process_stubs.c 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619
  1. /*
  2. * Copyright (C)2005-2015 Haxe Foundation
  3. *
  4. * Permission is hereby granted, free of charge, to any person obtaining a
  5. * copy of this software and associated documentation files (the "Software"),
  6. * to deal in the Software without restriction, including without limitation
  7. * the rights to use, copy, modify, merge, publish, distribute, sublicense,
  8. * and/or sell copies of the Software, and to permit persons to whom the
  9. * Software is 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
  19. * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
  20. * DEALINGS IN THE SOFTWARE.
  21. */
  22. // ported from NekoVM
  23. #include <caml/alloc.h>
  24. #include <caml/memory.h>
  25. #include <caml/callback.h>
  26. #include <caml/mlvalues.h>
  27. #include <caml/fail.h>
  28. #ifdef _WIN32
  29. # include <windows.h>
  30. #else
  31. # include <sys/types.h>
  32. # include <signal.h>
  33. # include <unistd.h>
  34. # include <errno.h>
  35. # include <string.h>
  36. # ifndef __APPLE__
  37. # if defined(__FreeBSD__) || defined(__DragonFly__)
  38. # include <sys/wait.h>
  39. # else
  40. # include <wait.h>
  41. # endif
  42. # endif
  43. #endif
  44. #ifdef _WIN32
  45. # define POSIX_LABEL(name)
  46. # define HANDLE_EINTR(label)
  47. # define HANDLE_FINTR(f,label)
  48. #else
  49. # include <errno.h>
  50. # define POSIX_LABEL(name) name:
  51. # define HANDLE_EINTR(label) if( errno == EINTR ) goto label
  52. # define HANDLE_FINTR(f,label) if( ferror(f) && errno == EINTR ) goto label
  53. #endif
  54. // --- neko-to-caml api --
  55. #define val_check(v,t)
  56. #define val_check_kind(v,k)
  57. #define val_data(v) v
  58. #define val_array_size(v) Wosize_val(v)
  59. #define val_array_ptr(v) (&Field(v,0))
  60. #define val_string(v) String_val(v)
  61. #define val_strlen(v) caml_string_length(v)
  62. #define alloc_abstract(_,data) ((value)data)
  63. #define alloc_int(i) Val_int(i)
  64. #define val_gc(v,callb)
  65. #define val_null Val_int(0)
  66. #define val_some(v) Field(v,0)
  67. #define val_int(v) Int_val(v)
  68. #define DEFINE_KIND(_)
  69. #define neko_error() failwith(__FUNCTION__)
  70. static value alloc_private( int size ) {
  71. return alloc((size + sizeof(value) - 1) / sizeof(value), Abstract_tag);
  72. }
  73. // --- buffer api
  74. #define EXTERN
  75. typedef struct _stringitem {
  76. char *str;
  77. int size;
  78. int len;
  79. struct _stringitem *next;
  80. } * stringitem;
  81. struct _buffer {
  82. int totlen;
  83. int blen;
  84. stringitem data;
  85. };
  86. typedef struct _buffer *buffer;
  87. static void buffer_append_new( buffer b, const char *s, int len ) {
  88. int size;
  89. stringitem it;
  90. while( b->totlen >= (b->blen << 2) )
  91. b->blen <<= 1;
  92. size = (len < b->blen)?b->blen:len;
  93. it = (stringitem)malloc(sizeof(struct _stringitem));
  94. it->str = (char*)malloc(size);
  95. memcpy(it->str,s,len);
  96. it->size = size;
  97. it->len = len;
  98. it->next = b->data;
  99. b->data = it;
  100. }
  101. EXTERN void buffer_append_sub( buffer b, const char *s, int len ) {
  102. stringitem it;
  103. if( s == NULL || len <= 0 )
  104. return;
  105. b->totlen += len;
  106. it = b->data;
  107. if( it ) {
  108. int free = it->size - it->len;
  109. if( free >= len ) {
  110. memcpy(it->str + it->len,s,len);
  111. it->len += len;
  112. return;
  113. } else {
  114. memcpy(it->str + it->len,s,free);
  115. it->len += free;
  116. s += free;
  117. len -= free;
  118. }
  119. }
  120. buffer_append_new(b,s,len);
  121. }
  122. EXTERN void buffer_append_str( buffer b, const char *s ) {
  123. if( s == NULL )
  124. return;
  125. buffer_append_sub(b,s,strlen(s));
  126. }
  127. EXTERN buffer alloc_buffer( const char *init ) {
  128. buffer b = (buffer)malloc(sizeof(struct _buffer));
  129. b->totlen = 0;
  130. b->blen = 16;
  131. b->data = NULL;
  132. if( init )
  133. buffer_append_str(b,init);
  134. return b;
  135. }
  136. EXTERN void buffer_append_char( buffer b, char c ) {
  137. stringitem it;
  138. b->totlen++;
  139. it = b->data;
  140. if( it && it->len != it->size ) {
  141. it->str[it->len++] = c;
  142. return;
  143. }
  144. buffer_append_new(b,&c,1);
  145. }
  146. EXTERN char *buffer_to_string( buffer b ) {
  147. char *v = (char*)malloc(b->totlen + 1);
  148. stringitem it = b->data;
  149. char *s = v + b->totlen;
  150. *s = 0;
  151. while( it != NULL ) {
  152. stringitem tmp;
  153. s -= it->len;
  154. memcpy(s,it->str,it->len);
  155. tmp = it->next;
  156. free(it->str);
  157. free(it);
  158. it = tmp;
  159. }
  160. free(b);
  161. return v;
  162. }
  163. EXTERN int buffer_length( buffer b ) {
  164. return b->totlen;
  165. }
  166. // ---------------
  167. #include <stdio.h>
  168. #include <stdlib.h>
  169. typedef struct {
  170. #ifdef _WIN32
  171. HANDLE oread;
  172. HANDLE eread;
  173. HANDLE iwrite;
  174. PROCESS_INFORMATION pinf;
  175. #else
  176. int oread;
  177. int eread;
  178. int iwrite;
  179. int pid;
  180. #endif
  181. } vprocess;
  182. DEFINE_KIND(k_process);
  183. #define val_process(v) ((vprocess*)val_data(v))
  184. /**
  185. <doc>
  186. <h1>Process</h1>
  187. <p>
  188. An API for starting and communication with sub processes.
  189. </p>
  190. </doc>
  191. **/
  192. #ifndef _WIN32
  193. static int do_close( int fd ) {
  194. POSIX_LABEL(close_again);
  195. if( close(fd) != 0 ) {
  196. HANDLE_EINTR(close_again);
  197. return 1;
  198. }
  199. return 0;
  200. }
  201. #endif
  202. static void free_process( value vp ) {
  203. vprocess *p = val_process(vp);
  204. # ifdef _WIN32
  205. CloseHandle(p->eread);
  206. CloseHandle(p->oread);
  207. CloseHandle(p->iwrite);
  208. CloseHandle(p->pinf.hProcess);
  209. CloseHandle(p->pinf.hThread);
  210. # else
  211. do_close(p->eread);
  212. do_close(p->oread);
  213. do_close(p->iwrite);
  214. # endif
  215. }
  216. /**
  217. process_run : cmd:string -> args:string array option -> 'process
  218. <doc>
  219. Start a process using a command and the specified arguments.
  220. When args is not null, cmd and args will be auto-quoted/escaped.
  221. If no auto-quoting/escaping is desired, you should append necessary
  222. arguments to cmd as if it is inputted to the shell directly, and pass
  223. null as args.
  224. </doc>
  225. **/
  226. CAMLprim value process_run( value cmd, value vargs ) {
  227. CAMLparam2(cmd,vargs);
  228. int i, isRaw;
  229. vprocess *p;
  230. val_check(cmd,string);
  231. isRaw = vargs == val_null;
  232. if (!isRaw) {
  233. val_check(vargs,array);
  234. vargs = val_some(vargs);
  235. }
  236. # ifdef _WIN32
  237. {
  238. SECURITY_ATTRIBUTES sattr;
  239. STARTUPINFO sinf;
  240. HANDLE proc = GetCurrentProcess();
  241. HANDLE oread,eread,iwrite;
  242. // creates commandline
  243. buffer b = alloc_buffer(NULL);
  244. char *sargs;
  245. if (isRaw) {
  246. char* cmdexe;
  247. buffer_append_char(b,'"');
  248. cmdexe = getenv("COMSPEC");
  249. if (!cmdexe) cmdexe = "cmd.exe";
  250. buffer_append_str(b,cmdexe);
  251. buffer_append_char(b,'"');
  252. buffer_append_str(b,"/C \"");
  253. buffer_append_str(b,val_string(cmd));
  254. buffer_append_char(b,'"');
  255. } else {
  256. buffer_append_char(b,'"');
  257. buffer_append_str(b,val_string(cmd));
  258. buffer_append_char(b,'"');
  259. for(i=0;i<val_array_size(vargs);i++) {
  260. value v = val_array_ptr(vargs)[i];
  261. int j,len;
  262. unsigned int bs_count = 0;
  263. unsigned int k;
  264. val_check(v,string);
  265. len = val_strlen(v);
  266. buffer_append_str(b," \"");
  267. for(j=0;j<len;j++) {
  268. char c = val_string(v)[j];
  269. switch( c ) {
  270. case '"':
  271. // Double backslashes.
  272. for (k=0;k<bs_count*2;k++) {
  273. buffer_append_char(b,'\\');
  274. }
  275. bs_count = 0;
  276. buffer_append_str(b, "\\\"");
  277. break;
  278. case '\\':
  279. // Don't know if we need to double yet.
  280. bs_count++;
  281. break;
  282. default:
  283. // Normal char
  284. for (k=0;k<bs_count;k++) {
  285. buffer_append_char(b,'\\');
  286. }
  287. bs_count = 0;
  288. buffer_append_char(b,c);
  289. break;
  290. }
  291. }
  292. // Add remaining backslashes, if any.
  293. for (k=0;k<bs_count*2;k++) {
  294. buffer_append_char(b,'\\');
  295. }
  296. buffer_append_char(b,'"');
  297. }
  298. }
  299. sargs = buffer_to_string(b);
  300. p = (vprocess*)alloc_private(sizeof(vprocess));
  301. // startup process
  302. sattr.nLength = sizeof(sattr);
  303. sattr.bInheritHandle = TRUE;
  304. sattr.lpSecurityDescriptor = NULL;
  305. memset(&sinf,0,sizeof(sinf));
  306. sinf.cb = sizeof(sinf);
  307. sinf.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW;
  308. sinf.wShowWindow = SW_HIDE;
  309. CreatePipe(&oread,&sinf.hStdOutput,&sattr,0);
  310. CreatePipe(&eread,&sinf.hStdError,&sattr,0);
  311. CreatePipe(&sinf.hStdInput,&iwrite,&sattr,0);
  312. DuplicateHandle(proc,oread,proc,&p->oread,0,FALSE,DUPLICATE_SAME_ACCESS);
  313. DuplicateHandle(proc,eread,proc,&p->eread,0,FALSE,DUPLICATE_SAME_ACCESS);
  314. DuplicateHandle(proc,iwrite,proc,&p->iwrite,0,FALSE,DUPLICATE_SAME_ACCESS);
  315. CloseHandle(oread);
  316. CloseHandle(eread);
  317. CloseHandle(iwrite);
  318. if( !CreateProcess(NULL,val_string(sargs),NULL,NULL,TRUE,0,NULL,NULL,&sinf,&p->pinf) ) {
  319. CloseHandle(p->eread);
  320. CloseHandle(p->oread);
  321. CloseHandle(p->iwrite);
  322. free(sargs);
  323. neko_error();
  324. }
  325. free(sargs);
  326. // close unused pipes
  327. CloseHandle(sinf.hStdOutput);
  328. CloseHandle(sinf.hStdError);
  329. CloseHandle(sinf.hStdInput);
  330. }
  331. # else
  332. char **argv;
  333. if (isRaw) {
  334. argv = (char**)alloc_private(sizeof(char*)*4);
  335. argv[0] = "/bin/sh";
  336. argv[1] = "-c";
  337. argv[2] = val_string(cmd);
  338. argv[3] = NULL;
  339. } else {
  340. argv = (char**)alloc_private(sizeof(char*)*(val_array_size(vargs)+2));
  341. argv[0] = val_string(cmd);
  342. for(i=0;i<val_array_size(vargs);i++) {
  343. value v = val_array_ptr(vargs)[i];
  344. val_check(v,string);
  345. argv[i+1] = val_string(v);
  346. }
  347. argv[i+1] = NULL;
  348. }
  349. int input[2], output[2], error[2];
  350. if( pipe(input) || pipe(output) || pipe(error) )
  351. neko_error();
  352. p = (vprocess*)alloc_private(sizeof(vprocess));
  353. p->pid = fork();
  354. if( p->pid == -1 ) {
  355. do_close(input[0]);
  356. do_close(input[1]);
  357. do_close(output[0]);
  358. do_close(output[1]);
  359. do_close(error[0]);
  360. do_close(error[1]);
  361. neko_error();
  362. }
  363. // child
  364. if( p->pid == 0 ) {
  365. close(input[1]);
  366. close(output[0]);
  367. close(error[0]);
  368. dup2(input[0],0);
  369. dup2(output[1],1);
  370. dup2(error[1],2);
  371. execvp(argv[0],argv);
  372. fprintf(stderr,"Command not found : %s\n",val_string(cmd));
  373. exit(1);
  374. }
  375. // parent
  376. do_close(input[0]);
  377. do_close(output[1]);
  378. do_close(error[1]);
  379. p->iwrite = input[1];
  380. p->oread = output[0];
  381. p->eread = error[0];
  382. # endif
  383. {
  384. CAMLlocal1(vp);
  385. vp = alloc_abstract(k_process,p);
  386. val_gc(vp,free_process);
  387. CAMLreturn(vp);
  388. }
  389. }
  390. #define CHECK_ARGS() \
  391. vprocess *p; \
  392. val_check_kind(vp,k_process); \
  393. val_check(str,string); \
  394. val_check(pos,int); \
  395. val_check(len,int); \
  396. if( val_int(pos) < 0 || val_int(len) < 0 || val_int(pos) + val_int(len) > val_strlen(str) ) \
  397. neko_error(); \
  398. p = val_process(vp); \
  399. /**
  400. process_stdout_read : 'process -> buf:string -> pos:int -> len:int -> int
  401. <doc>
  402. Read up to [len] bytes in [buf] starting at [pos] from the process stdout.
  403. Returns the number of bytes read this way. Raise an exception if this
  404. process stdout is closed and no more data is available for reading.
  405. </doc>
  406. **/
  407. CAMLprim value process_stdout_read( value vp, value str, value pos, value len ) {
  408. CHECK_ARGS();
  409. # ifdef _WIN32
  410. {
  411. DWORD nbytes;
  412. if( !ReadFile(p->oread,val_string(str)+val_int(pos),val_int(len),&nbytes,NULL) )
  413. neko_error();
  414. return alloc_int(nbytes);
  415. }
  416. # else
  417. int nbytes;
  418. POSIX_LABEL(stdout_read_again);
  419. nbytes = read(p->oread,val_string(str)+val_int(pos),val_int(len));
  420. if( nbytes < 0 ) {
  421. HANDLE_EINTR(stdout_read_again);
  422. neko_error();
  423. }
  424. if( nbytes == 0 )
  425. neko_error();
  426. return alloc_int(nbytes);
  427. # endif
  428. }
  429. /**
  430. process_stderr_read : 'process -> buf:string -> pos:int -> len:int -> int
  431. <doc>
  432. Read up to [len] bytes in [buf] starting at [pos] from the process stderr.
  433. Returns the number of bytes read this way. Raise an exception if this
  434. process stderr is closed and no more data is available for reading.
  435. </doc>
  436. **/
  437. CAMLprim value process_stderr_read( value vp, value str, value pos, value len ) {
  438. CHECK_ARGS();
  439. # ifdef _WIN32
  440. {
  441. DWORD nbytes;
  442. if( !ReadFile(p->eread,val_string(str)+val_int(pos),val_int(len),&nbytes,NULL) )
  443. neko_error();
  444. return alloc_int(nbytes);
  445. }
  446. # else
  447. int nbytes;
  448. POSIX_LABEL(stderr_read_again);
  449. nbytes = read(p->eread,val_string(str)+val_int(pos),val_int(len));
  450. if( nbytes < 0 ) {
  451. HANDLE_EINTR(stderr_read_again);
  452. neko_error();
  453. }
  454. if( nbytes == 0 )
  455. neko_error();
  456. return alloc_int(nbytes);
  457. # endif
  458. }
  459. /**
  460. process_stdin_write : 'process -> buf:string -> pos:int -> len:int -> int
  461. <doc>
  462. Write up to [len] bytes from [buf] starting at [pos] to the process stdin.
  463. Returns the number of bytes writen this way. Raise an exception if this
  464. process stdin is closed.
  465. </doc>
  466. **/
  467. CAMLprim value process_stdin_write( value vp, value str, value pos, value len ) {
  468. CHECK_ARGS();
  469. # ifdef _WIN32
  470. {
  471. DWORD nbytes;
  472. if( !WriteFile(p->iwrite,val_string(str)+val_int(pos),val_int(len),&nbytes,NULL) )
  473. neko_error();
  474. return alloc_int(nbytes);
  475. }
  476. # else
  477. int nbytes;
  478. POSIX_LABEL(stdin_write_again);
  479. nbytes = write(p->iwrite,val_string(str)+val_int(pos),val_int(len));
  480. if( nbytes == -1 ) {
  481. HANDLE_EINTR(stdin_write_again);
  482. neko_error();
  483. }
  484. return alloc_int(nbytes);
  485. # endif
  486. }
  487. /**
  488. process_stdin_close : 'process -> void
  489. <doc>
  490. Close the process standard input.
  491. </doc>
  492. **/
  493. CAMLprim value process_stdin_close( value vp ) {
  494. vprocess *p;
  495. val_check_kind(vp,k_process);
  496. p = val_process(vp);
  497. # ifdef _WIN32
  498. if( !CloseHandle(p->iwrite) )
  499. neko_error();
  500. # else
  501. if( do_close(p->iwrite) )
  502. neko_error();
  503. p->iwrite = -1;
  504. # endif
  505. return val_null;
  506. }
  507. /**
  508. process_exit : 'process -> int
  509. <doc>
  510. Wait until the process terminate, then returns its exit code.
  511. </doc>
  512. **/
  513. CAMLprim value process_exit( value vp ) {
  514. vprocess *p;
  515. val_check_kind(vp,k_process);
  516. p = val_process(vp);
  517. # ifdef _WIN32
  518. {
  519. DWORD rval;
  520. WaitForSingleObject(p->pinf.hProcess,INFINITE);
  521. if( !GetExitCodeProcess(p->pinf.hProcess,&rval) )
  522. neko_error();
  523. return alloc_int(rval);
  524. }
  525. # else
  526. int rval;
  527. while( waitpid(p->pid,&rval,0) != p->pid ) {
  528. if( errno == EINTR )
  529. continue;
  530. neko_error();
  531. }
  532. if( !WIFEXITED(rval) )
  533. neko_error();
  534. return alloc_int(WEXITSTATUS(rval));
  535. # endif
  536. }
  537. /**
  538. process_pid : 'process -> int
  539. <doc>
  540. Returns the process id.
  541. </doc>
  542. **/
  543. CAMLprim value process_pid( value vp ) {
  544. vprocess *p;
  545. val_check_kind(vp,k_process);
  546. p = val_process(vp);
  547. # ifdef _WIN32
  548. return alloc_int(p->pinf.dwProcessId);
  549. # else
  550. return alloc_int(p->pid);
  551. # endif
  552. }
  553. /**
  554. process_close : 'process -> void
  555. <doc>
  556. Close the process I/O.
  557. </doc>
  558. **/
  559. CAMLprim value process_close( value vp ) {
  560. val_check_kind(vp,k_process);
  561. free_process(vp);
  562. //val_kind(vp) = NULL;
  563. //val_gc(vp,NULL);
  564. return val_null;
  565. }
  566. /**
  567. process_kill : 'process -> void
  568. <doc>
  569. Terminates a running process.
  570. </doc>
  571. **/
  572. CAMLprim value process_kill( value vp ) {
  573. val_check_kind(vp,k_process);
  574. # ifdef _WIN32
  575. TerminateProcess(val_process(vp)->pinf.hProcess,-1);
  576. # else
  577. kill(val_process(vp)->pid,9);
  578. # endif
  579. return val_null;
  580. }
  581. /* ************************************************************************ */