43# define EXIT_SUCCESS 0
47# define EXIT_FAILURE 1
54#ifdef HAVE_SYS_RESOURCE_H
55# include <sys/resource.h>
62#ifdef HAVE_SYS_PARAM_H
63# include <sys/param.h>
67# define MAXPATHLEN 1024
76#ifdef HAVE_SYS_TIMES_H
77# include <sys/times.h>
87int initgroups(
const char *, rb_gid_t);
96# include <mach/mach_time.h>
104#include "internal/error.h"
105#include "internal/eval.h"
110#include "internal/variable.h"
123#define open rb_w32_uopen
126#if defined(HAVE_TIMES) || defined(_WIN32)
127static VALUE rb_cProcessTms;
131#define WIFEXITED(w) (((w) & 0xff) == 0)
134#define WIFSIGNALED(w) (((w) & 0x7f) > 0 && (((w) & 0x7f) < 0x7f))
137#define WIFSTOPPED(w) (((w) & 0xff) == 0x7f)
140#define WEXITSTATUS(w) (((w) >> 8) & 0xff)
143#define WTERMSIG(w) ((w) & 0x7f)
146#define WSTOPSIG WEXITSTATUS
149#if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__bsdi__)
150#define HAVE_44BSD_SETUID 1
151#define HAVE_44BSD_SETGID 1
159#ifdef BROKEN_SETREUID
160#define setreuid ruby_setreuid
161int setreuid(rb_uid_t ruid, rb_uid_t euid);
163#ifdef BROKEN_SETREGID
164#define setregid ruby_setregid
165int setregid(rb_gid_t rgid, rb_gid_t egid);
168#if defined(HAVE_44BSD_SETUID) || defined(__APPLE__)
169#if !defined(USE_SETREUID) && !defined(BROKEN_SETREUID)
170#define OBSOLETE_SETREUID 1
172#if !defined(USE_SETREGID) && !defined(BROKEN_SETREGID)
173#define OBSOLETE_SETREGID 1
177static void check_uid_switch(
void);
178static void check_gid_switch(
void);
179static int exec_async_signal_safe(
const struct rb_execarg *,
char *,
size_t);
182#define p_uid_from_name p_uid_from_name
183#define p_gid_from_name p_gid_from_name
186#if defined(HAVE_UNISTD_H)
187# if defined(HAVE_GETLOGIN_R)
188# define USE_GETLOGIN_R 1
189# define GETLOGIN_R_SIZE_DEFAULT 0x100
190# define GETLOGIN_R_SIZE_LIMIT 0x1000
191# if defined(_SC_LOGIN_NAME_MAX)
192# define GETLOGIN_R_SIZE_INIT sysconf(_SC_LOGIN_NAME_MAX)
194# define GETLOGIN_R_SIZE_INIT GETLOGIN_R_SIZE_DEFAULT
196# elif defined(HAVE_GETLOGIN)
197# define USE_GETLOGIN 1
201#if defined(HAVE_PWD_H)
202# if defined(HAVE_GETPWUID_R)
203# define USE_GETPWUID_R 1
204# elif defined(HAVE_GETPWUID)
205# define USE_GETPWUID 1
207# if defined(HAVE_GETPWNAM_R)
208# define USE_GETPWNAM_R 1
209# elif defined(HAVE_GETPWNAM)
210# define USE_GETPWNAM 1
212# if defined(HAVE_GETPWNAM_R) || defined(HAVE_GETPWUID_R)
213# define GETPW_R_SIZE_DEFAULT 0x1000
214# define GETPW_R_SIZE_LIMIT 0x10000
215# if defined(_SC_GETPW_R_SIZE_MAX)
216# define GETPW_R_SIZE_INIT sysconf(_SC_GETPW_R_SIZE_MAX)
218# define GETPW_R_SIZE_INIT GETPW_R_SIZE_DEFAULT
221# ifdef USE_GETPWNAM_R
222# define PREPARE_GETPWNAM \
224# define FINISH_GETPWNAM \
225 (getpw_buf ? (void)rb_str_resize(getpw_buf, 0) : (void)0)
226# define OBJ2UID1(id) obj2uid((id), &getpw_buf)
227# define OBJ2UID(id) obj2uid0(id)
228static rb_uid_t obj2uid(
VALUE id,
VALUE *getpw_buf);
229static inline rb_uid_t
239# define PREPARE_GETPWNAM
240# define FINISH_GETPWNAM
241# define OBJ2UID1(id) obj2uid((id))
242# define OBJ2UID(id) obj2uid((id))
243static rb_uid_t obj2uid(
VALUE id);
246# define PREPARE_GETPWNAM
247# define FINISH_GETPWNAM
248# define OBJ2UID1(id) NUM2UIDT(id)
249# define OBJ2UID(id) NUM2UIDT(id)
250# ifdef p_uid_from_name
251# undef p_uid_from_name
252# define p_uid_from_name rb_f_notimplement
256#if defined(HAVE_GRP_H)
257# if defined(HAVE_GETGRNAM_R) && defined(_SC_GETGR_R_SIZE_MAX)
258# define USE_GETGRNAM_R
259# define GETGR_R_SIZE_INIT sysconf(_SC_GETGR_R_SIZE_MAX)
260# define GETGR_R_SIZE_DEFAULT 0x1000
261# define GETGR_R_SIZE_LIMIT 0x10000
263# ifdef USE_GETGRNAM_R
264# define PREPARE_GETGRNAM \
266# define FINISH_GETGRNAM \
267 (getgr_buf ? (void)rb_str_resize(getgr_buf, 0) : (void)0)
268# define OBJ2GID1(id) obj2gid((id), &getgr_buf)
269# define OBJ2GID(id) obj2gid0(id)
270static rb_gid_t obj2gid(
VALUE id,
VALUE *getgr_buf);
271static inline rb_gid_t
280static rb_gid_t obj2gid(
VALUE id,
VALUE *getgr_buf);
282# define PREPARE_GETGRNAM
283# define FINISH_GETGRNAM
284# define OBJ2GID1(id) obj2gid((id))
285# define OBJ2GID(id) obj2gid((id))
286static rb_gid_t obj2gid(
VALUE id);
289# define PREPARE_GETGRNAM
290# define FINISH_GETGRNAM
291# define OBJ2GID1(id) NUM2GIDT(id)
292# define OBJ2GID(id) NUM2GIDT(id)
293# ifdef p_gid_from_name
294# undef p_gid_from_name
295# define p_gid_from_name rb_f_notimplement
299#if SIZEOF_CLOCK_T == SIZEOF_INT
301#elif SIZEOF_CLOCK_T == SIZEOF_LONG
303#elif defined(HAVE_LONG_LONG) && SIZEOF_CLOCK_T == SIZEOF_LONG_LONG
310#define id_exception idException
311static ID id_in, id_out, id_err, id_pid, id_uid, id_gid;
312static ID id_close, id_child;
317static ID id_new_pgroup;
319static ID id_unsetenv_others, id_chdir, id_umask, id_close_others, id_ENV;
320static ID id_nanosecond, id_microsecond, id_millisecond, id_second;
321static ID id_float_microsecond, id_float_millisecond, id_float_second;
322static ID id_GETTIMEOFDAY_BASED_CLOCK_REALTIME, id_TIME_BASED_CLOCK_REALTIME;
324static ID id_TIMES_BASED_CLOCK_MONOTONIC;
325static ID id_TIMES_BASED_CLOCK_PROCESS_CPUTIME_ID;
328static ID id_GETRUSAGE_BASED_CLOCK_PROCESS_CPUTIME_ID;
330static ID id_CLOCK_BASED_CLOCK_PROCESS_CPUTIME_ID;
332static ID id_MACH_ABSOLUTE_TIME_BASED_CLOCK_MONOTONIC;
337#if defined(__sun) && !defined(_XPG7)
338#define execv(path, argv) (rb_async_bug_errno("unreachable: async-signal-unsafe execv() is called", 0))
339#define execl(path, arg0, arg1, arg2, term) do { extern char **environ; execle((path), (arg0), (arg1), (arg2), (term), (environ)); } while (0)
340#define ALWAYS_NEED_ENVP 1
342#define ALWAYS_NEED_ENVP 0
346assert_close_on_exec(
int fd)
349#if defined(HAVE_FCNTL) && defined(F_GETFD) && defined(FD_CLOEXEC)
352 static const char m[] =
"reserved FD closed unexpectedly?\n";
353 (void)!
write(2, m,
sizeof(m) - 1);
357 rb_bug(
"reserved FD did not have close-on-exec set");
359 rb_bug(
"reserved FD without close-on-exec support");
365close_unless_reserved(
int fd)
368 assert_close_on_exec(fd);
375#if defined(DEBUG_REDIRECT)
378ttyprintf(
const char *fmt, ...)
384 tty = fopen(
"con",
"w");
386 tty = fopen(
"/dev/tty",
"w");
392 vfprintf(tty, fmt, ap);
403 ttyprintf(
"dup(%d) => %d\n", oldfd, ret);
411 ret =
dup2(oldfd, newfd);
412 ttyprintf(
"dup2(%d, %d) => %d\n", oldfd, newfd, ret);
421 ttyprintf(
"cloexec_dup(%d) => %d\n", oldfd, ret);
430 ttyprintf(
"cloexec_dup2(%d, %d) => %d\n", oldfd, newfd, ret);
438 ret = close_unless_reserved(fd);
439 ttyprintf(
"close(%d) => %d\n", fd, ret);
448 ttyprintf(
"parent_open(\"%s\", 0x%x, 0%o) => %d\n", pathname, flags, perm, ret);
456 ret = close_unless_reserved(fd);
457 ttyprintf(
"parent_close(%d) => %d\n", fd, ret);
462#define redirect_dup(oldfd) dup(oldfd)
463#define redirect_dup2(oldfd, newfd) dup2((oldfd), (newfd))
464#define redirect_cloexec_dup(oldfd) rb_cloexec_dup(oldfd)
465#define redirect_cloexec_dup2(oldfd, newfd) rb_cloexec_dup2((oldfd), (newfd))
466#define redirect_close(fd) close_unless_reserved(fd)
467#define parent_redirect_open(pathname, flags, perm) rb_cloexec_open((pathname), (flags), (perm))
468#define parent_redirect_close(fd) close_unless_reserved(fd)
570static VALUE rb_cProcessStatus;
588rb_process_status_allocate(
VALUE klass)
598 return GET_THREAD()->last_status;
625 VALUE last_status = rb_process_status_allocate(rb_cProcessStatus);
649process_status_load(
VALUE real_obj,
VALUE load_obj)
668 GET_THREAD()->last_status =
Qnil;
700 int status = pst_status(self);
704#define PST2INT(st) pst_status(st)
720 rb_pid_t
pid = pst_pid(self);
837 if (st1 == st2)
return Qtrue;
838 return rb_equal(pst_to_i(st1), st2);
894pst_wifstopped(
VALUE st)
914pst_wstopsig(
VALUE st)
933pst_wifsignaled(
VALUE st)
954pst_wtermsig(
VALUE st)
974pst_wifexited(
VALUE st)
1004pst_wexitstatus(
VALUE st)
1023pst_success_p(
VALUE st)
1042pst_wcoredump(
VALUE st)
1057do_waitpid(rb_pid_t
pid,
int *st,
int flags)
1059#if defined HAVE_WAITPID
1061#elif defined HAVE_WAIT4
1062 return wait4(
pid, st, flags,
NULL);
1064# error waitpid or wait4 is required.
1068#define WAITPID_LOCK_ONLY ((struct waitpid_state *)-1)
1112sigwait_fd_migrate_sleeper(
rb_vm_t *vm)
1117 if (waitpid_signal(w))
return;
1120 if (waitpid_signal(w))
return;
1128 sigwait_fd_migrate_sleeper(vm);
1136waitpid_each(
struct list_head *head)
1140 list_for_each_safe(head, w, next,
wnode) {
1147 list_del_init(&w->
wnode);
1152# define ruby_nocldwait 0
1184sigwait_sleep_time(
void)
1212 int sigwait_fd = -1;
1220 if (sigwait_fd >= 0) {
1234 if (sigwait_fd >= 0) {
1236 sigwait_fd_migrate_sleeper(vm);
1247waitpid_sleep(
VALUE x)
1259waitpid_cleanup(
VALUE x)
1271 list_del(&w->
wnode);
1282 int need_sleep =
FALSE;
1318waitpid_blocking_no_SIGCHLD(
void *x)
1356 waitpid_state_init(w,
pid, flags);
1363 waitpid_no_SIGCHLD(w);
1451 if (st) *st = data->
status;
1454 errno = data->
error;
1457 GET_THREAD()->last_status =
status;
1553 return proc_wait(c, v);
1625static VALUE rb_cWaiter;
1628detach_process_pid(
VALUE thread)
1634detach_process_watcher(
void *arg)
1636 rb_pid_t cpid,
pid = (rb_pid_t)(
VALUE)arg;
1650 RBASIC_SET_CLASS(watcher, rb_cWaiter);
1709before_exec_async_signal_safe(
void)
1714before_exec_non_async_signal_safe(
void)
1728#define WRITE_CONST(fd, str) (void)(write((fd),(str),sizeof(str)-1)<0)
1738#elif defined(F_GETFL) && defined(F_SETFL)
1739 int fl =
fcntl(fd, F_GETFL);
1742 if (fl == -1)
return fl;
1752stdfd_clear_nonblock(
void)
1756 for (fd = 0; fd < 3; fd++) {
1757 (void)set_blocking(fd);
1764 before_exec_non_async_signal_safe();
1765 before_exec_async_signal_safe();
1770after_exec_async_signal_safe(
void)
1775after_exec_non_async_signal_safe(
void)
1784 after_exec_async_signal_safe();
1785 after_exec_non_async_signal_safe();
1788#if defined HAVE_WORKING_FORK || defined HAVE_DAEMON
1790before_fork_ruby(
void)
1796after_fork_ruby(
void)
1803#if defined(HAVE_WORKING_FORK)
1806#define try_with_sh(err, prog, argv, envp) ((err == ENOEXEC) ? exec_with_sh((prog), (argv), (envp)) : (void)0)
1808exec_with_sh(
const char *
prog,
char **
argv,
char **envp)
1811 *--
argv = (
char *)
"sh";
1813 execve(
"/bin/sh",
argv, envp);
1815 execv(
"/bin/sh",
argv);
1819#define try_with_sh(err, prog, argv, envp) (void)0
1832 argv = ARGVSTR2ARGV(argv_str);
1842 envp = envp_str ? RB_IMEMO_TMPBUF_PTR(envp_str) :
NULL;
1855proc_exec_sh(
const char *
str,
VALUE envp_str)
1860 while (*s ==
' ' || *s ==
'\t' || *s ==
'\n')
1869#elif defined(__CYGWIN32__)
1875 execl(shell,
"sh",
"-c",
str, (
char *)
NULL);
1883 execle(
"/bin/sh",
"sh",
"-c",
str, (
char *)
NULL, RB_IMEMO_TMPBUF_PTR(envp_str));
1885 execl(
"/bin/sh",
"sh",
"-c",
str, (
char *)
NULL);
1902mark_exec_arg(
void *
ptr)
1928memsize_exec_arg(
const void *
ptr)
1940# define DEFAULT_PROCESS_ENCODING rb_utf8_encoding()
1942#ifdef DEFAULT_PROCESS_ENCODING
1943# define EXPORT_STR(str) rb_str_export_to_enc((str), DEFAULT_PROCESS_ENCODING)
1944# define EXPORT_DUP(str) export_dup(str)
1953# define EXPORT_STR(str) (str)
1954# define EXPORT_DUP(str) rb_str_dup(str)
1957#if !defined(HAVE_WORKING_FORK) && defined(HAVE_SPAWNV)
1958# define USE_SPAWNV 1
1960# define USE_SPAWNV 0
1963# define P_NOWAIT _P_NOWAIT
1968#define proc_spawn_cmd_internal(argv, prog) rb_w32_uaspawn(P_NOWAIT, (prog), (argv))
1971proc_spawn_cmd_internal(
char **
argv,
char *
prog)
1984 if (status == -1 && errno == ENOEXEC) {
1986 *--
argv = (
char *)
"sh";
1987 status = spawnv(
P_NOWAIT,
"/bin/sh", (
const char **)
argv);
1989 if (status == -1) errno = ENOEXEC;
2004 flags = CREATE_NEW_PROCESS_GROUP;
2015#define proc_spawn_sh(str) rb_w32_uspawn(P_NOWAIT, (str), 0)
2018proc_spawn_sh(
char *
str)
2025 status = spawnl(
P_NOWAIT, (shell ? shell :
"/bin/sh"),
"sh",
"-c",
str, (
char*)
NULL);
2035 RBASIC_CLEAR_CLASS(obj);
2040check_exec_redirect_fd(
VALUE v,
int iskey)
2051 else if (
id == id_out)
2053 else if (
id == id_err)
2072 else if (fd >= 3 && iskey) {
2097 VALUE fd = check_exec_redirect_fd(v, !
NIL_P(param));
2108 VALUE path, flags, perm;
2112 switch (
TYPE(val)) {
2115 if (
id == id_close) {
2119 else if (
id ==
id_in) {
2123 else if (
id == id_out) {
2127 else if (
id == id_err) {
2139 val = check_exec_redirect_fd(val, 0);
2149 path ==
ID2SYM(id_child)) {
2150 param = check_exec_redirect_fd(
rb_ary_entry(val, 1), 0);
2158 else if (RB_TYPE_P(flags,
T_STRING))
2165 flags, perm,
Qnil));
2174 key = check_exec_redirect_fd(
key, 1);
2176 flags =
INT2NUM(O_WRONLY|O_CREAT|O_TRUNC);
2181 VALUE fd = check_exec_redirect_fd(v, 1);
2185 flags =
INT2NUM(O_WRONLY|O_CREAT|O_TRUNC);
2193 flags, perm,
Qnil));
2200 if (!
NIL_P(val))
goto io;
2206#if defined(HAVE_SETRLIMIT) && defined(NUM2RLIM)
2207static int rlimit_type_by_sym(
VALUE key);
2210rb_execarg_addopt_rlimit(
struct rb_execarg *eargp,
int rtype,
VALUE val)
2213 VALUE tmp, softlim, hardlim;
2238#define TO_BOOL(val, name) NIL_P(val) ? 0 : rb_bool_expected((val), name)
2248#if defined(HAVE_SETRLIMIT) && defined(NUM2RLIM)
2250 int rtype = rlimit_type_by_sym(
key);
2252 rb_execarg_addopt_rlimit(eargp, rtype, val);
2260 if (
id == id_pgroup) {
2267 else if (val ==
Qtrue)
2281 if (
id == id_new_pgroup) {
2290 if (
id == id_unsetenv_others) {
2297 else if (
id == id_chdir) {
2306 else if (
id == id_umask) {
2314 else if (
id == id_close_others) {
2321 else if (
id ==
id_in) {
2325 else if (
id == id_out) {
2329 else if (
id == id_err) {
2333 else if (
id == id_uid) {
2345 "uid option is unimplemented on this machine");
2348 else if (
id == id_gid) {
2360 "gid option is unimplemented on this machine");
2368 eargp->exception =
TO_BOOL(val,
"exception");
2379 check_exec_redirect(
key, val, eargp);
2411 VALUE execarg_obj = args[0];
2413 VALUE nonopts = args[1];
2458 maxhint = check_exec_fds_1(eargp, h, maxhint, eargp->
fd_dup2);
2459 maxhint = check_exec_fds_1(eargp, h, maxhint, eargp->
fd_close);
2460 maxhint = check_exec_fds_1(eargp, h, maxhint, eargp->
fd_dup2_child);
2480 if (oldfd != lastfd) {
2498rb_check_exec_options(
VALUE opthash,
VALUE execarg_obj)
2511 args[0] = execarg_obj;
2517#ifdef ENV_IGNORECASE
2518#define ENVMATCH(s1, s2) (STRCASECMP((s1), (s2)) == 0)
2520#define ENVMATCH(n1, n2) (strcmp((n1), (n2)) == 0)
2583 for (i = 0; i <
argc; i++) {
2592check_hash(
VALUE obj)
2594 if (RB_SPECIAL_CONST_P(obj))
return Qnil;
2595 switch (RB_BUILTIN_TYPE(obj)) {
2606rb_exec_getargs(
int *argc_p,
VALUE **argv_p,
int accept_shell,
VALUE *env_ret,
VALUE *opthash_ret)
2611 hash = check_hash((*argv_p)[*argc_p-1]);
2613 *opthash_ret = hash;
2619 hash = check_hash((*argv_p)[0]);
2626 prog = rb_check_argv(*argc_p, *argv_p);
2628 prog = (*argv_p)[0];
2629 if (accept_shell && *argc_p == 1) {
2644compare_posix_sh(
const void *
key,
const void *el)
2647 int ret = strncmp(word->
ptr, el, word->
len);
2648 if (!ret && ((
const char *)el)[word->
len]) ret = -1;
2661 if (!
NIL_P(opthash)) {
2662 rb_check_exec_options(opthash, execarg_obj);
2678 static const char posix_sh_cmds[][9] = {
2737 if (*p ==
' ' || *p ==
'\t') {
2738 if (first.
ptr && !first.
len) first.
len = p - first.
ptr;
2741 if (!first.
ptr) first.
ptr = p;
2743 if (!has_meta &&
strchr(
"*?{}[]<>()~&|\\$;'`\"\n#", *p))
2749 else if (*p ==
'/') {
2756 if (!has_meta && first.
ptr) {
2757 if (!first.
len) first.
len = p - first.
ptr;
2758 if (first.
len > 0 && first.
len <=
sizeof(posix_sh_cmds[0]) &&
2759 bsearch(&first, posix_sh_cmds,
numberof(posix_sh_cmds),
sizeof(posix_sh_cmds[0]), compare_posix_sh))
2771 while (*p ==
' ' || *p ==
'\t')
2775 while (*p && *p !=
' ' && *p !=
'\t')
2790 const char *abspath;
2791 const char *path_env = 0;
2794 path_env, fbuf,
sizeof(fbuf));
2806 for (i = 0; i <
argc; i++) {
2809#ifdef DEFAULT_PROCESS_ENCODING
2819 const char *p, *ep, *null=
NULL;
2831 rb_imemo_tmpbuf_auto_free_pointer_new_from_an_RString(argv_str);
2845rb_execarg_init(
int argc,
const VALUE *orig_argv,
int accept_shell,
VALUE execarg_obj)
2867 rb_execarg_init(
argc,
argv, accept_shell, execarg_obj);
2898static long run_exec_dup2_tmpbuf_size(
long n);
2919rb_execarg_allocate_dup2_tmpbuf(
struct rb_execarg *eargp,
long len)
2921 VALUE tmpbuf = rb_imemo_tmpbuf_auto_free_pointer();
2922 rb_imemo_tmpbuf_set_ptr(tmpbuf,
ruby_xmalloc(run_exec_dup2_tmpbuf_size(
len)));
2927rb_execarg_parent_start1(
VALUE execarg_obj)
2930 int unsetenv_others;
2949 open_data.
fname = vpath;
2950 open_data.oflags = flags;
2951 open_data.perm =
perm;
2953 open_data.err = EINTR;
2955 if (open_data.ret == -1) {
2956 if (open_data.err == EINTR) {
2962 fd2 = open_data.ret;
2964 RARRAY_ASET(param, 3,
INT2FIX(fd2));
2978 rb_execarg_allocate_dup2_tmpbuf(eargp,
RARRAY_LEN(ary));
2984 VALUE envtbl, envp_str, envp_buf;
2986 if (unsetenv_others) {
3026 rb_imemo_tmpbuf_auto_free_pointer_new_from_an_RString(envp_str);
3054execarg_parent_end(
VALUE execarg_obj)
3072 RARRAY_ASET(param, 3,
Qnil);
3084 execarg_parent_end(execarg_obj);
3089rb_exec_fail(
struct rb_execarg *eargp,
int err,
const char *errmsg)
3091 if (!errmsg || !*errmsg)
return;
3092 if (strcmp(errmsg,
"chdir") == 0) {
3100rb_execarg_fail(
VALUE execarg_obj,
int err,
const char *errmsg)
3102 if (!errmsg || !*errmsg)
return;
3111 VALUE execarg_obj, fail_str;
3113#define CHILD_ERRMSG_BUFLEN 80
3124 execarg_parent_end(execarg_obj);
3131 err = exec_async_signal_safe(eargp, errmsg,
sizeof(errmsg));
3134 rb_exec_fail(eargp,
err, errmsg);
3222#define ERRMSG(str) do { if (errmsg && 0 < errmsg_buflen) strlcpy(errmsg, (str), errmsg_buflen); } while (0)
3223#define ERRMSG1(str, a) do { if (errmsg && 0 < errmsg_buflen) snprintf(errmsg, errmsg_buflen, (str), (a)); } while (0)
3224#define ERRMSG2(str, a, b) do { if (errmsg && 0 < errmsg_buflen) snprintf(errmsg, errmsg_buflen, (str), (a), (b)); } while (0)
3226static int fd_get_cloexec(
int fd,
char *errmsg,
size_t errmsg_buflen);
3227static int fd_set_cloexec(
int fd,
char *errmsg,
size_t errmsg_buflen);
3228static int fd_clear_cloexec(
int fd,
char *errmsg,
size_t errmsg_buflen);
3231save_redirect_fd(
int fd,
struct rb_execarg *sargp,
char *errmsg,
size_t errmsg_buflen)
3234 VALUE newary, redirection;
3236 if (save_fd == -1) {
3248 cloexec = fd_get_cloexec(fd, errmsg, errmsg_buflen);
3265intcmp(
const void *a,
const void *b)
3267 return *(
int*)a - *(
int*)b;
3271intrcmp(
const void *a,
const void *b)
3273 return *(
int*)b - *(
int*)a;
3285run_exec_dup2_tmpbuf_size(
long n)
3292fd_get_cloexec(
int fd,
char *errmsg,
size_t errmsg_buflen)
3298 ERRMSG(
"fcntl(F_GETFD)");
3308fd_set_cloexec(
int fd,
char *errmsg,
size_t errmsg_buflen)
3314 ERRMSG(
"fcntl(F_GETFD)");
3321 ERRMSG(
"fcntl(F_SETFD)");
3331fd_clear_cloexec(
int fd,
char *errmsg,
size_t errmsg_buflen)
3337 ERRMSG(
"fcntl(F_GETFD)");
3344 ERRMSG(
"fcntl(F_SETFD)");
3354run_exec_dup2(
VALUE ary,
VALUE tmpbuf,
struct rb_execarg *sargp,
char *errmsg,
size_t errmsg_buflen)
3365 for (i = 0; i < n; i++) {
3380 for (i = 0; i < n; i++) {
3387 while (pairs < found && (found-1)->
oldfd ==
newfd)
3389 while (found < pairs+n && found->
oldfd ==
newfd) {
3398 for (i = 0; i < n; i++) {
3400 while (j != -1 && pairs[j].
oldfd != -1 && pairs[j].
num_newer == 0) {
3401 if (save_redirect_fd(pairs[j].
newfd, sargp, errmsg, errmsg_buflen) < 0)
3409 fd_set_cloexec(pairs[j].
newfd, errmsg, errmsg_buflen)) {
3413 pairs[j].
oldfd = -1;
3421 for (i = 0; i < n; i++) {
3423 if (pairs[i].
oldfd == -1)
3426 if (fd_clear_cloexec(pairs[i].
oldfd, errmsg, errmsg_buflen) == -1)
3428 pairs[i].
oldfd = -1;
3431 if (extra_fd == -1) {
3433 if (extra_fd == -1) {
3447 pairs[i].
oldfd = extra_fd;
3457 pairs[j].
oldfd = -1;
3461 if (extra_fd != -1) {
3477run_exec_close(
VALUE ary,
char *errmsg,
size_t errmsg_buflen)
3496run_exec_dup2_child(
VALUE ary,
struct rb_execarg *sargp,
char *errmsg,
size_t errmsg_buflen)
3506 if (save_redirect_fd(
newfd, sargp, errmsg, errmsg_buflen) < 0)
3521run_exec_pgroup(
const struct rb_execarg *eargp,
struct rb_execarg *sargp,
char *errmsg,
size_t errmsg_buflen)
3546 ret = setpgid(getpid(), pgroup);
3547 if (ret == -1)
ERRMSG(
"setpgid");
3552#if defined(HAVE_SETRLIMIT) && defined(RLIM2NUM)
3555run_exec_rlimit(
VALUE ary,
struct rb_execarg *sargp,
char *errmsg,
size_t errmsg_buflen)
3564 if (getrlimit(rtype, &rlim) == -1) {
3569 RLIM2NUM(rlim.rlim_cur),
3570 RLIM2NUM(rlim.rlim_max)));
3579 if (setrlimit(rtype, &rlim) == -1) {
3588#if !defined(HAVE_WORKING_FORK)
3617#define chdir(p) rb_w32_uchdir(p)
3634 if (run_exec_pgroup(eargp, sargp, errmsg, errmsg_buflen) == -1)
3639#if defined(HAVE_SETRLIMIT) && defined(RLIM2NUM)
3642 if (run_exec_rlimit(obj, sargp, errmsg, errmsg_buflen) == -1)
3647#if !defined(HAVE_WORKING_FORK)
3680 if (run_exec_dup2(obj, eargp->
dup2_tmpbuf, sargp, errmsg, errmsg_buflen) == -1)
3687 rb_warn(
"cannot close fd before spawn");
3689 if (run_exec_close(obj, errmsg, errmsg_buflen) == -1)
3694#ifdef HAVE_WORKING_FORK
3702 if (run_exec_dup2_child(obj, sargp, errmsg, errmsg_buflen) == -1)
3737 rb_execarg_allocate_dup2_tmpbuf(sargp,
RARRAY_LEN(ary));
3741 int preserve = errno;
3742 stdfd_clear_nonblock();
3753 errno = exec_async_signal_safe(eargp, errmsg, errmsg_buflen);
3758exec_async_signal_safe(
const struct rb_execarg *eargp,
char *errmsg,
size_t errmsg_buflen)
3760#if !defined(HAVE_WORKING_FORK)
3761 struct rb_execarg sarg, *
const sargp = &sarg;
3775 char *abspath =
NULL;
3780#if !defined(HAVE_WORKING_FORK)
3787#ifdef HAVE_WORKING_FORK
3790rb_exec_atfork(
void* arg,
char *errmsg,
size_t errmsg_buflen)
3795#if SIZEOF_INT == SIZEOF_LONG
3796#define proc_syswait (VALUE (*)(VALUE))rb_syswait
3799proc_syswait(
VALUE pid)
3807move_fds_to_avoid_crash(
int *fdp,
int n,
VALUE fds)
3811 for (i = 0; i < n; i++) {
3830pipe_nocrash(
int filedes[2],
VALUE fds)
3838 if (move_fds_to_avoid_crash(filedes, 2, fds) == -1) {
3853rb_thread_sleep_that_takes_VALUE_as_sole_argument(
VALUE n)
3860handle_fork_error(
int err,
int *status,
int *ep,
volatile int *try_gc_p)
3872#if defined(EWOULDBLOCK) && EWOULDBLOCK != EAGAIN
3875 if (!status && !ep) {
3881 if (status) *status =
state;
3882 if (!
state)
return 0;
3895#define prefork() ( \
3896 rb_io_flush(rb_stdout), \
3897 rb_io_flush(rb_stderr) \
3927write_retry(
int fd,
const void *
buf,
size_t len)
3933 }
while (w < 0 && errno == EINTR);
3939read_retry(
int fd,
void *
buf,
size_t len)
3943 if (set_blocking(fd) != 0) {
3951 }
while (r < 0 && errno == EINTR);
3957send_child_error(
int fd,
char *errmsg,
size_t errmsg_buflen)
3962 if (write_retry(fd, &
err,
sizeof(
err)) < 0)
err = errno;
3963 if (errmsg && 0 < errmsg_buflen) {
3964 errmsg[errmsg_buflen-1] =
'\0';
3965 errmsg_buflen =
strlen(errmsg);
3966 if (errmsg_buflen > 0 && write_retry(fd, errmsg, errmsg_buflen) < 0)
3972recv_child_error(
int fd,
int *errp,
char *errmsg,
size_t errmsg_buflen)
3976 if ((
size = read_retry(fd, &
err,
sizeof(
err))) < 0) {
3981 errmsg && 0 < errmsg_buflen) {
3982 ssize_t ret = read_retry(fd, errmsg, errmsg_buflen-1);
3991#ifdef HAVE_WORKING_VFORK
3992#if !defined(HAVE_GETRESUID) && defined(HAVE_GETUIDX)
3995getresuid(rb_uid_t *ruid, rb_uid_t *euid, rb_uid_t *suid)
4001 ret = getuidx(ID_SAVED);
4002 if (ret == (rb_uid_t)-1)
4007#define HAVE_GETRESUID
4010#if !defined(HAVE_GETRESGID) && defined(HAVE_GETGIDX)
4013getresgid(rb_gid_t *rgid, rb_gid_t *egid, rb_gid_t *sgid)
4019 ret = getgidx(ID_SAVED);
4020 if (ret == (rb_gid_t)-1)
4025#define HAVE_GETRESGID
4043 rb_uid_t ruid, euid;
4044 rb_gid_t rgid, egid;
4046#if defined HAVE_ISSETUGID
4051#ifdef HAVE_GETRESUID
4055 ret = getresuid(&ruid, &euid, &suid);
4066 if (euid == 0 || euid != ruid)
4069#ifdef HAVE_GETRESGID
4073 ret = getresgid(&rgid, &egid, &sgid);
4091struct child_handler_disabler_state
4097disable_child_handler_before_fork(
struct child_handler_disabler_state *old)
4102#ifdef HAVE_PTHREAD_SIGMASK
4103 ret = sigfillset(&all);
4107 ret = pthread_sigmask(SIG_SETMASK, &all, &old->sigmask);
4112# pragma GCC warning "pthread_sigmask on fork is not available. potentially dangerous"
4117disable_child_handler_fork_parent(
struct child_handler_disabler_state *old)
4121#ifdef HAVE_PTHREAD_SIGMASK
4122 ret = pthread_sigmask(SIG_SETMASK, &old->sigmask,
NULL);
4127# pragma GCC warning "pthread_sigmask on fork is not available. potentially dangerous"
4133disable_child_handler_fork_child(
struct child_handler_disabler_state *old,
char *errmsg,
size_t errmsg_buflen)
4138 for (sig = 1; sig <
NSIG; sig++) {
4139 sig_t handler = signal(sig, SIG_DFL);
4141 if (handler == SIG_ERR && errno == EINVAL) {
4144 if (handler == SIG_ERR) {
4145 ERRMSG(
"signal to obtain old action");
4149 if (sig == SIGPIPE) {
4154 if (handler == SIG_IGN) {
4155 signal(sig, SIG_IGN);
4160 sigemptyset(&old->sigmask);
4161 ret = sigprocmask(SIG_SETMASK, &old->sigmask,
NULL);
4170retry_fork_async_signal_safe(
int *status,
int *ep,
4171 int (*chfunc)(
void*,
char *,
size_t),
void *charg,
4172 char *errmsg,
size_t errmsg_buflen,
4176 volatile int try_gc = 1;
4177 struct child_handler_disabler_state old;
4179 rb_nativethread_lock_t *
const volatile waitpid_lock_init =
4183 rb_nativethread_lock_t *waitpid_lock = waitpid_lock_init;
4185 disable_child_handler_before_fork(&old);
4189#ifdef HAVE_WORKING_VFORK
4190 if (!has_privilege())
4200 ret = disable_child_handler_fork_child(&old, errmsg, errmsg_buflen);
4202 ret = chfunc(charg, errmsg, errmsg_buflen);
4205 send_child_error(ep[1], errmsg, errmsg_buflen);
4206#if EXIT_SUCCESS == 127
4213 waitpid_lock = waitpid_lock_init;
4217 list_add(&GET_VM()->waiting_pids, &w->
wnode);
4221 disable_child_handler_fork_parent(&old);
4225 if (handle_fork_error(
err, status, ep, &try_gc))
4231fork_check_err(
int *status,
int (*chfunc)(
void*,
char *,
size_t),
void *charg,
4232 VALUE fds,
char *errmsg,
size_t errmsg_buflen,
4245 if (pipe_nocrash(ep, fds))
return -1;
4246 pid = retry_fork_async_signal_safe(
status, ep, chfunc, charg,
4247 errmsg, errmsg_buflen, w);
4251 error_occurred = recv_child_error(ep[0], &
err, errmsg, errmsg_buflen);
4252 if (error_occurred) {
4255 "only used by extensions");
4276 int (*chfunc)(
void*,
char *,
size_t),
void *charg,
4277 VALUE fds,
char *errmsg,
size_t errmsg_buflen)
4279 return fork_check_err(
status, chfunc, charg, fds, errmsg, errmsg_buflen, 0);
4286 int try_gc = 1,
err;
4287 struct child_handler_disabler_state old;
4289 if (status) *status = 0;
4294 disable_child_handler_before_fork(&old);
4299 disable_child_handler_fork_parent(&old);
4304 if (handle_fork_error(
err, status,
NULL, &try_gc))
4311#if defined(HAVE_WORKING_FORK) && !defined(CANNOT_FORK_WITH_PTHREAD)
4361#define rb_f_fork rb_f_notimplement
4365exit_status_code(
VALUE status)
4378#if EXIT_SUCCESS != 0
4405 istatus = exit_status_code(
argv[0]);
4418 if (GET_EC()->tag) {
4434 istatus = exit_status_code(
argv[0]);
4500 if (!
NIL_P(errinfo)) {
4508 args[1] = args[0] =
argv[0];
4546#if !defined HAVE_WORKING_FORK && !defined HAVE_SPAWNV
4554 char *p, **
argv = ARGVSTR2ARGV(
str);
4555 long i,
argc = ARGVSTR2ARGC(
str);
4559 for (i = 1; i <
argc; ++i) {
4560 p[
argv[i] - start - 1] =
' ';
4570rb_spawn_process(
struct rb_execarg *eargp,
char *errmsg,
size_t errmsg_buflen)
4573#if !defined HAVE_WORKING_FORK || USE_SPAWNV
4576# if !defined HAVE_SPAWNV
4581#if defined HAVE_WORKING_FORK && !USE_SPAWNV
4582 pid = fork_check_err(0, rb_exec_atfork, eargp, eargp->
redirect_fds, errmsg, errmsg_buflen, eargp);
4594# if defined HAVE_SPAWNV
4600 pid = proc_spawn_cmd(
argv,
prog, eargp);
4631do_spawn_process(
VALUE arg)
4634 rb_execarg_parent_start1(argp->
execarg);
4640rb_execarg_spawn(
VALUE execarg_obj,
char *
errmsg,
size_t errmsg_buflen)
4653 args.execarg = execarg_obj;
4654 args.errmsg.ptr = errmsg;
4655 args.errmsg.buflen = errmsg_buflen;
4657 execarg_parent_end, execarg_obj);
4661rb_spawn_internal(
int argc,
const VALUE *
argv,
char *errmsg,
size_t errmsg_buflen)
4666 return rb_execarg_spawn(execarg_obj, errmsg, errmsg_buflen);
4672 return rb_spawn_internal(
argc,
argv, errmsg, errmsg_buflen);
4748 waitpid_state_init(w, 0, 0);
4750 pid = rb_execarg_spawn(execarg_obj, 0, 0);
4751 exec_errnum = pid < 0 ? errno : 0;
4753#if defined(HAVE_WORKING_FORK) || defined(HAVE_SPAWNV)
4760 waitpid_no_SIGCHLD(w);
4765 if (w->
pid < 0 || pid < 0 ) {
4766 if (eargp->exception) {
4767 int err = exec_errnum ? exec_errnum : w->
errnum;
4777 if (eargp->exception) {
5064 VALUE execarg_obj, fail_str;
5071 pid = rb_execarg_spawn(execarg_obj, errmsg,
sizeof(errmsg));
5075 rb_exec_fail(eargp,
err, errmsg);
5079#if defined(HAVE_WORKING_FORK) || defined(HAVE_SPAWNV)
5106 time_t beg = time(0);
5109 if (scheduler !=
Qnil) {
5122 time_t end = time(0) - beg;
5124 return TIMET2NUM(end);
5128#if (defined(HAVE_GETPGRP) && defined(GETPGRP_VOID)) || defined(HAVE_GETPGID)
5145#if defined(HAVE_GETPGRP) && defined(GETPGRP_VOID)
5156#define proc_getpgrp rb_f_notimplement
5160#if defined(HAVE_SETPGID) || (defined(HAVE_SETPGRP) && defined(SETPGRP_VOID))
5178#elif defined(HAVE_SETPGRP) && defined(SETPGRP_VOID)
5184#define proc_setpgrp rb_f_notimplement
5188#if defined(HAVE_GETPGID)
5209#define proc_getpgid rb_f_notimplement
5225 rb_pid_t ipid, ipgrp;
5234#define proc_setpgid rb_f_notimplement
5265#define proc_getsid rb_f_notimplement
5269#if defined(HAVE_SETSID) || (defined(HAVE_SETPGRP) && defined(TIOCNOTTY))
5270#if !defined(HAVE_SETSID)
5271static rb_pid_t ruby_setsid(
void);
5272#define setsid() ruby_setsid()
5295#if !defined(HAVE_SETSID)
5296#define HAVE_SETSID 1
5304#if defined(SETPGRP_VOID)
5310 ret = setpgrp(0, pid);
5312 if (ret == -1)
return -1;
5323#define proc_setsid rb_f_notimplement
5327#ifdef HAVE_GETPRIORITY
5348 int prio, iwhich, iwho;
5354 prio = getpriority(iwhich, iwho);
5359#define proc_getpriority rb_f_notimplement
5363#ifdef HAVE_GETPRIORITY
5379 int iwhich, iwho, iprio;
5385 if (setpriority(iwhich, iwho, iprio) < 0)
5390#define proc_setpriority rb_f_notimplement
5393#if defined(HAVE_SETRLIMIT) && defined(NUM2RLIM)
5395rlimit_resource_name2int(
const char *
name,
long len,
int casetype)
5399#define RESCHECK(r) \
5401 if (len == rb_strlen_lit(#r) && STRCASECMP(name, #r) == 0) { \
5402 resource = RLIMIT_##r; \
5436#ifdef RLIMIT_MEMLOCK
5439#ifdef RLIMIT_MSGQUEUE
5475#ifdef RLIMIT_SIGPENDING
5476 RESCHECK(SIGPENDING);
5485 for (p =
name; *p; p++)
5491 for (p =
name; *p; p++)
5497 rb_bug(
"unexpected casetype");
5504rlimit_type_by_hname(
const char *
name,
long len)
5506 return rlimit_resource_name2int(
name,
len, 0);
5510rlimit_type_by_lname(
const char *
name,
long len)
5512 return rlimit_resource_name2int(
name,
len, 1);
5522 static const char prefix[] =
"rlimit_";
5523 enum {prefix_len =
sizeof(
prefix)-1};
5525 if (
len > prefix_len && strncmp(
prefix, rname, prefix_len) == 0) {
5526 rtype = rlimit_type_by_lname(rname + prefix_len,
len - prefix_len);
5534rlimit_resource_type(
VALUE rtype)
5541 switch (
TYPE(rtype)) {
5564 r = rlimit_type_by_hname(
name,
len);
5574rlimit_resource_value(
VALUE rval)
5579 switch (
TYPE(rval)) {
5597 return NUM2RLIM(rval);
5601 if (strcmp(
name,
"INFINITY") == 0)
return RLIM_INFINITY;
5603#ifdef RLIM_SAVED_MAX
5604 if (strcmp(
name,
"SAVED_MAX") == 0)
return RLIM_SAVED_MAX;
5606#ifdef RLIM_SAVED_CUR
5607 if (strcmp(
name,
"SAVED_CUR") == 0)
return RLIM_SAVED_CUR;
5615#if defined(HAVE_GETRLIMIT) && defined(RLIM2NUM)
5641 if (getrlimit(rlimit_resource_type(resource), &rlim) < 0) {
5644 return rb_assoc_new(RLIM2NUM(rlim.rlim_cur), RLIM2NUM(rlim.rlim_max));
5647#define proc_getrlimit rb_f_notimplement
5650#if defined(HAVE_SETRLIMIT) && defined(NUM2RLIM)
5705 VALUE resource, rlim_cur, rlim_max;
5712 rlim_max = rlim_cur;
5714 rlim.rlim_cur = rlimit_resource_value(rlim_cur);
5715 rlim.rlim_max = rlimit_resource_value(rlim_max);
5717 if (setrlimit(rlimit_resource_type(resource), &rlim) < 0) {
5723#define proc_setrlimit rb_f_notimplement
5726static int under_uid_switch = 0;
5728check_uid_switch(
void)
5730 if (under_uid_switch) {
5735static int under_gid_switch = 0;
5737check_gid_switch(
void)
5739 if (under_gid_switch) {
5745#if defined(HAVE_PWD_H)
5754#if ( !defined(USE_GETLOGIN_R) && !defined(USE_GETLOGIN) )
5759# ifdef USE_GETLOGIN_R
5761#if defined(__FreeBSD__)
5762 typedef int getlogin_r_size_t;
5764 typedef size_t getlogin_r_size_t;
5767 long loginsize = GETLOGIN_R_SIZE_INIT;
5770 loginsize = GETLOGIN_R_SIZE_DEFAULT;
5780 while ((gle = getlogin_r(login, (getlogin_r_size_t)loginsize)) != 0) {
5782 if (gle == ENOTTY || gle == ENXIO || gle == ENOENT) {
5787 if (gle != ERANGE || loginsize >= GETLOGIN_R_SIZE_LIMIT) {
5797 if (login ==
NULL) {
5802 return maybe_result;
5809 if (errno == ENOTTY || errno == ENXIO || errno == ENOENT) {
5822rb_getpwdirnam_for_login(
VALUE login_name)
5824#if ( !defined(USE_GETPWNAM_R) && !defined(USE_GETPWNAM) )
5828 if (
NIL_P(login_name)) {
5835 struct passwd *pwptr;
5837# ifdef USE_GETPWNAM_R
5839 struct passwd pwdnm;
5841 long bufsizenm = GETPW_R_SIZE_INIT;
5844 bufsizenm = GETPW_R_SIZE_DEFAULT;
5854 while ((enm = getpwnam_r(login, &pwdnm, bufnm, bufsizenm, &pwptr)) != 0) {
5856 if (enm == ENOENT || enm== ESRCH || enm == EBADF || enm == EPERM) {
5862 if (enm != ERANGE || bufsizenm >= GETPW_R_SIZE_LIMIT) {
5872 if (pwptr ==
NULL) {
5886 pwptr = getpwnam(login);
5893 && ( errno != ENOENT && errno != ESRCH && errno != EBADF && errno != EPERM)) {
5909# if !defined(USE_GETPWUID_R) && !defined(USE_GETPWUID)
5915 struct passwd *pwptr;
5917# ifdef USE_GETPWUID_R
5919 struct passwd pwdid;
5921 long bufsizeid = GETPW_R_SIZE_INIT;
5924 bufsizeid = GETPW_R_SIZE_DEFAULT;
5934 while ((eid = getpwuid_r(ruid, &pwdid, bufid, bufsizeid, &pwptr)) != 0) {
5936 if (eid == ENOENT || eid== ESRCH || eid == EBADF || eid == EPERM) {
5942 if (eid != ERANGE || bufsizeid >= GETPW_R_SIZE_LIMIT) {
5952 if (pwptr ==
NULL) {
5963# elif defined(USE_GETPWUID)
5966 pwptr = getpwuid(ruid);
5973 && ( errno == ENOENT || errno == ESRCH || errno == EBADF || errno == EPERM)) {
5995#if defined(HAVE_PWD_H)
5998# ifdef USE_GETPWNAM_R
6011 struct passwd *pwptr;
6012#ifdef USE_GETPWNAM_R
6013 struct passwd pwbuf;
6018 getpw_buf_len = GETPW_R_SIZE_INIT;
6019 if (getpw_buf_len < 0) getpw_buf_len = GETPW_R_SIZE_DEFAULT;
6026 while ((e = getpwnam_r(usrname, &pwbuf, getpw_buf, getpw_buf_len, &pwptr)) != 0) {
6027 if (e != ERANGE || getpw_buf_len >= GETPW_R_SIZE_LIMIT) {
6036 pwptr = getpwnam(usrname);
6039#ifndef USE_GETPWNAM_R
6044 uid = pwptr->pw_uid;
6045#ifndef USE_GETPWNAM_R
6052# ifdef p_uid_from_name
6072#if defined(HAVE_GRP_H)
6075# ifdef USE_GETGRNAM_R
6088 struct group *grptr;
6089#ifdef USE_GETGRNAM_R
6095 getgr_buf_len = GETGR_R_SIZE_INIT;
6096 if (getgr_buf_len < 0) getgr_buf_len = GETGR_R_SIZE_DEFAULT;
6103 while ((e = getgrnam_r(grpname, &grbuf, getgr_buf, getgr_buf_len, &grptr)) != 0) {
6104 if (e != ERANGE || getgr_buf_len >= GETGR_R_SIZE_LIMIT) {
6112#elif defined(HAVE_GETGRNAM)
6113 grptr = getgrnam(grpname);
6118#if !defined(USE_GETGRNAM_R) && defined(HAVE_ENDGRENT)
6123 gid = grptr->gr_gid;
6124#if !defined(USE_GETGRNAM_R) && defined(HAVE_ENDGRENT)
6131# ifdef p_gid_from_name
6151#if defined HAVE_SETUID
6169#define p_sys_setuid rb_f_notimplement
6173#if defined HAVE_SETRUID
6191#define p_sys_setruid rb_f_notimplement
6195#if defined HAVE_SETEUID
6213#define p_sys_seteuid rb_f_notimplement
6217#if defined HAVE_SETREUID
6232 rb_uid_t ruid, euid;
6242#define p_sys_setreuid rb_f_notimplement
6246#if defined HAVE_SETRESUID
6261 rb_uid_t ruid, euid, suid;
6268 if (setresuid(ruid, euid, suid) != 0)
rb_sys_fail(0);
6272#define p_sys_setresuid rb_f_notimplement
6288proc_getuid(
VALUE obj)
6295#if defined(HAVE_SETRESUID) || defined(HAVE_SETREUID) || defined(HAVE_SETRUID) || defined(HAVE_SETUID)
6312#if defined(HAVE_SETRESUID)
6314#elif defined HAVE_SETREUID
6316#elif defined HAVE_SETRUID
6318#elif defined HAVE_SETUID
6331#define proc_setuid rb_f_notimplement
6345static rb_uid_t SAVED_USER_ID = -1;
6347#ifdef BROKEN_SETREUID
6349setreuid(rb_uid_t ruid, rb_uid_t euid)
6351 if (ruid != (rb_uid_t)-1 && ruid !=
getuid()) {
6352 if (euid == (rb_uid_t)-1) euid =
geteuid();
6353 if (
setuid(ruid) < 0)
return -1;
6355 if (euid != (rb_uid_t)-1 && euid !=
geteuid()) {
6356 if (seteuid(euid) < 0)
return -1;
6385#if defined(HAVE_SETRESUID)
6387 SAVED_USER_ID = uid;
6388#elif defined(HAVE_SETUID)
6390 SAVED_USER_ID = uid;
6391#elif defined(HAVE_SETREUID) && !defined(OBSOLETE_SETREUID)
6393 if (SAVED_USER_ID == uid) {
6398 if (setreuid(-1, SAVED_USER_ID) < 0)
rb_sys_fail(0);
6399 if (setreuid(SAVED_USER_ID, 0) < 0)
rb_sys_fail(0);
6402 SAVED_USER_ID = uid;
6408 SAVED_USER_ID = uid;
6414 SAVED_USER_ID = uid;
6416#elif defined(HAVE_SETRUID) && defined(HAVE_SETEUID)
6418 if (SAVED_USER_ID == uid) {
6432 SAVED_USER_ID = uid;
6439 SAVED_USER_ID = uid;
6447#if defined(HAVE_SETRESUID)
6448 if (setresuid((
getuid() == uid)? (rb_uid_t)-1: uid,
6449 (
geteuid() == uid)? (rb_uid_t)-1: uid,
6450 (SAVED_USER_ID == uid)? (rb_uid_t)-1: uid) < 0)
rb_sys_fail(0);
6451 SAVED_USER_ID = uid;
6452#elif defined(HAVE_SETREUID) && !defined(OBSOLETE_SETREUID)
6453 if (SAVED_USER_ID == uid) {
6454 if (setreuid((
getuid() == uid)? (rb_uid_t)-1: uid,
6455 (
geteuid() == uid)? (rb_uid_t)-1: uid) < 0)
6458 else if (
getuid() != uid) {
6459 if (setreuid(uid, (
geteuid() == uid)? (rb_uid_t)-1: uid) < 0)
6461 SAVED_USER_ID = uid;
6465 SAVED_USER_ID = uid;
6469 if (setreuid(-1, SAVED_USER_ID) < 0)
rb_sys_fail(0);
6470 if (setreuid(SAVED_USER_ID, uid) < 0)
rb_sys_fail(0);
6471 SAVED_USER_ID = uid;
6474#elif defined(HAVE_SETRUID) && defined(HAVE_SETEUID)
6475 if (SAVED_USER_ID == uid) {
6482 SAVED_USER_ID = uid;
6486 SAVED_USER_ID = uid;
6490 else if (
getuid() == uid) {
6493 SAVED_USER_ID = uid;
6499#elif defined HAVE_44BSD_SETUID
6503 SAVED_USER_ID = uid;
6508#elif defined HAVE_SETEUID
6509 if (
getuid() == uid && SAVED_USER_ID == uid) {
6515#elif defined HAVE_SETUID
6516 if (
getuid() == uid && SAVED_USER_ID == uid) {
6531#if defined HAVE_SETGID
6549#define p_sys_setgid rb_f_notimplement
6553#if defined HAVE_SETRGID
6571#define p_sys_setrgid rb_f_notimplement
6575#if defined HAVE_SETEGID
6593#define p_sys_setegid rb_f_notimplement
6597#if defined HAVE_SETREGID
6612 rb_gid_t rgid, egid;
6620#define p_sys_setregid rb_f_notimplement
6623#if defined HAVE_SETRESGID
6638 rb_gid_t rgid, egid, sgid;
6643 if (setresgid(rgid, egid, sgid) != 0)
rb_sys_fail(0);
6647#define p_sys_setresgid rb_f_notimplement
6651#if defined HAVE_ISSETUGID
6675#define p_sys_issetugid rb_f_notimplement
6691proc_getgid(
VALUE obj)
6698#if defined(HAVE_SETRESGID) || defined(HAVE_SETREGID) || defined(HAVE_SETRGID) || defined(HAVE_SETGID)
6714#if defined(HAVE_SETRESGID)
6716#elif defined HAVE_SETREGID
6718#elif defined HAVE_SETRGID
6720#elif defined HAVE_SETGID
6733#define proc_setgid rb_f_notimplement
6737#if defined(_SC_NGROUPS_MAX) || defined(NGROUPS_MAX)
6758static int _maxgroups = -1;
6760get_sc_ngroups_max(
void)
6762#ifdef _SC_NGROUPS_MAX
6763 return (
int)sysconf(_SC_NGROUPS_MAX);
6764#elif defined(NGROUPS_MAX)
6765 return (
int)NGROUPS_MAX;
6773 if (_maxgroups < 0) {
6774 _maxgroups = get_sc_ngroups_max();
6785#ifdef HAVE_GETGROUPS
6817 ngroups = getgroups(0,
NULL);
6821 groups =
ALLOCV_N(rb_gid_t, tmp, ngroups);
6823 ngroups = getgroups(ngroups, groups);
6828 for (i = 0; i < ngroups; i++)
6836#define proc_getgroups rb_f_notimplement
6840#ifdef HAVE_SETGROUPS
6864 ngroups = RARRAY_LENINT(ary);
6865 if (ngroups > maxgroups())
6868 groups =
ALLOCV_N(rb_gid_t, tmp, ngroups);
6870 for (i = 0; i < ngroups; i++) {
6877 if (setgroups(ngroups, groups) == -1)
6885#define proc_setgroups rb_f_notimplement
6889#ifdef HAVE_INITGROUPS
6916#define proc_initgroups rb_f_notimplement
6919#if defined(_SC_NGROUPS_MAX) || defined(NGROUPS_MAX)
6936#define proc_getmaxgroups rb_f_notimplement
6939#ifdef HAVE_SETGROUPS
6952 int ngroups_max = get_sc_ngroups_max();
6960 if (ngroups_max > 0 && ngroups > ngroups_max)
6961 ngroups = ngroups_max;
6963 _maxgroups = ngroups;
6968#define proc_setmaxgroups rb_f_notimplement
6971#if defined(HAVE_DAEMON) || (defined(HAVE_WORKING_FORK) && defined(HAVE_SETSID))
6972static int rb_daemon(
int nochdir,
int noclose);
6999 n = rb_daemon(nochdir, noclose);
7005rb_daemon(
int nochdir,
int noclose)
7011 err = daemon(nochdir, noclose);
7017#define fork_daemon() \
7018 switch (rb_fork_ruby(NULL)) { \
7019 case -1: return -1; \
7020 case 0: rb_thread_atfork(); break; \
7021 default: _exit(EXIT_SUCCESS); \
7026 if (setsid() < 0)
return -1;
7034 if (!noclose && (n =
rb_cloexec_open(
"/dev/null", O_RDWR, 0)) != -1) {
7046#define proc_daemon rb_f_notimplement
7059static rb_gid_t SAVED_GROUP_ID = -1;
7061#ifdef BROKEN_SETREGID
7063setregid(rb_gid_t rgid, rb_gid_t egid)
7065 if (rgid != (rb_gid_t)-1 && rgid !=
getgid()) {
7066 if (egid == (rb_gid_t)-1) egid =
getegid();
7067 if (
setgid(rgid) < 0)
return -1;
7069 if (egid != (rb_gid_t)-1 && egid !=
getegid()) {
7070 if (setegid(egid) < 0)
return -1;
7099#if defined(HAVE_SETRESGID)
7101 SAVED_GROUP_ID = gid;
7102#elif defined HAVE_SETGID
7104 SAVED_GROUP_ID = gid;
7105#elif defined(HAVE_SETREGID) && !defined(OBSOLETE_SETREGID)
7107 if (SAVED_GROUP_ID == gid) {
7112 if (setregid(-1, SAVED_GROUP_ID) < 0)
rb_sys_fail(0);
7113 if (setregid(SAVED_GROUP_ID, 0) < 0)
rb_sys_fail(0);
7116 SAVED_GROUP_ID = gid;
7122 SAVED_GROUP_ID = gid;
7128 SAVED_GROUP_ID = gid;
7130#elif defined(HAVE_SETRGID) && defined (HAVE_SETEGID)
7132 if (SAVED_GROUP_ID == gid) {
7147 SAVED_GROUP_ID = gid;
7154 SAVED_GROUP_ID = gid;
7161#if defined(HAVE_SETRESGID)
7162 if (setresgid((
getgid() == gid)? (rb_gid_t)-1: gid,
7163 (
getegid() == gid)? (rb_gid_t)-1: gid,
7164 (SAVED_GROUP_ID == gid)? (rb_gid_t)-1: gid) < 0)
rb_sys_fail(0);
7165 SAVED_GROUP_ID = gid;
7166#elif defined(HAVE_SETREGID) && !defined(OBSOLETE_SETREGID)
7167 if (SAVED_GROUP_ID == gid) {
7168 if (setregid((
getgid() == gid)? (rb_uid_t)-1: gid,
7169 (
getegid() == gid)? (rb_uid_t)-1: gid) < 0)
7172 else if (
getgid() != gid) {
7173 if (setregid(gid, (
getegid() == gid)? (rb_uid_t)-1: gid) < 0)
7175 SAVED_GROUP_ID = gid;
7179 SAVED_GROUP_ID = gid;
7183 if (setregid(-1, SAVED_GROUP_ID) < 0)
rb_sys_fail(0);
7184 if (setregid(SAVED_GROUP_ID, gid) < 0)
rb_sys_fail(0);
7185 SAVED_GROUP_ID = gid;
7188#elif defined(HAVE_SETRGID) && defined(HAVE_SETEGID)
7189 if (SAVED_GROUP_ID == gid) {
7196 SAVED_GROUP_ID = gid;
7200 SAVED_GROUP_ID = gid;
7204 else if (
getgid() == gid) {
7207 SAVED_GROUP_ID = gid;
7213#elif defined HAVE_44BSD_SETGID
7217 SAVED_GROUP_ID = gid;
7222#elif defined HAVE_SETEGID
7223 if (
getgid() == gid && SAVED_GROUP_ID == gid) {
7229#elif defined HAVE_SETGID
7230 if (
getgid() == gid && SAVED_GROUP_ID == gid) {
7257proc_geteuid(
VALUE obj)
7263#if defined(HAVE_SETRESUID) || defined(HAVE_SETREUID) || defined(HAVE_SETEUID) || defined(HAVE_SETUID) || defined(_POSIX_SAVED_IDS)
7265proc_seteuid(rb_uid_t uid)
7267#if defined(HAVE_SETRESUID)
7269#elif defined HAVE_SETREUID
7271#elif defined HAVE_SETEUID
7273#elif defined HAVE_SETUID
7286#if defined(HAVE_SETRESUID) || defined(HAVE_SETREUID) || defined(HAVE_SETEUID) || defined(HAVE_SETUID)
7303#define proc_seteuid_m rb_f_notimplement
7307rb_seteuid_core(rb_uid_t euid)
7309#if defined(HAVE_SETRESUID) || (defined(HAVE_SETREUID) && !defined(OBSOLETE_SETREUID))
7315#if defined(HAVE_SETRESUID) || (defined(HAVE_SETREUID) && !defined(OBSOLETE_SETREUID))
7319#if defined(HAVE_SETRESUID)
7322 SAVED_USER_ID = euid;
7327#elif defined(HAVE_SETREUID) && !defined(OBSOLETE_SETREUID)
7332 SAVED_USER_ID = euid;
7334#elif defined HAVE_SETEUID
7336#elif defined HAVE_SETUID
7381proc_getegid(
VALUE obj)
7388#if defined(HAVE_SETRESGID) || defined(HAVE_SETREGID) || defined(HAVE_SETEGID) || defined(HAVE_SETGID) || defined(_POSIX_SAVED_IDS)
7400#if defined(HAVE_SETRESGID) || defined(HAVE_SETREGID) || defined(HAVE_SETEGID) || defined(HAVE_SETGID)
7406#if defined(HAVE_SETRESGID) || defined(HAVE_SETREGID) || defined(HAVE_SETEGID) || defined(HAVE_SETGID)
7410#if defined(HAVE_SETRESGID)
7412#elif defined HAVE_SETREGID
7414#elif defined HAVE_SETEGID
7416#elif defined HAVE_SETGID
7430#if defined(HAVE_SETRESGID) || defined(HAVE_SETREGID) || defined(HAVE_SETEGID) || defined(HAVE_SETGID)
7431#define proc_setegid_m proc_setegid
7433#define proc_setegid_m rb_f_notimplement
7437rb_setegid_core(rb_gid_t egid)
7439#if defined(HAVE_SETRESGID) || (defined(HAVE_SETREGID) && !defined(OBSOLETE_SETREGID))
7445#if defined(HAVE_SETRESGID) || (defined(HAVE_SETREGID) && !defined(OBSOLETE_SETREGID))
7449#if defined(HAVE_SETRESGID)
7452 SAVED_GROUP_ID = egid;
7457#elif defined(HAVE_SETREGID) && !defined(OBSOLETE_SETREGID)
7462 SAVED_GROUP_ID = egid;
7464#elif defined HAVE_SETEGID
7466#elif defined HAVE_SETGID
7508p_uid_exchangeable(
VALUE _)
7510#if defined(HAVE_SETRESUID)
7512#elif defined(HAVE_SETREUID) && !defined(OBSOLETE_SETREUID)
7533p_uid_exchange(
VALUE obj)
7536#if defined(HAVE_SETRESUID) || (defined(HAVE_SETREUID) && !defined(OBSOLETE_SETREUID))
7543#if defined(HAVE_SETRESUID) || (defined(HAVE_SETREUID) && !defined(OBSOLETE_SETREUID))
7547#if defined(HAVE_SETRESUID)
7548 if (setresuid(euid, uid, uid) < 0)
rb_sys_fail(0);
7549 SAVED_USER_ID = uid;
7550#elif defined(HAVE_SETREUID) && !defined(OBSOLETE_SETREUID)
7552 SAVED_USER_ID = uid;
7570p_gid_exchangeable(
VALUE _)
7572#if defined(HAVE_SETRESGID)
7574#elif defined(HAVE_SETREGID) && !defined(OBSOLETE_SETREGID)
7595p_gid_exchange(
VALUE obj)
7598#if defined(HAVE_SETRESGID) || (defined(HAVE_SETREGID) && !defined(OBSOLETE_SETREGID))
7605#if defined(HAVE_SETRESGID) || (defined(HAVE_SETREGID) && !defined(OBSOLETE_SETREGID))
7609#if defined(HAVE_SETRESGID)
7610 if (setresgid(egid, gid, gid) < 0)
rb_sys_fail(0);
7611 SAVED_GROUP_ID = gid;
7612#elif defined(HAVE_SETREGID) && !defined(OBSOLETE_SETREGID)
7614 SAVED_GROUP_ID = gid;
7633p_uid_have_saved_id(
VALUE _)
7635#if defined(HAVE_SETRESUID) || defined(HAVE_SETEUID) || defined(_POSIX_SAVED_IDS)
7643#if defined(HAVE_SETRESUID) || defined(HAVE_SETEUID) || defined(_POSIX_SAVED_IDS)
7645p_uid_sw_ensure(
VALUE i)
7647 rb_uid_t
id = (rb_uid_t)i;
7648 under_uid_switch = 0;
7649 id = rb_seteuid_core(
id);
7668p_uid_switch(
VALUE obj)
7680 under_uid_switch = 1;
7687 else if (euid != SAVED_USER_ID) {
7688 proc_seteuid(SAVED_USER_ID);
7690 under_uid_switch = 1;
7705p_uid_sw_ensure(
VALUE obj)
7707 under_uid_switch = 0;
7708 return p_uid_exchange(obj);
7712p_uid_switch(
VALUE obj)
7724 p_uid_exchange(obj);
7726 under_uid_switch = 1;
7748p_gid_have_saved_id(
VALUE _)
7750#if defined(HAVE_SETRESGID) || defined(HAVE_SETEGID) || defined(_POSIX_SAVED_IDS)
7757#if defined(HAVE_SETRESGID) || defined(HAVE_SETEGID) || defined(_POSIX_SAVED_IDS)
7759p_gid_sw_ensure(
VALUE i)
7761 rb_gid_t
id = (rb_gid_t)i;
7762 under_gid_switch = 0;
7763 id = rb_setegid_core(
id);
7782p_gid_switch(
VALUE obj)
7794 under_gid_switch = 1;
7801 else if (egid != SAVED_GROUP_ID) {
7802 proc_setegid(obj,
GIDT2NUM(SAVED_GROUP_ID));
7804 under_gid_switch = 1;
7819p_gid_sw_ensure(
VALUE obj)
7821 under_gid_switch = 0;
7822 return p_gid_exchange(obj);
7826p_gid_switch(
VALUE obj)
7838 p_gid_exchange(obj);
7840 under_gid_switch = 1;
7850#if defined(HAVE_TIMES)
7854#ifdef HAVE__SC_CLK_TCK
7855 return sysconf(_SC_CLK_TCK);
7856#elif defined CLK_TCK
7880 VALUE utime, stime, cutime, cstime, ret;
7881#if defined(RUSAGE_SELF) && defined(RUSAGE_CHILDREN)
7882 struct rusage usage_s, usage_c;
7884 if (getrusage(RUSAGE_SELF, &usage_s) != 0 || getrusage(RUSAGE_CHILDREN, &usage_c) != 0)
7886 utime =
DBL2NUM((
double)usage_s.ru_utime.tv_sec + (
double)usage_s.ru_utime.tv_usec/1e6);
7887 stime =
DBL2NUM((
double)usage_s.ru_stime.tv_sec + (
double)usage_s.ru_stime.tv_usec/1e6);
7888 cutime =
DBL2NUM((
double)usage_c.ru_utime.tv_sec + (
double)usage_c.ru_utime.tv_usec/1e6);
7889 cstime =
DBL2NUM((
double)usage_c.ru_stime.tv_sec + (
double)usage_c.ru_stime.tv_usec/1e6);
7891 const double hertz = (double)get_clk_tck();
7900 ret =
rb_struct_new(rb_cProcessTms, utime, stime, cutime, cstime);
7908#define rb_proc_times rb_f_notimplement
7911#ifdef HAVE_LONG_LONG
7913#define TIMETICK_INT_MIN LLONG_MIN
7914#define TIMETICK_INT_MAX LLONG_MAX
7915#define TIMETICK_INT2NUM(v) LL2NUM(v)
7916#define MUL_OVERFLOW_TIMETICK_P(a, b) MUL_OVERFLOW_LONG_LONG_P(a, b)
7919#define TIMETICK_INT_MIN LONG_MIN
7920#define TIMETICK_INT_MAX LONG_MAX
7921#define TIMETICK_INT2NUM(v) LONG2NUM(v)
7922#define MUL_OVERFLOW_TIMETICK_P(a, b) MUL_OVERFLOW_LONG_P(a, b)
7961 for (i = 0; i < num_numerators; i++) {
7962 if (numerators[i] == 1)
7964 for (j = 0; j < num_denominators; j++) {
7965 if (denominators[j] == 1)
7967 reduce_fraction(&numerators[i], &denominators[j]);
7978timetick2dblnum(
struct timetick *ttp,
7985 reduce_factors(numerators, num_numerators,
7986 denominators, num_denominators);
7990 for (i = 0; i < num_numerators; i++)
7992 for (i = 0; i < num_denominators; i++)
7993 d /= denominators[i];
7999timetick2dblnum_reciprocal(
struct timetick *ttp,
8006 reduce_factors(numerators, num_numerators,
8007 denominators, num_denominators);
8010 for (i = 0; i < num_denominators; i++)
8011 d *= denominators[i];
8012 for (i = 0; i < num_numerators; i++)
8019#define NDIV(x,y) (-(-((x)+1)/(y))-1)
8020#define DIV(n,d) ((n)<0 ? NDIV((n),(d)) : (n)/(d))
8023timetick2integer(
struct timetick *ttp,
8030 reduce_factors(numerators, num_numerators,
8031 denominators, num_denominators);
8036 for (i = 0; i < num_numerators; i++) {
8042 for (i = 0; i < num_denominators; i++) {
8043 t =
DIV(
t, denominators[i]);
8052 for (i = 0; i < num_numerators; i++) {
8058 for (i = 0; i < num_denominators; i++) {
8065make_clock_result(
struct timetick *ttp,
8070 if (unit ==
ID2SYM(id_nanosecond)) {
8071 numerators[num_numerators++] = 1000000000;
8072 return timetick2integer(ttp, numerators, num_numerators, denominators, num_denominators);
8074 else if (unit ==
ID2SYM(id_microsecond)) {
8075 numerators[num_numerators++] = 1000000;
8076 return timetick2integer(ttp, numerators, num_numerators, denominators, num_denominators);
8078 else if (unit ==
ID2SYM(id_millisecond)) {
8079 numerators[num_numerators++] = 1000;
8080 return timetick2integer(ttp, numerators, num_numerators, denominators, num_denominators);
8082 else if (unit ==
ID2SYM(id_second)) {
8083 return timetick2integer(ttp, numerators, num_numerators, denominators, num_denominators);
8085 else if (unit ==
ID2SYM(id_float_microsecond)) {
8086 numerators[num_numerators++] = 1000000;
8087 return timetick2dblnum(ttp, numerators, num_numerators, denominators, num_denominators);
8089 else if (unit ==
ID2SYM(id_float_millisecond)) {
8090 numerators[num_numerators++] = 1000;
8091 return timetick2dblnum(ttp, numerators, num_numerators, denominators, num_denominators);
8093 else if (
NIL_P(unit) || unit ==
ID2SYM(id_float_second)) {
8094 return timetick2dblnum(ttp, numerators, num_numerators, denominators, num_denominators);
8101static const mach_timebase_info_data_t *
8102get_mach_timebase_info(
void)
8104 static mach_timebase_info_data_t sTimebaseInfo;
8106 if ( sTimebaseInfo.denom == 0 ) {
8107 (void) mach_timebase_info(&sTimebaseInfo);
8110 return &sTimebaseInfo;
8114ruby_real_ms_time(
void)
8116 const mach_timebase_info_data_t *info = get_mach_timebase_info();
8118 return (
double)
t * info->numer / info->denom / 1e6;
8257 int num_numerators = 0;
8258 int num_denominators = 0;
8267#ifdef HAVE_GETTIMEOFDAY
8272#define RUBY_GETTIMEOFDAY_BASED_CLOCK_REALTIME ID2SYM(id_GETTIMEOFDAY_BASED_CLOCK_REALTIME)
8273 if (clk_id == RUBY_GETTIMEOFDAY_BASED_CLOCK_REALTIME) {
8280 denominators[num_denominators++] = 1000000000;
8285#define RUBY_TIME_BASED_CLOCK_REALTIME ID2SYM(id_TIME_BASED_CLOCK_REALTIME)
8289 if (
t == (time_t)-1)
8293 denominators[num_denominators++] = 1000000000;
8298#define RUBY_TIMES_BASED_CLOCK_MONOTONIC \
8299 ID2SYM(id_TIMES_BASED_CLOCK_MONOTONIC)
8300 if (clk_id == RUBY_TIMES_BASED_CLOCK_MONOTONIC) {
8305 if (c == (clock_t)-1)
8308 tt.
count = (int32_t)(uc % 1000000000);
8310 denominators[num_denominators++] = get_clk_tck();
8316#define RUBY_GETRUSAGE_BASED_CLOCK_PROCESS_CPUTIME_ID \
8317 ID2SYM(id_GETRUSAGE_BASED_CLOCK_PROCESS_CPUTIME_ID)
8318 if (clk_id == RUBY_GETRUSAGE_BASED_CLOCK_PROCESS_CPUTIME_ID) {
8319 struct rusage usage;
8321 ret = getrusage(RUSAGE_SELF, &usage);
8324 tt.
giga_count = usage.ru_utime.tv_sec + usage.ru_stime.tv_sec;
8325 usec = (int32_t)(usage.ru_utime.tv_usec + usage.ru_stime.tv_usec);
8326 if (1000000 <= usec) {
8330 tt.
count = usec * 1000;
8331 denominators[num_denominators++] = 1000000000;
8337#define RUBY_TIMES_BASED_CLOCK_PROCESS_CPUTIME_ID \
8338 ID2SYM(id_TIMES_BASED_CLOCK_PROCESS_CPUTIME_ID)
8339 if (clk_id == RUBY_TIMES_BASED_CLOCK_PROCESS_CPUTIME_ID) {
8342 if (times(&
buf) == (clock_t)-1)
8346 tt.
count = (int32_t)((utime % 1000000000) + (stime % 1000000000));
8347 tt.
giga_count = (utime / 1000000000) + (stime / 1000000000);
8348 if (1000000000 <= tt.
count) {
8349 tt.
count -= 1000000000;
8352 denominators[num_denominators++] = get_clk_tck();
8357#define RUBY_CLOCK_BASED_CLOCK_PROCESS_CPUTIME_ID \
8358 ID2SYM(id_CLOCK_BASED_CLOCK_PROCESS_CPUTIME_ID)
8364 if (c == (clock_t)-1)
8367 tt.
count = (int32_t)(uc % 1000000000);
8369 denominators[num_denominators++] = CLOCKS_PER_SEC;
8374#define RUBY_MACH_ABSOLUTE_TIME_BASED_CLOCK_MONOTONIC ID2SYM(id_MACH_ABSOLUTE_TIME_BASED_CLOCK_MONOTONIC)
8375 if (clk_id == RUBY_MACH_ABSOLUTE_TIME_BASED_CLOCK_MONOTONIC) {
8376 const mach_timebase_info_data_t *info = get_mach_timebase_info();
8378 tt.
count = (int32_t)(
t % 1000000000);
8380 numerators[num_numerators++] = info->numer;
8381 denominators[num_denominators++] = info->denom;
8382 denominators[num_denominators++] = 1000000000;
8388#if defined(HAVE_CLOCK_GETTIME)
8391 c = NUM2CLOCKID(clk_id);
8397 denominators[num_denominators++] = 1000000000;
8405 return make_clock_result(&tt, numerators, num_numerators, denominators, num_denominators, unit);
8456 int num_numerators = 0;
8457 int num_denominators = 0;
8463#ifdef RUBY_GETTIMEOFDAY_BASED_CLOCK_REALTIME
8464 if (clk_id == RUBY_GETTIMEOFDAY_BASED_CLOCK_REALTIME) {
8467 denominators[num_denominators++] = 1000000000;
8472#ifdef RUBY_TIME_BASED_CLOCK_REALTIME
8476 denominators[num_denominators++] = 1000000000;
8481#ifdef RUBY_TIMES_BASED_CLOCK_MONOTONIC
8482 if (clk_id == RUBY_TIMES_BASED_CLOCK_MONOTONIC) {
8485 denominators[num_denominators++] = get_clk_tck();
8490#ifdef RUBY_GETRUSAGE_BASED_CLOCK_PROCESS_CPUTIME_ID
8491 if (clk_id == RUBY_GETRUSAGE_BASED_CLOCK_PROCESS_CPUTIME_ID) {
8494 denominators[num_denominators++] = 1000000000;
8499#ifdef RUBY_TIMES_BASED_CLOCK_PROCESS_CPUTIME_ID
8500 if (clk_id == RUBY_TIMES_BASED_CLOCK_PROCESS_CPUTIME_ID) {
8503 denominators[num_denominators++] = get_clk_tck();
8508#ifdef RUBY_CLOCK_BASED_CLOCK_PROCESS_CPUTIME_ID
8512 denominators[num_denominators++] = CLOCKS_PER_SEC;
8517#ifdef RUBY_MACH_ABSOLUTE_TIME_BASED_CLOCK_MONOTONIC
8518 if (clk_id == RUBY_MACH_ABSOLUTE_TIME_BASED_CLOCK_MONOTONIC) {
8519 const mach_timebase_info_data_t *info = get_mach_timebase_info();
8522 numerators[num_numerators++] = info->numer;
8523 denominators[num_denominators++] = info->denom;
8524 denominators[num_denominators++] = 1000000000;
8530#if defined(HAVE_CLOCK_GETRES)
8538 denominators[num_denominators++] = 1000000000;
8546 if (unit ==
ID2SYM(id_hertz)) {
8547 return timetick2dblnum_reciprocal(&tt, numerators, num_numerators, denominators, num_denominators);
8550 return make_clock_result(&tt, numerators, num_numerators, denominators, num_denominators, unit);
8555get_CHILD_STATUS(
ID _x,
VALUE *_y)
8561get_PROCESS_ID(
ID _x,
VALUE *_y)
8609static VALUE rb_mProcUID;
8610static VALUE rb_mProcGID;
8611static VALUE rb_mProcID_Syscall;
8680 process_status_dump, process_status_load);
8716#ifdef HAVE_GETPRIORITY
8727#if defined(RLIM2NUM) && defined(RLIM_INFINITY)
8729 VALUE inf = RLIM2NUM(RLIM_INFINITY);
8730#ifdef RLIM_SAVED_MAX
8732 VALUE v = RLIM_INFINITY == RLIM_SAVED_MAX ?
inf : RLIM2NUM(RLIM_SAVED_MAX);
8739#ifdef RLIM_SAVED_CUR
8741 VALUE v = RLIM_INFINITY == RLIM_SAVED_CUR ?
inf : RLIM2NUM(RLIM_SAVED_CUR);
8782#ifdef RLIMIT_MEMLOCK
8789#ifdef RLIMIT_MSGQUEUE
8847#ifdef RLIMIT_SIGPENDING
8882#ifdef CLOCK_REALTIME
8885#elif defined(RUBY_GETTIMEOFDAY_BASED_CLOCK_REALTIME)
8889#ifdef CLOCK_MONOTONIC
8892#elif defined(RUBY_MACH_ABSOLUTE_TIME_BASED_CLOCK_MONOTONIC)
8896#ifdef CLOCK_PROCESS_CPUTIME_ID
8899#elif defined(RUBY_GETRUSAGE_BASED_CLOCK_PROCESS_CPUTIME_ID)
8903#ifdef CLOCK_THREAD_CPUTIME_ID
8915#ifdef CLOCK_REALTIME_FAST
8919#ifdef CLOCK_REALTIME_PRECISE
8923#ifdef CLOCK_REALTIME_COARSE
8927#ifdef CLOCK_REALTIME_ALARM
8931#ifdef CLOCK_MONOTONIC_FAST
8935#ifdef CLOCK_MONOTONIC_PRECISE
8939#ifdef CLOCK_MONOTONIC_RAW
8943#ifdef CLOCK_MONOTONIC_RAW_APPROX
8947#ifdef CLOCK_MONOTONIC_COARSE
8951#ifdef CLOCK_BOOTTIME
8955#ifdef CLOCK_BOOTTIME_ALARM
8963#ifdef CLOCK_UPTIME_FAST
8967#ifdef CLOCK_UPTIME_PRECISE
8971#ifdef CLOCK_UPTIME_RAW
8975#ifdef CLOCK_UPTIME_RAW_APPROX
8990#if defined(HAVE_TIMES) || defined(_WIN32)
9019#ifdef p_uid_from_name
9022#ifdef p_gid_from_name
9053 id_in = rb_intern_const(
"in");
9054 id_out = rb_intern_const(
"out");
9055 id_err = rb_intern_const(
"err");
9056 id_pid = rb_intern_const(
"pid");
9057 id_uid = rb_intern_const(
"uid");
9058 id_gid = rb_intern_const(
"gid");
9059 id_close = rb_intern_const(
"close");
9060 id_child = rb_intern_const(
"child");
9062 id_pgroup = rb_intern_const(
"pgroup");
9065 id_new_pgroup = rb_intern_const(
"new_pgroup");
9067 id_unsetenv_others = rb_intern_const(
"unsetenv_others");
9068 id_chdir = rb_intern_const(
"chdir");
9069 id_umask = rb_intern_const(
"umask");
9070 id_close_others = rb_intern_const(
"close_others");
9071 id_ENV = rb_intern_const(
"ENV");
9072 id_nanosecond = rb_intern_const(
"nanosecond");
9073 id_microsecond = rb_intern_const(
"microsecond");
9074 id_millisecond = rb_intern_const(
"millisecond");
9075 id_second = rb_intern_const(
"second");
9076 id_float_microsecond = rb_intern_const(
"float_microsecond");
9077 id_float_millisecond = rb_intern_const(
"float_millisecond");
9078 id_float_second = rb_intern_const(
"float_second");
9079 id_GETTIMEOFDAY_BASED_CLOCK_REALTIME = rb_intern_const(
"GETTIMEOFDAY_BASED_CLOCK_REALTIME");
9080 id_TIME_BASED_CLOCK_REALTIME = rb_intern_const(
"TIME_BASED_CLOCK_REALTIME");
9082 id_TIMES_BASED_CLOCK_MONOTONIC = rb_intern_const(
"TIMES_BASED_CLOCK_MONOTONIC");
9083 id_TIMES_BASED_CLOCK_PROCESS_CPUTIME_ID = rb_intern_const(
"TIMES_BASED_CLOCK_PROCESS_CPUTIME_ID");
9086 id_GETRUSAGE_BASED_CLOCK_PROCESS_CPUTIME_ID = rb_intern_const(
"GETRUSAGE_BASED_CLOCK_PROCESS_CPUTIME_ID");
9088 id_CLOCK_BASED_CLOCK_PROCESS_CPUTIME_ID = rb_intern_const(
"CLOCK_BASED_CLOCK_PROCESS_CPUTIME_ID");
9090 id_MACH_ABSOLUTE_TIME_BASED_CLOCK_MONOTONIC = rb_intern_const(
"MACH_ABSOLUTE_TIME_BASED_CLOCK_MONOTONIC");
9092 id_hertz = rb_intern_const(
"hertz");
#define COROUTINE_STACK_LOCAL(type, name)
#define COROUTINE_STACK_FREE(name)
void rb_ary_store(VALUE ary, long idx, VALUE val)
VALUE rb_ary_dup(VALUE ary)
VALUE rb_ary_push(VALUE ary, VALUE item)
VALUE rb_check_array_type(VALUE ary)
VALUE rb_ary_entry(VALUE ary, long offset)
VALUE rb_assoc_new(VALUE car, VALUE cdr)
#define UNREACHABLE_RETURN
#define MUL_OVERFLOW_SIGNED_INTEGER_P(a, b, min, max)
Internal header for bitwise integer algorithms.
int ruby_thread_has_gvl_p(void)
Our own, locale independent, character handling routines.
#define rb_define_method(klass, mid, func, arity)
Defines klass#mid.
#define rb_define_singleton_method(klass, mid, func, arity)
Defines klass.mid.
#define rb_define_module_function(klass, mid, func, arity)
Defines klass#mid and makes it a module function.
#define rb_define_global_function(mid, func, arity)
Defines rb_mKernel #mid.
VALUE rb_dir_getwd_ospath(void)
char * strchr(char *, char)
void rb_enc_copy(VALUE obj1, VALUE obj2)
char str[HTML_ESCAPE_MAX_LEN+1]
VALUE rb_ec_get_errinfo(const rb_execution_context_t *ec)
void rb_ec_error_print(rb_execution_context_t *volatile ec, volatile VALUE errinfo)
#define RSTRING_LEN(string)
#define RSTRING_PTR(string)
VALUE rb_str_encode_ospath(VALUE path)
void rb_gc_mark(VALUE ptr)
void * ruby_xmalloc(size_t size)
Allocates a storage instance.
VALUE rb_singleton_class(VALUE obj)
Returns the singleton class of obj.
VALUE rb_define_class_under(VALUE outer, const char *name, VALUE super)
Defines a class under the namespace of outer.
VALUE rb_define_module(const char *name)
VALUE rb_define_module_under(VALUE outer, const char *name)
void rb_undef_method(VALUE klass, const char *name)
void rb_define_alias(VALUE klass, const char *name1, const char *name2)
Defines an alias of a method.
int rb_block_given_p(void)
Determines if the current method is given a block.
void ruby_stop(int ex)
Calls ruby_cleanup() and exits the process.
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(*proc)(VALUE), VALUE data, int *pstate)
Protects a function call from potential global escapes from the function.
void * rb_check_typeddata(VALUE obj, const rb_data_type_t *data_type)
void rb_warn(const char *fmt,...)
VALUE rb_exc_new_str(VALUE etype, VALUE str)
VALUE rb_ensure(VALUE(*b_proc)(VALUE), VALUE data1, VALUE(*e_proc)(VALUE), VALUE data2)
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_cObject
Object class.
VALUE rb_class_new_instance(int, const VALUE *, VALUE)
Allocates and initializes an instance of klass.
VALUE rb_equal(VALUE, VALUE)
This function is an optimized version of calling #==.
VALUE rb_obj_freeze(VALUE)
Make the object unmodifiable.
VALUE rb_to_int(VALUE)
Converts val into Integer.
unsigned short prefix[65536]
unsigned gcd(unsigned a, unsigned b)
VALUE rb_to_hash_type(VALUE hash)
VALUE rb_check_hash_type(VALUE hash)
int rb_hash_stlike_foreach(VALUE hash, st_foreach_callback_func *func, st_data_t arg)
VALUE rb_hash_aset(VALUE hash, VALUE key, VALUE val)
VALUE rb_hash_lookup(VALUE hash, VALUE key)
void ruby_setenv(const char *name, const char *value)
#define RB_HRTIME_PER_MSEC
Thin wrapper to ruby/config.h.
VALUE rb_funcall(VALUE, ID, int,...)
Calls a method.
#define UNLIMITED_ARGUMENTS
int rb_cloexec_dup2(int oldfd, int newfd)
void rb_update_max_fd(int fd)
int rb_cloexec_open(const char *pathname, int flags, mode_t mode)
void rb_close_before_exec(int lowfd, int maxhint, VALUE noclose_fds)
int rb_reserved_fd_p(int fd)
VALUE rb_io_puts(int, const VALUE *, VALUE)
int rb_cloexec_fcntl_dupfd(int fd, int minfd)
int rb_cloexec_dup(int oldfd)
VALUE rb_f_kill(int, const VALUE *)
const char * ruby_signal_name(int)
VALUE rb_str_resize(VALUE, long)
#define rb_str_new(str, len)
void rb_str_set_len(VALUE, long)
VALUE rb_str_buf_new(long)
VALUE rb_check_string_type(VALUE)
VALUE rb_str_tmp_new(long)
VALUE rb_str_subseq(VALUE, long, long)
VALUE rb_str_append(VALUE, VALUE)
VALUE rb_str_new_frozen(VALUE)
void rb_str_modify_expand(VALUE, long)
#define rb_str_cat_cstr(buf, str)
size_t rb_str_capacity(VALUE)
#define rb_str_new_cstr(str)
VALUE rb_struct_define_under(VALUE, const char *,...)
VALUE rb_struct_new(VALUE,...)
void rb_thread_wait_for(struct timeval)
VALUE rb_thread_local_aref(VALUE, ID)
void rb_thread_sleep_forever(void)
void rb_thread_check_ints(void)
void rb_thread_atfork(void)
void rb_thread_sleep(int)
VALUE rb_thread_local_aset(VALUE, ID, VALUE)
struct timeval rb_time_interval(VALUE num)
VALUE rb_const_get(VALUE, ID)
VALUE rb_attr_get(VALUE, ID)
VALUE rb_ivar_set(VALUE, ID, VALUE)
void rb_define_alloc_func(VALUE, rb_alloc_func_t)
void rb_undef_alloc_func(VALUE)
ID rb_check_id(volatile VALUE *)
Returns ID for the given name if it is interned already, or 0.
void rb_define_const(VALUE, const char *, VALUE)
int rb_io_modestr_oflags(const char *modestr)
VALUE rb_io_check_io(VALUE io)
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)
Internal header for Hash.
Internal header for Object.
Internal header for Process.
rb_pid_t rb_fork_ruby(int *status)
rb_pid_t rb_fork_async_signal_safe(int *status, int(*chfunc)(void *, char *, size_t), void *charg, VALUE fds, char *errmsg, size_t errmsg_buflen)
Internal header for Thread.
void rb_gvar_ractor_local(const char *name)
typedef int(ZCALLBACK *close_file_func) OF((voidpf opaque
#define RB_BLOCK_CALL_FUNC_ARGLIST(yielded_arg, callback_arg)
void rb_marshal_define_compat(VALUE newclass, VALUE oldclass, VALUE(*dumper)(VALUE), VALUE(*loader)(VALUE, VALUE))
#define MEMCPY(p1, p2, type, n)
#define MEMZERO(p, type, n)
VALUE rb_thread_create(type *q, void *w)
Creates a rb_cThread instance.
VALUE rb_block_call(VALUE q, ID w, int e, const VALUE *r, type *t, VALUE y)
Call a method with a block.
void rb_define_virtual_variable(const char *q, type *w, void_type *e)
Define a function-backended global variable.
struct rb_execarg * rb_execarg_get(VALUE execarg_obj)
VALUE rb_process_status_new(rb_pid_t pid, int status, int error)
#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)
VALUE rb_process_status_waitv(int argc, VALUE *argv, VALUE _)
#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)
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)
VALUE rb_process_status_wait(rb_pid_t pid, int flags)
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)
#define RARRAY_AREF(a, i)
#define WIFSTOPPED(status)
VALUE rb_ractor_stderr(void)
#define RUBY_DEFAULT_FREE
#define RB_OBJ_WRITTEN(a, oldv, b)
WB for new reference from ‘a’ to ‘b’.
#define SafeStringValue(v)
#define StringValueCStr(v)
#define RTYPEDDATA_DATA(v)
#define RUBY_TYPED_DEFAULT_FREE
#define TypedData_Get_Struct(obj, type, data_type, sval)
@ RUBY_TYPED_FREE_IMMEDIATELY
#define TypedData_Make_Struct(klass, type, data_type, sval)
const char * rb_class2name(VALUE)
Internal header for Scheduler.
VALUE rb_scheduler_current()
VALUE rb_scheduler_kernel_sleepv(VALUE scheduler, int argc, VALUE *argv)
VALUE rb_scheduler_process_wait(VALUE scheduler, rb_pid_t pid, int flags)
int rb_scheduler_supports_process_wait(VALUE scheduler)
unsigned long long uint64_t
VALUE rb_str_catf(VALUE, const char *,...)
VALUE rb_sprintf(const char *,...)
size_t strlen(const char *)
const char * wrap_struct_name
struct rb_execarg::@113::@114 sh
unsigned unsetenv_others_given
unsigned new_pgroup_given
struct waitpid_state * waitpid_state
struct rb_execarg::@113::@115 cmd
unsigned unsetenv_others_do
unsigned close_others_given
union rb_execarg::@113 invoke
VALUE tied_io_for_writing
rb_nativethread_lock_t waitpid_lock
struct list_head waiting_pids
struct list_head waiting_grps
struct spawn_args::@140 errmsg
timetick_int_t giga_count
rb_nativethread_cond_t * cond
rb_execution_context_t * ec
void rb_threadptr_pending_interrupt_clear(rb_thread_t *th)
void rb_thread_reset_timer_thread(void)
void rb_thread_stop_timer_thread(void)
void rb_threadptr_interrupt(rb_thread_t *th)
void rb_thread_start_timer_thread(void)
void error(const char *msg)
#define WAITPID_USE_SIGCHLD
#define RUBY_VM_CHECK_INTS(ec)
Internal header to suppres / mandate warnings.
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)
int clock_gettime(clockid_t, struct timespec *)
int clock_getres(clockid_t, struct timespec *)
rb_pid_t rb_w32_uspawn(int, const char *, const char *)
rb_pid_t rb_w32_uaspawn(int, const char *, char *const *)
int inf(FILE *source, FILE *dest)
int write(ozstream &zs, const T *x, Items items)
int read(izstream &zs, T *x, Items items)