Ruby 2.7.0p0(2019-12-25revision647ee6f091eafcce70ffb75ddf7e121e192ab217)

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