Coverage Report

Created: 2026-09-14 06:56

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/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
}