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
2897 err = exec_async_signal_safe(eargp, errmsg,
sizeof(errmsg));
2900 rb_exec_fail(eargp,
err, errmsg);
2985 #define ERRMSG(str) do { if (errmsg && 0 < errmsg_buflen) strlcpy(errmsg, (str), errmsg_buflen); } while (0)
2986 #define ERRMSG1(str, a) do { if (errmsg && 0 < errmsg_buflen) snprintf(errmsg, errmsg_buflen, (str), (a)); } while (0)
2987 #define ERRMSG2(str, a, b) do { if (errmsg && 0 < errmsg_buflen) snprintf(errmsg, errmsg_buflen, (str), (a), (b)); } while (0)
2989 static int fd_get_cloexec(
int fd,
char *errmsg,
size_t errmsg_buflen);
2990 static int fd_set_cloexec(
int fd,
char *errmsg,
size_t errmsg_buflen);
2991 static int fd_clear_cloexec(
int fd,
char *errmsg,
size_t errmsg_buflen);
2994 save_redirect_fd(
int fd,
struct rb_execarg *sargp,
char *errmsg,
size_t errmsg_buflen)
2997 VALUE newary, redirection;
2999 if (save_fd == -1) {
3011 cloexec = fd_get_cloexec(fd, errmsg, errmsg_buflen);
3028 intcmp(
const void *a,
const void *b)
3030 return *(
int*)a - *(
int*)b;
3034 intrcmp(
const void *a,
const void *b)
3036 return *(
int*)b - *(
int*)a;
3048 run_exec_dup2_tmpbuf_size(
long n)
3055 fd_get_cloexec(
int fd,
char *errmsg,
size_t errmsg_buflen)
3061 ERRMSG(
"fcntl(F_GETFD)");
3071 fd_set_cloexec(
int fd,
char *errmsg,
size_t errmsg_buflen)
3077 ERRMSG(
"fcntl(F_GETFD)");
3084 ERRMSG(
"fcntl(F_SETFD)");
3094 fd_clear_cloexec(
int fd,
char *errmsg,
size_t errmsg_buflen)
3100 ERRMSG(
"fcntl(F_GETFD)");
3107 ERRMSG(
"fcntl(F_SETFD)");
3117 run_exec_dup2(
VALUE ary,
VALUE tmpbuf,
struct rb_execarg *sargp,
char *errmsg,
size_t errmsg_buflen)
3128 for (
i = 0;
i <
n;
i++) {
3143 for (
i = 0;
i <
n;
i++) {
3150 while (pairs < found && (found-1)->
oldfd ==
newfd)
3152 while (found < pairs+n && found->
oldfd ==
newfd) {
3161 for (
i = 0;
i <
n;
i++) {
3163 while (j != -1 && pairs[j].
oldfd != -1 && pairs[j].
num_newer == 0) {
3164 if (save_redirect_fd(pairs[j].
newfd, sargp, errmsg, errmsg_buflen) < 0)
3172 fd_set_cloexec(pairs[j].
newfd, errmsg, errmsg_buflen)) {
3176 pairs[j].
oldfd = -1;
3184 for (
i = 0;
i <
n;
i++) {
3186 if (pairs[
i].
oldfd == -1)
3189 if (fd_clear_cloexec(pairs[
i].
oldfd, errmsg, errmsg_buflen) == -1)
3194 if (extra_fd == -1) {
3196 if (extra_fd == -1) {
3210 pairs[
i].
oldfd = extra_fd;
3220 pairs[j].
oldfd = -1;
3224 if (extra_fd != -1) {
3240 run_exec_close(
VALUE ary,
char *errmsg,
size_t errmsg_buflen)
3259 run_exec_dup2_child(
VALUE ary,
struct rb_execarg *sargp,
char *errmsg,
size_t errmsg_buflen)
3269 if (save_redirect_fd(
newfd, sargp, errmsg, errmsg_buflen) < 0)
3284 run_exec_pgroup(
const struct rb_execarg *eargp,
struct rb_execarg *sargp,
char *errmsg,
size_t errmsg_buflen)
3310 if (ret == -1)
ERRMSG(
"setpgid");
3315 #if defined(HAVE_SETRLIMIT) && defined(RLIM2NUM)
3318 run_exec_rlimit(
VALUE ary,
struct rb_execarg *sargp,
char *errmsg,
size_t errmsg_buflen)
3327 if (getrlimit(rtype, &rlim) == -1) {
3342 if (setrlimit(rtype, &rlim) == -1) {
3351 #if !defined(HAVE_WORKING_FORK)
3380 #define chdir(p) rb_w32_uchdir(p)
3397 if (run_exec_pgroup(eargp, sargp, errmsg, errmsg_buflen) == -1)
3402 #if defined(HAVE_SETRLIMIT) && defined(RLIM2NUM)
3405 if (run_exec_rlimit(
obj, sargp, errmsg, errmsg_buflen) == -1)
3410 #if !defined(HAVE_WORKING_FORK)
3443 if (run_exec_dup2(
obj, eargp->
dup2_tmpbuf, sargp, errmsg, errmsg_buflen) == -1)
3450 rb_warn(
"cannot close fd before spawn");
3452 if (run_exec_close(
obj, errmsg, errmsg_buflen) == -1)
3457 #ifdef HAVE_WORKING_FORK
3465 if (run_exec_dup2_child(
obj, sargp, errmsg, errmsg_buflen) == -1)
3502 rb_execarg_allocate_dup2_tmpbuf(sargp,
RARRAY_LEN(ary));
3506 int preserve =
errno;
3507 stdfd_clear_nonblock();
3518 errno = exec_async_signal_safe(eargp, errmsg, errmsg_buflen);
3523 exec_async_signal_safe(
const struct rb_execarg *eargp,
char *errmsg,
size_t errmsg_buflen)
3525 #if !defined(HAVE_WORKING_FORK)
3526 struct rb_execarg sarg, *
const sargp = &sarg;
3540 char *abspath =
NULL;
3545 #if !defined(HAVE_WORKING_FORK)
3552 #ifdef HAVE_WORKING_FORK
3555 rb_exec_atfork(
void*
arg,
char *errmsg,
size_t errmsg_buflen)
3560 #if SIZEOF_INT == SIZEOF_LONG
3561 #define proc_syswait (VALUE (*)(VALUE))rb_syswait
3564 proc_syswait(
VALUE pid)
3572 move_fds_to_avoid_crash(
int *fdp,
int n,
VALUE fds)
3576 for (
i = 0;
i <
n;
i++) {
3595 pipe_nocrash(
int filedes[2],
VALUE fds)
3603 if (move_fds_to_avoid_crash(filedes, 2, fds) == -1) {
3618 rb_thread_sleep_that_takes_VALUE_as_sole_argument(
VALUE n)
3625 handle_fork_error(
int err,
int *status,
int *ep,
volatile int *try_gc_p)
3637 #if defined(EWOULDBLOCK) && EWOULDBLOCK != EAGAIN
3640 if (!status && !ep) {
3645 rb_protect(rb_thread_sleep_that_takes_VALUE_as_sole_argument,
INT2FIX(1), &state);
3646 if (status) *status = state;
3647 if (!state)
return 0;
3660 #define prefork() ( \
3661 rb_io_flush(rb_stdout), \
3662 rb_io_flush(rb_stderr) \
3692 write_retry(
int fd,
const void *
buf,
size_t len)
3704 read_retry(
int fd,
void *
buf,
size_t len)
3708 if (set_blocking(fd) != 0) {
3722 send_child_error(
int fd,
char *errmsg,
size_t errmsg_buflen)
3728 if (errmsg && 0 < errmsg_buflen) {
3729 errmsg[errmsg_buflen-1] =
'\0';
3730 errmsg_buflen =
strlen(errmsg);
3731 if (errmsg_buflen > 0 && write_retry(fd, errmsg, errmsg_buflen) < 0)
3737 recv_child_error(
int fd,
int *errp,
char *errmsg,
size_t errmsg_buflen)
3741 if ((
size = read_retry(fd, &
err,
sizeof(
err))) < 0) {
3746 errmsg && 0 < errmsg_buflen) {
3747 ssize_t ret = read_retry(fd, errmsg, errmsg_buflen-1);
3756 #ifdef HAVE_WORKING_VFORK
3757 #if !defined(HAVE_GETRESUID) && defined(HAVE_GETUIDX)
3766 ret = getuidx(ID_SAVED);
3772 #define HAVE_GETRESUID
3775 #if !defined(HAVE_GETRESGID) && defined(HAVE_GETGIDX)
3784 ret = getgidx(ID_SAVED);
3790 #define HAVE_GETRESGID
3811 #if defined HAVE_ISSETUGID
3816 #ifdef HAVE_GETRESUID
3820 ret = getresuid(&ruid, &euid, &suid);
3831 if (euid == 0 || euid != ruid)
3834 #ifdef HAVE_GETRESGID
3838 ret = getresgid(&rgid, &egid, &sgid);
3856 struct child_handler_disabler_state
3862 disable_child_handler_before_fork(
struct child_handler_disabler_state *
old)
3867 #ifdef HAVE_PTHREAD_SIGMASK
3877 # pragma GCC warning "pthread_sigmask on fork is not available. potentially dangerous"
3882 disable_child_handler_fork_parent(
struct child_handler_disabler_state *
old)
3886 #ifdef HAVE_PTHREAD_SIGMASK
3892 # pragma GCC warning "pthread_sigmask on fork is not available. potentially dangerous"
3898 disable_child_handler_fork_child(
struct child_handler_disabler_state *
old,
char *errmsg,
size_t errmsg_buflen)
3910 ERRMSG(
"signal to obtain old action");
3939 retry_fork_async_signal_safe(
int *status,
int *ep,
3940 int (*chfunc)(
void*,
char *,
size_t),
void *charg,
3941 char *errmsg,
size_t errmsg_buflen,
3945 volatile int try_gc = 1;
3946 struct child_handler_disabler_state
old;
3954 disable_child_handler_before_fork(&
old);
3958 #ifdef HAVE_WORKING_VFORK
3959 if (!has_privilege())
3969 ret = disable_child_handler_fork_child(&
old, errmsg, errmsg_buflen);
3971 ret = chfunc(charg, errmsg, errmsg_buflen);
3974 send_child_error(ep[1], errmsg, errmsg_buflen);
3975 #if EXIT_SUCCESS == 127
3982 waitpid_lock = waitpid_lock_init;
3990 disable_child_handler_fork_parent(&
old);
3994 if (handle_fork_error(
err, status, ep, &try_gc))
4001 fork_check_err(
int *status,
int (*chfunc)(
void*,
char *,
size_t),
void *charg,
4002 VALUE fds,
char *errmsg,
size_t errmsg_buflen,
4015 if (pipe_nocrash(ep, fds))
return -1;
4016 pid = retry_fork_async_signal_safe(
status, ep, chfunc, charg,
4017 errmsg, errmsg_buflen, w);
4021 error_occurred = recv_child_error(ep[0], &
err, errmsg, errmsg_buflen);
4022 if (error_occurred) {
4025 "only used by extensions");
4046 int (*chfunc)(
void*,
char *,
size_t),
void *charg,
4047 VALUE fds,
char *errmsg,
size_t errmsg_buflen)
4049 return fork_check_err(
status, chfunc, charg, fds, errmsg, errmsg_buflen, 0);
4060 int try_gc = 1,
err;
4061 struct child_handler_disabler_state
old;
4063 if (status) *status = 0;
4068 disable_child_handler_before_fork(&
old);
4073 disable_child_handler_fork_parent(&
old);
4078 if (handle_fork_error(
err, status,
NULL, &try_gc))
4086 #if defined(HAVE_WORKING_FORK) && !defined(CANNOT_FORK_WITH_PTHREAD)
4136 #define rb_f_fork rb_f_notimplement
4140 exit_status_code(
VALUE status)
4153 #if EXIT_SUCCESS != 0
4179 istatus = exit_status_code(
argv[0]);
4208 istatus = exit_status_code(
argv[0]);
4283 if (!
NIL_P(errinfo)) {
4291 args[1] = args[0] =
argv[0];
4315 #if !defined HAVE_WORKING_FORK && !defined HAVE_SPAWNV
4329 p[
argv[
i] - start - 1] =
' ';
4339 rb_spawn_process(
struct rb_execarg *eargp,
char *errmsg,
size_t errmsg_buflen)
4342 #if !defined HAVE_WORKING_FORK || USE_SPAWNV
4345 # if !defined HAVE_SPAWNV
4350 #if defined HAVE_WORKING_FORK && !USE_SPAWNV
4351 pid = fork_check_err(0, rb_exec_atfork, eargp, eargp->
redirect_fds,
4352 errmsg, errmsg_buflen, eargp);
4364 # if defined HAVE_SPAWNV
4370 pid = proc_spawn_cmd(
argv, prog, eargp);
4399 rb_execarg_parent_start1(argp->
execarg);
4405 rb_execarg_spawn(
VALUE execarg_obj,
char *
errmsg,
size_t errmsg_buflen)
4418 args.execarg = execarg_obj;
4419 args.errmsg.ptr = errmsg;
4420 args.errmsg.buflen = errmsg_buflen;
4422 execarg_parent_end, execarg_obj);
4426 rb_spawn_internal(
int argc,
const VALUE *
argv,
char *errmsg,
size_t errmsg_buflen)
4431 return rb_execarg_spawn(execarg_obj, errmsg, errmsg_buflen);
4437 return rb_spawn_internal(
argc,
argv, errmsg, errmsg_buflen);
4513 waitpid_state_init(w, 0, 0);
4515 pid = rb_execarg_spawn(execarg_obj, 0, 0);
4516 exec_errnum = pid < 0 ?
errno : 0;
4518 #if defined(HAVE_WORKING_FORK) || defined(HAVE_SPAWNV)
4525 waitpid_no_SIGCHLD(w);
4530 if (w->
pid < 0 || pid < 0 ) {
4531 if (eargp->exception) {
4532 int err = exec_errnum ? exec_errnum : w->
errnum;
4542 if (eargp->exception) {
4829 VALUE execarg_obj, fail_str;
4836 pid = rb_execarg_spawn(execarg_obj, errmsg,
sizeof(errmsg));
4840 rb_exec_fail(eargp,
err, errmsg);
4844 #if defined(HAVE_WORKING_FORK) || defined(HAVE_SPAWNV)
4882 end =
time(0) - beg;
4888 #if (defined(HAVE_GETPGRP) && defined(GETPGRP_VOID)) || defined(HAVE_GETPGID)
4905 #if defined(HAVE_GETPGRP) && defined(GETPGRP_VOID)
4916 #define proc_getpgrp rb_f_notimplement
4920 #if defined(HAVE_SETPGID) || (defined(HAVE_SETPGRP) && defined(SETPGRP_VOID))
4938 #elif defined(HAVE_SETPGRP) && defined(SETPGRP_VOID)
4944 #define proc_setpgrp rb_f_notimplement
4948 #if defined(HAVE_GETPGID)
4969 #define proc_getpgid rb_f_notimplement
4994 #define proc_setpgid rb_f_notimplement
5025 #define proc_getsid rb_f_notimplement
5029 #if defined(HAVE_SETSID) || (defined(HAVE_SETPGRP) && defined(TIOCNOTTY))
5030 #if !defined(HAVE_SETSID)
5032 #define setsid() ruby_setsid()
5055 #if !defined(HAVE_SETSID)
5056 #define HAVE_SETSID 1
5064 #if defined(SETPGRP_VOID)
5072 if (ret == -1)
return -1;
5083 #define proc_setsid rb_f_notimplement
5087 #ifdef HAVE_GETPRIORITY
5108 int prio, iwhich, iwho;
5114 prio = getpriority(iwhich, iwho);
5119 #define proc_getpriority rb_f_notimplement
5123 #ifdef HAVE_GETPRIORITY
5139 int iwhich, iwho, iprio;
5145 if (setpriority(iwhich, iwho, iprio) < 0)
5150 #define proc_setpriority rb_f_notimplement
5153 #if defined(HAVE_SETRLIMIT) && defined(NUM2RLIM)
5155 rlimit_resource_name2int(
const char *
name,
long len,
int casetype)
5159 #define RESCHECK(r) \
5161 if (len == rb_strlen_lit(#r) && STRCASECMP(name, #r) == 0) { \
5162 resource = RLIMIT_##r; \
5196 #ifdef RLIMIT_MEMLOCK
5199 #ifdef RLIMIT_MSGQUEUE
5205 #ifdef RLIMIT_NOFILE
5220 #ifdef RLIMIT_RTPRIO
5223 #ifdef RLIMIT_RTTIME
5232 #ifdef RLIMIT_SBSIZE
5235 #ifdef RLIMIT_SIGPENDING
5236 RESCHECK(SIGPENDING);
5245 for (p =
name; *p; p++)
5251 for (p =
name; *p; p++)
5257 rb_bug(
"unexpected casetype");
5264 rlimit_type_by_hname(
const char *
name,
long len)
5266 return rlimit_resource_name2int(
name,
len, 0);
5270 rlimit_type_by_lname(
const char *
name,
long len)
5272 return rlimit_resource_name2int(
name,
len, 1);
5282 static const char prefix[] =
"rlimit_";
5283 enum {prefix_len =
sizeof(prefix)-1};
5285 if (
len > prefix_len &&
strncmp(prefix, rname, prefix_len) == 0) {
5286 rtype = rlimit_type_by_lname(rname + prefix_len,
len - prefix_len);
5294 rlimit_resource_type(
VALUE rtype)
5301 switch (
TYPE(rtype)) {
5324 r = rlimit_type_by_hname(
name,
len);
5334 rlimit_resource_value(
VALUE rval)
5339 switch (
TYPE(rval)) {
5360 #ifdef RLIM_INFINITY
5361 if (
strcmp(
name,
"INFINITY") == 0)
return RLIM_INFINITY;
5363 #ifdef RLIM_SAVED_MAX
5364 if (
strcmp(
name,
"SAVED_MAX") == 0)
return RLIM_SAVED_MAX;
5366 #ifdef RLIM_SAVED_CUR
5367 if (
strcmp(
name,
"SAVED_CUR") == 0)
return RLIM_SAVED_CUR;
5375 #if defined(HAVE_GETRLIMIT) && defined(RLIM2NUM)
5401 if (getrlimit(rlimit_resource_type(resource), &rlim) < 0) {
5407 #define proc_getrlimit rb_f_notimplement
5410 #if defined(HAVE_SETRLIMIT) && defined(NUM2RLIM)
5465 VALUE resource, rlim_cur, rlim_max;
5472 rlim_max = rlim_cur;
5474 rlim.rlim_cur = rlimit_resource_value(rlim_cur);
5475 rlim.rlim_max = rlimit_resource_value(rlim_max);
5477 if (setrlimit(rlimit_resource_type(resource), &rlim) < 0) {
5483 #define proc_setrlimit rb_f_notimplement
5486 static int under_uid_switch = 0;
5488 check_uid_switch(
void)
5490 if (under_uid_switch) {
5495 static int under_gid_switch = 0;
5497 check_gid_switch(
void)
5499 if (under_gid_switch) {
5515 #if defined(HAVE_PWD_H)
5518 # ifdef USE_GETPWNAM_R
5531 struct passwd *pwptr;
5532 #ifdef USE_GETPWNAM_R
5533 struct passwd pwbuf;
5538 getpw_buf_len = GETPW_R_SIZE_INIT;
5539 if (getpw_buf_len < 0) getpw_buf_len = GETPW_R_SIZE_DEFAULT;
5546 while ((e = getpwnam_r(usrname, &pwbuf, getpw_buf, getpw_buf_len, &pwptr)) != 0) {
5547 if (e !=
ERANGE || getpw_buf_len >= GETPW_R_SIZE_LIMIT) {
5556 pwptr = getpwnam(usrname);
5559 #ifndef USE_GETPWNAM_R
5564 uid = pwptr->pw_uid;
5565 #ifndef USE_GETPWNAM_R
5572 # ifdef p_uid_from_name
5592 #if defined(HAVE_GRP_H)
5595 # ifdef USE_GETGRNAM_R
5608 struct group *grptr;
5609 #ifdef USE_GETGRNAM_R
5615 getgr_buf_len = GETGR_R_SIZE_INIT;
5616 if (getgr_buf_len < 0) getgr_buf_len = GETGR_R_SIZE_DEFAULT;
5623 while ((e = getgrnam_r(grpname, &grbuf, getgr_buf, getgr_buf_len, &grptr)) != 0) {
5624 if (e !=
ERANGE || getgr_buf_len >= GETGR_R_SIZE_LIMIT) {
5632 #elif defined(HAVE_GETGRNAM)
5633 grptr = getgrnam(grpname);
5638 #if !defined(USE_GETGRNAM_R) && defined(HAVE_ENDGRENT)
5643 gid = grptr->gr_gid;
5644 #if !defined(USE_GETGRNAM_R) && defined(HAVE_ENDGRENT)
5651 # ifdef p_gid_from_name
5671 #if defined HAVE_SETUID
5689 #define p_sys_setuid rb_f_notimplement
5693 #if defined HAVE_SETRUID
5711 #define p_sys_setruid rb_f_notimplement
5715 #if defined HAVE_SETEUID
5733 #define p_sys_seteuid rb_f_notimplement
5737 #if defined HAVE_SETREUID
5762 #define p_sys_setreuid rb_f_notimplement
5766 #if defined HAVE_SETRESUID
5788 if (setresuid(ruid, euid, suid) != 0)
rb_sys_fail(0);
5792 #define p_sys_setresuid rb_f_notimplement
5815 #if defined(HAVE_SETRESUID) || defined(HAVE_SETREUID) || defined(HAVE_SETRUID) || defined(HAVE_SETUID)
5832 #if defined(HAVE_SETRESUID)
5834 #elif defined HAVE_SETREUID
5836 #elif defined HAVE_SETRUID
5838 #elif defined HAVE_SETUID
5851 #define proc_setuid rb_f_notimplement
5865 static rb_uid_t SAVED_USER_ID = -1;
5867 #ifdef BROKEN_SETREUID
5873 if (
setuid(ruid) < 0)
return -1;
5876 if (
seteuid(euid) < 0)
return -1;
5905 #if defined(HAVE_SETRESUID)
5907 SAVED_USER_ID = uid;
5908 #elif defined(HAVE_SETUID)
5910 SAVED_USER_ID = uid;
5911 #elif defined(HAVE_SETREUID) && !defined(OBSOLETE_SETREUID)
5913 if (SAVED_USER_ID == uid) {
5922 SAVED_USER_ID = uid;
5928 SAVED_USER_ID = uid;
5934 SAVED_USER_ID = uid;
5936 #elif defined(HAVE_SETRUID) && defined(HAVE_SETEUID)
5938 if (SAVED_USER_ID == uid) {
5952 SAVED_USER_ID = uid;
5959 SAVED_USER_ID = uid;
5967 #if defined(HAVE_SETRESUID)
5971 SAVED_USER_ID = uid;
5972 #elif defined(HAVE_SETREUID) && !defined(OBSOLETE_SETREUID)
5973 if (SAVED_USER_ID == uid) {
5978 else if (
getuid() != uid) {
5981 SAVED_USER_ID = uid;
5985 SAVED_USER_ID = uid;
5991 SAVED_USER_ID = uid;
5994 #elif defined(HAVE_SETRUID) && defined(HAVE_SETEUID)
5995 if (SAVED_USER_ID == uid) {
6002 SAVED_USER_ID = uid;
6006 SAVED_USER_ID = uid;
6010 else if (
getuid() == uid) {
6013 SAVED_USER_ID = uid;
6019 #elif defined HAVE_44BSD_SETUID
6023 SAVED_USER_ID = uid;
6028 #elif defined HAVE_SETEUID
6029 if (
getuid() == uid && SAVED_USER_ID == uid) {
6035 #elif defined HAVE_SETUID
6036 if (
getuid() == uid && SAVED_USER_ID == uid) {
6051 #if defined HAVE_SETGID
6069 #define p_sys_setgid rb_f_notimplement
6073 #if defined HAVE_SETRGID
6091 #define p_sys_setrgid rb_f_notimplement
6095 #if defined HAVE_SETEGID
6113 #define p_sys_setegid rb_f_notimplement
6117 #if defined HAVE_SETREGID
6140 #define p_sys_setregid rb_f_notimplement
6143 #if defined HAVE_SETRESGID
6163 if (setresgid(rgid, egid, sgid) != 0)
rb_sys_fail(0);
6167 #define p_sys_setresgid rb_f_notimplement
6171 #if defined HAVE_ISSETUGID
6195 #define p_sys_issetugid rb_f_notimplement
6218 #if defined(HAVE_SETRESGID) || defined(HAVE_SETREGID) || defined(HAVE_SETRGID) || defined(HAVE_SETGID)
6234 #if defined(HAVE_SETRESGID)
6236 #elif defined HAVE_SETREGID
6238 #elif defined HAVE_SETRGID
6240 #elif defined HAVE_SETGID
6253 #define proc_setgid rb_f_notimplement
6257 #if defined(_SC_NGROUPS_MAX) || defined(NGROUPS_MAX)
6278 static int _maxgroups = -1;
6280 get_sc_ngroups_max(
void)
6282 #ifdef _SC_NGROUPS_MAX
6284 #elif defined(NGROUPS_MAX)
6293 if (_maxgroups < 0) {
6294 _maxgroups = get_sc_ngroups_max();
6305 #ifdef HAVE_GETGROUPS
6348 for (
i = 0;
i < ngroups;
i++)
6356 #define proc_getgroups rb_f_notimplement
6360 #ifdef HAVE_SETGROUPS
6385 if (ngroups > maxgroups())
6390 for (
i = 0;
i < ngroups;
i++) {
6405 #define proc_setgroups rb_f_notimplement
6409 #ifdef HAVE_INITGROUPS
6436 #define proc_initgroups rb_f_notimplement
6439 #if defined(_SC_NGROUPS_MAX) || defined(NGROUPS_MAX)
6456 #define proc_getmaxgroups rb_f_notimplement
6459 #ifdef HAVE_SETGROUPS
6472 int ngroups_max = get_sc_ngroups_max();
6480 if (ngroups_max > 0 && ngroups > ngroups_max)
6481 ngroups = ngroups_max;
6483 _maxgroups = ngroups;
6488 #define proc_setmaxgroups rb_f_notimplement
6491 #if defined(HAVE_DAEMON) || (defined(HAVE_WORKING_FORK) && defined(HAVE_SETSID))
6492 static int rb_daemon(
int nochdir,
int noclose);
6519 n = rb_daemon(nochdir, noclose);
6525 rb_daemon(
int nochdir,
int noclose)
6537 #define fork_daemon() \
6538 switch (rb_fork_ruby(NULL)) { \
6539 case -1: return -1; \
6540 case 0: rb_thread_atfork(); break; \
6541 default: _exit(EXIT_SUCCESS); \
6546 if (
setsid() < 0)
return -1;
6566 #define proc_daemon rb_f_notimplement
6579 static rb_gid_t SAVED_GROUP_ID = -1;
6581 #ifdef BROKEN_SETREGID
6587 if (
setgid(rgid) < 0)
return -1;
6590 if (
setegid(egid) < 0)
return -1;
6619 #if defined(HAVE_SETRESGID)
6621 SAVED_GROUP_ID = gid;
6622 #elif defined HAVE_SETGID
6624 SAVED_GROUP_ID = gid;
6625 #elif defined(HAVE_SETREGID) && !defined(OBSOLETE_SETREGID)
6627 if (SAVED_GROUP_ID == gid) {
6636 SAVED_GROUP_ID = gid;
6642 SAVED_GROUP_ID = gid;
6648 SAVED_GROUP_ID = gid;
6650 #elif defined(HAVE_SETRGID) && defined (HAVE_SETEGID)
6652 if (SAVED_GROUP_ID == gid) {
6667 SAVED_GROUP_ID = gid;
6674 SAVED_GROUP_ID = gid;
6681 #if defined(HAVE_SETRESGID)
6685 SAVED_GROUP_ID = gid;
6686 #elif defined(HAVE_SETREGID) && !defined(OBSOLETE_SETREGID)
6687 if (SAVED_GROUP_ID == gid) {
6692 else if (
getgid() != gid) {
6695 SAVED_GROUP_ID = gid;
6699 SAVED_GROUP_ID = gid;
6705 SAVED_GROUP_ID = gid;
6708 #elif defined(HAVE_SETRGID) && defined(HAVE_SETEGID)
6709 if (SAVED_GROUP_ID == gid) {
6716 SAVED_GROUP_ID = gid;
6720 SAVED_GROUP_ID = gid;
6724 else if (
getgid() == gid) {
6727 SAVED_GROUP_ID = gid;
6733 #elif defined HAVE_44BSD_SETGID
6737 SAVED_GROUP_ID = gid;
6742 #elif defined HAVE_SETEGID
6743 if (
getgid() == gid && SAVED_GROUP_ID == gid) {
6749 #elif defined HAVE_SETGID
6750 if (
getgid() == gid && SAVED_GROUP_ID == gid) {
6783 #if defined(HAVE_SETRESUID) || defined(HAVE_SETREUID) || defined(HAVE_SETEUID) || defined(HAVE_SETUID) || defined(_POSIX_SAVED_IDS)
6787 #if defined(HAVE_SETRESUID)
6789 #elif defined HAVE_SETREUID
6791 #elif defined HAVE_SETEUID
6793 #elif defined HAVE_SETUID
6806 #if defined(HAVE_SETRESUID) || defined(HAVE_SETREUID) || defined(HAVE_SETEUID) || defined(HAVE_SETUID)
6823 #define proc_seteuid_m rb_f_notimplement
6829 #if defined(HAVE_SETRESUID) || (defined(HAVE_SETREUID) && !defined(OBSOLETE_SETREUID))
6835 #if defined(HAVE_SETRESUID) || (defined(HAVE_SETREUID) && !defined(OBSOLETE_SETREUID))
6839 #if defined(HAVE_SETRESUID)
6842 SAVED_USER_ID = euid;
6847 #elif defined(HAVE_SETREUID) && !defined(OBSOLETE_SETREUID)
6852 SAVED_USER_ID = euid;
6854 #elif defined HAVE_SETEUID
6856 #elif defined HAVE_SETUID
6908 #if defined(HAVE_SETRESGID) || defined(HAVE_SETREGID) || defined(HAVE_SETEGID) || defined(HAVE_SETGID) || defined(_POSIX_SAVED_IDS)
6920 #if defined(HAVE_SETRESGID) || defined(HAVE_SETREGID) || defined(HAVE_SETEGID) || defined(HAVE_SETGID)
6926 #if defined(HAVE_SETRESGID) || defined(HAVE_SETREGID) || defined(HAVE_SETEGID) || defined(HAVE_SETGID)
6930 #if defined(HAVE_SETRESGID)
6932 #elif defined HAVE_SETREGID
6934 #elif defined HAVE_SETEGID
6936 #elif defined HAVE_SETGID
6950 #if defined(HAVE_SETRESGID) || defined(HAVE_SETREGID) || defined(HAVE_SETEGID) || defined(HAVE_SETGID)
6951 #define proc_setegid_m proc_setegid
6953 #define proc_setegid_m rb_f_notimplement
6959 #if defined(HAVE_SETRESGID) || (defined(HAVE_SETREGID) && !defined(OBSOLETE_SETREGID))
6965 #if defined(HAVE_SETRESGID) || (defined(HAVE_SETREGID) && !defined(OBSOLETE_SETREGID))
6969 #if defined(HAVE_SETRESGID)
6972 SAVED_GROUP_ID = egid;
6977 #elif defined(HAVE_SETREGID) && !defined(OBSOLETE_SETREGID)
6982 SAVED_GROUP_ID = egid;
6984 #elif defined HAVE_SETEGID
6986 #elif defined HAVE_SETGID
7028 p_uid_exchangeable(
VALUE _)
7030 #if defined(HAVE_SETRESUID)
7032 #elif defined(HAVE_SETREUID) && !defined(OBSOLETE_SETREUID)
7056 #if defined(HAVE_SETRESUID) || (defined(HAVE_SETREUID) && !defined(OBSOLETE_SETREUID))
7063 #if defined(HAVE_SETRESUID) || (defined(HAVE_SETREUID) && !defined(OBSOLETE_SETREUID))
7067 #if defined(HAVE_SETRESUID)
7068 if (setresuid(euid, uid, uid) < 0)
rb_sys_fail(0);
7069 SAVED_USER_ID = uid;
7070 #elif defined(HAVE_SETREUID) && !defined(OBSOLETE_SETREUID)
7072 SAVED_USER_ID = uid;
7090 p_gid_exchangeable(
VALUE _)
7092 #if defined(HAVE_SETRESGID)
7094 #elif defined(HAVE_SETREGID) && !defined(OBSOLETE_SETREGID)
7118 #if defined(HAVE_SETRESGID) || (defined(HAVE_SETREGID) && !defined(OBSOLETE_SETREGID))
7125 #if defined(HAVE_SETRESGID) || (defined(HAVE_SETREGID) && !defined(OBSOLETE_SETREGID))
7129 #if defined(HAVE_SETRESGID)
7130 if (setresgid(egid, gid, gid) < 0)
rb_sys_fail(0);
7131 SAVED_GROUP_ID = gid;
7132 #elif defined(HAVE_SETREGID) && !defined(OBSOLETE_SETREGID)
7134 SAVED_GROUP_ID = gid;
7153 p_uid_have_saved_id(
VALUE _)
7155 #if defined(HAVE_SETRESUID) || defined(HAVE_SETEUID) || defined(_POSIX_SAVED_IDS)
7163 #if defined(HAVE_SETRESUID) || defined(HAVE_SETEUID) || defined(_POSIX_SAVED_IDS)
7168 under_uid_switch = 0;
7169 id = rb_seteuid_core(
id);
7200 under_uid_switch = 1;
7207 else if (euid != SAVED_USER_ID) {
7208 proc_seteuid(SAVED_USER_ID);
7210 under_uid_switch = 1;
7227 under_uid_switch = 0;
7228 return p_uid_exchange(
obj);
7244 p_uid_exchange(
obj);
7246 under_uid_switch = 1;
7268 p_gid_have_saved_id(
VALUE _)
7270 #if defined(HAVE_SETRESGID) || defined(HAVE_SETEGID) || defined(_POSIX_SAVED_IDS)
7277 #if defined(HAVE_SETRESGID) || defined(HAVE_SETEGID) || defined(_POSIX_SAVED_IDS)
7282 under_gid_switch = 0;
7283 id = rb_setegid_core(
id);
7314 under_gid_switch = 1;
7321 else if (egid != SAVED_GROUP_ID) {
7324 under_gid_switch = 1;
7341 under_gid_switch = 0;
7342 return p_gid_exchange(
obj);
7358 p_gid_exchange(
obj);
7360 under_gid_switch = 1;
7370 #if defined(HAVE_TIMES)
7374 #ifdef HAVE__SC_CLK_TCK
7376 #elif defined CLK_TCK
7401 #if defined(RUSAGE_SELF) && defined(RUSAGE_CHILDREN)
7402 struct rusage usage_s, usage_c;
7404 if (getrusage(RUSAGE_SELF, &usage_s) != 0 || getrusage(RUSAGE_CHILDREN, &usage_c) != 0)
7406 utime =
DBL2NUM((
double)usage_s.ru_utime.tv_sec + (
double)usage_s.ru_utime.tv_usec/1e6);
7407 stime =
DBL2NUM((
double)usage_s.ru_stime.tv_sec + (
double)usage_s.ru_stime.tv_usec/1e6);
7408 cutime =
DBL2NUM((
double)usage_c.ru_utime.tv_sec + (
double)usage_c.ru_utime.tv_usec/1e6);
7409 cstime =
DBL2NUM((
double)usage_c.ru_stime.tv_sec + (
double)usage_c.ru_stime.tv_usec/1e6);
7411 const double hertz = (
double)get_clk_tck();
7428 #define rb_proc_times rb_f_notimplement
7431 #ifdef HAVE_LONG_LONG
7433 #define TIMETICK_INT_MIN LLONG_MIN
7434 #define TIMETICK_INT_MAX LLONG_MAX
7435 #define TIMETICK_INT2NUM(v) LL2NUM(v)
7436 #define MUL_OVERFLOW_TIMETICK_P(a, b) MUL_OVERFLOW_LONG_LONG_P(a, b)
7439 #define TIMETICK_INT_MIN LONG_MIN
7440 #define TIMETICK_INT_MAX LONG_MAX
7441 #define TIMETICK_INT2NUM(v) LONG2NUM(v)
7442 #define MUL_OVERFLOW_TIMETICK_P(a, b) MUL_OVERFLOW_LONG_P(a, b)
7481 for (
i = 0;
i < num_numerators;
i++) {
7482 if (numerators[
i] == 1)
7484 for (j = 0; j < num_denominators; j++) {
7485 if (denominators[j] == 1)
7487 reduce_fraction(&numerators[
i], &denominators[j]);
7498 timetick2dblnum(
struct timetick *ttp,
7505 reduce_factors(numerators, num_numerators,
7506 denominators, num_denominators);
7510 for (
i = 0;
i < num_numerators;
i++)
7512 for (
i = 0;
i < num_denominators;
i++)
7513 d /= denominators[
i];
7519 timetick2dblnum_reciprocal(
struct timetick *ttp,
7526 reduce_factors(numerators, num_numerators,
7527 denominators, num_denominators);
7530 for (
i = 0;
i < num_denominators;
i++)
7531 d *= denominators[
i];
7532 for (
i = 0;
i < num_numerators;
i++)
7539 #define NDIV(x,y) (-(-((x)+1)/(y))-1)
7540 #define DIV(n,d) ((n)<0 ? NDIV((n),(d)) : (n)/(d))
7543 timetick2integer(
struct timetick *ttp,
7550 reduce_factors(numerators, num_numerators,
7551 denominators, num_denominators);
7556 for (
i = 0;
i < num_numerators;
i++) {
7562 for (
i = 0;
i < num_denominators;
i++) {
7563 t =
DIV(t, denominators[
i]);
7572 for (
i = 0;
i < num_numerators;
i++) {
7578 for (
i = 0;
i < num_denominators;
i++) {
7585 make_clock_result(
struct timetick *ttp,
7590 if (unit ==
ID2SYM(id_nanosecond)) {
7591 numerators[num_numerators++] = 1000000000;
7592 return timetick2integer(ttp, numerators, num_numerators, denominators, num_denominators);
7594 else if (unit ==
ID2SYM(id_microsecond)) {
7595 numerators[num_numerators++] = 1000000;
7596 return timetick2integer(ttp, numerators, num_numerators, denominators, num_denominators);
7598 else if (unit ==
ID2SYM(id_millisecond)) {
7599 numerators[num_numerators++] = 1000;
7600 return timetick2integer(ttp, numerators, num_numerators, denominators, num_denominators);
7602 else if (unit ==
ID2SYM(id_second)) {
7603 return timetick2integer(ttp, numerators, num_numerators, denominators, num_denominators);
7605 else if (unit ==
ID2SYM(id_float_microsecond)) {
7606 numerators[num_numerators++] = 1000000;
7607 return timetick2dblnum(ttp, numerators, num_numerators, denominators, num_denominators);
7609 else if (unit ==
ID2SYM(id_float_millisecond)) {
7610 numerators[num_numerators++] = 1000;
7611 return timetick2dblnum(ttp, numerators, num_numerators, denominators, num_denominators);
7613 else if (
NIL_P(unit) || unit ==
ID2SYM(id_float_second)) {
7614 return timetick2dblnum(ttp, numerators, num_numerators, denominators, num_denominators);
7621 static const mach_timebase_info_data_t *
7622 get_mach_timebase_info(
void)
7624 static mach_timebase_info_data_t sTimebaseInfo;
7626 if ( sTimebaseInfo.denom == 0 ) {
7627 (
void) mach_timebase_info(&sTimebaseInfo);
7630 return &sTimebaseInfo;
7634 ruby_real_ms_time(
void)
7636 const mach_timebase_info_data_t *info = get_mach_timebase_info();
7638 return (
double)t * info->numer / info->denom / 1e6;
7777 int num_numerators = 0;
7778 int num_denominators = 0;
7787 #ifdef HAVE_GETTIMEOFDAY
7792 #define RUBY_GETTIMEOFDAY_BASED_CLOCK_REALTIME ID2SYM(id_GETTIMEOFDAY_BASED_CLOCK_REALTIME)
7793 if (clk_id == RUBY_GETTIMEOFDAY_BASED_CLOCK_REALTIME) {
7800 denominators[num_denominators++] = 1000000000;
7805 #define RUBY_TIME_BASED_CLOCK_REALTIME ID2SYM(id_TIME_BASED_CLOCK_REALTIME)
7813 denominators[num_denominators++] = 1000000000;
7818 #define RUBY_TIMES_BASED_CLOCK_MONOTONIC \
7819 ID2SYM(id_TIMES_BASED_CLOCK_MONOTONIC)
7820 if (clk_id == RUBY_TIMES_BASED_CLOCK_MONOTONIC) {
7830 denominators[num_denominators++] = get_clk_tck();
7836 #define RUBY_GETRUSAGE_BASED_CLOCK_PROCESS_CPUTIME_ID \
7837 ID2SYM(id_GETRUSAGE_BASED_CLOCK_PROCESS_CPUTIME_ID)
7838 if (clk_id == RUBY_GETRUSAGE_BASED_CLOCK_PROCESS_CPUTIME_ID) {
7839 struct rusage usage;
7841 ret = getrusage(RUSAGE_SELF, &usage);
7844 tt.
giga_count = usage.ru_utime.tv_sec + usage.ru_stime.tv_sec;
7845 usec = (
int32_t)(usage.ru_utime.tv_usec + usage.ru_stime.tv_usec);
7846 if (1000000 <= usec) {
7850 tt.
count = usec * 1000;
7851 denominators[num_denominators++] = 1000000000;
7857 #define RUBY_TIMES_BASED_CLOCK_PROCESS_CPUTIME_ID \
7858 ID2SYM(id_TIMES_BASED_CLOCK_PROCESS_CPUTIME_ID)
7859 if (clk_id == RUBY_TIMES_BASED_CLOCK_PROCESS_CPUTIME_ID) {
7868 if (1000000000 <= tt.
count) {
7869 tt.
count -= 1000000000;
7872 denominators[num_denominators++] = get_clk_tck();
7877 #define RUBY_CLOCK_BASED_CLOCK_PROCESS_CPUTIME_ID \
7878 ID2SYM(id_CLOCK_BASED_CLOCK_PROCESS_CPUTIME_ID)
7894 #define RUBY_MACH_ABSOLUTE_TIME_BASED_CLOCK_MONOTONIC ID2SYM(id_MACH_ABSOLUTE_TIME_BASED_CLOCK_MONOTONIC)
7895 if (clk_id == RUBY_MACH_ABSOLUTE_TIME_BASED_CLOCK_MONOTONIC) {
7896 const mach_timebase_info_data_t *info = get_mach_timebase_info();
7900 numerators[num_numerators++] = info->numer;
7901 denominators[num_denominators++] = info->denom;
7902 denominators[num_denominators++] = 1000000000;
7908 #if defined(HAVE_CLOCK_GETTIME)
7917 denominators[num_denominators++] = 1000000000;
7925 return make_clock_result(&tt, numerators, num_numerators, denominators, num_denominators, unit);
7972 int num_numerators = 0;
7973 int num_denominators = 0;
7979 #ifdef RUBY_GETTIMEOFDAY_BASED_CLOCK_REALTIME
7980 if (clk_id == RUBY_GETTIMEOFDAY_BASED_CLOCK_REALTIME) {
7983 denominators[num_denominators++] = 1000000000;
7988 #ifdef RUBY_TIME_BASED_CLOCK_REALTIME
7992 denominators[num_denominators++] = 1000000000;
7997 #ifdef RUBY_TIMES_BASED_CLOCK_MONOTONIC
7998 if (clk_id == RUBY_TIMES_BASED_CLOCK_MONOTONIC) {
8001 denominators[num_denominators++] = get_clk_tck();
8006 #ifdef RUBY_GETRUSAGE_BASED_CLOCK_PROCESS_CPUTIME_ID
8007 if (clk_id == RUBY_GETRUSAGE_BASED_CLOCK_PROCESS_CPUTIME_ID) {
8010 denominators[num_denominators++] = 1000000000;
8015 #ifdef RUBY_TIMES_BASED_CLOCK_PROCESS_CPUTIME_ID
8016 if (clk_id == RUBY_TIMES_BASED_CLOCK_PROCESS_CPUTIME_ID) {
8019 denominators[num_denominators++] = get_clk_tck();
8024 #ifdef RUBY_CLOCK_BASED_CLOCK_PROCESS_CPUTIME_ID
8033 #ifdef RUBY_MACH_ABSOLUTE_TIME_BASED_CLOCK_MONOTONIC
8034 if (clk_id == RUBY_MACH_ABSOLUTE_TIME_BASED_CLOCK_MONOTONIC) {
8035 const mach_timebase_info_data_t *info = get_mach_timebase_info();
8038 numerators[num_numerators++] = info->numer;
8039 denominators[num_denominators++] = info->denom;
8040 denominators[num_denominators++] = 1000000000;
8046 #if defined(HAVE_CLOCK_GETRES)
8054 denominators[num_denominators++] = 1000000000;
8062 if (unit ==
ID2SYM(id_hertz)) {
8063 return timetick2dblnum_reciprocal(&tt, numerators, num_numerators, denominators, num_denominators);
8066 return make_clock_result(&tt, numerators, num_numerators, denominators, num_denominators, unit);
8071 get_CHILD_STATUS(
ID _x,
VALUE *_y)
8077 get_PROCESS_ID(
ID _x,
VALUE *_y)
8125 static VALUE rb_mProcUID;
8126 static VALUE rb_mProcGID;
8127 static VALUE rb_mProcID_Syscall;
8139 #define rb_intern(str) rb_intern_const(str)
8225 #ifdef HAVE_GETPRIORITY
8236 #if defined(RLIM2NUM) && defined(RLIM_INFINITY)
8239 #ifdef RLIM_SAVED_MAX
8241 VALUE v = RLIM_INFINITY == RLIM_SAVED_MAX ? inf :
RLIM2NUM(RLIM_SAVED_MAX);
8248 #ifdef RLIM_SAVED_CUR
8250 VALUE v = RLIM_INFINITY == RLIM_SAVED_CUR ? inf :
RLIM2NUM(RLIM_SAVED_CUR);
8291 #ifdef RLIMIT_MEMLOCK
8298 #ifdef RLIMIT_MSGQUEUE
8313 #ifdef RLIMIT_NOFILE
8336 #ifdef RLIMIT_RTPRIO
8343 #ifdef RLIMIT_RTTIME
8351 #ifdef RLIMIT_SBSIZE
8356 #ifdef RLIMIT_SIGPENDING
8391 #ifdef CLOCK_REALTIME
8394 #elif defined(RUBY_GETTIMEOFDAY_BASED_CLOCK_REALTIME)
8398 #ifdef CLOCK_MONOTONIC
8401 #elif defined(RUBY_MACH_ABSOLUTE_TIME_BASED_CLOCK_MONOTONIC)
8405 #ifdef CLOCK_PROCESS_CPUTIME_ID
8408 #elif defined(RUBY_GETRUSAGE_BASED_CLOCK_PROCESS_CPUTIME_ID)
8412 #ifdef CLOCK_THREAD_CPUTIME_ID
8416 #ifdef CLOCK_VIRTUAL
8424 #ifdef CLOCK_REALTIME_FAST
8428 #ifdef CLOCK_REALTIME_PRECISE
8432 #ifdef CLOCK_REALTIME_COARSE
8436 #ifdef CLOCK_REALTIME_ALARM
8440 #ifdef CLOCK_MONOTONIC_FAST
8444 #ifdef CLOCK_MONOTONIC_PRECISE
8448 #ifdef CLOCK_MONOTONIC_RAW
8452 #ifdef CLOCK_MONOTONIC_RAW_APPROX
8456 #ifdef CLOCK_MONOTONIC_COARSE
8460 #ifdef CLOCK_BOOTTIME
8464 #ifdef CLOCK_BOOTTIME_ALARM
8472 #ifdef CLOCK_UPTIME_FAST
8476 #ifdef CLOCK_UPTIME_PRECISE
8480 #ifdef CLOCK_UPTIME_RAW
8484 #ifdef CLOCK_UPTIME_RAW_APPROX
8499 #if defined(HAVE_TIMES) || defined(_WIN32)
8531 #ifdef p_uid_from_name
8534 #ifdef p_gid_from_name
8577 id_new_pgroup =
rb_intern(
"new_pgroup");
8579 id_unsetenv_others =
rb_intern(
"unsetenv_others");
8582 id_close_others =
rb_intern(
"close_others");
8584 id_nanosecond =
rb_intern(
"nanosecond");
8585 id_microsecond =
rb_intern(
"microsecond");
8586 id_millisecond =
rb_intern(
"millisecond");
8588 id_float_microsecond =
rb_intern(
"float_microsecond");
8589 id_float_millisecond =
rb_intern(
"float_millisecond");
8590 id_float_second =
rb_intern(
"float_second");
8591 id_GETTIMEOFDAY_BASED_CLOCK_REALTIME =
rb_intern(
"GETTIMEOFDAY_BASED_CLOCK_REALTIME");
8592 id_TIME_BASED_CLOCK_REALTIME =
rb_intern(
"TIME_BASED_CLOCK_REALTIME");
8594 id_TIMES_BASED_CLOCK_MONOTONIC =
rb_intern(
"TIMES_BASED_CLOCK_MONOTONIC");
8595 id_TIMES_BASED_CLOCK_PROCESS_CPUTIME_ID =
rb_intern(
"TIMES_BASED_CLOCK_PROCESS_CPUTIME_ID");
8598 id_GETRUSAGE_BASED_CLOCK_PROCESS_CPUTIME_ID =
rb_intern(
"GETRUSAGE_BASED_CLOCK_PROCESS_CPUTIME_ID");
8600 id_CLOCK_BASED_CLOCK_PROCESS_CPUTIME_ID =
rb_intern(
"CLOCK_BASED_CLOCK_PROCESS_CPUTIME_ID");
8602 id_MACH_ABSOLUTE_TIME_BASED_CLOCK_MONOTONIC =
rb_intern(
"MACH_ABSOLUTE_TIME_BASED_CLOCK_MONOTONIC");