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