process_stubs.c 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607
  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/custom.h>
  27. #include <caml/mlvalues.h>
  28. #include <caml/fail.h>
  29. #ifdef _WIN32
  30. # include <windows.h>
  31. #else
  32. # include <sys/types.h>
  33. # include <signal.h>
  34. # include <unistd.h>
  35. # include <errno.h>
  36. # include <string.h>
  37. # include <sys/wait.h>
  38. #endif
  39. #ifdef _WIN32
  40. # define POSIX_LABEL(name)
  41. # define HANDLE_EINTR(label)
  42. # define HANDLE_FINTR(f,label)
  43. #else
  44. # include <errno.h>
  45. # define POSIX_LABEL(name) name:
  46. # define HANDLE_EINTR(label) if( errno == EINTR ) goto label
  47. # define HANDLE_FINTR(f,label) if( ferror(f) && errno == EINTR ) goto label
  48. #endif
  49. // --- neko-to-caml api --
  50. #define val_data(v) v
  51. #define val_array_size(v) Wosize_val(v)
  52. #define val_array_ptr(v) (&Field(v,0))
  53. #define val_string(v) String_val(v)
  54. #define val_strlen(v) caml_string_length(v)
  55. #define alloc_int(i) Val_int(i)
  56. #define val_null Val_int(0)
  57. #define val_some(v) Field(v,0)
  58. #define val_int(v) Int_val(v)
  59. #define neko_error() caml_failwith(__FUNCTION__)
  60. static value alloc_private( int size ) {
  61. return caml_alloc((size + sizeof(value) - 1) / sizeof(value), Abstract_tag);
  62. }
  63. // --- buffer api
  64. #define EXTERN
  65. typedef struct _stringitem {
  66. char *str;
  67. int size;
  68. int len;
  69. struct _stringitem *next;
  70. } * stringitem;
  71. struct _buffer {
  72. int totlen;
  73. int blen;
  74. stringitem data;
  75. };
  76. typedef struct _buffer *buffer;
  77. static void buffer_append_new( buffer b, const char *s, int len ) {
  78. int size;
  79. stringitem it;
  80. while( b->totlen >= (b->blen << 2) )
  81. b->blen <<= 1;
  82. size = (len < b->blen)?b->blen:len;
  83. it = (stringitem)malloc(sizeof(struct _stringitem));
  84. it->str = (char*)malloc(size);
  85. memcpy(it->str,s,len);
  86. it->size = size;
  87. it->len = len;
  88. it->next = b->data;
  89. b->data = it;
  90. }
  91. EXTERN void buffer_append_sub( buffer b, const char *s, int len ) {
  92. stringitem it;
  93. if( s == NULL || len <= 0 )
  94. return;
  95. b->totlen += len;
  96. it = b->data;
  97. if( it ) {
  98. int free = it->size - it->len;
  99. if( free >= len ) {
  100. memcpy(it->str + it->len,s,len);
  101. it->len += len;
  102. return;
  103. } else {
  104. memcpy(it->str + it->len,s,free);
  105. it->len += free;
  106. s += free;
  107. len -= free;
  108. }
  109. }
  110. buffer_append_new(b,s,len);
  111. }
  112. EXTERN void buffer_append_str( buffer b, const char *s ) {
  113. if( s == NULL )
  114. return;
  115. buffer_append_sub(b,s,strlen(s));
  116. }
  117. EXTERN buffer alloc_buffer( const char *init ) {
  118. buffer b = (buffer)malloc(sizeof(struct _buffer));
  119. b->totlen = 0;
  120. b->blen = 16;
  121. b->data = NULL;
  122. if( init )
  123. buffer_append_str(b,init);
  124. return b;
  125. }
  126. EXTERN void buffer_append_char( buffer b, char c ) {
  127. stringitem it;
  128. b->totlen++;
  129. it = b->data;
  130. if( it && it->len != it->size ) {
  131. it->str[it->len++] = c;
  132. return;
  133. }
  134. buffer_append_new(b,&c,1);
  135. }
  136. EXTERN char *buffer_to_string( buffer b ) {
  137. char *v = (char*)malloc(b->totlen + 1);
  138. stringitem it = b->data;
  139. char *s = v + b->totlen;
  140. *s = 0;
  141. while( it != NULL ) {
  142. stringitem tmp;
  143. s -= it->len;
  144. memcpy(s,it->str,it->len);
  145. tmp = it->next;
  146. free(it->str);
  147. free(it);
  148. it = tmp;
  149. }
  150. free(b);
  151. return v;
  152. }
  153. EXTERN int buffer_length( buffer b ) {
  154. return b->totlen;
  155. }
  156. // ---------------
  157. #include <stdio.h>
  158. #include <stdlib.h>
  159. typedef struct {
  160. #ifdef _WIN32
  161. HANDLE oread;
  162. HANDLE eread;
  163. HANDLE iwrite;
  164. PROCESS_INFORMATION pinf;
  165. #else
  166. int oread;
  167. int eread;
  168. int iwrite;
  169. int pid;
  170. #endif
  171. } vprocess;
  172. #define val_process(v) (*((vprocess**) Data_custom_val(v)))
  173. /**
  174. <doc>
  175. <h1>Process</h1>
  176. <p>
  177. An API for starting and communication with sub processes.
  178. </p>
  179. </doc>
  180. **/
  181. #ifndef _WIN32
  182. static int do_close( int fd ) {
  183. POSIX_LABEL(close_again);
  184. if( close(fd) != 0 ) {
  185. HANDLE_EINTR(close_again);
  186. return 1;
  187. }
  188. return 0;
  189. }
  190. #endif
  191. static void free_process( value vp ) {
  192. vprocess *p = val_process(vp);
  193. if (p == NULL) {
  194. return;
  195. }
  196. # ifdef _WIN32
  197. CloseHandle(p->eread);
  198. CloseHandle(p->oread);
  199. CloseHandle(p->iwrite);
  200. CloseHandle(p->pinf.hProcess);
  201. CloseHandle(p->pinf.hThread);
  202. # else
  203. do_close(p->eread);
  204. do_close(p->oread);
  205. do_close(p->iwrite);
  206. # endif
  207. free(p);
  208. }
  209. static struct custom_operations vprocess_ops = {
  210. .identifier = "vprocess_ops",
  211. .finalize = custom_finalize_default,
  212. .compare = custom_compare_default,
  213. .hash = custom_hash_default,
  214. .serialize = custom_serialize_default,
  215. .deserialize = custom_deserialize_default,
  216. };
  217. /**
  218. process_run : cmd:string -> args:string array option -> 'process
  219. <doc>
  220. Start a process using a command and the specified arguments.
  221. When args is not null, cmd and args will be auto-quoted/escaped.
  222. If no auto-quoting/escaping is desired, you should append necessary
  223. arguments to cmd as if it is inputted to the shell directly, and pass
  224. null as args.
  225. </doc>
  226. **/
  227. CAMLprim value process_run( value cmd, value vargs ) {
  228. CAMLparam2(cmd, vargs);
  229. CAMLlocal1(vp);
  230. int i, isRaw;
  231. vprocess *p;
  232. vp = caml_alloc_custom(&vprocess_ops, sizeof(vprocess*), 0, 1);
  233. isRaw = vargs == val_null;
  234. if (!isRaw) {
  235. vargs = val_some(vargs);
  236. }
  237. # ifdef _WIN32
  238. {
  239. SECURITY_ATTRIBUTES sattr;
  240. STARTUPINFO sinf;
  241. HANDLE proc = GetCurrentProcess();
  242. HANDLE oread,eread,iwrite;
  243. // creates commandline
  244. buffer b = alloc_buffer(NULL);
  245. char *sargs;
  246. if (isRaw) {
  247. char* cmdexe;
  248. buffer_append_char(b,'"');
  249. cmdexe = getenv("COMSPEC");
  250. if (!cmdexe) cmdexe = "cmd.exe";
  251. buffer_append_str(b,cmdexe);
  252. buffer_append_char(b,'"');
  253. buffer_append_str(b,"/C \"");
  254. buffer_append_str(b,val_string(cmd));
  255. buffer_append_char(b,'"');
  256. } else {
  257. buffer_append_char(b,'"');
  258. buffer_append_str(b,val_string(cmd));
  259. buffer_append_char(b,'"');
  260. for(i=0;i<val_array_size(vargs);i++) {
  261. value v = val_array_ptr(vargs)[i];
  262. int j,len;
  263. unsigned int bs_count = 0;
  264. unsigned int k;
  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*)malloc(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. argv[i+1] = val_string(v);
  345. }
  346. argv[i+1] = NULL;
  347. }
  348. int input[2], output[2], error[2];
  349. if( pipe(input) || pipe(output) || pipe(error) )
  350. neko_error();
  351. p = (vprocess*)malloc(sizeof(vprocess));
  352. p->pid = fork();
  353. if( p->pid == -1 ) {
  354. do_close(input[0]);
  355. do_close(input[1]);
  356. do_close(output[0]);
  357. do_close(output[1]);
  358. do_close(error[0]);
  359. do_close(error[1]);
  360. neko_error();
  361. }
  362. // child
  363. if( p->pid == 0 ) {
  364. close(input[1]);
  365. close(output[0]);
  366. close(error[0]);
  367. dup2(input[0],0);
  368. dup2(output[1],1);
  369. dup2(error[1],2);
  370. execvp(argv[0],argv);
  371. fprintf(stderr,"Command not found : %s\n",val_string(cmd));
  372. exit(1);
  373. }
  374. // parent
  375. do_close(input[0]);
  376. do_close(output[1]);
  377. do_close(error[1]);
  378. p->iwrite = input[1];
  379. p->oread = output[0];
  380. p->eread = error[0];
  381. # endif
  382. val_process(vp) = p;
  383. CAMLreturn(vp);
  384. }
  385. #define CHECK_ARGS() \
  386. CAMLparam4(vp, str, pos, len); \
  387. vprocess *p; \
  388. if( val_int(pos) < 0 || val_int(len) < 0 || val_int(pos) + val_int(len) > val_strlen(str) ) \
  389. neko_error(); \
  390. p = val_process(vp); \
  391. /**
  392. process_stdout_read : 'process -> buf:string -> pos:int -> len:int -> int
  393. <doc>
  394. Read up to [len] bytes in [buf] starting at [pos] from the process stdout.
  395. Returns the number of bytes read this way. Raise an exception if this
  396. process stdout is closed and no more data is available for reading.
  397. </doc>
  398. **/
  399. CAMLprim value process_stdout_read( value vp, value str, value pos, value len ) {
  400. CHECK_ARGS();
  401. # ifdef _WIN32
  402. {
  403. DWORD nbytes;
  404. if( !ReadFile(p->oread,val_string(str)+val_int(pos),val_int(len),&nbytes,NULL) )
  405. neko_error();
  406. CAMLreturn(alloc_int(nbytes));
  407. }
  408. # else
  409. int nbytes;
  410. POSIX_LABEL(stdout_read_again);
  411. nbytes = read(p->oread,val_string(str)+val_int(pos),val_int(len));
  412. if( nbytes < 0 ) {
  413. HANDLE_EINTR(stdout_read_again);
  414. neko_error();
  415. }
  416. if( nbytes == 0 )
  417. neko_error();
  418. CAMLreturn(alloc_int(nbytes));
  419. # endif
  420. }
  421. /**
  422. process_stderr_read : 'process -> buf:string -> pos:int -> len:int -> int
  423. <doc>
  424. Read up to [len] bytes in [buf] starting at [pos] from the process stderr.
  425. Returns the number of bytes read this way. Raise an exception if this
  426. process stderr is closed and no more data is available for reading.
  427. </doc>
  428. **/
  429. CAMLprim value process_stderr_read( value vp, value str, value pos, value len ) {
  430. CHECK_ARGS();
  431. # ifdef _WIN32
  432. {
  433. DWORD nbytes;
  434. if( !ReadFile(p->eread,val_string(str)+val_int(pos),val_int(len),&nbytes,NULL) )
  435. neko_error();
  436. CAMLreturn(alloc_int(nbytes));
  437. }
  438. # else
  439. int nbytes;
  440. POSIX_LABEL(stderr_read_again);
  441. nbytes = read(p->eread,val_string(str)+val_int(pos),val_int(len));
  442. if( nbytes < 0 ) {
  443. HANDLE_EINTR(stderr_read_again);
  444. neko_error();
  445. }
  446. if( nbytes == 0 )
  447. neko_error();
  448. CAMLreturn(alloc_int(nbytes));
  449. # endif
  450. }
  451. /**
  452. process_stdin_write : 'process -> buf:string -> pos:int -> len:int -> int
  453. <doc>
  454. Write up to [len] bytes from [buf] starting at [pos] to the process stdin.
  455. Returns the number of bytes writen this way. Raise an exception if this
  456. process stdin is closed.
  457. </doc>
  458. **/
  459. CAMLprim value process_stdin_write( value vp, value str, value pos, value len ) {
  460. CHECK_ARGS();
  461. # ifdef _WIN32
  462. {
  463. DWORD nbytes;
  464. if( !WriteFile(p->iwrite,val_string(str)+val_int(pos),val_int(len),&nbytes,NULL) )
  465. neko_error();
  466. CAMLreturn(alloc_int(nbytes));
  467. }
  468. # else
  469. int nbytes;
  470. POSIX_LABEL(stdin_write_again);
  471. nbytes = write(p->iwrite,val_string(str)+val_int(pos),val_int(len));
  472. if( nbytes == -1 ) {
  473. HANDLE_EINTR(stdin_write_again);
  474. neko_error();
  475. }
  476. CAMLreturn(alloc_int(nbytes));
  477. # endif
  478. }
  479. /**
  480. process_stdin_close : 'process -> void
  481. <doc>
  482. Close the process standard input.
  483. </doc>
  484. **/
  485. CAMLprim value process_stdin_close( value vp ) {
  486. CAMLparam1(vp);
  487. vprocess *p = val_process(vp);
  488. # ifdef _WIN32
  489. if( !CloseHandle(p->iwrite) )
  490. neko_error();
  491. # else
  492. if( do_close(p->iwrite) )
  493. neko_error();
  494. p->iwrite = -1;
  495. # endif
  496. CAMLreturn(val_null);
  497. }
  498. /**
  499. process_exit : 'process -> int
  500. <doc>
  501. Wait until the process terminate, then returns its exit code.
  502. </doc>
  503. **/
  504. CAMLprim value process_exit( value vp ) {
  505. CAMLparam1(vp);
  506. vprocess *p = val_process(vp);
  507. # ifdef _WIN32
  508. {
  509. DWORD rval;
  510. WaitForSingleObject(p->pinf.hProcess,INFINITE);
  511. if( !GetExitCodeProcess(p->pinf.hProcess,&rval) )
  512. neko_error();
  513. CAMLreturn(alloc_int(rval));
  514. }
  515. # else
  516. int rval;
  517. while( waitpid(p->pid,&rval,0) != p->pid ) {
  518. if( errno == EINTR )
  519. continue;
  520. neko_error();
  521. }
  522. if( !WIFEXITED(rval) )
  523. neko_error();
  524. CAMLreturn(alloc_int(WEXITSTATUS(rval)));
  525. # endif
  526. }
  527. /**
  528. process_pid : 'process -> int
  529. <doc>
  530. Returns the process id.
  531. </doc>
  532. **/
  533. CAMLprim value process_pid( value vp ) {
  534. CAMLparam1(vp);
  535. vprocess *p = val_process(vp);
  536. # ifdef _WIN32
  537. CAMLreturn(alloc_int(p->pinf.dwProcessId));
  538. # else
  539. CAMLreturn(alloc_int(p->pid));
  540. # endif
  541. }
  542. /**
  543. process_close : 'process -> void
  544. <doc>
  545. Close the process I/O.
  546. </doc>
  547. **/
  548. CAMLprim value process_close( value vp ) {
  549. CAMLparam1(vp);
  550. free_process(vp);
  551. //val_kind(vp) = NULL;
  552. CAMLreturn(val_null);
  553. }
  554. /**
  555. process_kill : 'process -> void
  556. <doc>
  557. Terminates a running process.
  558. </doc>
  559. **/
  560. CAMLprim value process_kill( value vp ) {
  561. CAMLparam1(vp);
  562. # ifdef _WIN32
  563. TerminateProcess(val_process(vp)->pinf.hProcess,-1);
  564. # else
  565. kill(val_process(vp)->pid,9);
  566. # endif
  567. CAMLreturn(val_null);
  568. }
  569. /* ************************************************************************ */