Ruby 3.2.4p170 (2024-04-23 revision af471c0e0127eea0cafa6f308c0425bbfab0acf5)
process.c
1/**********************************************************************
2
3 process.c -
4
5 $Author$
6 created at: Tue Aug 10 14:30:50 JST 1993
7
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
11
12**********************************************************************/
13
14#include "ruby/internal/config.h"
15
17
18#include <ctype.h>
19#include <errno.h>
20#include <signal.h>
21#include <stdarg.h>
22#include <stdio.h>
23#include <time.h>
24
25#ifdef HAVE_STDLIB_H
26# include <stdlib.h>
27#endif
28
29#ifdef HAVE_UNISTD_H
30# include <unistd.h>
31#endif
32
33#ifdef HAVE_FCNTL_H
34# include <fcntl.h>
35#endif
36
37#ifdef HAVE_PROCESS_H
38# include <process.h>
39#endif
40
41#ifndef EXIT_SUCCESS
42# define EXIT_SUCCESS 0
43#endif
44
45#ifndef EXIT_FAILURE
46# define EXIT_FAILURE 1
47#endif
48
49#ifdef HAVE_SYS_WAIT_H
50# include <sys/wait.h>
51#endif
52
53#ifdef HAVE_SYS_RESOURCE_H
54# include <sys/resource.h>
55#endif
56
57#ifdef HAVE_VFORK_H
58# include <vfork.h>
59#endif
60
61#ifdef HAVE_SYS_PARAM_H
62# include <sys/param.h>
63#endif
64
65#ifndef MAXPATHLEN
66# define MAXPATHLEN 1024
67#endif
68
69#include <sys/stat.h>
70
71#ifdef HAVE_SYS_TIME_H
72# include <sys/time.h>
73#endif
74
75#ifdef HAVE_SYS_TIMES_H
76# include <sys/times.h>
77#endif
78
79#ifdef HAVE_PWD_H
80# include <pwd.h>
81#endif
82
83#ifdef HAVE_GRP_H
84# include <grp.h>
85# ifdef __CYGWIN__
86int initgroups(const char *, rb_gid_t);
87# endif
88#endif
89
90#ifdef HAVE_SYS_ID_H
91# include <sys/id.h>
92#endif
93
94#ifdef __APPLE__
95# include <mach/mach_time.h>
96#endif
97
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"
119
120/* define system APIs */
121#ifdef _WIN32
122#undef open
123#define open rb_w32_uopen
124#endif
125
126#if defined(HAVE_TIMES) || defined(_WIN32)
127/*********************************************************************
128 *
129 * Document-class: Process::Tms
130 *
131 * Placeholder for rusage
132 */
133static VALUE rb_cProcessTms;
134#endif
135
136#ifndef WIFEXITED
137#define WIFEXITED(w) (((w) & 0xff) == 0)
138#endif
139#ifndef WIFSIGNALED
140#define WIFSIGNALED(w) (((w) & 0x7f) > 0 && (((w) & 0x7f) < 0x7f))
141#endif
142#ifndef WIFSTOPPED
143#define WIFSTOPPED(w) (((w) & 0xff) == 0x7f)
144#endif
145#ifndef WEXITSTATUS
146#define WEXITSTATUS(w) (((w) >> 8) & 0xff)
147#endif
148#ifndef WTERMSIG
149#define WTERMSIG(w) ((w) & 0x7f)
150#endif
151#ifndef WSTOPSIG
152#define WSTOPSIG WEXITSTATUS
153#endif
154
155#if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__bsdi__)
156#define HAVE_44BSD_SETUID 1
157#define HAVE_44BSD_SETGID 1
158#endif
159
160#ifdef __NetBSD__
161#undef HAVE_SETRUID
162#undef HAVE_SETRGID
163#endif
164
165#ifdef BROKEN_SETREUID
166#define setreuid ruby_setreuid
167int setreuid(rb_uid_t ruid, rb_uid_t euid);
168#endif
169#ifdef BROKEN_SETREGID
170#define setregid ruby_setregid
171int setregid(rb_gid_t rgid, rb_gid_t egid);
172#endif
173
174#if defined(HAVE_44BSD_SETUID) || defined(__APPLE__)
175#if !defined(USE_SETREUID) && !defined(BROKEN_SETREUID)
176#define OBSOLETE_SETREUID 1
177#endif
178#if !defined(USE_SETREGID) && !defined(BROKEN_SETREGID)
179#define OBSOLETE_SETREGID 1
180#endif
181#endif
182
183static void check_uid_switch(void);
184static void check_gid_switch(void);
185static int exec_async_signal_safe(const struct rb_execarg *, char *, size_t);
186
187VALUE rb_envtbl(void);
188VALUE rb_env_to_hash(void);
189
190#if 1
191#define p_uid_from_name p_uid_from_name
192#define p_gid_from_name p_gid_from_name
193#endif
194
195#if defined(HAVE_UNISTD_H)
196# if defined(HAVE_GETLOGIN_R)
197# define USE_GETLOGIN_R 1
198# define GETLOGIN_R_SIZE_DEFAULT 0x100
199# define GETLOGIN_R_SIZE_LIMIT 0x1000
200# if defined(_SC_LOGIN_NAME_MAX)
201# define GETLOGIN_R_SIZE_INIT sysconf(_SC_LOGIN_NAME_MAX)
202# else
203# define GETLOGIN_R_SIZE_INIT GETLOGIN_R_SIZE_DEFAULT
204# endif
205# elif defined(HAVE_GETLOGIN)
206# define USE_GETLOGIN 1
207# endif
208#endif
209
210#if defined(HAVE_PWD_H)
211# if defined(HAVE_GETPWUID_R)
212# define USE_GETPWUID_R 1
213# elif defined(HAVE_GETPWUID)
214# define USE_GETPWUID 1
215# endif
216# if defined(HAVE_GETPWNAM_R)
217# define USE_GETPWNAM_R 1
218# elif defined(HAVE_GETPWNAM)
219# define USE_GETPWNAM 1
220# endif
221# if defined(HAVE_GETPWNAM_R) || defined(HAVE_GETPWUID_R)
222# define GETPW_R_SIZE_DEFAULT 0x1000
223# define GETPW_R_SIZE_LIMIT 0x10000
224# if defined(_SC_GETPW_R_SIZE_MAX)
225# define GETPW_R_SIZE_INIT sysconf(_SC_GETPW_R_SIZE_MAX)
226# else
227# define GETPW_R_SIZE_INIT GETPW_R_SIZE_DEFAULT
228# endif
229# endif
230# ifdef USE_GETPWNAM_R
231# define PREPARE_GETPWNAM \
232 VALUE getpw_buf = 0
233# define FINISH_GETPWNAM \
234 (getpw_buf ? (void)rb_str_resize(getpw_buf, 0) : (void)0)
235# define OBJ2UID1(id) obj2uid((id), &getpw_buf)
236# define OBJ2UID(id) obj2uid0(id)
237static rb_uid_t obj2uid(VALUE id, VALUE *getpw_buf);
238static inline rb_uid_t
239obj2uid0(VALUE id)
240{
241 rb_uid_t uid;
242 PREPARE_GETPWNAM;
243 uid = OBJ2UID1(id);
244 FINISH_GETPWNAM;
245 return uid;
246}
247# else
248# define PREPARE_GETPWNAM /* do nothing */
249# define FINISH_GETPWNAM /* do nothing */
250# define OBJ2UID1(id) obj2uid((id))
251# define OBJ2UID(id) obj2uid((id))
252static rb_uid_t obj2uid(VALUE id);
253# endif
254#else
255# define PREPARE_GETPWNAM /* do nothing */
256# define FINISH_GETPWNAM /* do nothing */
257# define OBJ2UID1(id) NUM2UIDT(id)
258# define OBJ2UID(id) NUM2UIDT(id)
259# ifdef p_uid_from_name
260# undef p_uid_from_name
261# define p_uid_from_name rb_f_notimplement
262# endif
263#endif
264
265#if defined(HAVE_GRP_H)
266# if defined(HAVE_GETGRNAM_R) && defined(_SC_GETGR_R_SIZE_MAX)
267# define USE_GETGRNAM_R
268# define GETGR_R_SIZE_INIT sysconf(_SC_GETGR_R_SIZE_MAX)
269# define GETGR_R_SIZE_DEFAULT 0x1000
270# define GETGR_R_SIZE_LIMIT 0x10000
271# endif
272# ifdef USE_GETGRNAM_R
273# define PREPARE_GETGRNAM \
274 VALUE getgr_buf = 0
275# define FINISH_GETGRNAM \
276 (getgr_buf ? (void)rb_str_resize(getgr_buf, 0) : (void)0)
277# define OBJ2GID1(id) obj2gid((id), &getgr_buf)
278# define OBJ2GID(id) obj2gid0(id)
279static rb_gid_t obj2gid(VALUE id, VALUE *getgr_buf);
280static inline rb_gid_t
281obj2gid0(VALUE id)
282{
283 rb_gid_t gid;
284 PREPARE_GETGRNAM;
285 gid = OBJ2GID1(id);
286 FINISH_GETGRNAM;
287 return gid;
288}
289static rb_gid_t obj2gid(VALUE id, VALUE *getgr_buf);
290# else
291# define PREPARE_GETGRNAM /* do nothing */
292# define FINISH_GETGRNAM /* do nothing */
293# define OBJ2GID1(id) obj2gid((id))
294# define OBJ2GID(id) obj2gid((id))
295static rb_gid_t obj2gid(VALUE id);
296# endif
297#else
298# define PREPARE_GETGRNAM /* do nothing */
299# define FINISH_GETGRNAM /* do nothing */
300# define OBJ2GID1(id) NUM2GIDT(id)
301# define OBJ2GID(id) NUM2GIDT(id)
302# ifdef p_gid_from_name
303# undef p_gid_from_name
304# define p_gid_from_name rb_f_notimplement
305# endif
306#endif
307
308#if SIZEOF_CLOCK_T == SIZEOF_INT
309typedef unsigned int unsigned_clock_t;
310#elif SIZEOF_CLOCK_T == SIZEOF_LONG
311typedef unsigned long unsigned_clock_t;
312#elif defined(HAVE_LONG_LONG) && SIZEOF_CLOCK_T == SIZEOF_LONG_LONG
313typedef unsigned LONG_LONG unsigned_clock_t;
314#endif
315#ifndef HAVE_SIG_T
316typedef void (*sig_t) (int);
317#endif
318
319#define id_exception idException
320static ID id_in, id_out, id_err, id_pid, id_uid, id_gid;
321static ID id_close, id_child;
322#ifdef HAVE_SETPGID
323static ID id_pgroup;
324#endif
325#ifdef _WIN32
326static ID id_new_pgroup;
327#endif
328static ID id_unsetenv_others, id_chdir, id_umask, id_close_others;
329static ID id_nanosecond, id_microsecond, id_millisecond, id_second;
330static ID id_float_microsecond, id_float_millisecond, id_float_second;
331static ID id_GETTIMEOFDAY_BASED_CLOCK_REALTIME, id_TIME_BASED_CLOCK_REALTIME;
332#ifdef CLOCK_REALTIME
333static ID id_CLOCK_REALTIME;
334# define RUBY_CLOCK_REALTIME ID2SYM(id_CLOCK_REALTIME)
335#endif
336#ifdef CLOCK_MONOTONIC
337static ID id_CLOCK_MONOTONIC;
338# define RUBY_CLOCK_MONOTONIC ID2SYM(id_CLOCK_MONOTONIC)
339#endif
340#ifdef CLOCK_PROCESS_CPUTIME_ID
341static ID id_CLOCK_PROCESS_CPUTIME_ID;
342# define RUBY_CLOCK_PROCESS_CPUTIME_ID ID2SYM(id_CLOCK_PROCESS_CPUTIME_ID)
343#endif
344#ifdef CLOCK_THREAD_CPUTIME_ID
345static ID id_CLOCK_THREAD_CPUTIME_ID;
346# define RUBY_CLOCK_THREAD_CPUTIME_ID ID2SYM(id_CLOCK_THREAD_CPUTIME_ID)
347#endif
348#ifdef HAVE_TIMES
349static ID id_TIMES_BASED_CLOCK_MONOTONIC;
350static ID id_TIMES_BASED_CLOCK_PROCESS_CPUTIME_ID;
351#endif
352#ifdef RUSAGE_SELF
353static ID id_GETRUSAGE_BASED_CLOCK_PROCESS_CPUTIME_ID;
354#endif
355static ID id_CLOCK_BASED_CLOCK_PROCESS_CPUTIME_ID;
356#ifdef __APPLE__
357static ID id_MACH_ABSOLUTE_TIME_BASED_CLOCK_MONOTONIC;
358# define RUBY_MACH_ABSOLUTE_TIME_BASED_CLOCK_MONOTONIC ID2SYM(id_MACH_ABSOLUTE_TIME_BASED_CLOCK_MONOTONIC)
359#endif
360static ID id_hertz;
361
362/* execv and execl are async-signal-safe since SUSv4 (POSIX.1-2008, XPG7) */
363#if defined(__sun) && !defined(_XPG7) /* Solaris 10, 9, ... */
364#define execv(path, argv) (rb_async_bug_errno("unreachable: async-signal-unsafe execv() is called", 0))
365#define execl(path, arg0, arg1, arg2, term) do { extern char **environ; execle((path), (arg0), (arg1), (arg2), (term), (environ)); } while (0)
366#define ALWAYS_NEED_ENVP 1
367#else
368#define ALWAYS_NEED_ENVP 0
369#endif
370
371static void
372assert_close_on_exec(int fd)
373{
374#if VM_CHECK_MODE > 0
375#if defined(HAVE_FCNTL) && defined(F_GETFD) && defined(FD_CLOEXEC)
376 int flags = fcntl(fd, F_GETFD);
377 if (flags == -1) {
378 static const char m[] = "reserved FD closed unexpectedly?\n";
379 (void)!write(2, m, sizeof(m) - 1);
380 return;
381 }
382 if (flags & FD_CLOEXEC) return;
383 rb_bug("reserved FD did not have close-on-exec set");
384#else
385 rb_bug("reserved FD without close-on-exec support");
386#endif /* FD_CLOEXEC */
387#endif /* VM_CHECK_MODE */
388}
389
390static inline int
391close_unless_reserved(int fd)
392{
393 if (rb_reserved_fd_p(fd)) { /* async-signal-safe */
394 assert_close_on_exec(fd);
395 return 0;
396 }
397 return close(fd); /* async-signal-safe */
398}
399
400/*#define DEBUG_REDIRECT*/
401#if defined(DEBUG_REDIRECT)
402
403static void
404ttyprintf(const char *fmt, ...)
405{
406 va_list ap;
407 FILE *tty;
408 int save = errno;
409#ifdef _WIN32
410 tty = fopen("con", "w");
411#else
412 tty = fopen("/dev/tty", "w");
413#endif
414 if (!tty)
415 return;
416
417 va_start(ap, fmt);
418 vfprintf(tty, fmt, ap);
419 va_end(ap);
420 fclose(tty);
421 errno = save;
422}
423
424static int
425redirect_dup(int oldfd)
426{
427 int ret;
428 ret = dup(oldfd);
429 ttyprintf("dup(%d) => %d\n", oldfd, ret);
430 return ret;
431}
432
433static int
434redirect_dup2(int oldfd, int newfd)
435{
436 int ret;
437 ret = dup2(oldfd, newfd);
438 ttyprintf("dup2(%d, %d) => %d\n", oldfd, newfd, ret);
439 return ret;
440}
441
442static int
443redirect_cloexec_dup(int oldfd)
444{
445 int ret;
446 ret = rb_cloexec_dup(oldfd);
447 ttyprintf("cloexec_dup(%d) => %d\n", oldfd, ret);
448 return ret;
449}
450
451static int
452redirect_cloexec_dup2(int oldfd, int newfd)
453{
454 int ret;
455 ret = rb_cloexec_dup2(oldfd, newfd);
456 ttyprintf("cloexec_dup2(%d, %d) => %d\n", oldfd, newfd, ret);
457 return ret;
458}
459
460static int
461redirect_close(int fd)
462{
463 int ret;
464 ret = close_unless_reserved(fd);
465 ttyprintf("close(%d) => %d\n", fd, ret);
466 return ret;
467}
468
469static int
470parent_redirect_open(const char *pathname, int flags, mode_t perm)
471{
472 int ret;
473 ret = rb_cloexec_open(pathname, flags, perm);
474 ttyprintf("parent_open(\"%s\", 0x%x, 0%o) => %d\n", pathname, flags, perm, ret);
475 return ret;
476}
477
478static int
479parent_redirect_close(int fd)
480{
481 int ret;
482 ret = close_unless_reserved(fd);
483 ttyprintf("parent_close(%d) => %d\n", fd, ret);
484 return ret;
485}
486
487#else
488#define redirect_dup(oldfd) dup(oldfd)
489#define redirect_dup2(oldfd, newfd) dup2((oldfd), (newfd))
490#define redirect_cloexec_dup(oldfd) rb_cloexec_dup(oldfd)
491#define redirect_cloexec_dup2(oldfd, newfd) rb_cloexec_dup2((oldfd), (newfd))
492#define redirect_close(fd) close_unless_reserved(fd)
493#define parent_redirect_open(pathname, flags, perm) rb_cloexec_open((pathname), (flags), (perm))
494#define parent_redirect_close(fd) close_unless_reserved(fd)
495#endif
496
497/*
498 * Document-module: Process
499 *
500 * The module contains several groups of functionality for handling OS processes:
501 *
502 * * Low-level property introspection and management of the current process, like
503 * Process.argv0, Process.pid;
504 * * Low-level introspection of other processes, like Process.getpgid, Process.getpriority;
505 * * Management of the current process: Process.abort, Process.exit, Process.daemon, etc.
506 * (for convenience, most of those are also available as global functions
507 * and module functions of Kernel);
508 * * Creation and management of child processes: Process.fork, Process.spawn, and
509 * related methods;
510 * * Management of low-level system clock: Process.times and Process.clock_gettime,
511 * which could be important for proper benchmarking and other elapsed
512 * time measurement tasks.
513 */
514
515static VALUE
516get_pid(void)
517{
518 return PIDT2NUM(getpid());
519}
520
521/*
522 * call-seq:
523 * Process.pid -> integer
524 *
525 * Returns the process id of this process. Not available on all
526 * platforms.
527 *
528 * Process.pid #=> 27415
529 */
530
531static VALUE
532proc_get_pid(VALUE _)
533{
534 return get_pid();
535}
536
537static VALUE
538get_ppid(void)
539{
540 return PIDT2NUM(getppid());
541}
542
543/*
544 * call-seq:
545 * Process.ppid -> integer
546 *
547 * Returns the process id of the parent of this process. Returns
548 * untrustworthy value on Win32/64. Not available on all platforms.
549 *
550 * puts "I am #{Process.pid}"
551 * Process.fork { puts "Dad is #{Process.ppid}" }
552 *
553 * <em>produces:</em>
554 *
555 * I am 27417
556 * Dad is 27417
557 */
558
559static VALUE
560proc_get_ppid(VALUE _)
561{
562 return get_ppid();
563}
564
565
566/*********************************************************************
567 *
568 * Document-class: Process::Status
569 *
570 * Process::Status encapsulates the information on the
571 * status of a running or terminated system process. The built-in
572 * variable <code>$?</code> is either +nil+ or a
573 * Process::Status object.
574 *
575 * fork { exit 99 } #=> 26557
576 * Process.wait #=> 26557
577 * $?.class #=> Process::Status
578 * $?.to_i #=> 25344
579 * $? >> 8 #=> 99
580 * $?.stopped? #=> false
581 * $?.exited? #=> true
582 * $?.exitstatus #=> 99
583 *
584 * Posix systems record information on processes using a 16-bit
585 * integer. The lower bits record the process status (stopped,
586 * exited, signaled) and the upper bits possibly contain additional
587 * information (for example the program's return code in the case of
588 * exited processes). Pre Ruby 1.8, these bits were exposed directly
589 * to the Ruby program. Ruby now encapsulates these in a
590 * Process::Status object. To maximize compatibility,
591 * however, these objects retain a bit-oriented interface. In the
592 * descriptions that follow, when we talk about the integer value of
593 * _stat_, we're referring to this 16 bit value.
594 */
595
596static VALUE rb_cProcessStatus;
597
599 rb_pid_t pid;
600 int status;
601 int error;
602};
603
604static const rb_data_type_t rb_process_status_type = {
605 .wrap_struct_name = "Process::Status",
606 .function = {
607 .dfree = RUBY_DEFAULT_FREE,
608 },
609 .data = NULL,
610 .flags = RUBY_TYPED_FREE_IMMEDIATELY,
611};
612
613static VALUE
614rb_process_status_allocate(VALUE klass)
615{
616 struct rb_process_status *data = NULL;
617
618 return TypedData_Make_Struct(klass, struct rb_process_status, &rb_process_status_type, data);
619}
620
621VALUE
623{
624 return GET_THREAD()->last_status;
625}
626
627/*
628 * call-seq:
629 * Process.last_status -> Process::Status or nil
630 *
631 * Returns the status of the last executed child process in the
632 * current thread.
633 *
634 * Process.wait Process.spawn("ruby", "-e", "exit 13")
635 * Process.last_status #=> #<Process::Status: pid 4825 exit 13>
636 *
637 * If no child process has ever been executed in the current
638 * thread, this returns +nil+.
639 *
640 * Process.last_status #=> nil
641 */
642static VALUE
643proc_s_last_status(VALUE mod)
644{
645 return rb_last_status_get();
646}
647
648VALUE
649rb_process_status_new(rb_pid_t pid, int status, int error)
650{
651 VALUE last_status = rb_process_status_allocate(rb_cProcessStatus);
652
653 struct rb_process_status *data = RTYPEDDATA_DATA(last_status);
654 data->pid = pid;
655 data->status = status;
656 data->error = error;
657
658 rb_obj_freeze(last_status);
659 return last_status;
660}
661
662static VALUE
663process_status_dump(VALUE status)
664{
665 VALUE dump = rb_class_new_instance(0, 0, rb_cObject);
666 struct rb_process_status *data = RTYPEDDATA_DATA(status);
667 if (data->pid) {
668 rb_ivar_set(dump, id_status, INT2NUM(data->status));
669 rb_ivar_set(dump, id_pid, PIDT2NUM(data->pid));
670 }
671 return dump;
672}
673
674static VALUE
675process_status_load(VALUE real_obj, VALUE load_obj)
676{
677 struct rb_process_status *data = rb_check_typeddata(real_obj, &rb_process_status_type);
678 VALUE status = rb_attr_get(load_obj, id_status);
679 VALUE pid = rb_attr_get(load_obj, id_pid);
680 data->pid = NIL_P(pid) ? 0 : NUM2PIDT(pid);
681 data->status = NIL_P(status) ? 0 : NUM2INT(status);
682 return real_obj;
683}
684
685void
686rb_last_status_set(int status, rb_pid_t pid)
687{
688 GET_THREAD()->last_status = rb_process_status_new(pid, status, 0);
689}
690
691void
692rb_last_status_clear(void)
693{
694 GET_THREAD()->last_status = Qnil;
695}
696
697static rb_pid_t
698pst_pid(VALUE pst)
699{
700 struct rb_process_status *data = RTYPEDDATA_DATA(pst);
701 return data->pid;
702}
703
704static int
705pst_status(VALUE pst)
706{
707 struct rb_process_status *data = RTYPEDDATA_DATA(pst);
708 return data->status;
709}
710
711/*
712 * call-seq:
713 * stat.to_i -> integer
714 *
715 * Returns the bits in _stat_ as an Integer. Poking
716 * around in these bits is platform dependent.
717 *
718 * fork { exit 0xab } #=> 26566
719 * Process.wait #=> 26566
720 * sprintf('%04x', $?.to_i) #=> "ab00"
721 */
722
723static VALUE
724pst_to_i(VALUE self)
725{
726 int status = pst_status(self);
727 return RB_INT2NUM(status);
728}
729
730#define PST2INT(st) pst_status(st)
731
732/*
733 * call-seq:
734 * stat.pid -> integer
735 *
736 * Returns the process ID that this status object represents.
737 *
738 * fork { exit } #=> 26569
739 * Process.wait #=> 26569
740 * $?.pid #=> 26569
741 */
742
743static VALUE
744pst_pid_m(VALUE self)
745{
746 rb_pid_t pid = pst_pid(self);
747 return PIDT2NUM(pid);
748}
749
750static VALUE pst_message_status(VALUE str, int status);
751
752static void
753pst_message(VALUE str, rb_pid_t pid, int status)
754{
755 rb_str_catf(str, "pid %ld", (long)pid);
756 pst_message_status(str, status);
757}
758
759static VALUE
760pst_message_status(VALUE str, int status)
761{
762 if (WIFSTOPPED(status)) {
763 int stopsig = WSTOPSIG(status);
764 const char *signame = ruby_signal_name(stopsig);
765 if (signame) {
766 rb_str_catf(str, " stopped SIG%s (signal %d)", signame, stopsig);
767 }
768 else {
769 rb_str_catf(str, " stopped signal %d", stopsig);
770 }
771 }
772 if (WIFSIGNALED(status)) {
773 int termsig = WTERMSIG(status);
774 const char *signame = ruby_signal_name(termsig);
775 if (signame) {
776 rb_str_catf(str, " SIG%s (signal %d)", signame, termsig);
777 }
778 else {
779 rb_str_catf(str, " signal %d", termsig);
780 }
781 }
782 if (WIFEXITED(status)) {
783 rb_str_catf(str, " exit %d", WEXITSTATUS(status));
784 }
785#ifdef WCOREDUMP
786 if (WCOREDUMP(status)) {
787 rb_str_cat2(str, " (core dumped)");
788 }
789#endif
790 return str;
791}
792
793
794/*
795 * call-seq:
796 * stat.to_s -> string
797 *
798 * Show pid and exit status as a string.
799 *
800 * system("false")
801 * p $?.to_s #=> "pid 12766 exit 1"
802 *
803 */
804
805static VALUE
806pst_to_s(VALUE st)
807{
808 rb_pid_t pid;
809 int status;
810 VALUE str;
811
812 pid = pst_pid(st);
813 status = PST2INT(st);
814
815 str = rb_str_buf_new(0);
816 pst_message(str, pid, status);
817 return str;
818}
819
820
821/*
822 * call-seq:
823 * stat.inspect -> string
824 *
825 * Override the inspection method.
826 *
827 * system("false")
828 * p $?.inspect #=> "#<Process::Status: pid 12861 exit 1>"
829 *
830 */
831
832static VALUE
833pst_inspect(VALUE st)
834{
835 rb_pid_t pid;
836 int status;
837 VALUE str;
838
839 pid = pst_pid(st);
840 if (!pid) {
841 return rb_sprintf("#<%s: uninitialized>", rb_class2name(CLASS_OF(st)));
842 }
843 status = PST2INT(st);
844
845 str = rb_sprintf("#<%s: ", rb_class2name(CLASS_OF(st)));
846 pst_message(str, pid, status);
847 rb_str_cat2(str, ">");
848 return str;
849}
850
851
852/*
853 * call-seq:
854 * stat == other -> true or false
855 *
856 * Returns +true+ if the integer value of _stat_
857 * equals <em>other</em>.
858 */
859
860static VALUE
861pst_equal(VALUE st1, VALUE st2)
862{
863 if (st1 == st2) return Qtrue;
864 return rb_equal(pst_to_i(st1), st2);
865}
866
867
868/*
869 * call-seq:
870 * stat & num -> integer
871 *
872 * Logical AND of the bits in _stat_ with <em>num</em>.
873 *
874 * fork { exit 0x37 }
875 * Process.wait
876 * sprintf('%04x', $?.to_i) #=> "3700"
877 * sprintf('%04x', $? & 0x1e00) #=> "1600"
878 */
879
880static VALUE
881pst_bitand(VALUE st1, VALUE st2)
882{
883 int status = PST2INT(st1) & NUM2INT(st2);
884
885 return INT2NUM(status);
886}
887
888
889/*
890 * call-seq:
891 * stat >> num -> integer
892 *
893 * Shift the bits in _stat_ right <em>num</em> places.
894 *
895 * fork { exit 99 } #=> 26563
896 * Process.wait #=> 26563
897 * $?.to_i #=> 25344
898 * $? >> 8 #=> 99
899 */
900
901static VALUE
902pst_rshift(VALUE st1, VALUE st2)
903{
904 int status = PST2INT(st1) >> NUM2INT(st2);
905
906 return INT2NUM(status);
907}
908
909
910/*
911 * call-seq:
912 * stat.stopped? -> true or false
913 *
914 * Returns +true+ if this process is stopped. This is only returned
915 * if the corresponding #wait call had the Process::WUNTRACED flag
916 * set.
917 */
918
919static VALUE
920pst_wifstopped(VALUE st)
921{
922 int status = PST2INT(st);
923
924 return RBOOL(WIFSTOPPED(status));
925}
926
927
928/*
929 * call-seq:
930 * stat.stopsig -> integer or nil
931 *
932 * Returns the number of the signal that caused _stat_ to stop
933 * (or +nil+ if self is not stopped).
934 */
935
936static VALUE
937pst_wstopsig(VALUE st)
938{
939 int status = PST2INT(st);
940
941 if (WIFSTOPPED(status))
942 return INT2NUM(WSTOPSIG(status));
943 return Qnil;
944}
945
946
947/*
948 * call-seq:
949 * stat.signaled? -> true or false
950 *
951 * Returns +true+ if _stat_ terminated because of
952 * an uncaught signal.
953 */
954
955static VALUE
956pst_wifsignaled(VALUE st)
957{
958 int status = PST2INT(st);
959
960 return RBOOL(WIFSIGNALED(status));
961}
962
963
964/*
965 * call-seq:
966 * stat.termsig -> integer or nil
967 *
968 * Returns the number of the signal that caused _stat_ to
969 * terminate (or +nil+ if self was not terminated by an
970 * uncaught signal).
971 */
972
973static VALUE
974pst_wtermsig(VALUE st)
975{
976 int status = PST2INT(st);
977
978 if (WIFSIGNALED(status))
979 return INT2NUM(WTERMSIG(status));
980 return Qnil;
981}
982
983
984/*
985 * call-seq:
986 * stat.exited? -> true or false
987 *
988 * Returns +true+ if _stat_ exited normally (for
989 * example using an <code>exit()</code> call or finishing the
990 * program).
991 */
992
993static VALUE
994pst_wifexited(VALUE st)
995{
996 int status = PST2INT(st);
997
998 return RBOOL(WIFEXITED(status));
999}
1000
1001
1002/*
1003 * call-seq:
1004 * stat.exitstatus -> integer or nil
1005 *
1006 * Returns the least significant eight bits of the return code of
1007 * _stat_. Only available if #exited? is +true+.
1008 *
1009 * fork { } #=> 26572
1010 * Process.wait #=> 26572
1011 * $?.exited? #=> true
1012 * $?.exitstatus #=> 0
1013 *
1014 * fork { exit 99 } #=> 26573
1015 * Process.wait #=> 26573
1016 * $?.exited? #=> true
1017 * $?.exitstatus #=> 99
1018 */
1019
1020static VALUE
1021pst_wexitstatus(VALUE st)
1022{
1023 int status = PST2INT(st);
1024
1025 if (WIFEXITED(status))
1026 return INT2NUM(WEXITSTATUS(status));
1027 return Qnil;
1028}
1029
1030
1031/*
1032 * call-seq:
1033 * stat.success? -> true, false or nil
1034 *
1035 * Returns +true+ if _stat_ is successful, +false+ if not.
1036 * Returns +nil+ if #exited? is not +true+.
1037 */
1038
1039static VALUE
1040pst_success_p(VALUE st)
1041{
1042 int status = PST2INT(st);
1043
1044 if (!WIFEXITED(status))
1045 return Qnil;
1046 return RBOOL(WEXITSTATUS(status) == EXIT_SUCCESS);
1047}
1048
1049
1050/*
1051 * call-seq:
1052 * stat.coredump? -> true or false
1053 *
1054 * Returns +true+ if _stat_ generated a coredump
1055 * when it terminated. Not available on all platforms.
1056 */
1057
1058static VALUE
1059pst_wcoredump(VALUE st)
1060{
1061#ifdef WCOREDUMP
1062 int status = PST2INT(st);
1063
1064 return RBOOL(WCOREDUMP(status));
1065#else
1066 return Qfalse;
1067#endif
1068}
1069
1070static rb_pid_t
1071do_waitpid(rb_pid_t pid, int *st, int flags)
1072{
1073#if defined HAVE_WAITPID
1074 return waitpid(pid, st, flags);
1075#elif defined HAVE_WAIT4
1076 return wait4(pid, st, flags, NULL);
1077#else
1078# error waitpid or wait4 is required.
1079#endif
1080}
1081
1082#define WAITPID_LOCK_ONLY ((struct waitpid_state *)-1)
1083
1085 struct ccan_list_node wnode;
1087 rb_nativethread_cond_t *cond;
1088 rb_pid_t ret;
1089 rb_pid_t pid;
1090 int status;
1091 int options;
1092 int errnum;
1093};
1094
1095int rb_sigwait_fd_get(const rb_thread_t *);
1096void rb_sigwait_sleep(const rb_thread_t *, int fd, const rb_hrtime_t *);
1097void rb_sigwait_fd_put(const rb_thread_t *, int fd);
1098void rb_thread_sleep_interruptible(void);
1099
1100#if USE_MJIT
1101static struct waitpid_state mjit_waitpid_state;
1102
1103// variables shared with thread.c
1104// TODO: implement the same thing with postponed_job and obviate these variables
1105bool mjit_waitpid_finished = false;
1106int mjit_waitpid_status = 0;
1107#endif
1108
1109static int
1110waitpid_signal(struct waitpid_state *w)
1111{
1112 if (w->ec) { /* rb_waitpid */
1113 rb_threadptr_interrupt(rb_ec_thread_ptr(w->ec));
1114 return TRUE;
1115 }
1116#if USE_MJIT
1117 else if (w == &mjit_waitpid_state && w->ret) { /* mjit_add_waiting_pid */
1118 mjit_waitpid_finished = true;
1119 mjit_waitpid_status = w->status;
1120 return TRUE;
1121 }
1122#endif
1123 return FALSE;
1124}
1125
1126// Used for VM memsize reporting. Returns the size of a list of waitpid_state
1127// structs. Defined here because the struct definition lives here as well.
1128size_t
1129rb_vm_memsize_waiting_list(struct ccan_list_head *waiting_list)
1130{
1131 struct waitpid_state *waitpid = 0;
1132 size_t size = 0;
1133
1134 ccan_list_for_each(waiting_list, waitpid, wnode) {
1135 size += sizeof(struct waitpid_state);
1136 }
1137
1138 return size;
1139}
1140
1141/*
1142 * When a thread is done using sigwait_fd and there are other threads
1143 * sleeping on waitpid, we must kick one of the threads out of
1144 * rb_native_cond_wait so it can switch to rb_sigwait_sleep
1145 */
1146static void
1147sigwait_fd_migrate_sleeper(rb_vm_t *vm)
1148{
1149 struct waitpid_state *w = 0;
1150
1151 ccan_list_for_each(&vm->waiting_pids, w, wnode) {
1152 if (waitpid_signal(w)) return;
1153 }
1154 ccan_list_for_each(&vm->waiting_grps, w, wnode) {
1155 if (waitpid_signal(w)) return;
1156 }
1157}
1158
1159void
1160rb_sigwait_fd_migrate(rb_vm_t *vm)
1161{
1162 rb_native_mutex_lock(&vm->waitpid_lock);
1163 sigwait_fd_migrate_sleeper(vm);
1164 rb_native_mutex_unlock(&vm->waitpid_lock);
1165}
1166
1167#if RUBY_SIGCHLD
1168extern volatile unsigned int ruby_nocldwait; /* signal.c */
1169/* called by timer thread or thread which acquired sigwait_fd */
1170static void
1171waitpid_each(rb_vm_t *vm, struct ccan_list_head *head)
1172{
1173 struct waitpid_state *w = 0, *next;
1174
1175 ccan_list_for_each_safe(head, w, next, wnode) {
1176 rb_pid_t ret = do_waitpid(w->pid, &w->status, w->options | WNOHANG);
1177
1178 if (!ret) continue;
1179 if (ret == -1) w->errnum = errno;
1180
1181 if (w->pid <= 0) {
1182 /* when waiting for a group of processes, make sure a waiter for a
1183 * specific pid is given that event in preference */
1184 struct waitpid_state *w_inner = 0, *next_inner;
1185 ccan_list_for_each_safe(&vm->waiting_pids, w_inner, next_inner, wnode) {
1186 if (w_inner->pid == ret) {
1187 /* signal this one instead */
1188 w = w_inner;
1189 }
1190 }
1191 }
1192
1193 w->ret = ret;
1194 ccan_list_del_init(&w->wnode);
1195 waitpid_signal(w);
1196 }
1197}
1198#else
1199# define ruby_nocldwait 0
1200#endif
1201
1202void
1203ruby_waitpid_all(rb_vm_t *vm)
1204{
1205#if RUBY_SIGCHLD
1206 rb_native_mutex_lock(&vm->waitpid_lock);
1207 waitpid_each(vm, &vm->waiting_pids);
1208 waitpid_each(vm, &vm->waiting_grps);
1209 /* emulate SA_NOCLDWAIT */
1210 if (ccan_list_empty(&vm->waiting_pids) && ccan_list_empty(&vm->waiting_grps)) {
1211 while (ruby_nocldwait && do_waitpid(-1, 0, WNOHANG) > 0)
1212 ; /* keep looping */
1213 }
1214 rb_native_mutex_unlock(&vm->waitpid_lock);
1215#endif
1216}
1217
1218static void
1219waitpid_state_init(struct waitpid_state *w, rb_pid_t pid, int options)
1220{
1221 w->ret = 0;
1222 w->pid = pid;
1223 w->options = options;
1224 w->errnum = 0;
1225 w->status = 0;
1226}
1227
1228#if USE_MJIT
1229/*
1230 * must be called with vm->waitpid_lock held, this is not interruptible
1231 */
1232void
1233mjit_add_waiting_pid(rb_vm_t *vm, rb_pid_t pid)
1234{
1235 waitpid_state_init(&mjit_waitpid_state, pid, 0);
1236 mjit_waitpid_state.ec = 0; // switch the behavior of waitpid_signal
1237 ccan_list_add(&vm->waiting_pids, &mjit_waitpid_state.wnode);
1238}
1239#endif
1240
1241static VALUE
1242waitpid_sleep(VALUE x)
1243{
1244 struct waitpid_state *w = (struct waitpid_state *)x;
1245
1246 while (!w->ret) {
1247 rb_thread_sleep_interruptible();
1248 }
1249
1250 return Qfalse;
1251}
1252
1253static VALUE
1254waitpid_cleanup(VALUE x)
1255{
1256 struct waitpid_state *w = (struct waitpid_state *)x;
1257
1258 /*
1259 * XXX w->ret is sometimes set but ccan_list_del is still needed, here,
1260 * Not sure why, so we unconditionally do ccan_list_del here:
1261 */
1262 if (TRUE || w->ret == 0) {
1263 rb_vm_t *vm = rb_ec_vm_ptr(w->ec);
1264
1265 rb_native_mutex_lock(&vm->waitpid_lock);
1266 ccan_list_del(&w->wnode);
1267 rb_native_mutex_unlock(&vm->waitpid_lock);
1268 }
1269
1270 return Qfalse;
1271}
1272
1273static void
1274waitpid_wait(struct waitpid_state *w)
1275{
1276 rb_vm_t *vm = rb_ec_vm_ptr(w->ec);
1277 int need_sleep = FALSE;
1278
1279 /*
1280 * Lock here to prevent do_waitpid from stealing work from the
1281 * ruby_waitpid_locked done by mjit workers since mjit works
1282 * outside of GVL
1283 */
1284 rb_native_mutex_lock(&vm->waitpid_lock);
1285
1286 if (w->pid > 0 || ccan_list_empty(&vm->waiting_pids)) {
1287 w->ret = do_waitpid(w->pid, &w->status, w->options | WNOHANG);
1288 }
1289
1290 if (w->ret) {
1291 if (w->ret == -1) w->errnum = errno;
1292 }
1293 else if (w->options & WNOHANG) {
1294 }
1295 else {
1296 need_sleep = TRUE;
1297 }
1298
1299 if (need_sleep) {
1300 w->cond = 0;
1301 /* order matters, favor specified PIDs rather than -1 or 0 */
1302 ccan_list_add(w->pid > 0 ? &vm->waiting_pids : &vm->waiting_grps, &w->wnode);
1303 }
1304
1305 rb_native_mutex_unlock(&vm->waitpid_lock);
1306
1307 if (need_sleep) {
1308 rb_ensure(waitpid_sleep, (VALUE)w, waitpid_cleanup, (VALUE)w);
1309 }
1310}
1311
1312static void *
1313waitpid_blocking_no_SIGCHLD(void *x)
1314{
1315 struct waitpid_state *w = x;
1316
1317 w->ret = do_waitpid(w->pid, &w->status, w->options);
1318
1319 return 0;
1320}
1321
1322static void
1323waitpid_no_SIGCHLD(struct waitpid_state *w)
1324{
1325 if (w->options & WNOHANG) {
1326 w->ret = do_waitpid(w->pid, &w->status, w->options);
1327 }
1328 else {
1329 do {
1330 rb_thread_call_without_gvl(waitpid_blocking_no_SIGCHLD, w,
1331 RUBY_UBF_PROCESS, 0);
1332 } while (w->ret < 0 && errno == EINTR && (RUBY_VM_CHECK_INTS(w->ec),1));
1333 }
1334 if (w->ret == -1)
1335 w->errnum = errno;
1336}
1337
1338VALUE
1339rb_process_status_wait(rb_pid_t pid, int flags)
1340{
1341 // We only enter the scheduler if we are "blocking":
1342 if (!(flags & WNOHANG)) {
1343 VALUE scheduler = rb_fiber_scheduler_current();
1344 VALUE result = rb_fiber_scheduler_process_wait(scheduler, pid, flags);
1345 if (!UNDEF_P(result)) return result;
1346 }
1347
1349
1350 waitpid_state_init(&waitpid_state, pid, flags);
1351 waitpid_state.ec = GET_EC();
1352
1353 if (WAITPID_USE_SIGCHLD) {
1354 waitpid_wait(&waitpid_state);
1355 }
1356 else {
1357 waitpid_no_SIGCHLD(&waitpid_state);
1358 }
1359
1360 if (waitpid_state.ret == 0) return Qnil;
1361
1362 if (waitpid_state.ret > 0 && ruby_nocldwait) {
1363 waitpid_state.ret = -1;
1364 waitpid_state.errnum = ECHILD;
1365 }
1366
1367 return rb_process_status_new(waitpid_state.ret, waitpid_state.status, waitpid_state.errnum);
1368}
1369
1370/*
1371 * call-seq:
1372 * Process::Status.wait(pid=-1, flags=0) -> Process::Status
1373 *
1374 * Waits for a child process to exit and returns a Process::Status object
1375 * containing information on that process. Which child it waits on
1376 * depends on the value of _pid_:
1377 *
1378 * > 0:: Waits for the child whose process ID equals _pid_.
1379 *
1380 * 0:: Waits for any child whose process group ID equals that of the
1381 * calling process.
1382 *
1383 * -1:: Waits for any child process (the default if no _pid_ is
1384 * given).
1385 *
1386 * < -1:: Waits for any child whose process group ID equals the absolute
1387 * value of _pid_.
1388 *
1389 * The _flags_ argument may be a logical or of the flag values
1390 * Process::WNOHANG (do not block if no child available)
1391 * or Process::WUNTRACED (return stopped children that
1392 * haven't been reported). Not all flags are available on all
1393 * platforms, but a flag value of zero will work on all platforms.
1394 *
1395 * Returns +nil+ if there are no child processes.
1396 * Not available on all platforms.
1397 *
1398 * May invoke the scheduler hook _process_wait_.
1399 *
1400 * fork { exit 99 } #=> 27429
1401 * Process::Status.wait #=> pid 27429 exit 99
1402 * $? #=> nil
1403 *
1404 * pid = fork { sleep 3 } #=> 27440
1405 * Time.now #=> 2008-03-08 19:56:16 +0900
1406 * Process::Status.wait(pid, Process::WNOHANG) #=> nil
1407 * Time.now #=> 2008-03-08 19:56:16 +0900
1408 * Process::Status.wait(pid, 0) #=> pid 27440 exit 99
1409 * Time.now #=> 2008-03-08 19:56:19 +0900
1410 *
1411 * This is an EXPERIMENTAL FEATURE.
1412 */
1413
1414VALUE
1415rb_process_status_waitv(int argc, VALUE *argv, VALUE _)
1416{
1417 rb_check_arity(argc, 0, 2);
1418
1419 rb_pid_t pid = -1;
1420 int flags = 0;
1421
1422 if (argc >= 1) {
1423 pid = NUM2PIDT(argv[0]);
1424 }
1425
1426 if (argc >= 2) {
1427 flags = RB_NUM2INT(argv[1]);
1428 }
1429
1430 return rb_process_status_wait(pid, flags);
1431}
1432
1433rb_pid_t
1434rb_waitpid(rb_pid_t pid, int *st, int flags)
1435{
1436 VALUE status = rb_process_status_wait(pid, flags);
1437 if (NIL_P(status)) return 0;
1438
1439 struct rb_process_status *data = rb_check_typeddata(status, &rb_process_status_type);
1440 pid = data->pid;
1441
1442 if (st) *st = data->status;
1443
1444 if (pid == -1) {
1445 errno = data->error;
1446 }
1447 else {
1448 GET_THREAD()->last_status = status;
1449 }
1450
1451 return pid;
1452}
1453
1454static VALUE
1455proc_wait(int argc, VALUE *argv)
1456{
1457 rb_pid_t pid;
1458 int flags, status;
1459
1460 flags = 0;
1461 if (rb_check_arity(argc, 0, 2) == 0) {
1462 pid = -1;
1463 }
1464 else {
1465 VALUE vflags;
1466 pid = NUM2PIDT(argv[0]);
1467 if (argc == 2 && !NIL_P(vflags = argv[1])) {
1468 flags = NUM2UINT(vflags);
1469 }
1470 }
1471
1472 if ((pid = rb_waitpid(pid, &status, flags)) < 0)
1473 rb_sys_fail(0);
1474
1475 if (pid == 0) {
1476 rb_last_status_clear();
1477 return Qnil;
1478 }
1479
1480 return PIDT2NUM(pid);
1481}
1482
1483/* [MG]:FIXME: I wasn't sure how this should be done, since ::wait()
1484 has historically been documented as if it didn't take any arguments
1485 despite the fact that it's just an alias for ::waitpid(). The way I
1486 have it below is more truthful, but a little confusing.
1487
1488 I also took the liberty of putting in the pid values, as they're
1489 pretty useful, and it looked as if the original 'ri' output was
1490 supposed to contain them after "[...]depending on the value of
1491 aPid:".
1492
1493 The 'ansi' and 'bs' formats of the ri output don't display the
1494 definition list for some reason, but the plain text one does.
1495 */
1496
1497/*
1498 * call-seq:
1499 * Process.wait() -> integer
1500 * Process.wait(pid=-1, flags=0) -> integer
1501 * Process.waitpid(pid=-1, flags=0) -> integer
1502 *
1503 * Waits for a child process to exit, returns its process id, and
1504 * sets <code>$?</code> to a Process::Status object
1505 * containing information on that process. Which child it waits on
1506 * depends on the value of _pid_:
1507 *
1508 * > 0:: Waits for the child whose process ID equals _pid_.
1509 *
1510 * 0:: Waits for any child whose process group ID equals that of the
1511 * calling process.
1512 *
1513 * -1:: Waits for any child process (the default if no _pid_ is
1514 * given).
1515 *
1516 * < -1:: Waits for any child whose process group ID equals the absolute
1517 * value of _pid_.
1518 *
1519 * The _flags_ argument may be a logical or of the flag values
1520 * Process::WNOHANG (do not block if no child available)
1521 * or Process::WUNTRACED (return stopped children that
1522 * haven't been reported). Not all flags are available on all
1523 * platforms, but a flag value of zero will work on all platforms.
1524 *
1525 * Calling this method raises a SystemCallError if there are no child
1526 * processes. Not available on all platforms.
1527 *
1528 * include Process
1529 * fork { exit 99 } #=> 27429
1530 * wait #=> 27429
1531 * $?.exitstatus #=> 99
1532 *
1533 * pid = fork { sleep 3 } #=> 27440
1534 * Time.now #=> 2008-03-08 19:56:16 +0900
1535 * waitpid(pid, Process::WNOHANG) #=> nil
1536 * Time.now #=> 2008-03-08 19:56:16 +0900
1537 * waitpid(pid, 0) #=> 27440
1538 * Time.now #=> 2008-03-08 19:56:19 +0900
1539 */
1540
1541static VALUE
1542proc_m_wait(int c, VALUE *v, VALUE _)
1543{
1544 return proc_wait(c, v);
1545}
1546
1547
1548/*
1549 * call-seq:
1550 * Process.wait2(pid=-1, flags=0) -> [pid, status]
1551 * Process.waitpid2(pid=-1, flags=0) -> [pid, status]
1552 *
1553 * Waits for a child process to exit (see Process::waitpid for exact
1554 * semantics) and returns an array containing the process id and the
1555 * exit status (a Process::Status object) of that
1556 * child. Raises a SystemCallError if there are no child processes.
1557 *
1558 * Process.fork { exit 99 } #=> 27437
1559 * pid, status = Process.wait2
1560 * pid #=> 27437
1561 * status.exitstatus #=> 99
1562 */
1563
1564static VALUE
1565proc_wait2(int argc, VALUE *argv, VALUE _)
1566{
1567 VALUE pid = proc_wait(argc, argv);
1568 if (NIL_P(pid)) return Qnil;
1569 return rb_assoc_new(pid, rb_last_status_get());
1570}
1571
1572
1573/*
1574 * call-seq:
1575 * Process.waitall -> [ [pid1,status1], ...]
1576 *
1577 * Waits for all children, returning an array of
1578 * _pid_/_status_ pairs (where _status_ is a
1579 * Process::Status object).
1580 *
1581 * fork { sleep 0.2; exit 2 } #=> 27432
1582 * fork { sleep 0.1; exit 1 } #=> 27433
1583 * fork { exit 0 } #=> 27434
1584 * p Process.waitall
1585 *
1586 * <em>produces</em>:
1587 *
1588 * [[30982, #<Process::Status: pid 30982 exit 0>],
1589 * [30979, #<Process::Status: pid 30979 exit 1>],
1590 * [30976, #<Process::Status: pid 30976 exit 2>]]
1591 */
1592
1593static VALUE
1594proc_waitall(VALUE _)
1595{
1596 VALUE result;
1597 rb_pid_t pid;
1598 int status;
1599
1600 result = rb_ary_new();
1601 rb_last_status_clear();
1602
1603 for (pid = -1;;) {
1604 pid = rb_waitpid(-1, &status, 0);
1605 if (pid == -1) {
1606 int e = errno;
1607 if (e == ECHILD)
1608 break;
1609 rb_syserr_fail(e, 0);
1610 }
1611 rb_ary_push(result, rb_assoc_new(PIDT2NUM(pid), rb_last_status_get()));
1612 }
1613 return result;
1614}
1615
1616static VALUE rb_cWaiter;
1617
1618static VALUE
1619detach_process_pid(VALUE thread)
1620{
1621 return rb_thread_local_aref(thread, id_pid);
1622}
1623
1624static VALUE
1625detach_process_watcher(void *arg)
1626{
1627 rb_pid_t cpid, pid = (rb_pid_t)(VALUE)arg;
1628 int status;
1629
1630 while ((cpid = rb_waitpid(pid, &status, 0)) == 0) {
1631 /* wait while alive */
1632 }
1633 return rb_last_status_get();
1634}
1635
1636VALUE
1638{
1639 VALUE watcher = rb_thread_create(detach_process_watcher, (void*)(VALUE)pid);
1640 rb_thread_local_aset(watcher, id_pid, PIDT2NUM(pid));
1641 RBASIC_SET_CLASS(watcher, rb_cWaiter);
1642 return watcher;
1643}
1644
1645
1646/*
1647 * call-seq:
1648 * Process.detach(pid) -> thread
1649 *
1650 * Some operating systems retain the status of terminated child
1651 * processes until the parent collects that status (normally using
1652 * some variant of <code>wait()</code>). If the parent never collects
1653 * this status, the child stays around as a <em>zombie</em> process.
1654 * Process::detach prevents this by setting up a separate Ruby thread
1655 * whose sole job is to reap the status of the process _pid_ when it
1656 * terminates. Use #detach only when you do not intend to explicitly
1657 * wait for the child to terminate.
1658 *
1659 * The waiting thread returns the exit status of the detached process
1660 * when it terminates, so you can use Thread#join to
1661 * know the result. If specified _pid_ is not a valid child process
1662 * ID, the thread returns +nil+ immediately.
1663 *
1664 * The waiting thread has #pid method which returns the pid.
1665 *
1666 * In this first example, we don't reap the first child process, so
1667 * it appears as a zombie in the process status display.
1668 *
1669 * p1 = fork { sleep 0.1 }
1670 * p2 = fork { sleep 0.2 }
1671 * Process.waitpid(p2)
1672 * sleep 2
1673 * system("ps -ho pid,state -p #{p1}")
1674 *
1675 * <em>produces:</em>
1676 *
1677 * 27389 Z
1678 *
1679 * In the next example, Process::detach is used to reap
1680 * the child automatically.
1681 *
1682 * p1 = fork { sleep 0.1 }
1683 * p2 = fork { sleep 0.2 }
1684 * Process.detach(p1)
1685 * Process.waitpid(p2)
1686 * sleep 2
1687 * system("ps -ho pid,state -p #{p1}")
1688 *
1689 * <em>(produces no output)</em>
1690 */
1691
1692static VALUE
1693proc_detach(VALUE obj, VALUE pid)
1694{
1695 return rb_detach_process(NUM2PIDT(pid));
1696}
1697
1698/* This function should be async-signal-safe. Actually it is. */
1699static void
1700before_exec_async_signal_safe(void)
1701{
1702}
1703
1704static void
1705before_exec_non_async_signal_safe(void)
1706{
1707 /*
1708 * On Mac OS X 10.5.x (Leopard) or earlier, exec() may return ENOTSUP
1709 * if the process have multiple threads. Therefore we have to kill
1710 * internal threads temporary. [ruby-core:10583]
1711 * This is also true on Haiku. It returns Errno::EPERM against exec()
1712 * in multiple threads.
1713 *
1714 * Nowadays, we always stop the timer thread completely to allow redirects.
1715 */
1716 rb_thread_stop_timer_thread();
1717}
1718
1719#define WRITE_CONST(fd, str) (void)(write((fd),(str),sizeof(str)-1)<0)
1720#ifdef _WIN32
1721int rb_w32_set_nonblock2(int fd, int nonblock);
1722#endif
1723
1724static int
1725set_blocking(int fd)
1726{
1727#ifdef _WIN32
1728 return rb_w32_set_nonblock2(fd, 0);
1729#elif defined(F_GETFL) && defined(F_SETFL)
1730 int fl = fcntl(fd, F_GETFL); /* async-signal-safe */
1731
1732 /* EBADF ought to be possible */
1733 if (fl == -1) return fl;
1734 if (fl & O_NONBLOCK) {
1735 fl &= ~O_NONBLOCK;
1736 return fcntl(fd, F_SETFL, fl);
1737 }
1738 return 0;
1739#endif
1740}
1741
1742static void
1743stdfd_clear_nonblock(void)
1744{
1745 /* many programs cannot deal with non-blocking stdin/stdout/stderr */
1746 int fd;
1747 for (fd = 0; fd < 3; fd++) {
1748 (void)set_blocking(fd); /* can't do much about errors anyhow */
1749 }
1750}
1751
1752static void
1753before_exec(void)
1754{
1755 before_exec_non_async_signal_safe();
1756 before_exec_async_signal_safe();
1757}
1758
1759/* This function should be async-signal-safe. Actually it is. */
1760static void
1761after_exec_async_signal_safe(void)
1762{
1763}
1764
1765static void
1766after_exec_non_async_signal_safe(void)
1767{
1768 rb_thread_reset_timer_thread();
1769 rb_thread_start_timer_thread();
1770}
1771
1772static void
1773after_exec(void)
1774{
1775 after_exec_async_signal_safe();
1776 after_exec_non_async_signal_safe();
1777}
1778
1779#if defined HAVE_WORKING_FORK || defined HAVE_DAEMON
1780static void
1781before_fork_ruby(void)
1782{
1783 before_exec();
1784}
1785
1786static void
1787after_fork_ruby(void)
1788{
1789 rb_threadptr_pending_interrupt_clear(GET_THREAD());
1790 after_exec();
1791}
1792#endif
1793
1794#if defined(HAVE_WORKING_FORK)
1795
1796/* try_with_sh and exec_with_sh should be async-signal-safe. Actually it is.*/
1797#define try_with_sh(err, prog, argv, envp) ((err == ENOEXEC) ? exec_with_sh((prog), (argv), (envp)) : (void)0)
1798static void
1799exec_with_sh(const char *prog, char **argv, char **envp)
1800{
1801 *argv = (char *)prog;
1802 *--argv = (char *)"sh";
1803 if (envp)
1804 execve("/bin/sh", argv, envp); /* async-signal-safe */
1805 else
1806 execv("/bin/sh", argv); /* async-signal-safe (since SUSv4) */
1807}
1808
1809#else
1810#define try_with_sh(err, prog, argv, envp) (void)0
1811#endif
1812
1813/* This function should be async-signal-safe. Actually it is. */
1814static int
1815proc_exec_cmd(const char *prog, VALUE argv_str, VALUE envp_str)
1816{
1817 char **argv;
1818#ifndef _WIN32
1819 char **envp;
1820 int err;
1821#endif
1822
1823 argv = ARGVSTR2ARGV(argv_str);
1824
1825 if (!prog) {
1826 return ENOENT;
1827 }
1828
1829#ifdef _WIN32
1830 rb_w32_uaspawn(P_OVERLAY, prog, argv);
1831 return errno;
1832#else
1833 envp = envp_str ? RB_IMEMO_TMPBUF_PTR(envp_str) : NULL;
1834 if (envp_str)
1835 execve(prog, argv, envp); /* async-signal-safe */
1836 else
1837 execv(prog, argv); /* async-signal-safe (since SUSv4) */
1838 err = errno;
1839 try_with_sh(err, prog, argv, envp); /* try_with_sh() is async-signal-safe. */
1840 return err;
1841#endif
1842}
1843
1844/* This function should be async-signal-safe. Actually it is. */
1845static int
1846proc_exec_sh(const char *str, VALUE envp_str)
1847{
1848 const char *s;
1849
1850 s = str;
1851 while (*s == ' ' || *s == '\t' || *s == '\n')
1852 s++;
1853
1854 if (!*s) {
1855 return ENOENT;
1856 }
1857
1858#ifdef _WIN32
1859 rb_w32_uspawn(P_OVERLAY, (char *)str, 0);
1860#elif defined(__CYGWIN32__)
1861 {
1862 char fbuf[MAXPATHLEN];
1863 char *shell = dln_find_exe_r("sh", 0, fbuf, sizeof(fbuf));
1864 int status = -1;
1865 if (shell)
1866 execl(shell, "sh", "-c", str, (char *) NULL);
1867 else
1868 status = system(str);
1869 if (status != -1)
1870 exit(status);
1871 }
1872#else
1873 if (envp_str)
1874 execle("/bin/sh", "sh", "-c", str, (char *)NULL, RB_IMEMO_TMPBUF_PTR(envp_str)); /* async-signal-safe */
1875 else
1876 execl("/bin/sh", "sh", "-c", str, (char *)NULL); /* async-signal-safe (since SUSv4) */
1877#endif /* _WIN32 */
1878 return errno;
1879}
1880
1881int
1882rb_proc_exec(const char *str)
1883{
1884 int ret;
1885 before_exec();
1886 ret = proc_exec_sh(str, Qfalse);
1887 after_exec();
1888 errno = ret;
1889 return -1;
1890}
1891
1892static void
1893mark_exec_arg(void *ptr)
1894{
1895 struct rb_execarg *eargp = ptr;
1896 if (eargp->use_shell)
1897 rb_gc_mark(eargp->invoke.sh.shell_script);
1898 else {
1899 rb_gc_mark(eargp->invoke.cmd.command_name);
1900 rb_gc_mark(eargp->invoke.cmd.command_abspath);
1901 rb_gc_mark(eargp->invoke.cmd.argv_str);
1902 rb_gc_mark(eargp->invoke.cmd.argv_buf);
1903 }
1904 rb_gc_mark(eargp->redirect_fds);
1905 rb_gc_mark(eargp->envp_str);
1906 rb_gc_mark(eargp->envp_buf);
1907 rb_gc_mark(eargp->dup2_tmpbuf);
1908 rb_gc_mark(eargp->rlimit_limits);
1909 rb_gc_mark(eargp->fd_dup2);
1910 rb_gc_mark(eargp->fd_close);
1911 rb_gc_mark(eargp->fd_open);
1912 rb_gc_mark(eargp->fd_dup2_child);
1913 rb_gc_mark(eargp->env_modification);
1914 rb_gc_mark(eargp->path_env);
1915 rb_gc_mark(eargp->chdir_dir);
1916}
1917
1918static size_t
1919memsize_exec_arg(const void *ptr)
1920{
1921 return sizeof(struct rb_execarg);
1922}
1923
1924static const rb_data_type_t exec_arg_data_type = {
1925 "exec_arg",
1926 {mark_exec_arg, RUBY_TYPED_DEFAULT_FREE, memsize_exec_arg},
1927 0, 0, RUBY_TYPED_FREE_IMMEDIATELY
1928};
1929
1930#ifdef _WIN32
1931# define DEFAULT_PROCESS_ENCODING rb_utf8_encoding()
1932#endif
1933#ifdef DEFAULT_PROCESS_ENCODING
1934# define EXPORT_STR(str) rb_str_export_to_enc((str), DEFAULT_PROCESS_ENCODING)
1935# define EXPORT_DUP(str) export_dup(str)
1936static VALUE
1937export_dup(VALUE str)
1938{
1939 VALUE newstr = EXPORT_STR(str);
1940 if (newstr == str) newstr = rb_str_dup(str);
1941 return newstr;
1942}
1943#else
1944# define EXPORT_STR(str) (str)
1945# define EXPORT_DUP(str) rb_str_dup(str)
1946#endif
1947
1948#if !defined(HAVE_WORKING_FORK) && defined(HAVE_SPAWNV)
1949# define USE_SPAWNV 1
1950#else
1951# define USE_SPAWNV 0
1952#endif
1953#ifndef P_NOWAIT
1954# define P_NOWAIT _P_NOWAIT
1955#endif
1956
1957#if USE_SPAWNV
1958#if defined(_WIN32)
1959#define proc_spawn_cmd_internal(argv, prog) rb_w32_uaspawn(P_NOWAIT, (prog), (argv))
1960#else
1961static rb_pid_t
1962proc_spawn_cmd_internal(char **argv, char *prog)
1963{
1964 char fbuf[MAXPATHLEN];
1965 rb_pid_t status;
1966
1967 if (!prog)
1968 prog = argv[0];
1969 prog = dln_find_exe_r(prog, 0, fbuf, sizeof(fbuf));
1970 if (!prog)
1971 return -1;
1972
1973 before_exec();
1974 status = spawnv(P_NOWAIT, prog, (const char **)argv);
1975 if (status == -1 && errno == ENOEXEC) {
1976 *argv = (char *)prog;
1977 *--argv = (char *)"sh";
1978 status = spawnv(P_NOWAIT, "/bin/sh", (const char **)argv);
1979 after_exec();
1980 if (status == -1) errno = ENOEXEC;
1981 }
1982 return status;
1983}
1984#endif
1985
1986static rb_pid_t
1987proc_spawn_cmd(char **argv, VALUE prog, struct rb_execarg *eargp)
1988{
1989 rb_pid_t pid = -1;
1990
1991 if (argv[0]) {
1992#if defined(_WIN32)
1993 DWORD flags = 0;
1994 if (eargp->new_pgroup_given && eargp->new_pgroup_flag) {
1995 flags = CREATE_NEW_PROCESS_GROUP;
1996 }
1997 pid = rb_w32_uaspawn_flags(P_NOWAIT, prog ? RSTRING_PTR(prog) : 0, argv, flags);
1998#else
1999 pid = proc_spawn_cmd_internal(argv, prog ? RSTRING_PTR(prog) : 0);
2000#endif
2001 }
2002 return pid;
2003}
2004
2005#if defined(_WIN32)
2006#define proc_spawn_sh(str) rb_w32_uspawn(P_NOWAIT, (str), 0)
2007#else
2008static rb_pid_t
2009proc_spawn_sh(char *str)
2010{
2011 char fbuf[MAXPATHLEN];
2012 rb_pid_t status;
2013
2014 char *shell = dln_find_exe_r("sh", 0, fbuf, sizeof(fbuf));
2015 before_exec();
2016 status = spawnl(P_NOWAIT, (shell ? shell : "/bin/sh"), "sh", "-c", str, (char*)NULL);
2017 after_exec();
2018 return status;
2019}
2020#endif
2021#endif
2022
2023static VALUE
2024hide_obj(VALUE obj)
2025{
2026 RBASIC_CLEAR_CLASS(obj);
2027 return obj;
2028}
2029
2030static VALUE
2031check_exec_redirect_fd(VALUE v, int iskey)
2032{
2033 VALUE tmp;
2034 int fd;
2035 if (FIXNUM_P(v)) {
2036 fd = FIX2INT(v);
2037 }
2038 else if (SYMBOL_P(v)) {
2039 ID id = rb_check_id(&v);
2040 if (id == id_in)
2041 fd = 0;
2042 else if (id == id_out)
2043 fd = 1;
2044 else if (id == id_err)
2045 fd = 2;
2046 else
2047 goto wrong;
2048 }
2049 else if (!NIL_P(tmp = rb_io_check_io(v))) {
2050 rb_io_t *fptr;
2051 GetOpenFile(tmp, fptr);
2052 if (fptr->tied_io_for_writing)
2053 rb_raise(rb_eArgError, "duplex IO redirection");
2054 fd = fptr->fd;
2055 }
2056 else {
2057 goto wrong;
2058 }
2059 if (fd < 0) {
2060 rb_raise(rb_eArgError, "negative file descriptor");
2061 }
2062#ifdef _WIN32
2063 else if (fd >= 3 && iskey) {
2064 rb_raise(rb_eArgError, "wrong file descriptor (%d)", fd);
2065 }
2066#endif
2067 return INT2FIX(fd);
2068
2069 wrong:
2070 rb_raise(rb_eArgError, "wrong exec redirect");
2072}
2073
2074static VALUE
2075check_exec_redirect1(VALUE ary, VALUE key, VALUE param)
2076{
2077 if (ary == Qfalse) {
2078 ary = hide_obj(rb_ary_new());
2079 }
2080 if (!RB_TYPE_P(key, T_ARRAY)) {
2081 VALUE fd = check_exec_redirect_fd(key, !NIL_P(param));
2082 rb_ary_push(ary, hide_obj(rb_assoc_new(fd, param)));
2083 }
2084 else {
2085 int i;
2086 for (i = 0 ; i < RARRAY_LEN(key); i++) {
2087 VALUE v = RARRAY_AREF(key, i);
2088 VALUE fd = check_exec_redirect_fd(v, !NIL_P(param));
2089 rb_ary_push(ary, hide_obj(rb_assoc_new(fd, param)));
2090 }
2091 }
2092 return ary;
2093}
2094
2095static void
2096check_exec_redirect(VALUE key, VALUE val, struct rb_execarg *eargp)
2097{
2098 VALUE param;
2099 VALUE path, flags, perm;
2100 VALUE tmp;
2101 ID id;
2102
2103 switch (TYPE(val)) {
2104 case T_SYMBOL:
2105 id = rb_check_id(&val);
2106 if (id == id_close) {
2107 param = Qnil;
2108 eargp->fd_close = check_exec_redirect1(eargp->fd_close, key, param);
2109 }
2110 else if (id == id_in) {
2111 param = INT2FIX(0);
2112 eargp->fd_dup2 = check_exec_redirect1(eargp->fd_dup2, key, param);
2113 }
2114 else if (id == id_out) {
2115 param = INT2FIX(1);
2116 eargp->fd_dup2 = check_exec_redirect1(eargp->fd_dup2, key, param);
2117 }
2118 else if (id == id_err) {
2119 param = INT2FIX(2);
2120 eargp->fd_dup2 = check_exec_redirect1(eargp->fd_dup2, key, param);
2121 }
2122 else {
2123 rb_raise(rb_eArgError, "wrong exec redirect symbol: %"PRIsVALUE,
2124 val);
2125 }
2126 break;
2127
2128 case T_FILE:
2129 io:
2130 val = check_exec_redirect_fd(val, 0);
2131 /* fall through */
2132 case T_FIXNUM:
2133 param = val;
2134 eargp->fd_dup2 = check_exec_redirect1(eargp->fd_dup2, key, param);
2135 break;
2136
2137 case T_ARRAY:
2138 path = rb_ary_entry(val, 0);
2139 if (RARRAY_LEN(val) == 2 && SYMBOL_P(path) &&
2140 path == ID2SYM(id_child)) {
2141 param = check_exec_redirect_fd(rb_ary_entry(val, 1), 0);
2142 eargp->fd_dup2_child = check_exec_redirect1(eargp->fd_dup2_child, key, param);
2143 }
2144 else {
2145 FilePathValue(path);
2146 flags = rb_ary_entry(val, 1);
2147 if (NIL_P(flags))
2148 flags = INT2NUM(O_RDONLY);
2149 else if (RB_TYPE_P(flags, T_STRING))
2151 else
2152 flags = rb_to_int(flags);
2153 perm = rb_ary_entry(val, 2);
2154 perm = NIL_P(perm) ? INT2FIX(0644) : rb_to_int(perm);
2155 param = hide_obj(rb_ary_new3(4, hide_obj(EXPORT_DUP(path)),
2156 flags, perm, Qnil));
2157 eargp->fd_open = check_exec_redirect1(eargp->fd_open, key, param);
2158 }
2159 break;
2160
2161 case T_STRING:
2162 path = val;
2163 FilePathValue(path);
2164 if (RB_TYPE_P(key, T_FILE))
2165 key = check_exec_redirect_fd(key, 1);
2166 if (FIXNUM_P(key) && (FIX2INT(key) == 1 || FIX2INT(key) == 2))
2167 flags = INT2NUM(O_WRONLY|O_CREAT|O_TRUNC);
2168 else if (RB_TYPE_P(key, T_ARRAY)) {
2169 int i;
2170 for (i = 0; i < RARRAY_LEN(key); i++) {
2171 VALUE v = RARRAY_AREF(key, i);
2172 VALUE fd = check_exec_redirect_fd(v, 1);
2173 if (FIX2INT(fd) != 1 && FIX2INT(fd) != 2) break;
2174 }
2175 if (i == RARRAY_LEN(key))
2176 flags = INT2NUM(O_WRONLY|O_CREAT|O_TRUNC);
2177 else
2178 flags = INT2NUM(O_RDONLY);
2179 }
2180 else
2181 flags = INT2NUM(O_RDONLY);
2182 perm = INT2FIX(0644);
2183 param = hide_obj(rb_ary_new3(4, hide_obj(EXPORT_DUP(path)),
2184 flags, perm, Qnil));
2185 eargp->fd_open = check_exec_redirect1(eargp->fd_open, key, param);
2186 break;
2187
2188 default:
2189 tmp = val;
2190 val = rb_io_check_io(tmp);
2191 if (!NIL_P(val)) goto io;
2192 rb_raise(rb_eArgError, "wrong exec redirect action");
2193 }
2194
2195}
2196
2197#if defined(HAVE_SETRLIMIT) && defined(NUM2RLIM)
2198static int rlimit_type_by_sym(VALUE key);
2199
2200static void
2201rb_execarg_addopt_rlimit(struct rb_execarg *eargp, int rtype, VALUE val)
2202{
2203 VALUE ary = eargp->rlimit_limits;
2204 VALUE tmp, softlim, hardlim;
2205 if (eargp->rlimit_limits == Qfalse)
2206 ary = eargp->rlimit_limits = hide_obj(rb_ary_new());
2207 else
2208 ary = eargp->rlimit_limits;
2209 tmp = rb_check_array_type(val);
2210 if (!NIL_P(tmp)) {
2211 if (RARRAY_LEN(tmp) == 1)
2212 softlim = hardlim = rb_to_int(rb_ary_entry(tmp, 0));
2213 else if (RARRAY_LEN(tmp) == 2) {
2214 softlim = rb_to_int(rb_ary_entry(tmp, 0));
2215 hardlim = rb_to_int(rb_ary_entry(tmp, 1));
2216 }
2217 else {
2218 rb_raise(rb_eArgError, "wrong exec rlimit option");
2219 }
2220 }
2221 else {
2222 softlim = hardlim = rb_to_int(val);
2223 }
2224 tmp = hide_obj(rb_ary_new3(3, INT2NUM(rtype), softlim, hardlim));
2225 rb_ary_push(ary, tmp);
2226}
2227#endif
2228
2229#define TO_BOOL(val, name) (NIL_P(val) ? 0 : rb_bool_expected((val), name, TRUE))
2230int
2231rb_execarg_addopt(VALUE execarg_obj, VALUE key, VALUE val)
2232{
2233 struct rb_execarg *eargp = rb_execarg_get(execarg_obj);
2234
2235 ID id;
2236
2237 switch (TYPE(key)) {
2238 case T_SYMBOL:
2239#if defined(HAVE_SETRLIMIT) && defined(NUM2RLIM)
2240 {
2241 int rtype = rlimit_type_by_sym(key);
2242 if (rtype != -1) {
2243 rb_execarg_addopt_rlimit(eargp, rtype, val);
2244 RB_GC_GUARD(execarg_obj);
2245 return ST_CONTINUE;
2246 }
2247 }
2248#endif
2249 if (!(id = rb_check_id(&key))) return ST_STOP;
2250#ifdef HAVE_SETPGID
2251 if (id == id_pgroup) {
2252 rb_pid_t pgroup;
2253 if (eargp->pgroup_given) {
2254 rb_raise(rb_eArgError, "pgroup option specified twice");
2255 }
2256 if (!RTEST(val))
2257 pgroup = -1; /* asis(-1) means "don't call setpgid()". */
2258 else if (val == Qtrue)
2259 pgroup = 0; /* new process group. */
2260 else {
2261 pgroup = NUM2PIDT(val);
2262 if (pgroup < 0) {
2263 rb_raise(rb_eArgError, "negative process group ID : %ld", (long)pgroup);
2264 }
2265 }
2266 eargp->pgroup_given = 1;
2267 eargp->pgroup_pgid = pgroup;
2268 }
2269 else
2270#endif
2271#ifdef _WIN32
2272 if (id == id_new_pgroup) {
2273 if (eargp->new_pgroup_given) {
2274 rb_raise(rb_eArgError, "new_pgroup option specified twice");
2275 }
2276 eargp->new_pgroup_given = 1;
2277 eargp->new_pgroup_flag = TO_BOOL(val, "new_pgroup");
2278 }
2279 else
2280#endif
2281 if (id == id_unsetenv_others) {
2282 if (eargp->unsetenv_others_given) {
2283 rb_raise(rb_eArgError, "unsetenv_others option specified twice");
2284 }
2285 eargp->unsetenv_others_given = 1;
2286 eargp->unsetenv_others_do = TO_BOOL(val, "unsetenv_others");
2287 }
2288 else if (id == id_chdir) {
2289 if (eargp->chdir_given) {
2290 rb_raise(rb_eArgError, "chdir option specified twice");
2291 }
2292 FilePathValue(val);
2293 val = rb_str_encode_ospath(val);
2294 eargp->chdir_given = 1;
2295 eargp->chdir_dir = hide_obj(EXPORT_DUP(val));
2296 }
2297 else if (id == id_umask) {
2298 mode_t cmask = NUM2MODET(val);
2299 if (eargp->umask_given) {
2300 rb_raise(rb_eArgError, "umask option specified twice");
2301 }
2302 eargp->umask_given = 1;
2303 eargp->umask_mask = cmask;
2304 }
2305 else if (id == id_close_others) {
2306 if (eargp->close_others_given) {
2307 rb_raise(rb_eArgError, "close_others option specified twice");
2308 }
2309 eargp->close_others_given = 1;
2310 eargp->close_others_do = TO_BOOL(val, "close_others");
2311 }
2312 else if (id == id_in) {
2313 key = INT2FIX(0);
2314 goto redirect;
2315 }
2316 else if (id == id_out) {
2317 key = INT2FIX(1);
2318 goto redirect;
2319 }
2320 else if (id == id_err) {
2321 key = INT2FIX(2);
2322 goto redirect;
2323 }
2324 else if (id == id_uid) {
2325#ifdef HAVE_SETUID
2326 if (eargp->uid_given) {
2327 rb_raise(rb_eArgError, "uid option specified twice");
2328 }
2329 check_uid_switch();
2330 {
2331 eargp->uid = OBJ2UID(val);
2332 eargp->uid_given = 1;
2333 }
2334#else
2336 "uid option is unimplemented on this machine");
2337#endif
2338 }
2339 else if (id == id_gid) {
2340#ifdef HAVE_SETGID
2341 if (eargp->gid_given) {
2342 rb_raise(rb_eArgError, "gid option specified twice");
2343 }
2344 check_gid_switch();
2345 {
2346 eargp->gid = OBJ2GID(val);
2347 eargp->gid_given = 1;
2348 }
2349#else
2351 "gid option is unimplemented on this machine");
2352#endif
2353 }
2354 else if (id == id_exception) {
2355 if (eargp->exception_given) {
2356 rb_raise(rb_eArgError, "exception option specified twice");
2357 }
2358 eargp->exception_given = 1;
2359 eargp->exception = TO_BOOL(val, "exception");
2360 }
2361 else {
2362 return ST_STOP;
2363 }
2364 break;
2365
2366 case T_FIXNUM:
2367 case T_FILE:
2368 case T_ARRAY:
2369redirect:
2370 check_exec_redirect(key, val, eargp);
2371 break;
2372
2373 default:
2374 return ST_STOP;
2375 }
2376
2377 RB_GC_GUARD(execarg_obj);
2378 return ST_CONTINUE;
2379}
2380
2381static int
2382check_exec_options_i(st_data_t st_key, st_data_t st_val, st_data_t arg)
2383{
2384 VALUE key = (VALUE)st_key;
2385 VALUE val = (VALUE)st_val;
2386 VALUE execarg_obj = (VALUE)arg;
2387 if (rb_execarg_addopt(execarg_obj, key, val) != ST_CONTINUE) {
2388 if (SYMBOL_P(key))
2389 rb_raise(rb_eArgError, "wrong exec option symbol: % "PRIsVALUE,
2390 key);
2391 rb_raise(rb_eArgError, "wrong exec option");
2392 }
2393 return ST_CONTINUE;
2394}
2395
2396static int
2397check_exec_options_i_extract(st_data_t st_key, st_data_t st_val, st_data_t arg)
2398{
2399 VALUE key = (VALUE)st_key;
2400 VALUE val = (VALUE)st_val;
2401 VALUE *args = (VALUE *)arg;
2402 VALUE execarg_obj = args[0];
2403 if (rb_execarg_addopt(execarg_obj, key, val) != ST_CONTINUE) {
2404 VALUE nonopts = args[1];
2405 if (NIL_P(nonopts)) args[1] = nonopts = rb_hash_new();
2406 rb_hash_aset(nonopts, key, val);
2407 }
2408 return ST_CONTINUE;
2409}
2410
2411static int
2412check_exec_fds_1(struct rb_execarg *eargp, VALUE h, int maxhint, VALUE ary)
2413{
2414 long i;
2415
2416 if (ary != Qfalse) {
2417 for (i = 0; i < RARRAY_LEN(ary); i++) {
2418 VALUE elt = RARRAY_AREF(ary, i);
2419 int fd = FIX2INT(RARRAY_AREF(elt, 0));
2420 if (RTEST(rb_hash_lookup(h, INT2FIX(fd)))) {
2421 rb_raise(rb_eArgError, "fd %d specified twice", fd);
2422 }
2423 if (ary == eargp->fd_dup2)
2424 rb_hash_aset(h, INT2FIX(fd), Qtrue);
2425 else if (ary == eargp->fd_dup2_child)
2426 rb_hash_aset(h, INT2FIX(fd), RARRAY_AREF(elt, 1));
2427 else /* ary == eargp->fd_close */
2428 rb_hash_aset(h, INT2FIX(fd), INT2FIX(-1));
2429 if (maxhint < fd)
2430 maxhint = fd;
2431 if (ary == eargp->fd_dup2 || ary == eargp->fd_dup2_child) {
2432 fd = FIX2INT(RARRAY_AREF(elt, 1));
2433 if (maxhint < fd)
2434 maxhint = fd;
2435 }
2436 }
2437 }
2438 return maxhint;
2439}
2440
2441static VALUE
2442check_exec_fds(struct rb_execarg *eargp)
2443{
2444 VALUE h = rb_hash_new();
2445 VALUE ary;
2446 int maxhint = -1;
2447 long i;
2448
2449 maxhint = check_exec_fds_1(eargp, h, maxhint, eargp->fd_dup2);
2450 maxhint = check_exec_fds_1(eargp, h, maxhint, eargp->fd_close);
2451 maxhint = check_exec_fds_1(eargp, h, maxhint, eargp->fd_dup2_child);
2452
2453 if (eargp->fd_dup2_child) {
2454 ary = eargp->fd_dup2_child;
2455 for (i = 0; i < RARRAY_LEN(ary); i++) {
2456 VALUE elt = RARRAY_AREF(ary, i);
2457 int newfd = FIX2INT(RARRAY_AREF(elt, 0));
2458 int oldfd = FIX2INT(RARRAY_AREF(elt, 1));
2459 int lastfd = oldfd;
2460 VALUE val = rb_hash_lookup(h, INT2FIX(lastfd));
2461 long depth = 0;
2462 while (FIXNUM_P(val) && 0 <= FIX2INT(val)) {
2463 lastfd = FIX2INT(val);
2464 val = rb_hash_lookup(h, val);
2465 if (RARRAY_LEN(ary) < depth)
2466 rb_raise(rb_eArgError, "cyclic child fd redirection from %d", oldfd);
2467 depth++;
2468 }
2469 if (val != Qtrue)
2470 rb_raise(rb_eArgError, "child fd %d is not redirected", oldfd);
2471 if (oldfd != lastfd) {
2472 VALUE val2;
2473 rb_ary_store(elt, 1, INT2FIX(lastfd));
2474 rb_hash_aset(h, INT2FIX(newfd), INT2FIX(lastfd));
2475 val = INT2FIX(oldfd);
2476 while (FIXNUM_P(val2 = rb_hash_lookup(h, val))) {
2477 rb_hash_aset(h, val, INT2FIX(lastfd));
2478 val = val2;
2479 }
2480 }
2481 }
2482 }
2483
2484 eargp->close_others_maxhint = maxhint;
2485 return h;
2486}
2487
2488static void
2489rb_check_exec_options(VALUE opthash, VALUE execarg_obj)
2490{
2491 if (RHASH_EMPTY_P(opthash))
2492 return;
2493 rb_hash_stlike_foreach(opthash, check_exec_options_i, (st_data_t)execarg_obj);
2494}
2495
2496VALUE
2497rb_execarg_extract_options(VALUE execarg_obj, VALUE opthash)
2498{
2499 VALUE args[2];
2500 if (RHASH_EMPTY_P(opthash))
2501 return Qnil;
2502 args[0] = execarg_obj;
2503 args[1] = Qnil;
2504 rb_hash_stlike_foreach(opthash, check_exec_options_i_extract, (st_data_t)args);
2505 return args[1];
2506}
2507
2508#ifdef ENV_IGNORECASE
2509#define ENVMATCH(s1, s2) (STRCASECMP((s1), (s2)) == 0)
2510#else
2511#define ENVMATCH(n1, n2) (strcmp((n1), (n2)) == 0)
2512#endif
2513
2514static int
2515check_exec_env_i(st_data_t st_key, st_data_t st_val, st_data_t arg)
2516{
2517 VALUE key = (VALUE)st_key;
2518 VALUE val = (VALUE)st_val;
2519 VALUE env = ((VALUE *)arg)[0];
2520 VALUE *path = &((VALUE *)arg)[1];
2521 char *k;
2522
2523 k = StringValueCStr(key);
2524 if (strchr(k, '='))
2525 rb_raise(rb_eArgError, "environment name contains a equal : %"PRIsVALUE, key);
2526
2527 if (!NIL_P(val))
2528 StringValueCStr(val);
2529
2530 key = EXPORT_STR(key);
2531 if (!NIL_P(val)) val = EXPORT_STR(val);
2532
2533 if (ENVMATCH(k, PATH_ENV)) {
2534 *path = val;
2535 }
2536 rb_ary_push(env, hide_obj(rb_assoc_new(key, val)));
2537
2538 return ST_CONTINUE;
2539}
2540
2541static VALUE
2542rb_check_exec_env(VALUE hash, VALUE *path)
2543{
2544 VALUE env[2];
2545
2546 env[0] = hide_obj(rb_ary_new());
2547 env[1] = Qfalse;
2548 rb_hash_stlike_foreach(hash, check_exec_env_i, (st_data_t)env);
2549 *path = env[1];
2550
2551 return env[0];
2552}
2553
2554static VALUE
2555rb_check_argv(int argc, VALUE *argv)
2556{
2557 VALUE tmp, prog;
2558 int i;
2559
2561
2562 prog = 0;
2563 tmp = rb_check_array_type(argv[0]);
2564 if (!NIL_P(tmp)) {
2565 if (RARRAY_LEN(tmp) != 2) {
2566 rb_raise(rb_eArgError, "wrong first argument");
2567 }
2568 prog = RARRAY_AREF(tmp, 0);
2569 argv[0] = RARRAY_AREF(tmp, 1);
2570 SafeStringValue(prog);
2571 StringValueCStr(prog);
2572 prog = rb_str_new_frozen(prog);
2573 }
2574 for (i = 0; i < argc; i++) {
2575 SafeStringValue(argv[i]);
2576 argv[i] = rb_str_new_frozen(argv[i]);
2577 StringValueCStr(argv[i]);
2578 }
2579 return prog;
2580}
2581
2582static VALUE
2583check_hash(VALUE obj)
2584{
2585 if (RB_SPECIAL_CONST_P(obj)) return Qnil;
2586 switch (RB_BUILTIN_TYPE(obj)) {
2587 case T_STRING:
2588 case T_ARRAY:
2589 return Qnil;
2590 default:
2591 break;
2592 }
2593 return rb_check_hash_type(obj);
2594}
2595
2596static VALUE
2597rb_exec_getargs(int *argc_p, VALUE **argv_p, int accept_shell, VALUE *env_ret, VALUE *opthash_ret)
2598{
2599 VALUE hash, prog;
2600
2601 if (0 < *argc_p) {
2602 hash = check_hash((*argv_p)[*argc_p-1]);
2603 if (!NIL_P(hash)) {
2604 *opthash_ret = hash;
2605 (*argc_p)--;
2606 }
2607 }
2608
2609 if (0 < *argc_p) {
2610 hash = check_hash((*argv_p)[0]);
2611 if (!NIL_P(hash)) {
2612 *env_ret = hash;
2613 (*argc_p)--;
2614 (*argv_p)++;
2615 }
2616 }
2617 prog = rb_check_argv(*argc_p, *argv_p);
2618 if (!prog) {
2619 prog = (*argv_p)[0];
2620 if (accept_shell && *argc_p == 1) {
2621 *argc_p = 0;
2622 *argv_p = 0;
2623 }
2624 }
2625 return prog;
2626}
2627
2628#ifndef _WIN32
2630 const char *ptr;
2631 size_t len;
2632};
2633
2634static int
2635compare_posix_sh(const void *key, const void *el)
2636{
2637 const struct string_part *word = key;
2638 int ret = strncmp(word->ptr, el, word->len);
2639 if (!ret && ((const char *)el)[word->len]) ret = -1;
2640 return ret;
2641}
2642#endif
2643
2644static void
2645rb_exec_fillarg(VALUE prog, int argc, VALUE *argv, VALUE env, VALUE opthash, VALUE execarg_obj)
2646{
2647 struct rb_execarg *eargp = rb_execarg_get(execarg_obj);
2648 char fbuf[MAXPATHLEN];
2649
2650 MEMZERO(eargp, struct rb_execarg, 1);
2651
2652 if (!NIL_P(opthash)) {
2653 rb_check_exec_options(opthash, execarg_obj);
2654 }
2655 if (!NIL_P(env)) {
2656 env = rb_check_exec_env(env, &eargp->path_env);
2657 eargp->env_modification = env;
2658 }
2659
2660 prog = EXPORT_STR(prog);
2661 eargp->use_shell = argc == 0;
2662 if (eargp->use_shell)
2663 eargp->invoke.sh.shell_script = prog;
2664 else
2665 eargp->invoke.cmd.command_name = prog;
2666
2667#ifndef _WIN32
2668 if (eargp->use_shell) {
2669 static const char posix_sh_cmds[][9] = {
2670 "!", /* reserved */
2671 ".", /* special built-in */
2672 ":", /* special built-in */
2673 "break", /* special built-in */
2674 "case", /* reserved */
2675 "continue", /* special built-in */
2676 "do", /* reserved */
2677 "done", /* reserved */
2678 "elif", /* reserved */
2679 "else", /* reserved */
2680 "esac", /* reserved */
2681 "eval", /* special built-in */
2682 "exec", /* special built-in */
2683 "exit", /* special built-in */
2684 "export", /* special built-in */
2685 "fi", /* reserved */
2686 "for", /* reserved */
2687 "if", /* reserved */
2688 "in", /* reserved */
2689 "readonly", /* special built-in */
2690 "return", /* special built-in */
2691 "set", /* special built-in */
2692 "shift", /* special built-in */
2693 "then", /* reserved */
2694 "times", /* special built-in */
2695 "trap", /* special built-in */
2696 "unset", /* special built-in */
2697 "until", /* reserved */
2698 "while", /* reserved */
2699 };
2700 const char *p;
2701 struct string_part first = {0, 0};
2702 int has_meta = 0;
2703 /*
2704 * meta characters:
2705 *
2706 * * Pathname Expansion
2707 * ? Pathname Expansion
2708 * {} Grouping Commands
2709 * [] Pathname Expansion
2710 * <> Redirection
2711 * () Grouping Commands
2712 * ~ Tilde Expansion
2713 * & AND Lists, Asynchronous Lists
2714 * | OR Lists, Pipelines
2715 * \ Escape Character
2716 * $ Parameter Expansion
2717 * ; Sequential Lists
2718 * ' Single-Quotes
2719 * ` Command Substitution
2720 * " Double-Quotes
2721 * \n Lists
2722 *
2723 * # Comment
2724 * = Assignment preceding command name
2725 * % (used in Parameter Expansion)
2726 */
2727 for (p = RSTRING_PTR(prog); *p; p++) {
2728 if (*p == ' ' || *p == '\t') {
2729 if (first.ptr && !first.len) first.len = p - first.ptr;
2730 }
2731 else {
2732 if (!first.ptr) first.ptr = p;
2733 }
2734 if (!has_meta && strchr("*?{}[]<>()~&|\\$;'`\"\n#", *p))
2735 has_meta = 1;
2736 if (!first.len) {
2737 if (*p == '=') {
2738 has_meta = 1;
2739 }
2740 else if (*p == '/') {
2741 first.len = 0x100; /* longer than any posix_sh_cmds */
2742 }
2743 }
2744 if (has_meta)
2745 break;
2746 }
2747 if (!has_meta && first.ptr) {
2748 if (!first.len) first.len = p - first.ptr;
2749 if (first.len > 0 && first.len <= sizeof(posix_sh_cmds[0]) &&
2750 bsearch(&first, posix_sh_cmds, numberof(posix_sh_cmds), sizeof(posix_sh_cmds[0]), compare_posix_sh))
2751 has_meta = 1;
2752 }
2753 if (!has_meta) {
2754 /* avoid shell since no shell meta character found. */
2755 eargp->use_shell = 0;
2756 }
2757 if (!eargp->use_shell) {
2758 VALUE argv_buf;
2759 argv_buf = hide_obj(rb_str_buf_new(0));
2760 p = RSTRING_PTR(prog);
2761 while (*p) {
2762 while (*p == ' ' || *p == '\t')
2763 p++;
2764 if (*p) {
2765 const char *w = p;
2766 while (*p && *p != ' ' && *p != '\t')
2767 p++;
2768 rb_str_buf_cat(argv_buf, w, p-w);
2769 rb_str_buf_cat(argv_buf, "", 1); /* append '\0' */
2770 }
2771 }
2772 eargp->invoke.cmd.argv_buf = argv_buf;
2773 eargp->invoke.cmd.command_name =
2774 hide_obj(rb_str_subseq(argv_buf, 0, strlen(RSTRING_PTR(argv_buf))));
2775 rb_enc_copy(eargp->invoke.cmd.command_name, prog);
2776 }
2777 }
2778#endif
2779
2780 if (!eargp->use_shell) {
2781 const char *abspath;
2782 const char *path_env = 0;
2783 if (RTEST(eargp->path_env)) path_env = RSTRING_PTR(eargp->path_env);
2784 abspath = dln_find_exe_r(RSTRING_PTR(eargp->invoke.cmd.command_name),
2785 path_env, fbuf, sizeof(fbuf));
2786 if (abspath)
2787 eargp->invoke.cmd.command_abspath = rb_str_new_cstr(abspath);
2788 else
2789 eargp->invoke.cmd.command_abspath = Qnil;
2790 }
2791
2792 if (!eargp->use_shell && !eargp->invoke.cmd.argv_buf) {
2793 int i;
2794 VALUE argv_buf;
2795 argv_buf = rb_str_buf_new(0);
2796 hide_obj(argv_buf);
2797 for (i = 0; i < argc; i++) {
2798 VALUE arg = argv[i];
2799 const char *s = StringValueCStr(arg);
2800#ifdef DEFAULT_PROCESS_ENCODING
2801 arg = EXPORT_STR(arg);
2802 s = RSTRING_PTR(arg);
2803#endif
2804 rb_str_buf_cat(argv_buf, s, RSTRING_LEN(arg) + 1); /* include '\0' */
2805 }
2806 eargp->invoke.cmd.argv_buf = argv_buf;
2807 }
2808
2809 if (!eargp->use_shell) {
2810 const char *p, *ep, *null=NULL;
2811 VALUE argv_str;
2812 argv_str = hide_obj(rb_str_buf_new(sizeof(char*) * (argc + 2)));
2813 rb_str_buf_cat(argv_str, (char *)&null, sizeof(null)); /* place holder for /bin/sh of try_with_sh. */
2814 p = RSTRING_PTR(eargp->invoke.cmd.argv_buf);
2815 ep = p + RSTRING_LEN(eargp->invoke.cmd.argv_buf);
2816 while (p < ep) {
2817 rb_str_buf_cat(argv_str, (char *)&p, sizeof(p));
2818 p += strlen(p) + 1;
2819 }
2820 rb_str_buf_cat(argv_str, (char *)&null, sizeof(null)); /* terminator for execve. */
2821 eargp->invoke.cmd.argv_str =
2822 rb_imemo_tmpbuf_auto_free_pointer_new_from_an_RString(argv_str);
2823 }
2824 RB_GC_GUARD(execarg_obj);
2825}
2826
2827struct rb_execarg *
2828rb_execarg_get(VALUE execarg_obj)
2829{
2830 struct rb_execarg *eargp;
2831 TypedData_Get_Struct(execarg_obj, struct rb_execarg, &exec_arg_data_type, eargp);
2832 return eargp;
2833}
2834
2835static VALUE
2836rb_execarg_init(int argc, const VALUE *orig_argv, int accept_shell, VALUE execarg_obj)
2837{
2838 struct rb_execarg *eargp = rb_execarg_get(execarg_obj);
2839 VALUE prog, ret;
2840 VALUE env = Qnil, opthash = Qnil;
2841 VALUE argv_buf;
2842 VALUE *argv = ALLOCV_N(VALUE, argv_buf, argc);
2843 MEMCPY(argv, orig_argv, VALUE, argc);
2844 prog = rb_exec_getargs(&argc, &argv, accept_shell, &env, &opthash);
2845 rb_exec_fillarg(prog, argc, argv, env, opthash, execarg_obj);
2846 ALLOCV_END(argv_buf);
2847 ret = eargp->use_shell ? eargp->invoke.sh.shell_script : eargp->invoke.cmd.command_name;
2848 RB_GC_GUARD(execarg_obj);
2849 return ret;
2850}
2851
2852VALUE
2853rb_execarg_new(int argc, const VALUE *argv, int accept_shell, int allow_exc_opt)
2854{
2855 VALUE execarg_obj;
2856 struct rb_execarg *eargp;
2857 execarg_obj = TypedData_Make_Struct(0, struct rb_execarg, &exec_arg_data_type, eargp);
2858 rb_execarg_init(argc, argv, accept_shell, execarg_obj);
2859 if (!allow_exc_opt && eargp->exception_given) {
2860 rb_raise(rb_eArgError, "exception option is not allowed");
2861 }
2862 return execarg_obj;
2863}
2864
2865void
2866rb_execarg_setenv(VALUE execarg_obj, VALUE env)
2867{
2868 struct rb_execarg *eargp = rb_execarg_get(execarg_obj);
2869 env = !NIL_P(env) ? rb_check_exec_env(env, &eargp->path_env) : Qfalse;
2870 eargp->env_modification = env;
2871}
2872
2873static int
2874fill_envp_buf_i(st_data_t st_key, st_data_t st_val, st_data_t arg)
2875{
2876 VALUE key = (VALUE)st_key;
2877 VALUE val = (VALUE)st_val;
2878 VALUE envp_buf = (VALUE)arg;
2879
2880 rb_str_buf_cat2(envp_buf, StringValueCStr(key));
2881 rb_str_buf_cat2(envp_buf, "=");
2882 rb_str_buf_cat2(envp_buf, StringValueCStr(val));
2883 rb_str_buf_cat(envp_buf, "", 1); /* append '\0' */
2884
2885 return ST_CONTINUE;
2886}
2887
2888
2889static long run_exec_dup2_tmpbuf_size(long n);
2890
2892 VALUE fname;
2893 int oflags;
2894 mode_t perm;
2895 int ret;
2896 int err;
2897};
2898
2899static void *
2900open_func(void *ptr)
2901{
2902 struct open_struct *data = ptr;
2903 const char *fname = RSTRING_PTR(data->fname);
2904 data->ret = parent_redirect_open(fname, data->oflags, data->perm);
2905 data->err = errno;
2906 return NULL;
2907}
2908
2909static void
2910rb_execarg_allocate_dup2_tmpbuf(struct rb_execarg *eargp, long len)
2911{
2912 VALUE tmpbuf = rb_imemo_tmpbuf_auto_free_pointer();
2913 rb_imemo_tmpbuf_set_ptr(tmpbuf, ruby_xmalloc(run_exec_dup2_tmpbuf_size(len)));
2914 eargp->dup2_tmpbuf = tmpbuf;
2915}
2916
2917static VALUE
2918rb_execarg_parent_start1(VALUE execarg_obj)
2919{
2920 struct rb_execarg *eargp = rb_execarg_get(execarg_obj);
2921 int unsetenv_others;
2922 VALUE envopts;
2923 VALUE ary;
2924
2925 ary = eargp->fd_open;
2926 if (ary != Qfalse) {
2927 long i;
2928 for (i = 0; i < RARRAY_LEN(ary); i++) {
2929 VALUE elt = RARRAY_AREF(ary, i);
2930 int fd = FIX2INT(RARRAY_AREF(elt, 0));
2931 VALUE param = RARRAY_AREF(elt, 1);
2932 VALUE vpath = RARRAY_AREF(param, 0);
2933 int flags = NUM2INT(RARRAY_AREF(param, 1));
2934 mode_t perm = NUM2MODET(RARRAY_AREF(param, 2));
2935 VALUE fd2v = RARRAY_AREF(param, 3);
2936 int fd2;
2937 if (NIL_P(fd2v)) {
2938 struct open_struct open_data;
2939 again:
2940 open_data.fname = vpath;
2941 open_data.oflags = flags;
2942 open_data.perm = perm;
2943 open_data.ret = -1;
2944 open_data.err = EINTR;
2945 rb_thread_call_without_gvl2(open_func, (void *)&open_data, RUBY_UBF_IO, 0);
2946 if (open_data.ret == -1) {
2947 if (open_data.err == EINTR) {
2949 goto again;
2950 }
2951 rb_syserr_fail_str(open_data.err, vpath);
2952 }
2953 fd2 = open_data.ret;
2954 rb_update_max_fd(fd2);
2955 RARRAY_ASET(param, 3, INT2FIX(fd2));
2957 }
2958 else {
2959 fd2 = NUM2INT(fd2v);
2960 }
2961 rb_execarg_addopt(execarg_obj, INT2FIX(fd), INT2FIX(fd2));
2962 }
2963 }
2964
2965 eargp->redirect_fds = check_exec_fds(eargp);
2966
2967 ary = eargp->fd_dup2;
2968 if (ary != Qfalse) {
2969 rb_execarg_allocate_dup2_tmpbuf(eargp, RARRAY_LEN(ary));
2970 }
2971
2972 unsetenv_others = eargp->unsetenv_others_given && eargp->unsetenv_others_do;
2973 envopts = eargp->env_modification;
2974 if (ALWAYS_NEED_ENVP || unsetenv_others || envopts != Qfalse) {
2975 VALUE envtbl, envp_str, envp_buf;
2976 char *p, *ep;
2977 if (unsetenv_others) {
2978 envtbl = rb_hash_new();
2979 }
2980 else {
2981 envtbl = rb_env_to_hash();
2982 }
2983 hide_obj(envtbl);
2984 if (envopts != Qfalse) {
2985 st_table *stenv = RHASH_TBL_RAW(envtbl);
2986 long i;
2987 for (i = 0; i < RARRAY_LEN(envopts); i++) {
2988 VALUE pair = RARRAY_AREF(envopts, i);
2989 VALUE key = RARRAY_AREF(pair, 0);
2990 VALUE val = RARRAY_AREF(pair, 1);
2991 if (NIL_P(val)) {
2992 st_data_t stkey = (st_data_t)key;
2993 st_delete(stenv, &stkey, NULL);
2994 }
2995 else {
2996 st_insert(stenv, (st_data_t)key, (st_data_t)val);
2997 RB_OBJ_WRITTEN(envtbl, Qundef, key);
2998 RB_OBJ_WRITTEN(envtbl, Qundef, val);
2999 }
3000 }
3001 }
3002 envp_buf = rb_str_buf_new(0);
3003 hide_obj(envp_buf);
3004 rb_hash_stlike_foreach(envtbl, fill_envp_buf_i, (st_data_t)envp_buf);
3005 envp_str = rb_str_buf_new(sizeof(char*) * (RHASH_SIZE(envtbl) + 1));
3006 hide_obj(envp_str);
3007 p = RSTRING_PTR(envp_buf);
3008 ep = p + RSTRING_LEN(envp_buf);
3009 while (p < ep) {
3010 rb_str_buf_cat(envp_str, (char *)&p, sizeof(p));
3011 p += strlen(p) + 1;
3012 }
3013 p = NULL;
3014 rb_str_buf_cat(envp_str, (char *)&p, sizeof(p));
3015 eargp->envp_str =
3016 rb_imemo_tmpbuf_auto_free_pointer_new_from_an_RString(envp_str);
3017 eargp->envp_buf = envp_buf;
3018
3019 /*
3020 char **tmp_envp = (char **)RSTRING_PTR(envp_str);
3021 while (*tmp_envp) {
3022 printf("%s\n", *tmp_envp);
3023 tmp_envp++;
3024 }
3025 */
3026 }
3027
3028 RB_GC_GUARD(execarg_obj);
3029 return Qnil;
3030}
3031
3032void
3033rb_execarg_parent_start(VALUE execarg_obj)
3034{
3035 int state;
3036 rb_protect(rb_execarg_parent_start1, execarg_obj, &state);
3037 if (state) {
3038 rb_execarg_parent_end(execarg_obj);
3039 rb_jump_tag(state);
3040 }
3041}
3042
3043static VALUE
3044execarg_parent_end(VALUE execarg_obj)
3045{
3046 struct rb_execarg *eargp = rb_execarg_get(execarg_obj);
3047 int err = errno;
3048 VALUE ary;
3049
3050 ary = eargp->fd_open;
3051 if (ary != Qfalse) {
3052 long i;
3053 for (i = 0; i < RARRAY_LEN(ary); i++) {
3054 VALUE elt = RARRAY_AREF(ary, i);
3055 VALUE param = RARRAY_AREF(elt, 1);
3056 VALUE fd2v;
3057 int fd2;
3058 fd2v = RARRAY_AREF(param, 3);
3059 if (!NIL_P(fd2v)) {
3060 fd2 = FIX2INT(fd2v);
3061 parent_redirect_close(fd2);
3062 RARRAY_ASET(param, 3, Qnil);
3063 }
3064 }
3065 }
3066
3067 errno = err;
3068 return execarg_obj;
3069}
3070
3071void
3072rb_execarg_parent_end(VALUE execarg_obj)
3073{
3074 execarg_parent_end(execarg_obj);
3075 RB_GC_GUARD(execarg_obj);
3076}
3077
3078static void
3079rb_exec_fail(struct rb_execarg *eargp, int err, const char *errmsg)
3080{
3081 if (!errmsg || !*errmsg) return;
3082 if (strcmp(errmsg, "chdir") == 0) {
3083 rb_sys_fail_str(eargp->chdir_dir);
3084 }
3085 rb_sys_fail(errmsg);
3086}
3087
3088#if 0
3089void
3090rb_execarg_fail(VALUE execarg_obj, int err, const char *errmsg)
3091{
3092 if (!errmsg || !*errmsg) return;
3093 rb_exec_fail(rb_execarg_get(execarg_obj), err, errmsg);
3094 RB_GC_GUARD(execarg_obj);
3095}
3096#endif
3097
3098VALUE
3099rb_f_exec(int argc, const VALUE *argv)
3100{
3101 VALUE execarg_obj, fail_str;
3102 struct rb_execarg *eargp;
3103#define CHILD_ERRMSG_BUFLEN 80
3104 char errmsg[CHILD_ERRMSG_BUFLEN] = { '\0' };
3105 int err, state;
3106
3107 execarg_obj = rb_execarg_new(argc, argv, TRUE, FALSE);
3108 eargp = rb_execarg_get(execarg_obj);
3109 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.
3110 before_exec(); /* stop timer thread before redirects */
3111
3112 rb_protect(rb_execarg_parent_start1, execarg_obj, &state);
3113 if (state) {
3114 execarg_parent_end(execarg_obj);
3115 after_exec(); /* restart timer thread */
3116 rb_jump_tag(state);
3117 }
3118
3119 fail_str = eargp->use_shell ? eargp->invoke.sh.shell_script : eargp->invoke.cmd.command_name;
3120
3121 err = exec_async_signal_safe(eargp, errmsg, sizeof(errmsg));
3122 after_exec(); /* restart timer thread */
3123
3124 rb_exec_fail(eargp, err, errmsg);
3125 RB_GC_GUARD(execarg_obj);
3126 rb_syserr_fail_str(err, fail_str);
3128}
3129
3130NORETURN(static VALUE f_exec(int c, const VALUE *a, VALUE _));
3131
3132/*
3133 * call-seq:
3134 * exec([env,] command... [,options])
3135 *
3136 * Replaces the current process by running the given external _command_, which
3137 * can take one of the following forms:
3138 *
3139 * [<code>exec(commandline)</code>]
3140 * command line string which is passed to the standard shell
3141 * [<code>exec(cmdname, arg1, ...)</code>]
3142 * command name and one or more arguments (no shell)
3143 * [<code>exec([cmdname, argv0], arg1, ...)</code>]
3144 * command name, +argv[0]+ and zero or more arguments (no shell)
3145 *
3146 * In the first form, the string is taken as a command line that is subject to
3147 * shell expansion before being executed.
3148 *
3149 * The standard shell always means <code>"/bin/sh"</code> on Unix-like systems,
3150 * otherwise, <code>ENV["RUBYSHELL"]</code> or <code>ENV["COMSPEC"]</code> on
3151 * Windows and similar. The command is passed as an argument to the
3152 * <code>"-c"</code> switch to the shell, except in the case of +COMSPEC+.
3153 *
3154 * If the string from the first form (<code>exec("command")</code>) follows
3155 * these simple rules:
3156 *
3157 * * no meta characters,
3158 * * not starting with shell reserved word or special built-in,
3159 *
3160 * Ruby invokes the command directly without shell.
3161 *
3162 * You can force shell invocation by adding ";" to the string (because ";" is
3163 * a meta character).
3164 *
3165 * Note that this behavior is observable by pid obtained
3166 * (return value of spawn() and IO#pid for IO.popen) is the pid of the invoked
3167 * command, not shell.
3168 *
3169 * In the second form (<code>exec("command1", "arg1", ...)</code>), the first
3170 * is taken as a command name and the rest are passed as parameters to command
3171 * with no shell expansion.
3172 *
3173 * In the third form (<code>exec(["command", "argv0"], "arg1", ...)</code>),
3174 * starting a two-element array at the beginning of the command, the first
3175 * element is the command to be executed, and the second argument is used as
3176 * the <code>argv[0]</code> value, which may show up in process listings.
3177 *
3178 * In order to execute the command, one of the <code>exec(2)</code> system
3179 * calls are used, so the running command may inherit some of the environment
3180 * of the original program (including open file descriptors).
3181 *
3182 * This behavior is modified by the given +env+ and +options+ parameters. See
3183 * ::spawn for details.
3184 *
3185 * If the command fails to execute (typically Errno::ENOENT when
3186 * it was not found) a SystemCallError exception is raised.
3187 *
3188 * This method modifies process attributes according to given +options+ before
3189 * <code>exec(2)</code> system call. See ::spawn for more details about the
3190 * given +options+.
3191 *
3192 * The modified attributes may be retained when <code>exec(2)</code> system
3193 * call fails.
3194 *
3195 * For example, hard resource limits are not restorable.
3196 *
3197 * Consider to create a child process using ::spawn or Kernel#system if this
3198 * is not acceptable.
3199 *
3200 * exec "echo *" # echoes list of files in current directory
3201 * # never get here
3202 *
3203 * exec "echo", "*" # echoes an asterisk
3204 * # never get here
3205 */
3206
3207static VALUE
3208f_exec(int c, const VALUE *a, VALUE _)
3209{
3210 rb_f_exec(c, a);
3212}
3213
3214#define ERRMSG(str) do { if (errmsg && 0 < errmsg_buflen) strlcpy(errmsg, (str), errmsg_buflen); } while (0)
3215#define ERRMSG1(str, a) do { if (errmsg && 0 < errmsg_buflen) snprintf(errmsg, errmsg_buflen, (str), (a)); } while (0)
3216#define ERRMSG2(str, a, b) do { if (errmsg && 0 < errmsg_buflen) snprintf(errmsg, errmsg_buflen, (str), (a), (b)); } while (0)
3217
3218static int fd_get_cloexec(int fd, char *errmsg, size_t errmsg_buflen);
3219static int fd_set_cloexec(int fd, char *errmsg, size_t errmsg_buflen);
3220static int fd_clear_cloexec(int fd, char *errmsg, size_t errmsg_buflen);
3221
3222static int
3223save_redirect_fd(int fd, struct rb_execarg *sargp, char *errmsg, size_t errmsg_buflen)
3224{
3225 if (sargp) {
3226 VALUE newary, redirection;
3227 int save_fd = redirect_cloexec_dup(fd), cloexec;
3228 if (save_fd == -1) {
3229 if (errno == EBADF)
3230 return 0;
3231 ERRMSG("dup");
3232 return -1;
3233 }
3234 rb_update_max_fd(save_fd);
3235 newary = sargp->fd_dup2;
3236 if (newary == Qfalse) {
3237 newary = hide_obj(rb_ary_new());
3238 sargp->fd_dup2 = newary;
3239 }
3240 cloexec = fd_get_cloexec(fd, errmsg, errmsg_buflen);
3241 redirection = hide_obj(rb_assoc_new(INT2FIX(fd), INT2FIX(save_fd)));
3242 if (cloexec) rb_ary_push(redirection, Qtrue);
3243 rb_ary_push(newary, redirection);
3244
3245 newary = sargp->fd_close;
3246 if (newary == Qfalse) {
3247 newary = hide_obj(rb_ary_new());
3248 sargp->fd_close = newary;
3249 }
3250 rb_ary_push(newary, hide_obj(rb_assoc_new(INT2FIX(save_fd), Qnil)));
3251 }
3252
3253 return 0;
3254}
3255
3256static int
3257intcmp(const void *a, const void *b)
3258{
3259 return *(int*)a - *(int*)b;
3260}
3261
3262static int
3263intrcmp(const void *a, const void *b)
3264{
3265 return *(int*)b - *(int*)a;
3266}
3267
3269 int oldfd;
3270 int newfd;
3271 long older_index;
3272 long num_newer;
3273 int cloexec;
3274};
3275
3276static long
3277run_exec_dup2_tmpbuf_size(long n)
3278{
3279 return sizeof(struct run_exec_dup2_fd_pair) * n;
3280}
3281
3282/* This function should be async-signal-safe. Actually it is. */
3283static int
3284fd_get_cloexec(int fd, char *errmsg, size_t errmsg_buflen)
3285{
3286#ifdef F_GETFD
3287 int ret = 0;
3288 ret = fcntl(fd, F_GETFD); /* async-signal-safe */
3289 if (ret == -1) {
3290 ERRMSG("fcntl(F_GETFD)");
3291 return -1;
3292 }
3293 if (ret & FD_CLOEXEC) return 1;
3294#endif
3295 return 0;
3296}
3297
3298/* This function should be async-signal-safe. Actually it is. */
3299static int
3300fd_set_cloexec(int fd, char *errmsg, size_t errmsg_buflen)
3301{
3302#ifdef F_GETFD
3303 int ret = 0;
3304 ret = fcntl(fd, F_GETFD); /* async-signal-safe */
3305 if (ret == -1) {
3306 ERRMSG("fcntl(F_GETFD)");
3307 return -1;
3308 }
3309 if (!(ret & FD_CLOEXEC)) {
3310 ret |= FD_CLOEXEC;
3311 ret = fcntl(fd, F_SETFD, ret); /* async-signal-safe */
3312 if (ret == -1) {
3313 ERRMSG("fcntl(F_SETFD)");
3314 return -1;
3315 }
3316 }
3317#endif
3318 return 0;
3319}
3320
3321/* This function should be async-signal-safe. Actually it is. */
3322static int
3323fd_clear_cloexec(int fd, char *errmsg, size_t errmsg_buflen)
3324{
3325#ifdef F_GETFD
3326 int ret;
3327 ret = fcntl(fd, F_GETFD); /* async-signal-safe */
3328 if (ret == -1) {
3329 ERRMSG("fcntl(F_GETFD)");
3330 return -1;
3331 }
3332 if (ret & FD_CLOEXEC) {
3333 ret &= ~FD_CLOEXEC;
3334 ret = fcntl(fd, F_SETFD, ret); /* async-signal-safe */
3335 if (ret == -1) {
3336 ERRMSG("fcntl(F_SETFD)");
3337 return -1;
3338 }
3339 }
3340#endif
3341 return 0;
3342}
3343
3344/* This function should be async-signal-safe when sargp is NULL. Hopefully it is. */
3345static int
3346run_exec_dup2(VALUE ary, VALUE tmpbuf, struct rb_execarg *sargp, char *errmsg, size_t errmsg_buflen)
3347{
3348 long n, i;
3349 int ret;
3350 int extra_fd = -1;
3351 struct rb_imemo_tmpbuf_struct *buf = (void *)tmpbuf;
3352 struct run_exec_dup2_fd_pair *pairs = (void *)buf->ptr;
3353
3354 n = RARRAY_LEN(ary);
3355
3356 /* initialize oldfd and newfd: O(n) */
3357 for (i = 0; i < n; i++) {
3358 VALUE elt = RARRAY_AREF(ary, i);
3359 pairs[i].oldfd = FIX2INT(RARRAY_AREF(elt, 1));
3360 pairs[i].newfd = FIX2INT(RARRAY_AREF(elt, 0)); /* unique */
3361 pairs[i].cloexec = RARRAY_LEN(elt) > 2 && RTEST(RARRAY_AREF(elt, 2));
3362 pairs[i].older_index = -1;
3363 }
3364
3365 /* sort the table by oldfd: O(n log n) */
3366 if (!sargp)
3367 qsort(pairs, n, sizeof(struct run_exec_dup2_fd_pair), intcmp); /* hopefully async-signal-safe */
3368 else
3369 qsort(pairs, n, sizeof(struct run_exec_dup2_fd_pair), intrcmp);
3370
3371 /* initialize older_index and num_newer: O(n log n) */
3372 for (i = 0; i < n; i++) {
3373 int newfd = pairs[i].newfd;
3374 struct run_exec_dup2_fd_pair key, *found;
3375 key.oldfd = newfd;
3376 found = bsearch(&key, pairs, n, sizeof(struct run_exec_dup2_fd_pair), intcmp); /* hopefully async-signal-safe */
3377 pairs[i].num_newer = 0;
3378 if (found) {
3379 while (pairs < found && (found-1)->oldfd == newfd)
3380 found--;
3381 while (found < pairs+n && found->oldfd == newfd) {
3382 pairs[i].num_newer++;
3383 found->older_index = i;
3384 found++;
3385 }
3386 }
3387 }
3388
3389 /* non-cyclic redirection: O(n) */
3390 for (i = 0; i < n; i++) {
3391 long j = i;
3392 while (j != -1 && pairs[j].oldfd != -1 && pairs[j].num_newer == 0) {
3393 if (save_redirect_fd(pairs[j].newfd, sargp, errmsg, errmsg_buflen) < 0) /* async-signal-safe */
3394 goto fail;
3395 ret = redirect_dup2(pairs[j].oldfd, pairs[j].newfd); /* async-signal-safe */
3396 if (ret == -1) {
3397 ERRMSG("dup2");
3398 goto fail;
3399 }
3400 if (pairs[j].cloexec &&
3401 fd_set_cloexec(pairs[j].newfd, errmsg, errmsg_buflen)) {
3402 goto fail;
3403 }
3404 rb_update_max_fd(pairs[j].newfd); /* async-signal-safe but don't need to call it in a child process. */
3405 pairs[j].oldfd = -1;
3406 j = pairs[j].older_index;
3407 if (j != -1)
3408 pairs[j].num_newer--;
3409 }
3410 }
3411
3412 /* cyclic redirection: O(n) */
3413 for (i = 0; i < n; i++) {
3414 long j;
3415 if (pairs[i].oldfd == -1)
3416 continue;
3417 if (pairs[i].oldfd == pairs[i].newfd) { /* self cycle */
3418 if (fd_clear_cloexec(pairs[i].oldfd, errmsg, errmsg_buflen) == -1) /* async-signal-safe */
3419 goto fail;
3420 pairs[i].oldfd = -1;
3421 continue;
3422 }
3423 if (extra_fd == -1) {
3424 extra_fd = redirect_dup(pairs[i].oldfd); /* async-signal-safe */
3425 if (extra_fd == -1) {
3426 ERRMSG("dup");
3427 goto fail;
3428 }
3429 rb_update_max_fd(extra_fd);
3430 }
3431 else {
3432 ret = redirect_dup2(pairs[i].oldfd, extra_fd); /* async-signal-safe */
3433 if (ret == -1) {
3434 ERRMSG("dup2");
3435 goto fail;
3436 }
3437 rb_update_max_fd(extra_fd);
3438 }
3439 pairs[i].oldfd = extra_fd;
3440 j = pairs[i].older_index;
3441 pairs[i].older_index = -1;
3442 while (j != -1) {
3443 ret = redirect_dup2(pairs[j].oldfd, pairs[j].newfd); /* async-signal-safe */
3444 if (ret == -1) {
3445 ERRMSG("dup2");
3446 goto fail;
3447 }
3448 rb_update_max_fd(ret);
3449 pairs[j].oldfd = -1;
3450 j = pairs[j].older_index;
3451 }
3452 }
3453 if (extra_fd != -1) {
3454 ret = redirect_close(extra_fd); /* async-signal-safe */
3455 if (ret == -1) {
3456 ERRMSG("close");
3457 goto fail;
3458 }
3459 }
3460
3461 return 0;
3462
3463 fail:
3464 return -1;
3465}
3466
3467/* This function should be async-signal-safe. Actually it is. */
3468static int
3469run_exec_close(VALUE ary, char *errmsg, size_t errmsg_buflen)
3470{
3471 long i;
3472 int ret;
3473
3474 for (i = 0; i < RARRAY_LEN(ary); i++) {
3475 VALUE elt = RARRAY_AREF(ary, i);
3476 int fd = FIX2INT(RARRAY_AREF(elt, 0));
3477 ret = redirect_close(fd); /* async-signal-safe */
3478 if (ret == -1) {
3479 ERRMSG("close");
3480 return -1;
3481 }
3482 }
3483 return 0;
3484}
3485
3486/* This function should be async-signal-safe when sargp is NULL. Actually it is. */
3487static int
3488run_exec_dup2_child(VALUE ary, struct rb_execarg *sargp, char *errmsg, size_t errmsg_buflen)
3489{
3490 long i;
3491 int ret;
3492
3493 for (i = 0; i < RARRAY_LEN(ary); i++) {
3494 VALUE elt = RARRAY_AREF(ary, i);
3495 int newfd = FIX2INT(RARRAY_AREF(elt, 0));
3496 int oldfd = FIX2INT(RARRAY_AREF(elt, 1));
3497
3498 if (save_redirect_fd(newfd, sargp, errmsg, errmsg_buflen) < 0) /* async-signal-safe */
3499 return -1;
3500 ret = redirect_dup2(oldfd, newfd); /* async-signal-safe */
3501 if (ret == -1) {
3502 ERRMSG("dup2");
3503 return -1;
3504 }
3505 rb_update_max_fd(newfd);
3506 }
3507 return 0;
3508}
3509
3510#ifdef HAVE_SETPGID
3511/* This function should be async-signal-safe when sargp is NULL. Actually it is. */
3512static int
3513run_exec_pgroup(const struct rb_execarg *eargp, struct rb_execarg *sargp, char *errmsg, size_t errmsg_buflen)
3514{
3515 /*
3516 * If FD_CLOEXEC is available, rb_fork_async_signal_safe waits the child's execve.
3517 * So setpgid is done in the child when rb_fork_async_signal_safe is returned in
3518 * the parent.
3519 * No race condition, even without setpgid from the parent.
3520 * (Is there an environment which has setpgid but no FD_CLOEXEC?)
3521 */
3522 int ret;
3523 rb_pid_t pgroup;
3524
3525 pgroup = eargp->pgroup_pgid;
3526 if (pgroup == -1)
3527 return 0;
3528
3529 if (sargp) {
3530 /* maybe meaningless with no fork environment... */
3531 sargp->pgroup_given = 1;
3532 sargp->pgroup_pgid = getpgrp();
3533 }
3534
3535 if (pgroup == 0) {
3536 pgroup = getpid(); /* async-signal-safe */
3537 }
3538 ret = setpgid(getpid(), pgroup); /* async-signal-safe */
3539 if (ret == -1) ERRMSG("setpgid");
3540 return ret;
3541}
3542#endif
3543
3544#if defined(HAVE_SETRLIMIT) && defined(RLIM2NUM)
3545/* This function should be async-signal-safe when sargp is NULL. Hopefully it is. */
3546static int
3547run_exec_rlimit(VALUE ary, struct rb_execarg *sargp, char *errmsg, size_t errmsg_buflen)
3548{
3549 long i;
3550 for (i = 0; i < RARRAY_LEN(ary); i++) {
3551 VALUE elt = RARRAY_AREF(ary, i);
3552 int rtype = NUM2INT(RARRAY_AREF(elt, 0));
3553 struct rlimit rlim;
3554 if (sargp) {
3555 VALUE tmp, newary;
3556 if (getrlimit(rtype, &rlim) == -1) {
3557 ERRMSG("getrlimit");
3558 return -1;
3559 }
3560 tmp = hide_obj(rb_ary_new3(3, RARRAY_AREF(elt, 0),
3561 RLIM2NUM(rlim.rlim_cur),
3562 RLIM2NUM(rlim.rlim_max)));
3563 if (sargp->rlimit_limits == Qfalse)
3564 newary = sargp->rlimit_limits = hide_obj(rb_ary_new());
3565 else
3566 newary = sargp->rlimit_limits;
3567 rb_ary_push(newary, tmp);
3568 }
3569 rlim.rlim_cur = NUM2RLIM(RARRAY_AREF(elt, 1));
3570 rlim.rlim_max = NUM2RLIM(RARRAY_AREF(elt, 2));
3571 if (setrlimit(rtype, &rlim) == -1) { /* hopefully async-signal-safe */
3572 ERRMSG("setrlimit");
3573 return -1;
3574 }
3575 }
3576 return 0;
3577}
3578#endif
3579
3580#if !defined(HAVE_WORKING_FORK)
3581static VALUE
3582save_env_i(RB_BLOCK_CALL_FUNC_ARGLIST(i, ary))
3583{
3584 rb_ary_push(ary, hide_obj(rb_ary_dup(argv[0])));
3585 return Qnil;
3586}
3587
3588static void
3589save_env(struct rb_execarg *sargp)
3590{
3591 if (!sargp)
3592 return;
3593 if (sargp->env_modification == Qfalse) {
3594 VALUE env = rb_envtbl();
3595 if (RTEST(env)) {
3596 VALUE ary = hide_obj(rb_ary_new());
3597 rb_block_call(env, idEach, 0, 0, save_env_i,
3598 (VALUE)ary);
3599 sargp->env_modification = ary;
3600 }
3601 sargp->unsetenv_others_given = 1;
3602 sargp->unsetenv_others_do = 1;
3603 }
3604}
3605#endif
3606
3607#ifdef _WIN32
3608#undef chdir
3609#define chdir(p) rb_w32_uchdir(p)
3610#endif
3611
3612/* This function should be async-signal-safe when sargp is NULL. Hopefully it is. */
3613int
3614rb_execarg_run_options(const struct rb_execarg *eargp, struct rb_execarg *sargp, char *errmsg, size_t errmsg_buflen)
3615{
3616 VALUE obj;
3617
3618 if (sargp) {
3619 /* assume that sargp is always NULL on fork-able environments */
3620 MEMZERO(sargp, struct rb_execarg, 1);
3621 sargp->redirect_fds = Qnil;
3622 }
3623
3624#ifdef HAVE_SETPGID
3625 if (eargp->pgroup_given) {
3626 if (run_exec_pgroup(eargp, sargp, errmsg, errmsg_buflen) == -1) /* async-signal-safe */
3627 return -1;
3628 }
3629#endif
3630
3631#if defined(HAVE_SETRLIMIT) && defined(RLIM2NUM)
3632 obj = eargp->rlimit_limits;
3633 if (obj != Qfalse) {
3634 if (run_exec_rlimit(obj, sargp, errmsg, errmsg_buflen) == -1) /* hopefully async-signal-safe */
3635 return -1;
3636 }
3637#endif
3638
3639#if !defined(HAVE_WORKING_FORK)
3640 if (eargp->unsetenv_others_given && eargp->unsetenv_others_do) {
3641 save_env(sargp);
3642 rb_env_clear();
3643 }
3644
3645 obj = eargp->env_modification;
3646 if (obj != Qfalse) {
3647 long i;
3648 save_env(sargp);
3649 for (i = 0; i < RARRAY_LEN(obj); i++) {
3650 VALUE pair = RARRAY_AREF(obj, i);
3651 VALUE key = RARRAY_AREF(pair, 0);
3652 VALUE val = RARRAY_AREF(pair, 1);
3653 if (NIL_P(val))
3654 ruby_setenv(StringValueCStr(key), 0);
3655 else
3656 ruby_setenv(StringValueCStr(key), StringValueCStr(val));
3657 }
3658 }
3659#endif
3660
3661 if (eargp->umask_given) {
3662 mode_t mask = eargp->umask_mask;
3663 mode_t oldmask = umask(mask); /* never fail */ /* async-signal-safe */
3664 if (sargp) {
3665 sargp->umask_given = 1;
3666 sargp->umask_mask = oldmask;
3667 }
3668 }
3669
3670 obj = eargp->fd_dup2;
3671 if (obj != Qfalse) {
3672 if (run_exec_dup2(obj, eargp->dup2_tmpbuf, sargp, errmsg, errmsg_buflen) == -1) /* hopefully async-signal-safe */
3673 return -1;
3674 }
3675
3676 obj = eargp->fd_close;
3677 if (obj != Qfalse) {
3678 if (sargp)
3679 rb_warn("cannot close fd before spawn");
3680 else {
3681 if (run_exec_close(obj, errmsg, errmsg_buflen) == -1) /* async-signal-safe */
3682 return -1;
3683 }
3684 }
3685
3686#ifdef HAVE_WORKING_FORK
3687 if (eargp->close_others_do) {
3688 rb_close_before_exec(3, eargp->close_others_maxhint, eargp->redirect_fds); /* async-signal-safe */
3689 }
3690#endif
3691
3692 obj = eargp->fd_dup2_child;
3693 if (obj != Qfalse) {
3694 if (run_exec_dup2_child(obj, sargp, errmsg, errmsg_buflen) == -1) /* async-signal-safe */
3695 return -1;
3696 }
3697
3698 if (eargp->chdir_given) {
3699 if (sargp) {
3700 sargp->chdir_given = 1;
3701 sargp->chdir_dir = hide_obj(rb_dir_getwd_ospath());
3702 }
3703 if (chdir(RSTRING_PTR(eargp->chdir_dir)) == -1) { /* async-signal-safe */
3704 ERRMSG("chdir");
3705 return -1;
3706 }
3707 }
3708
3709#ifdef HAVE_SETGID
3710 if (eargp->gid_given) {
3711 if (setgid(eargp->gid) < 0) {
3712 ERRMSG("setgid");
3713 return -1;
3714 }
3715 }
3716#endif
3717#ifdef HAVE_SETUID
3718 if (eargp->uid_given) {
3719 if (setuid(eargp->uid) < 0) {
3720 ERRMSG("setuid");
3721 return -1;
3722 }
3723 }
3724#endif
3725
3726 if (sargp) {
3727 VALUE ary = sargp->fd_dup2;
3728 if (ary != Qfalse) {
3729 rb_execarg_allocate_dup2_tmpbuf(sargp, RARRAY_LEN(ary));
3730 }
3731 }
3732 {
3733 int preserve = errno;
3734 stdfd_clear_nonblock();
3735 errno = preserve;
3736 }
3737
3738 return 0;
3739}
3740
3741/* This function should be async-signal-safe. Hopefully it is. */
3742int
3743rb_exec_async_signal_safe(const struct rb_execarg *eargp, char *errmsg, size_t errmsg_buflen)
3744{
3745 errno = exec_async_signal_safe(eargp, errmsg, errmsg_buflen);
3746 return -1;
3747}
3748
3749static int
3750exec_async_signal_safe(const struct rb_execarg *eargp, char *errmsg, size_t errmsg_buflen)
3751{
3752#if !defined(HAVE_WORKING_FORK)
3753 struct rb_execarg sarg, *const sargp = &sarg;
3754#else
3755 struct rb_execarg *const sargp = NULL;
3756#endif
3757 int err;
3758
3759 if (rb_execarg_run_options(eargp, sargp, errmsg, errmsg_buflen) < 0) { /* hopefully async-signal-safe */
3760 return errno;
3761 }
3762
3763 if (eargp->use_shell) {
3764 err = proc_exec_sh(RSTRING_PTR(eargp->invoke.sh.shell_script), eargp->envp_str); /* async-signal-safe */
3765 }
3766 else {
3767 char *abspath = NULL;
3768 if (!NIL_P(eargp->invoke.cmd.command_abspath))
3769 abspath = RSTRING_PTR(eargp->invoke.cmd.command_abspath);
3770 err = proc_exec_cmd(abspath, eargp->invoke.cmd.argv_str, eargp->envp_str); /* async-signal-safe */
3771 }
3772#if !defined(HAVE_WORKING_FORK)
3773 rb_execarg_run_options(sargp, NULL, errmsg, errmsg_buflen);
3774#endif
3775
3776 return err;
3777}
3778
3779#ifdef HAVE_WORKING_FORK
3780/* This function should be async-signal-safe. Hopefully it is. */
3781static int
3782rb_exec_atfork(void* arg, char *errmsg, size_t errmsg_buflen)
3783{
3784 return rb_exec_async_signal_safe(arg, errmsg, errmsg_buflen); /* hopefully async-signal-safe */
3785}
3786
3787static VALUE
3788proc_syswait(VALUE pid)
3789{
3790 rb_syswait((rb_pid_t)pid);
3791 return Qnil;
3792}
3793
3794static int
3795move_fds_to_avoid_crash(int *fdp, int n, VALUE fds)
3796{
3797 int min = 0;
3798 int i;
3799 for (i = 0; i < n; i++) {
3800 int ret;
3801 while (RTEST(rb_hash_lookup(fds, INT2FIX(fdp[i])))) {
3802 if (min <= fdp[i])
3803 min = fdp[i]+1;
3804 while (RTEST(rb_hash_lookup(fds, INT2FIX(min))))
3805 min++;
3806 ret = rb_cloexec_fcntl_dupfd(fdp[i], min);
3807 if (ret == -1)
3808 return -1;
3809 rb_update_max_fd(ret);
3810 close(fdp[i]);
3811 fdp[i] = ret;
3812 }
3813 }
3814 return 0;
3815}
3816
3817static int
3818pipe_nocrash(int filedes[2], VALUE fds)
3819{
3820 int ret;
3821 ret = rb_pipe(filedes);
3822 if (ret == -1)
3823 return -1;
3824 if (RTEST(fds)) {
3825 int save = errno;
3826 if (move_fds_to_avoid_crash(filedes, 2, fds) == -1) {
3827 close(filedes[0]);
3828 close(filedes[1]);
3829 return -1;
3830 }
3831 errno = save;
3832 }
3833 return ret;
3834}
3835
3836#ifndef O_BINARY
3837#define O_BINARY 0
3838#endif
3839
3840static VALUE
3841rb_thread_sleep_that_takes_VALUE_as_sole_argument(VALUE n)
3842{
3844 return Qundef;
3845}
3846
3847static int
3848handle_fork_error(int err, struct rb_process_status *status, int *ep, volatile int *try_gc_p)
3849{
3850 int state = 0;
3851
3852 switch (err) {
3853 case ENOMEM:
3854 if ((*try_gc_p)-- > 0 && !rb_during_gc()) {
3855 rb_gc();
3856 return 0;
3857 }
3858 break;
3859 case EAGAIN:
3860#if defined(EWOULDBLOCK) && EWOULDBLOCK != EAGAIN
3861 case EWOULDBLOCK:
3862#endif
3863 if (!status && !ep) {
3864 rb_thread_sleep(1);
3865 return 0;
3866 }
3867 else {
3868 rb_protect(rb_thread_sleep_that_takes_VALUE_as_sole_argument, INT2FIX(1), &state);
3869 if (status) status->status = state;
3870 if (!state) return 0;
3871 }
3872 break;
3873 }
3874 if (ep) {
3875 close(ep[0]);
3876 close(ep[1]);
3877 errno = err;
3878 }
3879 if (state && !status) rb_jump_tag(state);
3880 return -1;
3881}
3882
3883#define prefork() ( \
3884 rb_io_flush(rb_stdout), \
3885 rb_io_flush(rb_stderr) \
3886 )
3887
3888/*
3889 * Forks child process, and returns the process ID in the parent
3890 * process.
3891 *
3892 * If +status+ is given, protects from any exceptions and sets the
3893 * jump status to it, and returns -1. If failed to fork new process
3894 * but no exceptions occurred, sets 0 to it. Otherwise, if forked
3895 * successfully, the value of +status+ is undetermined.
3896 *
3897 * In the child process, just returns 0 if +chfunc+ is +NULL+.
3898 * Otherwise +chfunc+ will be called with +charg+, and then the child
3899 * process exits with +EXIT_SUCCESS+ when it returned zero.
3900 *
3901 * In the case of the function is called and returns non-zero value,
3902 * the child process exits with non-+EXIT_SUCCESS+ value (normally
3903 * 127). And, on the platforms where +FD_CLOEXEC+ is available,
3904 * +errno+ is propagated to the parent process, and this function
3905 * returns -1 in the parent process. On the other platforms, just
3906 * returns pid.
3907 *
3908 * If fds is not Qnil, internal pipe for the errno propagation is
3909 * arranged to avoid conflicts of the hash keys in +fds+.
3910 *
3911 * +chfunc+ must not raise any exceptions.
3912 */
3913
3914static ssize_t
3915write_retry(int fd, const void *buf, size_t len)
3916{
3917 ssize_t w;
3918
3919 do {
3920 w = write(fd, buf, len);
3921 } while (w < 0 && errno == EINTR);
3922
3923 return w;
3924}
3925
3926static ssize_t
3927read_retry(int fd, void *buf, size_t len)
3928{
3929 ssize_t r;
3930
3931 if (set_blocking(fd) != 0) {
3932#ifndef _WIN32
3933 rb_async_bug_errno("set_blocking failed reading child error", errno);
3934#endif
3935 }
3936
3937 do {
3938 r = read(fd, buf, len);
3939 } while (r < 0 && errno == EINTR);
3940
3941 return r;
3942}
3943
3944static void
3945send_child_error(int fd, char *errmsg, size_t errmsg_buflen)
3946{
3947 int err;
3948
3949 err = errno;
3950 if (write_retry(fd, &err, sizeof(err)) < 0) err = errno;
3951 if (errmsg && 0 < errmsg_buflen) {
3952 errmsg[errmsg_buflen-1] = '\0';
3953 errmsg_buflen = strlen(errmsg);
3954 if (errmsg_buflen > 0 && write_retry(fd, errmsg, errmsg_buflen) < 0)
3955 err = errno;
3956 }
3957}
3958
3959static int
3960recv_child_error(int fd, int *errp, char *errmsg, size_t errmsg_buflen)
3961{
3962 int err;
3963 ssize_t size;
3964 if ((size = read_retry(fd, &err, sizeof(err))) < 0) {
3965 err = errno;
3966 }
3967 *errp = err;
3968 if (size == sizeof(err) &&
3969 errmsg && 0 < errmsg_buflen) {
3970 ssize_t ret = read_retry(fd, errmsg, errmsg_buflen-1);
3971 if (0 <= ret) {
3972 errmsg[ret] = '\0';
3973 }
3974 }
3975 close(fd);
3976 return size != 0;
3977}
3978
3979#ifdef HAVE_WORKING_VFORK
3980#if !defined(HAVE_GETRESUID) && defined(HAVE_GETUIDX)
3981/* AIX 7.1 */
3982static int
3983getresuid(rb_uid_t *ruid, rb_uid_t *euid, rb_uid_t *suid)
3984{
3985 rb_uid_t ret;
3986
3987 *ruid = getuid();
3988 *euid = geteuid();
3989 ret = getuidx(ID_SAVED);
3990 if (ret == (rb_uid_t)-1)
3991 return -1;
3992 *suid = ret;
3993 return 0;
3994}
3995#define HAVE_GETRESUID
3996#endif
3997
3998#if !defined(HAVE_GETRESGID) && defined(HAVE_GETGIDX)
3999/* AIX 7.1 */
4000static int
4001getresgid(rb_gid_t *rgid, rb_gid_t *egid, rb_gid_t *sgid)
4002{
4003 rb_gid_t ret;
4004
4005 *rgid = getgid();
4006 *egid = getegid();
4007 ret = getgidx(ID_SAVED);
4008 if (ret == (rb_gid_t)-1)
4009 return -1;
4010 *sgid = ret;
4011 return 0;
4012}
4013#define HAVE_GETRESGID
4014#endif
4015
4016static int
4017has_privilege(void)
4018{
4019 /*
4020 * has_privilege() is used to choose vfork() or fork().
4021 *
4022 * If the process has privilege, the parent process or
4023 * the child process can change UID/GID.
4024 * If vfork() is used to create the child process and
4025 * the parent or child process change effective UID/GID,
4026 * different privileged processes shares memory.
4027 * It is a bad situation.
4028 * So, fork() should be used.
4029 */
4030
4031 rb_uid_t ruid, euid;
4032 rb_gid_t rgid, egid;
4033
4034#if defined HAVE_ISSETUGID
4035 if (issetugid())
4036 return 1;
4037#endif
4038
4039#ifdef HAVE_GETRESUID
4040 {
4041 int ret;
4042 rb_uid_t suid;
4043 ret = getresuid(&ruid, &euid, &suid);
4044 if (ret == -1)
4045 rb_sys_fail("getresuid(2)");
4046 if (euid != suid)
4047 return 1;
4048 }
4049#else
4050 ruid = getuid();
4051 euid = geteuid();
4052#endif
4053
4054 if (euid == 0 || euid != ruid)
4055 return 1;
4056
4057#ifdef HAVE_GETRESGID
4058 {
4059 int ret;
4060 rb_gid_t sgid;
4061 ret = getresgid(&rgid, &egid, &sgid);
4062 if (ret == -1)
4063 rb_sys_fail("getresgid(2)");
4064 if (egid != sgid)
4065 return 1;
4066 }
4067#else
4068 rgid = getgid();
4069 egid = getegid();
4070#endif
4071
4072 if (egid != rgid)
4073 return 1;
4074
4075 return 0;
4076}
4077#endif
4078
4079struct child_handler_disabler_state
4080{
4081 sigset_t sigmask;
4082};
4083
4084static void
4085disable_child_handler_before_fork(struct child_handler_disabler_state *old)
4086{
4087#ifdef HAVE_PTHREAD_SIGMASK
4088 int ret;
4089 sigset_t all;
4090
4091 ret = sigfillset(&all);
4092 if (ret == -1)
4093 rb_sys_fail("sigfillset");
4094
4095 ret = pthread_sigmask(SIG_SETMASK, &all, &old->sigmask); /* not async-signal-safe */
4096 if (ret != 0) {
4097 rb_syserr_fail(ret, "pthread_sigmask");
4098 }
4099#else
4100# pragma GCC warning "pthread_sigmask on fork is not available. potentially dangerous"
4101#endif
4102}
4103
4104static void
4105disable_child_handler_fork_parent(struct child_handler_disabler_state *old)
4106{
4107#ifdef HAVE_PTHREAD_SIGMASK
4108 int ret;
4109
4110 ret = pthread_sigmask(SIG_SETMASK, &old->sigmask, NULL); /* not async-signal-safe */
4111 if (ret != 0) {
4112 rb_syserr_fail(ret, "pthread_sigmask");
4113 }
4114#else
4115# pragma GCC warning "pthread_sigmask on fork is not available. potentially dangerous"
4116#endif
4117}
4118
4119/* This function should be async-signal-safe. Actually it is. */
4120static int
4121disable_child_handler_fork_child(struct child_handler_disabler_state *old, char *errmsg, size_t errmsg_buflen)
4122{
4123 int sig;
4124 int ret;
4125
4126 for (sig = 1; sig < NSIG; sig++) {
4127 sig_t handler = signal(sig, SIG_DFL);
4128
4129 if (handler == SIG_ERR && errno == EINVAL) {
4130 continue; /* Ignore invalid signal number */
4131 }
4132 if (handler == SIG_ERR) {
4133 ERRMSG("signal to obtain old action");
4134 return -1;
4135 }
4136#ifdef SIGPIPE
4137 if (sig == SIGPIPE) {
4138 continue;
4139 }
4140#endif
4141 /* it will be reset to SIG_DFL at execve time, instead */
4142 if (handler == SIG_IGN) {
4143 signal(sig, SIG_IGN);
4144 }
4145 }
4146
4147 /* non-Ruby child process, ensure cmake can see SIGCHLD */
4148 sigemptyset(&old->sigmask);
4149 ret = sigprocmask(SIG_SETMASK, &old->sigmask, NULL); /* async-signal-safe */
4150 if (ret != 0) {
4151 ERRMSG("sigprocmask");
4152 return -1;
4153 }
4154 return 0;
4155}
4156
4157static rb_pid_t
4158retry_fork_async_signal_safe(struct rb_process_status *status, int *ep,
4159 int (*chfunc)(void*, char *, size_t), void *charg,
4160 char *errmsg, size_t errmsg_buflen,
4161 struct waitpid_state *w)
4162{
4163 rb_pid_t pid;
4164 volatile int try_gc = 1;
4165 struct child_handler_disabler_state old;
4166 int err;
4167 rb_nativethread_lock_t *const volatile waitpid_lock_init =
4168 (w && WAITPID_USE_SIGCHLD) ? &GET_VM()->waitpid_lock : 0;
4169
4170 while (1) {
4171 rb_nativethread_lock_t *waitpid_lock = waitpid_lock_init;
4172 prefork();
4173 disable_child_handler_before_fork(&old);
4174 if (waitpid_lock) {
4175 rb_native_mutex_lock(waitpid_lock);
4176 }
4177#ifdef HAVE_WORKING_VFORK
4178 if (!has_privilege())
4179 pid = vfork();
4180 else
4181 pid = rb_fork();
4182#else
4183 pid = rb_fork();
4184#endif
4185 if (pid == 0) {/* fork succeed, child process */
4186 int ret;
4187 close(ep[0]);
4188 ret = disable_child_handler_fork_child(&old, errmsg, errmsg_buflen); /* async-signal-safe */
4189 if (ret == 0) {
4190 ret = chfunc(charg, errmsg, errmsg_buflen);
4191 if (!ret) _exit(EXIT_SUCCESS);
4192 }
4193 send_child_error(ep[1], errmsg, errmsg_buflen);
4194#if EXIT_SUCCESS == 127
4195 _exit(EXIT_FAILURE);
4196#else
4197 _exit(127);
4198#endif
4199 }
4200 err = errno;
4201 waitpid_lock = waitpid_lock_init;
4202 if (waitpid_lock) {
4203 if (pid > 0 && w != WAITPID_LOCK_ONLY) {
4204 w->pid = pid;
4205 ccan_list_add(&GET_VM()->waiting_pids, &w->wnode);
4206 }
4207 rb_native_mutex_unlock(waitpid_lock);
4208 }
4209 disable_child_handler_fork_parent(&old);
4210 if (0 < pid) /* fork succeed, parent process */
4211 return pid;
4212 /* fork failed */
4213 if (handle_fork_error(err, status, ep, &try_gc))
4214 return -1;
4215 }
4216}
4217
4218#if USE_MJIT
4219// This is used to create MJIT's child Ruby process
4220pid_t
4221rb_mjit_fork(void)
4222{
4223 struct child_handler_disabler_state old;
4224 rb_vm_t *vm = GET_VM();
4225 prefork();
4226 disable_child_handler_before_fork(&old);
4227 before_fork_ruby();
4228
4229 rb_native_mutex_lock(&vm->waitpid_lock);
4230 pid_t pid = rb_fork();
4231 if (pid > 0) mjit_add_waiting_pid(vm, pid);
4232 rb_native_mutex_unlock(&vm->waitpid_lock);
4233
4234 after_fork_ruby();
4235 disable_child_handler_fork_parent(&old);
4236 if (pid == 0) rb_thread_atfork();
4237
4238 return pid;
4239}
4240#endif
4241
4242static rb_pid_t
4243fork_check_err(struct rb_process_status *status, int (*chfunc)(void*, char *, size_t), void *charg,
4244 VALUE fds, char *errmsg, size_t errmsg_buflen,
4245 struct rb_execarg *eargp)
4246{
4247 rb_pid_t pid;
4248 int err;
4249 int ep[2];
4250 int error_occurred;
4251
4252 struct waitpid_state *w = eargp && eargp->waitpid_state ? eargp->waitpid_state : 0;
4253
4254 if (status) status->status = 0;
4255
4256 if (pipe_nocrash(ep, fds)) return -1;
4257
4258 pid = retry_fork_async_signal_safe(status, ep, chfunc, charg, errmsg, errmsg_buflen, w);
4259
4260 if (status) status->pid = pid;
4261
4262 if (pid < 0) {
4263 if (status) status->error = errno;
4264
4265 return pid;
4266 }
4267
4268 close(ep[1]);
4269
4270 error_occurred = recv_child_error(ep[0], &err, errmsg, errmsg_buflen);
4271
4272 if (error_occurred) {
4273 if (status) {
4274 int state = 0;
4275 status->error = err;
4276
4277 VM_ASSERT((w == 0 || w == WAITPID_LOCK_ONLY) &&
4278 "only used by extensions");
4279 rb_protect(proc_syswait, (VALUE)pid, &state);
4280
4281 status->status = state;
4282 }
4283 else if (!w || w == WAITPID_LOCK_ONLY) {
4284 rb_syswait(pid);
4285 }
4286
4287 errno = err;
4288 return -1;
4289 }
4290
4291 return pid;
4292}
4293
4294/*
4295 * The "async_signal_safe" name is a lie, but it is used by pty.c and
4296 * maybe other exts. fork() is not async-signal-safe due to pthread_atfork
4297 * and future POSIX revisions will remove it from a list of signal-safe
4298 * functions. rb_waitpid is not async-signal-safe since MJIT, either.
4299 * For our purposes, we do not need async-signal-safety, here
4300 */
4301rb_pid_t
4302rb_fork_async_signal_safe(int *status,
4303 int (*chfunc)(void*, char *, size_t), void *charg,
4304 VALUE fds, char *errmsg, size_t errmsg_buflen)
4305{
4306 struct rb_process_status process_status;
4307
4308 rb_pid_t result = fork_check_err(&process_status, chfunc, charg, fds, errmsg, errmsg_buflen, 0);
4309
4310 if (status) {
4311 *status = process_status.status;
4312 }
4313
4314 return result;
4315}
4316
4317static rb_pid_t
4318rb_fork_ruby2(struct rb_process_status *status)
4319{
4320 rb_pid_t pid;
4321 int try_gc = 1, err;
4322 struct child_handler_disabler_state old;
4323
4324 if (status) status->status = 0;
4325
4326 while (1) {
4327 prefork();
4328 if (mjit_enabled) mjit_pause(false); // Don't leave locked mutex to child. Note: child_handler must be enabled to pause MJIT.
4329 disable_child_handler_before_fork(&old);
4330 before_fork_ruby();
4331 pid = rb_fork();
4332 err = errno;
4333 if (status) {
4334 status->pid = pid;
4335 status->error = err;
4336 }
4337 after_fork_ruby();
4338 disable_child_handler_fork_parent(&old); /* yes, bad name */
4339
4340 if (mjit_enabled && pid > 0) mjit_resume(); /* child (pid == 0) is cared by rb_thread_atfork */
4341
4342 if (pid >= 0) { /* fork succeed */
4343 if (pid == 0) rb_thread_atfork();
4344 return pid;
4345 }
4346
4347 /* fork failed */
4348 if (handle_fork_error(err, status, NULL, &try_gc)) {
4349 return -1;
4350 }
4351 }
4352}
4353
4354rb_pid_t
4355rb_fork_ruby(int *status)
4356{
4357 struct rb_process_status process_status = {0};
4358
4359 rb_pid_t pid = rb_fork_ruby2(&process_status);
4360
4361 if (status) *status = process_status.status;
4362
4363 return pid;
4364}
4365
4366static rb_pid_t
4367proc_fork_pid(void)
4368{
4369 rb_pid_t pid = rb_fork_ruby(NULL);
4370
4371 if (pid == -1) {
4372 rb_sys_fail("fork(2)");
4373 }
4374
4375 return pid;
4376}
4377
4378rb_pid_t
4379rb_call_proc__fork(void)
4380{
4381 ID id__fork;
4382 CONST_ID(id__fork, "_fork");
4383 if (rb_method_basic_definition_p(CLASS_OF(rb_mProcess), id__fork)) {
4384 return proc_fork_pid();
4385 }
4386 else {
4387 VALUE pid = rb_funcall(rb_mProcess, id__fork, 0);
4388 return NUM2PIDT(pid);
4389 }
4390}
4391#endif
4392
4393#if defined(HAVE_WORKING_FORK) && !defined(CANNOT_FORK_WITH_PTHREAD)
4394/*
4395 * call-seq:
4396 * Process._fork -> integer
4397 *
4398 * An internal API for fork. Do not call this method directly.
4399 * Currently, this is called via Kernel#fork, Process.fork, and
4400 * IO.popen with <tt>"-"</tt>.
4401 *
4402 * This method is not for casual code but for application monitoring
4403 * libraries. You can add custom code before and after fork events
4404 * by overriding this method.
4405 *
4406 * Note: Process.daemon may be implemented using fork(2) BUT does not go
4407 * through this method.
4408 * Thus, depending on your reason to hook into this method, you
4409 * may also want to hook into that one.
4410 * See {this issue}[https://bugs.ruby-lang.org/issues/18911] for a
4411 * more detailed discussion of this.
4412 */
4413VALUE
4414rb_proc__fork(VALUE _obj)
4415{
4416 rb_pid_t pid = proc_fork_pid();
4417 return PIDT2NUM(pid);
4418}
4419
4420/*
4421 * call-seq:
4422 * Kernel.fork [{ block }] -> integer or nil
4423 * Process.fork [{ block }] -> integer or nil
4424 *
4425 * Creates a subprocess. If a block is specified, that block is run
4426 * in the subprocess, and the subprocess terminates with a status of
4427 * zero. Otherwise, the +fork+ call returns twice, once in the
4428 * parent, returning the process ID of the child, and once in the
4429 * child, returning _nil_. The child process can exit using
4430 * Kernel.exit! to avoid running any <code>at_exit</code>
4431 * functions. The parent process should use Process.wait to collect
4432 * the termination statuses of its children or use Process.detach to
4433 * register disinterest in their status; otherwise, the operating
4434 * system may accumulate zombie processes.
4435 *
4436 * The thread calling fork is the only thread in the created child process.
4437 * fork doesn't copy other threads.
4438 *
4439 * If fork is not usable, Process.respond_to?(:fork) returns false.
4440 *
4441 * Note that fork(2) is not available on some platforms like Windows and NetBSD 4.
4442 * Therefore you should use spawn() instead of fork().
4443 */
4444
4445static VALUE
4446rb_f_fork(VALUE obj)
4447{
4448 rb_pid_t pid;
4449
4450 pid = rb_call_proc__fork();
4451
4452 if (pid == 0) {
4453 if (rb_block_given_p()) {
4454 int status;
4455 rb_protect(rb_yield, Qundef, &status);
4456 ruby_stop(status);
4457 }
4458 return Qnil;
4459 }
4460
4461 return PIDT2NUM(pid);
4462}
4463#else
4464#define rb_proc__fork rb_f_notimplement
4465#define rb_f_fork rb_f_notimplement
4466#endif
4467
4468static int
4469exit_status_code(VALUE status)
4470{
4471 int istatus;
4472
4473 switch (status) {
4474 case Qtrue:
4475 istatus = EXIT_SUCCESS;
4476 break;
4477 case Qfalse:
4478 istatus = EXIT_FAILURE;
4479 break;
4480 default:
4481 istatus = NUM2INT(status);
4482#if EXIT_SUCCESS != 0
4483 if (istatus == 0)
4484 istatus = EXIT_SUCCESS;
4485#endif
4486 break;
4487 }
4488 return istatus;
4489}
4490
4491NORETURN(static VALUE rb_f_exit_bang(int argc, VALUE *argv, VALUE obj));
4492/*
4493 * call-seq:
4494 * Process.exit!(status=false)
4495 *
4496 * Exits the process immediately. No exit handlers are
4497 * run. <em>status</em> is returned to the underlying system as the
4498 * exit status.
4499 *
4500 * Process.exit!(true)
4501 */
4502
4503static VALUE
4504rb_f_exit_bang(int argc, VALUE *argv, VALUE obj)
4505{
4506 int istatus;
4507
4508 if (rb_check_arity(argc, 0, 1) == 1) {
4509 istatus = exit_status_code(argv[0]);
4510 }
4511 else {
4512 istatus = EXIT_FAILURE;
4513 }
4514 _exit(istatus);
4515
4517}
4518
4519void
4520rb_exit(int status)
4521{
4522 if (GET_EC()->tag) {
4523 VALUE args[2];
4524
4525 args[0] = INT2NUM(status);
4526 args[1] = rb_str_new2("exit");
4528 }
4529 ruby_stop(status);
4530}
4531
4532VALUE
4533rb_f_exit(int argc, const VALUE *argv)
4534{
4535 int istatus;
4536
4537 if (rb_check_arity(argc, 0, 1) == 1) {
4538 istatus = exit_status_code(argv[0]);
4539 }
4540 else {
4541 istatus = EXIT_SUCCESS;
4542 }
4543 rb_exit(istatus);
4544
4546}
4547
4548NORETURN(static VALUE f_exit(int c, const VALUE *a, VALUE _));
4549/*
4550 * call-seq:
4551 * exit(status=true)
4552 * Kernel::exit(status=true)
4553 * Process::exit(status=true)
4554 *
4555 * Initiates the termination of the Ruby script by raising the
4556 * SystemExit exception. This exception may be caught. The
4557 * optional parameter is used to return a status code to the invoking
4558 * environment.
4559 * +true+ and +FALSE+ of _status_ means success and failure
4560 * respectively. The interpretation of other integer values are
4561 * system dependent.
4562 *
4563 * begin
4564 * exit
4565 * puts "never get here"
4566 * rescue SystemExit
4567 * puts "rescued a SystemExit exception"
4568 * end
4569 * puts "after begin block"
4570 *
4571 * <em>produces:</em>
4572 *
4573 * rescued a SystemExit exception
4574 * after begin block
4575 *
4576 * Just prior to termination, Ruby executes any <code>at_exit</code>
4577 * functions (see Kernel::at_exit) and runs any object finalizers
4578 * (see ObjectSpace::define_finalizer).
4579 *
4580 * at_exit { puts "at_exit function" }
4581 * ObjectSpace.define_finalizer("string", proc { puts "in finalizer" })
4582 * exit
4583 *
4584 * <em>produces:</em>
4585 *
4586 * at_exit function
4587 * in finalizer
4588 */
4589
4590static VALUE
4591f_exit(int c, const VALUE *a, VALUE _)
4592{
4593 rb_f_exit(c, a);
4595}
4596
4597VALUE
4598rb_f_abort(int argc, const VALUE *argv)
4599{
4600 rb_check_arity(argc, 0, 1);
4601 if (argc == 0) {
4602 rb_execution_context_t *ec = GET_EC();
4603 VALUE errinfo = rb_ec_get_errinfo(ec);
4604 if (!NIL_P(errinfo)) {
4605 rb_ec_error_print(ec, errinfo);
4606 }
4607 rb_exit(EXIT_FAILURE);
4608 }
4609 else {
4610 VALUE args[2];
4611
4612 args[1] = args[0] = argv[0];
4613 StringValue(args[0]);
4614 rb_io_puts(1, args, rb_ractor_stderr());
4615 args[0] = INT2NUM(EXIT_FAILURE);
4617 }
4618
4620}
4621
4622NORETURN(static VALUE f_abort(int c, const VALUE *a, VALUE _));
4623
4624/*
4625 * call-seq:
4626 * abort
4627 * Kernel::abort([msg])
4628 * Process.abort([msg])
4629 *
4630 * Terminate execution immediately, effectively by calling
4631 * <code>Kernel.exit(false)</code>. If _msg_ is given, it is written
4632 * to STDERR prior to terminating.
4633 */
4634
4635static VALUE
4636f_abort(int c, const VALUE *a, VALUE _)
4637{
4638 rb_f_abort(c, a);
4640}
4641
4642void
4643rb_syswait(rb_pid_t pid)
4644{
4645 int status;
4646
4647 rb_waitpid(pid, &status, 0);
4648}
4649
4650#if !defined HAVE_WORKING_FORK && !defined HAVE_SPAWNV && !defined __EMSCRIPTEN__
4651char *
4652rb_execarg_commandline(const struct rb_execarg *eargp, VALUE *prog)
4653{
4654 VALUE cmd = *prog;
4655 if (eargp && !eargp->use_shell) {
4656 VALUE str = eargp->invoke.cmd.argv_str;
4657 VALUE buf = eargp->invoke.cmd.argv_buf;
4658 char *p, **argv = ARGVSTR2ARGV(str);
4659 long i, argc = ARGVSTR2ARGC(str);
4660 const char *start = RSTRING_PTR(buf);
4661 cmd = rb_str_new(start, RSTRING_LEN(buf));
4662 p = RSTRING_PTR(cmd);
4663 for (i = 1; i < argc; ++i) {
4664 p[argv[i] - start - 1] = ' ';
4665 }
4666 *prog = cmd;
4667 return p;
4668 }
4669 return StringValueCStr(*prog);
4670}
4671#endif
4672
4673static rb_pid_t
4674rb_spawn_process(struct rb_execarg *eargp, char *errmsg, size_t errmsg_buflen)
4675{
4676 rb_pid_t pid;
4677#if !defined HAVE_WORKING_FORK || USE_SPAWNV
4678 VALUE prog;
4679 struct rb_execarg sarg;
4680# if !defined HAVE_SPAWNV
4681 int status;
4682# endif
4683#endif
4684
4685#if defined HAVE_WORKING_FORK && !USE_SPAWNV
4686 pid = fork_check_err(eargp->status, rb_exec_atfork, eargp, eargp->redirect_fds, errmsg, errmsg_buflen, eargp);
4687#else
4688 prog = eargp->use_shell ? eargp->invoke.sh.shell_script : eargp->invoke.cmd.command_name;
4689
4690 if (rb_execarg_run_options(eargp, &sarg, errmsg, errmsg_buflen) < 0) {
4691 return -1;
4692 }
4693
4694 if (prog && !eargp->use_shell) {
4695 char **argv = ARGVSTR2ARGV(eargp->invoke.cmd.argv_str);
4696 argv[0] = RSTRING_PTR(prog);
4697 }
4698# if defined HAVE_SPAWNV
4699 if (eargp->use_shell) {
4700 pid = proc_spawn_sh(RSTRING_PTR(prog));
4701 }
4702 else {
4703 char **argv = ARGVSTR2ARGV(eargp->invoke.cmd.argv_str);
4704 pid = proc_spawn_cmd(argv, prog, eargp);
4705 }
4706
4707 if (pid == -1) {
4708 rb_last_status_set(0x7f << 8, pid);
4709 }
4710# else
4711 status = system(rb_execarg_commandline(eargp, &prog));
4712 pid = 1; /* dummy */
4713 rb_last_status_set((status & 0xff) << 8, pid);
4714# endif
4715
4716 if (eargp->waitpid_state && eargp->waitpid_state != WAITPID_LOCK_ONLY) {
4717 eargp->waitpid_state->pid = pid;
4718 }
4719
4720 rb_execarg_run_options(&sarg, NULL, errmsg, errmsg_buflen);
4721#endif
4722
4723 return pid;
4724}
4725
4727 VALUE execarg;
4728 struct {
4729 char *ptr;
4730 size_t buflen;
4731 } errmsg;
4732};
4733
4734static VALUE
4735do_spawn_process(VALUE arg)
4736{
4737 struct spawn_args *argp = (struct spawn_args *)arg;
4738 rb_execarg_parent_start1(argp->execarg);
4739 return (VALUE)rb_spawn_process(DATA_PTR(argp->execarg),
4740 argp->errmsg.ptr, argp->errmsg.buflen);
4741}
4742
4743static rb_pid_t
4744rb_execarg_spawn(VALUE execarg_obj, char *errmsg, size_t errmsg_buflen)
4745{
4746 struct spawn_args args;
4747 struct rb_execarg *eargp = rb_execarg_get(execarg_obj);
4748
4749 /*
4750 * Prevent a race with MJIT where the compiler process where
4751 * can hold an FD of ours in between vfork + execve
4752 */
4753 if (!eargp->waitpid_state && mjit_enabled) {
4754 eargp->waitpid_state = WAITPID_LOCK_ONLY;
4755 }
4756
4757 args.execarg = execarg_obj;
4758 args.errmsg.ptr = errmsg;
4759 args.errmsg.buflen = errmsg_buflen;
4760 return (rb_pid_t)rb_ensure(do_spawn_process, (VALUE)&args,
4761 execarg_parent_end, execarg_obj);
4762}
4763
4764static rb_pid_t
4765rb_spawn_internal(int argc, const VALUE *argv, char *errmsg, size_t errmsg_buflen)
4766{
4767 VALUE execarg_obj;
4768
4769 execarg_obj = rb_execarg_new(argc, argv, TRUE, FALSE);
4770 return rb_execarg_spawn(execarg_obj, errmsg, errmsg_buflen);
4771}
4772
4773rb_pid_t
4774rb_spawn_err(int argc, const VALUE *argv, char *errmsg, size_t errmsg_buflen)
4775{
4776 return rb_spawn_internal(argc, argv, errmsg, errmsg_buflen);
4777}
4778
4779rb_pid_t
4780rb_spawn(int argc, const VALUE *argv)
4781{
4782 return rb_spawn_internal(argc, argv, NULL, 0);
4783}
4784
4785/*
4786 * call-seq:
4787 * system([env,] command... [,options], exception: false) -> true, false or nil
4788 *
4789 * Executes _command..._ in a subshell.
4790 * _command..._ is one of following forms.
4791 *
4792 * This method has potential security vulnerabilities if called with untrusted input;
4793 * see {Command Injection}[rdoc-ref:command_injection.rdoc].
4794 *
4795 * [<code>commandline</code>]
4796 * command line string which is passed to the standard shell
4797 * [<code>cmdname, arg1, ...</code>]
4798 * command name and one or more arguments (no shell)
4799 * [<code>[cmdname, argv0], arg1, ...</code>]
4800 * command name, <code>argv[0]</code> and zero or more arguments (no shell)
4801 *
4802 * system returns +true+ if the command gives zero exit status,
4803 * +false+ for non zero exit status.
4804 * Returns +nil+ if command execution fails.
4805 * An error status is available in <code>$?</code>.
4806 *
4807 * If the <code>exception: true</code> argument is passed, the method
4808 * raises an exception instead of returning +false+ or +nil+.
4809 *
4810 * The arguments are processed in the same way as
4811 * for Kernel#spawn.
4812 *
4813 * The hash arguments, env and options, are same as #exec and #spawn.
4814 * See Kernel#spawn for details.
4815 *
4816 * system("echo *")
4817 * system("echo", "*")
4818 *
4819 * <em>produces:</em>
4820 *
4821 * config.h main.rb
4822 * *
4823 *
4824 * Error handling:
4825 *
4826 * system("cat nonexistent.txt")
4827 * # => false
4828 * system("catt nonexistent.txt")
4829 * # => nil
4830 *
4831 * system("cat nonexistent.txt", exception: true)
4832 * # RuntimeError (Command failed with exit 1: cat)
4833 * system("catt nonexistent.txt", exception: true)
4834 * # Errno::ENOENT (No such file or directory - catt)
4835 *
4836 * See Kernel#exec for the standard shell.
4837 */
4838
4839static VALUE
4840rb_f_system(int argc, VALUE *argv, VALUE _)
4841{
4842 VALUE execarg_obj = rb_execarg_new(argc, argv, TRUE, TRUE);
4843 struct rb_execarg *eargp = rb_execarg_get(execarg_obj);
4844
4845 struct rb_process_status status = {0};
4846 eargp->status = &status;
4847
4848 rb_last_status_clear();
4849
4850 // This function can set the thread's last status.
4851 // May be different from waitpid_state.pid on exec failure.
4852 rb_pid_t pid = rb_execarg_spawn(execarg_obj, 0, 0);
4853
4854 if (pid > 0) {
4855 VALUE status = rb_process_status_wait(pid, 0);
4856
4857 struct rb_process_status *data = rb_check_typeddata(status, &rb_process_status_type);
4858
4859 // Set the last status:
4860 rb_obj_freeze(status);
4861 GET_THREAD()->last_status = status;
4862
4863 if (data->status == EXIT_SUCCESS) {
4864 return Qtrue;
4865 }
4866
4867 if (data->error != 0) {
4868 if (eargp->exception) {
4869 VALUE command = eargp->invoke.sh.shell_script;
4870 RB_GC_GUARD(execarg_obj);
4871 rb_syserr_fail_str(data->error, command);
4872 }
4873 else {
4874 return Qnil;
4875 }
4876 }
4877 else if (eargp->exception) {
4878 VALUE command = eargp->invoke.sh.shell_script;
4879 VALUE str = rb_str_new_cstr("Command failed with");
4880 rb_str_cat_cstr(pst_message_status(str, data->status), ": ");
4881 rb_str_append(str, command);
4882 RB_GC_GUARD(execarg_obj);
4884 }
4885 else {
4886 return Qfalse;
4887 }
4888
4889 RB_GC_GUARD(status);
4890 }
4891
4892 if (eargp->exception) {
4893 VALUE command = eargp->invoke.sh.shell_script;
4894 RB_GC_GUARD(execarg_obj);
4895 rb_syserr_fail_str(errno, command);
4896 }
4897 else {
4898 return Qnil;
4899 }
4900}
4901
4902/*
4903 * call-seq:
4904 * spawn([env,] command... [,options]) -> pid
4905 * Process.spawn([env,] command... [,options]) -> pid
4906 *
4907 * spawn executes specified command and return its pid.
4908 *
4909 * pid = spawn("tar xf ruby-2.0.0-p195.tar.bz2")
4910 * Process.wait pid
4911 *
4912 * pid = spawn(RbConfig.ruby, "-eputs'Hello, world!'")
4913 * Process.wait pid
4914 *
4915 * This method is similar to Kernel#system but it doesn't wait for the command
4916 * to finish.
4917 *
4918 * The parent process should
4919 * use Process.wait to collect
4920 * the termination status of its child or
4921 * use Process.detach to register
4922 * disinterest in their status;
4923 * otherwise, the operating system may accumulate zombie processes.
4924 *
4925 * spawn has bunch of options to specify process attributes:
4926 *
4927 * env: hash
4928 * name => val : set the environment variable
4929 * name => nil : unset the environment variable
4930 *
4931 * the keys and the values except for +nil+ must be strings.
4932 * command...:
4933 * commandline : command line string which is passed to the standard shell
4934 * cmdname, arg1, ... : command name and one or more arguments (This form does not use the shell. See below for caveats.)
4935 * [cmdname, argv0], arg1, ... : command name, argv[0] and zero or more arguments (no shell)
4936 * options: hash
4937 * clearing environment variables:
4938 * :unsetenv_others => true : clear environment variables except specified by env
4939 * :unsetenv_others => false : don't clear (default)
4940 * process group:
4941 * :pgroup => true or 0 : make a new process group
4942 * :pgroup => pgid : join the specified process group
4943 * :pgroup => nil : don't change the process group (default)
4944 * create new process group: Windows only
4945 * :new_pgroup => true : the new process is the root process of a new process group
4946 * :new_pgroup => false : don't create a new process group (default)
4947 * resource limit: resourcename is core, cpu, data, etc. See Process.setrlimit.
4948 * :rlimit_resourcename => limit
4949 * :rlimit_resourcename => [cur_limit, max_limit]
4950 * umask:
4951 * :umask => int
4952 * redirection:
4953 * key:
4954 * FD : single file descriptor in child process
4955 * [FD, FD, ...] : multiple file descriptor in child process
4956 * value:
4957 * FD : redirect to the file descriptor in parent process
4958 * string : redirect to file with open(string, "r" or "w")
4959 * [string] : redirect to file with open(string, File::RDONLY)
4960 * [string, open_mode] : redirect to file with open(string, open_mode, 0644)
4961 * [string, open_mode, perm] : redirect to file with open(string, open_mode, perm)
4962 * [:child, FD] : redirect to the redirected file descriptor
4963 * :close : close the file descriptor in child process
4964 * FD is one of follows
4965 * :in : the file descriptor 0 which is the standard input
4966 * :out : the file descriptor 1 which is the standard output
4967 * :err : the file descriptor 2 which is the standard error
4968 * integer : the file descriptor of specified the integer
4969 * io : the file descriptor specified as io.fileno
4970 * file descriptor inheritance: close non-redirected non-standard fds (3, 4, 5, ...) or not
4971 * :close_others => false : inherit
4972 * current directory:
4973 * :chdir => str
4974 *
4975 * The <code>cmdname, arg1, ...</code> form does not use the shell.
4976 * However, on different OSes, different things are provided as
4977 * built-in commands. An example of this is +'echo'+, which is a
4978 * built-in on Windows, but is a normal program on Linux and Mac OS X.
4979 * This means that <code>Process.spawn 'echo', '%Path%'</code> will
4980 * display the contents of the <tt>%Path%</tt> environment variable
4981 * on Windows, but <code>Process.spawn 'echo', '$PATH'</code> prints
4982 * the literal <tt>$PATH</tt>.
4983 *
4984 * If a hash is given as +env+, the environment is
4985 * updated by +env+ before <code>exec(2)</code> in the child process.
4986 * If a pair in +env+ has nil as the value, the variable is deleted.
4987 *
4988 * # set FOO as BAR and unset BAZ.
4989 * pid = spawn({"FOO"=>"BAR", "BAZ"=>nil}, command)
4990 *
4991 * If a hash is given as +options+,
4992 * it specifies
4993 * process group,
4994 * create new process group,
4995 * resource limit,
4996 * current directory,
4997 * umask and
4998 * redirects for the child process.
4999 * Also, it can be specified to clear environment variables.
5000 *
5001 * The <code>:unsetenv_others</code> key in +options+ specifies
5002 * to clear environment variables, other than specified by +env+.
5003 *
5004 * pid = spawn(command, :unsetenv_others=>true) # no environment variable
5005 * pid = spawn({"FOO"=>"BAR"}, command, :unsetenv_others=>true) # FOO only
5006 *
5007 * The <code>:pgroup</code> key in +options+ specifies a process group.
5008 * The corresponding value should be true, zero, a positive integer, or nil.
5009 * true and zero cause the process to be a process leader of a new process group.
5010 * A non-zero positive integer causes the process to join the provided process group.
5011 * The default value, nil, causes the process to remain in the same process group.
5012 *
5013 * pid = spawn(command, :pgroup=>true) # process leader
5014 * pid = spawn(command, :pgroup=>10) # belongs to the process group 10
5015 *
5016 * The <code>:new_pgroup</code> key in +options+ specifies to pass
5017 * +CREATE_NEW_PROCESS_GROUP+ flag to <code>CreateProcessW()</code> that is
5018 * Windows API. This option is only for Windows.
5019 * true means the new process is the root process of the new process group.
5020 * The new process has CTRL+C disabled. This flag is necessary for
5021 * <code>Process.kill(:SIGINT, pid)</code> on the subprocess.
5022 * :new_pgroup is false by default.
5023 *
5024 * pid = spawn(command, :new_pgroup=>true) # new process group
5025 * pid = spawn(command, :new_pgroup=>false) # same process group
5026 *
5027 * The <code>:rlimit_</code><em>foo</em> key specifies a resource limit.
5028 * <em>foo</em> should be one of resource types such as <code>core</code>.
5029 * The corresponding value should be an integer or an array which have one or
5030 * two integers: same as cur_limit and max_limit arguments for
5031 * Process.setrlimit.
5032 *
5033 * cur, max = Process.getrlimit(:CORE)
5034 * pid = spawn(command, :rlimit_core=>[0,max]) # disable core temporary.
5035 * pid = spawn(command, :rlimit_core=>max) # enable core dump
5036 * pid = spawn(command, :rlimit_core=>0) # never dump core.
5037 *
5038 * The <code>:umask</code> key in +options+ specifies the umask.
5039 *
5040 * pid = spawn(command, :umask=>077)
5041 *
5042 * The :in, :out, :err, an integer, an IO and an array key specifies a redirection.
5043 * The redirection maps a file descriptor in the child process.
5044 *
5045 * For example, stderr can be merged into stdout as follows:
5046 *
5047 * pid = spawn(command, :err=>:out)
5048 * pid = spawn(command, 2=>1)
5049 * pid = spawn(command, STDERR=>:out)
5050 * pid = spawn(command, STDERR=>STDOUT)
5051 *
5052 * The hash keys specifies a file descriptor in the child process
5053 * started by #spawn.
5054 * :err, 2 and STDERR specifies the standard error stream (stderr).
5055 *
5056 * The hash values specifies a file descriptor in the parent process
5057 * which invokes #spawn.
5058 * :out, 1 and STDOUT specifies the standard output stream (stdout).
5059 *
5060 * In the above example,
5061 * the standard output in the child process is not specified.
5062 * So it is inherited from the parent process.
5063 *
5064 * The standard input stream (stdin) can be specified by :in, 0 and STDIN.
5065 *
5066 * A filename can be specified as a hash value.
5067 *
5068 * pid = spawn(command, :in=>"/dev/null") # read mode
5069 * pid = spawn(command, :out=>"/dev/null") # write mode
5070 * pid = spawn(command, :err=>"log") # write mode
5071 * pid = spawn(command, [:out, :err]=>"/dev/null") # write mode
5072 * pid = spawn(command, 3=>"/dev/null") # read mode
5073 *
5074 * For stdout and stderr (and combination of them),
5075 * it is opened in write mode.
5076 * Otherwise read mode is used.
5077 *
5078 * For specifying flags and permission of file creation explicitly,
5079 * an array is used instead.
5080 *
5081 * pid = spawn(command, :in=>["file"]) # read mode is assumed
5082 * pid = spawn(command, :in=>["file", "r"])
5083 * pid = spawn(command, :out=>["log", "w"]) # 0644 assumed
5084 * pid = spawn(command, :out=>["log", "w", 0600])
5085 * pid = spawn(command, :out=>["log", File::WRONLY|File::EXCL|File::CREAT, 0600])
5086 *
5087 * The array specifies a filename, flags and permission.
5088 * The flags can be a string or an integer.
5089 * If the flags is omitted or nil, File::RDONLY is assumed.
5090 * The permission should be an integer.
5091 * If the permission is omitted or nil, 0644 is assumed.
5092 *
5093 * If an array of IOs and integers are specified as a hash key,
5094 * all the elements are redirected.
5095 *
5096 * # stdout and stderr is redirected to log file.
5097 * # The file "log" is opened just once.
5098 * pid = spawn(command, [:out, :err]=>["log", "w"])
5099 *
5100 * Another way to merge multiple file descriptors is [:child, fd].
5101 * \[:child, fd] means the file descriptor in the child process.
5102 * This is different from fd.
5103 * For example, :err=>:out means redirecting child stderr to parent stdout.
5104 * But :err=>[:child, :out] means redirecting child stderr to child stdout.
5105 * They differ if stdout is redirected in the child process as follows.
5106 *
5107 * # stdout and stderr is redirected to log file.
5108 * # The file "log" is opened just once.
5109 * pid = spawn(command, :out=>["log", "w"], :err=>[:child, :out])
5110 *
5111 * \[:child, :out] can be used to merge stderr into stdout in IO.popen.
5112 * In this case, IO.popen redirects stdout to a pipe in the child process
5113 * and [:child, :out] refers the redirected stdout.
5114 *
5115 * io = IO.popen(["sh", "-c", "echo out; echo err >&2", :err=>[:child, :out]])
5116 * p io.read #=> "out\nerr\n"
5117 *
5118 * The <code>:chdir</code> key in +options+ specifies the current directory.
5119 *
5120 * pid = spawn(command, :chdir=>"/var/tmp")
5121 *
5122 * spawn closes all non-standard unspecified descriptors by default.
5123 * The "standard" descriptors are 0, 1 and 2.
5124 * This behavior is specified by :close_others option.
5125 * :close_others doesn't affect the standard descriptors which are
5126 * closed only if :close is specified explicitly.
5127 *
5128 * pid = spawn(command, :close_others=>true) # close 3,4,5,... (default)
5129 * pid = spawn(command, :close_others=>false) # don't close 3,4,5,...
5130 *
5131 * :close_others is false by default for spawn and IO.popen.
5132 *
5133 * Note that fds which close-on-exec flag is already set are closed
5134 * regardless of :close_others option.
5135 *
5136 * So IO.pipe and spawn can be used as IO.popen.
5137 *
5138 * # similar to r = IO.popen(command)
5139 * r, w = IO.pipe
5140 * pid = spawn(command, :out=>w) # r, w is closed in the child process.
5141 * w.close
5142 *
5143 * :close is specified as a hash value to close a fd individually.
5144 *
5145 * f = open(foo)
5146 * system(command, f=>:close) # don't inherit f.
5147 *
5148 * If a file descriptor need to be inherited,
5149 * io=>io can be used.
5150 *
5151 * # valgrind has --log-fd option for log destination.
5152 * # log_w=>log_w indicates log_w.fileno inherits to child process.
5153 * log_r, log_w = IO.pipe
5154 * pid = spawn("valgrind", "--log-fd=#{log_w.fileno}", "echo", "a", log_w=>log_w)
5155 * log_w.close
5156 * p log_r.read
5157 *
5158 * It is also possible to exchange file descriptors.
5159 *
5160 * pid = spawn(command, :out=>:err, :err=>:out)
5161 *
5162 * The hash keys specify file descriptors in the child process.
5163 * The hash values specifies file descriptors in the parent process.
5164 * So the above specifies exchanging stdout and stderr.
5165 * Internally, +spawn+ uses an extra file descriptor to resolve such cyclic
5166 * file descriptor mapping.
5167 *
5168 * See Kernel.exec for the standard shell.
5169 */
5170
5171static VALUE
5172rb_f_spawn(int argc, VALUE *argv, VALUE _)
5173{
5174 rb_pid_t pid;
5175 char errmsg[CHILD_ERRMSG_BUFLEN] = { '\0' };
5176 VALUE execarg_obj, fail_str;
5177 struct rb_execarg *eargp;
5178
5179 execarg_obj = rb_execarg_new(argc, argv, TRUE, FALSE);
5180 eargp = rb_execarg_get(execarg_obj);
5181 fail_str = eargp->use_shell ? eargp->invoke.sh.shell_script : eargp->invoke.cmd.command_name;
5182
5183 pid = rb_execarg_spawn(execarg_obj, errmsg, sizeof(errmsg));
5184
5185 if (pid == -1) {
5186 int err = errno;
5187 rb_exec_fail(eargp, err, errmsg);
5188 RB_GC_GUARD(execarg_obj);
5189 rb_syserr_fail_str(err, fail_str);
5190 }
5191#if defined(HAVE_WORKING_FORK) || defined(HAVE_SPAWNV)
5192 return PIDT2NUM(pid);
5193#else
5194 return Qnil;
5195#endif
5196}
5197
5198/*
5199 * call-seq:
5200 * sleep([duration]) -> integer
5201 *
5202 * Suspends the current thread for _duration_ seconds (which may be any number,
5203 * including a +Float+ with fractional seconds). Returns the actual number of
5204 * seconds slept (rounded), which may be less than that asked for if another
5205 * thread calls Thread#run. Called without an argument, sleep()
5206 * will sleep forever.
5207 *
5208 * Time.new #=> 2008-03-08 19:56:19 +0900
5209 * sleep 1.2 #=> 1
5210 * Time.new #=> 2008-03-08 19:56:20 +0900
5211 * sleep 1.9 #=> 2
5212 * Time.new #=> 2008-03-08 19:56:22 +0900
5213 */
5214
5215static VALUE
5216rb_f_sleep(int argc, VALUE *argv, VALUE _)
5217{
5218 time_t beg = time(0);
5219 VALUE scheduler = rb_fiber_scheduler_current();
5220
5221 if (scheduler != Qnil) {
5222 rb_fiber_scheduler_kernel_sleepv(scheduler, argc, argv);
5223 }
5224 else {
5225 if (argc == 0) {
5227 }
5228 else {
5229 rb_check_arity(argc, 0, 1);
5231 }
5232 }
5233
5234 time_t end = time(0) - beg;
5235
5236 return TIMET2NUM(end);
5237}
5238
5239
5240#if (defined(HAVE_GETPGRP) && defined(GETPGRP_VOID)) || defined(HAVE_GETPGID)
5241/*
5242 * call-seq:
5243 * Process.getpgrp -> integer
5244 *
5245 * Returns the process group ID for this process. Not available on
5246 * all platforms.
5247 *
5248 * Process.getpgid(0) #=> 25527
5249 * Process.getpgrp #=> 25527
5250 */
5251
5252static VALUE
5253proc_getpgrp(VALUE _)
5254{
5255 rb_pid_t pgrp;
5256
5257#if defined(HAVE_GETPGRP) && defined(GETPGRP_VOID)
5258 pgrp = getpgrp();
5259 if (pgrp < 0) rb_sys_fail(0);
5260 return PIDT2NUM(pgrp);
5261#else /* defined(HAVE_GETPGID) */
5262 pgrp = getpgid(0);
5263 if (pgrp < 0) rb_sys_fail(0);
5264 return PIDT2NUM(pgrp);
5265#endif
5266}
5267#else
5268#define proc_getpgrp rb_f_notimplement
5269#endif
5270
5271
5272#if defined(HAVE_SETPGID) || (defined(HAVE_SETPGRP) && defined(SETPGRP_VOID))
5273/*
5274 * call-seq:
5275 * Process.setpgrp -> 0
5276 *
5277 * Equivalent to <code>setpgid(0,0)</code>. Not available on all
5278 * platforms.
5279 */
5280
5281static VALUE
5282proc_setpgrp(VALUE _)
5283{
5284 /* check for posix setpgid() first; this matches the posix */
5285 /* getpgrp() above. It appears that configure will set SETPGRP_VOID */
5286 /* even though setpgrp(0,0) would be preferred. The posix call avoids */
5287 /* this confusion. */
5288#ifdef HAVE_SETPGID
5289 if (setpgid(0,0) < 0) rb_sys_fail(0);
5290#elif defined(HAVE_SETPGRP) && defined(SETPGRP_VOID)
5291 if (setpgrp() < 0) rb_sys_fail(0);
5292#endif
5293 return INT2FIX(0);
5294}
5295#else
5296#define proc_setpgrp rb_f_notimplement
5297#endif
5298
5299
5300#if defined(HAVE_GETPGID)
5301/*
5302 * call-seq:
5303 * Process.getpgid(pid) -> integer
5304 *
5305 * Returns the process group ID for the given process id. Not
5306 * available on all platforms.
5307 *
5308 * Process.getpgid(Process.ppid()) #=> 25527
5309 */
5310
5311static VALUE
5312proc_getpgid(VALUE obj, VALUE pid)
5313{
5314 rb_pid_t i;
5315
5316 i = getpgid(NUM2PIDT(pid));
5317 if (i < 0) rb_sys_fail(0);
5318 return PIDT2NUM(i);
5319}
5320#else
5321#define proc_getpgid rb_f_notimplement
5322#endif
5323
5324
5325#ifdef HAVE_SETPGID
5326/*
5327 * call-seq:
5328 * Process.setpgid(pid, integer) -> 0
5329 *
5330 * Sets the process group ID of _pid_ (0 indicates this
5331 * process) to <em>integer</em>. Not available on all platforms.
5332 */
5333
5334static VALUE
5335proc_setpgid(VALUE obj, VALUE pid, VALUE pgrp)
5336{
5337 rb_pid_t ipid, ipgrp;
5338
5339 ipid = NUM2PIDT(pid);
5340 ipgrp = NUM2PIDT(pgrp);
5341
5342 if (setpgid(ipid, ipgrp) < 0) rb_sys_fail(0);
5343 return INT2FIX(0);
5344}
5345#else
5346#define proc_setpgid rb_f_notimplement
5347#endif
5348
5349
5350#ifdef HAVE_GETSID
5351/*
5352 * call-seq:
5353 * Process.getsid() -> integer
5354 * Process.getsid(pid) -> integer
5355 *
5356 * Returns the session ID for the given process id. If not given,
5357 * return current process sid. Not available on all platforms.
5358 *
5359 * Process.getsid() #=> 27422
5360 * Process.getsid(0) #=> 27422
5361 * Process.getsid(Process.pid()) #=> 27422
5362 */
5363static VALUE
5364proc_getsid(int argc, VALUE *argv, VALUE _)
5365{
5366 rb_pid_t sid;
5367 rb_pid_t pid = 0;
5368
5369 if (rb_check_arity(argc, 0, 1) == 1 && !NIL_P(argv[0]))
5370 pid = NUM2PIDT(argv[0]);
5371
5372 sid = getsid(pid);
5373 if (sid < 0) rb_sys_fail(0);
5374 return PIDT2NUM(sid);
5375}
5376#else
5377#define proc_getsid rb_f_notimplement
5378#endif
5379
5380
5381#if defined(HAVE_SETSID) || (defined(HAVE_SETPGRP) && defined(TIOCNOTTY))
5382#if !defined(HAVE_SETSID)
5383static rb_pid_t ruby_setsid(void);
5384#define setsid() ruby_setsid()
5385#endif
5386/*
5387 * call-seq:
5388 * Process.setsid -> integer
5389 *
5390 * Establishes this process as a new session and process group
5391 * leader, with no controlling tty. Returns the session id. Not
5392 * available on all platforms.
5393 *
5394 * Process.setsid #=> 27422
5395 */
5396
5397static VALUE
5398proc_setsid(VALUE _)
5399{
5400 rb_pid_t pid;
5401
5402 pid = setsid();
5403 if (pid < 0) rb_sys_fail(0);
5404 return PIDT2NUM(pid);
5405}
5406
5407#if !defined(HAVE_SETSID)
5408#define HAVE_SETSID 1
5409static rb_pid_t
5410ruby_setsid(void)
5411{
5412 rb_pid_t pid;
5413 int ret;
5414
5415 pid = getpid();
5416#if defined(SETPGRP_VOID)
5417 ret = setpgrp();
5418 /* If `pid_t setpgrp(void)' is equivalent to setsid(),
5419 `ret' will be the same value as `pid', and following open() will fail.
5420 In Linux, `int setpgrp(void)' is equivalent to setpgid(0, 0). */
5421#else
5422 ret = setpgrp(0, pid);
5423#endif
5424 if (ret == -1) return -1;
5425
5426 if ((fd = rb_cloexec_open("/dev/tty", O_RDWR, 0)) >= 0) {
5427 rb_update_max_fd(fd);
5428 ioctl(fd, TIOCNOTTY, NULL);
5429 close(fd);
5430 }
5431 return pid;
5432}
5433#endif
5434#else
5435#define proc_setsid rb_f_notimplement
5436#endif
5437
5438
5439#ifdef HAVE_GETPRIORITY
5440/*
5441 * call-seq:
5442 * Process.getpriority(kind, integer) -> integer
5443 *
5444 * Gets the scheduling priority for specified process, process group,
5445 * or user. <em>kind</em> indicates the kind of entity to find: one
5446 * of Process::PRIO_PGRP,
5447 * Process::PRIO_USER, or
5448 * Process::PRIO_PROCESS. _integer_ is an id
5449 * indicating the particular process, process group, or user (an id
5450 * of 0 means _current_). Lower priorities are more favorable
5451 * for scheduling. Not available on all platforms.
5452 *
5453 * Process.getpriority(Process::PRIO_USER, 0) #=> 19
5454 * Process.getpriority(Process::PRIO_PROCESS, 0) #=> 19
5455 */
5456
5457static VALUE
5458proc_getpriority(VALUE obj, VALUE which, VALUE who)
5459{
5460 int prio, iwhich, iwho;
5461
5462 iwhich = NUM2INT(which);
5463 iwho = NUM2INT(who);
5464
5465 errno = 0;
5466 prio = getpriority(iwhich, iwho);
5467 if (errno) rb_sys_fail(0);
5468 return INT2FIX(prio);
5469}
5470#else
5471#define proc_getpriority rb_f_notimplement
5472#endif
5473
5474
5475#ifdef HAVE_GETPRIORITY
5476/*
5477 * call-seq:
5478 * Process.setpriority(kind, integer, priority) -> 0
5479 *
5480 * See Process.getpriority.
5481 *
5482 * Process.setpriority(Process::PRIO_USER, 0, 19) #=> 0
5483 * Process.setpriority(Process::PRIO_PROCESS, 0, 19) #=> 0
5484 * Process.getpriority(Process::PRIO_USER, 0) #=> 19
5485 * Process.getpriority(Process::PRIO_PROCESS, 0) #=> 19
5486 */
5487
5488static VALUE
5489proc_setpriority(VALUE obj, VALUE which, VALUE who, VALUE prio)
5490{
5491 int iwhich, iwho, iprio;
5492
5493 iwhich = NUM2INT(which);
5494 iwho = NUM2INT(who);
5495 iprio = NUM2INT(prio);
5496
5497 if (setpriority(iwhich, iwho, iprio) < 0)
5498 rb_sys_fail(0);
5499 return INT2FIX(0);
5500}
5501#else
5502#define proc_setpriority rb_f_notimplement
5503#endif
5504
5505#if defined(HAVE_SETRLIMIT) && defined(NUM2RLIM)
5506static int
5507rlimit_resource_name2int(const char *name, long len, int casetype)
5508{
5509 int resource;
5510 const char *p;
5511#define RESCHECK(r) \
5512 do { \
5513 if (len == rb_strlen_lit(#r) && STRCASECMP(name, #r) == 0) { \
5514 resource = RLIMIT_##r; \
5515 goto found; \
5516 } \
5517 } while (0)
5518
5519 switch (TOUPPER(*name)) {
5520 case 'A':
5521#ifdef RLIMIT_AS
5522 RESCHECK(AS);
5523#endif
5524 break;
5525
5526 case 'C':
5527#ifdef RLIMIT_CORE
5528 RESCHECK(CORE);
5529#endif
5530#ifdef RLIMIT_CPU
5531 RESCHECK(CPU);
5532#endif
5533 break;
5534
5535 case 'D':
5536#ifdef RLIMIT_DATA
5537 RESCHECK(DATA);
5538#endif
5539 break;
5540
5541 case 'F':
5542#ifdef RLIMIT_FSIZE
5543 RESCHECK(FSIZE);
5544#endif
5545 break;
5546
5547 case 'M':
5548#ifdef RLIMIT_MEMLOCK
5549 RESCHECK(MEMLOCK);
5550#endif
5551#ifdef RLIMIT_MSGQUEUE
5552 RESCHECK(MSGQUEUE);
5553#endif
5554 break;
5555
5556 case 'N':
5557#ifdef RLIMIT_NOFILE
5558 RESCHECK(NOFILE);
5559#endif
5560#ifdef RLIMIT_NPROC
5561 RESCHECK(NPROC);
5562#endif
5563#ifdef RLIMIT_NPTS
5564 RESCHECK(NPTS);
5565#endif
5566#ifdef RLIMIT_NICE
5567 RESCHECK(NICE);
5568#endif
5569 break;
5570
5571 case 'R':
5572#ifdef RLIMIT_RSS
5573 RESCHECK(RSS);
5574#endif
5575#ifdef RLIMIT_RTPRIO
5576 RESCHECK(RTPRIO);
5577#endif
5578#ifdef RLIMIT_RTTIME
5579 RESCHECK(RTTIME);
5580#endif
5581 break;
5582
5583 case 'S':
5584#ifdef RLIMIT_STACK
5585 RESCHECK(STACK);
5586#endif
5587#ifdef RLIMIT_SBSIZE
5588 RESCHECK(SBSIZE);
5589#endif
5590#ifdef RLIMIT_SIGPENDING
5591 RESCHECK(SIGPENDING);
5592#endif
5593 break;
5594 }
5595 return -1;
5596
5597 found:
5598 switch (casetype) {
5599 case 0:
5600 for (p = name; *p; p++)
5601 if (!ISUPPER(*p))
5602 return -1;
5603 break;
5604
5605 case 1:
5606 for (p = name; *p; p++)
5607 if (!ISLOWER(*p))
5608 return -1;
5609 break;
5610
5611 default:
5612 rb_bug("unexpected casetype");
5613 }
5614 return resource;
5615#undef RESCHECK
5616}
5617
5618static int
5619rlimit_type_by_hname(const char *name, long len)
5620{
5621 return rlimit_resource_name2int(name, len, 0);
5622}
5623
5624static int
5625rlimit_type_by_lname(const char *name, long len)
5626{
5627 return rlimit_resource_name2int(name, len, 1);
5628}
5629
5630static int
5631rlimit_type_by_sym(VALUE key)
5632{
5633 VALUE name = rb_sym2str(key);
5634 const char *rname = RSTRING_PTR(name);
5635 long len = RSTRING_LEN(name);
5636 int rtype = -1;
5637 static const char prefix[] = "rlimit_";
5638 enum {prefix_len = sizeof(prefix)-1};
5639
5640 if (len > prefix_len && strncmp(prefix, rname, prefix_len) == 0) {
5641 rtype = rlimit_type_by_lname(rname + prefix_len, len - prefix_len);
5642 }
5643
5644 RB_GC_GUARD(key);
5645 return rtype;
5646}
5647
5648static int
5649rlimit_resource_type(VALUE rtype)
5650{
5651 const char *name;
5652 long len;
5653 VALUE v;
5654 int r;
5655
5656 switch (TYPE(rtype)) {
5657 case T_SYMBOL:
5658 v = rb_sym2str(rtype);
5659 name = RSTRING_PTR(v);
5660 len = RSTRING_LEN(v);
5661 break;
5662
5663 default:
5664 v = rb_check_string_type(rtype);
5665 if (!NIL_P(v)) {
5666 rtype = v;
5667 case T_STRING:
5668 name = StringValueCStr(rtype);
5669 len = RSTRING_LEN(rtype);
5670 break;
5671 }
5672 /* fall through */
5673
5674 case T_FIXNUM:
5675 case T_BIGNUM:
5676 return NUM2INT(rtype);
5677 }
5678
5679 r = rlimit_type_by_hname(name, len);
5680 if (r != -1)
5681 return r;
5682
5683 rb_raise(rb_eArgError, "invalid resource name: % "PRIsVALUE, rtype);
5684
5686}
5687
5688static rlim_t
5689rlimit_resource_value(VALUE rval)
5690{
5691 const char *name;
5692 VALUE v;
5693
5694 switch (TYPE(rval)) {
5695 case T_SYMBOL:
5696 v = rb_sym2str(rval);
5697 name = RSTRING_PTR(v);
5698 break;
5699
5700 default:
5701 v = rb_check_string_type(rval);
5702 if (!NIL_P(v)) {
5703 rval = v;
5704 case T_STRING:
5705 name = StringValueCStr(rval);
5706 break;
5707 }
5708 /* fall through */
5709
5710 case T_FIXNUM:
5711 case T_BIGNUM:
5712 return NUM2RLIM(rval);
5713 }
5714
5715#ifdef RLIM_INFINITY
5716 if (strcmp(name, "INFINITY") == 0) return RLIM_INFINITY;
5717#endif
5718#ifdef RLIM_SAVED_MAX
5719 if (strcmp(name, "SAVED_MAX") == 0) return RLIM_SAVED_MAX;
5720#endif
5721#ifdef RLIM_SAVED_CUR
5722 if (strcmp(name, "SAVED_CUR") == 0) return RLIM_SAVED_CUR;
5723#endif
5724 rb_raise(rb_eArgError, "invalid resource value: %"PRIsVALUE, rval);
5725
5726 UNREACHABLE_RETURN((rlim_t)-1);
5727}
5728#endif
5729
5730#if defined(HAVE_GETRLIMIT) && defined(RLIM2NUM)
5731/*
5732 * call-seq:
5733 * Process.getrlimit(resource) -> [cur_limit, max_limit]
5734 *
5735 * Gets the resource limit of the process.
5736 * _cur_limit_ means current (soft) limit and
5737 * _max_limit_ means maximum (hard) limit.
5738 *
5739 * _resource_ indicates the kind of resource to limit.
5740 * It is specified as a symbol such as <code>:CORE</code>,
5741 * a string such as <code>"CORE"</code> or
5742 * a constant such as Process::RLIMIT_CORE.
5743 * See Process.setrlimit for details.
5744 *
5745 * _cur_limit_ and _max_limit_ may be Process::RLIM_INFINITY,
5746 * Process::RLIM_SAVED_MAX or
5747 * Process::RLIM_SAVED_CUR.
5748 * See Process.setrlimit and the system getrlimit(2) manual for details.
5749 */
5750
5751static VALUE
5752proc_getrlimit(VALUE obj, VALUE resource)
5753{
5754 struct rlimit rlim;
5755
5756 if (getrlimit(rlimit_resource_type(resource), &rlim) < 0) {
5757 rb_sys_fail("getrlimit");
5758 }
5759 return rb_assoc_new(RLIM2NUM(rlim.rlim_cur), RLIM2NUM(rlim.rlim_max));
5760}
5761#else
5762#define proc_getrlimit rb_f_notimplement
5763#endif
5764
5765#if defined(HAVE_SETRLIMIT) && defined(NUM2RLIM)
5766/*
5767 * call-seq:
5768 * Process.setrlimit(resource, cur_limit, max_limit) -> nil
5769 * Process.setrlimit(resource, cur_limit) -> nil
5770 *
5771 * Sets the resource limit of the process.
5772 * _cur_limit_ means current (soft) limit and
5773 * _max_limit_ means maximum (hard) limit.
5774 *
5775 * If _max_limit_ is not given, _cur_limit_ is used.
5776 *
5777 * _resource_ indicates the kind of resource to limit.
5778 * It should be a symbol such as <code>:CORE</code>,
5779 * a string such as <code>"CORE"</code> or
5780 * a constant such as Process::RLIMIT_CORE.
5781 * The available resources are OS dependent.
5782 * Ruby may support following resources.
5783 *
5784 * [AS] total available memory (bytes) (SUSv3, NetBSD, FreeBSD, OpenBSD but 4.4BSD-Lite)
5785 * [CORE] core size (bytes) (SUSv3)
5786 * [CPU] CPU time (seconds) (SUSv3)
5787 * [DATA] data segment (bytes) (SUSv3)
5788 * [FSIZE] file size (bytes) (SUSv3)
5789 * [MEMLOCK] total size for mlock(2) (bytes) (4.4BSD, GNU/Linux)
5790 * [MSGQUEUE] allocation for POSIX message queues (bytes) (GNU/Linux)
5791 * [NICE] ceiling on process's nice(2) value (number) (GNU/Linux)
5792 * [NOFILE] file descriptors (number) (SUSv3)
5793 * [NPROC] number of processes for the user (number) (4.4BSD, GNU/Linux)
5794 * [NPTS] number of pseudo terminals (number) (FreeBSD)
5795 * [RSS] resident memory size (bytes) (4.2BSD, GNU/Linux)
5796 * [RTPRIO] ceiling on the process's real-time priority (number) (GNU/Linux)
5797 * [RTTIME] CPU time for real-time process (us) (GNU/Linux)
5798 * [SBSIZE] all socket buffers (bytes) (NetBSD, FreeBSD)
5799 * [SIGPENDING] number of queued signals allowed (signals) (GNU/Linux)
5800 * [STACK] stack size (bytes) (SUSv3)
5801 *
5802 * _cur_limit_ and _max_limit_ may be
5803 * <code>:INFINITY</code>, <code>"INFINITY"</code> or
5804 * Process::RLIM_INFINITY,
5805 * which means that the resource is not limited.
5806 * They may be Process::RLIM_SAVED_MAX,
5807 * Process::RLIM_SAVED_CUR and
5808 * corresponding symbols and strings too.
5809 * See system setrlimit(2) manual for details.
5810 *
5811 * The following example raises the soft limit of core size to
5812 * the hard limit to try to make core dump possible.
5813 *
5814 * Process.setrlimit(:CORE, Process.getrlimit(:CORE)[1])
5815 *
5816 */
5817
5818static VALUE
5819proc_setrlimit(int argc, VALUE *argv, VALUE obj)
5820{
5821 VALUE resource, rlim_cur, rlim_max;
5822 struct rlimit rlim;
5823
5824 rb_check_arity(argc, 2, 3);
5825 resource = argv[0];
5826 rlim_cur = argv[1];
5827 if (argc < 3 || NIL_P(rlim_max = argv[2]))
5828 rlim_max = rlim_cur;
5829
5830 rlim.rlim_cur = rlimit_resource_value(rlim_cur);
5831 rlim.rlim_max = rlimit_resource_value(rlim_max);
5832
5833 if (setrlimit(rlimit_resource_type(resource), &rlim) < 0) {
5834 rb_sys_fail("setrlimit");
5835 }
5836 return Qnil;
5837}
5838#else
5839#define proc_setrlimit rb_f_notimplement
5840#endif
5841
5842static int under_uid_switch = 0;
5843static void
5844check_uid_switch(void)
5845{
5846 if (under_uid_switch) {
5847 rb_raise(rb_eRuntimeError, "can't handle UID while evaluating block given to Process::UID.switch method");
5848 }
5849}
5850
5851static int under_gid_switch = 0;
5852static void
5853check_gid_switch(void)
5854{
5855 if (under_gid_switch) {
5856 rb_raise(rb_eRuntimeError, "can't handle GID while evaluating block given to Process::UID.switch method");
5857 }
5858}
5859
5860
5861#if defined(HAVE_PWD_H)
5867VALUE
5868rb_getlogin(void)
5869{
5870#if ( !defined(USE_GETLOGIN_R) && !defined(USE_GETLOGIN) )
5871 return Qnil;
5872#else
5873 char MAYBE_UNUSED(*login) = NULL;
5874
5875# ifdef USE_GETLOGIN_R
5876
5877#if defined(__FreeBSD__)
5878 typedef int getlogin_r_size_t;
5879#else
5880 typedef size_t getlogin_r_size_t;
5881#endif
5882
5883 long loginsize = GETLOGIN_R_SIZE_INIT; /* maybe -1 */
5884
5885 if (loginsize < 0)
5886 loginsize = GETLOGIN_R_SIZE_DEFAULT;
5887
5888 VALUE maybe_result = rb_str_buf_new(loginsize);
5889
5890 login = RSTRING_PTR(maybe_result);
5891 loginsize = rb_str_capacity(maybe_result);
5892 rb_str_set_len(maybe_result, loginsize);
5893
5894 int gle;
5895 errno = 0;
5896 while ((gle = getlogin_r(login, (getlogin_r_size_t)loginsize)) != 0) {
5897
5898 if (gle == ENOTTY || gle == ENXIO || gle == ENOENT) {
5899 rb_str_resize(maybe_result, 0);
5900 return Qnil;
5901 }
5902
5903 if (gle != ERANGE || loginsize >= GETLOGIN_R_SIZE_LIMIT) {
5904 rb_str_resize(maybe_result, 0);
5905 rb_syserr_fail(gle, "getlogin_r");
5906 }
5907
5908 rb_str_modify_expand(maybe_result, loginsize);
5909 login = RSTRING_PTR(maybe_result);
5910 loginsize = rb_str_capacity(maybe_result);
5911 }
5912
5913 if (login == NULL) {
5914 rb_str_resize(maybe_result, 0);
5915 return Qnil;
5916 }
5917
5918 return maybe_result;
5919
5920# elif USE_GETLOGIN
5921
5922 errno = 0;
5923 login = getlogin();
5924 if (errno) {
5925 if (errno == ENOTTY || errno == ENXIO || errno == ENOENT) {
5926 return Qnil;
5927 }
5928 rb_syserr_fail(errno, "getlogin");
5929 }
5930
5931 return login ? rb_str_new_cstr(login) : Qnil;
5932# endif
5933
5934#endif
5935}
5936
5937VALUE
5938rb_getpwdirnam_for_login(VALUE login_name)
5939{
5940#if ( !defined(USE_GETPWNAM_R) && !defined(USE_GETPWNAM) )
5941 return Qnil;
5942#else
5943
5944 if (NIL_P(login_name)) {
5945 /* nothing to do; no name with which to query the password database */
5946 return Qnil;
5947 }
5948
5949 char *login = RSTRING_PTR(login_name);
5950
5951 struct passwd *pwptr;
5952
5953# ifdef USE_GETPWNAM_R
5954
5955 struct passwd pwdnm;
5956 char *bufnm;
5957 long bufsizenm = GETPW_R_SIZE_INIT; /* maybe -1 */
5958
5959 if (bufsizenm < 0)
5960 bufsizenm = GETPW_R_SIZE_DEFAULT;
5961
5962 VALUE getpwnm_tmp = rb_str_tmp_new(bufsizenm);
5963
5964 bufnm = RSTRING_PTR(getpwnm_tmp);
5965 bufsizenm = rb_str_capacity(getpwnm_tmp);
5966 rb_str_set_len(getpwnm_tmp, bufsizenm);
5967
5968 int enm;
5969 errno = 0;
5970 while ((enm = getpwnam_r(login, &pwdnm, bufnm, bufsizenm, &pwptr)) != 0) {
5971
5972 if (enm == ENOENT || enm== ESRCH || enm == EBADF || enm == EPERM) {
5973 /* not found; non-errors */
5974 rb_str_resize(getpwnm_tmp, 0);
5975 return Qnil;
5976 }
5977
5978 if (enm != ERANGE || bufsizenm >= GETPW_R_SIZE_LIMIT) {
5979 rb_str_resize(getpwnm_tmp, 0);
5980 rb_syserr_fail(enm, "getpwnam_r");
5981 }
5982
5983 rb_str_modify_expand(getpwnm_tmp, bufsizenm);
5984 bufnm = RSTRING_PTR(getpwnm_tmp);
5985 bufsizenm = rb_str_capacity(getpwnm_tmp);
5986 }
5987
5988 if (pwptr == NULL) {
5989 /* no record in the password database for the login name */
5990 rb_str_resize(getpwnm_tmp, 0);
5991 return Qnil;
5992 }
5993
5994 /* found it */
5995 VALUE result = rb_str_new_cstr(pwptr->pw_dir);
5996 rb_str_resize(getpwnm_tmp, 0);
5997 return result;
5998
5999# elif USE_GETPWNAM
6000
6001 errno = 0;
6002 pwptr = getpwnam(login);
6003 if (pwptr) {
6004 /* found it */
6005 return rb_str_new_cstr(pwptr->pw_dir);
6006 }
6007 if (errno
6008 /* avoid treating as errors errno values that indicate "not found" */
6009 && ( errno != ENOENT && errno != ESRCH && errno != EBADF && errno != EPERM)) {
6010 rb_syserr_fail(errno, "getpwnam");
6011 }
6012
6013 return Qnil; /* not found */
6014# endif
6015
6016#endif
6017}
6018
6022VALUE
6023rb_getpwdiruid(void)
6024{
6025# if !defined(USE_GETPWUID_R) && !defined(USE_GETPWUID)
6026 /* Should never happen... </famous-last-words> */
6027 return Qnil;
6028# else
6029 uid_t ruid = getuid();
6030
6031 struct passwd *pwptr;
6032
6033# ifdef USE_GETPWUID_R
6034
6035 struct passwd pwdid;
6036 char *bufid;
6037 long bufsizeid = GETPW_R_SIZE_INIT; /* maybe -1 */
6038
6039 if (bufsizeid < 0)
6040 bufsizeid = GETPW_R_SIZE_DEFAULT;
6041
6042 VALUE getpwid_tmp = rb_str_tmp_new(bufsizeid);
6043
6044 bufid = RSTRING_PTR(getpwid_tmp);
6045 bufsizeid = rb_str_capacity(getpwid_tmp);
6046 rb_str_set_len(getpwid_tmp, bufsizeid);
6047
6048 int eid;
6049 errno = 0;
6050 while ((eid = getpwuid_r(ruid, &pwdid, bufid, bufsizeid, &pwptr)) != 0) {
6051
6052 if (eid == ENOENT || eid== ESRCH || eid == EBADF || eid == EPERM) {
6053 /* not found; non-errors */
6054 rb_str_resize(getpwid_tmp, 0);
6055 return Qnil;
6056 }
6057
6058 if (eid != ERANGE || bufsizeid >= GETPW_R_SIZE_LIMIT) {
6059 rb_str_resize(getpwid_tmp, 0);
6060 rb_syserr_fail(eid, "getpwuid_r");
6061 }
6062
6063 rb_str_modify_expand(getpwid_tmp, bufsizeid);
6064 bufid = RSTRING_PTR(getpwid_tmp);
6065 bufsizeid = rb_str_capacity(getpwid_tmp);
6066 }
6067
6068 if (pwptr == NULL) {
6069 /* no record in the password database for the uid */
6070 rb_str_resize(getpwid_tmp, 0);
6071 return Qnil;
6072 }
6073
6074 /* found it */
6075 VALUE result = rb_str_new_cstr(pwptr->pw_dir);
6076 rb_str_resize(getpwid_tmp, 0);
6077 return result;
6078
6079# elif defined(USE_GETPWUID)
6080
6081 errno = 0;
6082 pwptr = getpwuid(ruid);
6083 if (pwptr) {
6084 /* found it */
6085 return rb_str_new_cstr(pwptr->pw_dir);
6086 }
6087 if (errno
6088 /* avoid treating as errors errno values that indicate "not found" */
6089 && ( errno == ENOENT || errno == ESRCH || errno == EBADF || errno == EPERM)) {
6090 rb_syserr_fail(errno, "getpwuid");
6091 }
6092
6093 return Qnil; /* not found */
6094# endif
6095
6096#endif /* !defined(USE_GETPWUID_R) && !defined(USE_GETPWUID) */
6097}
6098#endif /* HAVE_PWD_H */
6099
6100
6101/*********************************************************************
6102 * Document-class: Process::Sys
6103 *
6104 * The Process::Sys module contains UID and GID
6105 * functions which provide direct bindings to the system calls of the
6106 * same names instead of the more-portable versions of the same
6107 * functionality found in the Process,
6108 * Process::UID, and Process::GID modules.
6109 */
6110
6111#if defined(HAVE_PWD_H)
6112static rb_uid_t
6113obj2uid(VALUE id
6114# ifdef USE_GETPWNAM_R
6115 , VALUE *getpw_tmp
6116# endif
6117 )
6118{
6119 rb_uid_t uid;
6120 VALUE tmp;
6121
6122 if (FIXNUM_P(id) || NIL_P(tmp = rb_check_string_type(id))) {
6123 uid = NUM2UIDT(id);
6124 }
6125 else {
6126 const char *usrname = StringValueCStr(id);
6127 struct passwd *pwptr;
6128#ifdef USE_GETPWNAM_R
6129 struct passwd pwbuf;
6130 char *getpw_buf;
6131 long getpw_buf_len;
6132 int e;
6133 if (!*getpw_tmp) {
6134 getpw_buf_len = GETPW_R_SIZE_INIT;
6135 if (getpw_buf_len < 0) getpw_buf_len = GETPW_R_SIZE_DEFAULT;
6136 *getpw_tmp = rb_str_tmp_new(getpw_buf_len);
6137 }
6138 getpw_buf = RSTRING_PTR(*getpw_tmp);
6139 getpw_buf_len = rb_str_capacity(*getpw_tmp);
6140 rb_str_set_len(*getpw_tmp, getpw_buf_len);
6141 errno = 0;
6142 while ((e = getpwnam_r(usrname, &pwbuf, getpw_buf, getpw_buf_len, &pwptr)) != 0) {
6143 if (e != ERANGE || getpw_buf_len >= GETPW_R_SIZE_LIMIT) {
6144 rb_str_resize(*getpw_tmp, 0);
6145 rb_syserr_fail(e, "getpwnam_r");
6146 }
6147 rb_str_modify_expand(*getpw_tmp, getpw_buf_len);
6148 getpw_buf = RSTRING_PTR(*getpw_tmp);
6149 getpw_buf_len = rb_str_capacity(*getpw_tmp);
6150 }
6151#else
6152 pwptr = getpwnam(usrname);
6153#endif
6154 if (!pwptr) {
6155#ifndef USE_GETPWNAM_R
6156 endpwent();
6157#endif
6158 rb_raise(rb_eArgError, "can't find user for %"PRIsVALUE, id);
6159 }
6160 uid = pwptr->pw_uid;
6161#ifndef USE_GETPWNAM_R
6162 endpwent();
6163#endif
6164 }
6165 return uid;
6166}
6167
6168# ifdef p_uid_from_name
6169/*
6170 * call-seq:
6171 * Process::UID.from_name(name) -> uid
6172 *
6173 * Get the user ID by the _name_.
6174 * If the user is not found, +ArgumentError+ will be raised.
6175 *
6176 * Process::UID.from_name("root") #=> 0
6177 * Process::UID.from_name("nosuchuser") #=> can't find user for nosuchuser (ArgumentError)
6178 */
6179
6180static VALUE
6181p_uid_from_name(VALUE self, VALUE id)
6182{
6183 return UIDT2NUM(OBJ2UID(id));
6184}
6185# endif
6186#endif
6187
6188#if defined(HAVE_GRP_H)
6189static rb_gid_t
6190obj2gid(VALUE id
6191# ifdef USE_GETGRNAM_R
6192 , VALUE *getgr_tmp
6193# endif
6194 )
6195{
6196 rb_gid_t gid;
6197 VALUE tmp;
6198
6199 if (FIXNUM_P(id) || NIL_P(tmp = rb_check_string_type(id))) {
6200 gid = NUM2GIDT(id);
6201 }
6202 else {
6203 const char *grpname = StringValueCStr(id);
6204 struct group *grptr;
6205#ifdef USE_GETGRNAM_R
6206 struct group grbuf;
6207 char *getgr_buf;
6208 long getgr_buf_len;
6209 int e;
6210 if (!*getgr_tmp) {
6211 getgr_buf_len = GETGR_R_SIZE_INIT;
6212 if (getgr_buf_len < 0) getgr_buf_len = GETGR_R_SIZE_DEFAULT;
6213 *getgr_tmp = rb_str_tmp_new(getgr_buf_len);
6214 }
6215 getgr_buf = RSTRING_PTR(*getgr_tmp);
6216 getgr_buf_len = rb_str_capacity(*getgr_tmp);
6217 rb_str_set_len(*getgr_tmp, getgr_buf_len);
6218 errno = 0;
6219 while ((e = getgrnam_r(grpname, &grbuf, getgr_buf, getgr_buf_len, &grptr)) != 0) {
6220 if (e != ERANGE || getgr_buf_len >= GETGR_R_SIZE_LIMIT) {
6221 rb_str_resize(*getgr_tmp, 0);
6222 rb_syserr_fail(e, "getgrnam_r");
6223 }
6224 rb_str_modify_expand(*getgr_tmp, getgr_buf_len);
6225 getgr_buf = RSTRING_PTR(*getgr_tmp);
6226 getgr_buf_len = rb_str_capacity(*getgr_tmp);
6227 }
6228#elif defined(HAVE_GETGRNAM)
6229 grptr = getgrnam(grpname);
6230#else
6231 grptr = NULL;
6232#endif
6233 if (!grptr) {
6234#if !defined(USE_GETGRNAM_R) && defined(HAVE_ENDGRENT)
6235 endgrent();
6236#endif
6237 rb_raise(rb_eArgError, "can't find group for %"PRIsVALUE, id);
6238 }
6239 gid = grptr->gr_gid;
6240#if !defined(USE_GETGRNAM_R) && defined(HAVE_ENDGRENT)
6241 endgrent();
6242#endif
6243 }
6244 return gid;
6245}
6246
6247# ifdef p_gid_from_name
6248/*
6249 * call-seq:
6250 * Process::GID.from_name(name) -> gid
6251 *
6252 * Get the group ID by the _name_.
6253 * If the group is not found, +ArgumentError+ will be raised.
6254 *
6255 * Process::GID.from_name("wheel") #=> 0
6256 * Process::GID.from_name("nosuchgroup") #=> can't find group for nosuchgroup (ArgumentError)
6257 */
6258
6259static VALUE
6260p_gid_from_name(VALUE self, VALUE id)
6261{
6262 return GIDT2NUM(OBJ2GID(id));
6263}
6264# endif
6265#endif
6266
6267#if defined HAVE_SETUID
6268/*
6269 * call-seq:
6270 * Process::Sys.setuid(user) -> nil
6271 *
6272 * Set the user ID of the current process to _user_. Not
6273 * available on all platforms.
6274 *
6275 */
6276
6277static VALUE
6278p_sys_setuid(VALUE obj, VALUE id)
6279{
6280 check_uid_switch();
6281 if (setuid(OBJ2UID(id)) != 0) rb_sys_fail(0);
6282 return Qnil;
6283}
6284#else
6285#define p_sys_setuid rb_f_notimplement
6286#endif
6287
6288
6289#if defined HAVE_SETRUID
6290/*
6291 * call-seq:
6292 * Process::Sys.setruid(user) -> nil
6293 *
6294 * Set the real user ID of the calling process to _user_.
6295 * Not available on all platforms.
6296 *
6297 */
6298
6299static VALUE
6300p_sys_setruid(VALUE obj, VALUE id)
6301{
6302 check_uid_switch();
6303 if (setruid(OBJ2UID(id)) != 0) rb_sys_fail(0);
6304 return Qnil;
6305}
6306#else
6307#define p_sys_setruid rb_f_notimplement
6308#endif
6309
6310
6311#if defined HAVE_SETEUID
6312/*
6313 * call-seq:
6314 * Process::Sys.seteuid(user) -> nil
6315 *
6316 * Set the effective user ID of the calling process to
6317 * _user_. Not available on all platforms.
6318 *
6319 */
6320
6321static VALUE
6322p_sys_seteuid(VALUE obj, VALUE id)
6323{
6324 check_uid_switch();
6325 if (seteuid(OBJ2UID(id)) != 0) rb_sys_fail(0);
6326 return Qnil;
6327}
6328#else
6329#define p_sys_seteuid rb_f_notimplement
6330#endif
6331
6332
6333#if defined HAVE_SETREUID
6334/*
6335 * call-seq:
6336 * Process::Sys.setreuid(rid, eid) -> nil
6337 *
6338 * Sets the (user) real and/or effective user IDs of the current
6339 * process to _rid_ and _eid_, respectively. A value of
6340 * <code>-1</code> for either means to leave that ID unchanged. Not
6341 * available on all platforms.
6342 *
6343 */
6344
6345static VALUE
6346p_sys_setreuid(VALUE obj, VALUE rid, VALUE eid)
6347{
6348 rb_uid_t ruid, euid;
6349 PREPARE_GETPWNAM;
6350 check_uid_switch();
6351 ruid = OBJ2UID1(rid);
6352 euid = OBJ2UID1(eid);
6353 FINISH_GETPWNAM;
6354 if (setreuid(ruid, euid) != 0) rb_sys_fail(0);
6355 return Qnil;
6356}
6357#else
6358#define p_sys_setreuid rb_f_notimplement
6359#endif
6360
6361
6362#if defined HAVE_SETRESUID
6363/*
6364 * call-seq:
6365 * Process::Sys.setresuid(rid, eid, sid) -> nil
6366 *
6367 * Sets the (user) real, effective, and saved user IDs of the
6368 * current process to _rid_, _eid_, and _sid_ respectively. A
6369 * value of <code>-1</code> for any value means to
6370 * leave that ID unchanged. Not available on all platforms.
6371 *
6372 */
6373
6374static VALUE
6375p_sys_setresuid(VALUE obj, VALUE rid, VALUE eid, VALUE sid)
6376{
6377 rb_uid_t ruid, euid, suid;
6378 PREPARE_GETPWNAM;
6379 check_uid_switch();
6380 ruid = OBJ2UID1(rid);
6381 euid = OBJ2UID1(eid);
6382 suid = OBJ2UID1(sid);
6383 FINISH_GETPWNAM;
6384 if (setresuid(ruid, euid, suid) != 0) rb_sys_fail(0);
6385 return Qnil;
6386}
6387#else
6388#define p_sys_setresuid rb_f_notimplement
6389#endif
6390
6391
6392/*
6393 * call-seq:
6394 * Process.uid -> integer
6395 * Process::UID.rid -> integer
6396 * Process::Sys.getuid -> integer
6397 *
6398 * Returns the (real) user ID of this process.
6399 *
6400 * Process.uid #=> 501
6401 */
6402
6403static VALUE
6404proc_getuid(VALUE obj)
6405{
6406 rb_uid_t uid = getuid();
6407 return UIDT2NUM(uid);
6408}
6409
6410
6411#if defined(HAVE_SETRESUID) || defined(HAVE_SETREUID) || defined(HAVE_SETRUID) || defined(HAVE_SETUID)
6412/*
6413 * call-seq:
6414 * Process.uid= user -> numeric
6415 *
6416 * Sets the (user) user ID for this process. Not available on all
6417 * platforms.
6418 */
6419
6420static VALUE
6421proc_setuid(VALUE obj, VALUE id)
6422{
6423 rb_uid_t uid;
6424
6425 check_uid_switch();
6426
6427 uid = OBJ2UID(id);
6428#if defined(HAVE_SETRESUID)
6429 if (setresuid(uid, -1, -1) < 0) rb_sys_fail(0);
6430#elif defined HAVE_SETREUID
6431 if (setreuid(uid, -1) < 0) rb_sys_fail(0);
6432#elif defined HAVE_SETRUID
6433 if (setruid(uid) < 0) rb_sys_fail(0);
6434#elif defined HAVE_SETUID
6435 {
6436 if (geteuid() == uid) {
6437 if (setuid(uid) < 0) rb_sys_fail(0);
6438 }
6439 else {
6441 }
6442 }
6443#endif
6444 return id;
6445}
6446#else
6447#define proc_setuid rb_f_notimplement
6448#endif
6449
6450
6451/********************************************************************
6452 *
6453 * Document-class: Process::UID
6454 *
6455 * The Process::UID module contains a collection of
6456 * module functions which can be used to portably get, set, and
6457 * switch the current process's real, effective, and saved user IDs.
6458 *
6459 */
6460
6461static rb_uid_t SAVED_USER_ID = -1;
6462
6463#ifdef BROKEN_SETREUID
6464int
6465setreuid(rb_uid_t ruid, rb_uid_t euid)
6466{
6467 if (ruid != (rb_uid_t)-1 && ruid != getuid()) {
6468 if (euid == (rb_uid_t)-1) euid = geteuid();
6469 if (setuid(ruid) < 0) return -1;
6470 }
6471 if (euid != (rb_uid_t)-1 && euid != geteuid()) {
6472 if (seteuid(euid) < 0) return -1;
6473 }
6474 return 0;
6475}
6476#endif
6477
6478/*
6479 * call-seq:
6480 * Process::UID.change_privilege(user) -> integer
6481 *
6482 * Change the current process's real and effective user ID to that
6483 * specified by _user_. Returns the new user ID. Not
6484 * available on all platforms.
6485 *
6486 * [Process.uid, Process.euid] #=> [0, 0]
6487 * Process::UID.change_privilege(31) #=> 31
6488 * [Process.uid, Process.euid] #=> [31, 31]
6489 */
6490
6491static VALUE
6492p_uid_change_privilege(VALUE obj, VALUE id)
6493{
6494 rb_uid_t uid;
6495
6496 check_uid_switch();
6497
6498 uid = OBJ2UID(id);
6499
6500 if (geteuid() == 0) { /* root-user */
6501#if defined(HAVE_SETRESUID)
6502 if (setresuid(uid, uid, uid) < 0) rb_sys_fail(0);
6503 SAVED_USER_ID = uid;
6504#elif defined(HAVE_SETUID)
6505 if (setuid(uid) < 0) rb_sys_fail(0);
6506 SAVED_USER_ID = uid;
6507#elif defined(HAVE_SETREUID) && !defined(OBSOLETE_SETREUID)
6508 if (getuid() == uid) {
6509 if (SAVED_USER_ID == uid) {
6510 if (setreuid(-1, uid) < 0) rb_sys_fail(0);
6511 }
6512 else {
6513 if (uid == 0) { /* (r,e,s) == (root, root, x) */
6514 if (setreuid(-1, SAVED_USER_ID) < 0) rb_sys_fail(0);
6515 if (setreuid(SAVED_USER_ID, 0) < 0) rb_sys_fail(0);
6516 SAVED_USER_ID = 0; /* (r,e,s) == (x, root, root) */
6517 if (setreuid(uid, uid) < 0) rb_sys_fail(0);
6518 SAVED_USER_ID = uid;
6519 }
6520 else {
6521 if (setreuid(0, -1) < 0) rb_sys_fail(0);
6522 SAVED_USER_ID = 0;
6523 if (setreuid(uid, uid) < 0) rb_sys_fail(0);
6524 SAVED_USER_ID = uid;
6525 }
6526 }
6527 }
6528 else {
6529 if (setreuid(uid, uid) < 0) rb_sys_fail(0);
6530 SAVED_USER_ID = uid;
6531 }
6532#elif defined(HAVE_SETRUID) && defined(HAVE_SETEUID)
6533 if (getuid() == uid) {
6534 if (SAVED_USER_ID == uid) {
6535 if (seteuid(uid) < 0) rb_sys_fail(0);
6536 }
6537 else {
6538 if (uid == 0) {
6539 if (setruid(SAVED_USER_ID) < 0) rb_sys_fail(0);
6540 SAVED_USER_ID = 0;
6541 if (setruid(0) < 0) rb_sys_fail(0);
6542 }
6543 else {
6544 if (setruid(0) < 0) rb_sys_fail(0);
6545 SAVED_USER_ID = 0;
6546 if (seteuid(uid) < 0) rb_sys_fail(0);
6547 if (setruid(uid) < 0) rb_sys_fail(0);
6548 SAVED_USER_ID = uid;
6549 }
6550 }
6551 }
6552 else {
6553 if (seteuid(uid) < 0) rb_sys_fail(0);
6554 if (setruid(uid) < 0) rb_sys_fail(0);
6555 SAVED_USER_ID = uid;
6556 }
6557#else
6558 (void)uid;
6560#endif
6561 }
6562 else { /* unprivileged user */
6563#if defined(HAVE_SETRESUID)
6564 if (setresuid((getuid() == uid)? (rb_uid_t)-1: uid,
6565 (geteuid() == uid)? (rb_uid_t)-1: uid,
6566 (SAVED_USER_ID == uid)? (rb_uid_t)-1: uid) < 0) rb_sys_fail(0);
6567 SAVED_USER_ID = uid;
6568#elif defined(HAVE_SETREUID) && !defined(OBSOLETE_SETREUID)
6569 if (SAVED_USER_ID == uid) {
6570 if (setreuid((getuid() == uid)? (rb_uid_t)-1: uid,
6571 (geteuid() == uid)? (rb_uid_t)-1: uid) < 0)
6572 rb_sys_fail(0);
6573 }
6574 else if (getuid() != uid) {
6575 if (setreuid(uid, (geteuid() == uid)? (rb_uid_t)-1: uid) < 0)
6576 rb_sys_fail(0);
6577 SAVED_USER_ID = uid;
6578 }
6579 else if (/* getuid() == uid && */ geteuid() != uid) {
6580 if (setreuid(geteuid(), uid) < 0) rb_sys_fail(0);
6581 SAVED_USER_ID = uid;
6582 if (setreuid(uid, -1) < 0) rb_sys_fail(0);
6583 }
6584 else { /* getuid() == uid && geteuid() == uid */
6585 if (setreuid(-1, SAVED_USER_ID) < 0) rb_sys_fail(0);
6586 if (setreuid(SAVED_USER_ID, uid) < 0) rb_sys_fail(0);
6587 SAVED_USER_ID = uid;
6588 if (setreuid(uid, -1) < 0) rb_sys_fail(0);
6589 }
6590#elif defined(HAVE_SETRUID) && defined(HAVE_SETEUID)
6591 if (SAVED_USER_ID == uid) {
6592 if (geteuid() != uid && seteuid(uid) < 0) rb_sys_fail(0);
6593 if (getuid() != uid && setruid(uid) < 0) rb_sys_fail(0);
6594 }
6595 else if (/* SAVED_USER_ID != uid && */ geteuid() == uid) {
6596 if (getuid() != uid) {
6597 if (setruid(uid) < 0) rb_sys_fail(0);
6598 SAVED_USER_ID = uid;
6599 }
6600 else {
6601 if (setruid(SAVED_USER_ID) < 0) rb_sys_fail(0);
6602 SAVED_USER_ID = uid;
6603 if (setruid(uid) < 0) rb_sys_fail(0);
6604 }
6605 }
6606 else if (/* geteuid() != uid && */ getuid() == uid) {
6607 if (seteuid(uid) < 0) rb_sys_fail(0);
6608 if (setruid(SAVED_USER_ID) < 0) rb_sys_fail(0);
6609 SAVED_USER_ID = uid;
6610 if (setruid(uid) < 0) rb_sys_fail(0);
6611 }
6612 else {
6613 rb_syserr_fail(EPERM, 0);
6614 }
6615#elif defined HAVE_44BSD_SETUID
6616 if (getuid() == uid) {
6617 /* (r,e,s)==(uid,?,?) ==> (uid,uid,uid) */
6618 if (setuid(uid) < 0) rb_sys_fail(0);
6619 SAVED_USER_ID = uid;
6620 }
6621 else {
6622 rb_syserr_fail(EPERM, 0);
6623 }
6624#elif defined HAVE_SETEUID
6625 if (getuid() == uid && SAVED_USER_ID == uid) {
6626 if (seteuid(uid) < 0) rb_sys_fail(0);
6627 }
6628 else {
6629 rb_syserr_fail(EPERM, 0);
6630 }
6631#elif defined HAVE_SETUID
6632 if (getuid() == uid && SAVED_USER_ID == uid) {
6633 if (setuid(uid) < 0) rb_sys_fail(0);
6634 }
6635 else {
6636 rb_syserr_fail(EPERM, 0);
6637 }
6638#else
6640#endif
6641 }
6642 return id;
6643}
6644
6645
6646
6647#if defined HAVE_SETGID
6648/*
6649 * call-seq:
6650 * Process::Sys.setgid(group) -> nil
6651 *
6652 * Set the group ID of the current process to _group_. Not
6653 * available on all platforms.
6654 *
6655 */
6656
6657static VALUE
6658p_sys_setgid(VALUE obj, VALUE id)
6659{
6660 check_gid_switch();
6661 if (setgid(OBJ2GID(id)) != 0) rb_sys_fail(0);
6662 return Qnil;
6663}
6664#else
6665#define p_sys_setgid rb_f_notimplement
6666#endif
6667
6668
6669#if defined HAVE_SETRGID
6670/*
6671 * call-seq:
6672 * Process::Sys.setrgid(group) -> nil
6673 *
6674 * Set the real group ID of the calling process to _group_.
6675 * Not available on all platforms.
6676 *
6677 */
6678
6679static VALUE
6680p_sys_setrgid(VALUE obj, VALUE id)
6681{
6682 check_gid_switch();
6683 if (setrgid(OBJ2GID(id)) != 0) rb_sys_fail(0);
6684 return Qnil;
6685}
6686#else
6687#define p_sys_setrgid rb_f_notimplement
6688#endif
6689
6690
6691#if defined HAVE_SETEGID
6692/*
6693 * call-seq:
6694 * Process::Sys.setegid(group) -> nil
6695 *
6696 * Set the effective group ID of the calling process to
6697 * _group_. Not available on all platforms.
6698 *
6699 */
6700
6701static VALUE
6702p_sys_setegid(VALUE obj, VALUE id)
6703{
6704 check_gid_switch();
6705 if (setegid(OBJ2GID(id)) != 0) rb_sys_fail(0);
6706 return Qnil;
6707}
6708#else
6709#define p_sys_setegid rb_f_notimplement
6710#endif
6711
6712
6713#if defined HAVE_SETREGID
6714/*
6715 * call-seq:
6716 * Process::Sys.setregid(rid, eid) -> nil
6717 *
6718 * Sets the (group) real and/or effective group IDs of the current
6719 * process to <em>rid</em> and <em>eid</em>, respectively. A value of
6720 * <code>-1</code> for either means to leave that ID unchanged. Not
6721 * available on all platforms.
6722 *
6723 */
6724
6725static VALUE
6726p_sys_setregid(VALUE obj, VALUE rid, VALUE eid)
6727{
6728 rb_gid_t rgid, egid;
6729 check_gid_switch();
6730 rgid = OBJ2GID(rid);
6731 egid = OBJ2GID(eid);
6732 if (setregid(rgid, egid) != 0) rb_sys_fail(0);
6733 return Qnil;
6734}
6735#else
6736#define p_sys_setregid rb_f_notimplement
6737#endif
6738
6739#if defined HAVE_SETRESGID
6740/*
6741 * call-seq:
6742 * Process::Sys.setresgid(rid, eid, sid) -> nil
6743 *
6744 * Sets the (group) real, effective, and saved user IDs of the
6745 * current process to <em>rid</em>, <em>eid</em>, and <em>sid</em>
6746 * respectively. A value of <code>-1</code> for any value means to
6747 * leave that ID unchanged. Not available on all platforms.
6748 *
6749 */
6750
6751static VALUE
6752p_sys_setresgid(VALUE obj, VALUE rid, VALUE eid, VALUE sid)
6753{
6754 rb_gid_t rgid, egid, sgid;
6755 check_gid_switch();
6756 rgid = OBJ2GID(rid);
6757 egid = OBJ2GID(eid);
6758 sgid = OBJ2GID(sid);
6759 if (setresgid(rgid, egid, sgid) != 0) rb_sys_fail(0);
6760 return Qnil;
6761}
6762#else
6763#define p_sys_setresgid rb_f_notimplement
6764#endif
6765
6766
6767#if defined HAVE_ISSETUGID
6768/*
6769 * call-seq:
6770 * Process::Sys.issetugid -> true or false
6771 *
6772 * Returns +true+ if the process was created as a result
6773 * of an execve(2) system call which had either of the setuid or
6774 * setgid bits set (and extra privileges were given as a result) or
6775 * if it has changed any of its real, effective or saved user or
6776 * group IDs since it began execution.
6777 *
6778 */
6779
6780static VALUE
6781p_sys_issetugid(VALUE obj)
6782{
6783 return RBOOL(issetugid());
6784}
6785#else
6786#define p_sys_issetugid rb_f_notimplement
6787#endif
6788
6789
6790/*
6791 * call-seq:
6792 * Process.gid -> integer
6793 * Process::GID.rid -> integer
6794 * Process::Sys.getgid -> integer
6795 *
6796 * Returns the (real) group ID for this process.
6797 *
6798 * Process.gid #=> 500
6799 */
6800
6801static VALUE
6802proc_getgid(VALUE obj)
6803{
6804 rb_gid_t gid = getgid();
6805 return GIDT2NUM(gid);
6806}
6807
6808
6809#if defined(HAVE_SETRESGID) || defined(HAVE_SETREGID) || defined(HAVE_SETRGID) || defined(HAVE_SETGID)
6810/*
6811 * call-seq:
6812 * Process.gid= integer -> integer
6813 *
6814 * Sets the group ID for this process.
6815 */
6816
6817static VALUE
6818proc_setgid(VALUE obj, VALUE id)
6819{
6820 rb_gid_t gid;
6821
6822 check_gid_switch();
6823
6824 gid = OBJ2GID(id);
6825#if defined(HAVE_SETRESGID)
6826 if (setresgid(gid, -1, -1) < 0) rb_sys_fail(0);
6827#elif defined HAVE_SETREGID
6828 if (setregid(gid, -1) < 0) rb_sys_fail(0);
6829#elif defined HAVE_SETRGID
6830 if (setrgid(gid) < 0) rb_sys_fail(0);
6831#elif defined HAVE_SETGID
6832 {
6833 if (getegid() == gid) {
6834 if (setgid(gid) < 0) rb_sys_fail(0);
6835 }
6836 else {
6838 }
6839 }
6840#endif
6841 return GIDT2NUM(gid);
6842}
6843#else
6844#define proc_setgid rb_f_notimplement
6845#endif
6846
6847
6848#if defined(_SC_NGROUPS_MAX) || defined(NGROUPS_MAX)
6849/*
6850 * Maximum supplementary groups are platform dependent.
6851 * FWIW, 65536 is enough big for our supported OSs.
6852 *
6853 * OS Name max groups
6854 * -----------------------------------------------
6855 * Linux Kernel >= 2.6.3 65536
6856 * Linux Kernel < 2.6.3 32
6857 * IBM AIX 5.2 64
6858 * IBM AIX 5.3 ... 6.1 128
6859 * IBM AIX 7.1 128 (can be configured to be up to 2048)
6860 * OpenBSD, NetBSD 16
6861 * FreeBSD < 8.0 16
6862 * FreeBSD >=8.0 1023
6863 * Darwin (Mac OS X) 16
6864 * Sun Solaris 7,8,9,10 16
6865 * Sun Solaris 11 / OpenSolaris 1024
6866 * Windows 1015
6867 */
6868static int _maxgroups = -1;
6869static int
6870get_sc_ngroups_max(void)
6871{
6872#ifdef _SC_NGROUPS_MAX
6873 return (int)sysconf(_SC_NGROUPS_MAX);
6874#elif defined(NGROUPS_MAX)
6875 return (int)NGROUPS_MAX;
6876#else
6877 return -1;
6878#endif
6879}
6880static int
6881maxgroups(void)
6882{
6883 if (_maxgroups < 0) {
6884 _maxgroups = get_sc_ngroups_max();
6885 if (_maxgroups < 0)
6886 _maxgroups = RB_MAX_GROUPS;
6887 }
6888
6889 return _maxgroups;
6890}
6891#endif
6892
6893
6894
6895#ifdef HAVE_GETGROUPS
6896/*
6897 * call-seq:
6898 * Process.groups -> array
6899 *
6900 * Get an Array of the group IDs in the
6901 * supplemental group access list for this process.
6902 *
6903 * Process.groups #=> [27, 6, 10, 11]
6904 *
6905 * Note that this method is just a wrapper of getgroups(2).
6906 * This means that the following characteristics of
6907 * the result completely depend on your system:
6908 *
6909 * - the result is sorted
6910 * - the result includes effective GIDs
6911 * - the result does not include duplicated GIDs
6912 * - the result size does not exceed the value of Process.maxgroups
6913 *
6914 * You can make sure to get a sorted unique GID list of
6915 * the current process by this expression:
6916 *
6917 * Process.groups.uniq.sort
6918 *
6919 */
6920
6921static VALUE
6922proc_getgroups(VALUE obj)
6923{
6924 VALUE ary, tmp;
6925 int i, ngroups;
6926 rb_gid_t *groups;
6927
6928 ngroups = getgroups(0, NULL);
6929 if (ngroups == -1)
6930 rb_sys_fail(0);
6931
6932 groups = ALLOCV_N(rb_gid_t, tmp, ngroups);
6933
6934 ngroups = getgroups(ngroups, groups);
6935 if (ngroups == -1)
6936 rb_sys_fail(0);
6937
6938 ary = rb_ary_new();
6939 for (i = 0; i < ngroups; i++)
6940 rb_ary_push(ary, GIDT2NUM(groups[i]));
6941
6942 ALLOCV_END(tmp);
6943
6944 return ary;
6945}
6946#else
6947#define proc_getgroups rb_f_notimplement
6948#endif
6949
6950
6951#ifdef HAVE_SETGROUPS
6952/*
6953 * call-seq:
6954 * Process.groups= array -> array
6955 *
6956 * Set the supplemental group access list to the given
6957 * Array of group IDs.
6958 *
6959 * Process.groups #=> [0, 1, 2, 3, 4, 6, 10, 11, 20, 26, 27]
6960 * Process.groups = [27, 6, 10, 11] #=> [27, 6, 10, 11]
6961 * Process.groups #=> [27, 6, 10, 11]
6962 *
6963 */
6964
6965static VALUE
6966proc_setgroups(VALUE obj, VALUE ary)
6967{
6968 int ngroups, i;
6969 rb_gid_t *groups;
6970 VALUE tmp;
6971 PREPARE_GETGRNAM;
6972
6973 Check_Type(ary, T_ARRAY);
6974
6975 ngroups = RARRAY_LENINT(ary);
6976 if (ngroups > maxgroups())
6977 rb_raise(rb_eArgError, "too many groups, %d max", maxgroups());
6978
6979 groups = ALLOCV_N(rb_gid_t, tmp, ngroups);
6980
6981 for (i = 0; i < ngroups; i++) {
6982 VALUE g = RARRAY_AREF(ary, i);
6983
6984 groups[i] = OBJ2GID1(g);
6985 }
6986 FINISH_GETGRNAM;
6987
6988 if (setgroups(ngroups, groups) == -1) /* ngroups <= maxgroups */
6989 rb_sys_fail(0);
6990
6991 ALLOCV_END(tmp);
6992
6993 return proc_getgroups(obj);
6994}
6995#else
6996#define proc_setgroups rb_f_notimplement
6997#endif
6998
6999
7000#ifdef HAVE_INITGROUPS
7001/*
7002 * call-seq:
7003 * Process.initgroups(username, gid) -> array
7004 *
7005 * Initializes the supplemental group access list by reading the
7006 * system group database and using all groups of which the given user
7007 * is a member. The group with the specified _gid_ is also added to
7008 * the list. Returns the resulting Array of the GIDs of all the
7009 * groups in the supplementary group access list. Not available on
7010 * all platforms.
7011 *
7012 * Process.groups #=> [0, 1, 2, 3, 4, 6, 10, 11, 20, 26, 27]
7013 * Process.initgroups( "mgranger", 30 ) #=> [30, 6, 10, 11]
7014 * Process.groups #=> [30, 6, 10, 11]
7015 *
7016 */
7017
7018static VALUE
7019proc_initgroups(VALUE obj, VALUE uname, VALUE base_grp)
7020{
7021 if (initgroups(StringValueCStr(uname), OBJ2GID(base_grp)) != 0) {
7022 rb_sys_fail(0);
7023 }
7024 return proc_getgroups(obj);
7025}
7026#else
7027#define proc_initgroups rb_f_notimplement
7028#endif
7029
7030#if defined(_SC_NGROUPS_MAX) || defined(NGROUPS_MAX)
7031/*
7032 * call-seq:
7033 * Process.maxgroups -> integer
7034 *
7035 * Returns the maximum number of GIDs allowed in the supplemental
7036 * group access list.
7037 *
7038 * Process.maxgroups #=> 32
7039 */
7040
7041static VALUE
7042proc_getmaxgroups(VALUE obj)
7043{
7044 return INT2FIX(maxgroups());
7045}
7046#else
7047#define proc_getmaxgroups rb_f_notimplement
7048#endif
7049
7050#ifdef HAVE_SETGROUPS
7051/*
7052 * call-seq:
7053 * Process.maxgroups= integer -> integer
7054 *
7055 * Sets the maximum number of GIDs allowed in the supplemental group
7056 * access list.
7057 */
7058
7059static VALUE
7060proc_setmaxgroups(VALUE obj, VALUE val)
7061{
7062 int ngroups = FIX2INT(val);
7063 int ngroups_max = get_sc_ngroups_max();
7064
7065 if (ngroups <= 0)
7066 rb_raise(rb_eArgError, "maxgroups %d should be positive", ngroups);
7067
7068 if (ngroups > RB_MAX_GROUPS)
7069 ngroups = RB_MAX_GROUPS;
7070
7071 if (ngroups_max > 0 && ngroups > ngroups_max)
7072 ngroups = ngroups_max;
7073
7074 _maxgroups = ngroups;
7075
7076 return INT2FIX(_maxgroups);
7077}
7078#else
7079#define proc_setmaxgroups rb_f_notimplement
7080#endif
7081
7082#if defined(HAVE_DAEMON) || (defined(HAVE_WORKING_FORK) && defined(HAVE_SETSID))
7083static int rb_daemon(int nochdir, int noclose);
7084
7085/*
7086 * call-seq:
7087 * Process.daemon() -> 0
7088 * Process.daemon(nochdir=nil,noclose=nil) -> 0
7089 *
7090 * Detach the process from controlling terminal and run in
7091 * the background as system daemon. Unless the argument
7092 * nochdir is true (i.e. non false), it changes the current
7093 * working directory to the root ("/"). Unless the argument
7094 * noclose is true, daemon() will redirect standard input,
7095 * standard output and standard error to /dev/null.
7096 * Return zero on success, or raise one of Errno::*.
7097 */
7098
7099static VALUE
7100proc_daemon(int argc, VALUE *argv, VALUE _)
7101{
7102 int n, nochdir = FALSE, noclose = FALSE;
7103
7104 switch (rb_check_arity(argc, 0, 2)) {
7105 case 2: noclose = TO_BOOL(argv[1], "noclose");
7106 case 1: nochdir = TO_BOOL(argv[0], "nochdir");
7107 }
7108
7109 prefork();
7110 n = rb_daemon(nochdir, noclose);
7111 if (n < 0) rb_sys_fail("daemon");
7112 return INT2FIX(n);
7113}
7114
7115static int
7116rb_daemon(int nochdir, int noclose)
7117{
7118 int err = 0;
7119#ifdef HAVE_DAEMON
7120 if (mjit_enabled) mjit_pause(false); // Don't leave locked mutex to child.
7121 before_fork_ruby();
7122 err = daemon(nochdir, noclose);
7123 after_fork_ruby();
7124 rb_thread_atfork(); /* calls mjit_resume() */
7125#else
7126 int n;
7127
7128 switch (rb_fork_ruby(NULL)) {
7129 case -1: return -1;
7130 case 0: break;
7131 default: _exit(EXIT_SUCCESS);
7132 }
7133
7134 /* ignore EPERM which means already being process-leader */
7135 if (setsid() < 0) (void)0;
7136
7137 if (!nochdir)
7138 err = chdir("/");
7139
7140 if (!noclose && (n = rb_cloexec_open("/dev/null", O_RDWR, 0)) != -1) {
7142 (void)dup2(n, 0);
7143 (void)dup2(n, 1);
7144 (void)dup2(n, 2);
7145 if (n > 2)
7146 (void)close (n);
7147 }
7148#endif
7149 return err;
7150}
7151#else
7152#define proc_daemon rb_f_notimplement
7153#endif
7154
7155/********************************************************************
7156 *
7157 * Document-class: Process::GID
7158 *
7159 * The Process::GID module contains a collection of
7160 * module functions which can be used to portably get, set, and
7161 * switch the current process's real, effective, and saved group IDs.
7162 *
7163 */
7164
7165static rb_gid_t SAVED_GROUP_ID = -1;
7166
7167#ifdef BROKEN_SETREGID
7168int
7169setregid(rb_gid_t rgid, rb_gid_t egid)
7170{
7171 if (rgid != (rb_gid_t)-1 && rgid != getgid()) {
7172 if (egid == (rb_gid_t)-1) egid = getegid();
7173 if (setgid(rgid) < 0) return -1;
7174 }
7175 if (egid != (rb_gid_t)-1 && egid != getegid()) {
7176 if (setegid(egid) < 0) return -1;
7177 }
7178 return 0;
7179}
7180#endif
7181
7182/*
7183 * call-seq:
7184 * Process::GID.change_privilege(group) -> integer
7185 *
7186 * Change the current process's real and effective group ID to that
7187 * specified by _group_. Returns the new group ID. Not
7188 * available on all platforms.
7189 *
7190 * [Process.gid, Process.egid] #=> [0, 0]
7191 * Process::GID.change_privilege(33) #=> 33
7192 * [Process.gid, Process.egid] #=> [33, 33]
7193 */
7194
7195static VALUE
7196p_gid_change_privilege(VALUE obj, VALUE id)
7197{
7198 rb_gid_t gid;
7199
7200 check_gid_switch();
7201
7202 gid = OBJ2GID(id);
7203
7204 if (geteuid() == 0) { /* root-user */
7205#if defined(HAVE_SETRESGID)
7206 if (setresgid(gid, gid, gid) < 0) rb_sys_fail(0);
7207 SAVED_GROUP_ID = gid;
7208#elif defined HAVE_SETGID
7209 if (setgid(gid) < 0) rb_sys_fail(0);
7210 SAVED_GROUP_ID = gid;
7211#elif defined(HAVE_SETREGID) && !defined(OBSOLETE_SETREGID)
7212 if (getgid() == gid) {
7213 if (SAVED_GROUP_ID == gid) {
7214 if (setregid(-1, gid) < 0) rb_sys_fail(0);
7215 }
7216 else {
7217 if (gid == 0) { /* (r,e,s) == (root, y, x) */
7218 if (setregid(-1, SAVED_GROUP_ID) < 0) rb_sys_fail(0);
7219 if (setregid(SAVED_GROUP_ID, 0) < 0) rb_sys_fail(0);
7220 SAVED_GROUP_ID = 0; /* (r,e,s) == (x, root, root) */
7221 if (setregid(gid, gid) < 0) rb_sys_fail(0);
7222 SAVED_GROUP_ID = gid;
7223 }
7224 else { /* (r,e,s) == (z, y, x) */
7225 if (setregid(0, 0) < 0) rb_sys_fail(0);
7226 SAVED_GROUP_ID = 0;
7227 if (setregid(gid, gid) < 0) rb_sys_fail(0);
7228 SAVED_GROUP_ID = gid;
7229 }
7230 }
7231 }
7232 else {
7233 if (setregid(gid, gid) < 0) rb_sys_fail(0);
7234 SAVED_GROUP_ID = gid;
7235 }
7236#elif defined(HAVE_SETRGID) && defined (HAVE_SETEGID)
7237 if (getgid() == gid) {
7238 if (SAVED_GROUP_ID == gid) {
7239 if (setegid(gid) < 0) rb_sys_fail(0);
7240 }
7241 else {
7242 if (gid == 0) {
7243 if (setegid(gid) < 0) rb_sys_fail(0);
7244 if (setrgid(SAVED_GROUP_ID) < 0) rb_sys_fail(0);
7245 SAVED_GROUP_ID = 0;
7246 if (setrgid(0) < 0) rb_sys_fail(0);
7247 }
7248 else {
7249 if (setrgid(0) < 0) rb_sys_fail(0);
7250 SAVED_GROUP_ID = 0;
7251 if (setegid(gid) < 0) rb_sys_fail(0);
7252 if (setrgid(gid) < 0) rb_sys_fail(0);
7253 SAVED_GROUP_ID = gid;
7254 }
7255 }
7256 }
7257 else {
7258 if (setegid(gid) < 0) rb_sys_fail(0);
7259 if (setrgid(gid) < 0) rb_sys_fail(0);
7260 SAVED_GROUP_ID = gid;
7261 }
7262#else
7264#endif
7265 }
7266 else { /* unprivileged user */
7267#if defined(HAVE_SETRESGID)
7268 if (setresgid((getgid() == gid)? (rb_gid_t)-1: gid,
7269 (getegid() == gid)? (rb_gid_t)-1: gid,
7270 (SAVED_GROUP_ID == gid)? (rb_gid_t)-1: gid) < 0) rb_sys_fail(0);
7271 SAVED_GROUP_ID = gid;
7272#elif defined(HAVE_SETREGID) && !defined(OBSOLETE_SETREGID)
7273 if (SAVED_GROUP_ID == gid) {
7274 if (setregid((getgid() == gid)? (rb_uid_t)-1: gid,
7275 (getegid() == gid)? (rb_uid_t)-1: gid) < 0)
7276 rb_sys_fail(0);
7277 }
7278 else if (getgid() != gid) {
7279 if (setregid(gid, (getegid() == gid)? (rb_uid_t)-1: gid) < 0)
7280 rb_sys_fail(0);
7281 SAVED_GROUP_ID = gid;
7282 }
7283 else if (/* getgid() == gid && */ getegid() != gid) {
7284 if (setregid(getegid(), gid) < 0) rb_sys_fail(0);
7285 SAVED_GROUP_ID = gid;
7286 if (setregid(gid, -1) < 0) rb_sys_fail(0);
7287 }
7288 else { /* getgid() == gid && getegid() == gid */
7289 if (setregid(-1, SAVED_GROUP_ID) < 0) rb_sys_fail(0);
7290 if (setregid(SAVED_GROUP_ID, gid) < 0) rb_sys_fail(0);
7291 SAVED_GROUP_ID = gid;
7292 if (setregid(gid, -1) < 0) rb_sys_fail(0);
7293 }
7294#elif defined(HAVE_SETRGID) && defined(HAVE_SETEGID)
7295 if (SAVED_GROUP_ID == gid) {
7296 if (getegid() != gid && setegid(gid) < 0) rb_sys_fail(0);
7297 if (getgid() != gid && setrgid(gid) < 0) rb_sys_fail(0);
7298 }
7299 else if (/* SAVED_GROUP_ID != gid && */ getegid() == gid) {
7300 if (getgid() != gid) {
7301 if (setrgid(gid) < 0) rb_sys_fail(0);
7302 SAVED_GROUP_ID = gid;
7303 }
7304 else {
7305 if (setrgid(SAVED_GROUP_ID) < 0) rb_sys_fail(0);
7306 SAVED_GROUP_ID = gid;
7307 if (setrgid(gid) < 0) rb_sys_fail(0);
7308 }
7309 }
7310 else if (/* getegid() != gid && */ getgid() == gid) {
7311 if (setegid(gid) < 0) rb_sys_fail(0);
7312 if (setrgid(SAVED_GROUP_ID) < 0) rb_sys_fail(0);
7313 SAVED_GROUP_ID = gid;
7314 if (setrgid(gid) < 0) rb_sys_fail(0);
7315 }
7316 else {
7317 rb_syserr_fail(EPERM, 0);
7318 }
7319#elif defined HAVE_44BSD_SETGID
7320 if (getgid() == gid) {
7321 /* (r,e,s)==(gid,?,?) ==> (gid,gid,gid) */
7322 if (setgid(gid) < 0) rb_sys_fail(0);
7323 SAVED_GROUP_ID = gid;
7324 }
7325 else {
7326 rb_syserr_fail(EPERM, 0);
7327 }
7328#elif defined HAVE_SETEGID
7329 if (getgid() == gid && SAVED_GROUP_ID == gid) {
7330 if (setegid(gid) < 0) rb_sys_fail(0);
7331 }
7332 else {
7333 rb_syserr_fail(EPERM, 0);
7334 }
7335#elif defined HAVE_SETGID
7336 if (getgid() == gid && SAVED_GROUP_ID == gid) {
7337 if (setgid(gid) < 0) rb_sys_fail(0);
7338 }
7339 else {
7340 rb_syserr_fail(EPERM, 0);
7341 }
7342#else
7343 (void)gid;
7345#endif
7346 }
7347 return id;
7348}
7349
7350
7351/*
7352 * call-seq:
7353 * Process.euid -> integer
7354 * Process::UID.eid -> integer
7355 * Process::Sys.geteuid -> integer
7356 *
7357 * Returns the effective user ID for this process.
7358 *
7359 * Process.euid #=> 501
7360 */
7361
7362static VALUE
7363proc_geteuid(VALUE obj)
7364{
7365 rb_uid_t euid = geteuid();
7366 return UIDT2NUM(euid);
7367}
7368
7369#if defined(HAVE_SETRESUID) || defined(HAVE_SETREUID) || defined(HAVE_SETEUID) || defined(HAVE_SETUID) || defined(_POSIX_SAVED_IDS)
7370static void
7371proc_seteuid(rb_uid_t uid)
7372{
7373#if defined(HAVE_SETRESUID)
7374 if (setresuid(-1, uid, -1) < 0) rb_sys_fail(0);
7375#elif defined HAVE_SETREUID
7376 if (setreuid(-1, uid) < 0) rb_sys_fail(0);
7377#elif defined HAVE_SETEUID
7378 if (seteuid(uid) < 0) rb_sys_fail(0);
7379#elif defined HAVE_SETUID
7380 if (uid == getuid()) {
7381 if (setuid(uid) < 0) rb_sys_fail(0);
7382 }
7383 else {
7385 }
7386#else
7388#endif
7389}
7390#endif
7391
7392#if defined(HAVE_SETRESUID) || defined(HAVE_SETREUID) || defined(HAVE_SETEUID) || defined(HAVE_SETUID)
7393/*
7394 * call-seq:
7395 * Process.euid= user
7396 *
7397 * Sets the effective user ID for this process. Not available on all
7398 * platforms.
7399 */
7400
7401static VALUE
7402proc_seteuid_m(VALUE mod, VALUE euid)
7403{
7404 check_uid_switch();
7405 proc_seteuid(OBJ2UID(euid));
7406 return euid;
7407}
7408#else
7409#define proc_seteuid_m rb_f_notimplement
7410#endif
7411
7412static rb_uid_t
7413rb_seteuid_core(rb_uid_t euid)
7414{
7415#if defined(HAVE_SETRESUID) || (defined(HAVE_SETREUID) && !defined(OBSOLETE_SETREUID))
7416 rb_uid_t uid;
7417#endif
7418
7419 check_uid_switch();
7420
7421#if defined(HAVE_SETRESUID) || (defined(HAVE_SETREUID) && !defined(OBSOLETE_SETREUID))
7422 uid = getuid();
7423#endif
7424
7425#if defined(HAVE_SETRESUID)
7426 if (uid != euid) {
7427 if (setresuid(-1,euid,euid) < 0) rb_sys_fail(0);
7428 SAVED_USER_ID = euid;
7429 }
7430 else {
7431 if (setresuid(-1,euid,-1) < 0) rb_sys_fail(0);
7432 }
7433#elif defined(HAVE_SETREUID) && !defined(OBSOLETE_SETREUID)
7434 if (setreuid(-1, euid) < 0) rb_sys_fail(0);
7435 if (uid != euid) {
7436 if (setreuid(euid,uid) < 0) rb_sys_fail(0);
7437 if (setreuid(uid,euid) < 0) rb_sys_fail(0);
7438 SAVED_USER_ID = euid;
7439 }
7440#elif defined HAVE_SETEUID
7441 if (seteuid(euid) < 0) rb_sys_fail(0);
7442#elif defined HAVE_SETUID
7443 if (geteuid() == 0) rb_sys_fail(0);
7444 if (setuid(euid) < 0) rb_sys_fail(0);
7445#else
7447#endif
7448 return euid;
7449}
7450
7451
7452/*
7453 * call-seq:
7454 * Process::UID.grant_privilege(user) -> integer
7455 * Process::UID.eid= user -> integer
7456 *
7457 * Set the effective user ID, and if possible, the saved user ID of
7458 * the process to the given _user_. Returns the new
7459 * effective user ID. Not available on all platforms.
7460 *
7461 * [Process.uid, Process.euid] #=> [0, 0]
7462 * Process::UID.grant_privilege(31) #=> 31
7463 * [Process.uid, Process.euid] #=> [0, 31]
7464 */
7465
7466static VALUE
7467p_uid_grant_privilege(VALUE obj, VALUE id)
7468{
7469 rb_seteuid_core(OBJ2UID(id));
7470 return id;
7471}
7472
7473
7474/*
7475 * call-seq:
7476 * Process.egid -> integer
7477 * Process::GID.eid -> integer
7478 * Process::Sys.geteid -> integer
7479 *
7480 * Returns the effective group ID for this process. Not available on
7481 * all platforms.
7482 *
7483 * Process.egid #=> 500
7484 */
7485
7486static VALUE
7487proc_getegid(VALUE obj)
7488{
7489 rb_gid_t egid = getegid();
7490
7491 return GIDT2NUM(egid);
7492}
7493
7494#if defined(HAVE_SETRESGID) || defined(HAVE_SETREGID) || defined(HAVE_SETEGID) || defined(HAVE_SETGID) || defined(_POSIX_SAVED_IDS)
7495/*
7496 * call-seq:
7497 * Process.egid = integer -> integer
7498 *
7499 * Sets the effective group ID for this process. Not available on all
7500 * platforms.
7501 */
7502
7503static VALUE
7504proc_setegid(VALUE obj, VALUE egid)
7505{
7506#if defined(HAVE_SETRESGID) || defined(HAVE_SETREGID) || defined(HAVE_SETEGID) || defined(HAVE_SETGID)
7507 rb_gid_t gid;
7508#endif
7509
7510 check_gid_switch();
7511
7512#if defined(HAVE_SETRESGID) || defined(HAVE_SETREGID) || defined(HAVE_SETEGID) || defined(HAVE_SETGID)
7513 gid = OBJ2GID(egid);
7514#endif
7515
7516#if defined(HAVE_SETRESGID)
7517 if (setresgid(-1, gid, -1) < 0) rb_sys_fail(0);
7518#elif defined HAVE_SETREGID
7519 if (setregid(-1, gid) < 0) rb_sys_fail(0);
7520#elif defined HAVE_SETEGID
7521 if (setegid(gid) < 0) rb_sys_fail(0);
7522#elif defined HAVE_SETGID
7523 if (gid == getgid()) {
7524 if (setgid(gid) < 0) rb_sys_fail(0);
7525 }
7526 else {
7528 }
7529#else
7531#endif
7532 return egid;
7533}
7534#endif
7535
7536#if defined(HAVE_SETRESGID) || defined(HAVE_SETREGID) || defined(HAVE_SETEGID) || defined(HAVE_SETGID)
7537#define proc_setegid_m proc_setegid
7538#else
7539#define proc_setegid_m rb_f_notimplement
7540#endif
7541
7542static rb_gid_t
7543rb_setegid_core(rb_gid_t egid)
7544{
7545#if defined(HAVE_SETRESGID) || (defined(HAVE_SETREGID) && !defined(OBSOLETE_SETREGID))
7546 rb_gid_t gid;
7547#endif
7548
7549 check_gid_switch();
7550
7551#if defined(HAVE_SETRESGID) || (defined(HAVE_SETREGID) && !defined(OBSOLETE_SETREGID))
7552 gid = getgid();
7553#endif
7554
7555#if defined(HAVE_SETRESGID)
7556 if (gid != egid) {
7557 if (setresgid(-1,egid,egid) < 0) rb_sys_fail(0);
7558 SAVED_GROUP_ID = egid;
7559 }
7560 else {
7561 if (setresgid(-1,egid,-1) < 0) rb_sys_fail(0);
7562 }
7563#elif defined(HAVE_SETREGID) && !defined(OBSOLETE_SETREGID)
7564 if (setregid(-1, egid) < 0) rb_sys_fail(0);
7565 if (gid != egid) {
7566 if (setregid(egid,gid) < 0) rb_sys_fail(0);
7567 if (setregid(gid,egid) < 0) rb_sys_fail(0);
7568 SAVED_GROUP_ID = egid;
7569 }
7570#elif defined HAVE_SETEGID
7571 if (setegid(egid) < 0) rb_sys_fail(0);
7572#elif defined HAVE_SETGID
7573 if (geteuid() == 0 /* root user */) rb_sys_fail(0);
7574 if (setgid(egid) < 0) rb_sys_fail(0);
7575#else
7577#endif
7578 return egid;
7579}
7580
7581
7582/*
7583 * call-seq:
7584 * Process::GID.grant_privilege(group) -> integer
7585 * Process::GID.eid = group -> integer
7586 *
7587 * Set the effective group ID, and if possible, the saved group ID of
7588 * the process to the given _group_. Returns the new
7589 * effective group ID. Not available on all platforms.
7590 *
7591 * [Process.gid, Process.egid] #=> [0, 0]
7592 * Process::GID.grant_privilege(31) #=> 33
7593 * [Process.gid, Process.egid] #=> [0, 33]
7594 */
7595
7596static VALUE
7597p_gid_grant_privilege(VALUE obj, VALUE id)
7598{
7599 rb_setegid_core(OBJ2GID(id));
7600 return id;
7601}
7602
7603
7604/*
7605 * call-seq:
7606 * Process::UID.re_exchangeable? -> true or false
7607 *
7608 * Returns +true+ if the real and effective user IDs of a
7609 * process may be exchanged on the current platform.
7610 *
7611 */
7612
7613static VALUE
7614p_uid_exchangeable(VALUE _)
7615{
7616#if defined(HAVE_SETRESUID)
7617 return Qtrue;
7618#elif defined(HAVE_SETREUID) && !defined(OBSOLETE_SETREUID)
7619 return Qtrue;
7620#else
7621 return Qfalse;
7622#endif
7623}
7624
7625
7626/*
7627 * call-seq:
7628 * Process::UID.re_exchange -> integer
7629 *
7630 * Exchange real and effective user IDs and return the new effective
7631 * user ID. Not available on all platforms.
7632 *
7633 * [Process.uid, Process.euid] #=> [0, 31]
7634 * Process::UID.re_exchange #=> 0
7635 * [Process.uid, Process.euid] #=> [31, 0]
7636 */
7637
7638static VALUE
7639p_uid_exchange(VALUE obj)
7640{
7641 rb_uid_t uid;
7642#if defined(HAVE_SETRESUID) || (defined(HAVE_SETREUID) && !defined(OBSOLETE_SETREUID))
7643 rb_uid_t euid;
7644#endif
7645
7646 check_uid_switch();
7647
7648 uid = getuid();
7649#if defined(HAVE_SETRESUID) || (defined(HAVE_SETREUID) && !defined(OBSOLETE_SETREUID))
7650 euid = geteuid();
7651#endif
7652
7653#if defined(HAVE_SETRESUID)
7654 if (setresuid(euid, uid, uid) < 0) rb_sys_fail(0);
7655 SAVED_USER_ID = uid;
7656#elif defined(HAVE_SETREUID) && !defined(OBSOLETE_SETREUID)
7657 if (setreuid(euid,uid) < 0) rb_sys_fail(0);
7658 SAVED_USER_ID = uid;
7659#else
7661#endif
7662 return UIDT2NUM(uid);
7663}
7664
7665
7666/*
7667 * call-seq:
7668 * Process::GID.re_exchangeable? -> true or false
7669 *
7670 * Returns +true+ if the real and effective group IDs of a
7671 * process may be exchanged on the current platform.
7672 *
7673 */
7674
7675static VALUE
7676p_gid_exchangeable(VALUE _)
7677{
7678#if defined(HAVE_SETRESGID)
7679 return Qtrue;
7680#elif defined(HAVE_SETREGID) && !defined(OBSOLETE_SETREGID)
7681 return Qtrue;
7682#else
7683 return Qfalse;
7684#endif
7685}
7686
7687
7688/*
7689 * call-seq:
7690 * Process::GID.re_exchange -> integer
7691 *
7692 * Exchange real and effective group IDs and return the new effective
7693 * group ID. Not available on all platforms.
7694 *
7695 * [Process.gid, Process.egid] #=> [0, 33]
7696 * Process::GID.re_exchange #=> 0
7697 * [Process.gid, Process.egid] #=> [33, 0]
7698 */
7699
7700static VALUE
7701p_gid_exchange(VALUE obj)
7702{
7703 rb_gid_t gid;
7704#if defined(HAVE_SETRESGID) || (defined(HAVE_SETREGID) && !defined(OBSOLETE_SETREGID))
7705 rb_gid_t egid;
7706#endif
7707
7708 check_gid_switch();
7709
7710 gid = getgid();
7711#if defined(HAVE_SETRESGID) || (defined(HAVE_SETREGID) && !defined(OBSOLETE_SETREGID))
7712 egid = getegid();
7713#endif
7714
7715#if defined(HAVE_SETRESGID)
7716 if (setresgid(egid, gid, gid) < 0) rb_sys_fail(0);
7717 SAVED_GROUP_ID = gid;
7718#elif defined(HAVE_SETREGID) && !defined(OBSOLETE_SETREGID)
7719 if (setregid(egid,gid) < 0) rb_sys_fail(0);
7720 SAVED_GROUP_ID = gid;
7721#else
7723#endif
7724 return GIDT2NUM(gid);
7725}
7726
7727/* [MG] :FIXME: Is this correct? I'm not sure how to phrase this. */
7728
7729/*
7730 * call-seq:
7731 * Process::UID.sid_available? -> true or false
7732 *
7733 * Returns +true+ if the current platform has saved user
7734 * ID functionality.
7735 *
7736 */
7737
7738static VALUE
7739p_uid_have_saved_id(VALUE _)
7740{
7741#if defined(HAVE_SETRESUID) || defined(HAVE_SETEUID) || defined(_POSIX_SAVED_IDS)
7742 return Qtrue;
7743#else
7744 return Qfalse;
7745#endif
7746}
7747
7748
7749#if defined(HAVE_SETRESUID) || defined(HAVE_SETEUID) || defined(_POSIX_SAVED_IDS)
7750static VALUE
7751p_uid_sw_ensure(VALUE i)
7752{
7753 rb_uid_t id = (rb_uid_t/* narrowing */)i;
7754 under_uid_switch = 0;
7755 id = rb_seteuid_core(id);
7756 return UIDT2NUM(id);
7757}
7758
7759
7760/*
7761 * call-seq:
7762 * Process::UID.switch -> integer
7763 * Process::UID.switch {|| block} -> object
7764 *
7765 * Switch the effective and real user IDs of the current process. If
7766 * a <em>block</em> is given, the user IDs will be switched back
7767 * after the block is executed. Returns the new effective user ID if
7768 * called without a block, and the return value of the block if one
7769 * is given.
7770 *
7771 */
7772
7773static VALUE
7774p_uid_switch(VALUE obj)
7775{
7776 rb_uid_t uid, euid;
7777
7778 check_uid_switch();
7779
7780 uid = getuid();
7781 euid = geteuid();
7782
7783 if (uid != euid) {
7784 proc_seteuid(uid);
7785 if (rb_block_given_p()) {
7786 under_uid_switch = 1;
7787 return rb_ensure(rb_yield, Qnil, p_uid_sw_ensure, SAVED_USER_ID);
7788 }
7789 else {
7790 return UIDT2NUM(euid);
7791 }
7792 }
7793 else if (euid != SAVED_USER_ID) {
7794 proc_seteuid(SAVED_USER_ID);
7795 if (rb_block_given_p()) {
7796 under_uid_switch = 1;
7797 return rb_ensure(rb_yield, Qnil, p_uid_sw_ensure, euid);
7798 }
7799 else {
7800 return UIDT2NUM(uid);
7801 }
7802 }
7803 else {
7804 rb_syserr_fail(EPERM, 0);
7805 }
7806
7808}
7809#else
7810static VALUE
7811p_uid_sw_ensure(VALUE obj)
7812{
7813 under_uid_switch = 0;
7814 return p_uid_exchange(obj);
7815}
7816
7817static VALUE
7818p_uid_switch(VALUE obj)
7819{
7820 rb_uid_t uid, euid;
7821
7822 check_uid_switch();
7823
7824 uid = getuid();
7825 euid = geteuid();
7826
7827 if (uid == euid) {
7828 rb_syserr_fail(EPERM, 0);
7829 }
7830 p_uid_exchange(obj);
7831 if (rb_block_given_p()) {
7832 under_uid_switch = 1;
7833 return rb_ensure(rb_yield, Qnil, p_uid_sw_ensure, obj);
7834 }
7835 else {
7836 return UIDT2NUM(euid);
7837 }
7838}
7839#endif
7840
7841
7842/* [MG] :FIXME: Is this correct? I'm not sure how to phrase this. */
7843
7844/*
7845 * call-seq:
7846 * Process::GID.sid_available? -> true or false
7847 *
7848 * Returns +true+ if the current platform has saved group
7849 * ID functionality.
7850 *
7851 */
7852
7853static VALUE
7854p_gid_have_saved_id(VALUE _)
7855{
7856#if defined(HAVE_SETRESGID) || defined(HAVE_SETEGID) || defined(_POSIX_SAVED_IDS)
7857 return Qtrue;
7858#else
7859 return Qfalse;
7860#endif
7861}
7862
7863#if defined(HAVE_SETRESGID) || defined(HAVE_SETEGID) || defined(_POSIX_SAVED_IDS)
7864static VALUE
7865p_gid_sw_ensure(VALUE i)
7866{
7867 rb_gid_t id = (rb_gid_t/* narrowing */)i;
7868 under_gid_switch = 0;
7869 id = rb_setegid_core(id);
7870 return GIDT2NUM(id);
7871}
7872
7873
7874/*
7875 * call-seq:
7876 * Process::GID.switch -> integer
7877 * Process::GID.switch {|| block} -> object
7878 *
7879 * Switch the effective and real group IDs of the current process. If
7880 * a <em>block</em> is given, the group IDs will be switched back
7881 * after the block is executed. Returns the new effective group ID if
7882 * called without a block, and the return value of the block if one
7883 * is given.
7884 *
7885 */
7886
7887static VALUE
7888p_gid_switch(VALUE obj)
7889{
7890 rb_gid_t gid, egid;
7891
7892 check_gid_switch();
7893
7894 gid = getgid();
7895 egid = getegid();
7896
7897 if (gid != egid) {
7898 proc_setegid(obj, GIDT2NUM(gid));
7899 if (rb_block_given_p()) {
7900 under_gid_switch = 1;
7901 return rb_ensure(rb_yield, Qnil, p_gid_sw_ensure, SAVED_GROUP_ID);
7902 }
7903 else {
7904 return GIDT2NUM(egid);
7905 }
7906 }
7907 else if (egid != SAVED_GROUP_ID) {
7908 proc_setegid(obj, GIDT2NUM(SAVED_GROUP_ID));
7909 if (rb_block_given_p()) {
7910 under_gid_switch = 1;
7911 return rb_ensure(rb_yield, Qnil, p_gid_sw_ensure, egid);
7912 }
7913 else {
7914 return GIDT2NUM(gid);
7915 }
7916 }
7917 else {
7918 rb_syserr_fail(EPERM, 0);
7919 }
7920
7922}
7923#else
7924static VALUE
7925p_gid_sw_ensure(VALUE obj)
7926{
7927 under_gid_switch = 0;
7928 return p_gid_exchange(obj);
7929}
7930
7931static VALUE
7932p_gid_switch(VALUE obj)
7933{
7934 rb_gid_t gid, egid;
7935
7936 check_gid_switch();
7937
7938 gid = getgid();
7939 egid = getegid();
7940
7941 if (gid == egid) {
7942 rb_syserr_fail(EPERM, 0);
7943 }
7944 p_gid_exchange(obj);
7945 if (rb_block_given_p()) {
7946 under_gid_switch = 1;
7947 return rb_ensure(rb_yield, Qnil, p_gid_sw_ensure, obj);
7948 }
7949 else {
7950 return GIDT2NUM(egid);
7951 }
7952}
7953#endif
7954
7955
7956#if defined(HAVE_TIMES)
7957static long
7958get_clk_tck(void)
7959{
7960#ifdef HAVE__SC_CLK_TCK
7961 return sysconf(_SC_CLK_TCK);
7962#elif defined CLK_TCK
7963 return CLK_TCK;
7964#elif defined HZ
7965 return HZ;
7966#else
7967 return 60;
7968#endif
7969}
7970
7971/*
7972 * call-seq:
7973 * Process.times -> aProcessTms
7974 *
7975 * Returns a <code>Tms</code> structure (see Process::Tms)
7976 * that contains user and system CPU times for this process,
7977 * and also for children processes.
7978 *
7979 * t = Process.times
7980 * [ t.utime, t.stime, t.cutime, t.cstime ] #=> [0.0, 0.02, 0.00, 0.00]
7981 */
7982
7983VALUE
7984rb_proc_times(VALUE obj)
7985{
7986 VALUE utime, stime, cutime, cstime, ret;
7987#if defined(RUSAGE_SELF) && defined(RUSAGE_CHILDREN)
7988 struct rusage usage_s, usage_c;
7989
7990 if (getrusage(RUSAGE_SELF, &usage_s) != 0 || getrusage(RUSAGE_CHILDREN, &usage_c) != 0)
7991 rb_sys_fail("getrusage");
7992 utime = DBL2NUM((double)usage_s.ru_utime.tv_sec + (double)usage_s.ru_utime.tv_usec/1e6);
7993 stime = DBL2NUM((double)usage_s.ru_stime.tv_sec + (double)usage_s.ru_stime.tv_usec/1e6);
7994 cutime = DBL2NUM((double)usage_c.ru_utime.tv_sec + (double)usage_c.ru_utime.tv_usec/1e6);
7995 cstime = DBL2NUM((double)usage_c.ru_stime.tv_sec + (double)usage_c.ru_stime.tv_usec/1e6);
7996#else
7997 const double hertz = (double)get_clk_tck();
7998 struct tms buf;
7999
8000 times(&buf);
8001 utime = DBL2NUM(buf.tms_utime / hertz);
8002 stime = DBL2NUM(buf.tms_stime / hertz);
8003 cutime = DBL2NUM(buf.tms_cutime / hertz);
8004 cstime = DBL2NUM(buf.tms_cstime / hertz);
8005#endif
8006 ret = rb_struct_new(rb_cProcessTms, utime, stime, cutime, cstime);
8007 RB_GC_GUARD(utime);
8008 RB_GC_GUARD(stime);
8009 RB_GC_GUARD(cutime);
8010 RB_GC_GUARD(cstime);
8011 return ret;
8012}
8013#else
8014#define rb_proc_times rb_f_notimplement
8015#endif
8016
8017#ifdef HAVE_LONG_LONG
8018typedef LONG_LONG timetick_int_t;
8019#define TIMETICK_INT_MIN LLONG_MIN
8020#define TIMETICK_INT_MAX LLONG_MAX
8021#define TIMETICK_INT2NUM(v) LL2NUM(v)
8022#define MUL_OVERFLOW_TIMETICK_P(a, b) MUL_OVERFLOW_LONG_LONG_P(a, b)
8023#else
8024typedef long timetick_int_t;
8025#define TIMETICK_INT_MIN LONG_MIN
8026#define TIMETICK_INT_MAX LONG_MAX
8027#define TIMETICK_INT2NUM(v) LONG2NUM(v)
8028#define MUL_OVERFLOW_TIMETICK_P(a, b) MUL_OVERFLOW_LONG_P(a, b)
8029#endif
8030
8031CONSTFUNC(static timetick_int_t gcd_timetick_int(timetick_int_t, timetick_int_t));
8032static timetick_int_t
8033gcd_timetick_int(timetick_int_t a, timetick_int_t b)
8034{
8035 timetick_int_t t;
8036
8037 if (a < b) {
8038 t = a;
8039 a = b;
8040 b = t;
8041 }
8042
8043 while (1) {
8044 t = a % b;
8045 if (t == 0)
8046 return b;
8047 a = b;
8048 b = t;
8049 }
8050}
8051
8052static void
8053reduce_fraction(timetick_int_t *np, timetick_int_t *dp)
8054{
8055 timetick_int_t gcd = gcd_timetick_int(*np, *dp);
8056 if (gcd != 1) {
8057 *np /= gcd;
8058 *dp /= gcd;
8059 }
8060}
8061
8062static void
8063reduce_factors(timetick_int_t *numerators, int num_numerators,
8064 timetick_int_t *denominators, int num_denominators)
8065{
8066 int i, j;
8067 for (i = 0; i < num_numerators; i++) {
8068 if (numerators[i] == 1)
8069 continue;
8070 for (j = 0; j < num_denominators; j++) {
8071 if (denominators[j] == 1)
8072 continue;
8073 reduce_fraction(&numerators[i], &denominators[j]);
8074 }
8075 }
8076}
8077
8078struct timetick {
8079 timetick_int_t giga_count;
8080 int32_t count; /* 0 .. 999999999 */
8081};
8082
8083static VALUE
8084timetick2dblnum(struct timetick *ttp,
8085 timetick_int_t *numerators, int num_numerators,
8086 timetick_int_t *denominators, int num_denominators)
8087{
8088 double d;
8089 int i;
8090
8091 reduce_factors(numerators, num_numerators,
8092 denominators, num_denominators);
8093
8094 d = ttp->giga_count * 1e9 + ttp->count;
8095
8096 for (i = 0; i < num_numerators; i++)
8097 d *= numerators[i];
8098 for (i = 0; i < num_denominators; i++)
8099 d /= denominators[i];
8100
8101 return DBL2NUM(d);
8102}
8103
8104static VALUE
8105timetick2dblnum_reciprocal(struct timetick *ttp,
8106 timetick_int_t *numerators, int num_numerators,
8107 timetick_int_t *denominators, int num_denominators)
8108{
8109 double d;
8110 int i;
8111
8112 reduce_factors(numerators, num_numerators,
8113 denominators, num_denominators);
8114
8115 d = 1.0;
8116 for (i = 0; i < num_denominators; i++)
8117 d *= denominators[i];
8118 for (i = 0; i < num_numerators; i++)
8119 d /= numerators[i];
8120 d /= ttp->giga_count * 1e9 + ttp->count;
8121
8122 return DBL2NUM(d);
8123}
8124
8125#define NDIV(x,y) (-(-((x)+1)/(y))-1)
8126#define DIV(n,d) ((n)<0 ? NDIV((n),(d)) : (n)/(d))
8127
8128static VALUE
8129timetick2integer(struct timetick *ttp,
8130 timetick_int_t *numerators, int num_numerators,
8131 timetick_int_t *denominators, int num_denominators)
8132{
8133 VALUE v;
8134 int i;
8135
8136 reduce_factors(numerators, num_numerators,
8137 denominators, num_denominators);
8138
8139 if (!MUL_OVERFLOW_SIGNED_INTEGER_P(1000000000, ttp->giga_count,
8140 TIMETICK_INT_MIN, TIMETICK_INT_MAX-ttp->count)) {
8141 timetick_int_t t = ttp->giga_count * 1000000000 + ttp->count;
8142 for (i = 0; i < num_numerators; i++) {
8143 timetick_int_t factor = numerators[i];
8144 if (MUL_OVERFLOW_TIMETICK_P(factor, t))
8145 goto generic;
8146 t *= factor;
8147 }
8148 for (i = 0; i < num_denominators; i++) {
8149 t = DIV(t, denominators[i]);
8150 }
8151 return TIMETICK_INT2NUM(t);
8152 }
8153
8154 generic:
8155 v = TIMETICK_INT2NUM(ttp->giga_count);
8156 v = rb_funcall(v, '*', 1, LONG2FIX(1000000000));
8157 v = rb_funcall(v, '+', 1, LONG2FIX(ttp->count));
8158 for (i = 0; i < num_numerators; i++) {
8159 timetick_int_t factor = numerators[i];
8160 if (factor == 1)
8161 continue;
8162 v = rb_funcall(v, '*', 1, TIMETICK_INT2NUM(factor));
8163 }
8164 for (i = 0; i < num_denominators; i++) {
8165 v = rb_funcall(v, '/', 1, TIMETICK_INT2NUM(denominators[i])); /* Ruby's '/' is div. */
8166 }
8167 return v;
8168}
8169
8170static VALUE
8171make_clock_result(struct timetick *ttp,
8172 timetick_int_t *numerators, int num_numerators,
8173 timetick_int_t *denominators, int num_denominators,
8174 VALUE unit)
8175{
8176 if (unit == ID2SYM(id_nanosecond)) {
8177 numerators[num_numerators++] = 1000000000;
8178 return timetick2integer(ttp, numerators, num_numerators, denominators, num_denominators);
8179 }
8180 else if (unit == ID2SYM(id_microsecond)) {
8181 numerators[num_numerators++] = 1000000;
8182 return timetick2integer(ttp, numerators, num_numerators, denominators, num_denominators);
8183 }
8184 else if (unit == ID2SYM(id_millisecond)) {
8185 numerators[num_numerators++] = 1000;
8186 return timetick2integer(ttp, numerators, num_numerators, denominators, num_denominators);
8187 }
8188 else if (unit == ID2SYM(id_second)) {
8189 return timetick2integer(ttp, numerators, num_numerators, denominators, num_denominators);
8190 }
8191 else if (unit == ID2SYM(id_float_microsecond)) {
8192 numerators[num_numerators++] = 1000000;
8193 return timetick2dblnum(ttp, numerators, num_numerators, denominators, num_denominators);
8194 }
8195 else if (unit == ID2SYM(id_float_millisecond)) {
8196 numerators[num_numerators++] = 1000;
8197 return timetick2dblnum(ttp, numerators, num_numerators, denominators, num_denominators);
8198 }
8199 else if (NIL_P(unit) || unit == ID2SYM(id_float_second)) {
8200 return timetick2dblnum(ttp, numerators, num_numerators, denominators, num_denominators);
8201 }
8202 else
8203 rb_raise(rb_eArgError, "unexpected unit: %"PRIsVALUE, unit);
8204}
8205
8206#ifdef __APPLE__
8207static const mach_timebase_info_data_t *
8208get_mach_timebase_info(void)
8209{
8210 static mach_timebase_info_data_t sTimebaseInfo;
8211
8212 if ( sTimebaseInfo.denom == 0 ) {
8213 (void) mach_timebase_info(&sTimebaseInfo);
8214 }
8215
8216 return &sTimebaseInfo;
8217}
8218
8219double
8220ruby_real_ms_time(void)
8221{
8222 const mach_timebase_info_data_t *info = get_mach_timebase_info();
8223 uint64_t t = mach_absolute_time();
8224 return (double)t * info->numer / info->denom / 1e6;
8225}
8226#endif
8227
8228#if defined(NUM2CLOCKID)
8229# define NUMERIC_CLOCKID 1
8230#else
8231# define NUMERIC_CLOCKID 0
8232# define NUM2CLOCKID(x) 0
8233#endif
8234
8235/*
8236 * call-seq:
8237 * Process.clock_gettime(clock_id [, unit]) -> number
8238 *
8239 * Returns a time returned by POSIX clock_gettime() function.
8240 *
8241 * p Process.clock_gettime(Process::CLOCK_MONOTONIC)
8242 * #=> 896053.968060096
8243 *
8244 * +clock_id+ specifies a kind of clock.
8245 * It is specified as a constant which begins with <code>Process::CLOCK_</code>
8246 * such as Process::CLOCK_REALTIME and Process::CLOCK_MONOTONIC.
8247 *
8248 * The supported constants depends on OS and version.
8249 * Ruby provides following types of +clock_id+ if available.
8250 *
8251 * [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
8252 * [CLOCK_MONOTONIC] SUSv3 to 4, Linux 2.5.63, FreeBSD 3.0, NetBSD 2.0, OpenBSD 3.4, macOS 10.12, Windows-2000
8253 * [CLOCK_PROCESS_CPUTIME_ID] SUSv3 to 4, Linux 2.5.63, FreeBSD 9.3, OpenBSD 5.4, macOS 10.12
8254 * [CLOCK_THREAD_CPUTIME_ID] SUSv3 to 4, Linux 2.5.63, FreeBSD 7.1, OpenBSD 5.4, macOS 10.12
8255 * [CLOCK_VIRTUAL] FreeBSD 3.0, OpenBSD 2.1
8256 * [CLOCK_PROF] FreeBSD 3.0, OpenBSD 2.1
8257 * [CLOCK_REALTIME_FAST] FreeBSD 8.1
8258 * [CLOCK_REALTIME_PRECISE] FreeBSD 8.1
8259 * [CLOCK_REALTIME_COARSE] Linux 2.6.32
8260 * [CLOCK_REALTIME_ALARM] Linux 3.0
8261 * [CLOCK_MONOTONIC_FAST] FreeBSD 8.1
8262 * [CLOCK_MONOTONIC_PRECISE] FreeBSD 8.1
8263 * [CLOCK_MONOTONIC_COARSE] Linux 2.6.32
8264 * [CLOCK_MONOTONIC_RAW] Linux 2.6.28, macOS 10.12
8265 * [CLOCK_MONOTONIC_RAW_APPROX] macOS 10.12
8266 * [CLOCK_BOOTTIME] Linux 2.6.39
8267 * [CLOCK_BOOTTIME_ALARM] Linux 3.0
8268 * [CLOCK_UPTIME] FreeBSD 7.0, OpenBSD 5.5
8269 * [CLOCK_UPTIME_FAST] FreeBSD 8.1
8270 * [CLOCK_UPTIME_RAW] macOS 10.12
8271 * [CLOCK_UPTIME_RAW_APPROX] macOS 10.12
8272 * [CLOCK_UPTIME_PRECISE] FreeBSD 8.1
8273 * [CLOCK_SECOND] FreeBSD 8.1
8274 * [CLOCK_TAI] Linux 3.10
8275 *
8276 * Note that SUS stands for Single Unix Specification.
8277 * SUS contains POSIX and clock_gettime is defined in the POSIX part.
8278 * SUS defines CLOCK_REALTIME mandatory but
8279 * CLOCK_MONOTONIC, CLOCK_PROCESS_CPUTIME_ID and CLOCK_THREAD_CPUTIME_ID are optional.
8280 *
8281 * Also, several symbols are accepted as +clock_id+.
8282 * There are emulations for clock_gettime().
8283 *
8284 * For example, Process::CLOCK_REALTIME is defined as
8285 * +:GETTIMEOFDAY_BASED_CLOCK_REALTIME+ when clock_gettime() is not available.
8286 *
8287 * Emulations for +CLOCK_REALTIME+:
8288 * [:GETTIMEOFDAY_BASED_CLOCK_REALTIME]
8289 * Use gettimeofday() defined by SUS.
8290 * (SUSv4 obsoleted it, though.)
8291 * The resolution is 1 microsecond.
8292 * [:TIME_BASED_CLOCK_REALTIME]
8293 * Use time() defined by ISO C.
8294 * The resolution is 1 second.
8295 *
8296 * Emulations for +CLOCK_MONOTONIC+:
8297 * [:MACH_ABSOLUTE_TIME_BASED_CLOCK_MONOTONIC]
8298 * Use mach_absolute_time(), available on Darwin.
8299 * The resolution is CPU dependent.
8300 * [:TIMES_BASED_CLOCK_MONOTONIC]
8301 * Use the result value of times() defined by POSIX.
8302 * 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)".
8303 * For example, GNU/Linux returns a value based on jiffies and it is monotonic.
8304 * However, 4.4BSD uses gettimeofday() and it is not monotonic.
8305 * (FreeBSD uses clock_gettime(CLOCK_MONOTONIC) instead, though.)
8306 * The resolution is the clock tick.
8307 * "getconf CLK_TCK" command shows the clock ticks per second.
8308 * (The clock ticks per second is defined by HZ macro in older systems.)
8309 * If it is 100 and clock_t is 32 bits integer type, the resolution is 10 millisecond and
8310 * cannot represent over 497 days.
8311 *
8312 * Emulations for +CLOCK_PROCESS_CPUTIME_ID+:
8313 * [:GETRUSAGE_BASED_CLOCK_PROCESS_CPUTIME_ID]
8314 * Use getrusage() defined by SUS.
8315 * getrusage() is used with RUSAGE_SELF to obtain the time only for
8316 * the calling process (excluding the time for child processes).
8317 * The result is addition of user time (ru_utime) and system time (ru_stime).
8318 * The resolution is 1 microsecond.
8319 * [:TIMES_BASED_CLOCK_PROCESS_CPUTIME_ID]
8320 * Use times() defined by POSIX.
8321 * The result is addition of user time (tms_utime) and system time (tms_stime).
8322 * tms_cutime and tms_cstime are ignored to exclude the time for child processes.
8323 * The resolution is the clock tick.
8324 * "getconf CLK_TCK" command shows the clock ticks per second.
8325 * (The clock ticks per second is defined by HZ macro in older systems.)
8326 * If it is 100, the resolution is 10 millisecond.
8327 * [:CLOCK_BASED_CLOCK_PROCESS_CPUTIME_ID]
8328 * Use clock() defined by ISO C.
8329 * The resolution is 1/CLOCKS_PER_SEC.
8330 * CLOCKS_PER_SEC is the C-level macro defined by time.h.
8331 * SUS defines CLOCKS_PER_SEC is 1000000.
8332 * Non-Unix systems may define it a different value, though.
8333 * If CLOCKS_PER_SEC is 1000000 as SUS, the resolution is 1 microsecond.
8334 * If CLOCKS_PER_SEC is 1000000 and clock_t is 32 bits integer type, it cannot represent over 72 minutes.
8335 *
8336 * If the given +clock_id+ is not supported, Errno::EINVAL is raised.
8337 *
8338 * +unit+ specifies a type of the return value.
8339 *
8340 * [:float_second] number of seconds as a float (default)
8341 * [:float_millisecond] number of milliseconds as a float
8342 * [:float_microsecond] number of microseconds as a float
8343 * [:second] number of seconds as an integer
8344 * [:millisecond] number of milliseconds as an integer
8345 * [:microsecond] number of microseconds as an integer
8346 * [:nanosecond] number of nanoseconds as an integer
8347 *
8348 * The underlying function, clock_gettime(), returns a number of nanoseconds.
8349 * Float object (IEEE 754 double) is not enough to represent
8350 * the return value for CLOCK_REALTIME.
8351 * If the exact nanoseconds value is required, use +:nanosecond+ as the +unit+.
8352 *
8353 * The origin (zero) of the returned value varies.
8354 * For example, system start up time, process start up time, the Epoch, etc.
8355 *
8356 * The origin in CLOCK_REALTIME is defined as the Epoch
8357 * (1970-01-01 00:00:00 UTC).
8358 * But some systems count leap seconds and others doesn't.
8359 * So the result can be interpreted differently across systems.
8360 * Time.now is recommended over CLOCK_REALTIME.
8361 */
8362static VALUE
8363rb_clock_gettime(int argc, VALUE *argv, VALUE _)
8364{
8365 int ret;
8366
8367 struct timetick tt;
8368 timetick_int_t numerators[2];
8369 timetick_int_t denominators[2];
8370 int num_numerators = 0;
8371 int num_denominators = 0;
8372
8373 VALUE unit = (rb_check_arity(argc, 1, 2) == 2) ? argv[1] : Qnil;
8374 VALUE clk_id = argv[0];
8375#ifdef HAVE_CLOCK_GETTIME
8376 clockid_t c;
8377#endif
8378
8379 if (SYMBOL_P(clk_id)) {
8380#ifdef CLOCK_REALTIME
8381 if (clk_id == RUBY_CLOCK_REALTIME) {
8382 c = CLOCK_REALTIME;
8383 goto gettime;
8384 }
8385#endif
8386
8387#ifdef CLOCK_MONOTONIC
8388 if (clk_id == RUBY_CLOCK_MONOTONIC) {
8389 c = CLOCK_MONOTONIC;
8390 goto gettime;
8391 }
8392#endif
8393
8394#ifdef CLOCK_PROCESS_CPUTIME_ID
8395 if (clk_id == RUBY_CLOCK_PROCESS_CPUTIME_ID) {
8396 c = CLOCK_PROCESS_CPUTIME_ID;
8397 goto gettime;
8398 }
8399#endif
8400
8401#ifdef CLOCK_THREAD_CPUTIME_ID
8402 if (clk_id == RUBY_CLOCK_THREAD_CPUTIME_ID) {
8403 c = CLOCK_THREAD_CPUTIME_ID;
8404 goto gettime;
8405 }
8406#endif
8407
8408 /*
8409 * Non-clock_gettime clocks are provided by symbol clk_id.
8410 */
8411#ifdef HAVE_GETTIMEOFDAY
8412 /*
8413 * GETTIMEOFDAY_BASED_CLOCK_REALTIME is used for
8414 * CLOCK_REALTIME if clock_gettime is not available.
8415 */
8416#define RUBY_GETTIMEOFDAY_BASED_CLOCK_REALTIME ID2SYM(id_GETTIMEOFDAY_BASED_CLOCK_REALTIME)
8417 if (clk_id == RUBY_GETTIMEOFDAY_BASED_CLOCK_REALTIME) {
8418 struct timeval tv;
8419 ret = gettimeofday(&tv, 0);
8420 if (ret != 0)
8421 rb_sys_fail("gettimeofday");
8422 tt.giga_count = tv.tv_sec;
8423 tt.count = (int32_t)tv.tv_usec * 1000;
8424 denominators[num_denominators++] = 1000000000;
8425 goto success;
8426 }
8427#endif
8428
8429#define RUBY_TIME_BASED_CLOCK_REALTIME ID2SYM(id_TIME_BASED_CLOCK_REALTIME)
8430 if (clk_id == RUBY_TIME_BASED_CLOCK_REALTIME) {
8431 time_t t;
8432 t = time(NULL);
8433 if (t == (time_t)-1)
8434 rb_sys_fail("time");
8435 tt.giga_count = t;
8436 tt.count = 0;
8437 denominators[num_denominators++] = 1000000000;
8438 goto success;
8439 }
8440
8441#ifdef HAVE_TIMES
8442#define RUBY_TIMES_BASED_CLOCK_MONOTONIC \
8443 ID2SYM(id_TIMES_BASED_CLOCK_MONOTONIC)
8444 if (clk_id == RUBY_TIMES_BASED_CLOCK_MONOTONIC) {
8445 struct tms buf;
8446 clock_t c;
8447 unsigned_clock_t uc;
8448 c = times(&buf);
8449 if (c == (clock_t)-1)
8450 rb_sys_fail("times");
8451 uc = (unsigned_clock_t)c;
8452 tt.count = (int32_t)(uc % 1000000000);
8453 tt.giga_count = (uc / 1000000000);
8454 denominators[num_denominators++] = get_clk_tck();
8455 goto success;
8456 }
8457#endif
8458
8459#ifdef RUSAGE_SELF
8460#define RUBY_GETRUSAGE_BASED_CLOCK_PROCESS_CPUTIME_ID \
8461 ID2SYM(id_GETRUSAGE_BASED_CLOCK_PROCESS_CPUTIME_ID)
8462 if (clk_id == RUBY_GETRUSAGE_BASED_CLOCK_PROCESS_CPUTIME_ID) {
8463 struct rusage usage;
8464 int32_t usec;
8465 ret = getrusage(RUSAGE_SELF, &usage);
8466 if (ret != 0)
8467 rb_sys_fail("getrusage");
8468 tt.giga_count = usage.ru_utime.tv_sec + usage.ru_stime.tv_sec;
8469 usec = (int32_t)(usage.ru_utime.tv_usec + usage.ru_stime.tv_usec);
8470 if (1000000 <= usec) {
8471 tt.giga_count++;
8472 usec -= 1000000;
8473 }
8474 tt.count = usec * 1000;
8475 denominators[num_denominators++] = 1000000000;
8476 goto success;
8477 }
8478#endif
8479
8480#ifdef HAVE_TIMES
8481#define RUBY_TIMES_BASED_CLOCK_PROCESS_CPUTIME_ID \
8482 ID2SYM(id_TIMES_BASED_CLOCK_PROCESS_CPUTIME_ID)
8483 if (clk_id == RUBY_TIMES_BASED_CLOCK_PROCESS_CPUTIME_ID) {
8484 struct tms buf;
8485 unsigned_clock_t utime, stime;
8486 if (times(&buf) == (clock_t)-1)
8487 rb_sys_fail("times");
8488 utime = (unsigned_clock_t)buf.tms_utime;
8489 stime = (unsigned_clock_t)buf.tms_stime;
8490 tt.count = (int32_t)((utime % 1000000000) + (stime % 1000000000));
8491 tt.giga_count = (utime / 1000000000) + (stime / 1000000000);
8492 if (1000000000 <= tt.count) {
8493 tt.count -= 1000000000;
8494 tt.giga_count++;
8495 }
8496 denominators[num_denominators++] = get_clk_tck();
8497 goto success;
8498 }
8499#endif
8500
8501#define RUBY_CLOCK_BASED_CLOCK_PROCESS_CPUTIME_ID \
8502 ID2SYM(id_CLOCK_BASED_CLOCK_PROCESS_CPUTIME_ID)
8503 if (clk_id == RUBY_CLOCK_BASED_CLOCK_PROCESS_CPUTIME_ID) {
8504 clock_t c;
8505 unsigned_clock_t uc;
8506 errno = 0;
8507 c = clock();
8508 if (c == (clock_t)-1)
8509 rb_sys_fail("clock");
8510 uc = (unsigned_clock_t)c;
8511 tt.count = (int32_t)(uc % 1000000000);
8512 tt.giga_count = uc / 1000000000;
8513 denominators[num_denominators++] = CLOCKS_PER_SEC;
8514 goto success;
8515 }
8516
8517#ifdef __APPLE__
8518 if (clk_id == RUBY_MACH_ABSOLUTE_TIME_BASED_CLOCK_MONOTONIC) {
8519 const mach_timebase_info_data_t *info = get_mach_timebase_info();
8520 uint64_t t = mach_absolute_time();
8521 tt.count = (int32_t)(t % 1000000000);
8522 tt.giga_count = t / 1000000000;
8523 numerators[num_numerators++] = info->numer;
8524 denominators[num_denominators++] = info->denom;
8525 denominators[num_denominators++] = 1000000000;
8526 goto success;
8527 }
8528#endif
8529 }
8530 else if (NUMERIC_CLOCKID) {
8531#if defined(HAVE_CLOCK_GETTIME)
8532 struct timespec ts;
8533 c = NUM2CLOCKID(clk_id);
8534 gettime:
8535 ret = clock_gettime(c, &ts);
8536 if (ret == -1)
8537 rb_sys_fail("clock_gettime");
8538 tt.count = (int32_t)ts.tv_nsec;
8539 tt.giga_count = ts.tv_sec;
8540 denominators[num_denominators++] = 1000000000;
8541 goto success;
8542#endif
8543 }
8544 /* EINVAL emulates clock_gettime behavior when clock_id is invalid. */
8545 rb_syserr_fail(EINVAL, 0);
8546
8547 success:
8548 return make_clock_result(&tt, numerators, num_numerators, denominators, num_denominators, unit);
8549}
8550
8551/*
8552 * call-seq:
8553 * Process.clock_getres(clock_id [, unit]) -> number
8554 *
8555 * Returns an estimate of the resolution of a +clock_id+ using the POSIX
8556 * <code>clock_getres()</code> function.
8557 *
8558 * Note the reported resolution is often inaccurate on most platforms due to
8559 * underlying bugs for this function and therefore the reported resolution
8560 * often differs from the actual resolution of the clock in practice.
8561 * Inaccurate reported resolutions have been observed for various clocks including
8562 * CLOCK_MONOTONIC and CLOCK_MONOTONIC_RAW when using Linux, macOS, BSD or AIX
8563 * platforms, when using ARM processors, or when using virtualization.
8564 *
8565 * +clock_id+ specifies a kind of clock.
8566 * See the document of +Process.clock_gettime+ for details.
8567 * +clock_id+ can be a symbol as for +Process.clock_gettime+.
8568 *
8569 * If the given +clock_id+ is not supported, Errno::EINVAL is raised.
8570 *
8571 * +unit+ specifies the type of the return value.
8572 * +Process.clock_getres+ accepts +unit+ as +Process.clock_gettime+.
8573 * The default value, +:float_second+, is also the same as
8574 * +Process.clock_gettime+.
8575 *
8576 * +Process.clock_getres+ also accepts +:hertz+ as +unit+.
8577 * +:hertz+ means the reciprocal of +:float_second+.
8578 *
8579 * +:hertz+ can be used to obtain the exact value of
8580 * the clock ticks per second for the times() function and
8581 * CLOCKS_PER_SEC for the clock() function.
8582 *
8583 * <code>Process.clock_getres(:TIMES_BASED_CLOCK_PROCESS_CPUTIME_ID, :hertz)</code>
8584 * returns the clock ticks per second.
8585 *
8586 * <code>Process.clock_getres(:CLOCK_BASED_CLOCK_PROCESS_CPUTIME_ID, :hertz)</code>
8587 * returns CLOCKS_PER_SEC.
8588 *
8589 * p Process.clock_getres(Process::CLOCK_MONOTONIC)
8590 * #=> 1.0e-09
8591 *
8592 */
8593static VALUE
8594rb_clock_getres(int argc, VALUE *argv, VALUE _)
8595{
8596 int ret;
8597
8598 struct timetick tt;
8599 timetick_int_t numerators[2];
8600 timetick_int_t denominators[2];
8601 int num_numerators = 0;
8602 int num_denominators = 0;
8603#ifdef HAVE_CLOCK_GETRES
8604 clockid_t c;
8605#endif
8606
8607 VALUE unit = (rb_check_arity(argc, 1, 2) == 2) ? argv[1] : Qnil;
8608 VALUE clk_id = argv[0];
8609
8610 if (SYMBOL_P(clk_id)) {
8611#ifdef CLOCK_REALTIME
8612 if (clk_id == RUBY_CLOCK_REALTIME) {
8613 c = CLOCK_REALTIME;
8614 goto getres;
8615 }
8616#endif
8617
8618#ifdef CLOCK_MONOTONIC
8619 if (clk_id == RUBY_CLOCK_MONOTONIC) {
8620 c = CLOCK_MONOTONIC;
8621 goto getres;
8622 }
8623#endif
8624
8625#ifdef CLOCK_PROCESS_CPUTIME_ID
8626 if (clk_id == RUBY_CLOCK_PROCESS_CPUTIME_ID) {
8627 c = CLOCK_PROCESS_CPUTIME_ID;
8628 goto getres;
8629 }
8630#endif
8631
8632#ifdef CLOCK_THREAD_CPUTIME_ID
8633 if (clk_id == RUBY_CLOCK_THREAD_CPUTIME_ID) {
8634 c = CLOCK_THREAD_CPUTIME_ID;
8635 goto getres;
8636 }
8637#endif
8638
8639#ifdef RUBY_GETTIMEOFDAY_BASED_CLOCK_REALTIME
8640 if (clk_id == RUBY_GETTIMEOFDAY_BASED_CLOCK_REALTIME) {
8641 tt.giga_count = 0;
8642 tt.count = 1000;
8643 denominators[num_denominators++] = 1000000000;
8644 goto success;
8645 }
8646#endif
8647
8648#ifdef RUBY_TIME_BASED_CLOCK_REALTIME
8649 if (clk_id == RUBY_TIME_BASED_CLOCK_REALTIME) {
8650 tt.giga_count = 1;
8651 tt.count = 0;
8652 denominators[num_denominators++] = 1000000000;
8653 goto success;
8654 }
8655#endif
8656
8657#ifdef RUBY_TIMES_BASED_CLOCK_MONOTONIC
8658 if (clk_id == RUBY_TIMES_BASED_CLOCK_MONOTONIC) {
8659 tt.count = 1;
8660 tt.giga_count = 0;
8661 denominators[num_denominators++] = get_clk_tck();
8662 goto success;
8663 }
8664#endif
8665
8666#ifdef RUBY_GETRUSAGE_BASED_CLOCK_PROCESS_CPUTIME_ID
8667 if (clk_id == RUBY_GETRUSAGE_BASED_CLOCK_PROCESS_CPUTIME_ID) {
8668 tt.giga_count = 0;
8669 tt.count = 1000;
8670 denominators[num_denominators++] = 1000000000;
8671 goto success;
8672 }
8673#endif
8674
8675#ifdef RUBY_TIMES_BASED_CLOCK_PROCESS_CPUTIME_ID
8676 if (clk_id == RUBY_TIMES_BASED_CLOCK_PROCESS_CPUTIME_ID) {
8677 tt.count = 1;
8678 tt.giga_count = 0;
8679 denominators[num_denominators++] = get_clk_tck();
8680 goto success;
8681 }
8682#endif
8683
8684#ifdef RUBY_CLOCK_BASED_CLOCK_PROCESS_CPUTIME_ID
8685 if (clk_id == RUBY_CLOCK_BASED_CLOCK_PROCESS_CPUTIME_ID) {
8686 tt.count = 1;
8687 tt.giga_count = 0;
8688 denominators[num_denominators++] = CLOCKS_PER_SEC;
8689 goto success;
8690 }
8691#endif
8692
8693#ifdef RUBY_MACH_ABSOLUTE_TIME_BASED_CLOCK_MONOTONIC
8694 if (clk_id == RUBY_MACH_ABSOLUTE_TIME_BASED_CLOCK_MONOTONIC) {
8695 const mach_timebase_info_data_t *info = get_mach_timebase_info();
8696 tt.count = 1;
8697 tt.giga_count = 0;
8698 numerators[num_numerators++] = info->numer;
8699 denominators[num_denominators++] = info->denom;
8700 denominators[num_denominators++] = 1000000000;
8701 goto success;
8702 }
8703#endif
8704 }
8705 else if (NUMERIC_CLOCKID) {
8706#if defined(HAVE_CLOCK_GETRES)
8707 struct timespec ts;
8708 c = NUM2CLOCKID(clk_id);
8709 getres:
8710 ret = clock_getres(c, &ts);
8711 if (ret == -1)
8712 rb_sys_fail("clock_getres");
8713 tt.count = (int32_t)ts.tv_nsec;
8714 tt.giga_count = ts.tv_sec;
8715 denominators[num_denominators++] = 1000000000;
8716 goto success;
8717#endif
8718 }
8719 /* EINVAL emulates clock_getres behavior when clock_id is invalid. */
8720 rb_syserr_fail(EINVAL, 0);
8721
8722 success:
8723 if (unit == ID2SYM(id_hertz)) {
8724 return timetick2dblnum_reciprocal(&tt, numerators, num_numerators, denominators, num_denominators);
8725 }
8726 else {
8727 return make_clock_result(&tt, numerators, num_numerators, denominators, num_denominators, unit);
8728 }
8729}
8730
8731static VALUE
8732get_CHILD_STATUS(ID _x, VALUE *_y)
8733{
8734 return rb_last_status_get();
8735}
8736
8737static VALUE
8738get_PROCESS_ID(ID _x, VALUE *_y)
8739{
8740 return get_pid();
8741}
8742
8743/*
8744 * call-seq:
8745 * Process.kill(signal, pid, *pids) -> integer
8746 *
8747 * Sends the given signal to the specified process id(s) if _pid_ is positive.
8748 * If _pid_ is zero, _signal_ is sent to all processes whose group ID is equal
8749 * to the group ID of the process. If _pid_ is negative, results are dependent
8750 * on the operating system. _signal_ may be an integer signal number or
8751 * a POSIX signal name (either with or without a +SIG+ prefix). If _signal_ is
8752 * negative (or starts with a minus sign), kills process groups instead of
8753 * processes. Not all signals are available on all platforms.
8754 * The keys and values of Signal.list are known signal names and numbers,
8755 * respectively.
8756 *
8757 * pid = fork do
8758 * Signal.trap("HUP") { puts "Ouch!"; exit }
8759 * # ... do some work ...
8760 * end
8761 * # ...
8762 * Process.kill("HUP", pid)
8763 * Process.wait
8764 *
8765 * <em>produces:</em>
8766 *
8767 * Ouch!
8768 *
8769 * If _signal_ is an integer but wrong for signal, Errno::EINVAL or
8770 * RangeError will be raised. Otherwise unless _signal_ is a String
8771 * or a Symbol, and a known signal name, ArgumentError will be
8772 * raised.
8773 *
8774 * Also, Errno::ESRCH or RangeError for invalid _pid_, Errno::EPERM
8775 * when failed because of no privilege, will be raised. In these
8776 * cases, signals may have been sent to preceding processes.
8777 */
8778
8779static VALUE
8780proc_rb_f_kill(int c, const VALUE *v, VALUE _)
8781{
8782 return rb_f_kill(c, v);
8783}
8784
8786static VALUE rb_mProcUID;
8787static VALUE rb_mProcGID;
8788static VALUE rb_mProcID_Syscall;
8789
8790
8791/*
8792 * The Process module is a collection of methods used to
8793 * manipulate processes.
8794 */
8795
8796void
8797InitVM_process(void)
8798{
8799 rb_define_virtual_variable("$?", get_CHILD_STATUS, 0);
8800 rb_define_virtual_variable("$$", get_PROCESS_ID, 0);
8801
8802 rb_gvar_ractor_local("$$");
8803 rb_gvar_ractor_local("$?");
8804
8805 rb_define_global_function("exec", f_exec, -1);
8806 rb_define_global_function("fork", rb_f_fork, 0);
8807 rb_define_global_function("exit!", rb_f_exit_bang, -1);
8808 rb_define_global_function("system", rb_f_system, -1);
8809 rb_define_global_function("spawn", rb_f_spawn, -1);
8810 rb_define_global_function("sleep", rb_f_sleep, -1);
8811 rb_define_global_function("exit", f_exit, -1);
8812 rb_define_global_function("abort", f_abort, -1);
8813
8814 rb_mProcess = rb_define_module("Process");
8815
8816#ifdef WNOHANG
8817 /* see Process.wait */
8818 rb_define_const(rb_mProcess, "WNOHANG", INT2FIX(WNOHANG));
8819#else
8820 /* see Process.wait */
8821 rb_define_const(rb_mProcess, "WNOHANG", INT2FIX(0));
8822#endif
8823#ifdef WUNTRACED
8824 /* see Process.wait */
8825 rb_define_const(rb_mProcess, "WUNTRACED", INT2FIX(WUNTRACED));
8826#else
8827 /* see Process.wait */
8828 rb_define_const(rb_mProcess, "WUNTRACED", INT2FIX(0));
8829#endif
8830
8831 rb_define_singleton_method(rb_mProcess, "exec", f_exec, -1);
8832 rb_define_singleton_method(rb_mProcess, "fork", rb_f_fork, 0);
8833 rb_define_singleton_method(rb_mProcess, "spawn", rb_f_spawn, -1);
8834 rb_define_singleton_method(rb_mProcess, "exit!", rb_f_exit_bang, -1);
8835 rb_define_singleton_method(rb_mProcess, "exit", f_exit, -1);
8836 rb_define_singleton_method(rb_mProcess, "abort", f_abort, -1);
8837 rb_define_singleton_method(rb_mProcess, "last_status", proc_s_last_status, 0);
8838 rb_define_singleton_method(rb_mProcess, "_fork", rb_proc__fork, 0);
8839
8840 rb_define_module_function(rb_mProcess, "kill", proc_rb_f_kill, -1);
8841 rb_define_module_function(rb_mProcess, "wait", proc_m_wait, -1);
8842 rb_define_module_function(rb_mProcess, "wait2", proc_wait2, -1);
8843 rb_define_module_function(rb_mProcess, "waitpid", proc_m_wait, -1);
8844 rb_define_module_function(rb_mProcess, "waitpid2", proc_wait2, -1);
8845 rb_define_module_function(rb_mProcess, "waitall", proc_waitall, 0);
8846 rb_define_module_function(rb_mProcess, "detach", proc_detach, 1);
8847
8848 /* :nodoc: */
8849 rb_cWaiter = rb_define_class_under(rb_mProcess, "Waiter", rb_cThread);
8850 rb_undef_alloc_func(rb_cWaiter);
8851 rb_undef_method(CLASS_OF(rb_cWaiter), "new");
8852 rb_define_method(rb_cWaiter, "pid", detach_process_pid, 0);
8853
8854 rb_cProcessStatus = rb_define_class_under(rb_mProcess, "Status", rb_cObject);
8855 rb_define_alloc_func(rb_cProcessStatus, rb_process_status_allocate);
8856 rb_undef_method(CLASS_OF(rb_cProcessStatus), "new");
8857 rb_marshal_define_compat(rb_cProcessStatus, rb_cObject,
8858 process_status_dump, process_status_load);
8859
8860 rb_define_singleton_method(rb_cProcessStatus, "wait", rb_process_status_waitv, -1);
8861
8862 rb_define_method(rb_cProcessStatus, "==", pst_equal, 1);
8863 rb_define_method(rb_cProcessStatus, "&", pst_bitand, 1);
8864 rb_define_method(rb_cProcessStatus, ">>", pst_rshift, 1);
8865 rb_define_method(rb_cProcessStatus, "to_i", pst_to_i, 0);
8866 rb_define_method(rb_cProcessStatus, "to_s", pst_to_s, 0);
8867 rb_define_method(rb_cProcessStatus, "inspect", pst_inspect, 0);
8868
8869 rb_define_method(rb_cProcessStatus, "pid", pst_pid_m, 0);
8870
8871 rb_define_method(rb_cProcessStatus, "stopped?", pst_wifstopped, 0);
8872 rb_define_method(rb_cProcessStatus, "stopsig", pst_wstopsig, 0);
8873 rb_define_method(rb_cProcessStatus, "signaled?", pst_wifsignaled, 0);
8874 rb_define_method(rb_cProcessStatus, "termsig", pst_wtermsig, 0);
8875 rb_define_method(rb_cProcessStatus, "exited?", pst_wifexited, 0);
8876 rb_define_method(rb_cProcessStatus, "exitstatus", pst_wexitstatus, 0);
8877 rb_define_method(rb_cProcessStatus, "success?", pst_success_p, 0);
8878 rb_define_method(rb_cProcessStatus, "coredump?", pst_wcoredump, 0);
8879
8880 rb_define_module_function(rb_mProcess, "pid", proc_get_pid, 0);
8881 rb_define_module_function(rb_mProcess, "ppid", proc_get_ppid, 0);
8882
8883 rb_define_module_function(rb_mProcess, "getpgrp", proc_getpgrp, 0);
8884 rb_define_module_function(rb_mProcess, "setpgrp", proc_setpgrp, 0);
8885 rb_define_module_function(rb_mProcess, "getpgid", proc_getpgid, 1);
8886 rb_define_module_function(rb_mProcess, "setpgid", proc_setpgid, 2);
8887
8888 rb_define_module_function(rb_mProcess, "getsid", proc_getsid, -1);
8889 rb_define_module_function(rb_mProcess, "setsid", proc_setsid, 0);
8890
8891 rb_define_module_function(rb_mProcess, "getpriority", proc_getpriority, 2);
8892 rb_define_module_function(rb_mProcess, "setpriority", proc_setpriority, 3);
8893
8894#ifdef HAVE_GETPRIORITY
8895 /* see Process.setpriority */
8896 rb_define_const(rb_mProcess, "PRIO_PROCESS", INT2FIX(PRIO_PROCESS));
8897 /* see Process.setpriority */
8898 rb_define_const(rb_mProcess, "PRIO_PGRP", INT2FIX(PRIO_PGRP));
8899 /* see Process.setpriority */
8900 rb_define_const(rb_mProcess, "PRIO_USER", INT2FIX(PRIO_USER));
8901#endif
8902
8903 rb_define_module_function(rb_mProcess, "getrlimit", proc_getrlimit, 1);
8904 rb_define_module_function(rb_mProcess, "setrlimit", proc_setrlimit, -1);
8905#if defined(RLIM2NUM) && defined(RLIM_INFINITY)
8906 {
8907 VALUE inf = RLIM2NUM(RLIM_INFINITY);
8908#ifdef RLIM_SAVED_MAX
8909 {
8910 VALUE v = RLIM_INFINITY == RLIM_SAVED_MAX ? inf : RLIM2NUM(RLIM_SAVED_MAX);
8911 /* see Process.setrlimit */
8912 rb_define_const(rb_mProcess, "RLIM_SAVED_MAX", v);
8913 }
8914#endif
8915 /* see Process.setrlimit */
8916 rb_define_const(rb_mProcess, "RLIM_INFINITY", inf);
8917#ifdef RLIM_SAVED_CUR
8918 {
8919 VALUE v = RLIM_INFINITY == RLIM_SAVED_CUR ? inf : RLIM2NUM(RLIM_SAVED_CUR);
8920 /* see Process.setrlimit */
8921 rb_define_const(rb_mProcess, "RLIM_SAVED_CUR", v);
8922 }
8923#endif
8924 }
8925#ifdef RLIMIT_AS
8926 /* Maximum size of the process's virtual memory (address space) in bytes.
8927 *
8928 * see the system getrlimit(2) manual for details.
8929 */
8930 rb_define_const(rb_mProcess, "RLIMIT_AS", INT2FIX(RLIMIT_AS));
8931#endif
8932#ifdef RLIMIT_CORE
8933 /* Maximum size of the core file.
8934 *
8935 * see the system getrlimit(2) manual for details.
8936 */
8937 rb_define_const(rb_mProcess, "RLIMIT_CORE", INT2FIX(RLIMIT_CORE));
8938#endif
8939#ifdef RLIMIT_CPU
8940 /* CPU time limit in seconds.
8941 *
8942 * see the system getrlimit(2) manual for details.
8943 */
8944 rb_define_const(rb_mProcess, "RLIMIT_CPU", INT2FIX(RLIMIT_CPU));
8945#endif
8946#ifdef RLIMIT_DATA
8947 /* Maximum size of the process's data segment.
8948 *
8949 * see the system getrlimit(2) manual for details.
8950 */
8951 rb_define_const(rb_mProcess, "RLIMIT_DATA", INT2FIX(RLIMIT_DATA));
8952#endif
8953#ifdef RLIMIT_FSIZE
8954 /* Maximum size of files that the process may create.
8955 *
8956 * see the system getrlimit(2) manual for details.
8957 */
8958 rb_define_const(rb_mProcess, "RLIMIT_FSIZE", INT2FIX(RLIMIT_FSIZE));
8959#endif
8960#ifdef RLIMIT_MEMLOCK
8961 /* Maximum number of bytes of memory that may be locked into RAM.
8962 *
8963 * see the system getrlimit(2) manual for details.
8964 */
8965 rb_define_const(rb_mProcess, "RLIMIT_MEMLOCK", INT2FIX(RLIMIT_MEMLOCK));
8966#endif
8967#ifdef RLIMIT_MSGQUEUE
8968 /* Specifies the limit on the number of bytes that can be allocated
8969 * for POSIX message queues for the real user ID of the calling process.
8970 *
8971 * see the system getrlimit(2) manual for details.
8972 */
8973 rb_define_const(rb_mProcess, "RLIMIT_MSGQUEUE", INT2FIX(RLIMIT_MSGQUEUE));
8974#endif
8975#ifdef RLIMIT_NICE
8976 /* Specifies a ceiling to which the process's nice value can be raised.
8977 *
8978 * see the system getrlimit(2) manual for details.
8979 */
8980 rb_define_const(rb_mProcess, "RLIMIT_NICE", INT2FIX(RLIMIT_NICE));
8981#endif
8982#ifdef RLIMIT_NOFILE
8983 /* Specifies a value one greater than the maximum file descriptor
8984 * number that can be opened by this process.
8985 *
8986 * see the system getrlimit(2) manual for details.
8987 */
8988 rb_define_const(rb_mProcess, "RLIMIT_NOFILE", INT2FIX(RLIMIT_NOFILE));
8989#endif
8990#ifdef RLIMIT_NPROC
8991 /* The maximum number of processes that can be created for the
8992 * real user ID of the calling process.
8993 *
8994 * see the system getrlimit(2) manual for details.
8995 */
8996 rb_define_const(rb_mProcess, "RLIMIT_NPROC", INT2FIX(RLIMIT_NPROC));
8997#endif
8998#ifdef RLIMIT_NPTS
8999 /* The maximum number of pseudo-terminals that can be created for the
9000 * real user ID of the calling process.
9001 *
9002 * see the system getrlimit(2) manual for details.
9003 */
9004 rb_define_const(rb_mProcess, "RLIMIT_NPTS", INT2FIX(RLIMIT_NPTS));
9005#endif
9006#ifdef RLIMIT_RSS
9007 /* Specifies the limit (in pages) of the process's resident set.
9008 *
9009 * see the system getrlimit(2) manual for details.
9010 */
9011 rb_define_const(rb_mProcess, "RLIMIT_RSS", INT2FIX(RLIMIT_RSS));
9012#endif
9013#ifdef RLIMIT_RTPRIO
9014 /* Specifies a ceiling on the real-time priority that may be set for this process.
9015 *
9016 * see the system getrlimit(2) manual for details.
9017 */
9018 rb_define_const(rb_mProcess, "RLIMIT_RTPRIO", INT2FIX(RLIMIT_RTPRIO));
9019#endif
9020#ifdef RLIMIT_RTTIME
9021 /* Specifies limit on CPU time this process scheduled under a real-time
9022 * scheduling policy can consume.
9023 *
9024 * see the system getrlimit(2) manual for details.
9025 */
9026 rb_define_const(rb_mProcess, "RLIMIT_RTTIME", INT2FIX(RLIMIT_RTTIME));
9027#endif
9028#ifdef RLIMIT_SBSIZE
9029 /* Maximum size of the socket buffer.
9030 */
9031 rb_define_const(rb_mProcess, "RLIMIT_SBSIZE", INT2FIX(RLIMIT_SBSIZE));
9032#endif
9033#ifdef RLIMIT_SIGPENDING
9034 /* Specifies a limit on the number of signals that may be queued for
9035 * the real user ID of the calling process.
9036 *
9037 * see the system getrlimit(2) manual for details.
9038 */
9039 rb_define_const(rb_mProcess, "RLIMIT_SIGPENDING", INT2FIX(RLIMIT_SIGPENDING));
9040#endif
9041#ifdef RLIMIT_STACK
9042 /* Maximum size of the stack, in bytes.
9043 *
9044 * see the system getrlimit(2) manual for details.
9045 */
9046 rb_define_const(rb_mProcess, "RLIMIT_STACK", INT2FIX(RLIMIT_STACK));
9047#endif
9048#endif
9049
9050 rb_define_module_function(rb_mProcess, "uid", proc_getuid, 0);
9051 rb_define_module_function(rb_mProcess, "uid=", proc_setuid, 1);
9052 rb_define_module_function(rb_mProcess, "gid", proc_getgid, 0);
9053 rb_define_module_function(rb_mProcess, "gid=", proc_setgid, 1);
9054 rb_define_module_function(rb_mProcess, "euid", proc_geteuid, 0);
9055 rb_define_module_function(rb_mProcess, "euid=", proc_seteuid_m, 1);
9056 rb_define_module_function(rb_mProcess, "egid", proc_getegid, 0);
9057 rb_define_module_function(rb_mProcess, "egid=", proc_setegid_m, 1);
9058 rb_define_module_function(rb_mProcess, "initgroups", proc_initgroups, 2);
9059 rb_define_module_function(rb_mProcess, "groups", proc_getgroups, 0);
9060 rb_define_module_function(rb_mProcess, "groups=", proc_setgroups, 1);
9061 rb_define_module_function(rb_mProcess, "maxgroups", proc_getmaxgroups, 0);
9062 rb_define_module_function(rb_mProcess, "maxgroups=", proc_setmaxgroups, 1);
9063
9064 rb_define_module_function(rb_mProcess, "daemon", proc_daemon, -1);
9065
9066 rb_define_module_function(rb_mProcess, "times", rb_proc_times, 0);
9067
9068#if defined(RUBY_CLOCK_REALTIME)
9069#elif defined(RUBY_GETTIMEOFDAY_BASED_CLOCK_REALTIME)
9070# define RUBY_CLOCK_REALTIME RUBY_GETTIMEOFDAY_BASED_CLOCK_REALTIME
9071#elif defined(RUBY_TIME_BASED_CLOCK_REALTIME)
9072# define RUBY_CLOCK_REALTIME RUBY_TIME_BASED_CLOCK_REALTIME
9073#endif
9074#if defined(CLOCK_REALTIME) && defined(CLOCKID2NUM)
9075 /* see Process.clock_gettime */
9076 rb_define_const(rb_mProcess, "CLOCK_REALTIME", CLOCKID2NUM(CLOCK_REALTIME));
9077#elif defined(RUBY_CLOCK_REALTIME)
9078 rb_define_const(rb_mProcess, "CLOCK_REALTIME", RUBY_CLOCK_REALTIME);
9079#endif
9080
9081#if defined(RUBY_CLOCK_MONOTONIC)
9082#elif defined(RUBY_MACH_ABSOLUTE_TIME_BASED_CLOCK_MONOTONIC)
9083# define RUBY_CLOCK_MONOTONIC RUBY_MACH_ABSOLUTE_TIME_BASED_CLOCK_MONOTONIC
9084#endif
9085#if defined(CLOCK_MONOTONIC) && defined(CLOCKID2NUM)
9086 /* see Process.clock_gettime */
9087 rb_define_const(rb_mProcess, "CLOCK_MONOTONIC", CLOCKID2NUM(CLOCK_MONOTONIC));
9088#elif defined(RUBY_CLOCK_MONOTONIC)
9089 rb_define_const(rb_mProcess, "CLOCK_MONOTONIC", RUBY_CLOCK_MONOTONIC);
9090#endif
9091
9092#if defined(RUBY_CLOCK_PROCESS_CPUTIME_ID)
9093#elif defined(RUBY_GETRUSAGE_BASED_CLOCK_PROCESS_CPUTIME_ID)
9094# define RUBY_CLOCK_PROCESS_CPUTIME_ID RUBY_GETRUSAGE_BASED_CLOCK_PROCESS_CPUTIME_ID
9095#endif
9096#if defined(CLOCK_PROCESS_CPUTIME_ID) && defined(CLOCKID2NUM)
9097 /* see Process.clock_gettime */
9098 rb_define_const(rb_mProcess, "CLOCK_PROCESS_CPUTIME_ID", CLOCKID2NUM(CLOCK_PROCESS_CPUTIME_ID));
9099#elif defined(RUBY_CLOCK_PROCESS_CPUTIME_ID)
9100 rb_define_const(rb_mProcess, "CLOCK_PROCESS_CPUTIME_ID", RUBY_CLOCK_PROCESS_CPUTIME_ID);
9101#endif
9102
9103#if defined(CLOCK_THREAD_CPUTIME_ID) && defined(CLOCKID2NUM)
9104 /* see Process.clock_gettime */
9105 rb_define_const(rb_mProcess, "CLOCK_THREAD_CPUTIME_ID", CLOCKID2NUM(CLOCK_THREAD_CPUTIME_ID));
9106#elif defined(RUBY_CLOCK_THREAD_CPUTIME_ID)
9107 rb_define_const(rb_mProcess, "CLOCK_THREAD_CPUTIME_ID", RUBY_CLOCK_THREAD_CPUTIME_ID);
9108#endif
9109
9110#ifdef CLOCKID2NUM
9111#ifdef CLOCK_VIRTUAL
9112 /* see Process.clock_gettime */
9113 rb_define_const(rb_mProcess, "CLOCK_VIRTUAL", CLOCKID2NUM(CLOCK_VIRTUAL));
9114#endif
9115#ifdef CLOCK_PROF
9116 /* see Process.clock_gettime */
9117 rb_define_const(rb_mProcess, "CLOCK_PROF", CLOCKID2NUM(CLOCK_PROF));
9118#endif
9119#ifdef CLOCK_REALTIME_FAST
9120 /* see Process.clock_gettime */
9121 rb_define_const(rb_mProcess, "CLOCK_REALTIME_FAST", CLOCKID2NUM(CLOCK_REALTIME_FAST));
9122#endif
9123#ifdef CLOCK_REALTIME_PRECISE
9124 /* see Process.clock_gettime */
9125 rb_define_const(rb_mProcess, "CLOCK_REALTIME_PRECISE", CLOCKID2NUM(CLOCK_REALTIME_PRECISE));
9126#endif
9127#ifdef CLOCK_REALTIME_COARSE
9128 /* see Process.clock_gettime */
9129 rb_define_const(rb_mProcess, "CLOCK_REALTIME_COARSE", CLOCKID2NUM(CLOCK_REALTIME_COARSE));
9130#endif
9131#ifdef CLOCK_REALTIME_ALARM
9132 /* see Process.clock_gettime */
9133 rb_define_const(rb_mProcess, "CLOCK_REALTIME_ALARM", CLOCKID2NUM(CLOCK_REALTIME_ALARM));
9134#endif
9135#ifdef CLOCK_MONOTONIC_FAST
9136 /* see Process.clock_gettime */
9137 rb_define_const(rb_mProcess, "CLOCK_MONOTONIC_FAST", CLOCKID2NUM(CLOCK_MONOTONIC_FAST));
9138#endif
9139#ifdef CLOCK_MONOTONIC_PRECISE
9140 /* see Process.clock_gettime */
9141 rb_define_const(rb_mProcess, "CLOCK_MONOTONIC_PRECISE", CLOCKID2NUM(CLOCK_MONOTONIC_PRECISE));
9142#endif
9143#ifdef CLOCK_MONOTONIC_RAW
9144 /* see Process.clock_gettime */
9145 rb_define_const(rb_mProcess, "CLOCK_MONOTONIC_RAW", CLOCKID2NUM(CLOCK_MONOTONIC_RAW));
9146#endif
9147#ifdef CLOCK_MONOTONIC_RAW_APPROX
9148 /* see Process.clock_gettime */
9149 rb_define_const(rb_mProcess, "CLOCK_MONOTONIC_RAW_APPROX", CLOCKID2NUM(CLOCK_MONOTONIC_RAW_APPROX));
9150#endif
9151#ifdef CLOCK_MONOTONIC_COARSE
9152 /* see Process.clock_gettime */
9153 rb_define_const(rb_mProcess, "CLOCK_MONOTONIC_COARSE", CLOCKID2NUM(CLOCK_MONOTONIC_COARSE));
9154#endif
9155#ifdef CLOCK_BOOTTIME
9156 /* see Process.clock_gettime */
9157 rb_define_const(rb_mProcess, "CLOCK_BOOTTIME", CLOCKID2NUM(CLOCK_BOOTTIME));
9158#endif
9159#ifdef CLOCK_BOOTTIME_ALARM
9160 /* see Process.clock_gettime */
9161 rb_define_const(rb_mProcess, "CLOCK_BOOTTIME_ALARM", CLOCKID2NUM(CLOCK_BOOTTIME_ALARM));
9162#endif
9163#ifdef CLOCK_UPTIME
9164 /* see Process.clock_gettime */
9165 rb_define_const(rb_mProcess, "CLOCK_UPTIME", CLOCKID2NUM(CLOCK_UPTIME));
9166#endif
9167#ifdef CLOCK_UPTIME_FAST
9168 /* see Process.clock_gettime */
9169 rb_define_const(rb_mProcess, "CLOCK_UPTIME_FAST", CLOCKID2NUM(CLOCK_UPTIME_FAST));
9170#endif
9171#ifdef CLOCK_UPTIME_PRECISE
9172 /* see Process.clock_gettime */
9173 rb_define_const(rb_mProcess, "CLOCK_UPTIME_PRECISE", CLOCKID2NUM(CLOCK_UPTIME_PRECISE));
9174#endif
9175#ifdef CLOCK_UPTIME_RAW
9176 /* see Process.clock_gettime */
9177 rb_define_const(rb_mProcess, "CLOCK_UPTIME_RAW", CLOCKID2NUM(CLOCK_UPTIME_RAW));
9178#endif
9179#ifdef CLOCK_UPTIME_RAW_APPROX
9180 /* see Process.clock_gettime */
9181 rb_define_const(rb_mProcess, "CLOCK_UPTIME_RAW_APPROX", CLOCKID2NUM(CLOCK_UPTIME_RAW_APPROX));
9182#endif
9183#ifdef CLOCK_SECOND
9184 /* see Process.clock_gettime */
9185 rb_define_const(rb_mProcess, "CLOCK_SECOND", CLOCKID2NUM(CLOCK_SECOND));
9186#endif
9187#ifdef CLOCK_TAI
9188 /* see Process.clock_gettime */
9189 rb_define_const(rb_mProcess, "CLOCK_TAI", CLOCKID2NUM(CLOCK_TAI));
9190#endif
9191#endif
9192 rb_define_module_function(rb_mProcess, "clock_gettime", rb_clock_gettime, -1);
9193 rb_define_module_function(rb_mProcess, "clock_getres", rb_clock_getres, -1);
9194
9195#if defined(HAVE_TIMES) || defined(_WIN32)
9196 rb_cProcessTms = rb_struct_define_under(rb_mProcess, "Tms", "utime", "stime", "cutime", "cstime", NULL);
9197#if 0 /* for RDoc */
9198 /* user time used in this process */
9199 rb_define_attr(rb_cProcessTms, "utime", TRUE, TRUE);
9200 /* system time used in this process */
9201 rb_define_attr(rb_cProcessTms, "stime", TRUE, TRUE);
9202 /* user time used in the child processes */
9203 rb_define_attr(rb_cProcessTms, "cutime", TRUE, TRUE);
9204 /* system time used in the child processes */
9205 rb_define_attr(rb_cProcessTms, "cstime", TRUE, TRUE);
9206#endif
9207#endif
9208
9209 SAVED_USER_ID = geteuid();
9210 SAVED_GROUP_ID = getegid();
9211
9212 rb_mProcUID = rb_define_module_under(rb_mProcess, "UID");
9213 rb_mProcGID = rb_define_module_under(rb_mProcess, "GID");
9214
9215 rb_define_module_function(rb_mProcUID, "rid", proc_getuid, 0);
9216 rb_define_module_function(rb_mProcGID, "rid", proc_getgid, 0);
9217 rb_define_module_function(rb_mProcUID, "eid", proc_geteuid, 0);
9218 rb_define_module_function(rb_mProcGID, "eid", proc_getegid, 0);
9219 rb_define_module_function(rb_mProcUID, "change_privilege", p_uid_change_privilege, 1);
9220 rb_define_module_function(rb_mProcGID, "change_privilege", p_gid_change_privilege, 1);
9221 rb_define_module_function(rb_mProcUID, "grant_privilege", p_uid_grant_privilege, 1);
9222 rb_define_module_function(rb_mProcGID, "grant_privilege", p_gid_grant_privilege, 1);
9223 rb_define_alias(rb_singleton_class(rb_mProcUID), "eid=", "grant_privilege");
9224 rb_define_alias(rb_singleton_class(rb_mProcGID), "eid=", "grant_privilege");
9225 rb_define_module_function(rb_mProcUID, "re_exchange", p_uid_exchange, 0);
9226 rb_define_module_function(rb_mProcGID, "re_exchange", p_gid_exchange, 0);
9227 rb_define_module_function(rb_mProcUID, "re_exchangeable?", p_uid_exchangeable, 0);
9228 rb_define_module_function(rb_mProcGID, "re_exchangeable?", p_gid_exchangeable, 0);
9229 rb_define_module_function(rb_mProcUID, "sid_available?", p_uid_have_saved_id, 0);
9230 rb_define_module_function(rb_mProcGID, "sid_available?", p_gid_have_saved_id, 0);
9231 rb_define_module_function(rb_mProcUID, "switch", p_uid_switch, 0);
9232 rb_define_module_function(rb_mProcGID, "switch", p_gid_switch, 0);
9233#ifdef p_uid_from_name
9234 rb_define_module_function(rb_mProcUID, "from_name", p_uid_from_name, 1);
9235#endif
9236#ifdef p_gid_from_name
9237 rb_define_module_function(rb_mProcGID, "from_name", p_gid_from_name, 1);
9238#endif
9239
9240 rb_mProcID_Syscall = rb_define_module_under(rb_mProcess, "Sys");
9241
9242 rb_define_module_function(rb_mProcID_Syscall, "getuid", proc_getuid, 0);
9243 rb_define_module_function(rb_mProcID_Syscall, "geteuid", proc_geteuid, 0);
9244 rb_define_module_function(rb_mProcID_Syscall, "getgid", proc_getgid, 0);
9245 rb_define_module_function(rb_mProcID_Syscall, "getegid", proc_getegid, 0);
9246
9247 rb_define_module_function(rb_mProcID_Syscall, "setuid", p_sys_setuid, 1);
9248 rb_define_module_function(rb_mProcID_Syscall, "setgid", p_sys_setgid, 1);
9249
9250 rb_define_module_function(rb_mProcID_Syscall, "setruid", p_sys_setruid, 1);
9251 rb_define_module_function(rb_mProcID_Syscall, "setrgid", p_sys_setrgid, 1);
9252
9253 rb_define_module_function(rb_mProcID_Syscall, "seteuid", p_sys_seteuid, 1);
9254 rb_define_module_function(rb_mProcID_Syscall, "setegid", p_sys_setegid, 1);
9255
9256 rb_define_module_function(rb_mProcID_Syscall, "setreuid", p_sys_setreuid, 2);
9257 rb_define_module_function(rb_mProcID_Syscall, "setregid", p_sys_setregid, 2);
9258
9259 rb_define_module_function(rb_mProcID_Syscall, "setresuid", p_sys_setresuid, 3);
9260 rb_define_module_function(rb_mProcID_Syscall, "setresgid", p_sys_setresgid, 3);
9261 rb_define_module_function(rb_mProcID_Syscall, "issetugid", p_sys_issetugid, 0);
9262}
9263
9264void
9265Init_process(void)
9266{
9267#define define_id(name) id_##name = rb_intern_const(#name)
9268 define_id(in);
9269 define_id(out);
9270 define_id(err);
9271 define_id(pid);
9272 define_id(uid);
9273 define_id(gid);
9274 define_id(close);
9275 define_id(child);
9276#ifdef HAVE_SETPGID
9277 define_id(pgroup);
9278#endif
9279#ifdef _WIN32
9280 define_id(new_pgroup);
9281#endif
9282 define_id(unsetenv_others);
9283 define_id(chdir);
9284 define_id(umask);
9285 define_id(close_others);
9286 define_id(nanosecond);
9287 define_id(microsecond);
9288 define_id(millisecond);
9289 define_id(second);
9290 define_id(float_microsecond);
9291 define_id(float_millisecond);
9292 define_id(float_second);
9293 define_id(GETTIMEOFDAY_BASED_CLOCK_REALTIME);
9294 define_id(TIME_BASED_CLOCK_REALTIME);
9295#ifdef CLOCK_REALTIME
9296 define_id(CLOCK_REALTIME);
9297#endif
9298#ifdef CLOCK_MONOTONIC
9299 define_id(CLOCK_MONOTONIC);
9300#endif
9301#ifdef CLOCK_PROCESS_CPUTIME_ID
9302 define_id(CLOCK_PROCESS_CPUTIME_ID);
9303#endif
9304#ifdef CLOCK_THREAD_CPUTIME_ID
9305 define_id(CLOCK_THREAD_CPUTIME_ID);
9306#endif
9307#ifdef HAVE_TIMES
9308 define_id(TIMES_BASED_CLOCK_MONOTONIC);
9309 define_id(TIMES_BASED_CLOCK_PROCESS_CPUTIME_ID);
9310#endif
9311#ifdef RUSAGE_SELF
9312 define_id(GETRUSAGE_BASED_CLOCK_PROCESS_CPUTIME_ID);
9313#endif
9314 define_id(CLOCK_BASED_CLOCK_PROCESS_CPUTIME_ID);
9315#ifdef __APPLE__
9316 define_id(MACH_ABSOLUTE_TIME_BASED_CLOCK_MONOTONIC);
9317#endif
9318 define_id(hertz);
9319
9320 InitVM(process);
9321}
#define LONG_LONG
Definition long_long.h:38
#define rb_define_method(klass, mid, func, arity)
Defines klass#mid.
#define rb_define_singleton_method(klass, mid, func, arity)
Defines klass.mid.
#define rb_define_module_function(klass, mid, func, arity)
Defines klass#mid and makes it a module function.
#define rb_define_global_function(mid, func, arity)
Defines rb_mKernel #mid.
#define PATH_ENV
Definition dosish.h:63
#define GIDT2NUM
Converts a C's gid_t into an instance of rb_cInteger.
Definition gid_t.h:28
#define NUM2GIDT
Converts an instance of rb_cNumeric into C's gid_t.
Definition gid_t.h:33
VALUE rb_singleton_class(VALUE obj)
Finds or creates the singleton class of the passed object.
Definition class.c:2236
VALUE rb_define_class_under(VALUE outer, const char *name, VALUE super)
Defines a class under the namespace of outer.
Definition class.c:955
VALUE rb_define_module(const char *name)
Defines a top-level module.
Definition class.c:1033
VALUE rb_define_module_under(VALUE outer, const char *name)
Defines a module under the namespace of outer.
Definition class.c:1057
void rb_define_alias(VALUE klass, const char *name1, const char *name2)
Defines an alias of a method.
Definition class.c:2284
void rb_define_attr(VALUE klass, const char *name, int read, int write)
Defines public accessor method(s) for an attribute.
Definition class.c:2290
void rb_undef_method(VALUE klass, const char *name)
Defines an undef of a method.
Definition class.c:2108
int rb_block_given_p(void)
Determines if the current method is given a block.
Definition eval.c:868
#define rb_str_new2
Old name of rb_str_new_cstr.
Definition string.h:1675
#define TYPE(_)
Old name of rb_type.
Definition value_type.h:107
#define T_FILE
Old name of RUBY_T_FILE.
Definition value_type.h:62
#define rb_str_buf_cat2
Old name of rb_usascii_str_new_cstr.
Definition string.h:1682
#define T_STRING
Old name of RUBY_T_STRING.
Definition value_type.h:78
#define Qundef
Old name of RUBY_Qundef.
#define INT2FIX
Old name of RB_INT2FIX.
Definition long.h:48
#define rb_str_cat2
Old name of rb_str_cat_cstr.
Definition string.h:1683
#define ISUPPER
Old name of rb_isupper.
Definition ctype.h:89
#define ID2SYM
Old name of RB_ID2SYM.
Definition symbol.h:44
#define T_BIGNUM
Old name of RUBY_T_BIGNUM.
Definition value_type.h:57
#define T_FIXNUM
Old name of RUBY_T_FIXNUM.
Definition value_type.h:63
#define UNREACHABLE_RETURN
Old name of RBIMPL_UNREACHABLE_RETURN.
Definition assume.h:29
#define CLASS_OF
Old name of rb_class_of.
Definition globals.h:203
#define LONG2FIX
Old name of RB_INT2FIX.
Definition long.h:49
#define FIX2INT
Old name of RB_FIX2INT.
Definition int.h:41
#define TOUPPER
Old name of rb_toupper.
Definition ctype.h:100
#define NUM2UINT
Old name of RB_NUM2UINT.
Definition int.h:45
#define ISLOWER
Old name of rb_islower.
Definition ctype.h:90
#define rb_ary_new3
Old name of rb_ary_new_from_args.
Definition array.h:652
#define Qtrue
Old name of RUBY_Qtrue.
#define NUM2INT
Old name of RB_NUM2INT.
Definition int.h:44
#define INT2NUM
Old name of RB_INT2NUM.
Definition int.h:43
#define Qnil
Old name of RUBY_Qnil.
#define Qfalse
Old name of RUBY_Qfalse.
#define T_ARRAY
Old name of RUBY_T_ARRAY.
Definition value_type.h:56
#define NIL_P
Old name of RB_NIL_P.
#define ALLOCV_N
Old name of RB_ALLOCV_N.
Definition memory.h:399
#define T_SYMBOL
Old name of RUBY_T_SYMBOL.
Definition value_type.h:80
#define DBL2NUM
Old name of rb_float_new.
Definition double.h:29
#define FIXNUM_P
Old name of RB_FIXNUM_P.
#define CONST_ID
Old name of RUBY_CONST_ID.
Definition symbol.h:47
#define ALLOCV_END
Old name of RB_ALLOCV_END.
Definition memory.h:400
#define SYMBOL_P
Old name of RB_SYMBOL_P.
Definition value_type.h:88
void ruby_stop(int ex)
Calls ruby_cleanup() and exits the process.
Definition eval.c:298
void rb_notimplement(void)
Definition error.c:3193
void rb_raise(VALUE exc, const char *fmt,...)
Exception entry point.
Definition error.c:3150
VALUE rb_eNotImpError
NotImplementedError exception.
Definition error.c:1101
void rb_exc_raise(VALUE mesg)
Raises an exception in the current thread.
Definition eval.c:688
void rb_syserr_fail(int e, const char *mesg)
Raises appropriate exception that represents a C errno.
Definition error.c:3262
void rb_bug(const char *fmt,...)
Interpreter panic switch.
Definition error.c:794
VALUE rb_eSystemExit
SystemExit exception.
Definition error.c:1084
void rb_sys_fail(const char *mesg)
Converts a C errno into a Ruby exception, then raises it.
Definition error.c:3274
void rb_syserr_fail_str(int e, VALUE mesg)
Identical to rb_syserr_fail(), except it takes the message in Ruby's String instead of C's.
Definition error.c:3268
VALUE rb_eRuntimeError
RuntimeError exception.
Definition error.c:1089
void * rb_check_typeddata(VALUE obj, const rb_data_type_t *data_type)
Identical to rb_typeddata_is_kind_of(), except it raises exceptions instead of returning false.
Definition error.c:1058
void rb_warn(const char *fmt,...)
Identical to rb_warning(), except it reports always regardless of runtime -W flag.
Definition error.c:411
VALUE rb_exc_new_str(VALUE etype, VALUE str)
Identical to rb_exc_new_cstr(), except it takes a Ruby's string instead of C's.
Definition error.c:1142
VALUE rb_eArgError
ArgumentError exception.
Definition error.c:1092
void rb_sys_fail_str(VALUE mesg)
Identical to rb_sys_fail(), except it takes the message in Ruby's String instead of C's.
Definition error.c:3280
void rb_exit(int status)
Terminates the current execution context.
Definition process.c:4520
VALUE rb_mProcess
Process module.
Definition process.c:8785
VALUE rb_class_new_instance(int argc, const VALUE *argv, VALUE klass)
Allocates, then initialises an instance of the given class.
Definition object.c:1980
VALUE rb_cThread
Thread class.
Definition vm.c:466
VALUE rb_equal(VALUE lhs, VALUE rhs)
This function is an optimised version of calling #==.
Definition object.c:122
VALUE rb_obj_freeze(VALUE obj)
Just calls rb_obj_freeze_inline() inside.
Definition object.c:1182
VALUE rb_to_int(VALUE val)
Identical to rb_check_to_int(), except it raises in case of conversion mismatch.
Definition object.c:3026
#define RB_OBJ_WRITTEN(old, oldv, young)
Identical to RB_OBJ_WRITE(), except it doesn't write any values, but only a WB declaration.
Definition rgengc.h:232
VALUE rb_funcall(VALUE recv, ID mid, int n,...)
Calls a method.
Definition vm_eval.c:1102
#define UNLIMITED_ARGUMENTS
This macro is used in conjunction with rb_check_arity().
Definition error.h:35
static int rb_check_arity(int argc, int min, int max)
Ensures that the passed integer is in the passed range.
Definition error.h:280
VALUE rb_f_abort(int argc, const VALUE *argv)
This is similar to rb_f_exit().
Definition process.c:4598
VALUE rb_f_exit(int argc, const VALUE *argv)
Identical to rb_exit(), except how arguments are passed.
Definition process.c:4533
VALUE rb_io_puts(int argc, const VALUE *argv, VALUE io)
Iterates over the passed array to apply rb_io_write() individually.
Definition io.c:8898
int rb_cloexec_dup2(int oldfd, int newfd)
Identical to rb_cloexec_dup(), except you can specify the destination file descriptor.
Definition io.c:356
void rb_update_max_fd(int fd)
Informs the interpreter that the passed fd can be the max.
Definition io.c:230
int rb_cloexec_open(const char *pathname, int flags, mode_t mode)
Opens a file that closes on exec.
Definition io.c:310
void rb_close_before_exec(int lowfd, int maxhint, VALUE noclose_fds)
Closes everything.
int rb_reserved_fd_p(int fd)
Queries if the given FD is reserved or not.
int rb_pipe(int *pipes)
This is an rb_cloexec_pipe() + rb_update_max_fd() combo.
Definition io.c:7282
int rb_cloexec_fcntl_dupfd(int fd, int minfd)
Duplicates a file descriptor with closing on exec.
Definition io.c:443
int rb_cloexec_dup(int oldfd)
Identical to rb_cloexec_fcntl_dupfd(), except it implies minfd is 3.
Definition io.c:349
int rb_proc_exec(const char *cmd)
Executes a shell command.
Definition process.c:1882
VALUE rb_last_status_get(void)
Queries the "last status", or the $?.
Definition process.c:622
rb_pid_t rb_waitpid(rb_pid_t pid, int *status, int flags)
Waits for a process, with releasing GVL.
Definition process.c:1434
rb_pid_t rb_spawn_err(int argc, const VALUE *argv, char *errbuf, size_t buflen)
Identical to rb_spawn(), except you can additionally know the detailed situation in case of abnormal ...
Definition process.c:4774
void rb_syswait(rb_pid_t pid)
This is a shorthand of rb_waitpid without status and flags.
Definition process.c:4643
VALUE rb_f_exec(int argc, const VALUE *argv)
Replaces the current process by running the given external command.
Definition process.c:3099
rb_pid_t rb_spawn(int argc, const VALUE *argv)
Identical to rb_f_exec(), except it spawns a child process instead of replacing the current one.
Definition process.c:4780
void rb_last_status_set(int status, rb_pid_t pid)
Sets the "last status", or the $?.
Definition process.c:686
VALUE rb_detach_process(rb_pid_t pid)
"Detaches" a subprocess.
Definition process.c:1637
const char * ruby_signal_name(int signo)
Queries the name of the signal.
Definition signal.c:316
VALUE rb_f_kill(int argc, const VALUE *argv)
Sends a signal ("kills") to processes.
Definition signal.c:423
VALUE rb_str_append(VALUE dst, VALUE src)
Identical to rb_str_buf_append(), except it converts the right hand side before concatenating.
Definition string.c:3353
VALUE rb_str_tmp_new(long len)
Allocates a "temporary" string.
Definition string.c:1565
VALUE rb_str_subseq(VALUE str, long beg, long len)
Identical to rb_str_substr(), except the numbers are interpreted as byte offsets instead of character...
Definition string.c:2826
#define rb_str_new(str, len)
Allocates an instance of rb_cString.
Definition string.h:1498
#define rb_str_buf_cat
Just another name of rb_str_cat.
Definition string.h:1681
size_t rb_str_capacity(VALUE str)
Queries the capacity of the given string.
Definition string.c:871
VALUE rb_str_new_frozen(VALUE str)
Creates a frozen copy of the string, if necessary.
Definition string.c:1382
VALUE rb_str_dup(VALUE str)
Duplicates a string.
Definition string.c:1834
void rb_str_set_len(VALUE str, long len)
Overwrites the length of the string.
Definition string.c:3020
VALUE rb_check_string_type(VALUE obj)
Try converting an object to its stringised representation using its to_str method,...
Definition string.c:2640
#define rb_str_cat_cstr(buf, str)
Identical to rb_str_cat(), except it assumes the passed pointer is a pointer to a C string.
Definition string.h:1656
VALUE rb_str_resize(VALUE str, long len)
Overwrites the length of the string.
Definition string.c:3064
void rb_str_modify_expand(VALUE str, long capa)
Identical to rb_str_modify(), except it additionally expands the capacity of the receiver.
Definition string.c:2445
VALUE rb_str_buf_new(long capa)
Allocates a "string buffer".
Definition string.c:1532
#define rb_str_new_cstr(str)
Identical to rb_str_new, except it assumes the passed pointer is a pointer to a C string.
Definition string.h:1514
VALUE rb_struct_define_under(VALUE space, const char *name,...)
Identical to rb_struct_define(), except it defines the class under the specified namespace instead of...
Definition struct.c:504
VALUE rb_struct_new(VALUE klass,...)
Creates an instance of the given struct.
Definition struct.c:875
VALUE rb_thread_local_aref(VALUE thread, ID key)
This badly named function reads from a Fiber local storage.
Definition thread.c:3382
#define RUBY_UBF_IO
A special UBF for blocking IO operations.
Definition thread.h:382
void rb_thread_sleep_forever(void)
Blocks indefinitely.
Definition thread.c:1365
void rb_thread_wait_for(struct timeval time)
Identical to rb_thread_sleep(), except it takes struct timeval instead.
Definition thread.c:1409
void rb_thread_check_ints(void)
Checks for interrupts.
Definition thread.c:1424
void rb_thread_atfork(void)
A pthread_atfork(3posix)-like API.
Definition thread.c:4687
VALUE rb_thread_local_aset(VALUE thread, ID key, VALUE val)
This badly named function writes to a Fiber local storage.
Definition thread.c:3530
#define RUBY_UBF_PROCESS
A special UBF for blocking process operations.
Definition thread.h:389
void rb_thread_sleep(int sec)
Blocks for the given period of time.
Definition thread.c:1447
struct timeval rb_time_interval(VALUE num)
Creates a "time interval".
Definition time.c:2847
VALUE rb_attr_get(VALUE obj, ID name)
Identical to rb_ivar_get()
Definition variable.c:1226
VALUE rb_ivar_set(VALUE obj, ID name, VALUE val)
Identical to rb_iv_set(), except it accepts the name as an ID instead of a C string.
Definition variable.c:1606
void rb_undef_alloc_func(VALUE klass)
Deletes the allocator function of a class.
Definition vm_method.c:1142
void rb_define_alloc_func(VALUE klass, rb_alloc_func_t func)
Sets the allocator function of a class.
ID rb_check_id(volatile VALUE *namep)
Detects if the given name is already interned or not.
Definition symbol.c:1085
VALUE rb_sym2str(VALUE id)
Identical to rb_id2str(), except it takes an instance of rb_cSymbol rather than an ID.
Definition symbol.c:943
void rb_define_const(VALUE klass, const char *name, VALUE val)
Defines a Ruby level constant under a namespace.
Definition variable.c:3440
int rb_io_modestr_oflags(const char *modestr)
Identical to rb_io_modestr_fmode(), except it returns a mixture of O_ flags.
Definition io.c:6496
#define GetOpenFile
This is an old name of RB_IO_POINTER.
Definition io.h:362
VALUE rb_io_check_io(VALUE io)
Try converting an object to its IO representation using its to_io method, if any.
Definition io.c:803
VALUE rb_ractor_stderr(void)
Queries the standard error of the current Ractor that is calling this function.
Definition ractor.c:2148
void * rb_thread_call_without_gvl2(void *(*func)(void *), void *data1, rb_unblock_function_t *ubf, void *data2)
Identical to rb_thread_call_without_gvl(), except it does not interface with signals etc.
Definition thread.c:1659
void * rb_thread_call_without_gvl(void *(*func)(void *), void *data1, rb_unblock_function_t *ubf, void *data2)
Allows the passed function to run in parallel with other Ruby threads.
#define RB_NUM2INT
Just another name of rb_num2int_inline.
Definition int.h:38
#define RB_INT2NUM
Just another name of rb_int2num_inline.
Definition int.h:37
VALUE rb_sprintf(const char *fmt,...)
Ruby's extended sprintf(3).
Definition sprintf.c:1219
VALUE rb_str_catf(VALUE dst, const char *fmt,...)
Identical to rb_sprintf(), except it renders the output to the specified object rather than creating ...
Definition sprintf.c:1242
#define RB_BLOCK_CALL_FUNC_ARGLIST(yielded_arg, callback_arg)
Shim for block function parameters.
Definition iterator.h:58
VALUE rb_yield(VALUE val)
Yields the block.
Definition vm_eval.c:1357
void rb_marshal_define_compat(VALUE newclass, VALUE oldclass, VALUE(*dumper)(VALUE), VALUE(*loader)(VALUE, VALUE))
Marshal format compatibility layer.
Definition marshal.c:150
#define MEMCPY(p1, p2, type, n)
Handy macro to call memcpy.
Definition memory.h:366
#define MEMZERO(p, type, n)
Handy macro to erase a region of memory.
Definition memory.h:354
#define RB_GC_GUARD(v)
Prevents premature destruction of local objects.
Definition memory.h:161
#define NUM2MODET
Converts a C's mode_t into an instance of rb_cInteger.
Definition mode_t.h:28
VALUE rb_thread_create(type *q, void *w)
Creates a rb_cThread instance.
VALUE rb_block_call(VALUE q, ID w, int e, const VALUE *r, type *t, VALUE y)
Call a method with a block.
void rb_define_virtual_variable(const char *q, type *w, void_type *e)
Define a function-backended global variable.
VALUE rb_ensure(type *q, VALUE w, type *e, VALUE r)
An equivalent of ensure clause.
#define PIDT2NUM
Converts a C's pid_t into an instance of rb_cInteger.
Definition pid_t.h:28
#define NUM2PIDT
Converts an instance of rb_cNumeric into C's pid_t.
Definition pid_t.h:33
#define RARRAY_LEN
Just another name of rb_array_len.
Definition rarray.h:68
static int RARRAY_LENINT(VALUE ary)
Identical to rb_array_len(), except it differs for the return type.
Definition rarray.h:343
static void RARRAY_ASET(VALUE ary, long i, VALUE v)
Assigns an object in an array.
Definition rarray.h:566
#define RARRAY_AREF(a, i)
Definition rarray.h:583
#define DATA_PTR(obj)
Convenient getter macro.
Definition rdata.h:71
#define RUBY_DEFAULT_FREE
This is a value you can set to RData::dfree.
Definition rdata.h:82
#define RHASH_SIZE(h)
Queries the size of the hash.
Definition rhash.h:82
#define RHASH_EMPTY_P(h)
Checks if the hash is empty.
Definition rhash.h:92
#define SafeStringValue(v)
Definition rstring.h:104
#define StringValue(v)
Ensures that the parameter object is a String.
Definition rstring.h:72
static long RSTRING_LEN(VALUE str)
Queries the length of the string.
Definition rstring.h:484
static char * RSTRING_PTR(VALUE str)
Queries the contents pointer of the string.
Definition rstring.h:498
#define StringValueCStr(v)
Identical to StringValuePtr, except it additionally checks for the contents for viability as a C stri...
Definition rstring.h:95
#define RTYPEDDATA_DATA(v)
Convenient getter macro.
Definition rtypeddata.h:102
#define RUBY_TYPED_DEFAULT_FREE
This is a value you can set to rb_data_type_struct::dfree.
Definition rtypeddata.h:79
#define TypedData_Get_Struct(obj, type, data_type, sval)
Obtains a C struct from inside of a wrapper Ruby object.
Definition rtypeddata.h:507
#define TypedData_Make_Struct(klass, type, data_type, sval)
Identical to TypedData_Wrap_Struct, except it allocates a new data region internally instead of takin...
Definition rtypeddata.h:489
const char * rb_class2name(VALUE klass)
Queries the name of the passed class.
Definition variable.c:316
#define FilePathValue(v)
Ensures that the parameter object is a path.
Definition ruby.h:91
#define InitVM(ext)
This macro is for internal use.
Definition ruby.h:230
Scheduler APIs.
VALUE rb_fiber_scheduler_current(void)
Identical to rb_fiber_scheduler_get(), except it also returns RUBY_Qnil in case of a blocking fiber.
Definition scheduler.c:203
VALUE rb_fiber_scheduler_kernel_sleepv(VALUE scheduler, int argc, VALUE *argv)
Identical to rb_fiber_scheduler_kernel_sleep(), except it can pass multiple arguments.
Definition scheduler.c:273
VALUE rb_fiber_scheduler_process_wait(VALUE scheduler, rb_pid_t pid, int flags)
Non-blocking waitpid.
Definition scheduler.c:343
static bool RB_SPECIAL_CONST_P(VALUE obj)
Checks if the given object is of enum ruby_special_consts.
#define RTEST
This is an old name of RB_TEST.
Defines old _.
#define _(args)
This was a transition path from K&R to ANSI.
Definition stdarg.h:35
This is the struct that holds necessary info for a struct.
Definition rtypeddata.h:190
const char * wrap_struct_name
Name of structs of this kind.
Definition rtypeddata.h:197
Ruby's IO, metadata and buffers.
Definition io.h:138
int fd
file descriptor.
Definition io.h:147
VALUE tied_io_for_writing
Duplex IO object, if set.
Definition io.h:178
Definition st.h:79
Definition win32.h:698
void rb_native_mutex_lock(rb_nativethread_lock_t *lock)
Just another name of rb_nativethread_lock_lock.
void rb_native_mutex_unlock(rb_nativethread_lock_t *lock)
Just another name of rb_nativethread_lock_unlock.
#define UIDT2NUM
Converts a C's uid_t into an instance of rb_cInteger.
Definition uid_t.h:28
#define NUM2UIDT
Converts an instance of rb_cNumeric into C's uid_t.
Definition uid_t.h:33
uintptr_t ID
Type that represents a Ruby identifier such as a variable name.
Definition value.h:52
uintptr_t VALUE
Type that represents a Ruby object.
Definition value.h:40
static enum ruby_value_type RB_BUILTIN_TYPE(VALUE obj)
Queries the type of the object.
Definition value_type.h:181
static void Check_Type(VALUE v, enum ruby_value_type t)
Identical to RB_TYPE_P(), except it raises exceptions on predication failure.
Definition value_type.h:432
static bool RB_TYPE_P(VALUE obj, enum ruby_value_type t)
Queries if the given object is of given type.
Definition value_type.h:375