14 #include "ruby/config.h"
42 #define EXIT_SUCCESS 0
45 #define EXIT_FAILURE 1
48 #ifdef HAVE_SYS_WAIT_H
49 # include <sys/wait.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
67 #ifdef HAVE_SYS_TIME_H
70 #ifdef HAVE_SYS_TIMES_H
71 #include <sys/times.h>
80 int 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)
98 static 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
148 static void check_uid_switch(
void);
149 static void check_gid_switch(
void);
150 static 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_PWD_H)
158 # if defined(HAVE_GETPWNAM_R) && defined(_SC_GETPW_R_SIZE_MAX)
159 # define USE_GETPWNAM_R 1
160 # define GETPW_R_SIZE_INIT sysconf(_SC_GETPW_R_SIZE_MAX)
161 # define GETPW_R_SIZE_DEFAULT 0x1000
162 # define GETPW_R_SIZE_LIMIT 0x10000
164 # ifdef USE_GETPWNAM_R
165 # define PREPARE_GETPWNAM \
167 # define FINISH_GETPWNAM \
168 (getpw_buf ? (void)rb_str_resize(getpw_buf, 0) : (void)0)
169 # define OBJ2UID1(id) obj2uid((id), &getpw_buf)
170 # define OBJ2UID(id) obj2uid0(id)
182 # define PREPARE_GETPWNAM
183 # define FINISH_GETPWNAM
184 # define OBJ2UID1(id) obj2uid((id))
185 # define OBJ2UID(id) obj2uid((id))
189 # define PREPARE_GETPWNAM
190 # define FINISH_GETPWNAM
191 # define OBJ2UID1(id) NUM2UIDT(id)
192 # define OBJ2UID(id) NUM2UIDT(id)
193 # ifdef p_uid_from_name
194 # undef p_uid_from_name
195 # define p_uid_from_name rb_f_notimplement
199 #if defined(HAVE_GRP_H)
200 # if defined(HAVE_GETGRNAM_R) && defined(_SC_GETGR_R_SIZE_MAX)
201 # define USE_GETGRNAM_R
202 # define GETGR_R_SIZE_INIT sysconf(_SC_GETGR_R_SIZE_MAX)
203 # define GETGR_R_SIZE_DEFAULT 0x1000
204 # define GETGR_R_SIZE_LIMIT 0x10000
206 # ifdef USE_GETGRNAM_R
207 # define PREPARE_GETGRNAM \
209 # define FINISH_GETGRNAM \
210 (getgr_buf ? (void)rb_str_resize(getgr_buf, 0) : (void)0)
211 # define OBJ2GID1(id) obj2gid((id), &getgr_buf)
212 # define OBJ2GID(id) obj2gid0(id)
225 # define PREPARE_GETGRNAM
226 # define FINISH_GETGRNAM
227 # define OBJ2GID1(id) obj2gid((id))
228 # define OBJ2GID(id) obj2gid((id))
232 # define PREPARE_GETGRNAM
233 # define FINISH_GETGRNAM
234 # define OBJ2GID1(id) NUM2GIDT(id)
235 # define OBJ2GID(id) NUM2GIDT(id)
236 # ifdef p_gid_from_name
237 # undef p_gid_from_name
238 # define p_gid_from_name rb_f_notimplement
242 #if SIZEOF_CLOCK_T == SIZEOF_INT
244 #elif SIZEOF_CLOCK_T == SIZEOF_LONG
246 #elif defined(HAVE_LONG_LONG) && SIZEOF_CLOCK_T == SIZEOF_LONG_LONG
253 #define id_exception idException
254 static ID id_in, id_out, id_err, id_pid, id_uid, id_gid;
255 static ID id_close, id_child;
260 static ID id_new_pgroup;
262 static ID id_unsetenv_others, id_chdir, id_umask, id_close_others, id_ENV;
263 static ID id_nanosecond, id_microsecond, id_millisecond, id_second;
264 static ID id_float_microsecond, id_float_millisecond, id_float_second;
265 static ID id_GETTIMEOFDAY_BASED_CLOCK_REALTIME, id_TIME_BASED_CLOCK_REALTIME;
267 static ID id_TIMES_BASED_CLOCK_MONOTONIC;
268 static ID id_TIMES_BASED_CLOCK_PROCESS_CPUTIME_ID;
271 static ID id_GETRUSAGE_BASED_CLOCK_PROCESS_CPUTIME_ID;
273 static ID id_CLOCK_BASED_CLOCK_PROCESS_CPUTIME_ID;
275 static ID id_MACH_ABSOLUTE_TIME_BASED_CLOCK_MONOTONIC;
280 #if defined(__sun) && !defined(_XPG7)
281 #define execv(path, argv) (rb_async_bug_errno("unreachable: async-signal-unsafe execv() is called", 0))
282 #define execl(path, arg0, arg1, arg2, term) do { extern char **environ; execle((path), (arg0), (arg1), (arg2), (term), (environ)); } while (0)
283 #define ALWAYS_NEED_ENVP 1
285 #define ALWAYS_NEED_ENVP 0
289 assert_close_on_exec(
int fd)
291 #if VM_CHECK_MODE > 0
292 #if defined(HAVE_FCNTL) && defined(F_GETFD) && defined(FD_CLOEXEC)
295 static const char m[] =
"reserved FD closed unexpectedly?\n";
300 rb_bug(
"reserved FD did not have close-on-exec set");
302 rb_bug(
"reserved FD without close-on-exec support");
308 close_unless_reserved(
int fd)
311 assert_close_on_exec(fd);
318 #if defined(DEBUG_REDIRECT)
323 ttyprintf(
const char *
fmt, ...)
329 tty =
fopen(
"con",
"w");
331 tty =
fopen(
"/dev/tty",
"w");
348 ttyprintf(
"dup(%d) => %d\n", oldfd, ret);
356 ret =
dup2(oldfd, newfd);
357 ttyprintf(
"dup2(%d, %d) => %d\n", oldfd, newfd, ret);
366 ttyprintf(
"cloexec_dup(%d) => %d\n", oldfd, ret);
375 ttyprintf(
"cloexec_dup2(%d, %d) => %d\n", oldfd, newfd, ret);
383 ret = close_unless_reserved(fd);
384 ttyprintf(
"close(%d) => %d\n", fd, ret);
393 ttyprintf(
"parent_open(\"%s\", 0x%x, 0%o) => %d\n", pathname,
flags, perm, ret);
401 ret = close_unless_reserved(fd);
402 ttyprintf(
"parent_close(%d) => %d\n", fd, ret);
407 #define redirect_dup(oldfd) dup(oldfd)
408 #define redirect_dup2(oldfd, newfd) dup2((oldfd), (newfd))
409 #define redirect_cloexec_dup(oldfd) rb_cloexec_dup(oldfd)
410 #define redirect_cloexec_dup2(oldfd, newfd) rb_cloexec_dup2((oldfd), (newfd))
411 #define redirect_close(fd) close_unless_reserved(fd)
412 #define parent_redirect_open(pathname, flags, perm) rb_cloexec_open((pathname), (flags), (perm))
413 #define parent_redirect_close(fd) close_unless_reserved(fd)
515 static VALUE rb_cProcessStatus;
577 #define PST2INT(st) NUM2INT(pst_to_i(st))
602 pst_message_status(
str, status);
606 pst_message_status(
VALUE str,
int status)
662 pst_message(
str, pid, status);
693 pst_message(
str, pid, status);
710 if (st1 == st2)
return Qtrue;
711 return rb_equal(pst_to_i(st1), st2);
932 #if defined HAVE_WAITPID
934 #elif defined HAVE_WAIT4
937 # error waitpid or wait4 is required.
941 #define WAITPID_LOCK_ONLY ((struct waitpid_state *)-1)
985 sigwait_fd_migrate_sleeper(
rb_vm_t *vm)
990 if (waitpid_signal(w))
return;
993 if (waitpid_signal(w))
return;
1001 sigwait_fd_migrate_sleeper(vm);
1025 # define ruby_nocldwait 0
1055 sigwait_sleep_time(
void)
1083 int sigwait_fd = -1;
1091 if (sigwait_fd >= 0) {
1105 if (sigwait_fd >= 0) {
1107 sigwait_fd_migrate_sleeper(vm);
1118 waitpid_sleep(
VALUE x)
1130 waitpid_cleanup(
VALUE x)
1153 int need_sleep =
FALSE;
1187 waitpid_blocking_no_SIGCHLD(
void *x)
1217 waitpid_state_init(&w,
pid, flags);
1224 waitpid_no_SIGCHLD(&w);
1231 else if (w.
ret > 0) {
1330 return proc_wait(c,
v);
1402 static VALUE rb_cWaiter;
1405 detach_process_pid(
VALUE thread)
1411 detach_process_watcher(
void *
arg)
1486 before_exec_async_signal_safe(
void)
1491 before_exec_non_async_signal_safe(
void)
1505 #define WRITE_CONST(fd, str) (void)(write((fd),(str),sizeof(str)-1)<0)
1511 set_blocking(
int fd)
1515 #elif defined(F_GETFL) && defined(F_SETFL)
1516 int fl =
fcntl(fd, F_GETFL);
1519 if (fl == -1)
return fl;
1529 stdfd_clear_nonblock(
void)
1533 for (fd = 0; fd < 3; fd++) {
1534 (
void)set_blocking(fd);
1541 before_exec_non_async_signal_safe();
1542 before_exec_async_signal_safe();
1547 after_exec_async_signal_safe(
void)
1552 after_exec_non_async_signal_safe(
void)
1561 after_exec_async_signal_safe();
1562 after_exec_non_async_signal_safe();
1565 #if defined HAVE_WORKING_FORK || defined HAVE_DAEMON
1566 #define before_fork_ruby() before_exec()
1568 after_fork_ruby(
void)
1577 #if defined(HAVE_WORKING_FORK)
1580 #define try_with_sh(err, prog, argv, envp) ((err == ENOEXEC) ? exec_with_sh((prog), (argv), (envp)) : (void)0)
1582 exec_with_sh(
const char *prog,
char **
argv,
char **envp)
1584 *
argv = (
char *)prog;
1585 *--
argv = (
char *)
"sh";
1593 #define try_with_sh(err, prog, argv, envp) (void)0
1598 proc_exec_cmd(
const char *prog,
VALUE argv_str,
VALUE envp_str)
1629 proc_exec_sh(
const char *
str,
VALUE envp_str)
1634 while (*s ==
' ' || *s ==
'\t' || *s ==
'\n')
1643 #elif defined(__CYGWIN32__)
1676 mark_exec_arg(
void *
ptr)
1702 memsize_exec_arg(
const void *
ptr)
1714 # define DEFAULT_PROCESS_ENCODING rb_utf8_encoding()
1716 #ifdef DEFAULT_PROCESS_ENCODING
1717 # define EXPORT_STR(str) rb_str_export_to_enc((str), DEFAULT_PROCESS_ENCODING)
1718 # define EXPORT_DUP(str) export_dup(str)
1727 # define EXPORT_STR(str) (str)
1728 # define EXPORT_DUP(str) rb_str_dup(str)
1731 #if !defined(HAVE_WORKING_FORK) && defined(HAVE_SPAWNV)
1732 # define USE_SPAWNV 1
1734 # define USE_SPAWNV 0
1737 # define P_NOWAIT _P_NOWAIT
1742 #define proc_spawn_cmd_internal(argv, prog) rb_w32_uaspawn(P_NOWAIT, (prog), (argv))
1745 proc_spawn_cmd_internal(
char **
argv,
char *prog)
1759 *
argv = (
char *)prog;
1760 *--
argv = (
char *)
"sh";
1761 status = spawnv(
P_NOWAIT,
"/bin/sh", (
const char **)
argv);
1778 flags = CREATE_NEW_PROCESS_GROUP;
1789 #define proc_spawn_sh(str) rb_w32_uspawn(P_NOWAIT, (str), 0)
1792 proc_spawn_sh(
char *
str)
1799 status = spawnl(
P_NOWAIT, (shell ? shell :
"/bin/sh"),
"sh",
"-c",
str, (
char*)
NULL);
1814 check_exec_redirect_fd(
VALUE v,
int iskey)
1825 else if (
id == id_out)
1827 else if (
id == id_err)
1847 else if (fd >= 3 && iskey) {
1868 VALUE fd = check_exec_redirect_fd(
v, !
NIL_P(param));
1884 switch (
TYPE(val)) {
1887 if (
id == id_close) {
1891 else if (
id ==
id_in) {
1895 else if (
id == id_out) {
1899 else if (
id == id_err) {
1912 val = check_exec_redirect_fd(val, 0);
1923 param = check_exec_redirect_fd(
rb_ary_entry(val, 1), 0);
1938 flags, perm,
Qnil));
1947 key = check_exec_redirect_fd(
key, 1);
1949 flags =
INT2NUM(O_WRONLY|O_CREAT|O_TRUNC);
1954 VALUE fd = check_exec_redirect_fd(
v, 1);
1958 flags =
INT2NUM(O_WRONLY|O_CREAT|O_TRUNC);
1966 flags, perm,
Qnil));
1973 if (!
NIL_P(val))
goto io;
1979 #if defined(HAVE_SETRLIMIT) && defined(NUM2RLIM)
1980 static int rlimit_type_by_sym(
VALUE key);
1983 rb_execarg_addopt_rlimit(
struct rb_execarg *eargp,
int rtype,
VALUE val)
1986 VALUE tmp, softlim, hardlim;
2011 #define TO_BOOL(val, name) NIL_P(val) ? 0 : rb_bool_expected((val), name)
2021 #if defined(HAVE_SETRLIMIT) && defined(NUM2RLIM)
2023 int rtype = rlimit_type_by_sym(
key);
2025 rb_execarg_addopt_rlimit(eargp, rtype, val);
2033 if (
id == id_pgroup) {
2040 else if (val ==
Qtrue)
2054 if (
id == id_new_pgroup) {
2063 if (
id == id_unsetenv_others) {
2070 else if (
id == id_chdir) {
2079 else if (
id == id_umask) {
2087 else if (
id == id_close_others) {
2094 else if (
id ==
id_in) {
2098 else if (
id == id_out) {
2102 else if (
id == id_err) {
2106 else if (
id == id_uid) {
2118 "uid option is unimplemented on this machine");
2121 else if (
id == id_gid) {
2133 "gid option is unimplemented on this machine");
2141 eargp->exception =
TO_BOOL(val,
"exception");
2152 check_exec_redirect(
key, val, eargp);
2184 VALUE execarg_obj = args[0];
2186 VALUE nonopts = args[1];
2231 maxhint = check_exec_fds_1(eargp,
h, maxhint, eargp->
fd_dup2);
2232 maxhint = check_exec_fds_1(eargp,
h, maxhint, eargp->
fd_close);
2233 maxhint = check_exec_fds_1(eargp,
h, maxhint, eargp->
fd_dup2_child);
2253 if (oldfd != lastfd) {
2271 rb_check_exec_options(
VALUE opthash,
VALUE execarg_obj)
2284 args[0] = execarg_obj;
2290 #ifdef ENV_IGNORECASE
2291 #define ENVMATCH(s1, s2) (STRCASECMP((s1), (s2)) == 0)
2293 #define ENVMATCH(n1, n2) (strcmp((n1), (n2)) == 0)
2377 rb_exec_getargs(
int *argc_p,
VALUE **argv_p,
int accept_shell,
VALUE *env_ret,
VALUE *opthash_ret)
2382 hash = check_hash((*argv_p)[*argc_p-1]);
2384 *opthash_ret = hash;
2390 hash = check_hash((*argv_p)[0]);
2397 prog = rb_check_argv(*argc_p, *argv_p);
2399 prog = (*argv_p)[0];
2400 if (accept_shell && *argc_p == 1) {
2415 compare_posix_sh(
const void *
key,
const void *el)
2419 if (!ret && ((
const char *)el)[word->
len]) ret = -1;
2432 if (!
NIL_P(opthash)) {
2433 rb_check_exec_options(opthash, execarg_obj);
2443 eargp->
invoke.
sh.shell_script = prog;
2449 static const char posix_sh_cmds[][9] = {
2508 if (*p ==
' ' || *p ==
'\t') {
2509 if (first.
ptr && !first.
len) first.
len = p - first.
ptr;
2512 if (!first.
ptr) first.
ptr = p;
2514 if (!has_meta &&
strchr(
"*?{}[]<>()~&|\\$;'`\"\n#", *p))
2520 else if (*p ==
'/') {
2527 if (!has_meta && first.
ptr) {
2528 if (!first.
len) first.
len = p - first.
ptr;
2529 if (first.
len > 0 && first.
len <=
sizeof(posix_sh_cmds[0]) &&
2530 bsearch(&first, posix_sh_cmds,
numberof(posix_sh_cmds),
sizeof(posix_sh_cmds[0]), compare_posix_sh))
2542 while (*p ==
' ' || *p ==
'\t')
2546 while (*p && *p !=
' ' && *p !=
'\t')
2561 const char *abspath;
2562 const char *path_env = 0;
2565 path_env, fbuf,
sizeof(fbuf));
2580 #ifdef DEFAULT_PROCESS_ENCODING
2590 const char *p, *ep, *
null=
NULL;
2602 rb_imemo_tmpbuf_auto_free_pointer_new_from_an_RString(argv_str);
2616 rb_execarg_init(
int argc,
const VALUE *orig_argv,
int accept_shell,
VALUE execarg_obj)
2624 prog = rb_exec_getargs(&
argc, &
argv, accept_shell, &
env, &opthash);
2625 rb_exec_fillarg(prog,
argc,
argv,
env, opthash, execarg_obj);
2638 rb_execarg_init(
argc,
argv, accept_shell, execarg_obj);
2669 static long run_exec_dup2_tmpbuf_size(
long n);
2680 open_func(
void *
ptr)
2690 rb_execarg_allocate_dup2_tmpbuf(
struct rb_execarg *eargp,
long len)
2693 rb_imemo_tmpbuf_set_ptr(tmpbuf,
ruby_xmalloc(run_exec_dup2_tmpbuf_size(
len)));
2698 rb_execarg_parent_start1(
VALUE execarg_obj)
2701 int unsetenv_others;
2722 open_data.fname = vpath;
2723 open_data.oflags = flags;
2724 open_data.perm =
perm;
2726 open_data.err =
EINTR;
2728 if (open_data.ret == -1) {
2729 if (open_data.err ==
EINTR) {
2735 fd2 = open_data.ret;
2751 rb_execarg_allocate_dup2_tmpbuf(eargp,
RARRAY_LEN(ary));
2757 VALUE envtbl, envp_str, envp_buf;
2759 if (unsetenv_others) {
2799 rb_imemo_tmpbuf_auto_free_pointer_new_from_an_RString(envp_str);
2819 rb_protect(rb_execarg_parent_start1, execarg_obj, &state);
2827 execarg_parent_end(
VALUE execarg_obj)
2857 execarg_parent_end(execarg_obj);
2862 rb_exec_fail(
struct rb_execarg *eargp,
int err,
const char *errmsg)
2864 if (!errmsg || !*errmsg)
return;
2865 if (
strcmp(errmsg,
"chdir") == 0) {
2873 rb_execarg_fail(
VALUE execarg_obj,
int err,
const char *errmsg)
2875 if (!errmsg || !*errmsg)
return;
2884 VALUE execarg_obj, fail_str;
2886 #define CHILD_ERRMSG_BUFLEN 80
2895 rb_protect(rb_execarg_parent_start1, execarg_obj, &state);
2897 execarg_parent_end(execarg_obj);
2904 err = exec_async_signal_safe(eargp, errmsg,
sizeof(errmsg));
2907 rb_exec_fail(eargp,
err, errmsg);
2992 #define ERRMSG(str) do { if (errmsg && 0 < errmsg_buflen) strlcpy(errmsg, (str), errmsg_buflen); } while (0)
2993 #define ERRMSG1(str, a) do { if (errmsg && 0 < errmsg_buflen) snprintf(errmsg, errmsg_buflen, (str), (a)); } while (0)
2994 #define ERRMSG2(str, a, b) do { if (errmsg && 0 < errmsg_buflen) snprintf(errmsg, errmsg_buflen, (str), (a), (b)); } while (0)
2996 static int fd_get_cloexec(
int fd,
char *errmsg,
size_t errmsg_buflen);
2997 static int fd_set_cloexec(
int fd,
char *errmsg,
size_t errmsg_buflen);
2998 static int fd_clear_cloexec(
int fd,
char *errmsg,
size_t errmsg_buflen);
3001 save_redirect_fd(
int fd,
struct rb_execarg *sargp,
char *errmsg,
size_t errmsg_buflen)
3004 VALUE newary, redirection;
3006 if (save_fd == -1) {
3018 cloexec = fd_get_cloexec(fd, errmsg, errmsg_buflen);
3035 intcmp(
const void *a,
const void *b)
3037 return *(
int*)a - *(
int*)b;
3041 intrcmp(
const void *a,
const void *b)
3043 return *(
int*)b - *(
int*)a;
3055 run_exec_dup2_tmpbuf_size(
long n)
3062 fd_get_cloexec(
int fd,
char *errmsg,
size_t errmsg_buflen)
3068 ERRMSG(
"fcntl(F_GETFD)");
3078 fd_set_cloexec(
int fd,
char *errmsg,
size_t errmsg_buflen)
3084 ERRMSG(
"fcntl(F_GETFD)");
3091 ERRMSG(
"fcntl(F_SETFD)");
3101 fd_clear_cloexec(
int fd,
char *errmsg,
size_t errmsg_buflen)
3107 ERRMSG(
"fcntl(F_GETFD)");
3114 ERRMSG(
"fcntl(F_SETFD)");
3124 run_exec_dup2(
VALUE ary,
VALUE tmpbuf,
struct rb_execarg *sargp,
char *errmsg,
size_t errmsg_buflen)
3135 for (
i = 0;
i <
n;
i++) {
3150 for (
i = 0;
i <
n;
i++) {
3157 while (pairs < found && (found-1)->
oldfd ==
newfd)
3159 while (found < pairs+n && found->
oldfd ==
newfd) {
3168 for (
i = 0;
i <
n;
i++) {
3170 while (j != -1 && pairs[j].
oldfd != -1 && pairs[j].
num_newer == 0) {
3171 if (save_redirect_fd(pairs[j].
newfd, sargp, errmsg, errmsg_buflen) < 0)
3179 fd_set_cloexec(pairs[j].
newfd, errmsg, errmsg_buflen)) {
3183 pairs[j].
oldfd = -1;
3191 for (
i = 0;
i <
n;
i++) {
3193 if (pairs[
i].
oldfd == -1)
3196 if (fd_clear_cloexec(pairs[
i].
oldfd, errmsg, errmsg_buflen) == -1)
3201 if (extra_fd == -1) {
3203 if (extra_fd == -1) {
3217 pairs[
i].
oldfd = extra_fd;
3227 pairs[j].
oldfd = -1;
3231 if (extra_fd != -1) {
3247 run_exec_close(
VALUE ary,
char *errmsg,
size_t errmsg_buflen)
3266 run_exec_dup2_child(
VALUE ary,
struct rb_execarg *sargp,
char *errmsg,
size_t errmsg_buflen)
3276 if (save_redirect_fd(
newfd, sargp, errmsg, errmsg_buflen) < 0)
3291 run_exec_pgroup(
const struct rb_execarg *eargp,
struct rb_execarg *sargp,
char *errmsg,
size_t errmsg_buflen)
3317 if (ret == -1)
ERRMSG(
"setpgid");
3322 #if defined(HAVE_SETRLIMIT) && defined(RLIM2NUM)
3325 run_exec_rlimit(
VALUE ary,
struct rb_execarg *sargp,
char *errmsg,
size_t errmsg_buflen)
3334 if (getrlimit(rtype, &rlim) == -1) {
3349 if (setrlimit(rtype, &rlim) == -1) {
3358 #if !defined(HAVE_WORKING_FORK)
3387 #define chdir(p) rb_w32_uchdir(p)
3404 if (run_exec_pgroup(eargp, sargp, errmsg, errmsg_buflen) == -1)
3409 #if defined(HAVE_SETRLIMIT) && defined(RLIM2NUM)
3412 if (run_exec_rlimit(
obj, sargp, errmsg, errmsg_buflen) == -1)
3417 #if !defined(HAVE_WORKING_FORK)
3450 if (run_exec_dup2(
obj, eargp->
dup2_tmpbuf, sargp, errmsg, errmsg_buflen) == -1)
3457 rb_warn(
"cannot close fd before spawn");
3459 if (run_exec_close(
obj, errmsg, errmsg_buflen) == -1)
3464 #ifdef HAVE_WORKING_FORK
3472 if (run_exec_dup2_child(
obj, sargp, errmsg, errmsg_buflen) == -1)
3509 rb_execarg_allocate_dup2_tmpbuf(sargp,
RARRAY_LEN(ary));
3513 int preserve =
errno;
3514 stdfd_clear_nonblock();
3525 errno = exec_async_signal_safe(eargp, errmsg, errmsg_buflen);
3530 exec_async_signal_safe(
const struct rb_execarg *eargp,
char *errmsg,
size_t errmsg_buflen)
3532 #if !defined(HAVE_WORKING_FORK)
3533 struct rb_execarg sarg, *
const sargp = &sarg;
3547 char *abspath =
NULL;
3552 #if !defined(HAVE_WORKING_FORK)
3559 #ifdef HAVE_WORKING_FORK
3562 rb_exec_atfork(
void*
arg,
char *errmsg,
size_t errmsg_buflen)
3567 #if SIZEOF_INT == SIZEOF_LONG
3568 #define proc_syswait (VALUE (*)(VALUE))rb_syswait
3571 proc_syswait(
VALUE pid)
3579 move_fds_to_avoid_crash(
int *fdp,
int n,
VALUE fds)
3583 for (
i = 0;
i <
n;
i++) {
3602 pipe_nocrash(
int filedes[2],
VALUE fds)
3610 if (move_fds_to_avoid_crash(filedes, 2, fds) == -1) {
3625 rb_thread_sleep_that_takes_VALUE_as_sole_argument(
VALUE n)
3632 handle_fork_error(
int err,
int *status,
int *ep,
volatile int *try_gc_p)
3644 #if defined(EWOULDBLOCK) && EWOULDBLOCK != EAGAIN
3647 if (!status && !ep) {
3652 rb_protect(rb_thread_sleep_that_takes_VALUE_as_sole_argument,
INT2FIX(1), &state);
3653 if (status) *status = state;
3654 if (!state)
return 0;
3667 #define prefork() ( \
3668 rb_io_flush(rb_stdout), \
3669 rb_io_flush(rb_stderr) \
3699 write_retry(
int fd,
const void *
buf,
size_t len)
3711 read_retry(
int fd,
void *
buf,
size_t len)
3715 if (set_blocking(fd) != 0) {
3729 send_child_error(
int fd,
char *errmsg,
size_t errmsg_buflen)
3735 if (errmsg && 0 < errmsg_buflen) {
3736 errmsg[errmsg_buflen-1] =
'\0';
3737 errmsg_buflen =
strlen(errmsg);
3738 if (errmsg_buflen > 0 && write_retry(fd, errmsg, errmsg_buflen) < 0)
3744 recv_child_error(
int fd,
int *errp,
char *errmsg,
size_t errmsg_buflen)
3748 if ((
size = read_retry(fd, &
err,
sizeof(
err))) < 0) {
3753 errmsg && 0 < errmsg_buflen) {
3754 ssize_t ret = read_retry(fd, errmsg, errmsg_buflen-1);
3763 #ifdef HAVE_WORKING_VFORK
3764 #if !defined(HAVE_GETRESUID) && defined(HAVE_GETUIDX)
3773 ret = getuidx(ID_SAVED);
3779 #define HAVE_GETRESUID
3782 #if !defined(HAVE_GETRESGID) && defined(HAVE_GETGIDX)
3791 ret = getgidx(ID_SAVED);
3797 #define HAVE_GETRESGID
3818 #if defined HAVE_ISSETUGID
3823 #ifdef HAVE_GETRESUID
3827 ret = getresuid(&ruid, &euid, &suid);
3838 if (euid == 0 || euid != ruid)
3841 #ifdef HAVE_GETRESGID
3845 ret = getresgid(&rgid, &egid, &sgid);
3863 struct child_handler_disabler_state
3869 disable_child_handler_before_fork(
struct child_handler_disabler_state *
old)
3874 #ifdef HAVE_PTHREAD_SIGMASK
3884 # pragma GCC warning "pthread_sigmask on fork is not available. potentially dangerous"
3889 disable_child_handler_fork_parent(
struct child_handler_disabler_state *
old)
3893 #ifdef HAVE_PTHREAD_SIGMASK
3899 # pragma GCC warning "pthread_sigmask on fork is not available. potentially dangerous"
3905 disable_child_handler_fork_child(
struct child_handler_disabler_state *
old,
char *errmsg,
size_t errmsg_buflen)
3917 ERRMSG(
"signal to obtain old action");
3946 retry_fork_async_signal_safe(
int *status,
int *ep,
3947 int (*chfunc)(
void*,
char *,
size_t),
void *charg,
3948 char *errmsg,
size_t errmsg_buflen,
3952 volatile int try_gc = 1;
3953 struct child_handler_disabler_state
old;
3961 disable_child_handler_before_fork(&
old);
3965 #ifdef HAVE_WORKING_VFORK
3966 if (!has_privilege())
3976 ret = disable_child_handler_fork_child(&
old, errmsg, errmsg_buflen);
3978 ret = chfunc(charg, errmsg, errmsg_buflen);
3981 send_child_error(ep[1], errmsg, errmsg_buflen);
3982 #if EXIT_SUCCESS == 127
3989 waitpid_lock = waitpid_lock_init;
3997 disable_child_handler_fork_parent(&
old);
4001 if (handle_fork_error(
err, status, ep, &try_gc))
4008 fork_check_err(
int *status,
int (*chfunc)(
void*,
char *,
size_t),
void *charg,
4009 VALUE fds,
char *errmsg,
size_t errmsg_buflen,
4022 if (pipe_nocrash(ep, fds))
return -1;
4023 pid = retry_fork_async_signal_safe(
status, ep, chfunc, charg,
4024 errmsg, errmsg_buflen, w);
4028 error_occurred = recv_child_error(ep[0], &
err, errmsg, errmsg_buflen);
4029 if (error_occurred) {
4032 "only used by extensions");
4053 int (*chfunc)(
void*,
char *,
size_t),
void *charg,
4054 VALUE fds,
char *errmsg,
size_t errmsg_buflen)
4056 return fork_check_err(
status, chfunc, charg, fds, errmsg, errmsg_buflen, 0);
4067 int try_gc = 1,
err;
4068 struct child_handler_disabler_state
old;
4070 if (status) *status = 0;
4075 disable_child_handler_before_fork(&
old);
4080 disable_child_handler_fork_parent(&
old);
4085 if (handle_fork_error(
err, status,
NULL, &try_gc))
4093 #if defined(HAVE_WORKING_FORK) && !defined(CANNOT_FORK_WITH_PTHREAD)
4143 #define rb_f_fork rb_f_notimplement
4147 exit_status_code(
VALUE status)
4160 #if EXIT_SUCCESS != 0
4186 istatus = exit_status_code(
argv[0]);
4215 istatus = exit_status_code(
argv[0]);
4290 if (!
NIL_P(errinfo)) {
4298 args[1] = args[0] =
argv[0];
4322 #if !defined HAVE_WORKING_FORK && !defined HAVE_SPAWNV
4336 p[
argv[
i] - start - 1] =
' ';
4346 rb_spawn_process(
struct rb_execarg *eargp,
char *errmsg,
size_t errmsg_buflen)
4349 #if !defined HAVE_WORKING_FORK || USE_SPAWNV
4352 # if !defined HAVE_SPAWNV
4357 #if defined HAVE_WORKING_FORK && !USE_SPAWNV
4358 pid = fork_check_err(0, rb_exec_atfork, eargp, eargp->
redirect_fds,
4359 errmsg, errmsg_buflen, eargp);
4371 # if defined HAVE_SPAWNV
4377 pid = proc_spawn_cmd(
argv, prog, eargp);
4406 rb_execarg_parent_start1(argp->
execarg);
4412 rb_execarg_spawn(
VALUE execarg_obj,
char *
errmsg,
size_t errmsg_buflen)
4425 args.execarg = execarg_obj;
4426 args.errmsg.ptr = errmsg;
4427 args.errmsg.buflen = errmsg_buflen;
4429 execarg_parent_end, execarg_obj);
4433 rb_spawn_internal(
int argc,
const VALUE *
argv,
char *errmsg,
size_t errmsg_buflen)
4438 return rb_execarg_spawn(execarg_obj, errmsg, errmsg_buflen);
4444 return rb_spawn_internal(
argc,
argv, errmsg, errmsg_buflen);
4520 waitpid_state_init(w, 0, 0);
4522 pid = rb_execarg_spawn(execarg_obj, 0, 0);
4523 exec_errnum = pid < 0 ?
errno : 0;
4525 #if defined(HAVE_WORKING_FORK) || defined(HAVE_SPAWNV)
4532 waitpid_no_SIGCHLD(w);
4537 if (w->
pid < 0 || pid < 0 ) {
4538 if (eargp->exception) {
4539 int err = exec_errnum ? exec_errnum : w->
errnum;
4549 if (eargp->exception) {
4836 VALUE execarg_obj, fail_str;
4843 pid = rb_execarg_spawn(execarg_obj, errmsg,
sizeof(errmsg));
4847 rb_exec_fail(eargp,
err, errmsg);
4851 #if defined(HAVE_WORKING_FORK) || defined(HAVE_SPAWNV)
4889 end =
time(0) - beg;
4895 #if (defined(HAVE_GETPGRP) && defined(GETPGRP_VOID)) || defined(HAVE_GETPGID)
4912 #if defined(HAVE_GETPGRP) && defined(GETPGRP_VOID)
4923 #define proc_getpgrp rb_f_notimplement
4927 #if defined(HAVE_SETPGID) || (defined(HAVE_SETPGRP) && defined(SETPGRP_VOID))
4945 #elif defined(HAVE_SETPGRP) && defined(SETPGRP_VOID)
4951 #define proc_setpgrp rb_f_notimplement
4955 #if defined(HAVE_GETPGID)
4976 #define proc_getpgid rb_f_notimplement
5001 #define proc_setpgid rb_f_notimplement
5032 #define proc_getsid rb_f_notimplement
5036 #if defined(HAVE_SETSID) || (defined(HAVE_SETPGRP) && defined(TIOCNOTTY))
5037 #if !defined(HAVE_SETSID)
5039 #define setsid() ruby_setsid()
5062 #if !defined(HAVE_SETSID)
5063 #define HAVE_SETSID 1
5071 #if defined(SETPGRP_VOID)
5079 if (ret == -1)
return -1;
5090 #define proc_setsid rb_f_notimplement
5094 #ifdef HAVE_GETPRIORITY
5115 int prio, iwhich, iwho;
5121 prio = getpriority(iwhich, iwho);
5126 #define proc_getpriority rb_f_notimplement
5130 #ifdef HAVE_GETPRIORITY
5146 int iwhich, iwho, iprio;
5152 if (setpriority(iwhich, iwho, iprio) < 0)
5157 #define proc_setpriority rb_f_notimplement
5160 #if defined(HAVE_SETRLIMIT) && defined(NUM2RLIM)
5162 rlimit_resource_name2int(
const char *
name,
long len,
int casetype)
5166 #define RESCHECK(r) \
5168 if (len == rb_strlen_lit(#r) && STRCASECMP(name, #r) == 0) { \
5169 resource = RLIMIT_##r; \
5203 #ifdef RLIMIT_MEMLOCK
5206 #ifdef RLIMIT_MSGQUEUE
5212 #ifdef RLIMIT_NOFILE
5227 #ifdef RLIMIT_RTPRIO
5230 #ifdef RLIMIT_RTTIME
5239 #ifdef RLIMIT_SBSIZE
5242 #ifdef RLIMIT_SIGPENDING
5243 RESCHECK(SIGPENDING);
5252 for (p =
name; *p; p++)
5258 for (p =
name; *p; p++)
5264 rb_bug(
"unexpected casetype");
5271 rlimit_type_by_hname(
const char *
name,
long len)
5273 return rlimit_resource_name2int(
name,
len, 0);
5277 rlimit_type_by_lname(
const char *
name,
long len)
5279 return rlimit_resource_name2int(
name,
len, 1);
5289 static const char prefix[] =
"rlimit_";
5290 enum {prefix_len =
sizeof(prefix)-1};
5292 if (
len > prefix_len &&
strncmp(prefix, rname, prefix_len) == 0) {
5293 rtype = rlimit_type_by_lname(rname + prefix_len,
len - prefix_len);
5301 rlimit_resource_type(
VALUE rtype)
5308 switch (
TYPE(rtype)) {
5331 r = rlimit_type_by_hname(
name,
len);
5341 rlimit_resource_value(
VALUE rval)
5346 switch (
TYPE(rval)) {
5367 #ifdef RLIM_INFINITY
5368 if (
strcmp(
name,
"INFINITY") == 0)
return RLIM_INFINITY;
5370 #ifdef RLIM_SAVED_MAX
5371 if (
strcmp(
name,
"SAVED_MAX") == 0)
return RLIM_SAVED_MAX;
5373 #ifdef RLIM_SAVED_CUR
5374 if (
strcmp(
name,
"SAVED_CUR") == 0)
return RLIM_SAVED_CUR;
5382 #if defined(HAVE_GETRLIMIT) && defined(RLIM2NUM)
5408 if (getrlimit(rlimit_resource_type(resource), &rlim) < 0) {
5414 #define proc_getrlimit rb_f_notimplement
5417 #if defined(HAVE_SETRLIMIT) && defined(NUM2RLIM)
5472 VALUE resource, rlim_cur, rlim_max;
5479 rlim_max = rlim_cur;
5481 rlim.rlim_cur = rlimit_resource_value(rlim_cur);
5482 rlim.rlim_max = rlimit_resource_value(rlim_max);
5484 if (setrlimit(rlimit_resource_type(resource), &rlim) < 0) {
5490 #define proc_setrlimit rb_f_notimplement
5493 static int under_uid_switch = 0;
5495 check_uid_switch(
void)
5497 if (under_uid_switch) {
5502 static int under_gid_switch = 0;
5504 check_gid_switch(
void)
5506 if (under_gid_switch) {
5522 #if defined(HAVE_PWD_H)
5525 # ifdef USE_GETPWNAM_R
5538 struct passwd *pwptr;
5539 #ifdef USE_GETPWNAM_R
5540 struct passwd pwbuf;
5545 getpw_buf_len = GETPW_R_SIZE_INIT;
5546 if (getpw_buf_len < 0) getpw_buf_len = GETPW_R_SIZE_DEFAULT;
5553 while ((e = getpwnam_r(usrname, &pwbuf, getpw_buf, getpw_buf_len, &pwptr)) != 0) {
5554 if (e !=
ERANGE || getpw_buf_len >= GETPW_R_SIZE_LIMIT) {
5563 pwptr = getpwnam(usrname);
5566 #ifndef USE_GETPWNAM_R
5571 uid = pwptr->pw_uid;
5572 #ifndef USE_GETPWNAM_R
5579 # ifdef p_uid_from_name
5599 #if defined(HAVE_GRP_H)
5602 # ifdef USE_GETGRNAM_R
5615 struct group *grptr;
5616 #ifdef USE_GETGRNAM_R
5622 getgr_buf_len = GETGR_R_SIZE_INIT;
5623 if (getgr_buf_len < 0) getgr_buf_len = GETGR_R_SIZE_DEFAULT;
5630 while ((e = getgrnam_r(grpname, &grbuf, getgr_buf, getgr_buf_len, &grptr)) != 0) {
5631 if (e !=
ERANGE || getgr_buf_len >= GETGR_R_SIZE_LIMIT) {
5639 #elif defined(HAVE_GETGRNAM)
5640 grptr = getgrnam(grpname);
5645 #if !defined(USE_GETGRNAM_R) && defined(HAVE_ENDGRENT)
5650 gid = grptr->gr_gid;
5651 #if !defined(USE_GETGRNAM_R) && defined(HAVE_ENDGRENT)
5658 # ifdef p_gid_from_name
5678 #if defined HAVE_SETUID
5696 #define p_sys_setuid rb_f_notimplement
5700 #if defined HAVE_SETRUID
5718 #define p_sys_setruid rb_f_notimplement
5722 #if defined HAVE_SETEUID
5740 #define p_sys_seteuid rb_f_notimplement
5744 #if defined HAVE_SETREUID
5769 #define p_sys_setreuid rb_f_notimplement
5773 #if defined HAVE_SETRESUID
5795 if (setresuid(ruid, euid, suid) != 0)
rb_sys_fail(0);
5799 #define p_sys_setresuid rb_f_notimplement
5822 #if defined(HAVE_SETRESUID) || defined(HAVE_SETREUID) || defined(HAVE_SETRUID) || defined(HAVE_SETUID)
5839 #if defined(HAVE_SETRESUID)
5841 #elif defined HAVE_SETREUID
5843 #elif defined HAVE_SETRUID
5845 #elif defined HAVE_SETUID
5858 #define proc_setuid rb_f_notimplement
5872 static rb_uid_t SAVED_USER_ID = -1;
5874 #ifdef BROKEN_SETREUID
5880 if (
setuid(ruid) < 0)
return -1;
5883 if (
seteuid(euid) < 0)
return -1;
5912 #if defined(HAVE_SETRESUID)
5914 SAVED_USER_ID = uid;
5915 #elif defined(HAVE_SETUID)
5917 SAVED_USER_ID = uid;
5918 #elif defined(HAVE_SETREUID) && !defined(OBSOLETE_SETREUID)
5920 if (SAVED_USER_ID == uid) {
5929 SAVED_USER_ID = uid;
5935 SAVED_USER_ID = uid;
5941 SAVED_USER_ID = uid;
5943 #elif defined(HAVE_SETRUID) && defined(HAVE_SETEUID)
5945 if (SAVED_USER_ID == uid) {
5959 SAVED_USER_ID = uid;
5966 SAVED_USER_ID = uid;
5974 #if defined(HAVE_SETRESUID)
5978 SAVED_USER_ID = uid;
5979 #elif defined(HAVE_SETREUID) && !defined(OBSOLETE_SETREUID)
5980 if (SAVED_USER_ID == uid) {
5985 else if (
getuid() != uid) {
5988 SAVED_USER_ID = uid;
5992 SAVED_USER_ID = uid;
5998 SAVED_USER_ID = uid;
6001 #elif defined(HAVE_SETRUID) && defined(HAVE_SETEUID)
6002 if (SAVED_USER_ID == uid) {
6009 SAVED_USER_ID = uid;
6013 SAVED_USER_ID = uid;
6017 else if (
getuid() == uid) {
6020 SAVED_USER_ID = uid;
6026 #elif defined HAVE_44BSD_SETUID
6030 SAVED_USER_ID = uid;
6035 #elif defined HAVE_SETEUID
6036 if (
getuid() == uid && SAVED_USER_ID == uid) {
6042 #elif defined HAVE_SETUID
6043 if (
getuid() == uid && SAVED_USER_ID == uid) {
6058 #if defined HAVE_SETGID
6076 #define p_sys_setgid rb_f_notimplement
6080 #if defined HAVE_SETRGID
6098 #define p_sys_setrgid rb_f_notimplement
6102 #if defined HAVE_SETEGID
6120 #define p_sys_setegid rb_f_notimplement
6124 #if defined HAVE_SETREGID
6147 #define p_sys_setregid rb_f_notimplement
6150 #if defined HAVE_SETRESGID
6170 if (setresgid(rgid, egid, sgid) != 0)
rb_sys_fail(0);
6174 #define p_sys_setresgid rb_f_notimplement
6178 #if defined HAVE_ISSETUGID
6202 #define p_sys_issetugid rb_f_notimplement
6225 #if defined(HAVE_SETRESGID) || defined(HAVE_SETREGID) || defined(HAVE_SETRGID) || defined(HAVE_SETGID)
6241 #if defined(HAVE_SETRESGID)
6243 #elif defined HAVE_SETREGID
6245 #elif defined HAVE_SETRGID
6247 #elif defined HAVE_SETGID
6260 #define proc_setgid rb_f_notimplement
6264 #if defined(_SC_NGROUPS_MAX) || defined(NGROUPS_MAX)
6285 static int _maxgroups = -1;
6287 get_sc_ngroups_max(
void)
6289 #ifdef _SC_NGROUPS_MAX
6291 #elif defined(NGROUPS_MAX)
6300 if (_maxgroups < 0) {
6301 _maxgroups = get_sc_ngroups_max();
6312 #ifdef HAVE_GETGROUPS
6355 for (
i = 0;
i < ngroups;
i++)
6363 #define proc_getgroups rb_f_notimplement
6367 #ifdef HAVE_SETGROUPS
6392 if (ngroups > maxgroups())
6397 for (
i = 0;
i < ngroups;
i++) {
6412 #define proc_setgroups rb_f_notimplement
6416 #ifdef HAVE_INITGROUPS
6443 #define proc_initgroups rb_f_notimplement
6446 #if defined(_SC_NGROUPS_MAX) || defined(NGROUPS_MAX)
6463 #define proc_getmaxgroups rb_f_notimplement
6466 #ifdef HAVE_SETGROUPS
6479 int ngroups_max = get_sc_ngroups_max();
6487 if (ngroups_max > 0 && ngroups > ngroups_max)
6488 ngroups = ngroups_max;
6490 _maxgroups = ngroups;
6495 #define proc_setmaxgroups rb_f_notimplement
6498 #if defined(HAVE_DAEMON) || (defined(HAVE_WORKING_FORK) && defined(HAVE_SETSID))
6499 static int rb_daemon(
int nochdir,
int noclose);
6526 n = rb_daemon(nochdir, noclose);
6532 rb_daemon(
int nochdir,
int noclose)
6544 #define fork_daemon() \
6545 switch (rb_fork_ruby(NULL)) { \
6546 case -1: return -1; \
6547 case 0: rb_thread_atfork(); break; \
6548 default: _exit(EXIT_SUCCESS); \
6553 if (
setsid() < 0)
return -1;
6573 #define proc_daemon rb_f_notimplement
6586 static rb_gid_t SAVED_GROUP_ID = -1;
6588 #ifdef BROKEN_SETREGID
6594 if (
setgid(rgid) < 0)
return -1;
6597 if (
setegid(egid) < 0)
return -1;
6626 #if defined(HAVE_SETRESGID)
6628 SAVED_GROUP_ID = gid;
6629 #elif defined HAVE_SETGID
6631 SAVED_GROUP_ID = gid;
6632 #elif defined(HAVE_SETREGID) && !defined(OBSOLETE_SETREGID)
6634 if (SAVED_GROUP_ID == gid) {
6643 SAVED_GROUP_ID = gid;
6649 SAVED_GROUP_ID = gid;
6655 SAVED_GROUP_ID = gid;
6657 #elif defined(HAVE_SETRGID) && defined (HAVE_SETEGID)
6659 if (SAVED_GROUP_ID == gid) {
6674 SAVED_GROUP_ID = gid;
6681 SAVED_GROUP_ID = gid;
6688 #if defined(HAVE_SETRESGID)
6692 SAVED_GROUP_ID = gid;
6693 #elif defined(HAVE_SETREGID) && !defined(OBSOLETE_SETREGID)
6694 if (SAVED_GROUP_ID == gid) {
6699 else if (
getgid() != gid) {
6702 SAVED_GROUP_ID = gid;
6706 SAVED_GROUP_ID = gid;
6712 SAVED_GROUP_ID = gid;
6715 #elif defined(HAVE_SETRGID) && defined(HAVE_SETEGID)
6716 if (SAVED_GROUP_ID == gid) {
6723 SAVED_GROUP_ID = gid;
6727 SAVED_GROUP_ID = gid;
6731 else if (
getgid() == gid) {
6734 SAVED_GROUP_ID = gid;
6740 #elif defined HAVE_44BSD_SETGID
6744 SAVED_GROUP_ID = gid;
6749 #elif defined HAVE_SETEGID
6750 if (
getgid() == gid && SAVED_GROUP_ID == gid) {
6756 #elif defined HAVE_SETGID
6757 if (
getgid() == gid && SAVED_GROUP_ID == gid) {
6790 #if defined(HAVE_SETRESUID) || defined(HAVE_SETREUID) || defined(HAVE_SETEUID) || defined(HAVE_SETUID) || defined(_POSIX_SAVED_IDS)
6794 #if defined(HAVE_SETRESUID)
6796 #elif defined HAVE_SETREUID
6798 #elif defined HAVE_SETEUID
6800 #elif defined HAVE_SETUID
6813 #if defined(HAVE_SETRESUID) || defined(HAVE_SETREUID) || defined(HAVE_SETEUID) || defined(HAVE_SETUID)
6830 #define proc_seteuid_m rb_f_notimplement
6836 #if defined(HAVE_SETRESUID) || (defined(HAVE_SETREUID) && !defined(OBSOLETE_SETREUID))
6842 #if defined(HAVE_SETRESUID) || (defined(HAVE_SETREUID) && !defined(OBSOLETE_SETREUID))
6846 #if defined(HAVE_SETRESUID)
6849 SAVED_USER_ID = euid;
6854 #elif defined(HAVE_SETREUID) && !defined(OBSOLETE_SETREUID)
6859 SAVED_USER_ID = euid;
6861 #elif defined HAVE_SETEUID
6863 #elif defined HAVE_SETUID
6915 #if defined(HAVE_SETRESGID) || defined(HAVE_SETREGID) || defined(HAVE_SETEGID) || defined(HAVE_SETGID) || defined(_POSIX_SAVED_IDS)
6927 #if defined(HAVE_SETRESGID) || defined(HAVE_SETREGID) || defined(HAVE_SETEGID) || defined(HAVE_SETGID)
6933 #if defined(HAVE_SETRESGID) || defined(HAVE_SETREGID) || defined(HAVE_SETEGID) || defined(HAVE_SETGID)
6937 #if defined(HAVE_SETRESGID)
6939 #elif defined HAVE_SETREGID
6941 #elif defined HAVE_SETEGID
6943 #elif defined HAVE_SETGID
6957 #if defined(HAVE_SETRESGID) || defined(HAVE_SETREGID) || defined(HAVE_SETEGID) || defined(HAVE_SETGID)
6958 #define proc_setegid_m proc_setegid
6960 #define proc_setegid_m rb_f_notimplement
6966 #if defined(HAVE_SETRESGID) || (defined(HAVE_SETREGID) && !defined(OBSOLETE_SETREGID))
6972 #if defined(HAVE_SETRESGID) || (defined(HAVE_SETREGID) && !defined(OBSOLETE_SETREGID))
6976 #if defined(HAVE_SETRESGID)
6979 SAVED_GROUP_ID = egid;
6984 #elif defined(HAVE_SETREGID) && !defined(OBSOLETE_SETREGID)
6989 SAVED_GROUP_ID = egid;
6991 #elif defined HAVE_SETEGID
6993 #elif defined HAVE_SETGID
7035 p_uid_exchangeable(
VALUE _)
7037 #if defined(HAVE_SETRESUID)
7039 #elif defined(HAVE_SETREUID) && !defined(OBSOLETE_SETREUID)
7063 #if defined(HAVE_SETRESUID) || (defined(HAVE_SETREUID) && !defined(OBSOLETE_SETREUID))
7070 #if defined(HAVE_SETRESUID) || (defined(HAVE_SETREUID) && !defined(OBSOLETE_SETREUID))
7074 #if defined(HAVE_SETRESUID)
7075 if (setresuid(euid, uid, uid) < 0)
rb_sys_fail(0);
7076 SAVED_USER_ID = uid;
7077 #elif defined(HAVE_SETREUID) && !defined(OBSOLETE_SETREUID)
7079 SAVED_USER_ID = uid;
7097 p_gid_exchangeable(
VALUE _)
7099 #if defined(HAVE_SETRESGID)
7101 #elif defined(HAVE_SETREGID) && !defined(OBSOLETE_SETREGID)
7125 #if defined(HAVE_SETRESGID) || (defined(HAVE_SETREGID) && !defined(OBSOLETE_SETREGID))
7132 #if defined(HAVE_SETRESGID) || (defined(HAVE_SETREGID) && !defined(OBSOLETE_SETREGID))
7136 #if defined(HAVE_SETRESGID)
7137 if (setresgid(egid, gid, gid) < 0)
rb_sys_fail(0);
7138 SAVED_GROUP_ID = gid;
7139 #elif defined(HAVE_SETREGID) && !defined(OBSOLETE_SETREGID)
7141 SAVED_GROUP_ID = gid;
7160 p_uid_have_saved_id(
VALUE _)
7162 #if defined(HAVE_SETRESUID) || defined(HAVE_SETEUID) || defined(_POSIX_SAVED_IDS)
7170 #if defined(HAVE_SETRESUID) || defined(HAVE_SETEUID) || defined(_POSIX_SAVED_IDS)
7175 under_uid_switch = 0;
7176 id = rb_seteuid_core(
id);
7207 under_uid_switch = 1;
7214 else if (euid != SAVED_USER_ID) {
7215 proc_seteuid(SAVED_USER_ID);
7217 under_uid_switch = 1;
7234 under_uid_switch = 0;
7235 return p_uid_exchange(
obj);
7251 p_uid_exchange(
obj);
7253 under_uid_switch = 1;
7275 p_gid_have_saved_id(
VALUE _)
7277 #if defined(HAVE_SETRESGID) || defined(HAVE_SETEGID) || defined(_POSIX_SAVED_IDS)
7284 #if defined(HAVE_SETRESGID) || defined(HAVE_SETEGID) || defined(_POSIX_SAVED_IDS)
7289 under_gid_switch = 0;
7290 id = rb_setegid_core(
id);
7321 under_gid_switch = 1;
7328 else if (egid != SAVED_GROUP_ID) {
7331 under_gid_switch = 1;
7348 under_gid_switch = 0;
7349 return p_gid_exchange(
obj);
7365 p_gid_exchange(
obj);
7367 under_gid_switch = 1;
7377 #if defined(HAVE_TIMES)
7381 #ifdef HAVE__SC_CLK_TCK
7383 #elif defined CLK_TCK
7408 #if defined(RUSAGE_SELF) && defined(RUSAGE_CHILDREN)
7409 struct rusage usage_s, usage_c;
7411 if (getrusage(RUSAGE_SELF, &usage_s) != 0 || getrusage(RUSAGE_CHILDREN, &usage_c) != 0)
7413 utime =
DBL2NUM((
double)usage_s.ru_utime.tv_sec + (
double)usage_s.ru_utime.tv_usec/1e6);
7414 stime =
DBL2NUM((
double)usage_s.ru_stime.tv_sec + (
double)usage_s.ru_stime.tv_usec/1e6);
7415 cutime =
DBL2NUM((
double)usage_c.ru_utime.tv_sec + (
double)usage_c.ru_utime.tv_usec/1e6);
7416 cstime =
DBL2NUM((
double)usage_c.ru_stime.tv_sec + (
double)usage_c.ru_stime.tv_usec/1e6);
7418 const double hertz = (
double)get_clk_tck();
7435 #define rb_proc_times rb_f_notimplement
7438 #ifdef HAVE_LONG_LONG
7440 #define TIMETICK_INT_MIN LLONG_MIN
7441 #define TIMETICK_INT_MAX LLONG_MAX
7442 #define TIMETICK_INT2NUM(v) LL2NUM(v)
7443 #define MUL_OVERFLOW_TIMETICK_P(a, b) MUL_OVERFLOW_LONG_LONG_P(a, b)
7446 #define TIMETICK_INT_MIN LONG_MIN
7447 #define TIMETICK_INT_MAX LONG_MAX
7448 #define TIMETICK_INT2NUM(v) LONG2NUM(v)
7449 #define MUL_OVERFLOW_TIMETICK_P(a, b) MUL_OVERFLOW_LONG_P(a, b)
7488 for (
i = 0;
i < num_numerators;
i++) {
7489 if (numerators[
i] == 1)
7491 for (j = 0; j < num_denominators; j++) {
7492 if (denominators[j] == 1)
7494 reduce_fraction(&numerators[
i], &denominators[j]);
7505 timetick2dblnum(
struct timetick *ttp,
7512 reduce_factors(numerators, num_numerators,
7513 denominators, num_denominators);
7517 for (
i = 0;
i < num_numerators;
i++)
7519 for (
i = 0;
i < num_denominators;
i++)
7520 d /= denominators[
i];
7526 timetick2dblnum_reciprocal(
struct timetick *ttp,
7533 reduce_factors(numerators, num_numerators,
7534 denominators, num_denominators);
7537 for (
i = 0;
i < num_denominators;
i++)
7538 d *= denominators[
i];
7539 for (
i = 0;
i < num_numerators;
i++)
7546 #define NDIV(x,y) (-(-((x)+1)/(y))-1)
7547 #define DIV(n,d) ((n)<0 ? NDIV((n),(d)) : (n)/(d))
7550 timetick2integer(
struct timetick *ttp,
7557 reduce_factors(numerators, num_numerators,
7558 denominators, num_denominators);
7563 for (
i = 0;
i < num_numerators;
i++) {
7569 for (
i = 0;
i < num_denominators;
i++) {
7570 t =
DIV(t, denominators[
i]);
7579 for (
i = 0;
i < num_numerators;
i++) {
7585 for (
i = 0;
i < num_denominators;
i++) {
7592 make_clock_result(
struct timetick *ttp,
7597 if (unit ==
ID2SYM(id_nanosecond)) {
7598 numerators[num_numerators++] = 1000000000;
7599 return timetick2integer(ttp, numerators, num_numerators, denominators, num_denominators);
7601 else if (unit ==
ID2SYM(id_microsecond)) {
7602 numerators[num_numerators++] = 1000000;
7603 return timetick2integer(ttp, numerators, num_numerators, denominators, num_denominators);
7605 else if (unit ==
ID2SYM(id_millisecond)) {
7606 numerators[num_numerators++] = 1000;
7607 return timetick2integer(ttp, numerators, num_numerators, denominators, num_denominators);
7609 else if (unit ==
ID2SYM(id_second)) {
7610 return timetick2integer(ttp, numerators, num_numerators, denominators, num_denominators);
7612 else if (unit ==
ID2SYM(id_float_microsecond)) {
7613 numerators[num_numerators++] = 1000000;
7614 return timetick2dblnum(ttp, numerators, num_numerators, denominators, num_denominators);
7616 else if (unit ==
ID2SYM(id_float_millisecond)) {
7617 numerators[num_numerators++] = 1000;
7618 return timetick2dblnum(ttp, numerators, num_numerators, denominators, num_denominators);
7620 else if (
NIL_P(unit) || unit ==
ID2SYM(id_float_second)) {
7621 return timetick2dblnum(ttp, numerators, num_numerators, denominators, num_denominators);
7628 static const mach_timebase_info_data_t *
7629 get_mach_timebase_info(
void)
7631 static mach_timebase_info_data_t sTimebaseInfo;
7633 if ( sTimebaseInfo.denom == 0 ) {
7634 (
void) mach_timebase_info(&sTimebaseInfo);
7637 return &sTimebaseInfo;
7641 ruby_real_ms_time(
void)
7643 const mach_timebase_info_data_t *info = get_mach_timebase_info();
7645 return (
double)t * info->numer / info->denom / 1e6;
7784 int num_numerators = 0;
7785 int num_denominators = 0;
7794 #ifdef HAVE_GETTIMEOFDAY
7799 #define RUBY_GETTIMEOFDAY_BASED_CLOCK_REALTIME ID2SYM(id_GETTIMEOFDAY_BASED_CLOCK_REALTIME)
7800 if (clk_id == RUBY_GETTIMEOFDAY_BASED_CLOCK_REALTIME) {
7807 denominators[num_denominators++] = 1000000000;
7812 #define RUBY_TIME_BASED_CLOCK_REALTIME ID2SYM(id_TIME_BASED_CLOCK_REALTIME)
7820 denominators[num_denominators++] = 1000000000;
7825 #define RUBY_TIMES_BASED_CLOCK_MONOTONIC \
7826 ID2SYM(id_TIMES_BASED_CLOCK_MONOTONIC)
7827 if (clk_id == RUBY_TIMES_BASED_CLOCK_MONOTONIC) {
7837 denominators[num_denominators++] = get_clk_tck();
7843 #define RUBY_GETRUSAGE_BASED_CLOCK_PROCESS_CPUTIME_ID \
7844 ID2SYM(id_GETRUSAGE_BASED_CLOCK_PROCESS_CPUTIME_ID)
7845 if (clk_id == RUBY_GETRUSAGE_BASED_CLOCK_PROCESS_CPUTIME_ID) {
7846 struct rusage usage;
7848 ret = getrusage(RUSAGE_SELF, &usage);
7851 tt.
giga_count = usage.ru_utime.tv_sec + usage.ru_stime.tv_sec;
7852 usec = (
int32_t)(usage.ru_utime.tv_usec + usage.ru_stime.tv_usec);
7853 if (1000000 <= usec) {
7857 tt.
count = usec * 1000;
7858 denominators[num_denominators++] = 1000000000;
7864 #define RUBY_TIMES_BASED_CLOCK_PROCESS_CPUTIME_ID \
7865 ID2SYM(id_TIMES_BASED_CLOCK_PROCESS_CPUTIME_ID)
7866 if (clk_id == RUBY_TIMES_BASED_CLOCK_PROCESS_CPUTIME_ID) {
7875 if (1000000000 <= tt.
count) {
7876 tt.
count -= 1000000000;
7879 denominators[num_denominators++] = get_clk_tck();
7884 #define RUBY_CLOCK_BASED_CLOCK_PROCESS_CPUTIME_ID \
7885 ID2SYM(id_CLOCK_BASED_CLOCK_PROCESS_CPUTIME_ID)
7901 #define RUBY_MACH_ABSOLUTE_TIME_BASED_CLOCK_MONOTONIC ID2SYM(id_MACH_ABSOLUTE_TIME_BASED_CLOCK_MONOTONIC)
7902 if (clk_id == RUBY_MACH_ABSOLUTE_TIME_BASED_CLOCK_MONOTONIC) {
7903 const mach_timebase_info_data_t *info = get_mach_timebase_info();
7907 numerators[num_numerators++] = info->numer;
7908 denominators[num_denominators++] = info->denom;
7909 denominators[num_denominators++] = 1000000000;
7915 #if defined(HAVE_CLOCK_GETTIME)
7924 denominators[num_denominators++] = 1000000000;
7932 return make_clock_result(&tt, numerators, num_numerators, denominators, num_denominators, unit);
7979 int num_numerators = 0;
7980 int num_denominators = 0;
7986 #ifdef RUBY_GETTIMEOFDAY_BASED_CLOCK_REALTIME
7987 if (clk_id == RUBY_GETTIMEOFDAY_BASED_CLOCK_REALTIME) {
7990 denominators[num_denominators++] = 1000000000;
7995 #ifdef RUBY_TIME_BASED_CLOCK_REALTIME
7999 denominators[num_denominators++] = 1000000000;
8004 #ifdef RUBY_TIMES_BASED_CLOCK_MONOTONIC
8005 if (clk_id == RUBY_TIMES_BASED_CLOCK_MONOTONIC) {
8008 denominators[num_denominators++] = get_clk_tck();
8013 #ifdef RUBY_GETRUSAGE_BASED_CLOCK_PROCESS_CPUTIME_ID
8014 if (clk_id == RUBY_GETRUSAGE_BASED_CLOCK_PROCESS_CPUTIME_ID) {
8017 denominators[num_denominators++] = 1000000000;
8022 #ifdef RUBY_TIMES_BASED_CLOCK_PROCESS_CPUTIME_ID
8023 if (clk_id == RUBY_TIMES_BASED_CLOCK_PROCESS_CPUTIME_ID) {
8026 denominators[num_denominators++] = get_clk_tck();
8031 #ifdef RUBY_CLOCK_BASED_CLOCK_PROCESS_CPUTIME_ID
8040 #ifdef RUBY_MACH_ABSOLUTE_TIME_BASED_CLOCK_MONOTONIC
8041 if (clk_id == RUBY_MACH_ABSOLUTE_TIME_BASED_CLOCK_MONOTONIC) {
8042 const mach_timebase_info_data_t *info = get_mach_timebase_info();
8045 numerators[num_numerators++] = info->numer;
8046 denominators[num_denominators++] = info->denom;
8047 denominators[num_denominators++] = 1000000000;
8053 #if defined(HAVE_CLOCK_GETRES)
8061 denominators[num_denominators++] = 1000000000;
8069 if (unit ==
ID2SYM(id_hertz)) {
8070 return timetick2dblnum_reciprocal(&tt, numerators, num_numerators, denominators, num_denominators);
8073 return make_clock_result(&tt, numerators, num_numerators, denominators, num_denominators, unit);
8078 get_CHILD_STATUS(
ID _x,
VALUE *_y)
8084 get_PROCESS_ID(
ID _x,
VALUE *_y)
8132 static VALUE rb_mProcUID;
8133 static VALUE rb_mProcGID;
8134 static VALUE rb_mProcID_Syscall;
8146 #define rb_intern(str) rb_intern_const(str)
8232 #ifdef HAVE_GETPRIORITY
8243 #if defined(RLIM2NUM) && defined(RLIM_INFINITY)
8246 #ifdef RLIM_SAVED_MAX
8248 VALUE v = RLIM_INFINITY == RLIM_SAVED_MAX ? inf :
RLIM2NUM(RLIM_SAVED_MAX);
8255 #ifdef RLIM_SAVED_CUR
8257 VALUE v = RLIM_INFINITY == RLIM_SAVED_CUR ? inf :
RLIM2NUM(RLIM_SAVED_CUR);
8298 #ifdef RLIMIT_MEMLOCK
8305 #ifdef RLIMIT_MSGQUEUE
8320 #ifdef RLIMIT_NOFILE
8343 #ifdef RLIMIT_RTPRIO
8350 #ifdef RLIMIT_RTTIME
8358 #ifdef RLIMIT_SBSIZE
8363 #ifdef RLIMIT_SIGPENDING
8398 #ifdef CLOCK_REALTIME
8401 #elif defined(RUBY_GETTIMEOFDAY_BASED_CLOCK_REALTIME)
8405 #ifdef CLOCK_MONOTONIC
8408 #elif defined(RUBY_MACH_ABSOLUTE_TIME_BASED_CLOCK_MONOTONIC)
8412 #ifdef CLOCK_PROCESS_CPUTIME_ID
8415 #elif defined(RUBY_GETRUSAGE_BASED_CLOCK_PROCESS_CPUTIME_ID)
8419 #ifdef CLOCK_THREAD_CPUTIME_ID
8423 #ifdef CLOCK_VIRTUAL
8431 #ifdef CLOCK_REALTIME_FAST
8435 #ifdef CLOCK_REALTIME_PRECISE
8439 #ifdef CLOCK_REALTIME_COARSE
8443 #ifdef CLOCK_REALTIME_ALARM
8447 #ifdef CLOCK_MONOTONIC_FAST
8451 #ifdef CLOCK_MONOTONIC_PRECISE
8455 #ifdef CLOCK_MONOTONIC_RAW
8459 #ifdef CLOCK_MONOTONIC_RAW_APPROX
8463 #ifdef CLOCK_MONOTONIC_COARSE
8467 #ifdef CLOCK_BOOTTIME
8471 #ifdef CLOCK_BOOTTIME_ALARM
8479 #ifdef CLOCK_UPTIME_FAST
8483 #ifdef CLOCK_UPTIME_PRECISE
8487 #ifdef CLOCK_UPTIME_RAW
8491 #ifdef CLOCK_UPTIME_RAW_APPROX
8506 #if defined(HAVE_TIMES) || defined(_WIN32)
8538 #ifdef p_uid_from_name
8541 #ifdef p_gid_from_name
8584 id_new_pgroup =
rb_intern(
"new_pgroup");
8586 id_unsetenv_others =
rb_intern(
"unsetenv_others");
8589 id_close_others =
rb_intern(
"close_others");
8591 id_nanosecond =
rb_intern(
"nanosecond");
8592 id_microsecond =
rb_intern(
"microsecond");
8593 id_millisecond =
rb_intern(
"millisecond");
8595 id_float_microsecond =
rb_intern(
"float_microsecond");
8596 id_float_millisecond =
rb_intern(
"float_millisecond");
8597 id_float_second =
rb_intern(
"float_second");
8598 id_GETTIMEOFDAY_BASED_CLOCK_REALTIME =
rb_intern(
"GETTIMEOFDAY_BASED_CLOCK_REALTIME");
8599 id_TIME_BASED_CLOCK_REALTIME =
rb_intern(
"TIME_BASED_CLOCK_REALTIME");
8601 id_TIMES_BASED_CLOCK_MONOTONIC =
rb_intern(
"TIMES_BASED_CLOCK_MONOTONIC");
8602 id_TIMES_BASED_CLOCK_PROCESS_CPUTIME_ID =
rb_intern(
"TIMES_BASED_CLOCK_PROCESS_CPUTIME_ID");
8605 id_GETRUSAGE_BASED_CLOCK_PROCESS_CPUTIME_ID =
rb_intern(
"GETRUSAGE_BASED_CLOCK_PROCESS_CPUTIME_ID");
8607 id_CLOCK_BASED_CLOCK_PROCESS_CPUTIME_ID =
rb_intern(
"CLOCK_BASED_CLOCK_PROCESS_CPUTIME_ID");
8609 id_MACH_ABSOLUTE_TIME_BASED_CLOCK_MONOTONIC =
rb_intern(
"MACH_ABSOLUTE_TIME_BASED_CLOCK_MONOTONIC");