/src/r-source/src/unix/sys-unix.c
Line | Count | Source |
1 | | /* |
2 | | * R : A Computer Language for Statistical Data Analysis |
3 | | * Copyright (C) 1997--2024 The R Core Team |
4 | | * Copyright (C) 1995, 1996 Robert Gentleman and Ross Ihaka |
5 | | * |
6 | | * This program is free software; you can redistribute it and/or modify |
7 | | * it under the terms of the GNU General Public License as published by |
8 | | * the Free Software Foundation; either version 2 of the License, or |
9 | | * (at your option) any later version. |
10 | | * |
11 | | * This program is distributed in the hope that it will be useful, |
12 | | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
13 | | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
14 | | * GNU General Public License for more details. |
15 | | * |
16 | | * You should have received a copy of the GNU General Public License |
17 | | * along with this program; if not, a copy is available at |
18 | | * https://www.R-project.org/Licenses/ |
19 | | */ |
20 | | |
21 | | /* <UTF8> |
22 | | char here is mainly handled as a whole string. |
23 | | Does handle file names. |
24 | | Chopping final \n is OK in UTF-8. |
25 | | */ |
26 | | |
27 | | |
28 | | /* See system.txt for a description of functions */ |
29 | | |
30 | | #ifdef HAVE_CONFIG_H |
31 | | # include <config.h> |
32 | | #endif |
33 | | |
34 | | #define R_USE_SIGNALS 1 |
35 | | #include <Defn.h> |
36 | | #include <Internal.h> |
37 | | #include <Fileio.h> |
38 | | #include <Rmath.h> /* for fround */ |
39 | | #include "Runix.h" |
40 | | |
41 | | #ifdef HAVE_UNISTD_H |
42 | | # include <unistd.h> |
43 | | #endif |
44 | | |
45 | | #ifndef HAVE_GETRUSAGE |
46 | | # ifdef HAVE_SYS_TIME_H |
47 | | # include <sys/times.h> |
48 | | # endif |
49 | | #endif |
50 | | |
51 | | #ifdef HAVE_FCNTL_H |
52 | | # include <fcntl.h> |
53 | | #endif |
54 | | |
55 | | #if defined(HAVE_SYS_RESOURCE_H) && defined(HAVE_GETRUSAGE) |
56 | | /* on macOS it seems sys/resource.h needs sys/time.h first */ |
57 | | # include <sys/time.h> |
58 | | # include <sys/resource.h> |
59 | | #endif |
60 | | |
61 | | #include <errno.h> |
62 | | |
63 | | /* |
64 | | * 4) INITIALIZATION AND TERMINATION ACTIONS |
65 | | */ |
66 | | |
67 | | attribute_hidden |
68 | | FILE *R_OpenInitFile(void) |
69 | 12 | { |
70 | 12 | char buf[R_PATH_MAX], *home, *p = getenv("R_PROFILE_USER"); |
71 | 12 | FILE *fp; |
72 | | |
73 | 12 | fp = NULL; |
74 | 12 | if (LoadInitFile) { |
75 | 0 | if(p) { |
76 | 0 | if(!*p) return NULL; /* set to "" */ |
77 | 0 | return R_fopen(R_ExpandFileName(p), "r"); |
78 | 0 | } |
79 | 0 | if((fp = R_fopen(".Rprofile", "r"))) |
80 | 0 | return fp; |
81 | 0 | if((home = getenv("HOME")) == NULL) |
82 | 0 | return NULL; |
83 | 0 | snprintf(buf, R_PATH_MAX, "%s/.Rprofile", home); |
84 | 0 | if((fp = R_fopen(buf, "r"))) |
85 | 0 | return fp; |
86 | 0 | } |
87 | 12 | return fp; |
88 | 12 | } |
89 | | /* |
90 | | * R_CleanUp is interface-specific |
91 | | */ |
92 | | |
93 | | /* |
94 | | * 5) FILESYSTEM INTERACTION |
95 | | */ |
96 | | |
97 | | |
98 | | /* |
99 | | * R_ShowFiles is interface-specific |
100 | | */ |
101 | | |
102 | | /* |
103 | | * R_ChooseFile is interface-specific |
104 | | */ |
105 | | |
106 | | #if defined(HAVE_LIBREADLINE) && defined(HAVE_TILDE_EXPAND_WORD) |
107 | | char *R_ExpandFileName_readline(const char *s, char *buff); /* sys-std.c */ |
108 | | #endif |
109 | | |
110 | | #if defined(HAVE_PWD_H) |
111 | | # include <pwd.h> |
112 | | #endif |
113 | | |
114 | | static const char *R_ExpandFileName_unix(const char *s, char *buff) |
115 | 0 | { |
116 | 0 | if(s[0] != '~') return s; |
117 | | |
118 | 0 | const char *user, *temp, *s2, *home; |
119 | 0 | char buff2[R_PATH_MAX]; |
120 | 0 | struct passwd *pass; |
121 | |
|
122 | 0 | temp = strchr(s + 1, '/'); |
123 | 0 | if (temp == NULL) { // ~name |
124 | 0 | user = s + 1; |
125 | 0 | } else { // ~name/path |
126 | | /* extract text befoe first slash */ |
127 | 0 | size_t len = (size_t)(temp - s + 1); |
128 | 0 | (void) strncpy(buff2, s + 1, len - 2); |
129 | 0 | buff2[len - 2] = '\0'; |
130 | 0 | user = buff2; |
131 | 0 | s2 = s + len; |
132 | 0 | } |
133 | 0 | if (user[0] == 0) { |
134 | | // follow readline (and not libedit) in preferring HOME |
135 | 0 | home = getenv("HOME"); |
136 | 0 | #if defined(HAVE_GETPWUID) && defined(HAVE_GETUID) |
137 | 0 | if(home == NULL || streql(home, "")) { |
138 | 0 | pass = getpwuid(getuid()); |
139 | 0 | if(pass == NULL) return s; |
140 | 0 | home = pass->pw_dir; |
141 | 0 | } |
142 | 0 | #endif |
143 | 0 | if(home == NULL) return s; |
144 | 0 | } else { |
145 | 0 | #ifdef HAVE_GETPWNAM |
146 | 0 | pass = getpwnam(user); |
147 | 0 | if(pass == NULL) return s; |
148 | 0 | home = pass->pw_dir; |
149 | | #else |
150 | | return s; |
151 | | #endif |
152 | 0 | } |
153 | | |
154 | 0 | if (temp == NULL) { // ~name |
155 | 0 | strcpy(buff, home); |
156 | 0 | } else { // ~name/path |
157 | | // ask snprintf to compute the length, as GCC 12 complains otherwise. |
158 | 0 | size_t len = snprintf(NULL, 0, "%s/%s", home, s2); |
159 | | // buff is passed from R_ExpandFileName, uses static array of |
160 | | // size R_PATH_MAX. |
161 | 0 | if (len >= R_PATH_MAX) { |
162 | 0 | warning(_("expanded path length %lld would be too long for\n%s\n"), |
163 | 0 | (long long)len, s); |
164 | 0 | return s; |
165 | 0 | } |
166 | 0 | (void)snprintf(buff, len + 1, "%s/%s", home, s2); |
167 | 0 | } |
168 | | |
169 | 0 | return buff; |
170 | 0 | } |
171 | | |
172 | | /* tilde_expand_word (in libreadline) mallocs storage for its return value. |
173 | | The R entry point does not require that storage to be freed, so we |
174 | | copy the value to a static buffer, to void a memory leak in R<=1.6.0. |
175 | | |
176 | | This is not thread-safe, but as R_ExpandFileName is a public entry |
177 | | point (in R-exts.texi) it would need to deprecated and replaced by a |
178 | | version which takes a buffer as an argument. |
179 | | |
180 | | BDR 10/2002 |
181 | | */ |
182 | | |
183 | | extern Rboolean UsingReadline; |
184 | | static char newFileName[R_PATH_MAX]; |
185 | | |
186 | | const char *R_ExpandFileName(const char *s) |
187 | 17.4k | { |
188 | 17.4k | #if defined(HAVE_LIBREADLINE) && defined(HAVE_TILDE_EXPAND_WORD) |
189 | 17.4k | if(UsingReadline) { |
190 | 17.4k | const char * c = R_ExpandFileName_readline(s, newFileName); |
191 | | /* we can return the result only if tilde_expand is not broken */ |
192 | 17.4k | if (!c || c[0]!='~' || (c[1]!='\0' && c[1]!='/')) |
193 | 17.4k | return c; |
194 | 17.4k | } |
195 | 0 | #endif |
196 | 0 | return R_ExpandFileName_unix(s, newFileName); |
197 | 17.4k | } |
198 | | |
199 | | |
200 | | /* |
201 | | * 7) PLATFORM DEPENDENT FUNCTIONS |
202 | | */ |
203 | | |
204 | | attribute_hidden SEXP do_machine(SEXP call, SEXP op, SEXP args, SEXP env) |
205 | 0 | { |
206 | 0 | checkArity(op, args); |
207 | 0 | return mkString("Unix"); |
208 | 0 | } |
209 | | |
210 | | # ifdef HAVE_SYS_TIMES_H |
211 | | # include <sys/times.h> /* times */ |
212 | | # endif |
213 | | |
214 | | static double clk_tck, StartTime; |
215 | | |
216 | | void R_setStartTime(void) |
217 | 12 | { |
218 | 12 | #ifdef HAVE_SYSCONF |
219 | 12 | clk_tck = (double) sysconf(_SC_CLK_TCK); |
220 | | #else |
221 | | # ifndef CLK_TCK |
222 | | /* this is in ticks/second, generally 60 on BSD style Unix, 100? on SysV |
223 | | */ |
224 | | # ifdef HZ |
225 | | # define CLK_TCK HZ |
226 | | # else |
227 | | # define CLK_TCK 60 |
228 | | # endif |
229 | | # endif /* not CLK_TCK */ |
230 | | clk_tck = (double) CLK_TCK; |
231 | | #endif |
232 | | /* printf("CLK_TCK = %d\n", CLK_TCK); */ |
233 | 12 | StartTime = currentTime(); |
234 | 12 | } |
235 | | |
236 | | /* NOTE |
237 | | This used to use times() for elapsed times, which is measured in |
238 | | clock ticks (which can overflow). It is possible this version uses |
239 | | time() and so is in seconds. But even Cygwin has gettimeofday. |
240 | | */ |
241 | | attribute_hidden |
242 | | void R_getProcTime(double *data) |
243 | 624 | { |
244 | | /* docs say this is rounded to the nearest ms */ |
245 | 624 | double et = currentTime() - StartTime; |
246 | 624 | data[2] = 1e-3 * rint(1000*et); |
247 | 624 | #ifdef HAVE_GETRUSAGE |
248 | | /* all known current OSes */ |
249 | 624 | struct rusage self, children; |
250 | 624 | getrusage(RUSAGE_SELF, &self); |
251 | 624 | getrusage(RUSAGE_CHILDREN, &children); |
252 | 624 | data[0] = (double) self.ru_utime.tv_sec + 1e-3 * (double)( self.ru_utime.tv_usec/1000); |
253 | 624 | data[1] = (double) self.ru_stime.tv_sec + 1e-3 * (double)( self.ru_stime.tv_usec/1000); |
254 | 624 | data[3] = (double) children.ru_utime.tv_sec + 1e-3 * (double)(children.ru_utime.tv_usec/1000); |
255 | 624 | data[4] = (double) children.ru_stime.tv_sec + 1e-3 * (double)(children.ru_stime.tv_usec/1000); |
256 | | #else |
257 | | /* Not known to be currently used */ |
258 | | struct tms timeinfo; |
259 | | times(&timeinfo); |
260 | | data[0] = fround(timeinfo.tms_utime / clk_tck, 3); |
261 | | data[1] = fround(timeinfo.tms_stime / clk_tck, 3); |
262 | | data[3] = fround(timeinfo.tms_cutime / clk_tck, 3); |
263 | | data[4] = fround(timeinfo.tms_cstime / clk_tck, 3); |
264 | | #endif |
265 | 624 | } |
266 | | |
267 | | /* used in memory.c */ |
268 | | /* FIXME: maybe should try to find the increment for getrusage */ |
269 | | attribute_hidden |
270 | | double R_getClockIncrement(void) |
271 | 0 | { |
272 | 0 | return 1.0 / clk_tck; |
273 | 0 | } |
274 | | |
275 | | |
276 | | #ifdef HAVE_SYS_WAIT_H |
277 | | # include <sys/wait.h> |
278 | | #endif |
279 | | |
280 | | /* The timeout support is inspired by timeout utility from coreutils. |
281 | | However, here the child process creates a new process group rather than |
282 | | the parent (R) process, because changing the group leader for the whole |
283 | | of R might have undesirable consequences. According to comments in |
284 | | coreutils, this could lead to issues with propagating signals between |
285 | | foreground and background process groups. Like with coreutils, the |
286 | | timeout is not always enforced: an external application can run longer |
287 | | than the timeout when it creates a new process group or when it spawns a |
288 | | child process and exits without waiting for it to finish (becomes a |
289 | | daemon). This implementation only works for processes that do not read |
290 | | from the standard input - the new process group is always created, and |
291 | | hence the executed process can no longer access the terminal. To prevent |
292 | | interference with job control, the new process is thus started with |
293 | | standard input redirected from /dev/null. Note that while the timeout |
294 | | utility allows to run processes also without creating the new group |
295 | | (option `foreground`), that approach would interfere with job control in |
296 | | "/bin/sh" that is documented to be used by the R system call. There does |
297 | | not seem to be a simple way to address this issue, and hence interactive |
298 | | applications cannot be executed with timeout (and note the same issues |
299 | | arise when timeout utility is used with /bin/sh). |
300 | | |
301 | | Currently we only have a single global structure and hence only one call |
302 | | to R_popen_timeout/R_system_timeout may be active at the same time. A more |
303 | | general implementation could use a linked list and identify entries by |
304 | | file pointer and child pid. |
305 | | |
306 | | Timeouts with background jobs (ending with &) are not supported. |
307 | | |
308 | | This code can also be used without an actual timeout (have_timeout == 0) |
309 | | as a partial implementation of system/popen/pclose which uses process |
310 | | groups, but it differs in signal handling and termination. |
311 | | */ |
312 | | |
313 | 0 | #define KILL_SIGNAL1 SIGINT |
314 | | #define KILL_SIGNAL2 SIGTERM |
315 | | #define KILL_SIGNAL3 SIGKILL |
316 | 0 | #define EMERGENCY_TIMEOUT 20 |
317 | | |
318 | | /* The child processes are sent KILL_SIGNAL1 after the specified timeout. |
319 | | As a backup, KILL_SIGNAL2 would be sent after additional EMERGENCY_TIMEOUT |
320 | | seconds. As a backup of the backup, KILL_SIGNAL3 would be sent after yet |
321 | | additional EMERGENCY_TIMEOUT seconds. |
322 | | |
323 | | SIGINT is used first because it seems to be handled better by applications: |
324 | | applications happen to wait for child processes to terminate, and hence |
325 | | their execution is included into getrusage/RUSAGE_CHILDREN (proc.time). |
326 | | As follows from empirical observations, SIGTERM can sometimes terminate |
327 | | applications that cannot be terminated by SIGINT. */ |
328 | | |
329 | | static int kill_signals[] = { KILL_SIGNAL1, KILL_SIGNAL2, KILL_SIGNAL3 }; |
330 | | static struct { |
331 | | pid_t child_pid; |
332 | | int timedout; /* set when the child has been timed out */ |
333 | | int kill_attempts; /* 1 after sending KILL_SIGNAL1, etc */ |
334 | | sigset_t oldset; |
335 | | struct sigaction oldalrm, oldint, oldquit, oldhup, oldterm, oldttin, |
336 | | oldttou, oldcont, oldtstp, oldchld; |
337 | | RCNTXT cntxt; /* for popen/pclose */ |
338 | | FILE *fp; /* for popen/pclose, sanity check */ |
339 | | int have_alarm; /* 0 when not really having a timeout */ |
340 | | } tost; |
341 | | |
342 | | static void timeout_handler(int sig); |
343 | | static void timeout_init(int have_alarm) |
344 | 0 | { |
345 | 0 | tost.child_pid = 0; |
346 | 0 | tost.timedout = 0; |
347 | 0 | tost.kill_attempts = 0; |
348 | 0 | sigprocmask(0, NULL, &tost.oldset); |
349 | 0 | tost.have_alarm = have_alarm; |
350 | 0 | if (tost.have_alarm) |
351 | 0 | sigaction(SIGALRM, NULL, &tost.oldalrm); |
352 | 0 | sigaction(SIGINT, NULL, &tost.oldint); |
353 | 0 | sigaction(SIGQUIT, NULL, &tost.oldquit); |
354 | 0 | sigaction(SIGHUP, NULL, &tost.oldhup); |
355 | 0 | sigaction(SIGTERM, NULL, &tost.oldterm); |
356 | 0 | sigaction(SIGTTIN, NULL, &tost.oldttin); |
357 | 0 | sigaction(SIGTTOU, NULL, &tost.oldttou); |
358 | 0 | sigaction(SIGCONT, NULL, &tost.oldcont); |
359 | 0 | sigaction(SIGTSTP, NULL, &tost.oldtstp); |
360 | 0 | sigaction(SIGCHLD, NULL, &tost.oldchld); |
361 | 0 | tost.fp = NULL; |
362 | | |
363 | | /* install handler */ |
364 | 0 | struct sigaction sa; |
365 | 0 | sigemptyset(&sa.sa_mask); |
366 | 0 | sa.sa_handler = &timeout_handler; |
367 | 0 | sa.sa_flags = SA_RESTART; |
368 | 0 | if (tost.have_alarm) |
369 | 0 | sigaction(SIGALRM, &sa, NULL); |
370 | 0 | sigaction(SIGINT, &sa, NULL); |
371 | 0 | sigaction(SIGQUIT, &sa, NULL); |
372 | 0 | sigaction(SIGHUP, &sa, NULL); |
373 | 0 | sigaction(SIGCONT, &sa, NULL); |
374 | 0 | sigaction(SIGTSTP, &sa, NULL); |
375 | 0 | sigaction(SIGTERM, &sa, NULL); |
376 | 0 | sigaction(SIGCHLD, &sa, NULL); |
377 | 0 | } |
378 | | |
379 | | static void timeout_cleanup_set(sigset_t *ss) |
380 | 0 | { |
381 | 0 | sigemptyset(ss); |
382 | 0 | if (tost.have_alarm) |
383 | 0 | sigaddset(ss, SIGALRM); |
384 | 0 | sigaddset(ss, SIGINT); |
385 | 0 | sigaddset(ss, SIGQUIT); |
386 | 0 | sigaddset(ss, SIGHUP); |
387 | 0 | sigaddset(ss, SIGTERM); |
388 | 0 | sigaddset(ss, SIGTTIN); |
389 | 0 | sigaddset(ss, SIGTTOU); |
390 | 0 | sigaddset(ss, SIGCONT); |
391 | 0 | sigaddset(ss, SIGTSTP); |
392 | 0 | sigaddset(ss, SIGCHLD); |
393 | 0 | } |
394 | | |
395 | | static void timeout_cleanup(void) |
396 | 0 | { |
397 | 0 | sigset_t ss; |
398 | 0 | timeout_cleanup_set(&ss); |
399 | 0 | sigprocmask(SIG_BLOCK, &ss, NULL); |
400 | 0 | if (tost.have_alarm) { |
401 | 0 | alarm(0); /* clear alarm */ |
402 | 0 | sigaction(SIGALRM, &tost.oldalrm, NULL); |
403 | 0 | } |
404 | 0 | sigaction(SIGINT, &tost.oldint, NULL); |
405 | 0 | sigaction(SIGQUIT, &tost.oldquit, NULL); |
406 | 0 | sigaction(SIGHUP, &tost.oldhup, NULL); |
407 | 0 | sigaction(SIGTERM, &tost.oldterm, NULL); |
408 | 0 | sigaction(SIGTTIN, &tost.oldttin, NULL); |
409 | 0 | sigaction(SIGTTOU, &tost.oldttou, NULL); |
410 | 0 | sigaction(SIGCONT, &tost.oldcont, NULL); |
411 | 0 | sigaction(SIGTSTP, &tost.oldtstp, NULL); |
412 | 0 | sigaction(SIGCHLD, &tost.oldchld, NULL); |
413 | |
|
414 | 0 | sigprocmask(SIG_SETMASK, &tost.oldset, NULL); |
415 | 0 | } |
416 | | |
417 | | static void timeout_handler(int sig) |
418 | 0 | { |
419 | 0 | if (sig == SIGCHLD) |
420 | 0 | return; /* needed for sigsuspend() to be interrupted */ |
421 | 0 | if (tost.child_pid > 0 && sig == SIGALRM && tost.have_alarm) { |
422 | 0 | tost.timedout = 1; |
423 | 0 | if (tost.kill_attempts < 3) { |
424 | 0 | sig = kill_signals[tost.kill_attempts]; |
425 | 0 | if (tost.kill_attempts < 2) { |
426 | 0 | int saveerrno = errno; |
427 | 0 | alarm(EMERGENCY_TIMEOUT); |
428 | 0 | errno = saveerrno; |
429 | 0 | } |
430 | 0 | tost.kill_attempts++; |
431 | 0 | } else |
432 | 0 | sig = KILL_SIGNAL1; /* should not happen */ |
433 | 0 | } |
434 | 0 | if (tost.child_pid > 0) { |
435 | | /* parent, received a signal */ |
436 | 0 | if (sig == SIGCONT) { |
437 | | /* restore our SIGTSTP handler */ |
438 | 0 | struct sigaction sa; |
439 | 0 | sigemptyset(&sa.sa_mask); |
440 | 0 | sa.sa_handler = &timeout_handler; |
441 | 0 | sa.sa_flags = SA_RESTART; |
442 | 0 | sigaction(SIGTSTP, &sa, NULL); |
443 | 0 | } |
444 | 0 | kill(tost.child_pid, sig); |
445 | 0 | int saveerrno = errno; |
446 | | /* on macOS, killpg fails with EPERM for groups with zombies */ |
447 | 0 | killpg(tost.child_pid, sig); |
448 | 0 | errno = saveerrno; |
449 | | /* NOTE: don't signal the group and don't send SIGCONT |
450 | | for interactive jobs */ |
451 | 0 | if (sig != SIGKILL && sig != SIGCONT && sig != SIGTSTP) { |
452 | 0 | kill(tost.child_pid, SIGCONT); |
453 | 0 | saveerrno = errno; |
454 | | /* on macOS, killpg fails with EPERM for groups with zombies */ |
455 | 0 | killpg(tost.child_pid, SIGCONT); |
456 | 0 | errno = saveerrno; |
457 | 0 | } |
458 | 0 | if (sig == SIGTSTP) { |
459 | | /* restore and invoke the original SIGTSTP handler */ |
460 | 0 | sigaction(SIGTSTP, &tost.oldtstp, NULL); |
461 | 0 | raise(SIGTSTP); |
462 | 0 | } |
463 | 0 | } else if (tost.child_pid == 0) { |
464 | | /* child */ |
465 | 0 | _exit(128 + sig); /* arbitrary status, such as in timeout utility */ |
466 | 0 | } |
467 | | /* tost.child_pid is -1 when child process no longer exists */ |
468 | 0 | } |
469 | | |
470 | | static pid_t timeout_wait(int *wstatus) |
471 | 0 | { |
472 | 0 | pid_t wres; |
473 | | |
474 | | /* make sure we do not accidentally send signals to a new process |
475 | | with re-used pid from the child */ |
476 | 0 | sigset_t ss; |
477 | 0 | timeout_cleanup_set(&ss); |
478 | 0 | sigset_t unblocked_ss; |
479 | 0 | sigprocmask(SIG_BLOCK, &ss, &unblocked_ss); |
480 | |
|
481 | 0 | int saveerrno = errno; |
482 | 0 | while((wres = waitpid(tost.child_pid, wstatus, WNOHANG)) == 0) |
483 | 0 | sigsuspend(&unblocked_ss); |
484 | |
|
485 | 0 | if (errno == EINTR) |
486 | | /* EINTR is not really an error but expected situation here, however, |
487 | | R's "system" call would report any non-zero errno as an error. */ |
488 | 0 | errno = saveerrno; |
489 | 0 | if (wres == tost.child_pid) |
490 | 0 | tost.child_pid = -1; /* the process no longer exists */ |
491 | 0 | timeout_cleanup(); |
492 | 0 | return wres; |
493 | 0 | } |
494 | | |
495 | | static void timeout_cend(void *data) |
496 | 0 | { |
497 | 0 | if (tost.child_pid > 0) { |
498 | 0 | timeout_handler(tost.have_alarm ? SIGALRM : SIGQUIT); |
499 | 0 | timeout_wait(NULL); |
500 | 0 | } |
501 | 0 | timeout_cleanup(); |
502 | 0 | } |
503 | | |
504 | | /* Fork with blocked SIGCHLD to make sure that tost.child_pid is set |
505 | | in the parent before the signal is received. Also makes sure |
506 | | SIGCHLD is unblocked in the parent after the call. */ |
507 | | static void timeout_fork(void) |
508 | 0 | { |
509 | 0 | sigset_t css; |
510 | 0 | sigemptyset(&css); |
511 | 0 | sigaddset(&css, SIGCHLD); |
512 | 0 | sigprocmask(SIG_BLOCK, &css, NULL); |
513 | 0 | tost.child_pid = fork(); |
514 | 0 | sigprocmask(SIG_UNBLOCK, &css, NULL); |
515 | 0 | } |
516 | | |
517 | | /* R_popen_timeout, R_pclose_timeout - a partial implementation of popen/close |
518 | | with support for timeout. The POSIX/Unix popen/pclose cannot be re-used, |
519 | | because the PID of the child process is not accessible via POSIX API. |
520 | | |
521 | | This simple implementation only supports a single pipe to be open at a time |
522 | | and R_system_timeout cannot be used at the same time. It installs signal |
523 | | handlers which exist between R_popen_timeout and R_pclose timeout, therefore |
524 | | the amount of code that can correctly run in between is limited - this is |
525 | | intended only for implementing system(,intern=TRUE). |
526 | | |
527 | | It does not support close-on-exec ("e" flag). |
528 | | A pipe opened with R_popen_timeout cannot be closed by pclose. |
529 | | A pipe opened with popen cannot be closed by R_pclose_timeout. |
530 | | Timeout is in seconds. After timing out, the child process is interrupted. |
531 | | */ |
532 | | static FILE *R_popen_timeout(const char *cmd, const char *type, int timeout) |
533 | 0 | { |
534 | | /* close-on-exec is not supported */ |
535 | 0 | if (!type || type[1] || (type[0] != 'r' && type[0] != 'w')) { |
536 | 0 | errno = EINVAL; |
537 | 0 | return NULL; |
538 | 0 | } |
539 | 0 | int doread = (type[0] == 'r'); |
540 | 0 | int pipefd[2]; |
541 | 0 | int parent_end, child_end; |
542 | 0 | if (pipe(pipefd) < 0) |
543 | 0 | return NULL; |
544 | 0 | if (doread) { |
545 | 0 | parent_end = pipefd[0]; |
546 | 0 | child_end = pipefd[1]; |
547 | 0 | } else { |
548 | 0 | parent_end = pipefd[1]; |
549 | 0 | child_end = pipefd[0]; |
550 | 0 | } |
551 | | |
552 | | /* Earlier version of R would block SIGPROF here on old Apple systems |
553 | | following Luke's recommendation on how to fix PR#1140 (see R_open, |
554 | | R_system). */ |
555 | |
|
556 | 0 | timeout_init(timeout > 0); |
557 | | |
558 | | /* set up a context to recover from R error between popen and pclose */ |
559 | 0 | begincontext(&tost.cntxt, CTXT_CCODE, R_NilValue, R_BaseEnv, R_BaseEnv, |
560 | 0 | R_NilValue, R_NilValue); |
561 | 0 | tost.cntxt.cenddata = NULL; |
562 | 0 | tost.cntxt.cend = &timeout_cend; |
563 | |
|
564 | 0 | signal(SIGTTIN, SIG_IGN); |
565 | 0 | signal(SIGTTOU, SIG_IGN); |
566 | 0 | timeout_fork(); |
567 | |
|
568 | 0 | if (tost.child_pid == 0) { |
569 | | /* child */ |
570 | 0 | setpgid(0, 0); /* NOTE: don't create new group in interactive jobs */ |
571 | 0 | signal(SIGTTIN, SIG_DFL); |
572 | 0 | signal(SIGTTOU, SIG_DFL); |
573 | 0 | dup2(child_end, doread ? 1 : 0); |
574 | 0 | close(child_end); |
575 | 0 | close(parent_end); |
576 | 0 | close(doread ? 0 : 1); |
577 | | /* ensure there is no read from terminal to avoid SIGTTIN */ |
578 | 0 | if (open("/dev/null", O_RDONLY) < 0) { |
579 | 0 | perror("Cannot open /dev/null for reading:"); |
580 | 0 | _exit(127); |
581 | 0 | } |
582 | 0 | execl("/bin/sh", "sh", "-c", cmd, (char *)NULL); |
583 | 0 | _exit(127); /* execl failed */ |
584 | 0 | } else if (tost.child_pid > 0) { |
585 | | /* parent */ |
586 | 0 | close(child_end); |
587 | 0 | tost.fp = fdopen(parent_end, type); |
588 | 0 | if (!tost.fp) { |
589 | 0 | close(parent_end); |
590 | 0 | return NULL; |
591 | 0 | } |
592 | 0 | if (tost.have_alarm) { |
593 | 0 | sigset_t ss; |
594 | 0 | sigemptyset(&ss); |
595 | 0 | sigaddset(&ss, SIGALRM); |
596 | 0 | sigprocmask(SIG_UNBLOCK, &ss, NULL); |
597 | 0 | alarm(timeout); /* will get SIGALRM on timeout */ |
598 | 0 | } |
599 | 0 | return tost.fp; |
600 | 0 | } else { |
601 | 0 | close(parent_end); |
602 | 0 | return NULL; |
603 | 0 | } |
604 | 0 | } |
605 | | |
606 | | static int R_pclose_timeout(FILE *fp) |
607 | 0 | { |
608 | 0 | if (fp != tost.fp) |
609 | | /* should not happen */ |
610 | 0 | error("Invalid file pointer in pclose"); |
611 | |
|
612 | 0 | int saveerrno = errno; |
613 | 0 | int res_fclose = fclose(fp); |
614 | 0 | if (!res_fclose) |
615 | | /* On Solaris, fclose sets errno to "Invalid seek" when the pipe is |
616 | | already closed (e.g. because of timeout). fclose would not |
617 | | return an error, but it would set errno and the non-zero errno |
618 | | would then be reported by R's "system" function. */ |
619 | 0 | errno = saveerrno; |
620 | |
|
621 | 0 | pid_t wres; |
622 | 0 | int wstatus; |
623 | |
|
624 | 0 | saveerrno = errno; |
625 | 0 | wres = timeout_wait(&wstatus); |
626 | 0 | endcontext(&tost.cntxt); |
627 | |
|
628 | 0 | if (wres < 0) |
629 | 0 | return -1; |
630 | 0 | if (res_fclose) { |
631 | | /* wait succeeded but fclose failed */ |
632 | 0 | errno = saveerrno; |
633 | 0 | return -1; |
634 | 0 | } |
635 | 0 | return wstatus; |
636 | 0 | } |
637 | | |
638 | | /* Similar to system, but supports timeout in seconds. |
639 | | Calls to R_system_timeout cannot be used when a pipe is open using |
640 | | R_popen_timeout. |
641 | | */ |
642 | | static int R_system_timeout(const char *cmd, int timeout) |
643 | 0 | { |
644 | 0 | if (!cmd) |
645 | 0 | return R_system(cmd); |
646 | | |
647 | | /* Earlier version of R would block SIGPROF here on old Apple systems |
648 | | following Luke's recommendation on how to fix PR#1140 (see R_open, |
649 | | R_system). */ |
650 | | |
651 | 0 | timeout_init(timeout > 0); |
652 | 0 | signal(SIGTTIN, SIG_IGN); |
653 | 0 | signal(SIGTTOU, SIG_IGN); |
654 | 0 | timeout_fork(); |
655 | |
|
656 | 0 | if (tost.child_pid == 0) { |
657 | | /* child */ |
658 | 0 | close(0); |
659 | | /* ensure there is no read from terminal to avoid SIGTTIN */ |
660 | 0 | if (open("/dev/null", O_RDONLY) < 0) { |
661 | 0 | perror("Cannot open /dev/null for reading:"); |
662 | 0 | _exit(127); |
663 | 0 | } |
664 | 0 | setpgid(0, 0); |
665 | 0 | signal(SIGTTIN, SIG_DFL); |
666 | 0 | signal(SIGTTOU, SIG_DFL); |
667 | |
|
668 | 0 | execl("/bin/sh", "sh", "-c", cmd, (char *)NULL); |
669 | 0 | _exit(127); /* execl failed */ |
670 | 0 | } else if (tost.child_pid > 0) { |
671 | | /* parent */ |
672 | 0 | if (tost.have_alarm) { |
673 | 0 | sigset_t ss; |
674 | 0 | sigemptyset(&ss); |
675 | 0 | sigaddset(&ss, SIGALRM); |
676 | 0 | sigprocmask(SIG_UNBLOCK, &ss, NULL); |
677 | 0 | alarm(timeout); /* will get SIGALRM on timeout */ |
678 | 0 | } |
679 | |
|
680 | 0 | int wstatus; |
681 | 0 | timeout_wait(&wstatus); |
682 | 0 | if (tost.child_pid != -1) |
683 | 0 | return -1; |
684 | 0 | #ifdef HAVE_SYS_WAIT_H |
685 | 0 | if (WIFEXITED(wstatus)) wstatus = WEXITSTATUS(wstatus); |
686 | | #else |
687 | | /* assume that this is shifted if a multiple of 256 */ |
688 | | if ((wstatus % 256) == 0) wstatus = wstatus/256; |
689 | | #endif |
690 | 0 | if (wstatus == -1) { |
691 | | /* this means that system() failed badly - it didn't |
692 | | even get to try to run the shell */ |
693 | 0 | warning(_("system call failed: %s"), strerror(errno)); |
694 | | /* R system() is documented to return 127 on failure, and a lot of |
695 | | code relies on that - it will misinterpret -1 as success */ |
696 | 0 | wstatus = 127; |
697 | 0 | } |
698 | 0 | return wstatus; |
699 | 0 | } else |
700 | 0 | return -1; |
701 | 0 | } |
702 | | |
703 | | /* R_popen_pg, R_pclose_pg are implementations of popen/pclose which run the |
704 | | background processes in a new process group, therefore guarding them from |
705 | | signals sent to the group R is in. The advantage is that Ctrl+C does not |
706 | | kill these processes. The disadvantage is that it is isolated also from |
707 | | other signals (SIGTSTP/SIGCONT, SIGHUP, SIGQUIT). However, the pipe can |
708 | | be expected to pause/terminate when the R's end keep quiet/is closed, so |
709 | | it is probably less of a problem than with R_system_timeout. |
710 | | |
711 | | Unlike R_popen_timeout/R_pclose_timeout, this does not install any signal |
712 | | handlers and multiple instances may be used at a time. One must use |
713 | | R_pclose_timeout on a pipe opened with R_popen_timeout. |
714 | | |
715 | | The implementation is not thread safe. */ |
716 | | |
717 | | typedef struct ppg_elt { |
718 | | FILE *fp; |
719 | | pid_t pid; |
720 | | struct ppg_elt *next; |
721 | | } ppg_t; |
722 | | |
723 | | static ppg_t *ppg = NULL; |
724 | | |
725 | | attribute_hidden FILE *R_popen_pg(const char *cmd, const char *type) |
726 | 0 | { |
727 | | /* close-on-exec is not supported */ |
728 | 0 | if (!type || type[1] || (type[0] != 'r' && type[0] != 'w')) { |
729 | 0 | errno = EINVAL; |
730 | 0 | return NULL; |
731 | 0 | } |
732 | | |
733 | 0 | ppg_t *nfo = malloc(sizeof(ppg_t)); |
734 | 0 | if (!nfo) { |
735 | 0 | errno = ENOMEM; |
736 | 0 | return NULL; |
737 | 0 | } |
738 | | |
739 | 0 | int doread = (type[0] == 'r'); |
740 | 0 | int pipefd[2]; |
741 | 0 | int parent_end, child_end; |
742 | 0 | if (pipe(pipefd) < 0) { |
743 | 0 | free(nfo); |
744 | 0 | return NULL; |
745 | 0 | } |
746 | 0 | if (doread) { |
747 | 0 | parent_end = pipefd[0]; |
748 | 0 | child_end = pipefd[1]; |
749 | 0 | } else { |
750 | 0 | parent_end = pipefd[1]; |
751 | 0 | child_end = pipefd[0]; |
752 | 0 | } |
753 | | |
754 | | /* Earlier version of R would block SIGPROF here on old Apple systems |
755 | | following Luke's recommendation on how to fix PR#1140 (see R_open, |
756 | | R_system). */ |
757 | |
|
758 | 0 | nfo->pid = fork(); |
759 | 0 | if (nfo->pid == 0) { |
760 | | /* child */ |
761 | 0 | setpgid(0, 0); |
762 | | /* close the parent ends of other pipes in the child, as required |
763 | | by POSIX */ |
764 | 0 | for(ppg_t *p = ppg; p != NULL; p = p->next) { |
765 | 0 | int fd = fileno(p->fp); |
766 | 0 | if (fd >= 0) |
767 | | /* do not use fclose to prevent sending FILE buffer content |
768 | | multiple times */ |
769 | 0 | close(fd); |
770 | 0 | } |
771 | 0 | dup2(child_end, doread ? 1 : 0); |
772 | 0 | close(child_end); |
773 | 0 | close(parent_end); |
774 | 0 | if (doread) { |
775 | | /* ensure there is no read from terminal to avoid SIGTTIN */ |
776 | 0 | close(0); |
777 | 0 | if (open("/dev/null", O_RDONLY) < 0) { |
778 | 0 | perror("Cannot open /dev/null for reading:"); |
779 | 0 | _exit(127); |
780 | 0 | } |
781 | 0 | } |
782 | | /* allow standard output with !doread, because originally R's pipe() |
783 | | allowed it via C popen(), but it would cause SIGTTOU with tostop */ |
784 | 0 | execl("/bin/sh", "sh", "-c", cmd, (char *)NULL); |
785 | 0 | _exit(127); /* execl failed */ |
786 | 0 | } else if (nfo->pid > 0) { |
787 | | /* parent */ |
788 | 0 | close(child_end); |
789 | 0 | nfo->fp = fdopen(parent_end, type); |
790 | 0 | if (!nfo->fp) { |
791 | 0 | close(parent_end); |
792 | 0 | free(nfo); |
793 | 0 | return NULL; |
794 | 0 | } |
795 | 0 | nfo->next = ppg; |
796 | 0 | ppg = nfo; |
797 | 0 | return nfo->fp; |
798 | 0 | } else { |
799 | 0 | free(nfo); |
800 | 0 | close(parent_end); |
801 | 0 | return NULL; |
802 | 0 | } |
803 | 0 | } |
804 | | |
805 | | attribute_hidden int R_pclose_pg(FILE *fp) |
806 | 0 | { |
807 | 0 | ppg_t *prev = NULL; |
808 | 0 | for (ppg_t *p = ppg; p != NULL; p = p->next) { |
809 | 0 | if (fp == p->fp) { |
810 | 0 | if (prev == NULL) |
811 | 0 | ppg = p->next; |
812 | 0 | else |
813 | 0 | prev->next = p->next; |
814 | |
|
815 | 0 | int saveerrno = errno; |
816 | 0 | int res_fclose = fclose(fp); |
817 | 0 | if (!res_fclose) |
818 | | /* see R_pclose_timeout for why restoring errno on success */ |
819 | 0 | errno = saveerrno; |
820 | | |
821 | | /* This may not reliably retrieve the status of the child process |
822 | | in case SIGCHLD was set to SIG_IGN or SA_NOCLDWAIT was set for |
823 | | SIGCHLD. In that case, we may get a status for another process |
824 | | or more likely ECHILD. */ |
825 | 0 | saveerrno = errno; |
826 | 0 | for(;;) { |
827 | 0 | int wstatus = 0; |
828 | 0 | pid_t res_waitpid = waitpid(p->pid, &wstatus, 0); |
829 | 0 | if (res_waitpid != -1 || errno != EINTR) { |
830 | 0 | free(p); |
831 | 0 | if (res_waitpid == -1) |
832 | 0 | return -1; |
833 | 0 | if (res_fclose) { |
834 | | /* waitpid() succeeded but fclose failed */ |
835 | 0 | errno = saveerrno; |
836 | 0 | return -1; |
837 | 0 | } |
838 | 0 | if (errno == EINTR) |
839 | | /* protect against incorrect error checking, hide |
840 | | EINTR from any previous calls to waitpid() */ |
841 | 0 | errno = saveerrno; |
842 | 0 | return wstatus; |
843 | 0 | } |
844 | 0 | } |
845 | 0 | } |
846 | 0 | prev = p; |
847 | 0 | } |
848 | 0 | errno = ECHILD; |
849 | 0 | return -1; |
850 | 0 | } |
851 | | |
852 | | static void warn_status(const char *cmd, int res) |
853 | 24 | { |
854 | 24 | if (!res) |
855 | 24 | return; |
856 | | |
857 | 0 | if (errno) |
858 | | /* FIXME: TK: non-zero errno is a sign of an error only when |
859 | | a function that modified it also signals an error by its |
860 | | return value, usually -1 or EOF. We should not be reporting |
861 | | an error here (CERT ERR30-C).*/ |
862 | | /* on Solaris, if the command ends with non-zero status and timeout |
863 | | is 0, "Illegal seek" error is reported; the timeout version |
864 | | works this around by restoring errno on success */ |
865 | 0 | warning(_("running command '%s' had status %d and error message '%s'"), |
866 | 0 | cmd, res, strerror(errno)); |
867 | 0 | else |
868 | 0 | warning(_("running command '%s' had status %d"), cmd, res); |
869 | 0 | } |
870 | | |
871 | | NORET static void cmdError(const char *cmd, const char *format, ...) |
872 | 0 | { |
873 | 0 | SEXP call = R_CurrentExpression; |
874 | 0 | int nextra = errno ? 3 : 1; |
875 | |
|
876 | 0 | va_list(ap); |
877 | 0 | va_start(ap, format); |
878 | 0 | SEXP cond = R_vmakeErrorCondition(call, "cmdError", NULL, |
879 | 0 | nextra, format, ap); |
880 | 0 | va_end(ap); |
881 | |
|
882 | 0 | PROTECT(cond); |
883 | 0 | R_setConditionField(cond, 2, "cmd", mkString(cmd)); |
884 | 0 | if (errno) { |
885 | 0 | R_setConditionField(cond, 3, "errno", ScalarInteger(errno)); |
886 | 0 | R_setConditionField(cond, 4, "error", mkString(strerror(errno))); |
887 | 0 | } |
888 | |
|
889 | 0 | R_signalErrorCondition(cond, call); |
890 | 0 | UNPROTECT(1); /* cond; not reached */ |
891 | 0 | } |
892 | | |
893 | | #define INTERN_BUFSIZE 8096 |
894 | | attribute_hidden SEXP do_system(SEXP call, SEXP op, SEXP args, SEXP rho) |
895 | 24 | { |
896 | 24 | SEXP tlist = R_NilValue; |
897 | 24 | int intern = 0; |
898 | 24 | int timeout = 0; |
899 | 24 | int consignals = 0; |
900 | | |
901 | 24 | checkArity(op, args); |
902 | 24 | if (!isValidStringF(CAR(args))) |
903 | 0 | error(_("non-empty character argument expected")); |
904 | 24 | intern = asLogical(CADR(args)); |
905 | 24 | if (intern == NA_INTEGER) |
906 | 0 | error(_("'intern' must be logical and not NA")); |
907 | 24 | timeout = asInteger(CADDR(args)); |
908 | 24 | if (timeout == NA_INTEGER || timeout < 0) |
909 | 0 | error(_("invalid '%s' argument"), "timeout"); |
910 | 24 | consignals = asLogical(CADDDR(args)); |
911 | 24 | if (consignals == NA_INTEGER) |
912 | 0 | error(_("'receive.console.signals' must be logical and not NA")); |
913 | 24 | const char *cmd = translateCharFP(STRING_ELT(CAR(args), 0)); |
914 | | |
915 | 24 | int last_is_amp = 0; |
916 | | /* command ending with & is not supported by timeout */ |
917 | 24 | const void *vmax = vmaxget(); |
918 | 24 | const char *c = trCharUTF8(STRING_ELT(CAR(args), 0)); |
919 | 24 | int len = 0; |
920 | 528 | for(;*c; c += len) { |
921 | 504 | len = utf8clen(*c); |
922 | 504 | if (len == 1) { |
923 | 504 | if (*c == '&') |
924 | 0 | last_is_amp = 1; |
925 | 504 | else if (*c != ' ' && *c != '\t' && *c != '\r' && *c != '\n') |
926 | 468 | last_is_amp = 0; |
927 | 504 | } else |
928 | 0 | last_is_amp = 0; |
929 | 504 | } |
930 | 24 | vmaxset(vmax); |
931 | 24 | if (last_is_amp && timeout > 0) |
932 | 0 | error("Timeout with background running processes is not supported."); |
933 | | |
934 | 24 | if (intern) { /* intern = TRUE */ |
935 | 24 | FILE *fp; |
936 | 24 | char *x = "r", |
937 | 24 | #ifdef HAVE_GETLINE |
938 | 24 | *buf = NULL; |
939 | 24 | size_t buf_len = 0; |
940 | | #else |
941 | | buf[INTERN_BUFSIZE + MB_LEN_MAX], |
942 | | buf2[MB_LEN_MAX + 1]; /* overflow bytes from MBCS truncation */ |
943 | | #endif |
944 | 24 | int i, j, res; |
945 | 24 | SEXP tchar, rval; |
946 | | |
947 | 24 | PROTECT(tlist); |
948 | 24 | errno = 0; /* precaution */ |
949 | 24 | if (timeout == 0) |
950 | 24 | fp = R_popen(cmd, x); |
951 | 0 | else |
952 | 0 | fp = R_popen_timeout(cmd, x, timeout); |
953 | 24 | if(!fp) |
954 | 0 | cmdError(cmd, _("cannot popen '%s', probable reason '%s'"), |
955 | 0 | cmd, strerror(errno)); |
956 | 24 | #ifdef HAVE_GETLINE |
957 | 24 | size_t read; |
958 | 48 | for(i = 0; (read = getline(&buf, &buf_len, fp)) != (size_t)-1; i++) { |
959 | 24 | if (buf[read - 1] == '\n') |
960 | | #else |
961 | | size_t read = 0; |
962 | | size_t truncb = 0; /* number of overflow bytes from MBCS truncation */ |
963 | | buf[0] = '\0'; |
964 | | for (i = 0; fgets(buf + truncb, INTERN_BUFSIZE, fp) || truncb; i++) { |
965 | | buf2[0] = '\0'; |
966 | | read = strlen(buf); |
967 | | if (read >= INTERN_BUFSIZE - 1 + truncb) { |
968 | | warning(_("line %d may be truncated in call to system(, intern = TRUE)"), i + 1); |
969 | | /* save trailing bytes in buf2 in case they are from incomplete |
970 | | multi-byte character, and hence will be removed from buf by |
971 | | mbcsTruncateToValid */ |
972 | | memcpy(buf2, buf + read - MB_LEN_MAX, MB_LEN_MAX); |
973 | | buf2[MB_LEN_MAX] = '\0'; |
974 | | mbcsTruncateToValid(buf); |
975 | | truncb = read - strlen(buf); |
976 | | } |
977 | | else truncb = 0; |
978 | | |
979 | | if (read > 0 && buf[read-1] == '\n') |
980 | | #endif |
981 | 24 | buf[read - 1] = '\0'; /* chop final CR */ |
982 | 24 | tchar = mkChar(buf); |
983 | 24 | UNPROTECT(1); |
984 | 24 | PROTECT(tlist = CONS(tchar, tlist)); |
985 | | #ifndef HAVE_GETLINE |
986 | | if (truncb > 0 && truncb <= MB_LEN_MAX) |
987 | | /* recover overflow bytes and prepend them for next line */ |
988 | | strcpy(buf, buf2 + (MB_LEN_MAX - truncb)); |
989 | | #endif |
990 | 24 | } |
991 | 24 | #ifdef HAVE_GETLINE |
992 | 24 | if (buf != NULL) |
993 | 24 | free(buf); |
994 | 24 | #endif |
995 | 24 | if (timeout == 0) |
996 | 24 | res = pclose(fp); |
997 | 0 | else |
998 | 0 | res = R_pclose_timeout(fp); |
999 | | |
1000 | | /* On Solaris, pclose sometimes returns -1 and sets errno to ESPIPE |
1001 | | (Illegal seek). In that case, do_system reports 0 exit status and |
1002 | | displays a warning via warn_status. ESPIPE is not mentioned by |
1003 | | POSIX as possible outcome of pclose. */ |
1004 | | |
1005 | 24 | #ifdef HAVE_SYS_WAIT_H |
1006 | 24 | if (WIFEXITED(res)) res = WEXITSTATUS(res); |
1007 | 0 | else res = 0; |
1008 | | #else |
1009 | | /* assume that this is shifted if a multiple of 256 */ |
1010 | | if ((res % 256) == 0) res = res/256; |
1011 | | #endif |
1012 | 24 | if ((res & 0xff) == 127) {/* 127, aka -1 */ |
1013 | 0 | if (errno) |
1014 | 0 | cmdError(cmd, _("error in running command: '%s'"), |
1015 | 0 | strerror(errno)); |
1016 | 0 | else |
1017 | 0 | cmdError(cmd, _("error in running command")); |
1018 | 0 | } |
1019 | | |
1020 | 24 | if (timeout && tost.timedout) { |
1021 | 0 | res = 124; |
1022 | 0 | warning(_("command '%s' timed out after %ds"), cmd, timeout); |
1023 | 0 | } else |
1024 | 24 | warn_status(cmd, res); |
1025 | | |
1026 | 24 | rval = PROTECT(allocVector(STRSXP, i)); |
1027 | 48 | for (j = (i - 1); j >= 0; j--) { |
1028 | 24 | SET_STRING_ELT(rval, j, CAR(tlist)); |
1029 | 24 | tlist = CDR(tlist); |
1030 | 24 | } |
1031 | 24 | if(res) { |
1032 | 0 | SEXP lsym = install("status"); |
1033 | 0 | setAttrib(rval, lsym, ScalarInteger(res)); |
1034 | 0 | if(errno) { |
1035 | 0 | lsym = install("errmsg"); |
1036 | 0 | setAttrib(rval, lsym, mkString(strerror(errno))); |
1037 | 0 | } |
1038 | 0 | } |
1039 | 24 | UNPROTECT(2); |
1040 | 24 | return rval; |
1041 | 24 | } |
1042 | 0 | else { /* intern = FALSE */ |
1043 | | #ifdef HAVE_AQUA |
1044 | | R_Busy(1); |
1045 | | #endif |
1046 | 0 | tlist = PROTECT(allocVector(INTSXP, 1)); |
1047 | 0 | fflush(stdout); |
1048 | 0 | int res; |
1049 | | /* When running background processes (last_is_amp) in interactive mode, |
1050 | | Ctrl+C (SIGINT) should just interrupt the currently executing R |
1051 | | loop or cancel currently edited command, but it should not kill |
1052 | | the background processes (PR#17764). The C library system() runs |
1053 | | background processes as (orphaned) processes in the same process |
1054 | | group as R, so they receive SIGINT, and may terminate themselves |
1055 | | consequently, such as R itself used to. Applications that leave |
1056 | | the SIG_IGN disposition of SIGINT (set by system()) alone will not |
1057 | | be terminated. |
1058 | | |
1059 | | We hence use R_system_timeout (even without a real timeout), which |
1060 | | runs the task in a new process group, and hence does not receive |
1061 | | SIGINT as a result of Ctrl+C from R console. However, we only |
1062 | | use R_system_timeout in this case, because it has undesirable |
1063 | | consequences for job control (SIGTSTP, SIGCONT missed, so Ctrl+Z does |
1064 | | not suspend) and termination (SIGHUP missed, so terminal close does |
1065 | | not terminate). |
1066 | | |
1067 | | When running a background process (last_is_amp, normally via |
1068 | | wait=FALSE), which serves as an implementation of a foreground |
1069 | | operation (such as clusterApply()), one can use |
1070 | | receive.console.signals=TRUE to force the non-timeout |
1071 | | implementation. */ |
1072 | 0 | if (timeout == 0 && (!R_Interactive || !last_is_amp || consignals)) |
1073 | 0 | res = R_system(cmd); |
1074 | 0 | else |
1075 | 0 | res = R_system_timeout(cmd, timeout); |
1076 | 0 | if (res == 127) |
1077 | 0 | warning(_("error in running command")); |
1078 | 0 | if (timeout && tost.timedout) { |
1079 | 0 | res = 124; |
1080 | 0 | warning(_("command '%s' timed out after %ds"), cmd, timeout); |
1081 | 0 | } |
1082 | 0 | INTEGER(tlist)[0] = res; |
1083 | | #ifdef HAVE_AQUA |
1084 | | R_Busy(0); |
1085 | | #endif |
1086 | 0 | UNPROTECT(1); |
1087 | 0 | R_Visible = 0; |
1088 | 0 | return tlist; |
1089 | 0 | } |
1090 | 24 | } |
1091 | | |
1092 | | #ifdef HAVE_SYS_UTSNAME_H |
1093 | | # include <sys/utsname.h> |
1094 | | |
1095 | | # ifdef HAVE_UNISTD_H |
1096 | | # include <unistd.h> |
1097 | | # endif |
1098 | | |
1099 | | # ifdef HAVE_PWD_H |
1100 | | # include <pwd.h> |
1101 | | # endif |
1102 | | |
1103 | | attribute_hidden SEXP do_sysinfo(SEXP call, SEXP op, SEXP args, SEXP rho) |
1104 | 24 | { |
1105 | 24 | SEXP ans, ansnames; |
1106 | 24 | struct utsname name; |
1107 | 24 | char *login; |
1108 | | |
1109 | 24 | checkArity(op, args); |
1110 | 24 | PROTECT(ans = allocVector(STRSXP, 8)); |
1111 | 24 | if(uname(&name) == -1) { |
1112 | 0 | UNPROTECT(1); |
1113 | 0 | return R_NilValue; |
1114 | 0 | } |
1115 | 24 | SET_STRING_ELT(ans, 0, mkChar(name.sysname)); |
1116 | 24 | SET_STRING_ELT(ans, 1, mkChar(name.release)); |
1117 | 24 | SET_STRING_ELT(ans, 2, mkChar(name.version)); |
1118 | 24 | SET_STRING_ELT(ans, 3, mkChar(name.nodename)); |
1119 | 24 | SET_STRING_ELT(ans, 4, mkChar(name.machine)); |
1120 | 24 | login = getlogin(); |
1121 | 24 | SET_STRING_ELT(ans, 5, login ? mkChar(login) : mkChar("unknown")); |
1122 | 24 | #if defined(HAVE_PWD_H) && defined(HAVE_GETPWUID) && defined(HAVE_GETUID) |
1123 | 24 | { |
1124 | 24 | struct passwd *stpwd; |
1125 | 24 | stpwd = getpwuid(getuid()); |
1126 | 24 | SET_STRING_ELT(ans, 6, stpwd ? mkChar(stpwd->pw_name) : mkChar("unknown")); |
1127 | 24 | } |
1128 | | #else |
1129 | | SET_STRING_ELT(ans, 6, mkChar("unknown")); |
1130 | | #endif |
1131 | 24 | #if defined(HAVE_PWD_H) && defined(HAVE_GETPWUID) && defined(HAVE_GETEUID) |
1132 | 24 | { |
1133 | 24 | struct passwd *stpwd; |
1134 | 24 | stpwd = getpwuid(geteuid()); |
1135 | 24 | SET_STRING_ELT(ans, 7, stpwd ? mkChar(stpwd->pw_name) : mkChar("unknown")); |
1136 | 24 | } |
1137 | | #else |
1138 | | SET_STRING_ELT(ans, 7, mkChar("unknown")); |
1139 | | #endif |
1140 | 24 | PROTECT(ansnames = allocVector(STRSXP, 8)); |
1141 | 24 | SET_STRING_ELT(ansnames, 0, mkChar("sysname")); |
1142 | 24 | SET_STRING_ELT(ansnames, 1, mkChar("release")); |
1143 | 24 | SET_STRING_ELT(ansnames, 2, mkChar("version")); |
1144 | 24 | SET_STRING_ELT(ansnames, 3, mkChar("nodename")); |
1145 | 24 | SET_STRING_ELT(ansnames, 4, mkChar("machine")); |
1146 | 24 | SET_STRING_ELT(ansnames, 5, mkChar("login")); |
1147 | 24 | SET_STRING_ELT(ansnames, 6, mkChar("user")); |
1148 | 24 | SET_STRING_ELT(ansnames, 7, mkChar("effective_user")); |
1149 | 24 | setAttrib(ans, R_NamesSymbol, ansnames); |
1150 | 24 | UNPROTECT(2); |
1151 | 24 | return ans; |
1152 | 24 | } |
1153 | | #else /* not HAVE_SYS_UTSNAME_H */ |
1154 | | SEXP do_sysinfo(SEXP call, SEXP op, SEXP args, SEXP rho) |
1155 | | { |
1156 | | warning(_("Sys.info() is not implemented on this system")); |
1157 | | return R_NilValue; /* -Wall */ |
1158 | | } |
1159 | | #endif /* not HAVE_SYS_UTSNAME_H */ |
1160 | | |
1161 | | /* The pointer here is used in the Mac GUI */ |
1162 | | #include <R_ext/eventloop.h> /* for R_PolledEvents */ |
1163 | | #include <R_ext/Rdynload.h> |
1164 | | |
1165 | | #define R_INTERFACE_PTRS 1 |
1166 | | #include <Rinterface.h> /* for ptr_R_ProcessEvents */ |
1167 | | |
1168 | | void R_ProcessEvents(void) |
1169 | 380k | { |
1170 | | #ifdef HAVE_AQUA |
1171 | | /* disable ProcessEvents in child, |
1172 | | since we can't call CoreFoundation there. */ |
1173 | | if (ptr_R_ProcessEvents && !R_isForkedChild) ptr_R_ProcessEvents(); |
1174 | | #else |
1175 | | /* We might in due course want to always inhibit in a child */ |
1176 | 380k | if (ptr_R_ProcessEvents) ptr_R_ProcessEvents(); |
1177 | 380k | #endif |
1178 | 380k | R_PolledEvents(); |
1179 | 380k | if (cpuLimit > 0.0 || elapsedLimit > 0.0) |
1180 | 0 | R_CheckTimeLimits(); |
1181 | 380k | } |
1182 | | |
1183 | | |
1184 | | /* |
1185 | | * helpers for start-up code |
1186 | | */ |
1187 | | |
1188 | | #ifdef __FreeBSD__ |
1189 | | # ifdef HAVE_FLOATINGPOINT_H |
1190 | | # include <floatingpoint.h> |
1191 | | # endif |
1192 | | #endif |
1193 | | |
1194 | | /* patch from Ei-ji Nakama for Intel compilers on ix86. |
1195 | | From http://www.nakama.ne.jp/memo/ia32_linux/R-2.1.1.iccftzdaz.patch.txt. |
1196 | | Since updated to include x86_64. |
1197 | | */ |
1198 | | #if (defined(__i386) || defined(__x86_64)) && defined(__INTEL_COMPILER) && __INTEL_COMPILER > 800 |
1199 | | #include <xmmintrin.h> |
1200 | | #include <pmmintrin.h> |
1201 | | #endif |
1202 | | |
1203 | | /* exported for Rembedded.h */ |
1204 | | void fpu_setup(Rboolean start) |
1205 | 12 | { |
1206 | 12 | if (start) { |
1207 | | #ifdef __FreeBSD__ |
1208 | | fpsetmask(0); |
1209 | | #endif |
1210 | | |
1211 | | #if (defined(__i386) || defined(__x86_64)) && defined(__INTEL_COMPILER) && __INTEL_COMPILER > 800 |
1212 | | _MM_SET_FLUSH_ZERO_MODE(_MM_FLUSH_ZERO_OFF); |
1213 | | _MM_SET_DENORMALS_ZERO_MODE(_MM_DENORMALS_ZERO_OFF); |
1214 | | #endif |
1215 | | |
1216 | | #if defined(__ARM_ARCH) && defined(__ARM_32BIT_STATE) && defined(__ARM_FP) |
1217 | | uint32_t fpscr; |
1218 | | |
1219 | | __asm__ volatile("vmrs %0, fpscr" : "=r"(fpscr)); |
1220 | | /* clear/disable DN (default NaN) and FZ (flush to zero) bits */ |
1221 | | fpscr = fpscr & 0xfcffffff; |
1222 | | __asm__ volatile("vmsr fpscr, %0" : : "r"(fpscr)); |
1223 | | #elif defined(__ARM_ARCH) && defined(__ARM_64BIT_STATE) && defined(__ARM_FP) |
1224 | | uint64_t fpcr; |
1225 | | |
1226 | | __asm__ volatile("mrs %0, fpcr" : "=r"(fpcr)); |
1227 | | /* clear/disable DN (default NaN) and FZ (flush to zero) bits */ |
1228 | | fpcr = fpcr & 0xfffffffffcffffff; |
1229 | | __asm__ volatile("msr fpcr, %0" : : "r"(fpcr)); |
1230 | | #endif |
1231 | 12 | } else { |
1232 | | #ifdef __FreeBSD__ |
1233 | | fpsetmask(~0); |
1234 | | #endif |
1235 | 0 | } |
1236 | 12 | } |