sq_subprocess.cpp 40 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365
  1. /* Copyright (c) 2010 Joshua Phillips
  2. * Ported on 2016 to SquiLu by Domingo Alvarez Duarte
  3. *
  4. * Permission is hereby granted, free of charge, to any person obtaining a copy
  5. * of this software and associated documentation files (the "Software"), to deal
  6. * in the Software without restriction, including without limitation the rights
  7. * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  8. * copies of the Software, and to permit persons to whom the Software is
  9. * furnished to do so, subject to the following conditions:
  10. *
  11. * The above copyright notice and this permission notice shall be included in
  12. * all copies or substantial portions of the Software.
  13. *
  14. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  17. * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  18. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  19. * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  20. * THE SOFTWARE.
  21. */
  22. #ifdef OS_POSIX
  23. #define _POSIX_SOURCE
  24. #endif
  25. #if !defined(OS_WINDOWS) && !defined(OS_POSIX)
  26. #error None of these are defined: OS_WINDOWS, OS_POSIX
  27. #else
  28. #include "squirrel.h"
  29. #include "sqstdblobimpl.h"
  30. #include <string.h>
  31. #include <stdio.h>
  32. #include <stdlib.h>
  33. #include <errno.h>
  34. #include <fcntl.h>
  35. #include <assert.h>
  36. SQ_OPT_STRING_STRLEN();
  37. #if defined(OS_POSIX)
  38. #include <unistd.h>
  39. #include <sys/wait.h>
  40. #include <sys/stat.h>
  41. typedef int filedes_t;
  42. /* return 1 if the named directory exists and is a directory */
  43. static int direxists(const char *fname)
  44. {
  45. struct stat statbuf;
  46. if (stat(fname, &statbuf)){
  47. return 0;
  48. }
  49. return !!S_ISDIR(statbuf.st_mode);
  50. }
  51. #elif defined(OS_WINDOWS)
  52. #include "windows.h"
  53. /* Some SDKs don't define this */
  54. #ifndef INVALID_FILE_ATTRIBUTES
  55. #define INVALID_FILE_ATTRIBUTES ((DWORD) -1)
  56. #endif
  57. typedef HANDLE filedes_t;
  58. /* return 1 if the named directory exists and is a directory */
  59. static int direxists(const char *fname)
  60. {
  61. DWORD result;
  62. result = GetFileAttributes(fname);
  63. if (result == INVALID_FILE_ATTRIBUTES) return 0;
  64. return !!(result & FILE_ATTRIBUTE_DIRECTORY);
  65. }
  66. #endif /* defined(OS_WINDOWS) */
  67. /* Some systems don't define these, but we use them as indices for our arrays.
  68. I probably oughtn't, in case a system doesn't use 0, 1 and 2 for these. */
  69. #ifndef STDIN_FILENO
  70. #define STDIN_FILENO 0
  71. #define STDOUT_FILENO 1
  72. #define STDERR_FILENO 2
  73. #endif
  74. /* This is the proc object, which is stored as Lua userdata */
  75. struct proc {
  76. #if defined(OS_POSIX)
  77. pid_t pid;
  78. #elif defined(OS_WINDOWS)
  79. DWORD pid;
  80. HANDLE hProcess;
  81. #endif
  82. int exitcode;
  83. unsigned char done; /* set to 1 when child has finished and closed */
  84. };
  85. /* Lua registry key for proc metatable */
  86. #define SP_PROC_META "subprocess_proc*"
  87. /* Environment keys */
  88. /* This is an integer index into the environment of C functions in this module.
  89. At this index is stored a table of [pid]=proc items. The items in this table
  90. will all have their `done` fields set to false. This table is at present only
  91. used for the `subprocess.wait` function.
  92. On POSIX, it is used to get the proc object corresponding to a pid. On
  93. Windows, it is used to assemble a HANDLE array for WaitForMultipleObjects. */
  94. #define SP_LIST "subprocess_pid_list"
  95. /* Check to see if object at the given index is a proc object.
  96. Return pointer to proc object, or NULL if it isn't. */
  97. static struct proc *toproc(HSQUIRRELVM v, int index)
  98. {
  99. int eq;
  100. if (lua_type(L, index) != LUA_TUSERDATA) return NULL;
  101. lua_getmetatable(L, index);
  102. luaL_getmetatable(L, SP_PROC_META);
  103. eq = lua_equal(L, -2, -1);
  104. lua_pop(L, 2);
  105. if (!eq) return NULL;
  106. return lua_touserdata(L, index);
  107. }
  108. /* Same but raise an error instead of returning NULL */
  109. #define checkproc(L, index) ((struct proc *) luaL_checkudata((L), (index), SP_PROC_META))
  110. /* Create and return a new proc object */
  111. static struct proc *newproc(HSQUIRRELVM v)
  112. {
  113. struct proc *proc = sq_newuserdata(v, sizeof *proc);
  114. proc->done = 1;
  115. proc->pid = 0;
  116. luaL_getmetatable(L, SP_PROC_META);
  117. lua_setmetatable(L, -2);
  118. lua_newtable(L);
  119. lua_setfenv(L, -2);
  120. return proc;
  121. }
  122. /* Mark a process (at index) as done */
  123. static void doneproc(HSQUIRRELVM v, int index)
  124. {
  125. struct proc *proc = toproc(L, index);
  126. if (!proc){
  127. fputs("subprocess.c: doneproc: not a proc\n", stderr);
  128. } else {
  129. proc->done = 1;
  130. /* remove proc from SP_LIST */
  131. sq_reservestack(v, 4);
  132. sq_pushvalue(v, index); /* stack: proc */
  133. luaL_getmetatable(L, SP_LIST);
  134. /* stack: proc list */
  135. if (lua_isnil(L, -1)){
  136. fputs("subprocess.c: XXX: SP_LIST IS NIL\n", stderr);
  137. } else {
  138. lua_pushinteger(L, proc->pid); /* stack: proc list pid */
  139. lua_pushvalue(L, -1); /* stack: proc list pid pid */
  140. lua_gettable(L, -3); /* stack: proc list pid proc2 */
  141. if (!lua_equal(L, -4, -1)){
  142. /* lookup by pid didn't work */
  143. fputs("subprocess.c: doneproc: XXX: pid lookup in SP_LIST failed\n", stderr);
  144. lua_pop(L, 2); /* stack: proc list */
  145. } else {
  146. lua_pop(L, 1); /* stack: proc list pid */
  147. lua_pushnil(L); /* stack: proc list pid nil */
  148. lua_settable(L, -3); /* stack: proc list */
  149. }
  150. /* stack: proc list */
  151. }
  152. sq_pop(v, 2);
  153. }
  154. }
  155. /* Remove old SP_LIST entries by polling them.
  156. Calling this every now and again can avoid leaking proc objects
  157. that are not waited for. */
  158. static SQRESULT sq_subprocess_prune(HSQUIRRELVM v)
  159. {
  160. int top = lua_gettop(L);
  161. sq_reservestack(v, 5);
  162. luaL_getmetatable(L, SP_LIST);
  163. if (lua_isnil(L, -1)){
  164. lua_pop(L, 1);
  165. return 0;
  166. }
  167. lua_pushnil(L);
  168. while (lua_next(L, -2)){
  169. lua_getfield(L, -1, "poll");
  170. lua_pushvalue(L, -2);
  171. lua_call(L, 1, 0);
  172. lua_pop(L, 1);
  173. }
  174. lua_settop(L, top);
  175. return 0;
  176. }
  177. /* Special constants for popen arguments. */
  178. static char PIPE, STDOUT;
  179. /* Names of standard file handles. */
  180. static const char *fd_names[3] = {"stdin", "stdout", "stderr"};
  181. /* Information about what to do for a standard file handle.
  182. This is constructed from popen arguments. */
  183. struct fdinfo {
  184. enum {
  185. FDMODE_INHERIT = 0, /* fd is inherited from parent */
  186. FDMODE_FILENAME, /* open named file */
  187. FDMODE_FILEDES, /* use a file descriptor */
  188. FDMODE_FILEOBJ, /* use FILE* */
  189. FDMODE_PIPE, /* create and use pipe */
  190. FDMODE_STDOUT /* redirect to stdout (only for stderr) */
  191. } mode;
  192. union {
  193. const char *filename;
  194. filedes_t filedes;
  195. FILE *fileobj;
  196. } info;
  197. };
  198. /* Close multiple file descriptors */
  199. static void closefds(filedes_t *fds, int n)
  200. {
  201. int i;
  202. for (i=0; i<n; ++i){
  203. #if defined(OS_POSIX)
  204. if (fds[i] != -1)
  205. close(fds[i]);
  206. #elif defined(OS_WINDOWS)
  207. if (fds[i] != INVALID_HANDLE_VALUE)
  208. CloseHandle(fds[i]);
  209. #endif
  210. }
  211. }
  212. /* Close multiple C files */
  213. static void closefiles(FILE **files, int n)
  214. {
  215. int i;
  216. for (i=0; i<n; ++i)
  217. if (files[i] != NULL)
  218. fclose(files[i]);
  219. }
  220. /* Free multiple strings */
  221. static void freestrings(char **strs, int n)
  222. {
  223. int i;
  224. for (i=0; i<n; ++i)
  225. if (strs[i] != NULL)
  226. sq_free(strs[i], -1);
  227. }
  228. #ifdef OS_WINDOWS
  229. /* Copy a Windows error into a buffer */
  230. static void copy_w32error(char errmsg_out[], size_t errmsg_len, DWORD error)
  231. {
  232. if (FormatMessage(
  233. FORMAT_MESSAGE_FROM_SYSTEM, NULL, error, 0,
  234. (void *) errmsg_out, errmsg_len, NULL) == 0)
  235. {
  236. strncpy(errmsg_out, "failed to get error message", errmsg_len + 1);
  237. }
  238. }
  239. /* Push a Windows error onto a Lua stack */
  240. static void push_w32error(HSQUIRRELVM v, DWORD error)
  241. {
  242. LPTSTR buf;
  243. if (FormatMessage(
  244. FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
  245. NULL, error, 0, (void *) &buf, 1, NULL) == 0)
  246. {
  247. lua_pushliteral(L, "failed to get error message");
  248. } else {
  249. lua_pushstring(L, buf);
  250. LocalFree(buf);
  251. }
  252. }
  253. /* n is 0, 1 or 2
  254. return handle for standard input/output/error */
  255. static HANDLE getstdhandle(int n)
  256. {
  257. DWORD n2;
  258. switch (n){
  259. case 0: n2 = STD_INPUT_HANDLE; break;
  260. case 1: n2 = STD_OUTPUT_HANDLE; break;
  261. case 2: n2 = STD_ERROR_HANDLE; break;
  262. default: return INVALID_HANDLE_VALUE;
  263. }
  264. return GetStdHandle(n2);
  265. }
  266. struct str {
  267. char *data;
  268. size_t len;
  269. size_t size; /* size allocated */
  270. };
  271. static void str_init(struct str *s)
  272. {
  273. s->data = NULL;
  274. s->len = 0;
  275. s->size = 0;
  276. }
  277. /* Append n chars from s2 */
  278. static int str_appendlstr(struct str *s, char *s2, size_t n)
  279. {
  280. void *newp;
  281. if (s->size < s->len + n){
  282. if (s->size < 16) s->size = 16;
  283. while (s->size < s->len + n)
  284. s->size = (s->size * 3) / 2;
  285. newp = realloc(s->data, s->size + 1);
  286. if (newp == NULL){
  287. free(s->data);
  288. return 0;
  289. }
  290. s->data = newp;
  291. }
  292. memcpy(s->data + s->len, s2, n);
  293. s->len += n;
  294. s->data[s->len] = '\0';
  295. return 1;
  296. }
  297. static int str_appendc(struct str *s, char ch)
  298. {
  299. return str_appendlstr(s, &ch, 1);
  300. }
  301. /* Compiles command line for CreateProcess. Returns malloc'd string. */
  302. static char *compile_cmdline(const char *const *args)
  303. {
  304. /* " --> \"
  305. \" --> \\\"
  306. \<NUL> --> \\ */
  307. struct str str;
  308. const char *arg;
  309. str_init(&str);
  310. while (*args != NULL){
  311. arg = *args++;
  312. if (!str_appendc(&str, '"')) return NULL;
  313. while (arg[0]){
  314. if (arg[0] == '"'){
  315. if (!str_appendlstr(&str, "\\\"", 2)) return NULL;
  316. } else if (arg[0] == '\\'){
  317. if (arg[1] == '"' || arg[1] == '\0'){
  318. if (!str_appendlstr(&str, "\\\\", 2)) return NULL;
  319. } else {
  320. if (!str_appendc(&str, '\\')) return NULL;
  321. }
  322. } else {
  323. if (!str_appendc(&str, arg[0])) return NULL;
  324. }
  325. arg++;
  326. }
  327. if (!str_appendlstr(&str, "\" ", 2)) return NULL;
  328. }
  329. str.data[str.len - 1] = '\0';
  330. return str.data;
  331. }
  332. #endif
  333. /* Function for opening subprocesses. Returns 0 on success and -1 on failure.
  334. On failure, errmsg_out shall contain a '\0'-terminated error message. */
  335. static int dopopen(const char *const *args, /* program arguments with NULL sentinel */
  336. const char *executable, /* actual executable */
  337. struct fdinfo fdinfo[3], /* info for stdin/stdout/stderr */
  338. int close_fds, /* 1 to close all fds */
  339. int binary, /* 1 to use binary files */
  340. const char *cwd, /* working directory for program */
  341. struct proc *proc, /* populated on success! */
  342. FILE *pipe_ends_out[3], /* pipe ends are put here */
  343. char errmsg_out[], /* written to on failure */
  344. size_t errmsg_len /* length of errmsg_out (EXCLUDING sentinel) */
  345. )
  346. #if defined(OS_POSIX)
  347. {
  348. int fds[3];
  349. int i;
  350. struct fdinfo *fdi;
  351. int piperw[2];
  352. int errpipe[2]; /* pipe for returning error status */
  353. int flags;
  354. int en; /* saved errno */
  355. int count;
  356. pid_t pid;
  357. errmsg_out[errmsg_len] = '\0';
  358. for (i=0; i<3; ++i)
  359. pipe_ends_out[i] = NULL;
  360. /* Manage stdin/stdout/stderr */
  361. for (i=0; i<3; ++i){
  362. fdi = &fdinfo[i];
  363. switch (fdi->mode){
  364. case FDMODE_INHERIT:
  365. inherit:
  366. fds[i] = dup(i);
  367. if (fds[i] == -1){
  368. fd_failure:
  369. strncpy(errmsg_out, strerror(errno), errmsg_len + 1);
  370. closefds(fds, i);
  371. closefiles(pipe_ends_out, i);
  372. return -1;
  373. }
  374. break;
  375. case FDMODE_FILENAME:
  376. if (i == STDIN_FILENO){
  377. if ((fds[i] = open(fdi->info.filename, O_RDONLY)) == -1) goto fd_failure;
  378. } else {
  379. if ((fds[i] = creat(fdi->info.filename, 0666)) == -1) goto fd_failure;
  380. }
  381. break;
  382. case FDMODE_FILEDES:
  383. if ((fds[i] = dup(fdi->info.filedes)) == -1) goto fd_failure;
  384. break;
  385. case FDMODE_FILEOBJ:
  386. if ((fds[i] = dup(fileno(fdi->info.fileobj))) == -1) goto fd_failure;
  387. break;
  388. case FDMODE_PIPE:
  389. if (pipe(piperw) == -1) goto fd_failure;
  390. if (i == STDIN_FILENO){
  391. fds[i] = piperw[0]; /* give read end to process */
  392. if ((pipe_ends_out[i] = fdopen(piperw[1], "w")) == NULL) goto fd_failure;
  393. } else {
  394. fds[i] = piperw[1]; /* give write end to process */
  395. if ((pipe_ends_out[i] = fdopen(piperw[0], "r")) == NULL) goto fd_failure;
  396. }
  397. break;
  398. case FDMODE_STDOUT:
  399. if (i == STDERR_FILENO){
  400. if ((fds[STDERR_FILENO] = dup(fds[STDOUT_FILENO])) == -1) goto fd_failure;
  401. } else goto inherit;
  402. break;
  403. }
  404. }
  405. /* Find executable name */
  406. if (!executable){
  407. /* use first arg */
  408. executable = args[0];
  409. }
  410. assert(executable != NULL);
  411. /* Create a pipe for returning error status */
  412. if (pipe(errpipe) == -1){
  413. strncpy(errmsg_out, strerror(errno), errmsg_len + 1);
  414. closefds(fds, 3);
  415. closefiles(pipe_ends_out, 3);
  416. return -1;
  417. }
  418. /* Make write end close on exec */
  419. flags = fcntl(errpipe[1], F_GETFD);
  420. if (flags == -1){
  421. pipe_failure:
  422. strncpy(errmsg_out, strerror(errno), errmsg_len + 1);
  423. closefds(errpipe, 2);
  424. closefds(fds, 3);
  425. closefiles(pipe_ends_out, 3);
  426. return -1;
  427. }
  428. if (fcntl(errpipe[1], F_SETFD, flags | FD_CLOEXEC) == -1) goto pipe_failure;
  429. /* Do the fork/exec (TODO: use vfork somehow?) */
  430. pid = fork();
  431. if (pid == -1) goto pipe_failure;
  432. else if (pid == 0){
  433. /* child */
  434. close(errpipe[0]);
  435. /* dup file descriptors */
  436. for (i=0; i<3; ++i){
  437. if (dup2(fds[i], i) == -1) goto child_failure;
  438. }
  439. /* close other fds */
  440. if (close_fds){
  441. for (i=3; i<sysconf(_SC_OPEN_MAX); ++i){
  442. if (i != errpipe[1])
  443. close(i);
  444. }
  445. }
  446. /* change directory */
  447. if (cwd && chdir(cwd)) goto child_failure;
  448. /* exec! Farewell, subprocess.c! */
  449. execvp(executable, (char *const*) args); /* XXX: const cast */
  450. /* Oh dear, we're still here. */
  451. child_failure:
  452. en = errno;
  453. write(errpipe[1], &en, sizeof en);
  454. _exit(1);
  455. }
  456. /* parent */
  457. /* close unneeded fds */
  458. closefds(fds, 3);
  459. close(errpipe[1]);
  460. /* read errno from child */
  461. while ((count = read(errpipe[0], &en, sizeof en)) == -1)
  462. if (errno != EAGAIN && errno != EINTR) break;
  463. if (count > 0){
  464. /* exec failed */
  465. close(errpipe[0]);
  466. strncpy(errmsg_out, strerror(en), errmsg_len + 1);
  467. return -1;
  468. }
  469. close(errpipe[0]);
  470. /* Child is now running */
  471. proc->done = 0;
  472. proc->pid = pid;
  473. return 0;
  474. }
  475. #elif defined(OS_WINDOWS)
  476. {
  477. HANDLE hfiles[3], piper, pipew, hfile;
  478. int i, fd;
  479. struct fdinfo *fdi;
  480. SECURITY_ATTRIBUTES secattr;
  481. STARTUPINFO si;
  482. PROCESS_INFORMATION pi;
  483. char *cmdline;
  484. errmsg_out[errmsg_len] = '\0';
  485. /* Create a SECURITY_ATTRIBUTES for inheritable handles */
  486. secattr.nLength = sizeof secattr;
  487. secattr.lpSecurityDescriptor = NULL;
  488. secattr.bInheritHandle = TRUE;
  489. for (i=0; i<3; ++i)
  490. pipe_ends_out[i] = NULL;
  491. /* Manage stdin/stdout/stderr */
  492. for (i=0; i<3; ++i){
  493. fdi = &fdinfo[i];
  494. switch (fdi->mode){
  495. case FDMODE_INHERIT:
  496. inherit:
  497. /* XXX: duplicated file handles share the
  498. same object (and thus file cursor, etc.).
  499. CreateFile might be a better idea. */
  500. hfile = getstdhandle(i);
  501. if (hfile == INVALID_HANDLE_VALUE){
  502. fd_failure:
  503. copy_w32error(errmsg_out, errmsg_len, GetLastError());
  504. closefds(hfiles, i);
  505. closefiles(pipe_ends_out, i);
  506. return -1;
  507. }
  508. dup_hfile:
  509. if (DuplicateHandle(GetCurrentProcess(), hfile,
  510. GetCurrentProcess(), &hfiles[i], 0, TRUE,
  511. DUPLICATE_SAME_ACCESS) == 0)
  512. {
  513. goto fd_failure;
  514. }
  515. break;
  516. case FDMODE_FILENAME:
  517. if (i == STDIN_FILENO){
  518. hfiles[i] = CreateFile(
  519. fdi->info.filename,
  520. GENERIC_READ,
  521. FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
  522. &secattr,
  523. OPEN_EXISTING,
  524. FILE_ATTRIBUTE_NORMAL,
  525. NULL);
  526. } else {
  527. hfiles[i] = CreateFile(
  528. fdi->info.filename,
  529. GENERIC_WRITE,
  530. FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
  531. &secattr,
  532. CREATE_ALWAYS,
  533. FILE_ATTRIBUTE_NORMAL,
  534. NULL);
  535. }
  536. if (hfiles[i] == INVALID_HANDLE_VALUE){
  537. goto fd_failure;
  538. }
  539. break;
  540. case FDMODE_FILEDES:
  541. if (DuplicateHandle(GetCurrentProcess(), fdi->info.filedes,
  542. GetCurrentProcess(), &hfiles[i], 0, TRUE,
  543. DUPLICATE_SAME_ACCESS) == 0)
  544. {
  545. goto fd_failure;
  546. }
  547. break;
  548. case FDMODE_FILEOBJ:
  549. fd = _fileno(fdi->info.fileobj);
  550. if (fd == -1){
  551. get_osf_failure:
  552. strncpy(errmsg_out, strerror(errno), errmsg_len + 1);
  553. failure:
  554. closefds(hfiles, i);
  555. closefiles(pipe_ends_out, i);
  556. return -1;
  557. }
  558. hfile = (HANDLE) _get_osfhandle(fd);
  559. if (hfile == INVALID_HANDLE_VALUE) goto get_osf_failure;
  560. goto dup_hfile;
  561. case FDMODE_PIPE:
  562. if (CreatePipe(&piper, &pipew, &secattr, 0) == 0)
  563. goto fd_failure;
  564. if (i == STDIN_FILENO){
  565. hfiles[i] = piper;
  566. fd = _open_osfhandle((long) pipew, binary ? 0 : _O_TEXT);
  567. if (fd == -1){
  568. strncpy(errmsg_out, "_open_osfhandle failed", errmsg_len + 1);
  569. goto failure;
  570. }
  571. pipe_ends_out[i] = _fdopen(fd, "w");
  572. if (pipe_ends_out[i] == 0){
  573. strncpy(errmsg_out, "_fdopen failed", errmsg_len + 1);
  574. goto failure;
  575. }
  576. } else {
  577. hfiles[i] = pipew;
  578. fd = _open_osfhandle((long) piper, _O_RDONLY | (binary ? 0 : _O_TEXT));
  579. if (fd == -1){
  580. strncpy(errmsg_out, "_open_osfhandle failed", errmsg_len + 1);
  581. goto failure;
  582. }
  583. pipe_ends_out[i] = _fdopen(fd, "r");
  584. if (pipe_ends_out[i] == 0){
  585. strncpy(errmsg_out, "_fdopen failed", errmsg_len + 1);
  586. goto failure;
  587. }
  588. }
  589. break;
  590. case FDMODE_STDOUT:
  591. if (i == STDERR_FILENO){
  592. hfile = hfiles[STDOUT_FILENO];
  593. goto dup_hfile;
  594. } else goto inherit;
  595. }
  596. }
  597. /* Find executable name */
  598. if (executable == NULL){
  599. /* use first arg */
  600. /*executable = args[0];*/
  601. }
  602. /* Compile command line into string. Yuck. */
  603. cmdline = compile_cmdline(args);
  604. if (!cmdline){
  605. strncpy(errmsg_out, "memory full", errmsg_len + 1);
  606. closefds(hfiles, 3);
  607. closefiles(pipe_ends_out, 3);
  608. return -1;
  609. }
  610. si.cb = sizeof si;
  611. si.lpReserved = NULL;
  612. si.lpDesktop = NULL;
  613. si.lpTitle = NULL;
  614. si.dwFlags = STARTF_USESTDHANDLES;
  615. si.cbReserved2 = 0;
  616. si.lpReserved2 = NULL;
  617. si.hStdInput = hfiles[0];
  618. si.hStdOutput = hfiles[1];
  619. si.hStdError = hfiles[2];
  620. if (CreateProcess(
  621. executable, /* lpApplicationName */
  622. cmdline, /* lpCommandLine */
  623. NULL, /* lpProcessAttributes */
  624. NULL, /* lpThreadAttributes */
  625. TRUE, /* bInheritHandles */
  626. 0, /* dwCreationFlags */
  627. NULL, /* lpEnvironment */
  628. cwd, /* lpCurrentDirectory */
  629. &si, /* lpStartupInfo */
  630. &pi) /* lpProcessInformation */
  631. == 0){
  632. copy_w32error(errmsg_out, errmsg_len, GetLastError());
  633. free(cmdline);
  634. closefds(hfiles, 3);
  635. closefiles(pipe_ends_out, 3);
  636. return -1;
  637. }
  638. CloseHandle(pi.hThread); /* Don't want this handle */
  639. free(cmdline);
  640. closefds(hfiles, 3); /* XXX: is this correct? */
  641. proc->done = 0;
  642. proc->pid = pi.dwProcessId;
  643. proc->hProcess = pi.hProcess;
  644. return 0;
  645. }
  646. #endif
  647. /* popen {arg0, arg1, arg2, ..., [executable=...]} */
  648. static SQRESULT sq_subprocess_popen(HSQUIRRELVM v)
  649. {
  650. struct proc *proc = NULL;
  651. /* List of arguments (malloc'd NULL-terminated array of C strings.
  652. The C strings are owned by Lua) */
  653. int nargs = 0;
  654. const char **args = NULL;
  655. /* Command to run (owned by Lua) */
  656. const char *executable = NULL;
  657. /* Directory to run it in (owned by Lua) */
  658. const char *cwd = NULL;
  659. /* File options */
  660. struct fdinfo fdinfo[3];
  661. /* Close fds? */
  662. int close_fds = 0;
  663. /* Use binary mode for files? */
  664. int binary = 0;
  665. FILE *pipe_ends[3] = {NULL, NULL, NULL};
  666. int i, result;
  667. FILE *f;
  668. const char *s;
  669. char errmsg_buf[256];
  670. prune(v);
  671. luaL_checktype(L, 1, LUA_TTABLE);
  672. lua_settop(L, 1);
  673. proc = newproc(v);
  674. /* Stack: kwargs proc <strings etc....>
  675. Lua strings are left on the stack while they are needed,
  676. and Lua can garbage-collect them later. */
  677. /* get arguments */
  678. nargs = lua_objlen(L, 1);
  679. if (nargs == 0) return luaL_error(L, "no arguments specified");
  680. args = lua_newuserdata(L, (nargs + 1) * sizeof *args); /*alloc((nargs + 1) * sizeof *args);*/
  681. if (!args) return luaL_error(L, "memory full");
  682. for (i=0; i<=nargs; ++i) args[i] = NULL;
  683. luaL_checkstack(L, nargs, "cannot grow stack");
  684. for (i=1; i<=nargs; ++i){
  685. lua_rawgeti(L, 1, i);
  686. s = lua_tostring(L, -1);
  687. if (!s){
  688. /*freestrings(args, nargs);
  689. free(args);*/
  690. return luaL_error(L, "popen argument %d not a string", (int) i);
  691. }
  692. args[i-1] = s; /*strdup(s);*/
  693. /*if (args[i-1] == NULL){
  694. strings_failure:
  695. freestrings(args, nargs);
  696. free(args);
  697. return luaL_error(L, "memory full");
  698. } */
  699. /*lua_pop(L, 1);*/
  700. }
  701. luaL_checkstack(L, 12, "cannot grow stack");
  702. /* get executable string */
  703. lua_getfield(L, 1, "executable");
  704. s = lua_tostring(L, -1);
  705. if (s){
  706. executable = s; /*strdup(s);*/
  707. /*if (executable == NULL) goto strings_failure;*/
  708. } else lua_pop(L, 1);
  709. /*lua_pop(L, 1); */ /* to match lua_getfield */
  710. /* get directory name */
  711. lua_getfield(L, 1, "cwd");
  712. cwd = lua_tostring(L, -1);
  713. if (cwd == NULL) lua_pop(L, 1);
  714. else {
  715. /*if (lua_isstring(L, -1)){
  716. cwd = lua_tostring(L, -1);*/ /*strdup(lua_tostring(L, -1));
  717. if (!cwd){
  718. free(executable);
  719. freestrings(args, nargs);
  720. free(args);
  721. return luaL_error(L, "memory full");
  722. } */
  723. /* make sure the cwd exists */
  724. if (!direxists(cwd)){
  725. /*free(executable);
  726. freestrings(args, nargs);*/
  727. /*free(args);*/
  728. return luaL_error(L, "directory `%s' does not exist", cwd);
  729. }
  730. }
  731. /*lua_pop(L, 1);*/
  732. /* close_fds */
  733. lua_getfield(L, 1, "close_fds");
  734. close_fds = lua_toboolean(L, -1);
  735. lua_pop(L, 1);
  736. /* binary */
  737. lua_getfield(L, 1, "binary");
  738. binary = lua_toboolean(L, -1);
  739. lua_pop(L, 1);
  740. /* handle stdin/stdout/stderr */
  741. for (i=0; i<3; ++i){
  742. lua_getfield(L, 1, fd_names[i]);
  743. if (lua_isnil(L, -1)){
  744. fdinfo[i].mode = FDMODE_INHERIT;
  745. lua_pop(L, 1);
  746. } else if (lua_touserdata(L, -1) == &PIPE){
  747. fdinfo[i].mode = FDMODE_PIPE;
  748. lua_pop(L, 1);
  749. } else if (lua_touserdata(L, -1) == &STDOUT){
  750. if (i == STDERR_FILENO /*&& fdinfo[STDOUT_FILENO].mode == FDMODE_PIPE*/){
  751. fdinfo[i].mode = FDMODE_STDOUT;
  752. } else {
  753. lua_pushliteral(L, "STDOUT must be used only for stderr"/* when stdout is set to PIPE"*/);
  754. files_failure:
  755. /*for (j=0; j<i; ++j){
  756. if (fdinfo[j].mode == FDMODE_FILENAME)
  757. free(fdinfo[j].info.filename);
  758. }
  759. free(executable);
  760. freestrings(args, nargs);
  761. free(args);*/
  762. return lua_error(L);
  763. }
  764. lua_pop(L, 1);
  765. } else if (lua_isstring(L, -1)){
  766. /* open a file */
  767. fdinfo[i].mode = FDMODE_FILENAME;
  768. /*if ((fdinfo[i].info.filename = strdup(lua_tostring(L, -1))) == NULL){
  769. lua_pushliteral(L, "out of memory");
  770. goto files_failure;
  771. } */
  772. fdinfo[i].info.filename = lua_tostring(L, -1);
  773. /* do not pop */
  774. } else if (lua_isnumber(L, -1)){
  775. /* use this fd */
  776. fdinfo[i].mode = FDMODE_FILEDES;
  777. fdinfo[i].info.filedes = (filedes_t) lua_tointeger(L, -1);
  778. lua_pop(L, 1);
  779. } else {
  780. f = liolib_copy_tofile(L, -1);
  781. if (f){
  782. fdinfo[i].mode = FDMODE_FILEOBJ;
  783. fdinfo[i].info.fileobj = f;
  784. } else {
  785. /* huh? */
  786. lua_pushfstring(L, "unexpected value for %s", fd_names[i]);
  787. goto files_failure;
  788. }
  789. lua_pop(L, 1);
  790. }
  791. }
  792. result = dopopen(args, executable, fdinfo, close_fds, binary, cwd, proc, pipe_ends, errmsg_buf, 255);
  793. /*for (i=0; i<3; ++i)
  794. if (fdinfo[i].mode == FDMODE_FILENAME)
  795. free(fdinfo[i].info.filename);
  796. free(executable);
  797. freestrings(args, nargs);
  798. free(args);*/
  799. if (result == -1){
  800. /* failed */
  801. return luaL_error(L, "popen failed: %s", errmsg_buf);
  802. }
  803. /* Put pipe objects in proc userdata's environment */
  804. lua_getfenv(L, 2);
  805. for (i=0; i<3; ++i){
  806. if (pipe_ends[i]){
  807. *liolib_copy_newfile(L) = pipe_ends[i];
  808. lua_setfield(L, -2, fd_names[i]);
  809. }
  810. }
  811. lua_pop(L, 1);
  812. /* Put proc object in SP_LIST table */
  813. luaL_getmetatable(L, SP_LIST);
  814. if (lua_isnil(L, -1)){
  815. fputs("subprocess.c: XXX: SP_LIST IS NIL\n", stderr);
  816. } else {
  817. lua_pushinteger(L, proc->pid); /* stack: list pid */
  818. lua_pushvalue(L, 2); /* stack: list pid proc */
  819. lua_settable(L, -3); /* stack: list */
  820. }
  821. lua_pop(L, 1);
  822. /* Return the proc */
  823. lua_settop(L, 2);
  824. return 1;
  825. }
  826. /* __gc */
  827. static int proc_gc(HSQUIRRELVM v)
  828. {
  829. struct proc *proc = checkproc(v, 1);
  830. if (!proc->done){
  831. #if defined(OS_POSIX)
  832. /* Try to wait for process to avoid leaving zombie.
  833. If the process hasn't finished yet, we'll end up leaving a zombie. */
  834. int stat;
  835. waitpid(proc->pid, &stat, WNOHANG);
  836. #elif defined(OS_WINDOWS)
  837. CloseHandle(proc->hProcess);
  838. #endif
  839. doneproc(v, 1);
  840. }
  841. return 0;
  842. }
  843. /* __index */
  844. static int proc_index(HSQUIRRELVM v)
  845. {
  846. struct proc *proc;
  847. const char *s;
  848. lua_settop(L, 2);
  849. proc = checkproc(v, 1);
  850. /* first check environment table */
  851. lua_getfenv(L, 1);
  852. lua_pushvalue(L, 2);
  853. lua_gettable(L, 3);
  854. if (!lua_isnil(L, 4)) return 1;
  855. lua_pop(L, 2);
  856. /* next check metatable */
  857. lua_getmetatable(L, 1);
  858. lua_pushvalue(L, 2);
  859. lua_gettable(L, 3);
  860. if (!lua_isnil(L, 4)) return 1;
  861. lua_pop(L, 2);
  862. /* lastly, fixed fields */
  863. s = lua_tostring(L, 2);
  864. if (!strcmp(s, "pid")){
  865. lua_pushinteger(L, proc->pid);
  866. return 1;
  867. } else if (!strcmp(s, "exitcode") && proc->done){
  868. lua_pushinteger(L, proc->exitcode);
  869. return 1;
  870. } else {
  871. return 0;
  872. }
  873. }
  874. /* Push string representation of process on stack */
  875. static int proc_tostring(HSQUIRRELVM v)
  876. {
  877. struct proc *proc = checkproc(L, 1);
  878. if (proc->done)
  879. lua_pushliteral(L, "(finished process)");
  880. else
  881. lua_pushfstring(L, "process (%d)", (int) proc->pid);
  882. return 1;
  883. }
  884. #if defined(OS_POSIX)
  885. /* Get exitcode from wait's 'stat' value */
  886. static int getexitcode(int stat)
  887. {
  888. if (WIFEXITED(stat))
  889. return WEXITSTATUS(stat);
  890. else if (WIFSIGNALED(stat))
  891. return -WTERMSIG(stat);
  892. else if (WIFSTOPPED(stat))
  893. return -WSTOPSIG(stat);
  894. else {
  895. fputs("child disappeared into black hole\n", stderr);
  896. return -1;
  897. }
  898. }
  899. #endif
  900. /* Wait for, or poll, a process */
  901. static int do_waitpid(HSQUIRRELVM v, struct proc *proc, int wait)
  902. #if defined(OS_POSIX)
  903. {
  904. int stat, options;
  905. if (proc->done){
  906. lua_pushinteger(L, proc->exitcode);
  907. return 1;
  908. }
  909. if (wait) options = 0;
  910. else options = WNOHANG;
  911. switch (waitpid(proc->pid, &stat, options)){
  912. case -1:
  913. return luaL_error(L, strerror(errno));
  914. case 0:
  915. /* child still running */
  916. lua_pushnil(L);
  917. return 1;
  918. default:
  919. proc->exitcode = getexitcode(stat);
  920. doneproc(L, 1);
  921. lua_pushinteger(L, proc->exitcode);
  922. return 1;
  923. }
  924. }
  925. #elif defined(OS_WINDOWS)
  926. {
  927. DWORD dwMilliseconds, retval, exitcode;
  928. if (proc->done){
  929. lua_pushinteger(L, proc->exitcode);
  930. return 1;
  931. }
  932. if (wait) dwMilliseconds = INFINITE;
  933. else dwMilliseconds = 0;
  934. retval = WaitForSingleObject(proc->hProcess, dwMilliseconds);
  935. switch (retval){
  936. case WAIT_FAILED:
  937. failure:
  938. push_w32error(L, GetLastError());
  939. return lua_error(L);
  940. case WAIT_OBJECT_0:
  941. /* child finished */
  942. if (GetExitCodeProcess(proc->hProcess, &exitcode) == 0){
  943. goto failure;
  944. }
  945. CloseHandle(proc->hProcess);
  946. proc->exitcode = exitcode;
  947. doneproc(L, 1);
  948. lua_pushinteger(L, proc->exitcode);
  949. return 1;
  950. case WAIT_TIMEOUT:
  951. default:
  952. /* child still running */
  953. lua_pushnil(L);
  954. return 1;
  955. }
  956. }
  957. #endif
  958. static int SQRESULT sq_process_poll(HSQUIRRELVM v)
  959. {
  960. return do_waitpid(L, checkproc(L, 1), 0);
  961. }
  962. static int SQRESULT sq_process_wait(HSQUIRRELVM v)
  963. {
  964. return do_waitpid(L, checkproc(L, 1), 1);
  965. }
  966. #if defined(OS_POSIX)
  967. static SQRESULT sq_process_send_signal(HSQUIRRELVM v)
  968. {
  969. struct proc *proc = checkproc(L, 1);
  970. int sig = luaL_checkinteger(L, 2);
  971. if (!proc->done){
  972. if (kill(proc->pid, sig)){
  973. return luaL_error(L, "kill: %s", strerror(errno));
  974. }
  975. proc->exitcode = -sig;
  976. doneproc(L, 1);
  977. }
  978. return 0;
  979. }
  980. static SQRESULT sq_process_terminate(HSQUIRRELVM v)
  981. {
  982. lua_settop(L, 1);
  983. lua_pushinteger(L, SIGTERM);
  984. return proc_send_signal(L);
  985. }
  986. static SQRESULT sq_process_kill(HSQUIRRELVM v)
  987. {
  988. lua_settop(L, 1);
  989. lua_pushinteger(L, SIGKILL);
  990. return proc_send_signal(L);
  991. }
  992. #elif defined(OS_WINDOWS)
  993. static SQRESULT sq_process_terminate(HSQUIRRELVM v)
  994. {
  995. struct proc *proc = checkproc(L, 1);
  996. if (!proc->done){
  997. if (TerminateProcess(proc->hProcess, -9) == 0){
  998. push_w32error(L, GetLastError());
  999. return lua_error(L);
  1000. }
  1001. CloseHandle(proc->hProcess);
  1002. proc->exitcode = -9;
  1003. doneproc(L, 1);
  1004. }
  1005. return 0;
  1006. }
  1007. #endif
  1008. static const luaL_Reg proc_meta[] = {
  1009. {"__tostring", proc_tostring},
  1010. {"__gc", proc_gc},
  1011. {"__index", proc_index},
  1012. {"poll", proc_poll},
  1013. {"wait", proc_wait},
  1014. #if defined(OS_POSIX)
  1015. {"send_signal", proc_send_signal},
  1016. {"terminate", proc_terminate},
  1017. {"kill", proc_kill},
  1018. #elif defined(OS_WINDOWS)
  1019. {"terminate", proc_terminate},
  1020. {"kill", proc_terminate},
  1021. #endif
  1022. {NULL, NULL}
  1023. };
  1024. #define _DECL_FUNC(name,nparams,tycheck) {_SC(#name), sq_process_##name,nparams,tycheck}
  1025. static SQRegFunction sq_process_methods[] =
  1026. {
  1027. _DECL_FUNC(constructor, -2, _SC("xsi")),
  1028. _DECL_FUNC(poll, 1, _SC("x")),
  1029. _DECL_FUNC(wait, 1, _SC("x")),
  1030. #if defined(OS_POSIX)
  1031. _DECL_FUNC(send_signal, 1, _SC("x")),
  1032. _DECL_FUNC(terminate, 1, _SC("x")),
  1033. _DECL_FUNC(kill, 1, _SC("x")),
  1034. #elif defined(OS_WINDOWS)
  1035. _DECL_FUNC(terminate, 1, _SC("x")),
  1036. _DECL_FUNC(kill, 1, _SC("x")),
  1037. #endif
  1038. {0,0}
  1039. };
  1040. #undef _DECL_FUNC
  1041. /* convenience functions */
  1042. static SQRESULT sq_subprocess_call(HSQUIRRELVM v)
  1043. {
  1044. int r = superpopen(L);
  1045. if (r != 1){
  1046. return r;
  1047. }
  1048. lua_replace(L, 1);
  1049. lua_settop(L, 1);
  1050. return proc_wait(L);
  1051. }
  1052. static SQRESULT sq_subprocess_call_capture(HSQUIRRELVM v)
  1053. {
  1054. int r;
  1055. lua_settop(L, 1);
  1056. luaL_checktype(L, 1, LUA_TTABLE);
  1057. lua_getfield(L, 1, "stdout");
  1058. lua_pushlightuserdata(L, &PIPE);
  1059. lua_setfield(L, 1, "stdout");
  1060. r = superpopen(L);
  1061. if (r != 1) return r;
  1062. /* stack: args oldstdout sp */
  1063. /* restore old stdout value in table */
  1064. lua_pushvalue(L, 2);
  1065. lua_setfield(L, 1, "stdout");
  1066. lua_replace(L, 1);
  1067. lua_settop(L, 1);
  1068. /* stack: sp */
  1069. lua_getfield(L, 1, "stdout");
  1070. lua_getfield(L, 2, "read");
  1071. lua_pushvalue(L, 2);
  1072. lua_pushliteral(L, "*a");
  1073. lua_call(L, 2, 2);
  1074. /* stack: sp stdout a b */
  1075. /* close stdout, rather than relying on GC */
  1076. lua_getfield(L, 2, "close");
  1077. lua_pushvalue(L, 2);
  1078. lua_call(L, 1, 0);
  1079. /* wait for child (to avoid leaving a zombie) */
  1080. lua_getfield(L, 1, "wait");
  1081. lua_pushvalue(L, 1);
  1082. lua_call(L, 1, 1);
  1083. /* return exitcode, content */
  1084. lua_pushvalue(L, 3);
  1085. return 2;
  1086. }
  1087. /* Miscellaneous */
  1088. static SQRESULT sq_subprocess_wait(HSQUIRRELVM v)
  1089. {
  1090. struct proc *proc;
  1091. #if defined(OS_POSIX)
  1092. int stat;
  1093. pid_t pid;
  1094. int exitcode;
  1095. #elif defined(OS_WINDOWS)
  1096. HANDLE *handles = NULL, hProcess;
  1097. int i, nprocs;
  1098. DWORD retval;
  1099. DWORD exitcode;
  1100. #endif
  1101. luaL_getmetatable(L, SP_LIST);
  1102. if (lua_isnil(L, -1))
  1103. return luaL_error(L, "SP_LIST is nil");
  1104. #if defined(OS_POSIX)
  1105. pid = wait(&stat);
  1106. if (pid == -1){
  1107. lua_pushnil(L);
  1108. lua_pushstring(L, strerror(errno));
  1109. return 2;
  1110. }
  1111. exitcode = getexitcode(stat);
  1112. /* find proc object corresponding to pid */
  1113. lua_pushinteger(L, pid);
  1114. lua_pushvalue(L, -1); /* stack: list pid pid */
  1115. lua_gettable(L, -3); /* stack: list pid proc */
  1116. if (lua_isnil(L, -1)){
  1117. fprintf(stderr, "subprocess.c: XXX: cannot find proc object for pid %d\n", (int) pid);
  1118. }
  1119. lua_replace(L, -3); /* stack: proc pid */
  1120. lua_pop(L, 1); /* stack: proc */
  1121. /* update proc object */
  1122. proc = toproc(L, -1);
  1123. if (!proc){
  1124. fputs("subprocess.c: XXX: proc list entry is wrong type\n", stderr);
  1125. } else {
  1126. proc->exitcode = exitcode;
  1127. doneproc(L, -1);
  1128. }
  1129. lua_pushinteger(L, exitcode);
  1130. lua_pushinteger(L, pid);
  1131. /* stack: proc exitcode pid */
  1132. return 3;
  1133. #elif defined(OS_WINDOWS)
  1134. /* count number of procs there are */
  1135. nprocs = sq_getsize(v, -1);
  1136. /* stack: list */
  1137. if (nprocs > 0){
  1138. handles = malloc(nprocs * sizeof *handles);
  1139. if (!handles)
  1140. return luaL_error(L, "memory full");
  1141. i = 0;
  1142. lua_pushnil(L);
  1143. while (lua_next(L, -2)){
  1144. proc = toproc(L, -1);
  1145. if (proc && !proc->done && i < nprocs){
  1146. handles[i++] = proc->hProcess;
  1147. } else if (proc && !proc->done){
  1148. fputs("subprocess.c: XXX: handles array allocated too small\n", stderr);
  1149. } else if (!proc){
  1150. fputs("foreign object in SP_LIST\n", stderr);
  1151. }
  1152. lua_pop(L, 1);
  1153. }
  1154. } else i = 0;
  1155. if (i > 0){
  1156. if (i > MAXIMUM_WAIT_OBJECTS){
  1157. free(handles);
  1158. return luaL_error(L, "too many wait objects: %d", i);
  1159. }
  1160. retval = WaitForMultipleObjects(i, handles, FALSE, INFINITE);
  1161. if (retval >= WAIT_OBJECT_0 && retval < (DWORD)(WAIT_OBJECT_0 + i)){
  1162. hProcess = handles[retval - WAIT_OBJECT_0];
  1163. free(handles);
  1164. /* find this process again in the table */
  1165. lua_pushnil(L);
  1166. while (lua_next(L, -2)){
  1167. proc = toproc(L, -1);
  1168. if (proc && !proc->done && proc->hProcess == hProcess){
  1169. /* it's this one */
  1170. if (GetExitCodeProcess(proc->hProcess, &exitcode) == 0){
  1171. {
  1172. char buf[256];
  1173. copy_w32error(buf, 255, GetLastError());
  1174. fprintf(stderr, "GetExitCodeProcess failed: %s\n", buf);
  1175. }
  1176. proc->exitcode = -1; /* :-\ */
  1177. } else {
  1178. proc->exitcode = exitcode;
  1179. }
  1180. CloseHandle(proc->hProcess);
  1181. doneproc(L, -1);
  1182. lua_pushinteger(L, exitcode);
  1183. lua_pushinteger(L, proc->pid); /* stack: list key proc exitcode pid */
  1184. return 3;
  1185. }
  1186. lua_pop(L, 1);
  1187. }
  1188. fputs("proc has mysteriously disappeared from table!\n", stderr);
  1189. return 0;
  1190. } else if (retval == WAIT_FAILED){
  1191. free(handles);
  1192. push_w32error(L, GetLastError());
  1193. return lua_error(L);
  1194. } else {
  1195. free(handles);
  1196. return luaL_error(L, "WaitForMultipleObjects failed unexpectedly");
  1197. }
  1198. } else {
  1199. free(handles);
  1200. lua_pushnil(L);
  1201. lua_pushliteral(L, "no processes to wait for");
  1202. return 2;
  1203. }
  1204. #endif
  1205. }
  1206. static const luaL_Reg subprocess[] = {
  1207. /* {"pipe", superpipe}, */
  1208. {"popen", superpopen},
  1209. {"call", call},
  1210. {"call_capture", call_capture},
  1211. {"wait", superwait},
  1212. {"prune", prune},
  1213. {NULL, NULL}
  1214. };
  1215. #define _DECL_FUNC(name,nparams,tycheck) {_SC(#name), sq_subprocess_##name,nparams,tycheck}
  1216. static SQRegFunction sq_subprocess_methods[] =
  1217. {
  1218. _DECL_FUNC(constructor, -2, _SC("xsi")),
  1219. _DECL_FUNC(popen, 1, _SC("x")),
  1220. _DECL_FUNC(call, 1, _SC("x")),
  1221. _DECL_FUNC(call_capture, 1, _SC("x")),
  1222. _DECL_FUNC(prune, 1, _SC("x")),
  1223. _DECL_FUNC(wait, 1, _SC("x")),
  1224. {0,0}
  1225. };
  1226. #undef _DECL_FUNC
  1227. SQRESULT sq_register_subprocess(HSQUIRRELVM v)
  1228. {
  1229. /* create environment table for C functions */
  1230. lua_newtable(L);
  1231. lua_pushvalue(L, -1);
  1232. lua_setfield(L, LUA_REGISTRYINDEX, SP_LIST);
  1233. lua_pop(L, 1);
  1234. #if LUA_VERSION_NUM >= 502
  1235. lua_createtable(L, 0, sizeof subprocess / sizeof *subprocess - 1);
  1236. luaL_setfuncs(L, subprocess, 0);
  1237. #else
  1238. luaL_register(L, "subprocess", subprocess);
  1239. #endif
  1240. /* export PIPE and STDOUT constants */
  1241. lua_pushlightuserdata(L, &PIPE);
  1242. lua_setfield(L, -2, "PIPE");
  1243. lua_pushlightuserdata(L, &STDOUT);
  1244. lua_setfield(L, -2, "STDOUT");
  1245. /* create metatable for proc objects */
  1246. luaL_newmetatable(L, SP_PROC_META);
  1247. #if LUA_VERSION_NUM >= 502
  1248. luaL_setfuncs(L, proc_meta, 0);
  1249. #else
  1250. luaL_register(L, NULL, proc_meta);
  1251. #endif
  1252. lua_pushboolean(L, 0);
  1253. lua_setfield(L, -2, "__metatable");
  1254. lua_pop(L, 1);
  1255. return 1;
  1256. }
  1257. #endif