1 /* $Id$
2
3 Part of SWI-Prolog
4
5 Author: Jan Wielemaker
6 E-mail: J.Wielemaker@uva.nl
7 WWW: http://www.swi-prolog.org
8 Copyright (C): 2008-2009, University of Amsterdam
9
10 This library is free software; you can redistribute it and/or
11 modify it under the terms of the GNU Lesser General Public
12 License as published by the Free Software Foundation; either
13 version 2.1 of the License, or (at your option) any later version.
14
15 This library is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 Lesser General Public License for more details.
19
20 You should have received a copy of the GNU Lesser General Public
21 License along with this library; if not, write to the Free Software
22 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23 */
24
25 #ifdef HAVE_CONFIG_H
26 #include <config.h>
27 #endif
28
29 /*#define O_DEBUG 1*/
30 #include <SWI-Stream.h>
31 #include <SWI-Prolog.h>
32 #include "error.h"
33 #include <stdio.h>
34 #include <string.h>
35 #include <assert.h>
36 #include <errno.h>
37 #ifdef HAVE_SYS_TYPES_H
38 #include <sys/types.h>
39 #endif
40 #ifdef HAVE_SYS_WAIT_H
41 #include <sys/wait.h>
42 #endif
43 #ifdef HAVE_SYS_STAT_H
44 #include <sys/stat.h>
45 #endif
46 #ifdef HAVE_FCNTL_H
47 #include <fcntl.h>
48 #endif
49
50 static atom_t ATOM_stdin;
51 static atom_t ATOM_stdout;
52 static atom_t ATOM_stderr;
53 static atom_t ATOM_std;
54 static atom_t ATOM_null;
55 static atom_t ATOM_process;
56 static atom_t ATOM_detached;
57 static atom_t ATOM_cwd;
58 static atom_t ATOM_env;
59 static atom_t ATOM_window;
60 static atom_t ATOM_timeout;
61 static atom_t ATOM_release;
62 static atom_t ATOM_infinite;
63 static functor_t FUNCTOR_error2;
64 static functor_t FUNCTOR_type_error2;
65 static functor_t FUNCTOR_domain_error2;
66 static functor_t FUNCTOR_resource_error1;
67 static functor_t FUNCTOR_process_error2;
68 static functor_t FUNCTOR_system_error2;
69 static functor_t FUNCTOR_pipe1;
70 static functor_t FUNCTOR_exit1;
71 static functor_t FUNCTOR_killed1;
72 static functor_t FUNCTOR_eq2; /* =/2 */
73
74 #define MAYBE 2
75
76 #if O_DEBUG
77 #define DEBUG(g) g
78 #else
79 #define DEBUG(g) (void)0
80 #endif
81
82 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
83 ISSUES:
84 - Deal with child errors (no cwd, cannot execute, etc.)
85 - Windows version
86 - Complete test suite
87 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
88
89
90 /*******************************
91 * ERRORS *
92 *******************************/
93
94 static int
type_error(term_t actual,const char * expected)95 type_error(term_t actual, const char *expected)
96 { term_t ex;
97
98 if ( (ex=PL_new_term_ref()) &&
99 PL_unify_term(ex,
100 PL_FUNCTOR, FUNCTOR_error2,
101 PL_FUNCTOR, FUNCTOR_type_error2,
102 PL_CHARS, expected,
103 PL_TERM, actual,
104 PL_VARIABLE) )
105 return PL_raise_exception(ex);
106
107 return FALSE;
108 }
109
110
111 static int
domain_error(term_t actual,const char * expected)112 domain_error(term_t actual, const char *expected)
113 { term_t ex;
114
115 if ( (ex=PL_new_term_ref()) &&
116 PL_unify_term(ex,
117 PL_FUNCTOR, FUNCTOR_error2,
118 PL_FUNCTOR, FUNCTOR_domain_error2,
119 PL_CHARS, expected,
120 PL_TERM, actual,
121 PL_VARIABLE) )
122 return PL_raise_exception(ex);
123
124 return FALSE;
125 }
126
127
128 static int
resource_error(const char * resource)129 resource_error(const char *resource)
130 { term_t ex;
131
132 if ( (ex=PL_new_term_ref()) &&
133 PL_unify_term(ex,
134 PL_FUNCTOR, FUNCTOR_error2,
135 PL_FUNCTOR, FUNCTOR_resource_error1,
136 PL_CHARS, resource,
137 PL_VARIABLE) )
138 return PL_raise_exception(ex);
139
140 return FALSE;
141 }
142
143
144 /*******************************
145 * ADMIN *
146 *******************************/
147
148 #ifdef __WINDOWS__
149 #include <windows.h>
150 #include <stdio.h>
151 #include <fcntl.h>
152 #include <io.h>
153 #ifndef __MINGW32__
154 typedef DWORD pid_t;
155 #endif
156 typedef wchar_t echar; /* environment character */
157 #else
158 typedef char echar;
159 #endif
160
161 typedef enum std_type
162 { std_std,
163 std_null,
164 std_pipe
165 } std_type;
166
167
168 typedef struct p_stream
169 { term_t term; /* P in pipe(P) */
170 std_type type; /* type of stream */
171 #ifdef __WINDOWS__
172 HANDLE fd[2]; /* pipe handles */
173 #else
174 int fd[2]; /* pipe handles */
175 #endif
176 } p_stream;
177
178
179 typedef struct ecbuf
180 { echar *buffer;
181 size_t size;
182 size_t allocated;
183 } ecbuf;
184
185
186 typedef struct p_options
187 { atom_t exe_name; /* exe as atom */
188 #ifdef __WINDOWS__
189 wchar_t *exe; /* Executable */
190 wchar_t *cmdline; /* Command line */
191 wchar_t *cwd; /* CWD of new process */
192 #else
193 char *exe; /* Executable */
194 char **argv; /* argument vector */
195 char *cwd; /* CWD of new process */
196 char **envp; /* New environment */
197 #endif
198 ecbuf envbuf; /* environment buffer */
199 term_t pid; /* process(PID) */
200 int pipes; /* #pipes found */
201 p_stream streams[3];
202 int detached; /* create as detached */
203 int window; /* Show a window? */
204 } p_options;
205
206
207 typedef struct wait_options
208 { double timeout;
209 int has_timeout;
210 int release;
211 } wait_options;
212
213
214 #ifdef __WINDOWS__
215 static int win_command_line(term_t t, int arity,
216 const wchar_t *exepath, wchar_t **cmdline);
217 #endif
218
219 /*******************************
220 * STRING BUFFER *
221 *******************************/
222
223 static void
free_ecbuf(ecbuf * b)224 free_ecbuf(ecbuf *b)
225 { if ( b->buffer )
226 { PL_free(b->buffer);
227 b->buffer = NULL;
228 }
229 }
230
231
232 static int
add_ecbuf(ecbuf * b,echar * data,size_t len)233 add_ecbuf(ecbuf *b, echar *data, size_t len)
234 { if ( b->size + len > b->allocated )
235 { size_t newsize = (b->allocated ? b->allocated * 2 : 2048);
236
237 while( b->size + len > newsize )
238 newsize *= 2;
239
240 if ( b->buffer )
241 { b->buffer = PL_realloc(b->buffer, newsize*sizeof(echar));
242 } else
243 { b->buffer = PL_malloc(newsize*sizeof(echar));
244 }
245
246 b->allocated = newsize;
247 }
248
249 memcpy(b->buffer+b->size, data, len*sizeof(echar));
250 b->size += len;
251
252 return TRUE;
253 }
254
255 /*******************************
256 * ENVIRONMENT PARSING *
257 *******************************/
258
259 static int
get_echars_arg_ex(int i,term_t from,term_t arg,echar ** sp,size_t * lenp)260 get_echars_arg_ex(int i, term_t from, term_t arg, echar **sp, size_t *lenp)
261 { const echar *s, *e;
262
263 if ( !PL_get_arg(i, from, arg) )
264 return FALSE;
265
266 #ifdef __WINDOWS__
267 if ( !PL_get_wchars(arg, lenp, sp,
268 CVT_ATOMIC|CVT_EXCEPTION) )
269 #else
270 if ( !PL_get_nchars(arg, lenp, sp,
271 CVT_ATOMIC|CVT_EXCEPTION|REP_FN) )
272 #endif
273 return FALSE;
274
275 for(s = *sp, e = s+*lenp; s<e; s++)
276 { if ( !*s )
277 return domain_error(arg, "text_non_zero_code");
278 }
279
280 return TRUE;
281 }
282
283 #ifdef __WINDOWS__
284 #define ECHARS(s) L##s
285 #else
286 #define ECHARS(s) s
287 #endif
288
289 static int
parse_environment(term_t t,p_options * info)290 parse_environment(term_t t, p_options *info)
291 { term_t tail = PL_copy_term_ref(t);
292 term_t head = PL_new_term_ref();
293 term_t tmp = PL_new_term_ref();
294 ecbuf *eb = &info->envbuf;
295 int count = 0, c = 0;
296 #ifndef __WINDOWS__
297 echar *q;
298 char **ep;
299 #endif
300
301 assert(eb->size == 0);
302 assert(eb->allocated == 0);
303 assert(eb->buffer == NULL);
304
305 while( PL_get_list(tail, head, tail) )
306 { echar *s;
307 size_t len;
308
309 if ( !PL_is_functor(head, FUNCTOR_eq2) )
310 return type_error(head, "environment_variable");
311
312 if ( !get_echars_arg_ex(1, head, tmp, &s, &len) )
313 return FALSE;
314 add_ecbuf(eb, s, len);
315 add_ecbuf(eb, ECHARS("="), 1);
316 if ( !get_echars_arg_ex(2, head, tmp, &s, &len) )
317 return FALSE;
318 add_ecbuf(eb, s, len);
319 add_ecbuf(eb, ECHARS("\0"), 1);
320
321 count++;
322 }
323
324 if ( !PL_get_nil(tail) )
325 return type_error(tail, "list");
326
327 #ifdef __WINDOWS__
328 add_ecbuf(eb, ECHARS("\0"), 1);
329 #else
330 info->envp = PL_malloc((count+1)*sizeof(char*));
331
332 for(ep=info->envp, c=0, q=eb->buffer; c<count; c++, ep++)
333 { *ep = q;
334 q += strlen(q)+1;
335 }
336 assert((size_t)(q-eb->buffer) == eb->size);
337 *ep = NULL;
338 #endif
339
340 return TRUE;
341 }
342
343
344 static int
get_stream(term_t t,p_options * info,p_stream * stream)345 get_stream(term_t t, p_options *info, p_stream *stream)
346 { atom_t a;
347
348 if ( PL_get_atom(t, &a) )
349 { if ( a == ATOM_null )
350 { stream->type = std_null;
351 return TRUE;
352 } else if ( a == ATOM_std )
353 { stream->type = std_std;
354 return TRUE;
355 } else
356 { return domain_error(t, "process_stream");
357 }
358 } else if ( PL_is_functor(t, FUNCTOR_pipe1) )
359 { stream->term = PL_new_term_ref();
360 _PL_get_arg(1, t, stream->term);
361 stream->type = std_pipe;
362 info->pipes++;
363 return TRUE;
364 } else
365 return type_error(t, "process_stream");
366 }
367
368
369 static int
parse_options(term_t options,p_options * info)370 parse_options(term_t options, p_options *info)
371 { term_t tail = PL_copy_term_ref(options);
372 term_t head = PL_new_term_ref();
373 term_t arg = PL_new_term_ref();
374
375 info->window = MAYBE;
376
377 while(PL_get_list(tail, head, tail))
378 { atom_t name;
379 int arity;
380
381 if ( !PL_get_name_arity(head, &name, &arity) || arity != 1 )
382 return type_error(head, "option");
383 _PL_get_arg(1, head, arg);
384
385 if ( name == ATOM_stdin )
386 { if ( !get_stream(arg, info, &info->streams[0]) )
387 return FALSE;
388 } else if ( name == ATOM_stdout )
389 { if ( !get_stream(arg, info, &info->streams[1]) )
390 return FALSE;
391 } else if ( name == ATOM_stderr )
392 { if ( !get_stream(arg, info, &info->streams[2]) )
393 return FALSE;
394 } else if ( name == ATOM_process )
395 { info->pid = PL_copy_term_ref(arg);
396 } else if ( name == ATOM_detached )
397 { if ( !PL_get_bool(arg, &info->detached) )
398 return type_error(arg, "boolean");
399 } else if ( name == ATOM_cwd )
400 {
401 #ifdef __WINDOWS__
402 if ( !PL_get_wchars(arg, NULL, &info->cwd,
403 CVT_ATOM|CVT_STRING|CVT_EXCEPTION|BUF_MALLOC) )
404 return FALSE;
405 #else
406 if ( !PL_get_chars(arg, &info->cwd,
407 CVT_ATOM|CVT_STRING|CVT_EXCEPTION|BUF_MALLOC|REP_FN) )
408 return FALSE;
409 #endif
410 } else if ( name == ATOM_window )
411 { if ( !PL_get_bool(arg, &info->window) )
412 return type_error(arg, "boolean");
413 } else if ( name == ATOM_env )
414 { if ( !parse_environment(arg, info) )
415 return FALSE;
416 } else
417 return domain_error(head, "process_option");
418 }
419
420 if ( !PL_get_nil(tail) )
421 return type_error(tail, "list");
422
423 return TRUE;
424 }
425
426
427 static int
get_exe(term_t exe,p_options * info)428 get_exe(term_t exe, p_options *info)
429 { int arity;
430 term_t arg = PL_new_term_ref();
431
432 if ( !PL_get_name_arity(exe, &info->exe_name, &arity) )
433 return type_error(exe, "callable");
434
435 PL_put_atom(arg, info->exe_name);
436
437 #ifdef __WINDOWS__
438 if ( !PL_get_wchars(arg, NULL, &info->exe, CVT_ATOM|CVT_EXCEPTION|BUF_MALLOC) )
439 return FALSE;
440 if ( !win_command_line(exe, arity, info->exe, &info->cmdline) )
441 return FALSE;
442 #else /*__WINDOWS__*/
443 if ( !PL_get_chars(arg, &info->exe, CVT_ATOM|CVT_EXCEPTION|BUF_MALLOC|REP_FN) )
444 return FALSE;
445
446 info->argv = PL_malloc((arity+2)*sizeof(char*));
447 memset(info->argv, 0, (arity+2)*sizeof(char*));
448 info->argv[0] = strdup(info->exe);
449 { int i;
450
451 for(i=1; i<=arity; i++)
452 { _PL_get_arg(i, exe, arg);
453
454 if ( !PL_get_chars(arg, &info->argv[i],
455 CVT_ATOMIC|CVT_EXCEPTION|BUF_MALLOC|REP_FN) )
456 return FALSE;
457 }
458 info->argv[i] = NULL;
459 }
460 #endif /*__WINDOWS__*/
461
462 return TRUE;
463 }
464
465
466 static void
free_options(p_options * info)467 free_options(p_options *info) /* TBD: close streams */
468 { if ( info->exe )
469 { PL_free(info->exe);
470 info->exe = NULL;
471 }
472 if ( info->cwd )
473 { PL_free(info->cwd);
474 info->cwd = NULL;
475 }
476 #ifndef __WINDOWS__
477 if ( info->envp )
478 { PL_free(info->envp);
479 info->envp = NULL;
480 }
481 #endif
482 free_ecbuf(&info->envbuf);
483 #ifdef __WINDOWS__
484 if ( info->cmdline )
485 { PL_free(info->cmdline);
486 info->cmdline = NULL;
487 }
488
489 #else /*__WINDOWS__*/
490
491 if ( info->argv )
492 { char **a;
493 for(a=info->argv; *a; a++)
494 { if ( *a )
495 PL_free(*a);
496 }
497 PL_free(info->argv);
498
499 info->argv = NULL;
500 }
501
502 #endif /*__WINDOWS__*/
503 }
504
505
506 /*******************************
507 * PROCESS READS *
508 *******************************/
509
510 #define PROCESS_MAGIC 0x29498001
511
512 typedef struct process_context
513 { int magic; /* PROCESS_MAGIC */
514 #ifdef __WINDOWS__
515 HANDLE handle; /* process handle */
516 #else
517 pid_t pid; /* the process id */
518 #endif
519 int open_mask; /* Open streams */
520 int pipes[3]; /* stdin/stdout/stderr */
521 } process_context;
522
523 static int wait_for_process(process_context *pc);
524
525 static int
process_fd(void * handle,process_context ** PC)526 process_fd(void *handle, process_context **PC)
527 { process_context *pc = (process_context*) ((uintptr_t)handle&~(uintptr_t)0x3);
528 int pipe = (int)(uintptr_t)handle & 0x3;
529
530 if ( pc->magic == PROCESS_MAGIC )
531 { if ( PC )
532 *PC = pc;
533 return pc->pipes[pipe];
534 }
535
536 return -1;
537 }
538
539
540 static ssize_t
Sread_process(void * handle,char * buf,size_t size)541 Sread_process(void *handle, char *buf, size_t size)
542 { int fd = process_fd(handle, NULL);
543
544 return (*Sfilefunctions.read)((void*)(uintptr_t)fd, buf, size);
545 }
546
547
548 static ssize_t
Swrite_process(void * handle,char * buf,size_t size)549 Swrite_process(void *handle, char *buf, size_t size)
550 { int fd = process_fd(handle, NULL);
551
552 return (*Sfilefunctions.write)((void*)(uintptr_t)fd, buf, size);
553 }
554
555
556 static int
Sclose_process(void * handle)557 Sclose_process(void *handle)
558 { process_context *pc;
559 int fd = process_fd(handle, &pc);
560
561 if ( fd >= 0 )
562 { int which = (int)(uintptr_t)handle & 0x3;
563 int rc;
564
565 rc = (*Sfilefunctions.close)((void*)(uintptr_t)fd);
566 pc->open_mask &= ~(1<<which);
567
568 DEBUG(Sdprintf("Closing fd[%d]; mask = 0x%x\n", which, pc->open_mask));
569
570 if ( !pc->open_mask )
571 { int rcw = wait_for_process(pc);
572
573 return rcw ? 0 : -1;
574 }
575
576 return rc;
577 }
578
579 return -1;
580 }
581
582
583 static int
Scontrol_process(void * handle,int action,void * arg)584 Scontrol_process(void *handle, int action, void *arg)
585 { process_context *pc;
586 int fd = process_fd(handle, &pc);
587
588 switch(action)
589 { case SIO_GETFILENO:
590 { int *fdp = arg;
591 *fdp = fd;
592 return 0;
593 }
594 default:
595 return (*Sfilefunctions.control)((void*)(uintptr_t)fd, action, arg);
596 }
597 }
598
599
600 static IOFUNCTIONS Sprocessfunctions =
601 { Sread_process,
602 Swrite_process,
603 NULL, /* seek */
604 Sclose_process,
605 Scontrol_process,
606 NULL /* seek64 */
607 };
608
609
610 static IOSTREAM *
611 #ifdef __WINDOWS__
open_process_pipe(process_context * pc,int which,HANDLE fd)612 open_process_pipe(process_context *pc, int which, HANDLE fd)
613 #else
614 open_process_pipe(process_context *pc, int which, int fd)
615 #endif
616 { void *handle;
617 int flags;
618
619 pc->open_mask |= (1<<which);
620 #ifdef __WINDOWS__
621 pc->pipes[which] = _open_osfhandle((long)fd, _O_BINARY);
622 #else
623 pc->pipes[which] = fd;
624 #endif
625
626 #define ISO_FLAGS (SIO_RECORDPOS|SIO_FBUF|SIO_TEXT)
627
628 if ( which == 0 )
629 flags = SIO_OUTPUT|ISO_FLAGS;
630 else
631 flags = SIO_INPUT|ISO_FLAGS;
632
633 handle = (void *)((uintptr_t)pc | (uintptr_t)which);
634
635 return Snew(handle, flags, &Sprocessfunctions);
636 }
637
638
639 /*******************************
640 * OS STUFF *
641 *******************************/
642
643
644 #ifdef __WINDOWS__
645
646 CRITICAL_SECTION process_lock;
647 #define LOCK() EnterCriticalSection(&process_lock);
648 #define UNLOCK() LeaveCriticalSection(&process_lock);
649
650 static void
win_init()651 win_init()
652 { InitializeCriticalSection(&process_lock);
653 }
654
655
656 static atom_t
WinError()657 WinError()
658 { int id = GetLastError();
659 char *msg;
660 static WORD lang;
661 static lang_initialised = 0;
662
663 if ( !lang_initialised )
664 lang = MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_UK);
665
666 again:
667 if ( FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER|
668 FORMAT_MESSAGE_IGNORE_INSERTS|
669 FORMAT_MESSAGE_FROM_SYSTEM,
670 NULL, /* source */
671 id, /* identifier */
672 lang,
673 (LPTSTR) &msg,
674 0, /* size */
675 NULL) ) /* arguments */
676 { atom_t a = PL_new_atom(msg);
677
678 LocalFree(msg);
679 lang_initialised = 1;
680
681 return a;
682 } else
683 { if ( lang_initialised == 0 )
684 { lang = MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT);
685 lang_initialised = 1;
686 goto again;
687 }
688
689 return PL_new_atom("Unknown Windows error");
690 }
691 }
692
693
694 static int
win_error(const char * op)695 win_error(const char *op)
696 { atom_t msg = WinError();
697 term_t ex = PL_new_term_ref();
698
699 PL_unify_term(ex, PL_FUNCTOR, FUNCTOR_error2,
700 PL_FUNCTOR, FUNCTOR_system_error2,
701 PL_CHARS, op,
702 PL_ATOM, msg,
703 PL_VARIABLE);
704
705 return PL_raise_exception(ex);
706 }
707
708
709 typedef struct arg_string
710 { size_t len;
711 wchar_t *text;
712 wchar_t quote;
713 } arg_string;
714
715 #define QMISC 0x1
716 #define QDBLQ 0x2
717 #define QSBLQ 0x4
718
719 static int
set_quote(arg_string * as)720 set_quote(arg_string *as)
721 { int needq = 0;
722 const wchar_t *s = as->text;
723
724 for(; *s; s++)
725 { if ( !iswalnum(*s) )
726 { if ( *s == '"' )
727 needq |= QDBLQ;
728 else if ( *s == '\'' )
729 needq |= QSBLQ;
730 else
731 needq |= QMISC;
732 }
733 }
734
735 if ( !needq )
736 { as->quote = 0;
737 return TRUE;
738 }
739 needq &= ~QMISC;
740 switch( needq )
741 { case QDBLQ:
742 as->quote = '\'';
743 return TRUE;
744 case 0:
745 case QSBLQ:
746 as->quote = '"';
747 return TRUE;
748 default:
749 return FALSE;
750 }
751 }
752
753
754 static int
win_command_line(term_t t,int arity,const wchar_t * exe,wchar_t ** cline)755 win_command_line(term_t t, int arity, const wchar_t *exe, wchar_t **cline)
756 { if ( arity > 0 )
757 { arg_string *av = PL_malloc((arity+1)*sizeof(*av));
758 term_t arg = PL_new_term_ref();
759 size_t cmdlen;
760 wchar_t *cmdline, *o;
761 const wchar_t *b;
762 int i;
763
764 if ( (b=wcsrchr(exe, '\\')) )
765 b++;
766 else
767 b = exe;
768 av[0].text = (wchar_t*)b;
769 av[0].len = wcslen(av[0].text);
770 set_quote(&av[0]);
771 cmdlen = av[0].len+(av[0].quote?2:0)+1;
772
773 for( i=1; i<=arity; i++)
774 { PL_get_arg(i, t, arg);
775
776 if ( !PL_get_wchars(arg, &av[i].len, &av[i].text,
777 CVT_ATOMIC|CVT_EXCEPTION|BUF_MALLOC) )
778 return FALSE;
779
780 if ( wcslen(av[i].text) != av[i].len )
781 return domain_error(arg, "no_zero_code_atom");
782
783 if ( !set_quote(&av[i]) )
784 return domain_error(arg, "dos_quotable_atom");
785
786 cmdlen += av[i].len+(av[i].quote?2:0)+1;
787 }
788
789 cmdline = PL_malloc(cmdlen*sizeof(wchar_t));
790 for( o=cmdline,i=0; i<=arity; )
791 { wchar_t *s = av[i].text;
792
793 if ( av[i].quote )
794 *o++ = av[i].quote;
795 wcsncpy(o, s, av[i].len);
796 o += av[i].len;
797 if ( i > 0 )
798 PL_free(s); /* do not free shared exename */
799 if ( av[i].quote )
800 *o++ = av[i].quote;
801
802 if (++i <= arity)
803 *o++ = ' ';
804 }
805 *o = 0;
806 PL_free(av);
807
808 *cline = cmdline;
809 } else
810 { *cline = NULL;
811 }
812
813 return TRUE;
814 }
815
816
817 typedef struct win_process
818 { DWORD pid;
819 HANDLE handle;
820 struct win_process *next;
821 } win_process;
822
823
824 static win_process *processes;
825
826 static void
register_process(DWORD pid,HANDLE h)827 register_process(DWORD pid, HANDLE h)
828 { win_process *wp = PL_malloc(sizeof(*wp));
829
830 wp->pid = pid;
831 wp->handle = h;
832 LOCK();
833 wp->next = processes;
834 processes = wp;
835 UNLOCK();
836 }
837
838
839 static int
unregister_process(DWORD pid)840 unregister_process(DWORD pid)
841 { win_process **wpp, *wp;
842
843 LOCK();
844 for(wpp=&processes, wp=*wpp; wp; wpp=&wp->next, wp=*wpp)
845 { if ( wp->pid == pid )
846 { *wpp = wp->next;
847 PL_free(wp);
848 UNLOCK();
849 return TRUE;
850 }
851 }
852
853 UNLOCK();
854 return FALSE;
855 }
856
857
858 static HANDLE
find_process_from_pid(DWORD pid,const char * pred)859 find_process_from_pid(DWORD pid, const char *pred)
860 { win_process *wp;
861
862 LOCK();
863 for(wp=processes; wp; wp=wp->next)
864 { if ( wp->pid == pid )
865 { HANDLE h = wp->handle;
866 UNLOCK();
867 return h;
868 }
869 }
870
871 UNLOCK();
872
873 if ( pred )
874 { term_t ex = PL_new_term_ref();
875
876 PL_put_integer(ex, pid);
877 pl_error(NULL, 2, NULL, ERR_EXISTENCE,
878 "process", ex);
879 }
880
881 return (HANDLE)0;
882 }
883
884
885 #define WP_TIMEOUT 2
886
887 static int
wait_process_handle(HANDLE process,ULONG * rc,DWORD timeout)888 wait_process_handle(HANDLE process, ULONG *rc, DWORD timeout)
889 { DWORD wc;
890
891 retry:
892 wc = MsgWaitForMultipleObjects(1,
893 &process,
894 FALSE, /* return on any event */
895 timeout,
896 QS_ALLINPUT);
897
898 switch(wc)
899 { case WAIT_OBJECT_0:
900 if ( !GetExitCodeProcess(process, rc) )
901 { win_error("GetExitCodeProcess");
902 CloseHandle(process);
903 return FALSE;
904 }
905 CloseHandle(process);
906 return TRUE;
907 case WAIT_OBJECT_0+1:
908 { MSG msg;
909
910 while( PeekMessage(&msg, NULL, 0, 0, PM_REMOVE) )
911 { TranslateMessage(&msg);
912 DispatchMessage(&msg);
913 if ( PL_handle_signals() < 0 )
914 return FALSE;
915 }
916 goto retry;
917 }
918 case WAIT_TIMEOUT:
919 return WP_TIMEOUT;
920 default:
921 win_error("WaitForSingleObject");
922 CloseHandle(process);
923 return FALSE;
924 }
925 }
926
927
928 static int
wait_for_pid(pid_t pid,term_t code,wait_options * opts)929 wait_for_pid(pid_t pid, term_t code, wait_options *opts)
930 { HANDLE *h;
931
932 if ( (h=find_process_from_pid(pid, "process_wait")) )
933 { ULONG rc;
934 DWORD timeout;
935 int wc;
936
937 if ( opts->has_timeout )
938 timeout = (DWORD)(opts->timeout * 1000.0);
939 else
940 timeout = INFINITE;
941
942 if ( !(wc=wait_process_handle(h, &rc, timeout)) )
943 return FALSE;
944 if ( wc == WP_TIMEOUT )
945 return PL_unify_atom(code, ATOM_timeout);
946
947 unregister_process(pid);
948
949 return PL_unify_term(code,
950 PL_FUNCTOR, FUNCTOR_exit1,
951 PL_LONG, rc);
952 } else
953 { return FALSE;
954 }
955 }
956
957
958 static int
wait_for_process(process_context * pc)959 wait_for_process(process_context *pc)
960 { int rc;
961 ULONG prc;
962
963 rc = wait_process_handle(pc->handle, &prc, INFINITE);
964 CloseHandle(pc->handle);
965 PL_free(pc);
966
967 return rc;
968 }
969
970
971 static int
win_wait_success(atom_t exe,HANDLE process)972 win_wait_success(atom_t exe, HANDLE process)
973 { ULONG rc;
974
975 if ( !wait_process_handle(process, &rc, INFINITE) )
976 return FALSE;
977
978 if ( rc != 0 )
979 { term_t code = PL_new_term_ref();
980 term_t ex = PL_new_term_ref();
981
982 PL_unify_term(ex,
983 PL_FUNCTOR, FUNCTOR_error2,
984 PL_FUNCTOR, FUNCTOR_process_error2,
985 PL_ATOM, exe,
986 PL_FUNCTOR, FUNCTOR_exit1,
987 PL_LONG, rc,
988 PL_VARIABLE);
989 return PL_raise_exception(ex);
990 }
991
992 return TRUE;
993 }
994
995
996 static int
create_pipes(p_options * info)997 create_pipes(p_options *info)
998 { int i;
999 SECURITY_ATTRIBUTES sa;
1000
1001 sa.nLength = sizeof(sa); /* Length in bytes */
1002 sa.bInheritHandle = 1; /* the child must inherit these handles */
1003 sa.lpSecurityDescriptor = NULL;
1004
1005 for(i=0; i<3; i++)
1006 { p_stream *s = &info->streams[i];
1007
1008 if ( s->term )
1009 { if ( !CreatePipe(&s->fd[0], &s->fd[1], &sa, 1<<13) )
1010 { return win_error("CreatePipe");
1011 }
1012 }
1013 }
1014
1015 return TRUE;
1016 }
1017
1018
1019 static IOSTREAM *
Sopen_handle(HANDLE h,const char * mode)1020 Sopen_handle(HANDLE h, const char *mode)
1021 { return Sfdopen(_open_osfhandle((long)h, _O_BINARY), mode);
1022 }
1023
1024
1025 static HANDLE
open_null_stream(DWORD access)1026 open_null_stream(DWORD access)
1027 { SECURITY_ATTRIBUTES sa;
1028
1029 sa.nLength = sizeof(sa); /* Length in bytes */
1030 sa.bInheritHandle = 1; /* the child must inherit these handles */
1031 sa.lpSecurityDescriptor = NULL;
1032
1033 return CreateFile("nul",
1034 access,
1035 FILE_SHARE_READ|FILE_SHARE_WRITE,
1036 &sa, /* security */
1037 OPEN_EXISTING,
1038 0,
1039 NULL);
1040 }
1041
1042
1043 static int
console_app(void)1044 console_app(void)
1045 { HANDLE h;
1046
1047 if ( (h = GetStdHandle(STD_OUTPUT_HANDLE)) != INVALID_HANDLE_VALUE )
1048 { DWORD mode;
1049
1050 if ( GetConsoleMode(h, &mode) )
1051 return TRUE;
1052 }
1053
1054 return FALSE;
1055 }
1056
1057
1058 static int
do_create_process(p_options * info)1059 do_create_process(p_options *info)
1060 { int flags = 0;
1061 PROCESS_INFORMATION pi;
1062 STARTUPINFOW si;
1063
1064 switch(info->window)
1065 { case MAYBE:
1066 if ( !console_app() )
1067 flags |= CREATE_NO_WINDOW;
1068 break;
1069 case TRUE:
1070 break;
1071 case FALSE:
1072 flags |= CREATE_NO_WINDOW;
1073 break;
1074 }
1075
1076 memset(&si, 0, sizeof(si));
1077 si.cb = sizeof(si);
1078 si.dwFlags = STARTF_USESTDHANDLES;
1079
1080 /* stdin */
1081 switch( info->streams[0].type )
1082 { case std_pipe:
1083 si.hStdInput = info->streams[0].fd[0];
1084 SetHandleInformation(info->streams[0].fd[1],
1085 HANDLE_FLAG_INHERIT, FALSE);
1086 break;
1087 case std_null:
1088 si.hStdInput = open_null_stream(GENERIC_READ);
1089 break;
1090 case std_std:
1091 si.hStdInput = GetStdHandle(STD_INPUT_HANDLE);
1092 break;
1093 }
1094 /* stdout */
1095 switch( info->streams[1].type )
1096 { case std_pipe:
1097 si.hStdOutput = info->streams[1].fd[1];
1098 SetHandleInformation(info->streams[1].fd[0],
1099 HANDLE_FLAG_INHERIT, FALSE);
1100 break;
1101 case std_null:
1102 si.hStdOutput = open_null_stream(GENERIC_WRITE);
1103 break;
1104 case std_std:
1105 si.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE);
1106 break;
1107 }
1108 /* stderr */
1109 switch( info->streams[2].type )
1110 { case std_pipe:
1111 si.hStdError = info->streams[2].fd[1];
1112 SetHandleInformation(info->streams[2].fd[0],
1113 HANDLE_FLAG_INHERIT, FALSE);
1114 break;
1115 case std_null:
1116 si.hStdError = open_null_stream(GENERIC_WRITE);
1117 break;
1118 case std_std:
1119 si.hStdError = GetStdHandle(STD_ERROR_HANDLE);
1120 break;
1121 }
1122
1123 if ( CreateProcessW(info->exe,
1124 info->cmdline,
1125 NULL, /* Process security */
1126 NULL, /* Thread security */
1127 TRUE, /* Inherit handles */
1128 flags, /* Creation flags */
1129 info->envbuf.buffer, /* Environment */
1130 info->cwd, /* Directory */
1131 &si, /* Startup info */
1132 &pi) ) /* Process information */
1133 { CloseHandle(pi.hThread);
1134
1135 if ( info->pipes > 0 && info->pid == 0 )
1136 { IOSTREAM *s;
1137 process_context *pc = PL_malloc(sizeof(*pc));
1138
1139 DEBUG(Sdprintf("Wait on pipes\n"));
1140
1141 memset(pc, 0, sizeof(*pc));
1142 pc->magic = PROCESS_MAGIC;
1143 pc->handle = pi.hProcess;
1144
1145 if ( info->streams[0].type == std_pipe )
1146 { CloseHandle(info->streams[0].fd[0]);
1147 s = open_process_pipe(pc, 0, info->streams[0].fd[1]);
1148 PL_unify_stream(info->streams[0].term, s);
1149 }
1150 if ( info->streams[1].type == std_pipe )
1151 { CloseHandle(info->streams[1].fd[1]);
1152 s = open_process_pipe(pc, 1, info->streams[1].fd[0]);
1153 PL_unify_stream(info->streams[1].term, s);
1154 }
1155 if ( info->streams[2].type == std_pipe )
1156 { CloseHandle(info->streams[2].fd[1]);
1157 s = open_process_pipe(pc, 2, info->streams[2].fd[0]);
1158 PL_unify_stream(info->streams[2].term, s);
1159 }
1160
1161 return TRUE;
1162 } else if ( info->pipes > 0 )
1163 { IOSTREAM *s;
1164
1165 if ( info->streams[0].type == std_pipe )
1166 { CloseHandle(info->streams[0].fd[0]);
1167 s = Sopen_handle(info->streams[0].fd[1], "w");
1168 PL_unify_stream(info->streams[0].term, s);
1169 }
1170 if ( info->streams[1].type == std_pipe )
1171 { CloseHandle(info->streams[1].fd[1]);
1172 s = Sopen_handle(info->streams[1].fd[0], "r");
1173 PL_unify_stream(info->streams[1].term, s);
1174 }
1175 if ( info->streams[2].type == std_pipe )
1176 { CloseHandle(info->streams[2].fd[1]);
1177 s = Sopen_handle(info->streams[2].fd[0], "r");
1178 PL_unify_stream(info->streams[2].term, s);
1179 }
1180 }
1181
1182 if ( info->pid )
1183 { register_process(pi.dwProcessId, pi.hProcess);
1184 return PL_unify_integer(info->pid, pi.dwProcessId);
1185 }
1186
1187 return win_wait_success(info->exe_name, pi.hProcess);
1188 } else
1189 { return win_error("CreateProcess");
1190 }
1191 }
1192
1193 #else /*__WINDOWS__*/
1194
1195 static int
create_pipes(p_options * info)1196 create_pipes(p_options *info)
1197 { int i;
1198
1199 for(i=0; i<3; i++)
1200 { p_stream *s = &info->streams[i];
1201
1202 if ( s->term )
1203 { if ( pipe(s->fd) )
1204 { assert(errno = EMFILE);
1205 return resource_error("open_files");
1206 }
1207 }
1208 }
1209
1210 return TRUE;
1211 }
1212
1213
1214 static int
unify_exit_status(term_t code,int status)1215 unify_exit_status(term_t code, int status)
1216 { if ( WIFEXITED(status) )
1217 { return PL_unify_term(code,
1218 PL_FUNCTOR, FUNCTOR_exit1,
1219 PL_INT, (int)WEXITSTATUS(status));
1220 } else if ( WIFSIGNALED(status) )
1221 { return PL_unify_term(code,
1222 PL_FUNCTOR, FUNCTOR_killed1,
1223 PL_INT, (int)WTERMSIG(status));
1224 } else
1225 { assert(0);
1226 return FALSE;
1227 }
1228 }
1229
1230
1231 static int
wait_for_pid(pid_t pid,term_t code,wait_options * opts)1232 wait_for_pid(pid_t pid, term_t code, wait_options *opts)
1233 { pid_t p2;
1234 int status;
1235
1236 if ( opts->has_timeout && opts->timeout == 0.0 )
1237 { if ( (p2=waitpid(pid, &status, WNOHANG)) == pid )
1238 return unify_exit_status(code, status);
1239 else if ( p2 == 0 )
1240 return PL_unify_atom(code, ATOM_timeout);
1241 else
1242 { term_t PID;
1243
1244 error:
1245 return ((PID = PL_new_term_ref()) &&
1246 PL_put_integer(PID, pid) &&
1247 pl_error(NULL, 0, "waitpid", ERR_ERRNO,
1248 errno, "wait", "process", PID));
1249 }
1250 }
1251
1252 for(;;)
1253 { if ( (p2=waitpid(pid, &status, 0)) == pid )
1254 return unify_exit_status(code, status);
1255
1256 if ( p2 == -1 && errno == EINTR )
1257 { if ( PL_handle_signals() < 0 )
1258 return FALSE;
1259 } else
1260 { goto error;
1261 }
1262 }
1263 }
1264
1265
1266 static int
wait_for_process(process_context * pc)1267 wait_for_process(process_context *pc)
1268 { for(;;)
1269 { int status;
1270 pid_t p2;
1271
1272 if ( (p2=waitpid(pc->pid, &status, 0)) == pc->pid )
1273 { PL_free(pc);
1274 return TRUE;
1275 }
1276
1277 if ( errno == EINTR && PL_handle_signals() >= 0 )
1278 continue;
1279
1280 PL_free(pc);
1281 return FALSE;
1282 }
1283 }
1284
1285
1286 static int
wait_success(atom_t name,pid_t pid)1287 wait_success(atom_t name, pid_t pid)
1288 { pid_t p2;
1289
1290 for(;;)
1291 { int status;
1292
1293 if ( (p2=waitpid(pid, &status, 0)) == pid )
1294 { if ( WIFEXITED(status) && WEXITSTATUS(status) == 0 )
1295 { return TRUE;
1296 } else
1297 { term_t code, ex;
1298
1299 if ( (code = PL_new_term_ref()) &&
1300 (ex = PL_new_term_ref()) &&
1301 unify_exit_status(code, status) &&
1302 PL_unify_term(ex,
1303 PL_FUNCTOR, FUNCTOR_error2,
1304 PL_FUNCTOR, FUNCTOR_process_error2,
1305 PL_ATOM, name,
1306 PL_TERM, code,
1307 PL_VARIABLE) )
1308 return PL_raise_exception(ex);
1309 return FALSE;
1310 }
1311 }
1312
1313 if ( p2 == -1 && errno == EINTR )
1314 { if ( PL_handle_signals() < 0 )
1315 return FALSE;
1316 }
1317 }
1318 }
1319
1320
1321 static int
do_create_process(p_options * info)1322 do_create_process(p_options *info)
1323 { int pid;
1324
1325 if ( !(pid=fork()) ) /* child */
1326 { int fd;
1327 int rc;
1328
1329 PL_cleanup_fork();
1330
1331 if ( info->detached )
1332 setsid();
1333
1334 if ( info->cwd )
1335 { if ( chdir(info->cwd) )
1336 { perror(info->cwd);
1337 exit(1);
1338 }
1339 }
1340
1341 /* stdin */
1342 switch( info->streams[0].type )
1343 { case std_pipe:
1344 dup2(info->streams[0].fd[0], 0);
1345 close(info->streams[0].fd[1]);
1346 break;
1347 case std_null:
1348 if ( (fd = open("/dev/null", O_RDONLY)) >= 0 )
1349 dup2(fd, 0);
1350 break;
1351 case std_std:
1352 break;
1353 }
1354 /* stdout */
1355 switch( info->streams[1].type )
1356 { case std_pipe:
1357 dup2(info->streams[1].fd[1], 1);
1358 close(info->streams[1].fd[0]);
1359 break;
1360 case std_null:
1361 if ( (fd = open("/dev/null", O_WRONLY)) >= 0 )
1362 dup2(fd, 1);
1363 break;
1364 case std_std:
1365 break;
1366 }
1367 /* stderr */
1368 switch( info->streams[2].type )
1369 { case std_pipe:
1370 dup2(info->streams[2].fd[1], 2);
1371 close(info->streams[2].fd[0]);
1372 break;
1373 case std_null:
1374 if ( (fd = open("/dev/null", O_WRONLY)) >= 0 )
1375 dup2(fd, 2);
1376 break;
1377 case std_std:
1378 break;
1379 }
1380
1381 if ( info->envp )
1382 rc = execve(info->exe, info->argv, info->envp);
1383 else
1384 rc = execv(info->exe, info->argv);
1385
1386 if ( rc )
1387 { perror(info->exe);
1388 exit(1);
1389 }
1390
1391 { term_t exe = PL_new_term_ref();
1392 PL_put_atom_chars(exe, info->exe);
1393
1394 return pl_error(NULL, 0, "execv", ERR_ERRNO, errno, "exec", "process", exe);
1395 }
1396 } else /* parent */
1397 { if ( info->pipes > 0 && info->pid == 0 )
1398 { IOSTREAM *s;
1399 process_context *pc = PL_malloc(sizeof(*pc));
1400
1401 DEBUG(Sdprintf("Wait on pipes\n"));
1402
1403 memset(pc, 0, sizeof(*pc));
1404 pc->magic = PROCESS_MAGIC;
1405 pc->pid = pid;
1406
1407 if ( info->streams[0].type == std_pipe )
1408 { close(info->streams[0].fd[0]);
1409 s = open_process_pipe(pc, 0, info->streams[0].fd[1]);
1410 PL_unify_stream(info->streams[0].term, s);
1411 }
1412 if ( info->streams[1].type == std_pipe )
1413 { close(info->streams[1].fd[1]);
1414 s = open_process_pipe(pc, 1, info->streams[1].fd[0]);
1415 PL_unify_stream(info->streams[1].term, s);
1416 }
1417 if ( info->streams[2].type == std_pipe )
1418 { close(info->streams[2].fd[1]);
1419 s = open_process_pipe(pc, 2, info->streams[2].fd[0]);
1420 PL_unify_stream(info->streams[2].term, s);
1421 }
1422
1423 return TRUE;
1424 } else if ( info->pipes > 0 )
1425 { IOSTREAM *s;
1426
1427 if ( info->streams[0].type == std_pipe )
1428 { close(info->streams[0].fd[0]);
1429 s = Sfdopen(info->streams[0].fd[1], "w");
1430 PL_unify_stream(info->streams[0].term, s);
1431 }
1432 if ( info->streams[1].type == std_pipe )
1433 { close(info->streams[1].fd[1]);
1434 s = Sfdopen(info->streams[1].fd[0], "r");
1435 PL_unify_stream(info->streams[1].term, s);
1436 }
1437 if ( info->streams[2].type == std_pipe )
1438 { close(info->streams[2].fd[1]);
1439 s = Sfdopen(info->streams[2].fd[0], "r");
1440 PL_unify_stream(info->streams[2].term, s);
1441 }
1442 }
1443
1444 if ( info->pid )
1445 return PL_unify_integer(info->pid, pid);
1446
1447 return wait_success(info->exe_name, pid);
1448 }
1449 }
1450
1451 #endif /*__WINDOWS__*/
1452
1453
1454 /*******************************
1455 * BINDING *
1456 *******************************/
1457
1458 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1459 Basic process creation interface takes
1460
1461 * Exe file
1462 * List of arguments
1463 * standard streams % std, null, pipe(S)
1464 * Working directory
1465 * detached % Unix
1466 * window % Windows
1467 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
1468
1469 static foreign_t
process_create(term_t exe,term_t options)1470 process_create(term_t exe, term_t options)
1471 { p_options info;
1472 int rc = FALSE;
1473
1474 memset(&info, 0, sizeof(info));
1475
1476 if ( !get_exe(exe, &info) )
1477 goto out;
1478 if ( !parse_options(options, &info) )
1479 goto out;
1480 if ( !create_pipes(&info) )
1481 goto out;
1482
1483 rc = do_create_process(&info);
1484
1485 out:
1486 free_options(&info);
1487
1488 return rc;
1489 }
1490
1491
1492 static int
get_pid(term_t pid,pid_t * p)1493 get_pid(term_t pid, pid_t *p)
1494 { int n;
1495
1496 if ( !PL_get_integer(pid, &n) )
1497 return type_error(pid, "integer");
1498 if ( n < 0 )
1499 return domain_error(pid, "not_less_than_zero");
1500
1501 *p = n;
1502 return TRUE;
1503 }
1504
1505
1506 static foreign_t
process_wait(term_t pid,term_t code,term_t options)1507 process_wait(term_t pid, term_t code, term_t options)
1508 { pid_t p;
1509 wait_options opts;
1510 term_t tail = PL_copy_term_ref(options);
1511 term_t head = PL_new_term_ref();
1512 term_t arg = PL_new_term_ref();
1513
1514 if ( !get_pid(pid, &p) )
1515 return FALSE;
1516
1517 memset(&opts, 0, sizeof(opts));
1518 while(PL_get_list(tail, head, tail))
1519 { atom_t name;
1520 int arity;
1521
1522 if ( !PL_get_name_arity(head, &name, &arity) || arity != 1 )
1523 return type_error(head, "option");
1524 _PL_get_arg(1, head, arg);
1525 if ( name == ATOM_timeout )
1526 { atom_t a;
1527
1528 if ( !(PL_get_atom(arg, &a) && a == ATOM_infinite) )
1529 { if ( !PL_get_float(arg, &opts.timeout) )
1530 return type_error(arg, "timeout");
1531 opts.has_timeout = TRUE;
1532 }
1533 } else if ( name == ATOM_release )
1534 { if ( !PL_get_bool(arg, &opts.release) )
1535 return type_error(arg, "boolean");
1536 if ( opts.release == FALSE )
1537 return domain_error(arg, "true");
1538 } else
1539 return domain_error(head, "process_wait_option");
1540 }
1541 if ( !PL_get_nil(tail) )
1542 return type_error(tail, "list");
1543
1544 return wait_for_pid(p, code, &opts);
1545 }
1546
1547
1548 static foreign_t
process_kill(term_t pid,term_t signal)1549 process_kill(term_t pid, term_t signal)
1550 { int p;
1551
1552 if ( !get_pid(pid, &p) )
1553 return FALSE;
1554
1555 {
1556 #ifdef __WINDOWS__
1557 HANDLE h;
1558
1559 if ( !(h=find_process_from_pid(p, "process_kill")) )
1560 return FALSE;
1561
1562 if ( TerminateProcess(h, 255) )
1563 return TRUE;
1564
1565 return win_error("TerminateProcess");
1566 #else /*__WINDOWS__*/
1567 int sig;
1568
1569 if ( !PL_get_signum_ex(signal, &sig) )
1570 return FALSE;
1571
1572 if ( kill(p, sig) == 0 )
1573 return TRUE;
1574
1575 switch(errno)
1576 { case EPERM:
1577 return pl_error("process_kill", 2, NULL, ERR_PERMISSION,
1578 pid, "kill", "process");
1579 case ESRCH:
1580 return pl_error("process_kill", 2, NULL, ERR_EXISTENCE,
1581 "process", pid);
1582 default:
1583 return pl_error("process_kill", 2, "kill", ERR_ERRNO, errno, "kill", "process", pid);
1584 }
1585 #endif /*__WINDOWS__*/
1586 }
1587 }
1588
1589
1590 #define MKATOM(n) ATOM_ ## n = PL_new_atom(#n)
1591 #define MKFUNCTOR(n,a) FUNCTOR_ ## n ## a = PL_new_functor(PL_new_atom(#n), a)
1592
1593 install_t
install_process()1594 install_process()
1595 {
1596 #ifdef __WINDOWS__
1597 win_init();
1598 #endif
1599
1600 MKATOM(stdin);
1601 MKATOM(stdout);
1602 MKATOM(stderr);
1603 MKATOM(std);
1604 MKATOM(null);
1605 MKATOM(process);
1606 MKATOM(detached);
1607 MKATOM(cwd);
1608 MKATOM(env);
1609 MKATOM(window);
1610 MKATOM(timeout);
1611 MKATOM(release);
1612 MKATOM(infinite);
1613
1614 MKFUNCTOR(pipe, 1);
1615 MKFUNCTOR(error, 2);
1616 MKFUNCTOR(type_error, 2);
1617 MKFUNCTOR(domain_error, 2);
1618 MKFUNCTOR(process_error, 2);
1619 MKFUNCTOR(system_error, 2);
1620 MKFUNCTOR(resource_error, 1);
1621 MKFUNCTOR(exit, 1);
1622 MKFUNCTOR(killed, 1);
1623
1624 FUNCTOR_eq2 = PL_new_functor(PL_new_atom("="), 2);
1625
1626 PL_register_foreign("process_create", 2, process_create, 0);
1627 PL_register_foreign("process_wait", 3, process_wait, 0);
1628 PL_register_foreign("process_kill", 2, process_kill, 0);
1629 }
1630