process.c 38 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359
  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, or already contains a path
  283. * and the UV_PROCESS_WINDOWS_FILE_PATH_EXACT_NAME flag is specified,
  284. * search for the file with the exact specified filename first.
  285. *
  286. * - If the literal filename is not found in a directory, try *appending*
  287. * (not replacing) .com first and then .exe.
  288. *
  289. * - The path variable may contain relative paths; relative paths are relative
  290. * to the cwd.
  291. *
  292. * - Directories in path may or may not end with a trailing backslash.
  293. *
  294. * - CMD does not trim leading/trailing whitespace from path/pathex entries
  295. * nor from the environment variables as a whole.
  296. *
  297. * - When cmd.exe cannot read a directory, it will just skip it and go on
  298. * searching. However, unlike posix-y systems, it will happily try to run a
  299. * file that is not readable/executable; if the spawn fails it will not
  300. * continue searching.
  301. *
  302. * UNC path support: we are dealing with UNC paths in both the path and the
  303. * filename. This is a deviation from what cmd.exe does (it does not let you
  304. * start a program by specifying an UNC path on the command line) but this is
  305. * really a pointless restriction.
  306. *
  307. */
  308. static WCHAR* search_path(const WCHAR *file,
  309. WCHAR *cwd,
  310. const WCHAR *path,
  311. unsigned int flags) {
  312. int file_has_dir;
  313. WCHAR* result = NULL;
  314. WCHAR *file_name_start;
  315. WCHAR *dot;
  316. const WCHAR *dir_start, *dir_end, *dir_path;
  317. size_t dir_len;
  318. int name_has_ext;
  319. size_t file_len = wcslen(file);
  320. size_t cwd_len = wcslen(cwd);
  321. /* If the caller supplies an empty filename,
  322. * we're not gonna return c:\windows\.exe -- GFY!
  323. */
  324. if (file_len == 0
  325. || (file_len == 1 && file[0] == L'.')) {
  326. return NULL;
  327. }
  328. /* Find the start of the filename so we can split the directory from the
  329. * name. */
  330. for (file_name_start = (WCHAR*)file + file_len;
  331. file_name_start > file
  332. && file_name_start[-1] != L'\\'
  333. && file_name_start[-1] != L'/'
  334. && file_name_start[-1] != L':';
  335. file_name_start--);
  336. file_has_dir = file_name_start != file;
  337. /* Check if the filename includes an extension */
  338. dot = wcschr(file_name_start, L'.');
  339. name_has_ext = (dot != NULL && dot[1] != L'\0');
  340. if (file_has_dir) {
  341. /* The file has a path inside, don't use path */
  342. result = path_search_walk_ext(
  343. file, file_name_start - file,
  344. file_name_start, file_len - (file_name_start - file),
  345. cwd, cwd_len,
  346. name_has_ext || (flags & UV_PROCESS_WINDOWS_FILE_PATH_EXACT_NAME));
  347. } else {
  348. dir_end = path;
  349. if (NeedCurrentDirectoryForExePathW(L"")) {
  350. /* The file is really only a name; look in cwd first, then scan path */
  351. result = path_search_walk_ext(L"", 0,
  352. file, file_len,
  353. cwd, cwd_len,
  354. name_has_ext);
  355. }
  356. while (result == NULL) {
  357. if (dir_end == NULL || *dir_end == L'\0') {
  358. break;
  359. }
  360. /* Skip the separator that dir_end now points to */
  361. if (dir_end != path || *path == L';') {
  362. dir_end++;
  363. }
  364. /* Next slice starts just after where the previous one ended */
  365. dir_start = dir_end;
  366. /* If path is quoted, find quote end */
  367. if (*dir_start == L'"' || *dir_start == L'\'') {
  368. dir_end = wcschr(dir_start + 1, *dir_start);
  369. if (dir_end == NULL) {
  370. dir_end = wcschr(dir_start, L'\0');
  371. }
  372. }
  373. /* Slice until the next ; or \0 is found */
  374. dir_end = wcschr(dir_end, L';');
  375. if (dir_end == NULL) {
  376. dir_end = wcschr(dir_start, L'\0');
  377. }
  378. /* If the slice is zero-length, don't bother */
  379. if (dir_end - dir_start == 0) {
  380. continue;
  381. }
  382. dir_path = dir_start;
  383. dir_len = dir_end - dir_start;
  384. /* Adjust if the path is quoted. */
  385. if (dir_path[0] == '"' || dir_path[0] == '\'') {
  386. ++dir_path;
  387. --dir_len;
  388. }
  389. if (dir_path[dir_len - 1] == '"' || dir_path[dir_len - 1] == '\'') {
  390. --dir_len;
  391. }
  392. result = path_search_walk_ext(dir_path, dir_len,
  393. file, file_len,
  394. cwd, cwd_len,
  395. name_has_ext);
  396. }
  397. }
  398. return result;
  399. }
  400. /*
  401. * Quotes command line arguments
  402. * Returns a pointer to the end (next char to be written) of the buffer
  403. */
  404. WCHAR* quote_cmd_arg(const WCHAR *source, WCHAR *target) {
  405. size_t len = wcslen(source);
  406. size_t i;
  407. int quote_hit;
  408. WCHAR* start;
  409. if (len == 0) {
  410. /* Need double quotation for empty argument */
  411. *(target++) = L'"';
  412. *(target++) = L'"';
  413. return target;
  414. }
  415. if (NULL == wcspbrk(source, L" \t\"")) {
  416. /* No quotation needed */
  417. wcsncpy(target, source, len);
  418. target += len;
  419. return target;
  420. }
  421. if (NULL == wcspbrk(source, L"\"\\")) {
  422. /*
  423. * No embedded double quotes or backlashes, so I can just wrap
  424. * quote marks around the whole thing.
  425. */
  426. *(target++) = L'"';
  427. wcsncpy(target, source, len);
  428. target += len;
  429. *(target++) = L'"';
  430. return target;
  431. }
  432. /*
  433. * Expected input/output:
  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. * input : hello world\
  447. * output: "hello world\\"
  448. */
  449. *(target++) = L'"';
  450. start = target;
  451. quote_hit = 1;
  452. for (i = len; i > 0; --i) {
  453. *(target++) = source[i - 1];
  454. if (quote_hit && source[i - 1] == L'\\') {
  455. *(target++) = L'\\';
  456. } else if(source[i - 1] == L'"') {
  457. quote_hit = 1;
  458. *(target++) = L'\\';
  459. } else {
  460. quote_hit = 0;
  461. }
  462. }
  463. target[0] = L'\0';
  464. wcsrev(start);
  465. *(target++) = L'"';
  466. return target;
  467. }
  468. int make_program_args(char** args, int verbatim_arguments, WCHAR** dst_ptr) {
  469. char** arg;
  470. WCHAR* dst = NULL;
  471. WCHAR* temp_buffer = NULL;
  472. size_t dst_len = 0;
  473. size_t temp_buffer_len = 0;
  474. WCHAR* pos;
  475. int arg_count = 0;
  476. int err = 0;
  477. /* Count the required size. */
  478. for (arg = args; *arg; arg++) {
  479. DWORD arg_len;
  480. arg_len = MultiByteToWideChar(CP_UTF8,
  481. 0,
  482. *arg,
  483. -1,
  484. NULL,
  485. 0);
  486. if (arg_len == 0) {
  487. return GetLastError();
  488. }
  489. dst_len += arg_len;
  490. if (arg_len > temp_buffer_len)
  491. temp_buffer_len = arg_len;
  492. arg_count++;
  493. }
  494. /* Adjust for potential quotes. Also assume the worst-case scenario that
  495. * every character needs escaping, so we need twice as much space. */
  496. dst_len = dst_len * 2 + arg_count * 2;
  497. /* Allocate buffer for the final command line. */
  498. dst = (WCHAR*) uv__malloc(dst_len * sizeof(WCHAR));
  499. if (dst == NULL) {
  500. err = ERROR_OUTOFMEMORY;
  501. goto error;
  502. }
  503. /* Allocate temporary working buffer. */
  504. temp_buffer = (WCHAR*) uv__malloc(temp_buffer_len * sizeof(WCHAR));
  505. if (temp_buffer == NULL) {
  506. err = ERROR_OUTOFMEMORY;
  507. goto error;
  508. }
  509. pos = dst;
  510. for (arg = args; *arg; arg++) {
  511. DWORD arg_len;
  512. /* Convert argument to wide char. */
  513. arg_len = MultiByteToWideChar(CP_UTF8,
  514. 0,
  515. *arg,
  516. -1,
  517. temp_buffer,
  518. (int) (dst + dst_len - pos));
  519. if (arg_len == 0) {
  520. err = GetLastError();
  521. goto error;
  522. }
  523. if (verbatim_arguments) {
  524. /* Copy verbatim. */
  525. wcscpy(pos, temp_buffer);
  526. pos += arg_len - 1;
  527. } else {
  528. /* Quote/escape, if needed. */
  529. pos = quote_cmd_arg(temp_buffer, pos);
  530. }
  531. *pos++ = *(arg + 1) ? L' ' : L'\0';
  532. }
  533. uv__free(temp_buffer);
  534. *dst_ptr = dst;
  535. return 0;
  536. error:
  537. uv__free(dst);
  538. uv__free(temp_buffer);
  539. return err;
  540. }
  541. int env_strncmp(const wchar_t* a, int na, const wchar_t* b) {
  542. wchar_t* a_eq;
  543. wchar_t* b_eq;
  544. wchar_t* A;
  545. wchar_t* B;
  546. int nb;
  547. int r;
  548. if (na < 0) {
  549. a_eq = wcschr(a, L'=');
  550. assert(a_eq);
  551. na = (int)(long)(a_eq - a);
  552. } else {
  553. na--;
  554. }
  555. b_eq = wcschr(b, L'=');
  556. assert(b_eq);
  557. nb = b_eq - b;
  558. A = alloca((na+1) * sizeof(wchar_t));
  559. B = alloca((nb+1) * sizeof(wchar_t));
  560. r = LCMapStringW(LOCALE_INVARIANT, LCMAP_UPPERCASE, a, na, A, na);
  561. assert(r==na);
  562. A[na] = L'\0';
  563. r = LCMapStringW(LOCALE_INVARIANT, LCMAP_UPPERCASE, b, nb, B, nb);
  564. assert(r==nb);
  565. B[nb] = L'\0';
  566. for (;;) {
  567. wchar_t AA = *A++;
  568. wchar_t BB = *B++;
  569. if (AA < BB) {
  570. return -1;
  571. } else if (AA > BB) {
  572. return 1;
  573. } else if (!AA && !BB) {
  574. return 0;
  575. }
  576. }
  577. }
  578. static int qsort_wcscmp(const void *a, const void *b) {
  579. wchar_t* astr = *(wchar_t* const*)a;
  580. wchar_t* bstr = *(wchar_t* const*)b;
  581. return env_strncmp(astr, -1, bstr);
  582. }
  583. /*
  584. * The way windows takes environment variables is different than what C does;
  585. * Windows wants a contiguous block of null-terminated strings, terminated
  586. * with an additional null.
  587. *
  588. * Windows has a few "essential" environment variables. winsock will fail
  589. * to initialize if SYSTEMROOT is not defined; some APIs make reference to
  590. * TEMP. SYSTEMDRIVE is probably also important. We therefore ensure that
  591. * these get defined if the input environment block does not contain any
  592. * values for them.
  593. *
  594. * Also add variables known to Cygwin to be required for correct
  595. * subprocess operation in many cases:
  596. * https://github.com/Alexpux/Cygwin/blob/b266b04fbbd3a595f02ea149e4306d3ab9b1fe3d/winsup/cygwin/environ.cc#L955
  597. *
  598. */
  599. int make_program_env(char* env_block[], WCHAR** dst_ptr) {
  600. WCHAR* dst;
  601. WCHAR* ptr;
  602. char** env;
  603. size_t env_len = 0;
  604. int len;
  605. size_t i;
  606. DWORD var_size;
  607. size_t env_block_count = 1; /* 1 for null-terminator */
  608. WCHAR* dst_copy;
  609. WCHAR** ptr_copy;
  610. WCHAR** env_copy;
  611. DWORD required_vars_value_len[ARRAY_SIZE(required_vars)];
  612. /* first pass: determine size in UTF-16 */
  613. for (env = env_block; *env; env++) {
  614. int len;
  615. if (strchr(*env, '=')) {
  616. len = MultiByteToWideChar(CP_UTF8,
  617. 0,
  618. *env,
  619. -1,
  620. NULL,
  621. 0);
  622. if (len <= 0) {
  623. return GetLastError();
  624. }
  625. env_len += len;
  626. env_block_count++;
  627. }
  628. }
  629. /* second pass: copy to UTF-16 environment block */
  630. dst_copy = (WCHAR*)uv__malloc(env_len * sizeof(WCHAR));
  631. if (dst_copy == NULL && env_len > 0) {
  632. return ERROR_OUTOFMEMORY;
  633. }
  634. env_copy = alloca(env_block_count * sizeof(WCHAR*));
  635. ptr = dst_copy;
  636. ptr_copy = env_copy;
  637. for (env = env_block; *env; env++) {
  638. if (strchr(*env, '=')) {
  639. len = MultiByteToWideChar(CP_UTF8,
  640. 0,
  641. *env,
  642. -1,
  643. ptr,
  644. (int) (env_len - (ptr - dst_copy)));
  645. if (len <= 0) {
  646. DWORD err = GetLastError();
  647. uv__free(dst_copy);
  648. return err;
  649. }
  650. *ptr_copy++ = ptr;
  651. ptr += len;
  652. }
  653. }
  654. *ptr_copy = NULL;
  655. assert(env_len == 0 || env_len == (size_t) (ptr - dst_copy));
  656. /* sort our (UTF-16) copy */
  657. qsort(env_copy, env_block_count-1, sizeof(wchar_t*), qsort_wcscmp);
  658. /* third pass: check for required variables */
  659. for (ptr_copy = env_copy, i = 0; i < ARRAY_SIZE(required_vars); ) {
  660. int cmp;
  661. if (!*ptr_copy) {
  662. cmp = -1;
  663. } else {
  664. cmp = env_strncmp(required_vars[i].wide_eq,
  665. required_vars[i].len,
  666. *ptr_copy);
  667. }
  668. if (cmp < 0) {
  669. /* missing required var */
  670. var_size = GetEnvironmentVariableW(required_vars[i].wide, NULL, 0);
  671. required_vars_value_len[i] = var_size;
  672. if (var_size != 0) {
  673. env_len += required_vars[i].len;
  674. env_len += var_size;
  675. }
  676. i++;
  677. } else {
  678. ptr_copy++;
  679. if (cmp == 0)
  680. i++;
  681. }
  682. }
  683. /* final pass: copy, in sort order, and inserting required variables */
  684. dst = uv__malloc((1+env_len) * sizeof(WCHAR));
  685. if (!dst) {
  686. uv__free(dst_copy);
  687. return ERROR_OUTOFMEMORY;
  688. }
  689. for (ptr = dst, ptr_copy = env_copy, i = 0;
  690. *ptr_copy || i < ARRAY_SIZE(required_vars);
  691. ptr += len) {
  692. int cmp;
  693. if (i >= ARRAY_SIZE(required_vars)) {
  694. cmp = 1;
  695. } else if (!*ptr_copy) {
  696. cmp = -1;
  697. } else {
  698. cmp = env_strncmp(required_vars[i].wide_eq,
  699. required_vars[i].len,
  700. *ptr_copy);
  701. }
  702. if (cmp < 0) {
  703. /* missing required var */
  704. len = required_vars_value_len[i];
  705. if (len) {
  706. wcscpy(ptr, required_vars[i].wide_eq);
  707. ptr += required_vars[i].len;
  708. var_size = GetEnvironmentVariableW(required_vars[i].wide,
  709. ptr,
  710. (int) (env_len - (ptr - dst)));
  711. if (var_size != (DWORD) (len - 1)) { /* TODO: handle race condition? */
  712. uv_fatal_error(GetLastError(), "GetEnvironmentVariableW");
  713. }
  714. }
  715. i++;
  716. } else {
  717. /* copy var from env_block */
  718. len = wcslen(*ptr_copy) + 1;
  719. wmemcpy(ptr, *ptr_copy, len);
  720. ptr_copy++;
  721. if (cmp == 0)
  722. i++;
  723. }
  724. }
  725. /* Terminate with an extra NULL. */
  726. assert(env_len == (size_t) (ptr - dst));
  727. *ptr = L'\0';
  728. uv__free(dst_copy);
  729. *dst_ptr = dst;
  730. return 0;
  731. }
  732. /*
  733. * Attempt to find the value of the PATH environment variable in the child's
  734. * preprocessed environment.
  735. *
  736. * If found, a pointer into `env` is returned. If not found, NULL is returned.
  737. */
  738. static WCHAR* find_path(WCHAR *env) {
  739. for (; env != NULL && *env != 0; env += wcslen(env) + 1) {
  740. if ((env[0] == L'P' || env[0] == L'p') &&
  741. (env[1] == L'A' || env[1] == L'a') &&
  742. (env[2] == L'T' || env[2] == L't') &&
  743. (env[3] == L'H' || env[3] == L'h') &&
  744. (env[4] == L'=')) {
  745. return &env[5];
  746. }
  747. }
  748. return NULL;
  749. }
  750. /*
  751. * Called on Windows thread-pool thread to indicate that
  752. * a child process has exited.
  753. */
  754. static void CALLBACK exit_wait_callback(void* data, BOOLEAN didTimeout) {
  755. uv_process_t* process = (uv_process_t*) data;
  756. uv_loop_t* loop = process->loop;
  757. assert(didTimeout == FALSE);
  758. assert(process);
  759. assert(!process->exit_cb_pending);
  760. process->exit_cb_pending = 1;
  761. /* Post completed */
  762. POST_COMPLETION_FOR_REQ(loop, &process->exit_req);
  763. }
  764. /* Called on main thread after a child process has exited. */
  765. void uv__process_proc_exit(uv_loop_t* loop, uv_process_t* handle) {
  766. int64_t exit_code;
  767. DWORD status;
  768. assert(handle->exit_cb_pending);
  769. handle->exit_cb_pending = 0;
  770. /* If we're closing, don't call the exit callback. Just schedule a close
  771. * callback now. */
  772. if (handle->flags & UV_HANDLE_CLOSING) {
  773. uv__want_endgame(loop, (uv_handle_t*) handle);
  774. return;
  775. }
  776. /* Unregister from process notification. */
  777. if (handle->wait_handle != INVALID_HANDLE_VALUE) {
  778. UnregisterWait(handle->wait_handle);
  779. handle->wait_handle = INVALID_HANDLE_VALUE;
  780. }
  781. /* Set the handle to inactive: no callbacks will be made after the exit
  782. * callback. */
  783. uv__handle_stop(handle);
  784. if (GetExitCodeProcess(handle->process_handle, &status)) {
  785. exit_code = status;
  786. } else {
  787. /* Unable to obtain the exit code. This should never happen. */
  788. exit_code = uv_translate_sys_error(GetLastError());
  789. }
  790. /* Fire the exit callback. */
  791. if (handle->exit_cb) {
  792. handle->exit_cb(handle, exit_code, handle->exit_signal);
  793. }
  794. }
  795. void uv__process_close(uv_loop_t* loop, uv_process_t* handle) {
  796. uv__handle_closing(handle);
  797. if (handle->wait_handle != INVALID_HANDLE_VALUE) {
  798. /* This blocks until either the wait was cancelled, or the callback has
  799. * completed. */
  800. BOOL r = UnregisterWaitEx(handle->wait_handle, INVALID_HANDLE_VALUE);
  801. if (!r) {
  802. /* This should never happen, and if it happens, we can't recover... */
  803. uv_fatal_error(GetLastError(), "UnregisterWaitEx");
  804. }
  805. handle->wait_handle = INVALID_HANDLE_VALUE;
  806. }
  807. if (!handle->exit_cb_pending) {
  808. uv__want_endgame(loop, (uv_handle_t*)handle);
  809. }
  810. }
  811. void uv__process_endgame(uv_loop_t* loop, uv_process_t* handle) {
  812. assert(!handle->exit_cb_pending);
  813. assert(handle->flags & UV_HANDLE_CLOSING);
  814. assert(!(handle->flags & UV_HANDLE_CLOSED));
  815. /* Clean-up the process handle. */
  816. CloseHandle(handle->process_handle);
  817. uv__handle_close(handle);
  818. }
  819. int uv_spawn(uv_loop_t* loop,
  820. uv_process_t* process,
  821. const uv_process_options_t* options) {
  822. int i;
  823. int err = 0;
  824. WCHAR* path = NULL, *alloc_path = NULL;
  825. BOOL result;
  826. WCHAR* application_path = NULL, *application = NULL, *arguments = NULL,
  827. *env = NULL, *cwd = NULL;
  828. STARTUPINFOW startup;
  829. PROCESS_INFORMATION info;
  830. DWORD process_flags;
  831. uv__process_init(loop, process);
  832. process->exit_cb = options->exit_cb;
  833. if (options->flags & (UV_PROCESS_SETGID | UV_PROCESS_SETUID)) {
  834. return UV_ENOTSUP;
  835. }
  836. if (options->file == NULL ||
  837. options->args == NULL) {
  838. return UV_EINVAL;
  839. }
  840. if (options->cpumask != NULL) {
  841. if (options->cpumask_size < (size_t)uv_cpumask_size()) {
  842. return UV_EINVAL;
  843. }
  844. }
  845. assert(options->file != NULL);
  846. assert(!(options->flags & ~(UV_PROCESS_DETACHED |
  847. UV_PROCESS_SETGID |
  848. UV_PROCESS_SETUID |
  849. UV_PROCESS_WINDOWS_FILE_PATH_EXACT_NAME |
  850. UV_PROCESS_WINDOWS_HIDE |
  851. UV_PROCESS_WINDOWS_HIDE_CONSOLE |
  852. UV_PROCESS_WINDOWS_HIDE_GUI |
  853. UV_PROCESS_WINDOWS_VERBATIM_ARGUMENTS)));
  854. err = uv__utf8_to_utf16_alloc(options->file, &application);
  855. if (err)
  856. goto done;
  857. err = make_program_args(
  858. options->args,
  859. options->flags & UV_PROCESS_WINDOWS_VERBATIM_ARGUMENTS,
  860. &arguments);
  861. if (err)
  862. goto done;
  863. if (options->env) {
  864. err = make_program_env(options->env, &env);
  865. if (err)
  866. goto done;
  867. }
  868. if (options->cwd) {
  869. /* Explicit cwd */
  870. err = uv__utf8_to_utf16_alloc(options->cwd, &cwd);
  871. if (err)
  872. goto done;
  873. } else {
  874. /* Inherit cwd */
  875. DWORD cwd_len, r;
  876. cwd_len = GetCurrentDirectoryW(0, NULL);
  877. if (!cwd_len) {
  878. err = GetLastError();
  879. goto done;
  880. }
  881. cwd = (WCHAR*) uv__malloc(cwd_len * sizeof(WCHAR));
  882. if (cwd == NULL) {
  883. err = ERROR_OUTOFMEMORY;
  884. goto done;
  885. }
  886. r = GetCurrentDirectoryW(cwd_len, cwd);
  887. if (r == 0 || r >= cwd_len) {
  888. err = GetLastError();
  889. goto done;
  890. }
  891. }
  892. /* Get PATH environment variable. */
  893. path = find_path(env);
  894. if (path == NULL) {
  895. DWORD path_len, r;
  896. path_len = GetEnvironmentVariableW(L"PATH", NULL, 0);
  897. if (path_len != 0) {
  898. alloc_path = (WCHAR*) uv__malloc(path_len * sizeof(WCHAR));
  899. if (alloc_path == NULL) {
  900. err = ERROR_OUTOFMEMORY;
  901. goto done;
  902. }
  903. path = alloc_path;
  904. r = GetEnvironmentVariableW(L"PATH", path, path_len);
  905. if (r == 0 || r >= path_len) {
  906. err = GetLastError();
  907. goto done;
  908. }
  909. }
  910. }
  911. err = uv__stdio_create(loop, options, &process->child_stdio_buffer);
  912. if (err)
  913. goto done;
  914. application_path = search_path(application,
  915. cwd,
  916. path,
  917. options->flags);
  918. if (application_path == NULL) {
  919. /* Not found. */
  920. err = ERROR_FILE_NOT_FOUND;
  921. goto done;
  922. }
  923. startup.cb = sizeof(startup);
  924. startup.lpReserved = NULL;
  925. startup.lpDesktop = NULL;
  926. startup.lpTitle = NULL;
  927. startup.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW;
  928. startup.cbReserved2 = uv__stdio_size(process->child_stdio_buffer);
  929. startup.lpReserved2 = (BYTE*) process->child_stdio_buffer;
  930. startup.hStdInput = uv__stdio_handle(process->child_stdio_buffer, 0);
  931. startup.hStdOutput = uv__stdio_handle(process->child_stdio_buffer, 1);
  932. startup.hStdError = uv__stdio_handle(process->child_stdio_buffer, 2);
  933. process_flags = CREATE_UNICODE_ENVIRONMENT;
  934. if ((options->flags & UV_PROCESS_WINDOWS_HIDE_CONSOLE) ||
  935. (options->flags & UV_PROCESS_WINDOWS_HIDE)) {
  936. /* Avoid creating console window if stdio is not inherited. */
  937. for (i = 0; i < options->stdio_count; i++) {
  938. if (options->stdio[i].flags & UV_INHERIT_FD)
  939. break;
  940. if (i == options->stdio_count - 1)
  941. process_flags |= CREATE_NO_WINDOW;
  942. }
  943. }
  944. if ((options->flags & UV_PROCESS_WINDOWS_HIDE_GUI) ||
  945. (options->flags & UV_PROCESS_WINDOWS_HIDE)) {
  946. /* Use SW_HIDE to avoid any potential process window. */
  947. startup.wShowWindow = SW_HIDE;
  948. } else {
  949. startup.wShowWindow = SW_SHOWDEFAULT;
  950. }
  951. if (options->flags & UV_PROCESS_DETACHED) {
  952. /* Note that we're not setting the CREATE_BREAKAWAY_FROM_JOB flag. That
  953. * means that libuv might not let you create a fully daemonized process
  954. * when run under job control. However the type of job control that libuv
  955. * itself creates doesn't trickle down to subprocesses so they can still
  956. * daemonize.
  957. *
  958. * A reason to not do this is that CREATE_BREAKAWAY_FROM_JOB makes the
  959. * CreateProcess call fail if we're under job control that doesn't allow
  960. * breakaway.
  961. */
  962. process_flags |= DETACHED_PROCESS | CREATE_NEW_PROCESS_GROUP;
  963. process_flags |= CREATE_SUSPENDED;
  964. }
  965. if (options->cpumask != NULL) {
  966. /* Create the child in a suspended state so we have a chance to set
  967. its process affinity before it runs. */
  968. process_flags |= CREATE_SUSPENDED;
  969. }
  970. if (!CreateProcessW(application_path,
  971. arguments,
  972. NULL,
  973. NULL,
  974. 1,
  975. process_flags,
  976. env,
  977. cwd,
  978. &startup,
  979. &info)) {
  980. /* CreateProcessW failed. */
  981. err = GetLastError();
  982. goto done;
  983. }
  984. if (options->cpumask != NULL) {
  985. /* The child is currently suspended. Set its process affinity
  986. or terminate it if we can't. */
  987. int i;
  988. int cpumasksize;
  989. DWORD_PTR sysmask;
  990. DWORD_PTR oldmask;
  991. DWORD_PTR newmask;
  992. cpumasksize = uv_cpumask_size();
  993. if (!GetProcessAffinityMask(info.hProcess, &oldmask, &sysmask)) {
  994. err = GetLastError();
  995. TerminateProcess(info.hProcess, 1);
  996. goto done;
  997. }
  998. newmask = 0;
  999. for (i = 0; i < cpumasksize; i++) {
  1000. if (options->cpumask[i]) {
  1001. if (oldmask & (((DWORD_PTR)1) << i)) {
  1002. newmask |= ((DWORD_PTR)1) << i;
  1003. } else {
  1004. err = UV_EINVAL;
  1005. TerminateProcess(info.hProcess, 1);
  1006. goto done;
  1007. }
  1008. }
  1009. }
  1010. if (!SetProcessAffinityMask(info.hProcess, newmask)) {
  1011. err = GetLastError();
  1012. TerminateProcess(info.hProcess, 1);
  1013. goto done;
  1014. }
  1015. }
  1016. /* If the process isn't spawned as detached, assign to the global job object
  1017. * so windows will kill it when the parent process dies. */
  1018. if (!(options->flags & UV_PROCESS_DETACHED)) {
  1019. uv_once(&uv_global_job_handle_init_guard_, uv__init_global_job_handle);
  1020. if (!AssignProcessToJobObject(uv_global_job_handle_, info.hProcess)) {
  1021. /* AssignProcessToJobObject might fail if this process is under job
  1022. * control and the job doesn't have the
  1023. * JOB_OBJECT_LIMIT_SILENT_BREAKAWAY_OK flag set, on a Windows version
  1024. * that doesn't support nested jobs.
  1025. *
  1026. * When that happens we just swallow the error and continue without
  1027. * establishing a kill-child-on-parent-exit relationship, otherwise
  1028. * there would be no way for libuv applications run under job control
  1029. * to spawn processes at all.
  1030. */
  1031. DWORD err = GetLastError();
  1032. if (err != ERROR_ACCESS_DENIED)
  1033. uv_fatal_error(err, "AssignProcessToJobObject");
  1034. }
  1035. }
  1036. if (process_flags & CREATE_SUSPENDED) {
  1037. if (ResumeThread(info.hThread) == ((DWORD)-1)) {
  1038. err = GetLastError();
  1039. TerminateProcess(info.hProcess, 1);
  1040. goto done;
  1041. }
  1042. }
  1043. /* Spawn succeeded. Beyond this point, failure is reported asynchronously. */
  1044. process->process_handle = info.hProcess;
  1045. process->pid = info.dwProcessId;
  1046. /* Set IPC pid to all IPC pipes. */
  1047. for (i = 0; i < options->stdio_count; i++) {
  1048. const uv_stdio_container_t* fdopt = &options->stdio[i];
  1049. if (fdopt->flags & UV_CREATE_PIPE &&
  1050. fdopt->data.stream->type == UV_NAMED_PIPE &&
  1051. ((uv_pipe_t*) fdopt->data.stream)->ipc) {
  1052. ((uv_pipe_t*) fdopt->data.stream)->pipe.conn.ipc_remote_pid =
  1053. info.dwProcessId;
  1054. }
  1055. }
  1056. /* Setup notifications for when the child process exits. */
  1057. result = RegisterWaitForSingleObject(&process->wait_handle,
  1058. process->process_handle, exit_wait_callback, (void*)process, INFINITE,
  1059. WT_EXECUTEINWAITTHREAD | WT_EXECUTEONLYONCE);
  1060. if (!result) {
  1061. uv_fatal_error(GetLastError(), "RegisterWaitForSingleObject");
  1062. }
  1063. CloseHandle(info.hThread);
  1064. assert(!err);
  1065. /* Make the handle active. It will remain active until the exit callback is
  1066. * made or the handle is closed, whichever happens first. */
  1067. uv__handle_start(process);
  1068. /* Cleanup, whether we succeeded or failed. */
  1069. done:
  1070. uv__free(application);
  1071. uv__free(application_path);
  1072. uv__free(arguments);
  1073. uv__free(cwd);
  1074. uv__free(env);
  1075. uv__free(alloc_path);
  1076. if (process->child_stdio_buffer != NULL) {
  1077. /* Clean up child stdio handles. */
  1078. uv__stdio_destroy(process->child_stdio_buffer);
  1079. process->child_stdio_buffer = NULL;
  1080. }
  1081. return uv_translate_sys_error(err);
  1082. }
  1083. static int uv__kill(HANDLE process_handle, int signum) {
  1084. if (signum < 0 || signum >= NSIG) {
  1085. return UV_EINVAL;
  1086. }
  1087. switch (signum) {
  1088. case SIGTERM:
  1089. case SIGKILL:
  1090. case SIGINT: {
  1091. /* Unconditionally terminate the process. On Windows, killed processes
  1092. * normally return 1. */
  1093. DWORD status;
  1094. int err;
  1095. if (TerminateProcess(process_handle, 1))
  1096. return 0;
  1097. /* If the process already exited before TerminateProcess was called,.
  1098. * TerminateProcess will fail with ERROR_ACCESS_DENIED. */
  1099. err = GetLastError();
  1100. if (err == ERROR_ACCESS_DENIED &&
  1101. GetExitCodeProcess(process_handle, &status) &&
  1102. status != STILL_ACTIVE) {
  1103. return UV_ESRCH;
  1104. }
  1105. return uv_translate_sys_error(err);
  1106. }
  1107. case 0: {
  1108. /* Health check: is the process still alive? */
  1109. DWORD status;
  1110. if (!GetExitCodeProcess(process_handle, &status))
  1111. return uv_translate_sys_error(GetLastError());
  1112. if (status != STILL_ACTIVE)
  1113. return UV_ESRCH;
  1114. return 0;
  1115. }
  1116. default:
  1117. /* Unsupported signal. */
  1118. return UV_ENOSYS;
  1119. }
  1120. }
  1121. int uv_process_kill(uv_process_t* process, int signum) {
  1122. int err;
  1123. if (process->process_handle == INVALID_HANDLE_VALUE) {
  1124. return UV_EINVAL;
  1125. }
  1126. err = uv__kill(process->process_handle, signum);
  1127. if (err) {
  1128. return err; /* err is already translated. */
  1129. }
  1130. process->exit_signal = signum;
  1131. return 0;
  1132. }
  1133. int uv_kill(int pid, int signum) {
  1134. int err;
  1135. HANDLE process_handle;
  1136. if (pid == 0) {
  1137. process_handle = GetCurrentProcess();
  1138. } else {
  1139. process_handle = OpenProcess(PROCESS_TERMINATE | PROCESS_QUERY_INFORMATION,
  1140. FALSE,
  1141. pid);
  1142. }
  1143. if (process_handle == NULL) {
  1144. err = GetLastError();
  1145. if (err == ERROR_INVALID_PARAMETER) {
  1146. return UV_ESRCH;
  1147. } else {
  1148. return uv_translate_sys_error(err);
  1149. }
  1150. }
  1151. err = uv__kill(process_handle, signum);
  1152. CloseHandle(process_handle);
  1153. return err; /* err is already translated. */
  1154. }