Ruby: process.c Source File

Ruby 3.2.5p208 (2024-07-26 revision 31d0f1a2e7dbfb60731d1f05b868e1d578cda493)

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