1 /**********************************************************************
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"
17 #include "ruby/util.h"
40 #define EXIT_SUCCESS 0
43 #define EXIT_FAILURE 1
46 struct timeval
rb_time_interval(VALUE
);
48 #ifdef HAVE_SYS_WAIT_H
49 # include <sys/wait.h>
51 #ifdef HAVE_SYS_RESOURCE_H
52 # include <sys/resource.h>
54 #ifdef HAVE_SYS_PARAM_H
55 # include <sys/param.h>
58 # define MAXPATHLEN 1024
68 #ifdef HAVE_SYS_TIMES_H
69 #include <sys/times.h>
76 #if defined(HAVE_TIMES) || defined(_WIN32)
77 static VALUE rb_cProcessTms
;
81 #define WIFEXITED(w) (((w) & 0xff) == 0)
84 #define WIFSIGNALED(w) (((w) & 0x7f) > 0 && (((w) & 0x7f) < 0x7f))
87 #define WIFSTOPPED(w) (((w) & 0xff) == 0x7f)
90 #define WEXITSTATUS(w) (((w) >> 8) & 0xff)
93 #define WTERMSIG(w) ((w) & 0x7f)
96 #define WSTOPSIG WEXITSTATUS
99 #if defined(__APPLE__) && ( defined(__MACH__) || defined(__DARWIN__) ) && !defined(__MacOS_X__)
100 #define __MacOS_X__ 1
103 #if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__bsdi__)
104 #define HAVE_44BSD_SETUID 1
105 #define HAVE_44BSD_SETGID 1
113 #ifdef BROKEN_SETREUID
114 #define setreuid ruby_setreuid
116 #ifdef BROKEN_SETREGID
117 #define setregid ruby_setregid
120 #if defined(HAVE_44BSD_SETUID) || defined(__MacOS_X__)
121 #if !defined(USE_SETREUID) && !defined(BROKEN_SETREUID)
122 #define OBSOLETE_SETREUID 1
124 #if !defined(USE_SETREGID) && !defined(BROKEN_SETREGID)
125 #define OBSOLETE_SETREGID 1
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)
140 #define preserving_errno(stmts) \
141 do {int saved_errno = errno; stmts; errno = saved_errno;} while (0)
146 * Process.pid => fixnum
148 * Returns the process id of this process. Not available on all
151 * Process.pid #=> 27415
158 return PIDT2NUM(getpid());
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}" }
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
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
;
219 rb_last_status_get(void)
221 return GET_THREAD()->last_status
;
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
));
234 rb_last_status_clear(void)
236 GET_THREAD()->last_status
= Qnil
;
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"
255 return rb_iv_get(st
, "status");
258 #define PST2INT(st) NUM2INT(pst_to_i(st))
264 * Returns the process ID that this status object represents.
266 * fork { exit } #=> 26569
267 * Process.wait #=> 26569
274 return rb_iv_get(st
, "pid");
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
);
285 rb_str_catf(str
, " stopped SIG%s (signal %d)", signame
, stopsig
);
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
);
295 rb_str_catf(str
, " SIG%s (signal %d)", signame
, termsig
);
298 rb_str_catf(str
, " signal %d", termsig
);
301 if (WIFEXITED(status
)) {
302 rb_str_catf(str
, " exit %d", WEXITSTATUS(status
));
305 if (WCOREDUMP(status
)) {
306 rb_str_cat2(str
, " (core dumped)");
314 * stat.to_s => string
316 * Show pid and exit status as a string.
326 pid
= NUM2LONG(pst_pid(st
));
327 status
= PST2INT(st
);
329 str
= rb_str_buf_new(0);
330 pst_message(str
, pid
, status
);
337 * stat.inspect => string
339 * Override the inspection method.
343 pst_inspect(VALUE st
)
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
, ">");
361 * stat == other => true or false
363 * Returns +true+ if the integer value of _stat_
364 * equals <em>other</em>.
368 pst_equal(VALUE st1
, VALUE st2
)
370 if (st1
== st2
) return Qtrue
;
371 return rb_equal(pst_to_i(st1
), st2
);
377 * stat & num => fixnum
379 * Logical AND of the bits in _stat_ with <em>num</em>.
383 * sprintf('%04x', $?.to_i) #=> "3700"
384 * sprintf('%04x', $? & 0x1e00) #=> "1600"
388 pst_bitand(VALUE st1
, VALUE st2
)
390 int status
= PST2INT(st1
) & NUM2INT(st2
);
392 return INT2NUM(status
);
398 * stat >> num => fixnum
400 * Shift the bits in _stat_ right <em>num</em> places.
402 * fork { exit 99 } #=> 26563
403 * Process.wait #=> 26563
409 pst_rshift(VALUE st1
, VALUE st2
)
411 int status
= PST2INT(st1
) >> NUM2INT(st2
);
413 return INT2NUM(status
);
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.
427 pst_wifstopped(VALUE st
)
429 int status
= PST2INT(st
);
431 if (WIFSTOPPED(status
))
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).
447 pst_wstopsig(VALUE st
)
449 int status
= PST2INT(st
);
451 if (WIFSTOPPED(status
))
452 return INT2NUM(WSTOPSIG(status
));
459 * stat.signaled? => true or false
461 * Returns +true+ if _stat_ terminated because of
462 * an uncaught signal.
466 pst_wifsignaled(VALUE st
)
468 int status
= PST2INT(st
);
470 if (WIFSIGNALED(status
))
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
487 pst_wtermsig(VALUE st
)
489 int status
= PST2INT(st
);
491 if (WIFSIGNALED(status
))
492 return INT2NUM(WTERMSIG(status
));
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
507 pst_wifexited(VALUE st
)
509 int status
= PST2INT(st
);
511 if (WIFEXITED(status
))
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
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
538 pst_wexitstatus(VALUE st
)
540 int status
= PST2INT(st
);
542 if (WIFEXITED(status
))
543 return INT2NUM(WEXITSTATUS(status
));
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+.
557 pst_success_p(VALUE st
)
559 int status
= PST2INT(st
);
561 if (!WIFEXITED(status
))
563 return WEXITSTATUS(status
) == EXIT_SUCCESS
? Qtrue
: Qfalse
;
569 * stat.coredump? => true or false
571 * Returns +true+ if _stat_ generated a coredump
572 * when it terminated. Not available on all platforms.
576 pst_wcoredump(VALUE st
)
579 int status
= PST2INT(st
);
581 if (WCOREDUMP(status
))
590 #if !defined(HAVE_WAITPID) && !defined(HAVE_WAIT4)
592 static st_table
*pid_tbl
;
602 rb_waitpid_blocking(void *data
)
606 struct waitpid_arg
*arg
= data
;
610 #if defined NO_WAITPID
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
);
618 return (VALUE
)result
;
622 rb_waitpid(rb_pid_t pid
, int *st
, int flags
)
626 struct waitpid_arg arg
;
631 result
= (rb_pid_t
)rb_thread_blocking_region(rb_waitpid_blocking
, &arg
,
635 if (errno
== EINTR
) {
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
);
650 rb_raise(rb_eArgError
, "can't do waitpid with flags");
654 result
= (rb_pid_t
)rb_thread_blocking_region(rb_waitpid_blocking
,
657 if (errno
== EINTR
) {
658 rb_thread_schedule();
667 pid_tbl
= st_init_numtable();
668 st_insert(pid_tbl
, pid
, (st_data_t
)st
);
669 if (!rb_thread_alone()) rb_thread_schedule();
673 rb_last_status_set(*st
, result
);
685 wait_each(rb_pid_t pid
, int status
, struct wait_data
*data
)
687 if (data
->status
!= -1) return ST_STOP
;
690 data
->status
= status
;
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());
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
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.
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
734 * -1:: Waits for any child process (the default if no _pid_ is
737 * < -1:: Waits for any child whose process group ID equals the absolute
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.
750 * fork { exit 99 } #=> 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
763 proc_wait(int argc
, VALUE
*argv
)
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)
784 rb_last_status_clear();
787 return PIDT2NUM(pid
);
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
802 * Process.fork { exit 99 } #=> 27437
803 * pid, status = Process.wait2
805 * status.exitstatus #=> 99
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());
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
832 * [[27434, #<Process::Status: pid=27434,exited(0)>],
833 * [27433, #<Process::Status: pid=27433,exited(1)>],
834 * [27432, #<Process::Status: pid=27432,exited(2)>]]
845 result
= rb_ary_new();
848 st_foreach(pid_tbl
, waitall_each
, result
);
851 rb_last_status_clear();
858 pid
= rb_waitpid(-1, &status
, 0);
864 if (errno
== EINTR
) {
865 rb_thread_schedule();
872 rb_last_status_set(status
, pid
);
874 rb_ary_push(result
, rb_assoc_new(PIDT2NUM(pid
), rb_last_status_get()));
883 CONST_ID(pid
, "pid");
888 detach_process_pid(VALUE thread
)
890 return rb_thread_local_aref(thread
, id_pid());
894 detach_process_watcher(void *arg
)
896 rb_pid_t cpid
, pid
= (rb_pid_t
)(VALUE
)arg
;
899 while ((cpid
= rb_waitpid(pid
, &status
, 0)) == 0) {
900 /* wait while alive */
902 return rb_last_status_get();
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);
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
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)
941 * system("ps -ho pid,state -p #{p1}")
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 }
953 * Process.waitpid(p2)
955 * system("ps -ho pid,state -p #{p1}")
957 * <em>(produces no output)</em>
961 proc_detach(VALUE obj
, VALUE pid
)
964 return rb_detach_process(NUM2PIDT(pid
));
967 #ifndef HAVE_STRING_H
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())
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
);
993 proc_exec_v(char **argv
, const char *prog
)
995 char fbuf
[MAXPATHLEN
];
999 prog
= dln_find_exe_r(prog
, 0, fbuf
, sizeof(fbuf
));
1005 #if (defined(MSDOS) && !defined(DJGPP)) || defined(__human68k__) || defined(__EMX__) || defined(OS2)
1007 #if defined(__human68k__)
1008 #define COMMAND "command.x"
1010 #if defined(__EMX__) || defined(OS2) /* OS/2 emx */
1011 #define COMMAND "cmd.exe"
1013 #if (defined(MSDOS) && !defined(DJGPP))
1014 #define COMMAND "command.com"
1018 if ((extension
= strrchr(prog
, '.')) != NULL
&& STRCASECMP(extension
, ".bat") == 0) {
1023 for (n
= 0; argv
[n
]; n
++)
1025 new_argv
= ALLOCA_N(char*, n
+ 2);
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
++)
1032 new_argv
[0] = COMMAND
;
1034 prog
= dln_find_exe_r(argv
[0], 0, fbuf
, sizeof(fbuf
));
1041 #endif /* MSDOS or __human68k__ or __EMX__ */
1044 preserving_errno(after_exec());
1049 rb_proc_exec_n(int argc
, VALUE
*argv
, const char *prog
)
1054 args
= ALLOCA_N(char*, argc
+1);
1055 for (i
=0; i
<argc
; i
++) {
1056 args
[i
] = RSTRING_PTR(argv
[i
]);
1060 return proc_exec_v(args
, prog
);
1066 rb_proc_exec(const char *str
)
1069 const char *s
= str
;
1074 while (*str
&& ISSPACE(*str
))
1079 rb_w32_spawn(P_OVERLAY
, (char *)str
, 0);
1082 for (s
=str
; *s
; s
++) {
1084 const char *p
, *nl
= NULL
;
1085 for (p
= s
; ISSPACE(*p
); p
++) {
1086 if (*p
== '\n') nl
= p
;
1091 if (*s
!= ' ' && !ISALPHA(*s
) && strchr("*?{}[]<>()~&|\\$;'`\"\n",*s
)) {
1095 status
= system(str
);
1099 #elif defined(__human68k__) || defined(__CYGWIN32__) || defined(__EMX__)
1100 char fbuf
[MAXPATHLEN
];
1101 char *shell
= dln_find_exe_r("sh", 0, fbuf
, sizeof(fbuf
));
1105 execl(shell
, "sh", "-c", str
, (char *) NULL
);
1107 status
= system(str
);
1113 execl("/bin/sh", "sh", "-c", str
, (char *)NULL
);
1114 preserving_errno(after_exec());
1119 a
= argv
= ALLOCA_N(char*, (s
-str
)/2+2);
1120 ss
= ALLOCA_N(char, s
-str
+1);
1121 memcpy(ss
, str
, s
-str
);
1123 if ((*a
++ = strtok(ss
, " \t")) != 0) {
1124 while ((t
= strtok(NULL
, " \t")) != 0) {
1130 return proc_exec_v(argv
, 0);
1138 #define HAVE_SPAWNV 1
1141 #if !defined(HAVE_FORK) && defined(HAVE_SPAWNV)
1143 #define proc_spawn_v(argv, prog) rb_w32_aspawn(P_NOWAIT, prog, argv)
1146 proc_spawn_v(char **argv
, char *prog
)
1148 char fbuf
[MAXPATHLEN
];
1155 prog
= dln_find_exe_r(prog
, 0, fbuf
, sizeof(fbuf
));
1159 #if defined(__human68k__)
1160 if ((extension
= strrchr(prog
, '.')) != NULL
&& STRCASECMP(extension
, ".bat") == 0) {
1165 for (n
= 0; argv
[n
]; n
++)
1167 new_argv
= ALLOCA_N(char*, n
+ 2);
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
++)
1174 new_argv
[0] = COMMAND
;
1176 prog
= dln_find_exe_r(argv
[0], 0, fbuf
, sizeof(fbuf
));
1184 status
= spawnv(P_WAIT
, prog
, argv
);
1185 rb_last_status_set(status
== -1 ? 127 : status
, 0);
1192 proc_spawn_n(int argc
, VALUE
*argv
, VALUE prog
)
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;
1203 return proc_spawn_v(args
, prog
? RSTRING_PTR(prog
) : 0);
1208 #define proc_spawn(str) rb_w32_spawn(P_NOWAIT, str, 0)
1211 proc_spawn(char *str
)
1213 char fbuf
[MAXPATHLEN
];
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
));
1222 status
= shell
?spawnl(P_WAIT
,shell
,"sh","-c",str
,(char*)NULL
):system(str
);
1223 rb_last_status_set(status
== -1 ? 127 : status
, 0);
1228 a
= argv
= ALLOCA_N(char*, (s
- str
) / 2 + 2);
1229 s
= ALLOCA_N(char, s
- str
+ 1);
1231 if (*a
++ = strtok(s
, " \t")) {
1232 while (t
= strtok(NULL
, " \t"))
1236 return argv
[0] ? proc_spawn_v(argv
, 0) : -1;
1244 RBASIC(obj
)->klass
= 0;
1251 EXEC_OPTION_UNSETENV_OTHERS
,
1258 EXEC_OPTION_CLOSE_OTHERS
1262 check_exec_redirect_fd(VALUE v
)
1269 else if (!NIL_P(tmp
= rb_check_convert_type(v
, T_FILE
, "IO", "to_io"))) {
1271 GetOpenFile(tmp
, fptr
);
1272 if (fptr
->tied_io_for_writing
)
1273 rb_raise(rb_eArgError
, "duplex IO redirection");
1277 rb_raise(rb_eArgError
, "wrong exec redirect");
1280 rb_raise(rb_eArgError
, "negative file descriptor");
1286 check_exec_redirect(VALUE key
, VALUE val
, VALUE options
)
1290 VALUE path
, flags
, perm
;
1293 switch (TYPE(val
)) {
1296 if (id
== rb_intern("close")) {
1297 index
= EXEC_OPTION_CLOSE
;
1301 rb_raise(rb_eArgError
, "wrong exec redirect symbol: %s",
1307 val
= check_exec_redirect_fd(val
);
1310 index
= EXEC_OPTION_DUP2
;
1315 index
= EXEC_OPTION_OPEN
;
1316 path
= rb_ary_entry(val
, 0);
1317 FilePathValue(path
);
1318 flags
= rb_ary_entry(val
, 1);
1320 flags
= INT2NUM(O_RDONLY
);
1321 else if (TYPE(flags
) == T_STRING
)
1322 flags
= INT2NUM(rb_io_mode_modenum(StringValueCStr(flags
)));
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
)),
1332 index
= EXEC_OPTION_OPEN
;
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
);
1339 flags
= INT2NUM(O_RDONLY
);
1340 perm
= INT2FIX(0644);
1341 param
= hide_obj(rb_ary_new3(3, hide_obj(rb_str_dup(path
)),
1346 rb_raise(rb_eArgError
, "wrong exec redirect action");
1349 ary
= rb_ary_entry(options
, index
);
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
)));
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
)));
1370 static int rlimit_type_by_lname(const char *name
);
1374 rb_exec_arg_addopt(struct rb_exec_arg
*e
, VALUE key
, VALUE val
)
1376 VALUE options
= e
->options
;
1384 switch (TYPE(key
)) {
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");
1394 else if (val
== Qtrue
)
1397 pid_t pgroup
= NUM2PIDT(val
);
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
);
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
;
1413 ary
= hide_obj(rb_ary_new());
1414 rb_ary_store(options
, EXEC_OPTION_RLIMIT
, ary
);
1416 tmp
= rb_check_array_type(val
);
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));
1425 rb_raise(rb_eArgError
, "wrong exec rlimit option");
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
);
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");
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")) {
1469 else if (id
== rb_intern("out")) {
1473 else if (id
== rb_intern("err")) {
1478 rb_raise(rb_eArgError
, "wrong exec option symbol: %s",
1487 check_exec_redirect(key
, val
, options
);
1491 rb_raise(rb_eArgError
, "wrong exec option");
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
);
1507 check_exec_fds(VALUE options
)
1509 VALUE h
= rb_hash_new();
1514 for (index
= EXEC_OPTION_DUP2
; index
<= EXEC_OPTION_OPEN
; index
++) {
1515 ary
= rb_ary_entry(options
, index
);
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
);
1527 if (index
== EXEC_OPTION_DUP2
) {
1528 fd
= FIX2INT(RARRAY_PTR(elt
)[1]);
1534 if (rb_ary_entry(options
, EXEC_OPTION_CLOSE_OTHERS
) != Qfalse
) {
1535 rb_ary_store(options
, EXEC_OPTION_CLOSE_OTHERS
, INT2FIX(maxhint
));
1541 rb_check_exec_options(VALUE opthash
, struct rb_exec_arg
*e
)
1543 if (RHASH_EMPTY_P(opthash
))
1545 st_foreach(RHASH_TBL(opthash
), check_exec_options_i
, (st_data_t
)e
);
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
;
1556 k
= StringValueCStr(key
);
1558 rb_raise(rb_eArgError
, "environment name contains a equal : %s", k
);
1561 StringValueCStr(val
);
1563 rb_ary_push(env
, hide_obj(rb_assoc_new(key
, val
)));
1569 rb_check_exec_env(VALUE hash
)
1573 env
= hide_obj(rb_ary_new());
1574 st_foreach(RHASH_TBL(hash
), check_exec_env_i
, (st_data_t
)env
);
1580 rb_check_argv(int argc
, VALUE
*argv
)
1584 const char *name
= 0;
1587 rb_raise(rb_eArgError
, "wrong number of arguments");
1591 tmp
= rb_check_array_type(argv
[0]);
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]));
1613 rb_exec_getargs(int *argc_p
, VALUE
**argv_p
, int accept_shell
, VALUE
*env_ret
, VALUE
*opthash_ret
, struct rb_exec_arg
*e
)
1618 hash
= rb_check_convert_type((*argv_p
)[*argc_p
-1], T_HASH
, "Hash", "to_hash");
1620 *opthash_ret
= hash
;
1626 hash
= rb_check_convert_type((*argv_p
)[0], T_HASH
, "Hash", "to_hash");
1633 prog
= rb_check_argv(*argc_p
, *argv_p
);
1635 prog
= (*argv_p
)[0];
1636 if (accept_shell
&& *argc_p
== 1) {
1645 rb_exec_fillarg(VALUE prog
, int argc
, VALUE
*argv
, VALUE env
, VALUE opthash
, struct rb_exec_arg
*e
)
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
);
1656 env
= rb_check_exec_env(env
);
1657 rb_ary_store(options
, EXEC_OPTION_ENV
, env
);
1662 e
->prog
= prog
? RSTRING_PTR(prog
) : 0;
1666 rb_exec_arg_init(int argc
, VALUE
*argv
, int accept_shell
, struct rb_exec_arg
*e
)
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
);
1676 rb_exec_arg_fixup(struct rb_exec_arg
*e
)
1678 e
->redirect_fds
= check_exec_fds(e
->options
);
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
1709 * exec "echo", "*" # echoes an asterisk
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
);
1724 rb_sys_fail(earg
.prog
);
1725 return Qnil
; /* dummy */
1728 /*#define DEBUG_REDIRECT*/
1729 #if defined(DEBUG_REDIRECT)
1734 ttyprintf(const char *fmt
, ...)
1739 tty
= fopen("/dev/tty", "w");
1744 vfprintf(tty
, fmt
, ap
);
1751 redirect_dup(int oldfd
)
1755 ttyprintf("dup(%d) => %d\n", oldfd
, ret
);
1760 redirect_dup2(int oldfd
, int newfd
)
1763 ret
= dup2(oldfd
, newfd
);
1764 ttyprintf("dup2(%d, %d)\n", oldfd
, newfd
);
1769 redirect_close(int fd
)
1773 ttyprintf("close(%d)\n", fd
);
1778 redirect_open(const char *pathname
, int flags
, mode_t perm
)
1781 ret
= open(pathname
, flags
, perm
);
1782 ttyprintf("open(\"%s\", 0x%x, 0%o) => %d\n", pathname
, flags
, perm
, ret
);
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)
1794 save_redirect_fd(int fd
, VALUE save
)
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
);
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
)));
1820 save_env_i(VALUE i
, VALUE ary
, int argc
, VALUE
*argv
)
1822 rb_ary_push(ary
, hide_obj(rb_ary_dup(argv
[0])));
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"));
1832 VALUE ary
= hide_obj(rb_ary_new());
1833 rb_block_call(env
, rb_intern("each"), 0, 0, save_env_i
,
1835 rb_ary_store(save
, EXEC_OPTION_ENV
, ary
);
1837 rb_ary_store(save
, EXEC_OPTION_UNSETENV_OTHERS
, Qtrue
);
1842 intcmp(const void *a
, const void *b
)
1844 return *(int*)a
- *(int*)b
;
1848 run_exec_dup2(VALUE ary
, VALUE save
)
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
;
1879 found
= bsearch(&key
, pairs
, n
, sizeof(struct fd_pair
), intcmp
);
1880 pairs
[i
].num_newer
= 0;
1882 while (pairs
< found
&& (found
-1)->oldfd
== newfd
)
1884 while (found
< pairs
+n
&& found
->oldfd
== newfd
) {
1885 pairs
[i
].num_newer
++;
1886 found
->older_index
= i
;
1892 /* non-cyclic redirection: O(n) */
1893 for (i
= 0; i
< n
; i
++) {
1895 while (j
!= -1 && pairs
[j
].oldfd
!= -1 && pairs
[j
].num_newer
== 0) {
1896 if (save_redirect_fd(pairs
[j
].newfd
, save
) < 0)
1898 ret
= redirect_dup2(pairs
[j
].oldfd
, pairs
[j
].newfd
);
1901 pairs
[j
].oldfd
= -1;
1902 j
= pairs
[j
].older_index
;
1904 pairs
[j
].num_newer
--;
1908 /* cyclic redirection: O(n) */
1909 for (i
= 0; i
< n
; i
++) {
1911 if (pairs
[i
].oldfd
== -1)
1913 if (pairs
[i
].oldfd
== pairs
[i
].newfd
) { /* self cycle */
1915 int fd
= pairs
[i
].oldfd
;
1916 ret
= fcntl(fd
, F_GETFD
);
1919 if (ret
& FD_CLOEXEC
) {
1921 ret
= fcntl(fd
, F_SETFD
, ret
);
1926 pairs
[i
].oldfd
= -1;
1929 if (extra_fd
== -1) {
1930 extra_fd
= redirect_dup(pairs
[i
].oldfd
);
1935 ret
= redirect_dup2(pairs
[i
].oldfd
, extra_fd
);
1939 pairs
[i
].oldfd
= extra_fd
;
1940 j
= pairs
[i
].older_index
;
1941 pairs
[i
].older_index
= -1;
1943 ret
= redirect_dup2(pairs
[j
].oldfd
, pairs
[j
].newfd
);
1946 pairs
[j
].oldfd
= -1;
1947 j
= pairs
[j
].older_index
;
1950 if (extra_fd
!= -1) {
1951 ret
= redirect_close(extra_fd
);
1965 run_exec_close(VALUE ary
)
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
);
1980 run_exec_open(VALUE ary
, VALUE save
)
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]);
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]);
2001 if (save_redirect_fd(fd
, save
) < 0)
2003 ret
= redirect_dup2(fd2
, fd
);
2004 if (ret
== -1) return -1;
2009 ret
= redirect_close(fd2
);
2010 if (ret
== -1) return -1;
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?)
2028 /* maybe meaningless with no fork environment... */
2029 rb_ary_store(save
, EXEC_OPTION_PGROUP
, PIDT2NUM(getpgrp()));
2031 pgroup
= NUM2PIDT(obj
);
2035 return setpgid(getpid(), pgroup
);
2041 run_exec_rlimit(VALUE ary
, VALUE save
)
2044 for (i
= 0; i
< RARRAY_LEN(ary
); i
++) {
2045 VALUE elt
= RARRAY_PTR(ary
)[i
];
2046 int rtype
= NUM2INT(RARRAY_PTR(elt
)[0]);
2050 if (getrlimit(rtype
, &rlim
) == -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)
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
;
2078 if (!RTEST(options
))
2085 s
->options
= soptions
= hide_obj(rb_ary_new());
2086 s
->redirect_fds
= Qnil
;
2090 obj
= rb_ary_entry(options
, EXEC_OPTION_PGROUP
);
2092 if (run_exec_pgroup(obj
, soptions
) == -1)
2098 obj
= rb_ary_entry(options
, EXEC_OPTION_RLIMIT
);
2100 if (run_exec_rlimit(obj
, soptions
) == -1)
2105 obj
= rb_ary_entry(options
, EXEC_OPTION_UNSETENV_OTHERS
);
2111 obj
= rb_ary_entry(options
, EXEC_OPTION_ENV
);
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];
2120 ruby_setenv(StringValueCStr(key
), 0);
2122 ruby_setenv(StringValueCStr(key
), StringValueCStr(val
));
2126 obj
= rb_ary_entry(options
, EXEC_OPTION_CHDIR
);
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)
2137 obj
= rb_ary_entry(options
, EXEC_OPTION_UMASK
);
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
);
2147 if (run_exec_dup2(obj
, soptions
) == -1)
2151 obj
= rb_ary_entry(options
, EXEC_OPTION_CLOSE
);
2153 if (!NIL_P(soptions
))
2154 rb_warn("cannot close fd before spawn");
2156 if (run_exec_close(obj
) == -1)
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
);
2168 obj
= rb_ary_entry(options
, EXEC_OPTION_OPEN
);
2170 if (run_exec_open(obj
, soptions
) == -1)
2178 rb_exec(const struct rb_exec_arg
*e
)
2181 VALUE
*argv
= e
->argv
;
2182 const char *prog
= e
->prog
;
2184 if (rb_run_exec_options(e
, NULL
) < 0) {
2192 rb_proc_exec_n(argc
, argv
, prog
);
2196 fprintf(stderr
, "%s:%d: command not found: %s\n",
2197 rb_sourcefile(), rb_sourceline(), prog
);
2205 rb_exec_atfork(void* arg
)
2207 rb_thread_atfork_before_exec();
2208 return rb_exec(arg
);
2214 #if SIZEOF_INT == SIZEOF_LONG
2215 #define proc_syswait (VALUE (*)(VALUE))rb_syswait
2218 proc_syswait(VALUE pid
)
2220 rb_syswait((int)pid
);
2227 move_fds_to_avoid_crash(int *fdp
, int n
, VALUE fds
)
2231 for (i
= 0; i
< n
; i
++) {
2233 while (RTEST(rb_hash_lookup(fds
, INT2FIX(fdp
[i
])))) {
2236 while (RTEST(rb_hash_lookup(fds
, INT2FIX(min
))))
2238 ret
= fcntl(fdp
[i
], F_DUPFD
, min
);
2249 pipe_nocrash(int filedes
[2], VALUE fds
)
2252 ret
= rb_pipe(filedes
);
2257 if (move_fds_to_avoid_crash(filedes
, 2, fds
) == -1) {
2268 * Forks child process, and returns the process ID in the parent
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
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.
2291 rb_fork(int *status
, int (*chfunc
)(void*), void *charg
, VALUE fds
)
2300 #define prefork() ( \
2301 rb_io_flush(rb_stdout), \
2302 rb_io_flush(rb_stderr) \
2305 #define prefork() ((void)0)
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])));
2319 for (; (pid
= fork()) < 0; prefork()) {
2322 #if defined(EWOULDBLOCK) && EWOULDBLOCK != EAGAIN
2325 if (!status
&& !chfunc
) {
2330 rb_protect((VALUE (*)())rb_thread_sleep
, 1, &state
);
2331 if (status
) *status
= state
;
2332 if (!state
) continue;
2337 preserving_errno((close(ep
[0]), close(ep
[1])));
2340 if (state
&& !status
) rb_jump_tag(state
);
2345 rb_thread_reset_timer_thread();
2350 if (!(*chfunc
)(charg
)) _exit(EXIT_SUCCESS
);
2353 write(ep
[1], &err
, sizeof(err
));
2355 #if EXIT_SUCCESS == 127
2356 _exit(EXIT_FAILURE
);
2361 rb_thread_start_timer_thread();
2366 if ((state
= read(ep
[0], &err
, sizeof(err
))) < 0) {
2372 rb_protect(proc_syswait
, (VALUE
)pid
, status
);
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.
2408 rb_f_fork(VALUE obj
)
2410 #if defined(HAVE_FORK) && !defined(CANNOT_FORK_WITH_PTHREAD)
2415 switch (pid
= rb_fork(0, 0, 0, Qnil
)) {
2421 if (rb_block_given_p()) {
2424 rb_protect(rb_yield
, Qundef
, &status
);
2430 rb_sys_fail("fork(2)");
2434 return PIDT2NUM(pid
);
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
2454 rb_f_exit_bang(int argc
, VALUE
*argv
, VALUE obj
)
2460 if (argc
> 0 && rb_scan_args(argc
, argv
, "01", &status
) == 1) {
2463 istatus
= EXIT_SUCCESS
;
2466 istatus
= EXIT_FAILURE
;
2469 istatus
= NUM2INT(status
);
2474 istatus
= EXIT_FAILURE
;
2478 return Qnil
; /* not reached */
2484 if (GET_THREAD()->tag
) {
2487 args
[0] = INT2NUM(status
);
2488 args
[1] = rb_str_new2("exit");
2489 rb_exc_raise(rb_class_new_instance(2, args
, rb_eSystemExit
));
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
2509 * puts "never get here"
2511 * puts "rescued a SystemExit exception"
2513 * puts "after begin block"
2515 * <em>produces:</em>
2517 * rescued a SystemExit exception
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" })
2528 * <em>produces:</em>
2535 rb_f_exit(int argc
, VALUE
*argv
)
2541 if (argc
> 0 && rb_scan_args(argc
, argv
, "01", &status
) == 1) {
2544 istatus
= EXIT_SUCCESS
;
2547 istatus
= EXIT_FAILURE
;
2550 istatus
= NUM2INT(status
);
2551 #if EXIT_SUCCESS != 0
2553 istatus
= EXIT_SUCCESS
;
2559 istatus
= EXIT_SUCCESS
;
2562 return Qnil
; /* not reached */
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.
2578 rb_f_abort(int argc
, VALUE
*argv
)
2580 extern void ruby_error_print(void);
2584 if (!NIL_P(GET_THREAD()->errinfo
)) {
2587 rb_exit(EXIT_FAILURE
);
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 */
2603 #define signal(a,b) sigset(a,b)
2605 # if defined(POSIX_SIGNAL)
2606 # define signal(a,b) posix_signal(a,b)
2611 rb_syswait(rb_pid_t pid
)
2613 static int overriding
;
2615 RETSIGTYPE (*hfunc
)(int) = 0;
2618 RETSIGTYPE (*qfunc
)(int) = 0;
2620 RETSIGTYPE (*ifunc
)(int) = 0;
2622 int i
, hooked
= Qfalse
;
2626 hfunc
= signal(SIGHUP
, SIG_IGN
);
2629 qfunc
= signal(SIGQUIT
, SIG_IGN
);
2631 ifunc
= signal(SIGINT
, SIG_IGN
);
2637 i
= rb_waitpid(pid
, &status
, 0);
2638 } while (i
== -1 && errno
== EINTR
);
2642 signal(SIGHUP
, hfunc
);
2645 signal(SIGQUIT
, qfunc
);
2647 signal(SIGINT
, ifunc
);
2648 overriding
= Qfalse
;
2653 rb_spawn_internal(int argc
, VALUE
*argv
, int default_close_others
)
2657 struct rb_exec_arg earg
;
2658 #if !defined HAVE_FORK
2659 struct rb_exec_arg sarg
;
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
;
2673 if (rb_run_exec_options(&earg
, &sarg
) < 0) {
2679 if (prog
&& argc
) argv
[0] = prog
;
2680 # if defined HAVE_SPAWNV
2682 status
= proc_spawn(RSTRING_PTR(prog
));
2685 status
= proc_spawn_n(argc
, argv
, prog
);
2687 # if defined(_WIN32)
2689 rb_last_status_set(0x7f << 8, 0);
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);
2697 rb_last_status_set((status
& 0xff) << 8, 0);
2701 rb_run_exec_options(&sarg
, NULL
);
2707 rb_spawn(int argc
, VALUE
*argv
)
2709 return rb_spawn_internal(argc
, argv
, Qtrue
);
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.
2727 * system("echo", "*")
2729 * <em>produces:</em>
2736 rb_f_system(int argc
, VALUE
*argv
)
2740 #if defined(SIGCLD) && !defined(SIGCHLD)
2741 # define SIGCHLD SIGCLD
2745 RETSIGTYPE (*chfunc
)(int);
2747 chfunc
= signal(SIGCHLD
, SIG_DFL
);
2749 status
= rb_spawn_internal(argc
, argv
, Qfalse
);
2750 #if defined(HAVE_FORK) || defined(HAVE_SPAWNV)
2756 signal(SIGCHLD
, chfunc
);
2761 status
= PST2INT(rb_last_status_get());
2762 if (status
== EXIT_SUCCESS
) return Qtrue
;
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+,
2784 * current directory,
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)
2891 * pid = spawn(command, STDOUT=>w) # r, w is closed in the child process.
2894 * :close is specified as a hash value to close a fd individualy.
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.
2912 rb_f_spawn(int argc
, VALUE
*argv
)
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
);
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
2935 * Time.new #=> 2008-03-08 19:56:19 +0900
2937 * Time.new #=> 2008-03-08 19:56:20 +0900
2939 * Time.new #=> 2008-03-08 19:56:22 +0900
2943 rb_f_sleep(int argc
, VALUE
*argv
)
2949 rb_thread_sleep_forever();
2951 else if (argc
== 1) {
2952 rb_thread_wait_for(rb_time_interval(argv
[0]));
2955 rb_raise(rb_eArgError
, "wrong number of arguments");
2958 end
= time(0) - beg
;
2960 return INT2FIX(end
);
2966 * Process.getpgrp => integer
2968 * Returns the process group ID for this process. Not available on
2971 * Process.getpgid(0) #=> 25527
2972 * Process.getpgrp #=> 25527
2978 #if defined(HAVE_GETPGRP) && defined(GETPGRP_VOID) || defined(HAVE_GETPGID)
2983 #if defined(HAVE_GETPGRP) && defined(GETPGRP_VOID)
2985 if (pgrp
< 0) rb_sys_fail(0);
2986 return PIDT2NUM(pgrp
);
2988 # ifdef HAVE_GETPGID
2990 if (pgrp
< 0) rb_sys_fail(0);
2991 return PIDT2NUM(pgrp
);
3001 * Process.setpgrp => 0
3003 * Equivalent to <code>setpgid(0,0)</code>. Not available on all
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. */
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);
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
3037 proc_getpgid(VALUE obj
, VALUE pid
)
3039 #if defined(HAVE_GETPGID) && !defined(__CHECKER__)
3043 i
= getpgid(NUM2PIDT(pid
));
3044 if (i
< 0) rb_sys_fail(0);
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.
3061 proc_setpgid(VALUE obj
, VALUE pid
, VALUE pgrp
)
3064 rb_pid_t ipid
, ipgrp
;
3067 ipid
= NUM2PIDT(pid
);
3068 ipgrp
= NUM2PIDT(pgrp
);
3070 if (setpgid(ipid
, ipgrp
) < 0) rb_sys_fail(0);
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
3092 #if defined(HAVE_SETSID)
3097 if (pid
< 0) rb_sys_fail(0);
3098 return PIDT2NUM(pid
);
3099 #elif defined(HAVE_SETPGRP) && defined(TIOCNOTTY)
3105 #if defined(SETPGRP_VOID)
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). */
3111 ret
= setpgrp(0, pid
);
3113 if (ret
== -1) rb_sys_fail(0);
3115 if ((fd
= open("/dev/tty", O_RDWR
)) >= 0) {
3116 ioctl(fd
, TIOCNOTTY
, NULL
);
3119 return PIDT2NUM(pid
);
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
3144 proc_getpriority(VALUE obj
, VALUE which
, VALUE who
)
3146 #ifdef HAVE_GETPRIORITY
3147 int prio
, iwhich
, iwho
;
3150 iwhich
= NUM2INT(which
);
3151 iwho
= NUM2INT(who
);
3154 prio
= getpriority(iwhich
, iwho
);
3155 if (errno
) rb_sys_fail(0);
3156 return INT2FIX(prio
);
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
3176 proc_setpriority(VALUE obj
, VALUE which
, VALUE who
, VALUE prio
)
3178 #ifdef HAVE_GETPRIORITY
3179 int iwhich
, iwho
, iprio
;
3182 iwhich
= NUM2INT(which
);
3183 iwho
= NUM2INT(who
);
3184 iprio
= NUM2INT(prio
);
3186 if (setpriority(iwhich
, iwho
, iprio
) < 0)
3194 #if defined(RLIM2NUM)
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) {
3202 char *name2
= ALLOCA_N(char, len
+1);
3203 for (i
= 0; i
< len
; i
++) {
3204 if (!ISLOWER(name
[i
]))
3206 name2
[i
] = TOUPPER(name
[i
]);
3215 if (strcmp(name
, "AS") == 0) return RLIMIT_AS
;
3221 if (strcmp(name
, "CORE") == 0) return RLIMIT_CORE
;
3224 if (strcmp(name
, "CPU") == 0) return RLIMIT_CPU
;
3230 if (strcmp(name
, "DATA") == 0) return RLIMIT_DATA
;
3236 if (strcmp(name
, "FSIZE") == 0) return RLIMIT_FSIZE
;
3241 #ifdef RLIMIT_MEMLOCK
3242 if (strcmp(name
, "MEMLOCK") == 0) return RLIMIT_MEMLOCK
;
3247 #ifdef RLIMIT_NOFILE
3248 if (strcmp(name
, "NOFILE") == 0) return RLIMIT_NOFILE
;
3251 if (strcmp(name
, "NPROC") == 0) return RLIMIT_NPROC
;
3257 if (strcmp(name
, "RSS") == 0) return RLIMIT_RSS
;
3263 if (strcmp(name
, "STACK") == 0) return RLIMIT_STACK
;
3265 #ifdef RLIMIT_SBSIZE
3266 if (strcmp(name
, "SBSIZE") == 0) return RLIMIT_SBSIZE
;
3274 rlimit_type_by_hname(const char *name
)
3276 return rlimit_resource_name2int(name
, 0);
3280 rlimit_type_by_lname(const char *name
)
3282 return rlimit_resource_name2int(name
, 1);
3286 rlimit_resource_type(VALUE rtype
)
3292 switch (TYPE(rtype
)) {
3294 name
= rb_id2name(SYM2ID(rtype
));
3298 v
= rb_check_string_type(rtype
);
3302 name
= StringValueCStr(rtype
);
3309 return NUM2INT(rtype
);
3312 r
= rlimit_type_by_hname(name
);
3316 rb_raise(rb_eArgError
, "invalid resource name: %s", name
);
3320 rlimit_resource_value(VALUE rval
)
3325 switch (TYPE(rval
)) {
3327 name
= rb_id2name(SYM2ID(rval
));
3331 v
= rb_check_string_type(rval
);
3335 name
= StringValueCStr(rval
);
3342 return NUM2RLIM(rval
);
3345 #ifdef RLIM_INFINITY
3346 if (strcmp(name
, "INFINITY") == 0) return RLIM_INFINITY
;
3348 #ifdef RLIM_SAVED_MAX
3349 if (strcmp(name
, "SAVED_MAX") == 0) return RLIM_SAVED_MAX
;
3351 #ifdef RLIM_SAVED_CUR
3352 if (strcmp(name
, "SAVED_CUR") == 0) return RLIM_SAVED_CUR
;
3354 rb_raise(rb_eArgError
, "invalid resource value: %s", name
);
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.
3379 proc_getrlimit(VALUE obj
, VALUE resource
)
3381 #if defined(HAVE_GETRLIMIT) && defined(RLIM2NUM)
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
));
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])
3442 proc_setrlimit(int argc
, VALUE
*argv
, VALUE obj
)
3444 #if defined(HAVE_SETRLIMIT) && defined(NUM2RLIM)
3445 VALUE resource
, rlim_cur
, rlim_max
;
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");
3466 static int under_uid_switch
= 0;
3468 check_uid_switch(void)
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;
3478 check_gid_switch(void)
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.
3500 * Process::Sys.setuid(integer) => nil
3502 * Set the user ID of the current process to _integer_. Not
3503 * available on all platforms.
3508 p_sys_setuid(VALUE obj
, VALUE id
)
3510 #if defined HAVE_SETUID
3512 if (setuid(NUM2UIDT(id
)) != 0) rb_sys_fail(0);
3523 * Process::Sys.setruid(integer) => nil
3525 * Set the real user ID of the calling process to _integer_.
3526 * Not available on all platforms.
3531 p_sys_setruid(VALUE obj
, VALUE id
)
3533 #if defined HAVE_SETRUID
3535 if (setruid(NUM2UIDT(id
)) != 0) rb_sys_fail(0);
3545 * Process::Sys.seteuid(integer) => nil
3547 * Set the effective user ID of the calling process to
3548 * _integer_. Not available on all platforms.
3553 p_sys_seteuid(VALUE obj
, VALUE id
)
3555 #if defined HAVE_SETEUID
3557 if (seteuid(NUM2UIDT(id
)) != 0) rb_sys_fail(0);
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.
3577 p_sys_setreuid(VALUE obj
, VALUE rid
, VALUE eid
)
3579 #if defined HAVE_SETREUID
3581 if (setreuid(NUM2UIDT(rid
),NUM2UIDT(eid
)) != 0) rb_sys_fail(0);
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.
3601 p_sys_setresuid(VALUE obj
, VALUE rid
, VALUE eid
, VALUE sid
)
3603 #if defined HAVE_SETRESUID
3605 if (setresuid(NUM2UIDT(rid
),NUM2UIDT(eid
),NUM2UIDT(sid
)) != 0) rb_sys_fail(0);
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
3625 proc_getuid(VALUE obj
)
3627 rb_uid_t uid
= getuid();
3628 return UIDT2NUM(uid
);
3634 * Process.uid= integer => numeric
3636 * Sets the (integer) user ID for this process. Not available on all
3641 proc_setuid(VALUE obj
, VALUE 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);
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;
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]
3711 p_uid_change_privilege(VALUE obj
, VALUE 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);
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
;
3738 if (setreuid(0, -1) < 0) rb_sys_fail(0);
3740 if (setreuid(uid
, uid
) < 0) rb_sys_fail(0);
3741 SAVED_USER_ID
= uid
;
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);
3754 if (setruid(SAVED_USER_ID
) < 0) rb_sys_fail(0);
3756 if (setruid(0) < 0) rb_sys_fail(0);
3758 if (setruid(0) < 0) rb_sys_fail(0);
3760 if (seteuid(uid
) < 0) rb_sys_fail(0);
3761 if (setruid(uid
) < 0) rb_sys_fail(0);
3762 SAVED_USER_ID
= uid
;
3766 if (seteuid(uid
) < 0) rb_sys_fail(0);
3767 if (setruid(uid
) < 0) rb_sys_fail(0);
3768 SAVED_USER_ID
= uid
;
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
;
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);
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
;
3827 #elif defined HAVE_SETEUID
3828 if (getuid() == uid
&& SAVED_USER_ID
== uid
) {
3829 if (seteuid(uid
) < 0) 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);
3852 * Process::Sys.setgid(integer) => nil
3854 * Set the group ID of the current process to _integer_. Not
3855 * available on all platforms.
3860 p_sys_setgid(VALUE obj
, VALUE id
)
3862 #if defined HAVE_SETGID
3864 if (setgid(NUM2GIDT(id
)) != 0) rb_sys_fail(0);
3874 * Process::Sys.setrgid(integer) => nil
3876 * Set the real group ID of the calling process to _integer_.
3877 * Not available on all platforms.
3882 p_sys_setrgid(VALUE obj
, VALUE id
)
3884 #if defined HAVE_SETRGID
3886 if (setrgid(NUM2GIDT(id
)) != 0) rb_sys_fail(0);
3897 * Process::Sys.setegid(integer) => nil
3899 * Set the effective group ID of the calling process to
3900 * _integer_. Not available on all platforms.
3905 p_sys_setegid(VALUE obj
, VALUE id
)
3907 #if defined HAVE_SETEGID
3909 if (setegid(NUM2GIDT(id
)) != 0) rb_sys_fail(0);
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.
3929 p_sys_setregid(VALUE obj
, VALUE rid
, VALUE eid
)
3931 #if defined HAVE_SETREGID
3933 if (setregid(NUM2GIDT(rid
),NUM2GIDT(eid
)) != 0) rb_sys_fail(0);
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.
3952 p_sys_setresgid(VALUE obj
, VALUE rid
, VALUE eid
, VALUE sid
)
3954 #if defined HAVE_SETRESGID
3956 if (setresgid(NUM2GIDT(rid
),NUM2GIDT(eid
),NUM2GIDT(sid
)) != 0) rb_sys_fail(0);
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.
3977 p_sys_issetugid(VALUE obj
)
3979 #if defined HAVE_ISSETUGID
3988 return Qnil
; /* not reached */
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
4005 proc_getgid(VALUE obj
)
4007 rb_gid_t gid
= getgid();
4008 return GIDT2NUM(gid
);
4014 * Process.gid= fixnum => fixnum
4016 * Sets the group ID for this process.
4020 proc_setgid(VALUE obj
, VALUE 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);
4045 return GIDT2NUM(gid
);
4049 static size_t maxgroups
= 32;
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]
4064 proc_getgroups(VALUE obj
)
4066 #ifdef HAVE_GETGROUPS
4072 groups
= ALLOCA_N(rb_gid_t
, maxgroups
);
4074 ngroups
= getgroups(maxgroups
, groups
);
4079 for (i
= 0; i
< ngroups
; i
++)
4080 rb_ary_push(ary
, GIDT2NUM(groups
[i
]));
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]
4104 proc_setgroups(VALUE obj
, VALUE ary
)
4106 #ifdef HAVE_SETGROUPS
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
];
4124 groups
[i
] = NUM2GIDT(g
);
4127 VALUE tmp
= rb_check_string_type(g
);
4130 groups
[i
] = NUM2GIDT(g
);
4133 gr
= getgrnam(RSTRING_PTR(tmp
));
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
);
4146 return proc_getgroups(obj
);
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]
4172 proc_initgroups(VALUE obj
, VALUE uname
, VALUE base_grp
)
4174 #ifdef HAVE_INITGROUPS
4175 if (initgroups(StringValuePtr(uname
), NUM2GIDT(base_grp
)) != 0) {
4178 return proc_getgroups(obj
);
4188 * Process.maxgroups => fixnum
4190 * Returns the maximum number of gids allowed in the supplemental
4191 * group access list.
4193 * Process.maxgroups #=> 32
4197 proc_getmaxgroups(VALUE obj
)
4199 return INT2FIX(maxgroups
);
4205 * Process.maxgroups= fixnum => fixnum
4207 * Sets the maximum number of gids allowed in the supplemental group
4212 proc_setmaxgroups(VALUE obj
, VALUE val
)
4214 size_t ngroups
= FIX2INT(val
);
4219 maxgroups
= ngroups
;
4221 return INT2FIX(maxgroups
);
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.
4238 proc_daemon(int argc
, VALUE
*argv
)
4240 VALUE nochdir
, noclose
;
4241 #if defined(HAVE_DAEMON) || defined(HAVE_FORK)
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");
4252 #elif defined(HAVE_FORK)
4253 switch (rb_fork(0, 0, 0, Qnil
)) {
4264 if (!RTEST(nochdir
))
4267 if (!RTEST(noclose
) && (n
= open("/dev/null", O_RDWR
, 0)) != -1) {
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;
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]
4321 p_gid_change_privilege(VALUE obj
, VALUE 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);
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);
4350 if (setregid(gid
, gid
) < 0) rb_sys_fail(0);
4351 SAVED_GROUP_ID
= gid
;
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);
4364 if (setegid(gid
) < 0) rb_sys_fail(0);
4365 if (setrgid(SAVED_GROUP_ID
) < 0) rb_sys_fail(0);
4367 if (setrgid(0) < 0) rb_sys_fail(0);
4369 if (setrgid(0) < 0) rb_sys_fail(0);
4371 if (setegid(gid
) < 0) rb_sys_fail(0);
4372 if (setrgid(gid
) < 0) rb_sys_fail(0);
4373 SAVED_GROUP_ID
= gid
;
4377 if (setegid(gid
) < 0) rb_sys_fail(0);
4378 if (setrgid(gid
) < 0) rb_sys_fail(0);
4379 SAVED_GROUP_ID
= gid
;
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
;
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);
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
;
4438 #elif defined HAVE_SETEGID
4439 if (getgid() == gid
&& SAVED_GROUP_ID
== gid
) {
4440 if (setegid(gid
) < 0) 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);
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
4472 proc_geteuid(VALUE obj
)
4474 rb_uid_t euid
= geteuid();
4475 return UIDT2NUM(euid
);
4481 * Process.euid= integer
4483 * Sets the effective user ID for this process. Not available on all
4488 proc_seteuid(VALUE obj
, VALUE euid
)
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);
4515 rb_seteuid_core(rb_uid_t euid
)
4523 #if defined(HAVE_SETRESUID) && !defined(__CHECKER__)
4525 if (setresuid(-1,euid
,euid
) < 0) rb_sys_fail(0);
4526 SAVED_USER_ID
= euid
;
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);
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);
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]
4564 p_uid_grant_privilege(VALUE obj
, VALUE id
)
4566 rb_seteuid_core(NUM2UIDT(id
));
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
4580 * Process.egid #=> 500
4584 proc_getegid(VALUE obj
)
4586 rb_gid_t egid
= getegid();
4588 return GIDT2NUM(egid
);
4594 * Process.egid = fixnum => fixnum
4596 * Sets the effective group ID for this process. Not available on all
4601 proc_setegid(VALUE obj
, VALUE egid
)
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);
4628 rb_setegid_core(rb_gid_t egid
)
4636 #if defined(HAVE_SETRESGID) && !defined(__CHECKER__)
4638 if (setresgid(-1,egid
,egid
) < 0) rb_sys_fail(0);
4639 SAVED_GROUP_ID
= egid
;
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);
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);
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]
4677 p_gid_grant_privilege(VALUE obj
, VALUE id
)
4679 rb_setegid_core(NUM2GIDT(id
));
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.
4694 p_uid_exchangeable(void)
4696 #if defined(HAVE_SETRESUID) && !defined(__CHECKER__)
4698 #elif defined(HAVE_SETREUID) && !defined(OBSOLETE_SETREUID)
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]
4719 p_uid_exchange(VALUE obj
)
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
;
4737 return UIDT2NUM(uid
);
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.
4751 p_gid_exchangeable(void)
4753 #if defined(HAVE_SETRESGID) && !defined(__CHECKER__)
4755 #elif defined(HAVE_SETREGID) && !defined(OBSOLETE_SETREGID)
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]
4776 p_gid_exchange(VALUE obj
)
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
;
4794 return GIDT2NUM(gid
);
4797 /* [MG] :FIXME: Is this correct? I'm not sure how to phrase this. */
4801 * Process::UID.sid_available? => true or false
4803 * Returns +true+ if the current platform has saved user
4809 p_uid_have_saved_id(void)
4811 #if defined(HAVE_SETRESUID) || defined(HAVE_SETEUID) || defined(_POSIX_SAVED_IDS)
4819 #if defined(HAVE_SETRESUID) || defined(HAVE_SETEUID) || defined(_POSIX_SAVED_IDS)
4821 p_uid_sw_ensure(rb_uid_t id
)
4823 under_uid_switch
= 0;
4824 id
= rb_seteuid_core(id
);
4825 return UIDT2NUM(id
);
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
4843 p_uid_switch(VALUE obj
)
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
);
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
);
4866 return UIDT2NUM(uid
);
4875 p_uid_sw_ensure(VALUE obj
)
4877 under_uid_switch
= 0;
4878 return p_uid_exchange(obj
);
4882 p_uid_switch(VALUE obj
)
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
);
4900 return UIDT2NUM(euid
);
4906 /* [MG] :FIXME: Is this correct? I'm not sure how to phrase this. */
4910 * Process::GID.sid_available? => true or false
4912 * Returns +true+ if the current platform has saved group
4918 p_gid_have_saved_id(void)
4920 #if defined(HAVE_SETRESGID) || defined(HAVE_SETEGID) || defined(_POSIX_SAVED_IDS)
4927 #if defined(HAVE_SETRESGID) || defined(HAVE_SETEGID) || defined(_POSIX_SAVED_IDS)
4929 p_gid_sw_ensure(rb_gid_t id
)
4931 under_gid_switch
= 0;
4932 id
= rb_setegid_core(id
);
4933 return GIDT2NUM(id
);
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
4951 p_gid_switch(VALUE obj
)
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
);
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
);
4974 return GIDT2NUM(gid
);
4983 p_gid_sw_ensure(VALUE obj
)
4985 under_gid_switch
= 0;
4986 return p_gid_exchange(obj
);
4990 p_gid_switch(VALUE obj
)
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
);
5008 return GIDT2NUM(egid
);
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
5023 * [ t.utime, t.stime ] #=> [0.0, 0.02]
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
);
5044 volatile VALUE utime
, stime
, cutime
, sctime
;
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
));
5060 VALUE rb_mProcID_Syscall
;
5064 * The <code>Process</code> module is a collection of methods used to
5065 * manipulate processes.
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");
5085 rb_define_const(rb_mProcess
, "WNOHANG", INT2FIX(WNOHANG
));
5087 rb_define_const(rb_mProcess
, "WNOHANG", INT2FIX(0));
5090 rb_define_const(rb_mProcess
, "WUNTRACED", INT2FIX(WUNTRACED
));
5092 rb_define_const(rb_mProcess
, "WUNTRACED", INT2FIX(0));
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
));
5150 rb_define_module_function(rb_mProcess
, "getrlimit", proc_getrlimit
, 1);
5151 rb_define_module_function(rb_mProcess
, "setrlimit", proc_setrlimit
, -1);
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
);
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
);
5166 rb_define_const(rb_mProcess
, "RLIMIT_CORE", INT2FIX(RLIMIT_CORE
));
5169 rb_define_const(rb_mProcess
, "RLIMIT_CPU", INT2FIX(RLIMIT_CPU
));
5172 rb_define_const(rb_mProcess
, "RLIMIT_DATA", INT2FIX(RLIMIT_DATA
));
5175 rb_define_const(rb_mProcess
, "RLIMIT_FSIZE", INT2FIX(RLIMIT_FSIZE
));
5177 #ifdef RLIMIT_NOFILE
5178 rb_define_const(rb_mProcess
, "RLIMIT_NOFILE", INT2FIX(RLIMIT_NOFILE
));
5181 rb_define_const(rb_mProcess
, "RLIMIT_STACK", INT2FIX(RLIMIT_STACK
));
5184 rb_define_const(rb_mProcess
, "RLIMIT_AS", INT2FIX(RLIMIT_AS
));
5186 #ifdef RLIMIT_MEMLOCK
5187 rb_define_const(rb_mProcess
, "RLIMIT_MEMLOCK", INT2FIX(RLIMIT_MEMLOCK
));
5190 rb_define_const(rb_mProcess
, "RLIMIT_NPROC", INT2FIX(RLIMIT_NPROC
));
5193 rb_define_const(rb_mProcess
, "RLIMIT_RSS", INT2FIX(RLIMIT_RSS
));
5195 #ifdef RLIMIT_SBSIZE
5196 rb_define_const(rb_mProcess
, "RLIMIT_SBSIZE", INT2FIX(RLIMIT_SBSIZE
));
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
);
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);