process.c

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

Generated on 19 Jul 2016 for Ruby by  doxygen 1.4.7