14#include "ruby/config.h"
51#ifdef HAVE_SYS_RESOURCE_H
52# include <sys/resource.h>
57#ifdef HAVE_SYS_PARAM_H
58# include <sys/param.h>
61# define MAXPATHLEN 1024
70#ifdef HAVE_SYS_TIMES_H
80int initgroups(
const char *,
rb_gid_t);
88# include <mach/mach_time.h>
94#define open rb_w32_uopen
97#if defined(HAVE_TIMES) || defined(_WIN32)
98static VALUE rb_cProcessTms;
102#define WIFEXITED(w) (((w) & 0xff) == 0)
105#define WIFSIGNALED(w) (((w) & 0x7f) > 0 && (((w) & 0x7f) < 0x7f))
108#define WIFSTOPPED(w) (((w) & 0xff) == 0x7f)
111#define WEXITSTATUS(w) (((w) >> 8) & 0xff)
114#define WTERMSIG(w) ((w) & 0x7f)
117#define WSTOPSIG WEXITSTATUS
120#if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__bsdi__)
121#define HAVE_44BSD_SETUID 1
122#define HAVE_44BSD_SETGID 1
130#ifdef BROKEN_SETREUID
131#define setreuid ruby_setreuid
134#ifdef BROKEN_SETREGID
135#define setregid ruby_setregid
139#if defined(HAVE_44BSD_SETUID) || defined(__APPLE__)
140#if !defined(USE_SETREUID) && !defined(BROKEN_SETREUID)
141#define OBSOLETE_SETREUID 1
143#if !defined(USE_SETREGID) && !defined(BROKEN_SETREGID)
144#define OBSOLETE_SETREGID 1
148static void check_uid_switch(
void);
149static void check_gid_switch(
void);
150static int exec_async_signal_safe(
const struct rb_execarg *,
char *,
size_t);
153#define p_uid_from_name p_uid_from_name
154#define p_gid_from_name p_gid_from_name
157#if defined(HAVE_UNISTD_H)
158# if defined(HAVE_GETLOGIN_R)
159# define USE_GETLOGIN_R 1
160# define GETLOGIN_R_SIZE_DEFAULT 0x100
161# define GETLOGIN_R_SIZE_LIMIT 0x1000
162# if defined(_SC_LOGIN_NAME_MAX)
163# define GETLOGIN_R_SIZE_INIT sysconf(_SC_LOGIN_NAME_MAX)
165# define GETLOGIN_R_SIZE_INIT GETLOGIN_R_SIZE_DEFAULT
167# elif defined(HAVE_GETLOGIN)
168# define USE_GETLOGIN 1
172#if defined(HAVE_PWD_H)
173# if defined(HAVE_GETPWUID_R)
174# define USE_GETPWUID_R 1
175# elif defined(HAVE_GETPWUID)
176# define USE_GETPWUID 1
178# if defined(HAVE_GETPWNAM_R)
179# define USE_GETPWNAM_R 1
180# elif defined(HAVE_GETPWNAM)
181# define USE_GETPWNAM 1
183# if defined(HAVE_GETPWNAM_R) || defined(HAVE_GETPWUID_R)
184# define GETPW_R_SIZE_DEFAULT 0x1000
185# define GETPW_R_SIZE_LIMIT 0x10000
186# if defined(_SC_GETPW_R_SIZE_MAX)
187# define GETPW_R_SIZE_INIT sysconf(_SC_GETPW_R_SIZE_MAX)
189# define GETPW_R_SIZE_INIT GETPW_R_SIZE_DEFAULT
192# ifdef USE_GETPWNAM_R
193# define PREPARE_GETPWNAM \
195# define FINISH_GETPWNAM \
196 (getpw_buf ? (void)rb_str_resize(getpw_buf, 0) : (void)0)
197# define OBJ2UID1(id) obj2uid((id), &getpw_buf)
198# define OBJ2UID(id) obj2uid0(id)
210# define PREPARE_GETPWNAM
211# define FINISH_GETPWNAM
212# define OBJ2UID1(id) obj2uid((id))
213# define OBJ2UID(id) obj2uid((id))
217# define PREPARE_GETPWNAM
218# define FINISH_GETPWNAM
219# define OBJ2UID1(id) NUM2UIDT(id)
220# define OBJ2UID(id) NUM2UIDT(id)
221# ifdef p_uid_from_name
222# undef p_uid_from_name
223# define p_uid_from_name rb_f_notimplement
227#if defined(HAVE_GRP_H)
228# if defined(HAVE_GETGRNAM_R) && defined(_SC_GETGR_R_SIZE_MAX)
229# define USE_GETGRNAM_R
230# define GETGR_R_SIZE_INIT sysconf(_SC_GETGR_R_SIZE_MAX)
231# define GETGR_R_SIZE_DEFAULT 0x1000
232# define GETGR_R_SIZE_LIMIT 0x10000
234# ifdef USE_GETGRNAM_R
235# define PREPARE_GETGRNAM \
237# define FINISH_GETGRNAM \
238 (getgr_buf ? (void)rb_str_resize(getgr_buf, 0) : (void)0)
239# define OBJ2GID1(id) obj2gid((id), &getgr_buf)
240# define OBJ2GID(id) obj2gid0(id)
253# define PREPARE_GETGRNAM
254# define FINISH_GETGRNAM
255# define OBJ2GID1(id) obj2gid((id))
256# define OBJ2GID(id) obj2gid((id))
260# define PREPARE_GETGRNAM
261# define FINISH_GETGRNAM
262# define OBJ2GID1(id) NUM2GIDT(id)
263# define OBJ2GID(id) NUM2GIDT(id)
264# ifdef p_gid_from_name
265# undef p_gid_from_name
266# define p_gid_from_name rb_f_notimplement
270#if SIZEOF_CLOCK_T == SIZEOF_INT
272#elif SIZEOF_CLOCK_T == SIZEOF_LONG
274#elif defined(HAVE_LONG_LONG) && SIZEOF_CLOCK_T == SIZEOF_LONG_LONG
281#define id_exception idException
282static ID id_in, id_out, id_err, id_pid, id_uid, id_gid;
283static ID id_close, id_child;
288static ID id_new_pgroup;
290static ID id_unsetenv_others, id_chdir, id_umask, id_close_others, id_ENV;
291static ID id_nanosecond, id_microsecond, id_millisecond, id_second;
292static ID id_float_microsecond, id_float_millisecond, id_float_second;
293static ID id_GETTIMEOFDAY_BASED_CLOCK_REALTIME, id_TIME_BASED_CLOCK_REALTIME;
295static ID id_TIMES_BASED_CLOCK_MONOTONIC;
296static ID id_TIMES_BASED_CLOCK_PROCESS_CPUTIME_ID;
299static ID id_GETRUSAGE_BASED_CLOCK_PROCESS_CPUTIME_ID;
301static ID id_CLOCK_BASED_CLOCK_PROCESS_CPUTIME_ID;
303static ID id_MACH_ABSOLUTE_TIME_BASED_CLOCK_MONOTONIC;
308#if defined(__sun) && !defined(_XPG7)
309#define execv(path, argv) (rb_async_bug_errno("unreachable: async-signal-unsafe execv() is called", 0))
310#define execl(path, arg0, arg1, arg2, term) do { extern char **environ; execle((path), (arg0), (arg1), (arg2), (term), (environ)); } while (0)
311#define ALWAYS_NEED_ENVP 1
313#define ALWAYS_NEED_ENVP 0
317assert_close_on_exec(
int fd)
320#if defined(HAVE_FCNTL) && defined(F_GETFD) && defined(FD_CLOEXEC)
323 static const char m[] =
"reserved FD closed unexpectedly?\n";
328 rb_bug(
"reserved FD did not have close-on-exec set");
330 rb_bug(
"reserved FD without close-on-exec support");
336close_unless_reserved(
int fd)
339 assert_close_on_exec(fd);
346#if defined(DEBUG_REDIRECT)
351ttyprintf(
const char *
fmt, ...)
357 tty =
fopen(
"con",
"w");
359 tty =
fopen(
"/dev/tty",
"w");
376 ttyprintf(
"dup(%d) => %d\n", oldfd, ret);
384 ret =
dup2(oldfd, newfd);
385 ttyprintf(
"dup2(%d, %d) => %d\n", oldfd, newfd, ret);
394 ttyprintf(
"cloexec_dup(%d) => %d\n", oldfd, ret);
403 ttyprintf(
"cloexec_dup2(%d, %d) => %d\n", oldfd, newfd, ret);
411 ret = close_unless_reserved(fd);
412 ttyprintf(
"close(%d) => %d\n", fd, ret);
421 ttyprintf(
"parent_open(\"%s\", 0x%x, 0%o) => %d\n", pathname, flags, perm, ret);
429 ret = close_unless_reserved(fd);
430 ttyprintf(
"parent_close(%d) => %d\n", fd, ret);
435#define redirect_dup(oldfd) dup(oldfd)
436#define redirect_dup2(oldfd, newfd) dup2((oldfd), (newfd))
437#define redirect_cloexec_dup(oldfd) rb_cloexec_dup(oldfd)
438#define redirect_cloexec_dup2(oldfd, newfd) rb_cloexec_dup2((oldfd), (newfd))
439#define redirect_close(fd) close_unless_reserved(fd)
440#define parent_redirect_open(pathname, flags, perm) rb_cloexec_open((pathname), (flags), (perm))
441#define parent_redirect_close(fd) close_unless_reserved(fd)
543static VALUE rb_cProcessStatus;
605#define PST2INT(st) NUM2INT(pst_to_i(st))
630 pst_message_status(
str, status);
634pst_message_status(
VALUE str,
int status)
690 pst_message(
str, pid, status);
721 pst_message(
str, pid, status);
738 if (st1 == st2)
return Qtrue;
739 return rb_equal(pst_to_i(st1), st2);
960#if defined HAVE_WAITPID
962#elif defined HAVE_WAIT4
963 return wait4(pid,
st, flags,
NULL);
965# error waitpid or wait4 is required.
969#define WAITPID_LOCK_ONLY ((struct waitpid_state *)-1)
1013sigwait_fd_migrate_sleeper(
rb_vm_t *vm)
1018 if (waitpid_signal(w))
return;
1021 if (waitpid_signal(w))
return;
1029 sigwait_fd_migrate_sleeper(vm);
1053# define ruby_nocldwait 0
1083sigwait_sleep_time(
void)
1111 int sigwait_fd = -1;
1119 if (sigwait_fd >= 0) {
1133 if (sigwait_fd >= 0) {
1135 sigwait_fd_migrate_sleeper(vm);
1146waitpid_sleep(
VALUE x)
1158waitpid_cleanup(
VALUE x)
1181 int need_sleep =
FALSE;
1215waitpid_blocking_no_SIGCHLD(
void *x)
1245 waitpid_state_init(&w,
pid, flags);
1252 waitpid_no_SIGCHLD(&w);
1259 else if (w.
ret > 0) {
1358 return proc_wait(c,
v);
1430static VALUE rb_cWaiter;
1433detach_process_pid(
VALUE thread)
1439detach_process_watcher(
void *
arg)
1514before_exec_async_signal_safe(
void)
1519before_exec_non_async_signal_safe(
void)
1533#define WRITE_CONST(fd, str) (void)(write((fd),(str),sizeof(str)-1)<0)
1543#elif defined(F_GETFL) && defined(F_SETFL)
1544 int fl =
fcntl(fd, F_GETFL);
1547 if (fl == -1)
return fl;
1557stdfd_clear_nonblock(
void)
1561 for (fd = 0; fd < 3; fd++) {
1562 (
void)set_blocking(fd);
1569 before_exec_non_async_signal_safe();
1570 before_exec_async_signal_safe();
1575after_exec_async_signal_safe(
void)
1580after_exec_non_async_signal_safe(
void)
1589 after_exec_async_signal_safe();
1590 after_exec_non_async_signal_safe();
1593#if defined HAVE_WORKING_FORK || defined HAVE_DAEMON
1594#define before_fork_ruby() before_exec()
1596after_fork_ruby(
void)
1605#if defined(HAVE_WORKING_FORK)
1608#define try_with_sh(err, prog, argv, envp) ((err == ENOEXEC) ? exec_with_sh((prog), (argv), (envp)) : (void)0)
1610exec_with_sh(
const char *prog,
char **
argv,
char **envp)
1612 *
argv = (
char *)prog;
1613 *--
argv = (
char *)
"sh";
1621#define try_with_sh(err, prog, argv, envp) (void)0
1626proc_exec_cmd(
const char *prog,
VALUE argv_str,
VALUE envp_str)
1657proc_exec_sh(
const char *
str,
VALUE envp_str)
1662 while (*s ==
' ' || *s ==
'\t' || *s ==
'\n')
1671#elif defined(__CYGWIN32__)
1704mark_exec_arg(
void *
ptr)
1730memsize_exec_arg(
const void *
ptr)
1742# define DEFAULT_PROCESS_ENCODING rb_utf8_encoding()
1744#ifdef DEFAULT_PROCESS_ENCODING
1745# define EXPORT_STR(str) rb_str_export_to_enc((str), DEFAULT_PROCESS_ENCODING)
1746# define EXPORT_DUP(str) export_dup(str)
1755# define EXPORT_STR(str) (str)
1756# define EXPORT_DUP(str) rb_str_dup(str)
1759#if !defined(HAVE_WORKING_FORK) && defined(HAVE_SPAWNV)
1760# define USE_SPAWNV 1
1762# define USE_SPAWNV 0
1765# define P_NOWAIT _P_NOWAIT
1770#define proc_spawn_cmd_internal(argv, prog) rb_w32_uaspawn(P_NOWAIT, (prog), (argv))
1773proc_spawn_cmd_internal(
char **
argv,
char *prog)
1787 *
argv = (
char *)prog;
1788 *--
argv = (
char *)
"sh";
1789 status = spawnv(
P_NOWAIT,
"/bin/sh", (
const char **)
argv);
1806 flags = CREATE_NEW_PROCESS_GROUP;
1817#define proc_spawn_sh(str) rb_w32_uspawn(P_NOWAIT, (str), 0)
1820proc_spawn_sh(
char *
str)
1827 status = spawnl(
P_NOWAIT, (shell ? shell :
"/bin/sh"),
"sh",
"-c",
str, (
char*)
NULL);
1842check_exec_redirect_fd(
VALUE v,
int iskey)
1853 else if (
id == id_out)
1855 else if (
id == id_err)
1875 else if (fd >= 3 && iskey) {
1896 VALUE fd = check_exec_redirect_fd(
v, !
NIL_P(param));
1912 switch (
TYPE(val)) {
1915 if (
id == id_close) {
1919 else if (
id ==
id_in) {
1923 else if (
id == id_out) {
1927 else if (
id == id_err) {
1940 val = check_exec_redirect_fd(val, 0);
1951 param = check_exec_redirect_fd(
rb_ary_entry(val, 1), 0);
1966 flags, perm,
Qnil));
1975 key = check_exec_redirect_fd(
key, 1);
1977 flags =
INT2NUM(O_WRONLY|O_CREAT|O_TRUNC);
1982 VALUE fd = check_exec_redirect_fd(
v, 1);
1986 flags =
INT2NUM(O_WRONLY|O_CREAT|O_TRUNC);
1994 flags, perm,
Qnil));
2001 if (!
NIL_P(val))
goto io;
2007#if defined(HAVE_SETRLIMIT) && defined(NUM2RLIM)
2008static int rlimit_type_by_sym(
VALUE key);
2011rb_execarg_addopt_rlimit(
struct rb_execarg *eargp,
int rtype,
VALUE val)
2014 VALUE tmp, softlim, hardlim;
2039#define TO_BOOL(val, name) NIL_P(val) ? 0 : rb_bool_expected((val), name)
2049#if defined(HAVE_SETRLIMIT) && defined(NUM2RLIM)
2051 int rtype = rlimit_type_by_sym(
key);
2053 rb_execarg_addopt_rlimit(eargp, rtype, val);
2061 if (
id == id_pgroup) {
2068 else if (val ==
Qtrue)
2082 if (
id == id_new_pgroup) {
2091 if (
id == id_unsetenv_others) {
2098 else if (
id == id_chdir) {
2107 else if (
id == id_umask) {
2115 else if (
id == id_close_others) {
2122 else if (
id ==
id_in) {
2126 else if (
id == id_out) {
2130 else if (
id == id_err) {
2134 else if (
id == id_uid) {
2146 "uid option is unimplemented on this machine");
2149 else if (
id == id_gid) {
2161 "gid option is unimplemented on this machine");
2169 eargp->exception =
TO_BOOL(val,
"exception");
2180 check_exec_redirect(
key, val, eargp);
2212 VALUE execarg_obj = args[0];
2214 VALUE nonopts = args[1];
2259 maxhint = check_exec_fds_1(eargp,
h, maxhint, eargp->
fd_dup2);
2260 maxhint = check_exec_fds_1(eargp,
h, maxhint, eargp->
fd_close);
2261 maxhint = check_exec_fds_1(eargp,
h, maxhint, eargp->
fd_dup2_child);
2281 if (oldfd != lastfd) {
2299rb_check_exec_options(
VALUE opthash,
VALUE execarg_obj)
2312 args[0] = execarg_obj;
2318#ifdef ENV_IGNORECASE
2319#define ENVMATCH(s1, s2) (STRCASECMP((s1), (s2)) == 0)
2321#define ENVMATCH(n1, n2) (strcmp((n1), (n2)) == 0)
2405rb_exec_getargs(
int *argc_p,
VALUE **argv_p,
int accept_shell,
VALUE *env_ret,
VALUE *opthash_ret)
2410 hash = check_hash((*argv_p)[*argc_p-1]);
2412 *opthash_ret = hash;
2418 hash = check_hash((*argv_p)[0]);
2425 prog = rb_check_argv(*argc_p, *argv_p);
2427 prog = (*argv_p)[0];
2428 if (accept_shell && *argc_p == 1) {
2443compare_posix_sh(
const void *
key,
const void *el)
2447 if (!ret && ((
const char *)el)[word->
len]) ret = -1;
2460 if (!
NIL_P(opthash)) {
2461 rb_check_exec_options(opthash, execarg_obj);
2477 static const char posix_sh_cmds[][9] = {
2536 if (*p ==
' ' || *p ==
'\t') {
2537 if (first.
ptr && !first.
len) first.
len = p - first.
ptr;
2540 if (!first.
ptr) first.
ptr = p;
2542 if (!has_meta &&
strchr(
"*?{}[]<>()~&|\\$;'`\"\n#", *p))
2548 else if (*p ==
'/') {
2555 if (!has_meta && first.
ptr) {
2556 if (!first.
len) first.
len = p - first.
ptr;
2557 if (first.
len > 0 && first.
len <=
sizeof(posix_sh_cmds[0]) &&
2558 bsearch(&first, posix_sh_cmds,
numberof(posix_sh_cmds),
sizeof(posix_sh_cmds[0]), compare_posix_sh))
2570 while (*p ==
' ' || *p ==
'\t')
2574 while (*p && *p !=
' ' && *p !=
'\t')
2589 const char *abspath;
2590 const char *path_env = 0;
2593 path_env, fbuf,
sizeof(fbuf));
2608#ifdef DEFAULT_PROCESS_ENCODING
2618 const char *p, *ep, *
null=
NULL;
2630 rb_imemo_tmpbuf_auto_free_pointer_new_from_an_RString(argv_str);
2644rb_execarg_init(
int argc,
const VALUE *orig_argv,
int accept_shell,
VALUE execarg_obj)
2652 prog = rb_exec_getargs(&
argc, &
argv, accept_shell, &
env, &opthash);
2653 rb_exec_fillarg(prog,
argc,
argv,
env, opthash, execarg_obj);
2666 rb_execarg_init(
argc,
argv, accept_shell, execarg_obj);
2697static long run_exec_dup2_tmpbuf_size(
long n);
2718rb_execarg_allocate_dup2_tmpbuf(
struct rb_execarg *eargp,
long len)
2721 rb_imemo_tmpbuf_set_ptr(tmpbuf,
ruby_xmalloc(run_exec_dup2_tmpbuf_size(
len)));
2726rb_execarg_parent_start1(
VALUE execarg_obj)
2729 int unsetenv_others;
2750 open_data.fname = vpath;
2751 open_data.oflags = flags;
2752 open_data.perm =
perm;
2754 open_data.err =
EINTR;
2756 if (open_data.ret == -1) {
2757 if (open_data.err ==
EINTR) {
2763 fd2 = open_data.ret;
2779 rb_execarg_allocate_dup2_tmpbuf(eargp,
RARRAY_LEN(ary));
2785 VALUE envtbl, envp_str, envp_buf;
2787 if (unsetenv_others) {
2827 rb_imemo_tmpbuf_auto_free_pointer_new_from_an_RString(envp_str);
2847 rb_protect(rb_execarg_parent_start1, execarg_obj, &state);
2855execarg_parent_end(
VALUE execarg_obj)
2885 execarg_parent_end(execarg_obj);
2890rb_exec_fail(
struct rb_execarg *eargp,
int err,
const char *errmsg)
2892 if (!errmsg || !*errmsg)
return;
2893 if (
strcmp(errmsg,
"chdir") == 0) {
2901rb_execarg_fail(
VALUE execarg_obj,
int err,
const char *errmsg)
2903 if (!errmsg || !*errmsg)
return;
2912 VALUE execarg_obj, fail_str;
2914#define CHILD_ERRMSG_BUFLEN 80
2923 rb_protect(rb_execarg_parent_start1, execarg_obj, &state);
2925 execarg_parent_end(execarg_obj);
2932 err = exec_async_signal_safe(eargp, errmsg,
sizeof(errmsg));
2935 rb_exec_fail(eargp,
err, errmsg);
3020#define ERRMSG(str) do { if (errmsg && 0 < errmsg_buflen) strlcpy(errmsg, (str), errmsg_buflen); } while (0)
3021#define ERRMSG1(str, a) do { if (errmsg && 0 < errmsg_buflen) snprintf(errmsg, errmsg_buflen, (str), (a)); } while (0)
3022#define ERRMSG2(str, a, b) do { if (errmsg && 0 < errmsg_buflen) snprintf(errmsg, errmsg_buflen, (str), (a), (b)); } while (0)
3024static int fd_get_cloexec(
int fd,
char *errmsg,
size_t errmsg_buflen);
3025static int fd_set_cloexec(
int fd,
char *errmsg,
size_t errmsg_buflen);
3026static int fd_clear_cloexec(
int fd,
char *errmsg,
size_t errmsg_buflen);
3029save_redirect_fd(
int fd,
struct rb_execarg *sargp,
char *errmsg,
size_t errmsg_buflen)
3032 VALUE newary, redirection;
3034 if (save_fd == -1) {
3046 cloexec = fd_get_cloexec(fd, errmsg, errmsg_buflen);
3063intcmp(
const void *a,
const void *b)
3065 return *(
int*)a - *(
int*)b;
3069intrcmp(
const void *a,
const void *b)
3071 return *(
int*)b - *(
int*)a;
3083run_exec_dup2_tmpbuf_size(
long n)
3090fd_get_cloexec(
int fd,
char *errmsg,
size_t errmsg_buflen)
3096 ERRMSG(
"fcntl(F_GETFD)");
3106fd_set_cloexec(
int fd,
char *errmsg,
size_t errmsg_buflen)
3112 ERRMSG(
"fcntl(F_GETFD)");
3119 ERRMSG(
"fcntl(F_SETFD)");
3129fd_clear_cloexec(
int fd,
char *errmsg,
size_t errmsg_buflen)
3135 ERRMSG(
"fcntl(F_GETFD)");
3142 ERRMSG(
"fcntl(F_SETFD)");
3152run_exec_dup2(
VALUE ary,
VALUE tmpbuf,
struct rb_execarg *sargp,
char *errmsg,
size_t errmsg_buflen)
3163 for (
i = 0;
i <
n;
i++) {
3178 for (
i = 0;
i <
n;
i++) {
3185 while (pairs < found && (found-1)->
oldfd ==
newfd)
3187 while (found < pairs+n && found->
oldfd ==
newfd) {
3196 for (
i = 0;
i <
n;
i++) {
3198 while (j != -1 && pairs[j].
oldfd != -1 && pairs[j].
num_newer == 0) {
3199 if (save_redirect_fd(pairs[j].
newfd, sargp, errmsg, errmsg_buflen) < 0)
3207 fd_set_cloexec(pairs[j].
newfd, errmsg, errmsg_buflen)) {
3211 pairs[j].
oldfd = -1;
3219 for (
i = 0;
i <
n;
i++) {
3221 if (pairs[
i].
oldfd == -1)
3224 if (fd_clear_cloexec(pairs[
i].
oldfd, errmsg, errmsg_buflen) == -1)
3229 if (extra_fd == -1) {
3231 if (extra_fd == -1) {
3245 pairs[
i].
oldfd = extra_fd;
3255 pairs[j].
oldfd = -1;
3259 if (extra_fd != -1) {
3275run_exec_close(
VALUE ary,
char *errmsg,
size_t errmsg_buflen)
3294run_exec_dup2_child(
VALUE ary,
struct rb_execarg *sargp,
char *errmsg,
size_t errmsg_buflen)
3304 if (save_redirect_fd(
newfd, sargp, errmsg, errmsg_buflen) < 0)
3319run_exec_pgroup(
const struct rb_execarg *eargp,
struct rb_execarg *sargp,
char *errmsg,
size_t errmsg_buflen)
3345 if (ret == -1)
ERRMSG(
"setpgid");
3350#if defined(HAVE_SETRLIMIT) && defined(RLIM2NUM)
3353run_exec_rlimit(
VALUE ary,
struct rb_execarg *sargp,
char *errmsg,
size_t errmsg_buflen)
3362 if (getrlimit(rtype, &rlim) == -1) {
3377 if (setrlimit(rtype, &rlim) == -1) {
3386#if !defined(HAVE_WORKING_FORK)
3415#define chdir(p) rb_w32_uchdir(p)
3432 if (run_exec_pgroup(eargp, sargp, errmsg, errmsg_buflen) == -1)
3437#if defined(HAVE_SETRLIMIT) && defined(RLIM2NUM)
3440 if (run_exec_rlimit(
obj, sargp, errmsg, errmsg_buflen) == -1)
3445#if !defined(HAVE_WORKING_FORK)
3478 if (run_exec_dup2(
obj, eargp->
dup2_tmpbuf, sargp, errmsg, errmsg_buflen) == -1)
3485 rb_warn(
"cannot close fd before spawn");
3487 if (run_exec_close(
obj, errmsg, errmsg_buflen) == -1)
3492#ifdef HAVE_WORKING_FORK
3500 if (run_exec_dup2_child(
obj, sargp, errmsg, errmsg_buflen) == -1)
3537 rb_execarg_allocate_dup2_tmpbuf(sargp,
RARRAY_LEN(ary));
3541 int preserve =
errno;
3542 stdfd_clear_nonblock();
3553 errno = exec_async_signal_safe(eargp, errmsg, errmsg_buflen);
3558exec_async_signal_safe(
const struct rb_execarg *eargp,
char *errmsg,
size_t errmsg_buflen)
3560#if !defined(HAVE_WORKING_FORK)
3561 struct rb_execarg sarg, *
const sargp = &sarg;
3575 char *abspath =
NULL;
3580#if !defined(HAVE_WORKING_FORK)
3587#ifdef HAVE_WORKING_FORK
3590rb_exec_atfork(
void*
arg,
char *errmsg,
size_t errmsg_buflen)
3595#if SIZEOF_INT == SIZEOF_LONG
3596#define proc_syswait (VALUE (*)(VALUE))rb_syswait
3599proc_syswait(
VALUE pid)
3607move_fds_to_avoid_crash(
int *fdp,
int n,
VALUE fds)
3611 for (
i = 0;
i <
n;
i++) {
3630pipe_nocrash(
int filedes[2],
VALUE fds)
3638 if (move_fds_to_avoid_crash(filedes, 2, fds) == -1) {
3653rb_thread_sleep_that_takes_VALUE_as_sole_argument(
VALUE n)
3660handle_fork_error(
int err,
int *status,
int *ep,
volatile int *try_gc_p)
3672#if defined(EWOULDBLOCK) && EWOULDBLOCK != EAGAIN
3675 if (!status && !ep) {
3680 rb_protect(rb_thread_sleep_that_takes_VALUE_as_sole_argument,
INT2FIX(1), &state);
3681 if (status) *status = state;
3682 if (!state)
return 0;
3695#define prefork() ( \
3696 rb_io_flush(rb_stdout), \
3697 rb_io_flush(rb_stderr) \
3727write_retry(
int fd,
const void *
buf,
size_t len)
3739read_retry(
int fd,
void *
buf,
size_t len)
3743 if (set_blocking(fd) != 0) {
3757send_child_error(
int fd,
char *errmsg,
size_t errmsg_buflen)
3763 if (errmsg && 0 < errmsg_buflen) {
3764 errmsg[errmsg_buflen-1] =
'\0';
3765 errmsg_buflen =
strlen(errmsg);
3766 if (errmsg_buflen > 0 && write_retry(fd, errmsg, errmsg_buflen) < 0)
3772recv_child_error(
int fd,
int *errp,
char *errmsg,
size_t errmsg_buflen)
3776 if ((
size = read_retry(fd, &
err,
sizeof(
err))) < 0) {
3781 errmsg && 0 < errmsg_buflen) {
3782 ssize_t ret = read_retry(fd, errmsg, errmsg_buflen-1);
3791#ifdef HAVE_WORKING_VFORK
3792#if !defined(HAVE_GETRESUID) && defined(HAVE_GETUIDX)
3801 ret = getuidx(ID_SAVED);
3807#define HAVE_GETRESUID
3810#if !defined(HAVE_GETRESGID) && defined(HAVE_GETGIDX)
3819 ret = getgidx(ID_SAVED);
3825#define HAVE_GETRESGID
3846#if defined HAVE_ISSETUGID
3851#ifdef HAVE_GETRESUID
3855 ret = getresuid(&ruid, &euid, &suid);
3866 if (euid == 0 || euid != ruid)
3869#ifdef HAVE_GETRESGID
3873 ret = getresgid(&rgid, &egid, &sgid);
3891struct child_handler_disabler_state
3897disable_child_handler_before_fork(
struct child_handler_disabler_state *
old)
3902#ifdef HAVE_PTHREAD_SIGMASK
3912# pragma GCC warning "pthread_sigmask on fork is not available. potentially dangerous"
3917disable_child_handler_fork_parent(
struct child_handler_disabler_state *
old)
3921#ifdef HAVE_PTHREAD_SIGMASK
3927# pragma GCC warning "pthread_sigmask on fork is not available. potentially dangerous"
3933disable_child_handler_fork_child(
struct child_handler_disabler_state *
old,
char *errmsg,
size_t errmsg_buflen)
3945 ERRMSG(
"signal to obtain old action");
3974retry_fork_async_signal_safe(
int *status,
int *ep,
3975 int (*chfunc)(
void*,
char *,
size_t),
void *charg,
3976 char *errmsg,
size_t errmsg_buflen,
3980 volatile int try_gc = 1;
3981 struct child_handler_disabler_state
old;
3989 disable_child_handler_before_fork(&
old);
3993#ifdef HAVE_WORKING_VFORK
3994 if (!has_privilege())
4004 ret = disable_child_handler_fork_child(&
old, errmsg, errmsg_buflen);
4006 ret = chfunc(charg, errmsg, errmsg_buflen);
4009 send_child_error(ep[1], errmsg, errmsg_buflen);
4010#if EXIT_SUCCESS == 127
4017 waitpid_lock = waitpid_lock_init;
4025 disable_child_handler_fork_parent(&
old);
4029 if (handle_fork_error(
err, status, ep, &try_gc))
4036fork_check_err(
int *status,
int (*chfunc)(
void*,
char *,
size_t),
void *charg,
4037 VALUE fds,
char *errmsg,
size_t errmsg_buflen,
4050 if (pipe_nocrash(ep, fds))
return -1;
4051 pid = retry_fork_async_signal_safe(
status, ep, chfunc, charg,
4052 errmsg, errmsg_buflen, w);
4056 error_occurred = recv_child_error(ep[0], &
err, errmsg, errmsg_buflen);
4057 if (error_occurred) {
4060 "only used by extensions");
4081 int (*chfunc)(
void*,
char *,
size_t),
void *charg,
4082 VALUE fds,
char *errmsg,
size_t errmsg_buflen)
4084 return fork_check_err(
status, chfunc, charg, fds, errmsg, errmsg_buflen, 0);
4095 int try_gc = 1,
err;
4096 struct child_handler_disabler_state
old;
4098 if (status) *status = 0;
4103 disable_child_handler_before_fork(&
old);
4108 disable_child_handler_fork_parent(&
old);
4113 if (handle_fork_error(
err, status,
NULL, &try_gc))
4121#if defined(HAVE_WORKING_FORK) && !defined(CANNOT_FORK_WITH_PTHREAD)
4171#define rb_f_fork rb_f_notimplement
4175exit_status_code(
VALUE status)
4188#if EXIT_SUCCESS != 0
4214 istatus = exit_status_code(
argv[0]);
4243 istatus = exit_status_code(
argv[0]);
4318 if (!
NIL_P(errinfo)) {
4326 args[1] = args[0] =
argv[0];
4350#if !defined HAVE_WORKING_FORK && !defined HAVE_SPAWNV
4364 p[
argv[
i] - start - 1] =
' ';
4374rb_spawn_process(
struct rb_execarg *eargp,
char *errmsg,
size_t errmsg_buflen)
4377#if !defined HAVE_WORKING_FORK || USE_SPAWNV
4380# if !defined HAVE_SPAWNV
4385#if defined HAVE_WORKING_FORK && !USE_SPAWNV
4386 pid = fork_check_err(0, rb_exec_atfork, eargp, eargp->
redirect_fds,
4387 errmsg, errmsg_buflen, eargp);
4399# if defined HAVE_SPAWNV
4405 pid = proc_spawn_cmd(
argv, prog, eargp);
4434 rb_execarg_parent_start1(argp->
execarg);
4440rb_execarg_spawn(
VALUE execarg_obj,
char *
errmsg,
size_t errmsg_buflen)
4453 args.execarg = execarg_obj;
4454 args.errmsg.ptr = errmsg;
4455 args.errmsg.buflen = errmsg_buflen;
4457 execarg_parent_end, execarg_obj);
4461rb_spawn_internal(
int argc,
const VALUE *
argv,
char *errmsg,
size_t errmsg_buflen)
4466 return rb_execarg_spawn(execarg_obj, errmsg, errmsg_buflen);
4472 return rb_spawn_internal(
argc,
argv, errmsg, errmsg_buflen);
4548 waitpid_state_init(w, 0, 0);
4550 pid = rb_execarg_spawn(execarg_obj, 0, 0);
4551 exec_errnum = pid < 0 ?
errno : 0;
4553#if defined(HAVE_WORKING_FORK) || defined(HAVE_SPAWNV)
4560 waitpid_no_SIGCHLD(w);
4565 if (w->
pid < 0 || pid < 0 ) {
4566 if (eargp->exception) {
4567 int err = exec_errnum ? exec_errnum : w->
errnum;
4577 if (eargp->exception) {
4864 VALUE execarg_obj, fail_str;
4871 pid = rb_execarg_spawn(execarg_obj, errmsg,
sizeof(errmsg));
4875 rb_exec_fail(eargp,
err, errmsg);
4879#if defined(HAVE_WORKING_FORK) || defined(HAVE_SPAWNV)
4917 end =
time(0) - beg;
4923#if (defined(HAVE_GETPGRP) && defined(GETPGRP_VOID)) || defined(HAVE_GETPGID)
4940#if defined(HAVE_GETPGRP) && defined(GETPGRP_VOID)
4951#define proc_getpgrp rb_f_notimplement
4955#if defined(HAVE_SETPGID) || (defined(HAVE_SETPGRP) && defined(SETPGRP_VOID))
4973#elif defined(HAVE_SETPGRP) && defined(SETPGRP_VOID)
4979#define proc_setpgrp rb_f_notimplement
4983#if defined(HAVE_GETPGID)
5004#define proc_getpgid rb_f_notimplement
5029#define proc_setpgid rb_f_notimplement
5060#define proc_getsid rb_f_notimplement
5064#if defined(HAVE_SETSID) || (defined(HAVE_SETPGRP) && defined(TIOCNOTTY))
5065#if !defined(HAVE_SETSID)
5067#define setsid() ruby_setsid()
5090#if !defined(HAVE_SETSID)
5091#define HAVE_SETSID 1
5099#if defined(SETPGRP_VOID)
5107 if (ret == -1)
return -1;
5118#define proc_setsid rb_f_notimplement
5122#ifdef HAVE_GETPRIORITY
5143 int prio, iwhich, iwho;
5149 prio = getpriority(iwhich, iwho);
5154#define proc_getpriority rb_f_notimplement
5158#ifdef HAVE_GETPRIORITY
5174 int iwhich, iwho, iprio;
5180 if (setpriority(iwhich, iwho, iprio) < 0)
5185#define proc_setpriority rb_f_notimplement
5188#if defined(HAVE_SETRLIMIT) && defined(NUM2RLIM)
5190rlimit_resource_name2int(
const char *
name,
long len,
int casetype)
5194#define RESCHECK(r) \
5196 if (len == rb_strlen_lit(#r) && STRCASECMP(name, #r) == 0) { \
5197 resource = RLIMIT_##r; \
5231#ifdef RLIMIT_MEMLOCK
5234#ifdef RLIMIT_MSGQUEUE
5270#ifdef RLIMIT_SIGPENDING
5271 RESCHECK(SIGPENDING);
5280 for (p =
name; *p; p++)
5286 for (p =
name; *p; p++)
5292 rb_bug(
"unexpected casetype");
5299rlimit_type_by_hname(
const char *
name,
long len)
5301 return rlimit_resource_name2int(
name,
len, 0);
5305rlimit_type_by_lname(
const char *
name,
long len)
5307 return rlimit_resource_name2int(
name,
len, 1);
5317 static const char prefix[] =
"rlimit_";
5318 enum {prefix_len =
sizeof(prefix)-1};
5320 if (
len > prefix_len &&
strncmp(prefix, rname, prefix_len) == 0) {
5321 rtype = rlimit_type_by_lname(rname + prefix_len,
len - prefix_len);
5329rlimit_resource_type(
VALUE rtype)
5336 switch (
TYPE(rtype)) {
5359 r = rlimit_type_by_hname(
name,
len);
5369rlimit_resource_value(
VALUE rval)
5374 switch (
TYPE(rval)) {
5396 if (
strcmp(
name,
"INFINITY") == 0)
return RLIM_INFINITY;
5398#ifdef RLIM_SAVED_MAX
5399 if (
strcmp(
name,
"SAVED_MAX") == 0)
return RLIM_SAVED_MAX;
5401#ifdef RLIM_SAVED_CUR
5402 if (
strcmp(
name,
"SAVED_CUR") == 0)
return RLIM_SAVED_CUR;
5410#if defined(HAVE_GETRLIMIT) && defined(RLIM2NUM)
5436 if (getrlimit(rlimit_resource_type(resource), &rlim) < 0) {
5442#define proc_getrlimit rb_f_notimplement
5445#if defined(HAVE_SETRLIMIT) && defined(NUM2RLIM)
5500 VALUE resource, rlim_cur, rlim_max;
5507 rlim_max = rlim_cur;
5509 rlim.rlim_cur = rlimit_resource_value(rlim_cur);
5510 rlim.rlim_max = rlimit_resource_value(rlim_max);
5512 if (setrlimit(rlimit_resource_type(resource), &rlim) < 0) {
5518#define proc_setrlimit rb_f_notimplement
5521static int under_uid_switch = 0;
5523check_uid_switch(
void)
5525 if (under_uid_switch) {
5530static int under_gid_switch = 0;
5532check_gid_switch(
void)
5534 if (under_gid_switch) {
5540#if defined(HAVE_PWD_H)
5549#if ( !defined(USE_GETLOGIN_R) && !defined(USE_GETLOGIN) )
5554# ifdef USE_GETLOGIN_R
5556 long loginsize = GETLOGIN_R_SIZE_INIT;
5559 loginsize = GETLOGIN_R_SIZE_DEFAULT;
5569 while ((gle =
getlogin_r(login, loginsize)) != 0) {
5576 if (gle !=
ERANGE || loginsize >= GETLOGIN_R_SIZE_LIMIT) {
5586 if (login ==
NULL) {
5591 return maybe_result;
5613#if ( !defined(USE_GETPWNAM_R) && !defined(USE_GETPWNAM) )
5617 if (
NIL_P(login_name)) {
5624 struct passwd *pwptr;
5626# ifdef USE_GETPWNAM_R
5628 struct passwd pwdnm;
5630 long bufsizenm = GETPW_R_SIZE_INIT;
5633 bufsizenm = GETPW_R_SIZE_DEFAULT;
5643 while ((enm = getpwnam_r(login, &pwdnm, bufnm, bufsizenm, &pwptr)) != 0) {
5651 if (enm !=
ERANGE || bufsizenm >= GETPW_R_SIZE_LIMIT) {
5661 if (pwptr ==
NULL) {
5675 pwptr = getpwnam(login);
5698# if !defined(USE_GETPWUID_R) && !defined(USE_GETPWUID)
5704 struct passwd *pwptr;
5706# ifdef USE_GETPWUID_R
5708 struct passwd pwdid;
5710 long bufsizeid = GETPW_R_SIZE_INIT;
5713 bufsizeid = GETPW_R_SIZE_DEFAULT;
5723 while ((eid = getpwuid_r(ruid, &pwdid, bufid, bufsizeid, &pwptr)) != 0) {
5731 if (eid !=
ERANGE || bufsizeid >= GETPW_R_SIZE_LIMIT) {
5741 if (pwptr ==
NULL) {
5752# elif defined(USE_GETPWUID)
5755 pwptr = getpwuid(ruid);
5784#if defined(HAVE_PWD_H)
5787# ifdef USE_GETPWNAM_R
5800 struct passwd *pwptr;
5801#ifdef USE_GETPWNAM_R
5802 struct passwd pwbuf;
5807 getpw_buf_len = GETPW_R_SIZE_INIT;
5808 if (getpw_buf_len < 0) getpw_buf_len = GETPW_R_SIZE_DEFAULT;
5815 while ((e = getpwnam_r(usrname, &pwbuf, getpw_buf, getpw_buf_len, &pwptr)) != 0) {
5816 if (e !=
ERANGE || getpw_buf_len >= GETPW_R_SIZE_LIMIT) {
5825 pwptr = getpwnam(usrname);
5828#ifndef USE_GETPWNAM_R
5833 uid = pwptr->pw_uid;
5834#ifndef USE_GETPWNAM_R
5841# ifdef p_uid_from_name
5861#if defined(HAVE_GRP_H)
5864# ifdef USE_GETGRNAM_R
5877 struct group *grptr;
5878#ifdef USE_GETGRNAM_R
5884 getgr_buf_len = GETGR_R_SIZE_INIT;
5885 if (getgr_buf_len < 0) getgr_buf_len = GETGR_R_SIZE_DEFAULT;
5892 while ((e = getgrnam_r(grpname, &grbuf, getgr_buf, getgr_buf_len, &grptr)) != 0) {
5893 if (e !=
ERANGE || getgr_buf_len >= GETGR_R_SIZE_LIMIT) {
5901#elif defined(HAVE_GETGRNAM)
5902 grptr = getgrnam(grpname);
5907#if !defined(USE_GETGRNAM_R) && defined(HAVE_ENDGRENT)
5912 gid = grptr->gr_gid;
5913#if !defined(USE_GETGRNAM_R) && defined(HAVE_ENDGRENT)
5920# ifdef p_gid_from_name
5940#if defined HAVE_SETUID
5958#define p_sys_setuid rb_f_notimplement
5962#if defined HAVE_SETRUID
5980#define p_sys_setruid rb_f_notimplement
5984#if defined HAVE_SETEUID
6002#define p_sys_seteuid rb_f_notimplement
6006#if defined HAVE_SETREUID
6031#define p_sys_setreuid rb_f_notimplement
6035#if defined HAVE_SETRESUID
6057 if (setresuid(ruid, euid, suid) != 0)
rb_sys_fail(0);
6061#define p_sys_setresuid rb_f_notimplement
6084#if defined(HAVE_SETRESUID) || defined(HAVE_SETREUID) || defined(HAVE_SETRUID) || defined(HAVE_SETUID)
6101#if defined(HAVE_SETRESUID)
6103#elif defined HAVE_SETREUID
6105#elif defined HAVE_SETRUID
6107#elif defined HAVE_SETUID
6120#define proc_setuid rb_f_notimplement
6136#ifdef BROKEN_SETREUID
6142 if (
setuid(ruid) < 0)
return -1;
6145 if (
seteuid(euid) < 0)
return -1;
6174#if defined(HAVE_SETRESUID)
6176 SAVED_USER_ID = uid;
6177#elif defined(HAVE_SETUID)
6179 SAVED_USER_ID = uid;
6180#elif defined(HAVE_SETREUID) && !defined(OBSOLETE_SETREUID)
6182 if (SAVED_USER_ID == uid) {
6191 SAVED_USER_ID = uid;
6197 SAVED_USER_ID = uid;
6203 SAVED_USER_ID = uid;
6205#elif defined(HAVE_SETRUID) && defined(HAVE_SETEUID)
6207 if (SAVED_USER_ID == uid) {
6221 SAVED_USER_ID = uid;
6228 SAVED_USER_ID = uid;
6236#if defined(HAVE_SETRESUID)
6240 SAVED_USER_ID = uid;
6241#elif defined(HAVE_SETREUID) && !defined(OBSOLETE_SETREUID)
6242 if (SAVED_USER_ID == uid) {
6247 else if (
getuid() != uid) {
6250 SAVED_USER_ID = uid;
6254 SAVED_USER_ID = uid;
6260 SAVED_USER_ID = uid;
6263#elif defined(HAVE_SETRUID) && defined(HAVE_SETEUID)
6264 if (SAVED_USER_ID == uid) {
6271 SAVED_USER_ID = uid;
6275 SAVED_USER_ID = uid;
6279 else if (
getuid() == uid) {
6282 SAVED_USER_ID = uid;
6288#elif defined HAVE_44BSD_SETUID
6292 SAVED_USER_ID = uid;
6297#elif defined HAVE_SETEUID
6298 if (
getuid() == uid && SAVED_USER_ID == uid) {
6304#elif defined HAVE_SETUID
6305 if (
getuid() == uid && SAVED_USER_ID == uid) {
6320#if defined HAVE_SETGID
6338#define p_sys_setgid rb_f_notimplement
6342#if defined HAVE_SETRGID
6360#define p_sys_setrgid rb_f_notimplement
6364#if defined HAVE_SETEGID
6382#define p_sys_setegid rb_f_notimplement
6386#if defined HAVE_SETREGID
6409#define p_sys_setregid rb_f_notimplement
6412#if defined HAVE_SETRESGID
6432 if (setresgid(rgid, egid, sgid) != 0)
rb_sys_fail(0);
6436#define p_sys_setresgid rb_f_notimplement
6440#if defined HAVE_ISSETUGID
6464#define p_sys_issetugid rb_f_notimplement
6487#if defined(HAVE_SETRESGID) || defined(HAVE_SETREGID) || defined(HAVE_SETRGID) || defined(HAVE_SETGID)
6503#if defined(HAVE_SETRESGID)
6505#elif defined HAVE_SETREGID
6507#elif defined HAVE_SETRGID
6509#elif defined HAVE_SETGID
6522#define proc_setgid rb_f_notimplement
6526#if defined(_SC_NGROUPS_MAX) || defined(NGROUPS_MAX)
6547static int _maxgroups = -1;
6549get_sc_ngroups_max(
void)
6551#ifdef _SC_NGROUPS_MAX
6553#elif defined(NGROUPS_MAX)
6562 if (_maxgroups < 0) {
6563 _maxgroups = get_sc_ngroups_max();
6574#ifdef HAVE_GETGROUPS
6617 for (
i = 0;
i < ngroups;
i++)
6625#define proc_getgroups rb_f_notimplement
6629#ifdef HAVE_SETGROUPS
6654 if (ngroups > maxgroups())
6659 for (
i = 0;
i < ngroups;
i++) {
6674#define proc_setgroups rb_f_notimplement
6678#ifdef HAVE_INITGROUPS
6705#define proc_initgroups rb_f_notimplement
6708#if defined(_SC_NGROUPS_MAX) || defined(NGROUPS_MAX)
6725#define proc_getmaxgroups rb_f_notimplement
6728#ifdef HAVE_SETGROUPS
6741 int ngroups_max = get_sc_ngroups_max();
6749 if (ngroups_max > 0 && ngroups > ngroups_max)
6750 ngroups = ngroups_max;
6752 _maxgroups = ngroups;
6757#define proc_setmaxgroups rb_f_notimplement
6760#if defined(HAVE_DAEMON) || (defined(HAVE_WORKING_FORK) && defined(HAVE_SETSID))
6761static int rb_daemon(
int nochdir,
int noclose);
6788 n = rb_daemon(nochdir, noclose);
6794rb_daemon(
int nochdir,
int noclose)
6806#define fork_daemon() \
6807 switch (rb_fork_ruby(NULL)) { \
6808 case -1: return -1; \
6809 case 0: rb_thread_atfork(); break; \
6810 default: _exit(EXIT_SUCCESS); \
6815 if (
setsid() < 0)
return -1;
6835#define proc_daemon rb_f_notimplement
6848static rb_gid_t SAVED_GROUP_ID = -1;
6850#ifdef BROKEN_SETREGID
6856 if (
setgid(rgid) < 0)
return -1;
6859 if (
setegid(egid) < 0)
return -1;
6888#if defined(HAVE_SETRESGID)
6890 SAVED_GROUP_ID = gid;
6891#elif defined HAVE_SETGID
6893 SAVED_GROUP_ID = gid;
6894#elif defined(HAVE_SETREGID) && !defined(OBSOLETE_SETREGID)
6896 if (SAVED_GROUP_ID == gid) {
6905 SAVED_GROUP_ID = gid;
6911 SAVED_GROUP_ID = gid;
6917 SAVED_GROUP_ID = gid;
6919#elif defined(HAVE_SETRGID) && defined (HAVE_SETEGID)
6921 if (SAVED_GROUP_ID == gid) {
6936 SAVED_GROUP_ID = gid;
6943 SAVED_GROUP_ID = gid;
6950#if defined(HAVE_SETRESGID)
6954 SAVED_GROUP_ID = gid;
6955#elif defined(HAVE_SETREGID) && !defined(OBSOLETE_SETREGID)
6956 if (SAVED_GROUP_ID == gid) {
6961 else if (
getgid() != gid) {
6964 SAVED_GROUP_ID = gid;
6968 SAVED_GROUP_ID = gid;
6974 SAVED_GROUP_ID = gid;
6977#elif defined(HAVE_SETRGID) && defined(HAVE_SETEGID)
6978 if (SAVED_GROUP_ID == gid) {
6985 SAVED_GROUP_ID = gid;
6989 SAVED_GROUP_ID = gid;
6993 else if (
getgid() == gid) {
6996 SAVED_GROUP_ID = gid;
7002#elif defined HAVE_44BSD_SETGID
7006 SAVED_GROUP_ID = gid;
7011#elif defined HAVE_SETEGID
7012 if (
getgid() == gid && SAVED_GROUP_ID == gid) {
7018#elif defined HAVE_SETGID
7019 if (
getgid() == gid && SAVED_GROUP_ID == gid) {
7052#if defined(HAVE_SETRESUID) || defined(HAVE_SETREUID) || defined(HAVE_SETEUID) || defined(HAVE_SETUID) || defined(_POSIX_SAVED_IDS)
7056#if defined(HAVE_SETRESUID)
7058#elif defined HAVE_SETREUID
7060#elif defined HAVE_SETEUID
7062#elif defined HAVE_SETUID
7075#if defined(HAVE_SETRESUID) || defined(HAVE_SETREUID) || defined(HAVE_SETEUID) || defined(HAVE_SETUID)
7092#define proc_seteuid_m rb_f_notimplement
7098#if defined(HAVE_SETRESUID) || (defined(HAVE_SETREUID) && !defined(OBSOLETE_SETREUID))
7104#if defined(HAVE_SETRESUID) || (defined(HAVE_SETREUID) && !defined(OBSOLETE_SETREUID))
7108#if defined(HAVE_SETRESUID)
7111 SAVED_USER_ID = euid;
7116#elif defined(HAVE_SETREUID) && !defined(OBSOLETE_SETREUID)
7121 SAVED_USER_ID = euid;
7123#elif defined HAVE_SETEUID
7125#elif defined HAVE_SETUID
7177#if defined(HAVE_SETRESGID) || defined(HAVE_SETREGID) || defined(HAVE_SETEGID) || defined(HAVE_SETGID) || defined(_POSIX_SAVED_IDS)
7189#if defined(HAVE_SETRESGID) || defined(HAVE_SETREGID) || defined(HAVE_SETEGID) || defined(HAVE_SETGID)
7195#if defined(HAVE_SETRESGID) || defined(HAVE_SETREGID) || defined(HAVE_SETEGID) || defined(HAVE_SETGID)
7199#if defined(HAVE_SETRESGID)
7201#elif defined HAVE_SETREGID
7203#elif defined HAVE_SETEGID
7205#elif defined HAVE_SETGID
7219#if defined(HAVE_SETRESGID) || defined(HAVE_SETREGID) || defined(HAVE_SETEGID) || defined(HAVE_SETGID)
7220#define proc_setegid_m proc_setegid
7222#define proc_setegid_m rb_f_notimplement
7228#if defined(HAVE_SETRESGID) || (defined(HAVE_SETREGID) && !defined(OBSOLETE_SETREGID))
7234#if defined(HAVE_SETRESGID) || (defined(HAVE_SETREGID) && !defined(OBSOLETE_SETREGID))
7238#if defined(HAVE_SETRESGID)
7241 SAVED_GROUP_ID = egid;
7246#elif defined(HAVE_SETREGID) && !defined(OBSOLETE_SETREGID)
7251 SAVED_GROUP_ID = egid;
7253#elif defined HAVE_SETEGID
7255#elif defined HAVE_SETGID
7297p_uid_exchangeable(
VALUE _)
7299#if defined(HAVE_SETRESUID)
7301#elif defined(HAVE_SETREUID) && !defined(OBSOLETE_SETREUID)
7325#if defined(HAVE_SETRESUID) || (defined(HAVE_SETREUID) && !defined(OBSOLETE_SETREUID))
7332#if defined(HAVE_SETRESUID) || (defined(HAVE_SETREUID) && !defined(OBSOLETE_SETREUID))
7336#if defined(HAVE_SETRESUID)
7337 if (setresuid(euid, uid, uid) < 0)
rb_sys_fail(0);
7338 SAVED_USER_ID = uid;
7339#elif defined(HAVE_SETREUID) && !defined(OBSOLETE_SETREUID)
7341 SAVED_USER_ID = uid;
7359p_gid_exchangeable(
VALUE _)
7361#if defined(HAVE_SETRESGID)
7363#elif defined(HAVE_SETREGID) && !defined(OBSOLETE_SETREGID)
7387#if defined(HAVE_SETRESGID) || (defined(HAVE_SETREGID) && !defined(OBSOLETE_SETREGID))
7394#if defined(HAVE_SETRESGID) || (defined(HAVE_SETREGID) && !defined(OBSOLETE_SETREGID))
7398#if defined(HAVE_SETRESGID)
7399 if (setresgid(egid, gid, gid) < 0)
rb_sys_fail(0);
7400 SAVED_GROUP_ID = gid;
7401#elif defined(HAVE_SETREGID) && !defined(OBSOLETE_SETREGID)
7403 SAVED_GROUP_ID = gid;
7422p_uid_have_saved_id(
VALUE _)
7424#if defined(HAVE_SETRESUID) || defined(HAVE_SETEUID) || defined(_POSIX_SAVED_IDS)
7432#if defined(HAVE_SETRESUID) || defined(HAVE_SETEUID) || defined(_POSIX_SAVED_IDS)
7437 under_uid_switch = 0;
7438 id = rb_seteuid_core(
id);
7469 under_uid_switch = 1;
7476 else if (euid != SAVED_USER_ID) {
7477 proc_seteuid(SAVED_USER_ID);
7479 under_uid_switch = 1;
7496 under_uid_switch = 0;
7497 return p_uid_exchange(
obj);
7513 p_uid_exchange(
obj);
7515 under_uid_switch = 1;
7537p_gid_have_saved_id(
VALUE _)
7539#if defined(HAVE_SETRESGID) || defined(HAVE_SETEGID) || defined(_POSIX_SAVED_IDS)
7546#if defined(HAVE_SETRESGID) || defined(HAVE_SETEGID) || defined(_POSIX_SAVED_IDS)
7551 under_gid_switch = 0;
7552 id = rb_setegid_core(
id);
7583 under_gid_switch = 1;
7590 else if (egid != SAVED_GROUP_ID) {
7593 under_gid_switch = 1;
7610 under_gid_switch = 0;
7611 return p_gid_exchange(
obj);
7627 p_gid_exchange(
obj);
7629 under_gid_switch = 1;
7639#if defined(HAVE_TIMES)
7643#ifdef HAVE__SC_CLK_TCK
7645#elif defined CLK_TCK
7670#if defined(RUSAGE_SELF) && defined(RUSAGE_CHILDREN)
7671 struct rusage usage_s, usage_c;
7673 if (getrusage(RUSAGE_SELF, &usage_s) != 0 || getrusage(RUSAGE_CHILDREN, &usage_c) != 0)
7675 utime =
DBL2NUM((
double)usage_s.ru_utime.tv_sec + (
double)usage_s.ru_utime.tv_usec/1e6);
7676 stime =
DBL2NUM((
double)usage_s.ru_stime.tv_sec + (
double)usage_s.ru_stime.tv_usec/1e6);
7677 cutime =
DBL2NUM((
double)usage_c.ru_utime.tv_sec + (
double)usage_c.ru_utime.tv_usec/1e6);
7678 cstime =
DBL2NUM((
double)usage_c.ru_stime.tv_sec + (
double)usage_c.ru_stime.tv_usec/1e6);
7680 const double hertz = (
double)get_clk_tck();
7697#define rb_proc_times rb_f_notimplement
7700#ifdef HAVE_LONG_LONG
7702#define TIMETICK_INT_MIN LLONG_MIN
7703#define TIMETICK_INT_MAX LLONG_MAX
7704#define TIMETICK_INT2NUM(v) LL2NUM(v)
7705#define MUL_OVERFLOW_TIMETICK_P(a, b) MUL_OVERFLOW_LONG_LONG_P(a, b)
7708#define TIMETICK_INT_MIN LONG_MIN
7709#define TIMETICK_INT_MAX LONG_MAX
7710#define TIMETICK_INT2NUM(v) LONG2NUM(v)
7711#define MUL_OVERFLOW_TIMETICK_P(a, b) MUL_OVERFLOW_LONG_P(a, b)
7750 for (
i = 0;
i < num_numerators;
i++) {
7751 if (numerators[
i] == 1)
7753 for (j = 0; j < num_denominators; j++) {
7754 if (denominators[j] == 1)
7756 reduce_fraction(&numerators[
i], &denominators[j]);
7767timetick2dblnum(
struct timetick *ttp,
7774 reduce_factors(numerators, num_numerators,
7775 denominators, num_denominators);
7779 for (
i = 0;
i < num_numerators;
i++)
7781 for (
i = 0;
i < num_denominators;
i++)
7782 d /= denominators[
i];
7788timetick2dblnum_reciprocal(
struct timetick *ttp,
7795 reduce_factors(numerators, num_numerators,
7796 denominators, num_denominators);
7799 for (
i = 0;
i < num_denominators;
i++)
7800 d *= denominators[
i];
7801 for (
i = 0;
i < num_numerators;
i++)
7808#define NDIV(x,y) (-(-((x)+1)/(y))-1)
7809#define DIV(n,d) ((n)<0 ? NDIV((n),(d)) : (n)/(d))
7812timetick2integer(
struct timetick *ttp,
7819 reduce_factors(numerators, num_numerators,
7820 denominators, num_denominators);
7825 for (
i = 0;
i < num_numerators;
i++) {
7831 for (
i = 0;
i < num_denominators;
i++) {
7832 t =
DIV(t, denominators[
i]);
7841 for (
i = 0;
i < num_numerators;
i++) {
7847 for (
i = 0;
i < num_denominators;
i++) {
7854make_clock_result(
struct timetick *ttp,
7859 if (unit ==
ID2SYM(id_nanosecond)) {
7860 numerators[num_numerators++] = 1000000000;
7861 return timetick2integer(ttp, numerators, num_numerators, denominators, num_denominators);
7863 else if (unit ==
ID2SYM(id_microsecond)) {
7864 numerators[num_numerators++] = 1000000;
7865 return timetick2integer(ttp, numerators, num_numerators, denominators, num_denominators);
7867 else if (unit ==
ID2SYM(id_millisecond)) {
7868 numerators[num_numerators++] = 1000;
7869 return timetick2integer(ttp, numerators, num_numerators, denominators, num_denominators);
7871 else if (unit ==
ID2SYM(id_second)) {
7872 return timetick2integer(ttp, numerators, num_numerators, denominators, num_denominators);
7874 else if (unit ==
ID2SYM(id_float_microsecond)) {
7875 numerators[num_numerators++] = 1000000;
7876 return timetick2dblnum(ttp, numerators, num_numerators, denominators, num_denominators);
7878 else if (unit ==
ID2SYM(id_float_millisecond)) {
7879 numerators[num_numerators++] = 1000;
7880 return timetick2dblnum(ttp, numerators, num_numerators, denominators, num_denominators);
7882 else if (
NIL_P(unit) || unit ==
ID2SYM(id_float_second)) {
7883 return timetick2dblnum(ttp, numerators, num_numerators, denominators, num_denominators);
7890static const mach_timebase_info_data_t *
7891get_mach_timebase_info(
void)
7893 static mach_timebase_info_data_t sTimebaseInfo;
7895 if ( sTimebaseInfo.denom == 0 ) {
7896 (
void) mach_timebase_info(&sTimebaseInfo);
7899 return &sTimebaseInfo;
7903ruby_real_ms_time(
void)
7905 const mach_timebase_info_data_t *info = get_mach_timebase_info();
7907 return (
double)t * info->numer / info->denom / 1e6;
8046 int num_numerators = 0;
8047 int num_denominators = 0;
8056#ifdef HAVE_GETTIMEOFDAY
8061#define RUBY_GETTIMEOFDAY_BASED_CLOCK_REALTIME ID2SYM(id_GETTIMEOFDAY_BASED_CLOCK_REALTIME)
8062 if (clk_id == RUBY_GETTIMEOFDAY_BASED_CLOCK_REALTIME) {
8069 denominators[num_denominators++] = 1000000000;
8074#define RUBY_TIME_BASED_CLOCK_REALTIME ID2SYM(id_TIME_BASED_CLOCK_REALTIME)
8082 denominators[num_denominators++] = 1000000000;
8087#define RUBY_TIMES_BASED_CLOCK_MONOTONIC \
8088 ID2SYM(id_TIMES_BASED_CLOCK_MONOTONIC)
8089 if (clk_id == RUBY_TIMES_BASED_CLOCK_MONOTONIC) {
8099 denominators[num_denominators++] = get_clk_tck();
8105#define RUBY_GETRUSAGE_BASED_CLOCK_PROCESS_CPUTIME_ID \
8106 ID2SYM(id_GETRUSAGE_BASED_CLOCK_PROCESS_CPUTIME_ID)
8107 if (clk_id == RUBY_GETRUSAGE_BASED_CLOCK_PROCESS_CPUTIME_ID) {
8108 struct rusage usage;
8110 ret = getrusage(RUSAGE_SELF, &usage);
8113 tt.
giga_count = usage.ru_utime.tv_sec + usage.ru_stime.tv_sec;
8114 usec = (
int32_t)(usage.ru_utime.tv_usec + usage.ru_stime.tv_usec);
8115 if (1000000 <= usec) {
8119 tt.
count = usec * 1000;
8120 denominators[num_denominators++] = 1000000000;
8126#define RUBY_TIMES_BASED_CLOCK_PROCESS_CPUTIME_ID \
8127 ID2SYM(id_TIMES_BASED_CLOCK_PROCESS_CPUTIME_ID)
8128 if (clk_id == RUBY_TIMES_BASED_CLOCK_PROCESS_CPUTIME_ID) {
8137 if (1000000000 <= tt.
count) {
8138 tt.
count -= 1000000000;
8141 denominators[num_denominators++] = get_clk_tck();
8146#define RUBY_CLOCK_BASED_CLOCK_PROCESS_CPUTIME_ID \
8147 ID2SYM(id_CLOCK_BASED_CLOCK_PROCESS_CPUTIME_ID)
8163#define RUBY_MACH_ABSOLUTE_TIME_BASED_CLOCK_MONOTONIC ID2SYM(id_MACH_ABSOLUTE_TIME_BASED_CLOCK_MONOTONIC)
8164 if (clk_id == RUBY_MACH_ABSOLUTE_TIME_BASED_CLOCK_MONOTONIC) {
8165 const mach_timebase_info_data_t *info = get_mach_timebase_info();
8169 numerators[num_numerators++] = info->numer;
8170 denominators[num_denominators++] = info->denom;
8171 denominators[num_denominators++] = 1000000000;
8177#if defined(HAVE_CLOCK_GETTIME)
8186 denominators[num_denominators++] = 1000000000;
8194 return make_clock_result(&tt, numerators, num_numerators, denominators, num_denominators, unit);
8241 int num_numerators = 0;
8242 int num_denominators = 0;
8248#ifdef RUBY_GETTIMEOFDAY_BASED_CLOCK_REALTIME
8249 if (clk_id == RUBY_GETTIMEOFDAY_BASED_CLOCK_REALTIME) {
8252 denominators[num_denominators++] = 1000000000;
8257#ifdef RUBY_TIME_BASED_CLOCK_REALTIME
8261 denominators[num_denominators++] = 1000000000;
8266#ifdef RUBY_TIMES_BASED_CLOCK_MONOTONIC
8267 if (clk_id == RUBY_TIMES_BASED_CLOCK_MONOTONIC) {
8270 denominators[num_denominators++] = get_clk_tck();
8275#ifdef RUBY_GETRUSAGE_BASED_CLOCK_PROCESS_CPUTIME_ID
8276 if (clk_id == RUBY_GETRUSAGE_BASED_CLOCK_PROCESS_CPUTIME_ID) {
8279 denominators[num_denominators++] = 1000000000;
8284#ifdef RUBY_TIMES_BASED_CLOCK_PROCESS_CPUTIME_ID
8285 if (clk_id == RUBY_TIMES_BASED_CLOCK_PROCESS_CPUTIME_ID) {
8288 denominators[num_denominators++] = get_clk_tck();
8293#ifdef RUBY_CLOCK_BASED_CLOCK_PROCESS_CPUTIME_ID
8302#ifdef RUBY_MACH_ABSOLUTE_TIME_BASED_CLOCK_MONOTONIC
8303 if (clk_id == RUBY_MACH_ABSOLUTE_TIME_BASED_CLOCK_MONOTONIC) {
8304 const mach_timebase_info_data_t *info = get_mach_timebase_info();
8307 numerators[num_numerators++] = info->numer;
8308 denominators[num_denominators++] = info->denom;
8309 denominators[num_denominators++] = 1000000000;
8315#if defined(HAVE_CLOCK_GETRES)
8323 denominators[num_denominators++] = 1000000000;
8331 if (unit ==
ID2SYM(id_hertz)) {
8332 return timetick2dblnum_reciprocal(&tt, numerators, num_numerators, denominators, num_denominators);
8335 return make_clock_result(&tt, numerators, num_numerators, denominators, num_denominators, unit);
8340get_CHILD_STATUS(
ID _x,
VALUE *_y)
8346get_PROCESS_ID(
ID _x,
VALUE *_y)
8394static VALUE rb_mProcUID;
8395static VALUE rb_mProcGID;
8396static VALUE rb_mProcID_Syscall;
8408#define rb_intern(str) rb_intern_const(str)
8494#ifdef HAVE_GETPRIORITY
8505#if defined(RLIM2NUM) && defined(RLIM_INFINITY)
8508#ifdef RLIM_SAVED_MAX
8510 VALUE v = RLIM_INFINITY == RLIM_SAVED_MAX ? inf :
RLIM2NUM(RLIM_SAVED_MAX);
8517#ifdef RLIM_SAVED_CUR
8519 VALUE v = RLIM_INFINITY == RLIM_SAVED_CUR ? inf :
RLIM2NUM(RLIM_SAVED_CUR);
8560#ifdef RLIMIT_MEMLOCK
8567#ifdef RLIMIT_MSGQUEUE
8625#ifdef RLIMIT_SIGPENDING
8660#ifdef CLOCK_REALTIME
8663#elif defined(RUBY_GETTIMEOFDAY_BASED_CLOCK_REALTIME)
8667#ifdef CLOCK_MONOTONIC
8670#elif defined(RUBY_MACH_ABSOLUTE_TIME_BASED_CLOCK_MONOTONIC)
8674#ifdef CLOCK_PROCESS_CPUTIME_ID
8677#elif defined(RUBY_GETRUSAGE_BASED_CLOCK_PROCESS_CPUTIME_ID)
8681#ifdef CLOCK_THREAD_CPUTIME_ID
8693#ifdef CLOCK_REALTIME_FAST
8697#ifdef CLOCK_REALTIME_PRECISE
8701#ifdef CLOCK_REALTIME_COARSE
8705#ifdef CLOCK_REALTIME_ALARM
8709#ifdef CLOCK_MONOTONIC_FAST
8713#ifdef CLOCK_MONOTONIC_PRECISE
8717#ifdef CLOCK_MONOTONIC_RAW
8721#ifdef CLOCK_MONOTONIC_RAW_APPROX
8725#ifdef CLOCK_MONOTONIC_COARSE
8729#ifdef CLOCK_BOOTTIME
8733#ifdef CLOCK_BOOTTIME_ALARM
8741#ifdef CLOCK_UPTIME_FAST
8745#ifdef CLOCK_UPTIME_PRECISE
8749#ifdef CLOCK_UPTIME_RAW
8753#ifdef CLOCK_UPTIME_RAW_APPROX
8768#if defined(HAVE_TIMES) || defined(_WIN32)
8800#ifdef p_uid_from_name
8803#ifdef p_gid_from_name
8846 id_new_pgroup =
rb_intern(
"new_pgroup");
8848 id_unsetenv_others =
rb_intern(
"unsetenv_others");
8851 id_close_others =
rb_intern(
"close_others");
8853 id_nanosecond =
rb_intern(
"nanosecond");
8854 id_microsecond =
rb_intern(
"microsecond");
8855 id_millisecond =
rb_intern(
"millisecond");
8857 id_float_microsecond =
rb_intern(
"float_microsecond");
8858 id_float_millisecond =
rb_intern(
"float_millisecond");
8859 id_float_second =
rb_intern(
"float_second");
8860 id_GETTIMEOFDAY_BASED_CLOCK_REALTIME =
rb_intern(
"GETTIMEOFDAY_BASED_CLOCK_REALTIME");
8861 id_TIME_BASED_CLOCK_REALTIME =
rb_intern(
"TIME_BASED_CLOCK_REALTIME");
8863 id_TIMES_BASED_CLOCK_MONOTONIC =
rb_intern(
"TIMES_BASED_CLOCK_MONOTONIC");
8864 id_TIMES_BASED_CLOCK_PROCESS_CPUTIME_ID =
rb_intern(
"TIMES_BASED_CLOCK_PROCESS_CPUTIME_ID");
8867 id_GETRUSAGE_BASED_CLOCK_PROCESS_CPUTIME_ID =
rb_intern(
"GETRUSAGE_BASED_CLOCK_PROCESS_CPUTIME_ID");
8869 id_CLOCK_BASED_CLOCK_PROCESS_CPUTIME_ID =
rb_intern(
"CLOCK_BASED_CLOCK_PROCESS_CPUTIME_ID");
8871 id_MACH_ABSOLUTE_TIME_BASED_CLOCK_MONOTONIC =
rb_intern(
"MACH_ABSOLUTE_TIME_BASED_CLOCK_MONOTONIC");
void rb_enc_copy(VALUE obj1, VALUE obj2)
char str[HTML_ESCAPE_MAX_LEN+1]
void ruby_stop(int ex)
Calls ruby_cleanup() and exits the process.
VALUE rb_singleton_class(VALUE)
Returns the singleton class of obj.
VALUE rb_define_class_under(VALUE, const char *, VALUE)
Defines a class under the namespace of outer.
VALUE rb_define_module(const char *)
VALUE rb_define_module_under(VALUE, const char *)
void rb_undef_method(VALUE, const char *)
void rb_define_alias(VALUE, const char *, const char *)
Defines an alias of a method.
int rb_block_given_p(void)
Determines if the current method is given a block.
VALUE rb_cObject
Object class.
void rb_notimplement(void)
void rb_syserr_fail(int e, const char *mesg)
void rb_raise(VALUE exc, const char *fmt,...)
void rb_exc_raise(VALUE mesg)
Raises an exception in the current thread.
void rb_bug(const char *fmt,...)
void rb_syserr_fail_str(int e, VALUE mesg)
void rb_sys_fail_str(VALUE mesg)
VALUE rb_protect(VALUE(*)(VALUE), VALUE, int *)
Protects a function call from potential global escapes from the function.
void rb_warn(const char *fmt,...)
VALUE rb_exc_new_str(VALUE, VALUE)
VALUE rb_ensure(VALUE(*)(VALUE), VALUE, VALUE(*)(VALUE), VALUE)
An equivalent to ensure clause.
void rb_async_bug_errno(const char *mesg, int errno_arg)
void rb_jump_tag(int tag)
Continues the exception caught by rb_protect() and rb_eval_string_protect().
void rb_sys_fail(const char *mesg)
VALUE rb_obj_alloc(VALUE)
Allocates an instance of klass.
VALUE rb_class_new_instance(int, const VALUE *, VALUE)
Allocates and initializes an instance of klass.
VALUE rb_equal(VALUE, VALUE)
Same as Object#===, case equality.
VALUE rb_to_int(VALUE)
Converts val into Integer.
void ruby_setenv(const char *name, const char *value)
#define RB_HRTIME_PER_MSEC
int rb_io_modestr_oflags(const char *modestr)
#define GetOpenFile(obj, fp)
VALUE rb_io_check_io(VALUE io)
struct rb_execarg * rb_execarg_get(VALUE execarg_obj)
#define redirect_close(fd)
VALUE rb_last_status_get(void)
void rb_native_cond_signal(rb_nativethread_cond_t *)
#define redirect_dup2(oldfd, newfd)
#define CHILD_ERRMSG_BUFLEN
void rb_execarg_parent_end(VALUE execarg_obj)
#define redirect_cloexec_dup2(oldfd, newfd)
int rb_execarg_run_options(const struct rb_execarg *eargp, struct rb_execarg *sargp, char *errmsg, size_t errmsg_buflen)
rb_pid_t rb_waitpid(rb_pid_t pid, int *st, int flags)
#define proc_getmaxgroups
#define RUBY_TIME_BASED_CLOCK_REALTIME
VALUE rb_f_abort(int argc, const VALUE *argv)
unsigned int unsigned_clock_t
void InitVM_process(void)
#define RUBY_CLOCK_BASED_CLOCK_PROCESS_CPUTIME_ID
#define parent_redirect_close(fd)
VALUE rb_f_exit(int argc, const VALUE *argv)
CONSTFUNC(static timetick_int_t gcd_timetick_int(timetick_int_t, timetick_int_t))
rb_pid_t ruby_waitpid_locked(rb_vm_t *vm, rb_pid_t pid, int *status, int options, rb_nativethread_cond_t *cond)
void rb_native_mutex_lock(rb_nativethread_lock_t *)
void rb_last_status_clear(void)
void rb_execarg_setenv(VALUE execarg_obj, VALUE env)
#define redirect_dup(oldfd)
VALUE rb_execarg_extract_options(VALUE execarg_obj, VALUE opthash)
rb_pid_t rb_spawn_err(int argc, const VALUE *argv, char *errmsg, size_t errmsg_buflen)
int rb_proc_exec(const char *str)
void rb_syswait(rb_pid_t pid)
VALUE rb_f_exec(int argc, const VALUE *argv)
#define redirect_cloexec_dup(oldfd)
void rb_sigwait_fd_migrate(rb_vm_t *vm)
void rb_thread_sleep_interruptible(void)
void rb_native_mutex_unlock(rb_nativethread_lock_t *)
#define TO_BOOL(val, name)
int rb_exec_async_signal_safe(const struct rb_execarg *eargp, char *errmsg, size_t errmsg_buflen)
VALUE rb_execarg_new(int argc, const VALUE *argv, int accept_shell, int allow_exc_opt)
void rb_execarg_parent_start(VALUE execarg_obj)
#define MUL_OVERFLOW_TIMETICK_P(a, b)
int rb_execarg_addopt(VALUE execarg_obj, VALUE key, VALUE val)
rb_pid_t rb_spawn(int argc, const VALUE *argv)
#define WAITPID_LOCK_ONLY
void rb_sigwait_fd_put(const rb_thread_t *, int fd)
#define TIMETICK_INT2NUM(v)
void rb_native_cond_wait(rb_nativethread_cond_t *, rb_nativethread_lock_t *)
void ruby_waitpid_all(rb_vm_t *vm)
int rb_sigwait_fd_get(const rb_thread_t *)
#define proc_setmaxgroups
#define parent_redirect_open(pathname, flags, perm)
void rb_last_status_set(int status, rb_pid_t pid)
#define try_with_sh(err, prog, argv, envp)
VALUE rb_detach_process(rb_pid_t pid)
void rb_sigwait_sleep(const rb_thread_t *, int fd, const rb_hrtime_t *)
char * rb_execarg_commandline(const struct rb_execarg *eargp, VALUE *prog)
int st_delete(st_table *tab, st_data_t *key, st_data_t *value)
int st_insert(st_table *tab, st_data_t key, st_data_t value)
size_t rb_str_capacity(VALUE str)
struct rb_execarg::@34::@36 cmd
unsigned unsetenv_others_given
unsigned new_pgroup_given
union rb_execarg::@34 invoke
struct waitpid_state * waitpid_state
unsigned unsetenv_others_do
unsigned close_others_given
struct rb_execarg::@34::@35 sh
VALUE tied_io_for_writing
rb_nativethread_lock_t waitpid_lock
struct list_head waiting_pids
struct list_head waiting_grps
struct spawn_args::@196 errmsg
timetick_int_t giga_count
rb_nativethread_cond_t * cond
rb_execution_context_t * ec
void * rb_thread_call_without_gvl2(void *(*func)(void *), void *data1, rb_unblock_function_t *ubf, void *data2)
void * rb_thread_call_without_gvl(void *(*func)(void *), void *data1, rb_unblock_function_t *ubf, void *data2)
int rb_w32_set_nonblock2(int fd, int nonblock)
int gettimeofday(struct timeval *, struct timezone *)
rb_pid_t waitpid(rb_pid_t, int *, int)
rb_pid_t rb_w32_uaspawn_flags(int, const char *, char *const *, DWORD)
rb_pid_t rb_w32_uspawn(int, const char *, const char *)
rb_pid_t rb_w32_uaspawn(int, const char *, char *const *)