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