Ruby  2.7.1p83(2020-03-31revisiona0c7c23c9cec0d0ffcba012279cd652d28ad5bf3)
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, state;
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 
2895  rb_protect(rb_execarg_parent_start1, execarg_obj, &state);
2896  if (state) {
2897  execarg_parent_end(execarg_obj);
2898  after_exec(); /* restart timer thread */
2899  rb_jump_tag(state);
2900  }
2901 
2902  fail_str = eargp->use_shell ? eargp->invoke.sh.shell_script : eargp->invoke.cmd.command_name;
2903 
2904  err = exec_async_signal_safe(eargp, errmsg, sizeof(errmsg));
2905  after_exec(); /* restart timer thread */
2906 
2907  rb_exec_fail(eargp, err, errmsg);
2908  RB_GC_GUARD(execarg_obj);
2909  rb_syserr_fail_str(err, fail_str);
2911 }
2912 
2913 /*
2914  * call-seq:
2915  * exec([env,] command... [,options])
2916  *
2917  * Replaces the current process by running the given external _command_, which
2918  * can take one of the following forms:
2919  *
2920  * [<code>exec(commandline)</code>]
2921  * command line string which is passed to the standard shell
2922  * [<code>exec(cmdname, arg1, ...)</code>]
2923  * command name and one or more arguments (no shell)
2924  * [<code>exec([cmdname, argv0], arg1, ...)</code>]
2925  * command name, argv[0] and zero or more arguments (no shell)
2926  *
2927  * In the first form, the string is taken as a command line that is subject to
2928  * shell expansion before being executed.
2929  *
2930  * The standard shell always means <code>"/bin/sh"</code> on Unix-like systems,
2931  * same as <code>ENV["RUBYSHELL"]</code>
2932  * (or <code>ENV["COMSPEC"]</code> on Windows NT series), and similar.
2933  *
2934  * If the string from the first form (<code>exec("command")</code>) follows
2935  * these simple rules:
2936  *
2937  * * no meta characters
2938  * * no shell reserved word and no special built-in
2939  * * Ruby invokes the command directly without shell
2940  *
2941  * You can force shell invocation by adding ";" to the string (because ";" is
2942  * a meta character).
2943  *
2944  * Note that this behavior is observable by pid obtained
2945  * (return value of spawn() and IO#pid for IO.popen) is the pid of the invoked
2946  * command, not shell.
2947  *
2948  * In the second form (<code>exec("command1", "arg1", ...)</code>), the first
2949  * is taken as a command name and the rest are passed as parameters to command
2950  * with no shell expansion.
2951  *
2952  * In the third form (<code>exec(["command", "argv0"], "arg1", ...)</code>),
2953  * starting a two-element array at the beginning of the command, the first
2954  * element is the command to be executed, and the second argument is used as
2955  * the <code>argv[0]</code> value, which may show up in process listings.
2956  *
2957  * In order to execute the command, one of the <code>exec(2)</code> system
2958  * calls are used, so the running command may inherit some of the environment
2959  * of the original program (including open file descriptors).
2960  *
2961  * This behavior is modified by the given +env+ and +options+ parameters. See
2962  * ::spawn for details.
2963  *
2964  * If the command fails to execute (typically Errno::ENOENT when
2965  * it was not found) a SystemCallError exception is raised.
2966  *
2967  * This method modifies process attributes according to given +options+ before
2968  * <code>exec(2)</code> system call. See ::spawn for more details about the
2969  * given +options+.
2970  *
2971  * The modified attributes may be retained when <code>exec(2)</code> system
2972  * call fails.
2973  *
2974  * For example, hard resource limits are not restorable.
2975  *
2976  * Consider to create a child process using ::spawn or Kernel#system if this
2977  * is not acceptable.
2978  *
2979  * exec "echo *" # echoes list of files in current directory
2980  * # never get here
2981  *
2982  * exec "echo", "*" # echoes an asterisk
2983  * # never get here
2984  */
2985 
2986 static VALUE
2987 f_exec(int c, const VALUE *a, VALUE _)
2988 {
2989  return rb_f_exec(c, a);
2990 }
2991 
2992 #define ERRMSG(str) do { if (errmsg && 0 < errmsg_buflen) strlcpy(errmsg, (str), errmsg_buflen); } while (0)
2993 #define ERRMSG1(str, a) do { if (errmsg && 0 < errmsg_buflen) snprintf(errmsg, errmsg_buflen, (str), (a)); } while (0)
2994 #define ERRMSG2(str, a, b) do { if (errmsg && 0 < errmsg_buflen) snprintf(errmsg, errmsg_buflen, (str), (a), (b)); } while (0)
2995 
2996 static int fd_get_cloexec(int fd, char *errmsg, size_t errmsg_buflen);
2997 static int fd_set_cloexec(int fd, char *errmsg, size_t errmsg_buflen);
2998 static int fd_clear_cloexec(int fd, char *errmsg, size_t errmsg_buflen);
2999 
3000 static int
3001 save_redirect_fd(int fd, struct rb_execarg *sargp, char *errmsg, size_t errmsg_buflen)
3002 {
3003  if (sargp) {
3004  VALUE newary, redirection;
3005  int save_fd = redirect_cloexec_dup(fd), cloexec;
3006  if (save_fd == -1) {
3007  if (errno == EBADF)
3008  return 0;
3009  ERRMSG("dup");
3010  return -1;
3011  }
3012  rb_update_max_fd(save_fd);
3013  newary = sargp->fd_dup2;
3014  if (newary == Qfalse) {
3015  newary = hide_obj(rb_ary_new());
3016  sargp->fd_dup2 = newary;
3017  }
3018  cloexec = fd_get_cloexec(fd, errmsg, errmsg_buflen);
3019  redirection = hide_obj(rb_assoc_new(INT2FIX(fd), INT2FIX(save_fd)));
3020  if (cloexec) rb_ary_push(redirection, Qtrue);
3021  rb_ary_push(newary, redirection);
3022 
3023  newary = sargp->fd_close;
3024  if (newary == Qfalse) {
3025  newary = hide_obj(rb_ary_new());
3026  sargp->fd_close = newary;
3027  }
3028  rb_ary_push(newary, hide_obj(rb_assoc_new(INT2FIX(save_fd), Qnil)));
3029  }
3030 
3031  return 0;
3032 }
3033 
3034 static int
3035 intcmp(const void *a, const void *b)
3036 {
3037  return *(int*)a - *(int*)b;
3038 }
3039 
3040 static int
3041 intrcmp(const void *a, const void *b)
3042 {
3043  return *(int*)b - *(int*)a;
3044 }
3045 
3047  int oldfd;
3048  int newfd;
3051  int cloexec;
3052 };
3053 
3054 static long
3055 run_exec_dup2_tmpbuf_size(long n)
3056 {
3057  return sizeof(struct run_exec_dup2_fd_pair) * n;
3058 }
3059 
3060 /* This function should be async-signal-safe. Actually it is. */
3061 static int
3062 fd_get_cloexec(int fd, char *errmsg, size_t errmsg_buflen)
3063 {
3064 #ifdef F_GETFD
3065  int ret = 0;
3066  ret = fcntl(fd, F_GETFD); /* async-signal-safe */
3067  if (ret == -1) {
3068  ERRMSG("fcntl(F_GETFD)");
3069  return -1;
3070  }
3071  if (ret & FD_CLOEXEC) return 1;
3072 #endif
3073  return 0;
3074 }
3075 
3076 /* This function should be async-signal-safe. Actually it is. */
3077 static int
3078 fd_set_cloexec(int fd, char *errmsg, size_t errmsg_buflen)
3079 {
3080 #ifdef F_GETFD
3081  int ret = 0;
3082  ret = fcntl(fd, F_GETFD); /* async-signal-safe */
3083  if (ret == -1) {
3084  ERRMSG("fcntl(F_GETFD)");
3085  return -1;
3086  }
3087  if (!(ret & FD_CLOEXEC)) {
3088  ret |= FD_CLOEXEC;
3089  ret = fcntl(fd, F_SETFD, ret); /* async-signal-safe */
3090  if (ret == -1) {
3091  ERRMSG("fcntl(F_SETFD)");
3092  return -1;
3093  }
3094  }
3095 #endif
3096  return 0;
3097 }
3098 
3099 /* This function should be async-signal-safe. Actually it is. */
3100 static int
3101 fd_clear_cloexec(int fd, char *errmsg, size_t errmsg_buflen)
3102 {
3103 #ifdef F_GETFD
3104  int ret;
3105  ret = fcntl(fd, F_GETFD); /* async-signal-safe */
3106  if (ret == -1) {
3107  ERRMSG("fcntl(F_GETFD)");
3108  return -1;
3109  }
3110  if (ret & FD_CLOEXEC) {
3111  ret &= ~FD_CLOEXEC;
3112  ret = fcntl(fd, F_SETFD, ret); /* async-signal-safe */
3113  if (ret == -1) {
3114  ERRMSG("fcntl(F_SETFD)");
3115  return -1;
3116  }
3117  }
3118 #endif
3119  return 0;
3120 }
3121 
3122 /* This function should be async-signal-safe when sargp is NULL. Hopefully it is. */
3123 static int
3124 run_exec_dup2(VALUE ary, VALUE tmpbuf, struct rb_execarg *sargp, char *errmsg, size_t errmsg_buflen)
3125 {
3126  long n, i;
3127  int ret;
3128  int extra_fd = -1;
3129  struct rb_imemo_tmpbuf_struct *buf = (void *)tmpbuf;
3130  struct run_exec_dup2_fd_pair *pairs = (void *)buf->ptr;
3131 
3132  n = RARRAY_LEN(ary);
3133 
3134  /* initialize oldfd and newfd: O(n) */
3135  for (i = 0; i < n; i++) {
3136  VALUE elt = RARRAY_AREF(ary, i);
3137  pairs[i].oldfd = FIX2INT(RARRAY_AREF(elt, 1));
3138  pairs[i].newfd = FIX2INT(RARRAY_AREF(elt, 0)); /* unique */
3139  pairs[i].cloexec = RARRAY_LEN(elt) > 2 && RTEST(RARRAY_AREF(elt, 2));
3140  pairs[i].older_index = -1;
3141  }
3142 
3143  /* sort the table by oldfd: O(n log n) */
3144  if (!sargp)
3145  qsort(pairs, n, sizeof(struct run_exec_dup2_fd_pair), intcmp); /* hopefully async-signal-safe */
3146  else
3147  qsort(pairs, n, sizeof(struct run_exec_dup2_fd_pair), intrcmp);
3148 
3149  /* initialize older_index and num_newer: O(n log n) */
3150  for (i = 0; i < n; i++) {
3151  int newfd = pairs[i].newfd;
3152  struct run_exec_dup2_fd_pair key, *found;
3153  key.oldfd = newfd;
3154  found = bsearch(&key, pairs, n, sizeof(struct run_exec_dup2_fd_pair), intcmp); /* hopefully async-signal-safe */
3155  pairs[i].num_newer = 0;
3156  if (found) {
3157  while (pairs < found && (found-1)->oldfd == newfd)
3158  found--;
3159  while (found < pairs+n && found->oldfd == newfd) {
3160  pairs[i].num_newer++;
3161  found->older_index = i;
3162  found++;
3163  }
3164  }
3165  }
3166 
3167  /* non-cyclic redirection: O(n) */
3168  for (i = 0; i < n; i++) {
3169  long j = i;
3170  while (j != -1 && pairs[j].oldfd != -1 && pairs[j].num_newer == 0) {
3171  if (save_redirect_fd(pairs[j].newfd, sargp, errmsg, errmsg_buflen) < 0) /* async-signal-safe */
3172  goto fail;
3173  ret = redirect_dup2(pairs[j].oldfd, pairs[j].newfd); /* async-signal-safe */
3174  if (ret == -1) {
3175  ERRMSG("dup2");
3176  goto fail;
3177  }
3178  if (pairs[j].cloexec &&
3179  fd_set_cloexec(pairs[j].newfd, errmsg, errmsg_buflen)) {
3180  goto fail;
3181  }
3182  rb_update_max_fd(pairs[j].newfd); /* async-signal-safe but don't need to call it in a child process. */
3183  pairs[j].oldfd = -1;
3184  j = pairs[j].older_index;
3185  if (j != -1)
3186  pairs[j].num_newer--;
3187  }
3188  }
3189 
3190  /* cyclic redirection: O(n) */
3191  for (i = 0; i < n; i++) {
3192  long j;
3193  if (pairs[i].oldfd == -1)
3194  continue;
3195  if (pairs[i].oldfd == pairs[i].newfd) { /* self cycle */
3196  if (fd_clear_cloexec(pairs[i].oldfd, errmsg, errmsg_buflen) == -1) /* async-signal-safe */
3197  goto fail;
3198  pairs[i].oldfd = -1;
3199  continue;
3200  }
3201  if (extra_fd == -1) {
3202  extra_fd = redirect_dup(pairs[i].oldfd); /* async-signal-safe */
3203  if (extra_fd == -1) {
3204  ERRMSG("dup");
3205  goto fail;
3206  }
3207  rb_update_max_fd(extra_fd);
3208  }
3209  else {
3210  ret = redirect_dup2(pairs[i].oldfd, extra_fd); /* async-signal-safe */
3211  if (ret == -1) {
3212  ERRMSG("dup2");
3213  goto fail;
3214  }
3215  rb_update_max_fd(extra_fd);
3216  }
3217  pairs[i].oldfd = extra_fd;
3218  j = pairs[i].older_index;
3219  pairs[i].older_index = -1;
3220  while (j != -1) {
3221  ret = redirect_dup2(pairs[j].oldfd, pairs[j].newfd); /* async-signal-safe */
3222  if (ret == -1) {
3223  ERRMSG("dup2");
3224  goto fail;
3225  }
3226  rb_update_max_fd(ret);
3227  pairs[j].oldfd = -1;
3228  j = pairs[j].older_index;
3229  }
3230  }
3231  if (extra_fd != -1) {
3232  ret = redirect_close(extra_fd); /* async-signal-safe */
3233  if (ret == -1) {
3234  ERRMSG("close");
3235  goto fail;
3236  }
3237  }
3238 
3239  return 0;
3240 
3241  fail:
3242  return -1;
3243 }
3244 
3245 /* This function should be async-signal-safe. Actually it is. */
3246 static int
3247 run_exec_close(VALUE ary, char *errmsg, size_t errmsg_buflen)
3248 {
3249  long i;
3250  int ret;
3251 
3252  for (i = 0; i < RARRAY_LEN(ary); i++) {
3253  VALUE elt = RARRAY_AREF(ary, i);
3254  int fd = FIX2INT(RARRAY_AREF(elt, 0));
3255  ret = redirect_close(fd); /* async-signal-safe */
3256  if (ret == -1) {
3257  ERRMSG("close");
3258  return -1;
3259  }
3260  }
3261  return 0;
3262 }
3263 
3264 /* This function should be async-signal-safe when sargp is NULL. Actually it is. */
3265 static int
3266 run_exec_dup2_child(VALUE ary, struct rb_execarg *sargp, char *errmsg, size_t errmsg_buflen)
3267 {
3268  long i;
3269  int ret;
3270 
3271  for (i = 0; i < RARRAY_LEN(ary); i++) {
3272  VALUE elt = RARRAY_AREF(ary, i);
3273  int newfd = FIX2INT(RARRAY_AREF(elt, 0));
3274  int oldfd = FIX2INT(RARRAY_AREF(elt, 1));
3275 
3276  if (save_redirect_fd(newfd, sargp, errmsg, errmsg_buflen) < 0) /* async-signal-safe */
3277  return -1;
3278  ret = redirect_dup2(oldfd, newfd); /* async-signal-safe */
3279  if (ret == -1) {
3280  ERRMSG("dup2");
3281  return -1;
3282  }
3284  }
3285  return 0;
3286 }
3287 
3288 #ifdef HAVE_SETPGID
3289 /* This function should be async-signal-safe when sargp is NULL. Actually it is. */
3290 static int
3291 run_exec_pgroup(const struct rb_execarg *eargp, struct rb_execarg *sargp, char *errmsg, size_t errmsg_buflen)
3292 {
3293  /*
3294  * If FD_CLOEXEC is available, rb_fork_async_signal_safe waits the child's execve.
3295  * So setpgid is done in the child when rb_fork_async_signal_safe is returned in
3296  * the parent.
3297  * No race condition, even without setpgid from the parent.
3298  * (Is there an environment which has setpgid but no FD_CLOEXEC?)
3299  */
3300  int ret;
3301  rb_pid_t pgroup;
3302 
3303  pgroup = eargp->pgroup_pgid;
3304  if (pgroup == -1)
3305  return 0;
3306 
3307  if (sargp) {
3308  /* maybe meaningless with no fork environment... */
3309  sargp->pgroup_given = 1;
3310  sargp->pgroup_pgid = getpgrp();
3311  }
3312 
3313  if (pgroup == 0) {
3314  pgroup = getpid(); /* async-signal-safe */
3315  }
3316  ret = setpgid(getpid(), pgroup); /* async-signal-safe */
3317  if (ret == -1) ERRMSG("setpgid");
3318  return ret;
3319 }
3320 #endif
3321 
3322 #if defined(HAVE_SETRLIMIT) && defined(RLIM2NUM)
3323 /* This function should be async-signal-safe when sargp is NULL. Hopefully it is. */
3324 static int
3325 run_exec_rlimit(VALUE ary, struct rb_execarg *sargp, char *errmsg, size_t errmsg_buflen)
3326 {
3327  long i;
3328  for (i = 0; i < RARRAY_LEN(ary); i++) {
3329  VALUE elt = RARRAY_AREF(ary, i);
3330  int rtype = NUM2INT(RARRAY_AREF(elt, 0));
3331  struct rlimit rlim;
3332  if (sargp) {
3333  VALUE tmp, newary;
3334  if (getrlimit(rtype, &rlim) == -1) {
3335  ERRMSG("getrlimit");
3336  return -1;
3337  }
3338  tmp = hide_obj(rb_ary_new3(3, RARRAY_AREF(elt, 0),
3339  RLIM2NUM(rlim.rlim_cur),
3340  RLIM2NUM(rlim.rlim_max)));
3341  if (sargp->rlimit_limits == Qfalse)
3342  newary = sargp->rlimit_limits = hide_obj(rb_ary_new());
3343  else
3344  newary = sargp->rlimit_limits;
3345  rb_ary_push(newary, tmp);
3346  }
3347  rlim.rlim_cur = NUM2RLIM(RARRAY_AREF(elt, 1));
3348  rlim.rlim_max = NUM2RLIM(RARRAY_AREF(elt, 2));
3349  if (setrlimit(rtype, &rlim) == -1) { /* hopefully async-signal-safe */
3350  ERRMSG("setrlimit");
3351  return -1;
3352  }
3353  }
3354  return 0;
3355 }
3356 #endif
3357 
3358 #if !defined(HAVE_WORKING_FORK)
3359 static VALUE
3360 save_env_i(RB_BLOCK_CALL_FUNC_ARGLIST(i, ary))
3361 {
3362  rb_ary_push(ary, hide_obj(rb_ary_dup(argv[0])));
3363  return Qnil;
3364 }
3365 
3366 static void
3367 save_env(struct rb_execarg *sargp)
3368 {
3369  if (!sargp)
3370  return;
3371  if (sargp->env_modification == Qfalse) {
3372  VALUE env = rb_const_get(rb_cObject, id_ENV);
3373  if (RTEST(env)) {
3374  VALUE ary = hide_obj(rb_ary_new());
3375  rb_block_call(env, idEach, 0, 0, save_env_i,
3376  (VALUE)ary);
3377  sargp->env_modification = ary;
3378  }
3379  sargp->unsetenv_others_given = 1;
3380  sargp->unsetenv_others_do = 1;
3381  }
3382 }
3383 #endif
3384 
3385 #ifdef _WIN32
3386 #undef chdir
3387 #define chdir(p) rb_w32_uchdir(p)
3388 #endif
3389 
3390 /* This function should be async-signal-safe when sargp is NULL. Hopefully it is. */
3391 int
3392 rb_execarg_run_options(const struct rb_execarg *eargp, struct rb_execarg *sargp, char *errmsg, size_t errmsg_buflen)
3393 {
3394  VALUE obj;
3395 
3396  if (sargp) {
3397  /* assume that sargp is always NULL on fork-able environments */
3398  MEMZERO(sargp, struct rb_execarg, 1);
3399  sargp->redirect_fds = Qnil;
3400  }
3401 
3402 #ifdef HAVE_SETPGID
3403  if (eargp->pgroup_given) {
3404  if (run_exec_pgroup(eargp, sargp, errmsg, errmsg_buflen) == -1) /* async-signal-safe */
3405  return -1;
3406  }
3407 #endif
3408 
3409 #if defined(HAVE_SETRLIMIT) && defined(RLIM2NUM)
3410  obj = eargp->rlimit_limits;
3411  if (obj != Qfalse) {
3412  if (run_exec_rlimit(obj, sargp, errmsg, errmsg_buflen) == -1) /* hopefully async-signal-safe */
3413  return -1;
3414  }
3415 #endif
3416 
3417 #if !defined(HAVE_WORKING_FORK)
3418  if (eargp->unsetenv_others_given && eargp->unsetenv_others_do) {
3419  save_env(sargp);
3420  rb_env_clear();
3421  }
3422 
3423  obj = eargp->env_modification;
3424  if (obj != Qfalse) {
3425  long i;
3426  save_env(sargp);
3427  for (i = 0; i < RARRAY_LEN(obj); i++) {
3428  VALUE pair = RARRAY_AREF(obj, i);
3429  VALUE key = RARRAY_AREF(pair, 0);
3430  VALUE val = RARRAY_AREF(pair, 1);
3431  if (NIL_P(val))
3433  else
3435  }
3436  }
3437 #endif
3438 
3439  if (eargp->umask_given) {
3440  mode_t mask = eargp->umask_mask;
3441  mode_t oldmask = umask(mask); /* never fail */ /* async-signal-safe */
3442  if (sargp) {
3443  sargp->umask_given = 1;
3444  sargp->umask_mask = oldmask;
3445  }
3446  }
3447 
3448  obj = eargp->fd_dup2;
3449  if (obj != Qfalse) {
3450  if (run_exec_dup2(obj, eargp->dup2_tmpbuf, sargp, errmsg, errmsg_buflen) == -1) /* hopefully async-signal-safe */
3451  return -1;
3452  }
3453 
3454  obj = eargp->fd_close;
3455  if (obj != Qfalse) {
3456  if (sargp)
3457  rb_warn("cannot close fd before spawn");
3458  else {
3459  if (run_exec_close(obj, errmsg, errmsg_buflen) == -1) /* async-signal-safe */
3460  return -1;
3461  }
3462  }
3463 
3464 #ifdef HAVE_WORKING_FORK
3465  if (eargp->close_others_do) {
3466  rb_close_before_exec(3, eargp->close_others_maxhint, eargp->redirect_fds); /* async-signal-safe */
3467  }
3468 #endif
3469 
3470  obj = eargp->fd_dup2_child;
3471  if (obj != Qfalse) {
3472  if (run_exec_dup2_child(obj, sargp, errmsg, errmsg_buflen) == -1) /* async-signal-safe */
3473  return -1;
3474  }
3475 
3476  if (eargp->chdir_given) {
3477  if (sargp) {
3478  char *cwd = ruby_getcwd();
3479  sargp->chdir_given = 1;
3480  sargp->chdir_dir = hide_obj(rb_str_new2(cwd));
3481  xfree(cwd);
3482  }
3483  if (chdir(RSTRING_PTR(eargp->chdir_dir)) == -1) { /* async-signal-safe */
3484  ERRMSG("chdir");
3485  return -1;
3486  }
3487  }
3488 
3489 #ifdef HAVE_SETGID
3490  if (eargp->gid_given) {
3491  if (setgid(eargp->gid) < 0) {
3492  ERRMSG("setgid");
3493  return -1;
3494  }
3495  }
3496 #endif
3497 #ifdef HAVE_SETUID
3498  if (eargp->uid_given) {
3499  if (setuid(eargp->uid) < 0) {
3500  ERRMSG("setuid");
3501  return -1;
3502  }
3503  }
3504 #endif
3505 
3506  if (sargp) {
3507  VALUE ary = sargp->fd_dup2;
3508  if (ary != Qfalse) {
3509  rb_execarg_allocate_dup2_tmpbuf(sargp, RARRAY_LEN(ary));
3510  }
3511  }
3512  {
3513  int preserve = errno;
3514  stdfd_clear_nonblock();
3515  errno = preserve;
3516  }
3517 
3518  return 0;
3519 }
3520 
3521 /* This function should be async-signal-safe. Hopefully it is. */
3522 int
3523 rb_exec_async_signal_safe(const struct rb_execarg *eargp, char *errmsg, size_t errmsg_buflen)
3524 {
3525  errno = exec_async_signal_safe(eargp, errmsg, errmsg_buflen);
3526  return -1;
3527 }
3528 
3529 static int
3530 exec_async_signal_safe(const struct rb_execarg *eargp, char *errmsg, size_t errmsg_buflen)
3531 {
3532 #if !defined(HAVE_WORKING_FORK)
3533  struct rb_execarg sarg, *const sargp = &sarg;
3534 #else
3535  struct rb_execarg *const sargp = NULL;
3536 #endif
3537  int err;
3538 
3539  if (rb_execarg_run_options(eargp, sargp, errmsg, errmsg_buflen) < 0) { /* hopefully async-signal-safe */
3540  return errno;
3541  }
3542 
3543  if (eargp->use_shell) {
3544  err = proc_exec_sh(RSTRING_PTR(eargp->invoke.sh.shell_script), eargp->envp_str); /* async-signal-safe */
3545  }
3546  else {
3547  char *abspath = NULL;
3548  if (!NIL_P(eargp->invoke.cmd.command_abspath))
3549  abspath = RSTRING_PTR(eargp->invoke.cmd.command_abspath);
3550  err = proc_exec_cmd(abspath, eargp->invoke.cmd.argv_str, eargp->envp_str); /* async-signal-safe */
3551  }
3552 #if !defined(HAVE_WORKING_FORK)
3553  rb_execarg_run_options(sargp, NULL, errmsg, errmsg_buflen);
3554 #endif
3555 
3556  return err;
3557 }
3558 
3559 #ifdef HAVE_WORKING_FORK
3560 /* This function should be async-signal-safe. Hopefully it is. */
3561 static int
3562 rb_exec_atfork(void* arg, char *errmsg, size_t errmsg_buflen)
3563 {
3564  return rb_exec_async_signal_safe(arg, errmsg, errmsg_buflen); /* hopefully async-signal-safe */
3565 }
3566 
3567 #if SIZEOF_INT == SIZEOF_LONG
3568 #define proc_syswait (VALUE (*)(VALUE))rb_syswait
3569 #else
3570 static VALUE
3571 proc_syswait(VALUE pid)
3572 {
3573  rb_syswait((int)pid);
3574  return Qnil;
3575 }
3576 #endif
3577 
3578 static int
3579 move_fds_to_avoid_crash(int *fdp, int n, VALUE fds)
3580 {
3581  int min = 0;
3582  int i;
3583  for (i = 0; i < n; i++) {
3584  int ret;
3585  while (RTEST(rb_hash_lookup(fds, INT2FIX(fdp[i])))) {
3586  if (min <= fdp[i])
3587  min = fdp[i]+1;
3588  while (RTEST(rb_hash_lookup(fds, INT2FIX(min))))
3589  min++;
3590  ret = rb_cloexec_fcntl_dupfd(fdp[i], min);
3591  if (ret == -1)
3592  return -1;
3593  rb_update_max_fd(ret);
3594  close(fdp[i]);
3595  fdp[i] = ret;
3596  }
3597  }
3598  return 0;
3599 }
3600 
3601 static int
3602 pipe_nocrash(int filedes[2], VALUE fds)
3603 {
3604  int ret;
3605  ret = rb_pipe(filedes);
3606  if (ret == -1)
3607  return -1;
3608  if (RTEST(fds)) {
3609  int save = errno;
3610  if (move_fds_to_avoid_crash(filedes, 2, fds) == -1) {
3611  close(filedes[0]);
3612  close(filedes[1]);
3613  return -1;
3614  }
3615  errno = save;
3616  }
3617  return ret;
3618 }
3619 
3620 #ifndef O_BINARY
3621 #define O_BINARY 0
3622 #endif
3623 
3624 static VALUE
3625 rb_thread_sleep_that_takes_VALUE_as_sole_argument(VALUE n)
3626 {
3628  return Qundef;
3629 }
3630 
3631 static int
3632 handle_fork_error(int err, int *status, int *ep, volatile int *try_gc_p)
3633 {
3634  int state = 0;
3635 
3636  switch (err) {
3637  case ENOMEM:
3638  if ((*try_gc_p)-- > 0 && !rb_during_gc()) {
3639  rb_gc();
3640  return 0;
3641  }
3642  break;
3643  case EAGAIN:
3644 #if defined(EWOULDBLOCK) && EWOULDBLOCK != EAGAIN
3645  case EWOULDBLOCK:
3646 #endif
3647  if (!status && !ep) {
3648  rb_thread_sleep(1);
3649  return 0;
3650  }
3651  else {
3652  rb_protect(rb_thread_sleep_that_takes_VALUE_as_sole_argument, INT2FIX(1), &state);
3653  if (status) *status = state;
3654  if (!state) return 0;
3655  }
3656  break;
3657  }
3658  if (ep) {
3659  close(ep[0]);
3660  close(ep[1]);
3661  errno = err;
3662  }
3663  if (state && !status) rb_jump_tag(state);
3664  return -1;
3665 }
3666 
3667 #define prefork() ( \
3668  rb_io_flush(rb_stdout), \
3669  rb_io_flush(rb_stderr) \
3670  )
3671 
3672 /*
3673  * Forks child process, and returns the process ID in the parent
3674  * process.
3675  *
3676  * If +status+ is given, protects from any exceptions and sets the
3677  * jump status to it, and returns -1. If failed to fork new process
3678  * but no exceptions occurred, sets 0 to it. Otherwise, if forked
3679  * successfully, the value of +status+ is undetermined.
3680  *
3681  * In the child process, just returns 0 if +chfunc+ is +NULL+.
3682  * Otherwise +chfunc+ will be called with +charg+, and then the child
3683  * process exits with +EXIT_SUCCESS+ when it returned zero.
3684  *
3685  * In the case of the function is called and returns non-zero value,
3686  * the child process exits with non-+EXIT_SUCCESS+ value (normally
3687  * 127). And, on the platforms where +FD_CLOEXEC+ is available,
3688  * +errno+ is propagated to the parent process, and this function
3689  * returns -1 in the parent process. On the other platforms, just
3690  * returns pid.
3691  *
3692  * If fds is not Qnil, internal pipe for the errno propagation is
3693  * arranged to avoid conflicts of the hash keys in +fds+.
3694  *
3695  * +chfunc+ must not raise any exceptions.
3696  */
3697 
3698 static ssize_t
3699 write_retry(int fd, const void *buf, size_t len)
3700 {
3701  ssize_t w;
3702 
3703  do {
3704  w = write(fd, buf, len);
3705  } while (w < 0 && errno == EINTR);
3706 
3707  return w;
3708 }
3709 
3710 static ssize_t
3711 read_retry(int fd, void *buf, size_t len)
3712 {
3713  ssize_t r;
3714 
3715  if (set_blocking(fd) != 0) {
3716 #ifndef _WIN32
3717  rb_async_bug_errno("set_blocking failed reading child error", errno);
3718 #endif
3719  }
3720 
3721  do {
3722  r = read(fd, buf, len);
3723  } while (r < 0 && errno == EINTR);
3724 
3725  return r;
3726 }
3727 
3728 static void
3729 send_child_error(int fd, char *errmsg, size_t errmsg_buflen)
3730 {
3731  int err;
3732 
3733  err = errno;
3734  if (write_retry(fd, &err, sizeof(err)) < 0) err = errno;
3735  if (errmsg && 0 < errmsg_buflen) {
3736  errmsg[errmsg_buflen-1] = '\0';
3737  errmsg_buflen = strlen(errmsg);
3738  if (errmsg_buflen > 0 && write_retry(fd, errmsg, errmsg_buflen) < 0)
3739  err = errno;
3740  }
3741 }
3742 
3743 static int
3744 recv_child_error(int fd, int *errp, char *errmsg, size_t errmsg_buflen)
3745 {
3746  int err;
3747  ssize_t size;
3748  if ((size = read_retry(fd, &err, sizeof(err))) < 0) {
3749  err = errno;
3750  }
3751  *errp = err;
3752  if (size == sizeof(err) &&
3753  errmsg && 0 < errmsg_buflen) {
3754  ssize_t ret = read_retry(fd, errmsg, errmsg_buflen-1);
3755  if (0 <= ret) {
3756  errmsg[ret] = '\0';
3757  }
3758  }
3759  close(fd);
3760  return size != 0;
3761 }
3762 
3763 #ifdef HAVE_WORKING_VFORK
3764 #if !defined(HAVE_GETRESUID) && defined(HAVE_GETUIDX)
3765 /* AIX 7.1 */
3766 static int
3767 getresuid(rb_uid_t *ruid, rb_uid_t *euid, rb_uid_t *suid)
3768 {
3769  rb_uid_t ret;
3770 
3771  *ruid = getuid();
3772  *euid = geteuid();
3773  ret = getuidx(ID_SAVED);
3774  if (ret == (rb_uid_t)-1)
3775  return -1;
3776  *suid = ret;
3777  return 0;
3778 }
3779 #define HAVE_GETRESUID
3780 #endif
3781 
3782 #if !defined(HAVE_GETRESGID) && defined(HAVE_GETGIDX)
3783 /* AIX 7.1 */
3784 static int
3785 getresgid(rb_gid_t *rgid, rb_gid_t *egid, rb_gid_t *sgid)
3786 {
3787  rb_gid_t ret;
3788 
3789  *rgid = getgid();
3790  *egid = getegid();
3791  ret = getgidx(ID_SAVED);
3792  if (ret == (rb_gid_t)-1)
3793  return -1;
3794  *sgid = ret;
3795  return 0;
3796 }
3797 #define HAVE_GETRESGID
3798 #endif
3799 
3800 static int
3801 has_privilege(void)
3802 {
3803  /*
3804  * has_privilege() is used to choose vfork() or fork().
3805  *
3806  * If the process has privilege, the parent process or
3807  * the child process can change UID/GID.
3808  * If vfork() is used to create the child process and
3809  * the parent or child process change effective UID/GID,
3810  * different privileged processes shares memory.
3811  * It is a bad situation.
3812  * So, fork() should be used.
3813  */
3814 
3815  rb_uid_t ruid, euid;
3816  rb_gid_t rgid, egid;
3817 
3818 #if defined HAVE_ISSETUGID
3819  if (issetugid())
3820  return 1;
3821 #endif
3822 
3823 #ifdef HAVE_GETRESUID
3824  {
3825  int ret;
3826  rb_uid_t suid;
3827  ret = getresuid(&ruid, &euid, &suid);
3828  if (ret == -1)
3829  rb_sys_fail("getresuid(2)");
3830  if (euid != suid)
3831  return 1;
3832  }
3833 #else
3834  ruid = getuid();
3835  euid = geteuid();
3836 #endif
3837 
3838  if (euid == 0 || euid != ruid)
3839  return 1;
3840 
3841 #ifdef HAVE_GETRESGID
3842  {
3843  int ret;
3844  rb_gid_t sgid;
3845  ret = getresgid(&rgid, &egid, &sgid);
3846  if (ret == -1)
3847  rb_sys_fail("getresgid(2)");
3848  if (egid != sgid)
3849  return 1;
3850  }
3851 #else
3852  rgid = getgid();
3853  egid = getegid();
3854 #endif
3855 
3856  if (egid != rgid)
3857  return 1;
3858 
3859  return 0;
3860 }
3861 #endif
3862 
3863 struct child_handler_disabler_state
3864 {
3865  sigset_t sigmask;
3866 };
3867 
3868 static void
3869 disable_child_handler_before_fork(struct child_handler_disabler_state *old)
3870 {
3871  int ret;
3872  sigset_t all;
3873 
3874 #ifdef HAVE_PTHREAD_SIGMASK
3875  ret = sigfillset(&all);
3876  if (ret == -1)
3877  rb_sys_fail("sigfillset");
3878 
3879  ret = pthread_sigmask(SIG_SETMASK, &all, &old->sigmask); /* not async-signal-safe */
3880  if (ret != 0) {
3881  rb_syserr_fail(ret, "pthread_sigmask");
3882  }
3883 #else
3884 # pragma GCC warning "pthread_sigmask on fork is not available. potentially dangerous"
3885 #endif
3886 }
3887 
3888 static void
3889 disable_child_handler_fork_parent(struct child_handler_disabler_state *old)
3890 {
3891  int ret;
3892 
3893 #ifdef HAVE_PTHREAD_SIGMASK
3894  ret = pthread_sigmask(SIG_SETMASK, &old->sigmask, NULL); /* not async-signal-safe */
3895  if (ret != 0) {
3896  rb_syserr_fail(ret, "pthread_sigmask");
3897  }
3898 #else
3899 # pragma GCC warning "pthread_sigmask on fork is not available. potentially dangerous"
3900 #endif
3901 }
3902 
3903 /* This function should be async-signal-safe. Actually it is. */
3904 static int
3905 disable_child_handler_fork_child(struct child_handler_disabler_state *old, char *errmsg, size_t errmsg_buflen)
3906 {
3907  int sig;
3908  int ret;
3909 
3910  for (sig = 1; sig < NSIG; sig++) {
3911  sig_t handler = signal(sig, SIG_DFL);
3912 
3913  if (handler == SIG_ERR && errno == EINVAL) {
3914  continue; /* Ignore invalid signal number */
3915  }
3916  if (handler == SIG_ERR) {
3917  ERRMSG("signal to obtain old action");
3918  return -1;
3919  }
3920 #ifdef SIGPIPE
3921  if (sig == SIGPIPE) {
3922  continue;
3923  }
3924 #endif
3925  /* it will be reset to SIG_DFL at execve time, instead */
3926  if (handler == SIG_IGN) {
3927  signal(sig, SIG_IGN);
3928  }
3929  }
3930 
3931  /* non-Ruby child process, ensure cmake can see SIGCHLD */
3932  sigemptyset(&old->sigmask);
3933  ret = sigprocmask(SIG_SETMASK, &old->sigmask, NULL); /* async-signal-safe */
3934  if (ret != 0) {
3935  ERRMSG("sigprocmask");
3936  return -1;
3937  }
3938  return 0;
3939 }
3940 
3942 #ifdef __GNUC__
3943 COMPILER_WARNING_IGNORED(-Wdeprecated-declarations)
3944 #endif
3945 static rb_pid_t
3946 retry_fork_async_signal_safe(int *status, int *ep,
3947  int (*chfunc)(void*, char *, size_t), void *charg,
3948  char *errmsg, size_t errmsg_buflen,
3949  struct waitpid_state *w)
3950 {
3951  rb_pid_t pid;
3952  volatile int try_gc = 1;
3953  struct child_handler_disabler_state old;
3954  int err;
3955  rb_nativethread_lock_t *const volatile waitpid_lock_init =
3956  (w && WAITPID_USE_SIGCHLD) ? &GET_VM()->waitpid_lock : 0;
3957 
3958  while (1) {
3959  rb_nativethread_lock_t *waitpid_lock = waitpid_lock_init;
3960  prefork();
3961  disable_child_handler_before_fork(&old);
3962  if (waitpid_lock) {
3963  rb_native_mutex_lock(waitpid_lock);
3964  }
3965 #ifdef HAVE_WORKING_VFORK
3966  if (!has_privilege())
3967  pid = vfork();
3968  else
3969  pid = fork();
3970 #else
3971  pid = fork();
3972 #endif
3973  if (pid == 0) {/* fork succeed, child process */
3974  int ret;
3975  close(ep[0]);
3976  ret = disable_child_handler_fork_child(&old, errmsg, errmsg_buflen); /* async-signal-safe */
3977  if (ret == 0) {
3978  ret = chfunc(charg, errmsg, errmsg_buflen);
3979  if (!ret) _exit(EXIT_SUCCESS);
3980  }
3981  send_child_error(ep[1], errmsg, errmsg_buflen);
3982 #if EXIT_SUCCESS == 127
3984 #else
3985  _exit(127);
3986 #endif
3987  }
3988  err = errno;
3989  waitpid_lock = waitpid_lock_init;
3990  if (waitpid_lock) {
3991  if (pid > 0 && w != WAITPID_LOCK_ONLY) {
3992  w->pid = pid;
3993  list_add(&GET_VM()->waiting_pids, &w->wnode);
3994  }
3995  rb_native_mutex_unlock(waitpid_lock);
3996  }
3997  disable_child_handler_fork_parent(&old);
3998  if (0 < pid) /* fork succeed, parent process */
3999  return pid;
4000  /* fork failed */
4001  if (handle_fork_error(err, status, ep, &try_gc))
4002  return -1;
4003  }
4004 }
4006 
4007 static rb_pid_t
4008 fork_check_err(int *status, int (*chfunc)(void*, char *, size_t), void *charg,
4009  VALUE fds, char *errmsg, size_t errmsg_buflen,
4010  struct rb_execarg *eargp)
4011 {
4012  rb_pid_t pid;
4013  int err;
4014  int ep[2];
4015  int error_occurred;
4016  struct waitpid_state *w;
4017 
4018  w = eargp && eargp->waitpid_state ? eargp->waitpid_state : 0;
4019 
4020  if (status) *status = 0;
4021 
4022  if (pipe_nocrash(ep, fds)) return -1;
4023  pid = retry_fork_async_signal_safe(status, ep, chfunc, charg,
4024  errmsg, errmsg_buflen, w);
4025  if (pid < 0)
4026  return pid;
4027  close(ep[1]);
4028  error_occurred = recv_child_error(ep[0], &err, errmsg, errmsg_buflen);
4029  if (error_occurred) {
4030  if (status) {
4031  VM_ASSERT((w == 0 || w == WAITPID_LOCK_ONLY) &&
4032  "only used by extensions");
4033  rb_protect(proc_syswait, (VALUE)pid, status);
4034  }
4035  else if (!w) {
4036  rb_syswait(pid);
4037  }
4038  errno = err;
4039  return -1;
4040  }
4041  return pid;
4042 }
4043 
4044 /*
4045  * The "async_signal_safe" name is a lie, but it is used by pty.c and
4046  * maybe other exts. fork() is not async-signal-safe due to pthread_atfork
4047  * and future POSIX revisions will remove it from a list of signal-safe
4048  * functions. rb_waitpid is not async-signal-safe since MJIT, either.
4049  * For our purposes, we do not need async-signal-safety, here
4050  */
4051 rb_pid_t
4053  int (*chfunc)(void*, char *, size_t), void *charg,
4054  VALUE fds, char *errmsg, size_t errmsg_buflen)
4055 {
4056  return fork_check_err(status, chfunc, charg, fds, errmsg, errmsg_buflen, 0);
4057 }
4058 
4060 #ifdef __GNUC__
4061 COMPILER_WARNING_IGNORED(-Wdeprecated-declarations)
4062 #endif
4063 rb_pid_t
4064 rb_fork_ruby(int *status)
4065 {
4066  rb_pid_t pid;
4067  int try_gc = 1, err;
4068  struct child_handler_disabler_state old;
4069 
4070  if (status) *status = 0;
4071 
4072  while (1) {
4073  prefork();
4074  if (mjit_enabled) mjit_pause(false); // Don't leave locked mutex to child. Note: child_handler must be enabled to pause MJIT.
4075  disable_child_handler_before_fork(&old);
4076  before_fork_ruby();
4077  pid = fork();
4078  err = errno;
4079  after_fork_ruby();
4080  disable_child_handler_fork_parent(&old); /* yes, bad name */
4081  if (mjit_enabled && pid > 0) mjit_resume(); /* child (pid == 0) is cared by rb_thread_atfork */
4082  if (pid >= 0) /* fork succeed */
4083  return pid;
4084  /* fork failed */
4085  if (handle_fork_error(err, status, NULL, &try_gc))
4086  return -1;
4087  }
4088 }
4090 
4091 #endif
4092 
4093 #if defined(HAVE_WORKING_FORK) && !defined(CANNOT_FORK_WITH_PTHREAD)
4094 /*
4095  * call-seq:
4096  * Kernel.fork [{ block }] -> integer or nil
4097  * Process.fork [{ block }] -> integer or nil
4098  *
4099  * Creates a subprocess. If a block is specified, that block is run
4100  * in the subprocess, and the subprocess terminates with a status of
4101  * zero. Otherwise, the +fork+ call returns twice, once in the
4102  * parent, returning the process ID of the child, and once in the
4103  * child, returning _nil_. The child process can exit using
4104  * Kernel.exit! to avoid running any <code>at_exit</code>
4105  * functions. The parent process should use Process.wait to collect
4106  * the termination statuses of its children or use Process.detach to
4107  * register disinterest in their status; otherwise, the operating
4108  * system may accumulate zombie processes.
4109  *
4110  * The thread calling fork is the only thread in the created child process.
4111  * fork doesn't copy other threads.
4112  *
4113  * If fork is not usable, Process.respond_to?(:fork) returns false.
4114  *
4115  * Note that fork(2) is not available on some platforms like Windows and NetBSD 4.
4116  * Therefore you should use spawn() instead of fork().
4117  */
4118 
4119 static VALUE
4121 {
4122  rb_pid_t pid;
4123 
4124  switch (pid = rb_fork_ruby(NULL)) {
4125  case 0:
4126  rb_thread_atfork();
4127  if (rb_block_given_p()) {
4128  int status;
4129  rb_protect(rb_yield, Qundef, &status);
4130  ruby_stop(status);
4131  }
4132  return Qnil;
4133 
4134  case -1:
4135  rb_sys_fail("fork(2)");
4136  return Qnil;
4137 
4138  default:
4139  return PIDT2NUM(pid);
4140  }
4141 }
4142 #else
4143 #define rb_f_fork rb_f_notimplement
4144 #endif
4145 
4146 static int
4147 exit_status_code(VALUE status)
4148 {
4149  int istatus;
4150 
4151  switch (status) {
4152  case Qtrue:
4153  istatus = EXIT_SUCCESS;
4154  break;
4155  case Qfalse:
4156  istatus = EXIT_FAILURE;
4157  break;
4158  default:
4159  istatus = NUM2INT(status);
4160 #if EXIT_SUCCESS != 0
4161  if (istatus == 0)
4162  istatus = EXIT_SUCCESS;
4163 #endif
4164  break;
4165  }
4166  return istatus;
4167 }
4168 
4169 /*
4170  * call-seq:
4171  * Process.exit!(status=false)
4172  *
4173  * Exits the process immediately. No exit handlers are
4174  * run. <em>status</em> is returned to the underlying system as the
4175  * exit status.
4176  *
4177  * Process.exit!(true)
4178  */
4179 
4180 static VALUE
4181 rb_f_exit_bang(int argc, VALUE *argv, VALUE obj)
4182 {
4183  int istatus;
4184 
4185  if (rb_check_arity(argc, 0, 1) == 1) {
4186  istatus = exit_status_code(argv[0]);
4187  }
4188  else {
4189  istatus = EXIT_FAILURE;
4190  }
4191  _exit(istatus);
4192 
4194 }
4195 
4196 void
4197 rb_exit(int status)
4198 {
4199  if (GET_EC()->tag) {
4200  VALUE args[2];
4201 
4202  args[0] = INT2NUM(status);
4203  args[1] = rb_str_new2("exit");
4205  }
4206  ruby_stop(status);
4207 }
4208 
4209 VALUE
4210 rb_f_exit(int argc, const VALUE *argv)
4211 {
4212  int istatus;
4213 
4214  if (rb_check_arity(argc, 0, 1) == 1) {
4215  istatus = exit_status_code(argv[0]);
4216  }
4217  else {
4218  istatus = EXIT_SUCCESS;
4219  }
4220  rb_exit(istatus);
4221 
4223 }
4224 
4225 /*
4226  * call-seq:
4227  * exit(status=true)
4228  * Kernel::exit(status=true)
4229  * Process::exit(status=true)
4230  *
4231  * Initiates the termination of the Ruby script by raising the
4232  * SystemExit exception. This exception may be caught. The
4233  * optional parameter is used to return a status code to the invoking
4234  * environment.
4235  * +true+ and +FALSE+ of _status_ means success and failure
4236  * respectively. The interpretation of other integer values are
4237  * system dependent.
4238  *
4239  * begin
4240  * exit
4241  * puts "never get here"
4242  * rescue SystemExit
4243  * puts "rescued a SystemExit exception"
4244  * end
4245  * puts "after begin block"
4246  *
4247  * <em>produces:</em>
4248  *
4249  * rescued a SystemExit exception
4250  * after begin block
4251  *
4252  * Just prior to termination, Ruby executes any <code>at_exit</code>
4253  * functions (see Kernel::at_exit) and runs any object finalizers
4254  * (see ObjectSpace::define_finalizer).
4255  *
4256  * at_exit { puts "at_exit function" }
4257  * ObjectSpace.define_finalizer("string", proc { puts "in finalizer" })
4258  * exit
4259  *
4260  * <em>produces:</em>
4261  *
4262  * at_exit function
4263  * in finalizer
4264  */
4265 
4266 static VALUE
4267 f_exit(int c, const VALUE *a, VALUE _)
4268 {
4269  return rb_f_exit(c, a);
4270 }
4271 
4272 /*
4273  * call-seq:
4274  * abort
4275  * Kernel::abort([msg])
4276  * Process.abort([msg])
4277  *
4278  * Terminate execution immediately, effectively by calling
4279  * <code>Kernel.exit(false)</code>. If _msg_ is given, it is written
4280  * to STDERR prior to terminating.
4281  */
4282 
4283 VALUE
4285 {
4286  rb_check_arity(argc, 0, 1);
4287  if (argc == 0) {
4289  VALUE errinfo = rb_ec_get_errinfo(ec);
4290  if (!NIL_P(errinfo)) {
4291  rb_ec_error_print(ec, errinfo);
4292  }
4294  }
4295  else {
4296  VALUE args[2];
4297 
4298  args[1] = args[0] = argv[0];
4299  StringValue(args[0]);
4300  rb_io_puts(1, args, rb_stderr);
4301  args[0] = INT2NUM(EXIT_FAILURE);
4303  }
4304 
4306 }
4307 
4308 static VALUE
4309 f_abort(int c, const VALUE *a, VALUE _)
4310 {
4311  return rb_f_abort(c, a);
4312 }
4313 
4314 void
4316 {
4317  int status;
4318 
4319  rb_waitpid(pid, &status, 0);
4320 }
4321 
4322 #if !defined HAVE_WORKING_FORK && !defined HAVE_SPAWNV
4323 char *
4324 rb_execarg_commandline(const struct rb_execarg *eargp, VALUE *prog)
4325 {
4326  VALUE cmd = *prog;
4327  if (eargp && !eargp->use_shell) {
4328  VALUE str = eargp->invoke.cmd.argv_str;
4329  VALUE buf = eargp->invoke.cmd.argv_buf;
4330  char *p, **argv = ARGVSTR2ARGV(str);
4331  long i, argc = ARGVSTR2ARGC(str);
4332  const char *start = RSTRING_PTR(buf);
4333  cmd = rb_str_new(start, RSTRING_LEN(buf));
4334  p = RSTRING_PTR(cmd);
4335  for (i = 1; i < argc; ++i) {
4336  p[argv[i] - start - 1] = ' ';
4337  }
4338  *prog = cmd;
4339  return p;
4340  }
4341  return StringValueCStr(*prog);
4342 }
4343 #endif
4344 
4345 static rb_pid_t
4346 rb_spawn_process(struct rb_execarg *eargp, char *errmsg, size_t errmsg_buflen)
4347 {
4348  rb_pid_t pid;
4349 #if !defined HAVE_WORKING_FORK || USE_SPAWNV
4350  VALUE prog;
4351  struct rb_execarg sarg;
4352 # if !defined HAVE_SPAWNV
4353  int status;
4354 # endif
4355 #endif
4356 
4357 #if defined HAVE_WORKING_FORK && !USE_SPAWNV
4358  pid = fork_check_err(0, rb_exec_atfork, eargp, eargp->redirect_fds,
4359  errmsg, errmsg_buflen, eargp);
4360 #else
4361  prog = eargp->use_shell ? eargp->invoke.sh.shell_script : eargp->invoke.cmd.command_name;
4362 
4363  if (rb_execarg_run_options(eargp, &sarg, errmsg, errmsg_buflen) < 0) {
4364  return -1;
4365  }
4366 
4367  if (prog && !eargp->use_shell) {
4368  char **argv = ARGVSTR2ARGV(eargp->invoke.cmd.argv_str);
4369  argv[0] = RSTRING_PTR(prog);
4370  }
4371 # if defined HAVE_SPAWNV
4372  if (eargp->use_shell) {
4373  pid = proc_spawn_sh(RSTRING_PTR(prog));
4374  }
4375  else {
4376  char **argv = ARGVSTR2ARGV(eargp->invoke.cmd.argv_str);
4377  pid = proc_spawn_cmd(argv, prog, eargp);
4378  }
4379  if (pid == -1)
4380  rb_last_status_set(0x7f << 8, 0);
4381 # else
4382  status = system(rb_execarg_commandline(eargp, &prog));
4383  rb_last_status_set((status & 0xff) << 8, 0);
4384  pid = 1; /* dummy */
4385 # endif
4386  if (eargp->waitpid_state && eargp->waitpid_state != WAITPID_LOCK_ONLY) {
4387  eargp->waitpid_state->pid = pid;
4388  }
4389  rb_execarg_run_options(&sarg, NULL, errmsg, errmsg_buflen);
4390 #endif
4391  return pid;
4392 }
4393 
4394 struct spawn_args {
4396  struct {
4397  char *ptr;
4398  size_t buflen;
4399  } errmsg;
4400 };
4401 
4402 static VALUE
4403 do_spawn_process(VALUE arg)
4404 {
4405  struct spawn_args *argp = (struct spawn_args *)arg;
4406  rb_execarg_parent_start1(argp->execarg);
4407  return (VALUE)rb_spawn_process(DATA_PTR(argp->execarg),
4408  argp->errmsg.ptr, argp->errmsg.buflen);
4409 }
4410 
4411 static rb_pid_t
4412 rb_execarg_spawn(VALUE execarg_obj, char *errmsg, size_t errmsg_buflen)
4413 {
4414  struct spawn_args args;
4415  struct rb_execarg *eargp = rb_execarg_get(execarg_obj);
4416 
4417  /*
4418  * Prevent a race with MJIT where the compiler process where
4419  * can hold an FD of ours in between vfork + execve
4420  */
4421  if (!eargp->waitpid_state && mjit_enabled) {
4423  }
4424 
4425  args.execarg = execarg_obj;
4426  args.errmsg.ptr = errmsg;
4427  args.errmsg.buflen = errmsg_buflen;
4428  return (rb_pid_t)rb_ensure(do_spawn_process, (VALUE)&args,
4429  execarg_parent_end, execarg_obj);
4430 }
4431 
4432 static rb_pid_t
4433 rb_spawn_internal(int argc, const VALUE *argv, char *errmsg, size_t errmsg_buflen)
4434 {
4435  VALUE execarg_obj;
4436 
4437  execarg_obj = rb_execarg_new(argc, argv, TRUE, FALSE);
4438  return rb_execarg_spawn(execarg_obj, errmsg, errmsg_buflen);
4439 }
4440 
4441 rb_pid_t
4442 rb_spawn_err(int argc, const VALUE *argv, char *errmsg, size_t errmsg_buflen)
4443 {
4444  return rb_spawn_internal(argc, argv, errmsg, errmsg_buflen);
4445 }
4446 
4447 rb_pid_t
4448 rb_spawn(int argc, const VALUE *argv)
4449 {
4450  return rb_spawn_internal(argc, argv, NULL, 0);
4451 }
4452 
4453 /*
4454  * call-seq:
4455  * system([env,] command... [,options], exception: false) -> true, false or nil
4456  *
4457  * Executes _command..._ in a subshell.
4458  * _command..._ is one of following forms.
4459  *
4460  * [<code>commandline</code>]
4461  * command line string which is passed to the standard shell
4462  * [<code>cmdname, arg1, ...</code>]
4463  * command name and one or more arguments (no shell)
4464  * [<code>[cmdname, argv0], arg1, ...</code>]
4465  * command name, <code>argv[0]</code> and zero or more arguments (no shell)
4466  *
4467  * system returns +true+ if the command gives zero exit status,
4468  * +false+ for non zero exit status.
4469  * Returns +nil+ if command execution fails.
4470  * An error status is available in <code>$?</code>.
4471  *
4472  * If the <code>exception: true</code> argument is passed, the method
4473  * raises an exception instead of returning +false+ or +nil+.
4474  *
4475  * The arguments are processed in the same way as
4476  * for Kernel#spawn.
4477  *
4478  * The hash arguments, env and options, are same as #exec and #spawn.
4479  * See Kernel#spawn for details.
4480  *
4481  * system("echo *")
4482  * system("echo", "*")
4483  *
4484  * <em>produces:</em>
4485  *
4486  * config.h main.rb
4487  * *
4488  *
4489  * Error handling:
4490  *
4491  * system("cat nonexistent.txt")
4492  * # => false
4493  * system("catt nonexistent.txt")
4494  * # => nil
4495  *
4496  * system("cat nonexistent.txt", exception: true)
4497  * # RuntimeError (Command failed with exit 1: cat)
4498  * system("catt nonexistent.txt", exception: true)
4499  * # Errno::ENOENT (No such file or directory - catt)
4500  *
4501  * See Kernel#exec for the standard shell.
4502  */
4503 
4504 static VALUE
4505 rb_f_system(int argc, VALUE *argv, VALUE _)
4506 {
4507  /*
4508  * n.b. using alloca for now to simplify future Thread::Light code
4509  * when we need to use malloc for non-native Fiber
4510  */
4511  struct waitpid_state *w = alloca(sizeof(struct waitpid_state));
4512  rb_pid_t pid; /* may be different from waitpid_state.pid on exec failure */
4513  VALUE execarg_obj;
4514  struct rb_execarg *eargp;
4515  int exec_errnum;
4516 
4517  execarg_obj = rb_execarg_new(argc, argv, TRUE, TRUE);
4518  eargp = rb_execarg_get(execarg_obj);
4519  w->ec = GET_EC();
4520  waitpid_state_init(w, 0, 0);
4521  eargp->waitpid_state = w;
4522  pid = rb_execarg_spawn(execarg_obj, 0, 0);
4523  exec_errnum = pid < 0 ? errno : 0;
4524 
4525 #if defined(HAVE_WORKING_FORK) || defined(HAVE_SPAWNV)
4526  if (w->pid > 0) {
4527  /* `pid' (not w->pid) may be < 0 here if execve failed in child */
4528  if (WAITPID_USE_SIGCHLD) {
4529  rb_ensure(waitpid_sleep, (VALUE)w, waitpid_cleanup, (VALUE)w);
4530  }
4531  else {
4532  waitpid_no_SIGCHLD(w);
4533  }
4534  rb_last_status_set(w->status, w->ret);
4535  }
4536 #endif
4537  if (w->pid < 0 /* fork failure */ || pid < 0 /* exec failure */) {
4538  if (eargp->exception) {
4539  int err = exec_errnum ? exec_errnum : w->errnum;
4540  VALUE command = eargp->invoke.sh.shell_script;
4541  RB_GC_GUARD(execarg_obj);
4542  rb_syserr_fail_str(err, command);
4543  }
4544  else {
4545  return Qnil;
4546  }
4547  }
4548  if (w->status == EXIT_SUCCESS) return Qtrue;
4549  if (eargp->exception) {
4550  VALUE command = eargp->invoke.sh.shell_script;
4551  VALUE str = rb_str_new_cstr("Command failed with");
4552  rb_str_cat_cstr(pst_message_status(str, w->status), ": ");
4553  rb_str_append(str, command);
4554  RB_GC_GUARD(execarg_obj);
4556  }
4557  else {
4558  return Qfalse;
4559  }
4560 }
4561 
4562 /*
4563  * call-seq:
4564  * spawn([env,] command... [,options]) -> pid
4565  * Process.spawn([env,] command... [,options]) -> pid
4566  *
4567  * spawn executes specified command and return its pid.
4568  *
4569  * pid = spawn("tar xf ruby-2.0.0-p195.tar.bz2")
4570  * Process.wait pid
4571  *
4572  * pid = spawn(RbConfig.ruby, "-eputs'Hello, world!'")
4573  * Process.wait pid
4574  *
4575  * This method is similar to Kernel#system but it doesn't wait for the command
4576  * to finish.
4577  *
4578  * The parent process should
4579  * use Process.wait to collect
4580  * the termination status of its child or
4581  * use Process.detach to register
4582  * disinterest in their status;
4583  * otherwise, the operating system may accumulate zombie processes.
4584  *
4585  * spawn has bunch of options to specify process attributes:
4586  *
4587  * env: hash
4588  * name => val : set the environment variable
4589  * name => nil : unset the environment variable
4590  *
4591  * the keys and the values except for +nil+ must be strings.
4592  * command...:
4593  * commandline : command line string which is passed to the standard shell
4594  * cmdname, arg1, ... : command name and one or more arguments (This form does not use the shell. See below for caveats.)
4595  * [cmdname, argv0], arg1, ... : command name, argv[0] and zero or more arguments (no shell)
4596  * options: hash
4597  * clearing environment variables:
4598  * :unsetenv_others => true : clear environment variables except specified by env
4599  * :unsetenv_others => false : don't clear (default)
4600  * process group:
4601  * :pgroup => true or 0 : make a new process group
4602  * :pgroup => pgid : join the specified process group
4603  * :pgroup => nil : don't change the process group (default)
4604  * create new process group: Windows only
4605  * :new_pgroup => true : the new process is the root process of a new process group
4606  * :new_pgroup => false : don't create a new process group (default)
4607  * resource limit: resourcename is core, cpu, data, etc. See Process.setrlimit.
4608  * :rlimit_resourcename => limit
4609  * :rlimit_resourcename => [cur_limit, max_limit]
4610  * umask:
4611  * :umask => int
4612  * redirection:
4613  * key:
4614  * FD : single file descriptor in child process
4615  * [FD, FD, ...] : multiple file descriptor in child process
4616  * value:
4617  * FD : redirect to the file descriptor in parent process
4618  * string : redirect to file with open(string, "r" or "w")
4619  * [string] : redirect to file with open(string, File::RDONLY)
4620  * [string, open_mode] : redirect to file with open(string, open_mode, 0644)
4621  * [string, open_mode, perm] : redirect to file with open(string, open_mode, perm)
4622  * [:child, FD] : redirect to the redirected file descriptor
4623  * :close : close the file descriptor in child process
4624  * FD is one of follows
4625  * :in : the file descriptor 0 which is the standard input
4626  * :out : the file descriptor 1 which is the standard output
4627  * :err : the file descriptor 2 which is the standard error
4628  * integer : the file descriptor of specified the integer
4629  * io : the file descriptor specified as io.fileno
4630  * file descriptor inheritance: close non-redirected non-standard fds (3, 4, 5, ...) or not
4631  * :close_others => false : inherit
4632  * current directory:
4633  * :chdir => str
4634  *
4635  * The <code>cmdname, arg1, ...</code> form does not use the shell.
4636  * However, on different OSes, different things are provided as
4637  * built-in commands. An example of this is +'echo'+, which is a
4638  * built-in on Windows, but is a normal program on Linux and Mac OS X.
4639  * This means that <code>Process.spawn 'echo', '%Path%'</code> will
4640  * display the contents of the <tt>%Path%</tt> environment variable
4641  * on Windows, but <code>Process.spawn 'echo', '$PATH'</code> prints
4642  * the literal <tt>$PATH</tt>.
4643  *
4644  * If a hash is given as +env+, the environment is
4645  * updated by +env+ before <code>exec(2)</code> in the child process.
4646  * If a pair in +env+ has nil as the value, the variable is deleted.
4647  *
4648  * # set FOO as BAR and unset BAZ.
4649  * pid = spawn({"FOO"=>"BAR", "BAZ"=>nil}, command)
4650  *
4651  * If a hash is given as +options+,
4652  * it specifies
4653  * process group,
4654  * create new process group,
4655  * resource limit,
4656  * current directory,
4657  * umask and
4658  * redirects for the child process.
4659  * Also, it can be specified to clear environment variables.
4660  *
4661  * The <code>:unsetenv_others</code> key in +options+ specifies
4662  * to clear environment variables, other than specified by +env+.
4663  *
4664  * pid = spawn(command, :unsetenv_others=>true) # no environment variable
4665  * pid = spawn({"FOO"=>"BAR"}, command, :unsetenv_others=>true) # FOO only
4666  *
4667  * The <code>:pgroup</code> key in +options+ specifies a process group.
4668  * The corresponding value should be true, zero, a positive integer, or nil.
4669  * true and zero cause the process to be a process leader of a new process group.
4670  * A non-zero positive integer causes the process to join the provided process group.
4671  * The default value, nil, causes the process to remain in the same process group.
4672  *
4673  * pid = spawn(command, :pgroup=>true) # process leader
4674  * pid = spawn(command, :pgroup=>10) # belongs to the process group 10
4675  *
4676  * The <code>:new_pgroup</code> key in +options+ specifies to pass
4677  * +CREATE_NEW_PROCESS_GROUP+ flag to <code>CreateProcessW()</code> that is
4678  * Windows API. This option is only for Windows.
4679  * true means the new process is the root process of the new process group.
4680  * The new process has CTRL+C disabled. This flag is necessary for
4681  * <code>Process.kill(:SIGINT, pid)</code> on the subprocess.
4682  * :new_pgroup is false by default.
4683  *
4684  * pid = spawn(command, :new_pgroup=>true) # new process group
4685  * pid = spawn(command, :new_pgroup=>false) # same process group
4686  *
4687  * The <code>:rlimit_</code><em>foo</em> key specifies a resource limit.
4688  * <em>foo</em> should be one of resource types such as <code>core</code>.
4689  * The corresponding value should be an integer or an array which have one or
4690  * two integers: same as cur_limit and max_limit arguments for
4691  * Process.setrlimit.
4692  *
4693  * cur, max = Process.getrlimit(:CORE)
4694  * pid = spawn(command, :rlimit_core=>[0,max]) # disable core temporary.
4695  * pid = spawn(command, :rlimit_core=>max) # enable core dump
4696  * pid = spawn(command, :rlimit_core=>0) # never dump core.
4697  *
4698  * The <code>:umask</code> key in +options+ specifies the umask.
4699  *
4700  * pid = spawn(command, :umask=>077)
4701  *
4702  * The :in, :out, :err, an integer, an IO and an array key specifies a redirection.
4703  * The redirection maps a file descriptor in the child process.
4704  *
4705  * For example, stderr can be merged into stdout as follows:
4706  *
4707  * pid = spawn(command, :err=>:out)
4708  * pid = spawn(command, 2=>1)
4709  * pid = spawn(command, STDERR=>:out)
4710  * pid = spawn(command, STDERR=>STDOUT)
4711  *
4712  * The hash keys specifies a file descriptor in the child process
4713  * started by #spawn.
4714  * :err, 2 and STDERR specifies the standard error stream (stderr).
4715  *
4716  * The hash values specifies a file descriptor in the parent process
4717  * which invokes #spawn.
4718  * :out, 1 and STDOUT specifies the standard output stream (stdout).
4719  *
4720  * In the above example,
4721  * the standard output in the child process is not specified.
4722  * So it is inherited from the parent process.
4723  *
4724  * The standard input stream (stdin) can be specified by :in, 0 and STDIN.
4725  *
4726  * A filename can be specified as a hash value.
4727  *
4728  * pid = spawn(command, :in=>"/dev/null") # read mode
4729  * pid = spawn(command, :out=>"/dev/null") # write mode
4730  * pid = spawn(command, :err=>"log") # write mode
4731  * pid = spawn(command, [:out, :err]=>"/dev/null") # write mode
4732  * pid = spawn(command, 3=>"/dev/null") # read mode
4733  *
4734  * For stdout and stderr (and combination of them),
4735  * it is opened in write mode.
4736  * Otherwise read mode is used.
4737  *
4738  * For specifying flags and permission of file creation explicitly,
4739  * an array is used instead.
4740  *
4741  * pid = spawn(command, :in=>["file"]) # read mode is assumed
4742  * pid = spawn(command, :in=>["file", "r"])
4743  * pid = spawn(command, :out=>["log", "w"]) # 0644 assumed
4744  * pid = spawn(command, :out=>["log", "w", 0600])
4745  * pid = spawn(command, :out=>["log", File::WRONLY|File::EXCL|File::CREAT, 0600])
4746  *
4747  * The array specifies a filename, flags and permission.
4748  * The flags can be a string or an integer.
4749  * If the flags is omitted or nil, File::RDONLY is assumed.
4750  * The permission should be an integer.
4751  * If the permission is omitted or nil, 0644 is assumed.
4752  *
4753  * If an array of IOs and integers are specified as a hash key,
4754  * all the elements are redirected.
4755  *
4756  * # stdout and stderr is redirected to log file.
4757  * # The file "log" is opened just once.
4758  * pid = spawn(command, [:out, :err]=>["log", "w"])
4759  *
4760  * Another way to merge multiple file descriptors is [:child, fd].
4761  * \[:child, fd] means the file descriptor in the child process.
4762  * This is different from fd.
4763  * For example, :err=>:out means redirecting child stderr to parent stdout.
4764  * But :err=>[:child, :out] means redirecting child stderr to child stdout.
4765  * They differ if stdout is redirected in the child process as follows.
4766  *
4767  * # stdout and stderr is redirected to log file.
4768  * # The file "log" is opened just once.
4769  * pid = spawn(command, :out=>["log", "w"], :err=>[:child, :out])
4770  *
4771  * \[:child, :out] can be used to merge stderr into stdout in IO.popen.
4772  * In this case, IO.popen redirects stdout to a pipe in the child process
4773  * and [:child, :out] refers the redirected stdout.
4774  *
4775  * io = IO.popen(["sh", "-c", "echo out; echo err >&2", :err=>[:child, :out]])
4776  * p io.read #=> "out\nerr\n"
4777  *
4778  * The <code>:chdir</code> key in +options+ specifies the current directory.
4779  *
4780  * pid = spawn(command, :chdir=>"/var/tmp")
4781  *
4782  * spawn closes all non-standard unspecified descriptors by default.
4783  * The "standard" descriptors are 0, 1 and 2.
4784  * This behavior is specified by :close_others option.
4785  * :close_others doesn't affect the standard descriptors which are
4786  * closed only if :close is specified explicitly.
4787  *
4788  * pid = spawn(command, :close_others=>true) # close 3,4,5,... (default)
4789  * pid = spawn(command, :close_others=>false) # don't close 3,4,5,...
4790  *
4791  * :close_others is false by default for spawn and IO.popen.
4792  *
4793  * Note that fds which close-on-exec flag is already set are closed
4794  * regardless of :close_others option.
4795  *
4796  * So IO.pipe and spawn can be used as IO.popen.
4797  *
4798  * # similar to r = IO.popen(command)
4799  * r, w = IO.pipe
4800  * pid = spawn(command, :out=>w) # r, w is closed in the child process.
4801  * w.close
4802  *
4803  * :close is specified as a hash value to close a fd individually.
4804  *
4805  * f = open(foo)
4806  * system(command, f=>:close) # don't inherit f.
4807  *
4808  * If a file descriptor need to be inherited,
4809  * io=>io can be used.
4810  *
4811  * # valgrind has --log-fd option for log destination.
4812  * # log_w=>log_w indicates log_w.fileno inherits to child process.
4813  * log_r, log_w = IO.pipe
4814  * pid = spawn("valgrind", "--log-fd=#{log_w.fileno}", "echo", "a", log_w=>log_w)
4815  * log_w.close
4816  * p log_r.read
4817  *
4818  * It is also possible to exchange file descriptors.
4819  *
4820  * pid = spawn(command, :out=>:err, :err=>:out)
4821  *
4822  * The hash keys specify file descriptors in the child process.
4823  * The hash values specifies file descriptors in the parent process.
4824  * So the above specifies exchanging stdout and stderr.
4825  * Internally, +spawn+ uses an extra file descriptor to resolve such cyclic
4826  * file descriptor mapping.
4827  *
4828  * See Kernel.exec for the standard shell.
4829  */
4830 
4831 static VALUE
4832 rb_f_spawn(int argc, VALUE *argv, VALUE _)
4833 {
4834  rb_pid_t pid;
4835  char errmsg[CHILD_ERRMSG_BUFLEN] = { '\0' };
4836  VALUE execarg_obj, fail_str;
4837  struct rb_execarg *eargp;
4838 
4839  execarg_obj = rb_execarg_new(argc, argv, TRUE, FALSE);
4840  eargp = rb_execarg_get(execarg_obj);
4841  fail_str = eargp->use_shell ? eargp->invoke.sh.shell_script : eargp->invoke.cmd.command_name;
4842 
4843  pid = rb_execarg_spawn(execarg_obj, errmsg, sizeof(errmsg));
4844 
4845  if (pid == -1) {
4846  int err = errno;
4847  rb_exec_fail(eargp, err, errmsg);
4848  RB_GC_GUARD(execarg_obj);
4849  rb_syserr_fail_str(err, fail_str);
4850  }
4851 #if defined(HAVE_WORKING_FORK) || defined(HAVE_SPAWNV)
4852  return PIDT2NUM(pid);
4853 #else
4854  return Qnil;
4855 #endif
4856 }
4857 
4858 /*
4859  * call-seq:
4860  * sleep([duration]) -> integer
4861  *
4862  * Suspends the current thread for _duration_ seconds (which may be any number,
4863  * including a +Float+ with fractional seconds). Returns the actual number of
4864  * seconds slept (rounded), which may be less than that asked for if another
4865  * thread calls Thread#run. Called without an argument, sleep()
4866  * will sleep forever.
4867  *
4868  * Time.new #=> 2008-03-08 19:56:19 +0900
4869  * sleep 1.2 #=> 1
4870  * Time.new #=> 2008-03-08 19:56:20 +0900
4871  * sleep 1.9 #=> 2
4872  * Time.new #=> 2008-03-08 19:56:22 +0900
4873  */
4874 
4875 static VALUE
4876 rb_f_sleep(int argc, VALUE *argv, VALUE _)
4877 {
4878  time_t beg, end;
4879 
4880  beg = time(0);
4881  if (argc == 0) {
4883  }
4884  else {
4885  rb_check_arity(argc, 0, 1);
4887  }
4888 
4889  end = time(0) - beg;
4890 
4891  return INT2FIX(end);
4892 }
4893 
4894 
4895 #if (defined(HAVE_GETPGRP) && defined(GETPGRP_VOID)) || defined(HAVE_GETPGID)
4896 /*
4897  * call-seq:
4898  * Process.getpgrp -> integer
4899  *
4900  * Returns the process group ID for this process. Not available on
4901  * all platforms.
4902  *
4903  * Process.getpgid(0) #=> 25527
4904  * Process.getpgrp #=> 25527
4905  */
4906 
4907 static VALUE
4909 {
4910  rb_pid_t pgrp;
4911 
4912 #if defined(HAVE_GETPGRP) && defined(GETPGRP_VOID)
4913  pgrp = getpgrp();
4914  if (pgrp < 0) rb_sys_fail(0);
4915  return PIDT2NUM(pgrp);
4916 #else /* defined(HAVE_GETPGID) */
4917  pgrp = getpgid(0);
4918  if (pgrp < 0) rb_sys_fail(0);
4919  return PIDT2NUM(pgrp);
4920 #endif
4921 }
4922 #else
4923 #define proc_getpgrp rb_f_notimplement
4924 #endif
4925 
4926 
4927 #if defined(HAVE_SETPGID) || (defined(HAVE_SETPGRP) && defined(SETPGRP_VOID))
4928 /*
4929  * call-seq:
4930  * Process.setpgrp -> 0
4931  *
4932  * Equivalent to <code>setpgid(0,0)</code>. Not available on all
4933  * platforms.
4934  */
4935 
4936 static VALUE
4938 {
4939  /* check for posix setpgid() first; this matches the posix */
4940  /* getpgrp() above. It appears that configure will set SETPGRP_VOID */
4941  /* even though setpgrp(0,0) would be preferred. The posix call avoids */
4942  /* this confusion. */
4943 #ifdef HAVE_SETPGID
4944  if (setpgid(0,0) < 0) rb_sys_fail(0);
4945 #elif defined(HAVE_SETPGRP) && defined(SETPGRP_VOID)
4946  if (setpgrp() < 0) rb_sys_fail(0);
4947 #endif
4948  return INT2FIX(0);
4949 }
4950 #else
4951 #define proc_setpgrp rb_f_notimplement
4952 #endif
4953 
4954 
4955 #if defined(HAVE_GETPGID)
4956 /*
4957  * call-seq:
4958  * Process.getpgid(pid) -> integer
4959  *
4960  * Returns the process group ID for the given process id. Not
4961  * available on all platforms.
4962  *
4963  * Process.getpgid(Process.ppid()) #=> 25527
4964  */
4965 
4966 static VALUE
4968 {
4969  rb_pid_t i;
4970 
4971  i = getpgid(NUM2PIDT(pid));
4972  if (i < 0) rb_sys_fail(0);
4973  return PIDT2NUM(i);
4974 }
4975 #else
4976 #define proc_getpgid rb_f_notimplement
4977 #endif
4978 
4979 
4980 #ifdef HAVE_SETPGID
4981 /*
4982  * call-seq:
4983  * Process.setpgid(pid, integer) -> 0
4984  *
4985  * Sets the process group ID of _pid_ (0 indicates this
4986  * process) to <em>integer</em>. Not available on all platforms.
4987  */
4988 
4989 static VALUE
4990 proc_setpgid(VALUE obj, VALUE pid, VALUE pgrp)
4991 {
4992  rb_pid_t ipid, ipgrp;
4993 
4994  ipid = NUM2PIDT(pid);
4995  ipgrp = NUM2PIDT(pgrp);
4996 
4997  if (setpgid(ipid, ipgrp) < 0) rb_sys_fail(0);
4998  return INT2FIX(0);
4999 }
5000 #else
5001 #define proc_setpgid rb_f_notimplement
5002 #endif
5003 
5004 
5005 #ifdef HAVE_GETSID
5006 /*
5007  * call-seq:
5008  * Process.getsid() -> integer
5009  * Process.getsid(pid) -> integer
5010  *
5011  * Returns the session ID for the given process id. If not given,
5012  * return current process sid. Not available on all platforms.
5013  *
5014  * Process.getsid() #=> 27422
5015  * Process.getsid(0) #=> 27422
5016  * Process.getsid(Process.pid()) #=> 27422
5017  */
5018 static VALUE
5019 proc_getsid(int argc, VALUE *argv, VALUE _)
5020 {
5021  rb_pid_t sid;
5022  rb_pid_t pid = 0;
5023 
5024  if (rb_check_arity(argc, 0, 1) == 1 && !NIL_P(argv[0]))
5025  pid = NUM2PIDT(argv[0]);
5026 
5027  sid = getsid(pid);
5028  if (sid < 0) rb_sys_fail(0);
5029  return PIDT2NUM(sid);
5030 }
5031 #else
5032 #define proc_getsid rb_f_notimplement
5033 #endif
5034 
5035 
5036 #if defined(HAVE_SETSID) || (defined(HAVE_SETPGRP) && defined(TIOCNOTTY))
5037 #if !defined(HAVE_SETSID)
5038 static rb_pid_t ruby_setsid(void);
5039 #define setsid() ruby_setsid()
5040 #endif
5041 /*
5042  * call-seq:
5043  * Process.setsid -> integer
5044  *
5045  * Establishes this process as a new session and process group
5046  * leader, with no controlling tty. Returns the session id. Not
5047  * available on all platforms.
5048  *
5049  * Process.setsid #=> 27422
5050  */
5051 
5052 static VALUE
5054 {
5055  rb_pid_t pid;
5056 
5057  pid = setsid();
5058  if (pid < 0) rb_sys_fail(0);
5059  return PIDT2NUM(pid);
5060 }
5061 
5062 #if !defined(HAVE_SETSID)
5063 #define HAVE_SETSID 1
5064 static rb_pid_t
5065 ruby_setsid(void)
5066 {
5067  rb_pid_t pid;
5068  int ret;
5069 
5070  pid = getpid();
5071 #if defined(SETPGRP_VOID)
5072  ret = setpgrp();
5073  /* If `pid_t setpgrp(void)' is equivalent to setsid(),
5074  `ret' will be the same value as `pid', and following open() will fail.
5075  In Linux, `int setpgrp(void)' is equivalent to setpgid(0, 0). */
5076 #else
5077  ret = setpgrp(0, pid);
5078 #endif
5079  if (ret == -1) return -1;
5080 
5081  if ((fd = rb_cloexec_open("/dev/tty", O_RDWR, 0)) >= 0) {
5082  rb_update_max_fd(fd);
5083  ioctl(fd, TIOCNOTTY, NULL);
5084  close(fd);
5085  }
5086  return pid;
5087 }
5088 #endif
5089 #else
5090 #define proc_setsid rb_f_notimplement
5091 #endif
5092 
5093 
5094 #ifdef HAVE_GETPRIORITY
5095 /*
5096  * call-seq:
5097  * Process.getpriority(kind, integer) -> integer
5098  *
5099  * Gets the scheduling priority for specified process, process group,
5100  * or user. <em>kind</em> indicates the kind of entity to find: one
5101  * of Process::PRIO_PGRP,
5102  * Process::PRIO_USER, or
5103  * Process::PRIO_PROCESS. _integer_ is an id
5104  * indicating the particular process, process group, or user (an id
5105  * of 0 means _current_). Lower priorities are more favorable
5106  * for scheduling. Not available on all platforms.
5107  *
5108  * Process.getpriority(Process::PRIO_USER, 0) #=> 19
5109  * Process.getpriority(Process::PRIO_PROCESS, 0) #=> 19
5110  */
5111 
5112 static VALUE
5113 proc_getpriority(VALUE obj, VALUE which, VALUE who)
5114 {
5115  int prio, iwhich, iwho;
5116 
5117  iwhich = NUM2INT(which);
5118  iwho = NUM2INT(who);
5119 
5120  errno = 0;
5121  prio = getpriority(iwhich, iwho);
5122  if (errno) rb_sys_fail(0);
5123  return INT2FIX(prio);
5124 }
5125 #else
5126 #define proc_getpriority rb_f_notimplement
5127 #endif
5128 
5129 
5130 #ifdef HAVE_GETPRIORITY
5131 /*
5132  * call-seq:
5133  * Process.setpriority(kind, integer, priority) -> 0
5134  *
5135  * See Process.getpriority.
5136  *
5137  * Process.setpriority(Process::PRIO_USER, 0, 19) #=> 0
5138  * Process.setpriority(Process::PRIO_PROCESS, 0, 19) #=> 0
5139  * Process.getpriority(Process::PRIO_USER, 0) #=> 19
5140  * Process.getpriority(Process::PRIO_PROCESS, 0) #=> 19
5141  */
5142 
5143 static VALUE
5144 proc_setpriority(VALUE obj, VALUE which, VALUE who, VALUE prio)
5145 {
5146  int iwhich, iwho, iprio;
5147 
5148  iwhich = NUM2INT(which);
5149  iwho = NUM2INT(who);
5150  iprio = NUM2INT(prio);
5151 
5152  if (setpriority(iwhich, iwho, iprio) < 0)
5153  rb_sys_fail(0);
5154  return INT2FIX(0);
5155 }
5156 #else
5157 #define proc_setpriority rb_f_notimplement
5158 #endif
5159 
5160 #if defined(HAVE_SETRLIMIT) && defined(NUM2RLIM)
5161 static int
5162 rlimit_resource_name2int(const char *name, long len, int casetype)
5163 {
5164  int resource;
5165  const char *p;
5166 #define RESCHECK(r) \
5167  do { \
5168  if (len == rb_strlen_lit(#r) && STRCASECMP(name, #r) == 0) { \
5169  resource = RLIMIT_##r; \
5170  goto found; \
5171  } \
5172  } while (0)
5173 
5174  switch (TOUPPER(*name)) {
5175  case 'A':
5176 #ifdef RLIMIT_AS
5177  RESCHECK(AS);
5178 #endif
5179  break;
5180 
5181  case 'C':
5182 #ifdef RLIMIT_CORE
5183  RESCHECK(CORE);
5184 #endif
5185 #ifdef RLIMIT_CPU
5186  RESCHECK(CPU);
5187 #endif
5188  break;
5189 
5190  case 'D':
5191 #ifdef RLIMIT_DATA
5192  RESCHECK(DATA);
5193 #endif
5194  break;
5195 
5196  case 'F':
5197 #ifdef RLIMIT_FSIZE
5198  RESCHECK(FSIZE);
5199 #endif
5200  break;
5201 
5202  case 'M':
5203 #ifdef RLIMIT_MEMLOCK
5204  RESCHECK(MEMLOCK);
5205 #endif
5206 #ifdef RLIMIT_MSGQUEUE
5207  RESCHECK(MSGQUEUE);
5208 #endif
5209  break;
5210 
5211  case 'N':
5212 #ifdef RLIMIT_NOFILE
5213  RESCHECK(NOFILE);
5214 #endif
5215 #ifdef RLIMIT_NPROC
5216  RESCHECK(NPROC);
5217 #endif
5218 #ifdef RLIMIT_NICE
5219  RESCHECK(NICE);
5220 #endif
5221  break;
5222 
5223  case 'R':
5224 #ifdef RLIMIT_RSS
5225  RESCHECK(RSS);
5226 #endif
5227 #ifdef RLIMIT_RTPRIO
5228  RESCHECK(RTPRIO);
5229 #endif
5230 #ifdef RLIMIT_RTTIME
5231  RESCHECK(RTTIME);
5232 #endif
5233  break;
5234 
5235  case 'S':
5236 #ifdef RLIMIT_STACK
5237  RESCHECK(STACK);
5238 #endif
5239 #ifdef RLIMIT_SBSIZE
5240  RESCHECK(SBSIZE);
5241 #endif
5242 #ifdef RLIMIT_SIGPENDING
5243  RESCHECK(SIGPENDING);
5244 #endif
5245  break;
5246  }
5247  return -1;
5248 
5249  found:
5250  switch (casetype) {
5251  case 0:
5252  for (p = name; *p; p++)
5253  if (!ISUPPER(*p))
5254  return -1;
5255  break;
5256 
5257  case 1:
5258  for (p = name; *p; p++)
5259  if (!ISLOWER(*p))
5260  return -1;
5261  break;
5262 
5263  default:
5264  rb_bug("unexpected casetype");
5265  }
5266  return resource;
5267 #undef RESCHECK
5268 }
5269 
5270 static int
5271 rlimit_type_by_hname(const char *name, long len)
5272 {
5273  return rlimit_resource_name2int(name, len, 0);
5274 }
5275 
5276 static int
5277 rlimit_type_by_lname(const char *name, long len)
5278 {
5279  return rlimit_resource_name2int(name, len, 1);
5280 }
5281 
5282 static int
5283 rlimit_type_by_sym(VALUE key)
5284 {
5285  VALUE name = rb_sym2str(key);
5286  const char *rname = RSTRING_PTR(name);
5287  long len = RSTRING_LEN(name);
5288  int rtype = -1;
5289  static const char prefix[] = "rlimit_";
5290  enum {prefix_len = sizeof(prefix)-1};
5291 
5292  if (len > prefix_len && strncmp(prefix, rname, prefix_len) == 0) {
5293  rtype = rlimit_type_by_lname(rname + prefix_len, len - prefix_len);
5294  }
5295 
5296  RB_GC_GUARD(key);
5297  return rtype;
5298 }
5299 
5300 static int
5301 rlimit_resource_type(VALUE rtype)
5302 {
5303  const char *name;
5304  long len;
5305  VALUE v;
5306  int r;
5307 
5308  switch (TYPE(rtype)) {
5309  case T_SYMBOL:
5310  v = rb_sym2str(rtype);
5311  name = RSTRING_PTR(v);
5312  len = RSTRING_LEN(v);
5313  break;
5314 
5315  default:
5316  v = rb_check_string_type(rtype);
5317  if (!NIL_P(v)) {
5318  rtype = v;
5319  case T_STRING:
5320  name = StringValueCStr(rtype);
5321  len = RSTRING_LEN(rtype);
5322  break;
5323  }
5324  /* fall through */
5325 
5326  case T_FIXNUM:
5327  case T_BIGNUM:
5328  return NUM2INT(rtype);
5329  }
5330 
5331  r = rlimit_type_by_hname(name, len);
5332  if (r != -1)
5333  return r;
5334 
5335  rb_raise(rb_eArgError, "invalid resource name: % "PRIsVALUE, rtype);
5336 
5337  UNREACHABLE_RETURN(-1);
5338 }
5339 
5340 static rlim_t
5341 rlimit_resource_value(VALUE rval)
5342 {
5343  const char *name;
5344  VALUE v;
5345 
5346  switch (TYPE(rval)) {
5347  case T_SYMBOL:
5348  v = rb_sym2str(rval);
5349  name = RSTRING_PTR(v);
5350  break;
5351 
5352  default:
5353  v = rb_check_string_type(rval);
5354  if (!NIL_P(v)) {
5355  rval = v;
5356  case T_STRING:
5357  name = StringValueCStr(rval);
5358  break;
5359  }
5360  /* fall through */
5361 
5362  case T_FIXNUM:
5363  case T_BIGNUM:
5364  return NUM2RLIM(rval);
5365  }
5366 
5367 #ifdef RLIM_INFINITY
5368  if (strcmp(name, "INFINITY") == 0) return RLIM_INFINITY;
5369 #endif
5370 #ifdef RLIM_SAVED_MAX
5371  if (strcmp(name, "SAVED_MAX") == 0) return RLIM_SAVED_MAX;
5372 #endif
5373 #ifdef RLIM_SAVED_CUR
5374  if (strcmp(name, "SAVED_CUR") == 0) return RLIM_SAVED_CUR;
5375 #endif
5376  rb_raise(rb_eArgError, "invalid resource value: %"PRIsVALUE, rval);
5377 
5378  UNREACHABLE_RETURN((rlim_t)-1);
5379 }
5380 #endif
5381 
5382 #if defined(HAVE_GETRLIMIT) && defined(RLIM2NUM)
5383 /*
5384  * call-seq:
5385  * Process.getrlimit(resource) -> [cur_limit, max_limit]
5386  *
5387  * Gets the resource limit of the process.
5388  * _cur_limit_ means current (soft) limit and
5389  * _max_limit_ means maximum (hard) limit.
5390  *
5391  * _resource_ indicates the kind of resource to limit.
5392  * It is specified as a symbol such as <code>:CORE</code>,
5393  * a string such as <code>"CORE"</code> or
5394  * a constant such as Process::RLIMIT_CORE.
5395  * See Process.setrlimit for details.
5396  *
5397  * _cur_limit_ and _max_limit_ may be Process::RLIM_INFINITY,
5398  * Process::RLIM_SAVED_MAX or
5399  * Process::RLIM_SAVED_CUR.
5400  * See Process.setrlimit and the system getrlimit(2) manual for details.
5401  */
5402 
5403 static VALUE
5404 proc_getrlimit(VALUE obj, VALUE resource)
5405 {
5406  struct rlimit rlim;
5407 
5408  if (getrlimit(rlimit_resource_type(resource), &rlim) < 0) {
5409  rb_sys_fail("getrlimit");
5410  }
5411  return rb_assoc_new(RLIM2NUM(rlim.rlim_cur), RLIM2NUM(rlim.rlim_max));
5412 }
5413 #else
5414 #define proc_getrlimit rb_f_notimplement
5415 #endif
5416 
5417 #if defined(HAVE_SETRLIMIT) && defined(NUM2RLIM)
5418 /*
5419  * call-seq:
5420  * Process.setrlimit(resource, cur_limit, max_limit) -> nil
5421  * Process.setrlimit(resource, cur_limit) -> nil
5422  *
5423  * Sets the resource limit of the process.
5424  * _cur_limit_ means current (soft) limit and
5425  * _max_limit_ means maximum (hard) limit.
5426  *
5427  * If _max_limit_ is not given, _cur_limit_ is used.
5428  *
5429  * _resource_ indicates the kind of resource to limit.
5430  * It should be a symbol such as <code>:CORE</code>,
5431  * a string such as <code>"CORE"</code> or
5432  * a constant such as Process::RLIMIT_CORE.
5433  * The available resources are OS dependent.
5434  * Ruby may support following resources.
5435  *
5436  * [AS] total available memory (bytes) (SUSv3, NetBSD, FreeBSD, OpenBSD but 4.4BSD-Lite)
5437  * [CORE] core size (bytes) (SUSv3)
5438  * [CPU] CPU time (seconds) (SUSv3)
5439  * [DATA] data segment (bytes) (SUSv3)
5440  * [FSIZE] file size (bytes) (SUSv3)
5441  * [MEMLOCK] total size for mlock(2) (bytes) (4.4BSD, GNU/Linux)
5442  * [MSGQUEUE] allocation for POSIX message queues (bytes) (GNU/Linux)
5443  * [NICE] ceiling on process's nice(2) value (number) (GNU/Linux)
5444  * [NOFILE] file descriptors (number) (SUSv3)
5445  * [NPROC] number of processes for the user (number) (4.4BSD, GNU/Linux)
5446  * [RSS] resident memory size (bytes) (4.2BSD, GNU/Linux)
5447  * [RTPRIO] ceiling on the process's real-time priority (number) (GNU/Linux)
5448  * [RTTIME] CPU time for real-time process (us) (GNU/Linux)
5449  * [SBSIZE] all socket buffers (bytes) (NetBSD, FreeBSD)
5450  * [SIGPENDING] number of queued signals allowed (signals) (GNU/Linux)
5451  * [STACK] stack size (bytes) (SUSv3)
5452  *
5453  * _cur_limit_ and _max_limit_ may be
5454  * <code>:INFINITY</code>, <code>"INFINITY"</code> or
5455  * Process::RLIM_INFINITY,
5456  * which means that the resource is not limited.
5457  * They may be Process::RLIM_SAVED_MAX,
5458  * Process::RLIM_SAVED_CUR and
5459  * corresponding symbols and strings too.
5460  * See system setrlimit(2) manual for details.
5461  *
5462  * The following example raises the soft limit of core size to
5463  * the hard limit to try to make core dump possible.
5464  *
5465  * Process.setrlimit(:CORE, Process.getrlimit(:CORE)[1])
5466  *
5467  */
5468 
5469 static VALUE
5471 {
5472  VALUE resource, rlim_cur, rlim_max;
5473  struct rlimit rlim;
5474 
5475  rb_check_arity(argc, 2, 3);
5476  resource = argv[0];
5477  rlim_cur = argv[1];
5478  if (argc < 3 || NIL_P(rlim_max = argv[2]))
5479  rlim_max = rlim_cur;
5480 
5481  rlim.rlim_cur = rlimit_resource_value(rlim_cur);
5482  rlim.rlim_max = rlimit_resource_value(rlim_max);
5483 
5484  if (setrlimit(rlimit_resource_type(resource), &rlim) < 0) {
5485  rb_sys_fail("setrlimit");
5486  }
5487  return Qnil;
5488 }
5489 #else
5490 #define proc_setrlimit rb_f_notimplement
5491 #endif
5492 
5493 static int under_uid_switch = 0;
5494 static void
5495 check_uid_switch(void)
5496 {
5497  if (under_uid_switch) {
5498  rb_raise(rb_eRuntimeError, "can't handle UID while evaluating block given to Process::UID.switch method");
5499  }
5500 }
5501 
5502 static int under_gid_switch = 0;
5503 static void
5504 check_gid_switch(void)
5505 {
5506  if (under_gid_switch) {
5507  rb_raise(rb_eRuntimeError, "can't handle GID while evaluating block given to Process::UID.switch method");
5508  }
5509 }
5510 
5511 
5512 /*********************************************************************
5513  * Document-class: Process::Sys
5514  *
5515  * The Process::Sys module contains UID and GID
5516  * functions which provide direct bindings to the system calls of the
5517  * same names instead of the more-portable versions of the same
5518  * functionality found in the Process,
5519  * Process::UID, and Process::GID modules.
5520  */
5521 
5522 #if defined(HAVE_PWD_H)
5523 static rb_uid_t
5524 obj2uid(VALUE id
5525 # ifdef USE_GETPWNAM_R
5526  , VALUE *getpw_tmp
5527 # endif
5528  )
5529 {
5530  rb_uid_t uid;
5531  VALUE tmp;
5532 
5533  if (FIXNUM_P(id) || NIL_P(tmp = rb_check_string_type(id))) {
5534  uid = NUM2UIDT(id);
5535  }
5536  else {
5537  const char *usrname = StringValueCStr(id);
5538  struct passwd *pwptr;
5539 #ifdef USE_GETPWNAM_R
5540  struct passwd pwbuf;
5541  char *getpw_buf;
5542  long getpw_buf_len;
5543  int e;
5544  if (!*getpw_tmp) {
5545  getpw_buf_len = GETPW_R_SIZE_INIT;
5546  if (getpw_buf_len < 0) getpw_buf_len = GETPW_R_SIZE_DEFAULT;
5547  *getpw_tmp = rb_str_tmp_new(getpw_buf_len);
5548  }
5549  getpw_buf = RSTRING_PTR(*getpw_tmp);
5550  getpw_buf_len = rb_str_capacity(*getpw_tmp);
5551  rb_str_set_len(*getpw_tmp, getpw_buf_len);
5552  errno = 0;
5553  while ((e = getpwnam_r(usrname, &pwbuf, getpw_buf, getpw_buf_len, &pwptr)) != 0) {
5554  if (e != ERANGE || getpw_buf_len >= GETPW_R_SIZE_LIMIT) {
5555  rb_str_resize(*getpw_tmp, 0);
5556  rb_syserr_fail(e, "getpwnam_r");
5557  }
5558  rb_str_modify_expand(*getpw_tmp, getpw_buf_len);
5559  getpw_buf = RSTRING_PTR(*getpw_tmp);
5560  getpw_buf_len = rb_str_capacity(*getpw_tmp);
5561  }
5562 #else
5563  pwptr = getpwnam(usrname);
5564 #endif
5565  if (!pwptr) {
5566 #ifndef USE_GETPWNAM_R
5567  endpwent();
5568 #endif
5569  rb_raise(rb_eArgError, "can't find user for %s", usrname);
5570  }
5571  uid = pwptr->pw_uid;
5572 #ifndef USE_GETPWNAM_R
5573  endpwent();
5574 #endif
5575  }
5576  return uid;
5577 }
5578 
5579 # ifdef p_uid_from_name
5580 /*
5581  * call-seq:
5582  * Process::UID.from_name(name) -> uid
5583  *
5584  * Get the user ID by the _name_.
5585  * If the user is not found, +ArgumentError+ will be raised.
5586  *
5587  * Process::UID.from_name("root") #=> 0
5588  * Process::UID.from_name("nosuchuser") #=> can't find user for nosuchuser (ArgumentError)
5589  */
5590 
5591 static VALUE
5592 p_uid_from_name(VALUE self, VALUE id)
5593 {
5594  return UIDT2NUM(OBJ2UID(id));
5595 }
5596 # endif
5597 #endif
5598 
5599 #if defined(HAVE_GRP_H)
5600 static rb_gid_t
5601 obj2gid(VALUE id
5602 # ifdef USE_GETGRNAM_R
5603  , VALUE *getgr_tmp
5604 # endif
5605  )
5606 {
5607  rb_gid_t gid;
5608  VALUE tmp;
5609 
5610  if (FIXNUM_P(id) || NIL_P(tmp = rb_check_string_type(id))) {
5611  gid = NUM2GIDT(id);
5612  }
5613  else {
5614  const char *grpname = StringValueCStr(id);
5615  struct group *grptr;
5616 #ifdef USE_GETGRNAM_R
5617  struct group grbuf;
5618  char *getgr_buf;
5619  long getgr_buf_len;
5620  int e;
5621  if (!*getgr_tmp) {
5622  getgr_buf_len = GETGR_R_SIZE_INIT;
5623  if (getgr_buf_len < 0) getgr_buf_len = GETGR_R_SIZE_DEFAULT;
5624  *getgr_tmp = rb_str_tmp_new(getgr_buf_len);
5625  }
5626  getgr_buf = RSTRING_PTR(*getgr_tmp);
5627  getgr_buf_len = rb_str_capacity(*getgr_tmp);
5628  rb_str_set_len(*getgr_tmp, getgr_buf_len);
5629  errno = 0;
5630  while ((e = getgrnam_r(grpname, &grbuf, getgr_buf, getgr_buf_len, &grptr)) != 0) {
5631  if (e != ERANGE || getgr_buf_len >= GETGR_R_SIZE_LIMIT) {
5632  rb_str_resize(*getgr_tmp, 0);
5633  rb_syserr_fail(e, "getgrnam_r");
5634  }
5635  rb_str_modify_expand(*getgr_tmp, getgr_buf_len);
5636  getgr_buf = RSTRING_PTR(*getgr_tmp);
5637  getgr_buf_len = rb_str_capacity(*getgr_tmp);
5638  }
5639 #elif defined(HAVE_GETGRNAM)
5640  grptr = getgrnam(grpname);
5641 #else
5642  grptr = NULL;
5643 #endif
5644  if (!grptr) {
5645 #if !defined(USE_GETGRNAM_R) && defined(HAVE_ENDGRENT)
5646  endgrent();
5647 #endif
5648  rb_raise(rb_eArgError, "can't find group for %s", grpname);
5649  }
5650  gid = grptr->gr_gid;
5651 #if !defined(USE_GETGRNAM_R) && defined(HAVE_ENDGRENT)
5652  endgrent();
5653 #endif
5654  }
5655  return gid;
5656 }
5657 
5658 # ifdef p_gid_from_name
5659 /*
5660  * call-seq:
5661  * Process::GID.from_name(name) -> gid
5662  *
5663  * Get the group ID by the _name_.
5664  * If the group is not found, +ArgumentError+ will be raised.
5665  *
5666  * Process::GID.from_name("wheel") #=> 0
5667  * Process::GID.from_name("nosuchgroup") #=> can't find group for nosuchgroup (ArgumentError)
5668  */
5669 
5670 static VALUE
5671 p_gid_from_name(VALUE self, VALUE id)
5672 {
5673  return GIDT2NUM(OBJ2GID(id));
5674 }
5675 # endif
5676 #endif
5677 
5678 #if defined HAVE_SETUID
5679 /*
5680  * call-seq:
5681  * Process::Sys.setuid(user) -> nil
5682  *
5683  * Set the user ID of the current process to _user_. Not
5684  * available on all platforms.
5685  *
5686  */
5687 
5688 static VALUE
5690 {
5691  check_uid_switch();
5692  if (setuid(OBJ2UID(id)) != 0) rb_sys_fail(0);
5693  return Qnil;
5694 }
5695 #else
5696 #define p_sys_setuid rb_f_notimplement
5697 #endif
5698 
5699 
5700 #if defined HAVE_SETRUID
5701 /*
5702  * call-seq:
5703  * Process::Sys.setruid(user) -> nil
5704  *
5705  * Set the real user ID of the calling process to _user_.
5706  * Not available on all platforms.
5707  *
5708  */
5709 
5710 static VALUE
5712 {
5713  check_uid_switch();
5714  if (setruid(OBJ2UID(id)) != 0) rb_sys_fail(0);
5715  return Qnil;
5716 }
5717 #else
5718 #define p_sys_setruid rb_f_notimplement
5719 #endif
5720 
5721 
5722 #if defined HAVE_SETEUID
5723 /*
5724  * call-seq:
5725  * Process::Sys.seteuid(user) -> nil
5726  *
5727  * Set the effective user ID of the calling process to
5728  * _user_. Not available on all platforms.
5729  *
5730  */
5731 
5732 static VALUE
5734 {
5735  check_uid_switch();
5736  if (seteuid(OBJ2UID(id)) != 0) rb_sys_fail(0);
5737  return Qnil;
5738 }
5739 #else
5740 #define p_sys_seteuid rb_f_notimplement
5741 #endif
5742 
5743 
5744 #if defined HAVE_SETREUID
5745 /*
5746  * call-seq:
5747  * Process::Sys.setreuid(rid, eid) -> nil
5748  *
5749  * Sets the (user) real and/or effective user IDs of the current
5750  * process to _rid_ and _eid_, respectively. A value of
5751  * <code>-1</code> for either means to leave that ID unchanged. Not
5752  * available on all platforms.
5753  *
5754  */
5755 
5756 static VALUE
5757 p_sys_setreuid(VALUE obj, VALUE rid, VALUE eid)
5758 {
5759  rb_uid_t ruid, euid;
5761  check_uid_switch();
5762  ruid = OBJ2UID1(rid);
5763  euid = OBJ2UID1(eid);
5765  if (setreuid(ruid, euid) != 0) rb_sys_fail(0);
5766  return Qnil;
5767 }
5768 #else
5769 #define p_sys_setreuid rb_f_notimplement
5770 #endif
5771 
5772 
5773 #if defined HAVE_SETRESUID
5774 /*
5775  * call-seq:
5776  * Process::Sys.setresuid(rid, eid, sid) -> nil
5777  *
5778  * Sets the (user) real, effective, and saved user IDs of the
5779  * current process to _rid_, _eid_, and _sid_ respectively. A
5780  * value of <code>-1</code> for any value means to
5781  * leave that ID unchanged. Not available on all platforms.
5782  *
5783  */
5784 
5785 static VALUE
5786 p_sys_setresuid(VALUE obj, VALUE rid, VALUE eid, VALUE sid)
5787 {
5788  rb_uid_t ruid, euid, suid;
5790  check_uid_switch();
5791  ruid = OBJ2UID1(rid);
5792  euid = OBJ2UID1(eid);
5793  suid = OBJ2UID1(sid);
5795  if (setresuid(ruid, euid, suid) != 0) rb_sys_fail(0);
5796  return Qnil;
5797 }
5798 #else
5799 #define p_sys_setresuid rb_f_notimplement
5800 #endif
5801 
5802 
5803 /*
5804  * call-seq:
5805  * Process.uid -> integer
5806  * Process::UID.rid -> integer
5807  * Process::Sys.getuid -> integer
5808  *
5809  * Returns the (real) user ID of this process.
5810  *
5811  * Process.uid #=> 501
5812  */
5813 
5814 static VALUE
5815 proc_getuid(VALUE obj)
5816 {
5817  rb_uid_t uid = getuid();
5818  return UIDT2NUM(uid);
5819 }
5820 
5821 
5822 #if defined(HAVE_SETRESUID) || defined(HAVE_SETREUID) || defined(HAVE_SETRUID) || defined(HAVE_SETUID)
5823 /*
5824  * call-seq:
5825  * Process.uid= user -> numeric
5826  *
5827  * Sets the (user) user ID for this process. Not available on all
5828  * platforms.
5829  */
5830 
5831 static VALUE
5833 {
5834  rb_uid_t uid;
5835 
5836  check_uid_switch();
5837 
5838  uid = OBJ2UID(id);
5839 #if defined(HAVE_SETRESUID)
5840  if (setresuid(uid, -1, -1) < 0) rb_sys_fail(0);
5841 #elif defined HAVE_SETREUID
5842  if (setreuid(uid, -1) < 0) rb_sys_fail(0);
5843 #elif defined HAVE_SETRUID
5844  if (setruid(uid) < 0) rb_sys_fail(0);
5845 #elif defined HAVE_SETUID
5846  {
5847  if (geteuid() == uid) {
5848  if (setuid(uid) < 0) rb_sys_fail(0);
5849  }
5850  else {
5851  rb_notimplement();
5852  }
5853  }
5854 #endif
5855  return id;
5856 }
5857 #else
5858 #define proc_setuid rb_f_notimplement
5859 #endif
5860 
5861 
5862 /********************************************************************
5863  *
5864  * Document-class: Process::UID
5865  *
5866  * The Process::UID module contains a collection of
5867  * module functions which can be used to portably get, set, and
5868  * switch the current process's real, effective, and saved user IDs.
5869  *
5870  */
5871 
5872 static rb_uid_t SAVED_USER_ID = -1;
5873 
5874 #ifdef BROKEN_SETREUID
5875 int
5876 setreuid(rb_uid_t ruid, rb_uid_t euid)
5877 {
5878  if (ruid != (rb_uid_t)-1 && ruid != getuid()) {
5879  if (euid == (rb_uid_t)-1) euid = geteuid();
5880  if (setuid(ruid) < 0) return -1;
5881  }
5882  if (euid != (rb_uid_t)-1 && euid != geteuid()) {
5883  if (seteuid(euid) < 0) return -1;
5884  }
5885  return 0;
5886 }
5887 #endif
5888 
5889 /*
5890  * call-seq:
5891  * Process::UID.change_privilege(user) -> integer
5892  *
5893  * Change the current process's real and effective user ID to that
5894  * specified by _user_. Returns the new user ID. Not
5895  * available on all platforms.
5896  *
5897  * [Process.uid, Process.euid] #=> [0, 0]
5898  * Process::UID.change_privilege(31) #=> 31
5899  * [Process.uid, Process.euid] #=> [31, 31]
5900  */
5901 
5902 static VALUE
5903 p_uid_change_privilege(VALUE obj, VALUE id)
5904 {
5905  rb_uid_t uid;
5906 
5907  check_uid_switch();
5908 
5909  uid = OBJ2UID(id);
5910 
5911  if (geteuid() == 0) { /* root-user */
5912 #if defined(HAVE_SETRESUID)
5913  if (setresuid(uid, uid, uid) < 0) rb_sys_fail(0);
5914  SAVED_USER_ID = uid;
5915 #elif defined(HAVE_SETUID)
5916  if (setuid(uid) < 0) rb_sys_fail(0);
5917  SAVED_USER_ID = uid;
5918 #elif defined(HAVE_SETREUID) && !defined(OBSOLETE_SETREUID)
5919  if (getuid() == uid) {
5920  if (SAVED_USER_ID == uid) {
5921  if (setreuid(-1, uid) < 0) rb_sys_fail(0);
5922  }
5923  else {
5924  if (uid == 0) { /* (r,e,s) == (root, root, x) */
5925  if (setreuid(-1, SAVED_USER_ID) < 0) rb_sys_fail(0);
5926  if (setreuid(SAVED_USER_ID, 0) < 0) rb_sys_fail(0);
5927  SAVED_USER_ID = 0; /* (r,e,s) == (x, root, root) */
5928  if (setreuid(uid, uid) < 0) rb_sys_fail(0);
5929  SAVED_USER_ID = uid;
5930  }
5931  else {
5932  if (setreuid(0, -1) < 0) rb_sys_fail(0);
5933  SAVED_USER_ID = 0;
5934  if (setreuid(uid, uid) < 0) rb_sys_fail(0);
5935  SAVED_USER_ID = uid;
5936  }
5937  }
5938  }
5939  else {
5940  if (setreuid(uid, uid) < 0) rb_sys_fail(0);
5941  SAVED_USER_ID = uid;
5942  }
5943 #elif defined(HAVE_SETRUID) && defined(HAVE_SETEUID)
5944  if (getuid() == uid) {
5945  if (SAVED_USER_ID == uid) {
5946  if (seteuid(uid) < 0) rb_sys_fail(0);
5947  }
5948  else {
5949  if (uid == 0) {
5950  if (setruid(SAVED_USER_ID) < 0) rb_sys_fail(0);
5951  SAVED_USER_ID = 0;
5952  if (setruid(0) < 0) rb_sys_fail(0);
5953  }
5954  else {
5955  if (setruid(0) < 0) rb_sys_fail(0);
5956  SAVED_USER_ID = 0;
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  }
5962  }
5963  else {
5964  if (seteuid(uid) < 0) rb_sys_fail(0);
5965  if (setruid(uid) < 0) rb_sys_fail(0);
5966  SAVED_USER_ID = uid;
5967  }
5968 #else
5969  (void)uid;
5970  rb_notimplement();
5971 #endif
5972  }
5973  else { /* unprivileged user */
5974 #if defined(HAVE_SETRESUID)
5975  if (setresuid((getuid() == uid)? (rb_uid_t)-1: uid,
5976  (geteuid() == uid)? (rb_uid_t)-1: uid,
5977  (SAVED_USER_ID == uid)? (rb_uid_t)-1: uid) < 0) rb_sys_fail(0);
5978  SAVED_USER_ID = uid;
5979 #elif defined(HAVE_SETREUID) && !defined(OBSOLETE_SETREUID)
5980  if (SAVED_USER_ID == uid) {
5981  if (setreuid((getuid() == uid)? (rb_uid_t)-1: uid,
5982  (geteuid() == uid)? (rb_uid_t)-1: uid) < 0)
5983  rb_sys_fail(0);
5984  }
5985  else if (getuid() != uid) {
5986  if (setreuid(uid, (geteuid() == uid)? (rb_uid_t)-1: uid) < 0)
5987  rb_sys_fail(0);
5988  SAVED_USER_ID = uid;
5989  }
5990  else if (/* getuid() == uid && */ geteuid() != uid) {
5991  if (setreuid(geteuid(), uid) < 0) rb_sys_fail(0);
5992  SAVED_USER_ID = uid;
5993  if (setreuid(uid, -1) < 0) rb_sys_fail(0);
5994  }
5995  else { /* getuid() == uid && geteuid() == uid */
5996  if (setreuid(-1, SAVED_USER_ID) < 0) rb_sys_fail(0);
5997  if (setreuid(SAVED_USER_ID, uid) < 0) rb_sys_fail(0);
5998  SAVED_USER_ID = uid;
5999  if (setreuid(uid, -1) < 0) rb_sys_fail(0);
6000  }
6001 #elif defined(HAVE_SETRUID) && defined(HAVE_SETEUID)
6002  if (SAVED_USER_ID == uid) {
6003  if (geteuid() != uid && seteuid(uid) < 0) rb_sys_fail(0);
6004  if (getuid() != uid && setruid(uid) < 0) rb_sys_fail(0);
6005  }
6006  else if (/* SAVED_USER_ID != uid && */ geteuid() == uid) {
6007  if (getuid() != uid) {
6008  if (setruid(uid) < 0) rb_sys_fail(0);
6009  SAVED_USER_ID = uid;
6010  }
6011  else {
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  }
6017  else if (/* geteuid() != uid && */ getuid() == uid) {
6018  if (seteuid(uid) < 0) rb_sys_fail(0);
6019  if (setruid(SAVED_USER_ID) < 0) rb_sys_fail(0);
6020  SAVED_USER_ID = uid;
6021  if (setruid(uid) < 0) rb_sys_fail(0);
6022  }
6023  else {
6024  rb_syserr_fail(EPERM, 0);
6025  }
6026 #elif defined HAVE_44BSD_SETUID
6027  if (getuid() == uid) {
6028  /* (r,e,s)==(uid,?,?) ==> (uid,uid,uid) */
6029  if (setuid(uid) < 0) rb_sys_fail(0);
6030  SAVED_USER_ID = uid;
6031  }
6032  else {
6033  rb_syserr_fail(EPERM, 0);
6034  }
6035 #elif defined HAVE_SETEUID
6036  if (getuid() == uid && SAVED_USER_ID == uid) {
6037  if (seteuid(uid) < 0) rb_sys_fail(0);
6038  }
6039  else {
6040  rb_syserr_fail(EPERM, 0);
6041  }
6042 #elif defined HAVE_SETUID
6043  if (getuid() == uid && SAVED_USER_ID == uid) {
6044  if (setuid(uid) < 0) rb_sys_fail(0);
6045  }
6046  else {
6047  rb_syserr_fail(EPERM, 0);
6048  }
6049 #else
6050  rb_notimplement();
6051 #endif
6052  }
6053  return id;
6054 }
6055 
6056 
6057 
6058 #if defined HAVE_SETGID
6059 /*
6060  * call-seq:
6061  * Process::Sys.setgid(group) -> nil
6062  *
6063  * Set the group ID of the current process to _group_. Not
6064  * available on all platforms.
6065  *
6066  */
6067 
6068 static VALUE
6070 {
6071  check_gid_switch();
6072  if (setgid(OBJ2GID(id)) != 0) rb_sys_fail(0);
6073  return Qnil;
6074 }
6075 #else
6076 #define p_sys_setgid rb_f_notimplement
6077 #endif
6078 
6079 
6080 #if defined HAVE_SETRGID
6081 /*
6082  * call-seq:
6083  * Process::Sys.setrgid(group) -> nil
6084  *
6085  * Set the real group ID of the calling process to _group_.
6086  * Not available on all platforms.
6087  *
6088  */
6089 
6090 static VALUE
6092 {
6093  check_gid_switch();
6094  if (setrgid(OBJ2GID(id)) != 0) rb_sys_fail(0);
6095  return Qnil;
6096 }
6097 #else
6098 #define p_sys_setrgid rb_f_notimplement
6099 #endif
6100 
6101 
6102 #if defined HAVE_SETEGID
6103 /*
6104  * call-seq:
6105  * Process::Sys.setegid(group) -> nil
6106  *
6107  * Set the effective group ID of the calling process to
6108  * _group_. Not available on all platforms.
6109  *
6110  */
6111 
6112 static VALUE
6114 {
6115  check_gid_switch();
6116  if (setegid(OBJ2GID(id)) != 0) rb_sys_fail(0);
6117  return Qnil;
6118 }
6119 #else
6120 #define p_sys_setegid rb_f_notimplement
6121 #endif
6122 
6123 
6124 #if defined HAVE_SETREGID
6125 /*
6126  * call-seq:
6127  * Process::Sys.setregid(rid, eid) -> nil
6128  *
6129  * Sets the (group) real and/or effective group IDs of the current
6130  * process to <em>rid</em> and <em>eid</em>, respectively. A value of
6131  * <code>-1</code> for either means to leave that ID unchanged. Not
6132  * available on all platforms.
6133  *
6134  */
6135 
6136 static VALUE
6137 p_sys_setregid(VALUE obj, VALUE rid, VALUE eid)
6138 {
6139  rb_gid_t rgid, egid;
6140  check_gid_switch();
6141  rgid = OBJ2GID(rid);
6142  egid = OBJ2GID(eid);
6143  if (setregid(rgid, egid) != 0) rb_sys_fail(0);
6144  return Qnil;
6145 }
6146 #else
6147 #define p_sys_setregid rb_f_notimplement
6148 #endif
6149 
6150 #if defined HAVE_SETRESGID
6151 /*
6152  * call-seq:
6153  * Process::Sys.setresgid(rid, eid, sid) -> nil
6154  *
6155  * Sets the (group) real, effective, and saved user IDs of the
6156  * current process to <em>rid</em>, <em>eid</em>, and <em>sid</em>
6157  * respectively. A value of <code>-1</code> for any value means to
6158  * leave that ID unchanged. Not available on all platforms.
6159  *
6160  */
6161 
6162 static VALUE
6163 p_sys_setresgid(VALUE obj, VALUE rid, VALUE eid, VALUE sid)
6164 {
6165  rb_gid_t rgid, egid, sgid;
6166  check_gid_switch();
6167  rgid = OBJ2GID(rid);
6168  egid = OBJ2GID(eid);
6169  sgid = OBJ2GID(sid);
6170  if (setresgid(rgid, egid, sgid) != 0) rb_sys_fail(0);
6171  return Qnil;
6172 }
6173 #else
6174 #define p_sys_setresgid rb_f_notimplement
6175 #endif
6176 
6177 
6178 #if defined HAVE_ISSETUGID
6179 /*
6180  * call-seq:
6181  * Process::Sys.issetugid -> true or false
6182  *
6183  * Returns +true+ if the process was created as a result
6184  * of an execve(2) system call which had either of the setuid or
6185  * setgid bits set (and extra privileges were given as a result) or
6186  * if it has changed any of its real, effective or saved user or
6187  * group IDs since it began execution.
6188  *
6189  */
6190 
6191 static VALUE
6193 {
6194  if (issetugid()) {
6195  return Qtrue;
6196  }
6197  else {
6198  return Qfalse;
6199  }
6200 }
6201 #else
6202 #define p_sys_issetugid rb_f_notimplement
6203 #endif
6204 
6205 
6206 /*
6207  * call-seq:
6208  * Process.gid -> integer
6209  * Process::GID.rid -> integer
6210  * Process::Sys.getgid -> integer
6211  *
6212  * Returns the (real) group ID for this process.
6213  *
6214  * Process.gid #=> 500
6215  */
6216 
6217 static VALUE
6218 proc_getgid(VALUE obj)
6219 {
6220  rb_gid_t gid = getgid();
6221  return GIDT2NUM(gid);
6222 }
6223 
6224 
6225 #if defined(HAVE_SETRESGID) || defined(HAVE_SETREGID) || defined(HAVE_SETRGID) || defined(HAVE_SETGID)
6226 /*
6227  * call-seq:
6228  * Process.gid= integer -> integer
6229  *
6230  * Sets the group ID for this process.
6231  */
6232 
6233 static VALUE
6235 {
6236  rb_gid_t gid;
6237 
6238  check_gid_switch();
6239 
6240  gid = OBJ2GID(id);
6241 #if defined(HAVE_SETRESGID)
6242  if (setresgid(gid, -1, -1) < 0) rb_sys_fail(0);
6243 #elif defined HAVE_SETREGID
6244  if (setregid(gid, -1) < 0) rb_sys_fail(0);
6245 #elif defined HAVE_SETRGID
6246  if (setrgid(gid) < 0) rb_sys_fail(0);
6247 #elif defined HAVE_SETGID
6248  {
6249  if (getegid() == gid) {
6250  if (setgid(gid) < 0) rb_sys_fail(0);
6251  }
6252  else {
6253  rb_notimplement();
6254  }
6255  }
6256 #endif
6257  return GIDT2NUM(gid);
6258 }
6259 #else
6260 #define proc_setgid rb_f_notimplement
6261 #endif
6262 
6263 
6264 #if defined(_SC_NGROUPS_MAX) || defined(NGROUPS_MAX)
6265 /*
6266  * Maximum supplementary groups are platform dependent.
6267  * FWIW, 65536 is enough big for our supported OSs.
6268  *
6269  * OS Name max groups
6270  * -----------------------------------------------
6271  * Linux Kernel >= 2.6.3 65536
6272  * Linux Kernel < 2.6.3 32
6273  * IBM AIX 5.2 64
6274  * IBM AIX 5.3 ... 6.1 128
6275  * IBM AIX 7.1 128 (can be configured to be up to 2048)
6276  * OpenBSD, NetBSD 16
6277  * FreeBSD < 8.0 16
6278  * FreeBSD >=8.0 1023
6279  * Darwin (Mac OS X) 16
6280  * Sun Solaris 7,8,9,10 16
6281  * Sun Solaris 11 / OpenSolaris 1024
6282  * HP-UX 20
6283  * Windows 1015
6284  */
6285 static int _maxgroups = -1;
6286 static int
6287 get_sc_ngroups_max(void)
6288 {
6289 #ifdef _SC_NGROUPS_MAX
6290  return (int)sysconf(_SC_NGROUPS_MAX);
6291 #elif defined(NGROUPS_MAX)
6292  return (int)NGROUPS_MAX;
6293 #else
6294  return -1;
6295 #endif
6296 }
6297 static int
6298 maxgroups(void)
6299 {
6300  if (_maxgroups < 0) {
6301  _maxgroups = get_sc_ngroups_max();
6302  if (_maxgroups < 0)
6303  _maxgroups = RB_MAX_GROUPS;
6304  }
6305 
6306  return _maxgroups;
6307 }
6308 #endif
6309 
6310 
6311 
6312 #ifdef HAVE_GETGROUPS
6313 /*
6314  * call-seq:
6315  * Process.groups -> array
6316  *
6317  * Get an Array of the group IDs in the
6318  * supplemental group access list for this process.
6319  *
6320  * Process.groups #=> [27, 6, 10, 11]
6321  *
6322  * Note that this method is just a wrapper of getgroups(2).
6323  * This means that the following characteristics of
6324  * the result completely depend on your system:
6325  *
6326  * - the result is sorted
6327  * - the result includes effective GIDs
6328  * - the result does not include duplicated GIDs
6329  *
6330  * You can make sure to get a sorted unique GID list of
6331  * the current process by this expression:
6332  *
6333  * Process.groups.uniq.sort
6334  *
6335  */
6336 
6337 static VALUE
6339 {
6340  VALUE ary, tmp;
6341  int i, ngroups;
6342  rb_gid_t *groups;
6343 
6344  ngroups = getgroups(0, NULL);
6345  if (ngroups == -1)
6346  rb_sys_fail(0);
6347 
6348  groups = ALLOCV_N(rb_gid_t, tmp, ngroups);
6349 
6350  ngroups = getgroups(ngroups, groups);
6351  if (ngroups == -1)
6352  rb_sys_fail(0);
6353 
6354  ary = rb_ary_new();
6355  for (i = 0; i < ngroups; i++)
6356  rb_ary_push(ary, GIDT2NUM(groups[i]));
6357 
6358  ALLOCV_END(tmp);
6359 
6360  return ary;
6361 }
6362 #else
6363 #define proc_getgroups rb_f_notimplement
6364 #endif
6365 
6366 
6367 #ifdef HAVE_SETGROUPS
6368 /*
6369  * call-seq:
6370  * Process.groups= array -> array
6371  *
6372  * Set the supplemental group access list to the given
6373  * Array of group IDs.
6374  *
6375  * Process.groups #=> [0, 1, 2, 3, 4, 6, 10, 11, 20, 26, 27]
6376  * Process.groups = [27, 6, 10, 11] #=> [27, 6, 10, 11]
6377  * Process.groups #=> [27, 6, 10, 11]
6378  *
6379  */
6380 
6381 static VALUE
6383 {
6384  int ngroups, i;
6385  rb_gid_t *groups;
6386  VALUE tmp;
6388 
6389  Check_Type(ary, T_ARRAY);
6390 
6391  ngroups = RARRAY_LENINT(ary);
6392  if (ngroups > maxgroups())
6393  rb_raise(rb_eArgError, "too many groups, %d max", maxgroups());
6394 
6395  groups = ALLOCV_N(rb_gid_t, tmp, ngroups);
6396 
6397  for (i = 0; i < ngroups; i++) {
6398  VALUE g = RARRAY_AREF(ary, i);
6399 
6400  groups[i] = OBJ2GID1(g);
6401  }
6403 
6404  if (setgroups(ngroups, groups) == -1) /* ngroups <= maxgroups */
6405  rb_sys_fail(0);
6406 
6407  ALLOCV_END(tmp);
6408 
6409  return proc_getgroups(obj);
6410 }
6411 #else
6412 #define proc_setgroups rb_f_notimplement
6413 #endif
6414 
6415 
6416 #ifdef HAVE_INITGROUPS
6417 /*
6418  * call-seq:
6419  * Process.initgroups(username, gid) -> array
6420  *
6421  * Initializes the supplemental group access list by reading the
6422  * system group database and using all groups of which the given user
6423  * is a member. The group with the specified <em>gid</em> is also
6424  * added to the list. Returns the resulting Array of the
6425  * gids of all the groups in the supplementary group access list. Not
6426  * available on all platforms.
6427  *
6428  * Process.groups #=> [0, 1, 2, 3, 4, 6, 10, 11, 20, 26, 27]
6429  * Process.initgroups( "mgranger", 30 ) #=> [30, 6, 10, 11]
6430  * Process.groups #=> [30, 6, 10, 11]
6431  *
6432  */
6433 
6434 static VALUE
6435 proc_initgroups(VALUE obj, VALUE uname, VALUE base_grp)
6436 {
6437  if (initgroups(StringValueCStr(uname), OBJ2GID(base_grp)) != 0) {
6438  rb_sys_fail(0);
6439  }
6440  return proc_getgroups(obj);
6441 }
6442 #else
6443 #define proc_initgroups rb_f_notimplement
6444 #endif
6445 
6446 #if defined(_SC_NGROUPS_MAX) || defined(NGROUPS_MAX)
6447 /*
6448  * call-seq:
6449  * Process.maxgroups -> integer
6450  *
6451  * Returns the maximum number of gids allowed in the supplemental
6452  * group access list.
6453  *
6454  * Process.maxgroups #=> 32
6455  */
6456 
6457 static VALUE
6459 {
6460  return INT2FIX(maxgroups());
6461 }
6462 #else
6463 #define proc_getmaxgroups rb_f_notimplement
6464 #endif
6465 
6466 #ifdef HAVE_SETGROUPS
6467 /*
6468  * call-seq:
6469  * Process.maxgroups= integer -> integer
6470  *
6471  * Sets the maximum number of gids allowed in the supplemental group
6472  * access list.
6473  */
6474 
6475 static VALUE
6477 {
6478  int ngroups = FIX2INT(val);
6479  int ngroups_max = get_sc_ngroups_max();
6480 
6481  if (ngroups <= 0)
6482  rb_raise(rb_eArgError, "maxgroups %d should be positive", ngroups);
6483 
6484  if (ngroups > RB_MAX_GROUPS)
6485  ngroups = RB_MAX_GROUPS;
6486 
6487  if (ngroups_max > 0 && ngroups > ngroups_max)
6488  ngroups = ngroups_max;
6489 
6490  _maxgroups = ngroups;
6491 
6492  return INT2FIX(_maxgroups);
6493 }
6494 #else
6495 #define proc_setmaxgroups rb_f_notimplement
6496 #endif
6497 
6498 #if defined(HAVE_DAEMON) || (defined(HAVE_WORKING_FORK) && defined(HAVE_SETSID))
6499 static int rb_daemon(int nochdir, int noclose);
6500 
6501 /*
6502  * call-seq:
6503  * Process.daemon() -> 0
6504  * Process.daemon(nochdir=nil,noclose=nil) -> 0
6505  *
6506  * Detach the process from controlling terminal and run in
6507  * the background as system daemon. Unless the argument
6508  * nochdir is true (i.e. non false), it changes the current
6509  * working directory to the root ("/"). Unless the argument
6510  * noclose is true, daemon() will redirect standard input,
6511  * standard output and standard error to /dev/null.
6512  * Return zero on success, or raise one of Errno::*.
6513  */
6514 
6515 static VALUE
6516 proc_daemon(int argc, VALUE *argv, VALUE _)
6517 {
6518  int n, nochdir = FALSE, noclose = FALSE;
6519 
6520  switch (rb_check_arity(argc, 0, 2)) {
6521  case 2: noclose = TO_BOOL(argv[1], "noclose");
6522  case 1: nochdir = TO_BOOL(argv[0], "nochdir");
6523  }
6524 
6525  prefork();
6526  n = rb_daemon(nochdir, noclose);
6527  if (n < 0) rb_sys_fail("daemon");
6528  return INT2FIX(n);
6529 }
6530 
6531 static int
6532 rb_daemon(int nochdir, int noclose)
6533 {
6534  int err = 0;
6535 #ifdef HAVE_DAEMON
6536  if (mjit_enabled) mjit_pause(false); // Don't leave locked mutex to child.
6537  before_fork_ruby();
6538  err = daemon(nochdir, noclose);
6539  after_fork_ruby();
6540  rb_thread_atfork(); /* calls mjit_resume() */
6541 #else
6542  int n;
6543 
6544 #define fork_daemon() \
6545  switch (rb_fork_ruby(NULL)) { \
6546  case -1: return -1; \
6547  case 0: rb_thread_atfork(); break; \
6548  default: _exit(EXIT_SUCCESS); \
6549  }
6550 
6551  fork_daemon();
6552 
6553  if (setsid() < 0) return -1;
6554 
6555  /* must not be process-leader */
6556  fork_daemon();
6557 
6558  if (!nochdir)
6559  err = chdir("/");
6560 
6561  if (!noclose && (n = rb_cloexec_open("/dev/null", O_RDWR, 0)) != -1) {
6563  (void)dup2(n, 0);
6564  (void)dup2(n, 1);
6565  (void)dup2(n, 2);
6566  if (n > 2)
6567  (void)close (n);
6568  }
6569 #endif
6570  return err;
6571 }
6572 #else
6573 #define proc_daemon rb_f_notimplement
6574 #endif
6575 
6576 /********************************************************************
6577  *
6578  * Document-class: Process::GID
6579  *
6580  * The Process::GID module contains a collection of
6581  * module functions which can be used to portably get, set, and
6582  * switch the current process's real, effective, and saved group IDs.
6583  *
6584  */
6585 
6586 static rb_gid_t SAVED_GROUP_ID = -1;
6587 
6588 #ifdef BROKEN_SETREGID
6589 int
6590 setregid(rb_gid_t rgid, rb_gid_t egid)
6591 {
6592  if (rgid != (rb_gid_t)-1 && rgid != getgid()) {
6593  if (egid == (rb_gid_t)-1) egid = getegid();
6594  if (setgid(rgid) < 0) return -1;
6595  }
6596  if (egid != (rb_gid_t)-1 && egid != getegid()) {
6597  if (setegid(egid) < 0) return -1;
6598  }
6599  return 0;
6600 }
6601 #endif
6602 
6603 /*
6604  * call-seq:
6605  * Process::GID.change_privilege(group) -> integer
6606  *
6607  * Change the current process's real and effective group ID to that
6608  * specified by _group_. Returns the new group ID. Not
6609  * available on all platforms.
6610  *
6611  * [Process.gid, Process.egid] #=> [0, 0]
6612  * Process::GID.change_privilege(33) #=> 33
6613  * [Process.gid, Process.egid] #=> [33, 33]
6614  */
6615 
6616 static VALUE
6617 p_gid_change_privilege(VALUE obj, VALUE id)
6618 {
6619  rb_gid_t gid;
6620 
6621  check_gid_switch();
6622 
6623  gid = OBJ2GID(id);
6624 
6625  if (geteuid() == 0) { /* root-user */
6626 #if defined(HAVE_SETRESGID)
6627  if (setresgid(gid, gid, gid) < 0) rb_sys_fail(0);
6628  SAVED_GROUP_ID = gid;
6629 #elif defined HAVE_SETGID
6630  if (setgid(gid) < 0) rb_sys_fail(0);
6631  SAVED_GROUP_ID = gid;
6632 #elif defined(HAVE_SETREGID) && !defined(OBSOLETE_SETREGID)
6633  if (getgid() == gid) {
6634  if (SAVED_GROUP_ID == gid) {
6635  if (setregid(-1, gid) < 0) rb_sys_fail(0);
6636  }
6637  else {
6638  if (gid == 0) { /* (r,e,s) == (root, y, x) */
6639  if (setregid(-1, SAVED_GROUP_ID) < 0) rb_sys_fail(0);
6640  if (setregid(SAVED_GROUP_ID, 0) < 0) rb_sys_fail(0);
6641  SAVED_GROUP_ID = 0; /* (r,e,s) == (x, root, root) */
6642  if (setregid(gid, gid) < 0) rb_sys_fail(0);
6643  SAVED_GROUP_ID = gid;
6644  }
6645  else { /* (r,e,s) == (z, y, x) */
6646  if (setregid(0, 0) < 0) rb_sys_fail(0);
6647  SAVED_GROUP_ID = 0;
6648  if (setregid(gid, gid) < 0) rb_sys_fail(0);
6649  SAVED_GROUP_ID = gid;
6650  }
6651  }
6652  }
6653  else {
6654  if (setregid(gid, gid) < 0) rb_sys_fail(0);
6655  SAVED_GROUP_ID = gid;
6656  }
6657 #elif defined(HAVE_SETRGID) && defined (HAVE_SETEGID)
6658  if (getgid() == gid) {
6659  if (SAVED_GROUP_ID == gid) {
6660  if (setegid(gid) < 0) rb_sys_fail(0);
6661  }
6662  else {
6663  if (gid == 0) {
6664  if (setegid(gid) < 0) rb_sys_fail(0);
6665  if (setrgid(SAVED_GROUP_ID) < 0) rb_sys_fail(0);
6666  SAVED_GROUP_ID = 0;
6667  if (setrgid(0) < 0) rb_sys_fail(0);
6668  }
6669  else {
6670  if (setrgid(0) < 0) rb_sys_fail(0);
6671  SAVED_GROUP_ID = 0;
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  }
6677  }
6678  else {
6679  if (setegid(gid) < 0) rb_sys_fail(0);
6680  if (setrgid(gid) < 0) rb_sys_fail(0);
6681  SAVED_GROUP_ID = gid;
6682  }
6683 #else
6684  rb_notimplement();
6685 #endif
6686  }
6687  else { /* unprivileged user */
6688 #if defined(HAVE_SETRESGID)
6689  if (setresgid((getgid() == gid)? (rb_gid_t)-1: gid,
6690  (getegid() == gid)? (rb_gid_t)-1: gid,
6691  (SAVED_GROUP_ID == gid)? (rb_gid_t)-1: gid) < 0) rb_sys_fail(0);
6692  SAVED_GROUP_ID = gid;
6693 #elif defined(HAVE_SETREGID) && !defined(OBSOLETE_SETREGID)
6694  if (SAVED_GROUP_ID == gid) {
6695  if (setregid((getgid() == gid)? (rb_uid_t)-1: gid,
6696  (getegid() == gid)? (rb_uid_t)-1: gid) < 0)
6697  rb_sys_fail(0);
6698  }
6699  else if (getgid() != gid) {
6700  if (setregid(gid, (getegid() == gid)? (rb_uid_t)-1: gid) < 0)
6701  rb_sys_fail(0);
6702  SAVED_GROUP_ID = gid;
6703  }
6704  else if (/* getgid() == gid && */ getegid() != gid) {
6705  if (setregid(getegid(), gid) < 0) rb_sys_fail(0);
6706  SAVED_GROUP_ID = gid;
6707  if (setregid(gid, -1) < 0) rb_sys_fail(0);
6708  }
6709  else { /* getgid() == gid && getegid() == gid */
6710  if (setregid(-1, SAVED_GROUP_ID) < 0) rb_sys_fail(0);
6711  if (setregid(SAVED_GROUP_ID, gid) < 0) rb_sys_fail(0);
6712  SAVED_GROUP_ID = gid;
6713  if (setregid(gid, -1) < 0) rb_sys_fail(0);
6714  }
6715 #elif defined(HAVE_SETRGID) && defined(HAVE_SETEGID)
6716  if (SAVED_GROUP_ID == gid) {
6717  if (getegid() != gid && setegid(gid) < 0) rb_sys_fail(0);
6718  if (getgid() != gid && setrgid(gid) < 0) rb_sys_fail(0);
6719  }
6720  else if (/* SAVED_GROUP_ID != gid && */ getegid() == gid) {
6721  if (getgid() != gid) {
6722  if (setrgid(gid) < 0) rb_sys_fail(0);
6723  SAVED_GROUP_ID = gid;
6724  }
6725  else {
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  }
6731  else if (/* getegid() != gid && */ getgid() == gid) {
6732  if (setegid(gid) < 0) rb_sys_fail(0);
6733  if (setrgid(SAVED_GROUP_ID) < 0) rb_sys_fail(0);
6734  SAVED_GROUP_ID = gid;
6735  if (setrgid(gid) < 0) rb_sys_fail(0);
6736  }
6737  else {
6738  rb_syserr_fail(EPERM, 0);
6739  }
6740 #elif defined HAVE_44BSD_SETGID
6741  if (getgid() == gid) {
6742  /* (r,e,s)==(gid,?,?) ==> (gid,gid,gid) */
6743  if (setgid(gid) < 0) rb_sys_fail(0);
6744  SAVED_GROUP_ID = gid;
6745  }
6746  else {
6747  rb_syserr_fail(EPERM, 0);
6748  }
6749 #elif defined HAVE_SETEGID
6750  if (getgid() == gid && SAVED_GROUP_ID == gid) {
6751  if (setegid(gid) < 0) rb_sys_fail(0);
6752  }
6753  else {
6754  rb_syserr_fail(EPERM, 0);
6755  }
6756 #elif defined HAVE_SETGID
6757  if (getgid() == gid && SAVED_GROUP_ID == gid) {
6758  if (setgid(gid) < 0) rb_sys_fail(0);
6759  }
6760  else {
6761  rb_syserr_fail(EPERM, 0);
6762  }
6763 #else
6764  (void)gid;
6765  rb_notimplement();
6766 #endif
6767  }
6768  return id;
6769 }
6770 
6771 
6772 /*
6773  * call-seq:
6774  * Process.euid -> integer
6775  * Process::UID.eid -> integer
6776  * Process::Sys.geteuid -> integer
6777  *
6778  * Returns the effective user ID for this process.
6779  *
6780  * Process.euid #=> 501
6781  */
6782 
6783 static VALUE
6784 proc_geteuid(VALUE obj)
6785 {
6786  rb_uid_t euid = geteuid();
6787  return UIDT2NUM(euid);
6788 }
6789 
6790 #if defined(HAVE_SETRESUID) || defined(HAVE_SETREUID) || defined(HAVE_SETEUID) || defined(HAVE_SETUID) || defined(_POSIX_SAVED_IDS)
6791 static void
6792 proc_seteuid(rb_uid_t uid)
6793 {
6794 #if defined(HAVE_SETRESUID)
6795  if (setresuid(-1, uid, -1) < 0) rb_sys_fail(0);
6796 #elif defined HAVE_SETREUID
6797  if (setreuid(-1, uid) < 0) rb_sys_fail(0);
6798 #elif defined HAVE_SETEUID
6799  if (seteuid(uid) < 0) rb_sys_fail(0);
6800 #elif defined HAVE_SETUID
6801  if (uid == getuid()) {
6802  if (setuid(uid) < 0) rb_sys_fail(0);
6803  }
6804  else {
6805  rb_notimplement();
6806  }
6807 #else
6808  rb_notimplement();
6809 #endif
6810 }
6811 #endif
6812 
6813 #if defined(HAVE_SETRESUID) || defined(HAVE_SETREUID) || defined(HAVE_SETEUID) || defined(HAVE_SETUID)
6814 /*
6815  * call-seq:
6816  * Process.euid= user
6817  *
6818  * Sets the effective user ID for this process. Not available on all
6819  * platforms.
6820  */
6821 
6822 static VALUE
6824 {
6825  check_uid_switch();
6826  proc_seteuid(OBJ2UID(euid));
6827  return euid;
6828 }
6829 #else
6830 #define proc_seteuid_m rb_f_notimplement
6831 #endif
6832 
6833 static rb_uid_t
6834 rb_seteuid_core(rb_uid_t euid)
6835 {
6836 #if defined(HAVE_SETRESUID) || (defined(HAVE_SETREUID) && !defined(OBSOLETE_SETREUID))
6837  rb_uid_t uid;
6838 #endif
6839 
6840  check_uid_switch();
6841 
6842 #if defined(HAVE_SETRESUID) || (defined(HAVE_SETREUID) && !defined(OBSOLETE_SETREUID))
6843  uid = getuid();
6844 #endif
6845 
6846 #if defined(HAVE_SETRESUID)
6847  if (uid != euid) {
6848  if (setresuid(-1,euid,euid) < 0) rb_sys_fail(0);
6849  SAVED_USER_ID = euid;
6850  }
6851  else {
6852  if (setresuid(-1,euid,-1) < 0) rb_sys_fail(0);
6853  }
6854 #elif defined(HAVE_SETREUID) && !defined(OBSOLETE_SETREUID)
6855  if (setreuid(-1, euid) < 0) rb_sys_fail(0);
6856  if (uid != euid) {
6857  if (setreuid(euid,uid) < 0) rb_sys_fail(0);
6858  if (setreuid(uid,euid) < 0) rb_sys_fail(0);
6859  SAVED_USER_ID = euid;
6860  }
6861 #elif defined HAVE_SETEUID
6862  if (seteuid(euid) < 0) rb_sys_fail(0);
6863 #elif defined HAVE_SETUID
6864  if (geteuid() == 0) rb_sys_fail(0);
6865  if (setuid(euid) < 0) rb_sys_fail(0);
6866 #else
6867  rb_notimplement();
6868 #endif
6869  return euid;
6870 }
6871 
6872 
6873 /*
6874  * call-seq:
6875  * Process::UID.grant_privilege(user) -> integer
6876  * Process::UID.eid= user -> integer
6877  *
6878  * Set the effective user ID, and if possible, the saved user ID of
6879  * the process to the given _user_. Returns the new
6880  * effective user ID. Not available on all platforms.
6881  *
6882  * [Process.uid, Process.euid] #=> [0, 0]
6883  * Process::UID.grant_privilege(31) #=> 31
6884  * [Process.uid, Process.euid] #=> [0, 31]
6885  */
6886 
6887 static VALUE
6888 p_uid_grant_privilege(VALUE obj, VALUE id)
6889 {
6890  rb_seteuid_core(OBJ2UID(id));
6891  return id;
6892 }
6893 
6894 
6895 /*
6896  * call-seq:
6897  * Process.egid -> integer
6898  * Process::GID.eid -> integer
6899  * Process::Sys.geteid -> integer
6900  *
6901  * Returns the effective group ID for this process. Not available on
6902  * all platforms.
6903  *
6904  * Process.egid #=> 500
6905  */
6906 
6907 static VALUE
6908 proc_getegid(VALUE obj)
6909 {
6910  rb_gid_t egid = getegid();
6911 
6912  return GIDT2NUM(egid);
6913 }
6914 
6915 #if defined(HAVE_SETRESGID) || defined(HAVE_SETREGID) || defined(HAVE_SETEGID) || defined(HAVE_SETGID) || defined(_POSIX_SAVED_IDS)
6916 /*
6917  * call-seq:
6918  * Process.egid = integer -> integer
6919  *
6920  * Sets the effective group ID for this process. Not available on all
6921  * platforms.
6922  */
6923 
6924 static VALUE
6925 proc_setegid(VALUE obj, VALUE egid)
6926 {
6927 #if defined(HAVE_SETRESGID) || defined(HAVE_SETREGID) || defined(HAVE_SETEGID) || defined(HAVE_SETGID)
6928  rb_gid_t gid;
6929 #endif
6930 
6931  check_gid_switch();
6932 
6933 #if defined(HAVE_SETRESGID) || defined(HAVE_SETREGID) || defined(HAVE_SETEGID) || defined(HAVE_SETGID)
6934  gid = OBJ2GID(egid);
6935 #endif
6936 
6937 #if defined(HAVE_SETRESGID)
6938  if (setresgid(-1, gid, -1) < 0) rb_sys_fail(0);
6939 #elif defined HAVE_SETREGID
6940  if (setregid(-1, gid) < 0) rb_sys_fail(0);
6941 #elif defined HAVE_SETEGID
6942  if (setegid(gid) < 0) rb_sys_fail(0);
6943 #elif defined HAVE_SETGID
6944  if (gid == getgid()) {
6945  if (setgid(gid) < 0) rb_sys_fail(0);
6946  }
6947  else {
6948  rb_notimplement();
6949  }
6950 #else
6951  rb_notimplement();
6952 #endif
6953  return egid;
6954 }
6955 #endif
6956 
6957 #if defined(HAVE_SETRESGID) || defined(HAVE_SETREGID) || defined(HAVE_SETEGID) || defined(HAVE_SETGID)
6958 #define proc_setegid_m proc_setegid
6959 #else
6960 #define proc_setegid_m rb_f_notimplement
6961 #endif
6962 
6963 static rb_gid_t
6964 rb_setegid_core(rb_gid_t egid)
6965 {
6966 #if defined(HAVE_SETRESGID) || (defined(HAVE_SETREGID) && !defined(OBSOLETE_SETREGID))
6967  rb_gid_t gid;
6968 #endif
6969 
6970  check_gid_switch();
6971 
6972 #if defined(HAVE_SETRESGID) || (defined(HAVE_SETREGID) && !defined(OBSOLETE_SETREGID))
6973  gid = getgid();
6974 #endif
6975 
6976 #if defined(HAVE_SETRESGID)
6977  if (gid != egid) {
6978  if (setresgid(-1,egid,egid) < 0) rb_sys_fail(0);
6979  SAVED_GROUP_ID = egid;
6980  }
6981  else {
6982  if (setresgid(-1,egid,-1) < 0) rb_sys_fail(0);
6983  }
6984 #elif defined(HAVE_SETREGID) && !defined(OBSOLETE_SETREGID)
6985  if (setregid(-1, egid) < 0) rb_sys_fail(0);
6986  if (gid != egid) {
6987  if (setregid(egid,gid) < 0) rb_sys_fail(0);
6988  if (setregid(gid,egid) < 0) rb_sys_fail(0);
6989  SAVED_GROUP_ID = egid;
6990  }
6991 #elif defined HAVE_SETEGID
6992  if (setegid(egid) < 0) rb_sys_fail(0);
6993 #elif defined HAVE_SETGID
6994  if (geteuid() == 0 /* root user */) rb_sys_fail(0);
6995  if (setgid(egid) < 0) rb_sys_fail(0);
6996 #else
6997  rb_notimplement();
6998 #endif
6999  return egid;
7000 }
7001 
7002 
7003 /*
7004  * call-seq:
7005  * Process::GID.grant_privilege(group) -> integer
7006  * Process::GID.eid = group -> integer
7007  *
7008  * Set the effective group ID, and if possible, the saved group ID of
7009  * the process to the given _group_. Returns the new
7010  * effective group ID. Not available on all platforms.
7011  *
7012  * [Process.gid, Process.egid] #=> [0, 0]
7013  * Process::GID.grant_privilege(31) #=> 33
7014  * [Process.gid, Process.egid] #=> [0, 33]
7015  */
7016 
7017 static VALUE
7018 p_gid_grant_privilege(VALUE obj, VALUE id)
7019 {
7020  rb_setegid_core(OBJ2GID(id));
7021  return id;
7022 }
7023 
7024 
7025 /*
7026  * call-seq:
7027  * Process::UID.re_exchangeable? -> true or false
7028  *
7029  * Returns +true+ if the real and effective user IDs of a
7030  * process may be exchanged on the current platform.
7031  *
7032  */
7033 
7034 static VALUE
7035 p_uid_exchangeable(VALUE _)
7036 {
7037 #if defined(HAVE_SETRESUID)
7038  return Qtrue;
7039 #elif defined(HAVE_SETREUID) && !defined(OBSOLETE_SETREUID)
7040  return Qtrue;
7041 #else
7042  return Qfalse;
7043 #endif
7044 }
7045 
7046 
7047 /*
7048  * call-seq:
7049  * Process::UID.re_exchange -> integer
7050  *
7051  * Exchange real and effective user IDs and return the new effective
7052  * user ID. Not available on all platforms.
7053  *
7054  * [Process.uid, Process.euid] #=> [0, 31]
7055  * Process::UID.re_exchange #=> 0
7056  * [Process.uid, Process.euid] #=> [31, 0]
7057  */
7058 
7059 static VALUE
7060 p_uid_exchange(VALUE obj)
7061 {
7062  rb_uid_t uid;
7063 #if defined(HAVE_SETRESUID) || (defined(HAVE_SETREUID) && !defined(OBSOLETE_SETREUID))
7064  rb_uid_t euid;
7065 #endif
7066 
7067  check_uid_switch();
7068 
7069  uid = getuid();
7070 #if defined(HAVE_SETRESUID) || (defined(HAVE_SETREUID) && !defined(OBSOLETE_SETREUID))
7071  euid = geteuid();
7072 #endif
7073 
7074 #if defined(HAVE_SETRESUID)
7075  if (setresuid(euid, uid, uid) < 0) rb_sys_fail(0);
7076  SAVED_USER_ID = uid;
7077 #elif defined(HAVE_SETREUID) && !defined(OBSOLETE_SETREUID)
7078  if (setreuid(euid,uid) < 0) rb_sys_fail(0);
7079  SAVED_USER_ID = uid;
7080 #else
7081  rb_notimplement();
7082 #endif
7083  return UIDT2NUM(uid);
7084 }
7085 
7086 
7087 /*
7088  * call-seq:
7089  * Process::GID.re_exchangeable? -> true or false
7090  *
7091  * Returns +true+ if the real and effective group IDs of a
7092  * process may be exchanged on the current platform.
7093  *
7094  */
7095 
7096 static VALUE
7097 p_gid_exchangeable(VALUE _)
7098 {
7099 #if defined(HAVE_SETRESGID)
7100  return Qtrue;
7101 #elif defined(HAVE_SETREGID) && !defined(OBSOLETE_SETREGID)
7102  return Qtrue;
7103 #else
7104  return Qfalse;
7105 #endif
7106 }
7107 
7108 
7109 /*
7110  * call-seq:
7111  * Process::GID.re_exchange -> integer
7112  *
7113  * Exchange real and effective group IDs and return the new effective
7114  * group ID. Not available on all platforms.
7115  *
7116  * [Process.gid, Process.egid] #=> [0, 33]
7117  * Process::GID.re_exchange #=> 0
7118  * [Process.gid, Process.egid] #=> [33, 0]
7119  */
7120 
7121 static VALUE
7122 p_gid_exchange(VALUE obj)
7123 {
7124  rb_gid_t gid;
7125 #if defined(HAVE_SETRESGID) || (defined(HAVE_SETREGID) && !defined(OBSOLETE_SETREGID))
7126  rb_gid_t egid;
7127 #endif
7128 
7129  check_gid_switch();
7130 
7131  gid = getgid();
7132 #if defined(HAVE_SETRESGID) || (defined(HAVE_SETREGID) && !defined(OBSOLETE_SETREGID))
7133  egid = getegid();
7134 #endif
7135 
7136 #if defined(HAVE_SETRESGID)
7137  if (setresgid(egid, gid, gid) < 0) rb_sys_fail(0);
7138  SAVED_GROUP_ID = gid;
7139 #elif defined(HAVE_SETREGID) && !defined(OBSOLETE_SETREGID)
7140  if (setregid(egid,gid) < 0) rb_sys_fail(0);
7141  SAVED_GROUP_ID = gid;
7142 #else
7143  rb_notimplement();
7144 #endif
7145  return GIDT2NUM(gid);
7146 }
7147 
7148 /* [MG] :FIXME: Is this correct? I'm not sure how to phrase this. */
7149 
7150 /*
7151  * call-seq:
7152  * Process::UID.sid_available? -> true or false
7153  *
7154  * Returns +true+ if the current platform has saved user
7155  * ID functionality.
7156  *
7157  */
7158 
7159 static VALUE
7160 p_uid_have_saved_id(VALUE _)
7161 {
7162 #if defined(HAVE_SETRESUID) || defined(HAVE_SETEUID) || defined(_POSIX_SAVED_IDS)
7163  return Qtrue;
7164 #else
7165  return Qfalse;
7166 #endif
7167 }
7168 
7169 
7170 #if defined(HAVE_SETRESUID) || defined(HAVE_SETEUID) || defined(_POSIX_SAVED_IDS)
7171 static VALUE
7172 p_uid_sw_ensure(VALUE i)
7173 {
7174  rb_uid_t id = (rb_uid_t/* narrowing */)i;
7175  under_uid_switch = 0;
7176  id = rb_seteuid_core(id);
7177  return UIDT2NUM(id);
7178 }
7179 
7180 
7181 /*
7182  * call-seq:
7183  * Process::UID.switch -> integer
7184  * Process::UID.switch {|| block} -> object
7185  *
7186  * Switch the effective and real user IDs of the current process. If
7187  * a <em>block</em> is given, the user IDs will be switched back
7188  * after the block is executed. Returns the new effective user ID if
7189  * called without a block, and the return value of the block if one
7190  * is given.
7191  *
7192  */
7193 
7194 static VALUE
7195 p_uid_switch(VALUE obj)
7196 {
7197  rb_uid_t uid, euid;
7198 
7199  check_uid_switch();
7200 
7201  uid = getuid();
7202  euid = geteuid();
7203 
7204  if (uid != euid) {
7205  proc_seteuid(uid);
7206  if (rb_block_given_p()) {
7207  under_uid_switch = 1;
7208  return rb_ensure(rb_yield, Qnil, p_uid_sw_ensure, SAVED_USER_ID);
7209  }
7210  else {
7211  return UIDT2NUM(euid);
7212  }
7213  }
7214  else if (euid != SAVED_USER_ID) {
7215  proc_seteuid(SAVED_USER_ID);
7216  if (rb_block_given_p()) {
7217  under_uid_switch = 1;
7218  return rb_ensure(rb_yield, Qnil, p_uid_sw_ensure, euid);
7219  }
7220  else {
7221  return UIDT2NUM(uid);
7222  }
7223  }
7224  else {
7225  rb_syserr_fail(EPERM, 0);
7226  }
7227 
7229 }
7230 #else
7231 static VALUE
7232 p_uid_sw_ensure(VALUE obj)
7233 {
7234  under_uid_switch = 0;
7235  return p_uid_exchange(obj);
7236 }
7237 
7238 static VALUE
7239 p_uid_switch(VALUE obj)
7240 {
7241  rb_uid_t uid, euid;
7242 
7243  check_uid_switch();
7244 
7245  uid = getuid();
7246  euid = geteuid();
7247 
7248  if (uid == euid) {
7249  rb_syserr_fail(EPERM, 0);
7250  }
7251  p_uid_exchange(obj);
7252  if (rb_block_given_p()) {
7253  under_uid_switch = 1;
7254  return rb_ensure(rb_yield, Qnil, p_uid_sw_ensure, obj);
7255  }
7256  else {
7257  return UIDT2NUM(euid);
7258  }
7259 }
7260 #endif
7261 
7262 
7263 /* [MG] :FIXME: Is this correct? I'm not sure how to phrase this. */
7264 
7265 /*
7266  * call-seq:
7267  * Process::GID.sid_available? -> true or false
7268  *
7269  * Returns +true+ if the current platform has saved group
7270  * ID functionality.
7271  *
7272  */
7273 
7274 static VALUE
7275 p_gid_have_saved_id(VALUE _)
7276 {
7277 #if defined(HAVE_SETRESGID) || defined(HAVE_SETEGID) || defined(_POSIX_SAVED_IDS)
7278  return Qtrue;
7279 #else
7280  return Qfalse;
7281 #endif
7282 }
7283 
7284 #if defined(HAVE_SETRESGID) || defined(HAVE_SETEGID) || defined(_POSIX_SAVED_IDS)
7285 static VALUE
7286 p_gid_sw_ensure(VALUE i)
7287 {
7288  rb_gid_t id = (rb_gid_t/* narrowing */)i;
7289  under_gid_switch = 0;
7290  id = rb_setegid_core(id);
7291  return GIDT2NUM(id);
7292 }
7293 
7294 
7295 /*
7296  * call-seq:
7297  * Process::GID.switch -> integer
7298  * Process::GID.switch {|| block} -> object
7299  *
7300  * Switch the effective and real group IDs of the current process. If
7301  * a <em>block</em> is given, the group IDs will be switched back
7302  * after the block is executed. Returns the new effective group ID if
7303  * called without a block, and the return value of the block if one
7304  * is given.
7305  *
7306  */
7307 
7308 static VALUE
7309 p_gid_switch(VALUE obj)
7310 {
7311  rb_gid_t gid, egid;
7312 
7313  check_gid_switch();
7314 
7315  gid = getgid();
7316  egid = getegid();
7317 
7318  if (gid != egid) {
7319  proc_setegid(obj, GIDT2NUM(gid));
7320  if (rb_block_given_p()) {
7321  under_gid_switch = 1;
7322  return rb_ensure(rb_yield, Qnil, p_gid_sw_ensure, SAVED_GROUP_ID);
7323  }
7324  else {
7325  return GIDT2NUM(egid);
7326  }
7327  }
7328  else if (egid != SAVED_GROUP_ID) {
7329  proc_setegid(obj, GIDT2NUM(SAVED_GROUP_ID));
7330  if (rb_block_given_p()) {
7331  under_gid_switch = 1;
7332  return rb_ensure(rb_yield, Qnil, p_gid_sw_ensure, egid);
7333  }
7334  else {
7335  return GIDT2NUM(gid);
7336  }
7337  }
7338  else {
7339  rb_syserr_fail(EPERM, 0);
7340  }
7341 
7343 }
7344 #else
7345 static VALUE
7346 p_gid_sw_ensure(VALUE obj)
7347 {
7348  under_gid_switch = 0;
7349  return p_gid_exchange(obj);
7350 }
7351 
7352 static VALUE
7353 p_gid_switch(VALUE obj)
7354 {
7355  rb_gid_t gid, egid;
7356 
7357  check_gid_switch();
7358 
7359  gid = getgid();
7360  egid = getegid();
7361 
7362  if (gid == egid) {
7363  rb_syserr_fail(EPERM, 0);
7364  }
7365  p_gid_exchange(obj);
7366  if (rb_block_given_p()) {
7367  under_gid_switch = 1;
7368  return rb_ensure(rb_yield, Qnil, p_gid_sw_ensure, obj);
7369  }
7370  else {
7371  return GIDT2NUM(egid);
7372  }
7373 }
7374 #endif
7375 
7376 
7377 #if defined(HAVE_TIMES)
7378 static long
7379 get_clk_tck(void)
7380 {
7381 #ifdef HAVE__SC_CLK_TCK
7382  return sysconf(_SC_CLK_TCK);
7383 #elif defined CLK_TCK
7384  return CLK_TCK;
7385 #elif defined HZ
7386  return HZ;
7387 #else
7388  return 60;
7389 #endif
7390 }
7391 
7392 /*
7393  * call-seq:
7394  * Process.times -> aProcessTms
7395  *
7396  * Returns a <code>Tms</code> structure (see Process::Tms)
7397  * that contains user and system CPU times for this process,
7398  * and also for children processes.
7399  *
7400  * t = Process.times
7401  * [ t.utime, t.stime, t.cutime, t.cstime ] #=> [0.0, 0.02, 0.00, 0.00]
7402  */
7403 
7404 VALUE
7406 {
7407  VALUE utime, stime, cutime, cstime, ret;
7408 #if defined(RUSAGE_SELF) && defined(RUSAGE_CHILDREN)
7409  struct rusage usage_s, usage_c;
7410 
7411  if (getrusage(RUSAGE_SELF, &usage_s) != 0 || getrusage(RUSAGE_CHILDREN, &usage_c) != 0)
7412  rb_sys_fail("getrusage");
7413  utime = DBL2NUM((double)usage_s.ru_utime.tv_sec + (double)usage_s.ru_utime.tv_usec/1e6);
7414  stime = DBL2NUM((double)usage_s.ru_stime.tv_sec + (double)usage_s.ru_stime.tv_usec/1e6);
7415  cutime = DBL2NUM((double)usage_c.ru_utime.tv_sec + (double)usage_c.ru_utime.tv_usec/1e6);
7416  cstime = DBL2NUM((double)usage_c.ru_stime.tv_sec + (double)usage_c.ru_stime.tv_usec/1e6);
7417 #else
7418  const double hertz = (double)get_clk_tck();
7419  struct tms buf;
7420 
7421  times(&buf);
7422  utime = DBL2NUM(buf.tms_utime / hertz);
7423  stime = DBL2NUM(buf.tms_stime / hertz);
7424  cutime = DBL2NUM(buf.tms_cutime / hertz);
7425  cstime = DBL2NUM(buf.tms_cstime / hertz);
7426 #endif
7427  ret = rb_struct_new(rb_cProcessTms, utime, stime, cutime, cstime);
7428  RB_GC_GUARD(utime);
7429  RB_GC_GUARD(stime);
7430  RB_GC_GUARD(cutime);
7431  RB_GC_GUARD(cstime);
7432  return ret;
7433 }
7434 #else
7435 #define rb_proc_times rb_f_notimplement
7436 #endif
7437 
7438 #ifdef HAVE_LONG_LONG
7439 typedef LONG_LONG timetick_int_t;
7440 #define TIMETICK_INT_MIN LLONG_MIN
7441 #define TIMETICK_INT_MAX LLONG_MAX
7442 #define TIMETICK_INT2NUM(v) LL2NUM(v)
7443 #define MUL_OVERFLOW_TIMETICK_P(a, b) MUL_OVERFLOW_LONG_LONG_P(a, b)
7444 #else
7445 typedef long timetick_int_t;
7446 #define TIMETICK_INT_MIN LONG_MIN
7447 #define TIMETICK_INT_MAX LONG_MAX
7448 #define TIMETICK_INT2NUM(v) LONG2NUM(v)
7449 #define MUL_OVERFLOW_TIMETICK_P(a, b) MUL_OVERFLOW_LONG_P(a, b)
7450 #endif
7451 
7452 CONSTFUNC(static timetick_int_t gcd_timetick_int(timetick_int_t, timetick_int_t));
7453 static timetick_int_t
7454 gcd_timetick_int(timetick_int_t a, timetick_int_t b)
7455 {
7456  timetick_int_t t;
7457 
7458  if (a < b) {
7459  t = a;
7460  a = b;
7461  b = t;
7462  }
7463 
7464  while (1) {
7465  t = a % b;
7466  if (t == 0)
7467  return b;
7468  a = b;
7469  b = t;
7470  }
7471 }
7472 
7473 static void
7474 reduce_fraction(timetick_int_t *np, timetick_int_t *dp)
7475 {
7476  timetick_int_t gcd = gcd_timetick_int(*np, *dp);
7477  if (gcd != 1) {
7478  *np /= gcd;
7479  *dp /= gcd;
7480  }
7481 }
7482 
7483 static void
7484 reduce_factors(timetick_int_t *numerators, int num_numerators,
7485  timetick_int_t *denominators, int num_denominators)
7486 {
7487  int i, j;
7488  for (i = 0; i < num_numerators; i++) {
7489  if (numerators[i] == 1)
7490  continue;
7491  for (j = 0; j < num_denominators; j++) {
7492  if (denominators[j] == 1)
7493  continue;
7494  reduce_fraction(&numerators[i], &denominators[j]);
7495  }
7496  }
7497 }
7498 
7499 struct timetick {
7501  int32_t count; /* 0 .. 999999999 */
7502 };
7503 
7504 static VALUE
7505 timetick2dblnum(struct timetick *ttp,
7506  timetick_int_t *numerators, int num_numerators,
7507  timetick_int_t *denominators, int num_denominators)
7508 {
7509  double d;
7510  int i;
7511 
7512  reduce_factors(numerators, num_numerators,
7513  denominators, num_denominators);
7514 
7515  d = ttp->giga_count * 1e9 + ttp->count;
7516 
7517  for (i = 0; i < num_numerators; i++)
7518  d *= numerators[i];
7519  for (i = 0; i < num_denominators; i++)
7520  d /= denominators[i];
7521 
7522  return DBL2NUM(d);
7523 }
7524 
7525 static VALUE
7526 timetick2dblnum_reciprocal(struct timetick *ttp,
7527  timetick_int_t *numerators, int num_numerators,
7528  timetick_int_t *denominators, int num_denominators)
7529 {
7530  double d;
7531  int i;
7532 
7533  reduce_factors(numerators, num_numerators,
7534  denominators, num_denominators);
7535 
7536  d = 1.0;
7537  for (i = 0; i < num_denominators; i++)
7538  d *= denominators[i];
7539  for (i = 0; i < num_numerators; i++)
7540  d /= numerators[i];
7541  d /= ttp->giga_count * 1e9 + ttp->count;
7542 
7543  return DBL2NUM(d);
7544 }
7545 
7546 #define NDIV(x,y) (-(-((x)+1)/(y))-1)
7547 #define DIV(n,d) ((n)<0 ? NDIV((n),(d)) : (n)/(d))
7548 
7549 static VALUE
7550 timetick2integer(struct timetick *ttp,
7551  timetick_int_t *numerators, int num_numerators,
7552  timetick_int_t *denominators, int num_denominators)
7553 {
7554  VALUE v;
7555  int i;
7556 
7557  reduce_factors(numerators, num_numerators,
7558  denominators, num_denominators);
7559 
7560  if (!MUL_OVERFLOW_SIGNED_INTEGER_P(1000000000, ttp->giga_count,
7562  timetick_int_t t = ttp->giga_count * 1000000000 + ttp->count;
7563  for (i = 0; i < num_numerators; i++) {
7564  timetick_int_t factor = numerators[i];
7565  if (MUL_OVERFLOW_TIMETICK_P(factor, t))
7566  goto generic;
7567  t *= factor;
7568  }
7569  for (i = 0; i < num_denominators; i++) {
7570  t = DIV(t, denominators[i]);
7571  }
7572  return TIMETICK_INT2NUM(t);
7573  }
7574 
7575  generic:
7576  v = TIMETICK_INT2NUM(ttp->giga_count);
7577  v = rb_funcall(v, '*', 1, LONG2FIX(1000000000));
7578  v = rb_funcall(v, '+', 1, LONG2FIX(ttp->count));
7579  for (i = 0; i < num_numerators; i++) {
7580  timetick_int_t factor = numerators[i];
7581  if (factor == 1)
7582  continue;
7583  v = rb_funcall(v, '*', 1, TIMETICK_INT2NUM(factor));
7584  }
7585  for (i = 0; i < num_denominators; i++) {
7586  v = rb_funcall(v, '/', 1, TIMETICK_INT2NUM(denominators[i])); /* Ruby's '/' is div. */
7587  }
7588  return v;
7589 }
7590 
7591 static VALUE
7592 make_clock_result(struct timetick *ttp,
7593  timetick_int_t *numerators, int num_numerators,
7594  timetick_int_t *denominators, int num_denominators,
7595  VALUE unit)
7596 {
7597  if (unit == ID2SYM(id_nanosecond)) {
7598  numerators[num_numerators++] = 1000000000;
7599  return timetick2integer(ttp, numerators, num_numerators, denominators, num_denominators);
7600  }
7601  else if (unit == ID2SYM(id_microsecond)) {
7602  numerators[num_numerators++] = 1000000;
7603  return timetick2integer(ttp, numerators, num_numerators, denominators, num_denominators);
7604  }
7605  else if (unit == ID2SYM(id_millisecond)) {
7606  numerators[num_numerators++] = 1000;
7607  return timetick2integer(ttp, numerators, num_numerators, denominators, num_denominators);
7608  }
7609  else if (unit == ID2SYM(id_second)) {
7610  return timetick2integer(ttp, numerators, num_numerators, denominators, num_denominators);
7611  }
7612  else if (unit == ID2SYM(id_float_microsecond)) {
7613  numerators[num_numerators++] = 1000000;
7614  return timetick2dblnum(ttp, numerators, num_numerators, denominators, num_denominators);
7615  }
7616  else if (unit == ID2SYM(id_float_millisecond)) {
7617  numerators[num_numerators++] = 1000;
7618  return timetick2dblnum(ttp, numerators, num_numerators, denominators, num_denominators);
7619  }
7620  else if (NIL_P(unit) || unit == ID2SYM(id_float_second)) {
7621  return timetick2dblnum(ttp, numerators, num_numerators, denominators, num_denominators);
7622  }
7623  else
7624  rb_raise(rb_eArgError, "unexpected unit: %"PRIsVALUE, unit);
7625 }
7626 
7627 #ifdef __APPLE__
7628 static const mach_timebase_info_data_t *
7629 get_mach_timebase_info(void)
7630 {
7631  static mach_timebase_info_data_t sTimebaseInfo;
7632 
7633  if ( sTimebaseInfo.denom == 0 ) {
7634  (void) mach_timebase_info(&sTimebaseInfo);
7635  }
7636 
7637  return &sTimebaseInfo;
7638 }
7639 
7640 double
7641 ruby_real_ms_time(void)
7642 {
7643  const mach_timebase_info_data_t *info = get_mach_timebase_info();
7644  uint64_t t = mach_absolute_time();
7645  return (double)t * info->numer / info->denom / 1e6;
7646 }
7647 #endif
7648 
7649 /*
7650  * call-seq:
7651  * Process.clock_gettime(clock_id [, unit]) -> number
7652  *
7653  * Returns a time returned by POSIX clock_gettime() function.
7654  *
7655  * p Process.clock_gettime(Process::CLOCK_MONOTONIC)
7656  * #=> 896053.968060096
7657  *
7658  * +clock_id+ specifies a kind of clock.
7659  * It is specified as a constant which begins with <code>Process::CLOCK_</code>
7660  * such as Process::CLOCK_REALTIME and Process::CLOCK_MONOTONIC.
7661  *
7662  * The supported constants depends on OS and version.
7663  * Ruby provides following types of +clock_id+ if available.
7664  *
7665  * [CLOCK_REALTIME] SUSv2 to 4, Linux 2.5.63, FreeBSD 3.0, NetBSD 2.0, OpenBSD 2.1, macOS 10.12
7666  * [CLOCK_MONOTONIC] SUSv3 to 4, Linux 2.5.63, FreeBSD 3.0, NetBSD 2.0, OpenBSD 3.4, macOS 10.12
7667  * [CLOCK_PROCESS_CPUTIME_ID] SUSv3 to 4, Linux 2.5.63, FreeBSD 9.3, OpenBSD 5.4, macOS 10.12
7668  * [CLOCK_THREAD_CPUTIME_ID] SUSv3 to 4, Linux 2.5.63, FreeBSD 7.1, OpenBSD 5.4, macOS 10.12
7669  * [CLOCK_VIRTUAL] FreeBSD 3.0, OpenBSD 2.1
7670  * [CLOCK_PROF] FreeBSD 3.0, OpenBSD 2.1
7671  * [CLOCK_REALTIME_FAST] FreeBSD 8.1
7672  * [CLOCK_REALTIME_PRECISE] FreeBSD 8.1
7673  * [CLOCK_REALTIME_COARSE] Linux 2.6.32
7674  * [CLOCK_REALTIME_ALARM] Linux 3.0
7675  * [CLOCK_MONOTONIC_FAST] FreeBSD 8.1
7676  * [CLOCK_MONOTONIC_PRECISE] FreeBSD 8.1
7677  * [CLOCK_MONOTONIC_COARSE] Linux 2.6.32
7678  * [CLOCK_MONOTONIC_RAW] Linux 2.6.28, macOS 10.12
7679  * [CLOCK_MONOTONIC_RAW_APPROX] macOS 10.12
7680  * [CLOCK_BOOTTIME] Linux 2.6.39
7681  * [CLOCK_BOOTTIME_ALARM] Linux 3.0
7682  * [CLOCK_UPTIME] FreeBSD 7.0, OpenBSD 5.5
7683  * [CLOCK_UPTIME_FAST] FreeBSD 8.1
7684  * [CLOCK_UPTIME_RAW] macOS 10.12
7685  * [CLOCK_UPTIME_RAW_APPROX] macOS 10.12
7686  * [CLOCK_UPTIME_PRECISE] FreeBSD 8.1
7687  * [CLOCK_SECOND] FreeBSD 8.1
7688  * [CLOCK_TAI] Linux 3.10
7689  *
7690  * Note that SUS stands for Single Unix Specification.
7691  * SUS contains POSIX and clock_gettime is defined in the POSIX part.
7692  * SUS defines CLOCK_REALTIME mandatory but
7693  * CLOCK_MONOTONIC, CLOCK_PROCESS_CPUTIME_ID and CLOCK_THREAD_CPUTIME_ID are optional.
7694  *
7695  * Also, several symbols are accepted as +clock_id+.
7696  * There are emulations for clock_gettime().
7697  *
7698  * For example, Process::CLOCK_REALTIME is defined as
7699  * +:GETTIMEOFDAY_BASED_CLOCK_REALTIME+ when clock_gettime() is not available.
7700  *
7701  * Emulations for +CLOCK_REALTIME+:
7702  * [:GETTIMEOFDAY_BASED_CLOCK_REALTIME]
7703  * Use gettimeofday() defined by SUS.
7704  * (SUSv4 obsoleted it, though.)
7705  * The resolution is 1 microsecond.
7706  * [:TIME_BASED_CLOCK_REALTIME]
7707  * Use time() defined by ISO C.
7708  * The resolution is 1 second.
7709  *
7710  * Emulations for +CLOCK_MONOTONIC+:
7711  * [:MACH_ABSOLUTE_TIME_BASED_CLOCK_MONOTONIC]
7712  * Use mach_absolute_time(), available on Darwin.
7713  * The resolution is CPU dependent.
7714  * [:TIMES_BASED_CLOCK_MONOTONIC]
7715  * Use the result value of times() defined by POSIX.
7716  * 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)".
7717  * For example, GNU/Linux returns a value based on jiffies and it is monotonic.
7718  * However, 4.4BSD uses gettimeofday() and it is not monotonic.
7719  * (FreeBSD uses clock_gettime(CLOCK_MONOTONIC) instead, though.)
7720  * The resolution is the clock tick.
7721  * "getconf CLK_TCK" command shows the clock ticks per second.
7722  * (The clock ticks per second is defined by HZ macro in older systems.)
7723  * If it is 100 and clock_t is 32 bits integer type, the resolution is 10 millisecond and
7724  * cannot represent over 497 days.
7725  *
7726  * Emulations for +CLOCK_PROCESS_CPUTIME_ID+:
7727  * [:GETRUSAGE_BASED_CLOCK_PROCESS_CPUTIME_ID]
7728  * Use getrusage() defined by SUS.
7729  * getrusage() is used with RUSAGE_SELF to obtain the time only for
7730  * the calling process (excluding the time for child processes).
7731  * The result is addition of user time (ru_utime) and system time (ru_stime).
7732  * The resolution is 1 microsecond.
7733  * [:TIMES_BASED_CLOCK_PROCESS_CPUTIME_ID]
7734  * Use times() defined by POSIX.
7735  * The result is addition of user time (tms_utime) and system time (tms_stime).
7736  * tms_cutime and tms_cstime are ignored to exclude the time for child processes.
7737  * The resolution is the clock tick.
7738  * "getconf CLK_TCK" command shows the clock ticks per second.
7739  * (The clock ticks per second is defined by HZ macro in older systems.)
7740  * If it is 100, the resolution is 10 millisecond.
7741  * [:CLOCK_BASED_CLOCK_PROCESS_CPUTIME_ID]
7742  * Use clock() defined by ISO C.
7743  * The resolution is 1/CLOCKS_PER_SEC.
7744  * CLOCKS_PER_SEC is the C-level macro defined by time.h.
7745  * SUS defines CLOCKS_PER_SEC is 1000000.
7746  * Non-Unix systems may define it a different value, though.
7747  * If CLOCKS_PER_SEC is 1000000 as SUS, the resolution is 1 microsecond.
7748  * If CLOCKS_PER_SEC is 1000000 and clock_t is 32 bits integer type, it cannot represent over 72 minutes.
7749  *
7750  * If the given +clock_id+ is not supported, Errno::EINVAL is raised.
7751  *
7752  * +unit+ specifies a type of the return value.
7753  *
7754  * [:float_second] number of seconds as a float (default)
7755  * [:float_millisecond] number of milliseconds as a float
7756  * [:float_microsecond] number of microseconds as a float
7757  * [:second] number of seconds as an integer
7758  * [:millisecond] number of milliseconds as an integer
7759  * [:microsecond] number of microseconds as an integer
7760  * [:nanosecond] number of nanoseconds as an integer
7761  *
7762  * The underlying function, clock_gettime(), returns a number of nanoseconds.
7763  * Float object (IEEE 754 double) is not enough to represent
7764  * the return value for CLOCK_REALTIME.
7765  * If the exact nanoseconds value is required, use +:nanoseconds+ as the +unit+.
7766  *
7767  * The origin (zero) of the returned value varies.
7768  * For example, system start up time, process start up time, the Epoch, etc.
7769  *
7770  * The origin in CLOCK_REALTIME is defined as the Epoch
7771  * (1970-01-01 00:00:00 UTC).
7772  * But some systems count leap seconds and others doesn't.
7773  * So the result can be interpreted differently across systems.
7774  * Time.now is recommended over CLOCK_REALTIME.
7775  */
7776 static VALUE
7777 rb_clock_gettime(int argc, VALUE *argv, VALUE _)
7778 {
7779  int ret;
7780 
7781  struct timetick tt;
7782  timetick_int_t numerators[2];
7783  timetick_int_t denominators[2];
7784  int num_numerators = 0;
7785  int num_denominators = 0;
7786 
7787  VALUE unit = (rb_check_arity(argc, 1, 2) == 2) ? argv[1] : Qnil;
7788  VALUE clk_id = argv[0];
7789 
7790  if (SYMBOL_P(clk_id)) {
7791  /*
7792  * Non-clock_gettime clocks are provided by symbol clk_id.
7793  */
7794 #ifdef HAVE_GETTIMEOFDAY
7795  /*
7796  * GETTIMEOFDAY_BASED_CLOCK_REALTIME is used for
7797  * CLOCK_REALTIME if clock_gettime is not available.
7798  */
7799 #define RUBY_GETTIMEOFDAY_BASED_CLOCK_REALTIME ID2SYM(id_GETTIMEOFDAY_BASED_CLOCK_REALTIME)
7800  if (clk_id == RUBY_GETTIMEOFDAY_BASED_CLOCK_REALTIME) {
7801  struct timeval tv;
7802  ret = gettimeofday(&tv, 0);
7803  if (ret != 0)
7804  rb_sys_fail("gettimeofday");
7805  tt.giga_count = tv.tv_sec;
7806  tt.count = (int32_t)tv.tv_usec * 1000;
7807  denominators[num_denominators++] = 1000000000;
7808  goto success;
7809  }
7810 #endif
7811 
7812 #define RUBY_TIME_BASED_CLOCK_REALTIME ID2SYM(id_TIME_BASED_CLOCK_REALTIME)
7813  if (clk_id == RUBY_TIME_BASED_CLOCK_REALTIME) {
7814  time_t t;
7815  t = time(NULL);
7816  if (t == (time_t)-1)
7817  rb_sys_fail("time");
7818  tt.giga_count = t;
7819  tt.count = 0;
7820  denominators[num_denominators++] = 1000000000;
7821  goto success;
7822  }
7823 
7824 #ifdef HAVE_TIMES
7825 #define RUBY_TIMES_BASED_CLOCK_MONOTONIC \
7826  ID2SYM(id_TIMES_BASED_CLOCK_MONOTONIC)
7827  if (clk_id == RUBY_TIMES_BASED_CLOCK_MONOTONIC) {
7828  struct tms buf;
7829  clock_t c;
7830  unsigned_clock_t uc;
7831  c = times(&buf);
7832  if (c == (clock_t)-1)
7833  rb_sys_fail("times");
7834  uc = (unsigned_clock_t)c;
7835  tt.count = (int32_t)(uc % 1000000000);
7836  tt.giga_count = (uc / 1000000000);
7837  denominators[num_denominators++] = get_clk_tck();
7838  goto success;
7839  }
7840 #endif
7841 
7842 #ifdef RUSAGE_SELF
7843 #define RUBY_GETRUSAGE_BASED_CLOCK_PROCESS_CPUTIME_ID \
7844  ID2SYM(id_GETRUSAGE_BASED_CLOCK_PROCESS_CPUTIME_ID)
7845  if (clk_id == RUBY_GETRUSAGE_BASED_CLOCK_PROCESS_CPUTIME_ID) {
7846  struct rusage usage;
7847  int32_t usec;
7848  ret = getrusage(RUSAGE_SELF, &usage);
7849  if (ret != 0)
7850  rb_sys_fail("getrusage");
7851  tt.giga_count = usage.ru_utime.tv_sec + usage.ru_stime.tv_sec;
7852  usec = (int32_t)(usage.ru_utime.tv_usec + usage.ru_stime.tv_usec);
7853  if (1000000 <= usec) {
7854  tt.giga_count++;
7855  usec -= 1000000;
7856  }
7857  tt.count = usec * 1000;
7858  denominators[num_denominators++] = 1000000000;
7859  goto success;
7860  }
7861 #endif
7862 
7863 #ifdef HAVE_TIMES
7864 #define RUBY_TIMES_BASED_CLOCK_PROCESS_CPUTIME_ID \
7865  ID2SYM(id_TIMES_BASED_CLOCK_PROCESS_CPUTIME_ID)
7866  if (clk_id == RUBY_TIMES_BASED_CLOCK_PROCESS_CPUTIME_ID) {
7867  struct tms buf;
7868  unsigned_clock_t utime, stime;
7869  if (times(&buf) == (clock_t)-1)
7870  rb_sys_fail("times");
7871  utime = (unsigned_clock_t)buf.tms_utime;
7872  stime = (unsigned_clock_t)buf.tms_stime;
7873  tt.count = (int32_t)((utime % 1000000000) + (stime % 1000000000));
7874  tt.giga_count = (utime / 1000000000) + (stime / 1000000000);
7875  if (1000000000 <= tt.count) {
7876  tt.count -= 1000000000;
7877  tt.giga_count++;
7878  }
7879  denominators[num_denominators++] = get_clk_tck();
7880  goto success;
7881  }
7882 #endif
7883 
7884 #define RUBY_CLOCK_BASED_CLOCK_PROCESS_CPUTIME_ID \
7885  ID2SYM(id_CLOCK_BASED_CLOCK_PROCESS_CPUTIME_ID)
7887  clock_t c;
7888  unsigned_clock_t uc;
7889  errno = 0;
7890  c = clock();
7891  if (c == (clock_t)-1)
7892  rb_sys_fail("clock");
7893  uc = (unsigned_clock_t)c;
7894  tt.count = (int32_t)(uc % 1000000000);
7895  tt.giga_count = uc / 1000000000;
7896  denominators[num_denominators++] = CLOCKS_PER_SEC;
7897  goto success;
7898  }
7899 
7900 #ifdef __APPLE__
7901 #define RUBY_MACH_ABSOLUTE_TIME_BASED_CLOCK_MONOTONIC ID2SYM(id_MACH_ABSOLUTE_TIME_BASED_CLOCK_MONOTONIC)
7902  if (clk_id == RUBY_MACH_ABSOLUTE_TIME_BASED_CLOCK_MONOTONIC) {
7903  const mach_timebase_info_data_t *info = get_mach_timebase_info();
7904  uint64_t t = mach_absolute_time();
7905  tt.count = (int32_t)(t % 1000000000);
7906  tt.giga_count = t / 1000000000;
7907  numerators[num_numerators++] = info->numer;
7908  denominators[num_denominators++] = info->denom;
7909  denominators[num_denominators++] = 1000000000;
7910  goto success;
7911  }
7912 #endif
7913  }
7914  else {
7915 #if defined(HAVE_CLOCK_GETTIME)
7916  struct timespec ts;
7917  clockid_t c;
7918  c = NUM2CLOCKID(clk_id);
7919  ret = clock_gettime(c, &ts);
7920  if (ret == -1)
7921  rb_sys_fail("clock_gettime");
7922  tt.count = (int32_t)ts.tv_nsec;
7923  tt.giga_count = ts.tv_sec;
7924  denominators[num_denominators++] = 1000000000;
7925  goto success;
7926 #endif
7927  }
7928  /* EINVAL emulates clock_gettime behavior when clock_id is invalid. */
7929  rb_syserr_fail(EINVAL, 0);
7930 
7931  success:
7932  return make_clock_result(&tt, numerators, num_numerators, denominators, num_denominators, unit);
7933 }
7934 
7935 /*
7936  * call-seq:
7937  * Process.clock_getres(clock_id [, unit]) -> number
7938  *
7939  * Returns the time resolution returned by POSIX clock_getres() function.
7940  *
7941  * +clock_id+ specifies a kind of clock.
7942  * See the document of +Process.clock_gettime+ for details.
7943  *
7944  * +clock_id+ can be a symbol as +Process.clock_gettime+.
7945  * However the result may not be accurate.
7946  * For example, <code>Process.clock_getres(:GETTIMEOFDAY_BASED_CLOCK_REALTIME)</code>
7947  * returns 1.0e-06 which means 1 microsecond, but actual resolution can be more coarse.
7948  *
7949  * If the given +clock_id+ is not supported, Errno::EINVAL is raised.
7950  *
7951  * +unit+ specifies a type of the return value.
7952  * +Process.clock_getres+ accepts +unit+ as +Process.clock_gettime+.
7953  * The default value, +:float_second+, is also same as
7954  * +Process.clock_gettime+.
7955  *
7956  * +Process.clock_getres+ also accepts +:hertz+ as +unit+.
7957  * +:hertz+ means a the reciprocal of +:float_second+.
7958  *
7959  * +:hertz+ can be used to obtain the exact value of
7960  * the clock ticks per second for times() function and
7961  * CLOCKS_PER_SEC for clock() function.
7962  *
7963  * <code>Process.clock_getres(:TIMES_BASED_CLOCK_PROCESS_CPUTIME_ID, :hertz)</code>
7964  * returns the clock ticks per second.
7965  *
7966  * <code>Process.clock_getres(:CLOCK_BASED_CLOCK_PROCESS_CPUTIME_ID, :hertz)</code>
7967  * returns CLOCKS_PER_SEC.
7968  *
7969  * p Process.clock_getres(Process::CLOCK_MONOTONIC)
7970  * #=> 1.0e-09
7971  *
7972  */
7973 static VALUE
7974 rb_clock_getres(int argc, VALUE *argv, VALUE _)
7975 {
7976  struct timetick tt;
7977  timetick_int_t numerators[2];
7978  timetick_int_t denominators[2];
7979  int num_numerators = 0;
7980  int num_denominators = 0;
7981 
7982  VALUE unit = (rb_check_arity(argc, 1, 2) == 2) ? argv[1] : Qnil;
7983  VALUE clk_id = argv[0];
7984 
7985  if (SYMBOL_P(clk_id)) {
7986 #ifdef RUBY_GETTIMEOFDAY_BASED_CLOCK_REALTIME
7987  if (clk_id == RUBY_GETTIMEOFDAY_BASED_CLOCK_REALTIME) {
7988  tt.giga_count = 0;
7989  tt.count = 1000;
7990  denominators[num_denominators++] = 1000000000;
7991  goto success;
7992  }
7993 #endif
7994 
7995 #ifdef RUBY_TIME_BASED_CLOCK_REALTIME
7996  if (clk_id == RUBY_TIME_BASED_CLOCK_REALTIME) {
7997  tt.giga_count = 1;
7998  tt.count = 0;
7999  denominators[num_denominators++] = 1000000000;
8000  goto success;
8001  }
8002 #endif
8003 
8004 #ifdef RUBY_TIMES_BASED_CLOCK_MONOTONIC
8005  if (clk_id == RUBY_TIMES_BASED_CLOCK_MONOTONIC) {
8006  tt.count = 1;
8007  tt.giga_count = 0;
8008  denominators[num_denominators++] = get_clk_tck();
8009  goto success;
8010  }
8011 #endif
8012 
8013 #ifdef RUBY_GETRUSAGE_BASED_CLOCK_PROCESS_CPUTIME_ID
8014  if (clk_id == RUBY_GETRUSAGE_BASED_CLOCK_PROCESS_CPUTIME_ID) {
8015  tt.giga_count = 0;
8016  tt.count = 1000;
8017  denominators[num_denominators++] = 1000000000;
8018  goto success;
8019  }
8020 #endif
8021 
8022 #ifdef RUBY_TIMES_BASED_CLOCK_PROCESS_CPUTIME_ID
8023  if (clk_id == RUBY_TIMES_BASED_CLOCK_PROCESS_CPUTIME_ID) {
8024  tt.count = 1;
8025  tt.giga_count = 0;
8026  denominators[num_denominators++] = get_clk_tck();
8027  goto success;
8028  }
8029 #endif
8030 
8031 #ifdef RUBY_CLOCK_BASED_CLOCK_PROCESS_CPUTIME_ID
8033  tt.count = 1;
8034  tt.giga_count = 0;
8035  denominators[num_denominators++] = CLOCKS_PER_SEC;
8036  goto success;
8037  }
8038 #endif
8039 
8040 #ifdef RUBY_MACH_ABSOLUTE_TIME_BASED_CLOCK_MONOTONIC
8041  if (clk_id == RUBY_MACH_ABSOLUTE_TIME_BASED_CLOCK_MONOTONIC) {
8042  const mach_timebase_info_data_t *info = get_mach_timebase_info();
8043  tt.count = 1;
8044  tt.giga_count = 0;
8045  numerators[num_numerators++] = info->numer;
8046  denominators[num_denominators++] = info->denom;
8047  denominators[num_denominators++] = 1000000000;
8048  goto success;
8049  }
8050 #endif
8051  }
8052  else {
8053 #if defined(HAVE_CLOCK_GETRES)
8054  struct timespec ts;
8055  clockid_t c = NUM2CLOCKID(clk_id);
8056  int ret = clock_getres(c, &ts);
8057  if (ret == -1)
8058  rb_sys_fail("clock_getres");
8059  tt.count = (int32_t)ts.tv_nsec;
8060  tt.giga_count = ts.tv_sec;
8061  denominators[num_denominators++] = 1000000000;
8062  goto success;
8063 #endif
8064  }
8065  /* EINVAL emulates clock_getres behavior when clock_id is invalid. */
8066  rb_syserr_fail(EINVAL, 0);
8067 
8068  success:
8069  if (unit == ID2SYM(id_hertz)) {
8070  return timetick2dblnum_reciprocal(&tt, numerators, num_numerators, denominators, num_denominators);
8071  }
8072  else {
8073  return make_clock_result(&tt, numerators, num_numerators, denominators, num_denominators, unit);
8074  }
8075 }
8076 
8077 static VALUE
8078 get_CHILD_STATUS(ID _x, VALUE *_y)
8079 {
8080  return rb_last_status_get();
8081 }
8082 
8083 static VALUE
8084 get_PROCESS_ID(ID _x, VALUE *_y)
8085 {
8086  return get_pid();
8087 }
8088 
8089 /*
8090  * call-seq:
8091  * Process.kill(signal, pid, ...) -> integer
8092  *
8093  * Sends the given signal to the specified process id(s) if _pid_ is positive.
8094  * If _pid_ is zero, _signal_ is sent to all processes whose group ID is equal
8095  * to the group ID of the process. If _pid_ is negative, results are dependent
8096  * on the operating system. _signal_ may be an integer signal number or
8097  * a POSIX signal name (either with or without a +SIG+ prefix). If _signal_ is
8098  * negative (or starts with a minus sign), kills process groups instead of
8099  * processes. Not all signals are available on all platforms.
8100  * The keys and values of Signal.list are known signal names and numbers,
8101  * respectively.
8102  *
8103  * pid = fork do
8104  * Signal.trap("HUP") { puts "Ouch!"; exit }
8105  * # ... do some work ...
8106  * end
8107  * # ...
8108  * Process.kill("HUP", pid)
8109  * Process.wait
8110  *
8111  * <em>produces:</em>
8112  *
8113  * Ouch!
8114  *
8115  * If _signal_ is an integer but wrong for signal, Errno::EINVAL or
8116  * RangeError will be raised. Otherwise unless _signal_ is a String
8117  * or a Symbol, and a known signal name, ArgumentError will be
8118  * raised.
8119  *
8120  * Also, Errno::ESRCH or RangeError for invalid _pid_, Errno::EPERM
8121  * when failed because of no privilege, will be raised. In these
8122  * cases, signals may have been sent to preceding processes.
8123  */
8124 
8125 static VALUE
8126 proc_rb_f_kill(int c, const VALUE *v, VALUE _)
8127 {
8128  return rb_f_kill(c, v);
8129 }
8130 
8132 static VALUE rb_mProcUID;
8133 static VALUE rb_mProcGID;
8134 static VALUE rb_mProcID_Syscall;
8135 
8136 
8137 /*
8138  * The Process module is a collection of methods used to
8139  * manipulate processes.
8140  */
8141 
8142 void
8144 {
8145 #undef rb_intern
8146 #define rb_intern(str) rb_intern_const(str)
8147  rb_define_virtual_variable("$?", get_CHILD_STATUS, 0);
8148  rb_define_virtual_variable("$$", get_PROCESS_ID, 0);
8149  rb_define_global_function("exec", f_exec, -1);
8151  rb_define_global_function("exit!", rb_f_exit_bang, -1);
8152  rb_define_global_function("system", rb_f_system, -1);
8153  rb_define_global_function("spawn", rb_f_spawn, -1);
8154  rb_define_global_function("sleep", rb_f_sleep, -1);
8155  rb_define_global_function("exit", f_exit, -1);
8156  rb_define_global_function("abort", f_abort, -1);
8157 
8158  rb_mProcess = rb_define_module("Process");
8159 
8160 #ifdef WNOHANG
8161  /* see Process.wait */
8163 #else
8164  /* see Process.wait */
8165  rb_define_const(rb_mProcess, "WNOHANG", INT2FIX(0));
8166 #endif
8167 #ifdef WUNTRACED
8168  /* see Process.wait */
8169  rb_define_const(rb_mProcess, "WUNTRACED", INT2FIX(WUNTRACED));
8170 #else
8171  /* see Process.wait */
8172  rb_define_const(rb_mProcess, "WUNTRACED", INT2FIX(0));
8173 #endif
8174 
8175  rb_define_singleton_method(rb_mProcess, "exec", f_exec, -1);
8177  rb_define_singleton_method(rb_mProcess, "spawn", rb_f_spawn, -1);
8178  rb_define_singleton_method(rb_mProcess, "exit!", rb_f_exit_bang, -1);
8179  rb_define_singleton_method(rb_mProcess, "exit", f_exit, -1);
8180  rb_define_singleton_method(rb_mProcess, "abort", f_abort, -1);
8181  rb_define_singleton_method(rb_mProcess, "last_status", proc_s_last_status, 0);
8182 
8183  rb_define_module_function(rb_mProcess, "kill", proc_rb_f_kill, -1);
8184  rb_define_module_function(rb_mProcess, "wait", proc_m_wait, -1);
8185  rb_define_module_function(rb_mProcess, "wait2", proc_wait2, -1);
8186  rb_define_module_function(rb_mProcess, "waitpid", proc_m_wait, -1);
8187  rb_define_module_function(rb_mProcess, "waitpid2", proc_wait2, -1);
8188  rb_define_module_function(rb_mProcess, "waitall", proc_waitall, 0);
8189  rb_define_module_function(rb_mProcess, "detach", proc_detach, 1);
8190 
8191  /* :nodoc: */
8192  rb_cWaiter = rb_define_class_under(rb_mProcess, "Waiter", rb_cThread);
8193  rb_undef_alloc_func(rb_cWaiter);
8194  rb_undef_method(CLASS_OF(rb_cWaiter), "new");
8195  rb_define_method(rb_cWaiter, "pid", detach_process_pid, 0);
8196 
8197  rb_cProcessStatus = rb_define_class_under(rb_mProcess, "Status", rb_cObject);
8198  rb_undef_method(CLASS_OF(rb_cProcessStatus), "new");
8199 
8200  rb_define_method(rb_cProcessStatus, "==", pst_equal, 1);
8201  rb_define_method(rb_cProcessStatus, "&", pst_bitand, 1);
8202  rb_define_method(rb_cProcessStatus, ">>", pst_rshift, 1);
8203  rb_define_method(rb_cProcessStatus, "to_i", pst_to_i, 0);
8204  rb_define_method(rb_cProcessStatus, "to_s", pst_to_s, 0);
8205  rb_define_method(rb_cProcessStatus, "inspect", pst_inspect, 0);
8206 
8207  rb_define_method(rb_cProcessStatus, "pid", pst_pid, 0);
8208 
8209  rb_define_method(rb_cProcessStatus, "stopped?", pst_wifstopped, 0);
8210  rb_define_method(rb_cProcessStatus, "stopsig", pst_wstopsig, 0);
8211  rb_define_method(rb_cProcessStatus, "signaled?", pst_wifsignaled, 0);
8212  rb_define_method(rb_cProcessStatus, "termsig", pst_wtermsig, 0);
8213  rb_define_method(rb_cProcessStatus, "exited?", pst_wifexited, 0);
8214  rb_define_method(rb_cProcessStatus, "exitstatus", pst_wexitstatus, 0);
8215  rb_define_method(rb_cProcessStatus, "success?", pst_success_p, 0);
8216  rb_define_method(rb_cProcessStatus, "coredump?", pst_wcoredump, 0);
8217 
8218  rb_define_module_function(rb_mProcess, "pid", proc_get_pid, 0);
8219  rb_define_module_function(rb_mProcess, "ppid", proc_get_ppid, 0);
8220 
8225 
8228 
8231 
8232 #ifdef HAVE_GETPRIORITY
8233  /* see Process.setpriority */
8234  rb_define_const(rb_mProcess, "PRIO_PROCESS", INT2FIX(PRIO_PROCESS));
8235  /* see Process.setpriority */
8236  rb_define_const(rb_mProcess, "PRIO_PGRP", INT2FIX(PRIO_PGRP));
8237  /* see Process.setpriority */
8238  rb_define_const(rb_mProcess, "PRIO_USER", INT2FIX(PRIO_USER));
8239 #endif
8240 
8243 #if defined(RLIM2NUM) && defined(RLIM_INFINITY)
8244  {
8245  VALUE inf = RLIM2NUM(RLIM_INFINITY);
8246 #ifdef RLIM_SAVED_MAX
8247  {
8248  VALUE v = RLIM_INFINITY == RLIM_SAVED_MAX ? inf : RLIM2NUM(RLIM_SAVED_MAX);
8249  /* see Process.setrlimit */
8250  rb_define_const(rb_mProcess, "RLIM_SAVED_MAX", v);
8251  }
8252 #endif
8253  /* see Process.setrlimit */
8254  rb_define_const(rb_mProcess, "RLIM_INFINITY", inf);
8255 #ifdef RLIM_SAVED_CUR
8256  {
8257  VALUE v = RLIM_INFINITY == RLIM_SAVED_CUR ? inf : RLIM2NUM(RLIM_SAVED_CUR);
8258  /* see Process.setrlimit */
8259  rb_define_const(rb_mProcess, "RLIM_SAVED_CUR", v);
8260  }
8261 #endif
8262  }
8263 #ifdef RLIMIT_AS
8264  /* Maximum size of the process's virtual memory (address space) in bytes.
8265  *
8266  * see the system getrlimit(2) manual for details.
8267  */
8268  rb_define_const(rb_mProcess, "RLIMIT_AS", INT2FIX(RLIMIT_AS));
8269 #endif
8270 #ifdef RLIMIT_CORE
8271  /* Maximum size of the core file.
8272  *
8273  * see the system getrlimit(2) manual for details.
8274  */
8275  rb_define_const(rb_mProcess, "RLIMIT_CORE", INT2FIX(RLIMIT_CORE));
8276 #endif
8277 #ifdef RLIMIT_CPU
8278  /* CPU time limit in seconds.
8279  *
8280  * see the system getrlimit(2) manual for details.
8281  */
8282  rb_define_const(rb_mProcess, "RLIMIT_CPU", INT2FIX(RLIMIT_CPU));
8283 #endif
8284 #ifdef RLIMIT_DATA
8285  /* Maximum size of the process's data segment.
8286  *
8287  * see the system getrlimit(2) manual for details.
8288  */
8289  rb_define_const(rb_mProcess, "RLIMIT_DATA", INT2FIX(RLIMIT_DATA));
8290 #endif
8291 #ifdef RLIMIT_FSIZE
8292  /* Maximum size of files that the process may create.
8293  *
8294  * see the system getrlimit(2) manual for details.
8295  */
8296  rb_define_const(rb_mProcess, "RLIMIT_FSIZE", INT2FIX(RLIMIT_FSIZE));
8297 #endif
8298 #ifdef RLIMIT_MEMLOCK
8299  /* Maximum number of bytes of memory that may be locked into RAM.
8300  *
8301  * see the system getrlimit(2) manual for details.
8302  */
8303  rb_define_const(rb_mProcess, "RLIMIT_MEMLOCK", INT2FIX(RLIMIT_MEMLOCK));
8304 #endif
8305 #ifdef RLIMIT_MSGQUEUE
8306  /* Specifies the limit on the number of bytes that can be allocated
8307  * for POSIX message queues for the real user ID of the calling process.
8308  *
8309  * see the system getrlimit(2) manual for details.
8310  */
8311  rb_define_const(rb_mProcess, "RLIMIT_MSGQUEUE", INT2FIX(RLIMIT_MSGQUEUE));
8312 #endif
8313 #ifdef RLIMIT_NICE
8314  /* Specifies a ceiling to which the process's nice value can be raised.
8315  *
8316  * see the system getrlimit(2) manual for details.
8317  */
8318  rb_define_const(rb_mProcess, "RLIMIT_NICE", INT2FIX(RLIMIT_NICE));
8319 #endif
8320 #ifdef RLIMIT_NOFILE
8321  /* Specifies a value one greater than the maximum file descriptor
8322  * number that can be opened by this process.
8323  *
8324  * see the system getrlimit(2) manual for details.
8325  */
8326  rb_define_const(rb_mProcess, "RLIMIT_NOFILE", INT2FIX(RLIMIT_NOFILE));
8327 #endif
8328 #ifdef RLIMIT_NPROC
8329  /* The maximum number of processes that can be created for the
8330  * real user ID of the calling process.
8331  *
8332  * see the system getrlimit(2) manual for details.
8333  */
8334  rb_define_const(rb_mProcess, "RLIMIT_NPROC", INT2FIX(RLIMIT_NPROC));
8335 #endif
8336 #ifdef RLIMIT_RSS
8337  /* Specifies the limit (in pages) of the process's resident set.
8338  *
8339  * see the system getrlimit(2) manual for details.
8340  */
8341  rb_define_const(rb_mProcess, "RLIMIT_RSS", INT2FIX(RLIMIT_RSS));
8342 #endif
8343 #ifdef RLIMIT_RTPRIO
8344  /* Specifies a ceiling on the real-time priority that may be set for this process.
8345  *
8346  * see the system getrlimit(2) manual for details.
8347  */
8348  rb_define_const(rb_mProcess, "RLIMIT_RTPRIO", INT2FIX(RLIMIT_RTPRIO));
8349 #endif
8350 #ifdef RLIMIT_RTTIME
8351  /* Specifies limit on CPU time this process scheduled under a real-time
8352  * scheduling policy can consume.
8353  *
8354  * see the system getrlimit(2) manual for details.
8355  */
8356  rb_define_const(rb_mProcess, "RLIMIT_RTTIME", INT2FIX(RLIMIT_RTTIME));
8357 #endif
8358 #ifdef RLIMIT_SBSIZE
8359  /* Maximum size of the socket buffer.
8360  */
8361  rb_define_const(rb_mProcess, "RLIMIT_SBSIZE", INT2FIX(RLIMIT_SBSIZE));
8362 #endif
8363 #ifdef RLIMIT_SIGPENDING
8364  /* Specifies a limit on the number of signals that may be queued for
8365  * the real user ID of the calling process.
8366  *
8367  * see the system getrlimit(2) manual for details.
8368  */
8369  rb_define_const(rb_mProcess, "RLIMIT_SIGPENDING", INT2FIX(RLIMIT_SIGPENDING));
8370 #endif
8371 #ifdef RLIMIT_STACK
8372  /* Maximum size of the stack, in bytes.
8373  *
8374  * see the system getrlimit(2) manual for details.
8375  */
8376  rb_define_const(rb_mProcess, "RLIMIT_STACK", INT2FIX(RLIMIT_STACK));
8377 #endif
8378 #endif
8379 
8380  rb_define_module_function(rb_mProcess, "uid", proc_getuid, 0);
8382  rb_define_module_function(rb_mProcess, "gid", proc_getgid, 0);
8384  rb_define_module_function(rb_mProcess, "euid", proc_geteuid, 0);
8386  rb_define_module_function(rb_mProcess, "egid", proc_getegid, 0);
8393 
8395 
8397 
8398 #ifdef CLOCK_REALTIME
8399  /* see Process.clock_gettime */
8401 #elif defined(RUBY_GETTIMEOFDAY_BASED_CLOCK_REALTIME)
8402  /* see Process.clock_gettime */
8403  rb_define_const(rb_mProcess, "CLOCK_REALTIME", RUBY_GETTIMEOFDAY_BASED_CLOCK_REALTIME);
8404 #endif
8405 #ifdef CLOCK_MONOTONIC
8406  /* see Process.clock_gettime */
8408 #elif defined(RUBY_MACH_ABSOLUTE_TIME_BASED_CLOCK_MONOTONIC)
8409  /* see Process.clock_gettime */
8410  rb_define_const(rb_mProcess, "CLOCK_MONOTONIC", RUBY_MACH_ABSOLUTE_TIME_BASED_CLOCK_MONOTONIC);
8411 #endif
8412 #ifdef CLOCK_PROCESS_CPUTIME_ID
8413  /* see Process.clock_gettime */
8414  rb_define_const(rb_mProcess, "CLOCK_PROCESS_CPUTIME_ID", CLOCKID2NUM(CLOCK_PROCESS_CPUTIME_ID));
8415 #elif defined(RUBY_GETRUSAGE_BASED_CLOCK_PROCESS_CPUTIME_ID)
8416  /* see Process.clock_gettime */
8417  rb_define_const(rb_mProcess, "CLOCK_PROCESS_CPUTIME_ID", RUBY_GETRUSAGE_BASED_CLOCK_PROCESS_CPUTIME_ID);
8418 #endif
8419 #ifdef CLOCK_THREAD_CPUTIME_ID
8420  /* see Process.clock_gettime */
8421  rb_define_const(rb_mProcess, "CLOCK_THREAD_CPUTIME_ID", CLOCKID2NUM(CLOCK_THREAD_CPUTIME_ID));
8422 #endif
8423 #ifdef CLOCK_VIRTUAL
8424  /* see Process.clock_gettime */
8425  rb_define_const(rb_mProcess, "CLOCK_VIRTUAL", CLOCKID2NUM(CLOCK_VIRTUAL));
8426 #endif
8427 #ifdef CLOCK_PROF
8428  /* see Process.clock_gettime */
8429  rb_define_const(rb_mProcess, "CLOCK_PROF", CLOCKID2NUM(CLOCK_PROF));
8430 #endif
8431 #ifdef CLOCK_REALTIME_FAST
8432  /* see Process.clock_gettime */
8433  rb_define_const(rb_mProcess, "CLOCK_REALTIME_FAST", CLOCKID2NUM(CLOCK_REALTIME_FAST));
8434 #endif
8435 #ifdef CLOCK_REALTIME_PRECISE
8436  /* see Process.clock_gettime */
8437  rb_define_const(rb_mProcess, "CLOCK_REALTIME_PRECISE", CLOCKID2NUM(CLOCK_REALTIME_PRECISE));
8438 #endif
8439 #ifdef CLOCK_REALTIME_COARSE
8440  /* see Process.clock_gettime */
8441  rb_define_const(rb_mProcess, "CLOCK_REALTIME_COARSE", CLOCKID2NUM(CLOCK_REALTIME_COARSE));
8442 #endif
8443 #ifdef CLOCK_REALTIME_ALARM
8444  /* see Process.clock_gettime */
8445  rb_define_const(rb_mProcess, "CLOCK_REALTIME_ALARM", CLOCKID2NUM(CLOCK_REALTIME_ALARM));
8446 #endif
8447 #ifdef CLOCK_MONOTONIC_FAST
8448  /* see Process.clock_gettime */
8449  rb_define_const(rb_mProcess, "CLOCK_MONOTONIC_FAST", CLOCKID2NUM(CLOCK_MONOTONIC_FAST));
8450 #endif
8451 #ifdef CLOCK_MONOTONIC_PRECISE
8452  /* see Process.clock_gettime */
8453  rb_define_const(rb_mProcess, "CLOCK_MONOTONIC_PRECISE", CLOCKID2NUM(CLOCK_MONOTONIC_PRECISE));
8454 #endif
8455 #ifdef CLOCK_MONOTONIC_RAW
8456  /* see Process.clock_gettime */
8457  rb_define_const(rb_mProcess, "CLOCK_MONOTONIC_RAW", CLOCKID2NUM(CLOCK_MONOTONIC_RAW));
8458 #endif
8459 #ifdef CLOCK_MONOTONIC_RAW_APPROX
8460  /* see Process.clock_gettime */
8461  rb_define_const(rb_mProcess, "CLOCK_MONOTONIC_RAW_APPROX", CLOCKID2NUM(CLOCK_MONOTONIC_RAW_APPROX));
8462 #endif
8463 #ifdef CLOCK_MONOTONIC_COARSE
8464  /* see Process.clock_gettime */
8465  rb_define_const(rb_mProcess, "CLOCK_MONOTONIC_COARSE", CLOCKID2NUM(CLOCK_MONOTONIC_COARSE));
8466 #endif
8467 #ifdef CLOCK_BOOTTIME
8468  /* see Process.clock_gettime */
8470 #endif
8471 #ifdef CLOCK_BOOTTIME_ALARM
8472  /* see Process.clock_gettime */
8473  rb_define_const(rb_mProcess, "CLOCK_BOOTTIME_ALARM", CLOCKID2NUM(CLOCK_BOOTTIME_ALARM));
8474 #endif
8475 #ifdef CLOCK_UPTIME
8476  /* see Process.clock_gettime */
8477  rb_define_const(rb_mProcess, "CLOCK_UPTIME", CLOCKID2NUM(CLOCK_UPTIME));
8478 #endif
8479 #ifdef CLOCK_UPTIME_FAST
8480  /* see Process.clock_gettime */
8481  rb_define_const(rb_mProcess, "CLOCK_UPTIME_FAST", CLOCKID2NUM(CLOCK_UPTIME_FAST));
8482 #endif
8483 #ifdef CLOCK_UPTIME_PRECISE
8484  /* see Process.clock_gettime */
8485  rb_define_const(rb_mProcess, "CLOCK_UPTIME_PRECISE", CLOCKID2NUM(CLOCK_UPTIME_PRECISE));
8486 #endif
8487 #ifdef CLOCK_UPTIME_RAW
8488  /* see Process.clock_gettime */
8489  rb_define_const(rb_mProcess, "CLOCK_UPTIME_RAW", CLOCKID2NUM(CLOCK_UPTIME_RAW));
8490 #endif
8491 #ifdef CLOCK_UPTIME_RAW_APPROX
8492  /* see Process.clock_gettime */
8493  rb_define_const(rb_mProcess, "CLOCK_UPTIME_RAW_APPROX", CLOCKID2NUM(CLOCK_UPTIME_RAW_APPROX));
8494 #endif
8495 #ifdef CLOCK_SECOND
8496  /* see Process.clock_gettime */
8497  rb_define_const(rb_mProcess, "CLOCK_SECOND", CLOCKID2NUM(CLOCK_SECOND));
8498 #endif
8499 #ifdef CLOCK_TAI
8500  /* see Process.clock_gettime */
8501  rb_define_const(rb_mProcess, "CLOCK_TAI", CLOCKID2NUM(CLOCK_TAI));
8502 #endif
8503  rb_define_module_function(rb_mProcess, "clock_gettime", rb_clock_gettime, -1);
8504  rb_define_module_function(rb_mProcess, "clock_getres", rb_clock_getres, -1);
8505 
8506 #if defined(HAVE_TIMES) || defined(_WIN32)
8507  /* Placeholder for rusage */
8508  rb_cProcessTms = rb_struct_define_under(rb_mProcess, "Tms", "utime", "stime", "cutime", "cstime", NULL);
8509  /* An obsolete name of Process::Tms for backward compatibility */
8510  rb_define_const(rb_cStruct, "Tms", rb_cProcessTms);
8512 #endif
8513 
8514  SAVED_USER_ID = geteuid();
8515  SAVED_GROUP_ID = getegid();
8516 
8517  rb_mProcUID = rb_define_module_under(rb_mProcess, "UID");
8518  rb_mProcGID = rb_define_module_under(rb_mProcess, "GID");
8519 
8520  rb_define_module_function(rb_mProcUID, "rid", proc_getuid, 0);
8521  rb_define_module_function(rb_mProcGID, "rid", proc_getgid, 0);
8522  rb_define_module_function(rb_mProcUID, "eid", proc_geteuid, 0);
8523  rb_define_module_function(rb_mProcGID, "eid", proc_getegid, 0);
8524  rb_define_module_function(rb_mProcUID, "change_privilege", p_uid_change_privilege, 1);
8525  rb_define_module_function(rb_mProcGID, "change_privilege", p_gid_change_privilege, 1);
8526  rb_define_module_function(rb_mProcUID, "grant_privilege", p_uid_grant_privilege, 1);
8527  rb_define_module_function(rb_mProcGID, "grant_privilege", p_gid_grant_privilege, 1);
8528  rb_define_alias(rb_singleton_class(rb_mProcUID), "eid=", "grant_privilege");
8529  rb_define_alias(rb_singleton_class(rb_mProcGID), "eid=", "grant_privilege");
8530  rb_define_module_function(rb_mProcUID, "re_exchange", p_uid_exchange, 0);
8531  rb_define_module_function(rb_mProcGID, "re_exchange", p_gid_exchange, 0);
8532  rb_define_module_function(rb_mProcUID, "re_exchangeable?", p_uid_exchangeable, 0);
8533  rb_define_module_function(rb_mProcGID, "re_exchangeable?", p_gid_exchangeable, 0);
8534  rb_define_module_function(rb_mProcUID, "sid_available?", p_uid_have_saved_id, 0);
8535  rb_define_module_function(rb_mProcGID, "sid_available?", p_gid_have_saved_id, 0);
8536  rb_define_module_function(rb_mProcUID, "switch", p_uid_switch, 0);
8537  rb_define_module_function(rb_mProcGID, "switch", p_gid_switch, 0);
8538 #ifdef p_uid_from_name
8539  rb_define_module_function(rb_mProcUID, "from_name", p_uid_from_name, 1);
8540 #endif
8541 #ifdef p_gid_from_name
8542  rb_define_module_function(rb_mProcGID, "from_name", p_gid_from_name, 1);
8543 #endif
8544 
8545  rb_mProcID_Syscall = rb_define_module_under(rb_mProcess, "Sys");
8546 
8547  rb_define_module_function(rb_mProcID_Syscall, "getuid", proc_getuid, 0);
8548  rb_define_module_function(rb_mProcID_Syscall, "geteuid", proc_geteuid, 0);
8549  rb_define_module_function(rb_mProcID_Syscall, "getgid", proc_getgid, 0);
8550  rb_define_module_function(rb_mProcID_Syscall, "getegid", proc_getegid, 0);
8551 
8552  rb_define_module_function(rb_mProcID_Syscall, "setuid", p_sys_setuid, 1);
8553  rb_define_module_function(rb_mProcID_Syscall, "setgid", p_sys_setgid, 1);
8554 
8555  rb_define_module_function(rb_mProcID_Syscall, "setruid", p_sys_setruid, 1);
8556  rb_define_module_function(rb_mProcID_Syscall, "setrgid", p_sys_setrgid, 1);
8557 
8558  rb_define_module_function(rb_mProcID_Syscall, "seteuid", p_sys_seteuid, 1);
8559  rb_define_module_function(rb_mProcID_Syscall, "setegid", p_sys_setegid, 1);
8560 
8561  rb_define_module_function(rb_mProcID_Syscall, "setreuid", p_sys_setreuid, 2);
8562  rb_define_module_function(rb_mProcID_Syscall, "setregid", p_sys_setregid, 2);
8563 
8564  rb_define_module_function(rb_mProcID_Syscall, "setresuid", p_sys_setresuid, 3);
8565  rb_define_module_function(rb_mProcID_Syscall, "setresgid", p_sys_setresgid, 3);
8566  rb_define_module_function(rb_mProcID_Syscall, "issetugid", p_sys_issetugid, 0);
8567 }
8568 
8569 void
8571 {
8572  id_in = rb_intern("in");
8573  id_out = rb_intern("out");
8574  id_err = rb_intern("err");
8575  id_pid = rb_intern("pid");
8576  id_uid = rb_intern("uid");
8577  id_gid = rb_intern("gid");
8578  id_close = rb_intern("close");
8579  id_child = rb_intern("child");
8580 #ifdef HAVE_SETPGID
8581  id_pgroup = rb_intern("pgroup");
8582 #endif
8583 #ifdef _WIN32
8584  id_new_pgroup = rb_intern("new_pgroup");
8585 #endif
8586  id_unsetenv_others = rb_intern("unsetenv_others");
8587  id_chdir = rb_intern("chdir");
8588  id_umask = rb_intern("umask");
8589  id_close_others = rb_intern("close_others");
8590  id_ENV = rb_intern("ENV");
8591  id_nanosecond = rb_intern("nanosecond");
8592  id_microsecond = rb_intern("microsecond");
8593  id_millisecond = rb_intern("millisecond");
8594  id_second = rb_intern("second");
8595  id_float_microsecond = rb_intern("float_microsecond");
8596  id_float_millisecond = rb_intern("float_millisecond");
8597  id_float_second = rb_intern("float_second");
8598  id_GETTIMEOFDAY_BASED_CLOCK_REALTIME = rb_intern("GETTIMEOFDAY_BASED_CLOCK_REALTIME");
8599  id_TIME_BASED_CLOCK_REALTIME = rb_intern("TIME_BASED_CLOCK_REALTIME");
8600 #ifdef HAVE_TIMES
8601  id_TIMES_BASED_CLOCK_MONOTONIC = rb_intern("TIMES_BASED_CLOCK_MONOTONIC");
8602  id_TIMES_BASED_CLOCK_PROCESS_CPUTIME_ID = rb_intern("TIMES_BASED_CLOCK_PROCESS_CPUTIME_ID");
8603 #endif
8604 #ifdef RUSAGE_SELF
8605  id_GETRUSAGE_BASED_CLOCK_PROCESS_CPUTIME_ID = rb_intern("GETRUSAGE_BASED_CLOCK_PROCESS_CPUTIME_ID");
8606 #endif
8607  id_CLOCK_BASED_CLOCK_PROCESS_CPUTIME_ID = rb_intern("CLOCK_BASED_CLOCK_PROCESS_CPUTIME_ID");
8608 #ifdef __APPLE__
8609  id_MACH_ABSOLUTE_TIME_BASED_CLOCK_MONOTONIC = rb_intern("MACH_ABSOLUTE_TIME_BASED_CLOCK_MONOTONIC");
8610 #endif
8611  id_hertz = rb_intern("hertz");
8612 
8613  InitVM(process);
8614 }
strcmp
int strcmp(const char *, const char *)
spawn_args
Definition: process.c:4394
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
setpgrp
int setpgrp(void)
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:288
CLOCK_BOOTTIME_ALARM
#define CLOCK_BOOTTIME_ALARM
Definition: rb_mjit_min_header-2.7.1.h:2379
CLOCK_REALTIME_COARSE
#define CLOCK_REALTIME_COARSE
Definition: rb_mjit_min_header-2.7.1.h:2370
i
uint32_t i
Definition: rb_mjit_min_header-2.7.1.h:5464
system
int system(const char *__string)
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
stime
int stime(const time_t *)
rb_to_hash_type
VALUE rb_to_hash_type(VALUE hash)
Definition: hash.c:1840
rb_str_cat_cstr
#define rb_str_cat_cstr(str, ptr)
Definition: rb_mjit_min_header-2.7.1.h:6126
PST2INT
#define PST2INT(st)
Definition: process.c:577
list_for_each
#define list_for_each(h, i, member)
Definition: rb_mjit_min_header-2.7.1.h:9099
obj
const VALUE VALUE obj
Definition: rb_mjit_min_header-2.7.1.h:5742
p_sys_setresuid
#define p_sys_setresuid
Definition: process.c:5799
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
rb_struct_define_under
VALUE rb_struct_define_under(VALUE, const char *,...)
Definition: struct.c:449
proc_getpriority
#define proc_getpriority
Definition: process.c:5126
run_exec_dup2_fd_pair::older_index
long older_index
Definition: process.c:3049
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:5001
run_exec_dup2_fd_pair::num_newer
long num_newer
Definition: process.c:3050
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
p_sys_setrgid
#define p_sys_setrgid
Definition: process.c:6098
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:2064
proc_setgroups
#define proc_setgroups
Definition: process.c:6412
CLOCK_MONOTONIC_RAW
#define CLOCK_MONOTONIC_RAW
Definition: rb_mjit_min_header-2.7.1.h:2375
timetick
Definition: process.c:7499
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:2067
p_sys_seteuid
#define p_sys_seteuid
Definition: process.c:5740
double
double
Definition: rb_mjit_min_header-2.7.1.h:5923
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:4315
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
st_data_t
unsigned long st_data_t
Definition: rb_mjit_min_header-2.7.1.h:5363
id
const int id
Definition: nkf.c:209
rb_execarg::env_modification
VALUE env_modification
Definition: internal.h:2065
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
list_del_init
#define list_del_init(n)
Definition: rb_mjit_min_header-2.7.1.h:9053
rb_hash_new
VALUE rb_hash_new(void)
Definition: hash.c:1523
getsid
pid_t getsid(pid_t)
seteuid
int seteuid(uid_t __uid)
p_sys_issetugid
#define p_sys_issetugid
Definition: process.c:6202
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
rb_block_given_p
int rb_block_given_p(void)
Determines if the current method is given a block.
Definition: eval.c:898
rb_stderr
RUBY_EXTERN VALUE rb_stderr
Definition: ruby.h:2090
CLOCK_THREAD_CPUTIME_ID
#define CLOCK_THREAD_CPUTIME_ID
Definition: rb_mjit_min_header-2.7.1.h:2373
sigemptyset
int sigemptyset(sigset_t *)
RB_BUILTIN_TYPE
#define RB_BUILTIN_TYPE(x)
Definition: ruby.h:550
RBASIC_CLEAR_CLASS
#define RBASIC_CLEAR_CLASS(obj)
Definition: internal.h:1986
proc_initgroups
#define proc_initgroups
Definition: process.c:6443
idEach
@ idEach
Definition: rb_mjit_min_header-2.7.1.h:8708
ST_STOP
@ ST_STOP
Definition: st.h:99
EWOULDBLOCK
#define EWOULDBLOCK
Definition: rubysocket.h:134
FINISH_GETGRNAM
#define FINISH_GETGRNAM
Definition: process.c:233
rb_funcall
#define rb_funcall(recv, mid, argc,...)
Definition: rb_mjit_min_header-2.7.1.h:6585
INT2FIX
#define INT2FIX(i)
Definition: ruby.h:263
n
const char size_t n
Definition: rb_mjit_min_header-2.7.1.h:5456
fopen
FILE * fopen(const char *__restrict _name, const char *__restrict _type)
clock_getres
int clock_getres(clockid_t, struct timespec *)
Definition: win32.c:4652
strchr
char * strchr(char *, char)
rb_execarg::gid
rb_gid_t gid
Definition: internal.h:2059
rb_during_gc
int rb_during_gc(void)
Definition: gc.c:8689
rb_f_abort
VALUE rb_f_abort(int argc, const VALUE *argv)
Definition: process.c:4284
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:11969
p_sys_setegid
#define p_sys_setegid
Definition: process.c:6120
rb_execarg::unsetenv_others_do
unsigned unsetenv_others_do
Definition: internal.h:2044
st
enum ruby_tag_type st
Definition: rb_mjit_min_header-2.7.1.h:11116
TIMETICK_INT_MAX
#define TIMETICK_INT_MAX
Definition: process.c:7447
RSTRING_PTR
#define RSTRING_PTR(str)
Definition: ruby.h:1009
SIG_ERR
#define SIG_ERR
Definition: rb_mjit_min_header-2.7.1.h:2342
rb_attr_get
VALUE rb_attr_get(VALUE, ID)
Definition: variable.c:1084
O_NONBLOCK
#define O_NONBLOCK
Definition: win32.h:611
rb_str_new_cstr
#define rb_str_new_cstr(str)
Definition: rb_mjit_min_header-2.7.1.h:6117
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)
EINVAL
#define EINVAL
Definition: rb_mjit_min_header-2.7.1.h:10964
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:6363
VALUE
unsigned long VALUE
Definition: ruby.h:102
CLOCK_BOOTTIME
#define CLOCK_BOOTTIME
Definition: rb_mjit_min_header-2.7.1.h:2377
GET_VM
#define GET_VM()
Definition: vm_core.h:1764
rb_eArgError
VALUE rb_eArgError
Definition: error.c:923
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:5769
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
fmt
const VALUE int int int int int int VALUE char * fmt
Definition: rb_mjit_min_header-2.7.1.h:6462
CLOCKID2NUM
#define CLOCKID2NUM(v)
Definition: rb_mjit_min_header-2.7.1.h:149
umask
mode_t umask(mode_t __mask)
TYPE
#define TYPE(x)
Definition: ruby.h:554
rb_f_exit
VALUE rb_f_exit(int argc, const VALUE *argv)
Definition: process.c:4210
SIG_SETMASK
#define SIG_SETMASK
Definition: rb_mjit_min_header-2.7.1.h:2305
rb_execarg::pgroup_given
unsigned pgroup_given
Definition: internal.h:2041
sig_t
_sig_func_ptr sig_t
Definition: rb_mjit_min_header-2.7.1.h:2338
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:3392
bsearch
void * bsearch(const void *__key, const void *__base, size_t __nmemb, size_t __size, __compar_fn_t _compar)
rb_hrtime_t
uint64_t rb_hrtime_t
Definition: hrtime.h:47
open_struct
Definition: process.c:2671
spawn_args::ptr
char * ptr
Definition: process.c:4397
rb_execarg::waitpid_state
struct waitpid_state * waitpid_state
Definition: internal.h:2054
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:2048
proc_getpgrp
#define proc_getpgrp
Definition: process.c:4923
CLOCK_REALTIME
#define CLOCK_REALTIME
Definition: win32.h:133
EBADF
#define EBADF
Definition: rb_mjit_min_header-2.7.1.h:10951
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:7449
rb_ec_get_errinfo
VALUE rb_ec_get_errinfo(const rb_execution_context_t *ec)
Definition: eval.c:1852
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:2051
uint64_t
unsigned long long uint64_t
Definition: sha2.h:102
DWORD
IUnknown DWORD
Definition: win32ole.c:33
WUNTRACED
#define WUNTRACED
Definition: rb_mjit_min_header-2.7.1.h:2493
rb_last_status_get
VALUE rb_last_status_get(void)
Definition: process.c:518
arg
VALUE arg
Definition: rb_mjit_min_header-2.7.1.h:5601
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
fclose
int fclose(FILE *)
timetick_int_t
long timetick_int_t
Definition: process.c:7445
getpid
pid_t getpid(void)
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
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
rb_str_new
#define rb_str_new(str, len)
Definition: rb_mjit_min_header-2.7.1.h:6116
Qfalse
#define Qfalse
Definition: ruby.h:467
rb_f_fork
#define rb_f_fork
Definition: process.c:4143
rb_execarg::unsetenv_others_given
unsigned unsetenv_others_given
Definition: internal.h:2043
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:2033
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
_SC_CLK_TCK
#define _SC_CLK_TCK
Definition: rb_mjit_min_header-2.7.1.h:3365
sigprocmask
int sigprocmask(int, const sigset_t *, sigset_t *)
run_exec_dup2_fd_pair::oldfd
int oldfd
Definition: process.c:3047
rb_waitpid
rb_pid_t rb_waitpid(rb_pid_t pid, int *st, int flags)
Definition: process.c:1213
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
NUM2CLOCKID
#define NUM2CLOCKID(v)
Definition: rb_mjit_min_header-2.7.1.h:150
st.h
NULL
#define NULL
Definition: _sdbm.c:101
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:2055
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:3048
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:1988
hrtime.h
EXIT_SUCCESS
#define EXIT_SUCCESS
Definition: process.c:42
proc_setsid
#define proc_setsid
Definition: process.c:5090
rb_pid_t
#define rb_pid_t
Definition: rb_mjit_min_header-2.7.1.h:99
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:2060
strlen
size_t strlen(const char *)
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
issetugid
int issetugid(void)
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:1072
rb_check_arity
#define rb_check_arity
Definition: intern.h:347
timespec::tv_nsec
long tv_nsec
Definition: missing.h:62
chdir
int chdir(const char *__path)
InitVM
#define InitVM(ext)
Definition: ruby.h:2329
RARRAY_LENINT
#define RARRAY_LENINT(ary)
Definition: ruby.h:1071
waitpid_state
Definition: process.c:943
rb_str_capacity
size_t rb_str_capacity(VALUE str)
Definition: string.c:712
daemon
int daemon(int nochdir, int noclose)
rb_str_resize
VALUE rb_str_resize(VALUE, long)
Definition: string.c:2709
rb_exit
void rb_exit(int status)
Definition: process.c:4197
UNLIMITED_ARGUMENTS
#define UNLIMITED_ARGUMENTS
Definition: intern.h:57
RUBY_TYPED_DEFAULT_FREE
#define RUBY_TYPED_DEFAULT_FREE
Definition: ruby.h:1203
sigfillset
int sigfillset(sigset_t *)
execle
int execle(const char *__path, const char *,...)
rb_raise
void rb_raise(VALUE exc, const char *fmt,...)
Definition: error.c:2669
TOUPPER
#define TOUPPER(c)
Definition: ruby.h:2318
rb_io_check_io
VALUE rb_io_check_io(VALUE io)
Definition: io.c:739
mode_t
__mode_t mode_t
Definition: rb_mjit_min_header-2.7.1.h:1331
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
CLOCKS_PER_SEC
#define CLOCKS_PER_SEC
Definition: rb_mjit_min_header-2.7.1.h:1926
T_FILE
#define T_FILE
Definition: ruby.h:534
rb_execarg::fd_open
VALUE fd_open
Definition: internal.h:2063
WNOHANG
#define WNOHANG
Definition: win32.h:128
sig
int sig
Definition: rb_mjit_min_header-2.7.1.h:10427
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
getppid
pid_t getppid(void)
CLK_TCK
#define CLK_TCK
Definition: rb_mjit_min_header-2.7.1.h:1927
proc_daemon
#define proc_daemon
Definition: process.c:6573
proc_seteuid_m
#define proc_seteuid_m
Definition: process.c:6830
void
void
Definition: rb_mjit_min_header-2.7.1.h:13278
_exit
void _exit(int __status) __attribute__((__noreturn__))
list_for_each_safe
#define list_for_each_safe(h, i, nxt, member)
Definition: rb_mjit_min_header-2.7.1.h:9102
ENOENT
#define ENOENT
Definition: rb_mjit_min_header-2.7.1.h:10944
timetick::count
int32_t count
Definition: process.c:7501
run_exec_dup2_fd_pair::cloexec
int cloexec
Definition: process.c:3051
UIDT2NUM
#define UIDT2NUM(v)
Definition: ruby.h:360
rb_syserr_fail
void rb_syserr_fail(int e, const char *mesg)
Definition: error.c:2781
va_start
#define va_start(v, l)
Definition: rb_mjit_min_header-2.7.1.h:3978
rb_execarg::fd_dup2
VALUE fd_dup2
Definition: internal.h:2061
DATA_PTR
#define DATA_PTR(dta)
Definition: ruby.h:1175
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.1.h:1346
NUM2RLIM
#define NUM2RLIM(v)
Definition: rb_mjit_min_header-2.7.1.h:138
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:2057
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
ECHILD
#define ECHILD
Definition: rb_mjit_min_header-2.7.1.h:10952
rb_execarg::new_pgroup_flag
unsigned new_pgroup_flag
Definition: internal.h:2049
WAITPID_LOCK_ONLY
#define WAITPID_LOCK_ONLY
Definition: process.c:941
rb_uid_t
#define rb_uid_t
Definition: rb_mjit_min_header-2.7.1.h:105
fork
pid_t fork(void)
setsid
pid_t setsid(void)
list_head
Definition: rb_mjit_min_header-2.7.1.h:8980
NGROUPS_MAX
#define NGROUPS_MAX
Definition: rb_mjit_min_header-2.7.1.h:4166
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:2039
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:3523
CHILD_ERRMSG_BUFLEN
#define CHILD_ERRMSG_BUFLEN
spawn_args::buflen
size_t buflen
Definition: process.c:4398
waitpid_state::wnode
struct list_node wnode
Definition: process.c:944
h
size_t st_index_t h
Definition: rb_mjit_min_header-2.7.1.h:5462
RB_OBJ_WRITTEN
#define RB_OBJ_WRITTEN(a, oldv, b)
Definition: ruby.h:1509
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:884
vfork
pid_t vfork(void)
TO_BOOL
#define TO_BOOL(val, name)
Definition: process.c:2011
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:4442
SIGCHLD_LOSSY
#define SIGCHLD_LOSSY
Definition: vm_core.h:120
TIMETICK_INT2NUM
#define TIMETICK_INT2NUM(v)
Definition: process.c:7448
rb_hash_lookup
VALUE rb_hash_lookup(VALUE hash, VALUE key)
Definition: hash.c:2058
timetick::giga_count
timetick_int_t giga_count
Definition: process.c:7500
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:2670
rb_execarg::uid_given
unsigned uid_given
Definition: internal.h:2050
execv
int execv(const char *__path, char *const __argv[])
execl
int execl(const char *__path, const char *,...)
rb_update_max_fd
void rb_update_max_fd(int fd)
Definition: io.c:218
WIFSIGNALED
#define WIFSIGNALED(w)
Definition: process.c:105
qsort
void qsort(void *__base, size_t __nmemb, size_t __size, __compar_fn_t _compar)
va_list
__gnuc_va_list va_list
Definition: rb_mjit_min_header-2.7.1.h:836
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
dup
int dup(int __fildes)
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:6260
id_status
#define id_status
Definition: internal.h:1590
open_struct::err
int err
Definition: process.c:2676
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
rb_w32_set_nonblock2
int rb_w32_set_nonblock2(int fd, int nonblock)
Definition: win32.c:4359
CLOCK_PROCESS_CPUTIME_ID
#define CLOCK_PROCESS_CPUTIME_ID
Definition: rb_mjit_min_header-2.7.1.h:2372
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:2992
RLIM2NUM
#define RLIM2NUM(v)
Definition: rb_mjit_min_header-2.7.1.h:137
mjit_resume
VALUE mjit_resume(void)
rb_execarg::envp_str
VALUE envp_str
Definition: internal.h:2037
mjit_enabled
#define mjit_enabled
Definition: internal.h:1765
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
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:6463
EINTR
#define EINTR
Definition: rb_mjit_min_header-2.7.1.h:10946
setregid
int setregid(gid_t __rgid, gid_t __egid)
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:8681
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
write
_ssize_t write(int __fd, const void *__buf, size_t __nbyte)
execve
int execve(const char *__path, char *const __argv[], char *const __envp[])
p_sys_setregid
#define p_sys_setregid
Definition: process.c:6147
rb_env_clear
VALUE rb_env_clear(void)
Definition: hash.c:5622
PIDT2NUM
#define PIDT2NUM(v)
Definition: ruby.h:354
time_t
long time_t
Definition: rb_mjit_min_header-2.7.1.h:1236
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
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:4976
p_gid_from_name
#define p_gid_from_name
Definition: process.c:238
rb_execarg::use_shell
unsigned use_shell
Definition: internal.h:2040
FD_CLOEXEC
#define FD_CLOEXEC
Definition: win32.h:610
waitpid
rb_pid_t waitpid(rb_pid_t, int *, int)
Definition: win32.c:4476
open_struct::oflags
int oflags
Definition: process.c:2673
StringValueCStr
#define StringValueCStr(v)
Definition: ruby.h:604
pthread_sigmask
int pthread_sigmask(int, const sigset_t *, sigset_t *)
COMPILER_WARNING_PUSH
#define COMPILER_WARNING_PUSH
Definition: internal.h:2669
clock_t
unsigned long clock_t
Definition: rb_mjit_min_header-2.7.1.h:1303
list_del
#define list_del(n)
Definition: rb_mjit_min_header-2.7.1.h:9046
rb_check_array_type
VALUE rb_check_array_type(VALUE ary)
Definition: array.c:909
key
key
Definition: openssl_missing.h:181
rb_execarg::close_others_given
unsigned close_others_given
Definition: internal.h:2045
path
VALUE path
Definition: rb_mjit_min_header-2.7.1.h:7353
proc_getrlimit
#define proc_getrlimit
Definition: process.c:5414
EPERM
#define EPERM
Definition: _sdbm.c:92
vm_ifunc::flags
VALUE flags
Definition: internal.h:1216
clock
clock_t clock(void)
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:2042
mjit_finish
void mjit_finish(_Bool close_handle_p)
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:6174
timeval::tv_sec
time_t tv_sec
Definition: missing.h:54
rb_eNotImpError
VALUE rb_eNotImpError
Definition: error.c:932
getpgid
pid_t getpgid(pid_t)
CLASS_OF
#define CLASS_OF(v)
Definition: ruby.h:484
waitpid_state::errnum
int errnum
Definition: process.c:951
CLOCK_REALTIME_ALARM
#define CLOCK_REALTIME_ALARM
Definition: rb_mjit_min_header-2.7.1.h:2378
OBJ2GID
#define OBJ2GID(id)
Definition: process.c:235
rb_sigwait_sleep
void rb_sigwait_sleep(const rb_thread_t *, int fd, const rb_hrtime_t *)
RUBY_UBF_PROCESS
#define RUBY_UBF_PROCESS
Definition: intern.h:946
dup2
RUBY_EXTERN int dup2(int, int)
Definition: dup2.c:27
InitVM_process
void InitVM_process(void)
Definition: process.c:8143
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.1.h:1351
TIMETICK_INT_MIN
#define TIMETICK_INT_MIN
Definition: process.c:7446
rb_check_hash_type
VALUE rb_check_hash_type(VALUE hash)
Definition: hash.c:1847
spawn_args::execarg
VALUE execarg
Definition: process.c:4395
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:2056
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
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:668
list_add
#define list_add(h, n)
Definition: rb_mjit_min_header-2.7.1.h:9009
rb_mProcess
VALUE rb_mProcess
Definition: process.c:8131
ENVMATCH
#define ENVMATCH(n1, n2)
Definition: process.c:2293
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_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
setgroups
int setgroups(int ngroups, const gid_t *grouplist)
rb_bug
void rb_bug(const char *fmt,...)
Definition: error.c:634
StringValue
use StringValue() instead")))
internal.h
run_exec_dup2_fd_pair
Definition: process.c:3046
timeval::tv_usec
long tv_usec
Definition: missing.h:55
T_ARRAY
#define T_ARRAY
Definition: ruby.h:530
argv
char ** argv
Definition: ruby.c:223
rb_native_cond_wait
void rb_native_cond_wait(rb_nativethread_cond_t *, rb_nativethread_lock_t *)
getpgrp
pid_t getpgrp(void)
p_sys_setgid
#define p_sys_setgid
Definition: process.c:6076
time
time_t time(time_t *_timer)
F_SETFL
#define F_SETFL
Definition: win32.h:608
LONG_LONG
#define LONG_LONG
Definition: rb_mjit_min_header-2.7.1.h:3939
rb_native_mutex_unlock
void rb_native_mutex_unlock(rb_nativethread_lock_t *)
p_sys_setuid
#define p_sys_setuid
Definition: process.c:5696
ST_CONTINUE
@ ST_CONTINUE
Definition: st.h:99
ruby_setenv
void ruby_setenv(const char *name, const char *value)
Definition: hash.c:4992
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
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:5858
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
GET_THREAD
#define GET_THREAD()
Definition: vm_core.h:1765
rb_execarg
Definition: internal.h:2024
CLOCK_MONOTONIC_COARSE
#define CLOCK_MONOTONIC_COARSE
Definition: rb_mjit_min_header-2.7.1.h:2376
ssize_t
_ssize_t ssize_t
Definition: rb_mjit_min_header-2.7.1.h:1329
close
int close(int __fildes)
SIGPIPE
#define SIGPIPE
Definition: rb_mjit_min_header-2.7.1.h:2261
p_sys_setruid
#define p_sys_setruid
Definition: process.c:5718
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
WCOREDUMP
#define WCOREDUMP(_w)
Definition: rb_mjit_min_header-2.7.1.h:2503
RUBY_TYPED_FREE_IMMEDIATELY
#define RUBY_TYPED_FREE_IMMEDIATELY
Definition: ruby.h:1207
ERANGE
#define ERANGE
Definition: rb_mjit_min_header-2.7.1.h:10976
ARGVSTR2ARGV
#define ARGVSTR2ARGV(argv_str)
Definition: internal.h:2074
rb_execarg::fd_close
VALUE fd_close
Definition: internal.h:2062
parent_redirect_close
#define parent_redirect_close(fd)
Definition: process.c:413
read
_ssize_t read(int __fd, void *__buf, size_t __nbyte)
MEMCPY
#define MEMCPY(p1, p2, type, n)
Definition: ruby.h:1753
_SC_NGROUPS_MAX
#define _SC_NGROUPS_MAX
Definition: rb_mjit_min_header-2.7.1.h:3366
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:2847
int
__inline__ int
Definition: rb_mjit_min_header-2.7.1.h:2839
rb_execarg::redirect_fds
VALUE redirect_fds
Definition: internal.h:2036
old
VALUE ID VALUE old
Definition: rb_mjit_min_header-2.7.1.h:16153
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:7547
signal
_sig_func_ptr signal(int, _sig_func_ptr)
argc
int argc
Definition: ruby.c:222
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
list_node
Definition: rb_mjit_min_header-2.7.1.h:8976
rb_define_const
void rb_define_const(VALUE, const char *, VALUE)
Definition: variable.c:2880
err
int err
Definition: win32.c:135
setpgid
int setpgid(pid_t __pid, pid_t __pgid)
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:2038
ruby_getcwd
char * ruby_getcwd(void)
Definition: util.c:539
rb_execarg::invoke
union rb_execarg::@110 invoke
GetOpenFile
#define GetOpenFile(obj, fp)
Definition: io.h:127
rb_execarg::close_others_do
unsigned close_others_do
Definition: internal.h:2046
v
int VALUE v
Definition: rb_mjit_min_header-2.7.1.h:12337
rb_execarg::path_env
VALUE path_env
Definition: internal.h:2066
ENOMEM
#define ENOMEM
Definition: rb_mjit_min_header-2.7.1.h:10954
COMPILER_WARNING_IGNORED
#define COMPILER_WARNING_IGNORED(flag)
Definition: internal.h:2672
rb_deprecate_constant
void rb_deprecate_constant(VALUE mod, const char *name)
Definition: variable.c:2947
proc_setmaxgroups
#define proc_setmaxgroups
Definition: process.c:6495
rb_gc_mark
void rb_gc_mark(VALUE ptr)
Definition: gc.c:5214
RB_MAX_GROUPS
#define RB_MAX_GROUPS
Definition: internal.h:2021
int32_t
__int32_t int32_t
Definition: rb_mjit_min_header-2.7.1.h:1175
rb_spawn
rb_pid_t rb_spawn(int argc, const VALUE *argv)
Definition: process.c:4448
_
#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:8570
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
EAGAIN
#define EAGAIN
Definition: rb_mjit_min_header-2.7.1.h:10953
NUM2UIDT
#define NUM2UIDT(v)
Definition: ruby.h:363
exit
void exit(int __status) __attribute__((__noreturn__))
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:4324
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
alloca
#define alloca(size)
Definition: rb_mjit_min_header-2.7.1.h:2487
timespec
Definition: missing.h:60
vfprintf
int int int int int int vfprintf(FILE *__restrict, const char *__restrict, __gnuc_va_list) __attribute__((__format__(__printf__
rb_execarg::uid
rb_uid_t uid
Definition: internal.h:2058
sysconf
long sysconf(int __name)
rb_io_t::tied_io_for_writing
VALUE tied_io_for_writing
Definition: io.h:77
LONG2FIX
#define LONG2FIX(i)
Definition: ruby.h:265
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
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)
proc_getsid
#define proc_getsid
Definition: process.c:5032
SIG_DFL
#define SIG_DFL
Definition: rb_mjit_min_header-2.7.1.h:2340
rb_w32_uaspawn_flags
rb_pid_t rb_w32_uaspawn_flags(int, const char *, char *const *, DWORD)
Definition: win32.c:1556
list_empty
#define list_empty(h)
Definition: rb_mjit_min_header-2.7.1.h:9035
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
getgroups
int getgroups(int __gidsetsize, gid_t __grouplist[])
rb_sym2str
VALUE rb_sym2str(VALUE)
Definition: symbol.c:784
rb_execarg::exception_given
unsigned exception_given
Definition: internal.h:2052
rb_execarg::chdir_given
unsigned chdir_given
Definition: internal.h:2047
ruby_signal_name
const char * ruby_signal_name(int)
Definition: signal.c:310
strncmp
int strncmp(const char *, const char *, size_t)
HZ
#define HZ
Definition: rb_mjit_min_header-2.7.1.h:11082
RHASH_TBL_RAW
#define RHASH_TBL_RAW(h)
Definition: internal.h:1694
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:1442
SIG_IGN
#define SIG_IGN
Definition: rb_mjit_min_header-2.7.1.h:2341
redirect_close
#define redirect_close(fd)
Definition: process.c:411
ENOEXEC
#define ENOEXEC
Definition: rb_mjit_min_header-2.7.1.h:10950
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:1115
proc_setpriority
#define proc_setpriority
Definition: process.c:5157
setegid
int setegid(gid_t __gid)
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
waitpid_state::options
int options
Definition: process.c:950
rb_str_buf_cat
#define rb_str_buf_cat
Definition: intern.h:910
thread.h
redirect_cloexec_dup
#define redirect_cloexec_dup(oldfd)
Definition: process.c:409
RUBY_TIME_BASED_CLOCK_REALTIME
#define RUBY_TIME_BASED_CLOCK_REALTIME
sigset_t
__sigset_t sigset_t
Definition: rb_mjit_min_header-2.7.1.h:1262
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
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
setreuid
int setreuid(uid_t __ruid, uid_t __euid)
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))
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
proc_setrlimit
#define proc_setrlimit
Definition: process.c:5490
proc_setegid_m
#define proc_setegid_m
Definition: process.c:6960
rb_proc_times
#define rb_proc_times
Definition: process.c:7435
rb_gid_t
#define rb_gid_t
Definition: rb_mjit_min_header-2.7.1.h:111
proc_setpgrp
#define proc_setpgrp
Definition: process.c:4951
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
setgid
int setgid(rb_gid_t)
Definition: win32.c:2800
__sFILE
Definition: vsnprintf.c:169
va_end
#define va_end(v)
Definition: rb_mjit_min_header-2.7.1.h:3979
rb_eSystemExit
VALUE rb_eSystemExit
Definition: error.c:915
rb_thread_sleep_interruptible
void rb_thread_sleep_interruptible(void)
Definition: thread.c:1328
mjit_pause
VALUE mjit_pause(_Bool wait_p)
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
GIDT2NUM
#define GIDT2NUM(v)
Definition: ruby.h:366
rb_thread_local_aset
VALUE rb_thread_local_aset(VALUE, ID, VALUE)
Definition: thread.c:3364
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)
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