Ruby 2.1.5p273(2014-11-13revision48405)

- Main Page
- Modules
- Data Structures
- Files

- File List
- Globals

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