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 #else
01953 #define redirect_dup(oldfd) dup(oldfd)
01954 #endif
01955
01956 #if defined(DEBUG_REDIRECT) || defined(_WIN32)
01957 static int
01958 redirect_dup2(int oldfd, int newfd)
01959 {
01960 int ret;
01961 ret = dup2(oldfd, newfd);
01962 if (newfd >= 0 && newfd <= 2)
01963 SetStdHandle(newfd == 0 ? STD_INPUT_HANDLE : newfd == 1 ? STD_OUTPUT_HANDLE : STD_ERROR_HANDLE, (HANDLE)rb_w32_get_osfhandle(newfd));
01964 #if defined(DEBUG_REDIRECT)
01965 ttyprintf("dup2(%d, %d)\n", oldfd, newfd);
01966 #endif
01967 return ret;
01968 }
01969 #else
01970 #define redirect_dup2(oldfd, newfd) dup2((oldfd), (newfd))
01971 #endif
01972
01973 #if defined(DEBUG_REDIRECT)
01974 static int
01975 redirect_close(int fd)
01976 {
01977 int ret;
01978 ret = close(fd);
01979 ttyprintf("close(%d)\n", fd);
01980 return ret;
01981 }
01982
01983 static int
01984 redirect_open(const char *pathname, int flags, mode_t perm)
01985 {
01986 int ret;
01987 ret = open(pathname, flags, perm);
01988 ttyprintf("open(\"%s\", 0x%x, 0%o) => %d\n", pathname, flags, perm, ret);
01989 return ret;
01990 }
01991
01992 #else
01993 #define redirect_close(fd) close(fd)
01994 #define redirect_open(pathname, flags, perm) open((pathname), (flags), (perm))
01995 #endif
01996
01997 static int
01998 save_redirect_fd(int fd, VALUE save, char *errmsg, size_t errmsg_buflen)
01999 {
02000 if (!NIL_P(save)) {
02001 VALUE newary;
02002 int save_fd = redirect_dup(fd);
02003 if (save_fd == -1) {
02004 if (errno == EBADF)
02005 return 0;
02006 ERRMSG("dup");
02007 return -1;
02008 }
02009 rb_update_max_fd(save_fd);
02010 newary = rb_ary_entry(save, EXEC_OPTION_DUP2);
02011 if (NIL_P(newary)) {
02012 newary = hide_obj(rb_ary_new());
02013 rb_ary_store(save, EXEC_OPTION_DUP2, newary);
02014 }
02015 rb_ary_push(newary,
02016 hide_obj(rb_assoc_new(INT2FIX(fd), INT2FIX(save_fd))));
02017
02018 newary = rb_ary_entry(save, EXEC_OPTION_CLOSE);
02019 if (NIL_P(newary)) {
02020 newary = hide_obj(rb_ary_new());
02021 rb_ary_store(save, EXEC_OPTION_CLOSE, newary);
02022 }
02023 rb_ary_push(newary, hide_obj(rb_assoc_new(INT2FIX(save_fd), Qnil)));
02024 }
02025
02026 return 0;
02027 }
02028
02029 static VALUE
02030 save_env_i(VALUE i, VALUE ary, int argc, VALUE *argv)
02031 {
02032 rb_ary_push(ary, hide_obj(rb_ary_dup(argv[0])));
02033 return Qnil;
02034 }
02035
02036 static void
02037 save_env(VALUE save)
02038 {
02039 if (!NIL_P(save) && NIL_P(rb_ary_entry(save, EXEC_OPTION_ENV))) {
02040 VALUE env = rb_const_get(rb_cObject, rb_intern("ENV"));
02041 if (RTEST(env)) {
02042 VALUE ary = hide_obj(rb_ary_new());
02043 rb_block_call(env, rb_intern("each"), 0, 0, save_env_i,
02044 (VALUE)ary);
02045 rb_ary_store(save, EXEC_OPTION_ENV, ary);
02046 }
02047 rb_ary_store(save, EXEC_OPTION_UNSETENV_OTHERS, Qtrue);
02048 }
02049 }
02050
02051 static int
02052 intcmp(const void *a, const void *b)
02053 {
02054 return *(int*)a - *(int*)b;
02055 }
02056
02057 static int
02058 intrcmp(const void *a, const void *b)
02059 {
02060 return *(int*)b - *(int*)a;
02061 }
02062
02063 static int
02064 run_exec_dup2(VALUE ary, VALUE save, char *errmsg, size_t errmsg_buflen)
02065 {
02066 long n, i;
02067 int ret;
02068 int extra_fd = -1;
02069 struct fd_pair {
02070 int oldfd;
02071 int newfd;
02072 long older_index;
02073 long num_newer;
02074 } *pairs = 0;
02075
02076 n = RARRAY_LEN(ary);
02077 pairs = (struct fd_pair *)malloc(sizeof(struct fd_pair) * n);
02078 if (pairs == NULL) {
02079 ERRMSG("malloc");
02080 return -1;
02081 }
02082
02083
02084 for (i = 0; i < n; i++) {
02085 VALUE elt = RARRAY_PTR(ary)[i];
02086 pairs[i].oldfd = FIX2INT(RARRAY_PTR(elt)[1]);
02087 pairs[i].newfd = FIX2INT(RARRAY_PTR(elt)[0]);
02088 pairs[i].older_index = -1;
02089 }
02090
02091
02092 if (!RTEST(save))
02093 qsort(pairs, n, sizeof(struct fd_pair), intcmp);
02094 else
02095 qsort(pairs, n, sizeof(struct fd_pair), intrcmp);
02096
02097
02098 for (i = 0; i < n; i++) {
02099 int newfd = pairs[i].newfd;
02100 struct fd_pair key, *found;
02101 key.oldfd = newfd;
02102 found = bsearch(&key, pairs, n, sizeof(struct fd_pair), intcmp);
02103 pairs[i].num_newer = 0;
02104 if (found) {
02105 while (pairs < found && (found-1)->oldfd == newfd)
02106 found--;
02107 while (found < pairs+n && found->oldfd == newfd) {
02108 pairs[i].num_newer++;
02109 found->older_index = i;
02110 found++;
02111 }
02112 }
02113 }
02114
02115
02116 for (i = 0; i < n; i++) {
02117 long j = i;
02118 while (j != -1 && pairs[j].oldfd != -1 && pairs[j].num_newer == 0) {
02119 if (save_redirect_fd(pairs[j].newfd, save, errmsg, errmsg_buflen) < 0)
02120 goto fail;
02121 ret = redirect_dup2(pairs[j].oldfd, pairs[j].newfd);
02122 if (ret == -1) {
02123 ERRMSG("dup2");
02124 goto fail;
02125 }
02126 rb_update_max_fd(pairs[j].newfd);
02127 pairs[j].oldfd = -1;
02128 j = pairs[j].older_index;
02129 if (j != -1)
02130 pairs[j].num_newer--;
02131 }
02132 }
02133
02134
02135 for (i = 0; i < n; i++) {
02136 long j;
02137 if (pairs[i].oldfd == -1)
02138 continue;
02139 if (pairs[i].oldfd == pairs[i].newfd) {
02140 #ifdef F_GETFD
02141 int fd = pairs[i].oldfd;
02142 ret = fcntl(fd, F_GETFD);
02143 if (ret == -1) {
02144 ERRMSG("fcntl(F_GETFD)");
02145 goto fail;
02146 }
02147 if (ret & FD_CLOEXEC) {
02148 ret &= ~FD_CLOEXEC;
02149 ret = fcntl(fd, F_SETFD, ret);
02150 if (ret == -1) {
02151 ERRMSG("fcntl(F_SETFD)");
02152 goto fail;
02153 }
02154 }
02155 #endif
02156 pairs[i].oldfd = -1;
02157 continue;
02158 }
02159 if (extra_fd == -1) {
02160 extra_fd = redirect_dup(pairs[i].oldfd);
02161 if (extra_fd == -1) {
02162 ERRMSG("dup");
02163 goto fail;
02164 }
02165 rb_update_max_fd(extra_fd);
02166 }
02167 else {
02168 ret = redirect_dup2(pairs[i].oldfd, extra_fd);
02169 if (ret == -1) {
02170 ERRMSG("dup2");
02171 goto fail;
02172 }
02173 rb_update_max_fd(extra_fd);
02174 }
02175 pairs[i].oldfd = extra_fd;
02176 j = pairs[i].older_index;
02177 pairs[i].older_index = -1;
02178 while (j != -1) {
02179 ret = redirect_dup2(pairs[j].oldfd, pairs[j].newfd);
02180 if (ret == -1) {
02181 ERRMSG("dup2");
02182 goto fail;
02183 }
02184 rb_update_max_fd(ret);
02185 pairs[j].oldfd = -1;
02186 j = pairs[j].older_index;
02187 }
02188 }
02189 if (extra_fd != -1) {
02190 ret = redirect_close(extra_fd);
02191 if (ret == -1) {
02192 ERRMSG("close");
02193 goto fail;
02194 }
02195 }
02196
02197 xfree(pairs);
02198 return 0;
02199
02200 fail:
02201 xfree(pairs);
02202 return -1;
02203 }
02204
02205 static int
02206 run_exec_close(VALUE ary, char *errmsg, size_t errmsg_buflen)
02207 {
02208 long i;
02209 int ret;
02210
02211 for (i = 0; i < RARRAY_LEN(ary); i++) {
02212 VALUE elt = RARRAY_PTR(ary)[i];
02213 int fd = FIX2INT(RARRAY_PTR(elt)[0]);
02214 ret = redirect_close(fd);
02215 if (ret == -1) {
02216 ERRMSG("close");
02217 return -1;
02218 }
02219 }
02220 return 0;
02221 }
02222
02223 static int
02224 run_exec_open(VALUE ary, VALUE save, char *errmsg, size_t errmsg_buflen)
02225 {
02226 long i;
02227 int ret;
02228
02229 for (i = 0; i < RARRAY_LEN(ary);) {
02230 VALUE elt = RARRAY_PTR(ary)[i];
02231 int fd = FIX2INT(RARRAY_PTR(elt)[0]);
02232 VALUE param = RARRAY_PTR(elt)[1];
02233 char *path = RSTRING_PTR(RARRAY_PTR(param)[0]);
02234 int flags = NUM2INT(RARRAY_PTR(param)[1]);
02235 int perm = NUM2INT(RARRAY_PTR(param)[2]);
02236 int need_close = 1;
02237 int fd2 = redirect_open(path, flags, perm);
02238 if (fd2 == -1) {
02239 ERRMSG("open");
02240 return -1;
02241 }
02242 rb_update_max_fd(fd2);
02243 while (i < RARRAY_LEN(ary) &&
02244 (elt = RARRAY_PTR(ary)[i], RARRAY_PTR(elt)[1] == param)) {
02245 fd = FIX2INT(RARRAY_PTR(elt)[0]);
02246 if (fd == fd2) {
02247 need_close = 0;
02248 }
02249 else {
02250 if (save_redirect_fd(fd, save, errmsg, errmsg_buflen) < 0)
02251 return -1;
02252 ret = redirect_dup2(fd2, fd);
02253 if (ret == -1) {
02254 ERRMSG("dup2");
02255 return -1;
02256 }
02257 rb_update_max_fd(fd);
02258 }
02259 i++;
02260 }
02261 if (need_close) {
02262 ret = redirect_close(fd2);
02263 if (ret == -1) {
02264 ERRMSG("close");
02265 return -1;
02266 }
02267 }
02268 }
02269 return 0;
02270 }
02271
02272 static int
02273 run_exec_dup2_child(VALUE ary, VALUE save, char *errmsg, size_t errmsg_buflen)
02274 {
02275 long i;
02276 int ret;
02277
02278 for (i = 0; i < RARRAY_LEN(ary); i++) {
02279 VALUE elt = RARRAY_PTR(ary)[i];
02280 int newfd = FIX2INT(RARRAY_PTR(elt)[0]);
02281 int oldfd = FIX2INT(RARRAY_PTR(elt)[1]);
02282
02283 if (save_redirect_fd(newfd, save, errmsg, errmsg_buflen) < 0)
02284 return -1;
02285 ret = redirect_dup2(oldfd, newfd);
02286 if (ret == -1) {
02287 ERRMSG("dup2");
02288 return -1;
02289 }
02290 rb_update_max_fd(newfd);
02291 }
02292 return 0;
02293 }
02294
02295 #ifdef HAVE_SETPGID
02296 static int
02297 run_exec_pgroup(VALUE obj, VALUE save, char *errmsg, size_t errmsg_buflen)
02298 {
02299
02300
02301
02302
02303
02304
02305 int ret;
02306 pid_t pgroup;
02307 if (!NIL_P(save)) {
02308
02309 rb_ary_store(save, EXEC_OPTION_PGROUP, PIDT2NUM(getpgrp()));
02310 }
02311 pgroup = NUM2PIDT(obj);
02312 if (pgroup == 0) {
02313 pgroup = getpid();
02314 }
02315 ret = setpgid(getpid(), pgroup);
02316 if (ret == -1) ERRMSG("setpgid");
02317 return ret;
02318 }
02319 #endif
02320
02321 #if defined(HAVE_SETRLIMIT) && defined(RLIM2NUM)
02322 static int
02323 run_exec_rlimit(VALUE ary, VALUE save, char *errmsg, size_t errmsg_buflen)
02324 {
02325 long i;
02326 for (i = 0; i < RARRAY_LEN(ary); i++) {
02327 VALUE elt = RARRAY_PTR(ary)[i];
02328 int rtype = NUM2INT(RARRAY_PTR(elt)[0]);
02329 struct rlimit rlim;
02330 if (!NIL_P(save)) {
02331 VALUE tmp, newary;
02332 if (getrlimit(rtype, &rlim) == -1) {
02333 ERRMSG("getrlimit");
02334 return -1;
02335 }
02336 tmp = hide_obj(rb_ary_new3(3, RARRAY_PTR(elt)[0],
02337 RLIM2NUM(rlim.rlim_cur),
02338 RLIM2NUM(rlim.rlim_max)));
02339 newary = rb_ary_entry(save, EXEC_OPTION_RLIMIT);
02340 if (NIL_P(newary)) {
02341 newary = hide_obj(rb_ary_new());
02342 rb_ary_store(save, EXEC_OPTION_RLIMIT, newary);
02343 }
02344 rb_ary_push(newary, tmp);
02345 }
02346 rlim.rlim_cur = NUM2RLIM(RARRAY_PTR(elt)[1]);
02347 rlim.rlim_max = NUM2RLIM(RARRAY_PTR(elt)[2]);
02348 if (setrlimit(rtype, &rlim) == -1) {
02349 ERRMSG("setrlimit");
02350 return -1;
02351 }
02352 }
02353 return 0;
02354 }
02355 #endif
02356
02357 int
02358 rb_run_exec_options_err(const struct rb_exec_arg *e, struct rb_exec_arg *s, char *errmsg, size_t errmsg_buflen)
02359 {
02360 VALUE options = e->options;
02361 VALUE soptions = Qnil;
02362 VALUE obj;
02363
02364 if (!RTEST(options))
02365 return 0;
02366
02367 if (s) {
02368 s->argc = 0;
02369 s->argv = NULL;
02370 s->prog = NULL;
02371 s->options = soptions = hide_obj(rb_ary_new());
02372 s->redirect_fds = Qnil;
02373 }
02374
02375 #ifdef HAVE_SETPGID
02376 obj = rb_ary_entry(options, EXEC_OPTION_PGROUP);
02377 if (RTEST(obj)) {
02378 if (run_exec_pgroup(obj, soptions, errmsg, errmsg_buflen) == -1)
02379 return -1;
02380 }
02381 #endif
02382
02383 #if defined(HAVE_SETRLIMIT) && defined(RLIM2NUM)
02384 obj = rb_ary_entry(options, EXEC_OPTION_RLIMIT);
02385 if (!NIL_P(obj)) {
02386 if (run_exec_rlimit(obj, soptions, errmsg, errmsg_buflen) == -1)
02387 return -1;
02388 }
02389 #endif
02390
02391 obj = rb_ary_entry(options, EXEC_OPTION_UNSETENV_OTHERS);
02392 if (RTEST(obj)) {
02393 save_env(soptions);
02394 rb_env_clear();
02395 }
02396
02397 obj = rb_ary_entry(options, EXEC_OPTION_ENV);
02398 if (!NIL_P(obj)) {
02399 long i;
02400 save_env(soptions);
02401 for (i = 0; i < RARRAY_LEN(obj); i++) {
02402 VALUE pair = RARRAY_PTR(obj)[i];
02403 VALUE key = RARRAY_PTR(pair)[0];
02404 VALUE val = RARRAY_PTR(pair)[1];
02405 if (NIL_P(val))
02406 ruby_setenv(StringValueCStr(key), 0);
02407 else
02408 ruby_setenv(StringValueCStr(key), StringValueCStr(val));
02409 }
02410 }
02411
02412 obj = rb_ary_entry(options, EXEC_OPTION_CHDIR);
02413 if (!NIL_P(obj)) {
02414 if (!NIL_P(soptions)) {
02415 char *cwd = my_getcwd();
02416 rb_ary_store(soptions, EXEC_OPTION_CHDIR,
02417 hide_obj(rb_str_new2(cwd)));
02418 xfree(cwd);
02419 }
02420 if (chdir(RSTRING_PTR(obj)) == -1) {
02421 ERRMSG("chdir");
02422 return -1;
02423 }
02424 }
02425
02426 obj = rb_ary_entry(options, EXEC_OPTION_UMASK);
02427 if (!NIL_P(obj)) {
02428 mode_t mask = NUM2MODET(obj);
02429 mode_t oldmask = umask(mask);
02430 if (!NIL_P(soptions))
02431 rb_ary_store(soptions, EXEC_OPTION_UMASK, MODET2NUM(oldmask));
02432 }
02433
02434 obj = rb_ary_entry(options, EXEC_OPTION_DUP2);
02435 if (!NIL_P(obj)) {
02436 if (run_exec_dup2(obj, soptions, errmsg, errmsg_buflen) == -1)
02437 return -1;
02438 }
02439
02440 obj = rb_ary_entry(options, EXEC_OPTION_CLOSE);
02441 if (!NIL_P(obj)) {
02442 if (!NIL_P(soptions))
02443 rb_warn("cannot close fd before spawn");
02444 else {
02445 if (run_exec_close(obj, errmsg, errmsg_buflen) == -1)
02446 return -1;
02447 }
02448 }
02449
02450 #ifdef HAVE_FORK
02451 obj = rb_ary_entry(options, EXEC_OPTION_CLOSE_OTHERS);
02452 if (obj != Qfalse) {
02453 rb_close_before_exec(3, FIX2INT(obj), e->redirect_fds);
02454 }
02455 #endif
02456
02457 obj = rb_ary_entry(options, EXEC_OPTION_OPEN);
02458 if (!NIL_P(obj)) {
02459 if (run_exec_open(obj, soptions, errmsg, errmsg_buflen) == -1)
02460 return -1;
02461 }
02462
02463 obj = rb_ary_entry(options, EXEC_OPTION_DUP2_CHILD);
02464 if (!NIL_P(obj)) {
02465 if (run_exec_dup2_child(obj, soptions, errmsg, errmsg_buflen) == -1)
02466 return -1;
02467 }
02468
02469 return 0;
02470 }
02471
02472 int
02473 rb_run_exec_options(const struct rb_exec_arg *e, struct rb_exec_arg *s)
02474 {
02475 return rb_run_exec_options_err(e, s, NULL, 0);
02476 }
02477
02478 int
02479 rb_exec_err(const struct rb_exec_arg *e, char *errmsg, size_t errmsg_buflen)
02480 {
02481 int argc = e->argc;
02482 VALUE *argv = e->argv;
02483 const char *prog = e->prog;
02484
02485 if (rb_run_exec_options_err(e, NULL, errmsg, errmsg_buflen) < 0) {
02486 return -1;
02487 }
02488
02489 if (argc == 0) {
02490 rb_proc_exec(prog);
02491 }
02492 else {
02493 rb_proc_exec_n(argc, argv, prog);
02494 }
02495 return -1;
02496 }
02497
02498 int
02499 rb_exec(const struct rb_exec_arg *e)
02500 {
02501 #if !defined FD_CLOEXEC && !defined HAVE_SPAWNV
02502 char errmsg[80] = { '\0' };
02503 int ret = rb_exec_err(e, errmsg, sizeof(errmsg));
02504 preserving_errno(
02505 if (errmsg[0]) {
02506 fprintf(stderr, "%s\n", errmsg);
02507 }
02508 else {
02509 fprintf(stderr, "%s:%d: command not found: %s\n",
02510 rb_sourcefile(), rb_sourceline(), e->prog);
02511 }
02512 );
02513 return ret;
02514 #else
02515 return rb_exec_err(e, NULL, 0);
02516 #endif
02517 }
02518
02519 #ifdef HAVE_FORK
02520 static int
02521 rb_exec_atfork(void* arg, char *errmsg, size_t errmsg_buflen)
02522 {
02523 rb_thread_atfork_before_exec();
02524 return rb_exec_err(arg, errmsg, errmsg_buflen);
02525 }
02526 #endif
02527
02528 #ifdef HAVE_FORK
02529 #ifdef FD_CLOEXEC
02530 #if SIZEOF_INT == SIZEOF_LONG
02531 #define proc_syswait (VALUE (*)(VALUE))rb_syswait
02532 #else
02533 static VALUE
02534 proc_syswait(VALUE pid)
02535 {
02536 rb_syswait((int)pid);
02537 return Qnil;
02538 }
02539 #endif
02540 #endif
02541
02542 static int
02543 move_fds_to_avoid_crash(int *fdp, int n, VALUE fds)
02544 {
02545 long min = 0;
02546 int i;
02547 for (i = 0; i < n; i++) {
02548 int ret;
02549 while (RTEST(rb_hash_lookup(fds, INT2FIX(fdp[i])))) {
02550 if (min <= fdp[i])
02551 min = fdp[i]+1;
02552 while (RTEST(rb_hash_lookup(fds, INT2FIX(min))))
02553 min++;
02554 ret = fcntl(fdp[i], F_DUPFD, min);
02555 if (ret == -1)
02556 return -1;
02557 rb_update_max_fd(ret);
02558 close(fdp[i]);
02559 fdp[i] = ret;
02560 }
02561 }
02562 return 0;
02563 }
02564
02565 static int
02566 pipe_nocrash(int filedes[2], VALUE fds)
02567 {
02568 int ret;
02569 ret = rb_pipe(filedes);
02570 if (ret == -1)
02571 return -1;
02572 if (RTEST(fds)) {
02573 int save = errno;
02574 if (move_fds_to_avoid_crash(filedes, 2, fds) == -1) {
02575 close(filedes[0]);
02576 close(filedes[1]);
02577 return -1;
02578 }
02579 errno = save;
02580 }
02581 return ret;
02582 }
02583
02584 struct chfunc_protect_t {
02585 int (*chfunc)(void*, char *, size_t);
02586 void *arg;
02587 char *errmsg;
02588 size_t buflen;
02589 };
02590
02591 static VALUE
02592 chfunc_protect(VALUE arg)
02593 {
02594 struct chfunc_protect_t *p = (struct chfunc_protect_t *)arg;
02595
02596 return (VALUE)(*p->chfunc)(p->arg, p->errmsg, p->buflen);
02597 }
02598
02599 #ifndef O_BINARY
02600 #define O_BINARY 0
02601 #endif
02602
02603
02604
02605
02606
02607
02608
02609
02610
02611
02612
02613
02614
02615
02616
02617
02618
02619
02620
02621
02622
02623
02624
02625
02626 rb_pid_t
02627 rb_fork_err(int *status, int (*chfunc)(void*, char *, size_t), void *charg, VALUE fds,
02628 char *errmsg, size_t errmsg_buflen)
02629 {
02630 rb_pid_t pid;
02631 int err, state = 0;
02632 #ifdef FD_CLOEXEC
02633 int ep[2];
02634 VALUE io = Qnil;
02635 #endif
02636
02637 #define prefork() ( \
02638 rb_io_flush(rb_stdout), \
02639 rb_io_flush(rb_stderr) \
02640 )
02641 prefork();
02642
02643 #ifdef FD_CLOEXEC
02644 if (chfunc) {
02645 if (pipe_nocrash(ep, fds)) return -1;
02646 if (fcntl(ep[1], F_SETFD, FD_CLOEXEC)) {
02647 preserving_errno((close(ep[0]), close(ep[1])));
02648 return -1;
02649 }
02650 }
02651 #endif
02652 for (; before_fork(), (pid = fork()) < 0; prefork()) {
02653 after_fork();
02654 switch (errno) {
02655 case EAGAIN:
02656 #if defined(EWOULDBLOCK) && EWOULDBLOCK != EAGAIN
02657 case EWOULDBLOCK:
02658 #endif
02659 if (!status && !chfunc) {
02660 rb_thread_sleep(1);
02661 continue;
02662 }
02663 else {
02664 rb_protect((VALUE (*)())rb_thread_sleep, 1, &state);
02665 if (status) *status = state;
02666 if (!state) continue;
02667 }
02668 default:
02669 #ifdef FD_CLOEXEC
02670 if (chfunc) {
02671 preserving_errno((close(ep[0]), close(ep[1])));
02672 }
02673 #endif
02674 if (state && !status) rb_jump_tag(state);
02675 return -1;
02676 }
02677 }
02678 if (!pid) {
02679 forked_child = 1;
02680 if (chfunc) {
02681 struct chfunc_protect_t arg;
02682 arg.chfunc = chfunc;
02683 arg.arg = charg;
02684 arg.errmsg = errmsg;
02685 arg.buflen = errmsg_buflen;
02686 #ifdef FD_CLOEXEC
02687 close(ep[0]);
02688 #endif
02689 if (!(int)rb_protect(chfunc_protect, (VALUE)&arg, &state)) _exit(EXIT_SUCCESS);
02690 #ifdef FD_CLOEXEC
02691 if (write(ep[1], &state, sizeof(state)) == sizeof(state) && state) {
02692 VALUE errinfo = rb_errinfo();
02693 io = rb_io_fdopen(ep[1], O_WRONLY|O_BINARY, NULL);
02694 rb_marshal_dump(errinfo, io);
02695 rb_io_flush(io);
02696 }
02697 err = errno;
02698 if (write(ep[1], &err, sizeof(err)) < 0) err = errno;
02699 if (errmsg && 0 < errmsg_buflen) {
02700 errmsg[errmsg_buflen-1] = '\0';
02701 errmsg_buflen = strlen(errmsg);
02702 if (errmsg_buflen > 0 &&write(ep[1], errmsg, errmsg_buflen) < 0)
02703 err = errno;
02704 }
02705 if (!NIL_P(io)) rb_io_close(io);
02706 #endif
02707 #if EXIT_SUCCESS == 127
02708 _exit(EXIT_FAILURE);
02709 #else
02710 _exit(127);
02711 #endif
02712 }
02713 }
02714 after_fork();
02715 #ifdef FD_CLOEXEC
02716 if (pid && chfunc) {
02717 ssize_t size;
02718 VALUE exc = Qnil;
02719 close(ep[1]);
02720 if ((read(ep[0], &state, sizeof(state))) == sizeof(state) && state) {
02721 io = rb_io_fdopen(ep[0], O_RDONLY|O_BINARY, NULL);
02722 exc = rb_marshal_load(io);
02723 rb_set_errinfo(exc);
02724 }
02725 #define READ_FROM_CHILD(ptr, len) \
02726 (NIL_P(io) ? read(ep[0], (ptr), (len)) : rb_io_bufread(io, (ptr), (len)))
02727 if ((size = READ_FROM_CHILD(&err, sizeof(err))) < 0) {
02728 err = errno;
02729 }
02730 if (size == sizeof(err) &&
02731 errmsg && 0 < errmsg_buflen) {
02732 ssize_t ret = READ_FROM_CHILD(errmsg, errmsg_buflen-1);
02733 if (0 <= ret) {
02734 errmsg[ret] = '\0';
02735 }
02736 }
02737 if (NIL_P(io))
02738 close(ep[0]);
02739 else
02740 rb_io_close(io);
02741 if (state || size) {
02742 if (status) {
02743 *status = state;
02744 rb_protect(proc_syswait, (VALUE)pid, status);
02745 }
02746 else {
02747 rb_syswait(pid);
02748 if (state) rb_exc_raise(exc);
02749 }
02750 errno = err;
02751 return -1;
02752 }
02753 }
02754 #endif
02755 return pid;
02756 }
02757
02758 struct chfunc_wrapper_t {
02759 int (*chfunc)(void*);
02760 void *arg;
02761 };
02762
02763 static int
02764 chfunc_wrapper(void *arg_, char *errmsg, size_t errmsg_buflen)
02765 {
02766 struct chfunc_wrapper_t *arg = arg_;
02767 return arg->chfunc(arg->arg);
02768 }
02769
02770 rb_pid_t
02771 rb_fork(int *status, int (*chfunc)(void*), void *charg, VALUE fds)
02772 {
02773 if (chfunc) {
02774 struct chfunc_wrapper_t warg;
02775 warg.chfunc = chfunc;
02776 warg.arg = charg;
02777 return rb_fork_err(status, chfunc_wrapper, &warg, fds, NULL, 0);
02778 }
02779 else {
02780 return rb_fork_err(status, NULL, NULL, fds, NULL, 0);
02781 }
02782
02783 }
02784
02785 #endif
02786
02787 #if defined(HAVE_FORK) && !defined(CANNOT_FORK_WITH_PTHREAD)
02788
02789
02790
02791
02792
02793
02794
02795
02796
02797
02798
02799
02800
02801
02802
02803
02804
02805
02806
02807
02808
02809
02810
02811 static VALUE
02812 rb_f_fork(VALUE obj)
02813 {
02814 rb_pid_t pid;
02815
02816 rb_secure(2);
02817
02818 switch (pid = rb_fork(0, 0, 0, Qnil)) {
02819 case 0:
02820 rb_thread_atfork();
02821 if (rb_block_given_p()) {
02822 int status;
02823
02824 rb_protect(rb_yield, Qundef, &status);
02825 ruby_stop(status);
02826 }
02827 return Qnil;
02828
02829 case -1:
02830 rb_sys_fail("fork(2)");
02831 return Qnil;
02832
02833 default:
02834 return PIDT2NUM(pid);
02835 }
02836 }
02837 #else
02838 #define rb_f_fork rb_f_notimplement
02839 #endif
02840
02841
02842
02843
02844
02845
02846
02847
02848
02849
02850
02851
02852 static VALUE
02853 rb_f_exit_bang(int argc, VALUE *argv, VALUE obj)
02854 {
02855 VALUE status;
02856 int istatus;
02857
02858 rb_secure(4);
02859 if (argc > 0 && rb_scan_args(argc, argv, "01", &status) == 1) {
02860 switch (status) {
02861 case Qtrue:
02862 istatus = EXIT_SUCCESS;
02863 break;
02864 case Qfalse:
02865 istatus = EXIT_FAILURE;
02866 break;
02867 default:
02868 istatus = NUM2INT(status);
02869 break;
02870 }
02871 }
02872 else {
02873 istatus = EXIT_FAILURE;
02874 }
02875 _exit(istatus);
02876
02877 return Qnil;
02878 }
02879
02880 void
02881 rb_exit(int status)
02882 {
02883 if (GET_THREAD()->tag) {
02884 VALUE args[2];
02885
02886 args[0] = INT2NUM(status);
02887 args[1] = rb_str_new2("exit");
02888 rb_exc_raise(rb_class_new_instance(2, args, rb_eSystemExit));
02889 }
02890 ruby_finalize();
02891 exit(status);
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
02927
02928
02929
02930
02931
02932
02933
02934
02935
02936 VALUE
02937 rb_f_exit(int argc, VALUE *argv)
02938 {
02939 VALUE status;
02940 int istatus;
02941
02942 rb_secure(4);
02943 if (argc > 0 && rb_scan_args(argc, argv, "01", &status) == 1) {
02944 switch (status) {
02945 case Qtrue:
02946 istatus = EXIT_SUCCESS;
02947 break;
02948 case Qfalse:
02949 istatus = EXIT_FAILURE;
02950 break;
02951 default:
02952 istatus = NUM2INT(status);
02953 #if EXIT_SUCCESS != 0
02954 if (istatus == 0)
02955 istatus = EXIT_SUCCESS;
02956 #endif
02957 break;
02958 }
02959 }
02960 else {
02961 istatus = EXIT_SUCCESS;
02962 }
02963 rb_exit(istatus);
02964 return Qnil;
02965 }
02966
02967
02968
02969
02970
02971
02972
02973
02974
02975
02976
02977
02978
02979 VALUE
02980 rb_f_abort(int argc, VALUE *argv)
02981 {
02982 rb_secure(4);
02983 if (argc == 0) {
02984 if (!NIL_P(GET_THREAD()->errinfo)) {
02985 ruby_error_print();
02986 }
02987 rb_exit(EXIT_FAILURE);
02988 }
02989 else {
02990 VALUE args[2];
02991
02992 rb_scan_args(argc, argv, "1", &args[1]);
02993 StringValue(argv[0]);
02994 rb_io_puts(argc, argv, rb_stderr);
02995 args[0] = INT2NUM(EXIT_FAILURE);
02996 rb_exc_raise(rb_class_new_instance(2, args, rb_eSystemExit));
02997 }
02998 return Qnil;
02999 }
03000
03001 void
03002 rb_syswait(rb_pid_t pid)
03003 {
03004 static int overriding;
03005 #ifdef SIGHUP
03006 RETSIGTYPE (*hfunc)(int) = 0;
03007 #endif
03008 #ifdef SIGQUIT
03009 RETSIGTYPE (*qfunc)(int) = 0;
03010 #endif
03011 RETSIGTYPE (*ifunc)(int) = 0;
03012 int status;
03013 int i, hooked = FALSE;
03014
03015 if (!overriding) {
03016 #ifdef SIGHUP
03017 hfunc = signal(SIGHUP, SIG_IGN);
03018 #endif
03019 #ifdef SIGQUIT
03020 qfunc = signal(SIGQUIT, SIG_IGN);
03021 #endif
03022 ifunc = signal(SIGINT, SIG_IGN);
03023 overriding = TRUE;
03024 hooked = TRUE;
03025 }
03026
03027 do {
03028 i = rb_waitpid(pid, &status, 0);
03029 } while (i == -1 && errno == EINTR);
03030
03031 if (hooked) {
03032 #ifdef SIGHUP
03033 signal(SIGHUP, hfunc);
03034 #endif
03035 #ifdef SIGQUIT
03036 signal(SIGQUIT, qfunc);
03037 #endif
03038 signal(SIGINT, ifunc);
03039 overriding = FALSE;
03040 }
03041 }
03042
03043 static VALUE
03044 rb_exec_arg_prepare(struct rb_exec_arg *earg, int argc, VALUE *argv, int default_close_others)
03045 {
03046 VALUE prog = rb_exec_arg_init(argc, argv, TRUE, earg);
03047 if (NIL_P(rb_ary_entry(earg->options, EXEC_OPTION_CLOSE_OTHERS))) {
03048 VALUE v = default_close_others ? Qtrue : Qfalse;
03049 rb_exec_arg_addopt(earg, ID2SYM(rb_intern("close_others")), v);
03050 }
03051 rb_exec_arg_fixup(earg);
03052 return prog;
03053 }
03054
03055 static rb_pid_t
03056 rb_spawn_process(struct rb_exec_arg *earg, VALUE prog, char *errmsg, size_t errmsg_buflen)
03057 {
03058 rb_pid_t pid;
03059 #if !USE_SPAWNV
03060 int status;
03061 #endif
03062 #if !defined HAVE_FORK || USE_SPAWNV
03063 struct rb_exec_arg sarg;
03064 int argc;
03065 VALUE *argv;
03066 #endif
03067
03068 #if defined HAVE_FORK && !USE_SPAWNV
03069 pid = rb_fork_err(&status, rb_exec_atfork, earg, earg->redirect_fds, errmsg, errmsg_buflen);
03070 #else
03071 if (rb_run_exec_options_err(earg, &sarg, errmsg, errmsg_buflen) < 0) {
03072 return -1;
03073 }
03074
03075 argc = earg->argc;
03076 argv = earg->argv;
03077 if (prog && argc) argv[0] = prog;
03078 # if defined HAVE_SPAWNV
03079 if (!argc) {
03080 pid = proc_spawn(RSTRING_PTR(prog));
03081 }
03082 else {
03083 pid = proc_spawn_n(argc, argv, prog, earg->options);
03084 }
03085 # if defined(_WIN32)
03086 if (pid == -1)
03087 rb_last_status_set(0x7f << 8, 0);
03088 # endif
03089 # else
03090 if (argc) prog = rb_ary_join(rb_ary_new4(argc, argv), rb_str_new2(" "));
03091 status = system(StringValuePtr(prog));
03092 rb_last_status_set((status & 0xff) << 8, 0);
03093 # endif
03094
03095 rb_run_exec_options_err(&sarg, NULL, errmsg, errmsg_buflen);
03096 #endif
03097 return pid;
03098 }
03099
03100 static rb_pid_t
03101 rb_spawn_internal(int argc, VALUE *argv, int default_close_others,
03102 char *errmsg, size_t errmsg_buflen)
03103 {
03104 struct rb_exec_arg earg;
03105 VALUE prog = rb_exec_arg_prepare(&earg, argc, argv, default_close_others);
03106 return rb_spawn_process(&earg, prog, errmsg, errmsg_buflen);
03107 }
03108
03109 rb_pid_t
03110 rb_spawn_err(int argc, VALUE *argv, char *errmsg, size_t errmsg_buflen)
03111 {
03112 return rb_spawn_internal(argc, argv, TRUE, errmsg, errmsg_buflen);
03113 }
03114
03115 rb_pid_t
03116 rb_spawn(int argc, VALUE *argv)
03117 {
03118 return rb_spawn_internal(argc, argv, TRUE, NULL, 0);
03119 }
03120
03121
03122
03123
03124
03125
03126
03127
03128
03129
03130
03131
03132
03133
03134
03135
03136
03137
03138
03139
03140
03141
03142
03143
03144
03145
03146
03147
03148
03149
03150
03151
03152
03153
03154 static VALUE
03155 rb_f_system(int argc, VALUE *argv)
03156 {
03157 rb_pid_t pid;
03158 int status;
03159
03160 #if defined(SIGCLD) && !defined(SIGCHLD)
03161 # define SIGCHLD SIGCLD
03162 #endif
03163
03164 #ifdef SIGCHLD
03165 RETSIGTYPE (*chfunc)(int);
03166
03167 chfunc = signal(SIGCHLD, SIG_DFL);
03168 #endif
03169 pid = rb_spawn_internal(argc, argv, FALSE, NULL, 0);
03170 #if defined(HAVE_FORK) || defined(HAVE_SPAWNV)
03171 if (pid > 0) {
03172 rb_syswait(pid);
03173 }
03174 #endif
03175 #ifdef SIGCHLD
03176 signal(SIGCHLD, chfunc);
03177 #endif
03178 if (pid < 0) {
03179 return Qnil;
03180 }
03181 status = PST2INT(rb_last_status_get());
03182 if (status == EXIT_SUCCESS) return Qtrue;
03183 return Qfalse;
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
03424
03425
03426
03427
03428
03429
03430
03431
03432
03433 static VALUE
03434 rb_f_spawn(int argc, VALUE *argv)
03435 {
03436 rb_pid_t pid;
03437 char errmsg[CHILD_ERRMSG_BUFLEN] = { '\0' };
03438 struct rb_exec_arg earg;
03439
03440 pid = rb_spawn_process(&earg, rb_exec_arg_prepare(&earg, argc, argv, TRUE), errmsg, sizeof(errmsg));
03441 if (pid == -1) {
03442 const char *prog = errmsg;
03443 if (!prog[0] && !(prog = earg.prog) && earg.argc) {
03444 prog = RSTRING_PTR(earg.argv[0]);
03445 }
03446 rb_sys_fail(prog);
03447 }
03448 #if defined(HAVE_FORK) || defined(HAVE_SPAWNV)
03449 return PIDT2NUM(pid);
03450 #else
03451 return Qnil;
03452 #endif
03453 }
03454
03455
03456
03457
03458
03459
03460
03461
03462
03463
03464
03465
03466
03467
03468
03469
03470
03471
03472 static VALUE
03473 rb_f_sleep(int argc, VALUE *argv)
03474 {
03475 time_t beg, end;
03476
03477 beg = time(0);
03478 if (argc == 0) {
03479 rb_thread_sleep_forever();
03480 }
03481 else if (argc == 1) {
03482 rb_thread_wait_for(rb_time_interval(argv[0]));
03483 }
03484 else {
03485 rb_raise(rb_eArgError, "wrong number of arguments (%d for 0..1)", argc);
03486 }
03487
03488 end = time(0) - beg;
03489
03490 return INT2FIX(end);
03491 }
03492
03493
03494 #if (defined(HAVE_GETPGRP) && defined(GETPGRP_VOID)) || defined(HAVE_GETPGID)
03495
03496
03497
03498
03499
03500
03501
03502
03503
03504
03505
03506 static VALUE
03507 proc_getpgrp(void)
03508 {
03509 rb_pid_t pgrp;
03510
03511 rb_secure(2);
03512 #if defined(HAVE_GETPGRP) && defined(GETPGRP_VOID)
03513 pgrp = getpgrp();
03514 if (pgrp < 0) rb_sys_fail(0);
03515 return PIDT2NUM(pgrp);
03516 #else
03517 pgrp = getpgid(0);
03518 if (pgrp < 0) rb_sys_fail(0);
03519 return PIDT2NUM(pgrp);
03520 #endif
03521 }
03522 #else
03523 #define proc_getpgrp rb_f_notimplement
03524 #endif
03525
03526
03527 #if defined(HAVE_SETPGID) || (defined(HAVE_SETPGRP) && defined(SETPGRP_VOID))
03528
03529
03530
03531
03532
03533
03534
03535
03536 static VALUE
03537 proc_setpgrp(void)
03538 {
03539 rb_secure(2);
03540
03541
03542
03543
03544 #ifdef HAVE_SETPGID
03545 if (setpgid(0,0) < 0) rb_sys_fail(0);
03546 #elif defined(HAVE_SETPGRP) && defined(SETPGRP_VOID)
03547 if (setpgrp() < 0) rb_sys_fail(0);
03548 #endif
03549 return INT2FIX(0);
03550 }
03551 #else
03552 #define proc_setpgrp rb_f_notimplement
03553 #endif
03554
03555
03556 #if defined(HAVE_GETPGID)
03557
03558
03559
03560
03561
03562
03563
03564
03565
03566
03567 static VALUE
03568 proc_getpgid(VALUE obj, VALUE pid)
03569 {
03570 rb_pid_t i;
03571
03572 rb_secure(2);
03573 i = getpgid(NUM2PIDT(pid));
03574 if (i < 0) rb_sys_fail(0);
03575 return PIDT2NUM(i);
03576 }
03577 #else
03578 #define proc_getpgid rb_f_notimplement
03579 #endif
03580
03581
03582 #ifdef HAVE_SETPGID
03583
03584
03585
03586
03587
03588
03589
03590
03591 static VALUE
03592 proc_setpgid(VALUE obj, VALUE pid, VALUE pgrp)
03593 {
03594 rb_pid_t ipid, ipgrp;
03595
03596 rb_secure(2);
03597 ipid = NUM2PIDT(pid);
03598 ipgrp = NUM2PIDT(pgrp);
03599
03600 if (setpgid(ipid, ipgrp) < 0) rb_sys_fail(0);
03601 return INT2FIX(0);
03602 }
03603 #else
03604 #define proc_setpgid rb_f_notimplement
03605 #endif
03606
03607
03608 #if defined(HAVE_SETSID) || (defined(HAVE_SETPGRP) && defined(TIOCNOTTY))
03609 #if !defined(HAVE_SETSID)
03610 static rb_pid_t ruby_setsid(void);
03611 #define setsid() ruby_setsid()
03612 #endif
03613
03614
03615
03616
03617
03618
03619
03620
03621
03622
03623
03624 static VALUE
03625 proc_setsid(void)
03626 {
03627 rb_pid_t pid;
03628
03629 rb_secure(2);
03630 pid = setsid();
03631 if (pid < 0) rb_sys_fail(0);
03632 return PIDT2NUM(pid);
03633 }
03634
03635 #if !defined(HAVE_SETSID)
03636 #define HAVE_SETSID 1
03637 static rb_pid_t
03638 ruby_setsid(void)
03639 {
03640 rb_pid_t pid;
03641 int ret;
03642
03643 pid = getpid();
03644 #if defined(SETPGRP_VOID)
03645 ret = setpgrp();
03646
03647
03648
03649 #else
03650 ret = setpgrp(0, pid);
03651 #endif
03652 if (ret == -1) return -1;
03653
03654 if ((fd = open("/dev/tty", O_RDWR)) >= 0) {
03655 rb_update_max_fd(fd);
03656 ioctl(fd, TIOCNOTTY, NULL);
03657 close(fd);
03658 }
03659 return pid;
03660 }
03661 #endif
03662 #else
03663 #define proc_setsid rb_f_notimplement
03664 #endif
03665
03666
03667 #ifdef HAVE_GETPRIORITY
03668
03669
03670
03671
03672
03673
03674
03675
03676
03677
03678
03679
03680
03681
03682
03683
03684
03685 static VALUE
03686 proc_getpriority(VALUE obj, VALUE which, VALUE who)
03687 {
03688 int prio, iwhich, iwho;
03689
03690 rb_secure(2);
03691 iwhich = NUM2INT(which);
03692 iwho = NUM2INT(who);
03693
03694 errno = 0;
03695 prio = getpriority(iwhich, iwho);
03696 if (errno) rb_sys_fail(0);
03697 return INT2FIX(prio);
03698 }
03699 #else
03700 #define proc_getpriority rb_f_notimplement
03701 #endif
03702
03703
03704 #ifdef HAVE_GETPRIORITY
03705
03706
03707
03708
03709
03710
03711
03712
03713
03714
03715
03716
03717 static VALUE
03718 proc_setpriority(VALUE obj, VALUE which, VALUE who, VALUE prio)
03719 {
03720 int iwhich, iwho, iprio;
03721
03722 rb_secure(2);
03723 iwhich = NUM2INT(which);
03724 iwho = NUM2INT(who);
03725 iprio = NUM2INT(prio);
03726
03727 if (setpriority(iwhich, iwho, iprio) < 0)
03728 rb_sys_fail(0);
03729 return INT2FIX(0);
03730 }
03731 #else
03732 #define proc_setpriority rb_f_notimplement
03733 #endif
03734
03735 #if defined(HAVE_SETRLIMIT) && defined(NUM2RLIM)
03736 static int
03737 rlimit_resource_name2int(const char *name, int casetype)
03738 {
03739 int resource;
03740 const char *p;
03741 #define RESCHECK(r) \
03742 do { \
03743 if (STRCASECMP(name, #r) == 0) { \
03744 resource = RLIMIT_##r; \
03745 goto found; \
03746 } \
03747 } while (0)
03748
03749 switch (TOUPPER(*name)) {
03750 case 'A':
03751 #ifdef RLIMIT_AS
03752 RESCHECK(AS);
03753 #endif
03754 break;
03755
03756 case 'C':
03757 #ifdef RLIMIT_CORE
03758 RESCHECK(CORE);
03759 #endif
03760 #ifdef RLIMIT_CPU
03761 RESCHECK(CPU);
03762 #endif
03763 break;
03764
03765 case 'D':
03766 #ifdef RLIMIT_DATA
03767 RESCHECK(DATA);
03768 #endif
03769 break;
03770
03771 case 'F':
03772 #ifdef RLIMIT_FSIZE
03773 RESCHECK(FSIZE);
03774 #endif
03775 break;
03776
03777 case 'M':
03778 #ifdef RLIMIT_MEMLOCK
03779 RESCHECK(MEMLOCK);
03780 #endif
03781 #ifdef RLIMIT_MSGQUEUE
03782 RESCHECK(MSGQUEUE);
03783 #endif
03784 break;
03785
03786 case 'N':
03787 #ifdef RLIMIT_NOFILE
03788 RESCHECK(NOFILE);
03789 #endif
03790 #ifdef RLIMIT_NPROC
03791 RESCHECK(NPROC);
03792 #endif
03793 #ifdef RLIMIT_NICE
03794 RESCHECK(NICE);
03795 #endif
03796 break;
03797
03798 case 'R':
03799 #ifdef RLIMIT_RSS
03800 RESCHECK(RSS);
03801 #endif
03802 #ifdef RLIMIT_RTPRIO
03803 RESCHECK(RTPRIO);
03804 #endif
03805 #ifdef RLIMIT_RTTIME
03806 RESCHECK(RTTIME);
03807 #endif
03808 break;
03809
03810 case 'S':
03811 #ifdef RLIMIT_STACK
03812 RESCHECK(STACK);
03813 #endif
03814 #ifdef RLIMIT_SBSIZE
03815 RESCHECK(SBSIZE);
03816 #endif
03817 #ifdef RLIMIT_SIGPENDING
03818 RESCHECK(SIGPENDING);
03819 #endif
03820 break;
03821 }
03822 return -1;
03823
03824 found:
03825 switch (casetype) {
03826 case 0:
03827 for (p = name; *p; p++)
03828 if (!ISUPPER(*p))
03829 return -1;
03830 break;
03831
03832 case 1:
03833 for (p = name; *p; p++)
03834 if (!ISLOWER(*p))
03835 return -1;
03836 break;
03837
03838 default:
03839 rb_bug("unexpected casetype");
03840 }
03841 return resource;
03842 #undef RESCHECK
03843 }
03844
03845 static int
03846 rlimit_type_by_hname(const char *name)
03847 {
03848 return rlimit_resource_name2int(name, 0);
03849 }
03850
03851 static int
03852 rlimit_type_by_lname(const char *name)
03853 {
03854 return rlimit_resource_name2int(name, 1);
03855 }
03856
03857 static int
03858 rlimit_resource_type(VALUE rtype)
03859 {
03860 const char *name;
03861 VALUE v;
03862 int r;
03863
03864 switch (TYPE(rtype)) {
03865 case T_SYMBOL:
03866 name = rb_id2name(SYM2ID(rtype));
03867 break;
03868
03869 default:
03870 v = rb_check_string_type(rtype);
03871 if (!NIL_P(v)) {
03872 rtype = v;
03873 case T_STRING:
03874 name = StringValueCStr(rtype);
03875 break;
03876 }
03877
03878
03879 case T_FIXNUM:
03880 case T_BIGNUM:
03881 return NUM2INT(rtype);
03882 }
03883
03884 r = rlimit_type_by_hname(name);
03885 if (r != -1)
03886 return r;
03887
03888 rb_raise(rb_eArgError, "invalid resource name: %s", name);
03889 }
03890
03891 static rlim_t
03892 rlimit_resource_value(VALUE rval)
03893 {
03894 const char *name;
03895 VALUE v;
03896
03897 switch (TYPE(rval)) {
03898 case T_SYMBOL:
03899 name = rb_id2name(SYM2ID(rval));
03900 break;
03901
03902 default:
03903 v = rb_check_string_type(rval);
03904 if (!NIL_P(v)) {
03905 rval = v;
03906 case T_STRING:
03907 name = StringValueCStr(rval);
03908 break;
03909 }
03910
03911
03912 case T_FIXNUM:
03913 case T_BIGNUM:
03914 return NUM2RLIM(rval);
03915 }
03916
03917 #ifdef RLIM_INFINITY
03918 if (strcmp(name, "INFINITY") == 0) return RLIM_INFINITY;
03919 #endif
03920 #ifdef RLIM_SAVED_MAX
03921 if (strcmp(name, "SAVED_MAX") == 0) return RLIM_SAVED_MAX;
03922 #endif
03923 #ifdef RLIM_SAVED_CUR
03924 if (strcmp(name, "SAVED_CUR") == 0) return RLIM_SAVED_CUR;
03925 #endif
03926 rb_raise(rb_eArgError, "invalid resource value: %s", name);
03927 }
03928 #endif
03929
03930 #if defined(HAVE_GETRLIMIT) && defined(RLIM2NUM)
03931
03932
03933
03934
03935
03936
03937
03938
03939
03940
03941
03942
03943
03944
03945
03946
03947
03948
03949
03950
03951 static VALUE
03952 proc_getrlimit(VALUE obj, VALUE resource)
03953 {
03954 struct rlimit rlim;
03955
03956 rb_secure(2);
03957
03958 if (getrlimit(rlimit_resource_type(resource), &rlim) < 0) {
03959 rb_sys_fail("getrlimit");
03960 }
03961 return rb_assoc_new(RLIM2NUM(rlim.rlim_cur), RLIM2NUM(rlim.rlim_max));
03962 }
03963 #else
03964 #define proc_getrlimit rb_f_notimplement
03965 #endif
03966
03967 #if defined(HAVE_SETRLIMIT) && defined(NUM2RLIM)
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
04010
04011
04012
04013
04014
04015
04016
04017
04018
04019 static VALUE
04020 proc_setrlimit(int argc, VALUE *argv, VALUE obj)
04021 {
04022 VALUE resource, rlim_cur, rlim_max;
04023 struct rlimit rlim;
04024
04025 rb_secure(2);
04026
04027 rb_scan_args(argc, argv, "21", &resource, &rlim_cur, &rlim_max);
04028 if (rlim_max == Qnil)
04029 rlim_max = rlim_cur;
04030
04031 rlim.rlim_cur = rlimit_resource_value(rlim_cur);
04032 rlim.rlim_max = rlimit_resource_value(rlim_max);
04033
04034 if (setrlimit(rlimit_resource_type(resource), &rlim) < 0) {
04035 rb_sys_fail("setrlimit");
04036 }
04037 return Qnil;
04038 }
04039 #else
04040 #define proc_setrlimit rb_f_notimplement
04041 #endif
04042
04043 static int under_uid_switch = 0;
04044 static void
04045 check_uid_switch(void)
04046 {
04047 rb_secure(2);
04048 if (under_uid_switch) {
04049 rb_raise(rb_eRuntimeError, "can't handle UID while evaluating block given to Process::UID.switch method");
04050 }
04051 }
04052
04053 static int under_gid_switch = 0;
04054 static void
04055 check_gid_switch(void)
04056 {
04057 rb_secure(2);
04058 if (under_gid_switch) {
04059 rb_raise(rb_eRuntimeError, "can't handle GID while evaluating block given to Process::UID.switch method");
04060 }
04061 }
04062
04063
04064
04065
04066
04067
04068
04069
04070
04071
04072
04073
04074
04075 #if defined HAVE_SETUID
04076
04077
04078
04079
04080
04081
04082
04083
04084
04085 static VALUE
04086 p_sys_setuid(VALUE obj, VALUE id)
04087 {
04088 check_uid_switch();
04089 if (setuid(NUM2UIDT(id)) != 0) rb_sys_fail(0);
04090 return Qnil;
04091 }
04092 #else
04093 #define p_sys_setuid rb_f_notimplement
04094 #endif
04095
04096
04097 #if defined HAVE_SETRUID
04098
04099
04100
04101
04102
04103
04104
04105
04106
04107 static VALUE
04108 p_sys_setruid(VALUE obj, VALUE id)
04109 {
04110 check_uid_switch();
04111 if (setruid(NUM2UIDT(id)) != 0) rb_sys_fail(0);
04112 return Qnil;
04113 }
04114 #else
04115 #define p_sys_setruid rb_f_notimplement
04116 #endif
04117
04118
04119 #if defined HAVE_SETEUID
04120
04121
04122
04123
04124
04125
04126
04127
04128
04129 static VALUE
04130 p_sys_seteuid(VALUE obj, VALUE id)
04131 {
04132 check_uid_switch();
04133 if (seteuid(NUM2UIDT(id)) != 0) rb_sys_fail(0);
04134 return Qnil;
04135 }
04136 #else
04137 #define p_sys_seteuid rb_f_notimplement
04138 #endif
04139
04140
04141 #if defined HAVE_SETREUID
04142
04143
04144
04145
04146
04147
04148
04149
04150
04151
04152
04153 static VALUE
04154 p_sys_setreuid(VALUE obj, VALUE rid, VALUE eid)
04155 {
04156 check_uid_switch();
04157 if (setreuid(NUM2UIDT(rid),NUM2UIDT(eid)) != 0) rb_sys_fail(0);
04158 return Qnil;
04159 }
04160 #else
04161 #define p_sys_setreuid rb_f_notimplement
04162 #endif
04163
04164
04165 #if defined HAVE_SETRESUID
04166
04167
04168
04169
04170
04171
04172
04173
04174
04175
04176
04177 static VALUE
04178 p_sys_setresuid(VALUE obj, VALUE rid, VALUE eid, VALUE sid)
04179 {
04180 check_uid_switch();
04181 if (setresuid(NUM2UIDT(rid),NUM2UIDT(eid),NUM2UIDT(sid)) != 0) rb_sys_fail(0);
04182 return Qnil;
04183 }
04184 #else
04185 #define p_sys_setresuid rb_f_notimplement
04186 #endif
04187
04188
04189
04190
04191
04192
04193
04194
04195
04196
04197
04198
04199
04200 static VALUE
04201 proc_getuid(VALUE obj)
04202 {
04203 rb_uid_t uid = getuid();
04204 return UIDT2NUM(uid);
04205 }
04206
04207
04208 #if defined(HAVE_SETRESUID) || defined(HAVE_SETREUID) || defined(HAVE_SETRUID) || defined(HAVE_SETUID)
04209
04210
04211
04212
04213
04214
04215
04216
04217 static VALUE
04218 proc_setuid(VALUE obj, VALUE id)
04219 {
04220 rb_uid_t uid;
04221
04222 check_uid_switch();
04223
04224 uid = NUM2UIDT(id);
04225 #if defined(HAVE_SETRESUID)
04226 if (setresuid(uid, -1, -1) < 0) rb_sys_fail(0);
04227 #elif defined HAVE_SETREUID
04228 if (setreuid(uid, -1) < 0) rb_sys_fail(0);
04229 #elif defined HAVE_SETRUID
04230 if (setruid(uid) < 0) rb_sys_fail(0);
04231 #elif defined HAVE_SETUID
04232 {
04233 if (geteuid() == uid) {
04234 if (setuid(uid) < 0) rb_sys_fail(0);
04235 }
04236 else {
04237 rb_notimplement();
04238 }
04239 }
04240 #endif
04241 return id;
04242 }
04243 #else
04244 #define proc_setuid rb_f_notimplement
04245 #endif
04246
04247
04248
04249
04250
04251
04252
04253
04254
04255
04256
04257
04258 static rb_uid_t SAVED_USER_ID = -1;
04259
04260 #ifdef BROKEN_SETREUID
04261 int
04262 setreuid(rb_uid_t ruid, rb_uid_t euid)
04263 {
04264 if (ruid != (rb_uid_t)-1 && ruid != getuid()) {
04265 if (euid == (rb_uid_t)-1) euid = geteuid();
04266 if (setuid(ruid) < 0) return -1;
04267 }
04268 if (euid != (rb_uid_t)-1 && euid != geteuid()) {
04269 if (seteuid(euid) < 0) return -1;
04270 }
04271 return 0;
04272 }
04273 #endif
04274
04275
04276
04277
04278
04279
04280
04281
04282
04283
04284
04285
04286
04287
04288 static VALUE
04289 p_uid_change_privilege(VALUE obj, VALUE id)
04290 {
04291 rb_uid_t uid;
04292
04293 check_uid_switch();
04294
04295 uid = NUM2UIDT(id);
04296
04297 if (geteuid() == 0) {
04298 #if defined(HAVE_SETRESUID)
04299 if (setresuid(uid, uid, uid) < 0) rb_sys_fail(0);
04300 SAVED_USER_ID = uid;
04301 #elif defined(HAVE_SETUID)
04302 if (setuid(uid) < 0) rb_sys_fail(0);
04303 SAVED_USER_ID = uid;
04304 #elif defined(HAVE_SETREUID) && !defined(OBSOLETE_SETREUID)
04305 if (getuid() == uid) {
04306 if (SAVED_USER_ID == uid) {
04307 if (setreuid(-1, uid) < 0) rb_sys_fail(0);
04308 } else {
04309 if (uid == 0) {
04310 if (setreuid(-1, SAVED_USER_ID) < 0) rb_sys_fail(0);
04311 if (setreuid(SAVED_USER_ID, 0) < 0) rb_sys_fail(0);
04312 SAVED_USER_ID = 0;
04313 if (setreuid(uid, uid) < 0) rb_sys_fail(0);
04314 SAVED_USER_ID = uid;
04315 } else {
04316 if (setreuid(0, -1) < 0) rb_sys_fail(0);
04317 SAVED_USER_ID = 0;
04318 if (setreuid(uid, uid) < 0) rb_sys_fail(0);
04319 SAVED_USER_ID = uid;
04320 }
04321 }
04322 } else {
04323 if (setreuid(uid, uid) < 0) rb_sys_fail(0);
04324 SAVED_USER_ID = uid;
04325 }
04326 #elif defined(HAVE_SETRUID) && defined(HAVE_SETEUID)
04327 if (getuid() == uid) {
04328 if (SAVED_USER_ID == uid) {
04329 if (seteuid(uid) < 0) rb_sys_fail(0);
04330 } else {
04331 if (uid == 0) {
04332 if (setruid(SAVED_USER_ID) < 0) rb_sys_fail(0);
04333 SAVED_USER_ID = 0;
04334 if (setruid(0) < 0) rb_sys_fail(0);
04335 } else {
04336 if (setruid(0) < 0) rb_sys_fail(0);
04337 SAVED_USER_ID = 0;
04338 if (seteuid(uid) < 0) rb_sys_fail(0);
04339 if (setruid(uid) < 0) rb_sys_fail(0);
04340 SAVED_USER_ID = uid;
04341 }
04342 }
04343 } else {
04344 if (seteuid(uid) < 0) rb_sys_fail(0);
04345 if (setruid(uid) < 0) rb_sys_fail(0);
04346 SAVED_USER_ID = uid;
04347 }
04348 #else
04349 rb_notimplement();
04350 #endif
04351 } else {
04352 #if defined(HAVE_SETRESUID)
04353 if (setresuid((getuid() == uid)? (rb_uid_t)-1: uid,
04354 (geteuid() == uid)? (rb_uid_t)-1: uid,
04355 (SAVED_USER_ID == uid)? (rb_uid_t)-1: uid) < 0) rb_sys_fail(0);
04356 SAVED_USER_ID = uid;
04357 #elif defined(HAVE_SETREUID) && !defined(OBSOLETE_SETREUID)
04358 if (SAVED_USER_ID == uid) {
04359 if (setreuid((getuid() == uid)? (rb_uid_t)-1: uid,
04360 (geteuid() == uid)? (rb_uid_t)-1: uid) < 0)
04361 rb_sys_fail(0);
04362 } else if (getuid() != uid) {
04363 if (setreuid(uid, (geteuid() == uid)? (rb_uid_t)-1: uid) < 0)
04364 rb_sys_fail(0);
04365 SAVED_USER_ID = uid;
04366 } else if ( geteuid() != uid) {
04367 if (setreuid(geteuid(), uid) < 0) rb_sys_fail(0);
04368 SAVED_USER_ID = uid;
04369 if (setreuid(uid, -1) < 0) rb_sys_fail(0);
04370 } else {
04371 if (setreuid(-1, SAVED_USER_ID) < 0) rb_sys_fail(0);
04372 if (setreuid(SAVED_USER_ID, uid) < 0) rb_sys_fail(0);
04373 SAVED_USER_ID = uid;
04374 if (setreuid(uid, -1) < 0) rb_sys_fail(0);
04375 }
04376 #elif defined(HAVE_SETRUID) && defined(HAVE_SETEUID)
04377 if (SAVED_USER_ID == uid) {
04378 if (geteuid() != uid && seteuid(uid) < 0) rb_sys_fail(0);
04379 if (getuid() != uid && setruid(uid) < 0) rb_sys_fail(0);
04380 } else if ( geteuid() == uid) {
04381 if (getuid() != uid) {
04382 if (setruid(uid) < 0) rb_sys_fail(0);
04383 SAVED_USER_ID = uid;
04384 } else {
04385 if (setruid(SAVED_USER_ID) < 0) rb_sys_fail(0);
04386 SAVED_USER_ID = uid;
04387 if (setruid(uid) < 0) rb_sys_fail(0);
04388 }
04389 } else if ( getuid() == uid) {
04390 if (seteuid(uid) < 0) rb_sys_fail(0);
04391 if (setruid(SAVED_USER_ID) < 0) rb_sys_fail(0);
04392 SAVED_USER_ID = uid;
04393 if (setruid(uid) < 0) rb_sys_fail(0);
04394 } else {
04395 errno = EPERM;
04396 rb_sys_fail(0);
04397 }
04398 #elif defined HAVE_44BSD_SETUID
04399 if (getuid() == uid) {
04400
04401 if (setuid(uid) < 0) rb_sys_fail(0);
04402 SAVED_USER_ID = uid;
04403 } else {
04404 errno = EPERM;
04405 rb_sys_fail(0);
04406 }
04407 #elif defined HAVE_SETEUID
04408 if (getuid() == uid && SAVED_USER_ID == uid) {
04409 if (seteuid(uid) < 0) rb_sys_fail(0);
04410 } else {
04411 errno = EPERM;
04412 rb_sys_fail(0);
04413 }
04414 #elif defined HAVE_SETUID
04415 if (getuid() == uid && SAVED_USER_ID == uid) {
04416 if (setuid(uid) < 0) rb_sys_fail(0);
04417 } else {
04418 errno = EPERM;
04419 rb_sys_fail(0);
04420 }
04421 #else
04422 rb_notimplement();
04423 #endif
04424 }
04425 return id;
04426 }
04427
04428
04429
04430 #if defined HAVE_SETGID
04431
04432
04433
04434
04435
04436
04437
04438
04439
04440 static VALUE
04441 p_sys_setgid(VALUE obj, VALUE id)
04442 {
04443 check_gid_switch();
04444 if (setgid(NUM2GIDT(id)) != 0) rb_sys_fail(0);
04445 return Qnil;
04446 }
04447 #else
04448 #define p_sys_setgid rb_f_notimplement
04449 #endif
04450
04451
04452 #if defined HAVE_SETRGID
04453
04454
04455
04456
04457
04458
04459
04460
04461
04462 static VALUE
04463 p_sys_setrgid(VALUE obj, VALUE id)
04464 {
04465 check_gid_switch();
04466 if (setrgid(NUM2GIDT(id)) != 0) rb_sys_fail(0);
04467 return Qnil;
04468 }
04469 #else
04470 #define p_sys_setrgid rb_f_notimplement
04471 #endif
04472
04473
04474 #if defined HAVE_SETEGID
04475
04476
04477
04478
04479
04480
04481
04482
04483
04484 static VALUE
04485 p_sys_setegid(VALUE obj, VALUE id)
04486 {
04487 check_gid_switch();
04488 if (setegid(NUM2GIDT(id)) != 0) rb_sys_fail(0);
04489 return Qnil;
04490 }
04491 #else
04492 #define p_sys_setegid rb_f_notimplement
04493 #endif
04494
04495
04496 #if defined HAVE_SETREGID
04497
04498
04499
04500
04501
04502
04503
04504
04505
04506
04507
04508 static VALUE
04509 p_sys_setregid(VALUE obj, VALUE rid, VALUE eid)
04510 {
04511 check_gid_switch();
04512 if (setregid(NUM2GIDT(rid),NUM2GIDT(eid)) != 0) rb_sys_fail(0);
04513 return Qnil;
04514 }
04515 #else
04516 #define p_sys_setregid rb_f_notimplement
04517 #endif
04518
04519 #if defined HAVE_SETRESGID
04520
04521
04522
04523
04524
04525
04526
04527
04528
04529
04530
04531 static VALUE
04532 p_sys_setresgid(VALUE obj, VALUE rid, VALUE eid, VALUE sid)
04533 {
04534 check_gid_switch();
04535 if (setresgid(NUM2GIDT(rid),NUM2GIDT(eid),NUM2GIDT(sid)) != 0) rb_sys_fail(0);
04536 return Qnil;
04537 }
04538 #else
04539 #define p_sys_setresgid rb_f_notimplement
04540 #endif
04541
04542
04543 #if defined HAVE_ISSETUGID
04544
04545
04546
04547
04548
04549
04550
04551
04552
04553
04554
04555
04556 static VALUE
04557 p_sys_issetugid(VALUE obj)
04558 {
04559 rb_secure(2);
04560 if (issetugid()) {
04561 return Qtrue;
04562 } else {
04563 return Qfalse;
04564 }
04565 }
04566 #else
04567 #define p_sys_issetugid rb_f_notimplement
04568 #endif
04569
04570
04571
04572
04573
04574
04575
04576
04577
04578
04579
04580
04581
04582 static VALUE
04583 proc_getgid(VALUE obj)
04584 {
04585 rb_gid_t gid = getgid();
04586 return GIDT2NUM(gid);
04587 }
04588
04589
04590 #if defined(HAVE_SETRESGID) || defined(HAVE_SETREGID) || defined(HAVE_SETRGID) || defined(HAVE_SETGID)
04591
04592
04593
04594
04595
04596
04597
04598 static VALUE
04599 proc_setgid(VALUE obj, VALUE id)
04600 {
04601 rb_gid_t gid;
04602
04603 check_gid_switch();
04604
04605 gid = NUM2GIDT(id);
04606 #if defined(HAVE_SETRESGID)
04607 if (setresgid(gid, -1, -1) < 0) rb_sys_fail(0);
04608 #elif defined HAVE_SETREGID
04609 if (setregid(gid, -1) < 0) rb_sys_fail(0);
04610 #elif defined HAVE_SETRGID
04611 if (setrgid(gid) < 0) rb_sys_fail(0);
04612 #elif defined HAVE_SETGID
04613 {
04614 if (getegid() == gid) {
04615 if (setgid(gid) < 0) rb_sys_fail(0);
04616 }
04617 else {
04618 rb_notimplement();
04619 }
04620 }
04621 #endif
04622 return GIDT2NUM(gid);
04623 }
04624 #else
04625 #define proc_setgid rb_f_notimplement
04626 #endif
04627
04628
04629 #if defined(HAVE_SETGROUPS) || defined(HAVE_GETGROUPS)
04630
04631
04632
04633
04634
04635
04636
04637
04638
04639
04640
04641
04642
04643
04644
04645
04646
04647
04648
04649
04650 #define RB_MAX_GROUPS (65536)
04651 static int _maxgroups = -1;
04652 static int get_sc_ngroups_max(void)
04653 {
04654 #ifdef _SC_NGROUPS_MAX
04655 return (int)sysconf(_SC_NGROUPS_MAX);
04656 #elif defined(NGROUPS_MAX)
04657 return (int)NGROUPS_MAX;
04658 #else
04659 return -1;
04660 #endif
04661 }
04662 static int maxgroups(void)
04663 {
04664 if (_maxgroups < 0) {
04665 _maxgroups = get_sc_ngroups_max();
04666 if (_maxgroups < 0)
04667 _maxgroups = RB_MAX_GROUPS;
04668 }
04669
04670 return _maxgroups;
04671 }
04672 #endif
04673
04674
04675
04676 #ifdef HAVE_GETGROUPS
04677
04678
04679
04680
04681
04682
04683
04684
04685
04686
04687
04688 static VALUE
04689 proc_getgroups(VALUE obj)
04690 {
04691 VALUE ary;
04692 int i, ngroups;
04693 rb_gid_t *groups;
04694
04695 ngroups = getgroups(0, NULL);
04696 if (ngroups == -1)
04697 rb_sys_fail(0);
04698
04699 groups = ALLOCA_N(rb_gid_t, ngroups);
04700
04701 ngroups = getgroups(ngroups, groups);
04702 if (ngroups == -1)
04703 rb_sys_fail(0);
04704
04705 ary = rb_ary_new();
04706 for (i = 0; i < ngroups; i++)
04707 rb_ary_push(ary, GIDT2NUM(groups[i]));
04708
04709 return ary;
04710 }
04711 #else
04712 #define proc_getgroups rb_f_notimplement
04713 #endif
04714
04715
04716 #ifdef HAVE_SETGROUPS
04717
04718
04719
04720
04721
04722
04723
04724
04725
04726
04727
04728
04729
04730 static VALUE
04731 proc_setgroups(VALUE obj, VALUE ary)
04732 {
04733 int ngroups, i;
04734 rb_gid_t *groups;
04735 #ifdef HAVE_GETGRNAM_R
04736 long getgr_buf_len = sysconf(_SC_GETGR_R_SIZE_MAX);
04737 char* getgr_buf;
04738
04739 if (getgr_buf_len < 0)
04740 getgr_buf_len = 4096;
04741 getgr_buf = ALLOCA_N(char, getgr_buf_len);
04742 #endif
04743
04744 Check_Type(ary, T_ARRAY);
04745
04746 ngroups = RARRAY_LENINT(ary);
04747 if (ngroups > maxgroups())
04748 rb_raise(rb_eArgError, "too many groups, %d max", maxgroups());
04749
04750 groups = ALLOCA_N(rb_gid_t, ngroups);
04751
04752 for (i = 0; i < ngroups; i++) {
04753 VALUE g = RARRAY_PTR(ary)[i];
04754
04755 if (FIXNUM_P(g)) {
04756 groups[i] = NUM2GIDT(g);
04757 }
04758 else {
04759 VALUE tmp = rb_check_string_type(g);
04760 struct group grp;
04761 struct group *p;
04762 int ret;
04763
04764 if (NIL_P(tmp)) {
04765 groups[i] = NUM2GIDT(g);
04766 }
04767 else {
04768 const char *grpname = StringValueCStr(tmp);
04769
04770 #ifdef HAVE_GETGRNAM_R
04771 ret = getgrnam_r(grpname, &grp, getgr_buf, getgr_buf_len, &p);
04772 if (ret)
04773 rb_sys_fail("getgrnam_r");
04774 #else
04775 p = getgrnam(grpname);
04776 #endif
04777 if (p == NULL) {
04778 rb_raise(rb_eArgError,
04779 "can't find group for %s", RSTRING_PTR(tmp));
04780 }
04781 groups[i] = p->gr_gid;
04782 }
04783 }
04784 }
04785
04786 if (setgroups(ngroups, groups) == -1)
04787 rb_sys_fail(0);
04788
04789 return proc_getgroups(obj);
04790 }
04791 #else
04792 #define proc_setgroups rb_f_notimplement
04793 #endif
04794
04795
04796 #ifdef HAVE_INITGROUPS
04797
04798
04799
04800
04801
04802
04803
04804
04805
04806
04807
04808
04809
04810
04811
04812
04813
04814 static VALUE
04815 proc_initgroups(VALUE obj, VALUE uname, VALUE base_grp)
04816 {
04817 if (initgroups(StringValuePtr(uname), NUM2GIDT(base_grp)) != 0) {
04818 rb_sys_fail(0);
04819 }
04820 return proc_getgroups(obj);
04821 }
04822 #else
04823 #define proc_initgroups rb_f_notimplement
04824 #endif
04825
04826 #if defined(_SC_NGROUPS_MAX) || defined(NGROUPS_MAX)
04827
04828
04829
04830
04831
04832
04833
04834
04835
04836
04837 static VALUE
04838 proc_getmaxgroups(VALUE obj)
04839 {
04840 return INT2FIX(maxgroups());
04841 }
04842 #else
04843 #define proc_getmaxgroups rb_f_notimplement
04844 #endif
04845
04846 #ifdef HAVE_SETGROUPS
04847
04848
04849
04850
04851
04852
04853
04854
04855 static VALUE
04856 proc_setmaxgroups(VALUE obj, VALUE val)
04857 {
04858 int ngroups = FIX2INT(val);
04859 int ngroups_max = get_sc_ngroups_max();
04860
04861 if (ngroups <= 0)
04862 rb_raise(rb_eArgError, "maxgroups %d shold be positive", ngroups);
04863
04864 if (ngroups > RB_MAX_GROUPS)
04865 ngroups = RB_MAX_GROUPS;
04866
04867 if (ngroups_max > 0 && ngroups > ngroups_max)
04868 ngroups = ngroups_max;
04869
04870 _maxgroups = ngroups;
04871
04872 return INT2FIX(_maxgroups);
04873 }
04874 #else
04875 #define proc_setmaxgroups rb_f_notimplement
04876 #endif
04877
04878 #if defined(HAVE_DAEMON) || (defined(HAVE_FORK) && defined(HAVE_SETSID))
04879 static int rb_daemon(int nochdir, int noclose);
04880
04881
04882
04883
04884
04885
04886
04887
04888
04889
04890
04891
04892
04893
04894
04895 static VALUE
04896 proc_daemon(int argc, VALUE *argv)
04897 {
04898 VALUE nochdir, noclose;
04899 int n;
04900
04901 rb_secure(2);
04902 rb_scan_args(argc, argv, "02", &nochdir, &noclose);
04903
04904 prefork();
04905 n = rb_daemon(RTEST(nochdir), RTEST(noclose));
04906 if (n < 0) rb_sys_fail("daemon");
04907 return INT2FIX(n);
04908 }
04909
04910 static int
04911 rb_daemon(int nochdir, int noclose)
04912 {
04913 int err = 0;
04914 #ifdef HAVE_DAEMON
04915 before_fork();
04916 err = daemon(nochdir, noclose);
04917 after_fork();
04918 rb_thread_atfork();
04919 #else
04920 int n;
04921
04922 #define fork_daemon() \
04923 switch (rb_fork(0, 0, 0, Qnil)) { \
04924 case -1: return -1; \
04925 case 0: rb_thread_atfork(); break; \
04926 default: _exit(EXIT_SUCCESS); \
04927 }
04928
04929 fork_daemon();
04930
04931 if (setsid() < 0) return -1;
04932
04933
04934 fork_daemon();
04935
04936 if (!nochdir)
04937 err = chdir("/");
04938
04939 if (!noclose && (n = open("/dev/null", O_RDWR, 0)) != -1) {
04940 rb_update_max_fd(n);
04941 (void)dup2(n, 0);
04942 (void)dup2(n, 1);
04943 (void)dup2(n, 2);
04944 if (n > 2)
04945 (void)close (n);
04946 }
04947 #endif
04948 return err;
04949 }
04950 #else
04951 #define proc_daemon rb_f_notimplement
04952 #endif
04953
04954
04955
04956
04957
04958
04959
04960
04961
04962
04963
04964 static rb_gid_t SAVED_GROUP_ID = -1;
04965
04966 #ifdef BROKEN_SETREGID
04967 int
04968 setregid(rb_gid_t rgid, rb_gid_t egid)
04969 {
04970 if (rgid != (rb_gid_t)-1 && rgid != getgid()) {
04971 if (egid == (rb_gid_t)-1) egid = getegid();
04972 if (setgid(rgid) < 0) return -1;
04973 }
04974 if (egid != (rb_gid_t)-1 && egid != getegid()) {
04975 if (setegid(egid) < 0) return -1;
04976 }
04977 return 0;
04978 }
04979 #endif
04980
04981
04982
04983
04984
04985
04986
04987
04988
04989
04990
04991
04992
04993
04994 static VALUE
04995 p_gid_change_privilege(VALUE obj, VALUE id)
04996 {
04997 rb_gid_t gid;
04998
04999 check_gid_switch();
05000
05001 gid = NUM2GIDT(id);
05002
05003 if (geteuid() == 0) {
05004 #if defined(HAVE_SETRESGID)
05005 if (setresgid(gid, gid, gid) < 0) rb_sys_fail(0);
05006 SAVED_GROUP_ID = gid;
05007 #elif defined HAVE_SETGID
05008 if (setgid(gid) < 0) rb_sys_fail(0);
05009 SAVED_GROUP_ID = gid;
05010 #elif defined(HAVE_SETREGID) && !defined(OBSOLETE_SETREGID)
05011 if (getgid() == gid) {
05012 if (SAVED_GROUP_ID == gid) {
05013 if (setregid(-1, gid) < 0) rb_sys_fail(0);
05014 } else {
05015 if (gid == 0) {
05016 if (setregid(-1, SAVED_GROUP_ID) < 0) rb_sys_fail(0);
05017 if (setregid(SAVED_GROUP_ID, 0) < 0) rb_sys_fail(0);
05018 SAVED_GROUP_ID = 0;
05019 if (setregid(gid, gid) < 0) rb_sys_fail(0);
05020 SAVED_GROUP_ID = gid;
05021 } else {
05022 if (setregid(0, 0) < 0) rb_sys_fail(0);
05023 SAVED_GROUP_ID = 0;
05024 if (setregid(gid, gid) < 0) rb_sys_fail(0);
05025 SAVED_GROUP_ID = gid;
05026 }
05027 }
05028 } else {
05029 if (setregid(gid, gid) < 0) rb_sys_fail(0);
05030 SAVED_GROUP_ID = gid;
05031 }
05032 #elif defined(HAVE_SETRGID) && defined (HAVE_SETEGID)
05033 if (getgid() == gid) {
05034 if (SAVED_GROUP_ID == gid) {
05035 if (setegid(gid) < 0) rb_sys_fail(0);
05036 } else {
05037 if (gid == 0) {
05038 if (setegid(gid) < 0) rb_sys_fail(0);
05039 if (setrgid(SAVED_GROUP_ID) < 0) rb_sys_fail(0);
05040 SAVED_GROUP_ID = 0;
05041 if (setrgid(0) < 0) rb_sys_fail(0);
05042 } else {
05043 if (setrgid(0) < 0) rb_sys_fail(0);
05044 SAVED_GROUP_ID = 0;
05045 if (setegid(gid) < 0) rb_sys_fail(0);
05046 if (setrgid(gid) < 0) rb_sys_fail(0);
05047 SAVED_GROUP_ID = gid;
05048 }
05049 }
05050 } else {
05051 if (setegid(gid) < 0) rb_sys_fail(0);
05052 if (setrgid(gid) < 0) rb_sys_fail(0);
05053 SAVED_GROUP_ID = gid;
05054 }
05055 #else
05056 rb_notimplement();
05057 #endif
05058 } else {
05059 #if defined(HAVE_SETRESGID)
05060 if (setresgid((getgid() == gid)? (rb_gid_t)-1: gid,
05061 (getegid() == gid)? (rb_gid_t)-1: gid,
05062 (SAVED_GROUP_ID == gid)? (rb_gid_t)-1: gid) < 0) rb_sys_fail(0);
05063 SAVED_GROUP_ID = gid;
05064 #elif defined(HAVE_SETREGID) && !defined(OBSOLETE_SETREGID)
05065 if (SAVED_GROUP_ID == gid) {
05066 if (setregid((getgid() == gid)? (rb_uid_t)-1: gid,
05067 (getegid() == gid)? (rb_uid_t)-1: gid) < 0)
05068 rb_sys_fail(0);
05069 } else if (getgid() != gid) {
05070 if (setregid(gid, (getegid() == gid)? (rb_uid_t)-1: gid) < 0)
05071 rb_sys_fail(0);
05072 SAVED_GROUP_ID = gid;
05073 } else if ( getegid() != gid) {
05074 if (setregid(getegid(), gid) < 0) rb_sys_fail(0);
05075 SAVED_GROUP_ID = gid;
05076 if (setregid(gid, -1) < 0) rb_sys_fail(0);
05077 } else {
05078 if (setregid(-1, SAVED_GROUP_ID) < 0) rb_sys_fail(0);
05079 if (setregid(SAVED_GROUP_ID, gid) < 0) rb_sys_fail(0);
05080 SAVED_GROUP_ID = gid;
05081 if (setregid(gid, -1) < 0) rb_sys_fail(0);
05082 }
05083 #elif defined(HAVE_SETRGID) && defined(HAVE_SETEGID)
05084 if (SAVED_GROUP_ID == gid) {
05085 if (getegid() != gid && setegid(gid) < 0) rb_sys_fail(0);
05086 if (getgid() != gid && setrgid(gid) < 0) rb_sys_fail(0);
05087 } else if ( getegid() == gid) {
05088 if (getgid() != gid) {
05089 if (setrgid(gid) < 0) rb_sys_fail(0);
05090 SAVED_GROUP_ID = gid;
05091 } else {
05092 if (setrgid(SAVED_GROUP_ID) < 0) rb_sys_fail(0);
05093 SAVED_GROUP_ID = gid;
05094 if (setrgid(gid) < 0) rb_sys_fail(0);
05095 }
05096 } else if ( getgid() == gid) {
05097 if (setegid(gid) < 0) rb_sys_fail(0);
05098 if (setrgid(SAVED_GROUP_ID) < 0) rb_sys_fail(0);
05099 SAVED_GROUP_ID = gid;
05100 if (setrgid(gid) < 0) rb_sys_fail(0);
05101 } else {
05102 errno = EPERM;
05103 rb_sys_fail(0);
05104 }
05105 #elif defined HAVE_44BSD_SETGID
05106 if (getgid() == gid) {
05107
05108 if (setgid(gid) < 0) rb_sys_fail(0);
05109 SAVED_GROUP_ID = gid;
05110 } else {
05111 errno = EPERM;
05112 rb_sys_fail(0);
05113 }
05114 #elif defined HAVE_SETEGID
05115 if (getgid() == gid && SAVED_GROUP_ID == gid) {
05116 if (setegid(gid) < 0) rb_sys_fail(0);
05117 } else {
05118 errno = EPERM;
05119 rb_sys_fail(0);
05120 }
05121 #elif defined HAVE_SETGID
05122 if (getgid() == gid && SAVED_GROUP_ID == gid) {
05123 if (setgid(gid) < 0) rb_sys_fail(0);
05124 } else {
05125 errno = EPERM;
05126 rb_sys_fail(0);
05127 }
05128 #else
05129 rb_notimplement();
05130 #endif
05131 }
05132 return id;
05133 }
05134
05135
05136
05137
05138
05139
05140
05141
05142
05143
05144
05145
05146
05147 static VALUE
05148 proc_geteuid(VALUE obj)
05149 {
05150 rb_uid_t euid = geteuid();
05151 return UIDT2NUM(euid);
05152 }
05153
05154 #if defined(HAVE_SETRESUID) || defined(HAVE_SETREUID) || defined(HAVE_SETEUID) || defined(HAVE_SETUID) || defined(_POSIX_SAVED_IDS)
05155
05156
05157
05158
05159
05160
05161
05162
05163 static VALUE
05164 proc_seteuid(VALUE obj, VALUE euid)
05165 {
05166 rb_uid_t uid;
05167
05168 check_uid_switch();
05169
05170 uid = NUM2UIDT(euid);
05171 #if defined(HAVE_SETRESUID)
05172 if (setresuid(-1, uid, -1) < 0) rb_sys_fail(0);
05173 #elif defined HAVE_SETREUID
05174 if (setreuid(-1, uid) < 0) rb_sys_fail(0);
05175 #elif defined HAVE_SETEUID
05176 if (seteuid(uid) < 0) rb_sys_fail(0);
05177 #elif defined HAVE_SETUID
05178 if (uid == getuid()) {
05179 if (setuid(uid) < 0) rb_sys_fail(0);
05180 }
05181 else {
05182 rb_notimplement();
05183 }
05184 #else
05185 rb_notimplement();
05186 #endif
05187 return euid;
05188 }
05189 #endif
05190
05191 #if defined(HAVE_SETRESUID) || defined(HAVE_SETREUID) || defined(HAVE_SETEUID) || defined(HAVE_SETUID)
05192 #define proc_seteuid_m proc_seteuid
05193 #else
05194 #define proc_seteuid_m rb_f_notimplement
05195 #endif
05196
05197 static rb_uid_t
05198 rb_seteuid_core(rb_uid_t euid)
05199 {
05200 rb_uid_t uid;
05201
05202 check_uid_switch();
05203
05204 uid = getuid();
05205
05206 #if defined(HAVE_SETRESUID)
05207 if (uid != euid) {
05208 if (setresuid(-1,euid,euid) < 0) rb_sys_fail(0);
05209 SAVED_USER_ID = euid;
05210 } else {
05211 if (setresuid(-1,euid,-1) < 0) rb_sys_fail(0);
05212 }
05213 #elif defined(HAVE_SETREUID) && !defined(OBSOLETE_SETREUID)
05214 if (setreuid(-1, euid) < 0) rb_sys_fail(0);
05215 if (uid != euid) {
05216 if (setreuid(euid,uid) < 0) rb_sys_fail(0);
05217 if (setreuid(uid,euid) < 0) rb_sys_fail(0);
05218 SAVED_USER_ID = euid;
05219 }
05220 #elif defined HAVE_SETEUID
05221 if (seteuid(euid) < 0) rb_sys_fail(0);
05222 #elif defined HAVE_SETUID
05223 if (geteuid() == 0) rb_sys_fail(0);
05224 if (setuid(euid) < 0) rb_sys_fail(0);
05225 #else
05226 rb_notimplement();
05227 #endif
05228 return euid;
05229 }
05230
05231
05232
05233
05234
05235
05236
05237
05238
05239
05240
05241
05242
05243
05244
05245
05246 static VALUE
05247 p_uid_grant_privilege(VALUE obj, VALUE id)
05248 {
05249 rb_seteuid_core(NUM2UIDT(id));
05250 return id;
05251 }
05252
05253
05254
05255
05256
05257
05258
05259
05260
05261
05262
05263
05264
05265
05266 static VALUE
05267 proc_getegid(VALUE obj)
05268 {
05269 rb_gid_t egid = getegid();
05270
05271 return GIDT2NUM(egid);
05272 }
05273
05274 #if defined(HAVE_SETRESGID) || defined(HAVE_SETREGID) || defined(HAVE_SETEGID) || defined(HAVE_SETGID) || defined(_POSIX_SAVED_IDS)
05275
05276
05277
05278
05279
05280
05281
05282
05283 static VALUE
05284 proc_setegid(VALUE obj, VALUE egid)
05285 {
05286 rb_gid_t gid;
05287
05288 check_gid_switch();
05289
05290 gid = NUM2GIDT(egid);
05291 #if defined(HAVE_SETRESGID)
05292 if (setresgid(-1, gid, -1) < 0) rb_sys_fail(0);
05293 #elif defined HAVE_SETREGID
05294 if (setregid(-1, gid) < 0) rb_sys_fail(0);
05295 #elif defined HAVE_SETEGID
05296 if (setegid(gid) < 0) rb_sys_fail(0);
05297 #elif defined HAVE_SETGID
05298 if (gid == getgid()) {
05299 if (setgid(gid) < 0) rb_sys_fail(0);
05300 }
05301 else {
05302 rb_notimplement();
05303 }
05304 #else
05305 rb_notimplement();
05306 #endif
05307 return egid;
05308 }
05309 #endif
05310
05311 #if defined(HAVE_SETRESGID) || defined(HAVE_SETREGID) || defined(HAVE_SETEGID) || defined(HAVE_SETGID)
05312 #define proc_setegid_m proc_setegid
05313 #else
05314 #define proc_setegid_m rb_f_notimplement
05315 #endif
05316
05317 static rb_gid_t
05318 rb_setegid_core(rb_gid_t egid)
05319 {
05320 rb_gid_t gid;
05321
05322 check_gid_switch();
05323
05324 gid = getgid();
05325
05326 #if defined(HAVE_SETRESGID)
05327 if (gid != egid) {
05328 if (setresgid(-1,egid,egid) < 0) rb_sys_fail(0);
05329 SAVED_GROUP_ID = egid;
05330 } else {
05331 if (setresgid(-1,egid,-1) < 0) rb_sys_fail(0);
05332 }
05333 #elif defined(HAVE_SETREGID) && !defined(OBSOLETE_SETREGID)
05334 if (setregid(-1, egid) < 0) rb_sys_fail(0);
05335 if (gid != egid) {
05336 if (setregid(egid,gid) < 0) rb_sys_fail(0);
05337 if (setregid(gid,egid) < 0) rb_sys_fail(0);
05338 SAVED_GROUP_ID = egid;
05339 }
05340 #elif defined HAVE_SETEGID
05341 if (setegid(egid) < 0) rb_sys_fail(0);
05342 #elif defined HAVE_SETGID
05343 if (geteuid() == 0 ) rb_sys_fail(0);
05344 if (setgid(egid) < 0) rb_sys_fail(0);
05345 #else
05346 rb_notimplement();
05347 #endif
05348 return egid;
05349 }
05350
05351
05352
05353
05354
05355
05356
05357
05358
05359
05360
05361
05362
05363
05364
05365
05366 static VALUE
05367 p_gid_grant_privilege(VALUE obj, VALUE id)
05368 {
05369 rb_setegid_core(NUM2GIDT(id));
05370 return id;
05371 }
05372
05373
05374
05375
05376
05377
05378
05379
05380
05381
05382
05383 static VALUE
05384 p_uid_exchangeable(void)
05385 {
05386 #if defined(HAVE_SETRESUID)
05387 return Qtrue;
05388 #elif defined(HAVE_SETREUID) && !defined(OBSOLETE_SETREUID)
05389 return Qtrue;
05390 #else
05391 return Qfalse;
05392 #endif
05393 }
05394
05395
05396
05397
05398
05399
05400
05401
05402
05403
05404
05405
05406
05407
05408 static VALUE
05409 p_uid_exchange(VALUE obj)
05410 {
05411 rb_uid_t uid, euid;
05412
05413 check_uid_switch();
05414
05415 uid = getuid();
05416 euid = geteuid();
05417
05418 #if defined(HAVE_SETRESUID)
05419 if (setresuid(euid, uid, uid) < 0) rb_sys_fail(0);
05420 SAVED_USER_ID = uid;
05421 #elif defined(HAVE_SETREUID) && !defined(OBSOLETE_SETREUID)
05422 if (setreuid(euid,uid) < 0) rb_sys_fail(0);
05423 SAVED_USER_ID = uid;
05424 #else
05425 rb_notimplement();
05426 #endif
05427 return UIDT2NUM(uid);
05428 }
05429
05430
05431
05432
05433
05434
05435
05436
05437
05438
05439
05440 static VALUE
05441 p_gid_exchangeable(void)
05442 {
05443 #if defined(HAVE_SETRESGID)
05444 return Qtrue;
05445 #elif defined(HAVE_SETREGID) && !defined(OBSOLETE_SETREGID)
05446 return Qtrue;
05447 #else
05448 return Qfalse;
05449 #endif
05450 }
05451
05452
05453
05454
05455
05456
05457
05458
05459
05460
05461
05462
05463
05464
05465 static VALUE
05466 p_gid_exchange(VALUE obj)
05467 {
05468 rb_gid_t gid, egid;
05469
05470 check_gid_switch();
05471
05472 gid = getgid();
05473 egid = getegid();
05474
05475 #if defined(HAVE_SETRESGID)
05476 if (setresgid(egid, gid, gid) < 0) rb_sys_fail(0);
05477 SAVED_GROUP_ID = gid;
05478 #elif defined(HAVE_SETREGID) && !defined(OBSOLETE_SETREGID)
05479 if (setregid(egid,gid) < 0) rb_sys_fail(0);
05480 SAVED_GROUP_ID = gid;
05481 #else
05482 rb_notimplement();
05483 #endif
05484 return GIDT2NUM(gid);
05485 }
05486
05487
05488
05489
05490
05491
05492
05493
05494
05495
05496
05497
05498 static VALUE
05499 p_uid_have_saved_id(void)
05500 {
05501 #if defined(HAVE_SETRESUID) || defined(HAVE_SETEUID) || defined(_POSIX_SAVED_IDS)
05502 return Qtrue;
05503 #else
05504 return Qfalse;
05505 #endif
05506 }
05507
05508
05509 #if defined(HAVE_SETRESUID) || defined(HAVE_SETEUID) || defined(_POSIX_SAVED_IDS)
05510 static VALUE
05511 p_uid_sw_ensure(rb_uid_t id)
05512 {
05513 under_uid_switch = 0;
05514 id = rb_seteuid_core(id);
05515 return UIDT2NUM(id);
05516 }
05517
05518
05519
05520
05521
05522
05523
05524
05525
05526
05527
05528
05529
05530
05531
05532 static VALUE
05533 p_uid_switch(VALUE obj)
05534 {
05535 rb_uid_t uid, euid;
05536
05537 check_uid_switch();
05538
05539 uid = getuid();
05540 euid = geteuid();
05541
05542 if (uid != euid) {
05543 proc_seteuid(obj, UIDT2NUM(uid));
05544 if (rb_block_given_p()) {
05545 under_uid_switch = 1;
05546 return rb_ensure(rb_yield, Qnil, p_uid_sw_ensure, SAVED_USER_ID);
05547 } else {
05548 return UIDT2NUM(euid);
05549 }
05550 } else if (euid != SAVED_USER_ID) {
05551 proc_seteuid(obj, UIDT2NUM(SAVED_USER_ID));
05552 if (rb_block_given_p()) {
05553 under_uid_switch = 1;
05554 return rb_ensure(rb_yield, Qnil, p_uid_sw_ensure, euid);
05555 } else {
05556 return UIDT2NUM(uid);
05557 }
05558 } else {
05559 errno = EPERM;
05560 rb_sys_fail(0);
05561 }
05562 }
05563 #else
05564 static VALUE
05565 p_uid_sw_ensure(VALUE obj)
05566 {
05567 under_uid_switch = 0;
05568 return p_uid_exchange(obj);
05569 }
05570
05571 static VALUE
05572 p_uid_switch(VALUE obj)
05573 {
05574 rb_uid_t uid, euid;
05575
05576 check_uid_switch();
05577
05578 uid = getuid();
05579 euid = geteuid();
05580
05581 if (uid == euid) {
05582 errno = EPERM;
05583 rb_sys_fail(0);
05584 }
05585 p_uid_exchange(obj);
05586 if (rb_block_given_p()) {
05587 under_uid_switch = 1;
05588 return rb_ensure(rb_yield, Qnil, p_uid_sw_ensure, obj);
05589 } else {
05590 return UIDT2NUM(euid);
05591 }
05592 }
05593 #endif
05594
05595
05596
05597
05598
05599
05600
05601
05602
05603
05604
05605
05606
05607 static VALUE
05608 p_gid_have_saved_id(void)
05609 {
05610 #if defined(HAVE_SETRESGID) || defined(HAVE_SETEGID) || defined(_POSIX_SAVED_IDS)
05611 return Qtrue;
05612 #else
05613 return Qfalse;
05614 #endif
05615 }
05616
05617 #if defined(HAVE_SETRESGID) || defined(HAVE_SETEGID) || defined(_POSIX_SAVED_IDS)
05618 static VALUE
05619 p_gid_sw_ensure(rb_gid_t id)
05620 {
05621 under_gid_switch = 0;
05622 id = rb_setegid_core(id);
05623 return GIDT2NUM(id);
05624 }
05625
05626
05627
05628
05629
05630
05631
05632
05633
05634
05635
05636
05637
05638
05639
05640 static VALUE
05641 p_gid_switch(VALUE obj)
05642 {
05643 rb_gid_t gid, egid;
05644
05645 check_gid_switch();
05646
05647 gid = getgid();
05648 egid = getegid();
05649
05650 if (gid != egid) {
05651 proc_setegid(obj, GIDT2NUM(gid));
05652 if (rb_block_given_p()) {
05653 under_gid_switch = 1;
05654 return rb_ensure(rb_yield, Qnil, p_gid_sw_ensure, SAVED_GROUP_ID);
05655 } else {
05656 return GIDT2NUM(egid);
05657 }
05658 }
05659 else if (egid != SAVED_GROUP_ID) {
05660 proc_setegid(obj, GIDT2NUM(SAVED_GROUP_ID));
05661 if (rb_block_given_p()) {
05662 under_gid_switch = 1;
05663 return rb_ensure(rb_yield, Qnil, p_gid_sw_ensure, egid);
05664 } else {
05665 return GIDT2NUM(gid);
05666 }
05667 }
05668 else {
05669 errno = EPERM;
05670 rb_sys_fail(0);
05671 }
05672 }
05673 #else
05674 static VALUE
05675 p_gid_sw_ensure(VALUE obj)
05676 {
05677 under_gid_switch = 0;
05678 return p_gid_exchange(obj);
05679 }
05680
05681 static VALUE
05682 p_gid_switch(VALUE obj)
05683 {
05684 rb_gid_t gid, egid;
05685
05686 check_gid_switch();
05687
05688 gid = getgid();
05689 egid = getegid();
05690
05691 if (gid == egid) {
05692 errno = EPERM;
05693 rb_sys_fail(0);
05694 }
05695 p_gid_exchange(obj);
05696 if (rb_block_given_p()) {
05697 under_gid_switch = 1;
05698 return rb_ensure(rb_yield, Qnil, p_gid_sw_ensure, obj);
05699 } else {
05700 return GIDT2NUM(egid);
05701 }
05702 }
05703 #endif
05704
05705
05706 #if defined(HAVE_TIMES)
05707
05708
05709
05710
05711
05712
05713
05714
05715
05716
05717
05718
05719 VALUE
05720 rb_proc_times(VALUE obj)
05721 {
05722 const double hertz =
05723 #ifdef HAVE__SC_CLK_TCK
05724 (double)sysconf(_SC_CLK_TCK);
05725 #else
05726 #ifndef HZ
05727 # ifdef CLK_TCK
05728 # define HZ CLK_TCK
05729 # else
05730 # define HZ 60
05731 # endif
05732 #endif
05733 HZ;
05734 #endif
05735 struct tms buf;
05736 volatile VALUE utime, stime, cutime, sctime;
05737
05738 times(&buf);
05739 return rb_struct_new(rb_cProcessTms,
05740 utime = DBL2NUM(buf.tms_utime / hertz),
05741 stime = DBL2NUM(buf.tms_stime / hertz),
05742 cutime = DBL2NUM(buf.tms_cutime / hertz),
05743 sctime = DBL2NUM(buf.tms_cstime / hertz));
05744 }
05745 #else
05746 #define rb_proc_times rb_f_notimplement
05747 #endif
05748
05749 VALUE rb_mProcess;
05750 VALUE rb_mProcUID;
05751 VALUE rb_mProcGID;
05752 VALUE rb_mProcID_Syscall;
05753
05754
05755
05756
05757
05758
05759
05760 void
05761 Init_process(void)
05762 {
05763 rb_define_virtual_variable("$?", rb_last_status_get, 0);
05764 rb_define_virtual_variable("$$", get_pid, 0);
05765 rb_define_global_function("exec", rb_f_exec, -1);
05766 rb_define_global_function("fork", rb_f_fork, 0);
05767 rb_define_global_function("exit!", rb_f_exit_bang, -1);
05768 rb_define_global_function("system", rb_f_system, -1);
05769 rb_define_global_function("spawn", rb_f_spawn, -1);
05770 rb_define_global_function("sleep", rb_f_sleep, -1);
05771 rb_define_global_function("exit", rb_f_exit, -1);
05772 rb_define_global_function("abort", rb_f_abort, -1);
05773
05774 rb_mProcess = rb_define_module("Process");
05775
05776 #ifdef WNOHANG
05777
05778 rb_define_const(rb_mProcess, "WNOHANG", INT2FIX(WNOHANG));
05779 #else
05780
05781 rb_define_const(rb_mProcess, "WNOHANG", INT2FIX(0));
05782 #endif
05783 #ifdef WUNTRACED
05784
05785 rb_define_const(rb_mProcess, "WUNTRACED", INT2FIX(WUNTRACED));
05786 #else
05787
05788 rb_define_const(rb_mProcess, "WUNTRACED", INT2FIX(0));
05789 #endif
05790
05791 rb_define_singleton_method(rb_mProcess, "exec", rb_f_exec, -1);
05792 rb_define_singleton_method(rb_mProcess, "fork", rb_f_fork, 0);
05793 rb_define_singleton_method(rb_mProcess, "spawn", rb_f_spawn, -1);
05794 rb_define_singleton_method(rb_mProcess, "exit!", rb_f_exit_bang, -1);
05795 rb_define_singleton_method(rb_mProcess, "exit", rb_f_exit, -1);
05796 rb_define_singleton_method(rb_mProcess, "abort", rb_f_abort, -1);
05797
05798 rb_define_module_function(rb_mProcess, "kill", rb_f_kill, -1);
05799 rb_define_module_function(rb_mProcess, "wait", proc_wait, -1);
05800 rb_define_module_function(rb_mProcess, "wait2", proc_wait2, -1);
05801 rb_define_module_function(rb_mProcess, "waitpid", proc_wait, -1);
05802 rb_define_module_function(rb_mProcess, "waitpid2", proc_wait2, -1);
05803 rb_define_module_function(rb_mProcess, "waitall", proc_waitall, 0);
05804 rb_define_module_function(rb_mProcess, "detach", proc_detach, 1);
05805
05806 rb_cProcessStatus = rb_define_class_under(rb_mProcess, "Status", rb_cObject);
05807 rb_undef_method(CLASS_OF(rb_cProcessStatus), "new");
05808
05809 rb_define_method(rb_cProcessStatus, "==", pst_equal, 1);
05810 rb_define_method(rb_cProcessStatus, "&", pst_bitand, 1);
05811 rb_define_method(rb_cProcessStatus, ">>", pst_rshift, 1);
05812 rb_define_method(rb_cProcessStatus, "to_i", pst_to_i, 0);
05813 rb_define_method(rb_cProcessStatus, "to_s", pst_to_s, 0);
05814 rb_define_method(rb_cProcessStatus, "inspect", pst_inspect, 0);
05815
05816 rb_define_method(rb_cProcessStatus, "pid", pst_pid, 0);
05817
05818 rb_define_method(rb_cProcessStatus, "stopped?", pst_wifstopped, 0);
05819 rb_define_method(rb_cProcessStatus, "stopsig", pst_wstopsig, 0);
05820 rb_define_method(rb_cProcessStatus, "signaled?", pst_wifsignaled, 0);
05821 rb_define_method(rb_cProcessStatus, "termsig", pst_wtermsig, 0);
05822 rb_define_method(rb_cProcessStatus, "exited?", pst_wifexited, 0);
05823 rb_define_method(rb_cProcessStatus, "exitstatus", pst_wexitstatus, 0);
05824 rb_define_method(rb_cProcessStatus, "success?", pst_success_p, 0);
05825 rb_define_method(rb_cProcessStatus, "coredump?", pst_wcoredump, 0);
05826
05827 rb_define_module_function(rb_mProcess, "pid", get_pid, 0);
05828 rb_define_module_function(rb_mProcess, "ppid", get_ppid, 0);
05829
05830 rb_define_module_function(rb_mProcess, "getpgrp", proc_getpgrp, 0);
05831 rb_define_module_function(rb_mProcess, "setpgrp", proc_setpgrp, 0);
05832 rb_define_module_function(rb_mProcess, "getpgid", proc_getpgid, 1);
05833 rb_define_module_function(rb_mProcess, "setpgid", proc_setpgid, 2);
05834
05835 rb_define_module_function(rb_mProcess, "setsid", proc_setsid, 0);
05836
05837 rb_define_module_function(rb_mProcess, "getpriority", proc_getpriority, 2);
05838 rb_define_module_function(rb_mProcess, "setpriority", proc_setpriority, 3);
05839
05840 #ifdef HAVE_GETPRIORITY
05841
05842 rb_define_const(rb_mProcess, "PRIO_PROCESS", INT2FIX(PRIO_PROCESS));
05843
05844 rb_define_const(rb_mProcess, "PRIO_PGRP", INT2FIX(PRIO_PGRP));
05845
05846 rb_define_const(rb_mProcess, "PRIO_USER", INT2FIX(PRIO_USER));
05847 #endif
05848
05849 rb_define_module_function(rb_mProcess, "getrlimit", proc_getrlimit, 1);
05850 rb_define_module_function(rb_mProcess, "setrlimit", proc_setrlimit, -1);
05851 #if defined(RLIM2NUM) && defined(RLIM_INFINITY)
05852 {
05853 VALUE inf = RLIM2NUM(RLIM_INFINITY);
05854 #ifdef RLIM_SAVED_MAX
05855 {
05856 VALUE v = RLIM_INFINITY == RLIM_SAVED_MAX ? inf : RLIM2NUM(RLIM_SAVED_MAX);
05857
05858 rb_define_const(rb_mProcess, "RLIM_SAVED_MAX", v);
05859 }
05860 #endif
05861
05862 rb_define_const(rb_mProcess, "RLIM_INFINITY", inf);
05863 #ifdef RLIM_SAVED_CUR
05864 {
05865 VALUE v = RLIM_INFINITY == RLIM_SAVED_CUR ? inf : RLIM2NUM(RLIM_SAVED_CUR);
05866
05867 rb_define_const(rb_mProcess, "RLIM_SAVED_CUR", v);
05868 }
05869 #endif
05870 }
05871 #ifdef RLIMIT_AS
05872
05873
05874
05875
05876 rb_define_const(rb_mProcess, "RLIMIT_AS", INT2FIX(RLIMIT_AS));
05877 #endif
05878 #ifdef RLIMIT_CORE
05879
05880
05881
05882
05883 rb_define_const(rb_mProcess, "RLIMIT_CORE", INT2FIX(RLIMIT_CORE));
05884 #endif
05885 #ifdef RLIMIT_CPU
05886
05887
05888
05889
05890 rb_define_const(rb_mProcess, "RLIMIT_CPU", INT2FIX(RLIMIT_CPU));
05891 #endif
05892 #ifdef RLIMIT_DATA
05893
05894
05895
05896
05897 rb_define_const(rb_mProcess, "RLIMIT_DATA", INT2FIX(RLIMIT_DATA));
05898 #endif
05899 #ifdef RLIMIT_FSIZE
05900
05901
05902
05903
05904 rb_define_const(rb_mProcess, "RLIMIT_FSIZE", INT2FIX(RLIMIT_FSIZE));
05905 #endif
05906 #ifdef RLIMIT_MEMLOCK
05907
05908
05909
05910
05911 rb_define_const(rb_mProcess, "RLIMIT_MEMLOCK", INT2FIX(RLIMIT_MEMLOCK));
05912 #endif
05913 #ifdef RLIMIT_MSGQUEUE
05914
05915
05916
05917
05918
05919 rb_define_const(rb_mProcess, "RLIMIT_MSGQUEUE", INT2FIX(RLIMIT_MSGQUEUE));
05920 #endif
05921 #ifdef RLIMIT_NICE
05922
05923
05924
05925
05926 rb_define_const(rb_mProcess, "RLIMIT_NICE", INT2FIX(RLIMIT_NICE));
05927 #endif
05928 #ifdef RLIMIT_NOFILE
05929
05930
05931
05932
05933
05934 rb_define_const(rb_mProcess, "RLIMIT_NOFILE", INT2FIX(RLIMIT_NOFILE));
05935 #endif
05936 #ifdef RLIMIT_NPROC
05937
05938
05939
05940
05941
05942 rb_define_const(rb_mProcess, "RLIMIT_NPROC", INT2FIX(RLIMIT_NPROC));
05943 #endif
05944 #ifdef RLIMIT_RSS
05945
05946
05947
05948
05949 rb_define_const(rb_mProcess, "RLIMIT_RSS", INT2FIX(RLIMIT_RSS));
05950 #endif
05951 #ifdef RLIMIT_RTPRIO
05952
05953
05954
05955
05956 rb_define_const(rb_mProcess, "RLIMIT_RTPRIO", INT2FIX(RLIMIT_RTPRIO));
05957 #endif
05958 #ifdef RLIMIT_RTTIME
05959
05960
05961
05962
05963
05964 rb_define_const(rb_mProcess, "RLIMIT_RTTIME", INT2FIX(RLIMIT_RTTIME));
05965 #endif
05966 #ifdef RLIMIT_SBSIZE
05967
05968
05969 rb_define_const(rb_mProcess, "RLIMIT_SBSIZE", INT2FIX(RLIMIT_SBSIZE));
05970 #endif
05971 #ifdef RLIMIT_SIGPENDING
05972
05973
05974
05975
05976
05977 rb_define_const(rb_mProcess, "RLIMIT_SIGPENDING", INT2FIX(RLIMIT_SIGPENDING));
05978 #endif
05979 #ifdef RLIMIT_STACK
05980
05981
05982
05983
05984 rb_define_const(rb_mProcess, "RLIMIT_STACK", INT2FIX(RLIMIT_STACK));
05985 #endif
05986 #endif
05987
05988 rb_define_module_function(rb_mProcess, "uid", proc_getuid, 0);
05989 rb_define_module_function(rb_mProcess, "uid=", proc_setuid, 1);
05990 rb_define_module_function(rb_mProcess, "gid", proc_getgid, 0);
05991 rb_define_module_function(rb_mProcess, "gid=", proc_setgid, 1);
05992 rb_define_module_function(rb_mProcess, "euid", proc_geteuid, 0);
05993 rb_define_module_function(rb_mProcess, "euid=", proc_seteuid_m, 1);
05994 rb_define_module_function(rb_mProcess, "egid", proc_getegid, 0);
05995 rb_define_module_function(rb_mProcess, "egid=", proc_setegid_m, 1);
05996 rb_define_module_function(rb_mProcess, "initgroups", proc_initgroups, 2);
05997 rb_define_module_function(rb_mProcess, "groups", proc_getgroups, 0);
05998 rb_define_module_function(rb_mProcess, "groups=", proc_setgroups, 1);
05999 rb_define_module_function(rb_mProcess, "maxgroups", proc_getmaxgroups, 0);
06000 rb_define_module_function(rb_mProcess, "maxgroups=", proc_setmaxgroups, 1);
06001
06002 rb_define_module_function(rb_mProcess, "daemon", proc_daemon, -1);
06003
06004 rb_define_module_function(rb_mProcess, "times", rb_proc_times, 0);
06005
06006 #if defined(HAVE_TIMES) || defined(_WIN32)
06007 rb_cProcessTms = rb_struct_define("Tms", "utime", "stime", "cutime", "cstime", NULL);
06008 #endif
06009
06010 SAVED_USER_ID = geteuid();
06011 SAVED_GROUP_ID = getegid();
06012
06013 rb_mProcUID = rb_define_module_under(rb_mProcess, "UID");
06014 rb_mProcGID = rb_define_module_under(rb_mProcess, "GID");
06015
06016 rb_define_module_function(rb_mProcUID, "rid", proc_getuid, 0);
06017 rb_define_module_function(rb_mProcGID, "rid", proc_getgid, 0);
06018 rb_define_module_function(rb_mProcUID, "eid", proc_geteuid, 0);
06019 rb_define_module_function(rb_mProcGID, "eid", proc_getegid, 0);
06020 rb_define_module_function(rb_mProcUID, "change_privilege", p_uid_change_privilege, 1);
06021 rb_define_module_function(rb_mProcGID, "change_privilege", p_gid_change_privilege, 1);
06022 rb_define_module_function(rb_mProcUID, "grant_privilege", p_uid_grant_privilege, 1);
06023 rb_define_module_function(rb_mProcGID, "grant_privilege", p_gid_grant_privilege, 1);
06024 rb_define_alias(rb_singleton_class(rb_mProcUID), "eid=", "grant_privilege");
06025 rb_define_alias(rb_singleton_class(rb_mProcGID), "eid=", "grant_privilege");
06026 rb_define_module_function(rb_mProcUID, "re_exchange", p_uid_exchange, 0);
06027 rb_define_module_function(rb_mProcGID, "re_exchange", p_gid_exchange, 0);
06028 rb_define_module_function(rb_mProcUID, "re_exchangeable?", p_uid_exchangeable, 0);
06029 rb_define_module_function(rb_mProcGID, "re_exchangeable?", p_gid_exchangeable, 0);
06030 rb_define_module_function(rb_mProcUID, "sid_available?", p_uid_have_saved_id, 0);
06031 rb_define_module_function(rb_mProcGID, "sid_available?", p_gid_have_saved_id, 0);
06032 rb_define_module_function(rb_mProcUID, "switch", p_uid_switch, 0);
06033 rb_define_module_function(rb_mProcGID, "switch", p_gid_switch, 0);
06034
06035 rb_mProcID_Syscall = rb_define_module_under(rb_mProcess, "Sys");
06036
06037 rb_define_module_function(rb_mProcID_Syscall, "getuid", proc_getuid, 0);
06038 rb_define_module_function(rb_mProcID_Syscall, "geteuid", proc_geteuid, 0);
06039 rb_define_module_function(rb_mProcID_Syscall, "getgid", proc_getgid, 0);
06040 rb_define_module_function(rb_mProcID_Syscall, "getegid", proc_getegid, 0);
06041
06042 rb_define_module_function(rb_mProcID_Syscall, "setuid", p_sys_setuid, 1);
06043 rb_define_module_function(rb_mProcID_Syscall, "setgid", p_sys_setgid, 1);
06044
06045 rb_define_module_function(rb_mProcID_Syscall, "setruid", p_sys_setruid, 1);
06046 rb_define_module_function(rb_mProcID_Syscall, "setrgid", p_sys_setrgid, 1);
06047
06048 rb_define_module_function(rb_mProcID_Syscall, "seteuid", p_sys_seteuid, 1);
06049 rb_define_module_function(rb_mProcID_Syscall, "setegid", p_sys_setegid, 1);
06050
06051 rb_define_module_function(rb_mProcID_Syscall, "setreuid", p_sys_setreuid, 2);
06052 rb_define_module_function(rb_mProcID_Syscall, "setregid", p_sys_setregid, 2);
06053
06054 rb_define_module_function(rb_mProcID_Syscall, "setresuid", p_sys_setresuid, 3);
06055 rb_define_module_function(rb_mProcID_Syscall, "setresgid", p_sys_setresgid, 3);
06056 rb_define_module_function(rb_mProcID_Syscall, "issetugid", p_sys_issetugid, 0);
06057 }
06058