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