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