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