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