* include/ruby/encoding.h (rb_econv_t): add fields: in_buf_start,
[ruby-svn.git] / process.c
blobc231920eed03533363fdf55bb83223093bd6d949
1 /**********************************************************************
3 process.c -
5 $Author$
6 created at: Tue Aug 10 14:30:50 JST 1993
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
12 **********************************************************************/
14 #include "ruby/ruby.h"
15 #include "ruby/signal.h"
16 #include "ruby/io.h"
17 #include "ruby/util.h"
18 #include "vm_core.h"
20 #include <stdio.h>
21 #include <errno.h>
22 #include <signal.h>
23 #ifdef HAVE_STDLIB_H
24 #include <stdlib.h>
25 #endif
26 #ifdef HAVE_UNISTD_H
27 #include <unistd.h>
28 #endif
29 #ifdef HAVE_FCNTL_H
30 #include <fcntl.h>
31 #endif
32 #ifdef __DJGPP__
33 #include <process.h>
34 #endif
36 #include <time.h>
37 #include <ctype.h>
39 #ifndef EXIT_SUCCESS
40 #define EXIT_SUCCESS 0
41 #endif
42 #ifndef EXIT_FAILURE
43 #define EXIT_FAILURE 1
44 #endif
46 struct timeval rb_time_interval(VALUE);
48 #ifdef HAVE_SYS_WAIT_H
49 # include <sys/wait.h>
50 #endif
51 #ifdef HAVE_SYS_RESOURCE_H
52 # include <sys/resource.h>
53 #endif
54 #ifdef HAVE_SYS_PARAM_H
55 # include <sys/param.h>
56 #endif
57 #ifndef MAXPATHLEN
58 # define MAXPATHLEN 1024
59 #endif
60 #include "ruby/st.h"
62 #ifdef __EMX__
63 #undef HAVE_GETPGRP
64 #endif
66 #include <sys/stat.h>
68 #ifdef HAVE_SYS_TIMES_H
69 #include <sys/times.h>
70 #endif
72 #ifdef HAVE_GRP_H
73 #include <grp.h>
74 #endif
76 #if defined(HAVE_TIMES) || defined(_WIN32)
77 static VALUE rb_cProcessTms;
78 #endif
80 #ifndef WIFEXITED
81 #define WIFEXITED(w) (((w) & 0xff) == 0)
82 #endif
83 #ifndef WIFSIGNALED
84 #define WIFSIGNALED(w) (((w) & 0x7f) > 0 && (((w) & 0x7f) < 0x7f))
85 #endif
86 #ifndef WIFSTOPPED
87 #define WIFSTOPPED(w) (((w) & 0xff) == 0x7f)
88 #endif
89 #ifndef WEXITSTATUS
90 #define WEXITSTATUS(w) (((w) >> 8) & 0xff)
91 #endif
92 #ifndef WTERMSIG
93 #define WTERMSIG(w) ((w) & 0x7f)
94 #endif
95 #ifndef WSTOPSIG
96 #define WSTOPSIG WEXITSTATUS
97 #endif
99 #if defined(__APPLE__) && ( defined(__MACH__) || defined(__DARWIN__) ) && !defined(__MacOS_X__)
100 #define __MacOS_X__ 1
101 #endif
103 #if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__bsdi__)
104 #define HAVE_44BSD_SETUID 1
105 #define HAVE_44BSD_SETGID 1
106 #endif
108 #ifdef __NetBSD__
109 #undef HAVE_SETRUID
110 #undef HAVE_SETRGID
111 #endif
113 #ifdef BROKEN_SETREUID
114 #define setreuid ruby_setreuid
115 #endif
116 #ifdef BROKEN_SETREGID
117 #define setregid ruby_setregid
118 #endif
120 #if defined(HAVE_44BSD_SETUID) || defined(__MacOS_X__)
121 #if !defined(USE_SETREUID) && !defined(BROKEN_SETREUID)
122 #define OBSOLETE_SETREUID 1
123 #endif
124 #if !defined(USE_SETREGID) && !defined(BROKEN_SETREGID)
125 #define OBSOLETE_SETREGID 1
126 #endif
127 #endif
129 #if SIZEOF_RLIM_T == SIZEOF_INT
130 # define RLIM2NUM(v) UINT2NUM(v)
131 # define NUM2RLIM(v) NUM2UINT(v)
132 #elif SIZEOF_RLIM_T == SIZEOF_LONG
133 # define RLIM2NUM(v) ULONG2NUM(v)
134 # define NUM2RLIM(v) NUM2ULONG(v)
135 #elif SIZEOF_RLIM_T == SIZEOF_LONG_LONG
136 # define RLIM2NUM(v) ULL2NUM(v)
137 # define NUM2RLIM(v) NUM2ULL(v)
138 #endif
140 #define preserving_errno(stmts) \
141 do {int saved_errno = errno; stmts; errno = saved_errno;} while (0)
145 * call-seq:
146 * Process.pid => fixnum
148 * Returns the process id of this process. Not available on all
149 * platforms.
151 * Process.pid #=> 27415
154 static VALUE
155 get_pid(void)
157 rb_secure(2);
158 return PIDT2NUM(getpid());
163 * call-seq:
164 * Process.ppid => fixnum
166 * Returns the process id of the parent of this process. Always
167 * returns 0 on NT. Not available on all platforms.
169 * puts "I am #{Process.pid}"
170 * Process.fork { puts "Dad is #{Process.ppid}" }
172 * <em>produces:</em>
174 * I am 27417
175 * Dad is 27417
178 static VALUE
179 get_ppid(void)
181 rb_secure(2);
182 return PIDT2NUM(getppid());
186 /*********************************************************************
188 * Document-class: Process::Status
190 * <code>Process::Status</code> encapsulates the information on the
191 * status of a running or terminated system process. The built-in
192 * variable <code>$?</code> is either +nil+ or a
193 * <code>Process::Status</code> object.
195 * fork { exit 99 } #=> 26557
196 * Process.wait #=> 26557
197 * $?.class #=> Process::Status
198 * $?.to_i #=> 25344
199 * $? >> 8 #=> 99
200 * $?.stopped? #=> false
201 * $?.exited? #=> true
202 * $?.exitstatus #=> 99
204 * Posix systems record information on processes using a 16-bit
205 * integer. The lower bits record the process status (stopped,
206 * exited, signaled) and the upper bits possibly contain additional
207 * information (for example the program's return code in the case of
208 * exited processes). Pre Ruby 1.8, these bits were exposed directly
209 * to the Ruby program. Ruby now encapsulates these in a
210 * <code>Process::Status</code> object. To maximize compatibility,
211 * however, these objects retain a bit-oriented interface. In the
212 * descriptions that follow, when we talk about the integer value of
213 * _stat_, we're referring to this 16 bit value.
216 static VALUE rb_cProcessStatus;
218 VALUE
219 rb_last_status_get(void)
221 return GET_THREAD()->last_status;
224 void
225 rb_last_status_set(int status, rb_pid_t pid)
227 rb_thread_t *th = GET_THREAD();
228 th->last_status = rb_obj_alloc(rb_cProcessStatus);
229 rb_iv_set(th->last_status, "status", INT2FIX(status));
230 rb_iv_set(th->last_status, "pid", PIDT2NUM(pid));
233 static void
234 rb_last_status_clear(void)
236 GET_THREAD()->last_status = Qnil;
240 * call-seq:
241 * stat.to_i => fixnum
242 * stat.to_int => fixnum
244 * Returns the bits in _stat_ as a <code>Fixnum</code>. Poking
245 * around in these bits is platform dependent.
247 * fork { exit 0xab } #=> 26566
248 * Process.wait #=> 26566
249 * sprintf('%04x', $?.to_i) #=> "ab00"
252 static VALUE
253 pst_to_i(VALUE st)
255 return rb_iv_get(st, "status");
258 #define PST2INT(st) NUM2INT(pst_to_i(st))
261 * call-seq:
262 * stat.pid => fixnum
264 * Returns the process ID that this status object represents.
266 * fork { exit } #=> 26569
267 * Process.wait #=> 26569
268 * $?.pid #=> 26569
271 static VALUE
272 pst_pid(VALUE st)
274 return rb_iv_get(st, "pid");
277 static void
278 pst_message(VALUE str, rb_pid_t pid, int status)
280 rb_str_catf(str, "pid %ld", (long)pid);
281 if (WIFSTOPPED(status)) {
282 int stopsig = WSTOPSIG(status);
283 const char *signame = ruby_signal_name(stopsig);
284 if (signame) {
285 rb_str_catf(str, " stopped SIG%s (signal %d)", signame, stopsig);
287 else {
288 rb_str_catf(str, " stopped signal %d", stopsig);
291 if (WIFSIGNALED(status)) {
292 int termsig = WTERMSIG(status);
293 const char *signame = ruby_signal_name(termsig);
294 if (signame) {
295 rb_str_catf(str, " SIG%s (signal %d)", signame, termsig);
297 else {
298 rb_str_catf(str, " signal %d", termsig);
301 if (WIFEXITED(status)) {
302 rb_str_catf(str, " exit %d", WEXITSTATUS(status));
304 #ifdef WCOREDUMP
305 if (WCOREDUMP(status)) {
306 rb_str_cat2(str, " (core dumped)");
308 #endif
313 * call-seq:
314 * stat.to_s => string
316 * Show pid and exit status as a string.
319 static VALUE
320 pst_to_s(VALUE st)
322 rb_pid_t pid;
323 int status;
324 VALUE str;
326 pid = NUM2LONG(pst_pid(st));
327 status = PST2INT(st);
329 str = rb_str_buf_new(0);
330 pst_message(str, pid, status);
331 return str;
336 * call-seq:
337 * stat.inspect => string
339 * Override the inspection method.
342 static VALUE
343 pst_inspect(VALUE st)
345 rb_pid_t pid;
346 int status;
347 VALUE str;
349 pid = NUM2LONG(pst_pid(st));
350 status = PST2INT(st);
352 str = rb_sprintf("#<%s: ", rb_class2name(CLASS_OF(st)));
353 pst_message(str, pid, status);
354 rb_str_cat2(str, ">");
355 return str;
360 * call-seq:
361 * stat == other => true or false
363 * Returns +true+ if the integer value of _stat_
364 * equals <em>other</em>.
367 static VALUE
368 pst_equal(VALUE st1, VALUE st2)
370 if (st1 == st2) return Qtrue;
371 return rb_equal(pst_to_i(st1), st2);
376 * call-seq:
377 * stat & num => fixnum
379 * Logical AND of the bits in _stat_ with <em>num</em>.
381 * fork { exit 0x37 }
382 * Process.wait
383 * sprintf('%04x', $?.to_i) #=> "3700"
384 * sprintf('%04x', $? & 0x1e00) #=> "1600"
387 static VALUE
388 pst_bitand(VALUE st1, VALUE st2)
390 int status = PST2INT(st1) & NUM2INT(st2);
392 return INT2NUM(status);
397 * call-seq:
398 * stat >> num => fixnum
400 * Shift the bits in _stat_ right <em>num</em> places.
402 * fork { exit 99 } #=> 26563
403 * Process.wait #=> 26563
404 * $?.to_i #=> 25344
405 * $? >> 8 #=> 99
408 static VALUE
409 pst_rshift(VALUE st1, VALUE st2)
411 int status = PST2INT(st1) >> NUM2INT(st2);
413 return INT2NUM(status);
418 * call-seq:
419 * stat.stopped? => true or false
421 * Returns +true+ if this process is stopped. This is only
422 * returned if the corresponding <code>wait</code> call had the
423 * <code>WUNTRACED</code> flag set.
426 static VALUE
427 pst_wifstopped(VALUE st)
429 int status = PST2INT(st);
431 if (WIFSTOPPED(status))
432 return Qtrue;
433 else
434 return Qfalse;
439 * call-seq:
440 * stat.stopsig => fixnum or nil
442 * Returns the number of the signal that caused _stat_ to stop
443 * (or +nil+ if self is not stopped).
446 static VALUE
447 pst_wstopsig(VALUE st)
449 int status = PST2INT(st);
451 if (WIFSTOPPED(status))
452 return INT2NUM(WSTOPSIG(status));
453 return Qnil;
458 * call-seq:
459 * stat.signaled? => true or false
461 * Returns +true+ if _stat_ terminated because of
462 * an uncaught signal.
465 static VALUE
466 pst_wifsignaled(VALUE st)
468 int status = PST2INT(st);
470 if (WIFSIGNALED(status))
471 return Qtrue;
472 else
473 return Qfalse;
478 * call-seq:
479 * stat.termsig => fixnum or nil
481 * Returns the number of the signal that caused _stat_ to
482 * terminate (or +nil+ if self was not terminated by an
483 * uncaught signal).
486 static VALUE
487 pst_wtermsig(VALUE st)
489 int status = PST2INT(st);
491 if (WIFSIGNALED(status))
492 return INT2NUM(WTERMSIG(status));
493 return Qnil;
498 * call-seq:
499 * stat.exited? => true or false
501 * Returns +true+ if _stat_ exited normally (for
502 * example using an <code>exit()</code> call or finishing the
503 * program).
506 static VALUE
507 pst_wifexited(VALUE st)
509 int status = PST2INT(st);
511 if (WIFEXITED(status))
512 return Qtrue;
513 else
514 return Qfalse;
519 * call-seq:
520 * stat.exitstatus => fixnum or nil
522 * Returns the least significant eight bits of the return code of
523 * _stat_. Only available if <code>exited?</code> is
524 * +true+.
526 * fork { } #=> 26572
527 * Process.wait #=> 26572
528 * $?.exited? #=> true
529 * $?.exitstatus #=> 0
531 * fork { exit 99 } #=> 26573
532 * Process.wait #=> 26573
533 * $?.exited? #=> true
534 * $?.exitstatus #=> 99
537 static VALUE
538 pst_wexitstatus(VALUE st)
540 int status = PST2INT(st);
542 if (WIFEXITED(status))
543 return INT2NUM(WEXITSTATUS(status));
544 return Qnil;
549 * call-seq:
550 * stat.success? => true, false or nil
552 * Returns +true+ if _stat_ is successful, +false+ if not.
553 * Returns +nil+ if <code>exited?</code> is not +true+.
556 static VALUE
557 pst_success_p(VALUE st)
559 int status = PST2INT(st);
561 if (!WIFEXITED(status))
562 return Qnil;
563 return WEXITSTATUS(status) == EXIT_SUCCESS ? Qtrue : Qfalse;
568 * call-seq:
569 * stat.coredump? => true or false
571 * Returns +true+ if _stat_ generated a coredump
572 * when it terminated. Not available on all platforms.
575 static VALUE
576 pst_wcoredump(VALUE st)
578 #ifdef WCOREDUMP
579 int status = PST2INT(st);
581 if (WCOREDUMP(status))
582 return Qtrue;
583 else
584 return Qfalse;
585 #else
586 return Qfalse;
587 #endif
590 #if !defined(HAVE_WAITPID) && !defined(HAVE_WAIT4)
591 #define NO_WAITPID
592 static st_table *pid_tbl;
593 #else
594 struct waitpid_arg {
595 rb_pid_t pid;
596 int *st;
597 int flags;
599 #endif
601 static VALUE
602 rb_waitpid_blocking(void *data)
604 rb_pid_t result;
605 #ifndef NO_WAITPID
606 struct waitpid_arg *arg = data;
607 #endif
609 TRAP_BEG;
610 #if defined NO_WAITPID
611 result = wait(data);
612 #elif defined HAVE_WAITPID
613 result = waitpid(arg->pid, arg->st, arg->flags);
614 #else /* HAVE_WAIT4 */
615 result = wait4(arg->pid, arg->st, arg->flags, NULL);
616 #endif
617 TRAP_END;
618 return (VALUE)result;
621 rb_pid_t
622 rb_waitpid(rb_pid_t pid, int *st, int flags)
624 rb_pid_t result;
625 #ifndef NO_WAITPID
626 struct waitpid_arg arg;
628 arg.pid = pid;
629 arg.st = st;
630 arg.flags = flags;
631 result = (rb_pid_t)rb_thread_blocking_region(rb_waitpid_blocking, &arg,
632 RB_UBF_DFL, 0);
633 if (result < 0) {
634 #if 0
635 if (errno == EINTR) {
636 rb_thread_polling();
637 goto retry;
639 #endif
640 return -1;
642 #else /* NO_WAITPID */
643 if (pid_tbl && st_lookup(pid_tbl, pid, (st_data_t *)st)) {
644 rb_last_status_set(*st, pid);
645 st_delete(pid_tbl, (st_data_t*)&pid, NULL);
646 return pid;
649 if (flags) {
650 rb_raise(rb_eArgError, "can't do waitpid with flags");
653 for (;;) {
654 result = (rb_pid_t)rb_thread_blocking_region(rb_waitpid_blocking,
655 st, RB_UBF_DFL);
656 if (result < 0) {
657 if (errno == EINTR) {
658 rb_thread_schedule();
659 continue;
661 return -1;
663 if (result == pid) {
664 break;
666 if (!pid_tbl)
667 pid_tbl = st_init_numtable();
668 st_insert(pid_tbl, pid, (st_data_t)st);
669 if (!rb_thread_alone()) rb_thread_schedule();
671 #endif
672 if (result > 0) {
673 rb_last_status_set(*st, result);
675 return result;
678 #ifdef NO_WAITPID
679 struct wait_data {
680 rb_pid_t pid;
681 int status;
684 static int
685 wait_each(rb_pid_t pid, int status, struct wait_data *data)
687 if (data->status != -1) return ST_STOP;
689 data->pid = pid;
690 data->status = status;
691 return ST_DELETE;
694 static int
695 waitall_each(rb_pid_t pid, int status, VALUE ary)
697 rb_last_status_set(status, pid);
698 rb_ary_push(ary, rb_assoc_new(PIDT2NUM(pid), rb_last_status_get());
699 return ST_DELETE;
701 #endif
704 /* [MG]:FIXME: I wasn't sure how this should be done, since ::wait()
705 has historically been documented as if it didn't take any arguments
706 despite the fact that it's just an alias for ::waitpid(). The way I
707 have it below is more truthful, but a little confusing.
709 I also took the liberty of putting in the pid values, as they're
710 pretty useful, and it looked as if the original 'ri' output was
711 supposed to contain them after "[...]depending on the value of
712 aPid:".
714 The 'ansi' and 'bs' formats of the ri output don't display the
715 definition list for some reason, but the plain text one does.
719 * call-seq:
720 * Process.wait() => fixnum
721 * Process.wait(pid=-1, flags=0) => fixnum
722 * Process.waitpid(pid=-1, flags=0) => fixnum
724 * Waits for a child process to exit, returns its process id, and
725 * sets <code>$?</code> to a <code>Process::Status</code> object
726 * containing information on that process. Which child it waits on
727 * depends on the value of _pid_:
729 * > 0:: Waits for the child whose process ID equals _pid_.
731 * 0:: Waits for any child whose process group ID equals that of the
732 * calling process.
734 * -1:: Waits for any child process (the default if no _pid_ is
735 * given).
737 * < -1:: Waits for any child whose process group ID equals the absolute
738 * value of _pid_.
740 * The _flags_ argument may be a logical or of the flag values
741 * <code>Process::WNOHANG</code> (do not block if no child available)
742 * or <code>Process::WUNTRACED</code> (return stopped children that
743 * haven't been reported). Not all flags are available on all
744 * platforms, but a flag value of zero will work on all platforms.
746 * Calling this method raises a <code>SystemError</code> if there are
747 * no child processes. Not available on all platforms.
749 * include Process
750 * fork { exit 99 } #=> 27429
751 * wait #=> 27429
752 * $?.exitstatus #=> 99
754 * pid = fork { sleep 3 } #=> 27440
755 * Time.now #=> 2008-03-08 19:56:16 +0900
756 * waitpid(pid, Process::WNOHANG) #=> nil
757 * Time.now #=> 2008-03-08 19:56:16 +0900
758 * waitpid(pid, 0) #=> 27440
759 * Time.now #=> 2008-03-08 19:56:19 +0900
762 static VALUE
763 proc_wait(int argc, VALUE *argv)
765 VALUE vpid, vflags;
766 rb_pid_t pid;
767 int flags, status;
769 rb_secure(2);
770 flags = 0;
771 if (argc == 0) {
772 pid = -1;
774 else {
775 rb_scan_args(argc, argv, "02", &vpid, &vflags);
776 pid = NUM2PIDT(vpid);
777 if (argc == 2 && !NIL_P(vflags)) {
778 flags = NUM2UINT(vflags);
781 if ((pid = rb_waitpid(pid, &status, flags)) < 0)
782 rb_sys_fail(0);
783 if (pid == 0) {
784 rb_last_status_clear();
785 return Qnil;
787 return PIDT2NUM(pid);
792 * call-seq:
793 * Process.wait2(pid=-1, flags=0) => [pid, status]
794 * Process.waitpid2(pid=-1, flags=0) => [pid, status]
796 * Waits for a child process to exit (see Process::waitpid for exact
797 * semantics) and returns an array containing the process id and the
798 * exit status (a <code>Process::Status</code> object) of that
799 * child. Raises a <code>SystemError</code> if there are no child
800 * processes.
802 * Process.fork { exit 99 } #=> 27437
803 * pid, status = Process.wait2
804 * pid #=> 27437
805 * status.exitstatus #=> 99
808 static VALUE
809 proc_wait2(int argc, VALUE *argv)
811 VALUE pid = proc_wait(argc, argv);
812 if (NIL_P(pid)) return Qnil;
813 return rb_assoc_new(pid, rb_last_status_get());
818 * call-seq:
819 * Process.waitall => [ [pid1,status1], ...]
821 * Waits for all children, returning an array of
822 * _pid_/_status_ pairs (where _status_ is a
823 * <code>Process::Status</code> object).
825 * fork { sleep 0.2; exit 2 } #=> 27432
826 * fork { sleep 0.1; exit 1 } #=> 27433
827 * fork { exit 0 } #=> 27434
828 * p Process.waitall
830 * <em>produces</em>:
832 * [[27434, #<Process::Status: pid=27434,exited(0)>],
833 * [27433, #<Process::Status: pid=27433,exited(1)>],
834 * [27432, #<Process::Status: pid=27432,exited(2)>]]
837 static VALUE
838 proc_waitall(void)
840 VALUE result;
841 rb_pid_t pid;
842 int status;
844 rb_secure(2);
845 result = rb_ary_new();
846 #ifdef NO_WAITPID
847 if (pid_tbl) {
848 st_foreach(pid_tbl, waitall_each, result);
850 #else
851 rb_last_status_clear();
852 #endif
854 for (pid = -1;;) {
855 #ifdef NO_WAITPID
856 pid = wait(&status);
857 #else
858 pid = rb_waitpid(-1, &status, 0);
859 #endif
860 if (pid == -1) {
861 if (errno == ECHILD)
862 break;
863 #ifdef NO_WAITPID
864 if (errno == EINTR) {
865 rb_thread_schedule();
866 continue;
868 #endif
869 rb_sys_fail(0);
871 #ifdef NO_WAITPID
872 rb_last_status_set(status, pid);
873 #endif
874 rb_ary_push(result, rb_assoc_new(PIDT2NUM(pid), rb_last_status_get()));
876 return result;
879 static inline ID
880 id_pid(void)
882 ID pid;
883 CONST_ID(pid, "pid");
884 return pid;
887 static VALUE
888 detach_process_pid(VALUE thread)
890 return rb_thread_local_aref(thread, id_pid());
893 static VALUE
894 detach_process_watcher(void *arg)
896 rb_pid_t cpid, pid = (rb_pid_t)(VALUE)arg;
897 int status;
899 while ((cpid = rb_waitpid(pid, &status, 0)) == 0) {
900 /* wait while alive */
902 return rb_last_status_get();
905 VALUE
906 rb_detach_process(rb_pid_t pid)
908 VALUE watcher = rb_thread_create(detach_process_watcher, (void*)(VALUE)pid);
909 rb_thread_local_aset(watcher, id_pid(), PIDT2NUM(pid));
910 rb_define_singleton_method(watcher, "pid", detach_process_pid, 0);
911 return watcher;
916 * call-seq:
917 * Process.detach(pid) => thread
919 * Some operating systems retain the status of terminated child
920 * processes until the parent collects that status (normally using
921 * some variant of <code>wait()</code>. If the parent never collects
922 * this status, the child stays around as a <em>zombie</em> process.
923 * <code>Process::detach</code> prevents this by setting up a
924 * separate Ruby thread whose sole job is to reap the status of the
925 * process _pid_ when it terminates. Use <code>detach</code>
926 * only when you do not intent to explicitly wait for the child to
927 * terminate.
929 * The waiting thread returns the exit status of the detached process
930 * when it terminates, so you can use <code>Thread#join</code> to
931 * know the result. If specified _pid_ is not a valid child process
932 * ID, the thread returns +nil+ immediately.
934 * In this first example, we don't reap the first child process, so
935 * it appears as a zombie in the process status display.
937 * p1 = fork { sleep 0.1 }
938 * p2 = fork { sleep 0.2 }
939 * Process.waitpid(p2)
940 * sleep 2
941 * system("ps -ho pid,state -p #{p1}")
943 * <em>produces:</em>
945 * 27389 Z
947 * In the next example, <code>Process::detach</code> is used to reap
948 * the child automatically.
950 * p1 = fork { sleep 0.1 }
951 * p2 = fork { sleep 0.2 }
952 * Process.detach(p1)
953 * Process.waitpid(p2)
954 * sleep 2
955 * system("ps -ho pid,state -p #{p1}")
957 * <em>(produces no output)</em>
960 static VALUE
961 proc_detach(VALUE obj, VALUE pid)
963 rb_secure(2);
964 return rb_detach_process(NUM2PIDT(pid));
967 #ifndef HAVE_STRING_H
968 char *strtok();
969 #endif
971 void rb_thread_stop_timer_thread(void);
972 void rb_thread_start_timer_thread(void);
973 void rb_thread_reset_timer_thread(void);
975 #define before_exec() \
976 (rb_enable_interrupt(), rb_thread_stop_timer_thread())
977 #define after_exec() \
978 (rb_thread_start_timer_thread(), rb_disable_interrupt())
980 #include "dln.h"
982 static void
983 security(const char *str)
985 if (rb_env_path_tainted()) {
986 if (rb_safe_level() > 0) {
987 rb_raise(rb_eSecurityError, "Insecure PATH - %s", str);
992 static int
993 proc_exec_v(char **argv, const char *prog)
995 char fbuf[MAXPATHLEN];
997 if (!prog)
998 prog = argv[0];
999 prog = dln_find_exe_r(prog, 0, fbuf, sizeof(fbuf));
1000 if (!prog) {
1001 errno = ENOENT;
1002 return -1;
1005 #if (defined(MSDOS) && !defined(DJGPP)) || defined(__human68k__) || defined(__EMX__) || defined(OS2)
1007 #if defined(__human68k__)
1008 #define COMMAND "command.x"
1009 #endif
1010 #if defined(__EMX__) || defined(OS2) /* OS/2 emx */
1011 #define COMMAND "cmd.exe"
1012 #endif
1013 #if (defined(MSDOS) && !defined(DJGPP))
1014 #define COMMAND "command.com"
1015 #endif
1016 char *extension;
1018 if ((extension = strrchr(prog, '.')) != NULL && STRCASECMP(extension, ".bat") == 0) {
1019 char **new_argv;
1020 char *p;
1021 int n;
1023 for (n = 0; argv[n]; n++)
1024 /* no-op */;
1025 new_argv = ALLOCA_N(char*, n + 2);
1026 for (; n > 0; n--)
1027 new_argv[n + 1] = argv[n];
1028 new_argv[1] = strcpy(ALLOCA_N(char, strlen(argv[0]) + 1), argv[0]);
1029 for (p = new_argv[1]; *p != '\0'; p++)
1030 if (*p == '/')
1031 *p = '\\';
1032 new_argv[0] = COMMAND;
1033 argv = new_argv;
1034 prog = dln_find_exe_r(argv[0], 0, fbuf, sizeof(fbuf));
1035 if (!prog) {
1036 errno = ENOENT;
1037 return -1;
1041 #endif /* MSDOS or __human68k__ or __EMX__ */
1042 before_exec();
1043 execv(prog, argv);
1044 preserving_errno(after_exec());
1045 return -1;
1049 rb_proc_exec_n(int argc, VALUE *argv, const char *prog)
1051 char **args;
1052 int i;
1054 args = ALLOCA_N(char*, argc+1);
1055 for (i=0; i<argc; i++) {
1056 args[i] = RSTRING_PTR(argv[i]);
1058 args[i] = 0;
1059 if (args[0]) {
1060 return proc_exec_v(args, prog);
1062 return -1;
1066 rb_proc_exec(const char *str)
1068 #ifndef _WIN32
1069 const char *s = str;
1070 char *ss, *t;
1071 char **argv, **a;
1072 #endif
1074 while (*str && ISSPACE(*str))
1075 str++;
1077 #ifdef _WIN32
1078 before_exec();
1079 rb_w32_spawn(P_OVERLAY, (char *)str, 0);
1080 after_exec();
1081 #else
1082 for (s=str; *s; s++) {
1083 if (ISSPACE(*s)) {
1084 const char *p, *nl = NULL;
1085 for (p = s; ISSPACE(*p); p++) {
1086 if (*p == '\n') nl = p;
1088 if (!*p) break;
1089 if (nl) s = nl;
1091 if (*s != ' ' && !ISALPHA(*s) && strchr("*?{}[]<>()~&|\\$;'`\"\n",*s)) {
1092 #if defined(MSDOS)
1093 int status;
1094 before_exec();
1095 status = system(str);
1096 after_exec();
1097 if (status != -1)
1098 exit(status);
1099 #elif defined(__human68k__) || defined(__CYGWIN32__) || defined(__EMX__)
1100 char fbuf[MAXPATHLEN];
1101 char *shell = dln_find_exe_r("sh", 0, fbuf, sizeof(fbuf));
1102 int status = -1;
1103 before_exec();
1104 if (shell)
1105 execl(shell, "sh", "-c", str, (char *) NULL);
1106 else
1107 status = system(str);
1108 after_exec();
1109 if (status != -1)
1110 exit(status);
1111 #else
1112 before_exec();
1113 execl("/bin/sh", "sh", "-c", str, (char *)NULL);
1114 preserving_errno(after_exec());
1115 #endif
1116 return -1;
1119 a = argv = ALLOCA_N(char*, (s-str)/2+2);
1120 ss = ALLOCA_N(char, s-str+1);
1121 memcpy(ss, str, s-str);
1122 ss[s-str] = '\0';
1123 if ((*a++ = strtok(ss, " \t")) != 0) {
1124 while ((t = strtok(NULL, " \t")) != 0) {
1125 *a++ = t;
1127 *a = NULL;
1129 if (argv[0]) {
1130 return proc_exec_v(argv, 0);
1132 errno = ENOENT;
1133 #endif /* _WIN32 */
1134 return -1;
1137 #if defined(_WIN32)
1138 #define HAVE_SPAWNV 1
1139 #endif
1141 #if !defined(HAVE_FORK) && defined(HAVE_SPAWNV)
1142 #if defined(_WIN32)
1143 #define proc_spawn_v(argv, prog) rb_w32_aspawn(P_NOWAIT, prog, argv)
1144 #else
1145 static rb_pid_t
1146 proc_spawn_v(char **argv, char *prog)
1148 char fbuf[MAXPATHLEN];
1149 char *extension;
1150 rb_pid_t status;
1152 if (!prog)
1153 prog = argv[0];
1154 security(prog);
1155 prog = dln_find_exe_r(prog, 0, fbuf, sizeof(fbuf));
1156 if (!prog)
1157 return -1;
1159 #if defined(__human68k__)
1160 if ((extension = strrchr(prog, '.')) != NULL && STRCASECMP(extension, ".bat") == 0) {
1161 char **new_argv;
1162 char *p;
1163 int n;
1165 for (n = 0; argv[n]; n++)
1166 /* no-op */;
1167 new_argv = ALLOCA_N(char*, n + 2);
1168 for (; n > 0; n--)
1169 new_argv[n + 1] = argv[n];
1170 new_argv[1] = strcpy(ALLOCA_N(char, strlen(argv[0]) + 1), argv[0]);
1171 for (p = new_argv[1]; *p != '\0'; p++)
1172 if (*p == '/')
1173 *p = '\\';
1174 new_argv[0] = COMMAND;
1175 argv = new_argv;
1176 prog = dln_find_exe_r(argv[0], 0, fbuf, sizeof(fbuf));
1177 if (!prog) {
1178 errno = ENOENT;
1179 return -1;
1182 #endif
1183 before_exec();
1184 status = spawnv(P_WAIT, prog, argv);
1185 rb_last_status_set(status == -1 ? 127 : status, 0);
1186 after_exec();
1187 return status;
1189 #endif
1191 static rb_pid_t
1192 proc_spawn_n(int argc, VALUE *argv, VALUE prog)
1194 char **args;
1195 int i;
1197 args = ALLOCA_N(char*, argc + 1);
1198 for (i = 0; i < argc; i++) {
1199 args[i] = RSTRING_PTR(argv[i]);
1201 args[i] = (char*) 0;
1202 if (args[0])
1203 return proc_spawn_v(args, prog ? RSTRING_PTR(prog) : 0);
1204 return -1;
1207 #if defined(_WIN32)
1208 #define proc_spawn(str) rb_w32_spawn(P_NOWAIT, str, 0)
1209 #else
1210 static rb_pid_t
1211 proc_spawn(char *str)
1213 char fbuf[MAXPATHLEN];
1214 char *s, *t;
1215 char **argv, **a;
1216 rb_pid_t status;
1218 for (s = str; *s; s++) {
1219 if (*s != ' ' && !ISALPHA(*s) && strchr("*?{}[]<>()~&|\\$;'`\"\n",*s)) {
1220 char *shell = dln_find_exe_r("sh", 0, fbuf, sizeof(fbuf));
1221 before_exec();
1222 status = shell?spawnl(P_WAIT,shell,"sh","-c",str,(char*)NULL):system(str);
1223 rb_last_status_set(status == -1 ? 127 : status, 0);
1224 after_exec();
1225 return status;
1228 a = argv = ALLOCA_N(char*, (s - str) / 2 + 2);
1229 s = ALLOCA_N(char, s - str + 1);
1230 strcpy(s, str);
1231 if (*a++ = strtok(s, " \t")) {
1232 while (t = strtok(NULL, " \t"))
1233 *a++ = t;
1234 *a = NULL;
1236 return argv[0] ? proc_spawn_v(argv, 0) : -1;
1238 #endif
1239 #endif
1241 static VALUE
1242 hide_obj(VALUE obj)
1244 RBASIC(obj)->klass = 0;
1245 return obj;
1248 enum {
1249 EXEC_OPTION_PGROUP,
1250 EXEC_OPTION_RLIMIT,
1251 EXEC_OPTION_UNSETENV_OTHERS,
1252 EXEC_OPTION_ENV,
1253 EXEC_OPTION_CHDIR,
1254 EXEC_OPTION_UMASK,
1255 EXEC_OPTION_DUP2,
1256 EXEC_OPTION_CLOSE,
1257 EXEC_OPTION_OPEN,
1258 EXEC_OPTION_CLOSE_OTHERS
1261 static VALUE
1262 check_exec_redirect_fd(VALUE v)
1264 VALUE tmp;
1265 int fd;
1266 if (FIXNUM_P(v)) {
1267 fd = FIX2INT(v);
1269 else if (!NIL_P(tmp = rb_check_convert_type(v, T_FILE, "IO", "to_io"))) {
1270 rb_io_t *fptr;
1271 GetOpenFile(tmp, fptr);
1272 if (fptr->tied_io_for_writing)
1273 rb_raise(rb_eArgError, "duplex IO redirection");
1274 fd = fptr->fd;
1276 else {
1277 rb_raise(rb_eArgError, "wrong exec redirect");
1279 if (fd < 0) {
1280 rb_raise(rb_eArgError, "negative file descriptor");
1282 return INT2FIX(fd);
1285 static void
1286 check_exec_redirect(VALUE key, VALUE val, VALUE options)
1288 int index;
1289 VALUE ary, param;
1290 VALUE path, flags, perm;
1291 ID id;
1293 switch (TYPE(val)) {
1294 case T_SYMBOL:
1295 id = SYM2ID(val);
1296 if (id == rb_intern("close")) {
1297 index = EXEC_OPTION_CLOSE;
1298 param = Qnil;
1300 else {
1301 rb_raise(rb_eArgError, "wrong exec redirect symbol: %s",
1302 rb_id2name(id));
1304 break;
1306 case T_FILE:
1307 val = check_exec_redirect_fd(val);
1308 /* fall through */
1309 case T_FIXNUM:
1310 index = EXEC_OPTION_DUP2;
1311 param = val;
1312 break;
1314 case T_ARRAY:
1315 index = EXEC_OPTION_OPEN;
1316 path = rb_ary_entry(val, 0);
1317 FilePathValue(path);
1318 flags = rb_ary_entry(val, 1);
1319 if (NIL_P(flags))
1320 flags = INT2NUM(O_RDONLY);
1321 else if (TYPE(flags) == T_STRING)
1322 flags = INT2NUM(rb_io_mode_modenum(StringValueCStr(flags)));
1323 else
1324 flags = rb_to_int(flags);
1325 perm = rb_ary_entry(val, 2);
1326 perm = NIL_P(perm) ? INT2FIX(0644) : rb_to_int(perm);
1327 param = hide_obj(rb_ary_new3(3, hide_obj(rb_str_dup(path)),
1328 flags, perm));
1329 break;
1331 case T_STRING:
1332 index = EXEC_OPTION_OPEN;
1333 path = val;
1334 FilePathValue(path);
1335 if ((FIXNUM_P(key) && (FIX2INT(key) == 1 || FIX2INT(key) == 2)) ||
1336 key == rb_stdout || key == rb_stderr)
1337 flags = INT2NUM(O_WRONLY|O_CREAT|O_TRUNC);
1338 else
1339 flags = INT2NUM(O_RDONLY);
1340 perm = INT2FIX(0644);
1341 param = hide_obj(rb_ary_new3(3, hide_obj(rb_str_dup(path)),
1342 flags, perm));
1343 break;
1345 default:
1346 rb_raise(rb_eArgError, "wrong exec redirect action");
1349 ary = rb_ary_entry(options, index);
1350 if (NIL_P(ary)) {
1351 ary = hide_obj(rb_ary_new());
1352 rb_ary_store(options, index, ary);
1354 if (TYPE(key) != T_ARRAY) {
1355 VALUE fd = check_exec_redirect_fd(key);
1356 rb_ary_push(ary, hide_obj(rb_assoc_new(fd, param)));
1358 else {
1359 int i, n=0;
1360 for (i = 0 ; i < RARRAY_LEN(key); i++) {
1361 VALUE v = RARRAY_PTR(key)[i];
1362 VALUE fd = check_exec_redirect_fd(v);
1363 rb_ary_push(ary, hide_obj(rb_assoc_new(fd, param)));
1364 n++;
1369 #ifdef RLIM2NUM
1370 static int rlimit_type_by_lname(const char *name);
1371 #endif
1374 rb_exec_arg_addopt(struct rb_exec_arg *e, VALUE key, VALUE val)
1376 VALUE options = e->options;
1377 ID id;
1378 #ifdef RLIM2NUM
1379 int rtype;
1380 #endif
1382 rb_secure(2);
1384 switch (TYPE(key)) {
1385 case T_SYMBOL:
1386 id = SYM2ID(key);
1387 #ifdef HAVE_SETPGID
1388 if (id == rb_intern("pgroup")) {
1389 if (!NIL_P(rb_ary_entry(options, EXEC_OPTION_PGROUP))) {
1390 rb_raise(rb_eArgError, "pgroup option specified twice");
1392 if (!RTEST(val))
1393 val = Qfalse;
1394 else if (val == Qtrue)
1395 val = INT2FIX(0);
1396 else {
1397 pid_t pgroup = NUM2PIDT(val);
1398 if (pgroup < 0) {
1399 rb_raise(rb_eArgError, "negative process group ID : %ld", (long)pgroup);
1401 val = PIDT2NUM(pgroup);
1403 rb_ary_store(options, EXEC_OPTION_PGROUP, val);
1405 else
1406 #endif
1407 #ifdef RLIM2NUM
1408 if (strncmp("rlimit_", rb_id2name(id), 7) == 0 &&
1409 (rtype = rlimit_type_by_lname(rb_id2name(id)+7)) != -1) {
1410 VALUE ary = rb_ary_entry(options, EXEC_OPTION_RLIMIT);
1411 VALUE tmp, softlim, hardlim;
1412 if (NIL_P(ary)) {
1413 ary = hide_obj(rb_ary_new());
1414 rb_ary_store(options, EXEC_OPTION_RLIMIT, ary);
1416 tmp = rb_check_array_type(val);
1417 if (!NIL_P(tmp)) {
1418 if (RARRAY_LEN(tmp) == 1)
1419 softlim = hardlim = rb_to_int(rb_ary_entry(tmp, 0));
1420 else if (RARRAY_LEN(tmp) == 2) {
1421 softlim = rb_to_int(rb_ary_entry(tmp, 0));
1422 hardlim = rb_to_int(rb_ary_entry(tmp, 1));
1424 else {
1425 rb_raise(rb_eArgError, "wrong exec rlimit option");
1428 else {
1429 softlim = hardlim = rb_to_int(val);
1431 tmp = hide_obj(rb_ary_new3(3, INT2NUM(rtype), softlim, hardlim));
1432 rb_ary_push(ary, tmp);
1434 else
1435 #endif
1436 if (id == rb_intern("unsetenv_others")) {
1437 if (!NIL_P(rb_ary_entry(options, EXEC_OPTION_UNSETENV_OTHERS))) {
1438 rb_raise(rb_eArgError, "unsetenv_others option specified twice");
1440 val = RTEST(val) ? Qtrue : Qfalse;
1441 rb_ary_store(options, EXEC_OPTION_UNSETENV_OTHERS, val);
1443 else if (id == rb_intern("chdir")) {
1444 if (!NIL_P(rb_ary_entry(options, EXEC_OPTION_CHDIR))) {
1445 rb_raise(rb_eArgError, "chdir option specified twice");
1447 FilePathValue(val);
1448 rb_ary_store(options, EXEC_OPTION_CHDIR,
1449 hide_obj(rb_str_dup(val)));
1451 else if (id == rb_intern("umask")) {
1452 mode_t cmask = NUM2LONG(val);
1453 if (!NIL_P(rb_ary_entry(options, EXEC_OPTION_UMASK))) {
1454 rb_raise(rb_eArgError, "umask option specified twice");
1456 rb_ary_store(options, EXEC_OPTION_UMASK, LONG2NUM(cmask));
1458 else if (id == rb_intern("close_others")) {
1459 if (!NIL_P(rb_ary_entry(options, EXEC_OPTION_CLOSE_OTHERS))) {
1460 rb_raise(rb_eArgError, "close_others option specified twice");
1462 val = RTEST(val) ? Qtrue : Qfalse;
1463 rb_ary_store(options, EXEC_OPTION_CLOSE_OTHERS, val);
1465 else if (id == rb_intern("in")) {
1466 key = INT2FIX(0);
1467 goto redirect;
1469 else if (id == rb_intern("out")) {
1470 key = INT2FIX(1);
1471 goto redirect;
1473 else if (id == rb_intern("err")) {
1474 key = INT2FIX(2);
1475 goto redirect;
1477 else {
1478 rb_raise(rb_eArgError, "wrong exec option symbol: %s",
1479 rb_id2name(id));
1481 break;
1483 case T_FIXNUM:
1484 case T_FILE:
1485 case T_ARRAY:
1486 redirect:
1487 check_exec_redirect(key, val, options);
1488 break;
1490 default:
1491 rb_raise(rb_eArgError, "wrong exec option");
1494 return ST_CONTINUE;
1497 static int
1498 check_exec_options_i(st_data_t st_key, st_data_t st_val, st_data_t arg)
1500 VALUE key = (VALUE)st_key;
1501 VALUE val = (VALUE)st_val;
1502 struct rb_exec_arg *e = (struct rb_exec_arg *)arg;
1503 return rb_exec_arg_addopt(e, key, val);
1506 static VALUE
1507 check_exec_fds(VALUE options)
1509 VALUE h = rb_hash_new();
1510 VALUE ary;
1511 int index, i;
1512 int maxhint = -1;
1514 for (index = EXEC_OPTION_DUP2; index <= EXEC_OPTION_OPEN; index++) {
1515 ary = rb_ary_entry(options, index);
1516 if (NIL_P(ary))
1517 continue;
1518 for (i = 0; i < RARRAY_LEN(ary); i++) {
1519 VALUE elt = RARRAY_PTR(ary)[i];
1520 int fd = FIX2INT(RARRAY_PTR(elt)[0]);
1521 if (RTEST(rb_hash_lookup(h, INT2FIX(fd)))) {
1522 rb_raise(rb_eArgError, "fd %d specified twice", fd);
1524 rb_hash_aset(h, INT2FIX(fd), Qtrue);
1525 if (maxhint < fd)
1526 maxhint = fd;
1527 if (index == EXEC_OPTION_DUP2) {
1528 fd = FIX2INT(RARRAY_PTR(elt)[1]);
1529 if (maxhint < fd)
1530 maxhint = fd;
1534 if (rb_ary_entry(options, EXEC_OPTION_CLOSE_OTHERS) != Qfalse) {
1535 rb_ary_store(options, EXEC_OPTION_CLOSE_OTHERS, INT2FIX(maxhint));
1537 return h;
1540 static void
1541 rb_check_exec_options(VALUE opthash, struct rb_exec_arg *e)
1543 if (RHASH_EMPTY_P(opthash))
1544 return;
1545 st_foreach(RHASH_TBL(opthash), check_exec_options_i, (st_data_t)e);
1548 static int
1549 check_exec_env_i(st_data_t st_key, st_data_t st_val, st_data_t arg)
1551 VALUE key = (VALUE)st_key;
1552 VALUE val = (VALUE)st_val;
1553 VALUE env = (VALUE)arg;
1554 char *k;
1556 k = StringValueCStr(key);
1557 if (strchr(k, '='))
1558 rb_raise(rb_eArgError, "environment name contains a equal : %s", k);
1560 if (!NIL_P(val))
1561 StringValueCStr(val);
1563 rb_ary_push(env, hide_obj(rb_assoc_new(key, val)));
1565 return ST_CONTINUE;
1568 static VALUE
1569 rb_check_exec_env(VALUE hash)
1571 VALUE env;
1573 env = hide_obj(rb_ary_new());
1574 st_foreach(RHASH_TBL(hash), check_exec_env_i, (st_data_t)env);
1576 return env;
1579 static VALUE
1580 rb_check_argv(int argc, VALUE *argv)
1582 VALUE tmp, prog;
1583 int i;
1584 const char *name = 0;
1586 if (argc == 0) {
1587 rb_raise(rb_eArgError, "wrong number of arguments");
1590 prog = 0;
1591 tmp = rb_check_array_type(argv[0]);
1592 if (!NIL_P(tmp)) {
1593 if (RARRAY_LEN(tmp) != 2) {
1594 rb_raise(rb_eArgError, "wrong first argument");
1596 prog = RARRAY_PTR(tmp)[0];
1597 argv[0] = RARRAY_PTR(tmp)[1];
1598 SafeStringValue(prog);
1599 StringValueCStr(prog);
1600 prog = rb_str_new4(prog);
1601 name = RSTRING_PTR(prog);
1603 for (i = 0; i < argc; i++) {
1604 SafeStringValue(argv[i]);
1605 argv[i] = rb_str_new4(argv[i]);
1606 StringValueCStr(argv[i]);
1608 security(name ? name : RSTRING_PTR(argv[0]));
1609 return prog;
1612 static VALUE
1613 rb_exec_getargs(int *argc_p, VALUE **argv_p, int accept_shell, VALUE *env_ret, VALUE *opthash_ret, struct rb_exec_arg *e)
1615 VALUE hash, prog;
1617 if (0 < *argc_p) {
1618 hash = rb_check_convert_type((*argv_p)[*argc_p-1], T_HASH, "Hash", "to_hash");
1619 if (!NIL_P(hash)) {
1620 *opthash_ret = hash;
1621 (*argc_p)--;
1625 if (0 < *argc_p) {
1626 hash = rb_check_convert_type((*argv_p)[0], T_HASH, "Hash", "to_hash");
1627 if (!NIL_P(hash)) {
1628 *env_ret = hash;
1629 (*argc_p)--;
1630 (*argv_p)++;
1633 prog = rb_check_argv(*argc_p, *argv_p);
1634 if (!prog) {
1635 prog = (*argv_p)[0];
1636 if (accept_shell && *argc_p == 1) {
1637 *argc_p = 0;
1638 *argv_p = 0;
1641 return prog;
1644 static void
1645 rb_exec_fillarg(VALUE prog, int argc, VALUE *argv, VALUE env, VALUE opthash, struct rb_exec_arg *e)
1647 VALUE options;
1648 MEMZERO(e, struct rb_exec_arg, 1);
1649 options = hide_obj(rb_ary_new());
1650 e->options = options;
1652 if (!NIL_P(opthash)) {
1653 rb_check_exec_options(opthash, e);
1655 if (!NIL_P(env)) {
1656 env = rb_check_exec_env(env);
1657 rb_ary_store(options, EXEC_OPTION_ENV, env);
1660 e->argc = argc;
1661 e->argv = argv;
1662 e->prog = prog ? RSTRING_PTR(prog) : 0;
1665 VALUE
1666 rb_exec_arg_init(int argc, VALUE *argv, int accept_shell, struct rb_exec_arg *e)
1668 VALUE prog;
1669 VALUE env = Qnil, opthash = Qnil;
1670 prog = rb_exec_getargs(&argc, &argv, accept_shell, &env, &opthash, e);
1671 rb_exec_fillarg(prog, argc, argv, env, opthash, e);
1672 return prog;
1675 void
1676 rb_exec_arg_fixup(struct rb_exec_arg *e)
1678 e->redirect_fds = check_exec_fds(e->options);
1682 * call-seq:
1683 * exec([env,] command [, arg, ...] [,options])
1685 * Replaces the current process by running the given external _command_.
1686 * If optional arguments, sequence of +arg+, are not given, that argument is
1687 * taken as a line that is subject to shell expansion before being
1688 * executed. If one or more +arg+ given, they
1689 * are passed as parameters to _command_ with no shell
1690 * expansion. If +command+ is a two-element array, the first
1691 * element is the command to be executed, and the second argument is
1692 * used as the <code>argv[0]</code> value, which may show up in process
1693 * listings. In MSDOS environments, the command is executed in a
1694 * subshell; otherwise, one of the <code>exec(2)</code> system calls is
1695 * used, so the running command may inherit some of the environment of
1696 * the original program (including open file descriptors).
1698 * The hash arguments, env and options, are same as
1699 * <code>system</code> and <code>spawn</code>.
1700 * See <code>spawn</code> for details.
1702 * Raises SystemCallError if the _command_ couldn't execute (typically
1703 * <code>Errno::ENOENT</code> when it was not found).
1705 * exec "echo *" # echoes list of files in current directory
1706 * # never get here
1709 * exec "echo", "*" # echoes an asterisk
1710 * # never get here
1713 VALUE
1714 rb_f_exec(int argc, VALUE *argv)
1716 struct rb_exec_arg earg;
1718 rb_exec_arg_init(argc, argv, Qtrue, &earg);
1719 if (NIL_P(rb_ary_entry(earg.options, EXEC_OPTION_CLOSE_OTHERS)))
1720 rb_exec_arg_addopt(&earg, ID2SYM(rb_intern("close_others")), Qfalse);
1721 rb_exec_arg_fixup(&earg);
1723 rb_exec(&earg);
1724 rb_sys_fail(earg.prog);
1725 return Qnil; /* dummy */
1728 /*#define DEBUG_REDIRECT*/
1729 #if defined(DEBUG_REDIRECT)
1731 #include <stdarg.h>
1733 static void
1734 ttyprintf(const char *fmt, ...)
1736 va_list ap;
1737 FILE *tty;
1738 int save = errno;
1739 tty = fopen("/dev/tty", "w");
1740 if (!tty)
1741 return;
1743 va_start(ap, fmt);
1744 vfprintf(tty, fmt, ap);
1745 va_end(ap);
1746 fclose(tty);
1747 errno = save;
1750 static int
1751 redirect_dup(int oldfd)
1753 int ret;
1754 ret = dup(oldfd);
1755 ttyprintf("dup(%d) => %d\n", oldfd, ret);
1756 return ret;
1759 static int
1760 redirect_dup2(int oldfd, int newfd)
1762 int ret;
1763 ret = dup2(oldfd, newfd);
1764 ttyprintf("dup2(%d, %d)\n", oldfd, newfd);
1765 return ret;
1768 static int
1769 redirect_close(int fd)
1771 int ret;
1772 ret = close(fd);
1773 ttyprintf("close(%d)\n", fd);
1774 return ret;
1777 static int
1778 redirect_open(const char *pathname, int flags, mode_t perm)
1780 int ret;
1781 ret = open(pathname, flags, perm);
1782 ttyprintf("open(\"%s\", 0x%x, 0%o) => %d\n", pathname, flags, perm, ret);
1783 return ret;
1786 #else
1787 #define redirect_dup(oldfd) dup(oldfd)
1788 #define redirect_dup2(oldfd, newfd) dup2(oldfd, newfd)
1789 #define redirect_close(fd) close(fd)
1790 #define redirect_open(pathname, flags, perm) open(pathname, flags, perm)
1791 #endif
1793 static int
1794 save_redirect_fd(int fd, VALUE save)
1796 if (!NIL_P(save)) {
1797 VALUE newary;
1798 int save_fd = redirect_dup(fd);
1799 if (save_fd == -1) return -1;
1800 newary = rb_ary_entry(save, EXEC_OPTION_DUP2);
1801 if (NIL_P(newary)) {
1802 newary = hide_obj(rb_ary_new());
1803 rb_ary_store(save, EXEC_OPTION_DUP2, newary);
1805 rb_ary_push(newary,
1806 hide_obj(rb_assoc_new(INT2FIX(fd), INT2FIX(save_fd))));
1808 newary = rb_ary_entry(save, EXEC_OPTION_CLOSE);
1809 if (NIL_P(newary)) {
1810 newary = hide_obj(rb_ary_new());
1811 rb_ary_store(save, EXEC_OPTION_CLOSE, newary);
1813 rb_ary_push(newary, hide_obj(rb_assoc_new(INT2FIX(save_fd), Qnil)));
1816 return 0;
1819 static VALUE
1820 save_env_i(VALUE i, VALUE ary, int argc, VALUE *argv)
1822 rb_ary_push(ary, hide_obj(rb_ary_dup(argv[0])));
1823 return Qnil;
1826 static void
1827 save_env(VALUE save)
1829 if (!NIL_P(save) && NIL_P(rb_ary_entry(save, EXEC_OPTION_ENV))) {
1830 VALUE env = rb_const_get(rb_cObject, rb_intern("ENV"));
1831 if (RTEST(env)) {
1832 VALUE ary = hide_obj(rb_ary_new());
1833 rb_block_call(env, rb_intern("each"), 0, 0, save_env_i,
1834 (VALUE)ary);
1835 rb_ary_store(save, EXEC_OPTION_ENV, ary);
1837 rb_ary_store(save, EXEC_OPTION_UNSETENV_OTHERS, Qtrue);
1841 static int
1842 intcmp(const void *a, const void *b)
1844 return *(int*)a - *(int*)b;
1847 static int
1848 run_exec_dup2(VALUE ary, VALUE save)
1850 int n, i;
1851 int ret;
1852 int extra_fd = -1;
1853 struct fd_pair {
1854 int oldfd;
1855 int newfd;
1856 int older_index;
1857 int num_newer;
1858 } *pairs = 0;
1860 n = RARRAY_LEN(ary);
1861 pairs = ALLOC_N(struct fd_pair, n);
1863 /* initialize oldfd and newfd: O(n) */
1864 for (i = 0; i < n; i++) {
1865 VALUE elt = RARRAY_PTR(ary)[i];
1866 pairs[i].oldfd = FIX2INT(RARRAY_PTR(elt)[1]);
1867 pairs[i].newfd = FIX2INT(RARRAY_PTR(elt)[0]); /* unique */
1868 pairs[i].older_index = -1;
1871 /* sort the table by oldfd: O(n log n) */
1872 qsort(pairs, n, sizeof(struct fd_pair), intcmp);
1874 /* initialize older_index and num_newer: O(n log n) */
1875 for (i = 0; i < n; i++) {
1876 int newfd = pairs[i].newfd;
1877 struct fd_pair key, *found;
1878 key.oldfd = newfd;
1879 found = bsearch(&key, pairs, n, sizeof(struct fd_pair), intcmp);
1880 pairs[i].num_newer = 0;
1881 if (found) {
1882 while (pairs < found && (found-1)->oldfd == newfd)
1883 found--;
1884 while (found < pairs+n && found->oldfd == newfd) {
1885 pairs[i].num_newer++;
1886 found->older_index = i;
1887 found++;
1892 /* non-cyclic redirection: O(n) */
1893 for (i = 0; i < n; i++) {
1894 int j = i;
1895 while (j != -1 && pairs[j].oldfd != -1 && pairs[j].num_newer == 0) {
1896 if (save_redirect_fd(pairs[j].newfd, save) < 0)
1897 return -1;
1898 ret = redirect_dup2(pairs[j].oldfd, pairs[j].newfd);
1899 if (ret == -1)
1900 goto fail;
1901 pairs[j].oldfd = -1;
1902 j = pairs[j].older_index;
1903 if (j != -1)
1904 pairs[j].num_newer--;
1908 /* cyclic redirection: O(n) */
1909 for (i = 0; i < n; i++) {
1910 int j;
1911 if (pairs[i].oldfd == -1)
1912 continue;
1913 if (pairs[i].oldfd == pairs[i].newfd) { /* self cycle */
1914 #ifdef F_GETFD
1915 int fd = pairs[i].oldfd;
1916 ret = fcntl(fd, F_GETFD);
1917 if (ret == -1)
1918 goto fail;
1919 if (ret & FD_CLOEXEC) {
1920 ret &= ~FD_CLOEXEC;
1921 ret = fcntl(fd, F_SETFD, ret);
1922 if (ret == -1)
1923 goto fail;
1925 #endif
1926 pairs[i].oldfd = -1;
1927 continue;
1929 if (extra_fd == -1) {
1930 extra_fd = redirect_dup(pairs[i].oldfd);
1931 if (extra_fd == -1)
1932 goto fail;
1934 else {
1935 ret = redirect_dup2(pairs[i].oldfd, extra_fd);
1936 if (ret == -1)
1937 goto fail;
1939 pairs[i].oldfd = extra_fd;
1940 j = pairs[i].older_index;
1941 pairs[i].older_index = -1;
1942 while (j != -1) {
1943 ret = redirect_dup2(pairs[j].oldfd, pairs[j].newfd);
1944 if (ret == -1)
1945 goto fail;
1946 pairs[j].oldfd = -1;
1947 j = pairs[j].older_index;
1950 if (extra_fd != -1) {
1951 ret = redirect_close(extra_fd);
1952 if (ret == -1)
1953 goto fail;
1956 xfree(pairs);
1957 return 0;
1959 fail:
1960 xfree(pairs);
1961 return -1;
1964 static int
1965 run_exec_close(VALUE ary)
1967 int i, ret;
1969 for (i = 0; i < RARRAY_LEN(ary); i++) {
1970 VALUE elt = RARRAY_PTR(ary)[i];
1971 int fd = FIX2INT(RARRAY_PTR(elt)[0]);
1972 ret = redirect_close(fd);
1973 if (ret == -1)
1974 return -1;
1976 return 0;
1979 static int
1980 run_exec_open(VALUE ary, VALUE save)
1982 int i, ret;
1984 for (i = 0; i < RARRAY_LEN(ary);) {
1985 VALUE elt = RARRAY_PTR(ary)[i];
1986 int fd = FIX2INT(RARRAY_PTR(elt)[0]);
1987 VALUE param = RARRAY_PTR(elt)[1];
1988 char *path = RSTRING_PTR(RARRAY_PTR(param)[0]);
1989 int flags = NUM2INT(RARRAY_PTR(param)[1]);
1990 int perm = NUM2INT(RARRAY_PTR(param)[2]);
1991 int need_close = 1;
1992 int fd2 = redirect_open(path, flags, perm);
1993 if (fd2 == -1) return -1;
1994 while (i < RARRAY_LEN(ary) &&
1995 (elt = RARRAY_PTR(ary)[i], RARRAY_PTR(elt)[1] == param)) {
1996 fd = FIX2INT(RARRAY_PTR(elt)[0]);
1997 if (fd == fd2) {
1998 need_close = 0;
2000 else {
2001 if (save_redirect_fd(fd, save) < 0)
2002 return -1;
2003 ret = redirect_dup2(fd2, fd);
2004 if (ret == -1) return -1;
2006 i++;
2008 if (need_close) {
2009 ret = redirect_close(fd2);
2010 if (ret == -1) return -1;
2013 return 0;
2016 #ifdef HAVE_SETPGID
2017 static int
2018 run_exec_pgroup(VALUE obj, VALUE save)
2021 * If FD_CLOEXEC is available, rb_fork waits the child's execve.
2022 * So setpgid is done in the child when rb_fork is returned in the parent.
2023 * No race condition, even without setpgid from the parent.
2024 * (Is there an environment which has setpgid but FD_CLOEXEC?)
2026 pid_t pgroup;
2027 if (!NIL_P(save)) {
2028 /* maybe meaningless with no fork environment... */
2029 rb_ary_store(save, EXEC_OPTION_PGROUP, PIDT2NUM(getpgrp()));
2031 pgroup = NUM2PIDT(obj);
2032 if (pgroup == 0) {
2033 pgroup = getpid();
2035 return setpgid(getpid(), pgroup);
2037 #endif
2039 #ifdef RLIM2NUM
2040 static int
2041 run_exec_rlimit(VALUE ary, VALUE save)
2043 int i;
2044 for (i = 0; i < RARRAY_LEN(ary); i++) {
2045 VALUE elt = RARRAY_PTR(ary)[i];
2046 int rtype = NUM2INT(RARRAY_PTR(elt)[0]);
2047 struct rlimit rlim;
2048 if (!NIL_P(save)) {
2049 VALUE tmp, newary;
2050 if (getrlimit(rtype, &rlim) == -1)
2051 return -1;
2052 tmp = hide_obj(rb_ary_new3(3, RARRAY_PTR(elt)[0],
2053 RLIM2NUM(rlim.rlim_cur),
2054 RLIM2NUM(rlim.rlim_max)));
2055 newary = rb_ary_entry(save, EXEC_OPTION_RLIMIT);
2056 if (NIL_P(newary)) {
2057 newary = hide_obj(rb_ary_new());
2058 rb_ary_store(save, EXEC_OPTION_RLIMIT, newary);
2060 rb_ary_push(newary, tmp);
2062 rlim.rlim_cur = NUM2RLIM(RARRAY_PTR(elt)[1]);
2063 rlim.rlim_max = NUM2RLIM(RARRAY_PTR(elt)[2]);
2064 if (setrlimit(rtype, &rlim) == -1)
2065 return -1;
2067 return 0;
2069 #endif
2072 rb_run_exec_options(const struct rb_exec_arg *e, struct rb_exec_arg *s)
2074 VALUE options = e->options;
2075 VALUE soptions = Qnil;
2076 VALUE obj;
2078 if (!RTEST(options))
2079 return 0;
2081 if (s) {
2082 s->argc = 0;
2083 s->argv = NULL;
2084 s->prog = NULL;
2085 s->options = soptions = hide_obj(rb_ary_new());
2086 s->redirect_fds = Qnil;
2089 #ifdef HAVE_SETPGID
2090 obj = rb_ary_entry(options, EXEC_OPTION_PGROUP);
2091 if (RTEST(obj)) {
2092 if (run_exec_pgroup(obj, soptions) == -1)
2093 return -1;
2095 #endif
2097 #ifdef RLIM2NUM
2098 obj = rb_ary_entry(options, EXEC_OPTION_RLIMIT);
2099 if (!NIL_P(obj)) {
2100 if (run_exec_rlimit(obj, soptions) == -1)
2101 return -1;
2103 #endif
2105 obj = rb_ary_entry(options, EXEC_OPTION_UNSETENV_OTHERS);
2106 if (RTEST(obj)) {
2107 save_env(soptions);
2108 rb_env_clear();
2111 obj = rb_ary_entry(options, EXEC_OPTION_ENV);
2112 if (!NIL_P(obj)) {
2113 int i;
2114 save_env(soptions);
2115 for (i = 0; i < RARRAY_LEN(obj); i++) {
2116 VALUE pair = RARRAY_PTR(obj)[i];
2117 VALUE key = RARRAY_PTR(pair)[0];
2118 VALUE val = RARRAY_PTR(pair)[1];
2119 if (NIL_P(val))
2120 ruby_setenv(StringValueCStr(key), 0);
2121 else
2122 ruby_setenv(StringValueCStr(key), StringValueCStr(val));
2126 obj = rb_ary_entry(options, EXEC_OPTION_CHDIR);
2127 if (!NIL_P(obj)) {
2128 if (!NIL_P(soptions)) {
2129 char *cwd = my_getcwd();
2130 rb_ary_store(soptions, EXEC_OPTION_CHDIR,
2131 hide_obj(rb_str_new2(cwd)));
2133 if (chdir(RSTRING_PTR(obj)) == -1)
2134 return -1;
2137 obj = rb_ary_entry(options, EXEC_OPTION_UMASK);
2138 if (!NIL_P(obj)) {
2139 mode_t mask = NUM2LONG(obj);
2140 mode_t oldmask = umask(mask); /* never fail */
2141 if (!NIL_P(soptions))
2142 rb_ary_store(soptions, EXEC_OPTION_UMASK, LONG2NUM(oldmask));
2145 obj = rb_ary_entry(options, EXEC_OPTION_DUP2);
2146 if (!NIL_P(obj)) {
2147 if (run_exec_dup2(obj, soptions) == -1)
2148 return -1;
2151 obj = rb_ary_entry(options, EXEC_OPTION_CLOSE);
2152 if (!NIL_P(obj)) {
2153 if (!NIL_P(soptions))
2154 rb_warn("cannot close fd before spawn");
2155 else {
2156 if (run_exec_close(obj) == -1)
2157 return -1;
2161 #ifdef HAVE_FORK
2162 obj = rb_ary_entry(options, EXEC_OPTION_CLOSE_OTHERS);
2163 if (obj != Qfalse) {
2164 rb_close_before_exec(3, FIX2LONG(obj), e->redirect_fds);
2166 #endif
2168 obj = rb_ary_entry(options, EXEC_OPTION_OPEN);
2169 if (!NIL_P(obj)) {
2170 if (run_exec_open(obj, soptions) == -1)
2171 return -1;
2174 return 0;
2178 rb_exec(const struct rb_exec_arg *e)
2180 int argc = e->argc;
2181 VALUE *argv = e->argv;
2182 const char *prog = e->prog;
2184 if (rb_run_exec_options(e, NULL) < 0) {
2185 return -1;
2188 if (argc == 0) {
2189 rb_proc_exec(prog);
2191 else {
2192 rb_proc_exec_n(argc, argv, prog);
2194 #ifndef FD_CLOEXEC
2195 preserving_errno({
2196 fprintf(stderr, "%s:%d: command not found: %s\n",
2197 rb_sourcefile(), rb_sourceline(), prog);
2199 #endif
2200 return -1;
2203 #ifdef HAVE_FORK
2204 static int
2205 rb_exec_atfork(void* arg)
2207 rb_thread_atfork_before_exec();
2208 return rb_exec(arg);
2210 #endif
2212 #ifdef HAVE_FORK
2213 #ifdef FD_CLOEXEC
2214 #if SIZEOF_INT == SIZEOF_LONG
2215 #define proc_syswait (VALUE (*)(VALUE))rb_syswait
2216 #else
2217 static VALUE
2218 proc_syswait(VALUE pid)
2220 rb_syswait((int)pid);
2221 return Qnil;
2223 #endif
2224 #endif
2226 static int
2227 move_fds_to_avoid_crash(int *fdp, int n, VALUE fds)
2229 long min = 0;
2230 int i;
2231 for (i = 0; i < n; i++) {
2232 int ret;
2233 while (RTEST(rb_hash_lookup(fds, INT2FIX(fdp[i])))) {
2234 if (min <= fdp[i])
2235 min = fdp[i]+1;
2236 while (RTEST(rb_hash_lookup(fds, INT2FIX(min))))
2237 min++;
2238 ret = fcntl(fdp[i], F_DUPFD, min);
2239 if (ret == -1)
2240 return -1;
2241 close(fdp[i]);
2242 fdp[i] = ret;
2245 return 0;
2248 static int
2249 pipe_nocrash(int filedes[2], VALUE fds)
2251 int ret;
2252 ret = rb_pipe(filedes);
2253 if (ret == -1)
2254 return -1;
2255 if (RTEST(fds)) {
2256 int save = errno;
2257 if (move_fds_to_avoid_crash(filedes, 2, fds) == -1) {
2258 close(filedes[0]);
2259 close(filedes[1]);
2260 return -1;
2262 errno = save;
2264 return ret;
2268 * Forks child process, and returns the process ID in the parent
2269 * process.
2271 * If +status+ is given, protects from any exceptions and sets the
2272 * jump status to it.
2274 * In the child process, just returns 0 if +chfunc+ is +NULL+.
2275 * Otherwise +chfunc+ will be called with +charg+, and then the child
2276 * process exits with +EXIT_SUCCESS+ when it returned zero.
2278 * In the case of the function is called and returns non-zero value,
2279 * the child process exits with non-+EXIT_SUCCESS+ value (normally
2280 * 127). And, on the platforms where +FD_CLOEXEC+ is available,
2281 * +errno+ is propagated to the parent process, and this function
2282 * returns -1 in the parent process. On the other platforms, just
2283 * returns pid.
2285 * If fds is not Qnil, internal pipe for the errno propagation is
2286 * arranged to avoid conflicts of the hash keys in +fds+.
2288 * +chfunc+ must not raise any exceptions.
2290 rb_pid_t
2291 rb_fork(int *status, int (*chfunc)(void*), void *charg, VALUE fds)
2293 rb_pid_t pid;
2294 int err, state = 0;
2295 #ifdef FD_CLOEXEC
2296 int ep[2];
2297 #endif
2299 #ifndef __VMS
2300 #define prefork() ( \
2301 rb_io_flush(rb_stdout), \
2302 rb_io_flush(rb_stderr) \
2304 #else
2305 #define prefork() ((void)0)
2306 #endif
2308 prefork();
2310 #ifdef FD_CLOEXEC
2311 if (chfunc) {
2312 if (pipe_nocrash(ep, fds)) return -1;
2313 if (fcntl(ep[1], F_SETFD, FD_CLOEXEC)) {
2314 preserving_errno((close(ep[0]), close(ep[1])));
2315 return -1;
2318 #endif
2319 for (; (pid = fork()) < 0; prefork()) {
2320 switch (errno) {
2321 case EAGAIN:
2322 #if defined(EWOULDBLOCK) && EWOULDBLOCK != EAGAIN
2323 case EWOULDBLOCK:
2324 #endif
2325 if (!status && !chfunc) {
2326 rb_thread_sleep(1);
2327 continue;
2329 else {
2330 rb_protect((VALUE (*)())rb_thread_sleep, 1, &state);
2331 if (status) *status = state;
2332 if (!state) continue;
2334 default:
2335 #ifdef FD_CLOEXEC
2336 if (chfunc) {
2337 preserving_errno((close(ep[0]), close(ep[1])));
2339 #endif
2340 if (state && !status) rb_jump_tag(state);
2341 return -1;
2344 if (!pid) {
2345 rb_thread_reset_timer_thread();
2346 if (chfunc) {
2347 #ifdef FD_CLOEXEC
2348 close(ep[0]);
2349 #endif
2350 if (!(*chfunc)(charg)) _exit(EXIT_SUCCESS);
2351 #ifdef FD_CLOEXEC
2352 err = errno;
2353 write(ep[1], &err, sizeof(err));
2354 #endif
2355 #if EXIT_SUCCESS == 127
2356 _exit(EXIT_FAILURE);
2357 #else
2358 _exit(127);
2359 #endif
2361 rb_thread_start_timer_thread();
2363 #ifdef FD_CLOEXEC
2364 else if (chfunc) {
2365 close(ep[1]);
2366 if ((state = read(ep[0], &err, sizeof(err))) < 0) {
2367 err = errno;
2369 close(ep[0]);
2370 if (state) {
2371 if (status) {
2372 rb_protect(proc_syswait, (VALUE)pid, status);
2374 else {
2375 rb_syswait(pid);
2377 errno = err;
2378 return -1;
2381 #endif
2382 return pid;
2384 #endif
2387 * call-seq:
2388 * Kernel.fork [{ block }] => fixnum or nil
2389 * Process.fork [{ block }] => fixnum or nil
2391 * Creates a subprocess. If a block is specified, that block is run
2392 * in the subprocess, and the subprocess terminates with a status of
2393 * zero. Otherwise, the +fork+ call returns twice, once in
2394 * the parent, returning the process ID of the child, and once in
2395 * the child, returning _nil_. The child process can exit using
2396 * <code>Kernel.exit!</code> to avoid running any
2397 * <code>at_exit</code> functions. The parent process should
2398 * use <code>Process.wait</code> to collect the termination statuses
2399 * of its children or use <code>Process.detach</code> to register
2400 * disinterest in their status; otherwise, the operating system
2401 * may accumulate zombie processes.
2403 * The thread calling fork is the only thread in the created child process.
2404 * fork doesn't copy other threads.
2407 static VALUE
2408 rb_f_fork(VALUE obj)
2410 #if defined(HAVE_FORK) && !defined(CANNOT_FORK_WITH_PTHREAD)
2411 rb_pid_t pid;
2413 rb_secure(2);
2415 switch (pid = rb_fork(0, 0, 0, Qnil)) {
2416 case 0:
2417 #ifdef linux
2418 after_exec();
2419 #endif
2420 rb_thread_atfork();
2421 if (rb_block_given_p()) {
2422 int status;
2424 rb_protect(rb_yield, Qundef, &status);
2425 ruby_stop(status);
2427 return Qnil;
2429 case -1:
2430 rb_sys_fail("fork(2)");
2431 return Qnil;
2433 default:
2434 return PIDT2NUM(pid);
2436 #else
2437 rb_notimplement();
2438 #endif
2443 * call-seq:
2444 * Process.exit!(fixnum=-1)
2446 * Exits the process immediately. No exit handlers are
2447 * run. <em>fixnum</em> is returned to the underlying system as the
2448 * exit status.
2450 * Process.exit!(0)
2453 static VALUE
2454 rb_f_exit_bang(int argc, VALUE *argv, VALUE obj)
2456 VALUE status;
2457 int istatus;
2459 rb_secure(4);
2460 if (argc > 0 && rb_scan_args(argc, argv, "01", &status) == 1) {
2461 switch (status) {
2462 case Qtrue:
2463 istatus = EXIT_SUCCESS;
2464 break;
2465 case Qfalse:
2466 istatus = EXIT_FAILURE;
2467 break;
2468 default:
2469 istatus = NUM2INT(status);
2470 break;
2473 else {
2474 istatus = EXIT_FAILURE;
2476 _exit(istatus);
2478 return Qnil; /* not reached */
2481 void
2482 rb_exit(int status)
2484 if (GET_THREAD()->tag) {
2485 VALUE args[2];
2487 args[0] = INT2NUM(status);
2488 args[1] = rb_str_new2("exit");
2489 rb_exc_raise(rb_class_new_instance(2, args, rb_eSystemExit));
2491 ruby_finalize();
2492 exit(status);
2497 * call-seq:
2498 * exit(integer=0)
2499 * Kernel::exit(integer=0)
2500 * Process::exit(integer=0)
2502 * Initiates the termination of the Ruby script by raising the
2503 * <code>SystemExit</code> exception. This exception may be caught. The
2504 * optional parameter is used to return a status code to the invoking
2505 * environment.
2507 * begin
2508 * exit
2509 * puts "never get here"
2510 * rescue SystemExit
2511 * puts "rescued a SystemExit exception"
2512 * end
2513 * puts "after begin block"
2515 * <em>produces:</em>
2517 * rescued a SystemExit exception
2518 * after begin block
2520 * Just prior to termination, Ruby executes any <code>at_exit</code> functions
2521 * (see Kernel::at_exit) and runs any object finalizers (see
2522 * ObjectSpace::define_finalizer).
2524 * at_exit { puts "at_exit function" }
2525 * ObjectSpace.define_finalizer("string", proc { puts "in finalizer" })
2526 * exit
2528 * <em>produces:</em>
2530 * at_exit function
2531 * in finalizer
2534 VALUE
2535 rb_f_exit(int argc, VALUE *argv)
2537 VALUE status;
2538 int istatus;
2540 rb_secure(4);
2541 if (argc > 0 && rb_scan_args(argc, argv, "01", &status) == 1) {
2542 switch (status) {
2543 case Qtrue:
2544 istatus = EXIT_SUCCESS;
2545 break;
2546 case Qfalse:
2547 istatus = EXIT_FAILURE;
2548 break;
2549 default:
2550 istatus = NUM2INT(status);
2551 #if EXIT_SUCCESS != 0
2552 if (istatus == 0)
2553 istatus = EXIT_SUCCESS;
2554 #endif
2555 break;
2558 else {
2559 istatus = EXIT_SUCCESS;
2561 rb_exit(istatus);
2562 return Qnil; /* not reached */
2567 * call-seq:
2568 * abort
2569 * Kernel::abort
2570 * Process::abort
2572 * Terminate execution immediately, effectively by calling
2573 * <code>Kernel.exit(1)</code>. If _msg_ is given, it is written
2574 * to STDERR prior to terminating.
2577 VALUE
2578 rb_f_abort(int argc, VALUE *argv)
2580 extern void ruby_error_print(void);
2582 rb_secure(4);
2583 if (argc == 0) {
2584 if (!NIL_P(GET_THREAD()->errinfo)) {
2585 ruby_error_print();
2587 rb_exit(EXIT_FAILURE);
2589 else {
2590 VALUE args[2];
2592 rb_scan_args(argc, argv, "1", &args[1]);
2593 StringValue(argv[0]);
2594 rb_io_puts(argc, argv, rb_stderr);
2595 args[0] = INT2NUM(EXIT_FAILURE);
2596 rb_exc_raise(rb_class_new_instance(2, args, rb_eSystemExit));
2598 return Qnil; /* not reached */
2602 #if defined(sun)
2603 #define signal(a,b) sigset(a,b)
2604 #else
2605 # if defined(POSIX_SIGNAL)
2606 # define signal(a,b) posix_signal(a,b)
2607 # endif
2608 #endif
2610 void
2611 rb_syswait(rb_pid_t pid)
2613 static int overriding;
2614 #ifdef SIGHUP
2615 RETSIGTYPE (*hfunc)(int) = 0;
2616 #endif
2617 #ifdef SIGQUIT
2618 RETSIGTYPE (*qfunc)(int) = 0;
2619 #endif
2620 RETSIGTYPE (*ifunc)(int) = 0;
2621 int status;
2622 int i, hooked = Qfalse;
2624 if (!overriding) {
2625 #ifdef SIGHUP
2626 hfunc = signal(SIGHUP, SIG_IGN);
2627 #endif
2628 #ifdef SIGQUIT
2629 qfunc = signal(SIGQUIT, SIG_IGN);
2630 #endif
2631 ifunc = signal(SIGINT, SIG_IGN);
2632 overriding = Qtrue;
2633 hooked = Qtrue;
2636 do {
2637 i = rb_waitpid(pid, &status, 0);
2638 } while (i == -1 && errno == EINTR);
2640 if (hooked) {
2641 #ifdef SIGHUP
2642 signal(SIGHUP, hfunc);
2643 #endif
2644 #ifdef SIGQUIT
2645 signal(SIGQUIT, qfunc);
2646 #endif
2647 signal(SIGINT, ifunc);
2648 overriding = Qfalse;
2652 static rb_pid_t
2653 rb_spawn_internal(int argc, VALUE *argv, int default_close_others)
2655 rb_pid_t status;
2656 VALUE prog;
2657 struct rb_exec_arg earg;
2658 #if !defined HAVE_FORK
2659 struct rb_exec_arg sarg;
2660 #endif
2662 prog = rb_exec_arg_init(argc, argv, Qtrue, &earg);
2663 if (NIL_P(rb_ary_entry(earg.options, EXEC_OPTION_CLOSE_OTHERS))) {
2664 VALUE v = default_close_others ? Qtrue : Qfalse;
2665 rb_exec_arg_addopt(&earg, ID2SYM(rb_intern("close_others")), v);
2667 rb_exec_arg_fixup(&earg);
2669 #if defined HAVE_FORK
2670 status = rb_fork(&status, rb_exec_atfork, &earg, earg.redirect_fds);
2671 if (prog && earg.argc) earg.argv[0] = prog;
2672 #else
2673 if (rb_run_exec_options(&earg, &sarg) < 0) {
2674 return -1;
2677 argc = earg.argc;
2678 argv = earg.argv;
2679 if (prog && argc) argv[0] = prog;
2680 # if defined HAVE_SPAWNV
2681 if (!argc) {
2682 status = proc_spawn(RSTRING_PTR(prog));
2684 else {
2685 status = proc_spawn_n(argc, argv, prog);
2687 # if defined(_WIN32)
2688 if (status == -1)
2689 rb_last_status_set(0x7f << 8, 0);
2690 # endif
2691 # else
2692 if (argc) prog = rb_ary_join(rb_ary_new4(argc, argv), rb_str_new2(" "));
2693 status = system(StringValuePtr(prog));
2694 # if defined(__human68k__) || defined(__DJGPP__)
2695 rb_last_status_set(status == -1 ? 127 : status, 0);
2696 # else
2697 rb_last_status_set((status & 0xff) << 8, 0);
2698 # endif
2699 # endif
2701 rb_run_exec_options(&sarg, NULL);
2702 #endif
2703 return status;
2706 rb_pid_t
2707 rb_spawn(int argc, VALUE *argv)
2709 return rb_spawn_internal(argc, argv, Qtrue);
2713 * call-seq:
2714 * system([env,] cmd [, arg, ...] [,options]) => true, false or nil
2716 * Executes _cmd_ in a subshell, returning +true+ if the command
2717 * gives zero exit status, +false+ for non zero exit status. Returns
2718 * +nil+ if command execution fails. An error status is available in
2719 * <code>$?</code>. The arguments are processed in the same way as
2720 * for <code>Kernel::exec</code>.
2722 * The hash arguments, env and options, are same as
2723 * <code>exec</code> and <code>spawn</code>.
2724 * See <code>spawn</code> for details.
2726 * system("echo *")
2727 * system("echo", "*")
2729 * <em>produces:</em>
2731 * config.h main.rb
2735 static VALUE
2736 rb_f_system(int argc, VALUE *argv)
2738 int status;
2740 #if defined(SIGCLD) && !defined(SIGCHLD)
2741 # define SIGCHLD SIGCLD
2742 #endif
2744 #ifdef SIGCHLD
2745 RETSIGTYPE (*chfunc)(int);
2747 chfunc = signal(SIGCHLD, SIG_DFL);
2748 #endif
2749 status = rb_spawn_internal(argc, argv, Qfalse);
2750 #if defined(HAVE_FORK) || defined(HAVE_SPAWNV)
2751 if (status > 0) {
2752 rb_syswait(status);
2754 #endif
2755 #ifdef SIGCHLD
2756 signal(SIGCHLD, chfunc);
2757 #endif
2758 if (status < 0) {
2759 return Qnil;
2761 status = PST2INT(rb_last_status_get());
2762 if (status == EXIT_SUCCESS) return Qtrue;
2763 return Qfalse;
2767 * call-seq:
2768 * spawn([env,] cmd [, arg, ...] [,options]) => pid
2770 * Similar to <code>Kernel::system</code> except for not waiting for
2771 * end of _cmd_, but returns its <i>pid</i>.
2773 * If a hash is given as +env+, the environment is
2774 * updated by +env+ before <code>exec(2)</code> in the child process.
2775 * If a pair in +env+ has nil as the value, the variable is deleted.
2777 * # set FOO as BAR and unset BAZ.
2778 * pid = spawn({"FOO"=>"BAR", "BAZ"=>nil}, command)
2780 * If a hash is given as +options+,
2781 * it specifies
2782 * process group,
2783 * resource limit,
2784 * current directory,
2785 * umask and
2786 * redirects for the child process.
2787 * Also, it can be specified to clear environment variables.
2789 * The <code>:unsetenv_others</code> key in +options+ specifies
2790 * to clear environment variables, other than specified by +env+.
2792 * pid = spawn(command, :unsetenv_others=>true) # no environment variable
2793 * pid = spawn({"FOO"=>"BAR"}, command, :unsetenv_others=>true) # FOO only
2795 * The <code>:pgroup</code> key in +options+ specifies a process group.
2796 * The corresponding value should be true, zero or positive integer.
2797 * true and zero means the process should be a process leader.
2798 * Other values specifies a process group to be belongs.
2800 * pid = spawn(command, :pgroup=>true) # process leader
2801 * pid = spawn(command, :pgroup=>10) # belongs to the process group 10
2803 * The <code>:rlimit_</code><em>foo</em> key specifies a resource limit.
2804 * <em>foo</em> should be one of resource types such as <code>core</code>
2805 * The corresponding value should be an integer or an array which have one or
2806 * two integers: same as cur_limit and max_limit arguments for
2807 * Process.setrlimit.
2809 * pid = spawn(command, :rlimit_core=>0) # never dump core.
2810 * cur, max = Process.getrlimit(:CORE)
2811 * pid = spawn(command, :rlimit_core=>[0,max]) # disable core temporary.
2812 * pid = spawn(command, :rlimit_core=>max) # enable core dump
2814 * The <code>:chdir</code> key in +options+ specifies the current directory.
2816 * pid = spawn(command, :chdir=>"/var/tmp")
2818 * The <code>:umask</code> key in +options+ specifies the umask.
2820 * pid = spawn(command, :umask=>077)
2822 * The :in, :out, :err, a fixnum, an IO and an array key specifies a redirect.
2823 * The redirection maps a file descriptor in the child process.
2825 * For example, stderr can be merged into stdout:
2827 * pid = spawn(command, :err=>:out)
2828 * pid = spawn(command, STDERR=>STDOUT)
2829 * pid = spawn(command, 2=>1)
2831 * The hash keys specifies a file descriptor
2832 * in the child process started by <code>spawn</code>.
2833 * :err, STDERR and 2 specifies the standard error stream.
2835 * The hash values specifies a file descriptor
2836 * in the parent process which invokes <code>spawn</code>.
2837 * :out, STDOUT and 1 specifies the standard output stream.
2839 * The standard output in the child process is not specified.
2840 * So it is inherited from the parent process.
2842 * The standard input stream can be specifed by :in, STDIN and 0.
2844 * A filename can be specified as a hash value.
2846 * pid = spawn(command, STDIN=>"/dev/null") # read mode
2847 * pid = spawn(command, STDOUT=>"/dev/null") # write mode
2848 * pid = spawn(command, STDERR=>"log") # write mode
2849 * pid = spawn(command, 3=>"/dev/null") # read mode
2851 * For standard output and standard error,
2852 * it is opened in write mode.
2853 * Otherwise read mode is used.
2855 * For specifying flags and permission of file creation explicitly,
2856 * an array is used instead.
2858 * pid = spawn(command, STDIN=>["file"]) # read mode is assumed
2859 * pid = spawn(command, STDIN=>["file", "r"])
2860 * pid = spawn(command, STDOUT=>["log", "w"]) # 0644 assumed
2861 * pid = spawn(command, STDOUT=>["log", "w", 0600])
2862 * pid = spawn(command, STDOUT=>["log", File::WRONLY|File::EXCL|File::CREAT, 0600])
2864 * The array specifies a filename, flags and permission.
2865 * The flags can be a string or an integer.
2866 * If the flags is ommitted or nil, File::RDONLY is assumed.
2867 * The permission should be an integer.
2868 * If the permission is ommitted or nil, 0644 is assumed.
2870 * If an array of IOs and integers are specified as a hash key,
2871 * all the elemetns are redirected.
2873 * # standard output and standard error is redirected to log file.
2874 * pid = spawn(command, [STDOUT, STDERR]=>["log", "w"])
2876 * spawn closes all non-standard unspecified descriptors by default.
2877 * The "standard" descriptors are 0, 1 and 2.
2878 * This behavior is specified by :close_others option.
2879 * :close_others doesn't affect the standard descriptors which are
2880 * closed only if :close is specified explicitly.
2882 * pid = spawn(command, :close_others=>true) # close 3,4,5,... (default)
2883 * pid = spawn(command, :close_others=>false) # don't close 3,4,5,...
2885 * :close_others is true by default for spawn and IO.popen.
2887 * So IO.pipe and spawn can be used as IO.popen.
2889 * # similar to r = IO.popen(command)
2890 * r, w = IO.pipe
2891 * pid = spawn(command, STDOUT=>w) # r, w is closed in the child process.
2892 * w.close
2894 * :close is specified as a hash value to close a fd individualy.
2896 * f = open(foo)
2897 * system(command, f=>:close) # don't inherit f.
2899 * It is also possible to exchange file descriptors.
2901 * pid = spawn(command, STDOUT=>STDERR, STDERR=>STDOUT)
2903 * The hash keys specify file descriptors in the child process.
2904 * The hash values specifies file descriptors in the parent process.
2905 * So the above specifies exchanging STDOUT and STDERR.
2906 * Internally, +spawn+ uses an extra file descriptor to resolve such cyclic
2907 * file descriptor mapping.
2911 static VALUE
2912 rb_f_spawn(int argc, VALUE *argv)
2914 rb_pid_t pid;
2916 pid = rb_spawn(argc, argv);
2917 if (pid == -1) rb_sys_fail(RSTRING_PTR(argv[0]));
2918 #if defined(HAVE_FORK) || defined(HAVE_SPAWNV)
2919 return PIDT2NUM(pid);
2920 #else
2921 return Qnil;
2922 #endif
2926 * call-seq:
2927 * sleep([duration]) => fixnum
2929 * Suspends the current thread for _duration_ seconds (which may be any number,
2930 * including a +Float+ with fractional seconds). Returns the actual number of
2931 * seconds slept (rounded), which may be less than that asked for if another
2932 * thread calls <code>Thread#run</code>. Zero arguments causes +sleep+ to sleep
2933 * forever.
2935 * Time.new #=> 2008-03-08 19:56:19 +0900
2936 * sleep 1.2 #=> 1
2937 * Time.new #=> 2008-03-08 19:56:20 +0900
2938 * sleep 1.9 #=> 2
2939 * Time.new #=> 2008-03-08 19:56:22 +0900
2942 static VALUE
2943 rb_f_sleep(int argc, VALUE *argv)
2945 int beg, end;
2947 beg = time(0);
2948 if (argc == 0) {
2949 rb_thread_sleep_forever();
2951 else if (argc == 1) {
2952 rb_thread_wait_for(rb_time_interval(argv[0]));
2954 else {
2955 rb_raise(rb_eArgError, "wrong number of arguments");
2958 end = time(0) - beg;
2960 return INT2FIX(end);
2965 * call-seq:
2966 * Process.getpgrp => integer
2968 * Returns the process group ID for this process. Not available on
2969 * all platforms.
2971 * Process.getpgid(0) #=> 25527
2972 * Process.getpgrp #=> 25527
2975 static VALUE
2976 proc_getpgrp(void)
2978 #if defined(HAVE_GETPGRP) && defined(GETPGRP_VOID) || defined(HAVE_GETPGID)
2979 rb_pid_t pgrp;
2980 #endif
2982 rb_secure(2);
2983 #if defined(HAVE_GETPGRP) && defined(GETPGRP_VOID)
2984 pgrp = getpgrp();
2985 if (pgrp < 0) rb_sys_fail(0);
2986 return PIDT2NUM(pgrp);
2987 #else
2988 # ifdef HAVE_GETPGID
2989 pgrp = getpgid(0);
2990 if (pgrp < 0) rb_sys_fail(0);
2991 return PIDT2NUM(pgrp);
2992 # else
2993 rb_notimplement();
2994 # endif
2995 #endif
3000 * call-seq:
3001 * Process.setpgrp => 0
3003 * Equivalent to <code>setpgid(0,0)</code>. Not available on all
3004 * platforms.
3007 static VALUE
3008 proc_setpgrp(void)
3010 rb_secure(2);
3011 /* check for posix setpgid() first; this matches the posix */
3012 /* getpgrp() above. It appears that configure will set SETPGRP_VOID */
3013 /* even though setpgrp(0,0) would be preferred. The posix call avoids */
3014 /* this confusion. */
3015 #ifdef HAVE_SETPGID
3016 if (setpgid(0,0) < 0) rb_sys_fail(0);
3017 #elif defined(HAVE_SETPGRP) && defined(SETPGRP_VOID)
3018 if (setpgrp() < 0) rb_sys_fail(0);
3019 #else
3020 rb_notimplement();
3021 #endif
3022 return INT2FIX(0);
3027 * call-seq:
3028 * Process.getpgid(pid) => integer
3030 * Returns the process group ID for the given process id. Not
3031 * available on all platforms.
3033 * Process.getpgid(Process.ppid()) #=> 25527
3036 static VALUE
3037 proc_getpgid(VALUE obj, VALUE pid)
3039 #if defined(HAVE_GETPGID) && !defined(__CHECKER__)
3040 rb_pid_t i;
3042 rb_secure(2);
3043 i = getpgid(NUM2PIDT(pid));
3044 if (i < 0) rb_sys_fail(0);
3045 return PIDT2NUM(i);
3046 #else
3047 rb_notimplement();
3048 #endif
3053 * call-seq:
3054 * Process.setpgid(pid, integer) => 0
3056 * Sets the process group ID of _pid_ (0 indicates this
3057 * process) to <em>integer</em>. Not available on all platforms.
3060 static VALUE
3061 proc_setpgid(VALUE obj, VALUE pid, VALUE pgrp)
3063 #ifdef HAVE_SETPGID
3064 rb_pid_t ipid, ipgrp;
3066 rb_secure(2);
3067 ipid = NUM2PIDT(pid);
3068 ipgrp = NUM2PIDT(pgrp);
3070 if (setpgid(ipid, ipgrp) < 0) rb_sys_fail(0);
3071 return INT2FIX(0);
3072 #else
3073 rb_notimplement();
3074 #endif
3079 * call-seq:
3080 * Process.setsid => fixnum
3082 * Establishes this process as a new session and process group
3083 * leader, with no controlling tty. Returns the session id. Not
3084 * available on all platforms.
3086 * Process.setsid #=> 27422
3089 static VALUE
3090 proc_setsid(void)
3092 #if defined(HAVE_SETSID)
3093 rb_pid_t pid;
3095 rb_secure(2);
3096 pid = setsid();
3097 if (pid < 0) rb_sys_fail(0);
3098 return PIDT2NUM(pid);
3099 #elif defined(HAVE_SETPGRP) && defined(TIOCNOTTY)
3100 rb_pid_t pid;
3101 int ret;
3103 rb_secure(2);
3104 pid = getpid();
3105 #if defined(SETPGRP_VOID)
3106 ret = setpgrp();
3107 /* If `pid_t setpgrp(void)' is equivalent to setsid(),
3108 `ret' will be the same value as `pid', and following open() will fail.
3109 In Linux, `int setpgrp(void)' is equivalent to setpgid(0, 0). */
3110 #else
3111 ret = setpgrp(0, pid);
3112 #endif
3113 if (ret == -1) rb_sys_fail(0);
3115 if ((fd = open("/dev/tty", O_RDWR)) >= 0) {
3116 ioctl(fd, TIOCNOTTY, NULL);
3117 close(fd);
3119 return PIDT2NUM(pid);
3120 #else
3121 rb_notimplement();
3122 #endif
3127 * call-seq:
3128 * Process.getpriority(kind, integer) => fixnum
3130 * Gets the scheduling priority for specified process, process group,
3131 * or user. <em>kind</em> indicates the kind of entity to find: one
3132 * of <code>Process::PRIO_PGRP</code>,
3133 * <code>Process::PRIO_USER</code>, or
3134 * <code>Process::PRIO_PROCESS</code>. _integer_ is an id
3135 * indicating the particular process, process group, or user (an id
3136 * of 0 means _current_). Lower priorities are more favorable
3137 * for scheduling. Not available on all platforms.
3139 * Process.getpriority(Process::PRIO_USER, 0) #=> 19
3140 * Process.getpriority(Process::PRIO_PROCESS, 0) #=> 19
3143 static VALUE
3144 proc_getpriority(VALUE obj, VALUE which, VALUE who)
3146 #ifdef HAVE_GETPRIORITY
3147 int prio, iwhich, iwho;
3149 rb_secure(2);
3150 iwhich = NUM2INT(which);
3151 iwho = NUM2INT(who);
3153 errno = 0;
3154 prio = getpriority(iwhich, iwho);
3155 if (errno) rb_sys_fail(0);
3156 return INT2FIX(prio);
3157 #else
3158 rb_notimplement();
3159 #endif
3164 * call-seq:
3165 * Process.setpriority(kind, integer, priority) => 0
3167 * See <code>Process#getpriority</code>.
3169 * Process.setpriority(Process::PRIO_USER, 0, 19) #=> 0
3170 * Process.setpriority(Process::PRIO_PROCESS, 0, 19) #=> 0
3171 * Process.getpriority(Process::PRIO_USER, 0) #=> 19
3172 * Process.getpriority(Process::PRIO_PROCESS, 0) #=> 19
3175 static VALUE
3176 proc_setpriority(VALUE obj, VALUE which, VALUE who, VALUE prio)
3178 #ifdef HAVE_GETPRIORITY
3179 int iwhich, iwho, iprio;
3181 rb_secure(2);
3182 iwhich = NUM2INT(which);
3183 iwho = NUM2INT(who);
3184 iprio = NUM2INT(prio);
3186 if (setpriority(iwhich, iwho, iprio) < 0)
3187 rb_sys_fail(0);
3188 return INT2FIX(0);
3189 #else
3190 rb_notimplement();
3191 #endif
3194 #if defined(RLIM2NUM)
3195 static int
3196 rlimit_resource_name2int(const char *name, int casetype)
3198 size_t len = strlen(name);
3199 if (16 < len) return -1;
3200 if (casetype == 1) {
3201 int i;
3202 char *name2 = ALLOCA_N(char, len+1);
3203 for (i = 0; i < len; i++) {
3204 if (!ISLOWER(name[i]))
3205 return -1;
3206 name2[i] = TOUPPER(name[i]);
3208 name2[len] = '\0';
3209 name = name2;
3212 switch (*name) {
3213 case 'A':
3214 #ifdef RLIMIT_AS
3215 if (strcmp(name, "AS") == 0) return RLIMIT_AS;
3216 #endif
3217 break;
3219 case 'C':
3220 #ifdef RLIMIT_CORE
3221 if (strcmp(name, "CORE") == 0) return RLIMIT_CORE;
3222 #endif
3223 #ifdef RLIMIT_CPU
3224 if (strcmp(name, "CPU") == 0) return RLIMIT_CPU;
3225 #endif
3226 break;
3228 case 'D':
3229 #ifdef RLIMIT_DATA
3230 if (strcmp(name, "DATA") == 0) return RLIMIT_DATA;
3231 #endif
3232 break;
3234 case 'F':
3235 #ifdef RLIMIT_FSIZE
3236 if (strcmp(name, "FSIZE") == 0) return RLIMIT_FSIZE;
3237 #endif
3238 break;
3240 case 'M':
3241 #ifdef RLIMIT_MEMLOCK
3242 if (strcmp(name, "MEMLOCK") == 0) return RLIMIT_MEMLOCK;
3243 #endif
3244 break;
3246 case 'N':
3247 #ifdef RLIMIT_NOFILE
3248 if (strcmp(name, "NOFILE") == 0) return RLIMIT_NOFILE;
3249 #endif
3250 #ifdef RLIMIT_NPROC
3251 if (strcmp(name, "NPROC") == 0) return RLIMIT_NPROC;
3252 #endif
3253 break;
3255 case 'R':
3256 #ifdef RLIMIT_RSS
3257 if (strcmp(name, "RSS") == 0) return RLIMIT_RSS;
3258 #endif
3259 break;
3261 case 'S':
3262 #ifdef RLIMIT_STACK
3263 if (strcmp(name, "STACK") == 0) return RLIMIT_STACK;
3264 #endif
3265 #ifdef RLIMIT_SBSIZE
3266 if (strcmp(name, "SBSIZE") == 0) return RLIMIT_SBSIZE;
3267 #endif
3268 break;
3270 return -1;
3273 static int
3274 rlimit_type_by_hname(const char *name)
3276 return rlimit_resource_name2int(name, 0);
3279 static int
3280 rlimit_type_by_lname(const char *name)
3282 return rlimit_resource_name2int(name, 1);
3285 static int
3286 rlimit_resource_type(VALUE rtype)
3288 const char *name;
3289 VALUE v;
3290 int r;
3292 switch (TYPE(rtype)) {
3293 case T_SYMBOL:
3294 name = rb_id2name(SYM2ID(rtype));
3295 break;
3297 default:
3298 v = rb_check_string_type(rtype);
3299 if (!NIL_P(v)) {
3300 rtype = v;
3301 case T_STRING:
3302 name = StringValueCStr(rtype);
3303 break;
3305 /* fall through */
3307 case T_FIXNUM:
3308 case T_BIGNUM:
3309 return NUM2INT(rtype);
3312 r = rlimit_type_by_hname(name);
3313 if (r != -1)
3314 return r;
3316 rb_raise(rb_eArgError, "invalid resource name: %s", name);
3319 static rlim_t
3320 rlimit_resource_value(VALUE rval)
3322 const char *name;
3323 VALUE v;
3325 switch (TYPE(rval)) {
3326 case T_SYMBOL:
3327 name = rb_id2name(SYM2ID(rval));
3328 break;
3330 default:
3331 v = rb_check_string_type(rval);
3332 if (!NIL_P(v)) {
3333 rval = v;
3334 case T_STRING:
3335 name = StringValueCStr(rval);
3336 break;
3338 /* fall through */
3340 case T_FIXNUM:
3341 case T_BIGNUM:
3342 return NUM2RLIM(rval);
3345 #ifdef RLIM_INFINITY
3346 if (strcmp(name, "INFINITY") == 0) return RLIM_INFINITY;
3347 #endif
3348 #ifdef RLIM_SAVED_MAX
3349 if (strcmp(name, "SAVED_MAX") == 0) return RLIM_SAVED_MAX;
3350 #endif
3351 #ifdef RLIM_SAVED_CUR
3352 if (strcmp(name, "SAVED_CUR") == 0) return RLIM_SAVED_CUR;
3353 #endif
3354 rb_raise(rb_eArgError, "invalid resource value: %s", name);
3356 #endif
3359 * call-seq:
3360 * Process.getrlimit(resource) => [cur_limit, max_limit]
3362 * Gets the resource limit of the process.
3363 * _cur_limit_ means current (soft) limit and
3364 * _max_limit_ means maximum (hard) limit.
3366 * _resource_ indicates the kind of resource to limit.
3367 * It is specified as a symbol such as <code>:CORE</code>,
3368 * a string such as <code>"CORE"</code> or
3369 * a constant such as <code>Process::RLIMIT_CORE</code>.
3370 * See Process.setrlimit for details.
3372 * _cur_limit_ and _max_limit_ may be <code>Process::RLIM_INFINITY</code>,
3373 * <code>Process::RLIM_SAVED_MAX</code> or
3374 * <code>Process::RLIM_SAVED_CUR</code>.
3375 * See Process.setrlimit and the system getrlimit(2) manual for details.
3378 static VALUE
3379 proc_getrlimit(VALUE obj, VALUE resource)
3381 #if defined(HAVE_GETRLIMIT) && defined(RLIM2NUM)
3382 struct rlimit rlim;
3384 rb_secure(2);
3386 if (getrlimit(rlimit_resource_type(resource), &rlim) < 0) {
3387 rb_sys_fail("getrlimit");
3389 return rb_assoc_new(RLIM2NUM(rlim.rlim_cur), RLIM2NUM(rlim.rlim_max));
3390 #else
3391 rb_notimplement();
3392 #endif
3396 * call-seq:
3397 * Process.setrlimit(resource, cur_limit, max_limit) => nil
3398 * Process.setrlimit(resource, cur_limit) => nil
3400 * Sets the resource limit of the process.
3401 * _cur_limit_ means current (soft) limit and
3402 * _max_limit_ means maximum (hard) limit.
3404 * If _max_limit_ is not given, _cur_limit_ is used.
3406 * _resource_ indicates the kind of resource to limit.
3407 * It should be a symbol such as <code>:CORE</code>,
3408 * a string such as <code>"CORE"</code> or
3409 * a constant such as <code>Process::RLIMIT_CORE</code>.
3410 * The available resources are OS dependent.
3411 * Ruby may support following resources.
3413 * [CORE] core size (bytes) (SUSv3)
3414 * [CPU] CPU time (seconds) (SUSv3)
3415 * [DATA] data segment (bytes) (SUSv3)
3416 * [FSIZE] file size (bytes) (SUSv3)
3417 * [NOFILE] file descriptors (number) (SUSv3)
3418 * [STACK] stack size (bytes) (SUSv3)
3419 * [AS] total available memory (bytes) (SUSv3, NetBSD, FreeBSD, OpenBSD but 4.4BSD-Lite)
3420 * [MEMLOCK] total size for mlock(2) (bytes) (4.4BSD, GNU/Linux)
3421 * [NPROC] number of processes for the user (number) (4.4BSD, GNU/Linux)
3422 * [RSS] resident memory size (bytes) (4.2BSD, GNU/Linux)
3423 * [SBSIZE] all socket buffers (bytes) (NetBSD, FreeBSD)
3425 * _cur_limit_ and _max_limit_ may be
3426 * <code>:INFINITY</code>, <code>"INFINITY"</code> or
3427 * <code>Process::RLIM_INFINITY</code>,
3428 * which means that the resource is not limited.
3429 * They may be <code>Process::RLIM_SAVED_MAX</code>,
3430 * <code>Process::RLIM_SAVED_CUR</code> and
3431 * corresponding symbols and strings too.
3432 * See system setrlimit(2) manual for details.
3434 * The following example raise the soft limit of core size to
3435 * the hard limit to try to make core dump possible.
3437 * Process.setrlimit(:CORE, Process.getrlimit(:CORE)[1])
3441 static VALUE
3442 proc_setrlimit(int argc, VALUE *argv, VALUE obj)
3444 #if defined(HAVE_SETRLIMIT) && defined(NUM2RLIM)
3445 VALUE resource, rlim_cur, rlim_max;
3446 struct rlimit rlim;
3448 rb_secure(2);
3450 rb_scan_args(argc, argv, "21", &resource, &rlim_cur, &rlim_max);
3451 if (rlim_max == Qnil)
3452 rlim_max = rlim_cur;
3454 rlim.rlim_cur = rlimit_resource_value(rlim_cur);
3455 rlim.rlim_max = rlimit_resource_value(rlim_max);
3457 if (setrlimit(rlimit_resource_type(resource), &rlim) < 0) {
3458 rb_sys_fail("setrlimit");
3460 return Qnil;
3461 #else
3462 rb_notimplement();
3463 #endif
3466 static int under_uid_switch = 0;
3467 static void
3468 check_uid_switch(void)
3470 rb_secure(2);
3471 if (under_uid_switch) {
3472 rb_raise(rb_eRuntimeError, "can't handle UID while evaluating block given to Process::UID.switch method");
3476 static int under_gid_switch = 0;
3477 static void
3478 check_gid_switch(void)
3480 rb_secure(2);
3481 if (under_gid_switch) {
3482 rb_raise(rb_eRuntimeError, "can't handle GID while evaluating block given to Process::UID.switch method");
3487 /*********************************************************************
3488 * Document-class: Process::Sys
3490 * The <code>Process::Sys</code> module contains UID and GID
3491 * functions which provide direct bindings to the system calls of the
3492 * same names instead of the more-portable versions of the same
3493 * functionality found in the <code>Process</code>,
3494 * <code>Process::UID</code>, and <code>Process::GID</code> modules.
3499 * call-seq:
3500 * Process::Sys.setuid(integer) => nil
3502 * Set the user ID of the current process to _integer_. Not
3503 * available on all platforms.
3507 static VALUE
3508 p_sys_setuid(VALUE obj, VALUE id)
3510 #if defined HAVE_SETUID
3511 check_uid_switch();
3512 if (setuid(NUM2UIDT(id)) != 0) rb_sys_fail(0);
3513 #else
3514 rb_notimplement();
3515 #endif
3516 return Qnil;
3522 * call-seq:
3523 * Process::Sys.setruid(integer) => nil
3525 * Set the real user ID of the calling process to _integer_.
3526 * Not available on all platforms.
3530 static VALUE
3531 p_sys_setruid(VALUE obj, VALUE id)
3533 #if defined HAVE_SETRUID
3534 check_uid_switch();
3535 if (setruid(NUM2UIDT(id)) != 0) rb_sys_fail(0);
3536 #else
3537 rb_notimplement();
3538 #endif
3539 return Qnil;
3544 * call-seq:
3545 * Process::Sys.seteuid(integer) => nil
3547 * Set the effective user ID of the calling process to
3548 * _integer_. Not available on all platforms.
3552 static VALUE
3553 p_sys_seteuid(VALUE obj, VALUE id)
3555 #if defined HAVE_SETEUID
3556 check_uid_switch();
3557 if (seteuid(NUM2UIDT(id)) != 0) rb_sys_fail(0);
3558 #else
3559 rb_notimplement();
3560 #endif
3561 return Qnil;
3566 * call-seq:
3567 * Process::Sys.setreuid(rid, eid) => nil
3569 * Sets the (integer) real and/or effective user IDs of the current
3570 * process to _rid_ and _eid_, respectively. A value of
3571 * <code>-1</code> for either means to leave that ID unchanged. Not
3572 * available on all platforms.
3576 static VALUE
3577 p_sys_setreuid(VALUE obj, VALUE rid, VALUE eid)
3579 #if defined HAVE_SETREUID
3580 check_uid_switch();
3581 if (setreuid(NUM2UIDT(rid),NUM2UIDT(eid)) != 0) rb_sys_fail(0);
3582 #else
3583 rb_notimplement();
3584 #endif
3585 return Qnil;
3590 * call-seq:
3591 * Process::Sys.setresuid(rid, eid, sid) => nil
3593 * Sets the (integer) real, effective, and saved user IDs of the
3594 * current process to _rid_, _eid_, and _sid_ respectively. A
3595 * value of <code>-1</code> for any value means to
3596 * leave that ID unchanged. Not available on all platforms.
3600 static VALUE
3601 p_sys_setresuid(VALUE obj, VALUE rid, VALUE eid, VALUE sid)
3603 #if defined HAVE_SETRESUID
3604 check_uid_switch();
3605 if (setresuid(NUM2UIDT(rid),NUM2UIDT(eid),NUM2UIDT(sid)) != 0) rb_sys_fail(0);
3606 #else
3607 rb_notimplement();
3608 #endif
3609 return Qnil;
3614 * call-seq:
3615 * Process.uid => fixnum
3616 * Process::UID.rid => fixnum
3617 * Process::Sys.getuid => fixnum
3619 * Returns the (real) user ID of this process.
3621 * Process.uid #=> 501
3624 static VALUE
3625 proc_getuid(VALUE obj)
3627 rb_uid_t uid = getuid();
3628 return UIDT2NUM(uid);
3633 * call-seq:
3634 * Process.uid= integer => numeric
3636 * Sets the (integer) user ID for this process. Not available on all
3637 * platforms.
3640 static VALUE
3641 proc_setuid(VALUE obj, VALUE id)
3643 rb_uid_t uid;
3645 check_uid_switch();
3647 uid = NUM2UIDT(id);
3648 #if defined(HAVE_SETRESUID) && !defined(__CHECKER__)
3649 if (setresuid(uid, -1, -1) < 0) rb_sys_fail(0);
3650 #elif defined HAVE_SETREUID
3651 if (setreuid(uid, -1) < 0) rb_sys_fail(0);
3652 #elif defined HAVE_SETRUID
3653 if (setruid(uid) < 0) rb_sys_fail(0);
3654 #elif defined HAVE_SETUID
3656 if (geteuid() == uid) {
3657 if (setuid(uid) < 0) rb_sys_fail(0);
3659 else {
3660 rb_notimplement();
3663 #else
3664 rb_notimplement();
3665 #endif
3666 return id;
3670 /********************************************************************
3672 * Document-class: Process::UID
3674 * The <code>Process::UID</code> module contains a collection of
3675 * module functions which can be used to portably get, set, and
3676 * switch the current process's real, effective, and saved user IDs.
3680 static rb_uid_t SAVED_USER_ID = -1;
3682 #ifdef BROKEN_SETREUID
3684 setreuid(rb_uid_t ruid, rb_uid_t euid)
3686 if (ruid != -1 && ruid != getuid()) {
3687 if (euid == -1) euid = geteuid();
3688 if (setuid(ruid) < 0) return -1;
3690 if (euid != -1 && euid != geteuid()) {
3691 if (seteuid(euid) < 0) return -1;
3693 return 0;
3695 #endif
3698 * call-seq:
3699 * Process::UID.change_privilege(integer) => fixnum
3701 * Change the current process's real and effective user ID to that
3702 * specified by _integer_. Returns the new user ID. Not
3703 * available on all platforms.
3705 * [Process.uid, Process.euid] #=> [0, 0]
3706 * Process::UID.change_privilege(31) #=> 31
3707 * [Process.uid, Process.euid] #=> [31, 31]
3710 static VALUE
3711 p_uid_change_privilege(VALUE obj, VALUE id)
3713 rb_uid_t uid;
3715 check_uid_switch();
3717 uid = NUM2UIDT(id);
3719 if (geteuid() == 0) { /* root-user */
3720 #if defined(HAVE_SETRESUID)
3721 if (setresuid(uid, uid, uid) < 0) rb_sys_fail(0);
3722 SAVED_USER_ID = uid;
3723 #elif defined(HAVE_SETUID)
3724 if (setuid(uid) < 0) rb_sys_fail(0);
3725 SAVED_USER_ID = uid;
3726 #elif defined(HAVE_SETREUID) && !defined(OBSOLETE_SETREUID)
3727 if (getuid() == uid) {
3728 if (SAVED_USER_ID == uid) {
3729 if (setreuid(-1, uid) < 0) rb_sys_fail(0);
3730 } else {
3731 if (uid == 0) { /* (r,e,s) == (root, root, x) */
3732 if (setreuid(-1, SAVED_USER_ID) < 0) rb_sys_fail(0);
3733 if (setreuid(SAVED_USER_ID, 0) < 0) rb_sys_fail(0);
3734 SAVED_USER_ID = 0; /* (r,e,s) == (x, root, root) */
3735 if (setreuid(uid, uid) < 0) rb_sys_fail(0);
3736 SAVED_USER_ID = uid;
3737 } else {
3738 if (setreuid(0, -1) < 0) rb_sys_fail(0);
3739 SAVED_USER_ID = 0;
3740 if (setreuid(uid, uid) < 0) rb_sys_fail(0);
3741 SAVED_USER_ID = uid;
3744 } else {
3745 if (setreuid(uid, uid) < 0) rb_sys_fail(0);
3746 SAVED_USER_ID = uid;
3748 #elif defined(HAVE_SETRUID) && defined(HAVE_SETEUID)
3749 if (getuid() == uid) {
3750 if (SAVED_USER_ID == uid) {
3751 if (seteuid(uid) < 0) rb_sys_fail(0);
3752 } else {
3753 if (uid == 0) {
3754 if (setruid(SAVED_USER_ID) < 0) rb_sys_fail(0);
3755 SAVED_USER_ID = 0;
3756 if (setruid(0) < 0) rb_sys_fail(0);
3757 } else {
3758 if (setruid(0) < 0) rb_sys_fail(0);
3759 SAVED_USER_ID = 0;
3760 if (seteuid(uid) < 0) rb_sys_fail(0);
3761 if (setruid(uid) < 0) rb_sys_fail(0);
3762 SAVED_USER_ID = uid;
3765 } else {
3766 if (seteuid(uid) < 0) rb_sys_fail(0);
3767 if (setruid(uid) < 0) rb_sys_fail(0);
3768 SAVED_USER_ID = uid;
3770 #else
3771 rb_notimplement();
3772 #endif
3773 } else { /* unprivileged user */
3774 #if defined(HAVE_SETRESUID)
3775 if (setresuid((getuid() == uid)? -1: uid,
3776 (geteuid() == uid)? -1: uid,
3777 (SAVED_USER_ID == uid)? -1: uid) < 0) rb_sys_fail(0);
3778 SAVED_USER_ID = uid;
3779 #elif defined(HAVE_SETREUID) && !defined(OBSOLETE_SETREUID)
3780 if (SAVED_USER_ID == uid) {
3781 if (setreuid((getuid() == uid)? -1: uid,
3782 (geteuid() == uid)? -1: uid) < 0) rb_sys_fail(0);
3783 } else if (getuid() != uid) {
3784 if (setreuid(uid, (geteuid() == uid)? -1: uid) < 0) rb_sys_fail(0);
3785 SAVED_USER_ID = uid;
3786 } else if (/* getuid() == uid && */ geteuid() != uid) {
3787 if (setreuid(geteuid(), uid) < 0) rb_sys_fail(0);
3788 SAVED_USER_ID = uid;
3789 if (setreuid(uid, -1) < 0) rb_sys_fail(0);
3790 } else { /* getuid() == uid && geteuid() == uid */
3791 if (setreuid(-1, SAVED_USER_ID) < 0) rb_sys_fail(0);
3792 if (setreuid(SAVED_USER_ID, uid) < 0) rb_sys_fail(0);
3793 SAVED_USER_ID = uid;
3794 if (setreuid(uid, -1) < 0) rb_sys_fail(0);
3796 #elif defined(HAVE_SETRUID) && defined(HAVE_SETEUID)
3797 if (SAVED_USER_ID == uid) {
3798 if (geteuid() != uid && seteuid(uid) < 0) rb_sys_fail(0);
3799 if (getuid() != uid && setruid(uid) < 0) rb_sys_fail(0);
3800 } else if (/* SAVED_USER_ID != uid && */ geteuid() == uid) {
3801 if (getuid() != uid) {
3802 if (setruid(uid) < 0) rb_sys_fail(0);
3803 SAVED_USER_ID = uid;
3804 } else {
3805 if (setruid(SAVED_USER_ID) < 0) rb_sys_fail(0);
3806 SAVED_USER_ID = uid;
3807 if (setruid(uid) < 0) rb_sys_fail(0);
3809 } else if (/* geteuid() != uid && */ getuid() == uid) {
3810 if (seteuid(uid) < 0) rb_sys_fail(0);
3811 if (setruid(SAVED_USER_ID) < 0) rb_sys_fail(0);
3812 SAVED_USER_ID = uid;
3813 if (setruid(uid) < 0) rb_sys_fail(0);
3814 } else {
3815 errno = EPERM;
3816 rb_sys_fail(0);
3818 #elif defined HAVE_44BSD_SETUID
3819 if (getuid() == uid) {
3820 /* (r,e,s)==(uid,?,?) ==> (uid,uid,uid) */
3821 if (setuid(uid) < 0) rb_sys_fail(0);
3822 SAVED_USER_ID = uid;
3823 } else {
3824 errno = EPERM;
3825 rb_sys_fail(0);
3827 #elif defined HAVE_SETEUID
3828 if (getuid() == uid && SAVED_USER_ID == uid) {
3829 if (seteuid(uid) < 0) rb_sys_fail(0);
3830 } else {
3831 errno = EPERM;
3832 rb_sys_fail(0);
3834 #elif defined HAVE_SETUID
3835 if (getuid() == uid && SAVED_USER_ID == uid) {
3836 if (setuid(uid) < 0) rb_sys_fail(0);
3837 } else {
3838 errno = EPERM;
3839 rb_sys_fail(0);
3841 #else
3842 rb_notimplement();
3843 #endif
3845 return id;
3851 * call-seq:
3852 * Process::Sys.setgid(integer) => nil
3854 * Set the group ID of the current process to _integer_. Not
3855 * available on all platforms.
3859 static VALUE
3860 p_sys_setgid(VALUE obj, VALUE id)
3862 #if defined HAVE_SETGID
3863 check_gid_switch();
3864 if (setgid(NUM2GIDT(id)) != 0) rb_sys_fail(0);
3865 #else
3866 rb_notimplement();
3867 #endif
3868 return Qnil;
3873 * call-seq:
3874 * Process::Sys.setrgid(integer) => nil
3876 * Set the real group ID of the calling process to _integer_.
3877 * Not available on all platforms.
3881 static VALUE
3882 p_sys_setrgid(VALUE obj, VALUE id)
3884 #if defined HAVE_SETRGID
3885 check_gid_switch();
3886 if (setrgid(NUM2GIDT(id)) != 0) rb_sys_fail(0);
3887 #else
3888 rb_notimplement();
3889 #endif
3890 return Qnil;
3896 * call-seq:
3897 * Process::Sys.setegid(integer) => nil
3899 * Set the effective group ID of the calling process to
3900 * _integer_. Not available on all platforms.
3904 static VALUE
3905 p_sys_setegid(VALUE obj, VALUE id)
3907 #if defined HAVE_SETEGID
3908 check_gid_switch();
3909 if (setegid(NUM2GIDT(id)) != 0) rb_sys_fail(0);
3910 #else
3911 rb_notimplement();
3912 #endif
3913 return Qnil;
3918 * call-seq:
3919 * Process::Sys.setregid(rid, eid) => nil
3921 * Sets the (integer) real and/or effective group IDs of the current
3922 * process to <em>rid</em> and <em>eid</em>, respectively. A value of
3923 * <code>-1</code> for either means to leave that ID unchanged. Not
3924 * available on all platforms.
3928 static VALUE
3929 p_sys_setregid(VALUE obj, VALUE rid, VALUE eid)
3931 #if defined HAVE_SETREGID
3932 check_gid_switch();
3933 if (setregid(NUM2GIDT(rid),NUM2GIDT(eid)) != 0) rb_sys_fail(0);
3934 #else
3935 rb_notimplement();
3936 #endif
3937 return Qnil;
3941 * call-seq:
3942 * Process::Sys.setresgid(rid, eid, sid) => nil
3944 * Sets the (integer) real, effective, and saved user IDs of the
3945 * current process to <em>rid</em>, <em>eid</em>, and <em>sid</em>
3946 * respectively. A value of <code>-1</code> for any value means to
3947 * leave that ID unchanged. Not available on all platforms.
3951 static VALUE
3952 p_sys_setresgid(VALUE obj, VALUE rid, VALUE eid, VALUE sid)
3954 #if defined HAVE_SETRESGID
3955 check_gid_switch();
3956 if (setresgid(NUM2GIDT(rid),NUM2GIDT(eid),NUM2GIDT(sid)) != 0) rb_sys_fail(0);
3957 #else
3958 rb_notimplement();
3959 #endif
3960 return Qnil;
3965 * call-seq:
3966 * Process::Sys.issetugid => true or false
3968 * Returns +true+ if the process was created as a result
3969 * of an execve(2) system call which had either of the setuid or
3970 * setgid bits set (and extra privileges were given as a result) or
3971 * if it has changed any of its real, effective or saved user or
3972 * group IDs since it began execution.
3976 static VALUE
3977 p_sys_issetugid(VALUE obj)
3979 #if defined HAVE_ISSETUGID
3980 rb_secure(2);
3981 if (issetugid()) {
3982 return Qtrue;
3983 } else {
3984 return Qfalse;
3986 #else
3987 rb_notimplement();
3988 return Qnil; /* not reached */
3989 #endif
3994 * call-seq:
3995 * Process.gid => fixnum
3996 * Process::GID.rid => fixnum
3997 * Process::Sys.getgid => fixnum
3999 * Returns the (real) group ID for this process.
4001 * Process.gid #=> 500
4004 static VALUE
4005 proc_getgid(VALUE obj)
4007 rb_gid_t gid = getgid();
4008 return GIDT2NUM(gid);
4013 * call-seq:
4014 * Process.gid= fixnum => fixnum
4016 * Sets the group ID for this process.
4019 static VALUE
4020 proc_setgid(VALUE obj, VALUE id)
4022 rb_gid_t gid;
4024 check_gid_switch();
4026 gid = NUM2GIDT(id);
4027 #if defined(HAVE_SETRESGID) && !defined(__CHECKER__)
4028 if (setresgid(gid, -1, -1) < 0) rb_sys_fail(0);
4029 #elif defined HAVE_SETREGID
4030 if (setregid(gid, -1) < 0) rb_sys_fail(0);
4031 #elif defined HAVE_SETRGID
4032 if (setrgid(gid) < 0) rb_sys_fail(0);
4033 #elif defined HAVE_SETGID
4035 if (getegid() == gid) {
4036 if (setgid(gid) < 0) rb_sys_fail(0);
4038 else {
4039 rb_notimplement();
4042 #else
4043 rb_notimplement();
4044 #endif
4045 return GIDT2NUM(gid);
4049 static size_t maxgroups = 32;
4053 * call-seq:
4054 * Process.groups => array
4056 * Get an <code>Array</code> of the gids of groups in the
4057 * supplemental group access list for this process.
4059 * Process.groups #=> [27, 6, 10, 11]
4063 static VALUE
4064 proc_getgroups(VALUE obj)
4066 #ifdef HAVE_GETGROUPS
4067 VALUE ary;
4068 size_t ngroups;
4069 rb_gid_t *groups;
4070 int i;
4072 groups = ALLOCA_N(rb_gid_t, maxgroups);
4074 ngroups = getgroups(maxgroups, groups);
4075 if (ngroups == -1)
4076 rb_sys_fail(0);
4078 ary = rb_ary_new();
4079 for (i = 0; i < ngroups; i++)
4080 rb_ary_push(ary, GIDT2NUM(groups[i]));
4082 return ary;
4083 #else
4084 rb_notimplement();
4085 return Qnil;
4086 #endif
4091 * call-seq:
4092 * Process.groups= array => array
4094 * Set the supplemental group access list to the given
4095 * <code>Array</code> of group IDs.
4097 * Process.groups #=> [0, 1, 2, 3, 4, 6, 10, 11, 20, 26, 27]
4098 * Process.groups = [27, 6, 10, 11] #=> [27, 6, 10, 11]
4099 * Process.groups #=> [27, 6, 10, 11]
4103 static VALUE
4104 proc_setgroups(VALUE obj, VALUE ary)
4106 #ifdef HAVE_SETGROUPS
4107 size_t ngroups;
4108 rb_gid_t *groups;
4109 int i;
4110 struct group *gr;
4112 Check_Type(ary, T_ARRAY);
4114 ngroups = RARRAY_LEN(ary);
4115 if (ngroups > maxgroups)
4116 rb_raise(rb_eArgError, "too many groups, %lu max", (unsigned long)maxgroups);
4118 groups = ALLOCA_N(rb_gid_t, ngroups);
4120 for (i = 0; i < ngroups && i < RARRAY_LEN(ary); i++) {
4121 VALUE g = RARRAY_PTR(ary)[i];
4123 if (FIXNUM_P(g)) {
4124 groups[i] = NUM2GIDT(g);
4126 else {
4127 VALUE tmp = rb_check_string_type(g);
4129 if (NIL_P(tmp)) {
4130 groups[i] = NUM2GIDT(g);
4132 else {
4133 gr = getgrnam(RSTRING_PTR(tmp));
4134 if (gr == NULL)
4135 rb_raise(rb_eArgError,
4136 "can't find group for %s", RSTRING_PTR(tmp));
4137 groups[i] = gr->gr_gid;
4142 i = setgroups(ngroups, groups);
4143 if (i == -1)
4144 rb_sys_fail(0);
4146 return proc_getgroups(obj);
4147 #else
4148 rb_notimplement();
4149 return Qnil;
4150 #endif
4155 * call-seq:
4156 * Process.initgroups(username, gid) => array
4158 * Initializes the supplemental group access list by reading the
4159 * system group database and using all groups of which the given user
4160 * is a member. The group with the specified <em>gid</em> is also
4161 * added to the list. Returns the resulting <code>Array</code> of the
4162 * gids of all the groups in the supplementary group access list. Not
4163 * available on all platforms.
4165 * Process.groups #=> [0, 1, 2, 3, 4, 6, 10, 11, 20, 26, 27]
4166 * Process.initgroups( "mgranger", 30 ) #=> [30, 6, 10, 11]
4167 * Process.groups #=> [30, 6, 10, 11]
4171 static VALUE
4172 proc_initgroups(VALUE obj, VALUE uname, VALUE base_grp)
4174 #ifdef HAVE_INITGROUPS
4175 if (initgroups(StringValuePtr(uname), NUM2GIDT(base_grp)) != 0) {
4176 rb_sys_fail(0);
4178 return proc_getgroups(obj);
4179 #else
4180 rb_notimplement();
4181 return Qnil;
4182 #endif
4187 * call-seq:
4188 * Process.maxgroups => fixnum
4190 * Returns the maximum number of gids allowed in the supplemental
4191 * group access list.
4193 * Process.maxgroups #=> 32
4196 static VALUE
4197 proc_getmaxgroups(VALUE obj)
4199 return INT2FIX(maxgroups);
4204 * call-seq:
4205 * Process.maxgroups= fixnum => fixnum
4207 * Sets the maximum number of gids allowed in the supplemental group
4208 * access list.
4211 static VALUE
4212 proc_setmaxgroups(VALUE obj, VALUE val)
4214 size_t ngroups = FIX2INT(val);
4216 if (ngroups > 4096)
4217 ngroups = 4096;
4219 maxgroups = ngroups;
4221 return INT2FIX(maxgroups);
4225 * call-seq:
4226 * Process.daemon() => fixnum
4227 * Process.daemon(nochdir=nil,noclose=nil) => fixnum
4229 * Detach the process from controlling terminal and run in
4230 * the background as system daemon. Unless the argument
4231 * nochdir is true (i.e. non false), it changes the current
4232 * working directory to the root ("/"). Unless the argument
4233 * noclose is true, daemon() will redirect standard input,
4234 * standard output and standard error to /dev/null.
4237 static VALUE
4238 proc_daemon(int argc, VALUE *argv)
4240 VALUE nochdir, noclose;
4241 #if defined(HAVE_DAEMON) || defined(HAVE_FORK)
4242 int n;
4243 #endif
4245 rb_secure(2);
4246 rb_scan_args(argc, argv, "02", &nochdir, &noclose);
4248 #if defined(HAVE_DAEMON)
4249 n = daemon(RTEST(nochdir), RTEST(noclose));
4250 if (n < 0) rb_sys_fail("daemon");
4251 return INT2FIX(n);
4252 #elif defined(HAVE_FORK)
4253 switch (rb_fork(0, 0, 0, Qnil)) {
4254 case -1:
4255 return (-1);
4256 case 0:
4257 break;
4258 default:
4259 _exit(0);
4262 proc_setsid();
4264 if (!RTEST(nochdir))
4265 (void)chdir("/");
4267 if (!RTEST(noclose) && (n = open("/dev/null", O_RDWR, 0)) != -1) {
4268 (void)dup2(n, 0);
4269 (void)dup2(n, 1);
4270 (void)dup2(n, 2);
4271 if (n > 2)
4272 (void)close (n);
4274 return INT2FIX(0);
4275 #else
4276 rb_notimplement();
4277 #endif
4280 /********************************************************************
4282 * Document-class: Process::GID
4284 * The <code>Process::GID</code> module contains a collection of
4285 * module functions which can be used to portably get, set, and
4286 * switch the current process's real, effective, and saved group IDs.
4290 static int SAVED_GROUP_ID = -1;
4292 #ifdef BROKEN_SETREGID
4294 setregid(rb_gid_t rgid, rb_gid_t egid)
4296 if (rgid != -1 && rgid != getgid()) {
4297 if (egid == -1) egid = getegid();
4298 if (setgid(rgid) < 0) return -1;
4300 if (egid != -1 && egid != getegid()) {
4301 if (setegid(egid) < 0) return -1;
4303 return 0;
4305 #endif
4308 * call-seq:
4309 * Process::GID.change_privilege(integer) => fixnum
4311 * Change the current process's real and effective group ID to that
4312 * specified by _integer_. Returns the new group ID. Not
4313 * available on all platforms.
4315 * [Process.gid, Process.egid] #=> [0, 0]
4316 * Process::GID.change_privilege(33) #=> 33
4317 * [Process.gid, Process.egid] #=> [33, 33]
4320 static VALUE
4321 p_gid_change_privilege(VALUE obj, VALUE id)
4323 rb_gid_t gid;
4325 check_gid_switch();
4327 gid = NUM2GIDT(id);
4329 if (geteuid() == 0) { /* root-user */
4330 #if defined(HAVE_SETRESGID)
4331 if (setresgid(gid, gid, gid) < 0) rb_sys_fail(0);
4332 SAVED_GROUP_ID = gid;
4333 #elif defined HAVE_SETGID
4334 if (setgid(gid) < 0) rb_sys_fail(0);
4335 SAVED_GROUP_ID = gid;
4336 #elif defined(HAVE_SETREGID) && !defined(OBSOLETE_SETREGID)
4337 if (getgid() == gid) {
4338 if (SAVED_GROUP_ID == gid) {
4339 if (setregid(-1, gid) < 0) rb_sys_fail(0);
4340 } else {
4341 if (gid == 0) { /* (r,e,s) == (root, y, x) */
4342 if (setregid(-1, SAVED_GROUP_ID) < 0) rb_sys_fail(0);
4343 if (setregid(SAVED_GROUP_ID, 0) < 0) rb_sys_fail(0);
4344 SAVED_GROUP_ID = 0; /* (r,e,s) == (x, root, root) */
4345 if (setregid(gid, gid) < 0) rb_sys_fail(0);
4346 SAVED_GROUP_ID = gid;
4347 } else { /* (r,e,s) == (z, y, x) */
4348 if (setregid(0, 0) < 0) rb_sys_fail(0);
4349 SAVED_GROUP_ID = 0;
4350 if (setregid(gid, gid) < 0) rb_sys_fail(0);
4351 SAVED_GROUP_ID = gid;
4354 } else {
4355 if (setregid(gid, gid) < 0) rb_sys_fail(0);
4356 SAVED_GROUP_ID = gid;
4358 #elif defined(HAVE_SETRGID) && defined (HAVE_SETEGID)
4359 if (getgid() == gid) {
4360 if (SAVED_GROUP_ID == gid) {
4361 if (setegid(gid) < 0) rb_sys_fail(0);
4362 } else {
4363 if (gid == 0) {
4364 if (setegid(gid) < 0) rb_sys_fail(0);
4365 if (setrgid(SAVED_GROUP_ID) < 0) rb_sys_fail(0);
4366 SAVED_GROUP_ID = 0;
4367 if (setrgid(0) < 0) rb_sys_fail(0);
4368 } else {
4369 if (setrgid(0) < 0) rb_sys_fail(0);
4370 SAVED_GROUP_ID = 0;
4371 if (setegid(gid) < 0) rb_sys_fail(0);
4372 if (setrgid(gid) < 0) rb_sys_fail(0);
4373 SAVED_GROUP_ID = gid;
4376 } else {
4377 if (setegid(gid) < 0) rb_sys_fail(0);
4378 if (setrgid(gid) < 0) rb_sys_fail(0);
4379 SAVED_GROUP_ID = gid;
4381 #else
4382 rb_notimplement();
4383 #endif
4384 } else { /* unprivileged user */
4385 #if defined(HAVE_SETRESGID)
4386 if (setresgid((getgid() == gid)? -1: gid,
4387 (getegid() == gid)? -1: gid,
4388 (SAVED_GROUP_ID == gid)? -1: gid) < 0) rb_sys_fail(0);
4389 SAVED_GROUP_ID = gid;
4390 #elif defined(HAVE_SETREGID) && !defined(OBSOLETE_SETREGID)
4391 if (SAVED_GROUP_ID == gid) {
4392 if (setregid((getgid() == gid)? -1: gid,
4393 (getegid() == gid)? -1: gid) < 0) rb_sys_fail(0);
4394 } else if (getgid() != gid) {
4395 if (setregid(gid, (getegid() == gid)? -1: gid) < 0) rb_sys_fail(0);
4396 SAVED_GROUP_ID = gid;
4397 } else if (/* getgid() == gid && */ getegid() != gid) {
4398 if (setregid(getegid(), gid) < 0) rb_sys_fail(0);
4399 SAVED_GROUP_ID = gid;
4400 if (setregid(gid, -1) < 0) rb_sys_fail(0);
4401 } else { /* getgid() == gid && getegid() == gid */
4402 if (setregid(-1, SAVED_GROUP_ID) < 0) rb_sys_fail(0);
4403 if (setregid(SAVED_GROUP_ID, gid) < 0) rb_sys_fail(0);
4404 SAVED_GROUP_ID = gid;
4405 if (setregid(gid, -1) < 0) rb_sys_fail(0);
4407 #elif defined(HAVE_SETRGID) && defined(HAVE_SETEGID)
4408 if (SAVED_GROUP_ID == gid) {
4409 if (getegid() != gid && setegid(gid) < 0) rb_sys_fail(0);
4410 if (getgid() != gid && setrgid(gid) < 0) rb_sys_fail(0);
4411 } else if (/* SAVED_GROUP_ID != gid && */ getegid() == gid) {
4412 if (getgid() != gid) {
4413 if (setrgid(gid) < 0) rb_sys_fail(0);
4414 SAVED_GROUP_ID = gid;
4415 } else {
4416 if (setrgid(SAVED_GROUP_ID) < 0) rb_sys_fail(0);
4417 SAVED_GROUP_ID = gid;
4418 if (setrgid(gid) < 0) rb_sys_fail(0);
4420 } else if (/* getegid() != gid && */ getgid() == gid) {
4421 if (setegid(gid) < 0) rb_sys_fail(0);
4422 if (setrgid(SAVED_GROUP_ID) < 0) rb_sys_fail(0);
4423 SAVED_GROUP_ID = gid;
4424 if (setrgid(gid) < 0) rb_sys_fail(0);
4425 } else {
4426 errno = EPERM;
4427 rb_sys_fail(0);
4429 #elif defined HAVE_44BSD_SETGID
4430 if (getgid() == gid) {
4431 /* (r,e,s)==(gid,?,?) ==> (gid,gid,gid) */
4432 if (setgid(gid) < 0) rb_sys_fail(0);
4433 SAVED_GROUP_ID = gid;
4434 } else {
4435 errno = EPERM;
4436 rb_sys_fail(0);
4438 #elif defined HAVE_SETEGID
4439 if (getgid() == gid && SAVED_GROUP_ID == gid) {
4440 if (setegid(gid) < 0) rb_sys_fail(0);
4441 } else {
4442 errno = EPERM;
4443 rb_sys_fail(0);
4445 #elif defined HAVE_SETGID
4446 if (getgid() == gid && SAVED_GROUP_ID == gid) {
4447 if (setgid(gid) < 0) rb_sys_fail(0);
4448 } else {
4449 errno = EPERM;
4450 rb_sys_fail(0);
4452 #else
4453 rb_notimplement();
4454 #endif
4456 return id;
4461 * call-seq:
4462 * Process.euid => fixnum
4463 * Process::UID.eid => fixnum
4464 * Process::Sys.geteuid => fixnum
4466 * Returns the effective user ID for this process.
4468 * Process.euid #=> 501
4471 static VALUE
4472 proc_geteuid(VALUE obj)
4474 rb_uid_t euid = geteuid();
4475 return UIDT2NUM(euid);
4480 * call-seq:
4481 * Process.euid= integer
4483 * Sets the effective user ID for this process. Not available on all
4484 * platforms.
4487 static VALUE
4488 proc_seteuid(VALUE obj, VALUE euid)
4490 rb_uid_t uid;
4492 check_uid_switch();
4494 uid = NUM2UIDT(euid);
4495 #if defined(HAVE_SETRESUID) && !defined(__CHECKER__)
4496 if (setresuid(-1, uid, -1) < 0) rb_sys_fail(0);
4497 #elif defined HAVE_SETREUID
4498 if (setreuid(-1, uid) < 0) rb_sys_fail(0);
4499 #elif defined HAVE_SETEUID
4500 if (seteuid(uid) < 0) rb_sys_fail(0);
4501 #elif defined HAVE_SETUID
4502 if (uid == getuid()) {
4503 if (setuid(uid) < 0) rb_sys_fail(0);
4505 else {
4506 rb_notimplement();
4508 #else
4509 rb_notimplement();
4510 #endif
4511 return euid;
4514 static rb_uid_t
4515 rb_seteuid_core(rb_uid_t euid)
4517 rb_uid_t uid;
4519 check_uid_switch();
4521 uid = getuid();
4523 #if defined(HAVE_SETRESUID) && !defined(__CHECKER__)
4524 if (uid != euid) {
4525 if (setresuid(-1,euid,euid) < 0) rb_sys_fail(0);
4526 SAVED_USER_ID = euid;
4527 } else {
4528 if (setresuid(-1,euid,-1) < 0) rb_sys_fail(0);
4530 #elif defined(HAVE_SETREUID) && !defined(OBSOLETE_SETREUID)
4531 if (setreuid(-1, euid) < 0) rb_sys_fail(0);
4532 if (uid != euid) {
4533 if (setreuid(euid,uid) < 0) rb_sys_fail(0);
4534 if (setreuid(uid,euid) < 0) rb_sys_fail(0);
4535 SAVED_USER_ID = euid;
4537 #elif defined HAVE_SETEUID
4538 if (seteuid(euid) < 0) rb_sys_fail(0);
4539 #elif defined HAVE_SETUID
4540 if (geteuid() == 0) rb_sys_fail(0);
4541 if (setuid(euid) < 0) rb_sys_fail(0);
4542 #else
4543 rb_notimplement();
4544 #endif
4545 return euid;
4550 * call-seq:
4551 * Process::UID.grant_privilege(integer) => fixnum
4552 * Process::UID.eid= integer => fixnum
4554 * Set the effective user ID, and if possible, the saved user ID of
4555 * the process to the given _integer_. Returns the new
4556 * effective user ID. Not available on all platforms.
4558 * [Process.uid, Process.euid] #=> [0, 0]
4559 * Process::UID.grant_privilege(31) #=> 31
4560 * [Process.uid, Process.euid] #=> [0, 31]
4563 static VALUE
4564 p_uid_grant_privilege(VALUE obj, VALUE id)
4566 rb_seteuid_core(NUM2UIDT(id));
4567 return id;
4572 * call-seq:
4573 * Process.egid => fixnum
4574 * Process::GID.eid => fixnum
4575 * Process::Sys.geteid => fixnum
4577 * Returns the effective group ID for this process. Not available on
4578 * all platforms.
4580 * Process.egid #=> 500
4583 static VALUE
4584 proc_getegid(VALUE obj)
4586 rb_gid_t egid = getegid();
4588 return GIDT2NUM(egid);
4593 * call-seq:
4594 * Process.egid = fixnum => fixnum
4596 * Sets the effective group ID for this process. Not available on all
4597 * platforms.
4600 static VALUE
4601 proc_setegid(VALUE obj, VALUE egid)
4603 rb_gid_t gid;
4605 check_gid_switch();
4607 gid = NUM2GIDT(egid);
4608 #if defined(HAVE_SETRESGID) && !defined(__CHECKER__)
4609 if (setresgid(-1, gid, -1) < 0) rb_sys_fail(0);
4610 #elif defined HAVE_SETREGID
4611 if (setregid(-1, gid) < 0) rb_sys_fail(0);
4612 #elif defined HAVE_SETEGID
4613 if (setegid(gid) < 0) rb_sys_fail(0);
4614 #elif defined HAVE_SETGID
4615 if (gid == getgid()) {
4616 if (setgid(gid) < 0) rb_sys_fail(0);
4618 else {
4619 rb_notimplement();
4621 #else
4622 rb_notimplement();
4623 #endif
4624 return egid;
4627 static rb_gid_t
4628 rb_setegid_core(rb_gid_t egid)
4630 rb_gid_t gid;
4632 check_gid_switch();
4634 gid = getgid();
4636 #if defined(HAVE_SETRESGID) && !defined(__CHECKER__)
4637 if (gid != egid) {
4638 if (setresgid(-1,egid,egid) < 0) rb_sys_fail(0);
4639 SAVED_GROUP_ID = egid;
4640 } else {
4641 if (setresgid(-1,egid,-1) < 0) rb_sys_fail(0);
4643 #elif defined(HAVE_SETREGID) && !defined(OBSOLETE_SETREGID)
4644 if (setregid(-1, egid) < 0) rb_sys_fail(0);
4645 if (gid != egid) {
4646 if (setregid(egid,gid) < 0) rb_sys_fail(0);
4647 if (setregid(gid,egid) < 0) rb_sys_fail(0);
4648 SAVED_GROUP_ID = egid;
4650 #elif defined HAVE_SETEGID
4651 if (setegid(egid) < 0) rb_sys_fail(0);
4652 #elif defined HAVE_SETGID
4653 if (geteuid() == 0 /* root user */) rb_sys_fail(0);
4654 if (setgid(egid) < 0) rb_sys_fail(0);
4655 #else
4656 rb_notimplement();
4657 #endif
4658 return egid;
4663 * call-seq:
4664 * Process::GID.grant_privilege(integer) => fixnum
4665 * Process::GID.eid = integer => fixnum
4667 * Set the effective group ID, and if possible, the saved group ID of
4668 * the process to the given _integer_. Returns the new
4669 * effective group ID. Not available on all platforms.
4671 * [Process.gid, Process.egid] #=> [0, 0]
4672 * Process::GID.grant_privilege(31) #=> 33
4673 * [Process.gid, Process.egid] #=> [0, 33]
4676 static VALUE
4677 p_gid_grant_privilege(VALUE obj, VALUE id)
4679 rb_setegid_core(NUM2GIDT(id));
4680 return id;
4685 * call-seq:
4686 * Process::UID.re_exchangeable? => true or false
4688 * Returns +true+ if the real and effective user IDs of a
4689 * process may be exchanged on the current platform.
4693 static VALUE
4694 p_uid_exchangeable(void)
4696 #if defined(HAVE_SETRESUID) && !defined(__CHECKER__)
4697 return Qtrue;
4698 #elif defined(HAVE_SETREUID) && !defined(OBSOLETE_SETREUID)
4699 return Qtrue;
4700 #else
4701 return Qfalse;
4702 #endif
4707 * call-seq:
4708 * Process::UID.re_exchange => fixnum
4710 * Exchange real and effective user IDs and return the new effective
4711 * user ID. Not available on all platforms.
4713 * [Process.uid, Process.euid] #=> [0, 31]
4714 * Process::UID.re_exchange #=> 0
4715 * [Process.uid, Process.euid] #=> [31, 0]
4718 static VALUE
4719 p_uid_exchange(VALUE obj)
4721 rb_uid_t uid, euid;
4723 check_uid_switch();
4725 uid = getuid();
4726 euid = geteuid();
4728 #if defined(HAVE_SETRESUID) && !defined(__CHECKER__)
4729 if (setresuid(euid, uid, uid) < 0) rb_sys_fail(0);
4730 SAVED_USER_ID = uid;
4731 #elif defined(HAVE_SETREUID) && !defined(OBSOLETE_SETREUID)
4732 if (setreuid(euid,uid) < 0) rb_sys_fail(0);
4733 SAVED_USER_ID = uid;
4734 #else
4735 rb_notimplement();
4736 #endif
4737 return UIDT2NUM(uid);
4742 * call-seq:
4743 * Process::GID.re_exchangeable? => true or false
4745 * Returns +true+ if the real and effective group IDs of a
4746 * process may be exchanged on the current platform.
4750 static VALUE
4751 p_gid_exchangeable(void)
4753 #if defined(HAVE_SETRESGID) && !defined(__CHECKER__)
4754 return Qtrue;
4755 #elif defined(HAVE_SETREGID) && !defined(OBSOLETE_SETREGID)
4756 return Qtrue;
4757 #else
4758 return Qfalse;
4759 #endif
4764 * call-seq:
4765 * Process::GID.re_exchange => fixnum
4767 * Exchange real and effective group IDs and return the new effective
4768 * group ID. Not available on all platforms.
4770 * [Process.gid, Process.egid] #=> [0, 33]
4771 * Process::GID.re_exchange #=> 0
4772 * [Process.gid, Process.egid] #=> [33, 0]
4775 static VALUE
4776 p_gid_exchange(VALUE obj)
4778 rb_gid_t gid, egid;
4780 check_gid_switch();
4782 gid = getgid();
4783 egid = getegid();
4785 #if defined(HAVE_SETRESGID) && !defined(__CHECKER__)
4786 if (setresgid(egid, gid, gid) < 0) rb_sys_fail(0);
4787 SAVED_GROUP_ID = gid;
4788 #elif defined(HAVE_SETREGID) && !defined(OBSOLETE_SETREGID)
4789 if (setregid(egid,gid) < 0) rb_sys_fail(0);
4790 SAVED_GROUP_ID = gid;
4791 #else
4792 rb_notimplement();
4793 #endif
4794 return GIDT2NUM(gid);
4797 /* [MG] :FIXME: Is this correct? I'm not sure how to phrase this. */
4800 * call-seq:
4801 * Process::UID.sid_available? => true or false
4803 * Returns +true+ if the current platform has saved user
4804 * ID functionality.
4808 static VALUE
4809 p_uid_have_saved_id(void)
4811 #if defined(HAVE_SETRESUID) || defined(HAVE_SETEUID) || defined(_POSIX_SAVED_IDS)
4812 return Qtrue;
4813 #else
4814 return Qfalse;
4815 #endif
4819 #if defined(HAVE_SETRESUID) || defined(HAVE_SETEUID) || defined(_POSIX_SAVED_IDS)
4820 static VALUE
4821 p_uid_sw_ensure(rb_uid_t id)
4823 under_uid_switch = 0;
4824 id = rb_seteuid_core(id);
4825 return UIDT2NUM(id);
4830 * call-seq:
4831 * Process::UID.switch => fixnum
4832 * Process::UID.switch {|| block} => object
4834 * Switch the effective and real user IDs of the current process. If
4835 * a <em>block</em> is given, the user IDs will be switched back
4836 * after the block is executed. Returns the new effective user ID if
4837 * called without a block, and the return value of the block if one
4838 * is given.
4842 static VALUE
4843 p_uid_switch(VALUE obj)
4845 rb_uid_t uid, euid;
4847 check_uid_switch();
4849 uid = getuid();
4850 euid = geteuid();
4852 if (uid != euid) {
4853 proc_seteuid(obj, UIDT2NUM(uid));
4854 if (rb_block_given_p()) {
4855 under_uid_switch = 1;
4856 return rb_ensure(rb_yield, Qnil, p_uid_sw_ensure, SAVED_USER_ID);
4857 } else {
4858 return UIDT2NUM(euid);
4860 } else if (euid != SAVED_USER_ID) {
4861 proc_seteuid(obj, UIDT2NUM(SAVED_USER_ID));
4862 if (rb_block_given_p()) {
4863 under_uid_switch = 1;
4864 return rb_ensure(rb_yield, Qnil, p_uid_sw_ensure, euid);
4865 } else {
4866 return UIDT2NUM(uid);
4868 } else {
4869 errno = EPERM;
4870 rb_sys_fail(0);
4873 #else
4874 static VALUE
4875 p_uid_sw_ensure(VALUE obj)
4877 under_uid_switch = 0;
4878 return p_uid_exchange(obj);
4881 static VALUE
4882 p_uid_switch(VALUE obj)
4884 rb_uid_t uid, euid;
4886 check_uid_switch();
4888 uid = getuid();
4889 euid = geteuid();
4891 if (uid == euid) {
4892 errno = EPERM;
4893 rb_sys_fail(0);
4895 p_uid_exchange(obj);
4896 if (rb_block_given_p()) {
4897 under_uid_switch = 1;
4898 return rb_ensure(rb_yield, Qnil, p_uid_sw_ensure, obj);
4899 } else {
4900 return UIDT2NUM(euid);
4903 #endif
4906 /* [MG] :FIXME: Is this correct? I'm not sure how to phrase this. */
4909 * call-seq:
4910 * Process::GID.sid_available? => true or false
4912 * Returns +true+ if the current platform has saved group
4913 * ID functionality.
4917 static VALUE
4918 p_gid_have_saved_id(void)
4920 #if defined(HAVE_SETRESGID) || defined(HAVE_SETEGID) || defined(_POSIX_SAVED_IDS)
4921 return Qtrue;
4922 #else
4923 return Qfalse;
4924 #endif
4927 #if defined(HAVE_SETRESGID) || defined(HAVE_SETEGID) || defined(_POSIX_SAVED_IDS)
4928 static VALUE
4929 p_gid_sw_ensure(rb_gid_t id)
4931 under_gid_switch = 0;
4932 id = rb_setegid_core(id);
4933 return GIDT2NUM(id);
4938 * call-seq:
4939 * Process::GID.switch => fixnum
4940 * Process::GID.switch {|| block} => object
4942 * Switch the effective and real group IDs of the current process. If
4943 * a <em>block</em> is given, the group IDs will be switched back
4944 * after the block is executed. Returns the new effective group ID if
4945 * called without a block, and the return value of the block if one
4946 * is given.
4950 static VALUE
4951 p_gid_switch(VALUE obj)
4953 int gid, egid;
4955 check_gid_switch();
4957 gid = getgid();
4958 egid = getegid();
4960 if (gid != egid) {
4961 proc_setegid(obj, GIDT2NUM(gid));
4962 if (rb_block_given_p()) {
4963 under_gid_switch = 1;
4964 return rb_ensure(rb_yield, Qnil, p_gid_sw_ensure, SAVED_GROUP_ID);
4965 } else {
4966 return GIDT2NUM(egid);
4968 } else if (egid != SAVED_GROUP_ID) {
4969 proc_setegid(obj, GIDT2NUM(SAVED_GROUP_ID));
4970 if (rb_block_given_p()) {
4971 under_gid_switch = 1;
4972 return rb_ensure(rb_yield, Qnil, p_gid_sw_ensure, egid);
4973 } else {
4974 return GIDT2NUM(gid);
4976 } else {
4977 errno = EPERM;
4978 rb_sys_fail(0);
4981 #else
4982 static VALUE
4983 p_gid_sw_ensure(VALUE obj)
4985 under_gid_switch = 0;
4986 return p_gid_exchange(obj);
4989 static VALUE
4990 p_gid_switch(VALUE obj)
4992 rb_gid_t gid, egid;
4994 check_gid_switch();
4996 gid = getgid();
4997 egid = getegid();
4999 if (gid == egid) {
5000 errno = EPERM;
5001 rb_sys_fail(0);
5003 p_gid_exchange(obj);
5004 if (rb_block_given_p()) {
5005 under_gid_switch = 1;
5006 return rb_ensure(rb_yield, Qnil, p_gid_sw_ensure, obj);
5007 } else {
5008 return GIDT2NUM(egid);
5011 #endif
5015 * call-seq:
5016 * Process.times => aStructTms
5018 * Returns a <code>Tms</code> structure (see <code>Struct::Tms</code>
5019 * on page 388) that contains user and system CPU times for this
5020 * process.
5022 * t = Process.times
5023 * [ t.utime, t.stime ] #=> [0.0, 0.02]
5026 VALUE
5027 rb_proc_times(VALUE obj)
5029 #if defined(HAVE_TIMES) && !defined(__CHECKER__)
5030 const double hertz =
5031 #ifdef HAVE__SC_CLK_TCK
5032 (double)sysconf(_SC_CLK_TCK);
5033 #else
5034 #ifndef HZ
5035 # ifdef CLK_TCK
5036 # define HZ CLK_TCK
5037 # else
5038 # define HZ 60
5039 # endif
5040 #endif /* HZ */
5042 #endif
5043 struct tms buf;
5044 volatile VALUE utime, stime, cutime, sctime;
5046 times(&buf);
5047 return rb_struct_new(rb_cProcessTms,
5048 utime = DOUBLE2NUM(buf.tms_utime / hertz),
5049 stime = DOUBLE2NUM(buf.tms_stime / hertz),
5050 cutime = DOUBLE2NUM(buf.tms_cutime / hertz),
5051 sctime = DOUBLE2NUM(buf.tms_cstime / hertz));
5052 #else
5053 rb_notimplement();
5054 #endif
5057 VALUE rb_mProcess;
5058 VALUE rb_mProcUID;
5059 VALUE rb_mProcGID;
5060 VALUE rb_mProcID_Syscall;
5064 * The <code>Process</code> module is a collection of methods used to
5065 * manipulate processes.
5068 void
5069 Init_process(void)
5071 rb_define_virtual_variable("$?", rb_last_status_get, 0);
5072 rb_define_virtual_variable("$$", get_pid, 0);
5073 rb_define_global_function("exec", rb_f_exec, -1);
5074 rb_define_global_function("fork", rb_f_fork, 0);
5075 rb_define_global_function("exit!", rb_f_exit_bang, -1);
5076 rb_define_global_function("system", rb_f_system, -1);
5077 rb_define_global_function("spawn", rb_f_spawn, -1);
5078 rb_define_global_function("sleep", rb_f_sleep, -1);
5079 rb_define_global_function("exit", rb_f_exit, -1);
5080 rb_define_global_function("abort", rb_f_abort, -1);
5082 rb_mProcess = rb_define_module("Process");
5084 #ifdef WNOHANG
5085 rb_define_const(rb_mProcess, "WNOHANG", INT2FIX(WNOHANG));
5086 #else
5087 rb_define_const(rb_mProcess, "WNOHANG", INT2FIX(0));
5088 #endif
5089 #ifdef WUNTRACED
5090 rb_define_const(rb_mProcess, "WUNTRACED", INT2FIX(WUNTRACED));
5091 #else
5092 rb_define_const(rb_mProcess, "WUNTRACED", INT2FIX(0));
5093 #endif
5095 rb_define_singleton_method(rb_mProcess, "exec", rb_f_exec, -1);
5096 rb_define_singleton_method(rb_mProcess, "fork", rb_f_fork, 0);
5097 rb_define_singleton_method(rb_mProcess, "spawn", rb_f_spawn, -1);
5098 rb_define_singleton_method(rb_mProcess, "exit!", rb_f_exit_bang, -1);
5099 rb_define_singleton_method(rb_mProcess, "exit", rb_f_exit, -1);
5100 rb_define_singleton_method(rb_mProcess, "abort", rb_f_abort, -1);
5102 rb_define_module_function(rb_mProcess, "kill", rb_f_kill, -1); /* in signal.c */
5103 rb_define_module_function(rb_mProcess, "wait", proc_wait, -1);
5104 rb_define_module_function(rb_mProcess, "wait2", proc_wait2, -1);
5105 rb_define_module_function(rb_mProcess, "waitpid", proc_wait, -1);
5106 rb_define_module_function(rb_mProcess, "waitpid2", proc_wait2, -1);
5107 rb_define_module_function(rb_mProcess, "waitall", proc_waitall, 0);
5108 rb_define_module_function(rb_mProcess, "detach", proc_detach, 1);
5110 rb_cProcessStatus = rb_define_class_under(rb_mProcess, "Status", rb_cObject);
5111 rb_undef_method(CLASS_OF(rb_cProcessStatus), "new");
5113 rb_define_method(rb_cProcessStatus, "==", pst_equal, 1);
5114 rb_define_method(rb_cProcessStatus, "&", pst_bitand, 1);
5115 rb_define_method(rb_cProcessStatus, ">>", pst_rshift, 1);
5116 rb_define_method(rb_cProcessStatus, "to_i", pst_to_i, 0);
5117 rb_define_method(rb_cProcessStatus, "to_s", pst_to_s, 0);
5118 rb_define_method(rb_cProcessStatus, "inspect", pst_inspect, 0);
5120 rb_define_method(rb_cProcessStatus, "pid", pst_pid, 0);
5122 rb_define_method(rb_cProcessStatus, "stopped?", pst_wifstopped, 0);
5123 rb_define_method(rb_cProcessStatus, "stopsig", pst_wstopsig, 0);
5124 rb_define_method(rb_cProcessStatus, "signaled?", pst_wifsignaled, 0);
5125 rb_define_method(rb_cProcessStatus, "termsig", pst_wtermsig, 0);
5126 rb_define_method(rb_cProcessStatus, "exited?", pst_wifexited, 0);
5127 rb_define_method(rb_cProcessStatus, "exitstatus", pst_wexitstatus, 0);
5128 rb_define_method(rb_cProcessStatus, "success?", pst_success_p, 0);
5129 rb_define_method(rb_cProcessStatus, "coredump?", pst_wcoredump, 0);
5131 rb_define_module_function(rb_mProcess, "pid", get_pid, 0);
5132 rb_define_module_function(rb_mProcess, "ppid", get_ppid, 0);
5134 rb_define_module_function(rb_mProcess, "getpgrp", proc_getpgrp, 0);
5135 rb_define_module_function(rb_mProcess, "setpgrp", proc_setpgrp, 0);
5136 rb_define_module_function(rb_mProcess, "getpgid", proc_getpgid, 1);
5137 rb_define_module_function(rb_mProcess, "setpgid", proc_setpgid, 2);
5139 rb_define_module_function(rb_mProcess, "setsid", proc_setsid, 0);
5141 rb_define_module_function(rb_mProcess, "getpriority", proc_getpriority, 2);
5142 rb_define_module_function(rb_mProcess, "setpriority", proc_setpriority, 3);
5144 #ifdef HAVE_GETPRIORITY
5145 rb_define_const(rb_mProcess, "PRIO_PROCESS", INT2FIX(PRIO_PROCESS));
5146 rb_define_const(rb_mProcess, "PRIO_PGRP", INT2FIX(PRIO_PGRP));
5147 rb_define_const(rb_mProcess, "PRIO_USER", INT2FIX(PRIO_USER));
5148 #endif
5150 rb_define_module_function(rb_mProcess, "getrlimit", proc_getrlimit, 1);
5151 rb_define_module_function(rb_mProcess, "setrlimit", proc_setrlimit, -1);
5152 #ifdef RLIM2NUM
5154 VALUE inf = RLIM2NUM(RLIM_INFINITY);
5155 #ifdef RLIM_SAVED_MAX
5156 VALUE v = RLIM_INFINITY == RLIM_SAVED_MAX ? inf : RLIM2NUM(RLIM_SAVED_MAX);
5157 rb_define_const(rb_mProcess, "RLIM_SAVED_MAX", v);
5158 #endif
5159 rb_define_const(rb_mProcess, "RLIM_INFINITY", inf);
5160 #ifdef RLIM_SAVED_CUR
5161 v = RLIM_INFINITY == RLIM_SAVED_CUR ? inf : RLIM2NUM(RLIM_SAVED_CUR);
5162 rb_define_const(rb_mProcess, "RLIM_SAVED_CUR", v);
5163 #endif
5165 #ifdef RLIMIT_CORE
5166 rb_define_const(rb_mProcess, "RLIMIT_CORE", INT2FIX(RLIMIT_CORE));
5167 #endif
5168 #ifdef RLIMIT_CPU
5169 rb_define_const(rb_mProcess, "RLIMIT_CPU", INT2FIX(RLIMIT_CPU));
5170 #endif
5171 #ifdef RLIMIT_DATA
5172 rb_define_const(rb_mProcess, "RLIMIT_DATA", INT2FIX(RLIMIT_DATA));
5173 #endif
5174 #ifdef RLIMIT_FSIZE
5175 rb_define_const(rb_mProcess, "RLIMIT_FSIZE", INT2FIX(RLIMIT_FSIZE));
5176 #endif
5177 #ifdef RLIMIT_NOFILE
5178 rb_define_const(rb_mProcess, "RLIMIT_NOFILE", INT2FIX(RLIMIT_NOFILE));
5179 #endif
5180 #ifdef RLIMIT_STACK
5181 rb_define_const(rb_mProcess, "RLIMIT_STACK", INT2FIX(RLIMIT_STACK));
5182 #endif
5183 #ifdef RLIMIT_AS
5184 rb_define_const(rb_mProcess, "RLIMIT_AS", INT2FIX(RLIMIT_AS));
5185 #endif
5186 #ifdef RLIMIT_MEMLOCK
5187 rb_define_const(rb_mProcess, "RLIMIT_MEMLOCK", INT2FIX(RLIMIT_MEMLOCK));
5188 #endif
5189 #ifdef RLIMIT_NPROC
5190 rb_define_const(rb_mProcess, "RLIMIT_NPROC", INT2FIX(RLIMIT_NPROC));
5191 #endif
5192 #ifdef RLIMIT_RSS
5193 rb_define_const(rb_mProcess, "RLIMIT_RSS", INT2FIX(RLIMIT_RSS));
5194 #endif
5195 #ifdef RLIMIT_SBSIZE
5196 rb_define_const(rb_mProcess, "RLIMIT_SBSIZE", INT2FIX(RLIMIT_SBSIZE));
5197 #endif
5198 #endif
5200 rb_define_module_function(rb_mProcess, "uid", proc_getuid, 0);
5201 rb_define_module_function(rb_mProcess, "uid=", proc_setuid, 1);
5202 rb_define_module_function(rb_mProcess, "gid", proc_getgid, 0);
5203 rb_define_module_function(rb_mProcess, "gid=", proc_setgid, 1);
5204 rb_define_module_function(rb_mProcess, "euid", proc_geteuid, 0);
5205 rb_define_module_function(rb_mProcess, "euid=", proc_seteuid, 1);
5206 rb_define_module_function(rb_mProcess, "egid", proc_getegid, 0);
5207 rb_define_module_function(rb_mProcess, "egid=", proc_setegid, 1);
5208 rb_define_module_function(rb_mProcess, "initgroups", proc_initgroups, 2);
5209 rb_define_module_function(rb_mProcess, "groups", proc_getgroups, 0);
5210 rb_define_module_function(rb_mProcess, "groups=", proc_setgroups, 1);
5211 rb_define_module_function(rb_mProcess, "maxgroups", proc_getmaxgroups, 0);
5212 rb_define_module_function(rb_mProcess, "maxgroups=", proc_setmaxgroups, 1);
5214 rb_define_module_function(rb_mProcess, "daemon", proc_daemon, -1);
5216 rb_define_module_function(rb_mProcess, "times", rb_proc_times, 0);
5218 #if defined(HAVE_TIMES) || defined(_WIN32)
5219 rb_cProcessTms = rb_struct_define("Tms", "utime", "stime", "cutime", "cstime", NULL);
5220 #endif
5222 SAVED_USER_ID = geteuid();
5223 SAVED_GROUP_ID = getegid();
5225 rb_mProcUID = rb_define_module_under(rb_mProcess, "UID");
5226 rb_mProcGID = rb_define_module_under(rb_mProcess, "GID");
5228 rb_define_module_function(rb_mProcUID, "rid", proc_getuid, 0);
5229 rb_define_module_function(rb_mProcGID, "rid", proc_getgid, 0);
5230 rb_define_module_function(rb_mProcUID, "eid", proc_geteuid, 0);
5231 rb_define_module_function(rb_mProcGID, "eid", proc_getegid, 0);
5232 rb_define_module_function(rb_mProcUID, "change_privilege", p_uid_change_privilege, 1);
5233 rb_define_module_function(rb_mProcGID, "change_privilege", p_gid_change_privilege, 1);
5234 rb_define_module_function(rb_mProcUID, "grant_privilege", p_uid_grant_privilege, 1);
5235 rb_define_module_function(rb_mProcGID, "grant_privilege", p_gid_grant_privilege, 1);
5236 rb_define_alias(rb_singleton_class(rb_mProcUID), "eid=", "grant_privilege");
5237 rb_define_alias(rb_singleton_class(rb_mProcGID), "eid=", "grant_privilege");
5238 rb_define_module_function(rb_mProcUID, "re_exchange", p_uid_exchange, 0);
5239 rb_define_module_function(rb_mProcGID, "re_exchange", p_gid_exchange, 0);
5240 rb_define_module_function(rb_mProcUID, "re_exchangeable?", p_uid_exchangeable, 0);
5241 rb_define_module_function(rb_mProcGID, "re_exchangeable?", p_gid_exchangeable, 0);
5242 rb_define_module_function(rb_mProcUID, "sid_available?", p_uid_have_saved_id, 0);
5243 rb_define_module_function(rb_mProcGID, "sid_available?", p_gid_have_saved_id, 0);
5244 rb_define_module_function(rb_mProcUID, "switch", p_uid_switch, 0);
5245 rb_define_module_function(rb_mProcGID, "switch", p_gid_switch, 0);
5247 rb_mProcID_Syscall = rb_define_module_under(rb_mProcess, "Sys");
5249 rb_define_module_function(rb_mProcID_Syscall, "getuid", proc_getuid, 0);
5250 rb_define_module_function(rb_mProcID_Syscall, "geteuid", proc_geteuid, 0);
5251 rb_define_module_function(rb_mProcID_Syscall, "getgid", proc_getgid, 0);
5252 rb_define_module_function(rb_mProcID_Syscall, "getegid", proc_getegid, 0);
5254 rb_define_module_function(rb_mProcID_Syscall, "setuid", p_sys_setuid, 1);
5255 rb_define_module_function(rb_mProcID_Syscall, "setgid", p_sys_setgid, 1);
5257 rb_define_module_function(rb_mProcID_Syscall, "setruid", p_sys_setruid, 1);
5258 rb_define_module_function(rb_mProcID_Syscall, "setrgid", p_sys_setrgid, 1);
5260 rb_define_module_function(rb_mProcID_Syscall, "seteuid", p_sys_seteuid, 1);
5261 rb_define_module_function(rb_mProcID_Syscall, "setegid", p_sys_setegid, 1);
5263 rb_define_module_function(rb_mProcID_Syscall, "setreuid", p_sys_setreuid, 2);
5264 rb_define_module_function(rb_mProcID_Syscall, "setregid", p_sys_setregid, 2);
5266 rb_define_module_function(rb_mProcID_Syscall, "setresuid", p_sys_setresuid, 3);
5267 rb_define_module_function(rb_mProcID_Syscall, "setresgid", p_sys_setresgid, 3);
5268 rb_define_module_function(rb_mProcID_Syscall, "issetugid", p_sys_issetugid, 0);