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