14 #include "ruby/internal/config.h"
42 # define EXIT_SUCCESS 0
46 # define EXIT_FAILURE 1
49 #ifdef HAVE_SYS_WAIT_H
50 # include <sys/wait.h>
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
71 #ifdef HAVE_SYS_TIME_H
72 # include <sys/time.h>
75 #ifdef HAVE_SYS_TIMES_H
76 # include <sys/times.h>
86 int initgroups(
const char *, rb_gid_t);
95 # include <mach/mach_time.h>
100 #include "internal.h"
101 #include "internal/bits.h"
102 #include "internal/dir.h"
103 #include "internal/error.h"
104 #include "internal/eval.h"
105 #include "internal/hash.h"
106 #include "internal/io.h"
107 #include "internal/numeric.h"
108 #include "internal/object.h"
109 #include "internal/process.h"
110 #include "internal/thread.h"
111 #include "internal/variable.h"
112 #include "internal/warnings.h"
125 #define open rb_w32_uopen
128 #if defined(HAVE_TIMES) || defined(_WIN32)
135 static VALUE rb_cProcessTms;
139 #define WIFEXITED(w) (((w) & 0xff) == 0)
142 #define WIFSIGNALED(w) (((w) & 0x7f) > 0 && (((w) & 0x7f) < 0x7f))
145 #define WIFSTOPPED(w) (((w) & 0xff) == 0x7f)
148 #define WEXITSTATUS(w) (((w) >> 8) & 0xff)
151 #define WTERMSIG(w) ((w) & 0x7f)
154 #define WSTOPSIG WEXITSTATUS
157 #if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__bsdi__)
158 #define HAVE_44BSD_SETUID 1
159 #define HAVE_44BSD_SETGID 1
167 #ifdef BROKEN_SETREUID
168 #define setreuid ruby_setreuid
169 int setreuid(rb_uid_t ruid, rb_uid_t euid);
171 #ifdef BROKEN_SETREGID
172 #define setregid ruby_setregid
173 int setregid(rb_gid_t rgid, rb_gid_t egid);
176 #if defined(HAVE_44BSD_SETUID) || defined(__APPLE__)
177 #if !defined(USE_SETREUID) && !defined(BROKEN_SETREUID)
178 #define OBSOLETE_SETREUID 1
180 #if !defined(USE_SETREGID) && !defined(BROKEN_SETREGID)
181 #define OBSOLETE_SETREGID 1
185 static void check_uid_switch(
void);
186 static void check_gid_switch(
void);
187 static int exec_async_signal_safe(
const struct rb_execarg *,
char *,
size_t);
189 VALUE rb_envtbl(
void);
190 VALUE rb_env_to_hash(
void);
193 #define p_uid_from_name p_uid_from_name
194 #define p_gid_from_name p_gid_from_name
197 #if defined(HAVE_UNISTD_H)
198 # if defined(HAVE_GETLOGIN_R)
199 # define USE_GETLOGIN_R 1
200 # define GETLOGIN_R_SIZE_DEFAULT 0x100
201 # define GETLOGIN_R_SIZE_LIMIT 0x1000
202 # if defined(_SC_LOGIN_NAME_MAX)
203 # define GETLOGIN_R_SIZE_INIT sysconf(_SC_LOGIN_NAME_MAX)
205 # define GETLOGIN_R_SIZE_INIT GETLOGIN_R_SIZE_DEFAULT
207 # elif defined(HAVE_GETLOGIN)
208 # define USE_GETLOGIN 1
212 #if defined(HAVE_PWD_H)
213 # if defined(HAVE_GETPWUID_R)
214 # define USE_GETPWUID_R 1
215 # elif defined(HAVE_GETPWUID)
216 # define USE_GETPWUID 1
218 # if defined(HAVE_GETPWNAM_R)
219 # define USE_GETPWNAM_R 1
220 # elif defined(HAVE_GETPWNAM)
221 # define USE_GETPWNAM 1
223 # if defined(HAVE_GETPWNAM_R) || defined(HAVE_GETPWUID_R)
224 # define GETPW_R_SIZE_DEFAULT 0x1000
225 # define GETPW_R_SIZE_LIMIT 0x10000
226 # if defined(_SC_GETPW_R_SIZE_MAX)
227 # define GETPW_R_SIZE_INIT sysconf(_SC_GETPW_R_SIZE_MAX)
229 # define GETPW_R_SIZE_INIT GETPW_R_SIZE_DEFAULT
232 # ifdef USE_GETPWNAM_R
233 # define PREPARE_GETPWNAM \
235 # define FINISH_GETPWNAM \
236 (getpw_buf ? (void)rb_str_resize(getpw_buf, 0) : (void)0)
237 # define OBJ2UID1(id) obj2uid((id), &getpw_buf)
238 # define OBJ2UID(id) obj2uid0(id)
239 static rb_uid_t obj2uid(
VALUE id,
VALUE *getpw_buf);
240 static inline rb_uid_t
250 # define PREPARE_GETPWNAM
251 # define FINISH_GETPWNAM
252 # define OBJ2UID1(id) obj2uid((id))
253 # define OBJ2UID(id) obj2uid((id))
254 static rb_uid_t obj2uid(
VALUE id);
257 # define PREPARE_GETPWNAM
258 # define FINISH_GETPWNAM
259 # define OBJ2UID1(id) NUM2UIDT(id)
260 # define OBJ2UID(id) NUM2UIDT(id)
261 # ifdef p_uid_from_name
262 # undef p_uid_from_name
263 # define p_uid_from_name rb_f_notimplement
267 #if defined(HAVE_GRP_H)
268 # if defined(HAVE_GETGRNAM_R) && defined(_SC_GETGR_R_SIZE_MAX)
269 # define USE_GETGRNAM_R
270 # define GETGR_R_SIZE_INIT sysconf(_SC_GETGR_R_SIZE_MAX)
271 # define GETGR_R_SIZE_DEFAULT 0x1000
272 # define GETGR_R_SIZE_LIMIT 0x10000
274 # ifdef USE_GETGRNAM_R
275 # define PREPARE_GETGRNAM \
277 # define FINISH_GETGRNAM \
278 (getgr_buf ? (void)rb_str_resize(getgr_buf, 0) : (void)0)
279 # define OBJ2GID1(id) obj2gid((id), &getgr_buf)
280 # define OBJ2GID(id) obj2gid0(id)
281 static rb_gid_t obj2gid(
VALUE id,
VALUE *getgr_buf);
282 static inline rb_gid_t
291 static rb_gid_t obj2gid(
VALUE id,
VALUE *getgr_buf);
293 # define PREPARE_GETGRNAM
294 # define FINISH_GETGRNAM
295 # define OBJ2GID1(id) obj2gid((id))
296 # define OBJ2GID(id) obj2gid((id))
297 static rb_gid_t obj2gid(
VALUE id);
300 # define PREPARE_GETGRNAM
301 # define FINISH_GETGRNAM
302 # define OBJ2GID1(id) NUM2GIDT(id)
303 # define OBJ2GID(id) NUM2GIDT(id)
304 # ifdef p_gid_from_name
305 # undef p_gid_from_name
306 # define p_gid_from_name rb_f_notimplement
310 #if SIZEOF_CLOCK_T == SIZEOF_INT
311 typedef unsigned int unsigned_clock_t;
312 #elif SIZEOF_CLOCK_T == SIZEOF_LONG
313 typedef unsigned long unsigned_clock_t;
314 #elif defined(HAVE_LONG_LONG) && SIZEOF_CLOCK_T == SIZEOF_LONG_LONG
315 typedef unsigned LONG_LONG unsigned_clock_t;
318 typedef void (*sig_t) (int);
321 #define id_exception idException
322 static ID id_in, id_out, id_err, id_pid, id_uid, id_gid;
323 static ID id_close, id_child;
328 static ID id_new_pgroup;
330 static ID id_unsetenv_others, id_chdir, id_umask, id_close_others;
331 static ID id_nanosecond, id_microsecond, id_millisecond, id_second;
332 static ID id_float_microsecond, id_float_millisecond, id_float_second;
333 static ID id_GETTIMEOFDAY_BASED_CLOCK_REALTIME, id_TIME_BASED_CLOCK_REALTIME;
334 #ifdef CLOCK_REALTIME
335 static ID id_CLOCK_REALTIME;
336 # define RUBY_CLOCK_REALTIME ID2SYM(id_CLOCK_REALTIME)
338 #ifdef CLOCK_MONOTONIC
339 static ID id_CLOCK_MONOTONIC;
340 # define RUBY_CLOCK_MONOTONIC ID2SYM(id_CLOCK_MONOTONIC)
342 #ifdef CLOCK_PROCESS_CPUTIME_ID
343 static ID id_CLOCK_PROCESS_CPUTIME_ID;
344 # define RUBY_CLOCK_PROCESS_CPUTIME_ID ID2SYM(id_CLOCK_PROCESS_CPUTIME_ID)
346 #ifdef CLOCK_THREAD_CPUTIME_ID
347 static ID id_CLOCK_THREAD_CPUTIME_ID;
348 # define RUBY_CLOCK_THREAD_CPUTIME_ID ID2SYM(id_CLOCK_THREAD_CPUTIME_ID)
351 static ID id_TIMES_BASED_CLOCK_MONOTONIC;
352 static ID id_TIMES_BASED_CLOCK_PROCESS_CPUTIME_ID;
355 static ID id_GETRUSAGE_BASED_CLOCK_PROCESS_CPUTIME_ID;
357 static ID id_CLOCK_BASED_CLOCK_PROCESS_CPUTIME_ID;
359 static ID id_MACH_ABSOLUTE_TIME_BASED_CLOCK_MONOTONIC;
360 # define RUBY_MACH_ABSOLUTE_TIME_BASED_CLOCK_MONOTONIC ID2SYM(id_MACH_ABSOLUTE_TIME_BASED_CLOCK_MONOTONIC)
364 static rb_pid_t cached_pid;
367 #if defined(__sun) && !defined(_XPG7)
368 #define execv(path, argv) (rb_async_bug_errno("unreachable: async-signal-unsafe execv() is called", 0))
369 #define execl(path, arg0, arg1, arg2, term) do { extern char **environ; execle((path), (arg0), (arg1), (arg2), (term), (environ)); } while (0)
370 #define ALWAYS_NEED_ENVP 1
372 #define ALWAYS_NEED_ENVP 0
376 assert_close_on_exec(
int fd)
378 #if VM_CHECK_MODE > 0
379 #if defined(HAVE_FCNTL) && defined(F_GETFD) && defined(FD_CLOEXEC)
380 int flags = fcntl(fd, F_GETFD);
382 static const char m[] =
"reserved FD closed unexpectedly?\n";
383 (void)!write(2, m,
sizeof(m) - 1);
386 if (flags & FD_CLOEXEC)
return;
387 rb_bug(
"reserved FD did not have close-on-exec set");
389 rb_bug(
"reserved FD without close-on-exec support");
395 close_unless_reserved(
int fd)
398 assert_close_on_exec(fd);
405 #if defined(DEBUG_REDIRECT)
408 ttyprintf(
const char *fmt, ...)
414 tty = fopen(
"con",
"w");
416 tty = fopen(
"/dev/tty",
"w");
422 vfprintf(tty, fmt, ap);
429 redirect_dup(
int oldfd)
433 ttyprintf(
"dup(%d) => %d\n", oldfd, ret);
438 redirect_dup2(
int oldfd,
int newfd)
441 ret = dup2(oldfd, newfd);
442 ttyprintf(
"dup2(%d, %d) => %d\n", oldfd, newfd, ret);
447 redirect_cloexec_dup(
int oldfd)
451 ttyprintf(
"cloexec_dup(%d) => %d\n", oldfd, ret);
456 redirect_cloexec_dup2(
int oldfd,
int newfd)
460 ttyprintf(
"cloexec_dup2(%d, %d) => %d\n", oldfd, newfd, ret);
465 redirect_close(
int fd)
468 ret = close_unless_reserved(fd);
469 ttyprintf(
"close(%d) => %d\n", fd, ret);
474 parent_redirect_open(
const char *pathname,
int flags, mode_t perm)
478 ttyprintf(
"parent_open(\"%s\", 0x%x, 0%o) => %d\n", pathname, flags, perm, ret);
483 parent_redirect_close(
int fd)
486 ret = close_unless_reserved(fd);
487 ttyprintf(
"parent_close(%d) => %d\n", fd, ret);
492 #define redirect_dup(oldfd) dup(oldfd)
493 #define redirect_dup2(oldfd, newfd) dup2((oldfd), (newfd))
494 #define redirect_cloexec_dup(oldfd) rb_cloexec_dup(oldfd)
495 #define redirect_cloexec_dup2(oldfd, newfd) rb_cloexec_dup2((oldfd), (newfd))
496 #define redirect_close(fd) close_unless_reserved(fd)
497 #define parent_redirect_open(pathname, flags, perm) rb_cloexec_open((pathname), (flags), (perm))
498 #define parent_redirect_close(fd) close_unless_reserved(fd)
504 if (UNLIKELY(!cached_pid)) {
505 cached_pid = getpid();
511 #if defined HAVE_WORKING_FORK || defined HAVE_DAEMON
513 clear_pid_cache(
void)
585 static VALUE rb_cProcessStatus;
600 .flags = RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED | RUBY_TYPED_EMBEDDABLE,
604 rb_process_status_allocate(
VALUE klass)
613 return GET_THREAD()->last_status;
639 proc_s_last_status(
VALUE mod)
645 rb_process_status_new(rb_pid_t pid,
int status,
int error)
647 VALUE last_status = rb_process_status_allocate(rb_cProcessStatus);
650 data->status = status;
658 process_status_dump(
VALUE status)
671 process_status_load(
VALUE real_obj,
VALUE load_obj)
684 GET_THREAD()->last_status = rb_process_status_new(pid, status, 0);
690 th->last_status =
Qnil;
694 rb_last_status_clear(
void)
696 last_status_clear(GET_THREAD());
700 pst_pid(
VALUE status)
708 pst_status(
VALUE status)
728 int status = pst_status(
self);
732 #define PST2INT(st) pst_status(st)
746 pst_pid_m(
VALUE self)
748 rb_pid_t pid = pst_pid(
self);
752 static VALUE pst_message_status(
VALUE str,
int status);
755 pst_message(
VALUE str, rb_pid_t pid,
int status)
758 pst_message_status(str, status);
762 pst_message_status(
VALUE str,
int status)
764 if (WIFSTOPPED(status)) {
765 int stopsig = WSTOPSIG(status);
768 rb_str_catf(str,
" stopped SIG%s (signal %d)", signame, stopsig);
774 if (WIFSIGNALED(status)) {
775 int termsig = WTERMSIG(status);
778 rb_str_catf(str,
" SIG%s (signal %d)", signame, termsig);
784 if (WIFEXITED(status)) {
788 if (WCOREDUMP(status)) {
816 status = PST2INT(st);
819 pst_message(str, pid, status);
836 pst_inspect(
VALUE st)
846 status = PST2INT(st);
849 pst_message(str, pid, status);
871 if (st1 == st2)
return Qtrue;
872 return rb_equal(pst_to_i(st1), st2);
897 int status = PST2INT(st1);
903 #define WARN_SUGGEST(suggest) \
904 rb_warn_deprecated_to_remove_at(3.5, "Process::Status#&", suggest)
908 WARN_SUGGEST(
"Process::Status#coredump?");
911 WARN_SUGGEST(
"Process::Status#signaled? or Process::Status#termsig");
914 WARN_SUGGEST(
"Process::Status#exited?, Process::Status#stopped? or Process::Status#coredump?");
917 WARN_SUGGEST(
"Process::Status#exitstatus or Process::Status#stopsig");
920 WARN_SUGGEST(
"other Process::Status predicates");
952 int status = PST2INT(st1);
958 #define WARN_SUGGEST(suggest) \
959 rb_warn_deprecated_to_remove_at(3.5, "Process::Status#>>", suggest)
963 WARN_SUGGEST(
"Process::Status#coredump?");
966 WARN_SUGGEST(
"Process::Status#exitstatus or Process::Status#stopsig");
969 WARN_SUGGEST(
"other Process::Status attributes");
989 pst_wifstopped(
VALUE st)
991 int status = PST2INT(st);
993 return RBOOL(WIFSTOPPED(status));
1006 pst_wstopsig(
VALUE st)
1008 int status = PST2INT(st);
1010 if (WIFSTOPPED(status))
1011 return INT2NUM(WSTOPSIG(status));
1025 pst_wifsignaled(
VALUE st)
1027 int status = PST2INT(st);
1029 return RBOOL(WIFSIGNALED(status));
1042 pst_wtermsig(
VALUE st)
1044 int status = PST2INT(st);
1046 if (WIFSIGNALED(status))
1047 return INT2NUM(WTERMSIG(status));
1062 pst_wifexited(
VALUE st)
1064 int status = PST2INT(st);
1066 return RBOOL(WIFEXITED(status));
1084 pst_wexitstatus(
VALUE st)
1086 int status = PST2INT(st);
1088 if (WIFEXITED(status))
1089 return INT2NUM(WEXITSTATUS(status));
1107 pst_success_p(
VALUE st)
1109 int status = PST2INT(st);
1111 if (!WIFEXITED(status))
1113 return RBOOL(WEXITSTATUS(status) == EXIT_SUCCESS);
1128 pst_wcoredump(
VALUE st)
1131 int status = PST2INT(st);
1133 return RBOOL(WCOREDUMP(status));
1140 do_waitpid(rb_pid_t pid,
int *st,
int flags)
1142 #if defined HAVE_WAITPID
1143 return waitpid(pid, st, flags);
1144 #elif defined HAVE_WAIT4
1145 return wait4(pid, st, flags, NULL);
1147 # error waitpid or wait4 is required.
1152 struct ccan_list_node wnode;
1154 rb_nativethread_cond_t *cond;
1163 waitpid_state_init(
struct waitpid_state *w, rb_pid_t pid,
int options)
1167 w->options = options;
1173 waitpid_blocking_no_SIGCHLD(
void *x)
1177 w->ret = do_waitpid(w->pid, &w->status, w->options);
1185 if (w->options & WNOHANG) {
1186 w->ret = do_waitpid(w->pid, &w->status, w->options);
1191 }
while (w->ret < 0 &&
errno == EINTR && (RUBY_VM_CHECK_INTS(w->ec),1));
1201 if (!(flags & WNOHANG)) {
1204 if (!UNDEF_P(result))
return result;
1250 rb_process_status_waitv(
int argc,
VALUE *argv,
VALUE _)
1272 if (
NIL_P(status))
return 0;
1277 if (st) *st = data->status;
1280 errno = data->error;
1283 GET_THREAD()->last_status = status;
1290 proc_wait(
int argc,
VALUE *argv)
1302 if (argc == 2 && !
NIL_P(vflags = argv[1])) {
1307 if ((pid =
rb_waitpid(pid, &status, flags)) < 0)
1311 rb_last_status_clear();
1468 return proc_wait(c, v);
1488 VALUE pid = proc_wait(argc, argv);
1517 rb_last_status_clear();
1532 static VALUE rb_cWaiter;
1535 detach_process_pid(
VALUE thread)
1541 detach_process_watcher(
void *arg)
1543 rb_pid_t cpid, pid = (rb_pid_t)(
VALUE)arg;
1546 while ((cpid =
rb_waitpid(pid, &status, 0)) == 0) {
1557 RBASIC_SET_CLASS(watcher, rb_cWaiter);
1609 before_exec_async_signal_safe(
void)
1614 before_exec_non_async_signal_safe(
void)
1625 rb_thread_stop_timer_thread();
1628 #define WRITE_CONST(fd, str) (void)(write((fd),(str),sizeof(str)-1)<0)
1630 int rb_w32_set_nonblock2(
int fd,
int nonblock);
1634 set_blocking(
int fd)
1637 return rb_w32_set_nonblock2(fd, 0);
1638 #elif defined(F_GETFL) && defined(F_SETFL)
1639 int fl = fcntl(fd, F_GETFL);
1642 if (fl == -1)
return fl;
1643 if (fl & O_NONBLOCK) {
1645 return fcntl(fd, F_SETFL, fl);
1652 stdfd_clear_nonblock(
void)
1656 for (fd = 0; fd < 3; fd++) {
1657 (void)set_blocking(fd);
1664 before_exec_non_async_signal_safe();
1665 before_exec_async_signal_safe();
1671 rb_thread_reset_timer_thread();
1672 rb_thread_start_timer_thread();
1675 #if defined HAVE_WORKING_FORK || defined HAVE_DAEMON
1677 before_fork_ruby(
void)
1679 rb_gc_before_fork();
1684 after_fork_ruby(rb_pid_t pid)
1686 rb_gc_after_fork(pid);
1700 #if defined(HAVE_WORKING_FORK)
1702 COMPILER_WARNING_PUSH
1703 #if __has_warning("-Wdeprecated-declarations") || RBIMPL_COMPILER_IS(GCC)
1704 COMPILER_WARNING_IGNORED(-Wdeprecated-declarations)
1706 static inline rb_pid_t
1711 COMPILER_WARNING_POP
1714 #define try_with_sh(err, prog, argv, envp) ((err == ENOEXEC) ? exec_with_sh((prog), (argv), (envp)) : (void)0)
1716 exec_with_sh(
const char *prog,
char **argv,
char **envp)
1718 *argv = (
char *)prog;
1719 *--argv = (
char *)
"sh";
1721 execve(
"/bin/sh", argv, envp);
1723 execv(
"/bin/sh", argv);
1727 #define try_with_sh(err, prog, argv, envp) (void)0
1732 proc_exec_cmd(
const char *prog,
VALUE argv_str,
VALUE envp_str)
1740 argv = ARGVSTR2ARGV(argv_str);
1747 rb_w32_uaspawn(P_OVERLAY, prog, argv);
1750 envp = envp_str ? RB_IMEMO_TMPBUF_PTR(envp_str) : NULL;
1752 execve(prog, argv, envp);
1756 try_with_sh(err, prog, argv, envp);
1763 proc_exec_sh(
const char *str,
VALUE envp_str)
1768 while (*s ==
' ' || *s ==
'\t' || *s ==
'\n')
1776 rb_w32_uspawn(P_OVERLAY, (
char *)str, 0);
1777 #elif defined(__CYGWIN32__)
1779 char fbuf[MAXPATHLEN];
1780 char *shell = dln_find_exe_r(
"sh", 0, fbuf,
sizeof(fbuf));
1783 execl(shell,
"sh",
"-c", str, (
char *) NULL);
1785 status = system(str);
1791 execle(
"/bin/sh",
"sh",
"-c", str, (
char *)NULL, RB_IMEMO_TMPBUF_PTR(envp_str));
1793 execl(
"/bin/sh",
"sh",
"-c", str, (
char *)NULL);
1803 ret = proc_exec_sh(str,
Qfalse);
1810 mark_exec_arg(
void *
ptr)
1813 if (eargp->use_shell)
1817 rb_gc_mark(eargp->invoke.cmd.command_abspath);
1836 memsize_exec_arg(
const void *
ptr)
1844 0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_EMBEDDABLE
1848 # define DEFAULT_PROCESS_ENCODING rb_utf8_encoding()
1850 #ifdef DEFAULT_PROCESS_ENCODING
1851 # define EXPORT_STR(str) rb_str_export_to_enc((str), DEFAULT_PROCESS_ENCODING)
1852 # define EXPORT_DUP(str) export_dup(str)
1854 export_dup(
VALUE str)
1856 VALUE newstr = EXPORT_STR(str);
1861 # define EXPORT_STR(str) (str)
1862 # define EXPORT_DUP(str) rb_str_dup(str)
1865 #if !defined(HAVE_WORKING_FORK) && defined(HAVE_SPAWNV)
1866 # define USE_SPAWNV 1
1868 # define USE_SPAWNV 0
1871 # define P_NOWAIT _P_NOWAIT
1876 #define proc_spawn_cmd_internal(argv, prog) rb_w32_uaspawn(P_NOWAIT, (prog), (argv))
1879 proc_spawn_cmd_internal(
char **argv,
char *prog)
1881 char fbuf[MAXPATHLEN];
1886 prog = dln_find_exe_r(prog, 0, fbuf,
sizeof(fbuf));
1891 status = spawnv(P_NOWAIT, prog, (
const char **)argv);
1892 if (status == -1 &&
errno == ENOEXEC) {
1893 *argv = (
char *)prog;
1894 *--argv = (
char *)
"sh";
1895 status = spawnv(P_NOWAIT,
"/bin/sh", (
const char **)argv);
1897 if (status == -1)
errno = ENOEXEC;
1911 if (eargp->new_pgroup_given && eargp->new_pgroup_flag) {
1912 flags = CREATE_NEW_PROCESS_GROUP;
1914 pid = rb_w32_uaspawn_flags(P_NOWAIT, prog ?
RSTRING_PTR(prog) : 0, argv, flags);
1916 pid = proc_spawn_cmd_internal(argv, prog ?
RSTRING_PTR(prog) : 0);
1923 #define proc_spawn_sh(str) rb_w32_uspawn(P_NOWAIT, (str), 0)
1926 proc_spawn_sh(
char *str)
1928 char fbuf[MAXPATHLEN];
1931 char *shell = dln_find_exe_r(
"sh", 0, fbuf,
sizeof(fbuf));
1933 status = spawnl(P_NOWAIT, (shell ? shell :
"/bin/sh"),
"sh",
"-c", str, (
char*)NULL);
1943 RBASIC_CLEAR_CLASS(obj);
1948 check_exec_redirect_fd(
VALUE v,
int iskey)
1959 else if (
id == id_out)
1961 else if (
id == id_err)
1980 else if (fd >= 3 && iskey) {
1998 VALUE fd = check_exec_redirect_fd(key, !
NIL_P(param));
2005 VALUE fd = check_exec_redirect_fd(v, !
NIL_P(param));
2016 VALUE path, flags, perm;
2020 switch (
TYPE(val)) {
2023 if (
id == id_close) {
2025 eargp->fd_close = check_exec_redirect1(eargp->fd_close, key, param);
2027 else if (
id == id_in) {
2029 eargp->fd_dup2 = check_exec_redirect1(eargp->fd_dup2, key, param);
2031 else if (
id == id_out) {
2033 eargp->fd_dup2 = check_exec_redirect1(eargp->fd_dup2, key, param);
2035 else if (
id == id_err) {
2037 eargp->fd_dup2 = check_exec_redirect1(eargp->fd_dup2, key, param);
2047 val = check_exec_redirect_fd(val, 0);
2051 eargp->fd_dup2 = check_exec_redirect1(eargp->fd_dup2, key, param);
2057 path ==
ID2SYM(id_child)) {
2058 param = check_exec_redirect_fd(
rb_ary_entry(val, 1), 0);
2059 eargp->fd_dup2_child = check_exec_redirect1(eargp->fd_dup2_child, key, param);
2072 param = hide_obj(
rb_ary_new3(4, hide_obj(EXPORT_DUP(path)),
2073 flags, perm,
Qnil));
2074 eargp->fd_open = check_exec_redirect1(eargp->fd_open, key, param);
2082 key = check_exec_redirect_fd(key, 1);
2084 flags =
INT2NUM(O_WRONLY|O_CREAT|O_TRUNC);
2089 VALUE fd = check_exec_redirect_fd(v, 1);
2093 flags =
INT2NUM(O_WRONLY|O_CREAT|O_TRUNC);
2100 param = hide_obj(
rb_ary_new3(4, hide_obj(EXPORT_DUP(path)),
2101 flags, perm,
Qnil));
2102 eargp->fd_open = check_exec_redirect1(eargp->fd_open, key, param);
2108 if (!
NIL_P(val))
goto io;
2114 #if defined(HAVE_SETRLIMIT) && defined(NUM2RLIM)
2115 static int rlimit_type_by_sym(
VALUE key);
2118 rb_execarg_addopt_rlimit(
struct rb_execarg *eargp,
int rtype,
VALUE val)
2120 VALUE ary = eargp->rlimit_limits;
2121 VALUE tmp, softlim, hardlim;
2122 if (eargp->rlimit_limits ==
Qfalse)
2123 ary = eargp->rlimit_limits = hide_obj(
rb_ary_new());
2125 ary = eargp->rlimit_limits;
2146 #define TO_BOOL(val, name) (NIL_P(val) ? 0 : rb_bool_expected((val), name, TRUE))
2150 struct rb_execarg *eargp = rb_execarg_get(execarg_obj);
2154 switch (
TYPE(key)) {
2156 #if defined(HAVE_SETRLIMIT) && defined(NUM2RLIM)
2158 int rtype = rlimit_type_by_sym(key);
2160 rb_execarg_addopt_rlimit(eargp, rtype, val);
2168 if (
id == id_pgroup) {
2170 if (eargp->pgroup_given) {
2175 else if (val ==
Qtrue)
2183 eargp->pgroup_given = 1;
2184 eargp->pgroup_pgid = pgroup;
2189 if (
id == id_new_pgroup) {
2190 if (eargp->new_pgroup_given) {
2193 eargp->new_pgroup_given = 1;
2194 eargp->new_pgroup_flag = TO_BOOL(val,
"new_pgroup");
2198 if (
id == id_unsetenv_others) {
2199 if (eargp->unsetenv_others_given) {
2202 eargp->unsetenv_others_given = 1;
2203 eargp->unsetenv_others_do = TO_BOOL(val,
"unsetenv_others");
2205 else if (
id == id_chdir) {
2206 if (eargp->chdir_given) {
2211 eargp->chdir_given = 1;
2212 eargp->chdir_dir = hide_obj(EXPORT_DUP(val));
2214 else if (
id == id_umask) {
2216 if (eargp->umask_given) {
2219 eargp->umask_given = 1;
2220 eargp->umask_mask = cmask;
2222 else if (
id == id_close_others) {
2223 if (eargp->close_others_given) {
2226 eargp->close_others_given = 1;
2227 eargp->close_others_do = TO_BOOL(val,
"close_others");
2229 else if (
id == id_in) {
2233 else if (
id == id_out) {
2237 else if (
id == id_err) {
2241 else if (
id == id_uid) {
2243 if (eargp->uid_given) {
2248 eargp->uid = OBJ2UID(val);
2249 eargp->uid_given = 1;
2253 "uid option is unimplemented on this machine");
2256 else if (
id == id_gid) {
2258 if (eargp->gid_given) {
2263 eargp->gid = OBJ2GID(val);
2264 eargp->gid_given = 1;
2268 "gid option is unimplemented on this machine");
2271 else if (
id == id_exception) {
2272 if (eargp->exception_given) {
2275 eargp->exception_given = 1;
2276 eargp->exception = TO_BOOL(val,
"exception");
2287 check_exec_redirect(key, val, eargp);
2299 check_exec_options_i(st_data_t st_key, st_data_t st_val, st_data_t arg)
2304 if (rb_execarg_addopt(execarg_obj, key, val) != ST_CONTINUE) {
2314 check_exec_options_i_extract(st_data_t st_key, st_data_t st_val, st_data_t arg)
2319 VALUE execarg_obj = args[0];
2320 if (rb_execarg_addopt(execarg_obj, key, val) != ST_CONTINUE) {
2321 VALUE nonopts = args[1];
2340 if (ary == eargp->fd_dup2)
2342 else if (ary == eargp->fd_dup2_child)
2348 if (ary == eargp->fd_dup2 || ary == eargp->fd_dup2_child) {
2366 maxhint = check_exec_fds_1(eargp, h, maxhint, eargp->fd_dup2);
2367 maxhint = check_exec_fds_1(eargp, h, maxhint, eargp->fd_close);
2368 maxhint = check_exec_fds_1(eargp, h, maxhint, eargp->fd_dup2_child);
2370 if (eargp->fd_dup2_child) {
2371 ary = eargp->fd_dup2_child;
2388 if (oldfd != lastfd) {
2401 eargp->close_others_maxhint = maxhint;
2406 rb_check_exec_options(
VALUE opthash,
VALUE execarg_obj)
2410 rb_hash_stlike_foreach(opthash, check_exec_options_i, (st_data_t)execarg_obj);
2414 rb_execarg_extract_options(
VALUE execarg_obj,
VALUE opthash)
2419 args[0] = execarg_obj;
2421 rb_hash_stlike_foreach(opthash, check_exec_options_i_extract, (st_data_t)args);
2425 #ifdef ENV_IGNORECASE
2426 #define ENVMATCH(s1, s2) (STRCASECMP((s1), (s2)) == 0)
2428 #define ENVMATCH(n1, n2) (strcmp((n1), (n2)) == 0)
2432 check_exec_env_i(st_data_t st_key, st_data_t st_val, st_data_t arg)
2447 key = EXPORT_STR(key);
2448 if (!
NIL_P(val)) val = EXPORT_STR(val);
2465 rb_hash_stlike_foreach(hash, check_exec_env_i, (st_data_t)env);
2472 rb_check_argv(
int argc,
VALUE *argv)
2491 for (i = 0; i < argc; i++) {
2500 check_hash(
VALUE obj)
2514 rb_exec_getargs(
int *argc_p,
VALUE **argv_p,
int accept_shell,
VALUE *env_ret,
VALUE *opthash_ret)
2519 hash = check_hash((*argv_p)[*argc_p-1]);
2521 *opthash_ret = hash;
2527 hash = check_hash((*argv_p)[0]);
2534 prog = rb_check_argv(*argc_p, *argv_p);
2536 prog = (*argv_p)[0];
2537 if (accept_shell && *argc_p == 1) {
2552 compare_posix_sh(
const void *key,
const void *el)
2555 int ret = strncmp(word->ptr, el, word->len);
2556 if (!ret && ((
const char *)el)[word->len]) ret = -1;
2564 struct rb_execarg *eargp = rb_execarg_get(execarg_obj);
2565 char fbuf[MAXPATHLEN];
2569 if (!
NIL_P(opthash)) {
2570 rb_check_exec_options(opthash, execarg_obj);
2573 env = rb_check_exec_env(env, &eargp->path_env);
2574 eargp->env_modification = env;
2577 prog = EXPORT_STR(prog);
2578 eargp->use_shell = argc == 0;
2579 if (eargp->use_shell)
2580 eargp->invoke.sh.shell_script = prog;
2582 eargp->invoke.cmd.command_name = prog;
2585 if (eargp->use_shell) {
2586 static const char posix_sh_cmds[][9] = {
2645 if (*p ==
' ' || *p ==
'\t') {
2646 if (first.ptr && !first.len) first.len = p - first.ptr;
2649 if (!first.ptr) first.ptr = p;
2651 if (!has_meta && strchr(
"*?{}[]<>()~&|\\$;'`\"\n#", *p))
2657 else if (*p ==
'/') {
2664 if (!has_meta && first.ptr) {
2665 if (!first.len) first.len = p - first.ptr;
2666 if (first.len > 0 && first.len <=
sizeof(posix_sh_cmds[0]) &&
2667 bsearch(&first, posix_sh_cmds, numberof(posix_sh_cmds),
sizeof(posix_sh_cmds[0]), compare_posix_sh))
2672 eargp->use_shell = 0;
2674 if (!eargp->use_shell) {
2679 while (*p ==
' ' || *p ==
'\t')
2683 while (*p && *p !=
' ' && *p !=
'\t')
2689 eargp->invoke.cmd.argv_buf = argv_buf;
2690 eargp->invoke.cmd.command_name =
2692 rb_enc_copy(eargp->invoke.cmd.command_name, prog);
2697 if (!eargp->use_shell) {
2698 const char *abspath;
2699 const char *path_env = 0;
2701 abspath = dln_find_exe_r(
RSTRING_PTR(eargp->invoke.cmd.command_name),
2702 path_env, fbuf,
sizeof(fbuf));
2706 eargp->invoke.cmd.command_abspath =
Qnil;
2709 if (!eargp->use_shell && !eargp->invoke.cmd.argv_buf) {
2714 for (i = 0; i < argc; i++) {
2715 VALUE arg = argv[i];
2717 #ifdef DEFAULT_PROCESS_ENCODING
2718 arg = EXPORT_STR(arg);
2723 eargp->invoke.cmd.argv_buf = argv_buf;
2726 if (!eargp->use_shell) {
2727 const char *p, *ep, *
null=NULL;
2738 eargp->invoke.cmd.argv_str =
2739 rb_imemo_tmpbuf_auto_free_pointer_new_from_an_RString(argv_str);
2745 rb_execarg_get(
VALUE execarg_obj)
2753 rb_execarg_init(
int argc,
const VALUE *orig_argv,
int accept_shell,
VALUE execarg_obj)
2755 struct rb_execarg *eargp = rb_execarg_get(execarg_obj);
2761 prog = rb_exec_getargs(&argc, &argv, accept_shell, &env, &opthash);
2762 rb_exec_fillarg(prog, argc, argv, env, opthash, execarg_obj);
2764 ret = eargp->use_shell ? eargp->invoke.sh.shell_script : eargp->invoke.cmd.command_name;
2770 rb_execarg_new(
int argc,
const VALUE *argv,
int accept_shell,
int allow_exc_opt)
2775 rb_execarg_init(argc, argv, accept_shell, execarg_obj);
2776 if (!allow_exc_opt && eargp->exception_given) {
2783 rb_execarg_setenv(
VALUE execarg_obj,
VALUE env)
2785 struct rb_execarg *eargp = rb_execarg_get(execarg_obj);
2786 env = !
NIL_P(env) ? rb_check_exec_env(env, &eargp->path_env) :
Qfalse;
2787 eargp->env_modification = env;
2792 fill_envp_buf_i(st_data_t st_key, st_data_t st_val, st_data_t arg)
2807 static long run_exec_dup2_tmpbuf_size(
long n);
2818 open_func(
void *
ptr)
2822 data->ret = parent_redirect_open(fname, data->oflags, data->perm);
2828 rb_execarg_allocate_dup2_tmpbuf(
struct rb_execarg *eargp,
long len)
2830 VALUE tmpbuf = rb_imemo_tmpbuf_auto_free_pointer();
2831 rb_imemo_tmpbuf_set_ptr(tmpbuf,
ruby_xmalloc(run_exec_dup2_tmpbuf_size(
len)));
2832 eargp->dup2_tmpbuf = tmpbuf;
2836 rb_execarg_parent_start1(
VALUE execarg_obj)
2838 struct rb_execarg *eargp = rb_execarg_get(execarg_obj);
2839 int unsetenv_others;
2843 ary = eargp->fd_open;
2858 open_data.fname = vpath;
2859 open_data.oflags = flags;
2860 open_data.perm = perm;
2862 open_data.err = EINTR;
2864 if (open_data.ret == -1) {
2865 if (open_data.err == EINTR) {
2871 fd2 = open_data.ret;
2883 eargp->redirect_fds = check_exec_fds(eargp);
2885 ary = eargp->fd_dup2;
2887 rb_execarg_allocate_dup2_tmpbuf(eargp,
RARRAY_LEN(ary));
2890 unsetenv_others = eargp->unsetenv_others_given && eargp->unsetenv_others_do;
2891 envopts = eargp->env_modification;
2892 if (ALWAYS_NEED_ENVP || unsetenv_others || envopts !=
Qfalse) {
2893 VALUE envtbl, envp_str, envp_buf;
2895 if (unsetenv_others) {
2899 envtbl = rb_env_to_hash();
2903 st_table *stenv = RHASH_TBL_RAW(envtbl);
2910 st_data_t stkey = (st_data_t)key;
2911 st_delete(stenv, &stkey, NULL);
2914 st_insert(stenv, (st_data_t)key, (st_data_t)val);
2922 rb_hash_stlike_foreach(envtbl, fill_envp_buf_i, (st_data_t)envp_buf);
2934 rb_imemo_tmpbuf_auto_free_pointer_new_from_an_RString(envp_str);
2935 eargp->envp_buf = envp_buf;
2951 rb_execarg_parent_start(
VALUE execarg_obj)
2954 rb_protect(rb_execarg_parent_start1, execarg_obj, &state);
2956 rb_execarg_parent_end(execarg_obj);
2962 execarg_parent_end(
VALUE execarg_obj)
2964 struct rb_execarg *eargp = rb_execarg_get(execarg_obj);
2968 ary = eargp->fd_open;
2979 parent_redirect_close(fd2);
2991 rb_execarg_parent_end(
VALUE execarg_obj)
2993 execarg_parent_end(execarg_obj);
2998 rb_exec_fail(
struct rb_execarg *eargp,
int err,
const char *errmsg)
3000 if (!errmsg || !*errmsg)
return;
3001 if (strcmp(errmsg,
"chdir") == 0) {
3009 rb_execarg_fail(
VALUE execarg_obj,
int err,
const char *errmsg)
3011 if (!errmsg || !*errmsg)
return;
3012 rb_exec_fail(rb_execarg_get(execarg_obj), err, errmsg);
3020 VALUE execarg_obj, fail_str;
3022 #define CHILD_ERRMSG_BUFLEN 80
3023 char errmsg[CHILD_ERRMSG_BUFLEN] = {
'\0' };
3026 execarg_obj = rb_execarg_new(argc, argv, TRUE, FALSE);
3027 eargp = rb_execarg_get(execarg_obj);
3030 rb_protect(rb_execarg_parent_start1, execarg_obj, &state);
3032 execarg_parent_end(execarg_obj);
3037 fail_str = eargp->use_shell ? eargp->invoke.sh.shell_script : eargp->invoke.cmd.command_name;
3039 err = exec_async_signal_safe(eargp, errmsg,
sizeof(errmsg));
3042 rb_exec_fail(eargp, err, errmsg);
3146 #define ERRMSG(str) \
3147 ((errmsg && 0 < errmsg_buflen) ? \
3148 (void)strlcpy(errmsg, (str), errmsg_buflen) : (void)0)
3150 #define ERRMSG_FMT(...) \
3151 ((errmsg && 0 < errmsg_buflen) ? \
3152 (void)snprintf(errmsg, errmsg_buflen, __VA_ARGS__) : (void)0)
3154 static int fd_get_cloexec(
int fd,
char *errmsg,
size_t errmsg_buflen);
3155 static int fd_set_cloexec(
int fd,
char *errmsg,
size_t errmsg_buflen);
3156 static int fd_clear_cloexec(
int fd,
char *errmsg,
size_t errmsg_buflen);
3159 save_redirect_fd(
int fd,
struct rb_execarg *sargp,
char *errmsg,
size_t errmsg_buflen)
3162 VALUE newary, redirection;
3163 int save_fd = redirect_cloexec_dup(fd), cloexec;
3164 if (save_fd == -1) {
3171 newary = sargp->fd_dup2;
3174 sargp->fd_dup2 = newary;
3176 cloexec = fd_get_cloexec(fd, errmsg, errmsg_buflen);
3181 newary = sargp->fd_close;
3184 sargp->fd_close = newary;
3193 intcmp(
const void *a,
const void *b)
3195 return *(
int*)a - *(
int*)b;
3199 intrcmp(
const void *a,
const void *b)
3201 return *(
int*)b - *(
int*)a;
3213 run_exec_dup2_tmpbuf_size(
long n)
3220 fd_get_cloexec(
int fd,
char *errmsg,
size_t errmsg_buflen)
3224 ret = fcntl(fd, F_GETFD);
3226 ERRMSG(
"fcntl(F_GETFD)");
3229 if (ret & FD_CLOEXEC)
return 1;
3236 fd_set_cloexec(
int fd,
char *errmsg,
size_t errmsg_buflen)
3240 ret = fcntl(fd, F_GETFD);
3242 ERRMSG(
"fcntl(F_GETFD)");
3245 if (!(ret & FD_CLOEXEC)) {
3247 ret = fcntl(fd, F_SETFD, ret);
3249 ERRMSG(
"fcntl(F_SETFD)");
3259 fd_clear_cloexec(
int fd,
char *errmsg,
size_t errmsg_buflen)
3263 ret = fcntl(fd, F_GETFD);
3265 ERRMSG(
"fcntl(F_GETFD)");
3268 if (ret & FD_CLOEXEC) {
3270 ret = fcntl(fd, F_SETFD, ret);
3272 ERRMSG(
"fcntl(F_SETFD)");
3282 run_exec_dup2(
VALUE ary,
VALUE tmpbuf,
struct rb_execarg *sargp,
char *errmsg,
size_t errmsg_buflen)
3293 for (i = 0; i < n; i++) {
3298 pairs[i].older_index = -1;
3308 for (i = 0; i < n; i++) {
3309 int newfd = pairs[i].newfd;
3313 pairs[i].num_newer = 0;
3315 while (pairs < found && (found-1)->oldfd == newfd)
3317 while (found < pairs+n && found->oldfd == newfd) {
3318 pairs[i].num_newer++;
3319 found->older_index = i;
3326 for (i = 0; i < n; i++) {
3328 while (j != -1 && pairs[j].oldfd != -1 && pairs[j].num_newer == 0) {
3329 if (save_redirect_fd(pairs[j].newfd, sargp, errmsg, errmsg_buflen) < 0)
3331 ret = redirect_dup2(pairs[j].oldfd, pairs[j].newfd);
3336 if (pairs[j].cloexec &&
3337 fd_set_cloexec(pairs[j].newfd, errmsg, errmsg_buflen)) {
3341 pairs[j].oldfd = -1;
3342 j = pairs[j].older_index;
3344 pairs[j].num_newer--;
3349 for (i = 0; i < n; i++) {
3351 if (pairs[i].oldfd == -1)
3353 if (pairs[i].oldfd == pairs[i].newfd) {
3354 if (fd_clear_cloexec(pairs[i].oldfd, errmsg, errmsg_buflen) == -1)
3356 pairs[i].oldfd = -1;
3359 if (extra_fd == -1) {
3360 extra_fd = redirect_dup(pairs[i].oldfd);
3361 if (extra_fd == -1) {
3367 if (fd_get_cloexec(pairs[i].oldfd, errmsg, errmsg_buflen)) {
3368 if (fd_set_cloexec(extra_fd, errmsg, errmsg_buflen)) {
3375 ret = redirect_dup2(pairs[i].oldfd, extra_fd);
3382 pairs[i].oldfd = extra_fd;
3383 j = pairs[i].older_index;
3384 pairs[i].older_index = -1;
3386 ret = redirect_dup2(pairs[j].oldfd, pairs[j].newfd);
3392 pairs[j].oldfd = -1;
3393 j = pairs[j].older_index;
3396 if (extra_fd != -1) {
3397 ret = redirect_close(extra_fd);
3412 run_exec_close(
VALUE ary,
char *errmsg,
size_t errmsg_buflen)
3420 ret = redirect_close(fd);
3431 run_exec_dup2_child(
VALUE ary,
struct rb_execarg *sargp,
char *errmsg,
size_t errmsg_buflen)
3441 if (save_redirect_fd(newfd, sargp, errmsg, errmsg_buflen) < 0)
3443 ret = redirect_dup2(oldfd, newfd);
3456 run_exec_pgroup(
const struct rb_execarg *eargp,
struct rb_execarg *sargp,
char *errmsg,
size_t errmsg_buflen)
3468 pgroup = eargp->pgroup_pgid;
3474 sargp->pgroup_given = 1;
3475 sargp->pgroup_pgid = getpgrp();
3481 ret = setpgid(getpid(), pgroup);
3482 if (ret == -1) ERRMSG(
"setpgid");
3487 #if defined(HAVE_SETRLIMIT) && defined(RLIM2NUM)
3490 run_exec_rlimit(
VALUE ary,
struct rb_execarg *sargp,
char *errmsg,
size_t errmsg_buflen)
3499 if (getrlimit(rtype, &rlim) == -1) {
3500 ERRMSG(
"getrlimit");
3504 RLIM2NUM(rlim.rlim_cur),
3505 RLIM2NUM(rlim.rlim_max)));
3506 if (sargp->rlimit_limits ==
Qfalse)
3507 newary = sargp->rlimit_limits = hide_obj(
rb_ary_new());
3509 newary = sargp->rlimit_limits;
3514 if (setrlimit(rtype, &rlim) == -1) {
3515 ERRMSG(
"setrlimit");
3523 #if !defined(HAVE_WORKING_FORK)
3536 if (sargp->env_modification ==
Qfalse) {
3537 VALUE env = rb_envtbl();
3542 sargp->env_modification = ary;
3544 sargp->unsetenv_others_given = 1;
3545 sargp->unsetenv_others_do = 1;
3552 #define chdir(p) rb_w32_uchdir(p)
3557 rb_execarg_run_options(
const struct rb_execarg *eargp,
struct rb_execarg *sargp,
char *errmsg,
size_t errmsg_buflen)
3564 sargp->redirect_fds =
Qnil;
3568 if (eargp->pgroup_given) {
3569 if (run_exec_pgroup(eargp, sargp, errmsg, errmsg_buflen) == -1)
3574 #if defined(HAVE_SETRLIMIT) && defined(RLIM2NUM)
3575 obj = eargp->rlimit_limits;
3577 if (run_exec_rlimit(obj, sargp, errmsg, errmsg_buflen) == -1)
3582 #if !defined(HAVE_WORKING_FORK)
3583 if (eargp->unsetenv_others_given && eargp->unsetenv_others_do) {
3588 obj = eargp->env_modification;
3604 if (eargp->umask_given) {
3605 mode_t mask = eargp->umask_mask;
3606 mode_t oldmask = umask(mask);
3608 sargp->umask_given = 1;
3609 sargp->umask_mask = oldmask;
3613 obj = eargp->fd_dup2;
3615 if (run_exec_dup2(obj, eargp->dup2_tmpbuf, sargp, errmsg, errmsg_buflen) == -1)
3619 obj = eargp->fd_close;
3622 rb_warn(
"cannot close fd before spawn");
3624 if (run_exec_close(obj, errmsg, errmsg_buflen) == -1)
3629 #ifdef HAVE_WORKING_FORK
3630 if (eargp->close_others_do) {
3635 obj = eargp->fd_dup2_child;
3637 if (run_exec_dup2_child(obj, sargp, errmsg, errmsg_buflen) == -1)
3641 if (eargp->chdir_given) {
3643 sargp->chdir_given = 1;
3644 sargp->chdir_dir = hide_obj(rb_dir_getwd_ospath());
3653 if (eargp->gid_given) {
3654 if (setgid(eargp->gid) < 0) {
3661 if (eargp->uid_given) {
3662 if (setuid(eargp->uid) < 0) {
3670 VALUE ary = sargp->fd_dup2;
3672 rb_execarg_allocate_dup2_tmpbuf(sargp,
RARRAY_LEN(ary));
3676 int preserve =
errno;
3677 stdfd_clear_nonblock();
3686 rb_exec_async_signal_safe(
const struct rb_execarg *eargp,
char *errmsg,
size_t errmsg_buflen)
3688 errno = exec_async_signal_safe(eargp, errmsg, errmsg_buflen);
3693 exec_async_signal_safe(
const struct rb_execarg *eargp,
char *errmsg,
size_t errmsg_buflen)
3695 #if !defined(HAVE_WORKING_FORK)
3696 struct rb_execarg sarg, *
const sargp = &sarg;
3702 if (rb_execarg_run_options(eargp, sargp, errmsg, errmsg_buflen) < 0) {
3706 if (eargp->use_shell) {
3707 err = proc_exec_sh(
RSTRING_PTR(eargp->invoke.sh.shell_script), eargp->envp_str);
3710 char *abspath = NULL;
3711 if (!
NIL_P(eargp->invoke.cmd.command_abspath))
3712 abspath =
RSTRING_PTR(eargp->invoke.cmd.command_abspath);
3713 err = proc_exec_cmd(abspath, eargp->invoke.cmd.argv_str, eargp->envp_str);
3715 #if !defined(HAVE_WORKING_FORK)
3716 rb_execarg_run_options(sargp, NULL, errmsg, errmsg_buflen);
3722 #ifdef HAVE_WORKING_FORK
3725 rb_exec_atfork(
void* arg,
char *errmsg,
size_t errmsg_buflen)
3727 return rb_exec_async_signal_safe(arg, errmsg, errmsg_buflen);
3731 proc_syswait(
VALUE pid)
3738 move_fds_to_avoid_crash(
int *fdp,
int n,
VALUE fds)
3742 for (i = 0; i < n; i++) {
3761 pipe_nocrash(
int filedes[2],
VALUE fds)
3769 if (move_fds_to_avoid_crash(filedes, 2, fds) == -1) {
3784 rb_thread_sleep_that_takes_VALUE_as_sole_argument(
VALUE n)
3791 handle_fork_error(
int err,
struct rb_process_status *status,
int *ep,
volatile int *try_gc_p)
3803 #if defined(EWOULDBLOCK) && EWOULDBLOCK != EAGAIN
3806 if (!status && !ep) {
3811 rb_protect(rb_thread_sleep_that_takes_VALUE_as_sole_argument,
INT2FIX(1), &state);
3812 if (status) status->status = state;
3813 if (!state)
return 0;
3826 #define prefork() ( \
3827 rb_io_flush(rb_stdout), \
3828 rb_io_flush(rb_stderr) \
3858 write_retry(
int fd,
const void *buf,
size_t len)
3863 w = write(fd, buf,
len);
3864 }
while (w < 0 &&
errno == EINTR);
3870 read_retry(
int fd,
void *buf,
size_t len)
3874 if (set_blocking(fd) != 0) {
3876 rb_async_bug_errno(
"set_blocking failed reading child error",
errno);
3881 r = read(fd, buf,
len);
3882 }
while (r < 0 &&
errno == EINTR);
3888 send_child_error(
int fd,
char *errmsg,
size_t errmsg_buflen)
3893 if (write_retry(fd, &err,
sizeof(err)) < 0) err =
errno;
3894 if (errmsg && 0 < errmsg_buflen) {
3895 errmsg[errmsg_buflen-1] =
'\0';
3896 errmsg_buflen = strlen(errmsg);
3897 if (errmsg_buflen > 0 && write_retry(fd, errmsg, errmsg_buflen) < 0)
3903 recv_child_error(
int fd,
int *errp,
char *errmsg,
size_t errmsg_buflen)
3907 if ((size = read_retry(fd, &err,
sizeof(err))) < 0) {
3911 if (size ==
sizeof(err) &&
3912 errmsg && 0 < errmsg_buflen) {
3913 ssize_t ret = read_retry(fd, errmsg, errmsg_buflen-1);
3922 #ifdef HAVE_WORKING_VFORK
3923 #if !defined(HAVE_GETRESUID) && defined(HAVE_GETUIDX)
3926 getresuid(rb_uid_t *ruid, rb_uid_t *euid, rb_uid_t *suid)
3932 ret = getuidx(ID_SAVED);
3933 if (ret == (rb_uid_t)-1)
3938 #define HAVE_GETRESUID
3941 #if !defined(HAVE_GETRESGID) && defined(HAVE_GETGIDX)
3944 getresgid(rb_gid_t *rgid, rb_gid_t *egid, rb_gid_t *sgid)
3950 ret = getgidx(ID_SAVED);
3951 if (ret == (rb_gid_t)-1)
3956 #define HAVE_GETRESGID
3974 rb_uid_t ruid, euid;
3975 rb_gid_t rgid, egid;
3977 #if defined HAVE_ISSETUGID
3982 #ifdef HAVE_GETRESUID
3986 ret = getresuid(&ruid, &euid, &suid);
3997 if (euid == 0 || euid != ruid)
4000 #ifdef HAVE_GETRESGID
4004 ret = getresgid(&rgid, &egid, &sgid);
4022 struct child_handler_disabler_state
4028 disable_child_handler_before_fork(
struct child_handler_disabler_state *old)
4030 #ifdef HAVE_PTHREAD_SIGMASK
4034 ret = sigfillset(&all);
4038 ret = pthread_sigmask(SIG_SETMASK, &all, &old->sigmask);
4043 # pragma GCC warning "pthread_sigmask on fork is not available. potentially dangerous"
4048 disable_child_handler_fork_parent(
struct child_handler_disabler_state *old)
4050 #ifdef HAVE_PTHREAD_SIGMASK
4053 ret = pthread_sigmask(SIG_SETMASK, &old->sigmask, NULL);
4058 # pragma GCC warning "pthread_sigmask on fork is not available. potentially dangerous"
4064 disable_child_handler_fork_child(
struct child_handler_disabler_state *old,
char *errmsg,
size_t errmsg_buflen)
4069 for (sig = 1; sig < NSIG; sig++) {
4070 sig_t handler = signal(sig, SIG_DFL);
4072 if (handler == SIG_ERR &&
errno == EINVAL) {
4075 if (handler == SIG_ERR) {
4076 ERRMSG(
"signal to obtain old action");
4080 if (sig == SIGPIPE) {
4085 if (handler == SIG_IGN) {
4086 signal(sig, SIG_IGN);
4091 sigemptyset(&old->sigmask);
4092 ret = sigprocmask(SIG_SETMASK, &old->sigmask, NULL);
4094 ERRMSG(
"sigprocmask");
4102 int (*chfunc)(
void*,
char *,
size_t),
void *charg,
4103 char *errmsg,
size_t errmsg_buflen,
4107 volatile int try_gc = 1;
4108 struct child_handler_disabler_state old;
4113 disable_child_handler_before_fork(&old);
4114 #ifdef HAVE_WORKING_VFORK
4115 if (!has_privilege())
4125 ret = disable_child_handler_fork_child(&old, errmsg, errmsg_buflen);
4127 ret = chfunc(charg, errmsg, errmsg_buflen);
4128 if (!ret) _exit(EXIT_SUCCESS);
4130 send_child_error(ep[1], errmsg, errmsg_buflen);
4131 #if EXIT_SUCCESS == 127
4132 _exit(EXIT_FAILURE);
4138 disable_child_handler_fork_parent(&old);
4142 if (handle_fork_error(err, status, ep, &try_gc))
4148 fork_check_err(
struct rb_process_status *status,
int (*chfunc)(
void*,
char *,
size_t),
void *charg,
4149 VALUE fds,
char *errmsg,
size_t errmsg_buflen,
4157 struct waitpid_state *w = eargp && eargp->waitpid_state ? eargp->waitpid_state : 0;
4159 if (status) status->status = 0;
4161 if (pipe_nocrash(ep, fds))
return -1;
4163 pid = retry_fork_async_signal_safe(status, ep, chfunc, charg, errmsg, errmsg_buflen, w);
4165 if (status) status->pid = pid;
4168 if (status) status->error =
errno;
4175 error_occurred = recv_child_error(ep[0], &err, errmsg, errmsg_buflen);
4177 if (error_occurred) {
4180 status->error = err;
4182 VM_ASSERT((w == 0) &&
"only used by extensions");
4185 status->status = state;
4206 rb_fork_async_signal_safe(
int *status,
4207 int (*chfunc)(
void*,
char *,
size_t),
void *charg,
4208 VALUE fds,
char *errmsg,
size_t errmsg_buflen)
4212 rb_pid_t result = fork_check_err(&process_status, chfunc, charg, fds, errmsg, errmsg_buflen, 0);
4215 *status = process_status.status;
4222 rb_fork_ruby(
int *status)
4226 int try_gc = 1, err;
4227 struct child_handler_disabler_state old;
4233 rb_thread_acquire_fork_lock();
4234 disable_child_handler_before_fork(&old);
4236 child.pid = pid = rb_fork();
4237 child.error = err =
errno;
4239 disable_child_handler_fork_parent(&old);
4241 #
if defined(__FreeBSD__)
4245 rb_thread_release_fork_lock();
4248 rb_thread_reset_fork_lock();
4250 after_fork_ruby(pid);
4253 }
while (pid < 0 && handle_fork_error(err, &child, NULL, &try_gc) == 0);
4255 if (status) *status = child.status;
4263 rb_pid_t pid = rb_fork_ruby(NULL);
4273 rb_call_proc__fork(
void)
4278 return proc_fork_pid();
4287 #if defined(HAVE_WORKING_FORK) && !defined(CANNOT_FORK_WITH_PTHREAD)
4308 rb_proc__fork(
VALUE _obj)
4310 rb_pid_t pid = proc_fork_pid();
4375 rb_f_fork(
VALUE obj)
4379 pid = rb_call_proc__fork();
4393 #define rb_proc__fork rb_f_notimplement
4394 #define rb_f_fork rb_f_notimplement
4398 exit_status_code(
VALUE status)
4404 istatus = EXIT_SUCCESS;
4407 istatus = EXIT_FAILURE;
4411 #if EXIT_SUCCESS != 0
4413 istatus = EXIT_SUCCESS;
4420 NORETURN(
static VALUE rb_f_exit_bang(
int argc,
VALUE *argv,
VALUE obj));
4438 rb_f_exit_bang(
int argc,
VALUE *argv,
VALUE obj)
4443 istatus = exit_status_code(argv[0]);
4446 istatus = EXIT_FAILURE;
4456 if (GET_EC()->tag) {
4472 istatus = exit_status_code(argv[0]);
4475 istatus = EXIT_SUCCESS;
4541 VALUE errinfo = rb_ec_get_errinfo(ec);
4542 if (!
NIL_P(errinfo)) {
4543 rb_ec_error_print(ec, errinfo);
4550 args[1] = args[0] = argv[0];
4553 args[0] =
INT2NUM(EXIT_FAILURE);
4591 #if !defined HAVE_WORKING_FORK && !defined HAVE_SPAWNV && !defined __EMSCRIPTEN__
4596 if (eargp && !eargp->use_shell) {
4597 VALUE str = eargp->invoke.cmd.argv_str;
4598 VALUE buf = eargp->invoke.cmd.argv_buf;
4599 char *p, **argv = ARGVSTR2ARGV(str);
4600 long i, argc = ARGVSTR2ARGC(str);
4604 for (i = 1; i < argc; ++i) {
4605 p[argv[i] - start - 1] =
' ';
4615 rb_spawn_process(
struct rb_execarg *eargp,
char *errmsg,
size_t errmsg_buflen)
4618 #if !defined HAVE_WORKING_FORK || USE_SPAWNV
4621 # if !defined HAVE_SPAWNV
4626 #if defined HAVE_WORKING_FORK && !USE_SPAWNV
4627 pid = fork_check_err(eargp->status, rb_exec_atfork, eargp, eargp->redirect_fds, errmsg, errmsg_buflen, eargp);
4629 prog = eargp->use_shell ? eargp->invoke.sh.shell_script : eargp->invoke.cmd.command_name;
4631 if (rb_execarg_run_options(eargp, &sarg, errmsg, errmsg_buflen) < 0) {
4635 if (prog && !eargp->use_shell) {
4636 char **argv = ARGVSTR2ARGV(eargp->invoke.cmd.argv_str);
4639 # if defined HAVE_SPAWNV
4640 if (eargp->use_shell) {
4644 char **argv = ARGVSTR2ARGV(eargp->invoke.cmd.argv_str);
4645 pid = proc_spawn_cmd(argv, prog, eargp);
4652 status = system(rb_execarg_commandline(eargp, &prog));
4657 if (eargp->waitpid_state) {
4658 eargp->waitpid_state->pid = pid;
4661 rb_execarg_run_options(&sarg, NULL, errmsg, errmsg_buflen);
4676 do_spawn_process(
VALUE arg)
4680 rb_execarg_parent_start1(argp->execarg);
4682 return (
VALUE)rb_spawn_process(rb_execarg_get(argp->execarg),
4683 argp->errmsg.ptr, argp->errmsg.buflen);
4686 NOINLINE(
static rb_pid_t
4687 rb_execarg_spawn(
VALUE execarg_obj,
char *errmsg,
size_t errmsg_buflen));
4690 rb_execarg_spawn(
VALUE execarg_obj,
char *errmsg,
size_t errmsg_buflen)
4694 args.execarg = execarg_obj;
4695 args.errmsg.ptr = errmsg;
4696 args.errmsg.buflen = errmsg_buflen;
4699 execarg_parent_end, execarg_obj);
4704 rb_spawn_internal(
int argc,
const VALUE *argv,
char *errmsg,
size_t errmsg_buflen)
4708 execarg_obj = rb_execarg_new(argc, argv, TRUE, FALSE);
4709 return rb_execarg_spawn(execarg_obj, errmsg, errmsg_buflen);
4715 return rb_spawn_internal(argc, argv, errmsg, errmsg_buflen);
4721 return rb_spawn_internal(argc, argv, NULL, 0);
4846 VALUE execarg_obj = rb_execarg_new(argc, argv, TRUE, TRUE);
4847 struct rb_execarg *eargp = rb_execarg_get(execarg_obj);
4850 eargp->status = &status;
4852 last_status_clear(th);
4856 rb_pid_t pid = rb_execarg_spawn(execarg_obj, 0, 0);
4863 th->last_status = status;
4865 if (data->status == EXIT_SUCCESS) {
4869 if (data->error != 0) {
4870 if (eargp->exception) {
4871 VALUE command = eargp->invoke.sh.shell_script;
4879 else if (eargp->exception) {
4880 VALUE command = eargp->invoke.sh.shell_script;
4894 if (eargp->exception) {
4895 VALUE command = eargp->invoke.sh.shell_script;
5011 char errmsg[CHILD_ERRMSG_BUFLEN] = {
'\0' };
5012 VALUE execarg_obj, fail_str;
5015 execarg_obj = rb_execarg_new(argc, argv, TRUE, FALSE);
5016 eargp = rb_execarg_get(execarg_obj);
5017 fail_str = eargp->use_shell ? eargp->invoke.sh.shell_script : eargp->invoke.cmd.command_name;
5019 pid = rb_execarg_spawn(execarg_obj, errmsg,
sizeof(errmsg));
5023 rb_exec_fail(eargp, err, errmsg);
5027 #if defined(HAVE_WORKING_FORK) || defined(HAVE_SPAWNV)
5053 time_t beg = time(0);
5056 if (scheduler !=
Qnil) {
5060 if (argc == 0 || (argc == 1 &&
NIL_P(argv[0]))) {
5069 time_t end = time(0) - beg;
5071 return TIMET2NUM(end);
5075 #if (defined(HAVE_GETPGRP) && defined(GETPGRP_VOID)) || defined(HAVE_GETPGID)
5092 #if defined(HAVE_GETPGRP) && defined(GETPGRP_VOID)
5103 #define proc_getpgrp rb_f_notimplement
5107 #if defined(HAVE_SETPGID) || (defined(HAVE_SETPGRP) && defined(SETPGRP_VOID))
5126 #elif defined(HAVE_SETPGRP) && defined(SETPGRP_VOID)
5132 #define proc_setpgrp rb_f_notimplement
5136 #if defined(HAVE_GETPGID)
5158 #define proc_getpgid rb_f_notimplement
5176 rb_pid_t ipid, ipgrp;
5185 #define proc_setpgid rb_f_notimplement
5217 #define proc_getsid rb_f_notimplement
5221 #if defined(HAVE_SETSID) || (defined(HAVE_SETPGRP) && defined(TIOCNOTTY))
5222 #if !defined(HAVE_SETSID)
5223 static rb_pid_t ruby_setsid(
void);
5224 #define setsid() ruby_setsid()
5249 #if !defined(HAVE_SETSID)
5250 #define HAVE_SETSID 1
5258 #if defined(SETPGRP_VOID)
5264 ret = setpgrp(0, pid);
5266 if (ret == -1)
return -1;
5270 ioctl(fd, TIOCNOTTY, NULL);
5277 #define proc_setsid rb_f_notimplement
5281 #ifdef HAVE_GETPRIORITY
5309 int prio, iwhich, iwho;
5315 prio = getpriority(iwhich, iwho);
5320 #define proc_getpriority rb_f_notimplement
5324 #ifdef HAVE_GETPRIORITY
5344 int iwhich, iwho, iprio;
5350 if (setpriority(iwhich, iwho, iprio) < 0)
5355 #define proc_setpriority rb_f_notimplement
5358 #if defined(HAVE_SETRLIMIT) && defined(NUM2RLIM)
5360 rlimit_resource_name2int(
const char *name,
long len,
int casetype)
5364 #define RESCHECK(r) \
5366 if (len == rb_strlen_lit(#r) && STRCASECMP(name, #r) == 0) { \
5367 resource = RLIMIT_##r; \
5401 #ifdef RLIMIT_MEMLOCK
5404 #ifdef RLIMIT_MSGQUEUE
5410 #ifdef RLIMIT_NOFILE
5428 #ifdef RLIMIT_RTPRIO
5431 #ifdef RLIMIT_RTTIME
5440 #ifdef RLIMIT_SBSIZE
5443 #ifdef RLIMIT_SIGPENDING
5444 RESCHECK(SIGPENDING);
5453 for (p = name; *p; p++)
5459 for (p = name; *p; p++)
5465 rb_bug(
"unexpected casetype");
5472 rlimit_type_by_hname(
const char *name,
long len)
5474 return rlimit_resource_name2int(name,
len, 0);
5478 rlimit_type_by_lname(
const char *name,
long len)
5480 return rlimit_resource_name2int(name,
len, 1);
5484 rlimit_type_by_sym(
VALUE key)
5490 static const char prefix[] =
"rlimit_";
5491 enum {prefix_len =
sizeof(prefix)-1};
5493 if (
len > prefix_len && strncmp(prefix, rname, prefix_len) == 0) {
5494 rtype = rlimit_type_by_lname(rname + prefix_len,
len - prefix_len);
5502 rlimit_resource_type(
VALUE rtype)
5509 switch (
TYPE(rtype)) {
5532 r = rlimit_type_by_hname(name,
len);
5542 rlimit_resource_value(
VALUE rval)
5547 switch (
TYPE(rval)) {
5565 return NUM2RLIM(rval);
5568 #ifdef RLIM_INFINITY
5569 if (strcmp(name,
"INFINITY") == 0)
return RLIM_INFINITY;
5571 #ifdef RLIM_SAVED_MAX
5572 if (strcmp(name,
"SAVED_MAX") == 0)
return RLIM_SAVED_MAX;
5574 #ifdef RLIM_SAVED_CUR
5575 if (strcmp(name,
"SAVED_CUR") == 0)
return RLIM_SAVED_CUR;
5583 #if defined(HAVE_GETRLIMIT) && defined(RLIM2NUM)
5611 if (getrlimit(rlimit_resource_type(resource), &rlim) < 0) {
5614 return rb_assoc_new(RLIM2NUM(rlim.rlim_cur), RLIM2NUM(rlim.rlim_max));
5617 #define proc_getrlimit rb_f_notimplement
5620 #if defined(HAVE_SETRLIMIT) && defined(NUM2RLIM)
5674 proc_setrlimit(
int argc,
VALUE *argv,
VALUE obj)
5676 VALUE resource, rlim_cur, rlim_max;
5682 if (argc < 3 ||
NIL_P(rlim_max = argv[2]))
5683 rlim_max = rlim_cur;
5685 rlim.rlim_cur = rlimit_resource_value(rlim_cur);
5686 rlim.rlim_max = rlimit_resource_value(rlim_max);
5688 if (setrlimit(rlimit_resource_type(resource), &rlim) < 0) {
5694 #define proc_setrlimit rb_f_notimplement
5697 static int under_uid_switch = 0;
5699 check_uid_switch(
void)
5701 if (under_uid_switch) {
5706 static int under_gid_switch = 0;
5708 check_gid_switch(
void)
5710 if (under_gid_switch) {
5716 #if defined(HAVE_PWD_H)
5718 login_not_found(
int err)
5720 return (err == ENOTTY || err == ENXIO || err == ENOENT);
5731 # if !defined(USE_GETLOGIN_R) && !defined(USE_GETLOGIN)
5734 char MAYBE_UNUSED(*login) = NULL;
5736 # ifdef USE_GETLOGIN_R
5738 # if defined(__FreeBSD__)
5739 typedef int getlogin_r_size_t;
5741 typedef size_t getlogin_r_size_t;
5744 long loginsize = GETLOGIN_R_SIZE_INIT;
5747 loginsize = GETLOGIN_R_SIZE_DEFAULT;
5756 while ((gle = getlogin_r(login, (getlogin_r_size_t)loginsize)) != 0) {
5757 if (login_not_found(gle)) {
5762 if (gle != ERANGE || loginsize >= GETLOGIN_R_SIZE_LIMIT) {
5772 if (login == NULL) {
5778 return maybe_result;
5780 # elif defined(USE_GETLOGIN)
5786 if (login_not_found(err)) {
5800 pwd_not_found(
int err)
5814 # if defined(USE_GETPWNAM_R)
5815 struct getpwnam_r_args {
5819 struct passwd *result;
5820 struct passwd pwstore;
5823 # define GETPWNAM_R_ARGS(login_, buf_, bufsize_) (struct getpwnam_r_args) \
5824 {.login = login_, .buf = buf_, .bufsize = bufsize_, .result = NULL}
5827 nogvl_getpwnam_r(
void *args)
5829 struct getpwnam_r_args *arg = args;
5830 return (
void *)(
VALUE)getpwnam_r(arg->login, &arg->pwstore, arg->buf, arg->bufsize, &arg->result);
5835 rb_getpwdirnam_for_login(
VALUE login_name)
5837 #if !defined(USE_GETPWNAM_R) && !defined(USE_GETPWNAM)
5841 if (
NIL_P(login_name)) {
5849 # ifdef USE_GETPWNAM_R
5852 long bufsizenm = GETPW_R_SIZE_INIT;
5855 bufsizenm = GETPW_R_SIZE_DEFAULT;
5862 struct getpwnam_r_args args = GETPWNAM_R_ARGS(login, bufnm, (
size_t)bufsizenm);
5865 while ((enm = IO_WITHOUT_GVL_INT(nogvl_getpwnam_r, &args)) != 0) {
5866 if (pwd_not_found(enm)) {
5871 if (enm != ERANGE || args.bufsize >= GETPW_R_SIZE_LIMIT) {
5881 if (args.result == NULL) {
5892 # elif defined(USE_GETPWNAM)
5894 struct passwd *pwptr;
5896 if (!(pwptr = getpwnam(login))) {
5899 if (pwd_not_found(err)) {
5913 # if defined(USE_GETPWUID_R)
5914 struct getpwuid_r_args {
5918 struct passwd *result;
5919 struct passwd pwstore;
5922 # define GETPWUID_R_ARGS(uid_, buf_, bufsize_) (struct getpwuid_r_args) \
5923 {.uid = uid_, .buf = buf_, .bufsize = bufsize_, .result = NULL}
5926 nogvl_getpwuid_r(
void *args)
5928 struct getpwuid_r_args *arg = args;
5929 return (
void *)(
VALUE)getpwuid_r(arg->uid, &arg->pwstore, arg->buf, arg->bufsize, &arg->result);
5937 rb_getpwdiruid(
void)
5939 # if !defined(USE_GETPWUID_R) && !defined(USE_GETPWUID)
5943 uid_t ruid = getuid();
5945 # ifdef USE_GETPWUID_R
5948 long bufsizeid = GETPW_R_SIZE_INIT;
5951 bufsizeid = GETPW_R_SIZE_DEFAULT;
5958 struct getpwuid_r_args args = GETPWUID_R_ARGS(ruid, bufid, (
size_t)bufsizeid);
5961 while ((eid = IO_WITHOUT_GVL_INT(nogvl_getpwuid_r, &args)) != 0) {
5962 if (pwd_not_found(eid)) {
5967 if (eid != ERANGE || args.bufsize >= GETPW_R_SIZE_LIMIT) {
5977 if (args.result == NULL) {
5988 # elif defined(USE_GETPWUID)
5990 struct passwd *pwptr;
5992 if (!(pwptr = getpwuid(ruid))) {
5995 if (pwd_not_found(err)) {
6021 #if defined(HAVE_PWD_H)
6024 # ifdef USE_GETPWNAM_R
6037 struct passwd *pwptr;
6038 #ifdef USE_GETPWNAM_R
6043 getpw_buf_len = GETPW_R_SIZE_INIT;
6044 if (getpw_buf_len < 0) getpw_buf_len = GETPW_R_SIZE_DEFAULT;
6051 struct getpwnam_r_args args = GETPWNAM_R_ARGS((
char *)usrname, getpw_buf, (
size_t)getpw_buf_len);
6053 while ((e = IO_WITHOUT_GVL_INT(nogvl_getpwnam_r, &args)) != 0) {
6054 if (e != ERANGE || args.bufsize >= GETPW_R_SIZE_LIMIT) {
6062 pwptr = args.result;
6064 pwptr = getpwnam(usrname);
6067 #ifndef USE_GETPWNAM_R
6072 uid = pwptr->pw_uid;
6073 #ifndef USE_GETPWNAM_R
6080 # ifdef p_uid_from_name
6100 #if defined(HAVE_GRP_H)
6101 # if defined(USE_GETGRNAM_R)
6102 struct getgrnam_r_args {
6106 struct group *result;
6110 # define GETGRNAM_R_ARGS(name_, buf_, bufsize_) (struct getgrnam_r_args) \
6111 {.name = name_, .buf = buf_, .bufsize = bufsize_, .result = NULL}
6114 nogvl_getgrnam_r(
void *args)
6116 struct getgrnam_r_args *arg = args;
6117 return (
void *)(
VALUE)getgrnam_r(arg->name, &arg->grp, arg->buf, arg->bufsize, &arg->result);
6123 # ifdef USE_GETGRNAM_R
6136 struct group *grptr;
6137 #ifdef USE_GETGRNAM_R
6142 getgr_buf_len = GETGR_R_SIZE_INIT;
6143 if (getgr_buf_len < 0) getgr_buf_len = GETGR_R_SIZE_DEFAULT;
6150 struct getgrnam_r_args args = GETGRNAM_R_ARGS(grpname, getgr_buf, (
size_t)getgr_buf_len);
6152 while ((e = IO_WITHOUT_GVL_INT(nogvl_getgrnam_r, &args)) != 0) {
6153 if (e != ERANGE || args.bufsize >= GETGR_R_SIZE_LIMIT) {
6161 grptr = args.result;
6162 #elif defined(HAVE_GETGRNAM)
6163 grptr = getgrnam(grpname);
6168 #if !defined(USE_GETGRNAM_R) && defined(HAVE_ENDGRENT)
6173 gid = grptr->gr_gid;
6174 #if !defined(USE_GETGRNAM_R) && defined(HAVE_ENDGRENT)
6181 # ifdef p_gid_from_name
6201 #if defined HAVE_SETUID
6219 #define p_sys_setuid rb_f_notimplement
6223 #if defined HAVE_SETRUID
6241 #define p_sys_setruid rb_f_notimplement
6245 #if defined HAVE_SETEUID
6263 #define p_sys_seteuid rb_f_notimplement
6267 #if defined HAVE_SETREUID
6282 rb_uid_t ruid, euid;
6285 ruid = OBJ2UID1(rid);
6286 euid = OBJ2UID1(eid);
6292 #define p_sys_setreuid rb_f_notimplement
6296 #if defined HAVE_SETRESUID
6311 rb_uid_t ruid, euid, suid;
6314 ruid = OBJ2UID1(rid);
6315 euid = OBJ2UID1(eid);
6316 suid = OBJ2UID1(sid);
6318 if (setresuid(ruid, euid, suid) != 0)
rb_sys_fail(0);
6322 #define p_sys_setresuid rb_f_notimplement
6339 proc_getuid(
VALUE obj)
6341 rb_uid_t uid = getuid();
6346 #if defined(HAVE_SETRESUID) || defined(HAVE_SETREUID) || defined(HAVE_SETRUID) || defined(HAVE_SETUID)
6366 #if defined(HAVE_SETRESUID)
6368 #elif defined HAVE_SETREUID
6370 #elif defined HAVE_SETRUID
6372 #elif defined HAVE_SETUID
6374 if (geteuid() == uid) {
6385 #define proc_setuid rb_f_notimplement
6399 static rb_uid_t SAVED_USER_ID = -1;
6401 #ifdef BROKEN_SETREUID
6403 setreuid(rb_uid_t ruid, rb_uid_t euid)
6405 if (ruid != (rb_uid_t)-1 && ruid != getuid()) {
6406 if (euid == (rb_uid_t)-1) euid = geteuid();
6407 if (setuid(ruid) < 0)
return -1;
6409 if (euid != (rb_uid_t)-1 && euid != geteuid()) {
6410 if (seteuid(euid) < 0)
return -1;
6438 if (geteuid() == 0) {
6439 #if defined(HAVE_SETRESUID)
6441 SAVED_USER_ID = uid;
6442 #elif defined(HAVE_SETUID)
6444 SAVED_USER_ID = uid;
6445 #elif defined(HAVE_SETREUID) && !defined(OBSOLETE_SETREUID)
6446 if (getuid() == uid) {
6447 if (SAVED_USER_ID == uid) {
6452 if (setreuid(-1, SAVED_USER_ID) < 0)
rb_sys_fail(0);
6453 if (setreuid(SAVED_USER_ID, 0) < 0)
rb_sys_fail(0);
6456 SAVED_USER_ID = uid;
6462 SAVED_USER_ID = uid;
6468 SAVED_USER_ID = uid;
6470 #elif defined(HAVE_SETRUID) && defined(HAVE_SETEUID)
6471 if (getuid() == uid) {
6472 if (SAVED_USER_ID == uid) {
6486 SAVED_USER_ID = uid;
6493 SAVED_USER_ID = uid;
6501 #if defined(HAVE_SETRESUID)
6502 if (setresuid((getuid() == uid)? (rb_uid_t)-1: uid,
6503 (geteuid() == uid)? (rb_uid_t)-1: uid,
6504 (SAVED_USER_ID == uid)? (rb_uid_t)-1: uid) < 0)
rb_sys_fail(0);
6505 SAVED_USER_ID = uid;
6506 #elif defined(HAVE_SETREUID) && !defined(OBSOLETE_SETREUID)
6507 if (SAVED_USER_ID == uid) {
6508 if (setreuid((getuid() == uid)? (rb_uid_t)-1: uid,
6509 (geteuid() == uid)? (rb_uid_t)-1: uid) < 0)
6512 else if (getuid() != uid) {
6513 if (setreuid(uid, (geteuid() == uid)? (rb_uid_t)-1: uid) < 0)
6515 SAVED_USER_ID = uid;
6517 else if ( geteuid() != uid) {
6519 SAVED_USER_ID = uid;
6523 if (setreuid(-1, SAVED_USER_ID) < 0)
rb_sys_fail(0);
6524 if (setreuid(SAVED_USER_ID, uid) < 0)
rb_sys_fail(0);
6525 SAVED_USER_ID = uid;
6528 #elif defined(HAVE_SETRUID) && defined(HAVE_SETEUID)
6529 if (SAVED_USER_ID == uid) {
6530 if (geteuid() != uid && seteuid(uid) < 0)
rb_sys_fail(0);
6531 if (getuid() != uid && setruid(uid) < 0)
rb_sys_fail(0);
6533 else if ( geteuid() == uid) {
6534 if (getuid() != uid) {
6536 SAVED_USER_ID = uid;
6540 SAVED_USER_ID = uid;
6544 else if ( getuid() == uid) {
6547 SAVED_USER_ID = uid;
6553 #elif defined HAVE_44BSD_SETUID
6554 if (getuid() == uid) {
6557 SAVED_USER_ID = uid;
6562 #elif defined HAVE_SETEUID
6563 if (getuid() == uid && SAVED_USER_ID == uid) {
6569 #elif defined HAVE_SETUID
6570 if (getuid() == uid && SAVED_USER_ID == uid) {
6585 #if defined HAVE_SETGID
6603 #define p_sys_setgid rb_f_notimplement
6607 #if defined HAVE_SETRGID
6625 #define p_sys_setrgid rb_f_notimplement
6629 #if defined HAVE_SETEGID
6647 #define p_sys_setegid rb_f_notimplement
6651 #if defined HAVE_SETREGID
6666 rb_gid_t rgid, egid;
6668 rgid = OBJ2GID(rid);
6669 egid = OBJ2GID(eid);
6674 #define p_sys_setregid rb_f_notimplement
6677 #if defined HAVE_SETRESGID
6692 rb_gid_t rgid, egid, sgid;
6694 rgid = OBJ2GID(rid);
6695 egid = OBJ2GID(eid);
6696 sgid = OBJ2GID(sid);
6697 if (setresgid(rgid, egid, sgid) != 0)
rb_sys_fail(0);
6701 #define p_sys_setresgid rb_f_notimplement
6705 #if defined HAVE_ISSETUGID
6719 p_sys_issetugid(
VALUE obj)
6721 return RBOOL(issetugid());
6724 #define p_sys_issetugid rb_f_notimplement
6741 proc_getgid(
VALUE obj)
6743 rb_gid_t gid = getgid();
6748 #if defined(HAVE_SETRESGID) || defined(HAVE_SETREGID) || defined(HAVE_SETRGID) || defined(HAVE_SETGID)
6767 #if defined(HAVE_SETRESGID)
6769 #elif defined HAVE_SETREGID
6771 #elif defined HAVE_SETRGID
6773 #elif defined HAVE_SETGID
6775 if (getegid() == gid) {
6786 #define proc_setgid rb_f_notimplement
6790 #if defined(_SC_NGROUPS_MAX) || defined(NGROUPS_MAX)
6810 static int _maxgroups = -1;
6812 get_sc_ngroups_max(
void)
6814 #ifdef _SC_NGROUPS_MAX
6815 return (
int)sysconf(_SC_NGROUPS_MAX);
6816 #elif defined(NGROUPS_MAX)
6817 return (
int)NGROUPS_MAX;
6825 if (_maxgroups < 0) {
6826 _maxgroups = get_sc_ngroups_max();
6828 _maxgroups = RB_MAX_GROUPS;
6837 #ifdef HAVE_GETGROUPS
6861 proc_getgroups(
VALUE obj)
6867 ngroups = getgroups(0, NULL);
6871 groups =
ALLOCV_N(rb_gid_t, tmp, ngroups);
6873 ngroups = getgroups(ngroups, groups);
6878 for (i = 0; i < ngroups; i++)
6886 #define proc_getgroups rb_f_notimplement
6890 #ifdef HAVE_SETGROUPS
6915 if (ngroups > maxgroups())
6918 groups =
ALLOCV_N(rb_gid_t, tmp, ngroups);
6920 for (i = 0; i < ngroups; i++) {
6923 groups[i] = OBJ2GID1(g);
6927 if (setgroups(ngroups, groups) == -1)
6932 return proc_getgroups(obj);
6935 #define proc_setgroups rb_f_notimplement
6939 #ifdef HAVE_INITGROUPS
6965 return proc_getgroups(obj);
6968 #define proc_initgroups rb_f_notimplement
6971 #if defined(_SC_NGROUPS_MAX) || defined(NGROUPS_MAX)
6984 proc_getmaxgroups(
VALUE obj)
6989 #define proc_getmaxgroups rb_f_notimplement
6992 #ifdef HAVE_SETGROUPS
7005 int ngroups_max = get_sc_ngroups_max();
7010 if (ngroups > RB_MAX_GROUPS)
7011 ngroups = RB_MAX_GROUPS;
7013 if (ngroups_max > 0 && ngroups > ngroups_max)
7014 ngroups = ngroups_max;
7016 _maxgroups = ngroups;
7021 #define proc_setmaxgroups rb_f_notimplement
7024 #if defined(HAVE_DAEMON) || (defined(HAVE_WORKING_FORK) && defined(HAVE_SETSID))
7025 static int rb_daemon(
int nochdir,
int noclose);
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);
7063 extern const char ruby_null_device[];
7066 rb_daemon(
int nochdir,
int noclose)
7071 err = daemon(nochdir, noclose);
7076 switch (rb_fork_ruby(NULL)) {
7079 default: _exit(EXIT_SUCCESS);
7083 if (setsid() < 0) (void)0;
7088 if (!noclose && (n =
rb_cloexec_open(ruby_null_device, O_RDWR, 0)) != -1) {
7100 #define proc_daemon rb_f_notimplement
7113 static rb_gid_t SAVED_GROUP_ID = -1;
7115 #ifdef BROKEN_SETREGID
7117 setregid(rb_gid_t rgid, rb_gid_t egid)
7119 if (rgid != (rb_gid_t)-1 && rgid != getgid()) {
7120 if (egid == (rb_gid_t)-1) egid = getegid();
7121 if (setgid(rgid) < 0)
return -1;
7123 if (egid != (rb_gid_t)-1 && egid != getegid()) {
7124 if (setegid(egid) < 0)
return -1;
7152 if (geteuid() == 0) {
7153 #if defined(HAVE_SETRESGID)
7155 SAVED_GROUP_ID = gid;
7156 #elif defined HAVE_SETGID
7158 SAVED_GROUP_ID = gid;
7159 #elif defined(HAVE_SETREGID) && !defined(OBSOLETE_SETREGID)
7160 if (getgid() == gid) {
7161 if (SAVED_GROUP_ID == gid) {
7166 if (setregid(-1, SAVED_GROUP_ID) < 0)
rb_sys_fail(0);
7167 if (setregid(SAVED_GROUP_ID, 0) < 0)
rb_sys_fail(0);
7170 SAVED_GROUP_ID = gid;
7176 SAVED_GROUP_ID = gid;
7182 SAVED_GROUP_ID = gid;
7184 #elif defined(HAVE_SETRGID) && defined (HAVE_SETEGID)
7185 if (getgid() == gid) {
7186 if (SAVED_GROUP_ID == gid) {
7201 SAVED_GROUP_ID = gid;
7208 SAVED_GROUP_ID = gid;
7215 #if defined(HAVE_SETRESGID)
7216 if (setresgid((getgid() == gid)? (rb_gid_t)-1: gid,
7217 (getegid() == gid)? (rb_gid_t)-1: gid,
7218 (SAVED_GROUP_ID == gid)? (rb_gid_t)-1: gid) < 0)
rb_sys_fail(0);
7219 SAVED_GROUP_ID = gid;
7220 #elif defined(HAVE_SETREGID) && !defined(OBSOLETE_SETREGID)
7221 if (SAVED_GROUP_ID == gid) {
7222 if (setregid((getgid() == gid)? (rb_uid_t)-1: gid,
7223 (getegid() == gid)? (rb_uid_t)-1: gid) < 0)
7226 else if (getgid() != gid) {
7227 if (setregid(gid, (getegid() == gid)? (rb_uid_t)-1: gid) < 0)
7229 SAVED_GROUP_ID = gid;
7231 else if ( getegid() != gid) {
7233 SAVED_GROUP_ID = gid;
7237 if (setregid(-1, SAVED_GROUP_ID) < 0)
rb_sys_fail(0);
7238 if (setregid(SAVED_GROUP_ID, gid) < 0)
rb_sys_fail(0);
7239 SAVED_GROUP_ID = gid;
7242 #elif defined(HAVE_SETRGID) && defined(HAVE_SETEGID)
7243 if (SAVED_GROUP_ID == gid) {
7244 if (getegid() != gid && setegid(gid) < 0)
rb_sys_fail(0);
7245 if (getgid() != gid && setrgid(gid) < 0)
rb_sys_fail(0);
7247 else if ( getegid() == gid) {
7248 if (getgid() != gid) {
7250 SAVED_GROUP_ID = gid;
7254 SAVED_GROUP_ID = gid;
7258 else if ( getgid() == gid) {
7261 SAVED_GROUP_ID = gid;
7267 #elif defined HAVE_44BSD_SETGID
7268 if (getgid() == gid) {
7271 SAVED_GROUP_ID = gid;
7276 #elif defined HAVE_SETEGID
7277 if (getgid() == gid && SAVED_GROUP_ID == gid) {
7283 #elif defined HAVE_SETGID
7284 if (getgid() == gid && SAVED_GROUP_ID == gid) {
7312 proc_geteuid(
VALUE obj)
7314 rb_uid_t euid = geteuid();
7318 #if defined(HAVE_SETRESUID) || defined(HAVE_SETREUID) || defined(HAVE_SETEUID) || defined(HAVE_SETUID) || defined(_POSIX_SAVED_IDS)
7320 proc_seteuid(rb_uid_t uid)
7322 #if defined(HAVE_SETRESUID)
7324 #elif defined HAVE_SETREUID
7326 #elif defined HAVE_SETEUID
7328 #elif defined HAVE_SETUID
7329 if (uid == getuid()) {
7341 #if defined(HAVE_SETRESUID) || defined(HAVE_SETREUID) || defined(HAVE_SETEUID) || defined(HAVE_SETUID)
7355 proc_seteuid(OBJ2UID(euid));
7359 #define proc_seteuid_m rb_f_notimplement
7363 rb_seteuid_core(rb_uid_t euid)
7365 #if defined(HAVE_SETRESUID) || (defined(HAVE_SETREUID) && !defined(OBSOLETE_SETREUID))
7371 #if defined(HAVE_SETRESUID) || (defined(HAVE_SETREUID) && !defined(OBSOLETE_SETREUID))
7375 #if defined(HAVE_SETRESUID)
7378 SAVED_USER_ID = euid;
7383 #elif defined(HAVE_SETREUID) && !defined(OBSOLETE_SETREUID)
7388 SAVED_USER_ID = euid;
7390 #elif defined HAVE_SETEUID
7392 #elif defined HAVE_SETUID
7419 rb_seteuid_core(OBJ2UID(
id));
7438 proc_getegid(
VALUE obj)
7440 rb_gid_t egid = getegid();
7445 #if defined(HAVE_SETRESGID) || defined(HAVE_SETREGID) || defined(HAVE_SETEGID) || defined(HAVE_SETGID) || defined(_POSIX_SAVED_IDS)
7458 #if defined(HAVE_SETRESGID) || defined(HAVE_SETREGID) || defined(HAVE_SETEGID) || defined(HAVE_SETGID)
7464 #if defined(HAVE_SETRESGID) || defined(HAVE_SETREGID) || defined(HAVE_SETEGID) || defined(HAVE_SETGID)
7465 gid = OBJ2GID(egid);
7468 #if defined(HAVE_SETRESGID)
7470 #elif defined HAVE_SETREGID
7472 #elif defined HAVE_SETEGID
7474 #elif defined HAVE_SETGID
7475 if (gid == getgid()) {
7488 #if defined(HAVE_SETRESGID) || defined(HAVE_SETREGID) || defined(HAVE_SETEGID) || defined(HAVE_SETGID)
7489 #define proc_setegid_m proc_setegid
7491 #define proc_setegid_m rb_f_notimplement
7495 rb_setegid_core(rb_gid_t egid)
7497 #if defined(HAVE_SETRESGID) || (defined(HAVE_SETREGID) && !defined(OBSOLETE_SETREGID))
7503 #if defined(HAVE_SETRESGID) || (defined(HAVE_SETREGID) && !defined(OBSOLETE_SETREGID))
7507 #if defined(HAVE_SETRESGID)
7510 SAVED_GROUP_ID = egid;
7515 #elif defined(HAVE_SETREGID) && !defined(OBSOLETE_SETREGID)
7520 SAVED_GROUP_ID = egid;
7522 #elif defined HAVE_SETEGID
7524 #elif defined HAVE_SETGID
7551 rb_setegid_core(OBJ2GID(
id));
7566 p_uid_exchangeable(
VALUE _)
7568 #if defined(HAVE_SETRESUID)
7570 #elif defined(HAVE_SETREUID) && !defined(OBSOLETE_SETREUID)
7591 p_uid_exchange(
VALUE obj)
7594 #if defined(HAVE_SETRESUID) || (defined(HAVE_SETREUID) && !defined(OBSOLETE_SETREUID))
7601 #if defined(HAVE_SETRESUID) || (defined(HAVE_SETREUID) && !defined(OBSOLETE_SETREUID))
7605 #if defined(HAVE_SETRESUID)
7606 if (setresuid(euid, uid, uid) < 0)
rb_sys_fail(0);
7607 SAVED_USER_ID = uid;
7608 #elif defined(HAVE_SETREUID) && !defined(OBSOLETE_SETREUID)
7610 SAVED_USER_ID = uid;
7628 p_gid_exchangeable(
VALUE _)
7630 #if defined(HAVE_SETRESGID)
7632 #elif defined(HAVE_SETREGID) && !defined(OBSOLETE_SETREGID)
7653 p_gid_exchange(
VALUE obj)
7656 #if defined(HAVE_SETRESGID) || (defined(HAVE_SETREGID) && !defined(OBSOLETE_SETREGID))
7663 #if defined(HAVE_SETRESGID) || (defined(HAVE_SETREGID) && !defined(OBSOLETE_SETREGID))
7667 #if defined(HAVE_SETRESGID)
7668 if (setresgid(egid, gid, gid) < 0)
rb_sys_fail(0);
7669 SAVED_GROUP_ID = gid;
7670 #elif defined(HAVE_SETREGID) && !defined(OBSOLETE_SETREGID)
7672 SAVED_GROUP_ID = gid;
7691 p_uid_have_saved_id(
VALUE _)
7693 #if defined(HAVE_SETRESUID) || defined(HAVE_SETEUID) || defined(_POSIX_SAVED_IDS)
7701 #if defined(HAVE_SETRESUID) || defined(HAVE_SETEUID) || defined(_POSIX_SAVED_IDS)
7703 p_uid_sw_ensure(
VALUE i)
7705 rb_uid_t
id = (rb_uid_t)i;
7706 under_uid_switch = 0;
7707 id = rb_seteuid_core(
id);
7726 p_uid_switch(
VALUE obj)
7738 under_uid_switch = 1;
7745 else if (euid != SAVED_USER_ID) {
7746 proc_seteuid(SAVED_USER_ID);
7748 under_uid_switch = 1;
7763 p_uid_sw_ensure(
VALUE obj)
7765 under_uid_switch = 0;
7766 return p_uid_exchange(obj);
7770 p_uid_switch(
VALUE obj)
7782 p_uid_exchange(obj);
7784 under_uid_switch = 1;
7806 p_gid_have_saved_id(
VALUE _)
7808 #if defined(HAVE_SETRESGID) || defined(HAVE_SETEGID) || defined(_POSIX_SAVED_IDS)
7815 #if defined(HAVE_SETRESGID) || defined(HAVE_SETEGID) || defined(_POSIX_SAVED_IDS)
7817 p_gid_sw_ensure(
VALUE i)
7819 rb_gid_t
id = (rb_gid_t)i;
7820 under_gid_switch = 0;
7821 id = rb_setegid_core(
id);
7840 p_gid_switch(
VALUE obj)
7852 under_gid_switch = 1;
7859 else if (egid != SAVED_GROUP_ID) {
7860 proc_setegid(obj,
GIDT2NUM(SAVED_GROUP_ID));
7862 under_gid_switch = 1;
7877 p_gid_sw_ensure(
VALUE obj)
7879 under_gid_switch = 0;
7880 return p_gid_exchange(obj);
7884 p_gid_switch(
VALUE obj)
7896 p_gid_exchange(obj);
7898 under_gid_switch = 1;
7908 #if defined(HAVE_TIMES)
7912 #ifdef HAVE__SC_CLK_TCK
7913 return sysconf(_SC_CLK_TCK);
7914 #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)
7977 typedef 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)
7984 CONSTFUNC(
static timetick_int_t gcd_timetick_int(timetick_int_t, timetick_int_t));
7985 static timetick_int_t
7986 gcd_timetick_int(timetick_int_t a, timetick_int_t b)
8006 reduce_fraction(timetick_int_t *np, timetick_int_t *dp)
8008 timetick_int_t gcd = gcd_timetick_int(*np, *dp);
8016 reduce_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;
8037 timetick2dblnum(
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];
8058 timetick2dblnum_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))
8082 timetick2integer(
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]));
8124 make_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);
8160 static const mach_timebase_info_data_t *
8161 get_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;
8173 ruby_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;
8181 #if defined(NUM2CLOCKID)
8182 # define NUMERIC_CLOCKID 1
8184 # define NUMERIC_CLOCKID 0
8185 # define NUM2CLOCKID(x) 0
8188 #define clock_failed(name, err, arg) do { \
8189 int clock_error = (err); \
8190 rb_syserr_fail_str(clock_error, rb_sprintf("clock_" name "(%+"PRIsVALUE")", (arg))); \
8363 timetick_int_t numerators[2];
8364 timetick_int_t denominators[2];
8365 int num_numerators = 0;
8366 int num_denominators = 0;
8369 VALUE clk_id = argv[0];
8370 #ifdef HAVE_CLOCK_GETTIME
8375 #ifdef CLOCK_REALTIME
8376 if (clk_id == RUBY_CLOCK_REALTIME) {
8382 #ifdef CLOCK_MONOTONIC
8383 if (clk_id == RUBY_CLOCK_MONOTONIC) {
8384 c = CLOCK_MONOTONIC;
8389 #ifdef CLOCK_PROCESS_CPUTIME_ID
8390 if (clk_id == RUBY_CLOCK_PROCESS_CPUTIME_ID) {
8391 c = CLOCK_PROCESS_CPUTIME_ID;
8396 #ifdef CLOCK_THREAD_CPUTIME_ID
8397 if (clk_id == RUBY_CLOCK_THREAD_CPUTIME_ID) {
8398 c = CLOCK_THREAD_CPUTIME_ID;
8406 #ifdef HAVE_GETTIMEOFDAY
8411 #define RUBY_GETTIMEOFDAY_BASED_CLOCK_REALTIME ID2SYM(id_GETTIMEOFDAY_BASED_CLOCK_REALTIME)
8412 if (clk_id == RUBY_GETTIMEOFDAY_BASED_CLOCK_REALTIME) {
8414 ret = gettimeofday(&tv, 0);
8417 tt.giga_count = tv.tv_sec;
8418 tt.count = (int32_t)tv.tv_usec * 1000;
8419 denominators[num_denominators++] = 1000000000;
8424 #define RUBY_TIME_BASED_CLOCK_REALTIME ID2SYM(id_TIME_BASED_CLOCK_REALTIME)
8425 if (clk_id == RUBY_TIME_BASED_CLOCK_REALTIME) {
8428 if (t == (time_t)-1)
8432 denominators[num_denominators++] = 1000000000;
8437 #define RUBY_TIMES_BASED_CLOCK_MONOTONIC \
8438 ID2SYM(id_TIMES_BASED_CLOCK_MONOTONIC)
8439 if (clk_id == RUBY_TIMES_BASED_CLOCK_MONOTONIC) {
8442 unsigned_clock_t uc;
8444 if (c == (clock_t)-1)
8446 uc = (unsigned_clock_t)c;
8447 tt.count = (int32_t)(uc % 1000000000);
8448 tt.giga_count = (uc / 1000000000);
8449 denominators[num_denominators++] = get_clk_tck();
8455 #define RUBY_GETRUSAGE_BASED_CLOCK_PROCESS_CPUTIME_ID \
8456 ID2SYM(id_GETRUSAGE_BASED_CLOCK_PROCESS_CPUTIME_ID)
8457 if (clk_id == RUBY_GETRUSAGE_BASED_CLOCK_PROCESS_CPUTIME_ID) {
8458 struct rusage usage;
8460 ret = getrusage(RUSAGE_SELF, &usage);
8463 tt.giga_count = usage.ru_utime.tv_sec + usage.ru_stime.tv_sec;
8464 usec = (int32_t)(usage.ru_utime.tv_usec + usage.ru_stime.tv_usec);
8465 if (1000000 <= usec) {
8469 tt.count = usec * 1000;
8470 denominators[num_denominators++] = 1000000000;
8476 #define RUBY_TIMES_BASED_CLOCK_PROCESS_CPUTIME_ID \
8477 ID2SYM(id_TIMES_BASED_CLOCK_PROCESS_CPUTIME_ID)
8478 if (clk_id == RUBY_TIMES_BASED_CLOCK_PROCESS_CPUTIME_ID) {
8480 unsigned_clock_t utime, stime;
8481 if (times(&buf) == (clock_t)-1)
8483 utime = (unsigned_clock_t)buf.tms_utime;
8484 stime = (unsigned_clock_t)buf.tms_stime;
8485 tt.count = (int32_t)((utime % 1000000000) + (stime % 1000000000));
8486 tt.giga_count = (utime / 1000000000) + (stime / 1000000000);
8487 if (1000000000 <= tt.count) {
8488 tt.count -= 1000000000;
8491 denominators[num_denominators++] = get_clk_tck();
8496 #define RUBY_CLOCK_BASED_CLOCK_PROCESS_CPUTIME_ID \
8497 ID2SYM(id_CLOCK_BASED_CLOCK_PROCESS_CPUTIME_ID)
8498 if (clk_id == RUBY_CLOCK_BASED_CLOCK_PROCESS_CPUTIME_ID) {
8500 unsigned_clock_t uc;
8503 if (c == (clock_t)-1)
8505 uc = (unsigned_clock_t)c;
8506 tt.count = (int32_t)(uc % 1000000000);
8507 tt.giga_count = uc / 1000000000;
8508 denominators[num_denominators++] = CLOCKS_PER_SEC;
8513 if (clk_id == RUBY_MACH_ABSOLUTE_TIME_BASED_CLOCK_MONOTONIC) {
8514 const mach_timebase_info_data_t *info = get_mach_timebase_info();
8515 uint64_t t = mach_absolute_time();
8516 tt.count = (int32_t)(t % 1000000000);
8517 tt.giga_count = t / 1000000000;
8518 numerators[num_numerators++] = info->numer;
8519 denominators[num_denominators++] = info->denom;
8520 denominators[num_denominators++] = 1000000000;
8525 else if (NUMERIC_CLOCKID) {
8526 #if defined(HAVE_CLOCK_GETTIME)
8528 c = NUM2CLOCKID(clk_id);
8530 ret = clock_gettime(c, &ts);
8532 clock_failed(
"gettime",
errno, clk_id);
8533 tt.count = (int32_t)ts.tv_nsec;
8534 tt.giga_count = ts.tv_sec;
8535 denominators[num_denominators++] = 1000000000;
8542 clock_failed(
"gettime", EINVAL, clk_id);
8545 return make_clock_result(&tt, numerators, num_numerators, denominators, num_denominators, unit);
8590 timetick_int_t numerators[2];
8591 timetick_int_t denominators[2];
8592 int num_numerators = 0;
8593 int num_denominators = 0;
8594 #ifdef HAVE_CLOCK_GETRES
8599 VALUE clk_id = argv[0];
8602 #ifdef CLOCK_REALTIME
8603 if (clk_id == RUBY_CLOCK_REALTIME) {
8609 #ifdef CLOCK_MONOTONIC
8610 if (clk_id == RUBY_CLOCK_MONOTONIC) {
8611 c = CLOCK_MONOTONIC;
8616 #ifdef CLOCK_PROCESS_CPUTIME_ID
8617 if (clk_id == RUBY_CLOCK_PROCESS_CPUTIME_ID) {
8618 c = CLOCK_PROCESS_CPUTIME_ID;
8623 #ifdef CLOCK_THREAD_CPUTIME_ID
8624 if (clk_id == RUBY_CLOCK_THREAD_CPUTIME_ID) {
8625 c = CLOCK_THREAD_CPUTIME_ID;
8630 #ifdef RUBY_GETTIMEOFDAY_BASED_CLOCK_REALTIME
8631 if (clk_id == RUBY_GETTIMEOFDAY_BASED_CLOCK_REALTIME) {
8634 denominators[num_denominators++] = 1000000000;
8639 #ifdef RUBY_TIME_BASED_CLOCK_REALTIME
8640 if (clk_id == RUBY_TIME_BASED_CLOCK_REALTIME) {
8643 denominators[num_denominators++] = 1000000000;
8648 #ifdef RUBY_TIMES_BASED_CLOCK_MONOTONIC
8649 if (clk_id == RUBY_TIMES_BASED_CLOCK_MONOTONIC) {
8652 denominators[num_denominators++] = get_clk_tck();
8657 #ifdef RUBY_GETRUSAGE_BASED_CLOCK_PROCESS_CPUTIME_ID
8658 if (clk_id == RUBY_GETRUSAGE_BASED_CLOCK_PROCESS_CPUTIME_ID) {
8661 denominators[num_denominators++] = 1000000000;
8666 #ifdef RUBY_TIMES_BASED_CLOCK_PROCESS_CPUTIME_ID
8667 if (clk_id == RUBY_TIMES_BASED_CLOCK_PROCESS_CPUTIME_ID) {
8670 denominators[num_denominators++] = get_clk_tck();
8675 #ifdef RUBY_CLOCK_BASED_CLOCK_PROCESS_CPUTIME_ID
8676 if (clk_id == RUBY_CLOCK_BASED_CLOCK_PROCESS_CPUTIME_ID) {
8679 denominators[num_denominators++] = CLOCKS_PER_SEC;
8684 #ifdef RUBY_MACH_ABSOLUTE_TIME_BASED_CLOCK_MONOTONIC
8685 if (clk_id == RUBY_MACH_ABSOLUTE_TIME_BASED_CLOCK_MONOTONIC) {
8686 const mach_timebase_info_data_t *info = get_mach_timebase_info();
8689 numerators[num_numerators++] = info->numer;
8690 denominators[num_denominators++] = info->denom;
8691 denominators[num_denominators++] = 1000000000;
8696 else if (NUMERIC_CLOCKID) {
8697 #if defined(HAVE_CLOCK_GETRES)
8699 c = NUM2CLOCKID(clk_id);
8701 ret = clock_getres(c, &ts);
8703 clock_failed(
"getres",
errno, clk_id);
8704 tt.count = (int32_t)ts.tv_nsec;
8705 tt.giga_count = ts.tv_sec;
8706 denominators[num_denominators++] = 1000000000;
8713 clock_failed(
"getres", EINVAL, clk_id);
8716 if (unit ==
ID2SYM(id_hertz)) {
8717 return timetick2dblnum_reciprocal(&tt, numerators, num_numerators, denominators, num_denominators);
8720 return make_clock_result(&tt, numerators, num_numerators, denominators, num_denominators, unit);
8725 get_CHILD_STATUS(
ID _x,
VALUE *_y)
8731 get_PROCESS_ID(
ID _x,
VALUE *_y)
8823 static VALUE rb_mProcUID;
8824 static VALUE rb_mProcGID;
8825 static VALUE rb_mProcID_Syscall;
8857 rb_gc_prepare_heap();
9280 InitVM_process(
void)
9285 rb_gvar_ractor_local(
"$$");
9286 rb_gvar_ractor_local(
"$?");
9341 process_status_dump, process_status_load);
9379 #ifdef HAVE_GETPRIORITY
9390 #if defined(RLIM2NUM) && defined(RLIM_INFINITY)
9392 VALUE inf = RLIM2NUM(RLIM_INFINITY);
9393 #ifdef RLIM_SAVED_MAX
9395 VALUE v = RLIM_INFINITY == RLIM_SAVED_MAX ? inf : RLIM2NUM(RLIM_SAVED_MAX);
9402 #ifdef RLIM_SAVED_CUR
9404 VALUE v = RLIM_INFINITY == RLIM_SAVED_CUR ? inf : RLIM2NUM(RLIM_SAVED_CUR);
9445 #ifdef RLIMIT_MEMLOCK
9452 #ifdef RLIMIT_MSGQUEUE
9467 #ifdef RLIMIT_NOFILE
9498 #ifdef RLIMIT_RTPRIO
9505 #ifdef RLIMIT_RTTIME
9513 #ifdef RLIMIT_SBSIZE
9518 #ifdef RLIMIT_SIGPENDING
9553 #if defined(RUBY_CLOCK_REALTIME)
9554 #elif defined(RUBY_GETTIMEOFDAY_BASED_CLOCK_REALTIME)
9555 # define RUBY_CLOCK_REALTIME RUBY_GETTIMEOFDAY_BASED_CLOCK_REALTIME
9556 #elif defined(RUBY_TIME_BASED_CLOCK_REALTIME)
9557 # define RUBY_CLOCK_REALTIME RUBY_TIME_BASED_CLOCK_REALTIME
9559 #if defined(CLOCK_REALTIME) && defined(CLOCKID2NUM)
9562 #elif defined(RUBY_CLOCK_REALTIME)
9566 #if defined(RUBY_CLOCK_MONOTONIC)
9567 #elif defined(RUBY_MACH_ABSOLUTE_TIME_BASED_CLOCK_MONOTONIC)
9568 # define RUBY_CLOCK_MONOTONIC RUBY_MACH_ABSOLUTE_TIME_BASED_CLOCK_MONOTONIC
9570 #if defined(CLOCK_MONOTONIC) && defined(CLOCKID2NUM)
9573 #elif defined(RUBY_CLOCK_MONOTONIC)
9577 #if defined(RUBY_CLOCK_PROCESS_CPUTIME_ID)
9578 #elif defined(RUBY_GETRUSAGE_BASED_CLOCK_PROCESS_CPUTIME_ID)
9579 # define RUBY_CLOCK_PROCESS_CPUTIME_ID RUBY_GETRUSAGE_BASED_CLOCK_PROCESS_CPUTIME_ID
9581 #if defined(CLOCK_PROCESS_CPUTIME_ID) && defined(CLOCKID2NUM)
9584 #elif defined(RUBY_CLOCK_PROCESS_CPUTIME_ID)
9588 #if defined(CLOCK_THREAD_CPUTIME_ID) && defined(CLOCKID2NUM)
9591 #elif defined(RUBY_CLOCK_THREAD_CPUTIME_ID)
9596 #ifdef CLOCK_VIRTUAL
9604 #ifdef CLOCK_REALTIME_FAST
9608 #ifdef CLOCK_REALTIME_PRECISE
9612 #ifdef CLOCK_REALTIME_COARSE
9616 #ifdef CLOCK_REALTIME_ALARM
9620 #ifdef CLOCK_MONOTONIC_FAST
9624 #ifdef CLOCK_MONOTONIC_PRECISE
9628 #ifdef CLOCK_MONOTONIC_RAW
9632 #ifdef CLOCK_MONOTONIC_RAW_APPROX
9636 #ifdef CLOCK_MONOTONIC_COARSE
9640 #ifdef CLOCK_BOOTTIME
9644 #ifdef CLOCK_BOOTTIME_ALARM
9652 #ifdef CLOCK_UPTIME_FAST
9656 #ifdef CLOCK_UPTIME_PRECISE
9660 #ifdef CLOCK_UPTIME_RAW
9664 #ifdef CLOCK_UPTIME_RAW_APPROX
9680 #if defined(HAVE_TIMES) || defined(_WIN32)
9694 SAVED_USER_ID = geteuid();
9695 SAVED_GROUP_ID = getegid();
9718 #ifdef p_uid_from_name
9721 #ifdef p_gid_from_name
9752 #define define_id(name) id_##name = rb_intern_const(#name)
9765 define_id(new_pgroup);
9767 define_id(unsetenv_others);
9770 define_id(close_others);
9771 define_id(nanosecond);
9772 define_id(microsecond);
9773 define_id(millisecond);
9775 define_id(float_microsecond);
9776 define_id(float_millisecond);
9777 define_id(float_second);
9778 define_id(GETTIMEOFDAY_BASED_CLOCK_REALTIME);
9779 define_id(TIME_BASED_CLOCK_REALTIME);
9780 #ifdef CLOCK_REALTIME
9781 define_id(CLOCK_REALTIME);
9783 #ifdef CLOCK_MONOTONIC
9784 define_id(CLOCK_MONOTONIC);
9786 #ifdef CLOCK_PROCESS_CPUTIME_ID
9787 define_id(CLOCK_PROCESS_CPUTIME_ID);
9789 #ifdef CLOCK_THREAD_CPUTIME_ID
9790 define_id(CLOCK_THREAD_CPUTIME_ID);
9793 define_id(TIMES_BASED_CLOCK_MONOTONIC);
9794 define_id(TIMES_BASED_CLOCK_PROCESS_CPUTIME_ID);
9797 define_id(GETRUSAGE_BASED_CLOCK_PROCESS_CPUTIME_ID);
9799 define_id(CLOCK_BASED_CLOCK_PROCESS_CPUTIME_ID);
9801 define_id(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_singleton_class(VALUE obj)
Finds or creates the singleton class of the passed object.
VALUE rb_define_class_under(VALUE outer, const char *name, VALUE super)
Defines a class under the namespace of outer.
VALUE rb_define_module(const char *name)
Defines a top-level module.
VALUE rb_define_module_under(VALUE outer, const char *name)
Defines a module under the namespace of outer.
void rb_define_alias(VALUE klass, const char *name1, const char *name2)
Defines an alias of a method.
void rb_define_module_function(VALUE module, const char *name, VALUE(*func)(ANYARGS), int argc)
Defines a module function for a module.
void rb_define_attr(VALUE klass, const char *name, int read, int write)
Defines public accessor method(s) for an attribute.
void rb_undef_method(VALUE klass, const char *name)
Defines an undef of a method.
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 CONST_ID
Old name of RUBY_CONST_ID.
#define ALLOCV_END
Old name of RB_ALLOCV_END.
#define SYMBOL_P
Old name of RB_SYMBOL_P.
void ruby_stop(int ex)
Calls ruby_cleanup() and exits the process.
void rb_notimplement(void)
void * rb_check_typeddata(VALUE obj, const rb_data_type_t *data_type)
Identical to rb_typeddata_is_kind_of(), except it raises exceptions instead of returning false.
void rb_raise(VALUE exc_class, const char *fmt,...)
Exception entry point.
VALUE rb_eNotImpError
NotImplementedError exception.
void rb_exc_raise(VALUE mesg)
Raises an exception in the current thread.
void rb_syserr_fail(int e, const char *mesg)
Raises appropriate exception that represents a C errno.
void rb_bug(const char *fmt,...)
Interpreter panic switch.
VALUE rb_eSystemExit
SystemExit exception.
void rb_sys_fail(const char *mesg)
Converts a C errno into a Ruby exception, then raises it.
void rb_syserr_fail_str(int e, VALUE mesg)
Identical to rb_syserr_fail(), except it takes the message in Ruby's String instead of C's.
VALUE rb_eRuntimeError
RuntimeError exception.
void rb_warn(const char *fmt,...)
Identical to rb_warning(), except it reports unless $VERBOSE is nil.
VALUE rb_exc_new_str(VALUE etype, VALUE str)
Identical to rb_exc_new_cstr(), except it takes a Ruby's string instead of C's.
VALUE rb_eArgError
ArgumentError exception.
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_unexpected_type(VALUE x, int t)
Fails with the given object's type incompatibility to the type.
void rb_exit(int status)
Terminates the current execution context.
VALUE rb_mProcess
Process module.
VALUE rb_class_new_instance(int argc, const VALUE *argv, VALUE klass)
Allocates, then initialises an instance of the given class.
VALUE rb_cThread
Thread class.
VALUE rb_equal(VALUE lhs, VALUE rhs)
This function is an optimised version of calling #==.
VALUE rb_obj_freeze(VALUE obj)
Just calls rb_obj_freeze_inline() inside.
VALUE rb_to_int(VALUE val)
Identical to rb_check_to_int(), except it raises in case of conversion mismatch.
#define RB_OBJ_WRITTEN(old, oldv, young)
Identical to RB_OBJ_WRITE(), except it doesn't write any values, but only a WB declaration.
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.
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_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.
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.
VALUE rb_process_status_wait(rb_pid_t pid, int flags)
Wait for the specified process to terminate, reap it, and return its status.
void rb_last_status_set(int status, rb_pid_t pid)
Sets the "last status", or the $?.
VALUE rb_detach_process(rb_pid_t pid)
"Detaches" a subprocess.
const char * ruby_signal_name(int signo)
Queries the name of the signal.
VALUE rb_f_kill(int argc, const VALUE *argv)
Sends a signal ("kills") to processes.
VALUE rb_str_append(VALUE dst, VALUE src)
Identical to rb_str_buf_append(), except it converts the right hand side before concatenating.
VALUE rb_str_tmp_new(long len)
Allocates a "temporary" string.
VALUE rb_str_subseq(VALUE str, long beg, long len)
Identical to rb_str_substr(), except the numbers are interpreted as byte offsets instead of character...
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.
int rb_method_basic_definition_p(VALUE klass, ID mid)
Well...
void rb_define_alloc_func(VALUE klass, rb_alloc_func_t func)
Sets the allocator function of a class.
ID rb_check_id(volatile VALUE *namep)
Detects if the given name is already interned or not.
VALUE rb_sym2str(VALUE symbol)
Obtain a frozen string representation of a symbol (not including the leading colon).
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.
char * ptr
Pointer to the underlying memory region, of at least capa bytes.
VALUE rb_io_check_io(VALUE io)
Try converting an object to its IO representation using its to_io method, if any.
int len
Length of the buffer.
VALUE rb_ractor_stderr(void)
Queries the standard error of the current Ractor that is calling this function.
void * rb_thread_call_without_gvl2(void *(*func)(void *), void *data1, rb_unblock_function_t *ubf, void *data2)
Identical to rb_thread_call_without_gvl(), except it does not interface with signals etc.
void * rb_thread_call_without_gvl(void *(*func)(void *), void *data1, rb_unblock_function_t *ubf, void *data2)
Allows the passed function to run in parallel with other Ruby threads.
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.
#define RARRAY_LEN
Just another name of rb_array_len.
static int RARRAY_LENINT(VALUE ary)
Identical to rb_array_len(), except it differs for the return type.
static void RARRAY_ASET(VALUE ary, long i, VALUE v)
Assigns an object in an array.
#define RARRAY_AREF(a, i)
#define RUBY_DEFAULT_FREE
This is a value you can set to RData::dfree.
#define RHASH_SIZE(h)
Queries the size of the hash.
#define RHASH_EMPTY_P(h)
Checks if the hash is empty.
#define StringValue(v)
Ensures that the parameter object is a String.
static char * RSTRING_PTR(VALUE str)
Queries the contents pointer of the string.
static long RSTRING_LEN(VALUE str)
Queries the length of the string.
#define StringValueCStr(v)
Identical to StringValuePtr, except it additionally checks for the contents for viability as a C stri...
#define RUBY_TYPED_DEFAULT_FREE
This is a value you can set to rb_data_type_struct::dfree.
#define TypedData_Get_Struct(obj, type, data_type, sval)
Obtains a C struct from inside of a wrapper Ruby object.
#define TypedData_Make_Struct(klass, type, data_type, sval)
Identical to TypedData_Wrap_Struct, except it allocates a new data region internally instead of takin...
const char * rb_class2name(VALUE klass)
Queries the name of the passed class.
#define FilePathValue(v)
Ensures that the parameter object is a path.
#define errno
Ractor-aware version of errno.
#define InitVM(ext)
This macro is for internal use.
VALUE rb_fiber_scheduler_current(void)
Identical to rb_fiber_scheduler_get(), except it also returns RUBY_Qnil in case of a blocking fiber.
VALUE rb_fiber_scheduler_kernel_sleepv(VALUE scheduler, int argc, VALUE *argv)
Identical to rb_fiber_scheduler_kernel_sleep(), except it can pass multiple arguments.
VALUE rb_fiber_scheduler_process_wait(VALUE scheduler, rb_pid_t pid, int flags)
Non-blocking waitpid.
static bool RB_SPECIAL_CONST_P(VALUE obj)
Checks if the given object is of enum ruby_special_consts.
#define RTEST
This is an old name of RB_TEST.
#define _(args)
This was a transition path from K&R to ANSI.
This is the struct that holds necessary info for a struct.
const char * wrap_struct_name
Name of structs of this kind.
Ruby's IO, metadata and buffers.
VALUE tied_io_for_writing
Duplex IO object, if set.
#define UIDT2NUM
Converts a C's uid_t into an instance of rb_cInteger.
#define NUM2UIDT
Converts an instance of rb_cNumeric into C's uid_t.
uintptr_t ID
Type that represents a Ruby identifier such as a variable name.
uintptr_t VALUE
Type that represents a Ruby object.
static enum ruby_value_type RB_BUILTIN_TYPE(VALUE obj)
Queries the type of the object.
static void Check_Type(VALUE v, enum ruby_value_type t)
Identical to RB_TYPE_P(), except it raises exceptions on predication failure.
static bool RB_TYPE_P(VALUE obj, enum ruby_value_type t)
Queries if the given object is of given type.
void * ruby_xmalloc(size_t size)
Allocates a storage instance.