posix-w32.c 34 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303
  1. /* Copyright 2001,2006,2008,2016,2018,2021
  2. Free Software Foundation, Inc.
  3. This file is part of Guile.
  4. Guile is free software: you can redistribute it and/or modify it
  5. under the terms of the GNU Lesser General Public License as published
  6. by the Free Software Foundation, either version 3 of the License, or
  7. (at your option) any later version.
  8. Guile is distributed in the hope that it will be useful, but WITHOUT
  9. ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  10. FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
  11. License for more details.
  12. You should have received a copy of the GNU Lesser General Public
  13. License along with Guile. If not, see
  14. <https://www.gnu.org/licenses/>. */
  15. #ifdef HAVE_CONFIG_H
  16. # include <config.h>
  17. #endif
  18. #define WIN32_LEAN_AND_MEAN
  19. #include <windows.h>
  20. #include <c-strcase.h>
  21. #include <ctype.h>
  22. #include <process.h>
  23. #include <stdio.h>
  24. #include <stdlib.h>
  25. #include <string.h>
  26. #include <errno.h>
  27. #include <signal.h>
  28. #include <io.h>
  29. #include <fcntl.h>
  30. #include "gc.h" /* for scm_*alloc, scm_strdup */
  31. #include "filename.h"
  32. #include "threads.h" /* for scm_i_scm_pthread_mutex_lock */
  33. #include "posix-w32.h"
  34. /*
  35. * Get name and information about current kernel.
  36. */
  37. int
  38. uname (struct utsname *uts)
  39. {
  40. enum { WinNT, Win95, Win98, WinUnknown };
  41. OSVERSIONINFO osver;
  42. SYSTEM_INFO sysinfo;
  43. DWORD sLength;
  44. DWORD os = WinUnknown;
  45. memset (uts, 0, sizeof (*uts));
  46. osver.dwOSVersionInfoSize = sizeof (osver);
  47. GetVersionEx (&osver);
  48. GetSystemInfo (&sysinfo);
  49. switch (osver.dwPlatformId)
  50. {
  51. case VER_PLATFORM_WIN32_NT: /* NT, Windows 2000 or Windows XP */
  52. if (osver.dwMajorVersion == 4)
  53. strcpy (uts->sysname, "Windows NT4x"); /* NT4x */
  54. else if (osver.dwMajorVersion <= 3)
  55. strcpy (uts->sysname, "Windows NT3x"); /* NT3x */
  56. else if (osver.dwMajorVersion == 5 && osver.dwMinorVersion < 1)
  57. strcpy (uts->sysname, "Windows 2000"); /* 2k */
  58. else if (osver.dwMajorVersion < 6)
  59. strcpy (uts->sysname, "Windows XP"); /* XP */
  60. else if (osver.dwMajorVersion == 6)
  61. {
  62. if (osver.dwMinorVersion < 1)
  63. strcpy (uts->sysname, "Windows Vista"); /* Vista */
  64. else if (osver.dwMinorVersion < 2)
  65. strcpy (uts->sysname, "Windows 7"); /* Windows 7 */
  66. else if (osver.dwMinorVersion < 3)
  67. strcpy (uts->sysname, "Windows 8"); /* Windows 8 */
  68. else if (osver.dwMinorVersion < 4)
  69. strcpy (uts->sysname, "Windows 8.1"); /* Windows 8.1 */
  70. }
  71. else if (osver.dwMajorVersion >= 10)
  72. strcpy (uts->sysname, "Windows 10 or later"); /* Windows 10 and later */
  73. os = WinNT;
  74. break;
  75. case VER_PLATFORM_WIN32_WINDOWS: /* Win95, Win98 or WinME */
  76. if ((osver.dwMajorVersion > 4) ||
  77. ((osver.dwMajorVersion == 4) && (osver.dwMinorVersion > 0)))
  78. {
  79. if (osver.dwMinorVersion >= 90)
  80. strcpy (uts->sysname, "Windows ME"); /* ME */
  81. else
  82. strcpy (uts->sysname, "Windows 98"); /* 98 */
  83. os = Win98;
  84. }
  85. else
  86. {
  87. strcpy (uts->sysname, "Windows 95"); /* 95 */
  88. os = Win95;
  89. }
  90. break;
  91. case VER_PLATFORM_WIN32s: /* Windows 3.x */
  92. strcpy (uts->sysname, "Windows");
  93. break;
  94. }
  95. sprintf (uts->version, "%ld.%02ld",
  96. osver.dwMajorVersion, osver.dwMinorVersion);
  97. if (osver.szCSDVersion[0] != '\0' &&
  98. (strlen (osver.szCSDVersion) + strlen (uts->version) + 1) <
  99. sizeof (uts->version))
  100. {
  101. strcat (uts->version, " ");
  102. strcat (uts->version, osver.szCSDVersion);
  103. }
  104. sprintf (uts->release, "build %ld", osver.dwBuildNumber & 0xFFFF);
  105. switch (sysinfo.wProcessorArchitecture)
  106. {
  107. case PROCESSOR_ARCHITECTURE_PPC:
  108. strcpy (uts->machine, "ppc");
  109. break;
  110. case PROCESSOR_ARCHITECTURE_ALPHA:
  111. strcpy (uts->machine, "alpha");
  112. break;
  113. case PROCESSOR_ARCHITECTURE_MIPS:
  114. strcpy (uts->machine, "mips");
  115. break;
  116. case PROCESSOR_ARCHITECTURE_IA64:
  117. strcpy (uts->machine, "ia64");
  118. break;
  119. case PROCESSOR_ARCHITECTURE_INTEL:
  120. /*
  121. * dwProcessorType is only valid in Win95 and Win98 and WinME
  122. * wProcessorLevel is only valid in WinNT
  123. */
  124. switch (os)
  125. {
  126. case Win95:
  127. case Win98:
  128. switch (sysinfo.dwProcessorType)
  129. {
  130. case PROCESSOR_INTEL_386:
  131. case PROCESSOR_INTEL_486:
  132. case PROCESSOR_INTEL_PENTIUM:
  133. sprintf (uts->machine, "i%ld", sysinfo.dwProcessorType);
  134. break;
  135. default:
  136. strcpy (uts->machine, "i386");
  137. break;
  138. }
  139. break;
  140. case WinNT:
  141. sprintf (uts->machine, "i%d86", sysinfo.wProcessorLevel);
  142. break;
  143. default:
  144. strcpy (uts->machine, "unknown");
  145. break;
  146. }
  147. break;
  148. case PROCESSOR_ARCHITECTURE_AMD64:
  149. strcpy (uts->machine, "x86_64");
  150. break;
  151. default:
  152. strcpy (uts->machine, "unknown");
  153. break;
  154. }
  155. sLength = sizeof (uts->nodename) - 1;
  156. GetComputerName (uts->nodename, &sLength);
  157. return 0;
  158. }
  159. /* Utility functions for maintaining the list of subprocesses launched
  160. by Guile. */
  161. struct proc_record {
  162. DWORD pid;
  163. HANDLE handle;
  164. };
  165. static struct proc_record *procs;
  166. static ptrdiff_t proc_size;
  167. /* Find the process slot that corresponds to PID. Return the index of
  168. the slot, or -1 if not found. */
  169. static ptrdiff_t
  170. find_proc (pid_t pid)
  171. {
  172. ptrdiff_t found = -1, i;
  173. for (i = 0; i < proc_size; i++)
  174. {
  175. if (procs[i].pid == pid && procs[i].handle != INVALID_HANDLE_VALUE)
  176. found = i;
  177. }
  178. return found;
  179. }
  180. /* Return the process handle corresponding to its PID. If not found,
  181. return invalid handle value. */
  182. static HANDLE
  183. proc_handle (pid_t pid)
  184. {
  185. ptrdiff_t idx = find_proc (pid);
  186. if (idx < 0)
  187. return INVALID_HANDLE_VALUE;
  188. return procs[idx].handle;
  189. }
  190. /* Store a process record in the procs[] array. */
  191. static void
  192. record_proc (pid_t proc_pid, HANDLE proc_handle)
  193. {
  194. ptrdiff_t i;
  195. /* Find a vacant slot. */
  196. for (i = 0; i < proc_size; i++)
  197. {
  198. if (procs[i].handle == INVALID_HANDLE_VALUE)
  199. break;
  200. }
  201. /* If no vacant slot, enlarge the array. */
  202. if (i == proc_size)
  203. {
  204. proc_size++;
  205. procs = scm_realloc (procs, proc_size * sizeof(procs[0]));
  206. }
  207. /* Store the process data. */
  208. procs[i].pid = proc_pid;
  209. procs[i].handle = proc_handle;
  210. }
  211. /* Delete a process record for process PID. */
  212. static void
  213. delete_proc (pid_t pid)
  214. {
  215. ptrdiff_t idx = find_proc (pid);
  216. if (0 <= idx && idx < proc_size)
  217. procs[idx].handle = INVALID_HANDLE_VALUE;
  218. }
  219. /* Run a child process with redirected standard handles, without
  220. redirecting standard handles of the parent. This is required in
  221. multithreaded programs, where redirecting a standard handle affects
  222. all threads. */
  223. /* Prepare a possibly redirected file handle to be passed to a child
  224. process. The handle is for the file/device open on file descriptor
  225. FD; if FD is invalid, use the null device instead.
  226. USE_STD non-zero means we have been passed the descriptor used by
  227. the parent.
  228. ACCESS is the Windows access mode for opening the null device.
  229. Returns the Win32 handle to be passed to CreateProcess. */
  230. static HANDLE
  231. prepare_child_handle (int fd, int use_std, DWORD access)
  232. {
  233. HANDLE htem, hret;
  234. DWORD err = 0;
  235. /* Start with the descriptor, if specified by the caller and valid,
  236. otherwise open the null device. */
  237. if (fd < 0)
  238. htem = INVALID_HANDLE_VALUE;
  239. else
  240. htem = (HANDLE)_get_osfhandle (fd);
  241. /* Duplicate the handle and make it inheritable. */
  242. if (DuplicateHandle (GetCurrentProcess (),
  243. htem,
  244. GetCurrentProcess (),
  245. &hret,
  246. 0,
  247. TRUE,
  248. DUPLICATE_SAME_ACCESS) == FALSE)
  249. {
  250. /* If the original standard handle was invalid (happens, e.g.,
  251. in GUI programs), open the null device instead. */
  252. if ((err = GetLastError ()) == ERROR_INVALID_HANDLE
  253. && use_std)
  254. {
  255. htem = CreateFile ("NUL", access,
  256. FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
  257. OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
  258. if (htem != INVALID_HANDLE_VALUE
  259. && DuplicateHandle (GetCurrentProcess (),
  260. htem,
  261. GetCurrentProcess (),
  262. &hret,
  263. 0,
  264. TRUE,
  265. DUPLICATE_SAME_ACCESS) == FALSE)
  266. {
  267. err = GetLastError ();
  268. CloseHandle (htem);
  269. hret = INVALID_HANDLE_VALUE;
  270. }
  271. }
  272. }
  273. if (hret == INVALID_HANDLE_VALUE)
  274. {
  275. switch (err)
  276. {
  277. case ERROR_NO_MORE_FILES:
  278. errno = EMFILE;
  279. break;
  280. case ERROR_INVALID_HANDLE:
  281. default:
  282. errno = EBADF;
  283. break;
  284. }
  285. }
  286. return hret;
  287. }
  288. /* A comparison function for sorting the environment. */
  289. static int
  290. compenv (const void *a1, const void *a2)
  291. {
  292. return stricmp (*((char**)a1), *((char**)a2));
  293. }
  294. /* Convert the program's 'environ' array to a block of environment
  295. variables suitable to be passed to CreateProcess. This is needed
  296. to ensure the child process inherits the up-to-date environment of
  297. the parent, including any variables inserted by the parent. */
  298. static void
  299. prepare_envblk (char **envp, char **envblk)
  300. {
  301. char **tmp;
  302. int size_needed;
  303. int envcnt;
  304. char *ptr;
  305. for (envcnt = 0; envp[envcnt]; envcnt++)
  306. ;
  307. tmp = scm_calloc ((envcnt + 1) * sizeof (*tmp));
  308. for (envcnt = size_needed = 0; envp[envcnt]; envcnt++)
  309. {
  310. tmp[envcnt] = envp[envcnt];
  311. size_needed += strlen (envp[envcnt]) + 1;
  312. }
  313. size_needed++;
  314. /* Windows likes its environment variables sorted. */
  315. qsort ((void *) tmp, (size_t) envcnt, sizeof (char *), compenv);
  316. /* CreateProcess needs the environment block as a linear array,
  317. where each variable is terminated by a null character, and the
  318. last one is terminated by 2 null characters. */
  319. ptr = *envblk = scm_calloc (size_needed);
  320. for (envcnt = 0; tmp[envcnt]; envcnt++)
  321. {
  322. strcpy (ptr, tmp[envcnt]);
  323. ptr += strlen (tmp[envcnt]) + 1;
  324. }
  325. free (tmp);
  326. }
  327. /* Find an executable PROGRAM on PATH, return result in malloc'ed
  328. storage. If PROGRAM is /bin/sh, and no sh.exe was found on PATH,
  329. fall back on the Windows shell and set BIN_SH_REPLACED to non-zero. */
  330. static char *
  331. lookup_cmd (const char *program, int *bin_sh_replaced)
  332. {
  333. static const char *extensions[] = {
  334. ".exe", ".cmd", ".bat", "", ".com", NULL
  335. };
  336. int bin_sh_requested = 0;
  337. char *path, *dir, *sep;
  338. char abs_name[MAX_PATH];
  339. DWORD abs_namelen = 0;
  340. /* If they ask for the Unix system shell, try to find it on PATH. */
  341. if (c_strcasecmp (program, "/bin/sh") == 0)
  342. {
  343. bin_sh_requested = 1;
  344. program = "sh.exe";
  345. }
  346. /* If PROGRAM includes leading directories, the caller already did
  347. our job. */
  348. if (strchr (program, '/') != NULL
  349. || strchr (program, '\\') != NULL)
  350. return scm_strdup (program);
  351. /* Note: It is OK for getenv below to return NULL -- in that case,
  352. SearchPath will search in the directories whose list is specified
  353. by the system Registry. */
  354. path = getenv ("PATH");
  355. if (!path) /* shouldn't happen, really */
  356. path = ".";
  357. dir = sep = path = strdup (path);
  358. for ( ; sep && *sep; dir = sep + 1)
  359. {
  360. int i;
  361. sep = strpbrk (dir, ";");
  362. if (sep == dir) /* two or more ;'s in a row */
  363. continue;
  364. if (sep)
  365. *sep = '\0';
  366. for (i = 0; extensions[i]; i++)
  367. {
  368. abs_namelen = SearchPath (dir, program, extensions[i],
  369. MAX_PATH, abs_name, NULL);
  370. if (0 < abs_namelen && abs_namelen <= MAX_PATH) /* found! */
  371. break;
  372. }
  373. if (extensions[i]) /* found! */
  374. break;
  375. if (sep)
  376. *sep = ';';
  377. }
  378. free (path);
  379. /* If they asked for /bin/sh and we didn't find it, fall back on the
  380. default Windows shell. */
  381. if (abs_namelen <= 0 && bin_sh_requested)
  382. {
  383. const char *shell = getenv ("ComSpec");
  384. if (!shell)
  385. shell = "C:\\Windows\\system32\\cmd.exe";
  386. *bin_sh_replaced = 1;
  387. strcpy (abs_name, shell);
  388. abs_namelen = strlen (abs_name);
  389. }
  390. /* If not found, return the original PROGRAM name. */
  391. if (abs_namelen <= 0 || abs_namelen > MAX_PATH)
  392. return scm_strdup (program);
  393. return scm_strndup (abs_name, abs_namelen);
  394. }
  395. /* Concatenate command-line arguments in argv[] into a single
  396. command-line string, while quoting arguments as needed. The result
  397. is malloc'ed. */
  398. static char *
  399. prepare_cmdline (const char *cmd, const char * const *argv, int bin_sh_replaced)
  400. {
  401. /* These characters should include anything that is special to _any_
  402. program, including both Windows and Unixy shells, and the
  403. widlcard expansion in startup code of a typical Windows app. */
  404. const char need_quotes[] = " \t#;\"\'*?[]&|<>(){}$`^";
  405. size_t cmdlen = 1; /* for terminating null */
  406. char *cmdline = scm_malloc (cmdlen);
  407. char *dst = cmdline;
  408. int cmd_exe_quoting = 0;
  409. int i;
  410. const char *p;
  411. /* Are we constructing a command line for cmd.exe? */
  412. if (bin_sh_replaced)
  413. cmd_exe_quoting = 1;
  414. else
  415. {
  416. for (p = cmd + strlen (cmd);
  417. p > cmd && p[-1] != '/' && p[-1] != '\\' && p[-1] != ':';
  418. p--)
  419. ;
  420. if (c_strcasecmp (p, "cmd.exe") == 0
  421. || c_strcasecmp (p, "cmd") == 0)
  422. cmd_exe_quoting = 1;
  423. }
  424. /* Initialize the command line to empty. */
  425. *dst = '\0';
  426. /* Append arguments, if any, from argv[]. */
  427. for (i = 0; argv[i]; i++)
  428. {
  429. const char *src = argv[i];
  430. size_t len;
  431. int quote_this = 0, n_backslashes = 0;
  432. int j;
  433. /* Append the blank separator. We don't do that for argv[0]
  434. because that is the command name (will end up in child's
  435. argv[0]), and is only recognized as such if there're no
  436. blanks before it. */
  437. if (i > 0)
  438. *dst++ = ' ';
  439. len = dst - cmdline;
  440. /* How much space is required for this argument? */
  441. cmdlen += strlen (argv[i]) + 1; /* 1 for a blank separator */
  442. /* cmd.exe needs a different style of quoting: all the arguments
  443. beyond the /c switch are enclosed in an extra pair of quotes,
  444. and not otherwise quoted/escaped. */
  445. if (cmd_exe_quoting)
  446. {
  447. if (i == 2)
  448. cmdlen += 2;
  449. }
  450. else if (strpbrk (argv[i], need_quotes))
  451. {
  452. quote_this = 1;
  453. cmdlen += 2;
  454. for ( ; *src; src++)
  455. {
  456. /* An embedded quote needs to be escaped by a backslash.
  457. Any backslashes immediately preceding that quote need
  458. each one to be escaped by another backslash. */
  459. if (*src == '\"')
  460. cmdlen += n_backslashes + 1;
  461. if (*src == '\\')
  462. n_backslashes++;
  463. else
  464. n_backslashes = 0;
  465. }
  466. /* If the closing quote we will add is preceded by
  467. backslashes, those backslashes need to be escaped. */
  468. cmdlen += n_backslashes;
  469. }
  470. /* Enlarge the command-line string as needed. */
  471. cmdline = scm_realloc (cmdline, cmdlen);
  472. dst = cmdline + len;
  473. if (i == 0
  474. && c_strcasecmp (argv[0], "/bin/sh") == 0
  475. && bin_sh_replaced)
  476. {
  477. strcpy (dst, "cmd.exe");
  478. dst += sizeof ("cmd.exe") - 1;
  479. continue;
  480. }
  481. if (i == 1 && bin_sh_replaced && strcmp (argv[1], "-c") == 0)
  482. {
  483. *dst++ = '/';
  484. *dst++ = 'c';
  485. *dst = '\0';
  486. continue;
  487. }
  488. /* Add this argument, possibly quoted, to the command line. */
  489. if (quote_this || (i == 2 && cmd_exe_quoting))
  490. *dst++ = '\"';
  491. for (src = argv[i]; *src; src++)
  492. {
  493. if (quote_this)
  494. {
  495. if (*src == '\"')
  496. for (j = n_backslashes + 1; j > 0; j--)
  497. *dst++ = '\\';
  498. if (*src == '\\')
  499. n_backslashes++;
  500. else
  501. n_backslashes = 0;
  502. }
  503. *dst++ = *src;
  504. }
  505. if (quote_this)
  506. {
  507. for (j = n_backslashes; j > 0; j--)
  508. *dst++ = '\\';
  509. *dst++ = '\"';
  510. }
  511. *dst = '\0';
  512. }
  513. if (cmd_exe_quoting && i > 2)
  514. {
  515. /* One extra slot was already reserved when we enlarged cmdlen
  516. by 2 in the "if (cmd_exe_quoting)" clause above. So we can
  517. safely append a closing quote. */
  518. *dst++ = '\"';
  519. *dst = '\0';
  520. }
  521. return cmdline;
  522. }
  523. /* Start a child process running the program in EXEC_FILE with its
  524. standard input and output optionally redirected to a pipe. ARGV is
  525. the array of command-line arguments to pass to the child. P2C and
  526. C2P are 2 pipes for communicating with the child, and ERRFD is the
  527. standard error file descriptor to be inherited by the child.
  528. READING and WRITING, if non-zero, mean that the corresponding pipe
  529. will be used.
  530. Return the PID of the child process, or -1 if couldn't start a
  531. process. */
  532. pid_t
  533. start_child (const char *exec_file, char **argv,
  534. int reading, int c2p[2], int writing, int p2c[2],
  535. int infd, int outfd, int errfd)
  536. {
  537. HANDLE hin = INVALID_HANDLE_VALUE, hout = INVALID_HANDLE_VALUE;
  538. HANDLE herr = INVALID_HANDLE_VALUE;
  539. STARTUPINFO si;
  540. char *env_block = NULL;
  541. char *cmdline = NULL;
  542. PROCESS_INFORMATION pi;
  543. char *progfile, *p;
  544. int errno_save;
  545. intptr_t pid;
  546. int bin_sh_replaced = 0;
  547. if (!reading)
  548. c2p[1] = outfd;
  549. if (!writing)
  550. p2c[0] = infd;
  551. /* Prepare standard handles to be passed to the child process. */
  552. hin = prepare_child_handle (p2c[0], !writing, GENERIC_READ);
  553. if (hin == INVALID_HANDLE_VALUE)
  554. return -1;
  555. hout = prepare_child_handle (c2p[1], !reading, GENERIC_WRITE);
  556. if (hout == INVALID_HANDLE_VALUE)
  557. return -1;
  558. herr = prepare_child_handle (errfd, 1, GENERIC_WRITE);
  559. if (herr == INVALID_HANDLE_VALUE)
  560. return -1;
  561. /* Make sure the parent side of both pipes is not inherited. This
  562. is required because gnulib's 'pipe' creates pipes whose both ends
  563. are inheritable, which is traditional on Posix (where pipe
  564. descriptors are implicitly duplicated by 'fork'), but wrong on
  565. Windows (where pipe handles need to be explicitly
  566. duplicated). */
  567. if (writing)
  568. SetHandleInformation ((HANDLE)_get_osfhandle (p2c[1]),
  569. HANDLE_FLAG_INHERIT, 0);
  570. if (reading)
  571. {
  572. SetHandleInformation ((HANDLE)_get_osfhandle (c2p[0]),
  573. HANDLE_FLAG_INHERIT, 0);
  574. /* Gnulib's 'pipe' opens the pipe in binary mode, but we don't
  575. want to read text-mode input of subprocesses in binary more,
  576. because then we will get the ^M (a.k.a. "CR") characters we
  577. don't expect. */
  578. _setmode (c2p[0], _O_TEXT);
  579. }
  580. /* Set up the startup info for the child, using the parent's as the
  581. starting point, and specify in it the redirected handles. */
  582. GetStartupInfo (&si);
  583. si.dwFlags = STARTF_USESTDHANDLES;
  584. si.lpReserved = 0;
  585. si.cbReserved2 = 0;
  586. si.lpReserved2 = 0;
  587. si.hStdInput = hin;
  588. si.hStdOutput = hout;
  589. si.hStdError = herr;
  590. /* Create the environment block for the child. This is needed
  591. because the environment we have in 'environ' is not in the format
  592. expected by CreateProcess. */
  593. prepare_envblk (environ, &env_block);
  594. /* CreateProcess doesn't search PATH, so we must do that for it. */
  595. progfile = lookup_cmd (exec_file, &bin_sh_replaced);
  596. /* CreateProcess doesn't like forward slashes in the application
  597. file name. */
  598. for (p = progfile; *p; p++)
  599. if (*p == '/')
  600. *p = '\\';
  601. /* Construct the command line. */
  602. cmdline = prepare_cmdline (exec_file, (const char * const *)argv,
  603. bin_sh_replaced);
  604. /* When running in WINE, chances are we hit ENOENT (possibly
  605. translated to ENOEXEC). */
  606. errno = 0;
  607. /* All set and ready to fly. Launch the child process. */
  608. if (!CreateProcess (progfile, cmdline, NULL, NULL, TRUE, 0, env_block, NULL,
  609. &si, &pi))
  610. {
  611. pid = -1;
  612. /* Since we use Win32 APIs directly, we need to translate their
  613. errors to errno values by hand. */
  614. switch (GetLastError ())
  615. {
  616. case ERROR_FILE_NOT_FOUND:
  617. case ERROR_PATH_NOT_FOUND:
  618. case ERROR_INVALID_DRIVE:
  619. case ERROR_BAD_PATHNAME:
  620. errno = ENOENT;
  621. break;
  622. case ERROR_ACCESS_DENIED:
  623. errno = EACCES;
  624. break;
  625. case ERROR_BAD_ENVIRONMENT:
  626. errno = E2BIG;
  627. break;
  628. case ERROR_BROKEN_PIPE:
  629. errno = EPIPE;
  630. break;
  631. case ERROR_INVALID_HANDLE:
  632. errno = EBADF;
  633. break;
  634. case ERROR_MAX_THRDS_REACHED:
  635. errno = EAGAIN;
  636. break;
  637. case ERROR_BAD_EXE_FORMAT:
  638. case ERROR_BAD_FORMAT:
  639. default:
  640. errno = ENOEXEC;
  641. break;
  642. }
  643. }
  644. else
  645. {
  646. scm_i_scm_pthread_mutex_lock (&scm_i_misc_mutex);
  647. record_proc (pi.dwProcessId, pi.hProcess);
  648. scm_i_pthread_mutex_unlock (&scm_i_misc_mutex);
  649. pid = pi.dwProcessId;
  650. }
  651. errno_save = errno;
  652. /* Free resources. */
  653. free (progfile);
  654. free (cmdline);
  655. free (env_block);
  656. CloseHandle (hin);
  657. CloseHandle (hout);
  658. CloseHandle (herr);
  659. CloseHandle (pi.hThread);
  660. errno = errno_save;
  661. return pid;
  662. }
  663. /* Emulation of waitpid which only supports WNOHANG, since _cwait doesn't. */
  664. int
  665. waitpid (pid_t pid, int *status, int options)
  666. {
  667. HANDLE ph;
  668. /* Not supported on MS-Windows. */
  669. if (pid <= 0)
  670. {
  671. errno = ENOSYS;
  672. return -1;
  673. }
  674. scm_i_scm_pthread_mutex_lock (&scm_i_misc_mutex);
  675. ph = proc_handle (pid);
  676. scm_i_pthread_mutex_unlock (&scm_i_misc_mutex);
  677. /* Since scm_waitpid is documented to work only on child processes,
  678. being unable to find a process in our records means failure. */
  679. if (ph == INVALID_HANDLE_VALUE)
  680. {
  681. errno = ECHILD;
  682. return -1;
  683. }
  684. if ((options & WNOHANG) != 0)
  685. {
  686. DWORD st;
  687. if (!GetExitCodeProcess (ph, &st))
  688. {
  689. errno = ECHILD;
  690. return -1;
  691. }
  692. if (st == STILL_ACTIVE)
  693. return 0;
  694. if (status)
  695. *status = st;
  696. CloseHandle (ph);
  697. }
  698. else
  699. _cwait (status, (intptr_t)ph, WAIT_CHILD);
  700. scm_i_scm_pthread_mutex_lock (&scm_i_misc_mutex);
  701. delete_proc (pid);
  702. scm_i_pthread_mutex_unlock (&scm_i_misc_mutex);
  703. return pid;
  704. }
  705. /* Translate abnormal exit status of Windows programs into the signal
  706. that terminated the program. This is required to support scm_kill
  707. and WTERMSIG. */
  708. struct signal_and_status {
  709. int sig;
  710. DWORD status;
  711. };
  712. static const struct signal_and_status sigtbl[] = {
  713. {SIGSEGV, 0xC0000005}, /* access to invalid address */
  714. {SIGSEGV, 0xC0000008}, /* invalid handle */
  715. {SIGILL, 0xC000001D}, /* illegal instruction */
  716. {SIGILL, 0xC0000025}, /* non-continuable instruction */
  717. {SIGSEGV, 0xC000008C}, /* array bounds exceeded */
  718. {SIGFPE, 0xC000008D}, /* float denormal */
  719. {SIGFPE, 0xC000008E}, /* float divide by zero */
  720. {SIGFPE, 0xC000008F}, /* float inexact */
  721. {SIGFPE, 0xC0000090}, /* float invalid operation */
  722. {SIGFPE, 0xC0000091}, /* float overflow */
  723. {SIGFPE, 0xC0000092}, /* float stack check */
  724. {SIGFPE, 0xC0000093}, /* float underflow */
  725. {SIGFPE, 0xC0000094}, /* integer divide by zero */
  726. {SIGFPE, 0xC0000095}, /* integer overflow */
  727. {SIGILL, 0xC0000096}, /* privileged instruction */
  728. {SIGSEGV, 0xC00000FD}, /* stack overflow */
  729. {SIGTERM, 0xC000013A}, /* Ctrl-C exit */
  730. {SIGINT, 0xC000013A}
  731. };
  732. static int
  733. w32_signal_to_status (int sig)
  734. {
  735. int i;
  736. for (i = 0; i < sizeof (sigtbl) / sizeof (sigtbl[0]); i++)
  737. if (sig == sigtbl[i].sig)
  738. return sigtbl[i].status;
  739. return (int)0xC000013A;
  740. }
  741. int
  742. w32_status_to_termsig (DWORD status)
  743. {
  744. int i;
  745. for (i = 0; i < sizeof (sigtbl) / sizeof (sigtbl[0]); i++)
  746. if (status == sigtbl[i].status)
  747. return sigtbl[i].sig;
  748. return SIGTERM;
  749. }
  750. /* Support for scm_kill. */
  751. int
  752. kill (int pid, int sig)
  753. {
  754. HANDLE ph;
  755. int child_proc = 0;
  756. if (pid == getpid ())
  757. {
  758. if (raise (sig) == 0)
  759. errno = ENOSYS;
  760. return -1;
  761. }
  762. scm_i_scm_pthread_mutex_lock (&scm_i_misc_mutex);
  763. ph = proc_handle (pid);
  764. scm_i_pthread_mutex_unlock (&scm_i_misc_mutex);
  765. /* If not found among our subprocesses, look elsewhere in the
  766. system. */
  767. if (ph == INVALID_HANDLE_VALUE)
  768. ph = OpenProcess (PROCESS_TERMINATE, 0, pid);
  769. else
  770. child_proc = 1;
  771. if (!ph)
  772. {
  773. errno = EPERM;
  774. return -1;
  775. }
  776. if (!TerminateProcess (ph, w32_signal_to_status (sig)))
  777. {
  778. /* If it's our subprocess, it could have already exited. In
  779. that case, waitpid will handily delete the process from our
  780. records, and we should return a more meaningful ESRCH to the
  781. caller. */
  782. if (child_proc && waitpid (pid, NULL, WNOHANG) == pid)
  783. errno = ESRCH;
  784. else
  785. errno = EINVAL;
  786. return -1;
  787. }
  788. CloseHandle (ph);
  789. if (child_proc)
  790. {
  791. scm_i_scm_pthread_mutex_lock (&scm_i_misc_mutex);
  792. delete_proc (pid);
  793. scm_i_pthread_mutex_unlock (&scm_i_misc_mutex);
  794. }
  795. return 0;
  796. }
  797. /* Emulation of getpriority and setpriority. */
  798. #define NZERO 8
  799. int
  800. getpriority (int which, int who)
  801. {
  802. HANDLE hp;
  803. int nice_value = -1;
  804. int error = 0;
  805. int child_proc = 0;
  806. /* We don't support process groups and users. */
  807. if (which != PRIO_PROCESS)
  808. {
  809. errno = ENOSYS;
  810. return -1;
  811. }
  812. if (who == 0)
  813. hp = GetCurrentProcess ();
  814. else
  815. {
  816. scm_i_scm_pthread_mutex_lock (&scm_i_misc_mutex);
  817. hp = proc_handle (who);
  818. scm_i_pthread_mutex_unlock (&scm_i_misc_mutex);
  819. /* If not found among our subprocesses, look elsewhere in the
  820. system. */
  821. if (hp == INVALID_HANDLE_VALUE)
  822. hp = OpenProcess (PROCESS_QUERY_INFORMATION, FALSE, who);
  823. else
  824. child_proc = 1;
  825. }
  826. if (hp)
  827. {
  828. DWORD pri_class = GetPriorityClass (hp);
  829. /* The pseudo-handle returned by GetCurrentProcess doesn't need
  830. to be closed. */
  831. if (who > 0 && !child_proc)
  832. CloseHandle (hp);
  833. if (pri_class > 0)
  834. {
  835. switch (pri_class)
  836. {
  837. case IDLE_PRIORITY_CLASS:
  838. nice_value = 4;
  839. break;
  840. case BELOW_NORMAL_PRIORITY_CLASS:
  841. nice_value = 6;
  842. break;
  843. case NORMAL_PRIORITY_CLASS:
  844. nice_value = 8;
  845. break;
  846. case ABOVE_NORMAL_PRIORITY_CLASS:
  847. nice_value = 10;
  848. break;
  849. case HIGH_PRIORITY_CLASS:
  850. nice_value = 13;
  851. break;
  852. case REALTIME_PRIORITY_CLASS:
  853. nice_value = 24;
  854. break;
  855. }
  856. /* If WHO is us, we can provide a more fine-grained value by
  857. looking at the current thread's priority value. (For
  858. other processes, it is not clear which thread to use.) */
  859. if (who == 0 || who == GetCurrentProcessId ())
  860. {
  861. HANDLE ht = GetCurrentThread ();
  862. int tprio = GetThreadPriority (ht);
  863. switch (tprio)
  864. {
  865. case THREAD_PRIORITY_IDLE:
  866. if (pri_class == REALTIME_PRIORITY_CLASS)
  867. nice_value = 16;
  868. else
  869. nice_value = 1;
  870. break;
  871. case THREAD_PRIORITY_TIME_CRITICAL:
  872. if (pri_class == REALTIME_PRIORITY_CLASS)
  873. nice_value = 31;
  874. else
  875. nice_value = 15;
  876. case THREAD_PRIORITY_ERROR_RETURN:
  877. nice_value = -1;
  878. error = 1;
  879. break;
  880. default:
  881. nice_value += tprio;
  882. break;
  883. }
  884. }
  885. /* Map to "nice values" similar to what one would see on
  886. Posix platforms. */
  887. if (!error)
  888. nice_value = - (nice_value - NZERO);
  889. }
  890. else
  891. error = 1;
  892. }
  893. else
  894. error = 1;
  895. if (error)
  896. {
  897. DWORD err = GetLastError ();
  898. switch (err)
  899. {
  900. case ERROR_INVALID_PARAMETER:
  901. case ERROR_INVALID_THREAD_ID:
  902. errno = ESRCH;
  903. break;
  904. default:
  905. errno = EPERM;
  906. break;
  907. }
  908. }
  909. return nice_value;
  910. }
  911. int
  912. setpriority (int which, int who, int nice_val)
  913. {
  914. HANDLE hp;
  915. DWORD err;
  916. int child_proc = 0, retval = -1;
  917. if (which != PRIO_PROCESS)
  918. {
  919. errno = ENOSYS;
  920. return -1;
  921. }
  922. if (who == 0)
  923. hp = GetCurrentProcess ();
  924. else
  925. {
  926. scm_i_scm_pthread_mutex_lock (&scm_i_misc_mutex);
  927. hp = proc_handle (who);
  928. scm_i_pthread_mutex_unlock (&scm_i_misc_mutex);
  929. /* If not found among our subprocesses, look elsewhere in the
  930. system. */
  931. if (hp == INVALID_HANDLE_VALUE)
  932. hp = OpenProcess (PROCESS_SET_INFORMATION, FALSE, who);
  933. else
  934. child_proc = 1;
  935. }
  936. if (hp)
  937. {
  938. DWORD pri_class;
  939. /* Map "nice values" back to process priority classes. */
  940. nice_val = -nice_val + NZERO;
  941. if (nice_val < 6)
  942. pri_class = IDLE_PRIORITY_CLASS;
  943. else if (nice_val < 8)
  944. pri_class = BELOW_NORMAL_PRIORITY_CLASS;
  945. else if (nice_val < 10)
  946. pri_class = NORMAL_PRIORITY_CLASS;
  947. else if (nice_val < 13)
  948. pri_class = ABOVE_NORMAL_PRIORITY_CLASS;
  949. else if (nice_val < 16)
  950. pri_class = HIGH_PRIORITY_CLASS;
  951. else
  952. pri_class = REALTIME_PRIORITY_CLASS;
  953. if (SetPriorityClass (hp, pri_class))
  954. retval = 0;
  955. }
  956. err = GetLastError ();
  957. switch (err)
  958. {
  959. case ERROR_INVALID_PARAMETER:
  960. errno = ESRCH;
  961. break;
  962. default:
  963. errno = EPERM;
  964. break;
  965. }
  966. /* The pseudo-handle returned by GetCurrentProcess doesn't
  967. need to be closed. */
  968. if (hp && who > 0 && !child_proc)
  969. CloseHandle (hp);
  970. return retval;
  971. }
  972. /* Emulation of sched_getaffinity and sched_setaffinity. */
  973. int
  974. sched_getaffinity (int pid, size_t mask_size, cpu_set_t *mask)
  975. {
  976. HANDLE hp;
  977. DWORD err;
  978. int child_proc = 0;
  979. if (mask == NULL)
  980. {
  981. errno = EFAULT;
  982. return -1;
  983. }
  984. if (pid == 0)
  985. hp = GetCurrentProcess ();
  986. else
  987. {
  988. scm_i_scm_pthread_mutex_lock (&scm_i_misc_mutex);
  989. hp = proc_handle (pid);
  990. scm_i_pthread_mutex_unlock (&scm_i_misc_mutex);
  991. /* If not found among our subprocesses, look elsewhere in the
  992. system. */
  993. if (hp == INVALID_HANDLE_VALUE)
  994. hp = OpenProcess (PROCESS_QUERY_INFORMATION, FALSE, pid);
  995. else
  996. child_proc = 1;
  997. }
  998. if (hp)
  999. {
  1000. DWORD_PTR ignored;
  1001. BOOL result = GetProcessAffinityMask (hp, (DWORD_PTR *)mask, &ignored);
  1002. /* The pseudo-handle returned by GetCurrentProcess doesn't
  1003. need to be closed. */
  1004. if (pid > 0 && !child_proc)
  1005. CloseHandle (hp);
  1006. if (result)
  1007. return 0;
  1008. }
  1009. err = GetLastError ();
  1010. switch (err)
  1011. {
  1012. case ERROR_INVALID_PARAMETER:
  1013. errno = ESRCH;
  1014. break;
  1015. case ERROR_ACCESS_DENIED:
  1016. default:
  1017. errno = EPERM;
  1018. break;
  1019. }
  1020. return -1;
  1021. }
  1022. int
  1023. sched_setaffinity (int pid, size_t mask_size, cpu_set_t *mask)
  1024. {
  1025. HANDLE hp;
  1026. DWORD err;
  1027. int child_proc = 0;
  1028. if (mask == NULL)
  1029. {
  1030. errno = EFAULT;
  1031. return -1;
  1032. }
  1033. if (pid == 0)
  1034. hp = GetCurrentProcess ();
  1035. else
  1036. {
  1037. scm_i_scm_pthread_mutex_lock (&scm_i_misc_mutex);
  1038. hp = proc_handle (pid);
  1039. scm_i_pthread_mutex_unlock (&scm_i_misc_mutex);
  1040. /* If not found among our subprocesses, look elsewhere in the
  1041. system. */
  1042. if (hp == INVALID_HANDLE_VALUE)
  1043. hp = OpenProcess (PROCESS_SET_INFORMATION, FALSE, pid);
  1044. else
  1045. child_proc = 1;
  1046. }
  1047. if (hp)
  1048. {
  1049. BOOL result = SetProcessAffinityMask (hp, *(DWORD_PTR *)mask);
  1050. /* The pseudo-handle returned by GetCurrentProcess doesn't
  1051. need to be closed. */
  1052. if (pid > 0 && !child_proc)
  1053. CloseHandle (hp);
  1054. if (result)
  1055. return 0;
  1056. }
  1057. err = GetLastError ();
  1058. switch (err)
  1059. {
  1060. case ERROR_INVALID_PARAMETER:
  1061. errno = ESRCH;
  1062. break;
  1063. case ERROR_ACCESS_DENIED:
  1064. default:
  1065. errno = EPERM;
  1066. break;
  1067. }
  1068. return -1;
  1069. }
  1070. /* This only implements the absolute minimum features for
  1071. foreign-library.scm. */
  1072. void *
  1073. dlopen_w32 (const char *name, int flags)
  1074. {
  1075. void *ret = NULL;
  1076. if (name == NULL || *name == '\0')
  1077. return (void *) GetModuleHandle (NULL);
  1078. ret = (void *) LoadLibrary (name);
  1079. GetModuleHandleEx (0, name, (HMODULE *) & ret);
  1080. return ret;
  1081. }
  1082. void *
  1083. dlsym_w32 (void *handle, const char *name)
  1084. {
  1085. return (void *) GetProcAddress ((HMODULE) handle, name);
  1086. }
  1087. int
  1088. dlclose_w32 (void *handle)
  1089. {
  1090. FreeLibrary ((HMODULE) handle);
  1091. return 0;
  1092. }
  1093. #define DLERROR_LEN 80
  1094. static char dlerror_str[DLERROR_LEN + 1];
  1095. char *
  1096. dlerror_w32 ()
  1097. {
  1098. char *msg_buf;
  1099. DWORD dw = GetLastError ();
  1100. FormatMessage (FORMAT_MESSAGE_ALLOCATE_BUFFER |
  1101. FORMAT_MESSAGE_FROM_SYSTEM |
  1102. FORMAT_MESSAGE_IGNORE_INSERTS,
  1103. NULL,
  1104. dw,
  1105. MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT),
  1106. (LPTSTR) & msg_buf, 0, NULL);
  1107. if (dw == 0)
  1108. snprintf (dlerror_str, DLERROR_LEN, "No error");
  1109. else
  1110. snprintf (dlerror_str, DLERROR_LEN, "error %ld: %s", (long) dw, msg_buf);
  1111. return dlerror_str;
  1112. }
  1113. /* Use upcase drive letter in NAME. */
  1114. static char *
  1115. canonicalize_device_name (char *name)
  1116. {
  1117. if (name == NULL)
  1118. return name;
  1119. if (HAS_DEVICE (name))
  1120. name[0] = toupper (name[0]);
  1121. return name;
  1122. }
  1123. /* Replace any use of '\\' by '/' in NAME. */
  1124. static char *
  1125. slashify_file_name (char *name)
  1126. {
  1127. if (name == NULL)
  1128. return name;
  1129. for (char *p = name; *p; p++)
  1130. if (ISSLASH (*p))
  1131. *p = '/';
  1132. return name;
  1133. }
  1134. #undef canonicalize_file_name
  1135. /* Also canonicalize use of drive letter and '/' for NAME. */
  1136. char *
  1137. canonicalize_file_name_mingw (const char *name)
  1138. {
  1139. char *canon = canonicalize_file_name (name);
  1140. canonicalize_device_name (canon);
  1141. slashify_file_name (canon);
  1142. return canon;
  1143. }