[ruby/digest] [DOC] Update document to use `rb_digest_make_metadata`
[ruby.git] / process.c
blobb1f9931f06d47792165cb4f91f86475c62fbf3a3
1 /**********************************************************************
3 process.c -
5 $Author$
6 created at: Tue Aug 10 14:30:50 JST 1993
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
12 **********************************************************************/
14 #include "ruby/internal/config.h"
16 #include "ruby/fiber/scheduler.h"
18 #include <ctype.h>
19 #include <errno.h>
20 #include <signal.h>
21 #include <stdarg.h>
22 #include <stdio.h>
23 #include <time.h>
25 #ifdef HAVE_STDLIB_H
26 # include <stdlib.h>
27 #endif
29 #ifdef HAVE_UNISTD_H
30 # include <unistd.h>
31 #endif
33 #ifdef HAVE_FCNTL_H
34 # include <fcntl.h>
35 #endif
37 #ifdef HAVE_PROCESS_H
38 # include <process.h>
39 #endif
41 #ifndef EXIT_SUCCESS
42 # define EXIT_SUCCESS 0
43 #endif
45 #ifndef EXIT_FAILURE
46 # define EXIT_FAILURE 1
47 #endif
49 #ifdef HAVE_SYS_WAIT_H
50 # include <sys/wait.h>
51 #endif
53 #ifdef HAVE_SYS_RESOURCE_H
54 # include <sys/resource.h>
55 #endif
57 #ifdef HAVE_VFORK_H
58 # include <vfork.h>
59 #endif
61 #ifdef HAVE_SYS_PARAM_H
62 # include <sys/param.h>
63 #endif
65 #ifndef MAXPATHLEN
66 # define MAXPATHLEN 1024
67 #endif
69 #include <sys/stat.h>
71 #ifdef HAVE_SYS_TIME_H
72 # include <sys/time.h>
73 #endif
75 #ifdef HAVE_SYS_TIMES_H
76 # include <sys/times.h>
77 #endif
79 #ifdef HAVE_PWD_H
80 # include <pwd.h>
81 #endif
83 #ifdef HAVE_GRP_H
84 # include <grp.h>
85 # ifdef __CYGWIN__
86 int initgroups(const char *, rb_gid_t);
87 # endif
88 #endif
90 #ifdef HAVE_SYS_ID_H
91 # include <sys/id.h>
92 #endif
94 #ifdef __APPLE__
95 # include <mach/mach_time.h>
96 #endif
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"
122 /* define system APIs */
123 #ifdef _WIN32
124 #undef open
125 #define open rb_w32_uopen
126 #endif
128 #if defined(HAVE_TIMES) || defined(_WIN32)
129 /*********************************************************************
131 * Document-class: Process::Tms
133 * Placeholder for rusage
135 static VALUE rb_cProcessTms;
136 #endif
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
157 #if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__bsdi__)
158 #define HAVE_44BSD_SETUID 1
159 #define HAVE_44BSD_SETGID 1
160 #endif
162 #ifdef __NetBSD__
163 #undef HAVE_SETRUID
164 #undef HAVE_SETRGID
165 #endif
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
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
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);
189 VALUE rb_envtbl(void);
190 VALUE rb_env_to_hash(void);
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
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
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)
243 rb_uid_t uid;
244 PREPARE_GETPWNAM;
245 uid = OBJ2UID1(id);
246 FINISH_GETPWNAM;
247 return uid;
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
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)
285 rb_gid_t gid;
286 PREPARE_GETGRNAM;
287 gid = OBJ2GID1(id);
288 FINISH_GETGRNAM;
289 return gid;
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
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
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;
364 static rb_pid_t cached_pid;
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
375 static void
376 assert_close_on_exec(int fd)
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;
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 */
394 static inline int
395 close_unless_reserved(int fd)
397 if (rb_reserved_fd_p(fd)) { /* async-signal-safe */
398 assert_close_on_exec(fd);
399 return 0;
401 return close(fd); /* async-signal-safe */
404 /*#define DEBUG_REDIRECT*/
405 #if defined(DEBUG_REDIRECT)
407 static void
408 ttyprintf(const char *fmt, ...)
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;
421 va_start(ap, fmt);
422 vfprintf(tty, fmt, ap);
423 va_end(ap);
424 fclose(tty);
425 errno = save;
428 static int
429 redirect_dup(int oldfd)
431 int ret;
432 ret = dup(oldfd);
433 ttyprintf("dup(%d) => %d\n", oldfd, ret);
434 return ret;
437 static int
438 redirect_dup2(int oldfd, int newfd)
440 int ret;
441 ret = dup2(oldfd, newfd);
442 ttyprintf("dup2(%d, %d) => %d\n", oldfd, newfd, ret);
443 return ret;
446 static int
447 redirect_cloexec_dup(int oldfd)
449 int ret;
450 ret = rb_cloexec_dup(oldfd);
451 ttyprintf("cloexec_dup(%d) => %d\n", oldfd, ret);
452 return ret;
455 static int
456 redirect_cloexec_dup2(int oldfd, int newfd)
458 int ret;
459 ret = rb_cloexec_dup2(oldfd, newfd);
460 ttyprintf("cloexec_dup2(%d, %d) => %d\n", oldfd, newfd, ret);
461 return ret;
464 static int
465 redirect_close(int fd)
467 int ret;
468 ret = close_unless_reserved(fd);
469 ttyprintf("close(%d) => %d\n", fd, ret);
470 return ret;
473 static int
474 parent_redirect_open(const char *pathname, int flags, mode_t perm)
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;
482 static int
483 parent_redirect_close(int fd)
485 int ret;
486 ret = close_unless_reserved(fd);
487 ttyprintf("parent_close(%d) => %d\n", fd, ret);
488 return ret;
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
501 static VALUE
502 get_pid(void)
504 if (UNLIKELY(!cached_pid)) { /* 0 is not a valid pid */
505 cached_pid = getpid();
507 /* pid should be likely POSFIXABLE() */
508 return PIDT2NUM(cached_pid);
511 #if defined HAVE_WORKING_FORK || defined HAVE_DAEMON
512 static void
513 clear_pid_cache(void)
515 cached_pid = 0;
517 #endif
520 * call-seq:
521 * Process.pid -> integer
523 * Returns the process ID of the current process:
525 * Process.pid # => 15668
529 static VALUE
530 proc_get_pid(VALUE _)
532 return get_pid();
535 static VALUE
536 get_ppid(void)
538 return PIDT2NUM(getppid());
542 * call-seq:
543 * Process.ppid -> integer
545 * Returns the process ID of the parent of the current process:
547 * puts "Pid is #{Process.pid}."
548 * fork { puts "Parent pid is #{Process.ppid}." }
550 * Output:
552 * Pid is 271290.
553 * Parent pid is 271290.
555 * May not return a trustworthy value on certain platforms.
558 static VALUE
559 proc_get_ppid(VALUE _)
561 return get_ppid();
565 /*********************************************************************
567 * Document-class: Process::Status
569 * A Process::Status contains information about a system process.
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):
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
585 static VALUE rb_cProcessStatus;
587 struct rb_process_status {
588 rb_pid_t pid;
589 int status;
590 int error;
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,
600 .flags = RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED | RUBY_TYPED_EMBEDDABLE,
603 static VALUE
604 rb_process_status_allocate(VALUE klass)
606 struct rb_process_status *data;
607 return TypedData_Make_Struct(klass, struct rb_process_status, &rb_process_status_type, data);
610 VALUE
611 rb_last_status_get(void)
613 return GET_THREAD()->last_status;
617 * call-seq:
618 * Process.last_status -> Process::Status or nil
620 * Returns a Process::Status object representing the most recently exited
621 * child process in the current thread, or +nil+ if none:
623 * Process.spawn('ruby', '-e', 'exit 13')
624 * Process.wait
625 * Process.last_status # => #<Process::Status: pid 14396 exit 13>
627 * Process.spawn('ruby', '-e', 'exit 14')
628 * Process.wait
629 * Process.last_status # => #<Process::Status: pid 4692 exit 14>
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>
638 static VALUE
639 proc_s_last_status(VALUE mod)
641 return rb_last_status_get();
644 VALUE
645 rb_process_status_new(rb_pid_t pid, int status, int error)
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;
653 rb_obj_freeze(last_status);
654 return last_status;
657 static VALUE
658 process_status_dump(VALUE status)
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));
667 return dump;
670 static VALUE
671 process_status_load(VALUE real_obj, VALUE load_obj)
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;
681 void
682 rb_last_status_set(int status, rb_pid_t pid)
684 GET_THREAD()->last_status = rb_process_status_new(pid, status, 0);
687 static void
688 last_status_clear(rb_thread_t *th)
690 th->last_status = Qnil;
693 void
694 rb_last_status_clear(void)
696 last_status_clear(GET_THREAD());
699 static rb_pid_t
700 pst_pid(VALUE status)
702 struct rb_process_status *data;
703 TypedData_Get_Struct(status, struct rb_process_status, &rb_process_status_type, data);
704 return data->pid;
707 static int
708 pst_status(VALUE status)
710 struct rb_process_status *data;
711 TypedData_Get_Struct(status, struct rb_process_status, &rb_process_status_type, data);
712 return data->status;
716 * call-seq:
717 * to_i -> integer
719 * Returns the system-dependent integer status of +self+:
721 * `cat /nop`
722 * $?.to_i # => 256
725 static VALUE
726 pst_to_i(VALUE self)
728 int status = pst_status(self);
729 return RB_INT2NUM(status);
732 #define PST2INT(st) pst_status(st)
735 * call-seq:
736 * pid -> integer
738 * Returns the process ID of the process:
740 * system("false")
741 * $?.pid # => 1247002
745 static VALUE
746 pst_pid_m(VALUE self)
748 rb_pid_t pid = pst_pid(self);
749 return PIDT2NUM(pid);
752 static VALUE pst_message_status(VALUE str, int status);
754 static void
755 pst_message(VALUE str, rb_pid_t pid, int status)
757 rb_str_catf(str, "pid %ld", (long)pid);
758 pst_message_status(str, status);
761 static VALUE
762 pst_message_status(VALUE str, int status)
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);
770 else {
771 rb_str_catf(str, " stopped signal %d", stopsig);
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);
780 else {
781 rb_str_catf(str, " signal %d", termsig);
784 if (WIFEXITED(status)) {
785 rb_str_catf(str, " exit %d", WEXITSTATUS(status));
787 #ifdef WCOREDUMP
788 if (WCOREDUMP(status)) {
789 rb_str_cat2(str, " (core dumped)");
791 #endif
792 return str;
797 * call-seq:
798 * to_s -> string
800 * Returns a string representation of +self+:
802 * `cat /nop`
803 * $?.to_s # => "pid 1262141 exit 1"
808 static VALUE
809 pst_to_s(VALUE st)
811 rb_pid_t pid;
812 int status;
813 VALUE str;
815 pid = pst_pid(st);
816 status = PST2INT(st);
818 str = rb_str_buf_new(0);
819 pst_message(str, pid, status);
820 return str;
825 * call-seq:
826 * inspect -> string
828 * Returns a string representation of +self+:
830 * system("false")
831 * $?.inspect # => "#<Process::Status: pid 1303494 exit 1>"
835 static VALUE
836 pst_inspect(VALUE st)
838 rb_pid_t pid;
839 int status;
840 VALUE str;
842 pid = pst_pid(st);
843 if (!pid) {
844 return rb_sprintf("#<%s: uninitialized>", rb_class2name(CLASS_OF(st)));
846 status = PST2INT(st);
848 str = rb_sprintf("#<%s: ", rb_class2name(CLASS_OF(st)));
849 pst_message(str, pid, status);
850 rb_str_cat2(str, ">");
851 return str;
856 * call-seq:
857 * stat == other -> true or false
859 * Returns whether the value of #to_i == +other+:
861 * `cat /nop`
862 * stat = $? # => #<Process::Status: pid 1170366 exit 1>
863 * sprintf('%x', stat.to_i) # => "100"
864 * stat == 0x100 # => true
868 static VALUE
869 pst_equal(VALUE st1, VALUE st2)
871 if (st1 == st2) return Qtrue;
872 return rb_equal(pst_to_i(st1), st2);
877 * call-seq:
878 * stat & mask -> integer
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.
884 * Returns the logical AND of the value of #to_i with +mask+:
886 * `cat /nop`
887 * stat = $? # => #<Process::Status: pid 1155508 exit 1>
888 * sprintf('%x', stat.to_i) # => "100"
889 * stat & 0x00 # => 0
891 * ArgumentError is raised if +mask+ is negative.
894 static VALUE
895 pst_bitand(VALUE st1, VALUE st2)
897 int status = PST2INT(st1);
898 int mask = NUM2INT(st2);
900 if (mask < 0) {
901 rb_raise(rb_eArgError, "negative mask value: %d", mask);
903 #define WARN_SUGGEST(suggest) \
904 rb_warn_deprecated_to_remove_at(3.5, "Process::Status#&", suggest)
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;
923 #undef WARN_SUGGEST
924 status &= mask;
926 return INT2NUM(status);
931 * call-seq:
932 * stat >> places -> integer
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.
938 * Returns the value of #to_i, shifted +places+ to the right:
940 * `cat /nop`
941 * stat = $? # => #<Process::Status: pid 1155508 exit 1>
942 * stat.to_i # => 256
943 * stat >> 1 # => 128
944 * stat >> 2 # => 64
946 * ArgumentError is raised if +places+ is negative.
949 static VALUE
950 pst_rshift(VALUE st1, VALUE st2)
952 int status = PST2INT(st1);
953 int places = NUM2INT(st2);
955 if (places < 0) {
956 rb_raise(rb_eArgError, "negative shift value: %d", places);
958 #define WARN_SUGGEST(suggest) \
959 rb_warn_deprecated_to_remove_at(3.5, "Process::Status#>>", suggest)
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;
972 #undef WARN_SUGGEST
973 status >>= places;
975 return INT2NUM(status);
980 * call-seq:
981 * stopped? -> true or false
983 * Returns +true+ if this process is stopped,
984 * and if the corresponding #wait call had the Process::WUNTRACED flag set,
985 * +false+ otherwise.
988 static VALUE
989 pst_wifstopped(VALUE st)
991 int status = PST2INT(st);
993 return RBOOL(WIFSTOPPED(status));
998 * call-seq:
999 * stopsig -> integer or nil
1001 * Returns the number of the signal that caused the process to stop,
1002 * or +nil+ if the process is not stopped.
1005 static VALUE
1006 pst_wstopsig(VALUE st)
1008 int status = PST2INT(st);
1010 if (WIFSTOPPED(status))
1011 return INT2NUM(WSTOPSIG(status));
1012 return Qnil;
1017 * call-seq:
1018 * signaled? -> true or false
1020 * Returns +true+ if the process terminated because of an uncaught signal,
1021 * +false+ otherwise.
1024 static VALUE
1025 pst_wifsignaled(VALUE st)
1027 int status = PST2INT(st);
1029 return RBOOL(WIFSIGNALED(status));
1034 * call-seq:
1035 * termsig -> integer or nil
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.
1041 static VALUE
1042 pst_wtermsig(VALUE st)
1044 int status = PST2INT(st);
1046 if (WIFSIGNALED(status))
1047 return INT2NUM(WTERMSIG(status));
1048 return Qnil;
1053 * call-seq:
1054 * exited? -> true or false
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.
1061 static VALUE
1062 pst_wifexited(VALUE st)
1064 int status = PST2INT(st);
1066 return RBOOL(WIFEXITED(status));
1071 * call-seq:
1072 * exitstatus -> integer or nil
1074 * Returns the least significant eight bits of the return code
1075 * of the process if it has exited;
1076 * +nil+ otherwise:
1078 * `exit 99`
1079 * $?.exitstatus # => 99
1083 static VALUE
1084 pst_wexitstatus(VALUE st)
1086 int status = PST2INT(st);
1088 if (WIFEXITED(status))
1089 return INT2NUM(WEXITSTATUS(status));
1090 return Qnil;
1095 * call-seq:
1096 * success? -> true, false, or nil
1098 * Returns:
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.
1106 static VALUE
1107 pst_success_p(VALUE st)
1109 int status = PST2INT(st);
1111 if (!WIFEXITED(status))
1112 return Qnil;
1113 return RBOOL(WEXITSTATUS(status) == EXIT_SUCCESS);
1118 * call-seq:
1119 * coredump? -> true or false
1121 * Returns +true+ if the process generated a coredump
1122 * when it terminated, +false+ if not.
1124 * Not available on all platforms.
1127 static VALUE
1128 pst_wcoredump(VALUE st)
1130 #ifdef WCOREDUMP
1131 int status = PST2INT(st);
1133 return RBOOL(WCOREDUMP(status));
1134 #else
1135 return Qfalse;
1136 #endif
1139 static rb_pid_t
1140 do_waitpid(rb_pid_t pid, int *st, int flags)
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
1151 struct waitpid_state {
1152 struct ccan_list_node wnode;
1153 rb_execution_context_t *ec;
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;
1162 static void
1163 waitpid_state_init(struct waitpid_state *w, rb_pid_t pid, int options)
1165 w->ret = 0;
1166 w->pid = pid;
1167 w->options = options;
1168 w->errnum = 0;
1169 w->status = 0;
1172 static void *
1173 waitpid_blocking_no_SIGCHLD(void *x)
1175 struct waitpid_state *w = x;
1177 w->ret = do_waitpid(w->pid, &w->status, w->options);
1179 return 0;
1182 static void
1183 waitpid_no_SIGCHLD(struct waitpid_state *w)
1185 if (w->options & WNOHANG) {
1186 w->ret = do_waitpid(w->pid, &w->status, w->options);
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));
1193 if (w->ret == -1)
1194 w->errnum = errno;
1197 VALUE
1198 rb_process_status_wait(rb_pid_t pid, int flags)
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;
1207 struct waitpid_state waitpid_state;
1209 waitpid_state_init(&waitpid_state, pid, flags);
1210 waitpid_state.ec = GET_EC();
1212 waitpid_no_SIGCHLD(&waitpid_state);
1214 if (waitpid_state.ret == 0) return Qnil;
1216 return rb_process_status_new(waitpid_state.ret, waitpid_state.status, waitpid_state.errnum);
1220 * call-seq:
1221 * Process::Status.wait(pid = -1, flags = 0) -> Process::Status
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+.
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>:
1232 * Process.spawn('cat /nop') # => 1155880
1233 * Process::Status.wait # => #<Process::Status: pid 1155880 exit 1>
1234 * $? # => #<Process::Status: pid 1155508 exit 1>
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>:
1241 * Process::Status.wait # => #<Process::Status: pid -1 exit 0>
1242 * $? # => #<Process::Status: pid 1155508 exit 1> # Unchanged.
1244 * May invoke the scheduler hook Fiber::Scheduler#process_wait.
1246 * Not available on all platforms.
1249 static VALUE
1250 rb_process_status_waitv(int argc, VALUE *argv, VALUE _)
1252 rb_check_arity(argc, 0, 2);
1254 rb_pid_t pid = -1;
1255 int flags = 0;
1257 if (argc >= 1) {
1258 pid = NUM2PIDT(argv[0]);
1261 if (argc >= 2) {
1262 flags = RB_NUM2INT(argv[1]);
1265 return rb_process_status_wait(pid, flags);
1268 rb_pid_t
1269 rb_waitpid(rb_pid_t pid, int *st, int flags)
1271 VALUE status = rb_process_status_wait(pid, flags);
1272 if (NIL_P(status)) return 0;
1274 struct rb_process_status *data = rb_check_typeddata(status, &rb_process_status_type);
1275 pid = data->pid;
1277 if (st) *st = data->status;
1279 if (pid == -1) {
1280 errno = data->error;
1282 else {
1283 GET_THREAD()->last_status = status;
1286 return pid;
1289 static VALUE
1290 proc_wait(int argc, VALUE *argv)
1292 rb_pid_t pid;
1293 int flags, status;
1295 flags = 0;
1296 if (rb_check_arity(argc, 0, 2) == 0) {
1297 pid = -1;
1299 else {
1300 VALUE vflags;
1301 pid = NUM2PIDT(argv[0]);
1302 if (argc == 2 && !NIL_P(vflags = argv[1])) {
1303 flags = NUM2UINT(vflags);
1307 if ((pid = rb_waitpid(pid, &status, flags)) < 0)
1308 rb_sys_fail(0);
1310 if (pid == 0) {
1311 rb_last_status_clear();
1312 return Qnil;
1315 return PIDT2NUM(pid);
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.
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:".
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.
1333 * call-seq:
1334 * Process.wait(pid = -1, flags = 0) -> integer
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+:
1341 * - Positive integer: Waits for the child process whose process ID is +pid+:
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
1351 * - <tt>0</tt>: Waits for any child process whose group ID
1352 * is the same as that of the current process:
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
1375 * Output:
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.
1385 * - <tt>-1</tt> (default): Waits for any child process:
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)
1407 * Output:
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
1417 * - Less than <tt>-1</tt>: Waits for any child whose process group ID is <tt>-pid</tt>:
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
1441 * Output:
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.
1451 * Argument +flags+ should be given as one of the following constants,
1452 * or as the logical OR of both:
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.
1457 * Not all flags are available on all platforms.
1459 * Raises Errno::ECHILD if there is no suitable child process.
1461 * Not available on all platforms.
1463 * Process.waitpid is an alias for Process.wait.
1465 static VALUE
1466 proc_m_wait(int c, VALUE *v, VALUE _)
1468 return proc_wait(c, v);
1472 * call-seq:
1473 * Process.wait2(pid = -1, flags = 0) -> [pid, status]
1475 * Like Process.waitpid, but returns an array
1476 * containing the child process +pid+ and Process::Status +status+:
1478 * pid = Process.spawn('ruby', '-e', 'exit 13') # => 309581
1479 * Process.wait2(pid)
1480 * # => [309581, #<Process::Status: pid 309581 exit 13>]
1482 * Process.waitpid2 is an alias for Process.wait2.
1485 static VALUE
1486 proc_wait2(int argc, VALUE *argv, VALUE _)
1488 VALUE pid = proc_wait(argc, argv);
1489 if (NIL_P(pid)) return Qnil;
1490 return rb_assoc_new(pid, rb_last_status_get());
1495 * call-seq:
1496 * Process.waitall -> array
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:
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>]]
1509 static VALUE
1510 proc_waitall(VALUE _)
1512 VALUE result;
1513 rb_pid_t pid;
1514 int status;
1516 result = rb_ary_new();
1517 rb_last_status_clear();
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);
1527 rb_ary_push(result, rb_assoc_new(PIDT2NUM(pid), rb_last_status_get()));
1529 return result;
1532 static VALUE rb_cWaiter;
1534 static VALUE
1535 detach_process_pid(VALUE thread)
1537 return rb_thread_local_aref(thread, id_pid);
1540 static VALUE
1541 detach_process_watcher(void *arg)
1543 rb_pid_t cpid, pid = (rb_pid_t)(VALUE)arg;
1544 int status;
1546 while ((cpid = rb_waitpid(pid, &status, 0)) == 0) {
1547 /* wait while alive */
1549 return rb_last_status_get();
1552 VALUE
1553 rb_detach_process(rb_pid_t pid)
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;
1563 * call-seq:
1564 * Process.detach(pid) -> thread
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.
1571 * This method is needed only when the parent process will never wait
1572 * for the child process.
1574 * This example does not reap the second child process;
1575 * that process appears as a zombie in the process status (+ps+) output:
1577 * pid = Process.spawn('ruby', '-e', 'exit 13') # => 312691
1578 * sleep(1)
1579 * # Find zombies.
1580 * system("ps -ho pid,state -p #{pid}")
1582 * Output:
1584 * 312716 Z
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:
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.
1595 * The waiting thread can return the pid of the detached child process:
1597 * thread.join.pid # => 313262
1601 static VALUE
1602 proc_detach(VALUE obj, VALUE pid)
1604 return rb_detach_process(NUM2PIDT(pid));
1607 /* This function should be async-signal-safe. Actually it is. */
1608 static void
1609 before_exec_async_signal_safe(void)
1613 static void
1614 before_exec_non_async_signal_safe(void)
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.
1623 * Nowadays, we always stop the timer thread completely to allow redirects.
1625 rb_thread_stop_timer_thread();
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
1633 static int
1634 set_blocking(int fd)
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 */
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);
1647 return 0;
1648 #endif
1651 static void
1652 stdfd_clear_nonblock(void)
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 */
1661 static void
1662 before_exec(void)
1664 before_exec_non_async_signal_safe();
1665 before_exec_async_signal_safe();
1668 static void
1669 after_exec(void)
1671 rb_thread_reset_timer_thread();
1672 rb_thread_start_timer_thread();
1675 #if defined HAVE_WORKING_FORK || defined HAVE_DAEMON
1676 static void
1677 before_fork_ruby(void)
1679 before_exec();
1682 static void
1683 after_fork_ruby(rb_pid_t pid)
1685 if (pid == 0) {
1686 // child
1687 clear_pid_cache();
1688 rb_thread_atfork();
1690 else {
1691 // parent
1692 after_exec();
1695 #endif
1697 #if defined(HAVE_WORKING_FORK)
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)
1706 return fork();
1708 COMPILER_WARNING_POP
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)
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) */
1723 #else
1724 #define try_with_sh(err, prog, argv, envp) (void)0
1725 #endif
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)
1731 char **argv;
1732 #ifndef _WIN32
1733 char **envp;
1734 int err;
1735 #endif
1737 argv = ARGVSTR2ARGV(argv_str);
1739 if (!prog) {
1740 return ENOENT;
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
1758 /* This function should be async-signal-safe. Actually it is. */
1759 static int
1760 proc_exec_sh(const char *str, VALUE envp_str)
1762 const char *s;
1764 s = str;
1765 while (*s == ' ' || *s == '\t' || *s == '\n')
1766 s++;
1768 if (!*s) {
1769 return ENOENT;
1772 #ifdef _WIN32
1773 rb_w32_uspawn(P_OVERLAY, (char *)str, 0);
1774 #elif defined(__CYGWIN32__)
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);
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;
1796 rb_proc_exec(const char *str)
1798 int ret;
1799 before_exec();
1800 ret = proc_exec_sh(str, Qfalse);
1801 after_exec();
1802 errno = ret;
1803 return -1;
1806 static void
1807 mark_exec_arg(void *ptr)
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);
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);
1832 static size_t
1833 memsize_exec_arg(const void *ptr)
1835 return sizeof(struct rb_execarg);
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
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)
1853 VALUE newstr = EXPORT_STR(str);
1854 if (newstr == str) newstr = rb_str_dup(str);
1855 return newstr;
1857 #else
1858 # define EXPORT_STR(str) (str)
1859 # define EXPORT_DUP(str) rb_str_dup(str)
1860 #endif
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
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)
1878 char fbuf[MAXPATHLEN];
1879 rb_pid_t status;
1881 if (!prog)
1882 prog = argv[0];
1883 prog = dln_find_exe_r(prog, 0, fbuf, sizeof(fbuf));
1884 if (!prog)
1885 return -1;
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;
1896 return status;
1898 #endif
1900 static rb_pid_t
1901 proc_spawn_cmd(char **argv, VALUE prog, struct rb_execarg *eargp)
1903 rb_pid_t pid = -1;
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;
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
1916 return pid;
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)
1925 char fbuf[MAXPATHLEN];
1926 rb_pid_t status;
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;
1934 #endif
1935 #endif
1937 static VALUE
1938 hide_obj(VALUE obj)
1940 RBASIC_CLEAR_CLASS(obj);
1941 return obj;
1944 static VALUE
1945 check_exec_redirect_fd(VALUE v, int iskey)
1947 VALUE tmp;
1948 int fd;
1949 if (FIXNUM_P(v)) {
1950 fd = FIX2INT(v);
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;
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;
1970 else {
1971 goto wrong;
1973 if (fd < 0) {
1974 rb_raise(rb_eArgError, "negative file descriptor");
1976 #ifdef _WIN32
1977 else if (fd >= 3 && iskey) {
1978 rb_raise(rb_eArgError, "wrong file descriptor (%d)", fd);
1980 #endif
1981 return INT2FIX(fd);
1983 wrong:
1984 rb_raise(rb_eArgError, "wrong exec redirect");
1985 UNREACHABLE_RETURN(Qundef);
1988 static VALUE
1989 check_exec_redirect1(VALUE ary, VALUE key, VALUE param)
1991 if (ary == Qfalse) {
1992 ary = hide_obj(rb_ary_new());
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)));
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)));
2006 return ary;
2009 static void
2010 check_exec_redirect(VALUE key, VALUE val, struct rb_execarg *eargp)
2012 VALUE param;
2013 VALUE path, flags, perm;
2014 VALUE tmp;
2015 ID id;
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);
2024 else if (id == id_in) {
2025 param = INT2FIX(0);
2026 eargp->fd_dup2 = check_exec_redirect1(eargp->fd_dup2, key, param);
2028 else if (id == id_out) {
2029 param = INT2FIX(1);
2030 eargp->fd_dup2 = check_exec_redirect1(eargp->fd_dup2, key, param);
2032 else if (id == id_err) {
2033 param = INT2FIX(2);
2034 eargp->fd_dup2 = check_exec_redirect1(eargp->fd_dup2, key, param);
2036 else {
2037 rb_raise(rb_eArgError, "wrong exec redirect symbol: %"PRIsVALUE,
2038 val);
2040 break;
2042 case T_FILE:
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;
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);
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);
2073 break;
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;
2089 if (i == RARRAY_LEN(key))
2090 flags = INT2NUM(O_WRONLY|O_CREAT|O_TRUNC);
2091 else
2092 flags = INT2NUM(O_RDONLY);
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;
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");
2111 #if defined(HAVE_SETRLIMIT) && defined(NUM2RLIM)
2112 static int rlimit_type_by_sym(VALUE key);
2114 static void
2115 rb_execarg_addopt_rlimit(struct rb_execarg *eargp, int rtype, VALUE val)
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));
2131 else {
2132 rb_raise(rb_eArgError, "wrong exec rlimit option");
2135 else {
2136 softlim = hardlim = rb_to_int(val);
2138 tmp = hide_obj(rb_ary_new3(3, INT2NUM(rtype), softlim, hardlim));
2139 rb_ary_push(ary, tmp);
2141 #endif
2143 #define TO_BOOL(val, name) (NIL_P(val) ? 0 : rb_bool_expected((val), name, TRUE))
2145 rb_execarg_addopt(VALUE execarg_obj, VALUE key, VALUE val)
2147 struct rb_execarg *eargp = rb_execarg_get(execarg_obj);
2149 ID id;
2151 switch (TYPE(key)) {
2152 case T_SYMBOL:
2153 #if defined(HAVE_SETRLIMIT) && defined(NUM2RLIM)
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;
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");
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);
2180 eargp->pgroup_given = 1;
2181 eargp->pgroup_pgid = pgroup;
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");
2190 eargp->new_pgroup_given = 1;
2191 eargp->new_pgroup_flag = TO_BOOL(val, "new_pgroup");
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");
2199 eargp->unsetenv_others_given = 1;
2200 eargp->unsetenv_others_do = TO_BOOL(val, "unsetenv_others");
2202 else if (id == id_chdir) {
2203 if (eargp->chdir_given) {
2204 rb_raise(rb_eArgError, "chdir option specified twice");
2206 FilePathValue(val);
2207 val = rb_str_encode_ospath(val);
2208 eargp->chdir_given = 1;
2209 eargp->chdir_dir = hide_obj(EXPORT_DUP(val));
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");
2216 eargp->umask_given = 1;
2217 eargp->umask_mask = cmask;
2219 else if (id == id_close_others) {
2220 if (eargp->close_others_given) {
2221 rb_raise(rb_eArgError, "close_others option specified twice");
2223 eargp->close_others_given = 1;
2224 eargp->close_others_do = TO_BOOL(val, "close_others");
2226 else if (id == id_in) {
2227 key = INT2FIX(0);
2228 goto redirect;
2230 else if (id == id_out) {
2231 key = INT2FIX(1);
2232 goto redirect;
2234 else if (id == id_err) {
2235 key = INT2FIX(2);
2236 goto redirect;
2238 else if (id == id_uid) {
2239 #ifdef HAVE_SETUID
2240 if (eargp->uid_given) {
2241 rb_raise(rb_eArgError, "uid option specified twice");
2243 check_uid_switch();
2245 eargp->uid = OBJ2UID(val);
2246 eargp->uid_given = 1;
2248 #else
2249 rb_raise(rb_eNotImpError,
2250 "uid option is unimplemented on this machine");
2251 #endif
2253 else if (id == id_gid) {
2254 #ifdef HAVE_SETGID
2255 if (eargp->gid_given) {
2256 rb_raise(rb_eArgError, "gid option specified twice");
2258 check_gid_switch();
2260 eargp->gid = OBJ2GID(val);
2261 eargp->gid_given = 1;
2263 #else
2264 rb_raise(rb_eNotImpError,
2265 "gid option is unimplemented on this machine");
2266 #endif
2268 else if (id == id_exception) {
2269 if (eargp->exception_given) {
2270 rb_raise(rb_eArgError, "exception option specified twice");
2272 eargp->exception_given = 1;
2273 eargp->exception = TO_BOOL(val, "exception");
2275 else {
2276 return ST_STOP;
2278 break;
2280 case T_FIXNUM:
2281 case T_FILE:
2282 case T_ARRAY:
2283 redirect:
2284 check_exec_redirect(key, val, eargp);
2285 break;
2287 default:
2288 return ST_STOP;
2291 RB_GC_GUARD(execarg_obj);
2292 return ST_CONTINUE;
2295 static int
2296 check_exec_options_i(st_data_t st_key, st_data_t st_val, st_data_t arg)
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");
2307 return ST_CONTINUE;
2310 static int
2311 check_exec_options_i_extract(st_data_t st_key, st_data_t st_val, st_data_t arg)
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);
2322 return ST_CONTINUE;
2325 static int
2326 check_exec_fds_1(struct rb_execarg *eargp, VALUE h, int maxhint, VALUE ary)
2328 long i;
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);
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;
2352 return maxhint;
2355 static VALUE
2356 check_exec_fds(struct rb_execarg *eargp)
2358 VALUE h = rb_hash_new();
2359 VALUE ary;
2360 int maxhint = -1;
2361 long i;
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);
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++;
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;
2398 eargp->close_others_maxhint = maxhint;
2399 return h;
2402 static void
2403 rb_check_exec_options(VALUE opthash, VALUE execarg_obj)
2405 if (RHASH_EMPTY_P(opthash))
2406 return;
2407 rb_hash_stlike_foreach(opthash, check_exec_options_i, (st_data_t)execarg_obj);
2410 VALUE
2411 rb_execarg_extract_options(VALUE execarg_obj, VALUE opthash)
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];
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
2428 static int
2429 check_exec_env_i(st_data_t st_key, st_data_t st_val, st_data_t arg)
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;
2437 k = StringValueCStr(key);
2438 if (strchr(k, '='))
2439 rb_raise(rb_eArgError, "environment name contains a equal : %"PRIsVALUE, key);
2441 if (!NIL_P(val))
2442 StringValueCStr(val);
2444 key = EXPORT_STR(key);
2445 if (!NIL_P(val)) val = EXPORT_STR(val);
2447 if (ENVMATCH(k, PATH_ENV)) {
2448 *path = val;
2450 rb_ary_push(env, hide_obj(rb_assoc_new(key, val)));
2452 return ST_CONTINUE;
2455 static VALUE
2456 rb_check_exec_env(VALUE hash, VALUE *path)
2458 VALUE env[2];
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];
2465 return env[0];
2468 static VALUE
2469 rb_check_argv(int argc, VALUE *argv)
2471 VALUE tmp, prog;
2472 int i;
2474 rb_check_arity(argc, 1, UNLIMITED_ARGUMENTS);
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");
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);
2488 for (i = 0; i < argc; i++) {
2489 StringValue(argv[i]);
2490 argv[i] = rb_str_new_frozen(argv[i]);
2491 StringValueCStr(argv[i]);
2493 return prog;
2496 static VALUE
2497 check_hash(VALUE obj)
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;
2507 return rb_check_hash_type(obj);
2510 static VALUE
2511 rb_exec_getargs(int *argc_p, VALUE **argv_p, int accept_shell, VALUE *env_ret, VALUE *opthash_ret)
2513 VALUE hash, prog;
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)--;
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)++;
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;
2539 return prog;
2542 #ifndef _WIN32
2543 struct string_part {
2544 const char *ptr;
2545 size_t len;
2548 static int
2549 compare_posix_sh(const void *key, const void *el)
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;
2556 #endif
2558 static void
2559 rb_exec_fillarg(VALUE prog, int argc, VALUE *argv, VALUE env, VALUE opthash, VALUE execarg_obj)
2561 struct rb_execarg *eargp = rb_execarg_get(execarg_obj);
2562 char fbuf[MAXPATHLEN];
2564 MEMZERO(eargp, struct rb_execarg, 1);
2566 if (!NIL_P(opthash)) {
2567 rb_check_exec_options(opthash, execarg_obj);
2569 if (!NIL_P(env)) {
2570 env = rb_check_exec_env(env, &eargp->path_env);
2571 eargp->env_modification = env;
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;
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 */
2614 const char *p;
2615 struct string_part first = {0, 0};
2616 int has_meta = 0;
2618 * meta characters:
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
2637 * # Comment
2638 * = Assignment preceding command name
2639 * % (used in Parameter Expansion)
2641 for (p = RSTRING_PTR(prog); *p; p++) {
2642 if (*p == ' ' || *p == '\t') {
2643 if (first.ptr && !first.len) first.len = p - first.ptr;
2645 else {
2646 if (!first.ptr) first.ptr = p;
2648 if (!has_meta && strchr("*?{}[]<>()~&|\\$;'`\"\n#", *p))
2649 has_meta = 1;
2650 if (!first.len) {
2651 if (*p == '=') {
2652 has_meta = 1;
2654 else if (*p == '/') {
2655 first.len = 0x100; /* longer than any posix_sh_cmds */
2658 if (has_meta)
2659 break;
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;
2667 if (!has_meta) {
2668 /* avoid shell since no shell meta character found. */
2669 eargp->use_shell = 0;
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' */
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);
2692 #endif
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;
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' */
2720 eargp->invoke.cmd.argv_buf = argv_buf;
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;
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);
2738 RB_GC_GUARD(execarg_obj);
2741 struct rb_execarg *
2742 rb_execarg_get(VALUE execarg_obj)
2744 struct rb_execarg *eargp;
2745 TypedData_Get_Struct(execarg_obj, struct rb_execarg, &exec_arg_data_type, eargp);
2746 return eargp;
2749 static VALUE
2750 rb_execarg_init(int argc, const VALUE *orig_argv, int accept_shell, VALUE execarg_obj)
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;
2766 VALUE
2767 rb_execarg_new(int argc, const VALUE *argv, int accept_shell, int allow_exc_opt)
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");
2776 return execarg_obj;
2779 void
2780 rb_execarg_setenv(VALUE execarg_obj, VALUE env)
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);
2788 static int
2789 fill_envp_buf_i(st_data_t st_key, st_data_t st_val, st_data_t arg)
2791 VALUE key = (VALUE)st_key;
2792 VALUE val = (VALUE)st_val;
2793 VALUE envp_buf = (VALUE)arg;
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' */
2800 return ST_CONTINUE;
2804 static long run_exec_dup2_tmpbuf_size(long n);
2806 struct open_struct {
2807 VALUE fname;
2808 int oflags;
2809 mode_t perm;
2810 int ret;
2811 int err;
2814 static void *
2815 open_func(void *ptr)
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;
2824 static void
2825 rb_execarg_allocate_dup2_tmpbuf(struct rb_execarg *eargp, long len)
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;
2832 static VALUE
2833 rb_execarg_parent_start1(VALUE execarg_obj)
2835 struct rb_execarg *eargp = rb_execarg_get(execarg_obj);
2836 int unsetenv_others;
2837 VALUE envopts;
2838 VALUE ary;
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) {
2863 rb_thread_check_ints();
2864 goto again;
2866 rb_syserr_fail_str(open_data.err, vpath);
2868 fd2 = open_data.ret;
2869 rb_update_max_fd(fd2);
2870 RARRAY_ASET(param, 3, INT2FIX(fd2));
2871 rb_thread_check_ints();
2873 else {
2874 fd2 = NUM2INT(fd2v);
2876 rb_execarg_addopt(execarg_obj, INT2FIX(fd), INT2FIX(fd2));
2880 eargp->redirect_fds = check_exec_fds(eargp);
2882 ary = eargp->fd_dup2;
2883 if (ary != Qfalse) {
2884 rb_execarg_allocate_dup2_tmpbuf(eargp, RARRAY_LEN(ary));
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();
2895 else {
2896 envtbl = rb_env_to_hash();
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);
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);
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;
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;
2935 char **tmp_envp = (char **)RSTRING_PTR(envp_str);
2936 while (*tmp_envp) {
2937 printf("%s\n", *tmp_envp);
2938 tmp_envp++;
2943 RB_GC_GUARD(execarg_obj);
2944 return Qnil;
2947 void
2948 rb_execarg_parent_start(VALUE execarg_obj)
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);
2958 static VALUE
2959 execarg_parent_end(VALUE execarg_obj)
2961 struct rb_execarg *eargp = rb_execarg_get(execarg_obj);
2962 int err = errno;
2963 VALUE ary;
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);
2982 errno = err;
2983 RB_GC_GUARD(execarg_obj);
2984 return execarg_obj;
2987 void
2988 rb_execarg_parent_end(VALUE execarg_obj)
2990 execarg_parent_end(execarg_obj);
2991 RB_GC_GUARD(execarg_obj);
2994 static void
2995 rb_exec_fail(struct rb_execarg *eargp, int err, const char *errmsg)
2997 if (!errmsg || !*errmsg) return;
2998 if (strcmp(errmsg, "chdir") == 0) {
2999 rb_sys_fail_str(eargp->chdir_dir);
3001 rb_sys_fail(errmsg);
3004 #if 0
3005 void
3006 rb_execarg_fail(VALUE execarg_obj, int err, const char *errmsg)
3008 if (!errmsg || !*errmsg) return;
3009 rb_exec_fail(rb_execarg_get(execarg_obj), err, errmsg);
3010 RB_GC_GUARD(execarg_obj);
3012 #endif
3014 VALUE
3015 rb_f_exec(int argc, const VALUE *argv)
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;
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 */
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);
3034 fail_str = eargp->use_shell ? eargp->invoke.sh.shell_script : eargp->invoke.cmd.command_name;
3036 err = exec_async_signal_safe(eargp, errmsg, sizeof(errmsg));
3037 after_exec(); /* restart timer thread */
3039 rb_exec_fail(eargp, err, errmsg);
3040 RB_GC_GUARD(execarg_obj);
3041 rb_syserr_fail_str(err, fail_str);
3042 UNREACHABLE_RETURN(Qnil);
3045 NORETURN(static VALUE f_exec(int c, const VALUE *a, VALUE _));
3048 * call-seq:
3049 * exec([env, ] command_line, options = {})
3050 * exec([env, ] exe_path, *args, options = {})
3052 * Replaces the current process by doing one of the following:
3054 * - Passing string +command_line+ to the shell.
3055 * - Invoking the executable at +exe_path+.
3057 * This method has potential security vulnerabilities if called with untrusted input;
3058 * see {Command Injection}[rdoc-ref:command_injection.rdoc].
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).
3065 * Argument +env+, if given, is a hash that affects +ENV+ for the new process;
3066 * see {Execution Environment}[rdoc-ref:Process@Execution+Environment].
3068 * Argument +options+ is a hash of options for the new process;
3069 * see {Execution Options}[rdoc-ref:Process@Execution+Options].
3071 * The first required argument is one of the following:
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.
3078 * <b>Argument +command_line+</b>
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:
3084 * exec('if true; then echo "Foo"; fi') # Shell reserved word.
3085 * exec('exit') # Built-in.
3086 * exec('date > date.tmp') # Contains meta character.
3088 * The command line may also contain arguments and options for the command:
3090 * exec('echo "Foo"')
3092 * Output:
3094 * Foo
3096 * See {Execution Shell}[rdoc-ref:Process@Execution+Shell] for details about the shell.
3098 * Raises an exception if the new process could not execute.
3100 * <b>Argument +exe_path+</b>
3102 * Argument +exe_path+ is one of the following:
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.
3108 * Example:
3110 * exec('/usr/bin/date')
3112 * Output:
3114 * Sat Aug 26 09:38:00 AM CDT 2023
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.
3120 * exec('doesnt_exist') # Raises Errno::ENOENT
3122 * If one or more +args+ is given, each is an argument or option
3123 * to be passed to the executable:
3125 * exec('echo', 'C*')
3126 * exec('echo', 'hello', 'world')
3128 * Output:
3130 * C*
3131 * hello world
3133 * Raises an exception if the new process could not execute.
3136 static VALUE
3137 f_exec(int c, const VALUE *a, VALUE _)
3139 rb_f_exec(c, a);
3140 UNREACHABLE_RETURN(Qnil);
3143 #define ERRMSG(str) \
3144 ((errmsg && 0 < errmsg_buflen) ? \
3145 (void)strlcpy(errmsg, (str), errmsg_buflen) : (void)0)
3147 #define ERRMSG_FMT(...) \
3148 ((errmsg && 0 < errmsg_buflen) ? \
3149 (void)snprintf(errmsg, errmsg_buflen, __VA_ARGS__) : (void)0)
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);
3155 static int
3156 save_redirect_fd(int fd, struct rb_execarg *sargp, char *errmsg, size_t errmsg_buflen)
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;
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;
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);
3178 newary = sargp->fd_close;
3179 if (newary == Qfalse) {
3180 newary = hide_obj(rb_ary_new());
3181 sargp->fd_close = newary;
3183 rb_ary_push(newary, hide_obj(rb_assoc_new(INT2FIX(save_fd), Qnil)));
3186 return 0;
3189 static int
3190 intcmp(const void *a, const void *b)
3192 return *(int*)a - *(int*)b;
3195 static int
3196 intrcmp(const void *a, const void *b)
3198 return *(int*)b - *(int*)a;
3201 struct run_exec_dup2_fd_pair {
3202 int oldfd;
3203 int newfd;
3204 long older_index;
3205 long num_newer;
3206 int cloexec;
3209 static long
3210 run_exec_dup2_tmpbuf_size(long n)
3212 return sizeof(struct run_exec_dup2_fd_pair) * n;
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)
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;
3226 if (ret & FD_CLOEXEC) return 1;
3227 #endif
3228 return 0;
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)
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;
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;
3250 #endif
3251 return 0;
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)
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;
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;
3273 #endif
3274 return 0;
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)
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;
3287 n = RARRAY_LEN(ary);
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;
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);
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++;
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;
3333 if (pairs[j].cloexec &&
3334 fd_set_cloexec(pairs[j].newfd, errmsg, errmsg_buflen)) {
3335 goto fail;
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--;
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;
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;
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;
3369 rb_update_max_fd(extra_fd);
3371 else {
3372 ret = redirect_dup2(pairs[i].oldfd, extra_fd); /* async-signal-safe */
3373 if (ret == -1) {
3374 ERRMSG("dup2");
3375 goto fail;
3377 rb_update_max_fd(extra_fd);
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;
3388 rb_update_max_fd(ret);
3389 pairs[j].oldfd = -1;
3390 j = pairs[j].older_index;
3393 if (extra_fd != -1) {
3394 ret = redirect_close(extra_fd); /* async-signal-safe */
3395 if (ret == -1) {
3396 ERRMSG("close");
3397 goto fail;
3401 return 0;
3403 fail:
3404 return -1;
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)
3411 long i;
3412 int ret;
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;
3423 return 0;
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)
3430 long i;
3431 int ret;
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));
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;
3445 rb_update_max_fd(newfd);
3447 return 0;
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)
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?)
3462 int ret;
3463 rb_pid_t pgroup;
3465 pgroup = eargp->pgroup_pgid;
3466 if (pgroup == -1)
3467 return 0;
3469 if (sargp) {
3470 /* maybe meaningless with no fork environment... */
3471 sargp->pgroup_given = 1;
3472 sargp->pgroup_pgid = getpgrp();
3475 if (pgroup == 0) {
3476 pgroup = getpid(); /* async-signal-safe */
3478 ret = setpgid(getpid(), pgroup); /* async-signal-safe */
3479 if (ret == -1) ERRMSG("setpgid");
3480 return ret;
3482 #endif
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)
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;
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);
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;
3516 return 0;
3518 #endif
3520 #if !defined(HAVE_WORKING_FORK)
3521 static VALUE
3522 save_env_i(RB_BLOCK_CALL_FUNC_ARGLIST(i, ary))
3524 rb_ary_push(ary, hide_obj(rb_ary_dup(argv[0])));
3525 return Qnil;
3528 static void
3529 save_env(struct rb_execarg *sargp)
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;
3541 sargp->unsetenv_others_given = 1;
3542 sargp->unsetenv_others_do = 1;
3545 #endif
3547 #ifdef _WIN32
3548 #undef chdir
3549 #define chdir(p) rb_w32_uchdir(p)
3550 #endif
3552 /* This function should be async-signal-safe when sargp is NULL. Hopefully it is. */
3554 rb_execarg_run_options(const struct rb_execarg *eargp, struct rb_execarg *sargp, char *errmsg, size_t errmsg_buflen)
3556 VALUE obj;
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;
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;
3569 #endif
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;
3577 #endif
3579 #if !defined(HAVE_WORKING_FORK)
3580 if (eargp->unsetenv_others_given && eargp->unsetenv_others_do) {
3581 save_env(sargp);
3582 rb_env_clear();
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
3596 ruby_setenv(StringValueCStr(key), StringValueCStr(val));
3599 #endif
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;
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;
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;
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 */
3630 #endif
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;
3638 if (eargp->chdir_given) {
3639 if (sargp) {
3640 sargp->chdir_given = 1;
3641 sargp->chdir_dir = hide_obj(rb_dir_getwd_ospath());
3643 if (chdir(RSTRING_PTR(eargp->chdir_dir)) == -1) { /* async-signal-safe */
3644 ERRMSG("chdir");
3645 return -1;
3649 #ifdef HAVE_SETGID
3650 if (eargp->gid_given) {
3651 if (setgid(eargp->gid) < 0) {
3652 ERRMSG("setgid");
3653 return -1;
3656 #endif
3657 #ifdef HAVE_SETUID
3658 if (eargp->uid_given) {
3659 if (setuid(eargp->uid) < 0) {
3660 ERRMSG("setuid");
3661 return -1;
3664 #endif
3666 if (sargp) {
3667 VALUE ary = sargp->fd_dup2;
3668 if (ary != Qfalse) {
3669 rb_execarg_allocate_dup2_tmpbuf(sargp, RARRAY_LEN(ary));
3673 int preserve = errno;
3674 stdfd_clear_nonblock();
3675 errno = preserve;
3678 return 0;
3681 /* This function should be async-signal-safe. Hopefully it is. */
3683 rb_exec_async_signal_safe(const struct rb_execarg *eargp, char *errmsg, size_t errmsg_buflen)
3685 errno = exec_async_signal_safe(eargp, errmsg, errmsg_buflen);
3686 return -1;
3689 static int
3690 exec_async_signal_safe(const struct rb_execarg *eargp, char *errmsg, size_t errmsg_buflen)
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;
3699 if (rb_execarg_run_options(eargp, sargp, errmsg, errmsg_buflen) < 0) { /* hopefully async-signal-safe */
3700 return errno;
3703 if (eargp->use_shell) {
3704 err = proc_exec_sh(RSTRING_PTR(eargp->invoke.sh.shell_script), eargp->envp_str); /* async-signal-safe */
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 */
3712 #if !defined(HAVE_WORKING_FORK)
3713 rb_execarg_run_options(sargp, NULL, errmsg, errmsg_buflen);
3714 #endif
3716 return err;
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)
3724 return rb_exec_async_signal_safe(arg, errmsg, errmsg_buflen); /* hopefully async-signal-safe */
3727 static VALUE
3728 proc_syswait(VALUE pid)
3730 rb_syswait((rb_pid_t)pid);
3731 return Qnil;
3734 static int
3735 move_fds_to_avoid_crash(int *fdp, int n, VALUE fds)
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;
3754 return 0;
3757 static int
3758 pipe_nocrash(int filedes[2], VALUE fds)
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;
3771 errno = save;
3773 return ret;
3776 #ifndef O_BINARY
3777 #define O_BINARY 0
3778 #endif
3780 static VALUE
3781 rb_thread_sleep_that_takes_VALUE_as_sole_argument(VALUE n)
3783 rb_thread_sleep(NUM2INT(n));
3784 return Qundef;
3787 static int
3788 handle_fork_error(int err, struct rb_process_status *status, int *ep, volatile int *try_gc_p)
3790 int state = 0;
3792 switch (err) {
3793 case ENOMEM:
3794 if ((*try_gc_p)-- > 0 && !rb_during_gc()) {
3795 rb_gc();
3796 return 0;
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;
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;
3812 break;
3814 if (ep) {
3815 close(ep[0]);
3816 close(ep[1]);
3817 errno = err;
3819 if (state && !status) rb_jump_tag(state);
3820 return -1;
3823 #define prefork() ( \
3824 rb_io_flush(rb_stdout), \
3825 rb_io_flush(rb_stderr) \
3829 * Forks child process, and returns the process ID in the parent
3830 * process.
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.
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.
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.
3848 * If fds is not Qnil, internal pipe for the errno propagation is
3849 * arranged to avoid conflicts of the hash keys in +fds+.
3851 * +chfunc+ must not raise any exceptions.
3854 static ssize_t
3855 write_retry(int fd, const void *buf, size_t len)
3857 ssize_t w;
3859 do {
3860 w = write(fd, buf, len);
3861 } while (w < 0 && errno == EINTR);
3863 return w;
3866 static ssize_t
3867 read_retry(int fd, void *buf, size_t len)
3869 ssize_t r;
3871 if (set_blocking(fd) != 0) {
3872 #ifndef _WIN32
3873 rb_async_bug_errno("set_blocking failed reading child error", errno);
3874 #endif
3877 do {
3878 r = read(fd, buf, len);
3879 } while (r < 0 && errno == EINTR);
3881 return r;
3884 static void
3885 send_child_error(int fd, char *errmsg, size_t errmsg_buflen)
3887 int err;
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;
3899 static int
3900 recv_child_error(int fd, int *errp, char *errmsg, size_t errmsg_buflen)
3902 int err;
3903 ssize_t size;
3904 if ((size = read_retry(fd, &err, sizeof(err))) < 0) {
3905 err = errno;
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';
3915 close(fd);
3916 return size != 0;
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)
3925 rb_uid_t ret;
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;
3935 #define HAVE_GETRESUID
3936 #endif
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)
3943 rb_gid_t ret;
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;
3953 #define HAVE_GETRESGID
3954 #endif
3956 static int
3957 has_privilege(void)
3960 * has_privilege() is used to choose vfork() or fork().
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.
3971 rb_uid_t ruid, euid;
3972 rb_gid_t rgid, egid;
3974 #if defined HAVE_ISSETUGID
3975 if (issetugid())
3976 return 1;
3977 #endif
3979 #ifdef HAVE_GETRESUID
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;
3989 #else
3990 ruid = getuid();
3991 euid = geteuid();
3992 #endif
3994 if (euid == 0 || euid != ruid)
3995 return 1;
3997 #ifdef HAVE_GETRESGID
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;
4007 #else
4008 rgid = getgid();
4009 egid = getegid();
4010 #endif
4012 if (egid != rgid)
4013 return 1;
4015 return 0;
4017 #endif
4019 struct child_handler_disabler_state
4021 sigset_t sigmask;
4024 static void
4025 disable_child_handler_before_fork(struct child_handler_disabler_state *old)
4027 #ifdef HAVE_PTHREAD_SIGMASK
4028 int ret;
4029 sigset_t all;
4031 ret = sigfillset(&all);
4032 if (ret == -1)
4033 rb_sys_fail("sigfillset");
4035 ret = pthread_sigmask(SIG_SETMASK, &all, &old->sigmask); /* not async-signal-safe */
4036 if (ret != 0) {
4037 rb_syserr_fail(ret, "pthread_sigmask");
4039 #else
4040 # pragma GCC warning "pthread_sigmask on fork is not available. potentially dangerous"
4041 #endif
4044 static void
4045 disable_child_handler_fork_parent(struct child_handler_disabler_state *old)
4047 #ifdef HAVE_PTHREAD_SIGMASK
4048 int ret;
4050 ret = pthread_sigmask(SIG_SETMASK, &old->sigmask, NULL); /* not async-signal-safe */
4051 if (ret != 0) {
4052 rb_syserr_fail(ret, "pthread_sigmask");
4054 #else
4055 # pragma GCC warning "pthread_sigmask on fork is not available. potentially dangerous"
4056 #endif
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)
4063 int sig;
4064 int ret;
4066 for (sig = 1; sig < NSIG; sig++) {
4067 sig_t handler = signal(sig, SIG_DFL);
4069 if (handler == SIG_ERR && errno == EINVAL) {
4070 continue; /* Ignore invalid signal number */
4072 if (handler == SIG_ERR) {
4073 ERRMSG("signal to obtain old action");
4074 return -1;
4076 #ifdef SIGPIPE
4077 if (sig == SIGPIPE) {
4078 continue;
4080 #endif
4081 /* it will be reset to SIG_DFL at execve time, instead */
4082 if (handler == SIG_IGN) {
4083 signal(sig, SIG_IGN);
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;
4094 return 0;
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)
4103 rb_pid_t pid;
4104 volatile int try_gc = 1;
4105 struct child_handler_disabler_state old;
4106 int err;
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);
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
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;
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)
4149 rb_pid_t pid;
4150 int err;
4151 int ep[2];
4152 int error_occurred;
4154 struct waitpid_state *w = eargp && eargp->waitpid_state ? eargp->waitpid_state : 0;
4156 if (status) status->status = 0;
4158 if (pipe_nocrash(ep, fds)) return -1;
4160 pid = retry_fork_async_signal_safe(status, ep, chfunc, charg, errmsg, errmsg_buflen, w);
4162 if (status) status->pid = pid;
4164 if (pid < 0) {
4165 if (status) status->error = errno;
4167 return pid;
4170 close(ep[1]);
4172 error_occurred = recv_child_error(ep[0], &err, errmsg, errmsg_buflen);
4174 if (error_occurred) {
4175 if (status) {
4176 int state = 0;
4177 status->error = err;
4179 VM_ASSERT((w == 0) && "only used by extensions");
4180 rb_protect(proc_syswait, (VALUE)pid, &state);
4182 status->status = state;
4184 else if (!w) {
4185 rb_syswait(pid);
4188 errno = err;
4189 return -1;
4192 return pid;
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
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)
4207 struct rb_process_status process_status;
4209 rb_pid_t result = fork_check_err(&process_status, chfunc, charg, fds, errmsg, errmsg_buflen, 0);
4211 if (status) {
4212 *status = process_status.status;
4215 return result;
4218 static rb_pid_t
4219 rb_fork_ruby2(struct rb_process_status *status)
4221 rb_pid_t pid;
4222 int try_gc = 1, err;
4223 struct child_handler_disabler_state old;
4225 if (status) status->status = 0;
4227 while (1) {
4228 prefork();
4230 before_fork_ruby();
4231 disable_child_handler_before_fork(&old);
4233 pid = rb_fork();
4234 err = errno;
4235 if (status) {
4236 status->pid = pid;
4237 status->error = err;
4240 disable_child_handler_fork_parent(&old); /* yes, bad name */
4241 after_fork_ruby(pid);
4243 if (pid >= 0) { /* fork succeed */
4244 return pid;
4247 /* fork failed */
4248 if (handle_fork_error(err, status, NULL, &try_gc)) {
4249 return -1;
4254 rb_pid_t
4255 rb_fork_ruby(int *status)
4257 struct rb_process_status process_status = {0};
4259 rb_pid_t pid = rb_fork_ruby2(&process_status);
4261 if (status) *status = process_status.status;
4263 return pid;
4266 static rb_pid_t
4267 proc_fork_pid(void)
4269 rb_pid_t pid = rb_fork_ruby(NULL);
4271 if (pid == -1) {
4272 rb_sys_fail("fork(2)");
4275 return pid;
4278 rb_pid_t
4279 rb_call_proc__fork(void)
4281 ID id__fork;
4282 CONST_ID(id__fork, "_fork");
4283 if (rb_method_basic_definition_p(CLASS_OF(rb_mProcess), id__fork)) {
4284 return proc_fork_pid();
4286 else {
4287 VALUE pid = rb_funcall(rb_mProcess, id__fork, 0);
4288 return NUM2PIDT(pid);
4291 #endif
4293 #if defined(HAVE_WORKING_FORK) && !defined(CANNOT_FORK_WITH_PTHREAD)
4295 * call-seq:
4296 * Process._fork -> integer
4298 * An internal API for fork. Do not call this method directly.
4299 * Currently, this is called via Kernel#fork, Process.fork, and
4300 * IO.popen with <tt>"-"</tt>.
4302 * This method is not for casual code but for application monitoring
4303 * libraries. You can add custom code before and after fork events
4304 * by overriding this method.
4306 * Note: Process.daemon may be implemented using fork(2) BUT does not go
4307 * through this method.
4308 * Thus, depending on your reason to hook into this method, you
4309 * may also want to hook into that one.
4310 * See {this issue}[https://bugs.ruby-lang.org/issues/18911] for a
4311 * more detailed discussion of this.
4313 VALUE
4314 rb_proc__fork(VALUE _obj)
4316 rb_pid_t pid = proc_fork_pid();
4317 return PIDT2NUM(pid);
4321 * call-seq:
4322 * Process.fork { ... } -> integer or nil
4323 * Process.fork -> integer or nil
4325 * Creates a child process.
4327 * With a block given, runs the block in the child process;
4328 * on block exit, the child terminates with a status of zero:
4330 * puts "Before the fork: #{Process.pid}"
4331 * fork do
4332 * puts "In the child process: #{Process.pid}"
4333 * end # => 382141
4334 * puts "After the fork: #{Process.pid}"
4336 * Output:
4338 * Before the fork: 420496
4339 * After the fork: 420496
4340 * In the child process: 420520
4342 * With no block given, the +fork+ call returns twice:
4344 * - Once in the parent process, returning the pid of the child process.
4345 * - Once in the child process, returning +nil+.
4347 * Example:
4349 * puts "This is the first line before the fork (pid #{Process.pid})"
4350 * puts fork
4351 * puts "This is the second line after the fork (pid #{Process.pid})"
4353 * Output:
4355 * This is the first line before the fork (pid 420199)
4356 * 420223
4357 * This is the second line after the fork (pid 420199)
4359 * This is the second line after the fork (pid 420223)
4361 * In either case, the child process may exit using
4362 * Kernel.exit! to avoid the call to Kernel#at_exit.
4364 * To avoid zombie processes, the parent process should call either:
4366 * - Process.wait, to collect the termination statuses of its children.
4367 * - Process.detach, to register disinterest in their status.
4369 * The thread calling +fork+ is the only thread in the created child process;
4370 * +fork+ doesn't copy other threads.
4372 * Note that method +fork+ is available on some platforms,
4373 * but not on others:
4375 * Process.respond_to?(:fork) # => true # Would be false on some.
4377 * If not, you may use ::spawn instead of +fork+.
4380 static VALUE
4381 rb_f_fork(VALUE obj)
4383 rb_pid_t pid;
4385 pid = rb_call_proc__fork();
4387 if (pid == 0) {
4388 if (rb_block_given_p()) {
4389 int status;
4390 rb_protect(rb_yield, Qundef, &status);
4391 ruby_stop(status);
4393 return Qnil;
4396 return PIDT2NUM(pid);
4398 #else
4399 #define rb_proc__fork rb_f_notimplement
4400 #define rb_f_fork rb_f_notimplement
4401 #endif
4403 static int
4404 exit_status_code(VALUE status)
4406 int istatus;
4408 switch (status) {
4409 case Qtrue:
4410 istatus = EXIT_SUCCESS;
4411 break;
4412 case Qfalse:
4413 istatus = EXIT_FAILURE;
4414 break;
4415 default:
4416 istatus = NUM2INT(status);
4417 #if EXIT_SUCCESS != 0
4418 if (istatus == 0)
4419 istatus = EXIT_SUCCESS;
4420 #endif
4421 break;
4423 return istatus;
4426 NORETURN(static VALUE rb_f_exit_bang(int argc, VALUE *argv, VALUE obj));
4428 * call-seq:
4429 * exit!(status = false)
4430 * Process.exit!(status = false)
4432 * Exits the process immediately; no exit handlers are called.
4433 * Returns exit status +status+ to the underlying operating system.
4435 * Process.exit!(true)
4437 * Values +true+ and +false+ for argument +status+
4438 * indicate, respectively, success and failure;
4439 * The meanings of integer values are system-dependent.
4443 static VALUE
4444 rb_f_exit_bang(int argc, VALUE *argv, VALUE obj)
4446 int istatus;
4448 if (rb_check_arity(argc, 0, 1) == 1) {
4449 istatus = exit_status_code(argv[0]);
4451 else {
4452 istatus = EXIT_FAILURE;
4454 _exit(istatus);
4456 UNREACHABLE_RETURN(Qnil);
4459 void
4460 rb_exit(int status)
4462 if (GET_EC()->tag) {
4463 VALUE args[2];
4465 args[0] = INT2NUM(status);
4466 args[1] = rb_str_new2("exit");
4467 rb_exc_raise(rb_class_new_instance(2, args, rb_eSystemExit));
4469 ruby_stop(status);
4472 VALUE
4473 rb_f_exit(int argc, const VALUE *argv)
4475 int istatus;
4477 if (rb_check_arity(argc, 0, 1) == 1) {
4478 istatus = exit_status_code(argv[0]);
4480 else {
4481 istatus = EXIT_SUCCESS;
4483 rb_exit(istatus);
4485 UNREACHABLE_RETURN(Qnil);
4488 NORETURN(static VALUE f_exit(int c, const VALUE *a, VALUE _));
4490 * call-seq:
4491 * exit(status = true)
4492 * Process.exit(status = true)
4494 * Initiates termination of the Ruby script by raising SystemExit;
4495 * the exception may be caught.
4496 * Returns exit status +status+ to the underlying operating system.
4498 * Values +true+ and +false+ for argument +status+
4499 * indicate, respectively, success and failure;
4500 * The meanings of integer values are system-dependent.
4502 * Example:
4504 * begin
4505 * exit
4506 * puts 'Never get here.'
4507 * rescue SystemExit
4508 * puts 'Rescued a SystemExit exception.'
4509 * end
4510 * puts 'After begin block.'
4512 * Output:
4514 * Rescued a SystemExit exception.
4515 * After begin block.
4517 * Just prior to final termination,
4518 * Ruby executes any at-exit procedures (see Kernel::at_exit)
4519 * and any object finalizers (see ObjectSpace::define_finalizer).
4521 * Example:
4523 * at_exit { puts 'In at_exit function.' }
4524 * ObjectSpace.define_finalizer('string', proc { puts 'In finalizer.' })
4525 * exit
4527 * Output:
4529 * In at_exit function.
4530 * In finalizer.
4534 static VALUE
4535 f_exit(int c, const VALUE *a, VALUE _)
4537 rb_f_exit(c, a);
4538 UNREACHABLE_RETURN(Qnil);
4541 VALUE
4542 rb_f_abort(int argc, const VALUE *argv)
4544 rb_check_arity(argc, 0, 1);
4545 if (argc == 0) {
4546 rb_execution_context_t *ec = GET_EC();
4547 VALUE errinfo = rb_ec_get_errinfo(ec);
4548 if (!NIL_P(errinfo)) {
4549 rb_ec_error_print(ec, errinfo);
4551 rb_exit(EXIT_FAILURE);
4553 else {
4554 VALUE args[2];
4556 args[1] = args[0] = argv[0];
4557 StringValue(args[0]);
4558 rb_io_puts(1, args, rb_ractor_stderr());
4559 args[0] = INT2NUM(EXIT_FAILURE);
4560 rb_exc_raise(rb_class_new_instance(2, args, rb_eSystemExit));
4563 UNREACHABLE_RETURN(Qnil);
4566 NORETURN(static VALUE f_abort(int c, const VALUE *a, VALUE _));
4569 * call-seq:
4570 * abort
4571 * Process.abort(msg = nil)
4573 * Terminates execution immediately, effectively by calling
4574 * <tt>Kernel.exit(false)</tt>.
4576 * If string argument +msg+ is given,
4577 * it is written to STDERR prior to termination;
4578 * otherwise, if an exception was raised,
4579 * prints its message and backtrace.
4582 static VALUE
4583 f_abort(int c, const VALUE *a, VALUE _)
4585 rb_f_abort(c, a);
4586 UNREACHABLE_RETURN(Qnil);
4589 void
4590 rb_syswait(rb_pid_t pid)
4592 int status;
4594 rb_waitpid(pid, &status, 0);
4597 #if !defined HAVE_WORKING_FORK && !defined HAVE_SPAWNV && !defined __EMSCRIPTEN__
4598 char *
4599 rb_execarg_commandline(const struct rb_execarg *eargp, VALUE *prog)
4601 VALUE cmd = *prog;
4602 if (eargp && !eargp->use_shell) {
4603 VALUE str = eargp->invoke.cmd.argv_str;
4604 VALUE buf = eargp->invoke.cmd.argv_buf;
4605 char *p, **argv = ARGVSTR2ARGV(str);
4606 long i, argc = ARGVSTR2ARGC(str);
4607 const char *start = RSTRING_PTR(buf);
4608 cmd = rb_str_new(start, RSTRING_LEN(buf));
4609 p = RSTRING_PTR(cmd);
4610 for (i = 1; i < argc; ++i) {
4611 p[argv[i] - start - 1] = ' ';
4613 *prog = cmd;
4614 return p;
4616 return StringValueCStr(*prog);
4618 #endif
4620 static rb_pid_t
4621 rb_spawn_process(struct rb_execarg *eargp, char *errmsg, size_t errmsg_buflen)
4623 rb_pid_t pid;
4624 #if !defined HAVE_WORKING_FORK || USE_SPAWNV
4625 VALUE prog;
4626 struct rb_execarg sarg;
4627 # if !defined HAVE_SPAWNV
4628 int status;
4629 # endif
4630 #endif
4632 #if defined HAVE_WORKING_FORK && !USE_SPAWNV
4633 pid = fork_check_err(eargp->status, rb_exec_atfork, eargp, eargp->redirect_fds, errmsg, errmsg_buflen, eargp);
4634 #else
4635 prog = eargp->use_shell ? eargp->invoke.sh.shell_script : eargp->invoke.cmd.command_name;
4637 if (rb_execarg_run_options(eargp, &sarg, errmsg, errmsg_buflen) < 0) {
4638 return -1;
4641 if (prog && !eargp->use_shell) {
4642 char **argv = ARGVSTR2ARGV(eargp->invoke.cmd.argv_str);
4643 argv[0] = RSTRING_PTR(prog);
4645 # if defined HAVE_SPAWNV
4646 if (eargp->use_shell) {
4647 pid = proc_spawn_sh(RSTRING_PTR(prog));
4649 else {
4650 char **argv = ARGVSTR2ARGV(eargp->invoke.cmd.argv_str);
4651 pid = proc_spawn_cmd(argv, prog, eargp);
4654 if (pid == -1) {
4655 rb_last_status_set(0x7f << 8, pid);
4657 # else
4658 status = system(rb_execarg_commandline(eargp, &prog));
4659 pid = 1; /* dummy */
4660 rb_last_status_set((status & 0xff) << 8, pid);
4661 # endif
4663 if (eargp->waitpid_state) {
4664 eargp->waitpid_state->pid = pid;
4667 rb_execarg_run_options(&sarg, NULL, errmsg, errmsg_buflen);
4668 #endif
4670 return pid;
4673 struct spawn_args {
4674 VALUE execarg;
4675 struct {
4676 char *ptr;
4677 size_t buflen;
4678 } errmsg;
4681 static VALUE
4682 do_spawn_process(VALUE arg)
4684 struct spawn_args *argp = (struct spawn_args *)arg;
4686 rb_execarg_parent_start1(argp->execarg);
4688 return (VALUE)rb_spawn_process(rb_execarg_get(argp->execarg),
4689 argp->errmsg.ptr, argp->errmsg.buflen);
4692 NOINLINE(static rb_pid_t
4693 rb_execarg_spawn(VALUE execarg_obj, char *errmsg, size_t errmsg_buflen));
4695 static rb_pid_t
4696 rb_execarg_spawn(VALUE execarg_obj, char *errmsg, size_t errmsg_buflen)
4698 struct spawn_args args;
4700 args.execarg = execarg_obj;
4701 args.errmsg.ptr = errmsg;
4702 args.errmsg.buflen = errmsg_buflen;
4704 rb_pid_t r = (rb_pid_t)rb_ensure(do_spawn_process, (VALUE)&args,
4705 execarg_parent_end, execarg_obj);
4706 return r;
4709 static rb_pid_t
4710 rb_spawn_internal(int argc, const VALUE *argv, char *errmsg, size_t errmsg_buflen)
4712 VALUE execarg_obj;
4714 execarg_obj = rb_execarg_new(argc, argv, TRUE, FALSE);
4715 return rb_execarg_spawn(execarg_obj, errmsg, errmsg_buflen);
4718 rb_pid_t
4719 rb_spawn_err(int argc, const VALUE *argv, char *errmsg, size_t errmsg_buflen)
4721 return rb_spawn_internal(argc, argv, errmsg, errmsg_buflen);
4724 rb_pid_t
4725 rb_spawn(int argc, const VALUE *argv)
4727 return rb_spawn_internal(argc, argv, NULL, 0);
4731 * call-seq:
4732 * system([env, ] command_line, options = {}, exception: false) -> true, false, or nil
4733 * system([env, ] exe_path, *args, options = {}, exception: false) -> true, false, or nil
4735 * Creates a new child process by doing one of the following
4736 * in that process:
4738 * - Passing string +command_line+ to the shell.
4739 * - Invoking the executable at +exe_path+.
4741 * This method has potential security vulnerabilities if called with untrusted input;
4742 * see {Command Injection}[rdoc-ref:command_injection.rdoc].
4744 * Returns:
4746 * - +true+ if the command exits with status zero.
4747 * - +false+ if the exit status is a non-zero integer.
4748 * - +nil+ if the command could not execute.
4750 * Raises an exception (instead of returning +false+ or +nil+)
4751 * if keyword argument +exception+ is set to +true+.
4753 * Assigns the command's error status to <tt>$?</tt>.
4755 * The new process is created using the
4756 * {system system call}[https://pubs.opengroup.org/onlinepubs/9699919799.2018edition/functions/system.html];
4757 * it may inherit some of its environment from the calling program
4758 * (possibly including open file descriptors).
4760 * Argument +env+, if given, is a hash that affects +ENV+ for the new process;
4761 * see {Execution Environment}[rdoc-ref:Process@Execution+Environment].
4763 * Argument +options+ is a hash of options for the new process;
4764 * see {Execution Options}[rdoc-ref:Process@Execution+Options].
4766 * The first required argument is one of the following:
4768 * - +command_line+ if it is a string,
4769 * and if it begins with a shell reserved word or special built-in,
4770 * or if it contains one or more meta characters.
4771 * - +exe_path+ otherwise.
4773 * <b>Argument +command_line+</b>
4775 * \String argument +command_line+ is a command line to be passed to a shell;
4776 * it must begin with a shell reserved word, begin with a special built-in,
4777 * or contain meta characters:
4779 * system('if true; then echo "Foo"; fi') # => true # Shell reserved word.
4780 * system('exit') # => true # Built-in.
4781 * system('date > /tmp/date.tmp') # => true # Contains meta character.
4782 * system('date > /nop/date.tmp') # => false
4783 * system('date > /nop/date.tmp', exception: true) # Raises RuntimeError.
4785 * Assigns the command's error status to <tt>$?</tt>:
4787 * system('exit') # => true # Built-in.
4788 * $? # => #<Process::Status: pid 640610 exit 0>
4789 * system('date > /nop/date.tmp') # => false
4790 * $? # => #<Process::Status: pid 640742 exit 2>
4792 * The command line may also contain arguments and options for the command:
4794 * system('echo "Foo"') # => true
4796 * Output:
4798 * Foo
4800 * See {Execution Shell}[rdoc-ref:Process@Execution+Shell] for details about the shell.
4802 * Raises an exception if the new process could not execute.
4804 * <b>Argument +exe_path+</b>
4806 * Argument +exe_path+ is one of the following:
4808 * - The string path to an executable to be called.
4809 * - A 2-element array containing the path to an executable
4810 * and the string to be used as the name of the executing process.
4812 * Example:
4814 * system('/usr/bin/date') # => true # Path to date on Unix-style system.
4815 * system('foo') # => nil # Command failed.
4817 * Output:
4819 * Mon Aug 28 11:43:10 AM CDT 2023
4821 * Assigns the command's error status to <tt>$?</tt>:
4823 * system('/usr/bin/date') # => true
4824 * $? # => #<Process::Status: pid 645605 exit 0>
4825 * system('foo') # => nil
4826 * $? # => #<Process::Status: pid 645608 exit 127>
4828 * Ruby invokes the executable directly.
4829 * This form does not use the shell;
4830 * see {Arguments args}[rdoc-ref:Process@Arguments+args] for caveats.
4832 * system('doesnt_exist') # => nil
4834 * If one or more +args+ is given, each is an argument or option
4835 * to be passed to the executable:
4837 * system('echo', 'C*') # => true
4838 * system('echo', 'hello', 'world') # => true
4840 * Output:
4842 * C*
4843 * hello world
4845 * Raises an exception if the new process could not execute.
4848 static VALUE
4849 rb_f_system(int argc, VALUE *argv, VALUE _)
4851 rb_thread_t *th = GET_THREAD();
4852 VALUE execarg_obj = rb_execarg_new(argc, argv, TRUE, TRUE);
4853 struct rb_execarg *eargp = rb_execarg_get(execarg_obj);
4855 struct rb_process_status status = {0};
4856 eargp->status = &status;
4858 last_status_clear(th);
4860 // This function can set the thread's last status.
4861 // May be different from waitpid_state.pid on exec failure.
4862 rb_pid_t pid = rb_execarg_spawn(execarg_obj, 0, 0);
4864 if (pid > 0) {
4865 VALUE status = rb_process_status_wait(pid, 0);
4866 struct rb_process_status *data = rb_check_typeddata(status, &rb_process_status_type);
4867 // Set the last status:
4868 rb_obj_freeze(status);
4869 th->last_status = status;
4871 if (data->status == EXIT_SUCCESS) {
4872 return Qtrue;
4875 if (data->error != 0) {
4876 if (eargp->exception) {
4877 VALUE command = eargp->invoke.sh.shell_script;
4878 RB_GC_GUARD(execarg_obj);
4879 rb_syserr_fail_str(data->error, command);
4881 else {
4882 return Qnil;
4885 else if (eargp->exception) {
4886 VALUE command = eargp->invoke.sh.shell_script;
4887 VALUE str = rb_str_new_cstr("Command failed with");
4888 rb_str_cat_cstr(pst_message_status(str, data->status), ": ");
4889 rb_str_append(str, command);
4890 RB_GC_GUARD(execarg_obj);
4891 rb_exc_raise(rb_exc_new_str(rb_eRuntimeError, str));
4893 else {
4894 return Qfalse;
4897 RB_GC_GUARD(status);
4900 if (eargp->exception) {
4901 VALUE command = eargp->invoke.sh.shell_script;
4902 RB_GC_GUARD(execarg_obj);
4903 rb_syserr_fail_str(errno, command);
4905 else {
4906 return Qnil;
4911 * call-seq:
4912 * spawn([env, ] command_line, options = {}) -> pid
4913 * spawn([env, ] exe_path, *args, options = {}) -> pid
4915 * Creates a new child process by doing one of the following
4916 * in that process:
4918 * - Passing string +command_line+ to the shell.
4919 * - Invoking the executable at +exe_path+.
4921 * This method has potential security vulnerabilities if called with untrusted input;
4922 * see {Command Injection}[rdoc-ref:command_injection.rdoc].
4924 * Returns the process ID (pid) of the new process,
4925 * without waiting for it to complete.
4927 * To avoid zombie processes, the parent process should call either:
4929 * - Process.wait, to collect the termination statuses of its children.
4930 * - Process.detach, to register disinterest in their status.
4932 * The new process is created using the
4933 * {exec system call}[https://pubs.opengroup.org/onlinepubs/9699919799.2018edition/functions/execve.html];
4934 * it may inherit some of its environment from the calling program
4935 * (possibly including open file descriptors).
4937 * Argument +env+, if given, is a hash that affects +ENV+ for the new process;
4938 * see {Execution Environment}[rdoc-ref:Process@Execution+Environment].
4940 * Argument +options+ is a hash of options for the new process;
4941 * see {Execution Options}[rdoc-ref:Process@Execution+Options].
4943 * The first required argument is one of the following:
4945 * - +command_line+ if it is a string,
4946 * and if it begins with a shell reserved word or special built-in,
4947 * or if it contains one or more meta characters.
4948 * - +exe_path+ otherwise.
4950 * <b>Argument +command_line+</b>
4952 * \String argument +command_line+ is a command line to be passed to a shell;
4953 * it must begin with a shell reserved word, begin with a special built-in,
4954 * or contain meta characters:
4956 * spawn('if true; then echo "Foo"; fi') # => 798847 # Shell reserved word.
4957 * Process.wait # => 798847
4958 * spawn('exit') # => 798848 # Built-in.
4959 * Process.wait # => 798848
4960 * spawn('date > /tmp/date.tmp') # => 798879 # Contains meta character.
4961 * Process.wait # => 798849
4962 * spawn('date > /nop/date.tmp') # => 798882 # Issues error message.
4963 * Process.wait # => 798882
4965 * The command line may also contain arguments and options for the command:
4967 * spawn('echo "Foo"') # => 799031
4968 * Process.wait # => 799031
4970 * Output:
4972 * Foo
4974 * See {Execution Shell}[rdoc-ref:Process@Execution+Shell] for details about the shell.
4976 * Raises an exception if the new process could not execute.
4978 * <b>Argument +exe_path+</b>
4980 * Argument +exe_path+ is one of the following:
4982 * - The string path to an executable to be called.
4983 * - A 2-element array containing the path to an executable to be called,
4984 * and the string to be used as the name of the executing process.
4986 * spawn('/usr/bin/date') # Path to date on Unix-style system.
4987 * Process.wait
4989 * Output:
4991 * Mon Aug 28 11:43:10 AM CDT 2023
4993 * Ruby invokes the executable directly.
4994 * This form does not use the shell;
4995 * see {Arguments args}[rdoc-ref:Process@Arguments+args] for caveats.
4997 * If one or more +args+ is given, each is an argument or option
4998 * to be passed to the executable:
5000 * spawn('echo', 'C*') # => 799392
5001 * Process.wait # => 799392
5002 * spawn('echo', 'hello', 'world') # => 799393
5003 * Process.wait # => 799393
5005 * Output:
5007 * C*
5008 * hello world
5010 * Raises an exception if the new process could not execute.
5013 static VALUE
5014 rb_f_spawn(int argc, VALUE *argv, VALUE _)
5016 rb_pid_t pid;
5017 char errmsg[CHILD_ERRMSG_BUFLEN] = { '\0' };
5018 VALUE execarg_obj, fail_str;
5019 struct rb_execarg *eargp;
5021 execarg_obj = rb_execarg_new(argc, argv, TRUE, FALSE);
5022 eargp = rb_execarg_get(execarg_obj);
5023 fail_str = eargp->use_shell ? eargp->invoke.sh.shell_script : eargp->invoke.cmd.command_name;
5025 pid = rb_execarg_spawn(execarg_obj, errmsg, sizeof(errmsg));
5027 if (pid == -1) {
5028 int err = errno;
5029 rb_exec_fail(eargp, err, errmsg);
5030 RB_GC_GUARD(execarg_obj);
5031 rb_syserr_fail_str(err, fail_str);
5033 #if defined(HAVE_WORKING_FORK) || defined(HAVE_SPAWNV)
5034 return PIDT2NUM(pid);
5035 #else
5036 return Qnil;
5037 #endif
5041 * call-seq:
5042 * sleep(secs = nil) -> slept_secs
5044 * Suspends execution of the current thread for the number of seconds
5045 * specified by numeric argument +secs+, or forever if +secs+ is +nil+;
5046 * returns the integer number of seconds suspended (rounded).
5048 * Time.new # => 2008-03-08 19:56:19 +0900
5049 * sleep 1.2 # => 1
5050 * Time.new # => 2008-03-08 19:56:20 +0900
5051 * sleep 1.9 # => 2
5052 * Time.new # => 2008-03-08 19:56:22 +0900
5056 static VALUE
5057 rb_f_sleep(int argc, VALUE *argv, VALUE _)
5059 time_t beg = time(0);
5060 VALUE scheduler = rb_fiber_scheduler_current();
5062 if (scheduler != Qnil) {
5063 rb_fiber_scheduler_kernel_sleepv(scheduler, argc, argv);
5065 else {
5066 if (argc == 0 || (argc == 1 && NIL_P(argv[0]))) {
5067 rb_thread_sleep_forever();
5069 else {
5070 rb_check_arity(argc, 0, 1);
5071 rb_thread_wait_for(rb_time_interval(argv[0]));
5075 time_t end = time(0) - beg;
5077 return TIMET2NUM(end);
5081 #if (defined(HAVE_GETPGRP) && defined(GETPGRP_VOID)) || defined(HAVE_GETPGID)
5083 * call-seq:
5084 * Process.getpgrp -> integer
5086 * Returns the process group ID for the current process:
5088 * Process.getpgid(0) # => 25527
5089 * Process.getpgrp # => 25527
5093 static VALUE
5094 proc_getpgrp(VALUE _)
5096 rb_pid_t pgrp;
5098 #if defined(HAVE_GETPGRP) && defined(GETPGRP_VOID)
5099 pgrp = getpgrp();
5100 if (pgrp < 0) rb_sys_fail(0);
5101 return PIDT2NUM(pgrp);
5102 #else /* defined(HAVE_GETPGID) */
5103 pgrp = getpgid(0);
5104 if (pgrp < 0) rb_sys_fail(0);
5105 return PIDT2NUM(pgrp);
5106 #endif
5108 #else
5109 #define proc_getpgrp rb_f_notimplement
5110 #endif
5113 #if defined(HAVE_SETPGID) || (defined(HAVE_SETPGRP) && defined(SETPGRP_VOID))
5115 * call-seq:
5116 * Process.setpgrp -> 0
5118 * Equivalent to <tt>setpgid(0, 0)</tt>.
5120 * Not available on all platforms.
5123 static VALUE
5124 proc_setpgrp(VALUE _)
5126 /* check for posix setpgid() first; this matches the posix */
5127 /* getpgrp() above. It appears that configure will set SETPGRP_VOID */
5128 /* even though setpgrp(0,0) would be preferred. The posix call avoids */
5129 /* this confusion. */
5130 #ifdef HAVE_SETPGID
5131 if (setpgid(0,0) < 0) rb_sys_fail(0);
5132 #elif defined(HAVE_SETPGRP) && defined(SETPGRP_VOID)
5133 if (setpgrp() < 0) rb_sys_fail(0);
5134 #endif
5135 return INT2FIX(0);
5137 #else
5138 #define proc_setpgrp rb_f_notimplement
5139 #endif
5142 #if defined(HAVE_GETPGID)
5144 * call-seq:
5145 * Process.getpgid(pid) -> integer
5147 * Returns the process group ID for the given process ID +pid+:
5149 * Process.getpgid(Process.ppid) # => 25527
5151 * Not available on all platforms.
5154 static VALUE
5155 proc_getpgid(VALUE obj, VALUE pid)
5157 rb_pid_t i;
5159 i = getpgid(NUM2PIDT(pid));
5160 if (i < 0) rb_sys_fail(0);
5161 return PIDT2NUM(i);
5163 #else
5164 #define proc_getpgid rb_f_notimplement
5165 #endif
5168 #ifdef HAVE_SETPGID
5170 * call-seq:
5171 * Process.setpgid(pid, pgid) -> 0
5173 * Sets the process group ID for the process given by process ID +pid+
5174 * to +pgid+.
5176 * Not available on all platforms.
5179 static VALUE
5180 proc_setpgid(VALUE obj, VALUE pid, VALUE pgrp)
5182 rb_pid_t ipid, ipgrp;
5184 ipid = NUM2PIDT(pid);
5185 ipgrp = NUM2PIDT(pgrp);
5187 if (setpgid(ipid, ipgrp) < 0) rb_sys_fail(0);
5188 return INT2FIX(0);
5190 #else
5191 #define proc_setpgid rb_f_notimplement
5192 #endif
5195 #ifdef HAVE_GETSID
5197 * call-seq:
5198 * Process.getsid(pid = nil) -> integer
5200 * Returns the session ID of the given process ID +pid+,
5201 * or of the current process if not given:
5203 * Process.getsid # => 27422
5204 * Process.getsid(0) # => 27422
5205 * Process.getsid(Process.pid()) # => 27422
5207 * Not available on all platforms.
5209 static VALUE
5210 proc_getsid(int argc, VALUE *argv, VALUE _)
5212 rb_pid_t sid;
5213 rb_pid_t pid = 0;
5215 if (rb_check_arity(argc, 0, 1) == 1 && !NIL_P(argv[0]))
5216 pid = NUM2PIDT(argv[0]);
5218 sid = getsid(pid);
5219 if (sid < 0) rb_sys_fail(0);
5220 return PIDT2NUM(sid);
5222 #else
5223 #define proc_getsid rb_f_notimplement
5224 #endif
5227 #if defined(HAVE_SETSID) || (defined(HAVE_SETPGRP) && defined(TIOCNOTTY))
5228 #if !defined(HAVE_SETSID)
5229 static rb_pid_t ruby_setsid(void);
5230 #define setsid() ruby_setsid()
5231 #endif
5233 * call-seq:
5234 * Process.setsid -> integer
5236 * Establishes the current process as a new session and process group leader,
5237 * with no controlling tty;
5238 * returns the session ID:
5240 * Process.setsid # => 27422
5242 * Not available on all platforms.
5245 static VALUE
5246 proc_setsid(VALUE _)
5248 rb_pid_t pid;
5250 pid = setsid();
5251 if (pid < 0) rb_sys_fail(0);
5252 return PIDT2NUM(pid);
5255 #if !defined(HAVE_SETSID)
5256 #define HAVE_SETSID 1
5257 static rb_pid_t
5258 ruby_setsid(void)
5260 rb_pid_t pid;
5261 int ret, fd;
5263 pid = getpid();
5264 #if defined(SETPGRP_VOID)
5265 ret = setpgrp();
5266 /* If `pid_t setpgrp(void)' is equivalent to setsid(),
5267 `ret' will be the same value as `pid', and following open() will fail.
5268 In Linux, `int setpgrp(void)' is equivalent to setpgid(0, 0). */
5269 #else
5270 ret = setpgrp(0, pid);
5271 #endif
5272 if (ret == -1) return -1;
5274 if ((fd = rb_cloexec_open("/dev/tty", O_RDWR, 0)) >= 0) {
5275 rb_update_max_fd(fd);
5276 ioctl(fd, TIOCNOTTY, NULL);
5277 close(fd);
5279 return pid;
5281 #endif
5282 #else
5283 #define proc_setsid rb_f_notimplement
5284 #endif
5287 #ifdef HAVE_GETPRIORITY
5289 * call-seq:
5290 * Process.getpriority(kind, id) -> integer
5292 * Returns the scheduling priority for specified process, process group,
5293 * or user.
5295 * Argument +kind+ is one of:
5297 * - Process::PRIO_PROCESS: return priority for process.
5298 * - Process::PRIO_PGRP: return priority for process group.
5299 * - Process::PRIO_USER: return priority for user.
5301 * Argument +id+ is the ID for the process, process group, or user;
5302 * zero specified the current ID for +kind+.
5304 * Examples:
5306 * Process.getpriority(Process::PRIO_USER, 0) # => 19
5307 * Process.getpriority(Process::PRIO_PROCESS, 0) # => 19
5309 * Not available on all platforms.
5312 static VALUE
5313 proc_getpriority(VALUE obj, VALUE which, VALUE who)
5315 int prio, iwhich, iwho;
5317 iwhich = NUM2INT(which);
5318 iwho = NUM2INT(who);
5320 errno = 0;
5321 prio = getpriority(iwhich, iwho);
5322 if (errno) rb_sys_fail(0);
5323 return INT2FIX(prio);
5325 #else
5326 #define proc_getpriority rb_f_notimplement
5327 #endif
5330 #ifdef HAVE_GETPRIORITY
5332 * call-seq:
5333 * Process.setpriority(kind, integer, priority) -> 0
5335 * See Process.getpriority.
5337 * Examples:
5339 * Process.setpriority(Process::PRIO_USER, 0, 19) # => 0
5340 * Process.setpriority(Process::PRIO_PROCESS, 0, 19) # => 0
5341 * Process.getpriority(Process::PRIO_USER, 0) # => 19
5342 * Process.getpriority(Process::PRIO_PROCESS, 0) # => 19
5344 * Not available on all platforms.
5347 static VALUE
5348 proc_setpriority(VALUE obj, VALUE which, VALUE who, VALUE prio)
5350 int iwhich, iwho, iprio;
5352 iwhich = NUM2INT(which);
5353 iwho = NUM2INT(who);
5354 iprio = NUM2INT(prio);
5356 if (setpriority(iwhich, iwho, iprio) < 0)
5357 rb_sys_fail(0);
5358 return INT2FIX(0);
5360 #else
5361 #define proc_setpriority rb_f_notimplement
5362 #endif
5364 #if defined(HAVE_SETRLIMIT) && defined(NUM2RLIM)
5365 static int
5366 rlimit_resource_name2int(const char *name, long len, int casetype)
5368 int resource;
5369 const char *p;
5370 #define RESCHECK(r) \
5371 do { \
5372 if (len == rb_strlen_lit(#r) && STRCASECMP(name, #r) == 0) { \
5373 resource = RLIMIT_##r; \
5374 goto found; \
5376 } while (0)
5378 switch (TOUPPER(*name)) {
5379 case 'A':
5380 #ifdef RLIMIT_AS
5381 RESCHECK(AS);
5382 #endif
5383 break;
5385 case 'C':
5386 #ifdef RLIMIT_CORE
5387 RESCHECK(CORE);
5388 #endif
5389 #ifdef RLIMIT_CPU
5390 RESCHECK(CPU);
5391 #endif
5392 break;
5394 case 'D':
5395 #ifdef RLIMIT_DATA
5396 RESCHECK(DATA);
5397 #endif
5398 break;
5400 case 'F':
5401 #ifdef RLIMIT_FSIZE
5402 RESCHECK(FSIZE);
5403 #endif
5404 break;
5406 case 'M':
5407 #ifdef RLIMIT_MEMLOCK
5408 RESCHECK(MEMLOCK);
5409 #endif
5410 #ifdef RLIMIT_MSGQUEUE
5411 RESCHECK(MSGQUEUE);
5412 #endif
5413 break;
5415 case 'N':
5416 #ifdef RLIMIT_NOFILE
5417 RESCHECK(NOFILE);
5418 #endif
5419 #ifdef RLIMIT_NPROC
5420 RESCHECK(NPROC);
5421 #endif
5422 #ifdef RLIMIT_NPTS
5423 RESCHECK(NPTS);
5424 #endif
5425 #ifdef RLIMIT_NICE
5426 RESCHECK(NICE);
5427 #endif
5428 break;
5430 case 'R':
5431 #ifdef RLIMIT_RSS
5432 RESCHECK(RSS);
5433 #endif
5434 #ifdef RLIMIT_RTPRIO
5435 RESCHECK(RTPRIO);
5436 #endif
5437 #ifdef RLIMIT_RTTIME
5438 RESCHECK(RTTIME);
5439 #endif
5440 break;
5442 case 'S':
5443 #ifdef RLIMIT_STACK
5444 RESCHECK(STACK);
5445 #endif
5446 #ifdef RLIMIT_SBSIZE
5447 RESCHECK(SBSIZE);
5448 #endif
5449 #ifdef RLIMIT_SIGPENDING
5450 RESCHECK(SIGPENDING);
5451 #endif
5452 break;
5454 return -1;
5456 found:
5457 switch (casetype) {
5458 case 0:
5459 for (p = name; *p; p++)
5460 if (!ISUPPER(*p))
5461 return -1;
5462 break;
5464 case 1:
5465 for (p = name; *p; p++)
5466 if (!ISLOWER(*p))
5467 return -1;
5468 break;
5470 default:
5471 rb_bug("unexpected casetype");
5473 return resource;
5474 #undef RESCHECK
5477 static int
5478 rlimit_type_by_hname(const char *name, long len)
5480 return rlimit_resource_name2int(name, len, 0);
5483 static int
5484 rlimit_type_by_lname(const char *name, long len)
5486 return rlimit_resource_name2int(name, len, 1);
5489 static int
5490 rlimit_type_by_sym(VALUE key)
5492 VALUE name = rb_sym2str(key);
5493 const char *rname = RSTRING_PTR(name);
5494 long len = RSTRING_LEN(name);
5495 int rtype = -1;
5496 static const char prefix[] = "rlimit_";
5497 enum {prefix_len = sizeof(prefix)-1};
5499 if (len > prefix_len && strncmp(prefix, rname, prefix_len) == 0) {
5500 rtype = rlimit_type_by_lname(rname + prefix_len, len - prefix_len);
5503 RB_GC_GUARD(key);
5504 return rtype;
5507 static int
5508 rlimit_resource_type(VALUE rtype)
5510 const char *name;
5511 long len;
5512 VALUE v;
5513 int r;
5515 switch (TYPE(rtype)) {
5516 case T_SYMBOL:
5517 v = rb_sym2str(rtype);
5518 name = RSTRING_PTR(v);
5519 len = RSTRING_LEN(v);
5520 break;
5522 default:
5523 v = rb_check_string_type(rtype);
5524 if (!NIL_P(v)) {
5525 rtype = v;
5526 case T_STRING:
5527 name = StringValueCStr(rtype);
5528 len = RSTRING_LEN(rtype);
5529 break;
5531 /* fall through */
5533 case T_FIXNUM:
5534 case T_BIGNUM:
5535 return NUM2INT(rtype);
5538 r = rlimit_type_by_hname(name, len);
5539 if (r != -1)
5540 return r;
5542 rb_raise(rb_eArgError, "invalid resource name: % "PRIsVALUE, rtype);
5544 UNREACHABLE_RETURN(-1);
5547 static rlim_t
5548 rlimit_resource_value(VALUE rval)
5550 const char *name;
5551 VALUE v;
5553 switch (TYPE(rval)) {
5554 case T_SYMBOL:
5555 v = rb_sym2str(rval);
5556 name = RSTRING_PTR(v);
5557 break;
5559 default:
5560 v = rb_check_string_type(rval);
5561 if (!NIL_P(v)) {
5562 rval = v;
5563 case T_STRING:
5564 name = StringValueCStr(rval);
5565 break;
5567 /* fall through */
5569 case T_FIXNUM:
5570 case T_BIGNUM:
5571 return NUM2RLIM(rval);
5574 #ifdef RLIM_INFINITY
5575 if (strcmp(name, "INFINITY") == 0) return RLIM_INFINITY;
5576 #endif
5577 #ifdef RLIM_SAVED_MAX
5578 if (strcmp(name, "SAVED_MAX") == 0) return RLIM_SAVED_MAX;
5579 #endif
5580 #ifdef RLIM_SAVED_CUR
5581 if (strcmp(name, "SAVED_CUR") == 0) return RLIM_SAVED_CUR;
5582 #endif
5583 rb_raise(rb_eArgError, "invalid resource value: %"PRIsVALUE, rval);
5585 UNREACHABLE_RETURN((rlim_t)-1);
5587 #endif
5589 #if defined(HAVE_GETRLIMIT) && defined(RLIM2NUM)
5591 * call-seq:
5592 * Process.getrlimit(resource) -> [cur_limit, max_limit]
5594 * Returns a 2-element array of the current (soft) limit
5595 * and maximum (hard) limit for the given +resource+.
5597 * Argument +resource+ specifies the resource whose limits are to be returned;
5598 * see Process.setrlimit.
5600 * Each of the returned values +cur_limit+ and +max_limit+ is an integer;
5601 * see Process.setrlimit.
5603 * Example:
5605 * Process.getrlimit(:CORE) # => [0, 18446744073709551615]
5607 * See Process.setrlimit.
5609 * Not available on all platforms.
5612 static VALUE
5613 proc_getrlimit(VALUE obj, VALUE resource)
5615 struct rlimit rlim;
5617 if (getrlimit(rlimit_resource_type(resource), &rlim) < 0) {
5618 rb_sys_fail("getrlimit");
5620 return rb_assoc_new(RLIM2NUM(rlim.rlim_cur), RLIM2NUM(rlim.rlim_max));
5622 #else
5623 #define proc_getrlimit rb_f_notimplement
5624 #endif
5626 #if defined(HAVE_SETRLIMIT) && defined(NUM2RLIM)
5628 * call-seq:
5629 * Process.setrlimit(resource, cur_limit, max_limit = cur_limit) -> nil
5631 * Sets limits for the current process for the given +resource+
5632 * to +cur_limit+ (soft limit) and +max_limit+ (hard limit);
5633 * returns +nil+.
5635 * Argument +resource+ specifies the resource whose limits are to be set;
5636 * the argument may be given as a symbol, as a string, or as a constant
5637 * beginning with <tt>Process::RLIMIT_</tt>
5638 * (e.g., +:CORE+, <tt>'CORE'</tt>, or <tt>Process::RLIMIT_CORE</tt>.
5640 * The resources available and supported are system-dependent,
5641 * and may include (here expressed as symbols):
5643 * - +:AS+: Total available memory (bytes) (SUSv3, NetBSD, FreeBSD, OpenBSD except 4.4BSD-Lite).
5644 * - +:CORE+: Core size (bytes) (SUSv3).
5645 * - +:CPU+: CPU time (seconds) (SUSv3).
5646 * - +:DATA+: Data segment (bytes) (SUSv3).
5647 * - +:FSIZE+: File size (bytes) (SUSv3).
5648 * - +:MEMLOCK+: Total size for mlock(2) (bytes) (4.4BSD, GNU/Linux).
5649 * - +:MSGQUEUE+: Allocation for POSIX message queues (bytes) (GNU/Linux).
5650 * - +:NICE+: Ceiling on process's nice(2) value (number) (GNU/Linux).
5651 * - +:NOFILE+: File descriptors (number) (SUSv3).
5652 * - +:NPROC+: Number of processes for the user (number) (4.4BSD, GNU/Linux).
5653 * - +:NPTS+: Number of pseudo terminals (number) (FreeBSD).
5654 * - +:RSS+: Resident memory size (bytes) (4.2BSD, GNU/Linux).
5655 * - +:RTPRIO+: Ceiling on the process's real-time priority (number) (GNU/Linux).
5656 * - +:RTTIME+: CPU time for real-time process (us) (GNU/Linux).
5657 * - +:SBSIZE+: All socket buffers (bytes) (NetBSD, FreeBSD).
5658 * - +:SIGPENDING+: Number of queued signals allowed (signals) (GNU/Linux).
5659 * - +:STACK+: Stack size (bytes) (SUSv3).
5661 * Arguments +cur_limit+ and +max_limit+ may be:
5663 * - Integers (+max_limit+ should not be smaller than +cur_limit+).
5664 * - Symbol +:SAVED_MAX+, string <tt>'SAVED_MAX'</tt>,
5665 * or constant <tt>Process::RLIM_SAVED_MAX</tt>: saved maximum limit.
5666 * - Symbol +:SAVED_CUR+, string <tt>'SAVED_CUR'</tt>,
5667 * or constant <tt>Process::RLIM_SAVED_CUR</tt>: saved current limit.
5668 * - Symbol +:INFINITY+, string <tt>'INFINITY'</tt>,
5669 * or constant <tt>Process::RLIM_INFINITY</tt>: no limit on resource.
5671 * This example raises the soft limit of core size to
5672 * the hard limit to try to make core dump possible:
5674 * Process.setrlimit(:CORE, Process.getrlimit(:CORE)[1])
5676 * Not available on all platforms.
5679 static VALUE
5680 proc_setrlimit(int argc, VALUE *argv, VALUE obj)
5682 VALUE resource, rlim_cur, rlim_max;
5683 struct rlimit rlim;
5685 rb_check_arity(argc, 2, 3);
5686 resource = argv[0];
5687 rlim_cur = argv[1];
5688 if (argc < 3 || NIL_P(rlim_max = argv[2]))
5689 rlim_max = rlim_cur;
5691 rlim.rlim_cur = rlimit_resource_value(rlim_cur);
5692 rlim.rlim_max = rlimit_resource_value(rlim_max);
5694 if (setrlimit(rlimit_resource_type(resource), &rlim) < 0) {
5695 rb_sys_fail("setrlimit");
5697 return Qnil;
5699 #else
5700 #define proc_setrlimit rb_f_notimplement
5701 #endif
5703 static int under_uid_switch = 0;
5704 static void
5705 check_uid_switch(void)
5707 if (under_uid_switch) {
5708 rb_raise(rb_eRuntimeError, "can't handle UID while evaluating block given to Process::UID.switch method");
5712 static int under_gid_switch = 0;
5713 static void
5714 check_gid_switch(void)
5716 if (under_gid_switch) {
5717 rb_raise(rb_eRuntimeError, "can't handle GID while evaluating block given to Process::UID.switch method");
5722 #if defined(HAVE_PWD_H)
5724 * Best-effort attempt to obtain the name of the login user, if any,
5725 * associated with the process. Processes not descended from login(1) (or
5726 * similar) may not have a logged-in user; returns Qnil in that case.
5728 VALUE
5729 rb_getlogin(void)
5731 #if ( !defined(USE_GETLOGIN_R) && !defined(USE_GETLOGIN) )
5732 return Qnil;
5733 #else
5734 char MAYBE_UNUSED(*login) = NULL;
5736 # ifdef USE_GETLOGIN_R
5738 #if defined(__FreeBSD__)
5739 typedef int getlogin_r_size_t;
5740 #else
5741 typedef size_t getlogin_r_size_t;
5742 #endif
5744 long loginsize = GETLOGIN_R_SIZE_INIT; /* maybe -1 */
5746 if (loginsize < 0)
5747 loginsize = GETLOGIN_R_SIZE_DEFAULT;
5749 VALUE maybe_result = rb_str_buf_new(loginsize);
5751 login = RSTRING_PTR(maybe_result);
5752 loginsize = rb_str_capacity(maybe_result);
5753 rb_str_set_len(maybe_result, loginsize);
5755 int gle;
5756 errno = 0;
5757 while ((gle = getlogin_r(login, (getlogin_r_size_t)loginsize)) != 0) {
5759 if (gle == ENOTTY || gle == ENXIO || gle == ENOENT) {
5760 rb_str_resize(maybe_result, 0);
5761 return Qnil;
5764 if (gle != ERANGE || loginsize >= GETLOGIN_R_SIZE_LIMIT) {
5765 rb_str_resize(maybe_result, 0);
5766 rb_syserr_fail(gle, "getlogin_r");
5769 rb_str_modify_expand(maybe_result, loginsize);
5770 login = RSTRING_PTR(maybe_result);
5771 loginsize = rb_str_capacity(maybe_result);
5774 if (login == NULL) {
5775 rb_str_resize(maybe_result, 0);
5776 return Qnil;
5779 return maybe_result;
5781 # elif USE_GETLOGIN
5783 errno = 0;
5784 login = getlogin();
5785 if (errno) {
5786 if (errno == ENOTTY || errno == ENXIO || errno == ENOENT) {
5787 return Qnil;
5789 rb_syserr_fail(errno, "getlogin");
5792 return login ? rb_str_new_cstr(login) : Qnil;
5793 # endif
5795 #endif
5798 VALUE
5799 rb_getpwdirnam_for_login(VALUE login_name)
5801 #if ( !defined(USE_GETPWNAM_R) && !defined(USE_GETPWNAM) )
5802 return Qnil;
5803 #else
5805 if (NIL_P(login_name)) {
5806 /* nothing to do; no name with which to query the password database */
5807 return Qnil;
5810 char *login = RSTRING_PTR(login_name);
5812 struct passwd *pwptr;
5814 # ifdef USE_GETPWNAM_R
5816 struct passwd pwdnm;
5817 char *bufnm;
5818 long bufsizenm = GETPW_R_SIZE_INIT; /* maybe -1 */
5820 if (bufsizenm < 0)
5821 bufsizenm = GETPW_R_SIZE_DEFAULT;
5823 VALUE getpwnm_tmp = rb_str_tmp_new(bufsizenm);
5825 bufnm = RSTRING_PTR(getpwnm_tmp);
5826 bufsizenm = rb_str_capacity(getpwnm_tmp);
5827 rb_str_set_len(getpwnm_tmp, bufsizenm);
5829 int enm;
5830 errno = 0;
5831 while ((enm = getpwnam_r(login, &pwdnm, bufnm, bufsizenm, &pwptr)) != 0) {
5833 if (enm == ENOENT || enm== ESRCH || enm == EBADF || enm == EPERM) {
5834 /* not found; non-errors */
5835 rb_str_resize(getpwnm_tmp, 0);
5836 return Qnil;
5839 if (enm != ERANGE || bufsizenm >= GETPW_R_SIZE_LIMIT) {
5840 rb_str_resize(getpwnm_tmp, 0);
5841 rb_syserr_fail(enm, "getpwnam_r");
5844 rb_str_modify_expand(getpwnm_tmp, bufsizenm);
5845 bufnm = RSTRING_PTR(getpwnm_tmp);
5846 bufsizenm = rb_str_capacity(getpwnm_tmp);
5849 if (pwptr == NULL) {
5850 /* no record in the password database for the login name */
5851 rb_str_resize(getpwnm_tmp, 0);
5852 return Qnil;
5855 /* found it */
5856 VALUE result = rb_str_new_cstr(pwptr->pw_dir);
5857 rb_str_resize(getpwnm_tmp, 0);
5858 return result;
5860 # elif USE_GETPWNAM
5862 errno = 0;
5863 pwptr = getpwnam(login);
5864 if (pwptr) {
5865 /* found it */
5866 return rb_str_new_cstr(pwptr->pw_dir);
5868 if (errno
5869 /* avoid treating as errors errno values that indicate "not found" */
5870 && ( errno != ENOENT && errno != ESRCH && errno != EBADF && errno != EPERM)) {
5871 rb_syserr_fail(errno, "getpwnam");
5874 return Qnil; /* not found */
5875 # endif
5877 #endif
5881 * Look up the user's dflt home dir in the password db, by uid.
5883 VALUE
5884 rb_getpwdiruid(void)
5886 # if !defined(USE_GETPWUID_R) && !defined(USE_GETPWUID)
5887 /* Should never happen... </famous-last-words> */
5888 return Qnil;
5889 # else
5890 uid_t ruid = getuid();
5892 struct passwd *pwptr;
5894 # ifdef USE_GETPWUID_R
5896 struct passwd pwdid;
5897 char *bufid;
5898 long bufsizeid = GETPW_R_SIZE_INIT; /* maybe -1 */
5900 if (bufsizeid < 0)
5901 bufsizeid = GETPW_R_SIZE_DEFAULT;
5903 VALUE getpwid_tmp = rb_str_tmp_new(bufsizeid);
5905 bufid = RSTRING_PTR(getpwid_tmp);
5906 bufsizeid = rb_str_capacity(getpwid_tmp);
5907 rb_str_set_len(getpwid_tmp, bufsizeid);
5909 int eid;
5910 errno = 0;
5911 while ((eid = getpwuid_r(ruid, &pwdid, bufid, bufsizeid, &pwptr)) != 0) {
5913 if (eid == ENOENT || eid== ESRCH || eid == EBADF || eid == EPERM) {
5914 /* not found; non-errors */
5915 rb_str_resize(getpwid_tmp, 0);
5916 return Qnil;
5919 if (eid != ERANGE || bufsizeid >= GETPW_R_SIZE_LIMIT) {
5920 rb_str_resize(getpwid_tmp, 0);
5921 rb_syserr_fail(eid, "getpwuid_r");
5924 rb_str_modify_expand(getpwid_tmp, bufsizeid);
5925 bufid = RSTRING_PTR(getpwid_tmp);
5926 bufsizeid = rb_str_capacity(getpwid_tmp);
5929 if (pwptr == NULL) {
5930 /* no record in the password database for the uid */
5931 rb_str_resize(getpwid_tmp, 0);
5932 return Qnil;
5935 /* found it */
5936 VALUE result = rb_str_new_cstr(pwptr->pw_dir);
5937 rb_str_resize(getpwid_tmp, 0);
5938 return result;
5940 # elif defined(USE_GETPWUID)
5942 errno = 0;
5943 pwptr = getpwuid(ruid);
5944 if (pwptr) {
5945 /* found it */
5946 return rb_str_new_cstr(pwptr->pw_dir);
5948 if (errno
5949 /* avoid treating as errors errno values that indicate "not found" */
5950 && ( errno == ENOENT || errno == ESRCH || errno == EBADF || errno == EPERM)) {
5951 rb_syserr_fail(errno, "getpwuid");
5954 return Qnil; /* not found */
5955 # endif
5957 #endif /* !defined(USE_GETPWUID_R) && !defined(USE_GETPWUID) */
5959 #endif /* HAVE_PWD_H */
5962 /*********************************************************************
5963 * Document-class: Process::Sys
5965 * The Process::Sys module contains UID and GID
5966 * functions which provide direct bindings to the system calls of the
5967 * same names instead of the more-portable versions of the same
5968 * functionality found in the Process,
5969 * Process::UID, and Process::GID modules.
5972 #if defined(HAVE_PWD_H)
5973 static rb_uid_t
5974 obj2uid(VALUE id
5975 # ifdef USE_GETPWNAM_R
5976 , VALUE *getpw_tmp
5977 # endif
5980 rb_uid_t uid;
5981 VALUE tmp;
5983 if (FIXNUM_P(id) || NIL_P(tmp = rb_check_string_type(id))) {
5984 uid = NUM2UIDT(id);
5986 else {
5987 const char *usrname = StringValueCStr(id);
5988 struct passwd *pwptr;
5989 #ifdef USE_GETPWNAM_R
5990 struct passwd pwbuf;
5991 char *getpw_buf;
5992 long getpw_buf_len;
5993 int e;
5994 if (!*getpw_tmp) {
5995 getpw_buf_len = GETPW_R_SIZE_INIT;
5996 if (getpw_buf_len < 0) getpw_buf_len = GETPW_R_SIZE_DEFAULT;
5997 *getpw_tmp = rb_str_tmp_new(getpw_buf_len);
5999 getpw_buf = RSTRING_PTR(*getpw_tmp);
6000 getpw_buf_len = rb_str_capacity(*getpw_tmp);
6001 rb_str_set_len(*getpw_tmp, getpw_buf_len);
6002 errno = 0;
6003 while ((e = getpwnam_r(usrname, &pwbuf, getpw_buf, getpw_buf_len, &pwptr)) != 0) {
6004 if (e != ERANGE || getpw_buf_len >= GETPW_R_SIZE_LIMIT) {
6005 rb_str_resize(*getpw_tmp, 0);
6006 rb_syserr_fail(e, "getpwnam_r");
6008 rb_str_modify_expand(*getpw_tmp, getpw_buf_len);
6009 getpw_buf = RSTRING_PTR(*getpw_tmp);
6010 getpw_buf_len = rb_str_capacity(*getpw_tmp);
6012 #else
6013 pwptr = getpwnam(usrname);
6014 #endif
6015 if (!pwptr) {
6016 #ifndef USE_GETPWNAM_R
6017 endpwent();
6018 #endif
6019 rb_raise(rb_eArgError, "can't find user for %"PRIsVALUE, id);
6021 uid = pwptr->pw_uid;
6022 #ifndef USE_GETPWNAM_R
6023 endpwent();
6024 #endif
6026 return uid;
6029 # ifdef p_uid_from_name
6031 * call-seq:
6032 * Process::UID.from_name(name) -> uid
6034 * Get the user ID by the _name_.
6035 * If the user is not found, +ArgumentError+ will be raised.
6037 * Process::UID.from_name("root") #=> 0
6038 * Process::UID.from_name("nosuchuser") #=> can't find user for nosuchuser (ArgumentError)
6041 static VALUE
6042 p_uid_from_name(VALUE self, VALUE id)
6044 return UIDT2NUM(OBJ2UID(id));
6046 # endif
6047 #endif
6049 #if defined(HAVE_GRP_H)
6050 static rb_gid_t
6051 obj2gid(VALUE id
6052 # ifdef USE_GETGRNAM_R
6053 , VALUE *getgr_tmp
6054 # endif
6057 rb_gid_t gid;
6058 VALUE tmp;
6060 if (FIXNUM_P(id) || NIL_P(tmp = rb_check_string_type(id))) {
6061 gid = NUM2GIDT(id);
6063 else {
6064 const char *grpname = StringValueCStr(id);
6065 struct group *grptr;
6066 #ifdef USE_GETGRNAM_R
6067 struct group grbuf;
6068 char *getgr_buf;
6069 long getgr_buf_len;
6070 int e;
6071 if (!*getgr_tmp) {
6072 getgr_buf_len = GETGR_R_SIZE_INIT;
6073 if (getgr_buf_len < 0) getgr_buf_len = GETGR_R_SIZE_DEFAULT;
6074 *getgr_tmp = rb_str_tmp_new(getgr_buf_len);
6076 getgr_buf = RSTRING_PTR(*getgr_tmp);
6077 getgr_buf_len = rb_str_capacity(*getgr_tmp);
6078 rb_str_set_len(*getgr_tmp, getgr_buf_len);
6079 errno = 0;
6080 while ((e = getgrnam_r(grpname, &grbuf, getgr_buf, getgr_buf_len, &grptr)) != 0) {
6081 if (e != ERANGE || getgr_buf_len >= GETGR_R_SIZE_LIMIT) {
6082 rb_str_resize(*getgr_tmp, 0);
6083 rb_syserr_fail(e, "getgrnam_r");
6085 rb_str_modify_expand(*getgr_tmp, getgr_buf_len);
6086 getgr_buf = RSTRING_PTR(*getgr_tmp);
6087 getgr_buf_len = rb_str_capacity(*getgr_tmp);
6089 #elif defined(HAVE_GETGRNAM)
6090 grptr = getgrnam(grpname);
6091 #else
6092 grptr = NULL;
6093 #endif
6094 if (!grptr) {
6095 #if !defined(USE_GETGRNAM_R) && defined(HAVE_ENDGRENT)
6096 endgrent();
6097 #endif
6098 rb_raise(rb_eArgError, "can't find group for %"PRIsVALUE, id);
6100 gid = grptr->gr_gid;
6101 #if !defined(USE_GETGRNAM_R) && defined(HAVE_ENDGRENT)
6102 endgrent();
6103 #endif
6105 return gid;
6108 # ifdef p_gid_from_name
6110 * call-seq:
6111 * Process::GID.from_name(name) -> gid
6113 * Get the group ID by the _name_.
6114 * If the group is not found, +ArgumentError+ will be raised.
6116 * Process::GID.from_name("wheel") #=> 0
6117 * Process::GID.from_name("nosuchgroup") #=> can't find group for nosuchgroup (ArgumentError)
6120 static VALUE
6121 p_gid_from_name(VALUE self, VALUE id)
6123 return GIDT2NUM(OBJ2GID(id));
6125 # endif
6126 #endif
6128 #if defined HAVE_SETUID
6130 * call-seq:
6131 * Process::Sys.setuid(user) -> nil
6133 * Set the user ID of the current process to _user_. Not
6134 * available on all platforms.
6138 static VALUE
6139 p_sys_setuid(VALUE obj, VALUE id)
6141 check_uid_switch();
6142 if (setuid(OBJ2UID(id)) != 0) rb_sys_fail(0);
6143 return Qnil;
6145 #else
6146 #define p_sys_setuid rb_f_notimplement
6147 #endif
6150 #if defined HAVE_SETRUID
6152 * call-seq:
6153 * Process::Sys.setruid(user) -> nil
6155 * Set the real user ID of the calling process to _user_.
6156 * Not available on all platforms.
6160 static VALUE
6161 p_sys_setruid(VALUE obj, VALUE id)
6163 check_uid_switch();
6164 if (setruid(OBJ2UID(id)) != 0) rb_sys_fail(0);
6165 return Qnil;
6167 #else
6168 #define p_sys_setruid rb_f_notimplement
6169 #endif
6172 #if defined HAVE_SETEUID
6174 * call-seq:
6175 * Process::Sys.seteuid(user) -> nil
6177 * Set the effective user ID of the calling process to
6178 * _user_. Not available on all platforms.
6182 static VALUE
6183 p_sys_seteuid(VALUE obj, VALUE id)
6185 check_uid_switch();
6186 if (seteuid(OBJ2UID(id)) != 0) rb_sys_fail(0);
6187 return Qnil;
6189 #else
6190 #define p_sys_seteuid rb_f_notimplement
6191 #endif
6194 #if defined HAVE_SETREUID
6196 * call-seq:
6197 * Process::Sys.setreuid(rid, eid) -> nil
6199 * Sets the (user) real and/or effective user IDs of the current
6200 * process to _rid_ and _eid_, respectively. A value of
6201 * <code>-1</code> for either means to leave that ID unchanged. Not
6202 * available on all platforms.
6206 static VALUE
6207 p_sys_setreuid(VALUE obj, VALUE rid, VALUE eid)
6209 rb_uid_t ruid, euid;
6210 PREPARE_GETPWNAM;
6211 check_uid_switch();
6212 ruid = OBJ2UID1(rid);
6213 euid = OBJ2UID1(eid);
6214 FINISH_GETPWNAM;
6215 if (setreuid(ruid, euid) != 0) rb_sys_fail(0);
6216 return Qnil;
6218 #else
6219 #define p_sys_setreuid rb_f_notimplement
6220 #endif
6223 #if defined HAVE_SETRESUID
6225 * call-seq:
6226 * Process::Sys.setresuid(rid, eid, sid) -> nil
6228 * Sets the (user) real, effective, and saved user IDs of the
6229 * current process to _rid_, _eid_, and _sid_ respectively. A
6230 * value of <code>-1</code> for any value means to
6231 * leave that ID unchanged. Not available on all platforms.
6235 static VALUE
6236 p_sys_setresuid(VALUE obj, VALUE rid, VALUE eid, VALUE sid)
6238 rb_uid_t ruid, euid, suid;
6239 PREPARE_GETPWNAM;
6240 check_uid_switch();
6241 ruid = OBJ2UID1(rid);
6242 euid = OBJ2UID1(eid);
6243 suid = OBJ2UID1(sid);
6244 FINISH_GETPWNAM;
6245 if (setresuid(ruid, euid, suid) != 0) rb_sys_fail(0);
6246 return Qnil;
6248 #else
6249 #define p_sys_setresuid rb_f_notimplement
6250 #endif
6254 * call-seq:
6255 * Process.uid -> integer
6256 * Process::UID.rid -> integer
6257 * Process::Sys.getuid -> integer
6259 * Returns the (real) user ID of the current process.
6261 * Process.uid # => 1000
6265 static VALUE
6266 proc_getuid(VALUE obj)
6268 rb_uid_t uid = getuid();
6269 return UIDT2NUM(uid);
6273 #if defined(HAVE_SETRESUID) || defined(HAVE_SETREUID) || defined(HAVE_SETRUID) || defined(HAVE_SETUID)
6275 * call-seq:
6276 * Process.uid = new_uid -> new_uid
6278 * Sets the (user) user ID for the current process to +new_uid+:
6280 * Process.uid = 1000 # => 1000
6282 * Not available on all platforms.
6285 static VALUE
6286 proc_setuid(VALUE obj, VALUE id)
6288 rb_uid_t uid;
6290 check_uid_switch();
6292 uid = OBJ2UID(id);
6293 #if defined(HAVE_SETRESUID)
6294 if (setresuid(uid, -1, -1) < 0) rb_sys_fail(0);
6295 #elif defined HAVE_SETREUID
6296 if (setreuid(uid, -1) < 0) rb_sys_fail(0);
6297 #elif defined HAVE_SETRUID
6298 if (setruid(uid) < 0) rb_sys_fail(0);
6299 #elif defined HAVE_SETUID
6301 if (geteuid() == uid) {
6302 if (setuid(uid) < 0) rb_sys_fail(0);
6304 else {
6305 rb_notimplement();
6308 #endif
6309 return id;
6311 #else
6312 #define proc_setuid rb_f_notimplement
6313 #endif
6316 /********************************************************************
6318 * Document-class: Process::UID
6320 * The Process::UID module contains a collection of
6321 * module functions which can be used to portably get, set, and
6322 * switch the current process's real, effective, and saved user IDs.
6326 static rb_uid_t SAVED_USER_ID = -1;
6328 #ifdef BROKEN_SETREUID
6330 setreuid(rb_uid_t ruid, rb_uid_t euid)
6332 if (ruid != (rb_uid_t)-1 && ruid != getuid()) {
6333 if (euid == (rb_uid_t)-1) euid = geteuid();
6334 if (setuid(ruid) < 0) return -1;
6336 if (euid != (rb_uid_t)-1 && euid != geteuid()) {
6337 if (seteuid(euid) < 0) return -1;
6339 return 0;
6341 #endif
6344 * call-seq:
6345 * Process::UID.change_privilege(user) -> integer
6347 * Change the current process's real and effective user ID to that
6348 * specified by _user_. Returns the new user ID. Not
6349 * available on all platforms.
6351 * [Process.uid, Process.euid] #=> [0, 0]
6352 * Process::UID.change_privilege(31) #=> 31
6353 * [Process.uid, Process.euid] #=> [31, 31]
6356 static VALUE
6357 p_uid_change_privilege(VALUE obj, VALUE id)
6359 rb_uid_t uid;
6361 check_uid_switch();
6363 uid = OBJ2UID(id);
6365 if (geteuid() == 0) { /* root-user */
6366 #if defined(HAVE_SETRESUID)
6367 if (setresuid(uid, uid, uid) < 0) rb_sys_fail(0);
6368 SAVED_USER_ID = uid;
6369 #elif defined(HAVE_SETUID)
6370 if (setuid(uid) < 0) rb_sys_fail(0);
6371 SAVED_USER_ID = uid;
6372 #elif defined(HAVE_SETREUID) && !defined(OBSOLETE_SETREUID)
6373 if (getuid() == uid) {
6374 if (SAVED_USER_ID == uid) {
6375 if (setreuid(-1, uid) < 0) rb_sys_fail(0);
6377 else {
6378 if (uid == 0) { /* (r,e,s) == (root, root, x) */
6379 if (setreuid(-1, SAVED_USER_ID) < 0) rb_sys_fail(0);
6380 if (setreuid(SAVED_USER_ID, 0) < 0) rb_sys_fail(0);
6381 SAVED_USER_ID = 0; /* (r,e,s) == (x, root, root) */
6382 if (setreuid(uid, uid) < 0) rb_sys_fail(0);
6383 SAVED_USER_ID = uid;
6385 else {
6386 if (setreuid(0, -1) < 0) rb_sys_fail(0);
6387 SAVED_USER_ID = 0;
6388 if (setreuid(uid, uid) < 0) rb_sys_fail(0);
6389 SAVED_USER_ID = uid;
6393 else {
6394 if (setreuid(uid, uid) < 0) rb_sys_fail(0);
6395 SAVED_USER_ID = uid;
6397 #elif defined(HAVE_SETRUID) && defined(HAVE_SETEUID)
6398 if (getuid() == uid) {
6399 if (SAVED_USER_ID == uid) {
6400 if (seteuid(uid) < 0) rb_sys_fail(0);
6402 else {
6403 if (uid == 0) {
6404 if (setruid(SAVED_USER_ID) < 0) rb_sys_fail(0);
6405 SAVED_USER_ID = 0;
6406 if (setruid(0) < 0) rb_sys_fail(0);
6408 else {
6409 if (setruid(0) < 0) rb_sys_fail(0);
6410 SAVED_USER_ID = 0;
6411 if (seteuid(uid) < 0) rb_sys_fail(0);
6412 if (setruid(uid) < 0) rb_sys_fail(0);
6413 SAVED_USER_ID = uid;
6417 else {
6418 if (seteuid(uid) < 0) rb_sys_fail(0);
6419 if (setruid(uid) < 0) rb_sys_fail(0);
6420 SAVED_USER_ID = uid;
6422 #else
6423 (void)uid;
6424 rb_notimplement();
6425 #endif
6427 else { /* unprivileged user */
6428 #if defined(HAVE_SETRESUID)
6429 if (setresuid((getuid() == uid)? (rb_uid_t)-1: uid,
6430 (geteuid() == uid)? (rb_uid_t)-1: uid,
6431 (SAVED_USER_ID == uid)? (rb_uid_t)-1: uid) < 0) rb_sys_fail(0);
6432 SAVED_USER_ID = uid;
6433 #elif defined(HAVE_SETREUID) && !defined(OBSOLETE_SETREUID)
6434 if (SAVED_USER_ID == uid) {
6435 if (setreuid((getuid() == uid)? (rb_uid_t)-1: uid,
6436 (geteuid() == uid)? (rb_uid_t)-1: uid) < 0)
6437 rb_sys_fail(0);
6439 else if (getuid() != uid) {
6440 if (setreuid(uid, (geteuid() == uid)? (rb_uid_t)-1: uid) < 0)
6441 rb_sys_fail(0);
6442 SAVED_USER_ID = uid;
6444 else if (/* getuid() == uid && */ geteuid() != uid) {
6445 if (setreuid(geteuid(), uid) < 0) rb_sys_fail(0);
6446 SAVED_USER_ID = uid;
6447 if (setreuid(uid, -1) < 0) rb_sys_fail(0);
6449 else { /* getuid() == uid && geteuid() == uid */
6450 if (setreuid(-1, SAVED_USER_ID) < 0) rb_sys_fail(0);
6451 if (setreuid(SAVED_USER_ID, uid) < 0) rb_sys_fail(0);
6452 SAVED_USER_ID = uid;
6453 if (setreuid(uid, -1) < 0) rb_sys_fail(0);
6455 #elif defined(HAVE_SETRUID) && defined(HAVE_SETEUID)
6456 if (SAVED_USER_ID == uid) {
6457 if (geteuid() != uid && seteuid(uid) < 0) rb_sys_fail(0);
6458 if (getuid() != uid && setruid(uid) < 0) rb_sys_fail(0);
6460 else if (/* SAVED_USER_ID != uid && */ geteuid() == uid) {
6461 if (getuid() != uid) {
6462 if (setruid(uid) < 0) rb_sys_fail(0);
6463 SAVED_USER_ID = uid;
6465 else {
6466 if (setruid(SAVED_USER_ID) < 0) rb_sys_fail(0);
6467 SAVED_USER_ID = uid;
6468 if (setruid(uid) < 0) rb_sys_fail(0);
6471 else if (/* geteuid() != uid && */ getuid() == uid) {
6472 if (seteuid(uid) < 0) rb_sys_fail(0);
6473 if (setruid(SAVED_USER_ID) < 0) rb_sys_fail(0);
6474 SAVED_USER_ID = uid;
6475 if (setruid(uid) < 0) rb_sys_fail(0);
6477 else {
6478 rb_syserr_fail(EPERM, 0);
6480 #elif defined HAVE_44BSD_SETUID
6481 if (getuid() == uid) {
6482 /* (r,e,s)==(uid,?,?) ==> (uid,uid,uid) */
6483 if (setuid(uid) < 0) rb_sys_fail(0);
6484 SAVED_USER_ID = uid;
6486 else {
6487 rb_syserr_fail(EPERM, 0);
6489 #elif defined HAVE_SETEUID
6490 if (getuid() == uid && SAVED_USER_ID == uid) {
6491 if (seteuid(uid) < 0) rb_sys_fail(0);
6493 else {
6494 rb_syserr_fail(EPERM, 0);
6496 #elif defined HAVE_SETUID
6497 if (getuid() == uid && SAVED_USER_ID == uid) {
6498 if (setuid(uid) < 0) rb_sys_fail(0);
6500 else {
6501 rb_syserr_fail(EPERM, 0);
6503 #else
6504 rb_notimplement();
6505 #endif
6507 return id;
6512 #if defined HAVE_SETGID
6514 * call-seq:
6515 * Process::Sys.setgid(group) -> nil
6517 * Set the group ID of the current process to _group_. Not
6518 * available on all platforms.
6522 static VALUE
6523 p_sys_setgid(VALUE obj, VALUE id)
6525 check_gid_switch();
6526 if (setgid(OBJ2GID(id)) != 0) rb_sys_fail(0);
6527 return Qnil;
6529 #else
6530 #define p_sys_setgid rb_f_notimplement
6531 #endif
6534 #if defined HAVE_SETRGID
6536 * call-seq:
6537 * Process::Sys.setrgid(group) -> nil
6539 * Set the real group ID of the calling process to _group_.
6540 * Not available on all platforms.
6544 static VALUE
6545 p_sys_setrgid(VALUE obj, VALUE id)
6547 check_gid_switch();
6548 if (setrgid(OBJ2GID(id)) != 0) rb_sys_fail(0);
6549 return Qnil;
6551 #else
6552 #define p_sys_setrgid rb_f_notimplement
6553 #endif
6556 #if defined HAVE_SETEGID
6558 * call-seq:
6559 * Process::Sys.setegid(group) -> nil
6561 * Set the effective group ID of the calling process to
6562 * _group_. Not available on all platforms.
6566 static VALUE
6567 p_sys_setegid(VALUE obj, VALUE id)
6569 check_gid_switch();
6570 if (setegid(OBJ2GID(id)) != 0) rb_sys_fail(0);
6571 return Qnil;
6573 #else
6574 #define p_sys_setegid rb_f_notimplement
6575 #endif
6578 #if defined HAVE_SETREGID
6580 * call-seq:
6581 * Process::Sys.setregid(rid, eid) -> nil
6583 * Sets the (group) real and/or effective group IDs of the current
6584 * process to <em>rid</em> and <em>eid</em>, respectively. A value of
6585 * <code>-1</code> for either means to leave that ID unchanged. Not
6586 * available on all platforms.
6590 static VALUE
6591 p_sys_setregid(VALUE obj, VALUE rid, VALUE eid)
6593 rb_gid_t rgid, egid;
6594 check_gid_switch();
6595 rgid = OBJ2GID(rid);
6596 egid = OBJ2GID(eid);
6597 if (setregid(rgid, egid) != 0) rb_sys_fail(0);
6598 return Qnil;
6600 #else
6601 #define p_sys_setregid rb_f_notimplement
6602 #endif
6604 #if defined HAVE_SETRESGID
6606 * call-seq:
6607 * Process::Sys.setresgid(rid, eid, sid) -> nil
6609 * Sets the (group) real, effective, and saved user IDs of the
6610 * current process to <em>rid</em>, <em>eid</em>, and <em>sid</em>
6611 * respectively. A value of <code>-1</code> for any value means to
6612 * leave that ID unchanged. Not available on all platforms.
6616 static VALUE
6617 p_sys_setresgid(VALUE obj, VALUE rid, VALUE eid, VALUE sid)
6619 rb_gid_t rgid, egid, sgid;
6620 check_gid_switch();
6621 rgid = OBJ2GID(rid);
6622 egid = OBJ2GID(eid);
6623 sgid = OBJ2GID(sid);
6624 if (setresgid(rgid, egid, sgid) != 0) rb_sys_fail(0);
6625 return Qnil;
6627 #else
6628 #define p_sys_setresgid rb_f_notimplement
6629 #endif
6632 #if defined HAVE_ISSETUGID
6634 * call-seq:
6635 * Process::Sys.issetugid -> true or false
6637 * Returns +true+ if the process was created as a result
6638 * of an execve(2) system call which had either of the setuid or
6639 * setgid bits set (and extra privileges were given as a result) or
6640 * if it has changed any of its real, effective or saved user or
6641 * group IDs since it began execution.
6645 static VALUE
6646 p_sys_issetugid(VALUE obj)
6648 return RBOOL(issetugid());
6650 #else
6651 #define p_sys_issetugid rb_f_notimplement
6652 #endif
6656 * call-seq:
6657 * Process.gid -> integer
6658 * Process::GID.rid -> integer
6659 * Process::Sys.getgid -> integer
6661 * Returns the (real) group ID for the current process:
6663 * Process.gid # => 1000
6667 static VALUE
6668 proc_getgid(VALUE obj)
6670 rb_gid_t gid = getgid();
6671 return GIDT2NUM(gid);
6675 #if defined(HAVE_SETRESGID) || defined(HAVE_SETREGID) || defined(HAVE_SETRGID) || defined(HAVE_SETGID)
6677 * call-seq:
6678 * Process.gid = new_gid -> new_gid
6680 * Sets the group ID for the current process to +new_gid+:
6682 * Process.gid = 1000 # => 1000
6686 static VALUE
6687 proc_setgid(VALUE obj, VALUE id)
6689 rb_gid_t gid;
6691 check_gid_switch();
6693 gid = OBJ2GID(id);
6694 #if defined(HAVE_SETRESGID)
6695 if (setresgid(gid, -1, -1) < 0) rb_sys_fail(0);
6696 #elif defined HAVE_SETREGID
6697 if (setregid(gid, -1) < 0) rb_sys_fail(0);
6698 #elif defined HAVE_SETRGID
6699 if (setrgid(gid) < 0) rb_sys_fail(0);
6700 #elif defined HAVE_SETGID
6702 if (getegid() == gid) {
6703 if (setgid(gid) < 0) rb_sys_fail(0);
6705 else {
6706 rb_notimplement();
6709 #endif
6710 return GIDT2NUM(gid);
6712 #else
6713 #define proc_setgid rb_f_notimplement
6714 #endif
6717 #if defined(_SC_NGROUPS_MAX) || defined(NGROUPS_MAX)
6719 * Maximum supplementary groups are platform dependent.
6720 * FWIW, 65536 is enough big for our supported OSs.
6722 * OS Name max groups
6723 * -----------------------------------------------
6724 * Linux Kernel >= 2.6.3 65536
6725 * Linux Kernel < 2.6.3 32
6726 * IBM AIX 5.2 64
6727 * IBM AIX 5.3 ... 6.1 128
6728 * IBM AIX 7.1 128 (can be configured to be up to 2048)
6729 * OpenBSD, NetBSD 16
6730 * FreeBSD < 8.0 16
6731 * FreeBSD >=8.0 1023
6732 * Darwin (Mac OS X) 16
6733 * Sun Solaris 7,8,9,10 16
6734 * Sun Solaris 11 / OpenSolaris 1024
6735 * Windows 1015
6737 static int _maxgroups = -1;
6738 static int
6739 get_sc_ngroups_max(void)
6741 #ifdef _SC_NGROUPS_MAX
6742 return (int)sysconf(_SC_NGROUPS_MAX);
6743 #elif defined(NGROUPS_MAX)
6744 return (int)NGROUPS_MAX;
6745 #else
6746 return -1;
6747 #endif
6749 static int
6750 maxgroups(void)
6752 if (_maxgroups < 0) {
6753 _maxgroups = get_sc_ngroups_max();
6754 if (_maxgroups < 0)
6755 _maxgroups = RB_MAX_GROUPS;
6758 return _maxgroups;
6760 #endif
6764 #ifdef HAVE_GETGROUPS
6766 * call-seq:
6767 * Process.groups -> array
6769 * Returns an array of the group IDs
6770 * in the supplemental group access list for the current process:
6772 * Process.groups # => [4, 24, 27, 30, 46, 122, 135, 136, 1000]
6774 * These properties of the returned array are system-dependent:
6776 * - Whether (and how) the array is sorted.
6777 * - Whether the array includes effective group IDs.
6778 * - Whether the array includes duplicate group IDs.
6779 * - Whether the array size exceeds the value of Process.maxgroups.
6781 * Use this call to get a sorted and unique array:
6783 * Process.groups.uniq.sort
6787 static VALUE
6788 proc_getgroups(VALUE obj)
6790 VALUE ary, tmp;
6791 int i, ngroups;
6792 rb_gid_t *groups;
6794 ngroups = getgroups(0, NULL);
6795 if (ngroups == -1)
6796 rb_sys_fail(0);
6798 groups = ALLOCV_N(rb_gid_t, tmp, ngroups);
6800 ngroups = getgroups(ngroups, groups);
6801 if (ngroups == -1)
6802 rb_sys_fail(0);
6804 ary = rb_ary_new();
6805 for (i = 0; i < ngroups; i++)
6806 rb_ary_push(ary, GIDT2NUM(groups[i]));
6808 ALLOCV_END(tmp);
6810 return ary;
6812 #else
6813 #define proc_getgroups rb_f_notimplement
6814 #endif
6817 #ifdef HAVE_SETGROUPS
6819 * call-seq:
6820 * Process.groups = new_groups -> new_groups
6822 * Sets the supplemental group access list to the given
6823 * array of group IDs.
6825 * Process.groups # => [0, 1, 2, 3, 4, 6, 10, 11, 20, 26, 27]
6826 * Process.groups = [27, 6, 10, 11] # => [27, 6, 10, 11]
6827 * Process.groups # => [27, 6, 10, 11]
6831 static VALUE
6832 proc_setgroups(VALUE obj, VALUE ary)
6834 int ngroups, i;
6835 rb_gid_t *groups;
6836 VALUE tmp;
6837 PREPARE_GETGRNAM;
6839 Check_Type(ary, T_ARRAY);
6841 ngroups = RARRAY_LENINT(ary);
6842 if (ngroups > maxgroups())
6843 rb_raise(rb_eArgError, "too many groups, %d max", maxgroups());
6845 groups = ALLOCV_N(rb_gid_t, tmp, ngroups);
6847 for (i = 0; i < ngroups; i++) {
6848 VALUE g = RARRAY_AREF(ary, i);
6850 groups[i] = OBJ2GID1(g);
6852 FINISH_GETGRNAM;
6854 if (setgroups(ngroups, groups) == -1) /* ngroups <= maxgroups */
6855 rb_sys_fail(0);
6857 ALLOCV_END(tmp);
6859 return proc_getgroups(obj);
6861 #else
6862 #define proc_setgroups rb_f_notimplement
6863 #endif
6866 #ifdef HAVE_INITGROUPS
6868 * call-seq:
6869 * Process.initgroups(username, gid) -> array
6871 * Sets the supplemental group access list;
6872 * the new list includes:
6874 * - The group IDs of those groups to which the user given by +username+ belongs.
6875 * - The group ID +gid+.
6877 * Example:
6879 * Process.groups # => [0, 1, 2, 3, 4, 6, 10, 11, 20, 26, 27]
6880 * Process.initgroups('me', 30) # => [30, 6, 10, 11]
6881 * Process.groups # => [30, 6, 10, 11]
6883 * Not available on all platforms.
6886 static VALUE
6887 proc_initgroups(VALUE obj, VALUE uname, VALUE base_grp)
6889 if (initgroups(StringValueCStr(uname), OBJ2GID(base_grp)) != 0) {
6890 rb_sys_fail(0);
6892 return proc_getgroups(obj);
6894 #else
6895 #define proc_initgroups rb_f_notimplement
6896 #endif
6898 #if defined(_SC_NGROUPS_MAX) || defined(NGROUPS_MAX)
6900 * call-seq:
6901 * Process.maxgroups -> integer
6903 * Returns the maximum number of group IDs allowed
6904 * in the supplemental group access list:
6906 * Process.maxgroups # => 32
6910 static VALUE
6911 proc_getmaxgroups(VALUE obj)
6913 return INT2FIX(maxgroups());
6915 #else
6916 #define proc_getmaxgroups rb_f_notimplement
6917 #endif
6919 #ifdef HAVE_SETGROUPS
6921 * call-seq:
6922 * Process.maxgroups = new_max -> new_max
6924 * Sets the maximum number of group IDs allowed
6925 * in the supplemental group access list.
6928 static VALUE
6929 proc_setmaxgroups(VALUE obj, VALUE val)
6931 int ngroups = FIX2INT(val);
6932 int ngroups_max = get_sc_ngroups_max();
6934 if (ngroups <= 0)
6935 rb_raise(rb_eArgError, "maxgroups %d should be positive", ngroups);
6937 if (ngroups > RB_MAX_GROUPS)
6938 ngroups = RB_MAX_GROUPS;
6940 if (ngroups_max > 0 && ngroups > ngroups_max)
6941 ngroups = ngroups_max;
6943 _maxgroups = ngroups;
6945 return INT2FIX(_maxgroups);
6947 #else
6948 #define proc_setmaxgroups rb_f_notimplement
6949 #endif
6951 #if defined(HAVE_DAEMON) || (defined(HAVE_WORKING_FORK) && defined(HAVE_SETSID))
6952 static int rb_daemon(int nochdir, int noclose);
6955 * call-seq:
6956 * Process.daemon(nochdir = nil, noclose = nil) -> 0
6958 * Detaches the current process from its controlling terminal
6959 * and runs it in the background as system daemon;
6960 * returns zero.
6962 * By default:
6964 * - Changes the current working directory to the root directory.
6965 * - Redirects $stdin, $stdout, and $stderr to the null device.
6967 * If optional argument +nochdir+ is +true+,
6968 * does not change the current working directory.
6970 * If optional argument +noclose+ is +true+,
6971 * does not redirect $stdin, $stdout, or $stderr.
6974 static VALUE
6975 proc_daemon(int argc, VALUE *argv, VALUE _)
6977 int n, nochdir = FALSE, noclose = FALSE;
6979 switch (rb_check_arity(argc, 0, 2)) {
6980 case 2: noclose = TO_BOOL(argv[1], "noclose");
6981 case 1: nochdir = TO_BOOL(argv[0], "nochdir");
6984 prefork();
6985 n = rb_daemon(nochdir, noclose);
6986 if (n < 0) rb_sys_fail("daemon");
6987 return INT2FIX(n);
6990 extern const char ruby_null_device[];
6992 static int
6993 rb_daemon(int nochdir, int noclose)
6995 int err = 0;
6996 #ifdef HAVE_DAEMON
6997 before_fork_ruby();
6998 err = daemon(nochdir, noclose);
6999 after_fork_ruby(0);
7000 #else
7001 int n;
7003 switch (rb_fork_ruby(NULL)) {
7004 case -1: return -1;
7005 case 0: break;
7006 default: _exit(EXIT_SUCCESS);
7009 /* ignore EPERM which means already being process-leader */
7010 if (setsid() < 0) (void)0;
7012 if (!nochdir)
7013 err = chdir("/");
7015 if (!noclose && (n = rb_cloexec_open(ruby_null_device, O_RDWR, 0)) != -1) {
7016 rb_update_max_fd(n);
7017 (void)dup2(n, 0);
7018 (void)dup2(n, 1);
7019 (void)dup2(n, 2);
7020 if (n > 2)
7021 (void)close (n);
7023 #endif
7024 return err;
7026 #else
7027 #define proc_daemon rb_f_notimplement
7028 #endif
7030 /********************************************************************
7032 * Document-class: Process::GID
7034 * The Process::GID module contains a collection of
7035 * module functions which can be used to portably get, set, and
7036 * switch the current process's real, effective, and saved group IDs.
7040 static rb_gid_t SAVED_GROUP_ID = -1;
7042 #ifdef BROKEN_SETREGID
7044 setregid(rb_gid_t rgid, rb_gid_t egid)
7046 if (rgid != (rb_gid_t)-1 && rgid != getgid()) {
7047 if (egid == (rb_gid_t)-1) egid = getegid();
7048 if (setgid(rgid) < 0) return -1;
7050 if (egid != (rb_gid_t)-1 && egid != getegid()) {
7051 if (setegid(egid) < 0) return -1;
7053 return 0;
7055 #endif
7058 * call-seq:
7059 * Process::GID.change_privilege(group) -> integer
7061 * Change the current process's real and effective group ID to that
7062 * specified by _group_. Returns the new group ID. Not
7063 * available on all platforms.
7065 * [Process.gid, Process.egid] #=> [0, 0]
7066 * Process::GID.change_privilege(33) #=> 33
7067 * [Process.gid, Process.egid] #=> [33, 33]
7070 static VALUE
7071 p_gid_change_privilege(VALUE obj, VALUE id)
7073 rb_gid_t gid;
7075 check_gid_switch();
7077 gid = OBJ2GID(id);
7079 if (geteuid() == 0) { /* root-user */
7080 #if defined(HAVE_SETRESGID)
7081 if (setresgid(gid, gid, gid) < 0) rb_sys_fail(0);
7082 SAVED_GROUP_ID = gid;
7083 #elif defined HAVE_SETGID
7084 if (setgid(gid) < 0) rb_sys_fail(0);
7085 SAVED_GROUP_ID = gid;
7086 #elif defined(HAVE_SETREGID) && !defined(OBSOLETE_SETREGID)
7087 if (getgid() == gid) {
7088 if (SAVED_GROUP_ID == gid) {
7089 if (setregid(-1, gid) < 0) rb_sys_fail(0);
7091 else {
7092 if (gid == 0) { /* (r,e,s) == (root, y, x) */
7093 if (setregid(-1, SAVED_GROUP_ID) < 0) rb_sys_fail(0);
7094 if (setregid(SAVED_GROUP_ID, 0) < 0) rb_sys_fail(0);
7095 SAVED_GROUP_ID = 0; /* (r,e,s) == (x, root, root) */
7096 if (setregid(gid, gid) < 0) rb_sys_fail(0);
7097 SAVED_GROUP_ID = gid;
7099 else { /* (r,e,s) == (z, y, x) */
7100 if (setregid(0, 0) < 0) rb_sys_fail(0);
7101 SAVED_GROUP_ID = 0;
7102 if (setregid(gid, gid) < 0) rb_sys_fail(0);
7103 SAVED_GROUP_ID = gid;
7107 else {
7108 if (setregid(gid, gid) < 0) rb_sys_fail(0);
7109 SAVED_GROUP_ID = gid;
7111 #elif defined(HAVE_SETRGID) && defined (HAVE_SETEGID)
7112 if (getgid() == gid) {
7113 if (SAVED_GROUP_ID == gid) {
7114 if (setegid(gid) < 0) rb_sys_fail(0);
7116 else {
7117 if (gid == 0) {
7118 if (setegid(gid) < 0) rb_sys_fail(0);
7119 if (setrgid(SAVED_GROUP_ID) < 0) rb_sys_fail(0);
7120 SAVED_GROUP_ID = 0;
7121 if (setrgid(0) < 0) rb_sys_fail(0);
7123 else {
7124 if (setrgid(0) < 0) rb_sys_fail(0);
7125 SAVED_GROUP_ID = 0;
7126 if (setegid(gid) < 0) rb_sys_fail(0);
7127 if (setrgid(gid) < 0) rb_sys_fail(0);
7128 SAVED_GROUP_ID = gid;
7132 else {
7133 if (setegid(gid) < 0) rb_sys_fail(0);
7134 if (setrgid(gid) < 0) rb_sys_fail(0);
7135 SAVED_GROUP_ID = gid;
7137 #else
7138 rb_notimplement();
7139 #endif
7141 else { /* unprivileged user */
7142 #if defined(HAVE_SETRESGID)
7143 if (setresgid((getgid() == gid)? (rb_gid_t)-1: gid,
7144 (getegid() == gid)? (rb_gid_t)-1: gid,
7145 (SAVED_GROUP_ID == gid)? (rb_gid_t)-1: gid) < 0) rb_sys_fail(0);
7146 SAVED_GROUP_ID = gid;
7147 #elif defined(HAVE_SETREGID) && !defined(OBSOLETE_SETREGID)
7148 if (SAVED_GROUP_ID == gid) {
7149 if (setregid((getgid() == gid)? (rb_uid_t)-1: gid,
7150 (getegid() == gid)? (rb_uid_t)-1: gid) < 0)
7151 rb_sys_fail(0);
7153 else if (getgid() != gid) {
7154 if (setregid(gid, (getegid() == gid)? (rb_uid_t)-1: gid) < 0)
7155 rb_sys_fail(0);
7156 SAVED_GROUP_ID = gid;
7158 else if (/* getgid() == gid && */ getegid() != gid) {
7159 if (setregid(getegid(), gid) < 0) rb_sys_fail(0);
7160 SAVED_GROUP_ID = gid;
7161 if (setregid(gid, -1) < 0) rb_sys_fail(0);
7163 else { /* getgid() == gid && getegid() == gid */
7164 if (setregid(-1, SAVED_GROUP_ID) < 0) rb_sys_fail(0);
7165 if (setregid(SAVED_GROUP_ID, gid) < 0) rb_sys_fail(0);
7166 SAVED_GROUP_ID = gid;
7167 if (setregid(gid, -1) < 0) rb_sys_fail(0);
7169 #elif defined(HAVE_SETRGID) && defined(HAVE_SETEGID)
7170 if (SAVED_GROUP_ID == gid) {
7171 if (getegid() != gid && setegid(gid) < 0) rb_sys_fail(0);
7172 if (getgid() != gid && setrgid(gid) < 0) rb_sys_fail(0);
7174 else if (/* SAVED_GROUP_ID != gid && */ getegid() == gid) {
7175 if (getgid() != gid) {
7176 if (setrgid(gid) < 0) rb_sys_fail(0);
7177 SAVED_GROUP_ID = gid;
7179 else {
7180 if (setrgid(SAVED_GROUP_ID) < 0) rb_sys_fail(0);
7181 SAVED_GROUP_ID = gid;
7182 if (setrgid(gid) < 0) rb_sys_fail(0);
7185 else if (/* getegid() != gid && */ getgid() == gid) {
7186 if (setegid(gid) < 0) rb_sys_fail(0);
7187 if (setrgid(SAVED_GROUP_ID) < 0) rb_sys_fail(0);
7188 SAVED_GROUP_ID = gid;
7189 if (setrgid(gid) < 0) rb_sys_fail(0);
7191 else {
7192 rb_syserr_fail(EPERM, 0);
7194 #elif defined HAVE_44BSD_SETGID
7195 if (getgid() == gid) {
7196 /* (r,e,s)==(gid,?,?) ==> (gid,gid,gid) */
7197 if (setgid(gid) < 0) rb_sys_fail(0);
7198 SAVED_GROUP_ID = gid;
7200 else {
7201 rb_syserr_fail(EPERM, 0);
7203 #elif defined HAVE_SETEGID
7204 if (getgid() == gid && SAVED_GROUP_ID == gid) {
7205 if (setegid(gid) < 0) rb_sys_fail(0);
7207 else {
7208 rb_syserr_fail(EPERM, 0);
7210 #elif defined HAVE_SETGID
7211 if (getgid() == gid && SAVED_GROUP_ID == gid) {
7212 if (setgid(gid) < 0) rb_sys_fail(0);
7214 else {
7215 rb_syserr_fail(EPERM, 0);
7217 #else
7218 (void)gid;
7219 rb_notimplement();
7220 #endif
7222 return id;
7227 * call-seq:
7228 * Process.euid -> integer
7229 * Process::UID.eid -> integer
7230 * Process::Sys.geteuid -> integer
7232 * Returns the effective user ID for the current process.
7234 * Process.euid # => 501
7238 static VALUE
7239 proc_geteuid(VALUE obj)
7241 rb_uid_t euid = geteuid();
7242 return UIDT2NUM(euid);
7245 #if defined(HAVE_SETRESUID) || defined(HAVE_SETREUID) || defined(HAVE_SETEUID) || defined(HAVE_SETUID) || defined(_POSIX_SAVED_IDS)
7246 static void
7247 proc_seteuid(rb_uid_t uid)
7249 #if defined(HAVE_SETRESUID)
7250 if (setresuid(-1, uid, -1) < 0) rb_sys_fail(0);
7251 #elif defined HAVE_SETREUID
7252 if (setreuid(-1, uid) < 0) rb_sys_fail(0);
7253 #elif defined HAVE_SETEUID
7254 if (seteuid(uid) < 0) rb_sys_fail(0);
7255 #elif defined HAVE_SETUID
7256 if (uid == getuid()) {
7257 if (setuid(uid) < 0) rb_sys_fail(0);
7259 else {
7260 rb_notimplement();
7262 #else
7263 rb_notimplement();
7264 #endif
7266 #endif
7268 #if defined(HAVE_SETRESUID) || defined(HAVE_SETREUID) || defined(HAVE_SETEUID) || defined(HAVE_SETUID)
7270 * call-seq:
7271 * Process.euid = new_euid -> new_euid
7273 * Sets the effective user ID for the current process.
7275 * Not available on all platforms.
7278 static VALUE
7279 proc_seteuid_m(VALUE mod, VALUE euid)
7281 check_uid_switch();
7282 proc_seteuid(OBJ2UID(euid));
7283 return euid;
7285 #else
7286 #define proc_seteuid_m rb_f_notimplement
7287 #endif
7289 static rb_uid_t
7290 rb_seteuid_core(rb_uid_t euid)
7292 #if defined(HAVE_SETRESUID) || (defined(HAVE_SETREUID) && !defined(OBSOLETE_SETREUID))
7293 rb_uid_t uid;
7294 #endif
7296 check_uid_switch();
7298 #if defined(HAVE_SETRESUID) || (defined(HAVE_SETREUID) && !defined(OBSOLETE_SETREUID))
7299 uid = getuid();
7300 #endif
7302 #if defined(HAVE_SETRESUID)
7303 if (uid != euid) {
7304 if (setresuid(-1,euid,euid) < 0) rb_sys_fail(0);
7305 SAVED_USER_ID = euid;
7307 else {
7308 if (setresuid(-1,euid,-1) < 0) rb_sys_fail(0);
7310 #elif defined(HAVE_SETREUID) && !defined(OBSOLETE_SETREUID)
7311 if (setreuid(-1, euid) < 0) rb_sys_fail(0);
7312 if (uid != euid) {
7313 if (setreuid(euid,uid) < 0) rb_sys_fail(0);
7314 if (setreuid(uid,euid) < 0) rb_sys_fail(0);
7315 SAVED_USER_ID = euid;
7317 #elif defined HAVE_SETEUID
7318 if (seteuid(euid) < 0) rb_sys_fail(0);
7319 #elif defined HAVE_SETUID
7320 if (geteuid() == 0) rb_sys_fail(0);
7321 if (setuid(euid) < 0) rb_sys_fail(0);
7322 #else
7323 rb_notimplement();
7324 #endif
7325 return euid;
7330 * call-seq:
7331 * Process::UID.grant_privilege(user) -> integer
7332 * Process::UID.eid= user -> integer
7334 * Set the effective user ID, and if possible, the saved user ID of
7335 * the process to the given _user_. Returns the new
7336 * effective user ID. Not available on all platforms.
7338 * [Process.uid, Process.euid] #=> [0, 0]
7339 * Process::UID.grant_privilege(31) #=> 31
7340 * [Process.uid, Process.euid] #=> [0, 31]
7343 static VALUE
7344 p_uid_grant_privilege(VALUE obj, VALUE id)
7346 rb_seteuid_core(OBJ2UID(id));
7347 return id;
7352 * call-seq:
7353 * Process.egid -> integer
7354 * Process::GID.eid -> integer
7355 * Process::Sys.geteid -> integer
7357 * Returns the effective group ID for the current process:
7359 * Process.egid # => 500
7361 * Not available on all platforms.
7364 static VALUE
7365 proc_getegid(VALUE obj)
7367 rb_gid_t egid = getegid();
7369 return GIDT2NUM(egid);
7372 #if defined(HAVE_SETRESGID) || defined(HAVE_SETREGID) || defined(HAVE_SETEGID) || defined(HAVE_SETGID) || defined(_POSIX_SAVED_IDS)
7374 * call-seq:
7375 * Process.egid = new_egid -> new_egid
7377 * Sets the effective group ID for the current process.
7379 * Not available on all platforms.
7382 static VALUE
7383 proc_setegid(VALUE obj, VALUE egid)
7385 #if defined(HAVE_SETRESGID) || defined(HAVE_SETREGID) || defined(HAVE_SETEGID) || defined(HAVE_SETGID)
7386 rb_gid_t gid;
7387 #endif
7389 check_gid_switch();
7391 #if defined(HAVE_SETRESGID) || defined(HAVE_SETREGID) || defined(HAVE_SETEGID) || defined(HAVE_SETGID)
7392 gid = OBJ2GID(egid);
7393 #endif
7395 #if defined(HAVE_SETRESGID)
7396 if (setresgid(-1, gid, -1) < 0) rb_sys_fail(0);
7397 #elif defined HAVE_SETREGID
7398 if (setregid(-1, gid) < 0) rb_sys_fail(0);
7399 #elif defined HAVE_SETEGID
7400 if (setegid(gid) < 0) rb_sys_fail(0);
7401 #elif defined HAVE_SETGID
7402 if (gid == getgid()) {
7403 if (setgid(gid) < 0) rb_sys_fail(0);
7405 else {
7406 rb_notimplement();
7408 #else
7409 rb_notimplement();
7410 #endif
7411 return egid;
7413 #endif
7415 #if defined(HAVE_SETRESGID) || defined(HAVE_SETREGID) || defined(HAVE_SETEGID) || defined(HAVE_SETGID)
7416 #define proc_setegid_m proc_setegid
7417 #else
7418 #define proc_setegid_m rb_f_notimplement
7419 #endif
7421 static rb_gid_t
7422 rb_setegid_core(rb_gid_t egid)
7424 #if defined(HAVE_SETRESGID) || (defined(HAVE_SETREGID) && !defined(OBSOLETE_SETREGID))
7425 rb_gid_t gid;
7426 #endif
7428 check_gid_switch();
7430 #if defined(HAVE_SETRESGID) || (defined(HAVE_SETREGID) && !defined(OBSOLETE_SETREGID))
7431 gid = getgid();
7432 #endif
7434 #if defined(HAVE_SETRESGID)
7435 if (gid != egid) {
7436 if (setresgid(-1,egid,egid) < 0) rb_sys_fail(0);
7437 SAVED_GROUP_ID = egid;
7439 else {
7440 if (setresgid(-1,egid,-1) < 0) rb_sys_fail(0);
7442 #elif defined(HAVE_SETREGID) && !defined(OBSOLETE_SETREGID)
7443 if (setregid(-1, egid) < 0) rb_sys_fail(0);
7444 if (gid != egid) {
7445 if (setregid(egid,gid) < 0) rb_sys_fail(0);
7446 if (setregid(gid,egid) < 0) rb_sys_fail(0);
7447 SAVED_GROUP_ID = egid;
7449 #elif defined HAVE_SETEGID
7450 if (setegid(egid) < 0) rb_sys_fail(0);
7451 #elif defined HAVE_SETGID
7452 if (geteuid() == 0 /* root user */) rb_sys_fail(0);
7453 if (setgid(egid) < 0) rb_sys_fail(0);
7454 #else
7455 rb_notimplement();
7456 #endif
7457 return egid;
7462 * call-seq:
7463 * Process::GID.grant_privilege(group) -> integer
7464 * Process::GID.eid = group -> integer
7466 * Set the effective group ID, and if possible, the saved group ID of
7467 * the process to the given _group_. Returns the new
7468 * effective group ID. Not available on all platforms.
7470 * [Process.gid, Process.egid] #=> [0, 0]
7471 * Process::GID.grant_privilege(31) #=> 33
7472 * [Process.gid, Process.egid] #=> [0, 33]
7475 static VALUE
7476 p_gid_grant_privilege(VALUE obj, VALUE id)
7478 rb_setegid_core(OBJ2GID(id));
7479 return id;
7484 * call-seq:
7485 * Process::UID.re_exchangeable? -> true or false
7487 * Returns +true+ if the real and effective user IDs of a
7488 * process may be exchanged on the current platform.
7492 static VALUE
7493 p_uid_exchangeable(VALUE _)
7495 #if defined(HAVE_SETRESUID)
7496 return Qtrue;
7497 #elif defined(HAVE_SETREUID) && !defined(OBSOLETE_SETREUID)
7498 return Qtrue;
7499 #else
7500 return Qfalse;
7501 #endif
7506 * call-seq:
7507 * Process::UID.re_exchange -> integer
7509 * Exchange real and effective user IDs and return the new effective
7510 * user ID. Not available on all platforms.
7512 * [Process.uid, Process.euid] #=> [0, 31]
7513 * Process::UID.re_exchange #=> 0
7514 * [Process.uid, Process.euid] #=> [31, 0]
7517 static VALUE
7518 p_uid_exchange(VALUE obj)
7520 rb_uid_t uid;
7521 #if defined(HAVE_SETRESUID) || (defined(HAVE_SETREUID) && !defined(OBSOLETE_SETREUID))
7522 rb_uid_t euid;
7523 #endif
7525 check_uid_switch();
7527 uid = getuid();
7528 #if defined(HAVE_SETRESUID) || (defined(HAVE_SETREUID) && !defined(OBSOLETE_SETREUID))
7529 euid = geteuid();
7530 #endif
7532 #if defined(HAVE_SETRESUID)
7533 if (setresuid(euid, uid, uid) < 0) rb_sys_fail(0);
7534 SAVED_USER_ID = uid;
7535 #elif defined(HAVE_SETREUID) && !defined(OBSOLETE_SETREUID)
7536 if (setreuid(euid,uid) < 0) rb_sys_fail(0);
7537 SAVED_USER_ID = uid;
7538 #else
7539 rb_notimplement();
7540 #endif
7541 return UIDT2NUM(uid);
7546 * call-seq:
7547 * Process::GID.re_exchangeable? -> true or false
7549 * Returns +true+ if the real and effective group IDs of a
7550 * process may be exchanged on the current platform.
7554 static VALUE
7555 p_gid_exchangeable(VALUE _)
7557 #if defined(HAVE_SETRESGID)
7558 return Qtrue;
7559 #elif defined(HAVE_SETREGID) && !defined(OBSOLETE_SETREGID)
7560 return Qtrue;
7561 #else
7562 return Qfalse;
7563 #endif
7568 * call-seq:
7569 * Process::GID.re_exchange -> integer
7571 * Exchange real and effective group IDs and return the new effective
7572 * group ID. Not available on all platforms.
7574 * [Process.gid, Process.egid] #=> [0, 33]
7575 * Process::GID.re_exchange #=> 0
7576 * [Process.gid, Process.egid] #=> [33, 0]
7579 static VALUE
7580 p_gid_exchange(VALUE obj)
7582 rb_gid_t gid;
7583 #if defined(HAVE_SETRESGID) || (defined(HAVE_SETREGID) && !defined(OBSOLETE_SETREGID))
7584 rb_gid_t egid;
7585 #endif
7587 check_gid_switch();
7589 gid = getgid();
7590 #if defined(HAVE_SETRESGID) || (defined(HAVE_SETREGID) && !defined(OBSOLETE_SETREGID))
7591 egid = getegid();
7592 #endif
7594 #if defined(HAVE_SETRESGID)
7595 if (setresgid(egid, gid, gid) < 0) rb_sys_fail(0);
7596 SAVED_GROUP_ID = gid;
7597 #elif defined(HAVE_SETREGID) && !defined(OBSOLETE_SETREGID)
7598 if (setregid(egid,gid) < 0) rb_sys_fail(0);
7599 SAVED_GROUP_ID = gid;
7600 #else
7601 rb_notimplement();
7602 #endif
7603 return GIDT2NUM(gid);
7606 /* [MG] :FIXME: Is this correct? I'm not sure how to phrase this. */
7609 * call-seq:
7610 * Process::UID.sid_available? -> true or false
7612 * Returns +true+ if the current platform has saved user
7613 * ID functionality.
7617 static VALUE
7618 p_uid_have_saved_id(VALUE _)
7620 #if defined(HAVE_SETRESUID) || defined(HAVE_SETEUID) || defined(_POSIX_SAVED_IDS)
7621 return Qtrue;
7622 #else
7623 return Qfalse;
7624 #endif
7628 #if defined(HAVE_SETRESUID) || defined(HAVE_SETEUID) || defined(_POSIX_SAVED_IDS)
7629 static VALUE
7630 p_uid_sw_ensure(VALUE i)
7632 rb_uid_t id = (rb_uid_t/* narrowing */)i;
7633 under_uid_switch = 0;
7634 id = rb_seteuid_core(id);
7635 return UIDT2NUM(id);
7640 * call-seq:
7641 * Process::UID.switch -> integer
7642 * Process::UID.switch {|| block} -> object
7644 * Switch the effective and real user IDs of the current process. If
7645 * a <em>block</em> is given, the user IDs will be switched back
7646 * after the block is executed. Returns the new effective user ID if
7647 * called without a block, and the return value of the block if one
7648 * is given.
7652 static VALUE
7653 p_uid_switch(VALUE obj)
7655 rb_uid_t uid, euid;
7657 check_uid_switch();
7659 uid = getuid();
7660 euid = geteuid();
7662 if (uid != euid) {
7663 proc_seteuid(uid);
7664 if (rb_block_given_p()) {
7665 under_uid_switch = 1;
7666 return rb_ensure(rb_yield, Qnil, p_uid_sw_ensure, SAVED_USER_ID);
7668 else {
7669 return UIDT2NUM(euid);
7672 else if (euid != SAVED_USER_ID) {
7673 proc_seteuid(SAVED_USER_ID);
7674 if (rb_block_given_p()) {
7675 under_uid_switch = 1;
7676 return rb_ensure(rb_yield, Qnil, p_uid_sw_ensure, euid);
7678 else {
7679 return UIDT2NUM(uid);
7682 else {
7683 rb_syserr_fail(EPERM, 0);
7686 UNREACHABLE_RETURN(Qnil);
7688 #else
7689 static VALUE
7690 p_uid_sw_ensure(VALUE obj)
7692 under_uid_switch = 0;
7693 return p_uid_exchange(obj);
7696 static VALUE
7697 p_uid_switch(VALUE obj)
7699 rb_uid_t uid, euid;
7701 check_uid_switch();
7703 uid = getuid();
7704 euid = geteuid();
7706 if (uid == euid) {
7707 rb_syserr_fail(EPERM, 0);
7709 p_uid_exchange(obj);
7710 if (rb_block_given_p()) {
7711 under_uid_switch = 1;
7712 return rb_ensure(rb_yield, Qnil, p_uid_sw_ensure, obj);
7714 else {
7715 return UIDT2NUM(euid);
7718 #endif
7721 /* [MG] :FIXME: Is this correct? I'm not sure how to phrase this. */
7724 * call-seq:
7725 * Process::GID.sid_available? -> true or false
7727 * Returns +true+ if the current platform has saved group
7728 * ID functionality.
7732 static VALUE
7733 p_gid_have_saved_id(VALUE _)
7735 #if defined(HAVE_SETRESGID) || defined(HAVE_SETEGID) || defined(_POSIX_SAVED_IDS)
7736 return Qtrue;
7737 #else
7738 return Qfalse;
7739 #endif
7742 #if defined(HAVE_SETRESGID) || defined(HAVE_SETEGID) || defined(_POSIX_SAVED_IDS)
7743 static VALUE
7744 p_gid_sw_ensure(VALUE i)
7746 rb_gid_t id = (rb_gid_t/* narrowing */)i;
7747 under_gid_switch = 0;
7748 id = rb_setegid_core(id);
7749 return GIDT2NUM(id);
7754 * call-seq:
7755 * Process::GID.switch -> integer
7756 * Process::GID.switch {|| block} -> object
7758 * Switch the effective and real group IDs of the current process. If
7759 * a <em>block</em> is given, the group IDs will be switched back
7760 * after the block is executed. Returns the new effective group ID if
7761 * called without a block, and the return value of the block if one
7762 * is given.
7766 static VALUE
7767 p_gid_switch(VALUE obj)
7769 rb_gid_t gid, egid;
7771 check_gid_switch();
7773 gid = getgid();
7774 egid = getegid();
7776 if (gid != egid) {
7777 proc_setegid(obj, GIDT2NUM(gid));
7778 if (rb_block_given_p()) {
7779 under_gid_switch = 1;
7780 return rb_ensure(rb_yield, Qnil, p_gid_sw_ensure, SAVED_GROUP_ID);
7782 else {
7783 return GIDT2NUM(egid);
7786 else if (egid != SAVED_GROUP_ID) {
7787 proc_setegid(obj, GIDT2NUM(SAVED_GROUP_ID));
7788 if (rb_block_given_p()) {
7789 under_gid_switch = 1;
7790 return rb_ensure(rb_yield, Qnil, p_gid_sw_ensure, egid);
7792 else {
7793 return GIDT2NUM(gid);
7796 else {
7797 rb_syserr_fail(EPERM, 0);
7800 UNREACHABLE_RETURN(Qnil);
7802 #else
7803 static VALUE
7804 p_gid_sw_ensure(VALUE obj)
7806 under_gid_switch = 0;
7807 return p_gid_exchange(obj);
7810 static VALUE
7811 p_gid_switch(VALUE obj)
7813 rb_gid_t gid, egid;
7815 check_gid_switch();
7817 gid = getgid();
7818 egid = getegid();
7820 if (gid == egid) {
7821 rb_syserr_fail(EPERM, 0);
7823 p_gid_exchange(obj);
7824 if (rb_block_given_p()) {
7825 under_gid_switch = 1;
7826 return rb_ensure(rb_yield, Qnil, p_gid_sw_ensure, obj);
7828 else {
7829 return GIDT2NUM(egid);
7832 #endif
7835 #if defined(HAVE_TIMES)
7836 static long
7837 get_clk_tck(void)
7839 #ifdef HAVE__SC_CLK_TCK
7840 return sysconf(_SC_CLK_TCK);
7841 #elif defined CLK_TCK
7842 return CLK_TCK;
7843 #elif defined HZ
7844 return HZ;
7845 #else
7846 return 60;
7847 #endif
7851 * call-seq:
7852 * Process.times -> process_tms
7854 * Returns a Process::Tms structure that contains user and system CPU times
7855 * for the current process, and for its children processes:
7857 * Process.times
7858 * # => #<struct Process::Tms utime=55.122118, stime=35.533068, cutime=0.0, cstime=0.002846>
7860 * The precision is platform-defined.
7863 VALUE
7864 rb_proc_times(VALUE obj)
7866 VALUE utime, stime, cutime, cstime, ret;
7867 #if defined(RUSAGE_SELF) && defined(RUSAGE_CHILDREN)
7868 struct rusage usage_s, usage_c;
7870 if (getrusage(RUSAGE_SELF, &usage_s) != 0 || getrusage(RUSAGE_CHILDREN, &usage_c) != 0)
7871 rb_sys_fail("getrusage");
7872 utime = DBL2NUM((double)usage_s.ru_utime.tv_sec + (double)usage_s.ru_utime.tv_usec/1e6);
7873 stime = DBL2NUM((double)usage_s.ru_stime.tv_sec + (double)usage_s.ru_stime.tv_usec/1e6);
7874 cutime = DBL2NUM((double)usage_c.ru_utime.tv_sec + (double)usage_c.ru_utime.tv_usec/1e6);
7875 cstime = DBL2NUM((double)usage_c.ru_stime.tv_sec + (double)usage_c.ru_stime.tv_usec/1e6);
7876 #else
7877 const double hertz = (double)get_clk_tck();
7878 struct tms buf;
7880 times(&buf);
7881 utime = DBL2NUM(buf.tms_utime / hertz);
7882 stime = DBL2NUM(buf.tms_stime / hertz);
7883 cutime = DBL2NUM(buf.tms_cutime / hertz);
7884 cstime = DBL2NUM(buf.tms_cstime / hertz);
7885 #endif
7886 ret = rb_struct_new(rb_cProcessTms, utime, stime, cutime, cstime);
7887 RB_GC_GUARD(utime);
7888 RB_GC_GUARD(stime);
7889 RB_GC_GUARD(cutime);
7890 RB_GC_GUARD(cstime);
7891 return ret;
7893 #else
7894 #define rb_proc_times rb_f_notimplement
7895 #endif
7897 #ifdef HAVE_LONG_LONG
7898 typedef LONG_LONG timetick_int_t;
7899 #define TIMETICK_INT_MIN LLONG_MIN
7900 #define TIMETICK_INT_MAX LLONG_MAX
7901 #define TIMETICK_INT2NUM(v) LL2NUM(v)
7902 #define MUL_OVERFLOW_TIMETICK_P(a, b) MUL_OVERFLOW_LONG_LONG_P(a, b)
7903 #else
7904 typedef long timetick_int_t;
7905 #define TIMETICK_INT_MIN LONG_MIN
7906 #define TIMETICK_INT_MAX LONG_MAX
7907 #define TIMETICK_INT2NUM(v) LONG2NUM(v)
7908 #define MUL_OVERFLOW_TIMETICK_P(a, b) MUL_OVERFLOW_LONG_P(a, b)
7909 #endif
7911 CONSTFUNC(static timetick_int_t gcd_timetick_int(timetick_int_t, timetick_int_t));
7912 static timetick_int_t
7913 gcd_timetick_int(timetick_int_t a, timetick_int_t b)
7915 timetick_int_t t;
7917 if (a < b) {
7918 t = a;
7919 a = b;
7920 b = t;
7923 while (1) {
7924 t = a % b;
7925 if (t == 0)
7926 return b;
7927 a = b;
7928 b = t;
7932 static void
7933 reduce_fraction(timetick_int_t *np, timetick_int_t *dp)
7935 timetick_int_t gcd = gcd_timetick_int(*np, *dp);
7936 if (gcd != 1) {
7937 *np /= gcd;
7938 *dp /= gcd;
7942 static void
7943 reduce_factors(timetick_int_t *numerators, int num_numerators,
7944 timetick_int_t *denominators, int num_denominators)
7946 int i, j;
7947 for (i = 0; i < num_numerators; i++) {
7948 if (numerators[i] == 1)
7949 continue;
7950 for (j = 0; j < num_denominators; j++) {
7951 if (denominators[j] == 1)
7952 continue;
7953 reduce_fraction(&numerators[i], &denominators[j]);
7958 struct timetick {
7959 timetick_int_t giga_count;
7960 int32_t count; /* 0 .. 999999999 */
7963 static VALUE
7964 timetick2dblnum(struct timetick *ttp,
7965 timetick_int_t *numerators, int num_numerators,
7966 timetick_int_t *denominators, int num_denominators)
7968 double d;
7969 int i;
7971 reduce_factors(numerators, num_numerators,
7972 denominators, num_denominators);
7974 d = ttp->giga_count * 1e9 + ttp->count;
7976 for (i = 0; i < num_numerators; i++)
7977 d *= numerators[i];
7978 for (i = 0; i < num_denominators; i++)
7979 d /= denominators[i];
7981 return DBL2NUM(d);
7984 static VALUE
7985 timetick2dblnum_reciprocal(struct timetick *ttp,
7986 timetick_int_t *numerators, int num_numerators,
7987 timetick_int_t *denominators, int num_denominators)
7989 double d;
7990 int i;
7992 reduce_factors(numerators, num_numerators,
7993 denominators, num_denominators);
7995 d = 1.0;
7996 for (i = 0; i < num_denominators; i++)
7997 d *= denominators[i];
7998 for (i = 0; i < num_numerators; i++)
7999 d /= numerators[i];
8000 d /= ttp->giga_count * 1e9 + ttp->count;
8002 return DBL2NUM(d);
8005 #define NDIV(x,y) (-(-((x)+1)/(y))-1)
8006 #define DIV(n,d) ((n)<0 ? NDIV((n),(d)) : (n)/(d))
8008 static VALUE
8009 timetick2integer(struct timetick *ttp,
8010 timetick_int_t *numerators, int num_numerators,
8011 timetick_int_t *denominators, int num_denominators)
8013 VALUE v;
8014 int i;
8016 reduce_factors(numerators, num_numerators,
8017 denominators, num_denominators);
8019 if (!MUL_OVERFLOW_SIGNED_INTEGER_P(1000000000, ttp->giga_count,
8020 TIMETICK_INT_MIN, TIMETICK_INT_MAX-ttp->count)) {
8021 timetick_int_t t = ttp->giga_count * 1000000000 + ttp->count;
8022 for (i = 0; i < num_numerators; i++) {
8023 timetick_int_t factor = numerators[i];
8024 if (MUL_OVERFLOW_TIMETICK_P(factor, t))
8025 goto generic;
8026 t *= factor;
8028 for (i = 0; i < num_denominators; i++) {
8029 t = DIV(t, denominators[i]);
8031 return TIMETICK_INT2NUM(t);
8034 generic:
8035 v = TIMETICK_INT2NUM(ttp->giga_count);
8036 v = rb_funcall(v, '*', 1, LONG2FIX(1000000000));
8037 v = rb_funcall(v, '+', 1, LONG2FIX(ttp->count));
8038 for (i = 0; i < num_numerators; i++) {
8039 timetick_int_t factor = numerators[i];
8040 if (factor == 1)
8041 continue;
8042 v = rb_funcall(v, '*', 1, TIMETICK_INT2NUM(factor));
8044 for (i = 0; i < num_denominators; i++) {
8045 v = rb_funcall(v, '/', 1, TIMETICK_INT2NUM(denominators[i])); /* Ruby's '/' is div. */
8047 return v;
8050 static VALUE
8051 make_clock_result(struct timetick *ttp,
8052 timetick_int_t *numerators, int num_numerators,
8053 timetick_int_t *denominators, int num_denominators,
8054 VALUE unit)
8056 if (unit == ID2SYM(id_nanosecond)) {
8057 numerators[num_numerators++] = 1000000000;
8058 return timetick2integer(ttp, numerators, num_numerators, denominators, num_denominators);
8060 else if (unit == ID2SYM(id_microsecond)) {
8061 numerators[num_numerators++] = 1000000;
8062 return timetick2integer(ttp, numerators, num_numerators, denominators, num_denominators);
8064 else if (unit == ID2SYM(id_millisecond)) {
8065 numerators[num_numerators++] = 1000;
8066 return timetick2integer(ttp, numerators, num_numerators, denominators, num_denominators);
8068 else if (unit == ID2SYM(id_second)) {
8069 return timetick2integer(ttp, numerators, num_numerators, denominators, num_denominators);
8071 else if (unit == ID2SYM(id_float_microsecond)) {
8072 numerators[num_numerators++] = 1000000;
8073 return timetick2dblnum(ttp, numerators, num_numerators, denominators, num_denominators);
8075 else if (unit == ID2SYM(id_float_millisecond)) {
8076 numerators[num_numerators++] = 1000;
8077 return timetick2dblnum(ttp, numerators, num_numerators, denominators, num_denominators);
8079 else if (NIL_P(unit) || unit == ID2SYM(id_float_second)) {
8080 return timetick2dblnum(ttp, numerators, num_numerators, denominators, num_denominators);
8082 else
8083 rb_raise(rb_eArgError, "unexpected unit: %"PRIsVALUE, unit);
8086 #ifdef __APPLE__
8087 static const mach_timebase_info_data_t *
8088 get_mach_timebase_info(void)
8090 static mach_timebase_info_data_t sTimebaseInfo;
8092 if ( sTimebaseInfo.denom == 0 ) {
8093 (void) mach_timebase_info(&sTimebaseInfo);
8096 return &sTimebaseInfo;
8099 double
8100 ruby_real_ms_time(void)
8102 const mach_timebase_info_data_t *info = get_mach_timebase_info();
8103 uint64_t t = mach_absolute_time();
8104 return (double)t * info->numer / info->denom / 1e6;
8106 #endif
8108 #if defined(NUM2CLOCKID)
8109 # define NUMERIC_CLOCKID 1
8110 #else
8111 # define NUMERIC_CLOCKID 0
8112 # define NUM2CLOCKID(x) 0
8113 #endif
8115 #define clock_failed(name, err, arg) do { \
8116 int clock_error = (err); \
8117 rb_syserr_fail_str(clock_error, rb_sprintf("clock_" name "(%+"PRIsVALUE")", (arg))); \
8118 } while (0)
8121 * call-seq:
8122 * Process.clock_gettime(clock_id, unit = :float_second) -> number
8124 * Returns a clock time as determined by POSIX function
8125 * {clock_gettime()}[https://man7.org/linux/man-pages/man3/clock_gettime.3.html]:
8127 * Process.clock_gettime(:CLOCK_PROCESS_CPUTIME_ID) # => 198.650379677
8129 * Argument +clock_id+ should be a symbol or a constant that specifies
8130 * the clock whose time is to be returned;
8131 * see below.
8133 * Optional argument +unit+ should be a symbol that specifies
8134 * the unit to be used in the returned clock time;
8135 * see below.
8137 * <b>Argument +clock_id+</b>
8139 * Argument +clock_id+ specifies the clock whose time is to be returned;
8140 * it may be a constant such as <tt>Process::CLOCK_REALTIME</tt>,
8141 * or a symbol shorthand such as +:CLOCK_REALTIME+.
8143 * The supported clocks depend on the underlying operating system;
8144 * this method supports the following clocks on the indicated platforms
8145 * (raises Errno::EINVAL if called with an unsupported clock):
8147 * - +:CLOCK_BOOTTIME+: Linux 2.6.39.
8148 * - +:CLOCK_BOOTTIME_ALARM+: Linux 3.0.
8149 * - +:CLOCK_MONOTONIC+: SUSv3 to 4, Linux 2.5.63, FreeBSD 3.0, NetBSD 2.0, OpenBSD 3.4, macOS 10.12, Windows-2000.
8150 * - +:CLOCK_MONOTONIC_COARSE+: Linux 2.6.32.
8151 * - +:CLOCK_MONOTONIC_FAST+: FreeBSD 8.1.
8152 * - +:CLOCK_MONOTONIC_PRECISE+: FreeBSD 8.1.
8153 * - +:CLOCK_MONOTONIC_RAW+: Linux 2.6.28, macOS 10.12.
8154 * - +:CLOCK_MONOTONIC_RAW_APPROX+: macOS 10.12.
8155 * - +:CLOCK_PROCESS_CPUTIME_ID+: SUSv3 to 4, Linux 2.5.63, FreeBSD 9.3, OpenBSD 5.4, macOS 10.12.
8156 * - +:CLOCK_PROF+: FreeBSD 3.0, OpenBSD 2.1.
8157 * - +: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.
8158 * Time.now is recommended over +:CLOCK_REALTIME:.
8159 * - +:CLOCK_REALTIME_ALARM+: Linux 3.0.
8160 * - +:CLOCK_REALTIME_COARSE+: Linux 2.6.32.
8161 * - +:CLOCK_REALTIME_FAST+: FreeBSD 8.1.
8162 * - +:CLOCK_REALTIME_PRECISE+: FreeBSD 8.1.
8163 * - +:CLOCK_SECOND+: FreeBSD 8.1.
8164 * - +:CLOCK_TAI+: Linux 3.10.
8165 * - +:CLOCK_THREAD_CPUTIME_ID+: SUSv3 to 4, Linux 2.5.63, FreeBSD 7.1, OpenBSD 5.4, macOS 10.12.
8166 * - +:CLOCK_UPTIME+: FreeBSD 7.0, OpenBSD 5.5.
8167 * - +:CLOCK_UPTIME_FAST+: FreeBSD 8.1.
8168 * - +:CLOCK_UPTIME_PRECISE+: FreeBSD 8.1.
8169 * - +:CLOCK_UPTIME_RAW+: macOS 10.12.
8170 * - +:CLOCK_UPTIME_RAW_APPROX+: macOS 10.12.
8171 * - +:CLOCK_VIRTUAL+: FreeBSD 3.0, OpenBSD 2.1.
8173 * Note that SUS stands for Single Unix Specification.
8174 * SUS contains POSIX and clock_gettime is defined in the POSIX part.
8175 * SUS defines +:CLOCK_REALTIME+ as mandatory but
8176 * +:CLOCK_MONOTONIC+, +:CLOCK_PROCESS_CPUTIME_ID+,
8177 * and +:CLOCK_THREAD_CPUTIME_ID+ are optional.
8179 * Certain emulations are used when the given +clock_id+
8180 * is not supported directly:
8182 * - Emulations for +:CLOCK_REALTIME+:
8184 * - +:GETTIMEOFDAY_BASED_CLOCK_REALTIME+:
8185 * Use gettimeofday() defined by SUS (deprecated in SUSv4).
8186 * The resolution is 1 microsecond.
8187 * - +:TIME_BASED_CLOCK_REALTIME+:
8188 * Use time() defined by ISO C.
8189 * The resolution is 1 second.
8191 * - Emulations for +:CLOCK_MONOTONIC+:
8193 * - +:MACH_ABSOLUTE_TIME_BASED_CLOCK_MONOTONIC+:
8194 * Use mach_absolute_time(), available on Darwin.
8195 * The resolution is CPU dependent.
8196 * - +:TIMES_BASED_CLOCK_MONOTONIC+:
8197 * Use the result value of times() defined by POSIX, thus:
8198 * >>>
8199 * Upon successful completion, times() shall return the elapsed real time,
8200 * in clock ticks, since an arbitrary point in the past
8201 * (for example, system start-up time).
8203 * For example, GNU/Linux returns a value based on jiffies and it is monotonic.
8204 * However, 4.4BSD uses gettimeofday() and it is not monotonic.
8205 * (FreeBSD uses +:CLOCK_MONOTONIC+ instead, though.)
8207 * The resolution is the clock tick.
8208 * "getconf CLK_TCK" command shows the clock ticks per second.
8209 * (The clock ticks-per-second is defined by HZ macro in older systems.)
8210 * If it is 100 and clock_t is 32 bits integer type,
8211 * the resolution is 10 millisecond and cannot represent over 497 days.
8213 * - Emulations for +:CLOCK_PROCESS_CPUTIME_ID+:
8215 * - +:GETRUSAGE_BASED_CLOCK_PROCESS_CPUTIME_ID+:
8216 * Use getrusage() defined by SUS.
8217 * getrusage() is used with RUSAGE_SELF to obtain the time only for
8218 * the calling process (excluding the time for child processes).
8219 * The result is addition of user time (ru_utime) and system time (ru_stime).
8220 * The resolution is 1 microsecond.
8221 * - +:TIMES_BASED_CLOCK_PROCESS_CPUTIME_ID+:
8222 * Use times() defined by POSIX.
8223 * The result is addition of user time (tms_utime) and system time (tms_stime).
8224 * tms_cutime and tms_cstime are ignored to exclude the time for child processes.
8225 * The resolution is the clock tick.
8226 * "getconf CLK_TCK" command shows the clock ticks per second.
8227 * (The clock ticks per second is defined by HZ macro in older systems.)
8228 * If it is 100, the resolution is 10 millisecond.
8229 * - +:CLOCK_BASED_CLOCK_PROCESS_CPUTIME_ID+:
8230 * Use clock() defined by ISO C.
8231 * The resolution is <tt>1/CLOCKS_PER_SEC</tt>.
8232 * +CLOCKS_PER_SEC+ is the C-level macro defined by time.h.
8233 * SUS defines +CLOCKS_PER_SEC+ as 1000000;
8234 * other systems may define it differently.
8235 * If +CLOCKS_PER_SEC+ is 1000000 (as in SUS),
8236 * the resolution is 1 microsecond.
8237 * If +CLOCKS_PER_SEC+ is 1000000 and clock_t is a 32-bit integer type,
8238 * it cannot represent over 72 minutes.
8240 * <b>Argument +unit+</b>
8242 * Optional argument +unit+ (default +:float_second+)
8243 * specifies the unit for the returned value.
8245 * - +:float_microsecond+: Number of microseconds as a float.
8246 * - +:float_millisecond+: Number of milliseconds as a float.
8247 * - +:float_second+: Number of seconds as a float.
8248 * - +:microsecond+: Number of microseconds as an integer.
8249 * - +:millisecond+: Number of milliseconds as an integer.
8250 * - +:nanosecond+: Number of nanoseconds as an integer.
8251 * - +::second+: Number of seconds as an integer.
8253 * Examples:
8255 * Process.clock_gettime(:CLOCK_PROCESS_CPUTIME_ID, :float_microsecond)
8256 * # => 203605054.825
8257 * Process.clock_gettime(:CLOCK_PROCESS_CPUTIME_ID, :float_millisecond)
8258 * # => 203643.696848
8259 * Process.clock_gettime(:CLOCK_PROCESS_CPUTIME_ID, :float_second)
8260 * # => 203.762181929
8261 * Process.clock_gettime(:CLOCK_PROCESS_CPUTIME_ID, :microsecond)
8262 * # => 204123212
8263 * Process.clock_gettime(:CLOCK_PROCESS_CPUTIME_ID, :millisecond)
8264 * # => 204298
8265 * Process.clock_gettime(:CLOCK_PROCESS_CPUTIME_ID, :nanosecond)
8266 * # => 204602286036
8267 * Process.clock_gettime(:CLOCK_PROCESS_CPUTIME_ID, :second)
8268 * # => 204
8270 * The underlying function, clock_gettime(), returns a number of nanoseconds.
8271 * Float object (IEEE 754 double) is not enough to represent
8272 * the return value for +:CLOCK_REALTIME+.
8273 * If the exact nanoseconds value is required, use +:nanosecond+ as the +unit+.
8275 * The origin (time zero) of the returned value is system-dependent,
8276 * and may be, for example, system start up time,
8277 * process start up time, the Epoch, etc.
8279 * The origin in +:CLOCK_REALTIME+ is defined as the Epoch:
8280 * <tt>1970-01-01 00:00:00 UTC</tt>;
8281 * some systems count leap seconds and others don't,
8282 * so the result may vary across systems.
8284 static VALUE
8285 rb_clock_gettime(int argc, VALUE *argv, VALUE _)
8287 int ret;
8289 struct timetick tt;
8290 timetick_int_t numerators[2];
8291 timetick_int_t denominators[2];
8292 int num_numerators = 0;
8293 int num_denominators = 0;
8295 VALUE unit = (rb_check_arity(argc, 1, 2) == 2) ? argv[1] : Qnil;
8296 VALUE clk_id = argv[0];
8297 #ifdef HAVE_CLOCK_GETTIME
8298 clockid_t c;
8299 #endif
8301 if (SYMBOL_P(clk_id)) {
8302 #ifdef CLOCK_REALTIME
8303 if (clk_id == RUBY_CLOCK_REALTIME) {
8304 c = CLOCK_REALTIME;
8305 goto gettime;
8307 #endif
8309 #ifdef CLOCK_MONOTONIC
8310 if (clk_id == RUBY_CLOCK_MONOTONIC) {
8311 c = CLOCK_MONOTONIC;
8312 goto gettime;
8314 #endif
8316 #ifdef CLOCK_PROCESS_CPUTIME_ID
8317 if (clk_id == RUBY_CLOCK_PROCESS_CPUTIME_ID) {
8318 c = CLOCK_PROCESS_CPUTIME_ID;
8319 goto gettime;
8321 #endif
8323 #ifdef CLOCK_THREAD_CPUTIME_ID
8324 if (clk_id == RUBY_CLOCK_THREAD_CPUTIME_ID) {
8325 c = CLOCK_THREAD_CPUTIME_ID;
8326 goto gettime;
8328 #endif
8331 * Non-clock_gettime clocks are provided by symbol clk_id.
8333 #ifdef HAVE_GETTIMEOFDAY
8335 * GETTIMEOFDAY_BASED_CLOCK_REALTIME is used for
8336 * CLOCK_REALTIME if clock_gettime is not available.
8338 #define RUBY_GETTIMEOFDAY_BASED_CLOCK_REALTIME ID2SYM(id_GETTIMEOFDAY_BASED_CLOCK_REALTIME)
8339 if (clk_id == RUBY_GETTIMEOFDAY_BASED_CLOCK_REALTIME) {
8340 struct timeval tv;
8341 ret = gettimeofday(&tv, 0);
8342 if (ret != 0)
8343 rb_sys_fail("gettimeofday");
8344 tt.giga_count = tv.tv_sec;
8345 tt.count = (int32_t)tv.tv_usec * 1000;
8346 denominators[num_denominators++] = 1000000000;
8347 goto success;
8349 #endif
8351 #define RUBY_TIME_BASED_CLOCK_REALTIME ID2SYM(id_TIME_BASED_CLOCK_REALTIME)
8352 if (clk_id == RUBY_TIME_BASED_CLOCK_REALTIME) {
8353 time_t t;
8354 t = time(NULL);
8355 if (t == (time_t)-1)
8356 rb_sys_fail("time");
8357 tt.giga_count = t;
8358 tt.count = 0;
8359 denominators[num_denominators++] = 1000000000;
8360 goto success;
8363 #ifdef HAVE_TIMES
8364 #define RUBY_TIMES_BASED_CLOCK_MONOTONIC \
8365 ID2SYM(id_TIMES_BASED_CLOCK_MONOTONIC)
8366 if (clk_id == RUBY_TIMES_BASED_CLOCK_MONOTONIC) {
8367 struct tms buf;
8368 clock_t c;
8369 unsigned_clock_t uc;
8370 c = times(&buf);
8371 if (c == (clock_t)-1)
8372 rb_sys_fail("times");
8373 uc = (unsigned_clock_t)c;
8374 tt.count = (int32_t)(uc % 1000000000);
8375 tt.giga_count = (uc / 1000000000);
8376 denominators[num_denominators++] = get_clk_tck();
8377 goto success;
8379 #endif
8381 #ifdef RUSAGE_SELF
8382 #define RUBY_GETRUSAGE_BASED_CLOCK_PROCESS_CPUTIME_ID \
8383 ID2SYM(id_GETRUSAGE_BASED_CLOCK_PROCESS_CPUTIME_ID)
8384 if (clk_id == RUBY_GETRUSAGE_BASED_CLOCK_PROCESS_CPUTIME_ID) {
8385 struct rusage usage;
8386 int32_t usec;
8387 ret = getrusage(RUSAGE_SELF, &usage);
8388 if (ret != 0)
8389 rb_sys_fail("getrusage");
8390 tt.giga_count = usage.ru_utime.tv_sec + usage.ru_stime.tv_sec;
8391 usec = (int32_t)(usage.ru_utime.tv_usec + usage.ru_stime.tv_usec);
8392 if (1000000 <= usec) {
8393 tt.giga_count++;
8394 usec -= 1000000;
8396 tt.count = usec * 1000;
8397 denominators[num_denominators++] = 1000000000;
8398 goto success;
8400 #endif
8402 #ifdef HAVE_TIMES
8403 #define RUBY_TIMES_BASED_CLOCK_PROCESS_CPUTIME_ID \
8404 ID2SYM(id_TIMES_BASED_CLOCK_PROCESS_CPUTIME_ID)
8405 if (clk_id == RUBY_TIMES_BASED_CLOCK_PROCESS_CPUTIME_ID) {
8406 struct tms buf;
8407 unsigned_clock_t utime, stime;
8408 if (times(&buf) == (clock_t)-1)
8409 rb_sys_fail("times");
8410 utime = (unsigned_clock_t)buf.tms_utime;
8411 stime = (unsigned_clock_t)buf.tms_stime;
8412 tt.count = (int32_t)((utime % 1000000000) + (stime % 1000000000));
8413 tt.giga_count = (utime / 1000000000) + (stime / 1000000000);
8414 if (1000000000 <= tt.count) {
8415 tt.count -= 1000000000;
8416 tt.giga_count++;
8418 denominators[num_denominators++] = get_clk_tck();
8419 goto success;
8421 #endif
8423 #define RUBY_CLOCK_BASED_CLOCK_PROCESS_CPUTIME_ID \
8424 ID2SYM(id_CLOCK_BASED_CLOCK_PROCESS_CPUTIME_ID)
8425 if (clk_id == RUBY_CLOCK_BASED_CLOCK_PROCESS_CPUTIME_ID) {
8426 clock_t c;
8427 unsigned_clock_t uc;
8428 errno = 0;
8429 c = clock();
8430 if (c == (clock_t)-1)
8431 rb_sys_fail("clock");
8432 uc = (unsigned_clock_t)c;
8433 tt.count = (int32_t)(uc % 1000000000);
8434 tt.giga_count = uc / 1000000000;
8435 denominators[num_denominators++] = CLOCKS_PER_SEC;
8436 goto success;
8439 #ifdef __APPLE__
8440 if (clk_id == RUBY_MACH_ABSOLUTE_TIME_BASED_CLOCK_MONOTONIC) {
8441 const mach_timebase_info_data_t *info = get_mach_timebase_info();
8442 uint64_t t = mach_absolute_time();
8443 tt.count = (int32_t)(t % 1000000000);
8444 tt.giga_count = t / 1000000000;
8445 numerators[num_numerators++] = info->numer;
8446 denominators[num_denominators++] = info->denom;
8447 denominators[num_denominators++] = 1000000000;
8448 goto success;
8450 #endif
8452 else if (NUMERIC_CLOCKID) {
8453 #if defined(HAVE_CLOCK_GETTIME)
8454 struct timespec ts;
8455 c = NUM2CLOCKID(clk_id);
8456 gettime:
8457 ret = clock_gettime(c, &ts);
8458 if (ret == -1)
8459 clock_failed("gettime", errno, clk_id);
8460 tt.count = (int32_t)ts.tv_nsec;
8461 tt.giga_count = ts.tv_sec;
8462 denominators[num_denominators++] = 1000000000;
8463 goto success;
8464 #endif
8466 else {
8467 rb_unexpected_type(clk_id, T_SYMBOL);
8469 clock_failed("gettime", EINVAL, clk_id);
8471 success:
8472 return make_clock_result(&tt, numerators, num_numerators, denominators, num_denominators, unit);
8476 * call-seq:
8477 * Process.clock_getres(clock_id, unit = :float_second) -> number
8479 * Returns a clock resolution as determined by POSIX function
8480 * {clock_getres()}[https://man7.org/linux/man-pages/man3/clock_getres.3.html]:
8482 * Process.clock_getres(:CLOCK_REALTIME) # => 1.0e-09
8484 * See Process.clock_gettime for the values of +clock_id+ and +unit+.
8486 * Examples:
8488 * Process.clock_getres(:CLOCK_PROCESS_CPUTIME_ID, :float_microsecond) # => 0.001
8489 * Process.clock_getres(:CLOCK_PROCESS_CPUTIME_ID, :float_millisecond) # => 1.0e-06
8490 * Process.clock_getres(:CLOCK_PROCESS_CPUTIME_ID, :float_second) # => 1.0e-09
8491 * Process.clock_getres(:CLOCK_PROCESS_CPUTIME_ID, :microsecond) # => 0
8492 * Process.clock_getres(:CLOCK_PROCESS_CPUTIME_ID, :millisecond) # => 0
8493 * Process.clock_getres(:CLOCK_PROCESS_CPUTIME_ID, :nanosecond) # => 1
8494 * Process.clock_getres(:CLOCK_PROCESS_CPUTIME_ID, :second) # => 0
8496 * In addition to the values for +unit+ supported in Process.clock_gettime,
8497 * this method supports +:hertz+, the integer number of clock ticks per second
8498 * (which is the reciprocal of +:float_second+):
8500 * Process.clock_getres(:TIMES_BASED_CLOCK_PROCESS_CPUTIME_ID, :hertz) # => 100.0
8501 * Process.clock_getres(:TIMES_BASED_CLOCK_PROCESS_CPUTIME_ID, :float_second) # => 0.01
8503 * <b>Accuracy</b>:
8504 * Note that the returned resolution may be inaccurate on some platforms
8505 * due to underlying bugs.
8506 * Inaccurate resolutions have been reported for various clocks including
8507 * +:CLOCK_MONOTONIC+ and +:CLOCK_MONOTONIC_RAW+
8508 * on Linux, macOS, BSD or AIX platforms, when using ARM processors,
8509 * or when using virtualization.
8511 static VALUE
8512 rb_clock_getres(int argc, VALUE *argv, VALUE _)
8514 int ret;
8516 struct timetick tt;
8517 timetick_int_t numerators[2];
8518 timetick_int_t denominators[2];
8519 int num_numerators = 0;
8520 int num_denominators = 0;
8521 #ifdef HAVE_CLOCK_GETRES
8522 clockid_t c;
8523 #endif
8525 VALUE unit = (rb_check_arity(argc, 1, 2) == 2) ? argv[1] : Qnil;
8526 VALUE clk_id = argv[0];
8528 if (SYMBOL_P(clk_id)) {
8529 #ifdef CLOCK_REALTIME
8530 if (clk_id == RUBY_CLOCK_REALTIME) {
8531 c = CLOCK_REALTIME;
8532 goto getres;
8534 #endif
8536 #ifdef CLOCK_MONOTONIC
8537 if (clk_id == RUBY_CLOCK_MONOTONIC) {
8538 c = CLOCK_MONOTONIC;
8539 goto getres;
8541 #endif
8543 #ifdef CLOCK_PROCESS_CPUTIME_ID
8544 if (clk_id == RUBY_CLOCK_PROCESS_CPUTIME_ID) {
8545 c = CLOCK_PROCESS_CPUTIME_ID;
8546 goto getres;
8548 #endif
8550 #ifdef CLOCK_THREAD_CPUTIME_ID
8551 if (clk_id == RUBY_CLOCK_THREAD_CPUTIME_ID) {
8552 c = CLOCK_THREAD_CPUTIME_ID;
8553 goto getres;
8555 #endif
8557 #ifdef RUBY_GETTIMEOFDAY_BASED_CLOCK_REALTIME
8558 if (clk_id == RUBY_GETTIMEOFDAY_BASED_CLOCK_REALTIME) {
8559 tt.giga_count = 0;
8560 tt.count = 1000;
8561 denominators[num_denominators++] = 1000000000;
8562 goto success;
8564 #endif
8566 #ifdef RUBY_TIME_BASED_CLOCK_REALTIME
8567 if (clk_id == RUBY_TIME_BASED_CLOCK_REALTIME) {
8568 tt.giga_count = 1;
8569 tt.count = 0;
8570 denominators[num_denominators++] = 1000000000;
8571 goto success;
8573 #endif
8575 #ifdef RUBY_TIMES_BASED_CLOCK_MONOTONIC
8576 if (clk_id == RUBY_TIMES_BASED_CLOCK_MONOTONIC) {
8577 tt.count = 1;
8578 tt.giga_count = 0;
8579 denominators[num_denominators++] = get_clk_tck();
8580 goto success;
8582 #endif
8584 #ifdef RUBY_GETRUSAGE_BASED_CLOCK_PROCESS_CPUTIME_ID
8585 if (clk_id == RUBY_GETRUSAGE_BASED_CLOCK_PROCESS_CPUTIME_ID) {
8586 tt.giga_count = 0;
8587 tt.count = 1000;
8588 denominators[num_denominators++] = 1000000000;
8589 goto success;
8591 #endif
8593 #ifdef RUBY_TIMES_BASED_CLOCK_PROCESS_CPUTIME_ID
8594 if (clk_id == RUBY_TIMES_BASED_CLOCK_PROCESS_CPUTIME_ID) {
8595 tt.count = 1;
8596 tt.giga_count = 0;
8597 denominators[num_denominators++] = get_clk_tck();
8598 goto success;
8600 #endif
8602 #ifdef RUBY_CLOCK_BASED_CLOCK_PROCESS_CPUTIME_ID
8603 if (clk_id == RUBY_CLOCK_BASED_CLOCK_PROCESS_CPUTIME_ID) {
8604 tt.count = 1;
8605 tt.giga_count = 0;
8606 denominators[num_denominators++] = CLOCKS_PER_SEC;
8607 goto success;
8609 #endif
8611 #ifdef RUBY_MACH_ABSOLUTE_TIME_BASED_CLOCK_MONOTONIC
8612 if (clk_id == RUBY_MACH_ABSOLUTE_TIME_BASED_CLOCK_MONOTONIC) {
8613 const mach_timebase_info_data_t *info = get_mach_timebase_info();
8614 tt.count = 1;
8615 tt.giga_count = 0;
8616 numerators[num_numerators++] = info->numer;
8617 denominators[num_denominators++] = info->denom;
8618 denominators[num_denominators++] = 1000000000;
8619 goto success;
8621 #endif
8623 else if (NUMERIC_CLOCKID) {
8624 #if defined(HAVE_CLOCK_GETRES)
8625 struct timespec ts;
8626 c = NUM2CLOCKID(clk_id);
8627 getres:
8628 ret = clock_getres(c, &ts);
8629 if (ret == -1)
8630 clock_failed("getres", errno, clk_id);
8631 tt.count = (int32_t)ts.tv_nsec;
8632 tt.giga_count = ts.tv_sec;
8633 denominators[num_denominators++] = 1000000000;
8634 goto success;
8635 #endif
8637 else {
8638 rb_unexpected_type(clk_id, T_SYMBOL);
8640 clock_failed("getres", EINVAL, clk_id);
8642 success:
8643 if (unit == ID2SYM(id_hertz)) {
8644 return timetick2dblnum_reciprocal(&tt, numerators, num_numerators, denominators, num_denominators);
8646 else {
8647 return make_clock_result(&tt, numerators, num_numerators, denominators, num_denominators, unit);
8651 static VALUE
8652 get_CHILD_STATUS(ID _x, VALUE *_y)
8654 return rb_last_status_get();
8657 static VALUE
8658 get_PROCESS_ID(ID _x, VALUE *_y)
8660 return get_pid();
8664 * call-seq:
8665 * Process.kill(signal, *ids) -> count
8667 * Sends a signal to each process specified by +ids+
8668 * (which must specify at least one ID);
8669 * returns the count of signals sent.
8671 * For each given +id+, if +id+ is:
8673 * - Positive, sends the signal to the process whose process ID is +id+.
8674 * - Zero, send the signal to all processes in the current process group.
8675 * - Negative, sends the signal to a system-dependent collection of processes.
8677 * Argument +signal+ specifies the signal to be sent;
8678 * the argument may be:
8680 * - An integer signal number: e.g., +-29+, +0+, +29+.
8681 * - A signal name (string), with or without leading <tt>'SIG'</tt>,
8682 * and with or without a further prefixed minus sign (<tt>'-'</tt>):
8683 * e.g.:
8685 * - <tt>'SIGPOLL'</tt>.
8686 * - <tt>'POLL'</tt>,
8687 * - <tt>'-SIGPOLL'</tt>.
8688 * - <tt>'-POLL'</tt>.
8690 * - A signal symbol, with or without leading <tt>'SIG'</tt>,
8691 * and with or without a further prefixed minus sign (<tt>'-'</tt>):
8692 * e.g.:
8694 * - +:SIGPOLL+.
8695 * - +:POLL+.
8696 * - <tt>:'-SIGPOLL'</tt>.
8697 * - <tt>:'-POLL'</tt>.
8699 * If +signal+ is:
8701 * - A non-negative integer, or a signal name or symbol
8702 * without prefixed <tt>'-'</tt>,
8703 * each process with process ID +id+ is signalled.
8704 * - A negative integer, or a signal name or symbol
8705 * with prefixed <tt>'-'</tt>,
8706 * each process group with group ID +id+ is signalled.
8708 * Use method Signal.list to see which signals are supported
8709 * by Ruby on the underlying platform;
8710 * the method returns a hash of the string names
8711 * and non-negative integer values of the supported signals.
8712 * The size and content of the returned hash varies widely
8713 * among platforms.
8715 * Additionally, signal +0+ is useful to determine if the process exists.
8717 * Example:
8719 * pid = fork do
8720 * Signal.trap('HUP') { puts 'Ouch!'; exit }
8721 * # ... do some work ...
8722 * end
8723 * # ...
8724 * Process.kill('HUP', pid)
8725 * Process.wait
8727 * Output:
8729 * Ouch!
8731 * Exceptions:
8733 * - Raises Errno::EINVAL or RangeError if +signal+ is an integer
8734 * but invalid.
8735 * - Raises ArgumentError if +signal+ is a string or symbol
8736 * but invalid.
8737 * - Raises Errno::ESRCH or RangeError if one of +ids+ is invalid.
8738 * - Raises Errno::EPERM if needed permissions are not in force.
8740 * In the last two cases, signals may have been sent to some processes.
8743 static VALUE
8744 proc_rb_f_kill(int c, const VALUE *v, VALUE _)
8746 return rb_f_kill(c, v);
8749 VALUE rb_mProcess;
8750 static VALUE rb_mProcUID;
8751 static VALUE rb_mProcGID;
8752 static VALUE rb_mProcID_Syscall;
8755 * call-seq:
8756 * Process.warmup -> true
8758 * Notify the Ruby virtual machine that the boot sequence is finished,
8759 * and that now is a good time to optimize the application. This is useful
8760 * for long running applications.
8762 * This method is expected to be called at the end of the application boot.
8763 * If the application is deployed using a pre-forking model, +Process.warmup+
8764 * should be called in the original process before the first fork.
8766 * The actual optimizations performed are entirely implementation specific
8767 * and may change in the future without notice.
8769 * On CRuby, +Process.warmup+:
8771 * * Performs a major GC.
8772 * * Compacts the heap.
8773 * * Promotes all surviving objects to the old generation.
8774 * * Precomputes the coderange of all strings.
8775 * * Frees all empty heap pages and increments the allocatable pages counter
8776 * by the number of pages freed.
8777 * * Invoke +malloc_trim+ if available to free empty malloc pages.
8780 static VALUE
8781 proc_warmup(VALUE _)
8783 RB_VM_LOCK_ENTER();
8784 rb_gc_prepare_heap();
8785 RB_VM_LOCK_LEAVE();
8786 return Qtrue;
8790 * Document-module: Process
8792 * \Module +Process+ represents a process in the underlying operating system.
8793 * Its methods support management of the current process and its child processes.
8795 * == \Process Creation
8797 * Each of the following methods executes a given command in a new process or subshell,
8798 * or multiple commands in new processes and/or subshells.
8799 * The choice of process or subshell depends on the form of the command;
8800 * see {Argument command_line or exe_path}[rdoc-ref:Process@Argument+command_line+or+exe_path].
8802 * - Process.spawn, Kernel#spawn: Executes the command;
8803 * returns the new pid without waiting for completion.
8804 * - Process.exec: Replaces the current process by executing the command.
8806 * In addition:
8808 * - \Method Kernel#system executes a given command-line (string) in a subshell;
8809 * returns +true+, +false+, or +nil+.
8810 * - \Method Kernel#` executes a given command-line (string) in a subshell;
8811 * returns its $stdout string.
8812 * - \Module Open3 supports creating child processes
8813 * with access to their $stdin, $stdout, and $stderr streams.
8815 * === Execution Environment
8817 * Optional leading argument +env+ is a hash of name/value pairs,
8818 * where each name is a string and each value is a string or +nil+;
8819 * each name/value pair is added to ENV in the new process.
8821 * Process.spawn( 'ruby -e "p ENV[\"Foo\"]"')
8822 * Process.spawn({'Foo' => '0'}, 'ruby -e "p ENV[\"Foo\"]"')
8824 * Output:
8826 * "0"
8828 * The effect is usually similar to that of calling ENV#update with argument +env+,
8829 * where each named environment variable is created or updated
8830 * (if the value is non-+nil+),
8831 * or deleted (if the value is +nil+).
8833 * However, some modifications to the calling process may remain
8834 * if the new process fails.
8835 * For example, hard resource limits are not restored.
8837 * === Argument +command_line+ or +exe_path+
8839 * The required string argument is one of the following:
8841 * - +command_line+ if it begins with a shell reserved word or special built-in,
8842 * or if it contains one or more meta characters.
8843 * - +exe_path+ otherwise.
8845 * ==== Argument +command_line+
8847 * \String argument +command_line+ is a command line to be passed to a shell;
8848 * it must begin with a shell reserved word, begin with a special built-in,
8849 * or contain meta characters:
8851 * system('if true; then echo "Foo"; fi') # => true # Shell reserved word.
8852 * system('exit') # => true # Built-in.
8853 * system('date > /tmp/date.tmp') # => true # Contains meta character.
8854 * system('date > /nop/date.tmp') # => false
8855 * system('date > /nop/date.tmp', exception: true) # Raises RuntimeError.
8857 * The command line may also contain arguments and options for the command:
8859 * system('echo "Foo"') # => true
8861 * Output:
8863 * Foo
8865 * See {Execution Shell}[rdoc-ref:Process@Execution+Shell] for details about the shell.
8867 * ==== Argument +exe_path+
8869 * Argument +exe_path+ is one of the following:
8871 * - The string path to an executable file to be called:
8873 * Example:
8875 * system('/usr/bin/date') # => true # Path to date on Unix-style system.
8876 * system('foo') # => nil # Command execlution failed.
8878 * Output:
8880 * Thu Aug 31 10:06:48 AM CDT 2023
8882 * A path or command name containing spaces without arguments cannot
8883 * be distinguished from +command_line+ above, so you must quote or
8884 * escape the entire command name using a shell in platform
8885 * dependent manner, or use the array form below.
8887 * If +exe_path+ does not contain any path separator, an executable
8888 * file is searched from directories specified with the +PATH+
8889 * environment variable. What the word "executable" means here is
8890 * depending on platforms.
8892 * Even if the file considered "executable", its content may not be
8893 * in proper executable format. In that case, Ruby tries to run it
8894 * by using <tt>/bin/sh</tt> on a Unix-like system, like system(3)
8895 * does.
8897 * File.write('shell_command', 'echo $SHELL', perm: 0o755)
8898 * system('./shell_command') # prints "/bin/sh" or something.
8900 * - A 2-element array containing the path to an executable
8901 * and the string to be used as the name of the executing process:
8903 * Example:
8905 * pid = spawn(['sleep', 'Hello!'], '1') # 2-element array.
8906 * p `ps -p #{pid} -o command=`
8908 * Output:
8910 * "Hello! 1\n"
8912 * === Arguments +args+
8914 * If +command_line+ does not contain shell meta characters except for
8915 * spaces and tabs, or +exe_path+ is given, Ruby invokes the
8916 * executable directly. This form does not use the shell:
8918 * spawn("doesnt_exist") # Raises Errno::ENOENT
8919 * spawn("doesnt_exist", "\n") # Raises Errno::ENOENT
8921 * spawn("doesnt_exist\n") # => false
8922 * # sh: 1: doesnot_exist: not found
8924 * The error message is from a shell and would vary depending on your
8925 * system.
8927 * If one or more +args+ is given after +exe_path+, each is an
8928 * argument or option to be passed to the executable:
8930 * Example:
8932 * system('echo', '<', 'C*', '|', '$SHELL', '>') # => true
8934 * Output:
8936 * < C* | $SHELL >
8938 * However, there are exceptions on Windows. See {Execution Shell on
8939 * Windows}[rdoc-ref:Process@Execution+Shell+on+Windows].
8941 * If you want to invoke a path containing spaces with no arguments
8942 * without shell, you will need to use a 2-element array +exe_path+.
8944 * Example:
8946 * path = '/Applications/Google Chrome.app/Contents/MacOS/Google Chrome'
8947 * spawn(path) # Raises Errno::ENOENT; No such file or directory - /Applications/Google
8948 * spawn([path] * 2)
8950 * === Execution Options
8952 * Optional trailing argument +options+ is a hash of execution options.
8954 * ==== Working Directory (+:chdir+)
8956 * By default, the working directory for the new process is the same as
8957 * that of the current process:
8959 * Dir.chdir('/var')
8960 * Process.spawn('ruby -e "puts Dir.pwd"')
8962 * Output:
8964 * /var
8966 * Use option +:chdir+ to set the working directory for the new process:
8968 * Process.spawn('ruby -e "puts Dir.pwd"', {chdir: '/tmp'})
8970 * Output:
8972 * /tmp
8974 * The working directory of the current process is not changed:
8976 * Dir.pwd # => "/var"
8978 * ==== \File Redirection (\File Descriptor)
8980 * Use execution options for file redirection in the new process.
8982 * The key for such an option may be an integer file descriptor (fd),
8983 * specifying a source,
8984 * or an array of fds, specifying multiple sources.
8986 * An integer source fd may be specified as:
8988 * - _n_: Specifies file descriptor _n_.
8990 * There are these shorthand symbols for fds:
8992 * - +:in+: Specifies file descriptor 0 (STDIN).
8993 * - +:out+: Specifies file descriptor 1 (STDOUT).
8994 * - +:err+: Specifies file descriptor 2 (STDERR).
8996 * The value given with a source is one of:
8998 * - _n_:
8999 * Redirects to fd _n_ in the parent process.
9000 * - +filepath+:
9001 * Redirects from or to the file at +filepath+ via <tt>open(filepath, mode, 0644)</tt>,
9002 * where +mode+ is <tt>'r'</tt> for source +:in+,
9003 * or <tt>'w'</tt> for source +:out+ or +:err+.
9004 * - <tt>[filepath]</tt>:
9005 * Redirects from the file at +filepath+ via <tt>open(filepath, 'r', 0644)</tt>.
9006 * - <tt>[filepath, mode]</tt>:
9007 * Redirects from or to the file at +filepath+ via <tt>open(filepath, mode, 0644)</tt>.
9008 * - <tt>[filepath, mode, perm]</tt>:
9009 * Redirects from or to the file at +filepath+ via <tt>open(filepath, mode, perm)</tt>.
9010 * - <tt>[:child, fd]</tt>:
9011 * Redirects to the redirected +fd+.
9012 * - +:close+: Closes the file descriptor in child process.
9014 * See {Access Modes}[rdoc-ref:File@Access+Modes]
9015 * and {File Permissions}[rdoc-ref:File@File+Permissions].
9017 * ==== Environment Variables (+:unsetenv_others+)
9019 * By default, the new process inherits environment variables
9020 * from the parent process;
9021 * use execution option key +:unsetenv_others+ with value +true+
9022 * to clear environment variables in the new process.
9024 * Any changes specified by execution option +env+ are made after the new process
9025 * inherits or clears its environment variables;
9026 * see {Execution Environment}[rdoc-ref:Process@Execution+Environment].
9028 * ==== \File-Creation Access (+:umask+)
9030 * Use execution option +:umask+ to set the file-creation access
9031 * for the new process;
9032 * see {Access Modes}[rdoc-ref:File@Access+Modes]:
9034 * command = 'ruby -e "puts sprintf(\"0%o\", File.umask)"'
9035 * options = {:umask => 0644}
9036 * Process.spawn(command, options)
9038 * Output:
9040 * 0644
9042 * ==== \Process Groups (+:pgroup+ and +:new_pgroup+)
9044 * By default, the new process belongs to the same
9045 * {process group}[https://en.wikipedia.org/wiki/Process_group]
9046 * as the parent process.
9048 * To specify a different process group.
9049 * use execution option +:pgroup+ with one of the following values:
9051 * - +true+: Create a new process group for the new process.
9052 * - _pgid_: Create the new process in the process group
9053 * whose id is _pgid_.
9055 * On Windows only, use execution option +:new_pgroup+ with value +true+
9056 * to create a new process group for the new process.
9058 * ==== Resource Limits
9060 * Use execution options to set resource limits.
9062 * The keys for these options are symbols of the form
9063 * <tt>:rlimit_<i>resource_name</i></tt>,
9064 * where _resource_name_ is the downcased form of one of the string
9065 * resource names described at method Process.setrlimit.
9066 * For example, key +:rlimit_cpu+ corresponds to resource limit <tt>'CPU'</tt>.
9068 * The value for such as key is one of:
9070 * - An integer, specifying both the current and maximum limits.
9071 * - A 2-element array of integers, specifying the current and maximum limits.
9073 * ==== \File Descriptor Inheritance
9075 * By default, the new process inherits file descriptors from the parent process.
9077 * Use execution option <tt>:close_others => true</tt> to modify that inheritance
9078 * by closing non-standard fds (3 and greater) that are not otherwise redirected.
9080 * === Execution Shell
9082 * On a Unix-like system, the shell invoked is <tt>/bin/sh</tt>;
9083 * the entire string +command_line+ is passed as an argument
9084 * to {shell option -c}[https://pubs.opengroup.org/onlinepubs/9699919799.2018edition/utilities/sh.html].
9086 * The shell performs normal shell expansion on the command line:
9088 * Example:
9090 * system('echo $SHELL: C*') # => true
9092 * Output:
9094 * /bin/bash: CONTRIBUTING.md COPYING COPYING.ja
9096 * ==== Execution Shell on Windows
9098 * On Windows, the shell invoked is determined by environment variable
9099 * +RUBYSHELL+, if defined, or +COMSPEC+ otherwise; the entire string
9100 * +command_line+ is passed as an argument to <tt>-c</tt> option for
9101 * +RUBYSHELL+, as well as <tt>/bin/sh</tt>, and {/c
9102 * option}[https://learn.microsoft.com/en-us/windows-server/administration/windows-commands/cmd]
9103 * for +COMSPEC+. The shell is invoked automatically in the following
9104 * cases:
9106 * - The command is a built-in of +cmd.exe+, such as +echo+.
9107 * - The executable file is a batch file; its name ends with +.bat+ or
9108 * +.cmd+.
9110 * Note that the command will still be invoked as +command_line+ form
9111 * even when called in +exe_path+ form, because +cmd.exe+ does not
9112 * accept a script name like <tt>/bin/sh</tt> does but only works with
9113 * <tt>/c</tt> option.
9115 * The standard shell +cmd.exe+ performs environment variable
9116 * expansion but does not have globbing functionality:
9118 * Example:
9120 * system("echo %COMSPEC%: C*")' # => true
9122 * Output:
9124 * C:\WINDOWS\system32\cmd.exe: C*
9126 * == What's Here
9128 * === Current-Process Getters
9130 * - ::argv0: Returns the process name as a frozen string.
9131 * - ::egid: Returns the effective group ID.
9132 * - ::euid: Returns the effective user ID.
9133 * - ::getpgrp: Return the process group ID.
9134 * - ::getrlimit: Returns the resource limit.
9135 * - ::gid: Returns the (real) group ID.
9136 * - ::pid: Returns the process ID.
9137 * - ::ppid: Returns the process ID of the parent process.
9138 * - ::uid: Returns the (real) user ID.
9140 * === Current-Process Setters
9142 * - ::egid=: Sets the effective group ID.
9143 * - ::euid=: Sets the effective user ID.
9144 * - ::gid=: Sets the (real) group ID.
9145 * - ::setproctitle: Sets the process title.
9146 * - ::setpgrp: Sets the process group ID of the process to zero.
9147 * - ::setrlimit: Sets a resource limit.
9148 * - ::setsid: Establishes the process as a new session and process group leader,
9149 * with no controlling tty.
9150 * - ::uid=: Sets the user ID.
9152 * === Current-Process Execution
9154 * - ::abort: Immediately terminates the process.
9155 * - ::daemon: Detaches the process from its controlling terminal
9156 * and continues running it in the background as system daemon.
9157 * - ::exec: Replaces the process by running a given external command.
9158 * - ::exit: Initiates process termination by raising exception SystemExit
9159 * (which may be caught).
9160 * - ::exit!: Immediately exits the process.
9161 * - ::warmup: Notifies the Ruby virtual machine that the boot sequence
9162 * for the application is completed,
9163 * and that the VM may begin optimizing the application.
9165 * === Child Processes
9167 * - ::detach: Guards against a child process becoming a zombie.
9168 * - ::fork: Creates a child process.
9169 * - ::kill: Sends a given signal to processes.
9170 * - ::spawn: Creates a child process.
9171 * - ::wait, ::waitpid: Waits for a child process to exit; returns its process ID.
9172 * - ::wait2, ::waitpid2: Waits for a child process to exit; returns its process ID and status.
9173 * - ::waitall: Waits for all child processes to exit;
9174 * returns their process IDs and statuses.
9176 * === \Process Groups
9178 * - ::getpgid: Returns the process group ID for a process.
9179 * - ::getpriority: Returns the scheduling priority
9180 * for a process, process group, or user.
9181 * - ::getsid: Returns the session ID for a process.
9182 * - ::groups: Returns an array of the group IDs
9183 * in the supplemental group access list for this process.
9184 * - ::groups=: Sets the supplemental group access list
9185 * to the given array of group IDs.
9186 * - ::initgroups: Initializes the supplemental group access list.
9187 * - ::last_status: Returns the status of the last executed child process
9188 * in the current thread.
9189 * - ::maxgroups: Returns the maximum number of group IDs allowed
9190 * in the supplemental group access list.
9191 * - ::maxgroups=: Sets the maximum number of group IDs allowed
9192 * in the supplemental group access list.
9193 * - ::setpgid: Sets the process group ID of a process.
9194 * - ::setpriority: Sets the scheduling priority
9195 * for a process, process group, or user.
9197 * === Timing
9199 * - ::clock_getres: Returns the resolution of a system clock.
9200 * - ::clock_gettime: Returns the time from a system clock.
9201 * - ::times: Returns a Process::Tms object containing times
9202 * for the current process and its child processes.
9206 void
9207 InitVM_process(void)
9209 rb_define_virtual_variable("$?", get_CHILD_STATUS, 0);
9210 rb_define_virtual_variable("$$", get_PROCESS_ID, 0);
9212 rb_gvar_ractor_local("$$");
9213 rb_gvar_ractor_local("$?");
9215 rb_define_global_function("exec", f_exec, -1);
9216 rb_define_global_function("fork", rb_f_fork, 0);
9217 rb_define_global_function("exit!", rb_f_exit_bang, -1);
9218 rb_define_global_function("system", rb_f_system, -1);
9219 rb_define_global_function("spawn", rb_f_spawn, -1);
9220 rb_define_global_function("sleep", rb_f_sleep, -1);
9221 rb_define_global_function("exit", f_exit, -1);
9222 rb_define_global_function("abort", f_abort, -1);
9224 rb_mProcess = rb_define_module("Process");
9226 #ifdef WNOHANG
9227 /* see Process.wait */
9228 rb_define_const(rb_mProcess, "WNOHANG", INT2FIX(WNOHANG));
9229 #else
9230 /* see Process.wait */
9231 rb_define_const(rb_mProcess, "WNOHANG", INT2FIX(0));
9232 #endif
9233 #ifdef WUNTRACED
9234 /* see Process.wait */
9235 rb_define_const(rb_mProcess, "WUNTRACED", INT2FIX(WUNTRACED));
9236 #else
9237 /* see Process.wait */
9238 rb_define_const(rb_mProcess, "WUNTRACED", INT2FIX(0));
9239 #endif
9241 rb_define_singleton_method(rb_mProcess, "exec", f_exec, -1);
9242 rb_define_singleton_method(rb_mProcess, "fork", rb_f_fork, 0);
9243 rb_define_singleton_method(rb_mProcess, "spawn", rb_f_spawn, -1);
9244 rb_define_singleton_method(rb_mProcess, "exit!", rb_f_exit_bang, -1);
9245 rb_define_singleton_method(rb_mProcess, "exit", f_exit, -1);
9246 rb_define_singleton_method(rb_mProcess, "abort", f_abort, -1);
9247 rb_define_singleton_method(rb_mProcess, "last_status", proc_s_last_status, 0);
9248 rb_define_singleton_method(rb_mProcess, "_fork", rb_proc__fork, 0);
9250 rb_define_module_function(rb_mProcess, "kill", proc_rb_f_kill, -1);
9251 rb_define_module_function(rb_mProcess, "wait", proc_m_wait, -1);
9252 rb_define_module_function(rb_mProcess, "wait2", proc_wait2, -1);
9253 rb_define_module_function(rb_mProcess, "waitpid", proc_m_wait, -1);
9254 rb_define_module_function(rb_mProcess, "waitpid2", proc_wait2, -1);
9255 rb_define_module_function(rb_mProcess, "waitall", proc_waitall, 0);
9256 rb_define_module_function(rb_mProcess, "detach", proc_detach, 1);
9258 /* :nodoc: */
9259 rb_cWaiter = rb_define_class_under(rb_mProcess, "Waiter", rb_cThread);
9260 rb_undef_alloc_func(rb_cWaiter);
9261 rb_undef_method(CLASS_OF(rb_cWaiter), "new");
9262 rb_define_method(rb_cWaiter, "pid", detach_process_pid, 0);
9264 rb_cProcessStatus = rb_define_class_under(rb_mProcess, "Status", rb_cObject);
9265 rb_define_alloc_func(rb_cProcessStatus, rb_process_status_allocate);
9266 rb_undef_method(CLASS_OF(rb_cProcessStatus), "new");
9267 rb_marshal_define_compat(rb_cProcessStatus, rb_cObject,
9268 process_status_dump, process_status_load);
9270 rb_define_singleton_method(rb_cProcessStatus, "wait", rb_process_status_waitv, -1);
9272 rb_define_method(rb_cProcessStatus, "==", pst_equal, 1);
9273 rb_define_method(rb_cProcessStatus, "&", pst_bitand, 1);
9274 rb_define_method(rb_cProcessStatus, ">>", pst_rshift, 1);
9275 rb_define_method(rb_cProcessStatus, "to_i", pst_to_i, 0);
9276 rb_define_method(rb_cProcessStatus, "to_s", pst_to_s, 0);
9277 rb_define_method(rb_cProcessStatus, "inspect", pst_inspect, 0);
9279 rb_define_method(rb_cProcessStatus, "pid", pst_pid_m, 0);
9281 rb_define_method(rb_cProcessStatus, "stopped?", pst_wifstopped, 0);
9282 rb_define_method(rb_cProcessStatus, "stopsig", pst_wstopsig, 0);
9283 rb_define_method(rb_cProcessStatus, "signaled?", pst_wifsignaled, 0);
9284 rb_define_method(rb_cProcessStatus, "termsig", pst_wtermsig, 0);
9285 rb_define_method(rb_cProcessStatus, "exited?", pst_wifexited, 0);
9286 rb_define_method(rb_cProcessStatus, "exitstatus", pst_wexitstatus, 0);
9287 rb_define_method(rb_cProcessStatus, "success?", pst_success_p, 0);
9288 rb_define_method(rb_cProcessStatus, "coredump?", pst_wcoredump, 0);
9290 rb_define_module_function(rb_mProcess, "pid", proc_get_pid, 0);
9291 rb_define_module_function(rb_mProcess, "ppid", proc_get_ppid, 0);
9293 rb_define_module_function(rb_mProcess, "getpgrp", proc_getpgrp, 0);
9294 rb_define_module_function(rb_mProcess, "setpgrp", proc_setpgrp, 0);
9295 rb_define_module_function(rb_mProcess, "getpgid", proc_getpgid, 1);
9296 rb_define_module_function(rb_mProcess, "setpgid", proc_setpgid, 2);
9298 rb_define_module_function(rb_mProcess, "getsid", proc_getsid, -1);
9299 rb_define_module_function(rb_mProcess, "setsid", proc_setsid, 0);
9301 rb_define_module_function(rb_mProcess, "getpriority", proc_getpriority, 2);
9302 rb_define_module_function(rb_mProcess, "setpriority", proc_setpriority, 3);
9304 rb_define_module_function(rb_mProcess, "warmup", proc_warmup, 0);
9306 #ifdef HAVE_GETPRIORITY
9307 /* see Process.setpriority */
9308 rb_define_const(rb_mProcess, "PRIO_PROCESS", INT2FIX(PRIO_PROCESS));
9309 /* see Process.setpriority */
9310 rb_define_const(rb_mProcess, "PRIO_PGRP", INT2FIX(PRIO_PGRP));
9311 /* see Process.setpriority */
9312 rb_define_const(rb_mProcess, "PRIO_USER", INT2FIX(PRIO_USER));
9313 #endif
9315 rb_define_module_function(rb_mProcess, "getrlimit", proc_getrlimit, 1);
9316 rb_define_module_function(rb_mProcess, "setrlimit", proc_setrlimit, -1);
9317 #if defined(RLIM2NUM) && defined(RLIM_INFINITY)
9319 VALUE inf = RLIM2NUM(RLIM_INFINITY);
9320 #ifdef RLIM_SAVED_MAX
9322 VALUE v = RLIM_INFINITY == RLIM_SAVED_MAX ? inf : RLIM2NUM(RLIM_SAVED_MAX);
9323 /* see Process.setrlimit */
9324 rb_define_const(rb_mProcess, "RLIM_SAVED_MAX", v);
9326 #endif
9327 /* see Process.setrlimit */
9328 rb_define_const(rb_mProcess, "RLIM_INFINITY", inf);
9329 #ifdef RLIM_SAVED_CUR
9331 VALUE v = RLIM_INFINITY == RLIM_SAVED_CUR ? inf : RLIM2NUM(RLIM_SAVED_CUR);
9332 /* see Process.setrlimit */
9333 rb_define_const(rb_mProcess, "RLIM_SAVED_CUR", v);
9335 #endif
9337 #ifdef RLIMIT_AS
9338 /* Maximum size of the process's virtual memory (address space) in bytes.
9340 * see the system getrlimit(2) manual for details.
9342 rb_define_const(rb_mProcess, "RLIMIT_AS", INT2FIX(RLIMIT_AS));
9343 #endif
9344 #ifdef RLIMIT_CORE
9345 /* Maximum size of the core file.
9347 * see the system getrlimit(2) manual for details.
9349 rb_define_const(rb_mProcess, "RLIMIT_CORE", INT2FIX(RLIMIT_CORE));
9350 #endif
9351 #ifdef RLIMIT_CPU
9352 /* CPU time limit in seconds.
9354 * see the system getrlimit(2) manual for details.
9356 rb_define_const(rb_mProcess, "RLIMIT_CPU", INT2FIX(RLIMIT_CPU));
9357 #endif
9358 #ifdef RLIMIT_DATA
9359 /* Maximum size of the process's data segment.
9361 * see the system getrlimit(2) manual for details.
9363 rb_define_const(rb_mProcess, "RLIMIT_DATA", INT2FIX(RLIMIT_DATA));
9364 #endif
9365 #ifdef RLIMIT_FSIZE
9366 /* Maximum size of files that the process may create.
9368 * see the system getrlimit(2) manual for details.
9370 rb_define_const(rb_mProcess, "RLIMIT_FSIZE", INT2FIX(RLIMIT_FSIZE));
9371 #endif
9372 #ifdef RLIMIT_MEMLOCK
9373 /* Maximum number of bytes of memory that may be locked into RAM.
9375 * see the system getrlimit(2) manual for details.
9377 rb_define_const(rb_mProcess, "RLIMIT_MEMLOCK", INT2FIX(RLIMIT_MEMLOCK));
9378 #endif
9379 #ifdef RLIMIT_MSGQUEUE
9380 /* Specifies the limit on the number of bytes that can be allocated
9381 * for POSIX message queues for the real user ID of the calling process.
9383 * see the system getrlimit(2) manual for details.
9385 rb_define_const(rb_mProcess, "RLIMIT_MSGQUEUE", INT2FIX(RLIMIT_MSGQUEUE));
9386 #endif
9387 #ifdef RLIMIT_NICE
9388 /* Specifies a ceiling to which the process's nice value can be raised.
9390 * see the system getrlimit(2) manual for details.
9392 rb_define_const(rb_mProcess, "RLIMIT_NICE", INT2FIX(RLIMIT_NICE));
9393 #endif
9394 #ifdef RLIMIT_NOFILE
9395 /* Specifies a value one greater than the maximum file descriptor
9396 * number that can be opened by this process.
9398 * see the system getrlimit(2) manual for details.
9400 rb_define_const(rb_mProcess, "RLIMIT_NOFILE", INT2FIX(RLIMIT_NOFILE));
9401 #endif
9402 #ifdef RLIMIT_NPROC
9403 /* The maximum number of processes that can be created for the
9404 * real user ID of the calling process.
9406 * see the system getrlimit(2) manual for details.
9408 rb_define_const(rb_mProcess, "RLIMIT_NPROC", INT2FIX(RLIMIT_NPROC));
9409 #endif
9410 #ifdef RLIMIT_NPTS
9411 /* The maximum number of pseudo-terminals that can be created for the
9412 * real user ID of the calling process.
9414 * see the system getrlimit(2) manual for details.
9416 rb_define_const(rb_mProcess, "RLIMIT_NPTS", INT2FIX(RLIMIT_NPTS));
9417 #endif
9418 #ifdef RLIMIT_RSS
9419 /* Specifies the limit (in pages) of the process's resident set.
9421 * see the system getrlimit(2) manual for details.
9423 rb_define_const(rb_mProcess, "RLIMIT_RSS", INT2FIX(RLIMIT_RSS));
9424 #endif
9425 #ifdef RLIMIT_RTPRIO
9426 /* Specifies a ceiling on the real-time priority that may be set for this process.
9428 * see the system getrlimit(2) manual for details.
9430 rb_define_const(rb_mProcess, "RLIMIT_RTPRIO", INT2FIX(RLIMIT_RTPRIO));
9431 #endif
9432 #ifdef RLIMIT_RTTIME
9433 /* Specifies limit on CPU time this process scheduled under a real-time
9434 * scheduling policy can consume.
9436 * see the system getrlimit(2) manual for details.
9438 rb_define_const(rb_mProcess, "RLIMIT_RTTIME", INT2FIX(RLIMIT_RTTIME));
9439 #endif
9440 #ifdef RLIMIT_SBSIZE
9441 /* Maximum size of the socket buffer.
9443 rb_define_const(rb_mProcess, "RLIMIT_SBSIZE", INT2FIX(RLIMIT_SBSIZE));
9444 #endif
9445 #ifdef RLIMIT_SIGPENDING
9446 /* Specifies a limit on the number of signals that may be queued for
9447 * the real user ID of the calling process.
9449 * see the system getrlimit(2) manual for details.
9451 rb_define_const(rb_mProcess, "RLIMIT_SIGPENDING", INT2FIX(RLIMIT_SIGPENDING));
9452 #endif
9453 #ifdef RLIMIT_STACK
9454 /* Maximum size of the stack, in bytes.
9456 * see the system getrlimit(2) manual for details.
9458 rb_define_const(rb_mProcess, "RLIMIT_STACK", INT2FIX(RLIMIT_STACK));
9459 #endif
9460 #endif
9462 rb_define_module_function(rb_mProcess, "uid", proc_getuid, 0);
9463 rb_define_module_function(rb_mProcess, "uid=", proc_setuid, 1);
9464 rb_define_module_function(rb_mProcess, "gid", proc_getgid, 0);
9465 rb_define_module_function(rb_mProcess, "gid=", proc_setgid, 1);
9466 rb_define_module_function(rb_mProcess, "euid", proc_geteuid, 0);
9467 rb_define_module_function(rb_mProcess, "euid=", proc_seteuid_m, 1);
9468 rb_define_module_function(rb_mProcess, "egid", proc_getegid, 0);
9469 rb_define_module_function(rb_mProcess, "egid=", proc_setegid_m, 1);
9470 rb_define_module_function(rb_mProcess, "initgroups", proc_initgroups, 2);
9471 rb_define_module_function(rb_mProcess, "groups", proc_getgroups, 0);
9472 rb_define_module_function(rb_mProcess, "groups=", proc_setgroups, 1);
9473 rb_define_module_function(rb_mProcess, "maxgroups", proc_getmaxgroups, 0);
9474 rb_define_module_function(rb_mProcess, "maxgroups=", proc_setmaxgroups, 1);
9476 rb_define_module_function(rb_mProcess, "daemon", proc_daemon, -1);
9478 rb_define_module_function(rb_mProcess, "times", rb_proc_times, 0);
9480 #if defined(RUBY_CLOCK_REALTIME)
9481 #elif defined(RUBY_GETTIMEOFDAY_BASED_CLOCK_REALTIME)
9482 # define RUBY_CLOCK_REALTIME RUBY_GETTIMEOFDAY_BASED_CLOCK_REALTIME
9483 #elif defined(RUBY_TIME_BASED_CLOCK_REALTIME)
9484 # define RUBY_CLOCK_REALTIME RUBY_TIME_BASED_CLOCK_REALTIME
9485 #endif
9486 #if defined(CLOCK_REALTIME) && defined(CLOCKID2NUM)
9487 /* see Process.clock_gettime */
9488 rb_define_const(rb_mProcess, "CLOCK_REALTIME", CLOCKID2NUM(CLOCK_REALTIME));
9489 #elif defined(RUBY_CLOCK_REALTIME)
9490 rb_define_const(rb_mProcess, "CLOCK_REALTIME", RUBY_CLOCK_REALTIME);
9491 #endif
9493 #if defined(RUBY_CLOCK_MONOTONIC)
9494 #elif defined(RUBY_MACH_ABSOLUTE_TIME_BASED_CLOCK_MONOTONIC)
9495 # define RUBY_CLOCK_MONOTONIC RUBY_MACH_ABSOLUTE_TIME_BASED_CLOCK_MONOTONIC
9496 #endif
9497 #if defined(CLOCK_MONOTONIC) && defined(CLOCKID2NUM)
9498 /* see Process.clock_gettime */
9499 rb_define_const(rb_mProcess, "CLOCK_MONOTONIC", CLOCKID2NUM(CLOCK_MONOTONIC));
9500 #elif defined(RUBY_CLOCK_MONOTONIC)
9501 rb_define_const(rb_mProcess, "CLOCK_MONOTONIC", RUBY_CLOCK_MONOTONIC);
9502 #endif
9504 #if defined(RUBY_CLOCK_PROCESS_CPUTIME_ID)
9505 #elif defined(RUBY_GETRUSAGE_BASED_CLOCK_PROCESS_CPUTIME_ID)
9506 # define RUBY_CLOCK_PROCESS_CPUTIME_ID RUBY_GETRUSAGE_BASED_CLOCK_PROCESS_CPUTIME_ID
9507 #endif
9508 #if defined(CLOCK_PROCESS_CPUTIME_ID) && defined(CLOCKID2NUM)
9509 /* see Process.clock_gettime */
9510 rb_define_const(rb_mProcess, "CLOCK_PROCESS_CPUTIME_ID", CLOCKID2NUM(CLOCK_PROCESS_CPUTIME_ID));
9511 #elif defined(RUBY_CLOCK_PROCESS_CPUTIME_ID)
9512 rb_define_const(rb_mProcess, "CLOCK_PROCESS_CPUTIME_ID", RUBY_CLOCK_PROCESS_CPUTIME_ID);
9513 #endif
9515 #if defined(CLOCK_THREAD_CPUTIME_ID) && defined(CLOCKID2NUM)
9516 /* see Process.clock_gettime */
9517 rb_define_const(rb_mProcess, "CLOCK_THREAD_CPUTIME_ID", CLOCKID2NUM(CLOCK_THREAD_CPUTIME_ID));
9518 #elif defined(RUBY_CLOCK_THREAD_CPUTIME_ID)
9519 rb_define_const(rb_mProcess, "CLOCK_THREAD_CPUTIME_ID", RUBY_CLOCK_THREAD_CPUTIME_ID);
9520 #endif
9522 #ifdef CLOCKID2NUM
9523 #ifdef CLOCK_VIRTUAL
9524 /* see Process.clock_gettime */
9525 rb_define_const(rb_mProcess, "CLOCK_VIRTUAL", CLOCKID2NUM(CLOCK_VIRTUAL));
9526 #endif
9527 #ifdef CLOCK_PROF
9528 /* see Process.clock_gettime */
9529 rb_define_const(rb_mProcess, "CLOCK_PROF", CLOCKID2NUM(CLOCK_PROF));
9530 #endif
9531 #ifdef CLOCK_REALTIME_FAST
9532 /* see Process.clock_gettime */
9533 rb_define_const(rb_mProcess, "CLOCK_REALTIME_FAST", CLOCKID2NUM(CLOCK_REALTIME_FAST));
9534 #endif
9535 #ifdef CLOCK_REALTIME_PRECISE
9536 /* see Process.clock_gettime */
9537 rb_define_const(rb_mProcess, "CLOCK_REALTIME_PRECISE", CLOCKID2NUM(CLOCK_REALTIME_PRECISE));
9538 #endif
9539 #ifdef CLOCK_REALTIME_COARSE
9540 /* see Process.clock_gettime */
9541 rb_define_const(rb_mProcess, "CLOCK_REALTIME_COARSE", CLOCKID2NUM(CLOCK_REALTIME_COARSE));
9542 #endif
9543 #ifdef CLOCK_REALTIME_ALARM
9544 /* see Process.clock_gettime */
9545 rb_define_const(rb_mProcess, "CLOCK_REALTIME_ALARM", CLOCKID2NUM(CLOCK_REALTIME_ALARM));
9546 #endif
9547 #ifdef CLOCK_MONOTONIC_FAST
9548 /* see Process.clock_gettime */
9549 rb_define_const(rb_mProcess, "CLOCK_MONOTONIC_FAST", CLOCKID2NUM(CLOCK_MONOTONIC_FAST));
9550 #endif
9551 #ifdef CLOCK_MONOTONIC_PRECISE
9552 /* see Process.clock_gettime */
9553 rb_define_const(rb_mProcess, "CLOCK_MONOTONIC_PRECISE", CLOCKID2NUM(CLOCK_MONOTONIC_PRECISE));
9554 #endif
9555 #ifdef CLOCK_MONOTONIC_RAW
9556 /* see Process.clock_gettime */
9557 rb_define_const(rb_mProcess, "CLOCK_MONOTONIC_RAW", CLOCKID2NUM(CLOCK_MONOTONIC_RAW));
9558 #endif
9559 #ifdef CLOCK_MONOTONIC_RAW_APPROX
9560 /* see Process.clock_gettime */
9561 rb_define_const(rb_mProcess, "CLOCK_MONOTONIC_RAW_APPROX", CLOCKID2NUM(CLOCK_MONOTONIC_RAW_APPROX));
9562 #endif
9563 #ifdef CLOCK_MONOTONIC_COARSE
9564 /* see Process.clock_gettime */
9565 rb_define_const(rb_mProcess, "CLOCK_MONOTONIC_COARSE", CLOCKID2NUM(CLOCK_MONOTONIC_COARSE));
9566 #endif
9567 #ifdef CLOCK_BOOTTIME
9568 /* see Process.clock_gettime */
9569 rb_define_const(rb_mProcess, "CLOCK_BOOTTIME", CLOCKID2NUM(CLOCK_BOOTTIME));
9570 #endif
9571 #ifdef CLOCK_BOOTTIME_ALARM
9572 /* see Process.clock_gettime */
9573 rb_define_const(rb_mProcess, "CLOCK_BOOTTIME_ALARM", CLOCKID2NUM(CLOCK_BOOTTIME_ALARM));
9574 #endif
9575 #ifdef CLOCK_UPTIME
9576 /* see Process.clock_gettime */
9577 rb_define_const(rb_mProcess, "CLOCK_UPTIME", CLOCKID2NUM(CLOCK_UPTIME));
9578 #endif
9579 #ifdef CLOCK_UPTIME_FAST
9580 /* see Process.clock_gettime */
9581 rb_define_const(rb_mProcess, "CLOCK_UPTIME_FAST", CLOCKID2NUM(CLOCK_UPTIME_FAST));
9582 #endif
9583 #ifdef CLOCK_UPTIME_PRECISE
9584 /* see Process.clock_gettime */
9585 rb_define_const(rb_mProcess, "CLOCK_UPTIME_PRECISE", CLOCKID2NUM(CLOCK_UPTIME_PRECISE));
9586 #endif
9587 #ifdef CLOCK_UPTIME_RAW
9588 /* see Process.clock_gettime */
9589 rb_define_const(rb_mProcess, "CLOCK_UPTIME_RAW", CLOCKID2NUM(CLOCK_UPTIME_RAW));
9590 #endif
9591 #ifdef CLOCK_UPTIME_RAW_APPROX
9592 /* see Process.clock_gettime */
9593 rb_define_const(rb_mProcess, "CLOCK_UPTIME_RAW_APPROX", CLOCKID2NUM(CLOCK_UPTIME_RAW_APPROX));
9594 #endif
9595 #ifdef CLOCK_SECOND
9596 /* see Process.clock_gettime */
9597 rb_define_const(rb_mProcess, "CLOCK_SECOND", CLOCKID2NUM(CLOCK_SECOND));
9598 #endif
9599 #ifdef CLOCK_TAI
9600 /* see Process.clock_gettime */
9601 rb_define_const(rb_mProcess, "CLOCK_TAI", CLOCKID2NUM(CLOCK_TAI));
9602 #endif
9603 #endif
9604 rb_define_module_function(rb_mProcess, "clock_gettime", rb_clock_gettime, -1);
9605 rb_define_module_function(rb_mProcess, "clock_getres", rb_clock_getres, -1);
9607 #if defined(HAVE_TIMES) || defined(_WIN32)
9608 rb_cProcessTms = rb_struct_define_under(rb_mProcess, "Tms", "utime", "stime", "cutime", "cstime", NULL);
9609 #if 0 /* for RDoc */
9610 /* user time used in this process */
9611 rb_define_attr(rb_cProcessTms, "utime", TRUE, TRUE);
9612 /* system time used in this process */
9613 rb_define_attr(rb_cProcessTms, "stime", TRUE, TRUE);
9614 /* user time used in the child processes */
9615 rb_define_attr(rb_cProcessTms, "cutime", TRUE, TRUE);
9616 /* system time used in the child processes */
9617 rb_define_attr(rb_cProcessTms, "cstime", TRUE, TRUE);
9618 #endif
9619 #endif
9621 SAVED_USER_ID = geteuid();
9622 SAVED_GROUP_ID = getegid();
9624 rb_mProcUID = rb_define_module_under(rb_mProcess, "UID");
9625 rb_mProcGID = rb_define_module_under(rb_mProcess, "GID");
9627 rb_define_module_function(rb_mProcUID, "rid", proc_getuid, 0);
9628 rb_define_module_function(rb_mProcGID, "rid", proc_getgid, 0);
9629 rb_define_module_function(rb_mProcUID, "eid", proc_geteuid, 0);
9630 rb_define_module_function(rb_mProcGID, "eid", proc_getegid, 0);
9631 rb_define_module_function(rb_mProcUID, "change_privilege", p_uid_change_privilege, 1);
9632 rb_define_module_function(rb_mProcGID, "change_privilege", p_gid_change_privilege, 1);
9633 rb_define_module_function(rb_mProcUID, "grant_privilege", p_uid_grant_privilege, 1);
9634 rb_define_module_function(rb_mProcGID, "grant_privilege", p_gid_grant_privilege, 1);
9635 rb_define_alias(rb_singleton_class(rb_mProcUID), "eid=", "grant_privilege");
9636 rb_define_alias(rb_singleton_class(rb_mProcGID), "eid=", "grant_privilege");
9637 rb_define_module_function(rb_mProcUID, "re_exchange", p_uid_exchange, 0);
9638 rb_define_module_function(rb_mProcGID, "re_exchange", p_gid_exchange, 0);
9639 rb_define_module_function(rb_mProcUID, "re_exchangeable?", p_uid_exchangeable, 0);
9640 rb_define_module_function(rb_mProcGID, "re_exchangeable?", p_gid_exchangeable, 0);
9641 rb_define_module_function(rb_mProcUID, "sid_available?", p_uid_have_saved_id, 0);
9642 rb_define_module_function(rb_mProcGID, "sid_available?", p_gid_have_saved_id, 0);
9643 rb_define_module_function(rb_mProcUID, "switch", p_uid_switch, 0);
9644 rb_define_module_function(rb_mProcGID, "switch", p_gid_switch, 0);
9645 #ifdef p_uid_from_name
9646 rb_define_module_function(rb_mProcUID, "from_name", p_uid_from_name, 1);
9647 #endif
9648 #ifdef p_gid_from_name
9649 rb_define_module_function(rb_mProcGID, "from_name", p_gid_from_name, 1);
9650 #endif
9652 rb_mProcID_Syscall = rb_define_module_under(rb_mProcess, "Sys");
9654 rb_define_module_function(rb_mProcID_Syscall, "getuid", proc_getuid, 0);
9655 rb_define_module_function(rb_mProcID_Syscall, "geteuid", proc_geteuid, 0);
9656 rb_define_module_function(rb_mProcID_Syscall, "getgid", proc_getgid, 0);
9657 rb_define_module_function(rb_mProcID_Syscall, "getegid", proc_getegid, 0);
9659 rb_define_module_function(rb_mProcID_Syscall, "setuid", p_sys_setuid, 1);
9660 rb_define_module_function(rb_mProcID_Syscall, "setgid", p_sys_setgid, 1);
9662 rb_define_module_function(rb_mProcID_Syscall, "setruid", p_sys_setruid, 1);
9663 rb_define_module_function(rb_mProcID_Syscall, "setrgid", p_sys_setrgid, 1);
9665 rb_define_module_function(rb_mProcID_Syscall, "seteuid", p_sys_seteuid, 1);
9666 rb_define_module_function(rb_mProcID_Syscall, "setegid", p_sys_setegid, 1);
9668 rb_define_module_function(rb_mProcID_Syscall, "setreuid", p_sys_setreuid, 2);
9669 rb_define_module_function(rb_mProcID_Syscall, "setregid", p_sys_setregid, 2);
9671 rb_define_module_function(rb_mProcID_Syscall, "setresuid", p_sys_setresuid, 3);
9672 rb_define_module_function(rb_mProcID_Syscall, "setresgid", p_sys_setresgid, 3);
9673 rb_define_module_function(rb_mProcID_Syscall, "issetugid", p_sys_issetugid, 0);
9676 void
9677 Init_process(void)
9679 #define define_id(name) id_##name = rb_intern_const(#name)
9680 define_id(in);
9681 define_id(out);
9682 define_id(err);
9683 define_id(pid);
9684 define_id(uid);
9685 define_id(gid);
9686 define_id(close);
9687 define_id(child);
9688 #ifdef HAVE_SETPGID
9689 define_id(pgroup);
9690 #endif
9691 #ifdef _WIN32
9692 define_id(new_pgroup);
9693 #endif
9694 define_id(unsetenv_others);
9695 define_id(chdir);
9696 define_id(umask);
9697 define_id(close_others);
9698 define_id(nanosecond);
9699 define_id(microsecond);
9700 define_id(millisecond);
9701 define_id(second);
9702 define_id(float_microsecond);
9703 define_id(float_millisecond);
9704 define_id(float_second);
9705 define_id(GETTIMEOFDAY_BASED_CLOCK_REALTIME);
9706 define_id(TIME_BASED_CLOCK_REALTIME);
9707 #ifdef CLOCK_REALTIME
9708 define_id(CLOCK_REALTIME);
9709 #endif
9710 #ifdef CLOCK_MONOTONIC
9711 define_id(CLOCK_MONOTONIC);
9712 #endif
9713 #ifdef CLOCK_PROCESS_CPUTIME_ID
9714 define_id(CLOCK_PROCESS_CPUTIME_ID);
9715 #endif
9716 #ifdef CLOCK_THREAD_CPUTIME_ID
9717 define_id(CLOCK_THREAD_CPUTIME_ID);
9718 #endif
9719 #ifdef HAVE_TIMES
9720 define_id(TIMES_BASED_CLOCK_MONOTONIC);
9721 define_id(TIMES_BASED_CLOCK_PROCESS_CPUTIME_ID);
9722 #endif
9723 #ifdef RUSAGE_SELF
9724 define_id(GETRUSAGE_BASED_CLOCK_PROCESS_CPUTIME_ID);
9725 #endif
9726 define_id(CLOCK_BASED_CLOCK_PROCESS_CPUTIME_ID);
9727 #ifdef __APPLE__
9728 define_id(MACH_ABSOLUTE_TIME_BASED_CLOCK_MONOTONIC);
9729 #endif
9730 define_id(hertz);
9732 InitVM(process);