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