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