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"
117#include "ractor_core.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__)
158#define HAVE_44BSD_SETUID 1
159#define HAVE_44BSD_SETGID 1
167#if defined(HAVE_44BSD_SETUID) || defined(__APPLE__)
168#if !defined(USE_SETREUID)
169#define OBSOLETE_SETREUID 1
171#if !defined(USE_SETREGID)
172#define OBSOLETE_SETREGID 1
176static void check_uid_switch(
void);
177static void check_gid_switch(
void);
178static int exec_async_signal_safe(
const struct rb_execarg *,
char *,
size_t);
180VALUE rb_envtbl(
void);
181VALUE rb_env_to_hash(
void);
184#define p_uid_from_name p_uid_from_name
185#define p_gid_from_name p_gid_from_name
188#if defined(HAVE_UNISTD_H)
189# if defined(HAVE_GETLOGIN_R)
190# define USE_GETLOGIN_R 1
191# define GETLOGIN_R_SIZE_DEFAULT 0x100
192# define GETLOGIN_R_SIZE_LIMIT 0x1000
193# if defined(_SC_LOGIN_NAME_MAX)
194# define GETLOGIN_R_SIZE_INIT sysconf(_SC_LOGIN_NAME_MAX)
196# define GETLOGIN_R_SIZE_INIT GETLOGIN_R_SIZE_DEFAULT
198# elif defined(HAVE_GETLOGIN)
199# define USE_GETLOGIN 1
203#if defined(HAVE_PWD_H)
204# if defined(HAVE_GETPWUID_R)
205# define USE_GETPWUID_R 1
206# elif defined(HAVE_GETPWUID)
207# define USE_GETPWUID 1
209# if defined(HAVE_GETPWNAM_R)
210# define USE_GETPWNAM_R 1
211# elif defined(HAVE_GETPWNAM)
212# define USE_GETPWNAM 1
214# if defined(HAVE_GETPWNAM_R) || defined(HAVE_GETPWUID_R)
215# define GETPW_R_SIZE_DEFAULT 0x1000
216# define GETPW_R_SIZE_LIMIT 0x10000
217# if defined(_SC_GETPW_R_SIZE_MAX)
218# define GETPW_R_SIZE_INIT sysconf(_SC_GETPW_R_SIZE_MAX)
220# define GETPW_R_SIZE_INIT GETPW_R_SIZE_DEFAULT
223# ifdef USE_GETPWNAM_R
224# define PREPARE_GETPWNAM \
226# define FINISH_GETPWNAM \
227 (getpw_buf ? (void)rb_str_resize(getpw_buf, 0) : (void)0)
228# define OBJ2UID1(id) obj2uid((id), &getpw_buf)
229# define OBJ2UID(id) obj2uid0(id)
230static rb_uid_t obj2uid(
VALUE id,
VALUE *getpw_buf);
231static inline rb_uid_t
241# define PREPARE_GETPWNAM
242# define FINISH_GETPWNAM
243# define OBJ2UID1(id) obj2uid((id))
244# define OBJ2UID(id) obj2uid((id))
245static rb_uid_t obj2uid(
VALUE id);
248# define PREPARE_GETPWNAM
249# define FINISH_GETPWNAM
250# define OBJ2UID1(id) NUM2UIDT(id)
251# define OBJ2UID(id) NUM2UIDT(id)
252# ifdef p_uid_from_name
253# undef p_uid_from_name
254# define p_uid_from_name rb_f_notimplement
258#if defined(HAVE_GRP_H)
259# if defined(HAVE_GETGRNAM_R) && defined(_SC_GETGR_R_SIZE_MAX)
260# define USE_GETGRNAM_R
261# define GETGR_R_SIZE_INIT sysconf(_SC_GETGR_R_SIZE_MAX)
262# define GETGR_R_SIZE_DEFAULT 0x1000
263# define GETGR_R_SIZE_LIMIT 0x10000
265# ifdef USE_GETGRNAM_R
266# define PREPARE_GETGRNAM \
268# define FINISH_GETGRNAM \
269 (getgr_buf ? (void)rb_str_resize(getgr_buf, 0) : (void)0)
270# define OBJ2GID1(id) obj2gid((id), &getgr_buf)
271# define OBJ2GID(id) obj2gid0(id)
272static rb_gid_t obj2gid(
VALUE id,
VALUE *getgr_buf);
273static inline rb_gid_t
282static rb_gid_t obj2gid(
VALUE id,
VALUE *getgr_buf);
284# define PREPARE_GETGRNAM
285# define FINISH_GETGRNAM
286# define OBJ2GID1(id) obj2gid((id))
287# define OBJ2GID(id) obj2gid((id))
288static rb_gid_t obj2gid(
VALUE id);
291# define PREPARE_GETGRNAM
292# define FINISH_GETGRNAM
293# define OBJ2GID1(id) NUM2GIDT(id)
294# define OBJ2GID(id) NUM2GIDT(id)
295# ifdef p_gid_from_name
296# undef p_gid_from_name
297# define p_gid_from_name rb_f_notimplement
301#if SIZEOF_CLOCK_T == SIZEOF_INT
302typedef unsigned int unsigned_clock_t;
303#elif SIZEOF_CLOCK_T == SIZEOF_LONG
304typedef unsigned long unsigned_clock_t;
305#elif defined(HAVE_LONG_LONG) && SIZEOF_CLOCK_T == SIZEOF_LONG_LONG
306typedef unsigned LONG_LONG unsigned_clock_t;
309typedef void (*sig_t) (int);
312#define id_exception idException
313static ID id_in, id_out, id_err, id_pid, id_uid, id_gid;
314static ID id_close, id_child;
319static ID id_new_pgroup;
321static ID id_unsetenv_others, id_chdir, id_umask, id_close_others;
322static ID id_nanosecond, id_microsecond, id_millisecond, id_second;
323static ID id_float_microsecond, id_float_millisecond, id_float_second;
324static ID id_GETTIMEOFDAY_BASED_CLOCK_REALTIME, id_TIME_BASED_CLOCK_REALTIME;
326static ID id_CLOCK_REALTIME;
327# define RUBY_CLOCK_REALTIME ID2SYM(id_CLOCK_REALTIME)
329#ifdef CLOCK_MONOTONIC
330static ID id_CLOCK_MONOTONIC;
331# define RUBY_CLOCK_MONOTONIC ID2SYM(id_CLOCK_MONOTONIC)
333#ifdef CLOCK_PROCESS_CPUTIME_ID
334static ID id_CLOCK_PROCESS_CPUTIME_ID;
335# define RUBY_CLOCK_PROCESS_CPUTIME_ID ID2SYM(id_CLOCK_PROCESS_CPUTIME_ID)
337#ifdef CLOCK_THREAD_CPUTIME_ID
338static ID id_CLOCK_THREAD_CPUTIME_ID;
339# define RUBY_CLOCK_THREAD_CPUTIME_ID ID2SYM(id_CLOCK_THREAD_CPUTIME_ID)
342static ID id_TIMES_BASED_CLOCK_MONOTONIC;
343static ID id_TIMES_BASED_CLOCK_PROCESS_CPUTIME_ID;
346static ID id_GETRUSAGE_BASED_CLOCK_PROCESS_CPUTIME_ID;
348static ID id_CLOCK_BASED_CLOCK_PROCESS_CPUTIME_ID;
350static ID id_MACH_ABSOLUTE_TIME_BASED_CLOCK_MONOTONIC;
351# define RUBY_MACH_ABSOLUTE_TIME_BASED_CLOCK_MONOTONIC ID2SYM(id_MACH_ABSOLUTE_TIME_BASED_CLOCK_MONOTONIC)
354#ifdef HAVE_WORKING_FORK
358static rb_pid_t cached_pid;
361#if defined(__sun) && !defined(_XPG7)
362#define execv(path, argv) (rb_async_bug_errno("unreachable: async-signal-unsafe execv() is called", 0))
363#define execl(path, arg0, arg1, arg2, term) do { extern char **environ; execle((path), (arg0), (arg1), (arg2), (term), (environ)); } while (0)
364#define ALWAYS_NEED_ENVP 1
366#define ALWAYS_NEED_ENVP 0
370assert_close_on_exec(
int fd)
373#if defined(HAVE_FCNTL) && defined(F_GETFD) && defined(FD_CLOEXEC)
374 int flags = fcntl(fd, F_GETFD);
376 static const char m[] =
"reserved FD closed unexpectedly?\n";
377 (void)!write(2, m,
sizeof(m) - 1);
380 if (flags & FD_CLOEXEC)
return;
381 rb_bug(
"reserved FD did not have close-on-exec set");
383 rb_bug(
"reserved FD without close-on-exec support");
389close_unless_reserved(
int fd)
392 assert_close_on_exec(fd);
399#if defined(DEBUG_REDIRECT)
402ttyprintf(
const char *fmt, ...)
408 tty = fopen(
"con",
"w");
410 tty = fopen(
"/dev/tty",
"w");
416 vfprintf(tty, fmt, ap);
423redirect_dup(
int oldfd)
427 ttyprintf(
"dup(%d) => %d\n", oldfd, ret);
432redirect_dup2(
int oldfd,
int newfd)
435 ret = dup2(oldfd, newfd);
436 ttyprintf(
"dup2(%d, %d) => %d\n", oldfd, newfd, ret);
441redirect_cloexec_dup(
int oldfd)
445 ttyprintf(
"cloexec_dup(%d) => %d\n", oldfd, ret);
450redirect_cloexec_dup2(
int oldfd,
int newfd)
454 ttyprintf(
"cloexec_dup2(%d, %d) => %d\n", oldfd, newfd, ret);
459redirect_close(
int fd)
462 ret = close_unless_reserved(fd);
463 ttyprintf(
"close(%d) => %d\n", fd, ret);
468parent_redirect_open(
const char *pathname,
int flags, mode_t perm)
472 ttyprintf(
"parent_open(\"%s\", 0x%x, 0%o) => %d\n", pathname, flags, perm, ret);
477parent_redirect_close(
int fd)
480 ret = close_unless_reserved(fd);
481 ttyprintf(
"parent_close(%d) => %d\n", fd, ret);
486#define redirect_dup(oldfd) dup(oldfd)
487#define redirect_dup2(oldfd, newfd) dup2((oldfd), (newfd))
488#define redirect_cloexec_dup(oldfd) rb_cloexec_dup(oldfd)
489#define redirect_cloexec_dup2(oldfd, newfd) rb_cloexec_dup2((oldfd), (newfd))
490#define redirect_close(fd) close_unless_reserved(fd)
491#define parent_redirect_open(pathname, flags, perm) rb_cloexec_open((pathname), (flags), (perm))
492#define parent_redirect_close(fd) close_unless_reserved(fd)
498 if (UNLIKELY(!cached_pid)) {
499 cached_pid = getpid();
505#if defined HAVE_WORKING_FORK || defined HAVE_DAEMON
579static VALUE rb_cProcessStatus;
594 .flags = RUBY_TYPED_THREAD_SAFE_FREE | RUBY_TYPED_WB_PROTECTED | RUBY_TYPED_EMBEDDABLE,
598rb_process_status_allocate(
VALUE klass)
607 return GET_THREAD()->last_status;
633proc_s_last_status(
VALUE mod)
641 VALUE last_status = rb_process_status_allocate(rb_cProcessStatus);
644 data->status = status;
652process_status_dump(
VALUE status)
665process_status_load(
VALUE real_obj,
VALUE load_obj)
668 VALUE status = rb_attr_get(load_obj, id_status);
669 VALUE pid = rb_attr_get(load_obj, id_pid);
684 th->last_status =
Qnil;
688rb_last_status_clear(
void)
690 last_status_clear(GET_THREAD());
702pst_status(
VALUE status)
722 int status = pst_status(self);
726#define PST2INT(st) pst_status(st)
742 rb_pid_t pid = pst_pid(self);
746static VALUE pst_message_status(
VALUE str,
int status);
749pst_message(
VALUE str, rb_pid_t pid,
int status)
751 rb_str_catf(str,
"pid %ld", (
long)pid);
752 pst_message_status(str, status);
756pst_message_status(
VALUE str,
int status)
758 if (WIFSTOPPED(status)) {
759 int stopsig = WSTOPSIG(status);
762 rb_str_catf(str,
" stopped SIG%s (signal %d)", signame, stopsig);
765 rb_str_catf(str,
" stopped signal %d", stopsig);
768 if (WIFSIGNALED(status)) {
769 int termsig = WTERMSIG(status);
772 rb_str_catf(str,
" SIG%s (signal %d)", signame, termsig);
775 rb_str_catf(str,
" signal %d", termsig);
778 if (WIFEXITED(status)) {
779 rb_str_catf(str,
" exit %d", WEXITSTATUS(status));
782 if (WCOREDUMP(status)) {
810 status = PST2INT(st);
813 pst_message(str, pid, status);
840 status = PST2INT(st);
843 pst_message(str, pid, status);
865 if (st1 == st2)
return Qtrue;
866 return rb_equal(pst_to_i(st1), st2);
880pst_wifstopped(
VALUE st)
882 int status = PST2INT(st);
884 return RBOOL(WIFSTOPPED(status));
897pst_wstopsig(
VALUE st)
899 int status = PST2INT(st);
901 if (WIFSTOPPED(status))
902 return INT2NUM(WSTOPSIG(status));
916pst_wifsignaled(
VALUE st)
918 int status = PST2INT(st);
920 return RBOOL(WIFSIGNALED(status));
933pst_wtermsig(
VALUE st)
935 int status = PST2INT(st);
937 if (WIFSIGNALED(status))
938 return INT2NUM(WTERMSIG(status));
953pst_wifexited(
VALUE st)
955 int status = PST2INT(st);
957 return RBOOL(WIFEXITED(status));
975pst_wexitstatus(
VALUE st)
977 int status = PST2INT(st);
979 if (WIFEXITED(status))
980 return INT2NUM(WEXITSTATUS(status));
998pst_success_p(
VALUE st)
1000 int status = PST2INT(st);
1002 if (!WIFEXITED(status))
1004 return RBOOL(WEXITSTATUS(status) == EXIT_SUCCESS);
1019pst_wcoredump(
VALUE st)
1022 int status = PST2INT(st);
1024 return RBOOL(WCOREDUMP(status));
1031do_waitpid(rb_pid_t pid,
int *st,
int flags)
1033#if defined HAVE_WAITPID
1034 return waitpid(pid, st, flags);
1035#elif defined HAVE_WAIT4
1036 return wait4(pid, st, flags, NULL);
1038# error waitpid or wait4 is required.
1043 struct ccan_list_node wnode;
1045 rb_nativethread_cond_t *cond;
1054waitpid_state_init(
struct waitpid_state *w, rb_pid_t pid,
int options)
1058 w->options = options;
1064waitpid_blocking_no_SIGCHLD(
void *x)
1068 w->ret = do_waitpid(w->pid, &w->status, w->options);
1076 if (w->options & WNOHANG) {
1077 w->ret = do_waitpid(w->pid, &w->status, w->options);
1082 }
while (w->ret < 0 &&
errno == EINTR && (RUBY_VM_CHECK_INTS(w->ec),1));
1092 if (!(flags & WNOHANG)) {
1094 if (scheduler !=
Qnil) {
1096 if (!UNDEF_P(result))
return result;
1142rb_process_status_waitv(
int argc,
VALUE *argv,
VALUE _)
1164 if (
NIL_P(status))
return 0;
1169 if (st) *st = data->status;
1172 errno = data->error;
1175 GET_THREAD()->last_status = status;
1182proc_wait(
int argc,
VALUE *argv)
1194 if (argc == 2 && !
NIL_P(vflags = argv[1])) {
1199 if ((pid =
rb_waitpid(pid, &status, flags)) < 0)
1203 rb_last_status_clear();
1360 return proc_wait(c, v);
1380 VALUE pid = proc_wait(argc, argv);
1409 rb_last_status_clear();
1424static VALUE rb_cWaiter;
1427detach_process_pid(
VALUE thread)
1433detach_process_watcher(
void *arg)
1435 rb_pid_t cpid, pid = (rb_pid_t)(
VALUE)arg;
1438 while ((cpid =
rb_waitpid(pid, &status, 0)) == 0) {
1449 RBASIC_SET_CLASS(watcher, rb_cWaiter);
1501before_exec_async_signal_safe(
void)
1506before_exec_non_async_signal_safe(
void)
1517 rb_thread_stop_timer_thread();
1520#define WRITE_CONST(fd, str) (void)(write((fd),(str),sizeof(str)-1)<0)
1522int rb_w32_set_nonblock2(
int fd,
int nonblock);
1529 return rb_w32_set_nonblock2(fd, 0);
1530#elif defined(F_GETFL) && defined(F_SETFL)
1531 int fl = fcntl(fd, F_GETFL);
1534 if (fl == -1)
return fl;
1535 if (fl & O_NONBLOCK) {
1537 return fcntl(fd, F_SETFL, fl);
1544stdfd_clear_nonblock(
void)
1548 for (fd = 0; fd < 3; fd++) {
1549 (void)set_blocking(fd);
1556 before_exec_non_async_signal_safe();
1557 before_exec_async_signal_safe();
1563 rb_thread_reset_timer_thread();
1564 rb_thread_start_timer_thread();
1567#if defined HAVE_WORKING_FORK || defined HAVE_DAEMON
1569before_fork_ruby(
void)
1572 rb_gc_before_fork();
1576after_fork_ruby(rb_pid_t pid)
1578 rb_gc_after_fork(pid);
1592#if defined(HAVE_WORKING_FORK)
1594COMPILER_WARNING_PUSH
1595#if __has_warning("-Wdeprecated-declarations") || RBIMPL_COMPILER_IS(GCC)
1596COMPILER_WARNING_IGNORED(-Wdeprecated-declarations)
1598static inline rb_pid_t
1606#define try_with_sh(err, prog, argv, envp) ((err == ENOEXEC) ? exec_with_sh((prog), (argv), (envp)) : (void)0)
1608exec_with_sh(
const char *prog,
char **argv,
char **envp)
1610 *argv = (
char *)prog;
1611 *--argv = (
char *)
"sh";
1613 execve(
"/bin/sh", argv, envp);
1615 execv(
"/bin/sh", argv);
1619#define try_with_sh(err, prog, argv, envp) (void)0
1624proc_exec_cmd(
const char *prog,
VALUE argv_str,
VALUE envp_str)
1632 argv = ARGVSTR2ARGV(argv_str);
1639 rb_w32_uaspawn(P_OVERLAY, prog, argv);
1642 envp = envp_str ? RB_IMEMO_TMPBUF_PTR(envp_str) : NULL;
1644 execve(prog, argv, envp);
1648 try_with_sh(err, prog, argv, envp);
1655proc_exec_sh(
const char *str,
VALUE envp_str)
1660 while (*s ==
' ' || *s ==
'\t' || *s ==
'\n')
1668 rb_w32_uspawn(P_OVERLAY, (
char *)str, 0);
1671 execle(
"/bin/sh",
"sh",
"-c", str, (
char *)NULL, RB_IMEMO_TMPBUF_PTR(envp_str));
1673 execl(
"/bin/sh",
"sh",
"-c", str, (
char *)NULL);
1683 ret = proc_exec_sh(str,
Qfalse);
1690mark_exec_arg(
void *ptr)
1693 if (eargp->use_shell)
1694 rb_gc_mark(eargp->invoke.sh.shell_script);
1696 rb_gc_mark(eargp->invoke.cmd.command_name);
1697 rb_gc_mark(eargp->invoke.cmd.command_abspath);
1698 rb_gc_mark(eargp->invoke.cmd.argv_str);
1699 rb_gc_mark(eargp->invoke.cmd.argv_buf);
1701 rb_gc_mark(eargp->redirect_fds);
1702 rb_gc_mark(eargp->envp_str);
1703 rb_gc_mark(eargp->envp_buf);
1704 rb_gc_mark(eargp->dup2_tmpbuf);
1705 rb_gc_mark(eargp->rlimit_limits);
1706 rb_gc_mark(eargp->fd_dup2);
1707 rb_gc_mark(eargp->fd_close);
1708 rb_gc_mark(eargp->fd_open);
1709 rb_gc_mark(eargp->fd_dup2_child);
1710 rb_gc_mark(eargp->env_modification);
1711 rb_gc_mark(eargp->path_env);
1712 rb_gc_mark(eargp->chdir_dir);
1716memsize_exec_arg(
const void *ptr)
1724 0, 0, RUBY_TYPED_THREAD_SAFE_FREE | RUBY_TYPED_EMBEDDABLE
1728# define DEFAULT_PROCESS_ENCODING rb_utf8_encoding()
1730#ifdef DEFAULT_PROCESS_ENCODING
1731# define EXPORT_STR(str) rb_str_export_to_enc((str), DEFAULT_PROCESS_ENCODING)
1732# define EXPORT_DUP(str) export_dup(str)
1734export_dup(
VALUE str)
1736 VALUE newstr = EXPORT_STR(str);
1741# define EXPORT_STR(str) (str)
1742# define EXPORT_DUP(str) rb_str_dup(str)
1745#if !defined(HAVE_WORKING_FORK) && defined(HAVE_SPAWNV)
1746# define USE_SPAWNV 1
1748# define USE_SPAWNV 0
1751# define P_NOWAIT _P_NOWAIT
1756#define proc_spawn_cmd_internal(argv, prog) rb_w32_uaspawn(P_NOWAIT, (prog), (argv))
1759proc_spawn_cmd_internal(
char **argv,
char *prog)
1761 char fbuf[MAXPATHLEN];
1766 prog = dln_find_exe_r(prog, 0, fbuf,
sizeof(fbuf));
1771 status = spawnv(P_NOWAIT, prog, (
const char **)argv);
1772 if (status == -1 &&
errno == ENOEXEC) {
1773 *argv = (
char *)prog;
1774 *--argv = (
char *)
"sh";
1775 status = spawnv(P_NOWAIT,
"/bin/sh", (
const char **)argv);
1777 if (status == -1)
errno = ENOEXEC;
1791 if (eargp->new_pgroup_given && eargp->new_pgroup_flag) {
1792 flags = CREATE_NEW_PROCESS_GROUP;
1794 pid = rb_w32_uaspawn_flags(P_NOWAIT, prog ? RSTRING_PTR(prog) : 0, argv, flags);
1796 pid = proc_spawn_cmd_internal(argv, prog ? RSTRING_PTR(prog) : 0);
1803#define proc_spawn_sh(str) rb_w32_uspawn(P_NOWAIT, (str), 0)
1806proc_spawn_sh(
char *str)
1808 char fbuf[MAXPATHLEN];
1811 char *shell = dln_find_exe_r(
"sh", 0, fbuf,
sizeof(fbuf));
1813 status = spawnl(P_NOWAIT, (shell ? shell :
"/bin/sh"),
"sh",
"-c", str, (char*)NULL);
1823 RBASIC_CLEAR_CLASS(obj);
1828check_exec_redirect_fd(
VALUE v,
int iskey)
1839 else if (
id == id_out)
1841 else if (
id == id_err)
1850 rb_raise(rb_eArgError,
"duplex IO redirection");
1857 rb_raise(rb_eArgError,
"negative file descriptor");
1860 else if (fd >= 3 && iskey) {
1861 rb_raise(rb_eArgError,
"wrong file descriptor (%d)", fd);
1867 rb_raise(rb_eArgError,
"wrong exec redirect");
1878 VALUE fd = check_exec_redirect_fd(key, !
NIL_P(param));
1885 VALUE fd = check_exec_redirect_fd(v, !
NIL_P(param));
1896 VALUE path, flags, perm;
1900 switch (
TYPE(val)) {
1903 if (
id == id_close) {
1905 eargp->fd_close = check_exec_redirect1(eargp->fd_close, key, param);
1907 else if (
id == id_in) {
1909 eargp->fd_dup2 = check_exec_redirect1(eargp->fd_dup2, key, param);
1911 else if (
id == id_out) {
1913 eargp->fd_dup2 = check_exec_redirect1(eargp->fd_dup2, key, param);
1915 else if (
id == id_err) {
1917 eargp->fd_dup2 = check_exec_redirect1(eargp->fd_dup2, key, param);
1920 rb_raise(rb_eArgError,
"wrong exec redirect symbol: %"PRIsVALUE,
1927 val = check_exec_redirect_fd(val, 0);
1931 eargp->fd_dup2 = check_exec_redirect1(eargp->fd_dup2, key, param);
1937 path ==
ID2SYM(id_child)) {
1938 param = check_exec_redirect_fd(
rb_ary_entry(val, 1), 0);
1939 eargp->fd_dup2_child = check_exec_redirect1(eargp->fd_dup2_child, key, param);
1952 param = hide_obj(
rb_ary_new3(4, hide_obj(EXPORT_DUP(path)),
1953 flags, perm,
Qnil));
1954 eargp->fd_open = check_exec_redirect1(eargp->fd_open, key, param);
1962 key = check_exec_redirect_fd(key, 1);
1964 flags =
INT2NUM(O_WRONLY|O_CREAT|O_TRUNC);
1969 VALUE fd = check_exec_redirect_fd(v, 1);
1973 flags =
INT2NUM(O_WRONLY|O_CREAT|O_TRUNC);
1980 param = hide_obj(
rb_ary_new3(4, hide_obj(EXPORT_DUP(path)),
1981 flags, perm,
Qnil));
1982 eargp->fd_open = check_exec_redirect1(eargp->fd_open, key, param);
1988 if (!
NIL_P(val))
goto io;
1989 rb_raise(rb_eArgError,
"wrong exec redirect action");
1994#if defined(HAVE_SETRLIMIT) && defined(NUM2RLIM)
1995static int rlimit_type_by_sym(
VALUE key);
1998rb_execarg_addopt_rlimit(
struct rb_execarg *eargp,
int rtype,
VALUE val)
2000 VALUE ary = eargp->rlimit_limits;
2001 VALUE tmp, softlim, hardlim;
2002 if (eargp->rlimit_limits ==
Qfalse)
2003 ary = eargp->rlimit_limits = hide_obj(
rb_ary_new());
2005 ary = eargp->rlimit_limits;
2015 rb_raise(rb_eArgError,
"wrong exec rlimit option");
2026#define TO_BOOL(val, name) (NIL_P(val) ? 0 : rb_bool_expected((val), name, TRUE))
2030 struct rb_execarg *eargp = rb_execarg_get(execarg_obj);
2034 switch (
TYPE(key)) {
2036#if defined(HAVE_SETRLIMIT) && defined(NUM2RLIM)
2038 int rtype = rlimit_type_by_sym(key);
2040 rb_execarg_addopt_rlimit(eargp, rtype, val);
2048 if (
id == id_pgroup) {
2050 if (eargp->pgroup_given) {
2051 rb_raise(rb_eArgError,
"pgroup option specified twice");
2055 else if (val ==
Qtrue)
2060 rb_raise(rb_eArgError,
"negative process group ID : %ld", (
long)pgroup);
2063 eargp->pgroup_given = 1;
2064 eargp->pgroup_pgid = pgroup;
2069 if (
id == id_new_pgroup) {
2070 if (eargp->new_pgroup_given) {
2071 rb_raise(rb_eArgError,
"new_pgroup option specified twice");
2073 eargp->new_pgroup_given = 1;
2074 eargp->new_pgroup_flag = TO_BOOL(val,
"new_pgroup");
2078 if (
id == id_unsetenv_others) {
2079 if (eargp->unsetenv_others_given) {
2080 rb_raise(rb_eArgError,
"unsetenv_others option specified twice");
2082 eargp->unsetenv_others_given = 1;
2083 eargp->unsetenv_others_do = TO_BOOL(val,
"unsetenv_others");
2085 else if (
id == id_chdir) {
2086 if (eargp->chdir_given) {
2087 rb_raise(rb_eArgError,
"chdir option specified twice");
2090 val = rb_str_encode_ospath(val);
2091 eargp->chdir_given = 1;
2092 eargp->chdir_dir = hide_obj(EXPORT_DUP(val));
2094 else if (
id == id_umask) {
2096 if (eargp->umask_given) {
2097 rb_raise(rb_eArgError,
"umask option specified twice");
2099 eargp->umask_given = 1;
2100 eargp->umask_mask = cmask;
2102 else if (
id == id_close_others) {
2103 if (eargp->close_others_given) {
2104 rb_raise(rb_eArgError,
"close_others option specified twice");
2106 eargp->close_others_given = 1;
2107 eargp->close_others_do = TO_BOOL(val,
"close_others");
2109 else if (
id == id_in) {
2113 else if (
id == id_out) {
2117 else if (
id == id_err) {
2121 else if (
id == id_uid) {
2123 if (eargp->uid_given) {
2124 rb_raise(rb_eArgError,
"uid option specified twice");
2128 eargp->uid = OBJ2UID(val);
2129 eargp->uid_given = 1;
2133 "uid option is unimplemented on this machine");
2136 else if (
id == id_gid) {
2138 if (eargp->gid_given) {
2139 rb_raise(rb_eArgError,
"gid option specified twice");
2143 eargp->gid = OBJ2GID(val);
2144 eargp->gid_given = 1;
2148 "gid option is unimplemented on this machine");
2151 else if (
id == id_exception) {
2152 if (eargp->exception_given) {
2153 rb_raise(rb_eArgError,
"exception option specified twice");
2155 eargp->exception_given = 1;
2156 eargp->exception = TO_BOOL(val,
"exception");
2167 check_exec_redirect(key, val, eargp);
2179check_exec_options_i(st_data_t st_key, st_data_t st_val, st_data_t arg)
2184 if (rb_execarg_addopt(execarg_obj, key, val) != ST_CONTINUE) {
2186 rb_raise(rb_eArgError,
"wrong exec option symbol: % "PRIsVALUE,
2188 rb_raise(rb_eArgError,
"wrong exec option: %"PRIsVALUE,
rb_obj_class(key));
2194check_exec_options_i_extract(st_data_t st_key, st_data_t st_val, st_data_t arg)
2199 VALUE execarg_obj = args[0];
2200 if (rb_execarg_addopt(execarg_obj, key, val) != ST_CONTINUE) {
2201 VALUE nonopts = args[1];
2202 if (
NIL_P(nonopts)) args[1] = nonopts = rb_hash_new();
2203 rb_hash_aset(nonopts, key, val);
2218 rb_raise(rb_eArgError,
"fd %d specified twice", fd);
2220 if (ary == eargp->fd_dup2)
2222 else if (ary == eargp->fd_dup2_child)
2228 if (ary == eargp->fd_dup2 || ary == eargp->fd_dup2_child) {
2241 VALUE h = rb_hash_new();
2246 maxhint = check_exec_fds_1(eargp, h, maxhint, eargp->fd_dup2);
2247 maxhint = check_exec_fds_1(eargp, h, maxhint, eargp->fd_close);
2248 maxhint = check_exec_fds_1(eargp, h, maxhint, eargp->fd_dup2_child);
2250 if (eargp->fd_dup2_child) {
2251 ary = eargp->fd_dup2_child;
2261 val = rb_hash_lookup(h, val);
2263 rb_raise(rb_eArgError,
"cyclic child fd redirection from %d", oldfd);
2267 rb_raise(rb_eArgError,
"child fd %d is not redirected", oldfd);
2268 if (oldfd != lastfd) {
2273 while (
FIXNUM_P(val2 = rb_hash_lookup(h, val))) {
2274 rb_hash_aset(h, val,
INT2FIX(lastfd));
2281 eargp->close_others_maxhint = maxhint;
2286rb_check_exec_options(
VALUE opthash,
VALUE execarg_obj)
2290 rb_hash_stlike_foreach(opthash, check_exec_options_i, (st_data_t)execarg_obj);
2294rb_execarg_extract_options(
VALUE execarg_obj,
VALUE opthash)
2299 args[0] = execarg_obj;
2301 rb_hash_stlike_foreach(opthash, check_exec_options_i_extract, (st_data_t)args);
2305#ifdef ENV_IGNORECASE
2306#define ENVMATCH(s1, s2) (STRCASECMP((s1), (s2)) == 0)
2308#define ENVMATCH(n1, n2) (strcmp((n1), (n2)) == 0)
2312check_exec_env_i(st_data_t st_key, st_data_t st_val, st_data_t arg)
2322 rb_raise(rb_eArgError,
"environment name contains a equal : %"PRIsVALUE, key);
2327 key = EXPORT_STR(key);
2328 if (!
NIL_P(val)) val = EXPORT_STR(val);
2345 rb_hash_stlike_foreach(hash, check_exec_env_i, (st_data_t)env);
2352rb_check_argv(
int argc,
VALUE *argv)
2363 rb_raise(rb_eArgError,
"wrong first argument");
2371 for (i = 0; i < argc; i++) {
2380check_hash(
VALUE obj)
2390 return rb_check_hash_type(obj);
2394rb_exec_getargs(
int *argc_p,
VALUE **argv_p,
int accept_shell,
VALUE *env_ret,
VALUE *opthash_ret)
2399 hash = check_hash((*argv_p)[*argc_p-1]);
2401 *opthash_ret = hash;
2407 hash = check_hash((*argv_p)[0]);
2414 prog = rb_check_argv(*argc_p, *argv_p);
2416 prog = (*argv_p)[0];
2417 if (accept_shell && *argc_p == 1) {
2432compare_posix_sh(
const void *key,
const void *el)
2435 int ret = strncmp(word->ptr, el, word->len);
2436 if (!ret && ((
const char *)el)[word->len]) ret = -1;
2441#define append_terminator(buf) rb_str_buf_cat(buf, "", 1)
2446 struct rb_execarg *eargp = rb_execarg_get(execarg_obj);
2447 char fbuf[MAXPATHLEN];
2451 if (!
NIL_P(opthash)) {
2452 rb_check_exec_options(opthash, execarg_obj);
2455 env = rb_check_exec_env(env, &eargp->path_env);
2456 eargp->env_modification = env;
2459 prog = EXPORT_STR(prog);
2460 eargp->use_shell = argc == 0;
2461 if (eargp->use_shell)
2462 eargp->invoke.sh.shell_script = prog;
2464 eargp->invoke.cmd.command_name = prog;
2467 if (eargp->use_shell) {
2468 static const char posix_sh_cmds[][9] = {
2500 const char *
const s = rb_str_null_check(prog);
2529 for (p = s; p < e; p++) {
2530 if (*p ==
' ' || *p ==
'\t') {
2531 if (first.ptr && !first.len) first.len = p - first.ptr;
2534 if (!first.ptr) first.ptr = p;
2536 if (!has_meta && strchr(
"*?{}[]<>()~&|\\$;'`\"\n#", *p))
2542 else if (*p ==
'/') {
2550 if (!first.ptr) first.ptr = e;
2551 if (!first.len) first.len = p - first.ptr;
2552 if (first.len > 0 && first.len <=
sizeof(posix_sh_cmds[0]) &&
2554 bsearch(&first, posix_sh_cmds, numberof(posix_sh_cmds),
sizeof(posix_sh_cmds[0]), compare_posix_sh))
2559 eargp->use_shell = 0;
2561 if (!eargp->use_shell) {
2565 append_terminator(argv_buf);
2566 for (p = first.ptr + first.len; p < e;) {
2567 while (p < e && (*p ==
' ' || *p ==
'\t'))
2571 while (p < e && *p !=
' ' && *p !=
'\t')
2574 append_terminator(argv_buf);
2577 eargp->invoke.cmd.argv_buf = argv_buf;
2578 eargp->invoke.cmd.command_name =
2580 rb_enc_copy(eargp->invoke.cmd.command_name, prog);
2585 if (!eargp->use_shell) {
2586 const char *abspath;
2587 const char *path_env = 0;
2588 if (
RTEST(eargp->path_env)) path_env = RSTRING_PTR(eargp->path_env);
2589 abspath = dln_find_exe_r(RSTRING_PTR(eargp->invoke.cmd.command_name),
2590 path_env, fbuf,
sizeof(fbuf));
2594 eargp->invoke.cmd.command_abspath =
Qnil;
2597 if (!eargp->use_shell && !eargp->invoke.cmd.argv_buf) {
2602 for (i = 0; i < argc; i++) {
2603 VALUE arg = argv[i];
2605#ifdef DEFAULT_PROCESS_ENCODING
2606 arg = EXPORT_STR(arg);
2607 s = RSTRING_PTR(arg);
2610 append_terminator(argv_buf);
2612 eargp->invoke.cmd.argv_buf = argv_buf;
2615 if (!eargp->use_shell) {
2616 const char *p, *ep, *null=NULL;
2620 p = RSTRING_PTR(eargp->invoke.cmd.argv_buf);
2621 ep = p + RSTRING_LEN(eargp->invoke.cmd.argv_buf);
2627 eargp->invoke.cmd.argv_str =
2628 rb_imemo_tmpbuf_new_from_an_RString(argv_str);
2634rb_execarg_get(
VALUE execarg_obj)
2642rb_execarg_init(
int argc,
const VALUE *orig_argv,
int accept_shell,
VALUE execarg_obj)
2644 struct rb_execarg *eargp = rb_execarg_get(execarg_obj);
2650 prog = rb_exec_getargs(&argc, &argv, accept_shell, &env, &opthash);
2651 rb_exec_fillarg(prog, argc, argv, env, opthash, execarg_obj);
2653 ret = eargp->use_shell ? eargp->invoke.sh.shell_script : eargp->invoke.cmd.command_name;
2659rb_execarg_new(
int argc,
const VALUE *argv,
int accept_shell,
int allow_exc_opt)
2664 rb_execarg_init(argc, argv, accept_shell, execarg_obj);
2665 if (!allow_exc_opt && eargp->exception_given) {
2666 rb_raise(rb_eArgError,
"exception option is not allowed");
2672rb_execarg_setenv(
VALUE execarg_obj,
VALUE env)
2674 struct rb_execarg *eargp = rb_execarg_get(execarg_obj);
2675 env = !
NIL_P(env) ? rb_check_exec_env(env, &eargp->path_env) :
Qfalse;
2676 eargp->env_modification = env;
2681fill_envp_buf_i(st_data_t st_key, st_data_t st_val, st_data_t arg)
2690 append_terminator(envp_buf);
2696static long run_exec_dup2_tmpbuf_size(
long n);
2710 const char *fname = RSTRING_PTR(data->fname);
2711 data->ret = parent_redirect_open(fname, data->oflags, data->perm);
2717rb_execarg_allocate_dup2_tmpbuf(
struct rb_execarg *eargp,
long len)
2719 rb_alloc_tmp_buffer(&eargp->dup2_tmpbuf, run_exec_dup2_tmpbuf_size(
len),
false);
2723rb_execarg_parent_start1(
VALUE execarg_obj)
2725 struct rb_execarg *eargp = rb_execarg_get(execarg_obj);
2726 int unsetenv_others;
2730 ary = eargp->fd_open;
2745 open_data.fname = vpath;
2746 open_data.oflags = flags;
2747 open_data.perm = perm;
2749 open_data.err = EINTR;
2751 if (open_data.ret == -1) {
2752 if (open_data.err == EINTR) {
2758 fd2 = open_data.ret;
2770 eargp->redirect_fds = check_exec_fds(eargp);
2772 ary = eargp->fd_dup2;
2774 rb_execarg_allocate_dup2_tmpbuf(eargp,
RARRAY_LEN(ary));
2777 unsetenv_others = eargp->unsetenv_others_given && eargp->unsetenv_others_do;
2778 envopts = eargp->env_modification;
2779 if (ALWAYS_NEED_ENVP || unsetenv_others || envopts !=
Qfalse) {
2780 VALUE envtbl, envp_str, envp_buf;
2782 if (unsetenv_others) {
2783 envtbl = rb_hash_new();
2786 envtbl = rb_env_to_hash();
2796 rb_hash_delete(envtbl, key);
2799 rb_hash_aset(envtbl, key, val);
2805 rb_hash_stlike_foreach(envtbl, fill_envp_buf_i, (st_data_t)envp_buf);
2808 p = RSTRING_PTR(envp_buf);
2809 ep = p + RSTRING_LEN(envp_buf);
2817 rb_imemo_tmpbuf_new_from_an_RString(envp_str);
2818 eargp->envp_buf = envp_buf;
2834rb_execarg_parent_start(
VALUE execarg_obj)
2837 rb_protect(rb_execarg_parent_start1, execarg_obj, &state);
2839 rb_execarg_parent_end(execarg_obj);
2845execarg_parent_end(
VALUE execarg_obj)
2847 struct rb_execarg *eargp = rb_execarg_get(execarg_obj);
2851 ary = eargp->fd_open;
2862 parent_redirect_close(fd2);
2874rb_execarg_parent_end(
VALUE execarg_obj)
2876 execarg_parent_end(execarg_obj);
2880rb_exec_fail(
struct rb_execarg *eargp,
int err,
const char *errmsg)
2882 if (!errmsg || !*errmsg)
return;
2883 if (strcmp(errmsg,
"chdir") == 0) {
2884 rb_sys_fail_str(eargp->chdir_dir);
2886 rb_sys_fail(errmsg);
2891rb_execarg_fail(
VALUE execarg_obj,
int err,
const char *errmsg)
2893 if (!errmsg || !*errmsg)
return;
2894 rb_exec_fail(rb_execarg_get(execarg_obj), err, errmsg);
2902 VALUE execarg_obj, fail_str;
2904#define CHILD_ERRMSG_BUFLEN 80
2905 char errmsg[CHILD_ERRMSG_BUFLEN] = {
'\0' };
2908 execarg_obj = rb_execarg_new(argc, argv, TRUE, FALSE);
2909 eargp = rb_execarg_get(execarg_obj);
2912 rb_protect(rb_execarg_parent_start1, execarg_obj, &state);
2914 execarg_parent_end(execarg_obj);
2919 fail_str = eargp->use_shell ? eargp->invoke.sh.shell_script : eargp->invoke.cmd.command_name;
2921 err = exec_async_signal_safe(eargp, errmsg,
sizeof(errmsg));
2924 rb_exec_fail(eargp, err, errmsg);
3028#define ERRMSG(str) \
3029 ((errmsg && 0 < errmsg_buflen) ? \
3030 (void)strlcpy(errmsg, (str), errmsg_buflen) : (void)0)
3032#define ERRMSG_FMT(...) \
3033 ((errmsg && 0 < errmsg_buflen) ? \
3034 (void)snprintf(errmsg, errmsg_buflen, __VA_ARGS__) : (void)0)
3036static int fd_get_cloexec(
int fd,
char *errmsg,
size_t errmsg_buflen);
3037static int fd_set_cloexec(
int fd,
char *errmsg,
size_t errmsg_buflen);
3038static int fd_clear_cloexec(
int fd,
char *errmsg,
size_t errmsg_buflen);
3041save_redirect_fd(
int fd,
struct rb_execarg *sargp,
char *errmsg,
size_t errmsg_buflen)
3044 VALUE newary, redirection;
3045 int save_fd = redirect_cloexec_dup(fd), cloexec;
3046 if (save_fd == -1) {
3053 newary = sargp->fd_dup2;
3056 sargp->fd_dup2 = newary;
3058 cloexec = fd_get_cloexec(fd, errmsg, errmsg_buflen);
3063 newary = sargp->fd_close;
3066 sargp->fd_close = newary;
3075intcmp(
const void *a,
const void *b)
3077 return *(
int*)a - *(
int*)b;
3081intrcmp(
const void *a,
const void *b)
3083 return *(
int*)b - *(
int*)a;
3095run_exec_dup2_tmpbuf_size(
long n)
3102fd_get_cloexec(
int fd,
char *errmsg,
size_t errmsg_buflen)
3106 ret = fcntl(fd, F_GETFD);
3108 ERRMSG(
"fcntl(F_GETFD)");
3111 if (ret & FD_CLOEXEC)
return 1;
3118fd_set_cloexec(
int fd,
char *errmsg,
size_t errmsg_buflen)
3122 ret = fcntl(fd, F_GETFD);
3124 ERRMSG(
"fcntl(F_GETFD)");
3127 if (!(ret & FD_CLOEXEC)) {
3129 ret = fcntl(fd, F_SETFD, ret);
3131 ERRMSG(
"fcntl(F_SETFD)");
3141fd_clear_cloexec(
int fd,
char *errmsg,
size_t errmsg_buflen)
3145 ret = fcntl(fd, F_GETFD);
3147 ERRMSG(
"fcntl(F_GETFD)");
3150 if (ret & FD_CLOEXEC) {
3152 ret = fcntl(fd, F_SETFD, ret);
3154 ERRMSG(
"fcntl(F_SETFD)");
3164run_exec_dup2(
VALUE ary,
VALUE tmpbuf,
struct rb_execarg *sargp,
char *errmsg,
size_t errmsg_buflen)
3174 for (i = 0; i < n; i++) {
3179 pairs[i].older_index = -1;
3189 for (i = 0; i < n; i++) {
3190 int newfd = pairs[i].newfd;
3194 pairs[i].num_newer = 0;
3196 while (pairs < found && (found-1)->oldfd == newfd)
3198 while (found < pairs+n && found->oldfd == newfd) {
3199 pairs[i].num_newer++;
3200 found->older_index = i;
3207 for (i = 0; i < n; i++) {
3209 while (j != -1 && pairs[j].oldfd != -1 && pairs[j].num_newer == 0) {
3210 if (save_redirect_fd(pairs[j].newfd, sargp, errmsg, errmsg_buflen) < 0)
3212 ret = redirect_dup2(pairs[j].oldfd, pairs[j].newfd);
3217 if (pairs[j].cloexec &&
3218 fd_set_cloexec(pairs[j].newfd, errmsg, errmsg_buflen)) {
3222 pairs[j].oldfd = -1;
3223 j = pairs[j].older_index;
3225 pairs[j].num_newer--;
3230 for (i = 0; i < n; i++) {
3232 if (pairs[i].oldfd == -1)
3234 if (pairs[i].oldfd == pairs[i].newfd) {
3235 if (fd_clear_cloexec(pairs[i].oldfd, errmsg, errmsg_buflen) == -1)
3237 pairs[i].oldfd = -1;
3240 if (extra_fd == -1) {
3241 extra_fd = redirect_dup(pairs[i].oldfd);
3242 if (extra_fd == -1) {
3248 if (fd_get_cloexec(pairs[i].oldfd, errmsg, errmsg_buflen)) {
3249 if (fd_set_cloexec(extra_fd, errmsg, errmsg_buflen)) {
3257 ret = redirect_dup2(pairs[i].oldfd, extra_fd);
3264 pairs[i].oldfd = extra_fd;
3265 j = pairs[i].older_index;
3266 pairs[i].older_index = -1;
3268 ret = redirect_dup2(pairs[j].oldfd, pairs[j].newfd);
3274 pairs[j].oldfd = -1;
3275 j = pairs[j].older_index;
3278 if (extra_fd != -1) {
3279 ret = redirect_close(extra_fd);
3294run_exec_close(
VALUE ary,
char *errmsg,
size_t errmsg_buflen)
3302 ret = redirect_close(fd);
3313run_exec_dup2_child(
VALUE ary,
struct rb_execarg *sargp,
char *errmsg,
size_t errmsg_buflen)
3323 if (save_redirect_fd(newfd, sargp, errmsg, errmsg_buflen) < 0)
3325 ret = redirect_dup2(oldfd, newfd);
3338run_exec_pgroup(
const struct rb_execarg *eargp,
struct rb_execarg *sargp,
char *errmsg,
size_t errmsg_buflen)
3350 pgroup = eargp->pgroup_pgid;
3356 sargp->pgroup_given = 1;
3357 sargp->pgroup_pgid = getpgrp();
3363 ret = setpgid(getpid(), pgroup);
3364 if (ret == -1) ERRMSG(
"setpgid");
3369#if defined(HAVE_SETRLIMIT) && defined(RLIM2NUM)
3372run_exec_rlimit(
VALUE ary,
struct rb_execarg *sargp,
char *errmsg,
size_t errmsg_buflen)
3381 if (getrlimit(rtype, &rlim) == -1) {
3382 ERRMSG(
"getrlimit");
3386 RLIM2NUM(rlim.rlim_cur),
3387 RLIM2NUM(rlim.rlim_max)));
3388 if (sargp->rlimit_limits ==
Qfalse)
3389 newary = sargp->rlimit_limits = hide_obj(
rb_ary_new());
3391 newary = sargp->rlimit_limits;
3396 if (setrlimit(rtype, &rlim) == -1) {
3397 ERRMSG(
"setrlimit");
3405#if !defined(HAVE_WORKING_FORK)
3418 if (sargp->env_modification ==
Qfalse) {
3419 VALUE env = rb_envtbl();
3424 sargp->env_modification = ary;
3426 sargp->unsetenv_others_given = 1;
3427 sargp->unsetenv_others_do = 1;
3434#define chdir(p) rb_w32_uchdir(p)
3439rb_execarg_run_options(
const struct rb_execarg *eargp,
struct rb_execarg *sargp,
char *errmsg,
size_t errmsg_buflen)
3446 sargp->redirect_fds =
Qnil;
3450 if (eargp->pgroup_given) {
3451 if (run_exec_pgroup(eargp, sargp, errmsg, errmsg_buflen) == -1)
3456#if defined(HAVE_SETRLIMIT) && defined(RLIM2NUM)
3457 obj = eargp->rlimit_limits;
3459 if (run_exec_rlimit(obj, sargp, errmsg, errmsg_buflen) == -1)
3464#if !defined(HAVE_WORKING_FORK)
3465 if (eargp->unsetenv_others_given && eargp->unsetenv_others_do) {
3470 obj = eargp->env_modification;
3486 if (eargp->umask_given) {
3487 mode_t mask = eargp->umask_mask;
3488 mode_t oldmask = umask(mask);
3490 sargp->umask_given = 1;
3491 sargp->umask_mask = oldmask;
3495 obj = eargp->fd_dup2;
3497 if (run_exec_dup2(obj, eargp->dup2_tmpbuf, sargp, errmsg, errmsg_buflen) == -1)
3501 obj = eargp->fd_close;
3504 rb_warn(
"cannot close fd before spawn");
3506 if (run_exec_close(obj, errmsg, errmsg_buflen) == -1)
3511#ifdef HAVE_WORKING_FORK
3512 if (eargp->close_others_do) {
3517 obj = eargp->fd_dup2_child;
3519 if (run_exec_dup2_child(obj, sargp, errmsg, errmsg_buflen) == -1)
3523 if (eargp->chdir_given) {
3525 sargp->chdir_given = 1;
3526 sargp->chdir_dir = hide_obj(rb_dir_getwd_ospath());
3528 if (chdir(RSTRING_PTR(eargp->chdir_dir)) == -1) {
3535 if (eargp->gid_given) {
3536 if (setgid(eargp->gid) < 0) {
3543 if (eargp->uid_given) {
3544 if (setuid(eargp->uid) < 0) {
3552 VALUE ary = sargp->fd_dup2;
3554 rb_execarg_allocate_dup2_tmpbuf(sargp,
RARRAY_LEN(ary));
3558 int preserve =
errno;
3559 stdfd_clear_nonblock();
3568rb_exec_async_signal_safe(
const struct rb_execarg *eargp,
char *errmsg,
size_t errmsg_buflen)
3570 errno = exec_async_signal_safe(eargp, errmsg, errmsg_buflen);
3575exec_async_signal_safe(
const struct rb_execarg *eargp,
char *errmsg,
size_t errmsg_buflen)
3577#if !defined(HAVE_WORKING_FORK)
3578 struct rb_execarg sarg, *
const sargp = &sarg;
3584 if (rb_execarg_run_options(eargp, sargp, errmsg, errmsg_buflen) < 0) {
3588 if (eargp->use_shell) {
3589 err = proc_exec_sh(RSTRING_PTR(eargp->invoke.sh.shell_script), eargp->envp_str);
3592 char *abspath = NULL;
3593 if (!
NIL_P(eargp->invoke.cmd.command_abspath))
3594 abspath = RSTRING_PTR(eargp->invoke.cmd.command_abspath);
3595 err = proc_exec_cmd(abspath, eargp->invoke.cmd.argv_str, eargp->envp_str);
3597#if !defined(HAVE_WORKING_FORK)
3598 rb_execarg_run_options(sargp, NULL, errmsg, errmsg_buflen);
3604#ifdef HAVE_WORKING_FORK
3607rb_exec_atfork(
void* arg,
char *errmsg,
size_t errmsg_buflen)
3609 return rb_exec_async_signal_safe(arg, errmsg, errmsg_buflen);
3613proc_syswait(
VALUE pid)
3620move_fds_to_avoid_crash(
int *fdp,
int n,
VALUE fds)
3624 for (i = 0; i < n; i++) {
3643pipe_nocrash(
int filedes[2],
VALUE fds)
3651 if (move_fds_to_avoid_crash(filedes, 2, fds) == -1) {
3666rb_thread_sleep_that_takes_VALUE_as_sole_argument(
VALUE n)
3673handle_fork_error(
int err,
struct rb_process_status *status,
int *ep,
volatile int *try_gc_p)
3679 if ((*try_gc_p)-- > 0 && !rb_during_gc()) {
3685#if defined(EWOULDBLOCK) && EWOULDBLOCK != EAGAIN
3688 if (!status && !ep) {
3693 rb_protect(rb_thread_sleep_that_takes_VALUE_as_sole_argument,
INT2FIX(1), &state);
3694 if (status) status->status = state;
3695 if (!state)
return 0;
3704 if (state && !status) rb_jump_tag(state);
3708#define prefork() ( \
3709 rb_io_flush(rb_stdout), \
3710 rb_io_flush(rb_stderr) \
3740write_retry(
int fd,
const void *buf,
size_t len)
3745 w = write(fd, buf,
len);
3746 }
while (w < 0 &&
errno == EINTR);
3752read_retry(
int fd,
void *buf,
size_t len)
3756 if (set_blocking(fd) != 0) {
3758 rb_async_bug_errno(
"set_blocking failed reading child error",
errno);
3763 r = read(fd, buf,
len);
3764 }
while (r < 0 &&
errno == EINTR);
3770send_child_error(
int fd,
char *errmsg,
size_t errmsg_buflen)
3775 if (write_retry(fd, &err,
sizeof(err)) < 0) err =
errno;
3776 if (errmsg && 0 < errmsg_buflen) {
3777 errmsg[errmsg_buflen-1] =
'\0';
3778 errmsg_buflen = strlen(errmsg);
3779 if (errmsg_buflen > 0 && write_retry(fd, errmsg, errmsg_buflen) < 0)
3785recv_child_error(
int fd,
int *errp,
char *errmsg,
size_t errmsg_buflen)
3789 if ((size = read_retry(fd, &err,
sizeof(err))) < 0) {
3793 if (size ==
sizeof(err) &&
3794 errmsg && 0 < errmsg_buflen) {
3795 ssize_t ret = read_retry(fd, errmsg, errmsg_buflen-1);
3804#ifdef HAVE_WORKING_VFORK
3805#if !defined(HAVE_GETRESUID) && defined(HAVE_GETUIDX)
3808getresuid(rb_uid_t *ruid, rb_uid_t *euid, rb_uid_t *suid)
3814 ret = getuidx(ID_SAVED);
3815 if (ret == (rb_uid_t)-1)
3820#define HAVE_GETRESUID
3823#if !defined(HAVE_GETRESGID) && defined(HAVE_GETGIDX)
3826getresgid(rb_gid_t *rgid, rb_gid_t *egid, rb_gid_t *sgid)
3832 ret = getgidx(ID_SAVED);
3833 if (ret == (rb_gid_t)-1)
3838#define HAVE_GETRESGID
3841#if !defined(RUBY_ASAN_ENABLED)
3857 rb_uid_t ruid, euid;
3858 rb_gid_t rgid, egid;
3860#if defined HAVE_ISSETUGID
3865#ifdef HAVE_GETRESUID
3869 ret = getresuid(&ruid, &euid, &suid);
3871 rb_sys_fail(
"getresuid(2)");
3880 if (euid == 0 || euid != ruid)
3883#ifdef HAVE_GETRESGID
3887 ret = getresgid(&rgid, &egid, &sgid);
3889 rb_sys_fail(
"getresgid(2)");
3906struct child_handler_disabler_state
3912disable_child_handler_before_fork(
struct child_handler_disabler_state *old)
3914#ifdef HAVE_PTHREAD_SIGMASK
3918 ret = sigfillset(&all);
3920 rb_sys_fail(
"sigfillset");
3922 ret = pthread_sigmask(SIG_SETMASK, &all, &old->sigmask);
3927# pragma GCC warning "pthread_sigmask on fork is not available. potentially dangerous"
3932disable_child_handler_fork_parent(
struct child_handler_disabler_state *old)
3934#ifdef HAVE_PTHREAD_SIGMASK
3937 ret = pthread_sigmask(SIG_SETMASK, &old->sigmask, NULL);
3942# pragma GCC warning "pthread_sigmask on fork is not available. potentially dangerous"
3948disable_child_handler_fork_child(
struct child_handler_disabler_state *old,
char *errmsg,
size_t errmsg_buflen)
3953 for (sig = 1; sig < NSIG; sig++) {
3954 sig_t handler = signal(sig, SIG_DFL);
3956 if (handler == SIG_ERR &&
errno == EINVAL) {
3959 if (handler == SIG_ERR) {
3960 ERRMSG(
"signal to obtain old action");
3964 if (sig == SIGPIPE) {
3969 if (handler == SIG_IGN) {
3970 signal(sig, SIG_IGN);
3975 sigemptyset(&old->sigmask);
3976 ret = sigprocmask(SIG_SETMASK, &old->sigmask, NULL);
3978 ERRMSG(
"sigprocmask");
3986 int (*chfunc)(
void*,
char *,
size_t),
void *charg,
3987 char *errmsg,
size_t errmsg_buflen,
3991 volatile int try_gc = 1;
3992 struct child_handler_disabler_state old;
3997 disable_child_handler_before_fork(&old);
4001#if defined(HAVE_WORKING_VFORK) && !defined(RUBY_ASAN_ENABLED)
4002 if (!has_privilege())
4012 ret = disable_child_handler_fork_child(&old, errmsg, errmsg_buflen);
4014 ret = chfunc(charg, errmsg, errmsg_buflen);
4015 if (!ret) _exit(EXIT_SUCCESS);
4017 send_child_error(ep[1], errmsg, errmsg_buflen);
4018#if EXIT_SUCCESS == 127
4019 _exit(EXIT_FAILURE);
4025 disable_child_handler_fork_parent(&old);
4029 if (handle_fork_error(err, status, ep, &try_gc))
4035fork_check_err(
struct rb_process_status *status,
int (*chfunc)(
void*,
char *,
size_t),
void *charg,
4036 VALUE fds,
char *errmsg,
size_t errmsg_buflen,
4044 struct waitpid_state *w = eargp && eargp->waitpid_state ? eargp->waitpid_state : 0;
4046 if (status) status->status = 0;
4048 if (pipe_nocrash(ep, fds))
return -1;
4050 pid = retry_fork_async_signal_safe(status, ep, chfunc, charg, errmsg, errmsg_buflen, w);
4052 if (status) status->pid = pid;
4055 if (status) status->error =
errno;
4062 error_occurred = recv_child_error(ep[0], &err, errmsg, errmsg_buflen);
4064 if (error_occurred) {
4067 status->error = err;
4069 VM_ASSERT((w == 0) &&
"only used by extensions");
4070 rb_protect(proc_syswait, (
VALUE)pid, &state);
4072 status->status = state;
4093rb_fork_async_signal_safe(
int *status,
4094 int (*chfunc)(
void*,
char *,
size_t),
void *charg,
4095 VALUE fds,
char *errmsg,
size_t errmsg_buflen)
4099 rb_pid_t result = fork_check_err(&process_status, chfunc, charg, fds, errmsg, errmsg_buflen, 0);
4102 *status = process_status.status;
4109rb_fork_ruby(
int *status)
4111 if (UNLIKELY(!rb_ractor_main_p())) {
4112 rb_raise(rb_eRactorIsolationError,
"can not fork from non-main Ractors");
4117 int try_gc = 1, err = 0;
4118 struct child_handler_disabler_state old;
4124 rb_thread_acquire_fork_lock();
4125 disable_child_handler_before_fork(&old);
4128 child.pid = pid = rb_fork();
4129 child.error = err =
errno;
4132 disable_child_handler_fork_parent(&old);
4134#
if defined(__FreeBSD__)
4138 rb_thread_release_fork_lock();
4141 rb_thread_reset_fork_lock();
4143 after_fork_ruby(pid);
4146 }
while (pid < 0 && handle_fork_error(err, &child, NULL, &try_gc) == 0);
4148 if (status) *status = child.status;
4156 rb_pid_t pid = rb_fork_ruby(NULL);
4159 rb_sys_fail(
"fork(2)");
4166call_proc__fork_protected(
VALUE arg)
4175rb_call_proc__fork(
void)
4178 return proc_fork_pid();
4181 rb_pid_t parent = getpid(), pid;
4184 if (
NIL_P(rb_protect(call_proc__fork_protected, (
VALUE)&pid, &state))) {
4185 if (getpid() != parent) {
4195#if defined(HAVE_WORKING_FORK) && !defined(CANNOT_FORK_WITH_PTHREAD)
4216rb_proc__fork(
VALUE _obj)
4218 rb_pid_t pid = proc_fork_pid();
4287 pid = rb_call_proc__fork();
4301#define rb_proc__fork rb_f_notimplement
4302#define rb_f_fork rb_f_notimplement
4306exit_status_code(
VALUE status)
4312 istatus = EXIT_SUCCESS;
4315 istatus = EXIT_FAILURE;
4319#if EXIT_SUCCESS != 0
4321 istatus = EXIT_SUCCESS;
4328NORETURN(
static VALUE rb_f_exit_bang(
int argc,
VALUE *argv,
VALUE obj));
4346rb_f_exit_bang(
int argc,
VALUE *argv,
VALUE obj)
4351 istatus = exit_status_code(argv[0]);
4354 istatus = EXIT_FAILURE;
4364 if (GET_EC()->tag) {
4380 istatus = exit_status_code(argv[0]);
4383 istatus = EXIT_SUCCESS;
4449 VALUE errinfo = rb_ec_get_errinfo(ec);
4450 if (!
NIL_P(errinfo)) {
4451 rb_ec_error_print(ec, errinfo);
4458 args[1] = args[0] = argv[0];
4460 rb_io_puts(1, args, rb_ractor_stderr());
4461 args[0] =
INT2NUM(EXIT_FAILURE);
4499#if !defined HAVE_WORKING_FORK && !defined HAVE_SPAWNV && !defined __EMSCRIPTEN__
4504 if (eargp && !eargp->use_shell) {
4505 VALUE str = eargp->invoke.cmd.argv_str;
4506 VALUE buf = eargp->invoke.cmd.argv_buf;
4507 char *p, **argv = ARGVSTR2ARGV(str);
4508 long i, argc = ARGVSTR2ARGC(str);
4509 const char *start = RSTRING_PTR(buf);
4511 p = RSTRING_PTR(cmd);
4512 for (i = 1; i < argc; ++i) {
4513 p[argv[i] - start - 1] =
' ';
4523rb_spawn_process(
struct rb_execarg *eargp,
char *errmsg,
size_t errmsg_buflen)
4526#if !defined HAVE_WORKING_FORK || USE_SPAWNV
4529# if !defined HAVE_SPAWNV
4534#if defined HAVE_WORKING_FORK && !USE_SPAWNV
4535 pid = fork_check_err(eargp->status, rb_exec_atfork, eargp, eargp->redirect_fds, errmsg, errmsg_buflen, eargp);
4537 prog = eargp->use_shell ? eargp->invoke.sh.shell_script : eargp->invoke.cmd.command_name;
4539 if (rb_execarg_run_options(eargp, &sarg, errmsg, errmsg_buflen) < 0) {
4543 if (prog && !eargp->use_shell) {
4544 char **argv = ARGVSTR2ARGV(eargp->invoke.cmd.argv_str);
4545 argv[0] = RSTRING_PTR(prog);
4547# if defined HAVE_SPAWNV
4548 if (eargp->use_shell) {
4549 pid = proc_spawn_sh(RSTRING_PTR(prog));
4552 char **argv = ARGVSTR2ARGV(eargp->invoke.cmd.argv_str);
4553 pid = proc_spawn_cmd(argv, prog, eargp);
4560 status = system(rb_execarg_commandline(eargp, &prog));
4565 if (eargp->waitpid_state) {
4566 eargp->waitpid_state->pid = pid;
4569 rb_execarg_run_options(&sarg, NULL, errmsg, errmsg_buflen);
4584do_spawn_process(
VALUE arg)
4588 rb_execarg_parent_start1(argp->execarg);
4590 return (
VALUE)rb_spawn_process(rb_execarg_get(argp->execarg),
4591 argp->errmsg.ptr, argp->errmsg.buflen);
4594NOINLINE(
static rb_pid_t
4595 rb_execarg_spawn(
VALUE execarg_obj,
char *errmsg,
size_t errmsg_buflen));
4598rb_execarg_spawn(
VALUE execarg_obj,
char *errmsg,
size_t errmsg_buflen)
4602 args.execarg = execarg_obj;
4603 args.errmsg.ptr = errmsg;
4604 args.errmsg.buflen = errmsg_buflen;
4607 execarg_parent_end, execarg_obj);
4612rb_spawn_internal(
int argc,
const VALUE *argv,
char *errmsg,
size_t errmsg_buflen)
4616 execarg_obj = rb_execarg_new(argc, argv, TRUE, FALSE);
4617 return rb_execarg_spawn(execarg_obj, errmsg, errmsg_buflen);
4623 return rb_spawn_internal(argc, argv, errmsg, errmsg_buflen);
4629 return rb_spawn_internal(argc, argv, NULL, 0);
4751 VALUE execarg_obj = rb_execarg_new(argc, argv, TRUE, TRUE);
4752 struct rb_execarg *eargp = rb_execarg_get(execarg_obj);
4755 eargp->status = &status;
4757 last_status_clear(th);
4761 rb_pid_t pid = rb_execarg_spawn(execarg_obj, 0, 0);
4768 th->last_status = status;
4770 if (data->status == EXIT_SUCCESS) {
4774 if (data->error != 0) {
4775 if (eargp->exception) {
4776 VALUE command = eargp->invoke.sh.shell_script;
4784 else if (eargp->exception) {
4785 VALUE command = eargp->invoke.sh.shell_script;
4799 if (eargp->exception) {
4800 VALUE command = eargp->invoke.sh.shell_script;
4916 char errmsg[CHILD_ERRMSG_BUFLEN] = {
'\0' };
4917 VALUE execarg_obj, fail_str;
4920 execarg_obj = rb_execarg_new(argc, argv, TRUE, FALSE);
4921 eargp = rb_execarg_get(execarg_obj);
4922 fail_str = eargp->use_shell ? eargp->invoke.sh.shell_script : eargp->invoke.cmd.command_name;
4924 pid = rb_execarg_spawn(execarg_obj, errmsg,
sizeof(errmsg));
4928 rb_exec_fail(eargp, err, errmsg);
4932#if defined(HAVE_WORKING_FORK) || defined(HAVE_SPAWNV)
4958 time_t beg = time(0);
4961 if (scheduler !=
Qnil) {
4965 if (argc == 0 || (argc == 1 &&
NIL_P(argv[0]))) {
4974 time_t end = time(0) - beg;
4976 return TIMET2NUM(end);
4980#if (defined(HAVE_GETPGRP) && defined(GETPGRP_VOID)) || defined(HAVE_GETPGID)
4997#if defined(HAVE_GETPGRP) && defined(GETPGRP_VOID)
4999 if (pgrp < 0) rb_sys_fail(0);
5003 if (pgrp < 0) rb_sys_fail(0);
5008#define proc_getpgrp rb_f_notimplement
5012#if defined(HAVE_SETPGID) || (defined(HAVE_SETPGRP) && defined(SETPGRP_VOID))
5030 if (setpgid(0,0) < 0) rb_sys_fail(0);
5031#elif defined(HAVE_SETPGRP) && defined(SETPGRP_VOID)
5032 if (setpgrp() < 0) rb_sys_fail(0);
5037#define proc_setpgrp rb_f_notimplement
5041#if defined(HAVE_GETPGID)
5059 if (i < 0) rb_sys_fail(0);
5063#define proc_getpgid rb_f_notimplement
5081 rb_pid_t ipid, ipgrp;
5086 if (setpgid(ipid, ipgrp) < 0) rb_sys_fail(0);
5090#define proc_setpgid rb_f_notimplement
5118 if (sid < 0) rb_sys_fail(0);
5122#define proc_getsid rb_f_notimplement
5126#if defined(HAVE_SETSID) || (defined(HAVE_SETPGRP) && defined(TIOCNOTTY))
5127#if !defined(HAVE_SETSID)
5128static rb_pid_t ruby_setsid(
void);
5129#define setsid() ruby_setsid()
5150 if (pid < 0) rb_sys_fail(0);
5154#if !defined(HAVE_SETSID)
5155#define HAVE_SETSID 1
5163#if defined(SETPGRP_VOID)
5169 ret = setpgrp(0, pid);
5171 if (ret == -1)
return -1;
5175 ioctl(fd, TIOCNOTTY, NULL);
5182#define proc_setsid rb_f_notimplement
5186#ifdef HAVE_GETPRIORITY
5214 int prio, iwhich, iwho;
5220 prio = getpriority(iwhich, iwho);
5221 if (
errno) rb_sys_fail(0);
5225#define proc_getpriority rb_f_notimplement
5229#ifdef HAVE_GETPRIORITY
5249 int iwhich, iwho, iprio;
5255 if (setpriority(iwhich, iwho, iprio) < 0)
5260#define proc_setpriority rb_f_notimplement
5263#if defined(HAVE_SETRLIMIT) && defined(NUM2RLIM)
5265rlimit_resource_name2int(
const char *name,
long len,
int casetype)
5269#define RESCHECK(r) \
5271 if (len == rb_strlen_lit(#r) && STRCASECMP(name, #r) == 0) { \
5272 resource = RLIMIT_##r; \
5306#ifdef RLIMIT_MEMLOCK
5309#ifdef RLIMIT_MSGQUEUE
5348#ifdef RLIMIT_SIGPENDING
5349 RESCHECK(SIGPENDING);
5358 for (p = name; *p; p++)
5364 for (p = name; *p; p++)
5370 rb_bug(
"unexpected casetype");
5377rlimit_type_by_hname(
const char *name,
long len)
5379 return rlimit_resource_name2int(name,
len, 0);
5383rlimit_type_by_lname(
const char *name,
long len)
5385 return rlimit_resource_name2int(name,
len, 1);
5389rlimit_type_by_sym(
VALUE key)
5392 const char *rname = RSTRING_PTR(name);
5393 long len = RSTRING_LEN(name);
5395 static const char prefix[] =
"rlimit_";
5396 enum {prefix_len =
sizeof(prefix)-1};
5398 if (
len > prefix_len && strncmp(prefix, rname, prefix_len) == 0) {
5399 rtype = rlimit_type_by_lname(rname + prefix_len,
len - prefix_len);
5407rlimit_resource_type(
VALUE rtype)
5414 switch (
TYPE(rtype)) {
5417 name = RSTRING_PTR(v);
5418 len = RSTRING_LEN(v);
5427 len = RSTRING_LEN(rtype);
5437 r = rlimit_type_by_hname(name,
len);
5441 rb_raise(rb_eArgError,
"invalid resource name: % "PRIsVALUE, rtype);
5447rlimit_resource_value(
VALUE rval)
5452 switch (
TYPE(rval)) {
5455 name = RSTRING_PTR(v);
5470 return NUM2RLIM(rval);
5474 if (strcmp(name,
"INFINITY") == 0)
return RLIM_INFINITY;
5476#ifdef RLIM_SAVED_MAX
5477 if (strcmp(name,
"SAVED_MAX") == 0)
return RLIM_SAVED_MAX;
5479#ifdef RLIM_SAVED_CUR
5480 if (strcmp(name,
"SAVED_CUR") == 0)
return RLIM_SAVED_CUR;
5482 rb_raise(rb_eArgError,
"invalid resource value: %"PRIsVALUE, rval);
5488#if defined(HAVE_GETRLIMIT) && defined(RLIM2NUM)
5516 if (getrlimit(rlimit_resource_type(resource), &rlim) < 0) {
5517 rb_sys_fail(
"getrlimit");
5519 return rb_assoc_new(RLIM2NUM(rlim.rlim_cur), RLIM2NUM(rlim.rlim_max));
5522#define proc_getrlimit rb_f_notimplement
5525#if defined(HAVE_SETRLIMIT) && defined(NUM2RLIM)
5579proc_setrlimit(
int argc,
VALUE *argv,
VALUE obj)
5581 VALUE resource, rlim_cur, rlim_max;
5587 if (argc < 3 ||
NIL_P(rlim_max = argv[2]))
5588 rlim_max = rlim_cur;
5590 rlim.rlim_cur = rlimit_resource_value(rlim_cur);
5591 rlim.rlim_max = rlimit_resource_value(rlim_max);
5593 if (setrlimit(rlimit_resource_type(resource), &rlim) < 0) {
5594 rb_sys_fail(
"setrlimit");
5599#define proc_setrlimit rb_f_notimplement
5602static int under_uid_switch = 0;
5604check_uid_switch(
void)
5606 if (under_uid_switch) {
5607 rb_raise(
rb_eRuntimeError,
"can't handle UID while evaluating block given to Process::UID.switch method");
5611static int under_gid_switch = 0;
5613check_gid_switch(
void)
5615 if (under_gid_switch) {
5616 rb_raise(
rb_eRuntimeError,
"can't handle GID while evaluating block given to Process::UID.switch method");
5621#if defined(HAVE_PWD_H)
5623login_not_found(
int err)
5625 return (err == ENOTTY || err == ENXIO || err == ENOENT);
5636# if !defined(USE_GETLOGIN_R) && !defined(USE_GETLOGIN)
5639 char MAYBE_UNUSED(*login) = NULL;
5641# ifdef USE_GETLOGIN_R
5643# if defined(__FreeBSD__)
5644 typedef int getlogin_r_size_t;
5646 typedef size_t getlogin_r_size_t;
5649 long loginsize = GETLOGIN_R_SIZE_INIT;
5652 loginsize = GETLOGIN_R_SIZE_DEFAULT;
5656 login = RSTRING_PTR(maybe_result);
5661 while ((gle = getlogin_r(login, (getlogin_r_size_t)loginsize)) != 0) {
5662 if (login_not_found(gle)) {
5663 rb_str_resize(maybe_result, 0);
5667 if (gle != ERANGE || loginsize >= GETLOGIN_R_SIZE_LIMIT) {
5668 rb_str_resize(maybe_result, 0);
5673 login = RSTRING_PTR(maybe_result);
5677 if (login == NULL) {
5678 rb_str_resize(maybe_result, 0);
5683 return maybe_result;
5685# elif defined(USE_GETLOGIN)
5691 if (login_not_found(err)) {
5705pwd_not_found(
int err)
5719# if defined(USE_GETPWNAM_R)
5720struct getpwnam_r_args {
5724 struct passwd *result;
5725 struct passwd pwstore;
5728# define GETPWNAM_R_ARGS(login_, buf_, bufsize_) (struct getpwnam_r_args) \
5729 {.login = login_, .buf = buf_, .bufsize = bufsize_, .result = NULL}
5732nogvl_getpwnam_r(
void *args)
5734 struct getpwnam_r_args *arg = args;
5735 return (
void *)(
VALUE)getpwnam_r(arg->login, &arg->pwstore, arg->buf, arg->bufsize, &arg->result);
5740rb_getpwdirnam_for_login(
VALUE login_name)
5742#if !defined(USE_GETPWNAM_R) && !defined(USE_GETPWNAM)
5746 if (
NIL_P(login_name)) {
5751 const char *login = RSTRING_PTR(login_name);
5754# ifdef USE_GETPWNAM_R
5757 long bufsizenm = GETPW_R_SIZE_INIT;
5760 bufsizenm = GETPW_R_SIZE_DEFAULT;
5764 bufnm = RSTRING_PTR(getpwnm_tmp);
5767 struct getpwnam_r_args args = GETPWNAM_R_ARGS(login, bufnm, (
size_t)bufsizenm);
5770 while ((enm = IO_WITHOUT_GVL_INT(nogvl_getpwnam_r, &args)) != 0) {
5771 if (pwd_not_found(enm)) {
5772 rb_str_resize(getpwnm_tmp, 0);
5776 if (enm != ERANGE || args.bufsize >= GETPW_R_SIZE_LIMIT) {
5777 rb_str_resize(getpwnm_tmp, 0);
5782 args.buf = RSTRING_PTR(getpwnm_tmp);
5786 if (args.result == NULL) {
5788 rb_str_resize(getpwnm_tmp, 0);
5794 rb_str_resize(getpwnm_tmp, 0);
5797# elif defined(USE_GETPWNAM)
5799 struct passwd *pwptr;
5801 if (!(pwptr = getpwnam(login))) {
5804 if (pwd_not_found(err)) {
5818# if defined(USE_GETPWUID_R)
5819struct getpwuid_r_args {
5823 struct passwd *result;
5824 struct passwd pwstore;
5827# define GETPWUID_R_ARGS(uid_, buf_, bufsize_) (struct getpwuid_r_args) \
5828 {.uid = uid_, .buf = buf_, .bufsize = bufsize_, .result = NULL}
5831nogvl_getpwuid_r(
void *args)
5833 struct getpwuid_r_args *arg = args;
5834 return (
void *)(
VALUE)getpwuid_r(arg->uid, &arg->pwstore, arg->buf, arg->bufsize, &arg->result);
5844# if !defined(USE_GETPWUID_R) && !defined(USE_GETPWUID)
5848 uid_t ruid = getuid();
5850# ifdef USE_GETPWUID_R
5853 long bufsizeid = GETPW_R_SIZE_INIT;
5856 bufsizeid = GETPW_R_SIZE_DEFAULT;
5860 bufid = RSTRING_PTR(getpwid_tmp);
5863 struct getpwuid_r_args args = GETPWUID_R_ARGS(ruid, bufid, (
size_t)bufsizeid);
5866 while ((eid = IO_WITHOUT_GVL_INT(nogvl_getpwuid_r, &args)) != 0) {
5867 if (pwd_not_found(eid)) {
5868 rb_str_resize(getpwid_tmp, 0);
5872 if (eid != ERANGE || args.bufsize >= GETPW_R_SIZE_LIMIT) {
5873 rb_str_resize(getpwid_tmp, 0);
5878 args.buf = RSTRING_PTR(getpwid_tmp);
5882 if (args.result == NULL) {
5884 rb_str_resize(getpwid_tmp, 0);
5890 rb_str_resize(getpwid_tmp, 0);
5893# elif defined(USE_GETPWUID)
5895 struct passwd *pwptr;
5897 if (!(pwptr = getpwuid(ruid))) {
5900 if (pwd_not_found(err)) {
5926#if defined(HAVE_PWD_H)
5929# ifdef USE_GETPWNAM_R
5942 struct passwd *pwptr;
5943#ifdef USE_GETPWNAM_R
5948 getpw_buf_len = GETPW_R_SIZE_INIT;
5949 if (getpw_buf_len < 0) getpw_buf_len = GETPW_R_SIZE_DEFAULT;
5952 getpw_buf = RSTRING_PTR(*getpw_tmp);
5956 struct getpwnam_r_args args = GETPWNAM_R_ARGS((
char *)usrname, getpw_buf, (
size_t)getpw_buf_len);
5958 while ((e = IO_WITHOUT_GVL_INT(nogvl_getpwnam_r, &args)) != 0) {
5959 if (e != ERANGE || args.bufsize >= GETPW_R_SIZE_LIMIT) {
5960 rb_str_resize(*getpw_tmp, 0);
5964 args.buf = RSTRING_PTR(*getpw_tmp);
5967 pwptr = args.result;
5969 pwptr = getpwnam(usrname);
5972#ifndef USE_GETPWNAM_R
5975 rb_raise(rb_eArgError,
"can't find user for %"PRIsVALUE,
id);
5977 uid = pwptr->pw_uid;
5978#ifndef USE_GETPWNAM_R
5985# ifdef p_uid_from_name
6005#if defined(HAVE_GRP_H)
6006# if defined(USE_GETGRNAM_R)
6007struct getgrnam_r_args {
6011 struct group *result;
6015# define GETGRNAM_R_ARGS(name_, buf_, bufsize_) (struct getgrnam_r_args) \
6016 {.name = name_, .buf = buf_, .bufsize = bufsize_, .result = NULL}
6019nogvl_getgrnam_r(
void *args)
6021 struct getgrnam_r_args *arg = args;
6022 return (
void *)(
VALUE)getgrnam_r(arg->name, &arg->grp, arg->buf, arg->bufsize, &arg->result);
6028# ifdef USE_GETGRNAM_R
6041 struct group *grptr;
6042#ifdef USE_GETGRNAM_R
6047 getgr_buf_len = GETGR_R_SIZE_INIT;
6048 if (getgr_buf_len < 0) getgr_buf_len = GETGR_R_SIZE_DEFAULT;
6051 getgr_buf = RSTRING_PTR(*getgr_tmp);
6055 struct getgrnam_r_args args = GETGRNAM_R_ARGS(grpname, getgr_buf, (
size_t)getgr_buf_len);
6057 while ((e = IO_WITHOUT_GVL_INT(nogvl_getgrnam_r, &args)) != 0) {
6058 if (e != ERANGE || args.bufsize >= GETGR_R_SIZE_LIMIT) {
6059 rb_str_resize(*getgr_tmp, 0);
6063 args.buf = RSTRING_PTR(*getgr_tmp);
6066 grptr = args.result;
6067#elif defined(HAVE_GETGRNAM)
6068 grptr = getgrnam(grpname);
6073#if !defined(USE_GETGRNAM_R) && defined(HAVE_ENDGRENT)
6076 rb_raise(rb_eArgError,
"can't find group for %"PRIsVALUE,
id);
6078 gid = grptr->gr_gid;
6079#if !defined(USE_GETGRNAM_R) && defined(HAVE_ENDGRENT)
6086# ifdef p_gid_from_name
6106#if defined HAVE_SETUID
6120 if (setuid(OBJ2UID(
id)) != 0) rb_sys_fail(0);
6124#define p_sys_setuid rb_f_notimplement
6128#if defined HAVE_SETRUID
6142 if (setruid(OBJ2UID(
id)) != 0) rb_sys_fail(0);
6146#define p_sys_setruid rb_f_notimplement
6150#if defined HAVE_SETEUID
6164 if (seteuid(OBJ2UID(
id)) != 0) rb_sys_fail(0);
6168#define p_sys_seteuid rb_f_notimplement
6172#if defined HAVE_SETREUID
6187 rb_uid_t ruid, euid;
6190 ruid = OBJ2UID1(rid);
6191 euid = OBJ2UID1(eid);
6193 if (setreuid(ruid, euid) != 0) rb_sys_fail(0);
6197#define p_sys_setreuid rb_f_notimplement
6201#if defined HAVE_SETRESUID
6216 rb_uid_t ruid, euid, suid;
6219 ruid = OBJ2UID1(rid);
6220 euid = OBJ2UID1(eid);
6221 suid = OBJ2UID1(sid);
6223 if (setresuid(ruid, euid, suid) != 0) rb_sys_fail(0);
6227#define p_sys_setresuid rb_f_notimplement
6244proc_getuid(
VALUE obj)
6246 rb_uid_t uid = getuid();
6251#if defined(HAVE_SETRESUID) || defined(HAVE_SETREUID) || defined(HAVE_SETRUID) || defined(HAVE_SETUID)
6271#if defined(HAVE_SETRESUID)
6272 if (setresuid(uid, -1, -1) < 0) rb_sys_fail(0);
6273#elif defined HAVE_SETREUID
6274 if (setreuid(uid, -1) < 0) rb_sys_fail(0);
6275#elif defined HAVE_SETRUID
6276 if (setruid(uid) < 0) rb_sys_fail(0);
6277#elif defined HAVE_SETUID
6279 if (geteuid() == uid) {
6280 if (setuid(uid) < 0) rb_sys_fail(0);
6290#define proc_setuid rb_f_notimplement
6304static rb_uid_t SAVED_USER_ID = -1;
6328 if (geteuid() == 0) {
6329#if defined(HAVE_SETRESUID)
6330 if (setresuid(uid, uid, uid) < 0) rb_sys_fail(0);
6331 SAVED_USER_ID = uid;
6332#elif defined(HAVE_SETUID)
6333 if (setuid(uid) < 0) rb_sys_fail(0);
6334 SAVED_USER_ID = uid;
6335#elif defined(HAVE_SETREUID) && !defined(OBSOLETE_SETREUID)
6336 if (getuid() == uid) {
6337 if (SAVED_USER_ID == uid) {
6338 if (setreuid(-1, uid) < 0) rb_sys_fail(0);
6342 if (setreuid(-1, SAVED_USER_ID) < 0) rb_sys_fail(0);
6343 if (setreuid(SAVED_USER_ID, 0) < 0) rb_sys_fail(0);
6345 if (setreuid(uid, uid) < 0) rb_sys_fail(0);
6346 SAVED_USER_ID = uid;
6349 if (setreuid(0, -1) < 0) rb_sys_fail(0);
6351 if (setreuid(uid, uid) < 0) rb_sys_fail(0);
6352 SAVED_USER_ID = uid;
6357 if (setreuid(uid, uid) < 0) rb_sys_fail(0);
6358 SAVED_USER_ID = uid;
6360#elif defined(HAVE_SETRUID) && defined(HAVE_SETEUID)
6361 if (getuid() == uid) {
6362 if (SAVED_USER_ID == uid) {
6363 if (seteuid(uid) < 0) rb_sys_fail(0);
6367 if (setruid(SAVED_USER_ID) < 0) rb_sys_fail(0);
6369 if (setruid(0) < 0) rb_sys_fail(0);
6372 if (setruid(0) < 0) rb_sys_fail(0);
6374 if (seteuid(uid) < 0) rb_sys_fail(0);
6375 if (setruid(uid) < 0) rb_sys_fail(0);
6376 SAVED_USER_ID = uid;
6381 if (seteuid(uid) < 0) rb_sys_fail(0);
6382 if (setruid(uid) < 0) rb_sys_fail(0);
6383 SAVED_USER_ID = uid;
6391#if defined(HAVE_SETRESUID)
6392 if (setresuid((getuid() == uid)? (rb_uid_t)-1: uid,
6393 (geteuid() == uid)? (rb_uid_t)-1: uid,
6394 (SAVED_USER_ID == uid)? (rb_uid_t)-1: uid) < 0) rb_sys_fail(0);
6395 SAVED_USER_ID = uid;
6396#elif defined(HAVE_SETREUID) && !defined(OBSOLETE_SETREUID)
6397 if (SAVED_USER_ID == uid) {
6398 if (setreuid((getuid() == uid)? (rb_uid_t)-1: uid,
6399 (geteuid() == uid)? (rb_uid_t)-1: uid) < 0)
6402 else if (getuid() != uid) {
6403 if (setreuid(uid, (geteuid() == uid)? (rb_uid_t)-1: uid) < 0)
6405 SAVED_USER_ID = uid;
6407 else if ( geteuid() != uid) {
6408 if (setreuid(geteuid(), uid) < 0) rb_sys_fail(0);
6409 SAVED_USER_ID = uid;
6410 if (setreuid(uid, -1) < 0) rb_sys_fail(0);
6413 if (setreuid(-1, SAVED_USER_ID) < 0) rb_sys_fail(0);
6414 if (setreuid(SAVED_USER_ID, uid) < 0) rb_sys_fail(0);
6415 SAVED_USER_ID = uid;
6416 if (setreuid(uid, -1) < 0) rb_sys_fail(0);
6418#elif defined(HAVE_SETRUID) && defined(HAVE_SETEUID)
6419 if (SAVED_USER_ID == uid) {
6420 if (geteuid() != uid && seteuid(uid) < 0) rb_sys_fail(0);
6421 if (getuid() != uid && setruid(uid) < 0) rb_sys_fail(0);
6423 else if ( geteuid() == uid) {
6424 if (getuid() != uid) {
6425 if (setruid(uid) < 0) rb_sys_fail(0);
6426 SAVED_USER_ID = uid;
6429 if (setruid(SAVED_USER_ID) < 0) rb_sys_fail(0);
6430 SAVED_USER_ID = uid;
6431 if (setruid(uid) < 0) rb_sys_fail(0);
6434 else if ( getuid() == uid) {
6435 if (seteuid(uid) < 0) rb_sys_fail(0);
6436 if (setruid(SAVED_USER_ID) < 0) rb_sys_fail(0);
6437 SAVED_USER_ID = uid;
6438 if (setruid(uid) < 0) rb_sys_fail(0);
6443#elif defined HAVE_44BSD_SETUID
6444 if (getuid() == uid) {
6446 if (setuid(uid) < 0) rb_sys_fail(0);
6447 SAVED_USER_ID = uid;
6452#elif defined HAVE_SETEUID
6453 if (getuid() == uid && SAVED_USER_ID == uid) {
6454 if (seteuid(uid) < 0) rb_sys_fail(0);
6459#elif defined HAVE_SETUID
6460 if (getuid() == uid && SAVED_USER_ID == uid) {
6461 if (setuid(uid) < 0) rb_sys_fail(0);
6475#if defined HAVE_SETGID
6489 if (setgid(OBJ2GID(
id)) != 0) rb_sys_fail(0);
6493#define p_sys_setgid rb_f_notimplement
6497#if defined HAVE_SETRGID
6511 if (setrgid(OBJ2GID(
id)) != 0) rb_sys_fail(0);
6515#define p_sys_setrgid rb_f_notimplement
6519#if defined HAVE_SETEGID
6533 if (setegid(OBJ2GID(
id)) != 0) rb_sys_fail(0);
6537#define p_sys_setegid rb_f_notimplement
6541#if defined HAVE_SETREGID
6556 rb_gid_t rgid, egid;
6558 rgid = OBJ2GID(rid);
6559 egid = OBJ2GID(eid);
6560 if (setregid(rgid, egid) != 0) rb_sys_fail(0);
6564#define p_sys_setregid rb_f_notimplement
6567#if defined HAVE_SETRESGID
6582 rb_gid_t rgid, egid, sgid;
6584 rgid = OBJ2GID(rid);
6585 egid = OBJ2GID(eid);
6586 sgid = OBJ2GID(sid);
6587 if (setresgid(rgid, egid, sgid) != 0) rb_sys_fail(0);
6591#define p_sys_setresgid rb_f_notimplement
6595#if defined HAVE_ISSETUGID
6609p_sys_issetugid(
VALUE obj)
6611 return RBOOL(issetugid());
6614#define p_sys_issetugid rb_f_notimplement
6631proc_getgid(
VALUE obj)
6633 rb_gid_t gid = getgid();
6638#if defined(HAVE_SETRESGID) || defined(HAVE_SETREGID) || defined(HAVE_SETRGID) || defined(HAVE_SETGID)
6657#if defined(HAVE_SETRESGID)
6658 if (setresgid(gid, -1, -1) < 0) rb_sys_fail(0);
6659#elif defined HAVE_SETREGID
6660 if (setregid(gid, -1) < 0) rb_sys_fail(0);
6661#elif defined HAVE_SETRGID
6662 if (setrgid(gid) < 0) rb_sys_fail(0);
6663#elif defined HAVE_SETGID
6665 if (getegid() == gid) {
6666 if (setgid(gid) < 0) rb_sys_fail(0);
6676#define proc_setgid rb_f_notimplement
6680#if defined(_SC_NGROUPS_MAX) || defined(NGROUPS_MAX)
6700static int _maxgroups = -1;
6702get_sc_ngroups_max(
void)
6704#ifdef _SC_NGROUPS_MAX
6705 return (
int)sysconf(_SC_NGROUPS_MAX);
6706#elif defined(NGROUPS_MAX)
6707 return (
int)NGROUPS_MAX;
6715 if (_maxgroups < 0) {
6716 _maxgroups = get_sc_ngroups_max();
6718 _maxgroups = RB_MAX_GROUPS;
6727#ifdef HAVE_GETGROUPS
6751proc_getgroups(
VALUE obj)
6757 ngroups = getgroups(0, NULL);
6761 groups =
ALLOCV_N(rb_gid_t, tmp, ngroups);
6763 ngroups = getgroups(ngroups, groups);
6768 for (i = 0; i < ngroups; i++)
6776#define proc_getgroups rb_f_notimplement
6780#ifdef HAVE_SETGROUPS
6805 if (ngroups > maxgroups())
6806 rb_raise(rb_eArgError,
"too many groups, %d max", maxgroups());
6808 groups =
ALLOCV_N(rb_gid_t, tmp, ngroups);
6810 for (i = 0; i < ngroups; i++) {
6813 groups[i] = OBJ2GID1(g);
6817 if (setgroups(ngroups, groups) == -1)
6822 return proc_getgroups(obj);
6825#define proc_setgroups rb_f_notimplement
6829#ifdef HAVE_INITGROUPS
6855 return proc_getgroups(obj);
6858#define proc_initgroups rb_f_notimplement
6861#if defined(_SC_NGROUPS_MAX) || defined(NGROUPS_MAX)
6874proc_getmaxgroups(
VALUE obj)
6879#define proc_getmaxgroups rb_f_notimplement
6882#ifdef HAVE_SETGROUPS
6895 int ngroups_max = get_sc_ngroups_max();
6898 rb_raise(rb_eArgError,
"maxgroups %d should be positive", ngroups);
6900 if (ngroups > RB_MAX_GROUPS)
6901 ngroups = RB_MAX_GROUPS;
6903 if (ngroups_max > 0 && ngroups > ngroups_max)
6904 ngroups = ngroups_max;
6906 _maxgroups = ngroups;
6911#define proc_setmaxgroups rb_f_notimplement
6914#if defined(HAVE_DAEMON) || (defined(HAVE_WORKING_FORK) && defined(HAVE_SETSID))
6915static int rb_daemon(
int nochdir,
int noclose);
6940 int n, nochdir = FALSE, noclose = FALSE;
6943 case 2: noclose = TO_BOOL(argv[1],
"noclose");
6944 case 1: nochdir = TO_BOOL(argv[0],
"nochdir");
6948 n = rb_daemon(nochdir, noclose);
6949 if (n < 0) rb_sys_fail(
"daemon");
6953extern const char ruby_null_device[];
6956rb_daemon(
int nochdir,
int noclose)
6961 err = daemon(nochdir, noclose);
6966 switch (rb_fork_ruby(NULL)) {
6969 default: _exit(EXIT_SUCCESS);
6973 if (setsid() < 0) (void)0;
6978 if (!noclose && (n =
rb_cloexec_open(ruby_null_device, O_RDWR, 0)) != -1) {
6990#define proc_daemon rb_f_notimplement
7003static rb_gid_t SAVED_GROUP_ID = -1;
7027 if (geteuid() == 0) {
7028#if defined(HAVE_SETRESGID)
7029 if (setresgid(gid, gid, gid) < 0) rb_sys_fail(0);
7030 SAVED_GROUP_ID = gid;
7031#elif defined HAVE_SETGID
7032 if (setgid(gid) < 0) rb_sys_fail(0);
7033 SAVED_GROUP_ID = gid;
7034#elif defined(HAVE_SETREGID) && !defined(OBSOLETE_SETREGID)
7035 if (getgid() == gid) {
7036 if (SAVED_GROUP_ID == gid) {
7037 if (setregid(-1, gid) < 0) rb_sys_fail(0);
7041 if (setregid(-1, SAVED_GROUP_ID) < 0) rb_sys_fail(0);
7042 if (setregid(SAVED_GROUP_ID, 0) < 0) rb_sys_fail(0);
7044 if (setregid(gid, gid) < 0) rb_sys_fail(0);
7045 SAVED_GROUP_ID = gid;
7048 if (setregid(0, 0) < 0) rb_sys_fail(0);
7050 if (setregid(gid, gid) < 0) rb_sys_fail(0);
7051 SAVED_GROUP_ID = gid;
7056 if (setregid(gid, gid) < 0) rb_sys_fail(0);
7057 SAVED_GROUP_ID = gid;
7059#elif defined(HAVE_SETRGID) && defined (HAVE_SETEGID)
7060 if (getgid() == gid) {
7061 if (SAVED_GROUP_ID == gid) {
7062 if (setegid(gid) < 0) rb_sys_fail(0);
7066 if (setegid(gid) < 0) rb_sys_fail(0);
7067 if (setrgid(SAVED_GROUP_ID) < 0) rb_sys_fail(0);
7069 if (setrgid(0) < 0) rb_sys_fail(0);
7072 if (setrgid(0) < 0) rb_sys_fail(0);
7074 if (setegid(gid) < 0) rb_sys_fail(0);
7075 if (setrgid(gid) < 0) rb_sys_fail(0);
7076 SAVED_GROUP_ID = gid;
7081 if (setegid(gid) < 0) rb_sys_fail(0);
7082 if (setrgid(gid) < 0) rb_sys_fail(0);
7083 SAVED_GROUP_ID = gid;
7090#if defined(HAVE_SETRESGID)
7091 if (setresgid((getgid() == gid)? (rb_gid_t)-1: gid,
7092 (getegid() == gid)? (rb_gid_t)-1: gid,
7093 (SAVED_GROUP_ID == gid)? (rb_gid_t)-1: gid) < 0) rb_sys_fail(0);
7094 SAVED_GROUP_ID = gid;
7095#elif defined(HAVE_SETREGID) && !defined(OBSOLETE_SETREGID)
7096 if (SAVED_GROUP_ID == gid) {
7097 if (setregid((getgid() == gid)? (rb_uid_t)-1: gid,
7098 (getegid() == gid)? (rb_uid_t)-1: gid) < 0)
7101 else if (getgid() != gid) {
7102 if (setregid(gid, (getegid() == gid)? (rb_uid_t)-1: gid) < 0)
7104 SAVED_GROUP_ID = gid;
7106 else if ( getegid() != gid) {
7107 if (setregid(getegid(), gid) < 0) rb_sys_fail(0);
7108 SAVED_GROUP_ID = gid;
7109 if (setregid(gid, -1) < 0) rb_sys_fail(0);
7112 if (setregid(-1, SAVED_GROUP_ID) < 0) rb_sys_fail(0);
7113 if (setregid(SAVED_GROUP_ID, gid) < 0) rb_sys_fail(0);
7114 SAVED_GROUP_ID = gid;
7115 if (setregid(gid, -1) < 0) rb_sys_fail(0);
7117#elif defined(HAVE_SETRGID) && defined(HAVE_SETEGID)
7118 if (SAVED_GROUP_ID == gid) {
7119 if (getegid() != gid && setegid(gid) < 0) rb_sys_fail(0);
7120 if (getgid() != gid && setrgid(gid) < 0) rb_sys_fail(0);
7122 else if ( getegid() == gid) {
7123 if (getgid() != gid) {
7124 if (setrgid(gid) < 0) rb_sys_fail(0);
7125 SAVED_GROUP_ID = gid;
7128 if (setrgid(SAVED_GROUP_ID) < 0) rb_sys_fail(0);
7129 SAVED_GROUP_ID = gid;
7130 if (setrgid(gid) < 0) rb_sys_fail(0);
7133 else if ( getgid() == gid) {
7134 if (setegid(gid) < 0) rb_sys_fail(0);
7135 if (setrgid(SAVED_GROUP_ID) < 0) rb_sys_fail(0);
7136 SAVED_GROUP_ID = gid;
7137 if (setrgid(gid) < 0) rb_sys_fail(0);
7142#elif defined HAVE_44BSD_SETGID
7143 if (getgid() == gid) {
7145 if (setgid(gid) < 0) rb_sys_fail(0);
7146 SAVED_GROUP_ID = gid;
7151#elif defined HAVE_SETEGID
7152 if (getgid() == gid && SAVED_GROUP_ID == gid) {
7153 if (setegid(gid) < 0) rb_sys_fail(0);
7158#elif defined HAVE_SETGID
7159 if (getgid() == gid && SAVED_GROUP_ID == gid) {
7160 if (setgid(gid) < 0) rb_sys_fail(0);
7187proc_geteuid(
VALUE obj)
7189 rb_uid_t euid = geteuid();
7193#if defined(HAVE_SETRESUID) || defined(HAVE_SETREUID) || defined(HAVE_SETEUID) || defined(HAVE_SETUID) || defined(_POSIX_SAVED_IDS)
7195proc_seteuid(rb_uid_t uid)
7197#if defined(HAVE_SETRESUID)
7198 if (setresuid(-1, uid, -1) < 0) rb_sys_fail(0);
7199#elif defined HAVE_SETREUID
7200 if (setreuid(-1, uid) < 0) rb_sys_fail(0);
7201#elif defined HAVE_SETEUID
7202 if (seteuid(uid) < 0) rb_sys_fail(0);
7203#elif defined HAVE_SETUID
7204 if (uid == getuid()) {
7205 if (setuid(uid) < 0) rb_sys_fail(0);
7216#if defined(HAVE_SETRESUID) || defined(HAVE_SETREUID) || defined(HAVE_SETEUID) || defined(HAVE_SETUID)
7230 proc_seteuid(OBJ2UID(euid));
7234#define proc_seteuid_m rb_f_notimplement
7238rb_seteuid_core(rb_uid_t euid)
7240#if defined(HAVE_SETRESUID) || (defined(HAVE_SETREUID) && !defined(OBSOLETE_SETREUID))
7246#if defined(HAVE_SETRESUID) || (defined(HAVE_SETREUID) && !defined(OBSOLETE_SETREUID))
7250#if defined(HAVE_SETRESUID)
7252 if (setresuid(-1,euid,euid) < 0) rb_sys_fail(0);
7253 SAVED_USER_ID = euid;
7256 if (setresuid(-1,euid,-1) < 0) rb_sys_fail(0);
7258#elif defined(HAVE_SETREUID) && !defined(OBSOLETE_SETREUID)
7259 if (setreuid(-1, euid) < 0) rb_sys_fail(0);
7261 if (setreuid(euid,uid) < 0) rb_sys_fail(0);
7262 if (setreuid(uid,euid) < 0) rb_sys_fail(0);
7263 SAVED_USER_ID = euid;
7265#elif defined HAVE_SETEUID
7266 if (seteuid(euid) < 0) rb_sys_fail(0);
7267#elif defined HAVE_SETUID
7268 if (geteuid() == 0) rb_sys_fail(0);
7269 if (setuid(euid) < 0) rb_sys_fail(0);
7294 rb_seteuid_core(OBJ2UID(
id));
7313proc_getegid(
VALUE obj)
7315 rb_gid_t egid = getegid();
7320#if defined(HAVE_SETRESGID) || defined(HAVE_SETREGID) || defined(HAVE_SETEGID) || defined(HAVE_SETGID) || defined(_POSIX_SAVED_IDS)
7333#if defined(HAVE_SETRESGID) || defined(HAVE_SETREGID) || defined(HAVE_SETEGID) || defined(HAVE_SETGID)
7339#if defined(HAVE_SETRESGID) || defined(HAVE_SETREGID) || defined(HAVE_SETEGID) || defined(HAVE_SETGID)
7340 gid = OBJ2GID(egid);
7343#if defined(HAVE_SETRESGID)
7344 if (setresgid(-1, gid, -1) < 0) rb_sys_fail(0);
7345#elif defined HAVE_SETREGID
7346 if (setregid(-1, gid) < 0) rb_sys_fail(0);
7347#elif defined HAVE_SETEGID
7348 if (setegid(gid) < 0) rb_sys_fail(0);
7349#elif defined HAVE_SETGID
7350 if (gid == getgid()) {
7351 if (setgid(gid) < 0) rb_sys_fail(0);
7363#if defined(HAVE_SETRESGID) || defined(HAVE_SETREGID) || defined(HAVE_SETEGID) || defined(HAVE_SETGID)
7364#define proc_setegid_m proc_setegid
7366#define proc_setegid_m rb_f_notimplement
7370rb_setegid_core(rb_gid_t egid)
7372#if defined(HAVE_SETRESGID) || (defined(HAVE_SETREGID) && !defined(OBSOLETE_SETREGID))
7378#if defined(HAVE_SETRESGID) || (defined(HAVE_SETREGID) && !defined(OBSOLETE_SETREGID))
7382#if defined(HAVE_SETRESGID)
7384 if (setresgid(-1,egid,egid) < 0) rb_sys_fail(0);
7385 SAVED_GROUP_ID = egid;
7388 if (setresgid(-1,egid,-1) < 0) rb_sys_fail(0);
7390#elif defined(HAVE_SETREGID) && !defined(OBSOLETE_SETREGID)
7391 if (setregid(-1, egid) < 0) rb_sys_fail(0);
7393 if (setregid(egid,gid) < 0) rb_sys_fail(0);
7394 if (setregid(gid,egid) < 0) rb_sys_fail(0);
7395 SAVED_GROUP_ID = egid;
7397#elif defined HAVE_SETEGID
7398 if (setegid(egid) < 0) rb_sys_fail(0);
7399#elif defined HAVE_SETGID
7400 if (geteuid() == 0 ) rb_sys_fail(0);
7401 if (setgid(egid) < 0) rb_sys_fail(0);
7426 rb_setegid_core(OBJ2GID(
id));
7441p_uid_exchangeable(
VALUE _)
7443#if defined(HAVE_SETRESUID)
7445#elif defined(HAVE_SETREUID) && !defined(OBSOLETE_SETREUID)
7466p_uid_exchange(
VALUE obj)
7469#if defined(HAVE_SETRESUID) || (defined(HAVE_SETREUID) && !defined(OBSOLETE_SETREUID))
7476#if defined(HAVE_SETRESUID) || (defined(HAVE_SETREUID) && !defined(OBSOLETE_SETREUID))
7480#if defined(HAVE_SETRESUID)
7481 if (setresuid(euid, uid, uid) < 0) rb_sys_fail(0);
7482 SAVED_USER_ID = uid;
7483#elif defined(HAVE_SETREUID) && !defined(OBSOLETE_SETREUID)
7484 if (setreuid(euid,uid) < 0) rb_sys_fail(0);
7485 SAVED_USER_ID = uid;
7503p_gid_exchangeable(
VALUE _)
7505#if defined(HAVE_SETRESGID)
7507#elif defined(HAVE_SETREGID) && !defined(OBSOLETE_SETREGID)
7528p_gid_exchange(
VALUE obj)
7531#if defined(HAVE_SETRESGID) || (defined(HAVE_SETREGID) && !defined(OBSOLETE_SETREGID))
7538#if defined(HAVE_SETRESGID) || (defined(HAVE_SETREGID) && !defined(OBSOLETE_SETREGID))
7542#if defined(HAVE_SETRESGID)
7543 if (setresgid(egid, gid, gid) < 0) rb_sys_fail(0);
7544 SAVED_GROUP_ID = gid;
7545#elif defined(HAVE_SETREGID) && !defined(OBSOLETE_SETREGID)
7546 if (setregid(egid,gid) < 0) rb_sys_fail(0);
7547 SAVED_GROUP_ID = gid;
7566p_uid_have_saved_id(
VALUE _)
7568#if defined(HAVE_SETRESUID) || defined(HAVE_SETEUID) || defined(_POSIX_SAVED_IDS)
7576#if defined(HAVE_SETRESUID) || defined(HAVE_SETEUID) || defined(_POSIX_SAVED_IDS)
7578p_uid_sw_ensure(
VALUE i)
7580 rb_uid_t
id = (rb_uid_t)i;
7581 under_uid_switch = 0;
7582 id = rb_seteuid_core(
id);
7601p_uid_switch(
VALUE obj)
7613 under_uid_switch = 1;
7620 else if (euid != SAVED_USER_ID) {
7621 proc_seteuid(SAVED_USER_ID);
7623 under_uid_switch = 1;
7638p_uid_sw_ensure(
VALUE obj)
7640 under_uid_switch = 0;
7641 return p_uid_exchange(obj);
7645p_uid_switch(
VALUE obj)
7657 p_uid_exchange(obj);
7659 under_uid_switch = 1;
7681p_gid_have_saved_id(
VALUE _)
7683#if defined(HAVE_SETRESGID) || defined(HAVE_SETEGID) || defined(_POSIX_SAVED_IDS)
7690#if defined(HAVE_SETRESGID) || defined(HAVE_SETEGID) || defined(_POSIX_SAVED_IDS)
7692p_gid_sw_ensure(
VALUE i)
7694 rb_gid_t
id = (rb_gid_t)i;
7695 under_gid_switch = 0;
7696 id = rb_setegid_core(
id);
7715p_gid_switch(
VALUE obj)
7727 under_gid_switch = 1;
7734 else if (egid != SAVED_GROUP_ID) {
7735 proc_setegid(obj,
GIDT2NUM(SAVED_GROUP_ID));
7737 under_gid_switch = 1;
7752p_gid_sw_ensure(
VALUE obj)
7754 under_gid_switch = 0;
7755 return p_gid_exchange(obj);
7759p_gid_switch(
VALUE obj)
7771 p_gid_exchange(obj);
7773 under_gid_switch = 1;
7783#if defined(HAVE_TIMES)
7787#ifdef HAVE__SC_CLK_TCK
7788 return sysconf(_SC_CLK_TCK);
7789#elif defined CLK_TCK
7812rb_proc_times(
VALUE obj)
7814 VALUE utime, stime, cutime, cstime, ret;
7815#if defined(RUSAGE_SELF) && defined(RUSAGE_CHILDREN)
7816 struct rusage usage_s, usage_c;
7818 if (getrusage(RUSAGE_SELF, &usage_s) != 0 || getrusage(RUSAGE_CHILDREN, &usage_c) != 0)
7819 rb_sys_fail(
"getrusage");
7820 utime =
DBL2NUM((
double)usage_s.ru_utime.tv_sec + (
double)usage_s.ru_utime.tv_usec/1e6);
7821 stime =
DBL2NUM((
double)usage_s.ru_stime.tv_sec + (
double)usage_s.ru_stime.tv_usec/1e6);
7822 cutime =
DBL2NUM((
double)usage_c.ru_utime.tv_sec + (
double)usage_c.ru_utime.tv_usec/1e6);
7823 cstime =
DBL2NUM((
double)usage_c.ru_stime.tv_sec + (
double)usage_c.ru_stime.tv_usec/1e6);
7825 const double hertz = (double)get_clk_tck();
7829 utime =
DBL2NUM(buf.tms_utime / hertz);
7830 stime =
DBL2NUM(buf.tms_stime / hertz);
7831 cutime =
DBL2NUM(buf.tms_cutime / hertz);
7832 cstime =
DBL2NUM(buf.tms_cstime / hertz);
7834 ret =
rb_struct_new(rb_cProcessTms, utime, stime, cutime, cstime);
7842#define rb_proc_times rb_f_notimplement
7845#ifdef HAVE_LONG_LONG
7847#define TIMETICK_INT_MIN LLONG_MIN
7848#define TIMETICK_INT_MAX LLONG_MAX
7849#define TIMETICK_INT2NUM(v) LL2NUM(v)
7850#define MUL_OVERFLOW_TIMETICK_P(a, b) MUL_OVERFLOW_LONG_LONG_P(a, b)
7852typedef long timetick_int_t;
7853#define TIMETICK_INT_MIN LONG_MIN
7854#define TIMETICK_INT_MAX LONG_MAX
7855#define TIMETICK_INT2NUM(v) LONG2NUM(v)
7856#define MUL_OVERFLOW_TIMETICK_P(a, b) MUL_OVERFLOW_LONG_P(a, b)
7859CONSTFUNC(
static timetick_int_t gcd_timetick_int(timetick_int_t, timetick_int_t));
7860static timetick_int_t
7861gcd_timetick_int(timetick_int_t a, timetick_int_t b)
7881reduce_fraction(timetick_int_t *np, timetick_int_t *dp)
7883 timetick_int_t gcd = gcd_timetick_int(*np, *dp);
7891reduce_factors(timetick_int_t *numerators,
int num_numerators,
7892 timetick_int_t *denominators,
int num_denominators)
7895 for (i = 0; i < num_numerators; i++) {
7896 if (numerators[i] == 1)
7898 for (j = 0; j < num_denominators; j++) {
7899 if (denominators[j] == 1)
7901 reduce_fraction(&numerators[i], &denominators[j]);
7907 timetick_int_t giga_count;
7912timetick2dblnum(
struct timetick *ttp,
7913 timetick_int_t *numerators,
int num_numerators,
7914 timetick_int_t *denominators,
int num_denominators)
7919 reduce_factors(numerators, num_numerators,
7920 denominators, num_denominators);
7922 d = ttp->giga_count * 1e9 + ttp->count;
7924 for (i = 0; i < num_numerators; i++)
7926 for (i = 0; i < num_denominators; i++)
7927 d /= denominators[i];
7933timetick2dblnum_reciprocal(
struct timetick *ttp,
7934 timetick_int_t *numerators,
int num_numerators,
7935 timetick_int_t *denominators,
int num_denominators)
7940 reduce_factors(numerators, num_numerators,
7941 denominators, num_denominators);
7944 for (i = 0; i < num_denominators; i++)
7945 d *= denominators[i];
7946 for (i = 0; i < num_numerators; i++)
7948 d /= ttp->giga_count * 1e9 + ttp->count;
7953#define NDIV(x,y) (-(-((x)+1)/(y))-1)
7954#define DIV(n,d) ((n)<0 ? NDIV((n),(d)) : (n)/(d))
7957timetick2integer(
struct timetick *ttp,
7958 timetick_int_t *numerators,
int num_numerators,
7959 timetick_int_t *denominators,
int num_denominators)
7964 reduce_factors(numerators, num_numerators,
7965 denominators, num_denominators);
7967 if (!MUL_OVERFLOW_SIGNED_INTEGER_P(1000000000, ttp->giga_count,
7968 TIMETICK_INT_MIN, TIMETICK_INT_MAX-ttp->count)) {
7969 timetick_int_t t = ttp->giga_count * 1000000000 + ttp->count;
7970 for (i = 0; i < num_numerators; i++) {
7971 timetick_int_t factor = numerators[i];
7972 if (MUL_OVERFLOW_TIMETICK_P(factor, t))
7976 for (i = 0; i < num_denominators; i++) {
7977 t = DIV(t, denominators[i]);
7979 return TIMETICK_INT2NUM(t);
7983 v = TIMETICK_INT2NUM(ttp->giga_count);
7986 for (i = 0; i < num_numerators; i++) {
7987 timetick_int_t factor = numerators[i];
7990 v =
rb_funcall(v,
'*', 1, TIMETICK_INT2NUM(factor));
7992 for (i = 0; i < num_denominators; i++) {
7993 v =
rb_funcall(v,
'/', 1, TIMETICK_INT2NUM(denominators[i]));
7999make_clock_result(
struct timetick *ttp,
8000 timetick_int_t *numerators,
int num_numerators,
8001 timetick_int_t *denominators,
int num_denominators,
8004 if (unit ==
ID2SYM(id_nanosecond)) {
8005 numerators[num_numerators++] = 1000000000;
8006 return timetick2integer(ttp, numerators, num_numerators, denominators, num_denominators);
8008 else if (unit ==
ID2SYM(id_microsecond)) {
8009 numerators[num_numerators++] = 1000000;
8010 return timetick2integer(ttp, numerators, num_numerators, denominators, num_denominators);
8012 else if (unit ==
ID2SYM(id_millisecond)) {
8013 numerators[num_numerators++] = 1000;
8014 return timetick2integer(ttp, numerators, num_numerators, denominators, num_denominators);
8016 else if (unit ==
ID2SYM(id_second)) {
8017 return timetick2integer(ttp, numerators, num_numerators, denominators, num_denominators);
8019 else if (unit ==
ID2SYM(id_float_microsecond)) {
8020 numerators[num_numerators++] = 1000000;
8021 return timetick2dblnum(ttp, numerators, num_numerators, denominators, num_denominators);
8023 else if (unit ==
ID2SYM(id_float_millisecond)) {
8024 numerators[num_numerators++] = 1000;
8025 return timetick2dblnum(ttp, numerators, num_numerators, denominators, num_denominators);
8027 else if (
NIL_P(unit) || unit ==
ID2SYM(id_float_second)) {
8028 return timetick2dblnum(ttp, numerators, num_numerators, denominators, num_denominators);
8031 rb_raise(rb_eArgError,
"unexpected unit: %"PRIsVALUE, unit);
8035static const mach_timebase_info_data_t *
8036get_mach_timebase_info(
void)
8038 static mach_timebase_info_data_t sTimebaseInfo;
8040 if ( sTimebaseInfo.denom == 0 ) {
8041 (void) mach_timebase_info(&sTimebaseInfo);
8044 return &sTimebaseInfo;
8048ruby_real_ms_time(
void)
8050 const mach_timebase_info_data_t *info = get_mach_timebase_info();
8051 uint64_t t = mach_absolute_time();
8052 return (
double)t * info->numer / info->denom / 1e6;
8056#if defined(NUM2CLOCKID)
8057# define NUMERIC_CLOCKID 1
8059# define NUMERIC_CLOCKID 0
8060# define NUM2CLOCKID(x) 0
8063#define clock_failed(name, err, arg) do { \
8064 int clock_error = (err); \
8065 rb_syserr_fail_str(clock_error, rb_sprintf("clock_" name "(%+"PRIsVALUE")", (arg))); \
8238 timetick_int_t numerators[2];
8239 timetick_int_t denominators[2];
8240 int num_numerators = 0;
8241 int num_denominators = 0;
8244 VALUE clk_id = argv[0];
8245#ifdef HAVE_CLOCK_GETTIME
8250#ifdef CLOCK_REALTIME
8251 if (clk_id == RUBY_CLOCK_REALTIME) {
8257#ifdef CLOCK_MONOTONIC
8258 if (clk_id == RUBY_CLOCK_MONOTONIC) {
8259 c = CLOCK_MONOTONIC;
8264#ifdef CLOCK_PROCESS_CPUTIME_ID
8265 if (clk_id == RUBY_CLOCK_PROCESS_CPUTIME_ID) {
8266 c = CLOCK_PROCESS_CPUTIME_ID;
8271#ifdef CLOCK_THREAD_CPUTIME_ID
8272 if (clk_id == RUBY_CLOCK_THREAD_CPUTIME_ID) {
8273 c = CLOCK_THREAD_CPUTIME_ID;
8281#ifdef HAVE_GETTIMEOFDAY
8286#define RUBY_GETTIMEOFDAY_BASED_CLOCK_REALTIME ID2SYM(id_GETTIMEOFDAY_BASED_CLOCK_REALTIME)
8287 if (clk_id == RUBY_GETTIMEOFDAY_BASED_CLOCK_REALTIME) {
8289 ret = gettimeofday(&tv, 0);
8291 rb_sys_fail(
"gettimeofday");
8292 tt.giga_count = tv.tv_sec;
8293 tt.count = (int32_t)tv.tv_usec * 1000;
8294 denominators[num_denominators++] = 1000000000;
8299#define RUBY_TIME_BASED_CLOCK_REALTIME ID2SYM(id_TIME_BASED_CLOCK_REALTIME)
8300 if (clk_id == RUBY_TIME_BASED_CLOCK_REALTIME) {
8303 if (t == (time_t)-1)
8304 rb_sys_fail(
"time");
8307 denominators[num_denominators++] = 1000000000;
8312#define RUBY_TIMES_BASED_CLOCK_MONOTONIC \
8313 ID2SYM(id_TIMES_BASED_CLOCK_MONOTONIC)
8314 if (clk_id == RUBY_TIMES_BASED_CLOCK_MONOTONIC) {
8317 unsigned_clock_t uc;
8319 if (c == (clock_t)-1)
8320 rb_sys_fail(
"times");
8321 uc = (unsigned_clock_t)c;
8322 tt.count = (int32_t)(uc % 1000000000);
8323 tt.giga_count = (uc / 1000000000);
8324 denominators[num_denominators++] = get_clk_tck();
8330#define RUBY_GETRUSAGE_BASED_CLOCK_PROCESS_CPUTIME_ID \
8331 ID2SYM(id_GETRUSAGE_BASED_CLOCK_PROCESS_CPUTIME_ID)
8332 if (clk_id == RUBY_GETRUSAGE_BASED_CLOCK_PROCESS_CPUTIME_ID) {
8333 struct rusage usage;
8335 ret = getrusage(RUSAGE_SELF, &usage);
8337 rb_sys_fail(
"getrusage");
8338 tt.giga_count = usage.ru_utime.tv_sec + usage.ru_stime.tv_sec;
8339 usec = (int32_t)(usage.ru_utime.tv_usec + usage.ru_stime.tv_usec);
8340 if (1000000 <= usec) {
8344 tt.count = usec * 1000;
8345 denominators[num_denominators++] = 1000000000;
8351#define RUBY_TIMES_BASED_CLOCK_PROCESS_CPUTIME_ID \
8352 ID2SYM(id_TIMES_BASED_CLOCK_PROCESS_CPUTIME_ID)
8353 if (clk_id == RUBY_TIMES_BASED_CLOCK_PROCESS_CPUTIME_ID) {
8355 unsigned_clock_t utime, stime;
8356 if (times(&buf) == (clock_t)-1)
8357 rb_sys_fail(
"times");
8358 utime = (unsigned_clock_t)buf.tms_utime;
8359 stime = (unsigned_clock_t)buf.tms_stime;
8360 tt.count = (int32_t)((utime % 1000000000) + (stime % 1000000000));
8361 tt.giga_count = (utime / 1000000000) + (stime / 1000000000);
8362 if (1000000000 <= tt.count) {
8363 tt.count -= 1000000000;
8366 denominators[num_denominators++] = get_clk_tck();
8371#define RUBY_CLOCK_BASED_CLOCK_PROCESS_CPUTIME_ID \
8372 ID2SYM(id_CLOCK_BASED_CLOCK_PROCESS_CPUTIME_ID)
8373 if (clk_id == RUBY_CLOCK_BASED_CLOCK_PROCESS_CPUTIME_ID) {
8375 unsigned_clock_t uc;
8378 if (c == (clock_t)-1)
8379 rb_sys_fail(
"clock");
8380 uc = (unsigned_clock_t)c;
8381 tt.count = (int32_t)(uc % 1000000000);
8382 tt.giga_count = uc / 1000000000;
8383 denominators[num_denominators++] = CLOCKS_PER_SEC;
8388 if (clk_id == RUBY_MACH_ABSOLUTE_TIME_BASED_CLOCK_MONOTONIC) {
8389 const mach_timebase_info_data_t *info = get_mach_timebase_info();
8390 uint64_t t = mach_absolute_time();
8391 tt.count = (int32_t)(t % 1000000000);
8392 tt.giga_count = t / 1000000000;
8393 numerators[num_numerators++] = info->numer;
8394 denominators[num_denominators++] = info->denom;
8395 denominators[num_denominators++] = 1000000000;
8400 else if (NUMERIC_CLOCKID) {
8401#if defined(HAVE_CLOCK_GETTIME)
8403 c = NUM2CLOCKID(clk_id);
8405 ret = clock_gettime(c, &ts);
8407 clock_failed(
"gettime",
errno, clk_id);
8408 tt.count = (int32_t)ts.tv_nsec;
8409 tt.giga_count = ts.tv_sec;
8410 denominators[num_denominators++] = 1000000000;
8417 clock_failed(
"gettime", EINVAL, clk_id);
8420 return make_clock_result(&tt, numerators, num_numerators, denominators, num_denominators, unit);
8465 timetick_int_t numerators[2];
8466 timetick_int_t denominators[2];
8467 int num_numerators = 0;
8468 int num_denominators = 0;
8469#ifdef HAVE_CLOCK_GETRES
8474 VALUE clk_id = argv[0];
8477#ifdef CLOCK_REALTIME
8478 if (clk_id == RUBY_CLOCK_REALTIME) {
8484#ifdef CLOCK_MONOTONIC
8485 if (clk_id == RUBY_CLOCK_MONOTONIC) {
8486 c = CLOCK_MONOTONIC;
8491#ifdef CLOCK_PROCESS_CPUTIME_ID
8492 if (clk_id == RUBY_CLOCK_PROCESS_CPUTIME_ID) {
8493 c = CLOCK_PROCESS_CPUTIME_ID;
8498#ifdef CLOCK_THREAD_CPUTIME_ID
8499 if (clk_id == RUBY_CLOCK_THREAD_CPUTIME_ID) {
8500 c = CLOCK_THREAD_CPUTIME_ID;
8505#ifdef RUBY_GETTIMEOFDAY_BASED_CLOCK_REALTIME
8506 if (clk_id == RUBY_GETTIMEOFDAY_BASED_CLOCK_REALTIME) {
8509 denominators[num_denominators++] = 1000000000;
8514#ifdef RUBY_TIME_BASED_CLOCK_REALTIME
8515 if (clk_id == RUBY_TIME_BASED_CLOCK_REALTIME) {
8518 denominators[num_denominators++] = 1000000000;
8523#ifdef RUBY_TIMES_BASED_CLOCK_MONOTONIC
8524 if (clk_id == RUBY_TIMES_BASED_CLOCK_MONOTONIC) {
8527 denominators[num_denominators++] = get_clk_tck();
8532#ifdef RUBY_GETRUSAGE_BASED_CLOCK_PROCESS_CPUTIME_ID
8533 if (clk_id == RUBY_GETRUSAGE_BASED_CLOCK_PROCESS_CPUTIME_ID) {
8536 denominators[num_denominators++] = 1000000000;
8541#ifdef RUBY_TIMES_BASED_CLOCK_PROCESS_CPUTIME_ID
8542 if (clk_id == RUBY_TIMES_BASED_CLOCK_PROCESS_CPUTIME_ID) {
8545 denominators[num_denominators++] = get_clk_tck();
8550#ifdef RUBY_CLOCK_BASED_CLOCK_PROCESS_CPUTIME_ID
8551 if (clk_id == RUBY_CLOCK_BASED_CLOCK_PROCESS_CPUTIME_ID) {
8554 denominators[num_denominators++] = CLOCKS_PER_SEC;
8559#ifdef RUBY_MACH_ABSOLUTE_TIME_BASED_CLOCK_MONOTONIC
8560 if (clk_id == RUBY_MACH_ABSOLUTE_TIME_BASED_CLOCK_MONOTONIC) {
8561 const mach_timebase_info_data_t *info = get_mach_timebase_info();
8564 numerators[num_numerators++] = info->numer;
8565 denominators[num_denominators++] = info->denom;
8566 denominators[num_denominators++] = 1000000000;
8571 else if (NUMERIC_CLOCKID) {
8572#if defined(HAVE_CLOCK_GETRES)
8574 c = NUM2CLOCKID(clk_id);
8576 ret = clock_getres(c, &ts);
8578 clock_failed(
"getres",
errno, clk_id);
8579 tt.count = (int32_t)ts.tv_nsec;
8580 tt.giga_count = ts.tv_sec;
8581 denominators[num_denominators++] = 1000000000;
8588 clock_failed(
"getres", EINVAL, clk_id);
8591 if (unit ==
ID2SYM(id_hertz)) {
8592 return timetick2dblnum_reciprocal(&tt, numerators, num_numerators, denominators, num_denominators);
8595 return make_clock_result(&tt, numerators, num_numerators, denominators, num_denominators, unit);
8600get_CHILD_STATUS(
ID _x,
VALUE *_y)
8606get_PROCESS_ID(
ID _x,
VALUE *_y)
8698static VALUE rb_mProcUID;
8699static VALUE rb_mProcGID;
8700static VALUE rb_mProcID_Syscall;
8736 rb_eager_load_detailed_message_extension();
8739 rb_gc_prepare_heap();
9167 rb_gvar_ractor_local(
"$$");
9168 rb_gvar_ractor_local(
"$?");
9223 process_status_dump, process_status_load);
9259#ifdef HAVE_GETPRIORITY
9270#if defined(RLIM2NUM) && defined(RLIM_INFINITY)
9272 VALUE inf = RLIM2NUM(RLIM_INFINITY);
9273#ifdef RLIM_SAVED_MAX
9275 VALUE v = RLIM_INFINITY == RLIM_SAVED_MAX ? inf : RLIM2NUM(RLIM_SAVED_MAX);
9277 rb_define_const(
rb_mProcess,
"RLIM_SAVED_MAX", v);
9281 rb_define_const(
rb_mProcess,
"RLIM_INFINITY", inf);
9282#ifdef RLIM_SAVED_CUR
9284 VALUE v = RLIM_INFINITY == RLIM_SAVED_CUR ? inf : RLIM2NUM(RLIM_SAVED_CUR);
9286 rb_define_const(
rb_mProcess,
"RLIM_SAVED_CUR", v);
9325#ifdef RLIMIT_MEMLOCK
9332#ifdef RLIMIT_MSGQUEUE
9398#ifdef RLIMIT_SIGPENDING
9433#if defined(RUBY_CLOCK_REALTIME)
9434#elif defined(RUBY_GETTIMEOFDAY_BASED_CLOCK_REALTIME)
9435# define RUBY_CLOCK_REALTIME RUBY_GETTIMEOFDAY_BASED_CLOCK_REALTIME
9436#elif defined(RUBY_TIME_BASED_CLOCK_REALTIME)
9437# define RUBY_CLOCK_REALTIME RUBY_TIME_BASED_CLOCK_REALTIME
9439#if defined(CLOCK_REALTIME) && defined(CLOCKID2NUM)
9441 rb_define_const(
rb_mProcess,
"CLOCK_REALTIME", CLOCKID2NUM(CLOCK_REALTIME));
9442#elif defined(RUBY_CLOCK_REALTIME)
9443 rb_define_const(
rb_mProcess,
"CLOCK_REALTIME", RUBY_CLOCK_REALTIME);
9446#if defined(RUBY_CLOCK_MONOTONIC)
9447#elif defined(RUBY_MACH_ABSOLUTE_TIME_BASED_CLOCK_MONOTONIC)
9448# define RUBY_CLOCK_MONOTONIC RUBY_MACH_ABSOLUTE_TIME_BASED_CLOCK_MONOTONIC
9450#if defined(CLOCK_MONOTONIC) && defined(CLOCKID2NUM)
9452 rb_define_const(
rb_mProcess,
"CLOCK_MONOTONIC", CLOCKID2NUM(CLOCK_MONOTONIC));
9453#elif defined(RUBY_CLOCK_MONOTONIC)
9454 rb_define_const(
rb_mProcess,
"CLOCK_MONOTONIC", RUBY_CLOCK_MONOTONIC);
9457#if defined(RUBY_CLOCK_PROCESS_CPUTIME_ID)
9458#elif defined(RUBY_GETRUSAGE_BASED_CLOCK_PROCESS_CPUTIME_ID)
9459# define RUBY_CLOCK_PROCESS_CPUTIME_ID RUBY_GETRUSAGE_BASED_CLOCK_PROCESS_CPUTIME_ID
9461#if defined(CLOCK_PROCESS_CPUTIME_ID) && defined(CLOCKID2NUM)
9463 rb_define_const(
rb_mProcess,
"CLOCK_PROCESS_CPUTIME_ID", CLOCKID2NUM(CLOCK_PROCESS_CPUTIME_ID));
9464#elif defined(RUBY_CLOCK_PROCESS_CPUTIME_ID)
9465 rb_define_const(
rb_mProcess,
"CLOCK_PROCESS_CPUTIME_ID", RUBY_CLOCK_PROCESS_CPUTIME_ID);
9468#if defined(CLOCK_THREAD_CPUTIME_ID) && defined(CLOCKID2NUM)
9470 rb_define_const(
rb_mProcess,
"CLOCK_THREAD_CPUTIME_ID", CLOCKID2NUM(CLOCK_THREAD_CPUTIME_ID));
9471#elif defined(RUBY_CLOCK_THREAD_CPUTIME_ID)
9472 rb_define_const(
rb_mProcess,
"CLOCK_THREAD_CPUTIME_ID", RUBY_CLOCK_THREAD_CPUTIME_ID);
9478 rb_define_const(
rb_mProcess,
"CLOCK_VIRTUAL", CLOCKID2NUM(CLOCK_VIRTUAL));
9482 rb_define_const(
rb_mProcess,
"CLOCK_PROF", CLOCKID2NUM(CLOCK_PROF));
9484#ifdef CLOCK_REALTIME_FAST
9486 rb_define_const(
rb_mProcess,
"CLOCK_REALTIME_FAST", CLOCKID2NUM(CLOCK_REALTIME_FAST));
9488#ifdef CLOCK_REALTIME_PRECISE
9490 rb_define_const(
rb_mProcess,
"CLOCK_REALTIME_PRECISE", CLOCKID2NUM(CLOCK_REALTIME_PRECISE));
9492#ifdef CLOCK_REALTIME_COARSE
9494 rb_define_const(
rb_mProcess,
"CLOCK_REALTIME_COARSE", CLOCKID2NUM(CLOCK_REALTIME_COARSE));
9496#ifdef CLOCK_REALTIME_ALARM
9498 rb_define_const(
rb_mProcess,
"CLOCK_REALTIME_ALARM", CLOCKID2NUM(CLOCK_REALTIME_ALARM));
9500#ifdef CLOCK_MONOTONIC_FAST
9502 rb_define_const(
rb_mProcess,
"CLOCK_MONOTONIC_FAST", CLOCKID2NUM(CLOCK_MONOTONIC_FAST));
9504#ifdef CLOCK_MONOTONIC_PRECISE
9506 rb_define_const(
rb_mProcess,
"CLOCK_MONOTONIC_PRECISE", CLOCKID2NUM(CLOCK_MONOTONIC_PRECISE));
9508#ifdef CLOCK_MONOTONIC_RAW
9510 rb_define_const(
rb_mProcess,
"CLOCK_MONOTONIC_RAW", CLOCKID2NUM(CLOCK_MONOTONIC_RAW));
9512#ifdef CLOCK_MONOTONIC_RAW_APPROX
9514 rb_define_const(
rb_mProcess,
"CLOCK_MONOTONIC_RAW_APPROX", CLOCKID2NUM(CLOCK_MONOTONIC_RAW_APPROX));
9516#ifdef CLOCK_MONOTONIC_COARSE
9518 rb_define_const(
rb_mProcess,
"CLOCK_MONOTONIC_COARSE", CLOCKID2NUM(CLOCK_MONOTONIC_COARSE));
9520#ifdef CLOCK_BOOTTIME
9522 rb_define_const(
rb_mProcess,
"CLOCK_BOOTTIME", CLOCKID2NUM(CLOCK_BOOTTIME));
9524#ifdef CLOCK_BOOTTIME_ALARM
9526 rb_define_const(
rb_mProcess,
"CLOCK_BOOTTIME_ALARM", CLOCKID2NUM(CLOCK_BOOTTIME_ALARM));
9530 rb_define_const(
rb_mProcess,
"CLOCK_UPTIME", CLOCKID2NUM(CLOCK_UPTIME));
9532#ifdef CLOCK_UPTIME_FAST
9534 rb_define_const(
rb_mProcess,
"CLOCK_UPTIME_FAST", CLOCKID2NUM(CLOCK_UPTIME_FAST));
9536#ifdef CLOCK_UPTIME_PRECISE
9538 rb_define_const(
rb_mProcess,
"CLOCK_UPTIME_PRECISE", CLOCKID2NUM(CLOCK_UPTIME_PRECISE));
9540#ifdef CLOCK_UPTIME_RAW
9542 rb_define_const(
rb_mProcess,
"CLOCK_UPTIME_RAW", CLOCKID2NUM(CLOCK_UPTIME_RAW));
9544#ifdef CLOCK_UPTIME_RAW_APPROX
9546 rb_define_const(
rb_mProcess,
"CLOCK_UPTIME_RAW_APPROX", CLOCKID2NUM(CLOCK_UPTIME_RAW_APPROX));
9550 rb_define_const(
rb_mProcess,
"CLOCK_SECOND", CLOCKID2NUM(CLOCK_SECOND));
9554 rb_define_const(
rb_mProcess,
"CLOCK_TAI", CLOCKID2NUM(CLOCK_TAI));
9560#if defined(HAVE_TIMES) || defined(_WIN32)
9574 SAVED_USER_ID = geteuid();
9575 SAVED_GROUP_ID = getegid();
9577 rb_mProcUID = rb_define_module_under(
rb_mProcess,
"UID");
9578 rb_mProcGID = rb_define_module_under(
rb_mProcess,
"GID");
9598#ifdef p_uid_from_name
9601#ifdef p_gid_from_name
9605 rb_mProcID_Syscall = rb_define_module_under(
rb_mProcess,
"Sys");
9632#define define_id(name) id_##name = rb_intern_const(#name)
9645 define_id(new_pgroup);
9647 define_id(unsetenv_others);
9650 define_id(close_others);
9651 define_id(nanosecond);
9652 define_id(microsecond);
9653 define_id(millisecond);
9655 define_id(float_microsecond);
9656 define_id(float_millisecond);
9657 define_id(float_second);
9658 define_id(GETTIMEOFDAY_BASED_CLOCK_REALTIME);
9659 define_id(TIME_BASED_CLOCK_REALTIME);
9660#ifdef CLOCK_REALTIME
9661 define_id(CLOCK_REALTIME);
9663#ifdef CLOCK_MONOTONIC
9664 define_id(CLOCK_MONOTONIC);
9666#ifdef CLOCK_PROCESS_CPUTIME_ID
9667 define_id(CLOCK_PROCESS_CPUTIME_ID);
9669#ifdef CLOCK_THREAD_CPUTIME_ID
9670 define_id(CLOCK_THREAD_CPUTIME_ID);
9673 define_id(TIMES_BASED_CLOCK_MONOTONIC);
9674 define_id(TIMES_BASED_CLOCK_PROCESS_CPUTIME_ID);
9677 define_id(GETRUSAGE_BASED_CLOCK_PROCESS_CPUTIME_ID);
9679 define_id(CLOCK_BASED_CLOCK_PROCESS_CPUTIME_ID);
9681 define_id(MACH_ABSOLUTE_TIME_BASED_CLOCK_MONOTONIC);
9684#ifdef HAVE_WORKING_FORK
#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.
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 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.
VALUE rb_eNotImpError
NotImplementedError exception.
void rb_exc_raise(VALUE mesg)
Raises an exception in the current thread.
void rb_syserr_fail(int e, const char *mesg)
Raises appropriate exception that represents a C errno.
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_cObject
Object class.
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_obj_class(VALUE obj)
Queries the class of an object.
VALUE rb_cThread
Thread class.
VALUE rb_equal(VALUE lhs, VALUE rhs)
This function is an optimised version of calling #==.
VALUE rb_obj_freeze(VALUE obj)
Just calls rb_obj_freeze_inline() inside.
VALUE rb_to_int(VALUE val)
Identical to rb_check_to_int(), except it raises in case of conversion mismatch.
VALUE rb_funcall(VALUE recv, ID mid, int n,...)
Calls a method.
VALUE rb_ary_dup(VALUE ary)
Duplicates an array.
VALUE rb_check_array_type(VALUE obj)
Try converting an object to its array representation using its to_ary method, if any.
VALUE rb_ary_new(void)
Allocates a new, empty array.
VALUE rb_ary_push(VALUE ary, VALUE elem)
Special case of rb_ary_cat() that it adds only one element.
VALUE rb_ary_entry(VALUE ary, long off)
Queries an element of an array.
VALUE rb_assoc_new(VALUE car, VALUE cdr)
Identical to rb_ary_new_from_values(), except it expects exactly two parameters.
void rb_ary_store(VALUE ary, long key, VALUE val)
Destructively stores the passed value to the passed array's passed index.
#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.
VALUE rb_process_status_for(rb_pid_t pid, int status, int error)
Returns the Ruby value representing a waitpid(2) outcome.
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.
VALUE rb_str_subseq(VALUE str, long beg, long len)
Identical to rb_str_substr(), except the numbers are interpreted as byte offsets instead of character...
#define rb_str_new(str, len)
Allocates an instance of rb_cString.
#define rb_str_buf_cat
Just another name of rb_str_cat.
size_t rb_str_capacity(VALUE str)
Queries the capacity of the given string.
VALUE rb_str_new_frozen(VALUE str)
Creates a frozen copy of the string, if necessary.
VALUE rb_str_dup(VALUE str)
Duplicates a string.
void rb_str_set_len(VALUE str, long len)
Overwrites the length of the string.
VALUE rb_check_string_type(VALUE obj)
Try converting an object to its stringised representation using its to_str method,...
#define rb_str_cat_cstr(buf, str)
Identical to rb_str_cat(), except it assumes the passed pointer is a pointer to a C string.
void rb_str_modify_expand(VALUE str, long capa)
Identical to rb_str_modify(), except it additionally expands the capacity of the receiver.
VALUE rb_str_buf_new(long capa)
Allocates a "string buffer".
#define rb_str_new_cstr(str)
Identical to rb_str_new, except it assumes the passed pointer is a pointer to a C string.
VALUE rb_struct_define_under(VALUE space, const char *name,...)
Identical to rb_struct_define(), except it defines the class under the specified namespace instead of...
VALUE rb_struct_new(VALUE klass,...)
Creates an instance of the given struct.
VALUE rb_thread_local_aref(VALUE thread, ID key)
This badly named function reads from a Fiber local storage.
#define RUBY_UBF_IO
A special UBF for blocking IO operations.
void rb_thread_sleep_forever(void)
Blocks indefinitely.
void rb_thread_wait_for(struct timeval time)
Identical to rb_thread_sleep(), except it takes struct timeval instead.
void rb_thread_check_ints(void)
Checks for interrupts.
void rb_thread_atfork(void)
A pthread_atfork(3posix)-like API.
VALUE rb_thread_local_aset(VALUE thread, ID key, VALUE val)
This badly named function writes to a Fiber local storage.
#define RUBY_UBF_PROCESS
A special UBF for blocking process operations.
void rb_thread_sleep(int sec)
Blocks for the given period of time.
struct timeval rb_time_interval(VALUE num)
Creates a "time interval".
VALUE rb_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.
int rb_method_basic_definition_p(VALUE klass, ID mid)
Well... Let us hesitate from describing what a "basic definition" is.
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 symbol)
Obtain a frozen string representation of a symbol (not including the leading colon).
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 StringValue(v)
Ensures that the parameter object is a String.
static char * RSTRING_END(VALUE str)
Queries the end of the contents pointer of the 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.
static bool RB_TYPE_P(VALUE obj, enum ruby_value_type t)
Queries if the given object is of given type.