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