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