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