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