• Main Page
  • Modules
  • Data Structures
  • Files
  • File List
  • Globals

process.c

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

Generated on Wed Sep 8 2010 21:55:10 for Ruby by  doxygen 1.7.1