Ruby 1.9.3p327(2012-11-10revision37606)
process.c
Go to the documentation of this file.
00001 /**********************************************************************
00002 
00003   process.c -
00004 
00005   $Author: naruse $
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 
01953 static int
01954 redirect_dup2(int oldfd, int newfd)
01955 {
01956     int ret;
01957     ret = dup2(oldfd, newfd);
01958     ttyprintf("dup2(%d, %d)\n", oldfd, newfd);
01959     return ret;
01960 }
01961 
01962 static int
01963 redirect_close(int fd)
01964 {
01965     int ret;
01966     ret = close(fd);
01967     ttyprintf("close(%d)\n", fd);
01968     return ret;
01969 }
01970 
01971 static int
01972 redirect_open(const char *pathname, int flags, mode_t perm)
01973 {
01974     int ret;
01975     ret = open(pathname, flags, perm);
01976     ttyprintf("open(\"%s\", 0x%x, 0%o) => %d\n", pathname, flags, perm, ret);
01977     return ret;
01978 }
01979 
01980 #else
01981 #define redirect_dup(oldfd) dup(oldfd)
01982 #define redirect_dup2(oldfd, newfd) dup2((oldfd), (newfd))
01983 #define redirect_close(fd) close(fd)
01984 #define redirect_open(pathname, flags, perm) open((pathname), (flags), (perm))
01985 #endif
01986 
01987 static int
01988 save_redirect_fd(int fd, VALUE save, char *errmsg, size_t errmsg_buflen)
01989 {
01990     if (!NIL_P(save)) {
01991         VALUE newary;
01992         int save_fd = redirect_dup(fd);
01993         if (save_fd == -1) {
01994             if (errno == EBADF)
01995                 return 0;
01996             ERRMSG("dup");
01997             return -1;
01998         }
01999         rb_update_max_fd(save_fd);
02000         newary = rb_ary_entry(save, EXEC_OPTION_DUP2);
02001         if (NIL_P(newary)) {
02002             newary = hide_obj(rb_ary_new());
02003             rb_ary_store(save, EXEC_OPTION_DUP2, newary);
02004         }
02005         rb_ary_push(newary,
02006                     hide_obj(rb_assoc_new(INT2FIX(fd), INT2FIX(save_fd))));
02007 
02008         newary = rb_ary_entry(save, EXEC_OPTION_CLOSE);
02009         if (NIL_P(newary)) {
02010             newary = hide_obj(rb_ary_new());
02011             rb_ary_store(save, EXEC_OPTION_CLOSE, newary);
02012         }
02013         rb_ary_push(newary, hide_obj(rb_assoc_new(INT2FIX(save_fd), Qnil)));
02014     }
02015 
02016     return 0;
02017 }
02018 
02019 static VALUE
02020 save_env_i(VALUE i, VALUE ary, int argc, VALUE *argv)
02021 {
02022     rb_ary_push(ary, hide_obj(rb_ary_dup(argv[0])));
02023     return Qnil;
02024 }
02025 
02026 static void
02027 save_env(VALUE save)
02028 {
02029     if (!NIL_P(save) && NIL_P(rb_ary_entry(save, EXEC_OPTION_ENV))) {
02030         VALUE env = rb_const_get(rb_cObject, rb_intern("ENV"));
02031         if (RTEST(env)) {
02032             VALUE ary = hide_obj(rb_ary_new());
02033             rb_block_call(env, rb_intern("each"), 0, 0, save_env_i,
02034                           (VALUE)ary);
02035             rb_ary_store(save, EXEC_OPTION_ENV, ary);
02036         }
02037         rb_ary_store(save, EXEC_OPTION_UNSETENV_OTHERS, Qtrue);
02038     }
02039 }
02040 
02041 static int
02042 intcmp(const void *a, const void *b)
02043 {
02044     return *(int*)a - *(int*)b;
02045 }
02046 
02047 static int
02048 intrcmp(const void *a, const void *b)
02049 {
02050     return *(int*)b - *(int*)a;
02051 }
02052 
02053 static int
02054 run_exec_dup2(VALUE ary, VALUE save, char *errmsg, size_t errmsg_buflen)
02055 {
02056     long n, i;
02057     int ret;
02058     int extra_fd = -1;
02059     struct fd_pair {
02060         int oldfd;
02061         int newfd;
02062         long older_index;
02063         long num_newer;
02064     } *pairs = 0;
02065 
02066     n = RARRAY_LEN(ary);
02067     pairs = (struct fd_pair *)malloc(sizeof(struct fd_pair) * n);
02068     if (pairs == NULL) {
02069         ERRMSG("malloc");
02070         return -1;
02071     }
02072 
02073     /* initialize oldfd and newfd: O(n) */
02074     for (i = 0; i < n; i++) {
02075         VALUE elt = RARRAY_PTR(ary)[i];
02076         pairs[i].oldfd = FIX2INT(RARRAY_PTR(elt)[1]);
02077         pairs[i].newfd = FIX2INT(RARRAY_PTR(elt)[0]); /* unique */
02078         pairs[i].older_index = -1;
02079     }
02080 
02081     /* sort the table by oldfd: O(n log n) */
02082     if (!RTEST(save))
02083         qsort(pairs, n, sizeof(struct fd_pair), intcmp);
02084     else
02085         qsort(pairs, n, sizeof(struct fd_pair), intrcmp);
02086 
02087     /* initialize older_index and num_newer: O(n log n) */
02088     for (i = 0; i < n; i++) {
02089         int newfd = pairs[i].newfd;
02090         struct fd_pair key, *found;
02091         key.oldfd = newfd;
02092         found = bsearch(&key, pairs, n, sizeof(struct fd_pair), intcmp);
02093         pairs[i].num_newer = 0;
02094         if (found) {
02095             while (pairs < found && (found-1)->oldfd == newfd)
02096                 found--;
02097             while (found < pairs+n && found->oldfd == newfd) {
02098                 pairs[i].num_newer++;
02099                 found->older_index = i;
02100                 found++;
02101             }
02102         }
02103     }
02104 
02105     /* non-cyclic redirection: O(n) */
02106     for (i = 0; i < n; i++) {
02107         long j = i;
02108         while (j != -1 && pairs[j].oldfd != -1 && pairs[j].num_newer == 0) {
02109             if (save_redirect_fd(pairs[j].newfd, save, errmsg, errmsg_buflen) < 0)
02110                 goto fail;
02111             ret = redirect_dup2(pairs[j].oldfd, pairs[j].newfd);
02112             if (ret == -1) {
02113                 ERRMSG("dup2");
02114                 goto fail;
02115             }
02116             rb_update_max_fd(pairs[j].newfd);
02117             pairs[j].oldfd = -1;
02118             j = pairs[j].older_index;
02119             if (j != -1)
02120                 pairs[j].num_newer--;
02121         }
02122     }
02123 
02124     /* cyclic redirection: O(n) */
02125     for (i = 0; i < n; i++) {
02126         long j;
02127         if (pairs[i].oldfd == -1)
02128             continue;
02129         if (pairs[i].oldfd == pairs[i].newfd) { /* self cycle */
02130 #ifdef F_GETFD
02131             int fd = pairs[i].oldfd;
02132             ret = fcntl(fd, F_GETFD);
02133             if (ret == -1) {
02134                 ERRMSG("fcntl(F_GETFD)");
02135                 goto fail;
02136             }
02137             if (ret & FD_CLOEXEC) {
02138                 ret &= ~FD_CLOEXEC;
02139                 ret = fcntl(fd, F_SETFD, ret);
02140                 if (ret == -1) {
02141                     ERRMSG("fcntl(F_SETFD)");
02142                     goto fail;
02143                 }
02144             }
02145 #endif
02146             pairs[i].oldfd = -1;
02147             continue;
02148         }
02149         if (extra_fd == -1) {
02150             extra_fd = redirect_dup(pairs[i].oldfd);
02151             if (extra_fd == -1) {
02152                 ERRMSG("dup");
02153                 goto fail;
02154             }
02155             rb_update_max_fd(extra_fd);
02156         }
02157         else {
02158             ret = redirect_dup2(pairs[i].oldfd, extra_fd);
02159             if (ret == -1) {
02160                 ERRMSG("dup2");
02161                 goto fail;
02162             }
02163             rb_update_max_fd(extra_fd);
02164         }
02165         pairs[i].oldfd = extra_fd;
02166         j = pairs[i].older_index;
02167         pairs[i].older_index = -1;
02168         while (j != -1) {
02169             ret = redirect_dup2(pairs[j].oldfd, pairs[j].newfd);
02170             if (ret == -1) {
02171                 ERRMSG("dup2");
02172                 goto fail;
02173             }
02174             rb_update_max_fd(ret);
02175             pairs[j].oldfd = -1;
02176             j = pairs[j].older_index;
02177         }
02178     }
02179     if (extra_fd != -1) {
02180         ret = redirect_close(extra_fd);
02181         if (ret == -1) {
02182             ERRMSG("close");
02183             goto fail;
02184         }
02185     }
02186 
02187     xfree(pairs);
02188     return 0;
02189 
02190   fail:
02191     xfree(pairs);
02192     return -1;
02193 }
02194 
02195 static int
02196 run_exec_close(VALUE ary, char *errmsg, size_t errmsg_buflen)
02197 {
02198     long i;
02199     int ret;
02200 
02201     for (i = 0; i < RARRAY_LEN(ary); i++) {
02202         VALUE elt = RARRAY_PTR(ary)[i];
02203         int fd = FIX2INT(RARRAY_PTR(elt)[0]);
02204         ret = redirect_close(fd);
02205         if (ret == -1) {
02206             ERRMSG("close");
02207             return -1;
02208         }
02209     }
02210     return 0;
02211 }
02212 
02213 static int
02214 run_exec_open(VALUE ary, VALUE save, char *errmsg, size_t errmsg_buflen)
02215 {
02216     long i;
02217     int ret;
02218 
02219     for (i = 0; i < RARRAY_LEN(ary);) {
02220         VALUE elt = RARRAY_PTR(ary)[i];
02221         int fd = FIX2INT(RARRAY_PTR(elt)[0]);
02222         VALUE param = RARRAY_PTR(elt)[1];
02223         char *path = RSTRING_PTR(RARRAY_PTR(param)[0]);
02224         int flags = NUM2INT(RARRAY_PTR(param)[1]);
02225         int perm = NUM2INT(RARRAY_PTR(param)[2]);
02226         int need_close = 1;
02227         int fd2 = redirect_open(path, flags, perm);
02228         if (fd2 == -1) {
02229             ERRMSG("open");
02230             return -1;
02231         }
02232         rb_update_max_fd(fd2);
02233         while (i < RARRAY_LEN(ary) &&
02234                (elt = RARRAY_PTR(ary)[i], RARRAY_PTR(elt)[1] == param)) {
02235             fd = FIX2INT(RARRAY_PTR(elt)[0]);
02236             if (fd == fd2) {
02237                 need_close = 0;
02238             }
02239             else {
02240                 if (save_redirect_fd(fd, save, errmsg, errmsg_buflen) < 0)
02241                     return -1;
02242                 ret = redirect_dup2(fd2, fd);
02243                 if (ret == -1) {
02244                     ERRMSG("dup2");
02245                     return -1;
02246                 }
02247                 rb_update_max_fd(fd);
02248             }
02249             i++;
02250         }
02251         if (need_close) {
02252             ret = redirect_close(fd2);
02253             if (ret == -1) {
02254                 ERRMSG("close");
02255                 return -1;
02256             }
02257         }
02258     }
02259     return 0;
02260 }
02261 
02262 static int
02263 run_exec_dup2_child(VALUE ary, VALUE save, char *errmsg, size_t errmsg_buflen)
02264 {
02265     long i;
02266     int ret;
02267 
02268     for (i = 0; i < RARRAY_LEN(ary); i++) {
02269         VALUE elt = RARRAY_PTR(ary)[i];
02270         int newfd = FIX2INT(RARRAY_PTR(elt)[0]);
02271         int oldfd = FIX2INT(RARRAY_PTR(elt)[1]);
02272 
02273         if (save_redirect_fd(newfd, save, errmsg, errmsg_buflen) < 0)
02274             return -1;
02275         ret = redirect_dup2(oldfd, newfd);
02276         if (ret == -1) {
02277             ERRMSG("dup2");
02278             return -1;
02279         }
02280         rb_update_max_fd(newfd);
02281     }
02282     return 0;
02283 }
02284 
02285 #ifdef HAVE_SETPGID
02286 static int
02287 run_exec_pgroup(VALUE obj, VALUE save, char *errmsg, size_t errmsg_buflen)
02288 {
02289     /*
02290      * If FD_CLOEXEC is available, rb_fork waits the child's execve.
02291      * So setpgid is done in the child when rb_fork is returned in the parent.
02292      * No race condition, even without setpgid from the parent.
02293      * (Is there an environment which has setpgid but FD_CLOEXEC?)
02294      */
02295     int ret;
02296     pid_t pgroup;
02297     if (!NIL_P(save)) {
02298         /* maybe meaningless with no fork environment... */
02299         rb_ary_store(save, EXEC_OPTION_PGROUP, PIDT2NUM(getpgrp()));
02300     }
02301     pgroup = NUM2PIDT(obj);
02302     if (pgroup == 0) {
02303         pgroup = getpid();
02304     }
02305     ret = setpgid(getpid(), pgroup);
02306     if (ret == -1) ERRMSG("setpgid");
02307     return ret;
02308 }
02309 #endif
02310 
02311 #if defined(HAVE_SETRLIMIT) && defined(RLIM2NUM)
02312 static int
02313 run_exec_rlimit(VALUE ary, VALUE save, char *errmsg, size_t errmsg_buflen)
02314 {
02315     long i;
02316     for (i = 0; i < RARRAY_LEN(ary); i++) {
02317         VALUE elt = RARRAY_PTR(ary)[i];
02318         int rtype = NUM2INT(RARRAY_PTR(elt)[0]);
02319         struct rlimit rlim;
02320         if (!NIL_P(save)) {
02321             VALUE tmp, newary;
02322             if (getrlimit(rtype, &rlim) == -1) {
02323                 ERRMSG("getrlimit");
02324                 return -1;
02325             }
02326             tmp = hide_obj(rb_ary_new3(3, RARRAY_PTR(elt)[0],
02327                                        RLIM2NUM(rlim.rlim_cur),
02328                                        RLIM2NUM(rlim.rlim_max)));
02329             newary = rb_ary_entry(save, EXEC_OPTION_RLIMIT);
02330             if (NIL_P(newary)) {
02331                 newary = hide_obj(rb_ary_new());
02332                 rb_ary_store(save, EXEC_OPTION_RLIMIT, newary);
02333             }
02334             rb_ary_push(newary, tmp);
02335         }
02336         rlim.rlim_cur = NUM2RLIM(RARRAY_PTR(elt)[1]);
02337         rlim.rlim_max = NUM2RLIM(RARRAY_PTR(elt)[2]);
02338         if (setrlimit(rtype, &rlim) == -1) {
02339             ERRMSG("setrlimit");
02340             return -1;
02341         }
02342     }
02343     return 0;
02344 }
02345 #endif
02346 
02347 int
02348 rb_run_exec_options_err(const struct rb_exec_arg *e, struct rb_exec_arg *s, char *errmsg, size_t errmsg_buflen)
02349 {
02350     VALUE options = e->options;
02351     VALUE soptions = Qnil;
02352     VALUE obj;
02353 
02354     if (!RTEST(options))
02355         return 0;
02356 
02357     if (s) {
02358         s->argc = 0;
02359         s->argv = NULL;
02360         s->prog = NULL;
02361         s->options = soptions = hide_obj(rb_ary_new());
02362         s->redirect_fds = Qnil;
02363     }
02364 
02365 #ifdef HAVE_SETPGID
02366     obj = rb_ary_entry(options, EXEC_OPTION_PGROUP);
02367     if (RTEST(obj)) {
02368         if (run_exec_pgroup(obj, soptions, errmsg, errmsg_buflen) == -1)
02369             return -1;
02370     }
02371 #endif
02372 
02373 #if defined(HAVE_SETRLIMIT) && defined(RLIM2NUM)
02374     obj = rb_ary_entry(options, EXEC_OPTION_RLIMIT);
02375     if (!NIL_P(obj)) {
02376         if (run_exec_rlimit(obj, soptions, errmsg, errmsg_buflen) == -1)
02377             return -1;
02378     }
02379 #endif
02380 
02381     obj = rb_ary_entry(options, EXEC_OPTION_UNSETENV_OTHERS);
02382     if (RTEST(obj)) {
02383         save_env(soptions);
02384         rb_env_clear();
02385     }
02386 
02387     obj = rb_ary_entry(options, EXEC_OPTION_ENV);
02388     if (!NIL_P(obj)) {
02389         long i;
02390         save_env(soptions);
02391         for (i = 0; i < RARRAY_LEN(obj); i++) {
02392             VALUE pair = RARRAY_PTR(obj)[i];
02393             VALUE key = RARRAY_PTR(pair)[0];
02394             VALUE val = RARRAY_PTR(pair)[1];
02395             if (NIL_P(val))
02396                 ruby_setenv(StringValueCStr(key), 0);
02397             else
02398                 ruby_setenv(StringValueCStr(key), StringValueCStr(val));
02399         }
02400     }
02401 
02402     obj = rb_ary_entry(options, EXEC_OPTION_CHDIR);
02403     if (!NIL_P(obj)) {
02404         if (!NIL_P(soptions)) {
02405             char *cwd = my_getcwd();
02406             rb_ary_store(soptions, EXEC_OPTION_CHDIR,
02407                          hide_obj(rb_str_new2(cwd)));
02408             xfree(cwd);
02409         }
02410         if (chdir(RSTRING_PTR(obj)) == -1) {
02411             ERRMSG("chdir");
02412             return -1;
02413         }
02414     }
02415 
02416     obj = rb_ary_entry(options, EXEC_OPTION_UMASK);
02417     if (!NIL_P(obj)) {
02418         mode_t mask = NUM2MODET(obj);
02419         mode_t oldmask = umask(mask); /* never fail */
02420         if (!NIL_P(soptions))
02421             rb_ary_store(soptions, EXEC_OPTION_UMASK, MODET2NUM(oldmask));
02422     }
02423 
02424     obj = rb_ary_entry(options, EXEC_OPTION_DUP2);
02425     if (!NIL_P(obj)) {
02426         if (run_exec_dup2(obj, soptions, errmsg, errmsg_buflen) == -1)
02427             return -1;
02428     }
02429 
02430     obj = rb_ary_entry(options, EXEC_OPTION_CLOSE);
02431     if (!NIL_P(obj)) {
02432         if (!NIL_P(soptions))
02433             rb_warn("cannot close fd before spawn");
02434         else {
02435             if (run_exec_close(obj, errmsg, errmsg_buflen) == -1)
02436                 return -1;
02437         }
02438     }
02439 
02440 #ifdef HAVE_FORK
02441     obj = rb_ary_entry(options, EXEC_OPTION_CLOSE_OTHERS);
02442     if (obj != Qfalse) {
02443         rb_close_before_exec(3, FIX2INT(obj), e->redirect_fds);
02444     }
02445 #endif
02446 
02447     obj = rb_ary_entry(options, EXEC_OPTION_OPEN);
02448     if (!NIL_P(obj)) {
02449         if (run_exec_open(obj, soptions, errmsg, errmsg_buflen) == -1)
02450             return -1;
02451     }
02452 
02453     obj = rb_ary_entry(options, EXEC_OPTION_DUP2_CHILD);
02454     if (!NIL_P(obj)) {
02455         if (run_exec_dup2_child(obj, soptions, errmsg, errmsg_buflen) == -1)
02456             return -1;
02457     }
02458 
02459     return 0;
02460 }
02461 
02462 int
02463 rb_run_exec_options(const struct rb_exec_arg *e, struct rb_exec_arg *s)
02464 {
02465     return rb_run_exec_options_err(e, s, NULL, 0);
02466 }
02467 
02468 int
02469 rb_exec_err(const struct rb_exec_arg *e, char *errmsg, size_t errmsg_buflen)
02470 {
02471     int argc = e->argc;
02472     VALUE *argv = e->argv;
02473     const char *prog = e->prog;
02474 
02475     if (rb_run_exec_options_err(e, NULL, errmsg, errmsg_buflen) < 0) {
02476         return -1;
02477     }
02478 
02479     if (argc == 0) {
02480         rb_proc_exec(prog);
02481     }
02482     else {
02483         rb_proc_exec_n(argc, argv, prog);
02484     }
02485     return -1;
02486 }
02487 
02488 int
02489 rb_exec(const struct rb_exec_arg *e)
02490 {
02491 #if !defined FD_CLOEXEC && !defined HAVE_SPAWNV
02492     char errmsg[80] = { '\0' };
02493     int ret = rb_exec_err(e, errmsg, sizeof(errmsg));
02494     preserving_errno(
02495         if (errmsg[0]) {
02496             fprintf(stderr, "%s\n", errmsg);
02497         }
02498         else {
02499             fprintf(stderr, "%s:%d: command not found: %s\n",
02500                     rb_sourcefile(), rb_sourceline(), e->prog);
02501         }
02502     );
02503     return ret;
02504 #else
02505     return rb_exec_err(e, NULL, 0);
02506 #endif
02507 }
02508 
02509 #ifdef HAVE_FORK
02510 static int
02511 rb_exec_atfork(void* arg, char *errmsg, size_t errmsg_buflen)
02512 {
02513     rb_thread_atfork_before_exec();
02514     return rb_exec_err(arg, errmsg, errmsg_buflen);
02515 }
02516 #endif
02517 
02518 #ifdef HAVE_FORK
02519 #ifdef FD_CLOEXEC
02520 #if SIZEOF_INT == SIZEOF_LONG
02521 #define proc_syswait (VALUE (*)(VALUE))rb_syswait
02522 #else
02523 static VALUE
02524 proc_syswait(VALUE pid)
02525 {
02526     rb_syswait((int)pid);
02527     return Qnil;
02528 }
02529 #endif
02530 #endif
02531 
02532 static int
02533 move_fds_to_avoid_crash(int *fdp, int n, VALUE fds)
02534 {
02535     long min = 0;
02536     int i;
02537     for (i = 0; i < n; i++) {
02538         int ret;
02539         while (RTEST(rb_hash_lookup(fds, INT2FIX(fdp[i])))) {
02540             if (min <= fdp[i])
02541                 min = fdp[i]+1;
02542             while (RTEST(rb_hash_lookup(fds, INT2FIX(min))))
02543                 min++;
02544             ret = fcntl(fdp[i], F_DUPFD, min);
02545             if (ret == -1)
02546                 return -1;
02547             rb_update_max_fd(ret);
02548             close(fdp[i]);
02549             fdp[i] = ret;
02550         }
02551     }
02552     return 0;
02553 }
02554 
02555 static int
02556 pipe_nocrash(int filedes[2], VALUE fds)
02557 {
02558     int ret;
02559     ret = rb_pipe(filedes);
02560     if (ret == -1)
02561         return -1;
02562     if (RTEST(fds)) {
02563         int save = errno;
02564         if (move_fds_to_avoid_crash(filedes, 2, fds) == -1) {
02565             close(filedes[0]);
02566             close(filedes[1]);
02567             return -1;
02568         }
02569         errno = save;
02570     }
02571     return ret;
02572 }
02573 
02574 struct chfunc_protect_t {
02575     int (*chfunc)(void*, char *, size_t);
02576     void *arg;
02577     char *errmsg;
02578     size_t buflen;
02579 };
02580 
02581 static VALUE
02582 chfunc_protect(VALUE arg)
02583 {
02584     struct chfunc_protect_t *p = (struct chfunc_protect_t *)arg;
02585 
02586     return (VALUE)(*p->chfunc)(p->arg, p->errmsg, p->buflen);
02587 }
02588 
02589 #ifndef O_BINARY
02590 #define O_BINARY 0
02591 #endif
02592 
02593 /*
02594  * Forks child process, and returns the process ID in the parent
02595  * process.
02596  *
02597  * If +status+ is given, protects from any exceptions and sets the
02598  * jump status to it.
02599  *
02600  * In the child process, just returns 0 if +chfunc+ is +NULL+.
02601  * Otherwise +chfunc+ will be called with +charg+, and then the child
02602  * process exits with +EXIT_SUCCESS+ when it returned zero.
02603  *
02604  * In the case of the function is called and returns non-zero value,
02605  * the child process exits with non-+EXIT_SUCCESS+ value (normally
02606  * 127).  And, on the platforms where +FD_CLOEXEC+ is available,
02607  * +errno+ is propagated to the parent process, and this function
02608  * returns -1 in the parent process.  On the other platforms, just
02609  * returns pid.
02610  *
02611  * If fds is not Qnil, internal pipe for the errno propagation is
02612  * arranged to avoid conflicts of the hash keys in +fds+.
02613  *
02614  * +chfunc+ must not raise any exceptions.
02615  */
02616 rb_pid_t
02617 rb_fork_err(int *status, int (*chfunc)(void*, char *, size_t), void *charg, VALUE fds,
02618         char *errmsg, size_t errmsg_buflen)
02619 {
02620     rb_pid_t pid;
02621     int err, state = 0;
02622 #ifdef FD_CLOEXEC
02623     int ep[2];
02624     VALUE io = Qnil;
02625 #endif
02626 
02627 #define prefork() (             \
02628         rb_io_flush(rb_stdout), \
02629         rb_io_flush(rb_stderr)  \
02630         )
02631     prefork();
02632 
02633 #ifdef FD_CLOEXEC
02634     if (chfunc) {
02635         if (pipe_nocrash(ep, fds)) return -1;
02636         if (fcntl(ep[1], F_SETFD, FD_CLOEXEC)) {
02637             preserving_errno((close(ep[0]), close(ep[1])));
02638             return -1;
02639         }
02640     }
02641 #endif
02642     for (; before_fork(), (pid = fork()) < 0; prefork()) {
02643         after_fork();
02644         switch (errno) {
02645           case EAGAIN:
02646 #if defined(EWOULDBLOCK) && EWOULDBLOCK != EAGAIN
02647           case EWOULDBLOCK:
02648 #endif
02649             if (!status && !chfunc) {
02650                 rb_thread_sleep(1);
02651                 continue;
02652             }
02653             else {
02654                 rb_protect((VALUE (*)())rb_thread_sleep, 1, &state);
02655                 if (status) *status = state;
02656                 if (!state) continue;
02657             }
02658           default:
02659 #ifdef FD_CLOEXEC
02660             if (chfunc) {
02661                 preserving_errno((close(ep[0]), close(ep[1])));
02662             }
02663 #endif
02664             if (state && !status) rb_jump_tag(state);
02665             return -1;
02666         }
02667     }
02668     if (!pid) {
02669         forked_child = 1;
02670         if (chfunc) {
02671             struct chfunc_protect_t arg;
02672             arg.chfunc = chfunc;
02673             arg.arg = charg;
02674             arg.errmsg = errmsg;
02675             arg.buflen = errmsg_buflen;
02676 #ifdef FD_CLOEXEC
02677             close(ep[0]);
02678 #endif
02679             if (!(int)rb_protect(chfunc_protect, (VALUE)&arg, &state)) _exit(EXIT_SUCCESS);
02680 #ifdef FD_CLOEXEC
02681             if (write(ep[1], &state, sizeof(state)) == sizeof(state) && state) {
02682                 VALUE errinfo = rb_errinfo();
02683                 io = rb_io_fdopen(ep[1], O_WRONLY|O_BINARY, NULL);
02684                 rb_marshal_dump(errinfo, io);
02685                 rb_io_flush(io);
02686             }
02687             err = errno;
02688             if (write(ep[1], &err, sizeof(err)) < 0) err = errno;
02689             if (errmsg && 0 < errmsg_buflen) {
02690                 errmsg[errmsg_buflen-1] = '\0';
02691                 errmsg_buflen = strlen(errmsg);
02692                 if (errmsg_buflen > 0 &&write(ep[1], errmsg, errmsg_buflen) < 0)
02693                     err = errno;
02694             }
02695             if (!NIL_P(io)) rb_io_close(io);
02696 #endif
02697 #if EXIT_SUCCESS == 127
02698             _exit(EXIT_FAILURE);
02699 #else
02700             _exit(127);
02701 #endif
02702         }
02703     }
02704     after_fork();
02705 #ifdef FD_CLOEXEC
02706     if (pid && chfunc) {
02707         ssize_t size;
02708         VALUE exc = Qnil;
02709         close(ep[1]);
02710         if ((read(ep[0], &state, sizeof(state))) == sizeof(state) && state) {
02711             io = rb_io_fdopen(ep[0], O_RDONLY|O_BINARY, NULL);
02712             exc = rb_marshal_load(io);
02713             rb_set_errinfo(exc);
02714         }
02715 #define READ_FROM_CHILD(ptr, len) \
02716         (NIL_P(io) ? read(ep[0], (ptr), (len)) : rb_io_bufread(io, (ptr), (len)))
02717         if ((size = READ_FROM_CHILD(&err, sizeof(err))) < 0) {
02718             err = errno;
02719         }
02720         if (size == sizeof(err) &&
02721             errmsg && 0 < errmsg_buflen) {
02722             ssize_t ret = READ_FROM_CHILD(errmsg, errmsg_buflen-1);
02723             if (0 <= ret) {
02724                 errmsg[ret] = '\0';
02725             }
02726         }
02727         if (NIL_P(io))
02728             close(ep[0]);
02729         else
02730             rb_io_close(io);
02731         if (state || size) {
02732             if (status) {
02733                 *status = state;
02734                 rb_protect(proc_syswait, (VALUE)pid, status);
02735             }
02736             else {
02737                 rb_syswait(pid);
02738                 if (state) rb_exc_raise(exc);
02739             }
02740             errno = err;
02741             return -1;
02742         }
02743     }
02744 #endif
02745     return pid;
02746 }
02747 
02748 struct chfunc_wrapper_t {
02749     int (*chfunc)(void*);
02750     void *arg;
02751 };
02752 
02753 static int
02754 chfunc_wrapper(void *arg_, char *errmsg, size_t errmsg_buflen)
02755 {
02756     struct chfunc_wrapper_t *arg = arg_;
02757     return arg->chfunc(arg->arg);
02758 }
02759 
02760 rb_pid_t
02761 rb_fork(int *status, int (*chfunc)(void*), void *charg, VALUE fds)
02762 {
02763     if (chfunc) {
02764         struct chfunc_wrapper_t warg;
02765         warg.chfunc = chfunc;
02766         warg.arg = charg;
02767         return rb_fork_err(status, chfunc_wrapper, &warg, fds, NULL, 0);
02768     }
02769     else {
02770         return rb_fork_err(status, NULL, NULL, fds, NULL, 0);
02771     }
02772 
02773 }
02774 
02775 #endif
02776 
02777 #if defined(HAVE_FORK) && !defined(CANNOT_FORK_WITH_PTHREAD)
02778 /*
02779  *  call-seq:
02780  *     Kernel.fork  [{ block }]   -> fixnum or nil
02781  *     Process.fork [{ block }]   -> fixnum or nil
02782  *
02783  *  Creates a subprocess. If a block is specified, that block is run
02784  *  in the subprocess, and the subprocess terminates with a status of
02785  *  zero. Otherwise, the +fork+ call returns twice, once in
02786  *  the parent, returning the process ID of the child, and once in
02787  *  the child, returning _nil_. The child process can exit using
02788  *  <code>Kernel.exit!</code> to avoid running any
02789  *  <code>at_exit</code> functions. The parent process should
02790  *  use <code>Process.wait</code> to collect the termination statuses
02791  *  of its children or use <code>Process.detach</code> to register
02792  *  disinterest in their status; otherwise, the operating system
02793  *  may accumulate zombie processes.
02794  *
02795  *  The thread calling fork is the only thread in the created child process.
02796  *  fork doesn't copy other threads.
02797  *
02798  *  If fork is not usable, Process.respond_to?(:fork) returns false.
02799  */
02800 
02801 static VALUE
02802 rb_f_fork(VALUE obj)
02803 {
02804     rb_pid_t pid;
02805 
02806     rb_secure(2);
02807 
02808     switch (pid = rb_fork(0, 0, 0, Qnil)) {
02809       case 0:
02810         rb_thread_atfork();
02811         if (rb_block_given_p()) {
02812             int status;
02813 
02814             rb_protect(rb_yield, Qundef, &status);
02815             ruby_stop(status);
02816         }
02817         return Qnil;
02818 
02819       case -1:
02820         rb_sys_fail("fork(2)");
02821         return Qnil;
02822 
02823       default:
02824         return PIDT2NUM(pid);
02825     }
02826 }
02827 #else
02828 #define rb_f_fork rb_f_notimplement
02829 #endif
02830 
02831 /*
02832  *  call-seq:
02833  *     Process.exit!(status=false)
02834  *
02835  *  Exits the process immediately. No exit handlers are
02836  *  run. <em>status</em> is returned to the underlying system as the
02837  *  exit status.
02838  *
02839  *     Process.exit!(true)
02840  */
02841 
02842 static VALUE
02843 rb_f_exit_bang(int argc, VALUE *argv, VALUE obj)
02844 {
02845     VALUE status;
02846     int istatus;
02847 
02848     rb_secure(4);
02849     if (argc > 0 && rb_scan_args(argc, argv, "01", &status) == 1) {
02850         switch (status) {
02851           case Qtrue:
02852             istatus = EXIT_SUCCESS;
02853             break;
02854           case Qfalse:
02855             istatus = EXIT_FAILURE;
02856             break;
02857           default:
02858             istatus = NUM2INT(status);
02859             break;
02860         }
02861     }
02862     else {
02863         istatus = EXIT_FAILURE;
02864     }
02865     _exit(istatus);
02866 
02867     return Qnil;                /* not reached */
02868 }
02869 
02870 void
02871 rb_exit(int status)
02872 {
02873     if (GET_THREAD()->tag) {
02874         VALUE args[2];
02875 
02876         args[0] = INT2NUM(status);
02877         args[1] = rb_str_new2("exit");
02878         rb_exc_raise(rb_class_new_instance(2, args, rb_eSystemExit));
02879     }
02880     ruby_finalize();
02881     exit(status);
02882 }
02883 
02884 
02885 /*
02886  *  call-seq:
02887  *     exit(status=true)
02888  *     Kernel::exit(status=true)
02889  *     Process::exit(status=true)
02890  *
02891  *  Initiates the termination of the Ruby script by raising the
02892  *  <code>SystemExit</code> exception. This exception may be caught. The
02893  *  optional parameter is used to return a status code to the invoking
02894  *  environment.
02895  *  +true+ and +FALSE+ of _status_ means success and failure
02896  *  respectively.  The interpretation of other integer values are
02897  *  system dependent.
02898  *
02899  *     begin
02900  *       exit
02901  *       puts "never get here"
02902  *     rescue SystemExit
02903  *       puts "rescued a SystemExit exception"
02904  *     end
02905  *     puts "after begin block"
02906  *
02907  *  <em>produces:</em>
02908  *
02909  *     rescued a SystemExit exception
02910  *     after begin block
02911  *
02912  *  Just prior to termination, Ruby executes any <code>at_exit</code> functions
02913  *  (see Kernel::at_exit) and runs any object finalizers (see
02914  *  ObjectSpace::define_finalizer).
02915  *
02916  *     at_exit { puts "at_exit function" }
02917  *     ObjectSpace.define_finalizer("string",  proc { puts "in finalizer" })
02918  *     exit
02919  *
02920  *  <em>produces:</em>
02921  *
02922  *     at_exit function
02923  *     in finalizer
02924  */
02925 
02926 VALUE
02927 rb_f_exit(int argc, VALUE *argv)
02928 {
02929     VALUE status;
02930     int istatus;
02931 
02932     rb_secure(4);
02933     if (argc > 0 && rb_scan_args(argc, argv, "01", &status) == 1) {
02934         switch (status) {
02935           case Qtrue:
02936             istatus = EXIT_SUCCESS;
02937             break;
02938           case Qfalse:
02939             istatus = EXIT_FAILURE;
02940             break;
02941           default:
02942             istatus = NUM2INT(status);
02943 #if EXIT_SUCCESS != 0
02944             if (istatus == 0)
02945                 istatus = EXIT_SUCCESS;
02946 #endif
02947             break;
02948         }
02949     }
02950     else {
02951         istatus = EXIT_SUCCESS;
02952     }
02953     rb_exit(istatus);
02954     return Qnil;                /* not reached */
02955 }
02956 
02957 
02958 /*
02959  *  call-seq:
02960  *     abort
02961  *     Kernel::abort([msg])
02962  *     Process::abort([msg])
02963  *
02964  *  Terminate execution immediately, effectively by calling
02965  *  <code>Kernel.exit(false)</code>. If _msg_ is given, it is written
02966  *  to STDERR prior to terminating.
02967  */
02968 
02969 VALUE
02970 rb_f_abort(int argc, VALUE *argv)
02971 {
02972     rb_secure(4);
02973     if (argc == 0) {
02974         if (!NIL_P(GET_THREAD()->errinfo)) {
02975             ruby_error_print();
02976         }
02977         rb_exit(EXIT_FAILURE);
02978     }
02979     else {
02980         VALUE args[2];
02981 
02982         rb_scan_args(argc, argv, "1", &args[1]);
02983         StringValue(argv[0]);
02984         rb_io_puts(argc, argv, rb_stderr);
02985         args[0] = INT2NUM(EXIT_FAILURE);
02986         rb_exc_raise(rb_class_new_instance(2, args, rb_eSystemExit));
02987     }
02988     return Qnil;                /* not reached */
02989 }
02990 
02991 void
02992 rb_syswait(rb_pid_t pid)
02993 {
02994     static int overriding;
02995 #ifdef SIGHUP
02996     RETSIGTYPE (*hfunc)(int) = 0;
02997 #endif
02998 #ifdef SIGQUIT
02999     RETSIGTYPE (*qfunc)(int) = 0;
03000 #endif
03001     RETSIGTYPE (*ifunc)(int) = 0;
03002     int status;
03003     int i, hooked = FALSE;
03004 
03005     if (!overriding) {
03006 #ifdef SIGHUP
03007         hfunc = signal(SIGHUP, SIG_IGN);
03008 #endif
03009 #ifdef SIGQUIT
03010         qfunc = signal(SIGQUIT, SIG_IGN);
03011 #endif
03012         ifunc = signal(SIGINT, SIG_IGN);
03013         overriding = TRUE;
03014         hooked = TRUE;
03015     }
03016 
03017     do {
03018         i = rb_waitpid(pid, &status, 0);
03019     } while (i == -1 && errno == EINTR);
03020 
03021     if (hooked) {
03022 #ifdef SIGHUP
03023         signal(SIGHUP, hfunc);
03024 #endif
03025 #ifdef SIGQUIT
03026         signal(SIGQUIT, qfunc);
03027 #endif
03028         signal(SIGINT, ifunc);
03029         overriding = FALSE;
03030     }
03031 }
03032 
03033 static VALUE
03034 rb_exec_arg_prepare(struct rb_exec_arg *earg, int argc, VALUE *argv, int default_close_others)
03035 {
03036     VALUE prog = rb_exec_arg_init(argc, argv, TRUE, earg);
03037     if (NIL_P(rb_ary_entry(earg->options, EXEC_OPTION_CLOSE_OTHERS))) {
03038         VALUE v = default_close_others ? Qtrue : Qfalse;
03039         rb_exec_arg_addopt(earg, ID2SYM(rb_intern("close_others")), v);
03040     }
03041     rb_exec_arg_fixup(earg);
03042     return prog;
03043 }
03044 
03045 static rb_pid_t
03046 rb_spawn_process(struct rb_exec_arg *earg, VALUE prog, char *errmsg, size_t errmsg_buflen)
03047 {
03048     rb_pid_t pid;
03049 #if !USE_SPAWNV
03050     int status;
03051 #endif
03052 #if !defined HAVE_FORK || USE_SPAWNV
03053     struct rb_exec_arg sarg;
03054     int argc;
03055     VALUE *argv;
03056 #endif
03057 
03058 #if defined HAVE_FORK && !USE_SPAWNV
03059     pid = rb_fork_err(&status, rb_exec_atfork, earg, earg->redirect_fds, errmsg, errmsg_buflen);
03060 #else
03061     if (rb_run_exec_options_err(earg, &sarg, errmsg, errmsg_buflen) < 0) {
03062         return -1;
03063     }
03064 
03065     argc = earg->argc;
03066     argv = earg->argv;
03067     if (prog && argc) argv[0] = prog;
03068 # if defined HAVE_SPAWNV
03069     if (!argc) {
03070         pid = proc_spawn(RSTRING_PTR(prog));
03071     }
03072     else {
03073         pid = proc_spawn_n(argc, argv, prog, earg->options);
03074     }
03075 #  if defined(_WIN32)
03076     if (pid == -1)
03077         rb_last_status_set(0x7f << 8, 0);
03078 #  endif
03079 # else
03080     if (argc) prog = rb_ary_join(rb_ary_new4(argc, argv), rb_str_new2(" "));
03081     status = system(StringValuePtr(prog));
03082     rb_last_status_set((status & 0xff) << 8, 0);
03083 # endif
03084 
03085     rb_run_exec_options_err(&sarg, NULL, errmsg, errmsg_buflen);
03086 #endif
03087     return pid;
03088 }
03089 
03090 static rb_pid_t
03091 rb_spawn_internal(int argc, VALUE *argv, int default_close_others,
03092                   char *errmsg, size_t errmsg_buflen)
03093 {
03094     struct rb_exec_arg earg;
03095     VALUE prog = rb_exec_arg_prepare(&earg, argc, argv, default_close_others);
03096     return rb_spawn_process(&earg, prog, errmsg, errmsg_buflen);
03097 }
03098 
03099 rb_pid_t
03100 rb_spawn_err(int argc, VALUE *argv, char *errmsg, size_t errmsg_buflen)
03101 {
03102     return rb_spawn_internal(argc, argv, TRUE, errmsg, errmsg_buflen);
03103 }
03104 
03105 rb_pid_t
03106 rb_spawn(int argc, VALUE *argv)
03107 {
03108     return rb_spawn_internal(argc, argv, TRUE, NULL, 0);
03109 }
03110 
03111 /*
03112  *  call-seq:
03113  *     system([env,] command... [,options])    -> true, false or nil
03114  *
03115  *  Executes _command..._ in a subshell.
03116  *  _command..._ is one of following forms.
03117  *
03118  *    commandline                 : command line string which is passed to the standard shell
03119  *    cmdname, arg1, ...          : command name and one or more arguments (no shell)
03120  *    [cmdname, argv0], arg1, ... : command name, argv[0] and zero or more arguments (no shell)
03121  *
03122  *  system returns +true+ if the command gives zero exit status,
03123  *  +false+ for non zero exit status.
03124  *  Returns +nil+ if command execution fails.
03125  *  An error status is available in <code>$?</code>.
03126  *  The arguments are processed in the same way as
03127  *  for <code>Kernel.spawn</code>.
03128  *
03129  *  The hash arguments, env and options, are same as
03130  *  <code>exec</code> and <code>spawn</code>.
03131  *  See <code>Kernel.spawn</code> for details.
03132  *
03133  *     system("echo *")
03134  *     system("echo", "*")
03135  *
03136  *  <em>produces:</em>
03137  *
03138  *     config.h main.rb
03139  *     *
03140  *
03141  *  See <code>Kernel.exec</code> for the standard shell.
03142  */
03143 
03144 static VALUE
03145 rb_f_system(int argc, VALUE *argv)
03146 {
03147     rb_pid_t pid;
03148     int status;
03149 
03150 #if defined(SIGCLD) && !defined(SIGCHLD)
03151 # define SIGCHLD SIGCLD
03152 #endif
03153 
03154 #ifdef SIGCHLD
03155     RETSIGTYPE (*chfunc)(int);
03156 
03157     chfunc = signal(SIGCHLD, SIG_DFL);
03158 #endif
03159     pid = rb_spawn_internal(argc, argv, FALSE, NULL, 0);
03160 #if defined(HAVE_FORK) || defined(HAVE_SPAWNV)
03161     if (pid > 0) {
03162         rb_syswait(pid);
03163     }
03164 #endif
03165 #ifdef SIGCHLD
03166     signal(SIGCHLD, chfunc);
03167 #endif
03168     if (pid < 0) {
03169         return Qnil;
03170     }
03171     status = PST2INT(rb_last_status_get());
03172     if (status == EXIT_SUCCESS) return Qtrue;
03173     return Qfalse;
03174 }
03175 
03176 /*
03177  *  call-seq:
03178  *     spawn([env,] command... [,options])     -> pid
03179  *     Process.spawn([env,] command... [,options])     -> pid
03180  *
03181  *  spawn executes specified command and return its pid.
03182  *
03183  *  This method doesn't wait for end of the command.
03184  *  The parent process should
03185  *  use <code>Process.wait</code> to collect
03186  *  the termination status of its child or
03187  *  use <code>Process.detach</code> to register
03188  *  disinterest in their status;
03189  *  otherwise, the operating system may accumulate zombie processes.
03190  *
03191  *  spawn has bunch of options to specify process attributes:
03192  *
03193  *    env: hash
03194  *      name => val : set the environment variable
03195  *      name => nil : unset the environment variable
03196  *    command...:
03197  *      commandline                 : command line string which is passed to the standard shell
03198  *      cmdname, arg1, ...          : command name and one or more arguments (no shell)
03199  *      [cmdname, argv0], arg1, ... : command name, argv[0] and zero or more arguments (no shell)
03200  *    options: hash
03201  *      clearing environment variables:
03202  *        :unsetenv_others => true   : clear environment variables except specified by env
03203  *        :unsetenv_others => false  : don't clear (default)
03204  *      process group:
03205  *        :pgroup => true or 0 : make a new process group
03206  *        :pgroup => pgid      : join to specified process group
03207  *        :pgroup => nil       : don't change the process group (default)
03208  *      create new process group: Windows only
03209  *        :new_pgroup => true  : the new process is the root process of a new process group
03210  *        :new_pgroup => false : don't create a new process group (default)
03211  *      resource limit: resourcename is core, cpu, data, etc.  See Process.setrlimit.
03212  *        :rlimit_resourcename => limit
03213  *        :rlimit_resourcename => [cur_limit, max_limit]
03214  *      current directory:
03215  *        :chdir => str
03216  *      umask:
03217  *        :umask => int
03218  *      redirection:
03219  *        key:
03220  *          FD              : single file descriptor in child process
03221  *          [FD, FD, ...]   : multiple file descriptor in child process
03222  *        value:
03223  *          FD                        : redirect to the file descriptor in parent process
03224  *          string                    : redirect to file with open(string, "r" or "w")
03225  *          [string]                  : redirect to file with open(string, File::RDONLY)
03226  *          [string, open_mode]       : redirect to file with open(string, open_mode, 0644)
03227  *          [string, open_mode, perm] : redirect to file with open(string, open_mode, perm)
03228  *          [:child, FD]              : redirect to the redirected file descriptor
03229  *          :close                    : close the file descriptor in child process
03230  *        FD is one of follows
03231  *          :in     : the file descriptor 0 which is the standard input
03232  *          :out    : the file descriptor 1 which is the standard output
03233  *          :err    : the file descriptor 2 which is the standard error
03234  *          integer : the file descriptor of specified the integer
03235  *          io      : the file descriptor specified as io.fileno
03236  *      file descriptor inheritance: close non-redirected non-standard fds (3, 4, 5, ...) or not
03237  *        :close_others => false : inherit fds (default for system and exec)
03238  *        :close_others => true  : don't inherit (default for spawn and IO.popen)
03239  *
03240  *  If a hash is given as +env+, the environment is
03241  *  updated by +env+ before <code>exec(2)</code> in the child process.
03242  *  If a pair in +env+ has nil as the value, the variable is deleted.
03243  *
03244  *    # set FOO as BAR and unset BAZ.
03245  *    pid = spawn({"FOO"=>"BAR", "BAZ"=>nil}, command)
03246  *
03247  *  If a hash is given as +options+,
03248  *  it specifies
03249  *  process group,
03250  *  create new process group,
03251  *  resource limit,
03252  *  current directory,
03253  *  umask and
03254  *  redirects for the child process.
03255  *  Also, it can be specified to clear environment variables.
03256  *
03257  *  The <code>:unsetenv_others</code> key in +options+ specifies
03258  *  to clear environment variables, other than specified by +env+.
03259  *
03260  *    pid = spawn(command, :unsetenv_others=>true) # no environment variable
03261  *    pid = spawn({"FOO"=>"BAR"}, command, :unsetenv_others=>true) # FOO only
03262  *
03263  *  The <code>:pgroup</code> key in +options+ specifies a process group.
03264  *  The corresponding value should be true, zero or positive integer.
03265  *  true and zero means the process should be a process leader of a new
03266  *  process group.
03267  *  Other values specifies a process group to be belongs.
03268  *
03269  *    pid = spawn(command, :pgroup=>true) # process leader
03270  *    pid = spawn(command, :pgroup=>10) # belongs to the process group 10
03271  *
03272  *  The <code>:new_pgroup</code> key in +options+ specifies to pass
03273  *  +CREATE_NEW_PROCESS_GROUP+ flag to <code>CreateProcessW()</code> that is
03274  *  Windows API. This option is only for Windows.
03275  *  true means the new process is the root process of the new process group.
03276  *  The new process has CTRL+C disabled. This flag is necessary for
03277  *  <code>Process.kill(:SIGINT, pid)</code> on the subprocess.
03278  *  :new_pgroup is false by default.
03279  *
03280  *    pid = spawn(command, :new_pgroup=>true)  # new process group
03281  *    pid = spawn(command, :new_pgroup=>false) # same process group
03282  *
03283  *  The <code>:rlimit_</code><em>foo</em> key specifies a resource limit.
03284  *  <em>foo</em> should be one of resource types such as <code>core</code>.
03285  *  The corresponding value should be an integer or an array which have one or
03286  *  two integers: same as cur_limit and max_limit arguments for
03287  *  Process.setrlimit.
03288  *
03289  *    cur, max = Process.getrlimit(:CORE)
03290  *    pid = spawn(command, :rlimit_core=>[0,max]) # disable core temporary.
03291  *    pid = spawn(command, :rlimit_core=>max) # enable core dump
03292  *    pid = spawn(command, :rlimit_core=>0) # never dump core.
03293  *
03294  *  The <code>:chdir</code> key in +options+ specifies the current directory.
03295  *
03296  *    pid = spawn(command, :chdir=>"/var/tmp")
03297  *
03298  *  The <code>:umask</code> key in +options+ specifies the umask.
03299  *
03300  *    pid = spawn(command, :umask=>077)
03301  *
03302  *  The :in, :out, :err, a fixnum, an IO and an array key specifies a redirection.
03303  *  The redirection maps a file descriptor in the child process.
03304  *
03305  *  For example, stderr can be merged into stdout as follows:
03306  *
03307  *    pid = spawn(command, :err=>:out)
03308  *    pid = spawn(command, 2=>1)
03309  *    pid = spawn(command, STDERR=>:out)
03310  *    pid = spawn(command, STDERR=>STDOUT)
03311  *
03312  *  The hash keys specifies a file descriptor
03313  *  in the child process started by <code>spawn</code>.
03314  *  :err, 2 and STDERR specifies the standard error stream (stderr).
03315  *
03316  *  The hash values specifies a file descriptor
03317  *  in the parent process which invokes <code>spawn</code>.
03318  *  :out, 1 and STDOUT specifies the standard output stream (stdout).
03319  *
03320  *  In the above example,
03321  *  the standard output in the child process is not specified.
03322  *  So it is inherited from the parent process.
03323  *
03324  *  The standard input stream (stdin) can be specified by :in, 0 and STDIN.
03325  *
03326  *  A filename can be specified as a hash value.
03327  *
03328  *    pid = spawn(command, :in=>"/dev/null") # read mode
03329  *    pid = spawn(command, :out=>"/dev/null") # write mode
03330  *    pid = spawn(command, :err=>"log") # write mode
03331  *    pid = spawn(command, 3=>"/dev/null") # read mode
03332  *
03333  *  For stdout and stderr,
03334  *  it is opened in write mode.
03335  *  Otherwise read mode is used.
03336  *
03337  *  For specifying flags and permission of file creation explicitly,
03338  *  an array is used instead.
03339  *
03340  *    pid = spawn(command, :in=>["file"]) # read mode is assumed
03341  *    pid = spawn(command, :in=>["file", "r"])
03342  *    pid = spawn(command, :out=>["log", "w"]) # 0644 assumed
03343  *    pid = spawn(command, :out=>["log", "w", 0600])
03344  *    pid = spawn(command, :out=>["log", File::WRONLY|File::EXCL|File::CREAT, 0600])
03345  *
03346  *  The array specifies a filename, flags and permission.
03347  *  The flags can be a string or an integer.
03348  *  If the flags is omitted or nil, File::RDONLY is assumed.
03349  *  The permission should be an integer.
03350  *  If the permission is omitted or nil, 0644 is assumed.
03351  *
03352  *  If an array of IOs and integers are specified as a hash key,
03353  *  all the elements are redirected.
03354  *
03355  *    # stdout and stderr is redirected to log file.
03356  *    # The file "log" is opened just once.
03357  *    pid = spawn(command, [:out, :err]=>["log", "w"])
03358  *
03359  *  Another way to merge multiple file descriptors is [:child, fd].
03360  *  \[:child, fd] means the file descriptor in the child process.
03361  *  This is different from fd.
03362  *  For example, :err=>:out means redirecting child stderr to parent stdout.
03363  *  But :err=>[:child, :out] means redirecting child stderr to child stdout.
03364  *  They differs if stdout is redirected in the child process as follows.
03365  *
03366  *    # stdout and stderr is redirected to log file.
03367  *    # The file "log" is opened just once.
03368  *    pid = spawn(command, :out=>["log", "w"], :err=>[:child, :out])
03369  *
03370  *  \[:child, :out] can be used to merge stderr into stdout in IO.popen.
03371  *  In this case, IO.popen redirects stdout to a pipe in the child process
03372  *  and [:child, :out] refers the redirected stdout.
03373  *
03374  *    io = IO.popen(["sh", "-c", "echo out; echo err >&2", :err=>[:child, :out]])
03375  *    p io.read #=> "out\nerr\n"
03376  *
03377  *  spawn closes all non-standard unspecified descriptors by default.
03378  *  The "standard" descriptors are 0, 1 and 2.
03379  *  This behavior is specified by :close_others option.
03380  *  :close_others doesn't affect the standard descriptors which are
03381  *  closed only if :close is specified explicitly.
03382  *
03383  *    pid = spawn(command, :close_others=>true)  # close 3,4,5,... (default)
03384  *    pid = spawn(command, :close_others=>false) # don't close 3,4,5,...
03385  *
03386  *  :close_others is true by default for spawn and IO.popen.
03387  *
03388  *  So IO.pipe and spawn can be used as IO.popen.
03389  *
03390  *    # similar to r = IO.popen(command)
03391  *    r, w = IO.pipe
03392  *    pid = spawn(command, :out=>w)   # r, w is closed in the child process.
03393  *    w.close
03394  *
03395  *  :close is specified as a hash value to close a fd individually.
03396  *
03397  *    f = open(foo)
03398  *    system(command, f=>:close)        # don't inherit f.
03399  *
03400  *  If a file descriptor need to be inherited,
03401  *  io=>io can be used.
03402  *
03403  *    # valgrind has --log-fd option for log destination.
03404  *    # log_w=>log_w indicates log_w.fileno inherits to child process.
03405  *    log_r, log_w = IO.pipe
03406  *    pid = spawn("valgrind", "--log-fd=#{log_w.fileno}", "echo", "a", log_w=>log_w)
03407  *    log_w.close
03408  *    p log_r.read
03409  *
03410  *  It is also possible to exchange file descriptors.
03411  *
03412  *    pid = spawn(command, :out=>:err, :err=>:out)
03413  *
03414  *  The hash keys specify file descriptors in the child process.
03415  *  The hash values specifies file descriptors in the parent process.
03416  *  So the above specifies exchanging stdout and stderr.
03417  *  Internally, +spawn+ uses an extra file descriptor to resolve such cyclic
03418  *  file descriptor mapping.
03419  *
03420  *  See <code>Kernel.exec</code> for the standard shell.
03421  */
03422 
03423 static VALUE
03424 rb_f_spawn(int argc, VALUE *argv)
03425 {
03426     rb_pid_t pid;
03427     char errmsg[CHILD_ERRMSG_BUFLEN] = { '\0' };
03428     struct rb_exec_arg earg;
03429 
03430     pid = rb_spawn_process(&earg, rb_exec_arg_prepare(&earg, argc, argv, TRUE), errmsg, sizeof(errmsg));
03431     if (pid == -1) {
03432         const char *prog = errmsg;
03433         if (!prog[0] && !(prog = earg.prog) && earg.argc) {
03434             prog = RSTRING_PTR(earg.argv[0]);
03435         }
03436         rb_sys_fail(prog);
03437     }
03438 #if defined(HAVE_FORK) || defined(HAVE_SPAWNV)
03439     return PIDT2NUM(pid);
03440 #else
03441     return Qnil;
03442 #endif
03443 }
03444 
03445 /*
03446  *  call-seq:
03447  *     sleep([duration])    -> fixnum
03448  *
03449  *  Suspends the current thread for _duration_ seconds (which may be any number,
03450  *  including a +Float+ with fractional seconds). Returns the actual number of
03451  *  seconds slept (rounded), which may be less than that asked for if another
03452  *  thread calls <code>Thread#run</code>. Called without an argument, sleep()
03453  *  will sleep forever.
03454  *
03455  *     Time.new    #=> 2008-03-08 19:56:19 +0900
03456  *     sleep 1.2   #=> 1
03457  *     Time.new    #=> 2008-03-08 19:56:20 +0900
03458  *     sleep 1.9   #=> 2
03459  *     Time.new    #=> 2008-03-08 19:56:22 +0900
03460  */
03461 
03462 static VALUE
03463 rb_f_sleep(int argc, VALUE *argv)
03464 {
03465     time_t beg, end;
03466 
03467     beg = time(0);
03468     if (argc == 0) {
03469         rb_thread_sleep_forever();
03470     }
03471     else if (argc == 1) {
03472         rb_thread_wait_for(rb_time_interval(argv[0]));
03473     }
03474     else {
03475         rb_raise(rb_eArgError, "wrong number of arguments (%d for 0..1)", argc);
03476     }
03477 
03478     end = time(0) - beg;
03479 
03480     return INT2FIX(end);
03481 }
03482 
03483 
03484 #if (defined(HAVE_GETPGRP) && defined(GETPGRP_VOID)) || defined(HAVE_GETPGID)
03485 /*
03486  *  call-seq:
03487  *     Process.getpgrp   -> integer
03488  *
03489  *  Returns the process group ID for this process. Not available on
03490  *  all platforms.
03491  *
03492  *     Process.getpgid(0)   #=> 25527
03493  *     Process.getpgrp      #=> 25527
03494  */
03495 
03496 static VALUE
03497 proc_getpgrp(void)
03498 {
03499     rb_pid_t pgrp;
03500 
03501     rb_secure(2);
03502 #if defined(HAVE_GETPGRP) && defined(GETPGRP_VOID)
03503     pgrp = getpgrp();
03504     if (pgrp < 0) rb_sys_fail(0);
03505     return PIDT2NUM(pgrp);
03506 #else /* defined(HAVE_GETPGID) */
03507     pgrp = getpgid(0);
03508     if (pgrp < 0) rb_sys_fail(0);
03509     return PIDT2NUM(pgrp);
03510 #endif
03511 }
03512 #else
03513 #define proc_getpgrp rb_f_notimplement
03514 #endif
03515 
03516 
03517 #if defined(HAVE_SETPGID) || (defined(HAVE_SETPGRP) && defined(SETPGRP_VOID))
03518 /*
03519  *  call-seq:
03520  *     Process.setpgrp   -> 0
03521  *
03522  *  Equivalent to <code>setpgid(0,0)</code>. Not available on all
03523  *  platforms.
03524  */
03525 
03526 static VALUE
03527 proc_setpgrp(void)
03528 {
03529     rb_secure(2);
03530   /* check for posix setpgid() first; this matches the posix */
03531   /* getpgrp() above.  It appears that configure will set SETPGRP_VOID */
03532   /* even though setpgrp(0,0) would be preferred. The posix call avoids */
03533   /* this confusion. */
03534 #ifdef HAVE_SETPGID
03535     if (setpgid(0,0) < 0) rb_sys_fail(0);
03536 #elif defined(HAVE_SETPGRP) && defined(SETPGRP_VOID)
03537     if (setpgrp() < 0) rb_sys_fail(0);
03538 #endif
03539     return INT2FIX(0);
03540 }
03541 #else
03542 #define proc_setpgrp rb_f_notimplement
03543 #endif
03544 
03545 
03546 #if defined(HAVE_GETPGID)
03547 /*
03548  *  call-seq:
03549  *     Process.getpgid(pid)   -> integer
03550  *
03551  *  Returns the process group ID for the given process id. Not
03552  *  available on all platforms.
03553  *
03554  *     Process.getpgid(Process.ppid())   #=> 25527
03555  */
03556 
03557 static VALUE
03558 proc_getpgid(VALUE obj, VALUE pid)
03559 {
03560     rb_pid_t i;
03561 
03562     rb_secure(2);
03563     i = getpgid(NUM2PIDT(pid));
03564     if (i < 0) rb_sys_fail(0);
03565     return PIDT2NUM(i);
03566 }
03567 #else
03568 #define proc_getpgid rb_f_notimplement
03569 #endif
03570 
03571 
03572 #ifdef HAVE_SETPGID
03573 /*
03574  *  call-seq:
03575  *     Process.setpgid(pid, integer)   -> 0
03576  *
03577  *  Sets the process group ID of _pid_ (0 indicates this
03578  *  process) to <em>integer</em>. Not available on all platforms.
03579  */
03580 
03581 static VALUE
03582 proc_setpgid(VALUE obj, VALUE pid, VALUE pgrp)
03583 {
03584     rb_pid_t ipid, ipgrp;
03585 
03586     rb_secure(2);
03587     ipid = NUM2PIDT(pid);
03588     ipgrp = NUM2PIDT(pgrp);
03589 
03590     if (setpgid(ipid, ipgrp) < 0) rb_sys_fail(0);
03591     return INT2FIX(0);
03592 }
03593 #else
03594 #define proc_setpgid rb_f_notimplement
03595 #endif
03596 
03597 
03598 #if defined(HAVE_SETSID) || (defined(HAVE_SETPGRP) && defined(TIOCNOTTY))
03599 #if !defined(HAVE_SETSID)
03600 static rb_pid_t ruby_setsid(void);
03601 #define setsid() ruby_setsid()
03602 #endif
03603 /*
03604  *  call-seq:
03605  *     Process.setsid   -> fixnum
03606  *
03607  *  Establishes this process as a new session and process group
03608  *  leader, with no controlling tty. Returns the session id. Not
03609  *  available on all platforms.
03610  *
03611  *     Process.setsid   #=> 27422
03612  */
03613 
03614 static VALUE
03615 proc_setsid(void)
03616 {
03617     rb_pid_t pid;
03618 
03619     rb_secure(2);
03620     pid = setsid();
03621     if (pid < 0) rb_sys_fail(0);
03622     return PIDT2NUM(pid);
03623 }
03624 
03625 #if !defined(HAVE_SETSID)
03626 #define HAVE_SETSID 1
03627 static rb_pid_t
03628 ruby_setsid(void)
03629 {
03630     rb_pid_t pid;
03631     int ret;
03632 
03633     pid = getpid();
03634 #if defined(SETPGRP_VOID)
03635     ret = setpgrp();
03636     /* If `pid_t setpgrp(void)' is equivalent to setsid(),
03637        `ret' will be the same value as `pid', and following open() will fail.
03638        In Linux, `int setpgrp(void)' is equivalent to setpgid(0, 0). */
03639 #else
03640     ret = setpgrp(0, pid);
03641 #endif
03642     if (ret == -1) return -1;
03643 
03644     if ((fd = open("/dev/tty", O_RDWR)) >= 0) {
03645         rb_update_max_fd(fd);
03646         ioctl(fd, TIOCNOTTY, NULL);
03647         close(fd);
03648     }
03649     return pid;
03650 }
03651 #endif
03652 #else
03653 #define proc_setsid rb_f_notimplement
03654 #endif
03655 
03656 
03657 #ifdef HAVE_GETPRIORITY
03658 /*
03659  *  call-seq:
03660  *     Process.getpriority(kind, integer)   -> fixnum
03661  *
03662  *  Gets the scheduling priority for specified process, process group,
03663  *  or user. <em>kind</em> indicates the kind of entity to find: one
03664  *  of <code>Process::PRIO_PGRP</code>,
03665  *  <code>Process::PRIO_USER</code>, or
03666  *  <code>Process::PRIO_PROCESS</code>. _integer_ is an id
03667  *  indicating the particular process, process group, or user (an id
03668  *  of 0 means _current_). Lower priorities are more favorable
03669  *  for scheduling. Not available on all platforms.
03670  *
03671  *     Process.getpriority(Process::PRIO_USER, 0)      #=> 19
03672  *     Process.getpriority(Process::PRIO_PROCESS, 0)   #=> 19
03673  */
03674 
03675 static VALUE
03676 proc_getpriority(VALUE obj, VALUE which, VALUE who)
03677 {
03678     int prio, iwhich, iwho;
03679 
03680     rb_secure(2);
03681     iwhich = NUM2INT(which);
03682     iwho   = NUM2INT(who);
03683 
03684     errno = 0;
03685     prio = getpriority(iwhich, iwho);
03686     if (errno) rb_sys_fail(0);
03687     return INT2FIX(prio);
03688 }
03689 #else
03690 #define proc_getpriority rb_f_notimplement
03691 #endif
03692 
03693 
03694 #ifdef HAVE_GETPRIORITY
03695 /*
03696  *  call-seq:
03697  *     Process.setpriority(kind, integer, priority)   -> 0
03698  *
03699  *  See <code>Process#getpriority</code>.
03700  *
03701  *     Process.setpriority(Process::PRIO_USER, 0, 19)      #=> 0
03702  *     Process.setpriority(Process::PRIO_PROCESS, 0, 19)   #=> 0
03703  *     Process.getpriority(Process::PRIO_USER, 0)          #=> 19
03704  *     Process.getpriority(Process::PRIO_PROCESS, 0)       #=> 19
03705  */
03706 
03707 static VALUE
03708 proc_setpriority(VALUE obj, VALUE which, VALUE who, VALUE prio)
03709 {
03710     int iwhich, iwho, iprio;
03711 
03712     rb_secure(2);
03713     iwhich = NUM2INT(which);
03714     iwho   = NUM2INT(who);
03715     iprio  = NUM2INT(prio);
03716 
03717     if (setpriority(iwhich, iwho, iprio) < 0)
03718         rb_sys_fail(0);
03719     return INT2FIX(0);
03720 }
03721 #else
03722 #define proc_setpriority rb_f_notimplement
03723 #endif
03724 
03725 #if defined(HAVE_SETRLIMIT) && defined(NUM2RLIM)
03726 static int
03727 rlimit_resource_name2int(const char *name, int casetype)
03728 {
03729     int resource;
03730     const char *p;
03731 #define RESCHECK(r) \
03732     do { \
03733         if (STRCASECMP(name, #r) == 0) { \
03734             resource = RLIMIT_##r; \
03735             goto found; \
03736         } \
03737     } while (0)
03738 
03739     switch (TOUPPER(*name)) {
03740       case 'A':
03741 #ifdef RLIMIT_AS
03742         RESCHECK(AS);
03743 #endif
03744         break;
03745 
03746       case 'C':
03747 #ifdef RLIMIT_CORE
03748         RESCHECK(CORE);
03749 #endif
03750 #ifdef RLIMIT_CPU
03751         RESCHECK(CPU);
03752 #endif
03753         break;
03754 
03755       case 'D':
03756 #ifdef RLIMIT_DATA
03757         RESCHECK(DATA);
03758 #endif
03759         break;
03760 
03761       case 'F':
03762 #ifdef RLIMIT_FSIZE
03763         RESCHECK(FSIZE);
03764 #endif
03765         break;
03766 
03767       case 'M':
03768 #ifdef RLIMIT_MEMLOCK
03769         RESCHECK(MEMLOCK);
03770 #endif
03771 #ifdef RLIMIT_MSGQUEUE
03772         RESCHECK(MSGQUEUE);
03773 #endif
03774         break;
03775 
03776       case 'N':
03777 #ifdef RLIMIT_NOFILE
03778         RESCHECK(NOFILE);
03779 #endif
03780 #ifdef RLIMIT_NPROC
03781         RESCHECK(NPROC);
03782 #endif
03783 #ifdef RLIMIT_NICE
03784         RESCHECK(NICE);
03785 #endif
03786         break;
03787 
03788       case 'R':
03789 #ifdef RLIMIT_RSS
03790         RESCHECK(RSS);
03791 #endif
03792 #ifdef RLIMIT_RTPRIO
03793         RESCHECK(RTPRIO);
03794 #endif
03795 #ifdef RLIMIT_RTTIME
03796         RESCHECK(RTTIME);
03797 #endif
03798         break;
03799 
03800       case 'S':
03801 #ifdef RLIMIT_STACK
03802         RESCHECK(STACK);
03803 #endif
03804 #ifdef RLIMIT_SBSIZE
03805         RESCHECK(SBSIZE);
03806 #endif
03807 #ifdef RLIMIT_SIGPENDING
03808         RESCHECK(SIGPENDING);
03809 #endif
03810         break;
03811     }
03812     return -1;
03813 
03814   found:
03815     switch (casetype) {
03816       case 0:
03817         for (p = name; *p; p++)
03818             if (!ISUPPER(*p))
03819                 return -1;
03820         break;
03821 
03822       case 1:
03823         for (p = name; *p; p++)
03824             if (!ISLOWER(*p))
03825                 return -1;
03826         break;
03827 
03828       default:
03829         rb_bug("unexpected casetype");
03830     }
03831     return resource;
03832 #undef RESCHECK
03833 }
03834 
03835 static int
03836 rlimit_type_by_hname(const char *name)
03837 {
03838     return rlimit_resource_name2int(name, 0);
03839 }
03840 
03841 static int
03842 rlimit_type_by_lname(const char *name)
03843 {
03844     return rlimit_resource_name2int(name, 1);
03845 }
03846 
03847 static int
03848 rlimit_resource_type(VALUE rtype)
03849 {
03850     const char *name;
03851     VALUE v;
03852     int r;
03853 
03854     switch (TYPE(rtype)) {
03855       case T_SYMBOL:
03856         name = rb_id2name(SYM2ID(rtype));
03857         break;
03858 
03859       default:
03860         v = rb_check_string_type(rtype);
03861         if (!NIL_P(v)) {
03862             rtype = v;
03863       case T_STRING:
03864             name = StringValueCStr(rtype);
03865             break;
03866         }
03867         /* fall through */
03868 
03869       case T_FIXNUM:
03870       case T_BIGNUM:
03871         return NUM2INT(rtype);
03872     }
03873 
03874     r = rlimit_type_by_hname(name);
03875     if (r != -1)
03876         return r;
03877 
03878     rb_raise(rb_eArgError, "invalid resource name: %s", name);
03879 }
03880 
03881 static rlim_t
03882 rlimit_resource_value(VALUE rval)
03883 {
03884     const char *name;
03885     VALUE v;
03886 
03887     switch (TYPE(rval)) {
03888       case T_SYMBOL:
03889         name = rb_id2name(SYM2ID(rval));
03890         break;
03891 
03892       default:
03893         v = rb_check_string_type(rval);
03894         if (!NIL_P(v)) {
03895             rval = v;
03896       case T_STRING:
03897             name = StringValueCStr(rval);
03898             break;
03899         }
03900         /* fall through */
03901 
03902       case T_FIXNUM:
03903       case T_BIGNUM:
03904         return NUM2RLIM(rval);
03905     }
03906 
03907 #ifdef RLIM_INFINITY
03908     if (strcmp(name, "INFINITY") == 0) return RLIM_INFINITY;
03909 #endif
03910 #ifdef RLIM_SAVED_MAX
03911     if (strcmp(name, "SAVED_MAX") == 0) return RLIM_SAVED_MAX;
03912 #endif
03913 #ifdef RLIM_SAVED_CUR
03914     if (strcmp(name, "SAVED_CUR") == 0) return RLIM_SAVED_CUR;
03915 #endif
03916     rb_raise(rb_eArgError, "invalid resource value: %s", name);
03917 }
03918 #endif
03919 
03920 #if defined(HAVE_GETRLIMIT) && defined(RLIM2NUM)
03921 /*
03922  *  call-seq:
03923  *     Process.getrlimit(resource)   -> [cur_limit, max_limit]
03924  *
03925  *  Gets the resource limit of the process.
03926  *  _cur_limit_ means current (soft) limit and
03927  *  _max_limit_ means maximum (hard) limit.
03928  *
03929  *  _resource_ indicates the kind of resource to limit.
03930  *  It is specified as a symbol such as <code>:CORE</code>,
03931  *  a string such as <code>"CORE"</code> or
03932  *  a constant such as <code>Process::RLIMIT_CORE</code>.
03933  *  See Process.setrlimit for details.
03934  *
03935  *  _cur_limit_ and _max_limit_ may be <code>Process::RLIM_INFINITY</code>,
03936  *  <code>Process::RLIM_SAVED_MAX</code> or
03937  *  <code>Process::RLIM_SAVED_CUR</code>.
03938  *  See Process.setrlimit and the system getrlimit(2) manual for details.
03939  */
03940 
03941 static VALUE
03942 proc_getrlimit(VALUE obj, VALUE resource)
03943 {
03944     struct rlimit rlim;
03945 
03946     rb_secure(2);
03947 
03948     if (getrlimit(rlimit_resource_type(resource), &rlim) < 0) {
03949         rb_sys_fail("getrlimit");
03950     }
03951     return rb_assoc_new(RLIM2NUM(rlim.rlim_cur), RLIM2NUM(rlim.rlim_max));
03952 }
03953 #else
03954 #define proc_getrlimit rb_f_notimplement
03955 #endif
03956 
03957 #if defined(HAVE_SETRLIMIT) && defined(NUM2RLIM)
03958 /*
03959  *  call-seq:
03960  *     Process.setrlimit(resource, cur_limit, max_limit)        -> nil
03961  *     Process.setrlimit(resource, cur_limit)                   -> nil
03962  *
03963  *  Sets the resource limit of the process.
03964  *  _cur_limit_ means current (soft) limit and
03965  *  _max_limit_ means maximum (hard) limit.
03966  *
03967  *  If _max_limit_ is not given, _cur_limit_ is used.
03968  *
03969  *  _resource_ indicates the kind of resource to limit.
03970  *  It should be a symbol such as <code>:CORE</code>,
03971  *  a string such as <code>"CORE"</code> or
03972  *  a constant such as <code>Process::RLIMIT_CORE</code>.
03973  *  The available resources are OS dependent.
03974  *  Ruby may support following resources.
03975  *
03976  *  [AS] total available memory (bytes) (SUSv3, NetBSD, FreeBSD, OpenBSD but 4.4BSD-Lite)
03977  *  [CORE] core size (bytes) (SUSv3)
03978  *  [CPU] CPU time (seconds) (SUSv3)
03979  *  [DATA] data segment (bytes) (SUSv3)
03980  *  [FSIZE] file size (bytes) (SUSv3)
03981  *  [MEMLOCK] total size for mlock(2) (bytes) (4.4BSD, GNU/Linux)
03982  *  [MSGQUEUE] allocation for POSIX message queues (bytes) (GNU/Linux)
03983  *  [NICE] ceiling on process's nice(2) value (number) (GNU/Linux)
03984  *  [NOFILE] file descriptors (number) (SUSv3)
03985  *  [NPROC] number of processes for the user (number) (4.4BSD, GNU/Linux)
03986  *  [RSS] resident memory size (bytes) (4.2BSD, GNU/Linux)
03987  *  [RTPRIO] ceiling on the process's real-time priority (number) (GNU/Linux)
03988  *  [RTTIME] CPU time for real-time process (us) (GNU/Linux)
03989  *  [SBSIZE] all socket buffers (bytes) (NetBSD, FreeBSD)
03990  *  [SIGPENDING] number of queued signals allowed (signals) (GNU/Linux)
03991  *  [STACK] stack size (bytes) (SUSv3)
03992  *
03993  *  _cur_limit_ and _max_limit_ may be
03994  *  <code>:INFINITY</code>, <code>"INFINITY"</code> or
03995  *  <code>Process::RLIM_INFINITY</code>,
03996  *  which means that the resource is not limited.
03997  *  They may be <code>Process::RLIM_SAVED_MAX</code>,
03998  *  <code>Process::RLIM_SAVED_CUR</code> and
03999  *  corresponding symbols and strings too.
04000  *  See system setrlimit(2) manual for details.
04001  *
04002  *  The following example raises the soft limit of core size to
04003  *  the hard limit to try to make core dump possible.
04004  *
04005  *    Process.setrlimit(:CORE, Process.getrlimit(:CORE)[1])
04006  *
04007  */
04008 
04009 static VALUE
04010 proc_setrlimit(int argc, VALUE *argv, VALUE obj)
04011 {
04012     VALUE resource, rlim_cur, rlim_max;
04013     struct rlimit rlim;
04014 
04015     rb_secure(2);
04016 
04017     rb_scan_args(argc, argv, "21", &resource, &rlim_cur, &rlim_max);
04018     if (rlim_max == Qnil)
04019         rlim_max = rlim_cur;
04020 
04021     rlim.rlim_cur = rlimit_resource_value(rlim_cur);
04022     rlim.rlim_max = rlimit_resource_value(rlim_max);
04023 
04024     if (setrlimit(rlimit_resource_type(resource), &rlim) < 0) {
04025         rb_sys_fail("setrlimit");
04026     }
04027     return Qnil;
04028 }
04029 #else
04030 #define proc_setrlimit rb_f_notimplement
04031 #endif
04032 
04033 static int under_uid_switch = 0;
04034 static void
04035 check_uid_switch(void)
04036 {
04037     rb_secure(2);
04038     if (under_uid_switch) {
04039         rb_raise(rb_eRuntimeError, "can't handle UID while evaluating block given to Process::UID.switch method");
04040     }
04041 }
04042 
04043 static int under_gid_switch = 0;
04044 static void
04045 check_gid_switch(void)
04046 {
04047     rb_secure(2);
04048     if (under_gid_switch) {
04049         rb_raise(rb_eRuntimeError, "can't handle GID while evaluating block given to Process::UID.switch method");
04050     }
04051 }
04052 
04053 
04054 /*********************************************************************
04055  * Document-class: Process::Sys
04056  *
04057  *  The <code>Process::Sys</code> module contains UID and GID
04058  *  functions which provide direct bindings to the system calls of the
04059  *  same names instead of the more-portable versions of the same
04060  *  functionality found in the <code>Process</code>,
04061  *  <code>Process::UID</code>, and <code>Process::GID</code> modules.
04062  */
04063 
04064 
04065 #if defined HAVE_SETUID
04066 /*
04067  *  call-seq:
04068  *     Process::Sys.setuid(integer)   -> nil
04069  *
04070  *  Set the user ID of the current process to _integer_. Not
04071  *  available on all platforms.
04072  *
04073  */
04074 
04075 static VALUE
04076 p_sys_setuid(VALUE obj, VALUE id)
04077 {
04078     check_uid_switch();
04079     if (setuid(NUM2UIDT(id)) != 0) rb_sys_fail(0);
04080     return Qnil;
04081 }
04082 #else
04083 #define p_sys_setuid rb_f_notimplement
04084 #endif
04085 
04086 
04087 #if defined HAVE_SETRUID
04088 /*
04089  *  call-seq:
04090  *     Process::Sys.setruid(integer)   -> nil
04091  *
04092  *  Set the real user ID of the calling process to _integer_.
04093  *  Not available on all platforms.
04094  *
04095  */
04096 
04097 static VALUE
04098 p_sys_setruid(VALUE obj, VALUE id)
04099 {
04100     check_uid_switch();
04101     if (setruid(NUM2UIDT(id)) != 0) rb_sys_fail(0);
04102     return Qnil;
04103 }
04104 #else
04105 #define p_sys_setruid rb_f_notimplement
04106 #endif
04107 
04108 
04109 #if defined HAVE_SETEUID
04110 /*
04111  *  call-seq:
04112  *     Process::Sys.seteuid(integer)   -> nil
04113  *
04114  *  Set the effective user ID of the calling process to
04115  *  _integer_.  Not available on all platforms.
04116  *
04117  */
04118 
04119 static VALUE
04120 p_sys_seteuid(VALUE obj, VALUE id)
04121 {
04122     check_uid_switch();
04123     if (seteuid(NUM2UIDT(id)) != 0) rb_sys_fail(0);
04124     return Qnil;
04125 }
04126 #else
04127 #define p_sys_seteuid rb_f_notimplement
04128 #endif
04129 
04130 
04131 #if defined HAVE_SETREUID
04132 /*
04133  *  call-seq:
04134  *     Process::Sys.setreuid(rid, eid)   -> nil
04135  *
04136  *  Sets the (integer) real and/or effective user IDs of the current
04137  *  process to _rid_ and _eid_, respectively. A value of
04138  *  <code>-1</code> for either means to leave that ID unchanged. Not
04139  *  available on all platforms.
04140  *
04141  */
04142 
04143 static VALUE
04144 p_sys_setreuid(VALUE obj, VALUE rid, VALUE eid)
04145 {
04146     check_uid_switch();
04147     if (setreuid(NUM2UIDT(rid),NUM2UIDT(eid)) != 0) rb_sys_fail(0);
04148     return Qnil;
04149 }
04150 #else
04151 #define p_sys_setreuid rb_f_notimplement
04152 #endif
04153 
04154 
04155 #if defined HAVE_SETRESUID
04156 /*
04157  *  call-seq:
04158  *     Process::Sys.setresuid(rid, eid, sid)   -> nil
04159  *
04160  *  Sets the (integer) real, effective, and saved user IDs of the
04161  *  current process to _rid_, _eid_, and _sid_ respectively. A
04162  *  value of <code>-1</code> for any value means to
04163  *  leave that ID unchanged. Not available on all platforms.
04164  *
04165  */
04166 
04167 static VALUE
04168 p_sys_setresuid(VALUE obj, VALUE rid, VALUE eid, VALUE sid)
04169 {
04170     check_uid_switch();
04171     if (setresuid(NUM2UIDT(rid),NUM2UIDT(eid),NUM2UIDT(sid)) != 0) rb_sys_fail(0);
04172     return Qnil;
04173 }
04174 #else
04175 #define p_sys_setresuid rb_f_notimplement
04176 #endif
04177 
04178 
04179 /*
04180  *  call-seq:
04181  *     Process.uid           -> fixnum
04182  *     Process::UID.rid      -> fixnum
04183  *     Process::Sys.getuid   -> fixnum
04184  *
04185  *  Returns the (real) user ID of this process.
04186  *
04187  *     Process.uid   #=> 501
04188  */
04189 
04190 static VALUE
04191 proc_getuid(VALUE obj)
04192 {
04193     rb_uid_t uid = getuid();
04194     return UIDT2NUM(uid);
04195 }
04196 
04197 
04198 #if defined(HAVE_SETRESUID) || defined(HAVE_SETREUID) || defined(HAVE_SETRUID) || defined(HAVE_SETUID)
04199 /*
04200  *  call-seq:
04201  *     Process.uid= integer   -> numeric
04202  *
04203  *  Sets the (integer) user ID for this process. Not available on all
04204  *  platforms.
04205  */
04206 
04207 static VALUE
04208 proc_setuid(VALUE obj, VALUE id)
04209 {
04210     rb_uid_t uid;
04211 
04212     check_uid_switch();
04213 
04214     uid = NUM2UIDT(id);
04215 #if defined(HAVE_SETRESUID)
04216     if (setresuid(uid, -1, -1) < 0) rb_sys_fail(0);
04217 #elif defined HAVE_SETREUID
04218     if (setreuid(uid, -1) < 0) rb_sys_fail(0);
04219 #elif defined HAVE_SETRUID
04220     if (setruid(uid) < 0) rb_sys_fail(0);
04221 #elif defined HAVE_SETUID
04222     {
04223         if (geteuid() == uid) {
04224             if (setuid(uid) < 0) rb_sys_fail(0);
04225         }
04226         else {
04227             rb_notimplement();
04228         }
04229     }
04230 #endif
04231     return id;
04232 }
04233 #else
04234 #define proc_setuid rb_f_notimplement
04235 #endif
04236 
04237 
04238 /********************************************************************
04239  *
04240  * Document-class: Process::UID
04241  *
04242  *  The <code>Process::UID</code> module contains a collection of
04243  *  module functions which can be used to portably get, set, and
04244  *  switch the current process's real, effective, and saved user IDs.
04245  *
04246  */
04247 
04248 static rb_uid_t SAVED_USER_ID = -1;
04249 
04250 #ifdef BROKEN_SETREUID
04251 int
04252 setreuid(rb_uid_t ruid, rb_uid_t euid)
04253 {
04254     if (ruid != (rb_uid_t)-1 && ruid != getuid()) {
04255         if (euid == (rb_uid_t)-1) euid = geteuid();
04256         if (setuid(ruid) < 0) return -1;
04257     }
04258     if (euid != (rb_uid_t)-1 && euid != geteuid()) {
04259         if (seteuid(euid) < 0) return -1;
04260     }
04261     return 0;
04262 }
04263 #endif
04264 
04265 /*
04266  *  call-seq:
04267  *     Process::UID.change_privilege(integer)   -> fixnum
04268  *
04269  *  Change the current process's real and effective user ID to that
04270  *  specified by _integer_. Returns the new user ID. Not
04271  *  available on all platforms.
04272  *
04273  *     [Process.uid, Process.euid]          #=> [0, 0]
04274  *     Process::UID.change_privilege(31)    #=> 31
04275  *     [Process.uid, Process.euid]          #=> [31, 31]
04276  */
04277 
04278 static VALUE
04279 p_uid_change_privilege(VALUE obj, VALUE id)
04280 {
04281     rb_uid_t uid;
04282 
04283     check_uid_switch();
04284 
04285     uid = NUM2UIDT(id);
04286 
04287     if (geteuid() == 0) { /* root-user */
04288 #if defined(HAVE_SETRESUID)
04289         if (setresuid(uid, uid, uid) < 0) rb_sys_fail(0);
04290         SAVED_USER_ID = uid;
04291 #elif defined(HAVE_SETUID)
04292         if (setuid(uid) < 0) rb_sys_fail(0);
04293         SAVED_USER_ID = uid;
04294 #elif defined(HAVE_SETREUID) && !defined(OBSOLETE_SETREUID)
04295         if (getuid() == uid) {
04296             if (SAVED_USER_ID == uid) {
04297                 if (setreuid(-1, uid) < 0) rb_sys_fail(0);
04298             } else {
04299                 if (uid == 0) { /* (r,e,s) == (root, root, x) */
04300                     if (setreuid(-1, SAVED_USER_ID) < 0) rb_sys_fail(0);
04301                     if (setreuid(SAVED_USER_ID, 0) < 0) rb_sys_fail(0);
04302                     SAVED_USER_ID = 0; /* (r,e,s) == (x, root, root) */
04303                     if (setreuid(uid, uid) < 0) rb_sys_fail(0);
04304                     SAVED_USER_ID = uid;
04305                 } else {
04306                     if (setreuid(0, -1) < 0) rb_sys_fail(0);
04307                     SAVED_USER_ID = 0;
04308                     if (setreuid(uid, uid) < 0) rb_sys_fail(0);
04309                     SAVED_USER_ID = uid;
04310                 }
04311             }
04312         } else {
04313             if (setreuid(uid, uid) < 0) rb_sys_fail(0);
04314             SAVED_USER_ID = uid;
04315         }
04316 #elif defined(HAVE_SETRUID) && defined(HAVE_SETEUID)
04317         if (getuid() == uid) {
04318             if (SAVED_USER_ID == uid) {
04319                 if (seteuid(uid) < 0) rb_sys_fail(0);
04320             } else {
04321                 if (uid == 0) {
04322                     if (setruid(SAVED_USER_ID) < 0) rb_sys_fail(0);
04323                     SAVED_USER_ID = 0;
04324                     if (setruid(0) < 0) rb_sys_fail(0);
04325                 } else {
04326                     if (setruid(0) < 0) rb_sys_fail(0);
04327                     SAVED_USER_ID = 0;
04328                     if (seteuid(uid) < 0) rb_sys_fail(0);
04329                     if (setruid(uid) < 0) rb_sys_fail(0);
04330                     SAVED_USER_ID = uid;
04331                 }
04332             }
04333         } else {
04334             if (seteuid(uid) < 0) rb_sys_fail(0);
04335             if (setruid(uid) < 0) rb_sys_fail(0);
04336             SAVED_USER_ID = uid;
04337         }
04338 #else
04339         rb_notimplement();
04340 #endif
04341     } else { /* unprivileged user */
04342 #if defined(HAVE_SETRESUID)
04343         if (setresuid((getuid() == uid)? (rb_uid_t)-1: uid,
04344                       (geteuid() == uid)? (rb_uid_t)-1: uid,
04345                       (SAVED_USER_ID == uid)? (rb_uid_t)-1: uid) < 0) rb_sys_fail(0);
04346         SAVED_USER_ID = uid;
04347 #elif defined(HAVE_SETREUID) && !defined(OBSOLETE_SETREUID)
04348         if (SAVED_USER_ID == uid) {
04349             if (setreuid((getuid() == uid)? (rb_uid_t)-1: uid,
04350                          (geteuid() == uid)? (rb_uid_t)-1: uid) < 0)
04351                 rb_sys_fail(0);
04352         } else if (getuid() != uid) {
04353             if (setreuid(uid, (geteuid() == uid)? (rb_uid_t)-1: uid) < 0)
04354                 rb_sys_fail(0);
04355             SAVED_USER_ID = uid;
04356         } else if (/* getuid() == uid && */ geteuid() != uid) {
04357             if (setreuid(geteuid(), uid) < 0) rb_sys_fail(0);
04358             SAVED_USER_ID = uid;
04359             if (setreuid(uid, -1) < 0) rb_sys_fail(0);
04360         } else { /* getuid() == uid && geteuid() == uid */
04361             if (setreuid(-1, SAVED_USER_ID) < 0) rb_sys_fail(0);
04362             if (setreuid(SAVED_USER_ID, uid) < 0) rb_sys_fail(0);
04363             SAVED_USER_ID = uid;
04364             if (setreuid(uid, -1) < 0) rb_sys_fail(0);
04365         }
04366 #elif defined(HAVE_SETRUID) && defined(HAVE_SETEUID)
04367         if (SAVED_USER_ID == uid) {
04368             if (geteuid() != uid && seteuid(uid) < 0) rb_sys_fail(0);
04369             if (getuid() != uid && setruid(uid) < 0) rb_sys_fail(0);
04370         } else if (/* SAVED_USER_ID != uid && */ geteuid() == uid) {
04371             if (getuid() != uid) {
04372                 if (setruid(uid) < 0) rb_sys_fail(0);
04373                 SAVED_USER_ID = uid;
04374             } else {
04375                 if (setruid(SAVED_USER_ID) < 0) rb_sys_fail(0);
04376                 SAVED_USER_ID = uid;
04377                 if (setruid(uid) < 0) rb_sys_fail(0);
04378             }
04379         } else if (/* geteuid() != uid && */ getuid() == uid) {
04380             if (seteuid(uid) < 0) rb_sys_fail(0);
04381             if (setruid(SAVED_USER_ID) < 0) rb_sys_fail(0);
04382             SAVED_USER_ID = uid;
04383             if (setruid(uid) < 0) rb_sys_fail(0);
04384         } else {
04385             errno = EPERM;
04386             rb_sys_fail(0);
04387         }
04388 #elif defined HAVE_44BSD_SETUID
04389         if (getuid() == uid) {
04390             /* (r,e,s)==(uid,?,?) ==> (uid,uid,uid) */
04391             if (setuid(uid) < 0) rb_sys_fail(0);
04392             SAVED_USER_ID = uid;
04393         } else {
04394             errno = EPERM;
04395             rb_sys_fail(0);
04396         }
04397 #elif defined HAVE_SETEUID
04398         if (getuid() == uid && SAVED_USER_ID == uid) {
04399             if (seteuid(uid) < 0) rb_sys_fail(0);
04400         } else {
04401             errno = EPERM;
04402             rb_sys_fail(0);
04403         }
04404 #elif defined HAVE_SETUID
04405         if (getuid() == uid && SAVED_USER_ID == uid) {
04406             if (setuid(uid) < 0) rb_sys_fail(0);
04407         } else {
04408             errno = EPERM;
04409             rb_sys_fail(0);
04410         }
04411 #else
04412         rb_notimplement();
04413 #endif
04414     }
04415     return id;
04416 }
04417 
04418 
04419 
04420 #if defined HAVE_SETGID
04421 /*
04422  *  call-seq:
04423  *     Process::Sys.setgid(integer)   -> nil
04424  *
04425  *  Set the group ID of the current process to _integer_. Not
04426  *  available on all platforms.
04427  *
04428  */
04429 
04430 static VALUE
04431 p_sys_setgid(VALUE obj, VALUE id)
04432 {
04433     check_gid_switch();
04434     if (setgid(NUM2GIDT(id)) != 0) rb_sys_fail(0);
04435     return Qnil;
04436 }
04437 #else
04438 #define p_sys_setgid rb_f_notimplement
04439 #endif
04440 
04441 
04442 #if defined HAVE_SETRGID
04443 /*
04444  *  call-seq:
04445  *     Process::Sys.setrgid(integer)   -> nil
04446  *
04447  *  Set the real group ID of the calling process to _integer_.
04448  *  Not available on all platforms.
04449  *
04450  */
04451 
04452 static VALUE
04453 p_sys_setrgid(VALUE obj, VALUE id)
04454 {
04455     check_gid_switch();
04456     if (setrgid(NUM2GIDT(id)) != 0) rb_sys_fail(0);
04457     return Qnil;
04458 }
04459 #else
04460 #define p_sys_setrgid rb_f_notimplement
04461 #endif
04462 
04463 
04464 #if defined HAVE_SETEGID
04465 /*
04466  *  call-seq:
04467  *     Process::Sys.setegid(integer)   -> nil
04468  *
04469  *  Set the effective group ID of the calling process to
04470  *  _integer_.  Not available on all platforms.
04471  *
04472  */
04473 
04474 static VALUE
04475 p_sys_setegid(VALUE obj, VALUE id)
04476 {
04477     check_gid_switch();
04478     if (setegid(NUM2GIDT(id)) != 0) rb_sys_fail(0);
04479     return Qnil;
04480 }
04481 #else
04482 #define p_sys_setegid rb_f_notimplement
04483 #endif
04484 
04485 
04486 #if defined HAVE_SETREGID
04487 /*
04488  *  call-seq:
04489  *     Process::Sys.setregid(rid, eid)   -> nil
04490  *
04491  *  Sets the (integer) real and/or effective group IDs of the current
04492  *  process to <em>rid</em> and <em>eid</em>, respectively. A value of
04493  *  <code>-1</code> for either means to leave that ID unchanged. Not
04494  *  available on all platforms.
04495  *
04496  */
04497 
04498 static VALUE
04499 p_sys_setregid(VALUE obj, VALUE rid, VALUE eid)
04500 {
04501     check_gid_switch();
04502     if (setregid(NUM2GIDT(rid),NUM2GIDT(eid)) != 0) rb_sys_fail(0);
04503     return Qnil;
04504 }
04505 #else
04506 #define p_sys_setregid rb_f_notimplement
04507 #endif
04508 
04509 #if defined HAVE_SETRESGID
04510 /*
04511  *  call-seq:
04512  *     Process::Sys.setresgid(rid, eid, sid)   -> nil
04513  *
04514  *  Sets the (integer) real, effective, and saved user IDs of the
04515  *  current process to <em>rid</em>, <em>eid</em>, and <em>sid</em>
04516  *  respectively. A value of <code>-1</code> for any value means to
04517  *  leave that ID unchanged. Not available on all platforms.
04518  *
04519  */
04520 
04521 static VALUE
04522 p_sys_setresgid(VALUE obj, VALUE rid, VALUE eid, VALUE sid)
04523 {
04524     check_gid_switch();
04525     if (setresgid(NUM2GIDT(rid),NUM2GIDT(eid),NUM2GIDT(sid)) != 0) rb_sys_fail(0);
04526     return Qnil;
04527 }
04528 #else
04529 #define p_sys_setresgid rb_f_notimplement
04530 #endif
04531 
04532 
04533 #if defined HAVE_ISSETUGID
04534 /*
04535  *  call-seq:
04536  *     Process::Sys.issetugid   -> true or false
04537  *
04538  *  Returns +true+ if the process was created as a result
04539  *  of an execve(2) system call which had either of the setuid or
04540  *  setgid bits set (and extra privileges were given as a result) or
04541  *  if it has changed any of its real, effective or saved user or
04542  *  group IDs since it began execution.
04543  *
04544  */
04545 
04546 static VALUE
04547 p_sys_issetugid(VALUE obj)
04548 {
04549     rb_secure(2);
04550     if (issetugid()) {
04551         return Qtrue;
04552     } else {
04553         return Qfalse;
04554     }
04555 }
04556 #else
04557 #define p_sys_issetugid rb_f_notimplement
04558 #endif
04559 
04560 
04561 /*
04562  *  call-seq:
04563  *     Process.gid           -> fixnum
04564  *     Process::GID.rid      -> fixnum
04565  *     Process::Sys.getgid   -> fixnum
04566  *
04567  *  Returns the (real) group ID for this process.
04568  *
04569  *     Process.gid   #=> 500
04570  */
04571 
04572 static VALUE
04573 proc_getgid(VALUE obj)
04574 {
04575     rb_gid_t gid = getgid();
04576     return GIDT2NUM(gid);
04577 }
04578 
04579 
04580 #if defined(HAVE_SETRESGID) || defined(HAVE_SETREGID) || defined(HAVE_SETRGID) || defined(HAVE_SETGID)
04581 /*
04582  *  call-seq:
04583  *     Process.gid= fixnum   -> fixnum
04584  *
04585  *  Sets the group ID for this process.
04586  */
04587 
04588 static VALUE
04589 proc_setgid(VALUE obj, VALUE id)
04590 {
04591     rb_gid_t gid;
04592 
04593     check_gid_switch();
04594 
04595     gid = NUM2GIDT(id);
04596 #if defined(HAVE_SETRESGID)
04597     if (setresgid(gid, -1, -1) < 0) rb_sys_fail(0);
04598 #elif defined HAVE_SETREGID
04599     if (setregid(gid, -1) < 0) rb_sys_fail(0);
04600 #elif defined HAVE_SETRGID
04601     if (setrgid(gid) < 0) rb_sys_fail(0);
04602 #elif defined HAVE_SETGID
04603     {
04604         if (getegid() == gid) {
04605             if (setgid(gid) < 0) rb_sys_fail(0);
04606         }
04607         else {
04608             rb_notimplement();
04609         }
04610     }
04611 #endif
04612     return GIDT2NUM(gid);
04613 }
04614 #else
04615 #define proc_setgid rb_f_notimplement
04616 #endif
04617 
04618 
04619 #if defined(HAVE_SETGROUPS) || defined(HAVE_GETGROUPS)
04620 /*
04621  * Maximum supplementary groups are platform dependent.
04622  * FWIW, 65536 is enough big for our supported OSs.
04623  *
04624  * OS Name                      max groups
04625  * -----------------------------------------------
04626  * Linux Kernel >= 2.6.3        65536
04627  * Linux Kernel < 2.6.3            32
04628  * IBM AIX 5.2                     64
04629  * IBM AIX 5.3 ... 6.1            128
04630  * IBM AIX 7.1                    128 (can be configured to be up to 2048)
04631  * OpenBSD, NetBSD                 16
04632  * FreeBSD < 8.0                   16
04633  * FreeBSD >=8.0                 1023
04634  * Darwin (Mac OS X)               16
04635  * Sun Solaris 7,8,9,10            16
04636  * Sun Solaris 11 / OpenSolaris  1024
04637  * HP-UX                           20
04638  * Windows                       1015
04639  */
04640 #define RB_MAX_GROUPS (65536)
04641 static int _maxgroups = -1;
04642 static int get_sc_ngroups_max(void)
04643 {
04644 #ifdef _SC_NGROUPS_MAX
04645     return (int)sysconf(_SC_NGROUPS_MAX);
04646 #elif defined(NGROUPS_MAX)
04647     return (int)NGROUPS_MAX;
04648 #else
04649     return -1;
04650 #endif
04651 }
04652 static int maxgroups(void)
04653 {
04654     if (_maxgroups < 0) {
04655         _maxgroups = get_sc_ngroups_max();
04656         if (_maxgroups < 0)
04657             _maxgroups = RB_MAX_GROUPS;
04658     }
04659 
04660     return _maxgroups;
04661 }
04662 #endif
04663 
04664 
04665 
04666 #ifdef HAVE_GETGROUPS
04667 /*
04668  *  call-seq:
04669  *     Process.groups   -> array
04670  *
04671  *  Get an <code>Array</code> of the gids of groups in the
04672  *  supplemental group access list for this process.
04673  *
04674  *     Process.groups   #=> [27, 6, 10, 11]
04675  *
04676  */
04677 
04678 static VALUE
04679 proc_getgroups(VALUE obj)
04680 {
04681     VALUE ary;
04682     int i, ngroups;
04683     rb_gid_t *groups;
04684 
04685     ngroups = getgroups(0, NULL);
04686     if (ngroups == -1)
04687         rb_sys_fail(0);
04688 
04689     groups = ALLOCA_N(rb_gid_t, ngroups);
04690 
04691     ngroups = getgroups(ngroups, groups);
04692     if (ngroups == -1)
04693         rb_sys_fail(0);
04694 
04695     ary = rb_ary_new();
04696     for (i = 0; i < ngroups; i++)
04697         rb_ary_push(ary, GIDT2NUM(groups[i]));
04698 
04699     return ary;
04700 }
04701 #else
04702 #define proc_getgroups rb_f_notimplement
04703 #endif
04704 
04705 
04706 #ifdef HAVE_SETGROUPS
04707 /*
04708  *  call-seq:
04709  *     Process.groups= array   -> array
04710  *
04711  *  Set the supplemental group access list to the given
04712  *  <code>Array</code> of group IDs.
04713  *
04714  *     Process.groups   #=> [0, 1, 2, 3, 4, 6, 10, 11, 20, 26, 27]
04715  *     Process.groups = [27, 6, 10, 11]   #=> [27, 6, 10, 11]
04716  *     Process.groups   #=> [27, 6, 10, 11]
04717  *
04718  */
04719 
04720 static VALUE
04721 proc_setgroups(VALUE obj, VALUE ary)
04722 {
04723     int ngroups, i;
04724     rb_gid_t *groups;
04725 #ifdef HAVE_GETGRNAM_R
04726     long getgr_buf_len = sysconf(_SC_GETGR_R_SIZE_MAX);
04727     char* getgr_buf;
04728 
04729     if (getgr_buf_len < 0)
04730         getgr_buf_len = 4096;
04731     getgr_buf = ALLOCA_N(char, getgr_buf_len);
04732 #endif
04733 
04734     Check_Type(ary, T_ARRAY);
04735 
04736     ngroups = RARRAY_LENINT(ary);
04737     if (ngroups > maxgroups())
04738         rb_raise(rb_eArgError, "too many groups, %d max", maxgroups());
04739 
04740     groups = ALLOCA_N(rb_gid_t, ngroups);
04741 
04742     for (i = 0; i < ngroups; i++) {
04743         VALUE g = RARRAY_PTR(ary)[i];
04744 
04745         if (FIXNUM_P(g)) {
04746             groups[i] = NUM2GIDT(g);
04747         }
04748         else {
04749             VALUE tmp = rb_check_string_type(g);
04750             struct group grp;
04751             struct group *p;
04752             int ret;
04753 
04754             if (NIL_P(tmp)) {
04755                 groups[i] = NUM2GIDT(g);
04756             }
04757             else {
04758                 const char *grpname = StringValueCStr(tmp);
04759 
04760 #ifdef HAVE_GETGRNAM_R
04761                 ret = getgrnam_r(grpname, &grp, getgr_buf, getgr_buf_len, &p);
04762                 if (ret)
04763                     rb_sys_fail("getgrnam_r");
04764 #else
04765                 p = getgrnam(grpname);
04766 #endif
04767                 if (p == NULL) {
04768                     rb_raise(rb_eArgError,
04769                              "can't find group for %s", RSTRING_PTR(tmp));
04770                 }
04771                 groups[i] = p->gr_gid;
04772             }
04773         }
04774     }
04775 
04776     if (setgroups(ngroups, groups) == -1) /* ngroups <= maxgroups */
04777         rb_sys_fail(0);
04778 
04779     return proc_getgroups(obj);
04780 }
04781 #else
04782 #define proc_setgroups rb_f_notimplement
04783 #endif
04784 
04785 
04786 #ifdef HAVE_INITGROUPS
04787 /*
04788  *  call-seq:
04789  *     Process.initgroups(username, gid)   -> array
04790  *
04791  *  Initializes the supplemental group access list by reading the
04792  *  system group database and using all groups of which the given user
04793  *  is a member. The group with the specified <em>gid</em> is also
04794  *  added to the list. Returns the resulting <code>Array</code> of the
04795  *  gids of all the groups in the supplementary group access list. Not
04796  *  available on all platforms.
04797  *
04798  *     Process.groups   #=> [0, 1, 2, 3, 4, 6, 10, 11, 20, 26, 27]
04799  *     Process.initgroups( "mgranger", 30 )   #=> [30, 6, 10, 11]
04800  *     Process.groups   #=> [30, 6, 10, 11]
04801  *
04802  */
04803 
04804 static VALUE
04805 proc_initgroups(VALUE obj, VALUE uname, VALUE base_grp)
04806 {
04807     if (initgroups(StringValuePtr(uname), NUM2GIDT(base_grp)) != 0) {
04808         rb_sys_fail(0);
04809     }
04810     return proc_getgroups(obj);
04811 }
04812 #else
04813 #define proc_initgroups rb_f_notimplement
04814 #endif
04815 
04816 #if defined(_SC_NGROUPS_MAX) || defined(NGROUPS_MAX)
04817 /*
04818  *  call-seq:
04819  *     Process.maxgroups   -> fixnum
04820  *
04821  *  Returns the maximum number of gids allowed in the supplemental
04822  *  group access list.
04823  *
04824  *     Process.maxgroups   #=> 32
04825  */
04826 
04827 static VALUE
04828 proc_getmaxgroups(VALUE obj)
04829 {
04830     return INT2FIX(maxgroups());
04831 }
04832 #else
04833 #define proc_getmaxgroups rb_f_notimplement
04834 #endif
04835 
04836 #ifdef HAVE_SETGROUPS
04837 /*
04838  *  call-seq:
04839  *     Process.maxgroups= fixnum   -> fixnum
04840  *
04841  *  Sets the maximum number of gids allowed in the supplemental group
04842  *  access list.
04843  */
04844 
04845 static VALUE
04846 proc_setmaxgroups(VALUE obj, VALUE val)
04847 {
04848     int ngroups = FIX2INT(val);
04849     int ngroups_max = get_sc_ngroups_max();
04850 
04851     if (ngroups <= 0)
04852         rb_raise(rb_eArgError, "maxgroups %d shold be positive", ngroups);
04853 
04854     if (ngroups > RB_MAX_GROUPS)
04855         ngroups = RB_MAX_GROUPS;
04856 
04857     if (ngroups_max > 0 && ngroups > ngroups_max)
04858         ngroups = ngroups_max;
04859 
04860     _maxgroups = ngroups;
04861 
04862     return INT2FIX(_maxgroups);
04863 }
04864 #else
04865 #define proc_setmaxgroups rb_f_notimplement
04866 #endif
04867 
04868 #if defined(HAVE_DAEMON) || (defined(HAVE_FORK) && defined(HAVE_SETSID))
04869 static int rb_daemon(int nochdir, int noclose);
04870 
04871 /*
04872  *  call-seq:
04873  *     Process.daemon()                        -> 0
04874  *     Process.daemon(nochdir=nil,noclose=nil) -> 0
04875  *
04876  *  Detach the process from controlling terminal and run in
04877  *  the background as system daemon.  Unless the argument
04878  *  nochdir is true (i.e. non false), it changes the current
04879  *  working directory to the root ("/"). Unless the argument
04880  *  noclose is true, daemon() will redirect standard input,
04881  *  standard output and standard error to /dev/null.
04882  *  Return zero on success, or raise one of Errno::*.
04883  */
04884 
04885 static VALUE
04886 proc_daemon(int argc, VALUE *argv)
04887 {
04888     VALUE nochdir, noclose;
04889     int n;
04890 
04891     rb_secure(2);
04892     rb_scan_args(argc, argv, "02", &nochdir, &noclose);
04893 
04894     prefork();
04895     n = rb_daemon(RTEST(nochdir), RTEST(noclose));
04896     if (n < 0) rb_sys_fail("daemon");
04897     return INT2FIX(n);
04898 }
04899 
04900 static int
04901 rb_daemon(int nochdir, int noclose)
04902 {
04903     int err = 0;
04904 #ifdef HAVE_DAEMON
04905     before_fork();
04906     err = daemon(nochdir, noclose);
04907     after_fork();
04908 #else
04909     int n;
04910 
04911     switch (rb_fork(0, 0, 0, Qnil)) {
04912       case -1:
04913         rb_sys_fail("daemon");
04914       case 0:
04915         break;
04916       default:
04917         _exit(EXIT_SUCCESS);
04918     }
04919 
04920     proc_setsid();
04921 
04922     /* must not be process-leader */
04923     switch (rb_fork(0, 0, 0, Qnil)) {
04924       case -1:
04925         return -1;
04926       case 0:
04927         break;
04928       default:
04929         _exit(EXIT_SUCCESS);
04930     }
04931 
04932     if (!nochdir)
04933         err = chdir("/");
04934 
04935     if (!noclose && (n = open("/dev/null", O_RDWR, 0)) != -1) {
04936         rb_update_max_fd(n);
04937         (void)dup2(n, 0);
04938         (void)dup2(n, 1);
04939         (void)dup2(n, 2);
04940         if (n > 2)
04941             (void)close (n);
04942     }
04943 #endif
04944     return err;
04945 }
04946 #else
04947 #define proc_daemon rb_f_notimplement
04948 #endif
04949 
04950 /********************************************************************
04951  *
04952  * Document-class: Process::GID
04953  *
04954  *  The <code>Process::GID</code> module contains a collection of
04955  *  module functions which can be used to portably get, set, and
04956  *  switch the current process's real, effective, and saved group IDs.
04957  *
04958  */
04959 
04960 static rb_gid_t SAVED_GROUP_ID = -1;
04961 
04962 #ifdef BROKEN_SETREGID
04963 int
04964 setregid(rb_gid_t rgid, rb_gid_t egid)
04965 {
04966     if (rgid != (rb_gid_t)-1 && rgid != getgid()) {
04967         if (egid == (rb_gid_t)-1) egid = getegid();
04968         if (setgid(rgid) < 0) return -1;
04969     }
04970     if (egid != (rb_gid_t)-1 && egid != getegid()) {
04971         if (setegid(egid) < 0) return -1;
04972     }
04973     return 0;
04974 }
04975 #endif
04976 
04977 /*
04978  *  call-seq:
04979  *     Process::GID.change_privilege(integer)   -> fixnum
04980  *
04981  *  Change the current process's real and effective group ID to that
04982  *  specified by _integer_. Returns the new group ID. Not
04983  *  available on all platforms.
04984  *
04985  *     [Process.gid, Process.egid]          #=> [0, 0]
04986  *     Process::GID.change_privilege(33)    #=> 33
04987  *     [Process.gid, Process.egid]          #=> [33, 33]
04988  */
04989 
04990 static VALUE
04991 p_gid_change_privilege(VALUE obj, VALUE id)
04992 {
04993     rb_gid_t gid;
04994 
04995     check_gid_switch();
04996 
04997     gid = NUM2GIDT(id);
04998 
04999     if (geteuid() == 0) { /* root-user */
05000 #if defined(HAVE_SETRESGID)
05001         if (setresgid(gid, gid, gid) < 0) rb_sys_fail(0);
05002         SAVED_GROUP_ID = gid;
05003 #elif defined HAVE_SETGID
05004         if (setgid(gid) < 0) rb_sys_fail(0);
05005         SAVED_GROUP_ID = gid;
05006 #elif defined(HAVE_SETREGID) && !defined(OBSOLETE_SETREGID)
05007         if (getgid() == gid) {
05008             if (SAVED_GROUP_ID == gid) {
05009                 if (setregid(-1, gid) < 0) rb_sys_fail(0);
05010             } else {
05011                 if (gid == 0) { /* (r,e,s) == (root, y, x) */
05012                     if (setregid(-1, SAVED_GROUP_ID) < 0) rb_sys_fail(0);
05013                     if (setregid(SAVED_GROUP_ID, 0) < 0) rb_sys_fail(0);
05014                     SAVED_GROUP_ID = 0; /* (r,e,s) == (x, root, root) */
05015                     if (setregid(gid, gid) < 0) rb_sys_fail(0);
05016                     SAVED_GROUP_ID = gid;
05017                 } else { /* (r,e,s) == (z, y, x) */
05018                     if (setregid(0, 0) < 0) rb_sys_fail(0);
05019                     SAVED_GROUP_ID = 0;
05020                     if (setregid(gid, gid) < 0) rb_sys_fail(0);
05021                     SAVED_GROUP_ID = gid;
05022                 }
05023             }
05024         } else {
05025             if (setregid(gid, gid) < 0) rb_sys_fail(0);
05026             SAVED_GROUP_ID = gid;
05027         }
05028 #elif defined(HAVE_SETRGID) && defined (HAVE_SETEGID)
05029         if (getgid() == gid) {
05030             if (SAVED_GROUP_ID == gid) {
05031                 if (setegid(gid) < 0) rb_sys_fail(0);
05032             } else {
05033                 if (gid == 0) {
05034                     if (setegid(gid) < 0) rb_sys_fail(0);
05035                     if (setrgid(SAVED_GROUP_ID) < 0) rb_sys_fail(0);
05036                     SAVED_GROUP_ID = 0;
05037                     if (setrgid(0) < 0) rb_sys_fail(0);
05038                 } else {
05039                     if (setrgid(0) < 0) rb_sys_fail(0);
05040                     SAVED_GROUP_ID = 0;
05041                     if (setegid(gid) < 0) rb_sys_fail(0);
05042                     if (setrgid(gid) < 0) rb_sys_fail(0);
05043                     SAVED_GROUP_ID = gid;
05044                 }
05045             }
05046         } else {
05047             if (setegid(gid) < 0) rb_sys_fail(0);
05048             if (setrgid(gid) < 0) rb_sys_fail(0);
05049             SAVED_GROUP_ID = gid;
05050         }
05051 #else
05052         rb_notimplement();
05053 #endif
05054     } else { /* unprivileged user */
05055 #if defined(HAVE_SETRESGID)
05056         if (setresgid((getgid() == gid)? (rb_gid_t)-1: gid,
05057                       (getegid() == gid)? (rb_gid_t)-1: gid,
05058                       (SAVED_GROUP_ID == gid)? (rb_gid_t)-1: gid) < 0) rb_sys_fail(0);
05059         SAVED_GROUP_ID = gid;
05060 #elif defined(HAVE_SETREGID) && !defined(OBSOLETE_SETREGID)
05061         if (SAVED_GROUP_ID == gid) {
05062             if (setregid((getgid() == gid)? (rb_uid_t)-1: gid,
05063                          (getegid() == gid)? (rb_uid_t)-1: gid) < 0)
05064                 rb_sys_fail(0);
05065         } else if (getgid() != gid) {
05066             if (setregid(gid, (getegid() == gid)? (rb_uid_t)-1: gid) < 0)
05067                 rb_sys_fail(0);
05068             SAVED_GROUP_ID = gid;
05069         } else if (/* getgid() == gid && */ getegid() != gid) {
05070             if (setregid(getegid(), gid) < 0) rb_sys_fail(0);
05071             SAVED_GROUP_ID = gid;
05072             if (setregid(gid, -1) < 0) rb_sys_fail(0);
05073         } else { /* getgid() == gid && getegid() == gid */
05074             if (setregid(-1, SAVED_GROUP_ID) < 0) rb_sys_fail(0);
05075             if (setregid(SAVED_GROUP_ID, gid) < 0) rb_sys_fail(0);
05076             SAVED_GROUP_ID = gid;
05077             if (setregid(gid, -1) < 0) rb_sys_fail(0);
05078         }
05079 #elif defined(HAVE_SETRGID) && defined(HAVE_SETEGID)
05080         if (SAVED_GROUP_ID == gid) {
05081             if (getegid() != gid && setegid(gid) < 0) rb_sys_fail(0);
05082             if (getgid() != gid && setrgid(gid) < 0) rb_sys_fail(0);
05083         } else if (/* SAVED_GROUP_ID != gid && */ getegid() == gid) {
05084             if (getgid() != gid) {
05085                 if (setrgid(gid) < 0) rb_sys_fail(0);
05086                 SAVED_GROUP_ID = gid;
05087             } else {
05088                 if (setrgid(SAVED_GROUP_ID) < 0) rb_sys_fail(0);
05089                 SAVED_GROUP_ID = gid;
05090                 if (setrgid(gid) < 0) rb_sys_fail(0);
05091         }
05092         } else if (/* getegid() != gid && */ getgid() == gid) {
05093             if (setegid(gid) < 0) rb_sys_fail(0);
05094             if (setrgid(SAVED_GROUP_ID) < 0) rb_sys_fail(0);
05095             SAVED_GROUP_ID = gid;
05096             if (setrgid(gid) < 0) rb_sys_fail(0);
05097         } else {
05098             errno = EPERM;
05099             rb_sys_fail(0);
05100         }
05101 #elif defined HAVE_44BSD_SETGID
05102         if (getgid() == gid) {
05103             /* (r,e,s)==(gid,?,?) ==> (gid,gid,gid) */
05104             if (setgid(gid) < 0) rb_sys_fail(0);
05105             SAVED_GROUP_ID = gid;
05106         } else {
05107             errno = EPERM;
05108             rb_sys_fail(0);
05109         }
05110 #elif defined HAVE_SETEGID
05111         if (getgid() == gid && SAVED_GROUP_ID == gid) {
05112             if (setegid(gid) < 0) rb_sys_fail(0);
05113         } else {
05114             errno = EPERM;
05115             rb_sys_fail(0);
05116         }
05117 #elif defined HAVE_SETGID
05118         if (getgid() == gid && SAVED_GROUP_ID == gid) {
05119             if (setgid(gid) < 0) rb_sys_fail(0);
05120         } else {
05121             errno = EPERM;
05122             rb_sys_fail(0);
05123         }
05124 #else
05125         rb_notimplement();
05126 #endif
05127     }
05128     return id;
05129 }
05130 
05131 
05132 /*
05133  *  call-seq:
05134  *     Process.euid           -> fixnum
05135  *     Process::UID.eid       -> fixnum
05136  *     Process::Sys.geteuid   -> fixnum
05137  *
05138  *  Returns the effective user ID for this process.
05139  *
05140  *     Process.euid   #=> 501
05141  */
05142 
05143 static VALUE
05144 proc_geteuid(VALUE obj)
05145 {
05146     rb_uid_t euid = geteuid();
05147     return UIDT2NUM(euid);
05148 }
05149 
05150 #if defined(HAVE_SETRESUID) || defined(HAVE_SETREUID) || defined(HAVE_SETEUID) || defined(HAVE_SETUID) || defined(_POSIX_SAVED_IDS)
05151 /*
05152  *  call-seq:
05153  *     Process.euid= integer
05154  *
05155  *  Sets the effective user ID for this process. Not available on all
05156  *  platforms.
05157  */
05158 
05159 static VALUE
05160 proc_seteuid(VALUE obj, VALUE euid)
05161 {
05162     rb_uid_t uid;
05163 
05164     check_uid_switch();
05165 
05166     uid = NUM2UIDT(euid);
05167 #if defined(HAVE_SETRESUID)
05168     if (setresuid(-1, uid, -1) < 0) rb_sys_fail(0);
05169 #elif defined HAVE_SETREUID
05170     if (setreuid(-1, uid) < 0) rb_sys_fail(0);
05171 #elif defined HAVE_SETEUID
05172     if (seteuid(uid) < 0) rb_sys_fail(0);
05173 #elif defined HAVE_SETUID
05174     if (uid == getuid()) {
05175         if (setuid(uid) < 0) rb_sys_fail(0);
05176     }
05177     else {
05178         rb_notimplement();
05179     }
05180 #else
05181     rb_notimplement();
05182 #endif
05183     return euid;
05184 }
05185 #endif
05186 
05187 #if defined(HAVE_SETRESUID) || defined(HAVE_SETREUID) || defined(HAVE_SETEUID) || defined(HAVE_SETUID)
05188 #define proc_seteuid_m proc_seteuid
05189 #else
05190 #define proc_seteuid_m rb_f_notimplement
05191 #endif
05192 
05193 static rb_uid_t
05194 rb_seteuid_core(rb_uid_t euid)
05195 {
05196     rb_uid_t uid;
05197 
05198     check_uid_switch();
05199 
05200     uid = getuid();
05201 
05202 #if defined(HAVE_SETRESUID)
05203     if (uid != euid) {
05204         if (setresuid(-1,euid,euid) < 0) rb_sys_fail(0);
05205         SAVED_USER_ID = euid;
05206     } else {
05207         if (setresuid(-1,euid,-1) < 0) rb_sys_fail(0);
05208     }
05209 #elif defined(HAVE_SETREUID) && !defined(OBSOLETE_SETREUID)
05210     if (setreuid(-1, euid) < 0) rb_sys_fail(0);
05211     if (uid != euid) {
05212         if (setreuid(euid,uid) < 0) rb_sys_fail(0);
05213         if (setreuid(uid,euid) < 0) rb_sys_fail(0);
05214         SAVED_USER_ID = euid;
05215     }
05216 #elif defined HAVE_SETEUID
05217     if (seteuid(euid) < 0) rb_sys_fail(0);
05218 #elif defined HAVE_SETUID
05219     if (geteuid() == 0) rb_sys_fail(0);
05220     if (setuid(euid) < 0) rb_sys_fail(0);
05221 #else
05222     rb_notimplement();
05223 #endif
05224     return euid;
05225 }
05226 
05227 
05228 /*
05229  *  call-seq:
05230  *     Process::UID.grant_privilege(integer)   -> fixnum
05231  *     Process::UID.eid= integer               -> fixnum
05232  *
05233  *  Set the effective user ID, and if possible, the saved user ID of
05234  *  the process to the given _integer_. Returns the new
05235  *  effective user ID. Not available on all platforms.
05236  *
05237  *     [Process.uid, Process.euid]          #=> [0, 0]
05238  *     Process::UID.grant_privilege(31)     #=> 31
05239  *     [Process.uid, Process.euid]          #=> [0, 31]
05240  */
05241 
05242 static VALUE
05243 p_uid_grant_privilege(VALUE obj, VALUE id)
05244 {
05245     rb_seteuid_core(NUM2UIDT(id));
05246     return id;
05247 }
05248 
05249 
05250 /*
05251  *  call-seq:
05252  *     Process.egid          -> fixnum
05253  *     Process::GID.eid      -> fixnum
05254  *     Process::Sys.geteid   -> fixnum
05255  *
05256  *  Returns the effective group ID for this process. Not available on
05257  *  all platforms.
05258  *
05259  *     Process.egid   #=> 500
05260  */
05261 
05262 static VALUE
05263 proc_getegid(VALUE obj)
05264 {
05265     rb_gid_t egid = getegid();
05266 
05267     return GIDT2NUM(egid);
05268 }
05269 
05270 #if defined(HAVE_SETRESGID) || defined(HAVE_SETREGID) || defined(HAVE_SETEGID) || defined(HAVE_SETGID) || defined(_POSIX_SAVED_IDS)
05271 /*
05272  *  call-seq:
05273  *     Process.egid = fixnum   -> fixnum
05274  *
05275  *  Sets the effective group ID for this process. Not available on all
05276  *  platforms.
05277  */
05278 
05279 static VALUE
05280 proc_setegid(VALUE obj, VALUE egid)
05281 {
05282     rb_gid_t gid;
05283 
05284     check_gid_switch();
05285 
05286     gid = NUM2GIDT(egid);
05287 #if defined(HAVE_SETRESGID)
05288     if (setresgid(-1, gid, -1) < 0) rb_sys_fail(0);
05289 #elif defined HAVE_SETREGID
05290     if (setregid(-1, gid) < 0) rb_sys_fail(0);
05291 #elif defined HAVE_SETEGID
05292     if (setegid(gid) < 0) rb_sys_fail(0);
05293 #elif defined HAVE_SETGID
05294     if (gid == getgid()) {
05295         if (setgid(gid) < 0) rb_sys_fail(0);
05296     }
05297     else {
05298         rb_notimplement();
05299     }
05300 #else
05301     rb_notimplement();
05302 #endif
05303     return egid;
05304 }
05305 #endif
05306 
05307 #if defined(HAVE_SETRESGID) || defined(HAVE_SETREGID) || defined(HAVE_SETEGID) || defined(HAVE_SETGID)
05308 #define proc_setegid_m proc_setegid
05309 #else
05310 #define proc_setegid_m rb_f_notimplement
05311 #endif
05312 
05313 static rb_gid_t
05314 rb_setegid_core(rb_gid_t egid)
05315 {
05316     rb_gid_t gid;
05317 
05318     check_gid_switch();
05319 
05320     gid = getgid();
05321 
05322 #if defined(HAVE_SETRESGID)
05323     if (gid != egid) {
05324         if (setresgid(-1,egid,egid) < 0) rb_sys_fail(0);
05325         SAVED_GROUP_ID = egid;
05326     } else {
05327         if (setresgid(-1,egid,-1) < 0) rb_sys_fail(0);
05328     }
05329 #elif defined(HAVE_SETREGID) && !defined(OBSOLETE_SETREGID)
05330     if (setregid(-1, egid) < 0) rb_sys_fail(0);
05331     if (gid != egid) {
05332         if (setregid(egid,gid) < 0) rb_sys_fail(0);
05333         if (setregid(gid,egid) < 0) rb_sys_fail(0);
05334         SAVED_GROUP_ID = egid;
05335     }
05336 #elif defined HAVE_SETEGID
05337     if (setegid(egid) < 0) rb_sys_fail(0);
05338 #elif defined HAVE_SETGID
05339     if (geteuid() == 0 /* root user */) rb_sys_fail(0);
05340     if (setgid(egid) < 0) rb_sys_fail(0);
05341 #else
05342     rb_notimplement();
05343 #endif
05344     return egid;
05345 }
05346 
05347 
05348 /*
05349  *  call-seq:
05350  *     Process::GID.grant_privilege(integer)    -> fixnum
05351  *     Process::GID.eid = integer               -> fixnum
05352  *
05353  *  Set the effective group ID, and if possible, the saved group ID of
05354  *  the process to the given _integer_. Returns the new
05355  *  effective group ID. Not available on all platforms.
05356  *
05357  *     [Process.gid, Process.egid]          #=> [0, 0]
05358  *     Process::GID.grant_privilege(31)     #=> 33
05359  *     [Process.gid, Process.egid]          #=> [0, 33]
05360  */
05361 
05362 static VALUE
05363 p_gid_grant_privilege(VALUE obj, VALUE id)
05364 {
05365     rb_setegid_core(NUM2GIDT(id));
05366     return id;
05367 }
05368 
05369 
05370 /*
05371  *  call-seq:
05372  *     Process::UID.re_exchangeable?   -> true or false
05373  *
05374  *  Returns +true+ if the real and effective user IDs of a
05375  *  process may be exchanged on the current platform.
05376  *
05377  */
05378 
05379 static VALUE
05380 p_uid_exchangeable(void)
05381 {
05382 #if defined(HAVE_SETRESUID)
05383     return Qtrue;
05384 #elif defined(HAVE_SETREUID) && !defined(OBSOLETE_SETREUID)
05385     return Qtrue;
05386 #else
05387     return Qfalse;
05388 #endif
05389 }
05390 
05391 
05392 /*
05393  *  call-seq:
05394  *     Process::UID.re_exchange   -> fixnum
05395  *
05396  *  Exchange real and effective user IDs and return the new effective
05397  *  user ID. Not available on all platforms.
05398  *
05399  *     [Process.uid, Process.euid]   #=> [0, 31]
05400  *     Process::UID.re_exchange      #=> 0
05401  *     [Process.uid, Process.euid]   #=> [31, 0]
05402  */
05403 
05404 static VALUE
05405 p_uid_exchange(VALUE obj)
05406 {
05407     rb_uid_t uid, euid;
05408 
05409     check_uid_switch();
05410 
05411     uid = getuid();
05412     euid = geteuid();
05413 
05414 #if defined(HAVE_SETRESUID)
05415     if (setresuid(euid, uid, uid) < 0) rb_sys_fail(0);
05416     SAVED_USER_ID = uid;
05417 #elif defined(HAVE_SETREUID) && !defined(OBSOLETE_SETREUID)
05418     if (setreuid(euid,uid) < 0) rb_sys_fail(0);
05419     SAVED_USER_ID = uid;
05420 #else
05421     rb_notimplement();
05422 #endif
05423     return UIDT2NUM(uid);
05424 }
05425 
05426 
05427 /*
05428  *  call-seq:
05429  *     Process::GID.re_exchangeable?   -> true or false
05430  *
05431  *  Returns +true+ if the real and effective group IDs of a
05432  *  process may be exchanged on the current platform.
05433  *
05434  */
05435 
05436 static VALUE
05437 p_gid_exchangeable(void)
05438 {
05439 #if defined(HAVE_SETRESGID)
05440     return Qtrue;
05441 #elif defined(HAVE_SETREGID) && !defined(OBSOLETE_SETREGID)
05442     return Qtrue;
05443 #else
05444     return Qfalse;
05445 #endif
05446 }
05447 
05448 
05449 /*
05450  *  call-seq:
05451  *     Process::GID.re_exchange   -> fixnum
05452  *
05453  *  Exchange real and effective group IDs and return the new effective
05454  *  group ID. Not available on all platforms.
05455  *
05456  *     [Process.gid, Process.egid]   #=> [0, 33]
05457  *     Process::GID.re_exchange      #=> 0
05458  *     [Process.gid, Process.egid]   #=> [33, 0]
05459  */
05460 
05461 static VALUE
05462 p_gid_exchange(VALUE obj)
05463 {
05464     rb_gid_t gid, egid;
05465 
05466     check_gid_switch();
05467 
05468     gid = getgid();
05469     egid = getegid();
05470 
05471 #if defined(HAVE_SETRESGID)
05472     if (setresgid(egid, gid, gid) < 0) rb_sys_fail(0);
05473     SAVED_GROUP_ID = gid;
05474 #elif defined(HAVE_SETREGID) && !defined(OBSOLETE_SETREGID)
05475     if (setregid(egid,gid) < 0) rb_sys_fail(0);
05476     SAVED_GROUP_ID = gid;
05477 #else
05478     rb_notimplement();
05479 #endif
05480     return GIDT2NUM(gid);
05481 }
05482 
05483 /* [MG] :FIXME: Is this correct? I'm not sure how to phrase this. */
05484 
05485 /*
05486  *  call-seq:
05487  *     Process::UID.sid_available?   -> true or false
05488  *
05489  *  Returns +true+ if the current platform has saved user
05490  *  ID functionality.
05491  *
05492  */
05493 
05494 static VALUE
05495 p_uid_have_saved_id(void)
05496 {
05497 #if defined(HAVE_SETRESUID) || defined(HAVE_SETEUID) || defined(_POSIX_SAVED_IDS)
05498     return Qtrue;
05499 #else
05500     return Qfalse;
05501 #endif
05502 }
05503 
05504 
05505 #if defined(HAVE_SETRESUID) || defined(HAVE_SETEUID) || defined(_POSIX_SAVED_IDS)
05506 static VALUE
05507 p_uid_sw_ensure(rb_uid_t id)
05508 {
05509     under_uid_switch = 0;
05510     id = rb_seteuid_core(id);
05511     return UIDT2NUM(id);
05512 }
05513 
05514 
05515 /*
05516  *  call-seq:
05517  *     Process::UID.switch              -> fixnum
05518  *     Process::UID.switch {|| block}   -> object
05519  *
05520  *  Switch the effective and real user IDs of the current process. If
05521  *  a <em>block</em> is given, the user IDs will be switched back
05522  *  after the block is executed. Returns the new effective user ID if
05523  *  called without a block, and the return value of the block if one
05524  *  is given.
05525  *
05526  */
05527 
05528 static VALUE
05529 p_uid_switch(VALUE obj)
05530 {
05531     rb_uid_t uid, euid;
05532 
05533     check_uid_switch();
05534 
05535     uid = getuid();
05536     euid = geteuid();
05537 
05538     if (uid != euid) {
05539         proc_seteuid(obj, UIDT2NUM(uid));
05540         if (rb_block_given_p()) {
05541             under_uid_switch = 1;
05542             return rb_ensure(rb_yield, Qnil, p_uid_sw_ensure, SAVED_USER_ID);
05543         } else {
05544             return UIDT2NUM(euid);
05545         }
05546     } else if (euid != SAVED_USER_ID) {
05547         proc_seteuid(obj, UIDT2NUM(SAVED_USER_ID));
05548         if (rb_block_given_p()) {
05549             under_uid_switch = 1;
05550             return rb_ensure(rb_yield, Qnil, p_uid_sw_ensure, euid);
05551         } else {
05552             return UIDT2NUM(uid);
05553         }
05554     } else {
05555         errno = EPERM;
05556         rb_sys_fail(0);
05557     }
05558 }
05559 #else
05560 static VALUE
05561 p_uid_sw_ensure(VALUE obj)
05562 {
05563     under_uid_switch = 0;
05564     return p_uid_exchange(obj);
05565 }
05566 
05567 static VALUE
05568 p_uid_switch(VALUE obj)
05569 {
05570     rb_uid_t uid, euid;
05571 
05572     check_uid_switch();
05573 
05574     uid = getuid();
05575     euid = geteuid();
05576 
05577     if (uid == euid) {
05578         errno = EPERM;
05579         rb_sys_fail(0);
05580     }
05581     p_uid_exchange(obj);
05582     if (rb_block_given_p()) {
05583         under_uid_switch = 1;
05584         return rb_ensure(rb_yield, Qnil, p_uid_sw_ensure, obj);
05585     } else {
05586         return UIDT2NUM(euid);
05587     }
05588 }
05589 #endif
05590 
05591 
05592 /* [MG] :FIXME: Is this correct? I'm not sure how to phrase this. */
05593 
05594 /*
05595  *  call-seq:
05596  *     Process::GID.sid_available?   -> true or false
05597  *
05598  *  Returns +true+ if the current platform has saved group
05599  *  ID functionality.
05600  *
05601  */
05602 
05603 static VALUE
05604 p_gid_have_saved_id(void)
05605 {
05606 #if defined(HAVE_SETRESGID) || defined(HAVE_SETEGID) || defined(_POSIX_SAVED_IDS)
05607     return Qtrue;
05608 #else
05609     return Qfalse;
05610 #endif
05611 }
05612 
05613 #if defined(HAVE_SETRESGID) || defined(HAVE_SETEGID) || defined(_POSIX_SAVED_IDS)
05614 static VALUE
05615 p_gid_sw_ensure(rb_gid_t id)
05616 {
05617     under_gid_switch = 0;
05618     id = rb_setegid_core(id);
05619     return GIDT2NUM(id);
05620 }
05621 
05622 
05623 /*
05624  *  call-seq:
05625  *     Process::GID.switch              -> fixnum
05626  *     Process::GID.switch {|| block}   -> object
05627  *
05628  *  Switch the effective and real group IDs of the current process. If
05629  *  a <em>block</em> is given, the group IDs will be switched back
05630  *  after the block is executed. Returns the new effective group ID if
05631  *  called without a block, and the return value of the block if one
05632  *  is given.
05633  *
05634  */
05635 
05636 static VALUE
05637 p_gid_switch(VALUE obj)
05638 {
05639     rb_gid_t gid, egid;
05640 
05641     check_gid_switch();
05642 
05643     gid = getgid();
05644     egid = getegid();
05645 
05646     if (gid != egid) {
05647         proc_setegid(obj, GIDT2NUM(gid));
05648         if (rb_block_given_p()) {
05649             under_gid_switch = 1;
05650             return rb_ensure(rb_yield, Qnil, p_gid_sw_ensure, SAVED_GROUP_ID);
05651         } else {
05652             return GIDT2NUM(egid);
05653         }
05654     }
05655     else if (egid != SAVED_GROUP_ID) {
05656         proc_setegid(obj, GIDT2NUM(SAVED_GROUP_ID));
05657         if (rb_block_given_p()) {
05658             under_gid_switch = 1;
05659             return rb_ensure(rb_yield, Qnil, p_gid_sw_ensure, egid);
05660         } else {
05661             return GIDT2NUM(gid);
05662         }
05663     }
05664     else {
05665         errno = EPERM;
05666         rb_sys_fail(0);
05667     }
05668 }
05669 #else
05670 static VALUE
05671 p_gid_sw_ensure(VALUE obj)
05672 {
05673     under_gid_switch = 0;
05674     return p_gid_exchange(obj);
05675 }
05676 
05677 static VALUE
05678 p_gid_switch(VALUE obj)
05679 {
05680     rb_gid_t gid, egid;
05681 
05682     check_gid_switch();
05683 
05684     gid = getgid();
05685     egid = getegid();
05686 
05687     if (gid == egid) {
05688         errno = EPERM;
05689         rb_sys_fail(0);
05690     }
05691     p_gid_exchange(obj);
05692     if (rb_block_given_p()) {
05693         under_gid_switch = 1;
05694         return rb_ensure(rb_yield, Qnil, p_gid_sw_ensure, obj);
05695     } else {
05696         return GIDT2NUM(egid);
05697     }
05698 }
05699 #endif
05700 
05701 
05702 #if defined(HAVE_TIMES)
05703 /*
05704  *  call-seq:
05705  *     Process.times   -> aStructTms
05706  *
05707  *  Returns a <code>Tms</code> structure (see <code>Struct::Tms</code>)
05708  *  that contains user and system CPU times for this process,
05709  *  and also for children processes.
05710  *
05711  *     t = Process.times
05712  *     [ t.utime, t.stime, t.cutime, t.cstime ]   #=> [0.0, 0.02, 0.00, 0.00]
05713  */
05714 
05715 VALUE
05716 rb_proc_times(VALUE obj)
05717 {
05718     const double hertz =
05719 #ifdef HAVE__SC_CLK_TCK
05720         (double)sysconf(_SC_CLK_TCK);
05721 #else
05722 #ifndef HZ
05723 # ifdef CLK_TCK
05724 #   define HZ CLK_TCK
05725 # else
05726 #   define HZ 60
05727 # endif
05728 #endif /* HZ */
05729         HZ;
05730 #endif
05731     struct tms buf;
05732     volatile VALUE utime, stime, cutime, sctime;
05733 
05734     times(&buf);
05735     return rb_struct_new(rb_cProcessTms,
05736                          utime = DBL2NUM(buf.tms_utime / hertz),
05737                          stime = DBL2NUM(buf.tms_stime / hertz),
05738                          cutime = DBL2NUM(buf.tms_cutime / hertz),
05739                          sctime = DBL2NUM(buf.tms_cstime / hertz));
05740 }
05741 #else
05742 #define rb_proc_times rb_f_notimplement
05743 #endif
05744 
05745 VALUE rb_mProcess;
05746 VALUE rb_mProcUID;
05747 VALUE rb_mProcGID;
05748 VALUE rb_mProcID_Syscall;
05749 
05750 
05751 /*
05752  *  The <code>Process</code> module is a collection of methods used to
05753  *  manipulate processes.
05754  */
05755 
05756 void
05757 Init_process(void)
05758 {
05759     rb_define_virtual_variable("$?", rb_last_status_get, 0);
05760     rb_define_virtual_variable("$$", get_pid, 0);
05761     rb_define_global_function("exec", rb_f_exec, -1);
05762     rb_define_global_function("fork", rb_f_fork, 0);
05763     rb_define_global_function("exit!", rb_f_exit_bang, -1);
05764     rb_define_global_function("system", rb_f_system, -1);
05765     rb_define_global_function("spawn", rb_f_spawn, -1);
05766     rb_define_global_function("sleep", rb_f_sleep, -1);
05767     rb_define_global_function("exit", rb_f_exit, -1);
05768     rb_define_global_function("abort", rb_f_abort, -1);
05769 
05770     rb_mProcess = rb_define_module("Process");
05771 
05772 #ifdef WNOHANG
05773     /* see Process.wait */
05774     rb_define_const(rb_mProcess, "WNOHANG", INT2FIX(WNOHANG));
05775 #else
05776     /* see Process.wait */
05777     rb_define_const(rb_mProcess, "WNOHANG", INT2FIX(0));
05778 #endif
05779 #ifdef WUNTRACED
05780     /* see Process.wait */
05781     rb_define_const(rb_mProcess, "WUNTRACED", INT2FIX(WUNTRACED));
05782 #else
05783     /* see Process.wait */
05784     rb_define_const(rb_mProcess, "WUNTRACED", INT2FIX(0));
05785 #endif
05786 
05787     rb_define_singleton_method(rb_mProcess, "exec", rb_f_exec, -1);
05788     rb_define_singleton_method(rb_mProcess, "fork", rb_f_fork, 0);
05789     rb_define_singleton_method(rb_mProcess, "spawn", rb_f_spawn, -1);
05790     rb_define_singleton_method(rb_mProcess, "exit!", rb_f_exit_bang, -1);
05791     rb_define_singleton_method(rb_mProcess, "exit", rb_f_exit, -1);
05792     rb_define_singleton_method(rb_mProcess, "abort", rb_f_abort, -1);
05793 
05794     rb_define_module_function(rb_mProcess, "kill", rb_f_kill, -1); /* in signal.c */
05795     rb_define_module_function(rb_mProcess, "wait", proc_wait, -1);
05796     rb_define_module_function(rb_mProcess, "wait2", proc_wait2, -1);
05797     rb_define_module_function(rb_mProcess, "waitpid", proc_wait, -1);
05798     rb_define_module_function(rb_mProcess, "waitpid2", proc_wait2, -1);
05799     rb_define_module_function(rb_mProcess, "waitall", proc_waitall, 0);
05800     rb_define_module_function(rb_mProcess, "detach", proc_detach, 1);
05801 
05802     rb_cProcessStatus = rb_define_class_under(rb_mProcess, "Status", rb_cObject);
05803     rb_undef_method(CLASS_OF(rb_cProcessStatus), "new");
05804 
05805     rb_define_method(rb_cProcessStatus, "==", pst_equal, 1);
05806     rb_define_method(rb_cProcessStatus, "&", pst_bitand, 1);
05807     rb_define_method(rb_cProcessStatus, ">>", pst_rshift, 1);
05808     rb_define_method(rb_cProcessStatus, "to_i", pst_to_i, 0);
05809     rb_define_method(rb_cProcessStatus, "to_s", pst_to_s, 0);
05810     rb_define_method(rb_cProcessStatus, "inspect", pst_inspect, 0);
05811 
05812     rb_define_method(rb_cProcessStatus, "pid", pst_pid, 0);
05813 
05814     rb_define_method(rb_cProcessStatus, "stopped?", pst_wifstopped, 0);
05815     rb_define_method(rb_cProcessStatus, "stopsig", pst_wstopsig, 0);
05816     rb_define_method(rb_cProcessStatus, "signaled?", pst_wifsignaled, 0);
05817     rb_define_method(rb_cProcessStatus, "termsig", pst_wtermsig, 0);
05818     rb_define_method(rb_cProcessStatus, "exited?", pst_wifexited, 0);
05819     rb_define_method(rb_cProcessStatus, "exitstatus", pst_wexitstatus, 0);
05820     rb_define_method(rb_cProcessStatus, "success?", pst_success_p, 0);
05821     rb_define_method(rb_cProcessStatus, "coredump?", pst_wcoredump, 0);
05822 
05823     rb_define_module_function(rb_mProcess, "pid", get_pid, 0);
05824     rb_define_module_function(rb_mProcess, "ppid", get_ppid, 0);
05825 
05826     rb_define_module_function(rb_mProcess, "getpgrp", proc_getpgrp, 0);
05827     rb_define_module_function(rb_mProcess, "setpgrp", proc_setpgrp, 0);
05828     rb_define_module_function(rb_mProcess, "getpgid", proc_getpgid, 1);
05829     rb_define_module_function(rb_mProcess, "setpgid", proc_setpgid, 2);
05830 
05831     rb_define_module_function(rb_mProcess, "setsid", proc_setsid, 0);
05832 
05833     rb_define_module_function(rb_mProcess, "getpriority", proc_getpriority, 2);
05834     rb_define_module_function(rb_mProcess, "setpriority", proc_setpriority, 3);
05835 
05836 #ifdef HAVE_GETPRIORITY
05837     /* see Process.setpriority */
05838     rb_define_const(rb_mProcess, "PRIO_PROCESS", INT2FIX(PRIO_PROCESS));
05839     /* see Process.setpriority */
05840     rb_define_const(rb_mProcess, "PRIO_PGRP", INT2FIX(PRIO_PGRP));
05841     /* see Process.setpriority */
05842     rb_define_const(rb_mProcess, "PRIO_USER", INT2FIX(PRIO_USER));
05843 #endif
05844 
05845     rb_define_module_function(rb_mProcess, "getrlimit", proc_getrlimit, 1);
05846     rb_define_module_function(rb_mProcess, "setrlimit", proc_setrlimit, -1);
05847 #if defined(RLIM2NUM) && defined(RLIM_INFINITY)
05848     {
05849         VALUE inf = RLIM2NUM(RLIM_INFINITY);
05850 #ifdef RLIM_SAVED_MAX
05851         {
05852             VALUE v = RLIM_INFINITY == RLIM_SAVED_MAX ? inf : RLIM2NUM(RLIM_SAVED_MAX);
05853             /* see Process.setrlimit */
05854             rb_define_const(rb_mProcess, "RLIM_SAVED_MAX", v);
05855         }
05856 #endif
05857         /* see Process.setrlimit */
05858         rb_define_const(rb_mProcess, "RLIM_INFINITY", inf);
05859 #ifdef RLIM_SAVED_CUR
05860         {
05861             VALUE v = RLIM_INFINITY == RLIM_SAVED_CUR ? inf : RLIM2NUM(RLIM_SAVED_CUR);
05862             /* see Process.setrlimit */
05863             rb_define_const(rb_mProcess, "RLIM_SAVED_CUR", v);
05864         }
05865 #endif
05866     }
05867 #ifdef RLIMIT_AS
05868     /* Maximum size of the process's virtual memory (address space) in bytes.
05869      *
05870      * see the system getrlimit(2) manual for details.
05871      */
05872     rb_define_const(rb_mProcess, "RLIMIT_AS", INT2FIX(RLIMIT_AS));
05873 #endif
05874 #ifdef RLIMIT_CORE
05875     /* Maximum size of the core file.
05876      *
05877      * see the system getrlimit(2) manual for details.
05878      */
05879     rb_define_const(rb_mProcess, "RLIMIT_CORE", INT2FIX(RLIMIT_CORE));
05880 #endif
05881 #ifdef RLIMIT_CPU
05882     /* CPU time limit in seconds.
05883      *
05884      * see the system getrlimit(2) manual for details.
05885      */
05886     rb_define_const(rb_mProcess, "RLIMIT_CPU", INT2FIX(RLIMIT_CPU));
05887 #endif
05888 #ifdef RLIMIT_DATA
05889     /* Maximum size of the process's data segment.
05890      *
05891      * see the system getrlimit(2) manual for details.
05892      */
05893     rb_define_const(rb_mProcess, "RLIMIT_DATA", INT2FIX(RLIMIT_DATA));
05894 #endif
05895 #ifdef RLIMIT_FSIZE
05896     /* Maximum size of files that the process may create.
05897      *
05898      * see the system getrlimit(2) manual for details.
05899      */
05900     rb_define_const(rb_mProcess, "RLIMIT_FSIZE", INT2FIX(RLIMIT_FSIZE));
05901 #endif
05902 #ifdef RLIMIT_MEMLOCK
05903     /* Maximum number of bytes of memory that may be locked into RAM.
05904      *
05905      * see the system getrlimit(2) manual for details.
05906      */
05907     rb_define_const(rb_mProcess, "RLIMIT_MEMLOCK", INT2FIX(RLIMIT_MEMLOCK));
05908 #endif
05909 #ifdef RLIMIT_MSGQUEUE
05910     /* Specifies the limit on the number of bytes that can be allocated
05911      * for POSIX message queues for the real user ID of the calling process.
05912      *
05913      * see the system getrlimit(2) manual for details.
05914      */
05915     rb_define_const(rb_mProcess, "RLIMIT_MSGQUEUE", INT2FIX(RLIMIT_MSGQUEUE));
05916 #endif
05917 #ifdef RLIMIT_NICE
05918     /* Specifies a ceiling to which the process's nice value can be raised.
05919      *
05920      * see the system getrlimit(2) manual for details.
05921      */
05922     rb_define_const(rb_mProcess, "RLIMIT_NICE", INT2FIX(RLIMIT_NICE));
05923 #endif
05924 #ifdef RLIMIT_NOFILE
05925     /* Specifies a value one greater than the maximum file descriptor
05926      * number that can be opened by this process.
05927      *
05928      * see the system getrlimit(2) manual for details.
05929      */
05930     rb_define_const(rb_mProcess, "RLIMIT_NOFILE", INT2FIX(RLIMIT_NOFILE));
05931 #endif
05932 #ifdef RLIMIT_NPROC
05933     /* The maximum number of processes that can be created for the
05934      * real user ID of the calling process.
05935      *
05936      * see the system getrlimit(2) manual for details.
05937      */
05938     rb_define_const(rb_mProcess, "RLIMIT_NPROC", INT2FIX(RLIMIT_NPROC));
05939 #endif
05940 #ifdef RLIMIT_RSS
05941     /* Specifies the limit (in pages) of the process's resident set.
05942      *
05943      * see the system getrlimit(2) manual for details.
05944      */
05945     rb_define_const(rb_mProcess, "RLIMIT_RSS", INT2FIX(RLIMIT_RSS));
05946 #endif
05947 #ifdef RLIMIT_RTPRIO
05948     /* Specifies a ceiling on the real-time priority that may be set for this process.
05949      *
05950      * see the system getrlimit(2) manual for details.
05951      */
05952     rb_define_const(rb_mProcess, "RLIMIT_RTPRIO", INT2FIX(RLIMIT_RTPRIO));
05953 #endif
05954 #ifdef RLIMIT_RTTIME
05955     /* Specifies limit on CPU time this process scheduled under a real-time
05956      * scheduling policy can consume.
05957      *
05958      * see the system getrlimit(2) manual for details.
05959      */
05960     rb_define_const(rb_mProcess, "RLIMIT_RTTIME", INT2FIX(RLIMIT_RTTIME));
05961 #endif
05962 #ifdef RLIMIT_SBSIZE
05963     /* Maximum size of the socket buffer.
05964      */
05965     rb_define_const(rb_mProcess, "RLIMIT_SBSIZE", INT2FIX(RLIMIT_SBSIZE));
05966 #endif
05967 #ifdef RLIMIT_SIGPENDING
05968     /* Specifies a limit on the number of signals that may be queued for
05969      * the real user ID of the calling process.
05970      *
05971      * see the system getrlimit(2) manual for details.
05972      */
05973     rb_define_const(rb_mProcess, "RLIMIT_SIGPENDING", INT2FIX(RLIMIT_SIGPENDING));
05974 #endif
05975 #ifdef RLIMIT_STACK
05976     /* Maximum size of the stack, in bytes.
05977      *
05978      * see the system getrlimit(2) manual for details.
05979      */
05980     rb_define_const(rb_mProcess, "RLIMIT_STACK", INT2FIX(RLIMIT_STACK));
05981 #endif
05982 #endif
05983 
05984     rb_define_module_function(rb_mProcess, "uid", proc_getuid, 0);
05985     rb_define_module_function(rb_mProcess, "uid=", proc_setuid, 1);
05986     rb_define_module_function(rb_mProcess, "gid", proc_getgid, 0);
05987     rb_define_module_function(rb_mProcess, "gid=", proc_setgid, 1);
05988     rb_define_module_function(rb_mProcess, "euid", proc_geteuid, 0);
05989     rb_define_module_function(rb_mProcess, "euid=", proc_seteuid_m, 1);
05990     rb_define_module_function(rb_mProcess, "egid", proc_getegid, 0);
05991     rb_define_module_function(rb_mProcess, "egid=", proc_setegid_m, 1);
05992     rb_define_module_function(rb_mProcess, "initgroups", proc_initgroups, 2);
05993     rb_define_module_function(rb_mProcess, "groups", proc_getgroups, 0);
05994     rb_define_module_function(rb_mProcess, "groups=", proc_setgroups, 1);
05995     rb_define_module_function(rb_mProcess, "maxgroups", proc_getmaxgroups, 0);
05996     rb_define_module_function(rb_mProcess, "maxgroups=", proc_setmaxgroups, 1);
05997 
05998     rb_define_module_function(rb_mProcess, "daemon", proc_daemon, -1);
05999 
06000     rb_define_module_function(rb_mProcess, "times", rb_proc_times, 0);
06001 
06002 #if defined(HAVE_TIMES) || defined(_WIN32)
06003     rb_cProcessTms = rb_struct_define("Tms", "utime", "stime", "cutime", "cstime", NULL);
06004 #endif
06005 
06006     SAVED_USER_ID = geteuid();
06007     SAVED_GROUP_ID = getegid();
06008 
06009     rb_mProcUID = rb_define_module_under(rb_mProcess, "UID");
06010     rb_mProcGID = rb_define_module_under(rb_mProcess, "GID");
06011 
06012     rb_define_module_function(rb_mProcUID, "rid", proc_getuid, 0);
06013     rb_define_module_function(rb_mProcGID, "rid", proc_getgid, 0);
06014     rb_define_module_function(rb_mProcUID, "eid", proc_geteuid, 0);
06015     rb_define_module_function(rb_mProcGID, "eid", proc_getegid, 0);
06016     rb_define_module_function(rb_mProcUID, "change_privilege", p_uid_change_privilege, 1);
06017     rb_define_module_function(rb_mProcGID, "change_privilege", p_gid_change_privilege, 1);
06018     rb_define_module_function(rb_mProcUID, "grant_privilege", p_uid_grant_privilege, 1);
06019     rb_define_module_function(rb_mProcGID, "grant_privilege", p_gid_grant_privilege, 1);
06020     rb_define_alias(rb_singleton_class(rb_mProcUID), "eid=", "grant_privilege");
06021     rb_define_alias(rb_singleton_class(rb_mProcGID), "eid=", "grant_privilege");
06022     rb_define_module_function(rb_mProcUID, "re_exchange", p_uid_exchange, 0);
06023     rb_define_module_function(rb_mProcGID, "re_exchange", p_gid_exchange, 0);
06024     rb_define_module_function(rb_mProcUID, "re_exchangeable?", p_uid_exchangeable, 0);
06025     rb_define_module_function(rb_mProcGID, "re_exchangeable?", p_gid_exchangeable, 0);
06026     rb_define_module_function(rb_mProcUID, "sid_available?", p_uid_have_saved_id, 0);
06027     rb_define_module_function(rb_mProcGID, "sid_available?", p_gid_have_saved_id, 0);
06028     rb_define_module_function(rb_mProcUID, "switch", p_uid_switch, 0);
06029     rb_define_module_function(rb_mProcGID, "switch", p_gid_switch, 0);
06030 
06031     rb_mProcID_Syscall = rb_define_module_under(rb_mProcess, "Sys");
06032 
06033     rb_define_module_function(rb_mProcID_Syscall, "getuid", proc_getuid, 0);
06034     rb_define_module_function(rb_mProcID_Syscall, "geteuid", proc_geteuid, 0);
06035     rb_define_module_function(rb_mProcID_Syscall, "getgid", proc_getgid, 0);
06036     rb_define_module_function(rb_mProcID_Syscall, "getegid", proc_getegid, 0);
06037 
06038     rb_define_module_function(rb_mProcID_Syscall, "setuid", p_sys_setuid, 1);
06039     rb_define_module_function(rb_mProcID_Syscall, "setgid", p_sys_setgid, 1);
06040 
06041     rb_define_module_function(rb_mProcID_Syscall, "setruid", p_sys_setruid, 1);
06042     rb_define_module_function(rb_mProcID_Syscall, "setrgid", p_sys_setrgid, 1);
06043 
06044     rb_define_module_function(rb_mProcID_Syscall, "seteuid", p_sys_seteuid, 1);
06045     rb_define_module_function(rb_mProcID_Syscall, "setegid", p_sys_setegid, 1);
06046 
06047     rb_define_module_function(rb_mProcID_Syscall, "setreuid", p_sys_setreuid, 2);
06048     rb_define_module_function(rb_mProcID_Syscall, "setregid", p_sys_setregid, 2);
06049 
06050     rb_define_module_function(rb_mProcID_Syscall, "setresuid", p_sys_setresuid, 3);
06051     rb_define_module_function(rb_mProcID_Syscall, "setresgid", p_sys_setresgid, 3);
06052     rb_define_module_function(rb_mProcID_Syscall, "issetugid", p_sys_issetugid, 0);
06053 }
06054