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