1 /**********************************************************************
6 created at: Tue Aug 10 14:30:50 JST 1993
8 Copyright (C) 1993-2007 Yukihiro Matsumoto
9 Copyright (C) 2000 Network Applied Communication Laboratory, Inc.
10 Copyright (C) 2000 Information-technology Promotion Agency, Japan
12 **********************************************************************/
14 #include "ruby/internal/config.h"
16 #include "ruby/fiber/scheduler.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/numeric.h"
107 #include "internal/object.h"
108 #include "internal/process.h"
109 #include "internal/thread.h"
110 #include "internal/variable.h"
111 #include "internal/warnings.h"
115 #include "ruby/thread.h"
116 #include "ruby/util.h"
118 #include "ruby/ractor.h"
120 /* define system APIs */
123 #define open rb_w32_uopen
126 #if defined(HAVE_TIMES) || defined(_WIN32)
127 static VALUE rb_cProcessTms
;
131 #define WIFEXITED(w) (((w) & 0xff) == 0)
134 #define WIFSIGNALED(w) (((w) & 0x7f) > 0 && (((w) & 0x7f) < 0x7f))
137 #define WIFSTOPPED(w) (((w) & 0xff) == 0x7f)
140 #define WEXITSTATUS(w) (((w) >> 8) & 0xff)
143 #define WTERMSIG(w) ((w) & 0x7f)
146 #define WSTOPSIG WEXITSTATUS
149 #if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__bsdi__)
150 #define HAVE_44BSD_SETUID 1
151 #define HAVE_44BSD_SETGID 1
159 #ifdef BROKEN_SETREUID
160 #define setreuid ruby_setreuid
161 int setreuid(rb_uid_t ruid
, rb_uid_t euid
);
163 #ifdef BROKEN_SETREGID
164 #define setregid ruby_setregid
165 int setregid(rb_gid_t rgid
, rb_gid_t egid
);
168 #if defined(HAVE_44BSD_SETUID) || defined(__APPLE__)
169 #if !defined(USE_SETREUID) && !defined(BROKEN_SETREUID)
170 #define OBSOLETE_SETREUID 1
172 #if !defined(USE_SETREGID) && !defined(BROKEN_SETREGID)
173 #define OBSOLETE_SETREGID 1
177 static void check_uid_switch(void);
178 static void check_gid_switch(void);
179 static int exec_async_signal_safe(const struct rb_execarg
*, char *, size_t);
181 VALUE
rb_envtbl(void);
182 VALUE
rb_env_to_hash(void);
185 #define p_uid_from_name p_uid_from_name
186 #define p_gid_from_name p_gid_from_name
189 #if defined(HAVE_UNISTD_H)
190 # if defined(HAVE_GETLOGIN_R)
191 # define USE_GETLOGIN_R 1
192 # define GETLOGIN_R_SIZE_DEFAULT 0x100
193 # define GETLOGIN_R_SIZE_LIMIT 0x1000
194 # if defined(_SC_LOGIN_NAME_MAX)
195 # define GETLOGIN_R_SIZE_INIT sysconf(_SC_LOGIN_NAME_MAX)
197 # define GETLOGIN_R_SIZE_INIT GETLOGIN_R_SIZE_DEFAULT
199 # elif defined(HAVE_GETLOGIN)
200 # define USE_GETLOGIN 1
204 #if defined(HAVE_PWD_H)
205 # if defined(HAVE_GETPWUID_R)
206 # define USE_GETPWUID_R 1
207 # elif defined(HAVE_GETPWUID)
208 # define USE_GETPWUID 1
210 # if defined(HAVE_GETPWNAM_R)
211 # define USE_GETPWNAM_R 1
212 # elif defined(HAVE_GETPWNAM)
213 # define USE_GETPWNAM 1
215 # if defined(HAVE_GETPWNAM_R) || defined(HAVE_GETPWUID_R)
216 # define GETPW_R_SIZE_DEFAULT 0x1000
217 # define GETPW_R_SIZE_LIMIT 0x10000
218 # if defined(_SC_GETPW_R_SIZE_MAX)
219 # define GETPW_R_SIZE_INIT sysconf(_SC_GETPW_R_SIZE_MAX)
221 # define GETPW_R_SIZE_INIT GETPW_R_SIZE_DEFAULT
224 # ifdef USE_GETPWNAM_R
225 # define PREPARE_GETPWNAM \
227 # define FINISH_GETPWNAM \
228 (getpw_buf ? (void)rb_str_resize(getpw_buf, 0) : (void)0)
229 # define OBJ2UID1(id) obj2uid((id), &getpw_buf)
230 # define OBJ2UID(id) obj2uid0(id)
231 static rb_uid_t
obj2uid(VALUE id
, VALUE
*getpw_buf
);
232 static inline rb_uid_t
242 # define PREPARE_GETPWNAM /* do nothing */
243 # define FINISH_GETPWNAM /* do nothing */
244 # define OBJ2UID1(id) obj2uid((id))
245 # define OBJ2UID(id) obj2uid((id))
246 static rb_uid_t
obj2uid(VALUE id
);
249 # define PREPARE_GETPWNAM /* do nothing */
250 # define FINISH_GETPWNAM /* do nothing */
251 # define OBJ2UID1(id) NUM2UIDT(id)
252 # define OBJ2UID(id) NUM2UIDT(id)
253 # ifdef p_uid_from_name
254 # undef p_uid_from_name
255 # define p_uid_from_name rb_f_notimplement
259 #if defined(HAVE_GRP_H)
260 # if defined(HAVE_GETGRNAM_R) && defined(_SC_GETGR_R_SIZE_MAX)
261 # define USE_GETGRNAM_R
262 # define GETGR_R_SIZE_INIT sysconf(_SC_GETGR_R_SIZE_MAX)
263 # define GETGR_R_SIZE_DEFAULT 0x1000
264 # define GETGR_R_SIZE_LIMIT 0x10000
266 # ifdef USE_GETGRNAM_R
267 # define PREPARE_GETGRNAM \
269 # define FINISH_GETGRNAM \
270 (getgr_buf ? (void)rb_str_resize(getgr_buf, 0) : (void)0)
271 # define OBJ2GID1(id) obj2gid((id), &getgr_buf)
272 # define OBJ2GID(id) obj2gid0(id)
273 static rb_gid_t
obj2gid(VALUE id
, VALUE
*getgr_buf
);
274 static inline rb_gid_t
283 static rb_gid_t
obj2gid(VALUE id
, VALUE
*getgr_buf
);
285 # define PREPARE_GETGRNAM /* do nothing */
286 # define FINISH_GETGRNAM /* do nothing */
287 # define OBJ2GID1(id) obj2gid((id))
288 # define OBJ2GID(id) obj2gid((id))
289 static rb_gid_t
obj2gid(VALUE id
);
292 # define PREPARE_GETGRNAM /* do nothing */
293 # define FINISH_GETGRNAM /* do nothing */
294 # define OBJ2GID1(id) NUM2GIDT(id)
295 # define OBJ2GID(id) NUM2GIDT(id)
296 # ifdef p_gid_from_name
297 # undef p_gid_from_name
298 # define p_gid_from_name rb_f_notimplement
302 #if SIZEOF_CLOCK_T == SIZEOF_INT
303 typedef unsigned int unsigned_clock_t
;
304 #elif SIZEOF_CLOCK_T == SIZEOF_LONG
305 typedef unsigned long unsigned_clock_t
;
306 #elif defined(HAVE_LONG_LONG) && SIZEOF_CLOCK_T == SIZEOF_LONG_LONG
307 typedef unsigned LONG_LONG unsigned_clock_t
;
310 typedef void (*sig_t
) (int);
313 #define id_exception idException
314 static ID id_in
, id_out
, id_err
, id_pid
, id_uid
, id_gid
;
315 static ID id_close
, id_child
;
320 static ID id_new_pgroup
;
322 static ID id_unsetenv_others
, id_chdir
, id_umask
, id_close_others
;
323 static ID id_nanosecond
, id_microsecond
, id_millisecond
, id_second
;
324 static ID id_float_microsecond
, id_float_millisecond
, id_float_second
;
325 static ID id_GETTIMEOFDAY_BASED_CLOCK_REALTIME
, id_TIME_BASED_CLOCK_REALTIME
;
327 static ID id_TIMES_BASED_CLOCK_MONOTONIC
;
328 static ID id_TIMES_BASED_CLOCK_PROCESS_CPUTIME_ID
;
331 static ID id_GETRUSAGE_BASED_CLOCK_PROCESS_CPUTIME_ID
;
333 static ID id_CLOCK_BASED_CLOCK_PROCESS_CPUTIME_ID
;
335 static ID id_MACH_ABSOLUTE_TIME_BASED_CLOCK_MONOTONIC
;
339 /* execv and execl are async-signal-safe since SUSv4 (POSIX.1-2008, XPG7) */
340 #if defined(__sun) && !defined(_XPG7) /* Solaris 10, 9, ... */
341 #define execv(path, argv) (rb_async_bug_errno("unreachable: async-signal-unsafe execv() is called", 0))
342 #define execl(path, arg0, arg1, arg2, term) do { extern char **environ; execle((path), (arg0), (arg1), (arg2), (term), (environ)); } while (0)
343 #define ALWAYS_NEED_ENVP 1
345 #define ALWAYS_NEED_ENVP 0
349 assert_close_on_exec(int fd
)
351 #if VM_CHECK_MODE > 0
352 #if defined(HAVE_FCNTL) && defined(F_GETFD) && defined(FD_CLOEXEC)
353 int flags
= fcntl(fd
, F_GETFD
);
355 static const char m
[] = "reserved FD closed unexpectedly?\n";
356 (void)!write(2, m
, sizeof(m
) - 1);
359 if (flags
& FD_CLOEXEC
) return;
360 rb_bug("reserved FD did not have close-on-exec set");
362 rb_bug("reserved FD without close-on-exec support");
363 #endif /* FD_CLOEXEC */
364 #endif /* VM_CHECK_MODE */
368 close_unless_reserved(int fd
)
370 if (rb_reserved_fd_p(fd
)) { /* async-signal-safe */
371 assert_close_on_exec(fd
);
374 return close(fd
); /* async-signal-safe */
377 /*#define DEBUG_REDIRECT*/
378 #if defined(DEBUG_REDIRECT)
381 ttyprintf(const char *fmt
, ...)
387 tty
= fopen("con", "w");
389 tty
= fopen("/dev/tty", "w");
395 vfprintf(tty
, fmt
, ap
);
402 redirect_dup(int oldfd
)
406 ttyprintf("dup(%d) => %d\n", oldfd
, ret
);
411 redirect_dup2(int oldfd
, int newfd
)
414 ret
= dup2(oldfd
, newfd
);
415 ttyprintf("dup2(%d, %d) => %d\n", oldfd
, newfd
, ret
);
420 redirect_cloexec_dup(int oldfd
)
423 ret
= rb_cloexec_dup(oldfd
);
424 ttyprintf("cloexec_dup(%d) => %d\n", oldfd
, ret
);
429 redirect_cloexec_dup2(int oldfd
, int newfd
)
432 ret
= rb_cloexec_dup2(oldfd
, newfd
);
433 ttyprintf("cloexec_dup2(%d, %d) => %d\n", oldfd
, newfd
, ret
);
438 redirect_close(int fd
)
441 ret
= close_unless_reserved(fd
);
442 ttyprintf("close(%d) => %d\n", fd
, ret
);
447 parent_redirect_open(const char *pathname
, int flags
, mode_t perm
)
450 ret
= rb_cloexec_open(pathname
, flags
, perm
);
451 ttyprintf("parent_open(\"%s\", 0x%x, 0%o) => %d\n", pathname
, flags
, perm
, ret
);
456 parent_redirect_close(int fd
)
459 ret
= close_unless_reserved(fd
);
460 ttyprintf("parent_close(%d) => %d\n", fd
, ret
);
465 #define redirect_dup(oldfd) dup(oldfd)
466 #define redirect_dup2(oldfd, newfd) dup2((oldfd), (newfd))
467 #define redirect_cloexec_dup(oldfd) rb_cloexec_dup(oldfd)
468 #define redirect_cloexec_dup2(oldfd, newfd) rb_cloexec_dup2((oldfd), (newfd))
469 #define redirect_close(fd) close_unless_reserved(fd)
470 #define parent_redirect_open(pathname, flags, perm) rb_cloexec_open((pathname), (flags), (perm))
471 #define parent_redirect_close(fd) close_unless_reserved(fd)
475 * Document-module: Process
477 * The module contains several groups of functionality for handling OS processes:
479 * * Low-level property introspection and management of the current process, like
480 * Process.argv0, Process.pid;
481 * * Low-level introspection of other processes, like Process.getpgid, Process.getpriority;
482 * * Management of the current process: Process.abort, Process.exit, Process.daemon, etc.
483 * (for convenience, most of those are also available as global functions
484 * and module functions of Kernel);
485 * * Creation and management of child processes: Process.fork, Process.spawn, and
487 * * Management of low-level system clock: Process.times and Process.clock_gettime,
488 * which could be important for proper benchmarking and other elapsed
489 * time measurement tasks.
495 return PIDT2NUM(getpid());
500 * Process.pid -> integer
502 * Returns the process id of this process. Not available on all
505 * Process.pid #=> 27415
509 proc_get_pid(VALUE _
)
517 return PIDT2NUM(getppid());
522 * Process.ppid -> integer
524 * Returns the process id of the parent of this process. Returns
525 * untrustworthy value on Win32/64. Not available on all platforms.
527 * puts "I am #{Process.pid}"
528 * Process.fork { puts "Dad is #{Process.ppid}" }
537 proc_get_ppid(VALUE _
)
543 /*********************************************************************
545 * Document-class: Process::Status
547 * Process::Status encapsulates the information on the
548 * status of a running or terminated system process. The built-in
549 * variable <code>$?</code> is either +nil+ or a
550 * Process::Status object.
552 * fork { exit 99 } #=> 26557
553 * Process.wait #=> 26557
554 * $?.class #=> Process::Status
557 * $?.stopped? #=> false
558 * $?.exited? #=> true
559 * $?.exitstatus #=> 99
561 * Posix systems record information on processes using a 16-bit
562 * integer. The lower bits record the process status (stopped,
563 * exited, signaled) and the upper bits possibly contain additional
564 * information (for example the program's return code in the case of
565 * exited processes). Pre Ruby 1.8, these bits were exposed directly
566 * to the Ruby program. Ruby now encapsulates these in a
567 * Process::Status object. To maximize compatibility,
568 * however, these objects retain a bit-oriented interface. In the
569 * descriptions that follow, when we talk about the integer value of
570 * _stat_, we're referring to this 16 bit value.
573 static VALUE rb_cProcessStatus
;
575 struct rb_process_status
{
581 static const rb_data_type_t rb_process_status_type
= {
582 .wrap_struct_name
= "Process::Status",
584 .dfree
= RUBY_DEFAULT_FREE
,
587 .flags
= RUBY_TYPED_FREE_IMMEDIATELY
,
591 rb_process_status_allocate(VALUE klass
)
593 struct rb_process_status
*data
= NULL
;
595 return TypedData_Make_Struct(klass
, struct rb_process_status
, &rb_process_status_type
, data
);
599 rb_last_status_get(void)
601 return GET_THREAD()->last_status
;
606 * Process.last_status -> Process::Status or nil
608 * Returns the status of the last executed child process in the
611 * Process.wait Process.spawn("ruby", "-e", "exit 13")
612 * Process.last_status #=> #<Process::Status: pid 4825 exit 13>
614 * If no child process has ever been executed in the current
615 * thread, this returns +nil+.
617 * Process.last_status #=> nil
620 proc_s_last_status(VALUE mod
)
622 return rb_last_status_get();
626 rb_process_status_new(rb_pid_t pid
, int status
, int error
)
628 VALUE last_status
= rb_process_status_allocate(rb_cProcessStatus
);
630 struct rb_process_status
*data
= RTYPEDDATA_DATA(last_status
);
632 data
->status
= status
;
635 rb_obj_freeze(last_status
);
640 process_status_dump(VALUE status
)
642 VALUE dump
= rb_class_new_instance(0, 0, rb_cObject
);
643 struct rb_process_status
*data
= RTYPEDDATA_DATA(status
);
645 rb_ivar_set(dump
, id_status
, INT2NUM(data
->status
));
646 rb_ivar_set(dump
, id_pid
, PIDT2NUM(data
->pid
));
652 process_status_load(VALUE real_obj
, VALUE load_obj
)
654 struct rb_process_status
*data
= rb_check_typeddata(real_obj
, &rb_process_status_type
);
655 VALUE status
= rb_attr_get(load_obj
, id_status
);
656 VALUE pid
= rb_attr_get(load_obj
, id_pid
);
657 data
->pid
= NIL_P(pid
) ? 0 : NUM2PIDT(pid
);
658 data
->status
= NIL_P(status
) ? 0 : NUM2INT(status
);
663 rb_last_status_set(int status
, rb_pid_t pid
)
665 GET_THREAD()->last_status
= rb_process_status_new(pid
, status
, 0);
669 rb_last_status_clear(void)
671 GET_THREAD()->last_status
= Qnil
;
677 struct rb_process_status
*data
= RTYPEDDATA_DATA(pst
);
682 pst_status(VALUE pst
)
684 struct rb_process_status
*data
= RTYPEDDATA_DATA(pst
);
690 * stat.to_i -> integer
692 * Returns the bits in _stat_ as an Integer. Poking
693 * around in these bits is platform dependent.
695 * fork { exit 0xab } #=> 26566
696 * Process.wait #=> 26566
697 * sprintf('%04x', $?.to_i) #=> "ab00"
703 int status
= pst_status(self
);
704 return RB_INT2NUM(status
);
707 #define PST2INT(st) pst_status(st)
711 * stat.pid -> integer
713 * Returns the process ID that this status object represents.
715 * fork { exit } #=> 26569
716 * Process.wait #=> 26569
721 pst_pid_m(VALUE self
)
723 rb_pid_t pid
= pst_pid(self
);
724 return PIDT2NUM(pid
);
727 static VALUE
pst_message_status(VALUE str
, int status
);
730 pst_message(VALUE str
, rb_pid_t pid
, int status
)
732 rb_str_catf(str
, "pid %ld", (long)pid
);
733 pst_message_status(str
, status
);
737 pst_message_status(VALUE str
, int status
)
739 if (WIFSTOPPED(status
)) {
740 int stopsig
= WSTOPSIG(status
);
741 const char *signame
= ruby_signal_name(stopsig
);
743 rb_str_catf(str
, " stopped SIG%s (signal %d)", signame
, stopsig
);
746 rb_str_catf(str
, " stopped signal %d", stopsig
);
749 if (WIFSIGNALED(status
)) {
750 int termsig
= WTERMSIG(status
);
751 const char *signame
= ruby_signal_name(termsig
);
753 rb_str_catf(str
, " SIG%s (signal %d)", signame
, termsig
);
756 rb_str_catf(str
, " signal %d", termsig
);
759 if (WIFEXITED(status
)) {
760 rb_str_catf(str
, " exit %d", WEXITSTATUS(status
));
763 if (WCOREDUMP(status
)) {
764 rb_str_cat2(str
, " (core dumped)");
773 * stat.to_s -> string
775 * Show pid and exit status as a string.
778 * p $?.to_s #=> "pid 12766 exit 1"
790 status
= PST2INT(st
);
792 str
= rb_str_buf_new(0);
793 pst_message(str
, pid
, status
);
800 * stat.inspect -> string
802 * Override the inspection method.
805 * p $?.inspect #=> "#<Process::Status: pid 12861 exit 1>"
810 pst_inspect(VALUE st
)
818 return rb_sprintf("#<%s: uninitialized>", rb_class2name(CLASS_OF(st
)));
820 status
= PST2INT(st
);
822 str
= rb_sprintf("#<%s: ", rb_class2name(CLASS_OF(st
)));
823 pst_message(str
, pid
, status
);
824 rb_str_cat2(str
, ">");
831 * stat == other -> true or false
833 * Returns +true+ if the integer value of _stat_
834 * equals <em>other</em>.
838 pst_equal(VALUE st1
, VALUE st2
)
840 if (st1
== st2
) return Qtrue
;
841 return rb_equal(pst_to_i(st1
), st2
);
847 * stat & num -> integer
849 * Logical AND of the bits in _stat_ with <em>num</em>.
853 * sprintf('%04x', $?.to_i) #=> "3700"
854 * sprintf('%04x', $? & 0x1e00) #=> "1600"
858 pst_bitand(VALUE st1
, VALUE st2
)
860 int status
= PST2INT(st1
) & NUM2INT(st2
);
862 return INT2NUM(status
);
868 * stat >> num -> integer
870 * Shift the bits in _stat_ right <em>num</em> places.
872 * fork { exit 99 } #=> 26563
873 * Process.wait #=> 26563
879 pst_rshift(VALUE st1
, VALUE st2
)
881 int status
= PST2INT(st1
) >> NUM2INT(st2
);
883 return INT2NUM(status
);
889 * stat.stopped? -> true or false
891 * Returns +true+ if this process is stopped. This is only returned
892 * if the corresponding #wait call had the Process::WUNTRACED flag
897 pst_wifstopped(VALUE st
)
899 int status
= PST2INT(st
);
901 return RBOOL(WIFSTOPPED(status
));
907 * stat.stopsig -> integer or nil
909 * Returns the number of the signal that caused _stat_ to stop
910 * (or +nil+ if self is not stopped).
914 pst_wstopsig(VALUE st
)
916 int status
= PST2INT(st
);
918 if (WIFSTOPPED(status
))
919 return INT2NUM(WSTOPSIG(status
));
926 * stat.signaled? -> true or false
928 * Returns +true+ if _stat_ terminated because of
929 * an uncaught signal.
933 pst_wifsignaled(VALUE st
)
935 int status
= PST2INT(st
);
937 return RBOOL(WIFSIGNALED(status
));
943 * stat.termsig -> integer or nil
945 * Returns the number of the signal that caused _stat_ to
946 * terminate (or +nil+ if self was not terminated by an
951 pst_wtermsig(VALUE st
)
953 int status
= PST2INT(st
);
955 if (WIFSIGNALED(status
))
956 return INT2NUM(WTERMSIG(status
));
963 * stat.exited? -> true or false
965 * Returns +true+ if _stat_ exited normally (for
966 * example using an <code>exit()</code> call or finishing the
971 pst_wifexited(VALUE st
)
973 int status
= PST2INT(st
);
975 return RBOOL(WIFEXITED(status
));
981 * stat.exitstatus -> integer or nil
983 * Returns the least significant eight bits of the return code of
984 * _stat_. Only available if #exited? is +true+.
987 * Process.wait #=> 26572
988 * $?.exited? #=> true
989 * $?.exitstatus #=> 0
991 * fork { exit 99 } #=> 26573
992 * Process.wait #=> 26573
993 * $?.exited? #=> true
994 * $?.exitstatus #=> 99
998 pst_wexitstatus(VALUE st
)
1000 int status
= PST2INT(st
);
1002 if (WIFEXITED(status
))
1003 return INT2NUM(WEXITSTATUS(status
));
1010 * stat.success? -> true, false or nil
1012 * Returns +true+ if _stat_ is successful, +false+ if not.
1013 * Returns +nil+ if #exited? is not +true+.
1017 pst_success_p(VALUE st
)
1019 int status
= PST2INT(st
);
1021 if (!WIFEXITED(status
))
1023 return RBOOL(WEXITSTATUS(status
) == EXIT_SUCCESS
);
1029 * stat.coredump? -> true or false
1031 * Returns +true+ if _stat_ generated a coredump
1032 * when it terminated. Not available on all platforms.
1036 pst_wcoredump(VALUE st
)
1039 int status
= PST2INT(st
);
1041 return RBOOL(WCOREDUMP(status
));
1048 do_waitpid(rb_pid_t pid
, int *st
, int flags
)
1050 #if defined HAVE_WAITPID
1051 return waitpid(pid
, st
, flags
);
1052 #elif defined HAVE_WAIT4
1053 return wait4(pid
, st
, flags
, NULL
);
1055 # error waitpid or wait4 is required.
1059 #define WAITPID_LOCK_ONLY ((struct waitpid_state *)-1)
1061 struct waitpid_state
{
1062 struct list_node wnode
;
1063 rb_execution_context_t
*ec
;
1064 rb_nativethread_cond_t
*cond
;
1072 int rb_sigwait_fd_get(const rb_thread_t
*);
1073 void rb_sigwait_sleep(const rb_thread_t
*, int fd
, const rb_hrtime_t
*);
1074 void rb_sigwait_fd_put(const rb_thread_t
*, int fd
);
1075 void rb_thread_sleep_interruptible(void);
1078 waitpid_signal(struct waitpid_state
*w
)
1080 if (w
->ec
) { /* rb_waitpid */
1081 rb_threadptr_interrupt(rb_ec_thread_ptr(w
->ec
));
1084 else { /* ruby_waitpid_locked */
1086 rb_native_cond_signal(w
->cond
);
1094 * When a thread is done using sigwait_fd and there are other threads
1095 * sleeping on waitpid, we must kick one of the threads out of
1096 * rb_native_cond_wait so it can switch to rb_sigwait_sleep
1099 sigwait_fd_migrate_sleeper(rb_vm_t
*vm
)
1101 struct waitpid_state
*w
= 0;
1103 list_for_each(&vm
->waiting_pids
, w
, wnode
) {
1104 if (waitpid_signal(w
)) return;
1106 list_for_each(&vm
->waiting_grps
, w
, wnode
) {
1107 if (waitpid_signal(w
)) return;
1112 rb_sigwait_fd_migrate(rb_vm_t
*vm
)
1114 rb_native_mutex_lock(&vm
->waitpid_lock
);
1115 sigwait_fd_migrate_sleeper(vm
);
1116 rb_native_mutex_unlock(&vm
->waitpid_lock
);
1120 extern volatile unsigned int ruby_nocldwait
; /* signal.c */
1121 /* called by timer thread or thread which acquired sigwait_fd */
1123 waitpid_each(struct list_head
*head
)
1125 struct waitpid_state
*w
= 0, *next
;
1127 list_for_each_safe(head
, w
, next
, wnode
) {
1128 rb_pid_t ret
= do_waitpid(w
->pid
, &w
->status
, w
->options
| WNOHANG
);
1131 if (ret
== -1) w
->errnum
= errno
;
1134 list_del_init(&w
->wnode
);
1139 # define ruby_nocldwait 0
1143 ruby_waitpid_all(rb_vm_t
*vm
)
1146 rb_native_mutex_lock(&vm
->waitpid_lock
);
1147 waitpid_each(&vm
->waiting_pids
);
1148 if (list_empty(&vm
->waiting_pids
)) {
1149 waitpid_each(&vm
->waiting_grps
);
1151 /* emulate SA_NOCLDWAIT */
1152 if (list_empty(&vm
->waiting_pids
) && list_empty(&vm
->waiting_grps
)) {
1153 while (ruby_nocldwait
&& do_waitpid(-1, 0, WNOHANG
) > 0)
1154 ; /* keep looping */
1156 rb_native_mutex_unlock(&vm
->waitpid_lock
);
1161 waitpid_state_init(struct waitpid_state
*w
, rb_pid_t pid
, int options
)
1165 w
->options
= options
;
1170 static const rb_hrtime_t
*
1171 sigwait_sleep_time(void)
1173 if (SIGCHLD_LOSSY
) {
1174 static const rb_hrtime_t busy_wait
= 100 * RB_HRTIME_PER_MSEC
;
1182 * must be called with vm->waitpid_lock held, this is not interruptible
1185 ruby_waitpid_locked(rb_vm_t
*vm
, rb_pid_t pid
, int *status
, int options
,
1186 rb_nativethread_cond_t
*cond
)
1188 struct waitpid_state w
;
1190 assert(!ruby_thread_has_gvl_p() && "must not have GVL");
1192 waitpid_state_init(&w
, pid
, options
);
1193 if (w
.pid
> 0 || list_empty(&vm
->waiting_pids
))
1194 w
.ret
= do_waitpid(w
.pid
, &w
.status
, w
.options
| WNOHANG
);
1196 if (w
.ret
== -1) w
.errnum
= errno
;
1199 int sigwait_fd
= -1;
1202 list_add(w
.pid
> 0 ? &vm
->waiting_pids
: &vm
->waiting_grps
, &w
.wnode
);
1205 sigwait_fd
= rb_sigwait_fd_get(0);
1207 if (sigwait_fd
>= 0) {
1209 rb_native_mutex_unlock(&vm
->waitpid_lock
);
1210 rb_sigwait_sleep(0, sigwait_fd
, sigwait_sleep_time());
1211 rb_native_mutex_lock(&vm
->waitpid_lock
);
1215 rb_native_cond_wait(w
.cond
, &vm
->waitpid_lock
);
1220 /* we're done, maybe other waitpid callers are not: */
1221 if (sigwait_fd
>= 0) {
1222 rb_sigwait_fd_put(0, sigwait_fd
);
1223 sigwait_fd_migrate_sleeper(vm
);
1229 if (w
.ret
== -1) errno
= w
.errnum
;
1234 waitpid_sleep(VALUE x
)
1236 struct waitpid_state
*w
= (struct waitpid_state
*)x
;
1239 rb_thread_sleep_interruptible();
1246 waitpid_cleanup(VALUE x
)
1248 struct waitpid_state
*w
= (struct waitpid_state
*)x
;
1251 * XXX w->ret is sometimes set but list_del is still needed, here,
1252 * Not sure why, so we unconditionally do list_del here:
1254 if (TRUE
|| w
->ret
== 0) {
1255 rb_vm_t
*vm
= rb_ec_vm_ptr(w
->ec
);
1257 rb_native_mutex_lock(&vm
->waitpid_lock
);
1258 list_del(&w
->wnode
);
1259 rb_native_mutex_unlock(&vm
->waitpid_lock
);
1266 waitpid_wait(struct waitpid_state
*w
)
1268 rb_vm_t
*vm
= rb_ec_vm_ptr(w
->ec
);
1269 int need_sleep
= FALSE
;
1272 * Lock here to prevent do_waitpid from stealing work from the
1273 * ruby_waitpid_locked done by mjit workers since mjit works
1276 rb_native_mutex_lock(&vm
->waitpid_lock
);
1278 if (w
->pid
> 0 || list_empty(&vm
->waiting_pids
)) {
1279 w
->ret
= do_waitpid(w
->pid
, &w
->status
, w
->options
| WNOHANG
);
1283 if (w
->ret
== -1) w
->errnum
= errno
;
1285 else if (w
->options
& WNOHANG
) {
1293 /* order matters, favor specified PIDs rather than -1 or 0 */
1294 list_add(w
->pid
> 0 ? &vm
->waiting_pids
: &vm
->waiting_grps
, &w
->wnode
);
1297 rb_native_mutex_unlock(&vm
->waitpid_lock
);
1300 rb_ensure(waitpid_sleep
, (VALUE
)w
, waitpid_cleanup
, (VALUE
)w
);
1305 waitpid_blocking_no_SIGCHLD(void *x
)
1307 struct waitpid_state
*w
= x
;
1309 w
->ret
= do_waitpid(w
->pid
, &w
->status
, w
->options
);
1315 waitpid_no_SIGCHLD(struct waitpid_state
*w
)
1317 if (w
->options
& WNOHANG
) {
1318 w
->ret
= do_waitpid(w
->pid
, &w
->status
, w
->options
);
1322 rb_thread_call_without_gvl(waitpid_blocking_no_SIGCHLD
, w
,
1323 RUBY_UBF_PROCESS
, 0);
1324 } while (w
->ret
< 0 && errno
== EINTR
&& (RUBY_VM_CHECK_INTS(w
->ec
),1));
1331 rb_process_status_wait(rb_pid_t pid
, int flags
)
1333 // We only enter the scheduler if we are "blocking":
1334 if (!(flags
& WNOHANG
)) {
1335 VALUE scheduler
= rb_fiber_scheduler_current();
1336 VALUE result
= rb_fiber_scheduler_process_wait(scheduler
, pid
, flags
);
1337 if (result
!= Qundef
) return result
;
1340 struct waitpid_state waitpid_state
;
1342 waitpid_state_init(&waitpid_state
, pid
, flags
);
1343 waitpid_state
.ec
= GET_EC();
1345 if (WAITPID_USE_SIGCHLD
) {
1346 waitpid_wait(&waitpid_state
);
1349 waitpid_no_SIGCHLD(&waitpid_state
);
1352 if (waitpid_state
.ret
== 0) return Qnil
;
1354 if (waitpid_state
.ret
> 0 && ruby_nocldwait
) {
1355 waitpid_state
.ret
= -1;
1356 waitpid_state
.errnum
= ECHILD
;
1359 return rb_process_status_new(waitpid_state
.ret
, waitpid_state
.status
, waitpid_state
.errnum
);
1364 * Process::Status.wait(pid=-1, flags=0) -> Process::Status
1366 * Waits for a child process to exit and returns a Process::Status object
1367 * containing information on that process. Which child it waits on
1368 * depends on the value of _pid_:
1370 * > 0:: Waits for the child whose process ID equals _pid_.
1372 * 0:: Waits for any child whose process group ID equals that of the
1375 * -1:: Waits for any child process (the default if no _pid_ is
1378 * < -1:: Waits for any child whose process group ID equals the absolute
1381 * The _flags_ argument may be a logical or of the flag values
1382 * Process::WNOHANG (do not block if no child available)
1383 * or Process::WUNTRACED (return stopped children that
1384 * haven't been reported). Not all flags are available on all
1385 * platforms, but a flag value of zero will work on all platforms.
1387 * Returns +nil+ if there are no child processes.
1388 * Not available on all platforms.
1390 * May invoke the scheduler hook _process_wait_.
1392 * fork { exit 99 } #=> 27429
1393 * Process::Status.wait #=> pid 27429 exit 99
1396 * pid = fork { sleep 3 } #=> 27440
1397 * Time.now #=> 2008-03-08 19:56:16 +0900
1398 * Process::Status.wait(pid, Process::WNOHANG) #=> nil
1399 * Time.now #=> 2008-03-08 19:56:16 +0900
1400 * Process::Status.wait(pid, 0) #=> pid 27440 exit 99
1401 * Time.now #=> 2008-03-08 19:56:19 +0900
1403 * This is an EXPERIMENTAL FEATURE.
1407 rb_process_status_waitv(int argc
, VALUE
*argv
, VALUE _
)
1409 rb_check_arity(argc
, 0, 2);
1415 pid
= NUM2PIDT(argv
[0]);
1419 flags
= RB_NUM2INT(argv
[1]);
1422 return rb_process_status_wait(pid
, flags
);
1426 rb_waitpid(rb_pid_t pid
, int *st
, int flags
)
1428 VALUE status
= rb_process_status_wait(pid
, flags
);
1429 if (NIL_P(status
)) return 0;
1431 struct rb_process_status
*data
= RTYPEDDATA_DATA(status
);
1434 if (st
) *st
= data
->status
;
1437 errno
= data
->error
;
1440 GET_THREAD()->last_status
= status
;
1447 proc_wait(int argc
, VALUE
*argv
)
1453 if (rb_check_arity(argc
, 0, 2) == 0) {
1458 pid
= NUM2PIDT(argv
[0]);
1459 if (argc
== 2 && !NIL_P(vflags
= argv
[1])) {
1460 flags
= NUM2UINT(vflags
);
1464 if ((pid
= rb_waitpid(pid
, &status
, flags
)) < 0)
1468 rb_last_status_clear();
1472 return PIDT2NUM(pid
);
1475 /* [MG]:FIXME: I wasn't sure how this should be done, since ::wait()
1476 has historically been documented as if it didn't take any arguments
1477 despite the fact that it's just an alias for ::waitpid(). The way I
1478 have it below is more truthful, but a little confusing.
1480 I also took the liberty of putting in the pid values, as they're
1481 pretty useful, and it looked as if the original 'ri' output was
1482 supposed to contain them after "[...]depending on the value of
1485 The 'ansi' and 'bs' formats of the ri output don't display the
1486 definition list for some reason, but the plain text one does.
1491 * Process.wait() -> integer
1492 * Process.wait(pid=-1, flags=0) -> integer
1493 * Process.waitpid(pid=-1, flags=0) -> integer
1495 * Waits for a child process to exit, returns its process id, and
1496 * sets <code>$?</code> to a Process::Status object
1497 * containing information on that process. Which child it waits on
1498 * depends on the value of _pid_:
1500 * > 0:: Waits for the child whose process ID equals _pid_.
1502 * 0:: Waits for any child whose process group ID equals that of the
1505 * -1:: Waits for any child process (the default if no _pid_ is
1508 * < -1:: Waits for any child whose process group ID equals the absolute
1511 * The _flags_ argument may be a logical or of the flag values
1512 * Process::WNOHANG (do not block if no child available)
1513 * or Process::WUNTRACED (return stopped children that
1514 * haven't been reported). Not all flags are available on all
1515 * platforms, but a flag value of zero will work on all platforms.
1517 * Calling this method raises a SystemCallError if there are no child
1518 * processes. Not available on all platforms.
1521 * fork { exit 99 } #=> 27429
1523 * $?.exitstatus #=> 99
1525 * pid = fork { sleep 3 } #=> 27440
1526 * Time.now #=> 2008-03-08 19:56:16 +0900
1527 * waitpid(pid, Process::WNOHANG) #=> nil
1528 * Time.now #=> 2008-03-08 19:56:16 +0900
1529 * waitpid(pid, 0) #=> 27440
1530 * Time.now #=> 2008-03-08 19:56:19 +0900
1534 proc_m_wait(int c
, VALUE
*v
, VALUE _
)
1536 return proc_wait(c
, v
);
1542 * Process.wait2(pid=-1, flags=0) -> [pid, status]
1543 * Process.waitpid2(pid=-1, flags=0) -> [pid, status]
1545 * Waits for a child process to exit (see Process::waitpid for exact
1546 * semantics) and returns an array containing the process id and the
1547 * exit status (a Process::Status object) of that
1548 * child. Raises a SystemCallError if there are no child processes.
1550 * Process.fork { exit 99 } #=> 27437
1551 * pid, status = Process.wait2
1553 * status.exitstatus #=> 99
1557 proc_wait2(int argc
, VALUE
*argv
, VALUE _
)
1559 VALUE pid
= proc_wait(argc
, argv
);
1560 if (NIL_P(pid
)) return Qnil
;
1561 return rb_assoc_new(pid
, rb_last_status_get());
1567 * Process.waitall -> [ [pid1,status1], ...]
1569 * Waits for all children, returning an array of
1570 * _pid_/_status_ pairs (where _status_ is a
1571 * Process::Status object).
1573 * fork { sleep 0.2; exit 2 } #=> 27432
1574 * fork { sleep 0.1; exit 1 } #=> 27433
1575 * fork { exit 0 } #=> 27434
1578 * <em>produces</em>:
1580 * [[30982, #<Process::Status: pid 30982 exit 0>],
1581 * [30979, #<Process::Status: pid 30979 exit 1>],
1582 * [30976, #<Process::Status: pid 30976 exit 2>]]
1586 proc_waitall(VALUE _
)
1592 result
= rb_ary_new();
1593 rb_last_status_clear();
1596 pid
= rb_waitpid(-1, &status
, 0);
1601 rb_syserr_fail(e
, 0);
1603 rb_ary_push(result
, rb_assoc_new(PIDT2NUM(pid
), rb_last_status_get()));
1608 static VALUE rb_cWaiter
;
1611 detach_process_pid(VALUE thread
)
1613 return rb_thread_local_aref(thread
, id_pid
);
1617 detach_process_watcher(void *arg
)
1619 rb_pid_t cpid
, pid
= (rb_pid_t
)(VALUE
)arg
;
1622 while ((cpid
= rb_waitpid(pid
, &status
, 0)) == 0) {
1623 /* wait while alive */
1625 return rb_last_status_get();
1629 rb_detach_process(rb_pid_t pid
)
1631 VALUE watcher
= rb_thread_create(detach_process_watcher
, (void*)(VALUE
)pid
);
1632 rb_thread_local_aset(watcher
, id_pid
, PIDT2NUM(pid
));
1633 RBASIC_SET_CLASS(watcher
, rb_cWaiter
);
1640 * Process.detach(pid) -> thread
1642 * Some operating systems retain the status of terminated child
1643 * processes until the parent collects that status (normally using
1644 * some variant of <code>wait()</code>). If the parent never collects
1645 * this status, the child stays around as a <em>zombie</em> process.
1646 * Process::detach prevents this by setting up a separate Ruby thread
1647 * whose sole job is to reap the status of the process _pid_ when it
1648 * terminates. Use #detach only when you do not intend to explicitly
1649 * wait for the child to terminate.
1651 * The waiting thread returns the exit status of the detached process
1652 * when it terminates, so you can use Thread#join to
1653 * know the result. If specified _pid_ is not a valid child process
1654 * ID, the thread returns +nil+ immediately.
1656 * The waiting thread has #pid method which returns the pid.
1658 * In this first example, we don't reap the first child process, so
1659 * it appears as a zombie in the process status display.
1661 * p1 = fork { sleep 0.1 }
1662 * p2 = fork { sleep 0.2 }
1663 * Process.waitpid(p2)
1665 * system("ps -ho pid,state -p #{p1}")
1667 * <em>produces:</em>
1671 * In the next example, Process::detach is used to reap
1672 * the child automatically.
1674 * p1 = fork { sleep 0.1 }
1675 * p2 = fork { sleep 0.2 }
1676 * Process.detach(p1)
1677 * Process.waitpid(p2)
1679 * system("ps -ho pid,state -p #{p1}")
1681 * <em>(produces no output)</em>
1685 proc_detach(VALUE obj
, VALUE pid
)
1687 return rb_detach_process(NUM2PIDT(pid
));
1690 /* This function should be async-signal-safe. Actually it is. */
1692 before_exec_async_signal_safe(void)
1697 before_exec_non_async_signal_safe(void)
1700 * On Mac OS X 10.5.x (Leopard) or earlier, exec() may return ENOTSUP
1701 * if the process have multiple threads. Therefore we have to kill
1702 * internal threads temporary. [ruby-core:10583]
1703 * This is also true on Haiku. It returns Errno::EPERM against exec()
1704 * in multiple threads.
1706 * Nowadays, we always stop the timer thread completely to allow redirects.
1708 rb_thread_stop_timer_thread();
1711 #define WRITE_CONST(fd, str) (void)(write((fd),(str),sizeof(str)-1)<0)
1713 int rb_w32_set_nonblock2(int fd
, int nonblock
);
1717 set_blocking(int fd
)
1720 return rb_w32_set_nonblock2(fd
, 0);
1721 #elif defined(F_GETFL) && defined(F_SETFL)
1722 int fl
= fcntl(fd
, F_GETFL
); /* async-signal-safe */
1724 /* EBADF ought to be possible */
1725 if (fl
== -1) return fl
;
1726 if (fl
& O_NONBLOCK
) {
1728 return fcntl(fd
, F_SETFL
, fl
);
1735 stdfd_clear_nonblock(void)
1737 /* many programs cannot deal with non-blocking stdin/stdout/stderr */
1739 for (fd
= 0; fd
< 3; fd
++) {
1740 (void)set_blocking(fd
); /* can't do much about errors anyhow */
1747 before_exec_non_async_signal_safe();
1748 before_exec_async_signal_safe();
1751 /* This function should be async-signal-safe. Actually it is. */
1753 after_exec_async_signal_safe(void)
1758 after_exec_non_async_signal_safe(void)
1760 rb_thread_reset_timer_thread();
1761 rb_thread_start_timer_thread();
1767 after_exec_async_signal_safe();
1768 after_exec_non_async_signal_safe();
1771 #if defined HAVE_WORKING_FORK || defined HAVE_DAEMON
1773 before_fork_ruby(void)
1779 after_fork_ruby(void)
1781 rb_threadptr_pending_interrupt_clear(GET_THREAD());
1786 #if defined(HAVE_WORKING_FORK)
1788 /* try_with_sh and exec_with_sh should be async-signal-safe. Actually it is.*/
1789 #define try_with_sh(err, prog, argv, envp) ((err == ENOEXEC) ? exec_with_sh((prog), (argv), (envp)) : (void)0)
1791 exec_with_sh(const char *prog
, char **argv
, char **envp
)
1793 *argv
= (char *)prog
;
1794 *--argv
= (char *)"sh";
1796 execve("/bin/sh", argv
, envp
); /* async-signal-safe */
1798 execv("/bin/sh", argv
); /* async-signal-safe (since SUSv4) */
1802 #define try_with_sh(err, prog, argv, envp) (void)0
1805 /* This function should be async-signal-safe. Actually it is. */
1807 proc_exec_cmd(const char *prog
, VALUE argv_str
, VALUE envp_str
)
1815 argv
= ARGVSTR2ARGV(argv_str
);
1822 rb_w32_uaspawn(P_OVERLAY
, prog
, argv
);
1825 envp
= envp_str
? RB_IMEMO_TMPBUF_PTR(envp_str
) : NULL
;
1827 execve(prog
, argv
, envp
); /* async-signal-safe */
1829 execv(prog
, argv
); /* async-signal-safe (since SUSv4) */
1831 try_with_sh(err
, prog
, argv
, envp
); /* try_with_sh() is async-signal-safe. */
1836 /* This function should be async-signal-safe. Actually it is. */
1838 proc_exec_sh(const char *str
, VALUE envp_str
)
1843 while (*s
== ' ' || *s
== '\t' || *s
== '\n')
1851 rb_w32_uspawn(P_OVERLAY
, (char *)str
, 0);
1852 #elif defined(__CYGWIN32__)
1854 char fbuf
[MAXPATHLEN
];
1855 char *shell
= dln_find_exe_r("sh", 0, fbuf
, sizeof(fbuf
));
1858 execl(shell
, "sh", "-c", str
, (char *) NULL
);
1860 status
= system(str
);
1866 execle("/bin/sh", "sh", "-c", str
, (char *)NULL
, RB_IMEMO_TMPBUF_PTR(envp_str
)); /* async-signal-safe */
1868 execl("/bin/sh", "sh", "-c", str
, (char *)NULL
); /* async-signal-safe (since SUSv4) */
1874 rb_proc_exec(const char *str
)
1878 ret
= proc_exec_sh(str
, Qfalse
);
1885 mark_exec_arg(void *ptr
)
1887 struct rb_execarg
*eargp
= ptr
;
1888 if (eargp
->use_shell
)
1889 rb_gc_mark(eargp
->invoke
.sh
.shell_script
);
1891 rb_gc_mark(eargp
->invoke
.cmd
.command_name
);
1892 rb_gc_mark(eargp
->invoke
.cmd
.command_abspath
);
1893 rb_gc_mark(eargp
->invoke
.cmd
.argv_str
);
1894 rb_gc_mark(eargp
->invoke
.cmd
.argv_buf
);
1896 rb_gc_mark(eargp
->redirect_fds
);
1897 rb_gc_mark(eargp
->envp_str
);
1898 rb_gc_mark(eargp
->envp_buf
);
1899 rb_gc_mark(eargp
->dup2_tmpbuf
);
1900 rb_gc_mark(eargp
->rlimit_limits
);
1901 rb_gc_mark(eargp
->fd_dup2
);
1902 rb_gc_mark(eargp
->fd_close
);
1903 rb_gc_mark(eargp
->fd_open
);
1904 rb_gc_mark(eargp
->fd_dup2_child
);
1905 rb_gc_mark(eargp
->env_modification
);
1906 rb_gc_mark(eargp
->path_env
);
1907 rb_gc_mark(eargp
->chdir_dir
);
1911 memsize_exec_arg(const void *ptr
)
1913 return sizeof(struct rb_execarg
);
1916 static const rb_data_type_t exec_arg_data_type
= {
1918 {mark_exec_arg
, RUBY_TYPED_DEFAULT_FREE
, memsize_exec_arg
},
1919 0, 0, RUBY_TYPED_FREE_IMMEDIATELY
1923 # define DEFAULT_PROCESS_ENCODING rb_utf8_encoding()
1925 #ifdef DEFAULT_PROCESS_ENCODING
1926 # define EXPORT_STR(str) rb_str_export_to_enc((str), DEFAULT_PROCESS_ENCODING)
1927 # define EXPORT_DUP(str) export_dup(str)
1929 export_dup(VALUE str
)
1931 VALUE newstr
= EXPORT_STR(str
);
1932 if (newstr
== str
) newstr
= rb_str_dup(str
);
1936 # define EXPORT_STR(str) (str)
1937 # define EXPORT_DUP(str) rb_str_dup(str)
1940 #if !defined(HAVE_WORKING_FORK) && defined(HAVE_SPAWNV)
1941 # define USE_SPAWNV 1
1943 # define USE_SPAWNV 0
1946 # define P_NOWAIT _P_NOWAIT
1951 #define proc_spawn_cmd_internal(argv, prog) rb_w32_uaspawn(P_NOWAIT, (prog), (argv))
1954 proc_spawn_cmd_internal(char **argv
, char *prog
)
1956 char fbuf
[MAXPATHLEN
];
1961 prog
= dln_find_exe_r(prog
, 0, fbuf
, sizeof(fbuf
));
1966 status
= spawnv(P_NOWAIT
, prog
, (const char **)argv
);
1967 if (status
== -1 && errno
== ENOEXEC
) {
1968 *argv
= (char *)prog
;
1969 *--argv
= (char *)"sh";
1970 status
= spawnv(P_NOWAIT
, "/bin/sh", (const char **)argv
);
1972 if (status
== -1) errno
= ENOEXEC
;
1979 proc_spawn_cmd(char **argv
, VALUE prog
, struct rb_execarg
*eargp
)
1986 if (eargp
->new_pgroup_given
&& eargp
->new_pgroup_flag
) {
1987 flags
= CREATE_NEW_PROCESS_GROUP
;
1989 pid
= rb_w32_uaspawn_flags(P_NOWAIT
, prog
? RSTRING_PTR(prog
) : 0, argv
, flags
);
1991 pid
= proc_spawn_cmd_internal(argv
, prog
? RSTRING_PTR(prog
) : 0);
1998 #define proc_spawn_sh(str) rb_w32_uspawn(P_NOWAIT, (str), 0)
2001 proc_spawn_sh(char *str
)
2003 char fbuf
[MAXPATHLEN
];
2006 char *shell
= dln_find_exe_r("sh", 0, fbuf
, sizeof(fbuf
));
2008 status
= spawnl(P_NOWAIT
, (shell
? shell
: "/bin/sh"), "sh", "-c", str
, (char*)NULL
);
2018 RBASIC_CLEAR_CLASS(obj
);
2023 check_exec_redirect_fd(VALUE v
, int iskey
)
2030 else if (SYMBOL_P(v
)) {
2031 ID id
= rb_check_id(&v
);
2034 else if (id
== id_out
)
2036 else if (id
== id_err
)
2041 else if (!NIL_P(tmp
= rb_io_check_io(v
))) {
2043 GetOpenFile(tmp
, fptr
);
2044 if (fptr
->tied_io_for_writing
)
2045 rb_raise(rb_eArgError
, "duplex IO redirection");
2052 rb_raise(rb_eArgError
, "negative file descriptor");
2055 else if (fd
>= 3 && iskey
) {
2056 rb_raise(rb_eArgError
, "wrong file descriptor (%d)", fd
);
2062 rb_raise(rb_eArgError
, "wrong exec redirect");
2063 UNREACHABLE_RETURN(Qundef
);
2067 check_exec_redirect1(VALUE ary
, VALUE key
, VALUE param
)
2069 if (ary
== Qfalse
) {
2070 ary
= hide_obj(rb_ary_new());
2072 if (!RB_TYPE_P(key
, T_ARRAY
)) {
2073 VALUE fd
= check_exec_redirect_fd(key
, !NIL_P(param
));
2074 rb_ary_push(ary
, hide_obj(rb_assoc_new(fd
, param
)));
2078 for (i
= 0 ; i
< RARRAY_LEN(key
); i
++) {
2079 VALUE v
= RARRAY_AREF(key
, i
);
2080 VALUE fd
= check_exec_redirect_fd(v
, !NIL_P(param
));
2081 rb_ary_push(ary
, hide_obj(rb_assoc_new(fd
, param
)));
2088 check_exec_redirect(VALUE key
, VALUE val
, struct rb_execarg
*eargp
)
2091 VALUE path
, flags
, perm
;
2095 switch (TYPE(val
)) {
2097 id
= rb_check_id(&val
);
2098 if (id
== id_close
) {
2100 eargp
->fd_close
= check_exec_redirect1(eargp
->fd_close
, key
, param
);
2102 else if (id
== id_in
) {
2104 eargp
->fd_dup2
= check_exec_redirect1(eargp
->fd_dup2
, key
, param
);
2106 else if (id
== id_out
) {
2108 eargp
->fd_dup2
= check_exec_redirect1(eargp
->fd_dup2
, key
, param
);
2110 else if (id
== id_err
) {
2112 eargp
->fd_dup2
= check_exec_redirect1(eargp
->fd_dup2
, key
, param
);
2115 rb_raise(rb_eArgError
, "wrong exec redirect symbol: %"PRIsVALUE
,
2122 val
= check_exec_redirect_fd(val
, 0);
2126 eargp
->fd_dup2
= check_exec_redirect1(eargp
->fd_dup2
, key
, param
);
2130 path
= rb_ary_entry(val
, 0);
2131 if (RARRAY_LEN(val
) == 2 && SYMBOL_P(path
) &&
2132 path
== ID2SYM(id_child
)) {
2133 param
= check_exec_redirect_fd(rb_ary_entry(val
, 1), 0);
2134 eargp
->fd_dup2_child
= check_exec_redirect1(eargp
->fd_dup2_child
, key
, param
);
2137 FilePathValue(path
);
2138 flags
= rb_ary_entry(val
, 1);
2140 flags
= INT2NUM(O_RDONLY
);
2141 else if (RB_TYPE_P(flags
, T_STRING
))
2142 flags
= INT2NUM(rb_io_modestr_oflags(StringValueCStr(flags
)));
2144 flags
= rb_to_int(flags
);
2145 perm
= rb_ary_entry(val
, 2);
2146 perm
= NIL_P(perm
) ? INT2FIX(0644) : rb_to_int(perm
);
2147 param
= hide_obj(rb_ary_new3(4, hide_obj(EXPORT_DUP(path
)),
2148 flags
, perm
, Qnil
));
2149 eargp
->fd_open
= check_exec_redirect1(eargp
->fd_open
, key
, param
);
2155 FilePathValue(path
);
2156 if (RB_TYPE_P(key
, T_FILE
))
2157 key
= check_exec_redirect_fd(key
, 1);
2158 if (FIXNUM_P(key
) && (FIX2INT(key
) == 1 || FIX2INT(key
) == 2))
2159 flags
= INT2NUM(O_WRONLY
|O_CREAT
|O_TRUNC
);
2160 else if (RB_TYPE_P(key
, T_ARRAY
)) {
2162 for (i
= 0; i
< RARRAY_LEN(key
); i
++) {
2163 VALUE v
= RARRAY_AREF(key
, i
);
2164 VALUE fd
= check_exec_redirect_fd(v
, 1);
2165 if (FIX2INT(fd
) != 1 && FIX2INT(fd
) != 2) break;
2167 if (i
== RARRAY_LEN(key
))
2168 flags
= INT2NUM(O_WRONLY
|O_CREAT
|O_TRUNC
);
2170 flags
= INT2NUM(O_RDONLY
);
2173 flags
= INT2NUM(O_RDONLY
);
2174 perm
= INT2FIX(0644);
2175 param
= hide_obj(rb_ary_new3(4, hide_obj(EXPORT_DUP(path
)),
2176 flags
, perm
, Qnil
));
2177 eargp
->fd_open
= check_exec_redirect1(eargp
->fd_open
, key
, param
);
2182 val
= rb_io_check_io(tmp
);
2183 if (!NIL_P(val
)) goto io
;
2184 rb_raise(rb_eArgError
, "wrong exec redirect action");
2189 #if defined(HAVE_SETRLIMIT) && defined(NUM2RLIM)
2190 static int rlimit_type_by_sym(VALUE key
);
2193 rb_execarg_addopt_rlimit(struct rb_execarg
*eargp
, int rtype
, VALUE val
)
2195 VALUE ary
= eargp
->rlimit_limits
;
2196 VALUE tmp
, softlim
, hardlim
;
2197 if (eargp
->rlimit_limits
== Qfalse
)
2198 ary
= eargp
->rlimit_limits
= hide_obj(rb_ary_new());
2200 ary
= eargp
->rlimit_limits
;
2201 tmp
= rb_check_array_type(val
);
2203 if (RARRAY_LEN(tmp
) == 1)
2204 softlim
= hardlim
= rb_to_int(rb_ary_entry(tmp
, 0));
2205 else if (RARRAY_LEN(tmp
) == 2) {
2206 softlim
= rb_to_int(rb_ary_entry(tmp
, 0));
2207 hardlim
= rb_to_int(rb_ary_entry(tmp
, 1));
2210 rb_raise(rb_eArgError
, "wrong exec rlimit option");
2214 softlim
= hardlim
= rb_to_int(val
);
2216 tmp
= hide_obj(rb_ary_new3(3, INT2NUM(rtype
), softlim
, hardlim
));
2217 rb_ary_push(ary
, tmp
);
2221 #define TO_BOOL(val, name) NIL_P(val) ? 0 : rb_bool_expected((val), name)
2223 rb_execarg_addopt(VALUE execarg_obj
, VALUE key
, VALUE val
)
2225 struct rb_execarg
*eargp
= rb_execarg_get(execarg_obj
);
2229 switch (TYPE(key
)) {
2231 #if defined(HAVE_SETRLIMIT) && defined(NUM2RLIM)
2233 int rtype
= rlimit_type_by_sym(key
);
2235 rb_execarg_addopt_rlimit(eargp
, rtype
, val
);
2236 RB_GC_GUARD(execarg_obj
);
2241 if (!(id
= rb_check_id(&key
))) return ST_STOP
;
2243 if (id
== id_pgroup
) {
2245 if (eargp
->pgroup_given
) {
2246 rb_raise(rb_eArgError
, "pgroup option specified twice");
2249 pgroup
= -1; /* asis(-1) means "don't call setpgid()". */
2250 else if (val
== Qtrue
)
2251 pgroup
= 0; /* new process group. */
2253 pgroup
= NUM2PIDT(val
);
2255 rb_raise(rb_eArgError
, "negative process group ID : %ld", (long)pgroup
);
2258 eargp
->pgroup_given
= 1;
2259 eargp
->pgroup_pgid
= pgroup
;
2264 if (id
== id_new_pgroup
) {
2265 if (eargp
->new_pgroup_given
) {
2266 rb_raise(rb_eArgError
, "new_pgroup option specified twice");
2268 eargp
->new_pgroup_given
= 1;
2269 eargp
->new_pgroup_flag
= TO_BOOL(val
, "new_pgroup");
2273 if (id
== id_unsetenv_others
) {
2274 if (eargp
->unsetenv_others_given
) {
2275 rb_raise(rb_eArgError
, "unsetenv_others option specified twice");
2277 eargp
->unsetenv_others_given
= 1;
2278 eargp
->unsetenv_others_do
= TO_BOOL(val
, "unsetenv_others");
2280 else if (id
== id_chdir
) {
2281 if (eargp
->chdir_given
) {
2282 rb_raise(rb_eArgError
, "chdir option specified twice");
2285 val
= rb_str_encode_ospath(val
);
2286 eargp
->chdir_given
= 1;
2287 eargp
->chdir_dir
= hide_obj(EXPORT_DUP(val
));
2289 else if (id
== id_umask
) {
2290 mode_t cmask
= NUM2MODET(val
);
2291 if (eargp
->umask_given
) {
2292 rb_raise(rb_eArgError
, "umask option specified twice");
2294 eargp
->umask_given
= 1;
2295 eargp
->umask_mask
= cmask
;
2297 else if (id
== id_close_others
) {
2298 if (eargp
->close_others_given
) {
2299 rb_raise(rb_eArgError
, "close_others option specified twice");
2301 eargp
->close_others_given
= 1;
2302 eargp
->close_others_do
= TO_BOOL(val
, "close_others");
2304 else if (id
== id_in
) {
2308 else if (id
== id_out
) {
2312 else if (id
== id_err
) {
2316 else if (id
== id_uid
) {
2318 if (eargp
->uid_given
) {
2319 rb_raise(rb_eArgError
, "uid option specified twice");
2323 eargp
->uid
= OBJ2UID(val
);
2324 eargp
->uid_given
= 1;
2327 rb_raise(rb_eNotImpError
,
2328 "uid option is unimplemented on this machine");
2331 else if (id
== id_gid
) {
2333 if (eargp
->gid_given
) {
2334 rb_raise(rb_eArgError
, "gid option specified twice");
2338 eargp
->gid
= OBJ2GID(val
);
2339 eargp
->gid_given
= 1;
2342 rb_raise(rb_eNotImpError
,
2343 "gid option is unimplemented on this machine");
2346 else if (id
== id_exception
) {
2347 if (eargp
->exception_given
) {
2348 rb_raise(rb_eArgError
, "exception option specified twice");
2350 eargp
->exception_given
= 1;
2351 eargp
->exception
= TO_BOOL(val
, "exception");
2362 check_exec_redirect(key
, val
, eargp
);
2369 RB_GC_GUARD(execarg_obj
);
2374 check_exec_options_i(st_data_t st_key
, st_data_t st_val
, st_data_t arg
)
2376 VALUE key
= (VALUE
)st_key
;
2377 VALUE val
= (VALUE
)st_val
;
2378 VALUE execarg_obj
= (VALUE
)arg
;
2379 if (rb_execarg_addopt(execarg_obj
, key
, val
) != ST_CONTINUE
) {
2381 rb_raise(rb_eArgError
, "wrong exec option symbol: % "PRIsVALUE
,
2383 rb_raise(rb_eArgError
, "wrong exec option");
2389 check_exec_options_i_extract(st_data_t st_key
, st_data_t st_val
, st_data_t arg
)
2391 VALUE key
= (VALUE
)st_key
;
2392 VALUE val
= (VALUE
)st_val
;
2393 VALUE
*args
= (VALUE
*)arg
;
2394 VALUE execarg_obj
= args
[0];
2395 if (rb_execarg_addopt(execarg_obj
, key
, val
) != ST_CONTINUE
) {
2396 VALUE nonopts
= args
[1];
2397 if (NIL_P(nonopts
)) args
[1] = nonopts
= rb_hash_new();
2398 rb_hash_aset(nonopts
, key
, val
);
2404 check_exec_fds_1(struct rb_execarg
*eargp
, VALUE h
, int maxhint
, VALUE ary
)
2408 if (ary
!= Qfalse
) {
2409 for (i
= 0; i
< RARRAY_LEN(ary
); i
++) {
2410 VALUE elt
= RARRAY_AREF(ary
, i
);
2411 int fd
= FIX2INT(RARRAY_AREF(elt
, 0));
2412 if (RTEST(rb_hash_lookup(h
, INT2FIX(fd
)))) {
2413 rb_raise(rb_eArgError
, "fd %d specified twice", fd
);
2415 if (ary
== eargp
->fd_dup2
)
2416 rb_hash_aset(h
, INT2FIX(fd
), Qtrue
);
2417 else if (ary
== eargp
->fd_dup2_child
)
2418 rb_hash_aset(h
, INT2FIX(fd
), RARRAY_AREF(elt
, 1));
2419 else /* ary == eargp->fd_close */
2420 rb_hash_aset(h
, INT2FIX(fd
), INT2FIX(-1));
2423 if (ary
== eargp
->fd_dup2
|| ary
== eargp
->fd_dup2_child
) {
2424 fd
= FIX2INT(RARRAY_AREF(elt
, 1));
2434 check_exec_fds(struct rb_execarg
*eargp
)
2436 VALUE h
= rb_hash_new();
2441 maxhint
= check_exec_fds_1(eargp
, h
, maxhint
, eargp
->fd_dup2
);
2442 maxhint
= check_exec_fds_1(eargp
, h
, maxhint
, eargp
->fd_close
);
2443 maxhint
= check_exec_fds_1(eargp
, h
, maxhint
, eargp
->fd_dup2_child
);
2445 if (eargp
->fd_dup2_child
) {
2446 ary
= eargp
->fd_dup2_child
;
2447 for (i
= 0; i
< RARRAY_LEN(ary
); i
++) {
2448 VALUE elt
= RARRAY_AREF(ary
, i
);
2449 int newfd
= FIX2INT(RARRAY_AREF(elt
, 0));
2450 int oldfd
= FIX2INT(RARRAY_AREF(elt
, 1));
2452 VALUE val
= rb_hash_lookup(h
, INT2FIX(lastfd
));
2454 while (FIXNUM_P(val
) && 0 <= FIX2INT(val
)) {
2455 lastfd
= FIX2INT(val
);
2456 val
= rb_hash_lookup(h
, val
);
2457 if (RARRAY_LEN(ary
) < depth
)
2458 rb_raise(rb_eArgError
, "cyclic child fd redirection from %d", oldfd
);
2462 rb_raise(rb_eArgError
, "child fd %d is not redirected", oldfd
);
2463 if (oldfd
!= lastfd
) {
2465 rb_ary_store(elt
, 1, INT2FIX(lastfd
));
2466 rb_hash_aset(h
, INT2FIX(newfd
), INT2FIX(lastfd
));
2467 val
= INT2FIX(oldfd
);
2468 while (FIXNUM_P(val2
= rb_hash_lookup(h
, val
))) {
2469 rb_hash_aset(h
, val
, INT2FIX(lastfd
));
2476 eargp
->close_others_maxhint
= maxhint
;
2481 rb_check_exec_options(VALUE opthash
, VALUE execarg_obj
)
2483 if (RHASH_EMPTY_P(opthash
))
2485 rb_hash_stlike_foreach(opthash
, check_exec_options_i
, (st_data_t
)execarg_obj
);
2489 rb_execarg_extract_options(VALUE execarg_obj
, VALUE opthash
)
2492 if (RHASH_EMPTY_P(opthash
))
2494 args
[0] = execarg_obj
;
2496 rb_hash_stlike_foreach(opthash
, check_exec_options_i_extract
, (st_data_t
)args
);
2500 #ifdef ENV_IGNORECASE
2501 #define ENVMATCH(s1, s2) (STRCASECMP((s1), (s2)) == 0)
2503 #define ENVMATCH(n1, n2) (strcmp((n1), (n2)) == 0)
2507 check_exec_env_i(st_data_t st_key
, st_data_t st_val
, st_data_t arg
)
2509 VALUE key
= (VALUE
)st_key
;
2510 VALUE val
= (VALUE
)st_val
;
2511 VALUE env
= ((VALUE
*)arg
)[0];
2512 VALUE
*path
= &((VALUE
*)arg
)[1];
2515 k
= StringValueCStr(key
);
2517 rb_raise(rb_eArgError
, "environment name contains a equal : %"PRIsVALUE
, key
);
2520 StringValueCStr(val
);
2522 key
= EXPORT_STR(key
);
2523 if (!NIL_P(val
)) val
= EXPORT_STR(val
);
2525 if (ENVMATCH(k
, PATH_ENV
)) {
2528 rb_ary_push(env
, hide_obj(rb_assoc_new(key
, val
)));
2534 rb_check_exec_env(VALUE hash
, VALUE
*path
)
2538 env
[0] = hide_obj(rb_ary_new());
2540 rb_hash_stlike_foreach(hash
, check_exec_env_i
, (st_data_t
)env
);
2547 rb_check_argv(int argc
, VALUE
*argv
)
2552 rb_check_arity(argc
, 1, UNLIMITED_ARGUMENTS
);
2555 tmp
= rb_check_array_type(argv
[0]);
2557 if (RARRAY_LEN(tmp
) != 2) {
2558 rb_raise(rb_eArgError
, "wrong first argument");
2560 prog
= RARRAY_AREF(tmp
, 0);
2561 argv
[0] = RARRAY_AREF(tmp
, 1);
2562 SafeStringValue(prog
);
2563 StringValueCStr(prog
);
2564 prog
= rb_str_new_frozen(prog
);
2566 for (i
= 0; i
< argc
; i
++) {
2567 SafeStringValue(argv
[i
]);
2568 argv
[i
] = rb_str_new_frozen(argv
[i
]);
2569 StringValueCStr(argv
[i
]);
2575 check_hash(VALUE obj
)
2577 if (RB_SPECIAL_CONST_P(obj
)) return Qnil
;
2578 switch (RB_BUILTIN_TYPE(obj
)) {
2585 return rb_check_hash_type(obj
);
2589 rb_exec_getargs(int *argc_p
, VALUE
**argv_p
, int accept_shell
, VALUE
*env_ret
, VALUE
*opthash_ret
)
2594 hash
= check_hash((*argv_p
)[*argc_p
-1]);
2596 *opthash_ret
= hash
;
2602 hash
= check_hash((*argv_p
)[0]);
2609 prog
= rb_check_argv(*argc_p
, *argv_p
);
2611 prog
= (*argv_p
)[0];
2612 if (accept_shell
&& *argc_p
== 1) {
2621 struct string_part
{
2627 compare_posix_sh(const void *key
, const void *el
)
2629 const struct string_part
*word
= key
;
2630 int ret
= strncmp(word
->ptr
, el
, word
->len
);
2631 if (!ret
&& ((const char *)el
)[word
->len
]) ret
= -1;
2637 rb_exec_fillarg(VALUE prog
, int argc
, VALUE
*argv
, VALUE env
, VALUE opthash
, VALUE execarg_obj
)
2639 struct rb_execarg
*eargp
= rb_execarg_get(execarg_obj
);
2640 char fbuf
[MAXPATHLEN
];
2642 MEMZERO(eargp
, struct rb_execarg
, 1);
2644 if (!NIL_P(opthash
)) {
2645 rb_check_exec_options(opthash
, execarg_obj
);
2648 env
= rb_check_exec_env(env
, &eargp
->path_env
);
2649 eargp
->env_modification
= env
;
2652 prog
= EXPORT_STR(prog
);
2653 eargp
->use_shell
= argc
== 0;
2654 if (eargp
->use_shell
)
2655 eargp
->invoke
.sh
.shell_script
= prog
;
2657 eargp
->invoke
.cmd
.command_name
= prog
;
2660 if (eargp
->use_shell
) {
2661 static const char posix_sh_cmds
[][9] = {
2663 ".", /* special built-in */
2664 ":", /* special built-in */
2665 "break", /* special built-in */
2666 "case", /* reserved */
2667 "continue", /* special built-in */
2668 "do", /* reserved */
2669 "done", /* reserved */
2670 "elif", /* reserved */
2671 "else", /* reserved */
2672 "esac", /* reserved */
2673 "eval", /* special built-in */
2674 "exec", /* special built-in */
2675 "exit", /* special built-in */
2676 "export", /* special built-in */
2677 "fi", /* reserved */
2678 "for", /* reserved */
2679 "if", /* reserved */
2680 "in", /* reserved */
2681 "readonly", /* special built-in */
2682 "return", /* special built-in */
2683 "set", /* special built-in */
2684 "shift", /* special built-in */
2685 "then", /* reserved */
2686 "times", /* special built-in */
2687 "trap", /* special built-in */
2688 "unset", /* special built-in */
2689 "until", /* reserved */
2690 "while", /* reserved */
2693 struct string_part first
= {0, 0};
2698 * * Pathname Expansion
2699 * ? Pathname Expansion
2700 * {} Grouping Commands
2701 * [] Pathname Expansion
2703 * () Grouping Commands
2705 * & AND Lists, Asynchronous Lists
2706 * | OR Lists, Pipelines
2707 * \ Escape Character
2708 * $ Parameter Expansion
2709 * ; Sequential Lists
2711 * ` Command Substitution
2716 * = Assignment preceding command name
2717 * % (used in Parameter Expansion)
2719 for (p
= RSTRING_PTR(prog
); *p
; p
++) {
2720 if (*p
== ' ' || *p
== '\t') {
2721 if (first
.ptr
&& !first
.len
) first
.len
= p
- first
.ptr
;
2724 if (!first
.ptr
) first
.ptr
= p
;
2726 if (!has_meta
&& strchr("*?{}[]<>()~&|\\$;'`\"\n#", *p
))
2732 else if (*p
== '/') {
2733 first
.len
= 0x100; /* longer than any posix_sh_cmds */
2739 if (!has_meta
&& first
.ptr
) {
2740 if (!first
.len
) first
.len
= p
- first
.ptr
;
2741 if (first
.len
> 0 && first
.len
<= sizeof(posix_sh_cmds
[0]) &&
2742 bsearch(&first
, posix_sh_cmds
, numberof(posix_sh_cmds
), sizeof(posix_sh_cmds
[0]), compare_posix_sh
))
2746 /* avoid shell since no shell meta character found. */
2747 eargp
->use_shell
= 0;
2749 if (!eargp
->use_shell
) {
2751 argv_buf
= hide_obj(rb_str_buf_new(0));
2752 p
= RSTRING_PTR(prog
);
2754 while (*p
== ' ' || *p
== '\t')
2758 while (*p
&& *p
!= ' ' && *p
!= '\t')
2760 rb_str_buf_cat(argv_buf
, w
, p
-w
);
2761 rb_str_buf_cat(argv_buf
, "", 1); /* append '\0' */
2764 eargp
->invoke
.cmd
.argv_buf
= argv_buf
;
2765 eargp
->invoke
.cmd
.command_name
=
2766 hide_obj(rb_str_subseq(argv_buf
, 0, strlen(RSTRING_PTR(argv_buf
))));
2767 rb_enc_copy(eargp
->invoke
.cmd
.command_name
, prog
);
2772 if (!eargp
->use_shell
) {
2773 const char *abspath
;
2774 const char *path_env
= 0;
2775 if (RTEST(eargp
->path_env
)) path_env
= RSTRING_PTR(eargp
->path_env
);
2776 abspath
= dln_find_exe_r(RSTRING_PTR(eargp
->invoke
.cmd
.command_name
),
2777 path_env
, fbuf
, sizeof(fbuf
));
2779 eargp
->invoke
.cmd
.command_abspath
= rb_str_new_cstr(abspath
);
2781 eargp
->invoke
.cmd
.command_abspath
= Qnil
;
2784 if (!eargp
->use_shell
&& !eargp
->invoke
.cmd
.argv_buf
) {
2787 argv_buf
= rb_str_buf_new(0);
2789 for (i
= 0; i
< argc
; i
++) {
2790 VALUE arg
= argv
[i
];
2791 const char *s
= StringValueCStr(arg
);
2792 #ifdef DEFAULT_PROCESS_ENCODING
2793 arg
= EXPORT_STR(arg
);
2794 s
= RSTRING_PTR(arg
);
2796 rb_str_buf_cat(argv_buf
, s
, RSTRING_LEN(arg
) + 1); /* include '\0' */
2798 eargp
->invoke
.cmd
.argv_buf
= argv_buf
;
2801 if (!eargp
->use_shell
) {
2802 const char *p
, *ep
, *null
=NULL
;
2804 argv_str
= hide_obj(rb_str_buf_new(sizeof(char*) * (argc
+ 2)));
2805 rb_str_buf_cat(argv_str
, (char *)&null
, sizeof(null
)); /* place holder for /bin/sh of try_with_sh. */
2806 p
= RSTRING_PTR(eargp
->invoke
.cmd
.argv_buf
);
2807 ep
= p
+ RSTRING_LEN(eargp
->invoke
.cmd
.argv_buf
);
2809 rb_str_buf_cat(argv_str
, (char *)&p
, sizeof(p
));
2812 rb_str_buf_cat(argv_str
, (char *)&null
, sizeof(null
)); /* terminator for execve. */
2813 eargp
->invoke
.cmd
.argv_str
=
2814 rb_imemo_tmpbuf_auto_free_pointer_new_from_an_RString(argv_str
);
2816 RB_GC_GUARD(execarg_obj
);
2820 rb_execarg_get(VALUE execarg_obj
)
2822 struct rb_execarg
*eargp
;
2823 TypedData_Get_Struct(execarg_obj
, struct rb_execarg
, &exec_arg_data_type
, eargp
);
2828 rb_execarg_init(int argc
, const VALUE
*orig_argv
, int accept_shell
, VALUE execarg_obj
)
2830 struct rb_execarg
*eargp
= rb_execarg_get(execarg_obj
);
2832 VALUE env
= Qnil
, opthash
= Qnil
;
2834 VALUE
*argv
= ALLOCV_N(VALUE
, argv_buf
, argc
);
2835 MEMCPY(argv
, orig_argv
, VALUE
, argc
);
2836 prog
= rb_exec_getargs(&argc
, &argv
, accept_shell
, &env
, &opthash
);
2837 rb_exec_fillarg(prog
, argc
, argv
, env
, opthash
, execarg_obj
);
2838 ALLOCV_END(argv_buf
);
2839 ret
= eargp
->use_shell
? eargp
->invoke
.sh
.shell_script
: eargp
->invoke
.cmd
.command_name
;
2840 RB_GC_GUARD(execarg_obj
);
2845 rb_execarg_new(int argc
, const VALUE
*argv
, int accept_shell
, int allow_exc_opt
)
2848 struct rb_execarg
*eargp
;
2849 execarg_obj
= TypedData_Make_Struct(0, struct rb_execarg
, &exec_arg_data_type
, eargp
);
2850 rb_execarg_init(argc
, argv
, accept_shell
, execarg_obj
);
2851 if (!allow_exc_opt
&& eargp
->exception_given
) {
2852 rb_raise(rb_eArgError
, "exception option is not allowed");
2858 rb_execarg_setenv(VALUE execarg_obj
, VALUE env
)
2860 struct rb_execarg
*eargp
= rb_execarg_get(execarg_obj
);
2861 env
= !NIL_P(env
) ? rb_check_exec_env(env
, &eargp
->path_env
) : Qfalse
;
2862 eargp
->env_modification
= env
;
2866 fill_envp_buf_i(st_data_t st_key
, st_data_t st_val
, st_data_t arg
)
2868 VALUE key
= (VALUE
)st_key
;
2869 VALUE val
= (VALUE
)st_val
;
2870 VALUE envp_buf
= (VALUE
)arg
;
2872 rb_str_buf_cat2(envp_buf
, StringValueCStr(key
));
2873 rb_str_buf_cat2(envp_buf
, "=");
2874 rb_str_buf_cat2(envp_buf
, StringValueCStr(val
));
2875 rb_str_buf_cat(envp_buf
, "", 1); /* append '\0' */
2881 static long run_exec_dup2_tmpbuf_size(long n
);
2883 struct open_struct
{
2892 open_func(void *ptr
)
2894 struct open_struct
*data
= ptr
;
2895 const char *fname
= RSTRING_PTR(data
->fname
);
2896 data
->ret
= parent_redirect_open(fname
, data
->oflags
, data
->perm
);
2902 rb_execarg_allocate_dup2_tmpbuf(struct rb_execarg
*eargp
, long len
)
2904 VALUE tmpbuf
= rb_imemo_tmpbuf_auto_free_pointer();
2905 rb_imemo_tmpbuf_set_ptr(tmpbuf
, ruby_xmalloc(run_exec_dup2_tmpbuf_size(len
)));
2906 eargp
->dup2_tmpbuf
= tmpbuf
;
2910 rb_execarg_parent_start1(VALUE execarg_obj
)
2912 struct rb_execarg
*eargp
= rb_execarg_get(execarg_obj
);
2913 int unsetenv_others
;
2917 ary
= eargp
->fd_open
;
2918 if (ary
!= Qfalse
) {
2920 for (i
= 0; i
< RARRAY_LEN(ary
); i
++) {
2921 VALUE elt
= RARRAY_AREF(ary
, i
);
2922 int fd
= FIX2INT(RARRAY_AREF(elt
, 0));
2923 VALUE param
= RARRAY_AREF(elt
, 1);
2924 VALUE vpath
= RARRAY_AREF(param
, 0);
2925 int flags
= NUM2INT(RARRAY_AREF(param
, 1));
2926 mode_t perm
= NUM2MODET(RARRAY_AREF(param
, 2));
2927 VALUE fd2v
= RARRAY_AREF(param
, 3);
2930 struct open_struct open_data
;
2932 open_data
.fname
= vpath
;
2933 open_data
.oflags
= flags
;
2934 open_data
.perm
= perm
;
2936 open_data
.err
= EINTR
;
2937 rb_thread_call_without_gvl2(open_func
, (void *)&open_data
, RUBY_UBF_IO
, 0);
2938 if (open_data
.ret
== -1) {
2939 if (open_data
.err
== EINTR
) {
2940 rb_thread_check_ints();
2943 rb_syserr_fail_str(open_data
.err
, vpath
);
2945 fd2
= open_data
.ret
;
2946 rb_update_max_fd(fd2
);
2947 RARRAY_ASET(param
, 3, INT2FIX(fd2
));
2948 rb_thread_check_ints();
2951 fd2
= NUM2INT(fd2v
);
2953 rb_execarg_addopt(execarg_obj
, INT2FIX(fd
), INT2FIX(fd2
));
2957 eargp
->redirect_fds
= check_exec_fds(eargp
);
2959 ary
= eargp
->fd_dup2
;
2960 if (ary
!= Qfalse
) {
2961 rb_execarg_allocate_dup2_tmpbuf(eargp
, RARRAY_LEN(ary
));
2964 unsetenv_others
= eargp
->unsetenv_others_given
&& eargp
->unsetenv_others_do
;
2965 envopts
= eargp
->env_modification
;
2966 if (ALWAYS_NEED_ENVP
|| unsetenv_others
|| envopts
!= Qfalse
) {
2967 VALUE envtbl
, envp_str
, envp_buf
;
2969 if (unsetenv_others
) {
2970 envtbl
= rb_hash_new();
2973 envtbl
= rb_env_to_hash();
2976 if (envopts
!= Qfalse
) {
2977 st_table
*stenv
= RHASH_TBL_RAW(envtbl
);
2979 for (i
= 0; i
< RARRAY_LEN(envopts
); i
++) {
2980 VALUE pair
= RARRAY_AREF(envopts
, i
);
2981 VALUE key
= RARRAY_AREF(pair
, 0);
2982 VALUE val
= RARRAY_AREF(pair
, 1);
2984 st_data_t stkey
= (st_data_t
)key
;
2985 st_delete(stenv
, &stkey
, NULL
);
2988 st_insert(stenv
, (st_data_t
)key
, (st_data_t
)val
);
2989 RB_OBJ_WRITTEN(envtbl
, Qundef
, key
);
2990 RB_OBJ_WRITTEN(envtbl
, Qundef
, val
);
2994 envp_buf
= rb_str_buf_new(0);
2996 rb_hash_stlike_foreach(envtbl
, fill_envp_buf_i
, (st_data_t
)envp_buf
);
2997 envp_str
= rb_str_buf_new(sizeof(char*) * (RHASH_SIZE(envtbl
) + 1));
2999 p
= RSTRING_PTR(envp_buf
);
3000 ep
= p
+ RSTRING_LEN(envp_buf
);
3002 rb_str_buf_cat(envp_str
, (char *)&p
, sizeof(p
));
3006 rb_str_buf_cat(envp_str
, (char *)&p
, sizeof(p
));
3008 rb_imemo_tmpbuf_auto_free_pointer_new_from_an_RString(envp_str
);
3009 eargp
->envp_buf
= envp_buf
;
3012 char **tmp_envp = (char **)RSTRING_PTR(envp_str);
3014 printf("%s\n", *tmp_envp);
3020 RB_GC_GUARD(execarg_obj
);
3025 rb_execarg_parent_start(VALUE execarg_obj
)
3028 rb_protect(rb_execarg_parent_start1
, execarg_obj
, &state
);
3030 rb_execarg_parent_end(execarg_obj
);
3036 execarg_parent_end(VALUE execarg_obj
)
3038 struct rb_execarg
*eargp
= rb_execarg_get(execarg_obj
);
3042 ary
= eargp
->fd_open
;
3043 if (ary
!= Qfalse
) {
3045 for (i
= 0; i
< RARRAY_LEN(ary
); i
++) {
3046 VALUE elt
= RARRAY_AREF(ary
, i
);
3047 VALUE param
= RARRAY_AREF(elt
, 1);
3050 fd2v
= RARRAY_AREF(param
, 3);
3052 fd2
= FIX2INT(fd2v
);
3053 parent_redirect_close(fd2
);
3054 RARRAY_ASET(param
, 3, Qnil
);
3064 rb_execarg_parent_end(VALUE execarg_obj
)
3066 execarg_parent_end(execarg_obj
);
3067 RB_GC_GUARD(execarg_obj
);
3071 rb_exec_fail(struct rb_execarg
*eargp
, int err
, const char *errmsg
)
3073 if (!errmsg
|| !*errmsg
) return;
3074 if (strcmp(errmsg
, "chdir") == 0) {
3075 rb_sys_fail_str(eargp
->chdir_dir
);
3077 rb_sys_fail(errmsg
);
3082 rb_execarg_fail(VALUE execarg_obj
, int err
, const char *errmsg
)
3084 if (!errmsg
|| !*errmsg
) return;
3085 rb_exec_fail(rb_execarg_get(execarg_obj
), err
, errmsg
);
3086 RB_GC_GUARD(execarg_obj
);
3091 rb_f_exec(int argc
, const VALUE
*argv
)
3093 VALUE execarg_obj
, fail_str
;
3094 struct rb_execarg
*eargp
;
3095 #define CHILD_ERRMSG_BUFLEN 80
3096 char errmsg
[CHILD_ERRMSG_BUFLEN
] = { '\0' };
3099 execarg_obj
= rb_execarg_new(argc
, argv
, TRUE
, FALSE
);
3100 eargp
= rb_execarg_get(execarg_obj
);
3101 if (mjit_enabled
) mjit_finish(false); // avoid leaking resources, and do not leave files. XXX: JIT-ed handle can leak after exec error is rescued.
3102 before_exec(); /* stop timer thread before redirects */
3104 rb_protect(rb_execarg_parent_start1
, execarg_obj
, &state
);
3106 execarg_parent_end(execarg_obj
);
3107 after_exec(); /* restart timer thread */
3111 fail_str
= eargp
->use_shell
? eargp
->invoke
.sh
.shell_script
: eargp
->invoke
.cmd
.command_name
;
3113 err
= exec_async_signal_safe(eargp
, errmsg
, sizeof(errmsg
));
3114 after_exec(); /* restart timer thread */
3116 rb_exec_fail(eargp
, err
, errmsg
);
3117 RB_GC_GUARD(execarg_obj
);
3118 rb_syserr_fail_str(err
, fail_str
);
3119 UNREACHABLE_RETURN(Qnil
);
3122 NORETURN(static VALUE
f_exec(int c
, const VALUE
*a
, VALUE _
));
3126 * exec([env,] command... [,options])
3128 * Replaces the current process by running the given external _command_, which
3129 * can take one of the following forms:
3131 * [<code>exec(commandline)</code>]
3132 * command line string which is passed to the standard shell
3133 * [<code>exec(cmdname, arg1, ...)</code>]
3134 * command name and one or more arguments (no shell)
3135 * [<code>exec([cmdname, argv0], arg1, ...)</code>]
3136 * command name, argv[0] and zero or more arguments (no shell)
3138 * In the first form, the string is taken as a command line that is subject to
3139 * shell expansion before being executed.
3141 * The standard shell always means <code>"/bin/sh"</code> on Unix-like systems,
3142 * otherwise, <code>ENV["RUBYSHELL"]</code> or <code>ENV["COMSPEC"]</code> on
3143 * Windows and similar. The command is passed as an argument to the
3144 * <code>"-c"</code> switch to the shell, except in the case of +COMSPEC+.
3146 * If the string from the first form (<code>exec("command")</code>) follows
3147 * these simple rules:
3149 * * no meta characters
3150 * * not starting with shell reserved word or special built-in
3151 * * Ruby invokes the command directly without shell
3153 * You can force shell invocation by adding ";" to the string (because ";" is
3154 * a meta character).
3156 * Note that this behavior is observable by pid obtained
3157 * (return value of spawn() and IO#pid for IO.popen) is the pid of the invoked
3158 * command, not shell.
3160 * In the second form (<code>exec("command1", "arg1", ...)</code>), the first
3161 * is taken as a command name and the rest are passed as parameters to command
3162 * with no shell expansion.
3164 * In the third form (<code>exec(["command", "argv0"], "arg1", ...)</code>),
3165 * starting a two-element array at the beginning of the command, the first
3166 * element is the command to be executed, and the second argument is used as
3167 * the <code>argv[0]</code> value, which may show up in process listings.
3169 * In order to execute the command, one of the <code>exec(2)</code> system
3170 * calls are used, so the running command may inherit some of the environment
3171 * of the original program (including open file descriptors).
3173 * This behavior is modified by the given +env+ and +options+ parameters. See
3174 * ::spawn for details.
3176 * If the command fails to execute (typically Errno::ENOENT when
3177 * it was not found) a SystemCallError exception is raised.
3179 * This method modifies process attributes according to given +options+ before
3180 * <code>exec(2)</code> system call. See ::spawn for more details about the
3183 * The modified attributes may be retained when <code>exec(2)</code> system
3186 * For example, hard resource limits are not restorable.
3188 * Consider to create a child process using ::spawn or Kernel#system if this
3189 * is not acceptable.
3191 * exec "echo *" # echoes list of files in current directory
3194 * exec "echo", "*" # echoes an asterisk
3199 f_exec(int c
, const VALUE
*a
, VALUE _
)
3202 UNREACHABLE_RETURN(Qnil
);
3205 #define ERRMSG(str) do { if (errmsg && 0 < errmsg_buflen) strlcpy(errmsg, (str), errmsg_buflen); } while (0)
3206 #define ERRMSG1(str, a) do { if (errmsg && 0 < errmsg_buflen) snprintf(errmsg, errmsg_buflen, (str), (a)); } while (0)
3207 #define ERRMSG2(str, a, b) do { if (errmsg && 0 < errmsg_buflen) snprintf(errmsg, errmsg_buflen, (str), (a), (b)); } while (0)
3209 static int fd_get_cloexec(int fd
, char *errmsg
, size_t errmsg_buflen
);
3210 static int fd_set_cloexec(int fd
, char *errmsg
, size_t errmsg_buflen
);
3211 static int fd_clear_cloexec(int fd
, char *errmsg
, size_t errmsg_buflen
);
3214 save_redirect_fd(int fd
, struct rb_execarg
*sargp
, char *errmsg
, size_t errmsg_buflen
)
3217 VALUE newary
, redirection
;
3218 int save_fd
= redirect_cloexec_dup(fd
), cloexec
;
3219 if (save_fd
== -1) {
3225 rb_update_max_fd(save_fd
);
3226 newary
= sargp
->fd_dup2
;
3227 if (newary
== Qfalse
) {
3228 newary
= hide_obj(rb_ary_new());
3229 sargp
->fd_dup2
= newary
;
3231 cloexec
= fd_get_cloexec(fd
, errmsg
, errmsg_buflen
);
3232 redirection
= hide_obj(rb_assoc_new(INT2FIX(fd
), INT2FIX(save_fd
)));
3233 if (cloexec
) rb_ary_push(redirection
, Qtrue
);
3234 rb_ary_push(newary
, redirection
);
3236 newary
= sargp
->fd_close
;
3237 if (newary
== Qfalse
) {
3238 newary
= hide_obj(rb_ary_new());
3239 sargp
->fd_close
= newary
;
3241 rb_ary_push(newary
, hide_obj(rb_assoc_new(INT2FIX(save_fd
), Qnil
)));
3248 intcmp(const void *a
, const void *b
)
3250 return *(int*)a
- *(int*)b
;
3254 intrcmp(const void *a
, const void *b
)
3256 return *(int*)b
- *(int*)a
;
3259 struct run_exec_dup2_fd_pair
{
3268 run_exec_dup2_tmpbuf_size(long n
)
3270 return sizeof(struct run_exec_dup2_fd_pair
) * n
;
3273 /* This function should be async-signal-safe. Actually it is. */
3275 fd_get_cloexec(int fd
, char *errmsg
, size_t errmsg_buflen
)
3279 ret
= fcntl(fd
, F_GETFD
); /* async-signal-safe */
3281 ERRMSG("fcntl(F_GETFD)");
3284 if (ret
& FD_CLOEXEC
) return 1;
3289 /* This function should be async-signal-safe. Actually it is. */
3291 fd_set_cloexec(int fd
, char *errmsg
, size_t errmsg_buflen
)
3295 ret
= fcntl(fd
, F_GETFD
); /* async-signal-safe */
3297 ERRMSG("fcntl(F_GETFD)");
3300 if (!(ret
& FD_CLOEXEC
)) {
3302 ret
= fcntl(fd
, F_SETFD
, ret
); /* async-signal-safe */
3304 ERRMSG("fcntl(F_SETFD)");
3312 /* This function should be async-signal-safe. Actually it is. */
3314 fd_clear_cloexec(int fd
, char *errmsg
, size_t errmsg_buflen
)
3318 ret
= fcntl(fd
, F_GETFD
); /* async-signal-safe */
3320 ERRMSG("fcntl(F_GETFD)");
3323 if (ret
& FD_CLOEXEC
) {
3325 ret
= fcntl(fd
, F_SETFD
, ret
); /* async-signal-safe */
3327 ERRMSG("fcntl(F_SETFD)");
3335 /* This function should be async-signal-safe when sargp is NULL. Hopefully it is. */
3337 run_exec_dup2(VALUE ary
, VALUE tmpbuf
, struct rb_execarg
*sargp
, char *errmsg
, size_t errmsg_buflen
)
3342 struct rb_imemo_tmpbuf_struct
*buf
= (void *)tmpbuf
;
3343 struct run_exec_dup2_fd_pair
*pairs
= (void *)buf
->ptr
;
3345 n
= RARRAY_LEN(ary
);
3347 /* initialize oldfd and newfd: O(n) */
3348 for (i
= 0; i
< n
; i
++) {
3349 VALUE elt
= RARRAY_AREF(ary
, i
);
3350 pairs
[i
].oldfd
= FIX2INT(RARRAY_AREF(elt
, 1));
3351 pairs
[i
].newfd
= FIX2INT(RARRAY_AREF(elt
, 0)); /* unique */
3352 pairs
[i
].cloexec
= RARRAY_LEN(elt
) > 2 && RTEST(RARRAY_AREF(elt
, 2));
3353 pairs
[i
].older_index
= -1;
3356 /* sort the table by oldfd: O(n log n) */
3358 qsort(pairs
, n
, sizeof(struct run_exec_dup2_fd_pair
), intcmp
); /* hopefully async-signal-safe */
3360 qsort(pairs
, n
, sizeof(struct run_exec_dup2_fd_pair
), intrcmp
);
3362 /* initialize older_index and num_newer: O(n log n) */
3363 for (i
= 0; i
< n
; i
++) {
3364 int newfd
= pairs
[i
].newfd
;
3365 struct run_exec_dup2_fd_pair key
, *found
;
3367 found
= bsearch(&key
, pairs
, n
, sizeof(struct run_exec_dup2_fd_pair
), intcmp
); /* hopefully async-signal-safe */
3368 pairs
[i
].num_newer
= 0;
3370 while (pairs
< found
&& (found
-1)->oldfd
== newfd
)
3372 while (found
< pairs
+n
&& found
->oldfd
== newfd
) {
3373 pairs
[i
].num_newer
++;
3374 found
->older_index
= i
;
3380 /* non-cyclic redirection: O(n) */
3381 for (i
= 0; i
< n
; i
++) {
3383 while (j
!= -1 && pairs
[j
].oldfd
!= -1 && pairs
[j
].num_newer
== 0) {
3384 if (save_redirect_fd(pairs
[j
].newfd
, sargp
, errmsg
, errmsg_buflen
) < 0) /* async-signal-safe */
3386 ret
= redirect_dup2(pairs
[j
].oldfd
, pairs
[j
].newfd
); /* async-signal-safe */
3391 if (pairs
[j
].cloexec
&&
3392 fd_set_cloexec(pairs
[j
].newfd
, errmsg
, errmsg_buflen
)) {
3395 rb_update_max_fd(pairs
[j
].newfd
); /* async-signal-safe but don't need to call it in a child process. */
3396 pairs
[j
].oldfd
= -1;
3397 j
= pairs
[j
].older_index
;
3399 pairs
[j
].num_newer
--;
3403 /* cyclic redirection: O(n) */
3404 for (i
= 0; i
< n
; i
++) {
3406 if (pairs
[i
].oldfd
== -1)
3408 if (pairs
[i
].oldfd
== pairs
[i
].newfd
) { /* self cycle */
3409 if (fd_clear_cloexec(pairs
[i
].oldfd
, errmsg
, errmsg_buflen
) == -1) /* async-signal-safe */
3411 pairs
[i
].oldfd
= -1;
3414 if (extra_fd
== -1) {
3415 extra_fd
= redirect_dup(pairs
[i
].oldfd
); /* async-signal-safe */
3416 if (extra_fd
== -1) {
3420 rb_update_max_fd(extra_fd
);
3423 ret
= redirect_dup2(pairs
[i
].oldfd
, extra_fd
); /* async-signal-safe */
3428 rb_update_max_fd(extra_fd
);
3430 pairs
[i
].oldfd
= extra_fd
;
3431 j
= pairs
[i
].older_index
;
3432 pairs
[i
].older_index
= -1;
3434 ret
= redirect_dup2(pairs
[j
].oldfd
, pairs
[j
].newfd
); /* async-signal-safe */
3439 rb_update_max_fd(ret
);
3440 pairs
[j
].oldfd
= -1;
3441 j
= pairs
[j
].older_index
;
3444 if (extra_fd
!= -1) {
3445 ret
= redirect_close(extra_fd
); /* async-signal-safe */
3458 /* This function should be async-signal-safe. Actually it is. */
3460 run_exec_close(VALUE ary
, char *errmsg
, size_t errmsg_buflen
)
3465 for (i
= 0; i
< RARRAY_LEN(ary
); i
++) {
3466 VALUE elt
= RARRAY_AREF(ary
, i
);
3467 int fd
= FIX2INT(RARRAY_AREF(elt
, 0));
3468 ret
= redirect_close(fd
); /* async-signal-safe */
3477 /* This function should be async-signal-safe when sargp is NULL. Actually it is. */
3479 run_exec_dup2_child(VALUE ary
, struct rb_execarg
*sargp
, char *errmsg
, size_t errmsg_buflen
)
3484 for (i
= 0; i
< RARRAY_LEN(ary
); i
++) {
3485 VALUE elt
= RARRAY_AREF(ary
, i
);
3486 int newfd
= FIX2INT(RARRAY_AREF(elt
, 0));
3487 int oldfd
= FIX2INT(RARRAY_AREF(elt
, 1));
3489 if (save_redirect_fd(newfd
, sargp
, errmsg
, errmsg_buflen
) < 0) /* async-signal-safe */
3491 ret
= redirect_dup2(oldfd
, newfd
); /* async-signal-safe */
3496 rb_update_max_fd(newfd
);
3502 /* This function should be async-signal-safe when sargp is NULL. Actually it is. */
3504 run_exec_pgroup(const struct rb_execarg
*eargp
, struct rb_execarg
*sargp
, char *errmsg
, size_t errmsg_buflen
)
3507 * If FD_CLOEXEC is available, rb_fork_async_signal_safe waits the child's execve.
3508 * So setpgid is done in the child when rb_fork_async_signal_safe is returned in
3510 * No race condition, even without setpgid from the parent.
3511 * (Is there an environment which has setpgid but no FD_CLOEXEC?)
3516 pgroup
= eargp
->pgroup_pgid
;
3521 /* maybe meaningless with no fork environment... */
3522 sargp
->pgroup_given
= 1;
3523 sargp
->pgroup_pgid
= getpgrp();
3527 pgroup
= getpid(); /* async-signal-safe */
3529 ret
= setpgid(getpid(), pgroup
); /* async-signal-safe */
3530 if (ret
== -1) ERRMSG("setpgid");
3535 #if defined(HAVE_SETRLIMIT) && defined(RLIM2NUM)
3536 /* This function should be async-signal-safe when sargp is NULL. Hopefully it is. */
3538 run_exec_rlimit(VALUE ary
, struct rb_execarg
*sargp
, char *errmsg
, size_t errmsg_buflen
)
3541 for (i
= 0; i
< RARRAY_LEN(ary
); i
++) {
3542 VALUE elt
= RARRAY_AREF(ary
, i
);
3543 int rtype
= NUM2INT(RARRAY_AREF(elt
, 0));
3547 if (getrlimit(rtype
, &rlim
) == -1) {
3548 ERRMSG("getrlimit");
3551 tmp
= hide_obj(rb_ary_new3(3, RARRAY_AREF(elt
, 0),
3552 RLIM2NUM(rlim
.rlim_cur
),
3553 RLIM2NUM(rlim
.rlim_max
)));
3554 if (sargp
->rlimit_limits
== Qfalse
)
3555 newary
= sargp
->rlimit_limits
= hide_obj(rb_ary_new());
3557 newary
= sargp
->rlimit_limits
;
3558 rb_ary_push(newary
, tmp
);
3560 rlim
.rlim_cur
= NUM2RLIM(RARRAY_AREF(elt
, 1));
3561 rlim
.rlim_max
= NUM2RLIM(RARRAY_AREF(elt
, 2));
3562 if (setrlimit(rtype
, &rlim
) == -1) { /* hopefully async-signal-safe */
3563 ERRMSG("setrlimit");
3571 #if !defined(HAVE_WORKING_FORK)
3573 save_env_i(RB_BLOCK_CALL_FUNC_ARGLIST(i
, ary
))
3575 rb_ary_push(ary
, hide_obj(rb_ary_dup(argv
[0])));
3580 save_env(struct rb_execarg
*sargp
)
3584 if (sargp
->env_modification
== Qfalse
) {
3585 VALUE env
= rb_envtbl();
3587 VALUE ary
= hide_obj(rb_ary_new());
3588 rb_block_call(env
, idEach
, 0, 0, save_env_i
,
3590 sargp
->env_modification
= ary
;
3592 sargp
->unsetenv_others_given
= 1;
3593 sargp
->unsetenv_others_do
= 1;
3600 #define chdir(p) rb_w32_uchdir(p)
3603 /* This function should be async-signal-safe when sargp is NULL. Hopefully it is. */
3605 rb_execarg_run_options(const struct rb_execarg
*eargp
, struct rb_execarg
*sargp
, char *errmsg
, size_t errmsg_buflen
)
3610 /* assume that sargp is always NULL on fork-able environments */
3611 MEMZERO(sargp
, struct rb_execarg
, 1);
3612 sargp
->redirect_fds
= Qnil
;
3616 if (eargp
->pgroup_given
) {
3617 if (run_exec_pgroup(eargp
, sargp
, errmsg
, errmsg_buflen
) == -1) /* async-signal-safe */
3622 #if defined(HAVE_SETRLIMIT) && defined(RLIM2NUM)
3623 obj
= eargp
->rlimit_limits
;
3624 if (obj
!= Qfalse
) {
3625 if (run_exec_rlimit(obj
, sargp
, errmsg
, errmsg_buflen
) == -1) /* hopefully async-signal-safe */
3630 #if !defined(HAVE_WORKING_FORK)
3631 if (eargp
->unsetenv_others_given
&& eargp
->unsetenv_others_do
) {
3636 obj
= eargp
->env_modification
;
3637 if (obj
!= Qfalse
) {
3640 for (i
= 0; i
< RARRAY_LEN(obj
); i
++) {
3641 VALUE pair
= RARRAY_AREF(obj
, i
);
3642 VALUE key
= RARRAY_AREF(pair
, 0);
3643 VALUE val
= RARRAY_AREF(pair
, 1);
3645 ruby_setenv(StringValueCStr(key
), 0);
3647 ruby_setenv(StringValueCStr(key
), StringValueCStr(val
));
3652 if (eargp
->umask_given
) {
3653 mode_t mask
= eargp
->umask_mask
;
3654 mode_t oldmask
= umask(mask
); /* never fail */ /* async-signal-safe */
3656 sargp
->umask_given
= 1;
3657 sargp
->umask_mask
= oldmask
;
3661 obj
= eargp
->fd_dup2
;
3662 if (obj
!= Qfalse
) {
3663 if (run_exec_dup2(obj
, eargp
->dup2_tmpbuf
, sargp
, errmsg
, errmsg_buflen
) == -1) /* hopefully async-signal-safe */
3667 obj
= eargp
->fd_close
;
3668 if (obj
!= Qfalse
) {
3670 rb_warn("cannot close fd before spawn");
3672 if (run_exec_close(obj
, errmsg
, errmsg_buflen
) == -1) /* async-signal-safe */
3677 #ifdef HAVE_WORKING_FORK
3678 if (eargp
->close_others_do
) {
3679 rb_close_before_exec(3, eargp
->close_others_maxhint
, eargp
->redirect_fds
); /* async-signal-safe */
3683 obj
= eargp
->fd_dup2_child
;
3684 if (obj
!= Qfalse
) {
3685 if (run_exec_dup2_child(obj
, sargp
, errmsg
, errmsg_buflen
) == -1) /* async-signal-safe */
3689 if (eargp
->chdir_given
) {
3691 sargp
->chdir_given
= 1;
3692 sargp
->chdir_dir
= hide_obj(rb_dir_getwd_ospath());
3694 if (chdir(RSTRING_PTR(eargp
->chdir_dir
)) == -1) { /* async-signal-safe */
3701 if (eargp
->gid_given
) {
3702 if (setgid(eargp
->gid
) < 0) {
3709 if (eargp
->uid_given
) {
3710 if (setuid(eargp
->uid
) < 0) {
3718 VALUE ary
= sargp
->fd_dup2
;
3719 if (ary
!= Qfalse
) {
3720 rb_execarg_allocate_dup2_tmpbuf(sargp
, RARRAY_LEN(ary
));
3724 int preserve
= errno
;
3725 stdfd_clear_nonblock();
3732 /* This function should be async-signal-safe. Hopefully it is. */
3734 rb_exec_async_signal_safe(const struct rb_execarg
*eargp
, char *errmsg
, size_t errmsg_buflen
)
3736 errno
= exec_async_signal_safe(eargp
, errmsg
, errmsg_buflen
);
3741 exec_async_signal_safe(const struct rb_execarg
*eargp
, char *errmsg
, size_t errmsg_buflen
)
3743 #if !defined(HAVE_WORKING_FORK)
3744 struct rb_execarg sarg
, *const sargp
= &sarg
;
3746 struct rb_execarg
*const sargp
= NULL
;
3750 if (rb_execarg_run_options(eargp
, sargp
, errmsg
, errmsg_buflen
) < 0) { /* hopefully async-signal-safe */
3754 if (eargp
->use_shell
) {
3755 err
= proc_exec_sh(RSTRING_PTR(eargp
->invoke
.sh
.shell_script
), eargp
->envp_str
); /* async-signal-safe */
3758 char *abspath
= NULL
;
3759 if (!NIL_P(eargp
->invoke
.cmd
.command_abspath
))
3760 abspath
= RSTRING_PTR(eargp
->invoke
.cmd
.command_abspath
);
3761 err
= proc_exec_cmd(abspath
, eargp
->invoke
.cmd
.argv_str
, eargp
->envp_str
); /* async-signal-safe */
3763 #if !defined(HAVE_WORKING_FORK)
3764 rb_execarg_run_options(sargp
, NULL
, errmsg
, errmsg_buflen
);
3770 #ifdef HAVE_WORKING_FORK
3771 /* This function should be async-signal-safe. Hopefully it is. */
3773 rb_exec_atfork(void* arg
, char *errmsg
, size_t errmsg_buflen
)
3775 return rb_exec_async_signal_safe(arg
, errmsg
, errmsg_buflen
); /* hopefully async-signal-safe */
3778 #if SIZEOF_INT == SIZEOF_LONG
3779 #define proc_syswait (VALUE (*)(VALUE))rb_syswait
3782 proc_syswait(VALUE pid
)
3784 rb_syswait((int)pid
);
3790 move_fds_to_avoid_crash(int *fdp
, int n
, VALUE fds
)
3794 for (i
= 0; i
< n
; i
++) {
3796 while (RTEST(rb_hash_lookup(fds
, INT2FIX(fdp
[i
])))) {
3799 while (RTEST(rb_hash_lookup(fds
, INT2FIX(min
))))
3801 ret
= rb_cloexec_fcntl_dupfd(fdp
[i
], min
);
3804 rb_update_max_fd(ret
);
3813 pipe_nocrash(int filedes
[2], VALUE fds
)
3816 ret
= rb_pipe(filedes
);
3821 if (move_fds_to_avoid_crash(filedes
, 2, fds
) == -1) {
3836 rb_thread_sleep_that_takes_VALUE_as_sole_argument(VALUE n
)
3838 rb_thread_sleep(NUM2INT(n
));
3843 handle_fork_error(int err
, struct rb_process_status
*status
, int *ep
, volatile int *try_gc_p
)
3849 if ((*try_gc_p
)-- > 0 && !rb_during_gc()) {
3855 #if defined(EWOULDBLOCK) && EWOULDBLOCK != EAGAIN
3858 if (!status
&& !ep
) {
3863 rb_protect(rb_thread_sleep_that_takes_VALUE_as_sole_argument
, INT2FIX(1), &state
);
3864 if (status
) status
->status
= state
;
3865 if (!state
) return 0;
3874 if (state
&& !status
) rb_jump_tag(state
);
3878 #define prefork() ( \
3879 rb_io_flush(rb_stdout), \
3880 rb_io_flush(rb_stderr) \
3884 * Forks child process, and returns the process ID in the parent
3887 * If +status+ is given, protects from any exceptions and sets the
3888 * jump status to it, and returns -1. If failed to fork new process
3889 * but no exceptions occurred, sets 0 to it. Otherwise, if forked
3890 * successfully, the value of +status+ is undetermined.
3892 * In the child process, just returns 0 if +chfunc+ is +NULL+.
3893 * Otherwise +chfunc+ will be called with +charg+, and then the child
3894 * process exits with +EXIT_SUCCESS+ when it returned zero.
3896 * In the case of the function is called and returns non-zero value,
3897 * the child process exits with non-+EXIT_SUCCESS+ value (normally
3898 * 127). And, on the platforms where +FD_CLOEXEC+ is available,
3899 * +errno+ is propagated to the parent process, and this function
3900 * returns -1 in the parent process. On the other platforms, just
3903 * If fds is not Qnil, internal pipe for the errno propagation is
3904 * arranged to avoid conflicts of the hash keys in +fds+.
3906 * +chfunc+ must not raise any exceptions.
3910 write_retry(int fd
, const void *buf
, size_t len
)
3915 w
= write(fd
, buf
, len
);
3916 } while (w
< 0 && errno
== EINTR
);
3922 read_retry(int fd
, void *buf
, size_t len
)
3926 if (set_blocking(fd
) != 0) {
3928 rb_async_bug_errno("set_blocking failed reading child error", errno
);
3933 r
= read(fd
, buf
, len
);
3934 } while (r
< 0 && errno
== EINTR
);
3940 send_child_error(int fd
, char *errmsg
, size_t errmsg_buflen
)
3945 if (write_retry(fd
, &err
, sizeof(err
)) < 0) err
= errno
;
3946 if (errmsg
&& 0 < errmsg_buflen
) {
3947 errmsg
[errmsg_buflen
-1] = '\0';
3948 errmsg_buflen
= strlen(errmsg
);
3949 if (errmsg_buflen
> 0 && write_retry(fd
, errmsg
, errmsg_buflen
) < 0)
3955 recv_child_error(int fd
, int *errp
, char *errmsg
, size_t errmsg_buflen
)
3959 if ((size
= read_retry(fd
, &err
, sizeof(err
))) < 0) {
3963 if (size
== sizeof(err
) &&
3964 errmsg
&& 0 < errmsg_buflen
) {
3965 ssize_t ret
= read_retry(fd
, errmsg
, errmsg_buflen
-1);
3974 #ifdef HAVE_WORKING_VFORK
3975 #if !defined(HAVE_GETRESUID) && defined(HAVE_GETUIDX)
3978 getresuid(rb_uid_t
*ruid
, rb_uid_t
*euid
, rb_uid_t
*suid
)
3984 ret
= getuidx(ID_SAVED
);
3985 if (ret
== (rb_uid_t
)-1)
3990 #define HAVE_GETRESUID
3993 #if !defined(HAVE_GETRESGID) && defined(HAVE_GETGIDX)
3996 getresgid(rb_gid_t
*rgid
, rb_gid_t
*egid
, rb_gid_t
*sgid
)
4002 ret
= getgidx(ID_SAVED
);
4003 if (ret
== (rb_gid_t
)-1)
4008 #define HAVE_GETRESGID
4015 * has_privilege() is used to choose vfork() or fork().
4017 * If the process has privilege, the parent process or
4018 * the child process can change UID/GID.
4019 * If vfork() is used to create the child process and
4020 * the parent or child process change effective UID/GID,
4021 * different privileged processes shares memory.
4022 * It is a bad situation.
4023 * So, fork() should be used.
4026 rb_uid_t ruid
, euid
;
4027 rb_gid_t rgid
, egid
;
4029 #if defined HAVE_ISSETUGID
4034 #ifdef HAVE_GETRESUID
4038 ret
= getresuid(&ruid
, &euid
, &suid
);
4040 rb_sys_fail("getresuid(2)");
4049 if (euid
== 0 || euid
!= ruid
)
4052 #ifdef HAVE_GETRESGID
4056 ret
= getresgid(&rgid
, &egid
, &sgid
);
4058 rb_sys_fail("getresgid(2)");
4074 struct child_handler_disabler_state
4080 disable_child_handler_before_fork(struct child_handler_disabler_state
*old
)
4082 #ifdef HAVE_PTHREAD_SIGMASK
4086 ret
= sigfillset(&all
);
4088 rb_sys_fail("sigfillset");
4090 ret
= pthread_sigmask(SIG_SETMASK
, &all
, &old
->sigmask
); /* not async-signal-safe */
4092 rb_syserr_fail(ret
, "pthread_sigmask");
4095 # pragma GCC warning "pthread_sigmask on fork is not available. potentially dangerous"
4100 disable_child_handler_fork_parent(struct child_handler_disabler_state
*old
)
4102 #ifdef HAVE_PTHREAD_SIGMASK
4105 ret
= pthread_sigmask(SIG_SETMASK
, &old
->sigmask
, NULL
); /* not async-signal-safe */
4107 rb_syserr_fail(ret
, "pthread_sigmask");
4110 # pragma GCC warning "pthread_sigmask on fork is not available. potentially dangerous"
4114 /* This function should be async-signal-safe. Actually it is. */
4116 disable_child_handler_fork_child(struct child_handler_disabler_state
*old
, char *errmsg
, size_t errmsg_buflen
)
4121 for (sig
= 1; sig
< NSIG
; sig
++) {
4122 sig_t handler
= signal(sig
, SIG_DFL
);
4124 if (handler
== SIG_ERR
&& errno
== EINVAL
) {
4125 continue; /* Ignore invalid signal number */
4127 if (handler
== SIG_ERR
) {
4128 ERRMSG("signal to obtain old action");
4132 if (sig
== SIGPIPE
) {
4136 /* it will be reset to SIG_DFL at execve time, instead */
4137 if (handler
== SIG_IGN
) {
4138 signal(sig
, SIG_IGN
);
4142 /* non-Ruby child process, ensure cmake can see SIGCHLD */
4143 sigemptyset(&old
->sigmask
);
4144 ret
= sigprocmask(SIG_SETMASK
, &old
->sigmask
, NULL
); /* async-signal-safe */
4146 ERRMSG("sigprocmask");
4153 retry_fork_async_signal_safe(struct rb_process_status
*status
, int *ep
,
4154 int (*chfunc
)(void*, char *, size_t), void *charg
,
4155 char *errmsg
, size_t errmsg_buflen
,
4156 struct waitpid_state
*w
)
4159 volatile int try_gc
= 1;
4160 struct child_handler_disabler_state old
;
4162 rb_nativethread_lock_t
*const volatile waitpid_lock_init
=
4163 (w
&& WAITPID_USE_SIGCHLD
) ? &GET_VM()->waitpid_lock
: 0;
4166 rb_nativethread_lock_t
*waitpid_lock
= waitpid_lock_init
;
4168 disable_child_handler_before_fork(&old
);
4170 rb_native_mutex_lock(waitpid_lock
);
4172 #ifdef HAVE_WORKING_VFORK
4173 if (!has_privilege())
4180 if (pid
== 0) {/* fork succeed, child process */
4183 ret
= disable_child_handler_fork_child(&old
, errmsg
, errmsg_buflen
); /* async-signal-safe */
4185 ret
= chfunc(charg
, errmsg
, errmsg_buflen
);
4186 if (!ret
) _exit(EXIT_SUCCESS
);
4188 send_child_error(ep
[1], errmsg
, errmsg_buflen
);
4189 #if EXIT_SUCCESS == 127
4190 _exit(EXIT_FAILURE
);
4196 waitpid_lock
= waitpid_lock_init
;
4198 if (pid
> 0 && w
!= WAITPID_LOCK_ONLY
) {
4200 list_add(&GET_VM()->waiting_pids
, &w
->wnode
);
4202 rb_native_mutex_unlock(waitpid_lock
);
4204 disable_child_handler_fork_parent(&old
);
4205 if (0 < pid
) /* fork succeed, parent process */
4208 if (handle_fork_error(err
, status
, ep
, &try_gc
))
4214 fork_check_err(struct rb_process_status
*status
, int (*chfunc
)(void*, char *, size_t), void *charg
,
4215 VALUE fds
, char *errmsg
, size_t errmsg_buflen
,
4216 struct rb_execarg
*eargp
)
4223 struct waitpid_state
*w
= eargp
&& eargp
->waitpid_state
? eargp
->waitpid_state
: 0;
4225 if (status
) status
->status
= 0;
4227 if (pipe_nocrash(ep
, fds
)) return -1;
4229 pid
= retry_fork_async_signal_safe(status
, ep
, chfunc
, charg
, errmsg
, errmsg_buflen
, w
);
4231 if (status
) status
->pid
= pid
;
4234 if (status
) status
->error
= errno
;
4241 error_occurred
= recv_child_error(ep
[0], &err
, errmsg
, errmsg_buflen
);
4243 if (error_occurred
) {
4246 status
->error
= err
;
4248 VM_ASSERT((w
== 0 || w
== WAITPID_LOCK_ONLY
) &&
4249 "only used by extensions");
4250 rb_protect(proc_syswait
, (VALUE
)pid
, &state
);
4252 status
->status
= state
;
4254 else if (!w
|| w
== WAITPID_LOCK_ONLY
) {
4266 * The "async_signal_safe" name is a lie, but it is used by pty.c and
4267 * maybe other exts. fork() is not async-signal-safe due to pthread_atfork
4268 * and future POSIX revisions will remove it from a list of signal-safe
4269 * functions. rb_waitpid is not async-signal-safe since MJIT, either.
4270 * For our purposes, we do not need async-signal-safety, here
4273 rb_fork_async_signal_safe(int *status
,
4274 int (*chfunc
)(void*, char *, size_t), void *charg
,
4275 VALUE fds
, char *errmsg
, size_t errmsg_buflen
)
4277 struct rb_process_status process_status
;
4279 rb_pid_t result
= fork_check_err(&process_status
, chfunc
, charg
, fds
, errmsg
, errmsg_buflen
, 0);
4282 *status
= process_status
.status
;
4289 rb_fork_ruby2(struct rb_process_status
*status
)
4292 int try_gc
= 1, err
;
4293 struct child_handler_disabler_state old
;
4295 if (status
) status
->status
= 0;
4299 if (mjit_enabled
) mjit_pause(false); // Don't leave locked mutex to child. Note: child_handler must be enabled to pause MJIT.
4300 disable_child_handler_before_fork(&old
);
4306 status
->error
= err
;
4309 disable_child_handler_fork_parent(&old
); /* yes, bad name */
4311 if (mjit_enabled
&& pid
> 0) mjit_resume(); /* child (pid == 0) is cared by rb_thread_atfork */
4313 if (pid
>= 0) { /* fork succeed */
4314 if (pid
== 0) rb_thread_atfork();
4319 if (handle_fork_error(err
, status
, NULL
, &try_gc
)) {
4326 rb_fork_ruby(int *status
)
4328 struct rb_process_status process_status
= {0};
4330 rb_pid_t pid
= rb_fork_ruby2(&process_status
);
4332 if (status
) *status
= process_status
.status
;
4338 rb_call_proc__fork(void)
4340 VALUE pid
= rb_funcall(rb_mProcess
, rb_intern("_fork"), 0);
4342 return NUM2PIDT(pid
);
4346 #if defined(HAVE_WORKING_FORK) && !defined(CANNOT_FORK_WITH_PTHREAD)
4349 * Process._fork -> integer
4351 * An internal API for fork. Do not call this method directly.
4352 * Currently, this is called via Kernel#fork, Process.fork, and
4353 * IO.popen with <tt>"-"</tt>.
4355 * This method is not for casual code but for application monitoring
4356 * libraries. You can add custom code before and after fork events
4357 * by overriding this method.
4360 rb_proc__fork(VALUE _obj
)
4362 rb_pid_t pid
= rb_fork_ruby(NULL
);
4365 rb_sys_fail("fork(2)");
4368 return PIDT2NUM(pid
);
4373 * Kernel.fork [{ block }] -> integer or nil
4374 * Process.fork [{ block }] -> integer or nil
4376 * Creates a subprocess. If a block is specified, that block is run
4377 * in the subprocess, and the subprocess terminates with a status of
4378 * zero. Otherwise, the +fork+ call returns twice, once in the
4379 * parent, returning the process ID of the child, and once in the
4380 * child, returning _nil_. The child process can exit using
4381 * Kernel.exit! to avoid running any <code>at_exit</code>
4382 * functions. The parent process should use Process.wait to collect
4383 * the termination statuses of its children or use Process.detach to
4384 * register disinterest in their status; otherwise, the operating
4385 * system may accumulate zombie processes.
4387 * The thread calling fork is the only thread in the created child process.
4388 * fork doesn't copy other threads.
4390 * If fork is not usable, Process.respond_to?(:fork) returns false.
4392 * Note that fork(2) is not available on some platforms like Windows and NetBSD 4.
4393 * Therefore you should use spawn() instead of fork().
4397 rb_f_fork(VALUE obj
)
4401 pid
= rb_call_proc__fork();
4404 if (rb_block_given_p()) {
4406 rb_protect(rb_yield
, Qundef
, &status
);
4412 return PIDT2NUM(pid
);
4415 #define rb_proc__fork rb_f_notimplement
4416 #define rb_f_fork rb_f_notimplement
4420 exit_status_code(VALUE status
)
4426 istatus
= EXIT_SUCCESS
;
4429 istatus
= EXIT_FAILURE
;
4432 istatus
= NUM2INT(status
);
4433 #if EXIT_SUCCESS != 0
4435 istatus
= EXIT_SUCCESS
;
4442 NORETURN(static VALUE
rb_f_exit_bang(int argc
, VALUE
*argv
, VALUE obj
));
4445 * Process.exit!(status=false)
4447 * Exits the process immediately. No exit handlers are
4448 * run. <em>status</em> is returned to the underlying system as the
4451 * Process.exit!(true)
4455 rb_f_exit_bang(int argc
, VALUE
*argv
, VALUE obj
)
4459 if (rb_check_arity(argc
, 0, 1) == 1) {
4460 istatus
= exit_status_code(argv
[0]);
4463 istatus
= EXIT_FAILURE
;
4467 UNREACHABLE_RETURN(Qnil
);
4473 if (GET_EC()->tag
) {
4476 args
[0] = INT2NUM(status
);
4477 args
[1] = rb_str_new2("exit");
4478 rb_exc_raise(rb_class_new_instance(2, args
, rb_eSystemExit
));
4484 rb_f_exit(int argc
, const VALUE
*argv
)
4488 if (rb_check_arity(argc
, 0, 1) == 1) {
4489 istatus
= exit_status_code(argv
[0]);
4492 istatus
= EXIT_SUCCESS
;
4496 UNREACHABLE_RETURN(Qnil
);
4499 NORETURN(static VALUE
f_exit(int c
, const VALUE
*a
, VALUE _
));
4503 * Kernel::exit(status=true)
4504 * Process::exit(status=true)
4506 * Initiates the termination of the Ruby script by raising the
4507 * SystemExit exception. This exception may be caught. The
4508 * optional parameter is used to return a status code to the invoking
4510 * +true+ and +FALSE+ of _status_ means success and failure
4511 * respectively. The interpretation of other integer values are
4516 * puts "never get here"
4518 * puts "rescued a SystemExit exception"
4520 * puts "after begin block"
4522 * <em>produces:</em>
4524 * rescued a SystemExit exception
4527 * Just prior to termination, Ruby executes any <code>at_exit</code>
4528 * functions (see Kernel::at_exit) and runs any object finalizers
4529 * (see ObjectSpace::define_finalizer).
4531 * at_exit { puts "at_exit function" }
4532 * ObjectSpace.define_finalizer("string", proc { puts "in finalizer" })
4535 * <em>produces:</em>
4542 f_exit(int c
, const VALUE
*a
, VALUE _
)
4545 UNREACHABLE_RETURN(Qnil
);
4549 rb_f_abort(int argc
, const VALUE
*argv
)
4551 rb_check_arity(argc
, 0, 1);
4553 rb_execution_context_t
*ec
= GET_EC();
4554 VALUE errinfo
= rb_ec_get_errinfo(ec
);
4555 if (!NIL_P(errinfo
)) {
4556 rb_ec_error_print(ec
, errinfo
);
4558 rb_exit(EXIT_FAILURE
);
4563 args
[1] = args
[0] = argv
[0];
4564 StringValue(args
[0]);
4565 rb_io_puts(1, args
, rb_ractor_stderr());
4566 args
[0] = INT2NUM(EXIT_FAILURE
);
4567 rb_exc_raise(rb_class_new_instance(2, args
, rb_eSystemExit
));
4570 UNREACHABLE_RETURN(Qnil
);
4573 NORETURN(static VALUE
f_abort(int c
, const VALUE
*a
, VALUE _
));
4578 * Kernel::abort([msg])
4579 * Process.abort([msg])
4581 * Terminate execution immediately, effectively by calling
4582 * <code>Kernel.exit(false)</code>. If _msg_ is given, it is written
4583 * to STDERR prior to terminating.
4587 f_abort(int c
, const VALUE
*a
, VALUE _
)
4590 UNREACHABLE_RETURN(Qnil
);
4594 rb_syswait(rb_pid_t pid
)
4598 rb_waitpid(pid
, &status
, 0);
4601 #if !defined HAVE_WORKING_FORK && !defined HAVE_SPAWNV && !defined __EMSCRIPTEN__
4603 rb_execarg_commandline(const struct rb_execarg
*eargp
, VALUE
*prog
)
4606 if (eargp
&& !eargp
->use_shell
) {
4607 VALUE str
= eargp
->invoke
.cmd
.argv_str
;
4608 VALUE buf
= eargp
->invoke
.cmd
.argv_buf
;
4609 char *p
, **argv
= ARGVSTR2ARGV(str
);
4610 long i
, argc
= ARGVSTR2ARGC(str
);
4611 const char *start
= RSTRING_PTR(buf
);
4612 cmd
= rb_str_new(start
, RSTRING_LEN(buf
));
4613 p
= RSTRING_PTR(cmd
);
4614 for (i
= 1; i
< argc
; ++i
) {
4615 p
[argv
[i
] - start
- 1] = ' ';
4620 return StringValueCStr(*prog
);
4625 rb_spawn_process(struct rb_execarg
*eargp
, char *errmsg
, size_t errmsg_buflen
)
4628 #if !defined HAVE_WORKING_FORK || USE_SPAWNV
4630 struct rb_execarg sarg
;
4631 # if !defined HAVE_SPAWNV
4636 #if defined HAVE_WORKING_FORK && !USE_SPAWNV
4637 pid
= fork_check_err(eargp
->status
, rb_exec_atfork
, eargp
, eargp
->redirect_fds
, errmsg
, errmsg_buflen
, eargp
);
4639 prog
= eargp
->use_shell
? eargp
->invoke
.sh
.shell_script
: eargp
->invoke
.cmd
.command_name
;
4641 if (rb_execarg_run_options(eargp
, &sarg
, errmsg
, errmsg_buflen
) < 0) {
4645 if (prog
&& !eargp
->use_shell
) {
4646 char **argv
= ARGVSTR2ARGV(eargp
->invoke
.cmd
.argv_str
);
4647 argv
[0] = RSTRING_PTR(prog
);
4649 # if defined HAVE_SPAWNV
4650 if (eargp
->use_shell
) {
4651 pid
= proc_spawn_sh(RSTRING_PTR(prog
));
4654 char **argv
= ARGVSTR2ARGV(eargp
->invoke
.cmd
.argv_str
);
4655 pid
= proc_spawn_cmd(argv
, prog
, eargp
);
4659 rb_last_status_set(0x7f << 8, pid
);
4662 status
= system(rb_execarg_commandline(eargp
, &prog
));
4663 pid
= 1; /* dummy */
4664 rb_last_status_set((status
& 0xff) << 8, pid
);
4667 if (eargp
->waitpid_state
&& eargp
->waitpid_state
!= WAITPID_LOCK_ONLY
) {
4668 eargp
->waitpid_state
->pid
= pid
;
4671 rb_execarg_run_options(&sarg
, NULL
, errmsg
, errmsg_buflen
);
4686 do_spawn_process(VALUE arg
)
4688 struct spawn_args
*argp
= (struct spawn_args
*)arg
;
4689 rb_execarg_parent_start1(argp
->execarg
);
4690 return (VALUE
)rb_spawn_process(DATA_PTR(argp
->execarg
),
4691 argp
->errmsg
.ptr
, argp
->errmsg
.buflen
);
4695 rb_execarg_spawn(VALUE execarg_obj
, char *errmsg
, size_t errmsg_buflen
)
4697 struct spawn_args args
;
4698 struct rb_execarg
*eargp
= rb_execarg_get(execarg_obj
);
4701 * Prevent a race with MJIT where the compiler process where
4702 * can hold an FD of ours in between vfork + execve
4704 if (!eargp
->waitpid_state
&& mjit_enabled
) {
4705 eargp
->waitpid_state
= WAITPID_LOCK_ONLY
;
4708 args
.execarg
= execarg_obj
;
4709 args
.errmsg
.ptr
= errmsg
;
4710 args
.errmsg
.buflen
= errmsg_buflen
;
4711 return (rb_pid_t
)rb_ensure(do_spawn_process
, (VALUE
)&args
,
4712 execarg_parent_end
, execarg_obj
);
4716 rb_spawn_internal(int argc
, const VALUE
*argv
, char *errmsg
, size_t errmsg_buflen
)
4720 execarg_obj
= rb_execarg_new(argc
, argv
, TRUE
, FALSE
);
4721 return rb_execarg_spawn(execarg_obj
, errmsg
, errmsg_buflen
);
4725 rb_spawn_err(int argc
, const VALUE
*argv
, char *errmsg
, size_t errmsg_buflen
)
4727 return rb_spawn_internal(argc
, argv
, errmsg
, errmsg_buflen
);
4731 rb_spawn(int argc
, const VALUE
*argv
)
4733 return rb_spawn_internal(argc
, argv
, NULL
, 0);
4738 * system([env,] command... [,options], exception: false) -> true, false or nil
4740 * Executes _command..._ in a subshell.
4741 * _command..._ is one of following forms.
4743 * [<code>commandline</code>]
4744 * command line string which is passed to the standard shell
4745 * [<code>cmdname, arg1, ...</code>]
4746 * command name and one or more arguments (no shell)
4747 * [<code>[cmdname, argv0], arg1, ...</code>]
4748 * command name, <code>argv[0]</code> and zero or more arguments (no shell)
4750 * system returns +true+ if the command gives zero exit status,
4751 * +false+ for non zero exit status.
4752 * Returns +nil+ if command execution fails.
4753 * An error status is available in <code>$?</code>.
4755 * If the <code>exception: true</code> argument is passed, the method
4756 * raises an exception instead of returning +false+ or +nil+.
4758 * The arguments are processed in the same way as
4761 * The hash arguments, env and options, are same as #exec and #spawn.
4762 * See Kernel#spawn for details.
4765 * system("echo", "*")
4767 * <em>produces:</em>
4774 * system("cat nonexistent.txt")
4776 * system("catt nonexistent.txt")
4779 * system("cat nonexistent.txt", exception: true)
4780 * # RuntimeError (Command failed with exit 1: cat)
4781 * system("catt nonexistent.txt", exception: true)
4782 * # Errno::ENOENT (No such file or directory - catt)
4784 * See Kernel#exec for the standard shell.
4788 rb_f_system(int argc
, VALUE
*argv
, VALUE _
)
4790 VALUE execarg_obj
= rb_execarg_new(argc
, argv
, TRUE
, TRUE
);
4791 struct rb_execarg
*eargp
= rb_execarg_get(execarg_obj
);
4793 struct rb_process_status status
= {0};
4794 eargp
->status
= &status
;
4796 rb_last_status_clear();
4798 // This function can set the thread's last status.
4799 // May be different from waitpid_state.pid on exec failure.
4800 rb_pid_t pid
= rb_execarg_spawn(execarg_obj
, 0, 0);
4803 VALUE status
= rb_process_status_wait(pid
, 0);
4804 struct rb_process_status
*data
= RTYPEDDATA_DATA(status
);
4806 // Set the last status:
4807 rb_obj_freeze(status
);
4808 GET_THREAD()->last_status
= status
;
4810 if (data
->status
== EXIT_SUCCESS
) {
4814 if (data
->error
!= 0) {
4815 if (eargp
->exception
) {
4816 VALUE command
= eargp
->invoke
.sh
.shell_script
;
4817 RB_GC_GUARD(execarg_obj
);
4818 rb_syserr_fail_str(data
->error
, command
);
4824 else if (eargp
->exception
) {
4825 VALUE command
= eargp
->invoke
.sh
.shell_script
;
4826 VALUE str
= rb_str_new_cstr("Command failed with");
4827 rb_str_cat_cstr(pst_message_status(str
, data
->status
), ": ");
4828 rb_str_append(str
, command
);
4829 RB_GC_GUARD(execarg_obj
);
4830 rb_exc_raise(rb_exc_new_str(rb_eRuntimeError
, str
));
4836 RB_GC_GUARD(status
);
4839 if (eargp
->exception
) {
4840 VALUE command
= eargp
->invoke
.sh
.shell_script
;
4841 RB_GC_GUARD(execarg_obj
);
4842 rb_syserr_fail_str(errno
, command
);
4851 * spawn([env,] command... [,options]) -> pid
4852 * Process.spawn([env,] command... [,options]) -> pid
4854 * spawn executes specified command and return its pid.
4856 * pid = spawn("tar xf ruby-2.0.0-p195.tar.bz2")
4859 * pid = spawn(RbConfig.ruby, "-eputs'Hello, world!'")
4862 * This method is similar to Kernel#system but it doesn't wait for the command
4865 * The parent process should
4866 * use Process.wait to collect
4867 * the termination status of its child or
4868 * use Process.detach to register
4869 * disinterest in their status;
4870 * otherwise, the operating system may accumulate zombie processes.
4872 * spawn has bunch of options to specify process attributes:
4875 * name => val : set the environment variable
4876 * name => nil : unset the environment variable
4878 * the keys and the values except for +nil+ must be strings.
4880 * commandline : command line string which is passed to the standard shell
4881 * cmdname, arg1, ... : command name and one or more arguments (This form does not use the shell. See below for caveats.)
4882 * [cmdname, argv0], arg1, ... : command name, argv[0] and zero or more arguments (no shell)
4884 * clearing environment variables:
4885 * :unsetenv_others => true : clear environment variables except specified by env
4886 * :unsetenv_others => false : don't clear (default)
4888 * :pgroup => true or 0 : make a new process group
4889 * :pgroup => pgid : join the specified process group
4890 * :pgroup => nil : don't change the process group (default)
4891 * create new process group: Windows only
4892 * :new_pgroup => true : the new process is the root process of a new process group
4893 * :new_pgroup => false : don't create a new process group (default)
4894 * resource limit: resourcename is core, cpu, data, etc. See Process.setrlimit.
4895 * :rlimit_resourcename => limit
4896 * :rlimit_resourcename => [cur_limit, max_limit]
4901 * FD : single file descriptor in child process
4902 * [FD, FD, ...] : multiple file descriptor in child process
4904 * FD : redirect to the file descriptor in parent process
4905 * string : redirect to file with open(string, "r" or "w")
4906 * [string] : redirect to file with open(string, File::RDONLY)
4907 * [string, open_mode] : redirect to file with open(string, open_mode, 0644)
4908 * [string, open_mode, perm] : redirect to file with open(string, open_mode, perm)
4909 * [:child, FD] : redirect to the redirected file descriptor
4910 * :close : close the file descriptor in child process
4911 * FD is one of follows
4912 * :in : the file descriptor 0 which is the standard input
4913 * :out : the file descriptor 1 which is the standard output
4914 * :err : the file descriptor 2 which is the standard error
4915 * integer : the file descriptor of specified the integer
4916 * io : the file descriptor specified as io.fileno
4917 * file descriptor inheritance: close non-redirected non-standard fds (3, 4, 5, ...) or not
4918 * :close_others => false : inherit
4919 * current directory:
4922 * The <code>cmdname, arg1, ...</code> form does not use the shell.
4923 * However, on different OSes, different things are provided as
4924 * built-in commands. An example of this is +'echo'+, which is a
4925 * built-in on Windows, but is a normal program on Linux and Mac OS X.
4926 * This means that <code>Process.spawn 'echo', '%Path%'</code> will
4927 * display the contents of the <tt>%Path%</tt> environment variable
4928 * on Windows, but <code>Process.spawn 'echo', '$PATH'</code> prints
4929 * the literal <tt>$PATH</tt>.
4931 * If a hash is given as +env+, the environment is
4932 * updated by +env+ before <code>exec(2)</code> in the child process.
4933 * If a pair in +env+ has nil as the value, the variable is deleted.
4935 * # set FOO as BAR and unset BAZ.
4936 * pid = spawn({"FOO"=>"BAR", "BAZ"=>nil}, command)
4938 * If a hash is given as +options+,
4941 * create new process group,
4943 * current directory,
4945 * redirects for the child process.
4946 * Also, it can be specified to clear environment variables.
4948 * The <code>:unsetenv_others</code> key in +options+ specifies
4949 * to clear environment variables, other than specified by +env+.
4951 * pid = spawn(command, :unsetenv_others=>true) # no environment variable
4952 * pid = spawn({"FOO"=>"BAR"}, command, :unsetenv_others=>true) # FOO only
4954 * The <code>:pgroup</code> key in +options+ specifies a process group.
4955 * The corresponding value should be true, zero, a positive integer, or nil.
4956 * true and zero cause the process to be a process leader of a new process group.
4957 * A non-zero positive integer causes the process to join the provided process group.
4958 * The default value, nil, causes the process to remain in the same process group.
4960 * pid = spawn(command, :pgroup=>true) # process leader
4961 * pid = spawn(command, :pgroup=>10) # belongs to the process group 10
4963 * The <code>:new_pgroup</code> key in +options+ specifies to pass
4964 * +CREATE_NEW_PROCESS_GROUP+ flag to <code>CreateProcessW()</code> that is
4965 * Windows API. This option is only for Windows.
4966 * true means the new process is the root process of the new process group.
4967 * The new process has CTRL+C disabled. This flag is necessary for
4968 * <code>Process.kill(:SIGINT, pid)</code> on the subprocess.
4969 * :new_pgroup is false by default.
4971 * pid = spawn(command, :new_pgroup=>true) # new process group
4972 * pid = spawn(command, :new_pgroup=>false) # same process group
4974 * The <code>:rlimit_</code><em>foo</em> key specifies a resource limit.
4975 * <em>foo</em> should be one of resource types such as <code>core</code>.
4976 * The corresponding value should be an integer or an array which have one or
4977 * two integers: same as cur_limit and max_limit arguments for
4978 * Process.setrlimit.
4980 * cur, max = Process.getrlimit(:CORE)
4981 * pid = spawn(command, :rlimit_core=>[0,max]) # disable core temporary.
4982 * pid = spawn(command, :rlimit_core=>max) # enable core dump
4983 * pid = spawn(command, :rlimit_core=>0) # never dump core.
4985 * The <code>:umask</code> key in +options+ specifies the umask.
4987 * pid = spawn(command, :umask=>077)
4989 * The :in, :out, :err, an integer, an IO and an array key specifies a redirection.
4990 * The redirection maps a file descriptor in the child process.
4992 * For example, stderr can be merged into stdout as follows:
4994 * pid = spawn(command, :err=>:out)
4995 * pid = spawn(command, 2=>1)
4996 * pid = spawn(command, STDERR=>:out)
4997 * pid = spawn(command, STDERR=>STDOUT)
4999 * The hash keys specifies a file descriptor in the child process
5000 * started by #spawn.
5001 * :err, 2 and STDERR specifies the standard error stream (stderr).
5003 * The hash values specifies a file descriptor in the parent process
5004 * which invokes #spawn.
5005 * :out, 1 and STDOUT specifies the standard output stream (stdout).
5007 * In the above example,
5008 * the standard output in the child process is not specified.
5009 * So it is inherited from the parent process.
5011 * The standard input stream (stdin) can be specified by :in, 0 and STDIN.
5013 * A filename can be specified as a hash value.
5015 * pid = spawn(command, :in=>"/dev/null") # read mode
5016 * pid = spawn(command, :out=>"/dev/null") # write mode
5017 * pid = spawn(command, :err=>"log") # write mode
5018 * pid = spawn(command, [:out, :err]=>"/dev/null") # write mode
5019 * pid = spawn(command, 3=>"/dev/null") # read mode
5021 * For stdout and stderr (and combination of them),
5022 * it is opened in write mode.
5023 * Otherwise read mode is used.
5025 * For specifying flags and permission of file creation explicitly,
5026 * an array is used instead.
5028 * pid = spawn(command, :in=>["file"]) # read mode is assumed
5029 * pid = spawn(command, :in=>["file", "r"])
5030 * pid = spawn(command, :out=>["log", "w"]) # 0644 assumed
5031 * pid = spawn(command, :out=>["log", "w", 0600])
5032 * pid = spawn(command, :out=>["log", File::WRONLY|File::EXCL|File::CREAT, 0600])
5034 * The array specifies a filename, flags and permission.
5035 * The flags can be a string or an integer.
5036 * If the flags is omitted or nil, File::RDONLY is assumed.
5037 * The permission should be an integer.
5038 * If the permission is omitted or nil, 0644 is assumed.
5040 * If an array of IOs and integers are specified as a hash key,
5041 * all the elements are redirected.
5043 * # stdout and stderr is redirected to log file.
5044 * # The file "log" is opened just once.
5045 * pid = spawn(command, [:out, :err]=>["log", "w"])
5047 * Another way to merge multiple file descriptors is [:child, fd].
5048 * \[:child, fd] means the file descriptor in the child process.
5049 * This is different from fd.
5050 * For example, :err=>:out means redirecting child stderr to parent stdout.
5051 * But :err=>[:child, :out] means redirecting child stderr to child stdout.
5052 * They differ if stdout is redirected in the child process as follows.
5054 * # stdout and stderr is redirected to log file.
5055 * # The file "log" is opened just once.
5056 * pid = spawn(command, :out=>["log", "w"], :err=>[:child, :out])
5058 * \[:child, :out] can be used to merge stderr into stdout in IO.popen.
5059 * In this case, IO.popen redirects stdout to a pipe in the child process
5060 * and [:child, :out] refers the redirected stdout.
5062 * io = IO.popen(["sh", "-c", "echo out; echo err >&2", :err=>[:child, :out]])
5063 * p io.read #=> "out\nerr\n"
5065 * The <code>:chdir</code> key in +options+ specifies the current directory.
5067 * pid = spawn(command, :chdir=>"/var/tmp")
5069 * spawn closes all non-standard unspecified descriptors by default.
5070 * The "standard" descriptors are 0, 1 and 2.
5071 * This behavior is specified by :close_others option.
5072 * :close_others doesn't affect the standard descriptors which are
5073 * closed only if :close is specified explicitly.
5075 * pid = spawn(command, :close_others=>true) # close 3,4,5,... (default)
5076 * pid = spawn(command, :close_others=>false) # don't close 3,4,5,...
5078 * :close_others is false by default for spawn and IO.popen.
5080 * Note that fds which close-on-exec flag is already set are closed
5081 * regardless of :close_others option.
5083 * So IO.pipe and spawn can be used as IO.popen.
5085 * # similar to r = IO.popen(command)
5087 * pid = spawn(command, :out=>w) # r, w is closed in the child process.
5090 * :close is specified as a hash value to close a fd individually.
5093 * system(command, f=>:close) # don't inherit f.
5095 * If a file descriptor need to be inherited,
5096 * io=>io can be used.
5098 * # valgrind has --log-fd option for log destination.
5099 * # log_w=>log_w indicates log_w.fileno inherits to child process.
5100 * log_r, log_w = IO.pipe
5101 * pid = spawn("valgrind", "--log-fd=#{log_w.fileno}", "echo", "a", log_w=>log_w)
5105 * It is also possible to exchange file descriptors.
5107 * pid = spawn(command, :out=>:err, :err=>:out)
5109 * The hash keys specify file descriptors in the child process.
5110 * The hash values specifies file descriptors in the parent process.
5111 * So the above specifies exchanging stdout and stderr.
5112 * Internally, +spawn+ uses an extra file descriptor to resolve such cyclic
5113 * file descriptor mapping.
5115 * See Kernel.exec for the standard shell.
5119 rb_f_spawn(int argc
, VALUE
*argv
, VALUE _
)
5122 char errmsg
[CHILD_ERRMSG_BUFLEN
] = { '\0' };
5123 VALUE execarg_obj
, fail_str
;
5124 struct rb_execarg
*eargp
;
5126 execarg_obj
= rb_execarg_new(argc
, argv
, TRUE
, FALSE
);
5127 eargp
= rb_execarg_get(execarg_obj
);
5128 fail_str
= eargp
->use_shell
? eargp
->invoke
.sh
.shell_script
: eargp
->invoke
.cmd
.command_name
;
5130 pid
= rb_execarg_spawn(execarg_obj
, errmsg
, sizeof(errmsg
));
5134 rb_exec_fail(eargp
, err
, errmsg
);
5135 RB_GC_GUARD(execarg_obj
);
5136 rb_syserr_fail_str(err
, fail_str
);
5138 #if defined(HAVE_WORKING_FORK) || defined(HAVE_SPAWNV)
5139 return PIDT2NUM(pid
);
5147 * sleep([duration]) -> integer
5149 * Suspends the current thread for _duration_ seconds (which may be any number,
5150 * including a +Float+ with fractional seconds). Returns the actual number of
5151 * seconds slept (rounded), which may be less than that asked for if another
5152 * thread calls Thread#run. Called without an argument, sleep()
5153 * will sleep forever.
5155 * Time.new #=> 2008-03-08 19:56:19 +0900
5157 * Time.new #=> 2008-03-08 19:56:20 +0900
5159 * Time.new #=> 2008-03-08 19:56:22 +0900
5163 rb_f_sleep(int argc
, VALUE
*argv
, VALUE _
)
5165 time_t beg
= time(0);
5166 VALUE scheduler
= rb_fiber_scheduler_current();
5168 if (scheduler
!= Qnil
) {
5169 rb_fiber_scheduler_kernel_sleepv(scheduler
, argc
, argv
);
5173 rb_thread_sleep_forever();
5176 rb_check_arity(argc
, 0, 1);
5177 rb_thread_wait_for(rb_time_interval(argv
[0]));
5181 time_t end
= time(0) - beg
;
5183 return TIMET2NUM(end
);
5187 #if (defined(HAVE_GETPGRP) && defined(GETPGRP_VOID)) || defined(HAVE_GETPGID)
5190 * Process.getpgrp -> integer
5192 * Returns the process group ID for this process. Not available on
5195 * Process.getpgid(0) #=> 25527
5196 * Process.getpgrp #=> 25527
5200 proc_getpgrp(VALUE _
)
5204 #if defined(HAVE_GETPGRP) && defined(GETPGRP_VOID)
5206 if (pgrp
< 0) rb_sys_fail(0);
5207 return PIDT2NUM(pgrp
);
5208 #else /* defined(HAVE_GETPGID) */
5210 if (pgrp
< 0) rb_sys_fail(0);
5211 return PIDT2NUM(pgrp
);
5215 #define proc_getpgrp rb_f_notimplement
5219 #if defined(HAVE_SETPGID) || (defined(HAVE_SETPGRP) && defined(SETPGRP_VOID))
5222 * Process.setpgrp -> 0
5224 * Equivalent to <code>setpgid(0,0)</code>. Not available on all
5229 proc_setpgrp(VALUE _
)
5231 /* check for posix setpgid() first; this matches the posix */
5232 /* getpgrp() above. It appears that configure will set SETPGRP_VOID */
5233 /* even though setpgrp(0,0) would be preferred. The posix call avoids */
5234 /* this confusion. */
5236 if (setpgid(0,0) < 0) rb_sys_fail(0);
5237 #elif defined(HAVE_SETPGRP) && defined(SETPGRP_VOID)
5238 if (setpgrp() < 0) rb_sys_fail(0);
5243 #define proc_setpgrp rb_f_notimplement
5247 #if defined(HAVE_GETPGID)
5250 * Process.getpgid(pid) -> integer
5252 * Returns the process group ID for the given process id. Not
5253 * available on all platforms.
5255 * Process.getpgid(Process.ppid()) #=> 25527
5259 proc_getpgid(VALUE obj
, VALUE pid
)
5263 i
= getpgid(NUM2PIDT(pid
));
5264 if (i
< 0) rb_sys_fail(0);
5268 #define proc_getpgid rb_f_notimplement
5275 * Process.setpgid(pid, integer) -> 0
5277 * Sets the process group ID of _pid_ (0 indicates this
5278 * process) to <em>integer</em>. Not available on all platforms.
5282 proc_setpgid(VALUE obj
, VALUE pid
, VALUE pgrp
)
5284 rb_pid_t ipid
, ipgrp
;
5286 ipid
= NUM2PIDT(pid
);
5287 ipgrp
= NUM2PIDT(pgrp
);
5289 if (setpgid(ipid
, ipgrp
) < 0) rb_sys_fail(0);
5293 #define proc_setpgid rb_f_notimplement
5300 * Process.getsid() -> integer
5301 * Process.getsid(pid) -> integer
5303 * Returns the session ID for the given process id. If not given,
5304 * return current process sid. Not available on all platforms.
5306 * Process.getsid() #=> 27422
5307 * Process.getsid(0) #=> 27422
5308 * Process.getsid(Process.pid()) #=> 27422
5311 proc_getsid(int argc
, VALUE
*argv
, VALUE _
)
5316 if (rb_check_arity(argc
, 0, 1) == 1 && !NIL_P(argv
[0]))
5317 pid
= NUM2PIDT(argv
[0]);
5320 if (sid
< 0) rb_sys_fail(0);
5321 return PIDT2NUM(sid
);
5324 #define proc_getsid rb_f_notimplement
5328 #if defined(HAVE_SETSID) || (defined(HAVE_SETPGRP) && defined(TIOCNOTTY))
5329 #if !defined(HAVE_SETSID)
5330 static rb_pid_t
ruby_setsid(void);
5331 #define setsid() ruby_setsid()
5335 * Process.setsid -> integer
5337 * Establishes this process as a new session and process group
5338 * leader, with no controlling tty. Returns the session id. Not
5339 * available on all platforms.
5341 * Process.setsid #=> 27422
5345 proc_setsid(VALUE _
)
5350 if (pid
< 0) rb_sys_fail(0);
5351 return PIDT2NUM(pid
);
5354 #if !defined(HAVE_SETSID)
5355 #define HAVE_SETSID 1
5363 #if defined(SETPGRP_VOID)
5365 /* If `pid_t setpgrp(void)' is equivalent to setsid(),
5366 `ret' will be the same value as `pid', and following open() will fail.
5367 In Linux, `int setpgrp(void)' is equivalent to setpgid(0, 0). */
5369 ret
= setpgrp(0, pid
);
5371 if (ret
== -1) return -1;
5373 if ((fd
= rb_cloexec_open("/dev/tty", O_RDWR
, 0)) >= 0) {
5374 rb_update_max_fd(fd
);
5375 ioctl(fd
, TIOCNOTTY
, NULL
);
5382 #define proc_setsid rb_f_notimplement
5386 #ifdef HAVE_GETPRIORITY
5389 * Process.getpriority(kind, integer) -> integer
5391 * Gets the scheduling priority for specified process, process group,
5392 * or user. <em>kind</em> indicates the kind of entity to find: one
5393 * of Process::PRIO_PGRP,
5394 * Process::PRIO_USER, or
5395 * Process::PRIO_PROCESS. _integer_ is an id
5396 * indicating the particular process, process group, or user (an id
5397 * of 0 means _current_). Lower priorities are more favorable
5398 * for scheduling. Not available on all platforms.
5400 * Process.getpriority(Process::PRIO_USER, 0) #=> 19
5401 * Process.getpriority(Process::PRIO_PROCESS, 0) #=> 19
5405 proc_getpriority(VALUE obj
, VALUE which
, VALUE who
)
5407 int prio
, iwhich
, iwho
;
5409 iwhich
= NUM2INT(which
);
5410 iwho
= NUM2INT(who
);
5413 prio
= getpriority(iwhich
, iwho
);
5414 if (errno
) rb_sys_fail(0);
5415 return INT2FIX(prio
);
5418 #define proc_getpriority rb_f_notimplement
5422 #ifdef HAVE_GETPRIORITY
5425 * Process.setpriority(kind, integer, priority) -> 0
5427 * See Process.getpriority.
5429 * Process.setpriority(Process::PRIO_USER, 0, 19) #=> 0
5430 * Process.setpriority(Process::PRIO_PROCESS, 0, 19) #=> 0
5431 * Process.getpriority(Process::PRIO_USER, 0) #=> 19
5432 * Process.getpriority(Process::PRIO_PROCESS, 0) #=> 19
5436 proc_setpriority(VALUE obj
, VALUE which
, VALUE who
, VALUE prio
)
5438 int iwhich
, iwho
, iprio
;
5440 iwhich
= NUM2INT(which
);
5441 iwho
= NUM2INT(who
);
5442 iprio
= NUM2INT(prio
);
5444 if (setpriority(iwhich
, iwho
, iprio
) < 0)
5449 #define proc_setpriority rb_f_notimplement
5452 #if defined(HAVE_SETRLIMIT) && defined(NUM2RLIM)
5454 rlimit_resource_name2int(const char *name
, long len
, int casetype
)
5458 #define RESCHECK(r) \
5460 if (len == rb_strlen_lit(#r) && STRCASECMP(name, #r) == 0) { \
5461 resource = RLIMIT_##r; \
5466 switch (TOUPPER(*name
)) {
5495 #ifdef RLIMIT_MEMLOCK
5498 #ifdef RLIMIT_MSGQUEUE
5504 #ifdef RLIMIT_NOFILE
5519 #ifdef RLIMIT_RTPRIO
5522 #ifdef RLIMIT_RTTIME
5531 #ifdef RLIMIT_SBSIZE
5534 #ifdef RLIMIT_SIGPENDING
5535 RESCHECK(SIGPENDING
);
5544 for (p
= name
; *p
; p
++)
5550 for (p
= name
; *p
; p
++)
5556 rb_bug("unexpected casetype");
5563 rlimit_type_by_hname(const char *name
, long len
)
5565 return rlimit_resource_name2int(name
, len
, 0);
5569 rlimit_type_by_lname(const char *name
, long len
)
5571 return rlimit_resource_name2int(name
, len
, 1);
5575 rlimit_type_by_sym(VALUE key
)
5577 VALUE name
= rb_sym2str(key
);
5578 const char *rname
= RSTRING_PTR(name
);
5579 long len
= RSTRING_LEN(name
);
5581 static const char prefix
[] = "rlimit_";
5582 enum {prefix_len
= sizeof(prefix
)-1};
5584 if (len
> prefix_len
&& strncmp(prefix
, rname
, prefix_len
) == 0) {
5585 rtype
= rlimit_type_by_lname(rname
+ prefix_len
, len
- prefix_len
);
5593 rlimit_resource_type(VALUE rtype
)
5600 switch (TYPE(rtype
)) {
5602 v
= rb_sym2str(rtype
);
5603 name
= RSTRING_PTR(v
);
5604 len
= RSTRING_LEN(v
);
5608 v
= rb_check_string_type(rtype
);
5612 name
= StringValueCStr(rtype
);
5613 len
= RSTRING_LEN(rtype
);
5620 return NUM2INT(rtype
);
5623 r
= rlimit_type_by_hname(name
, len
);
5627 rb_raise(rb_eArgError
, "invalid resource name: % "PRIsVALUE
, rtype
);
5629 UNREACHABLE_RETURN(-1);
5633 rlimit_resource_value(VALUE rval
)
5638 switch (TYPE(rval
)) {
5640 v
= rb_sym2str(rval
);
5641 name
= RSTRING_PTR(v
);
5645 v
= rb_check_string_type(rval
);
5649 name
= StringValueCStr(rval
);
5656 return NUM2RLIM(rval
);
5659 #ifdef RLIM_INFINITY
5660 if (strcmp(name
, "INFINITY") == 0) return RLIM_INFINITY
;
5662 #ifdef RLIM_SAVED_MAX
5663 if (strcmp(name
, "SAVED_MAX") == 0) return RLIM_SAVED_MAX
;
5665 #ifdef RLIM_SAVED_CUR
5666 if (strcmp(name
, "SAVED_CUR") == 0) return RLIM_SAVED_CUR
;
5668 rb_raise(rb_eArgError
, "invalid resource value: %"PRIsVALUE
, rval
);
5670 UNREACHABLE_RETURN((rlim_t
)-1);
5674 #if defined(HAVE_GETRLIMIT) && defined(RLIM2NUM)
5677 * Process.getrlimit(resource) -> [cur_limit, max_limit]
5679 * Gets the resource limit of the process.
5680 * _cur_limit_ means current (soft) limit and
5681 * _max_limit_ means maximum (hard) limit.
5683 * _resource_ indicates the kind of resource to limit.
5684 * It is specified as a symbol such as <code>:CORE</code>,
5685 * a string such as <code>"CORE"</code> or
5686 * a constant such as Process::RLIMIT_CORE.
5687 * See Process.setrlimit for details.
5689 * _cur_limit_ and _max_limit_ may be Process::RLIM_INFINITY,
5690 * Process::RLIM_SAVED_MAX or
5691 * Process::RLIM_SAVED_CUR.
5692 * See Process.setrlimit and the system getrlimit(2) manual for details.
5696 proc_getrlimit(VALUE obj
, VALUE resource
)
5700 if (getrlimit(rlimit_resource_type(resource
), &rlim
) < 0) {
5701 rb_sys_fail("getrlimit");
5703 return rb_assoc_new(RLIM2NUM(rlim
.rlim_cur
), RLIM2NUM(rlim
.rlim_max
));
5706 #define proc_getrlimit rb_f_notimplement
5709 #if defined(HAVE_SETRLIMIT) && defined(NUM2RLIM)
5712 * Process.setrlimit(resource, cur_limit, max_limit) -> nil
5713 * Process.setrlimit(resource, cur_limit) -> nil
5715 * Sets the resource limit of the process.
5716 * _cur_limit_ means current (soft) limit and
5717 * _max_limit_ means maximum (hard) limit.
5719 * If _max_limit_ is not given, _cur_limit_ is used.
5721 * _resource_ indicates the kind of resource to limit.
5722 * It should be a symbol such as <code>:CORE</code>,
5723 * a string such as <code>"CORE"</code> or
5724 * a constant such as Process::RLIMIT_CORE.
5725 * The available resources are OS dependent.
5726 * Ruby may support following resources.
5728 * [AS] total available memory (bytes) (SUSv3, NetBSD, FreeBSD, OpenBSD but 4.4BSD-Lite)
5729 * [CORE] core size (bytes) (SUSv3)
5730 * [CPU] CPU time (seconds) (SUSv3)
5731 * [DATA] data segment (bytes) (SUSv3)
5732 * [FSIZE] file size (bytes) (SUSv3)
5733 * [MEMLOCK] total size for mlock(2) (bytes) (4.4BSD, GNU/Linux)
5734 * [MSGQUEUE] allocation for POSIX message queues (bytes) (GNU/Linux)
5735 * [NICE] ceiling on process's nice(2) value (number) (GNU/Linux)
5736 * [NOFILE] file descriptors (number) (SUSv3)
5737 * [NPROC] number of processes for the user (number) (4.4BSD, GNU/Linux)
5738 * [RSS] resident memory size (bytes) (4.2BSD, GNU/Linux)
5739 * [RTPRIO] ceiling on the process's real-time priority (number) (GNU/Linux)
5740 * [RTTIME] CPU time for real-time process (us) (GNU/Linux)
5741 * [SBSIZE] all socket buffers (bytes) (NetBSD, FreeBSD)
5742 * [SIGPENDING] number of queued signals allowed (signals) (GNU/Linux)
5743 * [STACK] stack size (bytes) (SUSv3)
5745 * _cur_limit_ and _max_limit_ may be
5746 * <code>:INFINITY</code>, <code>"INFINITY"</code> or
5747 * Process::RLIM_INFINITY,
5748 * which means that the resource is not limited.
5749 * They may be Process::RLIM_SAVED_MAX,
5750 * Process::RLIM_SAVED_CUR and
5751 * corresponding symbols and strings too.
5752 * See system setrlimit(2) manual for details.
5754 * The following example raises the soft limit of core size to
5755 * the hard limit to try to make core dump possible.
5757 * Process.setrlimit(:CORE, Process.getrlimit(:CORE)[1])
5762 proc_setrlimit(int argc
, VALUE
*argv
, VALUE obj
)
5764 VALUE resource
, rlim_cur
, rlim_max
;
5767 rb_check_arity(argc
, 2, 3);
5770 if (argc
< 3 || NIL_P(rlim_max
= argv
[2]))
5771 rlim_max
= rlim_cur
;
5773 rlim
.rlim_cur
= rlimit_resource_value(rlim_cur
);
5774 rlim
.rlim_max
= rlimit_resource_value(rlim_max
);
5776 if (setrlimit(rlimit_resource_type(resource
), &rlim
) < 0) {
5777 rb_sys_fail("setrlimit");
5782 #define proc_setrlimit rb_f_notimplement
5785 static int under_uid_switch
= 0;
5787 check_uid_switch(void)
5789 if (under_uid_switch
) {
5790 rb_raise(rb_eRuntimeError
, "can't handle UID while evaluating block given to Process::UID.switch method");
5794 static int under_gid_switch
= 0;
5796 check_gid_switch(void)
5798 if (under_gid_switch
) {
5799 rb_raise(rb_eRuntimeError
, "can't handle GID while evaluating block given to Process::UID.switch method");
5804 #if defined(HAVE_PWD_H)
5806 * Best-effort attempt to obtain the name of the login user, if any,
5807 * associated with the process. Processes not descended from login(1) (or
5808 * similar) may not have a logged-in user; returns Qnil in that case.
5813 #if ( !defined(USE_GETLOGIN_R) && !defined(USE_GETLOGIN) )
5816 char MAYBE_UNUSED(*login
) = NULL
;
5818 # ifdef USE_GETLOGIN_R
5820 #if defined(__FreeBSD__)
5821 typedef int getlogin_r_size_t
;
5823 typedef size_t getlogin_r_size_t
;
5826 long loginsize
= GETLOGIN_R_SIZE_INIT
; /* maybe -1 */
5829 loginsize
= GETLOGIN_R_SIZE_DEFAULT
;
5831 VALUE maybe_result
= rb_str_buf_new(loginsize
);
5833 login
= RSTRING_PTR(maybe_result
);
5834 loginsize
= rb_str_capacity(maybe_result
);
5835 rb_str_set_len(maybe_result
, loginsize
);
5839 while ((gle
= getlogin_r(login
, (getlogin_r_size_t
)loginsize
)) != 0) {
5841 if (gle
== ENOTTY
|| gle
== ENXIO
|| gle
== ENOENT
) {
5842 rb_str_resize(maybe_result
, 0);
5846 if (gle
!= ERANGE
|| loginsize
>= GETLOGIN_R_SIZE_LIMIT
) {
5847 rb_str_resize(maybe_result
, 0);
5848 rb_syserr_fail(gle
, "getlogin_r");
5851 rb_str_modify_expand(maybe_result
, loginsize
);
5852 login
= RSTRING_PTR(maybe_result
);
5853 loginsize
= rb_str_capacity(maybe_result
);
5856 if (login
== NULL
) {
5857 rb_str_resize(maybe_result
, 0);
5861 return maybe_result
;
5868 if (errno
== ENOTTY
|| errno
== ENXIO
|| errno
== ENOENT
) {
5871 rb_syserr_fail(errno
, "getlogin");
5874 return login
? rb_str_new_cstr(login
) : Qnil
;
5881 rb_getpwdirnam_for_login(VALUE login_name
)
5883 #if ( !defined(USE_GETPWNAM_R) && !defined(USE_GETPWNAM) )
5887 if (NIL_P(login_name
)) {
5888 /* nothing to do; no name with which to query the password database */
5892 char *login
= RSTRING_PTR(login_name
);
5894 struct passwd
*pwptr
;
5896 # ifdef USE_GETPWNAM_R
5898 struct passwd pwdnm
;
5900 long bufsizenm
= GETPW_R_SIZE_INIT
; /* maybe -1 */
5903 bufsizenm
= GETPW_R_SIZE_DEFAULT
;
5905 VALUE getpwnm_tmp
= rb_str_tmp_new(bufsizenm
);
5907 bufnm
= RSTRING_PTR(getpwnm_tmp
);
5908 bufsizenm
= rb_str_capacity(getpwnm_tmp
);
5909 rb_str_set_len(getpwnm_tmp
, bufsizenm
);
5913 while ((enm
= getpwnam_r(login
, &pwdnm
, bufnm
, bufsizenm
, &pwptr
)) != 0) {
5915 if (enm
== ENOENT
|| enm
== ESRCH
|| enm
== EBADF
|| enm
== EPERM
) {
5916 /* not found; non-errors */
5917 rb_str_resize(getpwnm_tmp
, 0);
5921 if (enm
!= ERANGE
|| bufsizenm
>= GETPW_R_SIZE_LIMIT
) {
5922 rb_str_resize(getpwnm_tmp
, 0);
5923 rb_syserr_fail(enm
, "getpwnam_r");
5926 rb_str_modify_expand(getpwnm_tmp
, bufsizenm
);
5927 bufnm
= RSTRING_PTR(getpwnm_tmp
);
5928 bufsizenm
= rb_str_capacity(getpwnm_tmp
);
5931 if (pwptr
== NULL
) {
5932 /* no record in the password database for the login name */
5933 rb_str_resize(getpwnm_tmp
, 0);
5938 VALUE result
= rb_str_new_cstr(pwptr
->pw_dir
);
5939 rb_str_resize(getpwnm_tmp
, 0);
5945 pwptr
= getpwnam(login
);
5948 return rb_str_new_cstr(pwptr
->pw_dir
);
5951 /* avoid treating as errors errno values that indicate "not found" */
5952 && ( errno
!= ENOENT
&& errno
!= ESRCH
&& errno
!= EBADF
&& errno
!= EPERM
)) {
5953 rb_syserr_fail(errno
, "getpwnam");
5956 return Qnil
; /* not found */
5963 * Look up the user's dflt home dir in the password db, by uid.
5966 rb_getpwdiruid(void)
5968 # if !defined(USE_GETPWUID_R) && !defined(USE_GETPWUID)
5969 /* Should never happen... </famous-last-words> */
5972 uid_t ruid
= getuid();
5974 struct passwd
*pwptr
;
5976 # ifdef USE_GETPWUID_R
5978 struct passwd pwdid
;
5980 long bufsizeid
= GETPW_R_SIZE_INIT
; /* maybe -1 */
5983 bufsizeid
= GETPW_R_SIZE_DEFAULT
;
5985 VALUE getpwid_tmp
= rb_str_tmp_new(bufsizeid
);
5987 bufid
= RSTRING_PTR(getpwid_tmp
);
5988 bufsizeid
= rb_str_capacity(getpwid_tmp
);
5989 rb_str_set_len(getpwid_tmp
, bufsizeid
);
5993 while ((eid
= getpwuid_r(ruid
, &pwdid
, bufid
, bufsizeid
, &pwptr
)) != 0) {
5995 if (eid
== ENOENT
|| eid
== ESRCH
|| eid
== EBADF
|| eid
== EPERM
) {
5996 /* not found; non-errors */
5997 rb_str_resize(getpwid_tmp
, 0);
6001 if (eid
!= ERANGE
|| bufsizeid
>= GETPW_R_SIZE_LIMIT
) {
6002 rb_str_resize(getpwid_tmp
, 0);
6003 rb_syserr_fail(eid
, "getpwuid_r");
6006 rb_str_modify_expand(getpwid_tmp
, bufsizeid
);
6007 bufid
= RSTRING_PTR(getpwid_tmp
);
6008 bufsizeid
= rb_str_capacity(getpwid_tmp
);
6011 if (pwptr
== NULL
) {
6012 /* no record in the password database for the uid */
6013 rb_str_resize(getpwid_tmp
, 0);
6018 VALUE result
= rb_str_new_cstr(pwptr
->pw_dir
);
6019 rb_str_resize(getpwid_tmp
, 0);
6022 # elif defined(USE_GETPWUID)
6025 pwptr
= getpwuid(ruid
);
6028 return rb_str_new_cstr(pwptr
->pw_dir
);
6031 /* avoid treating as errors errno values that indicate "not found" */
6032 && ( errno
== ENOENT
|| errno
== ESRCH
|| errno
== EBADF
|| errno
== EPERM
)) {
6033 rb_syserr_fail(errno
, "getpwuid");
6036 return Qnil
; /* not found */
6039 #endif /* !defined(USE_GETPWUID_R) && !defined(USE_GETPWUID) */
6041 #endif /* HAVE_PWD_H */
6044 /*********************************************************************
6045 * Document-class: Process::Sys
6047 * The Process::Sys module contains UID and GID
6048 * functions which provide direct bindings to the system calls of the
6049 * same names instead of the more-portable versions of the same
6050 * functionality found in the Process,
6051 * Process::UID, and Process::GID modules.
6054 #if defined(HAVE_PWD_H)
6057 # ifdef USE_GETPWNAM_R
6065 if (FIXNUM_P(id
) || NIL_P(tmp
= rb_check_string_type(id
))) {
6069 const char *usrname
= StringValueCStr(id
);
6070 struct passwd
*pwptr
;
6071 #ifdef USE_GETPWNAM_R
6072 struct passwd pwbuf
;
6077 getpw_buf_len
= GETPW_R_SIZE_INIT
;
6078 if (getpw_buf_len
< 0) getpw_buf_len
= GETPW_R_SIZE_DEFAULT
;
6079 *getpw_tmp
= rb_str_tmp_new(getpw_buf_len
);
6081 getpw_buf
= RSTRING_PTR(*getpw_tmp
);
6082 getpw_buf_len
= rb_str_capacity(*getpw_tmp
);
6083 rb_str_set_len(*getpw_tmp
, getpw_buf_len
);
6085 while ((e
= getpwnam_r(usrname
, &pwbuf
, getpw_buf
, getpw_buf_len
, &pwptr
)) != 0) {
6086 if (e
!= ERANGE
|| getpw_buf_len
>= GETPW_R_SIZE_LIMIT
) {
6087 rb_str_resize(*getpw_tmp
, 0);
6088 rb_syserr_fail(e
, "getpwnam_r");
6090 rb_str_modify_expand(*getpw_tmp
, getpw_buf_len
);
6091 getpw_buf
= RSTRING_PTR(*getpw_tmp
);
6092 getpw_buf_len
= rb_str_capacity(*getpw_tmp
);
6095 pwptr
= getpwnam(usrname
);
6098 #ifndef USE_GETPWNAM_R
6101 rb_raise(rb_eArgError
, "can't find user for %"PRIsVALUE
, id
);
6103 uid
= pwptr
->pw_uid
;
6104 #ifndef USE_GETPWNAM_R
6111 # ifdef p_uid_from_name
6114 * Process::UID.from_name(name) -> uid
6116 * Get the user ID by the _name_.
6117 * If the user is not found, +ArgumentError+ will be raised.
6119 * Process::UID.from_name("root") #=> 0
6120 * Process::UID.from_name("nosuchuser") #=> can't find user for nosuchuser (ArgumentError)
6124 p_uid_from_name(VALUE self
, VALUE id
)
6126 return UIDT2NUM(OBJ2UID(id
));
6131 #if defined(HAVE_GRP_H)
6134 # ifdef USE_GETGRNAM_R
6142 if (FIXNUM_P(id
) || NIL_P(tmp
= rb_check_string_type(id
))) {
6146 const char *grpname
= StringValueCStr(id
);
6147 struct group
*grptr
;
6148 #ifdef USE_GETGRNAM_R
6154 getgr_buf_len
= GETGR_R_SIZE_INIT
;
6155 if (getgr_buf_len
< 0) getgr_buf_len
= GETGR_R_SIZE_DEFAULT
;
6156 *getgr_tmp
= rb_str_tmp_new(getgr_buf_len
);
6158 getgr_buf
= RSTRING_PTR(*getgr_tmp
);
6159 getgr_buf_len
= rb_str_capacity(*getgr_tmp
);
6160 rb_str_set_len(*getgr_tmp
, getgr_buf_len
);
6162 while ((e
= getgrnam_r(grpname
, &grbuf
, getgr_buf
, getgr_buf_len
, &grptr
)) != 0) {
6163 if (e
!= ERANGE
|| getgr_buf_len
>= GETGR_R_SIZE_LIMIT
) {
6164 rb_str_resize(*getgr_tmp
, 0);
6165 rb_syserr_fail(e
, "getgrnam_r");
6167 rb_str_modify_expand(*getgr_tmp
, getgr_buf_len
);
6168 getgr_buf
= RSTRING_PTR(*getgr_tmp
);
6169 getgr_buf_len
= rb_str_capacity(*getgr_tmp
);
6171 #elif defined(HAVE_GETGRNAM)
6172 grptr
= getgrnam(grpname
);
6177 #if !defined(USE_GETGRNAM_R) && defined(HAVE_ENDGRENT)
6180 rb_raise(rb_eArgError
, "can't find group for %"PRIsVALUE
, id
);
6182 gid
= grptr
->gr_gid
;
6183 #if !defined(USE_GETGRNAM_R) && defined(HAVE_ENDGRENT)
6190 # ifdef p_gid_from_name
6193 * Process::GID.from_name(name) -> gid
6195 * Get the group ID by the _name_.
6196 * If the group is not found, +ArgumentError+ will be raised.
6198 * Process::GID.from_name("wheel") #=> 0
6199 * Process::GID.from_name("nosuchgroup") #=> can't find group for nosuchgroup (ArgumentError)
6203 p_gid_from_name(VALUE self
, VALUE id
)
6205 return GIDT2NUM(OBJ2GID(id
));
6210 #if defined HAVE_SETUID
6213 * Process::Sys.setuid(user) -> nil
6215 * Set the user ID of the current process to _user_. Not
6216 * available on all platforms.
6221 p_sys_setuid(VALUE obj
, VALUE id
)
6224 if (setuid(OBJ2UID(id
)) != 0) rb_sys_fail(0);
6228 #define p_sys_setuid rb_f_notimplement
6232 #if defined HAVE_SETRUID
6235 * Process::Sys.setruid(user) -> nil
6237 * Set the real user ID of the calling process to _user_.
6238 * Not available on all platforms.
6243 p_sys_setruid(VALUE obj
, VALUE id
)
6246 if (setruid(OBJ2UID(id
)) != 0) rb_sys_fail(0);
6250 #define p_sys_setruid rb_f_notimplement
6254 #if defined HAVE_SETEUID
6257 * Process::Sys.seteuid(user) -> nil
6259 * Set the effective user ID of the calling process to
6260 * _user_. Not available on all platforms.
6265 p_sys_seteuid(VALUE obj
, VALUE id
)
6268 if (seteuid(OBJ2UID(id
)) != 0) rb_sys_fail(0);
6272 #define p_sys_seteuid rb_f_notimplement
6276 #if defined HAVE_SETREUID
6279 * Process::Sys.setreuid(rid, eid) -> nil
6281 * Sets the (user) real and/or effective user IDs of the current
6282 * process to _rid_ and _eid_, respectively. A value of
6283 * <code>-1</code> for either means to leave that ID unchanged. Not
6284 * available on all platforms.
6289 p_sys_setreuid(VALUE obj
, VALUE rid
, VALUE eid
)
6291 rb_uid_t ruid
, euid
;
6294 ruid
= OBJ2UID1(rid
);
6295 euid
= OBJ2UID1(eid
);
6297 if (setreuid(ruid
, euid
) != 0) rb_sys_fail(0);
6301 #define p_sys_setreuid rb_f_notimplement
6305 #if defined HAVE_SETRESUID
6308 * Process::Sys.setresuid(rid, eid, sid) -> nil
6310 * Sets the (user) real, effective, and saved user IDs of the
6311 * current process to _rid_, _eid_, and _sid_ respectively. A
6312 * value of <code>-1</code> for any value means to
6313 * leave that ID unchanged. Not available on all platforms.
6318 p_sys_setresuid(VALUE obj
, VALUE rid
, VALUE eid
, VALUE sid
)
6320 rb_uid_t ruid
, euid
, suid
;
6323 ruid
= OBJ2UID1(rid
);
6324 euid
= OBJ2UID1(eid
);
6325 suid
= OBJ2UID1(sid
);
6327 if (setresuid(ruid
, euid
, suid
) != 0) rb_sys_fail(0);
6331 #define p_sys_setresuid rb_f_notimplement
6337 * Process.uid -> integer
6338 * Process::UID.rid -> integer
6339 * Process::Sys.getuid -> integer
6341 * Returns the (real) user ID of this process.
6343 * Process.uid #=> 501
6347 proc_getuid(VALUE obj
)
6349 rb_uid_t uid
= getuid();
6350 return UIDT2NUM(uid
);
6354 #if defined(HAVE_SETRESUID) || defined(HAVE_SETREUID) || defined(HAVE_SETRUID) || defined(HAVE_SETUID)
6357 * Process.uid= user -> numeric
6359 * Sets the (user) user ID for this process. Not available on all
6364 proc_setuid(VALUE obj
, VALUE id
)
6371 #if defined(HAVE_SETRESUID)
6372 if (setresuid(uid
, -1, -1) < 0) rb_sys_fail(0);
6373 #elif defined HAVE_SETREUID
6374 if (setreuid(uid
, -1) < 0) rb_sys_fail(0);
6375 #elif defined HAVE_SETRUID
6376 if (setruid(uid
) < 0) rb_sys_fail(0);
6377 #elif defined HAVE_SETUID
6379 if (geteuid() == uid
) {
6380 if (setuid(uid
) < 0) rb_sys_fail(0);
6390 #define proc_setuid rb_f_notimplement
6394 /********************************************************************
6396 * Document-class: Process::UID
6398 * The Process::UID module contains a collection of
6399 * module functions which can be used to portably get, set, and
6400 * switch the current process's real, effective, and saved user IDs.
6404 static rb_uid_t SAVED_USER_ID
= -1;
6406 #ifdef BROKEN_SETREUID
6408 setreuid(rb_uid_t ruid
, rb_uid_t euid
)
6410 if (ruid
!= (rb_uid_t
)-1 && ruid
!= getuid()) {
6411 if (euid
== (rb_uid_t
)-1) euid
= geteuid();
6412 if (setuid(ruid
) < 0) return -1;
6414 if (euid
!= (rb_uid_t
)-1 && euid
!= geteuid()) {
6415 if (seteuid(euid
) < 0) return -1;
6423 * Process::UID.change_privilege(user) -> integer
6425 * Change the current process's real and effective user ID to that
6426 * specified by _user_. Returns the new user ID. Not
6427 * available on all platforms.
6429 * [Process.uid, Process.euid] #=> [0, 0]
6430 * Process::UID.change_privilege(31) #=> 31
6431 * [Process.uid, Process.euid] #=> [31, 31]
6435 p_uid_change_privilege(VALUE obj
, VALUE id
)
6443 if (geteuid() == 0) { /* root-user */
6444 #if defined(HAVE_SETRESUID)
6445 if (setresuid(uid
, uid
, uid
) < 0) rb_sys_fail(0);
6446 SAVED_USER_ID
= uid
;
6447 #elif defined(HAVE_SETUID)
6448 if (setuid(uid
) < 0) rb_sys_fail(0);
6449 SAVED_USER_ID
= uid
;
6450 #elif defined(HAVE_SETREUID) && !defined(OBSOLETE_SETREUID)
6451 if (getuid() == uid
) {
6452 if (SAVED_USER_ID
== uid
) {
6453 if (setreuid(-1, uid
) < 0) rb_sys_fail(0);
6456 if (uid
== 0) { /* (r,e,s) == (root, root, x) */
6457 if (setreuid(-1, SAVED_USER_ID
) < 0) rb_sys_fail(0);
6458 if (setreuid(SAVED_USER_ID
, 0) < 0) rb_sys_fail(0);
6459 SAVED_USER_ID
= 0; /* (r,e,s) == (x, root, root) */
6460 if (setreuid(uid
, uid
) < 0) rb_sys_fail(0);
6461 SAVED_USER_ID
= uid
;
6464 if (setreuid(0, -1) < 0) rb_sys_fail(0);
6466 if (setreuid(uid
, uid
) < 0) rb_sys_fail(0);
6467 SAVED_USER_ID
= uid
;
6472 if (setreuid(uid
, uid
) < 0) rb_sys_fail(0);
6473 SAVED_USER_ID
= uid
;
6475 #elif defined(HAVE_SETRUID) && defined(HAVE_SETEUID)
6476 if (getuid() == uid
) {
6477 if (SAVED_USER_ID
== uid
) {
6478 if (seteuid(uid
) < 0) rb_sys_fail(0);
6482 if (setruid(SAVED_USER_ID
) < 0) rb_sys_fail(0);
6484 if (setruid(0) < 0) rb_sys_fail(0);
6487 if (setruid(0) < 0) rb_sys_fail(0);
6489 if (seteuid(uid
) < 0) rb_sys_fail(0);
6490 if (setruid(uid
) < 0) rb_sys_fail(0);
6491 SAVED_USER_ID
= uid
;
6496 if (seteuid(uid
) < 0) rb_sys_fail(0);
6497 if (setruid(uid
) < 0) rb_sys_fail(0);
6498 SAVED_USER_ID
= uid
;
6505 else { /* unprivileged user */
6506 #if defined(HAVE_SETRESUID)
6507 if (setresuid((getuid() == uid
)? (rb_uid_t
)-1: uid
,
6508 (geteuid() == uid
)? (rb_uid_t
)-1: uid
,
6509 (SAVED_USER_ID
== uid
)? (rb_uid_t
)-1: uid
) < 0) rb_sys_fail(0);
6510 SAVED_USER_ID
= uid
;
6511 #elif defined(HAVE_SETREUID) && !defined(OBSOLETE_SETREUID)
6512 if (SAVED_USER_ID
== uid
) {
6513 if (setreuid((getuid() == uid
)? (rb_uid_t
)-1: uid
,
6514 (geteuid() == uid
)? (rb_uid_t
)-1: uid
) < 0)
6517 else if (getuid() != uid
) {
6518 if (setreuid(uid
, (geteuid() == uid
)? (rb_uid_t
)-1: uid
) < 0)
6520 SAVED_USER_ID
= uid
;
6522 else if (/* getuid() == uid && */ geteuid() != uid
) {
6523 if (setreuid(geteuid(), uid
) < 0) rb_sys_fail(0);
6524 SAVED_USER_ID
= uid
;
6525 if (setreuid(uid
, -1) < 0) rb_sys_fail(0);
6527 else { /* getuid() == uid && geteuid() == uid */
6528 if (setreuid(-1, SAVED_USER_ID
) < 0) rb_sys_fail(0);
6529 if (setreuid(SAVED_USER_ID
, uid
) < 0) rb_sys_fail(0);
6530 SAVED_USER_ID
= uid
;
6531 if (setreuid(uid
, -1) < 0) rb_sys_fail(0);
6533 #elif defined(HAVE_SETRUID) && defined(HAVE_SETEUID)
6534 if (SAVED_USER_ID
== uid
) {
6535 if (geteuid() != uid
&& seteuid(uid
) < 0) rb_sys_fail(0);
6536 if (getuid() != uid
&& setruid(uid
) < 0) rb_sys_fail(0);
6538 else if (/* SAVED_USER_ID != uid && */ geteuid() == uid
) {
6539 if (getuid() != uid
) {
6540 if (setruid(uid
) < 0) rb_sys_fail(0);
6541 SAVED_USER_ID
= uid
;
6544 if (setruid(SAVED_USER_ID
) < 0) rb_sys_fail(0);
6545 SAVED_USER_ID
= uid
;
6546 if (setruid(uid
) < 0) rb_sys_fail(0);
6549 else if (/* geteuid() != uid && */ getuid() == uid
) {
6550 if (seteuid(uid
) < 0) rb_sys_fail(0);
6551 if (setruid(SAVED_USER_ID
) < 0) rb_sys_fail(0);
6552 SAVED_USER_ID
= uid
;
6553 if (setruid(uid
) < 0) rb_sys_fail(0);
6556 rb_syserr_fail(EPERM
, 0);
6558 #elif defined HAVE_44BSD_SETUID
6559 if (getuid() == uid
) {
6560 /* (r,e,s)==(uid,?,?) ==> (uid,uid,uid) */
6561 if (setuid(uid
) < 0) rb_sys_fail(0);
6562 SAVED_USER_ID
= uid
;
6565 rb_syserr_fail(EPERM
, 0);
6567 #elif defined HAVE_SETEUID
6568 if (getuid() == uid
&& SAVED_USER_ID
== uid
) {
6569 if (seteuid(uid
) < 0) rb_sys_fail(0);
6572 rb_syserr_fail(EPERM
, 0);
6574 #elif defined HAVE_SETUID
6575 if (getuid() == uid
&& SAVED_USER_ID
== uid
) {
6576 if (setuid(uid
) < 0) rb_sys_fail(0);
6579 rb_syserr_fail(EPERM
, 0);
6590 #if defined HAVE_SETGID
6593 * Process::Sys.setgid(group) -> nil
6595 * Set the group ID of the current process to _group_. Not
6596 * available on all platforms.
6601 p_sys_setgid(VALUE obj
, VALUE id
)
6604 if (setgid(OBJ2GID(id
)) != 0) rb_sys_fail(0);
6608 #define p_sys_setgid rb_f_notimplement
6612 #if defined HAVE_SETRGID
6615 * Process::Sys.setrgid(group) -> nil
6617 * Set the real group ID of the calling process to _group_.
6618 * Not available on all platforms.
6623 p_sys_setrgid(VALUE obj
, VALUE id
)
6626 if (setrgid(OBJ2GID(id
)) != 0) rb_sys_fail(0);
6630 #define p_sys_setrgid rb_f_notimplement
6634 #if defined HAVE_SETEGID
6637 * Process::Sys.setegid(group) -> nil
6639 * Set the effective group ID of the calling process to
6640 * _group_. Not available on all platforms.
6645 p_sys_setegid(VALUE obj
, VALUE id
)
6648 if (setegid(OBJ2GID(id
)) != 0) rb_sys_fail(0);
6652 #define p_sys_setegid rb_f_notimplement
6656 #if defined HAVE_SETREGID
6659 * Process::Sys.setregid(rid, eid) -> nil
6661 * Sets the (group) real and/or effective group IDs of the current
6662 * process to <em>rid</em> and <em>eid</em>, respectively. A value of
6663 * <code>-1</code> for either means to leave that ID unchanged. Not
6664 * available on all platforms.
6669 p_sys_setregid(VALUE obj
, VALUE rid
, VALUE eid
)
6671 rb_gid_t rgid
, egid
;
6673 rgid
= OBJ2GID(rid
);
6674 egid
= OBJ2GID(eid
);
6675 if (setregid(rgid
, egid
) != 0) rb_sys_fail(0);
6679 #define p_sys_setregid rb_f_notimplement
6682 #if defined HAVE_SETRESGID
6685 * Process::Sys.setresgid(rid, eid, sid) -> nil
6687 * Sets the (group) real, effective, and saved user IDs of the
6688 * current process to <em>rid</em>, <em>eid</em>, and <em>sid</em>
6689 * respectively. A value of <code>-1</code> for any value means to
6690 * leave that ID unchanged. Not available on all platforms.
6695 p_sys_setresgid(VALUE obj
, VALUE rid
, VALUE eid
, VALUE sid
)
6697 rb_gid_t rgid
, egid
, sgid
;
6699 rgid
= OBJ2GID(rid
);
6700 egid
= OBJ2GID(eid
);
6701 sgid
= OBJ2GID(sid
);
6702 if (setresgid(rgid
, egid
, sgid
) != 0) rb_sys_fail(0);
6706 #define p_sys_setresgid rb_f_notimplement
6710 #if defined HAVE_ISSETUGID
6713 * Process::Sys.issetugid -> true or false
6715 * Returns +true+ if the process was created as a result
6716 * of an execve(2) system call which had either of the setuid or
6717 * setgid bits set (and extra privileges were given as a result) or
6718 * if it has changed any of its real, effective or saved user or
6719 * group IDs since it began execution.
6724 p_sys_issetugid(VALUE obj
)
6734 #define p_sys_issetugid rb_f_notimplement
6740 * Process.gid -> integer
6741 * Process::GID.rid -> integer
6742 * Process::Sys.getgid -> integer
6744 * Returns the (real) group ID for this process.
6746 * Process.gid #=> 500
6750 proc_getgid(VALUE obj
)
6752 rb_gid_t gid
= getgid();
6753 return GIDT2NUM(gid
);
6757 #if defined(HAVE_SETRESGID) || defined(HAVE_SETREGID) || defined(HAVE_SETRGID) || defined(HAVE_SETGID)
6760 * Process.gid= integer -> integer
6762 * Sets the group ID for this process.
6766 proc_setgid(VALUE obj
, VALUE id
)
6773 #if defined(HAVE_SETRESGID)
6774 if (setresgid(gid
, -1, -1) < 0) rb_sys_fail(0);
6775 #elif defined HAVE_SETREGID
6776 if (setregid(gid
, -1) < 0) rb_sys_fail(0);
6777 #elif defined HAVE_SETRGID
6778 if (setrgid(gid
) < 0) rb_sys_fail(0);
6779 #elif defined HAVE_SETGID
6781 if (getegid() == gid
) {
6782 if (setgid(gid
) < 0) rb_sys_fail(0);
6789 return GIDT2NUM(gid
);
6792 #define proc_setgid rb_f_notimplement
6796 #if defined(_SC_NGROUPS_MAX) || defined(NGROUPS_MAX)
6798 * Maximum supplementary groups are platform dependent.
6799 * FWIW, 65536 is enough big for our supported OSs.
6801 * OS Name max groups
6802 * -----------------------------------------------
6803 * Linux Kernel >= 2.6.3 65536
6804 * Linux Kernel < 2.6.3 32
6806 * IBM AIX 5.3 ... 6.1 128
6807 * IBM AIX 7.1 128 (can be configured to be up to 2048)
6808 * OpenBSD, NetBSD 16
6810 * FreeBSD >=8.0 1023
6811 * Darwin (Mac OS X) 16
6812 * Sun Solaris 7,8,9,10 16
6813 * Sun Solaris 11 / OpenSolaris 1024
6817 static int _maxgroups
= -1;
6819 get_sc_ngroups_max(void)
6821 #ifdef _SC_NGROUPS_MAX
6822 return (int)sysconf(_SC_NGROUPS_MAX
);
6823 #elif defined(NGROUPS_MAX)
6824 return (int)NGROUPS_MAX
;
6832 if (_maxgroups
< 0) {
6833 _maxgroups
= get_sc_ngroups_max();
6835 _maxgroups
= RB_MAX_GROUPS
;
6844 #ifdef HAVE_GETGROUPS
6847 * Process.groups -> array
6849 * Get an Array of the group IDs in the
6850 * supplemental group access list for this process.
6852 * Process.groups #=> [27, 6, 10, 11]
6854 * Note that this method is just a wrapper of getgroups(2).
6855 * This means that the following characteristics of
6856 * the result completely depend on your system:
6858 * - the result is sorted
6859 * - the result includes effective GIDs
6860 * - the result does not include duplicated GIDs
6862 * You can make sure to get a sorted unique GID list of
6863 * the current process by this expression:
6865 * Process.groups.uniq.sort
6870 proc_getgroups(VALUE obj
)
6876 ngroups
= getgroups(0, NULL
);
6880 groups
= ALLOCV_N(rb_gid_t
, tmp
, ngroups
);
6882 ngroups
= getgroups(ngroups
, groups
);
6887 for (i
= 0; i
< ngroups
; i
++)
6888 rb_ary_push(ary
, GIDT2NUM(groups
[i
]));
6895 #define proc_getgroups rb_f_notimplement
6899 #ifdef HAVE_SETGROUPS
6902 * Process.groups= array -> array
6904 * Set the supplemental group access list to the given
6905 * Array of group IDs.
6907 * Process.groups #=> [0, 1, 2, 3, 4, 6, 10, 11, 20, 26, 27]
6908 * Process.groups = [27, 6, 10, 11] #=> [27, 6, 10, 11]
6909 * Process.groups #=> [27, 6, 10, 11]
6914 proc_setgroups(VALUE obj
, VALUE ary
)
6921 Check_Type(ary
, T_ARRAY
);
6923 ngroups
= RARRAY_LENINT(ary
);
6924 if (ngroups
> maxgroups())
6925 rb_raise(rb_eArgError
, "too many groups, %d max", maxgroups());
6927 groups
= ALLOCV_N(rb_gid_t
, tmp
, ngroups
);
6929 for (i
= 0; i
< ngroups
; i
++) {
6930 VALUE g
= RARRAY_AREF(ary
, i
);
6932 groups
[i
] = OBJ2GID1(g
);
6936 if (setgroups(ngroups
, groups
) == -1) /* ngroups <= maxgroups */
6941 return proc_getgroups(obj
);
6944 #define proc_setgroups rb_f_notimplement
6948 #ifdef HAVE_INITGROUPS
6951 * Process.initgroups(username, gid) -> array
6953 * Initializes the supplemental group access list by reading the
6954 * system group database and using all groups of which the given user
6955 * is a member. The group with the specified <em>gid</em> is also
6956 * added to the list. Returns the resulting Array of the
6957 * gids of all the groups in the supplementary group access list. Not
6958 * available on all platforms.
6960 * Process.groups #=> [0, 1, 2, 3, 4, 6, 10, 11, 20, 26, 27]
6961 * Process.initgroups( "mgranger", 30 ) #=> [30, 6, 10, 11]
6962 * Process.groups #=> [30, 6, 10, 11]
6967 proc_initgroups(VALUE obj
, VALUE uname
, VALUE base_grp
)
6969 if (initgroups(StringValueCStr(uname
), OBJ2GID(base_grp
)) != 0) {
6972 return proc_getgroups(obj
);
6975 #define proc_initgroups rb_f_notimplement
6978 #if defined(_SC_NGROUPS_MAX) || defined(NGROUPS_MAX)
6981 * Process.maxgroups -> integer
6983 * Returns the maximum number of gids allowed in the supplemental
6984 * group access list.
6986 * Process.maxgroups #=> 32
6990 proc_getmaxgroups(VALUE obj
)
6992 return INT2FIX(maxgroups());
6995 #define proc_getmaxgroups rb_f_notimplement
6998 #ifdef HAVE_SETGROUPS
7001 * Process.maxgroups= integer -> integer
7003 * Sets the maximum number of gids allowed in the supplemental group
7008 proc_setmaxgroups(VALUE obj
, VALUE val
)
7010 int ngroups
= FIX2INT(val
);
7011 int ngroups_max
= get_sc_ngroups_max();
7014 rb_raise(rb_eArgError
, "maxgroups %d should be positive", ngroups
);
7016 if (ngroups
> RB_MAX_GROUPS
)
7017 ngroups
= RB_MAX_GROUPS
;
7019 if (ngroups_max
> 0 && ngroups
> ngroups_max
)
7020 ngroups
= ngroups_max
;
7022 _maxgroups
= ngroups
;
7024 return INT2FIX(_maxgroups
);
7027 #define proc_setmaxgroups rb_f_notimplement
7030 #if defined(HAVE_DAEMON) || (defined(HAVE_WORKING_FORK) && defined(HAVE_SETSID))
7031 static int rb_daemon(int nochdir
, int noclose
);
7035 * Process.daemon() -> 0
7036 * Process.daemon(nochdir=nil,noclose=nil) -> 0
7038 * Detach the process from controlling terminal and run in
7039 * the background as system daemon. Unless the argument
7040 * nochdir is true (i.e. non false), it changes the current
7041 * working directory to the root ("/"). Unless the argument
7042 * noclose is true, daemon() will redirect standard input,
7043 * standard output and standard error to /dev/null.
7044 * Return zero on success, or raise one of Errno::*.
7048 proc_daemon(int argc
, VALUE
*argv
, VALUE _
)
7050 int n
, nochdir
= FALSE
, noclose
= FALSE
;
7052 switch (rb_check_arity(argc
, 0, 2)) {
7053 case 2: noclose
= TO_BOOL(argv
[1], "noclose");
7054 case 1: nochdir
= TO_BOOL(argv
[0], "nochdir");
7058 n
= rb_daemon(nochdir
, noclose
);
7059 if (n
< 0) rb_sys_fail("daemon");
7064 rb_daemon(int nochdir
, int noclose
)
7068 if (mjit_enabled
) mjit_pause(false); // Don't leave locked mutex to child.
7070 err
= daemon(nochdir
, noclose
);
7072 rb_thread_atfork(); /* calls mjit_resume() */
7076 #define fork_daemon() \
7077 switch (rb_fork_ruby(NULL)) { \
7078 case -1: return -1; \
7080 default: _exit(EXIT_SUCCESS); \
7085 if (setsid() < 0) return -1;
7087 /* must not be process-leader */
7093 if (!noclose
&& (n
= rb_cloexec_open("/dev/null", O_RDWR
, 0)) != -1) {
7094 rb_update_max_fd(n
);
7105 #define proc_daemon rb_f_notimplement
7108 /********************************************************************
7110 * Document-class: Process::GID
7112 * The Process::GID module contains a collection of
7113 * module functions which can be used to portably get, set, and
7114 * switch the current process's real, effective, and saved group IDs.
7118 static rb_gid_t SAVED_GROUP_ID
= -1;
7120 #ifdef BROKEN_SETREGID
7122 setregid(rb_gid_t rgid
, rb_gid_t egid
)
7124 if (rgid
!= (rb_gid_t
)-1 && rgid
!= getgid()) {
7125 if (egid
== (rb_gid_t
)-1) egid
= getegid();
7126 if (setgid(rgid
) < 0) return -1;
7128 if (egid
!= (rb_gid_t
)-1 && egid
!= getegid()) {
7129 if (setegid(egid
) < 0) return -1;
7137 * Process::GID.change_privilege(group) -> integer
7139 * Change the current process's real and effective group ID to that
7140 * specified by _group_. Returns the new group ID. Not
7141 * available on all platforms.
7143 * [Process.gid, Process.egid] #=> [0, 0]
7144 * Process::GID.change_privilege(33) #=> 33
7145 * [Process.gid, Process.egid] #=> [33, 33]
7149 p_gid_change_privilege(VALUE obj
, VALUE id
)
7157 if (geteuid() == 0) { /* root-user */
7158 #if defined(HAVE_SETRESGID)
7159 if (setresgid(gid
, gid
, gid
) < 0) rb_sys_fail(0);
7160 SAVED_GROUP_ID
= gid
;
7161 #elif defined HAVE_SETGID
7162 if (setgid(gid
) < 0) rb_sys_fail(0);
7163 SAVED_GROUP_ID
= gid
;
7164 #elif defined(HAVE_SETREGID) && !defined(OBSOLETE_SETREGID)
7165 if (getgid() == gid
) {
7166 if (SAVED_GROUP_ID
== gid
) {
7167 if (setregid(-1, gid
) < 0) rb_sys_fail(0);
7170 if (gid
== 0) { /* (r,e,s) == (root, y, x) */
7171 if (setregid(-1, SAVED_GROUP_ID
) < 0) rb_sys_fail(0);
7172 if (setregid(SAVED_GROUP_ID
, 0) < 0) rb_sys_fail(0);
7173 SAVED_GROUP_ID
= 0; /* (r,e,s) == (x, root, root) */
7174 if (setregid(gid
, gid
) < 0) rb_sys_fail(0);
7175 SAVED_GROUP_ID
= gid
;
7177 else { /* (r,e,s) == (z, y, x) */
7178 if (setregid(0, 0) < 0) rb_sys_fail(0);
7180 if (setregid(gid
, gid
) < 0) rb_sys_fail(0);
7181 SAVED_GROUP_ID
= gid
;
7186 if (setregid(gid
, gid
) < 0) rb_sys_fail(0);
7187 SAVED_GROUP_ID
= gid
;
7189 #elif defined(HAVE_SETRGID) && defined (HAVE_SETEGID)
7190 if (getgid() == gid
) {
7191 if (SAVED_GROUP_ID
== gid
) {
7192 if (setegid(gid
) < 0) rb_sys_fail(0);
7196 if (setegid(gid
) < 0) rb_sys_fail(0);
7197 if (setrgid(SAVED_GROUP_ID
) < 0) rb_sys_fail(0);
7199 if (setrgid(0) < 0) rb_sys_fail(0);
7202 if (setrgid(0) < 0) rb_sys_fail(0);
7204 if (setegid(gid
) < 0) rb_sys_fail(0);
7205 if (setrgid(gid
) < 0) rb_sys_fail(0);
7206 SAVED_GROUP_ID
= gid
;
7211 if (setegid(gid
) < 0) rb_sys_fail(0);
7212 if (setrgid(gid
) < 0) rb_sys_fail(0);
7213 SAVED_GROUP_ID
= gid
;
7219 else { /* unprivileged user */
7220 #if defined(HAVE_SETRESGID)
7221 if (setresgid((getgid() == gid
)? (rb_gid_t
)-1: gid
,
7222 (getegid() == gid
)? (rb_gid_t
)-1: gid
,
7223 (SAVED_GROUP_ID
== gid
)? (rb_gid_t
)-1: gid
) < 0) rb_sys_fail(0);
7224 SAVED_GROUP_ID
= gid
;
7225 #elif defined(HAVE_SETREGID) && !defined(OBSOLETE_SETREGID)
7226 if (SAVED_GROUP_ID
== gid
) {
7227 if (setregid((getgid() == gid
)? (rb_uid_t
)-1: gid
,
7228 (getegid() == gid
)? (rb_uid_t
)-1: gid
) < 0)
7231 else if (getgid() != gid
) {
7232 if (setregid(gid
, (getegid() == gid
)? (rb_uid_t
)-1: gid
) < 0)
7234 SAVED_GROUP_ID
= gid
;
7236 else if (/* getgid() == gid && */ getegid() != gid
) {
7237 if (setregid(getegid(), gid
) < 0) rb_sys_fail(0);
7238 SAVED_GROUP_ID
= gid
;
7239 if (setregid(gid
, -1) < 0) rb_sys_fail(0);
7241 else { /* getgid() == gid && getegid() == gid */
7242 if (setregid(-1, SAVED_GROUP_ID
) < 0) rb_sys_fail(0);
7243 if (setregid(SAVED_GROUP_ID
, gid
) < 0) rb_sys_fail(0);
7244 SAVED_GROUP_ID
= gid
;
7245 if (setregid(gid
, -1) < 0) rb_sys_fail(0);
7247 #elif defined(HAVE_SETRGID) && defined(HAVE_SETEGID)
7248 if (SAVED_GROUP_ID
== gid
) {
7249 if (getegid() != gid
&& setegid(gid
) < 0) rb_sys_fail(0);
7250 if (getgid() != gid
&& setrgid(gid
) < 0) rb_sys_fail(0);
7252 else if (/* SAVED_GROUP_ID != gid && */ getegid() == gid
) {
7253 if (getgid() != gid
) {
7254 if (setrgid(gid
) < 0) rb_sys_fail(0);
7255 SAVED_GROUP_ID
= gid
;
7258 if (setrgid(SAVED_GROUP_ID
) < 0) rb_sys_fail(0);
7259 SAVED_GROUP_ID
= gid
;
7260 if (setrgid(gid
) < 0) rb_sys_fail(0);
7263 else if (/* getegid() != gid && */ getgid() == gid
) {
7264 if (setegid(gid
) < 0) rb_sys_fail(0);
7265 if (setrgid(SAVED_GROUP_ID
) < 0) rb_sys_fail(0);
7266 SAVED_GROUP_ID
= gid
;
7267 if (setrgid(gid
) < 0) rb_sys_fail(0);
7270 rb_syserr_fail(EPERM
, 0);
7272 #elif defined HAVE_44BSD_SETGID
7273 if (getgid() == gid
) {
7274 /* (r,e,s)==(gid,?,?) ==> (gid,gid,gid) */
7275 if (setgid(gid
) < 0) rb_sys_fail(0);
7276 SAVED_GROUP_ID
= gid
;
7279 rb_syserr_fail(EPERM
, 0);
7281 #elif defined HAVE_SETEGID
7282 if (getgid() == gid
&& SAVED_GROUP_ID
== gid
) {
7283 if (setegid(gid
) < 0) rb_sys_fail(0);
7286 rb_syserr_fail(EPERM
, 0);
7288 #elif defined HAVE_SETGID
7289 if (getgid() == gid
&& SAVED_GROUP_ID
== gid
) {
7290 if (setgid(gid
) < 0) rb_sys_fail(0);
7293 rb_syserr_fail(EPERM
, 0);
7306 * Process.euid -> integer
7307 * Process::UID.eid -> integer
7308 * Process::Sys.geteuid -> integer
7310 * Returns the effective user ID for this process.
7312 * Process.euid #=> 501
7316 proc_geteuid(VALUE obj
)
7318 rb_uid_t euid
= geteuid();
7319 return UIDT2NUM(euid
);
7322 #if defined(HAVE_SETRESUID) || defined(HAVE_SETREUID) || defined(HAVE_SETEUID) || defined(HAVE_SETUID) || defined(_POSIX_SAVED_IDS)
7324 proc_seteuid(rb_uid_t uid
)
7326 #if defined(HAVE_SETRESUID)
7327 if (setresuid(-1, uid
, -1) < 0) rb_sys_fail(0);
7328 #elif defined HAVE_SETREUID
7329 if (setreuid(-1, uid
) < 0) rb_sys_fail(0);
7330 #elif defined HAVE_SETEUID
7331 if (seteuid(uid
) < 0) rb_sys_fail(0);
7332 #elif defined HAVE_SETUID
7333 if (uid
== getuid()) {
7334 if (setuid(uid
) < 0) rb_sys_fail(0);
7345 #if defined(HAVE_SETRESUID) || defined(HAVE_SETREUID) || defined(HAVE_SETEUID) || defined(HAVE_SETUID)
7348 * Process.euid= user
7350 * Sets the effective user ID for this process. Not available on all
7355 proc_seteuid_m(VALUE mod
, VALUE euid
)
7358 proc_seteuid(OBJ2UID(euid
));
7362 #define proc_seteuid_m rb_f_notimplement
7366 rb_seteuid_core(rb_uid_t euid
)
7368 #if defined(HAVE_SETRESUID) || (defined(HAVE_SETREUID) && !defined(OBSOLETE_SETREUID))
7374 #if defined(HAVE_SETRESUID) || (defined(HAVE_SETREUID) && !defined(OBSOLETE_SETREUID))
7378 #if defined(HAVE_SETRESUID)
7380 if (setresuid(-1,euid
,euid
) < 0) rb_sys_fail(0);
7381 SAVED_USER_ID
= euid
;
7384 if (setresuid(-1,euid
,-1) < 0) rb_sys_fail(0);
7386 #elif defined(HAVE_SETREUID) && !defined(OBSOLETE_SETREUID)
7387 if (setreuid(-1, euid
) < 0) rb_sys_fail(0);
7389 if (setreuid(euid
,uid
) < 0) rb_sys_fail(0);
7390 if (setreuid(uid
,euid
) < 0) rb_sys_fail(0);
7391 SAVED_USER_ID
= euid
;
7393 #elif defined HAVE_SETEUID
7394 if (seteuid(euid
) < 0) rb_sys_fail(0);
7395 #elif defined HAVE_SETUID
7396 if (geteuid() == 0) rb_sys_fail(0);
7397 if (setuid(euid
) < 0) rb_sys_fail(0);
7407 * Process::UID.grant_privilege(user) -> integer
7408 * Process::UID.eid= user -> integer
7410 * Set the effective user ID, and if possible, the saved user ID of
7411 * the process to the given _user_. Returns the new
7412 * effective user ID. Not available on all platforms.
7414 * [Process.uid, Process.euid] #=> [0, 0]
7415 * Process::UID.grant_privilege(31) #=> 31
7416 * [Process.uid, Process.euid] #=> [0, 31]
7420 p_uid_grant_privilege(VALUE obj
, VALUE id
)
7422 rb_seteuid_core(OBJ2UID(id
));
7429 * Process.egid -> integer
7430 * Process::GID.eid -> integer
7431 * Process::Sys.geteid -> integer
7433 * Returns the effective group ID for this process. Not available on
7436 * Process.egid #=> 500
7440 proc_getegid(VALUE obj
)
7442 rb_gid_t egid
= getegid();
7444 return GIDT2NUM(egid
);
7447 #if defined(HAVE_SETRESGID) || defined(HAVE_SETREGID) || defined(HAVE_SETEGID) || defined(HAVE_SETGID) || defined(_POSIX_SAVED_IDS)
7450 * Process.egid = integer -> integer
7452 * Sets the effective group ID for this process. Not available on all
7457 proc_setegid(VALUE obj
, VALUE egid
)
7459 #if defined(HAVE_SETRESGID) || defined(HAVE_SETREGID) || defined(HAVE_SETEGID) || defined(HAVE_SETGID)
7465 #if defined(HAVE_SETRESGID) || defined(HAVE_SETREGID) || defined(HAVE_SETEGID) || defined(HAVE_SETGID)
7466 gid
= OBJ2GID(egid
);
7469 #if defined(HAVE_SETRESGID)
7470 if (setresgid(-1, gid
, -1) < 0) rb_sys_fail(0);
7471 #elif defined HAVE_SETREGID
7472 if (setregid(-1, gid
) < 0) rb_sys_fail(0);
7473 #elif defined HAVE_SETEGID
7474 if (setegid(gid
) < 0) rb_sys_fail(0);
7475 #elif defined HAVE_SETGID
7476 if (gid
== getgid()) {
7477 if (setgid(gid
) < 0) rb_sys_fail(0);
7489 #if defined(HAVE_SETRESGID) || defined(HAVE_SETREGID) || defined(HAVE_SETEGID) || defined(HAVE_SETGID)
7490 #define proc_setegid_m proc_setegid
7492 #define proc_setegid_m rb_f_notimplement
7496 rb_setegid_core(rb_gid_t egid
)
7498 #if defined(HAVE_SETRESGID) || (defined(HAVE_SETREGID) && !defined(OBSOLETE_SETREGID))
7504 #if defined(HAVE_SETRESGID) || (defined(HAVE_SETREGID) && !defined(OBSOLETE_SETREGID))
7508 #if defined(HAVE_SETRESGID)
7510 if (setresgid(-1,egid
,egid
) < 0) rb_sys_fail(0);
7511 SAVED_GROUP_ID
= egid
;
7514 if (setresgid(-1,egid
,-1) < 0) rb_sys_fail(0);
7516 #elif defined(HAVE_SETREGID) && !defined(OBSOLETE_SETREGID)
7517 if (setregid(-1, egid
) < 0) rb_sys_fail(0);
7519 if (setregid(egid
,gid
) < 0) rb_sys_fail(0);
7520 if (setregid(gid
,egid
) < 0) rb_sys_fail(0);
7521 SAVED_GROUP_ID
= egid
;
7523 #elif defined HAVE_SETEGID
7524 if (setegid(egid
) < 0) rb_sys_fail(0);
7525 #elif defined HAVE_SETGID
7526 if (geteuid() == 0 /* root user */) rb_sys_fail(0);
7527 if (setgid(egid
) < 0) rb_sys_fail(0);
7537 * Process::GID.grant_privilege(group) -> integer
7538 * Process::GID.eid = group -> integer
7540 * Set the effective group ID, and if possible, the saved group ID of
7541 * the process to the given _group_. Returns the new
7542 * effective group ID. Not available on all platforms.
7544 * [Process.gid, Process.egid] #=> [0, 0]
7545 * Process::GID.grant_privilege(31) #=> 33
7546 * [Process.gid, Process.egid] #=> [0, 33]
7550 p_gid_grant_privilege(VALUE obj
, VALUE id
)
7552 rb_setegid_core(OBJ2GID(id
));
7559 * Process::UID.re_exchangeable? -> true or false
7561 * Returns +true+ if the real and effective user IDs of a
7562 * process may be exchanged on the current platform.
7567 p_uid_exchangeable(VALUE _
)
7569 #if defined(HAVE_SETRESUID)
7571 #elif defined(HAVE_SETREUID) && !defined(OBSOLETE_SETREUID)
7581 * Process::UID.re_exchange -> integer
7583 * Exchange real and effective user IDs and return the new effective
7584 * user ID. Not available on all platforms.
7586 * [Process.uid, Process.euid] #=> [0, 31]
7587 * Process::UID.re_exchange #=> 0
7588 * [Process.uid, Process.euid] #=> [31, 0]
7592 p_uid_exchange(VALUE obj
)
7595 #if defined(HAVE_SETRESUID) || (defined(HAVE_SETREUID) && !defined(OBSOLETE_SETREUID))
7602 #if defined(HAVE_SETRESUID) || (defined(HAVE_SETREUID) && !defined(OBSOLETE_SETREUID))
7606 #if defined(HAVE_SETRESUID)
7607 if (setresuid(euid
, uid
, uid
) < 0) rb_sys_fail(0);
7608 SAVED_USER_ID
= uid
;
7609 #elif defined(HAVE_SETREUID) && !defined(OBSOLETE_SETREUID)
7610 if (setreuid(euid
,uid
) < 0) rb_sys_fail(0);
7611 SAVED_USER_ID
= uid
;
7615 return UIDT2NUM(uid
);
7621 * Process::GID.re_exchangeable? -> true or false
7623 * Returns +true+ if the real and effective group IDs of a
7624 * process may be exchanged on the current platform.
7629 p_gid_exchangeable(VALUE _
)
7631 #if defined(HAVE_SETRESGID)
7633 #elif defined(HAVE_SETREGID) && !defined(OBSOLETE_SETREGID)
7643 * Process::GID.re_exchange -> integer
7645 * Exchange real and effective group IDs and return the new effective
7646 * group ID. Not available on all platforms.
7648 * [Process.gid, Process.egid] #=> [0, 33]
7649 * Process::GID.re_exchange #=> 0
7650 * [Process.gid, Process.egid] #=> [33, 0]
7654 p_gid_exchange(VALUE obj
)
7657 #if defined(HAVE_SETRESGID) || (defined(HAVE_SETREGID) && !defined(OBSOLETE_SETREGID))
7664 #if defined(HAVE_SETRESGID) || (defined(HAVE_SETREGID) && !defined(OBSOLETE_SETREGID))
7668 #if defined(HAVE_SETRESGID)
7669 if (setresgid(egid
, gid
, gid
) < 0) rb_sys_fail(0);
7670 SAVED_GROUP_ID
= gid
;
7671 #elif defined(HAVE_SETREGID) && !defined(OBSOLETE_SETREGID)
7672 if (setregid(egid
,gid
) < 0) rb_sys_fail(0);
7673 SAVED_GROUP_ID
= gid
;
7677 return GIDT2NUM(gid
);
7680 /* [MG] :FIXME: Is this correct? I'm not sure how to phrase this. */
7684 * Process::UID.sid_available? -> true or false
7686 * Returns +true+ if the current platform has saved user
7692 p_uid_have_saved_id(VALUE _
)
7694 #if defined(HAVE_SETRESUID) || defined(HAVE_SETEUID) || defined(_POSIX_SAVED_IDS)
7702 #if defined(HAVE_SETRESUID) || defined(HAVE_SETEUID) || defined(_POSIX_SAVED_IDS)
7704 p_uid_sw_ensure(VALUE i
)
7706 rb_uid_t id
= (rb_uid_t
/* narrowing */)i
;
7707 under_uid_switch
= 0;
7708 id
= rb_seteuid_core(id
);
7709 return UIDT2NUM(id
);
7715 * Process::UID.switch -> integer
7716 * Process::UID.switch {|| block} -> object
7718 * Switch the effective and real user IDs of the current process. If
7719 * a <em>block</em> is given, the user IDs will be switched back
7720 * after the block is executed. Returns the new effective user ID if
7721 * called without a block, and the return value of the block if one
7727 p_uid_switch(VALUE obj
)
7738 if (rb_block_given_p()) {
7739 under_uid_switch
= 1;
7740 return rb_ensure(rb_yield
, Qnil
, p_uid_sw_ensure
, SAVED_USER_ID
);
7743 return UIDT2NUM(euid
);
7746 else if (euid
!= SAVED_USER_ID
) {
7747 proc_seteuid(SAVED_USER_ID
);
7748 if (rb_block_given_p()) {
7749 under_uid_switch
= 1;
7750 return rb_ensure(rb_yield
, Qnil
, p_uid_sw_ensure
, euid
);
7753 return UIDT2NUM(uid
);
7757 rb_syserr_fail(EPERM
, 0);
7760 UNREACHABLE_RETURN(Qnil
);
7764 p_uid_sw_ensure(VALUE obj
)
7766 under_uid_switch
= 0;
7767 return p_uid_exchange(obj
);
7771 p_uid_switch(VALUE obj
)
7781 rb_syserr_fail(EPERM
, 0);
7783 p_uid_exchange(obj
);
7784 if (rb_block_given_p()) {
7785 under_uid_switch
= 1;
7786 return rb_ensure(rb_yield
, Qnil
, p_uid_sw_ensure
, obj
);
7789 return UIDT2NUM(euid
);
7795 /* [MG] :FIXME: Is this correct? I'm not sure how to phrase this. */
7799 * Process::GID.sid_available? -> true or false
7801 * Returns +true+ if the current platform has saved group
7807 p_gid_have_saved_id(VALUE _
)
7809 #if defined(HAVE_SETRESGID) || defined(HAVE_SETEGID) || defined(_POSIX_SAVED_IDS)
7816 #if defined(HAVE_SETRESGID) || defined(HAVE_SETEGID) || defined(_POSIX_SAVED_IDS)
7818 p_gid_sw_ensure(VALUE i
)
7820 rb_gid_t id
= (rb_gid_t
/* narrowing */)i
;
7821 under_gid_switch
= 0;
7822 id
= rb_setegid_core(id
);
7823 return GIDT2NUM(id
);
7829 * Process::GID.switch -> integer
7830 * Process::GID.switch {|| block} -> object
7832 * Switch the effective and real group IDs of the current process. If
7833 * a <em>block</em> is given, the group IDs will be switched back
7834 * after the block is executed. Returns the new effective group ID if
7835 * called without a block, and the return value of the block if one
7841 p_gid_switch(VALUE obj
)
7851 proc_setegid(obj
, GIDT2NUM(gid
));
7852 if (rb_block_given_p()) {
7853 under_gid_switch
= 1;
7854 return rb_ensure(rb_yield
, Qnil
, p_gid_sw_ensure
, SAVED_GROUP_ID
);
7857 return GIDT2NUM(egid
);
7860 else if (egid
!= SAVED_GROUP_ID
) {
7861 proc_setegid(obj
, GIDT2NUM(SAVED_GROUP_ID
));
7862 if (rb_block_given_p()) {
7863 under_gid_switch
= 1;
7864 return rb_ensure(rb_yield
, Qnil
, p_gid_sw_ensure
, egid
);
7867 return GIDT2NUM(gid
);
7871 rb_syserr_fail(EPERM
, 0);
7874 UNREACHABLE_RETURN(Qnil
);
7878 p_gid_sw_ensure(VALUE obj
)
7880 under_gid_switch
= 0;
7881 return p_gid_exchange(obj
);
7885 p_gid_switch(VALUE obj
)
7895 rb_syserr_fail(EPERM
, 0);
7897 p_gid_exchange(obj
);
7898 if (rb_block_given_p()) {
7899 under_gid_switch
= 1;
7900 return rb_ensure(rb_yield
, Qnil
, p_gid_sw_ensure
, obj
);
7903 return GIDT2NUM(egid
);
7909 #if defined(HAVE_TIMES)
7913 #ifdef HAVE__SC_CLK_TCK
7914 return sysconf(_SC_CLK_TCK
);
7915 #elif defined CLK_TCK
7926 * Process.times -> aProcessTms
7928 * Returns a <code>Tms</code> structure (see Process::Tms)
7929 * that contains user and system CPU times for this process,
7930 * and also for children processes.
7933 * [ t.utime, t.stime, t.cutime, t.cstime ] #=> [0.0, 0.02, 0.00, 0.00]
7937 rb_proc_times(VALUE obj
)
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)
7944 rb_sys_fail("getrusage");
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
);
7962 RB_GC_GUARD(cutime
);
7963 RB_GC_GUARD(cstime
);
7967 #define rb_proc_times rb_f_notimplement
7970 #ifdef HAVE_LONG_LONG
7971 typedef LONG_LONG timetick_int_t
;
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
;
8033 int32_t count
; /* 0 .. 999999999 */
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
);
8109 v
= rb_funcall(v
, '*', 1, LONG2FIX(1000000000));
8110 v
= rb_funcall(v
, '+', 1, LONG2FIX(ttp
->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
])); /* Ruby's '/' is div. */
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
);
8156 rb_raise(rb_eArgError
, "unexpected unit: %"PRIsVALUE
, unit
);
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
;
8183 * Process.clock_gettime(clock_id [, unit]) -> number
8185 * Returns a time returned by POSIX clock_gettime() function.
8187 * p Process.clock_gettime(Process::CLOCK_MONOTONIC)
8188 * #=> 896053.968060096
8190 * +clock_id+ specifies a kind of clock.
8191 * It is specified as a constant which begins with <code>Process::CLOCK_</code>
8192 * such as Process::CLOCK_REALTIME and Process::CLOCK_MONOTONIC.
8194 * The supported constants depends on OS and version.
8195 * Ruby provides following types of +clock_id+ if available.
8197 * [CLOCK_REALTIME] SUSv2 to 4, Linux 2.5.63, FreeBSD 3.0, NetBSD 2.0, OpenBSD 2.1, macOS 10.12, Windows-8/Server-2012
8198 * [CLOCK_MONOTONIC] SUSv3 to 4, Linux 2.5.63, FreeBSD 3.0, NetBSD 2.0, OpenBSD 3.4, macOS 10.12, Windows-2000
8199 * [CLOCK_PROCESS_CPUTIME_ID] SUSv3 to 4, Linux 2.5.63, FreeBSD 9.3, OpenBSD 5.4, macOS 10.12
8200 * [CLOCK_THREAD_CPUTIME_ID] SUSv3 to 4, Linux 2.5.63, FreeBSD 7.1, OpenBSD 5.4, macOS 10.12
8201 * [CLOCK_VIRTUAL] FreeBSD 3.0, OpenBSD 2.1
8202 * [CLOCK_PROF] FreeBSD 3.0, OpenBSD 2.1
8203 * [CLOCK_REALTIME_FAST] FreeBSD 8.1
8204 * [CLOCK_REALTIME_PRECISE] FreeBSD 8.1
8205 * [CLOCK_REALTIME_COARSE] Linux 2.6.32
8206 * [CLOCK_REALTIME_ALARM] Linux 3.0
8207 * [CLOCK_MONOTONIC_FAST] FreeBSD 8.1
8208 * [CLOCK_MONOTONIC_PRECISE] FreeBSD 8.1
8209 * [CLOCK_MONOTONIC_COARSE] Linux 2.6.32
8210 * [CLOCK_MONOTONIC_RAW] Linux 2.6.28, macOS 10.12
8211 * [CLOCK_MONOTONIC_RAW_APPROX] macOS 10.12
8212 * [CLOCK_BOOTTIME] Linux 2.6.39
8213 * [CLOCK_BOOTTIME_ALARM] Linux 3.0
8214 * [CLOCK_UPTIME] FreeBSD 7.0, OpenBSD 5.5
8215 * [CLOCK_UPTIME_FAST] FreeBSD 8.1
8216 * [CLOCK_UPTIME_RAW] macOS 10.12
8217 * [CLOCK_UPTIME_RAW_APPROX] macOS 10.12
8218 * [CLOCK_UPTIME_PRECISE] FreeBSD 8.1
8219 * [CLOCK_SECOND] FreeBSD 8.1
8220 * [CLOCK_TAI] Linux 3.10
8222 * Note that SUS stands for Single Unix Specification.
8223 * SUS contains POSIX and clock_gettime is defined in the POSIX part.
8224 * SUS defines CLOCK_REALTIME mandatory but
8225 * CLOCK_MONOTONIC, CLOCK_PROCESS_CPUTIME_ID and CLOCK_THREAD_CPUTIME_ID are optional.
8227 * Also, several symbols are accepted as +clock_id+.
8228 * There are emulations for clock_gettime().
8230 * For example, Process::CLOCK_REALTIME is defined as
8231 * +:GETTIMEOFDAY_BASED_CLOCK_REALTIME+ when clock_gettime() is not available.
8233 * Emulations for +CLOCK_REALTIME+:
8234 * [:GETTIMEOFDAY_BASED_CLOCK_REALTIME]
8235 * Use gettimeofday() defined by SUS.
8236 * (SUSv4 obsoleted it, though.)
8237 * The resolution is 1 microsecond.
8238 * [:TIME_BASED_CLOCK_REALTIME]
8239 * Use time() defined by ISO C.
8240 * The resolution is 1 second.
8242 * Emulations for +CLOCK_MONOTONIC+:
8243 * [:MACH_ABSOLUTE_TIME_BASED_CLOCK_MONOTONIC]
8244 * Use mach_absolute_time(), available on Darwin.
8245 * The resolution is CPU dependent.
8246 * [:TIMES_BASED_CLOCK_MONOTONIC]
8247 * Use the result value of times() defined by POSIX.
8248 * POSIX defines it as "times() shall return the elapsed real time, in clock ticks, since an arbitrary point in the past (for example, system start-up time)".
8249 * For example, GNU/Linux returns a value based on jiffies and it is monotonic.
8250 * However, 4.4BSD uses gettimeofday() and it is not monotonic.
8251 * (FreeBSD uses clock_gettime(CLOCK_MONOTONIC) instead, though.)
8252 * The resolution is the clock tick.
8253 * "getconf CLK_TCK" command shows the clock ticks per second.
8254 * (The clock ticks per second is defined by HZ macro in older systems.)
8255 * If it is 100 and clock_t is 32 bits integer type, the resolution is 10 millisecond and
8256 * cannot represent over 497 days.
8258 * Emulations for +CLOCK_PROCESS_CPUTIME_ID+:
8259 * [:GETRUSAGE_BASED_CLOCK_PROCESS_CPUTIME_ID]
8260 * Use getrusage() defined by SUS.
8261 * getrusage() is used with RUSAGE_SELF to obtain the time only for
8262 * the calling process (excluding the time for child processes).
8263 * The result is addition of user time (ru_utime) and system time (ru_stime).
8264 * The resolution is 1 microsecond.
8265 * [:TIMES_BASED_CLOCK_PROCESS_CPUTIME_ID]
8266 * Use times() defined by POSIX.
8267 * The result is addition of user time (tms_utime) and system time (tms_stime).
8268 * tms_cutime and tms_cstime are ignored to exclude the time for child processes.
8269 * The resolution is the clock tick.
8270 * "getconf CLK_TCK" command shows the clock ticks per second.
8271 * (The clock ticks per second is defined by HZ macro in older systems.)
8272 * If it is 100, the resolution is 10 millisecond.
8273 * [:CLOCK_BASED_CLOCK_PROCESS_CPUTIME_ID]
8274 * Use clock() defined by ISO C.
8275 * The resolution is 1/CLOCKS_PER_SEC.
8276 * CLOCKS_PER_SEC is the C-level macro defined by time.h.
8277 * SUS defines CLOCKS_PER_SEC is 1000000.
8278 * Non-Unix systems may define it a different value, though.
8279 * If CLOCKS_PER_SEC is 1000000 as SUS, the resolution is 1 microsecond.
8280 * If CLOCKS_PER_SEC is 1000000 and clock_t is 32 bits integer type, it cannot represent over 72 minutes.
8282 * If the given +clock_id+ is not supported, Errno::EINVAL is raised.
8284 * +unit+ specifies a type of the return value.
8286 * [:float_second] number of seconds as a float (default)
8287 * [:float_millisecond] number of milliseconds as a float
8288 * [:float_microsecond] number of microseconds as a float
8289 * [:second] number of seconds as an integer
8290 * [:millisecond] number of milliseconds as an integer
8291 * [:microsecond] number of microseconds as an integer
8292 * [:nanosecond] number of nanoseconds as an integer
8294 * The underlying function, clock_gettime(), returns a number of nanoseconds.
8295 * Float object (IEEE 754 double) is not enough to represent
8296 * the return value for CLOCK_REALTIME.
8297 * If the exact nanoseconds value is required, use +:nanoseconds+ as the +unit+.
8299 * The origin (zero) of the returned value varies.
8300 * For example, system start up time, process start up time, the Epoch, etc.
8302 * The origin in CLOCK_REALTIME is defined as the Epoch
8303 * (1970-01-01 00:00:00 UTC).
8304 * But some systems count leap seconds and others doesn't.
8305 * So the result can be interpreted differently across systems.
8306 * Time.now is recommended over CLOCK_REALTIME.
8309 rb_clock_gettime(int argc
, VALUE
*argv
, VALUE _
)
8314 timetick_int_t numerators
[2];
8315 timetick_int_t denominators
[2];
8316 int num_numerators
= 0;
8317 int num_denominators
= 0;
8319 VALUE unit
= (rb_check_arity(argc
, 1, 2) == 2) ? argv
[1] : Qnil
;
8320 VALUE clk_id
= argv
[0];
8322 if (SYMBOL_P(clk_id
)) {
8324 * Non-clock_gettime clocks are provided by symbol clk_id.
8326 #ifdef HAVE_GETTIMEOFDAY
8328 * GETTIMEOFDAY_BASED_CLOCK_REALTIME is used for
8329 * CLOCK_REALTIME if clock_gettime is not available.
8331 #define RUBY_GETTIMEOFDAY_BASED_CLOCK_REALTIME ID2SYM(id_GETTIMEOFDAY_BASED_CLOCK_REALTIME)
8332 if (clk_id
== RUBY_GETTIMEOFDAY_BASED_CLOCK_REALTIME
) {
8334 ret
= gettimeofday(&tv
, 0);
8336 rb_sys_fail("gettimeofday");
8337 tt
.giga_count
= tv
.tv_sec
;
8338 tt
.count
= (int32_t)tv
.tv_usec
* 1000;
8339 denominators
[num_denominators
++] = 1000000000;
8344 #define RUBY_TIME_BASED_CLOCK_REALTIME ID2SYM(id_TIME_BASED_CLOCK_REALTIME)
8345 if (clk_id
== RUBY_TIME_BASED_CLOCK_REALTIME
) {
8348 if (t
== (time_t)-1)
8349 rb_sys_fail("time");
8352 denominators
[num_denominators
++] = 1000000000;
8357 #define RUBY_TIMES_BASED_CLOCK_MONOTONIC \
8358 ID2SYM(id_TIMES_BASED_CLOCK_MONOTONIC)
8359 if (clk_id
== RUBY_TIMES_BASED_CLOCK_MONOTONIC
) {
8362 unsigned_clock_t uc
;
8364 if (c
== (clock_t)-1)
8365 rb_sys_fail("times");
8366 uc
= (unsigned_clock_t
)c
;
8367 tt
.count
= (int32_t)(uc
% 1000000000);
8368 tt
.giga_count
= (uc
/ 1000000000);
8369 denominators
[num_denominators
++] = get_clk_tck();
8375 #define RUBY_GETRUSAGE_BASED_CLOCK_PROCESS_CPUTIME_ID \
8376 ID2SYM(id_GETRUSAGE_BASED_CLOCK_PROCESS_CPUTIME_ID)
8377 if (clk_id
== RUBY_GETRUSAGE_BASED_CLOCK_PROCESS_CPUTIME_ID
) {
8378 struct rusage usage
;
8380 ret
= getrusage(RUSAGE_SELF
, &usage
);
8382 rb_sys_fail("getrusage");
8383 tt
.giga_count
= usage
.ru_utime
.tv_sec
+ usage
.ru_stime
.tv_sec
;
8384 usec
= (int32_t)(usage
.ru_utime
.tv_usec
+ usage
.ru_stime
.tv_usec
);
8385 if (1000000 <= usec
) {
8389 tt
.count
= usec
* 1000;
8390 denominators
[num_denominators
++] = 1000000000;
8396 #define RUBY_TIMES_BASED_CLOCK_PROCESS_CPUTIME_ID \
8397 ID2SYM(id_TIMES_BASED_CLOCK_PROCESS_CPUTIME_ID)
8398 if (clk_id
== RUBY_TIMES_BASED_CLOCK_PROCESS_CPUTIME_ID
) {
8400 unsigned_clock_t utime
, stime
;
8401 if (times(&buf
) == (clock_t)-1)
8402 rb_sys_fail("times");
8403 utime
= (unsigned_clock_t
)buf
.tms_utime
;
8404 stime
= (unsigned_clock_t
)buf
.tms_stime
;
8405 tt
.count
= (int32_t)((utime
% 1000000000) + (stime
% 1000000000));
8406 tt
.giga_count
= (utime
/ 1000000000) + (stime
/ 1000000000);
8407 if (1000000000 <= tt
.count
) {
8408 tt
.count
-= 1000000000;
8411 denominators
[num_denominators
++] = get_clk_tck();
8416 #define RUBY_CLOCK_BASED_CLOCK_PROCESS_CPUTIME_ID \
8417 ID2SYM(id_CLOCK_BASED_CLOCK_PROCESS_CPUTIME_ID)
8418 if (clk_id
== RUBY_CLOCK_BASED_CLOCK_PROCESS_CPUTIME_ID
) {
8420 unsigned_clock_t uc
;
8423 if (c
== (clock_t)-1)
8424 rb_sys_fail("clock");
8425 uc
= (unsigned_clock_t
)c
;
8426 tt
.count
= (int32_t)(uc
% 1000000000);
8427 tt
.giga_count
= uc
/ 1000000000;
8428 denominators
[num_denominators
++] = CLOCKS_PER_SEC
;
8433 #define RUBY_MACH_ABSOLUTE_TIME_BASED_CLOCK_MONOTONIC ID2SYM(id_MACH_ABSOLUTE_TIME_BASED_CLOCK_MONOTONIC)
8434 if (clk_id
== RUBY_MACH_ABSOLUTE_TIME_BASED_CLOCK_MONOTONIC
) {
8435 const mach_timebase_info_data_t
*info
= get_mach_timebase_info();
8436 uint64_t t
= mach_absolute_time();
8437 tt
.count
= (int32_t)(t
% 1000000000);
8438 tt
.giga_count
= t
/ 1000000000;
8439 numerators
[num_numerators
++] = info
->numer
;
8440 denominators
[num_denominators
++] = info
->denom
;
8441 denominators
[num_denominators
++] = 1000000000;
8447 #if defined(HAVE_CLOCK_GETTIME)
8450 c
= NUM2CLOCKID(clk_id
);
8451 ret
= clock_gettime(c
, &ts
);
8453 rb_sys_fail("clock_gettime");
8454 tt
.count
= (int32_t)ts
.tv_nsec
;
8455 tt
.giga_count
= ts
.tv_sec
;
8456 denominators
[num_denominators
++] = 1000000000;
8460 /* EINVAL emulates clock_gettime behavior when clock_id is invalid. */
8461 rb_syserr_fail(EINVAL
, 0);
8464 return make_clock_result(&tt
, numerators
, num_numerators
, denominators
, num_denominators
, unit
);
8469 * Process.clock_getres(clock_id [, unit]) -> number
8471 * Returns an estimate of the resolution of a +clock_id+ using the POSIX
8472 * <code>clock_getres()</code> function.
8474 * Note the reported resolution is often inaccurate on most platforms due to
8475 * underlying bugs for this function and therefore the reported resolution
8476 * often differs from the actual resolution of the clock in practice.
8477 * Inaccurate reported resolutions have been observed for various clocks including
8478 * CLOCK_MONOTONIC and CLOCK_MONOTONIC_RAW when using Linux, macOS, BSD or AIX
8479 * platforms, when using ARM processors, or when using virtualization.
8481 * +clock_id+ specifies a kind of clock.
8482 * See the document of +Process.clock_gettime+ for details.
8483 * +clock_id+ can be a symbol as for +Process.clock_gettime+.
8485 * If the given +clock_id+ is not supported, Errno::EINVAL is raised.
8487 * +unit+ specifies the type of the return value.
8488 * +Process.clock_getres+ accepts +unit+ as +Process.clock_gettime+.
8489 * The default value, +:float_second+, is also the same as
8490 * +Process.clock_gettime+.
8492 * +Process.clock_getres+ also accepts +:hertz+ as +unit+.
8493 * +:hertz+ means the reciprocal of +:float_second+.
8495 * +:hertz+ can be used to obtain the exact value of
8496 * the clock ticks per second for the times() function and
8497 * CLOCKS_PER_SEC for the clock() function.
8499 * <code>Process.clock_getres(:TIMES_BASED_CLOCK_PROCESS_CPUTIME_ID, :hertz)</code>
8500 * returns the clock ticks per second.
8502 * <code>Process.clock_getres(:CLOCK_BASED_CLOCK_PROCESS_CPUTIME_ID, :hertz)</code>
8503 * returns CLOCKS_PER_SEC.
8505 * p Process.clock_getres(Process::CLOCK_MONOTONIC)
8510 rb_clock_getres(int argc
, VALUE
*argv
, VALUE _
)
8513 timetick_int_t numerators
[2];
8514 timetick_int_t denominators
[2];
8515 int num_numerators
= 0;
8516 int num_denominators
= 0;
8518 VALUE unit
= (rb_check_arity(argc
, 1, 2) == 2) ? argv
[1] : Qnil
;
8519 VALUE clk_id
= argv
[0];
8521 if (SYMBOL_P(clk_id
)) {
8522 #ifdef RUBY_GETTIMEOFDAY_BASED_CLOCK_REALTIME
8523 if (clk_id
== RUBY_GETTIMEOFDAY_BASED_CLOCK_REALTIME
) {
8526 denominators
[num_denominators
++] = 1000000000;
8531 #ifdef RUBY_TIME_BASED_CLOCK_REALTIME
8532 if (clk_id
== RUBY_TIME_BASED_CLOCK_REALTIME
) {
8535 denominators
[num_denominators
++] = 1000000000;
8540 #ifdef RUBY_TIMES_BASED_CLOCK_MONOTONIC
8541 if (clk_id
== RUBY_TIMES_BASED_CLOCK_MONOTONIC
) {
8544 denominators
[num_denominators
++] = get_clk_tck();
8549 #ifdef RUBY_GETRUSAGE_BASED_CLOCK_PROCESS_CPUTIME_ID
8550 if (clk_id
== RUBY_GETRUSAGE_BASED_CLOCK_PROCESS_CPUTIME_ID
) {
8553 denominators
[num_denominators
++] = 1000000000;
8558 #ifdef RUBY_TIMES_BASED_CLOCK_PROCESS_CPUTIME_ID
8559 if (clk_id
== RUBY_TIMES_BASED_CLOCK_PROCESS_CPUTIME_ID
) {
8562 denominators
[num_denominators
++] = get_clk_tck();
8567 #ifdef RUBY_CLOCK_BASED_CLOCK_PROCESS_CPUTIME_ID
8568 if (clk_id
== RUBY_CLOCK_BASED_CLOCK_PROCESS_CPUTIME_ID
) {
8571 denominators
[num_denominators
++] = CLOCKS_PER_SEC
;
8576 #ifdef RUBY_MACH_ABSOLUTE_TIME_BASED_CLOCK_MONOTONIC
8577 if (clk_id
== RUBY_MACH_ABSOLUTE_TIME_BASED_CLOCK_MONOTONIC
) {
8578 const mach_timebase_info_data_t
*info
= get_mach_timebase_info();
8581 numerators
[num_numerators
++] = info
->numer
;
8582 denominators
[num_denominators
++] = info
->denom
;
8583 denominators
[num_denominators
++] = 1000000000;
8589 #if defined(HAVE_CLOCK_GETRES)
8591 clockid_t c
= NUM2CLOCKID(clk_id
);
8592 int ret
= clock_getres(c
, &ts
);
8594 rb_sys_fail("clock_getres");
8595 tt
.count
= (int32_t)ts
.tv_nsec
;
8596 tt
.giga_count
= ts
.tv_sec
;
8597 denominators
[num_denominators
++] = 1000000000;
8601 /* EINVAL emulates clock_getres behavior when clock_id is invalid. */
8602 rb_syserr_fail(EINVAL
, 0);
8605 if (unit
== ID2SYM(id_hertz
)) {
8606 return timetick2dblnum_reciprocal(&tt
, numerators
, num_numerators
, denominators
, num_denominators
);
8609 return make_clock_result(&tt
, numerators
, num_numerators
, denominators
, num_denominators
, unit
);
8614 get_CHILD_STATUS(ID _x
, VALUE
*_y
)
8616 return rb_last_status_get();
8620 get_PROCESS_ID(ID _x
, VALUE
*_y
)
8627 * Process.kill(signal, pid, ...) -> integer
8629 * Sends the given signal to the specified process id(s) if _pid_ is positive.
8630 * If _pid_ is zero, _signal_ is sent to all processes whose group ID is equal
8631 * to the group ID of the process. If _pid_ is negative, results are dependent
8632 * on the operating system. _signal_ may be an integer signal number or
8633 * a POSIX signal name (either with or without a +SIG+ prefix). If _signal_ is
8634 * negative (or starts with a minus sign), kills process groups instead of
8635 * processes. Not all signals are available on all platforms.
8636 * The keys and values of Signal.list are known signal names and numbers,
8640 * Signal.trap("HUP") { puts "Ouch!"; exit }
8641 * # ... do some work ...
8644 * Process.kill("HUP", pid)
8647 * <em>produces:</em>
8651 * If _signal_ is an integer but wrong for signal, Errno::EINVAL or
8652 * RangeError will be raised. Otherwise unless _signal_ is a String
8653 * or a Symbol, and a known signal name, ArgumentError will be
8656 * Also, Errno::ESRCH or RangeError for invalid _pid_, Errno::EPERM
8657 * when failed because of no privilege, will be raised. In these
8658 * cases, signals may have been sent to preceding processes.
8662 proc_rb_f_kill(int c
, const VALUE
*v
, VALUE _
)
8664 return rb_f_kill(c
, v
);
8668 static VALUE rb_mProcUID
;
8669 static VALUE rb_mProcGID
;
8670 static VALUE rb_mProcID_Syscall
;
8674 * The Process module is a collection of methods used to
8675 * manipulate processes.
8679 InitVM_process(void)
8681 rb_define_virtual_variable("$?", get_CHILD_STATUS
, 0);
8682 rb_define_virtual_variable("$$", get_PROCESS_ID
, 0);
8684 rb_gvar_ractor_local("$$");
8685 rb_gvar_ractor_local("$?");
8687 rb_define_global_function("exec", f_exec
, -1);
8688 rb_define_global_function("fork", rb_f_fork
, 0);
8689 rb_define_global_function("exit!", rb_f_exit_bang
, -1);
8690 rb_define_global_function("system", rb_f_system
, -1);
8691 rb_define_global_function("spawn", rb_f_spawn
, -1);
8692 rb_define_global_function("sleep", rb_f_sleep
, -1);
8693 rb_define_global_function("exit", f_exit
, -1);
8694 rb_define_global_function("abort", f_abort
, -1);
8696 rb_mProcess
= rb_define_module("Process");
8699 /* see Process.wait */
8700 rb_define_const(rb_mProcess
, "WNOHANG", INT2FIX(WNOHANG
));
8702 /* see Process.wait */
8703 rb_define_const(rb_mProcess
, "WNOHANG", INT2FIX(0));
8706 /* see Process.wait */
8707 rb_define_const(rb_mProcess
, "WUNTRACED", INT2FIX(WUNTRACED
));
8709 /* see Process.wait */
8710 rb_define_const(rb_mProcess
, "WUNTRACED", INT2FIX(0));
8713 rb_define_singleton_method(rb_mProcess
, "exec", f_exec
, -1);
8714 rb_define_singleton_method(rb_mProcess
, "fork", rb_f_fork
, 0);
8715 rb_define_singleton_method(rb_mProcess
, "spawn", rb_f_spawn
, -1);
8716 rb_define_singleton_method(rb_mProcess
, "exit!", rb_f_exit_bang
, -1);
8717 rb_define_singleton_method(rb_mProcess
, "exit", f_exit
, -1);
8718 rb_define_singleton_method(rb_mProcess
, "abort", f_abort
, -1);
8719 rb_define_singleton_method(rb_mProcess
, "last_status", proc_s_last_status
, 0);
8720 rb_define_singleton_method(rb_mProcess
, "_fork", rb_proc__fork
, 0);
8722 rb_define_module_function(rb_mProcess
, "kill", proc_rb_f_kill
, -1);
8723 rb_define_module_function(rb_mProcess
, "wait", proc_m_wait
, -1);
8724 rb_define_module_function(rb_mProcess
, "wait2", proc_wait2
, -1);
8725 rb_define_module_function(rb_mProcess
, "waitpid", proc_m_wait
, -1);
8726 rb_define_module_function(rb_mProcess
, "waitpid2", proc_wait2
, -1);
8727 rb_define_module_function(rb_mProcess
, "waitall", proc_waitall
, 0);
8728 rb_define_module_function(rb_mProcess
, "detach", proc_detach
, 1);
8731 rb_cWaiter
= rb_define_class_under(rb_mProcess
, "Waiter", rb_cThread
);
8732 rb_undef_alloc_func(rb_cWaiter
);
8733 rb_undef_method(CLASS_OF(rb_cWaiter
), "new");
8734 rb_define_method(rb_cWaiter
, "pid", detach_process_pid
, 0);
8736 rb_cProcessStatus
= rb_define_class_under(rb_mProcess
, "Status", rb_cObject
);
8737 rb_define_alloc_func(rb_cProcessStatus
, rb_process_status_allocate
);
8738 rb_undef_method(CLASS_OF(rb_cProcessStatus
), "new");
8739 rb_marshal_define_compat(rb_cProcessStatus
, rb_cObject
,
8740 process_status_dump
, process_status_load
);
8742 rb_define_singleton_method(rb_cProcessStatus
, "wait", rb_process_status_waitv
, -1);
8744 rb_define_method(rb_cProcessStatus
, "==", pst_equal
, 1);
8745 rb_define_method(rb_cProcessStatus
, "&", pst_bitand
, 1);
8746 rb_define_method(rb_cProcessStatus
, ">>", pst_rshift
, 1);
8747 rb_define_method(rb_cProcessStatus
, "to_i", pst_to_i
, 0);
8748 rb_define_method(rb_cProcessStatus
, "to_s", pst_to_s
, 0);
8749 rb_define_method(rb_cProcessStatus
, "inspect", pst_inspect
, 0);
8751 rb_define_method(rb_cProcessStatus
, "pid", pst_pid_m
, 0);
8753 rb_define_method(rb_cProcessStatus
, "stopped?", pst_wifstopped
, 0);
8754 rb_define_method(rb_cProcessStatus
, "stopsig", pst_wstopsig
, 0);
8755 rb_define_method(rb_cProcessStatus
, "signaled?", pst_wifsignaled
, 0);
8756 rb_define_method(rb_cProcessStatus
, "termsig", pst_wtermsig
, 0);
8757 rb_define_method(rb_cProcessStatus
, "exited?", pst_wifexited
, 0);
8758 rb_define_method(rb_cProcessStatus
, "exitstatus", pst_wexitstatus
, 0);
8759 rb_define_method(rb_cProcessStatus
, "success?", pst_success_p
, 0);
8760 rb_define_method(rb_cProcessStatus
, "coredump?", pst_wcoredump
, 0);
8762 rb_define_module_function(rb_mProcess
, "pid", proc_get_pid
, 0);
8763 rb_define_module_function(rb_mProcess
, "ppid", proc_get_ppid
, 0);
8765 rb_define_module_function(rb_mProcess
, "getpgrp", proc_getpgrp
, 0);
8766 rb_define_module_function(rb_mProcess
, "setpgrp", proc_setpgrp
, 0);
8767 rb_define_module_function(rb_mProcess
, "getpgid", proc_getpgid
, 1);
8768 rb_define_module_function(rb_mProcess
, "setpgid", proc_setpgid
, 2);
8770 rb_define_module_function(rb_mProcess
, "getsid", proc_getsid
, -1);
8771 rb_define_module_function(rb_mProcess
, "setsid", proc_setsid
, 0);
8773 rb_define_module_function(rb_mProcess
, "getpriority", proc_getpriority
, 2);
8774 rb_define_module_function(rb_mProcess
, "setpriority", proc_setpriority
, 3);
8776 #ifdef HAVE_GETPRIORITY
8777 /* see Process.setpriority */
8778 rb_define_const(rb_mProcess
, "PRIO_PROCESS", INT2FIX(PRIO_PROCESS
));
8779 /* see Process.setpriority */
8780 rb_define_const(rb_mProcess
, "PRIO_PGRP", INT2FIX(PRIO_PGRP
));
8781 /* see Process.setpriority */
8782 rb_define_const(rb_mProcess
, "PRIO_USER", INT2FIX(PRIO_USER
));
8785 rb_define_module_function(rb_mProcess
, "getrlimit", proc_getrlimit
, 1);
8786 rb_define_module_function(rb_mProcess
, "setrlimit", proc_setrlimit
, -1);
8787 #if defined(RLIM2NUM) && defined(RLIM_INFINITY)
8789 VALUE inf
= RLIM2NUM(RLIM_INFINITY
);
8790 #ifdef RLIM_SAVED_MAX
8792 VALUE v
= RLIM_INFINITY
== RLIM_SAVED_MAX
? inf
: RLIM2NUM(RLIM_SAVED_MAX
);
8793 /* see Process.setrlimit */
8794 rb_define_const(rb_mProcess
, "RLIM_SAVED_MAX", v
);
8797 /* see Process.setrlimit */
8798 rb_define_const(rb_mProcess
, "RLIM_INFINITY", inf
);
8799 #ifdef RLIM_SAVED_CUR
8801 VALUE v
= RLIM_INFINITY
== RLIM_SAVED_CUR
? inf
: RLIM2NUM(RLIM_SAVED_CUR
);
8802 /* see Process.setrlimit */
8803 rb_define_const(rb_mProcess
, "RLIM_SAVED_CUR", v
);
8808 /* Maximum size of the process's virtual memory (address space) in bytes.
8810 * see the system getrlimit(2) manual for details.
8812 rb_define_const(rb_mProcess
, "RLIMIT_AS", INT2FIX(RLIMIT_AS
));
8815 /* Maximum size of the core file.
8817 * see the system getrlimit(2) manual for details.
8819 rb_define_const(rb_mProcess
, "RLIMIT_CORE", INT2FIX(RLIMIT_CORE
));
8822 /* CPU time limit in seconds.
8824 * see the system getrlimit(2) manual for details.
8826 rb_define_const(rb_mProcess
, "RLIMIT_CPU", INT2FIX(RLIMIT_CPU
));
8829 /* Maximum size of the process's data segment.
8831 * see the system getrlimit(2) manual for details.
8833 rb_define_const(rb_mProcess
, "RLIMIT_DATA", INT2FIX(RLIMIT_DATA
));
8836 /* Maximum size of files that the process may create.
8838 * see the system getrlimit(2) manual for details.
8840 rb_define_const(rb_mProcess
, "RLIMIT_FSIZE", INT2FIX(RLIMIT_FSIZE
));
8842 #ifdef RLIMIT_MEMLOCK
8843 /* Maximum number of bytes of memory that may be locked into RAM.
8845 * see the system getrlimit(2) manual for details.
8847 rb_define_const(rb_mProcess
, "RLIMIT_MEMLOCK", INT2FIX(RLIMIT_MEMLOCK
));
8849 #ifdef RLIMIT_MSGQUEUE
8850 /* Specifies the limit on the number of bytes that can be allocated
8851 * for POSIX message queues for the real user ID of the calling process.
8853 * see the system getrlimit(2) manual for details.
8855 rb_define_const(rb_mProcess
, "RLIMIT_MSGQUEUE", INT2FIX(RLIMIT_MSGQUEUE
));
8858 /* Specifies a ceiling to which the process's nice value can be raised.
8860 * see the system getrlimit(2) manual for details.
8862 rb_define_const(rb_mProcess
, "RLIMIT_NICE", INT2FIX(RLIMIT_NICE
));
8864 #ifdef RLIMIT_NOFILE
8865 /* Specifies a value one greater than the maximum file descriptor
8866 * number that can be opened by this process.
8868 * see the system getrlimit(2) manual for details.
8870 rb_define_const(rb_mProcess
, "RLIMIT_NOFILE", INT2FIX(RLIMIT_NOFILE
));
8873 /* The maximum number of processes that can be created for the
8874 * real user ID of the calling process.
8876 * see the system getrlimit(2) manual for details.
8878 rb_define_const(rb_mProcess
, "RLIMIT_NPROC", INT2FIX(RLIMIT_NPROC
));
8881 /* Specifies the limit (in pages) of the process's resident set.
8883 * see the system getrlimit(2) manual for details.
8885 rb_define_const(rb_mProcess
, "RLIMIT_RSS", INT2FIX(RLIMIT_RSS
));
8887 #ifdef RLIMIT_RTPRIO
8888 /* Specifies a ceiling on the real-time priority that may be set for this process.
8890 * see the system getrlimit(2) manual for details.
8892 rb_define_const(rb_mProcess
, "RLIMIT_RTPRIO", INT2FIX(RLIMIT_RTPRIO
));
8894 #ifdef RLIMIT_RTTIME
8895 /* Specifies limit on CPU time this process scheduled under a real-time
8896 * scheduling policy can consume.
8898 * see the system getrlimit(2) manual for details.
8900 rb_define_const(rb_mProcess
, "RLIMIT_RTTIME", INT2FIX(RLIMIT_RTTIME
));
8902 #ifdef RLIMIT_SBSIZE
8903 /* Maximum size of the socket buffer.
8905 rb_define_const(rb_mProcess
, "RLIMIT_SBSIZE", INT2FIX(RLIMIT_SBSIZE
));
8907 #ifdef RLIMIT_SIGPENDING
8908 /* Specifies a limit on the number of signals that may be queued for
8909 * the real user ID of the calling process.
8911 * see the system getrlimit(2) manual for details.
8913 rb_define_const(rb_mProcess
, "RLIMIT_SIGPENDING", INT2FIX(RLIMIT_SIGPENDING
));
8916 /* Maximum size of the stack, in bytes.
8918 * see the system getrlimit(2) manual for details.
8920 rb_define_const(rb_mProcess
, "RLIMIT_STACK", INT2FIX(RLIMIT_STACK
));
8924 rb_define_module_function(rb_mProcess
, "uid", proc_getuid
, 0);
8925 rb_define_module_function(rb_mProcess
, "uid=", proc_setuid
, 1);
8926 rb_define_module_function(rb_mProcess
, "gid", proc_getgid
, 0);
8927 rb_define_module_function(rb_mProcess
, "gid=", proc_setgid
, 1);
8928 rb_define_module_function(rb_mProcess
, "euid", proc_geteuid
, 0);
8929 rb_define_module_function(rb_mProcess
, "euid=", proc_seteuid_m
, 1);
8930 rb_define_module_function(rb_mProcess
, "egid", proc_getegid
, 0);
8931 rb_define_module_function(rb_mProcess
, "egid=", proc_setegid_m
, 1);
8932 rb_define_module_function(rb_mProcess
, "initgroups", proc_initgroups
, 2);
8933 rb_define_module_function(rb_mProcess
, "groups", proc_getgroups
, 0);
8934 rb_define_module_function(rb_mProcess
, "groups=", proc_setgroups
, 1);
8935 rb_define_module_function(rb_mProcess
, "maxgroups", proc_getmaxgroups
, 0);
8936 rb_define_module_function(rb_mProcess
, "maxgroups=", proc_setmaxgroups
, 1);
8938 rb_define_module_function(rb_mProcess
, "daemon", proc_daemon
, -1);
8940 rb_define_module_function(rb_mProcess
, "times", rb_proc_times
, 0);
8942 #ifdef CLOCK_REALTIME
8943 /* see Process.clock_gettime */
8944 rb_define_const(rb_mProcess
, "CLOCK_REALTIME", CLOCKID2NUM(CLOCK_REALTIME
));
8945 #elif defined(RUBY_GETTIMEOFDAY_BASED_CLOCK_REALTIME)
8946 /* see Process.clock_gettime */
8947 rb_define_const(rb_mProcess
, "CLOCK_REALTIME", RUBY_GETTIMEOFDAY_BASED_CLOCK_REALTIME
);
8949 #ifdef CLOCK_MONOTONIC
8950 /* see Process.clock_gettime */
8951 rb_define_const(rb_mProcess
, "CLOCK_MONOTONIC", CLOCKID2NUM(CLOCK_MONOTONIC
));
8952 #elif defined(RUBY_MACH_ABSOLUTE_TIME_BASED_CLOCK_MONOTONIC)
8953 /* see Process.clock_gettime */
8954 rb_define_const(rb_mProcess
, "CLOCK_MONOTONIC", RUBY_MACH_ABSOLUTE_TIME_BASED_CLOCK_MONOTONIC
);
8956 #ifdef CLOCK_PROCESS_CPUTIME_ID
8957 /* see Process.clock_gettime */
8958 rb_define_const(rb_mProcess
, "CLOCK_PROCESS_CPUTIME_ID", CLOCKID2NUM(CLOCK_PROCESS_CPUTIME_ID
));
8959 #elif defined(RUBY_GETRUSAGE_BASED_CLOCK_PROCESS_CPUTIME_ID)
8960 /* see Process.clock_gettime */
8961 rb_define_const(rb_mProcess
, "CLOCK_PROCESS_CPUTIME_ID", RUBY_GETRUSAGE_BASED_CLOCK_PROCESS_CPUTIME_ID
);
8963 #ifdef CLOCK_THREAD_CPUTIME_ID
8964 /* see Process.clock_gettime */
8965 rb_define_const(rb_mProcess
, "CLOCK_THREAD_CPUTIME_ID", CLOCKID2NUM(CLOCK_THREAD_CPUTIME_ID
));
8967 #ifdef CLOCK_VIRTUAL
8968 /* see Process.clock_gettime */
8969 rb_define_const(rb_mProcess
, "CLOCK_VIRTUAL", CLOCKID2NUM(CLOCK_VIRTUAL
));
8972 /* see Process.clock_gettime */
8973 rb_define_const(rb_mProcess
, "CLOCK_PROF", CLOCKID2NUM(CLOCK_PROF
));
8975 #ifdef CLOCK_REALTIME_FAST
8976 /* see Process.clock_gettime */
8977 rb_define_const(rb_mProcess
, "CLOCK_REALTIME_FAST", CLOCKID2NUM(CLOCK_REALTIME_FAST
));
8979 #ifdef CLOCK_REALTIME_PRECISE
8980 /* see Process.clock_gettime */
8981 rb_define_const(rb_mProcess
, "CLOCK_REALTIME_PRECISE", CLOCKID2NUM(CLOCK_REALTIME_PRECISE
));
8983 #ifdef CLOCK_REALTIME_COARSE
8984 /* see Process.clock_gettime */
8985 rb_define_const(rb_mProcess
, "CLOCK_REALTIME_COARSE", CLOCKID2NUM(CLOCK_REALTIME_COARSE
));
8987 #ifdef CLOCK_REALTIME_ALARM
8988 /* see Process.clock_gettime */
8989 rb_define_const(rb_mProcess
, "CLOCK_REALTIME_ALARM", CLOCKID2NUM(CLOCK_REALTIME_ALARM
));
8991 #ifdef CLOCK_MONOTONIC_FAST
8992 /* see Process.clock_gettime */
8993 rb_define_const(rb_mProcess
, "CLOCK_MONOTONIC_FAST", CLOCKID2NUM(CLOCK_MONOTONIC_FAST
));
8995 #ifdef CLOCK_MONOTONIC_PRECISE
8996 /* see Process.clock_gettime */
8997 rb_define_const(rb_mProcess
, "CLOCK_MONOTONIC_PRECISE", CLOCKID2NUM(CLOCK_MONOTONIC_PRECISE
));
8999 #ifdef CLOCK_MONOTONIC_RAW
9000 /* see Process.clock_gettime */
9001 rb_define_const(rb_mProcess
, "CLOCK_MONOTONIC_RAW", CLOCKID2NUM(CLOCK_MONOTONIC_RAW
));
9003 #ifdef CLOCK_MONOTONIC_RAW_APPROX
9004 /* see Process.clock_gettime */
9005 rb_define_const(rb_mProcess
, "CLOCK_MONOTONIC_RAW_APPROX", CLOCKID2NUM(CLOCK_MONOTONIC_RAW_APPROX
));
9007 #ifdef CLOCK_MONOTONIC_COARSE
9008 /* see Process.clock_gettime */
9009 rb_define_const(rb_mProcess
, "CLOCK_MONOTONIC_COARSE", CLOCKID2NUM(CLOCK_MONOTONIC_COARSE
));
9011 #ifdef CLOCK_BOOTTIME
9012 /* see Process.clock_gettime */
9013 rb_define_const(rb_mProcess
, "CLOCK_BOOTTIME", CLOCKID2NUM(CLOCK_BOOTTIME
));
9015 #ifdef CLOCK_BOOTTIME_ALARM
9016 /* see Process.clock_gettime */
9017 rb_define_const(rb_mProcess
, "CLOCK_BOOTTIME_ALARM", CLOCKID2NUM(CLOCK_BOOTTIME_ALARM
));
9020 /* see Process.clock_gettime */
9021 rb_define_const(rb_mProcess
, "CLOCK_UPTIME", CLOCKID2NUM(CLOCK_UPTIME
));
9023 #ifdef CLOCK_UPTIME_FAST
9024 /* see Process.clock_gettime */
9025 rb_define_const(rb_mProcess
, "CLOCK_UPTIME_FAST", CLOCKID2NUM(CLOCK_UPTIME_FAST
));
9027 #ifdef CLOCK_UPTIME_PRECISE
9028 /* see Process.clock_gettime */
9029 rb_define_const(rb_mProcess
, "CLOCK_UPTIME_PRECISE", CLOCKID2NUM(CLOCK_UPTIME_PRECISE
));
9031 #ifdef CLOCK_UPTIME_RAW
9032 /* see Process.clock_gettime */
9033 rb_define_const(rb_mProcess
, "CLOCK_UPTIME_RAW", CLOCKID2NUM(CLOCK_UPTIME_RAW
));
9035 #ifdef CLOCK_UPTIME_RAW_APPROX
9036 /* see Process.clock_gettime */
9037 rb_define_const(rb_mProcess
, "CLOCK_UPTIME_RAW_APPROX", CLOCKID2NUM(CLOCK_UPTIME_RAW_APPROX
));
9040 /* see Process.clock_gettime */
9041 rb_define_const(rb_mProcess
, "CLOCK_SECOND", CLOCKID2NUM(CLOCK_SECOND
));
9044 /* see Process.clock_gettime */
9045 rb_define_const(rb_mProcess
, "CLOCK_TAI", CLOCKID2NUM(CLOCK_TAI
));
9047 rb_define_module_function(rb_mProcess
, "clock_gettime", rb_clock_gettime
, -1);
9048 rb_define_module_function(rb_mProcess
, "clock_getres", rb_clock_getres
, -1);
9050 #if defined(HAVE_TIMES) || defined(_WIN32)
9051 /* Placeholder for rusage */
9052 rb_cProcessTms
= rb_struct_define_under(rb_mProcess
, "Tms", "utime", "stime", "cutime", "cstime", NULL
);
9055 SAVED_USER_ID
= geteuid();
9056 SAVED_GROUP_ID
= getegid();
9058 rb_mProcUID
= rb_define_module_under(rb_mProcess
, "UID");
9059 rb_mProcGID
= rb_define_module_under(rb_mProcess
, "GID");
9061 rb_define_module_function(rb_mProcUID
, "rid", proc_getuid
, 0);
9062 rb_define_module_function(rb_mProcGID
, "rid", proc_getgid
, 0);
9063 rb_define_module_function(rb_mProcUID
, "eid", proc_geteuid
, 0);
9064 rb_define_module_function(rb_mProcGID
, "eid", proc_getegid
, 0);
9065 rb_define_module_function(rb_mProcUID
, "change_privilege", p_uid_change_privilege
, 1);
9066 rb_define_module_function(rb_mProcGID
, "change_privilege", p_gid_change_privilege
, 1);
9067 rb_define_module_function(rb_mProcUID
, "grant_privilege", p_uid_grant_privilege
, 1);
9068 rb_define_module_function(rb_mProcGID
, "grant_privilege", p_gid_grant_privilege
, 1);
9069 rb_define_alias(rb_singleton_class(rb_mProcUID
), "eid=", "grant_privilege");
9070 rb_define_alias(rb_singleton_class(rb_mProcGID
), "eid=", "grant_privilege");
9071 rb_define_module_function(rb_mProcUID
, "re_exchange", p_uid_exchange
, 0);
9072 rb_define_module_function(rb_mProcGID
, "re_exchange", p_gid_exchange
, 0);
9073 rb_define_module_function(rb_mProcUID
, "re_exchangeable?", p_uid_exchangeable
, 0);
9074 rb_define_module_function(rb_mProcGID
, "re_exchangeable?", p_gid_exchangeable
, 0);
9075 rb_define_module_function(rb_mProcUID
, "sid_available?", p_uid_have_saved_id
, 0);
9076 rb_define_module_function(rb_mProcGID
, "sid_available?", p_gid_have_saved_id
, 0);
9077 rb_define_module_function(rb_mProcUID
, "switch", p_uid_switch
, 0);
9078 rb_define_module_function(rb_mProcGID
, "switch", p_gid_switch
, 0);
9079 #ifdef p_uid_from_name
9080 rb_define_module_function(rb_mProcUID
, "from_name", p_uid_from_name
, 1);
9082 #ifdef p_gid_from_name
9083 rb_define_module_function(rb_mProcGID
, "from_name", p_gid_from_name
, 1);
9086 rb_mProcID_Syscall
= rb_define_module_under(rb_mProcess
, "Sys");
9088 rb_define_module_function(rb_mProcID_Syscall
, "getuid", proc_getuid
, 0);
9089 rb_define_module_function(rb_mProcID_Syscall
, "geteuid", proc_geteuid
, 0);
9090 rb_define_module_function(rb_mProcID_Syscall
, "getgid", proc_getgid
, 0);
9091 rb_define_module_function(rb_mProcID_Syscall
, "getegid", proc_getegid
, 0);
9093 rb_define_module_function(rb_mProcID_Syscall
, "setuid", p_sys_setuid
, 1);
9094 rb_define_module_function(rb_mProcID_Syscall
, "setgid", p_sys_setgid
, 1);
9096 rb_define_module_function(rb_mProcID_Syscall
, "setruid", p_sys_setruid
, 1);
9097 rb_define_module_function(rb_mProcID_Syscall
, "setrgid", p_sys_setrgid
, 1);
9099 rb_define_module_function(rb_mProcID_Syscall
, "seteuid", p_sys_seteuid
, 1);
9100 rb_define_module_function(rb_mProcID_Syscall
, "setegid", p_sys_setegid
, 1);
9102 rb_define_module_function(rb_mProcID_Syscall
, "setreuid", p_sys_setreuid
, 2);
9103 rb_define_module_function(rb_mProcID_Syscall
, "setregid", p_sys_setregid
, 2);
9105 rb_define_module_function(rb_mProcID_Syscall
, "setresuid", p_sys_setresuid
, 3);
9106 rb_define_module_function(rb_mProcID_Syscall
, "setresgid", p_sys_setresgid
, 3);
9107 rb_define_module_function(rb_mProcID_Syscall
, "issetugid", p_sys_issetugid
, 0);
9113 id_in
= rb_intern_const("in");
9114 id_out
= rb_intern_const("out");
9115 id_err
= rb_intern_const("err");
9116 id_pid
= rb_intern_const("pid");
9117 id_uid
= rb_intern_const("uid");
9118 id_gid
= rb_intern_const("gid");
9119 id_close
= rb_intern_const("close");
9120 id_child
= rb_intern_const("child");
9122 id_pgroup
= rb_intern_const("pgroup");
9125 id_new_pgroup
= rb_intern_const("new_pgroup");
9127 id_unsetenv_others
= rb_intern_const("unsetenv_others");
9128 id_chdir
= rb_intern_const("chdir");
9129 id_umask
= rb_intern_const("umask");
9130 id_close_others
= rb_intern_const("close_others");
9131 id_nanosecond
= rb_intern_const("nanosecond");
9132 id_microsecond
= rb_intern_const("microsecond");
9133 id_millisecond
= rb_intern_const("millisecond");
9134 id_second
= rb_intern_const("second");
9135 id_float_microsecond
= rb_intern_const("float_microsecond");
9136 id_float_millisecond
= rb_intern_const("float_millisecond");
9137 id_float_second
= rb_intern_const("float_second");
9138 id_GETTIMEOFDAY_BASED_CLOCK_REALTIME
= rb_intern_const("GETTIMEOFDAY_BASED_CLOCK_REALTIME");
9139 id_TIME_BASED_CLOCK_REALTIME
= rb_intern_const("TIME_BASED_CLOCK_REALTIME");
9141 id_TIMES_BASED_CLOCK_MONOTONIC
= rb_intern_const("TIMES_BASED_CLOCK_MONOTONIC");
9142 id_TIMES_BASED_CLOCK_PROCESS_CPUTIME_ID
= rb_intern_const("TIMES_BASED_CLOCK_PROCESS_CPUTIME_ID");
9145 id_GETRUSAGE_BASED_CLOCK_PROCESS_CPUTIME_ID
= rb_intern_const("GETRUSAGE_BASED_CLOCK_PROCESS_CPUTIME_ID");
9147 id_CLOCK_BASED_CLOCK_PROCESS_CPUTIME_ID
= rb_intern_const("CLOCK_BASED_CLOCK_PROCESS_CPUTIME_ID");
9149 id_MACH_ABSOLUTE_TIME_BASED_CLOCK_MONOTONIC
= rb_intern_const("MACH_ABSOLUTE_TIME_BASED_CLOCK_MONOTONIC");
9151 id_hertz
= rb_intern_const("hertz");