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