Changeset 3195 for trunk/src/kmk
- Timestamp:
- Mar 27, 2018, 8:09:23 PM (7 years ago)
- Location:
- trunk/src/kmk
- Files:
-
- 7 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/kmk/kmkbuiltin.h
r3192 r3195 89 89 /** The KMK output synchronizer. */ 90 90 struct output *pOut; 91 #if defined(KBUILD_OS_WINDOWS) && !defined(KMK_BUILTIN_STANDALONE) 92 /** Pointer to the worker thread, if we're on one. */ 93 void *pvWorker; 94 #endif 91 95 } KMKBUILTINCTX; 92 96 /** Pointer to kmk built-in command execution context. */ -
trunk/src/kmk/kmkbuiltin/redirect.c
r3192 r3195 92 92 # define LIBPATHSTRICT 3 93 93 # endif 94 #endif 95 96 #ifndef KMK_BUILTIN_STANDALONE 97 extern void kmk_cache_exec_image_a(const char *); /* imagecache.c */ 94 98 #endif 95 99 … … 596 600 597 601 /** 602 * Registers the child process with a care provider or waits on it to complete. 603 * 604 * @returns 0 or non-zero success indicator or child exit code, depending on 605 * the value pfIsChildExitCode points to. 606 * @param pCtx The command execution context. 607 * @param hProcess The child process handle. 608 * @param cVerbosity The verbosity level. 609 * @param pPidSpawned Where to return the PID of the spawned child 610 * when we're inside KMK and we're return without 611 * waiting. 612 * @param pfIsChildExitCode Where to indicate whether the return exit code 613 * is from the child or from our setup efforts. 614 */ 615 static int kRedirectPostnatalCareOnWindows(PKMKBUILTINCTX pCtx, HANDLE hProcess, unsigned cVerbosity, 616 pid_t *pPidSpawned, KBOOL *pfIsChildExitCode) 617 { 618 int rcExit; 619 DWORD dwTmp; 620 621 # ifndef KMK_BUILTIN_STANDALONE 622 /* 623 * Try register the child with a childcare provider, i.e. winchildren.c 624 * or sub_proc.c. 625 */ 626 # ifndef CONFIG_NEW_WIN_CHILDREN 627 if (process_kmk_register_redirect(hProcess, pPidSpawned) == 0) 628 # else 629 if ( pPidSpawned 630 && MkWinChildCreateRedirect((intptr_t)hProcess, pPidSpawned) == 0) 631 # endif 632 { 633 if (cVerbosity > 0) 634 warnx(pCtx, "debug: spawned %d", *pPidSpawned); 635 *pfIsChildExitCode = K_FALSE; 636 return 0; 637 } 638 # ifndef CONFIG_NEW_WIN_CHILDREN 639 warn(pCtx, "sub_proc is out of slots, waiting for child..."); 640 # else 641 if (pPidSpawned) 642 warn(pCtx, "MkWinChildCreateRedirect failed..."); 643 # endif 644 # endif 645 646 /* 647 * Either the provider is outbooked or we're not in a context (like 648 * standalone) where we get help with waiting and must to it ourselves 649 */ 650 dwTmp = WaitForSingleObject(hProcess, INFINITE); 651 if (dwTmp != WAIT_OBJECT_0) 652 warnx(pCtx, "WaitForSingleObject failed: %#x\n", dwTmp); 653 654 if (GetExitCodeProcess(hProcess, &dwTmp)) 655 rcExit = (int)dwTmp; 656 else 657 { 658 warnx(pCtx, "GetExitCodeProcess failed: %u\n", GetLastError()); 659 TerminateProcess(hProcess, 127); 660 rcExit = 127; 661 } 662 663 CloseHandle(hProcess); 664 *pfIsChildExitCode = K_TRUE; 665 return rcExit; 666 } 667 668 669 /** 598 670 * Tries to locate the executable image. 599 671 * … … 665 737 666 738 return pszExecutable; 739 } 740 741 742 /** 743 * Turns the orders into input for nt_child_inject_standard_handles and 744 * winchildren.c 745 * 746 * @returns 0 on success, non-zero on failure. 747 * @param pCtx The command execution context. 748 * @param cOrders Number of file operation orders. 749 * @param paOrders The file operation orders. 750 * @param pafReplace Replace (TRUE) or leave alone (FALSE) indicator 751 * for each of the starndard handles. 752 * @param pahChild Array of standard handles for injecting into the 753 * child. Parallel to pafReplace. 754 */ 755 static int kRedirectOrderToWindowsHandles(PKMKBUILTINCTX pCtx, unsigned cOrders, REDIRECTORDERS *paOrders, 756 BOOL pafReplace[3], HANDLE pahChild[3]) 757 { 758 int i; 759 for (i = 0; i < (int)cOrders; i++) 760 { 761 int fdTarget = paOrders[i].fdTarget; 762 assert(fdTarget >= 0 && fdTarget < 3); 763 switch (paOrders[i].enmOrder) 764 { 765 case kRedirectOrder_Open: 766 if ( (paOrders[i].fOpen & O_APPEND) 767 && lseek(paOrders[i].fdSource, 0, SEEK_END) < 0) 768 return err(pCtx, 10, "lseek-to-end failed on %d (for %d)", paOrders[i].fdSource, fdTarget); 769 /* fall thru */ 770 case kRedirectOrder_Dup: 771 pahChild[fdTarget] = (HANDLE)_get_osfhandle(paOrders[i].fdSource); 772 if (pahChild[fdTarget] == NULL || pahChild[fdTarget] == INVALID_HANDLE_VALUE) 773 return err(pCtx, 10, "_get_osfhandle failed on %d (for %d)", paOrders[i].fdSource, fdTarget); 774 break; 775 776 case kRedirectOrder_Close: 777 pahChild[fdTarget] = NULL; 778 break; 779 780 default: 781 assert(0); 782 } 783 pafReplace[fdTarget] = TRUE; 784 } 785 return 0; 667 786 } 668 787 … … 774 893 CloseHandle(ProcInfo.hThread); 775 894 *phProcess = ProcInfo.hProcess; 895 # ifndef KMK_BUILTIN_STANDALONE 896 kmk_cache_exec_image_a(pszExecutable); 897 # endif 776 898 rc = 0; 777 899 } … … 789 911 BOOL afReplace[3] = { FALSE, FALSE, FALSE }; 790 912 HANDLE ahChild[3] = { NULL, NULL, NULL }; 791 rc = 0; 792 for (i = 0; i < (int)cOrders; i++) 793 { 794 int fdTarget = paOrders[i].fdTarget; 795 assert(fdTarget >= 0 && fdTarget < 3); 796 switch (paOrders[i].enmOrder) 797 { 798 case kRedirectOrder_Open: 799 if ( (paOrders[i].fOpen & O_APPEND) 800 && lseek(paOrders[i].fdSource, 0, SEEK_END) < 0) 801 rc = err(pCtx, 10, "lseek-to-end failed on %d (for %d)", paOrders[i].fdSource, fdTarget); 802 case kRedirectOrder_Dup: 803 ahChild[fdTarget] = (HANDLE)_get_osfhandle(paOrders[i].fdSource); 804 if (ahChild[fdTarget] == NULL || ahChild[fdTarget] == INVALID_HANDLE_VALUE) 805 rc = err(pCtx, 10, "_get_osfhandle failed on %d (for %d)", paOrders[i].fdSource, fdTarget); 806 break; 807 case kRedirectOrder_Close: 808 ahChild[fdTarget] = NULL; 809 break; 810 default: 811 assert(0); 812 } 813 afReplace[fdTarget] = TRUE; 814 } 913 rc = kRedirectOrderToWindowsHandles(pCtx, cOrders, paOrders, afReplace, ahChild); 815 914 if (rc == 0) 816 915 { … … 835 934 CloseHandle(ProcInfo.hThread); 836 935 *phProcess = ProcInfo.hProcess; 936 # ifndef KMK_BUILTIN_STANDALONE 937 kmk_cache_exec_image_a(pszExecutable); 938 # endif 837 939 rc = 0; 838 940 } … … 848 950 return rc; 849 951 } 952 953 # if !defined(KMK_BUILTIN_STANDALONE) && defined(CONFIG_NEW_WIN_CHILDREN) 954 /** 955 * Pass the problem on to winchildren.c when we're on one of its workers. 956 * 957 * @returns 0 on success, non-zero on failure to create. 958 * @param pCtx The command execution context. 959 * @param pszExecutable The child process executable. 960 * @param cArgs Number of arguments. 961 * @param papszArgs The child argument vector. 962 * @param papszEnvVars The child environment vector. 963 * @param pszCwd The current working directory of the child. 964 * @param cOrders Number of file operation orders. 965 * @param paOrders The file operation orders. 966 * @param phProcess Where to return process handle. 967 * @param pfIsChildExitCode Where to indicate whether the return exit code 968 * is from the child or from our setup efforts. 969 */ 970 static int kRedirectExecProcessWithinOnWorker(PKMKBUILTINCTX pCtx, const char *pszExecutable, int cArgs, char **papszArgs, 971 char **papszEnvVars, const char *pszCwd, unsigned cOrders, 972 REDIRECTORDERS *paOrders, KBOOL *pfIsChildExitCode) 973 { 974 BOOL afReplace[3] = { FALSE, FALSE, FALSE }; 975 HANDLE ahChild[3] = { NULL, NULL, NULL }; 976 int rc = kRedirectOrderToWindowsHandles(pCtx, cOrders, paOrders, afReplace, ahChild); 977 if (rc == 0) 978 { 979 rc = MkWinChildBuiltInExecChild(pCtx->pvWorker, pszExecutable, papszArgs, TRUE /*fQuotedArgv*/, 980 papszEnvVars, pszCwd, afReplace, ahChild); 981 *pfIsChildExitCode = K_TRUE; 982 } 983 return rc; 984 } 985 # endif /* !KMK_BUILTIN_STANDALONE */ 850 986 851 987 #endif /* KBUILD_OS_WINDOWS */ … … 964 1100 # ifdef KBUILD_OS_WINDOWS 965 1101 /* Windows is slightly complicated due to handles and winchildren.c. */ 966 HANDLE hProcess = INVALID_HANDLE_VALUE; 967 rcExit = kRedirectCreateProcessWindows(pCtx, pszExecutable, cArgs, papszArgs, papszEnvVars, 968 pszSavedCwd ? pszCwd : NULL, cOrders, paOrders, &hProcess); 969 if (rcExit == 0) 970 { 971 # ifndef CONFIG_NEW_WIN_CHILDREN 972 if (process_kmk_register_redirect(hProcess, pPidSpawned) == 0) 973 # else 974 if ( pPidSpawned 975 && MkWinChildCreateRedirect((intptr_t)hProcess, pPidSpawned) == 0) 1102 if (pPidSpawned) 1103 *pPidSpawned = 0; 1104 # ifdef CONFIG_NEW_WIN_CHILDREN 1105 if (pCtx->pvWorker && !pPidSpawned) 1106 rcExit = kRedirectExecProcessWithinOnWorker(pCtx, pszExecutable, cArgs, papszArgs, papszEnvVars, 1107 pszSavedCwd ? pszCwd : NULL, cOrders, paOrders, 1108 pfIsChildExitCode); 1109 else 976 1110 # endif 977 { 978 if (cVerbosity > 0) 979 warnx(pCtx, "debug: spawned %d", *pPidSpawned); 980 } 981 else 982 { 983 DWORD dwTmp; 984 # ifndef CONFIG_NEW_WIN_CHILDREN 985 warn(pCtx, "sub_proc is out of slots, waiting for child..."); 986 # else 987 if (pPidSpawned) 988 warn(pCtx, "MkWinChildCreateRedirect failed..."); 989 # endif 990 dwTmp = WaitForSingleObject(hProcess, INFINITE); 991 if (dwTmp != WAIT_OBJECT_0) 992 warnx(pCtx, "WaitForSingleObject failed: %#x\n", dwTmp); 993 994 if (GetExitCodeProcess(hProcess, &dwTmp)) 995 rcExit = (int)dwTmp; 996 else 997 { 998 warnx(pCtx, "GetExitCodeProcess failed: %u\n", GetLastError()); 999 TerminateProcess(hProcess, 127); 1000 rcExit = 127; 1001 } 1002 1003 CloseHandle(hProcess); 1004 if (pPidSpawned) 1005 *pPidSpawned = 0; 1006 *pfIsChildExitCode = K_TRUE; 1007 } 1111 { 1112 HANDLE hProcess = INVALID_HANDLE_VALUE; 1113 rcExit = kRedirectCreateProcessWindows(pCtx, pszExecutable, cArgs, papszArgs, papszEnvVars, 1114 pszSavedCwd ? pszCwd : NULL, cOrders, paOrders, &hProcess); 1115 if (rcExit == 0) 1116 rcExit = kRedirectPostnatalCareOnWindows(pCtx, hProcess, cVerbosity, pPidSpawned, pfIsChildExitCode); 1008 1117 } 1009 1118 … … 1052 1161 dwWait = 11; 1053 1162 if (GetExitCodeProcess(hProcess, &dwWait)) 1163 { 1164 *pfIsChildExitCode = K_TRUE; 1054 1165 rcExit = dwWait; 1166 } 1055 1167 else 1056 1168 rcExit = errx(pCtx, 11, "GetExitCodeProcess(%s) failed: %u", pszExecutable, GetLastError()); -
trunk/src/kmk/output.c
r3194 r3195 126 126 fflush(prevdst); 127 127 prevdst = dst; 128 # ifdef KBUILD_OS_WINDOWS 128 # if 0 /* for debugging */ 129 while (len > 0) 130 { 131 const char *nl = (const char *)memchr (src, '\n', len); 132 size_t line_len = nl ? nl - (const char *)src + 1 : len; 133 char *tmp = (char *)xmalloc (2 + line_len + 1); 134 tmp[0] = '>'; 135 tmp[1] = ' '; 136 memcpy (&tmp[2], src, line_len); 137 # ifdef KBUILD_OS_WINDOWS 138 maybe_con_fwrite (tmp, 2 + line_len, 1, dst); 139 # else 140 fwrite (tmp, 2 + line_len, 1, dst); 141 # endif 142 free (tmp); 143 src = (const char *)src + line_len; 144 len -= line_len; 145 } 146 #else 147 # ifdef KBUILD_OS_WINDOWS 129 148 maybe_con_fwrite (src, len, 1, dst); 130 # else149 # else 131 150 fwrite (src, len, 1, dst); 151 # endif 132 152 # endif 133 153 } -
trunk/src/kmk/w32/imagecache.c
r3140 r3195 26 26 /* No GNU coding style here! */ 27 27 28 /******************************************************************************* 29 * Header Files *30 ******************************************************************************* /28 /********************************************************************************************************************************* 29 * Header Files * 30 *********************************************************************************************************************************/ 31 31 #include "makeint.h" 32 32 … … 34 34 35 35 36 /******************************************************************************* 37 * Structures and Typedefs *38 ******************************************************************************* /36 /********************************************************************************************************************************* 37 * Structures and Typedefs * 38 *********************************************************************************************************************************/ 39 39 typedef struct EXECCACHEENTRY 40 40 { … … 42 42 unsigned uHash; 43 43 /** The name length. */ 44 unsigned c chName;44 unsigned cwcName; 45 45 /** Pointer to the next name with the same hash. */ 46 46 struct EXECCACHEENTRY *pNext; 47 47 /** When it was last referenced. */ 48 48 unsigned uLastRef; 49 /** The module handle . */49 /** The module handle, LOAD_LIBRARY_AS_DATAFILE. */ 50 50 HMODULE hmod1; 51 /** The module handle . */51 /** The module handle, DONT_RESOLVE_DLL_REFERENCES. */ 52 52 HMODULE hmod2; 53 53 /** The executable path. */ 54 charszName[1];54 wchar_t wszName[1]; 55 55 } EXECCACHEENTRY; 56 56 typedef EXECCACHEENTRY *PEXECCACHEENTRY; 57 57 58 /******************************************************************************* 59 * Global Variables * 60 *******************************************************************************/ 58 59 /********************************************************************************************************************************* 60 * Global Variables * 61 *********************************************************************************************************************************/ 62 /** Critical section serializing all access. */ 63 static CRITICAL_SECTION g_CritSect; 64 /** Set if initialized. */ 65 static int volatile g_fInitialized = 0; 61 66 /** The number of cached images. */ 62 67 static unsigned g_cCached; … … 69 74 /** The hash table. */ 70 75 static PEXECCACHEENTRY g_apHashTab[EXECCACHE_HASHTAB_SIZE]; 76 77 78 /** A sleepy approach to do-once. */ 79 static void kmk_cache_lazy_init(void) 80 { 81 if (_InterlockedCompareExchange(&g_fInitialized, -1, 0) == 0) 82 { 83 InitializeCriticalSection(&g_CritSect); 84 _InterlockedExchange(&g_fInitialized, 1); 85 } 86 else 87 while (g_fInitialized != 1) 88 Sleep(1); 89 } 71 90 72 91 … … 83 102 elsewhere. */ 84 103 85 static unsigned execcache_calc_hash(const char *psz, unsigned*pcch)86 { 87 unsigned char *puch = (unsigned char *)psz;88 unsigned hash = 0;89 int ch;90 91 while ((ch = *p uch++))104 static unsigned execcache_calc_hash(const wchar_t *pwsz, size_t *pcch) 105 { 106 wchar_t const * const pwszStart = pwsz; 107 unsigned hash = 0; 108 int ch; 109 110 while ((ch = *pwsz++) != L'\0') 92 111 hash = ch + (hash << 6) + (hash << 16) - hash; 93 112 94 *pcch = ( unsigned)(puch - psz- 1);113 *pcch = (size_t)(pwsz - pwszStart - 1); 95 114 return hash; 96 115 } 97 116 98 99 extern void kmk_cache_exec_image(const char *pszExec) 100 { 101 /* 102 * Lookup the name. 103 */ 104 unsigned cchName; 105 const unsigned uHash = execcache_calc_hash(pszExec, &cchName); 117 /** 118 * Caches two memory mappings of the specified image so that it isn't flushed 119 * from the kernel's cache mananger. 120 * 121 * Not sure exactly how much this actually helps, but whatever... 122 * 123 * @param pwszExec The executable. 124 */ 125 extern void kmk_cache_exec_image_w(const wchar_t *pwszExec) 126 { 127 /* 128 * Prepare name lookup and to lazy init. 129 */ 130 size_t cwcName; 131 const unsigned uHash = execcache_calc_hash(pwszExec, &cwcName); 106 132 PEXECCACHEENTRY *ppCur = &g_apHashTab[uHash % EXECCACHE_HASHTAB_SIZE]; 107 PEXECCACHEENTRY pCur = *ppCur; 133 PEXECCACHEENTRY pCur; 134 135 if (g_fInitialized != 1) 136 kmk_cache_lazy_init(); 137 138 /* 139 * Do the lookup. 140 */ 141 EnterCriticalSection(&g_CritSect); 142 pCur = *ppCur; 108 143 while (pCur) 109 144 { 110 145 if ( pCur->uHash == uHash 111 && pCur->c chName == cchName112 && !memcmp(pCur-> szName, pszExec, cchName))146 && pCur->cwcName == cwcName 147 && !memcmp(pCur->wszName, pwszExec, cwcName * sizeof(wchar_t))) 113 148 { 114 149 pCur->uLastRef = ++g_uNow; 150 LeaveCriticalSection(&g_CritSect); 115 151 return; 116 152 } … … 118 154 pCur = pCur->pNext; 119 155 } 156 LeaveCriticalSection(&g_CritSect); 120 157 121 158 /* 122 159 * Not found, create a new entry. 123 160 */ 124 pCur = xmalloc(sizeof(*pCur) + c chName);161 pCur = xmalloc(sizeof(*pCur) + cwcName * sizeof(wchar_t)); 125 162 pCur->uHash = uHash; 126 pCur->c chName = cchName;163 pCur->cwcName = (unsigned)cwcName; 127 164 pCur->pNext = NULL; 128 165 pCur->uLastRef = ++g_uNow; 129 memcpy(pCur-> szName, pszExec, cchName + 1);130 pCur->hmod1 = LoadLibraryEx (pszExec, NULL, LOAD_LIBRARY_AS_DATAFILE);166 memcpy(pCur->wszName, pwszExec, (cwcName + 1) * sizeof(wchar_t)); 167 pCur->hmod1 = LoadLibraryExW(pwszExec, NULL, LOAD_LIBRARY_AS_DATAFILE); 131 168 if (pCur->hmod1 != NULL) 132 pCur->hmod2 = LoadLibraryEx (pszExec, NULL, DONT_RESOLVE_DLL_REFERENCES);169 pCur->hmod2 = LoadLibraryExW(pwszExec, NULL, DONT_RESOLVE_DLL_REFERENCES); 133 170 else 134 171 pCur->hmod2 = NULL; 135 172 136 *ppCur = pCur; 137 g_cCached++; 138 } 139 173 /* 174 * Insert it. 175 * Take into account that we might've been racing other threads, 176 * fortunately we don't evict anything from the cache. 177 */ 178 EnterCriticalSection(&g_CritSect); 179 if (*ppCur != NULL) 180 { 181 /* Find new end of chain and check for duplicate. */ 182 PEXECCACHEENTRY pCur2 = *ppCur; 183 while (pCur2) 184 { 185 if ( pCur->uHash == uHash 186 && pCur->cwcName == cwcName 187 && !memcmp(pCur->wszName, pwszExec, cwcName * sizeof(wchar_t))) 188 break; 189 ppCur = &pCur->pNext; 190 pCur = pCur->pNext; 191 } 192 193 } 194 if (*ppCur == NULL) 195 { 196 *ppCur = pCur; 197 g_cCached++; 198 LeaveCriticalSection(&g_CritSect); 199 } 200 else 201 { 202 LeaveCriticalSection(&g_CritSect); 203 204 if (pCur->hmod1 != NULL) 205 FreeLibrary(pCur->hmod1); 206 if (pCur->hmod2 != NULL) 207 FreeLibrary(pCur->hmod2); 208 free(pCur); 209 } 210 } 211 212 extern void kmk_cache_exec_image_a(const char *pszExec) 213 { 214 wchar_t wszExec[260]; 215 int cwc = MultiByteToWideChar(CP_ACP, 0 /*fFlags*/, pszExec, strlen(pszExec) + 1, wszExec, 260); 216 if (cwc > 0) 217 kmk_cache_exec_image_w(wszExec); 218 } 219 -
trunk/src/kmk/w32/subproc/sub_proc.c
r3140 r3195 40 40 # include <assert.h> 41 41 # include "kmkbuiltin.h" 42 extern void kmk_cache_exec_image (const char *); /* imagecache.c */42 extern void kmk_cache_exec_image_a(const char *); /* imagecache.c */ 43 43 #endif 44 44 … … 844 844 #ifdef KMK 845 845 if (exec_fname[0]) 846 kmk_cache_exec_image (exec_fname);846 kmk_cache_exec_image_a(exec_fname); 847 847 else if (exec_path) 848 kmk_cache_exec_image (exec_path);848 kmk_cache_exec_image_a(exec_path); 849 849 else if (argv[0]) 850 kmk_cache_exec_image (argv[0]);850 kmk_cache_exec_image_a(argv[0]); 851 851 852 852 switch (process_priority) { -
trunk/src/kmk/w32/winchildren.c
r3192 r3195 101 101 102 102 #include "nt/nt_child_inject_standard_handles.h" 103 104 #ifndef KMK_BUILTIN_STANDALONE 105 extern void kmk_cache_exec_image_w(const wchar_t *); /* imagecache.c */ 106 #endif 103 107 104 108 … … 805 809 * Commmon worker for waiting on a child process and retrieving the exit code. 806 810 * 811 * @returns Child exit code. 807 812 * @param pWorker The worker. 808 813 * @param pChild The child. … … 812 817 * associated with the worker. 813 818 */ 814 static voidmkWinChildcareWorkerWaitForProcess(PWINCHILDCAREWORKER pWorker, PWINCHILD pChild, HANDLE hProcess,815 819 static int mkWinChildcareWorkerWaitForProcess(PWINCHILDCAREWORKER pWorker, PWINCHILD pChild, HANDLE hProcess, 820 WCHAR const *pwszJob, BOOL fCatchOutput) 816 821 { 817 822 DWORD const msStart = GetTickCount(); … … 850 855 mkWinChildcareWorkerCatchOutput(pChild, &pWorker->StdErr, TRUE /*fFlushing*/); 851 856 } 852 return ;857 return dwExitCode; 853 858 } 854 859 } … … 891 896 if (pChild->iExitCode == 0) 892 897 pChild->iExitCode = -4242; 893 return ;898 return pChild->iExitCode; 894 899 } 895 900 } … … 930 935 * @param pwszzEnvironment The enviornment block. 931 936 */ 932 static int mkWinChildcareWorkerCreateProcess(PWINCHILDCAREWORKER pWorker, PWINCHILD pChild, WCHAR const *pwszImageName, 933 WCHAR const *pwszCommandLine, WCHAR const *pwszzEnvironment) 937 static int mkWinChildcareWorkerCreateProcess(PWINCHILDCAREWORKER pWorker, WCHAR const *pwszImageName, 938 WCHAR const *pwszCommandLine, WCHAR const *pwszzEnvironment, WCHAR const *pwszCwd, 939 BOOL pafReplace[3], HANDLE pahChild[3], BOOL fCatchOutput, HANDLE *phProcess) 934 940 { 935 941 PROCESS_INFORMATION ProcInfo; 936 942 STARTUPINFOW StartupInfo; 937 943 DWORD fFlags = CREATE_UNICODE_ENVIRONMENT; 938 BOOL const fHaveHandles = pChild->u.Process.hStdErr != INVALID_HANDLE_VALUE 939 || pChild->u.Process.hStdOut != INVALID_HANDLE_VALUE; 944 BOOL const fHaveHandles = pafReplace[0] | pafReplace[1] | pafReplace[2]; 940 945 BOOL fRet; 941 946 DWORD dwErr; … … 965 970 StartupInfo.cbReserved2 = 0; 966 971 if ( !fHaveHandles 967 && ! pChild->u.Process.fCatchOutput)972 && !fCatchOutput) 968 973 StartupInfo.dwFlags &= ~STARTF_USESTDHANDLES; 969 974 else … … 999 1004 1000 1005 fRet = CreateProcessW((WCHAR *)pwszImageName, (WCHAR *)pwszCommandLine, NULL /*pProcSecAttr*/, NULL /*pThreadSecAttr*/, 1001 FALSE /*fInheritHandles*/, fFlags, (WCHAR *)pwszzEnvironment, NULL /*pwsz*/, &StartupInfo, &ProcInfo);1006 FALSE /*fInheritHandles*/, fFlags, (WCHAR *)pwszzEnvironment, pwszCwd, &StartupInfo, &ProcInfo); 1002 1007 dwErr = GetLastError(); 1003 1008 … … 1006 1011 #endif 1007 1012 if (fRet) 1008 pChild->u.Process.hProcess = ProcInfo.hProcess;1013 *phProcess = ProcInfo.hProcess; 1009 1014 else 1010 1015 { 1011 1016 fprintf(stderr, "CreateProcess(%ls) failed: %u\n", pwszImageName, dwErr); 1012 return pChild->iExitCode =(int)dwErr;1017 return (int)dwErr; 1013 1018 } 1014 1019 … … 1022 1027 * First do handle inhertiance as that's the most complicated. 1023 1028 */ 1024 if (fHaveHandles || pChild->u.Process.fCatchOutput) 1025 { 1026 char szErrMsg[128]; 1027 BOOL afReplace[3]; 1028 HANDLE ahChild[3]; 1029 1030 afReplace[0] = FALSE; 1031 ahChild[0] = INVALID_HANDLE_VALUE; 1032 if (fHaveHandles) 1033 { 1034 afReplace[1] = pChild->u.Process.hStdOut != INVALID_HANDLE_VALUE; 1035 ahChild[1] = pChild->u.Process.hStdOut; 1036 afReplace[2] = pChild->u.Process.hStdErr != INVALID_HANDLE_VALUE; 1037 ahChild[2] = pChild->u.Process.hStdErr; 1038 } 1039 else 1040 { 1041 afReplace[1] = TRUE; 1042 ahChild[1] = pWorker->StdOut.hPipeChild; 1043 afReplace[2] = TRUE; 1044 ahChild[2] = pWorker->StdErr.hPipeChild; 1045 } 1046 1047 dwErr = nt_child_inject_standard_handles(ProcInfo.hProcess, afReplace, ahChild, szErrMsg, sizeof(szErrMsg)); 1029 if (fHaveHandles || fCatchOutput) 1030 { 1031 char szErrMsg[128]; 1032 if (fCatchOutput) 1033 { 1034 if (!pafReplace[1]) 1035 { 1036 pafReplace[1] = TRUE; 1037 pahChild[1] = pWorker->StdOut.hPipeChild; 1038 } 1039 if (!pafReplace[2]) 1040 { 1041 pafReplace[2] = TRUE; 1042 pahChild[2] = pWorker->StdErr.hPipeChild; 1043 } 1044 } 1045 dwErr = nt_child_inject_standard_handles(ProcInfo.hProcess, pafReplace, pahChild, szErrMsg, sizeof(szErrMsg)); 1048 1046 if (dwErr != 0) 1049 1047 fprintf(stderr, "%s\n", szErrMsg); … … 1094 1092 1095 1093 /* 1096 * Close unnecessary handles. 1097 */ 1098 mkWinChildcareWorkerCloseStandardHandles(pChild); 1094 * Close unnecessary handles and cache the image. 1095 */ 1099 1096 CloseHandle(ProcInfo.hThread); 1097 kmk_cache_exec_image_w(pwszImageName); 1098 return 0; 1099 } 1100 1101 /** 1102 * Converts a argument vector that has already been quoted correctly. 1103 * 1104 * The argument vector is typically the result of quote_argv(). 1105 * 1106 * @returns 0 on success, non-zero on failure. 1107 * @param papszArgs The argument vector to convert. 1108 * @param ppwszCommandLine Where to return the command line. 1109 */ 1110 static int mkWinChildcareWorkerConvertQuotedArgvToCommandline(char **papszArgs, WCHAR **ppwszCommandLine) 1111 { 1112 WCHAR *pwszCmdLine; 1113 WCHAR *pwszDst; 1114 1115 /* 1116 * Calc length the converted length. 1117 */ 1118 unsigned cwcNeeded = 1; 1119 unsigned i = 0; 1120 const char *pszSrc; 1121 while ((pszSrc = papszArgs[i]) != NULL) 1122 { 1123 int cwcThis = MultiByteToWideChar(CP_ACP, 0 /*fFlags*/, pszSrc, -1, NULL, 0); 1124 if (cwcThis > 0 || *pszSrc == '\0') 1125 cwcNeeded += cwcThis + 1; 1126 else 1127 { 1128 DWORD dwErr = GetLastError(); 1129 fprintf(stderr, _("MultiByteToWideChar failed to convert argv[%u] (%s): %u\n"), i, pszSrc, dwErr); 1130 return dwErr; 1131 } 1132 i++; 1133 } 1134 1135 /* 1136 * Allocate and do the conversion. 1137 */ 1138 pwszCmdLine = pwszDst = (WCHAR *)xmalloc(cwcNeeded * sizeof(WCHAR)); 1139 i = 0; 1140 while ((pszSrc = papszArgs[i]) != NULL) 1141 { 1142 int cwcThis; 1143 if (i > 0) 1144 { 1145 *pwszDst++ = ' '; 1146 cwcNeeded--; 1147 } 1148 1149 cwcThis = MultiByteToWideChar(CP_ACP, 0 /*fFlags*/, pszSrc, -1, pwszDst, cwcNeeded); 1150 if (!cwcThis && *pszSrc != '\0') 1151 { 1152 DWORD dwErr = GetLastError(); 1153 fprintf(stderr, _("MultiByteToWideChar failed to convert argv[%u] (%s): %u\n"), i, pszSrc, dwErr); 1154 free(pwszCmdLine); 1155 return dwErr; 1156 } 1157 if (cwcThis > 0 && pwszDst[cwcThis - 1] == '\0') 1158 cwcThis--; 1159 pwszDst += cwcThis; 1160 cwcNeeded -= cwcThis; 1161 i++; 1162 } 1163 *pwszDst++ = '\0'; 1164 1165 *ppwszCommandLine = pwszCmdLine; 1100 1166 return 0; 1101 1167 } … … 1707 1773 { 1708 1774 fprintf(stderr, "%s: not found!\n", pszArg0); 1709 //__debugbreak();1710 1775 dwErr = ERROR_FILE_NOT_FOUND; 1711 1776 } … … 1920 1985 if (rc == 0) 1921 1986 { 1922 rc = mkWinChildcareWorkerCreateProcess(pWorker, pChild, pwszImageName, pwszCommandLine, pwszzEnvironment); 1987 BOOL afReplace[3] = { FALSE, pChild->u.Process.hStdOut != INVALID_HANDLE_VALUE, pChild->u.Process.hStdErr != INVALID_HANDLE_VALUE }; 1988 HANDLE ahChild[3] = { INVALID_HANDLE_VALUE, pChild->u.Process.hStdOut, pChild->u.Process.hStdErr }; 1989 rc = mkWinChildcareWorkerCreateProcess(pWorker, pwszImageName, pwszCommandLine, pwszzEnvironment, 1990 NULL /*pwszCwd*/, afReplace, ahChild, pChild->u.Process.fCatchOutput, 1991 &pChild->u.Process.hProcess); 1992 mkWinChildcareWorkerCloseStandardHandles(pChild); 1923 1993 if (rc == 0) 1924 1994 { … … 1958 2028 { 1959 2029 PCKMKBUILTINENTRY pBuiltIn = pChild->u.BuiltIn.pBuiltIn; 1960 KMKBUILTINCTX Ctx = { pBuiltIn->uName.s.sz, pChild->pMkChild ? &pChild->pMkChild->output : NULL }; 2030 KMKBUILTINCTX Ctx = 2031 { 2032 pBuiltIn->uName.s.sz, 2033 pChild->pMkChild ? &pChild->pMkChild->output : NULL, 2034 pWorker, 2035 }; 1961 2036 if (pBuiltIn->uFnSignature == FN_SIG_MAIN) 1962 2037 pChild->iExitCode = pBuiltIn->u.pfnMain(pChild->u.BuiltIn.cArgs, pChild->u.BuiltIn.papszArgs, … … 1964 2039 else if (pBuiltIn->uFnSignature == FN_SIG_MAIN_SPAWNS) 1965 2040 pChild->iExitCode = pBuiltIn->u.pfnMainSpawns(pChild->u.BuiltIn.cArgs, pChild->u.BuiltIn.papszArgs, 1966 pChild->u.BuiltIn.papszEnv, &Ctx, pChild->pMkChild, NULL );2041 pChild->u.BuiltIn.papszEnv, &Ctx, pChild->pMkChild, NULL /*pPid*/); 1967 2042 else 1968 2043 { … … 2115 2190 PWINCHILD pTailExpect; 2116 2191 2192 pWorker->pCurChild = pChild; 2117 2193 switch (pChild->enmType) 2118 2194 { … … 2137 2213 assert(0); 2138 2214 } 2215 pWorker->pCurChild = NULL; 2139 2216 2140 2217 /* … … 2821 2898 } 2822 2899 2900 2901 /** 2902 * New interface used by redirect.c for spawning and waitin on a child. 2903 * 2904 * This interface is only used when kmk_builtin_redirect is already running on 2905 * a worker thread. 2906 * 2907 * @returns exit status. 2908 * @param pvWorker The worker instance. 2909 * @param pszExecutable The executable image to run. 2910 * @param papszArgs Argument vector. 2911 * @param fQuotedArgv Whether the argument vector is already quoted and 2912 * just need some space to be turned into a command 2913 * line. 2914 * @param papszEnvVars Environment vector. 2915 * @param pszCwd The working directory of the child. Optional. 2916 * @param pafReplace Which standard handles to replace. Maybe modified! 2917 * @param pahReplace The replacement handles. Maybe modified! 2918 * 2919 */ 2920 int MkWinChildBuiltInExecChild(void *pvWorker, const char *pszExecutable, char **papszArgs, BOOL fQuotedArgv, 2921 char **papszEnvVars, const char *pszCwd, BOOL pafReplace[3], HANDLE pahReplace[3]) 2922 { 2923 PWINCHILDCAREWORKER pWorker = (PWINCHILDCAREWORKER)pvWorker; 2924 WCHAR *pwszSearchPath = NULL; 2925 WCHAR *pwszzEnvironment = NULL; 2926 WCHAR *pwszCommandLine = NULL; 2927 WCHAR *pwszImageName = NULL; 2928 WCHAR *pwszCwd = NULL; 2929 BOOL fNeedShell = FALSE; 2930 int rc; 2931 assert(pWorker->uMagic == WINCHILDCAREWORKER_MAGIC); 2932 assert(pWorker->pCurChild != NULL && pWorker->pCurChild->uMagic == WINCHILD_MAGIC); 2933 2934 /* 2935 * Convert the CWD first since it's optional and we don't need to clean 2936 * up anything here if it fails. 2937 */ 2938 if (pszCwd) 2939 { 2940 size_t cchCwd = strlen(pszCwd); 2941 int cwcCwd = MultiByteToWideChar(CP_ACP, 0 /*fFlags*/, pszCwd, cchCwd + 1, NULL, 0); 2942 pwszCwd = xmalloc((cwcCwd + 1) * sizeof(WCHAR)); /* (+1 in case cwcCwd is 0) */ 2943 cwcCwd = MultiByteToWideChar(CP_ACP, 0 /*fFlags*/, pszCwd, cchCwd + 1, pwszCwd, cwcCwd + 1); 2944 if (!cwcCwd) 2945 { 2946 rc = GetLastError(); 2947 fprintf(stderr, _("MultiByteToWideChar failed to convert CWD (%s): %u\n"), pszCwd, (unsigned)rc); 2948 return rc; 2949 } 2950 } 2951 2952 /* 2953 * Before we search for the image, we convert the environment so we don't 2954 * have to traverse it twice to find the PATH. 2955 */ 2956 rc = mkWinChildcareWorkerConvertEnvironment(papszEnvVars ? papszEnvVars : environ, 0/*cbEnvStrings*/, 2957 &pwszzEnvironment, &pwszSearchPath); 2958 /* 2959 * Find the executable and maybe checking if it's a shell script, then 2960 * convert it to a command line. 2961 */ 2962 if (rc == 0) 2963 rc = mkWinChildcareWorkerFindImage(pszExecutable, pwszSearchPath, pwszzEnvironment, 2964 NULL /*pszNull*/, &pwszImageName, &fNeedShell); 2965 if (rc == 0) 2966 { 2967 assert(!fNeedShell); 2968 if (!fQuotedArgv) 2969 rc = mkWinChildcareWorkerConvertCommandline(papszArgs, 0 /*fFlags*/, &pwszCommandLine); 2970 else 2971 rc = mkWinChildcareWorkerConvertQuotedArgvToCommandline(papszArgs, &pwszCommandLine); 2972 2973 /* 2974 * Create the child process. 2975 */ 2976 if (rc == 0) 2977 { 2978 HANDLE hProcess; 2979 rc = mkWinChildcareWorkerCreateProcess(pWorker, pwszImageName, pwszCommandLine, pwszzEnvironment, 2980 pwszCwd, pafReplace, pahReplace, TRUE /*fCatchOutput*/, &hProcess); 2981 if (rc == 0) 2982 { 2983 /* 2984 * Wait for the child to complete. 2985 */ 2986 rc = mkWinChildcareWorkerWaitForProcess(pWorker, pWorker->pCurChild, hProcess, pwszImageName, 2987 TRUE /*fCatchOutput*/); 2988 CloseHandle(hProcess); 2989 } 2990 } 2991 } 2992 2993 free(pwszCwd); 2994 free(pwszCommandLine); 2995 free(pwszImageName); 2996 free(pwszzEnvironment); 2997 2998 return rc; 2999 } 3000 2823 3001 #endif /* CONFIG_NEW_WIN_CHILDREN */ 2824 3002 -
trunk/src/kmk/w32/winchildren.h
r3172 r3195 41 41 int MkWinChildCreateSubmit(intptr_t hEvent, void *pvSubmitWorker, pid_t *pPid); 42 42 int MkWinChildCreateRedirect(intptr_t hProcess, pid_t *pPid); 43 # ifdef DECLARE_HANDLE 44 int MkWinChildBuiltInExecChild(void *pvWorker, const char *pszExecutable, char **papszArgs, BOOL fQuotedArgv, 45 char **papszEnvVars, const char *pszCwd, BOOL pafReplace[3], HANDLE pahReplace[3]); 46 # endif 43 47 #endif 44 48 int MkWinChildKill(pid_t pid, int iSignal, struct child *pMkChild);
Note:
See TracChangeset
for help on using the changeset viewer.