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