Fix typos [ci skip]
[ruby-80x24.org.git] / process.c
blob399f0d7532dea8caf5b305c90d79b02790bbb3e6
1 /**********************************************************************
3 process.c -
5 $Author$
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"
18 #include <ctype.h>
19 #include <errno.h>
20 #include <signal.h>
21 #include <stdarg.h>
22 #include <stdio.h>
23 #include <time.h>
25 #ifdef HAVE_STDLIB_H
26 # include <stdlib.h>
27 #endif
29 #ifdef HAVE_UNISTD_H
30 # include <unistd.h>
31 #endif
33 #ifdef HAVE_FCNTL_H
34 # include <fcntl.h>
35 #endif
37 #ifdef HAVE_PROCESS_H
38 # include <process.h>
39 #endif
41 #ifndef EXIT_SUCCESS
42 # define EXIT_SUCCESS 0
43 #endif
45 #ifndef EXIT_FAILURE
46 # define EXIT_FAILURE 1
47 #endif
49 #ifdef HAVE_SYS_WAIT_H
50 # include <sys/wait.h>
51 #endif
53 #ifdef HAVE_SYS_RESOURCE_H
54 # include <sys/resource.h>
55 #endif
57 #ifdef HAVE_VFORK_H
58 # include <vfork.h>
59 #endif
61 #ifdef HAVE_SYS_PARAM_H
62 # include <sys/param.h>
63 #endif
65 #ifndef MAXPATHLEN
66 # define MAXPATHLEN 1024
67 #endif
69 #include <sys/stat.h>
71 #ifdef HAVE_SYS_TIME_H
72 # include <sys/time.h>
73 #endif
75 #ifdef HAVE_SYS_TIMES_H
76 # include <sys/times.h>
77 #endif
79 #ifdef HAVE_PWD_H
80 # include <pwd.h>
81 #endif
83 #ifdef HAVE_GRP_H
84 # include <grp.h>
85 # ifdef __CYGWIN__
86 int initgroups(const char *, rb_gid_t);
87 # endif
88 #endif
90 #ifdef HAVE_SYS_ID_H
91 # include <sys/id.h>
92 #endif
94 #ifdef __APPLE__
95 # include <mach/mach_time.h>
96 #endif
98 #include "dln.h"
99 #include "hrtime.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"
112 #include "mjit.h"
113 #include "ruby/io.h"
114 #include "ruby/st.h"
115 #include "ruby/thread.h"
116 #include "ruby/util.h"
117 #include "vm_core.h"
118 #include "ruby/ractor.h"
120 /* define system APIs */
121 #ifdef _WIN32
122 #undef open
123 #define open rb_w32_uopen
124 #endif
126 #if defined(HAVE_TIMES) || defined(_WIN32)
127 static VALUE rb_cProcessTms;
128 #endif
130 #ifndef WIFEXITED
131 #define WIFEXITED(w) (((w) & 0xff) == 0)
132 #endif
133 #ifndef WIFSIGNALED
134 #define WIFSIGNALED(w) (((w) & 0x7f) > 0 && (((w) & 0x7f) < 0x7f))
135 #endif
136 #ifndef WIFSTOPPED
137 #define WIFSTOPPED(w) (((w) & 0xff) == 0x7f)
138 #endif
139 #ifndef WEXITSTATUS
140 #define WEXITSTATUS(w) (((w) >> 8) & 0xff)
141 #endif
142 #ifndef WTERMSIG
143 #define WTERMSIG(w) ((w) & 0x7f)
144 #endif
145 #ifndef WSTOPSIG
146 #define WSTOPSIG WEXITSTATUS
147 #endif
149 #if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__bsdi__)
150 #define HAVE_44BSD_SETUID 1
151 #define HAVE_44BSD_SETGID 1
152 #endif
154 #ifdef __NetBSD__
155 #undef HAVE_SETRUID
156 #undef HAVE_SETRGID
157 #endif
159 #ifdef BROKEN_SETREUID
160 #define setreuid ruby_setreuid
161 int setreuid(rb_uid_t ruid, rb_uid_t euid);
162 #endif
163 #ifdef BROKEN_SETREGID
164 #define setregid ruby_setregid
165 int setregid(rb_gid_t rgid, rb_gid_t egid);
166 #endif
168 #if defined(HAVE_44BSD_SETUID) || defined(__APPLE__)
169 #if !defined(USE_SETREUID) && !defined(BROKEN_SETREUID)
170 #define OBSOLETE_SETREUID 1
171 #endif
172 #if !defined(USE_SETREGID) && !defined(BROKEN_SETREGID)
173 #define OBSOLETE_SETREGID 1
174 #endif
175 #endif
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);
184 #if 1
185 #define p_uid_from_name p_uid_from_name
186 #define p_gid_from_name p_gid_from_name
187 #endif
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)
196 # else
197 # define GETLOGIN_R_SIZE_INIT GETLOGIN_R_SIZE_DEFAULT
198 # endif
199 # elif defined(HAVE_GETLOGIN)
200 # define USE_GETLOGIN 1
201 # endif
202 #endif
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
209 # endif
210 # if defined(HAVE_GETPWNAM_R)
211 # define USE_GETPWNAM_R 1
212 # elif defined(HAVE_GETPWNAM)
213 # define USE_GETPWNAM 1
214 # endif
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)
220 # else
221 # define GETPW_R_SIZE_INIT GETPW_R_SIZE_DEFAULT
222 # endif
223 # endif
224 # ifdef USE_GETPWNAM_R
225 # define PREPARE_GETPWNAM \
226 VALUE getpw_buf = 0
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
233 obj2uid0(VALUE id)
235 rb_uid_t uid;
236 PREPARE_GETPWNAM;
237 uid = OBJ2UID1(id);
238 FINISH_GETPWNAM;
239 return uid;
241 # else
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);
247 # endif
248 #else
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
256 # endif
257 #endif
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
265 # endif
266 # ifdef USE_GETGRNAM_R
267 # define PREPARE_GETGRNAM \
268 VALUE getgr_buf = 0
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
275 obj2gid0(VALUE id)
277 rb_gid_t gid;
278 PREPARE_GETGRNAM;
279 gid = OBJ2GID1(id);
280 FINISH_GETGRNAM;
281 return gid;
283 static rb_gid_t obj2gid(VALUE id, VALUE *getgr_buf);
284 # else
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);
290 # endif
291 #else
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
299 # endif
300 #endif
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;
308 #endif
309 #ifndef HAVE_SIG_T
310 typedef void (*sig_t) (int);
311 #endif
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;
316 #ifdef HAVE_SETPGID
317 static ID id_pgroup;
318 #endif
319 #ifdef _WIN32
320 static ID id_new_pgroup;
321 #endif
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;
326 #ifdef HAVE_TIMES
327 static ID id_TIMES_BASED_CLOCK_MONOTONIC;
328 static ID id_TIMES_BASED_CLOCK_PROCESS_CPUTIME_ID;
329 #endif
330 #ifdef RUSAGE_SELF
331 static ID id_GETRUSAGE_BASED_CLOCK_PROCESS_CPUTIME_ID;
332 #endif
333 static ID id_CLOCK_BASED_CLOCK_PROCESS_CPUTIME_ID;
334 #ifdef __APPLE__
335 static ID id_MACH_ABSOLUTE_TIME_BASED_CLOCK_MONOTONIC;
336 #endif
337 static ID id_hertz;
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
344 #else
345 #define ALWAYS_NEED_ENVP 0
346 #endif
348 static void
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);
354 if (flags == -1) {
355 static const char m[] = "reserved FD closed unexpectedly?\n";
356 (void)!write(2, m, sizeof(m) - 1);
357 return;
359 if (flags & FD_CLOEXEC) return;
360 rb_bug("reserved FD did not have close-on-exec set");
361 #else
362 rb_bug("reserved FD without close-on-exec support");
363 #endif /* FD_CLOEXEC */
364 #endif /* VM_CHECK_MODE */
367 static inline int
368 close_unless_reserved(int fd)
370 if (rb_reserved_fd_p(fd)) { /* async-signal-safe */
371 assert_close_on_exec(fd);
372 return 0;
374 return close(fd); /* async-signal-safe */
377 /*#define DEBUG_REDIRECT*/
378 #if defined(DEBUG_REDIRECT)
380 static void
381 ttyprintf(const char *fmt, ...)
383 va_list ap;
384 FILE *tty;
385 int save = errno;
386 #ifdef _WIN32
387 tty = fopen("con", "w");
388 #else
389 tty = fopen("/dev/tty", "w");
390 #endif
391 if (!tty)
392 return;
394 va_start(ap, fmt);
395 vfprintf(tty, fmt, ap);
396 va_end(ap);
397 fclose(tty);
398 errno = save;
401 static int
402 redirect_dup(int oldfd)
404 int ret;
405 ret = dup(oldfd);
406 ttyprintf("dup(%d) => %d\n", oldfd, ret);
407 return ret;
410 static int
411 redirect_dup2(int oldfd, int newfd)
413 int ret;
414 ret = dup2(oldfd, newfd);
415 ttyprintf("dup2(%d, %d) => %d\n", oldfd, newfd, ret);
416 return ret;
419 static int
420 redirect_cloexec_dup(int oldfd)
422 int ret;
423 ret = rb_cloexec_dup(oldfd);
424 ttyprintf("cloexec_dup(%d) => %d\n", oldfd, ret);
425 return ret;
428 static int
429 redirect_cloexec_dup2(int oldfd, int newfd)
431 int ret;
432 ret = rb_cloexec_dup2(oldfd, newfd);
433 ttyprintf("cloexec_dup2(%d, %d) => %d\n", oldfd, newfd, ret);
434 return ret;
437 static int
438 redirect_close(int fd)
440 int ret;
441 ret = close_unless_reserved(fd);
442 ttyprintf("close(%d) => %d\n", fd, ret);
443 return ret;
446 static int
447 parent_redirect_open(const char *pathname, int flags, mode_t perm)
449 int ret;
450 ret = rb_cloexec_open(pathname, flags, perm);
451 ttyprintf("parent_open(\"%s\", 0x%x, 0%o) => %d\n", pathname, flags, perm, ret);
452 return ret;
455 static int
456 parent_redirect_close(int fd)
458 int ret;
459 ret = close_unless_reserved(fd);
460 ttyprintf("parent_close(%d) => %d\n", fd, ret);
461 return ret;
464 #else
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)
472 #endif
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
486 * related methods;
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.
492 static VALUE
493 get_pid(void)
495 return PIDT2NUM(getpid());
499 * call-seq:
500 * Process.pid -> integer
502 * Returns the process id of this process. Not available on all
503 * platforms.
505 * Process.pid #=> 27415
508 static VALUE
509 proc_get_pid(VALUE _)
511 return get_pid();
514 static VALUE
515 get_ppid(void)
517 return PIDT2NUM(getppid());
521 * call-seq:
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}" }
530 * <em>produces:</em>
532 * I am 27417
533 * Dad is 27417
536 static VALUE
537 proc_get_ppid(VALUE _)
539 return get_ppid();
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
555 * $?.to_i #=> 25344
556 * $? >> 8 #=> 99
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 {
576 rb_pid_t pid;
577 int status;
578 int error;
581 static const rb_data_type_t rb_process_status_type = {
582 .wrap_struct_name = "Process::Status",
583 .function = {
584 .dfree = RUBY_DEFAULT_FREE,
586 .data = NULL,
587 .flags = RUBY_TYPED_FREE_IMMEDIATELY,
590 static VALUE
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);
598 VALUE
599 rb_last_status_get(void)
601 return GET_THREAD()->last_status;
605 * call-seq:
606 * Process.last_status -> Process::Status or nil
608 * Returns the status of the last executed child process in the
609 * current thread.
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
619 static VALUE
620 proc_s_last_status(VALUE mod)
622 return rb_last_status_get();
625 VALUE
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);
631 data->pid = pid;
632 data->status = status;
633 data->error = error;
635 rb_obj_freeze(last_status);
636 return last_status;
639 static VALUE
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);
644 if (data->pid) {
645 rb_ivar_set(dump, id_status, INT2NUM(data->status));
646 rb_ivar_set(dump, id_pid, PIDT2NUM(data->pid));
648 return dump;
651 static VALUE
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);
659 return real_obj;
662 void
663 rb_last_status_set(int status, rb_pid_t pid)
665 GET_THREAD()->last_status = rb_process_status_new(pid, status, 0);
668 void
669 rb_last_status_clear(void)
671 GET_THREAD()->last_status = Qnil;
674 static rb_pid_t
675 pst_pid(VALUE pst)
677 struct rb_process_status *data = RTYPEDDATA_DATA(pst);
678 return data->pid;
681 static int
682 pst_status(VALUE pst)
684 struct rb_process_status *data = RTYPEDDATA_DATA(pst);
685 return data->status;
689 * call-seq:
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"
700 static VALUE
701 pst_to_i(VALUE self)
703 int status = pst_status(self);
704 return RB_INT2NUM(status);
707 #define PST2INT(st) pst_status(st)
710 * call-seq:
711 * stat.pid -> integer
713 * Returns the process ID that this status object represents.
715 * fork { exit } #=> 26569
716 * Process.wait #=> 26569
717 * $?.pid #=> 26569
720 static VALUE
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);
729 static void
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);
736 static VALUE
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);
742 if (signame) {
743 rb_str_catf(str, " stopped SIG%s (signal %d)", signame, stopsig);
745 else {
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);
752 if (signame) {
753 rb_str_catf(str, " SIG%s (signal %d)", signame, termsig);
755 else {
756 rb_str_catf(str, " signal %d", termsig);
759 if (WIFEXITED(status)) {
760 rb_str_catf(str, " exit %d", WEXITSTATUS(status));
762 #ifdef WCOREDUMP
763 if (WCOREDUMP(status)) {
764 rb_str_cat2(str, " (core dumped)");
766 #endif
767 return str;
772 * call-seq:
773 * stat.to_s -> string
775 * Show pid and exit status as a string.
777 * system("false")
778 * p $?.to_s #=> "pid 12766 exit 1"
782 static VALUE
783 pst_to_s(VALUE st)
785 rb_pid_t pid;
786 int status;
787 VALUE str;
789 pid = pst_pid(st);
790 status = PST2INT(st);
792 str = rb_str_buf_new(0);
793 pst_message(str, pid, status);
794 return str;
799 * call-seq:
800 * stat.inspect -> string
802 * Override the inspection method.
804 * system("false")
805 * p $?.inspect #=> "#<Process::Status: pid 12861 exit 1>"
809 static VALUE
810 pst_inspect(VALUE st)
812 rb_pid_t pid;
813 int status;
814 VALUE str;
816 pid = pst_pid(st);
817 if (!pid) {
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, ">");
825 return str;
830 * call-seq:
831 * stat == other -> true or false
833 * Returns +true+ if the integer value of _stat_
834 * equals <em>other</em>.
837 static VALUE
838 pst_equal(VALUE st1, VALUE st2)
840 if (st1 == st2) return Qtrue;
841 return rb_equal(pst_to_i(st1), st2);
846 * call-seq:
847 * stat & num -> integer
849 * Logical AND of the bits in _stat_ with <em>num</em>.
851 * fork { exit 0x37 }
852 * Process.wait
853 * sprintf('%04x', $?.to_i) #=> "3700"
854 * sprintf('%04x', $? & 0x1e00) #=> "1600"
857 static VALUE
858 pst_bitand(VALUE st1, VALUE st2)
860 int status = PST2INT(st1) & NUM2INT(st2);
862 return INT2NUM(status);
867 * call-seq:
868 * stat >> num -> integer
870 * Shift the bits in _stat_ right <em>num</em> places.
872 * fork { exit 99 } #=> 26563
873 * Process.wait #=> 26563
874 * $?.to_i #=> 25344
875 * $? >> 8 #=> 99
878 static VALUE
879 pst_rshift(VALUE st1, VALUE st2)
881 int status = PST2INT(st1) >> NUM2INT(st2);
883 return INT2NUM(status);
888 * call-seq:
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
893 * set.
896 static VALUE
897 pst_wifstopped(VALUE st)
899 int status = PST2INT(st);
901 return RBOOL(WIFSTOPPED(status));
906 * call-seq:
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).
913 static VALUE
914 pst_wstopsig(VALUE st)
916 int status = PST2INT(st);
918 if (WIFSTOPPED(status))
919 return INT2NUM(WSTOPSIG(status));
920 return Qnil;
925 * call-seq:
926 * stat.signaled? -> true or false
928 * Returns +true+ if _stat_ terminated because of
929 * an uncaught signal.
932 static VALUE
933 pst_wifsignaled(VALUE st)
935 int status = PST2INT(st);
937 return RBOOL(WIFSIGNALED(status));
942 * call-seq:
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
947 * uncaught signal).
950 static VALUE
951 pst_wtermsig(VALUE st)
953 int status = PST2INT(st);
955 if (WIFSIGNALED(status))
956 return INT2NUM(WTERMSIG(status));
957 return Qnil;
962 * call-seq:
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
967 * program).
970 static VALUE
971 pst_wifexited(VALUE st)
973 int status = PST2INT(st);
975 return RBOOL(WIFEXITED(status));
980 * call-seq:
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+.
986 * fork { } #=> 26572
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
997 static VALUE
998 pst_wexitstatus(VALUE st)
1000 int status = PST2INT(st);
1002 if (WIFEXITED(status))
1003 return INT2NUM(WEXITSTATUS(status));
1004 return Qnil;
1009 * call-seq:
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+.
1016 static VALUE
1017 pst_success_p(VALUE st)
1019 int status = PST2INT(st);
1021 if (!WIFEXITED(status))
1022 return Qnil;
1023 return RBOOL(WEXITSTATUS(status) == EXIT_SUCCESS);
1028 * call-seq:
1029 * stat.coredump? -> true or false
1031 * Returns +true+ if _stat_ generated a coredump
1032 * when it terminated. Not available on all platforms.
1035 static VALUE
1036 pst_wcoredump(VALUE st)
1038 #ifdef WCOREDUMP
1039 int status = PST2INT(st);
1041 return RBOOL(WCOREDUMP(status));
1042 #else
1043 return Qfalse;
1044 #endif
1047 static rb_pid_t
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);
1054 #else
1055 # error waitpid or wait4 is required.
1056 #endif
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;
1065 rb_pid_t ret;
1066 rb_pid_t pid;
1067 int status;
1068 int options;
1069 int errnum;
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);
1077 static int
1078 waitpid_signal(struct waitpid_state *w)
1080 if (w->ec) { /* rb_waitpid */
1081 rb_threadptr_interrupt(rb_ec_thread_ptr(w->ec));
1082 return TRUE;
1084 else { /* ruby_waitpid_locked */
1085 if (w->cond) {
1086 rb_native_cond_signal(w->cond);
1087 return TRUE;
1090 return FALSE;
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
1098 static void
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;
1111 void
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);
1119 #if RUBY_SIGCHLD
1120 extern volatile unsigned int ruby_nocldwait; /* signal.c */
1121 /* called by timer thread or thread which acquired sigwait_fd */
1122 static void
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);
1130 if (!ret) continue;
1131 if (ret == -1) w->errnum = errno;
1133 w->ret = ret;
1134 list_del_init(&w->wnode);
1135 waitpid_signal(w);
1138 #else
1139 # define ruby_nocldwait 0
1140 #endif
1142 void
1143 ruby_waitpid_all(rb_vm_t *vm)
1145 #if RUBY_SIGCHLD
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);
1157 #endif
1160 static void
1161 waitpid_state_init(struct waitpid_state *w, rb_pid_t pid, int options)
1163 w->ret = 0;
1164 w->pid = pid;
1165 w->options = options;
1166 w->errnum = 0;
1167 w->status = 0;
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;
1176 return &busy_wait;
1178 return 0;
1182 * must be called with vm->waitpid_lock held, this is not interruptible
1184 rb_pid_t
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);
1195 if (w.ret) {
1196 if (w.ret == -1) w.errnum = errno;
1198 else {
1199 int sigwait_fd = -1;
1201 w.ec = 0;
1202 list_add(w.pid > 0 ? &vm->waiting_pids : &vm->waiting_grps, &w.wnode);
1203 do {
1204 if (sigwait_fd < 0)
1205 sigwait_fd = rb_sigwait_fd_get(0);
1207 if (sigwait_fd >= 0) {
1208 w.cond = 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);
1213 else {
1214 w.cond = cond;
1215 rb_native_cond_wait(w.cond, &vm->waitpid_lock);
1217 } while (!w.ret);
1218 list_del(&w.wnode);
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);
1226 if (status) {
1227 *status = w.status;
1229 if (w.ret == -1) errno = w.errnum;
1230 return w.ret;
1233 static VALUE
1234 waitpid_sleep(VALUE x)
1236 struct waitpid_state *w = (struct waitpid_state *)x;
1238 while (!w->ret) {
1239 rb_thread_sleep_interruptible();
1242 return Qfalse;
1245 static VALUE
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);
1262 return Qfalse;
1265 static void
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
1274 * outside of GVL
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);
1282 if (w->ret) {
1283 if (w->ret == -1) w->errnum = errno;
1285 else if (w->options & WNOHANG) {
1287 else {
1288 need_sleep = TRUE;
1291 if (need_sleep) {
1292 w->cond = 0;
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);
1299 if (need_sleep) {
1300 rb_ensure(waitpid_sleep, (VALUE)w, waitpid_cleanup, (VALUE)w);
1304 static void *
1305 waitpid_blocking_no_SIGCHLD(void *x)
1307 struct waitpid_state *w = x;
1309 w->ret = do_waitpid(w->pid, &w->status, w->options);
1311 return 0;
1314 static void
1315 waitpid_no_SIGCHLD(struct waitpid_state *w)
1317 if (w->options & WNOHANG) {
1318 w->ret = do_waitpid(w->pid, &w->status, w->options);
1320 else {
1321 do {
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));
1326 if (w->ret == -1)
1327 w->errnum = errno;
1330 VALUE
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);
1348 else {
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);
1363 * call-seq:
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
1373 * calling process.
1375 * -1:: Waits for any child process (the default if no _pid_ is
1376 * given).
1378 * < -1:: Waits for any child whose process group ID equals the absolute
1379 * value of _pid_.
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
1394 * $? #=> nil
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.
1406 VALUE
1407 rb_process_status_waitv(int argc, VALUE *argv, VALUE _)
1409 rb_check_arity(argc, 0, 2);
1411 rb_pid_t pid = -1;
1412 int flags = 0;
1414 if (argc >= 1) {
1415 pid = NUM2PIDT(argv[0]);
1418 if (argc >= 2) {
1419 flags = RB_NUM2INT(argv[1]);
1422 return rb_process_status_wait(pid, flags);
1425 rb_pid_t
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);
1432 pid = data->pid;
1434 if (st) *st = data->status;
1436 if (pid == -1) {
1437 errno = data->error;
1439 else {
1440 GET_THREAD()->last_status = status;
1443 return pid;
1446 static VALUE
1447 proc_wait(int argc, VALUE *argv)
1449 rb_pid_t pid;
1450 int flags, status;
1452 flags = 0;
1453 if (rb_check_arity(argc, 0, 2) == 0) {
1454 pid = -1;
1456 else {
1457 VALUE vflags;
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)
1465 rb_sys_fail(0);
1467 if (pid == 0) {
1468 rb_last_status_clear();
1469 return Qnil;
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
1483 aPid:".
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.
1490 * call-seq:
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
1503 * calling process.
1505 * -1:: Waits for any child process (the default if no _pid_ is
1506 * given).
1508 * < -1:: Waits for any child whose process group ID equals the absolute
1509 * value of _pid_.
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.
1520 * include Process
1521 * fork { exit 99 } #=> 27429
1522 * wait #=> 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
1533 static VALUE
1534 proc_m_wait(int c, VALUE *v, VALUE _)
1536 return proc_wait(c, v);
1541 * call-seq:
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
1552 * pid #=> 27437
1553 * status.exitstatus #=> 99
1556 static VALUE
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());
1566 * call-seq:
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
1576 * p Process.waitall
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>]]
1585 static VALUE
1586 proc_waitall(VALUE _)
1588 VALUE result;
1589 rb_pid_t pid;
1590 int status;
1592 result = rb_ary_new();
1593 rb_last_status_clear();
1595 for (pid = -1;;) {
1596 pid = rb_waitpid(-1, &status, 0);
1597 if (pid == -1) {
1598 int e = errno;
1599 if (e == ECHILD)
1600 break;
1601 rb_syserr_fail(e, 0);
1603 rb_ary_push(result, rb_assoc_new(PIDT2NUM(pid), rb_last_status_get()));
1605 return result;
1608 static VALUE rb_cWaiter;
1610 static VALUE
1611 detach_process_pid(VALUE thread)
1613 return rb_thread_local_aref(thread, id_pid);
1616 static VALUE
1617 detach_process_watcher(void *arg)
1619 rb_pid_t cpid, pid = (rb_pid_t)(VALUE)arg;
1620 int status;
1622 while ((cpid = rb_waitpid(pid, &status, 0)) == 0) {
1623 /* wait while alive */
1625 return rb_last_status_get();
1628 VALUE
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);
1634 return watcher;
1639 * call-seq:
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)
1664 * sleep 2
1665 * system("ps -ho pid,state -p #{p1}")
1667 * <em>produces:</em>
1669 * 27389 Z
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)
1678 * sleep 2
1679 * system("ps -ho pid,state -p #{p1}")
1681 * <em>(produces no output)</em>
1684 static VALUE
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. */
1691 static void
1692 before_exec_async_signal_safe(void)
1696 static 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)
1712 #ifdef _WIN32
1713 int rb_w32_set_nonblock2(int fd, int nonblock);
1714 #endif
1716 static int
1717 set_blocking(int fd)
1719 #ifdef _WIN32
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) {
1727 fl &= ~O_NONBLOCK;
1728 return fcntl(fd, F_SETFL, fl);
1730 return 0;
1731 #endif
1734 static void
1735 stdfd_clear_nonblock(void)
1737 /* many programs cannot deal with non-blocking stdin/stdout/stderr */
1738 int fd;
1739 for (fd = 0; fd < 3; fd++) {
1740 (void)set_blocking(fd); /* can't do much about errors anyhow */
1744 static void
1745 before_exec(void)
1747 before_exec_non_async_signal_safe();
1748 before_exec_async_signal_safe();
1751 /* This function should be async-signal-safe. Actually it is. */
1752 static void
1753 after_exec_async_signal_safe(void)
1757 static void
1758 after_exec_non_async_signal_safe(void)
1760 rb_thread_reset_timer_thread();
1761 rb_thread_start_timer_thread();
1764 static void
1765 after_exec(void)
1767 after_exec_async_signal_safe();
1768 after_exec_non_async_signal_safe();
1771 #if defined HAVE_WORKING_FORK || defined HAVE_DAEMON
1772 static void
1773 before_fork_ruby(void)
1775 before_exec();
1778 static void
1779 after_fork_ruby(void)
1781 rb_threadptr_pending_interrupt_clear(GET_THREAD());
1782 after_exec();
1784 #endif
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)
1790 static void
1791 exec_with_sh(const char *prog, char **argv, char **envp)
1793 *argv = (char *)prog;
1794 *--argv = (char *)"sh";
1795 if (envp)
1796 execve("/bin/sh", argv, envp); /* async-signal-safe */
1797 else
1798 execv("/bin/sh", argv); /* async-signal-safe (since SUSv4) */
1801 #else
1802 #define try_with_sh(err, prog, argv, envp) (void)0
1803 #endif
1805 /* This function should be async-signal-safe. Actually it is. */
1806 static int
1807 proc_exec_cmd(const char *prog, VALUE argv_str, VALUE envp_str)
1809 char **argv;
1810 #ifndef _WIN32
1811 char **envp;
1812 int err;
1813 #endif
1815 argv = ARGVSTR2ARGV(argv_str);
1817 if (!prog) {
1818 return ENOENT;
1821 #ifdef _WIN32
1822 rb_w32_uaspawn(P_OVERLAY, prog, argv);
1823 return errno;
1824 #else
1825 envp = envp_str ? RB_IMEMO_TMPBUF_PTR(envp_str) : NULL;
1826 if (envp_str)
1827 execve(prog, argv, envp); /* async-signal-safe */
1828 else
1829 execv(prog, argv); /* async-signal-safe (since SUSv4) */
1830 err = errno;
1831 try_with_sh(err, prog, argv, envp); /* try_with_sh() is async-signal-safe. */
1832 return err;
1833 #endif
1836 /* This function should be async-signal-safe. Actually it is. */
1837 static int
1838 proc_exec_sh(const char *str, VALUE envp_str)
1840 const char *s;
1842 s = str;
1843 while (*s == ' ' || *s == '\t' || *s == '\n')
1844 s++;
1846 if (!*s) {
1847 return ENOENT;
1850 #ifdef _WIN32
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));
1856 int status = -1;
1857 if (shell)
1858 execl(shell, "sh", "-c", str, (char *) NULL);
1859 else
1860 status = system(str);
1861 if (status != -1)
1862 exit(status);
1864 #else
1865 if (envp_str)
1866 execle("/bin/sh", "sh", "-c", str, (char *)NULL, RB_IMEMO_TMPBUF_PTR(envp_str)); /* async-signal-safe */
1867 else
1868 execl("/bin/sh", "sh", "-c", str, (char *)NULL); /* async-signal-safe (since SUSv4) */
1869 #endif /* _WIN32 */
1870 return errno;
1874 rb_proc_exec(const char *str)
1876 int ret;
1877 before_exec();
1878 ret = proc_exec_sh(str, Qfalse);
1879 after_exec();
1880 errno = ret;
1881 return -1;
1884 static void
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);
1890 else {
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);
1910 static size_t
1911 memsize_exec_arg(const void *ptr)
1913 return sizeof(struct rb_execarg);
1916 static const rb_data_type_t exec_arg_data_type = {
1917 "exec_arg",
1918 {mark_exec_arg, RUBY_TYPED_DEFAULT_FREE, memsize_exec_arg},
1919 0, 0, RUBY_TYPED_FREE_IMMEDIATELY
1922 #ifdef _WIN32
1923 # define DEFAULT_PROCESS_ENCODING rb_utf8_encoding()
1924 #endif
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)
1928 static VALUE
1929 export_dup(VALUE str)
1931 VALUE newstr = EXPORT_STR(str);
1932 if (newstr == str) newstr = rb_str_dup(str);
1933 return newstr;
1935 #else
1936 # define EXPORT_STR(str) (str)
1937 # define EXPORT_DUP(str) rb_str_dup(str)
1938 #endif
1940 #if !defined(HAVE_WORKING_FORK) && defined(HAVE_SPAWNV)
1941 # define USE_SPAWNV 1
1942 #else
1943 # define USE_SPAWNV 0
1944 #endif
1945 #ifndef P_NOWAIT
1946 # define P_NOWAIT _P_NOWAIT
1947 #endif
1949 #if USE_SPAWNV
1950 #if defined(_WIN32)
1951 #define proc_spawn_cmd_internal(argv, prog) rb_w32_uaspawn(P_NOWAIT, (prog), (argv))
1952 #else
1953 static rb_pid_t
1954 proc_spawn_cmd_internal(char **argv, char *prog)
1956 char fbuf[MAXPATHLEN];
1957 rb_pid_t status;
1959 if (!prog)
1960 prog = argv[0];
1961 prog = dln_find_exe_r(prog, 0, fbuf, sizeof(fbuf));
1962 if (!prog)
1963 return -1;
1965 before_exec();
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);
1971 after_exec();
1972 if (status == -1) errno = ENOEXEC;
1974 return status;
1976 #endif
1978 static rb_pid_t
1979 proc_spawn_cmd(char **argv, VALUE prog, struct rb_execarg *eargp)
1981 rb_pid_t pid = -1;
1983 if (argv[0]) {
1984 #if defined(_WIN32)
1985 DWORD flags = 0;
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);
1990 #else
1991 pid = proc_spawn_cmd_internal(argv, prog ? RSTRING_PTR(prog) : 0);
1992 #endif
1994 return pid;
1997 #if defined(_WIN32)
1998 #define proc_spawn_sh(str) rb_w32_uspawn(P_NOWAIT, (str), 0)
1999 #else
2000 static rb_pid_t
2001 proc_spawn_sh(char *str)
2003 char fbuf[MAXPATHLEN];
2004 rb_pid_t status;
2006 char *shell = dln_find_exe_r("sh", 0, fbuf, sizeof(fbuf));
2007 before_exec();
2008 status = spawnl(P_NOWAIT, (shell ? shell : "/bin/sh"), "sh", "-c", str, (char*)NULL);
2009 after_exec();
2010 return status;
2012 #endif
2013 #endif
2015 static VALUE
2016 hide_obj(VALUE obj)
2018 RBASIC_CLEAR_CLASS(obj);
2019 return obj;
2022 static VALUE
2023 check_exec_redirect_fd(VALUE v, int iskey)
2025 VALUE tmp;
2026 int fd;
2027 if (FIXNUM_P(v)) {
2028 fd = FIX2INT(v);
2030 else if (SYMBOL_P(v)) {
2031 ID id = rb_check_id(&v);
2032 if (id == id_in)
2033 fd = 0;
2034 else if (id == id_out)
2035 fd = 1;
2036 else if (id == id_err)
2037 fd = 2;
2038 else
2039 goto wrong;
2041 else if (!NIL_P(tmp = rb_io_check_io(v))) {
2042 rb_io_t *fptr;
2043 GetOpenFile(tmp, fptr);
2044 if (fptr->tied_io_for_writing)
2045 rb_raise(rb_eArgError, "duplex IO redirection");
2046 fd = fptr->fd;
2048 else {
2049 goto wrong;
2051 if (fd < 0) {
2052 rb_raise(rb_eArgError, "negative file descriptor");
2054 #ifdef _WIN32
2055 else if (fd >= 3 && iskey) {
2056 rb_raise(rb_eArgError, "wrong file descriptor (%d)", fd);
2058 #endif
2059 return INT2FIX(fd);
2061 wrong:
2062 rb_raise(rb_eArgError, "wrong exec redirect");
2063 UNREACHABLE_RETURN(Qundef);
2066 static VALUE
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)));
2076 else {
2077 int i;
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)));
2084 return ary;
2087 static void
2088 check_exec_redirect(VALUE key, VALUE val, struct rb_execarg *eargp)
2090 VALUE param;
2091 VALUE path, flags, perm;
2092 VALUE tmp;
2093 ID id;
2095 switch (TYPE(val)) {
2096 case T_SYMBOL:
2097 id = rb_check_id(&val);
2098 if (id == id_close) {
2099 param = Qnil;
2100 eargp->fd_close = check_exec_redirect1(eargp->fd_close, key, param);
2102 else if (id == id_in) {
2103 param = INT2FIX(0);
2104 eargp->fd_dup2 = check_exec_redirect1(eargp->fd_dup2, key, param);
2106 else if (id == id_out) {
2107 param = INT2FIX(1);
2108 eargp->fd_dup2 = check_exec_redirect1(eargp->fd_dup2, key, param);
2110 else if (id == id_err) {
2111 param = INT2FIX(2);
2112 eargp->fd_dup2 = check_exec_redirect1(eargp->fd_dup2, key, param);
2114 else {
2115 rb_raise(rb_eArgError, "wrong exec redirect symbol: %"PRIsVALUE,
2116 val);
2118 break;
2120 case T_FILE:
2122 val = check_exec_redirect_fd(val, 0);
2123 /* fall through */
2124 case T_FIXNUM:
2125 param = val;
2126 eargp->fd_dup2 = check_exec_redirect1(eargp->fd_dup2, key, param);
2127 break;
2129 case T_ARRAY:
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);
2136 else {
2137 FilePathValue(path);
2138 flags = rb_ary_entry(val, 1);
2139 if (NIL_P(flags))
2140 flags = INT2NUM(O_RDONLY);
2141 else if (RB_TYPE_P(flags, T_STRING))
2142 flags = INT2NUM(rb_io_modestr_oflags(StringValueCStr(flags)));
2143 else
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);
2151 break;
2153 case T_STRING:
2154 path = val;
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)) {
2161 int i;
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);
2169 else
2170 flags = INT2NUM(O_RDONLY);
2172 else
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);
2178 break;
2180 default:
2181 tmp = val;
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);
2192 static void
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());
2199 else
2200 ary = eargp->rlimit_limits;
2201 tmp = rb_check_array_type(val);
2202 if (!NIL_P(tmp)) {
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));
2209 else {
2210 rb_raise(rb_eArgError, "wrong exec rlimit option");
2213 else {
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);
2219 #endif
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);
2227 ID id;
2229 switch (TYPE(key)) {
2230 case T_SYMBOL:
2231 #if defined(HAVE_SETRLIMIT) && defined(NUM2RLIM)
2233 int rtype = rlimit_type_by_sym(key);
2234 if (rtype != -1) {
2235 rb_execarg_addopt_rlimit(eargp, rtype, val);
2236 RB_GC_GUARD(execarg_obj);
2237 return ST_CONTINUE;
2240 #endif
2241 if (!(id = rb_check_id(&key))) return ST_STOP;
2242 #ifdef HAVE_SETPGID
2243 if (id == id_pgroup) {
2244 rb_pid_t pgroup;
2245 if (eargp->pgroup_given) {
2246 rb_raise(rb_eArgError, "pgroup option specified twice");
2248 if (!RTEST(val))
2249 pgroup = -1; /* asis(-1) means "don't call setpgid()". */
2250 else if (val == Qtrue)
2251 pgroup = 0; /* new process group. */
2252 else {
2253 pgroup = NUM2PIDT(val);
2254 if (pgroup < 0) {
2255 rb_raise(rb_eArgError, "negative process group ID : %ld", (long)pgroup);
2258 eargp->pgroup_given = 1;
2259 eargp->pgroup_pgid = pgroup;
2261 else
2262 #endif
2263 #ifdef _WIN32
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");
2271 else
2272 #endif
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");
2284 FilePathValue(val);
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) {
2305 key = INT2FIX(0);
2306 goto redirect;
2308 else if (id == id_out) {
2309 key = INT2FIX(1);
2310 goto redirect;
2312 else if (id == id_err) {
2313 key = INT2FIX(2);
2314 goto redirect;
2316 else if (id == id_uid) {
2317 #ifdef HAVE_SETUID
2318 if (eargp->uid_given) {
2319 rb_raise(rb_eArgError, "uid option specified twice");
2321 check_uid_switch();
2323 eargp->uid = OBJ2UID(val);
2324 eargp->uid_given = 1;
2326 #else
2327 rb_raise(rb_eNotImpError,
2328 "uid option is unimplemented on this machine");
2329 #endif
2331 else if (id == id_gid) {
2332 #ifdef HAVE_SETGID
2333 if (eargp->gid_given) {
2334 rb_raise(rb_eArgError, "gid option specified twice");
2336 check_gid_switch();
2338 eargp->gid = OBJ2GID(val);
2339 eargp->gid_given = 1;
2341 #else
2342 rb_raise(rb_eNotImpError,
2343 "gid option is unimplemented on this machine");
2344 #endif
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");
2353 else {
2354 return ST_STOP;
2356 break;
2358 case T_FIXNUM:
2359 case T_FILE:
2360 case T_ARRAY:
2361 redirect:
2362 check_exec_redirect(key, val, eargp);
2363 break;
2365 default:
2366 return ST_STOP;
2369 RB_GC_GUARD(execarg_obj);
2370 return ST_CONTINUE;
2373 static int
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) {
2380 if (SYMBOL_P(key))
2381 rb_raise(rb_eArgError, "wrong exec option symbol: % "PRIsVALUE,
2382 key);
2383 rb_raise(rb_eArgError, "wrong exec option");
2385 return ST_CONTINUE;
2388 static int
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);
2400 return ST_CONTINUE;
2403 static int
2404 check_exec_fds_1(struct rb_execarg *eargp, VALUE h, int maxhint, VALUE ary)
2406 long i;
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));
2421 if (maxhint < fd)
2422 maxhint = fd;
2423 if (ary == eargp->fd_dup2 || ary == eargp->fd_dup2_child) {
2424 fd = FIX2INT(RARRAY_AREF(elt, 1));
2425 if (maxhint < fd)
2426 maxhint = fd;
2430 return maxhint;
2433 static VALUE
2434 check_exec_fds(struct rb_execarg *eargp)
2436 VALUE h = rb_hash_new();
2437 VALUE ary;
2438 int maxhint = -1;
2439 long i;
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));
2451 int lastfd = oldfd;
2452 VALUE val = rb_hash_lookup(h, INT2FIX(lastfd));
2453 long depth = 0;
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);
2459 depth++;
2461 if (val != Qtrue)
2462 rb_raise(rb_eArgError, "child fd %d is not redirected", oldfd);
2463 if (oldfd != lastfd) {
2464 VALUE val2;
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));
2470 val = val2;
2476 eargp->close_others_maxhint = maxhint;
2477 return h;
2480 static void
2481 rb_check_exec_options(VALUE opthash, VALUE execarg_obj)
2483 if (RHASH_EMPTY_P(opthash))
2484 return;
2485 rb_hash_stlike_foreach(opthash, check_exec_options_i, (st_data_t)execarg_obj);
2488 VALUE
2489 rb_execarg_extract_options(VALUE execarg_obj, VALUE opthash)
2491 VALUE args[2];
2492 if (RHASH_EMPTY_P(opthash))
2493 return Qnil;
2494 args[0] = execarg_obj;
2495 args[1] = Qnil;
2496 rb_hash_stlike_foreach(opthash, check_exec_options_i_extract, (st_data_t)args);
2497 return args[1];
2500 #ifdef ENV_IGNORECASE
2501 #define ENVMATCH(s1, s2) (STRCASECMP((s1), (s2)) == 0)
2502 #else
2503 #define ENVMATCH(n1, n2) (strcmp((n1), (n2)) == 0)
2504 #endif
2506 static int
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];
2513 char *k;
2515 k = StringValueCStr(key);
2516 if (strchr(k, '='))
2517 rb_raise(rb_eArgError, "environment name contains a equal : %"PRIsVALUE, key);
2519 if (!NIL_P(val))
2520 StringValueCStr(val);
2522 key = EXPORT_STR(key);
2523 if (!NIL_P(val)) val = EXPORT_STR(val);
2525 if (ENVMATCH(k, PATH_ENV)) {
2526 *path = val;
2528 rb_ary_push(env, hide_obj(rb_assoc_new(key, val)));
2530 return ST_CONTINUE;
2533 static VALUE
2534 rb_check_exec_env(VALUE hash, VALUE *path)
2536 VALUE env[2];
2538 env[0] = hide_obj(rb_ary_new());
2539 env[1] = Qfalse;
2540 rb_hash_stlike_foreach(hash, check_exec_env_i, (st_data_t)env);
2541 *path = env[1];
2543 return env[0];
2546 static VALUE
2547 rb_check_argv(int argc, VALUE *argv)
2549 VALUE tmp, prog;
2550 int i;
2552 rb_check_arity(argc, 1, UNLIMITED_ARGUMENTS);
2554 prog = 0;
2555 tmp = rb_check_array_type(argv[0]);
2556 if (!NIL_P(tmp)) {
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]);
2571 return prog;
2574 static VALUE
2575 check_hash(VALUE obj)
2577 if (RB_SPECIAL_CONST_P(obj)) return Qnil;
2578 switch (RB_BUILTIN_TYPE(obj)) {
2579 case T_STRING:
2580 case T_ARRAY:
2581 return Qnil;
2582 default:
2583 break;
2585 return rb_check_hash_type(obj);
2588 static VALUE
2589 rb_exec_getargs(int *argc_p, VALUE **argv_p, int accept_shell, VALUE *env_ret, VALUE *opthash_ret)
2591 VALUE hash, prog;
2593 if (0 < *argc_p) {
2594 hash = check_hash((*argv_p)[*argc_p-1]);
2595 if (!NIL_P(hash)) {
2596 *opthash_ret = hash;
2597 (*argc_p)--;
2601 if (0 < *argc_p) {
2602 hash = check_hash((*argv_p)[0]);
2603 if (!NIL_P(hash)) {
2604 *env_ret = hash;
2605 (*argc_p)--;
2606 (*argv_p)++;
2609 prog = rb_check_argv(*argc_p, *argv_p);
2610 if (!prog) {
2611 prog = (*argv_p)[0];
2612 if (accept_shell && *argc_p == 1) {
2613 *argc_p = 0;
2614 *argv_p = 0;
2617 return prog;
2620 #ifndef _WIN32
2621 struct string_part {
2622 const char *ptr;
2623 size_t len;
2626 static int
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;
2632 return ret;
2634 #endif
2636 static void
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);
2647 if (!NIL_P(env)) {
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;
2656 else
2657 eargp->invoke.cmd.command_name = prog;
2659 #ifndef _WIN32
2660 if (eargp->use_shell) {
2661 static const char posix_sh_cmds[][9] = {
2662 "!", /* reserved */
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 */
2692 const char *p;
2693 struct string_part first = {0, 0};
2694 int has_meta = 0;
2696 * meta characters:
2698 * * Pathname Expansion
2699 * ? Pathname Expansion
2700 * {} Grouping Commands
2701 * [] Pathname Expansion
2702 * <> Redirection
2703 * () Grouping Commands
2704 * ~ Tilde Expansion
2705 * & AND Lists, Asynchronous Lists
2706 * | OR Lists, Pipelines
2707 * \ Escape Character
2708 * $ Parameter Expansion
2709 * ; Sequential Lists
2710 * ' Single-Quotes
2711 * ` Command Substitution
2712 * " Double-Quotes
2713 * \n Lists
2715 * # Comment
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;
2723 else {
2724 if (!first.ptr) first.ptr = p;
2726 if (!has_meta && strchr("*?{}[]<>()~&|\\$;'`\"\n#", *p))
2727 has_meta = 1;
2728 if (!first.len) {
2729 if (*p == '=') {
2730 has_meta = 1;
2732 else if (*p == '/') {
2733 first.len = 0x100; /* longer than any posix_sh_cmds */
2736 if (has_meta)
2737 break;
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))
2743 has_meta = 1;
2745 if (!has_meta) {
2746 /* avoid shell since no shell meta character found. */
2747 eargp->use_shell = 0;
2749 if (!eargp->use_shell) {
2750 VALUE argv_buf;
2751 argv_buf = hide_obj(rb_str_buf_new(0));
2752 p = RSTRING_PTR(prog);
2753 while (*p) {
2754 while (*p == ' ' || *p == '\t')
2755 p++;
2756 if (*p) {
2757 const char *w = p;
2758 while (*p && *p != ' ' && *p != '\t')
2759 p++;
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);
2770 #endif
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));
2778 if (abspath)
2779 eargp->invoke.cmd.command_abspath = rb_str_new_cstr(abspath);
2780 else
2781 eargp->invoke.cmd.command_abspath = Qnil;
2784 if (!eargp->use_shell && !eargp->invoke.cmd.argv_buf) {
2785 int i;
2786 VALUE argv_buf;
2787 argv_buf = rb_str_buf_new(0);
2788 hide_obj(argv_buf);
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);
2795 #endif
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;
2803 VALUE argv_str;
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);
2808 while (p < ep) {
2809 rb_str_buf_cat(argv_str, (char *)&p, sizeof(p));
2810 p += strlen(p) + 1;
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);
2819 struct rb_execarg *
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);
2824 return eargp;
2827 static VALUE
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);
2831 VALUE prog, ret;
2832 VALUE env = Qnil, opthash = Qnil;
2833 VALUE argv_buf;
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);
2841 return ret;
2844 VALUE
2845 rb_execarg_new(int argc, const VALUE *argv, int accept_shell, int allow_exc_opt)
2847 VALUE execarg_obj;
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");
2854 return execarg_obj;
2857 void
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;
2865 static int
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' */
2877 return ST_CONTINUE;
2881 static long run_exec_dup2_tmpbuf_size(long n);
2883 struct open_struct {
2884 VALUE fname;
2885 int oflags;
2886 mode_t perm;
2887 int ret;
2888 int err;
2891 static void *
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);
2897 data->err = errno;
2898 return NULL;
2901 static void
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;
2909 static VALUE
2910 rb_execarg_parent_start1(VALUE execarg_obj)
2912 struct rb_execarg *eargp = rb_execarg_get(execarg_obj);
2913 int unsetenv_others;
2914 VALUE envopts;
2915 VALUE ary;
2917 ary = eargp->fd_open;
2918 if (ary != Qfalse) {
2919 long i;
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);
2928 int fd2;
2929 if (NIL_P(fd2v)) {
2930 struct open_struct open_data;
2931 again:
2932 open_data.fname = vpath;
2933 open_data.oflags = flags;
2934 open_data.perm = perm;
2935 open_data.ret = -1;
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();
2941 goto again;
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();
2950 else {
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;
2968 char *p, *ep;
2969 if (unsetenv_others) {
2970 envtbl = rb_hash_new();
2972 else {
2973 envtbl = rb_env_to_hash();
2975 hide_obj(envtbl);
2976 if (envopts != Qfalse) {
2977 st_table *stenv = RHASH_TBL_RAW(envtbl);
2978 long i;
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);
2983 if (NIL_P(val)) {
2984 st_data_t stkey = (st_data_t)key;
2985 st_delete(stenv, &stkey, NULL);
2987 else {
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);
2995 hide_obj(envp_buf);
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));
2998 hide_obj(envp_str);
2999 p = RSTRING_PTR(envp_buf);
3000 ep = p + RSTRING_LEN(envp_buf);
3001 while (p < ep) {
3002 rb_str_buf_cat(envp_str, (char *)&p, sizeof(p));
3003 p += strlen(p) + 1;
3005 p = NULL;
3006 rb_str_buf_cat(envp_str, (char *)&p, sizeof(p));
3007 eargp->envp_str =
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);
3013 while (*tmp_envp) {
3014 printf("%s\n", *tmp_envp);
3015 tmp_envp++;
3020 RB_GC_GUARD(execarg_obj);
3021 return Qnil;
3024 void
3025 rb_execarg_parent_start(VALUE execarg_obj)
3027 int state;
3028 rb_protect(rb_execarg_parent_start1, execarg_obj, &state);
3029 if (state) {
3030 rb_execarg_parent_end(execarg_obj);
3031 rb_jump_tag(state);
3035 static VALUE
3036 execarg_parent_end(VALUE execarg_obj)
3038 struct rb_execarg *eargp = rb_execarg_get(execarg_obj);
3039 int err = errno;
3040 VALUE ary;
3042 ary = eargp->fd_open;
3043 if (ary != Qfalse) {
3044 long i;
3045 for (i = 0; i < RARRAY_LEN(ary); i++) {
3046 VALUE elt = RARRAY_AREF(ary, i);
3047 VALUE param = RARRAY_AREF(elt, 1);
3048 VALUE fd2v;
3049 int fd2;
3050 fd2v = RARRAY_AREF(param, 3);
3051 if (!NIL_P(fd2v)) {
3052 fd2 = FIX2INT(fd2v);
3053 parent_redirect_close(fd2);
3054 RARRAY_ASET(param, 3, Qnil);
3059 errno = err;
3060 return execarg_obj;
3063 void
3064 rb_execarg_parent_end(VALUE execarg_obj)
3066 execarg_parent_end(execarg_obj);
3067 RB_GC_GUARD(execarg_obj);
3070 static void
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);
3080 #if 0
3081 void
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);
3088 #endif
3090 VALUE
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' };
3097 int err, state;
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);
3105 if (state) {
3106 execarg_parent_end(execarg_obj);
3107 after_exec(); /* restart timer thread */
3108 rb_jump_tag(state);
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 _));
3125 * call-seq:
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
3181 * given +options+.
3183 * The modified attributes may be retained when <code>exec(2)</code> system
3184 * call fails.
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
3192 * # never get here
3194 * exec "echo", "*" # echoes an asterisk
3195 * # never get here
3198 static VALUE
3199 f_exec(int c, const VALUE *a, VALUE _)
3201 rb_f_exec(c, a);
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);
3213 static int
3214 save_redirect_fd(int fd, struct rb_execarg *sargp, char *errmsg, size_t errmsg_buflen)
3216 if (sargp) {
3217 VALUE newary, redirection;
3218 int save_fd = redirect_cloexec_dup(fd), cloexec;
3219 if (save_fd == -1) {
3220 if (errno == EBADF)
3221 return 0;
3222 ERRMSG("dup");
3223 return -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)));
3244 return 0;
3247 static int
3248 intcmp(const void *a, const void *b)
3250 return *(int*)a - *(int*)b;
3253 static int
3254 intrcmp(const void *a, const void *b)
3256 return *(int*)b - *(int*)a;
3259 struct run_exec_dup2_fd_pair {
3260 int oldfd;
3261 int newfd;
3262 long older_index;
3263 long num_newer;
3264 int cloexec;
3267 static long
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. */
3274 static int
3275 fd_get_cloexec(int fd, char *errmsg, size_t errmsg_buflen)
3277 #ifdef F_GETFD
3278 int ret = 0;
3279 ret = fcntl(fd, F_GETFD); /* async-signal-safe */
3280 if (ret == -1) {
3281 ERRMSG("fcntl(F_GETFD)");
3282 return -1;
3284 if (ret & FD_CLOEXEC) return 1;
3285 #endif
3286 return 0;
3289 /* This function should be async-signal-safe. Actually it is. */
3290 static int
3291 fd_set_cloexec(int fd, char *errmsg, size_t errmsg_buflen)
3293 #ifdef F_GETFD
3294 int ret = 0;
3295 ret = fcntl(fd, F_GETFD); /* async-signal-safe */
3296 if (ret == -1) {
3297 ERRMSG("fcntl(F_GETFD)");
3298 return -1;
3300 if (!(ret & FD_CLOEXEC)) {
3301 ret |= FD_CLOEXEC;
3302 ret = fcntl(fd, F_SETFD, ret); /* async-signal-safe */
3303 if (ret == -1) {
3304 ERRMSG("fcntl(F_SETFD)");
3305 return -1;
3308 #endif
3309 return 0;
3312 /* This function should be async-signal-safe. Actually it is. */
3313 static int
3314 fd_clear_cloexec(int fd, char *errmsg, size_t errmsg_buflen)
3316 #ifdef F_GETFD
3317 int ret;
3318 ret = fcntl(fd, F_GETFD); /* async-signal-safe */
3319 if (ret == -1) {
3320 ERRMSG("fcntl(F_GETFD)");
3321 return -1;
3323 if (ret & FD_CLOEXEC) {
3324 ret &= ~FD_CLOEXEC;
3325 ret = fcntl(fd, F_SETFD, ret); /* async-signal-safe */
3326 if (ret == -1) {
3327 ERRMSG("fcntl(F_SETFD)");
3328 return -1;
3331 #endif
3332 return 0;
3335 /* This function should be async-signal-safe when sargp is NULL. Hopefully it is. */
3336 static int
3337 run_exec_dup2(VALUE ary, VALUE tmpbuf, struct rb_execarg *sargp, char *errmsg, size_t errmsg_buflen)
3339 long n, i;
3340 int ret;
3341 int extra_fd = -1;
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) */
3357 if (!sargp)
3358 qsort(pairs, n, sizeof(struct run_exec_dup2_fd_pair), intcmp); /* hopefully async-signal-safe */
3359 else
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;
3366 key.oldfd = newfd;
3367 found = bsearch(&key, pairs, n, sizeof(struct run_exec_dup2_fd_pair), intcmp); /* hopefully async-signal-safe */
3368 pairs[i].num_newer = 0;
3369 if (found) {
3370 while (pairs < found && (found-1)->oldfd == newfd)
3371 found--;
3372 while (found < pairs+n && found->oldfd == newfd) {
3373 pairs[i].num_newer++;
3374 found->older_index = i;
3375 found++;
3380 /* non-cyclic redirection: O(n) */
3381 for (i = 0; i < n; i++) {
3382 long j = 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 */
3385 goto fail;
3386 ret = redirect_dup2(pairs[j].oldfd, pairs[j].newfd); /* async-signal-safe */
3387 if (ret == -1) {
3388 ERRMSG("dup2");
3389 goto fail;
3391 if (pairs[j].cloexec &&
3392 fd_set_cloexec(pairs[j].newfd, errmsg, errmsg_buflen)) {
3393 goto fail;
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;
3398 if (j != -1)
3399 pairs[j].num_newer--;
3403 /* cyclic redirection: O(n) */
3404 for (i = 0; i < n; i++) {
3405 long j;
3406 if (pairs[i].oldfd == -1)
3407 continue;
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 */
3410 goto fail;
3411 pairs[i].oldfd = -1;
3412 continue;
3414 if (extra_fd == -1) {
3415 extra_fd = redirect_dup(pairs[i].oldfd); /* async-signal-safe */
3416 if (extra_fd == -1) {
3417 ERRMSG("dup");
3418 goto fail;
3420 rb_update_max_fd(extra_fd);
3422 else {
3423 ret = redirect_dup2(pairs[i].oldfd, extra_fd); /* async-signal-safe */
3424 if (ret == -1) {
3425 ERRMSG("dup2");
3426 goto fail;
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;
3433 while (j != -1) {
3434 ret = redirect_dup2(pairs[j].oldfd, pairs[j].newfd); /* async-signal-safe */
3435 if (ret == -1) {
3436 ERRMSG("dup2");
3437 goto fail;
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 */
3446 if (ret == -1) {
3447 ERRMSG("close");
3448 goto fail;
3452 return 0;
3454 fail:
3455 return -1;
3458 /* This function should be async-signal-safe. Actually it is. */
3459 static int
3460 run_exec_close(VALUE ary, char *errmsg, size_t errmsg_buflen)
3462 long i;
3463 int ret;
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 */
3469 if (ret == -1) {
3470 ERRMSG("close");
3471 return -1;
3474 return 0;
3477 /* This function should be async-signal-safe when sargp is NULL. Actually it is. */
3478 static int
3479 run_exec_dup2_child(VALUE ary, struct rb_execarg *sargp, char *errmsg, size_t errmsg_buflen)
3481 long i;
3482 int ret;
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 */
3490 return -1;
3491 ret = redirect_dup2(oldfd, newfd); /* async-signal-safe */
3492 if (ret == -1) {
3493 ERRMSG("dup2");
3494 return -1;
3496 rb_update_max_fd(newfd);
3498 return 0;
3501 #ifdef HAVE_SETPGID
3502 /* This function should be async-signal-safe when sargp is NULL. Actually it is. */
3503 static int
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
3509 * the parent.
3510 * No race condition, even without setpgid from the parent.
3511 * (Is there an environment which has setpgid but no FD_CLOEXEC?)
3513 int ret;
3514 rb_pid_t pgroup;
3516 pgroup = eargp->pgroup_pgid;
3517 if (pgroup == -1)
3518 return 0;
3520 if (sargp) {
3521 /* maybe meaningless with no fork environment... */
3522 sargp->pgroup_given = 1;
3523 sargp->pgroup_pgid = getpgrp();
3526 if (pgroup == 0) {
3527 pgroup = getpid(); /* async-signal-safe */
3529 ret = setpgid(getpid(), pgroup); /* async-signal-safe */
3530 if (ret == -1) ERRMSG("setpgid");
3531 return ret;
3533 #endif
3535 #if defined(HAVE_SETRLIMIT) && defined(RLIM2NUM)
3536 /* This function should be async-signal-safe when sargp is NULL. Hopefully it is. */
3537 static int
3538 run_exec_rlimit(VALUE ary, struct rb_execarg *sargp, char *errmsg, size_t errmsg_buflen)
3540 long i;
3541 for (i = 0; i < RARRAY_LEN(ary); i++) {
3542 VALUE elt = RARRAY_AREF(ary, i);
3543 int rtype = NUM2INT(RARRAY_AREF(elt, 0));
3544 struct rlimit rlim;
3545 if (sargp) {
3546 VALUE tmp, newary;
3547 if (getrlimit(rtype, &rlim) == -1) {
3548 ERRMSG("getrlimit");
3549 return -1;
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());
3556 else
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");
3564 return -1;
3567 return 0;
3569 #endif
3571 #if !defined(HAVE_WORKING_FORK)
3572 static VALUE
3573 save_env_i(RB_BLOCK_CALL_FUNC_ARGLIST(i, ary))
3575 rb_ary_push(ary, hide_obj(rb_ary_dup(argv[0])));
3576 return Qnil;
3579 static void
3580 save_env(struct rb_execarg *sargp)
3582 if (!sargp)
3583 return;
3584 if (sargp->env_modification == Qfalse) {
3585 VALUE env = rb_envtbl();
3586 if (RTEST(env)) {
3587 VALUE ary = hide_obj(rb_ary_new());
3588 rb_block_call(env, idEach, 0, 0, save_env_i,
3589 (VALUE)ary);
3590 sargp->env_modification = ary;
3592 sargp->unsetenv_others_given = 1;
3593 sargp->unsetenv_others_do = 1;
3596 #endif
3598 #ifdef _WIN32
3599 #undef chdir
3600 #define chdir(p) rb_w32_uchdir(p)
3601 #endif
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)
3607 VALUE obj;
3609 if (sargp) {
3610 /* assume that sargp is always NULL on fork-able environments */
3611 MEMZERO(sargp, struct rb_execarg, 1);
3612 sargp->redirect_fds = Qnil;
3615 #ifdef HAVE_SETPGID
3616 if (eargp->pgroup_given) {
3617 if (run_exec_pgroup(eargp, sargp, errmsg, errmsg_buflen) == -1) /* async-signal-safe */
3618 return -1;
3620 #endif
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 */
3626 return -1;
3628 #endif
3630 #if !defined(HAVE_WORKING_FORK)
3631 if (eargp->unsetenv_others_given && eargp->unsetenv_others_do) {
3632 save_env(sargp);
3633 rb_env_clear();
3636 obj = eargp->env_modification;
3637 if (obj != Qfalse) {
3638 long i;
3639 save_env(sargp);
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);
3644 if (NIL_P(val))
3645 ruby_setenv(StringValueCStr(key), 0);
3646 else
3647 ruby_setenv(StringValueCStr(key), StringValueCStr(val));
3650 #endif
3652 if (eargp->umask_given) {
3653 mode_t mask = eargp->umask_mask;
3654 mode_t oldmask = umask(mask); /* never fail */ /* async-signal-safe */
3655 if (sargp) {
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 */
3664 return -1;
3667 obj = eargp->fd_close;
3668 if (obj != Qfalse) {
3669 if (sargp)
3670 rb_warn("cannot close fd before spawn");
3671 else {
3672 if (run_exec_close(obj, errmsg, errmsg_buflen) == -1) /* async-signal-safe */
3673 return -1;
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 */
3681 #endif
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 */
3686 return -1;
3689 if (eargp->chdir_given) {
3690 if (sargp) {
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 */
3695 ERRMSG("chdir");
3696 return -1;
3700 #ifdef HAVE_SETGID
3701 if (eargp->gid_given) {
3702 if (setgid(eargp->gid) < 0) {
3703 ERRMSG("setgid");
3704 return -1;
3707 #endif
3708 #ifdef HAVE_SETUID
3709 if (eargp->uid_given) {
3710 if (setuid(eargp->uid) < 0) {
3711 ERRMSG("setuid");
3712 return -1;
3715 #endif
3717 if (sargp) {
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();
3726 errno = preserve;
3729 return 0;
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);
3737 return -1;
3740 static int
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;
3745 #else
3746 struct rb_execarg *const sargp = NULL;
3747 #endif
3748 int err;
3750 if (rb_execarg_run_options(eargp, sargp, errmsg, errmsg_buflen) < 0) { /* hopefully async-signal-safe */
3751 return errno;
3754 if (eargp->use_shell) {
3755 err = proc_exec_sh(RSTRING_PTR(eargp->invoke.sh.shell_script), eargp->envp_str); /* async-signal-safe */
3757 else {
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);
3765 #endif
3767 return err;
3770 #ifdef HAVE_WORKING_FORK
3771 /* This function should be async-signal-safe. Hopefully it is. */
3772 static int
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
3780 #else
3781 static VALUE
3782 proc_syswait(VALUE pid)
3784 rb_syswait((int)pid);
3785 return Qnil;
3787 #endif
3789 static int
3790 move_fds_to_avoid_crash(int *fdp, int n, VALUE fds)
3792 int min = 0;
3793 int i;
3794 for (i = 0; i < n; i++) {
3795 int ret;
3796 while (RTEST(rb_hash_lookup(fds, INT2FIX(fdp[i])))) {
3797 if (min <= fdp[i])
3798 min = fdp[i]+1;
3799 while (RTEST(rb_hash_lookup(fds, INT2FIX(min))))
3800 min++;
3801 ret = rb_cloexec_fcntl_dupfd(fdp[i], min);
3802 if (ret == -1)
3803 return -1;
3804 rb_update_max_fd(ret);
3805 close(fdp[i]);
3806 fdp[i] = ret;
3809 return 0;
3812 static int
3813 pipe_nocrash(int filedes[2], VALUE fds)
3815 int ret;
3816 ret = rb_pipe(filedes);
3817 if (ret == -1)
3818 return -1;
3819 if (RTEST(fds)) {
3820 int save = errno;
3821 if (move_fds_to_avoid_crash(filedes, 2, fds) == -1) {
3822 close(filedes[0]);
3823 close(filedes[1]);
3824 return -1;
3826 errno = save;
3828 return ret;
3831 #ifndef O_BINARY
3832 #define O_BINARY 0
3833 #endif
3835 static VALUE
3836 rb_thread_sleep_that_takes_VALUE_as_sole_argument(VALUE n)
3838 rb_thread_sleep(NUM2INT(n));
3839 return Qundef;
3842 static int
3843 handle_fork_error(int err, struct rb_process_status *status, int *ep, volatile int *try_gc_p)
3845 int state = 0;
3847 switch (err) {
3848 case ENOMEM:
3849 if ((*try_gc_p)-- > 0 && !rb_during_gc()) {
3850 rb_gc();
3851 return 0;
3853 break;
3854 case EAGAIN:
3855 #if defined(EWOULDBLOCK) && EWOULDBLOCK != EAGAIN
3856 case EWOULDBLOCK:
3857 #endif
3858 if (!status && !ep) {
3859 rb_thread_sleep(1);
3860 return 0;
3862 else {
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;
3867 break;
3869 if (ep) {
3870 close(ep[0]);
3871 close(ep[1]);
3872 errno = err;
3874 if (state && !status) rb_jump_tag(state);
3875 return -1;
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
3885 * process.
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
3901 * returns pid.
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.
3909 static ssize_t
3910 write_retry(int fd, const void *buf, size_t len)
3912 ssize_t w;
3914 do {
3915 w = write(fd, buf, len);
3916 } while (w < 0 && errno == EINTR);
3918 return w;
3921 static ssize_t
3922 read_retry(int fd, void *buf, size_t len)
3924 ssize_t r;
3926 if (set_blocking(fd) != 0) {
3927 #ifndef _WIN32
3928 rb_async_bug_errno("set_blocking failed reading child error", errno);
3929 #endif
3932 do {
3933 r = read(fd, buf, len);
3934 } while (r < 0 && errno == EINTR);
3936 return r;
3939 static void
3940 send_child_error(int fd, char *errmsg, size_t errmsg_buflen)
3942 int err;
3944 err = errno;
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)
3950 err = errno;
3954 static int
3955 recv_child_error(int fd, int *errp, char *errmsg, size_t errmsg_buflen)
3957 int err;
3958 ssize_t size;
3959 if ((size = read_retry(fd, &err, sizeof(err))) < 0) {
3960 err = errno;
3962 *errp = err;
3963 if (size == sizeof(err) &&
3964 errmsg && 0 < errmsg_buflen) {
3965 ssize_t ret = read_retry(fd, errmsg, errmsg_buflen-1);
3966 if (0 <= ret) {
3967 errmsg[ret] = '\0';
3970 close(fd);
3971 return size != 0;
3974 #ifdef HAVE_WORKING_VFORK
3975 #if !defined(HAVE_GETRESUID) && defined(HAVE_GETUIDX)
3976 /* AIX 7.1 */
3977 static int
3978 getresuid(rb_uid_t *ruid, rb_uid_t *euid, rb_uid_t *suid)
3980 rb_uid_t ret;
3982 *ruid = getuid();
3983 *euid = geteuid();
3984 ret = getuidx(ID_SAVED);
3985 if (ret == (rb_uid_t)-1)
3986 return -1;
3987 *suid = ret;
3988 return 0;
3990 #define HAVE_GETRESUID
3991 #endif
3993 #if !defined(HAVE_GETRESGID) && defined(HAVE_GETGIDX)
3994 /* AIX 7.1 */
3995 static int
3996 getresgid(rb_gid_t *rgid, rb_gid_t *egid, rb_gid_t *sgid)
3998 rb_gid_t ret;
4000 *rgid = getgid();
4001 *egid = getegid();
4002 ret = getgidx(ID_SAVED);
4003 if (ret == (rb_gid_t)-1)
4004 return -1;
4005 *sgid = ret;
4006 return 0;
4008 #define HAVE_GETRESGID
4009 #endif
4011 static int
4012 has_privilege(void)
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
4030 if (issetugid())
4031 return 1;
4032 #endif
4034 #ifdef HAVE_GETRESUID
4036 int ret;
4037 rb_uid_t suid;
4038 ret = getresuid(&ruid, &euid, &suid);
4039 if (ret == -1)
4040 rb_sys_fail("getresuid(2)");
4041 if (euid != suid)
4042 return 1;
4044 #else
4045 ruid = getuid();
4046 euid = geteuid();
4047 #endif
4049 if (euid == 0 || euid != ruid)
4050 return 1;
4052 #ifdef HAVE_GETRESGID
4054 int ret;
4055 rb_gid_t sgid;
4056 ret = getresgid(&rgid, &egid, &sgid);
4057 if (ret == -1)
4058 rb_sys_fail("getresgid(2)");
4059 if (egid != sgid)
4060 return 1;
4062 #else
4063 rgid = getgid();
4064 egid = getegid();
4065 #endif
4067 if (egid != rgid)
4068 return 1;
4070 return 0;
4072 #endif
4074 struct child_handler_disabler_state
4076 sigset_t sigmask;
4079 static void
4080 disable_child_handler_before_fork(struct child_handler_disabler_state *old)
4082 #ifdef HAVE_PTHREAD_SIGMASK
4083 int ret;
4084 sigset_t all;
4086 ret = sigfillset(&all);
4087 if (ret == -1)
4088 rb_sys_fail("sigfillset");
4090 ret = pthread_sigmask(SIG_SETMASK, &all, &old->sigmask); /* not async-signal-safe */
4091 if (ret != 0) {
4092 rb_syserr_fail(ret, "pthread_sigmask");
4094 #else
4095 # pragma GCC warning "pthread_sigmask on fork is not available. potentially dangerous"
4096 #endif
4099 static void
4100 disable_child_handler_fork_parent(struct child_handler_disabler_state *old)
4102 #ifdef HAVE_PTHREAD_SIGMASK
4103 int ret;
4105 ret = pthread_sigmask(SIG_SETMASK, &old->sigmask, NULL); /* not async-signal-safe */
4106 if (ret != 0) {
4107 rb_syserr_fail(ret, "pthread_sigmask");
4109 #else
4110 # pragma GCC warning "pthread_sigmask on fork is not available. potentially dangerous"
4111 #endif
4114 /* This function should be async-signal-safe. Actually it is. */
4115 static int
4116 disable_child_handler_fork_child(struct child_handler_disabler_state *old, char *errmsg, size_t errmsg_buflen)
4118 int sig;
4119 int ret;
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");
4129 return -1;
4131 #ifdef SIGPIPE
4132 if (sig == SIGPIPE) {
4133 continue;
4135 #endif
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 */
4145 if (ret != 0) {
4146 ERRMSG("sigprocmask");
4147 return -1;
4149 return 0;
4152 static rb_pid_t
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)
4158 rb_pid_t pid;
4159 volatile int try_gc = 1;
4160 struct child_handler_disabler_state old;
4161 int err;
4162 rb_nativethread_lock_t *const volatile waitpid_lock_init =
4163 (w && WAITPID_USE_SIGCHLD) ? &GET_VM()->waitpid_lock : 0;
4165 while (1) {
4166 rb_nativethread_lock_t *waitpid_lock = waitpid_lock_init;
4167 prefork();
4168 disable_child_handler_before_fork(&old);
4169 if (waitpid_lock) {
4170 rb_native_mutex_lock(waitpid_lock);
4172 #ifdef HAVE_WORKING_VFORK
4173 if (!has_privilege())
4174 pid = vfork();
4175 else
4176 pid = rb_fork();
4177 #else
4178 pid = rb_fork();
4179 #endif
4180 if (pid == 0) {/* fork succeed, child process */
4181 int ret;
4182 close(ep[0]);
4183 ret = disable_child_handler_fork_child(&old, errmsg, errmsg_buflen); /* async-signal-safe */
4184 if (ret == 0) {
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);
4191 #else
4192 _exit(127);
4193 #endif
4195 err = errno;
4196 waitpid_lock = waitpid_lock_init;
4197 if (waitpid_lock) {
4198 if (pid > 0 && w != WAITPID_LOCK_ONLY) {
4199 w->pid = pid;
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 */
4206 return pid;
4207 /* fork failed */
4208 if (handle_fork_error(err, status, ep, &try_gc))
4209 return -1;
4213 static rb_pid_t
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)
4218 rb_pid_t pid;
4219 int err;
4220 int ep[2];
4221 int error_occurred;
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;
4233 if (pid < 0) {
4234 if (status) status->error = errno;
4236 return pid;
4239 close(ep[1]);
4241 error_occurred = recv_child_error(ep[0], &err, errmsg, errmsg_buflen);
4243 if (error_occurred) {
4244 if (status) {
4245 int state = 0;
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) {
4255 rb_syswait(pid);
4258 errno = err;
4259 return -1;
4262 return pid;
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
4272 rb_pid_t
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);
4281 if (status) {
4282 *status = process_status.status;
4285 return result;
4288 static rb_pid_t
4289 rb_fork_ruby2(struct rb_process_status *status)
4291 rb_pid_t pid;
4292 int try_gc = 1, err;
4293 struct child_handler_disabler_state old;
4295 if (status) status->status = 0;
4297 while (1) {
4298 prefork();
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);
4301 before_fork_ruby();
4302 pid = rb_fork();
4303 err = errno;
4304 if (status) {
4305 status->pid = pid;
4306 status->error = err;
4308 after_fork_ruby();
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();
4315 return pid;
4318 /* fork failed */
4319 if (handle_fork_error(err, status, NULL, &try_gc)) {
4320 return -1;
4325 rb_pid_t
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;
4334 return pid;
4337 rb_pid_t
4338 rb_call_proc__fork(void)
4340 VALUE pid = rb_funcall(rb_mProcess, rb_intern("_fork"), 0);
4342 return NUM2PIDT(pid);
4344 #endif
4346 #if defined(HAVE_WORKING_FORK) && !defined(CANNOT_FORK_WITH_PTHREAD)
4348 * call-seq:
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.
4359 VALUE
4360 rb_proc__fork(VALUE _obj)
4362 rb_pid_t pid = rb_fork_ruby(NULL);
4364 if (pid == -1) {
4365 rb_sys_fail("fork(2)");
4368 return PIDT2NUM(pid);
4372 * call-seq:
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().
4396 static VALUE
4397 rb_f_fork(VALUE obj)
4399 rb_pid_t pid;
4401 pid = rb_call_proc__fork();
4403 if (pid == 0) {
4404 if (rb_block_given_p()) {
4405 int status;
4406 rb_protect(rb_yield, Qundef, &status);
4407 ruby_stop(status);
4409 return Qnil;
4412 return PIDT2NUM(pid);
4414 #else
4415 #define rb_proc__fork rb_f_notimplement
4416 #define rb_f_fork rb_f_notimplement
4417 #endif
4419 static int
4420 exit_status_code(VALUE status)
4422 int istatus;
4424 switch (status) {
4425 case Qtrue:
4426 istatus = EXIT_SUCCESS;
4427 break;
4428 case Qfalse:
4429 istatus = EXIT_FAILURE;
4430 break;
4431 default:
4432 istatus = NUM2INT(status);
4433 #if EXIT_SUCCESS != 0
4434 if (istatus == 0)
4435 istatus = EXIT_SUCCESS;
4436 #endif
4437 break;
4439 return istatus;
4442 NORETURN(static VALUE rb_f_exit_bang(int argc, VALUE *argv, VALUE obj));
4444 * call-seq:
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
4449 * exit status.
4451 * Process.exit!(true)
4454 static VALUE
4455 rb_f_exit_bang(int argc, VALUE *argv, VALUE obj)
4457 int istatus;
4459 if (rb_check_arity(argc, 0, 1) == 1) {
4460 istatus = exit_status_code(argv[0]);
4462 else {
4463 istatus = EXIT_FAILURE;
4465 _exit(istatus);
4467 UNREACHABLE_RETURN(Qnil);
4470 void
4471 rb_exit(int status)
4473 if (GET_EC()->tag) {
4474 VALUE args[2];
4476 args[0] = INT2NUM(status);
4477 args[1] = rb_str_new2("exit");
4478 rb_exc_raise(rb_class_new_instance(2, args, rb_eSystemExit));
4480 ruby_stop(status);
4483 VALUE
4484 rb_f_exit(int argc, const VALUE *argv)
4486 int istatus;
4488 if (rb_check_arity(argc, 0, 1) == 1) {
4489 istatus = exit_status_code(argv[0]);
4491 else {
4492 istatus = EXIT_SUCCESS;
4494 rb_exit(istatus);
4496 UNREACHABLE_RETURN(Qnil);
4499 NORETURN(static VALUE f_exit(int c, const VALUE *a, VALUE _));
4501 * call-seq:
4502 * exit(status=true)
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
4509 * environment.
4510 * +true+ and +FALSE+ of _status_ means success and failure
4511 * respectively. The interpretation of other integer values are
4512 * system dependent.
4514 * begin
4515 * exit
4516 * puts "never get here"
4517 * rescue SystemExit
4518 * puts "rescued a SystemExit exception"
4519 * end
4520 * puts "after begin block"
4522 * <em>produces:</em>
4524 * rescued a SystemExit exception
4525 * after begin block
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" })
4533 * exit
4535 * <em>produces:</em>
4537 * at_exit function
4538 * in finalizer
4541 static VALUE
4542 f_exit(int c, const VALUE *a, VALUE _)
4544 rb_f_exit(c, a);
4545 UNREACHABLE_RETURN(Qnil);
4548 VALUE
4549 rb_f_abort(int argc, const VALUE *argv)
4551 rb_check_arity(argc, 0, 1);
4552 if (argc == 0) {
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);
4560 else {
4561 VALUE args[2];
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 _));
4576 * call-seq:
4577 * abort
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.
4586 static VALUE
4587 f_abort(int c, const VALUE *a, VALUE _)
4589 rb_f_abort(c, a);
4590 UNREACHABLE_RETURN(Qnil);
4593 void
4594 rb_syswait(rb_pid_t pid)
4596 int status;
4598 rb_waitpid(pid, &status, 0);
4601 #if !defined HAVE_WORKING_FORK && !defined HAVE_SPAWNV && !defined __EMSCRIPTEN__
4602 char *
4603 rb_execarg_commandline(const struct rb_execarg *eargp, VALUE *prog)
4605 VALUE cmd = *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] = ' ';
4617 *prog = cmd;
4618 return p;
4620 return StringValueCStr(*prog);
4622 #endif
4624 static rb_pid_t
4625 rb_spawn_process(struct rb_execarg *eargp, char *errmsg, size_t errmsg_buflen)
4627 rb_pid_t pid;
4628 #if !defined HAVE_WORKING_FORK || USE_SPAWNV
4629 VALUE prog;
4630 struct rb_execarg sarg;
4631 # if !defined HAVE_SPAWNV
4632 int status;
4633 # endif
4634 #endif
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);
4638 #else
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) {
4642 return -1;
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));
4653 else {
4654 char **argv = ARGVSTR2ARGV(eargp->invoke.cmd.argv_str);
4655 pid = proc_spawn_cmd(argv, prog, eargp);
4658 if (pid == -1) {
4659 rb_last_status_set(0x7f << 8, pid);
4661 # else
4662 status = system(rb_execarg_commandline(eargp, &prog));
4663 pid = 1; /* dummy */
4664 rb_last_status_set((status & 0xff) << 8, pid);
4665 # endif
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);
4672 #endif
4674 return pid;
4677 struct spawn_args {
4678 VALUE execarg;
4679 struct {
4680 char *ptr;
4681 size_t buflen;
4682 } errmsg;
4685 static VALUE
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);
4694 static rb_pid_t
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);
4715 static rb_pid_t
4716 rb_spawn_internal(int argc, const VALUE *argv, char *errmsg, size_t errmsg_buflen)
4718 VALUE execarg_obj;
4720 execarg_obj = rb_execarg_new(argc, argv, TRUE, FALSE);
4721 return rb_execarg_spawn(execarg_obj, errmsg, errmsg_buflen);
4724 rb_pid_t
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);
4730 rb_pid_t
4731 rb_spawn(int argc, const VALUE *argv)
4733 return rb_spawn_internal(argc, argv, NULL, 0);
4737 * call-seq:
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
4759 * for Kernel#spawn.
4761 * The hash arguments, env and options, are same as #exec and #spawn.
4762 * See Kernel#spawn for details.
4764 * system("echo *")
4765 * system("echo", "*")
4767 * <em>produces:</em>
4769 * config.h main.rb
4772 * Error handling:
4774 * system("cat nonexistent.txt")
4775 * # => false
4776 * system("catt nonexistent.txt")
4777 * # => nil
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.
4787 static VALUE
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);
4802 if (pid > 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) {
4811 return Qtrue;
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);
4820 else {
4821 return Qnil;
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));
4832 else {
4833 return Qfalse;
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);
4844 else {
4845 return Qnil;
4850 * call-seq:
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")
4857 * Process.wait pid
4859 * pid = spawn(RbConfig.ruby, "-eputs'Hello, world!'")
4860 * Process.wait pid
4862 * This method is similar to Kernel#system but it doesn't wait for the command
4863 * to finish.
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:
4874 * env: hash
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.
4879 * command...:
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)
4883 * options: hash
4884 * clearing environment variables:
4885 * :unsetenv_others => true : clear environment variables except specified by env
4886 * :unsetenv_others => false : don't clear (default)
4887 * process group:
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]
4897 * umask:
4898 * :umask => int
4899 * redirection:
4900 * key:
4901 * FD : single file descriptor in child process
4902 * [FD, FD, ...] : multiple file descriptor in child process
4903 * value:
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:
4920 * :chdir => str
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+,
4939 * it specifies
4940 * process group,
4941 * create new process group,
4942 * resource limit,
4943 * current directory,
4944 * umask and
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)
5086 * r, w = IO.pipe
5087 * pid = spawn(command, :out=>w) # r, w is closed in the child process.
5088 * w.close
5090 * :close is specified as a hash value to close a fd individually.
5092 * f = open(foo)
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)
5102 * log_w.close
5103 * p log_r.read
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.
5118 static VALUE
5119 rb_f_spawn(int argc, VALUE *argv, VALUE _)
5121 rb_pid_t pid;
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));
5132 if (pid == -1) {
5133 int err = errno;
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);
5140 #else
5141 return Qnil;
5142 #endif
5146 * call-seq:
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
5156 * sleep 1.2 #=> 1
5157 * Time.new #=> 2008-03-08 19:56:20 +0900
5158 * sleep 1.9 #=> 2
5159 * Time.new #=> 2008-03-08 19:56:22 +0900
5162 static VALUE
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);
5171 else {
5172 if (argc == 0) {
5173 rb_thread_sleep_forever();
5175 else {
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)
5189 * call-seq:
5190 * Process.getpgrp -> integer
5192 * Returns the process group ID for this process. Not available on
5193 * all platforms.
5195 * Process.getpgid(0) #=> 25527
5196 * Process.getpgrp #=> 25527
5199 static VALUE
5200 proc_getpgrp(VALUE _)
5202 rb_pid_t pgrp;
5204 #if defined(HAVE_GETPGRP) && defined(GETPGRP_VOID)
5205 pgrp = getpgrp();
5206 if (pgrp < 0) rb_sys_fail(0);
5207 return PIDT2NUM(pgrp);
5208 #else /* defined(HAVE_GETPGID) */
5209 pgrp = getpgid(0);
5210 if (pgrp < 0) rb_sys_fail(0);
5211 return PIDT2NUM(pgrp);
5212 #endif
5214 #else
5215 #define proc_getpgrp rb_f_notimplement
5216 #endif
5219 #if defined(HAVE_SETPGID) || (defined(HAVE_SETPGRP) && defined(SETPGRP_VOID))
5221 * call-seq:
5222 * Process.setpgrp -> 0
5224 * Equivalent to <code>setpgid(0,0)</code>. Not available on all
5225 * platforms.
5228 static VALUE
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. */
5235 #ifdef HAVE_SETPGID
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);
5239 #endif
5240 return INT2FIX(0);
5242 #else
5243 #define proc_setpgrp rb_f_notimplement
5244 #endif
5247 #if defined(HAVE_GETPGID)
5249 * call-seq:
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
5258 static VALUE
5259 proc_getpgid(VALUE obj, VALUE pid)
5261 rb_pid_t i;
5263 i = getpgid(NUM2PIDT(pid));
5264 if (i < 0) rb_sys_fail(0);
5265 return PIDT2NUM(i);
5267 #else
5268 #define proc_getpgid rb_f_notimplement
5269 #endif
5272 #ifdef HAVE_SETPGID
5274 * call-seq:
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.
5281 static VALUE
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);
5290 return INT2FIX(0);
5292 #else
5293 #define proc_setpgid rb_f_notimplement
5294 #endif
5297 #ifdef HAVE_GETSID
5299 * call-seq:
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
5310 static VALUE
5311 proc_getsid(int argc, VALUE *argv, VALUE _)
5313 rb_pid_t sid;
5314 rb_pid_t pid = 0;
5316 if (rb_check_arity(argc, 0, 1) == 1 && !NIL_P(argv[0]))
5317 pid = NUM2PIDT(argv[0]);
5319 sid = getsid(pid);
5320 if (sid < 0) rb_sys_fail(0);
5321 return PIDT2NUM(sid);
5323 #else
5324 #define proc_getsid rb_f_notimplement
5325 #endif
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()
5332 #endif
5334 * call-seq:
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
5344 static VALUE
5345 proc_setsid(VALUE _)
5347 rb_pid_t pid;
5349 pid = setsid();
5350 if (pid < 0) rb_sys_fail(0);
5351 return PIDT2NUM(pid);
5354 #if !defined(HAVE_SETSID)
5355 #define HAVE_SETSID 1
5356 static rb_pid_t
5357 ruby_setsid(void)
5359 rb_pid_t pid;
5360 int ret;
5362 pid = getpid();
5363 #if defined(SETPGRP_VOID)
5364 ret = setpgrp();
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). */
5368 #else
5369 ret = setpgrp(0, pid);
5370 #endif
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);
5376 close(fd);
5378 return pid;
5380 #endif
5381 #else
5382 #define proc_setsid rb_f_notimplement
5383 #endif
5386 #ifdef HAVE_GETPRIORITY
5388 * call-seq:
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
5404 static VALUE
5405 proc_getpriority(VALUE obj, VALUE which, VALUE who)
5407 int prio, iwhich, iwho;
5409 iwhich = NUM2INT(which);
5410 iwho = NUM2INT(who);
5412 errno = 0;
5413 prio = getpriority(iwhich, iwho);
5414 if (errno) rb_sys_fail(0);
5415 return INT2FIX(prio);
5417 #else
5418 #define proc_getpriority rb_f_notimplement
5419 #endif
5422 #ifdef HAVE_GETPRIORITY
5424 * call-seq:
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
5435 static VALUE
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)
5445 rb_sys_fail(0);
5446 return INT2FIX(0);
5448 #else
5449 #define proc_setpriority rb_f_notimplement
5450 #endif
5452 #if defined(HAVE_SETRLIMIT) && defined(NUM2RLIM)
5453 static int
5454 rlimit_resource_name2int(const char *name, long len, int casetype)
5456 int resource;
5457 const char *p;
5458 #define RESCHECK(r) \
5459 do { \
5460 if (len == rb_strlen_lit(#r) && STRCASECMP(name, #r) == 0) { \
5461 resource = RLIMIT_##r; \
5462 goto found; \
5464 } while (0)
5466 switch (TOUPPER(*name)) {
5467 case 'A':
5468 #ifdef RLIMIT_AS
5469 RESCHECK(AS);
5470 #endif
5471 break;
5473 case 'C':
5474 #ifdef RLIMIT_CORE
5475 RESCHECK(CORE);
5476 #endif
5477 #ifdef RLIMIT_CPU
5478 RESCHECK(CPU);
5479 #endif
5480 break;
5482 case 'D':
5483 #ifdef RLIMIT_DATA
5484 RESCHECK(DATA);
5485 #endif
5486 break;
5488 case 'F':
5489 #ifdef RLIMIT_FSIZE
5490 RESCHECK(FSIZE);
5491 #endif
5492 break;
5494 case 'M':
5495 #ifdef RLIMIT_MEMLOCK
5496 RESCHECK(MEMLOCK);
5497 #endif
5498 #ifdef RLIMIT_MSGQUEUE
5499 RESCHECK(MSGQUEUE);
5500 #endif
5501 break;
5503 case 'N':
5504 #ifdef RLIMIT_NOFILE
5505 RESCHECK(NOFILE);
5506 #endif
5507 #ifdef RLIMIT_NPROC
5508 RESCHECK(NPROC);
5509 #endif
5510 #ifdef RLIMIT_NICE
5511 RESCHECK(NICE);
5512 #endif
5513 break;
5515 case 'R':
5516 #ifdef RLIMIT_RSS
5517 RESCHECK(RSS);
5518 #endif
5519 #ifdef RLIMIT_RTPRIO
5520 RESCHECK(RTPRIO);
5521 #endif
5522 #ifdef RLIMIT_RTTIME
5523 RESCHECK(RTTIME);
5524 #endif
5525 break;
5527 case 'S':
5528 #ifdef RLIMIT_STACK
5529 RESCHECK(STACK);
5530 #endif
5531 #ifdef RLIMIT_SBSIZE
5532 RESCHECK(SBSIZE);
5533 #endif
5534 #ifdef RLIMIT_SIGPENDING
5535 RESCHECK(SIGPENDING);
5536 #endif
5537 break;
5539 return -1;
5541 found:
5542 switch (casetype) {
5543 case 0:
5544 for (p = name; *p; p++)
5545 if (!ISUPPER(*p))
5546 return -1;
5547 break;
5549 case 1:
5550 for (p = name; *p; p++)
5551 if (!ISLOWER(*p))
5552 return -1;
5553 break;
5555 default:
5556 rb_bug("unexpected casetype");
5558 return resource;
5559 #undef RESCHECK
5562 static int
5563 rlimit_type_by_hname(const char *name, long len)
5565 return rlimit_resource_name2int(name, len, 0);
5568 static int
5569 rlimit_type_by_lname(const char *name, long len)
5571 return rlimit_resource_name2int(name, len, 1);
5574 static int
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);
5580 int rtype = -1;
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);
5588 RB_GC_GUARD(key);
5589 return rtype;
5592 static int
5593 rlimit_resource_type(VALUE rtype)
5595 const char *name;
5596 long len;
5597 VALUE v;
5598 int r;
5600 switch (TYPE(rtype)) {
5601 case T_SYMBOL:
5602 v = rb_sym2str(rtype);
5603 name = RSTRING_PTR(v);
5604 len = RSTRING_LEN(v);
5605 break;
5607 default:
5608 v = rb_check_string_type(rtype);
5609 if (!NIL_P(v)) {
5610 rtype = v;
5611 case T_STRING:
5612 name = StringValueCStr(rtype);
5613 len = RSTRING_LEN(rtype);
5614 break;
5616 /* fall through */
5618 case T_FIXNUM:
5619 case T_BIGNUM:
5620 return NUM2INT(rtype);
5623 r = rlimit_type_by_hname(name, len);
5624 if (r != -1)
5625 return r;
5627 rb_raise(rb_eArgError, "invalid resource name: % "PRIsVALUE, rtype);
5629 UNREACHABLE_RETURN(-1);
5632 static rlim_t
5633 rlimit_resource_value(VALUE rval)
5635 const char *name;
5636 VALUE v;
5638 switch (TYPE(rval)) {
5639 case T_SYMBOL:
5640 v = rb_sym2str(rval);
5641 name = RSTRING_PTR(v);
5642 break;
5644 default:
5645 v = rb_check_string_type(rval);
5646 if (!NIL_P(v)) {
5647 rval = v;
5648 case T_STRING:
5649 name = StringValueCStr(rval);
5650 break;
5652 /* fall through */
5654 case T_FIXNUM:
5655 case T_BIGNUM:
5656 return NUM2RLIM(rval);
5659 #ifdef RLIM_INFINITY
5660 if (strcmp(name, "INFINITY") == 0) return RLIM_INFINITY;
5661 #endif
5662 #ifdef RLIM_SAVED_MAX
5663 if (strcmp(name, "SAVED_MAX") == 0) return RLIM_SAVED_MAX;
5664 #endif
5665 #ifdef RLIM_SAVED_CUR
5666 if (strcmp(name, "SAVED_CUR") == 0) return RLIM_SAVED_CUR;
5667 #endif
5668 rb_raise(rb_eArgError, "invalid resource value: %"PRIsVALUE, rval);
5670 UNREACHABLE_RETURN((rlim_t)-1);
5672 #endif
5674 #if defined(HAVE_GETRLIMIT) && defined(RLIM2NUM)
5676 * call-seq:
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.
5695 static VALUE
5696 proc_getrlimit(VALUE obj, VALUE resource)
5698 struct rlimit rlim;
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));
5705 #else
5706 #define proc_getrlimit rb_f_notimplement
5707 #endif
5709 #if defined(HAVE_SETRLIMIT) && defined(NUM2RLIM)
5711 * call-seq:
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])
5761 static VALUE
5762 proc_setrlimit(int argc, VALUE *argv, VALUE obj)
5764 VALUE resource, rlim_cur, rlim_max;
5765 struct rlimit rlim;
5767 rb_check_arity(argc, 2, 3);
5768 resource = argv[0];
5769 rlim_cur = argv[1];
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");
5779 return Qnil;
5781 #else
5782 #define proc_setrlimit rb_f_notimplement
5783 #endif
5785 static int under_uid_switch = 0;
5786 static void
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;
5795 static void
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.
5810 VALUE
5811 rb_getlogin(void)
5813 #if ( !defined(USE_GETLOGIN_R) && !defined(USE_GETLOGIN) )
5814 return Qnil;
5815 #else
5816 char MAYBE_UNUSED(*login) = NULL;
5818 # ifdef USE_GETLOGIN_R
5820 #if defined(__FreeBSD__)
5821 typedef int getlogin_r_size_t;
5822 #else
5823 typedef size_t getlogin_r_size_t;
5824 #endif
5826 long loginsize = GETLOGIN_R_SIZE_INIT; /* maybe -1 */
5828 if (loginsize < 0)
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);
5837 int gle;
5838 errno = 0;
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);
5843 return Qnil;
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);
5858 return Qnil;
5861 return maybe_result;
5863 # elif USE_GETLOGIN
5865 errno = 0;
5866 login = getlogin();
5867 if (errno) {
5868 if (errno == ENOTTY || errno == ENXIO || errno == ENOENT) {
5869 return Qnil;
5871 rb_syserr_fail(errno, "getlogin");
5874 return login ? rb_str_new_cstr(login) : Qnil;
5875 # endif
5877 #endif
5880 VALUE
5881 rb_getpwdirnam_for_login(VALUE login_name)
5883 #if ( !defined(USE_GETPWNAM_R) && !defined(USE_GETPWNAM) )
5884 return Qnil;
5885 #else
5887 if (NIL_P(login_name)) {
5888 /* nothing to do; no name with which to query the password database */
5889 return Qnil;
5892 char *login = RSTRING_PTR(login_name);
5894 struct passwd *pwptr;
5896 # ifdef USE_GETPWNAM_R
5898 struct passwd pwdnm;
5899 char *bufnm;
5900 long bufsizenm = GETPW_R_SIZE_INIT; /* maybe -1 */
5902 if (bufsizenm < 0)
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);
5911 int enm;
5912 errno = 0;
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);
5918 return Qnil;
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);
5934 return Qnil;
5937 /* found it */
5938 VALUE result = rb_str_new_cstr(pwptr->pw_dir);
5939 rb_str_resize(getpwnm_tmp, 0);
5940 return result;
5942 # elif USE_GETPWNAM
5944 errno = 0;
5945 pwptr = getpwnam(login);
5946 if (pwptr) {
5947 /* found it */
5948 return rb_str_new_cstr(pwptr->pw_dir);
5950 if (errno
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 */
5957 # endif
5959 #endif
5963 * Look up the user's dflt home dir in the password db, by uid.
5965 VALUE
5966 rb_getpwdiruid(void)
5968 # if !defined(USE_GETPWUID_R) && !defined(USE_GETPWUID)
5969 /* Should never happen... </famous-last-words> */
5970 return Qnil;
5971 # else
5972 uid_t ruid = getuid();
5974 struct passwd *pwptr;
5976 # ifdef USE_GETPWUID_R
5978 struct passwd pwdid;
5979 char *bufid;
5980 long bufsizeid = GETPW_R_SIZE_INIT; /* maybe -1 */
5982 if (bufsizeid < 0)
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);
5991 int eid;
5992 errno = 0;
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);
5998 return Qnil;
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);
6014 return Qnil;
6017 /* found it */
6018 VALUE result = rb_str_new_cstr(pwptr->pw_dir);
6019 rb_str_resize(getpwid_tmp, 0);
6020 return result;
6022 # elif defined(USE_GETPWUID)
6024 errno = 0;
6025 pwptr = getpwuid(ruid);
6026 if (pwptr) {
6027 /* found it */
6028 return rb_str_new_cstr(pwptr->pw_dir);
6030 if (errno
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 */
6037 # endif
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)
6055 static rb_uid_t
6056 obj2uid(VALUE id
6057 # ifdef USE_GETPWNAM_R
6058 , VALUE *getpw_tmp
6059 # endif
6062 rb_uid_t uid;
6063 VALUE tmp;
6065 if (FIXNUM_P(id) || NIL_P(tmp = rb_check_string_type(id))) {
6066 uid = NUM2UIDT(id);
6068 else {
6069 const char *usrname = StringValueCStr(id);
6070 struct passwd *pwptr;
6071 #ifdef USE_GETPWNAM_R
6072 struct passwd pwbuf;
6073 char *getpw_buf;
6074 long getpw_buf_len;
6075 int e;
6076 if (!*getpw_tmp) {
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);
6084 errno = 0;
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);
6094 #else
6095 pwptr = getpwnam(usrname);
6096 #endif
6097 if (!pwptr) {
6098 #ifndef USE_GETPWNAM_R
6099 endpwent();
6100 #endif
6101 rb_raise(rb_eArgError, "can't find user for %"PRIsVALUE, id);
6103 uid = pwptr->pw_uid;
6104 #ifndef USE_GETPWNAM_R
6105 endpwent();
6106 #endif
6108 return uid;
6111 # ifdef p_uid_from_name
6113 * call-seq:
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)
6123 static VALUE
6124 p_uid_from_name(VALUE self, VALUE id)
6126 return UIDT2NUM(OBJ2UID(id));
6128 # endif
6129 #endif
6131 #if defined(HAVE_GRP_H)
6132 static rb_gid_t
6133 obj2gid(VALUE id
6134 # ifdef USE_GETGRNAM_R
6135 , VALUE *getgr_tmp
6136 # endif
6139 rb_gid_t gid;
6140 VALUE tmp;
6142 if (FIXNUM_P(id) || NIL_P(tmp = rb_check_string_type(id))) {
6143 gid = NUM2GIDT(id);
6145 else {
6146 const char *grpname = StringValueCStr(id);
6147 struct group *grptr;
6148 #ifdef USE_GETGRNAM_R
6149 struct group grbuf;
6150 char *getgr_buf;
6151 long getgr_buf_len;
6152 int e;
6153 if (!*getgr_tmp) {
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);
6161 errno = 0;
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);
6173 #else
6174 grptr = NULL;
6175 #endif
6176 if (!grptr) {
6177 #if !defined(USE_GETGRNAM_R) && defined(HAVE_ENDGRENT)
6178 endgrent();
6179 #endif
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)
6184 endgrent();
6185 #endif
6187 return gid;
6190 # ifdef p_gid_from_name
6192 * call-seq:
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)
6202 static VALUE
6203 p_gid_from_name(VALUE self, VALUE id)
6205 return GIDT2NUM(OBJ2GID(id));
6207 # endif
6208 #endif
6210 #if defined HAVE_SETUID
6212 * call-seq:
6213 * Process::Sys.setuid(user) -> nil
6215 * Set the user ID of the current process to _user_. Not
6216 * available on all platforms.
6220 static VALUE
6221 p_sys_setuid(VALUE obj, VALUE id)
6223 check_uid_switch();
6224 if (setuid(OBJ2UID(id)) != 0) rb_sys_fail(0);
6225 return Qnil;
6227 #else
6228 #define p_sys_setuid rb_f_notimplement
6229 #endif
6232 #if defined HAVE_SETRUID
6234 * call-seq:
6235 * Process::Sys.setruid(user) -> nil
6237 * Set the real user ID of the calling process to _user_.
6238 * Not available on all platforms.
6242 static VALUE
6243 p_sys_setruid(VALUE obj, VALUE id)
6245 check_uid_switch();
6246 if (setruid(OBJ2UID(id)) != 0) rb_sys_fail(0);
6247 return Qnil;
6249 #else
6250 #define p_sys_setruid rb_f_notimplement
6251 #endif
6254 #if defined HAVE_SETEUID
6256 * call-seq:
6257 * Process::Sys.seteuid(user) -> nil
6259 * Set the effective user ID of the calling process to
6260 * _user_. Not available on all platforms.
6264 static VALUE
6265 p_sys_seteuid(VALUE obj, VALUE id)
6267 check_uid_switch();
6268 if (seteuid(OBJ2UID(id)) != 0) rb_sys_fail(0);
6269 return Qnil;
6271 #else
6272 #define p_sys_seteuid rb_f_notimplement
6273 #endif
6276 #if defined HAVE_SETREUID
6278 * call-seq:
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.
6288 static VALUE
6289 p_sys_setreuid(VALUE obj, VALUE rid, VALUE eid)
6291 rb_uid_t ruid, euid;
6292 PREPARE_GETPWNAM;
6293 check_uid_switch();
6294 ruid = OBJ2UID1(rid);
6295 euid = OBJ2UID1(eid);
6296 FINISH_GETPWNAM;
6297 if (setreuid(ruid, euid) != 0) rb_sys_fail(0);
6298 return Qnil;
6300 #else
6301 #define p_sys_setreuid rb_f_notimplement
6302 #endif
6305 #if defined HAVE_SETRESUID
6307 * call-seq:
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.
6317 static VALUE
6318 p_sys_setresuid(VALUE obj, VALUE rid, VALUE eid, VALUE sid)
6320 rb_uid_t ruid, euid, suid;
6321 PREPARE_GETPWNAM;
6322 check_uid_switch();
6323 ruid = OBJ2UID1(rid);
6324 euid = OBJ2UID1(eid);
6325 suid = OBJ2UID1(sid);
6326 FINISH_GETPWNAM;
6327 if (setresuid(ruid, euid, suid) != 0) rb_sys_fail(0);
6328 return Qnil;
6330 #else
6331 #define p_sys_setresuid rb_f_notimplement
6332 #endif
6336 * call-seq:
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
6346 static VALUE
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)
6356 * call-seq:
6357 * Process.uid= user -> numeric
6359 * Sets the (user) user ID for this process. Not available on all
6360 * platforms.
6363 static VALUE
6364 proc_setuid(VALUE obj, VALUE id)
6366 rb_uid_t uid;
6368 check_uid_switch();
6370 uid = OBJ2UID(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);
6382 else {
6383 rb_notimplement();
6386 #endif
6387 return id;
6389 #else
6390 #define proc_setuid rb_f_notimplement
6391 #endif
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;
6417 return 0;
6419 #endif
6422 * call-seq:
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]
6434 static VALUE
6435 p_uid_change_privilege(VALUE obj, VALUE id)
6437 rb_uid_t uid;
6439 check_uid_switch();
6441 uid = OBJ2UID(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);
6455 else {
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;
6463 else {
6464 if (setreuid(0, -1) < 0) rb_sys_fail(0);
6465 SAVED_USER_ID = 0;
6466 if (setreuid(uid, uid) < 0) rb_sys_fail(0);
6467 SAVED_USER_ID = uid;
6471 else {
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);
6480 else {
6481 if (uid == 0) {
6482 if (setruid(SAVED_USER_ID) < 0) rb_sys_fail(0);
6483 SAVED_USER_ID = 0;
6484 if (setruid(0) < 0) rb_sys_fail(0);
6486 else {
6487 if (setruid(0) < 0) rb_sys_fail(0);
6488 SAVED_USER_ID = 0;
6489 if (seteuid(uid) < 0) rb_sys_fail(0);
6490 if (setruid(uid) < 0) rb_sys_fail(0);
6491 SAVED_USER_ID = uid;
6495 else {
6496 if (seteuid(uid) < 0) rb_sys_fail(0);
6497 if (setruid(uid) < 0) rb_sys_fail(0);
6498 SAVED_USER_ID = uid;
6500 #else
6501 (void)uid;
6502 rb_notimplement();
6503 #endif
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)
6515 rb_sys_fail(0);
6517 else if (getuid() != uid) {
6518 if (setreuid(uid, (geteuid() == uid)? (rb_uid_t)-1: uid) < 0)
6519 rb_sys_fail(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;
6543 else {
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);
6555 else {
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;
6564 else {
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);
6571 else {
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);
6578 else {
6579 rb_syserr_fail(EPERM, 0);
6581 #else
6582 rb_notimplement();
6583 #endif
6585 return id;
6590 #if defined HAVE_SETGID
6592 * call-seq:
6593 * Process::Sys.setgid(group) -> nil
6595 * Set the group ID of the current process to _group_. Not
6596 * available on all platforms.
6600 static VALUE
6601 p_sys_setgid(VALUE obj, VALUE id)
6603 check_gid_switch();
6604 if (setgid(OBJ2GID(id)) != 0) rb_sys_fail(0);
6605 return Qnil;
6607 #else
6608 #define p_sys_setgid rb_f_notimplement
6609 #endif
6612 #if defined HAVE_SETRGID
6614 * call-seq:
6615 * Process::Sys.setrgid(group) -> nil
6617 * Set the real group ID of the calling process to _group_.
6618 * Not available on all platforms.
6622 static VALUE
6623 p_sys_setrgid(VALUE obj, VALUE id)
6625 check_gid_switch();
6626 if (setrgid(OBJ2GID(id)) != 0) rb_sys_fail(0);
6627 return Qnil;
6629 #else
6630 #define p_sys_setrgid rb_f_notimplement
6631 #endif
6634 #if defined HAVE_SETEGID
6636 * call-seq:
6637 * Process::Sys.setegid(group) -> nil
6639 * Set the effective group ID of the calling process to
6640 * _group_. Not available on all platforms.
6644 static VALUE
6645 p_sys_setegid(VALUE obj, VALUE id)
6647 check_gid_switch();
6648 if (setegid(OBJ2GID(id)) != 0) rb_sys_fail(0);
6649 return Qnil;
6651 #else
6652 #define p_sys_setegid rb_f_notimplement
6653 #endif
6656 #if defined HAVE_SETREGID
6658 * call-seq:
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.
6668 static VALUE
6669 p_sys_setregid(VALUE obj, VALUE rid, VALUE eid)
6671 rb_gid_t rgid, egid;
6672 check_gid_switch();
6673 rgid = OBJ2GID(rid);
6674 egid = OBJ2GID(eid);
6675 if (setregid(rgid, egid) != 0) rb_sys_fail(0);
6676 return Qnil;
6678 #else
6679 #define p_sys_setregid rb_f_notimplement
6680 #endif
6682 #if defined HAVE_SETRESGID
6684 * call-seq:
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.
6694 static VALUE
6695 p_sys_setresgid(VALUE obj, VALUE rid, VALUE eid, VALUE sid)
6697 rb_gid_t rgid, egid, sgid;
6698 check_gid_switch();
6699 rgid = OBJ2GID(rid);
6700 egid = OBJ2GID(eid);
6701 sgid = OBJ2GID(sid);
6702 if (setresgid(rgid, egid, sgid) != 0) rb_sys_fail(0);
6703 return Qnil;
6705 #else
6706 #define p_sys_setresgid rb_f_notimplement
6707 #endif
6710 #if defined HAVE_ISSETUGID
6712 * call-seq:
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.
6723 static VALUE
6724 p_sys_issetugid(VALUE obj)
6726 if (issetugid()) {
6727 return Qtrue;
6729 else {
6730 return Qfalse;
6733 #else
6734 #define p_sys_issetugid rb_f_notimplement
6735 #endif
6739 * call-seq:
6740 * Process.gid -> integer
6741 * Process::GID.rid -> integer
6742 * Process::Sys.getgid -> integer
6744 * Returns the (real) group ID for this process.
6746 * Process.gid #=> 500
6749 static VALUE
6750 proc_getgid(VALUE obj)
6752 rb_gid_t gid = getgid();
6753 return GIDT2NUM(gid);
6757 #if defined(HAVE_SETRESGID) || defined(HAVE_SETREGID) || defined(HAVE_SETRGID) || defined(HAVE_SETGID)
6759 * call-seq:
6760 * Process.gid= integer -> integer
6762 * Sets the group ID for this process.
6765 static VALUE
6766 proc_setgid(VALUE obj, VALUE id)
6768 rb_gid_t gid;
6770 check_gid_switch();
6772 gid = OBJ2GID(id);
6773 #if defined(HAVE_SETRESGID)
6774 if (setresgid(gid, -1, -1) < 0) rb_sys_fail(0);
6775 #elif defined HAVE_SETREGID
6776 if (setregid(gid, -1) < 0) rb_sys_fail(0);
6777 #elif defined HAVE_SETRGID
6778 if (setrgid(gid) < 0) rb_sys_fail(0);
6779 #elif defined HAVE_SETGID
6781 if (getegid() == gid) {
6782 if (setgid(gid) < 0) rb_sys_fail(0);
6784 else {
6785 rb_notimplement();
6788 #endif
6789 return GIDT2NUM(gid);
6791 #else
6792 #define proc_setgid rb_f_notimplement
6793 #endif
6796 #if defined(_SC_NGROUPS_MAX) || defined(NGROUPS_MAX)
6798 * Maximum supplementary groups are platform dependent.
6799 * FWIW, 65536 is enough big for our supported OSs.
6801 * OS Name max groups
6802 * -----------------------------------------------
6803 * Linux Kernel >= 2.6.3 65536
6804 * Linux Kernel < 2.6.3 32
6805 * IBM AIX 5.2 64
6806 * IBM AIX 5.3 ... 6.1 128
6807 * IBM AIX 7.1 128 (can be configured to be up to 2048)
6808 * OpenBSD, NetBSD 16
6809 * FreeBSD < 8.0 16
6810 * FreeBSD >=8.0 1023
6811 * Darwin (Mac OS X) 16
6812 * Sun Solaris 7,8,9,10 16
6813 * Sun Solaris 11 / OpenSolaris 1024
6814 * HP-UX 20
6815 * Windows 1015
6817 static int _maxgroups = -1;
6818 static int
6819 get_sc_ngroups_max(void)
6821 #ifdef _SC_NGROUPS_MAX
6822 return (int)sysconf(_SC_NGROUPS_MAX);
6823 #elif defined(NGROUPS_MAX)
6824 return (int)NGROUPS_MAX;
6825 #else
6826 return -1;
6827 #endif
6829 static int
6830 maxgroups(void)
6832 if (_maxgroups < 0) {
6833 _maxgroups = get_sc_ngroups_max();
6834 if (_maxgroups < 0)
6835 _maxgroups = RB_MAX_GROUPS;
6838 return _maxgroups;
6840 #endif
6844 #ifdef HAVE_GETGROUPS
6846 * call-seq:
6847 * Process.groups -> array
6849 * Get an Array of the group IDs in the
6850 * supplemental group access list for this process.
6852 * Process.groups #=> [27, 6, 10, 11]
6854 * Note that this method is just a wrapper of getgroups(2).
6855 * This means that the following characteristics of
6856 * the result completely depend on your system:
6858 * - the result is sorted
6859 * - the result includes effective GIDs
6860 * - the result does not include duplicated GIDs
6862 * You can make sure to get a sorted unique GID list of
6863 * the current process by this expression:
6865 * Process.groups.uniq.sort
6869 static VALUE
6870 proc_getgroups(VALUE obj)
6872 VALUE ary, tmp;
6873 int i, ngroups;
6874 rb_gid_t *groups;
6876 ngroups = getgroups(0, NULL);
6877 if (ngroups == -1)
6878 rb_sys_fail(0);
6880 groups = ALLOCV_N(rb_gid_t, tmp, ngroups);
6882 ngroups = getgroups(ngroups, groups);
6883 if (ngroups == -1)
6884 rb_sys_fail(0);
6886 ary = rb_ary_new();
6887 for (i = 0; i < ngroups; i++)
6888 rb_ary_push(ary, GIDT2NUM(groups[i]));
6890 ALLOCV_END(tmp);
6892 return ary;
6894 #else
6895 #define proc_getgroups rb_f_notimplement
6896 #endif
6899 #ifdef HAVE_SETGROUPS
6901 * call-seq:
6902 * Process.groups= array -> array
6904 * Set the supplemental group access list to the given
6905 * Array of group IDs.
6907 * Process.groups #=> [0, 1, 2, 3, 4, 6, 10, 11, 20, 26, 27]
6908 * Process.groups = [27, 6, 10, 11] #=> [27, 6, 10, 11]
6909 * Process.groups #=> [27, 6, 10, 11]
6913 static VALUE
6914 proc_setgroups(VALUE obj, VALUE ary)
6916 int ngroups, i;
6917 rb_gid_t *groups;
6918 VALUE tmp;
6919 PREPARE_GETGRNAM;
6921 Check_Type(ary, T_ARRAY);
6923 ngroups = RARRAY_LENINT(ary);
6924 if (ngroups > maxgroups())
6925 rb_raise(rb_eArgError, "too many groups, %d max", maxgroups());
6927 groups = ALLOCV_N(rb_gid_t, tmp, ngroups);
6929 for (i = 0; i < ngroups; i++) {
6930 VALUE g = RARRAY_AREF(ary, i);
6932 groups[i] = OBJ2GID1(g);
6934 FINISH_GETGRNAM;
6936 if (setgroups(ngroups, groups) == -1) /* ngroups <= maxgroups */
6937 rb_sys_fail(0);
6939 ALLOCV_END(tmp);
6941 return proc_getgroups(obj);
6943 #else
6944 #define proc_setgroups rb_f_notimplement
6945 #endif
6948 #ifdef HAVE_INITGROUPS
6950 * call-seq:
6951 * Process.initgroups(username, gid) -> array
6953 * Initializes the supplemental group access list by reading the
6954 * system group database and using all groups of which the given user
6955 * is a member. The group with the specified <em>gid</em> is also
6956 * added to the list. Returns the resulting Array of the
6957 * gids of all the groups in the supplementary group access list. Not
6958 * available on all platforms.
6960 * Process.groups #=> [0, 1, 2, 3, 4, 6, 10, 11, 20, 26, 27]
6961 * Process.initgroups( "mgranger", 30 ) #=> [30, 6, 10, 11]
6962 * Process.groups #=> [30, 6, 10, 11]
6966 static VALUE
6967 proc_initgroups(VALUE obj, VALUE uname, VALUE base_grp)
6969 if (initgroups(StringValueCStr(uname), OBJ2GID(base_grp)) != 0) {
6970 rb_sys_fail(0);
6972 return proc_getgroups(obj);
6974 #else
6975 #define proc_initgroups rb_f_notimplement
6976 #endif
6978 #if defined(_SC_NGROUPS_MAX) || defined(NGROUPS_MAX)
6980 * call-seq:
6981 * Process.maxgroups -> integer
6983 * Returns the maximum number of gids allowed in the supplemental
6984 * group access list.
6986 * Process.maxgroups #=> 32
6989 static VALUE
6990 proc_getmaxgroups(VALUE obj)
6992 return INT2FIX(maxgroups());
6994 #else
6995 #define proc_getmaxgroups rb_f_notimplement
6996 #endif
6998 #ifdef HAVE_SETGROUPS
7000 * call-seq:
7001 * Process.maxgroups= integer -> integer
7003 * Sets the maximum number of gids allowed in the supplemental group
7004 * access list.
7007 static VALUE
7008 proc_setmaxgroups(VALUE obj, VALUE val)
7010 int ngroups = FIX2INT(val);
7011 int ngroups_max = get_sc_ngroups_max();
7013 if (ngroups <= 0)
7014 rb_raise(rb_eArgError, "maxgroups %d should be positive", ngroups);
7016 if (ngroups > RB_MAX_GROUPS)
7017 ngroups = RB_MAX_GROUPS;
7019 if (ngroups_max > 0 && ngroups > ngroups_max)
7020 ngroups = ngroups_max;
7022 _maxgroups = ngroups;
7024 return INT2FIX(_maxgroups);
7026 #else
7027 #define proc_setmaxgroups rb_f_notimplement
7028 #endif
7030 #if defined(HAVE_DAEMON) || (defined(HAVE_WORKING_FORK) && defined(HAVE_SETSID))
7031 static int rb_daemon(int nochdir, int noclose);
7034 * call-seq:
7035 * Process.daemon() -> 0
7036 * Process.daemon(nochdir=nil,noclose=nil) -> 0
7038 * Detach the process from controlling terminal and run in
7039 * the background as system daemon. Unless the argument
7040 * nochdir is true (i.e. non false), it changes the current
7041 * working directory to the root ("/"). Unless the argument
7042 * noclose is true, daemon() will redirect standard input,
7043 * standard output and standard error to /dev/null.
7044 * Return zero on success, or raise one of Errno::*.
7047 static VALUE
7048 proc_daemon(int argc, VALUE *argv, VALUE _)
7050 int n, nochdir = FALSE, noclose = FALSE;
7052 switch (rb_check_arity(argc, 0, 2)) {
7053 case 2: noclose = TO_BOOL(argv[1], "noclose");
7054 case 1: nochdir = TO_BOOL(argv[0], "nochdir");
7057 prefork();
7058 n = rb_daemon(nochdir, noclose);
7059 if (n < 0) rb_sys_fail("daemon");
7060 return INT2FIX(n);
7063 static int
7064 rb_daemon(int nochdir, int noclose)
7066 int err = 0;
7067 #ifdef HAVE_DAEMON
7068 if (mjit_enabled) mjit_pause(false); // Don't leave locked mutex to child.
7069 before_fork_ruby();
7070 err = daemon(nochdir, noclose);
7071 after_fork_ruby();
7072 rb_thread_atfork(); /* calls mjit_resume() */
7073 #else
7074 int n;
7076 #define fork_daemon() \
7077 switch (rb_fork_ruby(NULL)) { \
7078 case -1: return -1; \
7079 case 0: break; \
7080 default: _exit(EXIT_SUCCESS); \
7083 fork_daemon();
7085 if (setsid() < 0) return -1;
7087 /* must not be process-leader */
7088 fork_daemon();
7090 if (!nochdir)
7091 err = chdir("/");
7093 if (!noclose && (n = rb_cloexec_open("/dev/null", O_RDWR, 0)) != -1) {
7094 rb_update_max_fd(n);
7095 (void)dup2(n, 0);
7096 (void)dup2(n, 1);
7097 (void)dup2(n, 2);
7098 if (n > 2)
7099 (void)close (n);
7101 #endif
7102 return err;
7104 #else
7105 #define proc_daemon rb_f_notimplement
7106 #endif
7108 /********************************************************************
7110 * Document-class: Process::GID
7112 * The Process::GID module contains a collection of
7113 * module functions which can be used to portably get, set, and
7114 * switch the current process's real, effective, and saved group IDs.
7118 static rb_gid_t SAVED_GROUP_ID = -1;
7120 #ifdef BROKEN_SETREGID
7122 setregid(rb_gid_t rgid, rb_gid_t egid)
7124 if (rgid != (rb_gid_t)-1 && rgid != getgid()) {
7125 if (egid == (rb_gid_t)-1) egid = getegid();
7126 if (setgid(rgid) < 0) return -1;
7128 if (egid != (rb_gid_t)-1 && egid != getegid()) {
7129 if (setegid(egid) < 0) return -1;
7131 return 0;
7133 #endif
7136 * call-seq:
7137 * Process::GID.change_privilege(group) -> integer
7139 * Change the current process's real and effective group ID to that
7140 * specified by _group_. Returns the new group ID. Not
7141 * available on all platforms.
7143 * [Process.gid, Process.egid] #=> [0, 0]
7144 * Process::GID.change_privilege(33) #=> 33
7145 * [Process.gid, Process.egid] #=> [33, 33]
7148 static VALUE
7149 p_gid_change_privilege(VALUE obj, VALUE id)
7151 rb_gid_t gid;
7153 check_gid_switch();
7155 gid = OBJ2GID(id);
7157 if (geteuid() == 0) { /* root-user */
7158 #if defined(HAVE_SETRESGID)
7159 if (setresgid(gid, gid, gid) < 0) rb_sys_fail(0);
7160 SAVED_GROUP_ID = gid;
7161 #elif defined HAVE_SETGID
7162 if (setgid(gid) < 0) rb_sys_fail(0);
7163 SAVED_GROUP_ID = gid;
7164 #elif defined(HAVE_SETREGID) && !defined(OBSOLETE_SETREGID)
7165 if (getgid() == gid) {
7166 if (SAVED_GROUP_ID == gid) {
7167 if (setregid(-1, gid) < 0) rb_sys_fail(0);
7169 else {
7170 if (gid == 0) { /* (r,e,s) == (root, y, x) */
7171 if (setregid(-1, SAVED_GROUP_ID) < 0) rb_sys_fail(0);
7172 if (setregid(SAVED_GROUP_ID, 0) < 0) rb_sys_fail(0);
7173 SAVED_GROUP_ID = 0; /* (r,e,s) == (x, root, root) */
7174 if (setregid(gid, gid) < 0) rb_sys_fail(0);
7175 SAVED_GROUP_ID = gid;
7177 else { /* (r,e,s) == (z, y, x) */
7178 if (setregid(0, 0) < 0) rb_sys_fail(0);
7179 SAVED_GROUP_ID = 0;
7180 if (setregid(gid, gid) < 0) rb_sys_fail(0);
7181 SAVED_GROUP_ID = gid;
7185 else {
7186 if (setregid(gid, gid) < 0) rb_sys_fail(0);
7187 SAVED_GROUP_ID = gid;
7189 #elif defined(HAVE_SETRGID) && defined (HAVE_SETEGID)
7190 if (getgid() == gid) {
7191 if (SAVED_GROUP_ID == gid) {
7192 if (setegid(gid) < 0) rb_sys_fail(0);
7194 else {
7195 if (gid == 0) {
7196 if (setegid(gid) < 0) rb_sys_fail(0);
7197 if (setrgid(SAVED_GROUP_ID) < 0) rb_sys_fail(0);
7198 SAVED_GROUP_ID = 0;
7199 if (setrgid(0) < 0) rb_sys_fail(0);
7201 else {
7202 if (setrgid(0) < 0) rb_sys_fail(0);
7203 SAVED_GROUP_ID = 0;
7204 if (setegid(gid) < 0) rb_sys_fail(0);
7205 if (setrgid(gid) < 0) rb_sys_fail(0);
7206 SAVED_GROUP_ID = gid;
7210 else {
7211 if (setegid(gid) < 0) rb_sys_fail(0);
7212 if (setrgid(gid) < 0) rb_sys_fail(0);
7213 SAVED_GROUP_ID = gid;
7215 #else
7216 rb_notimplement();
7217 #endif
7219 else { /* unprivileged user */
7220 #if defined(HAVE_SETRESGID)
7221 if (setresgid((getgid() == gid)? (rb_gid_t)-1: gid,
7222 (getegid() == gid)? (rb_gid_t)-1: gid,
7223 (SAVED_GROUP_ID == gid)? (rb_gid_t)-1: gid) < 0) rb_sys_fail(0);
7224 SAVED_GROUP_ID = gid;
7225 #elif defined(HAVE_SETREGID) && !defined(OBSOLETE_SETREGID)
7226 if (SAVED_GROUP_ID == gid) {
7227 if (setregid((getgid() == gid)? (rb_uid_t)-1: gid,
7228 (getegid() == gid)? (rb_uid_t)-1: gid) < 0)
7229 rb_sys_fail(0);
7231 else if (getgid() != gid) {
7232 if (setregid(gid, (getegid() == gid)? (rb_uid_t)-1: gid) < 0)
7233 rb_sys_fail(0);
7234 SAVED_GROUP_ID = gid;
7236 else if (/* getgid() == gid && */ getegid() != gid) {
7237 if (setregid(getegid(), gid) < 0) rb_sys_fail(0);
7238 SAVED_GROUP_ID = gid;
7239 if (setregid(gid, -1) < 0) rb_sys_fail(0);
7241 else { /* getgid() == gid && getegid() == gid */
7242 if (setregid(-1, SAVED_GROUP_ID) < 0) rb_sys_fail(0);
7243 if (setregid(SAVED_GROUP_ID, gid) < 0) rb_sys_fail(0);
7244 SAVED_GROUP_ID = gid;
7245 if (setregid(gid, -1) < 0) rb_sys_fail(0);
7247 #elif defined(HAVE_SETRGID) && defined(HAVE_SETEGID)
7248 if (SAVED_GROUP_ID == gid) {
7249 if (getegid() != gid && setegid(gid) < 0) rb_sys_fail(0);
7250 if (getgid() != gid && setrgid(gid) < 0) rb_sys_fail(0);
7252 else if (/* SAVED_GROUP_ID != gid && */ getegid() == gid) {
7253 if (getgid() != gid) {
7254 if (setrgid(gid) < 0) rb_sys_fail(0);
7255 SAVED_GROUP_ID = gid;
7257 else {
7258 if (setrgid(SAVED_GROUP_ID) < 0) rb_sys_fail(0);
7259 SAVED_GROUP_ID = gid;
7260 if (setrgid(gid) < 0) rb_sys_fail(0);
7263 else if (/* getegid() != gid && */ getgid() == gid) {
7264 if (setegid(gid) < 0) rb_sys_fail(0);
7265 if (setrgid(SAVED_GROUP_ID) < 0) rb_sys_fail(0);
7266 SAVED_GROUP_ID = gid;
7267 if (setrgid(gid) < 0) rb_sys_fail(0);
7269 else {
7270 rb_syserr_fail(EPERM, 0);
7272 #elif defined HAVE_44BSD_SETGID
7273 if (getgid() == gid) {
7274 /* (r,e,s)==(gid,?,?) ==> (gid,gid,gid) */
7275 if (setgid(gid) < 0) rb_sys_fail(0);
7276 SAVED_GROUP_ID = gid;
7278 else {
7279 rb_syserr_fail(EPERM, 0);
7281 #elif defined HAVE_SETEGID
7282 if (getgid() == gid && SAVED_GROUP_ID == gid) {
7283 if (setegid(gid) < 0) rb_sys_fail(0);
7285 else {
7286 rb_syserr_fail(EPERM, 0);
7288 #elif defined HAVE_SETGID
7289 if (getgid() == gid && SAVED_GROUP_ID == gid) {
7290 if (setgid(gid) < 0) rb_sys_fail(0);
7292 else {
7293 rb_syserr_fail(EPERM, 0);
7295 #else
7296 (void)gid;
7297 rb_notimplement();
7298 #endif
7300 return id;
7305 * call-seq:
7306 * Process.euid -> integer
7307 * Process::UID.eid -> integer
7308 * Process::Sys.geteuid -> integer
7310 * Returns the effective user ID for this process.
7312 * Process.euid #=> 501
7315 static VALUE
7316 proc_geteuid(VALUE obj)
7318 rb_uid_t euid = geteuid();
7319 return UIDT2NUM(euid);
7322 #if defined(HAVE_SETRESUID) || defined(HAVE_SETREUID) || defined(HAVE_SETEUID) || defined(HAVE_SETUID) || defined(_POSIX_SAVED_IDS)
7323 static void
7324 proc_seteuid(rb_uid_t uid)
7326 #if defined(HAVE_SETRESUID)
7327 if (setresuid(-1, uid, -1) < 0) rb_sys_fail(0);
7328 #elif defined HAVE_SETREUID
7329 if (setreuid(-1, uid) < 0) rb_sys_fail(0);
7330 #elif defined HAVE_SETEUID
7331 if (seteuid(uid) < 0) rb_sys_fail(0);
7332 #elif defined HAVE_SETUID
7333 if (uid == getuid()) {
7334 if (setuid(uid) < 0) rb_sys_fail(0);
7336 else {
7337 rb_notimplement();
7339 #else
7340 rb_notimplement();
7341 #endif
7343 #endif
7345 #if defined(HAVE_SETRESUID) || defined(HAVE_SETREUID) || defined(HAVE_SETEUID) || defined(HAVE_SETUID)
7347 * call-seq:
7348 * Process.euid= user
7350 * Sets the effective user ID for this process. Not available on all
7351 * platforms.
7354 static VALUE
7355 proc_seteuid_m(VALUE mod, VALUE euid)
7357 check_uid_switch();
7358 proc_seteuid(OBJ2UID(euid));
7359 return euid;
7361 #else
7362 #define proc_seteuid_m rb_f_notimplement
7363 #endif
7365 static rb_uid_t
7366 rb_seteuid_core(rb_uid_t euid)
7368 #if defined(HAVE_SETRESUID) || (defined(HAVE_SETREUID) && !defined(OBSOLETE_SETREUID))
7369 rb_uid_t uid;
7370 #endif
7372 check_uid_switch();
7374 #if defined(HAVE_SETRESUID) || (defined(HAVE_SETREUID) && !defined(OBSOLETE_SETREUID))
7375 uid = getuid();
7376 #endif
7378 #if defined(HAVE_SETRESUID)
7379 if (uid != euid) {
7380 if (setresuid(-1,euid,euid) < 0) rb_sys_fail(0);
7381 SAVED_USER_ID = euid;
7383 else {
7384 if (setresuid(-1,euid,-1) < 0) rb_sys_fail(0);
7386 #elif defined(HAVE_SETREUID) && !defined(OBSOLETE_SETREUID)
7387 if (setreuid(-1, euid) < 0) rb_sys_fail(0);
7388 if (uid != euid) {
7389 if (setreuid(euid,uid) < 0) rb_sys_fail(0);
7390 if (setreuid(uid,euid) < 0) rb_sys_fail(0);
7391 SAVED_USER_ID = euid;
7393 #elif defined HAVE_SETEUID
7394 if (seteuid(euid) < 0) rb_sys_fail(0);
7395 #elif defined HAVE_SETUID
7396 if (geteuid() == 0) rb_sys_fail(0);
7397 if (setuid(euid) < 0) rb_sys_fail(0);
7398 #else
7399 rb_notimplement();
7400 #endif
7401 return euid;
7406 * call-seq:
7407 * Process::UID.grant_privilege(user) -> integer
7408 * Process::UID.eid= user -> integer
7410 * Set the effective user ID, and if possible, the saved user ID of
7411 * the process to the given _user_. Returns the new
7412 * effective user ID. Not available on all platforms.
7414 * [Process.uid, Process.euid] #=> [0, 0]
7415 * Process::UID.grant_privilege(31) #=> 31
7416 * [Process.uid, Process.euid] #=> [0, 31]
7419 static VALUE
7420 p_uid_grant_privilege(VALUE obj, VALUE id)
7422 rb_seteuid_core(OBJ2UID(id));
7423 return id;
7428 * call-seq:
7429 * Process.egid -> integer
7430 * Process::GID.eid -> integer
7431 * Process::Sys.geteid -> integer
7433 * Returns the effective group ID for this process. Not available on
7434 * all platforms.
7436 * Process.egid #=> 500
7439 static VALUE
7440 proc_getegid(VALUE obj)
7442 rb_gid_t egid = getegid();
7444 return GIDT2NUM(egid);
7447 #if defined(HAVE_SETRESGID) || defined(HAVE_SETREGID) || defined(HAVE_SETEGID) || defined(HAVE_SETGID) || defined(_POSIX_SAVED_IDS)
7449 * call-seq:
7450 * Process.egid = integer -> integer
7452 * Sets the effective group ID for this process. Not available on all
7453 * platforms.
7456 static VALUE
7457 proc_setegid(VALUE obj, VALUE egid)
7459 #if defined(HAVE_SETRESGID) || defined(HAVE_SETREGID) || defined(HAVE_SETEGID) || defined(HAVE_SETGID)
7460 rb_gid_t gid;
7461 #endif
7463 check_gid_switch();
7465 #if defined(HAVE_SETRESGID) || defined(HAVE_SETREGID) || defined(HAVE_SETEGID) || defined(HAVE_SETGID)
7466 gid = OBJ2GID(egid);
7467 #endif
7469 #if defined(HAVE_SETRESGID)
7470 if (setresgid(-1, gid, -1) < 0) rb_sys_fail(0);
7471 #elif defined HAVE_SETREGID
7472 if (setregid(-1, gid) < 0) rb_sys_fail(0);
7473 #elif defined HAVE_SETEGID
7474 if (setegid(gid) < 0) rb_sys_fail(0);
7475 #elif defined HAVE_SETGID
7476 if (gid == getgid()) {
7477 if (setgid(gid) < 0) rb_sys_fail(0);
7479 else {
7480 rb_notimplement();
7482 #else
7483 rb_notimplement();
7484 #endif
7485 return egid;
7487 #endif
7489 #if defined(HAVE_SETRESGID) || defined(HAVE_SETREGID) || defined(HAVE_SETEGID) || defined(HAVE_SETGID)
7490 #define proc_setegid_m proc_setegid
7491 #else
7492 #define proc_setegid_m rb_f_notimplement
7493 #endif
7495 static rb_gid_t
7496 rb_setegid_core(rb_gid_t egid)
7498 #if defined(HAVE_SETRESGID) || (defined(HAVE_SETREGID) && !defined(OBSOLETE_SETREGID))
7499 rb_gid_t gid;
7500 #endif
7502 check_gid_switch();
7504 #if defined(HAVE_SETRESGID) || (defined(HAVE_SETREGID) && !defined(OBSOLETE_SETREGID))
7505 gid = getgid();
7506 #endif
7508 #if defined(HAVE_SETRESGID)
7509 if (gid != egid) {
7510 if (setresgid(-1,egid,egid) < 0) rb_sys_fail(0);
7511 SAVED_GROUP_ID = egid;
7513 else {
7514 if (setresgid(-1,egid,-1) < 0) rb_sys_fail(0);
7516 #elif defined(HAVE_SETREGID) && !defined(OBSOLETE_SETREGID)
7517 if (setregid(-1, egid) < 0) rb_sys_fail(0);
7518 if (gid != egid) {
7519 if (setregid(egid,gid) < 0) rb_sys_fail(0);
7520 if (setregid(gid,egid) < 0) rb_sys_fail(0);
7521 SAVED_GROUP_ID = egid;
7523 #elif defined HAVE_SETEGID
7524 if (setegid(egid) < 0) rb_sys_fail(0);
7525 #elif defined HAVE_SETGID
7526 if (geteuid() == 0 /* root user */) rb_sys_fail(0);
7527 if (setgid(egid) < 0) rb_sys_fail(0);
7528 #else
7529 rb_notimplement();
7530 #endif
7531 return egid;
7536 * call-seq:
7537 * Process::GID.grant_privilege(group) -> integer
7538 * Process::GID.eid = group -> integer
7540 * Set the effective group ID, and if possible, the saved group ID of
7541 * the process to the given _group_. Returns the new
7542 * effective group ID. Not available on all platforms.
7544 * [Process.gid, Process.egid] #=> [0, 0]
7545 * Process::GID.grant_privilege(31) #=> 33
7546 * [Process.gid, Process.egid] #=> [0, 33]
7549 static VALUE
7550 p_gid_grant_privilege(VALUE obj, VALUE id)
7552 rb_setegid_core(OBJ2GID(id));
7553 return id;
7558 * call-seq:
7559 * Process::UID.re_exchangeable? -> true or false
7561 * Returns +true+ if the real and effective user IDs of a
7562 * process may be exchanged on the current platform.
7566 static VALUE
7567 p_uid_exchangeable(VALUE _)
7569 #if defined(HAVE_SETRESUID)
7570 return Qtrue;
7571 #elif defined(HAVE_SETREUID) && !defined(OBSOLETE_SETREUID)
7572 return Qtrue;
7573 #else
7574 return Qfalse;
7575 #endif
7580 * call-seq:
7581 * Process::UID.re_exchange -> integer
7583 * Exchange real and effective user IDs and return the new effective
7584 * user ID. Not available on all platforms.
7586 * [Process.uid, Process.euid] #=> [0, 31]
7587 * Process::UID.re_exchange #=> 0
7588 * [Process.uid, Process.euid] #=> [31, 0]
7591 static VALUE
7592 p_uid_exchange(VALUE obj)
7594 rb_uid_t uid;
7595 #if defined(HAVE_SETRESUID) || (defined(HAVE_SETREUID) && !defined(OBSOLETE_SETREUID))
7596 rb_uid_t euid;
7597 #endif
7599 check_uid_switch();
7601 uid = getuid();
7602 #if defined(HAVE_SETRESUID) || (defined(HAVE_SETREUID) && !defined(OBSOLETE_SETREUID))
7603 euid = geteuid();
7604 #endif
7606 #if defined(HAVE_SETRESUID)
7607 if (setresuid(euid, uid, uid) < 0) rb_sys_fail(0);
7608 SAVED_USER_ID = uid;
7609 #elif defined(HAVE_SETREUID) && !defined(OBSOLETE_SETREUID)
7610 if (setreuid(euid,uid) < 0) rb_sys_fail(0);
7611 SAVED_USER_ID = uid;
7612 #else
7613 rb_notimplement();
7614 #endif
7615 return UIDT2NUM(uid);
7620 * call-seq:
7621 * Process::GID.re_exchangeable? -> true or false
7623 * Returns +true+ if the real and effective group IDs of a
7624 * process may be exchanged on the current platform.
7628 static VALUE
7629 p_gid_exchangeable(VALUE _)
7631 #if defined(HAVE_SETRESGID)
7632 return Qtrue;
7633 #elif defined(HAVE_SETREGID) && !defined(OBSOLETE_SETREGID)
7634 return Qtrue;
7635 #else
7636 return Qfalse;
7637 #endif
7642 * call-seq:
7643 * Process::GID.re_exchange -> integer
7645 * Exchange real and effective group IDs and return the new effective
7646 * group ID. Not available on all platforms.
7648 * [Process.gid, Process.egid] #=> [0, 33]
7649 * Process::GID.re_exchange #=> 0
7650 * [Process.gid, Process.egid] #=> [33, 0]
7653 static VALUE
7654 p_gid_exchange(VALUE obj)
7656 rb_gid_t gid;
7657 #if defined(HAVE_SETRESGID) || (defined(HAVE_SETREGID) && !defined(OBSOLETE_SETREGID))
7658 rb_gid_t egid;
7659 #endif
7661 check_gid_switch();
7663 gid = getgid();
7664 #if defined(HAVE_SETRESGID) || (defined(HAVE_SETREGID) && !defined(OBSOLETE_SETREGID))
7665 egid = getegid();
7666 #endif
7668 #if defined(HAVE_SETRESGID)
7669 if (setresgid(egid, gid, gid) < 0) rb_sys_fail(0);
7670 SAVED_GROUP_ID = gid;
7671 #elif defined(HAVE_SETREGID) && !defined(OBSOLETE_SETREGID)
7672 if (setregid(egid,gid) < 0) rb_sys_fail(0);
7673 SAVED_GROUP_ID = gid;
7674 #else
7675 rb_notimplement();
7676 #endif
7677 return GIDT2NUM(gid);
7680 /* [MG] :FIXME: Is this correct? I'm not sure how to phrase this. */
7683 * call-seq:
7684 * Process::UID.sid_available? -> true or false
7686 * Returns +true+ if the current platform has saved user
7687 * ID functionality.
7691 static VALUE
7692 p_uid_have_saved_id(VALUE _)
7694 #if defined(HAVE_SETRESUID) || defined(HAVE_SETEUID) || defined(_POSIX_SAVED_IDS)
7695 return Qtrue;
7696 #else
7697 return Qfalse;
7698 #endif
7702 #if defined(HAVE_SETRESUID) || defined(HAVE_SETEUID) || defined(_POSIX_SAVED_IDS)
7703 static VALUE
7704 p_uid_sw_ensure(VALUE i)
7706 rb_uid_t id = (rb_uid_t/* narrowing */)i;
7707 under_uid_switch = 0;
7708 id = rb_seteuid_core(id);
7709 return UIDT2NUM(id);
7714 * call-seq:
7715 * Process::UID.switch -> integer
7716 * Process::UID.switch {|| block} -> object
7718 * Switch the effective and real user IDs of the current process. If
7719 * a <em>block</em> is given, the user IDs will be switched back
7720 * after the block is executed. Returns the new effective user ID if
7721 * called without a block, and the return value of the block if one
7722 * is given.
7726 static VALUE
7727 p_uid_switch(VALUE obj)
7729 rb_uid_t uid, euid;
7731 check_uid_switch();
7733 uid = getuid();
7734 euid = geteuid();
7736 if (uid != euid) {
7737 proc_seteuid(uid);
7738 if (rb_block_given_p()) {
7739 under_uid_switch = 1;
7740 return rb_ensure(rb_yield, Qnil, p_uid_sw_ensure, SAVED_USER_ID);
7742 else {
7743 return UIDT2NUM(euid);
7746 else if (euid != SAVED_USER_ID) {
7747 proc_seteuid(SAVED_USER_ID);
7748 if (rb_block_given_p()) {
7749 under_uid_switch = 1;
7750 return rb_ensure(rb_yield, Qnil, p_uid_sw_ensure, euid);
7752 else {
7753 return UIDT2NUM(uid);
7756 else {
7757 rb_syserr_fail(EPERM, 0);
7760 UNREACHABLE_RETURN(Qnil);
7762 #else
7763 static VALUE
7764 p_uid_sw_ensure(VALUE obj)
7766 under_uid_switch = 0;
7767 return p_uid_exchange(obj);
7770 static VALUE
7771 p_uid_switch(VALUE obj)
7773 rb_uid_t uid, euid;
7775 check_uid_switch();
7777 uid = getuid();
7778 euid = geteuid();
7780 if (uid == euid) {
7781 rb_syserr_fail(EPERM, 0);
7783 p_uid_exchange(obj);
7784 if (rb_block_given_p()) {
7785 under_uid_switch = 1;
7786 return rb_ensure(rb_yield, Qnil, p_uid_sw_ensure, obj);
7788 else {
7789 return UIDT2NUM(euid);
7792 #endif
7795 /* [MG] :FIXME: Is this correct? I'm not sure how to phrase this. */
7798 * call-seq:
7799 * Process::GID.sid_available? -> true or false
7801 * Returns +true+ if the current platform has saved group
7802 * ID functionality.
7806 static VALUE
7807 p_gid_have_saved_id(VALUE _)
7809 #if defined(HAVE_SETRESGID) || defined(HAVE_SETEGID) || defined(_POSIX_SAVED_IDS)
7810 return Qtrue;
7811 #else
7812 return Qfalse;
7813 #endif
7816 #if defined(HAVE_SETRESGID) || defined(HAVE_SETEGID) || defined(_POSIX_SAVED_IDS)
7817 static VALUE
7818 p_gid_sw_ensure(VALUE i)
7820 rb_gid_t id = (rb_gid_t/* narrowing */)i;
7821 under_gid_switch = 0;
7822 id = rb_setegid_core(id);
7823 return GIDT2NUM(id);
7828 * call-seq:
7829 * Process::GID.switch -> integer
7830 * Process::GID.switch {|| block} -> object
7832 * Switch the effective and real group IDs of the current process. If
7833 * a <em>block</em> is given, the group IDs will be switched back
7834 * after the block is executed. Returns the new effective group ID if
7835 * called without a block, and the return value of the block if one
7836 * is given.
7840 static VALUE
7841 p_gid_switch(VALUE obj)
7843 rb_gid_t gid, egid;
7845 check_gid_switch();
7847 gid = getgid();
7848 egid = getegid();
7850 if (gid != egid) {
7851 proc_setegid(obj, GIDT2NUM(gid));
7852 if (rb_block_given_p()) {
7853 under_gid_switch = 1;
7854 return rb_ensure(rb_yield, Qnil, p_gid_sw_ensure, SAVED_GROUP_ID);
7856 else {
7857 return GIDT2NUM(egid);
7860 else if (egid != SAVED_GROUP_ID) {
7861 proc_setegid(obj, GIDT2NUM(SAVED_GROUP_ID));
7862 if (rb_block_given_p()) {
7863 under_gid_switch = 1;
7864 return rb_ensure(rb_yield, Qnil, p_gid_sw_ensure, egid);
7866 else {
7867 return GIDT2NUM(gid);
7870 else {
7871 rb_syserr_fail(EPERM, 0);
7874 UNREACHABLE_RETURN(Qnil);
7876 #else
7877 static VALUE
7878 p_gid_sw_ensure(VALUE obj)
7880 under_gid_switch = 0;
7881 return p_gid_exchange(obj);
7884 static VALUE
7885 p_gid_switch(VALUE obj)
7887 rb_gid_t gid, egid;
7889 check_gid_switch();
7891 gid = getgid();
7892 egid = getegid();
7894 if (gid == egid) {
7895 rb_syserr_fail(EPERM, 0);
7897 p_gid_exchange(obj);
7898 if (rb_block_given_p()) {
7899 under_gid_switch = 1;
7900 return rb_ensure(rb_yield, Qnil, p_gid_sw_ensure, obj);
7902 else {
7903 return GIDT2NUM(egid);
7906 #endif
7909 #if defined(HAVE_TIMES)
7910 static long
7911 get_clk_tck(void)
7913 #ifdef HAVE__SC_CLK_TCK
7914 return sysconf(_SC_CLK_TCK);
7915 #elif defined CLK_TCK
7916 return CLK_TCK;
7917 #elif defined HZ
7918 return HZ;
7919 #else
7920 return 60;
7921 #endif
7925 * call-seq:
7926 * Process.times -> aProcessTms
7928 * Returns a <code>Tms</code> structure (see Process::Tms)
7929 * that contains user and system CPU times for this process,
7930 * and also for children processes.
7932 * t = Process.times
7933 * [ t.utime, t.stime, t.cutime, t.cstime ] #=> [0.0, 0.02, 0.00, 0.00]
7936 VALUE
7937 rb_proc_times(VALUE obj)
7939 VALUE utime, stime, cutime, cstime, ret;
7940 #if defined(RUSAGE_SELF) && defined(RUSAGE_CHILDREN)
7941 struct rusage usage_s, usage_c;
7943 if (getrusage(RUSAGE_SELF, &usage_s) != 0 || getrusage(RUSAGE_CHILDREN, &usage_c) != 0)
7944 rb_sys_fail("getrusage");
7945 utime = DBL2NUM((double)usage_s.ru_utime.tv_sec + (double)usage_s.ru_utime.tv_usec/1e6);
7946 stime = DBL2NUM((double)usage_s.ru_stime.tv_sec + (double)usage_s.ru_stime.tv_usec/1e6);
7947 cutime = DBL2NUM((double)usage_c.ru_utime.tv_sec + (double)usage_c.ru_utime.tv_usec/1e6);
7948 cstime = DBL2NUM((double)usage_c.ru_stime.tv_sec + (double)usage_c.ru_stime.tv_usec/1e6);
7949 #else
7950 const double hertz = (double)get_clk_tck();
7951 struct tms buf;
7953 times(&buf);
7954 utime = DBL2NUM(buf.tms_utime / hertz);
7955 stime = DBL2NUM(buf.tms_stime / hertz);
7956 cutime = DBL2NUM(buf.tms_cutime / hertz);
7957 cstime = DBL2NUM(buf.tms_cstime / hertz);
7958 #endif
7959 ret = rb_struct_new(rb_cProcessTms, utime, stime, cutime, cstime);
7960 RB_GC_GUARD(utime);
7961 RB_GC_GUARD(stime);
7962 RB_GC_GUARD(cutime);
7963 RB_GC_GUARD(cstime);
7964 return ret;
7966 #else
7967 #define rb_proc_times rb_f_notimplement
7968 #endif
7970 #ifdef HAVE_LONG_LONG
7971 typedef LONG_LONG timetick_int_t;
7972 #define TIMETICK_INT_MIN LLONG_MIN
7973 #define TIMETICK_INT_MAX LLONG_MAX
7974 #define TIMETICK_INT2NUM(v) LL2NUM(v)
7975 #define MUL_OVERFLOW_TIMETICK_P(a, b) MUL_OVERFLOW_LONG_LONG_P(a, b)
7976 #else
7977 typedef long timetick_int_t;
7978 #define TIMETICK_INT_MIN LONG_MIN
7979 #define TIMETICK_INT_MAX LONG_MAX
7980 #define TIMETICK_INT2NUM(v) LONG2NUM(v)
7981 #define MUL_OVERFLOW_TIMETICK_P(a, b) MUL_OVERFLOW_LONG_P(a, b)
7982 #endif
7984 CONSTFUNC(static timetick_int_t gcd_timetick_int(timetick_int_t, timetick_int_t));
7985 static timetick_int_t
7986 gcd_timetick_int(timetick_int_t a, timetick_int_t b)
7988 timetick_int_t t;
7990 if (a < b) {
7991 t = a;
7992 a = b;
7993 b = t;
7996 while (1) {
7997 t = a % b;
7998 if (t == 0)
7999 return b;
8000 a = b;
8001 b = t;
8005 static void
8006 reduce_fraction(timetick_int_t *np, timetick_int_t *dp)
8008 timetick_int_t gcd = gcd_timetick_int(*np, *dp);
8009 if (gcd != 1) {
8010 *np /= gcd;
8011 *dp /= gcd;
8015 static void
8016 reduce_factors(timetick_int_t *numerators, int num_numerators,
8017 timetick_int_t *denominators, int num_denominators)
8019 int i, j;
8020 for (i = 0; i < num_numerators; i++) {
8021 if (numerators[i] == 1)
8022 continue;
8023 for (j = 0; j < num_denominators; j++) {
8024 if (denominators[j] == 1)
8025 continue;
8026 reduce_fraction(&numerators[i], &denominators[j]);
8031 struct timetick {
8032 timetick_int_t giga_count;
8033 int32_t count; /* 0 .. 999999999 */
8036 static VALUE
8037 timetick2dblnum(struct timetick *ttp,
8038 timetick_int_t *numerators, int num_numerators,
8039 timetick_int_t *denominators, int num_denominators)
8041 double d;
8042 int i;
8044 reduce_factors(numerators, num_numerators,
8045 denominators, num_denominators);
8047 d = ttp->giga_count * 1e9 + ttp->count;
8049 for (i = 0; i < num_numerators; i++)
8050 d *= numerators[i];
8051 for (i = 0; i < num_denominators; i++)
8052 d /= denominators[i];
8054 return DBL2NUM(d);
8057 static VALUE
8058 timetick2dblnum_reciprocal(struct timetick *ttp,
8059 timetick_int_t *numerators, int num_numerators,
8060 timetick_int_t *denominators, int num_denominators)
8062 double d;
8063 int i;
8065 reduce_factors(numerators, num_numerators,
8066 denominators, num_denominators);
8068 d = 1.0;
8069 for (i = 0; i < num_denominators; i++)
8070 d *= denominators[i];
8071 for (i = 0; i < num_numerators; i++)
8072 d /= numerators[i];
8073 d /= ttp->giga_count * 1e9 + ttp->count;
8075 return DBL2NUM(d);
8078 #define NDIV(x,y) (-(-((x)+1)/(y))-1)
8079 #define DIV(n,d) ((n)<0 ? NDIV((n),(d)) : (n)/(d))
8081 static VALUE
8082 timetick2integer(struct timetick *ttp,
8083 timetick_int_t *numerators, int num_numerators,
8084 timetick_int_t *denominators, int num_denominators)
8086 VALUE v;
8087 int i;
8089 reduce_factors(numerators, num_numerators,
8090 denominators, num_denominators);
8092 if (!MUL_OVERFLOW_SIGNED_INTEGER_P(1000000000, ttp->giga_count,
8093 TIMETICK_INT_MIN, TIMETICK_INT_MAX-ttp->count)) {
8094 timetick_int_t t = ttp->giga_count * 1000000000 + ttp->count;
8095 for (i = 0; i < num_numerators; i++) {
8096 timetick_int_t factor = numerators[i];
8097 if (MUL_OVERFLOW_TIMETICK_P(factor, t))
8098 goto generic;
8099 t *= factor;
8101 for (i = 0; i < num_denominators; i++) {
8102 t = DIV(t, denominators[i]);
8104 return TIMETICK_INT2NUM(t);
8107 generic:
8108 v = TIMETICK_INT2NUM(ttp->giga_count);
8109 v = rb_funcall(v, '*', 1, LONG2FIX(1000000000));
8110 v = rb_funcall(v, '+', 1, LONG2FIX(ttp->count));
8111 for (i = 0; i < num_numerators; i++) {
8112 timetick_int_t factor = numerators[i];
8113 if (factor == 1)
8114 continue;
8115 v = rb_funcall(v, '*', 1, TIMETICK_INT2NUM(factor));
8117 for (i = 0; i < num_denominators; i++) {
8118 v = rb_funcall(v, '/', 1, TIMETICK_INT2NUM(denominators[i])); /* Ruby's '/' is div. */
8120 return v;
8123 static VALUE
8124 make_clock_result(struct timetick *ttp,
8125 timetick_int_t *numerators, int num_numerators,
8126 timetick_int_t *denominators, int num_denominators,
8127 VALUE unit)
8129 if (unit == ID2SYM(id_nanosecond)) {
8130 numerators[num_numerators++] = 1000000000;
8131 return timetick2integer(ttp, numerators, num_numerators, denominators, num_denominators);
8133 else if (unit == ID2SYM(id_microsecond)) {
8134 numerators[num_numerators++] = 1000000;
8135 return timetick2integer(ttp, numerators, num_numerators, denominators, num_denominators);
8137 else if (unit == ID2SYM(id_millisecond)) {
8138 numerators[num_numerators++] = 1000;
8139 return timetick2integer(ttp, numerators, num_numerators, denominators, num_denominators);
8141 else if (unit == ID2SYM(id_second)) {
8142 return timetick2integer(ttp, numerators, num_numerators, denominators, num_denominators);
8144 else if (unit == ID2SYM(id_float_microsecond)) {
8145 numerators[num_numerators++] = 1000000;
8146 return timetick2dblnum(ttp, numerators, num_numerators, denominators, num_denominators);
8148 else if (unit == ID2SYM(id_float_millisecond)) {
8149 numerators[num_numerators++] = 1000;
8150 return timetick2dblnum(ttp, numerators, num_numerators, denominators, num_denominators);
8152 else if (NIL_P(unit) || unit == ID2SYM(id_float_second)) {
8153 return timetick2dblnum(ttp, numerators, num_numerators, denominators, num_denominators);
8155 else
8156 rb_raise(rb_eArgError, "unexpected unit: %"PRIsVALUE, unit);
8159 #ifdef __APPLE__
8160 static const mach_timebase_info_data_t *
8161 get_mach_timebase_info(void)
8163 static mach_timebase_info_data_t sTimebaseInfo;
8165 if ( sTimebaseInfo.denom == 0 ) {
8166 (void) mach_timebase_info(&sTimebaseInfo);
8169 return &sTimebaseInfo;
8172 double
8173 ruby_real_ms_time(void)
8175 const mach_timebase_info_data_t *info = get_mach_timebase_info();
8176 uint64_t t = mach_absolute_time();
8177 return (double)t * info->numer / info->denom / 1e6;
8179 #endif
8182 * call-seq:
8183 * Process.clock_gettime(clock_id [, unit]) -> number
8185 * Returns a time returned by POSIX clock_gettime() function.
8187 * p Process.clock_gettime(Process::CLOCK_MONOTONIC)
8188 * #=> 896053.968060096
8190 * +clock_id+ specifies a kind of clock.
8191 * It is specified as a constant which begins with <code>Process::CLOCK_</code>
8192 * such as Process::CLOCK_REALTIME and Process::CLOCK_MONOTONIC.
8194 * The supported constants depends on OS and version.
8195 * Ruby provides following types of +clock_id+ if available.
8197 * [CLOCK_REALTIME] SUSv2 to 4, Linux 2.5.63, FreeBSD 3.0, NetBSD 2.0, OpenBSD 2.1, macOS 10.12, Windows-8/Server-2012
8198 * [CLOCK_MONOTONIC] SUSv3 to 4, Linux 2.5.63, FreeBSD 3.0, NetBSD 2.0, OpenBSD 3.4, macOS 10.12, Windows-2000
8199 * [CLOCK_PROCESS_CPUTIME_ID] SUSv3 to 4, Linux 2.5.63, FreeBSD 9.3, OpenBSD 5.4, macOS 10.12
8200 * [CLOCK_THREAD_CPUTIME_ID] SUSv3 to 4, Linux 2.5.63, FreeBSD 7.1, OpenBSD 5.4, macOS 10.12
8201 * [CLOCK_VIRTUAL] FreeBSD 3.0, OpenBSD 2.1
8202 * [CLOCK_PROF] FreeBSD 3.0, OpenBSD 2.1
8203 * [CLOCK_REALTIME_FAST] FreeBSD 8.1
8204 * [CLOCK_REALTIME_PRECISE] FreeBSD 8.1
8205 * [CLOCK_REALTIME_COARSE] Linux 2.6.32
8206 * [CLOCK_REALTIME_ALARM] Linux 3.0
8207 * [CLOCK_MONOTONIC_FAST] FreeBSD 8.1
8208 * [CLOCK_MONOTONIC_PRECISE] FreeBSD 8.1
8209 * [CLOCK_MONOTONIC_COARSE] Linux 2.6.32
8210 * [CLOCK_MONOTONIC_RAW] Linux 2.6.28, macOS 10.12
8211 * [CLOCK_MONOTONIC_RAW_APPROX] macOS 10.12
8212 * [CLOCK_BOOTTIME] Linux 2.6.39
8213 * [CLOCK_BOOTTIME_ALARM] Linux 3.0
8214 * [CLOCK_UPTIME] FreeBSD 7.0, OpenBSD 5.5
8215 * [CLOCK_UPTIME_FAST] FreeBSD 8.1
8216 * [CLOCK_UPTIME_RAW] macOS 10.12
8217 * [CLOCK_UPTIME_RAW_APPROX] macOS 10.12
8218 * [CLOCK_UPTIME_PRECISE] FreeBSD 8.1
8219 * [CLOCK_SECOND] FreeBSD 8.1
8220 * [CLOCK_TAI] Linux 3.10
8222 * Note that SUS stands for Single Unix Specification.
8223 * SUS contains POSIX and clock_gettime is defined in the POSIX part.
8224 * SUS defines CLOCK_REALTIME mandatory but
8225 * CLOCK_MONOTONIC, CLOCK_PROCESS_CPUTIME_ID and CLOCK_THREAD_CPUTIME_ID are optional.
8227 * Also, several symbols are accepted as +clock_id+.
8228 * There are emulations for clock_gettime().
8230 * For example, Process::CLOCK_REALTIME is defined as
8231 * +:GETTIMEOFDAY_BASED_CLOCK_REALTIME+ when clock_gettime() is not available.
8233 * Emulations for +CLOCK_REALTIME+:
8234 * [:GETTIMEOFDAY_BASED_CLOCK_REALTIME]
8235 * Use gettimeofday() defined by SUS.
8236 * (SUSv4 obsoleted it, though.)
8237 * The resolution is 1 microsecond.
8238 * [:TIME_BASED_CLOCK_REALTIME]
8239 * Use time() defined by ISO C.
8240 * The resolution is 1 second.
8242 * Emulations for +CLOCK_MONOTONIC+:
8243 * [:MACH_ABSOLUTE_TIME_BASED_CLOCK_MONOTONIC]
8244 * Use mach_absolute_time(), available on Darwin.
8245 * The resolution is CPU dependent.
8246 * [:TIMES_BASED_CLOCK_MONOTONIC]
8247 * Use the result value of times() defined by POSIX.
8248 * POSIX defines it as "times() shall return the elapsed real time, in clock ticks, since an arbitrary point in the past (for example, system start-up time)".
8249 * For example, GNU/Linux returns a value based on jiffies and it is monotonic.
8250 * However, 4.4BSD uses gettimeofday() and it is not monotonic.
8251 * (FreeBSD uses clock_gettime(CLOCK_MONOTONIC) instead, though.)
8252 * The resolution is the clock tick.
8253 * "getconf CLK_TCK" command shows the clock ticks per second.
8254 * (The clock ticks per second is defined by HZ macro in older systems.)
8255 * If it is 100 and clock_t is 32 bits integer type, the resolution is 10 millisecond and
8256 * cannot represent over 497 days.
8258 * Emulations for +CLOCK_PROCESS_CPUTIME_ID+:
8259 * [:GETRUSAGE_BASED_CLOCK_PROCESS_CPUTIME_ID]
8260 * Use getrusage() defined by SUS.
8261 * getrusage() is used with RUSAGE_SELF to obtain the time only for
8262 * the calling process (excluding the time for child processes).
8263 * The result is addition of user time (ru_utime) and system time (ru_stime).
8264 * The resolution is 1 microsecond.
8265 * [:TIMES_BASED_CLOCK_PROCESS_CPUTIME_ID]
8266 * Use times() defined by POSIX.
8267 * The result is addition of user time (tms_utime) and system time (tms_stime).
8268 * tms_cutime and tms_cstime are ignored to exclude the time for child processes.
8269 * The resolution is the clock tick.
8270 * "getconf CLK_TCK" command shows the clock ticks per second.
8271 * (The clock ticks per second is defined by HZ macro in older systems.)
8272 * If it is 100, the resolution is 10 millisecond.
8273 * [:CLOCK_BASED_CLOCK_PROCESS_CPUTIME_ID]
8274 * Use clock() defined by ISO C.
8275 * The resolution is 1/CLOCKS_PER_SEC.
8276 * CLOCKS_PER_SEC is the C-level macro defined by time.h.
8277 * SUS defines CLOCKS_PER_SEC is 1000000.
8278 * Non-Unix systems may define it a different value, though.
8279 * If CLOCKS_PER_SEC is 1000000 as SUS, the resolution is 1 microsecond.
8280 * If CLOCKS_PER_SEC is 1000000 and clock_t is 32 bits integer type, it cannot represent over 72 minutes.
8282 * If the given +clock_id+ is not supported, Errno::EINVAL is raised.
8284 * +unit+ specifies a type of the return value.
8286 * [:float_second] number of seconds as a float (default)
8287 * [:float_millisecond] number of milliseconds as a float
8288 * [:float_microsecond] number of microseconds as a float
8289 * [:second] number of seconds as an integer
8290 * [:millisecond] number of milliseconds as an integer
8291 * [:microsecond] number of microseconds as an integer
8292 * [:nanosecond] number of nanoseconds as an integer
8294 * The underlying function, clock_gettime(), returns a number of nanoseconds.
8295 * Float object (IEEE 754 double) is not enough to represent
8296 * the return value for CLOCK_REALTIME.
8297 * If the exact nanoseconds value is required, use +:nanoseconds+ as the +unit+.
8299 * The origin (zero) of the returned value varies.
8300 * For example, system start up time, process start up time, the Epoch, etc.
8302 * The origin in CLOCK_REALTIME is defined as the Epoch
8303 * (1970-01-01 00:00:00 UTC).
8304 * But some systems count leap seconds and others doesn't.
8305 * So the result can be interpreted differently across systems.
8306 * Time.now is recommended over CLOCK_REALTIME.
8308 static VALUE
8309 rb_clock_gettime(int argc, VALUE *argv, VALUE _)
8311 int ret;
8313 struct timetick tt;
8314 timetick_int_t numerators[2];
8315 timetick_int_t denominators[2];
8316 int num_numerators = 0;
8317 int num_denominators = 0;
8319 VALUE unit = (rb_check_arity(argc, 1, 2) == 2) ? argv[1] : Qnil;
8320 VALUE clk_id = argv[0];
8322 if (SYMBOL_P(clk_id)) {
8324 * Non-clock_gettime clocks are provided by symbol clk_id.
8326 #ifdef HAVE_GETTIMEOFDAY
8328 * GETTIMEOFDAY_BASED_CLOCK_REALTIME is used for
8329 * CLOCK_REALTIME if clock_gettime is not available.
8331 #define RUBY_GETTIMEOFDAY_BASED_CLOCK_REALTIME ID2SYM(id_GETTIMEOFDAY_BASED_CLOCK_REALTIME)
8332 if (clk_id == RUBY_GETTIMEOFDAY_BASED_CLOCK_REALTIME) {
8333 struct timeval tv;
8334 ret = gettimeofday(&tv, 0);
8335 if (ret != 0)
8336 rb_sys_fail("gettimeofday");
8337 tt.giga_count = tv.tv_sec;
8338 tt.count = (int32_t)tv.tv_usec * 1000;
8339 denominators[num_denominators++] = 1000000000;
8340 goto success;
8342 #endif
8344 #define RUBY_TIME_BASED_CLOCK_REALTIME ID2SYM(id_TIME_BASED_CLOCK_REALTIME)
8345 if (clk_id == RUBY_TIME_BASED_CLOCK_REALTIME) {
8346 time_t t;
8347 t = time(NULL);
8348 if (t == (time_t)-1)
8349 rb_sys_fail("time");
8350 tt.giga_count = t;
8351 tt.count = 0;
8352 denominators[num_denominators++] = 1000000000;
8353 goto success;
8356 #ifdef HAVE_TIMES
8357 #define RUBY_TIMES_BASED_CLOCK_MONOTONIC \
8358 ID2SYM(id_TIMES_BASED_CLOCK_MONOTONIC)
8359 if (clk_id == RUBY_TIMES_BASED_CLOCK_MONOTONIC) {
8360 struct tms buf;
8361 clock_t c;
8362 unsigned_clock_t uc;
8363 c = times(&buf);
8364 if (c == (clock_t)-1)
8365 rb_sys_fail("times");
8366 uc = (unsigned_clock_t)c;
8367 tt.count = (int32_t)(uc % 1000000000);
8368 tt.giga_count = (uc / 1000000000);
8369 denominators[num_denominators++] = get_clk_tck();
8370 goto success;
8372 #endif
8374 #ifdef RUSAGE_SELF
8375 #define RUBY_GETRUSAGE_BASED_CLOCK_PROCESS_CPUTIME_ID \
8376 ID2SYM(id_GETRUSAGE_BASED_CLOCK_PROCESS_CPUTIME_ID)
8377 if (clk_id == RUBY_GETRUSAGE_BASED_CLOCK_PROCESS_CPUTIME_ID) {
8378 struct rusage usage;
8379 int32_t usec;
8380 ret = getrusage(RUSAGE_SELF, &usage);
8381 if (ret != 0)
8382 rb_sys_fail("getrusage");
8383 tt.giga_count = usage.ru_utime.tv_sec + usage.ru_stime.tv_sec;
8384 usec = (int32_t)(usage.ru_utime.tv_usec + usage.ru_stime.tv_usec);
8385 if (1000000 <= usec) {
8386 tt.giga_count++;
8387 usec -= 1000000;
8389 tt.count = usec * 1000;
8390 denominators[num_denominators++] = 1000000000;
8391 goto success;
8393 #endif
8395 #ifdef HAVE_TIMES
8396 #define RUBY_TIMES_BASED_CLOCK_PROCESS_CPUTIME_ID \
8397 ID2SYM(id_TIMES_BASED_CLOCK_PROCESS_CPUTIME_ID)
8398 if (clk_id == RUBY_TIMES_BASED_CLOCK_PROCESS_CPUTIME_ID) {
8399 struct tms buf;
8400 unsigned_clock_t utime, stime;
8401 if (times(&buf) == (clock_t)-1)
8402 rb_sys_fail("times");
8403 utime = (unsigned_clock_t)buf.tms_utime;
8404 stime = (unsigned_clock_t)buf.tms_stime;
8405 tt.count = (int32_t)((utime % 1000000000) + (stime % 1000000000));
8406 tt.giga_count = (utime / 1000000000) + (stime / 1000000000);
8407 if (1000000000 <= tt.count) {
8408 tt.count -= 1000000000;
8409 tt.giga_count++;
8411 denominators[num_denominators++] = get_clk_tck();
8412 goto success;
8414 #endif
8416 #define RUBY_CLOCK_BASED_CLOCK_PROCESS_CPUTIME_ID \
8417 ID2SYM(id_CLOCK_BASED_CLOCK_PROCESS_CPUTIME_ID)
8418 if (clk_id == RUBY_CLOCK_BASED_CLOCK_PROCESS_CPUTIME_ID) {
8419 clock_t c;
8420 unsigned_clock_t uc;
8421 errno = 0;
8422 c = clock();
8423 if (c == (clock_t)-1)
8424 rb_sys_fail("clock");
8425 uc = (unsigned_clock_t)c;
8426 tt.count = (int32_t)(uc % 1000000000);
8427 tt.giga_count = uc / 1000000000;
8428 denominators[num_denominators++] = CLOCKS_PER_SEC;
8429 goto success;
8432 #ifdef __APPLE__
8433 #define RUBY_MACH_ABSOLUTE_TIME_BASED_CLOCK_MONOTONIC ID2SYM(id_MACH_ABSOLUTE_TIME_BASED_CLOCK_MONOTONIC)
8434 if (clk_id == RUBY_MACH_ABSOLUTE_TIME_BASED_CLOCK_MONOTONIC) {
8435 const mach_timebase_info_data_t *info = get_mach_timebase_info();
8436 uint64_t t = mach_absolute_time();
8437 tt.count = (int32_t)(t % 1000000000);
8438 tt.giga_count = t / 1000000000;
8439 numerators[num_numerators++] = info->numer;
8440 denominators[num_denominators++] = info->denom;
8441 denominators[num_denominators++] = 1000000000;
8442 goto success;
8444 #endif
8446 else {
8447 #if defined(HAVE_CLOCK_GETTIME)
8448 struct timespec ts;
8449 clockid_t c;
8450 c = NUM2CLOCKID(clk_id);
8451 ret = clock_gettime(c, &ts);
8452 if (ret == -1)
8453 rb_sys_fail("clock_gettime");
8454 tt.count = (int32_t)ts.tv_nsec;
8455 tt.giga_count = ts.tv_sec;
8456 denominators[num_denominators++] = 1000000000;
8457 goto success;
8458 #endif
8460 /* EINVAL emulates clock_gettime behavior when clock_id is invalid. */
8461 rb_syserr_fail(EINVAL, 0);
8463 success:
8464 return make_clock_result(&tt, numerators, num_numerators, denominators, num_denominators, unit);
8468 * call-seq:
8469 * Process.clock_getres(clock_id [, unit]) -> number
8471 * Returns an estimate of the resolution of a +clock_id+ using the POSIX
8472 * <code>clock_getres()</code> function.
8474 * Note the reported resolution is often inaccurate on most platforms due to
8475 * underlying bugs for this function and therefore the reported resolution
8476 * often differs from the actual resolution of the clock in practice.
8477 * Inaccurate reported resolutions have been observed for various clocks including
8478 * CLOCK_MONOTONIC and CLOCK_MONOTONIC_RAW when using Linux, macOS, BSD or AIX
8479 * platforms, when using ARM processors, or when using virtualization.
8481 * +clock_id+ specifies a kind of clock.
8482 * See the document of +Process.clock_gettime+ for details.
8483 * +clock_id+ can be a symbol as for +Process.clock_gettime+.
8485 * If the given +clock_id+ is not supported, Errno::EINVAL is raised.
8487 * +unit+ specifies the type of the return value.
8488 * +Process.clock_getres+ accepts +unit+ as +Process.clock_gettime+.
8489 * The default value, +:float_second+, is also the same as
8490 * +Process.clock_gettime+.
8492 * +Process.clock_getres+ also accepts +:hertz+ as +unit+.
8493 * +:hertz+ means the reciprocal of +:float_second+.
8495 * +:hertz+ can be used to obtain the exact value of
8496 * the clock ticks per second for the times() function and
8497 * CLOCKS_PER_SEC for the clock() function.
8499 * <code>Process.clock_getres(:TIMES_BASED_CLOCK_PROCESS_CPUTIME_ID, :hertz)</code>
8500 * returns the clock ticks per second.
8502 * <code>Process.clock_getres(:CLOCK_BASED_CLOCK_PROCESS_CPUTIME_ID, :hertz)</code>
8503 * returns CLOCKS_PER_SEC.
8505 * p Process.clock_getres(Process::CLOCK_MONOTONIC)
8506 * #=> 1.0e-09
8509 static VALUE
8510 rb_clock_getres(int argc, VALUE *argv, VALUE _)
8512 struct timetick tt;
8513 timetick_int_t numerators[2];
8514 timetick_int_t denominators[2];
8515 int num_numerators = 0;
8516 int num_denominators = 0;
8518 VALUE unit = (rb_check_arity(argc, 1, 2) == 2) ? argv[1] : Qnil;
8519 VALUE clk_id = argv[0];
8521 if (SYMBOL_P(clk_id)) {
8522 #ifdef RUBY_GETTIMEOFDAY_BASED_CLOCK_REALTIME
8523 if (clk_id == RUBY_GETTIMEOFDAY_BASED_CLOCK_REALTIME) {
8524 tt.giga_count = 0;
8525 tt.count = 1000;
8526 denominators[num_denominators++] = 1000000000;
8527 goto success;
8529 #endif
8531 #ifdef RUBY_TIME_BASED_CLOCK_REALTIME
8532 if (clk_id == RUBY_TIME_BASED_CLOCK_REALTIME) {
8533 tt.giga_count = 1;
8534 tt.count = 0;
8535 denominators[num_denominators++] = 1000000000;
8536 goto success;
8538 #endif
8540 #ifdef RUBY_TIMES_BASED_CLOCK_MONOTONIC
8541 if (clk_id == RUBY_TIMES_BASED_CLOCK_MONOTONIC) {
8542 tt.count = 1;
8543 tt.giga_count = 0;
8544 denominators[num_denominators++] = get_clk_tck();
8545 goto success;
8547 #endif
8549 #ifdef RUBY_GETRUSAGE_BASED_CLOCK_PROCESS_CPUTIME_ID
8550 if (clk_id == RUBY_GETRUSAGE_BASED_CLOCK_PROCESS_CPUTIME_ID) {
8551 tt.giga_count = 0;
8552 tt.count = 1000;
8553 denominators[num_denominators++] = 1000000000;
8554 goto success;
8556 #endif
8558 #ifdef RUBY_TIMES_BASED_CLOCK_PROCESS_CPUTIME_ID
8559 if (clk_id == RUBY_TIMES_BASED_CLOCK_PROCESS_CPUTIME_ID) {
8560 tt.count = 1;
8561 tt.giga_count = 0;
8562 denominators[num_denominators++] = get_clk_tck();
8563 goto success;
8565 #endif
8567 #ifdef RUBY_CLOCK_BASED_CLOCK_PROCESS_CPUTIME_ID
8568 if (clk_id == RUBY_CLOCK_BASED_CLOCK_PROCESS_CPUTIME_ID) {
8569 tt.count = 1;
8570 tt.giga_count = 0;
8571 denominators[num_denominators++] = CLOCKS_PER_SEC;
8572 goto success;
8574 #endif
8576 #ifdef RUBY_MACH_ABSOLUTE_TIME_BASED_CLOCK_MONOTONIC
8577 if (clk_id == RUBY_MACH_ABSOLUTE_TIME_BASED_CLOCK_MONOTONIC) {
8578 const mach_timebase_info_data_t *info = get_mach_timebase_info();
8579 tt.count = 1;
8580 tt.giga_count = 0;
8581 numerators[num_numerators++] = info->numer;
8582 denominators[num_denominators++] = info->denom;
8583 denominators[num_denominators++] = 1000000000;
8584 goto success;
8586 #endif
8588 else {
8589 #if defined(HAVE_CLOCK_GETRES)
8590 struct timespec ts;
8591 clockid_t c = NUM2CLOCKID(clk_id);
8592 int ret = clock_getres(c, &ts);
8593 if (ret == -1)
8594 rb_sys_fail("clock_getres");
8595 tt.count = (int32_t)ts.tv_nsec;
8596 tt.giga_count = ts.tv_sec;
8597 denominators[num_denominators++] = 1000000000;
8598 goto success;
8599 #endif
8601 /* EINVAL emulates clock_getres behavior when clock_id is invalid. */
8602 rb_syserr_fail(EINVAL, 0);
8604 success:
8605 if (unit == ID2SYM(id_hertz)) {
8606 return timetick2dblnum_reciprocal(&tt, numerators, num_numerators, denominators, num_denominators);
8608 else {
8609 return make_clock_result(&tt, numerators, num_numerators, denominators, num_denominators, unit);
8613 static VALUE
8614 get_CHILD_STATUS(ID _x, VALUE *_y)
8616 return rb_last_status_get();
8619 static VALUE
8620 get_PROCESS_ID(ID _x, VALUE *_y)
8622 return get_pid();
8626 * call-seq:
8627 * Process.kill(signal, pid, ...) -> integer
8629 * Sends the given signal to the specified process id(s) if _pid_ is positive.
8630 * If _pid_ is zero, _signal_ is sent to all processes whose group ID is equal
8631 * to the group ID of the process. If _pid_ is negative, results are dependent
8632 * on the operating system. _signal_ may be an integer signal number or
8633 * a POSIX signal name (either with or without a +SIG+ prefix). If _signal_ is
8634 * negative (or starts with a minus sign), kills process groups instead of
8635 * processes. Not all signals are available on all platforms.
8636 * The keys and values of Signal.list are known signal names and numbers,
8637 * respectively.
8639 * pid = fork do
8640 * Signal.trap("HUP") { puts "Ouch!"; exit }
8641 * # ... do some work ...
8642 * end
8643 * # ...
8644 * Process.kill("HUP", pid)
8645 * Process.wait
8647 * <em>produces:</em>
8649 * Ouch!
8651 * If _signal_ is an integer but wrong for signal, Errno::EINVAL or
8652 * RangeError will be raised. Otherwise unless _signal_ is a String
8653 * or a Symbol, and a known signal name, ArgumentError will be
8654 * raised.
8656 * Also, Errno::ESRCH or RangeError for invalid _pid_, Errno::EPERM
8657 * when failed because of no privilege, will be raised. In these
8658 * cases, signals may have been sent to preceding processes.
8661 static VALUE
8662 proc_rb_f_kill(int c, const VALUE *v, VALUE _)
8664 return rb_f_kill(c, v);
8667 VALUE rb_mProcess;
8668 static VALUE rb_mProcUID;
8669 static VALUE rb_mProcGID;
8670 static VALUE rb_mProcID_Syscall;
8674 * The Process module is a collection of methods used to
8675 * manipulate processes.
8678 void
8679 InitVM_process(void)
8681 rb_define_virtual_variable("$?", get_CHILD_STATUS, 0);
8682 rb_define_virtual_variable("$$", get_PROCESS_ID, 0);
8684 rb_gvar_ractor_local("$$");
8685 rb_gvar_ractor_local("$?");
8687 rb_define_global_function("exec", f_exec, -1);
8688 rb_define_global_function("fork", rb_f_fork, 0);
8689 rb_define_global_function("exit!", rb_f_exit_bang, -1);
8690 rb_define_global_function("system", rb_f_system, -1);
8691 rb_define_global_function("spawn", rb_f_spawn, -1);
8692 rb_define_global_function("sleep", rb_f_sleep, -1);
8693 rb_define_global_function("exit", f_exit, -1);
8694 rb_define_global_function("abort", f_abort, -1);
8696 rb_mProcess = rb_define_module("Process");
8698 #ifdef WNOHANG
8699 /* see Process.wait */
8700 rb_define_const(rb_mProcess, "WNOHANG", INT2FIX(WNOHANG));
8701 #else
8702 /* see Process.wait */
8703 rb_define_const(rb_mProcess, "WNOHANG", INT2FIX(0));
8704 #endif
8705 #ifdef WUNTRACED
8706 /* see Process.wait */
8707 rb_define_const(rb_mProcess, "WUNTRACED", INT2FIX(WUNTRACED));
8708 #else
8709 /* see Process.wait */
8710 rb_define_const(rb_mProcess, "WUNTRACED", INT2FIX(0));
8711 #endif
8713 rb_define_singleton_method(rb_mProcess, "exec", f_exec, -1);
8714 rb_define_singleton_method(rb_mProcess, "fork", rb_f_fork, 0);
8715 rb_define_singleton_method(rb_mProcess, "spawn", rb_f_spawn, -1);
8716 rb_define_singleton_method(rb_mProcess, "exit!", rb_f_exit_bang, -1);
8717 rb_define_singleton_method(rb_mProcess, "exit", f_exit, -1);
8718 rb_define_singleton_method(rb_mProcess, "abort", f_abort, -1);
8719 rb_define_singleton_method(rb_mProcess, "last_status", proc_s_last_status, 0);
8720 rb_define_singleton_method(rb_mProcess, "_fork", rb_proc__fork, 0);
8722 rb_define_module_function(rb_mProcess, "kill", proc_rb_f_kill, -1);
8723 rb_define_module_function(rb_mProcess, "wait", proc_m_wait, -1);
8724 rb_define_module_function(rb_mProcess, "wait2", proc_wait2, -1);
8725 rb_define_module_function(rb_mProcess, "waitpid", proc_m_wait, -1);
8726 rb_define_module_function(rb_mProcess, "waitpid2", proc_wait2, -1);
8727 rb_define_module_function(rb_mProcess, "waitall", proc_waitall, 0);
8728 rb_define_module_function(rb_mProcess, "detach", proc_detach, 1);
8730 /* :nodoc: */
8731 rb_cWaiter = rb_define_class_under(rb_mProcess, "Waiter", rb_cThread);
8732 rb_undef_alloc_func(rb_cWaiter);
8733 rb_undef_method(CLASS_OF(rb_cWaiter), "new");
8734 rb_define_method(rb_cWaiter, "pid", detach_process_pid, 0);
8736 rb_cProcessStatus = rb_define_class_under(rb_mProcess, "Status", rb_cObject);
8737 rb_define_alloc_func(rb_cProcessStatus, rb_process_status_allocate);
8738 rb_undef_method(CLASS_OF(rb_cProcessStatus), "new");
8739 rb_marshal_define_compat(rb_cProcessStatus, rb_cObject,
8740 process_status_dump, process_status_load);
8742 rb_define_singleton_method(rb_cProcessStatus, "wait", rb_process_status_waitv, -1);
8744 rb_define_method(rb_cProcessStatus, "==", pst_equal, 1);
8745 rb_define_method(rb_cProcessStatus, "&", pst_bitand, 1);
8746 rb_define_method(rb_cProcessStatus, ">>", pst_rshift, 1);
8747 rb_define_method(rb_cProcessStatus, "to_i", pst_to_i, 0);
8748 rb_define_method(rb_cProcessStatus, "to_s", pst_to_s, 0);
8749 rb_define_method(rb_cProcessStatus, "inspect", pst_inspect, 0);
8751 rb_define_method(rb_cProcessStatus, "pid", pst_pid_m, 0);
8753 rb_define_method(rb_cProcessStatus, "stopped?", pst_wifstopped, 0);
8754 rb_define_method(rb_cProcessStatus, "stopsig", pst_wstopsig, 0);
8755 rb_define_method(rb_cProcessStatus, "signaled?", pst_wifsignaled, 0);
8756 rb_define_method(rb_cProcessStatus, "termsig", pst_wtermsig, 0);
8757 rb_define_method(rb_cProcessStatus, "exited?", pst_wifexited, 0);
8758 rb_define_method(rb_cProcessStatus, "exitstatus", pst_wexitstatus, 0);
8759 rb_define_method(rb_cProcessStatus, "success?", pst_success_p, 0);
8760 rb_define_method(rb_cProcessStatus, "coredump?", pst_wcoredump, 0);
8762 rb_define_module_function(rb_mProcess, "pid", proc_get_pid, 0);
8763 rb_define_module_function(rb_mProcess, "ppid", proc_get_ppid, 0);
8765 rb_define_module_function(rb_mProcess, "getpgrp", proc_getpgrp, 0);
8766 rb_define_module_function(rb_mProcess, "setpgrp", proc_setpgrp, 0);
8767 rb_define_module_function(rb_mProcess, "getpgid", proc_getpgid, 1);
8768 rb_define_module_function(rb_mProcess, "setpgid", proc_setpgid, 2);
8770 rb_define_module_function(rb_mProcess, "getsid", proc_getsid, -1);
8771 rb_define_module_function(rb_mProcess, "setsid", proc_setsid, 0);
8773 rb_define_module_function(rb_mProcess, "getpriority", proc_getpriority, 2);
8774 rb_define_module_function(rb_mProcess, "setpriority", proc_setpriority, 3);
8776 #ifdef HAVE_GETPRIORITY
8777 /* see Process.setpriority */
8778 rb_define_const(rb_mProcess, "PRIO_PROCESS", INT2FIX(PRIO_PROCESS));
8779 /* see Process.setpriority */
8780 rb_define_const(rb_mProcess, "PRIO_PGRP", INT2FIX(PRIO_PGRP));
8781 /* see Process.setpriority */
8782 rb_define_const(rb_mProcess, "PRIO_USER", INT2FIX(PRIO_USER));
8783 #endif
8785 rb_define_module_function(rb_mProcess, "getrlimit", proc_getrlimit, 1);
8786 rb_define_module_function(rb_mProcess, "setrlimit", proc_setrlimit, -1);
8787 #if defined(RLIM2NUM) && defined(RLIM_INFINITY)
8789 VALUE inf = RLIM2NUM(RLIM_INFINITY);
8790 #ifdef RLIM_SAVED_MAX
8792 VALUE v = RLIM_INFINITY == RLIM_SAVED_MAX ? inf : RLIM2NUM(RLIM_SAVED_MAX);
8793 /* see Process.setrlimit */
8794 rb_define_const(rb_mProcess, "RLIM_SAVED_MAX", v);
8796 #endif
8797 /* see Process.setrlimit */
8798 rb_define_const(rb_mProcess, "RLIM_INFINITY", inf);
8799 #ifdef RLIM_SAVED_CUR
8801 VALUE v = RLIM_INFINITY == RLIM_SAVED_CUR ? inf : RLIM2NUM(RLIM_SAVED_CUR);
8802 /* see Process.setrlimit */
8803 rb_define_const(rb_mProcess, "RLIM_SAVED_CUR", v);
8805 #endif
8807 #ifdef RLIMIT_AS
8808 /* Maximum size of the process's virtual memory (address space) in bytes.
8810 * see the system getrlimit(2) manual for details.
8812 rb_define_const(rb_mProcess, "RLIMIT_AS", INT2FIX(RLIMIT_AS));
8813 #endif
8814 #ifdef RLIMIT_CORE
8815 /* Maximum size of the core file.
8817 * see the system getrlimit(2) manual for details.
8819 rb_define_const(rb_mProcess, "RLIMIT_CORE", INT2FIX(RLIMIT_CORE));
8820 #endif
8821 #ifdef RLIMIT_CPU
8822 /* CPU time limit in seconds.
8824 * see the system getrlimit(2) manual for details.
8826 rb_define_const(rb_mProcess, "RLIMIT_CPU", INT2FIX(RLIMIT_CPU));
8827 #endif
8828 #ifdef RLIMIT_DATA
8829 /* Maximum size of the process's data segment.
8831 * see the system getrlimit(2) manual for details.
8833 rb_define_const(rb_mProcess, "RLIMIT_DATA", INT2FIX(RLIMIT_DATA));
8834 #endif
8835 #ifdef RLIMIT_FSIZE
8836 /* Maximum size of files that the process may create.
8838 * see the system getrlimit(2) manual for details.
8840 rb_define_const(rb_mProcess, "RLIMIT_FSIZE", INT2FIX(RLIMIT_FSIZE));
8841 #endif
8842 #ifdef RLIMIT_MEMLOCK
8843 /* Maximum number of bytes of memory that may be locked into RAM.
8845 * see the system getrlimit(2) manual for details.
8847 rb_define_const(rb_mProcess, "RLIMIT_MEMLOCK", INT2FIX(RLIMIT_MEMLOCK));
8848 #endif
8849 #ifdef RLIMIT_MSGQUEUE
8850 /* Specifies the limit on the number of bytes that can be allocated
8851 * for POSIX message queues for the real user ID of the calling process.
8853 * see the system getrlimit(2) manual for details.
8855 rb_define_const(rb_mProcess, "RLIMIT_MSGQUEUE", INT2FIX(RLIMIT_MSGQUEUE));
8856 #endif
8857 #ifdef RLIMIT_NICE
8858 /* Specifies a ceiling to which the process's nice value can be raised.
8860 * see the system getrlimit(2) manual for details.
8862 rb_define_const(rb_mProcess, "RLIMIT_NICE", INT2FIX(RLIMIT_NICE));
8863 #endif
8864 #ifdef RLIMIT_NOFILE
8865 /* Specifies a value one greater than the maximum file descriptor
8866 * number that can be opened by this process.
8868 * see the system getrlimit(2) manual for details.
8870 rb_define_const(rb_mProcess, "RLIMIT_NOFILE", INT2FIX(RLIMIT_NOFILE));
8871 #endif
8872 #ifdef RLIMIT_NPROC
8873 /* The maximum number of processes that can be created for the
8874 * real user ID of the calling process.
8876 * see the system getrlimit(2) manual for details.
8878 rb_define_const(rb_mProcess, "RLIMIT_NPROC", INT2FIX(RLIMIT_NPROC));
8879 #endif
8880 #ifdef RLIMIT_RSS
8881 /* Specifies the limit (in pages) of the process's resident set.
8883 * see the system getrlimit(2) manual for details.
8885 rb_define_const(rb_mProcess, "RLIMIT_RSS", INT2FIX(RLIMIT_RSS));
8886 #endif
8887 #ifdef RLIMIT_RTPRIO
8888 /* Specifies a ceiling on the real-time priority that may be set for this process.
8890 * see the system getrlimit(2) manual for details.
8892 rb_define_const(rb_mProcess, "RLIMIT_RTPRIO", INT2FIX(RLIMIT_RTPRIO));
8893 #endif
8894 #ifdef RLIMIT_RTTIME
8895 /* Specifies limit on CPU time this process scheduled under a real-time
8896 * scheduling policy can consume.
8898 * see the system getrlimit(2) manual for details.
8900 rb_define_const(rb_mProcess, "RLIMIT_RTTIME", INT2FIX(RLIMIT_RTTIME));
8901 #endif
8902 #ifdef RLIMIT_SBSIZE
8903 /* Maximum size of the socket buffer.
8905 rb_define_const(rb_mProcess, "RLIMIT_SBSIZE", INT2FIX(RLIMIT_SBSIZE));
8906 #endif
8907 #ifdef RLIMIT_SIGPENDING
8908 /* Specifies a limit on the number of signals that may be queued for
8909 * the real user ID of the calling process.
8911 * see the system getrlimit(2) manual for details.
8913 rb_define_const(rb_mProcess, "RLIMIT_SIGPENDING", INT2FIX(RLIMIT_SIGPENDING));
8914 #endif
8915 #ifdef RLIMIT_STACK
8916 /* Maximum size of the stack, in bytes.
8918 * see the system getrlimit(2) manual for details.
8920 rb_define_const(rb_mProcess, "RLIMIT_STACK", INT2FIX(RLIMIT_STACK));
8921 #endif
8922 #endif
8924 rb_define_module_function(rb_mProcess, "uid", proc_getuid, 0);
8925 rb_define_module_function(rb_mProcess, "uid=", proc_setuid, 1);
8926 rb_define_module_function(rb_mProcess, "gid", proc_getgid, 0);
8927 rb_define_module_function(rb_mProcess, "gid=", proc_setgid, 1);
8928 rb_define_module_function(rb_mProcess, "euid", proc_geteuid, 0);
8929 rb_define_module_function(rb_mProcess, "euid=", proc_seteuid_m, 1);
8930 rb_define_module_function(rb_mProcess, "egid", proc_getegid, 0);
8931 rb_define_module_function(rb_mProcess, "egid=", proc_setegid_m, 1);
8932 rb_define_module_function(rb_mProcess, "initgroups", proc_initgroups, 2);
8933 rb_define_module_function(rb_mProcess, "groups", proc_getgroups, 0);
8934 rb_define_module_function(rb_mProcess, "groups=", proc_setgroups, 1);
8935 rb_define_module_function(rb_mProcess, "maxgroups", proc_getmaxgroups, 0);
8936 rb_define_module_function(rb_mProcess, "maxgroups=", proc_setmaxgroups, 1);
8938 rb_define_module_function(rb_mProcess, "daemon", proc_daemon, -1);
8940 rb_define_module_function(rb_mProcess, "times", rb_proc_times, 0);
8942 #ifdef CLOCK_REALTIME
8943 /* see Process.clock_gettime */
8944 rb_define_const(rb_mProcess, "CLOCK_REALTIME", CLOCKID2NUM(CLOCK_REALTIME));
8945 #elif defined(RUBY_GETTIMEOFDAY_BASED_CLOCK_REALTIME)
8946 /* see Process.clock_gettime */
8947 rb_define_const(rb_mProcess, "CLOCK_REALTIME", RUBY_GETTIMEOFDAY_BASED_CLOCK_REALTIME);
8948 #endif
8949 #ifdef CLOCK_MONOTONIC
8950 /* see Process.clock_gettime */
8951 rb_define_const(rb_mProcess, "CLOCK_MONOTONIC", CLOCKID2NUM(CLOCK_MONOTONIC));
8952 #elif defined(RUBY_MACH_ABSOLUTE_TIME_BASED_CLOCK_MONOTONIC)
8953 /* see Process.clock_gettime */
8954 rb_define_const(rb_mProcess, "CLOCK_MONOTONIC", RUBY_MACH_ABSOLUTE_TIME_BASED_CLOCK_MONOTONIC);
8955 #endif
8956 #ifdef CLOCK_PROCESS_CPUTIME_ID
8957 /* see Process.clock_gettime */
8958 rb_define_const(rb_mProcess, "CLOCK_PROCESS_CPUTIME_ID", CLOCKID2NUM(CLOCK_PROCESS_CPUTIME_ID));
8959 #elif defined(RUBY_GETRUSAGE_BASED_CLOCK_PROCESS_CPUTIME_ID)
8960 /* see Process.clock_gettime */
8961 rb_define_const(rb_mProcess, "CLOCK_PROCESS_CPUTIME_ID", RUBY_GETRUSAGE_BASED_CLOCK_PROCESS_CPUTIME_ID);
8962 #endif
8963 #ifdef CLOCK_THREAD_CPUTIME_ID
8964 /* see Process.clock_gettime */
8965 rb_define_const(rb_mProcess, "CLOCK_THREAD_CPUTIME_ID", CLOCKID2NUM(CLOCK_THREAD_CPUTIME_ID));
8966 #endif
8967 #ifdef CLOCK_VIRTUAL
8968 /* see Process.clock_gettime */
8969 rb_define_const(rb_mProcess, "CLOCK_VIRTUAL", CLOCKID2NUM(CLOCK_VIRTUAL));
8970 #endif
8971 #ifdef CLOCK_PROF
8972 /* see Process.clock_gettime */
8973 rb_define_const(rb_mProcess, "CLOCK_PROF", CLOCKID2NUM(CLOCK_PROF));
8974 #endif
8975 #ifdef CLOCK_REALTIME_FAST
8976 /* see Process.clock_gettime */
8977 rb_define_const(rb_mProcess, "CLOCK_REALTIME_FAST", CLOCKID2NUM(CLOCK_REALTIME_FAST));
8978 #endif
8979 #ifdef CLOCK_REALTIME_PRECISE
8980 /* see Process.clock_gettime */
8981 rb_define_const(rb_mProcess, "CLOCK_REALTIME_PRECISE", CLOCKID2NUM(CLOCK_REALTIME_PRECISE));
8982 #endif
8983 #ifdef CLOCK_REALTIME_COARSE
8984 /* see Process.clock_gettime */
8985 rb_define_const(rb_mProcess, "CLOCK_REALTIME_COARSE", CLOCKID2NUM(CLOCK_REALTIME_COARSE));
8986 #endif
8987 #ifdef CLOCK_REALTIME_ALARM
8988 /* see Process.clock_gettime */
8989 rb_define_const(rb_mProcess, "CLOCK_REALTIME_ALARM", CLOCKID2NUM(CLOCK_REALTIME_ALARM));
8990 #endif
8991 #ifdef CLOCK_MONOTONIC_FAST
8992 /* see Process.clock_gettime */
8993 rb_define_const(rb_mProcess, "CLOCK_MONOTONIC_FAST", CLOCKID2NUM(CLOCK_MONOTONIC_FAST));
8994 #endif
8995 #ifdef CLOCK_MONOTONIC_PRECISE
8996 /* see Process.clock_gettime */
8997 rb_define_const(rb_mProcess, "CLOCK_MONOTONIC_PRECISE", CLOCKID2NUM(CLOCK_MONOTONIC_PRECISE));
8998 #endif
8999 #ifdef CLOCK_MONOTONIC_RAW
9000 /* see Process.clock_gettime */
9001 rb_define_const(rb_mProcess, "CLOCK_MONOTONIC_RAW", CLOCKID2NUM(CLOCK_MONOTONIC_RAW));
9002 #endif
9003 #ifdef CLOCK_MONOTONIC_RAW_APPROX
9004 /* see Process.clock_gettime */
9005 rb_define_const(rb_mProcess, "CLOCK_MONOTONIC_RAW_APPROX", CLOCKID2NUM(CLOCK_MONOTONIC_RAW_APPROX));
9006 #endif
9007 #ifdef CLOCK_MONOTONIC_COARSE
9008 /* see Process.clock_gettime */
9009 rb_define_const(rb_mProcess, "CLOCK_MONOTONIC_COARSE", CLOCKID2NUM(CLOCK_MONOTONIC_COARSE));
9010 #endif
9011 #ifdef CLOCK_BOOTTIME
9012 /* see Process.clock_gettime */
9013 rb_define_const(rb_mProcess, "CLOCK_BOOTTIME", CLOCKID2NUM(CLOCK_BOOTTIME));
9014 #endif
9015 #ifdef CLOCK_BOOTTIME_ALARM
9016 /* see Process.clock_gettime */
9017 rb_define_const(rb_mProcess, "CLOCK_BOOTTIME_ALARM", CLOCKID2NUM(CLOCK_BOOTTIME_ALARM));
9018 #endif
9019 #ifdef CLOCK_UPTIME
9020 /* see Process.clock_gettime */
9021 rb_define_const(rb_mProcess, "CLOCK_UPTIME", CLOCKID2NUM(CLOCK_UPTIME));
9022 #endif
9023 #ifdef CLOCK_UPTIME_FAST
9024 /* see Process.clock_gettime */
9025 rb_define_const(rb_mProcess, "CLOCK_UPTIME_FAST", CLOCKID2NUM(CLOCK_UPTIME_FAST));
9026 #endif
9027 #ifdef CLOCK_UPTIME_PRECISE
9028 /* see Process.clock_gettime */
9029 rb_define_const(rb_mProcess, "CLOCK_UPTIME_PRECISE", CLOCKID2NUM(CLOCK_UPTIME_PRECISE));
9030 #endif
9031 #ifdef CLOCK_UPTIME_RAW
9032 /* see Process.clock_gettime */
9033 rb_define_const(rb_mProcess, "CLOCK_UPTIME_RAW", CLOCKID2NUM(CLOCK_UPTIME_RAW));
9034 #endif
9035 #ifdef CLOCK_UPTIME_RAW_APPROX
9036 /* see Process.clock_gettime */
9037 rb_define_const(rb_mProcess, "CLOCK_UPTIME_RAW_APPROX", CLOCKID2NUM(CLOCK_UPTIME_RAW_APPROX));
9038 #endif
9039 #ifdef CLOCK_SECOND
9040 /* see Process.clock_gettime */
9041 rb_define_const(rb_mProcess, "CLOCK_SECOND", CLOCKID2NUM(CLOCK_SECOND));
9042 #endif
9043 #ifdef CLOCK_TAI
9044 /* see Process.clock_gettime */
9045 rb_define_const(rb_mProcess, "CLOCK_TAI", CLOCKID2NUM(CLOCK_TAI));
9046 #endif
9047 rb_define_module_function(rb_mProcess, "clock_gettime", rb_clock_gettime, -1);
9048 rb_define_module_function(rb_mProcess, "clock_getres", rb_clock_getres, -1);
9050 #if defined(HAVE_TIMES) || defined(_WIN32)
9051 /* Placeholder for rusage */
9052 rb_cProcessTms = rb_struct_define_under(rb_mProcess, "Tms", "utime", "stime", "cutime", "cstime", NULL);
9053 #endif
9055 SAVED_USER_ID = geteuid();
9056 SAVED_GROUP_ID = getegid();
9058 rb_mProcUID = rb_define_module_under(rb_mProcess, "UID");
9059 rb_mProcGID = rb_define_module_under(rb_mProcess, "GID");
9061 rb_define_module_function(rb_mProcUID, "rid", proc_getuid, 0);
9062 rb_define_module_function(rb_mProcGID, "rid", proc_getgid, 0);
9063 rb_define_module_function(rb_mProcUID, "eid", proc_geteuid, 0);
9064 rb_define_module_function(rb_mProcGID, "eid", proc_getegid, 0);
9065 rb_define_module_function(rb_mProcUID, "change_privilege", p_uid_change_privilege, 1);
9066 rb_define_module_function(rb_mProcGID, "change_privilege", p_gid_change_privilege, 1);
9067 rb_define_module_function(rb_mProcUID, "grant_privilege", p_uid_grant_privilege, 1);
9068 rb_define_module_function(rb_mProcGID, "grant_privilege", p_gid_grant_privilege, 1);
9069 rb_define_alias(rb_singleton_class(rb_mProcUID), "eid=", "grant_privilege");
9070 rb_define_alias(rb_singleton_class(rb_mProcGID), "eid=", "grant_privilege");
9071 rb_define_module_function(rb_mProcUID, "re_exchange", p_uid_exchange, 0);
9072 rb_define_module_function(rb_mProcGID, "re_exchange", p_gid_exchange, 0);
9073 rb_define_module_function(rb_mProcUID, "re_exchangeable?", p_uid_exchangeable, 0);
9074 rb_define_module_function(rb_mProcGID, "re_exchangeable?", p_gid_exchangeable, 0);
9075 rb_define_module_function(rb_mProcUID, "sid_available?", p_uid_have_saved_id, 0);
9076 rb_define_module_function(rb_mProcGID, "sid_available?", p_gid_have_saved_id, 0);
9077 rb_define_module_function(rb_mProcUID, "switch", p_uid_switch, 0);
9078 rb_define_module_function(rb_mProcGID, "switch", p_gid_switch, 0);
9079 #ifdef p_uid_from_name
9080 rb_define_module_function(rb_mProcUID, "from_name", p_uid_from_name, 1);
9081 #endif
9082 #ifdef p_gid_from_name
9083 rb_define_module_function(rb_mProcGID, "from_name", p_gid_from_name, 1);
9084 #endif
9086 rb_mProcID_Syscall = rb_define_module_under(rb_mProcess, "Sys");
9088 rb_define_module_function(rb_mProcID_Syscall, "getuid", proc_getuid, 0);
9089 rb_define_module_function(rb_mProcID_Syscall, "geteuid", proc_geteuid, 0);
9090 rb_define_module_function(rb_mProcID_Syscall, "getgid", proc_getgid, 0);
9091 rb_define_module_function(rb_mProcID_Syscall, "getegid", proc_getegid, 0);
9093 rb_define_module_function(rb_mProcID_Syscall, "setuid", p_sys_setuid, 1);
9094 rb_define_module_function(rb_mProcID_Syscall, "setgid", p_sys_setgid, 1);
9096 rb_define_module_function(rb_mProcID_Syscall, "setruid", p_sys_setruid, 1);
9097 rb_define_module_function(rb_mProcID_Syscall, "setrgid", p_sys_setrgid, 1);
9099 rb_define_module_function(rb_mProcID_Syscall, "seteuid", p_sys_seteuid, 1);
9100 rb_define_module_function(rb_mProcID_Syscall, "setegid", p_sys_setegid, 1);
9102 rb_define_module_function(rb_mProcID_Syscall, "setreuid", p_sys_setreuid, 2);
9103 rb_define_module_function(rb_mProcID_Syscall, "setregid", p_sys_setregid, 2);
9105 rb_define_module_function(rb_mProcID_Syscall, "setresuid", p_sys_setresuid, 3);
9106 rb_define_module_function(rb_mProcID_Syscall, "setresgid", p_sys_setresgid, 3);
9107 rb_define_module_function(rb_mProcID_Syscall, "issetugid", p_sys_issetugid, 0);
9110 void
9111 Init_process(void)
9113 id_in = rb_intern_const("in");
9114 id_out = rb_intern_const("out");
9115 id_err = rb_intern_const("err");
9116 id_pid = rb_intern_const("pid");
9117 id_uid = rb_intern_const("uid");
9118 id_gid = rb_intern_const("gid");
9119 id_close = rb_intern_const("close");
9120 id_child = rb_intern_const("child");
9121 #ifdef HAVE_SETPGID
9122 id_pgroup = rb_intern_const("pgroup");
9123 #endif
9124 #ifdef _WIN32
9125 id_new_pgroup = rb_intern_const("new_pgroup");
9126 #endif
9127 id_unsetenv_others = rb_intern_const("unsetenv_others");
9128 id_chdir = rb_intern_const("chdir");
9129 id_umask = rb_intern_const("umask");
9130 id_close_others = rb_intern_const("close_others");
9131 id_nanosecond = rb_intern_const("nanosecond");
9132 id_microsecond = rb_intern_const("microsecond");
9133 id_millisecond = rb_intern_const("millisecond");
9134 id_second = rb_intern_const("second");
9135 id_float_microsecond = rb_intern_const("float_microsecond");
9136 id_float_millisecond = rb_intern_const("float_millisecond");
9137 id_float_second = rb_intern_const("float_second");
9138 id_GETTIMEOFDAY_BASED_CLOCK_REALTIME = rb_intern_const("GETTIMEOFDAY_BASED_CLOCK_REALTIME");
9139 id_TIME_BASED_CLOCK_REALTIME = rb_intern_const("TIME_BASED_CLOCK_REALTIME");
9140 #ifdef HAVE_TIMES
9141 id_TIMES_BASED_CLOCK_MONOTONIC = rb_intern_const("TIMES_BASED_CLOCK_MONOTONIC");
9142 id_TIMES_BASED_CLOCK_PROCESS_CPUTIME_ID = rb_intern_const("TIMES_BASED_CLOCK_PROCESS_CPUTIME_ID");
9143 #endif
9144 #ifdef RUSAGE_SELF
9145 id_GETRUSAGE_BASED_CLOCK_PROCESS_CPUTIME_ID = rb_intern_const("GETRUSAGE_BASED_CLOCK_PROCESS_CPUTIME_ID");
9146 #endif
9147 id_CLOCK_BASED_CLOCK_PROCESS_CPUTIME_ID = rb_intern_const("CLOCK_BASED_CLOCK_PROCESS_CPUTIME_ID");
9148 #ifdef __APPLE__
9149 id_MACH_ABSOLUTE_TIME_BASED_CLOCK_MONOTONIC = rb_intern_const("MACH_ABSOLUTE_TIME_BASED_CLOCK_MONOTONIC");
9150 #endif
9151 id_hertz = rb_intern_const("hertz");
9153 InitVM(process);