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