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