1 
2 #ifndef _WIN32
3 
4 #ifndef _GNU_SOURCE
5 #define _GNU_SOURCE 1
6 #endif
7 
8 #include <stdlib.h>
9 #include <fcntl.h>
10 #include <stdio.h>
11 
12 #include "../processx.h"
13 #include "../cleancall.h"
14 
15 /* Internals */
16 
17 static void processx__child_init(processx_handle_t *handle, SEXP connections,
18 				 int (*pipes)[2], int stdio_count,
19 				 char *command, char **args,
20 				 int error_fd, const char *pty_name, char **env,
21                                  processx_options_t *options,
22 				 const char *tree_id);
23 
24 static SEXP processx__make_handle(SEXP private, int cleanup);
25 static void processx__handle_destroy(processx_handle_t *handle);
26 void processx__create_connections(processx_handle_t *handle, SEXP private,
27 				  const char *encoding);
28 
29 /* Define BSWAP_32 on Big Endian systems */
30 #ifdef WORDS_BIGENDIAN
31 #if (defined(__sun) && defined(__SVR4))
32 #include <sys/byteorder.h>
33 #elif defined(__FreeBSD__)
34 #include <sys/endian.h>
35 #elif (defined(__APPLE__) && defined(__ppc__) || defined(__ppc64__))
36 #include <libkern/OSByteOrder.h>
37 #define BSWAP_32 OSSwapInt32
38 #elif (defined(__OpenBSD__))
39 #define BSWAP_32(x) swap32(x)
40 #elif (defined(__GLIBC__))
41 #include <byteswap.h>
42 #define BSWAP_32(x) bswap_32(x)
43 #endif
44 #endif
45 
46 #if defined(__APPLE__)
47 # include <crt_externs.h>
48 # define environ (*_NSGetEnviron())
49 #else
50 extern char **environ;
51 #endif
52 
53 #include <termios.h>
54 #include <sys/ioctl.h>
55 
56 extern processx__child_list_t child_list_head;
57 extern processx__child_list_t *child_list;
58 extern processx__child_list_t child_free_list_head;
59 extern processx__child_list_t *child_free_list;
60 
61 extern int processx__notify_old_sigchld_handler;
62 
63 /* We are trying to make sure that the variables in the library are
64    properly set to their initial values after a library (re)load.
65    This function is called from `R_init_processx`. */
66 
R_init_processx_unix()67 void R_init_processx_unix() {
68   child_list_head.pid = 0;
69   child_list_head.weak_status = R_NilValue;
70   child_list_head.next = 0;
71   child_list = &child_list_head;
72 
73   child_free_list_head.pid = 0;
74   child_free_list_head.weak_status = R_NilValue;
75   child_free_list_head.next = 0;
76   child_free_list = &child_free_list_head;
77 
78   if (getenv("PROCESSX_NOTIFY_OLD_SIGCHLD")) {
79     processx__notify_old_sigchld_handler = 1;
80   }
81 }
82 
processx__pty_master_open(char * sub_name,size_t sn_len)83 int processx__pty_master_open(char *sub_name, size_t sn_len) {
84   int master_fd, saved_errno;
85   char *p;
86 
87   master_fd = posix_openpt(O_RDWR | O_NOCTTY);
88   if (master_fd == -1) return -1;
89 
90   if (grantpt(master_fd) == -1) {
91     saved_errno = errno;
92     close(master_fd);
93     errno = saved_errno;
94     return -1;
95   }
96 
97   if (unlockpt(master_fd) == -1) {
98     saved_errno = errno;
99     close(master_fd);
100     errno = saved_errno;
101     return -1;
102   }
103 
104   p = ptsname(master_fd);
105   if (p == NULL) {
106     saved_errno = errno;
107     close(master_fd);
108     errno = saved_errno;
109     return -1;
110   }
111 
112   if (strlen(p) < sn_len) {
113     strncpy(sub_name, p, sn_len);
114   } else {
115     close(master_fd);
116     errno = EOVERFLOW;
117     return -1;
118   }
119 
120   return master_fd;
121 }
122 
123 /* These run in the child process, so no coverage here. */
124 /* LCOV_EXCL_START */
125 
processx__write_int(int fd,int err)126 void processx__write_int(int fd, int err) {
127   ssize_t dummy = write(fd, &err, sizeof(int));
128   (void) dummy;
129 }
130 
processx__child_init(processx_handle_t * handle,SEXP connections,int (* pipes)[2],int stdio_count,char * command,char ** args,int error_fd,const char * pty_name,char ** env,processx_options_t * options,const char * tree_id)131 static void processx__child_init(processx_handle_t *handle, SEXP connections,
132                                  int (*pipes)[2], int stdio_count,
133                                  char *command, char **args,
134                                  int error_fd, const char *pty_name, char **env,
135                                  processx_options_t *options,
136                                  const char *tree_id) {
137 
138   int close_fd, use_fd, fd, i;
139   int min_fd = 0;
140 
141   setsid();
142 
143   /* Do we need a pty? */
144   if (pty_name) {
145     /* Do not mess with stdin/stdout/stderr, all handled by the pty */
146     min_fd = 3;
147 
148     int sub_fd = open(pty_name, O_RDWR);
149     if (sub_fd == -1) {
150       processx__write_int(error_fd, -errno);
151       raise(SIGKILL);
152     }
153 
154 #ifdef TIOCSCTTY
155     if (ioctl(sub_fd, TIOCSCTTY, 0) == -1) {
156       processx__write_int(error_fd, -errno);
157       raise(SIGKILL);
158     }
159 #endif
160 
161 #ifdef TIOCSWINSZ
162     struct winsize w;
163     w.ws_row = options->pty_rows;
164     w.ws_col = options->pty_cols;
165     if (ioctl(sub_fd, TIOCSWINSZ, &w) == -1) {
166       processx__write_int(error_fd, -errno);
167       raise(SIGKILL);
168     }
169 #endif
170 
171     struct termios tp;
172 
173     if (tcgetattr(sub_fd, &tp) == -1) {
174       processx__write_int(error_fd, -errno);
175       raise(SIGKILL);
176     }
177 
178     if (options->pty_echo) {
179       tp.c_lflag |= ECHO;
180     } else {
181       tp.c_lflag &= ~ECHO;
182     }
183 
184     if (tcsetattr(sub_fd, TCSAFLUSH, &tp) == -1) {
185       processx__write_int(error_fd, -errno);
186       raise(SIGKILL);
187     }
188 
189     /* TODO: set other terminal attributes and size */
190 
191     /* Duplicate pty sub to be child's stdin, stdout, and stderr */
192     if (dup2(sub_fd, STDIN_FILENO) != STDIN_FILENO) {
193       processx__write_int(error_fd, -errno);
194       raise(SIGKILL);
195     }
196     if (dup2(sub_fd, STDOUT_FILENO) != STDOUT_FILENO) {
197       processx__write_int(error_fd, -errno);
198       raise(SIGKILL);
199     }
200     if (dup2(sub_fd, STDERR_FILENO) != STDERR_FILENO) {
201       processx__write_int(error_fd, -errno);
202       raise(SIGKILL);
203     }
204 
205     if (sub_fd > STDERR_FILENO) close(sub_fd);
206   }
207 
208   /* We want to prevent use_fd < fd, because we will dup2() use_fd into
209      fd later. If use_fd >= fd, then this is always possible,
210      without mixing up stdin, stdout and stderr. Without this, we could
211      have a case when we dup2() 2 into 1, and then 1 is lost. */
212 
213   for (fd = min_fd; fd < stdio_count; fd++) {
214     use_fd = pipes[fd][1];
215     /* If use_fd < 0 then there is no pipe for fd. */
216     if (use_fd < 0 || use_fd >= fd) continue;
217     /* If use_fd < fd, then we create a brand new fd for it,
218        starting at stdio_count, which is bigger then fd, surely. */
219     pipes[fd][1] = fcntl(use_fd, F_DUPFD, stdio_count);
220     if (pipes[fd][1] == -1) {
221       processx__write_int(error_fd, -errno);
222       raise(SIGKILL);
223     }
224   }
225 
226   /* This loop initializes the stdin, stdout, stderr fds of the child
227      process properly. */
228 
229   for (fd = min_fd; fd < stdio_count; fd++) {
230     SEXP output = VECTOR_ELT(connections, fd);
231     const char *stroutput =
232       Rf_isString(output) ? CHAR(STRING_ELT(output, 0)) : NULL;
233 
234     /* close_fd is an fd that must be closed. Initially this is the
235        parent's end of a pipe. (-1 if no pipe for this fd.) */
236     close_fd = pipes[fd][0];
237     /* use_fd is the fd that the child must use for stdin/out/err. */
238     use_fd = pipes[fd][1];
239 
240     /* If no pipe, then we see if this is the 2>&1 case. */
241     if (fd == 2 && use_fd < 0 && stroutput &&
242 	! strcmp(stroutput, "2>&1")) {
243       use_fd = 1;
244 
245     } else if (use_fd < 0) {
246       /* Otherwise we open a file. If the stdin/out/err is not
247 	 requested, then we open a file to /dev/null */
248       /* For fd >= 3, the fd is just passed, and we just use it,
249 	 no need to open any file */
250       if (fd >= 3) continue;
251 
252       if (stroutput) {
253 	/* A file was requested, open it */
254 	if (fd == 0) {
255 	  use_fd = open(stroutput, O_RDONLY);
256 	} else {
257 	  use_fd = open(stroutput, O_CREAT | O_TRUNC| O_RDWR, 0644);
258 	}
259       } else {
260 	/* NULL, so stdin/out/err is ignored, using /dev/null */
261 	use_fd = open("/dev/null", fd == 0 ? O_RDONLY : O_RDWR);
262       }
263       /* In the output file case, we might need to close use_fd, after
264 	 we dup2()-d it into fd. */
265       close_fd = use_fd;
266 
267       if (use_fd == -1) {
268 	processx__write_int(error_fd, -errno);
269 	raise(SIGKILL);
270       }
271     }
272 
273     /* We will use use_fd for fd. If they happen to be equal, make
274        sure that fd is _not_ closed on exec. Otherwise dup2() use_fd
275        into fd. dup2() clears the CLOEXEC flag, so no need for a fcntl
276        call in this case. */
277     if (fd == use_fd) {
278       processx__cloexec_fcntl(use_fd, 0);
279     } else {
280       fd = dup2(use_fd, fd);
281     }
282 
283     if (fd == -1) {
284       processx__write_int(error_fd, -errno);
285       raise(SIGKILL);
286     }
287 
288     if (fd <= 2) processx__nonblock_fcntl(fd, 0);
289 
290     /* If we have an extra fd, that we already dup2()-d into fd,
291        we can close it now. */
292     if (close_fd >= stdio_count) close(close_fd);
293   }
294 
295   for (fd = min_fd; fd < stdio_count; fd++) {
296     use_fd = pipes[fd][1];
297     if (use_fd >= stdio_count) close(use_fd);
298   }
299 
300   for (i = stdio_count; i < error_fd; i++) {
301     close(i);
302   }
303   for (i = error_fd + 1; ; i++) {
304     if (-1 == close(i) && i > 200) break;
305   }
306 
307   if (options->wd != NULL && chdir(options->wd)) {
308     processx__write_int(error_fd, - errno);
309     raise(SIGKILL);
310   }
311 
312   if (env) environ = env;
313 
314   if (putenv(strdup(tree_id))) {
315     processx__write_int(error_fd, - errno);
316     raise(SIGKILL);
317   }
318 
319   execvp(command, args);
320   processx__write_int(error_fd, - errno);
321   raise(SIGKILL);
322 }
323 
324 /* LCOV_EXCL_STOP */
325 
processx__finalizer(SEXP status)326 void processx__finalizer(SEXP status) {
327   processx_handle_t *handle = (processx_handle_t*) R_ExternalPtrAddr(status);
328   pid_t pid;
329   int wp, wstat;
330 
331   processx__block_sigchld();
332 
333   /* Free child list nodes that are not needed any more. */
334   processx__freelist_free();
335 
336   /* Already freed? */
337   if (!handle) goto cleanup;
338 
339   pid = handle->pid;
340 
341   if (handle->cleanup) {
342     /* Do a non-blocking waitpid() to see if it is running */
343     do {
344       wp = waitpid(pid, &wstat, WNOHANG);
345     } while (wp == -1 && errno == EINTR);
346 
347     /* Maybe just waited on it? Then collect status */
348     if (wp == pid) processx__collect_exit_status(status, wp, wstat);
349 
350     /* If it is running, we need to kill it, and wait for the exit status */
351     if (wp == 0) {
352       kill(-pid, SIGKILL);
353       do {
354 	wp = waitpid(pid, &wstat, 0);
355       } while (wp == -1 && errno == EINTR);
356       processx__collect_exit_status(status, wp, wstat);
357     }
358   }
359 
360   /* Note: if no cleanup is requested, then we still have a sigchld
361      handler, to read out the exit code via waitpid, but no handle
362      any more. */
363 
364   /* Deallocate memory */
365   R_ClearExternalPtr(status);
366   processx__handle_destroy(handle);
367 
368  cleanup:
369   processx__unblock_sigchld();
370 }
371 
processx__make_handle(SEXP private,int cleanup)372 static SEXP processx__make_handle(SEXP private, int cleanup) {
373   processx_handle_t * handle;
374   SEXP result;
375 
376   handle = (processx_handle_t*) malloc(sizeof(processx_handle_t));
377   if (!handle) { R_THROW_ERROR("Cannot make processx handle, out of memory"); }
378   memset(handle, 0, sizeof(processx_handle_t));
379   handle->waitpipe[0] = handle->waitpipe[1] = -1;
380 
381   result = PROTECT(R_MakeExternalPtr(handle, private, R_NilValue));
382   R_RegisterCFinalizerEx(result, processx__finalizer, 1);
383   handle->cleanup = cleanup;
384 
385   UNPROTECT(1);
386   return result;
387 }
388 
processx__handle_destroy(processx_handle_t * handle)389 static void processx__handle_destroy(processx_handle_t *handle) {
390   if (!handle) return;
391   free(handle);
392 }
393 
processx__make_socketpair(int pipe[2],const char * exe)394 void processx__make_socketpair(int pipe[2], const char *exe) {
395 #if defined(__linux__)
396   static int no_cloexec;
397   if (no_cloexec)  goto skip;
398 
399   if (socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, pipe) == 0)
400     return;
401 
402   /* Retry on EINVAL, it means SOCK_CLOEXEC is not supported.
403    * Anything else is a genuine error.
404    */
405   if (errno != EINVAL) {
406     R_THROW_SYSTEM_ERROR("processx socketpair");
407   }
408 
409   no_cloexec = 1;
410 
411 skip:
412 #endif
413 
414   if (socketpair(AF_UNIX, SOCK_STREAM, 0, pipe)) {
415     if (exe) {
416       R_THROW_SYSTEM_ERROR("cannot make processx socketpair while "
417                            "running '%s'", exe);
418     } else {
419       R_THROW_SYSTEM_ERROR("cannot make processx socketpair");
420     }
421   }
422 
423   processx__cloexec_fcntl(pipe[0], 1);
424   processx__cloexec_fcntl(pipe[1], 1);
425 }
426 
processx_exec(SEXP command,SEXP args,SEXP pty,SEXP pty_options,SEXP connections,SEXP env,SEXP windows_verbatim_args,SEXP windows_hide_window,SEXP windows_detached_process,SEXP private,SEXP cleanup,SEXP wd,SEXP encoding,SEXP tree_id)427 SEXP processx_exec(SEXP command, SEXP args, SEXP pty, SEXP pty_options,
428                    SEXP connections, SEXP env, SEXP windows_verbatim_args,
429                    SEXP windows_hide_window, SEXP windows_detached_process,
430                    SEXP private, SEXP cleanup, SEXP wd, SEXP encoding,
431                    SEXP tree_id) {
432 
433   char *ccommand = processx__tmp_string(command, 0);
434   char **cargs = processx__tmp_character(args);
435   char **cenv = isNull(env) ? 0 : processx__tmp_character(env);
436   int ccleanup = INTEGER(cleanup)[0];
437 
438   const int cpty = LOGICAL(pty)[0];
439   const char *cencoding = CHAR(STRING_ELT(encoding, 0));
440   const char *ctree_id = CHAR(STRING_ELT(tree_id, 0));
441   processx_options_t options = { 0 };
442   int num_connections = LENGTH(connections);
443 
444   pid_t pid;
445   int err, exec_errorno = 0, status;
446   ssize_t r;
447   int signal_pipe[2] = { -1, -1 };
448   int (*pipes)[2];
449   int i;
450   int pty_master_fd;
451 #define R_PROCESSX_PTY_NAME_LEN 2014
452   char pty_namex[R_PROCESSX_PTY_NAME_LEN];
453   char *pty_name = cpty ? pty_namex : 0;
454 
455   processx_handle_t *handle = NULL;
456   SEXP result;
457 
458   pipes = (int(*)[2]) R_alloc(num_connections, sizeof(int) * 2);
459   for (i = 0; i < num_connections; i++) pipes[i][0] = pipes[i][1] = -1;
460 
461   options.wd = isNull(wd) ? 0 : CHAR(STRING_ELT(wd, 0));
462 
463   if (pipe(signal_pipe)) {
464     R_THROW_SYSTEM_ERROR("Cannot create pipe when running '%s'", ccommand);
465   }
466   processx__cloexec_fcntl(signal_pipe[0], 1);
467   processx__cloexec_fcntl(signal_pipe[1], 1);
468 
469   processx__setup_sigchld();
470 
471   result = PROTECT(processx__make_handle(private, ccleanup));
472   handle = R_ExternalPtrAddr(result);
473 
474   if (cpty) {
475     pty_master_fd =
476       processx__pty_master_open(pty_name, R_PROCESSX_PTY_NAME_LEN);
477     if (pty_master_fd == -1) {
478       R_THROW_SYSTEM_ERROR("Cannot open pty when running '%s'", ccommand);
479     }
480     options.pty_echo = LOGICAL(VECTOR_ELT(pty_options, 0))[0];
481     options.pty_rows = INTEGER(VECTOR_ELT(pty_options, 1))[0];
482     options.pty_cols = INTEGER(VECTOR_ELT(pty_options, 2))[0];
483   }
484 
485   handle->fd0 = handle->fd1 = handle->fd2 = -1;
486   for (i = 0; i < num_connections; i++) {
487     SEXP output = VECTOR_ELT(connections, i);
488     const char *stroutput =
489       Rf_isString(output) ? CHAR(STRING_ELT(output, 0)) : NULL;
490 
491     if (isNull(output)) {
492       /* Ignored output, nothing to do, handled in the child */
493 
494     } else if (stroutput && ! strcmp("|", stroutput)) {
495       /* pipe, need to create */
496       processx__make_socketpair(pipes[i], ccommand);
497       if (i == 0) handle->fd0 = pipes[i][0];
498       if (i == 1) handle->fd1 = pipes[i][0];
499       if (i == 2) handle->fd2 = pipes[i][0];
500       processx__nonblock_fcntl(pipes[i][0], 1);
501 
502     } else if (i == 2 && stroutput && ! strcmp("2>&1", stroutput)) {
503       /* redirected stderr, handled in child */
504 
505     } else if (stroutput && ! strcmp("", stroutput)) {
506       /* inherited std stream, assume usual numbers */
507       pipes[i][1] = i;
508 
509     } else if (stroutput) {
510       /* redirect to file, nothing to do the child will open it */
511 
512     } else {
513       /* inherited processx connection, need to duplicate */
514       processx_connection_t *ccon =
515 	R_ExternalPtrAddr(VECTOR_ELT(connections, i));
516       int fd = processx_c_connection_fileno(ccon);
517       pipes[i][1] = fd;
518     }
519   }
520 
521   processx__block_sigchld();
522 
523   pid = fork();
524 
525   /* TODO: how could we test a failure? */
526   if (pid == -1) {		/* ERROR */
527     err = -errno;
528     if (signal_pipe[0] >= 0) close(signal_pipe[0]);
529     if (signal_pipe[1] >= 0) close(signal_pipe[1]);
530     if (cpty) close(pty_master_fd);
531     processx__unblock_sigchld();
532     R_THROW_SYSTEM_ERROR_CODE(err, "Cannot fork when running '%s'",
533                               ccommand);
534   }
535 
536   /* CHILD */
537   if (pid == 0) {
538     /* LCOV_EXCL_START */
539     if (cpty) close(pty_master_fd);
540     processx__unblock_sigchld();
541     processx__child_init(handle, connections, pipes, num_connections,
542 			 ccommand, cargs, signal_pipe[1],
543                          pty_name, cenv, &options, ctree_id);
544     R_THROW_SYSTEM_ERROR("Cannot start child process when running '%s'",
545                          ccommand);
546     /* LCOV_EXCL_STOP */
547   }
548 
549   /* Query creation time ASAP. We'll use (pid, create_time) as an ID,
550      to avoid race conditions when sending signals */
551   handle->create_time = processx__create_time(pid);
552 
553   handle->ptyfd = -1;
554   if (cpty) handle->ptyfd = pty_master_fd;
555 
556   /* We need to know the processx children */
557   if (processx__child_add(pid, result)) {
558     err = -errno;
559     if (signal_pipe[0] >= 0) close(signal_pipe[0]);
560     if (signal_pipe[1] >= 0) close(signal_pipe[1]);
561     processx__unblock_sigchld();
562     R_THROW_ERROR("Cannot create child process '%s', out of memory",
563                   ccommand);
564   }
565 
566   /* SIGCHLD can arrive now */
567   processx__unblock_sigchld();
568 
569   if (signal_pipe[1] >= 0) close(signal_pipe[1]);
570 
571   do {
572     r = read(signal_pipe[0], &exec_errorno, sizeof(exec_errorno));
573   } while (r == -1 && errno == EINTR);
574 
575   if (r == 0) {
576     ; /* okay, EOF */
577   } else if (r == sizeof(exec_errorno)) {
578     do {
579       err = waitpid(pid, &status, 0); /* okay, read errorno */
580     } while (err == -1 && errno == EINTR);
581 
582   } else if (r == -1 && errno == EPIPE) {
583     do {
584       err = waitpid(pid, &status, 0); /* okay, got EPIPE */
585     } while (err == -1 && errno == EINTR);
586 
587   } else {
588     R_THROW_SYSTEM_ERROR_CODE(-exec_errorno,
589                               "Child process '%s' failed to start",
590                               ccommand);
591   }
592 
593   if (signal_pipe[0] >= 0) close(signal_pipe[0]);
594 
595   /* Closed unused ends of std pipes. If there is no parent end, then
596      this is an inherited std{in,out,err} fd, so we should not close it. */
597   for (i = 0; i < 3; i++) {
598     if (pipes[i][1] >= 0 && pipes[i][0] >= 0) close(pipes[i][1]);
599   }
600 
601   /* Create proper connections */
602   processx__create_connections(handle, private, cencoding);
603 
604   if (exec_errorno == 0) {
605     handle->pid = pid;
606     UNPROTECT(1);		/* result */
607     return result;
608   }
609 
610   R_THROW_SYSTEM_ERROR_CODE(-exec_errorno,
611                             "cannot start processx process '%s'",
612                             ccommand);
613   return R_NilValue;
614 }
615 
processx__collect_exit_status(SEXP status,int retval,int wstat)616 void processx__collect_exit_status(SEXP status, int retval, int wstat) {
617   processx_handle_t *handle = R_ExternalPtrAddr(status);
618 
619   /* This must be called from a function that blocks SIGCHLD.
620      So we are not blocking it here. */
621 
622   if (!handle) {
623     R_THROW_ERROR("Invalid handle, already finalized");
624   }
625 
626   if (handle->collected) { return; }
627 
628   /* If waitpid returned -1, then an error happened, e.g. ECHILD, because
629      another SIGCHLD handler collected the exit status already. */
630   if (retval == -1) {
631     handle->exitcode = NA_INTEGER;
632   } else if (WIFEXITED(wstat)) {
633     handle->exitcode = WEXITSTATUS(wstat);
634   } else {
635     handle->exitcode = - WTERMSIG(wstat);
636   }
637 
638   handle->collected = 1;
639 }
640 
processx__wait_cleanup(void * ptr)641 static void processx__wait_cleanup(void *ptr) {
642   int *fds = (int*) ptr;
643   if (!fds) return;
644   if (fds[0] >= 0) close(fds[0]);
645   if (fds[1] >= 0) close(fds[1]);
646   free(fds);
647 }
648 
649 /* In general we need to worry about three asynchronous processes here:
650  * 1. The main code, i.e. the code in this function.
651  * 2. The finalizer, that can be triggered by any R function.
652  *    A good strategy is to avoid calling R functions here completely.
653  *    Functions that return immediately, like `R_CheckUserInterrupt`, or
654  *    a `ScalarLogical` that we return, are fine.
655  * 3. The SIGCHLD handler that we just block at the beginning, but it can
656  *    still be called between the R function doing the `.Call` to us, and
657  *    the signal blocking call.
658  *
659  * Keeping these in mind, we do this:
660  *
661  * 1. If the exit status was copied over to R already, we return
662  *    immediately from R. Otherwise this C function is called.
663  * 2. We block SIGCHLD.
664  * 3. If we already collected the exit status, then this process has
665  *    finished, so we don't need to wait.
666  * 4. We set up a self-pipe that we can poll. The pipe will be closed in
667  *    the SIGCHLD signal handler, and that triggers the poll event.
668  * 5. We unblock the SIGCHLD handler, so that it can trigger the pipe event.
669  * 6. We start polling. We poll in small time chunks, to keep the wait still
670  *    interruptible.
671  * 7. We keep polling until the timeout expires or the process finishes.
672  */
673 
processx_wait(SEXP status,SEXP timeout,SEXP name)674 SEXP processx_wait(SEXP status, SEXP timeout, SEXP name) {
675   processx_handle_t *handle = R_ExternalPtrAddr(status);
676   const char *cname = isNull(name) ? "???" : CHAR(STRING_ELT(name, 0));
677   int ctimeout = INTEGER(timeout)[0], timeleft = ctimeout;
678   struct pollfd fd;
679   int ret = 0;
680   pid_t pid;
681 
682   int *fds = malloc(sizeof(int) * 2);
683   if (!fds) R_THROW_SYSTEM_ERROR("Allocating memory when waiting");
684   fds[0] = fds[1] = -1;
685   r_call_on_exit(processx__wait_cleanup, fds);
686 
687   processx__block_sigchld();
688 
689   if (!handle) {
690     processx__unblock_sigchld();
691     return ScalarLogical(1);
692   }
693 
694   pid = handle->pid;
695 
696   /* If we already have the status, then return now. */
697   if (handle->collected) {
698     processx__unblock_sigchld();
699     return ScalarLogical(1);
700   }
701 
702   /* Make sure this is active, in case another package replaced it... */
703   processx__setup_sigchld();
704   processx__block_sigchld();
705 
706   /* Setup the self-pipe that we can poll */
707   if (pipe(handle->waitpipe)) {
708     processx__unblock_sigchld();
709     R_THROW_SYSTEM_ERROR("processx error when waiting for '%s'", cname);
710   }
711   fds[0] = handle->waitpipe[0];
712   fds[1] = handle->waitpipe[1];
713   processx__nonblock_fcntl(handle->waitpipe[0], 1);
714   processx__nonblock_fcntl(handle->waitpipe[1], 1);
715 
716   /* Poll on the pipe, need to unblock sigchld before */
717   fd.fd = handle->waitpipe[0];
718   fd.events = POLLIN;
719   fd.revents = 0;
720 
721   processx__unblock_sigchld();
722 
723 
724 
725   while (ctimeout < 0 || timeleft > PROCESSX_INTERRUPT_INTERVAL) {
726     do {
727       ret = poll(&fd, 1, PROCESSX_INTERRUPT_INTERVAL);
728     } while (ret == -1 && errno == EINTR);
729 
730     /* If not a timeout, then we are done */
731     if (ret != 0) break;
732 
733     R_CheckUserInterrupt();
734 
735     /* We also check if the process is alive, because the SIGCHLD is
736        not delivered in valgrind :( This also works around the issue
737        of SIGCHLD handler interference, i.e. if another package (like
738        parallel) removes our signal handler. */
739     ret = kill(pid, 0);
740     if (ret != 0) {
741       ret = 1;
742       goto cleanup;
743     }
744 
745     if (ctimeout >= 0) timeleft -= PROCESSX_INTERRUPT_INTERVAL;
746   }
747 
748   /* Maybe we are not done, and there is a little left from the timeout */
749   if (ret == 0 && timeleft >= 0) {
750     do {
751       ret = poll(&fd, 1, timeleft);
752     } while (ret == -1 && errno == EINTR);
753   }
754 
755   if (ret == -1) {
756     R_THROW_SYSTEM_ERROR("processx wait with timeout error while "
757                          "waiting for '%s'", cname);
758   }
759 
760  cleanup:
761   /* pipe is closed in the on_exit handler */
762   handle->waitpipe[0] = -1;
763   handle->waitpipe[1] = -1;
764 
765   return ScalarLogical(ret != 0);
766 }
767 
768 /* This is similar to `processx_wait`, but a bit simpler, because we
769  * don't need to wait and poll. The same restrictions listed there, also
770  * apply here.
771  *
772  * 1. If the exit status was copied over to R already, we return
773  *    immediately from R. Otherwise this C function is called.
774  * 2. We block SIGCHLD.
775  * 3. If we already collected the exit status, then this process has
776  *    finished, and we return FALSE.
777  * 4. Otherwise we do a non-blocking `waitpid`, because the process might
778  *    have finished, we just haven't collected its exit status yet.
779  * 5. If the process is still running, `waitpid` returns 0. We return TRUE.
780  * 6. Otherwise we collect the exit status, and return FALSE.
781  */
782 
processx_is_alive(SEXP status,SEXP name)783 SEXP processx_is_alive(SEXP status, SEXP name) {
784   processx_handle_t *handle = R_ExternalPtrAddr(status);
785   const char *cname = isNull(name) ? "???" : CHAR(STRING_ELT(name, 0));
786   pid_t pid;
787   int wstat, wp;
788   int ret = 0;
789 
790   processx__block_sigchld();
791 
792   if (!handle) goto cleanup;
793   if (handle->collected) goto cleanup;
794 
795   /* Otherwise a non-blocking waitpid to collect zombies */
796   pid = handle->pid;
797   do {
798     wp = waitpid(pid, &wstat, WNOHANG);
799   } while (wp == -1 && errno == EINTR);
800 
801   /* Maybe another SIGCHLD handler collected the exit status?
802      Then we just set it to NA (in the collect_exit_status call) */
803   if (wp == -1 && errno == ECHILD) {
804     processx__collect_exit_status(status, wp, wstat);
805     goto cleanup;
806   }
807 
808   /* Some other error? */
809   if (wp == -1) {
810     processx__unblock_sigchld();
811     R_THROW_SYSTEM_ERROR("processx_is_alive, process '%s'", cname);
812   }
813 
814   /* If running, return TRUE, otherwise collect exit status, return FALSE */
815   if (wp == 0) {
816     ret = 1;
817   } else {
818     processx__collect_exit_status(status, wp, wstat);
819   }
820 
821  cleanup:
822   processx__unblock_sigchld();
823   return ScalarLogical(ret);
824 }
825 
826 /* This is essentially the same as `processx_is_alive`, but we return an
827  * exit status if the process has already finished. See above.
828  */
829 
processx_get_exit_status(SEXP status,SEXP name)830 SEXP processx_get_exit_status(SEXP status, SEXP name) {
831   processx_handle_t *handle = R_ExternalPtrAddr(status);
832   const char *cname = isNull(name) ? "???" : CHAR(STRING_ELT(name, 0));
833   pid_t pid;
834   int wstat, wp;
835   SEXP result;
836 
837   processx__block_sigchld();
838 
839   if (!handle) {
840     result = PROTECT(ScalarInteger(NA_INTEGER));
841     goto cleanup;
842   }
843 
844   /* If we already have the status, then just return */
845   if (handle->collected) {
846     result = PROTECT(ScalarInteger(handle->exitcode));
847     goto cleanup;
848   }
849 
850   /* Otherwise do a non-blocking waitpid to collect zombies */
851   pid = handle->pid;
852   do {
853     wp = waitpid(pid, &wstat, WNOHANG);
854   } while (wp == -1 && errno == EINTR);
855 
856   /* Another SIGCHLD handler already collected the exit code?
857      Then we set it to NA (in the collect_exit_status call). */
858   if (wp == -1 && errno == ECHILD) {
859     processx__collect_exit_status(status, wp, wstat);
860     result = PROTECT(ScalarInteger(handle->exitcode));
861     goto cleanup;
862   }
863 
864   /* Some other error? */
865   if (wp == -1) {
866     processx__unblock_sigchld();
867     R_THROW_SYSTEM_ERROR("processx_get_exit_status error for '%s'", cname);
868   }
869 
870   /* If running, do nothing otherwise collect */
871   if (wp == 0) {
872     result = PROTECT(R_NilValue);
873   } else {
874     processx__collect_exit_status(status, wp, wstat);
875     result = PROTECT(ScalarInteger(handle->exitcode));
876   }
877 
878  cleanup:
879   processx__unblock_sigchld();
880   UNPROTECT(1);
881   return result;
882 }
883 
884 /* See `processx_wait` above for the description of async processes and
885  * possible race conditions.
886  *
887  * This is mostly along the lines of `processx_is_alive`. After we
888  * successfully sent the signal, we try a `waitpid` just in case the
889  * processx has aborted on it. This is a harmless race condition, because
890  * the process might not have been cleaned up yet, when we call `waitpid`,
891  * but that's OK, then its exit status will be collected later, e.g. in
892  * the SIGCHLD handler.
893  */
894 
processx_signal(SEXP status,SEXP signal,SEXP name)895 SEXP processx_signal(SEXP status, SEXP signal, SEXP name) {
896   processx_handle_t *handle = R_ExternalPtrAddr(status);
897   const char *cname = isNull(name) ? "???" : CHAR(STRING_ELT(name, 0));
898   pid_t pid;
899   int wstat, wp, ret, result;
900 
901   processx__block_sigchld();
902 
903   if (!handle) {
904     result = 0;
905     goto cleanup;
906   }
907 
908   /* If we already have the status, then return `FALSE` */
909   if (handle->collected) {
910     result = 0;
911     goto cleanup;
912   }
913 
914   /* Otherwise try to send signal */
915   pid = handle->pid;
916   ret = kill(pid, INTEGER(signal)[0]);
917 
918   if (ret == 0) {
919     result = 1;
920   } else if (ret == -1 && errno == ESRCH) {
921     result = 0;
922   } else {
923     processx__unblock_sigchld();
924     R_THROW_SYSTEM_ERROR("processx_signal for '%s'", cname);
925     return R_NilValue;
926   }
927 
928   /* Possibly dead now, collect status */
929   do {
930     wp = waitpid(pid, &wstat, WNOHANG);
931   } while (wp == -1 && errno == EINTR);
932 
933   /* Maybe another SIGCHLD handler collected it already? */
934   if (wp == -1 && errno == ECHILD) {
935     processx__collect_exit_status(status, wp, wstat);
936     goto cleanup;
937   }
938 
939   if (wp == -1) {
940     processx__unblock_sigchld();
941     R_THROW_SYSTEM_ERROR("processx_signal for '%s'", cname);
942   }
943 
944  cleanup:
945   processx__unblock_sigchld();
946   return ScalarLogical(result);
947 }
948 
processx_interrupt(SEXP status,SEXP name)949 SEXP processx_interrupt(SEXP status, SEXP name) {
950   return processx_signal(status, ScalarInteger(2), name);
951 }
952 
953 /* This is a special case of `processx_signal`, and we implement it almost
954  * the same way. We make an effort to return a TRUE/FALSE value to indicate
955  * if the process died as a response to our KILL signal. This is not 100%
956  * accurate because of the unavoidable race conditions. (E.g. it might have
957  * been killed by another process's KILL signal.)
958  *
959  * To do a better job for the return value, we call a `waitpid` before
960  * delivering the signal, as a final check to see if the child process is
961  * still alive or not.
962  */
963 
processx_kill(SEXP status,SEXP grace,SEXP name)964 SEXP processx_kill(SEXP status, SEXP grace, SEXP name) {
965   processx_handle_t *handle = R_ExternalPtrAddr(status);
966   const char *cname = isNull(name) ? "???" : CHAR(STRING_ELT(name, 0));
967   pid_t pid;
968   int wstat, wp, result = 0;
969 
970   processx__block_sigchld();
971 
972   if (!handle) { goto cleanup; }
973 
974   /* Check if we have an exit status, it yes, just return (FALSE) */
975   if (handle->collected) { goto cleanup; }
976 
977   /* Do a non-blocking waitpid to collect zombies */
978   pid = handle->pid;
979   do {
980     wp = waitpid(pid, &wstat, WNOHANG);
981   } while (wp == -1 && errno == EINTR);
982 
983   /* The child does not exist any more, set exit status to NA &
984      return FALSE. */
985   if (wp == -1 && errno == ECHILD) {
986     processx__collect_exit_status(status, wp, wstat);
987     goto cleanup;
988   }
989 
990   /* Some other error? */
991   if (wp == -1) {
992     processx__unblock_sigchld();
993     R_THROW_SYSTEM_ERROR("processx_kill for '%s'", cname);
994   }
995 
996   /* If the process is not running, return (FALSE) */
997   if (wp != 0) { goto cleanup; }
998 
999   /* It is still running, so a SIGKILL */
1000   int ret = kill(-pid, SIGKILL);
1001   if (ret == -1 && (errno == ESRCH || errno == EPERM)) { goto cleanup; }
1002   if (ret == -1) {
1003     processx__unblock_sigchld();
1004     R_THROW_SYSTEM_ERROR("process_kill for '%s'", cname);
1005   }
1006 
1007   /* Do a waitpid to collect the status and reap the zombie */
1008   do {
1009     wp = waitpid(pid, &wstat, 0);
1010   } while (wp == -1 && errno == EINTR);
1011 
1012   /* Collect exit status, and check if it was killed by a SIGKILL
1013      If yes, this was most probably us (although we cannot be sure in
1014      general...
1015      If the status was collected by another SIGCHLD, then the exit
1016      status will be set to NA */
1017   processx__collect_exit_status(status, wp, wstat);
1018   result = handle->exitcode == - SIGKILL;
1019 
1020  cleanup:
1021   processx__unblock_sigchld();
1022   return ScalarLogical(result);
1023 }
1024 
processx_get_pid(SEXP status)1025 SEXP processx_get_pid(SEXP status) {
1026   processx_handle_t *handle = R_ExternalPtrAddr(status);
1027 
1028   /* This might happen if it was finalized at the end of the session,
1029      even though there are some references to the R object. */
1030   if (!handle) return ScalarInteger(NA_INTEGER);
1031 
1032   return ScalarInteger(handle->pid);
1033 }
1034 
1035 /* We send a 0 signal to check if the process is alive. Note that a process
1036  * that is in a zombie state also counts as 'alive' with this method.
1037 */
1038 
processx__process_exists(SEXP pid)1039 SEXP processx__process_exists(SEXP pid) {
1040   pid_t cpid = INTEGER(pid)[0];
1041   int res = kill(cpid, 0);
1042   if (res == 0) {
1043     return ScalarLogical(1);
1044   } else if (errno == ESRCH) {
1045     return ScalarLogical(0);
1046   } else {
1047     R_THROW_SYSTEM_ERROR("kill syscall error for pid '%d'", cpid);
1048     return R_NilValue;
1049   }
1050 }
1051 
1052 #endif
1053