Ruby  2.0.0p247(2013-06-27revision41674)
process.c
Go to the documentation of this file.
00001 /**********************************************************************
00002 
00003   process.c -
00004 
00005   $Author: nagachika $
00006   created at: Tue Aug 10 14:30:50 JST 1993
00007 
00008   Copyright (C) 1993-2007 Yukihiro Matsumoto
00009   Copyright (C) 2000  Network Applied Communication Laboratory, Inc.
00010   Copyright (C) 2000  Information-technology Promotion Agency, Japan
00011 
00012 **********************************************************************/
00013 
00014 #include "ruby/ruby.h"
00015 #include "ruby/io.h"
00016 #include "ruby/thread.h"
00017 #include "ruby/util.h"
00018 #include "internal.h"
00019 #include "vm_core.h"
00020 
00021 #include <stdio.h>
00022 #include <errno.h>
00023 #include <signal.h>
00024 #ifdef HAVE_STDLIB_H
00025 #include <stdlib.h>
00026 #endif
00027 #ifdef HAVE_UNISTD_H
00028 #include <unistd.h>
00029 #endif
00030 #ifdef HAVE_FCNTL_H
00031 #include <fcntl.h>
00032 #endif
00033 #ifdef HAVE_PROCESS_H
00034 #include <process.h>
00035 #endif
00036 
00037 #include <time.h>
00038 #include <ctype.h>
00039 
00040 #ifndef EXIT_SUCCESS
00041 #define EXIT_SUCCESS 0
00042 #endif
00043 #ifndef EXIT_FAILURE
00044 #define EXIT_FAILURE 1
00045 #endif
00046 
00047 #ifdef HAVE_SYS_WAIT_H
00048 # include <sys/wait.h>
00049 #endif
00050 #ifdef HAVE_SYS_RESOURCE_H
00051 # include <sys/resource.h>
00052 #endif
00053 #ifdef HAVE_SYS_PARAM_H
00054 # include <sys/param.h>
00055 #endif
00056 #ifndef MAXPATHLEN
00057 # define MAXPATHLEN 1024
00058 #endif
00059 #include "ruby/st.h"
00060 
00061 #ifdef __EMX__
00062 #undef HAVE_GETPGRP
00063 #endif
00064 
00065 #include <sys/stat.h>
00066 #if defined(__native_client__) && defined(NACL_NEWLIB)
00067 # include "nacl/stat.h"
00068 # include "nacl/unistd.h"
00069 #endif
00070 
00071 
00072 #ifdef HAVE_SYS_TIMES_H
00073 #include <sys/times.h>
00074 #endif
00075 
00076 #ifdef HAVE_PWD_H
00077 #include <pwd.h>
00078 #endif
00079 #ifdef HAVE_GRP_H
00080 #include <grp.h>
00081 #endif
00082 
00083 #define numberof(array) (int)(sizeof(array)/sizeof((array)[0]))
00084 
00085 #if defined(HAVE_TIMES) || defined(_WIN32)
00086 static VALUE rb_cProcessTms;
00087 #endif
00088 
00089 #ifndef WIFEXITED
00090 #define WIFEXITED(w)    (((w) & 0xff) == 0)
00091 #endif
00092 #ifndef WIFSIGNALED
00093 #define WIFSIGNALED(w)  (((w) & 0x7f) > 0 && (((w) & 0x7f) < 0x7f))
00094 #endif
00095 #ifndef WIFSTOPPED
00096 #define WIFSTOPPED(w)   (((w) & 0xff) == 0x7f)
00097 #endif
00098 #ifndef WEXITSTATUS
00099 #define WEXITSTATUS(w)  (((w) >> 8) & 0xff)
00100 #endif
00101 #ifndef WTERMSIG
00102 #define WTERMSIG(w)     ((w) & 0x7f)
00103 #endif
00104 #ifndef WSTOPSIG
00105 #define WSTOPSIG        WEXITSTATUS
00106 #endif
00107 
00108 #if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__bsdi__)
00109 #define HAVE_44BSD_SETUID 1
00110 #define HAVE_44BSD_SETGID 1
00111 #endif
00112 
00113 #ifdef __NetBSD__
00114 #undef HAVE_SETRUID
00115 #undef HAVE_SETRGID
00116 #endif
00117 
00118 #ifdef BROKEN_SETREUID
00119 #define setreuid ruby_setreuid
00120 int setreuid(rb_uid_t ruid, rb_uid_t euid);
00121 #endif
00122 #ifdef BROKEN_SETREGID
00123 #define setregid ruby_setregid
00124 int setregid(rb_gid_t rgid, rb_gid_t egid);
00125 #endif
00126 
00127 #if defined(HAVE_44BSD_SETUID) || defined(__APPLE__)
00128 #if !defined(USE_SETREUID) && !defined(BROKEN_SETREUID)
00129 #define OBSOLETE_SETREUID 1
00130 #endif
00131 #if !defined(USE_SETREGID) && !defined(BROKEN_SETREGID)
00132 #define OBSOLETE_SETREGID 1
00133 #endif
00134 #endif
00135 
00136 #define preserving_errno(stmts) \
00137         do {int saved_errno = errno; stmts; errno = saved_errno;} while (0)
00138 
00139 static void check_uid_switch(void);
00140 static void check_gid_switch(void);
00141 
00142 #if 1
00143 #define p_uid_from_name p_uid_from_name
00144 #define p_gid_from_name p_gid_from_name
00145 #endif
00146 
00147 #if defined(HAVE_PWD_H)
00148 # if defined(HAVE_GETPWNAM_R) && defined(_SC_GETPW_R_SIZE_MAX)
00149 #  define USE_GETPWNAM_R 1
00150 # endif
00151 # ifdef USE_GETPWNAM_R
00152 #   define PREPARE_GETPWNAM \
00153     long getpw_buf_len = sysconf(_SC_GETPW_R_SIZE_MAX); \
00154     char *getpw_buf = ALLOCA_N(char, (getpw_buf_len < 0 ? (getpw_buf_len = 4096) : getpw_buf_len));
00155 #   define OBJ2UID(id) obj2uid((id), getpw_buf, getpw_buf_len)
00156 static rb_uid_t obj2uid(VALUE id, char *getpw_buf, size_t getpw_buf_len);
00157 # else
00158 #   define PREPARE_GETPWNAM     /* do nothing */
00159 #   define OBJ2UID(id) obj2uid((id))
00160 static rb_uid_t obj2uid(VALUE id);
00161 # endif
00162 #else
00163 # define PREPARE_GETPWNAM       /* do nothing */
00164 # define OBJ2UID(id) NUM2UIDT(id)
00165 # ifdef p_uid_from_name
00166 #   undef p_uid_from_name
00167 #   define p_uid_from_name rb_f_notimplement
00168 # endif
00169 #endif
00170 
00171 #if defined(HAVE_GRP_H)
00172 # if defined(HAVE_GETGRNAM_R) && defined(_SC_GETGR_R_SIZE_MAX)
00173 #  define USE_GETGRNAM_R
00174 # endif
00175 # ifdef USE_GETGRNAM_R
00176 #   define PREPARE_GETGRNAM \
00177     long getgr_buf_len = sysconf(_SC_GETGR_R_SIZE_MAX); \
00178     char *getgr_buf = ALLOCA_N(char, (getgr_buf_len < 0 ? (getgr_buf_len = 4096) : getgr_buf_len));
00179 #   define OBJ2GID(id) obj2gid((id), getgr_buf, getgr_buf_len)
00180 static rb_gid_t obj2gid(VALUE id, char *getgr_buf, size_t getgr_buf_len);
00181 # else
00182 #   define PREPARE_GETGRNAM     /* do nothing */
00183 #   define OBJ2GID(id) obj2gid((id))
00184 static rb_gid_t obj2gid(VALUE id);
00185 # endif
00186 #else
00187 # define PREPARE_GETGRNAM       /* do nothing */
00188 # define OBJ2GID(id) NUM2GIDT(id)
00189 # ifdef p_gid_from_name
00190 #   undef p_gid_from_name
00191 #   define p_gid_from_name rb_f_notimplement
00192 # endif
00193 #endif
00194 
00195 /*
00196  *  call-seq:
00197  *     Process.pid   -> fixnum
00198  *
00199  *  Returns the process id of this process. Not available on all
00200  *  platforms.
00201  *
00202  *     Process.pid   #=> 27415
00203  */
00204 
00205 static VALUE
00206 get_pid(void)
00207 {
00208     rb_secure(2);
00209     return PIDT2NUM(getpid());
00210 }
00211 
00212 
00213 /*
00214  *  call-seq:
00215  *     Process.ppid   -> fixnum
00216  *
00217  *  Returns the process id of the parent of this process. Returns
00218  *  untrustworthy value on Win32/64. Not available on all platforms.
00219  *
00220  *     puts "I am #{Process.pid}"
00221  *     Process.fork { puts "Dad is #{Process.ppid}" }
00222  *
00223  *  <em>produces:</em>
00224  *
00225  *     I am 27417
00226  *     Dad is 27417
00227  */
00228 
00229 static VALUE
00230 get_ppid(void)
00231 {
00232     rb_secure(2);
00233     return PIDT2NUM(getppid());
00234 }
00235 
00236 
00237 /*********************************************************************
00238  *
00239  * Document-class: Process::Status
00240  *
00241  *  <code>Process::Status</code> encapsulates the information on the
00242  *  status of a running or terminated system process. The built-in
00243  *  variable <code>$?</code> is either +nil+ or a
00244  *  <code>Process::Status</code> object.
00245  *
00246  *     fork { exit 99 }   #=> 26557
00247  *     Process.wait       #=> 26557
00248  *     $?.class           #=> Process::Status
00249  *     $?.to_i            #=> 25344
00250  *     $? >> 8            #=> 99
00251  *     $?.stopped?        #=> false
00252  *     $?.exited?         #=> true
00253  *     $?.exitstatus      #=> 99
00254  *
00255  *  Posix systems record information on processes using a 16-bit
00256  *  integer.  The lower bits record the process status (stopped,
00257  *  exited, signaled) and the upper bits possibly contain additional
00258  *  information (for example the program's return code in the case of
00259  *  exited processes). Pre Ruby 1.8, these bits were exposed directly
00260  *  to the Ruby program. Ruby now encapsulates these in a
00261  *  <code>Process::Status</code> object. To maximize compatibility,
00262  *  however, these objects retain a bit-oriented interface. In the
00263  *  descriptions that follow, when we talk about the integer value of
00264  *  _stat_, we're referring to this 16 bit value.
00265  */
00266 
00267 static VALUE rb_cProcessStatus;
00268 
00269 VALUE
00270 rb_last_status_get(void)
00271 {
00272     return GET_THREAD()->last_status;
00273 }
00274 
00275 void
00276 rb_last_status_set(int status, rb_pid_t pid)
00277 {
00278     rb_thread_t *th = GET_THREAD();
00279     th->last_status = rb_obj_alloc(rb_cProcessStatus);
00280     rb_iv_set(th->last_status, "status", INT2FIX(status));
00281     rb_iv_set(th->last_status, "pid", PIDT2NUM(pid));
00282 }
00283 
00284 void
00285 rb_last_status_clear(void)
00286 {
00287     GET_THREAD()->last_status = Qnil;
00288 }
00289 
00290 /*
00291  *  call-seq:
00292  *     stat.to_i     -> fixnum
00293  *     stat.to_int   -> fixnum
00294  *
00295  *  Returns the bits in _stat_ as a <code>Fixnum</code>. Poking
00296  *  around in these bits is platform dependent.
00297  *
00298  *     fork { exit 0xab }         #=> 26566
00299  *     Process.wait               #=> 26566
00300  *     sprintf('%04x', $?.to_i)   #=> "ab00"
00301  */
00302 
00303 static VALUE
00304 pst_to_i(VALUE st)
00305 {
00306     return rb_iv_get(st, "status");
00307 }
00308 
00309 #define PST2INT(st) NUM2INT(pst_to_i(st))
00310 
00311 /*
00312  *  call-seq:
00313  *     stat.pid   -> fixnum
00314  *
00315  *  Returns the process ID that this status object represents.
00316  *
00317  *     fork { exit }   #=> 26569
00318  *     Process.wait    #=> 26569
00319  *     $?.pid          #=> 26569
00320  */
00321 
00322 static VALUE
00323 pst_pid(VALUE st)
00324 {
00325     return rb_attr_get(st, rb_intern("pid"));
00326 }
00327 
00328 static void
00329 pst_message(VALUE str, rb_pid_t pid, int status)
00330 {
00331     rb_str_catf(str, "pid %ld", (long)pid);
00332     if (WIFSTOPPED(status)) {
00333         int stopsig = WSTOPSIG(status);
00334         const char *signame = ruby_signal_name(stopsig);
00335         if (signame) {
00336             rb_str_catf(str, " stopped SIG%s (signal %d)", signame, stopsig);
00337         }
00338         else {
00339             rb_str_catf(str, " stopped signal %d", stopsig);
00340         }
00341     }
00342     if (WIFSIGNALED(status)) {
00343         int termsig = WTERMSIG(status);
00344         const char *signame = ruby_signal_name(termsig);
00345         if (signame) {
00346             rb_str_catf(str, " SIG%s (signal %d)", signame, termsig);
00347         }
00348         else {
00349             rb_str_catf(str, " signal %d", termsig);
00350         }
00351     }
00352     if (WIFEXITED(status)) {
00353         rb_str_catf(str, " exit %d", WEXITSTATUS(status));
00354     }
00355 #ifdef WCOREDUMP
00356     if (WCOREDUMP(status)) {
00357         rb_str_cat2(str, " (core dumped)");
00358     }
00359 #endif
00360 }
00361 
00362 
00363 /*
00364  *  call-seq:
00365  *     stat.to_s   -> string
00366  *
00367  *  Show pid and exit status as a string.
00368  *
00369  *    system("false")
00370  *    p $?.to_s         #=> "pid 12766 exit 1"
00371  *
00372  */
00373 
00374 static VALUE
00375 pst_to_s(VALUE st)
00376 {
00377     rb_pid_t pid;
00378     int status;
00379     VALUE str;
00380 
00381     pid = NUM2PIDT(pst_pid(st));
00382     status = PST2INT(st);
00383 
00384     str = rb_str_buf_new(0);
00385     pst_message(str, pid, status);
00386     return str;
00387 }
00388 
00389 
00390 /*
00391  *  call-seq:
00392  *     stat.inspect   -> string
00393  *
00394  *  Override the inspection method.
00395  *
00396  *    system("false")
00397  *    p $?.inspect #=> "#<Process::Status: pid 12861 exit 1>"
00398  *
00399  */
00400 
00401 static VALUE
00402 pst_inspect(VALUE st)
00403 {
00404     rb_pid_t pid;
00405     int status;
00406     VALUE vpid, str;
00407 
00408     vpid = pst_pid(st);
00409     if (NIL_P(vpid)) {
00410         return rb_sprintf("#<%s: uninitialized>", rb_class2name(CLASS_OF(st)));
00411     }
00412     pid = NUM2PIDT(vpid);
00413     status = PST2INT(st);
00414 
00415     str = rb_sprintf("#<%s: ", rb_class2name(CLASS_OF(st)));
00416     pst_message(str, pid, status);
00417     rb_str_cat2(str, ">");
00418     return str;
00419 }
00420 
00421 
00422 /*
00423  *  call-seq:
00424  *     stat == other   -> true or false
00425  *
00426  *  Returns +true+ if the integer value of _stat_
00427  *  equals <em>other</em>.
00428  */
00429 
00430 static VALUE
00431 pst_equal(VALUE st1, VALUE st2)
00432 {
00433     if (st1 == st2) return Qtrue;
00434     return rb_equal(pst_to_i(st1), st2);
00435 }
00436 
00437 
00438 /*
00439  *  call-seq:
00440  *     stat & num   -> fixnum
00441  *
00442  *  Logical AND of the bits in _stat_ with <em>num</em>.
00443  *
00444  *     fork { exit 0x37 }
00445  *     Process.wait
00446  *     sprintf('%04x', $?.to_i)       #=> "3700"
00447  *     sprintf('%04x', $? & 0x1e00)   #=> "1600"
00448  */
00449 
00450 static VALUE
00451 pst_bitand(VALUE st1, VALUE st2)
00452 {
00453     int status = PST2INT(st1) & NUM2INT(st2);
00454 
00455     return INT2NUM(status);
00456 }
00457 
00458 
00459 /*
00460  *  call-seq:
00461  *     stat >> num   -> fixnum
00462  *
00463  *  Shift the bits in _stat_ right <em>num</em> places.
00464  *
00465  *     fork { exit 99 }   #=> 26563
00466  *     Process.wait       #=> 26563
00467  *     $?.to_i            #=> 25344
00468  *     $? >> 8            #=> 99
00469  */
00470 
00471 static VALUE
00472 pst_rshift(VALUE st1, VALUE st2)
00473 {
00474     int status = PST2INT(st1) >> NUM2INT(st2);
00475 
00476     return INT2NUM(status);
00477 }
00478 
00479 
00480 /*
00481  *  call-seq:
00482  *     stat.stopped?   -> true or false
00483  *
00484  *  Returns +true+ if this process is stopped. This is only
00485  *  returned if the corresponding <code>wait</code> call had the
00486  *  <code>WUNTRACED</code> flag set.
00487  */
00488 
00489 static VALUE
00490 pst_wifstopped(VALUE st)
00491 {
00492     int status = PST2INT(st);
00493 
00494     if (WIFSTOPPED(status))
00495         return Qtrue;
00496     else
00497         return Qfalse;
00498 }
00499 
00500 
00501 /*
00502  *  call-seq:
00503  *     stat.stopsig   -> fixnum or nil
00504  *
00505  *  Returns the number of the signal that caused _stat_ to stop
00506  *  (or +nil+ if self is not stopped).
00507  */
00508 
00509 static VALUE
00510 pst_wstopsig(VALUE st)
00511 {
00512     int status = PST2INT(st);
00513 
00514     if (WIFSTOPPED(status))
00515         return INT2NUM(WSTOPSIG(status));
00516     return Qnil;
00517 }
00518 
00519 
00520 /*
00521  *  call-seq:
00522  *     stat.signaled?   -> true or false
00523  *
00524  *  Returns +true+ if _stat_ terminated because of
00525  *  an uncaught signal.
00526  */
00527 
00528 static VALUE
00529 pst_wifsignaled(VALUE st)
00530 {
00531     int status = PST2INT(st);
00532 
00533     if (WIFSIGNALED(status))
00534         return Qtrue;
00535     else
00536         return Qfalse;
00537 }
00538 
00539 
00540 /*
00541  *  call-seq:
00542  *     stat.termsig   -> fixnum or nil
00543  *
00544  *  Returns the number of the signal that caused _stat_ to
00545  *  terminate (or +nil+ if self was not terminated by an
00546  *  uncaught signal).
00547  */
00548 
00549 static VALUE
00550 pst_wtermsig(VALUE st)
00551 {
00552     int status = PST2INT(st);
00553 
00554     if (WIFSIGNALED(status))
00555         return INT2NUM(WTERMSIG(status));
00556     return Qnil;
00557 }
00558 
00559 
00560 /*
00561  *  call-seq:
00562  *     stat.exited?   -> true or false
00563  *
00564  *  Returns +true+ if _stat_ exited normally (for
00565  *  example using an <code>exit()</code> call or finishing the
00566  *  program).
00567  */
00568 
00569 static VALUE
00570 pst_wifexited(VALUE st)
00571 {
00572     int status = PST2INT(st);
00573 
00574     if (WIFEXITED(status))
00575         return Qtrue;
00576     else
00577         return Qfalse;
00578 }
00579 
00580 
00581 /*
00582  *  call-seq:
00583  *     stat.exitstatus   -> fixnum or nil
00584  *
00585  *  Returns the least significant eight bits of the return code of
00586  *  _stat_. Only available if <code>exited?</code> is
00587  *  +true+.
00588  *
00589  *     fork { }           #=> 26572
00590  *     Process.wait       #=> 26572
00591  *     $?.exited?         #=> true
00592  *     $?.exitstatus      #=> 0
00593  *
00594  *     fork { exit 99 }   #=> 26573
00595  *     Process.wait       #=> 26573
00596  *     $?.exited?         #=> true
00597  *     $?.exitstatus      #=> 99
00598  */
00599 
00600 static VALUE
00601 pst_wexitstatus(VALUE st)
00602 {
00603     int status = PST2INT(st);
00604 
00605     if (WIFEXITED(status))
00606         return INT2NUM(WEXITSTATUS(status));
00607     return Qnil;
00608 }
00609 
00610 
00611 /*
00612  *  call-seq:
00613  *     stat.success?   -> true, false or nil
00614  *
00615  *  Returns +true+ if _stat_ is successful, +false+ if not.
00616  *  Returns +nil+ if <code>exited?</code> is not +true+.
00617  */
00618 
00619 static VALUE
00620 pst_success_p(VALUE st)
00621 {
00622     int status = PST2INT(st);
00623 
00624     if (!WIFEXITED(status))
00625         return Qnil;
00626     return WEXITSTATUS(status) == EXIT_SUCCESS ? Qtrue : Qfalse;
00627 }
00628 
00629 
00630 /*
00631  *  call-seq:
00632  *     stat.coredump?   -> true or false
00633  *
00634  *  Returns +true+ if _stat_ generated a coredump
00635  *  when it terminated. Not available on all platforms.
00636  */
00637 
00638 static VALUE
00639 pst_wcoredump(VALUE st)
00640 {
00641 #ifdef WCOREDUMP
00642     int status = PST2INT(st);
00643 
00644     if (WCOREDUMP(status))
00645         return Qtrue;
00646     else
00647         return Qfalse;
00648 #else
00649     return Qfalse;
00650 #endif
00651 }
00652 
00653 #if !defined(HAVE_WAITPID) && !defined(HAVE_WAIT4)
00654 #define NO_WAITPID
00655 static st_table *pid_tbl;
00656 
00657 struct wait_data {
00658     rb_pid_t pid;
00659     int status;
00660 };
00661 
00662 static int
00663 wait_each(rb_pid_t pid, int status, struct wait_data *data)
00664 {
00665     if (data->status != -1) return ST_STOP;
00666 
00667     data->pid = pid;
00668     data->status = status;
00669     return ST_DELETE;
00670 }
00671 
00672 static int
00673 waitall_each(rb_pid_t pid, int status, VALUE ary)
00674 {
00675     rb_last_status_set(status, pid);
00676     rb_ary_push(ary, rb_assoc_new(PIDT2NUM(pid), rb_last_status_get()));
00677     return ST_DELETE;
00678 }
00679 #else
00680 struct waitpid_arg {
00681     rb_pid_t pid;
00682     int *st;
00683     int flags;
00684 };
00685 #endif
00686 
00687 static void *
00688 rb_waitpid_blocking(void *data)
00689 {
00690     rb_pid_t result;
00691 #ifndef NO_WAITPID
00692     struct waitpid_arg *arg = data;
00693 #endif
00694 
00695 #if defined NO_WAITPID
00696     result = wait(data);
00697 #elif defined HAVE_WAITPID
00698     result = waitpid(arg->pid, arg->st, arg->flags);
00699 #else  /* HAVE_WAIT4 */
00700     result = wait4(arg->pid, arg->st, arg->flags, NULL);
00701 #endif
00702 
00703     return (void *)(VALUE)result;
00704 }
00705 
00706 rb_pid_t
00707 rb_waitpid(rb_pid_t pid, int *st, int flags)
00708 {
00709     rb_pid_t result;
00710 #ifndef NO_WAITPID
00711     struct waitpid_arg arg;
00712 
00713   retry:
00714     arg.pid = pid;
00715     arg.st = st;
00716     arg.flags = flags;
00717     result = (rb_pid_t)(VALUE)rb_thread_call_without_gvl(rb_waitpid_blocking, &arg,
00718                                                          RUBY_UBF_PROCESS, 0);
00719     if (result < 0) {
00720         if (errno == EINTR) {
00721             RUBY_VM_CHECK_INTS(GET_THREAD());
00722             goto retry;
00723         }
00724         return (rb_pid_t)-1;
00725     }
00726 #else  /* NO_WAITPID */
00727     if (pid_tbl) {
00728         st_data_t status, piddata = (st_data_t)pid;
00729         if (pid == (rb_pid_t)-1) {
00730             struct wait_data data;
00731             data.pid = (rb_pid_t)-1;
00732             data.status = -1;
00733             st_foreach(pid_tbl, wait_each, (st_data_t)&data);
00734             if (data.status != -1) {
00735                 rb_last_status_set(data.status, data.pid);
00736                 return data.pid;
00737             }
00738         }
00739         else if (st_delete(pid_tbl, &piddata, &status)) {
00740             rb_last_status_set(*st = (int)status, pid);
00741             return pid;
00742         }
00743     }
00744 
00745     if (flags) {
00746         rb_raise(rb_eArgError, "can't do waitpid with flags");
00747     }
00748 
00749     for (;;) {
00750         result = (rb_pid_t)(VALUE)rb_thread_blocking_region(rb_waitpid_blocking,
00751                                                             st, RUBY_UBF_PROCESS, 0);
00752         if (result < 0) {
00753             if (errno == EINTR) {
00754                 rb_thread_schedule();
00755                 continue;
00756             }
00757             return (rb_pid_t)-1;
00758         }
00759         if (result == pid || pid == (rb_pid_t)-1) {
00760             break;
00761         }
00762         if (!pid_tbl)
00763             pid_tbl = st_init_numtable();
00764         st_insert(pid_tbl, pid, (st_data_t)st);
00765         if (!rb_thread_alone()) rb_thread_schedule();
00766     }
00767 #endif
00768     if (result > 0) {
00769         rb_last_status_set(*st, result);
00770     }
00771     return result;
00772 }
00773 
00774 
00775 /* [MG]:FIXME: I wasn't sure how this should be done, since ::wait()
00776    has historically been documented as if it didn't take any arguments
00777    despite the fact that it's just an alias for ::waitpid(). The way I
00778    have it below is more truthful, but a little confusing.
00779 
00780    I also took the liberty of putting in the pid values, as they're
00781    pretty useful, and it looked as if the original 'ri' output was
00782    supposed to contain them after "[...]depending on the value of
00783    aPid:".
00784 
00785    The 'ansi' and 'bs' formats of the ri output don't display the
00786    definition list for some reason, but the plain text one does.
00787  */
00788 
00789 /*
00790  *  call-seq:
00791  *     Process.wait()                     -> fixnum
00792  *     Process.wait(pid=-1, flags=0)      -> fixnum
00793  *     Process.waitpid(pid=-1, flags=0)   -> fixnum
00794  *
00795  *  Waits for a child process to exit, returns its process id, and
00796  *  sets <code>$?</code> to a <code>Process::Status</code> object
00797  *  containing information on that process. Which child it waits on
00798  *  depends on the value of _pid_:
00799  *
00800  *  > 0::   Waits for the child whose process ID equals _pid_.
00801  *
00802  *  0::     Waits for any child whose process group ID equals that of the
00803  *          calling process.
00804  *
00805  *  -1::    Waits for any child process (the default if no _pid_ is
00806  *          given).
00807  *
00808  *  < -1::  Waits for any child whose process group ID equals the absolute
00809  *          value of _pid_.
00810  *
00811  *  The _flags_ argument may be a logical or of the flag values
00812  *  <code>Process::WNOHANG</code> (do not block if no child available)
00813  *  or <code>Process::WUNTRACED</code> (return stopped children that
00814  *  haven't been reported). Not all flags are available on all
00815  *  platforms, but a flag value of zero will work on all platforms.
00816  *
00817  *  Calling this method raises a SystemCallError if there are no child
00818  *  processes. Not available on all platforms.
00819  *
00820  *     include Process
00821  *     fork { exit 99 }                 #=> 27429
00822  *     wait                             #=> 27429
00823  *     $?.exitstatus                    #=> 99
00824  *
00825  *     pid = fork { sleep 3 }           #=> 27440
00826  *     Time.now                         #=> 2008-03-08 19:56:16 +0900
00827  *     waitpid(pid, Process::WNOHANG)   #=> nil
00828  *     Time.now                         #=> 2008-03-08 19:56:16 +0900
00829  *     waitpid(pid, 0)                  #=> 27440
00830  *     Time.now                         #=> 2008-03-08 19:56:19 +0900
00831  */
00832 
00833 static VALUE
00834 proc_wait(int argc, VALUE *argv)
00835 {
00836     VALUE vpid, vflags;
00837     rb_pid_t pid;
00838     int flags, status;
00839 
00840     rb_secure(2);
00841     flags = 0;
00842     if (argc == 0) {
00843         pid = -1;
00844     }
00845     else {
00846         rb_scan_args(argc, argv, "02", &vpid, &vflags);
00847         pid = NUM2PIDT(vpid);
00848         if (argc == 2 && !NIL_P(vflags)) {
00849             flags = NUM2UINT(vflags);
00850         }
00851     }
00852     if ((pid = rb_waitpid(pid, &status, flags)) < 0)
00853         rb_sys_fail(0);
00854     if (pid == 0) {
00855         rb_last_status_clear();
00856         return Qnil;
00857     }
00858     return PIDT2NUM(pid);
00859 }
00860 
00861 
00862 /*
00863  *  call-seq:
00864  *     Process.wait2(pid=-1, flags=0)      -> [pid, status]
00865  *     Process.waitpid2(pid=-1, flags=0)   -> [pid, status]
00866  *
00867  *  Waits for a child process to exit (see Process::waitpid for exact
00868  *  semantics) and returns an array containing the process id and the
00869  *  exit status (a <code>Process::Status</code> object) of that
00870  *  child. Raises a SystemCallError if there are no child processes.
00871  *
00872  *     Process.fork { exit 99 }   #=> 27437
00873  *     pid, status = Process.wait2
00874  *     pid                        #=> 27437
00875  *     status.exitstatus          #=> 99
00876  */
00877 
00878 static VALUE
00879 proc_wait2(int argc, VALUE *argv)
00880 {
00881     VALUE pid = proc_wait(argc, argv);
00882     if (NIL_P(pid)) return Qnil;
00883     return rb_assoc_new(pid, rb_last_status_get());
00884 }
00885 
00886 
00887 /*
00888  *  call-seq:
00889  *     Process.waitall   -> [ [pid1,status1], ...]
00890  *
00891  *  Waits for all children, returning an array of
00892  *  _pid_/_status_ pairs (where _status_ is a
00893  *  <code>Process::Status</code> object).
00894  *
00895  *     fork { sleep 0.2; exit 2 }   #=> 27432
00896  *     fork { sleep 0.1; exit 1 }   #=> 27433
00897  *     fork {            exit 0 }   #=> 27434
00898  *     p Process.waitall
00899  *
00900  *  <em>produces</em>:
00901  *
00902  *     [[30982, #<Process::Status: pid 30982 exit 0>],
00903  *      [30979, #<Process::Status: pid 30979 exit 1>],
00904  *      [30976, #<Process::Status: pid 30976 exit 2>]]
00905  */
00906 
00907 static VALUE
00908 proc_waitall(void)
00909 {
00910     VALUE result;
00911     rb_pid_t pid;
00912     int status;
00913 
00914     rb_secure(2);
00915     result = rb_ary_new();
00916 #ifdef NO_WAITPID
00917     if (pid_tbl) {
00918         st_foreach(pid_tbl, waitall_each, result);
00919     }
00920 #else
00921     rb_last_status_clear();
00922 #endif
00923 
00924     for (pid = -1;;) {
00925 #ifdef NO_WAITPID
00926         pid = wait(&status);
00927 #else
00928         pid = rb_waitpid(-1, &status, 0);
00929 #endif
00930         if (pid == -1) {
00931             if (errno == ECHILD)
00932                 break;
00933 #ifdef NO_WAITPID
00934             if (errno == EINTR) {
00935                 rb_thread_schedule();
00936                 continue;
00937             }
00938 #endif
00939             rb_sys_fail(0);
00940         }
00941 #ifdef NO_WAITPID
00942         rb_last_status_set(status, pid);
00943 #endif
00944         rb_ary_push(result, rb_assoc_new(PIDT2NUM(pid), rb_last_status_get()));
00945     }
00946     return result;
00947 }
00948 
00949 static inline ID
00950 id_pid(void)
00951 {
00952     ID pid;
00953     CONST_ID(pid, "pid");
00954     return pid;
00955 }
00956 
00957 static VALUE
00958 detach_process_pid(VALUE thread)
00959 {
00960     return rb_thread_local_aref(thread, id_pid());
00961 }
00962 
00963 static VALUE
00964 detach_process_watcher(void *arg)
00965 {
00966     rb_pid_t cpid, pid = (rb_pid_t)(VALUE)arg;
00967     int status;
00968 
00969     while ((cpid = rb_waitpid(pid, &status, 0)) == 0) {
00970         /* wait while alive */
00971     }
00972     return rb_last_status_get();
00973 }
00974 
00975 VALUE
00976 rb_detach_process(rb_pid_t pid)
00977 {
00978     VALUE watcher = rb_thread_create(detach_process_watcher, (void*)(VALUE)pid);
00979     rb_thread_local_aset(watcher, id_pid(), PIDT2NUM(pid));
00980     rb_define_singleton_method(watcher, "pid", detach_process_pid, 0);
00981     return watcher;
00982 }
00983 
00984 
00985 /*
00986  *  call-seq:
00987  *     Process.detach(pid)   -> thread
00988  *
00989  *  Some operating systems retain the status of terminated child
00990  *  processes until the parent collects that status (normally using
00991  *  some variant of <code>wait()</code>. If the parent never collects
00992  *  this status, the child stays around as a <em>zombie</em> process.
00993  *  <code>Process::detach</code> prevents this by setting up a
00994  *  separate Ruby thread whose sole job is to reap the status of the
00995  *  process _pid_ when it terminates. Use <code>detach</code>
00996  *  only when you do not intent to explicitly wait for the child to
00997  *  terminate.
00998  *
00999  *  The waiting thread returns the exit status of the detached process
01000  *  when it terminates, so you can use <code>Thread#join</code> to
01001  *  know the result.  If specified _pid_ is not a valid child process
01002  *  ID, the thread returns +nil+ immediately.
01003  *
01004  *  The waiting thread has <code>pid</code> method which returns the pid.
01005  *
01006  *  In this first example, we don't reap the first child process, so
01007  *  it appears as a zombie in the process status display.
01008  *
01009  *     p1 = fork { sleep 0.1 }
01010  *     p2 = fork { sleep 0.2 }
01011  *     Process.waitpid(p2)
01012  *     sleep 2
01013  *     system("ps -ho pid,state -p #{p1}")
01014  *
01015  *  <em>produces:</em>
01016  *
01017  *     27389 Z
01018  *
01019  *  In the next example, <code>Process::detach</code> is used to reap
01020  *  the child automatically.
01021  *
01022  *     p1 = fork { sleep 0.1 }
01023  *     p2 = fork { sleep 0.2 }
01024  *     Process.detach(p1)
01025  *     Process.waitpid(p2)
01026  *     sleep 2
01027  *     system("ps -ho pid,state -p #{p1}")
01028  *
01029  *  <em>(produces no output)</em>
01030  */
01031 
01032 static VALUE
01033 proc_detach(VALUE obj, VALUE pid)
01034 {
01035     rb_secure(2);
01036     return rb_detach_process(NUM2PIDT(pid));
01037 }
01038 
01039 static int forked_child = 0;
01040 
01041 #ifdef SIGPIPE
01042 static RETSIGTYPE (*saved_sigpipe_handler)(int) = 0;
01043 #endif
01044 
01045 #ifdef SIGPIPE
01046 static RETSIGTYPE
01047 sig_do_nothing(int sig)
01048 {
01049 }
01050 #endif
01051 
01052 /* This function should be async-signal-safe.  Actually it is. */
01053 static void
01054 before_exec_async_signal_safe(void)
01055 {
01056 #ifdef SIGPIPE
01057     /*
01058      * Some OS commands don't initialize signal handler properly. Thus we have
01059      * to reset signal handler before exec(). Otherwise, system() and similar
01060      * child process interaction might fail. (e.g. ruby -e "system 'yes | ls'")
01061      * [ruby-dev:12261]
01062      */
01063     saved_sigpipe_handler = signal(SIGPIPE, sig_do_nothing); /* async-signal-safe */
01064 #endif
01065 }
01066 
01067 static void
01068 before_exec_non_async_signal_safe(void)
01069 {
01070     if (!forked_child) {
01071         /*
01072          * On Mac OS X 10.5.x (Leopard) or earlier, exec() may return ENOTSUPP
01073          * if the process have multiple threads. Therefore we have to kill
01074          * internal threads temporary. [ruby-core:10583]
01075          * This is also true on Haiku. It returns Errno::EPERM against exec()
01076          * in multiple threads.
01077          */
01078         rb_thread_stop_timer_thread(0);
01079     }
01080 }
01081 
01082 static void
01083 before_exec(void)
01084 {
01085     before_exec_non_async_signal_safe();
01086     before_exec_async_signal_safe();
01087 }
01088 
01089 /* This function should be async-signal-safe.  Actually it is. */
01090 static void
01091 after_exec_async_signal_safe(void)
01092 {
01093 #ifdef SIGPIPE
01094     signal(SIGPIPE, saved_sigpipe_handler); /* async-signal-safe */
01095 #endif
01096 }
01097 
01098 static void
01099 after_exec_non_async_signal_safe(void)
01100 {
01101     rb_thread_reset_timer_thread();
01102     rb_thread_start_timer_thread();
01103 
01104     forked_child = 0;
01105 }
01106 
01107 static void
01108 after_exec(void)
01109 {
01110     after_exec_async_signal_safe();
01111     after_exec_non_async_signal_safe();
01112 }
01113 
01114 #define before_fork() before_exec()
01115 #define after_fork() (rb_threadptr_pending_interrupt_clear(GET_THREAD()), after_exec())
01116 
01117 #include "dln.h"
01118 
01119 static void
01120 security(const char *str)
01121 {
01122     if (rb_env_path_tainted()) {
01123         if (rb_safe_level() > 0) {
01124             rb_raise(rb_eSecurityError, "Insecure PATH - %s", str);
01125         }
01126     }
01127 }
01128 
01129 #if defined(HAVE_FORK) && !defined(__native_client__)
01130 
01131 /* try_with_sh and exec_with_sh should be async-signal-safe. Actually it is.*/
01132 #define try_with_sh(prog, argv, envp) ((saved_errno == ENOEXEC) ? exec_with_sh((prog), (argv), (envp)) : (void)0)
01133 static void
01134 exec_with_sh(const char *prog, char **argv, char **envp)
01135 {
01136     *argv = (char *)prog;
01137     *--argv = (char *)"sh";
01138     if (envp)
01139         execve("/bin/sh", argv, envp); /* async-signal-safe */
01140     else
01141         execv("/bin/sh", argv); /* async-signal-safe */
01142 }
01143 
01144 #else
01145 #define try_with_sh(prog, argv, envp) (void)0
01146 #endif
01147 
01148 /* This function should be async-signal-safe.  Actually it is. */
01149 static int
01150 proc_exec_cmd(const char *prog, VALUE argv_str, VALUE envp_str)
01151 {
01152 #ifdef __native_client__
01153     rb_notimplement();
01154     UNREACHABLE;
01155 #else
01156     char **argv;
01157     char **envp;
01158 # if defined(__EMX__) || defined(OS2)
01159     char **new_argv = NULL;
01160 # endif
01161 
01162     argv = ARGVSTR2ARGV(argv_str);
01163 
01164     if (!prog) {
01165         errno = ENOENT;
01166         return -1;
01167     }
01168 
01169 # if defined(__EMX__) || defined(OS2)
01170     {
01171 #  define COMMAND "cmd.exe"
01172         char *extension;
01173 
01174         if ((extension = strrchr(prog, '.')) != NULL && STRCASECMP(extension, ".bat") == 0) {
01175             char *p;
01176             int n;
01177 
01178             for (n = 0; argv[n]; n++)
01179                 /* no-op */;
01180             new_argv = ALLOC_N(char*, n + 2);
01181             for (; n > 0; n--)
01182                 new_argv[n + 1] = argv[n];
01183             new_argv[1] = strcpy(ALLOC_N(char, strlen(argv[0]) + 1), argv[0]);
01184             for (p = new_argv[1]; *p != '\0'; p++)
01185                 if (*p == '/')
01186                     *p = '\\';
01187             new_argv[0] = COMMAND;
01188             argv = new_argv;
01189             prog = dln_find_exe_r(argv[0], 0, fbuf, sizeof(fbuf));
01190             if (!prog) {
01191                 errno = ENOENT;
01192                 return -1;
01193             }
01194         }
01195     }
01196 # endif /* __EMX__ */
01197     envp = envp_str ? (char **)RSTRING_PTR(envp_str) : NULL;
01198     if (envp_str)
01199         execve(prog, argv, envp); /* async-signal-safe */
01200     else
01201         execv(prog, argv); /* async-signal-safe */
01202     preserving_errno(try_with_sh(prog, argv, envp)); /* try_with_sh() is async-signal-safe. */
01203 # if defined(__EMX__) || defined(OS2)
01204     if (new_argv) {
01205         xfree(new_argv[0]);
01206         xfree(new_argv);
01207     }
01208 # endif
01209     return -1;
01210 #endif
01211 }
01212 
01213 /* deprecated */
01214 static int
01215 proc_exec_v(char **argv, const char *prog)
01216 {
01217     char fbuf[MAXPATHLEN];
01218 
01219     if (!prog)
01220         prog = argv[0];
01221     prog = dln_find_exe_r(prog, 0, fbuf, sizeof(fbuf));
01222     if (!prog) {
01223         errno = ENOENT;
01224         return -1;
01225     }
01226     before_exec();
01227     execv(prog, argv);
01228     preserving_errno(try_with_sh(prog, argv, 0); after_exec());
01229     return -1;
01230 }
01231 
01232 /* deprecated */
01233 int
01234 rb_proc_exec_n(int argc, VALUE *argv, const char *prog)
01235 {
01236 #define ARGV_COUNT(n) ((n)+1)
01237 #define ARGV_SIZE(n) (sizeof(char*) * ARGV_COUNT(n))
01238 #define ALLOC_ARGV(n, v) ALLOCV_N(char*, (v), ARGV_COUNT(n))
01239 
01240     char **args;
01241     int i;
01242     int ret = -1;
01243     VALUE v;
01244 
01245     args = ALLOC_ARGV(argc+1, v);
01246     for (i=0; i<argc; i++) {
01247         args[i] = RSTRING_PTR(argv[i]);
01248     }
01249     args[i] = 0;
01250     if (args[0]) {
01251         ret = proc_exec_v(args, prog);
01252     }
01253     ALLOCV_END(v);
01254     return ret;
01255 
01256 #undef ARGV_COUNT
01257 #undef ARGV_SIZE
01258 #undef ALLOC_ARGV
01259 }
01260 
01261 /* This function should be async-signal-safe.  Actually it is. */
01262 static int
01263 proc_exec_sh(const char *str, VALUE envp_str)
01264 {
01265 #ifdef __native_client__
01266     rb_notimplement();
01267     UNREACHABLE;
01268 #else
01269     const char *s;
01270 
01271     s = str;
01272     while (*s == ' ' || *s == '\t' || *s == '\n')
01273         s++;
01274 
01275     if (!*s) {
01276         errno = ENOENT;
01277         return -1;
01278     }
01279 
01280 #ifdef _WIN32
01281     rb_w32_spawn(P_OVERLAY, (char *)str, 0);
01282     return -1;
01283 #else
01284 #if defined(__CYGWIN32__) || defined(__EMX__)
01285     {
01286         char fbuf[MAXPATHLEN];
01287         char *shell = dln_find_exe_r("sh", 0, fbuf, sizeof(fbuf));
01288         int status = -1;
01289         if (shell)
01290             execl(shell, "sh", "-c", str, (char *) NULL);
01291         else
01292             status = system(str);
01293         if (status != -1)
01294             exit(status);
01295     }
01296 #else
01297     if (envp_str)
01298         execle("/bin/sh", "sh", "-c", str, (char *)NULL, (char **)RSTRING_PTR(envp_str)); /* async-signal-safe */
01299     else
01300         execl("/bin/sh", "sh", "-c", str, (char *)NULL); /* async-signal-safe */
01301 #endif
01302     return -1;
01303 #endif  /* _WIN32 */
01304 #endif
01305 }
01306 
01307 int
01308 rb_proc_exec(const char *str)
01309 {
01310     int ret;
01311     before_exec();
01312     ret = proc_exec_sh(str, Qfalse);
01313     preserving_errno(after_exec());
01314     return ret;
01315 }
01316 
01317 static void
01318 mark_exec_arg(void *ptr)
01319 {
01320     struct rb_execarg *eargp = ptr;
01321     if (eargp->use_shell)
01322         rb_gc_mark(eargp->invoke.sh.shell_script);
01323     else {
01324         rb_gc_mark(eargp->invoke.cmd.command_name);
01325         rb_gc_mark(eargp->invoke.cmd.command_abspath);
01326         rb_gc_mark(eargp->invoke.cmd.argv_str);
01327         rb_gc_mark(eargp->invoke.cmd.argv_buf);
01328     }
01329     rb_gc_mark(eargp->redirect_fds);
01330     rb_gc_mark(eargp->envp_str);
01331     rb_gc_mark(eargp->envp_buf);
01332     rb_gc_mark(eargp->dup2_tmpbuf);
01333     rb_gc_mark(eargp->rlimit_limits);
01334     rb_gc_mark(eargp->fd_dup2);
01335     rb_gc_mark(eargp->fd_close);
01336     rb_gc_mark(eargp->fd_open);
01337     rb_gc_mark(eargp->fd_dup2_child);
01338     rb_gc_mark(eargp->env_modification);
01339     rb_gc_mark(eargp->chdir_dir);
01340 }
01341 
01342 static void
01343 free_exec_arg(void *ptr)
01344 {
01345     xfree(ptr);
01346 }
01347 
01348 static size_t
01349 memsize_exec_arg(const void *ptr)
01350 {
01351     return ptr ? sizeof(struct rb_execarg) : 0;
01352 }
01353 
01354 static const rb_data_type_t exec_arg_data_type = {
01355   "exec_arg",
01356   {mark_exec_arg, free_exec_arg, memsize_exec_arg},
01357 };
01358 
01359 #if defined(_WIN32)
01360 #define HAVE_SPAWNV 1
01361 #endif
01362 
01363 #if !defined(HAVE_FORK) && defined(HAVE_SPAWNV)
01364 # define USE_SPAWNV 1
01365 #else
01366 # define USE_SPAWNV 0
01367 #endif
01368 #ifndef P_NOWAIT
01369 # define P_NOWAIT _P_NOWAIT
01370 #endif
01371 
01372 #if USE_SPAWNV
01373 #if defined(_WIN32)
01374 #define proc_spawn_cmd_internal(argv, prog) rb_w32_aspawn(P_NOWAIT, (prog), (argv))
01375 #else
01376 static rb_pid_t
01377 proc_spawn_cmd_internal(char **argv, char *prog)
01378 {
01379     char fbuf[MAXPATHLEN];
01380     rb_pid_t status;
01381 
01382     if (!prog)
01383         prog = argv[0];
01384     security(prog);
01385     prog = dln_find_exe_r(prog, 0, fbuf, sizeof(fbuf));
01386     if (!prog)
01387         return -1;
01388 
01389     before_exec();
01390     status = spawnv(P_NOWAIT, prog, (const char **)argv);
01391     if (status == -1 && errno == ENOEXEC) {
01392         *argv = (char *)prog;
01393         *--argv = (char *)"sh";
01394         status = spawnv(P_NOWAIT, "/bin/sh", (const char **)argv);
01395         after_exec();
01396         if (status == -1) errno = ENOEXEC;
01397     }
01398     rb_last_status_set(status == -1 ? 127 : status, 0);
01399     return status;
01400 }
01401 #endif
01402 
01403 static rb_pid_t
01404 proc_spawn_cmd(char **argv, VALUE prog, struct rb_execarg *eargp)
01405 {
01406     rb_pid_t pid = -1;
01407 
01408     if (argv[0]) {
01409 #if defined(_WIN32)
01410         DWORD flags = 0;
01411         if (eargp->new_pgroup_given && eargp->new_pgroup_flag) {
01412             flags = CREATE_NEW_PROCESS_GROUP;
01413         }
01414         pid = rb_w32_aspawn_flags(P_NOWAIT, prog ? RSTRING_PTR(prog) : 0, argv, flags);
01415 #else
01416         pid = proc_spawn_cmd_internal(argv, prog ? RSTRING_PTR(prog) : 0);
01417 #endif
01418     }
01419     return pid;
01420 }
01421 
01422 #if defined(_WIN32)
01423 #define proc_spawn_sh(str) rb_w32_spawn(P_NOWAIT, (str), 0)
01424 #else
01425 static rb_pid_t
01426 proc_spawn_sh(char *str)
01427 {
01428     char fbuf[MAXPATHLEN];
01429     rb_pid_t status;
01430 
01431     char *shell = dln_find_exe_r("sh", 0, fbuf, sizeof(fbuf));
01432     before_exec();
01433     status = spawnl(P_NOWAIT, (shell ? shell : "/bin/sh"), "sh", "-c", str, (char*)NULL);
01434     rb_last_status_set(status == -1 ? 127 : status, 0);
01435     after_exec();
01436     return status;
01437 }
01438 #endif
01439 #endif
01440 
01441 static VALUE
01442 hide_obj(VALUE obj)
01443 {
01444     RBASIC(obj)->klass = 0;
01445     return obj;
01446 }
01447 
01448 static VALUE
01449 check_exec_redirect_fd(VALUE v, int iskey)
01450 {
01451     VALUE tmp;
01452     int fd;
01453     if (FIXNUM_P(v)) {
01454         fd = FIX2INT(v);
01455     }
01456     else if (SYMBOL_P(v)) {
01457         ID id = SYM2ID(v);
01458         if (id == rb_intern("in"))
01459             fd = 0;
01460         else if (id == rb_intern("out"))
01461             fd = 1;
01462         else if (id == rb_intern("err"))
01463             fd = 2;
01464         else
01465             goto wrong;
01466     }
01467     else if (!NIL_P(tmp = rb_check_convert_type(v, T_FILE, "IO", "to_io"))) {
01468         rb_io_t *fptr;
01469         GetOpenFile(tmp, fptr);
01470         if (fptr->tied_io_for_writing)
01471             rb_raise(rb_eArgError, "duplex IO redirection");
01472         fd = fptr->fd;
01473     }
01474     else {
01475         rb_raise(rb_eArgError, "wrong exec redirect");
01476     }
01477     if (fd < 0) {
01478       wrong:
01479         rb_raise(rb_eArgError, "negative file descriptor");
01480     }
01481 #ifdef _WIN32
01482     else if (fd >= 3 && iskey) {
01483         rb_raise(rb_eArgError, "wrong file descriptor (%d)", fd);
01484     }
01485 #endif
01486     return INT2FIX(fd);
01487 }
01488 
01489 static VALUE
01490 check_exec_redirect1(VALUE ary, VALUE key, VALUE param)
01491 {
01492     if (ary == Qfalse) {
01493         ary = hide_obj(rb_ary_new());
01494     }
01495     if (!RB_TYPE_P(key, T_ARRAY)) {
01496         VALUE fd = check_exec_redirect_fd(key, !NIL_P(param));
01497         rb_ary_push(ary, hide_obj(rb_assoc_new(fd, param)));
01498     }
01499     else {
01500         int i, n=0;
01501         for (i = 0 ; i < RARRAY_LEN(key); i++) {
01502             VALUE v = RARRAY_PTR(key)[i];
01503             VALUE fd = check_exec_redirect_fd(v, !NIL_P(param));
01504             rb_ary_push(ary, hide_obj(rb_assoc_new(fd, param)));
01505             n++;
01506         }
01507     }
01508     return ary;
01509 }
01510 
01511 static void
01512 check_exec_redirect(VALUE key, VALUE val, struct rb_execarg *eargp)
01513 {
01514     VALUE param;
01515     VALUE path, flags, perm;
01516     VALUE tmp;
01517     ID id;
01518 
01519     switch (TYPE(val)) {
01520       case T_SYMBOL:
01521         id = SYM2ID(val);
01522         if (id == rb_intern("close")) {
01523             param = Qnil;
01524             eargp->fd_close = check_exec_redirect1(eargp->fd_close, key, param);
01525         }
01526         else if (id == rb_intern("in")) {
01527             param = INT2FIX(0);
01528             eargp->fd_dup2 = check_exec_redirect1(eargp->fd_dup2, key, param);
01529         }
01530         else if (id == rb_intern("out")) {
01531             param = INT2FIX(1);
01532             eargp->fd_dup2 = check_exec_redirect1(eargp->fd_dup2, key, param);
01533         }
01534         else if (id == rb_intern("err")) {
01535             param = INT2FIX(2);
01536             eargp->fd_dup2 = check_exec_redirect1(eargp->fd_dup2, key, param);
01537         }
01538         else {
01539             rb_raise(rb_eArgError, "wrong exec redirect symbol: %s",
01540                                    rb_id2name(id));
01541         }
01542         break;
01543 
01544       case T_FILE:
01545       io:
01546         val = check_exec_redirect_fd(val, 0);
01547         /* fall through */
01548       case T_FIXNUM:
01549         param = val;
01550         eargp->fd_dup2 = check_exec_redirect1(eargp->fd_dup2, key, param);
01551         break;
01552 
01553       case T_ARRAY:
01554         path = rb_ary_entry(val, 0);
01555         if (RARRAY_LEN(val) == 2 && SYMBOL_P(path) &&
01556             SYM2ID(path) == rb_intern("child")) {
01557             param = check_exec_redirect_fd(rb_ary_entry(val, 1), 0);
01558             eargp->fd_dup2_child = check_exec_redirect1(eargp->fd_dup2_child, key, param);
01559         }
01560         else {
01561             FilePathValue(path);
01562             flags = rb_ary_entry(val, 1);
01563             if (NIL_P(flags))
01564                 flags = INT2NUM(O_RDONLY);
01565             else if (RB_TYPE_P(flags, T_STRING))
01566                 flags = INT2NUM(rb_io_modestr_oflags(StringValueCStr(flags)));
01567             else
01568                 flags = rb_to_int(flags);
01569             perm = rb_ary_entry(val, 2);
01570             perm = NIL_P(perm) ? INT2FIX(0644) : rb_to_int(perm);
01571             param = hide_obj(rb_ary_new3(3, hide_obj(rb_str_dup(path)),
01572                                             flags, perm));
01573             eargp->fd_open = check_exec_redirect1(eargp->fd_open, key, param);
01574         }
01575         break;
01576 
01577       case T_STRING:
01578         path = val;
01579         FilePathValue(path);
01580         if (RB_TYPE_P(key, T_FILE))
01581             key = check_exec_redirect_fd(key, 1);
01582         if (FIXNUM_P(key) && (FIX2INT(key) == 1 || FIX2INT(key) == 2))
01583             flags = INT2NUM(O_WRONLY|O_CREAT|O_TRUNC);
01584         else
01585             flags = INT2NUM(O_RDONLY);
01586         perm = INT2FIX(0644);
01587         param = hide_obj(rb_ary_new3(3, hide_obj(rb_str_dup(path)),
01588                                         flags, perm));
01589         eargp->fd_open = check_exec_redirect1(eargp->fd_open, key, param);
01590         break;
01591 
01592       default:
01593         tmp = val;
01594         val = rb_io_check_io(tmp);
01595         if (!NIL_P(val)) goto io;
01596         rb_raise(rb_eArgError, "wrong exec redirect action");
01597     }
01598 
01599 }
01600 
01601 #if defined(HAVE_SETRLIMIT) && defined(NUM2RLIM)
01602 static int rlimit_type_by_lname(const char *name);
01603 #endif
01604 
01605 int
01606 rb_execarg_addopt(VALUE execarg_obj, VALUE key, VALUE val)
01607 {
01608     struct rb_execarg *eargp = rb_execarg_get(execarg_obj);
01609 
01610     ID id;
01611 #if defined(HAVE_SETRLIMIT) && defined(NUM2RLIM)
01612     int rtype;
01613 #endif
01614 
01615     rb_secure(2);
01616 
01617     switch (TYPE(key)) {
01618       case T_SYMBOL:
01619         id = SYM2ID(key);
01620 #ifdef HAVE_SETPGID
01621         if (id == rb_intern("pgroup")) {
01622             pid_t pgroup;
01623             if (eargp->pgroup_given) {
01624                 rb_raise(rb_eArgError, "pgroup option specified twice");
01625             }
01626             if (!RTEST(val))
01627                 pgroup = -1; /* asis(-1) means "don't call setpgid()". */
01628             else if (val == Qtrue)
01629                 pgroup = 0; /* new process group. */
01630             else {
01631                 pgroup = NUM2PIDT(val);
01632                 if (pgroup < 0) {
01633                     rb_raise(rb_eArgError, "negative process group ID : %ld", (long)pgroup);
01634                 }
01635             }
01636             eargp->pgroup_given = 1;
01637             eargp->pgroup_pgid = pgroup;
01638         }
01639         else
01640 #endif
01641 #ifdef _WIN32
01642         if (id == rb_intern("new_pgroup")) {
01643             if (eargp->new_pgroup_given) {
01644                 rb_raise(rb_eArgError, "new_pgroup option specified twice");
01645             }
01646             eargp->new_pgroup_given = 1;
01647             eargp->new_pgroup_flag = RTEST(val) ? 1 : 0;
01648         }
01649         else
01650 #endif
01651 #if defined(HAVE_SETRLIMIT) && defined(NUM2RLIM)
01652         if (strncmp("rlimit_", rb_id2name(id), 7) == 0 &&
01653             (rtype = rlimit_type_by_lname(rb_id2name(id)+7)) != -1) {
01654             VALUE ary = eargp->rlimit_limits;
01655             VALUE tmp, softlim, hardlim;
01656             if (eargp->rlimit_limits == Qfalse)
01657                 ary = eargp->rlimit_limits = hide_obj(rb_ary_new());
01658             else
01659                 ary = eargp->rlimit_limits;
01660             tmp = rb_check_array_type(val);
01661             if (!NIL_P(tmp)) {
01662                 if (RARRAY_LEN(tmp) == 1)
01663                     softlim = hardlim = rb_to_int(rb_ary_entry(tmp, 0));
01664                 else if (RARRAY_LEN(tmp) == 2) {
01665                     softlim = rb_to_int(rb_ary_entry(tmp, 0));
01666                     hardlim = rb_to_int(rb_ary_entry(tmp, 1));
01667                 }
01668                 else {
01669                     rb_raise(rb_eArgError, "wrong exec rlimit option");
01670                 }
01671             }
01672             else {
01673                 softlim = hardlim = rb_to_int(val);
01674             }
01675             tmp = hide_obj(rb_ary_new3(3, INT2NUM(rtype), softlim, hardlim));
01676             rb_ary_push(ary, tmp);
01677         }
01678         else
01679 #endif
01680         if (id == rb_intern("unsetenv_others")) {
01681             if (eargp->unsetenv_others_given) {
01682                 rb_raise(rb_eArgError, "unsetenv_others option specified twice");
01683             }
01684             eargp->unsetenv_others_given = 1;
01685             eargp->unsetenv_others_do = RTEST(val) ? 1 : 0;
01686         }
01687         else if (id == rb_intern("chdir")) {
01688             if (eargp->chdir_given) {
01689                 rb_raise(rb_eArgError, "chdir option specified twice");
01690             }
01691             FilePathValue(val);
01692             eargp->chdir_given = 1;
01693             eargp->chdir_dir = hide_obj(rb_str_dup(val));
01694         }
01695         else if (id == rb_intern("umask")) {
01696             mode_t cmask = NUM2MODET(val);
01697             if (eargp->umask_given) {
01698                 rb_raise(rb_eArgError, "umask option specified twice");
01699             }
01700             eargp->umask_given = 1;
01701             eargp->umask_mask = cmask;
01702         }
01703         else if (id == rb_intern("close_others")) {
01704             if (eargp->close_others_given) {
01705                 rb_raise(rb_eArgError, "close_others option specified twice");
01706             }
01707             eargp->close_others_given = 1;
01708             eargp->close_others_do = RTEST(val) ? 1 : 0;
01709         }
01710         else if (id == rb_intern("in")) {
01711             key = INT2FIX(0);
01712             goto redirect;
01713         }
01714         else if (id == rb_intern("out")) {
01715             key = INT2FIX(1);
01716             goto redirect;
01717         }
01718         else if (id == rb_intern("err")) {
01719             key = INT2FIX(2);
01720             goto redirect;
01721         }
01722         else if (id == rb_intern("uid")) {
01723 #ifdef HAVE_SETUID
01724             if (eargp->uid_given) {
01725                 rb_raise(rb_eArgError, "uid option specified twice");
01726             }
01727             check_uid_switch();
01728             {
01729                 PREPARE_GETPWNAM;
01730                 eargp->uid = OBJ2UID(val);
01731                 eargp->uid_given = 1;
01732             }
01733 #else
01734             rb_raise(rb_eNotImpError,
01735                      "uid option is unimplemented on this machine");
01736 #endif
01737         }
01738         else if (id == rb_intern("gid")) {
01739 #ifdef HAVE_SETGID
01740             if (eargp->gid_given) {
01741                 rb_raise(rb_eArgError, "gid option specified twice");
01742             }
01743             check_gid_switch();
01744             {
01745                 PREPARE_GETGRNAM;
01746                 eargp->gid = OBJ2GID(val);
01747                 eargp->gid_given = 1;
01748             }
01749 #else
01750             rb_raise(rb_eNotImpError,
01751                      "gid option is unimplemented on this machine");
01752 #endif
01753         }
01754         else {
01755             return ST_STOP;
01756         }
01757         break;
01758 
01759       case T_FIXNUM:
01760       case T_FILE:
01761       case T_ARRAY:
01762 redirect:
01763         check_exec_redirect(key, val, eargp);
01764         break;
01765 
01766       default:
01767         return ST_STOP;
01768     }
01769 
01770     RB_GC_GUARD(execarg_obj);
01771     return ST_CONTINUE;
01772 }
01773 
01774 int
01775 rb_exec_arg_addopt(struct rb_exec_arg *e, VALUE key, VALUE val)
01776 {
01777     return rb_execarg_addopt(e->execarg_obj, key, val);
01778 }
01779 
01780 static int
01781 check_exec_options_i(st_data_t st_key, st_data_t st_val, st_data_t arg)
01782 {
01783     VALUE key = (VALUE)st_key;
01784     VALUE val = (VALUE)st_val;
01785     VALUE execarg_obj = (VALUE)arg;
01786     if (rb_execarg_addopt(execarg_obj, key, val) != ST_CONTINUE) {
01787         if (SYMBOL_P(key))
01788             rb_raise(rb_eArgError, "wrong exec option symbol: %"PRIsVALUE,
01789                      key);
01790         rb_raise(rb_eArgError, "wrong exec option");
01791     }
01792     return ST_CONTINUE;
01793 }
01794 
01795 static int
01796 check_exec_options_i_extract(st_data_t st_key, st_data_t st_val, st_data_t arg)
01797 {
01798     VALUE key = (VALUE)st_key;
01799     VALUE val = (VALUE)st_val;
01800     VALUE *args = (VALUE *)arg;
01801     VALUE execarg_obj = args[0];
01802     if (rb_execarg_addopt(execarg_obj, key, val) != ST_CONTINUE) {
01803         VALUE nonopts = args[1];
01804         if (NIL_P(nonopts)) args[1] = nonopts = rb_hash_new();
01805         rb_hash_aset(nonopts, key, val);
01806     }
01807     return ST_CONTINUE;
01808 }
01809 
01810 static int
01811 check_exec_fds_1(struct rb_execarg *eargp, VALUE h, int maxhint, VALUE ary)
01812 {
01813     long i;
01814 
01815     if (ary != Qfalse) {
01816         for (i = 0; i < RARRAY_LEN(ary); i++) {
01817             VALUE elt = RARRAY_PTR(ary)[i];
01818             int fd = FIX2INT(RARRAY_PTR(elt)[0]);
01819             if (RTEST(rb_hash_lookup(h, INT2FIX(fd)))) {
01820                 rb_raise(rb_eArgError, "fd %d specified twice", fd);
01821             }
01822             if (ary == eargp->fd_open || ary == eargp->fd_dup2)
01823                 rb_hash_aset(h, INT2FIX(fd), Qtrue);
01824             else if (ary == eargp->fd_dup2_child)
01825                 rb_hash_aset(h, INT2FIX(fd), RARRAY_PTR(elt)[1]);
01826             else /* ary == eargp->fd_close */
01827                 rb_hash_aset(h, INT2FIX(fd), INT2FIX(-1));
01828             if (maxhint < fd)
01829                 maxhint = fd;
01830             if (ary == eargp->fd_dup2 || ary == eargp->fd_dup2_child) {
01831                 fd = FIX2INT(RARRAY_PTR(elt)[1]);
01832                 if (maxhint < fd)
01833                     maxhint = fd;
01834             }
01835         }
01836     }
01837     return maxhint;
01838 }
01839 
01840 static VALUE
01841 check_exec_fds(struct rb_execarg *eargp)
01842 {
01843     VALUE h = rb_hash_new();
01844     VALUE ary;
01845     int maxhint = -1;
01846     long i;
01847 
01848     maxhint = check_exec_fds_1(eargp, h, maxhint, eargp->fd_dup2);
01849     maxhint = check_exec_fds_1(eargp, h, maxhint, eargp->fd_close);
01850     maxhint = check_exec_fds_1(eargp, h, maxhint, eargp->fd_open);
01851     maxhint = check_exec_fds_1(eargp, h, maxhint, eargp->fd_dup2_child);
01852 
01853     if (eargp->fd_dup2_child) {
01854         ary = eargp->fd_dup2_child;
01855         for (i = 0; i < RARRAY_LEN(ary); i++) {
01856             VALUE elt = RARRAY_PTR(ary)[i];
01857             int newfd = FIX2INT(RARRAY_PTR(elt)[0]);
01858             int oldfd = FIX2INT(RARRAY_PTR(elt)[1]);
01859             int lastfd = oldfd;
01860             VALUE val = rb_hash_lookup(h, INT2FIX(lastfd));
01861             long depth = 0;
01862             while (FIXNUM_P(val) && 0 <= FIX2INT(val)) {
01863                 lastfd = FIX2INT(val);
01864                 val = rb_hash_lookup(h, val);
01865                 if (RARRAY_LEN(ary) < depth)
01866                     rb_raise(rb_eArgError, "cyclic child fd redirection from %d", oldfd);
01867                 depth++;
01868             }
01869             if (val != Qtrue)
01870                 rb_raise(rb_eArgError, "child fd %d is not redirected", oldfd);
01871             if (oldfd != lastfd) {
01872                 VALUE val2;
01873                 rb_ary_store(elt, 1, INT2FIX(lastfd));
01874                 rb_hash_aset(h, INT2FIX(newfd), INT2FIX(lastfd));
01875                 val = INT2FIX(oldfd);
01876                 while (FIXNUM_P(val2 = rb_hash_lookup(h, val))) {
01877                     rb_hash_aset(h, val, INT2FIX(lastfd));
01878                     val = val2;
01879                 }
01880             }
01881         }
01882     }
01883 
01884     eargp->close_others_maxhint = maxhint;
01885     return h;
01886 }
01887 
01888 static void
01889 rb_check_exec_options(VALUE opthash, VALUE execarg_obj)
01890 {
01891     if (RHASH_EMPTY_P(opthash))
01892         return;
01893     st_foreach(RHASH_TBL(opthash), check_exec_options_i, (st_data_t)execarg_obj);
01894 }
01895 
01896 VALUE
01897 rb_execarg_extract_options(VALUE execarg_obj, VALUE opthash)
01898 {
01899     VALUE args[2];
01900     if (RHASH_EMPTY_P(opthash))
01901         return Qnil;
01902     args[0] = execarg_obj;
01903     args[1] = Qnil;
01904     st_foreach(RHASH_TBL(opthash), check_exec_options_i_extract, (st_data_t)args);
01905     return args[1];
01906 }
01907 
01908 static int
01909 check_exec_env_i(st_data_t st_key, st_data_t st_val, st_data_t arg)
01910 {
01911     VALUE key = (VALUE)st_key;
01912     VALUE val = (VALUE)st_val;
01913     VALUE env = (VALUE)arg;
01914     char *k;
01915 
01916     k = StringValueCStr(key);
01917     if (strchr(k, '='))
01918         rb_raise(rb_eArgError, "environment name contains a equal : %s", k);
01919 
01920     if (!NIL_P(val))
01921         StringValueCStr(val);
01922 
01923     rb_ary_push(env, hide_obj(rb_assoc_new(key, val)));
01924 
01925     return ST_CONTINUE;
01926 }
01927 
01928 static VALUE
01929 rb_check_exec_env(VALUE hash)
01930 {
01931     VALUE env;
01932 
01933     env = hide_obj(rb_ary_new());
01934     st_foreach(RHASH_TBL(hash), check_exec_env_i, (st_data_t)env);
01935 
01936     return env;
01937 }
01938 
01939 static VALUE
01940 rb_check_argv(int argc, VALUE *argv)
01941 {
01942     VALUE tmp, prog;
01943     int i;
01944     const char *name = 0;
01945 
01946     rb_check_arity(argc, 1, UNLIMITED_ARGUMENTS);
01947 
01948     prog = 0;
01949     tmp = rb_check_array_type(argv[0]);
01950     if (!NIL_P(tmp)) {
01951         if (RARRAY_LEN(tmp) != 2) {
01952             rb_raise(rb_eArgError, "wrong first argument");
01953         }
01954         prog = RARRAY_PTR(tmp)[0];
01955         argv[0] = RARRAY_PTR(tmp)[1];
01956         SafeStringValue(prog);
01957         StringValueCStr(prog);
01958         prog = rb_str_new_frozen(prog);
01959         name = RSTRING_PTR(prog);
01960     }
01961     for (i = 0; i < argc; i++) {
01962         SafeStringValue(argv[i]);
01963         argv[i] = rb_str_new_frozen(argv[i]);
01964         StringValueCStr(argv[i]);
01965     }
01966     security(name ? name : RSTRING_PTR(argv[0]));
01967     return prog;
01968 }
01969 
01970 static VALUE
01971 rb_exec_getargs(int *argc_p, VALUE **argv_p, int accept_shell, VALUE *env_ret, VALUE *opthash_ret)
01972 {
01973     VALUE hash, prog;
01974 
01975     if (0 < *argc_p) {
01976         hash = rb_check_hash_type((*argv_p)[*argc_p-1]);
01977         if (!NIL_P(hash)) {
01978             *opthash_ret = hash;
01979             (*argc_p)--;
01980         }
01981     }
01982 
01983     if (0 < *argc_p) {
01984         hash = rb_check_hash_type((*argv_p)[0]);
01985         if (!NIL_P(hash)) {
01986             *env_ret = hash;
01987             (*argc_p)--;
01988             (*argv_p)++;
01989         }
01990     }
01991     prog = rb_check_argv(*argc_p, *argv_p);
01992     if (!prog) {
01993         prog = (*argv_p)[0];
01994         if (accept_shell && *argc_p == 1) {
01995             *argc_p = 0;
01996             *argv_p = 0;
01997         }
01998     }
01999     return prog;
02000 }
02001 
02002 #ifndef _WIN32
02003 struct string_part {
02004     const char *ptr;
02005     size_t len;
02006 };
02007 
02008 static int
02009 compare_posix_sh(const void *key, const void *el)
02010 {
02011     const struct string_part *word = key;
02012     int ret = strncmp(word->ptr, el, word->len);
02013     if (!ret && ((const char *)el)[word->len]) ret = -1;
02014     return ret;
02015 }
02016 #endif
02017 
02018 static void
02019 rb_exec_fillarg(VALUE prog, int argc, VALUE *argv, VALUE env, VALUE opthash, VALUE execarg_obj)
02020 {
02021     struct rb_execarg *eargp = rb_execarg_get(execarg_obj);
02022     char fbuf[MAXPATHLEN];
02023 
02024     MEMZERO(eargp, struct rb_execarg, 1);
02025 
02026     if (!NIL_P(opthash)) {
02027         rb_check_exec_options(opthash, execarg_obj);
02028     }
02029     if (!NIL_P(env)) {
02030         env = rb_check_exec_env(env);
02031         eargp->env_modification = env;
02032     }
02033 
02034     eargp->use_shell = argc == 0;
02035     if (eargp->use_shell)
02036         eargp->invoke.sh.shell_script = prog;
02037     else
02038         eargp->invoke.cmd.command_name = prog;
02039 
02040 #ifndef _WIN32
02041     if (eargp->use_shell) {
02042         static const char posix_sh_cmds[][9] = {
02043             "!",                /* reserved */
02044             ".",                /* special built-in */
02045             ":",                /* special built-in */
02046             "break",            /* special built-in */
02047             "case",             /* reserved */
02048             "continue",         /* special built-in */
02049             "do",               /* reserved */
02050             "done",             /* reserved */
02051             "elif",             /* reserved */
02052             "else",             /* reserved */
02053             "esac",             /* reserved */
02054             "eval",             /* special built-in */
02055             "exec",             /* special built-in */
02056             "exit",             /* special built-in */
02057             "export",           /* special built-in */
02058             "fi",               /* reserved */
02059             "for",              /* reserved */
02060             "if",               /* reserved */
02061             "in",               /* reserved */
02062             "readonly",         /* special built-in */
02063             "return",           /* special built-in */
02064             "set",              /* special built-in */
02065             "shift",            /* special built-in */
02066             "then",             /* reserved */
02067             "times",            /* special built-in */
02068             "trap",             /* special built-in */
02069             "unset",            /* special built-in */
02070             "until",            /* reserved */
02071             "while",            /* reserved */
02072         };
02073         const char *p;
02074         struct string_part first = {0, 0};
02075         int has_meta = 0;
02076         /*
02077          * meta characters:
02078          *
02079          * *    Pathname Expansion
02080          * ?    Pathname Expansion
02081          * {}   Grouping Commands
02082          * []   Pathname Expansion
02083          * <>   Redirection
02084          * ()   Grouping Commands
02085          * ~    Tilde Expansion
02086          * &    AND Lists, Asynchronous Lists
02087          * |    OR Lists, Pipelines
02088          * \    Escape Character
02089          * $    Parameter Expansion
02090          * ;    Sequential Lists
02091          * '    Single-Quotes
02092          * `    Command Substitution
02093          * "    Double-Quotes
02094          * \n   Lists
02095          *
02096          * #    Comment
02097          * =    Assignment preceding command name
02098          * %    (used in Parameter Expansion)
02099          */
02100         for (p = RSTRING_PTR(prog); *p; p++) {
02101             if (*p == ' ' || *p == '\t') {
02102                 if (first.ptr && !first.len) first.len = p - first.ptr;
02103             }
02104             else {
02105                 if (!first.ptr) first.ptr = p;
02106             }
02107             if (!has_meta && strchr("*?{}[]<>()~&|\\$;'`\"\n#", *p))
02108                 has_meta = 1;
02109             if (!first.len) {
02110                 if (*p == '=') {
02111                     has_meta = 1;
02112                 }
02113                 else if (*p == '/') {
02114                     first.len = 0x100; /* longer than any posix_sh_cmds */
02115                 }
02116             }
02117             if (has_meta)
02118                 break;
02119         }
02120         if (!has_meta && first.ptr) {
02121             if (!first.len) first.len = p - first.ptr;
02122             if (first.len > 0 && first.len <= sizeof(posix_sh_cmds[0]) &&
02123                 bsearch(&first, posix_sh_cmds, numberof(posix_sh_cmds), sizeof(posix_sh_cmds[0]), compare_posix_sh))
02124                 has_meta = 1;
02125         }
02126         if (!has_meta) {
02127             /* avoid shell since no shell meta charactor found. */
02128             eargp->use_shell = 0;
02129         }
02130         if (!eargp->use_shell) {
02131             VALUE argv_buf;
02132             argv_buf = hide_obj(rb_str_buf_new(0));
02133             p = RSTRING_PTR(prog);
02134             while (*p) {
02135                 while (*p == ' ' || *p == '\t')
02136                     p++;
02137                 if (*p) {
02138                     const char *w = p;
02139                     while (*p && *p != ' ' && *p != '\t')
02140                         p++;
02141                     rb_str_buf_cat(argv_buf, w, p-w);
02142                     rb_str_buf_cat(argv_buf, "", 1); /* append '\0' */
02143                 }
02144             }
02145             eargp->invoke.cmd.argv_buf = argv_buf;
02146             eargp->invoke.cmd.command_name = hide_obj(rb_str_new_cstr(RSTRING_PTR(argv_buf)));
02147         }
02148     }
02149 #endif
02150 
02151     if (!eargp->use_shell) {
02152         const char *abspath;
02153         abspath = dln_find_exe_r(RSTRING_PTR(eargp->invoke.cmd.command_name), 0, fbuf, sizeof(fbuf));
02154         if (abspath)
02155             eargp->invoke.cmd.command_abspath = rb_str_new_cstr(abspath);
02156         else
02157             eargp->invoke.cmd.command_abspath = Qnil;
02158     }
02159 
02160     if (!eargp->use_shell && !eargp->invoke.cmd.argv_buf) {
02161         int i;
02162         VALUE argv_buf;
02163         argv_buf = rb_str_buf_new(0);
02164         hide_obj(argv_buf);
02165         for (i = 0; i < argc; i++) {
02166             rb_str_buf_cat2(argv_buf, StringValueCStr(argv[i]));
02167             rb_str_buf_cat(argv_buf, "", 1); /* append '\0' */
02168         }
02169         eargp->invoke.cmd.argv_buf = argv_buf;
02170     }
02171 
02172     if (!eargp->use_shell) {
02173         const char *p, *ep, *null=NULL;
02174         VALUE argv_str;
02175         argv_str = hide_obj(rb_str_buf_new(sizeof(char*) * (argc + 2)));
02176         rb_str_buf_cat(argv_str, (char *)&null, sizeof(null)); /* place holder for /bin/sh of try_with_sh. */
02177         p = RSTRING_PTR(eargp->invoke.cmd.argv_buf);
02178         ep = p + RSTRING_LEN(eargp->invoke.cmd.argv_buf);
02179         while (p < ep) {
02180             rb_str_buf_cat(argv_str, (char *)&p, sizeof(p));
02181             p += strlen(p) + 1;
02182         }
02183         rb_str_buf_cat(argv_str, (char *)&null, sizeof(null)); /* terminator for execve.  */
02184         eargp->invoke.cmd.argv_str = argv_str;
02185     }
02186     RB_GC_GUARD(execarg_obj);
02187 }
02188 
02189 VALUE
02190 rb_execarg_new(int argc, VALUE *argv, int accept_shell)
02191 {
02192     VALUE execarg_obj;
02193     struct rb_execarg *eargp;
02194     execarg_obj = TypedData_Make_Struct(rb_cData, struct rb_execarg, &exec_arg_data_type, eargp);
02195     hide_obj(execarg_obj);
02196     rb_execarg_init(argc, argv, accept_shell, execarg_obj);
02197     return execarg_obj;
02198 }
02199 
02200 struct rb_execarg
02201 *rb_execarg_get(VALUE execarg_obj)
02202 {
02203     struct rb_execarg *eargp;
02204     TypedData_Get_Struct(execarg_obj, struct rb_execarg, &exec_arg_data_type, eargp);
02205     return eargp;
02206 }
02207 
02208 VALUE
02209 rb_execarg_init(int argc, VALUE *argv, int accept_shell, VALUE execarg_obj)
02210 {
02211     struct rb_execarg *eargp = rb_execarg_get(execarg_obj);
02212     VALUE prog, ret;
02213     VALUE env = Qnil, opthash = Qnil;
02214     prog = rb_exec_getargs(&argc, &argv, accept_shell, &env, &opthash);
02215     rb_exec_fillarg(prog, argc, argv, env, opthash, execarg_obj);
02216     ret = eargp->use_shell ? eargp->invoke.sh.shell_script : eargp->invoke.cmd.command_name;
02217     RB_GC_GUARD(execarg_obj);
02218     return ret;
02219 }
02220 
02221 VALUE
02222 rb_exec_arg_init(int argc, VALUE *argv, int accept_shell, struct rb_exec_arg *e)
02223 {
02224     return rb_execarg_init(argc, argv, accept_shell, e->execarg_obj);
02225 }
02226 
02227 void
02228 rb_execarg_setenv(VALUE execarg_obj, VALUE env)
02229 {
02230     struct rb_execarg *eargp = rb_execarg_get(execarg_obj);
02231     env = !NIL_P(env) ? rb_check_exec_env(env) : Qfalse;
02232     eargp->env_modification = env;
02233 }
02234 
02235 static int
02236 fill_envp_buf_i(st_data_t st_key, st_data_t st_val, st_data_t arg)
02237 {
02238     VALUE key = (VALUE)st_key;
02239     VALUE val = (VALUE)st_val;
02240     VALUE envp_buf = (VALUE)arg;
02241 
02242     rb_str_buf_cat2(envp_buf, StringValueCStr(key));
02243     rb_str_buf_cat2(envp_buf, "=");
02244     rb_str_buf_cat2(envp_buf, StringValueCStr(val));
02245     rb_str_buf_cat(envp_buf, "", 1); /* append '\0' */
02246 
02247     return ST_CONTINUE;
02248 }
02249 
02250 
02251 static long run_exec_dup2_tmpbuf_size(long n);
02252 
02253 void
02254 rb_execarg_fixup(VALUE execarg_obj)
02255 {
02256     struct rb_execarg *eargp = rb_execarg_get(execarg_obj);
02257     int unsetenv_others;
02258     VALUE envopts;
02259     VALUE ary;
02260 
02261     eargp->redirect_fds = check_exec_fds(eargp);
02262 
02263     ary = eargp->fd_dup2;
02264     if (ary != Qfalse) {
02265         size_t len = run_exec_dup2_tmpbuf_size(RARRAY_LEN(ary));
02266         VALUE tmpbuf = hide_obj(rb_str_new(0, len));
02267         rb_str_set_len(tmpbuf, len);
02268         eargp->dup2_tmpbuf = tmpbuf;
02269     }
02270 
02271     unsetenv_others = eargp->unsetenv_others_given && eargp->unsetenv_others_do;
02272     envopts = eargp->env_modification;
02273     if (unsetenv_others || envopts != Qfalse) {
02274         VALUE envtbl, envp_str, envp_buf;
02275         char *p, *ep;
02276         if (unsetenv_others) {
02277             envtbl = rb_hash_new();
02278         }
02279         else {
02280             envtbl = rb_const_get(rb_cObject, rb_intern("ENV"));
02281             envtbl = rb_convert_type(envtbl, T_HASH, "Hash", "to_hash");
02282         }
02283         hide_obj(envtbl);
02284         if (envopts != Qfalse) {
02285             st_table *stenv = RHASH_TBL(envtbl);
02286             long i;
02287             for (i = 0; i < RARRAY_LEN(envopts); i++) {
02288                 VALUE pair = RARRAY_PTR(envopts)[i];
02289                 VALUE key = RARRAY_PTR(pair)[0];
02290                 VALUE val = RARRAY_PTR(pair)[1];
02291                 if (NIL_P(val)) {
02292                     st_data_t stkey = (st_data_t)key;
02293                     st_delete(stenv, &stkey, NULL);
02294                 }
02295                 else {
02296                     st_insert(stenv, (st_data_t)key, (st_data_t)val);
02297                 }
02298             }
02299         }
02300         envp_buf = rb_str_buf_new(0);
02301         hide_obj(envp_buf);
02302         st_foreach(RHASH_TBL(envtbl), fill_envp_buf_i, (st_data_t)envp_buf);
02303         envp_str = rb_str_buf_new(sizeof(char*) * (RHASH_SIZE(envtbl) + 1));
02304         hide_obj(envp_str);
02305         p = RSTRING_PTR(envp_buf);
02306         ep = p + RSTRING_LEN(envp_buf);
02307         while (p < ep) {
02308             rb_str_buf_cat(envp_str, (char *)&p, sizeof(p));
02309             p += strlen(p) + 1;
02310         }
02311         p = NULL;
02312         rb_str_buf_cat(envp_str, (char *)&p, sizeof(p));
02313         eargp->envp_str = envp_str;
02314         eargp->envp_buf = envp_buf;
02315 
02316         /*
02317         char **tmp_envp = (char **)RSTRING_PTR(envp_str);
02318         while (*tmp_envp) {
02319             printf("%s\n", *tmp_envp);
02320             tmp_envp++;
02321         }
02322         */
02323     }
02324     RB_GC_GUARD(execarg_obj);
02325 }
02326 
02327 void
02328 rb_exec_arg_fixup(struct rb_exec_arg *e)
02329 {
02330     rb_execarg_fixup(e->execarg_obj);
02331 }
02332 
02333 static int rb_exec_without_timer_thread(const struct rb_execarg *eargp, char *errmsg, size_t errmsg_buflen);
02334 
02335 /*
02336  *  call-seq:
02337  *     exec([env,] command... [,options])
02338  *
02339  *  Replaces the current process by running the given external _command_.
02340  *  _command..._ is one of following forms.
02341  *
02342  *    commandline                 : command line string which is passed to the standard shell
02343  *    cmdname, arg1, ...          : command name and one or more arguments (no shell)
02344  *    [cmdname, argv0], arg1, ... : command name, argv[0] and zero or more arguments (no shell)
02345  *
02346  *  If single string is given as the command,
02347  *  it is taken as a command line that is subject to shell expansion before being executed.
02348  *
02349  *  The standard shell means always <code>"/bin/sh"</code> on Unix-like systems,
02350  *  <code>ENV["RUBYSHELL"]</code> or <code>ENV["COMSPEC"]</code> on Windows NT series, and
02351  *  similar.
02352  *
02353  *  If two or more +string+ given,
02354  *  the first is taken as a command name and
02355  *  the rest are passed as parameters to command with no shell expansion.
02356  *
02357  *  If a two-element array at the beginning of the command,
02358  *  the first element is the command to be executed,
02359  *  and the second argument is used as the <code>argv[0]</code> value,
02360  *  which may show up in process listings.
02361  *
02362  *  In order to execute the command, one of the <code>exec(2)</code>
02363  *  system calls is used, so the running command may inherit some of the environment
02364  *  of the original program (including open file descriptors).
02365  *  This behavior is modified by env and options.
02366  *  See <code>spawn</code> for details.
02367  *
02368  *  Raises SystemCallError if the command couldn't execute (typically
02369  *  <code>Errno::ENOENT</code> when it was not found).
02370  *
02371  *  This method modifies process attributes according to _options_
02372  *  (details described in <code>spawn</code>)
02373  *  before <code>exec(2)</code> system call.
02374  *  The modified attributes may be retained when <code>exec(2)</code> system call fails.
02375  *  For example, hard resource limits is not restorable.
02376  *  If it is not acceptable, consider to create a child process using <code>spawn</code> or <code>system</code>.
02377  *
02378  *     exec "echo *"       # echoes list of files in current directory
02379  *     # never get here
02380  *
02381  *
02382  *     exec "echo", "*"    # echoes an asterisk
02383  *     # never get here
02384  */
02385 
02386 VALUE
02387 rb_f_exec(int argc, VALUE *argv)
02388 {
02389     VALUE execarg_obj, fail_str;
02390     struct rb_execarg *eargp;
02391 #define CHILD_ERRMSG_BUFLEN 80
02392     char errmsg[CHILD_ERRMSG_BUFLEN] = { '\0' };
02393 
02394     execarg_obj = rb_execarg_new(argc, argv, TRUE);
02395     eargp = rb_execarg_get(execarg_obj);
02396     rb_execarg_fixup(execarg_obj);
02397     fail_str = eargp->use_shell ? eargp->invoke.sh.shell_script : eargp->invoke.cmd.command_name;
02398 
02399 #if defined(__APPLE__) || defined(__HAIKU__)
02400     rb_exec_without_timer_thread(eargp, errmsg, sizeof(errmsg));
02401 #else
02402     rb_exec_async_signal_safe(eargp, errmsg, sizeof(errmsg));
02403 #endif
02404     RB_GC_GUARD(execarg_obj);
02405     if (errmsg[0])
02406         rb_sys_fail(errmsg);
02407     rb_sys_fail_str(fail_str);
02408     return Qnil;                /* dummy */
02409 }
02410 
02411 #define ERRMSG(str) do { if (errmsg && 0 < errmsg_buflen) strlcpy(errmsg, (str), errmsg_buflen); } while (0)
02412 
02413 /*#define DEBUG_REDIRECT*/
02414 #if defined(DEBUG_REDIRECT)
02415 
02416 #include <stdarg.h>
02417 
02418 static void
02419 ttyprintf(const char *fmt, ...)
02420 {
02421     va_list ap;
02422     FILE *tty;
02423     int save = errno;
02424 #ifdef _WIN32
02425     tty = fopen("con", "w");
02426 #else
02427     tty = fopen("/dev/tty", "w");
02428 #endif
02429     if (!tty)
02430         return;
02431 
02432     va_start(ap, fmt);
02433     vfprintf(tty, fmt, ap);
02434     va_end(ap);
02435     fclose(tty);
02436     errno = save;
02437 }
02438 
02439 static int
02440 redirect_dup(int oldfd)
02441 {
02442     int ret;
02443     ret = dup(oldfd);
02444     ttyprintf("dup(%d) => %d\n", oldfd, ret);
02445     return ret;
02446 }
02447 #else
02448 #define redirect_dup(oldfd) dup(oldfd)
02449 #endif
02450 
02451 #if defined(DEBUG_REDIRECT) || defined(_WIN32)
02452 static int
02453 redirect_dup2(int oldfd, int newfd)
02454 {
02455     int ret;
02456     ret = dup2(oldfd, newfd);
02457     if (newfd >= 0 && newfd <= 2)
02458         SetStdHandle(newfd == 0 ? STD_INPUT_HANDLE : newfd == 1 ? STD_OUTPUT_HANDLE : STD_ERROR_HANDLE, (HANDLE)rb_w32_get_osfhandle(newfd));
02459 #if defined(DEBUG_REDIRECT)
02460     ttyprintf("dup2(%d, %d)\n", oldfd, newfd);
02461 #endif
02462     return ret;
02463 }
02464 #else
02465 #define redirect_dup2(oldfd, newfd) dup2((oldfd), (newfd))
02466 #endif
02467 
02468 #if defined(DEBUG_REDIRECT)
02469 static int
02470 redirect_close(int fd)
02471 {
02472     int ret;
02473     ret = close(fd);
02474     ttyprintf("close(%d)\n", fd);
02475     return ret;
02476 }
02477 
02478 static int
02479 redirect_open(const char *pathname, int flags, mode_t perm)
02480 {
02481     int ret;
02482     ret = open(pathname, flags, perm);
02483     ttyprintf("open(\"%s\", 0x%x, 0%o) => %d\n", pathname, flags, perm, ret);
02484     return ret;
02485 }
02486 
02487 #else
02488 #define redirect_close(fd) close(fd)
02489 #define redirect_open(pathname, flags, perm) open((pathname), (flags), (perm))
02490 #endif
02491 
02492 static int
02493 save_redirect_fd(int fd, struct rb_execarg *sargp, char *errmsg, size_t errmsg_buflen)
02494 {
02495     if (sargp) {
02496         VALUE newary;
02497         int save_fd = redirect_dup(fd);
02498         if (save_fd == -1) {
02499             if (errno == EBADF)
02500                 return 0;
02501             ERRMSG("dup");
02502             return -1;
02503         }
02504         rb_update_max_fd(save_fd);
02505         newary = sargp->fd_dup2;
02506         if (newary == Qfalse) {
02507             newary = hide_obj(rb_ary_new());
02508             sargp->fd_dup2 = newary;
02509         }
02510         rb_ary_push(newary,
02511                     hide_obj(rb_assoc_new(INT2FIX(fd), INT2FIX(save_fd))));
02512 
02513         newary = sargp->fd_close;
02514         if (newary == Qfalse) {
02515             newary = hide_obj(rb_ary_new());
02516             sargp->fd_close = newary;
02517         }
02518         rb_ary_push(newary, hide_obj(rb_assoc_new(INT2FIX(save_fd), Qnil)));
02519     }
02520 
02521     return 0;
02522 }
02523 
02524 static int
02525 intcmp(const void *a, const void *b)
02526 {
02527     return *(int*)a - *(int*)b;
02528 }
02529 
02530 static int
02531 intrcmp(const void *a, const void *b)
02532 {
02533     return *(int*)b - *(int*)a;
02534 }
02535 
02536 struct run_exec_dup2_fd_pair {
02537     int oldfd;
02538     int newfd;
02539     long older_index;
02540     long num_newer;
02541 };
02542 
02543 static long
02544 run_exec_dup2_tmpbuf_size(long n)
02545 {
02546     return sizeof(struct run_exec_dup2_fd_pair) * n;
02547 }
02548 
02549 /* This function should be async-signal-safe when sargp is NULL.  Hopefully it is. */
02550 static int
02551 run_exec_dup2(VALUE ary, VALUE tmpbuf, struct rb_execarg *sargp, char *errmsg, size_t errmsg_buflen)
02552 {
02553     long n, i;
02554     int ret;
02555     int extra_fd = -1;
02556     struct run_exec_dup2_fd_pair *pairs = 0;
02557 
02558     n = RARRAY_LEN(ary);
02559     pairs = (struct run_exec_dup2_fd_pair *)RSTRING_PTR(tmpbuf);
02560 
02561     /* initialize oldfd and newfd: O(n) */
02562     for (i = 0; i < n; i++) {
02563         VALUE elt = RARRAY_PTR(ary)[i];
02564         pairs[i].oldfd = FIX2INT(RARRAY_PTR(elt)[1]);
02565         pairs[i].newfd = FIX2INT(RARRAY_PTR(elt)[0]); /* unique */
02566         pairs[i].older_index = -1;
02567     }
02568 
02569     /* sort the table by oldfd: O(n log n) */
02570     if (!sargp)
02571         qsort(pairs, n, sizeof(struct run_exec_dup2_fd_pair), intcmp); /* hopefully async-signal-safe */
02572     else
02573         qsort(pairs, n, sizeof(struct run_exec_dup2_fd_pair), intrcmp);
02574 
02575     /* initialize older_index and num_newer: O(n log n) */
02576     for (i = 0; i < n; i++) {
02577         int newfd = pairs[i].newfd;
02578         struct run_exec_dup2_fd_pair key, *found;
02579         key.oldfd = newfd;
02580         found = bsearch(&key, pairs, n, sizeof(struct run_exec_dup2_fd_pair), intcmp); /* hopefully async-signal-safe */
02581         pairs[i].num_newer = 0;
02582         if (found) {
02583             while (pairs < found && (found-1)->oldfd == newfd)
02584                 found--;
02585             while (found < pairs+n && found->oldfd == newfd) {
02586                 pairs[i].num_newer++;
02587                 found->older_index = i;
02588                 found++;
02589             }
02590         }
02591     }
02592 
02593     /* non-cyclic redirection: O(n) */
02594     for (i = 0; i < n; i++) {
02595         long j = i;
02596         while (j != -1 && pairs[j].oldfd != -1 && pairs[j].num_newer == 0) {
02597             if (save_redirect_fd(pairs[j].newfd, sargp, errmsg, errmsg_buflen) < 0) /* async-signal-safe */
02598                 goto fail;
02599             ret = redirect_dup2(pairs[j].oldfd, pairs[j].newfd); /* async-signal-safe */
02600             if (ret == -1) {
02601                 ERRMSG("dup2");
02602                 goto fail;
02603             }
02604             rb_update_max_fd(pairs[j].newfd); /* async-signal-safe but don't need to call it in a child process. */
02605             pairs[j].oldfd = -1;
02606             j = pairs[j].older_index;
02607             if (j != -1)
02608                 pairs[j].num_newer--;
02609         }
02610     }
02611 
02612     /* cyclic redirection: O(n) */
02613     for (i = 0; i < n; i++) {
02614         long j;
02615         if (pairs[i].oldfd == -1)
02616             continue;
02617         if (pairs[i].oldfd == pairs[i].newfd) { /* self cycle */
02618 #ifdef F_GETFD
02619             int fd = pairs[i].oldfd;
02620             ret = fcntl(fd, F_GETFD); /* async-signal-safe */
02621             if (ret == -1) {
02622                 ERRMSG("fcntl(F_GETFD)");
02623                 goto fail;
02624             }
02625             if (ret & FD_CLOEXEC) {
02626                 ret &= ~FD_CLOEXEC;
02627                 ret = fcntl(fd, F_SETFD, ret); /* async-signal-safe */
02628                 if (ret == -1) {
02629                     ERRMSG("fcntl(F_SETFD)");
02630                     goto fail;
02631                 }
02632             }
02633 #endif
02634             pairs[i].oldfd = -1;
02635             continue;
02636         }
02637         if (extra_fd == -1) {
02638             extra_fd = redirect_dup(pairs[i].oldfd); /* async-signal-safe */
02639             if (extra_fd == -1) {
02640                 ERRMSG("dup");
02641                 goto fail;
02642             }
02643             rb_update_max_fd(extra_fd);
02644         }
02645         else {
02646             ret = redirect_dup2(pairs[i].oldfd, extra_fd); /* async-signal-safe */
02647             if (ret == -1) {
02648                 ERRMSG("dup2");
02649                 goto fail;
02650             }
02651             rb_update_max_fd(extra_fd);
02652         }
02653         pairs[i].oldfd = extra_fd;
02654         j = pairs[i].older_index;
02655         pairs[i].older_index = -1;
02656         while (j != -1) {
02657             ret = redirect_dup2(pairs[j].oldfd, pairs[j].newfd); /* async-signal-safe */
02658             if (ret == -1) {
02659                 ERRMSG("dup2");
02660                 goto fail;
02661             }
02662             rb_update_max_fd(ret);
02663             pairs[j].oldfd = -1;
02664             j = pairs[j].older_index;
02665         }
02666     }
02667     if (extra_fd != -1) {
02668         ret = redirect_close(extra_fd); /* async-signal-safe */
02669         if (ret == -1) {
02670             ERRMSG("close");
02671             goto fail;
02672         }
02673     }
02674 
02675     return 0;
02676 
02677   fail:
02678     return -1;
02679 }
02680 
02681 /* This function should be async-signal-safe.  Actually it is. */
02682 static int
02683 run_exec_close(VALUE ary, char *errmsg, size_t errmsg_buflen)
02684 {
02685     long i;
02686     int ret;
02687 
02688     for (i = 0; i < RARRAY_LEN(ary); i++) {
02689         VALUE elt = RARRAY_PTR(ary)[i];
02690         int fd = FIX2INT(RARRAY_PTR(elt)[0]);
02691         ret = redirect_close(fd); /* async-signal-safe */
02692         if (ret == -1) {
02693             ERRMSG("close");
02694             return -1;
02695         }
02696     }
02697     return 0;
02698 }
02699 
02700 /* This function should be async-signal-safe when sargp is NULL.  Actually it is. */
02701 static int
02702 run_exec_open(VALUE ary, struct rb_execarg *sargp, char *errmsg, size_t errmsg_buflen)
02703 {
02704     long i;
02705     int ret;
02706 
02707     for (i = 0; i < RARRAY_LEN(ary);) {
02708         VALUE elt = RARRAY_PTR(ary)[i];
02709         int fd = FIX2INT(RARRAY_PTR(elt)[0]);
02710         VALUE param = RARRAY_PTR(elt)[1];
02711         char *path = RSTRING_PTR(RARRAY_PTR(param)[0]);
02712         int flags = NUM2INT(RARRAY_PTR(param)[1]);
02713         int perm = NUM2INT(RARRAY_PTR(param)[2]);
02714         int need_close = 1;
02715         int fd2 = redirect_open(path, flags, perm); /* async-signal-safe */
02716         if (fd2 == -1) {
02717             ERRMSG("open");
02718             return -1;
02719         }
02720         rb_update_max_fd(fd2);
02721         while (i < RARRAY_LEN(ary) &&
02722                (elt = RARRAY_PTR(ary)[i], RARRAY_PTR(elt)[1] == param)) {
02723             fd = FIX2INT(RARRAY_PTR(elt)[0]);
02724             if (fd == fd2) {
02725                 need_close = 0;
02726             }
02727             else {
02728                 if (save_redirect_fd(fd, sargp, errmsg, errmsg_buflen) < 0) /* async-signal-safe */
02729                     return -1;
02730                 ret = redirect_dup2(fd2, fd); /* async-signal-safe */
02731                 if (ret == -1) {
02732                     ERRMSG("dup2");
02733                     return -1;
02734                 }
02735                 rb_update_max_fd(fd);
02736             }
02737             i++;
02738         }
02739         if (need_close) {
02740             ret = redirect_close(fd2); /* async-signal-safe */
02741             if (ret == -1) {
02742                 ERRMSG("close");
02743                 return -1;
02744             }
02745         }
02746     }
02747     return 0;
02748 }
02749 
02750 /* This function should be async-signal-safe when sargp is NULL.  Actually it is. */
02751 static int
02752 run_exec_dup2_child(VALUE ary, struct rb_execarg *sargp, char *errmsg, size_t errmsg_buflen)
02753 {
02754     long i;
02755     int ret;
02756 
02757     for (i = 0; i < RARRAY_LEN(ary); i++) {
02758         VALUE elt = RARRAY_PTR(ary)[i];
02759         int newfd = FIX2INT(RARRAY_PTR(elt)[0]);
02760         int oldfd = FIX2INT(RARRAY_PTR(elt)[1]);
02761 
02762         if (save_redirect_fd(newfd, sargp, errmsg, errmsg_buflen) < 0) /* async-signal-safe */
02763             return -1;
02764         ret = redirect_dup2(oldfd, newfd); /* async-signal-safe */
02765         if (ret == -1) {
02766             ERRMSG("dup2");
02767             return -1;
02768         }
02769         rb_update_max_fd(newfd);
02770     }
02771     return 0;
02772 }
02773 
02774 #ifdef HAVE_SETPGID
02775 /* This function should be async-signal-safe when sargp is NULL.  Actually it is. */
02776 static int
02777 run_exec_pgroup(const struct rb_execarg *eargp, struct rb_execarg *sargp, char *errmsg, size_t errmsg_buflen)
02778 {
02779     /*
02780      * If FD_CLOEXEC is available, rb_fork waits the child's execve.
02781      * So setpgid is done in the child when rb_fork is returned in the parent.
02782      * No race condition, even without setpgid from the parent.
02783      * (Is there an environment which has setpgid but no FD_CLOEXEC?)
02784      */
02785     int ret;
02786     pid_t pgroup;
02787 
02788     pgroup = eargp->pgroup_pgid;
02789     if (pgroup == -1)
02790         return 0;
02791 
02792     if (sargp) {
02793         /* maybe meaningless with no fork environment... */
02794         sargp->pgroup_given = 1;
02795         sargp->pgroup_pgid = getpgrp();
02796     }
02797 
02798     if (pgroup == 0) {
02799         pgroup = getpid(); /* async-signal-safe */
02800     }
02801     ret = setpgid(getpid(), pgroup); /* async-signal-safe */
02802     if (ret == -1) ERRMSG("setpgid");
02803     return ret;
02804 }
02805 #endif
02806 
02807 #if defined(HAVE_SETRLIMIT) && defined(RLIM2NUM)
02808 /* This function should be async-signal-safe when sargp is NULL.  Hopefully it is. */
02809 static int
02810 run_exec_rlimit(VALUE ary, struct rb_execarg *sargp, char *errmsg, size_t errmsg_buflen)
02811 {
02812     long i;
02813     for (i = 0; i < RARRAY_LEN(ary); i++) {
02814         VALUE elt = RARRAY_PTR(ary)[i];
02815         int rtype = NUM2INT(RARRAY_PTR(elt)[0]);
02816         struct rlimit rlim;
02817         if (sargp) {
02818             VALUE tmp, newary;
02819             if (getrlimit(rtype, &rlim) == -1) {
02820                 ERRMSG("getrlimit");
02821                 return -1;
02822             }
02823             tmp = hide_obj(rb_ary_new3(3, RARRAY_PTR(elt)[0],
02824                                        RLIM2NUM(rlim.rlim_cur),
02825                                        RLIM2NUM(rlim.rlim_max)));
02826             if (sargp->rlimit_limits == Qfalse)
02827                 newary = sargp->rlimit_limits = hide_obj(rb_ary_new());
02828             else
02829                 newary = sargp->rlimit_limits;
02830             rb_ary_push(newary, tmp);
02831         }
02832         rlim.rlim_cur = NUM2RLIM(RARRAY_PTR(elt)[1]);
02833         rlim.rlim_max = NUM2RLIM(RARRAY_PTR(elt)[2]);
02834         if (setrlimit(rtype, &rlim) == -1) { /* hopefully async-signal-safe */
02835             ERRMSG("setrlimit");
02836             return -1;
02837         }
02838     }
02839     return 0;
02840 }
02841 #endif
02842 
02843 #if !defined(HAVE_FORK)
02844 static VALUE
02845 save_env_i(VALUE i, VALUE ary, int argc, VALUE *argv)
02846 {
02847     rb_ary_push(ary, hide_obj(rb_ary_dup(argv[0])));
02848     return Qnil;
02849 }
02850 
02851 static void
02852 save_env(struct rb_execarg *sargp)
02853 {
02854     if (!sargp)
02855         return;
02856     if (sargp->env_modification == Qfalse) {
02857         VALUE env = rb_const_get(rb_cObject, rb_intern("ENV"));
02858         if (RTEST(env)) {
02859             VALUE ary = hide_obj(rb_ary_new());
02860             rb_block_call(env, idEach, 0, 0, save_env_i,
02861                           (VALUE)ary);
02862             sargp->env_modification = ary;
02863         }
02864         sargp->unsetenv_others_given = 1;
02865         sargp->unsetenv_others_do = 1;
02866     }
02867 }
02868 #endif
02869 
02870 /* This function should be async-signal-safe when sargp is NULL.  Hopefully it is. */
02871 int
02872 rb_execarg_run_options(const struct rb_execarg *eargp, struct rb_execarg *sargp, char *errmsg, size_t errmsg_buflen)
02873 {
02874     VALUE obj;
02875 
02876     if (sargp) {
02877         /* assume that sargp is always NULL on fork-able environments */
02878         MEMZERO(sargp, struct rb_execarg, 1);
02879         sargp->redirect_fds = Qnil;
02880     }
02881 
02882 #ifdef HAVE_SETPGID
02883     if (eargp->pgroup_given) {
02884         if (run_exec_pgroup(eargp, sargp, errmsg, errmsg_buflen) == -1) /* async-signal-safe */
02885             return -1;
02886     }
02887 #endif
02888 
02889 #if defined(HAVE_SETRLIMIT) && defined(RLIM2NUM)
02890     obj = eargp->rlimit_limits;
02891     if (obj != Qfalse) {
02892         if (run_exec_rlimit(obj, sargp, errmsg, errmsg_buflen) == -1) /* hopefully async-signal-safe */
02893             return -1;
02894     }
02895 #endif
02896 
02897 #if !defined(HAVE_FORK)
02898     if (eargp->unsetenv_others_given && eargp->unsetenv_others_do) {
02899         save_env(sargp);
02900         rb_env_clear();
02901     }
02902 
02903     obj = eargp->env_modification;
02904     if (obj != Qfalse) {
02905         long i;
02906         save_env(sargp);
02907         for (i = 0; i < RARRAY_LEN(obj); i++) {
02908             VALUE pair = RARRAY_PTR(obj)[i];
02909             VALUE key = RARRAY_PTR(pair)[0];
02910             VALUE val = RARRAY_PTR(pair)[1];
02911             if (NIL_P(val))
02912                 ruby_setenv(StringValueCStr(key), 0);
02913             else
02914                 ruby_setenv(StringValueCStr(key), StringValueCStr(val));
02915         }
02916     }
02917 #endif
02918 
02919     if (eargp->umask_given) {
02920         mode_t mask = eargp->umask_mask;
02921         mode_t oldmask = umask(mask); /* never fail */ /* async-signal-safe */
02922         if (sargp) {
02923             sargp->umask_given = 1;
02924             sargp->umask_mask = oldmask;
02925         }
02926     }
02927 
02928     obj = eargp->fd_dup2;
02929     if (obj != Qfalse) {
02930         if (run_exec_dup2(obj, eargp->dup2_tmpbuf, sargp, errmsg, errmsg_buflen) == -1) /* hopefully async-signal-safe */
02931             return -1;
02932     }
02933 
02934     obj = eargp->fd_close;
02935     if (obj != Qfalse) {
02936         if (sargp)
02937             rb_warn("cannot close fd before spawn");
02938         else {
02939             if (run_exec_close(obj, errmsg, errmsg_buflen) == -1) /* async-signal-safe */
02940                 return -1;
02941         }
02942     }
02943 
02944 #ifdef HAVE_FORK
02945     if (!eargp->close_others_given || eargp->close_others_do) {
02946         rb_close_before_exec(3, eargp->close_others_maxhint, eargp->redirect_fds); /* async-signal-safe */
02947     }
02948 #endif
02949 
02950     obj = eargp->fd_open;
02951     if (obj != Qfalse) {
02952         if (run_exec_open(obj, sargp, errmsg, errmsg_buflen) == -1) /* async-signal-safe */
02953             return -1;
02954     }
02955 
02956     obj = eargp->fd_dup2_child;
02957     if (obj != Qfalse) {
02958         if (run_exec_dup2_child(obj, sargp, errmsg, errmsg_buflen) == -1) /* async-signal-safe */
02959             return -1;
02960     }
02961 
02962     if (eargp->chdir_given) {
02963         if (sargp) {
02964             char *cwd = my_getcwd();
02965             sargp->chdir_given = 1;
02966             sargp->chdir_dir = hide_obj(rb_str_new2(cwd));
02967             xfree(cwd);
02968         }
02969         if (chdir(RSTRING_PTR(eargp->chdir_dir)) == -1) { /* async-signal-safe */
02970             ERRMSG("chdir");
02971             return -1;
02972         }
02973     }
02974 
02975 #ifdef HAVE_SETGID
02976     if (eargp->gid_given) {
02977         if (setgid(eargp->gid) < 0) {
02978             ERRMSG("setgid");
02979             return -1;
02980         }
02981     }
02982 #endif
02983 #ifdef HAVE_SETUID
02984     if (eargp->uid_given) {
02985         if (setuid(eargp->uid) < 0) {
02986             ERRMSG("setuid");
02987             return -1;
02988         }
02989     }
02990 #endif
02991 
02992     if (sargp) {
02993         VALUE ary = sargp->fd_dup2;
02994         if (ary != Qfalse) {
02995             size_t len = run_exec_dup2_tmpbuf_size(RARRAY_LEN(ary));
02996             VALUE tmpbuf = hide_obj(rb_str_new(0, len));
02997             rb_str_set_len(tmpbuf, len);
02998             sargp->dup2_tmpbuf = tmpbuf;
02999         }
03000     }
03001 
03002     return 0;
03003 }
03004 
03005 int
03006 rb_run_exec_options_err(const struct rb_exec_arg *e, struct rb_exec_arg *s, char *errmsg, size_t errmsg_buflen)
03007 {
03008     return rb_execarg_run_options(rb_execarg_get(e->execarg_obj), rb_execarg_get(s->execarg_obj), errmsg, errmsg_buflen);
03009 }
03010 
03011 int
03012 rb_run_exec_options(const struct rb_exec_arg *e, struct rb_exec_arg *s)
03013 {
03014     return rb_execarg_run_options(rb_execarg_get(e->execarg_obj), rb_execarg_get(s->execarg_obj), NULL, 0);
03015 }
03016 
03017 /* This function should be async-signal-safe.  Hopefully it is. */
03018 int
03019 rb_exec_async_signal_safe(const struct rb_execarg *eargp, char *errmsg, size_t errmsg_buflen)
03020 {
03021 #if !defined(HAVE_FORK)
03022     struct rb_execarg sarg, *const sargp = &sarg;
03023 #else
03024     struct rb_execarg *const sargp = NULL;
03025 #endif
03026 
03027     before_exec_async_signal_safe(); /* async-signal-safe */
03028 
03029     if (rb_execarg_run_options(eargp, sargp, errmsg, errmsg_buflen) < 0) { /* hopefully async-signal-safe */
03030         goto failure;
03031     }
03032 
03033     if (eargp->use_shell) {
03034         proc_exec_sh(RSTRING_PTR(eargp->invoke.sh.shell_script), eargp->envp_str); /* async-signal-safe */
03035     }
03036     else {
03037         char *abspath = NULL;
03038         if (!NIL_P(eargp->invoke.cmd.command_abspath))
03039             abspath = RSTRING_PTR(eargp->invoke.cmd.command_abspath);
03040         proc_exec_cmd(abspath, eargp->invoke.cmd.argv_str, eargp->envp_str); /* async-signal-safe */
03041     }
03042 #if !defined(HAVE_FORK)
03043     preserving_errno(rb_execarg_run_options(sargp, NULL, errmsg, errmsg_buflen));
03044 #endif
03045 
03046 failure:
03047     preserving_errno(after_exec_async_signal_safe()); /* async-signal-safe */
03048     return -1;
03049 }
03050 
03051 static int
03052 rb_exec_without_timer_thread(const struct rb_execarg *eargp, char *errmsg, size_t errmsg_buflen)
03053 {
03054     int ret;
03055     before_exec_non_async_signal_safe(); /* async-signal-safe if forked_child is true */
03056     ret = rb_exec_async_signal_safe(eargp, errmsg, errmsg_buflen); /* hopefully async-signal-safe */
03057     preserving_errno(after_exec_non_async_signal_safe()); /* not async-signal-safe because it calls rb_thread_start_timer_thread.  */
03058     return ret;
03059 }
03060 
03061 int
03062 rb_exec_err(const struct rb_exec_arg *e, char *errmsg, size_t errmsg_buflen)
03063 {
03064     return rb_exec_without_timer_thread(rb_execarg_get(e->execarg_obj), errmsg, errmsg_buflen);
03065 }
03066 
03067 int
03068 rb_exec(const struct rb_exec_arg *e)
03069 {
03070 #if !defined FD_CLOEXEC && !defined HAVE_SPAWNV
03071     char errmsg[80] = { '\0' };
03072     int ret = rb_exec_without_timer_thread(rb_execarg_get(e->execarg_obj), errmsg, sizeof(errmsg));
03073     preserving_errno(
03074         if (errmsg[0]) {
03075             fprintf(stderr, "%s\n", errmsg);
03076         }
03077         else {
03078             fprintf(stderr, "%s:%d: command not found: %s\n",
03079                     rb_sourcefile(), rb_sourceline(),
03080                     RSTRING_PTR(e->use_shell ? e->invoke.sh.shell_script : e->invoke.cmd.command_name));
03081         }
03082     );
03083     return ret;
03084 #else
03085     return rb_exec_without_timer_thread(rb_execarg_get(e->execarg_obj), NULL, 0);
03086 #endif
03087 }
03088 
03089 #ifdef HAVE_FORK
03090 /* This function should be async-signal-safe.  Hopefully it is. */
03091 static int
03092 rb_exec_atfork(void* arg, char *errmsg, size_t errmsg_buflen)
03093 {
03094     return rb_exec_async_signal_safe(arg, errmsg, errmsg_buflen); /* hopefully async-signal-safe */
03095 }
03096 #endif
03097 
03098 #ifdef HAVE_FORK
03099 #if SIZEOF_INT == SIZEOF_LONG
03100 #define proc_syswait (VALUE (*)(VALUE))rb_syswait
03101 #else
03102 static VALUE
03103 proc_syswait(VALUE pid)
03104 {
03105     rb_syswait((int)pid);
03106     return Qnil;
03107 }
03108 #endif
03109 
03110 static int
03111 move_fds_to_avoid_crash(int *fdp, int n, VALUE fds)
03112 {
03113     int min = 0;
03114     int i;
03115     for (i = 0; i < n; i++) {
03116         int ret;
03117         while (RTEST(rb_hash_lookup(fds, INT2FIX(fdp[i])))) {
03118             if (min <= fdp[i])
03119                 min = fdp[i]+1;
03120             while (RTEST(rb_hash_lookup(fds, INT2FIX(min))))
03121                 min++;
03122             ret = rb_cloexec_fcntl_dupfd(fdp[i], min);
03123             if (ret == -1)
03124                 return -1;
03125             rb_update_max_fd(ret);
03126             close(fdp[i]);
03127             fdp[i] = ret;
03128         }
03129     }
03130     return 0;
03131 }
03132 
03133 static int
03134 pipe_nocrash(int filedes[2], VALUE fds)
03135 {
03136     int ret;
03137     ret = rb_pipe(filedes);
03138     if (ret == -1)
03139         return -1;
03140     if (RTEST(fds)) {
03141         int save = errno;
03142         if (move_fds_to_avoid_crash(filedes, 2, fds) == -1) {
03143             close(filedes[0]);
03144             close(filedes[1]);
03145             return -1;
03146         }
03147         errno = save;
03148     }
03149     return ret;
03150 }
03151 
03152 struct chfunc_protect_t {
03153     int (*chfunc)(void*, char *, size_t);
03154     void *arg;
03155     char *errmsg;
03156     size_t buflen;
03157 };
03158 
03159 static VALUE
03160 chfunc_protect(VALUE arg)
03161 {
03162     struct chfunc_protect_t *p = (struct chfunc_protect_t *)arg;
03163 
03164     return (VALUE)(*p->chfunc)(p->arg, p->errmsg, p->buflen);
03165 }
03166 
03167 #ifndef O_BINARY
03168 #define O_BINARY 0
03169 #endif
03170 
03171 /*
03172  * Forks child process, and returns the process ID in the parent
03173  * process.
03174  *
03175  * If +status+ is given, protects from any exceptions and sets the
03176  * jump status to it, and returns -1.  If failed to fork new process
03177  * but no exceptions occurred, sets 0 to it.  Otherwise, if forked
03178  * successfully, the value of +status+ is undetermined.
03179  *
03180  * In the child process, just returns 0 if +chfunc+ is +NULL+.
03181  * Otherwise +chfunc+ will be called with +charg+, and then the child
03182  * process exits with +EXIT_SUCCESS+ when it returned zero.
03183  *
03184  * In the case of the function is called and returns non-zero value,
03185  * the child process exits with non-+EXIT_SUCCESS+ value (normally
03186  * 127).  And, on the platforms where +FD_CLOEXEC+ is available,
03187  * +errno+ is propagated to the parent process, and this function
03188  * returns -1 in the parent process.  On the other platforms, just
03189  * returns pid.
03190  *
03191  * If fds is not Qnil, internal pipe for the errno propagation is
03192  * arranged to avoid conflicts of the hash keys in +fds+.
03193  *
03194  * +chfunc+ must not raise any exceptions.
03195  */
03196 
03197 static rb_pid_t
03198 retry_fork(int *status, int *ep, int chfunc_is_async_signal_safe)
03199 {
03200     rb_pid_t pid;
03201     int state = 0;
03202 
03203 #define prefork() (             \
03204         rb_io_flush(rb_stdout), \
03205         rb_io_flush(rb_stderr)  \
03206         )
03207 
03208     while (1) {
03209         prefork();
03210         if (!chfunc_is_async_signal_safe)
03211             before_fork();
03212         pid = fork();
03213         if (pid == 0) /* fork succeed, child process */
03214             return pid;
03215         if (!chfunc_is_async_signal_safe)
03216             preserving_errno(after_fork());
03217         if (0 < pid) /* fork succeed, parent process */
03218             return pid;
03219         /* fork failed */
03220         switch (errno) {
03221           case EAGAIN:
03222 #if defined(EWOULDBLOCK) && EWOULDBLOCK != EAGAIN
03223           case EWOULDBLOCK:
03224 #endif
03225             if (!status && !ep) {
03226                 rb_thread_sleep(1);
03227                 continue;
03228             }
03229             else {
03230                 rb_protect((VALUE (*)())rb_thread_sleep, 1, &state);
03231                 if (status) *status = state;
03232                 if (!state) continue;
03233             }
03234             /* fall through */
03235           default:
03236             if (ep) {
03237                 preserving_errno((close(ep[0]), close(ep[1])));
03238             }
03239             if (state && !status) rb_jump_tag(state);
03240             return -1;
03241         }
03242     }
03243 }
03244 
03245 static void
03246 send_child_error(int fd, int state, char *errmsg, size_t errmsg_buflen, int chfunc_is_async_signal_safe)
03247 {
03248     VALUE io = Qnil;
03249     int err;
03250 
03251     if (!chfunc_is_async_signal_safe) {
03252         if (write(fd, &state, sizeof(state)) == sizeof(state) && state) {
03253             VALUE errinfo = rb_errinfo();
03254             io = rb_io_fdopen(fd, O_WRONLY|O_BINARY, NULL);
03255             rb_marshal_dump(errinfo, io);
03256             rb_io_flush(io);
03257         }
03258     }
03259     err = errno;
03260     if (write(fd, &err, sizeof(err)) < 0) err = errno;
03261     if (errmsg && 0 < errmsg_buflen) {
03262         errmsg[errmsg_buflen-1] = '\0';
03263         errmsg_buflen = strlen(errmsg);
03264         if (errmsg_buflen > 0 && write(fd, errmsg, errmsg_buflen) < 0)
03265             err = errno;
03266     }
03267     if (!NIL_P(io)) rb_io_close(io);
03268 }
03269 
03270 static int
03271 recv_child_error(int fd, int *statep, VALUE *excp, int *errp, char *errmsg, size_t errmsg_buflen, int chfunc_is_async_signal_safe)
03272 {
03273     int err, state = 0;
03274     VALUE io = Qnil;
03275     ssize_t size;
03276     VALUE exc = Qnil;
03277     if (!chfunc_is_async_signal_safe) {
03278         if ((read(fd, &state, sizeof(state))) == sizeof(state) && state) {
03279             io = rb_io_fdopen(fd, O_RDONLY|O_BINARY, NULL);
03280             exc = rb_marshal_load(io);
03281             rb_set_errinfo(exc);
03282         }
03283         if (!*statep && state) *statep = state;
03284         *excp = exc;
03285     }
03286 #define READ_FROM_CHILD(ptr, len) \
03287     (NIL_P(io) ? read(fd, (ptr), (len)) : rb_io_bufread(io, (ptr), (len)))
03288     if ((size = READ_FROM_CHILD(&err, sizeof(err))) < 0) {
03289         err = errno;
03290     }
03291     *errp = err;
03292     if (size == sizeof(err) &&
03293         errmsg && 0 < errmsg_buflen) {
03294         ssize_t ret = READ_FROM_CHILD(errmsg, errmsg_buflen-1);
03295         if (0 <= ret) {
03296             errmsg[ret] = '\0';
03297         }
03298     }
03299     if (NIL_P(io))
03300         close(fd);
03301     else
03302         rb_io_close(io);
03303     return size != 0;
03304 }
03305 
03306 static rb_pid_t
03307 rb_fork_internal(int *status, int (*chfunc)(void*, char *, size_t), void *charg,
03308         int chfunc_is_async_signal_safe, VALUE fds,
03309         char *errmsg, size_t errmsg_buflen)
03310 {
03311     rb_pid_t pid;
03312     int err, state = 0;
03313     int ep[2];
03314     VALUE exc = Qnil;
03315     int error_occured;
03316 
03317     if (status) *status = 0;
03318 
03319     if (!chfunc) {
03320         pid = retry_fork(status, NULL, FALSE);
03321         if (pid < 0)
03322             return pid;
03323         if (!pid) {
03324             forked_child = 1;
03325             after_fork();
03326         }
03327         return pid;
03328     }
03329     else {
03330         if (pipe_nocrash(ep, fds)) return -1;
03331         if (fcntl(ep[1], F_SETFD, FD_CLOEXEC)) {
03332             preserving_errno((close(ep[0]), close(ep[1])));
03333             return -1;
03334         }
03335         pid = retry_fork(status, ep, chfunc_is_async_signal_safe);
03336         if (pid < 0)
03337             return pid;
03338         if (!pid) {
03339             int ret;
03340             forked_child = 1;
03341             close(ep[0]);
03342             if (chfunc_is_async_signal_safe)
03343                 ret = chfunc(charg, errmsg, errmsg_buflen);
03344             else {
03345                 struct chfunc_protect_t arg;
03346                 arg.chfunc = chfunc;
03347                 arg.arg = charg;
03348                 arg.errmsg = errmsg;
03349                 arg.buflen = errmsg_buflen;
03350                 ret = (int)rb_protect(chfunc_protect, (VALUE)&arg, &state);
03351             }
03352             if (!ret) _exit(EXIT_SUCCESS);
03353             send_child_error(ep[1], state, errmsg, errmsg_buflen, chfunc_is_async_signal_safe);
03354 #if EXIT_SUCCESS == 127
03355             _exit(EXIT_FAILURE);
03356 #else
03357             _exit(127);
03358 #endif
03359         }
03360         close(ep[1]);
03361         error_occured = recv_child_error(ep[0], &state, &exc, &err, errmsg, errmsg_buflen, chfunc_is_async_signal_safe);
03362         if (state || error_occured) {
03363             if (status) {
03364                 rb_protect(proc_syswait, (VALUE)pid, status);
03365                 if (state) *status = state;
03366             }
03367             else {
03368                 rb_syswait(pid);
03369                 if (state) rb_exc_raise(exc);
03370             }
03371             errno = err;
03372             return -1;
03373         }
03374         return pid;
03375     }
03376 }
03377 
03378 rb_pid_t
03379 rb_fork_err(int *status, int (*chfunc)(void*, char *, size_t), void *charg, VALUE fds,
03380         char *errmsg, size_t errmsg_buflen)
03381 {
03382     return rb_fork_internal(status, chfunc, charg, FALSE, fds, errmsg, errmsg_buflen);
03383 }
03384 
03385 rb_pid_t
03386 rb_fork_async_signal_safe(int *status, int (*chfunc)(void*, char *, size_t), void *charg, VALUE fds,
03387         char *errmsg, size_t errmsg_buflen)
03388 {
03389     return rb_fork_internal(status, chfunc, charg, TRUE, fds, errmsg, errmsg_buflen);
03390 }
03391 
03392 struct chfunc_wrapper_t {
03393     int (*chfunc)(void*);
03394     void *arg;
03395 };
03396 
03397 static int
03398 chfunc_wrapper(void *arg_, char *errmsg, size_t errmsg_buflen)
03399 {
03400     struct chfunc_wrapper_t *arg = arg_;
03401     return arg->chfunc(arg->arg);
03402 }
03403 
03404 rb_pid_t
03405 rb_fork(int *status, int (*chfunc)(void*), void *charg, VALUE fds)
03406 {
03407     if (chfunc) {
03408         struct chfunc_wrapper_t warg;
03409         warg.chfunc = chfunc;
03410         warg.arg = charg;
03411         return rb_fork_internal(status, chfunc_wrapper, &warg, FALSE, fds, NULL, 0);
03412     }
03413     else {
03414         return rb_fork_internal(status, NULL, NULL, FALSE, fds, NULL, 0);
03415     }
03416 
03417 }
03418 
03419 rb_pid_t
03420 rb_fork_ruby(int *status)
03421 {
03422     return rb_fork_internal(status, NULL, NULL, FALSE, Qnil, NULL, 0);
03423 }
03424 
03425 #endif
03426 
03427 #if defined(HAVE_FORK) && !defined(CANNOT_FORK_WITH_PTHREAD)
03428 /*
03429  *  call-seq:
03430  *     Kernel.fork  [{ block }]   -> fixnum or nil
03431  *     Process.fork [{ block }]   -> fixnum or nil
03432  *
03433  *  Creates a subprocess. If a block is specified, that block is run
03434  *  in the subprocess, and the subprocess terminates with a status of
03435  *  zero. Otherwise, the +fork+ call returns twice, once in
03436  *  the parent, returning the process ID of the child, and once in
03437  *  the child, returning _nil_. The child process can exit using
03438  *  <code>Kernel.exit!</code> to avoid running any
03439  *  <code>at_exit</code> functions. The parent process should
03440  *  use <code>Process.wait</code> to collect the termination statuses
03441  *  of its children or use <code>Process.detach</code> to register
03442  *  disinterest in their status; otherwise, the operating system
03443  *  may accumulate zombie processes.
03444  *
03445  *  The thread calling fork is the only thread in the created child process.
03446  *  fork doesn't copy other threads.
03447  *
03448  *  If fork is not usable, Process.respond_to?(:fork) returns false.
03449  */
03450 
03451 static VALUE
03452 rb_f_fork(VALUE obj)
03453 {
03454     rb_pid_t pid;
03455 
03456     rb_secure(2);
03457 
03458     switch (pid = rb_fork_ruby(NULL)) {
03459       case 0:
03460         rb_thread_atfork();
03461         if (rb_block_given_p()) {
03462             int status;
03463 
03464             rb_protect(rb_yield, Qundef, &status);
03465             ruby_stop(status);
03466         }
03467         return Qnil;
03468 
03469       case -1:
03470         rb_sys_fail("fork(2)");
03471         return Qnil;
03472 
03473       default:
03474         return PIDT2NUM(pid);
03475     }
03476 }
03477 #else
03478 #define rb_f_fork rb_f_notimplement
03479 #endif
03480 
03481 static int
03482 exit_status_code(VALUE status)
03483 {
03484     int istatus;
03485 
03486     switch (status) {
03487       case Qtrue:
03488         istatus = EXIT_SUCCESS;
03489         break;
03490       case Qfalse:
03491         istatus = EXIT_FAILURE;
03492         break;
03493       default:
03494         istatus = NUM2INT(status);
03495 #if EXIT_SUCCESS != 0
03496         if (istatus == 0)
03497             istatus = EXIT_SUCCESS;
03498 #endif
03499         break;
03500     }
03501     return istatus;
03502 }
03503 
03504 /*
03505  *  call-seq:
03506  *     Process.exit!(status=false)
03507  *
03508  *  Exits the process immediately. No exit handlers are
03509  *  run. <em>status</em> is returned to the underlying system as the
03510  *  exit status.
03511  *
03512  *     Process.exit!(true)
03513  */
03514 
03515 static VALUE
03516 rb_f_exit_bang(int argc, VALUE *argv, VALUE obj)
03517 {
03518     VALUE status;
03519     int istatus;
03520 
03521     rb_secure(4);
03522     if (argc > 0 && rb_scan_args(argc, argv, "01", &status) == 1) {
03523         istatus = exit_status_code(status);
03524     }
03525     else {
03526         istatus = EXIT_FAILURE;
03527     }
03528     _exit(istatus);
03529 
03530     UNREACHABLE;
03531 }
03532 
03533 void
03534 rb_exit(int status)
03535 {
03536     if (GET_THREAD()->tag) {
03537         VALUE args[2];
03538 
03539         args[0] = INT2NUM(status);
03540         args[1] = rb_str_new2("exit");
03541         rb_exc_raise(rb_class_new_instance(2, args, rb_eSystemExit));
03542     }
03543     ruby_finalize();
03544     exit(status);
03545 }
03546 
03547 
03548 /*
03549  *  call-seq:
03550  *     exit(status=true)
03551  *     Kernel::exit(status=true)
03552  *     Process::exit(status=true)
03553  *
03554  *  Initiates the termination of the Ruby script by raising the
03555  *  <code>SystemExit</code> exception. This exception may be caught. The
03556  *  optional parameter is used to return a status code to the invoking
03557  *  environment.
03558  *  +true+ and +FALSE+ of _status_ means success and failure
03559  *  respectively.  The interpretation of other integer values are
03560  *  system dependent.
03561  *
03562  *     begin
03563  *       exit
03564  *       puts "never get here"
03565  *     rescue SystemExit
03566  *       puts "rescued a SystemExit exception"
03567  *     end
03568  *     puts "after begin block"
03569  *
03570  *  <em>produces:</em>
03571  *
03572  *     rescued a SystemExit exception
03573  *     after begin block
03574  *
03575  *  Just prior to termination, Ruby executes any <code>at_exit</code> functions
03576  *  (see Kernel::at_exit) and runs any object finalizers (see
03577  *  ObjectSpace::define_finalizer).
03578  *
03579  *     at_exit { puts "at_exit function" }
03580  *     ObjectSpace.define_finalizer("string",  proc { puts "in finalizer" })
03581  *     exit
03582  *
03583  *  <em>produces:</em>
03584  *
03585  *     at_exit function
03586  *     in finalizer
03587  */
03588 
03589 VALUE
03590 rb_f_exit(int argc, VALUE *argv)
03591 {
03592     VALUE status;
03593     int istatus;
03594 
03595     rb_secure(4);
03596     if (argc > 0 && rb_scan_args(argc, argv, "01", &status) == 1) {
03597         istatus = exit_status_code(status);
03598     }
03599     else {
03600         istatus = EXIT_SUCCESS;
03601     }
03602     rb_exit(istatus);
03603 
03604     UNREACHABLE;
03605 }
03606 
03607 
03608 /*
03609  *  call-seq:
03610  *     abort
03611  *     Kernel::abort([msg])
03612  *     Process::abort([msg])
03613  *
03614  *  Terminate execution immediately, effectively by calling
03615  *  <code>Kernel.exit(false)</code>. If _msg_ is given, it is written
03616  *  to STDERR prior to terminating.
03617  */
03618 
03619 VALUE
03620 rb_f_abort(int argc, VALUE *argv)
03621 {
03622     rb_secure(4);
03623     if (argc == 0) {
03624         if (!NIL_P(GET_THREAD()->errinfo)) {
03625             ruby_error_print();
03626         }
03627         rb_exit(EXIT_FAILURE);
03628     }
03629     else {
03630         VALUE args[2];
03631 
03632         rb_scan_args(argc, argv, "1", &args[1]);
03633         StringValue(argv[0]);
03634         rb_io_puts(argc, argv, rb_stderr);
03635         args[0] = INT2NUM(EXIT_FAILURE);
03636         rb_exc_raise(rb_class_new_instance(2, args, rb_eSystemExit));
03637     }
03638 
03639     UNREACHABLE;
03640 }
03641 
03642 void
03643 rb_syswait(rb_pid_t pid)
03644 {
03645     int status;
03646 
03647     rb_waitpid(pid, &status, 0);
03648 }
03649 
03650 static rb_pid_t
03651 rb_spawn_process(struct rb_execarg *eargp, char *errmsg, size_t errmsg_buflen)
03652 {
03653     rb_pid_t pid;
03654 #if !USE_SPAWNV
03655     int status;
03656 #endif
03657 #if !defined HAVE_FORK || USE_SPAWNV
03658     VALUE prog;
03659     struct rb_execarg sarg;
03660 #endif
03661 
03662 #if defined HAVE_FORK && !USE_SPAWNV
03663     pid = rb_fork_async_signal_safe(&status, rb_exec_atfork, eargp, eargp->redirect_fds, errmsg, errmsg_buflen);
03664 #else
03665     prog = eargp->use_shell ? eargp->invoke.sh.shell_script : eargp->invoke.cmd.command_name;
03666 
03667     if (rb_execarg_run_options(eargp, &sarg, errmsg, errmsg_buflen) < 0) {
03668         return -1;
03669     }
03670 
03671     if (prog && !eargp->use_shell) {
03672         char **argv = ARGVSTR2ARGV(eargp->invoke.cmd.argv_str);
03673         argv[0] = RSTRING_PTR(prog);
03674     }
03675 # if defined HAVE_SPAWNV
03676     if (eargp->use_shell) {
03677         pid = proc_spawn_sh(RSTRING_PTR(prog));
03678     }
03679     else {
03680         char **argv = ARGVSTR2ARGV(eargp->invoke.cmd.argv_str);
03681         pid = proc_spawn_cmd(argv, prog, eargp);
03682     }
03683 #  if defined(_WIN32)
03684     if (pid == -1)
03685         rb_last_status_set(0x7f << 8, 0);
03686 #  endif
03687 # else
03688     if (!eargp->use_shell) {
03689         char **argv = ARGVSTR2ARGV(eargp->invoke.cmd.argv_str);
03690         int argc = ARGVSTR2ARGC(eargp->invoke.cmd.argv_str);
03691         prog = rb_ary_join(rb_ary_new4(argc, argv), rb_str_new2(" "));
03692     }
03693     status = system(StringValuePtr(prog));
03694     rb_last_status_set((status & 0xff) << 8, 0);
03695 # endif
03696 
03697     rb_execarg_run_options(&sarg, NULL, errmsg, errmsg_buflen);
03698 #endif
03699     return pid;
03700 }
03701 
03702 static rb_pid_t
03703 rb_spawn_internal(int argc, VALUE *argv, char *errmsg, size_t errmsg_buflen)
03704 {
03705     VALUE execarg_obj;
03706     struct rb_execarg *eargp;
03707     rb_pid_t ret;
03708 
03709     execarg_obj = rb_execarg_new(argc, argv, TRUE);
03710     eargp = rb_execarg_get(execarg_obj);
03711     rb_execarg_fixup(execarg_obj);
03712     ret = rb_spawn_process(eargp, errmsg, errmsg_buflen);
03713     RB_GC_GUARD(execarg_obj);
03714     return ret;
03715 }
03716 
03717 rb_pid_t
03718 rb_spawn_err(int argc, VALUE *argv, char *errmsg, size_t errmsg_buflen)
03719 {
03720     return rb_spawn_internal(argc, argv, errmsg, errmsg_buflen);
03721 }
03722 
03723 rb_pid_t
03724 rb_spawn(int argc, VALUE *argv)
03725 {
03726     return rb_spawn_internal(argc, argv, NULL, 0);
03727 }
03728 
03729 /*
03730  *  call-seq:
03731  *     system([env,] command... [,options])    -> true, false or nil
03732  *
03733  *  Executes _command..._ in a subshell.
03734  *  _command..._ is one of following forms.
03735  *
03736  *    commandline                 : command line string which is passed to the standard shell
03737  *    cmdname, arg1, ...          : command name and one or more arguments (no shell)
03738  *    [cmdname, argv0], arg1, ... : command name, argv[0] and zero or more arguments (no shell)
03739  *
03740  *  system returns +true+ if the command gives zero exit status,
03741  *  +false+ for non zero exit status.
03742  *  Returns +nil+ if command execution fails.
03743  *  An error status is available in <code>$?</code>.
03744  *  The arguments are processed in the same way as
03745  *  for <code>Kernel.spawn</code>.
03746  *
03747  *  The hash arguments, env and options, are same as
03748  *  <code>exec</code> and <code>spawn</code>.
03749  *  See <code>Kernel.spawn</code> for details.
03750  *
03751  *     system("echo *")
03752  *     system("echo", "*")
03753  *
03754  *  <em>produces:</em>
03755  *
03756  *     config.h main.rb
03757  *     *
03758  *
03759  *  See <code>Kernel.exec</code> for the standard shell.
03760  */
03761 
03762 static VALUE
03763 rb_f_system(int argc, VALUE *argv)
03764 {
03765     rb_pid_t pid;
03766     int status;
03767 
03768 #if defined(SIGCLD) && !defined(SIGCHLD)
03769 # define SIGCHLD SIGCLD
03770 #endif
03771 
03772 #ifdef SIGCHLD
03773     RETSIGTYPE (*chfunc)(int);
03774 
03775     rb_last_status_clear();
03776     chfunc = signal(SIGCHLD, SIG_DFL);
03777 #endif
03778     pid = rb_spawn_internal(argc, argv, NULL, 0);
03779 #if defined(HAVE_FORK) || defined(HAVE_SPAWNV)
03780     if (pid > 0) {
03781         int ret, status;
03782         ret = rb_waitpid(pid, &status, 0);
03783         if (ret == (rb_pid_t)-1)
03784             rb_sys_fail("Another thread waited the process started by system().");
03785     }
03786 #endif
03787 #ifdef SIGCHLD
03788     signal(SIGCHLD, chfunc);
03789 #endif
03790     if (pid < 0) {
03791         return Qnil;
03792     }
03793     status = PST2INT(rb_last_status_get());
03794     if (status == EXIT_SUCCESS) return Qtrue;
03795     return Qfalse;
03796 }
03797 
03798 /*
03799  *  call-seq:
03800  *     spawn([env,] command... [,options])     -> pid
03801  *     Process.spawn([env,] command... [,options])     -> pid
03802  *
03803  *  spawn executes specified command and return its pid.
03804  *
03805  *  This method doesn't wait for end of the command.
03806  *  The parent process should
03807  *  use <code>Process.wait</code> to collect
03808  *  the termination status of its child or
03809  *  use <code>Process.detach</code> to register
03810  *  disinterest in their status;
03811  *  otherwise, the operating system may accumulate zombie processes.
03812  *
03813  *  spawn has bunch of options to specify process attributes:
03814  *
03815  *    env: hash
03816  *      name => val : set the environment variable
03817  *      name => nil : unset the environment variable
03818  *    command...:
03819  *      commandline                 : command line string which is passed to the standard shell
03820  *      cmdname, arg1, ...          : command name and one or more arguments (no shell)
03821  *      [cmdname, argv0], arg1, ... : command name, argv[0] and zero or more arguments (no shell)
03822  *    options: hash
03823  *      clearing environment variables:
03824  *        :unsetenv_others => true   : clear environment variables except specified by env
03825  *        :unsetenv_others => false  : don't clear (default)
03826  *      process group:
03827  *        :pgroup => true or 0 : make a new process group
03828  *        :pgroup => pgid      : join to specified process group
03829  *        :pgroup => nil       : don't change the process group (default)
03830  *      create new process group: Windows only
03831  *        :new_pgroup => true  : the new process is the root process of a new process group
03832  *        :new_pgroup => false : don't create a new process group (default)
03833  *      resource limit: resourcename is core, cpu, data, etc.  See Process.setrlimit.
03834  *        :rlimit_resourcename => limit
03835  *        :rlimit_resourcename => [cur_limit, max_limit]
03836  *      umask:
03837  *        :umask => int
03838  *      redirection:
03839  *        key:
03840  *          FD              : single file descriptor in child process
03841  *          [FD, FD, ...]   : multiple file descriptor in child process
03842  *        value:
03843  *          FD                        : redirect to the file descriptor in parent process
03844  *          string                    : redirect to file with open(string, "r" or "w")
03845  *          [string]                  : redirect to file with open(string, File::RDONLY)
03846  *          [string, open_mode]       : redirect to file with open(string, open_mode, 0644)
03847  *          [string, open_mode, perm] : redirect to file with open(string, open_mode, perm)
03848  *          [:child, FD]              : redirect to the redirected file descriptor
03849  *          :close                    : close the file descriptor in child process
03850  *        FD is one of follows
03851  *          :in     : the file descriptor 0 which is the standard input
03852  *          :out    : the file descriptor 1 which is the standard output
03853  *          :err    : the file descriptor 2 which is the standard error
03854  *          integer : the file descriptor of specified the integer
03855  *          io      : the file descriptor specified as io.fileno
03856  *      file descriptor inheritance: close non-redirected non-standard fds (3, 4, 5, ...) or not
03857  *        :close_others => true  : don't inherit
03858  *      current directory:
03859  *        :chdir => str
03860  *
03861  *  If a hash is given as +env+, the environment is
03862  *  updated by +env+ before <code>exec(2)</code> in the child process.
03863  *  If a pair in +env+ has nil as the value, the variable is deleted.
03864  *
03865  *    # set FOO as BAR and unset BAZ.
03866  *    pid = spawn({"FOO"=>"BAR", "BAZ"=>nil}, command)
03867  *
03868  *  If a hash is given as +options+,
03869  *  it specifies
03870  *  process group,
03871  *  create new process group,
03872  *  resource limit,
03873  *  current directory,
03874  *  umask and
03875  *  redirects for the child process.
03876  *  Also, it can be specified to clear environment variables.
03877  *
03878  *  The <code>:unsetenv_others</code> key in +options+ specifies
03879  *  to clear environment variables, other than specified by +env+.
03880  *
03881  *    pid = spawn(command, :unsetenv_others=>true) # no environment variable
03882  *    pid = spawn({"FOO"=>"BAR"}, command, :unsetenv_others=>true) # FOO only
03883  *
03884  *  The <code>:pgroup</code> key in +options+ specifies a process group.
03885  *  The corresponding value should be true, zero or positive integer.
03886  *  true and zero means the process should be a process leader of a new
03887  *  process group.
03888  *  Other values specifies a process group to be belongs.
03889  *
03890  *    pid = spawn(command, :pgroup=>true) # process leader
03891  *    pid = spawn(command, :pgroup=>10) # belongs to the process group 10
03892  *
03893  *  The <code>:new_pgroup</code> key in +options+ specifies to pass
03894  *  +CREATE_NEW_PROCESS_GROUP+ flag to <code>CreateProcessW()</code> that is
03895  *  Windows API. This option is only for Windows.
03896  *  true means the new process is the root process of the new process group.
03897  *  The new process has CTRL+C disabled. This flag is necessary for
03898  *  <code>Process.kill(:SIGINT, pid)</code> on the subprocess.
03899  *  :new_pgroup is false by default.
03900  *
03901  *    pid = spawn(command, :new_pgroup=>true)  # new process group
03902  *    pid = spawn(command, :new_pgroup=>false) # same process group
03903  *
03904  *  The <code>:rlimit_</code><em>foo</em> key specifies a resource limit.
03905  *  <em>foo</em> should be one of resource types such as <code>core</code>.
03906  *  The corresponding value should be an integer or an array which have one or
03907  *  two integers: same as cur_limit and max_limit arguments for
03908  *  Process.setrlimit.
03909  *
03910  *    cur, max = Process.getrlimit(:CORE)
03911  *    pid = spawn(command, :rlimit_core=>[0,max]) # disable core temporary.
03912  *    pid = spawn(command, :rlimit_core=>max) # enable core dump
03913  *    pid = spawn(command, :rlimit_core=>0) # never dump core.
03914  *
03915  *  The <code>:umask</code> key in +options+ specifies the umask.
03916  *
03917  *    pid = spawn(command, :umask=>077)
03918  *
03919  *  The :in, :out, :err, a fixnum, an IO and an array key specifies a redirection.
03920  *  The redirection maps a file descriptor in the child process.
03921  *
03922  *  For example, stderr can be merged into stdout as follows:
03923  *
03924  *    pid = spawn(command, :err=>:out)
03925  *    pid = spawn(command, 2=>1)
03926  *    pid = spawn(command, STDERR=>:out)
03927  *    pid = spawn(command, STDERR=>STDOUT)
03928  *
03929  *  The hash keys specifies a file descriptor
03930  *  in the child process started by <code>spawn</code>.
03931  *  :err, 2 and STDERR specifies the standard error stream (stderr).
03932  *
03933  *  The hash values specifies a file descriptor
03934  *  in the parent process which invokes <code>spawn</code>.
03935  *  :out, 1 and STDOUT specifies the standard output stream (stdout).
03936  *
03937  *  In the above example,
03938  *  the standard output in the child process is not specified.
03939  *  So it is inherited from the parent process.
03940  *
03941  *  The standard input stream (stdin) can be specified by :in, 0 and STDIN.
03942  *
03943  *  A filename can be specified as a hash value.
03944  *
03945  *    pid = spawn(command, :in=>"/dev/null") # read mode
03946  *    pid = spawn(command, :out=>"/dev/null") # write mode
03947  *    pid = spawn(command, :err=>"log") # write mode
03948  *    pid = spawn(command, 3=>"/dev/null") # read mode
03949  *
03950  *  For stdout and stderr,
03951  *  it is opened in write mode.
03952  *  Otherwise read mode is used.
03953  *
03954  *  For specifying flags and permission of file creation explicitly,
03955  *  an array is used instead.
03956  *
03957  *    pid = spawn(command, :in=>["file"]) # read mode is assumed
03958  *    pid = spawn(command, :in=>["file", "r"])
03959  *    pid = spawn(command, :out=>["log", "w"]) # 0644 assumed
03960  *    pid = spawn(command, :out=>["log", "w", 0600])
03961  *    pid = spawn(command, :out=>["log", File::WRONLY|File::EXCL|File::CREAT, 0600])
03962  *
03963  *  The array specifies a filename, flags and permission.
03964  *  The flags can be a string or an integer.
03965  *  If the flags is omitted or nil, File::RDONLY is assumed.
03966  *  The permission should be an integer.
03967  *  If the permission is omitted or nil, 0644 is assumed.
03968  *
03969  *  If an array of IOs and integers are specified as a hash key,
03970  *  all the elements are redirected.
03971  *
03972  *    # stdout and stderr is redirected to log file.
03973  *    # The file "log" is opened just once.
03974  *    pid = spawn(command, [:out, :err]=>["log", "w"])
03975  *
03976  *  Another way to merge multiple file descriptors is [:child, fd].
03977  *  \[:child, fd] means the file descriptor in the child process.
03978  *  This is different from fd.
03979  *  For example, :err=>:out means redirecting child stderr to parent stdout.
03980  *  But :err=>[:child, :out] means redirecting child stderr to child stdout.
03981  *  They differ if stdout is redirected in the child process as follows.
03982  *
03983  *    # stdout and stderr is redirected to log file.
03984  *    # The file "log" is opened just once.
03985  *    pid = spawn(command, :out=>["log", "w"], :err=>[:child, :out])
03986  *
03987  *  \[:child, :out] can be used to merge stderr into stdout in IO.popen.
03988  *  In this case, IO.popen redirects stdout to a pipe in the child process
03989  *  and [:child, :out] refers the redirected stdout.
03990  *
03991  *    io = IO.popen(["sh", "-c", "echo out; echo err >&2", :err=>[:child, :out]])
03992  *    p io.read #=> "out\nerr\n"
03993  *
03994  *  The <code>:chdir</code> key in +options+ specifies the current directory.
03995  *
03996  *    pid = spawn(command, :chdir=>"/var/tmp")
03997  *
03998  *  spawn closes all non-standard unspecified descriptors by default.
03999  *  The "standard" descriptors are 0, 1 and 2.
04000  *  This behavior is specified by :close_others option.
04001  *  :close_others doesn't affect the standard descriptors which are
04002  *  closed only if :close is specified explicitly.
04003  *
04004  *    pid = spawn(command, :close_others=>true)  # close 3,4,5,... (default)
04005  *    pid = spawn(command, :close_others=>false) # don't close 3,4,5,...
04006  *
04007  *  :close_others is true by default for spawn and IO.popen.
04008  *
04009  *  Note that fds which close-on-exec flag is already set are closed
04010  *  regardless of :close_others option.
04011  *
04012  *  So IO.pipe and spawn can be used as IO.popen.
04013  *
04014  *    # similar to r = IO.popen(command)
04015  *    r, w = IO.pipe
04016  *    pid = spawn(command, :out=>w)   # r, w is closed in the child process.
04017  *    w.close
04018  *
04019  *  :close is specified as a hash value to close a fd individually.
04020  *
04021  *    f = open(foo)
04022  *    system(command, f=>:close)        # don't inherit f.
04023  *
04024  *  If a file descriptor need to be inherited,
04025  *  io=>io can be used.
04026  *
04027  *    # valgrind has --log-fd option for log destination.
04028  *    # log_w=>log_w indicates log_w.fileno inherits to child process.
04029  *    log_r, log_w = IO.pipe
04030  *    pid = spawn("valgrind", "--log-fd=#{log_w.fileno}", "echo", "a", log_w=>log_w)
04031  *    log_w.close
04032  *    p log_r.read
04033  *
04034  *  It is also possible to exchange file descriptors.
04035  *
04036  *    pid = spawn(command, :out=>:err, :err=>:out)
04037  *
04038  *  The hash keys specify file descriptors in the child process.
04039  *  The hash values specifies file descriptors in the parent process.
04040  *  So the above specifies exchanging stdout and stderr.
04041  *  Internally, +spawn+ uses an extra file descriptor to resolve such cyclic
04042  *  file descriptor mapping.
04043  *
04044  *  See <code>Kernel.exec</code> for the standard shell.
04045  */
04046 
04047 static VALUE
04048 rb_f_spawn(int argc, VALUE *argv)
04049 {
04050     rb_pid_t pid;
04051     char errmsg[CHILD_ERRMSG_BUFLEN] = { '\0' };
04052     VALUE execarg_obj, fail_str;
04053     struct rb_execarg *eargp;
04054 
04055     execarg_obj = rb_execarg_new(argc, argv, TRUE);
04056     eargp = rb_execarg_get(execarg_obj);
04057     rb_execarg_fixup(execarg_obj);
04058     fail_str = eargp->use_shell ? eargp->invoke.sh.shell_script : eargp->invoke.cmd.command_name;
04059 
04060     pid = rb_spawn_process(eargp, errmsg, sizeof(errmsg));
04061     RB_GC_GUARD(execarg_obj);
04062 
04063     if (pid == -1) {
04064         const char *prog = errmsg;
04065         if (!prog[0]) {
04066             rb_sys_fail_str(fail_str);
04067         }
04068         rb_sys_fail(prog);
04069     }
04070 #if defined(HAVE_FORK) || defined(HAVE_SPAWNV)
04071     return PIDT2NUM(pid);
04072 #else
04073     return Qnil;
04074 #endif
04075 }
04076 
04077 /*
04078  *  call-seq:
04079  *     sleep([duration])    -> fixnum
04080  *
04081  *  Suspends the current thread for _duration_ seconds (which may be any number,
04082  *  including a +Float+ with fractional seconds). Returns the actual number of
04083  *  seconds slept (rounded), which may be less than that asked for if another
04084  *  thread calls <code>Thread#run</code>. Called without an argument, sleep()
04085  *  will sleep forever.
04086  *
04087  *     Time.new    #=> 2008-03-08 19:56:19 +0900
04088  *     sleep 1.2   #=> 1
04089  *     Time.new    #=> 2008-03-08 19:56:20 +0900
04090  *     sleep 1.9   #=> 2
04091  *     Time.new    #=> 2008-03-08 19:56:22 +0900
04092  */
04093 
04094 static VALUE
04095 rb_f_sleep(int argc, VALUE *argv)
04096 {
04097     time_t beg, end;
04098 
04099     beg = time(0);
04100     if (argc == 0) {
04101         rb_thread_sleep_forever();
04102     }
04103     else {
04104         rb_check_arity(argc, 0, 1);
04105         rb_thread_wait_for(rb_time_interval(argv[0]));
04106     }
04107 
04108     end = time(0) - beg;
04109 
04110     return INT2FIX(end);
04111 }
04112 
04113 
04114 #if (defined(HAVE_GETPGRP) && defined(GETPGRP_VOID)) || defined(HAVE_GETPGID)
04115 /*
04116  *  call-seq:
04117  *     Process.getpgrp   -> integer
04118  *
04119  *  Returns the process group ID for this process. Not available on
04120  *  all platforms.
04121  *
04122  *     Process.getpgid(0)   #=> 25527
04123  *     Process.getpgrp      #=> 25527
04124  */
04125 
04126 static VALUE
04127 proc_getpgrp(void)
04128 {
04129     rb_pid_t pgrp;
04130 
04131     rb_secure(2);
04132 #if defined(HAVE_GETPGRP) && defined(GETPGRP_VOID)
04133     pgrp = getpgrp();
04134     if (pgrp < 0) rb_sys_fail(0);
04135     return PIDT2NUM(pgrp);
04136 #else /* defined(HAVE_GETPGID) */
04137     pgrp = getpgid(0);
04138     if (pgrp < 0) rb_sys_fail(0);
04139     return PIDT2NUM(pgrp);
04140 #endif
04141 }
04142 #else
04143 #define proc_getpgrp rb_f_notimplement
04144 #endif
04145 
04146 
04147 #if defined(HAVE_SETPGID) || (defined(HAVE_SETPGRP) && defined(SETPGRP_VOID))
04148 /*
04149  *  call-seq:
04150  *     Process.setpgrp   -> 0
04151  *
04152  *  Equivalent to <code>setpgid(0,0)</code>. Not available on all
04153  *  platforms.
04154  */
04155 
04156 static VALUE
04157 proc_setpgrp(void)
04158 {
04159     rb_secure(2);
04160   /* check for posix setpgid() first; this matches the posix */
04161   /* getpgrp() above.  It appears that configure will set SETPGRP_VOID */
04162   /* even though setpgrp(0,0) would be preferred. The posix call avoids */
04163   /* this confusion. */
04164 #ifdef HAVE_SETPGID
04165     if (setpgid(0,0) < 0) rb_sys_fail(0);
04166 #elif defined(HAVE_SETPGRP) && defined(SETPGRP_VOID)
04167     if (setpgrp() < 0) rb_sys_fail(0);
04168 #endif
04169     return INT2FIX(0);
04170 }
04171 #else
04172 #define proc_setpgrp rb_f_notimplement
04173 #endif
04174 
04175 
04176 #if defined(HAVE_GETPGID)
04177 /*
04178  *  call-seq:
04179  *     Process.getpgid(pid)   -> integer
04180  *
04181  *  Returns the process group ID for the given process id. Not
04182  *  available on all platforms.
04183  *
04184  *     Process.getpgid(Process.ppid())   #=> 25527
04185  */
04186 
04187 static VALUE
04188 proc_getpgid(VALUE obj, VALUE pid)
04189 {
04190     rb_pid_t i;
04191 
04192     rb_secure(2);
04193     i = getpgid(NUM2PIDT(pid));
04194     if (i < 0) rb_sys_fail(0);
04195     return PIDT2NUM(i);
04196 }
04197 #else
04198 #define proc_getpgid rb_f_notimplement
04199 #endif
04200 
04201 
04202 #ifdef HAVE_SETPGID
04203 /*
04204  *  call-seq:
04205  *     Process.setpgid(pid, integer)   -> 0
04206  *
04207  *  Sets the process group ID of _pid_ (0 indicates this
04208  *  process) to <em>integer</em>. Not available on all platforms.
04209  */
04210 
04211 static VALUE
04212 proc_setpgid(VALUE obj, VALUE pid, VALUE pgrp)
04213 {
04214     rb_pid_t ipid, ipgrp;
04215 
04216     rb_secure(2);
04217     ipid = NUM2PIDT(pid);
04218     ipgrp = NUM2PIDT(pgrp);
04219 
04220     if (setpgid(ipid, ipgrp) < 0) rb_sys_fail(0);
04221     return INT2FIX(0);
04222 }
04223 #else
04224 #define proc_setpgid rb_f_notimplement
04225 #endif
04226 
04227 
04228 #ifdef HAVE_GETSID
04229 /*
04230  *  call-seq:
04231  *     Process.getsid()      -> integer
04232  *     Process.getsid(pid)   -> integer
04233  *
04234  *  Returns the session ID for for the given process id. If not give,
04235  *  return current process sid. Not available on all platforms.
04236  *
04237  *     Process.getsid()                #=> 27422
04238  *     Process.getsid(0)               #=> 27422
04239  *     Process.getsid(Process.pid())   #=> 27422
04240  */
04241 static VALUE
04242 proc_getsid(int argc, VALUE *argv)
04243 {
04244     rb_pid_t sid;
04245     VALUE pid;
04246 
04247     rb_secure(2);
04248     rb_scan_args(argc, argv, "01", &pid);
04249 
04250     if (NIL_P(pid))
04251         pid = INT2NUM(0);
04252 
04253     sid = getsid(NUM2PIDT(pid));
04254     if (sid < 0) rb_sys_fail(0);
04255     return PIDT2NUM(sid);
04256 }
04257 #else
04258 #define proc_getsid rb_f_notimplement
04259 #endif
04260 
04261 
04262 #if defined(HAVE_SETSID) || (defined(HAVE_SETPGRP) && defined(TIOCNOTTY))
04263 #if !defined(HAVE_SETSID)
04264 static rb_pid_t ruby_setsid(void);
04265 #define setsid() ruby_setsid()
04266 #endif
04267 /*
04268  *  call-seq:
04269  *     Process.setsid   -> fixnum
04270  *
04271  *  Establishes this process as a new session and process group
04272  *  leader, with no controlling tty. Returns the session id. Not
04273  *  available on all platforms.
04274  *
04275  *     Process.setsid   #=> 27422
04276  */
04277 
04278 static VALUE
04279 proc_setsid(void)
04280 {
04281     rb_pid_t pid;
04282 
04283     rb_secure(2);
04284     pid = setsid();
04285     if (pid < 0) rb_sys_fail(0);
04286     return PIDT2NUM(pid);
04287 }
04288 
04289 #if !defined(HAVE_SETSID)
04290 #define HAVE_SETSID 1
04291 static rb_pid_t
04292 ruby_setsid(void)
04293 {
04294     rb_pid_t pid;
04295     int ret;
04296 
04297     pid = getpid();
04298 #if defined(SETPGRP_VOID)
04299     ret = setpgrp();
04300     /* If `pid_t setpgrp(void)' is equivalent to setsid(),
04301        `ret' will be the same value as `pid', and following open() will fail.
04302        In Linux, `int setpgrp(void)' is equivalent to setpgid(0, 0). */
04303 #else
04304     ret = setpgrp(0, pid);
04305 #endif
04306     if (ret == -1) return -1;
04307 
04308     if ((fd = rb_cloexec_open("/dev/tty", O_RDWR, 0)) >= 0) {
04309         rb_update_max_fd(fd);
04310         ioctl(fd, TIOCNOTTY, NULL);
04311         close(fd);
04312     }
04313     return pid;
04314 }
04315 #endif
04316 #else
04317 #define proc_setsid rb_f_notimplement
04318 #endif
04319 
04320 
04321 #ifdef HAVE_GETPRIORITY
04322 /*
04323  *  call-seq:
04324  *     Process.getpriority(kind, integer)   -> fixnum
04325  *
04326  *  Gets the scheduling priority for specified process, process group,
04327  *  or user. <em>kind</em> indicates the kind of entity to find: one
04328  *  of <code>Process::PRIO_PGRP</code>,
04329  *  <code>Process::PRIO_USER</code>, or
04330  *  <code>Process::PRIO_PROCESS</code>. _integer_ is an id
04331  *  indicating the particular process, process group, or user (an id
04332  *  of 0 means _current_). Lower priorities are more favorable
04333  *  for scheduling. Not available on all platforms.
04334  *
04335  *     Process.getpriority(Process::PRIO_USER, 0)      #=> 19
04336  *     Process.getpriority(Process::PRIO_PROCESS, 0)   #=> 19
04337  */
04338 
04339 static VALUE
04340 proc_getpriority(VALUE obj, VALUE which, VALUE who)
04341 {
04342     int prio, iwhich, iwho;
04343 
04344     rb_secure(2);
04345     iwhich = NUM2INT(which);
04346     iwho   = NUM2INT(who);
04347 
04348     errno = 0;
04349     prio = getpriority(iwhich, iwho);
04350     if (errno) rb_sys_fail(0);
04351     return INT2FIX(prio);
04352 }
04353 #else
04354 #define proc_getpriority rb_f_notimplement
04355 #endif
04356 
04357 
04358 #ifdef HAVE_GETPRIORITY
04359 /*
04360  *  call-seq:
04361  *     Process.setpriority(kind, integer, priority)   -> 0
04362  *
04363  *  See <code>Process#getpriority</code>.
04364  *
04365  *     Process.setpriority(Process::PRIO_USER, 0, 19)      #=> 0
04366  *     Process.setpriority(Process::PRIO_PROCESS, 0, 19)   #=> 0
04367  *     Process.getpriority(Process::PRIO_USER, 0)          #=> 19
04368  *     Process.getpriority(Process::PRIO_PROCESS, 0)       #=> 19
04369  */
04370 
04371 static VALUE
04372 proc_setpriority(VALUE obj, VALUE which, VALUE who, VALUE prio)
04373 {
04374     int iwhich, iwho, iprio;
04375 
04376     rb_secure(2);
04377     iwhich = NUM2INT(which);
04378     iwho   = NUM2INT(who);
04379     iprio  = NUM2INT(prio);
04380 
04381     if (setpriority(iwhich, iwho, iprio) < 0)
04382         rb_sys_fail(0);
04383     return INT2FIX(0);
04384 }
04385 #else
04386 #define proc_setpriority rb_f_notimplement
04387 #endif
04388 
04389 #if defined(HAVE_SETRLIMIT) && defined(NUM2RLIM)
04390 static int
04391 rlimit_resource_name2int(const char *name, int casetype)
04392 {
04393     int resource;
04394     const char *p;
04395 #define RESCHECK(r) \
04396     do { \
04397         if (STRCASECMP(name, #r) == 0) { \
04398             resource = RLIMIT_##r; \
04399             goto found; \
04400         } \
04401     } while (0)
04402 
04403     switch (TOUPPER(*name)) {
04404       case 'A':
04405 #ifdef RLIMIT_AS
04406         RESCHECK(AS);
04407 #endif
04408         break;
04409 
04410       case 'C':
04411 #ifdef RLIMIT_CORE
04412         RESCHECK(CORE);
04413 #endif
04414 #ifdef RLIMIT_CPU
04415         RESCHECK(CPU);
04416 #endif
04417         break;
04418 
04419       case 'D':
04420 #ifdef RLIMIT_DATA
04421         RESCHECK(DATA);
04422 #endif
04423         break;
04424 
04425       case 'F':
04426 #ifdef RLIMIT_FSIZE
04427         RESCHECK(FSIZE);
04428 #endif
04429         break;
04430 
04431       case 'M':
04432 #ifdef RLIMIT_MEMLOCK
04433         RESCHECK(MEMLOCK);
04434 #endif
04435 #ifdef RLIMIT_MSGQUEUE
04436         RESCHECK(MSGQUEUE);
04437 #endif
04438         break;
04439 
04440       case 'N':
04441 #ifdef RLIMIT_NOFILE
04442         RESCHECK(NOFILE);
04443 #endif
04444 #ifdef RLIMIT_NPROC
04445         RESCHECK(NPROC);
04446 #endif
04447 #ifdef RLIMIT_NICE
04448         RESCHECK(NICE);
04449 #endif
04450         break;
04451 
04452       case 'R':
04453 #ifdef RLIMIT_RSS
04454         RESCHECK(RSS);
04455 #endif
04456 #ifdef RLIMIT_RTPRIO
04457         RESCHECK(RTPRIO);
04458 #endif
04459 #ifdef RLIMIT_RTTIME
04460         RESCHECK(RTTIME);
04461 #endif
04462         break;
04463 
04464       case 'S':
04465 #ifdef RLIMIT_STACK
04466         RESCHECK(STACK);
04467 #endif
04468 #ifdef RLIMIT_SBSIZE
04469         RESCHECK(SBSIZE);
04470 #endif
04471 #ifdef RLIMIT_SIGPENDING
04472         RESCHECK(SIGPENDING);
04473 #endif
04474         break;
04475     }
04476     return -1;
04477 
04478   found:
04479     switch (casetype) {
04480       case 0:
04481         for (p = name; *p; p++)
04482             if (!ISUPPER(*p))
04483                 return -1;
04484         break;
04485 
04486       case 1:
04487         for (p = name; *p; p++)
04488             if (!ISLOWER(*p))
04489                 return -1;
04490         break;
04491 
04492       default:
04493         rb_bug("unexpected casetype");
04494     }
04495     return resource;
04496 #undef RESCHECK
04497 }
04498 
04499 static int
04500 rlimit_type_by_hname(const char *name)
04501 {
04502     return rlimit_resource_name2int(name, 0);
04503 }
04504 
04505 static int
04506 rlimit_type_by_lname(const char *name)
04507 {
04508     return rlimit_resource_name2int(name, 1);
04509 }
04510 
04511 static int
04512 rlimit_resource_type(VALUE rtype)
04513 {
04514     const char *name;
04515     VALUE v;
04516     int r;
04517 
04518     switch (TYPE(rtype)) {
04519       case T_SYMBOL:
04520         name = rb_id2name(SYM2ID(rtype));
04521         break;
04522 
04523       default:
04524         v = rb_check_string_type(rtype);
04525         if (!NIL_P(v)) {
04526             rtype = v;
04527       case T_STRING:
04528             name = StringValueCStr(rtype);
04529             break;
04530         }
04531         /* fall through */
04532 
04533       case T_FIXNUM:
04534       case T_BIGNUM:
04535         return NUM2INT(rtype);
04536     }
04537 
04538     r = rlimit_type_by_hname(name);
04539     if (r != -1)
04540         return r;
04541 
04542     rb_raise(rb_eArgError, "invalid resource name: %s", name);
04543 
04544     UNREACHABLE;
04545 }
04546 
04547 static rlim_t
04548 rlimit_resource_value(VALUE rval)
04549 {
04550     const char *name;
04551     VALUE v;
04552 
04553     switch (TYPE(rval)) {
04554       case T_SYMBOL:
04555         name = rb_id2name(SYM2ID(rval));
04556         break;
04557 
04558       default:
04559         v = rb_check_string_type(rval);
04560         if (!NIL_P(v)) {
04561             rval = v;
04562       case T_STRING:
04563             name = StringValueCStr(rval);
04564             break;
04565         }
04566         /* fall through */
04567 
04568       case T_FIXNUM:
04569       case T_BIGNUM:
04570         return NUM2RLIM(rval);
04571     }
04572 
04573 #ifdef RLIM_INFINITY
04574     if (strcmp(name, "INFINITY") == 0) return RLIM_INFINITY;
04575 #endif
04576 #ifdef RLIM_SAVED_MAX
04577     if (strcmp(name, "SAVED_MAX") == 0) return RLIM_SAVED_MAX;
04578 #endif
04579 #ifdef RLIM_SAVED_CUR
04580     if (strcmp(name, "SAVED_CUR") == 0) return RLIM_SAVED_CUR;
04581 #endif
04582     rb_raise(rb_eArgError, "invalid resource value: %s", name);
04583 
04584     UNREACHABLE;
04585 }
04586 #endif
04587 
04588 #if defined(HAVE_GETRLIMIT) && defined(RLIM2NUM)
04589 /*
04590  *  call-seq:
04591  *     Process.getrlimit(resource)   -> [cur_limit, max_limit]
04592  *
04593  *  Gets the resource limit of the process.
04594  *  _cur_limit_ means current (soft) limit and
04595  *  _max_limit_ means maximum (hard) limit.
04596  *
04597  *  _resource_ indicates the kind of resource to limit.
04598  *  It is specified as a symbol such as <code>:CORE</code>,
04599  *  a string such as <code>"CORE"</code> or
04600  *  a constant such as <code>Process::RLIMIT_CORE</code>.
04601  *  See Process.setrlimit for details.
04602  *
04603  *  _cur_limit_ and _max_limit_ may be <code>Process::RLIM_INFINITY</code>,
04604  *  <code>Process::RLIM_SAVED_MAX</code> or
04605  *  <code>Process::RLIM_SAVED_CUR</code>.
04606  *  See Process.setrlimit and the system getrlimit(2) manual for details.
04607  */
04608 
04609 static VALUE
04610 proc_getrlimit(VALUE obj, VALUE resource)
04611 {
04612     struct rlimit rlim;
04613 
04614     rb_secure(2);
04615 
04616     if (getrlimit(rlimit_resource_type(resource), &rlim) < 0) {
04617         rb_sys_fail("getrlimit");
04618     }
04619     return rb_assoc_new(RLIM2NUM(rlim.rlim_cur), RLIM2NUM(rlim.rlim_max));
04620 }
04621 #else
04622 #define proc_getrlimit rb_f_notimplement
04623 #endif
04624 
04625 #if defined(HAVE_SETRLIMIT) && defined(NUM2RLIM)
04626 /*
04627  *  call-seq:
04628  *     Process.setrlimit(resource, cur_limit, max_limit)        -> nil
04629  *     Process.setrlimit(resource, cur_limit)                   -> nil
04630  *
04631  *  Sets the resource limit of the process.
04632  *  _cur_limit_ means current (soft) limit and
04633  *  _max_limit_ means maximum (hard) limit.
04634  *
04635  *  If _max_limit_ is not given, _cur_limit_ is used.
04636  *
04637  *  _resource_ indicates the kind of resource to limit.
04638  *  It should be a symbol such as <code>:CORE</code>,
04639  *  a string such as <code>"CORE"</code> or
04640  *  a constant such as <code>Process::RLIMIT_CORE</code>.
04641  *  The available resources are OS dependent.
04642  *  Ruby may support following resources.
04643  *
04644  *  [AS] total available memory (bytes) (SUSv3, NetBSD, FreeBSD, OpenBSD but 4.4BSD-Lite)
04645  *  [CORE] core size (bytes) (SUSv3)
04646  *  [CPU] CPU time (seconds) (SUSv3)
04647  *  [DATA] data segment (bytes) (SUSv3)
04648  *  [FSIZE] file size (bytes) (SUSv3)
04649  *  [MEMLOCK] total size for mlock(2) (bytes) (4.4BSD, GNU/Linux)
04650  *  [MSGQUEUE] allocation for POSIX message queues (bytes) (GNU/Linux)
04651  *  [NICE] ceiling on process's nice(2) value (number) (GNU/Linux)
04652  *  [NOFILE] file descriptors (number) (SUSv3)
04653  *  [NPROC] number of processes for the user (number) (4.4BSD, GNU/Linux)
04654  *  [RSS] resident memory size (bytes) (4.2BSD, GNU/Linux)
04655  *  [RTPRIO] ceiling on the process's real-time priority (number) (GNU/Linux)
04656  *  [RTTIME] CPU time for real-time process (us) (GNU/Linux)
04657  *  [SBSIZE] all socket buffers (bytes) (NetBSD, FreeBSD)
04658  *  [SIGPENDING] number of queued signals allowed (signals) (GNU/Linux)
04659  *  [STACK] stack size (bytes) (SUSv3)
04660  *
04661  *  _cur_limit_ and _max_limit_ may be
04662  *  <code>:INFINITY</code>, <code>"INFINITY"</code> or
04663  *  <code>Process::RLIM_INFINITY</code>,
04664  *  which means that the resource is not limited.
04665  *  They may be <code>Process::RLIM_SAVED_MAX</code>,
04666  *  <code>Process::RLIM_SAVED_CUR</code> and
04667  *  corresponding symbols and strings too.
04668  *  See system setrlimit(2) manual for details.
04669  *
04670  *  The following example raises the soft limit of core size to
04671  *  the hard limit to try to make core dump possible.
04672  *
04673  *    Process.setrlimit(:CORE, Process.getrlimit(:CORE)[1])
04674  *
04675  */
04676 
04677 static VALUE
04678 proc_setrlimit(int argc, VALUE *argv, VALUE obj)
04679 {
04680     VALUE resource, rlim_cur, rlim_max;
04681     struct rlimit rlim;
04682 
04683     rb_secure(2);
04684 
04685     rb_scan_args(argc, argv, "21", &resource, &rlim_cur, &rlim_max);
04686     if (rlim_max == Qnil)
04687         rlim_max = rlim_cur;
04688 
04689     rlim.rlim_cur = rlimit_resource_value(rlim_cur);
04690     rlim.rlim_max = rlimit_resource_value(rlim_max);
04691 
04692     if (setrlimit(rlimit_resource_type(resource), &rlim) < 0) {
04693         rb_sys_fail("setrlimit");
04694     }
04695     return Qnil;
04696 }
04697 #else
04698 #define proc_setrlimit rb_f_notimplement
04699 #endif
04700 
04701 static int under_uid_switch = 0;
04702 static void
04703 check_uid_switch(void)
04704 {
04705     rb_secure(2);
04706     if (under_uid_switch) {
04707         rb_raise(rb_eRuntimeError, "can't handle UID while evaluating block given to Process::UID.switch method");
04708     }
04709 }
04710 
04711 static int under_gid_switch = 0;
04712 static void
04713 check_gid_switch(void)
04714 {
04715     rb_secure(2);
04716     if (under_gid_switch) {
04717         rb_raise(rb_eRuntimeError, "can't handle GID while evaluating block given to Process::UID.switch method");
04718     }
04719 }
04720 
04721 
04722 /*********************************************************************
04723  * Document-class: Process::Sys
04724  *
04725  *  The <code>Process::Sys</code> module contains UID and GID
04726  *  functions which provide direct bindings to the system calls of the
04727  *  same names instead of the more-portable versions of the same
04728  *  functionality found in the <code>Process</code>,
04729  *  <code>Process::UID</code>, and <code>Process::GID</code> modules.
04730  */
04731 
04732 #if defined(HAVE_PWD_H)
04733 static rb_uid_t
04734 obj2uid(VALUE id
04735 # ifdef USE_GETPWNAM_R
04736         , char *getpw_buf, size_t getpw_buf_len
04737 # endif
04738     )
04739 {
04740     rb_uid_t uid;
04741     VALUE tmp;
04742 
04743     if (FIXNUM_P(id) || NIL_P(tmp = rb_check_string_type(id))) {
04744         uid = NUM2UIDT(id);
04745     }
04746     else {
04747         const char *usrname = StringValueCStr(id);
04748         struct passwd *pwptr;
04749 #ifdef USE_GETPWNAM_R
04750         struct passwd pwbuf;
04751         if (getpwnam_r(usrname, &pwbuf, getpw_buf, getpw_buf_len, &pwptr))
04752             rb_sys_fail("getpwnam_r");
04753 #else
04754         pwptr = getpwnam(usrname);
04755 #endif
04756         if (!pwptr) {
04757 #ifndef USE_GETPWNAM_R
04758             endpwent();
04759 #endif
04760             rb_raise(rb_eArgError, "can't find user for %s", usrname);
04761         }
04762         uid = pwptr->pw_uid;
04763 #ifndef USE_GETPWNAM_R
04764         endpwent();
04765 #endif
04766     }
04767     return uid;
04768 }
04769 
04770 # ifdef p_uid_from_name
04771 static VALUE
04772 p_uid_from_name(VALUE self, VALUE id)
04773 {
04774     PREPARE_GETPWNAM
04775     return UIDT2NUM(OBJ2UID(id));
04776 }
04777 # endif
04778 #endif
04779 
04780 #if defined(HAVE_GRP_H)
04781 static rb_gid_t
04782 obj2gid(VALUE id
04783 # ifdef USE_GETGRNAM_R
04784         , char *getgr_buf, size_t getgr_buf_len
04785 # endif
04786     )
04787 {
04788     rb_gid_t gid;
04789     VALUE tmp;
04790 
04791     if (FIXNUM_P(id) || NIL_P(tmp = rb_check_string_type(id))) {
04792         gid = NUM2GIDT(id);
04793     }
04794     else {
04795         const char *grpname = StringValueCStr(id);
04796         struct group *grptr;
04797 #ifdef USE_GETGRNAM_R
04798         struct group grbuf;
04799         if (getgrnam_r(grpname, &grbuf, getgr_buf, getgr_buf_len, &grptr))
04800             rb_sys_fail("getgrnam_r");
04801 #else
04802         grptr = getgrnam(grpname);
04803 #endif
04804         if (!grptr) {
04805 #ifndef USE_GETGRNAM_R
04806             endgrent();
04807 #endif
04808             rb_raise(rb_eArgError, "can't find group for %s", grpname);
04809         }
04810         gid = grptr->gr_gid;
04811 #ifndef USE_GETGRNAM_R
04812         endgrent();
04813 #endif
04814     }
04815     return gid;
04816 }
04817 
04818 # ifdef p_gid_from_name
04819 static VALUE
04820 p_gid_from_name(VALUE self, VALUE id)
04821 {
04822     PREPARE_GETGRNAM;
04823     return GIDT2NUM(OBJ2GID(id));
04824 }
04825 # endif
04826 #endif
04827 
04828 #if defined HAVE_SETUID
04829 /*
04830  *  call-seq:
04831  *     Process::Sys.setuid(user)   -> nil
04832  *
04833  *  Set the user ID of the current process to _user_. Not
04834  *  available on all platforms.
04835  *
04836  */
04837 
04838 static VALUE
04839 p_sys_setuid(VALUE obj, VALUE id)
04840 {
04841     PREPARE_GETPWNAM;
04842     check_uid_switch();
04843     if (setuid(OBJ2UID(id)) != 0) rb_sys_fail(0);
04844     return Qnil;
04845 }
04846 #else
04847 #define p_sys_setuid rb_f_notimplement
04848 #endif
04849 
04850 
04851 #if defined HAVE_SETRUID
04852 /*
04853  *  call-seq:
04854  *     Process::Sys.setruid(user)   -> nil
04855  *
04856  *  Set the real user ID of the calling process to _user_.
04857  *  Not available on all platforms.
04858  *
04859  */
04860 
04861 static VALUE
04862 p_sys_setruid(VALUE obj, VALUE id)
04863 {
04864     PREPARE_GETPWNAM;
04865     check_uid_switch();
04866     if (setruid(OBJ2UID(id)) != 0) rb_sys_fail(0);
04867     return Qnil;
04868 }
04869 #else
04870 #define p_sys_setruid rb_f_notimplement
04871 #endif
04872 
04873 
04874 #if defined HAVE_SETEUID
04875 /*
04876  *  call-seq:
04877  *     Process::Sys.seteuid(user)   -> nil
04878  *
04879  *  Set the effective user ID of the calling process to
04880  *  _user_.  Not available on all platforms.
04881  *
04882  */
04883 
04884 static VALUE
04885 p_sys_seteuid(VALUE obj, VALUE id)
04886 {
04887     PREPARE_GETPWNAM;
04888     check_uid_switch();
04889     if (seteuid(OBJ2UID(id)) != 0) rb_sys_fail(0);
04890     return Qnil;
04891 }
04892 #else
04893 #define p_sys_seteuid rb_f_notimplement
04894 #endif
04895 
04896 
04897 #if defined HAVE_SETREUID
04898 /*
04899  *  call-seq:
04900  *     Process::Sys.setreuid(rid, eid)   -> nil
04901  *
04902  *  Sets the (user) real and/or effective user IDs of the current
04903  *  process to _rid_ and _eid_, respectively. A value of
04904  *  <code>-1</code> for either means to leave that ID unchanged. Not
04905  *  available on all platforms.
04906  *
04907  */
04908 
04909 static VALUE
04910 p_sys_setreuid(VALUE obj, VALUE rid, VALUE eid)
04911 {
04912     PREPARE_GETPWNAM;
04913     check_uid_switch();
04914     if (setreuid(OBJ2UID(rid), OBJ2UID(eid)) != 0) rb_sys_fail(0);
04915     return Qnil;
04916 }
04917 #else
04918 #define p_sys_setreuid rb_f_notimplement
04919 #endif
04920 
04921 
04922 #if defined HAVE_SETRESUID
04923 /*
04924  *  call-seq:
04925  *     Process::Sys.setresuid(rid, eid, sid)   -> nil
04926  *
04927  *  Sets the (user) real, effective, and saved user IDs of the
04928  *  current process to _rid_, _eid_, and _sid_ respectively. A
04929  *  value of <code>-1</code> for any value means to
04930  *  leave that ID unchanged. Not available on all platforms.
04931  *
04932  */
04933 
04934 static VALUE
04935 p_sys_setresuid(VALUE obj, VALUE rid, VALUE eid, VALUE sid)
04936 {
04937     PREPARE_GETPWNAM;
04938     check_uid_switch();
04939     if (setresuid(OBJ2UID(rid), OBJ2UID(eid), OBJ2UID(sid)) != 0) rb_sys_fail(0);
04940     return Qnil;
04941 }
04942 #else
04943 #define p_sys_setresuid rb_f_notimplement
04944 #endif
04945 
04946 
04947 /*
04948  *  call-seq:
04949  *     Process.uid           -> fixnum
04950  *     Process::UID.rid      -> fixnum
04951  *     Process::Sys.getuid   -> fixnum
04952  *
04953  *  Returns the (real) user ID of this process.
04954  *
04955  *     Process.uid   #=> 501
04956  */
04957 
04958 static VALUE
04959 proc_getuid(VALUE obj)
04960 {
04961     rb_uid_t uid = getuid();
04962     return UIDT2NUM(uid);
04963 }
04964 
04965 
04966 #if defined(HAVE_SETRESUID) || defined(HAVE_SETREUID) || defined(HAVE_SETRUID) || defined(HAVE_SETUID)
04967 /*
04968  *  call-seq:
04969  *     Process.uid= user   -> numeric
04970  *
04971  *  Sets the (user) user ID for this process. Not available on all
04972  *  platforms.
04973  */
04974 
04975 static VALUE
04976 proc_setuid(VALUE obj, VALUE id)
04977 {
04978     rb_uid_t uid;
04979     PREPARE_GETPWNAM;
04980 
04981     check_uid_switch();
04982 
04983     uid = OBJ2UID(id);
04984 #if defined(HAVE_SETRESUID)
04985     if (setresuid(uid, -1, -1) < 0) rb_sys_fail(0);
04986 #elif defined HAVE_SETREUID
04987     if (setreuid(uid, -1) < 0) rb_sys_fail(0);
04988 #elif defined HAVE_SETRUID
04989     if (setruid(uid) < 0) rb_sys_fail(0);
04990 #elif defined HAVE_SETUID
04991     {
04992         if (geteuid() == uid) {
04993             if (setuid(uid) < 0) rb_sys_fail(0);
04994         }
04995         else {
04996             rb_notimplement();
04997         }
04998     }
04999 #endif
05000     return id;
05001 }
05002 #else
05003 #define proc_setuid rb_f_notimplement
05004 #endif
05005 
05006 
05007 /********************************************************************
05008  *
05009  * Document-class: Process::UID
05010  *
05011  *  The <code>Process::UID</code> module contains a collection of
05012  *  module functions which can be used to portably get, set, and
05013  *  switch the current process's real, effective, and saved user IDs.
05014  *
05015  */
05016 
05017 static rb_uid_t SAVED_USER_ID = -1;
05018 
05019 #ifdef BROKEN_SETREUID
05020 int
05021 setreuid(rb_uid_t ruid, rb_uid_t euid)
05022 {
05023     if (ruid != (rb_uid_t)-1 && ruid != getuid()) {
05024         if (euid == (rb_uid_t)-1) euid = geteuid();
05025         if (setuid(ruid) < 0) return -1;
05026     }
05027     if (euid != (rb_uid_t)-1 && euid != geteuid()) {
05028         if (seteuid(euid) < 0) return -1;
05029     }
05030     return 0;
05031 }
05032 #endif
05033 
05034 /*
05035  *  call-seq:
05036  *     Process::UID.change_privilege(user)   -> fixnum
05037  *
05038  *  Change the current process's real and effective user ID to that
05039  *  specified by _user_. Returns the new user ID. Not
05040  *  available on all platforms.
05041  *
05042  *     [Process.uid, Process.euid]          #=> [0, 0]
05043  *     Process::UID.change_privilege(31)    #=> 31
05044  *     [Process.uid, Process.euid]          #=> [31, 31]
05045  */
05046 
05047 static VALUE
05048 p_uid_change_privilege(VALUE obj, VALUE id)
05049 {
05050     rb_uid_t uid;
05051     PREPARE_GETPWNAM;
05052 
05053     check_uid_switch();
05054 
05055     uid = OBJ2UID(id);
05056 
05057     if (geteuid() == 0) { /* root-user */
05058 #if defined(HAVE_SETRESUID)
05059         if (setresuid(uid, uid, uid) < 0) rb_sys_fail(0);
05060         SAVED_USER_ID = uid;
05061 #elif defined(HAVE_SETUID)
05062         if (setuid(uid) < 0) rb_sys_fail(0);
05063         SAVED_USER_ID = uid;
05064 #elif defined(HAVE_SETREUID) && !defined(OBSOLETE_SETREUID)
05065         if (getuid() == uid) {
05066             if (SAVED_USER_ID == uid) {
05067                 if (setreuid(-1, uid) < 0) rb_sys_fail(0);
05068             }
05069             else {
05070                 if (uid == 0) { /* (r,e,s) == (root, root, x) */
05071                     if (setreuid(-1, SAVED_USER_ID) < 0) rb_sys_fail(0);
05072                     if (setreuid(SAVED_USER_ID, 0) < 0) rb_sys_fail(0);
05073                     SAVED_USER_ID = 0; /* (r,e,s) == (x, root, root) */
05074                     if (setreuid(uid, uid) < 0) rb_sys_fail(0);
05075                     SAVED_USER_ID = uid;
05076                 }
05077                 else {
05078                     if (setreuid(0, -1) < 0) rb_sys_fail(0);
05079                     SAVED_USER_ID = 0;
05080                     if (setreuid(uid, uid) < 0) rb_sys_fail(0);
05081                     SAVED_USER_ID = uid;
05082                 }
05083             }
05084         }
05085         else {
05086             if (setreuid(uid, uid) < 0) rb_sys_fail(0);
05087             SAVED_USER_ID = uid;
05088         }
05089 #elif defined(HAVE_SETRUID) && defined(HAVE_SETEUID)
05090         if (getuid() == uid) {
05091             if (SAVED_USER_ID == uid) {
05092                 if (seteuid(uid) < 0) rb_sys_fail(0);
05093             }
05094             else {
05095                 if (uid == 0) {
05096                     if (setruid(SAVED_USER_ID) < 0) rb_sys_fail(0);
05097                     SAVED_USER_ID = 0;
05098                     if (setruid(0) < 0) rb_sys_fail(0);
05099                 }
05100                 else {
05101                     if (setruid(0) < 0) rb_sys_fail(0);
05102                     SAVED_USER_ID = 0;
05103                     if (seteuid(uid) < 0) rb_sys_fail(0);
05104                     if (setruid(uid) < 0) rb_sys_fail(0);
05105                     SAVED_USER_ID = uid;
05106                 }
05107             }
05108         }
05109         else {
05110             if (seteuid(uid) < 0) rb_sys_fail(0);
05111             if (setruid(uid) < 0) rb_sys_fail(0);
05112             SAVED_USER_ID = uid;
05113         }
05114 #else
05115         (void)uid;
05116         rb_notimplement();
05117 #endif
05118     }
05119     else { /* unprivileged user */
05120 #if defined(HAVE_SETRESUID)
05121         if (setresuid((getuid() == uid)? (rb_uid_t)-1: uid,
05122                       (geteuid() == uid)? (rb_uid_t)-1: uid,
05123                       (SAVED_USER_ID == uid)? (rb_uid_t)-1: uid) < 0) rb_sys_fail(0);
05124         SAVED_USER_ID = uid;
05125 #elif defined(HAVE_SETREUID) && !defined(OBSOLETE_SETREUID)
05126         if (SAVED_USER_ID == uid) {
05127             if (setreuid((getuid() == uid)? (rb_uid_t)-1: uid,
05128                          (geteuid() == uid)? (rb_uid_t)-1: uid) < 0)
05129                 rb_sys_fail(0);
05130         }
05131         else if (getuid() != uid) {
05132             if (setreuid(uid, (geteuid() == uid)? (rb_uid_t)-1: uid) < 0)
05133                 rb_sys_fail(0);
05134             SAVED_USER_ID = uid;
05135         }
05136         else if (/* getuid() == uid && */ geteuid() != uid) {
05137             if (setreuid(geteuid(), uid) < 0) rb_sys_fail(0);
05138             SAVED_USER_ID = uid;
05139             if (setreuid(uid, -1) < 0) rb_sys_fail(0);
05140         }
05141         else { /* getuid() == uid && geteuid() == uid */
05142             if (setreuid(-1, SAVED_USER_ID) < 0) rb_sys_fail(0);
05143             if (setreuid(SAVED_USER_ID, uid) < 0) rb_sys_fail(0);
05144             SAVED_USER_ID = uid;
05145             if (setreuid(uid, -1) < 0) rb_sys_fail(0);
05146         }
05147 #elif defined(HAVE_SETRUID) && defined(HAVE_SETEUID)
05148         if (SAVED_USER_ID == uid) {
05149             if (geteuid() != uid && seteuid(uid) < 0) rb_sys_fail(0);
05150             if (getuid() != uid && setruid(uid) < 0) rb_sys_fail(0);
05151         }
05152         else if (/* SAVED_USER_ID != uid && */ geteuid() == uid) {
05153             if (getuid() != uid) {
05154                 if (setruid(uid) < 0) rb_sys_fail(0);
05155                 SAVED_USER_ID = uid;
05156             }
05157             else {
05158                 if (setruid(SAVED_USER_ID) < 0) rb_sys_fail(0);
05159                 SAVED_USER_ID = uid;
05160                 if (setruid(uid) < 0) rb_sys_fail(0);
05161             }
05162         }
05163         else if (/* geteuid() != uid && */ getuid() == uid) {
05164             if (seteuid(uid) < 0) rb_sys_fail(0);
05165             if (setruid(SAVED_USER_ID) < 0) rb_sys_fail(0);
05166             SAVED_USER_ID = uid;
05167             if (setruid(uid) < 0) rb_sys_fail(0);
05168         }
05169         else {
05170             errno = EPERM;
05171             rb_sys_fail(0);
05172         }
05173 #elif defined HAVE_44BSD_SETUID
05174         if (getuid() == uid) {
05175             /* (r,e,s)==(uid,?,?) ==> (uid,uid,uid) */
05176             if (setuid(uid) < 0) rb_sys_fail(0);
05177             SAVED_USER_ID = uid;
05178         }
05179         else {
05180             errno = EPERM;
05181             rb_sys_fail(0);
05182         }
05183 #elif defined HAVE_SETEUID
05184         if (getuid() == uid && SAVED_USER_ID == uid) {
05185             if (seteuid(uid) < 0) rb_sys_fail(0);
05186         }
05187         else {
05188             errno = EPERM;
05189             rb_sys_fail(0);
05190         }
05191 #elif defined HAVE_SETUID
05192         if (getuid() == uid && SAVED_USER_ID == uid) {
05193             if (setuid(uid) < 0) rb_sys_fail(0);
05194         }
05195         else {
05196             errno = EPERM;
05197             rb_sys_fail(0);
05198         }
05199 #else
05200         rb_notimplement();
05201 #endif
05202     }
05203     return id;
05204 }
05205 
05206 
05207 
05208 #if defined HAVE_SETGID
05209 /*
05210  *  call-seq:
05211  *     Process::Sys.setgid(group)   -> nil
05212  *
05213  *  Set the group ID of the current process to _group_. Not
05214  *  available on all platforms.
05215  *
05216  */
05217 
05218 static VALUE
05219 p_sys_setgid(VALUE obj, VALUE id)
05220 {
05221     PREPARE_GETGRNAM;
05222     check_gid_switch();
05223     if (setgid(OBJ2GID(id)) != 0) rb_sys_fail(0);
05224     return Qnil;
05225 }
05226 #else
05227 #define p_sys_setgid rb_f_notimplement
05228 #endif
05229 
05230 
05231 #if defined HAVE_SETRGID
05232 /*
05233  *  call-seq:
05234  *     Process::Sys.setrgid(group)   -> nil
05235  *
05236  *  Set the real group ID of the calling process to _group_.
05237  *  Not available on all platforms.
05238  *
05239  */
05240 
05241 static VALUE
05242 p_sys_setrgid(VALUE obj, VALUE id)
05243 {
05244     PREPARE_GETGRNAM;
05245     check_gid_switch();
05246     if (setrgid(OBJ2GID(id)) != 0) rb_sys_fail(0);
05247     return Qnil;
05248 }
05249 #else
05250 #define p_sys_setrgid rb_f_notimplement
05251 #endif
05252 
05253 
05254 #if defined HAVE_SETEGID
05255 /*
05256  *  call-seq:
05257  *     Process::Sys.setegid(group)   -> nil
05258  *
05259  *  Set the effective group ID of the calling process to
05260  *  _group_.  Not available on all platforms.
05261  *
05262  */
05263 
05264 static VALUE
05265 p_sys_setegid(VALUE obj, VALUE id)
05266 {
05267     PREPARE_GETGRNAM;
05268     check_gid_switch();
05269     if (setegid(OBJ2GID(id)) != 0) rb_sys_fail(0);
05270     return Qnil;
05271 }
05272 #else
05273 #define p_sys_setegid rb_f_notimplement
05274 #endif
05275 
05276 
05277 #if defined HAVE_SETREGID
05278 /*
05279  *  call-seq:
05280  *     Process::Sys.setregid(rid, eid)   -> nil
05281  *
05282  *  Sets the (group) real and/or effective group IDs of the current
05283  *  process to <em>rid</em> and <em>eid</em>, respectively. A value of
05284  *  <code>-1</code> for either means to leave that ID unchanged. Not
05285  *  available on all platforms.
05286  *
05287  */
05288 
05289 static VALUE
05290 p_sys_setregid(VALUE obj, VALUE rid, VALUE eid)
05291 {
05292     PREPARE_GETGRNAM;
05293     check_gid_switch();
05294     if (setregid(OBJ2GID(rid), OBJ2GID(eid)) != 0) rb_sys_fail(0);
05295     return Qnil;
05296 }
05297 #else
05298 #define p_sys_setregid rb_f_notimplement
05299 #endif
05300 
05301 #if defined HAVE_SETRESGID
05302 /*
05303  *  call-seq:
05304  *     Process::Sys.setresgid(rid, eid, sid)   -> nil
05305  *
05306  *  Sets the (group) real, effective, and saved user IDs of the
05307  *  current process to <em>rid</em>, <em>eid</em>, and <em>sid</em>
05308  *  respectively. A value of <code>-1</code> for any value means to
05309  *  leave that ID unchanged. Not available on all platforms.
05310  *
05311  */
05312 
05313 static VALUE
05314 p_sys_setresgid(VALUE obj, VALUE rid, VALUE eid, VALUE sid)
05315 {
05316     PREPARE_GETGRNAM;
05317     check_gid_switch();
05318     if (setresgid(OBJ2GID(rid), OBJ2GID(eid), OBJ2GID(sid)) != 0) rb_sys_fail(0);
05319     return Qnil;
05320 }
05321 #else
05322 #define p_sys_setresgid rb_f_notimplement
05323 #endif
05324 
05325 
05326 #if defined HAVE_ISSETUGID
05327 /*
05328  *  call-seq:
05329  *     Process::Sys.issetugid   -> true or false
05330  *
05331  *  Returns +true+ if the process was created as a result
05332  *  of an execve(2) system call which had either of the setuid or
05333  *  setgid bits set (and extra privileges were given as a result) or
05334  *  if it has changed any of its real, effective or saved user or
05335  *  group IDs since it began execution.
05336  *
05337  */
05338 
05339 static VALUE
05340 p_sys_issetugid(VALUE obj)
05341 {
05342     rb_secure(2);
05343     if (issetugid()) {
05344         return Qtrue;
05345     }
05346     else {
05347         return Qfalse;
05348     }
05349 }
05350 #else
05351 #define p_sys_issetugid rb_f_notimplement
05352 #endif
05353 
05354 
05355 /*
05356  *  call-seq:
05357  *     Process.gid           -> fixnum
05358  *     Process::GID.rid      -> fixnum
05359  *     Process::Sys.getgid   -> fixnum
05360  *
05361  *  Returns the (real) group ID for this process.
05362  *
05363  *     Process.gid   #=> 500
05364  */
05365 
05366 static VALUE
05367 proc_getgid(VALUE obj)
05368 {
05369     rb_gid_t gid = getgid();
05370     return GIDT2NUM(gid);
05371 }
05372 
05373 
05374 #if defined(HAVE_SETRESGID) || defined(HAVE_SETREGID) || defined(HAVE_SETRGID) || defined(HAVE_SETGID)
05375 /*
05376  *  call-seq:
05377  *     Process.gid= fixnum   -> fixnum
05378  *
05379  *  Sets the group ID for this process.
05380  */
05381 
05382 static VALUE
05383 proc_setgid(VALUE obj, VALUE id)
05384 {
05385     rb_gid_t gid;
05386     PREPARE_GETGRNAM;
05387 
05388     check_gid_switch();
05389 
05390     gid = OBJ2GID(id);
05391 #if defined(HAVE_SETRESGID)
05392     if (setresgid(gid, -1, -1) < 0) rb_sys_fail(0);
05393 #elif defined HAVE_SETREGID
05394     if (setregid(gid, -1) < 0) rb_sys_fail(0);
05395 #elif defined HAVE_SETRGID
05396     if (setrgid(gid) < 0) rb_sys_fail(0);
05397 #elif defined HAVE_SETGID
05398     {
05399         if (getegid() == gid) {
05400             if (setgid(gid) < 0) rb_sys_fail(0);
05401         }
05402         else {
05403             rb_notimplement();
05404         }
05405     }
05406 #endif
05407     return GIDT2NUM(gid);
05408 }
05409 #else
05410 #define proc_setgid rb_f_notimplement
05411 #endif
05412 
05413 
05414 #if defined(HAVE_SETGROUPS) || defined(HAVE_GETGROUPS)
05415 /*
05416  * Maximum supplementary groups are platform dependent.
05417  * FWIW, 65536 is enough big for our supported OSs.
05418  *
05419  * OS Name                      max groups
05420  * -----------------------------------------------
05421  * Linux Kernel >= 2.6.3        65536
05422  * Linux Kernel < 2.6.3            32
05423  * IBM AIX 5.2                     64
05424  * IBM AIX 5.3 ... 6.1            128
05425  * IBM AIX 7.1                    128 (can be configured to be up to 2048)
05426  * OpenBSD, NetBSD                 16
05427  * FreeBSD < 8.0                   16
05428  * FreeBSD >=8.0                 1023
05429  * Darwin (Mac OS X)               16
05430  * Sun Solaris 7,8,9,10            16
05431  * Sun Solaris 11 / OpenSolaris  1024
05432  * HP-UX                           20
05433  * Windows                       1015
05434  */
05435 static int _maxgroups = -1;
05436 static int
05437 get_sc_ngroups_max(void)
05438 {
05439 #ifdef _SC_NGROUPS_MAX
05440     return (int)sysconf(_SC_NGROUPS_MAX);
05441 #elif defined(NGROUPS_MAX)
05442     return (int)NGROUPS_MAX;
05443 #else
05444     return -1;
05445 #endif
05446 }
05447 static int
05448 maxgroups(void)
05449 {
05450     if (_maxgroups < 0) {
05451         _maxgroups = get_sc_ngroups_max();
05452         if (_maxgroups < 0)
05453             _maxgroups = RB_MAX_GROUPS;
05454     }
05455 
05456     return _maxgroups;
05457 }
05458 #endif
05459 
05460 
05461 
05462 #ifdef HAVE_GETGROUPS
05463 /*
05464  *  call-seq:
05465  *     Process.groups   -> array
05466  *
05467  *  Get an <code>Array</code> of the gids of groups in the
05468  *  supplemental group access list for this process.
05469  *
05470  *     Process.groups   #=> [27, 6, 10, 11]
05471  *
05472  */
05473 
05474 static VALUE
05475 proc_getgroups(VALUE obj)
05476 {
05477     VALUE ary;
05478     int i, ngroups;
05479     rb_gid_t *groups;
05480 
05481     ngroups = getgroups(0, NULL);
05482     if (ngroups == -1)
05483         rb_sys_fail(0);
05484 
05485     groups = ALLOCA_N(rb_gid_t, ngroups);
05486 
05487     ngroups = getgroups(ngroups, groups);
05488     if (ngroups == -1)
05489         rb_sys_fail(0);
05490 
05491     ary = rb_ary_new();
05492     for (i = 0; i < ngroups; i++)
05493         rb_ary_push(ary, GIDT2NUM(groups[i]));
05494 
05495     return ary;
05496 }
05497 #else
05498 #define proc_getgroups rb_f_notimplement
05499 #endif
05500 
05501 
05502 #ifdef HAVE_SETGROUPS
05503 /*
05504  *  call-seq:
05505  *     Process.groups= array   -> array
05506  *
05507  *  Set the supplemental group access list to the given
05508  *  <code>Array</code> of group IDs.
05509  *
05510  *     Process.groups   #=> [0, 1, 2, 3, 4, 6, 10, 11, 20, 26, 27]
05511  *     Process.groups = [27, 6, 10, 11]   #=> [27, 6, 10, 11]
05512  *     Process.groups   #=> [27, 6, 10, 11]
05513  *
05514  */
05515 
05516 static VALUE
05517 proc_setgroups(VALUE obj, VALUE ary)
05518 {
05519     int ngroups, i;
05520     rb_gid_t *groups;
05521     PREPARE_GETGRNAM;
05522 
05523     Check_Type(ary, T_ARRAY);
05524 
05525     ngroups = RARRAY_LENINT(ary);
05526     if (ngroups > maxgroups())
05527         rb_raise(rb_eArgError, "too many groups, %d max", maxgroups());
05528 
05529     groups = ALLOCA_N(rb_gid_t, ngroups);
05530 
05531     for (i = 0; i < ngroups; i++) {
05532         VALUE g = RARRAY_PTR(ary)[i];
05533 
05534         groups[i] = OBJ2GID(g);
05535     }
05536 
05537     if (setgroups(ngroups, groups) == -1) /* ngroups <= maxgroups */
05538         rb_sys_fail(0);
05539 
05540     return proc_getgroups(obj);
05541 }
05542 #else
05543 #define proc_setgroups rb_f_notimplement
05544 #endif
05545 
05546 
05547 #ifdef HAVE_INITGROUPS
05548 /*
05549  *  call-seq:
05550  *     Process.initgroups(username, gid)   -> array
05551  *
05552  *  Initializes the supplemental group access list by reading the
05553  *  system group database and using all groups of which the given user
05554  *  is a member. The group with the specified <em>gid</em> is also
05555  *  added to the list. Returns the resulting <code>Array</code> of the
05556  *  gids of all the groups in the supplementary group access list. Not
05557  *  available on all platforms.
05558  *
05559  *     Process.groups   #=> [0, 1, 2, 3, 4, 6, 10, 11, 20, 26, 27]
05560  *     Process.initgroups( "mgranger", 30 )   #=> [30, 6, 10, 11]
05561  *     Process.groups   #=> [30, 6, 10, 11]
05562  *
05563  */
05564 
05565 static VALUE
05566 proc_initgroups(VALUE obj, VALUE uname, VALUE base_grp)
05567 {
05568     PREPARE_GETGRNAM;
05569     if (initgroups(StringValuePtr(uname), OBJ2GID(base_grp)) != 0) {
05570         rb_sys_fail(0);
05571     }
05572     return proc_getgroups(obj);
05573 }
05574 #else
05575 #define proc_initgroups rb_f_notimplement
05576 #endif
05577 
05578 #if defined(_SC_NGROUPS_MAX) || defined(NGROUPS_MAX)
05579 /*
05580  *  call-seq:
05581  *     Process.maxgroups   -> fixnum
05582  *
05583  *  Returns the maximum number of gids allowed in the supplemental
05584  *  group access list.
05585  *
05586  *     Process.maxgroups   #=> 32
05587  */
05588 
05589 static VALUE
05590 proc_getmaxgroups(VALUE obj)
05591 {
05592     return INT2FIX(maxgroups());
05593 }
05594 #else
05595 #define proc_getmaxgroups rb_f_notimplement
05596 #endif
05597 
05598 #ifdef HAVE_SETGROUPS
05599 /*
05600  *  call-seq:
05601  *     Process.maxgroups= fixnum   -> fixnum
05602  *
05603  *  Sets the maximum number of gids allowed in the supplemental group
05604  *  access list.
05605  */
05606 
05607 static VALUE
05608 proc_setmaxgroups(VALUE obj, VALUE val)
05609 {
05610     int ngroups = FIX2INT(val);
05611     int ngroups_max = get_sc_ngroups_max();
05612 
05613     if (ngroups <= 0)
05614         rb_raise(rb_eArgError, "maxgroups %d shold be positive", ngroups);
05615 
05616     if (ngroups > RB_MAX_GROUPS)
05617         ngroups = RB_MAX_GROUPS;
05618 
05619     if (ngroups_max > 0 && ngroups > ngroups_max)
05620         ngroups = ngroups_max;
05621 
05622     _maxgroups = ngroups;
05623 
05624     return INT2FIX(_maxgroups);
05625 }
05626 #else
05627 #define proc_setmaxgroups rb_f_notimplement
05628 #endif
05629 
05630 #if defined(HAVE_DAEMON) || (defined(HAVE_FORK) && defined(HAVE_SETSID))
05631 static int rb_daemon(int nochdir, int noclose);
05632 
05633 /*
05634  *  call-seq:
05635  *     Process.daemon()                        -> 0
05636  *     Process.daemon(nochdir=nil,noclose=nil) -> 0
05637  *
05638  *  Detach the process from controlling terminal and run in
05639  *  the background as system daemon.  Unless the argument
05640  *  nochdir is true (i.e. non false), it changes the current
05641  *  working directory to the root ("/"). Unless the argument
05642  *  noclose is true, daemon() will redirect standard input,
05643  *  standard output and standard error to /dev/null.
05644  *  Return zero on success, or raise one of Errno::*.
05645  */
05646 
05647 static VALUE
05648 proc_daemon(int argc, VALUE *argv)
05649 {
05650     VALUE nochdir, noclose;
05651     int n;
05652 
05653     rb_secure(2);
05654     rb_scan_args(argc, argv, "02", &nochdir, &noclose);
05655 
05656     prefork();
05657     n = rb_daemon(RTEST(nochdir), RTEST(noclose));
05658     if (n < 0) rb_sys_fail("daemon");
05659     return INT2FIX(n);
05660 }
05661 
05662 static int
05663 rb_daemon(int nochdir, int noclose)
05664 {
05665     int err = 0;
05666 #ifdef HAVE_DAEMON
05667     before_fork();
05668     err = daemon(nochdir, noclose);
05669     after_fork();
05670 #else
05671     int n;
05672 
05673     switch (rb_fork_ruby(NULL)) {
05674       case -1:
05675         rb_sys_fail("daemon");
05676       case 0:
05677         break;
05678       default:
05679         _exit(EXIT_SUCCESS);
05680     }
05681 
05682     proc_setsid();
05683 
05684     /* must not be process-leader */
05685     switch (rb_fork_ruby(NULL)) {
05686       case -1:
05687         return -1;
05688       case 0:
05689         break;
05690       default:
05691         _exit(EXIT_SUCCESS);
05692     }
05693 
05694     if (!nochdir)
05695         err = chdir("/");
05696 
05697     if (!noclose && (n = rb_cloexec_open("/dev/null", O_RDWR, 0)) != -1) {
05698         rb_update_max_fd(n);
05699         (void)dup2(n, 0);
05700         (void)dup2(n, 1);
05701         (void)dup2(n, 2);
05702         if (n > 2)
05703             (void)close (n);
05704     }
05705 #endif
05706     return err;
05707 }
05708 #else
05709 #define proc_daemon rb_f_notimplement
05710 #endif
05711 
05712 /********************************************************************
05713  *
05714  * Document-class: Process::GID
05715  *
05716  *  The <code>Process::GID</code> module contains a collection of
05717  *  module functions which can be used to portably get, set, and
05718  *  switch the current process's real, effective, and saved group IDs.
05719  *
05720  */
05721 
05722 static rb_gid_t SAVED_GROUP_ID = -1;
05723 
05724 #ifdef BROKEN_SETREGID
05725 int
05726 setregid(rb_gid_t rgid, rb_gid_t egid)
05727 {
05728     if (rgid != (rb_gid_t)-1 && rgid != getgid()) {
05729         if (egid == (rb_gid_t)-1) egid = getegid();
05730         if (setgid(rgid) < 0) return -1;
05731     }
05732     if (egid != (rb_gid_t)-1 && egid != getegid()) {
05733         if (setegid(egid) < 0) return -1;
05734     }
05735     return 0;
05736 }
05737 #endif
05738 
05739 /*
05740  *  call-seq:
05741  *     Process::GID.change_privilege(group)   -> fixnum
05742  *
05743  *  Change the current process's real and effective group ID to that
05744  *  specified by _group_. Returns the new group ID. Not
05745  *  available on all platforms.
05746  *
05747  *     [Process.gid, Process.egid]          #=> [0, 0]
05748  *     Process::GID.change_privilege(33)    #=> 33
05749  *     [Process.gid, Process.egid]          #=> [33, 33]
05750  */
05751 
05752 static VALUE
05753 p_gid_change_privilege(VALUE obj, VALUE id)
05754 {
05755     rb_gid_t gid;
05756     PREPARE_GETGRNAM;
05757 
05758     check_gid_switch();
05759 
05760     gid = OBJ2GID(id);
05761 
05762     if (geteuid() == 0) { /* root-user */
05763 #if defined(HAVE_SETRESGID)
05764         if (setresgid(gid, gid, gid) < 0) rb_sys_fail(0);
05765         SAVED_GROUP_ID = gid;
05766 #elif defined HAVE_SETGID
05767         if (setgid(gid) < 0) rb_sys_fail(0);
05768         SAVED_GROUP_ID = gid;
05769 #elif defined(HAVE_SETREGID) && !defined(OBSOLETE_SETREGID)
05770         if (getgid() == gid) {
05771             if (SAVED_GROUP_ID == gid) {
05772                 if (setregid(-1, gid) < 0) rb_sys_fail(0);
05773             }
05774             else {
05775                 if (gid == 0) { /* (r,e,s) == (root, y, x) */
05776                     if (setregid(-1, SAVED_GROUP_ID) < 0) rb_sys_fail(0);
05777                     if (setregid(SAVED_GROUP_ID, 0) < 0) rb_sys_fail(0);
05778                     SAVED_GROUP_ID = 0; /* (r,e,s) == (x, root, root) */
05779                     if (setregid(gid, gid) < 0) rb_sys_fail(0);
05780                     SAVED_GROUP_ID = gid;
05781                 }
05782                 else { /* (r,e,s) == (z, y, x) */
05783                     if (setregid(0, 0) < 0) rb_sys_fail(0);
05784                     SAVED_GROUP_ID = 0;
05785                     if (setregid(gid, gid) < 0) rb_sys_fail(0);
05786                     SAVED_GROUP_ID = gid;
05787                 }
05788             }
05789         }
05790         else {
05791             if (setregid(gid, gid) < 0) rb_sys_fail(0);
05792             SAVED_GROUP_ID = gid;
05793         }
05794 #elif defined(HAVE_SETRGID) && defined (HAVE_SETEGID)
05795         if (getgid() == gid) {
05796             if (SAVED_GROUP_ID == gid) {
05797                 if (setegid(gid) < 0) rb_sys_fail(0);
05798             }
05799             else {
05800                 if (gid == 0) {
05801                     if (setegid(gid) < 0) rb_sys_fail(0);
05802                     if (setrgid(SAVED_GROUP_ID) < 0) rb_sys_fail(0);
05803                     SAVED_GROUP_ID = 0;
05804                     if (setrgid(0) < 0) rb_sys_fail(0);
05805                 }
05806                 else {
05807                     if (setrgid(0) < 0) rb_sys_fail(0);
05808                     SAVED_GROUP_ID = 0;
05809                     if (setegid(gid) < 0) rb_sys_fail(0);
05810                     if (setrgid(gid) < 0) rb_sys_fail(0);
05811                     SAVED_GROUP_ID = gid;
05812                 }
05813             }
05814         }
05815         else {
05816             if (setegid(gid) < 0) rb_sys_fail(0);
05817             if (setrgid(gid) < 0) rb_sys_fail(0);
05818             SAVED_GROUP_ID = gid;
05819         }
05820 #else
05821         rb_notimplement();
05822 #endif
05823     }
05824     else { /* unprivileged user */
05825 #if defined(HAVE_SETRESGID)
05826         if (setresgid((getgid() == gid)? (rb_gid_t)-1: gid,
05827                       (getegid() == gid)? (rb_gid_t)-1: gid,
05828                       (SAVED_GROUP_ID == gid)? (rb_gid_t)-1: gid) < 0) rb_sys_fail(0);
05829         SAVED_GROUP_ID = gid;
05830 #elif defined(HAVE_SETREGID) && !defined(OBSOLETE_SETREGID)
05831         if (SAVED_GROUP_ID == gid) {
05832             if (setregid((getgid() == gid)? (rb_uid_t)-1: gid,
05833                          (getegid() == gid)? (rb_uid_t)-1: gid) < 0)
05834                 rb_sys_fail(0);
05835         }
05836         else if (getgid() != gid) {
05837             if (setregid(gid, (getegid() == gid)? (rb_uid_t)-1: gid) < 0)
05838                 rb_sys_fail(0);
05839             SAVED_GROUP_ID = gid;
05840         }
05841         else if (/* getgid() == gid && */ getegid() != gid) {
05842             if (setregid(getegid(), gid) < 0) rb_sys_fail(0);
05843             SAVED_GROUP_ID = gid;
05844             if (setregid(gid, -1) < 0) rb_sys_fail(0);
05845         }
05846         else { /* getgid() == gid && getegid() == gid */
05847             if (setregid(-1, SAVED_GROUP_ID) < 0) rb_sys_fail(0);
05848             if (setregid(SAVED_GROUP_ID, gid) < 0) rb_sys_fail(0);
05849             SAVED_GROUP_ID = gid;
05850             if (setregid(gid, -1) < 0) rb_sys_fail(0);
05851         }
05852 #elif defined(HAVE_SETRGID) && defined(HAVE_SETEGID)
05853         if (SAVED_GROUP_ID == gid) {
05854             if (getegid() != gid && setegid(gid) < 0) rb_sys_fail(0);
05855             if (getgid() != gid && setrgid(gid) < 0) rb_sys_fail(0);
05856         }
05857         else if (/* SAVED_GROUP_ID != gid && */ getegid() == gid) {
05858             if (getgid() != gid) {
05859                 if (setrgid(gid) < 0) rb_sys_fail(0);
05860                 SAVED_GROUP_ID = gid;
05861             }
05862             else {
05863                 if (setrgid(SAVED_GROUP_ID) < 0) rb_sys_fail(0);
05864                 SAVED_GROUP_ID = gid;
05865                 if (setrgid(gid) < 0) rb_sys_fail(0);
05866             }
05867         }
05868         else if (/* getegid() != gid && */ getgid() == gid) {
05869             if (setegid(gid) < 0) rb_sys_fail(0);
05870             if (setrgid(SAVED_GROUP_ID) < 0) rb_sys_fail(0);
05871             SAVED_GROUP_ID = gid;
05872             if (setrgid(gid) < 0) rb_sys_fail(0);
05873         }
05874         else {
05875             errno = EPERM;
05876             rb_sys_fail(0);
05877         }
05878 #elif defined HAVE_44BSD_SETGID
05879         if (getgid() == gid) {
05880             /* (r,e,s)==(gid,?,?) ==> (gid,gid,gid) */
05881             if (setgid(gid) < 0) rb_sys_fail(0);
05882             SAVED_GROUP_ID = gid;
05883         }
05884         else {
05885             errno = EPERM;
05886             rb_sys_fail(0);
05887         }
05888 #elif defined HAVE_SETEGID
05889         if (getgid() == gid && SAVED_GROUP_ID == gid) {
05890             if (setegid(gid) < 0) rb_sys_fail(0);
05891         }
05892         else {
05893             errno = EPERM;
05894             rb_sys_fail(0);
05895         }
05896 #elif defined HAVE_SETGID
05897         if (getgid() == gid && SAVED_GROUP_ID == gid) {
05898             if (setgid(gid) < 0) rb_sys_fail(0);
05899         }
05900         else {
05901             errno = EPERM;
05902             rb_sys_fail(0);
05903         }
05904 #else
05905         (void)gid;
05906         rb_notimplement();
05907 #endif
05908     }
05909     return id;
05910 }
05911 
05912 
05913 /*
05914  *  call-seq:
05915  *     Process.euid           -> fixnum
05916  *     Process::UID.eid       -> fixnum
05917  *     Process::Sys.geteuid   -> fixnum
05918  *
05919  *  Returns the effective user ID for this process.
05920  *
05921  *     Process.euid   #=> 501
05922  */
05923 
05924 static VALUE
05925 proc_geteuid(VALUE obj)
05926 {
05927     rb_uid_t euid = geteuid();
05928     return UIDT2NUM(euid);
05929 }
05930 
05931 #if defined(HAVE_SETRESUID) || defined(HAVE_SETREUID) || defined(HAVE_SETEUID) || defined(HAVE_SETUID) || defined(_POSIX_SAVED_IDS)
05932 static void
05933 proc_seteuid(rb_uid_t uid)
05934 {
05935 #if defined(HAVE_SETRESUID)
05936     if (setresuid(-1, uid, -1) < 0) rb_sys_fail(0);
05937 #elif defined HAVE_SETREUID
05938     if (setreuid(-1, uid) < 0) rb_sys_fail(0);
05939 #elif defined HAVE_SETEUID
05940     if (seteuid(uid) < 0) rb_sys_fail(0);
05941 #elif defined HAVE_SETUID
05942     if (uid == getuid()) {
05943         if (setuid(uid) < 0) rb_sys_fail(0);
05944     }
05945     else {
05946         rb_notimplement();
05947     }
05948 #else
05949     rb_notimplement();
05950 #endif
05951 }
05952 #endif
05953 
05954 #if defined(HAVE_SETRESUID) || defined(HAVE_SETREUID) || defined(HAVE_SETEUID) || defined(HAVE_SETUID)
05955 /*
05956  *  call-seq:
05957  *     Process.euid= user
05958  *
05959  *  Sets the effective user ID for this process. Not available on all
05960  *  platforms.
05961  */
05962 
05963 static VALUE
05964 proc_seteuid_m(VALUE mod, VALUE euid)
05965 {
05966     PREPARE_GETPWNAM;
05967     check_uid_switch();
05968     proc_seteuid(OBJ2UID(euid));
05969     return euid;
05970 }
05971 #else
05972 #define proc_seteuid_m rb_f_notimplement
05973 #endif
05974 
05975 static rb_uid_t
05976 rb_seteuid_core(rb_uid_t euid)
05977 {
05978 #if defined(HAVE_SETRESUID) || (defined(HAVE_SETREUID) && !defined(OBSOLETE_SETREUID))
05979     rb_uid_t uid;
05980 #endif
05981 
05982     check_uid_switch();
05983 
05984 #if defined(HAVE_SETRESUID) || (defined(HAVE_SETREUID) && !defined(OBSOLETE_SETREUID))
05985     uid = getuid();
05986 #endif
05987 
05988 #if defined(HAVE_SETRESUID)
05989     if (uid != euid) {
05990         if (setresuid(-1,euid,euid) < 0) rb_sys_fail(0);
05991         SAVED_USER_ID = euid;
05992     }
05993     else {
05994         if (setresuid(-1,euid,-1) < 0) rb_sys_fail(0);
05995     }
05996 #elif defined(HAVE_SETREUID) && !defined(OBSOLETE_SETREUID)
05997     if (setreuid(-1, euid) < 0) rb_sys_fail(0);
05998     if (uid != euid) {
05999         if (setreuid(euid,uid) < 0) rb_sys_fail(0);
06000         if (setreuid(uid,euid) < 0) rb_sys_fail(0);
06001         SAVED_USER_ID = euid;
06002     }
06003 #elif defined HAVE_SETEUID
06004     if (seteuid(euid) < 0) rb_sys_fail(0);
06005 #elif defined HAVE_SETUID
06006     if (geteuid() == 0) rb_sys_fail(0);
06007     if (setuid(euid) < 0) rb_sys_fail(0);
06008 #else
06009     rb_notimplement();
06010 #endif
06011     return euid;
06012 }
06013 
06014 
06015 /*
06016  *  call-seq:
06017  *     Process::UID.grant_privilege(user)   -> fixnum
06018  *     Process::UID.eid= user               -> fixnum
06019  *
06020  *  Set the effective user ID, and if possible, the saved user ID of
06021  *  the process to the given _user_. Returns the new
06022  *  effective user ID. Not available on all platforms.
06023  *
06024  *     [Process.uid, Process.euid]          #=> [0, 0]
06025  *     Process::UID.grant_privilege(31)     #=> 31
06026  *     [Process.uid, Process.euid]          #=> [0, 31]
06027  */
06028 
06029 static VALUE
06030 p_uid_grant_privilege(VALUE obj, VALUE id)
06031 {
06032     PREPARE_GETPWNAM;
06033     rb_seteuid_core(OBJ2UID(id));
06034     return id;
06035 }
06036 
06037 
06038 /*
06039  *  call-seq:
06040  *     Process.egid          -> fixnum
06041  *     Process::GID.eid      -> fixnum
06042  *     Process::Sys.geteid   -> fixnum
06043  *
06044  *  Returns the effective group ID for this process. Not available on
06045  *  all platforms.
06046  *
06047  *     Process.egid   #=> 500
06048  */
06049 
06050 static VALUE
06051 proc_getegid(VALUE obj)
06052 {
06053     rb_gid_t egid = getegid();
06054 
06055     return GIDT2NUM(egid);
06056 }
06057 
06058 #if defined(HAVE_SETRESGID) || defined(HAVE_SETREGID) || defined(HAVE_SETEGID) || defined(HAVE_SETGID) || defined(_POSIX_SAVED_IDS)
06059 /*
06060  *  call-seq:
06061  *     Process.egid = fixnum   -> fixnum
06062  *
06063  *  Sets the effective group ID for this process. Not available on all
06064  *  platforms.
06065  */
06066 
06067 static VALUE
06068 proc_setegid(VALUE obj, VALUE egid)
06069 {
06070 #if defined(HAVE_SETRESGID) || defined(HAVE_SETREGID) || defined(HAVE_SETEGID) || defined(HAVE_SETGID)
06071     rb_gid_t gid;
06072     PREPARE_GETGRNAM;
06073 #endif
06074 
06075     check_gid_switch();
06076 
06077 #if defined(HAVE_SETRESGID) || defined(HAVE_SETREGID) || defined(HAVE_SETEGID) || defined(HAVE_SETGID)
06078     gid = OBJ2GID(egid);
06079 #endif
06080 
06081 #if defined(HAVE_SETRESGID)
06082     if (setresgid(-1, gid, -1) < 0) rb_sys_fail(0);
06083 #elif defined HAVE_SETREGID
06084     if (setregid(-1, gid) < 0) rb_sys_fail(0);
06085 #elif defined HAVE_SETEGID
06086     if (setegid(gid) < 0) rb_sys_fail(0);
06087 #elif defined HAVE_SETGID
06088     if (gid == getgid()) {
06089         if (setgid(gid) < 0) rb_sys_fail(0);
06090     }
06091     else {
06092         rb_notimplement();
06093     }
06094 #else
06095     rb_notimplement();
06096 #endif
06097     return egid;
06098 }
06099 #endif
06100 
06101 #if defined(HAVE_SETRESGID) || defined(HAVE_SETREGID) || defined(HAVE_SETEGID) || defined(HAVE_SETGID)
06102 #define proc_setegid_m proc_setegid
06103 #else
06104 #define proc_setegid_m rb_f_notimplement
06105 #endif
06106 
06107 static rb_gid_t
06108 rb_setegid_core(rb_gid_t egid)
06109 {
06110 #if defined(HAVE_SETRESGID) || (defined(HAVE_SETREGID) && !defined(OBSOLETE_SETREGID))
06111     rb_gid_t gid;
06112 #endif
06113 
06114     check_gid_switch();
06115 
06116 #if defined(HAVE_SETRESGID) || (defined(HAVE_SETREGID) && !defined(OBSOLETE_SETREGID))
06117     gid = getgid();
06118 #endif
06119 
06120 #if defined(HAVE_SETRESGID)
06121     if (gid != egid) {
06122         if (setresgid(-1,egid,egid) < 0) rb_sys_fail(0);
06123         SAVED_GROUP_ID = egid;
06124     }
06125     else {
06126         if (setresgid(-1,egid,-1) < 0) rb_sys_fail(0);
06127     }
06128 #elif defined(HAVE_SETREGID) && !defined(OBSOLETE_SETREGID)
06129     if (setregid(-1, egid) < 0) rb_sys_fail(0);
06130     if (gid != egid) {
06131         if (setregid(egid,gid) < 0) rb_sys_fail(0);
06132         if (setregid(gid,egid) < 0) rb_sys_fail(0);
06133         SAVED_GROUP_ID = egid;
06134     }
06135 #elif defined HAVE_SETEGID
06136     if (setegid(egid) < 0) rb_sys_fail(0);
06137 #elif defined HAVE_SETGID
06138     if (geteuid() == 0 /* root user */) rb_sys_fail(0);
06139     if (setgid(egid) < 0) rb_sys_fail(0);
06140 #else
06141     rb_notimplement();
06142 #endif
06143     return egid;
06144 }
06145 
06146 
06147 /*
06148  *  call-seq:
06149  *     Process::GID.grant_privilege(group)    -> fixnum
06150  *     Process::GID.eid = group               -> fixnum
06151  *
06152  *  Set the effective group ID, and if possible, the saved group ID of
06153  *  the process to the given _group_. Returns the new
06154  *  effective group ID. Not available on all platforms.
06155  *
06156  *     [Process.gid, Process.egid]          #=> [0, 0]
06157  *     Process::GID.grant_privilege(31)     #=> 33
06158  *     [Process.gid, Process.egid]          #=> [0, 33]
06159  */
06160 
06161 static VALUE
06162 p_gid_grant_privilege(VALUE obj, VALUE id)
06163 {
06164     PREPARE_GETGRNAM;
06165     rb_setegid_core(OBJ2GID(id));
06166     return id;
06167 }
06168 
06169 
06170 /*
06171  *  call-seq:
06172  *     Process::UID.re_exchangeable?   -> true or false
06173  *
06174  *  Returns +true+ if the real and effective user IDs of a
06175  *  process may be exchanged on the current platform.
06176  *
06177  */
06178 
06179 static VALUE
06180 p_uid_exchangeable(void)
06181 {
06182 #if defined(HAVE_SETRESUID)
06183     return Qtrue;
06184 #elif defined(HAVE_SETREUID) && !defined(OBSOLETE_SETREUID)
06185     return Qtrue;
06186 #else
06187     return Qfalse;
06188 #endif
06189 }
06190 
06191 
06192 /*
06193  *  call-seq:
06194  *     Process::UID.re_exchange   -> fixnum
06195  *
06196  *  Exchange real and effective user IDs and return the new effective
06197  *  user ID. Not available on all platforms.
06198  *
06199  *     [Process.uid, Process.euid]   #=> [0, 31]
06200  *     Process::UID.re_exchange      #=> 0
06201  *     [Process.uid, Process.euid]   #=> [31, 0]
06202  */
06203 
06204 static VALUE
06205 p_uid_exchange(VALUE obj)
06206 {
06207     rb_uid_t uid;
06208 #if defined(HAVE_SETRESUID) || (defined(HAVE_SETREUID) && !defined(OBSOLETE_SETREUID))
06209     rb_uid_t euid;
06210 #endif
06211 
06212     check_uid_switch();
06213 
06214     uid = getuid();
06215 #if defined(HAVE_SETRESUID) || (defined(HAVE_SETREUID) && !defined(OBSOLETE_SETREUID))
06216     euid = geteuid();
06217 #endif
06218 
06219 #if defined(HAVE_SETRESUID)
06220     if (setresuid(euid, uid, uid) < 0) rb_sys_fail(0);
06221     SAVED_USER_ID = uid;
06222 #elif defined(HAVE_SETREUID) && !defined(OBSOLETE_SETREUID)
06223     if (setreuid(euid,uid) < 0) rb_sys_fail(0);
06224     SAVED_USER_ID = uid;
06225 #else
06226     rb_notimplement();
06227 #endif
06228     return UIDT2NUM(uid);
06229 }
06230 
06231 
06232 /*
06233  *  call-seq:
06234  *     Process::GID.re_exchangeable?   -> true or false
06235  *
06236  *  Returns +true+ if the real and effective group IDs of a
06237  *  process may be exchanged on the current platform.
06238  *
06239  */
06240 
06241 static VALUE
06242 p_gid_exchangeable(void)
06243 {
06244 #if defined(HAVE_SETRESGID)
06245     return Qtrue;
06246 #elif defined(HAVE_SETREGID) && !defined(OBSOLETE_SETREGID)
06247     return Qtrue;
06248 #else
06249     return Qfalse;
06250 #endif
06251 }
06252 
06253 
06254 /*
06255  *  call-seq:
06256  *     Process::GID.re_exchange   -> fixnum
06257  *
06258  *  Exchange real and effective group IDs and return the new effective
06259  *  group ID. Not available on all platforms.
06260  *
06261  *     [Process.gid, Process.egid]   #=> [0, 33]
06262  *     Process::GID.re_exchange      #=> 0
06263  *     [Process.gid, Process.egid]   #=> [33, 0]
06264  */
06265 
06266 static VALUE
06267 p_gid_exchange(VALUE obj)
06268 {
06269     rb_gid_t gid;
06270 #if defined(HAVE_SETRESGID) || (defined(HAVE_SETREGID) && !defined(OBSOLETE_SETREGID))
06271     rb_gid_t egid;
06272 #endif
06273 
06274     check_gid_switch();
06275 
06276     gid = getgid();
06277 #if defined(HAVE_SETRESGID) || (defined(HAVE_SETREGID) && !defined(OBSOLETE_SETREGID))
06278     egid = getegid();
06279 #endif
06280 
06281 #if defined(HAVE_SETRESGID)
06282     if (setresgid(egid, gid, gid) < 0) rb_sys_fail(0);
06283     SAVED_GROUP_ID = gid;
06284 #elif defined(HAVE_SETREGID) && !defined(OBSOLETE_SETREGID)
06285     if (setregid(egid,gid) < 0) rb_sys_fail(0);
06286     SAVED_GROUP_ID = gid;
06287 #else
06288     rb_notimplement();
06289 #endif
06290     return GIDT2NUM(gid);
06291 }
06292 
06293 /* [MG] :FIXME: Is this correct? I'm not sure how to phrase this. */
06294 
06295 /*
06296  *  call-seq:
06297  *     Process::UID.sid_available?   -> true or false
06298  *
06299  *  Returns +true+ if the current platform has saved user
06300  *  ID functionality.
06301  *
06302  */
06303 
06304 static VALUE
06305 p_uid_have_saved_id(void)
06306 {
06307 #if defined(HAVE_SETRESUID) || defined(HAVE_SETEUID) || defined(_POSIX_SAVED_IDS)
06308     return Qtrue;
06309 #else
06310     return Qfalse;
06311 #endif
06312 }
06313 
06314 
06315 #if defined(HAVE_SETRESUID) || defined(HAVE_SETEUID) || defined(_POSIX_SAVED_IDS)
06316 static VALUE
06317 p_uid_sw_ensure(rb_uid_t id)
06318 {
06319     under_uid_switch = 0;
06320     id = rb_seteuid_core(id);
06321     return UIDT2NUM(id);
06322 }
06323 
06324 
06325 /*
06326  *  call-seq:
06327  *     Process::UID.switch              -> fixnum
06328  *     Process::UID.switch {|| block}   -> object
06329  *
06330  *  Switch the effective and real user IDs of the current process. If
06331  *  a <em>block</em> is given, the user IDs will be switched back
06332  *  after the block is executed. Returns the new effective user ID if
06333  *  called without a block, and the return value of the block if one
06334  *  is given.
06335  *
06336  */
06337 
06338 static VALUE
06339 p_uid_switch(VALUE obj)
06340 {
06341     rb_uid_t uid, euid;
06342 
06343     check_uid_switch();
06344 
06345     uid = getuid();
06346     euid = geteuid();
06347 
06348     if (uid != euid) {
06349         proc_seteuid(uid);
06350         if (rb_block_given_p()) {
06351             under_uid_switch = 1;
06352             return rb_ensure(rb_yield, Qnil, p_uid_sw_ensure, SAVED_USER_ID);
06353         }
06354         else {
06355             return UIDT2NUM(euid);
06356         }
06357     }
06358     else if (euid != SAVED_USER_ID) {
06359         proc_seteuid(SAVED_USER_ID);
06360         if (rb_block_given_p()) {
06361             under_uid_switch = 1;
06362             return rb_ensure(rb_yield, Qnil, p_uid_sw_ensure, euid);
06363         }
06364         else {
06365             return UIDT2NUM(uid);
06366         }
06367     }
06368     else {
06369         errno = EPERM;
06370         rb_sys_fail(0);
06371     }
06372 
06373     UNREACHABLE;
06374 }
06375 #else
06376 static VALUE
06377 p_uid_sw_ensure(VALUE obj)
06378 {
06379     under_uid_switch = 0;
06380     return p_uid_exchange(obj);
06381 }
06382 
06383 static VALUE
06384 p_uid_switch(VALUE obj)
06385 {
06386     rb_uid_t uid, euid;
06387 
06388     check_uid_switch();
06389 
06390     uid = getuid();
06391     euid = geteuid();
06392 
06393     if (uid == euid) {
06394         errno = EPERM;
06395         rb_sys_fail(0);
06396     }
06397     p_uid_exchange(obj);
06398     if (rb_block_given_p()) {
06399         under_uid_switch = 1;
06400         return rb_ensure(rb_yield, Qnil, p_uid_sw_ensure, obj);
06401     }
06402     else {
06403         return UIDT2NUM(euid);
06404     }
06405 }
06406 #endif
06407 
06408 
06409 /* [MG] :FIXME: Is this correct? I'm not sure how to phrase this. */
06410 
06411 /*
06412  *  call-seq:
06413  *     Process::GID.sid_available?   -> true or false
06414  *
06415  *  Returns +true+ if the current platform has saved group
06416  *  ID functionality.
06417  *
06418  */
06419 
06420 static VALUE
06421 p_gid_have_saved_id(void)
06422 {
06423 #if defined(HAVE_SETRESGID) || defined(HAVE_SETEGID) || defined(_POSIX_SAVED_IDS)
06424     return Qtrue;
06425 #else
06426     return Qfalse;
06427 #endif
06428 }
06429 
06430 #if defined(HAVE_SETRESGID) || defined(HAVE_SETEGID) || defined(_POSIX_SAVED_IDS)
06431 static VALUE
06432 p_gid_sw_ensure(rb_gid_t id)
06433 {
06434     under_gid_switch = 0;
06435     id = rb_setegid_core(id);
06436     return GIDT2NUM(id);
06437 }
06438 
06439 
06440 /*
06441  *  call-seq:
06442  *     Process::GID.switch              -> fixnum
06443  *     Process::GID.switch {|| block}   -> object
06444  *
06445  *  Switch the effective and real group IDs of the current process. If
06446  *  a <em>block</em> is given, the group IDs will be switched back
06447  *  after the block is executed. Returns the new effective group ID if
06448  *  called without a block, and the return value of the block if one
06449  *  is given.
06450  *
06451  */
06452 
06453 static VALUE
06454 p_gid_switch(VALUE obj)
06455 {
06456     rb_gid_t gid, egid;
06457 
06458     check_gid_switch();
06459 
06460     gid = getgid();
06461     egid = getegid();
06462 
06463     if (gid != egid) {
06464         proc_setegid(obj, GIDT2NUM(gid));
06465         if (rb_block_given_p()) {
06466             under_gid_switch = 1;
06467             return rb_ensure(rb_yield, Qnil, p_gid_sw_ensure, SAVED_GROUP_ID);
06468         }
06469         else {
06470             return GIDT2NUM(egid);
06471         }
06472     }
06473     else if (egid != SAVED_GROUP_ID) {
06474         proc_setegid(obj, GIDT2NUM(SAVED_GROUP_ID));
06475         if (rb_block_given_p()) {
06476             under_gid_switch = 1;
06477             return rb_ensure(rb_yield, Qnil, p_gid_sw_ensure, egid);
06478         }
06479         else {
06480             return GIDT2NUM(gid);
06481         }
06482     }
06483     else {
06484         errno = EPERM;
06485         rb_sys_fail(0);
06486     }
06487 
06488     UNREACHABLE;
06489 }
06490 #else
06491 static VALUE
06492 p_gid_sw_ensure(VALUE obj)
06493 {
06494     under_gid_switch = 0;
06495     return p_gid_exchange(obj);
06496 }
06497 
06498 static VALUE
06499 p_gid_switch(VALUE obj)
06500 {
06501     rb_gid_t gid, egid;
06502 
06503     check_gid_switch();
06504 
06505     gid = getgid();
06506     egid = getegid();
06507 
06508     if (gid == egid) {
06509         errno = EPERM;
06510         rb_sys_fail(0);
06511     }
06512     p_gid_exchange(obj);
06513     if (rb_block_given_p()) {
06514         under_gid_switch = 1;
06515         return rb_ensure(rb_yield, Qnil, p_gid_sw_ensure, obj);
06516     }
06517     else {
06518         return GIDT2NUM(egid);
06519     }
06520 }
06521 #endif
06522 
06523 
06524 #if defined(HAVE_TIMES)
06525 /*
06526  *  call-seq:
06527  *     Process.times   -> aStructTms
06528  *
06529  *  Returns a <code>Tms</code> structure (see <code>Struct::Tms</code>)
06530  *  that contains user and system CPU times for this process,
06531  *  and also for children processes.
06532  *
06533  *     t = Process.times
06534  *     [ t.utime, t.stime, t.cutime, t.cstime ]   #=> [0.0, 0.02, 0.00, 0.00]
06535  */
06536 
06537 VALUE
06538 rb_proc_times(VALUE obj)
06539 {
06540     const double hertz =
06541 #ifdef HAVE__SC_CLK_TCK
06542         (double)sysconf(_SC_CLK_TCK);
06543 #else
06544 #ifndef HZ
06545 # ifdef CLK_TCK
06546 #   define HZ CLK_TCK
06547 # else
06548 #   define HZ 60
06549 # endif
06550 #endif /* HZ */
06551         HZ;
06552 #endif
06553     struct tms buf;
06554     volatile VALUE utime, stime, cutime, sctime;
06555 
06556     times(&buf);
06557     return rb_struct_new(rb_cProcessTms,
06558                          utime = DBL2NUM(buf.tms_utime / hertz),
06559                          stime = DBL2NUM(buf.tms_stime / hertz),
06560                          cutime = DBL2NUM(buf.tms_cutime / hertz),
06561                          sctime = DBL2NUM(buf.tms_cstime / hertz));
06562 }
06563 #else
06564 #define rb_proc_times rb_f_notimplement
06565 #endif
06566 
06567 VALUE rb_mProcess;
06568 VALUE rb_mProcUID;
06569 VALUE rb_mProcGID;
06570 VALUE rb_mProcID_Syscall;
06571 
06572 
06573 /*
06574  *  The <code>Process</code> module is a collection of methods used to
06575  *  manipulate processes.
06576  */
06577 
06578 void
06579 Init_process(void)
06580 {
06581     rb_define_virtual_variable("$?", rb_last_status_get, 0);
06582     rb_define_virtual_variable("$$", get_pid, 0);
06583     rb_define_global_function("exec", rb_f_exec, -1);
06584     rb_define_global_function("fork", rb_f_fork, 0);
06585     rb_define_global_function("exit!", rb_f_exit_bang, -1);
06586     rb_define_global_function("system", rb_f_system, -1);
06587     rb_define_global_function("spawn", rb_f_spawn, -1);
06588     rb_define_global_function("sleep", rb_f_sleep, -1);
06589     rb_define_global_function("exit", rb_f_exit, -1);
06590     rb_define_global_function("abort", rb_f_abort, -1);
06591 
06592     rb_mProcess = rb_define_module("Process");
06593 
06594 #ifdef WNOHANG
06595     /* see Process.wait */
06596     rb_define_const(rb_mProcess, "WNOHANG", INT2FIX(WNOHANG));
06597 #else
06598     /* see Process.wait */
06599     rb_define_const(rb_mProcess, "WNOHANG", INT2FIX(0));
06600 #endif
06601 #ifdef WUNTRACED
06602     /* see Process.wait */
06603     rb_define_const(rb_mProcess, "WUNTRACED", INT2FIX(WUNTRACED));
06604 #else
06605     /* see Process.wait */
06606     rb_define_const(rb_mProcess, "WUNTRACED", INT2FIX(0));
06607 #endif
06608 
06609     rb_define_singleton_method(rb_mProcess, "exec", rb_f_exec, -1);
06610     rb_define_singleton_method(rb_mProcess, "fork", rb_f_fork, 0);
06611     rb_define_singleton_method(rb_mProcess, "spawn", rb_f_spawn, -1);
06612     rb_define_singleton_method(rb_mProcess, "exit!", rb_f_exit_bang, -1);
06613     rb_define_singleton_method(rb_mProcess, "exit", rb_f_exit, -1);
06614     rb_define_singleton_method(rb_mProcess, "abort", rb_f_abort, -1);
06615 
06616     rb_define_module_function(rb_mProcess, "kill", rb_f_kill, -1); /* in signal.c */
06617     rb_define_module_function(rb_mProcess, "wait", proc_wait, -1);
06618     rb_define_module_function(rb_mProcess, "wait2", proc_wait2, -1);
06619     rb_define_module_function(rb_mProcess, "waitpid", proc_wait, -1);
06620     rb_define_module_function(rb_mProcess, "waitpid2", proc_wait2, -1);
06621     rb_define_module_function(rb_mProcess, "waitall", proc_waitall, 0);
06622     rb_define_module_function(rb_mProcess, "detach", proc_detach, 1);
06623 
06624     rb_cProcessStatus = rb_define_class_under(rb_mProcess, "Status", rb_cObject);
06625     rb_undef_method(CLASS_OF(rb_cProcessStatus), "new");
06626 
06627     rb_define_method(rb_cProcessStatus, "==", pst_equal, 1);
06628     rb_define_method(rb_cProcessStatus, "&", pst_bitand, 1);
06629     rb_define_method(rb_cProcessStatus, ">>", pst_rshift, 1);
06630     rb_define_method(rb_cProcessStatus, "to_i", pst_to_i, 0);
06631     rb_define_method(rb_cProcessStatus, "to_s", pst_to_s, 0);
06632     rb_define_method(rb_cProcessStatus, "inspect", pst_inspect, 0);
06633 
06634     rb_define_method(rb_cProcessStatus, "pid", pst_pid, 0);
06635 
06636     rb_define_method(rb_cProcessStatus, "stopped?", pst_wifstopped, 0);
06637     rb_define_method(rb_cProcessStatus, "stopsig", pst_wstopsig, 0);
06638     rb_define_method(rb_cProcessStatus, "signaled?", pst_wifsignaled, 0);
06639     rb_define_method(rb_cProcessStatus, "termsig", pst_wtermsig, 0);
06640     rb_define_method(rb_cProcessStatus, "exited?", pst_wifexited, 0);
06641     rb_define_method(rb_cProcessStatus, "exitstatus", pst_wexitstatus, 0);
06642     rb_define_method(rb_cProcessStatus, "success?", pst_success_p, 0);
06643     rb_define_method(rb_cProcessStatus, "coredump?", pst_wcoredump, 0);
06644 
06645     rb_define_module_function(rb_mProcess, "pid", get_pid, 0);
06646     rb_define_module_function(rb_mProcess, "ppid", get_ppid, 0);
06647 
06648     rb_define_module_function(rb_mProcess, "getpgrp", proc_getpgrp, 0);
06649     rb_define_module_function(rb_mProcess, "setpgrp", proc_setpgrp, 0);
06650     rb_define_module_function(rb_mProcess, "getpgid", proc_getpgid, 1);
06651     rb_define_module_function(rb_mProcess, "setpgid", proc_setpgid, 2);
06652 
06653     rb_define_module_function(rb_mProcess, "getsid", proc_getsid, -1);
06654     rb_define_module_function(rb_mProcess, "setsid", proc_setsid, 0);
06655 
06656     rb_define_module_function(rb_mProcess, "getpriority", proc_getpriority, 2);
06657     rb_define_module_function(rb_mProcess, "setpriority", proc_setpriority, 3);
06658 
06659 #ifdef HAVE_GETPRIORITY
06660     /* see Process.setpriority */
06661     rb_define_const(rb_mProcess, "PRIO_PROCESS", INT2FIX(PRIO_PROCESS));
06662     /* see Process.setpriority */
06663     rb_define_const(rb_mProcess, "PRIO_PGRP", INT2FIX(PRIO_PGRP));
06664     /* see Process.setpriority */
06665     rb_define_const(rb_mProcess, "PRIO_USER", INT2FIX(PRIO_USER));
06666 #endif
06667 
06668     rb_define_module_function(rb_mProcess, "getrlimit", proc_getrlimit, 1);
06669     rb_define_module_function(rb_mProcess, "setrlimit", proc_setrlimit, -1);
06670 #if defined(RLIM2NUM) && defined(RLIM_INFINITY)
06671     {
06672         VALUE inf = RLIM2NUM(RLIM_INFINITY);
06673 #ifdef RLIM_SAVED_MAX
06674         {
06675             VALUE v = RLIM_INFINITY == RLIM_SAVED_MAX ? inf : RLIM2NUM(RLIM_SAVED_MAX);
06676             /* see Process.setrlimit */
06677             rb_define_const(rb_mProcess, "RLIM_SAVED_MAX", v);
06678         }
06679 #endif
06680         /* see Process.setrlimit */
06681         rb_define_const(rb_mProcess, "RLIM_INFINITY", inf);
06682 #ifdef RLIM_SAVED_CUR
06683         {
06684             VALUE v = RLIM_INFINITY == RLIM_SAVED_CUR ? inf : RLIM2NUM(RLIM_SAVED_CUR);
06685             /* see Process.setrlimit */
06686             rb_define_const(rb_mProcess, "RLIM_SAVED_CUR", v);
06687         }
06688 #endif
06689     }
06690 #ifdef RLIMIT_AS
06691     /* Maximum size of the process's virtual memory (address space) in bytes.
06692      *
06693      * see the system getrlimit(2) manual for details.
06694      */
06695     rb_define_const(rb_mProcess, "RLIMIT_AS", INT2FIX(RLIMIT_AS));
06696 #endif
06697 #ifdef RLIMIT_CORE
06698     /* Maximum size of the core file.
06699      *
06700      * see the system getrlimit(2) manual for details.
06701      */
06702     rb_define_const(rb_mProcess, "RLIMIT_CORE", INT2FIX(RLIMIT_CORE));
06703 #endif
06704 #ifdef RLIMIT_CPU
06705     /* CPU time limit in seconds.
06706      *
06707      * see the system getrlimit(2) manual for details.
06708      */
06709     rb_define_const(rb_mProcess, "RLIMIT_CPU", INT2FIX(RLIMIT_CPU));
06710 #endif
06711 #ifdef RLIMIT_DATA
06712     /* Maximum size of the process's data segment.
06713      *
06714      * see the system getrlimit(2) manual for details.
06715      */
06716     rb_define_const(rb_mProcess, "RLIMIT_DATA", INT2FIX(RLIMIT_DATA));
06717 #endif
06718 #ifdef RLIMIT_FSIZE
06719     /* Maximum size of files that the process may create.
06720      *
06721      * see the system getrlimit(2) manual for details.
06722      */
06723     rb_define_const(rb_mProcess, "RLIMIT_FSIZE", INT2FIX(RLIMIT_FSIZE));
06724 #endif
06725 #ifdef RLIMIT_MEMLOCK
06726     /* Maximum number of bytes of memory that may be locked into RAM.
06727      *
06728      * see the system getrlimit(2) manual for details.
06729      */
06730     rb_define_const(rb_mProcess, "RLIMIT_MEMLOCK", INT2FIX(RLIMIT_MEMLOCK));
06731 #endif
06732 #ifdef RLIMIT_MSGQUEUE
06733     /* Specifies the limit on the number of bytes that can be allocated
06734      * for POSIX message queues for the real user ID of the calling process.
06735      *
06736      * see the system getrlimit(2) manual for details.
06737      */
06738     rb_define_const(rb_mProcess, "RLIMIT_MSGQUEUE", INT2FIX(RLIMIT_MSGQUEUE));
06739 #endif
06740 #ifdef RLIMIT_NICE
06741     /* Specifies a ceiling to which the process's nice value can be raised.
06742      *
06743      * see the system getrlimit(2) manual for details.
06744      */
06745     rb_define_const(rb_mProcess, "RLIMIT_NICE", INT2FIX(RLIMIT_NICE));
06746 #endif
06747 #ifdef RLIMIT_NOFILE
06748     /* Specifies a value one greater than the maximum file descriptor
06749      * number that can be opened by this process.
06750      *
06751      * see the system getrlimit(2) manual for details.
06752      */
06753     rb_define_const(rb_mProcess, "RLIMIT_NOFILE", INT2FIX(RLIMIT_NOFILE));
06754 #endif
06755 #ifdef RLIMIT_NPROC
06756     /* The maximum number of processes that can be created for the
06757      * real user ID of the calling process.
06758      *
06759      * see the system getrlimit(2) manual for details.
06760      */
06761     rb_define_const(rb_mProcess, "RLIMIT_NPROC", INT2FIX(RLIMIT_NPROC));
06762 #endif
06763 #ifdef RLIMIT_RSS
06764     /* Specifies the limit (in pages) of the process's resident set.
06765      *
06766      * see the system getrlimit(2) manual for details.
06767      */
06768     rb_define_const(rb_mProcess, "RLIMIT_RSS", INT2FIX(RLIMIT_RSS));
06769 #endif
06770 #ifdef RLIMIT_RTPRIO
06771     /* Specifies a ceiling on the real-time priority that may be set for this process.
06772      *
06773      * see the system getrlimit(2) manual for details.
06774      */
06775     rb_define_const(rb_mProcess, "RLIMIT_RTPRIO", INT2FIX(RLIMIT_RTPRIO));
06776 #endif
06777 #ifdef RLIMIT_RTTIME
06778     /* Specifies limit on CPU time this process scheduled under a real-time
06779      * scheduling policy can consume.
06780      *
06781      * see the system getrlimit(2) manual for details.
06782      */
06783     rb_define_const(rb_mProcess, "RLIMIT_RTTIME", INT2FIX(RLIMIT_RTTIME));
06784 #endif
06785 #ifdef RLIMIT_SBSIZE
06786     /* Maximum size of the socket buffer.
06787      */
06788     rb_define_const(rb_mProcess, "RLIMIT_SBSIZE", INT2FIX(RLIMIT_SBSIZE));
06789 #endif
06790 #ifdef RLIMIT_SIGPENDING
06791     /* Specifies a limit on the number of signals that may be queued for
06792      * the real user ID of the calling process.
06793      *
06794      * see the system getrlimit(2) manual for details.
06795      */
06796     rb_define_const(rb_mProcess, "RLIMIT_SIGPENDING", INT2FIX(RLIMIT_SIGPENDING));
06797 #endif
06798 #ifdef RLIMIT_STACK
06799     /* Maximum size of the stack, in bytes.
06800      *
06801      * see the system getrlimit(2) manual for details.
06802      */
06803     rb_define_const(rb_mProcess, "RLIMIT_STACK", INT2FIX(RLIMIT_STACK));
06804 #endif
06805 #endif
06806 
06807     rb_define_module_function(rb_mProcess, "uid", proc_getuid, 0);
06808     rb_define_module_function(rb_mProcess, "uid=", proc_setuid, 1);
06809     rb_define_module_function(rb_mProcess, "gid", proc_getgid, 0);
06810     rb_define_module_function(rb_mProcess, "gid=", proc_setgid, 1);
06811     rb_define_module_function(rb_mProcess, "euid", proc_geteuid, 0);
06812     rb_define_module_function(rb_mProcess, "euid=", proc_seteuid_m, 1);
06813     rb_define_module_function(rb_mProcess, "egid", proc_getegid, 0);
06814     rb_define_module_function(rb_mProcess, "egid=", proc_setegid_m, 1);
06815     rb_define_module_function(rb_mProcess, "initgroups", proc_initgroups, 2);
06816     rb_define_module_function(rb_mProcess, "groups", proc_getgroups, 0);
06817     rb_define_module_function(rb_mProcess, "groups=", proc_setgroups, 1);
06818     rb_define_module_function(rb_mProcess, "maxgroups", proc_getmaxgroups, 0);
06819     rb_define_module_function(rb_mProcess, "maxgroups=", proc_setmaxgroups, 1);
06820 
06821     rb_define_module_function(rb_mProcess, "daemon", proc_daemon, -1);
06822 
06823     rb_define_module_function(rb_mProcess, "times", rb_proc_times, 0);
06824 
06825 #if defined(HAVE_TIMES) || defined(_WIN32)
06826     rb_cProcessTms = rb_struct_define("Tms", "utime", "stime", "cutime", "cstime", NULL);
06827 #endif
06828 
06829     SAVED_USER_ID = geteuid();
06830     SAVED_GROUP_ID = getegid();
06831 
06832     rb_mProcUID = rb_define_module_under(rb_mProcess, "UID");
06833     rb_mProcGID = rb_define_module_under(rb_mProcess, "GID");
06834 
06835     rb_define_module_function(rb_mProcUID, "rid", proc_getuid, 0);
06836     rb_define_module_function(rb_mProcGID, "rid", proc_getgid, 0);
06837     rb_define_module_function(rb_mProcUID, "eid", proc_geteuid, 0);
06838     rb_define_module_function(rb_mProcGID, "eid", proc_getegid, 0);
06839     rb_define_module_function(rb_mProcUID, "change_privilege", p_uid_change_privilege, 1);
06840     rb_define_module_function(rb_mProcGID, "change_privilege", p_gid_change_privilege, 1);
06841     rb_define_module_function(rb_mProcUID, "grant_privilege", p_uid_grant_privilege, 1);
06842     rb_define_module_function(rb_mProcGID, "grant_privilege", p_gid_grant_privilege, 1);
06843     rb_define_alias(rb_singleton_class(rb_mProcUID), "eid=", "grant_privilege");
06844     rb_define_alias(rb_singleton_class(rb_mProcGID), "eid=", "grant_privilege");
06845     rb_define_module_function(rb_mProcUID, "re_exchange", p_uid_exchange, 0);
06846     rb_define_module_function(rb_mProcGID, "re_exchange", p_gid_exchange, 0);
06847     rb_define_module_function(rb_mProcUID, "re_exchangeable?", p_uid_exchangeable, 0);
06848     rb_define_module_function(rb_mProcGID, "re_exchangeable?", p_gid_exchangeable, 0);
06849     rb_define_module_function(rb_mProcUID, "sid_available?", p_uid_have_saved_id, 0);
06850     rb_define_module_function(rb_mProcGID, "sid_available?", p_gid_have_saved_id, 0);
06851     rb_define_module_function(rb_mProcUID, "switch", p_uid_switch, 0);
06852     rb_define_module_function(rb_mProcGID, "switch", p_gid_switch, 0);
06853 #ifdef p_uid_from_name
06854     rb_define_module_function(rb_mProcUID, "from_name", p_uid_from_name, 1);
06855 #endif
06856 #ifdef p_gid_from_name
06857     rb_define_module_function(rb_mProcGID, "from_name", p_gid_from_name, 1);
06858 #endif
06859 
06860     rb_mProcID_Syscall = rb_define_module_under(rb_mProcess, "Sys");
06861 
06862     rb_define_module_function(rb_mProcID_Syscall, "getuid", proc_getuid, 0);
06863     rb_define_module_function(rb_mProcID_Syscall, "geteuid", proc_geteuid, 0);
06864     rb_define_module_function(rb_mProcID_Syscall, "getgid", proc_getgid, 0);
06865     rb_define_module_function(rb_mProcID_Syscall, "getegid", proc_getegid, 0);
06866 
06867     rb_define_module_function(rb_mProcID_Syscall, "setuid", p_sys_setuid, 1);
06868     rb_define_module_function(rb_mProcID_Syscall, "setgid", p_sys_setgid, 1);
06869 
06870     rb_define_module_function(rb_mProcID_Syscall, "setruid", p_sys_setruid, 1);
06871     rb_define_module_function(rb_mProcID_Syscall, "setrgid", p_sys_setrgid, 1);
06872 
06873     rb_define_module_function(rb_mProcID_Syscall, "seteuid", p_sys_seteuid, 1);
06874     rb_define_module_function(rb_mProcID_Syscall, "setegid", p_sys_setegid, 1);
06875 
06876     rb_define_module_function(rb_mProcID_Syscall, "setreuid", p_sys_setreuid, 2);
06877     rb_define_module_function(rb_mProcID_Syscall, "setregid", p_sys_setregid, 2);
06878 
06879     rb_define_module_function(rb_mProcID_Syscall, "setresuid", p_sys_setresuid, 3);
06880     rb_define_module_function(rb_mProcID_Syscall, "setresgid", p_sys_setresgid, 3);
06881     rb_define_module_function(rb_mProcID_Syscall, "issetugid", p_sys_issetugid, 0);
06882 }
06883