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