Ruby 2.0.0p353(2013-11-22revision43784)

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