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
)
6726 return RBOOL(issetugid());
6729 #define p_sys_issetugid rb_f_notimplement
6735 * Process.gid -> integer
6736 * Process::GID.rid -> integer
6737 * Process::Sys.getgid -> integer
6739 * Returns the (real) group ID for this process.
6741 * Process.gid #=> 500
6745 proc_getgid(VALUE obj
)
6747 rb_gid_t gid
= getgid();
6748 return GIDT2NUM(gid
);
6752 #if defined(HAVE_SETRESGID) || defined(HAVE_SETREGID) || defined(HAVE_SETRGID) || defined(HAVE_SETGID)
6755 * Process.gid= integer -> integer
6757 * Sets the group ID for this process.
6761 proc_setgid(VALUE obj
, VALUE id
)
6768 #if defined(HAVE_SETRESGID)
6769 if (setresgid(gid
, -1, -1) < 0) rb_sys_fail(0);
6770 #elif defined HAVE_SETREGID
6771 if (setregid(gid
, -1) < 0) rb_sys_fail(0);
6772 #elif defined HAVE_SETRGID
6773 if (setrgid(gid
) < 0) rb_sys_fail(0);
6774 #elif defined HAVE_SETGID
6776 if (getegid() == gid
) {
6777 if (setgid(gid
) < 0) rb_sys_fail(0);
6784 return GIDT2NUM(gid
);
6787 #define proc_setgid rb_f_notimplement
6791 #if defined(_SC_NGROUPS_MAX) || defined(NGROUPS_MAX)
6793 * Maximum supplementary groups are platform dependent.
6794 * FWIW, 65536 is enough big for our supported OSs.
6796 * OS Name max groups
6797 * -----------------------------------------------
6798 * Linux Kernel >= 2.6.3 65536
6799 * Linux Kernel < 2.6.3 32
6801 * IBM AIX 5.3 ... 6.1 128
6802 * IBM AIX 7.1 128 (can be configured to be up to 2048)
6803 * OpenBSD, NetBSD 16
6805 * FreeBSD >=8.0 1023
6806 * Darwin (Mac OS X) 16
6807 * Sun Solaris 7,8,9,10 16
6808 * Sun Solaris 11 / OpenSolaris 1024
6812 static int _maxgroups
= -1;
6814 get_sc_ngroups_max(void)
6816 #ifdef _SC_NGROUPS_MAX
6817 return (int)sysconf(_SC_NGROUPS_MAX
);
6818 #elif defined(NGROUPS_MAX)
6819 return (int)NGROUPS_MAX
;
6827 if (_maxgroups
< 0) {
6828 _maxgroups
= get_sc_ngroups_max();
6830 _maxgroups
= RB_MAX_GROUPS
;
6839 #ifdef HAVE_GETGROUPS
6842 * Process.groups -> array
6844 * Get an Array of the group IDs in the
6845 * supplemental group access list for this process.
6847 * Process.groups #=> [27, 6, 10, 11]
6849 * Note that this method is just a wrapper of getgroups(2).
6850 * This means that the following characteristics of
6851 * the result completely depend on your system:
6853 * - the result is sorted
6854 * - the result includes effective GIDs
6855 * - the result does not include duplicated GIDs
6857 * You can make sure to get a sorted unique GID list of
6858 * the current process by this expression:
6860 * Process.groups.uniq.sort
6865 proc_getgroups(VALUE obj
)
6871 ngroups
= getgroups(0, NULL
);
6875 groups
= ALLOCV_N(rb_gid_t
, tmp
, ngroups
);
6877 ngroups
= getgroups(ngroups
, groups
);
6882 for (i
= 0; i
< ngroups
; i
++)
6883 rb_ary_push(ary
, GIDT2NUM(groups
[i
]));
6890 #define proc_getgroups rb_f_notimplement
6894 #ifdef HAVE_SETGROUPS
6897 * Process.groups= array -> array
6899 * Set the supplemental group access list to the given
6900 * Array of group IDs.
6902 * Process.groups #=> [0, 1, 2, 3, 4, 6, 10, 11, 20, 26, 27]
6903 * Process.groups = [27, 6, 10, 11] #=> [27, 6, 10, 11]
6904 * Process.groups #=> [27, 6, 10, 11]
6909 proc_setgroups(VALUE obj
, VALUE ary
)
6916 Check_Type(ary
, T_ARRAY
);
6918 ngroups
= RARRAY_LENINT(ary
);
6919 if (ngroups
> maxgroups())
6920 rb_raise(rb_eArgError
, "too many groups, %d max", maxgroups());
6922 groups
= ALLOCV_N(rb_gid_t
, tmp
, ngroups
);
6924 for (i
= 0; i
< ngroups
; i
++) {
6925 VALUE g
= RARRAY_AREF(ary
, i
);
6927 groups
[i
] = OBJ2GID1(g
);
6931 if (setgroups(ngroups
, groups
) == -1) /* ngroups <= maxgroups */
6936 return proc_getgroups(obj
);
6939 #define proc_setgroups rb_f_notimplement
6943 #ifdef HAVE_INITGROUPS
6946 * Process.initgroups(username, gid) -> array
6948 * Initializes the supplemental group access list by reading the
6949 * system group database and using all groups of which the given user
6950 * is a member. The group with the specified <em>gid</em> is also
6951 * added to the list. Returns the resulting Array of the
6952 * gids of all the groups in the supplementary group access list. Not
6953 * available on all platforms.
6955 * Process.groups #=> [0, 1, 2, 3, 4, 6, 10, 11, 20, 26, 27]
6956 * Process.initgroups( "mgranger", 30 ) #=> [30, 6, 10, 11]
6957 * Process.groups #=> [30, 6, 10, 11]
6962 proc_initgroups(VALUE obj
, VALUE uname
, VALUE base_grp
)
6964 if (initgroups(StringValueCStr(uname
), OBJ2GID(base_grp
)) != 0) {
6967 return proc_getgroups(obj
);
6970 #define proc_initgroups rb_f_notimplement
6973 #if defined(_SC_NGROUPS_MAX) || defined(NGROUPS_MAX)
6976 * Process.maxgroups -> integer
6978 * Returns the maximum number of gids allowed in the supplemental
6979 * group access list.
6981 * Process.maxgroups #=> 32
6985 proc_getmaxgroups(VALUE obj
)
6987 return INT2FIX(maxgroups());
6990 #define proc_getmaxgroups rb_f_notimplement
6993 #ifdef HAVE_SETGROUPS
6996 * Process.maxgroups= integer -> integer
6998 * Sets the maximum number of gids allowed in the supplemental group
7003 proc_setmaxgroups(VALUE obj
, VALUE val
)
7005 int ngroups
= FIX2INT(val
);
7006 int ngroups_max
= get_sc_ngroups_max();
7009 rb_raise(rb_eArgError
, "maxgroups %d should be positive", ngroups
);
7011 if (ngroups
> RB_MAX_GROUPS
)
7012 ngroups
= RB_MAX_GROUPS
;
7014 if (ngroups_max
> 0 && ngroups
> ngroups_max
)
7015 ngroups
= ngroups_max
;
7017 _maxgroups
= ngroups
;
7019 return INT2FIX(_maxgroups
);
7022 #define proc_setmaxgroups rb_f_notimplement
7025 #if defined(HAVE_DAEMON) || (defined(HAVE_WORKING_FORK) && defined(HAVE_SETSID))
7026 static int rb_daemon(int nochdir
, int noclose
);
7030 * Process.daemon() -> 0
7031 * Process.daemon(nochdir=nil,noclose=nil) -> 0
7033 * Detach the process from controlling terminal and run in
7034 * the background as system daemon. Unless the argument
7035 * nochdir is true (i.e. non false), it changes the current
7036 * working directory to the root ("/"). Unless the argument
7037 * noclose is true, daemon() will redirect standard input,
7038 * standard output and standard error to /dev/null.
7039 * Return zero on success, or raise one of Errno::*.
7043 proc_daemon(int argc
, VALUE
*argv
, VALUE _
)
7045 int n
, nochdir
= FALSE
, noclose
= FALSE
;
7047 switch (rb_check_arity(argc
, 0, 2)) {
7048 case 2: noclose
= TO_BOOL(argv
[1], "noclose");
7049 case 1: nochdir
= TO_BOOL(argv
[0], "nochdir");
7053 n
= rb_daemon(nochdir
, noclose
);
7054 if (n
< 0) rb_sys_fail("daemon");
7059 rb_daemon(int nochdir
, int noclose
)
7063 if (mjit_enabled
) mjit_pause(false); // Don't leave locked mutex to child.
7065 err
= daemon(nochdir
, noclose
);
7067 rb_thread_atfork(); /* calls mjit_resume() */
7071 #define fork_daemon() \
7072 switch (rb_fork_ruby(NULL)) { \
7073 case -1: return -1; \
7075 default: _exit(EXIT_SUCCESS); \
7080 if (setsid() < 0) return -1;
7082 /* must not be process-leader */
7088 if (!noclose
&& (n
= rb_cloexec_open("/dev/null", O_RDWR
, 0)) != -1) {
7089 rb_update_max_fd(n
);
7100 #define proc_daemon rb_f_notimplement
7103 /********************************************************************
7105 * Document-class: Process::GID
7107 * The Process::GID module contains a collection of
7108 * module functions which can be used to portably get, set, and
7109 * switch the current process's real, effective, and saved group IDs.
7113 static rb_gid_t SAVED_GROUP_ID
= -1;
7115 #ifdef BROKEN_SETREGID
7117 setregid(rb_gid_t rgid
, rb_gid_t egid
)
7119 if (rgid
!= (rb_gid_t
)-1 && rgid
!= getgid()) {
7120 if (egid
== (rb_gid_t
)-1) egid
= getegid();
7121 if (setgid(rgid
) < 0) return -1;
7123 if (egid
!= (rb_gid_t
)-1 && egid
!= getegid()) {
7124 if (setegid(egid
) < 0) return -1;
7132 * Process::GID.change_privilege(group) -> integer
7134 * Change the current process's real and effective group ID to that
7135 * specified by _group_. Returns the new group ID. Not
7136 * available on all platforms.
7138 * [Process.gid, Process.egid] #=> [0, 0]
7139 * Process::GID.change_privilege(33) #=> 33
7140 * [Process.gid, Process.egid] #=> [33, 33]
7144 p_gid_change_privilege(VALUE obj
, VALUE id
)
7152 if (geteuid() == 0) { /* root-user */
7153 #if defined(HAVE_SETRESGID)
7154 if (setresgid(gid
, gid
, gid
) < 0) rb_sys_fail(0);
7155 SAVED_GROUP_ID
= gid
;
7156 #elif defined HAVE_SETGID
7157 if (setgid(gid
) < 0) rb_sys_fail(0);
7158 SAVED_GROUP_ID
= gid
;
7159 #elif defined(HAVE_SETREGID) && !defined(OBSOLETE_SETREGID)
7160 if (getgid() == gid
) {
7161 if (SAVED_GROUP_ID
== gid
) {
7162 if (setregid(-1, gid
) < 0) rb_sys_fail(0);
7165 if (gid
== 0) { /* (r,e,s) == (root, y, x) */
7166 if (setregid(-1, SAVED_GROUP_ID
) < 0) rb_sys_fail(0);
7167 if (setregid(SAVED_GROUP_ID
, 0) < 0) rb_sys_fail(0);
7168 SAVED_GROUP_ID
= 0; /* (r,e,s) == (x, root, root) */
7169 if (setregid(gid
, gid
) < 0) rb_sys_fail(0);
7170 SAVED_GROUP_ID
= gid
;
7172 else { /* (r,e,s) == (z, y, x) */
7173 if (setregid(0, 0) < 0) rb_sys_fail(0);
7175 if (setregid(gid
, gid
) < 0) rb_sys_fail(0);
7176 SAVED_GROUP_ID
= gid
;
7181 if (setregid(gid
, gid
) < 0) rb_sys_fail(0);
7182 SAVED_GROUP_ID
= gid
;
7184 #elif defined(HAVE_SETRGID) && defined (HAVE_SETEGID)
7185 if (getgid() == gid
) {
7186 if (SAVED_GROUP_ID
== gid
) {
7187 if (setegid(gid
) < 0) rb_sys_fail(0);
7191 if (setegid(gid
) < 0) rb_sys_fail(0);
7192 if (setrgid(SAVED_GROUP_ID
) < 0) rb_sys_fail(0);
7194 if (setrgid(0) < 0) rb_sys_fail(0);
7197 if (setrgid(0) < 0) rb_sys_fail(0);
7199 if (setegid(gid
) < 0) rb_sys_fail(0);
7200 if (setrgid(gid
) < 0) rb_sys_fail(0);
7201 SAVED_GROUP_ID
= gid
;
7206 if (setegid(gid
) < 0) rb_sys_fail(0);
7207 if (setrgid(gid
) < 0) rb_sys_fail(0);
7208 SAVED_GROUP_ID
= gid
;
7214 else { /* unprivileged user */
7215 #if defined(HAVE_SETRESGID)
7216 if (setresgid((getgid() == gid
)? (rb_gid_t
)-1: gid
,
7217 (getegid() == gid
)? (rb_gid_t
)-1: gid
,
7218 (SAVED_GROUP_ID
== gid
)? (rb_gid_t
)-1: gid
) < 0) rb_sys_fail(0);
7219 SAVED_GROUP_ID
= gid
;
7220 #elif defined(HAVE_SETREGID) && !defined(OBSOLETE_SETREGID)
7221 if (SAVED_GROUP_ID
== gid
) {
7222 if (setregid((getgid() == gid
)? (rb_uid_t
)-1: gid
,
7223 (getegid() == gid
)? (rb_uid_t
)-1: gid
) < 0)
7226 else if (getgid() != gid
) {
7227 if (setregid(gid
, (getegid() == gid
)? (rb_uid_t
)-1: gid
) < 0)
7229 SAVED_GROUP_ID
= gid
;
7231 else if (/* getgid() == gid && */ getegid() != gid
) {
7232 if (setregid(getegid(), gid
) < 0) rb_sys_fail(0);
7233 SAVED_GROUP_ID
= gid
;
7234 if (setregid(gid
, -1) < 0) rb_sys_fail(0);
7236 else { /* getgid() == gid && getegid() == gid */
7237 if (setregid(-1, SAVED_GROUP_ID
) < 0) rb_sys_fail(0);
7238 if (setregid(SAVED_GROUP_ID
, gid
) < 0) rb_sys_fail(0);
7239 SAVED_GROUP_ID
= gid
;
7240 if (setregid(gid
, -1) < 0) rb_sys_fail(0);
7242 #elif defined(HAVE_SETRGID) && defined(HAVE_SETEGID)
7243 if (SAVED_GROUP_ID
== gid
) {
7244 if (getegid() != gid
&& setegid(gid
) < 0) rb_sys_fail(0);
7245 if (getgid() != gid
&& setrgid(gid
) < 0) rb_sys_fail(0);
7247 else if (/* SAVED_GROUP_ID != gid && */ getegid() == gid
) {
7248 if (getgid() != gid
) {
7249 if (setrgid(gid
) < 0) rb_sys_fail(0);
7250 SAVED_GROUP_ID
= gid
;
7253 if (setrgid(SAVED_GROUP_ID
) < 0) rb_sys_fail(0);
7254 SAVED_GROUP_ID
= gid
;
7255 if (setrgid(gid
) < 0) rb_sys_fail(0);
7258 else if (/* getegid() != gid && */ getgid() == gid
) {
7259 if (setegid(gid
) < 0) rb_sys_fail(0);
7260 if (setrgid(SAVED_GROUP_ID
) < 0) rb_sys_fail(0);
7261 SAVED_GROUP_ID
= gid
;
7262 if (setrgid(gid
) < 0) rb_sys_fail(0);
7265 rb_syserr_fail(EPERM
, 0);
7267 #elif defined HAVE_44BSD_SETGID
7268 if (getgid() == gid
) {
7269 /* (r,e,s)==(gid,?,?) ==> (gid,gid,gid) */
7270 if (setgid(gid
) < 0) rb_sys_fail(0);
7271 SAVED_GROUP_ID
= gid
;
7274 rb_syserr_fail(EPERM
, 0);
7276 #elif defined HAVE_SETEGID
7277 if (getgid() == gid
&& SAVED_GROUP_ID
== gid
) {
7278 if (setegid(gid
) < 0) rb_sys_fail(0);
7281 rb_syserr_fail(EPERM
, 0);
7283 #elif defined HAVE_SETGID
7284 if (getgid() == gid
&& SAVED_GROUP_ID
== gid
) {
7285 if (setgid(gid
) < 0) rb_sys_fail(0);
7288 rb_syserr_fail(EPERM
, 0);
7301 * Process.euid -> integer
7302 * Process::UID.eid -> integer
7303 * Process::Sys.geteuid -> integer
7305 * Returns the effective user ID for this process.
7307 * Process.euid #=> 501
7311 proc_geteuid(VALUE obj
)
7313 rb_uid_t euid
= geteuid();
7314 return UIDT2NUM(euid
);
7317 #if defined(HAVE_SETRESUID) || defined(HAVE_SETREUID) || defined(HAVE_SETEUID) || defined(HAVE_SETUID) || defined(_POSIX_SAVED_IDS)
7319 proc_seteuid(rb_uid_t uid
)
7321 #if defined(HAVE_SETRESUID)
7322 if (setresuid(-1, uid
, -1) < 0) rb_sys_fail(0);
7323 #elif defined HAVE_SETREUID
7324 if (setreuid(-1, uid
) < 0) rb_sys_fail(0);
7325 #elif defined HAVE_SETEUID
7326 if (seteuid(uid
) < 0) rb_sys_fail(0);
7327 #elif defined HAVE_SETUID
7328 if (uid
== getuid()) {
7329 if (setuid(uid
) < 0) rb_sys_fail(0);
7340 #if defined(HAVE_SETRESUID) || defined(HAVE_SETREUID) || defined(HAVE_SETEUID) || defined(HAVE_SETUID)
7343 * Process.euid= user
7345 * Sets the effective user ID for this process. Not available on all
7350 proc_seteuid_m(VALUE mod
, VALUE euid
)
7353 proc_seteuid(OBJ2UID(euid
));
7357 #define proc_seteuid_m rb_f_notimplement
7361 rb_seteuid_core(rb_uid_t euid
)
7363 #if defined(HAVE_SETRESUID) || (defined(HAVE_SETREUID) && !defined(OBSOLETE_SETREUID))
7369 #if defined(HAVE_SETRESUID) || (defined(HAVE_SETREUID) && !defined(OBSOLETE_SETREUID))
7373 #if defined(HAVE_SETRESUID)
7375 if (setresuid(-1,euid
,euid
) < 0) rb_sys_fail(0);
7376 SAVED_USER_ID
= euid
;
7379 if (setresuid(-1,euid
,-1) < 0) rb_sys_fail(0);
7381 #elif defined(HAVE_SETREUID) && !defined(OBSOLETE_SETREUID)
7382 if (setreuid(-1, euid
) < 0) rb_sys_fail(0);
7384 if (setreuid(euid
,uid
) < 0) rb_sys_fail(0);
7385 if (setreuid(uid
,euid
) < 0) rb_sys_fail(0);
7386 SAVED_USER_ID
= euid
;
7388 #elif defined HAVE_SETEUID
7389 if (seteuid(euid
) < 0) rb_sys_fail(0);
7390 #elif defined HAVE_SETUID
7391 if (geteuid() == 0) rb_sys_fail(0);
7392 if (setuid(euid
) < 0) rb_sys_fail(0);
7402 * Process::UID.grant_privilege(user) -> integer
7403 * Process::UID.eid= user -> integer
7405 * Set the effective user ID, and if possible, the saved user ID of
7406 * the process to the given _user_. Returns the new
7407 * effective user ID. Not available on all platforms.
7409 * [Process.uid, Process.euid] #=> [0, 0]
7410 * Process::UID.grant_privilege(31) #=> 31
7411 * [Process.uid, Process.euid] #=> [0, 31]
7415 p_uid_grant_privilege(VALUE obj
, VALUE id
)
7417 rb_seteuid_core(OBJ2UID(id
));
7424 * Process.egid -> integer
7425 * Process::GID.eid -> integer
7426 * Process::Sys.geteid -> integer
7428 * Returns the effective group ID for this process. Not available on
7431 * Process.egid #=> 500
7435 proc_getegid(VALUE obj
)
7437 rb_gid_t egid
= getegid();
7439 return GIDT2NUM(egid
);
7442 #if defined(HAVE_SETRESGID) || defined(HAVE_SETREGID) || defined(HAVE_SETEGID) || defined(HAVE_SETGID) || defined(_POSIX_SAVED_IDS)
7445 * Process.egid = integer -> integer
7447 * Sets the effective group ID for this process. Not available on all
7452 proc_setegid(VALUE obj
, VALUE egid
)
7454 #if defined(HAVE_SETRESGID) || defined(HAVE_SETREGID) || defined(HAVE_SETEGID) || defined(HAVE_SETGID)
7460 #if defined(HAVE_SETRESGID) || defined(HAVE_SETREGID) || defined(HAVE_SETEGID) || defined(HAVE_SETGID)
7461 gid
= OBJ2GID(egid
);
7464 #if defined(HAVE_SETRESGID)
7465 if (setresgid(-1, gid
, -1) < 0) rb_sys_fail(0);
7466 #elif defined HAVE_SETREGID
7467 if (setregid(-1, gid
) < 0) rb_sys_fail(0);
7468 #elif defined HAVE_SETEGID
7469 if (setegid(gid
) < 0) rb_sys_fail(0);
7470 #elif defined HAVE_SETGID
7471 if (gid
== getgid()) {
7472 if (setgid(gid
) < 0) rb_sys_fail(0);
7484 #if defined(HAVE_SETRESGID) || defined(HAVE_SETREGID) || defined(HAVE_SETEGID) || defined(HAVE_SETGID)
7485 #define proc_setegid_m proc_setegid
7487 #define proc_setegid_m rb_f_notimplement
7491 rb_setegid_core(rb_gid_t egid
)
7493 #if defined(HAVE_SETRESGID) || (defined(HAVE_SETREGID) && !defined(OBSOLETE_SETREGID))
7499 #if defined(HAVE_SETRESGID) || (defined(HAVE_SETREGID) && !defined(OBSOLETE_SETREGID))
7503 #if defined(HAVE_SETRESGID)
7505 if (setresgid(-1,egid
,egid
) < 0) rb_sys_fail(0);
7506 SAVED_GROUP_ID
= egid
;
7509 if (setresgid(-1,egid
,-1) < 0) rb_sys_fail(0);
7511 #elif defined(HAVE_SETREGID) && !defined(OBSOLETE_SETREGID)
7512 if (setregid(-1, egid
) < 0) rb_sys_fail(0);
7514 if (setregid(egid
,gid
) < 0) rb_sys_fail(0);
7515 if (setregid(gid
,egid
) < 0) rb_sys_fail(0);
7516 SAVED_GROUP_ID
= egid
;
7518 #elif defined HAVE_SETEGID
7519 if (setegid(egid
) < 0) rb_sys_fail(0);
7520 #elif defined HAVE_SETGID
7521 if (geteuid() == 0 /* root user */) rb_sys_fail(0);
7522 if (setgid(egid
) < 0) rb_sys_fail(0);
7532 * Process::GID.grant_privilege(group) -> integer
7533 * Process::GID.eid = group -> integer
7535 * Set the effective group ID, and if possible, the saved group ID of
7536 * the process to the given _group_. Returns the new
7537 * effective group ID. Not available on all platforms.
7539 * [Process.gid, Process.egid] #=> [0, 0]
7540 * Process::GID.grant_privilege(31) #=> 33
7541 * [Process.gid, Process.egid] #=> [0, 33]
7545 p_gid_grant_privilege(VALUE obj
, VALUE id
)
7547 rb_setegid_core(OBJ2GID(id
));
7554 * Process::UID.re_exchangeable? -> true or false
7556 * Returns +true+ if the real and effective user IDs of a
7557 * process may be exchanged on the current platform.
7562 p_uid_exchangeable(VALUE _
)
7564 #if defined(HAVE_SETRESUID)
7566 #elif defined(HAVE_SETREUID) && !defined(OBSOLETE_SETREUID)
7576 * Process::UID.re_exchange -> integer
7578 * Exchange real and effective user IDs and return the new effective
7579 * user ID. Not available on all platforms.
7581 * [Process.uid, Process.euid] #=> [0, 31]
7582 * Process::UID.re_exchange #=> 0
7583 * [Process.uid, Process.euid] #=> [31, 0]
7587 p_uid_exchange(VALUE obj
)
7590 #if defined(HAVE_SETRESUID) || (defined(HAVE_SETREUID) && !defined(OBSOLETE_SETREUID))
7597 #if defined(HAVE_SETRESUID) || (defined(HAVE_SETREUID) && !defined(OBSOLETE_SETREUID))
7601 #if defined(HAVE_SETRESUID)
7602 if (setresuid(euid
, uid
, uid
) < 0) rb_sys_fail(0);
7603 SAVED_USER_ID
= uid
;
7604 #elif defined(HAVE_SETREUID) && !defined(OBSOLETE_SETREUID)
7605 if (setreuid(euid
,uid
) < 0) rb_sys_fail(0);
7606 SAVED_USER_ID
= uid
;
7610 return UIDT2NUM(uid
);
7616 * Process::GID.re_exchangeable? -> true or false
7618 * Returns +true+ if the real and effective group IDs of a
7619 * process may be exchanged on the current platform.
7624 p_gid_exchangeable(VALUE _
)
7626 #if defined(HAVE_SETRESGID)
7628 #elif defined(HAVE_SETREGID) && !defined(OBSOLETE_SETREGID)
7638 * Process::GID.re_exchange -> integer
7640 * Exchange real and effective group IDs and return the new effective
7641 * group ID. Not available on all platforms.
7643 * [Process.gid, Process.egid] #=> [0, 33]
7644 * Process::GID.re_exchange #=> 0
7645 * [Process.gid, Process.egid] #=> [33, 0]
7649 p_gid_exchange(VALUE obj
)
7652 #if defined(HAVE_SETRESGID) || (defined(HAVE_SETREGID) && !defined(OBSOLETE_SETREGID))
7659 #if defined(HAVE_SETRESGID) || (defined(HAVE_SETREGID) && !defined(OBSOLETE_SETREGID))
7663 #if defined(HAVE_SETRESGID)
7664 if (setresgid(egid
, gid
, gid
) < 0) rb_sys_fail(0);
7665 SAVED_GROUP_ID
= gid
;
7666 #elif defined(HAVE_SETREGID) && !defined(OBSOLETE_SETREGID)
7667 if (setregid(egid
,gid
) < 0) rb_sys_fail(0);
7668 SAVED_GROUP_ID
= gid
;
7672 return GIDT2NUM(gid
);
7675 /* [MG] :FIXME: Is this correct? I'm not sure how to phrase this. */
7679 * Process::UID.sid_available? -> true or false
7681 * Returns +true+ if the current platform has saved user
7687 p_uid_have_saved_id(VALUE _
)
7689 #if defined(HAVE_SETRESUID) || defined(HAVE_SETEUID) || defined(_POSIX_SAVED_IDS)
7697 #if defined(HAVE_SETRESUID) || defined(HAVE_SETEUID) || defined(_POSIX_SAVED_IDS)
7699 p_uid_sw_ensure(VALUE i
)
7701 rb_uid_t id
= (rb_uid_t
/* narrowing */)i
;
7702 under_uid_switch
= 0;
7703 id
= rb_seteuid_core(id
);
7704 return UIDT2NUM(id
);
7710 * Process::UID.switch -> integer
7711 * Process::UID.switch {|| block} -> object
7713 * Switch the effective and real user IDs of the current process. If
7714 * a <em>block</em> is given, the user IDs will be switched back
7715 * after the block is executed. Returns the new effective user ID if
7716 * called without a block, and the return value of the block if one
7722 p_uid_switch(VALUE obj
)
7733 if (rb_block_given_p()) {
7734 under_uid_switch
= 1;
7735 return rb_ensure(rb_yield
, Qnil
, p_uid_sw_ensure
, SAVED_USER_ID
);
7738 return UIDT2NUM(euid
);
7741 else if (euid
!= SAVED_USER_ID
) {
7742 proc_seteuid(SAVED_USER_ID
);
7743 if (rb_block_given_p()) {
7744 under_uid_switch
= 1;
7745 return rb_ensure(rb_yield
, Qnil
, p_uid_sw_ensure
, euid
);
7748 return UIDT2NUM(uid
);
7752 rb_syserr_fail(EPERM
, 0);
7755 UNREACHABLE_RETURN(Qnil
);
7759 p_uid_sw_ensure(VALUE obj
)
7761 under_uid_switch
= 0;
7762 return p_uid_exchange(obj
);
7766 p_uid_switch(VALUE obj
)
7776 rb_syserr_fail(EPERM
, 0);
7778 p_uid_exchange(obj
);
7779 if (rb_block_given_p()) {
7780 under_uid_switch
= 1;
7781 return rb_ensure(rb_yield
, Qnil
, p_uid_sw_ensure
, obj
);
7784 return UIDT2NUM(euid
);
7790 /* [MG] :FIXME: Is this correct? I'm not sure how to phrase this. */
7794 * Process::GID.sid_available? -> true or false
7796 * Returns +true+ if the current platform has saved group
7802 p_gid_have_saved_id(VALUE _
)
7804 #if defined(HAVE_SETRESGID) || defined(HAVE_SETEGID) || defined(_POSIX_SAVED_IDS)
7811 #if defined(HAVE_SETRESGID) || defined(HAVE_SETEGID) || defined(_POSIX_SAVED_IDS)
7813 p_gid_sw_ensure(VALUE i
)
7815 rb_gid_t id
= (rb_gid_t
/* narrowing */)i
;
7816 under_gid_switch
= 0;
7817 id
= rb_setegid_core(id
);
7818 return GIDT2NUM(id
);
7824 * Process::GID.switch -> integer
7825 * Process::GID.switch {|| block} -> object
7827 * Switch the effective and real group IDs of the current process. If
7828 * a <em>block</em> is given, the group IDs will be switched back
7829 * after the block is executed. Returns the new effective group ID if
7830 * called without a block, and the return value of the block if one
7836 p_gid_switch(VALUE obj
)
7846 proc_setegid(obj
, GIDT2NUM(gid
));
7847 if (rb_block_given_p()) {
7848 under_gid_switch
= 1;
7849 return rb_ensure(rb_yield
, Qnil
, p_gid_sw_ensure
, SAVED_GROUP_ID
);
7852 return GIDT2NUM(egid
);
7855 else if (egid
!= SAVED_GROUP_ID
) {
7856 proc_setegid(obj
, GIDT2NUM(SAVED_GROUP_ID
));
7857 if (rb_block_given_p()) {
7858 under_gid_switch
= 1;
7859 return rb_ensure(rb_yield
, Qnil
, p_gid_sw_ensure
, egid
);
7862 return GIDT2NUM(gid
);
7866 rb_syserr_fail(EPERM
, 0);
7869 UNREACHABLE_RETURN(Qnil
);
7873 p_gid_sw_ensure(VALUE obj
)
7875 under_gid_switch
= 0;
7876 return p_gid_exchange(obj
);
7880 p_gid_switch(VALUE obj
)
7890 rb_syserr_fail(EPERM
, 0);
7892 p_gid_exchange(obj
);
7893 if (rb_block_given_p()) {
7894 under_gid_switch
= 1;
7895 return rb_ensure(rb_yield
, Qnil
, p_gid_sw_ensure
, obj
);
7898 return GIDT2NUM(egid
);
7904 #if defined(HAVE_TIMES)
7908 #ifdef HAVE__SC_CLK_TCK
7909 return sysconf(_SC_CLK_TCK
);
7910 #elif defined CLK_TCK
7921 * Process.times -> aProcessTms
7923 * Returns a <code>Tms</code> structure (see Process::Tms)
7924 * that contains user and system CPU times for this process,
7925 * and also for children processes.
7928 * [ t.utime, t.stime, t.cutime, t.cstime ] #=> [0.0, 0.02, 0.00, 0.00]
7932 rb_proc_times(VALUE obj
)
7934 VALUE utime
, stime
, cutime
, cstime
, ret
;
7935 #if defined(RUSAGE_SELF) && defined(RUSAGE_CHILDREN)
7936 struct rusage usage_s
, usage_c
;
7938 if (getrusage(RUSAGE_SELF
, &usage_s
) != 0 || getrusage(RUSAGE_CHILDREN
, &usage_c
) != 0)
7939 rb_sys_fail("getrusage");
7940 utime
= DBL2NUM((double)usage_s
.ru_utime
.tv_sec
+ (double)usage_s
.ru_utime
.tv_usec
/1e6
);
7941 stime
= DBL2NUM((double)usage_s
.ru_stime
.tv_sec
+ (double)usage_s
.ru_stime
.tv_usec
/1e6
);
7942 cutime
= DBL2NUM((double)usage_c
.ru_utime
.tv_sec
+ (double)usage_c
.ru_utime
.tv_usec
/1e6
);
7943 cstime
= DBL2NUM((double)usage_c
.ru_stime
.tv_sec
+ (double)usage_c
.ru_stime
.tv_usec
/1e6
);
7945 const double hertz
= (double)get_clk_tck();
7949 utime
= DBL2NUM(buf
.tms_utime
/ hertz
);
7950 stime
= DBL2NUM(buf
.tms_stime
/ hertz
);
7951 cutime
= DBL2NUM(buf
.tms_cutime
/ hertz
);
7952 cstime
= DBL2NUM(buf
.tms_cstime
/ hertz
);
7954 ret
= rb_struct_new(rb_cProcessTms
, utime
, stime
, cutime
, cstime
);
7957 RB_GC_GUARD(cutime
);
7958 RB_GC_GUARD(cstime
);
7962 #define rb_proc_times rb_f_notimplement
7965 #ifdef HAVE_LONG_LONG
7966 typedef LONG_LONG timetick_int_t
;
7967 #define TIMETICK_INT_MIN LLONG_MIN
7968 #define TIMETICK_INT_MAX LLONG_MAX
7969 #define TIMETICK_INT2NUM(v) LL2NUM(v)
7970 #define MUL_OVERFLOW_TIMETICK_P(a, b) MUL_OVERFLOW_LONG_LONG_P(a, b)
7972 typedef long timetick_int_t
;
7973 #define TIMETICK_INT_MIN LONG_MIN
7974 #define TIMETICK_INT_MAX LONG_MAX
7975 #define TIMETICK_INT2NUM(v) LONG2NUM(v)
7976 #define MUL_OVERFLOW_TIMETICK_P(a, b) MUL_OVERFLOW_LONG_P(a, b)
7979 CONSTFUNC(static timetick_int_t
gcd_timetick_int(timetick_int_t
, timetick_int_t
));
7980 static timetick_int_t
7981 gcd_timetick_int(timetick_int_t a
, timetick_int_t b
)
8001 reduce_fraction(timetick_int_t
*np
, timetick_int_t
*dp
)
8003 timetick_int_t gcd
= gcd_timetick_int(*np
, *dp
);
8011 reduce_factors(timetick_int_t
*numerators
, int num_numerators
,
8012 timetick_int_t
*denominators
, int num_denominators
)
8015 for (i
= 0; i
< num_numerators
; i
++) {
8016 if (numerators
[i
] == 1)
8018 for (j
= 0; j
< num_denominators
; j
++) {
8019 if (denominators
[j
] == 1)
8021 reduce_fraction(&numerators
[i
], &denominators
[j
]);
8027 timetick_int_t giga_count
;
8028 int32_t count
; /* 0 .. 999999999 */
8032 timetick2dblnum(struct timetick
*ttp
,
8033 timetick_int_t
*numerators
, int num_numerators
,
8034 timetick_int_t
*denominators
, int num_denominators
)
8039 reduce_factors(numerators
, num_numerators
,
8040 denominators
, num_denominators
);
8042 d
= ttp
->giga_count
* 1e9
+ ttp
->count
;
8044 for (i
= 0; i
< num_numerators
; i
++)
8046 for (i
= 0; i
< num_denominators
; i
++)
8047 d
/= denominators
[i
];
8053 timetick2dblnum_reciprocal(struct timetick
*ttp
,
8054 timetick_int_t
*numerators
, int num_numerators
,
8055 timetick_int_t
*denominators
, int num_denominators
)
8060 reduce_factors(numerators
, num_numerators
,
8061 denominators
, num_denominators
);
8064 for (i
= 0; i
< num_denominators
; i
++)
8065 d
*= denominators
[i
];
8066 for (i
= 0; i
< num_numerators
; i
++)
8068 d
/= ttp
->giga_count
* 1e9
+ ttp
->count
;
8073 #define NDIV(x,y) (-(-((x)+1)/(y))-1)
8074 #define DIV(n,d) ((n)<0 ? NDIV((n),(d)) : (n)/(d))
8077 timetick2integer(struct timetick
*ttp
,
8078 timetick_int_t
*numerators
, int num_numerators
,
8079 timetick_int_t
*denominators
, int num_denominators
)
8084 reduce_factors(numerators
, num_numerators
,
8085 denominators
, num_denominators
);
8087 if (!MUL_OVERFLOW_SIGNED_INTEGER_P(1000000000, ttp
->giga_count
,
8088 TIMETICK_INT_MIN
, TIMETICK_INT_MAX
-ttp
->count
)) {
8089 timetick_int_t t
= ttp
->giga_count
* 1000000000 + ttp
->count
;
8090 for (i
= 0; i
< num_numerators
; i
++) {
8091 timetick_int_t factor
= numerators
[i
];
8092 if (MUL_OVERFLOW_TIMETICK_P(factor
, t
))
8096 for (i
= 0; i
< num_denominators
; i
++) {
8097 t
= DIV(t
, denominators
[i
]);
8099 return TIMETICK_INT2NUM(t
);
8103 v
= TIMETICK_INT2NUM(ttp
->giga_count
);
8104 v
= rb_funcall(v
, '*', 1, LONG2FIX(1000000000));
8105 v
= rb_funcall(v
, '+', 1, LONG2FIX(ttp
->count
));
8106 for (i
= 0; i
< num_numerators
; i
++) {
8107 timetick_int_t factor
= numerators
[i
];
8110 v
= rb_funcall(v
, '*', 1, TIMETICK_INT2NUM(factor
));
8112 for (i
= 0; i
< num_denominators
; i
++) {
8113 v
= rb_funcall(v
, '/', 1, TIMETICK_INT2NUM(denominators
[i
])); /* Ruby's '/' is div. */
8119 make_clock_result(struct timetick
*ttp
,
8120 timetick_int_t
*numerators
, int num_numerators
,
8121 timetick_int_t
*denominators
, int num_denominators
,
8124 if (unit
== ID2SYM(id_nanosecond
)) {
8125 numerators
[num_numerators
++] = 1000000000;
8126 return timetick2integer(ttp
, numerators
, num_numerators
, denominators
, num_denominators
);
8128 else if (unit
== ID2SYM(id_microsecond
)) {
8129 numerators
[num_numerators
++] = 1000000;
8130 return timetick2integer(ttp
, numerators
, num_numerators
, denominators
, num_denominators
);
8132 else if (unit
== ID2SYM(id_millisecond
)) {
8133 numerators
[num_numerators
++] = 1000;
8134 return timetick2integer(ttp
, numerators
, num_numerators
, denominators
, num_denominators
);
8136 else if (unit
== ID2SYM(id_second
)) {
8137 return timetick2integer(ttp
, numerators
, num_numerators
, denominators
, num_denominators
);
8139 else if (unit
== ID2SYM(id_float_microsecond
)) {
8140 numerators
[num_numerators
++] = 1000000;
8141 return timetick2dblnum(ttp
, numerators
, num_numerators
, denominators
, num_denominators
);
8143 else if (unit
== ID2SYM(id_float_millisecond
)) {
8144 numerators
[num_numerators
++] = 1000;
8145 return timetick2dblnum(ttp
, numerators
, num_numerators
, denominators
, num_denominators
);
8147 else if (NIL_P(unit
) || unit
== ID2SYM(id_float_second
)) {
8148 return timetick2dblnum(ttp
, numerators
, num_numerators
, denominators
, num_denominators
);
8151 rb_raise(rb_eArgError
, "unexpected unit: %"PRIsVALUE
, unit
);
8155 static const mach_timebase_info_data_t
*
8156 get_mach_timebase_info(void)
8158 static mach_timebase_info_data_t sTimebaseInfo
;
8160 if ( sTimebaseInfo
.denom
== 0 ) {
8161 (void) mach_timebase_info(&sTimebaseInfo
);
8164 return &sTimebaseInfo
;
8168 ruby_real_ms_time(void)
8170 const mach_timebase_info_data_t
*info
= get_mach_timebase_info();
8171 uint64_t t
= mach_absolute_time();
8172 return (double)t
* info
->numer
/ info
->denom
/ 1e6
;
8178 * Process.clock_gettime(clock_id [, unit]) -> number
8180 * Returns a time returned by POSIX clock_gettime() function.
8182 * p Process.clock_gettime(Process::CLOCK_MONOTONIC)
8183 * #=> 896053.968060096
8185 * +clock_id+ specifies a kind of clock.
8186 * It is specified as a constant which begins with <code>Process::CLOCK_</code>
8187 * such as Process::CLOCK_REALTIME and Process::CLOCK_MONOTONIC.
8189 * The supported constants depends on OS and version.
8190 * Ruby provides following types of +clock_id+ if available.
8192 * [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
8193 * [CLOCK_MONOTONIC] SUSv3 to 4, Linux 2.5.63, FreeBSD 3.0, NetBSD 2.0, OpenBSD 3.4, macOS 10.12, Windows-2000
8194 * [CLOCK_PROCESS_CPUTIME_ID] SUSv3 to 4, Linux 2.5.63, FreeBSD 9.3, OpenBSD 5.4, macOS 10.12
8195 * [CLOCK_THREAD_CPUTIME_ID] SUSv3 to 4, Linux 2.5.63, FreeBSD 7.1, OpenBSD 5.4, macOS 10.12
8196 * [CLOCK_VIRTUAL] FreeBSD 3.0, OpenBSD 2.1
8197 * [CLOCK_PROF] FreeBSD 3.0, OpenBSD 2.1
8198 * [CLOCK_REALTIME_FAST] FreeBSD 8.1
8199 * [CLOCK_REALTIME_PRECISE] FreeBSD 8.1
8200 * [CLOCK_REALTIME_COARSE] Linux 2.6.32
8201 * [CLOCK_REALTIME_ALARM] Linux 3.0
8202 * [CLOCK_MONOTONIC_FAST] FreeBSD 8.1
8203 * [CLOCK_MONOTONIC_PRECISE] FreeBSD 8.1
8204 * [CLOCK_MONOTONIC_COARSE] Linux 2.6.32
8205 * [CLOCK_MONOTONIC_RAW] Linux 2.6.28, macOS 10.12
8206 * [CLOCK_MONOTONIC_RAW_APPROX] macOS 10.12
8207 * [CLOCK_BOOTTIME] Linux 2.6.39
8208 * [CLOCK_BOOTTIME_ALARM] Linux 3.0
8209 * [CLOCK_UPTIME] FreeBSD 7.0, OpenBSD 5.5
8210 * [CLOCK_UPTIME_FAST] FreeBSD 8.1
8211 * [CLOCK_UPTIME_RAW] macOS 10.12
8212 * [CLOCK_UPTIME_RAW_APPROX] macOS 10.12
8213 * [CLOCK_UPTIME_PRECISE] FreeBSD 8.1
8214 * [CLOCK_SECOND] FreeBSD 8.1
8215 * [CLOCK_TAI] Linux 3.10
8217 * Note that SUS stands for Single Unix Specification.
8218 * SUS contains POSIX and clock_gettime is defined in the POSIX part.
8219 * SUS defines CLOCK_REALTIME mandatory but
8220 * CLOCK_MONOTONIC, CLOCK_PROCESS_CPUTIME_ID and CLOCK_THREAD_CPUTIME_ID are optional.
8222 * Also, several symbols are accepted as +clock_id+.
8223 * There are emulations for clock_gettime().
8225 * For example, Process::CLOCK_REALTIME is defined as
8226 * +:GETTIMEOFDAY_BASED_CLOCK_REALTIME+ when clock_gettime() is not available.
8228 * Emulations for +CLOCK_REALTIME+:
8229 * [:GETTIMEOFDAY_BASED_CLOCK_REALTIME]
8230 * Use gettimeofday() defined by SUS.
8231 * (SUSv4 obsoleted it, though.)
8232 * The resolution is 1 microsecond.
8233 * [:TIME_BASED_CLOCK_REALTIME]
8234 * Use time() defined by ISO C.
8235 * The resolution is 1 second.
8237 * Emulations for +CLOCK_MONOTONIC+:
8238 * [:MACH_ABSOLUTE_TIME_BASED_CLOCK_MONOTONIC]
8239 * Use mach_absolute_time(), available on Darwin.
8240 * The resolution is CPU dependent.
8241 * [:TIMES_BASED_CLOCK_MONOTONIC]
8242 * Use the result value of times() defined by POSIX.
8243 * 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)".
8244 * For example, GNU/Linux returns a value based on jiffies and it is monotonic.
8245 * However, 4.4BSD uses gettimeofday() and it is not monotonic.
8246 * (FreeBSD uses clock_gettime(CLOCK_MONOTONIC) instead, though.)
8247 * The resolution is the clock tick.
8248 * "getconf CLK_TCK" command shows the clock ticks per second.
8249 * (The clock ticks per second is defined by HZ macro in older systems.)
8250 * If it is 100 and clock_t is 32 bits integer type, the resolution is 10 millisecond and
8251 * cannot represent over 497 days.
8253 * Emulations for +CLOCK_PROCESS_CPUTIME_ID+:
8254 * [:GETRUSAGE_BASED_CLOCK_PROCESS_CPUTIME_ID]
8255 * Use getrusage() defined by SUS.
8256 * getrusage() is used with RUSAGE_SELF to obtain the time only for
8257 * the calling process (excluding the time for child processes).
8258 * The result is addition of user time (ru_utime) and system time (ru_stime).
8259 * The resolution is 1 microsecond.
8260 * [:TIMES_BASED_CLOCK_PROCESS_CPUTIME_ID]
8261 * Use times() defined by POSIX.
8262 * The result is addition of user time (tms_utime) and system time (tms_stime).
8263 * tms_cutime and tms_cstime are ignored to exclude the time for child processes.
8264 * The resolution is the clock tick.
8265 * "getconf CLK_TCK" command shows the clock ticks per second.
8266 * (The clock ticks per second is defined by HZ macro in older systems.)
8267 * If it is 100, the resolution is 10 millisecond.
8268 * [:CLOCK_BASED_CLOCK_PROCESS_CPUTIME_ID]
8269 * Use clock() defined by ISO C.
8270 * The resolution is 1/CLOCKS_PER_SEC.
8271 * CLOCKS_PER_SEC is the C-level macro defined by time.h.
8272 * SUS defines CLOCKS_PER_SEC is 1000000.
8273 * Non-Unix systems may define it a different value, though.
8274 * If CLOCKS_PER_SEC is 1000000 as SUS, the resolution is 1 microsecond.
8275 * If CLOCKS_PER_SEC is 1000000 and clock_t is 32 bits integer type, it cannot represent over 72 minutes.
8277 * If the given +clock_id+ is not supported, Errno::EINVAL is raised.
8279 * +unit+ specifies a type of the return value.
8281 * [:float_second] number of seconds as a float (default)
8282 * [:float_millisecond] number of milliseconds as a float
8283 * [:float_microsecond] number of microseconds as a float
8284 * [:second] number of seconds as an integer
8285 * [:millisecond] number of milliseconds as an integer
8286 * [:microsecond] number of microseconds as an integer
8287 * [:nanosecond] number of nanoseconds as an integer
8289 * The underlying function, clock_gettime(), returns a number of nanoseconds.
8290 * Float object (IEEE 754 double) is not enough to represent
8291 * the return value for CLOCK_REALTIME.
8292 * If the exact nanoseconds value is required, use +:nanoseconds+ as the +unit+.
8294 * The origin (zero) of the returned value varies.
8295 * For example, system start up time, process start up time, the Epoch, etc.
8297 * The origin in CLOCK_REALTIME is defined as the Epoch
8298 * (1970-01-01 00:00:00 UTC).
8299 * But some systems count leap seconds and others doesn't.
8300 * So the result can be interpreted differently across systems.
8301 * Time.now is recommended over CLOCK_REALTIME.
8304 rb_clock_gettime(int argc
, VALUE
*argv
, VALUE _
)
8309 timetick_int_t numerators
[2];
8310 timetick_int_t denominators
[2];
8311 int num_numerators
= 0;
8312 int num_denominators
= 0;
8314 VALUE unit
= (rb_check_arity(argc
, 1, 2) == 2) ? argv
[1] : Qnil
;
8315 VALUE clk_id
= argv
[0];
8317 if (SYMBOL_P(clk_id
)) {
8319 * Non-clock_gettime clocks are provided by symbol clk_id.
8321 #ifdef HAVE_GETTIMEOFDAY
8323 * GETTIMEOFDAY_BASED_CLOCK_REALTIME is used for
8324 * CLOCK_REALTIME if clock_gettime is not available.
8326 #define RUBY_GETTIMEOFDAY_BASED_CLOCK_REALTIME ID2SYM(id_GETTIMEOFDAY_BASED_CLOCK_REALTIME)
8327 if (clk_id
== RUBY_GETTIMEOFDAY_BASED_CLOCK_REALTIME
) {
8329 ret
= gettimeofday(&tv
, 0);
8331 rb_sys_fail("gettimeofday");
8332 tt
.giga_count
= tv
.tv_sec
;
8333 tt
.count
= (int32_t)tv
.tv_usec
* 1000;
8334 denominators
[num_denominators
++] = 1000000000;
8339 #define RUBY_TIME_BASED_CLOCK_REALTIME ID2SYM(id_TIME_BASED_CLOCK_REALTIME)
8340 if (clk_id
== RUBY_TIME_BASED_CLOCK_REALTIME
) {
8343 if (t
== (time_t)-1)
8344 rb_sys_fail("time");
8347 denominators
[num_denominators
++] = 1000000000;
8352 #define RUBY_TIMES_BASED_CLOCK_MONOTONIC \
8353 ID2SYM(id_TIMES_BASED_CLOCK_MONOTONIC)
8354 if (clk_id
== RUBY_TIMES_BASED_CLOCK_MONOTONIC
) {
8357 unsigned_clock_t uc
;
8359 if (c
== (clock_t)-1)
8360 rb_sys_fail("times");
8361 uc
= (unsigned_clock_t
)c
;
8362 tt
.count
= (int32_t)(uc
% 1000000000);
8363 tt
.giga_count
= (uc
/ 1000000000);
8364 denominators
[num_denominators
++] = get_clk_tck();
8370 #define RUBY_GETRUSAGE_BASED_CLOCK_PROCESS_CPUTIME_ID \
8371 ID2SYM(id_GETRUSAGE_BASED_CLOCK_PROCESS_CPUTIME_ID)
8372 if (clk_id
== RUBY_GETRUSAGE_BASED_CLOCK_PROCESS_CPUTIME_ID
) {
8373 struct rusage usage
;
8375 ret
= getrusage(RUSAGE_SELF
, &usage
);
8377 rb_sys_fail("getrusage");
8378 tt
.giga_count
= usage
.ru_utime
.tv_sec
+ usage
.ru_stime
.tv_sec
;
8379 usec
= (int32_t)(usage
.ru_utime
.tv_usec
+ usage
.ru_stime
.tv_usec
);
8380 if (1000000 <= usec
) {
8384 tt
.count
= usec
* 1000;
8385 denominators
[num_denominators
++] = 1000000000;
8391 #define RUBY_TIMES_BASED_CLOCK_PROCESS_CPUTIME_ID \
8392 ID2SYM(id_TIMES_BASED_CLOCK_PROCESS_CPUTIME_ID)
8393 if (clk_id
== RUBY_TIMES_BASED_CLOCK_PROCESS_CPUTIME_ID
) {
8395 unsigned_clock_t utime
, stime
;
8396 if (times(&buf
) == (clock_t)-1)
8397 rb_sys_fail("times");
8398 utime
= (unsigned_clock_t
)buf
.tms_utime
;
8399 stime
= (unsigned_clock_t
)buf
.tms_stime
;
8400 tt
.count
= (int32_t)((utime
% 1000000000) + (stime
% 1000000000));
8401 tt
.giga_count
= (utime
/ 1000000000) + (stime
/ 1000000000);
8402 if (1000000000 <= tt
.count
) {
8403 tt
.count
-= 1000000000;
8406 denominators
[num_denominators
++] = get_clk_tck();
8411 #define RUBY_CLOCK_BASED_CLOCK_PROCESS_CPUTIME_ID \
8412 ID2SYM(id_CLOCK_BASED_CLOCK_PROCESS_CPUTIME_ID)
8413 if (clk_id
== RUBY_CLOCK_BASED_CLOCK_PROCESS_CPUTIME_ID
) {
8415 unsigned_clock_t uc
;
8418 if (c
== (clock_t)-1)
8419 rb_sys_fail("clock");
8420 uc
= (unsigned_clock_t
)c
;
8421 tt
.count
= (int32_t)(uc
% 1000000000);
8422 tt
.giga_count
= uc
/ 1000000000;
8423 denominators
[num_denominators
++] = CLOCKS_PER_SEC
;
8428 #define RUBY_MACH_ABSOLUTE_TIME_BASED_CLOCK_MONOTONIC ID2SYM(id_MACH_ABSOLUTE_TIME_BASED_CLOCK_MONOTONIC)
8429 if (clk_id
== RUBY_MACH_ABSOLUTE_TIME_BASED_CLOCK_MONOTONIC
) {
8430 const mach_timebase_info_data_t
*info
= get_mach_timebase_info();
8431 uint64_t t
= mach_absolute_time();
8432 tt
.count
= (int32_t)(t
% 1000000000);
8433 tt
.giga_count
= t
/ 1000000000;
8434 numerators
[num_numerators
++] = info
->numer
;
8435 denominators
[num_denominators
++] = info
->denom
;
8436 denominators
[num_denominators
++] = 1000000000;
8442 #if defined(HAVE_CLOCK_GETTIME)
8445 c
= NUM2CLOCKID(clk_id
);
8446 ret
= clock_gettime(c
, &ts
);
8448 rb_sys_fail("clock_gettime");
8449 tt
.count
= (int32_t)ts
.tv_nsec
;
8450 tt
.giga_count
= ts
.tv_sec
;
8451 denominators
[num_denominators
++] = 1000000000;
8455 /* EINVAL emulates clock_gettime behavior when clock_id is invalid. */
8456 rb_syserr_fail(EINVAL
, 0);
8459 return make_clock_result(&tt
, numerators
, num_numerators
, denominators
, num_denominators
, unit
);
8464 * Process.clock_getres(clock_id [, unit]) -> number
8466 * Returns an estimate of the resolution of a +clock_id+ using the POSIX
8467 * <code>clock_getres()</code> function.
8469 * Note the reported resolution is often inaccurate on most platforms due to
8470 * underlying bugs for this function and therefore the reported resolution
8471 * often differs from the actual resolution of the clock in practice.
8472 * Inaccurate reported resolutions have been observed for various clocks including
8473 * CLOCK_MONOTONIC and CLOCK_MONOTONIC_RAW when using Linux, macOS, BSD or AIX
8474 * platforms, when using ARM processors, or when using virtualization.
8476 * +clock_id+ specifies a kind of clock.
8477 * See the document of +Process.clock_gettime+ for details.
8478 * +clock_id+ can be a symbol as for +Process.clock_gettime+.
8480 * If the given +clock_id+ is not supported, Errno::EINVAL is raised.
8482 * +unit+ specifies the type of the return value.
8483 * +Process.clock_getres+ accepts +unit+ as +Process.clock_gettime+.
8484 * The default value, +:float_second+, is also the same as
8485 * +Process.clock_gettime+.
8487 * +Process.clock_getres+ also accepts +:hertz+ as +unit+.
8488 * +:hertz+ means the reciprocal of +:float_second+.
8490 * +:hertz+ can be used to obtain the exact value of
8491 * the clock ticks per second for the times() function and
8492 * CLOCKS_PER_SEC for the clock() function.
8494 * <code>Process.clock_getres(:TIMES_BASED_CLOCK_PROCESS_CPUTIME_ID, :hertz)</code>
8495 * returns the clock ticks per second.
8497 * <code>Process.clock_getres(:CLOCK_BASED_CLOCK_PROCESS_CPUTIME_ID, :hertz)</code>
8498 * returns CLOCKS_PER_SEC.
8500 * p Process.clock_getres(Process::CLOCK_MONOTONIC)
8505 rb_clock_getres(int argc
, VALUE
*argv
, VALUE _
)
8508 timetick_int_t numerators
[2];
8509 timetick_int_t denominators
[2];
8510 int num_numerators
= 0;
8511 int num_denominators
= 0;
8513 VALUE unit
= (rb_check_arity(argc
, 1, 2) == 2) ? argv
[1] : Qnil
;
8514 VALUE clk_id
= argv
[0];
8516 if (SYMBOL_P(clk_id
)) {
8517 #ifdef RUBY_GETTIMEOFDAY_BASED_CLOCK_REALTIME
8518 if (clk_id
== RUBY_GETTIMEOFDAY_BASED_CLOCK_REALTIME
) {
8521 denominators
[num_denominators
++] = 1000000000;
8526 #ifdef RUBY_TIME_BASED_CLOCK_REALTIME
8527 if (clk_id
== RUBY_TIME_BASED_CLOCK_REALTIME
) {
8530 denominators
[num_denominators
++] = 1000000000;
8535 #ifdef RUBY_TIMES_BASED_CLOCK_MONOTONIC
8536 if (clk_id
== RUBY_TIMES_BASED_CLOCK_MONOTONIC
) {
8539 denominators
[num_denominators
++] = get_clk_tck();
8544 #ifdef RUBY_GETRUSAGE_BASED_CLOCK_PROCESS_CPUTIME_ID
8545 if (clk_id
== RUBY_GETRUSAGE_BASED_CLOCK_PROCESS_CPUTIME_ID
) {
8548 denominators
[num_denominators
++] = 1000000000;
8553 #ifdef RUBY_TIMES_BASED_CLOCK_PROCESS_CPUTIME_ID
8554 if (clk_id
== RUBY_TIMES_BASED_CLOCK_PROCESS_CPUTIME_ID
) {
8557 denominators
[num_denominators
++] = get_clk_tck();
8562 #ifdef RUBY_CLOCK_BASED_CLOCK_PROCESS_CPUTIME_ID
8563 if (clk_id
== RUBY_CLOCK_BASED_CLOCK_PROCESS_CPUTIME_ID
) {
8566 denominators
[num_denominators
++] = CLOCKS_PER_SEC
;
8571 #ifdef RUBY_MACH_ABSOLUTE_TIME_BASED_CLOCK_MONOTONIC
8572 if (clk_id
== RUBY_MACH_ABSOLUTE_TIME_BASED_CLOCK_MONOTONIC
) {
8573 const mach_timebase_info_data_t
*info
= get_mach_timebase_info();
8576 numerators
[num_numerators
++] = info
->numer
;
8577 denominators
[num_denominators
++] = info
->denom
;
8578 denominators
[num_denominators
++] = 1000000000;
8584 #if defined(HAVE_CLOCK_GETRES)
8586 clockid_t c
= NUM2CLOCKID(clk_id
);
8587 int ret
= clock_getres(c
, &ts
);
8589 rb_sys_fail("clock_getres");
8590 tt
.count
= (int32_t)ts
.tv_nsec
;
8591 tt
.giga_count
= ts
.tv_sec
;
8592 denominators
[num_denominators
++] = 1000000000;
8596 /* EINVAL emulates clock_getres behavior when clock_id is invalid. */
8597 rb_syserr_fail(EINVAL
, 0);
8600 if (unit
== ID2SYM(id_hertz
)) {
8601 return timetick2dblnum_reciprocal(&tt
, numerators
, num_numerators
, denominators
, num_denominators
);
8604 return make_clock_result(&tt
, numerators
, num_numerators
, denominators
, num_denominators
, unit
);
8609 get_CHILD_STATUS(ID _x
, VALUE
*_y
)
8611 return rb_last_status_get();
8615 get_PROCESS_ID(ID _x
, VALUE
*_y
)
8622 * Process.kill(signal, pid, ...) -> integer
8624 * Sends the given signal to the specified process id(s) if _pid_ is positive.
8625 * If _pid_ is zero, _signal_ is sent to all processes whose group ID is equal
8626 * to the group ID of the process. If _pid_ is negative, results are dependent
8627 * on the operating system. _signal_ may be an integer signal number or
8628 * a POSIX signal name (either with or without a +SIG+ prefix). If _signal_ is
8629 * negative (or starts with a minus sign), kills process groups instead of
8630 * processes. Not all signals are available on all platforms.
8631 * The keys and values of Signal.list are known signal names and numbers,
8635 * Signal.trap("HUP") { puts "Ouch!"; exit }
8636 * # ... do some work ...
8639 * Process.kill("HUP", pid)
8642 * <em>produces:</em>
8646 * If _signal_ is an integer but wrong for signal, Errno::EINVAL or
8647 * RangeError will be raised. Otherwise unless _signal_ is a String
8648 * or a Symbol, and a known signal name, ArgumentError will be
8651 * Also, Errno::ESRCH or RangeError for invalid _pid_, Errno::EPERM
8652 * when failed because of no privilege, will be raised. In these
8653 * cases, signals may have been sent to preceding processes.
8657 proc_rb_f_kill(int c
, const VALUE
*v
, VALUE _
)
8659 return rb_f_kill(c
, v
);
8663 static VALUE rb_mProcUID
;
8664 static VALUE rb_mProcGID
;
8665 static VALUE rb_mProcID_Syscall
;
8669 * The Process module is a collection of methods used to
8670 * manipulate processes.
8674 InitVM_process(void)
8676 rb_define_virtual_variable("$?", get_CHILD_STATUS
, 0);
8677 rb_define_virtual_variable("$$", get_PROCESS_ID
, 0);
8679 rb_gvar_ractor_local("$$");
8680 rb_gvar_ractor_local("$?");
8682 rb_define_global_function("exec", f_exec
, -1);
8683 rb_define_global_function("fork", rb_f_fork
, 0);
8684 rb_define_global_function("exit!", rb_f_exit_bang
, -1);
8685 rb_define_global_function("system", rb_f_system
, -1);
8686 rb_define_global_function("spawn", rb_f_spawn
, -1);
8687 rb_define_global_function("sleep", rb_f_sleep
, -1);
8688 rb_define_global_function("exit", f_exit
, -1);
8689 rb_define_global_function("abort", f_abort
, -1);
8691 rb_mProcess
= rb_define_module("Process");
8694 /* see Process.wait */
8695 rb_define_const(rb_mProcess
, "WNOHANG", INT2FIX(WNOHANG
));
8697 /* see Process.wait */
8698 rb_define_const(rb_mProcess
, "WNOHANG", INT2FIX(0));
8701 /* see Process.wait */
8702 rb_define_const(rb_mProcess
, "WUNTRACED", INT2FIX(WUNTRACED
));
8704 /* see Process.wait */
8705 rb_define_const(rb_mProcess
, "WUNTRACED", INT2FIX(0));
8708 rb_define_singleton_method(rb_mProcess
, "exec", f_exec
, -1);
8709 rb_define_singleton_method(rb_mProcess
, "fork", rb_f_fork
, 0);
8710 rb_define_singleton_method(rb_mProcess
, "spawn", rb_f_spawn
, -1);
8711 rb_define_singleton_method(rb_mProcess
, "exit!", rb_f_exit_bang
, -1);
8712 rb_define_singleton_method(rb_mProcess
, "exit", f_exit
, -1);
8713 rb_define_singleton_method(rb_mProcess
, "abort", f_abort
, -1);
8714 rb_define_singleton_method(rb_mProcess
, "last_status", proc_s_last_status
, 0);
8715 rb_define_singleton_method(rb_mProcess
, "_fork", rb_proc__fork
, 0);
8717 rb_define_module_function(rb_mProcess
, "kill", proc_rb_f_kill
, -1);
8718 rb_define_module_function(rb_mProcess
, "wait", proc_m_wait
, -1);
8719 rb_define_module_function(rb_mProcess
, "wait2", proc_wait2
, -1);
8720 rb_define_module_function(rb_mProcess
, "waitpid", proc_m_wait
, -1);
8721 rb_define_module_function(rb_mProcess
, "waitpid2", proc_wait2
, -1);
8722 rb_define_module_function(rb_mProcess
, "waitall", proc_waitall
, 0);
8723 rb_define_module_function(rb_mProcess
, "detach", proc_detach
, 1);
8726 rb_cWaiter
= rb_define_class_under(rb_mProcess
, "Waiter", rb_cThread
);
8727 rb_undef_alloc_func(rb_cWaiter
);
8728 rb_undef_method(CLASS_OF(rb_cWaiter
), "new");
8729 rb_define_method(rb_cWaiter
, "pid", detach_process_pid
, 0);
8731 rb_cProcessStatus
= rb_define_class_under(rb_mProcess
, "Status", rb_cObject
);
8732 rb_define_alloc_func(rb_cProcessStatus
, rb_process_status_allocate
);
8733 rb_undef_method(CLASS_OF(rb_cProcessStatus
), "new");
8734 rb_marshal_define_compat(rb_cProcessStatus
, rb_cObject
,
8735 process_status_dump
, process_status_load
);
8737 rb_define_singleton_method(rb_cProcessStatus
, "wait", rb_process_status_waitv
, -1);
8739 rb_define_method(rb_cProcessStatus
, "==", pst_equal
, 1);
8740 rb_define_method(rb_cProcessStatus
, "&", pst_bitand
, 1);
8741 rb_define_method(rb_cProcessStatus
, ">>", pst_rshift
, 1);
8742 rb_define_method(rb_cProcessStatus
, "to_i", pst_to_i
, 0);
8743 rb_define_method(rb_cProcessStatus
, "to_s", pst_to_s
, 0);
8744 rb_define_method(rb_cProcessStatus
, "inspect", pst_inspect
, 0);
8746 rb_define_method(rb_cProcessStatus
, "pid", pst_pid_m
, 0);
8748 rb_define_method(rb_cProcessStatus
, "stopped?", pst_wifstopped
, 0);
8749 rb_define_method(rb_cProcessStatus
, "stopsig", pst_wstopsig
, 0);
8750 rb_define_method(rb_cProcessStatus
, "signaled?", pst_wifsignaled
, 0);
8751 rb_define_method(rb_cProcessStatus
, "termsig", pst_wtermsig
, 0);
8752 rb_define_method(rb_cProcessStatus
, "exited?", pst_wifexited
, 0);
8753 rb_define_method(rb_cProcessStatus
, "exitstatus", pst_wexitstatus
, 0);
8754 rb_define_method(rb_cProcessStatus
, "success?", pst_success_p
, 0);
8755 rb_define_method(rb_cProcessStatus
, "coredump?", pst_wcoredump
, 0);
8757 rb_define_module_function(rb_mProcess
, "pid", proc_get_pid
, 0);
8758 rb_define_module_function(rb_mProcess
, "ppid", proc_get_ppid
, 0);
8760 rb_define_module_function(rb_mProcess
, "getpgrp", proc_getpgrp
, 0);
8761 rb_define_module_function(rb_mProcess
, "setpgrp", proc_setpgrp
, 0);
8762 rb_define_module_function(rb_mProcess
, "getpgid", proc_getpgid
, 1);
8763 rb_define_module_function(rb_mProcess
, "setpgid", proc_setpgid
, 2);
8765 rb_define_module_function(rb_mProcess
, "getsid", proc_getsid
, -1);
8766 rb_define_module_function(rb_mProcess
, "setsid", proc_setsid
, 0);
8768 rb_define_module_function(rb_mProcess
, "getpriority", proc_getpriority
, 2);
8769 rb_define_module_function(rb_mProcess
, "setpriority", proc_setpriority
, 3);
8771 #ifdef HAVE_GETPRIORITY
8772 /* see Process.setpriority */
8773 rb_define_const(rb_mProcess
, "PRIO_PROCESS", INT2FIX(PRIO_PROCESS
));
8774 /* see Process.setpriority */
8775 rb_define_const(rb_mProcess
, "PRIO_PGRP", INT2FIX(PRIO_PGRP
));
8776 /* see Process.setpriority */
8777 rb_define_const(rb_mProcess
, "PRIO_USER", INT2FIX(PRIO_USER
));
8780 rb_define_module_function(rb_mProcess
, "getrlimit", proc_getrlimit
, 1);
8781 rb_define_module_function(rb_mProcess
, "setrlimit", proc_setrlimit
, -1);
8782 #if defined(RLIM2NUM) && defined(RLIM_INFINITY)
8784 VALUE inf
= RLIM2NUM(RLIM_INFINITY
);
8785 #ifdef RLIM_SAVED_MAX
8787 VALUE v
= RLIM_INFINITY
== RLIM_SAVED_MAX
? inf
: RLIM2NUM(RLIM_SAVED_MAX
);
8788 /* see Process.setrlimit */
8789 rb_define_const(rb_mProcess
, "RLIM_SAVED_MAX", v
);
8792 /* see Process.setrlimit */
8793 rb_define_const(rb_mProcess
, "RLIM_INFINITY", inf
);
8794 #ifdef RLIM_SAVED_CUR
8796 VALUE v
= RLIM_INFINITY
== RLIM_SAVED_CUR
? inf
: RLIM2NUM(RLIM_SAVED_CUR
);
8797 /* see Process.setrlimit */
8798 rb_define_const(rb_mProcess
, "RLIM_SAVED_CUR", v
);
8803 /* Maximum size of the process's virtual memory (address space) in bytes.
8805 * see the system getrlimit(2) manual for details.
8807 rb_define_const(rb_mProcess
, "RLIMIT_AS", INT2FIX(RLIMIT_AS
));
8810 /* Maximum size of the core file.
8812 * see the system getrlimit(2) manual for details.
8814 rb_define_const(rb_mProcess
, "RLIMIT_CORE", INT2FIX(RLIMIT_CORE
));
8817 /* CPU time limit in seconds.
8819 * see the system getrlimit(2) manual for details.
8821 rb_define_const(rb_mProcess
, "RLIMIT_CPU", INT2FIX(RLIMIT_CPU
));
8824 /* Maximum size of the process's data segment.
8826 * see the system getrlimit(2) manual for details.
8828 rb_define_const(rb_mProcess
, "RLIMIT_DATA", INT2FIX(RLIMIT_DATA
));
8831 /* Maximum size of files that the process may create.
8833 * see the system getrlimit(2) manual for details.
8835 rb_define_const(rb_mProcess
, "RLIMIT_FSIZE", INT2FIX(RLIMIT_FSIZE
));
8837 #ifdef RLIMIT_MEMLOCK
8838 /* Maximum number of bytes of memory that may be locked into RAM.
8840 * see the system getrlimit(2) manual for details.
8842 rb_define_const(rb_mProcess
, "RLIMIT_MEMLOCK", INT2FIX(RLIMIT_MEMLOCK
));
8844 #ifdef RLIMIT_MSGQUEUE
8845 /* Specifies the limit on the number of bytes that can be allocated
8846 * for POSIX message queues for the real user ID of the calling process.
8848 * see the system getrlimit(2) manual for details.
8850 rb_define_const(rb_mProcess
, "RLIMIT_MSGQUEUE", INT2FIX(RLIMIT_MSGQUEUE
));
8853 /* Specifies a ceiling to which the process's nice value can be raised.
8855 * see the system getrlimit(2) manual for details.
8857 rb_define_const(rb_mProcess
, "RLIMIT_NICE", INT2FIX(RLIMIT_NICE
));
8859 #ifdef RLIMIT_NOFILE
8860 /* Specifies a value one greater than the maximum file descriptor
8861 * number that can be opened by this process.
8863 * see the system getrlimit(2) manual for details.
8865 rb_define_const(rb_mProcess
, "RLIMIT_NOFILE", INT2FIX(RLIMIT_NOFILE
));
8868 /* The maximum number of processes that can be created for the
8869 * real user ID of the calling process.
8871 * see the system getrlimit(2) manual for details.
8873 rb_define_const(rb_mProcess
, "RLIMIT_NPROC", INT2FIX(RLIMIT_NPROC
));
8876 /* Specifies the limit (in pages) of the process's resident set.
8878 * see the system getrlimit(2) manual for details.
8880 rb_define_const(rb_mProcess
, "RLIMIT_RSS", INT2FIX(RLIMIT_RSS
));
8882 #ifdef RLIMIT_RTPRIO
8883 /* Specifies a ceiling on the real-time priority that may be set for this process.
8885 * see the system getrlimit(2) manual for details.
8887 rb_define_const(rb_mProcess
, "RLIMIT_RTPRIO", INT2FIX(RLIMIT_RTPRIO
));
8889 #ifdef RLIMIT_RTTIME
8890 /* Specifies limit on CPU time this process scheduled under a real-time
8891 * scheduling policy can consume.
8893 * see the system getrlimit(2) manual for details.
8895 rb_define_const(rb_mProcess
, "RLIMIT_RTTIME", INT2FIX(RLIMIT_RTTIME
));
8897 #ifdef RLIMIT_SBSIZE
8898 /* Maximum size of the socket buffer.
8900 rb_define_const(rb_mProcess
, "RLIMIT_SBSIZE", INT2FIX(RLIMIT_SBSIZE
));
8902 #ifdef RLIMIT_SIGPENDING
8903 /* Specifies a limit on the number of signals that may be queued for
8904 * the real user ID of the calling process.
8906 * see the system getrlimit(2) manual for details.
8908 rb_define_const(rb_mProcess
, "RLIMIT_SIGPENDING", INT2FIX(RLIMIT_SIGPENDING
));
8911 /* Maximum size of the stack, in bytes.
8913 * see the system getrlimit(2) manual for details.
8915 rb_define_const(rb_mProcess
, "RLIMIT_STACK", INT2FIX(RLIMIT_STACK
));
8919 rb_define_module_function(rb_mProcess
, "uid", proc_getuid
, 0);
8920 rb_define_module_function(rb_mProcess
, "uid=", proc_setuid
, 1);
8921 rb_define_module_function(rb_mProcess
, "gid", proc_getgid
, 0);
8922 rb_define_module_function(rb_mProcess
, "gid=", proc_setgid
, 1);
8923 rb_define_module_function(rb_mProcess
, "euid", proc_geteuid
, 0);
8924 rb_define_module_function(rb_mProcess
, "euid=", proc_seteuid_m
, 1);
8925 rb_define_module_function(rb_mProcess
, "egid", proc_getegid
, 0);
8926 rb_define_module_function(rb_mProcess
, "egid=", proc_setegid_m
, 1);
8927 rb_define_module_function(rb_mProcess
, "initgroups", proc_initgroups
, 2);
8928 rb_define_module_function(rb_mProcess
, "groups", proc_getgroups
, 0);
8929 rb_define_module_function(rb_mProcess
, "groups=", proc_setgroups
, 1);
8930 rb_define_module_function(rb_mProcess
, "maxgroups", proc_getmaxgroups
, 0);
8931 rb_define_module_function(rb_mProcess
, "maxgroups=", proc_setmaxgroups
, 1);
8933 rb_define_module_function(rb_mProcess
, "daemon", proc_daemon
, -1);
8935 rb_define_module_function(rb_mProcess
, "times", rb_proc_times
, 0);
8937 #ifdef CLOCK_REALTIME
8938 /* see Process.clock_gettime */
8939 rb_define_const(rb_mProcess
, "CLOCK_REALTIME", CLOCKID2NUM(CLOCK_REALTIME
));
8940 #elif defined(RUBY_GETTIMEOFDAY_BASED_CLOCK_REALTIME)
8941 /* see Process.clock_gettime */
8942 rb_define_const(rb_mProcess
, "CLOCK_REALTIME", RUBY_GETTIMEOFDAY_BASED_CLOCK_REALTIME
);
8944 #ifdef CLOCK_MONOTONIC
8945 /* see Process.clock_gettime */
8946 rb_define_const(rb_mProcess
, "CLOCK_MONOTONIC", CLOCKID2NUM(CLOCK_MONOTONIC
));
8947 #elif defined(RUBY_MACH_ABSOLUTE_TIME_BASED_CLOCK_MONOTONIC)
8948 /* see Process.clock_gettime */
8949 rb_define_const(rb_mProcess
, "CLOCK_MONOTONIC", RUBY_MACH_ABSOLUTE_TIME_BASED_CLOCK_MONOTONIC
);
8951 #ifdef CLOCK_PROCESS_CPUTIME_ID
8952 /* see Process.clock_gettime */
8953 rb_define_const(rb_mProcess
, "CLOCK_PROCESS_CPUTIME_ID", CLOCKID2NUM(CLOCK_PROCESS_CPUTIME_ID
));
8954 #elif defined(RUBY_GETRUSAGE_BASED_CLOCK_PROCESS_CPUTIME_ID)
8955 /* see Process.clock_gettime */
8956 rb_define_const(rb_mProcess
, "CLOCK_PROCESS_CPUTIME_ID", RUBY_GETRUSAGE_BASED_CLOCK_PROCESS_CPUTIME_ID
);
8958 #ifdef CLOCK_THREAD_CPUTIME_ID
8959 /* see Process.clock_gettime */
8960 rb_define_const(rb_mProcess
, "CLOCK_THREAD_CPUTIME_ID", CLOCKID2NUM(CLOCK_THREAD_CPUTIME_ID
));
8962 #ifdef CLOCK_VIRTUAL
8963 /* see Process.clock_gettime */
8964 rb_define_const(rb_mProcess
, "CLOCK_VIRTUAL", CLOCKID2NUM(CLOCK_VIRTUAL
));
8967 /* see Process.clock_gettime */
8968 rb_define_const(rb_mProcess
, "CLOCK_PROF", CLOCKID2NUM(CLOCK_PROF
));
8970 #ifdef CLOCK_REALTIME_FAST
8971 /* see Process.clock_gettime */
8972 rb_define_const(rb_mProcess
, "CLOCK_REALTIME_FAST", CLOCKID2NUM(CLOCK_REALTIME_FAST
));
8974 #ifdef CLOCK_REALTIME_PRECISE
8975 /* see Process.clock_gettime */
8976 rb_define_const(rb_mProcess
, "CLOCK_REALTIME_PRECISE", CLOCKID2NUM(CLOCK_REALTIME_PRECISE
));
8978 #ifdef CLOCK_REALTIME_COARSE
8979 /* see Process.clock_gettime */
8980 rb_define_const(rb_mProcess
, "CLOCK_REALTIME_COARSE", CLOCKID2NUM(CLOCK_REALTIME_COARSE
));
8982 #ifdef CLOCK_REALTIME_ALARM
8983 /* see Process.clock_gettime */
8984 rb_define_const(rb_mProcess
, "CLOCK_REALTIME_ALARM", CLOCKID2NUM(CLOCK_REALTIME_ALARM
));
8986 #ifdef CLOCK_MONOTONIC_FAST
8987 /* see Process.clock_gettime */
8988 rb_define_const(rb_mProcess
, "CLOCK_MONOTONIC_FAST", CLOCKID2NUM(CLOCK_MONOTONIC_FAST
));
8990 #ifdef CLOCK_MONOTONIC_PRECISE
8991 /* see Process.clock_gettime */
8992 rb_define_const(rb_mProcess
, "CLOCK_MONOTONIC_PRECISE", CLOCKID2NUM(CLOCK_MONOTONIC_PRECISE
));
8994 #ifdef CLOCK_MONOTONIC_RAW
8995 /* see Process.clock_gettime */
8996 rb_define_const(rb_mProcess
, "CLOCK_MONOTONIC_RAW", CLOCKID2NUM(CLOCK_MONOTONIC_RAW
));
8998 #ifdef CLOCK_MONOTONIC_RAW_APPROX
8999 /* see Process.clock_gettime */
9000 rb_define_const(rb_mProcess
, "CLOCK_MONOTONIC_RAW_APPROX", CLOCKID2NUM(CLOCK_MONOTONIC_RAW_APPROX
));
9002 #ifdef CLOCK_MONOTONIC_COARSE
9003 /* see Process.clock_gettime */
9004 rb_define_const(rb_mProcess
, "CLOCK_MONOTONIC_COARSE", CLOCKID2NUM(CLOCK_MONOTONIC_COARSE
));
9006 #ifdef CLOCK_BOOTTIME
9007 /* see Process.clock_gettime */
9008 rb_define_const(rb_mProcess
, "CLOCK_BOOTTIME", CLOCKID2NUM(CLOCK_BOOTTIME
));
9010 #ifdef CLOCK_BOOTTIME_ALARM
9011 /* see Process.clock_gettime */
9012 rb_define_const(rb_mProcess
, "CLOCK_BOOTTIME_ALARM", CLOCKID2NUM(CLOCK_BOOTTIME_ALARM
));
9015 /* see Process.clock_gettime */
9016 rb_define_const(rb_mProcess
, "CLOCK_UPTIME", CLOCKID2NUM(CLOCK_UPTIME
));
9018 #ifdef CLOCK_UPTIME_FAST
9019 /* see Process.clock_gettime */
9020 rb_define_const(rb_mProcess
, "CLOCK_UPTIME_FAST", CLOCKID2NUM(CLOCK_UPTIME_FAST
));
9022 #ifdef CLOCK_UPTIME_PRECISE
9023 /* see Process.clock_gettime */
9024 rb_define_const(rb_mProcess
, "CLOCK_UPTIME_PRECISE", CLOCKID2NUM(CLOCK_UPTIME_PRECISE
));
9026 #ifdef CLOCK_UPTIME_RAW
9027 /* see Process.clock_gettime */
9028 rb_define_const(rb_mProcess
, "CLOCK_UPTIME_RAW", CLOCKID2NUM(CLOCK_UPTIME_RAW
));
9030 #ifdef CLOCK_UPTIME_RAW_APPROX
9031 /* see Process.clock_gettime */
9032 rb_define_const(rb_mProcess
, "CLOCK_UPTIME_RAW_APPROX", CLOCKID2NUM(CLOCK_UPTIME_RAW_APPROX
));
9035 /* see Process.clock_gettime */
9036 rb_define_const(rb_mProcess
, "CLOCK_SECOND", CLOCKID2NUM(CLOCK_SECOND
));
9039 /* see Process.clock_gettime */
9040 rb_define_const(rb_mProcess
, "CLOCK_TAI", CLOCKID2NUM(CLOCK_TAI
));
9042 rb_define_module_function(rb_mProcess
, "clock_gettime", rb_clock_gettime
, -1);
9043 rb_define_module_function(rb_mProcess
, "clock_getres", rb_clock_getres
, -1);
9045 #if defined(HAVE_TIMES) || defined(_WIN32)
9046 /* Placeholder for rusage */
9047 rb_cProcessTms
= rb_struct_define_under(rb_mProcess
, "Tms", "utime", "stime", "cutime", "cstime", NULL
);
9050 SAVED_USER_ID
= geteuid();
9051 SAVED_GROUP_ID
= getegid();
9053 rb_mProcUID
= rb_define_module_under(rb_mProcess
, "UID");
9054 rb_mProcGID
= rb_define_module_under(rb_mProcess
, "GID");
9056 rb_define_module_function(rb_mProcUID
, "rid", proc_getuid
, 0);
9057 rb_define_module_function(rb_mProcGID
, "rid", proc_getgid
, 0);
9058 rb_define_module_function(rb_mProcUID
, "eid", proc_geteuid
, 0);
9059 rb_define_module_function(rb_mProcGID
, "eid", proc_getegid
, 0);
9060 rb_define_module_function(rb_mProcUID
, "change_privilege", p_uid_change_privilege
, 1);
9061 rb_define_module_function(rb_mProcGID
, "change_privilege", p_gid_change_privilege
, 1);
9062 rb_define_module_function(rb_mProcUID
, "grant_privilege", p_uid_grant_privilege
, 1);
9063 rb_define_module_function(rb_mProcGID
, "grant_privilege", p_gid_grant_privilege
, 1);
9064 rb_define_alias(rb_singleton_class(rb_mProcUID
), "eid=", "grant_privilege");
9065 rb_define_alias(rb_singleton_class(rb_mProcGID
), "eid=", "grant_privilege");
9066 rb_define_module_function(rb_mProcUID
, "re_exchange", p_uid_exchange
, 0);
9067 rb_define_module_function(rb_mProcGID
, "re_exchange", p_gid_exchange
, 0);
9068 rb_define_module_function(rb_mProcUID
, "re_exchangeable?", p_uid_exchangeable
, 0);
9069 rb_define_module_function(rb_mProcGID
, "re_exchangeable?", p_gid_exchangeable
, 0);
9070 rb_define_module_function(rb_mProcUID
, "sid_available?", p_uid_have_saved_id
, 0);
9071 rb_define_module_function(rb_mProcGID
, "sid_available?", p_gid_have_saved_id
, 0);
9072 rb_define_module_function(rb_mProcUID
, "switch", p_uid_switch
, 0);
9073 rb_define_module_function(rb_mProcGID
, "switch", p_gid_switch
, 0);
9074 #ifdef p_uid_from_name
9075 rb_define_module_function(rb_mProcUID
, "from_name", p_uid_from_name
, 1);
9077 #ifdef p_gid_from_name
9078 rb_define_module_function(rb_mProcGID
, "from_name", p_gid_from_name
, 1);
9081 rb_mProcID_Syscall
= rb_define_module_under(rb_mProcess
, "Sys");
9083 rb_define_module_function(rb_mProcID_Syscall
, "getuid", proc_getuid
, 0);
9084 rb_define_module_function(rb_mProcID_Syscall
, "geteuid", proc_geteuid
, 0);
9085 rb_define_module_function(rb_mProcID_Syscall
, "getgid", proc_getgid
, 0);
9086 rb_define_module_function(rb_mProcID_Syscall
, "getegid", proc_getegid
, 0);
9088 rb_define_module_function(rb_mProcID_Syscall
, "setuid", p_sys_setuid
, 1);
9089 rb_define_module_function(rb_mProcID_Syscall
, "setgid", p_sys_setgid
, 1);
9091 rb_define_module_function(rb_mProcID_Syscall
, "setruid", p_sys_setruid
, 1);
9092 rb_define_module_function(rb_mProcID_Syscall
, "setrgid", p_sys_setrgid
, 1);
9094 rb_define_module_function(rb_mProcID_Syscall
, "seteuid", p_sys_seteuid
, 1);
9095 rb_define_module_function(rb_mProcID_Syscall
, "setegid", p_sys_setegid
, 1);
9097 rb_define_module_function(rb_mProcID_Syscall
, "setreuid", p_sys_setreuid
, 2);
9098 rb_define_module_function(rb_mProcID_Syscall
, "setregid", p_sys_setregid
, 2);
9100 rb_define_module_function(rb_mProcID_Syscall
, "setresuid", p_sys_setresuid
, 3);
9101 rb_define_module_function(rb_mProcID_Syscall
, "setresgid", p_sys_setresgid
, 3);
9102 rb_define_module_function(rb_mProcID_Syscall
, "issetugid", p_sys_issetugid
, 0);
9108 id_in
= rb_intern_const("in");
9109 id_out
= rb_intern_const("out");
9110 id_err
= rb_intern_const("err");
9111 id_pid
= rb_intern_const("pid");
9112 id_uid
= rb_intern_const("uid");
9113 id_gid
= rb_intern_const("gid");
9114 id_close
= rb_intern_const("close");
9115 id_child
= rb_intern_const("child");
9117 id_pgroup
= rb_intern_const("pgroup");
9120 id_new_pgroup
= rb_intern_const("new_pgroup");
9122 id_unsetenv_others
= rb_intern_const("unsetenv_others");
9123 id_chdir
= rb_intern_const("chdir");
9124 id_umask
= rb_intern_const("umask");
9125 id_close_others
= rb_intern_const("close_others");
9126 id_nanosecond
= rb_intern_const("nanosecond");
9127 id_microsecond
= rb_intern_const("microsecond");
9128 id_millisecond
= rb_intern_const("millisecond");
9129 id_second
= rb_intern_const("second");
9130 id_float_microsecond
= rb_intern_const("float_microsecond");
9131 id_float_millisecond
= rb_intern_const("float_millisecond");
9132 id_float_second
= rb_intern_const("float_second");
9133 id_GETTIMEOFDAY_BASED_CLOCK_REALTIME
= rb_intern_const("GETTIMEOFDAY_BASED_CLOCK_REALTIME");
9134 id_TIME_BASED_CLOCK_REALTIME
= rb_intern_const("TIME_BASED_CLOCK_REALTIME");
9136 id_TIMES_BASED_CLOCK_MONOTONIC
= rb_intern_const("TIMES_BASED_CLOCK_MONOTONIC");
9137 id_TIMES_BASED_CLOCK_PROCESS_CPUTIME_ID
= rb_intern_const("TIMES_BASED_CLOCK_PROCESS_CPUTIME_ID");
9140 id_GETRUSAGE_BASED_CLOCK_PROCESS_CPUTIME_ID
= rb_intern_const("GETRUSAGE_BASED_CLOCK_PROCESS_CPUTIME_ID");
9142 id_CLOCK_BASED_CLOCK_PROCESS_CPUTIME_ID
= rb_intern_const("CLOCK_BASED_CLOCK_PROCESS_CPUTIME_ID");
9144 id_MACH_ABSOLUTE_TIME_BASED_CLOCK_MONOTONIC
= rb_intern_const("MACH_ABSOLUTE_TIME_BASED_CLOCK_MONOTONIC");
9146 id_hertz
= rb_intern_const("hertz");