14#include "ruby/internal/config.h"
42# define EXIT_SUCCESS 0
46# define EXIT_FAILURE 1
53#ifdef HAVE_SYS_RESOURCE_H
54# include <sys/resource.h>
61#ifdef HAVE_SYS_PARAM_H
62# include <sys/param.h>
66# define MAXPATHLEN 1024
75#ifdef HAVE_SYS_TIMES_H
76# include <sys/times.h>
86int initgroups(
const char *, rb_gid_t);
95# include <mach/mach_time.h>
101#include "internal/bits.h"
102#include "internal/dir.h"
103#include "internal/error.h"
104#include "internal/eval.h"
105#include "internal/hash.h"
106#include "internal/numeric.h"
107#include "internal/object.h"
108#include "internal/process.h"
109#include "internal/thread.h"
110#include "internal/variable.h"
111#include "internal/warnings.h"
123#define open rb_w32_uopen
126#if defined(HAVE_TIMES) || defined(_WIN32)
127static VALUE rb_cProcessTms;
131#define WIFEXITED(w) (((w) & 0xff) == 0)
134#define WIFSIGNALED(w) (((w) & 0x7f) > 0 && (((w) & 0x7f) < 0x7f))
137#define WIFSTOPPED(w) (((w) & 0xff) == 0x7f)
140#define WEXITSTATUS(w) (((w) >> 8) & 0xff)
143#define WTERMSIG(w) ((w) & 0x7f)
146#define WSTOPSIG WEXITSTATUS
149#if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__bsdi__)
150#define HAVE_44BSD_SETUID 1
151#define HAVE_44BSD_SETGID 1
159#ifdef BROKEN_SETREUID
160#define setreuid ruby_setreuid
161int setreuid(rb_uid_t ruid, rb_uid_t euid);
163#ifdef BROKEN_SETREGID
164#define setregid ruby_setregid
165int setregid(rb_gid_t rgid, rb_gid_t egid);
168#if defined(HAVE_44BSD_SETUID) || defined(__APPLE__)
169#if !defined(USE_SETREUID) && !defined(BROKEN_SETREUID)
170#define OBSOLETE_SETREUID 1
172#if !defined(USE_SETREGID) && !defined(BROKEN_SETREGID)
173#define OBSOLETE_SETREGID 1
177static void check_uid_switch(
void);
178static void check_gid_switch(
void);
179static int exec_async_signal_safe(
const struct rb_execarg *,
char *,
size_t);
181VALUE rb_envtbl(
void);
182VALUE rb_env_to_hash(
void);
185#define p_uid_from_name p_uid_from_name
186#define p_gid_from_name p_gid_from_name
189#if defined(HAVE_UNISTD_H)
190# if defined(HAVE_GETLOGIN_R)
191# define USE_GETLOGIN_R 1
192# define GETLOGIN_R_SIZE_DEFAULT 0x100
193# define GETLOGIN_R_SIZE_LIMIT 0x1000
194# if defined(_SC_LOGIN_NAME_MAX)
195# define GETLOGIN_R_SIZE_INIT sysconf(_SC_LOGIN_NAME_MAX)
197# define GETLOGIN_R_SIZE_INIT GETLOGIN_R_SIZE_DEFAULT
199# elif defined(HAVE_GETLOGIN)
200# define USE_GETLOGIN 1
204#if defined(HAVE_PWD_H)
205# if defined(HAVE_GETPWUID_R)
206# define USE_GETPWUID_R 1
207# elif defined(HAVE_GETPWUID)
208# define USE_GETPWUID 1
210# if defined(HAVE_GETPWNAM_R)
211# define USE_GETPWNAM_R 1
212# elif defined(HAVE_GETPWNAM)
213# define USE_GETPWNAM 1
215# if defined(HAVE_GETPWNAM_R) || defined(HAVE_GETPWUID_R)
216# define GETPW_R_SIZE_DEFAULT 0x1000
217# define GETPW_R_SIZE_LIMIT 0x10000
218# if defined(_SC_GETPW_R_SIZE_MAX)
219# define GETPW_R_SIZE_INIT sysconf(_SC_GETPW_R_SIZE_MAX)
221# define GETPW_R_SIZE_INIT GETPW_R_SIZE_DEFAULT
224# ifdef USE_GETPWNAM_R
225# define PREPARE_GETPWNAM \
227# define FINISH_GETPWNAM \
228 (getpw_buf ? (void)rb_str_resize(getpw_buf, 0) : (void)0)
229# define OBJ2UID1(id) obj2uid((id), &getpw_buf)
230# define OBJ2UID(id) obj2uid0(id)
231static rb_uid_t obj2uid(VALUE
id, VALUE *getpw_buf);
232static inline rb_uid_t
242# define PREPARE_GETPWNAM
243# define FINISH_GETPWNAM
244# define OBJ2UID1(id) obj2uid((id))
245# define OBJ2UID(id) obj2uid((id))
246static rb_uid_t obj2uid(VALUE
id);
249# define PREPARE_GETPWNAM
250# define FINISH_GETPWNAM
251# define OBJ2UID1(id) NUM2UIDT(id)
252# define OBJ2UID(id) NUM2UIDT(id)
253# ifdef p_uid_from_name
254# undef p_uid_from_name
255# define p_uid_from_name rb_f_notimplement
259#if defined(HAVE_GRP_H)
260# if defined(HAVE_GETGRNAM_R) && defined(_SC_GETGR_R_SIZE_MAX)
261# define USE_GETGRNAM_R
262# define GETGR_R_SIZE_INIT sysconf(_SC_GETGR_R_SIZE_MAX)
263# define GETGR_R_SIZE_DEFAULT 0x1000
264# define GETGR_R_SIZE_LIMIT 0x10000
266# ifdef USE_GETGRNAM_R
267# define PREPARE_GETGRNAM \
269# define FINISH_GETGRNAM \
270 (getgr_buf ? (void)rb_str_resize(getgr_buf, 0) : (void)0)
271# define OBJ2GID1(id) obj2gid((id), &getgr_buf)
272# define OBJ2GID(id) obj2gid0(id)
273static rb_gid_t obj2gid(VALUE
id, VALUE *getgr_buf);
274static inline rb_gid_t
283static rb_gid_t obj2gid(VALUE
id, VALUE *getgr_buf);
285# define PREPARE_GETGRNAM
286# define FINISH_GETGRNAM
287# define OBJ2GID1(id) obj2gid((id))
288# define OBJ2GID(id) obj2gid((id))
289static rb_gid_t obj2gid(VALUE
id);
292# define PREPARE_GETGRNAM
293# define FINISH_GETGRNAM
294# define OBJ2GID1(id) NUM2GIDT(id)
295# define OBJ2GID(id) NUM2GIDT(id)
296# ifdef p_gid_from_name
297# undef p_gid_from_name
298# define p_gid_from_name rb_f_notimplement
302#if SIZEOF_CLOCK_T == SIZEOF_INT
303typedef unsigned int unsigned_clock_t;
304#elif SIZEOF_CLOCK_T == SIZEOF_LONG
305typedef unsigned long unsigned_clock_t;
306#elif defined(HAVE_LONG_LONG) && SIZEOF_CLOCK_T == SIZEOF_LONG_LONG
307typedef unsigned LONG_LONG unsigned_clock_t;
310typedef void (*sig_t) (int);
313#define id_exception idException
314static ID id_in, id_out, id_err, id_pid, id_uid, id_gid;
315static ID id_close, id_child;
320static ID id_new_pgroup;
322static ID id_unsetenv_others, id_chdir, id_umask, id_close_others;
323static ID id_nanosecond, id_microsecond, id_millisecond, id_second;
324static ID id_float_microsecond, id_float_millisecond, id_float_second;
325static ID id_GETTIMEOFDAY_BASED_CLOCK_REALTIME, id_TIME_BASED_CLOCK_REALTIME;
327static ID id_TIMES_BASED_CLOCK_MONOTONIC;
328static ID id_TIMES_BASED_CLOCK_PROCESS_CPUTIME_ID;
331static ID id_GETRUSAGE_BASED_CLOCK_PROCESS_CPUTIME_ID;
333static ID id_CLOCK_BASED_CLOCK_PROCESS_CPUTIME_ID;
335static ID id_MACH_ABSOLUTE_TIME_BASED_CLOCK_MONOTONIC;
340#if defined(__sun) && !defined(_XPG7)
341#define execv(path, argv) (rb_async_bug_errno("unreachable: async-signal-unsafe execv() is called", 0))
342#define execl(path, arg0, arg1, arg2, term) do { extern char **environ; execle((path), (arg0), (arg1), (arg2), (term), (environ)); } while (0)
343#define ALWAYS_NEED_ENVP 1
345#define ALWAYS_NEED_ENVP 0
349assert_close_on_exec(
int fd)
352#if defined(HAVE_FCNTL) && defined(F_GETFD) && defined(FD_CLOEXEC)
353 int flags = fcntl(fd, F_GETFD);
355 static const char m[] =
"reserved FD closed unexpectedly?\n";
356 (void)!write(2, m,
sizeof(m) - 1);
359 if (flags & FD_CLOEXEC)
return;
360 rb_bug(
"reserved FD did not have close-on-exec set");
362 rb_bug(
"reserved FD without close-on-exec support");
368close_unless_reserved(
int fd)
371 assert_close_on_exec(fd);
378#if defined(DEBUG_REDIRECT)
381ttyprintf(
const char *fmt, ...)
387 tty = fopen(
"con",
"w");
389 tty = fopen(
"/dev/tty",
"w");
395 vfprintf(tty, fmt, ap);
402redirect_dup(
int oldfd)
406 ttyprintf(
"dup(%d) => %d\n", oldfd, ret);
411redirect_dup2(
int oldfd,
int newfd)
414 ret = dup2(oldfd, newfd);
415 ttyprintf(
"dup2(%d, %d) => %d\n", oldfd, newfd, ret);
420redirect_cloexec_dup(
int oldfd)
424 ttyprintf(
"cloexec_dup(%d) => %d\n", oldfd, ret);
429redirect_cloexec_dup2(
int oldfd,
int newfd)
433 ttyprintf(
"cloexec_dup2(%d, %d) => %d\n", oldfd, newfd, ret);
438redirect_close(
int fd)
441 ret = close_unless_reserved(fd);
442 ttyprintf(
"close(%d) => %d\n", fd, ret);
447parent_redirect_open(
const char *pathname,
int flags, mode_t perm)
451 ttyprintf(
"parent_open(\"%s\", 0x%x, 0%o) => %d\n", pathname, flags, perm, ret);
456parent_redirect_close(
int fd)
459 ret = close_unless_reserved(fd);
460 ttyprintf(
"parent_close(%d) => %d\n", fd, ret);
465#define redirect_dup(oldfd) dup(oldfd)
466#define redirect_dup2(oldfd, newfd) dup2((oldfd), (newfd))
467#define redirect_cloexec_dup(oldfd) rb_cloexec_dup(oldfd)
468#define redirect_cloexec_dup2(oldfd, newfd) rb_cloexec_dup2((oldfd), (newfd))
469#define redirect_close(fd) close_unless_reserved(fd)
470#define parent_redirect_open(pathname, flags, perm) rb_cloexec_open((pathname), (flags), (perm))
471#define parent_redirect_close(fd) close_unless_reserved(fd)
537proc_get_ppid(VALUE
_)
573static VALUE rb_cProcessStatus;
587 .flags = RUBY_TYPED_FREE_IMMEDIATELY,
591rb_process_status_allocate(VALUE klass)
601 return GET_THREAD()->last_status;
620proc_s_last_status(VALUE mod)
626rb_process_status_new(rb_pid_t pid,
int status,
int error)
628 VALUE last_status = rb_process_status_allocate(rb_cProcessStatus);
632 data->status = status;
635 rb_obj_freeze(last_status);
640process_status_dump(VALUE status)
642 VALUE dump = rb_class_new_instance(0, 0, rb_cObject);
652process_status_load(VALUE real_obj, VALUE load_obj)
654 struct rb_process_status *data = rb_check_typeddata(real_obj, &rb_process_status_type);
665 GET_THREAD()->last_status = rb_process_status_new(pid, status, 0);
669rb_last_status_clear(
void)
671 GET_THREAD()->last_status =
Qnil;
703 int status = pst_status(
self);
707#define PST2INT(st) pst_status(st)
723 rb_pid_t pid = pst_pid(
self);
727static VALUE pst_message_status(VALUE str,
int status);
730pst_message(VALUE str, rb_pid_t pid,
int status)
733 pst_message_status(str, status);
737pst_message_status(VALUE str,
int status)
739 if (WIFSTOPPED(status)) {
740 int stopsig = WSTOPSIG(status);
743 rb_str_catf(str,
" stopped SIG%s (signal %d)", signame, stopsig);
749 if (WIFSIGNALED(status)) {
750 int termsig = WTERMSIG(status);
753 rb_str_catf(str,
" SIG%s (signal %d)", signame, termsig);
759 if (WIFEXITED(status)) {
763 if (WCOREDUMP(status)) {
790 status = PST2INT(st);
793 pst_message(str, pid, status);
820 status = PST2INT(st);
823 pst_message(str, pid, status);
838pst_equal(VALUE st1, VALUE st2)
840 if (st1 == st2)
return Qtrue;
841 return rb_equal(pst_to_i(st1), st2);
858pst_bitand(VALUE st1, VALUE st2)
860 int status = PST2INT(st1) &
NUM2INT(st2);
879pst_rshift(VALUE st1, VALUE st2)
881 int status = PST2INT(st1) >>
NUM2INT(st2);
897pst_wifstopped(VALUE st)
899 int status = PST2INT(st);
901 return RBOOL(WIFSTOPPED(status));
914pst_wstopsig(VALUE st)
916 int status = PST2INT(st);
918 if (WIFSTOPPED(status))
919 return INT2NUM(WSTOPSIG(status));
933pst_wifsignaled(VALUE st)
935 int status = PST2INT(st);
937 return RBOOL(WIFSIGNALED(status));
951pst_wtermsig(VALUE st)
953 int status = PST2INT(st);
955 if (WIFSIGNALED(status))
956 return INT2NUM(WTERMSIG(status));
971pst_wifexited(VALUE st)
973 int status = PST2INT(st);
975 return RBOOL(WIFEXITED(status));
998pst_wexitstatus(VALUE st)
1000 int status = PST2INT(st);
1002 if (WIFEXITED(status))
1003 return INT2NUM(WEXITSTATUS(status));
1017pst_success_p(VALUE st)
1019 int status = PST2INT(st);
1021 if (!WIFEXITED(status))
1023 return RBOOL(WEXITSTATUS(status) == EXIT_SUCCESS);
1036pst_wcoredump(VALUE st)
1039 int status = PST2INT(st);
1041 return RBOOL(WCOREDUMP(status));
1048do_waitpid(rb_pid_t pid,
int *st,
int flags)
1050#if defined HAVE_WAITPID
1051 return waitpid(pid, st, flags);
1052#elif defined HAVE_WAIT4
1053 return wait4(pid, st, flags, NULL);
1055# error waitpid or wait4 is required.
1059#define WAITPID_LOCK_ONLY ((struct waitpid_state *)-1)
1073void rb_sigwait_sleep(
const rb_thread_t *,
int fd,
const rb_hrtime_t *);
1074void rb_sigwait_fd_put(
const rb_thread_t *,
int fd);
1075void rb_thread_sleep_interruptible(
void);
1081 rb_threadptr_interrupt(rb_ec_thread_ptr(w->ec));
1099sigwait_fd_migrate_sleeper(
rb_vm_t *vm)
1103 list_for_each(&vm->waiting_pids, w, wnode) {
1104 if (waitpid_signal(w))
return;
1106 list_for_each(&vm->waiting_grps, w, wnode) {
1107 if (waitpid_signal(w))
return;
1112rb_sigwait_fd_migrate(
rb_vm_t *vm)
1115 sigwait_fd_migrate_sleeper(vm);
1120extern volatile unsigned int ruby_nocldwait;
1127 list_for_each_safe(head, w, next, wnode) {
1128 rb_pid_t ret = do_waitpid(w->pid, &w->status, w->options | WNOHANG);
1131 if (ret == -1) w->errnum = errno;
1134 list_del_init(&w->wnode);
1139# define ruby_nocldwait 0
1147 waitpid_each(&vm->waiting_pids);
1148 if (list_empty(&vm->waiting_pids)) {
1149 waitpid_each(&vm->waiting_grps);
1152 if (list_empty(&vm->waiting_pids) && list_empty(&vm->waiting_grps)) {
1153 while (ruby_nocldwait && do_waitpid(-1, 0, WNOHANG) > 0)
1161waitpid_state_init(
struct waitpid_state *w, rb_pid_t pid,
int options)
1165 w->options = options;
1170static const rb_hrtime_t *
1171sigwait_sleep_time(
void)
1173 if (SIGCHLD_LOSSY) {
1174 static const rb_hrtime_t busy_wait = 100 * RB_HRTIME_PER_MSEC;
1185ruby_waitpid_locked(
rb_vm_t *vm, rb_pid_t pid,
int *status,
int options,
1190 assert(!ruby_thread_has_gvl_p() &&
"must not have GVL");
1192 waitpid_state_init(&w, pid, options);
1193 if (w.pid > 0 || list_empty(&vm->waiting_pids))
1194 w.ret = do_waitpid(w.pid, &w.status, w.options | WNOHANG);
1196 if (w.ret == -1) w.errnum = errno;
1199 int sigwait_fd = -1;
1202 list_add(w.pid > 0 ? &vm->waiting_pids : &vm->waiting_grps, &w.wnode);
1205 sigwait_fd = rb_sigwait_fd_get(0);
1207 if (sigwait_fd >= 0) {
1210 rb_sigwait_sleep(0, sigwait_fd, sigwait_sleep_time());
1221 if (sigwait_fd >= 0) {
1222 rb_sigwait_fd_put(0, sigwait_fd);
1223 sigwait_fd_migrate_sleeper(vm);
1229 if (w.ret == -1) errno = w.errnum;
1234waitpid_sleep(VALUE x)
1239 rb_thread_sleep_interruptible();
1246waitpid_cleanup(VALUE x)
1254 if (TRUE || w->ret == 0) {
1255 rb_vm_t *vm = rb_ec_vm_ptr(w->ec);
1258 list_del(&w->wnode);
1268 rb_vm_t *vm = rb_ec_vm_ptr(w->ec);
1269 int need_sleep = FALSE;
1278 if (w->pid > 0 || list_empty(&vm->waiting_pids)) {
1279 w->ret = do_waitpid(w->pid, &w->status, w->options | WNOHANG);
1283 if (w->ret == -1) w->errnum = errno;
1285 else if (w->options & WNOHANG) {
1294 list_add(w->pid > 0 ? &vm->waiting_pids : &vm->waiting_grps, &w->wnode);
1300 rb_ensure(waitpid_sleep, (VALUE)w, waitpid_cleanup, (VALUE)w);
1305waitpid_blocking_no_SIGCHLD(
void *x)
1309 w->ret = do_waitpid(w->pid, &w->status, w->options);
1317 if (w->options & WNOHANG) {
1318 w->ret = do_waitpid(w->pid, &w->status, w->options);
1324 }
while (w->ret < 0 && errno == EINTR && (RUBY_VM_CHECK_INTS(w->ec),1));
1331rb_process_status_wait(rb_pid_t pid,
int flags)
1334 if (!(flags & WNOHANG)) {
1337 if (result !=
Qundef)
return result;
1345 if (WAITPID_USE_SIGCHLD) {
1407rb_process_status_waitv(
int argc, VALUE *argv, VALUE
_)
1422 return rb_process_status_wait(pid, flags);
1428 VALUE status = rb_process_status_wait(pid, flags);
1429 if (
NIL_P(status))
return 0;
1434 if (st) *st = data->status;
1437 errno = data->error;
1440 GET_THREAD()->last_status = status;
1447proc_wait(
int argc, VALUE *argv)
1459 if (argc == 2 && !
NIL_P(vflags = argv[1])) {
1464 if ((pid =
rb_waitpid(pid, &status, flags)) < 0)
1468 rb_last_status_clear();
1534proc_m_wait(
int c, VALUE *v, VALUE
_)
1536 return proc_wait(c, v);
1557proc_wait2(
int argc, VALUE *argv, VALUE
_)
1559 VALUE pid = proc_wait(argc, argv);
1586proc_waitall(VALUE
_)
1593 rb_last_status_clear();
1608static VALUE rb_cWaiter;
1611detach_process_pid(VALUE thread)
1617detach_process_watcher(
void *arg)
1619 rb_pid_t cpid, pid = (rb_pid_t)(VALUE)arg;
1622 while ((cpid =
rb_waitpid(pid, &status, 0)) == 0) {
1631 VALUE watcher =
rb_thread_create(detach_process_watcher, (
void*)(VALUE)pid);
1633 RBASIC_SET_CLASS(watcher, rb_cWaiter);
1685proc_detach(VALUE obj, VALUE pid)
1692before_exec_async_signal_safe(
void)
1697before_exec_non_async_signal_safe(
void)
1708 rb_thread_stop_timer_thread();
1711#define WRITE_CONST(fd, str) (void)(write((fd),(str),sizeof(str)-1)<0)
1713int rb_w32_set_nonblock2(
int fd,
int nonblock);
1720 return rb_w32_set_nonblock2(fd, 0);
1721#elif defined(F_GETFL) && defined(F_SETFL)
1722 int fl = fcntl(fd, F_GETFL);
1725 if (fl == -1)
return fl;
1726 if (fl & O_NONBLOCK) {
1728 return fcntl(fd, F_SETFL, fl);
1735stdfd_clear_nonblock(
void)
1739 for (fd = 0; fd < 3; fd++) {
1740 (void)set_blocking(fd);
1747 before_exec_non_async_signal_safe();
1748 before_exec_async_signal_safe();
1753after_exec_async_signal_safe(
void)
1758after_exec_non_async_signal_safe(
void)
1760 rb_thread_reset_timer_thread();
1761 rb_thread_start_timer_thread();
1767 after_exec_async_signal_safe();
1768 after_exec_non_async_signal_safe();
1771#if defined HAVE_WORKING_FORK || defined HAVE_DAEMON
1773before_fork_ruby(
void)
1779after_fork_ruby(
void)
1781 rb_threadptr_pending_interrupt_clear(GET_THREAD());
1786#if defined(HAVE_WORKING_FORK)
1789#define try_with_sh(err, prog, argv, envp) ((err == ENOEXEC) ? exec_with_sh((prog), (argv), (envp)) : (void)0)
1791exec_with_sh(
const char *prog,
char **argv,
char **envp)
1793 *argv = (
char *)prog;
1794 *--argv = (
char *)
"sh";
1796 execve(
"/bin/sh", argv, envp);
1798 execv(
"/bin/sh", argv);
1802#define try_with_sh(err, prog, argv, envp) (void)0
1807proc_exec_cmd(
const char *prog, VALUE argv_str, VALUE envp_str)
1815 argv = ARGVSTR2ARGV(argv_str);
1822 rb_w32_uaspawn(P_OVERLAY, prog, argv);
1825 envp = envp_str ? RB_IMEMO_TMPBUF_PTR(envp_str) : NULL;
1827 execve(prog, argv, envp);
1831 try_with_sh(err, prog, argv, envp);
1838proc_exec_sh(
const char *str, VALUE envp_str)
1843 while (*s ==
' ' || *s ==
'\t' || *s ==
'\n')
1851 rb_w32_uspawn(P_OVERLAY, (
char *)str, 0);
1852#elif defined(__CYGWIN32__)
1854 char fbuf[MAXPATHLEN];
1855 char *shell = dln_find_exe_r(
"sh", 0, fbuf,
sizeof(fbuf));
1858 execl(shell,
"sh",
"-c", str, (
char *) NULL);
1860 status = system(str);
1866 execle(
"/bin/sh",
"sh",
"-c", str, (
char *)NULL, RB_IMEMO_TMPBUF_PTR(envp_str));
1868 execl(
"/bin/sh",
"sh",
"-c", str, (
char *)NULL);
1878 ret = proc_exec_sh(str,
Qfalse);
1885mark_exec_arg(
void *ptr)
1888 if (eargp->use_shell)
1892 rb_gc_mark(eargp->invoke.cmd.command_abspath);
1911memsize_exec_arg(
const void *ptr)
1919 0, 0, RUBY_TYPED_FREE_IMMEDIATELY
1923# define DEFAULT_PROCESS_ENCODING rb_utf8_encoding()
1925#ifdef DEFAULT_PROCESS_ENCODING
1926# define EXPORT_STR(str) rb_str_export_to_enc((str), DEFAULT_PROCESS_ENCODING)
1927# define EXPORT_DUP(str) export_dup(str)
1929export_dup(VALUE str)
1931 VALUE newstr = EXPORT_STR(str);
1936# define EXPORT_STR(str) (str)
1937# define EXPORT_DUP(str) rb_str_dup(str)
1940#if !defined(HAVE_WORKING_FORK) && defined(HAVE_SPAWNV)
1941# define USE_SPAWNV 1
1943# define USE_SPAWNV 0
1946# define P_NOWAIT _P_NOWAIT
1951#define proc_spawn_cmd_internal(argv, prog) rb_w32_uaspawn(P_NOWAIT, (prog), (argv))
1954proc_spawn_cmd_internal(
char **argv,
char *prog)
1956 char fbuf[MAXPATHLEN];
1961 prog = dln_find_exe_r(prog, 0, fbuf,
sizeof(fbuf));
1966 status = spawnv(P_NOWAIT, prog, (
const char **)argv);
1967 if (status == -1 && errno == ENOEXEC) {
1968 *argv = (
char *)prog;
1969 *--argv = (
char *)
"sh";
1970 status = spawnv(P_NOWAIT,
"/bin/sh", (
const char **)argv);
1972 if (status == -1) errno = ENOEXEC;
1979proc_spawn_cmd(
char **argv, VALUE prog,
struct rb_execarg *eargp)
1986 if (eargp->new_pgroup_given && eargp->new_pgroup_flag) {
1987 flags = CREATE_NEW_PROCESS_GROUP;
1989 pid = rb_w32_uaspawn_flags(P_NOWAIT, prog ?
RSTRING_PTR(prog) : 0, argv, flags);
1991 pid = proc_spawn_cmd_internal(argv, prog ?
RSTRING_PTR(prog) : 0);
1998#define proc_spawn_sh(str) rb_w32_uspawn(P_NOWAIT, (str), 0)
2001proc_spawn_sh(
char *str)
2003 char fbuf[MAXPATHLEN];
2006 char *shell = dln_find_exe_r(
"sh", 0, fbuf,
sizeof(fbuf));
2008 status = spawnl(P_NOWAIT, (shell ? shell :
"/bin/sh"),
"sh",
"-c", str, (
char*)NULL);
2018 RBASIC_CLEAR_CLASS(obj);
2023check_exec_redirect_fd(VALUE v,
int iskey)
2034 else if (
id == id_out)
2036 else if (
id == id_err)
2045 rb_raise(rb_eArgError,
"duplex IO redirection");
2052 rb_raise(rb_eArgError,
"negative file descriptor");
2055 else if (fd >= 3 && iskey) {
2056 rb_raise(rb_eArgError,
"wrong file descriptor (%d)", fd);
2062 rb_raise(rb_eArgError,
"wrong exec redirect");
2067check_exec_redirect1(VALUE ary, VALUE key, VALUE param)
2073 VALUE fd = check_exec_redirect_fd(key, !
NIL_P(param));
2080 VALUE fd = check_exec_redirect_fd(v, !
NIL_P(param));
2088check_exec_redirect(VALUE key, VALUE val,
struct rb_execarg *eargp)
2091 VALUE path, flags, perm;
2095 switch (
TYPE(val)) {
2098 if (
id == id_close) {
2100 eargp->fd_close = check_exec_redirect1(eargp->fd_close, key, param);
2102 else if (
id == id_in) {
2104 eargp->fd_dup2 = check_exec_redirect1(eargp->fd_dup2, key, param);
2106 else if (
id == id_out) {
2108 eargp->fd_dup2 = check_exec_redirect1(eargp->fd_dup2, key, param);
2110 else if (
id == id_err) {
2112 eargp->fd_dup2 = check_exec_redirect1(eargp->fd_dup2, key, param);
2115 rb_raise(rb_eArgError,
"wrong exec redirect symbol: %"PRIsVALUE,
2122 val = check_exec_redirect_fd(val, 0);
2126 eargp->fd_dup2 = check_exec_redirect1(eargp->fd_dup2, key, param);
2132 path ==
ID2SYM(id_child)) {
2133 param = check_exec_redirect_fd(
rb_ary_entry(val, 1), 0);
2134 eargp->fd_dup2_child = check_exec_redirect1(eargp->fd_dup2_child, key, param);
2144 flags = rb_to_int(flags);
2147 param = hide_obj(
rb_ary_new3(4, hide_obj(EXPORT_DUP(path)),
2148 flags, perm,
Qnil));
2149 eargp->fd_open = check_exec_redirect1(eargp->fd_open, key, param);
2157 key = check_exec_redirect_fd(key, 1);
2159 flags =
INT2NUM(O_WRONLY|O_CREAT|O_TRUNC);
2164 VALUE fd = check_exec_redirect_fd(v, 1);
2168 flags =
INT2NUM(O_WRONLY|O_CREAT|O_TRUNC);
2175 param = hide_obj(
rb_ary_new3(4, hide_obj(EXPORT_DUP(path)),
2176 flags, perm,
Qnil));
2177 eargp->fd_open = check_exec_redirect1(eargp->fd_open, key, param);
2183 if (!
NIL_P(val))
goto io;
2184 rb_raise(rb_eArgError,
"wrong exec redirect action");
2189#if defined(HAVE_SETRLIMIT) && defined(NUM2RLIM)
2190static int rlimit_type_by_sym(VALUE key);
2193rb_execarg_addopt_rlimit(
struct rb_execarg *eargp,
int rtype, VALUE val)
2195 VALUE ary = eargp->rlimit_limits;
2196 VALUE tmp, softlim, hardlim;
2197 if (eargp->rlimit_limits ==
Qfalse)
2198 ary = eargp->rlimit_limits = hide_obj(
rb_ary_new());
2200 ary = eargp->rlimit_limits;
2210 rb_raise(rb_eArgError,
"wrong exec rlimit option");
2214 softlim = hardlim = rb_to_int(val);
2221#define TO_BOOL(val, name) NIL_P(val) ? 0 : rb_bool_expected((val), name)
2223rb_execarg_addopt(VALUE execarg_obj, VALUE key, VALUE val)
2225 struct rb_execarg *eargp = rb_execarg_get(execarg_obj);
2229 switch (
TYPE(key)) {
2231#if defined(HAVE_SETRLIMIT) && defined(NUM2RLIM)
2233 int rtype = rlimit_type_by_sym(key);
2235 rb_execarg_addopt_rlimit(eargp, rtype, val);
2243 if (
id == id_pgroup) {
2245 if (eargp->pgroup_given) {
2246 rb_raise(rb_eArgError,
"pgroup option specified twice");
2250 else if (val ==
Qtrue)
2255 rb_raise(rb_eArgError,
"negative process group ID : %ld", (
long)pgroup);
2258 eargp->pgroup_given = 1;
2259 eargp->pgroup_pgid = pgroup;
2264 if (
id == id_new_pgroup) {
2265 if (eargp->new_pgroup_given) {
2266 rb_raise(rb_eArgError,
"new_pgroup option specified twice");
2268 eargp->new_pgroup_given = 1;
2269 eargp->new_pgroup_flag = TO_BOOL(val,
"new_pgroup");
2273 if (
id == id_unsetenv_others) {
2274 if (eargp->unsetenv_others_given) {
2275 rb_raise(rb_eArgError,
"unsetenv_others option specified twice");
2277 eargp->unsetenv_others_given = 1;
2278 eargp->unsetenv_others_do = TO_BOOL(val,
"unsetenv_others");
2280 else if (
id == id_chdir) {
2281 if (eargp->chdir_given) {
2282 rb_raise(rb_eArgError,
"chdir option specified twice");
2286 eargp->chdir_given = 1;
2287 eargp->chdir_dir = hide_obj(EXPORT_DUP(val));
2289 else if (
id == id_umask) {
2291 if (eargp->umask_given) {
2292 rb_raise(rb_eArgError,
"umask option specified twice");
2294 eargp->umask_given = 1;
2295 eargp->umask_mask = cmask;
2297 else if (
id == id_close_others) {
2298 if (eargp->close_others_given) {
2299 rb_raise(rb_eArgError,
"close_others option specified twice");
2301 eargp->close_others_given = 1;
2302 eargp->close_others_do = TO_BOOL(val,
"close_others");
2304 else if (
id == id_in) {
2308 else if (
id == id_out) {
2312 else if (
id == id_err) {
2316 else if (
id == id_uid) {
2318 if (eargp->uid_given) {
2319 rb_raise(rb_eArgError,
"uid option specified twice");
2323 eargp->uid = OBJ2UID(val);
2324 eargp->uid_given = 1;
2328 "uid option is unimplemented on this machine");
2331 else if (
id == id_gid) {
2333 if (eargp->gid_given) {
2334 rb_raise(rb_eArgError,
"gid option specified twice");
2338 eargp->gid = OBJ2GID(val);
2339 eargp->gid_given = 1;
2343 "gid option is unimplemented on this machine");
2346 else if (
id == id_exception) {
2347 if (eargp->exception_given) {
2348 rb_raise(rb_eArgError,
"exception option specified twice");
2350 eargp->exception_given = 1;
2351 eargp->exception = TO_BOOL(val,
"exception");
2362 check_exec_redirect(key, val, eargp);
2374check_exec_options_i(st_data_t st_key, st_data_t st_val, st_data_t arg)
2376 VALUE key = (
VALUE)st_key;
2377 VALUE val = (
VALUE)st_val;
2378 VALUE execarg_obj = (
VALUE)arg;
2379 if (rb_execarg_addopt(execarg_obj, key, val) != ST_CONTINUE) {
2381 rb_raise(rb_eArgError,
"wrong exec option symbol: % "PRIsVALUE,
2383 rb_raise(rb_eArgError,
"wrong exec option");
2389check_exec_options_i_extract(st_data_t st_key, st_data_t st_val, st_data_t arg)
2391 VALUE key = (
VALUE)st_key;
2392 VALUE val = (
VALUE)st_val;
2393 VALUE *args = (VALUE *)arg;
2394 VALUE execarg_obj = args[0];
2395 if (rb_execarg_addopt(execarg_obj, key, val) != ST_CONTINUE) {
2396 VALUE nonopts = args[1];
2404check_exec_fds_1(
struct rb_execarg *eargp, VALUE h,
int maxhint, VALUE ary)
2413 rb_raise(rb_eArgError,
"fd %d specified twice", fd);
2415 if (ary == eargp->fd_dup2)
2417 else if (ary == eargp->fd_dup2_child)
2423 if (ary == eargp->fd_dup2 || ary == eargp->fd_dup2_child) {
2441 maxhint = check_exec_fds_1(eargp, h, maxhint, eargp->fd_dup2);
2442 maxhint = check_exec_fds_1(eargp, h, maxhint, eargp->fd_close);
2443 maxhint = check_exec_fds_1(eargp, h, maxhint, eargp->fd_dup2_child);
2445 if (eargp->fd_dup2_child) {
2446 ary = eargp->fd_dup2_child;
2458 rb_raise(rb_eArgError,
"cyclic child fd redirection from %d", oldfd);
2462 rb_raise(rb_eArgError,
"child fd %d is not redirected", oldfd);
2463 if (oldfd != lastfd) {
2476 eargp->close_others_maxhint = maxhint;
2481rb_check_exec_options(VALUE opthash, VALUE execarg_obj)
2485 rb_hash_stlike_foreach(opthash, check_exec_options_i, (st_data_t)execarg_obj);
2489rb_execarg_extract_options(VALUE execarg_obj, VALUE opthash)
2494 args[0] = execarg_obj;
2496 rb_hash_stlike_foreach(opthash, check_exec_options_i_extract, (st_data_t)args);
2500#ifdef ENV_IGNORECASE
2501#define ENVMATCH(s1, s2) (STRCASECMP((s1), (s2)) == 0)
2503#define ENVMATCH(n1, n2) (strcmp((n1), (n2)) == 0)
2507check_exec_env_i(st_data_t st_key, st_data_t st_val, st_data_t arg)
2509 VALUE key = (
VALUE)st_key;
2510 VALUE val = (
VALUE)st_val;
2511 VALUE env = ((VALUE *)arg)[0];
2512 VALUE *path = &((VALUE *)arg)[1];
2517 rb_raise(rb_eArgError,
"environment name contains a equal : %"PRIsVALUE, key);
2522 key = EXPORT_STR(key);
2523 if (!
NIL_P(val)) val = EXPORT_STR(val);
2534rb_check_exec_env(VALUE hash, VALUE *path)
2540 rb_hash_stlike_foreach(hash, check_exec_env_i, (st_data_t)env);
2547rb_check_argv(
int argc, VALUE *argv)
2558 rb_raise(rb_eArgError,
"wrong first argument");
2566 for (i = 0; i < argc; i++) {
2575check_hash(VALUE obj)
2589rb_exec_getargs(
int *argc_p, VALUE **argv_p,
int accept_shell, VALUE *env_ret, VALUE *opthash_ret)
2594 hash = check_hash((*argv_p)[*argc_p-1]);
2596 *opthash_ret = hash;
2602 hash = check_hash((*argv_p)[0]);
2609 prog = rb_check_argv(*argc_p, *argv_p);
2611 prog = (*argv_p)[0];
2612 if (accept_shell && *argc_p == 1) {
2627compare_posix_sh(
const void *key,
const void *el)
2630 int ret = strncmp(word->ptr, el, word->len);
2631 if (!ret && ((
const char *)el)[word->len]) ret = -1;
2637rb_exec_fillarg(VALUE prog,
int argc, VALUE *argv, VALUE env, VALUE opthash, VALUE execarg_obj)
2639 struct rb_execarg *eargp = rb_execarg_get(execarg_obj);
2640 char fbuf[MAXPATHLEN];
2644 if (!
NIL_P(opthash)) {
2645 rb_check_exec_options(opthash, execarg_obj);
2648 env = rb_check_exec_env(env, &eargp->path_env);
2649 eargp->env_modification = env;
2652 prog = EXPORT_STR(prog);
2653 eargp->use_shell = argc == 0;
2654 if (eargp->use_shell)
2655 eargp->invoke.sh.shell_script = prog;
2657 eargp->invoke.cmd.command_name = prog;
2660 if (eargp->use_shell) {
2661 static const char posix_sh_cmds[][9] = {
2720 if (*p ==
' ' || *p ==
'\t') {
2721 if (first.ptr && !first.len) first.len = p - first.ptr;
2724 if (!first.ptr) first.ptr = p;
2726 if (!has_meta && strchr(
"*?{}[]<>()~&|\\$;'`\"\n#", *p))
2732 else if (*p ==
'/') {
2739 if (!has_meta && first.ptr) {
2740 if (!first.len) first.len = p - first.ptr;
2741 if (first.len > 0 && first.len <=
sizeof(posix_sh_cmds[0]) &&
2742 bsearch(&first, posix_sh_cmds, numberof(posix_sh_cmds),
sizeof(posix_sh_cmds[0]), compare_posix_sh))
2747 eargp->use_shell = 0;
2749 if (!eargp->use_shell) {
2754 while (*p ==
' ' || *p ==
'\t')
2758 while (*p && *p !=
' ' && *p !=
'\t')
2764 eargp->invoke.cmd.argv_buf = argv_buf;
2765 eargp->invoke.cmd.command_name =
2767 rb_enc_copy(eargp->invoke.cmd.command_name, prog);
2772 if (!eargp->use_shell) {
2773 const char *abspath;
2774 const char *path_env = 0;
2776 abspath = dln_find_exe_r(
RSTRING_PTR(eargp->invoke.cmd.command_name),
2777 path_env, fbuf,
sizeof(fbuf));
2781 eargp->invoke.cmd.command_abspath =
Qnil;
2784 if (!eargp->use_shell && !eargp->invoke.cmd.argv_buf) {
2789 for (i = 0; i < argc; i++) {
2790 VALUE arg = argv[i];
2792#ifdef DEFAULT_PROCESS_ENCODING
2793 arg = EXPORT_STR(arg);
2798 eargp->invoke.cmd.argv_buf = argv_buf;
2801 if (!eargp->use_shell) {
2802 const char *p, *ep, *
null=NULL;
2813 eargp->invoke.cmd.argv_str =
2814 rb_imemo_tmpbuf_auto_free_pointer_new_from_an_RString(argv_str);
2820rb_execarg_get(VALUE execarg_obj)
2828rb_execarg_init(
int argc,
const VALUE *orig_argv,
int accept_shell, VALUE execarg_obj)
2830 struct rb_execarg *eargp = rb_execarg_get(execarg_obj);
2834 VALUE *argv =
ALLOCV_N(VALUE, argv_buf, argc);
2835 MEMCPY(argv, orig_argv, VALUE, argc);
2836 prog = rb_exec_getargs(&argc, &argv, accept_shell, &env, &opthash);
2837 rb_exec_fillarg(prog, argc, argv, env, opthash, execarg_obj);
2839 ret = eargp->use_shell ? eargp->invoke.sh.shell_script : eargp->invoke.cmd.command_name;
2845rb_execarg_new(
int argc,
const VALUE *argv,
int accept_shell,
int allow_exc_opt)
2850 rb_execarg_init(argc, argv, accept_shell, execarg_obj);
2851 if (!allow_exc_opt && eargp->exception_given) {
2852 rb_raise(rb_eArgError,
"exception option is not allowed");
2858rb_execarg_setenv(VALUE execarg_obj, VALUE env)
2860 struct rb_execarg *eargp = rb_execarg_get(execarg_obj);
2861 env = !
NIL_P(env) ? rb_check_exec_env(env, &eargp->path_env) :
Qfalse;
2862 eargp->env_modification = env;
2866fill_envp_buf_i(st_data_t st_key, st_data_t st_val, st_data_t arg)
2868 VALUE key = (
VALUE)st_key;
2869 VALUE val = (
VALUE)st_val;
2870 VALUE envp_buf = (
VALUE)arg;
2881static long run_exec_dup2_tmpbuf_size(
long n);
2896 data->ret = parent_redirect_open(fname, data->oflags, data->perm);
2902rb_execarg_allocate_dup2_tmpbuf(
struct rb_execarg *eargp,
long len)
2904 VALUE tmpbuf = rb_imemo_tmpbuf_auto_free_pointer();
2905 rb_imemo_tmpbuf_set_ptr(tmpbuf,
ruby_xmalloc(run_exec_dup2_tmpbuf_size(len)));
2906 eargp->dup2_tmpbuf = tmpbuf;
2910rb_execarg_parent_start1(VALUE execarg_obj)
2912 struct rb_execarg *eargp = rb_execarg_get(execarg_obj);
2913 int unsetenv_others;
2917 ary = eargp->fd_open;
2932 open_data.fname = vpath;
2933 open_data.oflags = flags;
2934 open_data.perm = perm;
2936 open_data.err = EINTR;
2938 if (open_data.ret == -1) {
2939 if (open_data.err == EINTR) {
2945 fd2 = open_data.ret;
2957 eargp->redirect_fds = check_exec_fds(eargp);
2959 ary = eargp->fd_dup2;
2961 rb_execarg_allocate_dup2_tmpbuf(eargp,
RARRAY_LEN(ary));
2964 unsetenv_others = eargp->unsetenv_others_given && eargp->unsetenv_others_do;
2965 envopts = eargp->env_modification;
2966 if (ALWAYS_NEED_ENVP || unsetenv_others || envopts !=
Qfalse) {
2967 VALUE envtbl, envp_str, envp_buf;
2969 if (unsetenv_others) {
2973 envtbl = rb_env_to_hash();
2977 st_table *stenv = RHASH_TBL_RAW(envtbl);
2984 st_data_t stkey = (st_data_t)key;
2985 st_delete(stenv, &stkey, NULL);
2988 st_insert(stenv, (st_data_t)key, (st_data_t)val);
2996 rb_hash_stlike_foreach(envtbl, fill_envp_buf_i, (st_data_t)envp_buf);
3008 rb_imemo_tmpbuf_auto_free_pointer_new_from_an_RString(envp_str);
3009 eargp->envp_buf = envp_buf;
3025rb_execarg_parent_start(VALUE execarg_obj)
3028 rb_protect(rb_execarg_parent_start1, execarg_obj, &state);
3030 rb_execarg_parent_end(execarg_obj);
3036execarg_parent_end(VALUE execarg_obj)
3038 struct rb_execarg *eargp = rb_execarg_get(execarg_obj);
3042 ary = eargp->fd_open;
3053 parent_redirect_close(fd2);
3064rb_execarg_parent_end(VALUE execarg_obj)
3066 execarg_parent_end(execarg_obj);
3071rb_exec_fail(
struct rb_execarg *eargp,
int err,
const char *errmsg)
3073 if (!errmsg || !*errmsg)
return;
3074 if (strcmp(errmsg,
"chdir") == 0) {
3082rb_execarg_fail(VALUE execarg_obj,
int err,
const char *errmsg)
3084 if (!errmsg || !*errmsg)
return;
3085 rb_exec_fail(rb_execarg_get(execarg_obj), err, errmsg);
3093 VALUE execarg_obj, fail_str;
3095#define CHILD_ERRMSG_BUFLEN 80
3096 char errmsg[CHILD_ERRMSG_BUFLEN] = {
'\0' };
3099 execarg_obj = rb_execarg_new(argc, argv, TRUE, FALSE);
3100 eargp = rb_execarg_get(execarg_obj);
3101 if (mjit_enabled) mjit_finish(
false);
3104 rb_protect(rb_execarg_parent_start1, execarg_obj, &state);
3106 execarg_parent_end(execarg_obj);
3111 fail_str = eargp->use_shell ? eargp->invoke.sh.shell_script : eargp->invoke.cmd.command_name;
3113 err = exec_async_signal_safe(eargp, errmsg,
sizeof(errmsg));
3116 rb_exec_fail(eargp, err, errmsg);
3122NORETURN(
static VALUE f_exec(
int c,
const VALUE *a, VALUE
_));
3199f_exec(
int c,
const VALUE *a, VALUE
_)
3205#define ERRMSG(str) do { if (errmsg && 0 < errmsg_buflen) strlcpy(errmsg, (str), errmsg_buflen); } while (0)
3206#define ERRMSG1(str, a) do { if (errmsg && 0 < errmsg_buflen) snprintf(errmsg, errmsg_buflen, (str), (a)); } while (0)
3207#define ERRMSG2(str, a, b) do { if (errmsg && 0 < errmsg_buflen) snprintf(errmsg, errmsg_buflen, (str), (a), (b)); } while (0)
3209static int fd_get_cloexec(
int fd,
char *errmsg,
size_t errmsg_buflen);
3210static int fd_set_cloexec(
int fd,
char *errmsg,
size_t errmsg_buflen);
3211static int fd_clear_cloexec(
int fd,
char *errmsg,
size_t errmsg_buflen);
3214save_redirect_fd(
int fd,
struct rb_execarg *sargp,
char *errmsg,
size_t errmsg_buflen)
3217 VALUE newary, redirection;
3218 int save_fd = redirect_cloexec_dup(fd), cloexec;
3219 if (save_fd == -1) {
3226 newary = sargp->fd_dup2;
3229 sargp->fd_dup2 = newary;
3231 cloexec = fd_get_cloexec(fd, errmsg, errmsg_buflen);
3236 newary = sargp->fd_close;
3239 sargp->fd_close = newary;
3248intcmp(
const void *a,
const void *b)
3250 return *(
int*)a - *(
int*)b;
3254intrcmp(
const void *a,
const void *b)
3256 return *(
int*)b - *(
int*)a;
3268run_exec_dup2_tmpbuf_size(
long n)
3275fd_get_cloexec(
int fd,
char *errmsg,
size_t errmsg_buflen)
3279 ret = fcntl(fd, F_GETFD);
3281 ERRMSG(
"fcntl(F_GETFD)");
3284 if (ret & FD_CLOEXEC)
return 1;
3291fd_set_cloexec(
int fd,
char *errmsg,
size_t errmsg_buflen)
3295 ret = fcntl(fd, F_GETFD);
3297 ERRMSG(
"fcntl(F_GETFD)");
3300 if (!(ret & FD_CLOEXEC)) {
3302 ret = fcntl(fd, F_SETFD, ret);
3304 ERRMSG(
"fcntl(F_SETFD)");
3314fd_clear_cloexec(
int fd,
char *errmsg,
size_t errmsg_buflen)
3318 ret = fcntl(fd, F_GETFD);
3320 ERRMSG(
"fcntl(F_GETFD)");
3323 if (ret & FD_CLOEXEC) {
3325 ret = fcntl(fd, F_SETFD, ret);
3327 ERRMSG(
"fcntl(F_SETFD)");
3337run_exec_dup2(VALUE ary, VALUE tmpbuf,
struct rb_execarg *sargp,
char *errmsg,
size_t errmsg_buflen)
3348 for (i = 0; i < n; i++) {
3353 pairs[i].older_index = -1;
3363 for (i = 0; i < n; i++) {
3364 int newfd = pairs[i].newfd;
3368 pairs[i].num_newer = 0;
3370 while (pairs < found && (found-1)->oldfd == newfd)
3372 while (found < pairs+n && found->oldfd == newfd) {
3373 pairs[i].num_newer++;
3374 found->older_index = i;
3381 for (i = 0; i < n; i++) {
3383 while (j != -1 && pairs[j].oldfd != -1 && pairs[j].num_newer == 0) {
3384 if (save_redirect_fd(pairs[j].newfd, sargp, errmsg, errmsg_buflen) < 0)
3386 ret = redirect_dup2(pairs[j].oldfd, pairs[j].newfd);
3391 if (pairs[j].cloexec &&
3392 fd_set_cloexec(pairs[j].newfd, errmsg, errmsg_buflen)) {
3396 pairs[j].oldfd = -1;
3397 j = pairs[j].older_index;
3399 pairs[j].num_newer--;
3404 for (i = 0; i < n; i++) {
3406 if (pairs[i].oldfd == -1)
3408 if (pairs[i].oldfd == pairs[i].newfd) {
3409 if (fd_clear_cloexec(pairs[i].oldfd, errmsg, errmsg_buflen) == -1)
3411 pairs[i].oldfd = -1;
3414 if (extra_fd == -1) {
3415 extra_fd = redirect_dup(pairs[i].oldfd);
3416 if (extra_fd == -1) {
3423 ret = redirect_dup2(pairs[i].oldfd, extra_fd);
3430 pairs[i].oldfd = extra_fd;
3431 j = pairs[i].older_index;
3432 pairs[i].older_index = -1;
3434 ret = redirect_dup2(pairs[j].oldfd, pairs[j].newfd);
3440 pairs[j].oldfd = -1;
3441 j = pairs[j].older_index;
3444 if (extra_fd != -1) {
3445 ret = redirect_close(extra_fd);
3460run_exec_close(VALUE ary,
char *errmsg,
size_t errmsg_buflen)
3468 ret = redirect_close(fd);
3479run_exec_dup2_child(VALUE ary,
struct rb_execarg *sargp,
char *errmsg,
size_t errmsg_buflen)
3489 if (save_redirect_fd(newfd, sargp, errmsg, errmsg_buflen) < 0)
3491 ret = redirect_dup2(oldfd, newfd);
3504run_exec_pgroup(
const struct rb_execarg *eargp,
struct rb_execarg *sargp,
char *errmsg,
size_t errmsg_buflen)
3516 pgroup = eargp->pgroup_pgid;
3522 sargp->pgroup_given = 1;
3523 sargp->pgroup_pgid = getpgrp();
3529 ret = setpgid(getpid(), pgroup);
3530 if (ret == -1) ERRMSG(
"setpgid");
3535#if defined(HAVE_SETRLIMIT) && defined(RLIM2NUM)
3538run_exec_rlimit(VALUE ary,
struct rb_execarg *sargp,
char *errmsg,
size_t errmsg_buflen)
3547 if (getrlimit(rtype, &rlim) == -1) {
3548 ERRMSG(
"getrlimit");
3552 RLIM2NUM(rlim.rlim_cur),
3553 RLIM2NUM(rlim.rlim_max)));
3554 if (sargp->rlimit_limits ==
Qfalse)
3555 newary = sargp->rlimit_limits = hide_obj(
rb_ary_new());
3557 newary = sargp->rlimit_limits;
3562 if (setrlimit(rtype, &rlim) == -1) {
3563 ERRMSG(
"setrlimit");
3571#if !defined(HAVE_WORKING_FORK)
3584 if (sargp->env_modification ==
Qfalse) {
3585 VALUE env = rb_envtbl();
3590 sargp->env_modification = ary;
3592 sargp->unsetenv_others_given = 1;
3593 sargp->unsetenv_others_do = 1;
3600#define chdir(p) rb_w32_uchdir(p)
3605rb_execarg_run_options(
const struct rb_execarg *eargp,
struct rb_execarg *sargp,
char *errmsg,
size_t errmsg_buflen)
3612 sargp->redirect_fds =
Qnil;
3616 if (eargp->pgroup_given) {
3617 if (run_exec_pgroup(eargp, sargp, errmsg, errmsg_buflen) == -1)
3622#if defined(HAVE_SETRLIMIT) && defined(RLIM2NUM)
3623 obj = eargp->rlimit_limits;
3625 if (run_exec_rlimit(obj, sargp, errmsg, errmsg_buflen) == -1)
3630#if !defined(HAVE_WORKING_FORK)
3631 if (eargp->unsetenv_others_given && eargp->unsetenv_others_do) {
3636 obj = eargp->env_modification;
3652 if (eargp->umask_given) {
3653 mode_t mask = eargp->umask_mask;
3654 mode_t oldmask = umask(mask);
3656 sargp->umask_given = 1;
3657 sargp->umask_mask = oldmask;
3661 obj = eargp->fd_dup2;
3663 if (run_exec_dup2(obj, eargp->dup2_tmpbuf, sargp, errmsg, errmsg_buflen) == -1)
3667 obj = eargp->fd_close;
3670 rb_warn(
"cannot close fd before spawn");
3672 if (run_exec_close(obj, errmsg, errmsg_buflen) == -1)
3677#ifdef HAVE_WORKING_FORK
3678 if (eargp->close_others_do) {
3683 obj = eargp->fd_dup2_child;
3685 if (run_exec_dup2_child(obj, sargp, errmsg, errmsg_buflen) == -1)
3689 if (eargp->chdir_given) {
3691 sargp->chdir_given = 1;
3692 sargp->chdir_dir = hide_obj(rb_dir_getwd_ospath());
3701 if (eargp->gid_given) {
3702 if (setgid(eargp->gid) < 0) {
3709 if (eargp->uid_given) {
3710 if (setuid(eargp->uid) < 0) {
3718 VALUE ary = sargp->fd_dup2;
3720 rb_execarg_allocate_dup2_tmpbuf(sargp,
RARRAY_LEN(ary));
3724 int preserve = errno;
3725 stdfd_clear_nonblock();
3734rb_exec_async_signal_safe(
const struct rb_execarg *eargp,
char *errmsg,
size_t errmsg_buflen)
3736 errno = exec_async_signal_safe(eargp, errmsg, errmsg_buflen);
3741exec_async_signal_safe(
const struct rb_execarg *eargp,
char *errmsg,
size_t errmsg_buflen)
3743#if !defined(HAVE_WORKING_FORK)
3744 struct rb_execarg sarg, *
const sargp = &sarg;
3750 if (rb_execarg_run_options(eargp, sargp, errmsg, errmsg_buflen) < 0) {
3754 if (eargp->use_shell) {
3755 err = proc_exec_sh(
RSTRING_PTR(eargp->invoke.sh.shell_script), eargp->envp_str);
3758 char *abspath = NULL;
3759 if (!
NIL_P(eargp->invoke.cmd.command_abspath))
3760 abspath =
RSTRING_PTR(eargp->invoke.cmd.command_abspath);
3761 err = proc_exec_cmd(abspath, eargp->invoke.cmd.argv_str, eargp->envp_str);
3763#if !defined(HAVE_WORKING_FORK)
3764 rb_execarg_run_options(sargp, NULL, errmsg, errmsg_buflen);
3770#ifdef HAVE_WORKING_FORK
3773rb_exec_atfork(
void* arg,
char *errmsg,
size_t errmsg_buflen)
3775 return rb_exec_async_signal_safe(arg, errmsg, errmsg_buflen);
3778#if SIZEOF_INT == SIZEOF_LONG
3779#define proc_syswait (VALUE (*)(VALUE))rb_syswait
3782proc_syswait(VALUE pid)
3790move_fds_to_avoid_crash(
int *fdp,
int n, VALUE fds)
3794 for (i = 0; i < n; i++) {
3813pipe_nocrash(
int filedes[2], VALUE fds)
3821 if (move_fds_to_avoid_crash(filedes, 2, fds) == -1) {
3836rb_thread_sleep_that_takes_VALUE_as_sole_argument(VALUE n)
3843handle_fork_error(
int err,
struct rb_process_status *status,
int *ep,
volatile int *try_gc_p)
3855#if defined(EWOULDBLOCK) && EWOULDBLOCK != EAGAIN
3858 if (!status && !ep) {
3863 rb_protect(rb_thread_sleep_that_takes_VALUE_as_sole_argument,
INT2FIX(1), &state);
3864 if (status) status->status = state;
3865 if (!state)
return 0;
3878#define prefork() ( \
3879 rb_io_flush(rb_stdout), \
3880 rb_io_flush(rb_stderr) \
3910write_retry(
int fd,
const void *buf,
size_t len)
3915 w = write(fd, buf, len);
3916 }
while (w < 0 && errno == EINTR);
3922read_retry(
int fd,
void *buf,
size_t len)
3926 if (set_blocking(fd) != 0) {
3928 rb_async_bug_errno(
"set_blocking failed reading child error", errno);
3933 r = read(fd, buf, len);
3934 }
while (r < 0 && errno == EINTR);
3940send_child_error(
int fd,
char *errmsg,
size_t errmsg_buflen)
3945 if (write_retry(fd, &err,
sizeof(err)) < 0) err = errno;
3946 if (errmsg && 0 < errmsg_buflen) {
3947 errmsg[errmsg_buflen-1] =
'\0';
3948 errmsg_buflen = strlen(errmsg);
3949 if (errmsg_buflen > 0 && write_retry(fd, errmsg, errmsg_buflen) < 0)
3955recv_child_error(
int fd,
int *errp,
char *errmsg,
size_t errmsg_buflen)
3959 if ((size = read_retry(fd, &err,
sizeof(err))) < 0) {
3963 if (size ==
sizeof(err) &&
3964 errmsg && 0 < errmsg_buflen) {
3965 ssize_t ret = read_retry(fd, errmsg, errmsg_buflen-1);
3974#ifdef HAVE_WORKING_VFORK
3975#if !defined(HAVE_GETRESUID) && defined(HAVE_GETUIDX)
3978getresuid(rb_uid_t *ruid, rb_uid_t *euid, rb_uid_t *suid)
3984 ret = getuidx(ID_SAVED);
3985 if (ret == (rb_uid_t)-1)
3990#define HAVE_GETRESUID
3993#if !defined(HAVE_GETRESGID) && defined(HAVE_GETGIDX)
3996getresgid(rb_gid_t *rgid, rb_gid_t *egid, rb_gid_t *sgid)
4002 ret = getgidx(ID_SAVED);
4003 if (ret == (rb_gid_t)-1)
4008#define HAVE_GETRESGID
4026 rb_uid_t ruid, euid;
4027 rb_gid_t rgid, egid;
4029#if defined HAVE_ISSETUGID
4034#ifdef HAVE_GETRESUID
4038 ret = getresuid(&ruid, &euid, &suid);
4049 if (euid == 0 || euid != ruid)
4052#ifdef HAVE_GETRESGID
4056 ret = getresgid(&rgid, &egid, &sgid);
4074struct child_handler_disabler_state
4080disable_child_handler_before_fork(
struct child_handler_disabler_state *old)
4082#ifdef HAVE_PTHREAD_SIGMASK
4086 ret = sigfillset(&all);
4090 ret = pthread_sigmask(SIG_SETMASK, &all, &old->sigmask);
4095# pragma GCC warning "pthread_sigmask on fork is not available. potentially dangerous"
4100disable_child_handler_fork_parent(
struct child_handler_disabler_state *old)
4102#ifdef HAVE_PTHREAD_SIGMASK
4105 ret = pthread_sigmask(SIG_SETMASK, &old->sigmask, NULL);
4110# pragma GCC warning "pthread_sigmask on fork is not available. potentially dangerous"
4116disable_child_handler_fork_child(
struct child_handler_disabler_state *old,
char *errmsg,
size_t errmsg_buflen)
4121 for (sig = 1; sig < NSIG; sig++) {
4122 sig_t handler = signal(sig, SIG_DFL);
4124 if (handler == SIG_ERR && errno == EINVAL) {
4127 if (handler == SIG_ERR) {
4128 ERRMSG(
"signal to obtain old action");
4132 if (sig == SIGPIPE) {
4137 if (handler == SIG_IGN) {
4138 signal(sig, SIG_IGN);
4143 sigemptyset(&old->sigmask);
4144 ret = sigprocmask(SIG_SETMASK, &old->sigmask, NULL);
4146 ERRMSG(
"sigprocmask");
4154 int (*chfunc)(
void*,
char *,
size_t),
void *charg,
4155 char *errmsg,
size_t errmsg_buflen,
4159 volatile int try_gc = 1;
4160 struct child_handler_disabler_state old;
4163 (w && WAITPID_USE_SIGCHLD) ? &GET_VM()->waitpid_lock : 0;
4168 disable_child_handler_before_fork(&old);
4172#ifdef HAVE_WORKING_VFORK
4173 if (!has_privilege())
4183 ret = disable_child_handler_fork_child(&old, errmsg, errmsg_buflen);
4185 ret = chfunc(charg, errmsg, errmsg_buflen);
4186 if (!ret) _exit(EXIT_SUCCESS);
4188 send_child_error(ep[1], errmsg, errmsg_buflen);
4189#if EXIT_SUCCESS == 127
4190 _exit(EXIT_FAILURE);
4196 waitpid_lock = waitpid_lock_init;
4198 if (pid > 0 && w != WAITPID_LOCK_ONLY) {
4200 list_add(&GET_VM()->waiting_pids, &w->wnode);
4204 disable_child_handler_fork_parent(&old);
4208 if (handle_fork_error(err, status, ep, &try_gc))
4214fork_check_err(
struct rb_process_status *status,
int (*chfunc)(
void*,
char *,
size_t),
void *charg,
4215 VALUE fds,
char *errmsg,
size_t errmsg_buflen,
4223 struct waitpid_state *w = eargp && eargp->waitpid_state ? eargp->waitpid_state : 0;
4225 if (status) status->status = 0;
4227 if (pipe_nocrash(ep, fds))
return -1;
4229 pid = retry_fork_async_signal_safe(status, ep, chfunc, charg, errmsg, errmsg_buflen, w);
4231 if (status) status->pid = pid;
4234 if (status) status->error = errno;
4241 error_occurred = recv_child_error(ep[0], &err, errmsg, errmsg_buflen);
4243 if (error_occurred) {
4246 status->error = err;
4248 VM_ASSERT((w == 0 || w == WAITPID_LOCK_ONLY) &&
4249 "only used by extensions");
4250 rb_protect(proc_syswait, (VALUE)pid, &state);
4252 status->status = state;
4254 else if (!w || w == WAITPID_LOCK_ONLY) {
4273rb_fork_async_signal_safe(
int *status,
4274 int (*chfunc)(
void*,
char *,
size_t),
void *charg,
4275 VALUE fds,
char *errmsg,
size_t errmsg_buflen)
4279 rb_pid_t result = fork_check_err(&process_status, chfunc, charg, fds, errmsg, errmsg_buflen, 0);
4282 *status = process_status.status;
4292 int try_gc = 1, err;
4293 struct child_handler_disabler_state old;
4295 if (status) status->status = 0;
4299 if (mjit_enabled) mjit_pause(
false);
4300 disable_child_handler_before_fork(&old);
4306 status->error = err;
4309 disable_child_handler_fork_parent(&old);
4311 if (mjit_enabled && pid > 0) mjit_resume();
4319 if (handle_fork_error(err, status, NULL, &try_gc)) {
4326rb_fork_ruby(
int *status)
4330 rb_pid_t pid = rb_fork_ruby2(&process_status);
4332 if (status) *status = process_status.status;
4338rb_call_proc__fork(
void)
4346#if defined(HAVE_WORKING_FORK) && !defined(CANNOT_FORK_WITH_PTHREAD)
4360rb_proc__fork(VALUE _obj)
4362 rb_pid_t pid = rb_fork_ruby(NULL);
4401 pid = rb_call_proc__fork();
4415#define rb_proc__fork rb_f_notimplement
4416#define rb_f_fork rb_f_notimplement
4420exit_status_code(VALUE status)
4426 istatus = EXIT_SUCCESS;
4429 istatus = EXIT_FAILURE;
4433#if EXIT_SUCCESS != 0
4435 istatus = EXIT_SUCCESS;
4442NORETURN(
static VALUE rb_f_exit_bang(
int argc, VALUE *argv, VALUE obj));
4455rb_f_exit_bang(
int argc, VALUE *argv, VALUE obj)
4460 istatus = exit_status_code(argv[0]);
4463 istatus = EXIT_FAILURE;
4473 if (GET_EC()->tag) {
4478 rb_exc_raise(rb_class_new_instance(2, args, rb_eSystemExit));
4489 istatus = exit_status_code(argv[0]);
4492 istatus = EXIT_SUCCESS;
4499NORETURN(
static VALUE f_exit(
int c,
const VALUE *a, VALUE
_));
4542f_exit(
int c,
const VALUE *a, VALUE
_)
4554 VALUE errinfo = rb_ec_get_errinfo(ec);
4555 if (!
NIL_P(errinfo)) {
4556 rb_ec_error_print(ec, errinfo);
4563 args[1] = args[0] = argv[0];
4566 args[0] =
INT2NUM(EXIT_FAILURE);
4567 rb_exc_raise(rb_class_new_instance(2, args, rb_eSystemExit));
4573NORETURN(
static VALUE f_abort(
int c,
const VALUE *a, VALUE
_));
4587f_abort(
int c,
const VALUE *a, VALUE
_)
4601#if !defined HAVE_WORKING_FORK && !defined HAVE_SPAWNV && !defined __EMSCRIPTEN__
4603rb_execarg_commandline(
const struct rb_execarg *eargp, VALUE *prog)
4606 if (eargp && !eargp->use_shell) {
4607 VALUE str = eargp->invoke.cmd.argv_str;
4608 VALUE buf = eargp->invoke.cmd.argv_buf;
4609 char *p, **argv = ARGVSTR2ARGV(str);
4610 long i, argc = ARGVSTR2ARGC(str);
4614 for (i = 1; i < argc; ++i) {
4615 p[argv[i] - start - 1] =
' ';
4625rb_spawn_process(
struct rb_execarg *eargp,
char *errmsg,
size_t errmsg_buflen)
4628#if !defined HAVE_WORKING_FORK || USE_SPAWNV
4631# if !defined HAVE_SPAWNV
4636#if defined HAVE_WORKING_FORK && !USE_SPAWNV
4637 pid = fork_check_err(eargp->status, rb_exec_atfork, eargp, eargp->redirect_fds, errmsg, errmsg_buflen, eargp);
4639 prog = eargp->use_shell ? eargp->invoke.sh.shell_script : eargp->invoke.cmd.command_name;
4641 if (rb_execarg_run_options(eargp, &sarg, errmsg, errmsg_buflen) < 0) {
4645 if (prog && !eargp->use_shell) {
4646 char **argv = ARGVSTR2ARGV(eargp->invoke.cmd.argv_str);
4649# if defined HAVE_SPAWNV
4650 if (eargp->use_shell) {
4654 char **argv = ARGVSTR2ARGV(eargp->invoke.cmd.argv_str);
4655 pid = proc_spawn_cmd(argv, prog, eargp);
4662 status = system(rb_execarg_commandline(eargp, &prog));
4667 if (eargp->waitpid_state && eargp->waitpid_state != WAITPID_LOCK_ONLY) {
4668 eargp->waitpid_state->pid = pid;
4671 rb_execarg_run_options(&sarg, NULL, errmsg, errmsg_buflen);
4686do_spawn_process(VALUE arg)
4689 rb_execarg_parent_start1(argp->execarg);
4690 return (VALUE)rb_spawn_process(
DATA_PTR(argp->execarg),
4691 argp->errmsg.ptr, argp->errmsg.buflen);
4695rb_execarg_spawn(VALUE execarg_obj,
char *errmsg,
size_t errmsg_buflen)
4698 struct rb_execarg *eargp = rb_execarg_get(execarg_obj);
4704 if (!eargp->waitpid_state && mjit_enabled) {
4705 eargp->waitpid_state = WAITPID_LOCK_ONLY;
4708 args.execarg = execarg_obj;
4709 args.errmsg.ptr = errmsg;
4710 args.errmsg.buflen = errmsg_buflen;
4711 return (rb_pid_t)
rb_ensure(do_spawn_process, (VALUE)&args,
4712 execarg_parent_end, execarg_obj);
4716rb_spawn_internal(
int argc,
const VALUE *argv,
char *errmsg,
size_t errmsg_buflen)
4720 execarg_obj = rb_execarg_new(argc, argv, TRUE, FALSE);
4721 return rb_execarg_spawn(execarg_obj, errmsg, errmsg_buflen);
4725rb_spawn_err(
int argc,
const VALUE *argv,
char *errmsg,
size_t errmsg_buflen)
4727 return rb_spawn_internal(argc, argv, errmsg, errmsg_buflen);
4733 return rb_spawn_internal(argc, argv, NULL, 0);
4788rb_f_system(
int argc, VALUE *argv, VALUE
_)
4790 VALUE execarg_obj = rb_execarg_new(argc, argv, TRUE, TRUE);
4791 struct rb_execarg *eargp = rb_execarg_get(execarg_obj);
4794 eargp->status = &status;
4796 rb_last_status_clear();
4800 rb_pid_t pid = rb_execarg_spawn(execarg_obj, 0, 0);
4803 VALUE status = rb_process_status_wait(pid, 0);
4807 rb_obj_freeze(status);
4808 GET_THREAD()->last_status = status;
4810 if (data->status == EXIT_SUCCESS) {
4814 if (data->error != 0) {
4815 if (eargp->exception) {
4816 VALUE command = eargp->invoke.sh.shell_script;
4824 else if (eargp->exception) {
4825 VALUE command = eargp->invoke.sh.shell_script;
4839 if (eargp->exception) {
4840 VALUE command = eargp->invoke.sh.shell_script;
5119rb_f_spawn(
int argc, VALUE *argv, VALUE
_)
5122 char errmsg[CHILD_ERRMSG_BUFLEN] = {
'\0' };
5123 VALUE execarg_obj, fail_str;
5126 execarg_obj = rb_execarg_new(argc, argv, TRUE, FALSE);
5127 eargp = rb_execarg_get(execarg_obj);
5128 fail_str = eargp->use_shell ? eargp->invoke.sh.shell_script : eargp->invoke.cmd.command_name;
5130 pid = rb_execarg_spawn(execarg_obj, errmsg,
sizeof(errmsg));
5134 rb_exec_fail(eargp, err, errmsg);
5138#if defined(HAVE_WORKING_FORK) || defined(HAVE_SPAWNV)
5163rb_f_sleep(
int argc, VALUE *argv, VALUE
_)
5165 time_t beg = time(0);
5168 if (scheduler !=
Qnil) {
5181 time_t end = time(0) - beg;
5183 return TIMET2NUM(end);
5187#if (defined(HAVE_GETPGRP) && defined(GETPGRP_VOID)) || defined(HAVE_GETPGID)
5200proc_getpgrp(VALUE
_)
5204#if defined(HAVE_GETPGRP) && defined(GETPGRP_VOID)
5215#define proc_getpgrp rb_f_notimplement
5219#if defined(HAVE_SETPGID) || (defined(HAVE_SETPGRP) && defined(SETPGRP_VOID))
5229proc_setpgrp(VALUE
_)
5237#elif defined(HAVE_SETPGRP) && defined(SETPGRP_VOID)
5243#define proc_setpgrp rb_f_notimplement
5247#if defined(HAVE_GETPGID)
5259proc_getpgid(VALUE obj, VALUE pid)
5268#define proc_getpgid rb_f_notimplement
5282proc_setpgid(VALUE obj, VALUE pid, VALUE pgrp)
5284 rb_pid_t ipid, ipgrp;
5293#define proc_setpgid rb_f_notimplement
5311proc_getsid(
int argc, VALUE *argv, VALUE
_)
5324#define proc_getsid rb_f_notimplement
5328#if defined(HAVE_SETSID) || (defined(HAVE_SETPGRP) && defined(TIOCNOTTY))
5329#if !defined(HAVE_SETSID)
5330static rb_pid_t ruby_setsid(
void);
5331#define setsid() ruby_setsid()
5354#if !defined(HAVE_SETSID)
5355#define HAVE_SETSID 1
5363#if defined(SETPGRP_VOID)
5369 ret = setpgrp(0, pid);
5371 if (ret == -1)
return -1;
5375 ioctl(fd, TIOCNOTTY, NULL);
5382#define proc_setsid rb_f_notimplement
5386#ifdef HAVE_GETPRIORITY
5405proc_getpriority(VALUE obj, VALUE which, VALUE who)
5407 int prio, iwhich, iwho;
5413 prio = getpriority(iwhich, iwho);
5418#define proc_getpriority rb_f_notimplement
5422#ifdef HAVE_GETPRIORITY
5436proc_setpriority(VALUE obj, VALUE which, VALUE who, VALUE prio)
5438 int iwhich, iwho, iprio;
5444 if (setpriority(iwhich, iwho, iprio) < 0)
5449#define proc_setpriority rb_f_notimplement
5452#if defined(HAVE_SETRLIMIT) && defined(NUM2RLIM)
5454rlimit_resource_name2int(
const char *name,
long len,
int casetype)
5458#define RESCHECK(r) \
5460 if (len == rb_strlen_lit(#r) && STRCASECMP(name, #r) == 0) { \
5461 resource = RLIMIT_##r; \
5495#ifdef RLIMIT_MEMLOCK
5498#ifdef RLIMIT_MSGQUEUE
5534#ifdef RLIMIT_SIGPENDING
5535 RESCHECK(SIGPENDING);
5544 for (p = name; *p; p++)
5550 for (p = name; *p; p++)
5556 rb_bug(
"unexpected casetype");
5563rlimit_type_by_hname(
const char *name,
long len)
5565 return rlimit_resource_name2int(name, len, 0);
5569rlimit_type_by_lname(
const char *name,
long len)
5571 return rlimit_resource_name2int(name, len, 1);
5575rlimit_type_by_sym(VALUE key)
5581 static const char prefix[] =
"rlimit_";
5582 enum {prefix_len =
sizeof(prefix)-1};
5584 if (len > prefix_len && strncmp(prefix, rname, prefix_len) == 0) {
5585 rtype = rlimit_type_by_lname(rname + prefix_len, len - prefix_len);
5593rlimit_resource_type(VALUE rtype)
5600 switch (
TYPE(rtype)) {
5623 r = rlimit_type_by_hname(name, len);
5627 rb_raise(rb_eArgError,
"invalid resource name: % "PRIsVALUE, rtype);
5633rlimit_resource_value(VALUE rval)
5638 switch (
TYPE(rval)) {
5656 return NUM2RLIM(rval);
5660 if (strcmp(name,
"INFINITY") == 0)
return RLIM_INFINITY;
5662#ifdef RLIM_SAVED_MAX
5663 if (strcmp(name,
"SAVED_MAX") == 0)
return RLIM_SAVED_MAX;
5665#ifdef RLIM_SAVED_CUR
5666 if (strcmp(name,
"SAVED_CUR") == 0)
return RLIM_SAVED_CUR;
5668 rb_raise(rb_eArgError,
"invalid resource value: %"PRIsVALUE, rval);
5674#if defined(HAVE_GETRLIMIT) && defined(RLIM2NUM)
5696proc_getrlimit(VALUE obj, VALUE resource)
5700 if (getrlimit(rlimit_resource_type(resource), &rlim) < 0) {
5703 return rb_assoc_new(RLIM2NUM(rlim.rlim_cur), RLIM2NUM(rlim.rlim_max));
5706#define proc_getrlimit rb_f_notimplement
5709#if defined(HAVE_SETRLIMIT) && defined(NUM2RLIM)
5762proc_setrlimit(
int argc, VALUE *argv, VALUE obj)
5764 VALUE resource, rlim_cur, rlim_max;
5770 if (argc < 3 ||
NIL_P(rlim_max = argv[2]))
5771 rlim_max = rlim_cur;
5773 rlim.rlim_cur = rlimit_resource_value(rlim_cur);
5774 rlim.rlim_max = rlimit_resource_value(rlim_max);
5776 if (setrlimit(rlimit_resource_type(resource), &rlim) < 0) {
5782#define proc_setrlimit rb_f_notimplement
5785static int under_uid_switch = 0;
5787check_uid_switch(
void)
5789 if (under_uid_switch) {
5790 rb_raise(rb_eRuntimeError,
"can't handle UID while evaluating block given to Process::UID.switch method");
5794static int under_gid_switch = 0;
5796check_gid_switch(
void)
5798 if (under_gid_switch) {
5799 rb_raise(rb_eRuntimeError,
"can't handle GID while evaluating block given to Process::UID.switch method");
5804#if defined(HAVE_PWD_H)
5813#if ( !defined(USE_GETLOGIN_R) && !defined(USE_GETLOGIN) )
5816 char MAYBE_UNUSED(*login) = NULL;
5818# ifdef USE_GETLOGIN_R
5820#if defined(__FreeBSD__)
5821 typedef int getlogin_r_size_t;
5823 typedef size_t getlogin_r_size_t;
5826 long loginsize = GETLOGIN_R_SIZE_INIT;
5829 loginsize = GETLOGIN_R_SIZE_DEFAULT;
5839 while ((gle = getlogin_r(login, (getlogin_r_size_t)loginsize)) != 0) {
5841 if (gle == ENOTTY || gle == ENXIO || gle == ENOENT) {
5846 if (gle != ERANGE || loginsize >= GETLOGIN_R_SIZE_LIMIT) {
5856 if (login == NULL) {
5861 return maybe_result;
5868 if (errno == ENOTTY || errno == ENXIO || errno == ENOENT) {
5881rb_getpwdirnam_for_login(VALUE login_name)
5883#if ( !defined(USE_GETPWNAM_R) && !defined(USE_GETPWNAM) )
5887 if (
NIL_P(login_name)) {
5894 struct passwd *pwptr;
5896# ifdef USE_GETPWNAM_R
5898 struct passwd pwdnm;
5900 long bufsizenm = GETPW_R_SIZE_INIT;
5903 bufsizenm = GETPW_R_SIZE_DEFAULT;
5913 while ((enm = getpwnam_r(login, &pwdnm, bufnm, bufsizenm, &pwptr)) != 0) {
5915 if (enm == ENOENT || enm== ESRCH || enm == EBADF || enm == EPERM) {
5921 if (enm != ERANGE || bufsizenm >= GETPW_R_SIZE_LIMIT) {
5931 if (pwptr == NULL) {
5945 pwptr = getpwnam(login);
5952 && ( errno != ENOENT && errno != ESRCH && errno != EBADF && errno != EPERM)) {
5968# if !defined(USE_GETPWUID_R) && !defined(USE_GETPWUID)
5972 uid_t ruid = getuid();
5974 struct passwd *pwptr;
5976# ifdef USE_GETPWUID_R
5978 struct passwd pwdid;
5980 long bufsizeid = GETPW_R_SIZE_INIT;
5983 bufsizeid = GETPW_R_SIZE_DEFAULT;
5993 while ((eid = getpwuid_r(ruid, &pwdid, bufid, bufsizeid, &pwptr)) != 0) {
5995 if (eid == ENOENT || eid== ESRCH || eid == EBADF || eid == EPERM) {
6001 if (eid != ERANGE || bufsizeid >= GETPW_R_SIZE_LIMIT) {
6011 if (pwptr == NULL) {
6022# elif defined(USE_GETPWUID)
6025 pwptr = getpwuid(ruid);
6032 && ( errno == ENOENT || errno == ESRCH || errno == EBADF || errno == EPERM)) {
6054#if defined(HAVE_PWD_H)
6057# ifdef USE_GETPWNAM_R
6070 struct passwd *pwptr;
6071#ifdef USE_GETPWNAM_R
6072 struct passwd pwbuf;
6077 getpw_buf_len = GETPW_R_SIZE_INIT;
6078 if (getpw_buf_len < 0) getpw_buf_len = GETPW_R_SIZE_DEFAULT;
6085 while ((e = getpwnam_r(usrname, &pwbuf, getpw_buf, getpw_buf_len, &pwptr)) != 0) {
6086 if (e != ERANGE || getpw_buf_len >= GETPW_R_SIZE_LIMIT) {
6095 pwptr = getpwnam(usrname);
6098#ifndef USE_GETPWNAM_R
6101 rb_raise(rb_eArgError,
"can't find user for %"PRIsVALUE,
id);
6103 uid = pwptr->pw_uid;
6104#ifndef USE_GETPWNAM_R
6111# ifdef p_uid_from_name
6124p_uid_from_name(VALUE
self, VALUE
id)
6131#if defined(HAVE_GRP_H)
6134# ifdef USE_GETGRNAM_R
6147 struct group *grptr;
6148#ifdef USE_GETGRNAM_R
6154 getgr_buf_len = GETGR_R_SIZE_INIT;
6155 if (getgr_buf_len < 0) getgr_buf_len = GETGR_R_SIZE_DEFAULT;
6162 while ((e = getgrnam_r(grpname, &grbuf, getgr_buf, getgr_buf_len, &grptr)) != 0) {
6163 if (e != ERANGE || getgr_buf_len >= GETGR_R_SIZE_LIMIT) {
6171#elif defined(HAVE_GETGRNAM)
6172 grptr = getgrnam(grpname);
6177#if !defined(USE_GETGRNAM_R) && defined(HAVE_ENDGRENT)
6180 rb_raise(rb_eArgError,
"can't find group for %"PRIsVALUE,
id);
6182 gid = grptr->gr_gid;
6183#if !defined(USE_GETGRNAM_R) && defined(HAVE_ENDGRENT)
6190# ifdef p_gid_from_name
6203p_gid_from_name(VALUE
self, VALUE
id)
6210#if defined HAVE_SETUID
6221p_sys_setuid(VALUE obj, VALUE
id)
6228#define p_sys_setuid rb_f_notimplement
6232#if defined HAVE_SETRUID
6243p_sys_setruid(VALUE obj, VALUE
id)
6250#define p_sys_setruid rb_f_notimplement
6254#if defined HAVE_SETEUID
6265p_sys_seteuid(VALUE obj, VALUE
id)
6272#define p_sys_seteuid rb_f_notimplement
6276#if defined HAVE_SETREUID
6289p_sys_setreuid(VALUE obj, VALUE rid, VALUE eid)
6291 rb_uid_t ruid, euid;
6294 ruid = OBJ2UID1(rid);
6295 euid = OBJ2UID1(eid);
6301#define p_sys_setreuid rb_f_notimplement
6305#if defined HAVE_SETRESUID
6318p_sys_setresuid(VALUE obj, VALUE rid, VALUE eid, VALUE sid)
6320 rb_uid_t ruid, euid, suid;
6323 ruid = OBJ2UID1(rid);
6324 euid = OBJ2UID1(eid);
6325 suid = OBJ2UID1(sid);
6327 if (setresuid(ruid, euid, suid) != 0)
rb_sys_fail(0);
6331#define p_sys_setresuid rb_f_notimplement
6347proc_getuid(VALUE obj)
6349 rb_uid_t uid = getuid();
6354#if defined(HAVE_SETRESUID) || defined(HAVE_SETREUID) || defined(HAVE_SETRUID) || defined(HAVE_SETUID)
6364proc_setuid(VALUE obj, VALUE
id)
6371#if defined(HAVE_SETRESUID)
6373#elif defined HAVE_SETREUID
6375#elif defined HAVE_SETRUID
6377#elif defined HAVE_SETUID
6379 if (geteuid() == uid) {
6390#define proc_setuid rb_f_notimplement
6404static rb_uid_t SAVED_USER_ID = -1;
6406#ifdef BROKEN_SETREUID
6408setreuid(rb_uid_t ruid, rb_uid_t euid)
6410 if (ruid != (rb_uid_t)-1 && ruid != getuid()) {
6411 if (euid == (rb_uid_t)-1) euid = geteuid();
6412 if (setuid(ruid) < 0)
return -1;
6414 if (euid != (rb_uid_t)-1 && euid != geteuid()) {
6415 if (seteuid(euid) < 0)
return -1;
6435p_uid_change_privilege(VALUE obj, VALUE
id)
6443 if (geteuid() == 0) {
6444#if defined(HAVE_SETRESUID)
6446 SAVED_USER_ID = uid;
6447#elif defined(HAVE_SETUID)
6449 SAVED_USER_ID = uid;
6450#elif defined(HAVE_SETREUID) && !defined(OBSOLETE_SETREUID)
6451 if (getuid() == uid) {
6452 if (SAVED_USER_ID == uid) {
6457 if (setreuid(-1, SAVED_USER_ID) < 0)
rb_sys_fail(0);
6458 if (setreuid(SAVED_USER_ID, 0) < 0)
rb_sys_fail(0);
6461 SAVED_USER_ID = uid;
6467 SAVED_USER_ID = uid;
6473 SAVED_USER_ID = uid;
6475#elif defined(HAVE_SETRUID) && defined(HAVE_SETEUID)
6476 if (getuid() == uid) {
6477 if (SAVED_USER_ID == uid) {
6491 SAVED_USER_ID = uid;
6498 SAVED_USER_ID = uid;
6506#if defined(HAVE_SETRESUID)
6507 if (setresuid((getuid() == uid)? (rb_uid_t)-1: uid,
6508 (geteuid() == uid)? (rb_uid_t)-1: uid,
6509 (SAVED_USER_ID == uid)? (rb_uid_t)-1: uid) < 0)
rb_sys_fail(0);
6510 SAVED_USER_ID = uid;
6511#elif defined(HAVE_SETREUID) && !defined(OBSOLETE_SETREUID)
6512 if (SAVED_USER_ID == uid) {
6513 if (setreuid((getuid() == uid)? (rb_uid_t)-1: uid,
6514 (geteuid() == uid)? (rb_uid_t)-1: uid) < 0)
6517 else if (getuid() != uid) {
6518 if (setreuid(uid, (geteuid() == uid)? (rb_uid_t)-1: uid) < 0)
6520 SAVED_USER_ID = uid;
6522 else if ( geteuid() != uid) {
6524 SAVED_USER_ID = uid;
6528 if (setreuid(-1, SAVED_USER_ID) < 0)
rb_sys_fail(0);
6529 if (setreuid(SAVED_USER_ID, uid) < 0)
rb_sys_fail(0);
6530 SAVED_USER_ID = uid;
6533#elif defined(HAVE_SETRUID) && defined(HAVE_SETEUID)
6534 if (SAVED_USER_ID == uid) {
6535 if (geteuid() != uid && seteuid(uid) < 0)
rb_sys_fail(0);
6536 if (getuid() != uid && setruid(uid) < 0)
rb_sys_fail(0);
6538 else if ( geteuid() == uid) {
6539 if (getuid() != uid) {
6541 SAVED_USER_ID = uid;
6545 SAVED_USER_ID = uid;
6549 else if ( getuid() == uid) {
6552 SAVED_USER_ID = uid;
6558#elif defined HAVE_44BSD_SETUID
6559 if (getuid() == uid) {
6562 SAVED_USER_ID = uid;
6567#elif defined HAVE_SETEUID
6568 if (getuid() == uid && SAVED_USER_ID == uid) {
6574#elif defined HAVE_SETUID
6575 if (getuid() == uid && SAVED_USER_ID == uid) {
6590#if defined HAVE_SETGID
6601p_sys_setgid(VALUE obj, VALUE
id)
6608#define p_sys_setgid rb_f_notimplement
6612#if defined HAVE_SETRGID
6623p_sys_setrgid(VALUE obj, VALUE
id)
6630#define p_sys_setrgid rb_f_notimplement
6634#if defined HAVE_SETEGID
6645p_sys_setegid(VALUE obj, VALUE
id)
6652#define p_sys_setegid rb_f_notimplement
6656#if defined HAVE_SETREGID
6669p_sys_setregid(VALUE obj, VALUE rid, VALUE eid)
6671 rb_gid_t rgid, egid;
6673 rgid = OBJ2GID(rid);
6674 egid = OBJ2GID(eid);
6679#define p_sys_setregid rb_f_notimplement
6682#if defined HAVE_SETRESGID
6695p_sys_setresgid(VALUE obj, VALUE rid, VALUE eid, VALUE sid)
6697 rb_gid_t rgid, egid, sgid;
6699 rgid = OBJ2GID(rid);
6700 egid = OBJ2GID(eid);
6701 sgid = OBJ2GID(sid);
6702 if (setresgid(rgid, egid, sgid) != 0)
rb_sys_fail(0);
6706#define p_sys_setresgid rb_f_notimplement
6710#if defined HAVE_ISSETUGID
6724p_sys_issetugid(VALUE obj)
6734#define p_sys_issetugid rb_f_notimplement
6750proc_getgid(VALUE obj)
6752 rb_gid_t gid = getgid();
6757#if defined(HAVE_SETRESGID) || defined(HAVE_SETREGID) || defined(HAVE_SETRGID) || defined(HAVE_SETGID)
6766proc_setgid(VALUE obj, VALUE
id)
6773#if defined(HAVE_SETRESGID)
6775#elif defined HAVE_SETREGID
6777#elif defined HAVE_SETRGID
6779#elif defined HAVE_SETGID
6781 if (getegid() == gid) {
6792#define proc_setgid rb_f_notimplement
6796#if defined(_SC_NGROUPS_MAX) || defined(NGROUPS_MAX)
6817static int _maxgroups = -1;
6819get_sc_ngroups_max(
void)
6821#ifdef _SC_NGROUPS_MAX
6822 return (
int)sysconf(_SC_NGROUPS_MAX);
6823#elif defined(NGROUPS_MAX)
6824 return (
int)NGROUPS_MAX;
6832 if (_maxgroups < 0) {
6833 _maxgroups = get_sc_ngroups_max();
6835 _maxgroups = RB_MAX_GROUPS;
6844#ifdef HAVE_GETGROUPS
6870proc_getgroups(VALUE obj)
6876 ngroups = getgroups(0, NULL);
6880 groups =
ALLOCV_N(rb_gid_t, tmp, ngroups);
6882 ngroups = getgroups(ngroups, groups);
6887 for (i = 0; i < ngroups; i++)
6895#define proc_getgroups rb_f_notimplement
6899#ifdef HAVE_SETGROUPS
6914proc_setgroups(VALUE obj, VALUE ary)
6924 if (ngroups > maxgroups())
6925 rb_raise(rb_eArgError,
"too many groups, %d max", maxgroups());
6927 groups =
ALLOCV_N(rb_gid_t, tmp, ngroups);
6929 for (i = 0; i < ngroups; i++) {
6932 groups[i] = OBJ2GID1(g);
6936 if (setgroups(ngroups, groups) == -1)
6941 return proc_getgroups(obj);
6944#define proc_setgroups rb_f_notimplement
6948#ifdef HAVE_INITGROUPS
6967proc_initgroups(VALUE obj, VALUE uname, VALUE base_grp)
6972 return proc_getgroups(obj);
6975#define proc_initgroups rb_f_notimplement
6978#if defined(_SC_NGROUPS_MAX) || defined(NGROUPS_MAX)
6990proc_getmaxgroups(VALUE obj)
6995#define proc_getmaxgroups rb_f_notimplement
6998#ifdef HAVE_SETGROUPS
7008proc_setmaxgroups(VALUE obj, VALUE val)
7011 int ngroups_max = get_sc_ngroups_max();
7014 rb_raise(rb_eArgError,
"maxgroups %d should be positive", ngroups);
7016 if (ngroups > RB_MAX_GROUPS)
7017 ngroups = RB_MAX_GROUPS;
7019 if (ngroups_max > 0 && ngroups > ngroups_max)
7020 ngroups = ngroups_max;
7022 _maxgroups = ngroups;
7027#define proc_setmaxgroups rb_f_notimplement
7030#if defined(HAVE_DAEMON) || (defined(HAVE_WORKING_FORK) && defined(HAVE_SETSID))
7031static int rb_daemon(
int nochdir,
int noclose);
7048proc_daemon(
int argc, VALUE *argv, VALUE
_)
7050 int n, nochdir = FALSE, noclose = FALSE;
7053 case 2: noclose = TO_BOOL(argv[1],
"noclose");
7054 case 1: nochdir = TO_BOOL(argv[0],
"nochdir");
7058 n = rb_daemon(nochdir, noclose);
7064rb_daemon(
int nochdir,
int noclose)
7068 if (mjit_enabled) mjit_pause(
false);
7070 err = daemon(nochdir, noclose);
7076#define fork_daemon() \
7077 switch (rb_fork_ruby(NULL)) { \
7078 case -1: return -1; \
7080 default: _exit(EXIT_SUCCESS); \
7085 if (setsid() < 0)
return -1;
7093 if (!noclose && (n =
rb_cloexec_open(
"/dev/null", O_RDWR, 0)) != -1) {
7105#define proc_daemon rb_f_notimplement
7118static rb_gid_t SAVED_GROUP_ID = -1;
7120#ifdef BROKEN_SETREGID
7122setregid(rb_gid_t rgid, rb_gid_t egid)
7124 if (rgid != (rb_gid_t)-1 && rgid != getgid()) {
7125 if (egid == (rb_gid_t)-1) egid = getegid();
7126 if (setgid(rgid) < 0)
return -1;
7128 if (egid != (rb_gid_t)-1 && egid != getegid()) {
7129 if (setegid(egid) < 0)
return -1;
7149p_gid_change_privilege(VALUE obj, VALUE
id)
7157 if (geteuid() == 0) {
7158#if defined(HAVE_SETRESGID)
7160 SAVED_GROUP_ID = gid;
7161#elif defined HAVE_SETGID
7163 SAVED_GROUP_ID = gid;
7164#elif defined(HAVE_SETREGID) && !defined(OBSOLETE_SETREGID)
7165 if (getgid() == gid) {
7166 if (SAVED_GROUP_ID == gid) {
7171 if (setregid(-1, SAVED_GROUP_ID) < 0)
rb_sys_fail(0);
7172 if (setregid(SAVED_GROUP_ID, 0) < 0)
rb_sys_fail(0);
7175 SAVED_GROUP_ID = gid;
7181 SAVED_GROUP_ID = gid;
7187 SAVED_GROUP_ID = gid;
7189#elif defined(HAVE_SETRGID) && defined (HAVE_SETEGID)
7190 if (getgid() == gid) {
7191 if (SAVED_GROUP_ID == gid) {
7206 SAVED_GROUP_ID = gid;
7213 SAVED_GROUP_ID = gid;
7220#if defined(HAVE_SETRESGID)
7221 if (setresgid((getgid() == gid)? (rb_gid_t)-1: gid,
7222 (getegid() == gid)? (rb_gid_t)-1: gid,
7223 (SAVED_GROUP_ID == gid)? (rb_gid_t)-1: gid) < 0)
rb_sys_fail(0);
7224 SAVED_GROUP_ID = gid;
7225#elif defined(HAVE_SETREGID) && !defined(OBSOLETE_SETREGID)
7226 if (SAVED_GROUP_ID == gid) {
7227 if (setregid((getgid() == gid)? (rb_uid_t)-1: gid,
7228 (getegid() == gid)? (rb_uid_t)-1: gid) < 0)
7231 else if (getgid() != gid) {
7232 if (setregid(gid, (getegid() == gid)? (rb_uid_t)-1: gid) < 0)
7234 SAVED_GROUP_ID = gid;
7236 else if ( getegid() != gid) {
7238 SAVED_GROUP_ID = gid;
7242 if (setregid(-1, SAVED_GROUP_ID) < 0)
rb_sys_fail(0);
7243 if (setregid(SAVED_GROUP_ID, gid) < 0)
rb_sys_fail(0);
7244 SAVED_GROUP_ID = gid;
7247#elif defined(HAVE_SETRGID) && defined(HAVE_SETEGID)
7248 if (SAVED_GROUP_ID == gid) {
7249 if (getegid() != gid && setegid(gid) < 0)
rb_sys_fail(0);
7250 if (getgid() != gid && setrgid(gid) < 0)
rb_sys_fail(0);
7252 else if ( getegid() == gid) {
7253 if (getgid() != gid) {
7255 SAVED_GROUP_ID = gid;
7259 SAVED_GROUP_ID = gid;
7263 else if ( getgid() == gid) {
7266 SAVED_GROUP_ID = gid;
7272#elif defined HAVE_44BSD_SETGID
7273 if (getgid() == gid) {
7276 SAVED_GROUP_ID = gid;
7281#elif defined HAVE_SETEGID
7282 if (getgid() == gid && SAVED_GROUP_ID == gid) {
7288#elif defined HAVE_SETGID
7289 if (getgid() == gid && SAVED_GROUP_ID == gid) {
7316proc_geteuid(VALUE obj)
7318 rb_uid_t euid = geteuid();
7322#if defined(HAVE_SETRESUID) || defined(HAVE_SETREUID) || defined(HAVE_SETEUID) || defined(HAVE_SETUID) || defined(_POSIX_SAVED_IDS)
7324proc_seteuid(rb_uid_t uid)
7326#if defined(HAVE_SETRESUID)
7328#elif defined HAVE_SETREUID
7330#elif defined HAVE_SETEUID
7332#elif defined HAVE_SETUID
7333 if (uid == getuid()) {
7345#if defined(HAVE_SETRESUID) || defined(HAVE_SETREUID) || defined(HAVE_SETEUID) || defined(HAVE_SETUID)
7355proc_seteuid_m(VALUE mod, VALUE euid)
7358 proc_seteuid(OBJ2UID(euid));
7362#define proc_seteuid_m rb_f_notimplement
7366rb_seteuid_core(rb_uid_t euid)
7368#if defined(HAVE_SETRESUID) || (defined(HAVE_SETREUID) && !defined(OBSOLETE_SETREUID))
7374#if defined(HAVE_SETRESUID) || (defined(HAVE_SETREUID) && !defined(OBSOLETE_SETREUID))
7378#if defined(HAVE_SETRESUID)
7381 SAVED_USER_ID = euid;
7386#elif defined(HAVE_SETREUID) && !defined(OBSOLETE_SETREUID)
7391 SAVED_USER_ID = euid;
7393#elif defined HAVE_SETEUID
7395#elif defined HAVE_SETUID
7420p_uid_grant_privilege(VALUE obj, VALUE
id)
7422 rb_seteuid_core(OBJ2UID(
id));
7440proc_getegid(VALUE obj)
7442 rb_gid_t egid = getegid();
7447#if defined(HAVE_SETRESGID) || defined(HAVE_SETREGID) || defined(HAVE_SETEGID) || defined(HAVE_SETGID) || defined(_POSIX_SAVED_IDS)
7457proc_setegid(VALUE obj, VALUE egid)
7459#if defined(HAVE_SETRESGID) || defined(HAVE_SETREGID) || defined(HAVE_SETEGID) || defined(HAVE_SETGID)
7465#if defined(HAVE_SETRESGID) || defined(HAVE_SETREGID) || defined(HAVE_SETEGID) || defined(HAVE_SETGID)
7466 gid = OBJ2GID(egid);
7469#if defined(HAVE_SETRESGID)
7471#elif defined HAVE_SETREGID
7473#elif defined HAVE_SETEGID
7475#elif defined HAVE_SETGID
7476 if (gid == getgid()) {
7489#if defined(HAVE_SETRESGID) || defined(HAVE_SETREGID) || defined(HAVE_SETEGID) || defined(HAVE_SETGID)
7490#define proc_setegid_m proc_setegid
7492#define proc_setegid_m rb_f_notimplement
7496rb_setegid_core(rb_gid_t egid)
7498#if defined(HAVE_SETRESGID) || (defined(HAVE_SETREGID) && !defined(OBSOLETE_SETREGID))
7504#if defined(HAVE_SETRESGID) || (defined(HAVE_SETREGID) && !defined(OBSOLETE_SETREGID))
7508#if defined(HAVE_SETRESGID)
7511 SAVED_GROUP_ID = egid;
7516#elif defined(HAVE_SETREGID) && !defined(OBSOLETE_SETREGID)
7521 SAVED_GROUP_ID = egid;
7523#elif defined HAVE_SETEGID
7525#elif defined HAVE_SETGID
7550p_gid_grant_privilege(VALUE obj, VALUE
id)
7552 rb_setegid_core(OBJ2GID(
id));
7567p_uid_exchangeable(VALUE
_)
7569#if defined(HAVE_SETRESUID)
7571#elif defined(HAVE_SETREUID) && !defined(OBSOLETE_SETREUID)
7592p_uid_exchange(VALUE obj)
7595#if defined(HAVE_SETRESUID) || (defined(HAVE_SETREUID) && !defined(OBSOLETE_SETREUID))
7602#if defined(HAVE_SETRESUID) || (defined(HAVE_SETREUID) && !defined(OBSOLETE_SETREUID))
7606#if defined(HAVE_SETRESUID)
7607 if (setresuid(euid, uid, uid) < 0)
rb_sys_fail(0);
7608 SAVED_USER_ID = uid;
7609#elif defined(HAVE_SETREUID) && !defined(OBSOLETE_SETREUID)
7611 SAVED_USER_ID = uid;
7629p_gid_exchangeable(VALUE
_)
7631#if defined(HAVE_SETRESGID)
7633#elif defined(HAVE_SETREGID) && !defined(OBSOLETE_SETREGID)
7654p_gid_exchange(VALUE obj)
7657#if defined(HAVE_SETRESGID) || (defined(HAVE_SETREGID) && !defined(OBSOLETE_SETREGID))
7664#if defined(HAVE_SETRESGID) || (defined(HAVE_SETREGID) && !defined(OBSOLETE_SETREGID))
7668#if defined(HAVE_SETRESGID)
7669 if (setresgid(egid, gid, gid) < 0)
rb_sys_fail(0);
7670 SAVED_GROUP_ID = gid;
7671#elif defined(HAVE_SETREGID) && !defined(OBSOLETE_SETREGID)
7673 SAVED_GROUP_ID = gid;
7692p_uid_have_saved_id(VALUE
_)
7694#if defined(HAVE_SETRESUID) || defined(HAVE_SETEUID) || defined(_POSIX_SAVED_IDS)
7702#if defined(HAVE_SETRESUID) || defined(HAVE_SETEUID) || defined(_POSIX_SAVED_IDS)
7704p_uid_sw_ensure(VALUE i)
7706 rb_uid_t
id = (rb_uid_t)i;
7707 under_uid_switch = 0;
7708 id = rb_seteuid_core(
id);
7727p_uid_switch(VALUE obj)
7739 under_uid_switch = 1;
7746 else if (euid != SAVED_USER_ID) {
7747 proc_seteuid(SAVED_USER_ID);
7749 under_uid_switch = 1;
7764p_uid_sw_ensure(VALUE obj)
7766 under_uid_switch = 0;
7767 return p_uid_exchange(obj);
7771p_uid_switch(VALUE obj)
7783 p_uid_exchange(obj);
7785 under_uid_switch = 1;
7807p_gid_have_saved_id(VALUE
_)
7809#if defined(HAVE_SETRESGID) || defined(HAVE_SETEGID) || defined(_POSIX_SAVED_IDS)
7816#if defined(HAVE_SETRESGID) || defined(HAVE_SETEGID) || defined(_POSIX_SAVED_IDS)
7818p_gid_sw_ensure(VALUE i)
7820 rb_gid_t
id = (rb_gid_t)i;
7821 under_gid_switch = 0;
7822 id = rb_setegid_core(
id);
7841p_gid_switch(VALUE obj)
7853 under_gid_switch = 1;
7860 else if (egid != SAVED_GROUP_ID) {
7861 proc_setegid(obj,
GIDT2NUM(SAVED_GROUP_ID));
7863 under_gid_switch = 1;
7878p_gid_sw_ensure(VALUE obj)
7880 under_gid_switch = 0;
7881 return p_gid_exchange(obj);
7885p_gid_switch(VALUE obj)
7897 p_gid_exchange(obj);
7899 under_gid_switch = 1;
7909#if defined(HAVE_TIMES)
7913#ifdef HAVE__SC_CLK_TCK
7914 return sysconf(_SC_CLK_TCK);
7915#elif defined CLK_TCK
7939 VALUE utime, stime, cutime, cstime, ret;
7940#if defined(RUSAGE_SELF) && defined(RUSAGE_CHILDREN)
7941 struct rusage usage_s, usage_c;
7943 if (getrusage(RUSAGE_SELF, &usage_s) != 0 || getrusage(RUSAGE_CHILDREN, &usage_c) != 0)
7945 utime =
DBL2NUM((
double)usage_s.ru_utime.tv_sec + (
double)usage_s.ru_utime.tv_usec/1e6);
7946 stime =
DBL2NUM((
double)usage_s.ru_stime.tv_sec + (
double)usage_s.ru_stime.tv_usec/1e6);
7947 cutime =
DBL2NUM((
double)usage_c.ru_utime.tv_sec + (
double)usage_c.ru_utime.tv_usec/1e6);
7948 cstime =
DBL2NUM((
double)usage_c.ru_stime.tv_sec + (
double)usage_c.ru_stime.tv_usec/1e6);
7950 const double hertz = (double)get_clk_tck();
7954 utime =
DBL2NUM(buf.tms_utime / hertz);
7955 stime =
DBL2NUM(buf.tms_stime / hertz);
7956 cutime =
DBL2NUM(buf.tms_cutime / hertz);
7957 cstime =
DBL2NUM(buf.tms_cstime / hertz);
7959 ret =
rb_struct_new(rb_cProcessTms, utime, stime, cutime, cstime);
7967#define rb_proc_times rb_f_notimplement
7970#ifdef HAVE_LONG_LONG
7972#define TIMETICK_INT_MIN LLONG_MIN
7973#define TIMETICK_INT_MAX LLONG_MAX
7974#define TIMETICK_INT2NUM(v) LL2NUM(v)
7975#define MUL_OVERFLOW_TIMETICK_P(a, b) MUL_OVERFLOW_LONG_LONG_P(a, b)
7977typedef long timetick_int_t;
7978#define TIMETICK_INT_MIN LONG_MIN
7979#define TIMETICK_INT_MAX LONG_MAX
7980#define TIMETICK_INT2NUM(v) LONG2NUM(v)
7981#define MUL_OVERFLOW_TIMETICK_P(a, b) MUL_OVERFLOW_LONG_P(a, b)
7984CONSTFUNC(
static timetick_int_t gcd_timetick_int(timetick_int_t, timetick_int_t));
7985static timetick_int_t
7986gcd_timetick_int(timetick_int_t a, timetick_int_t b)
8006reduce_fraction(timetick_int_t *np, timetick_int_t *dp)
8008 timetick_int_t gcd = gcd_timetick_int(*np, *dp);
8016reduce_factors(timetick_int_t *numerators,
int num_numerators,
8017 timetick_int_t *denominators,
int num_denominators)
8020 for (i = 0; i < num_numerators; i++) {
8021 if (numerators[i] == 1)
8023 for (j = 0; j < num_denominators; j++) {
8024 if (denominators[j] == 1)
8026 reduce_fraction(&numerators[i], &denominators[j]);
8032 timetick_int_t giga_count;
8037timetick2dblnum(
struct timetick *ttp,
8038 timetick_int_t *numerators,
int num_numerators,
8039 timetick_int_t *denominators,
int num_denominators)
8044 reduce_factors(numerators, num_numerators,
8045 denominators, num_denominators);
8047 d = ttp->giga_count * 1e9 + ttp->count;
8049 for (i = 0; i < num_numerators; i++)
8051 for (i = 0; i < num_denominators; i++)
8052 d /= denominators[i];
8058timetick2dblnum_reciprocal(
struct timetick *ttp,
8059 timetick_int_t *numerators,
int num_numerators,
8060 timetick_int_t *denominators,
int num_denominators)
8065 reduce_factors(numerators, num_numerators,
8066 denominators, num_denominators);
8069 for (i = 0; i < num_denominators; i++)
8070 d *= denominators[i];
8071 for (i = 0; i < num_numerators; i++)
8073 d /= ttp->giga_count * 1e9 + ttp->count;
8078#define NDIV(x,y) (-(-((x)+1)/(y))-1)
8079#define DIV(n,d) ((n)<0 ? NDIV((n),(d)) : (n)/(d))
8082timetick2integer(
struct timetick *ttp,
8083 timetick_int_t *numerators,
int num_numerators,
8084 timetick_int_t *denominators,
int num_denominators)
8089 reduce_factors(numerators, num_numerators,
8090 denominators, num_denominators);
8092 if (!MUL_OVERFLOW_SIGNED_INTEGER_P(1000000000, ttp->giga_count,
8093 TIMETICK_INT_MIN, TIMETICK_INT_MAX-ttp->count)) {
8094 timetick_int_t t = ttp->giga_count * 1000000000 + ttp->count;
8095 for (i = 0; i < num_numerators; i++) {
8096 timetick_int_t factor = numerators[i];
8097 if (MUL_OVERFLOW_TIMETICK_P(factor, t))
8101 for (i = 0; i < num_denominators; i++) {
8102 t = DIV(t, denominators[i]);
8104 return TIMETICK_INT2NUM(t);
8108 v = TIMETICK_INT2NUM(ttp->giga_count);
8111 for (i = 0; i < num_numerators; i++) {
8112 timetick_int_t factor = numerators[i];
8115 v =
rb_funcall(v,
'*', 1, TIMETICK_INT2NUM(factor));
8117 for (i = 0; i < num_denominators; i++) {
8118 v =
rb_funcall(v,
'/', 1, TIMETICK_INT2NUM(denominators[i]));
8124make_clock_result(
struct timetick *ttp,
8125 timetick_int_t *numerators,
int num_numerators,
8126 timetick_int_t *denominators,
int num_denominators,
8129 if (unit ==
ID2SYM(id_nanosecond)) {
8130 numerators[num_numerators++] = 1000000000;
8131 return timetick2integer(ttp, numerators, num_numerators, denominators, num_denominators);
8133 else if (unit ==
ID2SYM(id_microsecond)) {
8134 numerators[num_numerators++] = 1000000;
8135 return timetick2integer(ttp, numerators, num_numerators, denominators, num_denominators);
8137 else if (unit ==
ID2SYM(id_millisecond)) {
8138 numerators[num_numerators++] = 1000;
8139 return timetick2integer(ttp, numerators, num_numerators, denominators, num_denominators);
8141 else if (unit ==
ID2SYM(id_second)) {
8142 return timetick2integer(ttp, numerators, num_numerators, denominators, num_denominators);
8144 else if (unit ==
ID2SYM(id_float_microsecond)) {
8145 numerators[num_numerators++] = 1000000;
8146 return timetick2dblnum(ttp, numerators, num_numerators, denominators, num_denominators);
8148 else if (unit ==
ID2SYM(id_float_millisecond)) {
8149 numerators[num_numerators++] = 1000;
8150 return timetick2dblnum(ttp, numerators, num_numerators, denominators, num_denominators);
8152 else if (
NIL_P(unit) || unit ==
ID2SYM(id_float_second)) {
8153 return timetick2dblnum(ttp, numerators, num_numerators, denominators, num_denominators);
8156 rb_raise(rb_eArgError,
"unexpected unit: %"PRIsVALUE, unit);
8160static const mach_timebase_info_data_t *
8161get_mach_timebase_info(
void)
8163 static mach_timebase_info_data_t sTimebaseInfo;
8165 if ( sTimebaseInfo.denom == 0 ) {
8166 (void) mach_timebase_info(&sTimebaseInfo);
8169 return &sTimebaseInfo;
8173ruby_real_ms_time(
void)
8175 const mach_timebase_info_data_t *info = get_mach_timebase_info();
8176 uint64_t t = mach_absolute_time();
8177 return (
double)t * info->numer / info->denom / 1e6;
8309rb_clock_gettime(
int argc, VALUE *argv, VALUE
_)
8314 timetick_int_t numerators[2];
8315 timetick_int_t denominators[2];
8316 int num_numerators = 0;
8317 int num_denominators = 0;
8320 VALUE clk_id = argv[0];
8326#ifdef HAVE_GETTIMEOFDAY
8331#define RUBY_GETTIMEOFDAY_BASED_CLOCK_REALTIME ID2SYM(id_GETTIMEOFDAY_BASED_CLOCK_REALTIME)
8332 if (clk_id == RUBY_GETTIMEOFDAY_BASED_CLOCK_REALTIME) {
8334 ret = gettimeofday(&tv, 0);
8337 tt.giga_count = tv.tv_sec;
8338 tt.count = (int32_t)tv.tv_usec * 1000;
8339 denominators[num_denominators++] = 1000000000;
8344#define RUBY_TIME_BASED_CLOCK_REALTIME ID2SYM(id_TIME_BASED_CLOCK_REALTIME)
8345 if (clk_id == RUBY_TIME_BASED_CLOCK_REALTIME) {
8348 if (t == (time_t)-1)
8352 denominators[num_denominators++] = 1000000000;
8357#define RUBY_TIMES_BASED_CLOCK_MONOTONIC \
8358 ID2SYM(id_TIMES_BASED_CLOCK_MONOTONIC)
8359 if (clk_id == RUBY_TIMES_BASED_CLOCK_MONOTONIC) {
8362 unsigned_clock_t uc;
8364 if (c == (clock_t)-1)
8366 uc = (unsigned_clock_t)c;
8367 tt.count = (int32_t)(uc % 1000000000);
8368 tt.giga_count = (uc / 1000000000);
8369 denominators[num_denominators++] = get_clk_tck();
8375#define RUBY_GETRUSAGE_BASED_CLOCK_PROCESS_CPUTIME_ID \
8376 ID2SYM(id_GETRUSAGE_BASED_CLOCK_PROCESS_CPUTIME_ID)
8377 if (clk_id == RUBY_GETRUSAGE_BASED_CLOCK_PROCESS_CPUTIME_ID) {
8378 struct rusage usage;
8380 ret = getrusage(RUSAGE_SELF, &usage);
8383 tt.giga_count = usage.ru_utime.tv_sec + usage.ru_stime.tv_sec;
8384 usec = (int32_t)(usage.ru_utime.tv_usec + usage.ru_stime.tv_usec);
8385 if (1000000 <= usec) {
8389 tt.count = usec * 1000;
8390 denominators[num_denominators++] = 1000000000;
8396#define RUBY_TIMES_BASED_CLOCK_PROCESS_CPUTIME_ID \
8397 ID2SYM(id_TIMES_BASED_CLOCK_PROCESS_CPUTIME_ID)
8398 if (clk_id == RUBY_TIMES_BASED_CLOCK_PROCESS_CPUTIME_ID) {
8400 unsigned_clock_t utime, stime;
8401 if (times(&buf) == (clock_t)-1)
8403 utime = (unsigned_clock_t)buf.tms_utime;
8404 stime = (unsigned_clock_t)buf.tms_stime;
8405 tt.count = (int32_t)((utime % 1000000000) + (stime % 1000000000));
8406 tt.giga_count = (utime / 1000000000) + (stime / 1000000000);
8407 if (1000000000 <= tt.count) {
8408 tt.count -= 1000000000;
8411 denominators[num_denominators++] = get_clk_tck();
8416#define RUBY_CLOCK_BASED_CLOCK_PROCESS_CPUTIME_ID \
8417 ID2SYM(id_CLOCK_BASED_CLOCK_PROCESS_CPUTIME_ID)
8418 if (clk_id == RUBY_CLOCK_BASED_CLOCK_PROCESS_CPUTIME_ID) {
8420 unsigned_clock_t uc;
8423 if (c == (clock_t)-1)
8425 uc = (unsigned_clock_t)c;
8426 tt.count = (int32_t)(uc % 1000000000);
8427 tt.giga_count = uc / 1000000000;
8428 denominators[num_denominators++] = CLOCKS_PER_SEC;
8433#define RUBY_MACH_ABSOLUTE_TIME_BASED_CLOCK_MONOTONIC ID2SYM(id_MACH_ABSOLUTE_TIME_BASED_CLOCK_MONOTONIC)
8434 if (clk_id == RUBY_MACH_ABSOLUTE_TIME_BASED_CLOCK_MONOTONIC) {
8435 const mach_timebase_info_data_t *info = get_mach_timebase_info();
8436 uint64_t t = mach_absolute_time();
8437 tt.count = (int32_t)(t % 1000000000);
8438 tt.giga_count = t / 1000000000;
8439 numerators[num_numerators++] = info->numer;
8440 denominators[num_denominators++] = info->denom;
8441 denominators[num_denominators++] = 1000000000;
8447#if defined(HAVE_CLOCK_GETTIME)
8450 c = NUM2CLOCKID(clk_id);
8451 ret = clock_gettime(c, &ts);
8454 tt.count = (int32_t)ts.tv_nsec;
8455 tt.giga_count = ts.tv_sec;
8456 denominators[num_denominators++] = 1000000000;
8464 return make_clock_result(&tt, numerators, num_numerators, denominators, num_denominators, unit);
8510rb_clock_getres(
int argc, VALUE *argv, VALUE
_)
8513 timetick_int_t numerators[2];
8514 timetick_int_t denominators[2];
8515 int num_numerators = 0;
8516 int num_denominators = 0;
8519 VALUE clk_id = argv[0];
8522#ifdef RUBY_GETTIMEOFDAY_BASED_CLOCK_REALTIME
8523 if (clk_id == RUBY_GETTIMEOFDAY_BASED_CLOCK_REALTIME) {
8526 denominators[num_denominators++] = 1000000000;
8531#ifdef RUBY_TIME_BASED_CLOCK_REALTIME
8532 if (clk_id == RUBY_TIME_BASED_CLOCK_REALTIME) {
8535 denominators[num_denominators++] = 1000000000;
8540#ifdef RUBY_TIMES_BASED_CLOCK_MONOTONIC
8541 if (clk_id == RUBY_TIMES_BASED_CLOCK_MONOTONIC) {
8544 denominators[num_denominators++] = get_clk_tck();
8549#ifdef RUBY_GETRUSAGE_BASED_CLOCK_PROCESS_CPUTIME_ID
8550 if (clk_id == RUBY_GETRUSAGE_BASED_CLOCK_PROCESS_CPUTIME_ID) {
8553 denominators[num_denominators++] = 1000000000;
8558#ifdef RUBY_TIMES_BASED_CLOCK_PROCESS_CPUTIME_ID
8559 if (clk_id == RUBY_TIMES_BASED_CLOCK_PROCESS_CPUTIME_ID) {
8562 denominators[num_denominators++] = get_clk_tck();
8567#ifdef RUBY_CLOCK_BASED_CLOCK_PROCESS_CPUTIME_ID
8568 if (clk_id == RUBY_CLOCK_BASED_CLOCK_PROCESS_CPUTIME_ID) {
8571 denominators[num_denominators++] = CLOCKS_PER_SEC;
8576#ifdef RUBY_MACH_ABSOLUTE_TIME_BASED_CLOCK_MONOTONIC
8577 if (clk_id == RUBY_MACH_ABSOLUTE_TIME_BASED_CLOCK_MONOTONIC) {
8578 const mach_timebase_info_data_t *info = get_mach_timebase_info();
8581 numerators[num_numerators++] = info->numer;
8582 denominators[num_denominators++] = info->denom;
8583 denominators[num_denominators++] = 1000000000;
8589#if defined(HAVE_CLOCK_GETRES)
8591 clockid_t c = NUM2CLOCKID(clk_id);
8592 int ret = clock_getres(c, &ts);
8595 tt.count = (int32_t)ts.tv_nsec;
8596 tt.giga_count = ts.tv_sec;
8597 denominators[num_denominators++] = 1000000000;
8605 if (unit ==
ID2SYM(id_hertz)) {
8606 return timetick2dblnum_reciprocal(&tt, numerators, num_numerators, denominators, num_denominators);
8609 return make_clock_result(&tt, numerators, num_numerators, denominators, num_denominators, unit);
8614get_CHILD_STATUS(ID _x, VALUE *_y)
8620get_PROCESS_ID(ID _x, VALUE *_y)
8662proc_rb_f_kill(
int c,
const VALUE *v, VALUE
_)
8668static VALUE rb_mProcUID;
8669static VALUE rb_mProcGID;
8670static VALUE rb_mProcID_Syscall;
8684 rb_gvar_ractor_local(
"$$");
8685 rb_gvar_ractor_local(
"$?");
8740 process_status_dump, process_status_load);
8776#ifdef HAVE_GETPRIORITY
8787#if defined(RLIM2NUM) && defined(RLIM_INFINITY)
8789 VALUE inf = RLIM2NUM(RLIM_INFINITY);
8790#ifdef RLIM_SAVED_MAX
8792 VALUE v = RLIM_INFINITY == RLIM_SAVED_MAX ? inf : RLIM2NUM(RLIM_SAVED_MAX);
8799#ifdef RLIM_SAVED_CUR
8801 VALUE v = RLIM_INFINITY == RLIM_SAVED_CUR ? inf : RLIM2NUM(RLIM_SAVED_CUR);
8842#ifdef RLIMIT_MEMLOCK
8849#ifdef RLIMIT_MSGQUEUE
8907#ifdef RLIMIT_SIGPENDING
8942#ifdef CLOCK_REALTIME
8945#elif defined(RUBY_GETTIMEOFDAY_BASED_CLOCK_REALTIME)
8949#ifdef CLOCK_MONOTONIC
8952#elif defined(RUBY_MACH_ABSOLUTE_TIME_BASED_CLOCK_MONOTONIC)
8956#ifdef CLOCK_PROCESS_CPUTIME_ID
8959#elif defined(RUBY_GETRUSAGE_BASED_CLOCK_PROCESS_CPUTIME_ID)
8963#ifdef CLOCK_THREAD_CPUTIME_ID
8975#ifdef CLOCK_REALTIME_FAST
8979#ifdef CLOCK_REALTIME_PRECISE
8983#ifdef CLOCK_REALTIME_COARSE
8987#ifdef CLOCK_REALTIME_ALARM
8991#ifdef CLOCK_MONOTONIC_FAST
8995#ifdef CLOCK_MONOTONIC_PRECISE
8999#ifdef CLOCK_MONOTONIC_RAW
9003#ifdef CLOCK_MONOTONIC_RAW_APPROX
9007#ifdef CLOCK_MONOTONIC_COARSE
9011#ifdef CLOCK_BOOTTIME
9015#ifdef CLOCK_BOOTTIME_ALARM
9023#ifdef CLOCK_UPTIME_FAST
9027#ifdef CLOCK_UPTIME_PRECISE
9031#ifdef CLOCK_UPTIME_RAW
9035#ifdef CLOCK_UPTIME_RAW_APPROX
9050#if defined(HAVE_TIMES) || defined(_WIN32)
9055 SAVED_USER_ID = geteuid();
9056 SAVED_GROUP_ID = getegid();
9069 rb_define_alias(rb_singleton_class(rb_mProcUID),
"eid=",
"grant_privilege");
9070 rb_define_alias(rb_singleton_class(rb_mProcGID),
"eid=",
"grant_privilege");
9079#ifdef p_uid_from_name
9082#ifdef p_gid_from_name
9138 id_GETTIMEOFDAY_BASED_CLOCK_REALTIME =
rb_intern_const(
"GETTIMEOFDAY_BASED_CLOCK_REALTIME");
9139 id_TIME_BASED_CLOCK_REALTIME =
rb_intern_const(
"TIME_BASED_CLOCK_REALTIME");
9141 id_TIMES_BASED_CLOCK_MONOTONIC =
rb_intern_const(
"TIMES_BASED_CLOCK_MONOTONIC");
9142 id_TIMES_BASED_CLOCK_PROCESS_CPUTIME_ID =
rb_intern_const(
"TIMES_BASED_CLOCK_PROCESS_CPUTIME_ID");
9145 id_GETRUSAGE_BASED_CLOCK_PROCESS_CPUTIME_ID =
rb_intern_const(
"GETRUSAGE_BASED_CLOCK_PROCESS_CPUTIME_ID");
9147 id_CLOCK_BASED_CLOCK_PROCESS_CPUTIME_ID =
rb_intern_const(
"CLOCK_BASED_CLOCK_PROCESS_CPUTIME_ID");
9149 id_MACH_ABSOLUTE_TIME_BASED_CLOCK_MONOTONIC =
rb_intern_const(
"MACH_ABSOLUTE_TIME_BASED_CLOCK_MONOTONIC");
#define rb_define_singleton_method(klass, mid, func, arity)
Defines klass.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_define_class_under(VALUE outer, const char *name, VALUE super)
Defines a class under the namespace of outer.
VALUE rb_define_module(const char *name)
Defines a top-level module.
VALUE rb_define_module_under(VALUE outer, const char *name)
Defines a module under the namespace of outer.
void rb_define_alias(VALUE klass, const char *name1, const char *name2)
Defines an alias of a method.
void rb_define_module_function(VALUE module, const char *name, VALUE(*func)(ANYARGS), int argc)
Defines a module function for a module.
void rb_undef_method(VALUE klass, const char *name)
Defines an undef of a method.
void rb_define_method(VALUE klass, const char *name, VALUE(*func)(ANYARGS), int argc)
Defines a method.
int rb_block_given_p(void)
Determines if the current method is given a block.
void rb_define_global_function(const char *name, VALUE(*func)(ANYARGS), int argc)
Defines a global function.
#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 T_STRING
Old name of RUBY_T_STRING.
#define Qundef
Old name of RUBY_Qundef.
#define INT2FIX
Old name of RB_INT2FIX.
#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.
void rb_notimplement(void)
void rb_raise(VALUE exc, const char *fmt,...)
Exception entry point.
void rb_exc_raise(VALUE mesg)
Raises an exception in the current thread.
void rb_syserr_fail(int e, const char *mesg)
Raises appropriate exception that represents a C errno.
void rb_bug(const char *fmt,...)
Interpreter panic switch.
void rb_sys_fail(const char *mesg)
Converts a C errno into a Ruby exception, then raises it.
void rb_syserr_fail_str(int e, VALUE mesg)
Identical to rb_syserr_fail(), except it takes the message in Ruby's String instead of C's.
void rb_warn(const char *fmt,...)
Identical to rb_warning(), except it reports always regardless of runtime -W flag.
VALUE rb_ensure(VALUE(*b_proc)(VALUE), VALUE data1, VALUE(*e_proc)(VALUE), VALUE data2)
An equivalent to ensure clause.
void rb_sys_fail_str(VALUE mesg)
Identical to rb_sys_fail(), except it takes the message in Ruby's String instead of C's.
void rb_exit(int status)
Terminates the current execution context.
VALUE rb_mProcess
Process module.
VALUE rb_cThread
Thread class.
#define RB_OBJ_WRITTEN(old, oldv, young)
Identical to RB_OBJ_WRITE(), except it doesn't write any values, but only a WB declaration.
void rb_enc_copy(VALUE dst, VALUE src)
Destructively copies the encoding of the latter object to that of former one.
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.
void rb_jump_tag(int state)
This function is to re-throw global escapes.
VALUE rb_str_encode_ospath(VALUE path)
Converts a string into an "OS Path" encoding, if any.
void rb_gc_mark(VALUE obj)
Marks an object.
int rb_during_gc(void)
Queries if the GC is busy.
void rb_gc(void)
Triggers a GC process.
VALUE rb_check_hash_type(VALUE obj)
Try converting an object to its hash representation using its to_hash method, if any.
VALUE rb_hash_aset(VALUE hash, VALUE key, VALUE val)
Inserts or replaces ("upsert"s) the objects into the given hash table.
VALUE rb_env_clear(void)
Destructively removes every environment variables of the running process.
VALUE rb_hash_lookup(VALUE hash, VALUE key)
Identical to rb_hash_aref(), except it always returns RUBY_Qnil for misshits.
VALUE rb_hash_new(void)
Creates a new, empty hash object.
VALUE rb_io_puts(int argc, const VALUE *argv, VALUE io)
Iterates over the passed array to apply rb_io_write() individually.
int rb_cloexec_dup2(int oldfd, int newfd)
Identical to rb_cloexec_dup(), except you can specify the destination file descriptor.
void rb_update_max_fd(int fd)
Informs the interpreter that the passed fd can be the max.
int rb_cloexec_open(const char *pathname, int flags, mode_t mode)
Opens a file that closes on exec.
void rb_close_before_exec(int lowfd, int maxhint, VALUE noclose_fds)
Closes everything.
int rb_reserved_fd_p(int fd)
Queries if the given FD is reserved or not.
int rb_pipe(int *pipes)
This is an rb_cloexec_pipe() + rb_update_max_fd() combo.
int rb_cloexec_fcntl_dupfd(int fd, int minfd)
Duplicates a file descriptor with closing on exec.
int rb_cloexec_dup(int oldfd)
Identical to rb_cloexec_fcntl_dupfd(), except it implies minfd is 3.
VALUE rb_protect(VALUE(*func)(VALUE args), VALUE args, int *state)
Protects a function call from potential global escapes from the function.
int rb_proc_exec(const char *cmd)
Executes a shell command.
VALUE rb_proc_times(VALUE _)
Gathers info about resources consumed by the current process.
VALUE rb_last_status_get(void)
Queries the "last status", or the $?.
rb_pid_t rb_waitpid(rb_pid_t pid, int *status, int flags)
Waits for a process, with releasing GVL.
rb_pid_t rb_spawn_err(int argc, const VALUE *argv, char *errbuf, size_t buflen)
Identical to rb_spawn(), except you can additionally know the detailed situation in case of abnormal ...
void rb_syswait(rb_pid_t pid)
This is a shorthand of rb_waitpid without status and flags.
VALUE rb_f_exec(int argc, const VALUE *argv)
Replaces the current process by running the given external command.
rb_pid_t rb_spawn(int argc, const VALUE *argv)
Identical to rb_f_exec(), except it spawns a child process instead of replacing the current one.
void rb_last_status_set(int status, rb_pid_t pid)
Sets the "last status", or the $?.
VALUE rb_detach_process(rb_pid_t pid)
"Detaches" a subprocess.
const char * ruby_signal_name(int signo)
Queries the name of the signal.
VALUE rb_f_kill(int argc, const VALUE *argv)
Sends a signal ("kills") to processes.
VALUE rb_str_append(VALUE dst, VALUE src)
Identical to rb_str_buf_append(), except it converts the right hand side before concatenating.
VALUE rb_str_tmp_new(long len)
Allocates a "temporary" string.
VALUE rb_str_subseq(VALUE str, long beg, long len)
Identical to rb_str_substr(), except the numbers are interpreted as byte offsets instead of character...
VALUE rb_str_buf_cat(VALUE, const char *, long)
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_cat2(VALUE, const char *)
Just another name of rb_str_cat_cstr.
VALUE rb_str_dup(VALUE str)
Duplicates a string.
VALUE rb_str_buf_cat2(VALUE, const char *)
Just another name of rb_str_cat_cstr.
void rb_str_set_len(VALUE str, long len)
Overwrites the length of the string.
VALUE rb_str_new(const char *ptr, long len)
Allocates an instance of rb_cString.
VALUE rb_check_string_type(VALUE obj)
Try converting an object to its stringised representation using its to_str method,...
VALUE rb_str_new_cstr(const char *ptr)
Identical to rb_str_new(), except it assumes the passed pointer is a pointer to a C string.
VALUE rb_str_resize(VALUE str, long len)
Overwrites the length of the string.
void rb_str_modify_expand(VALUE str, long capa)
Identical to rb_str_modify(), except it additionally expands the capacity of the receiver.
VALUE rb_str_buf_new(long capa)
Allocates a "string buffer".
VALUE rb_str_cat_cstr(VALUE dst, const char *src)
Identical to rb_str_cat(), 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.
VALUE rb_thread_create(VALUE(*f)(void *g), void *g)
Creates a Ruby thread that is backended by a C function.
void rb_thread_check_ints(void)
Checks for interrupts.
void rb_thread_atfork(void)
A pthread_atfork(3posix)-like API.
VALUE rb_thread_local_aset(VALUE thread, ID key, VALUE val)
This badly named function writes to a Fiber local storage.
#define RUBY_UBF_PROCESS
A special UBF for blocking process operations.
void rb_thread_sleep(int sec)
Blocks for the given period of time.
struct timeval rb_time_interval(VALUE num)
Creates a "time interval".
VALUE rb_attr_get(VALUE obj, ID name)
Identical to rb_ivar_get()
VALUE rb_ivar_set(VALUE obj, ID name, VALUE val)
Identical to rb_iv_set(), except it accepts the name as an ID instead of a C string.
void rb_undef_alloc_func(VALUE klass)
Deletes the allocator function of a class.
void rb_define_alloc_func(VALUE klass, rb_alloc_func_t func)
Sets the allocator function of a class.
static ID rb_intern_const(const char *str)
This is a "tiny optimisation" over rb_intern().
ID rb_check_id(volatile VALUE *namep)
Detects if the given name is already interned or not.
ID rb_intern(const char *name)
Finds or creates a symbol of the given name.
VALUE rb_sym2str(VALUE id)
Identical to rb_id2str(), except it takes an instance of rb_cSymbol rather than an ID.
void rb_define_virtual_variable(const char *name, rb_gvar_getter_t *getter, rb_gvar_setter_t *setter)
Defines a global variable that is purely function-backended.
void rb_define_const(VALUE klass, const char *name, VALUE val)
Defines a Ruby level constant under a namespace.
int rb_io_modestr_oflags(const char *modestr)
Identical to rb_io_modestr_fmode(), except it returns a mixture of O_ flags.
#define GetOpenFile
This is an old name of RB_IO_POINTER.
VALUE rb_io_check_io(VALUE io)
Try converting an object to its IO representation using its to_io method, if any.
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.
void ruby_setenv(const char *key, const char *val)
Sets an environment variable.
#define RB_NUM2INT
Just another name of rb_num2int_inline.
#define RB_INT2NUM
Just another name of rb_int2num_inline.
VALUE rb_sprintf(const char *fmt,...)
Ruby's extended sprintf(3).
VALUE rb_str_catf(VALUE dst, const char *fmt,...)
Identical to rb_sprintf(), except it renders the output to the specified object rather than creating ...
#define RB_BLOCK_CALL_FUNC_ARGLIST(yielded_arg, callback_arg)
Shim for block function parameters.
VALUE rb_block_call(VALUE obj, ID mid, int argc, const VALUE *argv, rb_block_call_func_t proc, VALUE data2)
Identical to rb_funcallv(), except it additionally passes a function as a block.
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.
#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.
VALUE rb_ractor_stderr(void)
Queries the standard error of the current Ractor that is calling this function.
#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 DATA_PTR(obj)
Convenient getter macro.
#define RUBY_DEFAULT_FREE
This is a value you can set to RData::dfree.
#define RHASH_SIZE(h)
Queries the size of the hash.
#define RHASH_EMPTY_P(h)
Checks if the hash is empty.
#define SafeStringValue(v)
#define StringValue(v)
Ensures that the parameter object is a String.
static long RSTRING_LEN(VALUE str)
Queries the length of the string.
static char * RSTRING_PTR(VALUE str)
Queries 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 RTYPEDDATA_DATA(v)
Convenient getter macro.
#define RUBY_TYPED_DEFAULT_FREE
This is a value you can set to rb_data_type_struct::dfree.
#define TypedData_Get_Struct(obj, type, data_type, sval)
Obtains a C struct from inside of a wrapper Ruby object.
#define TypedData_Make_Struct(klass, type, data_type, sval)
Identical to TypedData_Wrap_Struct, except it allocates a new data region internally instead of takin...
const char * rb_class2name(VALUE klass)
Queries the name of the passed class.
#define FilePathValue(v)
Ensures that the parameter object is a path.
#define InitVM(ext)
This macro is for internal use.
VALUE rb_fiber_scheduler_current(void)
Identical to rb_fiber_scheduler_get(), except it also returns RUBY_Qnil in case of a blocking fiber.
VALUE rb_fiber_scheduler_kernel_sleepv(VALUE scheduler, int argc, VALUE *argv)
Identical to rb_fiber_scheduler_kernel_sleep(), except it can pass multiple arguments.
VALUE rb_fiber_scheduler_process_wait(VALUE scheduler, rb_pid_t pid, int flags)
Nonblocking 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.
void rb_native_mutex_lock(rb_nativethread_lock_t *lock)
Just another name of rb_nativethread_lock_lock.
void rb_native_mutex_unlock(rb_nativethread_lock_t *lock)
Just another name of rb_nativethread_lock_unlock.
void rb_native_cond_signal(rb_nativethread_cond_t *cond)
Signals a condition variable.
void rb_native_cond_wait(rb_nativethread_cond_t *cond, rb_nativethread_lock_t *mutex)
Waits for the passed condition variable to be signalled.
#define UIDT2NUM
Converts a C's uid_t into an instance of rb_cInteger.
#define NUM2UIDT
Converts an instance of rb_cNumeric into C's uid_t.
uintptr_t VALUE
Type that represents a Ruby object.
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.
void * ruby_xmalloc(size_t size)
Allocates a storage instance.