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