Changeset 40685 in vbox
- Timestamp:
- Mar 28, 2012 2:48:00 PM (13 years ago)
- Location:
- trunk/src/VBox/Main
- Files:
-
- 6 edited
-
include/GuestImpl.h (modified) (9 diffs)
-
src-client/GuestCtrlImpl.cpp (modified) (47 diffs)
-
src-client/GuestCtrlImplDir.cpp (modified) (6 diffs)
-
src-client/GuestCtrlImplFile.cpp (modified) (2 diffs)
-
src-client/GuestCtrlImplTasks.cpp (modified) (6 diffs)
-
src-client/GuestImpl.cpp (modified) (3 diffs)
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Main/include/GuestImpl.h
r40084 r40685 175 175 HRESULT getProcessOutputInternal(ULONG aPID, ULONG aFlags, ULONG aTimeoutMS, 176 176 LONG64 aSize, ComSafeArrayOut(BYTE, aData), int *pRC); 177 HRESULT execute ProcessResult(const char *pszCommand, const char *pszUser, ULONG ulTimeout, PCALLBACKDATAEXECSTATUS pExecStatus, ULONG *puPID);177 HRESULT executeSetResult(const char *pszCommand, const char *pszUser, ULONG ulTimeout, PCALLBACKDATAEXECSTATUS pExecStatus, ULONG *puPID); 178 178 int executeStreamQueryFsObjInfo(IN_BSTR aObjName,GuestProcessStreamBlock &streamBlock, PRTFSOBJINFO pObjInfo, RTFSOBJATTRADD enmAddAttribs); 179 int executeStreamDrain(ULONG aPID, ULONG ulFlags, GuestProcessStream &stream);179 int executeStreamDrain(ULONG aPID, ULONG ulFlags, GuestProcessStream *pStream); 180 180 int executeStreamGetNextBlock(ULONG ulPID, ULONG ulFlags, GuestProcessStream &stream, GuestProcessStreamBlock &streamBlock); 181 181 int executeStreamParseNextBlock(ULONG ulPID, ULONG ulFlags, GuestProcessStream &stream, GuestProcessStreamBlock &streamBlock); 182 182 HRESULT executeStreamParse(ULONG uPID, ULONG ulFlags, GuestCtrlStreamObjects &streamObjects); 183 HRESULT executeWaitForExit(ULONG uPID, ComPtr<IProgress> pProgress, ULONG uTimeoutMS, 184 ExecuteProcessStatus_T *pRetStatus, ULONG *puRetExitCode); 183 HRESULT executeWaitForExit(ULONG uPID, ComPtr<IProgress> pProgress, ULONG uTimeoutMS); 185 184 // Internal guest file functions 186 185 HRESULT fileExistsInternal(IN_BSTR aFile, IN_BSTR aUsername, IN_BSTR aPassword, BOOL *aExists); … … 211 210 /** Size of user-supplied data. */ 212 211 uint32_t cbData; 212 /** The host PID. Needed for translating to 213 * a guest PID. */ 214 uint32_t uHostPID; 213 215 /** Pointer to user-supplied IProgress. */ 214 216 ComObjPtr<Progress> pProgress; … … 219 221 220 222 int callbackAdd(const PVBOXGUESTCTRL_CALLBACK pCallbackData, uint32_t *puContextID); 223 int callbackAssignHostPID(uint32_t uContextID, uint32_t uHostPID); 221 224 void callbackDestroy(uint32_t uContextID); 222 225 void callbackRemove(uint32_t uContextID); 223 226 bool callbackExists(uint32_t uContextID); 224 227 void callbackFreeUserData(void *pvData); 228 uint32_t callbackGetHostPID(uint32_t uContextID); 225 229 int callbackGetUserData(uint32_t uContextID, eVBoxGuestCtrlCallbackType *pEnmType, void **ppvData, size_t *pcbData); 226 230 void* callbackGetUserDataMutableRaw(uint32_t uContextID, size_t *pcbData); … … 231 235 int callbackNotifyEx(uint32_t uContextID, int iRC, const char *pszMessage); 232 236 int callbackNotifyComplete(uint32_t uContextID); 233 int callbackNotifyAllForPID(uint32_t u PID, int iRC, const char *pszMessage);237 int callbackNotifyAllForPID(uint32_t uGuestPID, int iRC, const char *pszMessage); 234 238 int callbackWaitForCompletion(uint32_t uContextID, LONG lStage, LONG lTimeout); 235 239 … … 242 246 typedef struct VBOXGUESTCTRL_PROCESS 243 247 { 248 /** The guest PID -- needed for controlling the actual guest 249 * process which has its own PID (generated by the guest OS). */ 250 uint32_t mGuestPID; 251 /** The last reported process status. */ 244 252 ExecuteProcessStatus_T mStatus; 253 /** The process execution flags. */ 245 254 uint32_t mFlags; 255 /** The process' exit code. */ 246 256 uint32_t mExitCode; 247 257 } VBOXGUESTCTRL_PROCESS, *PVBOXGUESTCTRL_PROCESS; … … 250 260 typedef std::map< uint32_t, VBOXGUESTCTRL_PROCESS >::const_iterator GuestProcessMapIterConst; 251 261 252 int processGetStatus(uint32_t u32PID, PVBOXGUESTCTRL_PROCESS pProcess, bool fRemove); 253 int processSetStatus(uint32_t u32PID, ExecuteProcessStatus_T enmStatus, uint32_t uExitCode, uint32_t uFlags); 262 uint32_t processGetGuestPID(uint32_t uHostPID); 263 int processGetStatus(uint32_t uHostPID, PVBOXGUESTCTRL_PROCESS pProcess, bool fRemove); 264 int processSetStatus(uint32_t uHostPID, uint32_t uGuestPID, 265 ExecuteProcessStatus_T enmStatus, uint32_t uExitCode, uint32_t uFlags); 254 266 255 267 // Internal guest directory representation. … … 259 271 Bstr mFilter; 260 272 ULONG mFlags; 261 /** Associated PID of started vbox_ls tool. */273 /** Associated host PID of started vbox_ls tool. */ 262 274 ULONG mPID; 263 275 GuestProcessStream mStream; 264 #if 0265 /** Next enetry in our stream objects vector266 * to process. */267 uint32_t mNextEntry;268 /** The guest stream object containing all */269 GuestCtrlStreamObjects mStream;270 #endif271 276 } VBOXGUESTCTRL_DIRECTORY, *PVBOXGUESTCTRL_DIRECTORY; 272 277 typedef std::map< uint32_t, VBOXGUESTCTRL_DIRECTORY > GuestDirectoryMap; … … 280 285 * Handler for guest execution control notifications. 281 286 */ 282 HRESULT handleErrorCompletion(int rc); 283 HRESULT handleErrorHGCM(int rc); 287 HRESULT setErrorCompletion(int rc); 288 HRESULT setErrorFromProgress(ComPtr<IProgress> pProgress); 289 HRESULT setErrorHGCM(int rc); 284 290 # endif 285 291 … … 319 325 /** Next upcoming context ID. */ 320 326 volatile uint32_t mNextContextID; 327 /** Next upcoming host PID */ 328 volatile uint32_t mNextHostPID; 321 329 /** Next upcoming directory handle ID. */ 322 330 volatile uint32_t mNextDirectoryID; -
trunk/src/VBox/Main/src-client/GuestCtrlImpl.cpp
r40574 r40685 158 158 159 159 /** 160 * Assigns a host PID to a specified context. 161 * Does not do locking! 162 * 163 * @param uContextID 164 * @param uHostPID 165 */ 166 int Guest::callbackAssignHostPID(uint32_t uContextID, uint32_t uHostPID) 167 { 168 AssertReturn(uContextID, VERR_INVALID_PARAMETER); 169 AssertReturn(uHostPID, VERR_INVALID_PARAMETER); 170 171 int rc = VINF_SUCCESS; 172 173 CallbackMapIter it = mCallbackMap.find(uContextID); 174 if (it == mCallbackMap.end()) 175 return VERR_NOT_FOUND; 176 177 it->second.uHostPID = uHostPID; 178 179 return VINF_SUCCESS; 180 } 181 182 /** 160 183 * Destroys the formerly allocated callback data. The callback then 161 184 * needs to get removed from the callback map via callbackRemove(). … … 211 234 } 212 235 236 /** 237 * Frees the user data (actual context data) of a callback. 238 * Does not do locking! 239 * 240 * @param pvData Data to free. 241 */ 213 242 void Guest::callbackFreeUserData(void *pvData) 214 243 { … … 218 247 pvData = NULL; 219 248 } 249 } 250 251 /** 252 * Retrieves the (generated) host PID of a given callback. 253 * 254 * @return The host PID, if found, 0 otherwise. 255 * @param uContextID Context ID to lookup host PID for. 256 * @param puHostPID Where to store the host PID. 257 */ 258 uint32_t Guest::callbackGetHostPID(uint32_t uContextID) 259 { 260 AssertReturn(uContextID, VERR_INVALID_PARAMETER); 261 262 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS); 263 264 CallbackMapIterConst it = mCallbackMap.find(uContextID); 265 if (it == mCallbackMap.end()) 266 return 0; 267 268 return it->second.uHostPID; 220 269 } 221 270 … … 256 305 void* Guest::callbackGetUserDataMutableRaw(uint32_t uContextID, size_t *pcbData) 257 306 { 258 AssertReturn(uContextID, NULL);307 /* uContextID can be 0. */ 259 308 /* pcbData is optional. */ 260 309 … … 326 375 bool Guest::callbackIsCanceled(uint32_t uContextID) 327 376 { 328 AssertReturn(uContextID, true); 377 if (!uContextID) 378 return true; /* If no context ID given then take a shortcut. */ 329 379 330 380 ComPtr<IProgress> pProgress; … … 468 518 else 469 519 { 470 471 520 hRC = pProgress->notifyComplete(VBOX_E_IPRT_ERROR /* Must not be S_OK. */, 472 521 COM_IIDOF(IGuest), … … 492 541 493 542 /** 494 * TODO 543 * Notifies all callbacks which are assigned to a certain guest PID to set a certain 544 * return/error code and an optional (error) message. 495 545 * 496 546 * @return IPRT status code. 497 * @param u PID498 * @param iRC 499 * @param pszMessage 547 * @param uGuestPID Guest PID to find all callbacks for. 548 * @param iRC Return (error) code to set for the found callbacks. 549 * @param pszMessage Optional (error) message to set. 500 550 */ 501 int Guest::callbackNotifyAllForPID(uint32_t u PID, int iRC, const char *pszMessage)502 { 503 AssertReturn(u PID, VERR_INVALID_PARAMETER);551 int Guest::callbackNotifyAllForPID(uint32_t uGuestPID, int iRC, const char *pszMessage) 552 { 553 AssertReturn(uGuestPID, VERR_INVALID_PARAMETER); 504 554 505 555 int vrc = VINF_SUCCESS; … … 522 572 PCALLBACKDATAEXECOUT pItData = (PCALLBACKDATAEXECOUT)it->second.pvData; 523 573 AssertPtr(pItData); 524 if (pItData->u32PID == u PID)574 if (pItData->u32PID == uGuestPID) 525 575 vrc = callbackNotifyEx(it->first, iRC, pszMessage); 526 576 break; … … 534 584 PCALLBACKDATAEXECINSTATUS pItData = (PCALLBACKDATAEXECINSTATUS)it->second.pvData; 535 585 AssertPtr(pItData); 536 if (pItData->u32PID == u PID)586 if (pItData->u32PID == uGuestPID) 537 587 vrc = callbackNotifyEx(it->first, iRC, pszMessage); 538 588 break; … … 712 762 713 763 uint32_t uContextID = pData->hdr.u32ContextID; 714 Assert(uContextID); 764 /* The context ID might be 0 in case the guest was not able to fetch 765 * actual command. So we can't do much now but report an error. */ 715 766 716 767 /* Scope write locks as much as possible. */ … … 744 795 /* Handle process map. This needs to be done first in order to have a valid 745 796 * map in case some callback gets notified a bit below. */ 797 798 uint32_t uHostPID = 0; 746 799 747 800 /* Note: PIDs never get removed here in case the guest process signalled its … … 751 804 if (pData->u32PID) /* Only add/change a process if it has a valid PID (>0). */ 752 805 { 806 uHostPID = callbackGetHostPID(uContextID); 807 Assert(uHostPID); 808 753 809 switch (pData->u32Status) 754 810 { … … 756 812 case PROC_STS_TES: 757 813 case PROC_STS_TOK: 758 vrc = processSetStatus( pData->u32PID,814 vrc = processSetStatus(uHostPID, pData->u32PID, 759 815 (ExecuteProcessStatus_T)pData->u32Status, 760 0 /* Exit code .*/, pData->u32Flags);816 0 /* Exit code */, pData->u32Flags); 761 817 break; 762 818 /* Interprete u32Flags as the guest process' exit code. */ 763 819 default: 764 vrc = processSetStatus( pData->u32PID,820 vrc = processSetStatus(uHostPID, pData->u32PID, 765 821 (ExecuteProcessStatus_T)pData->u32Status, 766 pData->u32Flags /* Exit code. */, 0 /* Flags. */); 767 822 pData->u32Flags /* Exit code */, 0 /* Flags */); 768 823 break; 769 824 } 770 825 } 771 826 772 /* Do progress handling. */ 773 switch (pData->u32Status) 774 { 775 case PROC_STS_STARTED: 776 vrc = callbackMoveForward(uContextID, Guest::tr("Waiting for process to exit ...")); 777 LogRel(("Guest process (PID %u) started\n", pData->u32PID)); /** @todo Add process name */ 778 break; 779 780 case PROC_STS_TEN: /* Terminated normally. */ 781 vrc = callbackNotifyComplete(uContextID); 782 LogRel(("Guest process (PID %u) exited normally\n", pData->u32PID)); /** @todo Add process name */ 783 break; 784 785 case PROC_STS_TEA: /* Terminated abnormally. */ 786 LogRel(("Guest process (PID %u) terminated abnormally with exit code = %u\n", 787 pData->u32PID, pData->u32Flags)); /** @todo Add process name */ 788 errMsg = Utf8StrFmt(Guest::tr("Process terminated abnormally with status '%u'"), 789 pData->u32Flags); 790 rcCallback = VERR_GENERAL_FAILURE; /** @todo */ 791 break; 792 793 case PROC_STS_TES: /* Terminated through signal. */ 794 LogRel(("Guest process (PID %u) terminated through signal with exit code = %u\n", 795 pData->u32PID, pData->u32Flags)); /** @todo Add process name */ 796 errMsg = Utf8StrFmt(Guest::tr("Process terminated via signal with status '%u'"), 797 pData->u32Flags); 798 rcCallback = VERR_GENERAL_FAILURE; /** @todo */ 799 break; 800 801 case PROC_STS_TOK: 802 LogRel(("Guest process (PID %u) timed out and was killed\n", pData->u32PID)); /** @todo Add process name */ 803 errMsg = Utf8StrFmt(Guest::tr("Process timed out and was killed")); 804 rcCallback = VERR_TIMEOUT; 805 break; 806 807 case PROC_STS_TOA: 808 LogRel(("Guest process (PID %u) timed out and could not be killed\n", pData->u32PID)); /** @todo Add process name */ 809 errMsg = Utf8StrFmt(Guest::tr("Process timed out and could not be killed")); 810 rcCallback = VERR_TIMEOUT; 811 break; 812 813 case PROC_STS_DWN: 814 LogRel(("Guest process (PID %u) killed because system is shutting down\n", pData->u32PID)); /** @todo Add process name */ 815 /* 816 * If u32Flags has ExecuteProcessFlag_IgnoreOrphanedProcesses set, we don't report an error to 817 * our progress object. This is helpful for waiters which rely on the success of our progress object 818 * even if the executed process was killed because the system/VBoxService is shutting down. 819 * 820 * In this case u32Flags contains the actual execution flags reached in via Guest::ExecuteProcess(). 821 */ 822 if (pData->u32Flags & ExecuteProcessFlag_IgnoreOrphanedProcesses) 827 if (RT_SUCCESS(vrc)) 828 { 829 /* Do progress handling. */ 830 switch (pData->u32Status) 831 { 832 case PROC_STS_STARTED: 833 vrc = callbackMoveForward(uContextID, Guest::tr("Waiting for process to exit ...")); 834 LogRel(("Guest process (PID %u) started\n", pData->u32PID)); /** @todo Add process name */ 835 break; 836 837 case PROC_STS_TEN: /* Terminated normally. */ 838 vrc = callbackNotifyComplete(uContextID); 839 LogRel(("Guest process (PID %u) exited normally (exit code: %u)\n", 840 pData->u32PID, pData->u32Flags)); /** @todo Add process name */ 841 break; 842 843 case PROC_STS_TEA: /* Terminated abnormally. */ 844 LogRel(("Guest process (PID %u) terminated abnormally (exit code: %u)\n", 845 pData->u32PID, pData->u32Flags)); /** @todo Add process name */ 846 errMsg = Utf8StrFmt(Guest::tr("Process terminated abnormally with status '%u'"), 847 pData->u32Flags); 848 rcCallback = VERR_GENERAL_FAILURE; /** @todo */ 849 break; 850 851 case PROC_STS_TES: /* Terminated through signal. */ 852 LogRel(("Guest process (PID %u) terminated through signal (exit code: %u)\n", 853 pData->u32PID, pData->u32Flags)); /** @todo Add process name */ 854 errMsg = Utf8StrFmt(Guest::tr("Process terminated via signal with status '%u'"), 855 pData->u32Flags); 856 rcCallback = VERR_GENERAL_FAILURE; /** @todo */ 857 break; 858 859 case PROC_STS_TOK: 860 LogRel(("Guest process (PID %u) timed out and was killed\n", pData->u32PID)); /** @todo Add process name */ 861 errMsg = Utf8StrFmt(Guest::tr("Process timed out and was killed")); 862 rcCallback = VERR_TIMEOUT; 863 break; 864 865 case PROC_STS_TOA: 866 LogRel(("Guest process (PID %u) timed out and could not be killed\n", pData->u32PID)); /** @todo Add process name */ 867 errMsg = Utf8StrFmt(Guest::tr("Process timed out and could not be killed")); 868 rcCallback = VERR_TIMEOUT; 869 break; 870 871 case PROC_STS_DWN: 872 LogRel(("Guest process (PID %u) killed because system is shutting down\n", pData->u32PID)); /** @todo Add process name */ 873 /* 874 * If u32Flags has ExecuteProcessFlag_IgnoreOrphanedProcesses set, we don't report an error to 875 * our progress object. This is helpful for waiters which rely on the success of our progress object 876 * even if the executed process was killed because the system/VBoxService is shutting down. 877 * 878 * In this case u32Flags contains the actual execution flags reached in via Guest::ExecuteProcess(). 879 */ 880 if (pData->u32Flags & ExecuteProcessFlag_IgnoreOrphanedProcesses) 881 { 882 vrc = callbackNotifyComplete(uContextID); 883 } 884 else 885 { 886 errMsg = Utf8StrFmt(Guest::tr("Process killed because system is shutting down")); 887 rcCallback = VERR_CANCELLED; 888 } 889 break; 890 891 case PROC_STS_ERROR: 823 892 { 824 vrc = callbackNotifyComplete(uContextID); 893 Utf8Str errDetail; 894 if (pData->u32PID) 895 { 896 errDetail = Utf8StrFmt(Guest::tr("Guest process (PID %u) could not be started because of rc=%Rrc"), 897 pData->u32PID, pData->u32Flags); 898 } 899 else 900 { 901 switch (pData->u32Flags) /* u32Flags member contains the IPRT error code from guest side. */ 902 { 903 case VERR_FILE_NOT_FOUND: /* This is the most likely error. */ 904 errDetail = Utf8StrFmt(Guest::tr("The specified file was not found on guest")); 905 break; 906 907 case VERR_PATH_NOT_FOUND: 908 errDetail = Utf8StrFmt(Guest::tr("Could not resolve path to specified file was not found on guest")); 909 break; 910 911 case VERR_BAD_EXE_FORMAT: 912 errDetail = Utf8StrFmt(Guest::tr("The specified file is not an executable format on guest")); 913 break; 914 915 case VERR_AUTHENTICATION_FAILURE: 916 errDetail = Utf8StrFmt(Guest::tr("The specified user was not able to logon on guest")); 917 break; 918 919 case VERR_TIMEOUT: 920 errDetail = Utf8StrFmt(Guest::tr("The guest did not respond within time")); 921 break; 922 923 case VERR_CANCELLED: 924 errDetail = Utf8StrFmt(Guest::tr("The execution operation was canceled")); 925 break; 926 927 case VERR_PERMISSION_DENIED: 928 errDetail = Utf8StrFmt(Guest::tr("Invalid user/password credentials")); 929 break; 930 931 case VERR_MAX_PROCS_REACHED: 932 errDetail = Utf8StrFmt(Guest::tr("Guest process could not be started because maximum number of parallel guest processes has been reached")); 933 break; 934 935 default: 936 errDetail = Utf8StrFmt(Guest::tr("Guest process reported error %Rrc"), pData->u32Flags); 937 break; 938 } 939 } 940 941 errMsg = Utf8StrFmt(Guest::tr("Process execution failed: "), pData->u32Flags) + errDetail; 942 rcCallback = pData->u32Flags; /* Report back guest rc. */ 943 944 LogRel((errMsg.c_str())); 945 946 break; 825 947 } 826 else 827 { 828 errMsg = Utf8StrFmt(Guest::tr("Process killed because system is shutting down")); 829 rcCallback = VERR_CANCELLED; 830 } 831 break; 832 833 case PROC_STS_ERROR: 834 if (pData->u32PID) 835 { 836 LogRel(("Guest process (PID %u) could not be started because of rc=%Rrc\n", 837 pData->u32PID, pData->u32Flags)); /** @todo Add process name */ 838 } 839 else 840 { 841 switch (pData->u32Flags) 842 { 843 case VERR_MAX_PROCS_REACHED: 844 LogRel(("Guest process could not be started because maximum number of parallel guest processes has been reached\n")); 845 break; 846 847 default: 848 LogRel(("Guest process could not be started because of rc=%Rrc\n", 849 pData->u32Flags)); 850 } 851 852 } 853 errMsg = Utf8StrFmt(Guest::tr("Process execution failed with rc=%Rrc"), pData->u32Flags); 854 rcCallback = pData->u32Flags; /* Report back rc. */ 855 break; 856 857 default: 858 vrc = VERR_INVALID_PARAMETER; 859 break; 948 949 default: 950 vrc = VERR_INVALID_PARAMETER; 951 break; 952 } 860 953 } 861 954 } … … 871 964 AssertMsg(!errMsg.isEmpty(), ("Error message must not be empty!\n")); 872 965 873 /* Notify all callbacks which are still waiting on something 874 * which is related to the current PID. */ 875 if (pData->u32PID) 876 { 877 int rc2 = callbackNotifyAllForPID(pData->u32PID, rcCallback, errMsg.c_str()); 966 if (uContextID) 967 { 968 /* Notify all callbacks which are still waiting on something 969 * which is related to the current PID. */ 970 if (pData->u32PID) 971 { 972 int rc2 = callbackNotifyAllForPID(pData->u32PID, rcCallback, errMsg.c_str()); 973 if (RT_FAILURE(rc2)) 974 { 975 LogFlowFunc(("Failed to notify other callbacks for PID=%u\n", 976 pData->u32PID)); 977 if (RT_SUCCESS(vrc)) 978 vrc = rc2; 979 } 980 } 981 982 /* Let the caller know what went wrong ... */ 983 int rc2 = callbackNotifyEx(uContextID, rcCallback, errMsg.c_str()); 878 984 if (RT_FAILURE(rc2)) 879 985 { 880 LogFlowFunc(("Failed to notify other callbacksfor PID=%u\n",881 pData->u32PID));986 LogFlowFunc(("Failed to notify callback CID=%u for PID=%u\n", 987 uContextID, pData->u32PID)); 882 988 if (RT_SUCCESS(vrc)) 883 989 vrc = rc2; 884 990 } 885 991 } 886 887 /* Let the caller know what went wrong ... */ 888 int rc2 = callbackNotifyEx(uContextID, rcCallback, errMsg.c_str()); 889 if (RT_FAILURE(rc2)) 890 { 891 LogFlowFunc(("Failed to notify callback CID=%u for PID=%u\n", 892 uContextID, pData->u32PID)); 893 if (RT_SUCCESS(vrc)) 894 vrc = rc2; 895 } 992 else 993 { 994 /* Since we don't know which context exactly failed all we can do is to shutdown 995 * all contexts ... */ 996 errMsg = Utf8StrFmt(Guest::tr("Client reported critical error %Rrc -- shutting down"), 997 pData->u32Flags); 998 999 /* Cancel all callbacks. */ 1000 CallbackMapIter it; 1001 for (it = mCallbackMap.begin(); it != mCallbackMap.end(); it++) 1002 { 1003 int rc2 = callbackNotifyEx(it->first, VERR_CANCELLED, 1004 errMsg.c_str()); 1005 AssertRC(rc2); 1006 } 1007 } 1008 896 1009 LogFlowFunc(("Process (CID=%u, status=%u) reported: %s\n", 897 1010 uContextID, pData->u32Status, errMsg.c_str())); … … 1011 1124 } 1012 1125 1126 uint32_t Guest::processGetGuestPID(uint32_t uHostPID) 1127 { 1128 AssertReturn(uHostPID, VERR_INVALID_PARAMETER); 1129 1130 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS); 1131 1132 GuestProcessMapIter it = mGuestProcessMap.find(uHostPID); 1133 if (it == mGuestProcessMap.end()) 1134 return 0; 1135 1136 return it->second.mGuestPID; 1137 } 1138 1013 1139 /** 1014 1140 * Gets guest process information. Removes the process from the map … … 1016 1142 * 1017 1143 * @return IPRT status code. 1018 * @param u 32PID PID ofprocess to get status for.1144 * @param uHostPID Host PID of guest process to get status for. 1019 1145 * @param pProcess Where to store the process information. Optional. 1020 1146 * @param fRemove Flag indicating whether to remove the … … 1022 1148 * exited/terminated. 1023 1149 */ 1024 int Guest::processGetStatus(uint32_t u 32PID, PVBOXGUESTCTRL_PROCESS pProcess,1150 int Guest::processGetStatus(uint32_t uHostPID, PVBOXGUESTCTRL_PROCESS pProcess, 1025 1151 bool fRemove) 1026 1152 { 1027 AssertReturn(u 32PID, VERR_INVALID_PARAMETER);1153 AssertReturn(uHostPID, VERR_INVALID_PARAMETER); 1028 1154 1029 1155 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS); 1030 1156 1031 GuestProcessMapIter it = mGuestProcessMap.find(u 32PID);1157 GuestProcessMapIter it = mGuestProcessMap.find(uHostPID); 1032 1158 if (it != mGuestProcessMap.end()) 1033 1159 { 1034 1160 if (pProcess) 1035 1161 { 1162 pProcess->mGuestPID = it->second.mGuestPID; 1036 1163 pProcess->mStatus = it->second.mStatus; 1037 1164 pProcess->mExitCode = it->second.mExitCode; … … 1039 1166 } 1040 1167 1041 /* If the is marked as stopped/terminated1042 * remove it from the map. */1168 /* Only remove processes from our map when they signalled their final 1169 * status. */ 1043 1170 if ( fRemove 1044 && it->second.mStatus != ExecuteProcessStatus_Started) 1171 && ( it->second.mStatus != ExecuteProcessStatus_Undefined 1172 && it->second.mStatus != ExecuteProcessStatus_Started)) 1045 1173 { 1046 1174 mGuestProcessMap.erase(it); … … 1053 1181 } 1054 1182 1055 int Guest::processSetStatus(uint32_t u32PID, ExecuteProcessStatus_T enmStatus, uint32_t uExitCode, uint32_t uFlags) 1056 { 1057 AssertReturn(u32PID, VERR_INVALID_PARAMETER); 1183 /** 1184 * Sets the current status of a guest process. 1185 * 1186 * @return IPRT status code. 1187 * @param uHostPID Host PID of guest process to set status (and guest PID) for. 1188 * @param uGuestPID Guest PID to assign to the host PID. 1189 * @param enmStatus Current status to set. 1190 * @param uExitCode Exit code (if any). 1191 * @param uFlags Additional flags. 1192 */ 1193 int Guest::processSetStatus(uint32_t uHostPID, uint32_t uGuestPID, 1194 ExecuteProcessStatus_T enmStatus, uint32_t uExitCode, uint32_t uFlags) 1195 { 1196 AssertReturn(uHostPID, VERR_INVALID_PARAMETER); 1197 /* Assigning a guest PID is optional. */ 1058 1198 1059 1199 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); 1060 1200 1061 GuestProcessMapIter it = mGuestProcessMap.find(u 32PID);1201 GuestProcessMapIter it = mGuestProcessMap.find(uHostPID); 1062 1202 if (it != mGuestProcessMap.end()) 1063 1203 { 1064 it->second.mStatus = enmStatus; 1204 it->second.mGuestPID = uGuestPID; 1205 it->second.mStatus = enmStatus; 1065 1206 it->second.mExitCode = uExitCode; 1066 it->second.mFlags = uFlags;1207 it->second.mFlags = uFlags; 1067 1208 } 1068 1209 else … … 1070 1211 VBOXGUESTCTRL_PROCESS process; 1071 1212 1072 process.mStatus = enmStatus; 1213 /* uGuestPID is optional -- the caller could call this function 1214 * before the guest process actually was started and a (valid) guest PID 1215 * was returned. */ 1216 process.mGuestPID = uGuestPID; 1217 process.mStatus = enmStatus; 1073 1218 process.mExitCode = uExitCode; 1074 process.mFlags = uFlags;1075 1076 mGuestProcessMap[u 32PID] = process;1219 process.mFlags = uFlags; 1220 1221 mGuestProcessMap[uHostPID] = process; 1077 1222 } 1078 1223 … … 1080 1225 } 1081 1226 1082 HRESULT Guest:: handleErrorCompletion(int rc)1227 HRESULT Guest::setErrorCompletion(int rc) 1083 1228 { 1084 1229 HRESULT hRC; … … 1098 1243 } 1099 1244 1100 HRESULT Guest::handleErrorHGCM(int rc) 1245 HRESULT Guest::setErrorFromProgress(ComPtr<IProgress> pProgress) 1246 { 1247 BOOL fCompleted; 1248 HRESULT rc = pProgress->COMGETTER(Completed)(&fCompleted); 1249 ComAssertComRC(rc); 1250 1251 HRESULT rcProc = S_OK; 1252 Utf8Str strError; 1253 1254 if (!fCompleted) 1255 { 1256 BOOL fCanceled; 1257 rc = pProgress->COMGETTER(Canceled)(&fCanceled); 1258 ComAssertComRC(rc); 1259 1260 strError = fCanceled ? Utf8StrFmt(Guest::tr("Process execution was canceled")) 1261 : Utf8StrFmt(Guest::tr("Process neither completed nor canceled; this shouldn't happen")); 1262 } 1263 else 1264 { 1265 rc = pProgress->COMGETTER(ResultCode)(&rcProc); 1266 ComAssertComRC(rc); 1267 1268 if (FAILED(rcProc)) 1269 { 1270 ProgressErrorInfo info(pProgress); 1271 strError = info.getText(); 1272 } 1273 } 1274 1275 if (FAILED(rcProc)) 1276 { 1277 AssertMsg(!strError.isEmpty(), ("Error message must not be empty!\n")); 1278 return setErrorInternal(rcProc, 1279 this->getClassIID(), 1280 this->getComponentName(), 1281 strError, 1282 false /* aWarning */, 1283 false /* aLogIt */); 1284 } 1285 1286 return S_OK; 1287 } 1288 1289 HRESULT Guest::setErrorHGCM(int rc) 1101 1290 { 1102 1291 HRESULT hRC; … … 1168 1357 IProgress **aProgress, ULONG *aPID) 1169 1358 { 1170 ComPtr<IProgress> p rogressTool;1359 ComPtr<IProgress> pProgress; 1171 1360 ULONG uPID; 1172 1361 ULONG uFlags = ExecuteProcessFlag_Hidden; … … 1174 1363 uFlags |= uFlagsToAdd; 1175 1364 1176 bool f WaitForOutput = false;1365 bool fParseOutput = false; 1177 1366 if ( ( (uFlags & ExecuteProcessFlag_WaitForStdOut) 1178 1367 && pObjStdOut) … … 1180 1369 && pObjStdErr)) 1181 1370 { 1182 f WaitForOutput = true;1183 } 1184 1185 HRESULT rc= ExecuteProcess(aTool,1371 fParseOutput = true; 1372 } 1373 1374 HRESULT hr = ExecuteProcess(aTool, 1186 1375 uFlags, 1187 1376 ComSafeArrayInArg(aArguments), 1188 1377 ComSafeArrayInArg(aEnvironment), 1189 1378 aUsername, aPassword, 1190 0 /* No timeout. */, 1191 &uPID, progressTool.asOutParam()); 1192 if ( SUCCEEDED(rc) 1193 && fWaitForOutput) 1194 { 1195 BOOL fCompleted; 1196 while ( SUCCEEDED(progressTool->COMGETTER(Completed)(&fCompleted)) 1197 && !fCompleted) 1198 { 1199 BOOL fCanceled; 1200 rc = progressTool->COMGETTER(Canceled)(&fCanceled); 1201 AssertComRC(rc); 1202 if (fCanceled) 1203 { 1204 rc = setErrorNoLog(VBOX_E_IPRT_ERROR, 1205 tr("%s was cancelled"), Utf8Str(aDescription).c_str()); 1206 break; 1207 } 1208 1209 if ( (uFlags & ExecuteProcessFlag_WaitForStdOut) 1210 && pObjStdOut) 1211 { 1212 rc = executeStreamParse(uPID, ProcessOutputFlag_None /* StdOut */, *pObjStdOut); 1213 } 1214 1215 if ( (uFlags & ExecuteProcessFlag_WaitForStdErr) 1216 && pObjStdErr) 1217 { 1218 rc = executeStreamParse(uPID, ProcessOutputFlag_StdErr, *pObjStdErr); 1219 } 1220 1221 if (FAILED(rc)) 1222 break; 1223 } 1224 } 1225 1226 if (SUCCEEDED(rc)) 1379 0 /* No timeout */, 1380 &uPID, pProgress.asOutParam()); 1381 if (SUCCEEDED(hr)) 1382 { 1383 /* Wait for tool being started. */ 1384 hr = pProgress->WaitForOperationCompletion( 0 /* Stage, starting the process */, 1385 -1 /* No timeout */); 1386 } 1387 1388 if ( SUCCEEDED(hr) 1389 && !(uFlags & ExecuteProcessFlag_WaitForProcessStartOnly)) 1390 { 1391 if (!fParseOutput) 1392 { 1393 if ( !(uFlags & ExecuteProcessFlag_WaitForStdOut) 1394 && !(uFlags & ExecuteProcessFlag_WaitForStdErr)) 1395 { 1396 hr = executeWaitForExit(uPID, pProgress, 0 /* No timeout */); 1397 } 1398 } 1399 else 1400 { 1401 BOOL fCompleted; 1402 while ( SUCCEEDED(pProgress->COMGETTER(Completed)(&fCompleted)) 1403 && !fCompleted) 1404 { 1405 BOOL fCanceled; 1406 hr = pProgress->COMGETTER(Canceled)(&fCanceled); 1407 AssertComRC(hr); 1408 if (fCanceled) 1409 { 1410 hr = setErrorNoLog(VBOX_E_IPRT_ERROR, 1411 tr("%s was cancelled"), Utf8Str(aDescription).c_str()); 1412 break; 1413 } 1414 1415 if ( (uFlags & ExecuteProcessFlag_WaitForStdOut) 1416 && pObjStdOut) 1417 { 1418 hr = executeStreamParse(uPID, ProcessOutputFlag_None /* StdOut */, *pObjStdOut); 1419 } 1420 1421 if ( (uFlags & ExecuteProcessFlag_WaitForStdErr) 1422 && pObjStdErr) 1423 { 1424 hr = executeStreamParse(uPID, ProcessOutputFlag_StdErr, *pObjStdErr); 1425 } 1426 1427 if (FAILED(hr)) 1428 break; 1429 } 1430 } 1431 } 1432 1433 if (SUCCEEDED(hr)) 1227 1434 { 1228 1435 if (aProgress) 1229 1436 { 1230 1437 /* Return the progress to the caller. */ 1231 progressTool.queryInterfaceTo(aProgress); 1232 } 1438 pProgress.queryInterfaceTo(aProgress); 1439 } 1440 else if (!pProgress.isNull()) 1441 pProgress.setNull(); 1233 1442 1234 1443 if (aPID) … … 1236 1445 } 1237 1446 1238 return rc; 1239 } 1240 1241 HRESULT Guest::executeProcessResult(const char *pszCommand, const char *pszUser, ULONG ulTimeout, 1242 PCALLBACKDATAEXECSTATUS pExecStatus, ULONG *puPID) 1243 { 1244 AssertPtrReturn(pExecStatus, E_INVALIDARG); 1245 AssertPtrReturn(puPID, E_INVALIDARG); 1246 1247 HRESULT rc = S_OK; 1248 1249 /* Did we get some status? */ 1250 switch (pExecStatus->u32Status) 1251 { 1252 case PROC_STS_STARTED: 1253 /* Process is (still) running; get PID. */ 1254 *puPID = pExecStatus->u32PID; 1255 break; 1256 1257 /* In any other case the process either already 1258 * terminated or something else went wrong, so no PID ... */ 1259 case PROC_STS_TEN: /* Terminated normally. */ 1260 case PROC_STS_TEA: /* Terminated abnormally. */ 1261 case PROC_STS_TES: /* Terminated through signal. */ 1262 case PROC_STS_TOK: 1263 case PROC_STS_TOA: 1264 case PROC_STS_DWN: 1265 /* 1266 * Process (already) ended, but we want to get the 1267 * PID anyway to retrieve the output in a later call. 1268 */ 1269 *puPID = pExecStatus->u32PID; 1270 break; 1271 1272 case PROC_STS_ERROR: 1273 { 1274 int vrc = pExecStatus->u32Flags; /* u32Flags member contains IPRT error code. */ 1275 if (vrc == VERR_FILE_NOT_FOUND) /* This is the most likely error. */ 1276 rc = setErrorNoLog(VBOX_E_IPRT_ERROR, 1277 tr("The file '%s' was not found on guest"), pszCommand); 1278 else if (vrc == VERR_PATH_NOT_FOUND) 1279 rc = setErrorNoLog(VBOX_E_IPRT_ERROR, 1280 tr("The path to file '%s' was not found on guest"), pszCommand); 1281 else if (vrc == VERR_BAD_EXE_FORMAT) 1282 rc = setErrorNoLog(VBOX_E_IPRT_ERROR, 1283 tr("The file '%s' is not an executable format on guest"), pszCommand); 1284 else if (vrc == VERR_AUTHENTICATION_FAILURE) 1285 rc = setErrorNoLog(VBOX_E_IPRT_ERROR, 1286 tr("The specified user '%s' was not able to logon on guest"), pszUser); 1287 else if (vrc == VERR_TIMEOUT) 1288 rc = setErrorNoLog(VBOX_E_IPRT_ERROR, 1289 tr("The guest did not respond within time (%ums)"), ulTimeout); 1290 else if (vrc == VERR_CANCELLED) 1291 rc = setErrorNoLog(VBOX_E_IPRT_ERROR, 1292 tr("The execution operation was canceled")); 1293 else if (vrc == VERR_PERMISSION_DENIED) 1294 rc = setErrorNoLog(VBOX_E_IPRT_ERROR, 1295 tr("Invalid user/password credentials")); 1296 else if (vrc == VERR_MAX_PROCS_REACHED) 1297 rc = setErrorNoLog(VBOX_E_IPRT_ERROR, 1298 tr("Concurrent guest process limit is reached")); 1299 else 1300 { 1301 if (pExecStatus && pExecStatus->u32Status == PROC_STS_ERROR) 1302 rc = setErrorNoLog(VBOX_E_IPRT_ERROR, 1303 tr("Process could not be started: %Rrc"), pExecStatus->u32Flags); 1304 else 1305 rc = setErrorNoLog(E_UNEXPECTED, 1306 tr("The service call failed with error %Rrc"), vrc); 1307 } 1308 } 1309 break; 1310 1311 case PROC_STS_UNDEFINED: /* . */ 1312 rc = setErrorNoLog(VBOX_E_IPRT_ERROR, 1313 tr("The operation did not complete within time")); 1314 break; 1315 1316 default: 1317 AssertReleaseMsgFailed(("Process (PID %u) reported back an undefined state!\n", 1318 pExecStatus->u32PID)); 1319 rc = E_UNEXPECTED; 1320 break; 1321 } 1322 1323 return rc; 1447 return hr; 1324 1448 } 1325 1449 … … 1355 1479 * @param aPID PID of process to get the output from. 1356 1480 * @param aFlags Which stream to drain (stdout or stderr). 1357 * @param stream Reference to guest process stream to fill. 1481 * @param pStream Pointer to guest process stream to fill. If NULL, 1482 * data goes to /dev/null. 1358 1483 */ 1359 int Guest::executeStreamDrain(ULONG aPID, ULONG aFlags, GuestProcessStream &stream)1484 int Guest::executeStreamDrain(ULONG aPID, ULONG aFlags, GuestProcessStream *pStream) 1360 1485 { 1361 1486 AssertReturn(aPID, VERR_INVALID_PARAMETER); 1487 /* pStream is optional. */ 1362 1488 1363 1489 int rc = VINF_SUCCESS; … … 1370 1496 if (RT_SUCCESS(rc)) 1371 1497 { 1372 if (aData.size()) 1373 { 1374 rc = stream.AddData(aData.raw(), aData.size()); 1498 if ( pStream 1499 && aData.size()) 1500 { 1501 rc = pStream->AddData(aData.raw(), aData.size()); 1375 1502 if (RT_UNLIKELY(RT_FAILURE(rc))) 1376 1503 break; … … 1387 1514 } 1388 1515 1389 /* In any case remove the (terminated/broken) process from1390 * the process table. */1391 int rc2 = processGetStatus(aPID, NULL /* PVBOXGUESTCTRL_PROCESS */,1392 true /* Remove from table */);1393 AssertRC(rc2);1394 1516 break; 1395 1517 } … … 1443 1565 LogFlowFunc(("Got %ld bytes of additional data\n", aData.size())); 1444 1566 1567 if (RT_FAILURE(rc)) 1568 { 1569 if (rc == VERR_BROKEN_PIPE) 1570 rc = VINF_SUCCESS; /* No more data because process already ended. */ 1571 break; 1572 } 1573 1445 1574 if (aData.size()) 1446 1575 { … … 1533 1662 { 1534 1663 GuestProcessStream stream; 1535 int rc = executeStreamDrain(ulPID, ulFlags, stream);1664 int rc = executeStreamDrain(ulPID, ulFlags, &stream); 1536 1665 if (RT_SUCCESS(rc)) 1537 1666 { … … 1571 1700 * exit code. Optional. 1572 1701 */ 1573 HRESULT Guest::executeWaitForExit(ULONG uPID, ComPtr<IProgress> pProgress, ULONG uTimeoutMS, 1574 ExecuteProcessStatus_T *pRetStatus, ULONG *puRetExitCode) 1702 HRESULT Guest::executeWaitForExit(ULONG uPID, ComPtr<IProgress> pProgress, ULONG uTimeoutMS) 1575 1703 { 1576 1704 HRESULT rc = S_OK; … … 1592 1720 if (FAILED(rc)) 1593 1721 rc = setError(VBOX_E_IPRT_ERROR, 1594 tr("Waiting for guest process to end failed (%Rhrc)"), 1595 rc); 1596 } 1597 1598 if (SUCCEEDED(rc)) 1599 { 1600 ULONG uExitCode, uRetFlags; 1601 ExecuteProcessStatus_T enmStatus; 1602 HRESULT hRC = GetProcessStatus(uPID, &uExitCode, &uRetFlags, &enmStatus); 1603 if (FAILED(hRC)) 1604 return hRC; 1605 1606 if (pRetStatus) 1607 *pRetStatus = enmStatus; 1608 if (puRetExitCode) 1609 *puRetExitCode = uExitCode; 1610 /** @todo Flags? */ 1722 tr("Waiting for guest process to end failed (%Rhrc)"), rc); 1611 1723 } 1612 1724 … … 1707 1819 Utf8Str Utf8UserName(aUsername); 1708 1820 Utf8Str Utf8Password(aPassword); 1821 uint32_t uHostPID = 0; 1822 1709 1823 if (RT_SUCCESS(vrc)) 1710 1824 { … … 1795 1909 if (RT_SUCCESS(vrc)) 1796 1910 { 1797 LogFlowFunc(("Waiting for HGCM callback (timeout=%RI32ms) ...\n", aTimeoutMS));1911 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); 1798 1912 1799 1913 /* 1800 * Wait for the HGCM low level callback until the process 1801 * has been started (or something went wrong). This is necessary to 1802 * get the PID. 1914 * Generate a host-driven PID so that we immediately can return to the caller and 1915 * don't need to wait until the guest started the desired process to return the 1916 * PID generated by the guest OS. 1917 * 1918 * The guest PID will later be mapped to the host PID for later lookup. 1803 1919 */ 1804 1805 PCALLBACKDATAEXECSTATUS pExecStatus = NULL; 1806 1807 /* 1808 * Wait for the first stage (=0) to complete (that is starting the process). 1809 */ 1810 vrc = callbackWaitForCompletion(uContextID, 0 /* Stage */, aTimeoutMS); 1920 vrc = VERR_NOT_FOUND; /* We did not find a host PID yet ... */ 1921 1922 uint32_t uTries = 0; 1923 for (;;) 1924 { 1925 /* Create a new context ID ... */ 1926 uHostPID = ASMAtomicIncU32(&mNextHostPID); 1927 if (uHostPID == UINT32_MAX) 1928 ASMAtomicUoWriteU32(&mNextHostPID, 1000); 1929 /* Is the host PID already used? Try next PID ... */ 1930 GuestProcessMapIter it = mGuestProcessMap.find(uHostPID); 1931 if (it == mGuestProcessMap.end()) 1932 { 1933 /* Host PID not used (anymore), we're done here ... */ 1934 vrc = VINF_SUCCESS; 1935 break; 1936 } 1937 1938 if (++uTries == UINT32_MAX) 1939 break; /* Don't try too hard. */ 1940 } 1941 1811 1942 if (RT_SUCCESS(vrc)) 1812 { 1813 vrc = callbackGetUserData(uContextID, NULL /* We know the type. */, 1814 (void**)&pExecStatus, NULL /* Don't need the size. */); 1815 if (RT_SUCCESS(vrc)) 1816 { 1817 rc = executeProcessResult(Utf8Command.c_str(), Utf8UserName.c_str(), aTimeoutMS, 1818 pExecStatus, aPID); 1819 callbackFreeUserData(pExecStatus); 1820 } 1821 else 1822 { 1823 rc = setErrorNoLog(VBOX_E_IPRT_ERROR, 1824 tr("Unable to retrieve process execution status data")); 1825 } 1826 } 1827 else 1828 rc = handleErrorCompletion(vrc); 1829 1830 /* 1831 * Do *not* remove the callback yet - we might wait with the IProgress object on something 1832 * else (like end of process) ... 1833 */ 1943 vrc = processSetStatus(uHostPID, 0 /* No guest PID yet */, 1944 ExecuteProcessStatus_Undefined /* Process not started yet */, 1945 0 /* uExitCode */, 0 /* uFlags */); 1946 1947 if (RT_SUCCESS(vrc)) 1948 vrc = callbackAssignHostPID(uContextID, uHostPID); 1834 1949 } 1835 1950 else 1836 rc = handleErrorHGCM(vrc);1951 rc = setErrorHGCM(vrc); 1837 1952 1838 1953 for (unsigned i = 0; i < uNumArgs; i++) 1839 1954 RTMemFree(papszArgv[i]); 1840 1955 RTMemFree(papszArgv); 1956 1957 if (RT_FAILURE(vrc)) 1958 rc = VBOX_E_IPRT_ERROR; 1841 1959 } 1842 1960 1843 1961 if (SUCCEEDED(rc)) 1844 1962 { 1963 /* Return host PID. */ 1964 *aPID = uHostPID; 1965 1845 1966 /* Return the progress to the caller. */ 1846 1967 pProgress.queryInterfaceTo(aProgress); … … 1897 2018 if (process.mStatus != ExecuteProcessStatus_Started) 1898 2019 rc = setError(VBOX_E_IPRT_ERROR, 1899 Guest::tr("Cannot inject input to not running process (PID %u)"), aPID);2020 Guest::tr("Cannot inject input to a not running process (PID %u)"), aPID); 1900 2021 } 1901 2022 else 1902 2023 rc = setError(VBOX_E_IPRT_ERROR, 1903 Guest::tr("Cannot inject input to non-existent process (PID %u)"), aPID);2024 Guest::tr("Cannot inject input to a non-existent process (PID %u)"), aPID); 1904 2025 1905 2026 if (RT_SUCCESS(vrc)) 1906 2027 { 1907 2028 uint32_t uContextID = 0; 2029 2030 uint32_t uGuestPID = processGetGuestPID(aPID); 2031 Assert(uGuestPID); 1908 2032 1909 2033 /* … … 1935 2059 1936 2060 /* Save PID + output flags for later use. */ 1937 pData->u32PID = aPID;2061 pData->u32PID = uGuestPID; 1938 2062 pData->u32Flags = aFlags; 1939 2063 } … … 1950 2074 int i = 0; 1951 2075 paParms[i++].setUInt32(uContextID); 1952 paParms[i++].setUInt32( aPID);2076 paParms[i++].setUInt32(uGuestPID); 1953 2077 paParms[i++].setUInt32(aFlags); 1954 2078 paParms[i++].setPointer(sfaData.raw(), cbSize); … … 1974 2098 i, paParms); 1975 2099 if (RT_FAILURE(vrc)) 1976 rc = handleErrorHGCM(vrc);2100 rc = setErrorHGCM(vrc); 1977 2101 } 1978 2102 } … … 2032 2156 } 2033 2157 else 2034 rc = handleErrorCompletion(vrc);2158 rc = setErrorCompletion(vrc); 2035 2159 } 2036 2160 … … 2107 2231 else if (proc.mStatus != ExecuteProcessStatus_Started) 2108 2232 { 2109 /* If the process is still in the process table but does not run anymore2110 * don't remove it but report back an appropriate error. */2233 /* If the process is already or still in the process table but does not run yet 2234 * (or anymore) don't remove it but report back an appropriate error. */ 2111 2235 vrc = VERR_BROKEN_PIPE; 2112 2236 /* Not getting any output is fine, so don't report an API error (rc) … … 2144 2268 uHandleID = OUTPUT_HANDLE_ID_STDERR; 2145 2269 2270 uint32_t uGuestPID = processGetGuestPID(aPID); 2271 Assert(uGuestPID); 2272 2146 2273 /** @todo Use a buffer for next iteration if returned data is too big 2147 2274 * for current read. … … 2154 2281 2155 2282 /* Save PID + output flags for later use. */ 2156 pData->u32PID = aPID;2283 pData->u32PID = uGuestPID; 2157 2284 pData->u32Flags = aFlags; 2158 2285 } … … 2166 2293 int i = 0; 2167 2294 paParms[i++].setUInt32(uContextID); 2168 paParms[i++].setUInt32( aPID);2295 paParms[i++].setUInt32(uGuestPID); 2169 2296 paParms[i++].setUInt32(uHandleID); 2170 2297 paParms[i++].setUInt32(0 /* Flags, none set yet */); … … 2249 2376 } 2250 2377 else 2251 rc = handleErrorCompletion(vrc);2378 rc = setErrorCompletion(vrc); 2252 2379 } 2253 2380 else 2254 rc = handleErrorHGCM(vrc);2381 rc = setErrorHGCM(vrc); 2255 2382 2256 2383 { … … 2427 2554 HRESULT rc = S_OK; 2428 2555 2429 ComObjPtr<Progress> p rogress;2556 ComObjPtr<Progress> pProgress; 2430 2557 try 2431 2558 { 2432 2559 /* Create the progress object. */ 2433 p rogress.createObject();2434 2435 rc = p rogress->init(static_cast<IGuest*>(this),2436 Bstr(tr("Copying file from host to guest")).raw(),2437 TRUE /* aCancelable */);2560 pProgress.createObject(); 2561 2562 rc = pProgress->init(static_cast<IGuest*>(this), 2563 Bstr(tr("Copying file from host to guest")).raw(), 2564 TRUE /* aCancelable */); 2438 2565 if (FAILED(rc)) throw rc; 2439 2566 2440 2567 /* Initialize our worker task. */ 2441 GuestTask *pTask = new GuestTask(GuestTask::TaskType_CopyFileToGuest, this, p rogress);2568 GuestTask *pTask = new GuestTask(GuestTask::TaskType_CopyFileToGuest, this, pProgress); 2442 2569 AssertPtr(pTask); 2443 2570 std::auto_ptr<GuestTask> task(pTask); … … 2465 2592 { 2466 2593 /* Return progress to the caller. */ 2467 p rogress.queryInterfaceTo(aProgress);2594 pProgress.queryInterfaceTo(aProgress); 2468 2595 } 2469 2596 return rc; -
trunk/src/VBox/Main/src-client/GuestCtrlImplDir.cpp
r39905 r40685 99 99 } 100 100 101 HRESULT rc = S_OK;101 HRESULT hr; 102 102 try 103 103 { … … 122 122 args.push_back(Bstr(Utf8Directory).raw()); /* The directory we want to create. */ 123 123 124 rc = executeAndWaitForTool(Bstr(VBOXSERVICE_TOOL_MKDIR).raw(), Bstr("Creating directory").raw(), 124 ULONG uPID; 125 ComPtr<IProgress> pProgress; 126 hr = executeAndWaitForTool(Bstr(VBOXSERVICE_TOOL_MKDIR).raw(), Bstr("Creating directory").raw(), 125 127 ComSafeArrayAsInParam(args), 126 128 ComSafeArrayAsInParam(env), … … 128 130 ExecuteProcessFlag_None, 129 131 NULL, NULL, 130 NULL /* Progress */, NULL /* PID */); 132 pProgress.asOutParam(), &uPID); 133 if (SUCCEEDED(hr)) 134 { 135 hr = setErrorFromProgress(pProgress); 136 pProgress.setNull(); 137 } 131 138 } 132 139 catch (std::bad_alloc &) 133 140 { 134 rc= E_OUTOFMEMORY;135 } 136 return rc;141 hr = E_OUTOFMEMORY; 142 } 143 return hr; 137 144 } 138 145 … … 299 306 { 300 307 #ifdef DEBUG 301 it->second.mStream.Dump(" /tmp/stream.txt");308 it->second.mStream.Dump("c:\\temp\\stream.txt"); 302 309 #endif 303 310 return executeStreamGetNextBlock(it->second.mPID, … … 482 489 */ 483 490 ULONG uPID; 491 ComPtr<IProgress> pProgress; 484 492 GuestCtrlStreamObjects stdOut; 485 493 hr = executeAndWaitForTool(Bstr(VBOXSERVICE_TOOL_STAT).raw(), Bstr("Querying directory information").raw(), … … 489 497 ExecuteProcessFlag_WaitForStdOut, 490 498 &stdOut, NULL /* stdErr */, 491 NULL /* Progress */, &uPID);499 pProgress.asOutParam(), &uPID); 492 500 if (SUCCEEDED(hr)) 493 501 { 494 int rc = VINF_SUCCESS;495 if ( stdOut.size())502 hr = setErrorFromProgress(pProgress); 503 if (SUCCEEDED(hr)) 496 504 { 497 const char *pszFsType = stdOut[0].GetString("ftype"); 498 if (!pszFsType) /* Attribute missing? */ 499 rc = VERR_PATH_NOT_FOUND; 500 if ( RT_SUCCESS(rc) 501 && strcmp(pszFsType, "d")) /* Directory? */ 505 int rc = VINF_SUCCESS; 506 if (stdOut.size()) 502 507 { 503 rc = VERR_PATH_NOT_FOUND; 504 /* This is not critical for Main, so don't set hr -- 505 * we will take care of rc then. */ 508 const char *pszFsType = stdOut[0].GetString("ftype"); 509 if (!pszFsType) /* Attribute missing? */ 510 rc = VERR_PATH_NOT_FOUND; 511 if ( RT_SUCCESS(rc) 512 && strcmp(pszFsType, "d")) /* Directory? */ 513 { 514 rc = VERR_PATH_NOT_FOUND; 515 /* This is not critical for Main, so don't set hr -- 516 * we will take care of rc then. */ 517 } 518 if ( RT_SUCCESS(rc) 519 && aObjInfo) /* Do we want object details? */ 520 { 521 rc = executeStreamQueryFsObjInfo(aDirectory, stdOut[0], 522 aObjInfo, enmAddAttribs); 523 } 506 524 } 507 if ( RT_SUCCESS(rc) 508 && aObjInfo) /* Do we want object details? */ 509 { 510 rc = executeStreamQueryFsObjInfo(aDirectory, stdOut[0], 511 aObjInfo, enmAddAttribs); 512 } 525 else 526 rc = VERR_NO_DATA; 527 528 if (pRC) 529 *pRC = rc; 513 530 } 514 else 515 rc = VERR_NO_DATA; 516 517 if (pRC) 518 *pRC = rc; 531 532 pProgress.setNull(); 519 533 } 520 534 } -
trunk/src/VBox/Main/src-client/GuestCtrlImplFile.cpp
r39850 r40685 132 132 ULONG uPID; 133 133 GuestCtrlStreamObjects stdOut; 134 ComPtr<IProgress> pProgress; 134 135 hr = executeAndWaitForTool(Bstr(VBOXSERVICE_TOOL_STAT).raw(), Bstr("Querying file information").raw(), 135 136 ComSafeArrayAsInParam(args), … … 138 139 ExecuteProcessFlag_WaitForStdOut, 139 140 &stdOut, NULL, 140 NULL /* Progress */, &uPID);141 pProgress.asOutParam(), &uPID); 141 142 if (SUCCEEDED(hr)) 142 143 { 143 int rc = VINF_SUCCESS;144 if ( stdOut.size())144 hr = setErrorFromProgress(pProgress); 145 if (SUCCEEDED(hr)) 145 146 { 147 int rc = VINF_SUCCESS; 148 if (stdOut.size()) 149 { 146 150 #if 0 147 /* Dump the parsed stream contents to Log(). */ 148 stdOut[0].Dump(); 149 #endif 150 const char *pszFsType = stdOut[0].GetString("ftype"); 151 if (!pszFsType) /* Was an object found at all? */ 152 rc = VERR_FILE_NOT_FOUND; 153 if ( RT_SUCCESS(rc) 154 && strcmp(pszFsType, "-")) /* Regular file? */ 155 { 156 rc = VERR_FILE_NOT_FOUND; 157 /* This is not critical for Main, so don't set hr -- 158 * we will take care of rc then. */ 151 /* Dump the parsed stream contents to Log(). */ 152 stdOut[0].Dump(); 153 #endif 154 const char *pszFsType = stdOut[0].GetString("ftype"); 155 if (!pszFsType) /* Was an object found at all? */ 156 rc = VERR_FILE_NOT_FOUND; 157 if ( RT_SUCCESS(rc) 158 && strcmp(pszFsType, "-")) /* Regular file? */ 159 { 160 rc = VERR_FILE_NOT_FOUND; 161 /* This is not critical for Main, so don't set hr -- 162 * we will take care of rc then. */ 163 } 164 if ( RT_SUCCESS(rc) 165 && aObjInfo) /* Do we want object details? */ 166 { 167 rc = executeStreamQueryFsObjInfo(aFile, stdOut[0], 168 aObjInfo, enmAddAttribs); 169 } 159 170 } 160 if ( RT_SUCCESS(rc) 161 && aObjInfo) /* Do we want object details? */ 162 { 163 rc = executeStreamQueryFsObjInfo(aFile, stdOut[0], 164 aObjInfo, enmAddAttribs); 165 } 171 else 172 rc = VERR_NO_DATA; 173 174 if (pRC) 175 *pRC = rc; 166 176 } 167 else 168 rc = VERR_NO_DATA; 169 170 if (pRC) 171 *pRC = rc; 177 178 pProgress.setNull(); 172 179 } 173 180 } -
trunk/src/VBox/Main/src-client/GuestCtrlImplTasks.cpp
r40579 r40685 279 279 BOOL fCompleted = FALSE; 280 280 BOOL fCanceled = FALSE; 281 281 282 uint64_t cbTransferedTotal = 0; 283 uint64_t cbToRead = cbSize; 282 284 283 285 SafeArray<BYTE> aInputData(_64K); … … 285 287 && !fCompleted) 286 288 { 287 size_t cbToRead = cbSize;288 289 size_t cbRead = 0; 289 290 if (cbSize) /* If we have nothing to read, take a shortcut. */ … … 334 335 } 335 336 336 ULONG uBytesWritten = 0;337 ULONG cbBytesWritten = 0; 337 338 rc = pGuest->SetProcessInput(uPID, uFlags, 338 339 0 /* Infinite timeout */, 339 ComSafeArrayAsInParam(aInputData), & uBytesWritten);340 ComSafeArrayAsInParam(aInputData), &cbBytesWritten); 340 341 if (FAILED(rc)) 341 342 { … … 346 347 Assert(cbRead <= cbToRead); 347 348 Assert(cbToRead >= cbRead); 348 cbToRead -= cbRead; 349 350 cbTransferedTotal += uBytesWritten; 349 /* Only subtract bytes reported written by the guest. */ 350 cbToRead -= cbBytesWritten; 351 352 cbTransferedTotal += cbBytesWritten; 351 353 Assert(cbTransferedTotal <= cbSize); 352 354 aTask->pProgress->SetCurrentOperationProgress((ULONG)(cbTransferedTotal * 100 / cbSize)); … … 377 379 * canceled or we simply got all stuff transferred. 378 380 */ 379 ExecuteProcessStatus_T retStatus; 380 ULONG uRetExitCode; 381 382 rc = executeWaitForExit(uPID, execProgress, 0 /* No timeout */, 383 &retStatus, &uRetExitCode); 381 rc = executeWaitForExit(uPID, execProgress, 0 /* No timeout */); 384 382 if (FAILED(rc)) 385 383 { … … 388 386 else 389 387 { 390 if ( uRetExitCode != 0 391 || retStatus != ExecuteProcessStatus_TerminatedNormally) 388 VBOXGUESTCTRL_PROCESS proc; 389 vrc = processGetStatus(uPID, &proc, true /* Remove from PID list. */); 390 if (RT_SUCCESS(vrc)) 392 391 { 393 rc = GuestTask::setProgressErrorMsg(VBOX_E_IPRT_ERROR, aTask->pProgress, 394 Guest::tr("Guest process reported error %u (status: %u) while copying file \"%s\" to \"%s\""), 395 uRetExitCode, retStatus, aTask->strSource.c_str(), aTask->strDest.c_str()); 392 393 if ( proc.mExitCode != 0 394 || proc.mStatus != ExecuteProcessStatus_TerminatedNormally) 395 { 396 rc = GuestTask::setProgressErrorMsg(VBOX_E_IPRT_ERROR, aTask->pProgress, 397 Guest::tr("Guest process reported error %u (status: %u) while copying file \"%s\" to \"%s\""), 398 proc.mExitCode, proc.mStatus, aTask->strSource.c_str(), aTask->strDest.c_str()); 399 } 396 400 } 397 401 } -
trunk/src/VBox/Main/src-client/GuestImpl.cpp
r40288 r40685 111 111 /* Init the context ID counter at 1000. */ 112 112 mNextContextID = 1000; 113 /* Init the host PID counter. */ 114 mNextHostPID = 0; 113 115 #endif 114 116 … … 211 213 */ 212 214 uFreeTotal = 0; 213 uAllocTotal = 0; 214 uBalloonedTotal = 0; 215 uAllocTotal = 0; 216 uBalloonedTotal = 0; 215 217 uSharedTotal = 0; 216 218 uTotalMem = 0; … … 253 255 mParent->reportGuestStatistics(validStats, 254 256 aGuestStats[GUESTSTATTYPE_CPUUSER], 255 aGuestStats[GUESTSTATTYPE_CPUKERNEL], 257 aGuestStats[GUESTSTATTYPE_CPUKERNEL], 256 258 aGuestStats[GUESTSTATTYPE_CPUIDLE], 257 259 /* Convert the units for RAM usage stats: page (4K) -> 1KB units */
Note:
See TracChangeset
for help on using the changeset viewer.

