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/io.h"
107#include "internal/numeric.h"
108#include "internal/object.h"
109#include "internal/process.h"
110#include "internal/thread.h"
111#include "internal/variable.h"
112#include "internal/warnings.h"
125#define open rb_w32_uopen
128#if defined(HAVE_TIMES) || defined(_WIN32)
135static VALUE rb_cProcessTms;
139#define WIFEXITED(w) (((w) & 0xff) == 0)
142#define WIFSIGNALED(w) (((w) & 0x7f) > 0 && (((w) & 0x7f) < 0x7f))
145#define WIFSTOPPED(w) (((w) & 0xff) == 0x7f)
148#define WEXITSTATUS(w) (((w) >> 8) & 0xff)
151#define WTERMSIG(w) ((w) & 0x7f)
154#define WSTOPSIG WEXITSTATUS
157#if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__bsdi__)
158#define HAVE_44BSD_SETUID 1
159#define HAVE_44BSD_SETGID 1
167#ifdef BROKEN_SETREUID
168#define setreuid ruby_setreuid
169int setreuid(rb_uid_t ruid, rb_uid_t euid);
171#ifdef BROKEN_SETREGID
172#define setregid ruby_setregid
173int setregid(rb_gid_t rgid, rb_gid_t egid);
176#if defined(HAVE_44BSD_SETUID) || defined(__APPLE__)
177#if !defined(USE_SETREUID) && !defined(BROKEN_SETREUID)
178#define OBSOLETE_SETREUID 1
180#if !defined(USE_SETREGID) && !defined(BROKEN_SETREGID)
181#define OBSOLETE_SETREGID 1
185static void check_uid_switch(
void);
186static void check_gid_switch(
void);
187static int exec_async_signal_safe(
const struct rb_execarg *,
char *,
size_t);
189VALUE rb_envtbl(
void);
190VALUE rb_env_to_hash(
void);
193#define p_uid_from_name p_uid_from_name
194#define p_gid_from_name p_gid_from_name
197#if defined(HAVE_UNISTD_H)
198# if defined(HAVE_GETLOGIN_R)
199# define USE_GETLOGIN_R 1
200# define GETLOGIN_R_SIZE_DEFAULT 0x100
201# define GETLOGIN_R_SIZE_LIMIT 0x1000
202# if defined(_SC_LOGIN_NAME_MAX)
203# define GETLOGIN_R_SIZE_INIT sysconf(_SC_LOGIN_NAME_MAX)
205# define GETLOGIN_R_SIZE_INIT GETLOGIN_R_SIZE_DEFAULT
207# elif defined(HAVE_GETLOGIN)
208# define USE_GETLOGIN 1
212#if defined(HAVE_PWD_H)
213# if defined(HAVE_GETPWUID_R)
214# define USE_GETPWUID_R 1
215# elif defined(HAVE_GETPWUID)
216# define USE_GETPWUID 1
218# if defined(HAVE_GETPWNAM_R)
219# define USE_GETPWNAM_R 1
220# elif defined(HAVE_GETPWNAM)
221# define USE_GETPWNAM 1
223# if defined(HAVE_GETPWNAM_R) || defined(HAVE_GETPWUID_R)
224# define GETPW_R_SIZE_DEFAULT 0x1000
225# define GETPW_R_SIZE_LIMIT 0x10000
226# if defined(_SC_GETPW_R_SIZE_MAX)
227# define GETPW_R_SIZE_INIT sysconf(_SC_GETPW_R_SIZE_MAX)
229# define GETPW_R_SIZE_INIT GETPW_R_SIZE_DEFAULT
232# ifdef USE_GETPWNAM_R
233# define PREPARE_GETPWNAM \
235# define FINISH_GETPWNAM \
236 (getpw_buf ? (void)rb_str_resize(getpw_buf, 0) : (void)0)
237# define OBJ2UID1(id) obj2uid((id), &getpw_buf)
238# define OBJ2UID(id) obj2uid0(id)
239static rb_uid_t obj2uid(
VALUE id,
VALUE *getpw_buf);
240static inline rb_uid_t
250# define PREPARE_GETPWNAM
251# define FINISH_GETPWNAM
252# define OBJ2UID1(id) obj2uid((id))
253# define OBJ2UID(id) obj2uid((id))
254static rb_uid_t obj2uid(
VALUE id);
257# define PREPARE_GETPWNAM
258# define FINISH_GETPWNAM
259# define OBJ2UID1(id) NUM2UIDT(id)
260# define OBJ2UID(id) NUM2UIDT(id)
261# ifdef p_uid_from_name
262# undef p_uid_from_name
263# define p_uid_from_name rb_f_notimplement
267#if defined(HAVE_GRP_H)
268# if defined(HAVE_GETGRNAM_R) && defined(_SC_GETGR_R_SIZE_MAX)
269# define USE_GETGRNAM_R
270# define GETGR_R_SIZE_INIT sysconf(_SC_GETGR_R_SIZE_MAX)
271# define GETGR_R_SIZE_DEFAULT 0x1000
272# define GETGR_R_SIZE_LIMIT 0x10000
274# ifdef USE_GETGRNAM_R
275# define PREPARE_GETGRNAM \
277# define FINISH_GETGRNAM \
278 (getgr_buf ? (void)rb_str_resize(getgr_buf, 0) : (void)0)
279# define OBJ2GID1(id) obj2gid((id), &getgr_buf)
280# define OBJ2GID(id) obj2gid0(id)
281static rb_gid_t obj2gid(
VALUE id,
VALUE *getgr_buf);
282static inline rb_gid_t
291static rb_gid_t obj2gid(
VALUE id,
VALUE *getgr_buf);
293# define PREPARE_GETGRNAM
294# define FINISH_GETGRNAM
295# define OBJ2GID1(id) obj2gid((id))
296# define OBJ2GID(id) obj2gid((id))
297static rb_gid_t obj2gid(
VALUE id);
300# define PREPARE_GETGRNAM
301# define FINISH_GETGRNAM
302# define OBJ2GID1(id) NUM2GIDT(id)
303# define OBJ2GID(id) NUM2GIDT(id)
304# ifdef p_gid_from_name
305# undef p_gid_from_name
306# define p_gid_from_name rb_f_notimplement
310#if SIZEOF_CLOCK_T == SIZEOF_INT
311typedef unsigned int unsigned_clock_t;
312#elif SIZEOF_CLOCK_T == SIZEOF_LONG
313typedef unsigned long unsigned_clock_t;
314#elif defined(HAVE_LONG_LONG) && SIZEOF_CLOCK_T == SIZEOF_LONG_LONG
315typedef unsigned LONG_LONG unsigned_clock_t;
318typedef void (*sig_t) (int);
321#define id_exception idException
322static ID id_in, id_out, id_err, id_pid, id_uid, id_gid;
323static ID id_close, id_child;
328static ID id_new_pgroup;
330static ID id_unsetenv_others, id_chdir, id_umask, id_close_others;
331static ID id_nanosecond, id_microsecond, id_millisecond, id_second;
332static ID id_float_microsecond, id_float_millisecond, id_float_second;
333static ID id_GETTIMEOFDAY_BASED_CLOCK_REALTIME, id_TIME_BASED_CLOCK_REALTIME;
335static ID id_CLOCK_REALTIME;
336# define RUBY_CLOCK_REALTIME ID2SYM(id_CLOCK_REALTIME)
338#ifdef CLOCK_MONOTONIC
339static ID id_CLOCK_MONOTONIC;
340# define RUBY_CLOCK_MONOTONIC ID2SYM(id_CLOCK_MONOTONIC)
342#ifdef CLOCK_PROCESS_CPUTIME_ID
343static ID id_CLOCK_PROCESS_CPUTIME_ID;
344# define RUBY_CLOCK_PROCESS_CPUTIME_ID ID2SYM(id_CLOCK_PROCESS_CPUTIME_ID)
346#ifdef CLOCK_THREAD_CPUTIME_ID
347static ID id_CLOCK_THREAD_CPUTIME_ID;
348# define RUBY_CLOCK_THREAD_CPUTIME_ID ID2SYM(id_CLOCK_THREAD_CPUTIME_ID)
351static ID id_TIMES_BASED_CLOCK_MONOTONIC;
352static ID id_TIMES_BASED_CLOCK_PROCESS_CPUTIME_ID;
355static ID id_GETRUSAGE_BASED_CLOCK_PROCESS_CPUTIME_ID;
357static ID id_CLOCK_BASED_CLOCK_PROCESS_CPUTIME_ID;
359static ID id_MACH_ABSOLUTE_TIME_BASED_CLOCK_MONOTONIC;
360# define RUBY_MACH_ABSOLUTE_TIME_BASED_CLOCK_MONOTONIC ID2SYM(id_MACH_ABSOLUTE_TIME_BASED_CLOCK_MONOTONIC)
364static rb_pid_t cached_pid;
367#if defined(__sun) && !defined(_XPG7)
368#define execv(path, argv) (rb_async_bug_errno("unreachable: async-signal-unsafe execv() is called", 0))
369#define execl(path, arg0, arg1, arg2, term) do { extern char **environ; execle((path), (arg0), (arg1), (arg2), (term), (environ)); } while (0)
370#define ALWAYS_NEED_ENVP 1
372#define ALWAYS_NEED_ENVP 0
376assert_close_on_exec(
int fd)
379#if defined(HAVE_FCNTL) && defined(F_GETFD) && defined(FD_CLOEXEC)
380 int flags = fcntl(fd, F_GETFD);
382 static const char m[] =
"reserved FD closed unexpectedly?\n";
383 (void)!write(2, m,
sizeof(m) - 1);
386 if (flags & FD_CLOEXEC)
return;
387 rb_bug(
"reserved FD did not have close-on-exec set");
389 rb_bug(
"reserved FD without close-on-exec support");
395close_unless_reserved(
int fd)
398 assert_close_on_exec(fd);
405#if defined(DEBUG_REDIRECT)
408ttyprintf(
const char *fmt, ...)
414 tty = fopen(
"con",
"w");
416 tty = fopen(
"/dev/tty",
"w");
422 vfprintf(tty, fmt, ap);
429redirect_dup(
int oldfd)
433 ttyprintf(
"dup(%d) => %d\n", oldfd, ret);
438redirect_dup2(
int oldfd,
int newfd)
441 ret = dup2(oldfd, newfd);
442 ttyprintf(
"dup2(%d, %d) => %d\n", oldfd, newfd, ret);
447redirect_cloexec_dup(
int oldfd)
451 ttyprintf(
"cloexec_dup(%d) => %d\n", oldfd, ret);
456redirect_cloexec_dup2(
int oldfd,
int newfd)
460 ttyprintf(
"cloexec_dup2(%d, %d) => %d\n", oldfd, newfd, ret);
465redirect_close(
int fd)
468 ret = close_unless_reserved(fd);
469 ttyprintf(
"close(%d) => %d\n", fd, ret);
474parent_redirect_open(
const char *pathname,
int flags, mode_t perm)
478 ttyprintf(
"parent_open(\"%s\", 0x%x, 0%o) => %d\n", pathname, flags, perm, ret);
483parent_redirect_close(
int fd)
486 ret = close_unless_reserved(fd);
487 ttyprintf(
"parent_close(%d) => %d\n", fd, ret);
492#define redirect_dup(oldfd) dup(oldfd)
493#define redirect_dup2(oldfd, newfd) dup2((oldfd), (newfd))
494#define redirect_cloexec_dup(oldfd) rb_cloexec_dup(oldfd)
495#define redirect_cloexec_dup2(oldfd, newfd) rb_cloexec_dup2((oldfd), (newfd))
496#define redirect_close(fd) close_unless_reserved(fd)
497#define parent_redirect_open(pathname, flags, perm) rb_cloexec_open((pathname), (flags), (perm))
498#define parent_redirect_close(fd) close_unless_reserved(fd)
504 if (UNLIKELY(!cached_pid)) {
505 cached_pid = getpid();
511#if defined HAVE_WORKING_FORK || defined HAVE_DAEMON
585static VALUE rb_cProcessStatus;
600 .flags = RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED | RUBY_TYPED_EMBEDDABLE,
604rb_process_status_allocate(
VALUE klass)
613 return GET_THREAD()->last_status;
639proc_s_last_status(
VALUE mod)
645rb_process_status_new(rb_pid_t pid,
int status,
int error)
647 VALUE last_status = rb_process_status_allocate(rb_cProcessStatus);
650 data->status = status;
653 rb_obj_freeze(last_status);
658process_status_dump(
VALUE status)
671process_status_load(
VALUE real_obj,
VALUE load_obj)
674 VALUE status = rb_attr_get(load_obj, id_status);
675 VALUE pid = rb_attr_get(load_obj, id_pid);
684 GET_THREAD()->last_status = rb_process_status_new(pid, status, 0);
690 th->last_status =
Qnil;
694rb_last_status_clear(
void)
696 last_status_clear(GET_THREAD());
708pst_status(
VALUE status)
728 int status = pst_status(self);
732#define PST2INT(st) pst_status(st)
748 rb_pid_t pid = pst_pid(self);
752static VALUE pst_message_status(
VALUE str,
int status);
755pst_message(
VALUE str, rb_pid_t pid,
int status)
757 rb_str_catf(str,
"pid %ld", (
long)pid);
758 pst_message_status(str, status);
762pst_message_status(
VALUE str,
int status)
764 if (WIFSTOPPED(status)) {
765 int stopsig = WSTOPSIG(status);
768 rb_str_catf(str,
" stopped SIG%s (signal %d)", signame, stopsig);
771 rb_str_catf(str,
" stopped signal %d", stopsig);
774 if (WIFSIGNALED(status)) {
775 int termsig = WTERMSIG(status);
778 rb_str_catf(str,
" SIG%s (signal %d)", signame, termsig);
781 rb_str_catf(str,
" signal %d", termsig);
784 if (WIFEXITED(status)) {
785 rb_str_catf(str,
" exit %d", WEXITSTATUS(status));
788 if (WCOREDUMP(status)) {
816 status = PST2INT(st);
818 str = rb_str_buf_new(0);
819 pst_message(str, pid, status);
846 status = PST2INT(st);
849 pst_message(str, pid, status);
871 if (st1 == st2)
return Qtrue;
872 return rb_equal(pst_to_i(st1), st2);
897 int status = PST2INT(st1);
901 rb_raise(rb_eArgError,
"negative mask value: %d", mask);
903#define WARN_SUGGEST(suggest) \
904 rb_warn_deprecated_to_remove_at(3.4, "Process::Status#&", suggest)
908 WARN_SUGGEST(
"Process::Status#coredump?");
911 WARN_SUGGEST(
"Process::Status#signaled? or Process::Status#termsig");
914 WARN_SUGGEST(
"Process::Status#exited?, Process::Status#stopped? or Process::Status#coredump?");
917 WARN_SUGGEST(
"Process::Status#exitstatus or Process::Status#stopsig");
920 WARN_SUGGEST(
"other Process::Status predicates");
952 int status = PST2INT(st1);
956 rb_raise(rb_eArgError,
"negative shift value: %d", places);
958#define WARN_SUGGEST(suggest) \
959 rb_warn_deprecated_to_remove_at(3.4, "Process::Status#>>", suggest)
963 WARN_SUGGEST(
"Process::Status#coredump?");
966 WARN_SUGGEST(
"Process::Status#exitstatus or Process::Status#stopsig");
969 WARN_SUGGEST(
"other Process::Status attributes");
989pst_wifstopped(
VALUE st)
991 int status = PST2INT(st);
993 return RBOOL(WIFSTOPPED(status));
1006pst_wstopsig(
VALUE st)
1008 int status = PST2INT(st);
1010 if (WIFSTOPPED(status))
1011 return INT2NUM(WSTOPSIG(status));
1025pst_wifsignaled(
VALUE st)
1027 int status = PST2INT(st);
1029 return RBOOL(WIFSIGNALED(status));
1042pst_wtermsig(
VALUE st)
1044 int status = PST2INT(st);
1046 if (WIFSIGNALED(status))
1047 return INT2NUM(WTERMSIG(status));
1062pst_wifexited(
VALUE st)
1064 int status = PST2INT(st);
1066 return RBOOL(WIFEXITED(status));
1084pst_wexitstatus(
VALUE st)
1086 int status = PST2INT(st);
1088 if (WIFEXITED(status))
1089 return INT2NUM(WEXITSTATUS(status));
1107pst_success_p(
VALUE st)
1109 int status = PST2INT(st);
1111 if (!WIFEXITED(status))
1113 return RBOOL(WEXITSTATUS(status) == EXIT_SUCCESS);
1128pst_wcoredump(
VALUE st)
1131 int status = PST2INT(st);
1133 return RBOOL(WCOREDUMP(status));
1140do_waitpid(rb_pid_t pid,
int *st,
int flags)
1142#if defined HAVE_WAITPID
1143 return waitpid(pid, st, flags);
1144#elif defined HAVE_WAIT4
1145 return wait4(pid, st, flags, NULL);
1147# error waitpid or wait4 is required.
1152 struct ccan_list_node wnode;
1154 rb_nativethread_cond_t *cond;
1163waitpid_state_init(
struct waitpid_state *w, rb_pid_t pid,
int options)
1167 w->options = options;
1173waitpid_blocking_no_SIGCHLD(
void *x)
1177 w->ret = do_waitpid(w->pid, &w->status, w->options);
1185 if (w->options & WNOHANG) {
1186 w->ret = do_waitpid(w->pid, &w->status, w->options);
1191 }
while (w->ret < 0 &&
errno == EINTR && (RUBY_VM_CHECK_INTS(w->ec),1));
1201 if (!(flags & WNOHANG)) {
1204 if (!UNDEF_P(result))
return result;
1250rb_process_status_waitv(
int argc,
VALUE *argv,
VALUE _)
1272 if (
NIL_P(status))
return 0;
1277 if (st) *st = data->status;
1280 errno = data->error;
1283 GET_THREAD()->last_status = status;
1290proc_wait(
int argc,
VALUE *argv)
1302 if (argc == 2 && !
NIL_P(vflags = argv[1])) {
1307 if ((pid =
rb_waitpid(pid, &status, flags)) < 0)
1311 rb_last_status_clear();
1468 return proc_wait(c, v);
1488 VALUE pid = proc_wait(argc, argv);
1516 result = rb_ary_new();
1517 rb_last_status_clear();
1532static VALUE rb_cWaiter;
1535detach_process_pid(
VALUE thread)
1541detach_process_watcher(
void *arg)
1543 rb_pid_t cpid, pid = (rb_pid_t)(
VALUE)arg;
1546 while ((cpid =
rb_waitpid(pid, &status, 0)) == 0) {
1557 RBASIC_SET_CLASS(watcher, rb_cWaiter);
1609before_exec_async_signal_safe(
void)
1614before_exec_non_async_signal_safe(
void)
1625 rb_thread_stop_timer_thread();
1628#define WRITE_CONST(fd, str) (void)(write((fd),(str),sizeof(str)-1)<0)
1630int rb_w32_set_nonblock2(
int fd,
int nonblock);
1637 return rb_w32_set_nonblock2(fd, 0);
1638#elif defined(F_GETFL) && defined(F_SETFL)
1639 int fl = fcntl(fd, F_GETFL);
1642 if (fl == -1)
return fl;
1643 if (fl & O_NONBLOCK) {
1645 return fcntl(fd, F_SETFL, fl);
1652stdfd_clear_nonblock(
void)
1656 for (fd = 0; fd < 3; fd++) {
1657 (void)set_blocking(fd);
1664 before_exec_non_async_signal_safe();
1665 before_exec_async_signal_safe();
1671 rb_thread_reset_timer_thread();
1672 rb_thread_start_timer_thread();
1675#if defined HAVE_WORKING_FORK || defined HAVE_DAEMON
1677before_fork_ruby(
void)
1683after_fork_ruby(rb_pid_t pid)
1685 rb_threadptr_pending_interrupt_clear(GET_THREAD());
1698#if defined(HAVE_WORKING_FORK)
1700COMPILER_WARNING_PUSH
1701#if __has_warning("-Wdeprecated-declarations") || RBIMPL_COMPILER_IS(GCC)
1702COMPILER_WARNING_IGNORED(-Wdeprecated-declarations)
1704static inline rb_pid_t
1712#define try_with_sh(err, prog, argv, envp) ((err == ENOEXEC) ? exec_with_sh((prog), (argv), (envp)) : (void)0)
1714exec_with_sh(
const char *prog,
char **argv,
char **envp)
1716 *argv = (
char *)prog;
1717 *--argv = (
char *)
"sh";
1719 execve(
"/bin/sh", argv, envp);
1721 execv(
"/bin/sh", argv);
1725#define try_with_sh(err, prog, argv, envp) (void)0
1730proc_exec_cmd(
const char *prog,
VALUE argv_str,
VALUE envp_str)
1738 argv = ARGVSTR2ARGV(argv_str);
1745 rb_w32_uaspawn(P_OVERLAY, prog, argv);
1748 envp = envp_str ? RB_IMEMO_TMPBUF_PTR(envp_str) : NULL;
1750 execve(prog, argv, envp);
1754 try_with_sh(err, prog, argv, envp);
1761proc_exec_sh(
const char *str,
VALUE envp_str)
1766 while (*s ==
' ' || *s ==
'\t' || *s ==
'\n')
1774 rb_w32_uspawn(P_OVERLAY, (
char *)str, 0);
1775#elif defined(__CYGWIN32__)
1777 char fbuf[MAXPATHLEN];
1778 char *shell = dln_find_exe_r(
"sh", 0, fbuf,
sizeof(fbuf));
1781 execl(shell,
"sh",
"-c", str, (
char *) NULL);
1783 status = system(str);
1789 execle(
"/bin/sh",
"sh",
"-c", str, (
char *)NULL, RB_IMEMO_TMPBUF_PTR(envp_str));
1791 execl(
"/bin/sh",
"sh",
"-c", str, (
char *)NULL);
1801 ret = proc_exec_sh(str,
Qfalse);
1808mark_exec_arg(
void *ptr)
1811 if (eargp->use_shell)
1812 rb_gc_mark(eargp->invoke.sh.shell_script);
1814 rb_gc_mark(eargp->invoke.cmd.command_name);
1815 rb_gc_mark(eargp->invoke.cmd.command_abspath);
1816 rb_gc_mark(eargp->invoke.cmd.argv_str);
1817 rb_gc_mark(eargp->invoke.cmd.argv_buf);
1819 rb_gc_mark(eargp->redirect_fds);
1820 rb_gc_mark(eargp->envp_str);
1821 rb_gc_mark(eargp->envp_buf);
1822 rb_gc_mark(eargp->dup2_tmpbuf);
1823 rb_gc_mark(eargp->rlimit_limits);
1824 rb_gc_mark(eargp->fd_dup2);
1825 rb_gc_mark(eargp->fd_close);
1826 rb_gc_mark(eargp->fd_open);
1827 rb_gc_mark(eargp->fd_dup2_child);
1828 rb_gc_mark(eargp->env_modification);
1829 rb_gc_mark(eargp->path_env);
1830 rb_gc_mark(eargp->chdir_dir);
1834memsize_exec_arg(
const void *ptr)
1842 0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_EMBEDDABLE
1846# define DEFAULT_PROCESS_ENCODING rb_utf8_encoding()
1848#ifdef DEFAULT_PROCESS_ENCODING
1849# define EXPORT_STR(str) rb_str_export_to_enc((str), DEFAULT_PROCESS_ENCODING)
1850# define EXPORT_DUP(str) export_dup(str)
1852export_dup(
VALUE str)
1854 VALUE newstr = EXPORT_STR(str);
1855 if (newstr == str) newstr = rb_str_dup(str);
1859# define EXPORT_STR(str) (str)
1860# define EXPORT_DUP(str) rb_str_dup(str)
1863#if !defined(HAVE_WORKING_FORK) && defined(HAVE_SPAWNV)
1864# define USE_SPAWNV 1
1866# define USE_SPAWNV 0
1869# define P_NOWAIT _P_NOWAIT
1874#define proc_spawn_cmd_internal(argv, prog) rb_w32_uaspawn(P_NOWAIT, (prog), (argv))
1877proc_spawn_cmd_internal(
char **argv,
char *prog)
1879 char fbuf[MAXPATHLEN];
1884 prog = dln_find_exe_r(prog, 0, fbuf,
sizeof(fbuf));
1889 status = spawnv(P_NOWAIT, prog, (
const char **)argv);
1890 if (status == -1 &&
errno == ENOEXEC) {
1891 *argv = (
char *)prog;
1892 *--argv = (
char *)
"sh";
1893 status = spawnv(P_NOWAIT,
"/bin/sh", (
const char **)argv);
1895 if (status == -1)
errno = ENOEXEC;
1909 if (eargp->new_pgroup_given && eargp->new_pgroup_flag) {
1910 flags = CREATE_NEW_PROCESS_GROUP;
1912 pid = rb_w32_uaspawn_flags(P_NOWAIT, prog ? RSTRING_PTR(prog) : 0, argv, flags);
1914 pid = proc_spawn_cmd_internal(argv, prog ? RSTRING_PTR(prog) : 0);
1921#define proc_spawn_sh(str) rb_w32_uspawn(P_NOWAIT, (str), 0)
1924proc_spawn_sh(
char *str)
1926 char fbuf[MAXPATHLEN];
1929 char *shell = dln_find_exe_r(
"sh", 0, fbuf,
sizeof(fbuf));
1931 status = spawnl(P_NOWAIT, (shell ? shell :
"/bin/sh"),
"sh",
"-c", str, (char*)NULL);
1941 RBASIC_CLEAR_CLASS(obj);
1946check_exec_redirect_fd(
VALUE v,
int iskey)
1957 else if (
id == id_out)
1959 else if (
id == id_err)
1968 rb_raise(rb_eArgError,
"duplex IO redirection");
1975 rb_raise(rb_eArgError,
"negative file descriptor");
1978 else if (fd >= 3 && iskey) {
1979 rb_raise(rb_eArgError,
"wrong file descriptor (%d)", fd);
1985 rb_raise(rb_eArgError,
"wrong exec redirect");
1993 ary = hide_obj(rb_ary_new());
1995 if (!RB_TYPE_P(key,
T_ARRAY)) {
1996 VALUE fd = check_exec_redirect_fd(key, !
NIL_P(param));
1997 rb_ary_push(ary, hide_obj(rb_assoc_new(fd, param)));
2003 VALUE fd = check_exec_redirect_fd(v, !
NIL_P(param));
2004 rb_ary_push(ary, hide_obj(rb_assoc_new(fd, param)));
2014 VALUE path, flags, perm;
2018 switch (
TYPE(val)) {
2021 if (
id == id_close) {
2023 eargp->fd_close = check_exec_redirect1(eargp->fd_close, key, param);
2025 else if (
id == id_in) {
2027 eargp->fd_dup2 = check_exec_redirect1(eargp->fd_dup2, key, param);
2029 else if (
id == id_out) {
2031 eargp->fd_dup2 = check_exec_redirect1(eargp->fd_dup2, key, param);
2033 else if (
id == id_err) {
2035 eargp->fd_dup2 = check_exec_redirect1(eargp->fd_dup2, key, param);
2038 rb_raise(rb_eArgError,
"wrong exec redirect symbol: %"PRIsVALUE,
2045 val = check_exec_redirect_fd(val, 0);
2049 eargp->fd_dup2 = check_exec_redirect1(eargp->fd_dup2, key, param);
2053 path = rb_ary_entry(val, 0);
2055 path ==
ID2SYM(id_child)) {
2056 param = check_exec_redirect_fd(rb_ary_entry(val, 1), 0);
2057 eargp->fd_dup2_child = check_exec_redirect1(eargp->fd_dup2_child, key, param);
2061 flags = rb_ary_entry(val, 1);
2064 else if (RB_TYPE_P(flags,
T_STRING))
2068 perm = rb_ary_entry(val, 2);
2070 param = hide_obj(
rb_ary_new3(4, hide_obj(EXPORT_DUP(path)),
2071 flags, perm,
Qnil));
2072 eargp->fd_open = check_exec_redirect1(eargp->fd_open, key, param);
2079 if (RB_TYPE_P(key,
T_FILE))
2080 key = check_exec_redirect_fd(key, 1);
2082 flags =
INT2NUM(O_WRONLY|O_CREAT|O_TRUNC);
2083 else if (RB_TYPE_P(key,
T_ARRAY)) {
2087 VALUE fd = check_exec_redirect_fd(v, 1);
2091 flags =
INT2NUM(O_WRONLY|O_CREAT|O_TRUNC);
2098 param = hide_obj(
rb_ary_new3(4, hide_obj(EXPORT_DUP(path)),
2099 flags, perm,
Qnil));
2100 eargp->fd_open = check_exec_redirect1(eargp->fd_open, key, param);
2106 if (!
NIL_P(val))
goto io;
2107 rb_raise(rb_eArgError,
"wrong exec redirect action");
2112#if defined(HAVE_SETRLIMIT) && defined(NUM2RLIM)
2113static int rlimit_type_by_sym(
VALUE key);
2116rb_execarg_addopt_rlimit(
struct rb_execarg *eargp,
int rtype,
VALUE val)
2118 VALUE ary = eargp->rlimit_limits;
2119 VALUE tmp, softlim, hardlim;
2120 if (eargp->rlimit_limits ==
Qfalse)
2121 ary = eargp->rlimit_limits = hide_obj(rb_ary_new());
2123 ary = eargp->rlimit_limits;
2124 tmp = rb_check_array_type(val);
2127 softlim = hardlim =
rb_to_int(rb_ary_entry(tmp, 0));
2129 softlim =
rb_to_int(rb_ary_entry(tmp, 0));
2130 hardlim =
rb_to_int(rb_ary_entry(tmp, 1));
2133 rb_raise(rb_eArgError,
"wrong exec rlimit option");
2140 rb_ary_push(ary, tmp);
2144#define TO_BOOL(val, name) (NIL_P(val) ? 0 : rb_bool_expected((val), name, TRUE))
2148 struct rb_execarg *eargp = rb_execarg_get(execarg_obj);
2152 switch (
TYPE(key)) {
2154#if defined(HAVE_SETRLIMIT) && defined(NUM2RLIM)
2156 int rtype = rlimit_type_by_sym(key);
2158 rb_execarg_addopt_rlimit(eargp, rtype, val);
2166 if (
id == id_pgroup) {
2168 if (eargp->pgroup_given) {
2169 rb_raise(rb_eArgError,
"pgroup option specified twice");
2173 else if (val ==
Qtrue)
2178 rb_raise(rb_eArgError,
"negative process group ID : %ld", (
long)pgroup);
2181 eargp->pgroup_given = 1;
2182 eargp->pgroup_pgid = pgroup;
2187 if (
id == id_new_pgroup) {
2188 if (eargp->new_pgroup_given) {
2189 rb_raise(rb_eArgError,
"new_pgroup option specified twice");
2191 eargp->new_pgroup_given = 1;
2192 eargp->new_pgroup_flag = TO_BOOL(val,
"new_pgroup");
2196 if (
id == id_unsetenv_others) {
2197 if (eargp->unsetenv_others_given) {
2198 rb_raise(rb_eArgError,
"unsetenv_others option specified twice");
2200 eargp->unsetenv_others_given = 1;
2201 eargp->unsetenv_others_do = TO_BOOL(val,
"unsetenv_others");
2203 else if (
id == id_chdir) {
2204 if (eargp->chdir_given) {
2205 rb_raise(rb_eArgError,
"chdir option specified twice");
2208 val = rb_str_encode_ospath(val);
2209 eargp->chdir_given = 1;
2210 eargp->chdir_dir = hide_obj(EXPORT_DUP(val));
2212 else if (
id == id_umask) {
2214 if (eargp->umask_given) {
2215 rb_raise(rb_eArgError,
"umask option specified twice");
2217 eargp->umask_given = 1;
2218 eargp->umask_mask = cmask;
2220 else if (
id == id_close_others) {
2221 if (eargp->close_others_given) {
2222 rb_raise(rb_eArgError,
"close_others option specified twice");
2224 eargp->close_others_given = 1;
2225 eargp->close_others_do = TO_BOOL(val,
"close_others");
2227 else if (
id == id_in) {
2231 else if (
id == id_out) {
2235 else if (
id == id_err) {
2239 else if (
id == id_uid) {
2241 if (eargp->uid_given) {
2242 rb_raise(rb_eArgError,
"uid option specified twice");
2246 eargp->uid = OBJ2UID(val);
2247 eargp->uid_given = 1;
2251 "uid option is unimplemented on this machine");
2254 else if (
id == id_gid) {
2256 if (eargp->gid_given) {
2257 rb_raise(rb_eArgError,
"gid option specified twice");
2261 eargp->gid = OBJ2GID(val);
2262 eargp->gid_given = 1;
2266 "gid option is unimplemented on this machine");
2269 else if (
id == id_exception) {
2270 if (eargp->exception_given) {
2271 rb_raise(rb_eArgError,
"exception option specified twice");
2273 eargp->exception_given = 1;
2274 eargp->exception = TO_BOOL(val,
"exception");
2285 check_exec_redirect(key, val, eargp);
2297check_exec_options_i(st_data_t st_key, st_data_t st_val, st_data_t arg)
2302 if (rb_execarg_addopt(execarg_obj, key, val) != ST_CONTINUE) {
2304 rb_raise(rb_eArgError,
"wrong exec option symbol: % "PRIsVALUE,
2306 rb_raise(rb_eArgError,
"wrong exec option");
2312check_exec_options_i_extract(st_data_t st_key, st_data_t st_val, st_data_t arg)
2317 VALUE execarg_obj = args[0];
2318 if (rb_execarg_addopt(execarg_obj, key, val) != ST_CONTINUE) {
2319 VALUE nonopts = args[1];
2320 if (
NIL_P(nonopts)) args[1] = nonopts = rb_hash_new();
2321 rb_hash_aset(nonopts, key, val);
2336 rb_raise(rb_eArgError,
"fd %d specified twice", fd);
2338 if (ary == eargp->fd_dup2)
2340 else if (ary == eargp->fd_dup2_child)
2346 if (ary == eargp->fd_dup2 || ary == eargp->fd_dup2_child) {
2359 VALUE h = rb_hash_new();
2364 maxhint = check_exec_fds_1(eargp, h, maxhint, eargp->fd_dup2);
2365 maxhint = check_exec_fds_1(eargp, h, maxhint, eargp->fd_close);
2366 maxhint = check_exec_fds_1(eargp, h, maxhint, eargp->fd_dup2_child);
2368 if (eargp->fd_dup2_child) {
2369 ary = eargp->fd_dup2_child;
2379 val = rb_hash_lookup(h, val);
2381 rb_raise(rb_eArgError,
"cyclic child fd redirection from %d", oldfd);
2385 rb_raise(rb_eArgError,
"child fd %d is not redirected", oldfd);
2386 if (oldfd != lastfd) {
2388 rb_ary_store(elt, 1,
INT2FIX(lastfd));
2391 while (
FIXNUM_P(val2 = rb_hash_lookup(h, val))) {
2392 rb_hash_aset(h, val,
INT2FIX(lastfd));
2399 eargp->close_others_maxhint = maxhint;
2404rb_check_exec_options(
VALUE opthash,
VALUE execarg_obj)
2408 rb_hash_stlike_foreach(opthash, check_exec_options_i, (st_data_t)execarg_obj);
2412rb_execarg_extract_options(
VALUE execarg_obj,
VALUE opthash)
2417 args[0] = execarg_obj;
2419 rb_hash_stlike_foreach(opthash, check_exec_options_i_extract, (st_data_t)args);
2423#ifdef ENV_IGNORECASE
2424#define ENVMATCH(s1, s2) (STRCASECMP((s1), (s2)) == 0)
2426#define ENVMATCH(n1, n2) (strcmp((n1), (n2)) == 0)
2430check_exec_env_i(st_data_t st_key, st_data_t st_val, st_data_t arg)
2440 rb_raise(rb_eArgError,
"environment name contains a equal : %"PRIsVALUE, key);
2445 key = EXPORT_STR(key);
2446 if (!
NIL_P(val)) val = EXPORT_STR(val);
2451 rb_ary_push(env, hide_obj(rb_assoc_new(key, val)));
2461 env[0] = hide_obj(rb_ary_new());
2463 rb_hash_stlike_foreach(hash, check_exec_env_i, (st_data_t)env);
2470rb_check_argv(
int argc,
VALUE *argv)
2478 tmp = rb_check_array_type(argv[0]);
2481 rb_raise(rb_eArgError,
"wrong first argument");
2487 prog = rb_str_new_frozen(prog);
2489 for (i = 0; i < argc; i++) {
2491 argv[i] = rb_str_new_frozen(argv[i]);
2498check_hash(
VALUE obj)
2508 return rb_check_hash_type(obj);
2512rb_exec_getargs(
int *argc_p,
VALUE **argv_p,
int accept_shell,
VALUE *env_ret,
VALUE *opthash_ret)
2517 hash = check_hash((*argv_p)[*argc_p-1]);
2519 *opthash_ret = hash;
2525 hash = check_hash((*argv_p)[0]);
2532 prog = rb_check_argv(*argc_p, *argv_p);
2534 prog = (*argv_p)[0];
2535 if (accept_shell && *argc_p == 1) {
2550compare_posix_sh(
const void *key,
const void *el)
2553 int ret = strncmp(word->ptr, el, word->len);
2554 if (!ret && ((
const char *)el)[word->len]) ret = -1;
2562 struct rb_execarg *eargp = rb_execarg_get(execarg_obj);
2563 char fbuf[MAXPATHLEN];
2567 if (!
NIL_P(opthash)) {
2568 rb_check_exec_options(opthash, execarg_obj);
2571 env = rb_check_exec_env(env, &eargp->path_env);
2572 eargp->env_modification = env;
2575 prog = EXPORT_STR(prog);
2576 eargp->use_shell = argc == 0;
2577 if (eargp->use_shell)
2578 eargp->invoke.sh.shell_script = prog;
2580 eargp->invoke.cmd.command_name = prog;
2583 if (eargp->use_shell) {
2584 static const char posix_sh_cmds[][9] = {
2642 for (p = RSTRING_PTR(prog); *p; p++) {
2643 if (*p ==
' ' || *p ==
'\t') {
2644 if (first.ptr && !first.len) first.len = p - first.ptr;
2647 if (!first.ptr) first.ptr = p;
2649 if (!has_meta && strchr(
"*?{}[]<>()~&|\\$;'`\"\n#", *p))
2655 else if (*p ==
'/') {
2662 if (!has_meta && first.ptr) {
2663 if (!first.len) first.len = p - first.ptr;
2664 if (first.len > 0 && first.len <=
sizeof(posix_sh_cmds[0]) &&
2665 bsearch(&first, posix_sh_cmds, numberof(posix_sh_cmds),
sizeof(posix_sh_cmds[0]), compare_posix_sh))
2670 eargp->use_shell = 0;
2672 if (!eargp->use_shell) {
2674 argv_buf = hide_obj(rb_str_buf_new(0));
2675 p = RSTRING_PTR(prog);
2677 while (*p ==
' ' || *p ==
'\t')
2681 while (*p && *p !=
' ' && *p !=
'\t')
2687 eargp->invoke.cmd.argv_buf = argv_buf;
2688 eargp->invoke.cmd.command_name =
2689 hide_obj(rb_str_subseq(argv_buf, 0, strlen(RSTRING_PTR(argv_buf))));
2690 rb_enc_copy(eargp->invoke.cmd.command_name, prog);
2695 if (!eargp->use_shell) {
2696 const char *abspath;
2697 const char *path_env = 0;
2698 if (
RTEST(eargp->path_env)) path_env = RSTRING_PTR(eargp->path_env);
2699 abspath = dln_find_exe_r(RSTRING_PTR(eargp->invoke.cmd.command_name),
2700 path_env, fbuf,
sizeof(fbuf));
2704 eargp->invoke.cmd.command_abspath =
Qnil;
2707 if (!eargp->use_shell && !eargp->invoke.cmd.argv_buf) {
2710 argv_buf = rb_str_buf_new(0);
2712 for (i = 0; i < argc; i++) {
2713 VALUE arg = argv[i];
2715#ifdef DEFAULT_PROCESS_ENCODING
2716 arg = EXPORT_STR(arg);
2717 s = RSTRING_PTR(arg);
2721 eargp->invoke.cmd.argv_buf = argv_buf;
2724 if (!eargp->use_shell) {
2725 const char *p, *ep, *null=NULL;
2727 argv_str = hide_obj(rb_str_buf_new(
sizeof(
char*) * (argc + 2)));
2729 p = RSTRING_PTR(eargp->invoke.cmd.argv_buf);
2730 ep = p + RSTRING_LEN(eargp->invoke.cmd.argv_buf);
2736 eargp->invoke.cmd.argv_str =
2737 rb_imemo_tmpbuf_auto_free_pointer_new_from_an_RString(argv_str);
2743rb_execarg_get(
VALUE execarg_obj)
2751rb_execarg_init(
int argc,
const VALUE *orig_argv,
int accept_shell,
VALUE execarg_obj)
2753 struct rb_execarg *eargp = rb_execarg_get(execarg_obj);
2759 prog = rb_exec_getargs(&argc, &argv, accept_shell, &env, &opthash);
2760 rb_exec_fillarg(prog, argc, argv, env, opthash, execarg_obj);
2762 ret = eargp->use_shell ? eargp->invoke.sh.shell_script : eargp->invoke.cmd.command_name;
2768rb_execarg_new(
int argc,
const VALUE *argv,
int accept_shell,
int allow_exc_opt)
2773 rb_execarg_init(argc, argv, accept_shell, execarg_obj);
2774 if (!allow_exc_opt && eargp->exception_given) {
2775 rb_raise(rb_eArgError,
"exception option is not allowed");
2781rb_execarg_setenv(
VALUE execarg_obj,
VALUE env)
2783 struct rb_execarg *eargp = rb_execarg_get(execarg_obj);
2784 env = !
NIL_P(env) ? rb_check_exec_env(env, &eargp->path_env) :
Qfalse;
2785 eargp->env_modification = env;
2790fill_envp_buf_i(st_data_t st_key, st_data_t st_val, st_data_t arg)
2805static long run_exec_dup2_tmpbuf_size(
long n);
2819 const char *fname = RSTRING_PTR(data->fname);
2820 data->ret = parent_redirect_open(fname, data->oflags, data->perm);
2826rb_execarg_allocate_dup2_tmpbuf(
struct rb_execarg *eargp,
long len)
2828 VALUE tmpbuf = rb_imemo_tmpbuf_auto_free_pointer();
2829 rb_imemo_tmpbuf_set_ptr(tmpbuf, ruby_xmalloc(run_exec_dup2_tmpbuf_size(
len)));
2830 eargp->dup2_tmpbuf = tmpbuf;
2834rb_execarg_parent_start1(
VALUE execarg_obj)
2836 struct rb_execarg *eargp = rb_execarg_get(execarg_obj);
2837 int unsetenv_others;
2841 ary = eargp->fd_open;
2856 open_data.fname = vpath;
2857 open_data.oflags = flags;
2858 open_data.perm = perm;
2860 open_data.err = EINTR;
2862 if (open_data.ret == -1) {
2863 if (open_data.err == EINTR) {
2869 fd2 = open_data.ret;
2881 eargp->redirect_fds = check_exec_fds(eargp);
2883 ary = eargp->fd_dup2;
2885 rb_execarg_allocate_dup2_tmpbuf(eargp,
RARRAY_LEN(ary));
2888 unsetenv_others = eargp->unsetenv_others_given && eargp->unsetenv_others_do;
2889 envopts = eargp->env_modification;
2890 if (ALWAYS_NEED_ENVP || unsetenv_others || envopts !=
Qfalse) {
2891 VALUE envtbl, envp_str, envp_buf;
2893 if (unsetenv_others) {
2894 envtbl = rb_hash_new();
2897 envtbl = rb_env_to_hash();
2901 st_table *stenv = RHASH_TBL_RAW(envtbl);
2908 st_data_t stkey = (st_data_t)key;
2909 st_delete(stenv, &stkey, NULL);
2912 st_insert(stenv, (st_data_t)key, (st_data_t)val);
2918 envp_buf = rb_str_buf_new(0);
2920 rb_hash_stlike_foreach(envtbl, fill_envp_buf_i, (st_data_t)envp_buf);
2921 envp_str = rb_str_buf_new(
sizeof(
char*) * (
RHASH_SIZE(envtbl) + 1));
2923 p = RSTRING_PTR(envp_buf);
2924 ep = p + RSTRING_LEN(envp_buf);
2932 rb_imemo_tmpbuf_auto_free_pointer_new_from_an_RString(envp_str);
2933 eargp->envp_buf = envp_buf;
2949rb_execarg_parent_start(
VALUE execarg_obj)
2952 rb_protect(rb_execarg_parent_start1, execarg_obj, &state);
2954 rb_execarg_parent_end(execarg_obj);
2960execarg_parent_end(
VALUE execarg_obj)
2962 struct rb_execarg *eargp = rb_execarg_get(execarg_obj);
2966 ary = eargp->fd_open;
2977 parent_redirect_close(fd2);
2989rb_execarg_parent_end(
VALUE execarg_obj)
2991 execarg_parent_end(execarg_obj);
2996rb_exec_fail(
struct rb_execarg *eargp,
int err,
const char *errmsg)
2998 if (!errmsg || !*errmsg)
return;
2999 if (strcmp(errmsg,
"chdir") == 0) {
3000 rb_sys_fail_str(eargp->chdir_dir);
3002 rb_sys_fail(errmsg);
3007rb_execarg_fail(
VALUE execarg_obj,
int err,
const char *errmsg)
3009 if (!errmsg || !*errmsg)
return;
3010 rb_exec_fail(rb_execarg_get(execarg_obj), err, errmsg);
3018 VALUE execarg_obj, fail_str;
3020#define CHILD_ERRMSG_BUFLEN 80
3021 char errmsg[CHILD_ERRMSG_BUFLEN] = {
'\0' };
3024 execarg_obj = rb_execarg_new(argc, argv, TRUE, FALSE);
3025 eargp = rb_execarg_get(execarg_obj);
3028 rb_protect(rb_execarg_parent_start1, execarg_obj, &state);
3030 execarg_parent_end(execarg_obj);
3035 fail_str = eargp->use_shell ? eargp->invoke.sh.shell_script : eargp->invoke.cmd.command_name;
3037 err = exec_async_signal_safe(eargp, errmsg,
sizeof(errmsg));
3040 rb_exec_fail(eargp, err, errmsg);
3142#define ERRMSG(str) do { if (errmsg && 0 < errmsg_buflen) strlcpy(errmsg, (str), errmsg_buflen); } while (0)
3143#define ERRMSG1(str, a) do { if (errmsg && 0 < errmsg_buflen) snprintf(errmsg, errmsg_buflen, (str), (a)); } while (0)
3144#define ERRMSG2(str, a, b) do { if (errmsg && 0 < errmsg_buflen) snprintf(errmsg, errmsg_buflen, (str), (a), (b)); } while (0)
3146static int fd_get_cloexec(
int fd,
char *errmsg,
size_t errmsg_buflen);
3147static int fd_set_cloexec(
int fd,
char *errmsg,
size_t errmsg_buflen);
3148static int fd_clear_cloexec(
int fd,
char *errmsg,
size_t errmsg_buflen);
3151save_redirect_fd(
int fd,
struct rb_execarg *sargp,
char *errmsg,
size_t errmsg_buflen)
3154 VALUE newary, redirection;
3155 int save_fd = redirect_cloexec_dup(fd), cloexec;
3156 if (save_fd == -1) {
3163 newary = sargp->fd_dup2;
3165 newary = hide_obj(rb_ary_new());
3166 sargp->fd_dup2 = newary;
3168 cloexec = fd_get_cloexec(fd, errmsg, errmsg_buflen);
3169 redirection = hide_obj(rb_assoc_new(
INT2FIX(fd),
INT2FIX(save_fd)));
3170 if (cloexec) rb_ary_push(redirection,
Qtrue);
3171 rb_ary_push(newary, redirection);
3173 newary = sargp->fd_close;
3175 newary = hide_obj(rb_ary_new());
3176 sargp->fd_close = newary;
3178 rb_ary_push(newary, hide_obj(rb_assoc_new(
INT2FIX(save_fd),
Qnil)));
3185intcmp(
const void *a,
const void *b)
3187 return *(
int*)a - *(
int*)b;
3191intrcmp(
const void *a,
const void *b)
3193 return *(
int*)b - *(
int*)a;
3205run_exec_dup2_tmpbuf_size(
long n)
3212fd_get_cloexec(
int fd,
char *errmsg,
size_t errmsg_buflen)
3216 ret = fcntl(fd, F_GETFD);
3218 ERRMSG(
"fcntl(F_GETFD)");
3221 if (ret & FD_CLOEXEC)
return 1;
3228fd_set_cloexec(
int fd,
char *errmsg,
size_t errmsg_buflen)
3232 ret = fcntl(fd, F_GETFD);
3234 ERRMSG(
"fcntl(F_GETFD)");
3237 if (!(ret & FD_CLOEXEC)) {
3239 ret = fcntl(fd, F_SETFD, ret);
3241 ERRMSG(
"fcntl(F_SETFD)");
3251fd_clear_cloexec(
int fd,
char *errmsg,
size_t errmsg_buflen)
3255 ret = fcntl(fd, F_GETFD);
3257 ERRMSG(
"fcntl(F_GETFD)");
3260 if (ret & FD_CLOEXEC) {
3262 ret = fcntl(fd, F_SETFD, ret);
3264 ERRMSG(
"fcntl(F_SETFD)");
3274run_exec_dup2(
VALUE ary,
VALUE tmpbuf,
struct rb_execarg *sargp,
char *errmsg,
size_t errmsg_buflen)
3285 for (i = 0; i < n; i++) {
3290 pairs[i].older_index = -1;
3300 for (i = 0; i < n; i++) {
3301 int newfd = pairs[i].newfd;
3305 pairs[i].num_newer = 0;
3307 while (pairs < found && (found-1)->oldfd == newfd)
3309 while (found < pairs+n && found->oldfd == newfd) {
3310 pairs[i].num_newer++;
3311 found->older_index = i;
3318 for (i = 0; i < n; i++) {
3320 while (j != -1 && pairs[j].oldfd != -1 && pairs[j].num_newer == 0) {
3321 if (save_redirect_fd(pairs[j].newfd, sargp, errmsg, errmsg_buflen) < 0)
3323 ret = redirect_dup2(pairs[j].oldfd, pairs[j].newfd);
3328 if (pairs[j].cloexec &&
3329 fd_set_cloexec(pairs[j].newfd, errmsg, errmsg_buflen)) {
3333 pairs[j].oldfd = -1;
3334 j = pairs[j].older_index;
3336 pairs[j].num_newer--;
3341 for (i = 0; i < n; i++) {
3343 if (pairs[i].oldfd == -1)
3345 if (pairs[i].oldfd == pairs[i].newfd) {
3346 if (fd_clear_cloexec(pairs[i].oldfd, errmsg, errmsg_buflen) == -1)
3348 pairs[i].oldfd = -1;
3351 if (extra_fd == -1) {
3352 extra_fd = redirect_dup(pairs[i].oldfd);
3353 if (extra_fd == -1) {
3359 if (fd_get_cloexec(pairs[i].oldfd, errmsg, errmsg_buflen)) {
3360 if (fd_set_cloexec(extra_fd, errmsg, errmsg_buflen)) {
3367 ret = redirect_dup2(pairs[i].oldfd, extra_fd);
3374 pairs[i].oldfd = extra_fd;
3375 j = pairs[i].older_index;
3376 pairs[i].older_index = -1;
3378 ret = redirect_dup2(pairs[j].oldfd, pairs[j].newfd);
3384 pairs[j].oldfd = -1;
3385 j = pairs[j].older_index;
3388 if (extra_fd != -1) {
3389 ret = redirect_close(extra_fd);
3404run_exec_close(
VALUE ary,
char *errmsg,
size_t errmsg_buflen)
3412 ret = redirect_close(fd);
3423run_exec_dup2_child(
VALUE ary,
struct rb_execarg *sargp,
char *errmsg,
size_t errmsg_buflen)
3433 if (save_redirect_fd(newfd, sargp, errmsg, errmsg_buflen) < 0)
3435 ret = redirect_dup2(oldfd, newfd);
3448run_exec_pgroup(
const struct rb_execarg *eargp,
struct rb_execarg *sargp,
char *errmsg,
size_t errmsg_buflen)
3460 pgroup = eargp->pgroup_pgid;
3466 sargp->pgroup_given = 1;
3467 sargp->pgroup_pgid = getpgrp();
3473 ret = setpgid(getpid(), pgroup);
3474 if (ret == -1) ERRMSG(
"setpgid");
3479#if defined(HAVE_SETRLIMIT) && defined(RLIM2NUM)
3482run_exec_rlimit(
VALUE ary,
struct rb_execarg *sargp,
char *errmsg,
size_t errmsg_buflen)
3491 if (getrlimit(rtype, &rlim) == -1) {
3492 ERRMSG(
"getrlimit");
3496 RLIM2NUM(rlim.rlim_cur),
3497 RLIM2NUM(rlim.rlim_max)));
3498 if (sargp->rlimit_limits ==
Qfalse)
3499 newary = sargp->rlimit_limits = hide_obj(rb_ary_new());
3501 newary = sargp->rlimit_limits;
3502 rb_ary_push(newary, tmp);
3506 if (setrlimit(rtype, &rlim) == -1) {
3507 ERRMSG(
"setrlimit");
3515#if !defined(HAVE_WORKING_FORK)
3519 rb_ary_push(ary, hide_obj(rb_ary_dup(argv[0])));
3528 if (sargp->env_modification ==
Qfalse) {
3529 VALUE env = rb_envtbl();
3531 VALUE ary = hide_obj(rb_ary_new());
3534 sargp->env_modification = ary;
3536 sargp->unsetenv_others_given = 1;
3537 sargp->unsetenv_others_do = 1;
3544#define chdir(p) rb_w32_uchdir(p)
3549rb_execarg_run_options(
const struct rb_execarg *eargp,
struct rb_execarg *sargp,
char *errmsg,
size_t errmsg_buflen)
3556 sargp->redirect_fds =
Qnil;
3560 if (eargp->pgroup_given) {
3561 if (run_exec_pgroup(eargp, sargp, errmsg, errmsg_buflen) == -1)
3566#if defined(HAVE_SETRLIMIT) && defined(RLIM2NUM)
3567 obj = eargp->rlimit_limits;
3569 if (run_exec_rlimit(obj, sargp, errmsg, errmsg_buflen) == -1)
3574#if !defined(HAVE_WORKING_FORK)
3575 if (eargp->unsetenv_others_given && eargp->unsetenv_others_do) {
3580 obj = eargp->env_modification;
3596 if (eargp->umask_given) {
3597 mode_t mask = eargp->umask_mask;
3598 mode_t oldmask = umask(mask);
3600 sargp->umask_given = 1;
3601 sargp->umask_mask = oldmask;
3605 obj = eargp->fd_dup2;
3607 if (run_exec_dup2(obj, eargp->dup2_tmpbuf, sargp, errmsg, errmsg_buflen) == -1)
3611 obj = eargp->fd_close;
3614 rb_warn(
"cannot close fd before spawn");
3616 if (run_exec_close(obj, errmsg, errmsg_buflen) == -1)
3621#ifdef HAVE_WORKING_FORK
3622 if (eargp->close_others_do) {
3627 obj = eargp->fd_dup2_child;
3629 if (run_exec_dup2_child(obj, sargp, errmsg, errmsg_buflen) == -1)
3633 if (eargp->chdir_given) {
3635 sargp->chdir_given = 1;
3636 sargp->chdir_dir = hide_obj(rb_dir_getwd_ospath());
3638 if (chdir(RSTRING_PTR(eargp->chdir_dir)) == -1) {
3645 if (eargp->gid_given) {
3646 if (setgid(eargp->gid) < 0) {
3653 if (eargp->uid_given) {
3654 if (setuid(eargp->uid) < 0) {
3662 VALUE ary = sargp->fd_dup2;
3664 rb_execarg_allocate_dup2_tmpbuf(sargp,
RARRAY_LEN(ary));
3668 int preserve =
errno;
3669 stdfd_clear_nonblock();
3678rb_exec_async_signal_safe(
const struct rb_execarg *eargp,
char *errmsg,
size_t errmsg_buflen)
3680 errno = exec_async_signal_safe(eargp, errmsg, errmsg_buflen);
3685exec_async_signal_safe(
const struct rb_execarg *eargp,
char *errmsg,
size_t errmsg_buflen)
3687#if !defined(HAVE_WORKING_FORK)
3688 struct rb_execarg sarg, *
const sargp = &sarg;
3694 if (rb_execarg_run_options(eargp, sargp, errmsg, errmsg_buflen) < 0) {
3698 if (eargp->use_shell) {
3699 err = proc_exec_sh(RSTRING_PTR(eargp->invoke.sh.shell_script), eargp->envp_str);
3702 char *abspath = NULL;
3703 if (!
NIL_P(eargp->invoke.cmd.command_abspath))
3704 abspath = RSTRING_PTR(eargp->invoke.cmd.command_abspath);
3705 err = proc_exec_cmd(abspath, eargp->invoke.cmd.argv_str, eargp->envp_str);
3707#if !defined(HAVE_WORKING_FORK)
3708 rb_execarg_run_options(sargp, NULL, errmsg, errmsg_buflen);
3714#ifdef HAVE_WORKING_FORK
3717rb_exec_atfork(
void* arg,
char *errmsg,
size_t errmsg_buflen)
3719 return rb_exec_async_signal_safe(arg, errmsg, errmsg_buflen);
3723proc_syswait(
VALUE pid)
3730move_fds_to_avoid_crash(
int *fdp,
int n,
VALUE fds)
3734 for (i = 0; i < n; i++) {
3753pipe_nocrash(
int filedes[2],
VALUE fds)
3761 if (move_fds_to_avoid_crash(filedes, 2, fds) == -1) {
3776rb_thread_sleep_that_takes_VALUE_as_sole_argument(
VALUE n)
3783handle_fork_error(
int err,
struct rb_process_status *status,
int *ep,
volatile int *try_gc_p)
3789 if ((*try_gc_p)-- > 0 && !rb_during_gc()) {
3795#if defined(EWOULDBLOCK) && EWOULDBLOCK != EAGAIN
3798 if (!status && !ep) {
3803 rb_protect(rb_thread_sleep_that_takes_VALUE_as_sole_argument,
INT2FIX(1), &state);
3804 if (status) status->status = state;
3805 if (!state)
return 0;
3814 if (state && !status) rb_jump_tag(state);
3818#define prefork() ( \
3819 rb_io_flush(rb_stdout), \
3820 rb_io_flush(rb_stderr) \
3850write_retry(
int fd,
const void *buf,
size_t len)
3855 w = write(fd, buf,
len);
3856 }
while (w < 0 &&
errno == EINTR);
3862read_retry(
int fd,
void *buf,
size_t len)
3866 if (set_blocking(fd) != 0) {
3868 rb_async_bug_errno(
"set_blocking failed reading child error",
errno);
3873 r = read(fd, buf,
len);
3874 }
while (r < 0 &&
errno == EINTR);
3880send_child_error(
int fd,
char *errmsg,
size_t errmsg_buflen)
3885 if (write_retry(fd, &err,
sizeof(err)) < 0) err =
errno;
3886 if (errmsg && 0 < errmsg_buflen) {
3887 errmsg[errmsg_buflen-1] =
'\0';
3888 errmsg_buflen = strlen(errmsg);
3889 if (errmsg_buflen > 0 && write_retry(fd, errmsg, errmsg_buflen) < 0)
3895recv_child_error(
int fd,
int *errp,
char *errmsg,
size_t errmsg_buflen)
3899 if ((size = read_retry(fd, &err,
sizeof(err))) < 0) {
3903 if (size ==
sizeof(err) &&
3904 errmsg && 0 < errmsg_buflen) {
3905 ssize_t ret = read_retry(fd, errmsg, errmsg_buflen-1);
3914#ifdef HAVE_WORKING_VFORK
3915#if !defined(HAVE_GETRESUID) && defined(HAVE_GETUIDX)
3918getresuid(rb_uid_t *ruid, rb_uid_t *euid, rb_uid_t *suid)
3924 ret = getuidx(ID_SAVED);
3925 if (ret == (rb_uid_t)-1)
3930#define HAVE_GETRESUID
3933#if !defined(HAVE_GETRESGID) && defined(HAVE_GETGIDX)
3936getresgid(rb_gid_t *rgid, rb_gid_t *egid, rb_gid_t *sgid)
3942 ret = getgidx(ID_SAVED);
3943 if (ret == (rb_gid_t)-1)
3948#define HAVE_GETRESGID
3966 rb_uid_t ruid, euid;
3967 rb_gid_t rgid, egid;
3969#if defined HAVE_ISSETUGID
3974#ifdef HAVE_GETRESUID
3978 ret = getresuid(&ruid, &euid, &suid);
3980 rb_sys_fail(
"getresuid(2)");
3989 if (euid == 0 || euid != ruid)
3992#ifdef HAVE_GETRESGID
3996 ret = getresgid(&rgid, &egid, &sgid);
3998 rb_sys_fail(
"getresgid(2)");
4014struct child_handler_disabler_state
4020disable_child_handler_before_fork(
struct child_handler_disabler_state *old)
4022#ifdef HAVE_PTHREAD_SIGMASK
4026 ret = sigfillset(&all);
4028 rb_sys_fail(
"sigfillset");
4030 ret = pthread_sigmask(SIG_SETMASK, &all, &old->sigmask);
4035# pragma GCC warning "pthread_sigmask on fork is not available. potentially dangerous"
4040disable_child_handler_fork_parent(
struct child_handler_disabler_state *old)
4042#ifdef HAVE_PTHREAD_SIGMASK
4045 ret = pthread_sigmask(SIG_SETMASK, &old->sigmask, NULL);
4050# pragma GCC warning "pthread_sigmask on fork is not available. potentially dangerous"
4056disable_child_handler_fork_child(
struct child_handler_disabler_state *old,
char *errmsg,
size_t errmsg_buflen)
4061 for (sig = 1; sig < NSIG; sig++) {
4062 sig_t handler = signal(sig, SIG_DFL);
4064 if (handler == SIG_ERR &&
errno == EINVAL) {
4067 if (handler == SIG_ERR) {
4068 ERRMSG(
"signal to obtain old action");
4072 if (sig == SIGPIPE) {
4077 if (handler == SIG_IGN) {
4078 signal(sig, SIG_IGN);
4083 sigemptyset(&old->sigmask);
4084 ret = sigprocmask(SIG_SETMASK, &old->sigmask, NULL);
4086 ERRMSG(
"sigprocmask");
4094 int (*chfunc)(
void*,
char *,
size_t),
void *charg,
4095 char *errmsg,
size_t errmsg_buflen,
4099 volatile int try_gc = 1;
4100 struct child_handler_disabler_state old;
4105 disable_child_handler_before_fork(&old);
4106#ifdef HAVE_WORKING_VFORK
4107 if (!has_privilege())
4117 ret = disable_child_handler_fork_child(&old, errmsg, errmsg_buflen);
4119 ret = chfunc(charg, errmsg, errmsg_buflen);
4120 if (!ret) _exit(EXIT_SUCCESS);
4122 send_child_error(ep[1], errmsg, errmsg_buflen);
4123#if EXIT_SUCCESS == 127
4124 _exit(EXIT_FAILURE);
4130 disable_child_handler_fork_parent(&old);
4134 if (handle_fork_error(err, status, ep, &try_gc))
4140fork_check_err(
struct rb_process_status *status,
int (*chfunc)(
void*,
char *,
size_t),
void *charg,
4141 VALUE fds,
char *errmsg,
size_t errmsg_buflen,
4149 struct waitpid_state *w = eargp && eargp->waitpid_state ? eargp->waitpid_state : 0;
4151 if (status) status->status = 0;
4153 if (pipe_nocrash(ep, fds))
return -1;
4155 pid = retry_fork_async_signal_safe(status, ep, chfunc, charg, errmsg, errmsg_buflen, w);
4157 if (status) status->pid = pid;
4160 if (status) status->error =
errno;
4167 error_occurred = recv_child_error(ep[0], &err, errmsg, errmsg_buflen);
4169 if (error_occurred) {
4172 status->error = err;
4174 VM_ASSERT((w == 0) &&
"only used by extensions");
4175 rb_protect(proc_syswait, (
VALUE)pid, &state);
4177 status->status = state;
4198rb_fork_async_signal_safe(
int *status,
4199 int (*chfunc)(
void*,
char *,
size_t),
void *charg,
4200 VALUE fds,
char *errmsg,
size_t errmsg_buflen)
4204 rb_pid_t result = fork_check_err(&process_status, chfunc, charg, fds, errmsg, errmsg_buflen, 0);
4207 *status = process_status.status;
4217 int try_gc = 1, err;
4218 struct child_handler_disabler_state old;
4220 if (status) status->status = 0;
4226 disable_child_handler_before_fork(&old);
4232 status->error = err;
4235 disable_child_handler_fork_parent(&old);
4236 after_fork_ruby(pid);
4243 if (handle_fork_error(err, status, NULL, &try_gc)) {
4250rb_fork_ruby(
int *status)
4254 rb_pid_t pid = rb_fork_ruby2(&process_status);
4256 if (status) *status = process_status.status;
4264 rb_pid_t pid = rb_fork_ruby(NULL);
4267 rb_sys_fail(
"fork(2)");
4274rb_call_proc__fork(
void)
4279 return proc_fork_pid();
4288#if defined(HAVE_WORKING_FORK) && !defined(CANNOT_FORK_WITH_PTHREAD)
4309rb_proc__fork(
VALUE _obj)
4311 rb_pid_t pid = proc_fork_pid();
4380 pid = rb_call_proc__fork();
4394#define rb_proc__fork rb_f_notimplement
4395#define rb_f_fork rb_f_notimplement
4399exit_status_code(
VALUE status)
4405 istatus = EXIT_SUCCESS;
4408 istatus = EXIT_FAILURE;
4412#if EXIT_SUCCESS != 0
4414 istatus = EXIT_SUCCESS;
4421NORETURN(
static VALUE rb_f_exit_bang(
int argc,
VALUE *argv,
VALUE obj));
4439rb_f_exit_bang(
int argc,
VALUE *argv,
VALUE obj)
4444 istatus = exit_status_code(argv[0]);
4447 istatus = EXIT_FAILURE;
4457 if (GET_EC()->tag) {
4473 istatus = exit_status_code(argv[0]);
4476 istatus = EXIT_SUCCESS;
4542 VALUE errinfo = rb_ec_get_errinfo(ec);
4543 if (!
NIL_P(errinfo)) {
4544 rb_ec_error_print(ec, errinfo);
4551 args[1] = args[0] = argv[0];
4553 rb_io_puts(1, args, rb_ractor_stderr());
4554 args[0] =
INT2NUM(EXIT_FAILURE);
4592#if !defined HAVE_WORKING_FORK && !defined HAVE_SPAWNV && !defined __EMSCRIPTEN__
4597 if (eargp && !eargp->use_shell) {
4598 VALUE str = eargp->invoke.cmd.argv_str;
4599 VALUE buf = eargp->invoke.cmd.argv_buf;
4600 char *p, **argv = ARGVSTR2ARGV(str);
4601 long i, argc = ARGVSTR2ARGC(str);
4602 const char *start = RSTRING_PTR(buf);
4604 p = RSTRING_PTR(cmd);
4605 for (i = 1; i < argc; ++i) {
4606 p[argv[i] - start - 1] =
' ';
4616rb_spawn_process(
struct rb_execarg *eargp,
char *errmsg,
size_t errmsg_buflen)
4619#if !defined HAVE_WORKING_FORK || USE_SPAWNV
4622# if !defined HAVE_SPAWNV
4627#if defined HAVE_WORKING_FORK && !USE_SPAWNV
4628 pid = fork_check_err(eargp->status, rb_exec_atfork, eargp, eargp->redirect_fds, errmsg, errmsg_buflen, eargp);
4630 prog = eargp->use_shell ? eargp->invoke.sh.shell_script : eargp->invoke.cmd.command_name;
4632 if (rb_execarg_run_options(eargp, &sarg, errmsg, errmsg_buflen) < 0) {
4636 if (prog && !eargp->use_shell) {
4637 char **argv = ARGVSTR2ARGV(eargp->invoke.cmd.argv_str);
4638 argv[0] = RSTRING_PTR(prog);
4640# if defined HAVE_SPAWNV
4641 if (eargp->use_shell) {
4642 pid = proc_spawn_sh(RSTRING_PTR(prog));
4645 char **argv = ARGVSTR2ARGV(eargp->invoke.cmd.argv_str);
4646 pid = proc_spawn_cmd(argv, prog, eargp);
4653 status = system(rb_execarg_commandline(eargp, &prog));
4658 if (eargp->waitpid_state) {
4659 eargp->waitpid_state->pid = pid;
4662 rb_execarg_run_options(&sarg, NULL, errmsg, errmsg_buflen);
4677do_spawn_process(
VALUE arg)
4681 rb_execarg_parent_start1(argp->execarg);
4683 return (
VALUE)rb_spawn_process(rb_execarg_get(argp->execarg),
4684 argp->errmsg.ptr, argp->errmsg.buflen);
4687NOINLINE(
static rb_pid_t
4688 rb_execarg_spawn(
VALUE execarg_obj,
char *errmsg,
size_t errmsg_buflen));
4691rb_execarg_spawn(
VALUE execarg_obj,
char *errmsg,
size_t errmsg_buflen)
4695 args.execarg = execarg_obj;
4696 args.errmsg.ptr = errmsg;
4697 args.errmsg.buflen = errmsg_buflen;
4700 execarg_parent_end, execarg_obj);
4705rb_spawn_internal(
int argc,
const VALUE *argv,
char *errmsg,
size_t errmsg_buflen)
4709 execarg_obj = rb_execarg_new(argc, argv, TRUE, FALSE);
4710 return rb_execarg_spawn(execarg_obj, errmsg, errmsg_buflen);
4716 return rb_spawn_internal(argc, argv, errmsg, errmsg_buflen);
4722 return rb_spawn_internal(argc, argv, NULL, 0);
4845 VALUE execarg_obj = rb_execarg_new(argc, argv, TRUE, TRUE);
4846 struct rb_execarg *eargp = rb_execarg_get(execarg_obj);
4849 eargp->status = &status;
4851 last_status_clear(th);
4855 rb_pid_t pid = rb_execarg_spawn(execarg_obj, 0, 0);
4861 rb_obj_freeze(status);
4862 th->last_status = status;
4864 if (data->status == EXIT_SUCCESS) {
4868 if (data->error != 0) {
4869 if (eargp->exception) {
4870 VALUE command = eargp->invoke.sh.shell_script;
4878 else if (eargp->exception) {
4879 VALUE command = eargp->invoke.sh.shell_script;
4893 if (eargp->exception) {
4894 VALUE command = eargp->invoke.sh.shell_script;
5016 char errmsg[CHILD_ERRMSG_BUFLEN] = {
'\0' };
5017 VALUE execarg_obj, fail_str;
5020 execarg_obj = rb_execarg_new(argc, argv, TRUE, FALSE);
5021 eargp = rb_execarg_get(execarg_obj);
5022 fail_str = eargp->use_shell ? eargp->invoke.sh.shell_script : eargp->invoke.cmd.command_name;
5024 pid = rb_execarg_spawn(execarg_obj, errmsg,
sizeof(errmsg));
5028 rb_exec_fail(eargp, err, errmsg);
5032#if defined(HAVE_WORKING_FORK) || defined(HAVE_SPAWNV)
5058 time_t beg = time(0);
5061 if (scheduler !=
Qnil) {
5065 if (argc == 0 || (argc == 1 &&
NIL_P(argv[0]))) {
5074 time_t end = time(0) - beg;
5076 return TIMET2NUM(end);
5080#if (defined(HAVE_GETPGRP) && defined(GETPGRP_VOID)) || defined(HAVE_GETPGID)
5097#if defined(HAVE_GETPGRP) && defined(GETPGRP_VOID)
5099 if (pgrp < 0) rb_sys_fail(0);
5103 if (pgrp < 0) rb_sys_fail(0);
5108#define proc_getpgrp rb_f_notimplement
5112#if defined(HAVE_SETPGID) || (defined(HAVE_SETPGRP) && defined(SETPGRP_VOID))
5130 if (setpgid(0,0) < 0) rb_sys_fail(0);
5131#elif defined(HAVE_SETPGRP) && defined(SETPGRP_VOID)
5132 if (setpgrp() < 0) rb_sys_fail(0);
5137#define proc_setpgrp rb_f_notimplement
5141#if defined(HAVE_GETPGID)
5159 if (i < 0) rb_sys_fail(0);
5163#define proc_getpgid rb_f_notimplement
5181 rb_pid_t ipid, ipgrp;
5186 if (setpgid(ipid, ipgrp) < 0) rb_sys_fail(0);
5190#define proc_setpgid rb_f_notimplement
5218 if (sid < 0) rb_sys_fail(0);
5222#define proc_getsid rb_f_notimplement
5226#if defined(HAVE_SETSID) || (defined(HAVE_SETPGRP) && defined(TIOCNOTTY))
5227#if !defined(HAVE_SETSID)
5228static rb_pid_t ruby_setsid(
void);
5229#define setsid() ruby_setsid()
5250 if (pid < 0) rb_sys_fail(0);
5254#if !defined(HAVE_SETSID)
5255#define HAVE_SETSID 1
5263#if defined(SETPGRP_VOID)
5269 ret = setpgrp(0, pid);
5271 if (ret == -1)
return -1;
5275 ioctl(fd, TIOCNOTTY, NULL);
5282#define proc_setsid rb_f_notimplement
5286#ifdef HAVE_GETPRIORITY
5314 int prio, iwhich, iwho;
5320 prio = getpriority(iwhich, iwho);
5321 if (
errno) rb_sys_fail(0);
5325#define proc_getpriority rb_f_notimplement
5329#ifdef HAVE_GETPRIORITY
5349 int iwhich, iwho, iprio;
5355 if (setpriority(iwhich, iwho, iprio) < 0)
5360#define proc_setpriority rb_f_notimplement
5363#if defined(HAVE_SETRLIMIT) && defined(NUM2RLIM)
5365rlimit_resource_name2int(
const char *name,
long len,
int casetype)
5369#define RESCHECK(r) \
5371 if (len == rb_strlen_lit(#r) && STRCASECMP(name, #r) == 0) { \
5372 resource = RLIMIT_##r; \
5406#ifdef RLIMIT_MEMLOCK
5409#ifdef RLIMIT_MSGQUEUE
5448#ifdef RLIMIT_SIGPENDING
5449 RESCHECK(SIGPENDING);
5458 for (p = name; *p; p++)
5464 for (p = name; *p; p++)
5470 rb_bug(
"unexpected casetype");
5477rlimit_type_by_hname(
const char *name,
long len)
5479 return rlimit_resource_name2int(name,
len, 0);
5483rlimit_type_by_lname(
const char *name,
long len)
5485 return rlimit_resource_name2int(name,
len, 1);
5489rlimit_type_by_sym(
VALUE key)
5492 const char *rname = RSTRING_PTR(name);
5493 long len = RSTRING_LEN(name);
5495 static const char prefix[] =
"rlimit_";
5496 enum {prefix_len =
sizeof(prefix)-1};
5498 if (
len > prefix_len && strncmp(prefix, rname, prefix_len) == 0) {
5499 rtype = rlimit_type_by_lname(rname + prefix_len,
len - prefix_len);
5507rlimit_resource_type(
VALUE rtype)
5514 switch (
TYPE(rtype)) {
5517 name = RSTRING_PTR(v);
5518 len = RSTRING_LEN(v);
5527 len = RSTRING_LEN(rtype);
5537 r = rlimit_type_by_hname(name,
len);
5541 rb_raise(rb_eArgError,
"invalid resource name: % "PRIsVALUE, rtype);
5547rlimit_resource_value(
VALUE rval)
5552 switch (
TYPE(rval)) {
5555 name = RSTRING_PTR(v);
5570 return NUM2RLIM(rval);
5574 if (strcmp(name,
"INFINITY") == 0)
return RLIM_INFINITY;
5576#ifdef RLIM_SAVED_MAX
5577 if (strcmp(name,
"SAVED_MAX") == 0)
return RLIM_SAVED_MAX;
5579#ifdef RLIM_SAVED_CUR
5580 if (strcmp(name,
"SAVED_CUR") == 0)
return RLIM_SAVED_CUR;
5582 rb_raise(rb_eArgError,
"invalid resource value: %"PRIsVALUE, rval);
5588#if defined(HAVE_GETRLIMIT) && defined(RLIM2NUM)
5616 if (getrlimit(rlimit_resource_type(resource), &rlim) < 0) {
5617 rb_sys_fail(
"getrlimit");
5619 return rb_assoc_new(RLIM2NUM(rlim.rlim_cur), RLIM2NUM(rlim.rlim_max));
5622#define proc_getrlimit rb_f_notimplement
5625#if defined(HAVE_SETRLIMIT) && defined(NUM2RLIM)
5679proc_setrlimit(
int argc,
VALUE *argv,
VALUE obj)
5681 VALUE resource, rlim_cur, rlim_max;
5687 if (argc < 3 ||
NIL_P(rlim_max = argv[2]))
5688 rlim_max = rlim_cur;
5690 rlim.rlim_cur = rlimit_resource_value(rlim_cur);
5691 rlim.rlim_max = rlimit_resource_value(rlim_max);
5693 if (setrlimit(rlimit_resource_type(resource), &rlim) < 0) {
5694 rb_sys_fail(
"setrlimit");
5699#define proc_setrlimit rb_f_notimplement
5702static int under_uid_switch = 0;
5704check_uid_switch(
void)
5706 if (under_uid_switch) {
5707 rb_raise(
rb_eRuntimeError,
"can't handle UID while evaluating block given to Process::UID.switch method");
5711static int under_gid_switch = 0;
5713check_gid_switch(
void)
5715 if (under_gid_switch) {
5716 rb_raise(
rb_eRuntimeError,
"can't handle GID while evaluating block given to Process::UID.switch method");
5721#if defined(HAVE_PWD_H)
5730#if ( !defined(USE_GETLOGIN_R) && !defined(USE_GETLOGIN) )
5733 char MAYBE_UNUSED(*login) = NULL;
5735# ifdef USE_GETLOGIN_R
5737#if defined(__FreeBSD__)
5738 typedef int getlogin_r_size_t;
5740 typedef size_t getlogin_r_size_t;
5743 long loginsize = GETLOGIN_R_SIZE_INIT;
5746 loginsize = GETLOGIN_R_SIZE_DEFAULT;
5748 VALUE maybe_result = rb_str_buf_new(loginsize);
5750 login = RSTRING_PTR(maybe_result);
5752 rb_str_set_len(maybe_result, loginsize);
5756 while ((gle = getlogin_r(login, (getlogin_r_size_t)loginsize)) != 0) {
5758 if (gle == ENOTTY || gle == ENXIO || gle == ENOENT) {
5759 rb_str_resize(maybe_result, 0);
5763 if (gle != ERANGE || loginsize >= GETLOGIN_R_SIZE_LIMIT) {
5764 rb_str_resize(maybe_result, 0);
5769 login = RSTRING_PTR(maybe_result);
5773 if (login == NULL) {
5774 rb_str_resize(maybe_result, 0);
5778 return maybe_result;
5798rb_getpwdirnam_for_login(
VALUE login_name)
5800#if ( !defined(USE_GETPWNAM_R) && !defined(USE_GETPWNAM) )
5804 if (
NIL_P(login_name)) {
5809 char *login = RSTRING_PTR(login_name);
5811 struct passwd *pwptr;
5813# ifdef USE_GETPWNAM_R
5815 struct passwd pwdnm;
5817 long bufsizenm = GETPW_R_SIZE_INIT;
5820 bufsizenm = GETPW_R_SIZE_DEFAULT;
5824 bufnm = RSTRING_PTR(getpwnm_tmp);
5826 rb_str_set_len(getpwnm_tmp, bufsizenm);
5830 while ((enm = getpwnam_r(login, &pwdnm, bufnm, bufsizenm, &pwptr)) != 0) {
5832 if (enm == ENOENT || enm== ESRCH || enm == EBADF || enm == EPERM) {
5834 rb_str_resize(getpwnm_tmp, 0);
5838 if (enm != ERANGE || bufsizenm >= GETPW_R_SIZE_LIMIT) {
5839 rb_str_resize(getpwnm_tmp, 0);
5844 bufnm = RSTRING_PTR(getpwnm_tmp);
5848 if (pwptr == NULL) {
5850 rb_str_resize(getpwnm_tmp, 0);
5856 rb_str_resize(getpwnm_tmp, 0);
5862 pwptr = getpwnam(login);
5885# if !defined(USE_GETPWUID_R) && !defined(USE_GETPWUID)
5889 uid_t ruid = getuid();
5891 struct passwd *pwptr;
5893# ifdef USE_GETPWUID_R
5895 struct passwd pwdid;
5897 long bufsizeid = GETPW_R_SIZE_INIT;
5900 bufsizeid = GETPW_R_SIZE_DEFAULT;
5904 bufid = RSTRING_PTR(getpwid_tmp);
5906 rb_str_set_len(getpwid_tmp, bufsizeid);
5910 while ((eid = getpwuid_r(ruid, &pwdid, bufid, bufsizeid, &pwptr)) != 0) {
5912 if (eid == ENOENT || eid== ESRCH || eid == EBADF || eid == EPERM) {
5914 rb_str_resize(getpwid_tmp, 0);
5918 if (eid != ERANGE || bufsizeid >= GETPW_R_SIZE_LIMIT) {
5919 rb_str_resize(getpwid_tmp, 0);
5924 bufid = RSTRING_PTR(getpwid_tmp);
5928 if (pwptr == NULL) {
5930 rb_str_resize(getpwid_tmp, 0);
5936 rb_str_resize(getpwid_tmp, 0);
5939# elif defined(USE_GETPWUID)
5942 pwptr = getpwuid(ruid);
5971#if defined(HAVE_PWD_H)
5974# ifdef USE_GETPWNAM_R
5987 struct passwd *pwptr;
5988#ifdef USE_GETPWNAM_R
5989 struct passwd pwbuf;
5994 getpw_buf_len = GETPW_R_SIZE_INIT;
5995 if (getpw_buf_len < 0) getpw_buf_len = GETPW_R_SIZE_DEFAULT;
5998 getpw_buf = RSTRING_PTR(*getpw_tmp);
6000 rb_str_set_len(*getpw_tmp, getpw_buf_len);
6002 while ((e = getpwnam_r(usrname, &pwbuf, getpw_buf, getpw_buf_len, &pwptr)) != 0) {
6003 if (e != ERANGE || getpw_buf_len >= GETPW_R_SIZE_LIMIT) {
6004 rb_str_resize(*getpw_tmp, 0);
6008 getpw_buf = RSTRING_PTR(*getpw_tmp);
6012 pwptr = getpwnam(usrname);
6015#ifndef USE_GETPWNAM_R
6018 rb_raise(rb_eArgError,
"can't find user for %"PRIsVALUE,
id);
6020 uid = pwptr->pw_uid;
6021#ifndef USE_GETPWNAM_R
6028# ifdef p_uid_from_name
6048#if defined(HAVE_GRP_H)
6051# ifdef USE_GETGRNAM_R
6064 struct group *grptr;
6065#ifdef USE_GETGRNAM_R
6071 getgr_buf_len = GETGR_R_SIZE_INIT;
6072 if (getgr_buf_len < 0) getgr_buf_len = GETGR_R_SIZE_DEFAULT;
6075 getgr_buf = RSTRING_PTR(*getgr_tmp);
6077 rb_str_set_len(*getgr_tmp, getgr_buf_len);
6079 while ((e = getgrnam_r(grpname, &grbuf, getgr_buf, getgr_buf_len, &grptr)) != 0) {
6080 if (e != ERANGE || getgr_buf_len >= GETGR_R_SIZE_LIMIT) {
6081 rb_str_resize(*getgr_tmp, 0);
6085 getgr_buf = RSTRING_PTR(*getgr_tmp);
6088#elif defined(HAVE_GETGRNAM)
6089 grptr = getgrnam(grpname);
6094#if !defined(USE_GETGRNAM_R) && defined(HAVE_ENDGRENT)
6097 rb_raise(rb_eArgError,
"can't find group for %"PRIsVALUE,
id);
6099 gid = grptr->gr_gid;
6100#if !defined(USE_GETGRNAM_R) && defined(HAVE_ENDGRENT)
6107# ifdef p_gid_from_name
6127#if defined HAVE_SETUID
6141 if (setuid(OBJ2UID(
id)) != 0) rb_sys_fail(0);
6145#define p_sys_setuid rb_f_notimplement
6149#if defined HAVE_SETRUID
6163 if (setruid(OBJ2UID(
id)) != 0) rb_sys_fail(0);
6167#define p_sys_setruid rb_f_notimplement
6171#if defined HAVE_SETEUID
6185 if (seteuid(OBJ2UID(
id)) != 0) rb_sys_fail(0);
6189#define p_sys_seteuid rb_f_notimplement
6193#if defined HAVE_SETREUID
6208 rb_uid_t ruid, euid;
6211 ruid = OBJ2UID1(rid);
6212 euid = OBJ2UID1(eid);
6214 if (setreuid(ruid, euid) != 0) rb_sys_fail(0);
6218#define p_sys_setreuid rb_f_notimplement
6222#if defined HAVE_SETRESUID
6237 rb_uid_t ruid, euid, suid;
6240 ruid = OBJ2UID1(rid);
6241 euid = OBJ2UID1(eid);
6242 suid = OBJ2UID1(sid);
6244 if (setresuid(ruid, euid, suid) != 0) rb_sys_fail(0);
6248#define p_sys_setresuid rb_f_notimplement
6265proc_getuid(
VALUE obj)
6267 rb_uid_t uid = getuid();
6272#if defined(HAVE_SETRESUID) || defined(HAVE_SETREUID) || defined(HAVE_SETRUID) || defined(HAVE_SETUID)
6292#if defined(HAVE_SETRESUID)
6293 if (setresuid(uid, -1, -1) < 0) rb_sys_fail(0);
6294#elif defined HAVE_SETREUID
6295 if (setreuid(uid, -1) < 0) rb_sys_fail(0);
6296#elif defined HAVE_SETRUID
6297 if (setruid(uid) < 0) rb_sys_fail(0);
6298#elif defined HAVE_SETUID
6300 if (geteuid() == uid) {
6301 if (setuid(uid) < 0) rb_sys_fail(0);
6311#define proc_setuid rb_f_notimplement
6325static rb_uid_t SAVED_USER_ID = -1;
6327#ifdef BROKEN_SETREUID
6329setreuid(rb_uid_t ruid, rb_uid_t euid)
6331 if (ruid != (rb_uid_t)-1 && ruid != getuid()) {
6332 if (euid == (rb_uid_t)-1) euid = geteuid();
6333 if (setuid(ruid) < 0)
return -1;
6335 if (euid != (rb_uid_t)-1 && euid != geteuid()) {
6336 if (seteuid(euid) < 0)
return -1;
6364 if (geteuid() == 0) {
6365#if defined(HAVE_SETRESUID)
6366 if (setresuid(uid, uid, uid) < 0) rb_sys_fail(0);
6367 SAVED_USER_ID = uid;
6368#elif defined(HAVE_SETUID)
6369 if (setuid(uid) < 0) rb_sys_fail(0);
6370 SAVED_USER_ID = uid;
6371#elif defined(HAVE_SETREUID) && !defined(OBSOLETE_SETREUID)
6372 if (getuid() == uid) {
6373 if (SAVED_USER_ID == uid) {
6374 if (setreuid(-1, uid) < 0) rb_sys_fail(0);
6378 if (setreuid(-1, SAVED_USER_ID) < 0) rb_sys_fail(0);
6379 if (setreuid(SAVED_USER_ID, 0) < 0) rb_sys_fail(0);
6381 if (setreuid(uid, uid) < 0) rb_sys_fail(0);
6382 SAVED_USER_ID = uid;
6385 if (setreuid(0, -1) < 0) rb_sys_fail(0);
6387 if (setreuid(uid, uid) < 0) rb_sys_fail(0);
6388 SAVED_USER_ID = uid;
6393 if (setreuid(uid, uid) < 0) rb_sys_fail(0);
6394 SAVED_USER_ID = uid;
6396#elif defined(HAVE_SETRUID) && defined(HAVE_SETEUID)
6397 if (getuid() == uid) {
6398 if (SAVED_USER_ID == uid) {
6399 if (seteuid(uid) < 0) rb_sys_fail(0);
6403 if (setruid(SAVED_USER_ID) < 0) rb_sys_fail(0);
6405 if (setruid(0) < 0) rb_sys_fail(0);
6408 if (setruid(0) < 0) rb_sys_fail(0);
6410 if (seteuid(uid) < 0) rb_sys_fail(0);
6411 if (setruid(uid) < 0) rb_sys_fail(0);
6412 SAVED_USER_ID = uid;
6417 if (seteuid(uid) < 0) rb_sys_fail(0);
6418 if (setruid(uid) < 0) rb_sys_fail(0);
6419 SAVED_USER_ID = uid;
6427#if defined(HAVE_SETRESUID)
6428 if (setresuid((getuid() == uid)? (rb_uid_t)-1: uid,
6429 (geteuid() == uid)? (rb_uid_t)-1: uid,
6430 (SAVED_USER_ID == uid)? (rb_uid_t)-1: uid) < 0) rb_sys_fail(0);
6431 SAVED_USER_ID = uid;
6432#elif defined(HAVE_SETREUID) && !defined(OBSOLETE_SETREUID)
6433 if (SAVED_USER_ID == uid) {
6434 if (setreuid((getuid() == uid)? (rb_uid_t)-1: uid,
6435 (geteuid() == uid)? (rb_uid_t)-1: uid) < 0)
6438 else if (getuid() != uid) {
6439 if (setreuid(uid, (geteuid() == uid)? (rb_uid_t)-1: uid) < 0)
6441 SAVED_USER_ID = uid;
6443 else if ( geteuid() != uid) {
6444 if (setreuid(geteuid(), uid) < 0) rb_sys_fail(0);
6445 SAVED_USER_ID = uid;
6446 if (setreuid(uid, -1) < 0) rb_sys_fail(0);
6449 if (setreuid(-1, SAVED_USER_ID) < 0) rb_sys_fail(0);
6450 if (setreuid(SAVED_USER_ID, uid) < 0) rb_sys_fail(0);
6451 SAVED_USER_ID = uid;
6452 if (setreuid(uid, -1) < 0) rb_sys_fail(0);
6454#elif defined(HAVE_SETRUID) && defined(HAVE_SETEUID)
6455 if (SAVED_USER_ID == uid) {
6456 if (geteuid() != uid && seteuid(uid) < 0) rb_sys_fail(0);
6457 if (getuid() != uid && setruid(uid) < 0) rb_sys_fail(0);
6459 else if ( geteuid() == uid) {
6460 if (getuid() != uid) {
6461 if (setruid(uid) < 0) rb_sys_fail(0);
6462 SAVED_USER_ID = uid;
6465 if (setruid(SAVED_USER_ID) < 0) rb_sys_fail(0);
6466 SAVED_USER_ID = uid;
6467 if (setruid(uid) < 0) rb_sys_fail(0);
6470 else if ( getuid() == uid) {
6471 if (seteuid(uid) < 0) rb_sys_fail(0);
6472 if (setruid(SAVED_USER_ID) < 0) rb_sys_fail(0);
6473 SAVED_USER_ID = uid;
6474 if (setruid(uid) < 0) rb_sys_fail(0);
6479#elif defined HAVE_44BSD_SETUID
6480 if (getuid() == uid) {
6482 if (setuid(uid) < 0) rb_sys_fail(0);
6483 SAVED_USER_ID = uid;
6488#elif defined HAVE_SETEUID
6489 if (getuid() == uid && SAVED_USER_ID == uid) {
6490 if (seteuid(uid) < 0) rb_sys_fail(0);
6495#elif defined HAVE_SETUID
6496 if (getuid() == uid && SAVED_USER_ID == uid) {
6497 if (setuid(uid) < 0) rb_sys_fail(0);
6511#if defined HAVE_SETGID
6525 if (setgid(OBJ2GID(
id)) != 0) rb_sys_fail(0);
6529#define p_sys_setgid rb_f_notimplement
6533#if defined HAVE_SETRGID
6547 if (setrgid(OBJ2GID(
id)) != 0) rb_sys_fail(0);
6551#define p_sys_setrgid rb_f_notimplement
6555#if defined HAVE_SETEGID
6569 if (setegid(OBJ2GID(
id)) != 0) rb_sys_fail(0);
6573#define p_sys_setegid rb_f_notimplement
6577#if defined HAVE_SETREGID
6592 rb_gid_t rgid, egid;
6594 rgid = OBJ2GID(rid);
6595 egid = OBJ2GID(eid);
6596 if (setregid(rgid, egid) != 0) rb_sys_fail(0);
6600#define p_sys_setregid rb_f_notimplement
6603#if defined HAVE_SETRESGID
6618 rb_gid_t rgid, egid, sgid;
6620 rgid = OBJ2GID(rid);
6621 egid = OBJ2GID(eid);
6622 sgid = OBJ2GID(sid);
6623 if (setresgid(rgid, egid, sgid) != 0) rb_sys_fail(0);
6627#define p_sys_setresgid rb_f_notimplement
6631#if defined HAVE_ISSETUGID
6645p_sys_issetugid(
VALUE obj)
6647 return RBOOL(issetugid());
6650#define p_sys_issetugid rb_f_notimplement
6667proc_getgid(
VALUE obj)
6669 rb_gid_t gid = getgid();
6674#if defined(HAVE_SETRESGID) || defined(HAVE_SETREGID) || defined(HAVE_SETRGID) || defined(HAVE_SETGID)
6693#if defined(HAVE_SETRESGID)
6694 if (setresgid(gid, -1, -1) < 0) rb_sys_fail(0);
6695#elif defined HAVE_SETREGID
6696 if (setregid(gid, -1) < 0) rb_sys_fail(0);
6697#elif defined HAVE_SETRGID
6698 if (setrgid(gid) < 0) rb_sys_fail(0);
6699#elif defined HAVE_SETGID
6701 if (getegid() == gid) {
6702 if (setgid(gid) < 0) rb_sys_fail(0);
6712#define proc_setgid rb_f_notimplement
6716#if defined(_SC_NGROUPS_MAX) || defined(NGROUPS_MAX)
6736static int _maxgroups = -1;
6738get_sc_ngroups_max(
void)
6740#ifdef _SC_NGROUPS_MAX
6741 return (
int)sysconf(_SC_NGROUPS_MAX);
6742#elif defined(NGROUPS_MAX)
6743 return (
int)NGROUPS_MAX;
6751 if (_maxgroups < 0) {
6752 _maxgroups = get_sc_ngroups_max();
6754 _maxgroups = RB_MAX_GROUPS;
6763#ifdef HAVE_GETGROUPS
6787proc_getgroups(
VALUE obj)
6793 ngroups = getgroups(0, NULL);
6797 groups =
ALLOCV_N(rb_gid_t, tmp, ngroups);
6799 ngroups = getgroups(ngroups, groups);
6804 for (i = 0; i < ngroups; i++)
6805 rb_ary_push(ary,
GIDT2NUM(groups[i]));
6812#define proc_getgroups rb_f_notimplement
6816#ifdef HAVE_SETGROUPS
6841 if (ngroups > maxgroups())
6842 rb_raise(rb_eArgError,
"too many groups, %d max", maxgroups());
6844 groups =
ALLOCV_N(rb_gid_t, tmp, ngroups);
6846 for (i = 0; i < ngroups; i++) {
6849 groups[i] = OBJ2GID1(g);
6853 if (setgroups(ngroups, groups) == -1)
6858 return proc_getgroups(obj);
6861#define proc_setgroups rb_f_notimplement
6865#ifdef HAVE_INITGROUPS
6891 return proc_getgroups(obj);
6894#define proc_initgroups rb_f_notimplement
6897#if defined(_SC_NGROUPS_MAX) || defined(NGROUPS_MAX)
6910proc_getmaxgroups(
VALUE obj)
6915#define proc_getmaxgroups rb_f_notimplement
6918#ifdef HAVE_SETGROUPS
6931 int ngroups_max = get_sc_ngroups_max();
6934 rb_raise(rb_eArgError,
"maxgroups %d should be positive", ngroups);
6936 if (ngroups > RB_MAX_GROUPS)
6937 ngroups = RB_MAX_GROUPS;
6939 if (ngroups_max > 0 && ngroups > ngroups_max)
6940 ngroups = ngroups_max;
6942 _maxgroups = ngroups;
6947#define proc_setmaxgroups rb_f_notimplement
6950#if defined(HAVE_DAEMON) || (defined(HAVE_WORKING_FORK) && defined(HAVE_SETSID))
6951static int rb_daemon(
int nochdir,
int noclose);
6976 int n, nochdir = FALSE, noclose = FALSE;
6979 case 2: noclose = TO_BOOL(argv[1],
"noclose");
6980 case 1: nochdir = TO_BOOL(argv[0],
"nochdir");
6984 n = rb_daemon(nochdir, noclose);
6985 if (n < 0) rb_sys_fail(
"daemon");
6989extern const char ruby_null_device[];
6992rb_daemon(
int nochdir,
int noclose)
6997 err = daemon(nochdir, noclose);
7002 switch (rb_fork_ruby(NULL)) {
7005 default: _exit(EXIT_SUCCESS);
7009 if (setsid() < 0) (void)0;
7014 if (!noclose && (n =
rb_cloexec_open(ruby_null_device, O_RDWR, 0)) != -1) {
7026#define proc_daemon rb_f_notimplement
7039static rb_gid_t SAVED_GROUP_ID = -1;
7041#ifdef BROKEN_SETREGID
7043setregid(rb_gid_t rgid, rb_gid_t egid)
7045 if (rgid != (rb_gid_t)-1 && rgid != getgid()) {
7046 if (egid == (rb_gid_t)-1) egid = getegid();
7047 if (setgid(rgid) < 0)
return -1;
7049 if (egid != (rb_gid_t)-1 && egid != getegid()) {
7050 if (setegid(egid) < 0)
return -1;
7078 if (geteuid() == 0) {
7079#if defined(HAVE_SETRESGID)
7080 if (setresgid(gid, gid, gid) < 0) rb_sys_fail(0);
7081 SAVED_GROUP_ID = gid;
7082#elif defined HAVE_SETGID
7083 if (setgid(gid) < 0) rb_sys_fail(0);
7084 SAVED_GROUP_ID = gid;
7085#elif defined(HAVE_SETREGID) && !defined(OBSOLETE_SETREGID)
7086 if (getgid() == gid) {
7087 if (SAVED_GROUP_ID == gid) {
7088 if (setregid(-1, gid) < 0) rb_sys_fail(0);
7092 if (setregid(-1, SAVED_GROUP_ID) < 0) rb_sys_fail(0);
7093 if (setregid(SAVED_GROUP_ID, 0) < 0) rb_sys_fail(0);
7095 if (setregid(gid, gid) < 0) rb_sys_fail(0);
7096 SAVED_GROUP_ID = gid;
7099 if (setregid(0, 0) < 0) rb_sys_fail(0);
7101 if (setregid(gid, gid) < 0) rb_sys_fail(0);
7102 SAVED_GROUP_ID = gid;
7107 if (setregid(gid, gid) < 0) rb_sys_fail(0);
7108 SAVED_GROUP_ID = gid;
7110#elif defined(HAVE_SETRGID) && defined (HAVE_SETEGID)
7111 if (getgid() == gid) {
7112 if (SAVED_GROUP_ID == gid) {
7113 if (setegid(gid) < 0) rb_sys_fail(0);
7117 if (setegid(gid) < 0) rb_sys_fail(0);
7118 if (setrgid(SAVED_GROUP_ID) < 0) rb_sys_fail(0);
7120 if (setrgid(0) < 0) rb_sys_fail(0);
7123 if (setrgid(0) < 0) rb_sys_fail(0);
7125 if (setegid(gid) < 0) rb_sys_fail(0);
7126 if (setrgid(gid) < 0) rb_sys_fail(0);
7127 SAVED_GROUP_ID = gid;
7132 if (setegid(gid) < 0) rb_sys_fail(0);
7133 if (setrgid(gid) < 0) rb_sys_fail(0);
7134 SAVED_GROUP_ID = gid;
7141#if defined(HAVE_SETRESGID)
7142 if (setresgid((getgid() == gid)? (rb_gid_t)-1: gid,
7143 (getegid() == gid)? (rb_gid_t)-1: gid,
7144 (SAVED_GROUP_ID == gid)? (rb_gid_t)-1: gid) < 0) rb_sys_fail(0);
7145 SAVED_GROUP_ID = gid;
7146#elif defined(HAVE_SETREGID) && !defined(OBSOLETE_SETREGID)
7147 if (SAVED_GROUP_ID == gid) {
7148 if (setregid((getgid() == gid)? (rb_uid_t)-1: gid,
7149 (getegid() == gid)? (rb_uid_t)-1: gid) < 0)
7152 else if (getgid() != gid) {
7153 if (setregid(gid, (getegid() == gid)? (rb_uid_t)-1: gid) < 0)
7155 SAVED_GROUP_ID = gid;
7157 else if ( getegid() != gid) {
7158 if (setregid(getegid(), gid) < 0) rb_sys_fail(0);
7159 SAVED_GROUP_ID = gid;
7160 if (setregid(gid, -1) < 0) rb_sys_fail(0);
7163 if (setregid(-1, SAVED_GROUP_ID) < 0) rb_sys_fail(0);
7164 if (setregid(SAVED_GROUP_ID, gid) < 0) rb_sys_fail(0);
7165 SAVED_GROUP_ID = gid;
7166 if (setregid(gid, -1) < 0) rb_sys_fail(0);
7168#elif defined(HAVE_SETRGID) && defined(HAVE_SETEGID)
7169 if (SAVED_GROUP_ID == gid) {
7170 if (getegid() != gid && setegid(gid) < 0) rb_sys_fail(0);
7171 if (getgid() != gid && setrgid(gid) < 0) rb_sys_fail(0);
7173 else if ( getegid() == gid) {
7174 if (getgid() != gid) {
7175 if (setrgid(gid) < 0) rb_sys_fail(0);
7176 SAVED_GROUP_ID = gid;
7179 if (setrgid(SAVED_GROUP_ID) < 0) rb_sys_fail(0);
7180 SAVED_GROUP_ID = gid;
7181 if (setrgid(gid) < 0) rb_sys_fail(0);
7184 else if ( getgid() == gid) {
7185 if (setegid(gid) < 0) rb_sys_fail(0);
7186 if (setrgid(SAVED_GROUP_ID) < 0) rb_sys_fail(0);
7187 SAVED_GROUP_ID = gid;
7188 if (setrgid(gid) < 0) rb_sys_fail(0);
7193#elif defined HAVE_44BSD_SETGID
7194 if (getgid() == gid) {
7196 if (setgid(gid) < 0) rb_sys_fail(0);
7197 SAVED_GROUP_ID = gid;
7202#elif defined HAVE_SETEGID
7203 if (getgid() == gid && SAVED_GROUP_ID == gid) {
7204 if (setegid(gid) < 0) rb_sys_fail(0);
7209#elif defined HAVE_SETGID
7210 if (getgid() == gid && SAVED_GROUP_ID == gid) {
7211 if (setgid(gid) < 0) rb_sys_fail(0);
7238proc_geteuid(
VALUE obj)
7240 rb_uid_t euid = geteuid();
7244#if defined(HAVE_SETRESUID) || defined(HAVE_SETREUID) || defined(HAVE_SETEUID) || defined(HAVE_SETUID) || defined(_POSIX_SAVED_IDS)
7246proc_seteuid(rb_uid_t uid)
7248#if defined(HAVE_SETRESUID)
7249 if (setresuid(-1, uid, -1) < 0) rb_sys_fail(0);
7250#elif defined HAVE_SETREUID
7251 if (setreuid(-1, uid) < 0) rb_sys_fail(0);
7252#elif defined HAVE_SETEUID
7253 if (seteuid(uid) < 0) rb_sys_fail(0);
7254#elif defined HAVE_SETUID
7255 if (uid == getuid()) {
7256 if (setuid(uid) < 0) rb_sys_fail(0);
7267#if defined(HAVE_SETRESUID) || defined(HAVE_SETREUID) || defined(HAVE_SETEUID) || defined(HAVE_SETUID)
7281 proc_seteuid(OBJ2UID(euid));
7285#define proc_seteuid_m rb_f_notimplement
7289rb_seteuid_core(rb_uid_t euid)
7291#if defined(HAVE_SETRESUID) || (defined(HAVE_SETREUID) && !defined(OBSOLETE_SETREUID))
7297#if defined(HAVE_SETRESUID) || (defined(HAVE_SETREUID) && !defined(OBSOLETE_SETREUID))
7301#if defined(HAVE_SETRESUID)
7303 if (setresuid(-1,euid,euid) < 0) rb_sys_fail(0);
7304 SAVED_USER_ID = euid;
7307 if (setresuid(-1,euid,-1) < 0) rb_sys_fail(0);
7309#elif defined(HAVE_SETREUID) && !defined(OBSOLETE_SETREUID)
7310 if (setreuid(-1, euid) < 0) rb_sys_fail(0);
7312 if (setreuid(euid,uid) < 0) rb_sys_fail(0);
7313 if (setreuid(uid,euid) < 0) rb_sys_fail(0);
7314 SAVED_USER_ID = euid;
7316#elif defined HAVE_SETEUID
7317 if (seteuid(euid) < 0) rb_sys_fail(0);
7318#elif defined HAVE_SETUID
7319 if (geteuid() == 0) rb_sys_fail(0);
7320 if (setuid(euid) < 0) rb_sys_fail(0);
7345 rb_seteuid_core(OBJ2UID(
id));
7364proc_getegid(
VALUE obj)
7366 rb_gid_t egid = getegid();
7371#if defined(HAVE_SETRESGID) || defined(HAVE_SETREGID) || defined(HAVE_SETEGID) || defined(HAVE_SETGID) || defined(_POSIX_SAVED_IDS)
7384#if defined(HAVE_SETRESGID) || defined(HAVE_SETREGID) || defined(HAVE_SETEGID) || defined(HAVE_SETGID)
7390#if defined(HAVE_SETRESGID) || defined(HAVE_SETREGID) || defined(HAVE_SETEGID) || defined(HAVE_SETGID)
7391 gid = OBJ2GID(egid);
7394#if defined(HAVE_SETRESGID)
7395 if (setresgid(-1, gid, -1) < 0) rb_sys_fail(0);
7396#elif defined HAVE_SETREGID
7397 if (setregid(-1, gid) < 0) rb_sys_fail(0);
7398#elif defined HAVE_SETEGID
7399 if (setegid(gid) < 0) rb_sys_fail(0);
7400#elif defined HAVE_SETGID
7401 if (gid == getgid()) {
7402 if (setgid(gid) < 0) rb_sys_fail(0);
7414#if defined(HAVE_SETRESGID) || defined(HAVE_SETREGID) || defined(HAVE_SETEGID) || defined(HAVE_SETGID)
7415#define proc_setegid_m proc_setegid
7417#define proc_setegid_m rb_f_notimplement
7421rb_setegid_core(rb_gid_t egid)
7423#if defined(HAVE_SETRESGID) || (defined(HAVE_SETREGID) && !defined(OBSOLETE_SETREGID))
7429#if defined(HAVE_SETRESGID) || (defined(HAVE_SETREGID) && !defined(OBSOLETE_SETREGID))
7433#if defined(HAVE_SETRESGID)
7435 if (setresgid(-1,egid,egid) < 0) rb_sys_fail(0);
7436 SAVED_GROUP_ID = egid;
7439 if (setresgid(-1,egid,-1) < 0) rb_sys_fail(0);
7441#elif defined(HAVE_SETREGID) && !defined(OBSOLETE_SETREGID)
7442 if (setregid(-1, egid) < 0) rb_sys_fail(0);
7444 if (setregid(egid,gid) < 0) rb_sys_fail(0);
7445 if (setregid(gid,egid) < 0) rb_sys_fail(0);
7446 SAVED_GROUP_ID = egid;
7448#elif defined HAVE_SETEGID
7449 if (setegid(egid) < 0) rb_sys_fail(0);
7450#elif defined HAVE_SETGID
7451 if (geteuid() == 0 ) rb_sys_fail(0);
7452 if (setgid(egid) < 0) rb_sys_fail(0);
7477 rb_setegid_core(OBJ2GID(
id));
7492p_uid_exchangeable(
VALUE _)
7494#if defined(HAVE_SETRESUID)
7496#elif defined(HAVE_SETREUID) && !defined(OBSOLETE_SETREUID)
7517p_uid_exchange(
VALUE obj)
7520#if defined(HAVE_SETRESUID) || (defined(HAVE_SETREUID) && !defined(OBSOLETE_SETREUID))
7527#if defined(HAVE_SETRESUID) || (defined(HAVE_SETREUID) && !defined(OBSOLETE_SETREUID))
7531#if defined(HAVE_SETRESUID)
7532 if (setresuid(euid, uid, uid) < 0) rb_sys_fail(0);
7533 SAVED_USER_ID = uid;
7534#elif defined(HAVE_SETREUID) && !defined(OBSOLETE_SETREUID)
7535 if (setreuid(euid,uid) < 0) rb_sys_fail(0);
7536 SAVED_USER_ID = uid;
7554p_gid_exchangeable(
VALUE _)
7556#if defined(HAVE_SETRESGID)
7558#elif defined(HAVE_SETREGID) && !defined(OBSOLETE_SETREGID)
7579p_gid_exchange(
VALUE obj)
7582#if defined(HAVE_SETRESGID) || (defined(HAVE_SETREGID) && !defined(OBSOLETE_SETREGID))
7589#if defined(HAVE_SETRESGID) || (defined(HAVE_SETREGID) && !defined(OBSOLETE_SETREGID))
7593#if defined(HAVE_SETRESGID)
7594 if (setresgid(egid, gid, gid) < 0) rb_sys_fail(0);
7595 SAVED_GROUP_ID = gid;
7596#elif defined(HAVE_SETREGID) && !defined(OBSOLETE_SETREGID)
7597 if (setregid(egid,gid) < 0) rb_sys_fail(0);
7598 SAVED_GROUP_ID = gid;
7617p_uid_have_saved_id(
VALUE _)
7619#if defined(HAVE_SETRESUID) || defined(HAVE_SETEUID) || defined(_POSIX_SAVED_IDS)
7627#if defined(HAVE_SETRESUID) || defined(HAVE_SETEUID) || defined(_POSIX_SAVED_IDS)
7629p_uid_sw_ensure(
VALUE i)
7631 rb_uid_t
id = (rb_uid_t)i;
7632 under_uid_switch = 0;
7633 id = rb_seteuid_core(
id);
7652p_uid_switch(
VALUE obj)
7664 under_uid_switch = 1;
7671 else if (euid != SAVED_USER_ID) {
7672 proc_seteuid(SAVED_USER_ID);
7674 under_uid_switch = 1;
7689p_uid_sw_ensure(
VALUE obj)
7691 under_uid_switch = 0;
7692 return p_uid_exchange(obj);
7696p_uid_switch(
VALUE obj)
7708 p_uid_exchange(obj);
7710 under_uid_switch = 1;
7732p_gid_have_saved_id(
VALUE _)
7734#if defined(HAVE_SETRESGID) || defined(HAVE_SETEGID) || defined(_POSIX_SAVED_IDS)
7741#if defined(HAVE_SETRESGID) || defined(HAVE_SETEGID) || defined(_POSIX_SAVED_IDS)
7743p_gid_sw_ensure(
VALUE i)
7745 rb_gid_t
id = (rb_gid_t)i;
7746 under_gid_switch = 0;
7747 id = rb_setegid_core(
id);
7766p_gid_switch(
VALUE obj)
7778 under_gid_switch = 1;
7785 else if (egid != SAVED_GROUP_ID) {
7786 proc_setegid(obj,
GIDT2NUM(SAVED_GROUP_ID));
7788 under_gid_switch = 1;
7803p_gid_sw_ensure(
VALUE obj)
7805 under_gid_switch = 0;
7806 return p_gid_exchange(obj);
7810p_gid_switch(
VALUE obj)
7822 p_gid_exchange(obj);
7824 under_gid_switch = 1;
7834#if defined(HAVE_TIMES)
7838#ifdef HAVE__SC_CLK_TCK
7839 return sysconf(_SC_CLK_TCK);
7840#elif defined CLK_TCK
7863rb_proc_times(
VALUE obj)
7865 VALUE utime, stime, cutime, cstime, ret;
7866#if defined(RUSAGE_SELF) && defined(RUSAGE_CHILDREN)
7867 struct rusage usage_s, usage_c;
7869 if (getrusage(RUSAGE_SELF, &usage_s) != 0 || getrusage(RUSAGE_CHILDREN, &usage_c) != 0)
7870 rb_sys_fail(
"getrusage");
7871 utime =
DBL2NUM((
double)usage_s.ru_utime.tv_sec + (
double)usage_s.ru_utime.tv_usec/1e6);
7872 stime =
DBL2NUM((
double)usage_s.ru_stime.tv_sec + (
double)usage_s.ru_stime.tv_usec/1e6);
7873 cutime =
DBL2NUM((
double)usage_c.ru_utime.tv_sec + (
double)usage_c.ru_utime.tv_usec/1e6);
7874 cstime =
DBL2NUM((
double)usage_c.ru_stime.tv_sec + (
double)usage_c.ru_stime.tv_usec/1e6);
7876 const double hertz = (double)get_clk_tck();
7880 utime =
DBL2NUM(buf.tms_utime / hertz);
7881 stime =
DBL2NUM(buf.tms_stime / hertz);
7882 cutime =
DBL2NUM(buf.tms_cutime / hertz);
7883 cstime =
DBL2NUM(buf.tms_cstime / hertz);
7885 ret =
rb_struct_new(rb_cProcessTms, utime, stime, cutime, cstime);
7893#define rb_proc_times rb_f_notimplement
7896#ifdef HAVE_LONG_LONG
7898#define TIMETICK_INT_MIN LLONG_MIN
7899#define TIMETICK_INT_MAX LLONG_MAX
7900#define TIMETICK_INT2NUM(v) LL2NUM(v)
7901#define MUL_OVERFLOW_TIMETICK_P(a, b) MUL_OVERFLOW_LONG_LONG_P(a, b)
7903typedef long timetick_int_t;
7904#define TIMETICK_INT_MIN LONG_MIN
7905#define TIMETICK_INT_MAX LONG_MAX
7906#define TIMETICK_INT2NUM(v) LONG2NUM(v)
7907#define MUL_OVERFLOW_TIMETICK_P(a, b) MUL_OVERFLOW_LONG_P(a, b)
7910CONSTFUNC(
static timetick_int_t gcd_timetick_int(timetick_int_t, timetick_int_t));
7911static timetick_int_t
7912gcd_timetick_int(timetick_int_t a, timetick_int_t b)
7932reduce_fraction(timetick_int_t *np, timetick_int_t *dp)
7934 timetick_int_t gcd = gcd_timetick_int(*np, *dp);
7942reduce_factors(timetick_int_t *numerators,
int num_numerators,
7943 timetick_int_t *denominators,
int num_denominators)
7946 for (i = 0; i < num_numerators; i++) {
7947 if (numerators[i] == 1)
7949 for (j = 0; j < num_denominators; j++) {
7950 if (denominators[j] == 1)
7952 reduce_fraction(&numerators[i], &denominators[j]);
7958 timetick_int_t giga_count;
7963timetick2dblnum(
struct timetick *ttp,
7964 timetick_int_t *numerators,
int num_numerators,
7965 timetick_int_t *denominators,
int num_denominators)
7970 reduce_factors(numerators, num_numerators,
7971 denominators, num_denominators);
7973 d = ttp->giga_count * 1e9 + ttp->count;
7975 for (i = 0; i < num_numerators; i++)
7977 for (i = 0; i < num_denominators; i++)
7978 d /= denominators[i];
7984timetick2dblnum_reciprocal(
struct timetick *ttp,
7985 timetick_int_t *numerators,
int num_numerators,
7986 timetick_int_t *denominators,
int num_denominators)
7991 reduce_factors(numerators, num_numerators,
7992 denominators, num_denominators);
7995 for (i = 0; i < num_denominators; i++)
7996 d *= denominators[i];
7997 for (i = 0; i < num_numerators; i++)
7999 d /= ttp->giga_count * 1e9 + ttp->count;
8004#define NDIV(x,y) (-(-((x)+1)/(y))-1)
8005#define DIV(n,d) ((n)<0 ? NDIV((n),(d)) : (n)/(d))
8008timetick2integer(
struct timetick *ttp,
8009 timetick_int_t *numerators,
int num_numerators,
8010 timetick_int_t *denominators,
int num_denominators)
8015 reduce_factors(numerators, num_numerators,
8016 denominators, num_denominators);
8018 if (!MUL_OVERFLOW_SIGNED_INTEGER_P(1000000000, ttp->giga_count,
8019 TIMETICK_INT_MIN, TIMETICK_INT_MAX-ttp->count)) {
8020 timetick_int_t t = ttp->giga_count * 1000000000 + ttp->count;
8021 for (i = 0; i < num_numerators; i++) {
8022 timetick_int_t factor = numerators[i];
8023 if (MUL_OVERFLOW_TIMETICK_P(factor, t))
8027 for (i = 0; i < num_denominators; i++) {
8028 t = DIV(t, denominators[i]);
8030 return TIMETICK_INT2NUM(t);
8034 v = TIMETICK_INT2NUM(ttp->giga_count);
8037 for (i = 0; i < num_numerators; i++) {
8038 timetick_int_t factor = numerators[i];
8041 v =
rb_funcall(v,
'*', 1, TIMETICK_INT2NUM(factor));
8043 for (i = 0; i < num_denominators; i++) {
8044 v =
rb_funcall(v,
'/', 1, TIMETICK_INT2NUM(denominators[i]));
8050make_clock_result(
struct timetick *ttp,
8051 timetick_int_t *numerators,
int num_numerators,
8052 timetick_int_t *denominators,
int num_denominators,
8055 if (unit ==
ID2SYM(id_nanosecond)) {
8056 numerators[num_numerators++] = 1000000000;
8057 return timetick2integer(ttp, numerators, num_numerators, denominators, num_denominators);
8059 else if (unit ==
ID2SYM(id_microsecond)) {
8060 numerators[num_numerators++] = 1000000;
8061 return timetick2integer(ttp, numerators, num_numerators, denominators, num_denominators);
8063 else if (unit ==
ID2SYM(id_millisecond)) {
8064 numerators[num_numerators++] = 1000;
8065 return timetick2integer(ttp, numerators, num_numerators, denominators, num_denominators);
8067 else if (unit ==
ID2SYM(id_second)) {
8068 return timetick2integer(ttp, numerators, num_numerators, denominators, num_denominators);
8070 else if (unit ==
ID2SYM(id_float_microsecond)) {
8071 numerators[num_numerators++] = 1000000;
8072 return timetick2dblnum(ttp, numerators, num_numerators, denominators, num_denominators);
8074 else if (unit ==
ID2SYM(id_float_millisecond)) {
8075 numerators[num_numerators++] = 1000;
8076 return timetick2dblnum(ttp, numerators, num_numerators, denominators, num_denominators);
8078 else if (
NIL_P(unit) || unit ==
ID2SYM(id_float_second)) {
8079 return timetick2dblnum(ttp, numerators, num_numerators, denominators, num_denominators);
8082 rb_raise(rb_eArgError,
"unexpected unit: %"PRIsVALUE, unit);
8086static const mach_timebase_info_data_t *
8087get_mach_timebase_info(
void)
8089 static mach_timebase_info_data_t sTimebaseInfo;
8091 if ( sTimebaseInfo.denom == 0 ) {
8092 (void) mach_timebase_info(&sTimebaseInfo);
8095 return &sTimebaseInfo;
8099ruby_real_ms_time(
void)
8101 const mach_timebase_info_data_t *info = get_mach_timebase_info();
8102 uint64_t t = mach_absolute_time();
8103 return (
double)t * info->numer / info->denom / 1e6;
8107#if defined(NUM2CLOCKID)
8108# define NUMERIC_CLOCKID 1
8110# define NUMERIC_CLOCKID 0
8111# define NUM2CLOCKID(x) 0
8114#define clock_failed(name, err, arg) do { \
8115 int clock_error = (err); \
8116 rb_syserr_fail_str(clock_error, rb_sprintf("clock_" name "(%+"PRIsVALUE")", (arg))); \
8289 timetick_int_t numerators[2];
8290 timetick_int_t denominators[2];
8291 int num_numerators = 0;
8292 int num_denominators = 0;
8295 VALUE clk_id = argv[0];
8296#ifdef HAVE_CLOCK_GETTIME
8301#ifdef CLOCK_REALTIME
8302 if (clk_id == RUBY_CLOCK_REALTIME) {
8308#ifdef CLOCK_MONOTONIC
8309 if (clk_id == RUBY_CLOCK_MONOTONIC) {
8310 c = CLOCK_MONOTONIC;
8315#ifdef CLOCK_PROCESS_CPUTIME_ID
8316 if (clk_id == RUBY_CLOCK_PROCESS_CPUTIME_ID) {
8317 c = CLOCK_PROCESS_CPUTIME_ID;
8322#ifdef CLOCK_THREAD_CPUTIME_ID
8323 if (clk_id == RUBY_CLOCK_THREAD_CPUTIME_ID) {
8324 c = CLOCK_THREAD_CPUTIME_ID;
8332#ifdef HAVE_GETTIMEOFDAY
8337#define RUBY_GETTIMEOFDAY_BASED_CLOCK_REALTIME ID2SYM(id_GETTIMEOFDAY_BASED_CLOCK_REALTIME)
8338 if (clk_id == RUBY_GETTIMEOFDAY_BASED_CLOCK_REALTIME) {
8340 ret = gettimeofday(&tv, 0);
8342 rb_sys_fail(
"gettimeofday");
8343 tt.giga_count = tv.tv_sec;
8344 tt.count = (int32_t)tv.tv_usec * 1000;
8345 denominators[num_denominators++] = 1000000000;
8350#define RUBY_TIME_BASED_CLOCK_REALTIME ID2SYM(id_TIME_BASED_CLOCK_REALTIME)
8351 if (clk_id == RUBY_TIME_BASED_CLOCK_REALTIME) {
8354 if (t == (time_t)-1)
8355 rb_sys_fail(
"time");
8358 denominators[num_denominators++] = 1000000000;
8363#define RUBY_TIMES_BASED_CLOCK_MONOTONIC \
8364 ID2SYM(id_TIMES_BASED_CLOCK_MONOTONIC)
8365 if (clk_id == RUBY_TIMES_BASED_CLOCK_MONOTONIC) {
8368 unsigned_clock_t uc;
8370 if (c == (clock_t)-1)
8371 rb_sys_fail(
"times");
8372 uc = (unsigned_clock_t)c;
8373 tt.count = (int32_t)(uc % 1000000000);
8374 tt.giga_count = (uc / 1000000000);
8375 denominators[num_denominators++] = get_clk_tck();
8381#define RUBY_GETRUSAGE_BASED_CLOCK_PROCESS_CPUTIME_ID \
8382 ID2SYM(id_GETRUSAGE_BASED_CLOCK_PROCESS_CPUTIME_ID)
8383 if (clk_id == RUBY_GETRUSAGE_BASED_CLOCK_PROCESS_CPUTIME_ID) {
8384 struct rusage usage;
8386 ret = getrusage(RUSAGE_SELF, &usage);
8388 rb_sys_fail(
"getrusage");
8389 tt.giga_count = usage.ru_utime.tv_sec + usage.ru_stime.tv_sec;
8390 usec = (int32_t)(usage.ru_utime.tv_usec + usage.ru_stime.tv_usec);
8391 if (1000000 <= usec) {
8395 tt.count = usec * 1000;
8396 denominators[num_denominators++] = 1000000000;
8402#define RUBY_TIMES_BASED_CLOCK_PROCESS_CPUTIME_ID \
8403 ID2SYM(id_TIMES_BASED_CLOCK_PROCESS_CPUTIME_ID)
8404 if (clk_id == RUBY_TIMES_BASED_CLOCK_PROCESS_CPUTIME_ID) {
8406 unsigned_clock_t utime, stime;
8407 if (times(&buf) == (clock_t)-1)
8408 rb_sys_fail(
"times");
8409 utime = (unsigned_clock_t)buf.tms_utime;
8410 stime = (unsigned_clock_t)buf.tms_stime;
8411 tt.count = (int32_t)((utime % 1000000000) + (stime % 1000000000));
8412 tt.giga_count = (utime / 1000000000) + (stime / 1000000000);
8413 if (1000000000 <= tt.count) {
8414 tt.count -= 1000000000;
8417 denominators[num_denominators++] = get_clk_tck();
8422#define RUBY_CLOCK_BASED_CLOCK_PROCESS_CPUTIME_ID \
8423 ID2SYM(id_CLOCK_BASED_CLOCK_PROCESS_CPUTIME_ID)
8424 if (clk_id == RUBY_CLOCK_BASED_CLOCK_PROCESS_CPUTIME_ID) {
8426 unsigned_clock_t uc;
8429 if (c == (clock_t)-1)
8430 rb_sys_fail(
"clock");
8431 uc = (unsigned_clock_t)c;
8432 tt.count = (int32_t)(uc % 1000000000);
8433 tt.giga_count = uc / 1000000000;
8434 denominators[num_denominators++] = CLOCKS_PER_SEC;
8439 if (clk_id == RUBY_MACH_ABSOLUTE_TIME_BASED_CLOCK_MONOTONIC) {
8440 const mach_timebase_info_data_t *info = get_mach_timebase_info();
8441 uint64_t t = mach_absolute_time();
8442 tt.count = (int32_t)(t % 1000000000);
8443 tt.giga_count = t / 1000000000;
8444 numerators[num_numerators++] = info->numer;
8445 denominators[num_denominators++] = info->denom;
8446 denominators[num_denominators++] = 1000000000;
8451 else if (NUMERIC_CLOCKID) {
8452#if defined(HAVE_CLOCK_GETTIME)
8454 c = NUM2CLOCKID(clk_id);
8456 ret = clock_gettime(c, &ts);
8458 clock_failed(
"gettime",
errno, clk_id);
8459 tt.count = (int32_t)ts.tv_nsec;
8460 tt.giga_count = ts.tv_sec;
8461 denominators[num_denominators++] = 1000000000;
8468 clock_failed(
"gettime", EINVAL, clk_id);
8471 return make_clock_result(&tt, numerators, num_numerators, denominators, num_denominators, unit);
8516 timetick_int_t numerators[2];
8517 timetick_int_t denominators[2];
8518 int num_numerators = 0;
8519 int num_denominators = 0;
8520#ifdef HAVE_CLOCK_GETRES
8525 VALUE clk_id = argv[0];
8528#ifdef CLOCK_REALTIME
8529 if (clk_id == RUBY_CLOCK_REALTIME) {
8535#ifdef CLOCK_MONOTONIC
8536 if (clk_id == RUBY_CLOCK_MONOTONIC) {
8537 c = CLOCK_MONOTONIC;
8542#ifdef CLOCK_PROCESS_CPUTIME_ID
8543 if (clk_id == RUBY_CLOCK_PROCESS_CPUTIME_ID) {
8544 c = CLOCK_PROCESS_CPUTIME_ID;
8549#ifdef CLOCK_THREAD_CPUTIME_ID
8550 if (clk_id == RUBY_CLOCK_THREAD_CPUTIME_ID) {
8551 c = CLOCK_THREAD_CPUTIME_ID;
8556#ifdef RUBY_GETTIMEOFDAY_BASED_CLOCK_REALTIME
8557 if (clk_id == RUBY_GETTIMEOFDAY_BASED_CLOCK_REALTIME) {
8560 denominators[num_denominators++] = 1000000000;
8565#ifdef RUBY_TIME_BASED_CLOCK_REALTIME
8566 if (clk_id == RUBY_TIME_BASED_CLOCK_REALTIME) {
8569 denominators[num_denominators++] = 1000000000;
8574#ifdef RUBY_TIMES_BASED_CLOCK_MONOTONIC
8575 if (clk_id == RUBY_TIMES_BASED_CLOCK_MONOTONIC) {
8578 denominators[num_denominators++] = get_clk_tck();
8583#ifdef RUBY_GETRUSAGE_BASED_CLOCK_PROCESS_CPUTIME_ID
8584 if (clk_id == RUBY_GETRUSAGE_BASED_CLOCK_PROCESS_CPUTIME_ID) {
8587 denominators[num_denominators++] = 1000000000;
8592#ifdef RUBY_TIMES_BASED_CLOCK_PROCESS_CPUTIME_ID
8593 if (clk_id == RUBY_TIMES_BASED_CLOCK_PROCESS_CPUTIME_ID) {
8596 denominators[num_denominators++] = get_clk_tck();
8601#ifdef RUBY_CLOCK_BASED_CLOCK_PROCESS_CPUTIME_ID
8602 if (clk_id == RUBY_CLOCK_BASED_CLOCK_PROCESS_CPUTIME_ID) {
8605 denominators[num_denominators++] = CLOCKS_PER_SEC;
8610#ifdef RUBY_MACH_ABSOLUTE_TIME_BASED_CLOCK_MONOTONIC
8611 if (clk_id == RUBY_MACH_ABSOLUTE_TIME_BASED_CLOCK_MONOTONIC) {
8612 const mach_timebase_info_data_t *info = get_mach_timebase_info();
8615 numerators[num_numerators++] = info->numer;
8616 denominators[num_denominators++] = info->denom;
8617 denominators[num_denominators++] = 1000000000;
8622 else if (NUMERIC_CLOCKID) {
8623#if defined(HAVE_CLOCK_GETRES)
8625 c = NUM2CLOCKID(clk_id);
8627 ret = clock_getres(c, &ts);
8629 clock_failed(
"getres",
errno, clk_id);
8630 tt.count = (int32_t)ts.tv_nsec;
8631 tt.giga_count = ts.tv_sec;
8632 denominators[num_denominators++] = 1000000000;
8639 clock_failed(
"getres", EINVAL, clk_id);
8642 if (unit ==
ID2SYM(id_hertz)) {
8643 return timetick2dblnum_reciprocal(&tt, numerators, num_numerators, denominators, num_denominators);
8646 return make_clock_result(&tt, numerators, num_numerators, denominators, num_denominators, unit);
8651get_CHILD_STATUS(
ID _x,
VALUE *_y)
8657get_PROCESS_ID(
ID _x,
VALUE *_y)
8749static VALUE rb_mProcUID;
8750static VALUE rb_mProcGID;
8751static VALUE rb_mProcID_Syscall;
8783 rb_gc_prepare_heap();
9118 rb_gvar_ractor_local(
"$$");
9119 rb_gvar_ractor_local(
"$?");
9174 process_status_dump, process_status_load);
9212#ifdef HAVE_GETPRIORITY
9223#if defined(RLIM2NUM) && defined(RLIM_INFINITY)
9225 VALUE inf = RLIM2NUM(RLIM_INFINITY);
9226#ifdef RLIM_SAVED_MAX
9228 VALUE v = RLIM_INFINITY == RLIM_SAVED_MAX ? inf : RLIM2NUM(RLIM_SAVED_MAX);
9235#ifdef RLIM_SAVED_CUR
9237 VALUE v = RLIM_INFINITY == RLIM_SAVED_CUR ? inf : RLIM2NUM(RLIM_SAVED_CUR);
9278#ifdef RLIMIT_MEMLOCK
9285#ifdef RLIMIT_MSGQUEUE
9351#ifdef RLIMIT_SIGPENDING
9386#if defined(RUBY_CLOCK_REALTIME)
9387#elif defined(RUBY_GETTIMEOFDAY_BASED_CLOCK_REALTIME)
9388# define RUBY_CLOCK_REALTIME RUBY_GETTIMEOFDAY_BASED_CLOCK_REALTIME
9389#elif defined(RUBY_TIME_BASED_CLOCK_REALTIME)
9390# define RUBY_CLOCK_REALTIME RUBY_TIME_BASED_CLOCK_REALTIME
9392#if defined(CLOCK_REALTIME) && defined(CLOCKID2NUM)
9395#elif defined(RUBY_CLOCK_REALTIME)
9399#if defined(RUBY_CLOCK_MONOTONIC)
9400#elif defined(RUBY_MACH_ABSOLUTE_TIME_BASED_CLOCK_MONOTONIC)
9401# define RUBY_CLOCK_MONOTONIC RUBY_MACH_ABSOLUTE_TIME_BASED_CLOCK_MONOTONIC
9403#if defined(CLOCK_MONOTONIC) && defined(CLOCKID2NUM)
9406#elif defined(RUBY_CLOCK_MONOTONIC)
9410#if defined(RUBY_CLOCK_PROCESS_CPUTIME_ID)
9411#elif defined(RUBY_GETRUSAGE_BASED_CLOCK_PROCESS_CPUTIME_ID)
9412# define RUBY_CLOCK_PROCESS_CPUTIME_ID RUBY_GETRUSAGE_BASED_CLOCK_PROCESS_CPUTIME_ID
9414#if defined(CLOCK_PROCESS_CPUTIME_ID) && defined(CLOCKID2NUM)
9417#elif defined(RUBY_CLOCK_PROCESS_CPUTIME_ID)
9421#if defined(CLOCK_THREAD_CPUTIME_ID) && defined(CLOCKID2NUM)
9424#elif defined(RUBY_CLOCK_THREAD_CPUTIME_ID)
9437#ifdef CLOCK_REALTIME_FAST
9441#ifdef CLOCK_REALTIME_PRECISE
9445#ifdef CLOCK_REALTIME_COARSE
9449#ifdef CLOCK_REALTIME_ALARM
9453#ifdef CLOCK_MONOTONIC_FAST
9457#ifdef CLOCK_MONOTONIC_PRECISE
9461#ifdef CLOCK_MONOTONIC_RAW
9465#ifdef CLOCK_MONOTONIC_RAW_APPROX
9469#ifdef CLOCK_MONOTONIC_COARSE
9473#ifdef CLOCK_BOOTTIME
9477#ifdef CLOCK_BOOTTIME_ALARM
9485#ifdef CLOCK_UPTIME_FAST
9489#ifdef CLOCK_UPTIME_PRECISE
9493#ifdef CLOCK_UPTIME_RAW
9497#ifdef CLOCK_UPTIME_RAW_APPROX
9513#if defined(HAVE_TIMES) || defined(_WIN32)
9527 SAVED_USER_ID = geteuid();
9528 SAVED_GROUP_ID = getegid();
9551#ifdef p_uid_from_name
9554#ifdef p_gid_from_name
9585#define define_id(name) id_##name = rb_intern_const(#name)
9598 define_id(new_pgroup);
9600 define_id(unsetenv_others);
9603 define_id(close_others);
9604 define_id(nanosecond);
9605 define_id(microsecond);
9606 define_id(millisecond);
9608 define_id(float_microsecond);
9609 define_id(float_millisecond);
9610 define_id(float_second);
9611 define_id(GETTIMEOFDAY_BASED_CLOCK_REALTIME);
9612 define_id(TIME_BASED_CLOCK_REALTIME);
9613#ifdef CLOCK_REALTIME
9614 define_id(CLOCK_REALTIME);
9616#ifdef CLOCK_MONOTONIC
9617 define_id(CLOCK_MONOTONIC);
9619#ifdef CLOCK_PROCESS_CPUTIME_ID
9620 define_id(CLOCK_PROCESS_CPUTIME_ID);
9622#ifdef CLOCK_THREAD_CPUTIME_ID
9623 define_id(CLOCK_THREAD_CPUTIME_ID);
9626 define_id(TIMES_BASED_CLOCK_MONOTONIC);
9627 define_id(TIMES_BASED_CLOCK_PROCESS_CPUTIME_ID);
9630 define_id(GETRUSAGE_BASED_CLOCK_PROCESS_CPUTIME_ID);
9632 define_id(CLOCK_BASED_CLOCK_PROCESS_CPUTIME_ID);
9634 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)
VALUE rb_eNotImpError
NotImplementedError exception.
void rb_syserr_fail(int e, const char *mesg)
Raises appropriate exception that represents a C errno.
VALUE rb_eSystemExit
SystemExit exception.
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 unless $VERBOSE is nil.
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.
void rb_unexpected_type(VALUE x, int t)
Fails with the given object's type incompatibility to the type.
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_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.
VALUE rb_funcall(VALUE recv, ID mid, int n,...)
Calls a method.
#define UNLIMITED_ARGUMENTS
This macro is used in conjunction with rb_check_arity().
static int rb_check_arity(int argc, int min, int max)
Ensures that the passed integer is in the passed range.
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.
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.
VALUE rb_process_status_wait(rb_pid_t pid, int flags)
Wait for the specified process to terminate, reap it, and return its status.
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.
#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_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.
void rb_str_modify_expand(VALUE str, long capa)
Identical to rb_str_modify(), except it additionally expands the capacity of the receiver.
#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_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.
int len
Length of the buffer.
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.
#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.
static int RARRAY_LENINT(VALUE ary)
Identical to rb_array_len(), except it differs for the return type.
static void RARRAY_ASET(VALUE ary, long i, VALUE v)
Assigns an object in an array.
#define RARRAY_AREF(a, i)
#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 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 errno
Ractor-aware version of errno.
#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.
static bool RB_SPECIAL_CONST_P(VALUE obj)
Checks if the given object is of enum ruby_special_consts.
#define RTEST
This is an old name of RB_TEST.
#define _(args)
This was a transition path from K&R to ANSI.
This is the struct that holds necessary info for a struct.
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.
#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 ID
Type that represents a Ruby identifier such as a variable name.
uintptr_t VALUE
Type that represents a Ruby object.
static enum ruby_value_type RB_BUILTIN_TYPE(VALUE obj)
Queries the type of the object.
static void Check_Type(VALUE v, enum ruby_value_type t)
Identical to RB_TYPE_P(), except it raises exceptions on predication failure.