14#include "ruby/internal/config.h"
42# define EXIT_SUCCESS 0
46# define EXIT_FAILURE 1
53#ifdef HAVE_SYS_RESOURCE_H
54# include <sys/resource.h>
61#ifdef HAVE_SYS_PARAM_H
62# include <sys/param.h>
66# define MAXPATHLEN 1024
75#ifdef HAVE_SYS_TIMES_H
76# include <sys/times.h>
86int initgroups(
const char *, rb_gid_t);
95# include <mach/mach_time.h>
101#include "internal/bits.h"
102#include "internal/dir.h"
103#include "internal/error.h"
104#include "internal/eval.h"
105#include "internal/hash.h"
106#include "internal/numeric.h"
107#include "internal/object.h"
108#include "internal/process.h"
109#include "internal/thread.h"
110#include "internal/variable.h"
111#include "internal/warnings.h"
123#define open rb_w32_uopen
126#if defined(HAVE_TIMES) || defined(_WIN32)
133static VALUE rb_cProcessTms;
137#define WIFEXITED(w) (((w) & 0xff) == 0)
140#define WIFSIGNALED(w) (((w) & 0x7f) > 0 && (((w) & 0x7f) < 0x7f))
143#define WIFSTOPPED(w) (((w) & 0xff) == 0x7f)
146#define WEXITSTATUS(w) (((w) >> 8) & 0xff)
149#define WTERMSIG(w) ((w) & 0x7f)
152#define WSTOPSIG WEXITSTATUS
155#if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__bsdi__)
156#define HAVE_44BSD_SETUID 1
157#define HAVE_44BSD_SETGID 1
165#ifdef BROKEN_SETREUID
166#define setreuid ruby_setreuid
167int setreuid(rb_uid_t ruid, rb_uid_t euid);
169#ifdef BROKEN_SETREGID
170#define setregid ruby_setregid
171int setregid(rb_gid_t rgid, rb_gid_t egid);
174#if defined(HAVE_44BSD_SETUID) || defined(__APPLE__)
175#if !defined(USE_SETREUID) && !defined(BROKEN_SETREUID)
176#define OBSOLETE_SETREUID 1
178#if !defined(USE_SETREGID) && !defined(BROKEN_SETREGID)
179#define OBSOLETE_SETREGID 1
183static void check_uid_switch(
void);
184static void check_gid_switch(
void);
185static int exec_async_signal_safe(
const struct rb_execarg *,
char *,
size_t);
187VALUE rb_envtbl(
void);
188VALUE rb_env_to_hash(
void);
191#define p_uid_from_name p_uid_from_name
192#define p_gid_from_name p_gid_from_name
195#if defined(HAVE_UNISTD_H)
196# if defined(HAVE_GETLOGIN_R)
197# define USE_GETLOGIN_R 1
198# define GETLOGIN_R_SIZE_DEFAULT 0x100
199# define GETLOGIN_R_SIZE_LIMIT 0x1000
200# if defined(_SC_LOGIN_NAME_MAX)
201# define GETLOGIN_R_SIZE_INIT sysconf(_SC_LOGIN_NAME_MAX)
203# define GETLOGIN_R_SIZE_INIT GETLOGIN_R_SIZE_DEFAULT
205# elif defined(HAVE_GETLOGIN)
206# define USE_GETLOGIN 1
210#if defined(HAVE_PWD_H)
211# if defined(HAVE_GETPWUID_R)
212# define USE_GETPWUID_R 1
213# elif defined(HAVE_GETPWUID)
214# define USE_GETPWUID 1
216# if defined(HAVE_GETPWNAM_R)
217# define USE_GETPWNAM_R 1
218# elif defined(HAVE_GETPWNAM)
219# define USE_GETPWNAM 1
221# if defined(HAVE_GETPWNAM_R) || defined(HAVE_GETPWUID_R)
222# define GETPW_R_SIZE_DEFAULT 0x1000
223# define GETPW_R_SIZE_LIMIT 0x10000
224# if defined(_SC_GETPW_R_SIZE_MAX)
225# define GETPW_R_SIZE_INIT sysconf(_SC_GETPW_R_SIZE_MAX)
227# define GETPW_R_SIZE_INIT GETPW_R_SIZE_DEFAULT
230# ifdef USE_GETPWNAM_R
231# define PREPARE_GETPWNAM \
233# define FINISH_GETPWNAM \
234 (getpw_buf ? (void)rb_str_resize(getpw_buf, 0) : (void)0)
235# define OBJ2UID1(id) obj2uid((id), &getpw_buf)
236# define OBJ2UID(id) obj2uid0(id)
237static rb_uid_t obj2uid(
VALUE id,
VALUE *getpw_buf);
238static inline rb_uid_t
248# define PREPARE_GETPWNAM
249# define FINISH_GETPWNAM
250# define OBJ2UID1(id) obj2uid((id))
251# define OBJ2UID(id) obj2uid((id))
252static rb_uid_t obj2uid(
VALUE id);
255# define PREPARE_GETPWNAM
256# define FINISH_GETPWNAM
257# define OBJ2UID1(id) NUM2UIDT(id)
258# define OBJ2UID(id) NUM2UIDT(id)
259# ifdef p_uid_from_name
260# undef p_uid_from_name
261# define p_uid_from_name rb_f_notimplement
265#if defined(HAVE_GRP_H)
266# if defined(HAVE_GETGRNAM_R) && defined(_SC_GETGR_R_SIZE_MAX)
267# define USE_GETGRNAM_R
268# define GETGR_R_SIZE_INIT sysconf(_SC_GETGR_R_SIZE_MAX)
269# define GETGR_R_SIZE_DEFAULT 0x1000
270# define GETGR_R_SIZE_LIMIT 0x10000
272# ifdef USE_GETGRNAM_R
273# define PREPARE_GETGRNAM \
275# define FINISH_GETGRNAM \
276 (getgr_buf ? (void)rb_str_resize(getgr_buf, 0) : (void)0)
277# define OBJ2GID1(id) obj2gid((id), &getgr_buf)
278# define OBJ2GID(id) obj2gid0(id)
279static rb_gid_t obj2gid(
VALUE id,
VALUE *getgr_buf);
280static inline rb_gid_t
289static rb_gid_t obj2gid(
VALUE id,
VALUE *getgr_buf);
291# define PREPARE_GETGRNAM
292# define FINISH_GETGRNAM
293# define OBJ2GID1(id) obj2gid((id))
294# define OBJ2GID(id) obj2gid((id))
295static rb_gid_t obj2gid(
VALUE id);
298# define PREPARE_GETGRNAM
299# define FINISH_GETGRNAM
300# define OBJ2GID1(id) NUM2GIDT(id)
301# define OBJ2GID(id) NUM2GIDT(id)
302# ifdef p_gid_from_name
303# undef p_gid_from_name
304# define p_gid_from_name rb_f_notimplement
308#if SIZEOF_CLOCK_T == SIZEOF_INT
309typedef unsigned int unsigned_clock_t;
310#elif SIZEOF_CLOCK_T == SIZEOF_LONG
311typedef unsigned long unsigned_clock_t;
312#elif defined(HAVE_LONG_LONG) && SIZEOF_CLOCK_T == SIZEOF_LONG_LONG
313typedef unsigned LONG_LONG unsigned_clock_t;
316typedef void (*sig_t) (int);
319#define id_exception idException
320static ID id_in, id_out, id_err, id_pid, id_uid, id_gid;
321static ID id_close, id_child;
326static ID id_new_pgroup;
328static ID id_unsetenv_others, id_chdir, id_umask, id_close_others;
329static ID id_nanosecond, id_microsecond, id_millisecond, id_second;
330static ID id_float_microsecond, id_float_millisecond, id_float_second;
331static ID id_GETTIMEOFDAY_BASED_CLOCK_REALTIME, id_TIME_BASED_CLOCK_REALTIME;
333static ID id_CLOCK_REALTIME;
334# define RUBY_CLOCK_REALTIME ID2SYM(id_CLOCK_REALTIME)
336#ifdef CLOCK_MONOTONIC
337static ID id_CLOCK_MONOTONIC;
338# define RUBY_CLOCK_MONOTONIC ID2SYM(id_CLOCK_MONOTONIC)
340#ifdef CLOCK_PROCESS_CPUTIME_ID
341static ID id_CLOCK_PROCESS_CPUTIME_ID;
342# define RUBY_CLOCK_PROCESS_CPUTIME_ID ID2SYM(id_CLOCK_PROCESS_CPUTIME_ID)
344#ifdef CLOCK_THREAD_CPUTIME_ID
345static ID id_CLOCK_THREAD_CPUTIME_ID;
346# define RUBY_CLOCK_THREAD_CPUTIME_ID ID2SYM(id_CLOCK_THREAD_CPUTIME_ID)
349static ID id_TIMES_BASED_CLOCK_MONOTONIC;
350static ID id_TIMES_BASED_CLOCK_PROCESS_CPUTIME_ID;
353static ID id_GETRUSAGE_BASED_CLOCK_PROCESS_CPUTIME_ID;
355static ID id_CLOCK_BASED_CLOCK_PROCESS_CPUTIME_ID;
357static ID id_MACH_ABSOLUTE_TIME_BASED_CLOCK_MONOTONIC;
358# define RUBY_MACH_ABSOLUTE_TIME_BASED_CLOCK_MONOTONIC ID2SYM(id_MACH_ABSOLUTE_TIME_BASED_CLOCK_MONOTONIC)
363#if defined(__sun) && !defined(_XPG7)
364#define execv(path, argv) (rb_async_bug_errno("unreachable: async-signal-unsafe execv() is called", 0))
365#define execl(path, arg0, arg1, arg2, term) do { extern char **environ; execle((path), (arg0), (arg1), (arg2), (term), (environ)); } while (0)
366#define ALWAYS_NEED_ENVP 1
368#define ALWAYS_NEED_ENVP 0
372assert_close_on_exec(
int fd)
375#if defined(HAVE_FCNTL) && defined(F_GETFD) && defined(FD_CLOEXEC)
376 int flags = fcntl(fd, F_GETFD);
378 static const char m[] =
"reserved FD closed unexpectedly?\n";
379 (void)!write(2, m,
sizeof(m) - 1);
382 if (flags & FD_CLOEXEC)
return;
383 rb_bug(
"reserved FD did not have close-on-exec set");
385 rb_bug(
"reserved FD without close-on-exec support");
391close_unless_reserved(
int fd)
394 assert_close_on_exec(fd);
401#if defined(DEBUG_REDIRECT)
404ttyprintf(
const char *fmt, ...)
410 tty = fopen(
"con",
"w");
412 tty = fopen(
"/dev/tty",
"w");
418 vfprintf(tty, fmt, ap);
425redirect_dup(
int oldfd)
429 ttyprintf(
"dup(%d) => %d\n", oldfd, ret);
434redirect_dup2(
int oldfd,
int newfd)
437 ret = dup2(oldfd, newfd);
438 ttyprintf(
"dup2(%d, %d) => %d\n", oldfd, newfd, ret);
443redirect_cloexec_dup(
int oldfd)
447 ttyprintf(
"cloexec_dup(%d) => %d\n", oldfd, ret);
452redirect_cloexec_dup2(
int oldfd,
int newfd)
456 ttyprintf(
"cloexec_dup2(%d, %d) => %d\n", oldfd, newfd, ret);
461redirect_close(
int fd)
464 ret = close_unless_reserved(fd);
465 ttyprintf(
"close(%d) => %d\n", fd, ret);
470parent_redirect_open(
const char *pathname,
int flags, mode_t perm)
474 ttyprintf(
"parent_open(\"%s\", 0x%x, 0%o) => %d\n", pathname, flags, perm, ret);
479parent_redirect_close(
int fd)
482 ret = close_unless_reserved(fd);
483 ttyprintf(
"parent_close(%d) => %d\n", fd, ret);
488#define redirect_dup(oldfd) dup(oldfd)
489#define redirect_dup2(oldfd, newfd) dup2((oldfd), (newfd))
490#define redirect_cloexec_dup(oldfd) rb_cloexec_dup(oldfd)
491#define redirect_cloexec_dup2(oldfd, newfd) rb_cloexec_dup2((oldfd), (newfd))
492#define redirect_close(fd) close_unless_reserved(fd)
493#define parent_redirect_open(pathname, flags, perm) rb_cloexec_open((pathname), (flags), (perm))
494#define parent_redirect_close(fd) close_unless_reserved(fd)
596static VALUE rb_cProcessStatus;
610 .flags = RUBY_TYPED_FREE_IMMEDIATELY,
614rb_process_status_allocate(
VALUE klass)
624 return GET_THREAD()->last_status;
643proc_s_last_status(
VALUE mod)
649rb_process_status_new(rb_pid_t pid,
int status,
int error)
651 VALUE last_status = rb_process_status_allocate(rb_cProcessStatus);
655 data->status = status;
663process_status_dump(
VALUE status)
675process_status_load(
VALUE real_obj,
VALUE load_obj)
688 GET_THREAD()->last_status = rb_process_status_new(pid, status, 0);
692rb_last_status_clear(
void)
694 GET_THREAD()->last_status =
Qnil;
726 int status = pst_status(self);
730#define PST2INT(st) pst_status(st)
746 rb_pid_t pid = pst_pid(self);
750static VALUE pst_message_status(
VALUE str,
int status);
753pst_message(
VALUE str, rb_pid_t pid,
int status)
756 pst_message_status(str, status);
760pst_message_status(
VALUE str,
int status)
762 if (WIFSTOPPED(status)) {
763 int stopsig = WSTOPSIG(status);
766 rb_str_catf(str,
" stopped SIG%s (signal %d)", signame, stopsig);
772 if (WIFSIGNALED(status)) {
773 int termsig = WTERMSIG(status);
776 rb_str_catf(str,
" SIG%s (signal %d)", signame, termsig);
782 if (WIFEXITED(status)) {
786 if (WCOREDUMP(status)) {
813 status = PST2INT(st);
816 pst_message(str, pid, status);
843 status = PST2INT(st);
846 pst_message(str, pid, status);
863 if (st1 == st2)
return Qtrue;
864 return rb_equal(pst_to_i(st1), st2);
883 int status = PST2INT(st1) &
NUM2INT(st2);
904 int status = PST2INT(st1) >>
NUM2INT(st2);
920pst_wifstopped(
VALUE st)
922 int status = PST2INT(st);
924 return RBOOL(WIFSTOPPED(status));
937pst_wstopsig(
VALUE st)
939 int status = PST2INT(st);
941 if (WIFSTOPPED(status))
942 return INT2NUM(WSTOPSIG(status));
956pst_wifsignaled(
VALUE st)
958 int status = PST2INT(st);
960 return RBOOL(WIFSIGNALED(status));
974pst_wtermsig(
VALUE st)
976 int status = PST2INT(st);
978 if (WIFSIGNALED(status))
979 return INT2NUM(WTERMSIG(status));
994pst_wifexited(
VALUE st)
996 int status = PST2INT(st);
998 return RBOOL(WIFEXITED(status));
1021pst_wexitstatus(
VALUE st)
1023 int status = PST2INT(st);
1025 if (WIFEXITED(status))
1026 return INT2NUM(WEXITSTATUS(status));
1040pst_success_p(
VALUE st)
1042 int status = PST2INT(st);
1044 if (!WIFEXITED(status))
1046 return RBOOL(WEXITSTATUS(status) == EXIT_SUCCESS);
1059pst_wcoredump(
VALUE st)
1062 int status = PST2INT(st);
1064 return RBOOL(WCOREDUMP(status));
1071do_waitpid(rb_pid_t pid,
int *st,
int flags)
1073#if defined HAVE_WAITPID
1074 return waitpid(pid, st, flags);
1075#elif defined HAVE_WAIT4
1076 return wait4(pid, st, flags, NULL);
1078# error waitpid or wait4 is required.
1082#define WAITPID_LOCK_ONLY ((struct waitpid_state *)-1)
1096void rb_sigwait_sleep(
const rb_thread_t *,
int fd,
const rb_hrtime_t *);
1097void rb_sigwait_fd_put(
const rb_thread_t *,
int fd);
1098void rb_thread_sleep_interruptible(
void);
1105bool mjit_waitpid_finished =
false;
1106int mjit_waitpid_status = 0;
1113 rb_threadptr_interrupt(rb_ec_thread_ptr(w->ec));
1117 else if (w == &mjit_waitpid_state && w->ret) {
1118 mjit_waitpid_finished =
true;
1119 mjit_waitpid_status = w->status;
1134 ccan_list_for_each(waiting_list, waitpid, wnode) {
1147sigwait_fd_migrate_sleeper(
rb_vm_t *vm)
1151 ccan_list_for_each(&vm->waiting_pids, w, wnode) {
1152 if (waitpid_signal(w))
return;
1154 ccan_list_for_each(&vm->waiting_grps, w, wnode) {
1155 if (waitpid_signal(w))
return;
1160rb_sigwait_fd_migrate(
rb_vm_t *vm)
1163 sigwait_fd_migrate_sleeper(vm);
1168extern volatile unsigned int ruby_nocldwait;
1175 ccan_list_for_each_safe(head, w, next, wnode) {
1176 rb_pid_t ret = do_waitpid(w->pid, &w->status, w->options | WNOHANG);
1179 if (ret == -1) w->errnum = errno;
1182 ccan_list_del_init(&w->wnode);
1187# define ruby_nocldwait 0
1195 waitpid_each(&vm->waiting_pids);
1196 if (ccan_list_empty(&vm->waiting_pids)) {
1197 waitpid_each(&vm->waiting_grps);
1200 if (ccan_list_empty(&vm->waiting_pids) && ccan_list_empty(&vm->waiting_grps)) {
1201 while (ruby_nocldwait && do_waitpid(-1, 0, WNOHANG) > 0)
1209waitpid_state_init(
struct waitpid_state *w, rb_pid_t pid,
int options)
1213 w->options = options;
1223mjit_add_waiting_pid(
rb_vm_t *vm, rb_pid_t pid)
1225 waitpid_state_init(&mjit_waitpid_state, pid, 0);
1226 mjit_waitpid_state.ec = 0;
1227 ccan_list_add(&vm->waiting_pids, &mjit_waitpid_state.wnode);
1232waitpid_sleep(
VALUE x)
1237 rb_thread_sleep_interruptible();
1244waitpid_cleanup(
VALUE x)
1252 if (TRUE || w->ret == 0) {
1253 rb_vm_t *vm = rb_ec_vm_ptr(w->ec);
1256 ccan_list_del(&w->wnode);
1266 rb_vm_t *vm = rb_ec_vm_ptr(w->ec);
1267 int need_sleep = FALSE;
1276 if (w->pid > 0 || ccan_list_empty(&vm->waiting_pids)) {
1277 w->ret = do_waitpid(w->pid, &w->status, w->options | WNOHANG);
1281 if (w->ret == -1) w->errnum = errno;
1283 else if (w->options & WNOHANG) {
1292 ccan_list_add(w->pid > 0 ? &vm->waiting_pids : &vm->waiting_grps, &w->wnode);
1303waitpid_blocking_no_SIGCHLD(
void *x)
1307 w->ret = do_waitpid(w->pid, &w->status, w->options);
1315 if (w->options & WNOHANG) {
1316 w->ret = do_waitpid(w->pid, &w->status, w->options);
1322 }
while (w->ret < 0 && errno == EINTR && (RUBY_VM_CHECK_INTS(w->ec),1));
1329rb_process_status_wait(rb_pid_t pid,
int flags)
1332 if (!(flags & WNOHANG)) {
1335 if (!UNDEF_P(result))
return result;
1343 if (WAITPID_USE_SIGCHLD) {
1405rb_process_status_waitv(
int argc,
VALUE *argv,
VALUE _)
1407 rb_check_arity(argc, 0, 2);
1420 return rb_process_status_wait(pid, flags);
1426 VALUE status = rb_process_status_wait(pid, flags);
1427 if (
NIL_P(status))
return 0;
1432 if (st) *st = data->status;
1435 errno = data->error;
1438 GET_THREAD()->last_status = status;
1445proc_wait(
int argc,
VALUE *argv)
1451 if (rb_check_arity(argc, 0, 2) == 0) {
1457 if (argc == 2 && !
NIL_P(vflags = argv[1])) {
1462 if ((pid =
rb_waitpid(pid, &status, flags)) < 0)
1466 rb_last_status_clear();
1534 return proc_wait(c, v);
1557 VALUE pid = proc_wait(argc, argv);
1590 result = rb_ary_new();
1591 rb_last_status_clear();
1606static VALUE rb_cWaiter;
1609detach_process_pid(
VALUE thread)
1615detach_process_watcher(
void *arg)
1617 rb_pid_t cpid, pid = (rb_pid_t)(
VALUE)arg;
1620 while ((cpid =
rb_waitpid(pid, &status, 0)) == 0) {
1631 RBASIC_SET_CLASS(watcher, rb_cWaiter);
1690before_exec_async_signal_safe(
void)
1695before_exec_non_async_signal_safe(
void)
1706 rb_thread_stop_timer_thread();
1709#define WRITE_CONST(fd, str) (void)(write((fd),(str),sizeof(str)-1)<0)
1711int rb_w32_set_nonblock2(
int fd,
int nonblock);
1718 return rb_w32_set_nonblock2(fd, 0);
1719#elif defined(F_GETFL) && defined(F_SETFL)
1720 int fl = fcntl(fd, F_GETFL);
1723 if (fl == -1)
return fl;
1724 if (fl & O_NONBLOCK) {
1726 return fcntl(fd, F_SETFL, fl);
1733stdfd_clear_nonblock(
void)
1737 for (fd = 0; fd < 3; fd++) {
1738 (void)set_blocking(fd);
1745 before_exec_non_async_signal_safe();
1746 before_exec_async_signal_safe();
1751after_exec_async_signal_safe(
void)
1756after_exec_non_async_signal_safe(
void)
1758 rb_thread_reset_timer_thread();
1759 rb_thread_start_timer_thread();
1765 after_exec_async_signal_safe();
1766 after_exec_non_async_signal_safe();
1769#if defined HAVE_WORKING_FORK || defined HAVE_DAEMON
1771before_fork_ruby(
void)
1777after_fork_ruby(
void)
1779 rb_threadptr_pending_interrupt_clear(GET_THREAD());
1784#if defined(HAVE_WORKING_FORK)
1787#define try_with_sh(err, prog, argv, envp) ((err == ENOEXEC) ? exec_with_sh((prog), (argv), (envp)) : (void)0)
1789exec_with_sh(
const char *prog,
char **argv,
char **envp)
1791 *argv = (
char *)prog;
1792 *--argv = (
char *)
"sh";
1794 execve(
"/bin/sh", argv, envp);
1796 execv(
"/bin/sh", argv);
1800#define try_with_sh(err, prog, argv, envp) (void)0
1805proc_exec_cmd(
const char *prog,
VALUE argv_str,
VALUE envp_str)
1813 argv = ARGVSTR2ARGV(argv_str);
1820 rb_w32_uaspawn(P_OVERLAY, prog, argv);
1823 envp = envp_str ? RB_IMEMO_TMPBUF_PTR(envp_str) : NULL;
1825 execve(prog, argv, envp);
1829 try_with_sh(err, prog, argv, envp);
1836proc_exec_sh(
const char *str,
VALUE envp_str)
1841 while (*s ==
' ' || *s ==
'\t' || *s ==
'\n')
1849 rb_w32_uspawn(P_OVERLAY, (
char *)str, 0);
1850#elif defined(__CYGWIN32__)
1852 char fbuf[MAXPATHLEN];
1853 char *shell = dln_find_exe_r(
"sh", 0, fbuf,
sizeof(fbuf));
1856 execl(shell,
"sh",
"-c", str, (
char *) NULL);
1858 status = system(str);
1864 execle(
"/bin/sh",
"sh",
"-c", str, (
char *)NULL, RB_IMEMO_TMPBUF_PTR(envp_str));
1866 execl(
"/bin/sh",
"sh",
"-c", str, (
char *)NULL);
1876 ret = proc_exec_sh(str,
Qfalse);
1883mark_exec_arg(
void *ptr)
1886 if (eargp->use_shell)
1887 rb_gc_mark(eargp->invoke.sh.shell_script);
1889 rb_gc_mark(eargp->invoke.cmd.command_name);
1890 rb_gc_mark(eargp->invoke.cmd.command_abspath);
1891 rb_gc_mark(eargp->invoke.cmd.argv_str);
1892 rb_gc_mark(eargp->invoke.cmd.argv_buf);
1894 rb_gc_mark(eargp->redirect_fds);
1895 rb_gc_mark(eargp->envp_str);
1896 rb_gc_mark(eargp->envp_buf);
1897 rb_gc_mark(eargp->dup2_tmpbuf);
1898 rb_gc_mark(eargp->rlimit_limits);
1899 rb_gc_mark(eargp->fd_dup2);
1900 rb_gc_mark(eargp->fd_close);
1901 rb_gc_mark(eargp->fd_open);
1902 rb_gc_mark(eargp->fd_dup2_child);
1903 rb_gc_mark(eargp->env_modification);
1904 rb_gc_mark(eargp->path_env);
1905 rb_gc_mark(eargp->chdir_dir);
1909memsize_exec_arg(
const void *ptr)
1917 0, 0, RUBY_TYPED_FREE_IMMEDIATELY
1921# define DEFAULT_PROCESS_ENCODING rb_utf8_encoding()
1923#ifdef DEFAULT_PROCESS_ENCODING
1924# define EXPORT_STR(str) rb_str_export_to_enc((str), DEFAULT_PROCESS_ENCODING)
1925# define EXPORT_DUP(str) export_dup(str)
1927export_dup(
VALUE str)
1929 VALUE newstr = EXPORT_STR(str);
1934# define EXPORT_STR(str) (str)
1935# define EXPORT_DUP(str) rb_str_dup(str)
1938#if !defined(HAVE_WORKING_FORK) && defined(HAVE_SPAWNV)
1939# define USE_SPAWNV 1
1941# define USE_SPAWNV 0
1944# define P_NOWAIT _P_NOWAIT
1949#define proc_spawn_cmd_internal(argv, prog) rb_w32_uaspawn(P_NOWAIT, (prog), (argv))
1952proc_spawn_cmd_internal(
char **argv,
char *prog)
1954 char fbuf[MAXPATHLEN];
1959 prog = dln_find_exe_r(prog, 0, fbuf,
sizeof(fbuf));
1964 status = spawnv(P_NOWAIT, prog, (
const char **)argv);
1965 if (status == -1 && errno == ENOEXEC) {
1966 *argv = (
char *)prog;
1967 *--argv = (
char *)
"sh";
1968 status = spawnv(P_NOWAIT,
"/bin/sh", (
const char **)argv);
1970 if (status == -1) errno = ENOEXEC;
1984 if (eargp->new_pgroup_given && eargp->new_pgroup_flag) {
1985 flags = CREATE_NEW_PROCESS_GROUP;
1987 pid = rb_w32_uaspawn_flags(P_NOWAIT, prog ? RSTRING_PTR(prog) : 0, argv, flags);
1989 pid = proc_spawn_cmd_internal(argv, prog ? RSTRING_PTR(prog) : 0);
1996#define proc_spawn_sh(str) rb_w32_uspawn(P_NOWAIT, (str), 0)
1999proc_spawn_sh(
char *str)
2001 char fbuf[MAXPATHLEN];
2004 char *shell = dln_find_exe_r(
"sh", 0, fbuf,
sizeof(fbuf));
2006 status = spawnl(P_NOWAIT, (shell ? shell :
"/bin/sh"),
"sh",
"-c", str, (char*)NULL);
2016 RBASIC_CLEAR_CLASS(obj);
2021check_exec_redirect_fd(
VALUE v,
int iskey)
2032 else if (
id == id_out)
2034 else if (
id == id_err)
2053 else if (fd >= 3 && iskey) {
2068 ary = hide_obj(rb_ary_new());
2070 if (!RB_TYPE_P(key,
T_ARRAY)) {
2071 VALUE fd = check_exec_redirect_fd(key, !
NIL_P(param));
2072 rb_ary_push(ary, hide_obj(rb_assoc_new(fd, param)));
2078 VALUE fd = check_exec_redirect_fd(v, !
NIL_P(param));
2079 rb_ary_push(ary, hide_obj(rb_assoc_new(fd, param)));
2089 VALUE path, flags, perm;
2093 switch (
TYPE(val)) {
2096 if (
id == id_close) {
2098 eargp->fd_close = check_exec_redirect1(eargp->fd_close, key, param);
2100 else if (
id == id_in) {
2102 eargp->fd_dup2 = check_exec_redirect1(eargp->fd_dup2, key, param);
2104 else if (
id == id_out) {
2106 eargp->fd_dup2 = check_exec_redirect1(eargp->fd_dup2, key, param);
2108 else if (
id == id_err) {
2110 eargp->fd_dup2 = check_exec_redirect1(eargp->fd_dup2, key, param);
2120 val = check_exec_redirect_fd(val, 0);
2124 eargp->fd_dup2 = check_exec_redirect1(eargp->fd_dup2, key, param);
2128 path = rb_ary_entry(val, 0);
2130 path ==
ID2SYM(id_child)) {
2131 param = check_exec_redirect_fd(rb_ary_entry(val, 1), 0);
2132 eargp->fd_dup2_child = check_exec_redirect1(eargp->fd_dup2_child, key, param);
2136 flags = rb_ary_entry(val, 1);
2139 else if (RB_TYPE_P(flags,
T_STRING))
2143 perm = rb_ary_entry(val, 2);
2145 param = hide_obj(
rb_ary_new3(4, hide_obj(EXPORT_DUP(path)),
2146 flags, perm,
Qnil));
2147 eargp->fd_open = check_exec_redirect1(eargp->fd_open, key, param);
2154 if (RB_TYPE_P(key,
T_FILE))
2155 key = check_exec_redirect_fd(key, 1);
2157 flags =
INT2NUM(O_WRONLY|O_CREAT|O_TRUNC);
2158 else if (RB_TYPE_P(key,
T_ARRAY)) {
2162 VALUE fd = check_exec_redirect_fd(v, 1);
2166 flags =
INT2NUM(O_WRONLY|O_CREAT|O_TRUNC);
2173 param = hide_obj(
rb_ary_new3(4, hide_obj(EXPORT_DUP(path)),
2174 flags, perm,
Qnil));
2175 eargp->fd_open = check_exec_redirect1(eargp->fd_open, key, param);
2181 if (!
NIL_P(val))
goto io;
2187#if defined(HAVE_SETRLIMIT) && defined(NUM2RLIM)
2188static int rlimit_type_by_sym(
VALUE key);
2191rb_execarg_addopt_rlimit(
struct rb_execarg *eargp,
int rtype,
VALUE val)
2193 VALUE ary = eargp->rlimit_limits;
2194 VALUE tmp, softlim, hardlim;
2195 if (eargp->rlimit_limits ==
Qfalse)
2196 ary = eargp->rlimit_limits = hide_obj(rb_ary_new());
2198 ary = eargp->rlimit_limits;
2199 tmp = rb_check_array_type(val);
2202 softlim = hardlim =
rb_to_int(rb_ary_entry(tmp, 0));
2204 softlim =
rb_to_int(rb_ary_entry(tmp, 0));
2205 hardlim =
rb_to_int(rb_ary_entry(tmp, 1));
2215 rb_ary_push(ary, tmp);
2219#define TO_BOOL(val, name) (NIL_P(val) ? 0 : rb_bool_expected((val), name, TRUE))
2223 struct rb_execarg *eargp = rb_execarg_get(execarg_obj);
2227 switch (
TYPE(key)) {
2229#if defined(HAVE_SETRLIMIT) && defined(NUM2RLIM)
2231 int rtype = rlimit_type_by_sym(key);
2233 rb_execarg_addopt_rlimit(eargp, rtype, val);
2241 if (
id == id_pgroup) {
2243 if (eargp->pgroup_given) {
2248 else if (val ==
Qtrue)
2256 eargp->pgroup_given = 1;
2257 eargp->pgroup_pgid = pgroup;
2262 if (
id == id_new_pgroup) {
2263 if (eargp->new_pgroup_given) {
2266 eargp->new_pgroup_given = 1;
2267 eargp->new_pgroup_flag = TO_BOOL(val,
"new_pgroup");
2271 if (
id == id_unsetenv_others) {
2272 if (eargp->unsetenv_others_given) {
2275 eargp->unsetenv_others_given = 1;
2276 eargp->unsetenv_others_do = TO_BOOL(val,
"unsetenv_others");
2278 else if (
id == id_chdir) {
2279 if (eargp->chdir_given) {
2283 val = rb_str_encode_ospath(val);
2284 eargp->chdir_given = 1;
2285 eargp->chdir_dir = hide_obj(EXPORT_DUP(val));
2287 else if (
id == id_umask) {
2289 if (eargp->umask_given) {
2292 eargp->umask_given = 1;
2293 eargp->umask_mask = cmask;
2295 else if (
id == id_close_others) {
2296 if (eargp->close_others_given) {
2299 eargp->close_others_given = 1;
2300 eargp->close_others_do = TO_BOOL(val,
"close_others");
2302 else if (
id == id_in) {
2306 else if (
id == id_out) {
2310 else if (
id == id_err) {
2314 else if (
id == id_uid) {
2316 if (eargp->uid_given) {
2321 eargp->uid = OBJ2UID(val);
2322 eargp->uid_given = 1;
2326 "uid option is unimplemented on this machine");
2329 else if (
id == id_gid) {
2331 if (eargp->gid_given) {
2336 eargp->gid = OBJ2GID(val);
2337 eargp->gid_given = 1;
2341 "gid option is unimplemented on this machine");
2344 else if (
id == id_exception) {
2345 if (eargp->exception_given) {
2348 eargp->exception_given = 1;
2349 eargp->exception = TO_BOOL(val,
"exception");
2360 check_exec_redirect(key, val, eargp);
2372check_exec_options_i(st_data_t st_key, st_data_t st_val, st_data_t arg)
2377 if (rb_execarg_addopt(execarg_obj, key, val) != ST_CONTINUE) {
2387check_exec_options_i_extract(st_data_t st_key, st_data_t st_val, st_data_t arg)
2392 VALUE execarg_obj = args[0];
2393 if (rb_execarg_addopt(execarg_obj, key, val) != ST_CONTINUE) {
2394 VALUE nonopts = args[1];
2395 if (
NIL_P(nonopts)) args[1] = nonopts = rb_hash_new();
2396 rb_hash_aset(nonopts, key, val);
2413 if (ary == eargp->fd_dup2)
2415 else if (ary == eargp->fd_dup2_child)
2421 if (ary == eargp->fd_dup2 || ary == eargp->fd_dup2_child) {
2434 VALUE h = rb_hash_new();
2439 maxhint = check_exec_fds_1(eargp, h, maxhint, eargp->fd_dup2);
2440 maxhint = check_exec_fds_1(eargp, h, maxhint, eargp->fd_close);
2441 maxhint = check_exec_fds_1(eargp, h, maxhint, eargp->fd_dup2_child);
2443 if (eargp->fd_dup2_child) {
2444 ary = eargp->fd_dup2_child;
2454 val = rb_hash_lookup(h, val);
2461 if (oldfd != lastfd) {
2463 rb_ary_store(elt, 1,
INT2FIX(lastfd));
2466 while (
FIXNUM_P(val2 = rb_hash_lookup(h, val))) {
2467 rb_hash_aset(h, val,
INT2FIX(lastfd));
2474 eargp->close_others_maxhint = maxhint;
2479rb_check_exec_options(
VALUE opthash,
VALUE execarg_obj)
2483 rb_hash_stlike_foreach(opthash, check_exec_options_i, (st_data_t)execarg_obj);
2487rb_execarg_extract_options(
VALUE execarg_obj,
VALUE opthash)
2492 args[0] = execarg_obj;
2494 rb_hash_stlike_foreach(opthash, check_exec_options_i_extract, (st_data_t)args);
2498#ifdef ENV_IGNORECASE
2499#define ENVMATCH(s1, s2) (STRCASECMP((s1), (s2)) == 0)
2501#define ENVMATCH(n1, n2) (strcmp((n1), (n2)) == 0)
2505check_exec_env_i(st_data_t st_key, st_data_t st_val, st_data_t arg)
2520 key = EXPORT_STR(key);
2521 if (!
NIL_P(val)) val = EXPORT_STR(val);
2526 rb_ary_push(env, hide_obj(rb_assoc_new(key, val)));
2536 env[0] = hide_obj(rb_ary_new());
2538 rb_hash_stlike_foreach(hash, check_exec_env_i, (st_data_t)env);
2545rb_check_argv(
int argc,
VALUE *argv)
2553 tmp = rb_check_array_type(argv[0]);
2564 for (i = 0; i < argc; i++) {
2573check_hash(
VALUE obj)
2575 if (RB_SPECIAL_CONST_P(obj))
return Qnil;
2576 switch (RB_BUILTIN_TYPE(obj)) {
2583 return rb_check_hash_type(obj);
2587rb_exec_getargs(
int *argc_p,
VALUE **argv_p,
int accept_shell,
VALUE *env_ret,
VALUE *opthash_ret)
2592 hash = check_hash((*argv_p)[*argc_p-1]);
2594 *opthash_ret = hash;
2600 hash = check_hash((*argv_p)[0]);
2607 prog = rb_check_argv(*argc_p, *argv_p);
2609 prog = (*argv_p)[0];
2610 if (accept_shell && *argc_p == 1) {
2625compare_posix_sh(
const void *key,
const void *el)
2628 int ret = strncmp(word->ptr, el, word->len);
2629 if (!ret && ((
const char *)el)[word->len]) ret = -1;
2637 struct rb_execarg *eargp = rb_execarg_get(execarg_obj);
2638 char fbuf[MAXPATHLEN];
2642 if (!
NIL_P(opthash)) {
2643 rb_check_exec_options(opthash, execarg_obj);
2646 env = rb_check_exec_env(env, &eargp->path_env);
2647 eargp->env_modification = env;
2650 prog = EXPORT_STR(prog);
2651 eargp->use_shell = argc == 0;
2652 if (eargp->use_shell)
2653 eargp->invoke.sh.shell_script = prog;
2655 eargp->invoke.cmd.command_name = prog;
2658 if (eargp->use_shell) {
2659 static const char posix_sh_cmds[][9] = {
2717 for (p = RSTRING_PTR(prog); *p; p++) {
2718 if (*p ==
' ' || *p ==
'\t') {
2719 if (first.ptr && !first.len) first.len = p - first.ptr;
2722 if (!first.ptr) first.ptr = p;
2724 if (!has_meta && strchr(
"*?{}[]<>()~&|\\$;'`\"\n#", *p))
2730 else if (*p ==
'/') {
2737 if (!has_meta && first.ptr) {
2738 if (!first.len) first.len = p - first.ptr;
2739 if (first.len > 0 && first.len <=
sizeof(posix_sh_cmds[0]) &&
2740 bsearch(&first, posix_sh_cmds, numberof(posix_sh_cmds),
sizeof(posix_sh_cmds[0]), compare_posix_sh))
2745 eargp->use_shell = 0;
2747 if (!eargp->use_shell) {
2750 p = RSTRING_PTR(prog);
2752 while (*p ==
' ' || *p ==
'\t')
2756 while (*p && *p !=
' ' && *p !=
'\t')
2762 eargp->invoke.cmd.argv_buf = argv_buf;
2763 eargp->invoke.cmd.command_name =
2764 hide_obj(
rb_str_subseq(argv_buf, 0, strlen(RSTRING_PTR(argv_buf))));
2765 rb_enc_copy(eargp->invoke.cmd.command_name, prog);
2770 if (!eargp->use_shell) {
2771 const char *abspath;
2772 const char *path_env = 0;
2773 if (
RTEST(eargp->path_env)) path_env = RSTRING_PTR(eargp->path_env);
2774 abspath = dln_find_exe_r(RSTRING_PTR(eargp->invoke.cmd.command_name),
2775 path_env, fbuf,
sizeof(fbuf));
2779 eargp->invoke.cmd.command_abspath =
Qnil;
2782 if (!eargp->use_shell && !eargp->invoke.cmd.argv_buf) {
2787 for (i = 0; i < argc; i++) {
2788 VALUE arg = argv[i];
2790#ifdef DEFAULT_PROCESS_ENCODING
2791 arg = EXPORT_STR(arg);
2792 s = RSTRING_PTR(arg);
2796 eargp->invoke.cmd.argv_buf = argv_buf;
2799 if (!eargp->use_shell) {
2800 const char *p, *ep, *null=NULL;
2804 p = RSTRING_PTR(eargp->invoke.cmd.argv_buf);
2805 ep = p + RSTRING_LEN(eargp->invoke.cmd.argv_buf);
2811 eargp->invoke.cmd.argv_str =
2812 rb_imemo_tmpbuf_auto_free_pointer_new_from_an_RString(argv_str);
2818rb_execarg_get(
VALUE execarg_obj)
2826rb_execarg_init(
int argc,
const VALUE *orig_argv,
int accept_shell,
VALUE execarg_obj)
2828 struct rb_execarg *eargp = rb_execarg_get(execarg_obj);
2834 prog = rb_exec_getargs(&argc, &argv, accept_shell, &env, &opthash);
2835 rb_exec_fillarg(prog, argc, argv, env, opthash, execarg_obj);
2837 ret = eargp->use_shell ? eargp->invoke.sh.shell_script : eargp->invoke.cmd.command_name;
2843rb_execarg_new(
int argc,
const VALUE *argv,
int accept_shell,
int allow_exc_opt)
2848 rb_execarg_init(argc, argv, accept_shell, execarg_obj);
2849 if (!allow_exc_opt && eargp->exception_given) {
2856rb_execarg_setenv(
VALUE execarg_obj,
VALUE env)
2858 struct rb_execarg *eargp = rb_execarg_get(execarg_obj);
2859 env = !
NIL_P(env) ? rb_check_exec_env(env, &eargp->path_env) :
Qfalse;
2860 eargp->env_modification = env;
2864fill_envp_buf_i(st_data_t st_key, st_data_t st_val, st_data_t arg)
2879static long run_exec_dup2_tmpbuf_size(
long n);
2893 const char *fname = RSTRING_PTR(data->fname);
2894 data->ret = parent_redirect_open(fname, data->oflags, data->perm);
2900rb_execarg_allocate_dup2_tmpbuf(
struct rb_execarg *eargp,
long len)
2902 VALUE tmpbuf = rb_imemo_tmpbuf_auto_free_pointer();
2903 rb_imemo_tmpbuf_set_ptr(tmpbuf, ruby_xmalloc(run_exec_dup2_tmpbuf_size(len)));
2904 eargp->dup2_tmpbuf = tmpbuf;
2908rb_execarg_parent_start1(
VALUE execarg_obj)
2910 struct rb_execarg *eargp = rb_execarg_get(execarg_obj);
2911 int unsetenv_others;
2915 ary = eargp->fd_open;
2930 open_data.fname = vpath;
2931 open_data.oflags = flags;
2932 open_data.perm = perm;
2934 open_data.err = EINTR;
2936 if (open_data.ret == -1) {
2937 if (open_data.err == EINTR) {
2943 fd2 = open_data.ret;
2945 RARRAY_ASET(param, 3,
INT2FIX(fd2));
2955 eargp->redirect_fds = check_exec_fds(eargp);
2957 ary = eargp->fd_dup2;
2959 rb_execarg_allocate_dup2_tmpbuf(eargp,
RARRAY_LEN(ary));
2962 unsetenv_others = eargp->unsetenv_others_given && eargp->unsetenv_others_do;
2963 envopts = eargp->env_modification;
2964 if (ALWAYS_NEED_ENVP || unsetenv_others || envopts !=
Qfalse) {
2965 VALUE envtbl, envp_str, envp_buf;
2967 if (unsetenv_others) {
2968 envtbl = rb_hash_new();
2971 envtbl = rb_env_to_hash();
2975 st_table *stenv = RHASH_TBL_RAW(envtbl);
2982 st_data_t stkey = (st_data_t)key;
2983 st_delete(stenv, &stkey, NULL);
2986 st_insert(stenv, (st_data_t)key, (st_data_t)val);
2994 rb_hash_stlike_foreach(envtbl, fill_envp_buf_i, (st_data_t)envp_buf);
2997 p = RSTRING_PTR(envp_buf);
2998 ep = p + RSTRING_LEN(envp_buf);
3006 rb_imemo_tmpbuf_auto_free_pointer_new_from_an_RString(envp_str);
3007 eargp->envp_buf = envp_buf;
3023rb_execarg_parent_start(
VALUE execarg_obj)
3026 rb_protect(rb_execarg_parent_start1, execarg_obj, &state);
3028 rb_execarg_parent_end(execarg_obj);
3034execarg_parent_end(
VALUE execarg_obj)
3036 struct rb_execarg *eargp = rb_execarg_get(execarg_obj);
3040 ary = eargp->fd_open;
3051 parent_redirect_close(fd2);
3052 RARRAY_ASET(param, 3,
Qnil);
3062rb_execarg_parent_end(
VALUE execarg_obj)
3064 execarg_parent_end(execarg_obj);
3069rb_exec_fail(
struct rb_execarg *eargp,
int err,
const char *errmsg)
3071 if (!errmsg || !*errmsg)
return;
3072 if (strcmp(errmsg,
"chdir") == 0) {
3080rb_execarg_fail(
VALUE execarg_obj,
int err,
const char *errmsg)
3082 if (!errmsg || !*errmsg)
return;
3083 rb_exec_fail(rb_execarg_get(execarg_obj), err, errmsg);
3091 VALUE execarg_obj, fail_str;
3093#define CHILD_ERRMSG_BUFLEN 80
3094 char errmsg[CHILD_ERRMSG_BUFLEN] = {
'\0' };
3097 execarg_obj = rb_execarg_new(argc, argv, TRUE, FALSE);
3098 eargp = rb_execarg_get(execarg_obj);
3099 if (mjit_enabled) mjit_finish(
false);
3102 rb_protect(rb_execarg_parent_start1, execarg_obj, &state);
3104 execarg_parent_end(execarg_obj);
3109 fail_str = eargp->use_shell ? eargp->invoke.sh.shell_script : eargp->invoke.cmd.command_name;
3111 err = exec_async_signal_safe(eargp, errmsg,
sizeof(errmsg));
3114 rb_exec_fail(eargp, err, errmsg);
3204#define ERRMSG(str) do { if (errmsg && 0 < errmsg_buflen) strlcpy(errmsg, (str), errmsg_buflen); } while (0)
3205#define ERRMSG1(str, a) do { if (errmsg && 0 < errmsg_buflen) snprintf(errmsg, errmsg_buflen, (str), (a)); } while (0)
3206#define ERRMSG2(str, a, b) do { if (errmsg && 0 < errmsg_buflen) snprintf(errmsg, errmsg_buflen, (str), (a), (b)); } while (0)
3208static int fd_get_cloexec(
int fd,
char *errmsg,
size_t errmsg_buflen);
3209static int fd_set_cloexec(
int fd,
char *errmsg,
size_t errmsg_buflen);
3210static int fd_clear_cloexec(
int fd,
char *errmsg,
size_t errmsg_buflen);
3213save_redirect_fd(
int fd,
struct rb_execarg *sargp,
char *errmsg,
size_t errmsg_buflen)
3216 VALUE newary, redirection;
3217 int save_fd = redirect_cloexec_dup(fd), cloexec;
3218 if (save_fd == -1) {
3225 newary = sargp->fd_dup2;
3227 newary = hide_obj(rb_ary_new());
3228 sargp->fd_dup2 = newary;
3230 cloexec = fd_get_cloexec(fd, errmsg, errmsg_buflen);
3231 redirection = hide_obj(rb_assoc_new(
INT2FIX(fd),
INT2FIX(save_fd)));
3232 if (cloexec) rb_ary_push(redirection,
Qtrue);
3233 rb_ary_push(newary, redirection);
3235 newary = sargp->fd_close;
3237 newary = hide_obj(rb_ary_new());
3238 sargp->fd_close = newary;
3240 rb_ary_push(newary, hide_obj(rb_assoc_new(
INT2FIX(save_fd),
Qnil)));
3247intcmp(
const void *a,
const void *b)
3249 return *(
int*)a - *(
int*)b;
3253intrcmp(
const void *a,
const void *b)
3255 return *(
int*)b - *(
int*)a;
3267run_exec_dup2_tmpbuf_size(
long n)
3274fd_get_cloexec(
int fd,
char *errmsg,
size_t errmsg_buflen)
3278 ret = fcntl(fd, F_GETFD);
3280 ERRMSG(
"fcntl(F_GETFD)");
3283 if (ret & FD_CLOEXEC)
return 1;
3290fd_set_cloexec(
int fd,
char *errmsg,
size_t errmsg_buflen)
3294 ret = fcntl(fd, F_GETFD);
3296 ERRMSG(
"fcntl(F_GETFD)");
3299 if (!(ret & FD_CLOEXEC)) {
3301 ret = fcntl(fd, F_SETFD, ret);
3303 ERRMSG(
"fcntl(F_SETFD)");
3313fd_clear_cloexec(
int fd,
char *errmsg,
size_t errmsg_buflen)
3317 ret = fcntl(fd, F_GETFD);
3319 ERRMSG(
"fcntl(F_GETFD)");
3322 if (ret & FD_CLOEXEC) {
3324 ret = fcntl(fd, F_SETFD, ret);
3326 ERRMSG(
"fcntl(F_SETFD)");
3336run_exec_dup2(
VALUE ary,
VALUE tmpbuf,
struct rb_execarg *sargp,
char *errmsg,
size_t errmsg_buflen)
3347 for (i = 0; i < n; i++) {
3352 pairs[i].older_index = -1;
3362 for (i = 0; i < n; i++) {
3363 int newfd = pairs[i].newfd;
3367 pairs[i].num_newer = 0;
3369 while (pairs < found && (found-1)->oldfd == newfd)
3371 while (found < pairs+n && found->oldfd == newfd) {
3372 pairs[i].num_newer++;
3373 found->older_index = i;
3380 for (i = 0; i < n; i++) {
3382 while (j != -1 && pairs[j].oldfd != -1 && pairs[j].num_newer == 0) {
3383 if (save_redirect_fd(pairs[j].newfd, sargp, errmsg, errmsg_buflen) < 0)
3385 ret = redirect_dup2(pairs[j].oldfd, pairs[j].newfd);
3390 if (pairs[j].cloexec &&
3391 fd_set_cloexec(pairs[j].newfd, errmsg, errmsg_buflen)) {
3395 pairs[j].oldfd = -1;
3396 j = pairs[j].older_index;
3398 pairs[j].num_newer--;
3403 for (i = 0; i < n; i++) {
3405 if (pairs[i].oldfd == -1)
3407 if (pairs[i].oldfd == pairs[i].newfd) {
3408 if (fd_clear_cloexec(pairs[i].oldfd, errmsg, errmsg_buflen) == -1)
3410 pairs[i].oldfd = -1;
3413 if (extra_fd == -1) {
3414 extra_fd = redirect_dup(pairs[i].oldfd);
3415 if (extra_fd == -1) {
3422 ret = redirect_dup2(pairs[i].oldfd, extra_fd);
3429 pairs[i].oldfd = extra_fd;
3430 j = pairs[i].older_index;
3431 pairs[i].older_index = -1;
3433 ret = redirect_dup2(pairs[j].oldfd, pairs[j].newfd);
3439 pairs[j].oldfd = -1;
3440 j = pairs[j].older_index;
3443 if (extra_fd != -1) {
3444 ret = redirect_close(extra_fd);
3459run_exec_close(
VALUE ary,
char *errmsg,
size_t errmsg_buflen)
3467 ret = redirect_close(fd);
3478run_exec_dup2_child(
VALUE ary,
struct rb_execarg *sargp,
char *errmsg,
size_t errmsg_buflen)
3488 if (save_redirect_fd(newfd, sargp, errmsg, errmsg_buflen) < 0)
3490 ret = redirect_dup2(oldfd, newfd);
3503run_exec_pgroup(
const struct rb_execarg *eargp,
struct rb_execarg *sargp,
char *errmsg,
size_t errmsg_buflen)
3515 pgroup = eargp->pgroup_pgid;
3521 sargp->pgroup_given = 1;
3522 sargp->pgroup_pgid = getpgrp();
3528 ret = setpgid(getpid(), pgroup);
3529 if (ret == -1) ERRMSG(
"setpgid");
3534#if defined(HAVE_SETRLIMIT) && defined(RLIM2NUM)
3537run_exec_rlimit(
VALUE ary,
struct rb_execarg *sargp,
char *errmsg,
size_t errmsg_buflen)
3546 if (getrlimit(rtype, &rlim) == -1) {
3547 ERRMSG(
"getrlimit");
3551 RLIM2NUM(rlim.rlim_cur),
3552 RLIM2NUM(rlim.rlim_max)));
3553 if (sargp->rlimit_limits ==
Qfalse)
3554 newary = sargp->rlimit_limits = hide_obj(rb_ary_new());
3556 newary = sargp->rlimit_limits;
3557 rb_ary_push(newary, tmp);
3561 if (setrlimit(rtype, &rlim) == -1) {
3562 ERRMSG(
"setrlimit");
3570#if !defined(HAVE_WORKING_FORK)
3574 rb_ary_push(ary, hide_obj(rb_ary_dup(argv[0])));
3583 if (sargp->env_modification ==
Qfalse) {
3584 VALUE env = rb_envtbl();
3586 VALUE ary = hide_obj(rb_ary_new());
3589 sargp->env_modification = ary;
3591 sargp->unsetenv_others_given = 1;
3592 sargp->unsetenv_others_do = 1;
3599#define chdir(p) rb_w32_uchdir(p)
3604rb_execarg_run_options(
const struct rb_execarg *eargp,
struct rb_execarg *sargp,
char *errmsg,
size_t errmsg_buflen)
3611 sargp->redirect_fds =
Qnil;
3615 if (eargp->pgroup_given) {
3616 if (run_exec_pgroup(eargp, sargp, errmsg, errmsg_buflen) == -1)
3621#if defined(HAVE_SETRLIMIT) && defined(RLIM2NUM)
3622 obj = eargp->rlimit_limits;
3624 if (run_exec_rlimit(obj, sargp, errmsg, errmsg_buflen) == -1)
3629#if !defined(HAVE_WORKING_FORK)
3630 if (eargp->unsetenv_others_given && eargp->unsetenv_others_do) {
3635 obj = eargp->env_modification;
3651 if (eargp->umask_given) {
3652 mode_t mask = eargp->umask_mask;
3653 mode_t oldmask = umask(mask);
3655 sargp->umask_given = 1;
3656 sargp->umask_mask = oldmask;
3660 obj = eargp->fd_dup2;
3662 if (run_exec_dup2(obj, eargp->dup2_tmpbuf, sargp, errmsg, errmsg_buflen) == -1)
3666 obj = eargp->fd_close;
3669 rb_warn(
"cannot close fd before spawn");
3671 if (run_exec_close(obj, errmsg, errmsg_buflen) == -1)
3676#ifdef HAVE_WORKING_FORK
3677 if (eargp->close_others_do) {
3682 obj = eargp->fd_dup2_child;
3684 if (run_exec_dup2_child(obj, sargp, errmsg, errmsg_buflen) == -1)
3688 if (eargp->chdir_given) {
3690 sargp->chdir_given = 1;
3691 sargp->chdir_dir = hide_obj(rb_dir_getwd_ospath());
3693 if (chdir(RSTRING_PTR(eargp->chdir_dir)) == -1) {
3700 if (eargp->gid_given) {
3701 if (setgid(eargp->gid) < 0) {
3708 if (eargp->uid_given) {
3709 if (setuid(eargp->uid) < 0) {
3717 VALUE ary = sargp->fd_dup2;
3719 rb_execarg_allocate_dup2_tmpbuf(sargp,
RARRAY_LEN(ary));
3723 int preserve = errno;
3724 stdfd_clear_nonblock();
3733rb_exec_async_signal_safe(
const struct rb_execarg *eargp,
char *errmsg,
size_t errmsg_buflen)
3735 errno = exec_async_signal_safe(eargp, errmsg, errmsg_buflen);
3740exec_async_signal_safe(
const struct rb_execarg *eargp,
char *errmsg,
size_t errmsg_buflen)
3742#if !defined(HAVE_WORKING_FORK)
3743 struct rb_execarg sarg, *
const sargp = &sarg;
3749 if (rb_execarg_run_options(eargp, sargp, errmsg, errmsg_buflen) < 0) {
3753 if (eargp->use_shell) {
3754 err = proc_exec_sh(RSTRING_PTR(eargp->invoke.sh.shell_script), eargp->envp_str);
3757 char *abspath = NULL;
3758 if (!
NIL_P(eargp->invoke.cmd.command_abspath))
3759 abspath = RSTRING_PTR(eargp->invoke.cmd.command_abspath);
3760 err = proc_exec_cmd(abspath, eargp->invoke.cmd.argv_str, eargp->envp_str);
3762#if !defined(HAVE_WORKING_FORK)
3763 rb_execarg_run_options(sargp, NULL, errmsg, errmsg_buflen);
3769#ifdef HAVE_WORKING_FORK
3772rb_exec_atfork(
void* arg,
char *errmsg,
size_t errmsg_buflen)
3774 return rb_exec_async_signal_safe(arg, errmsg, errmsg_buflen);
3778proc_syswait(
VALUE pid)
3785move_fds_to_avoid_crash(
int *fdp,
int n,
VALUE fds)
3789 for (i = 0; i < n; i++) {
3808pipe_nocrash(
int filedes[2],
VALUE fds)
3816 if (move_fds_to_avoid_crash(filedes, 2, fds) == -1) {
3831rb_thread_sleep_that_takes_VALUE_as_sole_argument(
VALUE n)
3838handle_fork_error(
int err,
struct rb_process_status *status,
int *ep,
volatile int *try_gc_p)
3844 if ((*try_gc_p)-- > 0 && !rb_during_gc()) {
3850#if defined(EWOULDBLOCK) && EWOULDBLOCK != EAGAIN
3853 if (!status && !ep) {
3858 rb_protect(rb_thread_sleep_that_takes_VALUE_as_sole_argument,
INT2FIX(1), &state);
3859 if (status) status->status = state;
3860 if (!state)
return 0;
3869 if (state && !status) rb_jump_tag(state);
3873#define prefork() ( \
3874 rb_io_flush(rb_stdout), \
3875 rb_io_flush(rb_stderr) \
3905write_retry(
int fd,
const void *buf,
size_t len)
3910 w = write(fd, buf, len);
3911 }
while (w < 0 && errno == EINTR);
3917read_retry(
int fd,
void *buf,
size_t len)
3921 if (set_blocking(fd) != 0) {
3923 rb_async_bug_errno(
"set_blocking failed reading child error", errno);
3928 r = read(fd, buf, len);
3929 }
while (r < 0 && errno == EINTR);
3935send_child_error(
int fd,
char *errmsg,
size_t errmsg_buflen)
3940 if (write_retry(fd, &err,
sizeof(err)) < 0) err = errno;
3941 if (errmsg && 0 < errmsg_buflen) {
3942 errmsg[errmsg_buflen-1] =
'\0';
3943 errmsg_buflen = strlen(errmsg);
3944 if (errmsg_buflen > 0 && write_retry(fd, errmsg, errmsg_buflen) < 0)
3950recv_child_error(
int fd,
int *errp,
char *errmsg,
size_t errmsg_buflen)
3954 if ((size = read_retry(fd, &err,
sizeof(err))) < 0) {
3958 if (size ==
sizeof(err) &&
3959 errmsg && 0 < errmsg_buflen) {
3960 ssize_t ret = read_retry(fd, errmsg, errmsg_buflen-1);
3969#ifdef HAVE_WORKING_VFORK
3970#if !defined(HAVE_GETRESUID) && defined(HAVE_GETUIDX)
3973getresuid(rb_uid_t *ruid, rb_uid_t *euid, rb_uid_t *suid)
3979 ret = getuidx(ID_SAVED);
3980 if (ret == (rb_uid_t)-1)
3985#define HAVE_GETRESUID
3988#if !defined(HAVE_GETRESGID) && defined(HAVE_GETGIDX)
3991getresgid(rb_gid_t *rgid, rb_gid_t *egid, rb_gid_t *sgid)
3997 ret = getgidx(ID_SAVED);
3998 if (ret == (rb_gid_t)-1)
4003#define HAVE_GETRESGID
4021 rb_uid_t ruid, euid;
4022 rb_gid_t rgid, egid;
4024#if defined HAVE_ISSETUGID
4029#ifdef HAVE_GETRESUID
4033 ret = getresuid(&ruid, &euid, &suid);
4044 if (euid == 0 || euid != ruid)
4047#ifdef HAVE_GETRESGID
4051 ret = getresgid(&rgid, &egid, &sgid);
4069struct child_handler_disabler_state
4075disable_child_handler_before_fork(
struct child_handler_disabler_state *old)
4077#ifdef HAVE_PTHREAD_SIGMASK
4081 ret = sigfillset(&all);
4085 ret = pthread_sigmask(SIG_SETMASK, &all, &old->sigmask);
4090# pragma GCC warning "pthread_sigmask on fork is not available. potentially dangerous"
4095disable_child_handler_fork_parent(
struct child_handler_disabler_state *old)
4097#ifdef HAVE_PTHREAD_SIGMASK
4100 ret = pthread_sigmask(SIG_SETMASK, &old->sigmask, NULL);
4105# pragma GCC warning "pthread_sigmask on fork is not available. potentially dangerous"
4111disable_child_handler_fork_child(
struct child_handler_disabler_state *old,
char *errmsg,
size_t errmsg_buflen)
4116 for (sig = 1; sig < NSIG; sig++) {
4117 sig_t handler = signal(sig, SIG_DFL);
4119 if (handler == SIG_ERR && errno == EINVAL) {
4122 if (handler == SIG_ERR) {
4123 ERRMSG(
"signal to obtain old action");
4127 if (sig == SIGPIPE) {
4132 if (handler == SIG_IGN) {
4133 signal(sig, SIG_IGN);
4138 sigemptyset(&old->sigmask);
4139 ret = sigprocmask(SIG_SETMASK, &old->sigmask, NULL);
4141 ERRMSG(
"sigprocmask");
4149 int (*chfunc)(
void*,
char *,
size_t),
void *charg,
4150 char *errmsg,
size_t errmsg_buflen,
4154 volatile int try_gc = 1;
4155 struct child_handler_disabler_state old;
4158 (w && WAITPID_USE_SIGCHLD) ? &GET_VM()->waitpid_lock : 0;
4163 disable_child_handler_before_fork(&old);
4167#ifdef HAVE_WORKING_VFORK
4168 if (!has_privilege())
4178 ret = disable_child_handler_fork_child(&old, errmsg, errmsg_buflen);
4180 ret = chfunc(charg, errmsg, errmsg_buflen);
4181 if (!ret) _exit(EXIT_SUCCESS);
4183 send_child_error(ep[1], errmsg, errmsg_buflen);
4184#if EXIT_SUCCESS == 127
4185 _exit(EXIT_FAILURE);
4191 waitpid_lock = waitpid_lock_init;
4193 if (pid > 0 && w != WAITPID_LOCK_ONLY) {
4195 ccan_list_add(&GET_VM()->waiting_pids, &w->wnode);
4199 disable_child_handler_fork_parent(&old);
4203 if (handle_fork_error(err, status, ep, &try_gc))
4213 struct child_handler_disabler_state old;
4216 disable_child_handler_before_fork(&old);
4220 pid_t pid = rb_fork();
4221 if (pid > 0) mjit_add_waiting_pid(vm, pid);
4225 disable_child_handler_fork_parent(&old);
4233fork_check_err(
struct rb_process_status *status,
int (*chfunc)(
void*,
char *,
size_t),
void *charg,
4234 VALUE fds,
char *errmsg,
size_t errmsg_buflen,
4242 struct waitpid_state *w = eargp && eargp->waitpid_state ? eargp->waitpid_state : 0;
4244 if (status) status->status = 0;
4246 if (pipe_nocrash(ep, fds))
return -1;
4248 pid = retry_fork_async_signal_safe(status, ep, chfunc, charg, errmsg, errmsg_buflen, w);
4250 if (status) status->pid = pid;
4253 if (status) status->error = errno;
4260 error_occurred = recv_child_error(ep[0], &err, errmsg, errmsg_buflen);
4262 if (error_occurred) {
4265 status->error = err;
4267 VM_ASSERT((w == 0 || w == WAITPID_LOCK_ONLY) &&
4268 "only used by extensions");
4269 rb_protect(proc_syswait, (
VALUE)pid, &state);
4271 status->status = state;
4273 else if (!w || w == WAITPID_LOCK_ONLY) {
4292rb_fork_async_signal_safe(
int *status,
4293 int (*chfunc)(
void*,
char *,
size_t),
void *charg,
4294 VALUE fds,
char *errmsg,
size_t errmsg_buflen)
4298 rb_pid_t result = fork_check_err(&process_status, chfunc, charg, fds, errmsg, errmsg_buflen, 0);
4301 *status = process_status.status;
4311 int try_gc = 1, err;
4312 struct child_handler_disabler_state old;
4314 if (status) status->status = 0;
4318 if (mjit_enabled) mjit_pause(
false);
4319 disable_child_handler_before_fork(&old);
4325 status->error = err;
4328 disable_child_handler_fork_parent(&old);
4330 if (mjit_enabled && pid > 0) mjit_resume();
4338 if (handle_fork_error(err, status, NULL, &try_gc)) {
4345rb_fork_ruby(
int *status)
4349 rb_pid_t pid = rb_fork_ruby2(&process_status);
4351 if (status) *status = process_status.status;
4359 rb_pid_t pid = rb_fork_ruby(NULL);
4369rb_call_proc__fork(
void)
4374 return proc_fork_pid();
4383#if defined(HAVE_WORKING_FORK) && !defined(CANNOT_FORK_WITH_PTHREAD)
4404rb_proc__fork(
VALUE _obj)
4406 rb_pid_t pid = proc_fork_pid();
4440 pid = rb_call_proc__fork();
4454#define rb_proc__fork rb_f_notimplement
4455#define rb_f_fork rb_f_notimplement
4459exit_status_code(
VALUE status)
4465 istatus = EXIT_SUCCESS;
4468 istatus = EXIT_FAILURE;
4472#if EXIT_SUCCESS != 0
4474 istatus = EXIT_SUCCESS;
4481NORETURN(
static VALUE rb_f_exit_bang(
int argc,
VALUE *argv,
VALUE obj));
4494rb_f_exit_bang(
int argc,
VALUE *argv,
VALUE obj)
4498 if (rb_check_arity(argc, 0, 1) == 1) {
4499 istatus = exit_status_code(argv[0]);
4502 istatus = EXIT_FAILURE;
4512 if (GET_EC()->tag) {
4527 if (rb_check_arity(argc, 0, 1) == 1) {
4528 istatus = exit_status_code(argv[0]);
4531 istatus = EXIT_SUCCESS;
4590 rb_check_arity(argc, 0, 1);
4593 VALUE errinfo = rb_ec_get_errinfo(ec);
4594 if (!
NIL_P(errinfo)) {
4595 rb_ec_error_print(ec, errinfo);
4602 args[1] = args[0] = argv[0];
4605 args[0] =
INT2NUM(EXIT_FAILURE);
4640#if !defined HAVE_WORKING_FORK && !defined HAVE_SPAWNV && !defined __EMSCRIPTEN__
4645 if (eargp && !eargp->use_shell) {
4646 VALUE str = eargp->invoke.cmd.argv_str;
4647 VALUE buf = eargp->invoke.cmd.argv_buf;
4648 char *p, **argv = ARGVSTR2ARGV(str);
4649 long i, argc = ARGVSTR2ARGC(str);
4650 const char *start = RSTRING_PTR(buf);
4652 p = RSTRING_PTR(cmd);
4653 for (i = 1; i < argc; ++i) {
4654 p[argv[i] - start - 1] =
' ';
4664rb_spawn_process(
struct rb_execarg *eargp,
char *errmsg,
size_t errmsg_buflen)
4667#if !defined HAVE_WORKING_FORK || USE_SPAWNV
4670# if !defined HAVE_SPAWNV
4675#if defined HAVE_WORKING_FORK && !USE_SPAWNV
4676 pid = fork_check_err(eargp->status, rb_exec_atfork, eargp, eargp->redirect_fds, errmsg, errmsg_buflen, eargp);
4678 prog = eargp->use_shell ? eargp->invoke.sh.shell_script : eargp->invoke.cmd.command_name;
4680 if (rb_execarg_run_options(eargp, &sarg, errmsg, errmsg_buflen) < 0) {
4684 if (prog && !eargp->use_shell) {
4685 char **argv = ARGVSTR2ARGV(eargp->invoke.cmd.argv_str);
4686 argv[0] = RSTRING_PTR(prog);
4688# if defined HAVE_SPAWNV
4689 if (eargp->use_shell) {
4690 pid = proc_spawn_sh(RSTRING_PTR(prog));
4693 char **argv = ARGVSTR2ARGV(eargp->invoke.cmd.argv_str);
4694 pid = proc_spawn_cmd(argv, prog, eargp);
4701 status = system(rb_execarg_commandline(eargp, &prog));
4706 if (eargp->waitpid_state && eargp->waitpid_state != WAITPID_LOCK_ONLY) {
4707 eargp->waitpid_state->pid = pid;
4710 rb_execarg_run_options(&sarg, NULL, errmsg, errmsg_buflen);
4725do_spawn_process(
VALUE arg)
4728 rb_execarg_parent_start1(argp->execarg);
4730 argp->errmsg.ptr, argp->errmsg.buflen);
4734rb_execarg_spawn(
VALUE execarg_obj,
char *errmsg,
size_t errmsg_buflen)
4737 struct rb_execarg *eargp = rb_execarg_get(execarg_obj);
4743 if (!eargp->waitpid_state && mjit_enabled) {
4744 eargp->waitpid_state = WAITPID_LOCK_ONLY;
4747 args.execarg = execarg_obj;
4748 args.errmsg.ptr = errmsg;
4749 args.errmsg.buflen = errmsg_buflen;
4751 execarg_parent_end, execarg_obj);
4755rb_spawn_internal(
int argc,
const VALUE *argv,
char *errmsg,
size_t errmsg_buflen)
4759 execarg_obj = rb_execarg_new(argc, argv, TRUE, FALSE);
4760 return rb_execarg_spawn(execarg_obj, errmsg, errmsg_buflen);
4766 return rb_spawn_internal(argc, argv, errmsg, errmsg_buflen);
4772 return rb_spawn_internal(argc, argv, NULL, 0);
4832 VALUE execarg_obj = rb_execarg_new(argc, argv, TRUE, TRUE);
4833 struct rb_execarg *eargp = rb_execarg_get(execarg_obj);
4836 eargp->status = &status;
4838 rb_last_status_clear();
4842 rb_pid_t pid = rb_execarg_spawn(execarg_obj, 0, 0);
4845 VALUE status = rb_process_status_wait(pid, 0);
4850 GET_THREAD()->last_status = status;
4852 if (data->status == EXIT_SUCCESS) {
4856 if (data->error != 0) {
4857 if (eargp->exception) {
4858 VALUE command = eargp->invoke.sh.shell_script;
4866 else if (eargp->exception) {
4867 VALUE command = eargp->invoke.sh.shell_script;
4881 if (eargp->exception) {
4882 VALUE command = eargp->invoke.sh.shell_script;
5164 char errmsg[CHILD_ERRMSG_BUFLEN] = {
'\0' };
5165 VALUE execarg_obj, fail_str;
5168 execarg_obj = rb_execarg_new(argc, argv, TRUE, FALSE);
5169 eargp = rb_execarg_get(execarg_obj);
5170 fail_str = eargp->use_shell ? eargp->invoke.sh.shell_script : eargp->invoke.cmd.command_name;
5172 pid = rb_execarg_spawn(execarg_obj, errmsg,
sizeof(errmsg));
5176 rb_exec_fail(eargp, err, errmsg);
5180#if defined(HAVE_WORKING_FORK) || defined(HAVE_SPAWNV)
5207 time_t beg = time(0);
5210 if (scheduler !=
Qnil) {
5218 rb_check_arity(argc, 0, 1);
5223 time_t end = time(0) - beg;
5225 return TIMET2NUM(end);
5229#if (defined(HAVE_GETPGRP) && defined(GETPGRP_VOID)) || defined(HAVE_GETPGID)
5246#if defined(HAVE_GETPGRP) && defined(GETPGRP_VOID)
5257#define proc_getpgrp rb_f_notimplement
5261#if defined(HAVE_SETPGID) || (defined(HAVE_SETPGRP) && defined(SETPGRP_VOID))
5279#elif defined(HAVE_SETPGRP) && defined(SETPGRP_VOID)
5285#define proc_setpgrp rb_f_notimplement
5289#if defined(HAVE_GETPGID)
5310#define proc_getpgid rb_f_notimplement
5326 rb_pid_t ipid, ipgrp;
5335#define proc_setpgid rb_f_notimplement
5358 if (rb_check_arity(argc, 0, 1) == 1 && !
NIL_P(argv[0]))
5366#define proc_getsid rb_f_notimplement
5370#if defined(HAVE_SETSID) || (defined(HAVE_SETPGRP) && defined(TIOCNOTTY))
5371#if !defined(HAVE_SETSID)
5372static rb_pid_t ruby_setsid(
void);
5373#define setsid() ruby_setsid()
5396#if !defined(HAVE_SETSID)
5397#define HAVE_SETSID 1
5405#if defined(SETPGRP_VOID)
5411 ret = setpgrp(0, pid);
5413 if (ret == -1)
return -1;
5417 ioctl(fd, TIOCNOTTY, NULL);
5424#define proc_setsid rb_f_notimplement
5428#ifdef HAVE_GETPRIORITY
5449 int prio, iwhich, iwho;
5455 prio = getpriority(iwhich, iwho);
5460#define proc_getpriority rb_f_notimplement
5464#ifdef HAVE_GETPRIORITY
5480 int iwhich, iwho, iprio;
5486 if (setpriority(iwhich, iwho, iprio) < 0)
5491#define proc_setpriority rb_f_notimplement
5494#if defined(HAVE_SETRLIMIT) && defined(NUM2RLIM)
5496rlimit_resource_name2int(
const char *name,
long len,
int casetype)
5500#define RESCHECK(r) \
5502 if (len == rb_strlen_lit(#r) && STRCASECMP(name, #r) == 0) { \
5503 resource = RLIMIT_##r; \
5537#ifdef RLIMIT_MEMLOCK
5540#ifdef RLIMIT_MSGQUEUE
5579#ifdef RLIMIT_SIGPENDING
5580 RESCHECK(SIGPENDING);
5589 for (p = name; *p; p++)
5595 for (p = name; *p; p++)
5601 rb_bug(
"unexpected casetype");
5608rlimit_type_by_hname(
const char *name,
long len)
5610 return rlimit_resource_name2int(name, len, 0);
5614rlimit_type_by_lname(
const char *name,
long len)
5616 return rlimit_resource_name2int(name, len, 1);
5620rlimit_type_by_sym(
VALUE key)
5623 const char *rname = RSTRING_PTR(name);
5624 long len = RSTRING_LEN(name);
5626 static const char prefix[] =
"rlimit_";
5627 enum {prefix_len =
sizeof(prefix)-1};
5629 if (len > prefix_len && strncmp(prefix, rname, prefix_len) == 0) {
5630 rtype = rlimit_type_by_lname(rname + prefix_len, len - prefix_len);
5638rlimit_resource_type(
VALUE rtype)
5645 switch (
TYPE(rtype)) {
5648 name = RSTRING_PTR(v);
5649 len = RSTRING_LEN(v);
5658 len = RSTRING_LEN(rtype);
5668 r = rlimit_type_by_hname(name, len);
5678rlimit_resource_value(
VALUE rval)
5683 switch (
TYPE(rval)) {
5686 name = RSTRING_PTR(v);
5701 return NUM2RLIM(rval);
5705 if (strcmp(name,
"INFINITY") == 0)
return RLIM_INFINITY;
5707#ifdef RLIM_SAVED_MAX
5708 if (strcmp(name,
"SAVED_MAX") == 0)
return RLIM_SAVED_MAX;
5710#ifdef RLIM_SAVED_CUR
5711 if (strcmp(name,
"SAVED_CUR") == 0)
return RLIM_SAVED_CUR;
5719#if defined(HAVE_GETRLIMIT) && defined(RLIM2NUM)
5745 if (getrlimit(rlimit_resource_type(resource), &rlim) < 0) {
5748 return rb_assoc_new(RLIM2NUM(rlim.rlim_cur), RLIM2NUM(rlim.rlim_max));
5751#define proc_getrlimit rb_f_notimplement
5754#if defined(HAVE_SETRLIMIT) && defined(NUM2RLIM)
5808proc_setrlimit(
int argc,
VALUE *argv,
VALUE obj)
5810 VALUE resource, rlim_cur, rlim_max;
5813 rb_check_arity(argc, 2, 3);
5816 if (argc < 3 ||
NIL_P(rlim_max = argv[2]))
5817 rlim_max = rlim_cur;
5819 rlim.rlim_cur = rlimit_resource_value(rlim_cur);
5820 rlim.rlim_max = rlimit_resource_value(rlim_max);
5822 if (setrlimit(rlimit_resource_type(resource), &rlim) < 0) {
5828#define proc_setrlimit rb_f_notimplement
5831static int under_uid_switch = 0;
5833check_uid_switch(
void)
5835 if (under_uid_switch) {
5840static int under_gid_switch = 0;
5842check_gid_switch(
void)
5844 if (under_gid_switch) {
5850#if defined(HAVE_PWD_H)
5859#if ( !defined(USE_GETLOGIN_R) && !defined(USE_GETLOGIN) )
5862 char MAYBE_UNUSED(*login) = NULL;
5864# ifdef USE_GETLOGIN_R
5866#if defined(__FreeBSD__)
5867 typedef int getlogin_r_size_t;
5869 typedef size_t getlogin_r_size_t;
5872 long loginsize = GETLOGIN_R_SIZE_INIT;
5875 loginsize = GETLOGIN_R_SIZE_DEFAULT;
5879 login = RSTRING_PTR(maybe_result);
5885 while ((gle = getlogin_r(login, (getlogin_r_size_t)loginsize)) != 0) {
5887 if (gle == ENOTTY || gle == ENXIO || gle == ENOENT) {
5892 if (gle != ERANGE || loginsize >= GETLOGIN_R_SIZE_LIMIT) {
5898 login = RSTRING_PTR(maybe_result);
5902 if (login == NULL) {
5907 return maybe_result;
5914 if (errno == ENOTTY || errno == ENXIO || errno == ENOENT) {
5927rb_getpwdirnam_for_login(
VALUE login_name)
5929#if ( !defined(USE_GETPWNAM_R) && !defined(USE_GETPWNAM) )
5933 if (
NIL_P(login_name)) {
5938 char *login = RSTRING_PTR(login_name);
5940 struct passwd *pwptr;
5942# ifdef USE_GETPWNAM_R
5944 struct passwd pwdnm;
5946 long bufsizenm = GETPW_R_SIZE_INIT;
5949 bufsizenm = GETPW_R_SIZE_DEFAULT;
5953 bufnm = RSTRING_PTR(getpwnm_tmp);
5959 while ((enm = getpwnam_r(login, &pwdnm, bufnm, bufsizenm, &pwptr)) != 0) {
5961 if (enm == ENOENT || enm== ESRCH || enm == EBADF || enm == EPERM) {
5967 if (enm != ERANGE || bufsizenm >= GETPW_R_SIZE_LIMIT) {
5973 bufnm = RSTRING_PTR(getpwnm_tmp);
5977 if (pwptr == NULL) {
5991 pwptr = getpwnam(login);
5998 && ( errno != ENOENT && errno != ESRCH && errno != EBADF && errno != EPERM)) {
6014# if !defined(USE_GETPWUID_R) && !defined(USE_GETPWUID)
6018 uid_t ruid = getuid();
6020 struct passwd *pwptr;
6022# ifdef USE_GETPWUID_R
6024 struct passwd pwdid;
6026 long bufsizeid = GETPW_R_SIZE_INIT;
6029 bufsizeid = GETPW_R_SIZE_DEFAULT;
6033 bufid = RSTRING_PTR(getpwid_tmp);
6039 while ((eid = getpwuid_r(ruid, &pwdid, bufid, bufsizeid, &pwptr)) != 0) {
6041 if (eid == ENOENT || eid== ESRCH || eid == EBADF || eid == EPERM) {
6047 if (eid != ERANGE || bufsizeid >= GETPW_R_SIZE_LIMIT) {
6053 bufid = RSTRING_PTR(getpwid_tmp);
6057 if (pwptr == NULL) {
6068# elif defined(USE_GETPWUID)
6071 pwptr = getpwuid(ruid);
6078 && ( errno == ENOENT || errno == ESRCH || errno == EBADF || errno == EPERM)) {
6100#if defined(HAVE_PWD_H)
6103# ifdef USE_GETPWNAM_R
6116 struct passwd *pwptr;
6117#ifdef USE_GETPWNAM_R
6118 struct passwd pwbuf;
6123 getpw_buf_len = GETPW_R_SIZE_INIT;
6124 if (getpw_buf_len < 0) getpw_buf_len = GETPW_R_SIZE_DEFAULT;
6127 getpw_buf = RSTRING_PTR(*getpw_tmp);
6131 while ((e = getpwnam_r(usrname, &pwbuf, getpw_buf, getpw_buf_len, &pwptr)) != 0) {
6132 if (e != ERANGE || getpw_buf_len >= GETPW_R_SIZE_LIMIT) {
6137 getpw_buf = RSTRING_PTR(*getpw_tmp);
6141 pwptr = getpwnam(usrname);
6144#ifndef USE_GETPWNAM_R
6149 uid = pwptr->pw_uid;
6150#ifndef USE_GETPWNAM_R
6157# ifdef p_uid_from_name
6177#if defined(HAVE_GRP_H)
6180# ifdef USE_GETGRNAM_R
6193 struct group *grptr;
6194#ifdef USE_GETGRNAM_R
6200 getgr_buf_len = GETGR_R_SIZE_INIT;
6201 if (getgr_buf_len < 0) getgr_buf_len = GETGR_R_SIZE_DEFAULT;
6204 getgr_buf = RSTRING_PTR(*getgr_tmp);
6208 while ((e = getgrnam_r(grpname, &grbuf, getgr_buf, getgr_buf_len, &grptr)) != 0) {
6209 if (e != ERANGE || getgr_buf_len >= GETGR_R_SIZE_LIMIT) {
6214 getgr_buf = RSTRING_PTR(*getgr_tmp);
6217#elif defined(HAVE_GETGRNAM)
6218 grptr = getgrnam(grpname);
6223#if !defined(USE_GETGRNAM_R) && defined(HAVE_ENDGRENT)
6228 gid = grptr->gr_gid;
6229#if !defined(USE_GETGRNAM_R) && defined(HAVE_ENDGRENT)
6236# ifdef p_gid_from_name
6256#if defined HAVE_SETUID
6274#define p_sys_setuid rb_f_notimplement
6278#if defined HAVE_SETRUID
6296#define p_sys_setruid rb_f_notimplement
6300#if defined HAVE_SETEUID
6318#define p_sys_seteuid rb_f_notimplement
6322#if defined HAVE_SETREUID
6337 rb_uid_t ruid, euid;
6340 ruid = OBJ2UID1(rid);
6341 euid = OBJ2UID1(eid);
6347#define p_sys_setreuid rb_f_notimplement
6351#if defined HAVE_SETRESUID
6366 rb_uid_t ruid, euid, suid;
6369 ruid = OBJ2UID1(rid);
6370 euid = OBJ2UID1(eid);
6371 suid = OBJ2UID1(sid);
6373 if (setresuid(ruid, euid, suid) != 0)
rb_sys_fail(0);
6377#define p_sys_setresuid rb_f_notimplement
6393proc_getuid(
VALUE obj)
6395 rb_uid_t uid = getuid();
6400#if defined(HAVE_SETRESUID) || defined(HAVE_SETREUID) || defined(HAVE_SETRUID) || defined(HAVE_SETUID)
6417#if defined(HAVE_SETRESUID)
6419#elif defined HAVE_SETREUID
6421#elif defined HAVE_SETRUID
6423#elif defined HAVE_SETUID
6425 if (geteuid() == uid) {
6436#define proc_setuid rb_f_notimplement
6450static rb_uid_t SAVED_USER_ID = -1;
6452#ifdef BROKEN_SETREUID
6454setreuid(rb_uid_t ruid, rb_uid_t euid)
6456 if (ruid != (rb_uid_t)-1 && ruid != getuid()) {
6457 if (euid == (rb_uid_t)-1) euid = geteuid();
6458 if (setuid(ruid) < 0)
return -1;
6460 if (euid != (rb_uid_t)-1 && euid != geteuid()) {
6461 if (seteuid(euid) < 0)
return -1;
6489 if (geteuid() == 0) {
6490#if defined(HAVE_SETRESUID)
6492 SAVED_USER_ID = uid;
6493#elif defined(HAVE_SETUID)
6495 SAVED_USER_ID = uid;
6496#elif defined(HAVE_SETREUID) && !defined(OBSOLETE_SETREUID)
6497 if (getuid() == uid) {
6498 if (SAVED_USER_ID == uid) {
6503 if (setreuid(-1, SAVED_USER_ID) < 0)
rb_sys_fail(0);
6504 if (setreuid(SAVED_USER_ID, 0) < 0)
rb_sys_fail(0);
6507 SAVED_USER_ID = uid;
6513 SAVED_USER_ID = uid;
6519 SAVED_USER_ID = uid;
6521#elif defined(HAVE_SETRUID) && defined(HAVE_SETEUID)
6522 if (getuid() == uid) {
6523 if (SAVED_USER_ID == uid) {
6537 SAVED_USER_ID = uid;
6544 SAVED_USER_ID = uid;
6552#if defined(HAVE_SETRESUID)
6553 if (setresuid((getuid() == uid)? (rb_uid_t)-1: uid,
6554 (geteuid() == uid)? (rb_uid_t)-1: uid,
6555 (SAVED_USER_ID == uid)? (rb_uid_t)-1: uid) < 0)
rb_sys_fail(0);
6556 SAVED_USER_ID = uid;
6557#elif defined(HAVE_SETREUID) && !defined(OBSOLETE_SETREUID)
6558 if (SAVED_USER_ID == uid) {
6559 if (setreuid((getuid() == uid)? (rb_uid_t)-1: uid,
6560 (geteuid() == uid)? (rb_uid_t)-1: uid) < 0)
6563 else if (getuid() != uid) {
6564 if (setreuid(uid, (geteuid() == uid)? (rb_uid_t)-1: uid) < 0)
6566 SAVED_USER_ID = uid;
6568 else if ( geteuid() != uid) {
6570 SAVED_USER_ID = uid;
6574 if (setreuid(-1, SAVED_USER_ID) < 0)
rb_sys_fail(0);
6575 if (setreuid(SAVED_USER_ID, uid) < 0)
rb_sys_fail(0);
6576 SAVED_USER_ID = uid;
6579#elif defined(HAVE_SETRUID) && defined(HAVE_SETEUID)
6580 if (SAVED_USER_ID == uid) {
6581 if (geteuid() != uid && seteuid(uid) < 0)
rb_sys_fail(0);
6582 if (getuid() != uid && setruid(uid) < 0)
rb_sys_fail(0);
6584 else if ( geteuid() == uid) {
6585 if (getuid() != uid) {
6587 SAVED_USER_ID = uid;
6591 SAVED_USER_ID = uid;
6595 else if ( getuid() == uid) {
6598 SAVED_USER_ID = uid;
6604#elif defined HAVE_44BSD_SETUID
6605 if (getuid() == uid) {
6608 SAVED_USER_ID = uid;
6613#elif defined HAVE_SETEUID
6614 if (getuid() == uid && SAVED_USER_ID == uid) {
6620#elif defined HAVE_SETUID
6621 if (getuid() == uid && SAVED_USER_ID == uid) {
6636#if defined HAVE_SETGID
6654#define p_sys_setgid rb_f_notimplement
6658#if defined HAVE_SETRGID
6676#define p_sys_setrgid rb_f_notimplement
6680#if defined HAVE_SETEGID
6698#define p_sys_setegid rb_f_notimplement
6702#if defined HAVE_SETREGID
6717 rb_gid_t rgid, egid;
6719 rgid = OBJ2GID(rid);
6720 egid = OBJ2GID(eid);
6725#define p_sys_setregid rb_f_notimplement
6728#if defined HAVE_SETRESGID
6743 rb_gid_t rgid, egid, sgid;
6745 rgid = OBJ2GID(rid);
6746 egid = OBJ2GID(eid);
6747 sgid = OBJ2GID(sid);
6748 if (setresgid(rgid, egid, sgid) != 0)
rb_sys_fail(0);
6752#define p_sys_setresgid rb_f_notimplement
6756#if defined HAVE_ISSETUGID
6770p_sys_issetugid(
VALUE obj)
6772 return RBOOL(issetugid());
6775#define p_sys_issetugid rb_f_notimplement
6791proc_getgid(
VALUE obj)
6793 rb_gid_t gid = getgid();
6798#if defined(HAVE_SETRESGID) || defined(HAVE_SETREGID) || defined(HAVE_SETRGID) || defined(HAVE_SETGID)
6814#if defined(HAVE_SETRESGID)
6816#elif defined HAVE_SETREGID
6818#elif defined HAVE_SETRGID
6820#elif defined HAVE_SETGID
6822 if (getegid() == gid) {
6833#define proc_setgid rb_f_notimplement
6837#if defined(_SC_NGROUPS_MAX) || defined(NGROUPS_MAX)
6857static int _maxgroups = -1;
6859get_sc_ngroups_max(
void)
6861#ifdef _SC_NGROUPS_MAX
6862 return (
int)sysconf(_SC_NGROUPS_MAX);
6863#elif defined(NGROUPS_MAX)
6864 return (
int)NGROUPS_MAX;
6872 if (_maxgroups < 0) {
6873 _maxgroups = get_sc_ngroups_max();
6875 _maxgroups = RB_MAX_GROUPS;
6884#ifdef HAVE_GETGROUPS
6911proc_getgroups(
VALUE obj)
6917 ngroups = getgroups(0, NULL);
6921 groups =
ALLOCV_N(rb_gid_t, tmp, ngroups);
6923 ngroups = getgroups(ngroups, groups);
6928 for (i = 0; i < ngroups; i++)
6929 rb_ary_push(ary,
GIDT2NUM(groups[i]));
6936#define proc_getgroups rb_f_notimplement
6940#ifdef HAVE_SETGROUPS
6964 ngroups = RARRAY_LENINT(ary);
6965 if (ngroups > maxgroups())
6968 groups =
ALLOCV_N(rb_gid_t, tmp, ngroups);
6970 for (i = 0; i < ngroups; i++) {
6973 groups[i] = OBJ2GID1(g);
6977 if (setgroups(ngroups, groups) == -1)
6982 return proc_getgroups(obj);
6985#define proc_setgroups rb_f_notimplement
6989#ifdef HAVE_INITGROUPS
7013 return proc_getgroups(obj);
7016#define proc_initgroups rb_f_notimplement
7019#if defined(_SC_NGROUPS_MAX) || defined(NGROUPS_MAX)
7031proc_getmaxgroups(
VALUE obj)
7036#define proc_getmaxgroups rb_f_notimplement
7039#ifdef HAVE_SETGROUPS
7052 int ngroups_max = get_sc_ngroups_max();
7057 if (ngroups > RB_MAX_GROUPS)
7058 ngroups = RB_MAX_GROUPS;
7060 if (ngroups_max > 0 && ngroups > ngroups_max)
7061 ngroups = ngroups_max;
7063 _maxgroups = ngroups;
7068#define proc_setmaxgroups rb_f_notimplement
7071#if defined(HAVE_DAEMON) || (defined(HAVE_WORKING_FORK) && defined(HAVE_SETSID))
7072static int rb_daemon(
int nochdir,
int noclose);
7091 int n, nochdir = FALSE, noclose = FALSE;
7093 switch (rb_check_arity(argc, 0, 2)) {
7094 case 2: noclose = TO_BOOL(argv[1],
"noclose");
7095 case 1: nochdir = TO_BOOL(argv[0],
"nochdir");
7099 n = rb_daemon(nochdir, noclose);
7105rb_daemon(
int nochdir,
int noclose)
7109 if (mjit_enabled) mjit_pause(
false);
7111 err = daemon(nochdir, noclose);
7117 switch (rb_fork_ruby(NULL)) {
7120 default: _exit(EXIT_SUCCESS);
7124 if (setsid() < 0) (void)0;
7129 if (!noclose && (n =
rb_cloexec_open(
"/dev/null", O_RDWR, 0)) != -1) {
7141#define proc_daemon rb_f_notimplement
7154static rb_gid_t SAVED_GROUP_ID = -1;
7156#ifdef BROKEN_SETREGID
7158setregid(rb_gid_t rgid, rb_gid_t egid)
7160 if (rgid != (rb_gid_t)-1 && rgid != getgid()) {
7161 if (egid == (rb_gid_t)-1) egid = getegid();
7162 if (setgid(rgid) < 0)
return -1;
7164 if (egid != (rb_gid_t)-1 && egid != getegid()) {
7165 if (setegid(egid) < 0)
return -1;
7193 if (geteuid() == 0) {
7194#if defined(HAVE_SETRESGID)
7196 SAVED_GROUP_ID = gid;
7197#elif defined HAVE_SETGID
7199 SAVED_GROUP_ID = gid;
7200#elif defined(HAVE_SETREGID) && !defined(OBSOLETE_SETREGID)
7201 if (getgid() == gid) {
7202 if (SAVED_GROUP_ID == gid) {
7207 if (setregid(-1, SAVED_GROUP_ID) < 0)
rb_sys_fail(0);
7208 if (setregid(SAVED_GROUP_ID, 0) < 0)
rb_sys_fail(0);
7211 SAVED_GROUP_ID = gid;
7217 SAVED_GROUP_ID = gid;
7223 SAVED_GROUP_ID = gid;
7225#elif defined(HAVE_SETRGID) && defined (HAVE_SETEGID)
7226 if (getgid() == gid) {
7227 if (SAVED_GROUP_ID == gid) {
7242 SAVED_GROUP_ID = gid;
7249 SAVED_GROUP_ID = gid;
7256#if defined(HAVE_SETRESGID)
7257 if (setresgid((getgid() == gid)? (rb_gid_t)-1: gid,
7258 (getegid() == gid)? (rb_gid_t)-1: gid,
7259 (SAVED_GROUP_ID == gid)? (rb_gid_t)-1: gid) < 0)
rb_sys_fail(0);
7260 SAVED_GROUP_ID = gid;
7261#elif defined(HAVE_SETREGID) && !defined(OBSOLETE_SETREGID)
7262 if (SAVED_GROUP_ID == gid) {
7263 if (setregid((getgid() == gid)? (rb_uid_t)-1: gid,
7264 (getegid() == gid)? (rb_uid_t)-1: gid) < 0)
7267 else if (getgid() != gid) {
7268 if (setregid(gid, (getegid() == gid)? (rb_uid_t)-1: gid) < 0)
7270 SAVED_GROUP_ID = gid;
7272 else if ( getegid() != gid) {
7274 SAVED_GROUP_ID = gid;
7278 if (setregid(-1, SAVED_GROUP_ID) < 0)
rb_sys_fail(0);
7279 if (setregid(SAVED_GROUP_ID, gid) < 0)
rb_sys_fail(0);
7280 SAVED_GROUP_ID = gid;
7283#elif defined(HAVE_SETRGID) && defined(HAVE_SETEGID)
7284 if (SAVED_GROUP_ID == gid) {
7285 if (getegid() != gid && setegid(gid) < 0)
rb_sys_fail(0);
7286 if (getgid() != gid && setrgid(gid) < 0)
rb_sys_fail(0);
7288 else if ( getegid() == gid) {
7289 if (getgid() != gid) {
7291 SAVED_GROUP_ID = gid;
7295 SAVED_GROUP_ID = gid;
7299 else if ( getgid() == gid) {
7302 SAVED_GROUP_ID = gid;
7308#elif defined HAVE_44BSD_SETGID
7309 if (getgid() == gid) {
7312 SAVED_GROUP_ID = gid;
7317#elif defined HAVE_SETEGID
7318 if (getgid() == gid && SAVED_GROUP_ID == gid) {
7324#elif defined HAVE_SETGID
7325 if (getgid() == gid && SAVED_GROUP_ID == gid) {
7352proc_geteuid(
VALUE obj)
7354 rb_uid_t euid = geteuid();
7358#if defined(HAVE_SETRESUID) || defined(HAVE_SETREUID) || defined(HAVE_SETEUID) || defined(HAVE_SETUID) || defined(_POSIX_SAVED_IDS)
7360proc_seteuid(rb_uid_t uid)
7362#if defined(HAVE_SETRESUID)
7364#elif defined HAVE_SETREUID
7366#elif defined HAVE_SETEUID
7368#elif defined HAVE_SETUID
7369 if (uid == getuid()) {
7381#if defined(HAVE_SETRESUID) || defined(HAVE_SETREUID) || defined(HAVE_SETEUID) || defined(HAVE_SETUID)
7394 proc_seteuid(OBJ2UID(euid));
7398#define proc_seteuid_m rb_f_notimplement
7402rb_seteuid_core(rb_uid_t euid)
7404#if defined(HAVE_SETRESUID) || (defined(HAVE_SETREUID) && !defined(OBSOLETE_SETREUID))
7410#if defined(HAVE_SETRESUID) || (defined(HAVE_SETREUID) && !defined(OBSOLETE_SETREUID))
7414#if defined(HAVE_SETRESUID)
7417 SAVED_USER_ID = euid;
7422#elif defined(HAVE_SETREUID) && !defined(OBSOLETE_SETREUID)
7427 SAVED_USER_ID = euid;
7429#elif defined HAVE_SETEUID
7431#elif defined HAVE_SETUID
7458 rb_seteuid_core(OBJ2UID(
id));
7476proc_getegid(
VALUE obj)
7478 rb_gid_t egid = getegid();
7483#if defined(HAVE_SETRESGID) || defined(HAVE_SETREGID) || defined(HAVE_SETEGID) || defined(HAVE_SETGID) || defined(_POSIX_SAVED_IDS)
7495#if defined(HAVE_SETRESGID) || defined(HAVE_SETREGID) || defined(HAVE_SETEGID) || defined(HAVE_SETGID)
7501#if defined(HAVE_SETRESGID) || defined(HAVE_SETREGID) || defined(HAVE_SETEGID) || defined(HAVE_SETGID)
7502 gid = OBJ2GID(egid);
7505#if defined(HAVE_SETRESGID)
7507#elif defined HAVE_SETREGID
7509#elif defined HAVE_SETEGID
7511#elif defined HAVE_SETGID
7512 if (gid == getgid()) {
7525#if defined(HAVE_SETRESGID) || defined(HAVE_SETREGID) || defined(HAVE_SETEGID) || defined(HAVE_SETGID)
7526#define proc_setegid_m proc_setegid
7528#define proc_setegid_m rb_f_notimplement
7532rb_setegid_core(rb_gid_t egid)
7534#if defined(HAVE_SETRESGID) || (defined(HAVE_SETREGID) && !defined(OBSOLETE_SETREGID))
7540#if defined(HAVE_SETRESGID) || (defined(HAVE_SETREGID) && !defined(OBSOLETE_SETREGID))
7544#if defined(HAVE_SETRESGID)
7547 SAVED_GROUP_ID = egid;
7552#elif defined(HAVE_SETREGID) && !defined(OBSOLETE_SETREGID)
7557 SAVED_GROUP_ID = egid;
7559#elif defined HAVE_SETEGID
7561#elif defined HAVE_SETGID
7588 rb_setegid_core(OBJ2GID(
id));
7603p_uid_exchangeable(
VALUE _)
7605#if defined(HAVE_SETRESUID)
7607#elif defined(HAVE_SETREUID) && !defined(OBSOLETE_SETREUID)
7628p_uid_exchange(
VALUE obj)
7631#if defined(HAVE_SETRESUID) || (defined(HAVE_SETREUID) && !defined(OBSOLETE_SETREUID))
7638#if defined(HAVE_SETRESUID) || (defined(HAVE_SETREUID) && !defined(OBSOLETE_SETREUID))
7642#if defined(HAVE_SETRESUID)
7643 if (setresuid(euid, uid, uid) < 0)
rb_sys_fail(0);
7644 SAVED_USER_ID = uid;
7645#elif defined(HAVE_SETREUID) && !defined(OBSOLETE_SETREUID)
7647 SAVED_USER_ID = uid;
7665p_gid_exchangeable(
VALUE _)
7667#if defined(HAVE_SETRESGID)
7669#elif defined(HAVE_SETREGID) && !defined(OBSOLETE_SETREGID)
7690p_gid_exchange(
VALUE obj)
7693#if defined(HAVE_SETRESGID) || (defined(HAVE_SETREGID) && !defined(OBSOLETE_SETREGID))
7700#if defined(HAVE_SETRESGID) || (defined(HAVE_SETREGID) && !defined(OBSOLETE_SETREGID))
7704#if defined(HAVE_SETRESGID)
7705 if (setresgid(egid, gid, gid) < 0)
rb_sys_fail(0);
7706 SAVED_GROUP_ID = gid;
7707#elif defined(HAVE_SETREGID) && !defined(OBSOLETE_SETREGID)
7709 SAVED_GROUP_ID = gid;
7728p_uid_have_saved_id(
VALUE _)
7730#if defined(HAVE_SETRESUID) || defined(HAVE_SETEUID) || defined(_POSIX_SAVED_IDS)
7738#if defined(HAVE_SETRESUID) || defined(HAVE_SETEUID) || defined(_POSIX_SAVED_IDS)
7740p_uid_sw_ensure(
VALUE i)
7742 rb_uid_t
id = (rb_uid_t)i;
7743 under_uid_switch = 0;
7744 id = rb_seteuid_core(
id);
7763p_uid_switch(
VALUE obj)
7775 under_uid_switch = 1;
7782 else if (euid != SAVED_USER_ID) {
7783 proc_seteuid(SAVED_USER_ID);
7785 under_uid_switch = 1;
7800p_uid_sw_ensure(
VALUE obj)
7802 under_uid_switch = 0;
7803 return p_uid_exchange(obj);
7807p_uid_switch(
VALUE obj)
7819 p_uid_exchange(obj);
7821 under_uid_switch = 1;
7843p_gid_have_saved_id(
VALUE _)
7845#if defined(HAVE_SETRESGID) || defined(HAVE_SETEGID) || defined(_POSIX_SAVED_IDS)
7852#if defined(HAVE_SETRESGID) || defined(HAVE_SETEGID) || defined(_POSIX_SAVED_IDS)
7854p_gid_sw_ensure(
VALUE i)
7856 rb_gid_t
id = (rb_gid_t)i;
7857 under_gid_switch = 0;
7858 id = rb_setegid_core(
id);
7877p_gid_switch(
VALUE obj)
7889 under_gid_switch = 1;
7896 else if (egid != SAVED_GROUP_ID) {
7897 proc_setegid(obj,
GIDT2NUM(SAVED_GROUP_ID));
7899 under_gid_switch = 1;
7914p_gid_sw_ensure(
VALUE obj)
7916 under_gid_switch = 0;
7917 return p_gid_exchange(obj);
7921p_gid_switch(
VALUE obj)
7933 p_gid_exchange(obj);
7935 under_gid_switch = 1;
7945#if defined(HAVE_TIMES)
7949#ifdef HAVE__SC_CLK_TCK
7950 return sysconf(_SC_CLK_TCK);
7951#elif defined CLK_TCK
7973rb_proc_times(
VALUE obj)
7975 VALUE utime, stime, cutime, cstime, ret;
7976#if defined(RUSAGE_SELF) && defined(RUSAGE_CHILDREN)
7977 struct rusage usage_s, usage_c;
7979 if (getrusage(RUSAGE_SELF, &usage_s) != 0 || getrusage(RUSAGE_CHILDREN, &usage_c) != 0)
7981 utime =
DBL2NUM((
double)usage_s.ru_utime.tv_sec + (
double)usage_s.ru_utime.tv_usec/1e6);
7982 stime =
DBL2NUM((
double)usage_s.ru_stime.tv_sec + (
double)usage_s.ru_stime.tv_usec/1e6);
7983 cutime =
DBL2NUM((
double)usage_c.ru_utime.tv_sec + (
double)usage_c.ru_utime.tv_usec/1e6);
7984 cstime =
DBL2NUM((
double)usage_c.ru_stime.tv_sec + (
double)usage_c.ru_stime.tv_usec/1e6);
7986 const double hertz = (double)get_clk_tck();
7990 utime =
DBL2NUM(buf.tms_utime / hertz);
7991 stime =
DBL2NUM(buf.tms_stime / hertz);
7992 cutime =
DBL2NUM(buf.tms_cutime / hertz);
7993 cstime =
DBL2NUM(buf.tms_cstime / hertz);
7995 ret =
rb_struct_new(rb_cProcessTms, utime, stime, cutime, cstime);
8003#define rb_proc_times rb_f_notimplement
8006#ifdef HAVE_LONG_LONG
8008#define TIMETICK_INT_MIN LLONG_MIN
8009#define TIMETICK_INT_MAX LLONG_MAX
8010#define TIMETICK_INT2NUM(v) LL2NUM(v)
8011#define MUL_OVERFLOW_TIMETICK_P(a, b) MUL_OVERFLOW_LONG_LONG_P(a, b)
8013typedef long timetick_int_t;
8014#define TIMETICK_INT_MIN LONG_MIN
8015#define TIMETICK_INT_MAX LONG_MAX
8016#define TIMETICK_INT2NUM(v) LONG2NUM(v)
8017#define MUL_OVERFLOW_TIMETICK_P(a, b) MUL_OVERFLOW_LONG_P(a, b)
8020CONSTFUNC(
static timetick_int_t gcd_timetick_int(timetick_int_t, timetick_int_t));
8021static timetick_int_t
8022gcd_timetick_int(timetick_int_t a, timetick_int_t b)
8042reduce_fraction(timetick_int_t *np, timetick_int_t *dp)
8044 timetick_int_t gcd = gcd_timetick_int(*np, *dp);
8052reduce_factors(timetick_int_t *numerators,
int num_numerators,
8053 timetick_int_t *denominators,
int num_denominators)
8056 for (i = 0; i < num_numerators; i++) {
8057 if (numerators[i] == 1)
8059 for (j = 0; j < num_denominators; j++) {
8060 if (denominators[j] == 1)
8062 reduce_fraction(&numerators[i], &denominators[j]);
8068 timetick_int_t giga_count;
8073timetick2dblnum(
struct timetick *ttp,
8074 timetick_int_t *numerators,
int num_numerators,
8075 timetick_int_t *denominators,
int num_denominators)
8080 reduce_factors(numerators, num_numerators,
8081 denominators, num_denominators);
8083 d = ttp->giga_count * 1e9 + ttp->count;
8085 for (i = 0; i < num_numerators; i++)
8087 for (i = 0; i < num_denominators; i++)
8088 d /= denominators[i];
8094timetick2dblnum_reciprocal(
struct timetick *ttp,
8095 timetick_int_t *numerators,
int num_numerators,
8096 timetick_int_t *denominators,
int num_denominators)
8101 reduce_factors(numerators, num_numerators,
8102 denominators, num_denominators);
8105 for (i = 0; i < num_denominators; i++)
8106 d *= denominators[i];
8107 for (i = 0; i < num_numerators; i++)
8109 d /= ttp->giga_count * 1e9 + ttp->count;
8114#define NDIV(x,y) (-(-((x)+1)/(y))-1)
8115#define DIV(n,d) ((n)<0 ? NDIV((n),(d)) : (n)/(d))
8118timetick2integer(
struct timetick *ttp,
8119 timetick_int_t *numerators,
int num_numerators,
8120 timetick_int_t *denominators,
int num_denominators)
8125 reduce_factors(numerators, num_numerators,
8126 denominators, num_denominators);
8128 if (!MUL_OVERFLOW_SIGNED_INTEGER_P(1000000000, ttp->giga_count,
8129 TIMETICK_INT_MIN, TIMETICK_INT_MAX-ttp->count)) {
8130 timetick_int_t t = ttp->giga_count * 1000000000 + ttp->count;
8131 for (i = 0; i < num_numerators; i++) {
8132 timetick_int_t factor = numerators[i];
8133 if (MUL_OVERFLOW_TIMETICK_P(factor, t))
8137 for (i = 0; i < num_denominators; i++) {
8138 t = DIV(t, denominators[i]);
8140 return TIMETICK_INT2NUM(t);
8144 v = TIMETICK_INT2NUM(ttp->giga_count);
8145 v = rb_funcall(v,
'*', 1,
LONG2FIX(1000000000));
8146 v = rb_funcall(v,
'+', 1,
LONG2FIX(ttp->count));
8147 for (i = 0; i < num_numerators; i++) {
8148 timetick_int_t factor = numerators[i];
8151 v = rb_funcall(v,
'*', 1, TIMETICK_INT2NUM(factor));
8153 for (i = 0; i < num_denominators; i++) {
8154 v = rb_funcall(v,
'/', 1, TIMETICK_INT2NUM(denominators[i]));
8160make_clock_result(
struct timetick *ttp,
8161 timetick_int_t *numerators,
int num_numerators,
8162 timetick_int_t *denominators,
int num_denominators,
8165 if (unit ==
ID2SYM(id_nanosecond)) {
8166 numerators[num_numerators++] = 1000000000;
8167 return timetick2integer(ttp, numerators, num_numerators, denominators, num_denominators);
8169 else if (unit ==
ID2SYM(id_microsecond)) {
8170 numerators[num_numerators++] = 1000000;
8171 return timetick2integer(ttp, numerators, num_numerators, denominators, num_denominators);
8173 else if (unit ==
ID2SYM(id_millisecond)) {
8174 numerators[num_numerators++] = 1000;
8175 return timetick2integer(ttp, numerators, num_numerators, denominators, num_denominators);
8177 else if (unit ==
ID2SYM(id_second)) {
8178 return timetick2integer(ttp, numerators, num_numerators, denominators, num_denominators);
8180 else if (unit ==
ID2SYM(id_float_microsecond)) {
8181 numerators[num_numerators++] = 1000000;
8182 return timetick2dblnum(ttp, numerators, num_numerators, denominators, num_denominators);
8184 else if (unit ==
ID2SYM(id_float_millisecond)) {
8185 numerators[num_numerators++] = 1000;
8186 return timetick2dblnum(ttp, numerators, num_numerators, denominators, num_denominators);
8188 else if (
NIL_P(unit) || unit ==
ID2SYM(id_float_second)) {
8189 return timetick2dblnum(ttp, numerators, num_numerators, denominators, num_denominators);
8196static const mach_timebase_info_data_t *
8197get_mach_timebase_info(
void)
8199 static mach_timebase_info_data_t sTimebaseInfo;
8201 if ( sTimebaseInfo.denom == 0 ) {
8202 (void) mach_timebase_info(&sTimebaseInfo);
8205 return &sTimebaseInfo;
8209ruby_real_ms_time(
void)
8211 const mach_timebase_info_data_t *info = get_mach_timebase_info();
8212 uint64_t t = mach_absolute_time();
8213 return (
double)t * info->numer / info->denom / 1e6;
8217#if defined(NUM2CLOCKID)
8218# define NUMERIC_CLOCKID 1
8220# define NUMERIC_CLOCKID 0
8221# define NUM2CLOCKID(x) 0
8357 timetick_int_t numerators[2];
8358 timetick_int_t denominators[2];
8359 int num_numerators = 0;
8360 int num_denominators = 0;
8362 VALUE unit = (rb_check_arity(argc, 1, 2) == 2) ? argv[1] :
Qnil;
8363 VALUE clk_id = argv[0];
8367#ifdef CLOCK_REALTIME
8368 if (clk_id == RUBY_CLOCK_REALTIME) {
8374#ifdef CLOCK_MONOTONIC
8375 if (clk_id == RUBY_CLOCK_MONOTONIC) {
8376 c = CLOCK_MONOTONIC;
8381#ifdef CLOCK_PROCESS_CPUTIME_ID
8382 if (clk_id == RUBY_CLOCK_PROCESS_CPUTIME_ID) {
8383 c = CLOCK_PROCESS_CPUTIME_ID;
8388#ifdef CLOCK_THREAD_CPUTIME_ID
8389 if (clk_id == RUBY_CLOCK_THREAD_CPUTIME_ID) {
8390 c = CLOCK_THREAD_CPUTIME_ID;
8398#ifdef HAVE_GETTIMEOFDAY
8403#define RUBY_GETTIMEOFDAY_BASED_CLOCK_REALTIME ID2SYM(id_GETTIMEOFDAY_BASED_CLOCK_REALTIME)
8404 if (clk_id == RUBY_GETTIMEOFDAY_BASED_CLOCK_REALTIME) {
8406 ret = gettimeofday(&tv, 0);
8409 tt.giga_count = tv.tv_sec;
8410 tt.count = (int32_t)tv.tv_usec * 1000;
8411 denominators[num_denominators++] = 1000000000;
8416#define RUBY_TIME_BASED_CLOCK_REALTIME ID2SYM(id_TIME_BASED_CLOCK_REALTIME)
8417 if (clk_id == RUBY_TIME_BASED_CLOCK_REALTIME) {
8420 if (t == (time_t)-1)
8424 denominators[num_denominators++] = 1000000000;
8429#define RUBY_TIMES_BASED_CLOCK_MONOTONIC \
8430 ID2SYM(id_TIMES_BASED_CLOCK_MONOTONIC)
8431 if (clk_id == RUBY_TIMES_BASED_CLOCK_MONOTONIC) {
8434 unsigned_clock_t uc;
8436 if (c == (clock_t)-1)
8438 uc = (unsigned_clock_t)c;
8439 tt.count = (int32_t)(uc % 1000000000);
8440 tt.giga_count = (uc / 1000000000);
8441 denominators[num_denominators++] = get_clk_tck();
8447#define RUBY_GETRUSAGE_BASED_CLOCK_PROCESS_CPUTIME_ID \
8448 ID2SYM(id_GETRUSAGE_BASED_CLOCK_PROCESS_CPUTIME_ID)
8449 if (clk_id == RUBY_GETRUSAGE_BASED_CLOCK_PROCESS_CPUTIME_ID) {
8450 struct rusage usage;
8452 ret = getrusage(RUSAGE_SELF, &usage);
8455 tt.giga_count = usage.ru_utime.tv_sec + usage.ru_stime.tv_sec;
8456 usec = (int32_t)(usage.ru_utime.tv_usec + usage.ru_stime.tv_usec);
8457 if (1000000 <= usec) {
8461 tt.count = usec * 1000;
8462 denominators[num_denominators++] = 1000000000;
8468#define RUBY_TIMES_BASED_CLOCK_PROCESS_CPUTIME_ID \
8469 ID2SYM(id_TIMES_BASED_CLOCK_PROCESS_CPUTIME_ID)
8470 if (clk_id == RUBY_TIMES_BASED_CLOCK_PROCESS_CPUTIME_ID) {
8472 unsigned_clock_t utime, stime;
8473 if (times(&buf) == (clock_t)-1)
8475 utime = (unsigned_clock_t)buf.tms_utime;
8476 stime = (unsigned_clock_t)buf.tms_stime;
8477 tt.count = (int32_t)((utime % 1000000000) + (stime % 1000000000));
8478 tt.giga_count = (utime / 1000000000) + (stime / 1000000000);
8479 if (1000000000 <= tt.count) {
8480 tt.count -= 1000000000;
8483 denominators[num_denominators++] = get_clk_tck();
8488#define RUBY_CLOCK_BASED_CLOCK_PROCESS_CPUTIME_ID \
8489 ID2SYM(id_CLOCK_BASED_CLOCK_PROCESS_CPUTIME_ID)
8490 if (clk_id == RUBY_CLOCK_BASED_CLOCK_PROCESS_CPUTIME_ID) {
8492 unsigned_clock_t uc;
8495 if (c == (clock_t)-1)
8497 uc = (unsigned_clock_t)c;
8498 tt.count = (int32_t)(uc % 1000000000);
8499 tt.giga_count = uc / 1000000000;
8500 denominators[num_denominators++] = CLOCKS_PER_SEC;
8505 if (clk_id == RUBY_MACH_ABSOLUTE_TIME_BASED_CLOCK_MONOTONIC) {
8506 const mach_timebase_info_data_t *info = get_mach_timebase_info();
8507 uint64_t t = mach_absolute_time();
8508 tt.count = (int32_t)(t % 1000000000);
8509 tt.giga_count = t / 1000000000;
8510 numerators[num_numerators++] = info->numer;
8511 denominators[num_denominators++] = info->denom;
8512 denominators[num_denominators++] = 1000000000;
8517 else if (NUMERIC_CLOCKID) {
8518#if defined(HAVE_CLOCK_GETTIME)
8520 c = NUM2CLOCKID(clk_id);
8522 ret = clock_gettime(c, &ts);
8525 tt.count = (int32_t)ts.tv_nsec;
8526 tt.giga_count = ts.tv_sec;
8527 denominators[num_denominators++] = 1000000000;
8535 return make_clock_result(&tt, numerators, num_numerators, denominators, num_denominators, unit);
8586 timetick_int_t numerators[2];
8587 timetick_int_t denominators[2];
8588 int num_numerators = 0;
8589 int num_denominators = 0;
8592 VALUE unit = (rb_check_arity(argc, 1, 2) == 2) ? argv[1] :
Qnil;
8593 VALUE clk_id = argv[0];
8596#ifdef CLOCK_REALTIME
8597 if (clk_id == RUBY_CLOCK_REALTIME) {
8603#ifdef CLOCK_MONOTONIC
8604 if (clk_id == RUBY_CLOCK_MONOTONIC) {
8605 c = CLOCK_MONOTONIC;
8610#ifdef CLOCK_PROCESS_CPUTIME_ID
8611 if (clk_id == RUBY_CLOCK_PROCESS_CPUTIME_ID) {
8612 c = CLOCK_PROCESS_CPUTIME_ID;
8617#ifdef CLOCK_THREAD_CPUTIME_ID
8618 if (clk_id == RUBY_CLOCK_THREAD_CPUTIME_ID) {
8619 c = CLOCK_THREAD_CPUTIME_ID;
8624#ifdef RUBY_GETTIMEOFDAY_BASED_CLOCK_REALTIME
8625 if (clk_id == RUBY_GETTIMEOFDAY_BASED_CLOCK_REALTIME) {
8628 denominators[num_denominators++] = 1000000000;
8633#ifdef RUBY_TIME_BASED_CLOCK_REALTIME
8634 if (clk_id == RUBY_TIME_BASED_CLOCK_REALTIME) {
8637 denominators[num_denominators++] = 1000000000;
8642#ifdef RUBY_TIMES_BASED_CLOCK_MONOTONIC
8643 if (clk_id == RUBY_TIMES_BASED_CLOCK_MONOTONIC) {
8646 denominators[num_denominators++] = get_clk_tck();
8651#ifdef RUBY_GETRUSAGE_BASED_CLOCK_PROCESS_CPUTIME_ID
8652 if (clk_id == RUBY_GETRUSAGE_BASED_CLOCK_PROCESS_CPUTIME_ID) {
8655 denominators[num_denominators++] = 1000000000;
8660#ifdef RUBY_TIMES_BASED_CLOCK_PROCESS_CPUTIME_ID
8661 if (clk_id == RUBY_TIMES_BASED_CLOCK_PROCESS_CPUTIME_ID) {
8664 denominators[num_denominators++] = get_clk_tck();
8669#ifdef RUBY_CLOCK_BASED_CLOCK_PROCESS_CPUTIME_ID
8670 if (clk_id == RUBY_CLOCK_BASED_CLOCK_PROCESS_CPUTIME_ID) {
8673 denominators[num_denominators++] = CLOCKS_PER_SEC;
8678#ifdef RUBY_MACH_ABSOLUTE_TIME_BASED_CLOCK_MONOTONIC
8679 if (clk_id == RUBY_MACH_ABSOLUTE_TIME_BASED_CLOCK_MONOTONIC) {
8680 const mach_timebase_info_data_t *info = get_mach_timebase_info();
8683 numerators[num_numerators++] = info->numer;
8684 denominators[num_denominators++] = info->denom;
8685 denominators[num_denominators++] = 1000000000;
8690 else if (NUMERIC_CLOCKID) {
8691#if defined(HAVE_CLOCK_GETRES)
8693 c = NUM2CLOCKID(clk_id);
8695 ret = clock_getres(c, &ts);
8698 tt.count = (int32_t)ts.tv_nsec;
8699 tt.giga_count = ts.tv_sec;
8700 denominators[num_denominators++] = 1000000000;
8708 if (unit ==
ID2SYM(id_hertz)) {
8709 return timetick2dblnum_reciprocal(&tt, numerators, num_numerators, denominators, num_denominators);
8712 return make_clock_result(&tt, numerators, num_numerators, denominators, num_denominators, unit);
8717get_CHILD_STATUS(
ID _x,
VALUE *_y)
8723get_PROCESS_ID(
ID _x,
VALUE *_y)
8771static VALUE rb_mProcUID;
8772static VALUE rb_mProcGID;
8773static VALUE rb_mProcID_Syscall;
8787 rb_gvar_ractor_local(
"$$");
8788 rb_gvar_ractor_local(
"$?");
8843 process_status_dump, process_status_load);
8879#ifdef HAVE_GETPRIORITY
8890#if defined(RLIM2NUM) && defined(RLIM_INFINITY)
8892 VALUE inf = RLIM2NUM(RLIM_INFINITY);
8893#ifdef RLIM_SAVED_MAX
8895 VALUE v = RLIM_INFINITY == RLIM_SAVED_MAX ? inf : RLIM2NUM(RLIM_SAVED_MAX);
8902#ifdef RLIM_SAVED_CUR
8904 VALUE v = RLIM_INFINITY == RLIM_SAVED_CUR ? inf : RLIM2NUM(RLIM_SAVED_CUR);
8945#ifdef RLIMIT_MEMLOCK
8952#ifdef RLIMIT_MSGQUEUE
9018#ifdef RLIMIT_SIGPENDING
9053#if defined(RUBY_CLOCK_REALTIME)
9054#elif defined(RUBY_GETTIMEOFDAY_BASED_CLOCK_REALTIME)
9055# define RUBY_CLOCK_REALTIME RUBY_GETTIMEOFDAY_BASED_CLOCK_REALTIME
9056#elif defined(RUBY_TIME_BASED_CLOCK_REALTIME)
9057# define RUBY_CLOCK_REALTIME RUBY_TIME_BASED_CLOCK_REALTIME
9059#if defined(CLOCK_REALTIME) && defined(CLOCKID2NUM)
9062#elif defined(RUBY_CLOCK_REALTIME)
9066#if defined(RUBY_CLOCK_MONOTONIC)
9067#elif defined(RUBY_MACH_ABSOLUTE_TIME_BASED_CLOCK_MONOTONIC)
9068# define RUBY_CLOCK_MONOTONIC RUBY_MACH_ABSOLUTE_TIME_BASED_CLOCK_MONOTONIC
9070#if defined(CLOCK_MONOTONIC) && defined(CLOCKID2NUM)
9073#elif defined(RUBY_CLOCK_MONOTONIC)
9077#if defined(RUBY_CLOCK_PROCESS_CPUTIME_ID)
9078#elif defined(RUBY_GETRUSAGE_BASED_CLOCK_PROCESS_CPUTIME_ID)
9079# define RUBY_CLOCK_PROCESS_CPUTIME_ID RUBY_GETRUSAGE_BASED_CLOCK_PROCESS_CPUTIME_ID
9081#if defined(CLOCK_PROCESS_CPUTIME_ID) && defined(CLOCKID2NUM)
9084#elif defined(RUBY_CLOCK_PROCESS_CPUTIME_ID)
9088#if defined(CLOCK_THREAD_CPUTIME_ID) && defined(CLOCKID2NUM)
9091#elif defined(RUBY_CLOCK_THREAD_CPUTIME_ID)
9104#ifdef CLOCK_REALTIME_FAST
9108#ifdef CLOCK_REALTIME_PRECISE
9112#ifdef CLOCK_REALTIME_COARSE
9116#ifdef CLOCK_REALTIME_ALARM
9120#ifdef CLOCK_MONOTONIC_FAST
9124#ifdef CLOCK_MONOTONIC_PRECISE
9128#ifdef CLOCK_MONOTONIC_RAW
9132#ifdef CLOCK_MONOTONIC_RAW_APPROX
9136#ifdef CLOCK_MONOTONIC_COARSE
9140#ifdef CLOCK_BOOTTIME
9144#ifdef CLOCK_BOOTTIME_ALARM
9152#ifdef CLOCK_UPTIME_FAST
9156#ifdef CLOCK_UPTIME_PRECISE
9160#ifdef CLOCK_UPTIME_RAW
9164#ifdef CLOCK_UPTIME_RAW_APPROX
9180#if defined(HAVE_TIMES) || defined(_WIN32)
9194 SAVED_USER_ID = geteuid();
9195 SAVED_GROUP_ID = getegid();
9218#ifdef p_uid_from_name
9221#ifdef p_gid_from_name
9252#define define_id(name) id_##name = rb_intern_const(#name)
9265 define_id(new_pgroup);
9267 define_id(unsetenv_others);
9270 define_id(close_others);
9271 define_id(nanosecond);
9272 define_id(microsecond);
9273 define_id(millisecond);
9275 define_id(float_microsecond);
9276 define_id(float_millisecond);
9277 define_id(float_second);
9278 define_id(GETTIMEOFDAY_BASED_CLOCK_REALTIME);
9279 define_id(TIME_BASED_CLOCK_REALTIME);
9280#ifdef CLOCK_REALTIME
9281 define_id(CLOCK_REALTIME);
9283#ifdef CLOCK_MONOTONIC
9284 define_id(CLOCK_MONOTONIC);
9286#ifdef CLOCK_PROCESS_CPUTIME_ID
9287 define_id(CLOCK_PROCESS_CPUTIME_ID);
9289#ifdef CLOCK_THREAD_CPUTIME_ID
9290 define_id(CLOCK_THREAD_CPUTIME_ID);
9293 define_id(TIMES_BASED_CLOCK_MONOTONIC);
9294 define_id(TIMES_BASED_CLOCK_PROCESS_CPUTIME_ID);
9297 define_id(GETRUSAGE_BASED_CLOCK_PROCESS_CPUTIME_ID);
9299 define_id(CLOCK_BASED_CLOCK_PROCESS_CPUTIME_ID);
9301 define_id(MACH_ABSOLUTE_TIME_BASED_CLOCK_MONOTONIC);
#define rb_define_method(klass, mid, func, arity)
Defines klass#mid.
#define rb_define_singleton_method(klass, mid, func, arity)
Defines klass.mid.
#define rb_define_module_function(klass, mid, func, arity)
Defines klass#mid and makes it a module function.
#define rb_define_global_function(mid, func, arity)
Defines rb_mKernel #mid.
#define GIDT2NUM
Converts a C's gid_t into an instance of rb_cInteger.
#define NUM2GIDT
Converts an instance of rb_cNumeric into C's gid_t.
VALUE rb_singleton_class(VALUE obj)
Finds or creates the singleton class of the passed object.
VALUE rb_define_class_under(VALUE outer, const char *name, VALUE super)
Defines a class under the namespace of outer.
VALUE rb_define_module(const char *name)
Defines a top-level module.
VALUE rb_define_module_under(VALUE outer, const char *name)
Defines a module under the namespace of outer.
void rb_define_alias(VALUE klass, const char *name1, const char *name2)
Defines an alias of a method.
void rb_define_attr(VALUE klass, const char *name, int read, int write)
Defines public accessor method(s) for an attribute.
void rb_undef_method(VALUE klass, const char *name)
Defines an undef of a method.
int rb_block_given_p(void)
Determines if the current method is given a block.
#define rb_str_new2
Old name of rb_str_new_cstr.
#define TYPE(_)
Old name of rb_type.
#define T_FILE
Old name of RUBY_T_FILE.
#define rb_str_buf_cat2
Old name of rb_usascii_str_new_cstr.
#define T_STRING
Old name of RUBY_T_STRING.
#define Qundef
Old name of RUBY_Qundef.
#define INT2FIX
Old name of RB_INT2FIX.
#define rb_str_cat2
Old name of rb_str_cat_cstr.
#define ISUPPER
Old name of rb_isupper.
#define ID2SYM
Old name of RB_ID2SYM.
#define T_BIGNUM
Old name of RUBY_T_BIGNUM.
#define T_FIXNUM
Old name of RUBY_T_FIXNUM.
#define UNREACHABLE_RETURN
Old name of RBIMPL_UNREACHABLE_RETURN.
#define CLASS_OF
Old name of rb_class_of.
#define LONG2FIX
Old name of RB_INT2FIX.
#define FIX2INT
Old name of RB_FIX2INT.
#define TOUPPER
Old name of rb_toupper.
#define NUM2UINT
Old name of RB_NUM2UINT.
#define ISLOWER
Old name of rb_islower.
#define rb_ary_new3
Old name of rb_ary_new_from_args.
#define Qtrue
Old name of RUBY_Qtrue.
#define NUM2INT
Old name of RB_NUM2INT.
#define INT2NUM
Old name of RB_INT2NUM.
#define Qnil
Old name of RUBY_Qnil.
#define Qfalse
Old name of RUBY_Qfalse.
#define T_ARRAY
Old name of RUBY_T_ARRAY.
#define NIL_P
Old name of RB_NIL_P.
#define ALLOCV_N
Old name of RB_ALLOCV_N.
#define T_SYMBOL
Old name of RUBY_T_SYMBOL.
#define DBL2NUM
Old name of rb_float_new.
#define FIXNUM_P
Old name of RB_FIXNUM_P.
#define CONST_ID
Old name of RUBY_CONST_ID.
#define ALLOCV_END
Old name of RB_ALLOCV_END.
#define SYMBOL_P
Old name of RB_SYMBOL_P.
void ruby_stop(int ex)
Calls ruby_cleanup() and exits the process.
void rb_notimplement(void)
void rb_raise(VALUE exc, const char *fmt,...)
Exception entry point.
VALUE rb_eNotImpError
NotImplementedError exception.
void rb_exc_raise(VALUE mesg)
Raises an exception in the current thread.
void rb_syserr_fail(int e, const char *mesg)
Raises appropriate exception that represents a C errno.
void rb_bug(const char *fmt,...)
Interpreter panic switch.
VALUE rb_eSystemExit
SystemExit exception.
void rb_sys_fail(const char *mesg)
Converts a C errno into a Ruby exception, then raises it.
void rb_syserr_fail_str(int e, VALUE mesg)
Identical to rb_syserr_fail(), except it takes the message in Ruby's String instead of C's.
VALUE rb_eRuntimeError
RuntimeError exception.
void * rb_check_typeddata(VALUE obj, const rb_data_type_t *data_type)
Identical to rb_typeddata_is_kind_of(), except it raises exceptions instead of returning false.
void rb_warn(const char *fmt,...)
Identical to rb_warning(), except it reports always regardless of runtime -W flag.
VALUE rb_exc_new_str(VALUE etype, VALUE str)
Identical to rb_exc_new_cstr(), except it takes a Ruby's string instead of C's.
VALUE rb_eArgError
ArgumentError exception.
void rb_sys_fail_str(VALUE mesg)
Identical to rb_sys_fail(), except it takes the message in Ruby's String instead of C's.
void rb_exit(int status)
Terminates the current execution context.
VALUE rb_mProcess
Process module.
VALUE rb_class_new_instance(int argc, const VALUE *argv, VALUE klass)
Allocates, then initialises an instance of the given class.
VALUE rb_cThread
Thread class.
VALUE rb_equal(VALUE lhs, VALUE rhs)
This function is an optimised version of calling #==.
VALUE rb_obj_freeze(VALUE obj)
Just calls rb_obj_freeze_inline() inside.
VALUE rb_to_int(VALUE val)
Identical to rb_check_to_int(), except it raises in case of conversion mismatch.
#define RB_OBJ_WRITTEN(old, oldv, young)
Identical to RB_OBJ_WRITE(), except it doesn't write any values, but only a WB declaration.
#define UNLIMITED_ARGUMENTS
This macro is used in conjunction with rb_check_arity().
VALUE rb_f_abort(int argc, const VALUE *argv)
This is similar to rb_f_exit().
VALUE rb_f_exit(int argc, const VALUE *argv)
Identical to rb_exit(), except how arguments are passed.
VALUE rb_io_puts(int argc, const VALUE *argv, VALUE io)
Iterates over the passed array to apply rb_io_write() individually.
int rb_cloexec_dup2(int oldfd, int newfd)
Identical to rb_cloexec_dup(), except you can specify the destination file descriptor.
void rb_update_max_fd(int fd)
Informs the interpreter that the passed fd can be the max.
int rb_cloexec_open(const char *pathname, int flags, mode_t mode)
Opens a file that closes on exec.
void rb_close_before_exec(int lowfd, int maxhint, VALUE noclose_fds)
Closes everything.
int rb_reserved_fd_p(int fd)
Queries if the given FD is reserved or not.
int rb_pipe(int *pipes)
This is an rb_cloexec_pipe() + rb_update_max_fd() combo.
int rb_cloexec_fcntl_dupfd(int fd, int minfd)
Duplicates a file descriptor with closing on exec.
int rb_cloexec_dup(int oldfd)
Identical to rb_cloexec_fcntl_dupfd(), except it implies minfd is 3.
int rb_proc_exec(const char *cmd)
Executes a shell command.
VALUE rb_last_status_get(void)
Queries the "last status", or the $?.
rb_pid_t rb_waitpid(rb_pid_t pid, int *status, int flags)
Waits for a process, with releasing GVL.
rb_pid_t rb_spawn_err(int argc, const VALUE *argv, char *errbuf, size_t buflen)
Identical to rb_spawn(), except you can additionally know the detailed situation in case of abnormal ...
void rb_syswait(rb_pid_t pid)
This is a shorthand of rb_waitpid without status and flags.
VALUE rb_f_exec(int argc, const VALUE *argv)
Replaces the current process by running the given external command.
rb_pid_t rb_spawn(int argc, const VALUE *argv)
Identical to rb_f_exec(), except it spawns a child process instead of replacing the current one.
void rb_last_status_set(int status, rb_pid_t pid)
Sets the "last status", or the $?.
VALUE rb_detach_process(rb_pid_t pid)
"Detaches" a subprocess.
const char * ruby_signal_name(int signo)
Queries the name of the signal.
VALUE rb_f_kill(int argc, const VALUE *argv)
Sends a signal ("kills") to processes.
VALUE rb_str_append(VALUE dst, VALUE src)
Identical to rb_str_buf_append(), except it converts the right hand side before concatenating.
VALUE rb_str_tmp_new(long len)
Allocates a "temporary" string.
VALUE rb_str_subseq(VALUE str, long beg, long len)
Identical to rb_str_substr(), except the numbers are interpreted as byte offsets instead of character...
#define rb_str_new(str, len)
Allocates an instance of rb_cString.
#define rb_str_buf_cat
Just another name of rb_str_cat.
size_t rb_str_capacity(VALUE str)
Queries the capacity of the given string.
VALUE rb_str_new_frozen(VALUE str)
Creates a frozen copy of the string, if necessary.
VALUE rb_str_dup(VALUE str)
Duplicates a string.
void rb_str_set_len(VALUE str, long len)
Overwrites the length of the string.
VALUE rb_check_string_type(VALUE obj)
Try converting an object to its stringised representation using its to_str method,...
#define rb_str_cat_cstr(buf, str)
Identical to rb_str_cat(), except it assumes the passed pointer is a pointer to a C string.
VALUE rb_str_resize(VALUE str, long len)
Overwrites the length of the string.
void rb_str_modify_expand(VALUE str, long capa)
Identical to rb_str_modify(), except it additionally expands the capacity of the receiver.
VALUE rb_str_buf_new(long capa)
Allocates a "string buffer".
#define rb_str_new_cstr(str)
Identical to rb_str_new, except it assumes the passed pointer is a pointer to a C string.
VALUE rb_struct_define_under(VALUE space, const char *name,...)
Identical to rb_struct_define(), except it defines the class under the specified namespace instead of...
VALUE rb_struct_new(VALUE klass,...)
Creates an instance of the given struct.
VALUE rb_thread_local_aref(VALUE thread, ID key)
This badly named function reads from a Fiber local storage.
#define RUBY_UBF_IO
A special UBF for blocking IO operations.
void rb_thread_sleep_forever(void)
Blocks indefinitely.
void rb_thread_wait_for(struct timeval time)
Identical to rb_thread_sleep(), except it takes struct timeval instead.
void rb_thread_check_ints(void)
Checks for interrupts.
void rb_thread_atfork(void)
A pthread_atfork(3posix)-like API.
VALUE rb_thread_local_aset(VALUE thread, ID key, VALUE val)
This badly named function writes to a Fiber local storage.
#define RUBY_UBF_PROCESS
A special UBF for blocking process operations.
void rb_thread_sleep(int sec)
Blocks for the given period of time.
struct timeval rb_time_interval(VALUE num)
Creates a "time interval".
VALUE rb_attr_get(VALUE obj, ID name)
Identical to rb_ivar_get()
VALUE rb_ivar_set(VALUE obj, ID name, VALUE val)
Identical to rb_iv_set(), except it accepts the name as an ID instead of a C string.
void rb_undef_alloc_func(VALUE klass)
Deletes the allocator function of a class.
void rb_define_alloc_func(VALUE klass, rb_alloc_func_t func)
Sets the allocator function of a class.
ID rb_check_id(volatile VALUE *namep)
Detects if the given name is already interned or not.
VALUE rb_sym2str(VALUE id)
Identical to rb_id2str(), except it takes an instance of rb_cSymbol rather than an ID.
void rb_define_const(VALUE klass, const char *name, VALUE val)
Defines a Ruby level constant under a namespace.
int rb_io_modestr_oflags(const char *modestr)
Identical to rb_io_modestr_fmode(), except it returns a mixture of O_ flags.
#define GetOpenFile
This is an old name of RB_IO_POINTER.
VALUE rb_io_check_io(VALUE io)
Try converting an object to its IO representation using its to_io method, if any.
VALUE rb_ractor_stderr(void)
Queries the standard error of the current Ractor that is calling this function.
void * rb_thread_call_without_gvl2(void *(*func)(void *), void *data1, rb_unblock_function_t *ubf, void *data2)
Identical to rb_thread_call_without_gvl(), except it does not interface with signals etc.
void * rb_thread_call_without_gvl(void *(*func)(void *), void *data1, rb_unblock_function_t *ubf, void *data2)
Allows the passed function to run in parallel with other Ruby threads.
#define RB_NUM2INT
Just another name of rb_num2int_inline.
#define RB_INT2NUM
Just another name of rb_int2num_inline.
VALUE rb_sprintf(const char *fmt,...)
Ruby's extended sprintf(3).
VALUE rb_str_catf(VALUE dst, const char *fmt,...)
Identical to rb_sprintf(), except it renders the output to the specified object rather than creating ...
#define RB_BLOCK_CALL_FUNC_ARGLIST(yielded_arg, callback_arg)
Shim for block function parameters.
VALUE rb_yield(VALUE val)
Yields the block.
void rb_marshal_define_compat(VALUE newclass, VALUE oldclass, VALUE(*dumper)(VALUE), VALUE(*loader)(VALUE, VALUE))
Marshal format compatibility layer.
#define MEMCPY(p1, p2, type, n)
Handy macro to call memcpy.
#define MEMZERO(p, type, n)
Handy macro to erase a region of memory.
#define RB_GC_GUARD(v)
Prevents premature destruction of local objects.
#define NUM2MODET
Converts a C's mode_t into an instance of rb_cInteger.
VALUE rb_thread_create(type *q, void *w)
Creates a rb_cThread instance.
VALUE rb_block_call(VALUE q, ID w, int e, const VALUE *r, type *t, VALUE y)
Call a method with a block.
void rb_define_virtual_variable(const char *q, type *w, void_type *e)
Define a function-backended global variable.
VALUE rb_ensure(type *q, VALUE w, type *e, VALUE r)
An equivalent of ensure clause.
#define PIDT2NUM
Converts a C's pid_t into an instance of rb_cInteger.
#define NUM2PIDT
Converts an instance of rb_cNumeric into C's pid_t.
#define RARRAY_LEN
Just another name of rb_array_len.
#define RARRAY_AREF(a, i)
#define DATA_PTR(obj)
Convenient getter macro.
#define RUBY_DEFAULT_FREE
This is a value you can set to RData::dfree.
#define RHASH_SIZE(h)
Queries the size of the hash.
#define RHASH_EMPTY_P(h)
Checks if the hash is empty.
#define SafeStringValue(v)
#define StringValue(v)
Ensures that the parameter object is a String.
#define StringValueCStr(v)
Identical to StringValuePtr, except it additionally checks for the contents for viability as a C stri...
#define RTYPEDDATA_DATA(v)
Convenient getter macro.
#define RUBY_TYPED_DEFAULT_FREE
This is a value you can set to rb_data_type_struct::dfree.
#define TypedData_Get_Struct(obj, type, data_type, sval)
Obtains a C struct from inside of a wrapper Ruby object.
#define TypedData_Make_Struct(klass, type, data_type, sval)
Identical to TypedData_Wrap_Struct, except it allocates a new data region internally instead of takin...
const char * rb_class2name(VALUE klass)
Queries the name of the passed class.
#define FilePathValue(v)
Ensures that the parameter object is a path.
#define InitVM(ext)
This macro is for internal use.
VALUE rb_fiber_scheduler_current(void)
Identical to rb_fiber_scheduler_get(), except it also returns RUBY_Qnil in case of a blocking fiber.
VALUE rb_fiber_scheduler_kernel_sleepv(VALUE scheduler, int argc, VALUE *argv)
Identical to rb_fiber_scheduler_kernel_sleep(), except it can pass multiple arguments.
VALUE rb_fiber_scheduler_process_wait(VALUE scheduler, rb_pid_t pid, int flags)
Non-blocking waitpid.
#define RTEST
This is an old name of RB_TEST.
#define _(args)
This was a transition path from K&R to ANSI.
const char * wrap_struct_name
Name of structs of this kind.
Ruby's IO, metadata and buffers.
VALUE tied_io_for_writing
Duplex IO object, if set.
void rb_native_mutex_lock(rb_nativethread_lock_t *lock)
Just another name of rb_nativethread_lock_lock.
void rb_native_mutex_unlock(rb_nativethread_lock_t *lock)
Just another name of rb_nativethread_lock_unlock.
#define UIDT2NUM
Converts a C's uid_t into an instance of rb_cInteger.
#define NUM2UIDT
Converts an instance of rb_cNumeric into C's uid_t.
uintptr_t VALUE
Type that represents a Ruby object.
uintptr_t ID
Type that represents a Ruby identifier such as a variable name.