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