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