Ruby 1.9.2p136(2010-12-25revision30365)

- 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