* 2022-01-18 [ci skip]
[ruby-80x24.org.git] / process.c
blob11031d2c7d21c5eec9329c10b8ad9a374a26cbf3
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 return RBOOL(issetugid());
6728 #else
6729 #define p_sys_issetugid rb_f_notimplement
6730 #endif
6734 * call-seq:
6735 * Process.gid -> integer
6736 * Process::GID.rid -> integer
6737 * Process::Sys.getgid -> integer
6739 * Returns the (real) group ID for this process.
6741 * Process.gid #=> 500
6744 static VALUE
6745 proc_getgid(VALUE obj)
6747 rb_gid_t gid = getgid();
6748 return GIDT2NUM(gid);
6752 #if defined(HAVE_SETRESGID) || defined(HAVE_SETREGID) || defined(HAVE_SETRGID) || defined(HAVE_SETGID)
6754 * call-seq:
6755 * Process.gid= integer -> integer
6757 * Sets the group ID for this process.
6760 static VALUE
6761 proc_setgid(VALUE obj, VALUE id)
6763 rb_gid_t gid;
6765 check_gid_switch();
6767 gid = OBJ2GID(id);
6768 #if defined(HAVE_SETRESGID)
6769 if (setresgid(gid, -1, -1) < 0) rb_sys_fail(0);
6770 #elif defined HAVE_SETREGID
6771 if (setregid(gid, -1) < 0) rb_sys_fail(0);
6772 #elif defined HAVE_SETRGID
6773 if (setrgid(gid) < 0) rb_sys_fail(0);
6774 #elif defined HAVE_SETGID
6776 if (getegid() == gid) {
6777 if (setgid(gid) < 0) rb_sys_fail(0);
6779 else {
6780 rb_notimplement();
6783 #endif
6784 return GIDT2NUM(gid);
6786 #else
6787 #define proc_setgid rb_f_notimplement
6788 #endif
6791 #if defined(_SC_NGROUPS_MAX) || defined(NGROUPS_MAX)
6793 * Maximum supplementary groups are platform dependent.
6794 * FWIW, 65536 is enough big for our supported OSs.
6796 * OS Name max groups
6797 * -----------------------------------------------
6798 * Linux Kernel >= 2.6.3 65536
6799 * Linux Kernel < 2.6.3 32
6800 * IBM AIX 5.2 64
6801 * IBM AIX 5.3 ... 6.1 128
6802 * IBM AIX 7.1 128 (can be configured to be up to 2048)
6803 * OpenBSD, NetBSD 16
6804 * FreeBSD < 8.0 16
6805 * FreeBSD >=8.0 1023
6806 * Darwin (Mac OS X) 16
6807 * Sun Solaris 7,8,9,10 16
6808 * Sun Solaris 11 / OpenSolaris 1024
6809 * HP-UX 20
6810 * Windows 1015
6812 static int _maxgroups = -1;
6813 static int
6814 get_sc_ngroups_max(void)
6816 #ifdef _SC_NGROUPS_MAX
6817 return (int)sysconf(_SC_NGROUPS_MAX);
6818 #elif defined(NGROUPS_MAX)
6819 return (int)NGROUPS_MAX;
6820 #else
6821 return -1;
6822 #endif
6824 static int
6825 maxgroups(void)
6827 if (_maxgroups < 0) {
6828 _maxgroups = get_sc_ngroups_max();
6829 if (_maxgroups < 0)
6830 _maxgroups = RB_MAX_GROUPS;
6833 return _maxgroups;
6835 #endif
6839 #ifdef HAVE_GETGROUPS
6841 * call-seq:
6842 * Process.groups -> array
6844 * Get an Array of the group IDs in the
6845 * supplemental group access list for this process.
6847 * Process.groups #=> [27, 6, 10, 11]
6849 * Note that this method is just a wrapper of getgroups(2).
6850 * This means that the following characteristics of
6851 * the result completely depend on your system:
6853 * - the result is sorted
6854 * - the result includes effective GIDs
6855 * - the result does not include duplicated GIDs
6857 * You can make sure to get a sorted unique GID list of
6858 * the current process by this expression:
6860 * Process.groups.uniq.sort
6864 static VALUE
6865 proc_getgroups(VALUE obj)
6867 VALUE ary, tmp;
6868 int i, ngroups;
6869 rb_gid_t *groups;
6871 ngroups = getgroups(0, NULL);
6872 if (ngroups == -1)
6873 rb_sys_fail(0);
6875 groups = ALLOCV_N(rb_gid_t, tmp, ngroups);
6877 ngroups = getgroups(ngroups, groups);
6878 if (ngroups == -1)
6879 rb_sys_fail(0);
6881 ary = rb_ary_new();
6882 for (i = 0; i < ngroups; i++)
6883 rb_ary_push(ary, GIDT2NUM(groups[i]));
6885 ALLOCV_END(tmp);
6887 return ary;
6889 #else
6890 #define proc_getgroups rb_f_notimplement
6891 #endif
6894 #ifdef HAVE_SETGROUPS
6896 * call-seq:
6897 * Process.groups= array -> array
6899 * Set the supplemental group access list to the given
6900 * Array of group IDs.
6902 * Process.groups #=> [0, 1, 2, 3, 4, 6, 10, 11, 20, 26, 27]
6903 * Process.groups = [27, 6, 10, 11] #=> [27, 6, 10, 11]
6904 * Process.groups #=> [27, 6, 10, 11]
6908 static VALUE
6909 proc_setgroups(VALUE obj, VALUE ary)
6911 int ngroups, i;
6912 rb_gid_t *groups;
6913 VALUE tmp;
6914 PREPARE_GETGRNAM;
6916 Check_Type(ary, T_ARRAY);
6918 ngroups = RARRAY_LENINT(ary);
6919 if (ngroups > maxgroups())
6920 rb_raise(rb_eArgError, "too many groups, %d max", maxgroups());
6922 groups = ALLOCV_N(rb_gid_t, tmp, ngroups);
6924 for (i = 0; i < ngroups; i++) {
6925 VALUE g = RARRAY_AREF(ary, i);
6927 groups[i] = OBJ2GID1(g);
6929 FINISH_GETGRNAM;
6931 if (setgroups(ngroups, groups) == -1) /* ngroups <= maxgroups */
6932 rb_sys_fail(0);
6934 ALLOCV_END(tmp);
6936 return proc_getgroups(obj);
6938 #else
6939 #define proc_setgroups rb_f_notimplement
6940 #endif
6943 #ifdef HAVE_INITGROUPS
6945 * call-seq:
6946 * Process.initgroups(username, gid) -> array
6948 * Initializes the supplemental group access list by reading the
6949 * system group database and using all groups of which the given user
6950 * is a member. The group with the specified <em>gid</em> is also
6951 * added to the list. Returns the resulting Array of the
6952 * gids of all the groups in the supplementary group access list. Not
6953 * available on all platforms.
6955 * Process.groups #=> [0, 1, 2, 3, 4, 6, 10, 11, 20, 26, 27]
6956 * Process.initgroups( "mgranger", 30 ) #=> [30, 6, 10, 11]
6957 * Process.groups #=> [30, 6, 10, 11]
6961 static VALUE
6962 proc_initgroups(VALUE obj, VALUE uname, VALUE base_grp)
6964 if (initgroups(StringValueCStr(uname), OBJ2GID(base_grp)) != 0) {
6965 rb_sys_fail(0);
6967 return proc_getgroups(obj);
6969 #else
6970 #define proc_initgroups rb_f_notimplement
6971 #endif
6973 #if defined(_SC_NGROUPS_MAX) || defined(NGROUPS_MAX)
6975 * call-seq:
6976 * Process.maxgroups -> integer
6978 * Returns the maximum number of gids allowed in the supplemental
6979 * group access list.
6981 * Process.maxgroups #=> 32
6984 static VALUE
6985 proc_getmaxgroups(VALUE obj)
6987 return INT2FIX(maxgroups());
6989 #else
6990 #define proc_getmaxgroups rb_f_notimplement
6991 #endif
6993 #ifdef HAVE_SETGROUPS
6995 * call-seq:
6996 * Process.maxgroups= integer -> integer
6998 * Sets the maximum number of gids allowed in the supplemental group
6999 * access list.
7002 static VALUE
7003 proc_setmaxgroups(VALUE obj, VALUE val)
7005 int ngroups = FIX2INT(val);
7006 int ngroups_max = get_sc_ngroups_max();
7008 if (ngroups <= 0)
7009 rb_raise(rb_eArgError, "maxgroups %d should be positive", ngroups);
7011 if (ngroups > RB_MAX_GROUPS)
7012 ngroups = RB_MAX_GROUPS;
7014 if (ngroups_max > 0 && ngroups > ngroups_max)
7015 ngroups = ngroups_max;
7017 _maxgroups = ngroups;
7019 return INT2FIX(_maxgroups);
7021 #else
7022 #define proc_setmaxgroups rb_f_notimplement
7023 #endif
7025 #if defined(HAVE_DAEMON) || (defined(HAVE_WORKING_FORK) && defined(HAVE_SETSID))
7026 static int rb_daemon(int nochdir, int noclose);
7029 * call-seq:
7030 * Process.daemon() -> 0
7031 * Process.daemon(nochdir=nil,noclose=nil) -> 0
7033 * Detach the process from controlling terminal and run in
7034 * the background as system daemon. Unless the argument
7035 * nochdir is true (i.e. non false), it changes the current
7036 * working directory to the root ("/"). Unless the argument
7037 * noclose is true, daemon() will redirect standard input,
7038 * standard output and standard error to /dev/null.
7039 * Return zero on success, or raise one of Errno::*.
7042 static VALUE
7043 proc_daemon(int argc, VALUE *argv, VALUE _)
7045 int n, nochdir = FALSE, noclose = FALSE;
7047 switch (rb_check_arity(argc, 0, 2)) {
7048 case 2: noclose = TO_BOOL(argv[1], "noclose");
7049 case 1: nochdir = TO_BOOL(argv[0], "nochdir");
7052 prefork();
7053 n = rb_daemon(nochdir, noclose);
7054 if (n < 0) rb_sys_fail("daemon");
7055 return INT2FIX(n);
7058 static int
7059 rb_daemon(int nochdir, int noclose)
7061 int err = 0;
7062 #ifdef HAVE_DAEMON
7063 if (mjit_enabled) mjit_pause(false); // Don't leave locked mutex to child.
7064 before_fork_ruby();
7065 err = daemon(nochdir, noclose);
7066 after_fork_ruby();
7067 rb_thread_atfork(); /* calls mjit_resume() */
7068 #else
7069 int n;
7071 #define fork_daemon() \
7072 switch (rb_fork_ruby(NULL)) { \
7073 case -1: return -1; \
7074 case 0: break; \
7075 default: _exit(EXIT_SUCCESS); \
7078 fork_daemon();
7080 if (setsid() < 0) return -1;
7082 /* must not be process-leader */
7083 fork_daemon();
7085 if (!nochdir)
7086 err = chdir("/");
7088 if (!noclose && (n = rb_cloexec_open("/dev/null", O_RDWR, 0)) != -1) {
7089 rb_update_max_fd(n);
7090 (void)dup2(n, 0);
7091 (void)dup2(n, 1);
7092 (void)dup2(n, 2);
7093 if (n > 2)
7094 (void)close (n);
7096 #endif
7097 return err;
7099 #else
7100 #define proc_daemon rb_f_notimplement
7101 #endif
7103 /********************************************************************
7105 * Document-class: Process::GID
7107 * The Process::GID module contains a collection of
7108 * module functions which can be used to portably get, set, and
7109 * switch the current process's real, effective, and saved group IDs.
7113 static rb_gid_t SAVED_GROUP_ID = -1;
7115 #ifdef BROKEN_SETREGID
7117 setregid(rb_gid_t rgid, rb_gid_t egid)
7119 if (rgid != (rb_gid_t)-1 && rgid != getgid()) {
7120 if (egid == (rb_gid_t)-1) egid = getegid();
7121 if (setgid(rgid) < 0) return -1;
7123 if (egid != (rb_gid_t)-1 && egid != getegid()) {
7124 if (setegid(egid) < 0) return -1;
7126 return 0;
7128 #endif
7131 * call-seq:
7132 * Process::GID.change_privilege(group) -> integer
7134 * Change the current process's real and effective group ID to that
7135 * specified by _group_. Returns the new group ID. Not
7136 * available on all platforms.
7138 * [Process.gid, Process.egid] #=> [0, 0]
7139 * Process::GID.change_privilege(33) #=> 33
7140 * [Process.gid, Process.egid] #=> [33, 33]
7143 static VALUE
7144 p_gid_change_privilege(VALUE obj, VALUE id)
7146 rb_gid_t gid;
7148 check_gid_switch();
7150 gid = OBJ2GID(id);
7152 if (geteuid() == 0) { /* root-user */
7153 #if defined(HAVE_SETRESGID)
7154 if (setresgid(gid, gid, gid) < 0) rb_sys_fail(0);
7155 SAVED_GROUP_ID = gid;
7156 #elif defined HAVE_SETGID
7157 if (setgid(gid) < 0) rb_sys_fail(0);
7158 SAVED_GROUP_ID = gid;
7159 #elif defined(HAVE_SETREGID) && !defined(OBSOLETE_SETREGID)
7160 if (getgid() == gid) {
7161 if (SAVED_GROUP_ID == gid) {
7162 if (setregid(-1, gid) < 0) rb_sys_fail(0);
7164 else {
7165 if (gid == 0) { /* (r,e,s) == (root, y, x) */
7166 if (setregid(-1, SAVED_GROUP_ID) < 0) rb_sys_fail(0);
7167 if (setregid(SAVED_GROUP_ID, 0) < 0) rb_sys_fail(0);
7168 SAVED_GROUP_ID = 0; /* (r,e,s) == (x, root, root) */
7169 if (setregid(gid, gid) < 0) rb_sys_fail(0);
7170 SAVED_GROUP_ID = gid;
7172 else { /* (r,e,s) == (z, y, x) */
7173 if (setregid(0, 0) < 0) rb_sys_fail(0);
7174 SAVED_GROUP_ID = 0;
7175 if (setregid(gid, gid) < 0) rb_sys_fail(0);
7176 SAVED_GROUP_ID = gid;
7180 else {
7181 if (setregid(gid, gid) < 0) rb_sys_fail(0);
7182 SAVED_GROUP_ID = gid;
7184 #elif defined(HAVE_SETRGID) && defined (HAVE_SETEGID)
7185 if (getgid() == gid) {
7186 if (SAVED_GROUP_ID == gid) {
7187 if (setegid(gid) < 0) rb_sys_fail(0);
7189 else {
7190 if (gid == 0) {
7191 if (setegid(gid) < 0) rb_sys_fail(0);
7192 if (setrgid(SAVED_GROUP_ID) < 0) rb_sys_fail(0);
7193 SAVED_GROUP_ID = 0;
7194 if (setrgid(0) < 0) rb_sys_fail(0);
7196 else {
7197 if (setrgid(0) < 0) rb_sys_fail(0);
7198 SAVED_GROUP_ID = 0;
7199 if (setegid(gid) < 0) rb_sys_fail(0);
7200 if (setrgid(gid) < 0) rb_sys_fail(0);
7201 SAVED_GROUP_ID = gid;
7205 else {
7206 if (setegid(gid) < 0) rb_sys_fail(0);
7207 if (setrgid(gid) < 0) rb_sys_fail(0);
7208 SAVED_GROUP_ID = gid;
7210 #else
7211 rb_notimplement();
7212 #endif
7214 else { /* unprivileged user */
7215 #if defined(HAVE_SETRESGID)
7216 if (setresgid((getgid() == gid)? (rb_gid_t)-1: gid,
7217 (getegid() == gid)? (rb_gid_t)-1: gid,
7218 (SAVED_GROUP_ID == gid)? (rb_gid_t)-1: gid) < 0) rb_sys_fail(0);
7219 SAVED_GROUP_ID = gid;
7220 #elif defined(HAVE_SETREGID) && !defined(OBSOLETE_SETREGID)
7221 if (SAVED_GROUP_ID == gid) {
7222 if (setregid((getgid() == gid)? (rb_uid_t)-1: gid,
7223 (getegid() == gid)? (rb_uid_t)-1: gid) < 0)
7224 rb_sys_fail(0);
7226 else if (getgid() != gid) {
7227 if (setregid(gid, (getegid() == gid)? (rb_uid_t)-1: gid) < 0)
7228 rb_sys_fail(0);
7229 SAVED_GROUP_ID = gid;
7231 else if (/* getgid() == gid && */ getegid() != gid) {
7232 if (setregid(getegid(), gid) < 0) rb_sys_fail(0);
7233 SAVED_GROUP_ID = gid;
7234 if (setregid(gid, -1) < 0) rb_sys_fail(0);
7236 else { /* getgid() == gid && getegid() == gid */
7237 if (setregid(-1, SAVED_GROUP_ID) < 0) rb_sys_fail(0);
7238 if (setregid(SAVED_GROUP_ID, gid) < 0) rb_sys_fail(0);
7239 SAVED_GROUP_ID = gid;
7240 if (setregid(gid, -1) < 0) rb_sys_fail(0);
7242 #elif defined(HAVE_SETRGID) && defined(HAVE_SETEGID)
7243 if (SAVED_GROUP_ID == gid) {
7244 if (getegid() != gid && setegid(gid) < 0) rb_sys_fail(0);
7245 if (getgid() != gid && setrgid(gid) < 0) rb_sys_fail(0);
7247 else if (/* SAVED_GROUP_ID != gid && */ getegid() == gid) {
7248 if (getgid() != gid) {
7249 if (setrgid(gid) < 0) rb_sys_fail(0);
7250 SAVED_GROUP_ID = gid;
7252 else {
7253 if (setrgid(SAVED_GROUP_ID) < 0) rb_sys_fail(0);
7254 SAVED_GROUP_ID = gid;
7255 if (setrgid(gid) < 0) rb_sys_fail(0);
7258 else if (/* getegid() != gid && */ getgid() == gid) {
7259 if (setegid(gid) < 0) rb_sys_fail(0);
7260 if (setrgid(SAVED_GROUP_ID) < 0) rb_sys_fail(0);
7261 SAVED_GROUP_ID = gid;
7262 if (setrgid(gid) < 0) rb_sys_fail(0);
7264 else {
7265 rb_syserr_fail(EPERM, 0);
7267 #elif defined HAVE_44BSD_SETGID
7268 if (getgid() == gid) {
7269 /* (r,e,s)==(gid,?,?) ==> (gid,gid,gid) */
7270 if (setgid(gid) < 0) rb_sys_fail(0);
7271 SAVED_GROUP_ID = gid;
7273 else {
7274 rb_syserr_fail(EPERM, 0);
7276 #elif defined HAVE_SETEGID
7277 if (getgid() == gid && SAVED_GROUP_ID == gid) {
7278 if (setegid(gid) < 0) rb_sys_fail(0);
7280 else {
7281 rb_syserr_fail(EPERM, 0);
7283 #elif defined HAVE_SETGID
7284 if (getgid() == gid && SAVED_GROUP_ID == gid) {
7285 if (setgid(gid) < 0) rb_sys_fail(0);
7287 else {
7288 rb_syserr_fail(EPERM, 0);
7290 #else
7291 (void)gid;
7292 rb_notimplement();
7293 #endif
7295 return id;
7300 * call-seq:
7301 * Process.euid -> integer
7302 * Process::UID.eid -> integer
7303 * Process::Sys.geteuid -> integer
7305 * Returns the effective user ID for this process.
7307 * Process.euid #=> 501
7310 static VALUE
7311 proc_geteuid(VALUE obj)
7313 rb_uid_t euid = geteuid();
7314 return UIDT2NUM(euid);
7317 #if defined(HAVE_SETRESUID) || defined(HAVE_SETREUID) || defined(HAVE_SETEUID) || defined(HAVE_SETUID) || defined(_POSIX_SAVED_IDS)
7318 static void
7319 proc_seteuid(rb_uid_t uid)
7321 #if defined(HAVE_SETRESUID)
7322 if (setresuid(-1, uid, -1) < 0) rb_sys_fail(0);
7323 #elif defined HAVE_SETREUID
7324 if (setreuid(-1, uid) < 0) rb_sys_fail(0);
7325 #elif defined HAVE_SETEUID
7326 if (seteuid(uid) < 0) rb_sys_fail(0);
7327 #elif defined HAVE_SETUID
7328 if (uid == getuid()) {
7329 if (setuid(uid) < 0) rb_sys_fail(0);
7331 else {
7332 rb_notimplement();
7334 #else
7335 rb_notimplement();
7336 #endif
7338 #endif
7340 #if defined(HAVE_SETRESUID) || defined(HAVE_SETREUID) || defined(HAVE_SETEUID) || defined(HAVE_SETUID)
7342 * call-seq:
7343 * Process.euid= user
7345 * Sets the effective user ID for this process. Not available on all
7346 * platforms.
7349 static VALUE
7350 proc_seteuid_m(VALUE mod, VALUE euid)
7352 check_uid_switch();
7353 proc_seteuid(OBJ2UID(euid));
7354 return euid;
7356 #else
7357 #define proc_seteuid_m rb_f_notimplement
7358 #endif
7360 static rb_uid_t
7361 rb_seteuid_core(rb_uid_t euid)
7363 #if defined(HAVE_SETRESUID) || (defined(HAVE_SETREUID) && !defined(OBSOLETE_SETREUID))
7364 rb_uid_t uid;
7365 #endif
7367 check_uid_switch();
7369 #if defined(HAVE_SETRESUID) || (defined(HAVE_SETREUID) && !defined(OBSOLETE_SETREUID))
7370 uid = getuid();
7371 #endif
7373 #if defined(HAVE_SETRESUID)
7374 if (uid != euid) {
7375 if (setresuid(-1,euid,euid) < 0) rb_sys_fail(0);
7376 SAVED_USER_ID = euid;
7378 else {
7379 if (setresuid(-1,euid,-1) < 0) rb_sys_fail(0);
7381 #elif defined(HAVE_SETREUID) && !defined(OBSOLETE_SETREUID)
7382 if (setreuid(-1, euid) < 0) rb_sys_fail(0);
7383 if (uid != euid) {
7384 if (setreuid(euid,uid) < 0) rb_sys_fail(0);
7385 if (setreuid(uid,euid) < 0) rb_sys_fail(0);
7386 SAVED_USER_ID = euid;
7388 #elif defined HAVE_SETEUID
7389 if (seteuid(euid) < 0) rb_sys_fail(0);
7390 #elif defined HAVE_SETUID
7391 if (geteuid() == 0) rb_sys_fail(0);
7392 if (setuid(euid) < 0) rb_sys_fail(0);
7393 #else
7394 rb_notimplement();
7395 #endif
7396 return euid;
7401 * call-seq:
7402 * Process::UID.grant_privilege(user) -> integer
7403 * Process::UID.eid= user -> integer
7405 * Set the effective user ID, and if possible, the saved user ID of
7406 * the process to the given _user_. Returns the new
7407 * effective user ID. Not available on all platforms.
7409 * [Process.uid, Process.euid] #=> [0, 0]
7410 * Process::UID.grant_privilege(31) #=> 31
7411 * [Process.uid, Process.euid] #=> [0, 31]
7414 static VALUE
7415 p_uid_grant_privilege(VALUE obj, VALUE id)
7417 rb_seteuid_core(OBJ2UID(id));
7418 return id;
7423 * call-seq:
7424 * Process.egid -> integer
7425 * Process::GID.eid -> integer
7426 * Process::Sys.geteid -> integer
7428 * Returns the effective group ID for this process. Not available on
7429 * all platforms.
7431 * Process.egid #=> 500
7434 static VALUE
7435 proc_getegid(VALUE obj)
7437 rb_gid_t egid = getegid();
7439 return GIDT2NUM(egid);
7442 #if defined(HAVE_SETRESGID) || defined(HAVE_SETREGID) || defined(HAVE_SETEGID) || defined(HAVE_SETGID) || defined(_POSIX_SAVED_IDS)
7444 * call-seq:
7445 * Process.egid = integer -> integer
7447 * Sets the effective group ID for this process. Not available on all
7448 * platforms.
7451 static VALUE
7452 proc_setegid(VALUE obj, VALUE egid)
7454 #if defined(HAVE_SETRESGID) || defined(HAVE_SETREGID) || defined(HAVE_SETEGID) || defined(HAVE_SETGID)
7455 rb_gid_t gid;
7456 #endif
7458 check_gid_switch();
7460 #if defined(HAVE_SETRESGID) || defined(HAVE_SETREGID) || defined(HAVE_SETEGID) || defined(HAVE_SETGID)
7461 gid = OBJ2GID(egid);
7462 #endif
7464 #if defined(HAVE_SETRESGID)
7465 if (setresgid(-1, gid, -1) < 0) rb_sys_fail(0);
7466 #elif defined HAVE_SETREGID
7467 if (setregid(-1, gid) < 0) rb_sys_fail(0);
7468 #elif defined HAVE_SETEGID
7469 if (setegid(gid) < 0) rb_sys_fail(0);
7470 #elif defined HAVE_SETGID
7471 if (gid == getgid()) {
7472 if (setgid(gid) < 0) rb_sys_fail(0);
7474 else {
7475 rb_notimplement();
7477 #else
7478 rb_notimplement();
7479 #endif
7480 return egid;
7482 #endif
7484 #if defined(HAVE_SETRESGID) || defined(HAVE_SETREGID) || defined(HAVE_SETEGID) || defined(HAVE_SETGID)
7485 #define proc_setegid_m proc_setegid
7486 #else
7487 #define proc_setegid_m rb_f_notimplement
7488 #endif
7490 static rb_gid_t
7491 rb_setegid_core(rb_gid_t egid)
7493 #if defined(HAVE_SETRESGID) || (defined(HAVE_SETREGID) && !defined(OBSOLETE_SETREGID))
7494 rb_gid_t gid;
7495 #endif
7497 check_gid_switch();
7499 #if defined(HAVE_SETRESGID) || (defined(HAVE_SETREGID) && !defined(OBSOLETE_SETREGID))
7500 gid = getgid();
7501 #endif
7503 #if defined(HAVE_SETRESGID)
7504 if (gid != egid) {
7505 if (setresgid(-1,egid,egid) < 0) rb_sys_fail(0);
7506 SAVED_GROUP_ID = egid;
7508 else {
7509 if (setresgid(-1,egid,-1) < 0) rb_sys_fail(0);
7511 #elif defined(HAVE_SETREGID) && !defined(OBSOLETE_SETREGID)
7512 if (setregid(-1, egid) < 0) rb_sys_fail(0);
7513 if (gid != egid) {
7514 if (setregid(egid,gid) < 0) rb_sys_fail(0);
7515 if (setregid(gid,egid) < 0) rb_sys_fail(0);
7516 SAVED_GROUP_ID = egid;
7518 #elif defined HAVE_SETEGID
7519 if (setegid(egid) < 0) rb_sys_fail(0);
7520 #elif defined HAVE_SETGID
7521 if (geteuid() == 0 /* root user */) rb_sys_fail(0);
7522 if (setgid(egid) < 0) rb_sys_fail(0);
7523 #else
7524 rb_notimplement();
7525 #endif
7526 return egid;
7531 * call-seq:
7532 * Process::GID.grant_privilege(group) -> integer
7533 * Process::GID.eid = group -> integer
7535 * Set the effective group ID, and if possible, the saved group ID of
7536 * the process to the given _group_. Returns the new
7537 * effective group ID. Not available on all platforms.
7539 * [Process.gid, Process.egid] #=> [0, 0]
7540 * Process::GID.grant_privilege(31) #=> 33
7541 * [Process.gid, Process.egid] #=> [0, 33]
7544 static VALUE
7545 p_gid_grant_privilege(VALUE obj, VALUE id)
7547 rb_setegid_core(OBJ2GID(id));
7548 return id;
7553 * call-seq:
7554 * Process::UID.re_exchangeable? -> true or false
7556 * Returns +true+ if the real and effective user IDs of a
7557 * process may be exchanged on the current platform.
7561 static VALUE
7562 p_uid_exchangeable(VALUE _)
7564 #if defined(HAVE_SETRESUID)
7565 return Qtrue;
7566 #elif defined(HAVE_SETREUID) && !defined(OBSOLETE_SETREUID)
7567 return Qtrue;
7568 #else
7569 return Qfalse;
7570 #endif
7575 * call-seq:
7576 * Process::UID.re_exchange -> integer
7578 * Exchange real and effective user IDs and return the new effective
7579 * user ID. Not available on all platforms.
7581 * [Process.uid, Process.euid] #=> [0, 31]
7582 * Process::UID.re_exchange #=> 0
7583 * [Process.uid, Process.euid] #=> [31, 0]
7586 static VALUE
7587 p_uid_exchange(VALUE obj)
7589 rb_uid_t uid;
7590 #if defined(HAVE_SETRESUID) || (defined(HAVE_SETREUID) && !defined(OBSOLETE_SETREUID))
7591 rb_uid_t euid;
7592 #endif
7594 check_uid_switch();
7596 uid = getuid();
7597 #if defined(HAVE_SETRESUID) || (defined(HAVE_SETREUID) && !defined(OBSOLETE_SETREUID))
7598 euid = geteuid();
7599 #endif
7601 #if defined(HAVE_SETRESUID)
7602 if (setresuid(euid, uid, uid) < 0) rb_sys_fail(0);
7603 SAVED_USER_ID = uid;
7604 #elif defined(HAVE_SETREUID) && !defined(OBSOLETE_SETREUID)
7605 if (setreuid(euid,uid) < 0) rb_sys_fail(0);
7606 SAVED_USER_ID = uid;
7607 #else
7608 rb_notimplement();
7609 #endif
7610 return UIDT2NUM(uid);
7615 * call-seq:
7616 * Process::GID.re_exchangeable? -> true or false
7618 * Returns +true+ if the real and effective group IDs of a
7619 * process may be exchanged on the current platform.
7623 static VALUE
7624 p_gid_exchangeable(VALUE _)
7626 #if defined(HAVE_SETRESGID)
7627 return Qtrue;
7628 #elif defined(HAVE_SETREGID) && !defined(OBSOLETE_SETREGID)
7629 return Qtrue;
7630 #else
7631 return Qfalse;
7632 #endif
7637 * call-seq:
7638 * Process::GID.re_exchange -> integer
7640 * Exchange real and effective group IDs and return the new effective
7641 * group ID. Not available on all platforms.
7643 * [Process.gid, Process.egid] #=> [0, 33]
7644 * Process::GID.re_exchange #=> 0
7645 * [Process.gid, Process.egid] #=> [33, 0]
7648 static VALUE
7649 p_gid_exchange(VALUE obj)
7651 rb_gid_t gid;
7652 #if defined(HAVE_SETRESGID) || (defined(HAVE_SETREGID) && !defined(OBSOLETE_SETREGID))
7653 rb_gid_t egid;
7654 #endif
7656 check_gid_switch();
7658 gid = getgid();
7659 #if defined(HAVE_SETRESGID) || (defined(HAVE_SETREGID) && !defined(OBSOLETE_SETREGID))
7660 egid = getegid();
7661 #endif
7663 #if defined(HAVE_SETRESGID)
7664 if (setresgid(egid, gid, gid) < 0) rb_sys_fail(0);
7665 SAVED_GROUP_ID = gid;
7666 #elif defined(HAVE_SETREGID) && !defined(OBSOLETE_SETREGID)
7667 if (setregid(egid,gid) < 0) rb_sys_fail(0);
7668 SAVED_GROUP_ID = gid;
7669 #else
7670 rb_notimplement();
7671 #endif
7672 return GIDT2NUM(gid);
7675 /* [MG] :FIXME: Is this correct? I'm not sure how to phrase this. */
7678 * call-seq:
7679 * Process::UID.sid_available? -> true or false
7681 * Returns +true+ if the current platform has saved user
7682 * ID functionality.
7686 static VALUE
7687 p_uid_have_saved_id(VALUE _)
7689 #if defined(HAVE_SETRESUID) || defined(HAVE_SETEUID) || defined(_POSIX_SAVED_IDS)
7690 return Qtrue;
7691 #else
7692 return Qfalse;
7693 #endif
7697 #if defined(HAVE_SETRESUID) || defined(HAVE_SETEUID) || defined(_POSIX_SAVED_IDS)
7698 static VALUE
7699 p_uid_sw_ensure(VALUE i)
7701 rb_uid_t id = (rb_uid_t/* narrowing */)i;
7702 under_uid_switch = 0;
7703 id = rb_seteuid_core(id);
7704 return UIDT2NUM(id);
7709 * call-seq:
7710 * Process::UID.switch -> integer
7711 * Process::UID.switch {|| block} -> object
7713 * Switch the effective and real user IDs of the current process. If
7714 * a <em>block</em> is given, the user IDs will be switched back
7715 * after the block is executed. Returns the new effective user ID if
7716 * called without a block, and the return value of the block if one
7717 * is given.
7721 static VALUE
7722 p_uid_switch(VALUE obj)
7724 rb_uid_t uid, euid;
7726 check_uid_switch();
7728 uid = getuid();
7729 euid = geteuid();
7731 if (uid != euid) {
7732 proc_seteuid(uid);
7733 if (rb_block_given_p()) {
7734 under_uid_switch = 1;
7735 return rb_ensure(rb_yield, Qnil, p_uid_sw_ensure, SAVED_USER_ID);
7737 else {
7738 return UIDT2NUM(euid);
7741 else if (euid != SAVED_USER_ID) {
7742 proc_seteuid(SAVED_USER_ID);
7743 if (rb_block_given_p()) {
7744 under_uid_switch = 1;
7745 return rb_ensure(rb_yield, Qnil, p_uid_sw_ensure, euid);
7747 else {
7748 return UIDT2NUM(uid);
7751 else {
7752 rb_syserr_fail(EPERM, 0);
7755 UNREACHABLE_RETURN(Qnil);
7757 #else
7758 static VALUE
7759 p_uid_sw_ensure(VALUE obj)
7761 under_uid_switch = 0;
7762 return p_uid_exchange(obj);
7765 static VALUE
7766 p_uid_switch(VALUE obj)
7768 rb_uid_t uid, euid;
7770 check_uid_switch();
7772 uid = getuid();
7773 euid = geteuid();
7775 if (uid == euid) {
7776 rb_syserr_fail(EPERM, 0);
7778 p_uid_exchange(obj);
7779 if (rb_block_given_p()) {
7780 under_uid_switch = 1;
7781 return rb_ensure(rb_yield, Qnil, p_uid_sw_ensure, obj);
7783 else {
7784 return UIDT2NUM(euid);
7787 #endif
7790 /* [MG] :FIXME: Is this correct? I'm not sure how to phrase this. */
7793 * call-seq:
7794 * Process::GID.sid_available? -> true or false
7796 * Returns +true+ if the current platform has saved group
7797 * ID functionality.
7801 static VALUE
7802 p_gid_have_saved_id(VALUE _)
7804 #if defined(HAVE_SETRESGID) || defined(HAVE_SETEGID) || defined(_POSIX_SAVED_IDS)
7805 return Qtrue;
7806 #else
7807 return Qfalse;
7808 #endif
7811 #if defined(HAVE_SETRESGID) || defined(HAVE_SETEGID) || defined(_POSIX_SAVED_IDS)
7812 static VALUE
7813 p_gid_sw_ensure(VALUE i)
7815 rb_gid_t id = (rb_gid_t/* narrowing */)i;
7816 under_gid_switch = 0;
7817 id = rb_setegid_core(id);
7818 return GIDT2NUM(id);
7823 * call-seq:
7824 * Process::GID.switch -> integer
7825 * Process::GID.switch {|| block} -> object
7827 * Switch the effective and real group IDs of the current process. If
7828 * a <em>block</em> is given, the group IDs will be switched back
7829 * after the block is executed. Returns the new effective group ID if
7830 * called without a block, and the return value of the block if one
7831 * is given.
7835 static VALUE
7836 p_gid_switch(VALUE obj)
7838 rb_gid_t gid, egid;
7840 check_gid_switch();
7842 gid = getgid();
7843 egid = getegid();
7845 if (gid != egid) {
7846 proc_setegid(obj, GIDT2NUM(gid));
7847 if (rb_block_given_p()) {
7848 under_gid_switch = 1;
7849 return rb_ensure(rb_yield, Qnil, p_gid_sw_ensure, SAVED_GROUP_ID);
7851 else {
7852 return GIDT2NUM(egid);
7855 else if (egid != SAVED_GROUP_ID) {
7856 proc_setegid(obj, GIDT2NUM(SAVED_GROUP_ID));
7857 if (rb_block_given_p()) {
7858 under_gid_switch = 1;
7859 return rb_ensure(rb_yield, Qnil, p_gid_sw_ensure, egid);
7861 else {
7862 return GIDT2NUM(gid);
7865 else {
7866 rb_syserr_fail(EPERM, 0);
7869 UNREACHABLE_RETURN(Qnil);
7871 #else
7872 static VALUE
7873 p_gid_sw_ensure(VALUE obj)
7875 under_gid_switch = 0;
7876 return p_gid_exchange(obj);
7879 static VALUE
7880 p_gid_switch(VALUE obj)
7882 rb_gid_t gid, egid;
7884 check_gid_switch();
7886 gid = getgid();
7887 egid = getegid();
7889 if (gid == egid) {
7890 rb_syserr_fail(EPERM, 0);
7892 p_gid_exchange(obj);
7893 if (rb_block_given_p()) {
7894 under_gid_switch = 1;
7895 return rb_ensure(rb_yield, Qnil, p_gid_sw_ensure, obj);
7897 else {
7898 return GIDT2NUM(egid);
7901 #endif
7904 #if defined(HAVE_TIMES)
7905 static long
7906 get_clk_tck(void)
7908 #ifdef HAVE__SC_CLK_TCK
7909 return sysconf(_SC_CLK_TCK);
7910 #elif defined CLK_TCK
7911 return CLK_TCK;
7912 #elif defined HZ
7913 return HZ;
7914 #else
7915 return 60;
7916 #endif
7920 * call-seq:
7921 * Process.times -> aProcessTms
7923 * Returns a <code>Tms</code> structure (see Process::Tms)
7924 * that contains user and system CPU times for this process,
7925 * and also for children processes.
7927 * t = Process.times
7928 * [ t.utime, t.stime, t.cutime, t.cstime ] #=> [0.0, 0.02, 0.00, 0.00]
7931 VALUE
7932 rb_proc_times(VALUE obj)
7934 VALUE utime, stime, cutime, cstime, ret;
7935 #if defined(RUSAGE_SELF) && defined(RUSAGE_CHILDREN)
7936 struct rusage usage_s, usage_c;
7938 if (getrusage(RUSAGE_SELF, &usage_s) != 0 || getrusage(RUSAGE_CHILDREN, &usage_c) != 0)
7939 rb_sys_fail("getrusage");
7940 utime = DBL2NUM((double)usage_s.ru_utime.tv_sec + (double)usage_s.ru_utime.tv_usec/1e6);
7941 stime = DBL2NUM((double)usage_s.ru_stime.tv_sec + (double)usage_s.ru_stime.tv_usec/1e6);
7942 cutime = DBL2NUM((double)usage_c.ru_utime.tv_sec + (double)usage_c.ru_utime.tv_usec/1e6);
7943 cstime = DBL2NUM((double)usage_c.ru_stime.tv_sec + (double)usage_c.ru_stime.tv_usec/1e6);
7944 #else
7945 const double hertz = (double)get_clk_tck();
7946 struct tms buf;
7948 times(&buf);
7949 utime = DBL2NUM(buf.tms_utime / hertz);
7950 stime = DBL2NUM(buf.tms_stime / hertz);
7951 cutime = DBL2NUM(buf.tms_cutime / hertz);
7952 cstime = DBL2NUM(buf.tms_cstime / hertz);
7953 #endif
7954 ret = rb_struct_new(rb_cProcessTms, utime, stime, cutime, cstime);
7955 RB_GC_GUARD(utime);
7956 RB_GC_GUARD(stime);
7957 RB_GC_GUARD(cutime);
7958 RB_GC_GUARD(cstime);
7959 return ret;
7961 #else
7962 #define rb_proc_times rb_f_notimplement
7963 #endif
7965 #ifdef HAVE_LONG_LONG
7966 typedef LONG_LONG timetick_int_t;
7967 #define TIMETICK_INT_MIN LLONG_MIN
7968 #define TIMETICK_INT_MAX LLONG_MAX
7969 #define TIMETICK_INT2NUM(v) LL2NUM(v)
7970 #define MUL_OVERFLOW_TIMETICK_P(a, b) MUL_OVERFLOW_LONG_LONG_P(a, b)
7971 #else
7972 typedef long timetick_int_t;
7973 #define TIMETICK_INT_MIN LONG_MIN
7974 #define TIMETICK_INT_MAX LONG_MAX
7975 #define TIMETICK_INT2NUM(v) LONG2NUM(v)
7976 #define MUL_OVERFLOW_TIMETICK_P(a, b) MUL_OVERFLOW_LONG_P(a, b)
7977 #endif
7979 CONSTFUNC(static timetick_int_t gcd_timetick_int(timetick_int_t, timetick_int_t));
7980 static timetick_int_t
7981 gcd_timetick_int(timetick_int_t a, timetick_int_t b)
7983 timetick_int_t t;
7985 if (a < b) {
7986 t = a;
7987 a = b;
7988 b = t;
7991 while (1) {
7992 t = a % b;
7993 if (t == 0)
7994 return b;
7995 a = b;
7996 b = t;
8000 static void
8001 reduce_fraction(timetick_int_t *np, timetick_int_t *dp)
8003 timetick_int_t gcd = gcd_timetick_int(*np, *dp);
8004 if (gcd != 1) {
8005 *np /= gcd;
8006 *dp /= gcd;
8010 static void
8011 reduce_factors(timetick_int_t *numerators, int num_numerators,
8012 timetick_int_t *denominators, int num_denominators)
8014 int i, j;
8015 for (i = 0; i < num_numerators; i++) {
8016 if (numerators[i] == 1)
8017 continue;
8018 for (j = 0; j < num_denominators; j++) {
8019 if (denominators[j] == 1)
8020 continue;
8021 reduce_fraction(&numerators[i], &denominators[j]);
8026 struct timetick {
8027 timetick_int_t giga_count;
8028 int32_t count; /* 0 .. 999999999 */
8031 static VALUE
8032 timetick2dblnum(struct timetick *ttp,
8033 timetick_int_t *numerators, int num_numerators,
8034 timetick_int_t *denominators, int num_denominators)
8036 double d;
8037 int i;
8039 reduce_factors(numerators, num_numerators,
8040 denominators, num_denominators);
8042 d = ttp->giga_count * 1e9 + ttp->count;
8044 for (i = 0; i < num_numerators; i++)
8045 d *= numerators[i];
8046 for (i = 0; i < num_denominators; i++)
8047 d /= denominators[i];
8049 return DBL2NUM(d);
8052 static VALUE
8053 timetick2dblnum_reciprocal(struct timetick *ttp,
8054 timetick_int_t *numerators, int num_numerators,
8055 timetick_int_t *denominators, int num_denominators)
8057 double d;
8058 int i;
8060 reduce_factors(numerators, num_numerators,
8061 denominators, num_denominators);
8063 d = 1.0;
8064 for (i = 0; i < num_denominators; i++)
8065 d *= denominators[i];
8066 for (i = 0; i < num_numerators; i++)
8067 d /= numerators[i];
8068 d /= ttp->giga_count * 1e9 + ttp->count;
8070 return DBL2NUM(d);
8073 #define NDIV(x,y) (-(-((x)+1)/(y))-1)
8074 #define DIV(n,d) ((n)<0 ? NDIV((n),(d)) : (n)/(d))
8076 static VALUE
8077 timetick2integer(struct timetick *ttp,
8078 timetick_int_t *numerators, int num_numerators,
8079 timetick_int_t *denominators, int num_denominators)
8081 VALUE v;
8082 int i;
8084 reduce_factors(numerators, num_numerators,
8085 denominators, num_denominators);
8087 if (!MUL_OVERFLOW_SIGNED_INTEGER_P(1000000000, ttp->giga_count,
8088 TIMETICK_INT_MIN, TIMETICK_INT_MAX-ttp->count)) {
8089 timetick_int_t t = ttp->giga_count * 1000000000 + ttp->count;
8090 for (i = 0; i < num_numerators; i++) {
8091 timetick_int_t factor = numerators[i];
8092 if (MUL_OVERFLOW_TIMETICK_P(factor, t))
8093 goto generic;
8094 t *= factor;
8096 for (i = 0; i < num_denominators; i++) {
8097 t = DIV(t, denominators[i]);
8099 return TIMETICK_INT2NUM(t);
8102 generic:
8103 v = TIMETICK_INT2NUM(ttp->giga_count);
8104 v = rb_funcall(v, '*', 1, LONG2FIX(1000000000));
8105 v = rb_funcall(v, '+', 1, LONG2FIX(ttp->count));
8106 for (i = 0; i < num_numerators; i++) {
8107 timetick_int_t factor = numerators[i];
8108 if (factor == 1)
8109 continue;
8110 v = rb_funcall(v, '*', 1, TIMETICK_INT2NUM(factor));
8112 for (i = 0; i < num_denominators; i++) {
8113 v = rb_funcall(v, '/', 1, TIMETICK_INT2NUM(denominators[i])); /* Ruby's '/' is div. */
8115 return v;
8118 static VALUE
8119 make_clock_result(struct timetick *ttp,
8120 timetick_int_t *numerators, int num_numerators,
8121 timetick_int_t *denominators, int num_denominators,
8122 VALUE unit)
8124 if (unit == ID2SYM(id_nanosecond)) {
8125 numerators[num_numerators++] = 1000000000;
8126 return timetick2integer(ttp, numerators, num_numerators, denominators, num_denominators);
8128 else if (unit == ID2SYM(id_microsecond)) {
8129 numerators[num_numerators++] = 1000000;
8130 return timetick2integer(ttp, numerators, num_numerators, denominators, num_denominators);
8132 else if (unit == ID2SYM(id_millisecond)) {
8133 numerators[num_numerators++] = 1000;
8134 return timetick2integer(ttp, numerators, num_numerators, denominators, num_denominators);
8136 else if (unit == ID2SYM(id_second)) {
8137 return timetick2integer(ttp, numerators, num_numerators, denominators, num_denominators);
8139 else if (unit == ID2SYM(id_float_microsecond)) {
8140 numerators[num_numerators++] = 1000000;
8141 return timetick2dblnum(ttp, numerators, num_numerators, denominators, num_denominators);
8143 else if (unit == ID2SYM(id_float_millisecond)) {
8144 numerators[num_numerators++] = 1000;
8145 return timetick2dblnum(ttp, numerators, num_numerators, denominators, num_denominators);
8147 else if (NIL_P(unit) || unit == ID2SYM(id_float_second)) {
8148 return timetick2dblnum(ttp, numerators, num_numerators, denominators, num_denominators);
8150 else
8151 rb_raise(rb_eArgError, "unexpected unit: %"PRIsVALUE, unit);
8154 #ifdef __APPLE__
8155 static const mach_timebase_info_data_t *
8156 get_mach_timebase_info(void)
8158 static mach_timebase_info_data_t sTimebaseInfo;
8160 if ( sTimebaseInfo.denom == 0 ) {
8161 (void) mach_timebase_info(&sTimebaseInfo);
8164 return &sTimebaseInfo;
8167 double
8168 ruby_real_ms_time(void)
8170 const mach_timebase_info_data_t *info = get_mach_timebase_info();
8171 uint64_t t = mach_absolute_time();
8172 return (double)t * info->numer / info->denom / 1e6;
8174 #endif
8177 * call-seq:
8178 * Process.clock_gettime(clock_id [, unit]) -> number
8180 * Returns a time returned by POSIX clock_gettime() function.
8182 * p Process.clock_gettime(Process::CLOCK_MONOTONIC)
8183 * #=> 896053.968060096
8185 * +clock_id+ specifies a kind of clock.
8186 * It is specified as a constant which begins with <code>Process::CLOCK_</code>
8187 * such as Process::CLOCK_REALTIME and Process::CLOCK_MONOTONIC.
8189 * The supported constants depends on OS and version.
8190 * Ruby provides following types of +clock_id+ if available.
8192 * [CLOCK_REALTIME] SUSv2 to 4, Linux 2.5.63, FreeBSD 3.0, NetBSD 2.0, OpenBSD 2.1, macOS 10.12, Windows-8/Server-2012
8193 * [CLOCK_MONOTONIC] SUSv3 to 4, Linux 2.5.63, FreeBSD 3.0, NetBSD 2.0, OpenBSD 3.4, macOS 10.12, Windows-2000
8194 * [CLOCK_PROCESS_CPUTIME_ID] SUSv3 to 4, Linux 2.5.63, FreeBSD 9.3, OpenBSD 5.4, macOS 10.12
8195 * [CLOCK_THREAD_CPUTIME_ID] SUSv3 to 4, Linux 2.5.63, FreeBSD 7.1, OpenBSD 5.4, macOS 10.12
8196 * [CLOCK_VIRTUAL] FreeBSD 3.0, OpenBSD 2.1
8197 * [CLOCK_PROF] FreeBSD 3.0, OpenBSD 2.1
8198 * [CLOCK_REALTIME_FAST] FreeBSD 8.1
8199 * [CLOCK_REALTIME_PRECISE] FreeBSD 8.1
8200 * [CLOCK_REALTIME_COARSE] Linux 2.6.32
8201 * [CLOCK_REALTIME_ALARM] Linux 3.0
8202 * [CLOCK_MONOTONIC_FAST] FreeBSD 8.1
8203 * [CLOCK_MONOTONIC_PRECISE] FreeBSD 8.1
8204 * [CLOCK_MONOTONIC_COARSE] Linux 2.6.32
8205 * [CLOCK_MONOTONIC_RAW] Linux 2.6.28, macOS 10.12
8206 * [CLOCK_MONOTONIC_RAW_APPROX] macOS 10.12
8207 * [CLOCK_BOOTTIME] Linux 2.6.39
8208 * [CLOCK_BOOTTIME_ALARM] Linux 3.0
8209 * [CLOCK_UPTIME] FreeBSD 7.0, OpenBSD 5.5
8210 * [CLOCK_UPTIME_FAST] FreeBSD 8.1
8211 * [CLOCK_UPTIME_RAW] macOS 10.12
8212 * [CLOCK_UPTIME_RAW_APPROX] macOS 10.12
8213 * [CLOCK_UPTIME_PRECISE] FreeBSD 8.1
8214 * [CLOCK_SECOND] FreeBSD 8.1
8215 * [CLOCK_TAI] Linux 3.10
8217 * Note that SUS stands for Single Unix Specification.
8218 * SUS contains POSIX and clock_gettime is defined in the POSIX part.
8219 * SUS defines CLOCK_REALTIME mandatory but
8220 * CLOCK_MONOTONIC, CLOCK_PROCESS_CPUTIME_ID and CLOCK_THREAD_CPUTIME_ID are optional.
8222 * Also, several symbols are accepted as +clock_id+.
8223 * There are emulations for clock_gettime().
8225 * For example, Process::CLOCK_REALTIME is defined as
8226 * +:GETTIMEOFDAY_BASED_CLOCK_REALTIME+ when clock_gettime() is not available.
8228 * Emulations for +CLOCK_REALTIME+:
8229 * [:GETTIMEOFDAY_BASED_CLOCK_REALTIME]
8230 * Use gettimeofday() defined by SUS.
8231 * (SUSv4 obsoleted it, though.)
8232 * The resolution is 1 microsecond.
8233 * [:TIME_BASED_CLOCK_REALTIME]
8234 * Use time() defined by ISO C.
8235 * The resolution is 1 second.
8237 * Emulations for +CLOCK_MONOTONIC+:
8238 * [:MACH_ABSOLUTE_TIME_BASED_CLOCK_MONOTONIC]
8239 * Use mach_absolute_time(), available on Darwin.
8240 * The resolution is CPU dependent.
8241 * [:TIMES_BASED_CLOCK_MONOTONIC]
8242 * Use the result value of times() defined by POSIX.
8243 * POSIX defines it as "times() shall return the elapsed real time, in clock ticks, since an arbitrary point in the past (for example, system start-up time)".
8244 * For example, GNU/Linux returns a value based on jiffies and it is monotonic.
8245 * However, 4.4BSD uses gettimeofday() and it is not monotonic.
8246 * (FreeBSD uses clock_gettime(CLOCK_MONOTONIC) instead, though.)
8247 * The resolution is the clock tick.
8248 * "getconf CLK_TCK" command shows the clock ticks per second.
8249 * (The clock ticks per second is defined by HZ macro in older systems.)
8250 * If it is 100 and clock_t is 32 bits integer type, the resolution is 10 millisecond and
8251 * cannot represent over 497 days.
8253 * Emulations for +CLOCK_PROCESS_CPUTIME_ID+:
8254 * [:GETRUSAGE_BASED_CLOCK_PROCESS_CPUTIME_ID]
8255 * Use getrusage() defined by SUS.
8256 * getrusage() is used with RUSAGE_SELF to obtain the time only for
8257 * the calling process (excluding the time for child processes).
8258 * The result is addition of user time (ru_utime) and system time (ru_stime).
8259 * The resolution is 1 microsecond.
8260 * [:TIMES_BASED_CLOCK_PROCESS_CPUTIME_ID]
8261 * Use times() defined by POSIX.
8262 * The result is addition of user time (tms_utime) and system time (tms_stime).
8263 * tms_cutime and tms_cstime are ignored to exclude the time for child processes.
8264 * The resolution is the clock tick.
8265 * "getconf CLK_TCK" command shows the clock ticks per second.
8266 * (The clock ticks per second is defined by HZ macro in older systems.)
8267 * If it is 100, the resolution is 10 millisecond.
8268 * [:CLOCK_BASED_CLOCK_PROCESS_CPUTIME_ID]
8269 * Use clock() defined by ISO C.
8270 * The resolution is 1/CLOCKS_PER_SEC.
8271 * CLOCKS_PER_SEC is the C-level macro defined by time.h.
8272 * SUS defines CLOCKS_PER_SEC is 1000000.
8273 * Non-Unix systems may define it a different value, though.
8274 * If CLOCKS_PER_SEC is 1000000 as SUS, the resolution is 1 microsecond.
8275 * If CLOCKS_PER_SEC is 1000000 and clock_t is 32 bits integer type, it cannot represent over 72 minutes.
8277 * If the given +clock_id+ is not supported, Errno::EINVAL is raised.
8279 * +unit+ specifies a type of the return value.
8281 * [:float_second] number of seconds as a float (default)
8282 * [:float_millisecond] number of milliseconds as a float
8283 * [:float_microsecond] number of microseconds as a float
8284 * [:second] number of seconds as an integer
8285 * [:millisecond] number of milliseconds as an integer
8286 * [:microsecond] number of microseconds as an integer
8287 * [:nanosecond] number of nanoseconds as an integer
8289 * The underlying function, clock_gettime(), returns a number of nanoseconds.
8290 * Float object (IEEE 754 double) is not enough to represent
8291 * the return value for CLOCK_REALTIME.
8292 * If the exact nanoseconds value is required, use +:nanoseconds+ as the +unit+.
8294 * The origin (zero) of the returned value varies.
8295 * For example, system start up time, process start up time, the Epoch, etc.
8297 * The origin in CLOCK_REALTIME is defined as the Epoch
8298 * (1970-01-01 00:00:00 UTC).
8299 * But some systems count leap seconds and others doesn't.
8300 * So the result can be interpreted differently across systems.
8301 * Time.now is recommended over CLOCK_REALTIME.
8303 static VALUE
8304 rb_clock_gettime(int argc, VALUE *argv, VALUE _)
8306 int ret;
8308 struct timetick tt;
8309 timetick_int_t numerators[2];
8310 timetick_int_t denominators[2];
8311 int num_numerators = 0;
8312 int num_denominators = 0;
8314 VALUE unit = (rb_check_arity(argc, 1, 2) == 2) ? argv[1] : Qnil;
8315 VALUE clk_id = argv[0];
8317 if (SYMBOL_P(clk_id)) {
8319 * Non-clock_gettime clocks are provided by symbol clk_id.
8321 #ifdef HAVE_GETTIMEOFDAY
8323 * GETTIMEOFDAY_BASED_CLOCK_REALTIME is used for
8324 * CLOCK_REALTIME if clock_gettime is not available.
8326 #define RUBY_GETTIMEOFDAY_BASED_CLOCK_REALTIME ID2SYM(id_GETTIMEOFDAY_BASED_CLOCK_REALTIME)
8327 if (clk_id == RUBY_GETTIMEOFDAY_BASED_CLOCK_REALTIME) {
8328 struct timeval tv;
8329 ret = gettimeofday(&tv, 0);
8330 if (ret != 0)
8331 rb_sys_fail("gettimeofday");
8332 tt.giga_count = tv.tv_sec;
8333 tt.count = (int32_t)tv.tv_usec * 1000;
8334 denominators[num_denominators++] = 1000000000;
8335 goto success;
8337 #endif
8339 #define RUBY_TIME_BASED_CLOCK_REALTIME ID2SYM(id_TIME_BASED_CLOCK_REALTIME)
8340 if (clk_id == RUBY_TIME_BASED_CLOCK_REALTIME) {
8341 time_t t;
8342 t = time(NULL);
8343 if (t == (time_t)-1)
8344 rb_sys_fail("time");
8345 tt.giga_count = t;
8346 tt.count = 0;
8347 denominators[num_denominators++] = 1000000000;
8348 goto success;
8351 #ifdef HAVE_TIMES
8352 #define RUBY_TIMES_BASED_CLOCK_MONOTONIC \
8353 ID2SYM(id_TIMES_BASED_CLOCK_MONOTONIC)
8354 if (clk_id == RUBY_TIMES_BASED_CLOCK_MONOTONIC) {
8355 struct tms buf;
8356 clock_t c;
8357 unsigned_clock_t uc;
8358 c = times(&buf);
8359 if (c == (clock_t)-1)
8360 rb_sys_fail("times");
8361 uc = (unsigned_clock_t)c;
8362 tt.count = (int32_t)(uc % 1000000000);
8363 tt.giga_count = (uc / 1000000000);
8364 denominators[num_denominators++] = get_clk_tck();
8365 goto success;
8367 #endif
8369 #ifdef RUSAGE_SELF
8370 #define RUBY_GETRUSAGE_BASED_CLOCK_PROCESS_CPUTIME_ID \
8371 ID2SYM(id_GETRUSAGE_BASED_CLOCK_PROCESS_CPUTIME_ID)
8372 if (clk_id == RUBY_GETRUSAGE_BASED_CLOCK_PROCESS_CPUTIME_ID) {
8373 struct rusage usage;
8374 int32_t usec;
8375 ret = getrusage(RUSAGE_SELF, &usage);
8376 if (ret != 0)
8377 rb_sys_fail("getrusage");
8378 tt.giga_count = usage.ru_utime.tv_sec + usage.ru_stime.tv_sec;
8379 usec = (int32_t)(usage.ru_utime.tv_usec + usage.ru_stime.tv_usec);
8380 if (1000000 <= usec) {
8381 tt.giga_count++;
8382 usec -= 1000000;
8384 tt.count = usec * 1000;
8385 denominators[num_denominators++] = 1000000000;
8386 goto success;
8388 #endif
8390 #ifdef HAVE_TIMES
8391 #define RUBY_TIMES_BASED_CLOCK_PROCESS_CPUTIME_ID \
8392 ID2SYM(id_TIMES_BASED_CLOCK_PROCESS_CPUTIME_ID)
8393 if (clk_id == RUBY_TIMES_BASED_CLOCK_PROCESS_CPUTIME_ID) {
8394 struct tms buf;
8395 unsigned_clock_t utime, stime;
8396 if (times(&buf) == (clock_t)-1)
8397 rb_sys_fail("times");
8398 utime = (unsigned_clock_t)buf.tms_utime;
8399 stime = (unsigned_clock_t)buf.tms_stime;
8400 tt.count = (int32_t)((utime % 1000000000) + (stime % 1000000000));
8401 tt.giga_count = (utime / 1000000000) + (stime / 1000000000);
8402 if (1000000000 <= tt.count) {
8403 tt.count -= 1000000000;
8404 tt.giga_count++;
8406 denominators[num_denominators++] = get_clk_tck();
8407 goto success;
8409 #endif
8411 #define RUBY_CLOCK_BASED_CLOCK_PROCESS_CPUTIME_ID \
8412 ID2SYM(id_CLOCK_BASED_CLOCK_PROCESS_CPUTIME_ID)
8413 if (clk_id == RUBY_CLOCK_BASED_CLOCK_PROCESS_CPUTIME_ID) {
8414 clock_t c;
8415 unsigned_clock_t uc;
8416 errno = 0;
8417 c = clock();
8418 if (c == (clock_t)-1)
8419 rb_sys_fail("clock");
8420 uc = (unsigned_clock_t)c;
8421 tt.count = (int32_t)(uc % 1000000000);
8422 tt.giga_count = uc / 1000000000;
8423 denominators[num_denominators++] = CLOCKS_PER_SEC;
8424 goto success;
8427 #ifdef __APPLE__
8428 #define RUBY_MACH_ABSOLUTE_TIME_BASED_CLOCK_MONOTONIC ID2SYM(id_MACH_ABSOLUTE_TIME_BASED_CLOCK_MONOTONIC)
8429 if (clk_id == RUBY_MACH_ABSOLUTE_TIME_BASED_CLOCK_MONOTONIC) {
8430 const mach_timebase_info_data_t *info = get_mach_timebase_info();
8431 uint64_t t = mach_absolute_time();
8432 tt.count = (int32_t)(t % 1000000000);
8433 tt.giga_count = t / 1000000000;
8434 numerators[num_numerators++] = info->numer;
8435 denominators[num_denominators++] = info->denom;
8436 denominators[num_denominators++] = 1000000000;
8437 goto success;
8439 #endif
8441 else {
8442 #if defined(HAVE_CLOCK_GETTIME)
8443 struct timespec ts;
8444 clockid_t c;
8445 c = NUM2CLOCKID(clk_id);
8446 ret = clock_gettime(c, &ts);
8447 if (ret == -1)
8448 rb_sys_fail("clock_gettime");
8449 tt.count = (int32_t)ts.tv_nsec;
8450 tt.giga_count = ts.tv_sec;
8451 denominators[num_denominators++] = 1000000000;
8452 goto success;
8453 #endif
8455 /* EINVAL emulates clock_gettime behavior when clock_id is invalid. */
8456 rb_syserr_fail(EINVAL, 0);
8458 success:
8459 return make_clock_result(&tt, numerators, num_numerators, denominators, num_denominators, unit);
8463 * call-seq:
8464 * Process.clock_getres(clock_id [, unit]) -> number
8466 * Returns an estimate of the resolution of a +clock_id+ using the POSIX
8467 * <code>clock_getres()</code> function.
8469 * Note the reported resolution is often inaccurate on most platforms due to
8470 * underlying bugs for this function and therefore the reported resolution
8471 * often differs from the actual resolution of the clock in practice.
8472 * Inaccurate reported resolutions have been observed for various clocks including
8473 * CLOCK_MONOTONIC and CLOCK_MONOTONIC_RAW when using Linux, macOS, BSD or AIX
8474 * platforms, when using ARM processors, or when using virtualization.
8476 * +clock_id+ specifies a kind of clock.
8477 * See the document of +Process.clock_gettime+ for details.
8478 * +clock_id+ can be a symbol as for +Process.clock_gettime+.
8480 * If the given +clock_id+ is not supported, Errno::EINVAL is raised.
8482 * +unit+ specifies the type of the return value.
8483 * +Process.clock_getres+ accepts +unit+ as +Process.clock_gettime+.
8484 * The default value, +:float_second+, is also the same as
8485 * +Process.clock_gettime+.
8487 * +Process.clock_getres+ also accepts +:hertz+ as +unit+.
8488 * +:hertz+ means the reciprocal of +:float_second+.
8490 * +:hertz+ can be used to obtain the exact value of
8491 * the clock ticks per second for the times() function and
8492 * CLOCKS_PER_SEC for the clock() function.
8494 * <code>Process.clock_getres(:TIMES_BASED_CLOCK_PROCESS_CPUTIME_ID, :hertz)</code>
8495 * returns the clock ticks per second.
8497 * <code>Process.clock_getres(:CLOCK_BASED_CLOCK_PROCESS_CPUTIME_ID, :hertz)</code>
8498 * returns CLOCKS_PER_SEC.
8500 * p Process.clock_getres(Process::CLOCK_MONOTONIC)
8501 * #=> 1.0e-09
8504 static VALUE
8505 rb_clock_getres(int argc, VALUE *argv, VALUE _)
8507 struct timetick tt;
8508 timetick_int_t numerators[2];
8509 timetick_int_t denominators[2];
8510 int num_numerators = 0;
8511 int num_denominators = 0;
8513 VALUE unit = (rb_check_arity(argc, 1, 2) == 2) ? argv[1] : Qnil;
8514 VALUE clk_id = argv[0];
8516 if (SYMBOL_P(clk_id)) {
8517 #ifdef RUBY_GETTIMEOFDAY_BASED_CLOCK_REALTIME
8518 if (clk_id == RUBY_GETTIMEOFDAY_BASED_CLOCK_REALTIME) {
8519 tt.giga_count = 0;
8520 tt.count = 1000;
8521 denominators[num_denominators++] = 1000000000;
8522 goto success;
8524 #endif
8526 #ifdef RUBY_TIME_BASED_CLOCK_REALTIME
8527 if (clk_id == RUBY_TIME_BASED_CLOCK_REALTIME) {
8528 tt.giga_count = 1;
8529 tt.count = 0;
8530 denominators[num_denominators++] = 1000000000;
8531 goto success;
8533 #endif
8535 #ifdef RUBY_TIMES_BASED_CLOCK_MONOTONIC
8536 if (clk_id == RUBY_TIMES_BASED_CLOCK_MONOTONIC) {
8537 tt.count = 1;
8538 tt.giga_count = 0;
8539 denominators[num_denominators++] = get_clk_tck();
8540 goto success;
8542 #endif
8544 #ifdef RUBY_GETRUSAGE_BASED_CLOCK_PROCESS_CPUTIME_ID
8545 if (clk_id == RUBY_GETRUSAGE_BASED_CLOCK_PROCESS_CPUTIME_ID) {
8546 tt.giga_count = 0;
8547 tt.count = 1000;
8548 denominators[num_denominators++] = 1000000000;
8549 goto success;
8551 #endif
8553 #ifdef RUBY_TIMES_BASED_CLOCK_PROCESS_CPUTIME_ID
8554 if (clk_id == RUBY_TIMES_BASED_CLOCK_PROCESS_CPUTIME_ID) {
8555 tt.count = 1;
8556 tt.giga_count = 0;
8557 denominators[num_denominators++] = get_clk_tck();
8558 goto success;
8560 #endif
8562 #ifdef RUBY_CLOCK_BASED_CLOCK_PROCESS_CPUTIME_ID
8563 if (clk_id == RUBY_CLOCK_BASED_CLOCK_PROCESS_CPUTIME_ID) {
8564 tt.count = 1;
8565 tt.giga_count = 0;
8566 denominators[num_denominators++] = CLOCKS_PER_SEC;
8567 goto success;
8569 #endif
8571 #ifdef RUBY_MACH_ABSOLUTE_TIME_BASED_CLOCK_MONOTONIC
8572 if (clk_id == RUBY_MACH_ABSOLUTE_TIME_BASED_CLOCK_MONOTONIC) {
8573 const mach_timebase_info_data_t *info = get_mach_timebase_info();
8574 tt.count = 1;
8575 tt.giga_count = 0;
8576 numerators[num_numerators++] = info->numer;
8577 denominators[num_denominators++] = info->denom;
8578 denominators[num_denominators++] = 1000000000;
8579 goto success;
8581 #endif
8583 else {
8584 #if defined(HAVE_CLOCK_GETRES)
8585 struct timespec ts;
8586 clockid_t c = NUM2CLOCKID(clk_id);
8587 int ret = clock_getres(c, &ts);
8588 if (ret == -1)
8589 rb_sys_fail("clock_getres");
8590 tt.count = (int32_t)ts.tv_nsec;
8591 tt.giga_count = ts.tv_sec;
8592 denominators[num_denominators++] = 1000000000;
8593 goto success;
8594 #endif
8596 /* EINVAL emulates clock_getres behavior when clock_id is invalid. */
8597 rb_syserr_fail(EINVAL, 0);
8599 success:
8600 if (unit == ID2SYM(id_hertz)) {
8601 return timetick2dblnum_reciprocal(&tt, numerators, num_numerators, denominators, num_denominators);
8603 else {
8604 return make_clock_result(&tt, numerators, num_numerators, denominators, num_denominators, unit);
8608 static VALUE
8609 get_CHILD_STATUS(ID _x, VALUE *_y)
8611 return rb_last_status_get();
8614 static VALUE
8615 get_PROCESS_ID(ID _x, VALUE *_y)
8617 return get_pid();
8621 * call-seq:
8622 * Process.kill(signal, pid, ...) -> integer
8624 * Sends the given signal to the specified process id(s) if _pid_ is positive.
8625 * If _pid_ is zero, _signal_ is sent to all processes whose group ID is equal
8626 * to the group ID of the process. If _pid_ is negative, results are dependent
8627 * on the operating system. _signal_ may be an integer signal number or
8628 * a POSIX signal name (either with or without a +SIG+ prefix). If _signal_ is
8629 * negative (or starts with a minus sign), kills process groups instead of
8630 * processes. Not all signals are available on all platforms.
8631 * The keys and values of Signal.list are known signal names and numbers,
8632 * respectively.
8634 * pid = fork do
8635 * Signal.trap("HUP") { puts "Ouch!"; exit }
8636 * # ... do some work ...
8637 * end
8638 * # ...
8639 * Process.kill("HUP", pid)
8640 * Process.wait
8642 * <em>produces:</em>
8644 * Ouch!
8646 * If _signal_ is an integer but wrong for signal, Errno::EINVAL or
8647 * RangeError will be raised. Otherwise unless _signal_ is a String
8648 * or a Symbol, and a known signal name, ArgumentError will be
8649 * raised.
8651 * Also, Errno::ESRCH or RangeError for invalid _pid_, Errno::EPERM
8652 * when failed because of no privilege, will be raised. In these
8653 * cases, signals may have been sent to preceding processes.
8656 static VALUE
8657 proc_rb_f_kill(int c, const VALUE *v, VALUE _)
8659 return rb_f_kill(c, v);
8662 VALUE rb_mProcess;
8663 static VALUE rb_mProcUID;
8664 static VALUE rb_mProcGID;
8665 static VALUE rb_mProcID_Syscall;
8669 * The Process module is a collection of methods used to
8670 * manipulate processes.
8673 void
8674 InitVM_process(void)
8676 rb_define_virtual_variable("$?", get_CHILD_STATUS, 0);
8677 rb_define_virtual_variable("$$", get_PROCESS_ID, 0);
8679 rb_gvar_ractor_local("$$");
8680 rb_gvar_ractor_local("$?");
8682 rb_define_global_function("exec", f_exec, -1);
8683 rb_define_global_function("fork", rb_f_fork, 0);
8684 rb_define_global_function("exit!", rb_f_exit_bang, -1);
8685 rb_define_global_function("system", rb_f_system, -1);
8686 rb_define_global_function("spawn", rb_f_spawn, -1);
8687 rb_define_global_function("sleep", rb_f_sleep, -1);
8688 rb_define_global_function("exit", f_exit, -1);
8689 rb_define_global_function("abort", f_abort, -1);
8691 rb_mProcess = rb_define_module("Process");
8693 #ifdef WNOHANG
8694 /* see Process.wait */
8695 rb_define_const(rb_mProcess, "WNOHANG", INT2FIX(WNOHANG));
8696 #else
8697 /* see Process.wait */
8698 rb_define_const(rb_mProcess, "WNOHANG", INT2FIX(0));
8699 #endif
8700 #ifdef WUNTRACED
8701 /* see Process.wait */
8702 rb_define_const(rb_mProcess, "WUNTRACED", INT2FIX(WUNTRACED));
8703 #else
8704 /* see Process.wait */
8705 rb_define_const(rb_mProcess, "WUNTRACED", INT2FIX(0));
8706 #endif
8708 rb_define_singleton_method(rb_mProcess, "exec", f_exec, -1);
8709 rb_define_singleton_method(rb_mProcess, "fork", rb_f_fork, 0);
8710 rb_define_singleton_method(rb_mProcess, "spawn", rb_f_spawn, -1);
8711 rb_define_singleton_method(rb_mProcess, "exit!", rb_f_exit_bang, -1);
8712 rb_define_singleton_method(rb_mProcess, "exit", f_exit, -1);
8713 rb_define_singleton_method(rb_mProcess, "abort", f_abort, -1);
8714 rb_define_singleton_method(rb_mProcess, "last_status", proc_s_last_status, 0);
8715 rb_define_singleton_method(rb_mProcess, "_fork", rb_proc__fork, 0);
8717 rb_define_module_function(rb_mProcess, "kill", proc_rb_f_kill, -1);
8718 rb_define_module_function(rb_mProcess, "wait", proc_m_wait, -1);
8719 rb_define_module_function(rb_mProcess, "wait2", proc_wait2, -1);
8720 rb_define_module_function(rb_mProcess, "waitpid", proc_m_wait, -1);
8721 rb_define_module_function(rb_mProcess, "waitpid2", proc_wait2, -1);
8722 rb_define_module_function(rb_mProcess, "waitall", proc_waitall, 0);
8723 rb_define_module_function(rb_mProcess, "detach", proc_detach, 1);
8725 /* :nodoc: */
8726 rb_cWaiter = rb_define_class_under(rb_mProcess, "Waiter", rb_cThread);
8727 rb_undef_alloc_func(rb_cWaiter);
8728 rb_undef_method(CLASS_OF(rb_cWaiter), "new");
8729 rb_define_method(rb_cWaiter, "pid", detach_process_pid, 0);
8731 rb_cProcessStatus = rb_define_class_under(rb_mProcess, "Status", rb_cObject);
8732 rb_define_alloc_func(rb_cProcessStatus, rb_process_status_allocate);
8733 rb_undef_method(CLASS_OF(rb_cProcessStatus), "new");
8734 rb_marshal_define_compat(rb_cProcessStatus, rb_cObject,
8735 process_status_dump, process_status_load);
8737 rb_define_singleton_method(rb_cProcessStatus, "wait", rb_process_status_waitv, -1);
8739 rb_define_method(rb_cProcessStatus, "==", pst_equal, 1);
8740 rb_define_method(rb_cProcessStatus, "&", pst_bitand, 1);
8741 rb_define_method(rb_cProcessStatus, ">>", pst_rshift, 1);
8742 rb_define_method(rb_cProcessStatus, "to_i", pst_to_i, 0);
8743 rb_define_method(rb_cProcessStatus, "to_s", pst_to_s, 0);
8744 rb_define_method(rb_cProcessStatus, "inspect", pst_inspect, 0);
8746 rb_define_method(rb_cProcessStatus, "pid", pst_pid_m, 0);
8748 rb_define_method(rb_cProcessStatus, "stopped?", pst_wifstopped, 0);
8749 rb_define_method(rb_cProcessStatus, "stopsig", pst_wstopsig, 0);
8750 rb_define_method(rb_cProcessStatus, "signaled?", pst_wifsignaled, 0);
8751 rb_define_method(rb_cProcessStatus, "termsig", pst_wtermsig, 0);
8752 rb_define_method(rb_cProcessStatus, "exited?", pst_wifexited, 0);
8753 rb_define_method(rb_cProcessStatus, "exitstatus", pst_wexitstatus, 0);
8754 rb_define_method(rb_cProcessStatus, "success?", pst_success_p, 0);
8755 rb_define_method(rb_cProcessStatus, "coredump?", pst_wcoredump, 0);
8757 rb_define_module_function(rb_mProcess, "pid", proc_get_pid, 0);
8758 rb_define_module_function(rb_mProcess, "ppid", proc_get_ppid, 0);
8760 rb_define_module_function(rb_mProcess, "getpgrp", proc_getpgrp, 0);
8761 rb_define_module_function(rb_mProcess, "setpgrp", proc_setpgrp, 0);
8762 rb_define_module_function(rb_mProcess, "getpgid", proc_getpgid, 1);
8763 rb_define_module_function(rb_mProcess, "setpgid", proc_setpgid, 2);
8765 rb_define_module_function(rb_mProcess, "getsid", proc_getsid, -1);
8766 rb_define_module_function(rb_mProcess, "setsid", proc_setsid, 0);
8768 rb_define_module_function(rb_mProcess, "getpriority", proc_getpriority, 2);
8769 rb_define_module_function(rb_mProcess, "setpriority", proc_setpriority, 3);
8771 #ifdef HAVE_GETPRIORITY
8772 /* see Process.setpriority */
8773 rb_define_const(rb_mProcess, "PRIO_PROCESS", INT2FIX(PRIO_PROCESS));
8774 /* see Process.setpriority */
8775 rb_define_const(rb_mProcess, "PRIO_PGRP", INT2FIX(PRIO_PGRP));
8776 /* see Process.setpriority */
8777 rb_define_const(rb_mProcess, "PRIO_USER", INT2FIX(PRIO_USER));
8778 #endif
8780 rb_define_module_function(rb_mProcess, "getrlimit", proc_getrlimit, 1);
8781 rb_define_module_function(rb_mProcess, "setrlimit", proc_setrlimit, -1);
8782 #if defined(RLIM2NUM) && defined(RLIM_INFINITY)
8784 VALUE inf = RLIM2NUM(RLIM_INFINITY);
8785 #ifdef RLIM_SAVED_MAX
8787 VALUE v = RLIM_INFINITY == RLIM_SAVED_MAX ? inf : RLIM2NUM(RLIM_SAVED_MAX);
8788 /* see Process.setrlimit */
8789 rb_define_const(rb_mProcess, "RLIM_SAVED_MAX", v);
8791 #endif
8792 /* see Process.setrlimit */
8793 rb_define_const(rb_mProcess, "RLIM_INFINITY", inf);
8794 #ifdef RLIM_SAVED_CUR
8796 VALUE v = RLIM_INFINITY == RLIM_SAVED_CUR ? inf : RLIM2NUM(RLIM_SAVED_CUR);
8797 /* see Process.setrlimit */
8798 rb_define_const(rb_mProcess, "RLIM_SAVED_CUR", v);
8800 #endif
8802 #ifdef RLIMIT_AS
8803 /* Maximum size of the process's virtual memory (address space) in bytes.
8805 * see the system getrlimit(2) manual for details.
8807 rb_define_const(rb_mProcess, "RLIMIT_AS", INT2FIX(RLIMIT_AS));
8808 #endif
8809 #ifdef RLIMIT_CORE
8810 /* Maximum size of the core file.
8812 * see the system getrlimit(2) manual for details.
8814 rb_define_const(rb_mProcess, "RLIMIT_CORE", INT2FIX(RLIMIT_CORE));
8815 #endif
8816 #ifdef RLIMIT_CPU
8817 /* CPU time limit in seconds.
8819 * see the system getrlimit(2) manual for details.
8821 rb_define_const(rb_mProcess, "RLIMIT_CPU", INT2FIX(RLIMIT_CPU));
8822 #endif
8823 #ifdef RLIMIT_DATA
8824 /* Maximum size of the process's data segment.
8826 * see the system getrlimit(2) manual for details.
8828 rb_define_const(rb_mProcess, "RLIMIT_DATA", INT2FIX(RLIMIT_DATA));
8829 #endif
8830 #ifdef RLIMIT_FSIZE
8831 /* Maximum size of files that the process may create.
8833 * see the system getrlimit(2) manual for details.
8835 rb_define_const(rb_mProcess, "RLIMIT_FSIZE", INT2FIX(RLIMIT_FSIZE));
8836 #endif
8837 #ifdef RLIMIT_MEMLOCK
8838 /* Maximum number of bytes of memory that may be locked into RAM.
8840 * see the system getrlimit(2) manual for details.
8842 rb_define_const(rb_mProcess, "RLIMIT_MEMLOCK", INT2FIX(RLIMIT_MEMLOCK));
8843 #endif
8844 #ifdef RLIMIT_MSGQUEUE
8845 /* Specifies the limit on the number of bytes that can be allocated
8846 * for POSIX message queues for the real user ID of the calling process.
8848 * see the system getrlimit(2) manual for details.
8850 rb_define_const(rb_mProcess, "RLIMIT_MSGQUEUE", INT2FIX(RLIMIT_MSGQUEUE));
8851 #endif
8852 #ifdef RLIMIT_NICE
8853 /* Specifies a ceiling to which the process's nice value can be raised.
8855 * see the system getrlimit(2) manual for details.
8857 rb_define_const(rb_mProcess, "RLIMIT_NICE", INT2FIX(RLIMIT_NICE));
8858 #endif
8859 #ifdef RLIMIT_NOFILE
8860 /* Specifies a value one greater than the maximum file descriptor
8861 * number that can be opened by this process.
8863 * see the system getrlimit(2) manual for details.
8865 rb_define_const(rb_mProcess, "RLIMIT_NOFILE", INT2FIX(RLIMIT_NOFILE));
8866 #endif
8867 #ifdef RLIMIT_NPROC
8868 /* The maximum number of processes that can be created for the
8869 * real user ID of the calling process.
8871 * see the system getrlimit(2) manual for details.
8873 rb_define_const(rb_mProcess, "RLIMIT_NPROC", INT2FIX(RLIMIT_NPROC));
8874 #endif
8875 #ifdef RLIMIT_RSS
8876 /* Specifies the limit (in pages) of the process's resident set.
8878 * see the system getrlimit(2) manual for details.
8880 rb_define_const(rb_mProcess, "RLIMIT_RSS", INT2FIX(RLIMIT_RSS));
8881 #endif
8882 #ifdef RLIMIT_RTPRIO
8883 /* Specifies a ceiling on the real-time priority that may be set for this process.
8885 * see the system getrlimit(2) manual for details.
8887 rb_define_const(rb_mProcess, "RLIMIT_RTPRIO", INT2FIX(RLIMIT_RTPRIO));
8888 #endif
8889 #ifdef RLIMIT_RTTIME
8890 /* Specifies limit on CPU time this process scheduled under a real-time
8891 * scheduling policy can consume.
8893 * see the system getrlimit(2) manual for details.
8895 rb_define_const(rb_mProcess, "RLIMIT_RTTIME", INT2FIX(RLIMIT_RTTIME));
8896 #endif
8897 #ifdef RLIMIT_SBSIZE
8898 /* Maximum size of the socket buffer.
8900 rb_define_const(rb_mProcess, "RLIMIT_SBSIZE", INT2FIX(RLIMIT_SBSIZE));
8901 #endif
8902 #ifdef RLIMIT_SIGPENDING
8903 /* Specifies a limit on the number of signals that may be queued for
8904 * the real user ID of the calling process.
8906 * see the system getrlimit(2) manual for details.
8908 rb_define_const(rb_mProcess, "RLIMIT_SIGPENDING", INT2FIX(RLIMIT_SIGPENDING));
8909 #endif
8910 #ifdef RLIMIT_STACK
8911 /* Maximum size of the stack, in bytes.
8913 * see the system getrlimit(2) manual for details.
8915 rb_define_const(rb_mProcess, "RLIMIT_STACK", INT2FIX(RLIMIT_STACK));
8916 #endif
8917 #endif
8919 rb_define_module_function(rb_mProcess, "uid", proc_getuid, 0);
8920 rb_define_module_function(rb_mProcess, "uid=", proc_setuid, 1);
8921 rb_define_module_function(rb_mProcess, "gid", proc_getgid, 0);
8922 rb_define_module_function(rb_mProcess, "gid=", proc_setgid, 1);
8923 rb_define_module_function(rb_mProcess, "euid", proc_geteuid, 0);
8924 rb_define_module_function(rb_mProcess, "euid=", proc_seteuid_m, 1);
8925 rb_define_module_function(rb_mProcess, "egid", proc_getegid, 0);
8926 rb_define_module_function(rb_mProcess, "egid=", proc_setegid_m, 1);
8927 rb_define_module_function(rb_mProcess, "initgroups", proc_initgroups, 2);
8928 rb_define_module_function(rb_mProcess, "groups", proc_getgroups, 0);
8929 rb_define_module_function(rb_mProcess, "groups=", proc_setgroups, 1);
8930 rb_define_module_function(rb_mProcess, "maxgroups", proc_getmaxgroups, 0);
8931 rb_define_module_function(rb_mProcess, "maxgroups=", proc_setmaxgroups, 1);
8933 rb_define_module_function(rb_mProcess, "daemon", proc_daemon, -1);
8935 rb_define_module_function(rb_mProcess, "times", rb_proc_times, 0);
8937 #ifdef CLOCK_REALTIME
8938 /* see Process.clock_gettime */
8939 rb_define_const(rb_mProcess, "CLOCK_REALTIME", CLOCKID2NUM(CLOCK_REALTIME));
8940 #elif defined(RUBY_GETTIMEOFDAY_BASED_CLOCK_REALTIME)
8941 /* see Process.clock_gettime */
8942 rb_define_const(rb_mProcess, "CLOCK_REALTIME", RUBY_GETTIMEOFDAY_BASED_CLOCK_REALTIME);
8943 #endif
8944 #ifdef CLOCK_MONOTONIC
8945 /* see Process.clock_gettime */
8946 rb_define_const(rb_mProcess, "CLOCK_MONOTONIC", CLOCKID2NUM(CLOCK_MONOTONIC));
8947 #elif defined(RUBY_MACH_ABSOLUTE_TIME_BASED_CLOCK_MONOTONIC)
8948 /* see Process.clock_gettime */
8949 rb_define_const(rb_mProcess, "CLOCK_MONOTONIC", RUBY_MACH_ABSOLUTE_TIME_BASED_CLOCK_MONOTONIC);
8950 #endif
8951 #ifdef CLOCK_PROCESS_CPUTIME_ID
8952 /* see Process.clock_gettime */
8953 rb_define_const(rb_mProcess, "CLOCK_PROCESS_CPUTIME_ID", CLOCKID2NUM(CLOCK_PROCESS_CPUTIME_ID));
8954 #elif defined(RUBY_GETRUSAGE_BASED_CLOCK_PROCESS_CPUTIME_ID)
8955 /* see Process.clock_gettime */
8956 rb_define_const(rb_mProcess, "CLOCK_PROCESS_CPUTIME_ID", RUBY_GETRUSAGE_BASED_CLOCK_PROCESS_CPUTIME_ID);
8957 #endif
8958 #ifdef CLOCK_THREAD_CPUTIME_ID
8959 /* see Process.clock_gettime */
8960 rb_define_const(rb_mProcess, "CLOCK_THREAD_CPUTIME_ID", CLOCKID2NUM(CLOCK_THREAD_CPUTIME_ID));
8961 #endif
8962 #ifdef CLOCK_VIRTUAL
8963 /* see Process.clock_gettime */
8964 rb_define_const(rb_mProcess, "CLOCK_VIRTUAL", CLOCKID2NUM(CLOCK_VIRTUAL));
8965 #endif
8966 #ifdef CLOCK_PROF
8967 /* see Process.clock_gettime */
8968 rb_define_const(rb_mProcess, "CLOCK_PROF", CLOCKID2NUM(CLOCK_PROF));
8969 #endif
8970 #ifdef CLOCK_REALTIME_FAST
8971 /* see Process.clock_gettime */
8972 rb_define_const(rb_mProcess, "CLOCK_REALTIME_FAST", CLOCKID2NUM(CLOCK_REALTIME_FAST));
8973 #endif
8974 #ifdef CLOCK_REALTIME_PRECISE
8975 /* see Process.clock_gettime */
8976 rb_define_const(rb_mProcess, "CLOCK_REALTIME_PRECISE", CLOCKID2NUM(CLOCK_REALTIME_PRECISE));
8977 #endif
8978 #ifdef CLOCK_REALTIME_COARSE
8979 /* see Process.clock_gettime */
8980 rb_define_const(rb_mProcess, "CLOCK_REALTIME_COARSE", CLOCKID2NUM(CLOCK_REALTIME_COARSE));
8981 #endif
8982 #ifdef CLOCK_REALTIME_ALARM
8983 /* see Process.clock_gettime */
8984 rb_define_const(rb_mProcess, "CLOCK_REALTIME_ALARM", CLOCKID2NUM(CLOCK_REALTIME_ALARM));
8985 #endif
8986 #ifdef CLOCK_MONOTONIC_FAST
8987 /* see Process.clock_gettime */
8988 rb_define_const(rb_mProcess, "CLOCK_MONOTONIC_FAST", CLOCKID2NUM(CLOCK_MONOTONIC_FAST));
8989 #endif
8990 #ifdef CLOCK_MONOTONIC_PRECISE
8991 /* see Process.clock_gettime */
8992 rb_define_const(rb_mProcess, "CLOCK_MONOTONIC_PRECISE", CLOCKID2NUM(CLOCK_MONOTONIC_PRECISE));
8993 #endif
8994 #ifdef CLOCK_MONOTONIC_RAW
8995 /* see Process.clock_gettime */
8996 rb_define_const(rb_mProcess, "CLOCK_MONOTONIC_RAW", CLOCKID2NUM(CLOCK_MONOTONIC_RAW));
8997 #endif
8998 #ifdef CLOCK_MONOTONIC_RAW_APPROX
8999 /* see Process.clock_gettime */
9000 rb_define_const(rb_mProcess, "CLOCK_MONOTONIC_RAW_APPROX", CLOCKID2NUM(CLOCK_MONOTONIC_RAW_APPROX));
9001 #endif
9002 #ifdef CLOCK_MONOTONIC_COARSE
9003 /* see Process.clock_gettime */
9004 rb_define_const(rb_mProcess, "CLOCK_MONOTONIC_COARSE", CLOCKID2NUM(CLOCK_MONOTONIC_COARSE));
9005 #endif
9006 #ifdef CLOCK_BOOTTIME
9007 /* see Process.clock_gettime */
9008 rb_define_const(rb_mProcess, "CLOCK_BOOTTIME", CLOCKID2NUM(CLOCK_BOOTTIME));
9009 #endif
9010 #ifdef CLOCK_BOOTTIME_ALARM
9011 /* see Process.clock_gettime */
9012 rb_define_const(rb_mProcess, "CLOCK_BOOTTIME_ALARM", CLOCKID2NUM(CLOCK_BOOTTIME_ALARM));
9013 #endif
9014 #ifdef CLOCK_UPTIME
9015 /* see Process.clock_gettime */
9016 rb_define_const(rb_mProcess, "CLOCK_UPTIME", CLOCKID2NUM(CLOCK_UPTIME));
9017 #endif
9018 #ifdef CLOCK_UPTIME_FAST
9019 /* see Process.clock_gettime */
9020 rb_define_const(rb_mProcess, "CLOCK_UPTIME_FAST", CLOCKID2NUM(CLOCK_UPTIME_FAST));
9021 #endif
9022 #ifdef CLOCK_UPTIME_PRECISE
9023 /* see Process.clock_gettime */
9024 rb_define_const(rb_mProcess, "CLOCK_UPTIME_PRECISE", CLOCKID2NUM(CLOCK_UPTIME_PRECISE));
9025 #endif
9026 #ifdef CLOCK_UPTIME_RAW
9027 /* see Process.clock_gettime */
9028 rb_define_const(rb_mProcess, "CLOCK_UPTIME_RAW", CLOCKID2NUM(CLOCK_UPTIME_RAW));
9029 #endif
9030 #ifdef CLOCK_UPTIME_RAW_APPROX
9031 /* see Process.clock_gettime */
9032 rb_define_const(rb_mProcess, "CLOCK_UPTIME_RAW_APPROX", CLOCKID2NUM(CLOCK_UPTIME_RAW_APPROX));
9033 #endif
9034 #ifdef CLOCK_SECOND
9035 /* see Process.clock_gettime */
9036 rb_define_const(rb_mProcess, "CLOCK_SECOND", CLOCKID2NUM(CLOCK_SECOND));
9037 #endif
9038 #ifdef CLOCK_TAI
9039 /* see Process.clock_gettime */
9040 rb_define_const(rb_mProcess, "CLOCK_TAI", CLOCKID2NUM(CLOCK_TAI));
9041 #endif
9042 rb_define_module_function(rb_mProcess, "clock_gettime", rb_clock_gettime, -1);
9043 rb_define_module_function(rb_mProcess, "clock_getres", rb_clock_getres, -1);
9045 #if defined(HAVE_TIMES) || defined(_WIN32)
9046 /* Placeholder for rusage */
9047 rb_cProcessTms = rb_struct_define_under(rb_mProcess, "Tms", "utime", "stime", "cutime", "cstime", NULL);
9048 #endif
9050 SAVED_USER_ID = geteuid();
9051 SAVED_GROUP_ID = getegid();
9053 rb_mProcUID = rb_define_module_under(rb_mProcess, "UID");
9054 rb_mProcGID = rb_define_module_under(rb_mProcess, "GID");
9056 rb_define_module_function(rb_mProcUID, "rid", proc_getuid, 0);
9057 rb_define_module_function(rb_mProcGID, "rid", proc_getgid, 0);
9058 rb_define_module_function(rb_mProcUID, "eid", proc_geteuid, 0);
9059 rb_define_module_function(rb_mProcGID, "eid", proc_getegid, 0);
9060 rb_define_module_function(rb_mProcUID, "change_privilege", p_uid_change_privilege, 1);
9061 rb_define_module_function(rb_mProcGID, "change_privilege", p_gid_change_privilege, 1);
9062 rb_define_module_function(rb_mProcUID, "grant_privilege", p_uid_grant_privilege, 1);
9063 rb_define_module_function(rb_mProcGID, "grant_privilege", p_gid_grant_privilege, 1);
9064 rb_define_alias(rb_singleton_class(rb_mProcUID), "eid=", "grant_privilege");
9065 rb_define_alias(rb_singleton_class(rb_mProcGID), "eid=", "grant_privilege");
9066 rb_define_module_function(rb_mProcUID, "re_exchange", p_uid_exchange, 0);
9067 rb_define_module_function(rb_mProcGID, "re_exchange", p_gid_exchange, 0);
9068 rb_define_module_function(rb_mProcUID, "re_exchangeable?", p_uid_exchangeable, 0);
9069 rb_define_module_function(rb_mProcGID, "re_exchangeable?", p_gid_exchangeable, 0);
9070 rb_define_module_function(rb_mProcUID, "sid_available?", p_uid_have_saved_id, 0);
9071 rb_define_module_function(rb_mProcGID, "sid_available?", p_gid_have_saved_id, 0);
9072 rb_define_module_function(rb_mProcUID, "switch", p_uid_switch, 0);
9073 rb_define_module_function(rb_mProcGID, "switch", p_gid_switch, 0);
9074 #ifdef p_uid_from_name
9075 rb_define_module_function(rb_mProcUID, "from_name", p_uid_from_name, 1);
9076 #endif
9077 #ifdef p_gid_from_name
9078 rb_define_module_function(rb_mProcGID, "from_name", p_gid_from_name, 1);
9079 #endif
9081 rb_mProcID_Syscall = rb_define_module_under(rb_mProcess, "Sys");
9083 rb_define_module_function(rb_mProcID_Syscall, "getuid", proc_getuid, 0);
9084 rb_define_module_function(rb_mProcID_Syscall, "geteuid", proc_geteuid, 0);
9085 rb_define_module_function(rb_mProcID_Syscall, "getgid", proc_getgid, 0);
9086 rb_define_module_function(rb_mProcID_Syscall, "getegid", proc_getegid, 0);
9088 rb_define_module_function(rb_mProcID_Syscall, "setuid", p_sys_setuid, 1);
9089 rb_define_module_function(rb_mProcID_Syscall, "setgid", p_sys_setgid, 1);
9091 rb_define_module_function(rb_mProcID_Syscall, "setruid", p_sys_setruid, 1);
9092 rb_define_module_function(rb_mProcID_Syscall, "setrgid", p_sys_setrgid, 1);
9094 rb_define_module_function(rb_mProcID_Syscall, "seteuid", p_sys_seteuid, 1);
9095 rb_define_module_function(rb_mProcID_Syscall, "setegid", p_sys_setegid, 1);
9097 rb_define_module_function(rb_mProcID_Syscall, "setreuid", p_sys_setreuid, 2);
9098 rb_define_module_function(rb_mProcID_Syscall, "setregid", p_sys_setregid, 2);
9100 rb_define_module_function(rb_mProcID_Syscall, "setresuid", p_sys_setresuid, 3);
9101 rb_define_module_function(rb_mProcID_Syscall, "setresgid", p_sys_setresgid, 3);
9102 rb_define_module_function(rb_mProcID_Syscall, "issetugid", p_sys_issetugid, 0);
9105 void
9106 Init_process(void)
9108 id_in = rb_intern_const("in");
9109 id_out = rb_intern_const("out");
9110 id_err = rb_intern_const("err");
9111 id_pid = rb_intern_const("pid");
9112 id_uid = rb_intern_const("uid");
9113 id_gid = rb_intern_const("gid");
9114 id_close = rb_intern_const("close");
9115 id_child = rb_intern_const("child");
9116 #ifdef HAVE_SETPGID
9117 id_pgroup = rb_intern_const("pgroup");
9118 #endif
9119 #ifdef _WIN32
9120 id_new_pgroup = rb_intern_const("new_pgroup");
9121 #endif
9122 id_unsetenv_others = rb_intern_const("unsetenv_others");
9123 id_chdir = rb_intern_const("chdir");
9124 id_umask = rb_intern_const("umask");
9125 id_close_others = rb_intern_const("close_others");
9126 id_nanosecond = rb_intern_const("nanosecond");
9127 id_microsecond = rb_intern_const("microsecond");
9128 id_millisecond = rb_intern_const("millisecond");
9129 id_second = rb_intern_const("second");
9130 id_float_microsecond = rb_intern_const("float_microsecond");
9131 id_float_millisecond = rb_intern_const("float_millisecond");
9132 id_float_second = rb_intern_const("float_second");
9133 id_GETTIMEOFDAY_BASED_CLOCK_REALTIME = rb_intern_const("GETTIMEOFDAY_BASED_CLOCK_REALTIME");
9134 id_TIME_BASED_CLOCK_REALTIME = rb_intern_const("TIME_BASED_CLOCK_REALTIME");
9135 #ifdef HAVE_TIMES
9136 id_TIMES_BASED_CLOCK_MONOTONIC = rb_intern_const("TIMES_BASED_CLOCK_MONOTONIC");
9137 id_TIMES_BASED_CLOCK_PROCESS_CPUTIME_ID = rb_intern_const("TIMES_BASED_CLOCK_PROCESS_CPUTIME_ID");
9138 #endif
9139 #ifdef RUSAGE_SELF
9140 id_GETRUSAGE_BASED_CLOCK_PROCESS_CPUTIME_ID = rb_intern_const("GETRUSAGE_BASED_CLOCK_PROCESS_CPUTIME_ID");
9141 #endif
9142 id_CLOCK_BASED_CLOCK_PROCESS_CPUTIME_ID = rb_intern_const("CLOCK_BASED_CLOCK_PROCESS_CPUTIME_ID");
9143 #ifdef __APPLE__
9144 id_MACH_ABSOLUTE_TIME_BASED_CLOCK_MONOTONIC = rb_intern_const("MACH_ABSOLUTE_TIME_BASED_CLOCK_MONOTONIC");
9145 #endif
9146 id_hertz = rb_intern_const("hertz");
9148 InitVM(process);