process_stubs.c 14 KB

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