Ruby  2.0.0p481(2014-05-08revision45883)
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_occurred;
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         pid = retry_fork(status, ep, chfunc_is_async_signal_safe);
03332         if (pid < 0)
03333             return pid;
03334         if (!pid) {
03335             int ret;
03336             forked_child = 1;
03337             close(ep[0]);
03338             if (chfunc_is_async_signal_safe)
03339                 ret = chfunc(charg, errmsg, errmsg_buflen);
03340             else {
03341                 struct chfunc_protect_t arg;
03342                 arg.chfunc = chfunc;
03343                 arg.arg = charg;
03344                 arg.errmsg = errmsg;
03345                 arg.buflen = errmsg_buflen;
03346                 ret = (int)rb_protect(chfunc_protect, (VALUE)&arg, &state);
03347             }
03348             if (!ret) _exit(EXIT_SUCCESS);
03349             send_child_error(ep[1], state, errmsg, errmsg_buflen, chfunc_is_async_signal_safe);
03350 #if EXIT_SUCCESS == 127
03351             _exit(EXIT_FAILURE);
03352 #else
03353             _exit(127);
03354 #endif
03355         }
03356         close(ep[1]);
03357         error_occurred = recv_child_error(ep[0], &state, &exc, &err, errmsg, errmsg_buflen, chfunc_is_async_signal_safe);
03358         if (state || error_occurred) {
03359             if (status) {
03360                 rb_protect(proc_syswait, (VALUE)pid, status);
03361                 if (state) *status = state;
03362             }
03363             else {
03364                 rb_syswait(pid);
03365                 if (state) rb_exc_raise(exc);
03366             }
03367             errno = err;
03368             return -1;
03369         }
03370         return pid;
03371     }
03372 }
03373 
03374 rb_pid_t
03375 rb_fork_err(int *status, int (*chfunc)(void*, char *, size_t), void *charg, VALUE fds,
03376         char *errmsg, size_t errmsg_buflen)
03377 {
03378     return rb_fork_internal(status, chfunc, charg, FALSE, fds, errmsg, errmsg_buflen);
03379 }
03380 
03381 rb_pid_t
03382 rb_fork_async_signal_safe(int *status, int (*chfunc)(void*, char *, size_t), void *charg, VALUE fds,
03383         char *errmsg, size_t errmsg_buflen)
03384 {
03385     return rb_fork_internal(status, chfunc, charg, TRUE, fds, errmsg, errmsg_buflen);
03386 }
03387 
03388 struct chfunc_wrapper_t {
03389     int (*chfunc)(void*);
03390     void *arg;
03391 };
03392 
03393 static int
03394 chfunc_wrapper(void *arg_, char *errmsg, size_t errmsg_buflen)
03395 {
03396     struct chfunc_wrapper_t *arg = arg_;
03397     return arg->chfunc(arg->arg);
03398 }
03399 
03400 rb_pid_t
03401 rb_fork(int *status, int (*chfunc)(void*), void *charg, VALUE fds)
03402 {
03403     if (chfunc) {
03404         struct chfunc_wrapper_t warg;
03405         warg.chfunc = chfunc;
03406         warg.arg = charg;
03407         return rb_fork_internal(status, chfunc_wrapper, &warg, FALSE, fds, NULL, 0);
03408     }
03409     else {
03410         return rb_fork_internal(status, NULL, NULL, FALSE, fds, NULL, 0);
03411     }
03412 
03413 }
03414 
03415 rb_pid_t
03416 rb_fork_ruby(int *status)
03417 {
03418     return rb_fork_internal(status, NULL, NULL, FALSE, Qnil, NULL, 0);
03419 }
03420 
03421 #endif
03422 
03423 #if defined(HAVE_FORK) && !defined(CANNOT_FORK_WITH_PTHREAD)
03424 /*
03425  *  call-seq:
03426  *     Kernel.fork  [{ block }]   -> fixnum or nil
03427  *     Process.fork [{ block }]   -> fixnum or nil
03428  *
03429  *  Creates a subprocess. If a block is specified, that block is run
03430  *  in the subprocess, and the subprocess terminates with a status of
03431  *  zero. Otherwise, the +fork+ call returns twice, once in
03432  *  the parent, returning the process ID of the child, and once in
03433  *  the child, returning _nil_. The child process can exit using
03434  *  <code>Kernel.exit!</code> to avoid running any
03435  *  <code>at_exit</code> functions. The parent process should
03436  *  use <code>Process.wait</code> to collect the termination statuses
03437  *  of its children or use <code>Process.detach</code> to register
03438  *  disinterest in their status; otherwise, the operating system
03439  *  may accumulate zombie processes.
03440  *
03441  *  The thread calling fork is the only thread in the created child process.
03442  *  fork doesn't copy other threads.
03443  *
03444  *  If fork is not usable, Process.respond_to?(:fork) returns false.
03445  */
03446 
03447 static VALUE
03448 rb_f_fork(VALUE obj)
03449 {
03450     rb_pid_t pid;
03451 
03452     rb_secure(2);
03453 
03454     switch (pid = rb_fork_ruby(NULL)) {
03455       case 0:
03456         rb_thread_atfork();
03457         if (rb_block_given_p()) {
03458             int status;
03459 
03460             rb_protect(rb_yield, Qundef, &status);
03461             ruby_stop(status);
03462         }
03463         return Qnil;
03464 
03465       case -1:
03466         rb_sys_fail("fork(2)");
03467         return Qnil;
03468 
03469       default:
03470         return PIDT2NUM(pid);
03471     }
03472 }
03473 #else
03474 #define rb_f_fork rb_f_notimplement
03475 #endif
03476 
03477 static int
03478 exit_status_code(VALUE status)
03479 {
03480     int istatus;
03481 
03482     switch (status) {
03483       case Qtrue:
03484         istatus = EXIT_SUCCESS;
03485         break;
03486       case Qfalse:
03487         istatus = EXIT_FAILURE;
03488         break;
03489       default:
03490         istatus = NUM2INT(status);
03491 #if EXIT_SUCCESS != 0
03492         if (istatus == 0)
03493             istatus = EXIT_SUCCESS;
03494 #endif
03495         break;
03496     }
03497     return istatus;
03498 }
03499 
03500 /*
03501  *  call-seq:
03502  *     Process.exit!(status=false)
03503  *
03504  *  Exits the process immediately. No exit handlers are
03505  *  run. <em>status</em> is returned to the underlying system as the
03506  *  exit status.
03507  *
03508  *     Process.exit!(true)
03509  */
03510 
03511 static VALUE
03512 rb_f_exit_bang(int argc, VALUE *argv, VALUE obj)
03513 {
03514     VALUE status;
03515     int istatus;
03516 
03517     rb_secure(4);
03518     if (argc > 0 && rb_scan_args(argc, argv, "01", &status) == 1) {
03519         istatus = exit_status_code(status);
03520     }
03521     else {
03522         istatus = EXIT_FAILURE;
03523     }
03524     _exit(istatus);
03525 
03526     UNREACHABLE;
03527 }
03528 
03529 void
03530 rb_exit(int status)
03531 {
03532     if (GET_THREAD()->tag) {
03533         VALUE args[2];
03534 
03535         args[0] = INT2NUM(status);
03536         args[1] = rb_str_new2("exit");
03537         rb_exc_raise(rb_class_new_instance(2, args, rb_eSystemExit));
03538     }
03539     ruby_finalize();
03540     exit(status);
03541 }
03542 
03543 
03544 /*
03545  *  call-seq:
03546  *     exit(status=true)
03547  *     Kernel::exit(status=true)
03548  *     Process::exit(status=true)
03549  *
03550  *  Initiates the termination of the Ruby script by raising the
03551  *  <code>SystemExit</code> exception. This exception may be caught. The
03552  *  optional parameter is used to return a status code to the invoking
03553  *  environment.
03554  *  +true+ and +FALSE+ of _status_ means success and failure
03555  *  respectively.  The interpretation of other integer values are
03556  *  system dependent.
03557  *
03558  *     begin
03559  *       exit
03560  *       puts "never get here"
03561  *     rescue SystemExit
03562  *       puts "rescued a SystemExit exception"
03563  *     end
03564  *     puts "after begin block"
03565  *
03566  *  <em>produces:</em>
03567  *
03568  *     rescued a SystemExit exception
03569  *     after begin block
03570  *
03571  *  Just prior to termination, Ruby executes any <code>at_exit</code> functions
03572  *  (see Kernel::at_exit) and runs any object finalizers (see
03573  *  ObjectSpace::define_finalizer).
03574  *
03575  *     at_exit { puts "at_exit function" }
03576  *     ObjectSpace.define_finalizer("string",  proc { puts "in finalizer" })
03577  *     exit
03578  *
03579  *  <em>produces:</em>
03580  *
03581  *     at_exit function
03582  *     in finalizer
03583  */
03584 
03585 VALUE
03586 rb_f_exit(int argc, VALUE *argv)
03587 {
03588     VALUE status;
03589     int istatus;
03590 
03591     rb_secure(4);
03592     if (argc > 0 && rb_scan_args(argc, argv, "01", &status) == 1) {
03593         istatus = exit_status_code(status);
03594     }
03595     else {
03596         istatus = EXIT_SUCCESS;
03597     }
03598     rb_exit(istatus);
03599 
03600     UNREACHABLE;
03601 }
03602 
03603 
03604 /*
03605  *  call-seq:
03606  *     abort
03607  *     Kernel::abort([msg])
03608  *     Process::abort([msg])
03609  *
03610  *  Terminate execution immediately, effectively by calling
03611  *  <code>Kernel.exit(false)</code>. If _msg_ is given, it is written
03612  *  to STDERR prior to terminating.
03613  */
03614 
03615 VALUE
03616 rb_f_abort(int argc, VALUE *argv)
03617 {
03618     rb_secure(4);
03619     if (argc == 0) {
03620         if (!NIL_P(GET_THREAD()->errinfo)) {
03621             ruby_error_print();
03622         }
03623         rb_exit(EXIT_FAILURE);
03624     }
03625     else {
03626         VALUE args[2];
03627 
03628         rb_scan_args(argc, argv, "1", &args[1]);
03629         StringValue(argv[0]);
03630         rb_io_puts(argc, argv, rb_stderr);
03631         args[0] = INT2NUM(EXIT_FAILURE);
03632         rb_exc_raise(rb_class_new_instance(2, args, rb_eSystemExit));
03633     }
03634 
03635     UNREACHABLE;
03636 }
03637 
03638 void
03639 rb_syswait(rb_pid_t pid)
03640 {
03641     int status;
03642 
03643     rb_waitpid(pid, &status, 0);
03644 }
03645 
03646 static rb_pid_t
03647 rb_spawn_process(struct rb_execarg *eargp, char *errmsg, size_t errmsg_buflen)
03648 {
03649     rb_pid_t pid;
03650 #if !USE_SPAWNV
03651     int status;
03652 #endif
03653 #if !defined HAVE_FORK || USE_SPAWNV
03654     VALUE prog;
03655     struct rb_execarg sarg;
03656 #endif
03657 
03658 #if defined HAVE_FORK && !USE_SPAWNV
03659     pid = rb_fork_async_signal_safe(&status, rb_exec_atfork, eargp, eargp->redirect_fds, errmsg, errmsg_buflen);
03660 #else
03661     prog = eargp->use_shell ? eargp->invoke.sh.shell_script : eargp->invoke.cmd.command_name;
03662 
03663     if (rb_execarg_run_options(eargp, &sarg, errmsg, errmsg_buflen) < 0) {
03664         return -1;
03665     }
03666 
03667     if (prog && !eargp->use_shell) {
03668         char **argv = ARGVSTR2ARGV(eargp->invoke.cmd.argv_str);
03669         argv[0] = RSTRING_PTR(prog);
03670     }
03671 # if defined HAVE_SPAWNV
03672     if (eargp->use_shell) {
03673         pid = proc_spawn_sh(RSTRING_PTR(prog));
03674     }
03675     else {
03676         char **argv = ARGVSTR2ARGV(eargp->invoke.cmd.argv_str);
03677         pid = proc_spawn_cmd(argv, prog, eargp);
03678     }
03679 #  if defined(_WIN32)
03680     if (pid == -1)
03681         rb_last_status_set(0x7f << 8, 0);
03682 #  endif
03683 # else
03684     if (!eargp->use_shell) {
03685         char **argv = ARGVSTR2ARGV(eargp->invoke.cmd.argv_str);
03686         int argc = ARGVSTR2ARGC(eargp->invoke.cmd.argv_str);
03687         prog = rb_ary_join(rb_ary_new4(argc, argv), rb_str_new2(" "));
03688     }
03689     status = system(StringValuePtr(prog));
03690     rb_last_status_set((status & 0xff) << 8, 0);
03691 # endif
03692 
03693     rb_execarg_run_options(&sarg, NULL, errmsg, errmsg_buflen);
03694 #endif
03695     return pid;
03696 }
03697 
03698 static rb_pid_t
03699 rb_spawn_internal(int argc, VALUE *argv, char *errmsg, size_t errmsg_buflen)
03700 {
03701     VALUE execarg_obj;
03702     struct rb_execarg *eargp;
03703     rb_pid_t ret;
03704 
03705     execarg_obj = rb_execarg_new(argc, argv, TRUE);
03706     eargp = rb_execarg_get(execarg_obj);
03707     rb_execarg_fixup(execarg_obj);
03708     ret = rb_spawn_process(eargp, errmsg, errmsg_buflen);
03709     RB_GC_GUARD(execarg_obj);
03710     return ret;
03711 }
03712 
03713 rb_pid_t
03714 rb_spawn_err(int argc, VALUE *argv, char *errmsg, size_t errmsg_buflen)
03715 {
03716     return rb_spawn_internal(argc, argv, errmsg, errmsg_buflen);
03717 }
03718 
03719 rb_pid_t
03720 rb_spawn(int argc, VALUE *argv)
03721 {
03722     return rb_spawn_internal(argc, argv, NULL, 0);
03723 }
03724 
03725 /*
03726  *  call-seq:
03727  *     system([env,] command... [,options])    -> true, false or nil
03728  *
03729  *  Executes _command..._ in a subshell.
03730  *  _command..._ is one of following forms.
03731  *
03732  *    commandline                 : command line string which is passed to the standard shell
03733  *    cmdname, arg1, ...          : command name and one or more arguments (no shell)
03734  *    [cmdname, argv0], arg1, ... : command name, argv[0] and zero or more arguments (no shell)
03735  *
03736  *  system returns +true+ if the command gives zero exit status,
03737  *  +false+ for non zero exit status.
03738  *  Returns +nil+ if command execution fails.
03739  *  An error status is available in <code>$?</code>.
03740  *  The arguments are processed in the same way as
03741  *  for <code>Kernel.spawn</code>.
03742  *
03743  *  The hash arguments, env and options, are same as
03744  *  <code>exec</code> and <code>spawn</code>.
03745  *  See <code>Kernel.spawn</code> for details.
03746  *
03747  *     system("echo *")
03748  *     system("echo", "*")
03749  *
03750  *  <em>produces:</em>
03751  *
03752  *     config.h main.rb
03753  *     *
03754  *
03755  *  See <code>Kernel.exec</code> for the standard shell.
03756  */
03757 
03758 static VALUE
03759 rb_f_system(int argc, VALUE *argv)
03760 {
03761     rb_pid_t pid;
03762     int status;
03763 
03764 #if defined(SIGCLD) && !defined(SIGCHLD)
03765 # define SIGCHLD SIGCLD
03766 #endif
03767 
03768 #ifdef SIGCHLD
03769     RETSIGTYPE (*chfunc)(int);
03770 
03771     rb_last_status_clear();
03772     chfunc = signal(SIGCHLD, SIG_DFL);
03773 #endif
03774     pid = rb_spawn_internal(argc, argv, NULL, 0);
03775 #if defined(HAVE_FORK) || defined(HAVE_SPAWNV)
03776     if (pid > 0) {
03777         int ret, status;
03778         ret = rb_waitpid(pid, &status, 0);
03779         if (ret == (rb_pid_t)-1)
03780             rb_sys_fail("Another thread waited the process started by system().");
03781     }
03782 #endif
03783 #ifdef SIGCHLD
03784     signal(SIGCHLD, chfunc);
03785 #endif
03786     if (pid < 0) {
03787         return Qnil;
03788     }
03789     status = PST2INT(rb_last_status_get());
03790     if (status == EXIT_SUCCESS) return Qtrue;
03791     return Qfalse;
03792 }
03793 
03794 /*
03795  *  call-seq:
03796  *     spawn([env,] command... [,options])     -> pid
03797  *     Process.spawn([env,] command... [,options])     -> pid
03798  *
03799  *  spawn executes specified command and return its pid.
03800  *
03801  *  This method doesn't wait for end of the command.
03802  *  The parent process should
03803  *  use <code>Process.wait</code> to collect
03804  *  the termination status of its child or
03805  *  use <code>Process.detach</code> to register
03806  *  disinterest in their status;
03807  *  otherwise, the operating system may accumulate zombie processes.
03808  *
03809  *  spawn has bunch of options to specify process attributes:
03810  *
03811  *    env: hash
03812  *      name => val : set the environment variable
03813  *      name => nil : unset the environment variable
03814  *    command...:
03815  *      commandline                 : command line string which is passed to the standard shell
03816  *      cmdname, arg1, ...          : command name and one or more arguments (no shell)
03817  *      [cmdname, argv0], arg1, ... : command name, argv[0] and zero or more arguments (no shell)
03818  *    options: hash
03819  *      clearing environment variables:
03820  *        :unsetenv_others => true   : clear environment variables except specified by env
03821  *        :unsetenv_others => false  : don't clear (default)
03822  *      process group:
03823  *        :pgroup => true or 0 : make a new process group
03824  *        :pgroup => pgid      : join to specified process group
03825  *        :pgroup => nil       : don't change the process group (default)
03826  *      create new process group: Windows only
03827  *        :new_pgroup => true  : the new process is the root process of a new process group
03828  *        :new_pgroup => false : don't create a new process group (default)
03829  *      resource limit: resourcename is core, cpu, data, etc.  See Process.setrlimit.
03830  *        :rlimit_resourcename => limit
03831  *        :rlimit_resourcename => [cur_limit, max_limit]
03832  *      umask:
03833  *        :umask => int
03834  *      redirection:
03835  *        key:
03836  *          FD              : single file descriptor in child process
03837  *          [FD, FD, ...]   : multiple file descriptor in child process
03838  *        value:
03839  *          FD                        : redirect to the file descriptor in parent process
03840  *          string                    : redirect to file with open(string, "r" or "w")
03841  *          [string]                  : redirect to file with open(string, File::RDONLY)
03842  *          [string, open_mode]       : redirect to file with open(string, open_mode, 0644)
03843  *          [string, open_mode, perm] : redirect to file with open(string, open_mode, perm)
03844  *          [:child, FD]              : redirect to the redirected file descriptor
03845  *          :close                    : close the file descriptor in child process
03846  *        FD is one of follows
03847  *          :in     : the file descriptor 0 which is the standard input
03848  *          :out    : the file descriptor 1 which is the standard output
03849  *          :err    : the file descriptor 2 which is the standard error
03850  *          integer : the file descriptor of specified the integer
03851  *          io      : the file descriptor specified as io.fileno
03852  *      file descriptor inheritance: close non-redirected non-standard fds (3, 4, 5, ...) or not
03853  *        :close_others => true  : don't inherit
03854  *      current directory:
03855  *        :chdir => str
03856  *
03857  *  If a hash is given as +env+, the environment is
03858  *  updated by +env+ before <code>exec(2)</code> in the child process.
03859  *  If a pair in +env+ has nil as the value, the variable is deleted.
03860  *
03861  *    # set FOO as BAR and unset BAZ.
03862  *    pid = spawn({"FOO"=>"BAR", "BAZ"=>nil}, command)
03863  *
03864  *  If a hash is given as +options+,
03865  *  it specifies
03866  *  process group,
03867  *  create new process group,
03868  *  resource limit,
03869  *  current directory,
03870  *  umask and
03871  *  redirects for the child process.
03872  *  Also, it can be specified to clear environment variables.
03873  *
03874  *  The <code>:unsetenv_others</code> key in +options+ specifies
03875  *  to clear environment variables, other than specified by +env+.
03876  *
03877  *    pid = spawn(command, :unsetenv_others=>true) # no environment variable
03878  *    pid = spawn({"FOO"=>"BAR"}, command, :unsetenv_others=>true) # FOO only
03879  *
03880  *  The <code>:pgroup</code> key in +options+ specifies a process group.
03881  *  The corresponding value should be true, zero or positive integer.
03882  *  true and zero means the process should be a process leader of a new
03883  *  process group.
03884  *  Other values specifies a process group to be belongs.
03885  *
03886  *    pid = spawn(command, :pgroup=>true) # process leader
03887  *    pid = spawn(command, :pgroup=>10) # belongs to the process group 10
03888  *
03889  *  The <code>:new_pgroup</code> key in +options+ specifies to pass
03890  *  +CREATE_NEW_PROCESS_GROUP+ flag to <code>CreateProcessW()</code> that is
03891  *  Windows API. This option is only for Windows.
03892  *  true means the new process is the root process of the new process group.
03893  *  The new process has CTRL+C disabled. This flag is necessary for
03894  *  <code>Process.kill(:SIGINT, pid)</code> on the subprocess.
03895  *  :new_pgroup is false by default.
03896  *
03897  *    pid = spawn(command, :new_pgroup=>true)  # new process group
03898  *    pid = spawn(command, :new_pgroup=>false) # same process group
03899  *
03900  *  The <code>:rlimit_</code><em>foo</em> key specifies a resource limit.
03901  *  <em>foo</em> should be one of resource types such as <code>core</code>.
03902  *  The corresponding value should be an integer or an array which have one or
03903  *  two integers: same as cur_limit and max_limit arguments for
03904  *  Process.setrlimit.
03905  *
03906  *    cur, max = Process.getrlimit(:CORE)
03907  *    pid = spawn(command, :rlimit_core=>[0,max]) # disable core temporary.
03908  *    pid = spawn(command, :rlimit_core=>max) # enable core dump
03909  *    pid = spawn(command, :rlimit_core=>0) # never dump core.
03910  *
03911  *  The <code>:umask</code> key in +options+ specifies the umask.
03912  *
03913  *    pid = spawn(command, :umask=>077)
03914  *
03915  *  The :in, :out, :err, a fixnum, an IO and an array key specifies a redirection.
03916  *  The redirection maps a file descriptor in the child process.
03917  *
03918  *  For example, stderr can be merged into stdout as follows:
03919  *
03920  *    pid = spawn(command, :err=>:out)
03921  *    pid = spawn(command, 2=>1)
03922  *    pid = spawn(command, STDERR=>:out)
03923  *    pid = spawn(command, STDERR=>STDOUT)
03924  *
03925  *  The hash keys specifies a file descriptor
03926  *  in the child process started by <code>spawn</code>.
03927  *  :err, 2 and STDERR specifies the standard error stream (stderr).
03928  *
03929  *  The hash values specifies a file descriptor
03930  *  in the parent process which invokes <code>spawn</code>.
03931  *  :out, 1 and STDOUT specifies the standard output stream (stdout).
03932  *
03933  *  In the above example,
03934  *  the standard output in the child process is not specified.
03935  *  So it is inherited from the parent process.
03936  *
03937  *  The standard input stream (stdin) can be specified by :in, 0 and STDIN.
03938  *
03939  *  A filename can be specified as a hash value.
03940  *
03941  *    pid = spawn(command, :in=>"/dev/null") # read mode
03942  *    pid = spawn(command, :out=>"/dev/null") # write mode
03943  *    pid = spawn(command, :err=>"log") # write mode
03944  *    pid = spawn(command, 3=>"/dev/null") # read mode
03945  *
03946  *  For stdout and stderr,
03947  *  it is opened in write mode.
03948  *  Otherwise read mode is used.
03949  *
03950  *  For specifying flags and permission of file creation explicitly,
03951  *  an array is used instead.
03952  *
03953  *    pid = spawn(command, :in=>["file"]) # read mode is assumed
03954  *    pid = spawn(command, :in=>["file", "r"])
03955  *    pid = spawn(command, :out=>["log", "w"]) # 0644 assumed
03956  *    pid = spawn(command, :out=>["log", "w", 0600])
03957  *    pid = spawn(command, :out=>["log", File::WRONLY|File::EXCL|File::CREAT, 0600])
03958  *
03959  *  The array specifies a filename, flags and permission.
03960  *  The flags can be a string or an integer.
03961  *  If the flags is omitted or nil, File::RDONLY is assumed.
03962  *  The permission should be an integer.
03963  *  If the permission is omitted or nil, 0644 is assumed.
03964  *
03965  *  If an array of IOs and integers are specified as a hash key,
03966  *  all the elements are redirected.
03967  *
03968  *    # stdout and stderr is redirected to log file.
03969  *    # The file "log" is opened just once.
03970  *    pid = spawn(command, [:out, :err]=>["log", "w"])
03971  *
03972  *  Another way to merge multiple file descriptors is [:child, fd].
03973  *  \[:child, fd] means the file descriptor in the child process.
03974  *  This is different from fd.
03975  *  For example, :err=>:out means redirecting child stderr to parent stdout.
03976  *  But :err=>[:child, :out] means redirecting child stderr to child stdout.
03977  *  They differ if stdout is redirected in the child process as follows.
03978  *
03979  *    # stdout and stderr is redirected to log file.
03980  *    # The file "log" is opened just once.
03981  *    pid = spawn(command, :out=>["log", "w"], :err=>[:child, :out])
03982  *
03983  *  \[:child, :out] can be used to merge stderr into stdout in IO.popen.
03984  *  In this case, IO.popen redirects stdout to a pipe in the child process
03985  *  and [:child, :out] refers the redirected stdout.
03986  *
03987  *    io = IO.popen(["sh", "-c", "echo out; echo err >&2", :err=>[:child, :out]])
03988  *    p io.read #=> "out\nerr\n"
03989  *
03990  *  The <code>:chdir</code> key in +options+ specifies the current directory.
03991  *
03992  *    pid = spawn(command, :chdir=>"/var/tmp")
03993  *
03994  *  spawn closes all non-standard unspecified descriptors by default.
03995  *  The "standard" descriptors are 0, 1 and 2.
03996  *  This behavior is specified by :close_others option.
03997  *  :close_others doesn't affect the standard descriptors which are
03998  *  closed only if :close is specified explicitly.
03999  *
04000  *    pid = spawn(command, :close_others=>true)  # close 3,4,5,... (default)
04001  *    pid = spawn(command, :close_others=>false) # don't close 3,4,5,...
04002  *
04003  *  :close_others is true by default for spawn and IO.popen.
04004  *
04005  *  Note that fds which close-on-exec flag is already set are closed
04006  *  regardless of :close_others option.
04007  *
04008  *  So IO.pipe and spawn can be used as IO.popen.
04009  *
04010  *    # similar to r = IO.popen(command)
04011  *    r, w = IO.pipe
04012  *    pid = spawn(command, :out=>w)   # r, w is closed in the child process.
04013  *    w.close
04014  *
04015  *  :close is specified as a hash value to close a fd individually.
04016  *
04017  *    f = open(foo)
04018  *    system(command, f=>:close)        # don't inherit f.
04019  *
04020  *  If a file descriptor need to be inherited,
04021  *  io=>io can be used.
04022  *
04023  *    # valgrind has --log-fd option for log destination.
04024  *    # log_w=>log_w indicates log_w.fileno inherits to child process.
04025  *    log_r, log_w = IO.pipe
04026  *    pid = spawn("valgrind", "--log-fd=#{log_w.fileno}", "echo", "a", log_w=>log_w)
04027  *    log_w.close
04028  *    p log_r.read
04029  *
04030  *  It is also possible to exchange file descriptors.
04031  *
04032  *    pid = spawn(command, :out=>:err, :err=>:out)
04033  *
04034  *  The hash keys specify file descriptors in the child process.
04035  *  The hash values specifies file descriptors in the parent process.
04036  *  So the above specifies exchanging stdout and stderr.
04037  *  Internally, +spawn+ uses an extra file descriptor to resolve such cyclic
04038  *  file descriptor mapping.
04039  *
04040  *  See <code>Kernel.exec</code> for the standard shell.
04041  */
04042 
04043 static VALUE
04044 rb_f_spawn(int argc, VALUE *argv)
04045 {
04046     rb_pid_t pid;
04047     char errmsg[CHILD_ERRMSG_BUFLEN] = { '\0' };
04048     VALUE execarg_obj, fail_str;
04049     struct rb_execarg *eargp;
04050 
04051     execarg_obj = rb_execarg_new(argc, argv, TRUE);
04052     eargp = rb_execarg_get(execarg_obj);
04053     rb_execarg_fixup(execarg_obj);
04054     fail_str = eargp->use_shell ? eargp->invoke.sh.shell_script : eargp->invoke.cmd.command_name;
04055 
04056     pid = rb_spawn_process(eargp, errmsg, sizeof(errmsg));
04057     RB_GC_GUARD(execarg_obj);
04058 
04059     if (pid == -1) {
04060         const char *prog = errmsg;
04061         if (!prog[0]) {
04062             rb_sys_fail_str(fail_str);
04063         }
04064         rb_sys_fail(prog);
04065     }
04066 #if defined(HAVE_FORK) || defined(HAVE_SPAWNV)
04067     return PIDT2NUM(pid);
04068 #else
04069     return Qnil;
04070 #endif
04071 }
04072 
04073 /*
04074  *  call-seq:
04075  *     sleep([duration])    -> fixnum
04076  *
04077  *  Suspends the current thread for _duration_ seconds (which may be any number,
04078  *  including a +Float+ with fractional seconds). Returns the actual number of
04079  *  seconds slept (rounded), which may be less than that asked for if another
04080  *  thread calls <code>Thread#run</code>. Called without an argument, sleep()
04081  *  will sleep forever.
04082  *
04083  *     Time.new    #=> 2008-03-08 19:56:19 +0900
04084  *     sleep 1.2   #=> 1
04085  *     Time.new    #=> 2008-03-08 19:56:20 +0900
04086  *     sleep 1.9   #=> 2
04087  *     Time.new    #=> 2008-03-08 19:56:22 +0900
04088  */
04089 
04090 static VALUE
04091 rb_f_sleep(int argc, VALUE *argv)
04092 {
04093     time_t beg, end;
04094 
04095     beg = time(0);
04096     if (argc == 0) {
04097         rb_thread_sleep_forever();
04098     }
04099     else {
04100         rb_check_arity(argc, 0, 1);
04101         rb_thread_wait_for(rb_time_interval(argv[0]));
04102     }
04103 
04104     end = time(0) - beg;
04105 
04106     return INT2FIX(end);
04107 }
04108 
04109 
04110 #if (defined(HAVE_GETPGRP) && defined(GETPGRP_VOID)) || defined(HAVE_GETPGID)
04111 /*
04112  *  call-seq:
04113  *     Process.getpgrp   -> integer
04114  *
04115  *  Returns the process group ID for this process. Not available on
04116  *  all platforms.
04117  *
04118  *     Process.getpgid(0)   #=> 25527
04119  *     Process.getpgrp      #=> 25527
04120  */
04121 
04122 static VALUE
04123 proc_getpgrp(void)
04124 {
04125     rb_pid_t pgrp;
04126 
04127     rb_secure(2);
04128 #if defined(HAVE_GETPGRP) && defined(GETPGRP_VOID)
04129     pgrp = getpgrp();
04130     if (pgrp < 0) rb_sys_fail(0);
04131     return PIDT2NUM(pgrp);
04132 #else /* defined(HAVE_GETPGID) */
04133     pgrp = getpgid(0);
04134     if (pgrp < 0) rb_sys_fail(0);
04135     return PIDT2NUM(pgrp);
04136 #endif
04137 }
04138 #else
04139 #define proc_getpgrp rb_f_notimplement
04140 #endif
04141 
04142 
04143 #if defined(HAVE_SETPGID) || (defined(HAVE_SETPGRP) && defined(SETPGRP_VOID))
04144 /*
04145  *  call-seq:
04146  *     Process.setpgrp   -> 0
04147  *
04148  *  Equivalent to <code>setpgid(0,0)</code>. Not available on all
04149  *  platforms.
04150  */
04151 
04152 static VALUE
04153 proc_setpgrp(void)
04154 {
04155     rb_secure(2);
04156   /* check for posix setpgid() first; this matches the posix */
04157   /* getpgrp() above.  It appears that configure will set SETPGRP_VOID */
04158   /* even though setpgrp(0,0) would be preferred. The posix call avoids */
04159   /* this confusion. */
04160 #ifdef HAVE_SETPGID
04161     if (setpgid(0,0) < 0) rb_sys_fail(0);
04162 #elif defined(HAVE_SETPGRP) && defined(SETPGRP_VOID)
04163     if (setpgrp() < 0) rb_sys_fail(0);
04164 #endif
04165     return INT2FIX(0);
04166 }
04167 #else
04168 #define proc_setpgrp rb_f_notimplement
04169 #endif
04170 
04171 
04172 #if defined(HAVE_GETPGID)
04173 /*
04174  *  call-seq:
04175  *     Process.getpgid(pid)   -> integer
04176  *
04177  *  Returns the process group ID for the given process id. Not
04178  *  available on all platforms.
04179  *
04180  *     Process.getpgid(Process.ppid())   #=> 25527
04181  */
04182 
04183 static VALUE
04184 proc_getpgid(VALUE obj, VALUE pid)
04185 {
04186     rb_pid_t i;
04187 
04188     rb_secure(2);
04189     i = getpgid(NUM2PIDT(pid));
04190     if (i < 0) rb_sys_fail(0);
04191     return PIDT2NUM(i);
04192 }
04193 #else
04194 #define proc_getpgid rb_f_notimplement
04195 #endif
04196 
04197 
04198 #ifdef HAVE_SETPGID
04199 /*
04200  *  call-seq:
04201  *     Process.setpgid(pid, integer)   -> 0
04202  *
04203  *  Sets the process group ID of _pid_ (0 indicates this
04204  *  process) to <em>integer</em>. Not available on all platforms.
04205  */
04206 
04207 static VALUE
04208 proc_setpgid(VALUE obj, VALUE pid, VALUE pgrp)
04209 {
04210     rb_pid_t ipid, ipgrp;
04211 
04212     rb_secure(2);
04213     ipid = NUM2PIDT(pid);
04214     ipgrp = NUM2PIDT(pgrp);
04215 
04216     if (setpgid(ipid, ipgrp) < 0) rb_sys_fail(0);
04217     return INT2FIX(0);
04218 }
04219 #else
04220 #define proc_setpgid rb_f_notimplement
04221 #endif
04222 
04223 
04224 #ifdef HAVE_GETSID
04225 /*
04226  *  call-seq:
04227  *     Process.getsid()      -> integer
04228  *     Process.getsid(pid)   -> integer
04229  *
04230  *  Returns the session ID for for the given process id. If not give,
04231  *  return current process sid. Not available on all platforms.
04232  *
04233  *     Process.getsid()                #=> 27422
04234  *     Process.getsid(0)               #=> 27422
04235  *     Process.getsid(Process.pid())   #=> 27422
04236  */
04237 static VALUE
04238 proc_getsid(int argc, VALUE *argv)
04239 {
04240     rb_pid_t sid;
04241     VALUE pid;
04242 
04243     rb_secure(2);
04244     rb_scan_args(argc, argv, "01", &pid);
04245 
04246     if (NIL_P(pid))
04247         pid = INT2NUM(0);
04248 
04249     sid = getsid(NUM2PIDT(pid));
04250     if (sid < 0) rb_sys_fail(0);
04251     return PIDT2NUM(sid);
04252 }
04253 #else
04254 #define proc_getsid rb_f_notimplement
04255 #endif
04256 
04257 
04258 #if defined(HAVE_SETSID) || (defined(HAVE_SETPGRP) && defined(TIOCNOTTY))
04259 #if !defined(HAVE_SETSID)
04260 static rb_pid_t ruby_setsid(void);
04261 #define setsid() ruby_setsid()
04262 #endif
04263 /*
04264  *  call-seq:
04265  *     Process.setsid   -> fixnum
04266  *
04267  *  Establishes this process as a new session and process group
04268  *  leader, with no controlling tty. Returns the session id. Not
04269  *  available on all platforms.
04270  *
04271  *     Process.setsid   #=> 27422
04272  */
04273 
04274 static VALUE
04275 proc_setsid(void)
04276 {
04277     rb_pid_t pid;
04278 
04279     rb_secure(2);
04280     pid = setsid();
04281     if (pid < 0) rb_sys_fail(0);
04282     return PIDT2NUM(pid);
04283 }
04284 
04285 #if !defined(HAVE_SETSID)
04286 #define HAVE_SETSID 1
04287 static rb_pid_t
04288 ruby_setsid(void)
04289 {
04290     rb_pid_t pid;
04291     int ret;
04292 
04293     pid = getpid();
04294 #if defined(SETPGRP_VOID)
04295     ret = setpgrp();
04296     /* If `pid_t setpgrp(void)' is equivalent to setsid(),
04297        `ret' will be the same value as `pid', and following open() will fail.
04298        In Linux, `int setpgrp(void)' is equivalent to setpgid(0, 0). */
04299 #else
04300     ret = setpgrp(0, pid);
04301 #endif
04302     if (ret == -1) return -1;
04303 
04304     if ((fd = rb_cloexec_open("/dev/tty", O_RDWR, 0)) >= 0) {
04305         rb_update_max_fd(fd);
04306         ioctl(fd, TIOCNOTTY, NULL);
04307         close(fd);
04308     }
04309     return pid;
04310 }
04311 #endif
04312 #else
04313 #define proc_setsid rb_f_notimplement
04314 #endif
04315 
04316 
04317 #ifdef HAVE_GETPRIORITY
04318 /*
04319  *  call-seq:
04320  *     Process.getpriority(kind, integer)   -> fixnum
04321  *
04322  *  Gets the scheduling priority for specified process, process group,
04323  *  or user. <em>kind</em> indicates the kind of entity to find: one
04324  *  of <code>Process::PRIO_PGRP</code>,
04325  *  <code>Process::PRIO_USER</code>, or
04326  *  <code>Process::PRIO_PROCESS</code>. _integer_ is an id
04327  *  indicating the particular process, process group, or user (an id
04328  *  of 0 means _current_). Lower priorities are more favorable
04329  *  for scheduling. Not available on all platforms.
04330  *
04331  *     Process.getpriority(Process::PRIO_USER, 0)      #=> 19
04332  *     Process.getpriority(Process::PRIO_PROCESS, 0)   #=> 19
04333  */
04334 
04335 static VALUE
04336 proc_getpriority(VALUE obj, VALUE which, VALUE who)
04337 {
04338     int prio, iwhich, iwho;
04339 
04340     rb_secure(2);
04341     iwhich = NUM2INT(which);
04342     iwho   = NUM2INT(who);
04343 
04344     errno = 0;
04345     prio = getpriority(iwhich, iwho);
04346     if (errno) rb_sys_fail(0);
04347     return INT2FIX(prio);
04348 }
04349 #else
04350 #define proc_getpriority rb_f_notimplement
04351 #endif
04352 
04353 
04354 #ifdef HAVE_GETPRIORITY
04355 /*
04356  *  call-seq:
04357  *     Process.setpriority(kind, integer, priority)   -> 0
04358  *
04359  *  See <code>Process#getpriority</code>.
04360  *
04361  *     Process.setpriority(Process::PRIO_USER, 0, 19)      #=> 0
04362  *     Process.setpriority(Process::PRIO_PROCESS, 0, 19)   #=> 0
04363  *     Process.getpriority(Process::PRIO_USER, 0)          #=> 19
04364  *     Process.getpriority(Process::PRIO_PROCESS, 0)       #=> 19
04365  */
04366 
04367 static VALUE
04368 proc_setpriority(VALUE obj, VALUE which, VALUE who, VALUE prio)
04369 {
04370     int iwhich, iwho, iprio;
04371 
04372     rb_secure(2);
04373     iwhich = NUM2INT(which);
04374     iwho   = NUM2INT(who);
04375     iprio  = NUM2INT(prio);
04376 
04377     if (setpriority(iwhich, iwho, iprio) < 0)
04378         rb_sys_fail(0);
04379     return INT2FIX(0);
04380 }
04381 #else
04382 #define proc_setpriority rb_f_notimplement
04383 #endif
04384 
04385 #if defined(HAVE_SETRLIMIT) && defined(NUM2RLIM)
04386 static int
04387 rlimit_resource_name2int(const char *name, int casetype)
04388 {
04389     int resource;
04390     const char *p;
04391 #define RESCHECK(r) \
04392     do { \
04393         if (STRCASECMP(name, #r) == 0) { \
04394             resource = RLIMIT_##r; \
04395             goto found; \
04396         } \
04397     } while (0)
04398 
04399     switch (TOUPPER(*name)) {
04400       case 'A':
04401 #ifdef RLIMIT_AS
04402         RESCHECK(AS);
04403 #endif
04404         break;
04405 
04406       case 'C':
04407 #ifdef RLIMIT_CORE
04408         RESCHECK(CORE);
04409 #endif
04410 #ifdef RLIMIT_CPU
04411         RESCHECK(CPU);
04412 #endif
04413         break;
04414 
04415       case 'D':
04416 #ifdef RLIMIT_DATA
04417         RESCHECK(DATA);
04418 #endif
04419         break;
04420 
04421       case 'F':
04422 #ifdef RLIMIT_FSIZE
04423         RESCHECK(FSIZE);
04424 #endif
04425         break;
04426 
04427       case 'M':
04428 #ifdef RLIMIT_MEMLOCK
04429         RESCHECK(MEMLOCK);
04430 #endif
04431 #ifdef RLIMIT_MSGQUEUE
04432         RESCHECK(MSGQUEUE);
04433 #endif
04434         break;
04435 
04436       case 'N':
04437 #ifdef RLIMIT_NOFILE
04438         RESCHECK(NOFILE);
04439 #endif
04440 #ifdef RLIMIT_NPROC
04441         RESCHECK(NPROC);
04442 #endif
04443 #ifdef RLIMIT_NICE
04444         RESCHECK(NICE);
04445 #endif
04446         break;
04447 
04448       case 'R':
04449 #ifdef RLIMIT_RSS
04450         RESCHECK(RSS);
04451 #endif
04452 #ifdef RLIMIT_RTPRIO
04453         RESCHECK(RTPRIO);
04454 #endif
04455 #ifdef RLIMIT_RTTIME
04456         RESCHECK(RTTIME);
04457 #endif
04458         break;
04459 
04460       case 'S':
04461 #ifdef RLIMIT_STACK
04462         RESCHECK(STACK);
04463 #endif
04464 #ifdef RLIMIT_SBSIZE
04465         RESCHECK(SBSIZE);
04466 #endif
04467 #ifdef RLIMIT_SIGPENDING
04468         RESCHECK(SIGPENDING);
04469 #endif
04470         break;
04471     }
04472     return -1;
04473 
04474   found:
04475     switch (casetype) {
04476       case 0:
04477         for (p = name; *p; p++)
04478             if (!ISUPPER(*p))
04479                 return -1;
04480         break;
04481 
04482       case 1:
04483         for (p = name; *p; p++)
04484             if (!ISLOWER(*p))
04485                 return -1;
04486         break;
04487 
04488       default:
04489         rb_bug("unexpected casetype");
04490     }
04491     return resource;
04492 #undef RESCHECK
04493 }
04494 
04495 static int
04496 rlimit_type_by_hname(const char *name)
04497 {
04498     return rlimit_resource_name2int(name, 0);
04499 }
04500 
04501 static int
04502 rlimit_type_by_lname(const char *name)
04503 {
04504     return rlimit_resource_name2int(name, 1);
04505 }
04506 
04507 static int
04508 rlimit_resource_type(VALUE rtype)
04509 {
04510     const char *name;
04511     VALUE v;
04512     int r;
04513 
04514     switch (TYPE(rtype)) {
04515       case T_SYMBOL:
04516         name = rb_id2name(SYM2ID(rtype));
04517         break;
04518 
04519       default:
04520         v = rb_check_string_type(rtype);
04521         if (!NIL_P(v)) {
04522             rtype = v;
04523       case T_STRING:
04524             name = StringValueCStr(rtype);
04525             break;
04526         }
04527         /* fall through */
04528 
04529       case T_FIXNUM:
04530       case T_BIGNUM:
04531         return NUM2INT(rtype);
04532     }
04533 
04534     r = rlimit_type_by_hname(name);
04535     if (r != -1)
04536         return r;
04537 
04538     rb_raise(rb_eArgError, "invalid resource name: %s", name);
04539 
04540     UNREACHABLE;
04541 }
04542 
04543 static rlim_t
04544 rlimit_resource_value(VALUE rval)
04545 {
04546     const char *name;
04547     VALUE v;
04548 
04549     switch (TYPE(rval)) {
04550       case T_SYMBOL:
04551         name = rb_id2name(SYM2ID(rval));
04552         break;
04553 
04554       default:
04555         v = rb_check_string_type(rval);
04556         if (!NIL_P(v)) {
04557             rval = v;
04558       case T_STRING:
04559             name = StringValueCStr(rval);
04560             break;
04561         }
04562         /* fall through */
04563 
04564       case T_FIXNUM:
04565       case T_BIGNUM:
04566         return NUM2RLIM(rval);
04567     }
04568 
04569 #ifdef RLIM_INFINITY
04570     if (strcmp(name, "INFINITY") == 0) return RLIM_INFINITY;
04571 #endif
04572 #ifdef RLIM_SAVED_MAX
04573     if (strcmp(name, "SAVED_MAX") == 0) return RLIM_SAVED_MAX;
04574 #endif
04575 #ifdef RLIM_SAVED_CUR
04576     if (strcmp(name, "SAVED_CUR") == 0) return RLIM_SAVED_CUR;
04577 #endif
04578     rb_raise(rb_eArgError, "invalid resource value: %s", name);
04579 
04580     UNREACHABLE;
04581 }
04582 #endif
04583 
04584 #if defined(HAVE_GETRLIMIT) && defined(RLIM2NUM)
04585 /*
04586  *  call-seq:
04587  *     Process.getrlimit(resource)   -> [cur_limit, max_limit]
04588  *
04589  *  Gets the resource limit of the process.
04590  *  _cur_limit_ means current (soft) limit and
04591  *  _max_limit_ means maximum (hard) limit.
04592  *
04593  *  _resource_ indicates the kind of resource to limit.
04594  *  It is specified as a symbol such as <code>:CORE</code>,
04595  *  a string such as <code>"CORE"</code> or
04596  *  a constant such as <code>Process::RLIMIT_CORE</code>.
04597  *  See Process.setrlimit for details.
04598  *
04599  *  _cur_limit_ and _max_limit_ may be <code>Process::RLIM_INFINITY</code>,
04600  *  <code>Process::RLIM_SAVED_MAX</code> or
04601  *  <code>Process::RLIM_SAVED_CUR</code>.
04602  *  See Process.setrlimit and the system getrlimit(2) manual for details.
04603  */
04604 
04605 static VALUE
04606 proc_getrlimit(VALUE obj, VALUE resource)
04607 {
04608     struct rlimit rlim;
04609 
04610     rb_secure(2);
04611 
04612     if (getrlimit(rlimit_resource_type(resource), &rlim) < 0) {
04613         rb_sys_fail("getrlimit");
04614     }
04615     return rb_assoc_new(RLIM2NUM(rlim.rlim_cur), RLIM2NUM(rlim.rlim_max));
04616 }
04617 #else
04618 #define proc_getrlimit rb_f_notimplement
04619 #endif
04620 
04621 #if defined(HAVE_SETRLIMIT) && defined(NUM2RLIM)
04622 /*
04623  *  call-seq:
04624  *     Process.setrlimit(resource, cur_limit, max_limit)        -> nil
04625  *     Process.setrlimit(resource, cur_limit)                   -> nil
04626  *
04627  *  Sets the resource limit of the process.
04628  *  _cur_limit_ means current (soft) limit and
04629  *  _max_limit_ means maximum (hard) limit.
04630  *
04631  *  If _max_limit_ is not given, _cur_limit_ is used.
04632  *
04633  *  _resource_ indicates the kind of resource to limit.
04634  *  It should be a symbol such as <code>:CORE</code>,
04635  *  a string such as <code>"CORE"</code> or
04636  *  a constant such as <code>Process::RLIMIT_CORE</code>.
04637  *  The available resources are OS dependent.
04638  *  Ruby may support following resources.
04639  *
04640  *  [AS] total available memory (bytes) (SUSv3, NetBSD, FreeBSD, OpenBSD but 4.4BSD-Lite)
04641  *  [CORE] core size (bytes) (SUSv3)
04642  *  [CPU] CPU time (seconds) (SUSv3)
04643  *  [DATA] data segment (bytes) (SUSv3)
04644  *  [FSIZE] file size (bytes) (SUSv3)
04645  *  [MEMLOCK] total size for mlock(2) (bytes) (4.4BSD, GNU/Linux)
04646  *  [MSGQUEUE] allocation for POSIX message queues (bytes) (GNU/Linux)
04647  *  [NICE] ceiling on process's nice(2) value (number) (GNU/Linux)
04648  *  [NOFILE] file descriptors (number) (SUSv3)
04649  *  [NPROC] number of processes for the user (number) (4.4BSD, GNU/Linux)
04650  *  [RSS] resident memory size (bytes) (4.2BSD, GNU/Linux)
04651  *  [RTPRIO] ceiling on the process's real-time priority (number) (GNU/Linux)
04652  *  [RTTIME] CPU time for real-time process (us) (GNU/Linux)
04653  *  [SBSIZE] all socket buffers (bytes) (NetBSD, FreeBSD)
04654  *  [SIGPENDING] number of queued signals allowed (signals) (GNU/Linux)
04655  *  [STACK] stack size (bytes) (SUSv3)
04656  *
04657  *  _cur_limit_ and _max_limit_ may be
04658  *  <code>:INFINITY</code>, <code>"INFINITY"</code> or
04659  *  <code>Process::RLIM_INFINITY</code>,
04660  *  which means that the resource is not limited.
04661  *  They may be <code>Process::RLIM_SAVED_MAX</code>,
04662  *  <code>Process::RLIM_SAVED_CUR</code> and
04663  *  corresponding symbols and strings too.
04664  *  See system setrlimit(2) manual for details.
04665  *
04666  *  The following example raises the soft limit of core size to
04667  *  the hard limit to try to make core dump possible.
04668  *
04669  *    Process.setrlimit(:CORE, Process.getrlimit(:CORE)[1])
04670  *
04671  */
04672 
04673 static VALUE
04674 proc_setrlimit(int argc, VALUE *argv, VALUE obj)
04675 {
04676     VALUE resource, rlim_cur, rlim_max;
04677     struct rlimit rlim;
04678 
04679     rb_secure(2);
04680 
04681     rb_scan_args(argc, argv, "21", &resource, &rlim_cur, &rlim_max);
04682     if (rlim_max == Qnil)
04683         rlim_max = rlim_cur;
04684 
04685     rlim.rlim_cur = rlimit_resource_value(rlim_cur);
04686     rlim.rlim_max = rlimit_resource_value(rlim_max);
04687 
04688     if (setrlimit(rlimit_resource_type(resource), &rlim) < 0) {
04689         rb_sys_fail("setrlimit");
04690     }
04691     return Qnil;
04692 }
04693 #else
04694 #define proc_setrlimit rb_f_notimplement
04695 #endif
04696 
04697 static int under_uid_switch = 0;
04698 static void
04699 check_uid_switch(void)
04700 {
04701     rb_secure(2);
04702     if (under_uid_switch) {
04703         rb_raise(rb_eRuntimeError, "can't handle UID while evaluating block given to Process::UID.switch method");
04704     }
04705 }
04706 
04707 static int under_gid_switch = 0;
04708 static void
04709 check_gid_switch(void)
04710 {
04711     rb_secure(2);
04712     if (under_gid_switch) {
04713         rb_raise(rb_eRuntimeError, "can't handle GID while evaluating block given to Process::UID.switch method");
04714     }
04715 }
04716 
04717 
04718 /*********************************************************************
04719  * Document-class: Process::Sys
04720  *
04721  *  The <code>Process::Sys</code> module contains UID and GID
04722  *  functions which provide direct bindings to the system calls of the
04723  *  same names instead of the more-portable versions of the same
04724  *  functionality found in the <code>Process</code>,
04725  *  <code>Process::UID</code>, and <code>Process::GID</code> modules.
04726  */
04727 
04728 #if defined(HAVE_PWD_H)
04729 static rb_uid_t
04730 obj2uid(VALUE id
04731 # ifdef USE_GETPWNAM_R
04732         , char *getpw_buf, size_t getpw_buf_len
04733 # endif
04734     )
04735 {
04736     rb_uid_t uid;
04737     VALUE tmp;
04738 
04739     if (FIXNUM_P(id) || NIL_P(tmp = rb_check_string_type(id))) {
04740         uid = NUM2UIDT(id);
04741     }
04742     else {
04743         const char *usrname = StringValueCStr(id);
04744         struct passwd *pwptr;
04745 #ifdef USE_GETPWNAM_R
04746         struct passwd pwbuf;
04747         if (getpwnam_r(usrname, &pwbuf, getpw_buf, getpw_buf_len, &pwptr))
04748             rb_sys_fail("getpwnam_r");
04749 #else
04750         pwptr = getpwnam(usrname);
04751 #endif
04752         if (!pwptr) {
04753 #ifndef USE_GETPWNAM_R
04754             endpwent();
04755 #endif
04756             rb_raise(rb_eArgError, "can't find user for %s", usrname);
04757         }
04758         uid = pwptr->pw_uid;
04759 #ifndef USE_GETPWNAM_R
04760         endpwent();
04761 #endif
04762     }
04763     return uid;
04764 }
04765 
04766 # ifdef p_uid_from_name
04767 static VALUE
04768 p_uid_from_name(VALUE self, VALUE id)
04769 {
04770     PREPARE_GETPWNAM
04771     return UIDT2NUM(OBJ2UID(id));
04772 }
04773 # endif
04774 #endif
04775 
04776 #if defined(HAVE_GRP_H)
04777 static rb_gid_t
04778 obj2gid(VALUE id
04779 # ifdef USE_GETGRNAM_R
04780         , char *getgr_buf, size_t getgr_buf_len
04781 # endif
04782     )
04783 {
04784     rb_gid_t gid;
04785     VALUE tmp;
04786 
04787     if (FIXNUM_P(id) || NIL_P(tmp = rb_check_string_type(id))) {
04788         gid = NUM2GIDT(id);
04789     }
04790     else {
04791         const char *grpname = StringValueCStr(id);
04792         struct group *grptr;
04793 #ifdef USE_GETGRNAM_R
04794         struct group grbuf;
04795         if (getgrnam_r(grpname, &grbuf, getgr_buf, getgr_buf_len, &grptr))
04796             rb_sys_fail("getgrnam_r");
04797 #else
04798         grptr = getgrnam(grpname);
04799 #endif
04800         if (!grptr) {
04801 #ifndef USE_GETGRNAM_R
04802             endgrent();
04803 #endif
04804             rb_raise(rb_eArgError, "can't find group for %s", grpname);
04805         }
04806         gid = grptr->gr_gid;
04807 #ifndef USE_GETGRNAM_R
04808         endgrent();
04809 #endif
04810     }
04811     return gid;
04812 }
04813 
04814 # ifdef p_gid_from_name
04815 static VALUE
04816 p_gid_from_name(VALUE self, VALUE id)
04817 {
04818     PREPARE_GETGRNAM;
04819     return GIDT2NUM(OBJ2GID(id));
04820 }
04821 # endif
04822 #endif
04823 
04824 #if defined HAVE_SETUID
04825 /*
04826  *  call-seq:
04827  *     Process::Sys.setuid(user)   -> nil
04828  *
04829  *  Set the user ID of the current process to _user_. Not
04830  *  available on all platforms.
04831  *
04832  */
04833 
04834 static VALUE
04835 p_sys_setuid(VALUE obj, VALUE id)
04836 {
04837     PREPARE_GETPWNAM;
04838     check_uid_switch();
04839     if (setuid(OBJ2UID(id)) != 0) rb_sys_fail(0);
04840     return Qnil;
04841 }
04842 #else
04843 #define p_sys_setuid rb_f_notimplement
04844 #endif
04845 
04846 
04847 #if defined HAVE_SETRUID
04848 /*
04849  *  call-seq:
04850  *     Process::Sys.setruid(user)   -> nil
04851  *
04852  *  Set the real user ID of the calling process to _user_.
04853  *  Not available on all platforms.
04854  *
04855  */
04856 
04857 static VALUE
04858 p_sys_setruid(VALUE obj, VALUE id)
04859 {
04860     PREPARE_GETPWNAM;
04861     check_uid_switch();
04862     if (setruid(OBJ2UID(id)) != 0) rb_sys_fail(0);
04863     return Qnil;
04864 }
04865 #else
04866 #define p_sys_setruid rb_f_notimplement
04867 #endif
04868 
04869 
04870 #if defined HAVE_SETEUID
04871 /*
04872  *  call-seq:
04873  *     Process::Sys.seteuid(user)   -> nil
04874  *
04875  *  Set the effective user ID of the calling process to
04876  *  _user_.  Not available on all platforms.
04877  *
04878  */
04879 
04880 static VALUE
04881 p_sys_seteuid(VALUE obj, VALUE id)
04882 {
04883     PREPARE_GETPWNAM;
04884     check_uid_switch();
04885     if (seteuid(OBJ2UID(id)) != 0) rb_sys_fail(0);
04886     return Qnil;
04887 }
04888 #else
04889 #define p_sys_seteuid rb_f_notimplement
04890 #endif
04891 
04892 
04893 #if defined HAVE_SETREUID
04894 /*
04895  *  call-seq:
04896  *     Process::Sys.setreuid(rid, eid)   -> nil
04897  *
04898  *  Sets the (user) real and/or effective user IDs of the current
04899  *  process to _rid_ and _eid_, respectively. A value of
04900  *  <code>-1</code> for either means to leave that ID unchanged. Not
04901  *  available on all platforms.
04902  *
04903  */
04904 
04905 static VALUE
04906 p_sys_setreuid(VALUE obj, VALUE rid, VALUE eid)
04907 {
04908     PREPARE_GETPWNAM;
04909     check_uid_switch();
04910     if (setreuid(OBJ2UID(rid), OBJ2UID(eid)) != 0) rb_sys_fail(0);
04911     return Qnil;
04912 }
04913 #else
04914 #define p_sys_setreuid rb_f_notimplement
04915 #endif
04916 
04917 
04918 #if defined HAVE_SETRESUID
04919 /*
04920  *  call-seq:
04921  *     Process::Sys.setresuid(rid, eid, sid)   -> nil
04922  *
04923  *  Sets the (user) real, effective, and saved user IDs of the
04924  *  current process to _rid_, _eid_, and _sid_ respectively. A
04925  *  value of <code>-1</code> for any value means to
04926  *  leave that ID unchanged. Not available on all platforms.
04927  *
04928  */
04929 
04930 static VALUE
04931 p_sys_setresuid(VALUE obj, VALUE rid, VALUE eid, VALUE sid)
04932 {
04933     PREPARE_GETPWNAM;
04934     check_uid_switch();
04935     if (setresuid(OBJ2UID(rid), OBJ2UID(eid), OBJ2UID(sid)) != 0) rb_sys_fail(0);
04936     return Qnil;
04937 }
04938 #else
04939 #define p_sys_setresuid rb_f_notimplement
04940 #endif
04941 
04942 
04943 /*
04944  *  call-seq:
04945  *     Process.uid           -> fixnum
04946  *     Process::UID.rid      -> fixnum
04947  *     Process::Sys.getuid   -> fixnum
04948  *
04949  *  Returns the (real) user ID of this process.
04950  *
04951  *     Process.uid   #=> 501
04952  */
04953 
04954 static VALUE
04955 proc_getuid(VALUE obj)
04956 {
04957     rb_uid_t uid = getuid();
04958     return UIDT2NUM(uid);
04959 }
04960 
04961 
04962 #if defined(HAVE_SETRESUID) || defined(HAVE_SETREUID) || defined(HAVE_SETRUID) || defined(HAVE_SETUID)
04963 /*
04964  *  call-seq:
04965  *     Process.uid= user   -> numeric
04966  *
04967  *  Sets the (user) user ID for this process. Not available on all
04968  *  platforms.
04969  */
04970 
04971 static VALUE
04972 proc_setuid(VALUE obj, VALUE id)
04973 {
04974     rb_uid_t uid;
04975     PREPARE_GETPWNAM;
04976 
04977     check_uid_switch();
04978 
04979     uid = OBJ2UID(id);
04980 #if defined(HAVE_SETRESUID)
04981     if (setresuid(uid, -1, -1) < 0) rb_sys_fail(0);
04982 #elif defined HAVE_SETREUID
04983     if (setreuid(uid, -1) < 0) rb_sys_fail(0);
04984 #elif defined HAVE_SETRUID
04985     if (setruid(uid) < 0) rb_sys_fail(0);
04986 #elif defined HAVE_SETUID
04987     {
04988         if (geteuid() == uid) {
04989             if (setuid(uid) < 0) rb_sys_fail(0);
04990         }
04991         else {
04992             rb_notimplement();
04993         }
04994     }
04995 #endif
04996     return id;
04997 }
04998 #else
04999 #define proc_setuid rb_f_notimplement
05000 #endif
05001 
05002 
05003 /********************************************************************
05004  *
05005  * Document-class: Process::UID
05006  *
05007  *  The <code>Process::UID</code> module contains a collection of
05008  *  module functions which can be used to portably get, set, and
05009  *  switch the current process's real, effective, and saved user IDs.
05010  *
05011  */
05012 
05013 static rb_uid_t SAVED_USER_ID = -1;
05014 
05015 #ifdef BROKEN_SETREUID
05016 int
05017 setreuid(rb_uid_t ruid, rb_uid_t euid)
05018 {
05019     if (ruid != (rb_uid_t)-1 && ruid != getuid()) {
05020         if (euid == (rb_uid_t)-1) euid = geteuid();
05021         if (setuid(ruid) < 0) return -1;
05022     }
05023     if (euid != (rb_uid_t)-1 && euid != geteuid()) {
05024         if (seteuid(euid) < 0) return -1;
05025     }
05026     return 0;
05027 }
05028 #endif
05029 
05030 /*
05031  *  call-seq:
05032  *     Process::UID.change_privilege(user)   -> fixnum
05033  *
05034  *  Change the current process's real and effective user ID to that
05035  *  specified by _user_. Returns the new user ID. Not
05036  *  available on all platforms.
05037  *
05038  *     [Process.uid, Process.euid]          #=> [0, 0]
05039  *     Process::UID.change_privilege(31)    #=> 31
05040  *     [Process.uid, Process.euid]          #=> [31, 31]
05041  */
05042 
05043 static VALUE
05044 p_uid_change_privilege(VALUE obj, VALUE id)
05045 {
05046     rb_uid_t uid;
05047     PREPARE_GETPWNAM;
05048 
05049     check_uid_switch();
05050 
05051     uid = OBJ2UID(id);
05052 
05053     if (geteuid() == 0) { /* root-user */
05054 #if defined(HAVE_SETRESUID)
05055         if (setresuid(uid, uid, uid) < 0) rb_sys_fail(0);
05056         SAVED_USER_ID = uid;
05057 #elif defined(HAVE_SETUID)
05058         if (setuid(uid) < 0) rb_sys_fail(0);
05059         SAVED_USER_ID = uid;
05060 #elif defined(HAVE_SETREUID) && !defined(OBSOLETE_SETREUID)
05061         if (getuid() == uid) {
05062             if (SAVED_USER_ID == uid) {
05063                 if (setreuid(-1, uid) < 0) rb_sys_fail(0);
05064             }
05065             else {
05066                 if (uid == 0) { /* (r,e,s) == (root, root, x) */
05067                     if (setreuid(-1, SAVED_USER_ID) < 0) rb_sys_fail(0);
05068                     if (setreuid(SAVED_USER_ID, 0) < 0) rb_sys_fail(0);
05069                     SAVED_USER_ID = 0; /* (r,e,s) == (x, root, root) */
05070                     if (setreuid(uid, uid) < 0) rb_sys_fail(0);
05071                     SAVED_USER_ID = uid;
05072                 }
05073                 else {
05074                     if (setreuid(0, -1) < 0) rb_sys_fail(0);
05075                     SAVED_USER_ID = 0;
05076                     if (setreuid(uid, uid) < 0) rb_sys_fail(0);
05077                     SAVED_USER_ID = uid;
05078                 }
05079             }
05080         }
05081         else {
05082             if (setreuid(uid, uid) < 0) rb_sys_fail(0);
05083             SAVED_USER_ID = uid;
05084         }
05085 #elif defined(HAVE_SETRUID) && defined(HAVE_SETEUID)
05086         if (getuid() == uid) {
05087             if (SAVED_USER_ID == uid) {
05088                 if (seteuid(uid) < 0) rb_sys_fail(0);
05089             }
05090             else {
05091                 if (uid == 0) {
05092                     if (setruid(SAVED_USER_ID) < 0) rb_sys_fail(0);
05093                     SAVED_USER_ID = 0;
05094                     if (setruid(0) < 0) rb_sys_fail(0);
05095                 }
05096                 else {
05097                     if (setruid(0) < 0) rb_sys_fail(0);
05098                     SAVED_USER_ID = 0;
05099                     if (seteuid(uid) < 0) rb_sys_fail(0);
05100                     if (setruid(uid) < 0) rb_sys_fail(0);
05101                     SAVED_USER_ID = uid;
05102                 }
05103             }
05104         }
05105         else {
05106             if (seteuid(uid) < 0) rb_sys_fail(0);
05107             if (setruid(uid) < 0) rb_sys_fail(0);
05108             SAVED_USER_ID = uid;
05109         }
05110 #else
05111         (void)uid;
05112         rb_notimplement();
05113 #endif
05114     }
05115     else { /* unprivileged user */
05116 #if defined(HAVE_SETRESUID)
05117         if (setresuid((getuid() == uid)? (rb_uid_t)-1: uid,
05118                       (geteuid() == uid)? (rb_uid_t)-1: uid,
05119                       (SAVED_USER_ID == uid)? (rb_uid_t)-1: uid) < 0) rb_sys_fail(0);
05120         SAVED_USER_ID = uid;
05121 #elif defined(HAVE_SETREUID) && !defined(OBSOLETE_SETREUID)
05122         if (SAVED_USER_ID == uid) {
05123             if (setreuid((getuid() == uid)? (rb_uid_t)-1: uid,
05124                          (geteuid() == uid)? (rb_uid_t)-1: uid) < 0)
05125                 rb_sys_fail(0);
05126         }
05127         else if (getuid() != uid) {
05128             if (setreuid(uid, (geteuid() == uid)? (rb_uid_t)-1: uid) < 0)
05129                 rb_sys_fail(0);
05130             SAVED_USER_ID = uid;
05131         }
05132         else if (/* getuid() == uid && */ geteuid() != uid) {
05133             if (setreuid(geteuid(), uid) < 0) rb_sys_fail(0);
05134             SAVED_USER_ID = uid;
05135             if (setreuid(uid, -1) < 0) rb_sys_fail(0);
05136         }
05137         else { /* getuid() == uid && geteuid() == uid */
05138             if (setreuid(-1, SAVED_USER_ID) < 0) rb_sys_fail(0);
05139             if (setreuid(SAVED_USER_ID, uid) < 0) rb_sys_fail(0);
05140             SAVED_USER_ID = uid;
05141             if (setreuid(uid, -1) < 0) rb_sys_fail(0);
05142         }
05143 #elif defined(HAVE_SETRUID) && defined(HAVE_SETEUID)
05144         if (SAVED_USER_ID == uid) {
05145             if (geteuid() != uid && seteuid(uid) < 0) rb_sys_fail(0);
05146             if (getuid() != uid && setruid(uid) < 0) rb_sys_fail(0);
05147         }
05148         else if (/* SAVED_USER_ID != uid && */ geteuid() == uid) {
05149             if (getuid() != uid) {
05150                 if (setruid(uid) < 0) rb_sys_fail(0);
05151                 SAVED_USER_ID = uid;
05152             }
05153             else {
05154                 if (setruid(SAVED_USER_ID) < 0) rb_sys_fail(0);
05155                 SAVED_USER_ID = uid;
05156                 if (setruid(uid) < 0) rb_sys_fail(0);
05157             }
05158         }
05159         else if (/* geteuid() != uid && */ getuid() == uid) {
05160             if (seteuid(uid) < 0) rb_sys_fail(0);
05161             if (setruid(SAVED_USER_ID) < 0) rb_sys_fail(0);
05162             SAVED_USER_ID = uid;
05163             if (setruid(uid) < 0) rb_sys_fail(0);
05164         }
05165         else {
05166             errno = EPERM;
05167             rb_sys_fail(0);
05168         }
05169 #elif defined HAVE_44BSD_SETUID
05170         if (getuid() == uid) {
05171             /* (r,e,s)==(uid,?,?) ==> (uid,uid,uid) */
05172             if (setuid(uid) < 0) rb_sys_fail(0);
05173             SAVED_USER_ID = uid;
05174         }
05175         else {
05176             errno = EPERM;
05177             rb_sys_fail(0);
05178         }
05179 #elif defined HAVE_SETEUID
05180         if (getuid() == uid && SAVED_USER_ID == uid) {
05181             if (seteuid(uid) < 0) rb_sys_fail(0);
05182         }
05183         else {
05184             errno = EPERM;
05185             rb_sys_fail(0);
05186         }
05187 #elif defined HAVE_SETUID
05188         if (getuid() == uid && SAVED_USER_ID == uid) {
05189             if (setuid(uid) < 0) rb_sys_fail(0);
05190         }
05191         else {
05192             errno = EPERM;
05193             rb_sys_fail(0);
05194         }
05195 #else
05196         rb_notimplement();
05197 #endif
05198     }
05199     return id;
05200 }
05201 
05202 
05203 
05204 #if defined HAVE_SETGID
05205 /*
05206  *  call-seq:
05207  *     Process::Sys.setgid(group)   -> nil
05208  *
05209  *  Set the group ID of the current process to _group_. Not
05210  *  available on all platforms.
05211  *
05212  */
05213 
05214 static VALUE
05215 p_sys_setgid(VALUE obj, VALUE id)
05216 {
05217     PREPARE_GETGRNAM;
05218     check_gid_switch();
05219     if (setgid(OBJ2GID(id)) != 0) rb_sys_fail(0);
05220     return Qnil;
05221 }
05222 #else
05223 #define p_sys_setgid rb_f_notimplement
05224 #endif
05225 
05226 
05227 #if defined HAVE_SETRGID
05228 /*
05229  *  call-seq:
05230  *     Process::Sys.setrgid(group)   -> nil
05231  *
05232  *  Set the real group ID of the calling process to _group_.
05233  *  Not available on all platforms.
05234  *
05235  */
05236 
05237 static VALUE
05238 p_sys_setrgid(VALUE obj, VALUE id)
05239 {
05240     PREPARE_GETGRNAM;
05241     check_gid_switch();
05242     if (setrgid(OBJ2GID(id)) != 0) rb_sys_fail(0);
05243     return Qnil;
05244 }
05245 #else
05246 #define p_sys_setrgid rb_f_notimplement
05247 #endif
05248 
05249 
05250 #if defined HAVE_SETEGID
05251 /*
05252  *  call-seq:
05253  *     Process::Sys.setegid(group)   -> nil
05254  *
05255  *  Set the effective group ID of the calling process to
05256  *  _group_.  Not available on all platforms.
05257  *
05258  */
05259 
05260 static VALUE
05261 p_sys_setegid(VALUE obj, VALUE id)
05262 {
05263     PREPARE_GETGRNAM;
05264     check_gid_switch();
05265     if (setegid(OBJ2GID(id)) != 0) rb_sys_fail(0);
05266     return Qnil;
05267 }
05268 #else
05269 #define p_sys_setegid rb_f_notimplement
05270 #endif
05271 
05272 
05273 #if defined HAVE_SETREGID
05274 /*
05275  *  call-seq:
05276  *     Process::Sys.setregid(rid, eid)   -> nil
05277  *
05278  *  Sets the (group) real and/or effective group IDs of the current
05279  *  process to <em>rid</em> and <em>eid</em>, respectively. A value of
05280  *  <code>-1</code> for either means to leave that ID unchanged. Not
05281  *  available on all platforms.
05282  *
05283  */
05284 
05285 static VALUE
05286 p_sys_setregid(VALUE obj, VALUE rid, VALUE eid)
05287 {
05288     PREPARE_GETGRNAM;
05289     check_gid_switch();
05290     if (setregid(OBJ2GID(rid), OBJ2GID(eid)) != 0) rb_sys_fail(0);
05291     return Qnil;
05292 }
05293 #else
05294 #define p_sys_setregid rb_f_notimplement
05295 #endif
05296 
05297 #if defined HAVE_SETRESGID
05298 /*
05299  *  call-seq:
05300  *     Process::Sys.setresgid(rid, eid, sid)   -> nil
05301  *
05302  *  Sets the (group) real, effective, and saved user IDs of the
05303  *  current process to <em>rid</em>, <em>eid</em>, and <em>sid</em>
05304  *  respectively. A value of <code>-1</code> for any value means to
05305  *  leave that ID unchanged. Not available on all platforms.
05306  *
05307  */
05308 
05309 static VALUE
05310 p_sys_setresgid(VALUE obj, VALUE rid, VALUE eid, VALUE sid)
05311 {
05312     PREPARE_GETGRNAM;
05313     check_gid_switch();
05314     if (setresgid(OBJ2GID(rid), OBJ2GID(eid), OBJ2GID(sid)) != 0) rb_sys_fail(0);
05315     return Qnil;
05316 }
05317 #else
05318 #define p_sys_setresgid rb_f_notimplement
05319 #endif
05320 
05321 
05322 #if defined HAVE_ISSETUGID
05323 /*
05324  *  call-seq:
05325  *     Process::Sys.issetugid   -> true or false
05326  *
05327  *  Returns +true+ if the process was created as a result
05328  *  of an execve(2) system call which had either of the setuid or
05329  *  setgid bits set (and extra privileges were given as a result) or
05330  *  if it has changed any of its real, effective or saved user or
05331  *  group IDs since it began execution.
05332  *
05333  */
05334 
05335 static VALUE
05336 p_sys_issetugid(VALUE obj)
05337 {
05338     rb_secure(2);
05339     if (issetugid()) {
05340         return Qtrue;
05341     }
05342     else {
05343         return Qfalse;
05344     }
05345 }
05346 #else
05347 #define p_sys_issetugid rb_f_notimplement
05348 #endif
05349 
05350 
05351 /*
05352  *  call-seq:
05353  *     Process.gid           -> fixnum
05354  *     Process::GID.rid      -> fixnum
05355  *     Process::Sys.getgid   -> fixnum
05356  *
05357  *  Returns the (real) group ID for this process.
05358  *
05359  *     Process.gid   #=> 500
05360  */
05361 
05362 static VALUE
05363 proc_getgid(VALUE obj)
05364 {
05365     rb_gid_t gid = getgid();
05366     return GIDT2NUM(gid);
05367 }
05368 
05369 
05370 #if defined(HAVE_SETRESGID) || defined(HAVE_SETREGID) || defined(HAVE_SETRGID) || defined(HAVE_SETGID)
05371 /*
05372  *  call-seq:
05373  *     Process.gid= fixnum   -> fixnum
05374  *
05375  *  Sets the group ID for this process.
05376  */
05377 
05378 static VALUE
05379 proc_setgid(VALUE obj, VALUE id)
05380 {
05381     rb_gid_t gid;
05382     PREPARE_GETGRNAM;
05383 
05384     check_gid_switch();
05385 
05386     gid = OBJ2GID(id);
05387 #if defined(HAVE_SETRESGID)
05388     if (setresgid(gid, -1, -1) < 0) rb_sys_fail(0);
05389 #elif defined HAVE_SETREGID
05390     if (setregid(gid, -1) < 0) rb_sys_fail(0);
05391 #elif defined HAVE_SETRGID
05392     if (setrgid(gid) < 0) rb_sys_fail(0);
05393 #elif defined HAVE_SETGID
05394     {
05395         if (getegid() == gid) {
05396             if (setgid(gid) < 0) rb_sys_fail(0);
05397         }
05398         else {
05399             rb_notimplement();
05400         }
05401     }
05402 #endif
05403     return GIDT2NUM(gid);
05404 }
05405 #else
05406 #define proc_setgid rb_f_notimplement
05407 #endif
05408 
05409 
05410 #if defined(HAVE_SETGROUPS) || defined(HAVE_GETGROUPS)
05411 /*
05412  * Maximum supplementary groups are platform dependent.
05413  * FWIW, 65536 is enough big for our supported OSs.
05414  *
05415  * OS Name                      max groups
05416  * -----------------------------------------------
05417  * Linux Kernel >= 2.6.3        65536
05418  * Linux Kernel < 2.6.3            32
05419  * IBM AIX 5.2                     64
05420  * IBM AIX 5.3 ... 6.1            128
05421  * IBM AIX 7.1                    128 (can be configured to be up to 2048)
05422  * OpenBSD, NetBSD                 16
05423  * FreeBSD < 8.0                   16
05424  * FreeBSD >=8.0                 1023
05425  * Darwin (Mac OS X)               16
05426  * Sun Solaris 7,8,9,10            16
05427  * Sun Solaris 11 / OpenSolaris  1024
05428  * HP-UX                           20
05429  * Windows                       1015
05430  */
05431 static int _maxgroups = -1;
05432 static int
05433 get_sc_ngroups_max(void)
05434 {
05435 #ifdef _SC_NGROUPS_MAX
05436     return (int)sysconf(_SC_NGROUPS_MAX);
05437 #elif defined(NGROUPS_MAX)
05438     return (int)NGROUPS_MAX;
05439 #else
05440     return -1;
05441 #endif
05442 }
05443 static int
05444 maxgroups(void)
05445 {
05446     if (_maxgroups < 0) {
05447         _maxgroups = get_sc_ngroups_max();
05448         if (_maxgroups < 0)
05449             _maxgroups = RB_MAX_GROUPS;
05450     }
05451 
05452     return _maxgroups;
05453 }
05454 #endif
05455 
05456 
05457 
05458 #ifdef HAVE_GETGROUPS
05459 /*
05460  *  call-seq:
05461  *     Process.groups   -> array
05462  *
05463  *  Get an <code>Array</code> of the gids of groups in the
05464  *  supplemental group access list for this process.
05465  *
05466  *     Process.groups   #=> [27, 6, 10, 11]
05467  *
05468  */
05469 
05470 static VALUE
05471 proc_getgroups(VALUE obj)
05472 {
05473     VALUE ary;
05474     int i, ngroups;
05475     rb_gid_t *groups;
05476 
05477     ngroups = getgroups(0, NULL);
05478     if (ngroups == -1)
05479         rb_sys_fail(0);
05480 
05481     groups = ALLOCA_N(rb_gid_t, ngroups);
05482 
05483     ngroups = getgroups(ngroups, groups);
05484     if (ngroups == -1)
05485         rb_sys_fail(0);
05486 
05487     ary = rb_ary_new();
05488     for (i = 0; i < ngroups; i++)
05489         rb_ary_push(ary, GIDT2NUM(groups[i]));
05490 
05491     return ary;
05492 }
05493 #else
05494 #define proc_getgroups rb_f_notimplement
05495 #endif
05496 
05497 
05498 #ifdef HAVE_SETGROUPS
05499 /*
05500  *  call-seq:
05501  *     Process.groups= array   -> array
05502  *
05503  *  Set the supplemental group access list to the given
05504  *  <code>Array</code> of group IDs.
05505  *
05506  *     Process.groups   #=> [0, 1, 2, 3, 4, 6, 10, 11, 20, 26, 27]
05507  *     Process.groups = [27, 6, 10, 11]   #=> [27, 6, 10, 11]
05508  *     Process.groups   #=> [27, 6, 10, 11]
05509  *
05510  */
05511 
05512 static VALUE
05513 proc_setgroups(VALUE obj, VALUE ary)
05514 {
05515     int ngroups, i;
05516     rb_gid_t *groups;
05517     PREPARE_GETGRNAM;
05518 
05519     Check_Type(ary, T_ARRAY);
05520 
05521     ngroups = RARRAY_LENINT(ary);
05522     if (ngroups > maxgroups())
05523         rb_raise(rb_eArgError, "too many groups, %d max", maxgroups());
05524 
05525     groups = ALLOCA_N(rb_gid_t, ngroups);
05526 
05527     for (i = 0; i < ngroups; i++) {
05528         VALUE g = RARRAY_PTR(ary)[i];
05529 
05530         groups[i] = OBJ2GID(g);
05531     }
05532 
05533     if (setgroups(ngroups, groups) == -1) /* ngroups <= maxgroups */
05534         rb_sys_fail(0);
05535 
05536     return proc_getgroups(obj);
05537 }
05538 #else
05539 #define proc_setgroups rb_f_notimplement
05540 #endif
05541 
05542 
05543 #ifdef HAVE_INITGROUPS
05544 /*
05545  *  call-seq:
05546  *     Process.initgroups(username, gid)   -> array
05547  *
05548  *  Initializes the supplemental group access list by reading the
05549  *  system group database and using all groups of which the given user
05550  *  is a member. The group with the specified <em>gid</em> is also
05551  *  added to the list. Returns the resulting <code>Array</code> of the
05552  *  gids of all the groups in the supplementary group access list. Not
05553  *  available on all platforms.
05554  *
05555  *     Process.groups   #=> [0, 1, 2, 3, 4, 6, 10, 11, 20, 26, 27]
05556  *     Process.initgroups( "mgranger", 30 )   #=> [30, 6, 10, 11]
05557  *     Process.groups   #=> [30, 6, 10, 11]
05558  *
05559  */
05560 
05561 static VALUE
05562 proc_initgroups(VALUE obj, VALUE uname, VALUE base_grp)
05563 {
05564     PREPARE_GETGRNAM;
05565     if (initgroups(StringValuePtr(uname), OBJ2GID(base_grp)) != 0) {
05566         rb_sys_fail(0);
05567     }
05568     return proc_getgroups(obj);
05569 }
05570 #else
05571 #define proc_initgroups rb_f_notimplement
05572 #endif
05573 
05574 #if defined(_SC_NGROUPS_MAX) || defined(NGROUPS_MAX)
05575 /*
05576  *  call-seq:
05577  *     Process.maxgroups   -> fixnum
05578  *
05579  *  Returns the maximum number of gids allowed in the supplemental
05580  *  group access list.
05581  *
05582  *     Process.maxgroups   #=> 32
05583  */
05584 
05585 static VALUE
05586 proc_getmaxgroups(VALUE obj)
05587 {
05588     return INT2FIX(maxgroups());
05589 }
05590 #else
05591 #define proc_getmaxgroups rb_f_notimplement
05592 #endif
05593 
05594 #ifdef HAVE_SETGROUPS
05595 /*
05596  *  call-seq:
05597  *     Process.maxgroups= fixnum   -> fixnum
05598  *
05599  *  Sets the maximum number of gids allowed in the supplemental group
05600  *  access list.
05601  */
05602 
05603 static VALUE
05604 proc_setmaxgroups(VALUE obj, VALUE val)
05605 {
05606     int ngroups = FIX2INT(val);
05607     int ngroups_max = get_sc_ngroups_max();
05608 
05609     if (ngroups <= 0)
05610         rb_raise(rb_eArgError, "maxgroups %d shold be positive", ngroups);
05611 
05612     if (ngroups > RB_MAX_GROUPS)
05613         ngroups = RB_MAX_GROUPS;
05614 
05615     if (ngroups_max > 0 && ngroups > ngroups_max)
05616         ngroups = ngroups_max;
05617 
05618     _maxgroups = ngroups;
05619 
05620     return INT2FIX(_maxgroups);
05621 }
05622 #else
05623 #define proc_setmaxgroups rb_f_notimplement
05624 #endif
05625 
05626 #if defined(HAVE_DAEMON) || (defined(HAVE_FORK) && defined(HAVE_SETSID))
05627 static int rb_daemon(int nochdir, int noclose);
05628 
05629 /*
05630  *  call-seq:
05631  *     Process.daemon()                        -> 0
05632  *     Process.daemon(nochdir=nil,noclose=nil) -> 0
05633  *
05634  *  Detach the process from controlling terminal and run in
05635  *  the background as system daemon.  Unless the argument
05636  *  nochdir is true (i.e. non false), it changes the current
05637  *  working directory to the root ("/"). Unless the argument
05638  *  noclose is true, daemon() will redirect standard input,
05639  *  standard output and standard error to /dev/null.
05640  *  Return zero on success, or raise one of Errno::*.
05641  */
05642 
05643 static VALUE
05644 proc_daemon(int argc, VALUE *argv)
05645 {
05646     VALUE nochdir, noclose;
05647     int n;
05648 
05649     rb_secure(2);
05650     rb_scan_args(argc, argv, "02", &nochdir, &noclose);
05651 
05652     prefork();
05653     n = rb_daemon(RTEST(nochdir), RTEST(noclose));
05654     if (n < 0) rb_sys_fail("daemon");
05655     return INT2FIX(n);
05656 }
05657 
05658 static int
05659 rb_daemon(int nochdir, int noclose)
05660 {
05661     int err = 0;
05662 #ifdef HAVE_DAEMON
05663     before_fork();
05664     err = daemon(nochdir, noclose);
05665     after_fork();
05666     rb_thread_atfork();
05667 #else
05668     int n;
05669 
05670 #define fork_daemon() \
05671     switch (rb_fork_ruby(NULL)) { \
05672       case -1: return -1; \
05673       case 0:  rb_thread_atfork(); break; \
05674       default: _exit(EXIT_SUCCESS); \
05675     }
05676 
05677     fork_daemon();
05678 
05679     if (setsid() < 0) return -1;
05680 
05681     /* must not be process-leader */
05682     fork_daemon();
05683 
05684     if (!nochdir)
05685         err = chdir("/");
05686 
05687     if (!noclose && (n = rb_cloexec_open("/dev/null", O_RDWR, 0)) != -1) {
05688         rb_update_max_fd(n);
05689         (void)dup2(n, 0);
05690         (void)dup2(n, 1);
05691         (void)dup2(n, 2);
05692         if (n > 2)
05693             (void)close (n);
05694     }
05695 #endif
05696     return err;
05697 }
05698 #else
05699 #define proc_daemon rb_f_notimplement
05700 #endif
05701 
05702 /********************************************************************
05703  *
05704  * Document-class: Process::GID
05705  *
05706  *  The <code>Process::GID</code> module contains a collection of
05707  *  module functions which can be used to portably get, set, and
05708  *  switch the current process's real, effective, and saved group IDs.
05709  *
05710  */
05711 
05712 static rb_gid_t SAVED_GROUP_ID = -1;
05713 
05714 #ifdef BROKEN_SETREGID
05715 int
05716 setregid(rb_gid_t rgid, rb_gid_t egid)
05717 {
05718     if (rgid != (rb_gid_t)-1 && rgid != getgid()) {
05719         if (egid == (rb_gid_t)-1) egid = getegid();
05720         if (setgid(rgid) < 0) return -1;
05721     }
05722     if (egid != (rb_gid_t)-1 && egid != getegid()) {
05723         if (setegid(egid) < 0) return -1;
05724     }
05725     return 0;
05726 }
05727 #endif
05728 
05729 /*
05730  *  call-seq:
05731  *     Process::GID.change_privilege(group)   -> fixnum
05732  *
05733  *  Change the current process's real and effective group ID to that
05734  *  specified by _group_. Returns the new group ID. Not
05735  *  available on all platforms.
05736  *
05737  *     [Process.gid, Process.egid]          #=> [0, 0]
05738  *     Process::GID.change_privilege(33)    #=> 33
05739  *     [Process.gid, Process.egid]          #=> [33, 33]
05740  */
05741 
05742 static VALUE
05743 p_gid_change_privilege(VALUE obj, VALUE id)
05744 {
05745     rb_gid_t gid;
05746     PREPARE_GETGRNAM;
05747 
05748     check_gid_switch();
05749 
05750     gid = OBJ2GID(id);
05751 
05752     if (geteuid() == 0) { /* root-user */
05753 #if defined(HAVE_SETRESGID)
05754         if (setresgid(gid, gid, gid) < 0) rb_sys_fail(0);
05755         SAVED_GROUP_ID = gid;
05756 #elif defined HAVE_SETGID
05757         if (setgid(gid) < 0) rb_sys_fail(0);
05758         SAVED_GROUP_ID = gid;
05759 #elif defined(HAVE_SETREGID) && !defined(OBSOLETE_SETREGID)
05760         if (getgid() == gid) {
05761             if (SAVED_GROUP_ID == gid) {
05762                 if (setregid(-1, gid) < 0) rb_sys_fail(0);
05763             }
05764             else {
05765                 if (gid == 0) { /* (r,e,s) == (root, y, x) */
05766                     if (setregid(-1, SAVED_GROUP_ID) < 0) rb_sys_fail(0);
05767                     if (setregid(SAVED_GROUP_ID, 0) < 0) rb_sys_fail(0);
05768                     SAVED_GROUP_ID = 0; /* (r,e,s) == (x, root, root) */
05769                     if (setregid(gid, gid) < 0) rb_sys_fail(0);
05770                     SAVED_GROUP_ID = gid;
05771                 }
05772                 else { /* (r,e,s) == (z, y, x) */
05773                     if (setregid(0, 0) < 0) rb_sys_fail(0);
05774                     SAVED_GROUP_ID = 0;
05775                     if (setregid(gid, gid) < 0) rb_sys_fail(0);
05776                     SAVED_GROUP_ID = gid;
05777                 }
05778             }
05779         }
05780         else {
05781             if (setregid(gid, gid) < 0) rb_sys_fail(0);
05782             SAVED_GROUP_ID = gid;
05783         }
05784 #elif defined(HAVE_SETRGID) && defined (HAVE_SETEGID)
05785         if (getgid() == gid) {
05786             if (SAVED_GROUP_ID == gid) {
05787                 if (setegid(gid) < 0) rb_sys_fail(0);
05788             }
05789             else {
05790                 if (gid == 0) {
05791                     if (setegid(gid) < 0) rb_sys_fail(0);
05792                     if (setrgid(SAVED_GROUP_ID) < 0) rb_sys_fail(0);
05793                     SAVED_GROUP_ID = 0;
05794                     if (setrgid(0) < 0) rb_sys_fail(0);
05795                 }
05796                 else {
05797                     if (setrgid(0) < 0) rb_sys_fail(0);
05798                     SAVED_GROUP_ID = 0;
05799                     if (setegid(gid) < 0) rb_sys_fail(0);
05800                     if (setrgid(gid) < 0) rb_sys_fail(0);
05801                     SAVED_GROUP_ID = gid;
05802                 }
05803             }
05804         }
05805         else {
05806             if (setegid(gid) < 0) rb_sys_fail(0);
05807             if (setrgid(gid) < 0) rb_sys_fail(0);
05808             SAVED_GROUP_ID = gid;
05809         }
05810 #else
05811         rb_notimplement();
05812 #endif
05813     }
05814     else { /* unprivileged user */
05815 #if defined(HAVE_SETRESGID)
05816         if (setresgid((getgid() == gid)? (rb_gid_t)-1: gid,
05817                       (getegid() == gid)? (rb_gid_t)-1: gid,
05818                       (SAVED_GROUP_ID == gid)? (rb_gid_t)-1: gid) < 0) rb_sys_fail(0);
05819         SAVED_GROUP_ID = gid;
05820 #elif defined(HAVE_SETREGID) && !defined(OBSOLETE_SETREGID)
05821         if (SAVED_GROUP_ID == gid) {
05822             if (setregid((getgid() == gid)? (rb_uid_t)-1: gid,
05823                          (getegid() == gid)? (rb_uid_t)-1: gid) < 0)
05824                 rb_sys_fail(0);
05825         }
05826         else if (getgid() != gid) {
05827             if (setregid(gid, (getegid() == gid)? (rb_uid_t)-1: gid) < 0)
05828                 rb_sys_fail(0);
05829             SAVED_GROUP_ID = gid;
05830         }
05831         else if (/* getgid() == gid && */ getegid() != gid) {
05832             if (setregid(getegid(), gid) < 0) rb_sys_fail(0);
05833             SAVED_GROUP_ID = gid;
05834             if (setregid(gid, -1) < 0) rb_sys_fail(0);
05835         }
05836         else { /* getgid() == gid && getegid() == gid */
05837             if (setregid(-1, SAVED_GROUP_ID) < 0) rb_sys_fail(0);
05838             if (setregid(SAVED_GROUP_ID, gid) < 0) rb_sys_fail(0);
05839             SAVED_GROUP_ID = gid;
05840             if (setregid(gid, -1) < 0) rb_sys_fail(0);
05841         }
05842 #elif defined(HAVE_SETRGID) && defined(HAVE_SETEGID)
05843         if (SAVED_GROUP_ID == gid) {
05844             if (getegid() != gid && setegid(gid) < 0) rb_sys_fail(0);
05845             if (getgid() != gid && setrgid(gid) < 0) rb_sys_fail(0);
05846         }
05847         else if (/* SAVED_GROUP_ID != gid && */ getegid() == gid) {
05848             if (getgid() != gid) {
05849                 if (setrgid(gid) < 0) rb_sys_fail(0);
05850                 SAVED_GROUP_ID = gid;
05851             }
05852             else {
05853                 if (setrgid(SAVED_GROUP_ID) < 0) rb_sys_fail(0);
05854                 SAVED_GROUP_ID = gid;
05855                 if (setrgid(gid) < 0) rb_sys_fail(0);
05856             }
05857         }
05858         else if (/* getegid() != gid && */ getgid() == gid) {
05859             if (setegid(gid) < 0) rb_sys_fail(0);
05860             if (setrgid(SAVED_GROUP_ID) < 0) rb_sys_fail(0);
05861             SAVED_GROUP_ID = gid;
05862             if (setrgid(gid) < 0) rb_sys_fail(0);
05863         }
05864         else {
05865             errno = EPERM;
05866             rb_sys_fail(0);
05867         }
05868 #elif defined HAVE_44BSD_SETGID
05869         if (getgid() == gid) {
05870             /* (r,e,s)==(gid,?,?) ==> (gid,gid,gid) */
05871             if (setgid(gid) < 0) rb_sys_fail(0);
05872             SAVED_GROUP_ID = gid;
05873         }
05874         else {
05875             errno = EPERM;
05876             rb_sys_fail(0);
05877         }
05878 #elif defined HAVE_SETEGID
05879         if (getgid() == gid && SAVED_GROUP_ID == gid) {
05880             if (setegid(gid) < 0) rb_sys_fail(0);
05881         }
05882         else {
05883             errno = EPERM;
05884             rb_sys_fail(0);
05885         }
05886 #elif defined HAVE_SETGID
05887         if (getgid() == gid && SAVED_GROUP_ID == gid) {
05888             if (setgid(gid) < 0) rb_sys_fail(0);
05889         }
05890         else {
05891             errno = EPERM;
05892             rb_sys_fail(0);
05893         }
05894 #else
05895         (void)gid;
05896         rb_notimplement();
05897 #endif
05898     }
05899     return id;
05900 }
05901 
05902 
05903 /*
05904  *  call-seq:
05905  *     Process.euid           -> fixnum
05906  *     Process::UID.eid       -> fixnum
05907  *     Process::Sys.geteuid   -> fixnum
05908  *
05909  *  Returns the effective user ID for this process.
05910  *
05911  *     Process.euid   #=> 501
05912  */
05913 
05914 static VALUE
05915 proc_geteuid(VALUE obj)
05916 {
05917     rb_uid_t euid = geteuid();
05918     return UIDT2NUM(euid);
05919 }
05920 
05921 #if defined(HAVE_SETRESUID) || defined(HAVE_SETREUID) || defined(HAVE_SETEUID) || defined(HAVE_SETUID) || defined(_POSIX_SAVED_IDS)
05922 static void
05923 proc_seteuid(rb_uid_t uid)
05924 {
05925 #if defined(HAVE_SETRESUID)
05926     if (setresuid(-1, uid, -1) < 0) rb_sys_fail(0);
05927 #elif defined HAVE_SETREUID
05928     if (setreuid(-1, uid) < 0) rb_sys_fail(0);
05929 #elif defined HAVE_SETEUID
05930     if (seteuid(uid) < 0) rb_sys_fail(0);
05931 #elif defined HAVE_SETUID
05932     if (uid == getuid()) {
05933         if (setuid(uid) < 0) rb_sys_fail(0);
05934     }
05935     else {
05936         rb_notimplement();
05937     }
05938 #else
05939     rb_notimplement();
05940 #endif
05941 }
05942 #endif
05943 
05944 #if defined(HAVE_SETRESUID) || defined(HAVE_SETREUID) || defined(HAVE_SETEUID) || defined(HAVE_SETUID)
05945 /*
05946  *  call-seq:
05947  *     Process.euid= user
05948  *
05949  *  Sets the effective user ID for this process. Not available on all
05950  *  platforms.
05951  */
05952 
05953 static VALUE
05954 proc_seteuid_m(VALUE mod, VALUE euid)
05955 {
05956     PREPARE_GETPWNAM;
05957     check_uid_switch();
05958     proc_seteuid(OBJ2UID(euid));
05959     return euid;
05960 }
05961 #else
05962 #define proc_seteuid_m rb_f_notimplement
05963 #endif
05964 
05965 static rb_uid_t
05966 rb_seteuid_core(rb_uid_t euid)
05967 {
05968 #if defined(HAVE_SETRESUID) || (defined(HAVE_SETREUID) && !defined(OBSOLETE_SETREUID))
05969     rb_uid_t uid;
05970 #endif
05971 
05972     check_uid_switch();
05973 
05974 #if defined(HAVE_SETRESUID) || (defined(HAVE_SETREUID) && !defined(OBSOLETE_SETREUID))
05975     uid = getuid();
05976 #endif
05977 
05978 #if defined(HAVE_SETRESUID)
05979     if (uid != euid) {
05980         if (setresuid(-1,euid,euid) < 0) rb_sys_fail(0);
05981         SAVED_USER_ID = euid;
05982     }
05983     else {
05984         if (setresuid(-1,euid,-1) < 0) rb_sys_fail(0);
05985     }
05986 #elif defined(HAVE_SETREUID) && !defined(OBSOLETE_SETREUID)
05987     if (setreuid(-1, euid) < 0) rb_sys_fail(0);
05988     if (uid != euid) {
05989         if (setreuid(euid,uid) < 0) rb_sys_fail(0);
05990         if (setreuid(uid,euid) < 0) rb_sys_fail(0);
05991         SAVED_USER_ID = euid;
05992     }
05993 #elif defined HAVE_SETEUID
05994     if (seteuid(euid) < 0) rb_sys_fail(0);
05995 #elif defined HAVE_SETUID
05996     if (geteuid() == 0) rb_sys_fail(0);
05997     if (setuid(euid) < 0) rb_sys_fail(0);
05998 #else
05999     rb_notimplement();
06000 #endif
06001     return euid;
06002 }
06003 
06004 
06005 /*
06006  *  call-seq:
06007  *     Process::UID.grant_privilege(user)   -> fixnum
06008  *     Process::UID.eid= user               -> fixnum
06009  *
06010  *  Set the effective user ID, and if possible, the saved user ID of
06011  *  the process to the given _user_. Returns the new
06012  *  effective user ID. Not available on all platforms.
06013  *
06014  *     [Process.uid, Process.euid]          #=> [0, 0]
06015  *     Process::UID.grant_privilege(31)     #=> 31
06016  *     [Process.uid, Process.euid]          #=> [0, 31]
06017  */
06018 
06019 static VALUE
06020 p_uid_grant_privilege(VALUE obj, VALUE id)
06021 {
06022     PREPARE_GETPWNAM;
06023     rb_seteuid_core(OBJ2UID(id));
06024     return id;
06025 }
06026 
06027 
06028 /*
06029  *  call-seq:
06030  *     Process.egid          -> fixnum
06031  *     Process::GID.eid      -> fixnum
06032  *     Process::Sys.geteid   -> fixnum
06033  *
06034  *  Returns the effective group ID for this process. Not available on
06035  *  all platforms.
06036  *
06037  *     Process.egid   #=> 500
06038  */
06039 
06040 static VALUE
06041 proc_getegid(VALUE obj)
06042 {
06043     rb_gid_t egid = getegid();
06044 
06045     return GIDT2NUM(egid);
06046 }
06047 
06048 #if defined(HAVE_SETRESGID) || defined(HAVE_SETREGID) || defined(HAVE_SETEGID) || defined(HAVE_SETGID) || defined(_POSIX_SAVED_IDS)
06049 /*
06050  *  call-seq:
06051  *     Process.egid = fixnum   -> fixnum
06052  *
06053  *  Sets the effective group ID for this process. Not available on all
06054  *  platforms.
06055  */
06056 
06057 static VALUE
06058 proc_setegid(VALUE obj, VALUE egid)
06059 {
06060 #if defined(HAVE_SETRESGID) || defined(HAVE_SETREGID) || defined(HAVE_SETEGID) || defined(HAVE_SETGID)
06061     rb_gid_t gid;
06062     PREPARE_GETGRNAM;
06063 #endif
06064 
06065     check_gid_switch();
06066 
06067 #if defined(HAVE_SETRESGID) || defined(HAVE_SETREGID) || defined(HAVE_SETEGID) || defined(HAVE_SETGID)
06068     gid = OBJ2GID(egid);
06069 #endif
06070 
06071 #if defined(HAVE_SETRESGID)
06072     if (setresgid(-1, gid, -1) < 0) rb_sys_fail(0);
06073 #elif defined HAVE_SETREGID
06074     if (setregid(-1, gid) < 0) rb_sys_fail(0);
06075 #elif defined HAVE_SETEGID
06076     if (setegid(gid) < 0) rb_sys_fail(0);
06077 #elif defined HAVE_SETGID
06078     if (gid == getgid()) {
06079         if (setgid(gid) < 0) rb_sys_fail(0);
06080     }
06081     else {
06082         rb_notimplement();
06083     }
06084 #else
06085     rb_notimplement();
06086 #endif
06087     return egid;
06088 }
06089 #endif
06090 
06091 #if defined(HAVE_SETRESGID) || defined(HAVE_SETREGID) || defined(HAVE_SETEGID) || defined(HAVE_SETGID)
06092 #define proc_setegid_m proc_setegid
06093 #else
06094 #define proc_setegid_m rb_f_notimplement
06095 #endif
06096 
06097 static rb_gid_t
06098 rb_setegid_core(rb_gid_t egid)
06099 {
06100 #if defined(HAVE_SETRESGID) || (defined(HAVE_SETREGID) && !defined(OBSOLETE_SETREGID))
06101     rb_gid_t gid;
06102 #endif
06103 
06104     check_gid_switch();
06105 
06106 #if defined(HAVE_SETRESGID) || (defined(HAVE_SETREGID) && !defined(OBSOLETE_SETREGID))
06107     gid = getgid();
06108 #endif
06109 
06110 #if defined(HAVE_SETRESGID)
06111     if (gid != egid) {
06112         if (setresgid(-1,egid,egid) < 0) rb_sys_fail(0);
06113         SAVED_GROUP_ID = egid;
06114     }
06115     else {
06116         if (setresgid(-1,egid,-1) < 0) rb_sys_fail(0);
06117     }
06118 #elif defined(HAVE_SETREGID) && !defined(OBSOLETE_SETREGID)
06119     if (setregid(-1, egid) < 0) rb_sys_fail(0);
06120     if (gid != egid) {
06121         if (setregid(egid,gid) < 0) rb_sys_fail(0);
06122         if (setregid(gid,egid) < 0) rb_sys_fail(0);
06123         SAVED_GROUP_ID = egid;
06124     }
06125 #elif defined HAVE_SETEGID
06126     if (setegid(egid) < 0) rb_sys_fail(0);
06127 #elif defined HAVE_SETGID
06128     if (geteuid() == 0 /* root user */) rb_sys_fail(0);
06129     if (setgid(egid) < 0) rb_sys_fail(0);
06130 #else
06131     rb_notimplement();
06132 #endif
06133     return egid;
06134 }
06135 
06136 
06137 /*
06138  *  call-seq:
06139  *     Process::GID.grant_privilege(group)    -> fixnum
06140  *     Process::GID.eid = group               -> fixnum
06141  *
06142  *  Set the effective group ID, and if possible, the saved group ID of
06143  *  the process to the given _group_. Returns the new
06144  *  effective group ID. Not available on all platforms.
06145  *
06146  *     [Process.gid, Process.egid]          #=> [0, 0]
06147  *     Process::GID.grant_privilege(31)     #=> 33
06148  *     [Process.gid, Process.egid]          #=> [0, 33]
06149  */
06150 
06151 static VALUE
06152 p_gid_grant_privilege(VALUE obj, VALUE id)
06153 {
06154     PREPARE_GETGRNAM;
06155     rb_setegid_core(OBJ2GID(id));
06156     return id;
06157 }
06158 
06159 
06160 /*
06161  *  call-seq:
06162  *     Process::UID.re_exchangeable?   -> true or false
06163  *
06164  *  Returns +true+ if the real and effective user IDs of a
06165  *  process may be exchanged on the current platform.
06166  *
06167  */
06168 
06169 static VALUE
06170 p_uid_exchangeable(void)
06171 {
06172 #if defined(HAVE_SETRESUID)
06173     return Qtrue;
06174 #elif defined(HAVE_SETREUID) && !defined(OBSOLETE_SETREUID)
06175     return Qtrue;
06176 #else
06177     return Qfalse;
06178 #endif
06179 }
06180 
06181 
06182 /*
06183  *  call-seq:
06184  *     Process::UID.re_exchange   -> fixnum
06185  *
06186  *  Exchange real and effective user IDs and return the new effective
06187  *  user ID. Not available on all platforms.
06188  *
06189  *     [Process.uid, Process.euid]   #=> [0, 31]
06190  *     Process::UID.re_exchange      #=> 0
06191  *     [Process.uid, Process.euid]   #=> [31, 0]
06192  */
06193 
06194 static VALUE
06195 p_uid_exchange(VALUE obj)
06196 {
06197     rb_uid_t uid;
06198 #if defined(HAVE_SETRESUID) || (defined(HAVE_SETREUID) && !defined(OBSOLETE_SETREUID))
06199     rb_uid_t euid;
06200 #endif
06201 
06202     check_uid_switch();
06203 
06204     uid = getuid();
06205 #if defined(HAVE_SETRESUID) || (defined(HAVE_SETREUID) && !defined(OBSOLETE_SETREUID))
06206     euid = geteuid();
06207 #endif
06208 
06209 #if defined(HAVE_SETRESUID)
06210     if (setresuid(euid, uid, uid) < 0) rb_sys_fail(0);
06211     SAVED_USER_ID = uid;
06212 #elif defined(HAVE_SETREUID) && !defined(OBSOLETE_SETREUID)
06213     if (setreuid(euid,uid) < 0) rb_sys_fail(0);
06214     SAVED_USER_ID = uid;
06215 #else
06216     rb_notimplement();
06217 #endif
06218     return UIDT2NUM(uid);
06219 }
06220 
06221 
06222 /*
06223  *  call-seq:
06224  *     Process::GID.re_exchangeable?   -> true or false
06225  *
06226  *  Returns +true+ if the real and effective group IDs of a
06227  *  process may be exchanged on the current platform.
06228  *
06229  */
06230 
06231 static VALUE
06232 p_gid_exchangeable(void)
06233 {
06234 #if defined(HAVE_SETRESGID)
06235     return Qtrue;
06236 #elif defined(HAVE_SETREGID) && !defined(OBSOLETE_SETREGID)
06237     return Qtrue;
06238 #else
06239     return Qfalse;
06240 #endif
06241 }
06242 
06243 
06244 /*
06245  *  call-seq:
06246  *     Process::GID.re_exchange   -> fixnum
06247  *
06248  *  Exchange real and effective group IDs and return the new effective
06249  *  group ID. Not available on all platforms.
06250  *
06251  *     [Process.gid, Process.egid]   #=> [0, 33]
06252  *     Process::GID.re_exchange      #=> 0
06253  *     [Process.gid, Process.egid]   #=> [33, 0]
06254  */
06255 
06256 static VALUE
06257 p_gid_exchange(VALUE obj)
06258 {
06259     rb_gid_t gid;
06260 #if defined(HAVE_SETRESGID) || (defined(HAVE_SETREGID) && !defined(OBSOLETE_SETREGID))
06261     rb_gid_t egid;
06262 #endif
06263 
06264     check_gid_switch();
06265 
06266     gid = getgid();
06267 #if defined(HAVE_SETRESGID) || (defined(HAVE_SETREGID) && !defined(OBSOLETE_SETREGID))
06268     egid = getegid();
06269 #endif
06270 
06271 #if defined(HAVE_SETRESGID)
06272     if (setresgid(egid, gid, gid) < 0) rb_sys_fail(0);
06273     SAVED_GROUP_ID = gid;
06274 #elif defined(HAVE_SETREGID) && !defined(OBSOLETE_SETREGID)
06275     if (setregid(egid,gid) < 0) rb_sys_fail(0);
06276     SAVED_GROUP_ID = gid;
06277 #else
06278     rb_notimplement();
06279 #endif
06280     return GIDT2NUM(gid);
06281 }
06282 
06283 /* [MG] :FIXME: Is this correct? I'm not sure how to phrase this. */
06284 
06285 /*
06286  *  call-seq:
06287  *     Process::UID.sid_available?   -> true or false
06288  *
06289  *  Returns +true+ if the current platform has saved user
06290  *  ID functionality.
06291  *
06292  */
06293 
06294 static VALUE
06295 p_uid_have_saved_id(void)
06296 {
06297 #if defined(HAVE_SETRESUID) || defined(HAVE_SETEUID) || defined(_POSIX_SAVED_IDS)
06298     return Qtrue;
06299 #else
06300     return Qfalse;
06301 #endif
06302 }
06303 
06304 
06305 #if defined(HAVE_SETRESUID) || defined(HAVE_SETEUID) || defined(_POSIX_SAVED_IDS)
06306 static VALUE
06307 p_uid_sw_ensure(rb_uid_t id)
06308 {
06309     under_uid_switch = 0;
06310     id = rb_seteuid_core(id);
06311     return UIDT2NUM(id);
06312 }
06313 
06314 
06315 /*
06316  *  call-seq:
06317  *     Process::UID.switch              -> fixnum
06318  *     Process::UID.switch {|| block}   -> object
06319  *
06320  *  Switch the effective and real user IDs of the current process. If
06321  *  a <em>block</em> is given, the user IDs will be switched back
06322  *  after the block is executed. Returns the new effective user ID if
06323  *  called without a block, and the return value of the block if one
06324  *  is given.
06325  *
06326  */
06327 
06328 static VALUE
06329 p_uid_switch(VALUE obj)
06330 {
06331     rb_uid_t uid, euid;
06332 
06333     check_uid_switch();
06334 
06335     uid = getuid();
06336     euid = geteuid();
06337 
06338     if (uid != euid) {
06339         proc_seteuid(uid);
06340         if (rb_block_given_p()) {
06341             under_uid_switch = 1;
06342             return rb_ensure(rb_yield, Qnil, p_uid_sw_ensure, SAVED_USER_ID);
06343         }
06344         else {
06345             return UIDT2NUM(euid);
06346         }
06347     }
06348     else if (euid != SAVED_USER_ID) {
06349         proc_seteuid(SAVED_USER_ID);
06350         if (rb_block_given_p()) {
06351             under_uid_switch = 1;
06352             return rb_ensure(rb_yield, Qnil, p_uid_sw_ensure, euid);
06353         }
06354         else {
06355             return UIDT2NUM(uid);
06356         }
06357     }
06358     else {
06359         errno = EPERM;
06360         rb_sys_fail(0);
06361     }
06362 
06363     UNREACHABLE;
06364 }
06365 #else
06366 static VALUE
06367 p_uid_sw_ensure(VALUE obj)
06368 {
06369     under_uid_switch = 0;
06370     return p_uid_exchange(obj);
06371 }
06372 
06373 static VALUE
06374 p_uid_switch(VALUE obj)
06375 {
06376     rb_uid_t uid, euid;
06377 
06378     check_uid_switch();
06379 
06380     uid = getuid();
06381     euid = geteuid();
06382 
06383     if (uid == euid) {
06384         errno = EPERM;
06385         rb_sys_fail(0);
06386     }
06387     p_uid_exchange(obj);
06388     if (rb_block_given_p()) {
06389         under_uid_switch = 1;
06390         return rb_ensure(rb_yield, Qnil, p_uid_sw_ensure, obj);
06391     }
06392     else {
06393         return UIDT2NUM(euid);
06394     }
06395 }
06396 #endif
06397 
06398 
06399 /* [MG] :FIXME: Is this correct? I'm not sure how to phrase this. */
06400 
06401 /*
06402  *  call-seq:
06403  *     Process::GID.sid_available?   -> true or false
06404  *
06405  *  Returns +true+ if the current platform has saved group
06406  *  ID functionality.
06407  *
06408  */
06409 
06410 static VALUE
06411 p_gid_have_saved_id(void)
06412 {
06413 #if defined(HAVE_SETRESGID) || defined(HAVE_SETEGID) || defined(_POSIX_SAVED_IDS)
06414     return Qtrue;
06415 #else
06416     return Qfalse;
06417 #endif
06418 }
06419 
06420 #if defined(HAVE_SETRESGID) || defined(HAVE_SETEGID) || defined(_POSIX_SAVED_IDS)
06421 static VALUE
06422 p_gid_sw_ensure(rb_gid_t id)
06423 {
06424     under_gid_switch = 0;
06425     id = rb_setegid_core(id);
06426     return GIDT2NUM(id);
06427 }
06428 
06429 
06430 /*
06431  *  call-seq:
06432  *     Process::GID.switch              -> fixnum
06433  *     Process::GID.switch {|| block}   -> object
06434  *
06435  *  Switch the effective and real group IDs of the current process. If
06436  *  a <em>block</em> is given, the group IDs will be switched back
06437  *  after the block is executed. Returns the new effective group ID if
06438  *  called without a block, and the return value of the block if one
06439  *  is given.
06440  *
06441  */
06442 
06443 static VALUE
06444 p_gid_switch(VALUE obj)
06445 {
06446     rb_gid_t gid, egid;
06447 
06448     check_gid_switch();
06449 
06450     gid = getgid();
06451     egid = getegid();
06452 
06453     if (gid != egid) {
06454         proc_setegid(obj, GIDT2NUM(gid));
06455         if (rb_block_given_p()) {
06456             under_gid_switch = 1;
06457             return rb_ensure(rb_yield, Qnil, p_gid_sw_ensure, SAVED_GROUP_ID);
06458         }
06459         else {
06460             return GIDT2NUM(egid);
06461         }
06462     }
06463     else if (egid != SAVED_GROUP_ID) {
06464         proc_setegid(obj, GIDT2NUM(SAVED_GROUP_ID));
06465         if (rb_block_given_p()) {
06466             under_gid_switch = 1;
06467             return rb_ensure(rb_yield, Qnil, p_gid_sw_ensure, egid);
06468         }
06469         else {
06470             return GIDT2NUM(gid);
06471         }
06472     }
06473     else {
06474         errno = EPERM;
06475         rb_sys_fail(0);
06476     }
06477 
06478     UNREACHABLE;
06479 }
06480 #else
06481 static VALUE
06482 p_gid_sw_ensure(VALUE obj)
06483 {
06484     under_gid_switch = 0;
06485     return p_gid_exchange(obj);
06486 }
06487 
06488 static VALUE
06489 p_gid_switch(VALUE obj)
06490 {
06491     rb_gid_t gid, egid;
06492 
06493     check_gid_switch();
06494 
06495     gid = getgid();
06496     egid = getegid();
06497 
06498     if (gid == egid) {
06499         errno = EPERM;
06500         rb_sys_fail(0);
06501     }
06502     p_gid_exchange(obj);
06503     if (rb_block_given_p()) {
06504         under_gid_switch = 1;
06505         return rb_ensure(rb_yield, Qnil, p_gid_sw_ensure, obj);
06506     }
06507     else {
06508         return GIDT2NUM(egid);
06509     }
06510 }
06511 #endif
06512 
06513 
06514 #if defined(HAVE_TIMES)
06515 /*
06516  *  call-seq:
06517  *     Process.times   -> aStructTms
06518  *
06519  *  Returns a <code>Tms</code> structure (see <code>Struct::Tms</code>)
06520  *  that contains user and system CPU times for this process,
06521  *  and also for children processes.
06522  *
06523  *     t = Process.times
06524  *     [ t.utime, t.stime, t.cutime, t.cstime ]   #=> [0.0, 0.02, 0.00, 0.00]
06525  */
06526 
06527 VALUE
06528 rb_proc_times(VALUE obj)
06529 {
06530     const double hertz =
06531 #ifdef HAVE__SC_CLK_TCK
06532         (double)sysconf(_SC_CLK_TCK);
06533 #else
06534 #ifndef HZ
06535 # ifdef CLK_TCK
06536 #   define HZ CLK_TCK
06537 # else
06538 #   define HZ 60
06539 # endif
06540 #endif /* HZ */
06541         HZ;
06542 #endif
06543     struct tms buf;
06544     volatile VALUE utime, stime, cutime, sctime;
06545 
06546     times(&buf);
06547     return rb_struct_new(rb_cProcessTms,
06548                          utime = DBL2NUM(buf.tms_utime / hertz),
06549                          stime = DBL2NUM(buf.tms_stime / hertz),
06550                          cutime = DBL2NUM(buf.tms_cutime / hertz),
06551                          sctime = DBL2NUM(buf.tms_cstime / hertz));
06552 }
06553 #else
06554 #define rb_proc_times rb_f_notimplement
06555 #endif
06556 
06557 VALUE rb_mProcess;
06558 VALUE rb_mProcUID;
06559 VALUE rb_mProcGID;
06560 VALUE rb_mProcID_Syscall;
06561 
06562 
06563 /*
06564  *  The <code>Process</code> module is a collection of methods used to
06565  *  manipulate processes.
06566  */
06567 
06568 void
06569 Init_process(void)
06570 {
06571     rb_define_virtual_variable("$?", rb_last_status_get, 0);
06572     rb_define_virtual_variable("$$", get_pid, 0);
06573     rb_define_global_function("exec", rb_f_exec, -1);
06574     rb_define_global_function("fork", rb_f_fork, 0);
06575     rb_define_global_function("exit!", rb_f_exit_bang, -1);
06576     rb_define_global_function("system", rb_f_system, -1);
06577     rb_define_global_function("spawn", rb_f_spawn, -1);
06578     rb_define_global_function("sleep", rb_f_sleep, -1);
06579     rb_define_global_function("exit", rb_f_exit, -1);
06580     rb_define_global_function("abort", rb_f_abort, -1);
06581 
06582     rb_mProcess = rb_define_module("Process");
06583 
06584 #ifdef WNOHANG
06585     /* see Process.wait */
06586     rb_define_const(rb_mProcess, "WNOHANG", INT2FIX(WNOHANG));
06587 #else
06588     /* see Process.wait */
06589     rb_define_const(rb_mProcess, "WNOHANG", INT2FIX(0));
06590 #endif
06591 #ifdef WUNTRACED
06592     /* see Process.wait */
06593     rb_define_const(rb_mProcess, "WUNTRACED", INT2FIX(WUNTRACED));
06594 #else
06595     /* see Process.wait */
06596     rb_define_const(rb_mProcess, "WUNTRACED", INT2FIX(0));
06597 #endif
06598 
06599     rb_define_singleton_method(rb_mProcess, "exec", rb_f_exec, -1);
06600     rb_define_singleton_method(rb_mProcess, "fork", rb_f_fork, 0);
06601     rb_define_singleton_method(rb_mProcess, "spawn", rb_f_spawn, -1);
06602     rb_define_singleton_method(rb_mProcess, "exit!", rb_f_exit_bang, -1);
06603     rb_define_singleton_method(rb_mProcess, "exit", rb_f_exit, -1);
06604     rb_define_singleton_method(rb_mProcess, "abort", rb_f_abort, -1);
06605 
06606     rb_define_module_function(rb_mProcess, "kill", rb_f_kill, -1); /* in signal.c */
06607     rb_define_module_function(rb_mProcess, "wait", proc_wait, -1);
06608     rb_define_module_function(rb_mProcess, "wait2", proc_wait2, -1);
06609     rb_define_module_function(rb_mProcess, "waitpid", proc_wait, -1);
06610     rb_define_module_function(rb_mProcess, "waitpid2", proc_wait2, -1);
06611     rb_define_module_function(rb_mProcess, "waitall", proc_waitall, 0);
06612     rb_define_module_function(rb_mProcess, "detach", proc_detach, 1);
06613 
06614     rb_cProcessStatus = rb_define_class_under(rb_mProcess, "Status", rb_cObject);
06615     rb_undef_method(CLASS_OF(rb_cProcessStatus), "new");
06616 
06617     rb_define_method(rb_cProcessStatus, "==", pst_equal, 1);
06618     rb_define_method(rb_cProcessStatus, "&", pst_bitand, 1);
06619     rb_define_method(rb_cProcessStatus, ">>", pst_rshift, 1);
06620     rb_define_method(rb_cProcessStatus, "to_i", pst_to_i, 0);
06621     rb_define_method(rb_cProcessStatus, "to_s", pst_to_s, 0);
06622     rb_define_method(rb_cProcessStatus, "inspect", pst_inspect, 0);
06623 
06624     rb_define_method(rb_cProcessStatus, "pid", pst_pid, 0);
06625 
06626     rb_define_method(rb_cProcessStatus, "stopped?", pst_wifstopped, 0);
06627     rb_define_method(rb_cProcessStatus, "stopsig", pst_wstopsig, 0);
06628     rb_define_method(rb_cProcessStatus, "signaled?", pst_wifsignaled, 0);
06629     rb_define_method(rb_cProcessStatus, "termsig", pst_wtermsig, 0);
06630     rb_define_method(rb_cProcessStatus, "exited?", pst_wifexited, 0);
06631     rb_define_method(rb_cProcessStatus, "exitstatus", pst_wexitstatus, 0);
06632     rb_define_method(rb_cProcessStatus, "success?", pst_success_p, 0);
06633     rb_define_method(rb_cProcessStatus, "coredump?", pst_wcoredump, 0);
06634 
06635     rb_define_module_function(rb_mProcess, "pid", get_pid, 0);
06636     rb_define_module_function(rb_mProcess, "ppid", get_ppid, 0);
06637 
06638     rb_define_module_function(rb_mProcess, "getpgrp", proc_getpgrp, 0);
06639     rb_define_module_function(rb_mProcess, "setpgrp", proc_setpgrp, 0);
06640     rb_define_module_function(rb_mProcess, "getpgid", proc_getpgid, 1);
06641     rb_define_module_function(rb_mProcess, "setpgid", proc_setpgid, 2);
06642 
06643     rb_define_module_function(rb_mProcess, "getsid", proc_getsid, -1);
06644     rb_define_module_function(rb_mProcess, "setsid", proc_setsid, 0);
06645 
06646     rb_define_module_function(rb_mProcess, "getpriority", proc_getpriority, 2);
06647     rb_define_module_function(rb_mProcess, "setpriority", proc_setpriority, 3);
06648 
06649 #ifdef HAVE_GETPRIORITY
06650     /* see Process.setpriority */
06651     rb_define_const(rb_mProcess, "PRIO_PROCESS", INT2FIX(PRIO_PROCESS));
06652     /* see Process.setpriority */
06653     rb_define_const(rb_mProcess, "PRIO_PGRP", INT2FIX(PRIO_PGRP));
06654     /* see Process.setpriority */
06655     rb_define_const(rb_mProcess, "PRIO_USER", INT2FIX(PRIO_USER));
06656 #endif
06657 
06658     rb_define_module_function(rb_mProcess, "getrlimit", proc_getrlimit, 1);
06659     rb_define_module_function(rb_mProcess, "setrlimit", proc_setrlimit, -1);
06660 #if defined(RLIM2NUM) && defined(RLIM_INFINITY)
06661     {
06662         VALUE inf = RLIM2NUM(RLIM_INFINITY);
06663 #ifdef RLIM_SAVED_MAX
06664         {
06665             VALUE v = RLIM_INFINITY == RLIM_SAVED_MAX ? inf : RLIM2NUM(RLIM_SAVED_MAX);
06666             /* see Process.setrlimit */
06667             rb_define_const(rb_mProcess, "RLIM_SAVED_MAX", v);
06668         }
06669 #endif
06670         /* see Process.setrlimit */
06671         rb_define_const(rb_mProcess, "RLIM_INFINITY", inf);
06672 #ifdef RLIM_SAVED_CUR
06673         {
06674             VALUE v = RLIM_INFINITY == RLIM_SAVED_CUR ? inf : RLIM2NUM(RLIM_SAVED_CUR);
06675             /* see Process.setrlimit */
06676             rb_define_const(rb_mProcess, "RLIM_SAVED_CUR", v);
06677         }
06678 #endif
06679     }
06680 #ifdef RLIMIT_AS
06681     /* Maximum size of the process's virtual memory (address space) in bytes.
06682      *
06683      * see the system getrlimit(2) manual for details.
06684      */
06685     rb_define_const(rb_mProcess, "RLIMIT_AS", INT2FIX(RLIMIT_AS));
06686 #endif
06687 #ifdef RLIMIT_CORE
06688     /* Maximum size of the core file.
06689      *
06690      * see the system getrlimit(2) manual for details.
06691      */
06692     rb_define_const(rb_mProcess, "RLIMIT_CORE", INT2FIX(RLIMIT_CORE));
06693 #endif
06694 #ifdef RLIMIT_CPU
06695     /* CPU time limit in seconds.
06696      *
06697      * see the system getrlimit(2) manual for details.
06698      */
06699     rb_define_const(rb_mProcess, "RLIMIT_CPU", INT2FIX(RLIMIT_CPU));
06700 #endif
06701 #ifdef RLIMIT_DATA
06702     /* Maximum size of the process's data segment.
06703      *
06704      * see the system getrlimit(2) manual for details.
06705      */
06706     rb_define_const(rb_mProcess, "RLIMIT_DATA", INT2FIX(RLIMIT_DATA));
06707 #endif
06708 #ifdef RLIMIT_FSIZE
06709     /* Maximum size of files that the process may create.
06710      *
06711      * see the system getrlimit(2) manual for details.
06712      */
06713     rb_define_const(rb_mProcess, "RLIMIT_FSIZE", INT2FIX(RLIMIT_FSIZE));
06714 #endif
06715 #ifdef RLIMIT_MEMLOCK
06716     /* Maximum number of bytes of memory that may be locked into RAM.
06717      *
06718      * see the system getrlimit(2) manual for details.
06719      */
06720     rb_define_const(rb_mProcess, "RLIMIT_MEMLOCK", INT2FIX(RLIMIT_MEMLOCK));
06721 #endif
06722 #ifdef RLIMIT_MSGQUEUE
06723     /* Specifies the limit on the number of bytes that can be allocated
06724      * for POSIX message queues for the real user ID of the calling process.
06725      *
06726      * see the system getrlimit(2) manual for details.
06727      */
06728     rb_define_const(rb_mProcess, "RLIMIT_MSGQUEUE", INT2FIX(RLIMIT_MSGQUEUE));
06729 #endif
06730 #ifdef RLIMIT_NICE
06731     /* Specifies a ceiling to which the process's nice value can be raised.
06732      *
06733      * see the system getrlimit(2) manual for details.
06734      */
06735     rb_define_const(rb_mProcess, "RLIMIT_NICE", INT2FIX(RLIMIT_NICE));
06736 #endif
06737 #ifdef RLIMIT_NOFILE
06738     /* Specifies a value one greater than the maximum file descriptor
06739      * number that can be opened by this process.
06740      *
06741      * see the system getrlimit(2) manual for details.
06742      */
06743     rb_define_const(rb_mProcess, "RLIMIT_NOFILE", INT2FIX(RLIMIT_NOFILE));
06744 #endif
06745 #ifdef RLIMIT_NPROC
06746     /* The maximum number of processes that can be created for the
06747      * real user ID of the calling process.
06748      *
06749      * see the system getrlimit(2) manual for details.
06750      */
06751     rb_define_const(rb_mProcess, "RLIMIT_NPROC", INT2FIX(RLIMIT_NPROC));
06752 #endif
06753 #ifdef RLIMIT_RSS
06754     /* Specifies the limit (in pages) of the process's resident set.
06755      *
06756      * see the system getrlimit(2) manual for details.
06757      */
06758     rb_define_const(rb_mProcess, "RLIMIT_RSS", INT2FIX(RLIMIT_RSS));
06759 #endif
06760 #ifdef RLIMIT_RTPRIO
06761     /* Specifies a ceiling on the real-time priority that may be set for this process.
06762      *
06763      * see the system getrlimit(2) manual for details.
06764      */
06765     rb_define_const(rb_mProcess, "RLIMIT_RTPRIO", INT2FIX(RLIMIT_RTPRIO));
06766 #endif
06767 #ifdef RLIMIT_RTTIME
06768     /* Specifies limit on CPU time this process scheduled under a real-time
06769      * scheduling policy can consume.
06770      *
06771      * see the system getrlimit(2) manual for details.
06772      */
06773     rb_define_const(rb_mProcess, "RLIMIT_RTTIME", INT2FIX(RLIMIT_RTTIME));
06774 #endif
06775 #ifdef RLIMIT_SBSIZE
06776     /* Maximum size of the socket buffer.
06777      */
06778     rb_define_const(rb_mProcess, "RLIMIT_SBSIZE", INT2FIX(RLIMIT_SBSIZE));
06779 #endif
06780 #ifdef RLIMIT_SIGPENDING
06781     /* Specifies a limit on the number of signals that may be queued for
06782      * the real user ID of the calling process.
06783      *
06784      * see the system getrlimit(2) manual for details.
06785      */
06786     rb_define_const(rb_mProcess, "RLIMIT_SIGPENDING", INT2FIX(RLIMIT_SIGPENDING));
06787 #endif
06788 #ifdef RLIMIT_STACK
06789     /* Maximum size of the stack, in bytes.
06790      *
06791      * see the system getrlimit(2) manual for details.
06792      */
06793     rb_define_const(rb_mProcess, "RLIMIT_STACK", INT2FIX(RLIMIT_STACK));
06794 #endif
06795 #endif
06796 
06797     rb_define_module_function(rb_mProcess, "uid", proc_getuid, 0);
06798     rb_define_module_function(rb_mProcess, "uid=", proc_setuid, 1);
06799     rb_define_module_function(rb_mProcess, "gid", proc_getgid, 0);
06800     rb_define_module_function(rb_mProcess, "gid=", proc_setgid, 1);
06801     rb_define_module_function(rb_mProcess, "euid", proc_geteuid, 0);
06802     rb_define_module_function(rb_mProcess, "euid=", proc_seteuid_m, 1);
06803     rb_define_module_function(rb_mProcess, "egid", proc_getegid, 0);
06804     rb_define_module_function(rb_mProcess, "egid=", proc_setegid_m, 1);
06805     rb_define_module_function(rb_mProcess, "initgroups", proc_initgroups, 2);
06806     rb_define_module_function(rb_mProcess, "groups", proc_getgroups, 0);
06807     rb_define_module_function(rb_mProcess, "groups=", proc_setgroups, 1);
06808     rb_define_module_function(rb_mProcess, "maxgroups", proc_getmaxgroups, 0);
06809     rb_define_module_function(rb_mProcess, "maxgroups=", proc_setmaxgroups, 1);
06810 
06811     rb_define_module_function(rb_mProcess, "daemon", proc_daemon, -1);
06812 
06813     rb_define_module_function(rb_mProcess, "times", rb_proc_times, 0);
06814 
06815 #if defined(HAVE_TIMES) || defined(_WIN32)
06816     rb_cProcessTms = rb_struct_define("Tms", "utime", "stime", "cutime", "cstime", NULL);
06817 #endif
06818 
06819     SAVED_USER_ID = geteuid();
06820     SAVED_GROUP_ID = getegid();
06821 
06822     rb_mProcUID = rb_define_module_under(rb_mProcess, "UID");
06823     rb_mProcGID = rb_define_module_under(rb_mProcess, "GID");
06824 
06825     rb_define_module_function(rb_mProcUID, "rid", proc_getuid, 0);
06826     rb_define_module_function(rb_mProcGID, "rid", proc_getgid, 0);
06827     rb_define_module_function(rb_mProcUID, "eid", proc_geteuid, 0);
06828     rb_define_module_function(rb_mProcGID, "eid", proc_getegid, 0);
06829     rb_define_module_function(rb_mProcUID, "change_privilege", p_uid_change_privilege, 1);
06830     rb_define_module_function(rb_mProcGID, "change_privilege", p_gid_change_privilege, 1);
06831     rb_define_module_function(rb_mProcUID, "grant_privilege", p_uid_grant_privilege, 1);
06832     rb_define_module_function(rb_mProcGID, "grant_privilege", p_gid_grant_privilege, 1);
06833     rb_define_alias(rb_singleton_class(rb_mProcUID), "eid=", "grant_privilege");
06834     rb_define_alias(rb_singleton_class(rb_mProcGID), "eid=", "grant_privilege");
06835     rb_define_module_function(rb_mProcUID, "re_exchange", p_uid_exchange, 0);
06836     rb_define_module_function(rb_mProcGID, "re_exchange", p_gid_exchange, 0);
06837     rb_define_module_function(rb_mProcUID, "re_exchangeable?", p_uid_exchangeable, 0);
06838     rb_define_module_function(rb_mProcGID, "re_exchangeable?", p_gid_exchangeable, 0);
06839     rb_define_module_function(rb_mProcUID, "sid_available?", p_uid_have_saved_id, 0);
06840     rb_define_module_function(rb_mProcGID, "sid_available?", p_gid_have_saved_id, 0);
06841     rb_define_module_function(rb_mProcUID, "switch", p_uid_switch, 0);
06842     rb_define_module_function(rb_mProcGID, "switch", p_gid_switch, 0);
06843 #ifdef p_uid_from_name
06844     rb_define_module_function(rb_mProcUID, "from_name", p_uid_from_name, 1);
06845 #endif
06846 #ifdef p_gid_from_name
06847     rb_define_module_function(rb_mProcGID, "from_name", p_gid_from_name, 1);
06848 #endif
06849 
06850     rb_mProcID_Syscall = rb_define_module_under(rb_mProcess, "Sys");
06851 
06852     rb_define_module_function(rb_mProcID_Syscall, "getuid", proc_getuid, 0);
06853     rb_define_module_function(rb_mProcID_Syscall, "geteuid", proc_geteuid, 0);
06854     rb_define_module_function(rb_mProcID_Syscall, "getgid", proc_getgid, 0);
06855     rb_define_module_function(rb_mProcID_Syscall, "getegid", proc_getegid, 0);
06856 
06857     rb_define_module_function(rb_mProcID_Syscall, "setuid", p_sys_setuid, 1);
06858     rb_define_module_function(rb_mProcID_Syscall, "setgid", p_sys_setgid, 1);
06859 
06860     rb_define_module_function(rb_mProcID_Syscall, "setruid", p_sys_setruid, 1);
06861     rb_define_module_function(rb_mProcID_Syscall, "setrgid", p_sys_setrgid, 1);
06862 
06863     rb_define_module_function(rb_mProcID_Syscall, "seteuid", p_sys_seteuid, 1);
06864     rb_define_module_function(rb_mProcID_Syscall, "setegid", p_sys_setegid, 1);
06865 
06866     rb_define_module_function(rb_mProcID_Syscall, "setreuid", p_sys_setreuid, 2);
06867     rb_define_module_function(rb_mProcID_Syscall, "setregid", p_sys_setregid, 2);
06868 
06869     rb_define_module_function(rb_mProcID_Syscall, "setresuid", p_sys_setresuid, 3);
06870     rb_define_module_function(rb_mProcID_Syscall, "setresgid", p_sys_setresgid, 3);
06871     rb_define_module_function(rb_mProcID_Syscall, "issetugid", p_sys_issetugid, 0);
06872 }
06873