process.c 38 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355
  1. /* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
  2. *
  3. * Permission is hereby granted, free of charge, to any person obtaining a copy
  4. * of this software and associated documentation files (the "Software"), to
  5. * deal in the Software without restriction, including without limitation the
  6. * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
  7. * sell copies of the Software, and to permit persons to whom the Software is
  8. * furnished to do so, subject to the following conditions:
  9. *
  10. * The above copyright notice and this permission notice shall be included in
  11. * all copies or substantial portions of the Software.
  12. *
  13. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  14. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  15. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  16. * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  17. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  18. * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
  19. * IN THE SOFTWARE.
  20. */
  21. #include <assert.h>
  22. #include <io.h>
  23. #include <stdio.h>
  24. #include <stdlib.h>
  25. #include <signal.h>
  26. #include <limits.h>
  27. #include <wchar.h>
  28. #include <malloc.h> /* alloca */
  29. #include "uv.h"
  30. #include "internal.h"
  31. #include "handle-inl.h"
  32. #include "req-inl.h"
  33. #define SIGKILL 9
  34. typedef struct env_var {
  35. const WCHAR* const wide;
  36. const WCHAR* const wide_eq;
  37. const size_t len; /* including null or '=' */
  38. } env_var_t;
  39. #define E_V(str) { L##str, L##str L"=", sizeof(str) }
  40. static const env_var_t required_vars[] = { /* keep me sorted */
  41. E_V("HOMEDRIVE"),
  42. E_V("HOMEPATH"),
  43. E_V("LOGONSERVER"),
  44. E_V("PATH"),
  45. E_V("SYSTEMDRIVE"),
  46. E_V("SYSTEMROOT"),
  47. E_V("TEMP"),
  48. E_V("USERDOMAIN"),
  49. E_V("USERNAME"),
  50. E_V("USERPROFILE"),
  51. E_V("WINDIR"),
  52. };
  53. static HANDLE uv_global_job_handle_;
  54. static uv_once_t uv_global_job_handle_init_guard_ = UV_ONCE_INIT;
  55. static void uv__init_global_job_handle(void) {
  56. /* Create a job object and set it up to kill all contained processes when
  57. * it's closed. Since this handle is made non-inheritable and we're not
  58. * giving it to anyone, we're the only process holding a reference to it.
  59. * That means that if this process exits it is closed and all the processes
  60. * it contains are killed. All processes created with uv_spawn that are not
  61. * spawned with the UV_PROCESS_DETACHED flag are assigned to this job.
  62. *
  63. * We're setting the JOB_OBJECT_LIMIT_SILENT_BREAKAWAY_OK flag so only the
  64. * processes that we explicitly add are affected, and *their* subprocesses
  65. * are not. This ensures that our child processes are not limited in their
  66. * ability to use job control on Windows versions that don't deal with
  67. * nested jobs (prior to Windows 8 / Server 2012). It also lets our child
  68. * processes created detached processes without explicitly breaking away
  69. * from job control (which uv_spawn doesn't, either).
  70. */
  71. SECURITY_ATTRIBUTES attr;
  72. JOBOBJECT_EXTENDED_LIMIT_INFORMATION info;
  73. memset(&attr, 0, sizeof attr);
  74. attr.bInheritHandle = FALSE;
  75. memset(&info, 0, sizeof info);
  76. info.BasicLimitInformation.LimitFlags =
  77. JOB_OBJECT_LIMIT_BREAKAWAY_OK |
  78. JOB_OBJECT_LIMIT_SILENT_BREAKAWAY_OK |
  79. JOB_OBJECT_LIMIT_DIE_ON_UNHANDLED_EXCEPTION |
  80. JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE;
  81. uv_global_job_handle_ = CreateJobObjectW(&attr, NULL);
  82. if (uv_global_job_handle_ == NULL)
  83. uv_fatal_error(GetLastError(), "CreateJobObjectW");
  84. if (!SetInformationJobObject(uv_global_job_handle_,
  85. JobObjectExtendedLimitInformation,
  86. &info,
  87. sizeof info))
  88. uv_fatal_error(GetLastError(), "SetInformationJobObject");
  89. if (!AssignProcessToJobObject(uv_global_job_handle_, GetCurrentProcess())) {
  90. /* Make sure this handle is functional. The Windows kernel has a bug that
  91. * if the first use of AssignProcessToJobObject is for a Windows Store
  92. * program, subsequent attempts to use the handle with fail with
  93. * INVALID_PARAMETER (87). This is possibly because all uses of the handle
  94. * must be for the same Terminal Services session. We can ensure it is tied
  95. * to our current session now by adding ourself to it. We could remove
  96. * ourself afterwards, but there doesn't seem to be a reason to.
  97. */
  98. DWORD err = GetLastError();
  99. if (err != ERROR_ACCESS_DENIED)
  100. uv_fatal_error(err, "AssignProcessToJobObject");
  101. }
  102. }
  103. static int uv__utf8_to_utf16_alloc(const char* s, WCHAR** ws_ptr) {
  104. int ws_len, r;
  105. WCHAR* ws;
  106. ws_len = MultiByteToWideChar(CP_UTF8,
  107. 0,
  108. s,
  109. -1,
  110. NULL,
  111. 0);
  112. if (ws_len <= 0) {
  113. return GetLastError();
  114. }
  115. ws = (WCHAR*) uv__malloc(ws_len * sizeof(WCHAR));
  116. if (ws == NULL) {
  117. return ERROR_OUTOFMEMORY;
  118. }
  119. r = MultiByteToWideChar(CP_UTF8,
  120. 0,
  121. s,
  122. -1,
  123. ws,
  124. ws_len);
  125. assert(r == ws_len);
  126. *ws_ptr = ws;
  127. return 0;
  128. }
  129. static void uv__process_init(uv_loop_t* loop, uv_process_t* handle) {
  130. uv__handle_init(loop, (uv_handle_t*) handle, UV_PROCESS);
  131. handle->exit_cb = NULL;
  132. handle->pid = 0;
  133. handle->exit_signal = 0;
  134. handle->wait_handle = INVALID_HANDLE_VALUE;
  135. handle->process_handle = INVALID_HANDLE_VALUE;
  136. handle->child_stdio_buffer = NULL;
  137. handle->exit_cb_pending = 0;
  138. UV_REQ_INIT(&handle->exit_req, UV_PROCESS_EXIT);
  139. handle->exit_req.data = handle;
  140. }
  141. /*
  142. * Path search functions
  143. */
  144. /*
  145. * Helper function for search_path
  146. */
  147. static WCHAR* search_path_join_test(const WCHAR* dir,
  148. size_t dir_len,
  149. const WCHAR* name,
  150. size_t name_len,
  151. const WCHAR* ext,
  152. size_t ext_len,
  153. const WCHAR* cwd,
  154. size_t cwd_len) {
  155. WCHAR *result, *result_pos;
  156. DWORD attrs;
  157. if (dir_len > 2 &&
  158. ((dir[0] == L'\\' || dir[0] == L'/') &&
  159. (dir[1] == L'\\' || dir[1] == L'/'))) {
  160. /* It's a UNC path so ignore cwd */
  161. cwd_len = 0;
  162. } else if (dir_len >= 1 && (dir[0] == L'/' || dir[0] == L'\\')) {
  163. /* It's a full path without drive letter, use cwd's drive letter only */
  164. cwd_len = 2;
  165. } else if (dir_len >= 2 && dir[1] == L':' &&
  166. (dir_len < 3 || (dir[2] != L'/' && dir[2] != L'\\'))) {
  167. /* It's a relative path with drive letter (ext.g. D:../some/file)
  168. * Replace drive letter in dir by full cwd if it points to the same drive,
  169. * otherwise use the dir only.
  170. */
  171. if (cwd_len < 2 || _wcsnicmp(cwd, dir, 2) != 0) {
  172. cwd_len = 0;
  173. } else {
  174. dir += 2;
  175. dir_len -= 2;
  176. }
  177. } else if (dir_len > 2 && dir[1] == L':') {
  178. /* It's an absolute path with drive letter
  179. * Don't use the cwd at all
  180. */
  181. cwd_len = 0;
  182. }
  183. /* Allocate buffer for output */
  184. result = result_pos = (WCHAR*)uv__malloc(sizeof(WCHAR) *
  185. (cwd_len + 1 + dir_len + 1 + name_len + 1 + ext_len + 1));
  186. /* Copy cwd */
  187. wcsncpy(result_pos, cwd, cwd_len);
  188. result_pos += cwd_len;
  189. /* Add a path separator if cwd didn't end with one */
  190. if (cwd_len && wcsrchr(L"\\/:", result_pos[-1]) == NULL) {
  191. result_pos[0] = L'\\';
  192. result_pos++;
  193. }
  194. /* Copy dir */
  195. wcsncpy(result_pos, dir, dir_len);
  196. result_pos += dir_len;
  197. /* Add a separator if the dir didn't end with one */
  198. if (dir_len && wcsrchr(L"\\/:", result_pos[-1]) == NULL) {
  199. result_pos[0] = L'\\';
  200. result_pos++;
  201. }
  202. /* Copy filename */
  203. wcsncpy(result_pos, name, name_len);
  204. result_pos += name_len;
  205. if (ext_len) {
  206. /* Add a dot if the filename didn't end with one */
  207. if (name_len && result_pos[-1] != '.') {
  208. result_pos[0] = L'.';
  209. result_pos++;
  210. }
  211. /* Copy extension */
  212. wcsncpy(result_pos, ext, ext_len);
  213. result_pos += ext_len;
  214. }
  215. /* Null terminator */
  216. result_pos[0] = L'\0';
  217. attrs = GetFileAttributesW(result);
  218. if (attrs != INVALID_FILE_ATTRIBUTES &&
  219. !(attrs & FILE_ATTRIBUTE_DIRECTORY)) {
  220. return result;
  221. }
  222. uv__free(result);
  223. return NULL;
  224. }
  225. /*
  226. * Helper function for search_path
  227. */
  228. static WCHAR* path_search_walk_ext(const WCHAR *dir,
  229. size_t dir_len,
  230. const WCHAR *name,
  231. size_t name_len,
  232. WCHAR *cwd,
  233. size_t cwd_len,
  234. int name_has_ext) {
  235. WCHAR* result;
  236. /* If the name itself has a nonempty extension, try this extension first */
  237. if (name_has_ext) {
  238. result = search_path_join_test(dir, dir_len,
  239. name, name_len,
  240. L"", 0,
  241. cwd, cwd_len);
  242. if (result != NULL) {
  243. return result;
  244. }
  245. }
  246. /* Try .com extension */
  247. result = search_path_join_test(dir, dir_len,
  248. name, name_len,
  249. L"com", 3,
  250. cwd, cwd_len);
  251. if (result != NULL) {
  252. return result;
  253. }
  254. /* Try .exe extension */
  255. result = search_path_join_test(dir, dir_len,
  256. name, name_len,
  257. L"exe", 3,
  258. cwd, cwd_len);
  259. if (result != NULL) {
  260. return result;
  261. }
  262. return NULL;
  263. }
  264. /*
  265. * search_path searches the system path for an executable filename -
  266. * the windows API doesn't provide this as a standalone function nor as an
  267. * option to CreateProcess.
  268. *
  269. * It tries to return an absolute filename.
  270. *
  271. * Furthermore, it tries to follow the semantics that cmd.exe, with this
  272. * exception that PATHEXT environment variable isn't used. Since CreateProcess
  273. * can start only .com and .exe files, only those extensions are tried. This
  274. * behavior equals that of msvcrt's spawn functions.
  275. *
  276. * - Do not search the path if the filename already contains a path (either
  277. * relative or absolute).
  278. *
  279. * - If there's really only a filename, check the current directory for file,
  280. * then search all path directories.
  281. *
  282. * - If filename specified has *any* extension, search for the file with the
  283. * specified extension first.
  284. *
  285. * - If the literal filename is not found in a directory, try *appending*
  286. * (not replacing) .com first and then .exe.
  287. *
  288. * - The path variable may contain relative paths; relative paths are relative
  289. * to the cwd.
  290. *
  291. * - Directories in path may or may not end with a trailing backslash.
  292. *
  293. * - CMD does not trim leading/trailing whitespace from path/pathex entries
  294. * nor from the environment variables as a whole.
  295. *
  296. * - When cmd.exe cannot read a directory, it will just skip it and go on
  297. * searching. However, unlike posix-y systems, it will happily try to run a
  298. * file that is not readable/executable; if the spawn fails it will not
  299. * continue searching.
  300. *
  301. * UNC path support: we are dealing with UNC paths in both the path and the
  302. * filename. This is a deviation from what cmd.exe does (it does not let you
  303. * start a program by specifying an UNC path on the command line) but this is
  304. * really a pointless restriction.
  305. *
  306. */
  307. static WCHAR* search_path(const WCHAR *file,
  308. WCHAR *cwd,
  309. const WCHAR *path) {
  310. int file_has_dir;
  311. WCHAR* result = NULL;
  312. WCHAR *file_name_start;
  313. WCHAR *dot;
  314. const WCHAR *dir_start, *dir_end, *dir_path;
  315. size_t dir_len;
  316. int name_has_ext;
  317. size_t file_len = wcslen(file);
  318. size_t cwd_len = wcslen(cwd);
  319. /* If the caller supplies an empty filename,
  320. * we're not gonna return c:\windows\.exe -- GFY!
  321. */
  322. if (file_len == 0
  323. || (file_len == 1 && file[0] == L'.')) {
  324. return NULL;
  325. }
  326. /* Find the start of the filename so we can split the directory from the
  327. * name. */
  328. for (file_name_start = (WCHAR*)file + file_len;
  329. file_name_start > file
  330. && file_name_start[-1] != L'\\'
  331. && file_name_start[-1] != L'/'
  332. && file_name_start[-1] != L':';
  333. file_name_start--);
  334. file_has_dir = file_name_start != file;
  335. /* Check if the filename includes an extension */
  336. dot = wcschr(file_name_start, L'.');
  337. name_has_ext = (dot != NULL && dot[1] != L'\0');
  338. if (file_has_dir) {
  339. /* The file has a path inside, don't use path */
  340. result = path_search_walk_ext(
  341. file, file_name_start - file,
  342. file_name_start, file_len - (file_name_start - file),
  343. cwd, cwd_len,
  344. name_has_ext);
  345. } else {
  346. dir_end = path;
  347. if (NeedCurrentDirectoryForExePathW(L"")) {
  348. /* The file is really only a name; look in cwd first, then scan path */
  349. result = path_search_walk_ext(L"", 0,
  350. file, file_len,
  351. cwd, cwd_len,
  352. name_has_ext);
  353. }
  354. while (result == NULL) {
  355. if (dir_end == NULL || *dir_end == L'\0') {
  356. break;
  357. }
  358. /* Skip the separator that dir_end now points to */
  359. if (dir_end != path || *path == L';') {
  360. dir_end++;
  361. }
  362. /* Next slice starts just after where the previous one ended */
  363. dir_start = dir_end;
  364. /* If path is quoted, find quote end */
  365. if (*dir_start == L'"' || *dir_start == L'\'') {
  366. dir_end = wcschr(dir_start + 1, *dir_start);
  367. if (dir_end == NULL) {
  368. dir_end = wcschr(dir_start, L'\0');
  369. }
  370. }
  371. /* Slice until the next ; or \0 is found */
  372. dir_end = wcschr(dir_end, L';');
  373. if (dir_end == NULL) {
  374. dir_end = wcschr(dir_start, L'\0');
  375. }
  376. /* If the slice is zero-length, don't bother */
  377. if (dir_end - dir_start == 0) {
  378. continue;
  379. }
  380. dir_path = dir_start;
  381. dir_len = dir_end - dir_start;
  382. /* Adjust if the path is quoted. */
  383. if (dir_path[0] == '"' || dir_path[0] == '\'') {
  384. ++dir_path;
  385. --dir_len;
  386. }
  387. if (dir_path[dir_len - 1] == '"' || dir_path[dir_len - 1] == '\'') {
  388. --dir_len;
  389. }
  390. result = path_search_walk_ext(dir_path, dir_len,
  391. file, file_len,
  392. cwd, cwd_len,
  393. name_has_ext);
  394. }
  395. }
  396. return result;
  397. }
  398. /*
  399. * Quotes command line arguments
  400. * Returns a pointer to the end (next char to be written) of the buffer
  401. */
  402. WCHAR* quote_cmd_arg(const WCHAR *source, WCHAR *target) {
  403. size_t len = wcslen(source);
  404. size_t i;
  405. int quote_hit;
  406. WCHAR* start;
  407. if (len == 0) {
  408. /* Need double quotation for empty argument */
  409. *(target++) = L'"';
  410. *(target++) = L'"';
  411. return target;
  412. }
  413. if (NULL == wcspbrk(source, L" \t\"")) {
  414. /* No quotation needed */
  415. wcsncpy(target, source, len);
  416. target += len;
  417. return target;
  418. }
  419. if (NULL == wcspbrk(source, L"\"\\")) {
  420. /*
  421. * No embedded double quotes or backlashes, so I can just wrap
  422. * quote marks around the whole thing.
  423. */
  424. *(target++) = L'"';
  425. wcsncpy(target, source, len);
  426. target += len;
  427. *(target++) = L'"';
  428. return target;
  429. }
  430. /*
  431. * Expected input/output:
  432. * input : hello"world
  433. * output: "hello\"world"
  434. * input : hello""world
  435. * output: "hello\"\"world"
  436. * input : hello\world
  437. * output: hello\world
  438. * input : hello\\world
  439. * output: hello\\world
  440. * input : hello\"world
  441. * output: "hello\\\"world"
  442. * input : hello\\"world
  443. * output: "hello\\\\\"world"
  444. * input : hello world\
  445. * output: "hello world\\"
  446. */
  447. *(target++) = L'"';
  448. start = target;
  449. quote_hit = 1;
  450. for (i = len; i > 0; --i) {
  451. *(target++) = source[i - 1];
  452. if (quote_hit && source[i - 1] == L'\\') {
  453. *(target++) = L'\\';
  454. } else if(source[i - 1] == L'"') {
  455. quote_hit = 1;
  456. *(target++) = L'\\';
  457. } else {
  458. quote_hit = 0;
  459. }
  460. }
  461. target[0] = L'\0';
  462. wcsrev(start);
  463. *(target++) = L'"';
  464. return target;
  465. }
  466. int make_program_args(char** args, int verbatim_arguments, WCHAR** dst_ptr) {
  467. char** arg;
  468. WCHAR* dst = NULL;
  469. WCHAR* temp_buffer = NULL;
  470. size_t dst_len = 0;
  471. size_t temp_buffer_len = 0;
  472. WCHAR* pos;
  473. int arg_count = 0;
  474. int err = 0;
  475. /* Count the required size. */
  476. for (arg = args; *arg; arg++) {
  477. DWORD arg_len;
  478. arg_len = MultiByteToWideChar(CP_UTF8,
  479. 0,
  480. *arg,
  481. -1,
  482. NULL,
  483. 0);
  484. if (arg_len == 0) {
  485. return GetLastError();
  486. }
  487. dst_len += arg_len;
  488. if (arg_len > temp_buffer_len)
  489. temp_buffer_len = arg_len;
  490. arg_count++;
  491. }
  492. /* Adjust for potential quotes. Also assume the worst-case scenario that
  493. * every character needs escaping, so we need twice as much space. */
  494. dst_len = dst_len * 2 + arg_count * 2;
  495. /* Allocate buffer for the final command line. */
  496. dst = (WCHAR*) uv__malloc(dst_len * sizeof(WCHAR));
  497. if (dst == NULL) {
  498. err = ERROR_OUTOFMEMORY;
  499. goto error;
  500. }
  501. /* Allocate temporary working buffer. */
  502. temp_buffer = (WCHAR*) uv__malloc(temp_buffer_len * sizeof(WCHAR));
  503. if (temp_buffer == NULL) {
  504. err = ERROR_OUTOFMEMORY;
  505. goto error;
  506. }
  507. pos = dst;
  508. for (arg = args; *arg; arg++) {
  509. DWORD arg_len;
  510. /* Convert argument to wide char. */
  511. arg_len = MultiByteToWideChar(CP_UTF8,
  512. 0,
  513. *arg,
  514. -1,
  515. temp_buffer,
  516. (int) (dst + dst_len - pos));
  517. if (arg_len == 0) {
  518. err = GetLastError();
  519. goto error;
  520. }
  521. if (verbatim_arguments) {
  522. /* Copy verbatim. */
  523. wcscpy(pos, temp_buffer);
  524. pos += arg_len - 1;
  525. } else {
  526. /* Quote/escape, if needed. */
  527. pos = quote_cmd_arg(temp_buffer, pos);
  528. }
  529. *pos++ = *(arg + 1) ? L' ' : L'\0';
  530. }
  531. uv__free(temp_buffer);
  532. *dst_ptr = dst;
  533. return 0;
  534. error:
  535. uv__free(dst);
  536. uv__free(temp_buffer);
  537. return err;
  538. }
  539. int env_strncmp(const wchar_t* a, int na, const wchar_t* b) {
  540. wchar_t* a_eq;
  541. wchar_t* b_eq;
  542. wchar_t* A;
  543. wchar_t* B;
  544. int nb;
  545. int r;
  546. if (na < 0) {
  547. a_eq = wcschr(a, L'=');
  548. assert(a_eq);
  549. na = (int)(long)(a_eq - a);
  550. } else {
  551. na--;
  552. }
  553. b_eq = wcschr(b, L'=');
  554. assert(b_eq);
  555. nb = b_eq - b;
  556. A = alloca((na+1) * sizeof(wchar_t));
  557. B = alloca((nb+1) * sizeof(wchar_t));
  558. r = LCMapStringW(LOCALE_INVARIANT, LCMAP_UPPERCASE, a, na, A, na);
  559. assert(r==na);
  560. A[na] = L'\0';
  561. r = LCMapStringW(LOCALE_INVARIANT, LCMAP_UPPERCASE, b, nb, B, nb);
  562. assert(r==nb);
  563. B[nb] = L'\0';
  564. for (;;) {
  565. wchar_t AA = *A++;
  566. wchar_t BB = *B++;
  567. if (AA < BB) {
  568. return -1;
  569. } else if (AA > BB) {
  570. return 1;
  571. } else if (!AA && !BB) {
  572. return 0;
  573. }
  574. }
  575. }
  576. static int qsort_wcscmp(const void *a, const void *b) {
  577. wchar_t* astr = *(wchar_t* const*)a;
  578. wchar_t* bstr = *(wchar_t* const*)b;
  579. return env_strncmp(astr, -1, bstr);
  580. }
  581. /*
  582. * The way windows takes environment variables is different than what C does;
  583. * Windows wants a contiguous block of null-terminated strings, terminated
  584. * with an additional null.
  585. *
  586. * Windows has a few "essential" environment variables. winsock will fail
  587. * to initialize if SYSTEMROOT is not defined; some APIs make reference to
  588. * TEMP. SYSTEMDRIVE is probably also important. We therefore ensure that
  589. * these get defined if the input environment block does not contain any
  590. * values for them.
  591. *
  592. * Also add variables known to Cygwin to be required for correct
  593. * subprocess operation in many cases:
  594. * https://github.com/Alexpux/Cygwin/blob/b266b04fbbd3a595f02ea149e4306d3ab9b1fe3d/winsup/cygwin/environ.cc#L955
  595. *
  596. */
  597. int make_program_env(char* env_block[], WCHAR** dst_ptr) {
  598. WCHAR* dst;
  599. WCHAR* ptr;
  600. char** env;
  601. size_t env_len = 0;
  602. int len;
  603. size_t i;
  604. DWORD var_size;
  605. size_t env_block_count = 1; /* 1 for null-terminator */
  606. WCHAR* dst_copy;
  607. WCHAR** ptr_copy;
  608. WCHAR** env_copy;
  609. DWORD required_vars_value_len[ARRAY_SIZE(required_vars)];
  610. /* first pass: determine size in UTF-16 */
  611. for (env = env_block; *env; env++) {
  612. int len;
  613. if (strchr(*env, '=')) {
  614. len = MultiByteToWideChar(CP_UTF8,
  615. 0,
  616. *env,
  617. -1,
  618. NULL,
  619. 0);
  620. if (len <= 0) {
  621. return GetLastError();
  622. }
  623. env_len += len;
  624. env_block_count++;
  625. }
  626. }
  627. /* second pass: copy to UTF-16 environment block */
  628. dst_copy = (WCHAR*)uv__malloc(env_len * sizeof(WCHAR));
  629. if (dst_copy == NULL && env_len > 0) {
  630. return ERROR_OUTOFMEMORY;
  631. }
  632. env_copy = alloca(env_block_count * sizeof(WCHAR*));
  633. ptr = dst_copy;
  634. ptr_copy = env_copy;
  635. for (env = env_block; *env; env++) {
  636. if (strchr(*env, '=')) {
  637. len = MultiByteToWideChar(CP_UTF8,
  638. 0,
  639. *env,
  640. -1,
  641. ptr,
  642. (int) (env_len - (ptr - dst_copy)));
  643. if (len <= 0) {
  644. DWORD err = GetLastError();
  645. uv__free(dst_copy);
  646. return err;
  647. }
  648. *ptr_copy++ = ptr;
  649. ptr += len;
  650. }
  651. }
  652. *ptr_copy = NULL;
  653. assert(env_len == 0 || env_len == (size_t) (ptr - dst_copy));
  654. /* sort our (UTF-16) copy */
  655. qsort(env_copy, env_block_count-1, sizeof(wchar_t*), qsort_wcscmp);
  656. /* third pass: check for required variables */
  657. for (ptr_copy = env_copy, i = 0; i < ARRAY_SIZE(required_vars); ) {
  658. int cmp;
  659. if (!*ptr_copy) {
  660. cmp = -1;
  661. } else {
  662. cmp = env_strncmp(required_vars[i].wide_eq,
  663. required_vars[i].len,
  664. *ptr_copy);
  665. }
  666. if (cmp < 0) {
  667. /* missing required var */
  668. var_size = GetEnvironmentVariableW(required_vars[i].wide, NULL, 0);
  669. required_vars_value_len[i] = var_size;
  670. if (var_size != 0) {
  671. env_len += required_vars[i].len;
  672. env_len += var_size;
  673. }
  674. i++;
  675. } else {
  676. ptr_copy++;
  677. if (cmp == 0)
  678. i++;
  679. }
  680. }
  681. /* final pass: copy, in sort order, and inserting required variables */
  682. dst = uv__malloc((1+env_len) * sizeof(WCHAR));
  683. if (!dst) {
  684. uv__free(dst_copy);
  685. return ERROR_OUTOFMEMORY;
  686. }
  687. for (ptr = dst, ptr_copy = env_copy, i = 0;
  688. *ptr_copy || i < ARRAY_SIZE(required_vars);
  689. ptr += len) {
  690. int cmp;
  691. if (i >= ARRAY_SIZE(required_vars)) {
  692. cmp = 1;
  693. } else if (!*ptr_copy) {
  694. cmp = -1;
  695. } else {
  696. cmp = env_strncmp(required_vars[i].wide_eq,
  697. required_vars[i].len,
  698. *ptr_copy);
  699. }
  700. if (cmp < 0) {
  701. /* missing required var */
  702. len = required_vars_value_len[i];
  703. if (len) {
  704. wcscpy(ptr, required_vars[i].wide_eq);
  705. ptr += required_vars[i].len;
  706. var_size = GetEnvironmentVariableW(required_vars[i].wide,
  707. ptr,
  708. (int) (env_len - (ptr - dst)));
  709. if (var_size != (DWORD) (len - 1)) { /* TODO: handle race condition? */
  710. uv_fatal_error(GetLastError(), "GetEnvironmentVariableW");
  711. }
  712. }
  713. i++;
  714. } else {
  715. /* copy var from env_block */
  716. len = wcslen(*ptr_copy) + 1;
  717. wmemcpy(ptr, *ptr_copy, len);
  718. ptr_copy++;
  719. if (cmp == 0)
  720. i++;
  721. }
  722. }
  723. /* Terminate with an extra NULL. */
  724. assert(env_len == (size_t) (ptr - dst));
  725. *ptr = L'\0';
  726. uv__free(dst_copy);
  727. *dst_ptr = dst;
  728. return 0;
  729. }
  730. /*
  731. * Attempt to find the value of the PATH environment variable in the child's
  732. * preprocessed environment.
  733. *
  734. * If found, a pointer into `env` is returned. If not found, NULL is returned.
  735. */
  736. static WCHAR* find_path(WCHAR *env) {
  737. for (; env != NULL && *env != 0; env += wcslen(env) + 1) {
  738. if ((env[0] == L'P' || env[0] == L'p') &&
  739. (env[1] == L'A' || env[1] == L'a') &&
  740. (env[2] == L'T' || env[2] == L't') &&
  741. (env[3] == L'H' || env[3] == L'h') &&
  742. (env[4] == L'=')) {
  743. return &env[5];
  744. }
  745. }
  746. return NULL;
  747. }
  748. /*
  749. * Called on Windows thread-pool thread to indicate that
  750. * a child process has exited.
  751. */
  752. static void CALLBACK exit_wait_callback(void* data, BOOLEAN didTimeout) {
  753. uv_process_t* process = (uv_process_t*) data;
  754. uv_loop_t* loop = process->loop;
  755. assert(didTimeout == FALSE);
  756. assert(process);
  757. assert(!process->exit_cb_pending);
  758. process->exit_cb_pending = 1;
  759. /* Post completed */
  760. POST_COMPLETION_FOR_REQ(loop, &process->exit_req);
  761. }
  762. /* Called on main thread after a child process has exited. */
  763. void uv__process_proc_exit(uv_loop_t* loop, uv_process_t* handle) {
  764. int64_t exit_code;
  765. DWORD status;
  766. assert(handle->exit_cb_pending);
  767. handle->exit_cb_pending = 0;
  768. /* If we're closing, don't call the exit callback. Just schedule a close
  769. * callback now. */
  770. if (handle->flags & UV_HANDLE_CLOSING) {
  771. uv__want_endgame(loop, (uv_handle_t*) handle);
  772. return;
  773. }
  774. /* Unregister from process notification. */
  775. if (handle->wait_handle != INVALID_HANDLE_VALUE) {
  776. UnregisterWait(handle->wait_handle);
  777. handle->wait_handle = INVALID_HANDLE_VALUE;
  778. }
  779. /* Set the handle to inactive: no callbacks will be made after the exit
  780. * callback. */
  781. uv__handle_stop(handle);
  782. if (GetExitCodeProcess(handle->process_handle, &status)) {
  783. exit_code = status;
  784. } else {
  785. /* Unable to obtain the exit code. This should never happen. */
  786. exit_code = uv_translate_sys_error(GetLastError());
  787. }
  788. /* Fire the exit callback. */
  789. if (handle->exit_cb) {
  790. handle->exit_cb(handle, exit_code, handle->exit_signal);
  791. }
  792. }
  793. void uv__process_close(uv_loop_t* loop, uv_process_t* handle) {
  794. uv__handle_closing(handle);
  795. if (handle->wait_handle != INVALID_HANDLE_VALUE) {
  796. /* This blocks until either the wait was cancelled, or the callback has
  797. * completed. */
  798. BOOL r = UnregisterWaitEx(handle->wait_handle, INVALID_HANDLE_VALUE);
  799. if (!r) {
  800. /* This should never happen, and if it happens, we can't recover... */
  801. uv_fatal_error(GetLastError(), "UnregisterWaitEx");
  802. }
  803. handle->wait_handle = INVALID_HANDLE_VALUE;
  804. }
  805. if (!handle->exit_cb_pending) {
  806. uv__want_endgame(loop, (uv_handle_t*)handle);
  807. }
  808. }
  809. void uv__process_endgame(uv_loop_t* loop, uv_process_t* handle) {
  810. assert(!handle->exit_cb_pending);
  811. assert(handle->flags & UV_HANDLE_CLOSING);
  812. assert(!(handle->flags & UV_HANDLE_CLOSED));
  813. /* Clean-up the process handle. */
  814. CloseHandle(handle->process_handle);
  815. uv__handle_close(handle);
  816. }
  817. int uv_spawn(uv_loop_t* loop,
  818. uv_process_t* process,
  819. const uv_process_options_t* options) {
  820. int i;
  821. int err = 0;
  822. WCHAR* path = NULL, *alloc_path = NULL;
  823. BOOL result;
  824. WCHAR* application_path = NULL, *application = NULL, *arguments = NULL,
  825. *env = NULL, *cwd = NULL;
  826. STARTUPINFOW startup;
  827. PROCESS_INFORMATION info;
  828. DWORD process_flags;
  829. uv__process_init(loop, process);
  830. process->exit_cb = options->exit_cb;
  831. if (options->flags & (UV_PROCESS_SETGID | UV_PROCESS_SETUID)) {
  832. return UV_ENOTSUP;
  833. }
  834. if (options->file == NULL ||
  835. options->args == NULL) {
  836. return UV_EINVAL;
  837. }
  838. if (options->cpumask != NULL) {
  839. if (options->cpumask_size < (size_t)uv_cpumask_size()) {
  840. return UV_EINVAL;
  841. }
  842. }
  843. assert(options->file != NULL);
  844. assert(!(options->flags & ~(UV_PROCESS_DETACHED |
  845. UV_PROCESS_SETGID |
  846. UV_PROCESS_SETUID |
  847. UV_PROCESS_WINDOWS_HIDE |
  848. UV_PROCESS_WINDOWS_HIDE_CONSOLE |
  849. UV_PROCESS_WINDOWS_HIDE_GUI |
  850. UV_PROCESS_WINDOWS_VERBATIM_ARGUMENTS)));
  851. err = uv__utf8_to_utf16_alloc(options->file, &application);
  852. if (err)
  853. goto done;
  854. err = make_program_args(
  855. options->args,
  856. options->flags & UV_PROCESS_WINDOWS_VERBATIM_ARGUMENTS,
  857. &arguments);
  858. if (err)
  859. goto done;
  860. if (options->env) {
  861. err = make_program_env(options->env, &env);
  862. if (err)
  863. goto done;
  864. }
  865. if (options->cwd) {
  866. /* Explicit cwd */
  867. err = uv__utf8_to_utf16_alloc(options->cwd, &cwd);
  868. if (err)
  869. goto done;
  870. } else {
  871. /* Inherit cwd */
  872. DWORD cwd_len, r;
  873. cwd_len = GetCurrentDirectoryW(0, NULL);
  874. if (!cwd_len) {
  875. err = GetLastError();
  876. goto done;
  877. }
  878. cwd = (WCHAR*) uv__malloc(cwd_len * sizeof(WCHAR));
  879. if (cwd == NULL) {
  880. err = ERROR_OUTOFMEMORY;
  881. goto done;
  882. }
  883. r = GetCurrentDirectoryW(cwd_len, cwd);
  884. if (r == 0 || r >= cwd_len) {
  885. err = GetLastError();
  886. goto done;
  887. }
  888. }
  889. /* Get PATH environment variable. */
  890. path = find_path(env);
  891. if (path == NULL) {
  892. DWORD path_len, r;
  893. path_len = GetEnvironmentVariableW(L"PATH", NULL, 0);
  894. if (path_len != 0) {
  895. alloc_path = (WCHAR*) uv__malloc(path_len * sizeof(WCHAR));
  896. if (alloc_path == NULL) {
  897. err = ERROR_OUTOFMEMORY;
  898. goto done;
  899. }
  900. path = alloc_path;
  901. r = GetEnvironmentVariableW(L"PATH", path, path_len);
  902. if (r == 0 || r >= path_len) {
  903. err = GetLastError();
  904. goto done;
  905. }
  906. }
  907. }
  908. err = uv__stdio_create(loop, options, &process->child_stdio_buffer);
  909. if (err)
  910. goto done;
  911. application_path = search_path(application,
  912. cwd,
  913. path);
  914. if (application_path == NULL) {
  915. /* Not found. */
  916. err = ERROR_FILE_NOT_FOUND;
  917. goto done;
  918. }
  919. startup.cb = sizeof(startup);
  920. startup.lpReserved = NULL;
  921. startup.lpDesktop = NULL;
  922. startup.lpTitle = NULL;
  923. startup.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW;
  924. startup.cbReserved2 = uv__stdio_size(process->child_stdio_buffer);
  925. startup.lpReserved2 = (BYTE*) process->child_stdio_buffer;
  926. startup.hStdInput = uv__stdio_handle(process->child_stdio_buffer, 0);
  927. startup.hStdOutput = uv__stdio_handle(process->child_stdio_buffer, 1);
  928. startup.hStdError = uv__stdio_handle(process->child_stdio_buffer, 2);
  929. process_flags = CREATE_UNICODE_ENVIRONMENT;
  930. if ((options->flags & UV_PROCESS_WINDOWS_HIDE_CONSOLE) ||
  931. (options->flags & UV_PROCESS_WINDOWS_HIDE)) {
  932. /* Avoid creating console window if stdio is not inherited. */
  933. for (i = 0; i < options->stdio_count; i++) {
  934. if (options->stdio[i].flags & UV_INHERIT_FD)
  935. break;
  936. if (i == options->stdio_count - 1)
  937. process_flags |= CREATE_NO_WINDOW;
  938. }
  939. }
  940. if ((options->flags & UV_PROCESS_WINDOWS_HIDE_GUI) ||
  941. (options->flags & UV_PROCESS_WINDOWS_HIDE)) {
  942. /* Use SW_HIDE to avoid any potential process window. */
  943. startup.wShowWindow = SW_HIDE;
  944. } else {
  945. startup.wShowWindow = SW_SHOWDEFAULT;
  946. }
  947. if (options->flags & UV_PROCESS_DETACHED) {
  948. /* Note that we're not setting the CREATE_BREAKAWAY_FROM_JOB flag. That
  949. * means that libuv might not let you create a fully daemonized process
  950. * when run under job control. However the type of job control that libuv
  951. * itself creates doesn't trickle down to subprocesses so they can still
  952. * daemonize.
  953. *
  954. * A reason to not do this is that CREATE_BREAKAWAY_FROM_JOB makes the
  955. * CreateProcess call fail if we're under job control that doesn't allow
  956. * breakaway.
  957. */
  958. process_flags |= DETACHED_PROCESS | CREATE_NEW_PROCESS_GROUP;
  959. process_flags |= CREATE_SUSPENDED;
  960. }
  961. if (options->cpumask != NULL) {
  962. /* Create the child in a suspended state so we have a chance to set
  963. its process affinity before it runs. */
  964. process_flags |= CREATE_SUSPENDED;
  965. }
  966. if (!CreateProcessW(application_path,
  967. arguments,
  968. NULL,
  969. NULL,
  970. 1,
  971. process_flags,
  972. env,
  973. cwd,
  974. &startup,
  975. &info)) {
  976. /* CreateProcessW failed. */
  977. err = GetLastError();
  978. goto done;
  979. }
  980. if (options->cpumask != NULL) {
  981. /* The child is currently suspended. Set its process affinity
  982. or terminate it if we can't. */
  983. int i;
  984. int cpumasksize;
  985. DWORD_PTR sysmask;
  986. DWORD_PTR oldmask;
  987. DWORD_PTR newmask;
  988. cpumasksize = uv_cpumask_size();
  989. if (!GetProcessAffinityMask(info.hProcess, &oldmask, &sysmask)) {
  990. err = GetLastError();
  991. TerminateProcess(info.hProcess, 1);
  992. goto done;
  993. }
  994. newmask = 0;
  995. for (i = 0; i < cpumasksize; i++) {
  996. if (options->cpumask[i]) {
  997. if (oldmask & (((DWORD_PTR)1) << i)) {
  998. newmask |= ((DWORD_PTR)1) << i;
  999. } else {
  1000. err = UV_EINVAL;
  1001. TerminateProcess(info.hProcess, 1);
  1002. goto done;
  1003. }
  1004. }
  1005. }
  1006. if (!SetProcessAffinityMask(info.hProcess, newmask)) {
  1007. err = GetLastError();
  1008. TerminateProcess(info.hProcess, 1);
  1009. goto done;
  1010. }
  1011. }
  1012. /* If the process isn't spawned as detached, assign to the global job object
  1013. * so windows will kill it when the parent process dies. */
  1014. if (!(options->flags & UV_PROCESS_DETACHED)) {
  1015. uv_once(&uv_global_job_handle_init_guard_, uv__init_global_job_handle);
  1016. if (!AssignProcessToJobObject(uv_global_job_handle_, info.hProcess)) {
  1017. /* AssignProcessToJobObject might fail if this process is under job
  1018. * control and the job doesn't have the
  1019. * JOB_OBJECT_LIMIT_SILENT_BREAKAWAY_OK flag set, on a Windows version
  1020. * that doesn't support nested jobs.
  1021. *
  1022. * When that happens we just swallow the error and continue without
  1023. * establishing a kill-child-on-parent-exit relationship, otherwise
  1024. * there would be no way for libuv applications run under job control
  1025. * to spawn processes at all.
  1026. */
  1027. DWORD err = GetLastError();
  1028. if (err != ERROR_ACCESS_DENIED)
  1029. uv_fatal_error(err, "AssignProcessToJobObject");
  1030. }
  1031. }
  1032. if (process_flags & CREATE_SUSPENDED) {
  1033. if (ResumeThread(info.hThread) == ((DWORD)-1)) {
  1034. err = GetLastError();
  1035. TerminateProcess(info.hProcess, 1);
  1036. goto done;
  1037. }
  1038. }
  1039. /* Spawn succeeded. Beyond this point, failure is reported asynchronously. */
  1040. process->process_handle = info.hProcess;
  1041. process->pid = info.dwProcessId;
  1042. /* Set IPC pid to all IPC pipes. */
  1043. for (i = 0; i < options->stdio_count; i++) {
  1044. const uv_stdio_container_t* fdopt = &options->stdio[i];
  1045. if (fdopt->flags & UV_CREATE_PIPE &&
  1046. fdopt->data.stream->type == UV_NAMED_PIPE &&
  1047. ((uv_pipe_t*) fdopt->data.stream)->ipc) {
  1048. ((uv_pipe_t*) fdopt->data.stream)->pipe.conn.ipc_remote_pid =
  1049. info.dwProcessId;
  1050. }
  1051. }
  1052. /* Setup notifications for when the child process exits. */
  1053. result = RegisterWaitForSingleObject(&process->wait_handle,
  1054. process->process_handle, exit_wait_callback, (void*)process, INFINITE,
  1055. WT_EXECUTEINWAITTHREAD | WT_EXECUTEONLYONCE);
  1056. if (!result) {
  1057. uv_fatal_error(GetLastError(), "RegisterWaitForSingleObject");
  1058. }
  1059. CloseHandle(info.hThread);
  1060. assert(!err);
  1061. /* Make the handle active. It will remain active until the exit callback is
  1062. * made or the handle is closed, whichever happens first. */
  1063. uv__handle_start(process);
  1064. /* Cleanup, whether we succeeded or failed. */
  1065. done:
  1066. uv__free(application);
  1067. uv__free(application_path);
  1068. uv__free(arguments);
  1069. uv__free(cwd);
  1070. uv__free(env);
  1071. uv__free(alloc_path);
  1072. if (process->child_stdio_buffer != NULL) {
  1073. /* Clean up child stdio handles. */
  1074. uv__stdio_destroy(process->child_stdio_buffer);
  1075. process->child_stdio_buffer = NULL;
  1076. }
  1077. return uv_translate_sys_error(err);
  1078. }
  1079. static int uv__kill(HANDLE process_handle, int signum) {
  1080. if (signum < 0 || signum >= NSIG) {
  1081. return UV_EINVAL;
  1082. }
  1083. switch (signum) {
  1084. case SIGTERM:
  1085. case SIGKILL:
  1086. case SIGINT: {
  1087. /* Unconditionally terminate the process. On Windows, killed processes
  1088. * normally return 1. */
  1089. DWORD status;
  1090. int err;
  1091. if (TerminateProcess(process_handle, 1))
  1092. return 0;
  1093. /* If the process already exited before TerminateProcess was called,.
  1094. * TerminateProcess will fail with ERROR_ACCESS_DENIED. */
  1095. err = GetLastError();
  1096. if (err == ERROR_ACCESS_DENIED &&
  1097. GetExitCodeProcess(process_handle, &status) &&
  1098. status != STILL_ACTIVE) {
  1099. return UV_ESRCH;
  1100. }
  1101. return uv_translate_sys_error(err);
  1102. }
  1103. case 0: {
  1104. /* Health check: is the process still alive? */
  1105. DWORD status;
  1106. if (!GetExitCodeProcess(process_handle, &status))
  1107. return uv_translate_sys_error(GetLastError());
  1108. if (status != STILL_ACTIVE)
  1109. return UV_ESRCH;
  1110. return 0;
  1111. }
  1112. default:
  1113. /* Unsupported signal. */
  1114. return UV_ENOSYS;
  1115. }
  1116. }
  1117. int uv_process_kill(uv_process_t* process, int signum) {
  1118. int err;
  1119. if (process->process_handle == INVALID_HANDLE_VALUE) {
  1120. return UV_EINVAL;
  1121. }
  1122. err = uv__kill(process->process_handle, signum);
  1123. if (err) {
  1124. return err; /* err is already translated. */
  1125. }
  1126. process->exit_signal = signum;
  1127. return 0;
  1128. }
  1129. int uv_kill(int pid, int signum) {
  1130. int err;
  1131. HANDLE process_handle;
  1132. if (pid == 0) {
  1133. process_handle = GetCurrentProcess();
  1134. } else {
  1135. process_handle = OpenProcess(PROCESS_TERMINATE | PROCESS_QUERY_INFORMATION,
  1136. FALSE,
  1137. pid);
  1138. }
  1139. if (process_handle == NULL) {
  1140. err = GetLastError();
  1141. if (err == ERROR_INVALID_PARAMETER) {
  1142. return UV_ESRCH;
  1143. } else {
  1144. return uv_translate_sys_error(err);
  1145. }
  1146. }
  1147. err = uv__kill(process_handle, signum);
  1148. CloseHandle(process_handle);
  1149. return err; /* err is already translated. */
  1150. }