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 eargp->chdir_given = 1;
01757 eargp->chdir_dir = hide_obj(EXPORT_DUP(val));
01758 }
01759 else if (id == rb_intern("umask")) {
01760 mode_t cmask = NUM2MODET(val);
01761 if (eargp->umask_given) {
01762 rb_raise(rb_eArgError, "umask option specified twice");
01763 }
01764 eargp->umask_given = 1;
01765 eargp->umask_mask = cmask;
01766 }
01767 else if (id == rb_intern("close_others")) {
01768 if (eargp->close_others_given) {
01769 rb_raise(rb_eArgError, "close_others option specified twice");
01770 }
01771 eargp->close_others_given = 1;
01772 eargp->close_others_do = RTEST(val) ? 1 : 0;
01773 }
01774 else if (id == rb_intern("in")) {
01775 key = INT2FIX(0);
01776 goto redirect;
01777 }
01778 else if (id == rb_intern("out")) {
01779 key = INT2FIX(1);
01780 goto redirect;
01781 }
01782 else if (id == rb_intern("err")) {
01783 key = INT2FIX(2);
01784 goto redirect;
01785 }
01786 else if (id == rb_intern("uid")) {
01787 #ifdef HAVE_SETUID
01788 if (eargp->uid_given) {
01789 rb_raise(rb_eArgError, "uid option specified twice");
01790 }
01791 check_uid_switch();
01792 {
01793 eargp->uid = OBJ2UID(val);
01794 eargp->uid_given = 1;
01795 }
01796 #else
01797 rb_raise(rb_eNotImpError,
01798 "uid option is unimplemented on this machine");
01799 #endif
01800 }
01801 else if (id == rb_intern("gid")) {
01802 #ifdef HAVE_SETGID
01803 if (eargp->gid_given) {
01804 rb_raise(rb_eArgError, "gid option specified twice");
01805 }
01806 check_gid_switch();
01807 {
01808 eargp->gid = OBJ2GID(val);
01809 eargp->gid_given = 1;
01810 }
01811 #else
01812 rb_raise(rb_eNotImpError,
01813 "gid option is unimplemented on this machine");
01814 #endif
01815 }
01816 else {
01817 return ST_STOP;
01818 }
01819 break;
01820
01821 case T_FIXNUM:
01822 case T_FILE:
01823 case T_ARRAY:
01824 redirect:
01825 check_exec_redirect(key, val, eargp);
01826 break;
01827
01828 default:
01829 return ST_STOP;
01830 }
01831
01832 RB_GC_GUARD(execarg_obj);
01833 return ST_CONTINUE;
01834 }
01835
01836 int
01837 rb_exec_arg_addopt(struct rb_exec_arg *e, VALUE key, VALUE val)
01838 {
01839 return rb_execarg_addopt(e->execarg_obj, key, val);
01840 }
01841
01842 static int
01843 check_exec_options_i(st_data_t st_key, st_data_t st_val, st_data_t arg)
01844 {
01845 VALUE key = (VALUE)st_key;
01846 VALUE val = (VALUE)st_val;
01847 VALUE execarg_obj = (VALUE)arg;
01848 if (rb_execarg_addopt(execarg_obj, key, val) != ST_CONTINUE) {
01849 if (SYMBOL_P(key))
01850 rb_raise(rb_eArgError, "wrong exec option symbol: %"PRIsVALUE,
01851 key);
01852 rb_raise(rb_eArgError, "wrong exec option");
01853 }
01854 return ST_CONTINUE;
01855 }
01856
01857 static int
01858 check_exec_options_i_extract(st_data_t st_key, st_data_t st_val, st_data_t arg)
01859 {
01860 VALUE key = (VALUE)st_key;
01861 VALUE val = (VALUE)st_val;
01862 VALUE *args = (VALUE *)arg;
01863 VALUE execarg_obj = args[0];
01864 if (rb_execarg_addopt(execarg_obj, key, val) != ST_CONTINUE) {
01865 VALUE nonopts = args[1];
01866 if (NIL_P(nonopts)) args[1] = nonopts = rb_hash_new();
01867 rb_hash_aset(nonopts, key, val);
01868 }
01869 return ST_CONTINUE;
01870 }
01871
01872 static int
01873 check_exec_fds_1(struct rb_execarg *eargp, VALUE h, int maxhint, VALUE ary)
01874 {
01875 long i;
01876
01877 if (ary != Qfalse) {
01878 for (i = 0; i < RARRAY_LEN(ary); i++) {
01879 VALUE elt = RARRAY_AREF(ary, i);
01880 int fd = FIX2INT(RARRAY_AREF(elt, 0));
01881 if (RTEST(rb_hash_lookup(h, INT2FIX(fd)))) {
01882 rb_raise(rb_eArgError, "fd %d specified twice", fd);
01883 }
01884 if (ary == eargp->fd_open || ary == eargp->fd_dup2)
01885 rb_hash_aset(h, INT2FIX(fd), Qtrue);
01886 else if (ary == eargp->fd_dup2_child)
01887 rb_hash_aset(h, INT2FIX(fd), RARRAY_AREF(elt, 1));
01888 else
01889 rb_hash_aset(h, INT2FIX(fd), INT2FIX(-1));
01890 if (maxhint < fd)
01891 maxhint = fd;
01892 if (ary == eargp->fd_dup2 || ary == eargp->fd_dup2_child) {
01893 fd = FIX2INT(RARRAY_AREF(elt, 1));
01894 if (maxhint < fd)
01895 maxhint = fd;
01896 }
01897 }
01898 }
01899 return maxhint;
01900 }
01901
01902 static VALUE
01903 check_exec_fds(struct rb_execarg *eargp)
01904 {
01905 VALUE h = rb_hash_new();
01906 VALUE ary;
01907 int maxhint = -1;
01908 long i;
01909
01910 maxhint = check_exec_fds_1(eargp, h, maxhint, eargp->fd_dup2);
01911 maxhint = check_exec_fds_1(eargp, h, maxhint, eargp->fd_close);
01912 maxhint = check_exec_fds_1(eargp, h, maxhint, eargp->fd_open);
01913 maxhint = check_exec_fds_1(eargp, h, maxhint, eargp->fd_dup2_child);
01914
01915 if (eargp->fd_dup2_child) {
01916 ary = eargp->fd_dup2_child;
01917 for (i = 0; i < RARRAY_LEN(ary); i++) {
01918 VALUE elt = RARRAY_AREF(ary, i);
01919 int newfd = FIX2INT(RARRAY_AREF(elt, 0));
01920 int oldfd = FIX2INT(RARRAY_AREF(elt, 1));
01921 int lastfd = oldfd;
01922 VALUE val = rb_hash_lookup(h, INT2FIX(lastfd));
01923 long depth = 0;
01924 while (FIXNUM_P(val) && 0 <= FIX2INT(val)) {
01925 lastfd = FIX2INT(val);
01926 val = rb_hash_lookup(h, val);
01927 if (RARRAY_LEN(ary) < depth)
01928 rb_raise(rb_eArgError, "cyclic child fd redirection from %d", oldfd);
01929 depth++;
01930 }
01931 if (val != Qtrue)
01932 rb_raise(rb_eArgError, "child fd %d is not redirected", oldfd);
01933 if (oldfd != lastfd) {
01934 VALUE val2;
01935 rb_ary_store(elt, 1, INT2FIX(lastfd));
01936 rb_hash_aset(h, INT2FIX(newfd), INT2FIX(lastfd));
01937 val = INT2FIX(oldfd);
01938 while (FIXNUM_P(val2 = rb_hash_lookup(h, val))) {
01939 rb_hash_aset(h, val, INT2FIX(lastfd));
01940 val = val2;
01941 }
01942 }
01943 }
01944 }
01945
01946 eargp->close_others_maxhint = maxhint;
01947 return h;
01948 }
01949
01950 static void
01951 rb_check_exec_options(VALUE opthash, VALUE execarg_obj)
01952 {
01953 if (RHASH_EMPTY_P(opthash))
01954 return;
01955 st_foreach(rb_hash_tbl_raw(opthash), check_exec_options_i, (st_data_t)execarg_obj);
01956 }
01957
01958 VALUE
01959 rb_execarg_extract_options(VALUE execarg_obj, VALUE opthash)
01960 {
01961 VALUE args[2];
01962 if (RHASH_EMPTY_P(opthash))
01963 return Qnil;
01964 args[0] = execarg_obj;
01965 args[1] = Qnil;
01966 st_foreach(rb_hash_tbl_raw(opthash), check_exec_options_i_extract, (st_data_t)args);
01967 return args[1];
01968 }
01969
01970 static int
01971 check_exec_env_i(st_data_t st_key, st_data_t st_val, st_data_t arg)
01972 {
01973 VALUE key = (VALUE)st_key;
01974 VALUE val = (VALUE)st_val;
01975 VALUE env = (VALUE)arg;
01976 char *k;
01977
01978 k = StringValueCStr(key);
01979 if (strchr(k, '='))
01980 rb_raise(rb_eArgError, "environment name contains a equal : %s", k);
01981
01982 if (!NIL_P(val))
01983 StringValueCStr(val);
01984
01985 key = EXPORT_STR(key);
01986 if (!NIL_P(val)) val = EXPORT_STR(val);
01987
01988 rb_ary_push(env, hide_obj(rb_assoc_new(key, val)));
01989
01990 return ST_CONTINUE;
01991 }
01992
01993 static VALUE
01994 rb_check_exec_env(VALUE hash)
01995 {
01996 VALUE env;
01997
01998 env = hide_obj(rb_ary_new());
01999 st_foreach(rb_hash_tbl_raw(hash), check_exec_env_i, (st_data_t)env);
02000
02001 return env;
02002 }
02003
02004 static VALUE
02005 rb_check_argv(int argc, VALUE *argv)
02006 {
02007 VALUE tmp, prog;
02008 int i;
02009 const char *name = 0;
02010
02011 rb_check_arity(argc, 1, UNLIMITED_ARGUMENTS);
02012
02013 prog = 0;
02014 tmp = rb_check_array_type(argv[0]);
02015 if (!NIL_P(tmp)) {
02016 if (RARRAY_LEN(tmp) != 2) {
02017 rb_raise(rb_eArgError, "wrong first argument");
02018 }
02019 prog = RARRAY_AREF(tmp, 0);
02020 argv[0] = RARRAY_AREF(tmp, 1);
02021 SafeStringValue(prog);
02022 StringValueCStr(prog);
02023 prog = rb_str_new_frozen(prog);
02024 name = RSTRING_PTR(prog);
02025 }
02026 for (i = 0; i < argc; i++) {
02027 SafeStringValue(argv[i]);
02028 argv[i] = rb_str_new_frozen(argv[i]);
02029 StringValueCStr(argv[i]);
02030 }
02031 security(name ? name : RSTRING_PTR(argv[0]));
02032 return prog;
02033 }
02034
02035 static VALUE
02036 rb_exec_getargs(int *argc_p, VALUE **argv_p, int accept_shell, VALUE *env_ret, VALUE *opthash_ret)
02037 {
02038 VALUE hash, prog;
02039
02040 if (0 < *argc_p) {
02041 hash = rb_check_hash_type((*argv_p)[*argc_p-1]);
02042 if (!NIL_P(hash)) {
02043 *opthash_ret = hash;
02044 (*argc_p)--;
02045 }
02046 }
02047
02048 if (0 < *argc_p) {
02049 hash = rb_check_hash_type((*argv_p)[0]);
02050 if (!NIL_P(hash)) {
02051 *env_ret = hash;
02052 (*argc_p)--;
02053 (*argv_p)++;
02054 }
02055 }
02056 prog = rb_check_argv(*argc_p, *argv_p);
02057 if (!prog) {
02058 prog = (*argv_p)[0];
02059 if (accept_shell && *argc_p == 1) {
02060 *argc_p = 0;
02061 *argv_p = 0;
02062 }
02063 }
02064 return prog;
02065 }
02066
02067 #ifndef _WIN32
02068 struct string_part {
02069 const char *ptr;
02070 size_t len;
02071 };
02072
02073 static int
02074 compare_posix_sh(const void *key, const void *el)
02075 {
02076 const struct string_part *word = key;
02077 int ret = strncmp(word->ptr, el, word->len);
02078 if (!ret && ((const char *)el)[word->len]) ret = -1;
02079 return ret;
02080 }
02081 #endif
02082
02083 static void
02084 rb_exec_fillarg(VALUE prog, int argc, VALUE *argv, VALUE env, VALUE opthash, VALUE execarg_obj)
02085 {
02086 struct rb_execarg *eargp = rb_execarg_get(execarg_obj);
02087 char fbuf[MAXPATHLEN];
02088
02089 MEMZERO(eargp, struct rb_execarg, 1);
02090
02091 if (!NIL_P(opthash)) {
02092 rb_check_exec_options(opthash, execarg_obj);
02093 }
02094 if (!NIL_P(env)) {
02095 env = rb_check_exec_env(env);
02096 eargp->env_modification = env;
02097 }
02098
02099 prog = EXPORT_STR(prog);
02100 eargp->use_shell = argc == 0;
02101 if (eargp->use_shell)
02102 eargp->invoke.sh.shell_script = prog;
02103 else
02104 eargp->invoke.cmd.command_name = prog;
02105
02106 #ifndef _WIN32
02107 if (eargp->use_shell) {
02108 static const char posix_sh_cmds[][9] = {
02109 "!",
02110 ".",
02111 ":",
02112 "break",
02113 "case",
02114 "continue",
02115 "do",
02116 "done",
02117 "elif",
02118 "else",
02119 "esac",
02120 "eval",
02121 "exec",
02122 "exit",
02123 "export",
02124 "fi",
02125 "for",
02126 "if",
02127 "in",
02128 "readonly",
02129 "return",
02130 "set",
02131 "shift",
02132 "then",
02133 "times",
02134 "trap",
02135 "unset",
02136 "until",
02137 "while",
02138 };
02139 const char *p;
02140 struct string_part first = {0, 0};
02141 int has_meta = 0;
02142
02143
02144
02145
02146
02147
02148
02149
02150
02151
02152
02153
02154
02155
02156
02157
02158
02159
02160
02161
02162
02163
02164
02165
02166 for (p = RSTRING_PTR(prog); *p; p++) {
02167 if (*p == ' ' || *p == '\t') {
02168 if (first.ptr && !first.len) first.len = p - first.ptr;
02169 }
02170 else {
02171 if (!first.ptr) first.ptr = p;
02172 }
02173 if (!has_meta && strchr("*?{}[]<>()~&|\\$;'`\"\n#", *p))
02174 has_meta = 1;
02175 if (!first.len) {
02176 if (*p == '=') {
02177 has_meta = 1;
02178 }
02179 else if (*p == '/') {
02180 first.len = 0x100;
02181 }
02182 }
02183 if (has_meta)
02184 break;
02185 }
02186 if (!has_meta && first.ptr) {
02187 if (!first.len) first.len = p - first.ptr;
02188 if (first.len > 0 && first.len <= sizeof(posix_sh_cmds[0]) &&
02189 bsearch(&first, posix_sh_cmds, numberof(posix_sh_cmds), sizeof(posix_sh_cmds[0]), compare_posix_sh))
02190 has_meta = 1;
02191 }
02192 if (!has_meta) {
02193
02194 eargp->use_shell = 0;
02195 }
02196 if (!eargp->use_shell) {
02197 VALUE argv_buf;
02198 argv_buf = hide_obj(rb_str_buf_new(0));
02199 p = RSTRING_PTR(prog);
02200 while (*p) {
02201 while (*p == ' ' || *p == '\t')
02202 p++;
02203 if (*p) {
02204 const char *w = p;
02205 while (*p && *p != ' ' && *p != '\t')
02206 p++;
02207 rb_str_buf_cat(argv_buf, w, p-w);
02208 rb_str_buf_cat(argv_buf, "", 1);
02209 }
02210 }
02211 eargp->invoke.cmd.argv_buf = argv_buf;
02212 eargp->invoke.cmd.command_name = hide_obj(rb_str_new_cstr(RSTRING_PTR(argv_buf)));
02213 }
02214 }
02215 #endif
02216
02217 if (!eargp->use_shell) {
02218 const char *abspath;
02219 abspath = dln_find_exe_r(RSTRING_PTR(eargp->invoke.cmd.command_name), 0, fbuf, sizeof(fbuf));
02220 if (abspath)
02221 eargp->invoke.cmd.command_abspath = rb_str_new_cstr(abspath);
02222 else
02223 eargp->invoke.cmd.command_abspath = Qnil;
02224 }
02225
02226 if (!eargp->use_shell && !eargp->invoke.cmd.argv_buf) {
02227 int i;
02228 VALUE argv_buf;
02229 argv_buf = rb_str_buf_new(0);
02230 hide_obj(argv_buf);
02231 for (i = 0; i < argc; i++) {
02232 VALUE arg = argv[i];
02233 const char *s = StringValueCStr(arg);
02234 #ifdef DEFAULT_PROCESS_ENCODING
02235 arg = EXPORT_STR(arg);
02236 s = RSTRING_PTR(arg);
02237 #endif
02238 rb_str_buf_cat(argv_buf, s, RSTRING_LEN(arg) + 1);
02239 }
02240 eargp->invoke.cmd.argv_buf = argv_buf;
02241 }
02242
02243 if (!eargp->use_shell) {
02244 const char *p, *ep, *null=NULL;
02245 VALUE argv_str;
02246 argv_str = hide_obj(rb_str_buf_new(sizeof(char*) * (argc + 2)));
02247 rb_str_buf_cat(argv_str, (char *)&null, sizeof(null));
02248 p = RSTRING_PTR(eargp->invoke.cmd.argv_buf);
02249 ep = p + RSTRING_LEN(eargp->invoke.cmd.argv_buf);
02250 while (p < ep) {
02251 rb_str_buf_cat(argv_str, (char *)&p, sizeof(p));
02252 p += strlen(p) + 1;
02253 }
02254 rb_str_buf_cat(argv_str, (char *)&null, sizeof(null));
02255 eargp->invoke.cmd.argv_str = argv_str;
02256 }
02257 RB_GC_GUARD(execarg_obj);
02258 }
02259
02260 VALUE
02261 rb_execarg_new(int argc, VALUE *argv, int accept_shell)
02262 {
02263 VALUE execarg_obj;
02264 struct rb_execarg *eargp;
02265 execarg_obj = TypedData_Make_Struct(rb_cData, struct rb_execarg, &exec_arg_data_type, eargp);
02266 hide_obj(execarg_obj);
02267 rb_execarg_init(argc, argv, accept_shell, execarg_obj);
02268 return execarg_obj;
02269 }
02270
02271 struct rb_execarg *
02272 rb_execarg_get(VALUE execarg_obj)
02273 {
02274 struct rb_execarg *eargp;
02275 TypedData_Get_Struct(execarg_obj, struct rb_execarg, &exec_arg_data_type, eargp);
02276 return eargp;
02277 }
02278
02279 VALUE
02280 rb_execarg_init(int argc, VALUE *argv, int accept_shell, VALUE execarg_obj)
02281 {
02282 struct rb_execarg *eargp = rb_execarg_get(execarg_obj);
02283 VALUE prog, ret;
02284 VALUE env = Qnil, opthash = Qnil;
02285 prog = rb_exec_getargs(&argc, &argv, accept_shell, &env, &opthash);
02286 rb_exec_fillarg(prog, argc, argv, env, opthash, execarg_obj);
02287 ret = eargp->use_shell ? eargp->invoke.sh.shell_script : eargp->invoke.cmd.command_name;
02288 RB_GC_GUARD(execarg_obj);
02289 return ret;
02290 }
02291
02292 VALUE
02293 rb_exec_arg_init(int argc, VALUE *argv, int accept_shell, struct rb_exec_arg *e)
02294 {
02295 return rb_execarg_init(argc, argv, accept_shell, e->execarg_obj);
02296 }
02297
02298 void
02299 rb_execarg_setenv(VALUE execarg_obj, VALUE env)
02300 {
02301 struct rb_execarg *eargp = rb_execarg_get(execarg_obj);
02302 env = !NIL_P(env) ? rb_check_exec_env(env) : Qfalse;
02303 eargp->env_modification = env;
02304 }
02305
02306 static int
02307 fill_envp_buf_i(st_data_t st_key, st_data_t st_val, st_data_t arg)
02308 {
02309 VALUE key = (VALUE)st_key;
02310 VALUE val = (VALUE)st_val;
02311 VALUE envp_buf = (VALUE)arg;
02312
02313 rb_str_buf_cat2(envp_buf, StringValueCStr(key));
02314 rb_str_buf_cat2(envp_buf, "=");
02315 rb_str_buf_cat2(envp_buf, StringValueCStr(val));
02316 rb_str_buf_cat(envp_buf, "", 1);
02317
02318 return ST_CONTINUE;
02319 }
02320
02321
02322 static long run_exec_dup2_tmpbuf_size(long n);
02323
02324 void
02325 rb_execarg_fixup(VALUE execarg_obj)
02326 {
02327 struct rb_execarg *eargp = rb_execarg_get(execarg_obj);
02328 int unsetenv_others;
02329 VALUE envopts;
02330 VALUE ary;
02331
02332 eargp->redirect_fds = check_exec_fds(eargp);
02333
02334 ary = eargp->fd_dup2;
02335 if (ary != Qfalse) {
02336 size_t len = run_exec_dup2_tmpbuf_size(RARRAY_LEN(ary));
02337 VALUE tmpbuf = hide_obj(rb_str_new(0, len));
02338 rb_str_set_len(tmpbuf, len);
02339 eargp->dup2_tmpbuf = tmpbuf;
02340 }
02341
02342 unsetenv_others = eargp->unsetenv_others_given && eargp->unsetenv_others_do;
02343 envopts = eargp->env_modification;
02344 if (unsetenv_others || envopts != Qfalse) {
02345 VALUE envtbl, envp_str, envp_buf;
02346 char *p, *ep;
02347 if (unsetenv_others) {
02348 envtbl = rb_hash_new();
02349 }
02350 else {
02351 envtbl = rb_const_get(rb_cObject, rb_intern("ENV"));
02352 envtbl = rb_convert_type(envtbl, T_HASH, "Hash", "to_hash");
02353 }
02354 hide_obj(envtbl);
02355 if (envopts != Qfalse) {
02356 st_table *stenv = RHASH_TBL_RAW(envtbl);
02357 long i;
02358 for (i = 0; i < RARRAY_LEN(envopts); i++) {
02359 VALUE pair = RARRAY_AREF(envopts, i);
02360 VALUE key = RARRAY_AREF(pair, 0);
02361 VALUE val = RARRAY_AREF(pair, 1);
02362 if (NIL_P(val)) {
02363 st_data_t stkey = (st_data_t)key;
02364 st_delete(stenv, &stkey, NULL);
02365 }
02366 else {
02367 st_insert(stenv, (st_data_t)key, (st_data_t)val);
02368 RB_OBJ_WRITTEN(envtbl, Qundef, key);
02369 RB_OBJ_WRITTEN(envtbl, Qundef, val);
02370 }
02371 }
02372 }
02373 envp_buf = rb_str_buf_new(0);
02374 hide_obj(envp_buf);
02375 st_foreach(RHASH_TBL_RAW(envtbl), fill_envp_buf_i, (st_data_t)envp_buf);
02376 envp_str = rb_str_buf_new(sizeof(char*) * (RHASH_SIZE(envtbl) + 1));
02377 hide_obj(envp_str);
02378 p = RSTRING_PTR(envp_buf);
02379 ep = p + RSTRING_LEN(envp_buf);
02380 while (p < ep) {
02381 rb_str_buf_cat(envp_str, (char *)&p, sizeof(p));
02382 p += strlen(p) + 1;
02383 }
02384 p = NULL;
02385 rb_str_buf_cat(envp_str, (char *)&p, sizeof(p));
02386 eargp->envp_str = envp_str;
02387 eargp->envp_buf = envp_buf;
02388
02389
02390
02391
02392
02393
02394
02395
02396 }
02397 RB_GC_GUARD(execarg_obj);
02398 }
02399
02400 void
02401 rb_exec_arg_fixup(struct rb_exec_arg *e)
02402 {
02403 rb_execarg_fixup(e->execarg_obj);
02404 }
02405
02406 static int rb_exec_without_timer_thread(const struct rb_execarg *eargp, char *errmsg, size_t errmsg_buflen);
02407
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 VALUE
02482 rb_f_exec(int argc, VALUE *argv)
02483 {
02484 VALUE execarg_obj, fail_str;
02485 struct rb_execarg *eargp;
02486 #define CHILD_ERRMSG_BUFLEN 80
02487 char errmsg[CHILD_ERRMSG_BUFLEN] = { '\0' };
02488
02489 execarg_obj = rb_execarg_new(argc, argv, TRUE);
02490 eargp = rb_execarg_get(execarg_obj);
02491 rb_execarg_fixup(execarg_obj);
02492 fail_str = eargp->use_shell ? eargp->invoke.sh.shell_script : eargp->invoke.cmd.command_name;
02493
02494 #if defined(__APPLE__) || defined(__HAIKU__)
02495 rb_exec_without_timer_thread(eargp, errmsg, sizeof(errmsg));
02496 #else
02497 rb_exec_async_signal_safe(eargp, errmsg, sizeof(errmsg));
02498 #endif
02499 RB_GC_GUARD(execarg_obj);
02500 if (errmsg[0])
02501 rb_sys_fail(errmsg);
02502 rb_sys_fail_str(fail_str);
02503 return Qnil;
02504 }
02505
02506 #define ERRMSG(str) do { if (errmsg && 0 < errmsg_buflen) strlcpy(errmsg, (str), errmsg_buflen); } while (0)
02507
02508
02509 #if defined(DEBUG_REDIRECT)
02510
02511 #include <stdarg.h>
02512
02513 static void
02514 ttyprintf(const char *fmt, ...)
02515 {
02516 va_list ap;
02517 FILE *tty;
02518 int save = errno;
02519 #ifdef _WIN32
02520 tty = fopen("con", "w");
02521 #else
02522 tty = fopen("/dev/tty", "w");
02523 #endif
02524 if (!tty)
02525 return;
02526
02527 va_start(ap, fmt);
02528 vfprintf(tty, fmt, ap);
02529 va_end(ap);
02530 fclose(tty);
02531 errno = save;
02532 }
02533
02534 static int
02535 redirect_dup(int oldfd)
02536 {
02537 int ret;
02538 ret = dup(oldfd);
02539 ttyprintf("dup(%d) => %d\n", oldfd, ret);
02540 return ret;
02541 }
02542
02543 static int
02544 redirect_dup2(int oldfd, int newfd)
02545 {
02546 int ret;
02547 ret = dup2(oldfd, newfd);
02548 ttyprintf("dup2(%d, %d)\n", oldfd, newfd);
02549 return ret;
02550 }
02551
02552 static int
02553 redirect_close(int fd)
02554 {
02555 int ret;
02556 ret = close(fd);
02557 ttyprintf("close(%d)\n", fd);
02558 return ret;
02559 }
02560
02561 static int
02562 redirect_open(const char *pathname, int flags, mode_t perm)
02563 {
02564 int ret;
02565 ret = open(pathname, flags, perm);
02566 ttyprintf("open(\"%s\", 0x%x, 0%o) => %d\n", pathname, flags, perm, ret);
02567 return ret;
02568 }
02569
02570 #else
02571 #define redirect_dup(oldfd) dup(oldfd)
02572 #define redirect_dup2(oldfd, newfd) dup2((oldfd), (newfd))
02573 #define redirect_close(fd) close(fd)
02574 #define redirect_open(pathname, flags, perm) open((pathname), (flags), (perm))
02575 #endif
02576
02577 static int
02578 save_redirect_fd(int fd, struct rb_execarg *sargp, char *errmsg, size_t errmsg_buflen)
02579 {
02580 if (sargp) {
02581 VALUE newary;
02582 int save_fd = redirect_dup(fd);
02583 if (save_fd == -1) {
02584 if (errno == EBADF)
02585 return 0;
02586 ERRMSG("dup");
02587 return -1;
02588 }
02589 rb_update_max_fd(save_fd);
02590 newary = sargp->fd_dup2;
02591 if (newary == Qfalse) {
02592 newary = hide_obj(rb_ary_new());
02593 sargp->fd_dup2 = newary;
02594 }
02595 rb_ary_push(newary,
02596 hide_obj(rb_assoc_new(INT2FIX(fd), INT2FIX(save_fd))));
02597
02598 newary = sargp->fd_close;
02599 if (newary == Qfalse) {
02600 newary = hide_obj(rb_ary_new());
02601 sargp->fd_close = newary;
02602 }
02603 rb_ary_push(newary, hide_obj(rb_assoc_new(INT2FIX(save_fd), Qnil)));
02604 }
02605
02606 return 0;
02607 }
02608
02609 static int
02610 intcmp(const void *a, const void *b)
02611 {
02612 return *(int*)a - *(int*)b;
02613 }
02614
02615 static int
02616 intrcmp(const void *a, const void *b)
02617 {
02618 return *(int*)b - *(int*)a;
02619 }
02620
02621 struct run_exec_dup2_fd_pair {
02622 int oldfd;
02623 int newfd;
02624 long older_index;
02625 long num_newer;
02626 };
02627
02628 static long
02629 run_exec_dup2_tmpbuf_size(long n)
02630 {
02631 return sizeof(struct run_exec_dup2_fd_pair) * n;
02632 }
02633
02634
02635 static int
02636 run_exec_dup2(VALUE ary, VALUE tmpbuf, struct rb_execarg *sargp, char *errmsg, size_t errmsg_buflen)
02637 {
02638 long n, i;
02639 int ret;
02640 int extra_fd = -1;
02641 struct run_exec_dup2_fd_pair *pairs = 0;
02642
02643 n = RARRAY_LEN(ary);
02644 pairs = (struct run_exec_dup2_fd_pair *)RSTRING_PTR(tmpbuf);
02645
02646
02647 for (i = 0; i < n; i++) {
02648 VALUE elt = RARRAY_AREF(ary, i);
02649 pairs[i].oldfd = FIX2INT(RARRAY_AREF(elt, 1));
02650 pairs[i].newfd = FIX2INT(RARRAY_AREF(elt, 0));
02651 pairs[i].older_index = -1;
02652 }
02653
02654
02655 if (!sargp)
02656 qsort(pairs, n, sizeof(struct run_exec_dup2_fd_pair), intcmp);
02657 else
02658 qsort(pairs, n, sizeof(struct run_exec_dup2_fd_pair), intrcmp);
02659
02660
02661 for (i = 0; i < n; i++) {
02662 int newfd = pairs[i].newfd;
02663 struct run_exec_dup2_fd_pair key, *found;
02664 key.oldfd = newfd;
02665 found = bsearch(&key, pairs, n, sizeof(struct run_exec_dup2_fd_pair), intcmp);
02666 pairs[i].num_newer = 0;
02667 if (found) {
02668 while (pairs < found && (found-1)->oldfd == newfd)
02669 found--;
02670 while (found < pairs+n && found->oldfd == newfd) {
02671 pairs[i].num_newer++;
02672 found->older_index = i;
02673 found++;
02674 }
02675 }
02676 }
02677
02678
02679 for (i = 0; i < n; i++) {
02680 long j = i;
02681 while (j != -1 && pairs[j].oldfd != -1 && pairs[j].num_newer == 0) {
02682 if (save_redirect_fd(pairs[j].newfd, sargp, errmsg, errmsg_buflen) < 0)
02683 goto fail;
02684 ret = redirect_dup2(pairs[j].oldfd, pairs[j].newfd);
02685 if (ret == -1) {
02686 ERRMSG("dup2");
02687 goto fail;
02688 }
02689 rb_update_max_fd(pairs[j].newfd);
02690 pairs[j].oldfd = -1;
02691 j = pairs[j].older_index;
02692 if (j != -1)
02693 pairs[j].num_newer--;
02694 }
02695 }
02696
02697
02698 for (i = 0; i < n; i++) {
02699 long j;
02700 if (pairs[i].oldfd == -1)
02701 continue;
02702 if (pairs[i].oldfd == pairs[i].newfd) {
02703 #ifdef F_GETFD
02704 int fd = pairs[i].oldfd;
02705 ret = fcntl(fd, F_GETFD);
02706 if (ret == -1) {
02707 ERRMSG("fcntl(F_GETFD)");
02708 goto fail;
02709 }
02710 if (ret & FD_CLOEXEC) {
02711 ret &= ~FD_CLOEXEC;
02712 ret = fcntl(fd, F_SETFD, ret);
02713 if (ret == -1) {
02714 ERRMSG("fcntl(F_SETFD)");
02715 goto fail;
02716 }
02717 }
02718 #endif
02719 pairs[i].oldfd = -1;
02720 continue;
02721 }
02722 if (extra_fd == -1) {
02723 extra_fd = redirect_dup(pairs[i].oldfd);
02724 if (extra_fd == -1) {
02725 ERRMSG("dup");
02726 goto fail;
02727 }
02728 rb_update_max_fd(extra_fd);
02729 }
02730 else {
02731 ret = redirect_dup2(pairs[i].oldfd, extra_fd);
02732 if (ret == -1) {
02733 ERRMSG("dup2");
02734 goto fail;
02735 }
02736 rb_update_max_fd(extra_fd);
02737 }
02738 pairs[i].oldfd = extra_fd;
02739 j = pairs[i].older_index;
02740 pairs[i].older_index = -1;
02741 while (j != -1) {
02742 ret = redirect_dup2(pairs[j].oldfd, pairs[j].newfd);
02743 if (ret == -1) {
02744 ERRMSG("dup2");
02745 goto fail;
02746 }
02747 rb_update_max_fd(ret);
02748 pairs[j].oldfd = -1;
02749 j = pairs[j].older_index;
02750 }
02751 }
02752 if (extra_fd != -1) {
02753 ret = redirect_close(extra_fd);
02754 if (ret == -1) {
02755 ERRMSG("close");
02756 goto fail;
02757 }
02758 }
02759
02760 return 0;
02761
02762 fail:
02763 return -1;
02764 }
02765
02766
02767 static int
02768 run_exec_close(VALUE ary, char *errmsg, size_t errmsg_buflen)
02769 {
02770 long i;
02771 int ret;
02772
02773 for (i = 0; i < RARRAY_LEN(ary); i++) {
02774 VALUE elt = RARRAY_AREF(ary, i);
02775 int fd = FIX2INT(RARRAY_AREF(elt, 0));
02776 ret = redirect_close(fd);
02777 if (ret == -1) {
02778 ERRMSG("close");
02779 return -1;
02780 }
02781 }
02782 return 0;
02783 }
02784
02785
02786 static int
02787 run_exec_open(VALUE ary, struct rb_execarg *sargp, char *errmsg, size_t errmsg_buflen)
02788 {
02789 long i;
02790 int ret;
02791
02792 for (i = 0; i < RARRAY_LEN(ary);) {
02793 VALUE elt = RARRAY_AREF(ary, i);
02794 int fd = FIX2INT(RARRAY_AREF(elt, 0));
02795 VALUE param = RARRAY_AREF(elt, 1);
02796 char *path = RSTRING_PTR(RARRAY_AREF(param, 0));
02797 int flags = NUM2INT(RARRAY_AREF(param, 1));
02798 int perm = NUM2INT(RARRAY_AREF(param, 2));
02799 int need_close = 1;
02800 int fd2 = redirect_open(path, flags, perm);
02801 if (fd2 == -1) {
02802 ERRMSG("open");
02803 return -1;
02804 }
02805 rb_update_max_fd(fd2);
02806 while (i < RARRAY_LEN(ary) &&
02807 (elt = RARRAY_AREF(ary, i), RARRAY_AREF(elt, 1) == param)) {
02808 fd = FIX2INT(RARRAY_AREF(elt, 0));
02809 if (fd == fd2) {
02810 need_close = 0;
02811 }
02812 else {
02813 if (save_redirect_fd(fd, sargp, errmsg, errmsg_buflen) < 0)
02814 return -1;
02815 ret = redirect_dup2(fd2, fd);
02816 if (ret == -1) {
02817 ERRMSG("dup2");
02818 return -1;
02819 }
02820 rb_update_max_fd(fd);
02821 }
02822 i++;
02823 }
02824 if (need_close) {
02825 ret = redirect_close(fd2);
02826 if (ret == -1) {
02827 ERRMSG("close");
02828 return -1;
02829 }
02830 }
02831 }
02832 return 0;
02833 }
02834
02835
02836 static int
02837 run_exec_dup2_child(VALUE ary, struct rb_execarg *sargp, char *errmsg, size_t errmsg_buflen)
02838 {
02839 long i;
02840 int ret;
02841
02842 for (i = 0; i < RARRAY_LEN(ary); i++) {
02843 VALUE elt = RARRAY_AREF(ary, i);
02844 int newfd = FIX2INT(RARRAY_AREF(elt, 0));
02845 int oldfd = FIX2INT(RARRAY_AREF(elt, 1));
02846
02847 if (save_redirect_fd(newfd, sargp, errmsg, errmsg_buflen) < 0)
02848 return -1;
02849 ret = redirect_dup2(oldfd, newfd);
02850 if (ret == -1) {
02851 ERRMSG("dup2");
02852 return -1;
02853 }
02854 rb_update_max_fd(newfd);
02855 }
02856 return 0;
02857 }
02858
02859 #ifdef HAVE_SETPGID
02860
02861 static int
02862 run_exec_pgroup(const struct rb_execarg *eargp, struct rb_execarg *sargp, char *errmsg, size_t errmsg_buflen)
02863 {
02864
02865
02866
02867
02868
02869
02870 int ret;
02871 rb_pid_t pgroup;
02872
02873 pgroup = eargp->pgroup_pgid;
02874 if (pgroup == -1)
02875 return 0;
02876
02877 if (sargp) {
02878
02879 sargp->pgroup_given = 1;
02880 sargp->pgroup_pgid = getpgrp();
02881 }
02882
02883 if (pgroup == 0) {
02884 pgroup = getpid();
02885 }
02886 ret = setpgid(getpid(), pgroup);
02887 if (ret == -1) ERRMSG("setpgid");
02888 return ret;
02889 }
02890 #endif
02891
02892 #if defined(HAVE_SETRLIMIT) && defined(RLIM2NUM)
02893
02894 static int
02895 run_exec_rlimit(VALUE ary, struct rb_execarg *sargp, char *errmsg, size_t errmsg_buflen)
02896 {
02897 long i;
02898 for (i = 0; i < RARRAY_LEN(ary); i++) {
02899 VALUE elt = RARRAY_AREF(ary, i);
02900 int rtype = NUM2INT(RARRAY_AREF(elt, 0));
02901 struct rlimit rlim;
02902 if (sargp) {
02903 VALUE tmp, newary;
02904 if (getrlimit(rtype, &rlim) == -1) {
02905 ERRMSG("getrlimit");
02906 return -1;
02907 }
02908 tmp = hide_obj(rb_ary_new3(3, RARRAY_AREF(elt, 0),
02909 RLIM2NUM(rlim.rlim_cur),
02910 RLIM2NUM(rlim.rlim_max)));
02911 if (sargp->rlimit_limits == Qfalse)
02912 newary = sargp->rlimit_limits = hide_obj(rb_ary_new());
02913 else
02914 newary = sargp->rlimit_limits;
02915 rb_ary_push(newary, tmp);
02916 }
02917 rlim.rlim_cur = NUM2RLIM(RARRAY_AREF(elt, 1));
02918 rlim.rlim_max = NUM2RLIM(RARRAY_AREF(elt, 2));
02919 if (setrlimit(rtype, &rlim) == -1) {
02920 ERRMSG("setrlimit");
02921 return -1;
02922 }
02923 }
02924 return 0;
02925 }
02926 #endif
02927
02928 #if !defined(HAVE_FORK)
02929 static VALUE
02930 save_env_i(RB_BLOCK_CALL_FUNC_ARGLIST(i, ary))
02931 {
02932 rb_ary_push(ary, hide_obj(rb_ary_dup(argv[0])));
02933 return Qnil;
02934 }
02935
02936 static void
02937 save_env(struct rb_execarg *sargp)
02938 {
02939 if (!sargp)
02940 return;
02941 if (sargp->env_modification == Qfalse) {
02942 VALUE env = rb_const_get(rb_cObject, rb_intern("ENV"));
02943 if (RTEST(env)) {
02944 VALUE ary = hide_obj(rb_ary_new());
02945 rb_block_call(env, idEach, 0, 0, save_env_i,
02946 (VALUE)ary);
02947 sargp->env_modification = ary;
02948 }
02949 sargp->unsetenv_others_given = 1;
02950 sargp->unsetenv_others_do = 1;
02951 }
02952 }
02953 #endif
02954
02955
02956 int
02957 rb_execarg_run_options(const struct rb_execarg *eargp, struct rb_execarg *sargp, char *errmsg, size_t errmsg_buflen)
02958 {
02959 VALUE obj;
02960
02961 if (sargp) {
02962
02963 MEMZERO(sargp, struct rb_execarg, 1);
02964 sargp->redirect_fds = Qnil;
02965 }
02966
02967 #ifdef HAVE_SETPGID
02968 if (eargp->pgroup_given) {
02969 if (run_exec_pgroup(eargp, sargp, errmsg, errmsg_buflen) == -1)
02970 return -1;
02971 }
02972 #endif
02973
02974 #if defined(HAVE_SETRLIMIT) && defined(RLIM2NUM)
02975 obj = eargp->rlimit_limits;
02976 if (obj != Qfalse) {
02977 if (run_exec_rlimit(obj, sargp, errmsg, errmsg_buflen) == -1)
02978 return -1;
02979 }
02980 #endif
02981
02982 #if !defined(HAVE_FORK)
02983 if (eargp->unsetenv_others_given && eargp->unsetenv_others_do) {
02984 save_env(sargp);
02985 rb_env_clear();
02986 }
02987
02988 obj = eargp->env_modification;
02989 if (obj != Qfalse) {
02990 long i;
02991 save_env(sargp);
02992 for (i = 0; i < RARRAY_LEN(obj); i++) {
02993 VALUE pair = RARRAY_AREF(obj, i);
02994 VALUE key = RARRAY_AREF(pair, 0);
02995 VALUE val = RARRAY_AREF(pair, 1);
02996 if (NIL_P(val))
02997 ruby_setenv(StringValueCStr(key), 0);
02998 else
02999 ruby_setenv(StringValueCStr(key), StringValueCStr(val));
03000 }
03001 }
03002 #endif
03003
03004 if (eargp->umask_given) {
03005 mode_t mask = eargp->umask_mask;
03006 mode_t oldmask = umask(mask);
03007 if (sargp) {
03008 sargp->umask_given = 1;
03009 sargp->umask_mask = oldmask;
03010 }
03011 }
03012
03013 obj = eargp->fd_dup2;
03014 if (obj != Qfalse) {
03015 if (run_exec_dup2(obj, eargp->dup2_tmpbuf, sargp, errmsg, errmsg_buflen) == -1)
03016 return -1;
03017 }
03018
03019 obj = eargp->fd_close;
03020 if (obj != Qfalse) {
03021 if (sargp)
03022 rb_warn("cannot close fd before spawn");
03023 else {
03024 if (run_exec_close(obj, errmsg, errmsg_buflen) == -1)
03025 return -1;
03026 }
03027 }
03028
03029 #ifdef HAVE_FORK
03030 if (!eargp->close_others_given || eargp->close_others_do) {
03031 rb_close_before_exec(3, eargp->close_others_maxhint, eargp->redirect_fds);
03032 }
03033 #endif
03034
03035 obj = eargp->fd_open;
03036 if (obj != Qfalse) {
03037 if (run_exec_open(obj, sargp, errmsg, errmsg_buflen) == -1)
03038 return -1;
03039 }
03040
03041 obj = eargp->fd_dup2_child;
03042 if (obj != Qfalse) {
03043 if (run_exec_dup2_child(obj, sargp, errmsg, errmsg_buflen) == -1)
03044 return -1;
03045 }
03046
03047 if (eargp->chdir_given) {
03048 if (sargp) {
03049 char *cwd = my_getcwd();
03050 sargp->chdir_given = 1;
03051 sargp->chdir_dir = hide_obj(rb_str_new2(cwd));
03052 xfree(cwd);
03053 }
03054 if (chdir(RSTRING_PTR(eargp->chdir_dir)) == -1) {
03055 ERRMSG("chdir");
03056 return -1;
03057 }
03058 }
03059
03060 #ifdef HAVE_SETGID
03061 if (eargp->gid_given) {
03062 if (setgid(eargp->gid) < 0) {
03063 ERRMSG("setgid");
03064 return -1;
03065 }
03066 }
03067 #endif
03068 #ifdef HAVE_SETUID
03069 if (eargp->uid_given) {
03070 if (setuid(eargp->uid) < 0) {
03071 ERRMSG("setuid");
03072 return -1;
03073 }
03074 }
03075 #endif
03076
03077 if (sargp) {
03078 VALUE ary = sargp->fd_dup2;
03079 if (ary != Qfalse) {
03080 size_t len = run_exec_dup2_tmpbuf_size(RARRAY_LEN(ary));
03081 VALUE tmpbuf = hide_obj(rb_str_new(0, len));
03082 rb_str_set_len(tmpbuf, len);
03083 sargp->dup2_tmpbuf = tmpbuf;
03084 }
03085 }
03086
03087 return 0;
03088 }
03089
03090 int
03091 rb_run_exec_options_err(const struct rb_exec_arg *e, struct rb_exec_arg *s, char *errmsg, size_t errmsg_buflen)
03092 {
03093 return rb_execarg_run_options(rb_execarg_get(e->execarg_obj), rb_execarg_get(s->execarg_obj), errmsg, errmsg_buflen);
03094 }
03095
03096 int
03097 rb_run_exec_options(const struct rb_exec_arg *e, struct rb_exec_arg *s)
03098 {
03099 return rb_execarg_run_options(rb_execarg_get(e->execarg_obj), rb_execarg_get(s->execarg_obj), NULL, 0);
03100 }
03101
03102
03103 int
03104 rb_exec_async_signal_safe(const struct rb_execarg *eargp, char *errmsg, size_t errmsg_buflen)
03105 {
03106 #if !defined(HAVE_FORK)
03107 struct rb_execarg sarg, *const sargp = &sarg;
03108 #else
03109 struct rb_execarg *const sargp = NULL;
03110 #endif
03111
03112 before_exec_async_signal_safe();
03113
03114 if (rb_execarg_run_options(eargp, sargp, errmsg, errmsg_buflen) < 0) {
03115 goto failure;
03116 }
03117
03118 if (eargp->use_shell) {
03119 proc_exec_sh(RSTRING_PTR(eargp->invoke.sh.shell_script), eargp->envp_str);
03120 }
03121 else {
03122 char *abspath = NULL;
03123 if (!NIL_P(eargp->invoke.cmd.command_abspath))
03124 abspath = RSTRING_PTR(eargp->invoke.cmd.command_abspath);
03125 proc_exec_cmd(abspath, eargp->invoke.cmd.argv_str, eargp->envp_str);
03126 }
03127 #if !defined(HAVE_FORK)
03128 preserving_errno(rb_execarg_run_options(sargp, NULL, errmsg, errmsg_buflen));
03129 #endif
03130
03131 failure:
03132 preserving_errno(after_exec_async_signal_safe());
03133 return -1;
03134 }
03135
03136 static int
03137 rb_exec_without_timer_thread(const struct rb_execarg *eargp, char *errmsg, size_t errmsg_buflen)
03138 {
03139 int ret;
03140 before_exec_non_async_signal_safe();
03141 ret = rb_exec_async_signal_safe(eargp, errmsg, errmsg_buflen);
03142 preserving_errno(after_exec_non_async_signal_safe());
03143 return ret;
03144 }
03145
03146 int
03147 rb_exec_err(const struct rb_exec_arg *e, char *errmsg, size_t errmsg_buflen)
03148 {
03149 return rb_exec_without_timer_thread(rb_execarg_get(e->execarg_obj), errmsg, errmsg_buflen);
03150 }
03151
03152 int
03153 rb_exec(const struct rb_exec_arg *e)
03154 {
03155 #if !defined FD_CLOEXEC && !defined HAVE_SPAWNV
03156 char errmsg[80] = { '\0' };
03157 int ret = rb_exec_without_timer_thread(rb_execarg_get(e->execarg_obj), errmsg, sizeof(errmsg));
03158 preserving_errno(
03159 if (errmsg[0]) {
03160 fprintf(stderr, "%s\n", errmsg);
03161 }
03162 else {
03163 fprintf(stderr, "%s:%d: command not found: %s\n",
03164 rb_sourcefile(), rb_sourceline(),
03165 RSTRING_PTR(e->use_shell ? e->invoke.sh.shell_script : e->invoke.cmd.command_name));
03166 }
03167 );
03168 return ret;
03169 #else
03170 return rb_exec_without_timer_thread(rb_execarg_get(e->execarg_obj), NULL, 0);
03171 #endif
03172 }
03173
03174 #ifdef HAVE_FORK
03175
03176 static int
03177 rb_exec_atfork(void* arg, char *errmsg, size_t errmsg_buflen)
03178 {
03179 return rb_exec_async_signal_safe(arg, errmsg, errmsg_buflen);
03180 }
03181 #endif
03182
03183 #ifdef HAVE_FORK
03184 #if SIZEOF_INT == SIZEOF_LONG
03185 #define proc_syswait (VALUE (*)(VALUE))rb_syswait
03186 #else
03187 static VALUE
03188 proc_syswait(VALUE pid)
03189 {
03190 rb_syswait((int)pid);
03191 return Qnil;
03192 }
03193 #endif
03194
03195 static int
03196 move_fds_to_avoid_crash(int *fdp, int n, VALUE fds)
03197 {
03198 int min = 0;
03199 int i;
03200 for (i = 0; i < n; i++) {
03201 int ret;
03202 while (RTEST(rb_hash_lookup(fds, INT2FIX(fdp[i])))) {
03203 if (min <= fdp[i])
03204 min = fdp[i]+1;
03205 while (RTEST(rb_hash_lookup(fds, INT2FIX(min))))
03206 min++;
03207 ret = rb_cloexec_fcntl_dupfd(fdp[i], min);
03208 if (ret == -1)
03209 return -1;
03210 rb_update_max_fd(ret);
03211 close(fdp[i]);
03212 fdp[i] = ret;
03213 }
03214 }
03215 return 0;
03216 }
03217
03218 static int
03219 pipe_nocrash(int filedes[2], VALUE fds)
03220 {
03221 int ret;
03222 ret = rb_pipe(filedes);
03223 if (ret == -1)
03224 return -1;
03225 if (RTEST(fds)) {
03226 int save = errno;
03227 if (move_fds_to_avoid_crash(filedes, 2, fds) == -1) {
03228 close(filedes[0]);
03229 close(filedes[1]);
03230 return -1;
03231 }
03232 errno = save;
03233 }
03234 return ret;
03235 }
03236
03237 struct chfunc_protect_t {
03238 int (*chfunc)(void*, char *, size_t);
03239 void *arg;
03240 char *errmsg;
03241 size_t buflen;
03242 };
03243
03244 static VALUE
03245 chfunc_protect(VALUE arg)
03246 {
03247 struct chfunc_protect_t *p = (struct chfunc_protect_t *)arg;
03248
03249 return (VALUE)(*p->chfunc)(p->arg, p->errmsg, p->buflen);
03250 }
03251
03252 #ifndef O_BINARY
03253 #define O_BINARY 0
03254 #endif
03255
03256
03257
03258
03259
03260
03261
03262
03263
03264
03265
03266
03267
03268
03269
03270
03271
03272
03273
03274
03275
03276
03277
03278
03279
03280
03281
03282 static rb_pid_t
03283 retry_fork(int *status, int *ep, int chfunc_is_async_signal_safe)
03284 {
03285 rb_pid_t pid;
03286 int state = 0;
03287 int try_gc = 1;
03288
03289 #define prefork() ( \
03290 rb_io_flush(rb_stdout), \
03291 rb_io_flush(rb_stderr) \
03292 )
03293
03294 while (1) {
03295 prefork();
03296 if (!chfunc_is_async_signal_safe)
03297 before_fork();
03298 pid = fork();
03299 if (pid == 0)
03300 return pid;
03301 if (!chfunc_is_async_signal_safe)
03302 preserving_errno(after_fork());
03303 if (0 < pid)
03304 return pid;
03305
03306 switch (errno) {
03307 case ENOMEM:
03308 if (try_gc-- > 0 && !rb_during_gc()) {
03309 rb_gc();
03310 continue;
03311 }
03312 break;
03313 case EAGAIN:
03314 #if defined(EWOULDBLOCK) && EWOULDBLOCK != EAGAIN
03315 case EWOULDBLOCK:
03316 #endif
03317 if (!status && !ep) {
03318 rb_thread_sleep(1);
03319 continue;
03320 }
03321 else {
03322 rb_protect((VALUE (*)())rb_thread_sleep, 1, &state);
03323 if (status) *status = state;
03324 if (!state) continue;
03325 }
03326 break;
03327 }
03328 if (ep) {
03329 preserving_errno((close(ep[0]), close(ep[1])));
03330 }
03331 if (state && !status) rb_jump_tag(state);
03332 return -1;
03333 }
03334 }
03335
03336 static ssize_t
03337 write_retry(int fd, const void *buf, size_t len)
03338 {
03339 ssize_t w;
03340
03341 do {
03342 w = write(fd, buf, len);
03343 } while (w < 0 && errno == EINTR);
03344
03345 return w;
03346 }
03347
03348 static ssize_t
03349 read_retry(int fd, void *buf, size_t len)
03350 {
03351 ssize_t r;
03352
03353 do {
03354 r = read(fd, buf, len);
03355 } while (r < 0 && errno == EINTR);
03356
03357 return r;
03358 }
03359
03360 static void
03361 send_child_error(int fd, int state, char *errmsg, size_t errmsg_buflen, int chfunc_is_async_signal_safe)
03362 {
03363 VALUE io = Qnil;
03364 int err;
03365
03366 if (!chfunc_is_async_signal_safe) {
03367 if (write_retry(fd, &state, sizeof(state)) == sizeof(state) && state) {
03368 VALUE errinfo = rb_errinfo();
03369 io = rb_io_fdopen(fd, O_WRONLY|O_BINARY, NULL);
03370 rb_marshal_dump(errinfo, io);
03371 rb_io_flush(io);
03372 }
03373 }
03374 err = errno;
03375 if (write_retry(fd, &err, sizeof(err)) < 0) err = errno;
03376 if (errmsg && 0 < errmsg_buflen) {
03377 errmsg[errmsg_buflen-1] = '\0';
03378 errmsg_buflen = strlen(errmsg);
03379 if (errmsg_buflen > 0 && write_retry(fd, errmsg, errmsg_buflen) < 0)
03380 err = errno;
03381 }
03382 if (!NIL_P(io)) rb_io_close(io);
03383 }
03384
03385 static int
03386 recv_child_error(int fd, int *statep, VALUE *excp, int *errp, char *errmsg, size_t errmsg_buflen, int chfunc_is_async_signal_safe)
03387 {
03388 int err, state = 0;
03389 VALUE io = Qnil;
03390 ssize_t size;
03391 VALUE exc = Qnil;
03392 if (!chfunc_is_async_signal_safe) {
03393 if ((read_retry(fd, &state, sizeof(state))) == sizeof(state) && state) {
03394 io = rb_io_fdopen(fd, O_RDONLY|O_BINARY, NULL);
03395 exc = rb_marshal_load(io);
03396 rb_set_errinfo(exc);
03397 }
03398 if (!*statep && state) *statep = state;
03399 *excp = exc;
03400 }
03401 #define READ_FROM_CHILD(ptr, len) \
03402 (NIL_P(io) ? read_retry(fd, (ptr), (len)) : rb_io_bufread(io, (ptr), (len)))
03403 if ((size = READ_FROM_CHILD(&err, sizeof(err))) < 0) {
03404 err = errno;
03405 }
03406 *errp = err;
03407 if (size == sizeof(err) &&
03408 errmsg && 0 < errmsg_buflen) {
03409 ssize_t ret = READ_FROM_CHILD(errmsg, errmsg_buflen-1);
03410 if (0 <= ret) {
03411 errmsg[ret] = '\0';
03412 }
03413 }
03414 if (NIL_P(io))
03415 close(fd);
03416 else
03417 rb_io_close(io);
03418 return size != 0;
03419 }
03420
03421 static rb_pid_t
03422 rb_fork_internal(int *status, int (*chfunc)(void*, char *, size_t), void *charg,
03423 int chfunc_is_async_signal_safe, VALUE fds,
03424 char *errmsg, size_t errmsg_buflen)
03425 {
03426 rb_pid_t pid;
03427 int err, state = 0;
03428 int ep[2];
03429 VALUE exc = Qnil;
03430 int error_occurred;
03431
03432 if (status) *status = 0;
03433
03434 if (!chfunc) {
03435 pid = retry_fork(status, NULL, FALSE);
03436 if (pid < 0)
03437 return pid;
03438 if (!pid) {
03439 forked_child = 1;
03440 after_fork();
03441 }
03442 return pid;
03443 }
03444 else {
03445 if (pipe_nocrash(ep, fds)) return -1;
03446 pid = retry_fork(status, ep, chfunc_is_async_signal_safe);
03447 if (pid < 0)
03448 return pid;
03449 if (!pid) {
03450 int ret;
03451 forked_child = 1;
03452 close(ep[0]);
03453 if (chfunc_is_async_signal_safe)
03454 ret = chfunc(charg, errmsg, errmsg_buflen);
03455 else {
03456 struct chfunc_protect_t arg;
03457 arg.chfunc = chfunc;
03458 arg.arg = charg;
03459 arg.errmsg = errmsg;
03460 arg.buflen = errmsg_buflen;
03461 ret = (int)rb_protect(chfunc_protect, (VALUE)&arg, &state);
03462 }
03463 if (!ret) _exit(EXIT_SUCCESS);
03464 send_child_error(ep[1], state, errmsg, errmsg_buflen, chfunc_is_async_signal_safe);
03465 #if EXIT_SUCCESS == 127
03466 _exit(EXIT_FAILURE);
03467 #else
03468 _exit(127);
03469 #endif
03470 }
03471 close(ep[1]);
03472 error_occurred = recv_child_error(ep[0], &state, &exc, &err, errmsg, errmsg_buflen, chfunc_is_async_signal_safe);
03473 if (state || error_occurred) {
03474 if (status) {
03475 rb_protect(proc_syswait, (VALUE)pid, status);
03476 if (state) *status = state;
03477 }
03478 else {
03479 rb_syswait(pid);
03480 if (state) rb_exc_raise(exc);
03481 }
03482 errno = err;
03483 return -1;
03484 }
03485 return pid;
03486 }
03487 }
03488
03489 rb_pid_t
03490 rb_fork_err(int *status, int (*chfunc)(void*, char *, size_t), void *charg, VALUE fds,
03491 char *errmsg, size_t errmsg_buflen)
03492 {
03493 return rb_fork_internal(status, chfunc, charg, FALSE, fds, errmsg, errmsg_buflen);
03494 }
03495
03496 rb_pid_t
03497 rb_fork_async_signal_safe(int *status, int (*chfunc)(void*, char *, size_t), void *charg, VALUE fds,
03498 char *errmsg, size_t errmsg_buflen)
03499 {
03500 return rb_fork_internal(status, chfunc, charg, TRUE, fds, errmsg, errmsg_buflen);
03501 }
03502
03503 struct chfunc_wrapper_t {
03504 int (*chfunc)(void*);
03505 void *arg;
03506 };
03507
03508 static int
03509 chfunc_wrapper(void *arg_, char *errmsg, size_t errmsg_buflen)
03510 {
03511 struct chfunc_wrapper_t *arg = arg_;
03512 return arg->chfunc(arg->arg);
03513 }
03514
03515 rb_pid_t
03516 rb_fork(int *status, int (*chfunc)(void*), void *charg, VALUE fds)
03517 {
03518 if (chfunc) {
03519 struct chfunc_wrapper_t warg;
03520 warg.chfunc = chfunc;
03521 warg.arg = charg;
03522 return rb_fork_internal(status, chfunc_wrapper, &warg, FALSE, fds, NULL, 0);
03523 }
03524 else {
03525 return rb_fork_internal(status, NULL, NULL, FALSE, fds, NULL, 0);
03526 }
03527
03528 }
03529
03530 rb_pid_t
03531 rb_fork_ruby(int *status)
03532 {
03533 return rb_fork_internal(status, NULL, NULL, FALSE, Qnil, NULL, 0);
03534 }
03535
03536 #endif
03537
03538 #if defined(HAVE_FORK) && !defined(CANNOT_FORK_WITH_PTHREAD)
03539
03540
03541
03542
03543
03544
03545
03546
03547
03548
03549
03550
03551
03552
03553
03554
03555
03556
03557
03558
03559
03560
03561
03562
03563
03564
03565 static VALUE
03566 rb_f_fork(VALUE obj)
03567 {
03568 rb_pid_t pid;
03569
03570 rb_secure(2);
03571
03572 switch (pid = rb_fork_ruby(NULL)) {
03573 case 0:
03574 rb_thread_atfork();
03575 if (rb_block_given_p()) {
03576 int status;
03577
03578 rb_protect(rb_yield, Qundef, &status);
03579 ruby_stop(status);
03580 }
03581 return Qnil;
03582
03583 case -1:
03584 rb_sys_fail("fork(2)");
03585 return Qnil;
03586
03587 default:
03588 return PIDT2NUM(pid);
03589 }
03590 }
03591 #else
03592 #define rb_f_fork rb_f_notimplement
03593 #endif
03594
03595 static int
03596 exit_status_code(VALUE status)
03597 {
03598 int istatus;
03599
03600 switch (status) {
03601 case Qtrue:
03602 istatus = EXIT_SUCCESS;
03603 break;
03604 case Qfalse:
03605 istatus = EXIT_FAILURE;
03606 break;
03607 default:
03608 istatus = NUM2INT(status);
03609 #if EXIT_SUCCESS != 0
03610 if (istatus == 0)
03611 istatus = EXIT_SUCCESS;
03612 #endif
03613 break;
03614 }
03615 return istatus;
03616 }
03617
03618
03619
03620
03621
03622
03623
03624
03625
03626
03627
03628
03629 static VALUE
03630 rb_f_exit_bang(int argc, VALUE *argv, VALUE obj)
03631 {
03632 VALUE status;
03633 int istatus;
03634
03635 if (argc > 0 && rb_scan_args(argc, argv, "01", &status) == 1) {
03636 istatus = exit_status_code(status);
03637 }
03638 else {
03639 istatus = EXIT_FAILURE;
03640 }
03641 _exit(istatus);
03642
03643 UNREACHABLE;
03644 }
03645
03646 void
03647 rb_exit(int status)
03648 {
03649 if (GET_THREAD()->tag) {
03650 VALUE args[2];
03651
03652 args[0] = INT2NUM(status);
03653 args[1] = rb_str_new2("exit");
03654 rb_exc_raise(rb_class_new_instance(2, args, rb_eSystemExit));
03655 }
03656 ruby_finalize();
03657 exit(status);
03658 }
03659
03660
03661
03662
03663
03664
03665
03666
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 VALUE
03703 rb_f_exit(int argc, VALUE *argv)
03704 {
03705 VALUE status;
03706 int istatus;
03707
03708 if (argc > 0 && rb_scan_args(argc, argv, "01", &status) == 1) {
03709 istatus = exit_status_code(status);
03710 }
03711 else {
03712 istatus = EXIT_SUCCESS;
03713 }
03714 rb_exit(istatus);
03715
03716 UNREACHABLE;
03717 }
03718
03719
03720
03721
03722
03723
03724
03725
03726
03727
03728
03729
03730
03731 VALUE
03732 rb_f_abort(int argc, VALUE *argv)
03733 {
03734 if (argc == 0) {
03735 if (!NIL_P(GET_THREAD()->errinfo)) {
03736 ruby_error_print();
03737 }
03738 rb_exit(EXIT_FAILURE);
03739 }
03740 else {
03741 VALUE args[2];
03742
03743 rb_scan_args(argc, argv, "1", &args[1]);
03744 StringValue(argv[0]);
03745 rb_io_puts(argc, argv, rb_stderr);
03746 args[0] = INT2NUM(EXIT_FAILURE);
03747 rb_exc_raise(rb_class_new_instance(2, args, rb_eSystemExit));
03748 }
03749
03750 UNREACHABLE;
03751 }
03752
03753 void
03754 rb_syswait(rb_pid_t pid)
03755 {
03756 int status;
03757
03758 rb_waitpid(pid, &status, 0);
03759 }
03760
03761 static rb_pid_t
03762 rb_spawn_process(struct rb_execarg *eargp, char *errmsg, size_t errmsg_buflen)
03763 {
03764 rb_pid_t pid;
03765 #if !USE_SPAWNV
03766 int status;
03767 #endif
03768 #if !defined HAVE_FORK || USE_SPAWNV
03769 VALUE prog;
03770 struct rb_execarg sarg;
03771 #endif
03772
03773 #if defined HAVE_FORK && !USE_SPAWNV
03774 pid = rb_fork_async_signal_safe(&status, rb_exec_atfork, eargp, eargp->redirect_fds, errmsg, errmsg_buflen);
03775 #else
03776 prog = eargp->use_shell ? eargp->invoke.sh.shell_script : eargp->invoke.cmd.command_name;
03777
03778 if (rb_execarg_run_options(eargp, &sarg, errmsg, errmsg_buflen) < 0) {
03779 return -1;
03780 }
03781
03782 if (prog && !eargp->use_shell) {
03783 char **argv = ARGVSTR2ARGV(eargp->invoke.cmd.argv_str);
03784 argv[0] = RSTRING_PTR(prog);
03785 }
03786 # if defined HAVE_SPAWNV
03787 if (eargp->use_shell) {
03788 pid = proc_spawn_sh(RSTRING_PTR(prog));
03789 }
03790 else {
03791 char **argv = ARGVSTR2ARGV(eargp->invoke.cmd.argv_str);
03792 pid = proc_spawn_cmd(argv, prog, eargp);
03793 }
03794 if (pid == -1)
03795 rb_last_status_set(0x7f << 8, 0);
03796 # else
03797 if (!eargp->use_shell) {
03798 char **argv = ARGVSTR2ARGV(eargp->invoke.cmd.argv_str);
03799 int argc = ARGVSTR2ARGC(eargp->invoke.cmd.argv_str);
03800 prog = rb_ary_join(rb_ary_new4(argc, argv), rb_str_new2(" "));
03801 }
03802 status = system(StringValuePtr(prog));
03803 rb_last_status_set((status & 0xff) << 8, 0);
03804 # endif
03805
03806 rb_execarg_run_options(&sarg, NULL, errmsg, errmsg_buflen);
03807 #endif
03808 return pid;
03809 }
03810
03811 static rb_pid_t
03812 rb_spawn_internal(int argc, VALUE *argv, char *errmsg, size_t errmsg_buflen)
03813 {
03814 VALUE execarg_obj;
03815 struct rb_execarg *eargp;
03816 rb_pid_t ret;
03817
03818 execarg_obj = rb_execarg_new(argc, argv, TRUE);
03819 eargp = rb_execarg_get(execarg_obj);
03820 rb_execarg_fixup(execarg_obj);
03821 ret = rb_spawn_process(eargp, errmsg, errmsg_buflen);
03822 RB_GC_GUARD(execarg_obj);
03823 return ret;
03824 }
03825
03826 rb_pid_t
03827 rb_spawn_err(int argc, VALUE *argv, char *errmsg, size_t errmsg_buflen)
03828 {
03829 return rb_spawn_internal(argc, argv, errmsg, errmsg_buflen);
03830 }
03831
03832 rb_pid_t
03833 rb_spawn(int argc, VALUE *argv)
03834 {
03835 return rb_spawn_internal(argc, argv, NULL, 0);
03836 }
03837
03838
03839
03840
03841
03842
03843
03844
03845
03846
03847
03848
03849
03850
03851
03852
03853
03854
03855
03856
03857
03858
03859
03860
03861
03862
03863
03864
03865
03866
03867
03868
03869
03870
03871 static VALUE
03872 rb_f_system(int argc, VALUE *argv)
03873 {
03874 rb_pid_t pid;
03875 int status;
03876
03877 #if defined(SIGCLD) && !defined(SIGCHLD)
03878 # define SIGCHLD SIGCLD
03879 #endif
03880
03881 #ifdef SIGCHLD
03882 RETSIGTYPE (*chfunc)(int);
03883
03884 rb_last_status_clear();
03885 chfunc = signal(SIGCHLD, SIG_DFL);
03886 #endif
03887 pid = rb_spawn_internal(argc, argv, NULL, 0);
03888 #if defined(HAVE_FORK) || defined(HAVE_SPAWNV)
03889 if (pid > 0) {
03890 int ret, status;
03891 ret = rb_waitpid(pid, &status, 0);
03892 if (ret == (rb_pid_t)-1)
03893 rb_sys_fail("Another thread waited the process started by system().");
03894 }
03895 #endif
03896 #ifdef SIGCHLD
03897 signal(SIGCHLD, chfunc);
03898 #endif
03899 if (pid < 0) {
03900 return Qnil;
03901 }
03902 status = PST2INT(rb_last_status_get());
03903 if (status == EXIT_SUCCESS) return Qtrue;
03904 return Qfalse;
03905 }
03906
03907
03908
03909
03910
03911
03912
03913
03914
03915
03916
03917
03918
03919
03920
03921
03922
03923
03924
03925
03926
03927
03928
03929
03930
03931
03932
03933
03934
03935
03936
03937
03938
03939
03940
03941
03942
03943
03944
03945
03946
03947
03948
03949
03950
03951
03952
03953
03954
03955
03956
03957
03958
03959
03960
03961
03962
03963
03964
03965
03966
03967
03968
03969
03970
03971
03972
03973
03974
03975
03976
03977
03978
03979
03980
03981
03982
03983
03984
03985
03986
03987
03988
03989
03990
03991
03992
03993
03994
03995
03996
03997
03998
03999
04000
04001
04002
04003
04004
04005
04006
04007
04008
04009
04010
04011
04012
04013
04014
04015
04016
04017
04018
04019
04020
04021
04022
04023
04024
04025
04026
04027
04028
04029
04030
04031
04032
04033
04034
04035
04036
04037
04038
04039
04040
04041
04042
04043
04044
04045
04046
04047
04048
04049
04050
04051
04052
04053
04054
04055
04056
04057
04058
04059
04060
04061
04062
04063
04064
04065
04066
04067
04068
04069
04070
04071
04072
04073
04074
04075
04076
04077
04078
04079
04080
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 static VALUE
04173 rb_f_spawn(int argc, VALUE *argv)
04174 {
04175 rb_pid_t pid;
04176 char errmsg[CHILD_ERRMSG_BUFLEN] = { '\0' };
04177 VALUE execarg_obj, fail_str;
04178 struct rb_execarg *eargp;
04179
04180 execarg_obj = rb_execarg_new(argc, argv, TRUE);
04181 eargp = rb_execarg_get(execarg_obj);
04182 rb_execarg_fixup(execarg_obj);
04183 fail_str = eargp->use_shell ? eargp->invoke.sh.shell_script : eargp->invoke.cmd.command_name;
04184
04185 pid = rb_spawn_process(eargp, errmsg, sizeof(errmsg));
04186 RB_GC_GUARD(execarg_obj);
04187
04188 if (pid == -1) {
04189 const char *prog = errmsg;
04190 if (!prog[0]) {
04191 rb_sys_fail_str(fail_str);
04192 }
04193 rb_sys_fail(prog);
04194 }
04195 #if defined(HAVE_FORK) || defined(HAVE_SPAWNV)
04196 return PIDT2NUM(pid);
04197 #else
04198 return Qnil;
04199 #endif
04200 }
04201
04202
04203
04204
04205
04206
04207
04208
04209
04210
04211
04212
04213
04214
04215
04216
04217
04218
04219 static VALUE
04220 rb_f_sleep(int argc, VALUE *argv)
04221 {
04222 time_t beg, end;
04223
04224 beg = time(0);
04225 if (argc == 0) {
04226 rb_thread_sleep_forever();
04227 }
04228 else {
04229 rb_check_arity(argc, 0, 1);
04230 rb_thread_wait_for(rb_time_interval(argv[0]));
04231 }
04232
04233 end = time(0) - beg;
04234
04235 return INT2FIX(end);
04236 }
04237
04238
04239 #if (defined(HAVE_GETPGRP) && defined(GETPGRP_VOID)) || defined(HAVE_GETPGID)
04240
04241
04242
04243
04244
04245
04246
04247
04248
04249
04250
04251 static VALUE
04252 proc_getpgrp(void)
04253 {
04254 rb_pid_t pgrp;
04255
04256 rb_secure(2);
04257 #if defined(HAVE_GETPGRP) && defined(GETPGRP_VOID)
04258 pgrp = getpgrp();
04259 if (pgrp < 0) rb_sys_fail(0);
04260 return PIDT2NUM(pgrp);
04261 #else
04262 pgrp = getpgid(0);
04263 if (pgrp < 0) rb_sys_fail(0);
04264 return PIDT2NUM(pgrp);
04265 #endif
04266 }
04267 #else
04268 #define proc_getpgrp rb_f_notimplement
04269 #endif
04270
04271
04272 #if defined(HAVE_SETPGID) || (defined(HAVE_SETPGRP) && defined(SETPGRP_VOID))
04273
04274
04275
04276
04277
04278
04279
04280
04281 static VALUE
04282 proc_setpgrp(void)
04283 {
04284 rb_secure(2);
04285
04286
04287
04288
04289 #ifdef HAVE_SETPGID
04290 if (setpgid(0,0) < 0) rb_sys_fail(0);
04291 #elif defined(HAVE_SETPGRP) && defined(SETPGRP_VOID)
04292 if (setpgrp() < 0) rb_sys_fail(0);
04293 #endif
04294 return INT2FIX(0);
04295 }
04296 #else
04297 #define proc_setpgrp rb_f_notimplement
04298 #endif
04299
04300
04301 #if defined(HAVE_GETPGID)
04302
04303
04304
04305
04306
04307
04308
04309
04310
04311
04312 static VALUE
04313 proc_getpgid(VALUE obj, VALUE pid)
04314 {
04315 rb_pid_t i;
04316
04317 rb_secure(2);
04318 i = getpgid(NUM2PIDT(pid));
04319 if (i < 0) rb_sys_fail(0);
04320 return PIDT2NUM(i);
04321 }
04322 #else
04323 #define proc_getpgid rb_f_notimplement
04324 #endif
04325
04326
04327 #ifdef HAVE_SETPGID
04328
04329
04330
04331
04332
04333
04334
04335
04336 static VALUE
04337 proc_setpgid(VALUE obj, VALUE pid, VALUE pgrp)
04338 {
04339 rb_pid_t ipid, ipgrp;
04340
04341 rb_secure(2);
04342 ipid = NUM2PIDT(pid);
04343 ipgrp = NUM2PIDT(pgrp);
04344
04345 if (setpgid(ipid, ipgrp) < 0) rb_sys_fail(0);
04346 return INT2FIX(0);
04347 }
04348 #else
04349 #define proc_setpgid rb_f_notimplement
04350 #endif
04351
04352
04353 #ifdef HAVE_GETSID
04354
04355
04356
04357
04358
04359
04360
04361
04362
04363
04364
04365
04366 static VALUE
04367 proc_getsid(int argc, VALUE *argv)
04368 {
04369 rb_pid_t sid;
04370 VALUE pid;
04371
04372 rb_secure(2);
04373 rb_scan_args(argc, argv, "01", &pid);
04374
04375 if (NIL_P(pid))
04376 pid = INT2FIX(0);
04377
04378 sid = getsid(NUM2PIDT(pid));
04379 if (sid < 0) rb_sys_fail(0);
04380 return PIDT2NUM(sid);
04381 }
04382 #else
04383 #define proc_getsid rb_f_notimplement
04384 #endif
04385
04386
04387 #if defined(HAVE_SETSID) || (defined(HAVE_SETPGRP) && defined(TIOCNOTTY))
04388 #if !defined(HAVE_SETSID)
04389 static rb_pid_t ruby_setsid(void);
04390 #define setsid() ruby_setsid()
04391 #endif
04392
04393
04394
04395
04396
04397
04398
04399
04400
04401
04402
04403 static VALUE
04404 proc_setsid(void)
04405 {
04406 rb_pid_t pid;
04407
04408 rb_secure(2);
04409 pid = setsid();
04410 if (pid < 0) rb_sys_fail(0);
04411 return PIDT2NUM(pid);
04412 }
04413
04414 #if !defined(HAVE_SETSID)
04415 #define HAVE_SETSID 1
04416 static rb_pid_t
04417 ruby_setsid(void)
04418 {
04419 rb_pid_t pid;
04420 int ret;
04421
04422 pid = getpid();
04423 #if defined(SETPGRP_VOID)
04424 ret = setpgrp();
04425
04426
04427
04428 #else
04429 ret = setpgrp(0, pid);
04430 #endif
04431 if (ret == -1) return -1;
04432
04433 if ((fd = rb_cloexec_open("/dev/tty", O_RDWR, 0)) >= 0) {
04434 rb_update_max_fd(fd);
04435 ioctl(fd, TIOCNOTTY, NULL);
04436 close(fd);
04437 }
04438 return pid;
04439 }
04440 #endif
04441 #else
04442 #define proc_setsid rb_f_notimplement
04443 #endif
04444
04445
04446 #ifdef HAVE_GETPRIORITY
04447
04448
04449
04450
04451
04452
04453
04454
04455
04456
04457
04458
04459
04460
04461
04462
04463
04464 static VALUE
04465 proc_getpriority(VALUE obj, VALUE which, VALUE who)
04466 {
04467 int prio, iwhich, iwho;
04468
04469 rb_secure(2);
04470 iwhich = NUM2INT(which);
04471 iwho = NUM2INT(who);
04472
04473 errno = 0;
04474 prio = getpriority(iwhich, iwho);
04475 if (errno) rb_sys_fail(0);
04476 return INT2FIX(prio);
04477 }
04478 #else
04479 #define proc_getpriority rb_f_notimplement
04480 #endif
04481
04482
04483 #ifdef HAVE_GETPRIORITY
04484
04485
04486
04487
04488
04489
04490
04491
04492
04493
04494
04495
04496 static VALUE
04497 proc_setpriority(VALUE obj, VALUE which, VALUE who, VALUE prio)
04498 {
04499 int iwhich, iwho, iprio;
04500
04501 rb_secure(2);
04502 iwhich = NUM2INT(which);
04503 iwho = NUM2INT(who);
04504 iprio = NUM2INT(prio);
04505
04506 if (setpriority(iwhich, iwho, iprio) < 0)
04507 rb_sys_fail(0);
04508 return INT2FIX(0);
04509 }
04510 #else
04511 #define proc_setpriority rb_f_notimplement
04512 #endif
04513
04514 #if defined(HAVE_SETRLIMIT) && defined(NUM2RLIM)
04515 static int
04516 rlimit_resource_name2int(const char *name, int casetype)
04517 {
04518 int resource;
04519 const char *p;
04520 #define RESCHECK(r) \
04521 do { \
04522 if (STRCASECMP(name, #r) == 0) { \
04523 resource = RLIMIT_##r; \
04524 goto found; \
04525 } \
04526 } while (0)
04527
04528 switch (TOUPPER(*name)) {
04529 case 'A':
04530 #ifdef RLIMIT_AS
04531 RESCHECK(AS);
04532 #endif
04533 break;
04534
04535 case 'C':
04536 #ifdef RLIMIT_CORE
04537 RESCHECK(CORE);
04538 #endif
04539 #ifdef RLIMIT_CPU
04540 RESCHECK(CPU);
04541 #endif
04542 break;
04543
04544 case 'D':
04545 #ifdef RLIMIT_DATA
04546 RESCHECK(DATA);
04547 #endif
04548 break;
04549
04550 case 'F':
04551 #ifdef RLIMIT_FSIZE
04552 RESCHECK(FSIZE);
04553 #endif
04554 break;
04555
04556 case 'M':
04557 #ifdef RLIMIT_MEMLOCK
04558 RESCHECK(MEMLOCK);
04559 #endif
04560 #ifdef RLIMIT_MSGQUEUE
04561 RESCHECK(MSGQUEUE);
04562 #endif
04563 break;
04564
04565 case 'N':
04566 #ifdef RLIMIT_NOFILE
04567 RESCHECK(NOFILE);
04568 #endif
04569 #ifdef RLIMIT_NPROC
04570 RESCHECK(NPROC);
04571 #endif
04572 #ifdef RLIMIT_NICE
04573 RESCHECK(NICE);
04574 #endif
04575 break;
04576
04577 case 'R':
04578 #ifdef RLIMIT_RSS
04579 RESCHECK(RSS);
04580 #endif
04581 #ifdef RLIMIT_RTPRIO
04582 RESCHECK(RTPRIO);
04583 #endif
04584 #ifdef RLIMIT_RTTIME
04585 RESCHECK(RTTIME);
04586 #endif
04587 break;
04588
04589 case 'S':
04590 #ifdef RLIMIT_STACK
04591 RESCHECK(STACK);
04592 #endif
04593 #ifdef RLIMIT_SBSIZE
04594 RESCHECK(SBSIZE);
04595 #endif
04596 #ifdef RLIMIT_SIGPENDING
04597 RESCHECK(SIGPENDING);
04598 #endif
04599 break;
04600 }
04601 return -1;
04602
04603 found:
04604 switch (casetype) {
04605 case 0:
04606 for (p = name; *p; p++)
04607 if (!ISUPPER(*p))
04608 return -1;
04609 break;
04610
04611 case 1:
04612 for (p = name; *p; p++)
04613 if (!ISLOWER(*p))
04614 return -1;
04615 break;
04616
04617 default:
04618 rb_bug("unexpected casetype");
04619 }
04620 return resource;
04621 #undef RESCHECK
04622 }
04623
04624 static int
04625 rlimit_type_by_hname(const char *name)
04626 {
04627 return rlimit_resource_name2int(name, 0);
04628 }
04629
04630 static int
04631 rlimit_type_by_lname(const char *name)
04632 {
04633 return rlimit_resource_name2int(name, 1);
04634 }
04635
04636 static int
04637 rlimit_resource_type(VALUE rtype)
04638 {
04639 const char *name;
04640 VALUE v;
04641 int r;
04642
04643 switch (TYPE(rtype)) {
04644 case T_SYMBOL:
04645 name = rb_id2name(SYM2ID(rtype));
04646 break;
04647
04648 default:
04649 v = rb_check_string_type(rtype);
04650 if (!NIL_P(v)) {
04651 rtype = v;
04652 case T_STRING:
04653 name = StringValueCStr(rtype);
04654 break;
04655 }
04656
04657
04658 case T_FIXNUM:
04659 case T_BIGNUM:
04660 return NUM2INT(rtype);
04661 }
04662
04663 r = rlimit_type_by_hname(name);
04664 if (r != -1)
04665 return r;
04666
04667 rb_raise(rb_eArgError, "invalid resource name: %s", name);
04668
04669 UNREACHABLE;
04670 }
04671
04672 static rlim_t
04673 rlimit_resource_value(VALUE rval)
04674 {
04675 const char *name;
04676 VALUE v;
04677
04678 switch (TYPE(rval)) {
04679 case T_SYMBOL:
04680 name = rb_id2name(SYM2ID(rval));
04681 break;
04682
04683 default:
04684 v = rb_check_string_type(rval);
04685 if (!NIL_P(v)) {
04686 rval = v;
04687 case T_STRING:
04688 name = StringValueCStr(rval);
04689 break;
04690 }
04691
04692
04693 case T_FIXNUM:
04694 case T_BIGNUM:
04695 return NUM2RLIM(rval);
04696 }
04697
04698 #ifdef RLIM_INFINITY
04699 if (strcmp(name, "INFINITY") == 0) return RLIM_INFINITY;
04700 #endif
04701 #ifdef RLIM_SAVED_MAX
04702 if (strcmp(name, "SAVED_MAX") == 0) return RLIM_SAVED_MAX;
04703 #endif
04704 #ifdef RLIM_SAVED_CUR
04705 if (strcmp(name, "SAVED_CUR") == 0) return RLIM_SAVED_CUR;
04706 #endif
04707 rb_raise(rb_eArgError, "invalid resource value: %s", name);
04708
04709 UNREACHABLE;
04710 }
04711 #endif
04712
04713 #if defined(HAVE_GETRLIMIT) && defined(RLIM2NUM)
04714
04715
04716
04717
04718
04719
04720
04721
04722
04723
04724
04725
04726
04727
04728
04729
04730
04731
04732
04733
04734 static VALUE
04735 proc_getrlimit(VALUE obj, VALUE resource)
04736 {
04737 struct rlimit rlim;
04738
04739 rb_secure(2);
04740
04741 if (getrlimit(rlimit_resource_type(resource), &rlim) < 0) {
04742 rb_sys_fail("getrlimit");
04743 }
04744 return rb_assoc_new(RLIM2NUM(rlim.rlim_cur), RLIM2NUM(rlim.rlim_max));
04745 }
04746 #else
04747 #define proc_getrlimit rb_f_notimplement
04748 #endif
04749
04750 #if defined(HAVE_SETRLIMIT) && defined(NUM2RLIM)
04751
04752
04753
04754
04755
04756
04757
04758
04759
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 static VALUE
04803 proc_setrlimit(int argc, VALUE *argv, VALUE obj)
04804 {
04805 VALUE resource, rlim_cur, rlim_max;
04806 struct rlimit rlim;
04807
04808 rb_secure(2);
04809
04810 rb_scan_args(argc, argv, "21", &resource, &rlim_cur, &rlim_max);
04811 if (rlim_max == Qnil)
04812 rlim_max = rlim_cur;
04813
04814 rlim.rlim_cur = rlimit_resource_value(rlim_cur);
04815 rlim.rlim_max = rlimit_resource_value(rlim_max);
04816
04817 if (setrlimit(rlimit_resource_type(resource), &rlim) < 0) {
04818 rb_sys_fail("setrlimit");
04819 }
04820 return Qnil;
04821 }
04822 #else
04823 #define proc_setrlimit rb_f_notimplement
04824 #endif
04825
04826 static int under_uid_switch = 0;
04827 static void
04828 check_uid_switch(void)
04829 {
04830 rb_secure(2);
04831 if (under_uid_switch) {
04832 rb_raise(rb_eRuntimeError, "can't handle UID while evaluating block given to Process::UID.switch method");
04833 }
04834 }
04835
04836 static int under_gid_switch = 0;
04837 static void
04838 check_gid_switch(void)
04839 {
04840 rb_secure(2);
04841 if (under_gid_switch) {
04842 rb_raise(rb_eRuntimeError, "can't handle GID while evaluating block given to Process::UID.switch method");
04843 }
04844 }
04845
04846
04847
04848
04849
04850
04851
04852
04853
04854
04855
04856
04857 #if defined(HAVE_PWD_H)
04858 static rb_uid_t
04859 obj2uid(VALUE id
04860 # ifdef USE_GETPWNAM_R
04861 , VALUE *getpw_tmp
04862 # endif
04863 )
04864 {
04865 rb_uid_t uid;
04866 VALUE tmp;
04867
04868 if (FIXNUM_P(id) || NIL_P(tmp = rb_check_string_type(id))) {
04869 uid = NUM2UIDT(id);
04870 }
04871 else {
04872 const char *usrname = StringValueCStr(id);
04873 struct passwd *pwptr;
04874 #ifdef USE_GETPWNAM_R
04875 struct passwd pwbuf;
04876 char *getpw_buf;
04877 long getpw_buf_len;
04878 if (!*getpw_tmp) {
04879 getpw_buf_len = GETPW_R_SIZE_INIT;
04880 if (getpw_buf_len < 0) getpw_buf_len = GETPW_R_SIZE_DEFAULT;
04881 getpw_buf = rb_alloc_tmp_buffer(getpw_tmp, getpw_buf_len);
04882 }
04883 else {
04884 getpw_buf = RSTRING_PTR(*getpw_tmp);
04885 getpw_buf_len = rb_str_capacity(*getpw_tmp);
04886 }
04887 errno = ERANGE;
04888
04889 while (getpwnam_r(usrname, &pwbuf, getpw_buf, getpw_buf_len, &pwptr)) {
04890 if (errno != ERANGE || getpw_buf_len >= GETPW_R_SIZE_LIMIT) {
04891 rb_free_tmp_buffer(getpw_tmp);
04892 rb_sys_fail("getpwnam_r");
04893 }
04894 rb_str_modify_expand(*getpw_tmp, getpw_buf_len);
04895 getpw_buf = RSTRING_PTR(*getpw_tmp);
04896 getpw_buf_len = rb_str_capacity(*getpw_tmp);
04897 }
04898 #else
04899 pwptr = getpwnam(usrname);
04900 #endif
04901 if (!pwptr) {
04902 #ifndef USE_GETPWNAM_R
04903 endpwent();
04904 #endif
04905 rb_raise(rb_eArgError, "can't find user for %s", usrname);
04906 }
04907 uid = pwptr->pw_uid;
04908 #ifndef USE_GETPWNAM_R
04909 endpwent();
04910 #endif
04911 }
04912 return uid;
04913 }
04914
04915 # ifdef p_uid_from_name
04916
04917
04918
04919
04920
04921
04922
04923
04924
04925
04926
04927 static VALUE
04928 p_uid_from_name(VALUE self, VALUE id)
04929 {
04930 return UIDT2NUM(OBJ2UID(id));
04931 }
04932 # endif
04933 #endif
04934
04935 #if defined(HAVE_GRP_H)
04936 static rb_gid_t
04937 obj2gid(VALUE id
04938 # ifdef USE_GETGRNAM_R
04939 , VALUE *getgr_tmp
04940 # endif
04941 )
04942 {
04943 rb_gid_t gid;
04944 VALUE tmp;
04945
04946 if (FIXNUM_P(id) || NIL_P(tmp = rb_check_string_type(id))) {
04947 gid = NUM2GIDT(id);
04948 }
04949 else {
04950 const char *grpname = StringValueCStr(id);
04951 struct group *grptr;
04952 #ifdef USE_GETGRNAM_R
04953 struct group grbuf;
04954 char *getgr_buf;
04955 long getgr_buf_len;
04956 if (!*getgr_tmp) {
04957 getgr_buf_len = GETGR_R_SIZE_INIT;
04958 if (getgr_buf_len < 0) getgr_buf_len = GETGR_R_SIZE_DEFAULT;
04959 getgr_buf = rb_alloc_tmp_buffer(getgr_tmp, getgr_buf_len);
04960 }
04961 else {
04962 getgr_buf = RSTRING_PTR(*getgr_tmp);
04963 getgr_buf_len = rb_str_capacity(*getgr_tmp);
04964 }
04965 errno = ERANGE;
04966
04967 while (getgrnam_r(grpname, &grbuf, getgr_buf, getgr_buf_len, &grptr)) {
04968 if (errno != ERANGE || getgr_buf_len >= GETGR_R_SIZE_LIMIT) {
04969 rb_free_tmp_buffer(getgr_tmp);
04970 rb_sys_fail("getgrnam_r");
04971 }
04972 rb_str_modify_expand(*getgr_tmp, getgr_buf_len);
04973 getgr_buf = RSTRING_PTR(*getgr_tmp);
04974 getgr_buf_len = rb_str_capacity(*getgr_tmp);
04975 }
04976 #else
04977 grptr = getgrnam(grpname);
04978 #endif
04979 if (!grptr) {
04980 #if !defined(USE_GETGRNAM_R) && defined(HAVE_ENDGRENT)
04981 endgrent();
04982 #endif
04983 rb_raise(rb_eArgError, "can't find group for %s", grpname);
04984 }
04985 gid = grptr->gr_gid;
04986 #if !defined(USE_GETGRNAM_R) && defined(HAVE_ENDGRENT)
04987 endgrent();
04988 #endif
04989 }
04990 return gid;
04991 }
04992
04993 # ifdef p_gid_from_name
04994
04995
04996
04997
04998
04999
05000
05001
05002
05003
05004
05005 static VALUE
05006 p_gid_from_name(VALUE self, VALUE id)
05007 {
05008 return GIDT2NUM(OBJ2GID(id));
05009 }
05010 # endif
05011 #endif
05012
05013 #if defined HAVE_SETUID
05014
05015
05016
05017
05018
05019
05020
05021
05022
05023 static VALUE
05024 p_sys_setuid(VALUE obj, VALUE id)
05025 {
05026 check_uid_switch();
05027 if (setuid(OBJ2UID(id)) != 0) rb_sys_fail(0);
05028 return Qnil;
05029 }
05030 #else
05031 #define p_sys_setuid rb_f_notimplement
05032 #endif
05033
05034
05035 #if defined HAVE_SETRUID
05036
05037
05038
05039
05040
05041
05042
05043
05044
05045 static VALUE
05046 p_sys_setruid(VALUE obj, VALUE id)
05047 {
05048 check_uid_switch();
05049 if (setruid(OBJ2UID(id)) != 0) rb_sys_fail(0);
05050 return Qnil;
05051 }
05052 #else
05053 #define p_sys_setruid rb_f_notimplement
05054 #endif
05055
05056
05057 #if defined HAVE_SETEUID
05058
05059
05060
05061
05062
05063
05064
05065
05066
05067 static VALUE
05068 p_sys_seteuid(VALUE obj, VALUE id)
05069 {
05070 check_uid_switch();
05071 if (seteuid(OBJ2UID(id)) != 0) rb_sys_fail(0);
05072 return Qnil;
05073 }
05074 #else
05075 #define p_sys_seteuid rb_f_notimplement
05076 #endif
05077
05078
05079 #if defined HAVE_SETREUID
05080
05081
05082
05083
05084
05085
05086
05087
05088
05089
05090
05091 static VALUE
05092 p_sys_setreuid(VALUE obj, VALUE rid, VALUE eid)
05093 {
05094 rb_uid_t ruid, euid;
05095 PREPARE_GETPWNAM;
05096 check_uid_switch();
05097 ruid = OBJ2UID1(rid);
05098 euid = OBJ2UID1(eid);
05099 FINISH_GETPWNAM;
05100 if (setreuid(ruid, euid) != 0) rb_sys_fail(0);
05101 return Qnil;
05102 }
05103 #else
05104 #define p_sys_setreuid rb_f_notimplement
05105 #endif
05106
05107
05108 #if defined HAVE_SETRESUID
05109
05110
05111
05112
05113
05114
05115
05116
05117
05118
05119
05120 static VALUE
05121 p_sys_setresuid(VALUE obj, VALUE rid, VALUE eid, VALUE sid)
05122 {
05123 rb_uid_t ruid, euid, suid;
05124 PREPARE_GETPWNAM;
05125 check_uid_switch();
05126 ruid = OBJ2UID1(rid);
05127 euid = OBJ2UID1(eid);
05128 suid = OBJ2UID1(sid);
05129 FINISH_GETPWNAM;
05130 if (setresuid(ruid, euid, suid) != 0) rb_sys_fail(0);
05131 return Qnil;
05132 }
05133 #else
05134 #define p_sys_setresuid rb_f_notimplement
05135 #endif
05136
05137
05138
05139
05140
05141
05142
05143
05144
05145
05146
05147
05148
05149 static VALUE
05150 proc_getuid(VALUE obj)
05151 {
05152 rb_uid_t uid = getuid();
05153 return UIDT2NUM(uid);
05154 }
05155
05156
05157 #if defined(HAVE_SETRESUID) || defined(HAVE_SETREUID) || defined(HAVE_SETRUID) || defined(HAVE_SETUID)
05158
05159
05160
05161
05162
05163
05164
05165
05166 static VALUE
05167 proc_setuid(VALUE obj, VALUE id)
05168 {
05169 rb_uid_t uid;
05170
05171 check_uid_switch();
05172
05173 uid = OBJ2UID(id);
05174 #if defined(HAVE_SETRESUID)
05175 if (setresuid(uid, -1, -1) < 0) rb_sys_fail(0);
05176 #elif defined HAVE_SETREUID
05177 if (setreuid(uid, -1) < 0) rb_sys_fail(0);
05178 #elif defined HAVE_SETRUID
05179 if (setruid(uid) < 0) rb_sys_fail(0);
05180 #elif defined HAVE_SETUID
05181 {
05182 if (geteuid() == uid) {
05183 if (setuid(uid) < 0) rb_sys_fail(0);
05184 }
05185 else {
05186 rb_notimplement();
05187 }
05188 }
05189 #endif
05190 return id;
05191 }
05192 #else
05193 #define proc_setuid rb_f_notimplement
05194 #endif
05195
05196
05197
05198
05199
05200
05201
05202
05203
05204
05205
05206
05207 static rb_uid_t SAVED_USER_ID = -1;
05208
05209 #ifdef BROKEN_SETREUID
05210 int
05211 setreuid(rb_uid_t ruid, rb_uid_t euid)
05212 {
05213 if (ruid != (rb_uid_t)-1 && ruid != getuid()) {
05214 if (euid == (rb_uid_t)-1) euid = geteuid();
05215 if (setuid(ruid) < 0) return -1;
05216 }
05217 if (euid != (rb_uid_t)-1 && euid != geteuid()) {
05218 if (seteuid(euid) < 0) return -1;
05219 }
05220 return 0;
05221 }
05222 #endif
05223
05224
05225
05226
05227
05228
05229
05230
05231
05232
05233
05234
05235
05236
05237 static VALUE
05238 p_uid_change_privilege(VALUE obj, VALUE id)
05239 {
05240 rb_uid_t uid;
05241
05242 check_uid_switch();
05243
05244 uid = OBJ2UID(id);
05245
05246 if (geteuid() == 0) {
05247 #if defined(HAVE_SETRESUID)
05248 if (setresuid(uid, uid, uid) < 0) rb_sys_fail(0);
05249 SAVED_USER_ID = uid;
05250 #elif defined(HAVE_SETUID)
05251 if (setuid(uid) < 0) rb_sys_fail(0);
05252 SAVED_USER_ID = uid;
05253 #elif defined(HAVE_SETREUID) && !defined(OBSOLETE_SETREUID)
05254 if (getuid() == uid) {
05255 if (SAVED_USER_ID == uid) {
05256 if (setreuid(-1, uid) < 0) rb_sys_fail(0);
05257 }
05258 else {
05259 if (uid == 0) {
05260 if (setreuid(-1, SAVED_USER_ID) < 0) rb_sys_fail(0);
05261 if (setreuid(SAVED_USER_ID, 0) < 0) rb_sys_fail(0);
05262 SAVED_USER_ID = 0;
05263 if (setreuid(uid, uid) < 0) rb_sys_fail(0);
05264 SAVED_USER_ID = uid;
05265 }
05266 else {
05267 if (setreuid(0, -1) < 0) rb_sys_fail(0);
05268 SAVED_USER_ID = 0;
05269 if (setreuid(uid, uid) < 0) rb_sys_fail(0);
05270 SAVED_USER_ID = uid;
05271 }
05272 }
05273 }
05274 else {
05275 if (setreuid(uid, uid) < 0) rb_sys_fail(0);
05276 SAVED_USER_ID = uid;
05277 }
05278 #elif defined(HAVE_SETRUID) && defined(HAVE_SETEUID)
05279 if (getuid() == uid) {
05280 if (SAVED_USER_ID == uid) {
05281 if (seteuid(uid) < 0) rb_sys_fail(0);
05282 }
05283 else {
05284 if (uid == 0) {
05285 if (setruid(SAVED_USER_ID) < 0) rb_sys_fail(0);
05286 SAVED_USER_ID = 0;
05287 if (setruid(0) < 0) rb_sys_fail(0);
05288 }
05289 else {
05290 if (setruid(0) < 0) rb_sys_fail(0);
05291 SAVED_USER_ID = 0;
05292 if (seteuid(uid) < 0) rb_sys_fail(0);
05293 if (setruid(uid) < 0) rb_sys_fail(0);
05294 SAVED_USER_ID = uid;
05295 }
05296 }
05297 }
05298 else {
05299 if (seteuid(uid) < 0) rb_sys_fail(0);
05300 if (setruid(uid) < 0) rb_sys_fail(0);
05301 SAVED_USER_ID = uid;
05302 }
05303 #else
05304 (void)uid;
05305 rb_notimplement();
05306 #endif
05307 }
05308 else {
05309 #if defined(HAVE_SETRESUID)
05310 if (setresuid((getuid() == uid)? (rb_uid_t)-1: uid,
05311 (geteuid() == uid)? (rb_uid_t)-1: uid,
05312 (SAVED_USER_ID == uid)? (rb_uid_t)-1: uid) < 0) rb_sys_fail(0);
05313 SAVED_USER_ID = uid;
05314 #elif defined(HAVE_SETREUID) && !defined(OBSOLETE_SETREUID)
05315 if (SAVED_USER_ID == uid) {
05316 if (setreuid((getuid() == uid)? (rb_uid_t)-1: uid,
05317 (geteuid() == uid)? (rb_uid_t)-1: uid) < 0)
05318 rb_sys_fail(0);
05319 }
05320 else if (getuid() != uid) {
05321 if (setreuid(uid, (geteuid() == uid)? (rb_uid_t)-1: uid) < 0)
05322 rb_sys_fail(0);
05323 SAVED_USER_ID = uid;
05324 }
05325 else if ( geteuid() != uid) {
05326 if (setreuid(geteuid(), uid) < 0) rb_sys_fail(0);
05327 SAVED_USER_ID = uid;
05328 if (setreuid(uid, -1) < 0) rb_sys_fail(0);
05329 }
05330 else {
05331 if (setreuid(-1, SAVED_USER_ID) < 0) rb_sys_fail(0);
05332 if (setreuid(SAVED_USER_ID, uid) < 0) rb_sys_fail(0);
05333 SAVED_USER_ID = uid;
05334 if (setreuid(uid, -1) < 0) rb_sys_fail(0);
05335 }
05336 #elif defined(HAVE_SETRUID) && defined(HAVE_SETEUID)
05337 if (SAVED_USER_ID == uid) {
05338 if (geteuid() != uid && seteuid(uid) < 0) rb_sys_fail(0);
05339 if (getuid() != uid && setruid(uid) < 0) rb_sys_fail(0);
05340 }
05341 else if ( geteuid() == uid) {
05342 if (getuid() != uid) {
05343 if (setruid(uid) < 0) rb_sys_fail(0);
05344 SAVED_USER_ID = uid;
05345 }
05346 else {
05347 if (setruid(SAVED_USER_ID) < 0) rb_sys_fail(0);
05348 SAVED_USER_ID = uid;
05349 if (setruid(uid) < 0) rb_sys_fail(0);
05350 }
05351 }
05352 else if ( getuid() == uid) {
05353 if (seteuid(uid) < 0) rb_sys_fail(0);
05354 if (setruid(SAVED_USER_ID) < 0) rb_sys_fail(0);
05355 SAVED_USER_ID = uid;
05356 if (setruid(uid) < 0) rb_sys_fail(0);
05357 }
05358 else {
05359 errno = EPERM;
05360 rb_sys_fail(0);
05361 }
05362 #elif defined HAVE_44BSD_SETUID
05363 if (getuid() == uid) {
05364
05365 if (setuid(uid) < 0) rb_sys_fail(0);
05366 SAVED_USER_ID = uid;
05367 }
05368 else {
05369 errno = EPERM;
05370 rb_sys_fail(0);
05371 }
05372 #elif defined HAVE_SETEUID
05373 if (getuid() == uid && SAVED_USER_ID == uid) {
05374 if (seteuid(uid) < 0) rb_sys_fail(0);
05375 }
05376 else {
05377 errno = EPERM;
05378 rb_sys_fail(0);
05379 }
05380 #elif defined HAVE_SETUID
05381 if (getuid() == uid && SAVED_USER_ID == uid) {
05382 if (setuid(uid) < 0) rb_sys_fail(0);
05383 }
05384 else {
05385 errno = EPERM;
05386 rb_sys_fail(0);
05387 }
05388 #else
05389 rb_notimplement();
05390 #endif
05391 }
05392 return id;
05393 }
05394
05395
05396
05397 #if defined HAVE_SETGID
05398
05399
05400
05401
05402
05403
05404
05405
05406
05407 static VALUE
05408 p_sys_setgid(VALUE obj, VALUE id)
05409 {
05410 check_gid_switch();
05411 if (setgid(OBJ2GID(id)) != 0) rb_sys_fail(0);
05412 return Qnil;
05413 }
05414 #else
05415 #define p_sys_setgid rb_f_notimplement
05416 #endif
05417
05418
05419 #if defined HAVE_SETRGID
05420
05421
05422
05423
05424
05425
05426
05427
05428
05429 static VALUE
05430 p_sys_setrgid(VALUE obj, VALUE id)
05431 {
05432 check_gid_switch();
05433 if (setrgid(OBJ2GID(id)) != 0) rb_sys_fail(0);
05434 return Qnil;
05435 }
05436 #else
05437 #define p_sys_setrgid rb_f_notimplement
05438 #endif
05439
05440
05441 #if defined HAVE_SETEGID
05442
05443
05444
05445
05446
05447
05448
05449
05450
05451 static VALUE
05452 p_sys_setegid(VALUE obj, VALUE id)
05453 {
05454 check_gid_switch();
05455 if (setegid(OBJ2GID(id)) != 0) rb_sys_fail(0);
05456 return Qnil;
05457 }
05458 #else
05459 #define p_sys_setegid rb_f_notimplement
05460 #endif
05461
05462
05463 #if defined HAVE_SETREGID
05464
05465
05466
05467
05468
05469
05470
05471
05472
05473
05474
05475 static VALUE
05476 p_sys_setregid(VALUE obj, VALUE rid, VALUE eid)
05477 {
05478 rb_gid_t rgid, egid;
05479 PREPARE_GETGRNAM;
05480 check_gid_switch();
05481 rgid = OBJ2GID(rid);
05482 egid = OBJ2GID(eid);
05483 FINISH_GETGRNAM;
05484 if (setregid(rgid, egid) != 0) rb_sys_fail(0);
05485 return Qnil;
05486 }
05487 #else
05488 #define p_sys_setregid rb_f_notimplement
05489 #endif
05490
05491 #if defined HAVE_SETRESGID
05492
05493
05494
05495
05496
05497
05498
05499
05500
05501
05502
05503 static VALUE
05504 p_sys_setresgid(VALUE obj, VALUE rid, VALUE eid, VALUE sid)
05505 {
05506 rb_gid_t rgid, egid, sgid;
05507 PREPARE_GETGRNAM;
05508 check_gid_switch();
05509 rgid = OBJ2GID(rid);
05510 egid = OBJ2GID(eid);
05511 sgid = OBJ2GID(sid);
05512 FINISH_GETGRNAM;
05513 if (setresgid(rgid, egid, sgid) != 0) rb_sys_fail(0);
05514 return Qnil;
05515 }
05516 #else
05517 #define p_sys_setresgid rb_f_notimplement
05518 #endif
05519
05520
05521 #if defined HAVE_ISSETUGID
05522
05523
05524
05525
05526
05527
05528
05529
05530
05531
05532
05533
05534 static VALUE
05535 p_sys_issetugid(VALUE obj)
05536 {
05537 rb_secure(2);
05538 if (issetugid()) {
05539 return Qtrue;
05540 }
05541 else {
05542 return Qfalse;
05543 }
05544 }
05545 #else
05546 #define p_sys_issetugid rb_f_notimplement
05547 #endif
05548
05549
05550
05551
05552
05553
05554
05555
05556
05557
05558
05559
05560
05561 static VALUE
05562 proc_getgid(VALUE obj)
05563 {
05564 rb_gid_t gid = getgid();
05565 return GIDT2NUM(gid);
05566 }
05567
05568
05569 #if defined(HAVE_SETRESGID) || defined(HAVE_SETREGID) || defined(HAVE_SETRGID) || defined(HAVE_SETGID)
05570
05571
05572
05573
05574
05575
05576
05577 static VALUE
05578 proc_setgid(VALUE obj, VALUE id)
05579 {
05580 rb_gid_t gid;
05581
05582 check_gid_switch();
05583
05584 gid = OBJ2GID(id);
05585 #if defined(HAVE_SETRESGID)
05586 if (setresgid(gid, -1, -1) < 0) rb_sys_fail(0);
05587 #elif defined HAVE_SETREGID
05588 if (setregid(gid, -1) < 0) rb_sys_fail(0);
05589 #elif defined HAVE_SETRGID
05590 if (setrgid(gid) < 0) rb_sys_fail(0);
05591 #elif defined HAVE_SETGID
05592 {
05593 if (getegid() == gid) {
05594 if (setgid(gid) < 0) rb_sys_fail(0);
05595 }
05596 else {
05597 rb_notimplement();
05598 }
05599 }
05600 #endif
05601 return GIDT2NUM(gid);
05602 }
05603 #else
05604 #define proc_setgid rb_f_notimplement
05605 #endif
05606
05607
05608 #if defined(HAVE_SETGROUPS) || defined(HAVE_GETGROUPS)
05609
05610
05611
05612
05613
05614
05615
05616
05617
05618
05619
05620
05621
05622
05623
05624
05625
05626
05627
05628
05629 static int _maxgroups = -1;
05630 static int
05631 get_sc_ngroups_max(void)
05632 {
05633 #ifdef _SC_NGROUPS_MAX
05634 return (int)sysconf(_SC_NGROUPS_MAX);
05635 #elif defined(NGROUPS_MAX)
05636 return (int)NGROUPS_MAX;
05637 #else
05638 return -1;
05639 #endif
05640 }
05641 static int
05642 maxgroups(void)
05643 {
05644 if (_maxgroups < 0) {
05645 _maxgroups = get_sc_ngroups_max();
05646 if (_maxgroups < 0)
05647 _maxgroups = RB_MAX_GROUPS;
05648 }
05649
05650 return _maxgroups;
05651 }
05652 #endif
05653
05654
05655
05656 #ifdef HAVE_GETGROUPS
05657
05658
05659
05660
05661
05662
05663
05664
05665
05666
05667
05668 static VALUE
05669 proc_getgroups(VALUE obj)
05670 {
05671 VALUE ary, tmp;
05672 int i, ngroups;
05673 rb_gid_t *groups;
05674
05675 ngroups = getgroups(0, NULL);
05676 if (ngroups == -1)
05677 rb_sys_fail(0);
05678
05679 groups = ALLOCV_N(rb_gid_t, tmp, ngroups);
05680
05681 ngroups = getgroups(ngroups, groups);
05682 if (ngroups == -1)
05683 rb_sys_fail(0);
05684
05685 ary = rb_ary_new();
05686 for (i = 0; i < ngroups; i++)
05687 rb_ary_push(ary, GIDT2NUM(groups[i]));
05688
05689 ALLOCV_END(tmp);
05690
05691 return ary;
05692 }
05693 #else
05694 #define proc_getgroups rb_f_notimplement
05695 #endif
05696
05697
05698 #ifdef HAVE_SETGROUPS
05699
05700
05701
05702
05703
05704
05705
05706
05707
05708
05709
05710
05711
05712 static VALUE
05713 proc_setgroups(VALUE obj, VALUE ary)
05714 {
05715 int ngroups, i;
05716 rb_gid_t *groups;
05717 VALUE tmp;
05718 PREPARE_GETGRNAM;
05719
05720 Check_Type(ary, T_ARRAY);
05721
05722 ngroups = RARRAY_LENINT(ary);
05723 if (ngroups > maxgroups())
05724 rb_raise(rb_eArgError, "too many groups, %d max", maxgroups());
05725
05726 groups = ALLOCV_N(rb_gid_t, tmp, ngroups);
05727
05728 for (i = 0; i < ngroups; i++) {
05729 VALUE g = RARRAY_AREF(ary, i);
05730
05731 groups[i] = OBJ2GID1(g);
05732 }
05733 FINISH_GETGRNAM;
05734
05735 if (setgroups(ngroups, groups) == -1)
05736 rb_sys_fail(0);
05737
05738 ALLOCV_END(tmp);
05739
05740 return proc_getgroups(obj);
05741 }
05742 #else
05743 #define proc_setgroups rb_f_notimplement
05744 #endif
05745
05746
05747 #ifdef HAVE_INITGROUPS
05748
05749
05750
05751
05752
05753
05754
05755
05756
05757
05758
05759
05760
05761
05762
05763
05764
05765 static VALUE
05766 proc_initgroups(VALUE obj, VALUE uname, VALUE base_grp)
05767 {
05768 if (initgroups(StringValuePtr(uname), OBJ2GID(base_grp)) != 0) {
05769 rb_sys_fail(0);
05770 }
05771 return proc_getgroups(obj);
05772 }
05773 #else
05774 #define proc_initgroups rb_f_notimplement
05775 #endif
05776
05777 #if defined(_SC_NGROUPS_MAX) || defined(NGROUPS_MAX)
05778
05779
05780
05781
05782
05783
05784
05785
05786
05787
05788 static VALUE
05789 proc_getmaxgroups(VALUE obj)
05790 {
05791 return INT2FIX(maxgroups());
05792 }
05793 #else
05794 #define proc_getmaxgroups rb_f_notimplement
05795 #endif
05796
05797 #ifdef HAVE_SETGROUPS
05798
05799
05800
05801
05802
05803
05804
05805
05806 static VALUE
05807 proc_setmaxgroups(VALUE obj, VALUE val)
05808 {
05809 int ngroups = FIX2INT(val);
05810 int ngroups_max = get_sc_ngroups_max();
05811
05812 if (ngroups <= 0)
05813 rb_raise(rb_eArgError, "maxgroups %d shold be positive", ngroups);
05814
05815 if (ngroups > RB_MAX_GROUPS)
05816 ngroups = RB_MAX_GROUPS;
05817
05818 if (ngroups_max > 0 && ngroups > ngroups_max)
05819 ngroups = ngroups_max;
05820
05821 _maxgroups = ngroups;
05822
05823 return INT2FIX(_maxgroups);
05824 }
05825 #else
05826 #define proc_setmaxgroups rb_f_notimplement
05827 #endif
05828
05829 #if defined(HAVE_DAEMON) || (defined(HAVE_FORK) && defined(HAVE_SETSID))
05830 static int rb_daemon(int nochdir, int noclose);
05831
05832
05833
05834
05835
05836
05837
05838
05839
05840
05841
05842
05843
05844
05845
05846 static VALUE
05847 proc_daemon(int argc, VALUE *argv)
05848 {
05849 VALUE nochdir, noclose;
05850 int n;
05851
05852 rb_secure(2);
05853 rb_scan_args(argc, argv, "02", &nochdir, &noclose);
05854
05855 prefork();
05856 n = rb_daemon(RTEST(nochdir), RTEST(noclose));
05857 if (n < 0) rb_sys_fail("daemon");
05858 return INT2FIX(n);
05859 }
05860
05861 static int
05862 rb_daemon(int nochdir, int noclose)
05863 {
05864 int err = 0;
05865 #ifdef HAVE_DAEMON
05866 before_fork();
05867 err = daemon(nochdir, noclose);
05868 after_fork();
05869 rb_thread_atfork();
05870 #else
05871 int n;
05872
05873 #define fork_daemon() \
05874 switch (rb_fork_ruby(NULL)) { \
05875 case -1: return -1; \
05876 case 0: rb_thread_atfork(); break; \
05877 default: _exit(EXIT_SUCCESS); \
05878 }
05879
05880 fork_daemon();
05881
05882 if (setsid() < 0) return -1;
05883
05884
05885 fork_daemon();
05886
05887 if (!nochdir)
05888 err = chdir("/");
05889
05890 if (!noclose && (n = rb_cloexec_open("/dev/null", O_RDWR, 0)) != -1) {
05891 rb_update_max_fd(n);
05892 (void)dup2(n, 0);
05893 (void)dup2(n, 1);
05894 (void)dup2(n, 2);
05895 if (n > 2)
05896 (void)close (n);
05897 }
05898 #endif
05899 return err;
05900 }
05901 #else
05902 #define proc_daemon rb_f_notimplement
05903 #endif
05904
05905
05906
05907
05908
05909
05910
05911
05912
05913
05914
05915 static rb_gid_t SAVED_GROUP_ID = -1;
05916
05917 #ifdef BROKEN_SETREGID
05918 int
05919 setregid(rb_gid_t rgid, rb_gid_t egid)
05920 {
05921 if (rgid != (rb_gid_t)-1 && rgid != getgid()) {
05922 if (egid == (rb_gid_t)-1) egid = getegid();
05923 if (setgid(rgid) < 0) return -1;
05924 }
05925 if (egid != (rb_gid_t)-1 && egid != getegid()) {
05926 if (setegid(egid) < 0) return -1;
05927 }
05928 return 0;
05929 }
05930 #endif
05931
05932
05933
05934
05935
05936
05937
05938
05939
05940
05941
05942
05943
05944
05945 static VALUE
05946 p_gid_change_privilege(VALUE obj, VALUE id)
05947 {
05948 rb_gid_t gid;
05949
05950 check_gid_switch();
05951
05952 gid = OBJ2GID(id);
05953
05954 if (geteuid() == 0) {
05955 #if defined(HAVE_SETRESGID)
05956 if (setresgid(gid, gid, gid) < 0) rb_sys_fail(0);
05957 SAVED_GROUP_ID = gid;
05958 #elif defined HAVE_SETGID
05959 if (setgid(gid) < 0) rb_sys_fail(0);
05960 SAVED_GROUP_ID = gid;
05961 #elif defined(HAVE_SETREGID) && !defined(OBSOLETE_SETREGID)
05962 if (getgid() == gid) {
05963 if (SAVED_GROUP_ID == gid) {
05964 if (setregid(-1, gid) < 0) rb_sys_fail(0);
05965 }
05966 else {
05967 if (gid == 0) {
05968 if (setregid(-1, SAVED_GROUP_ID) < 0) rb_sys_fail(0);
05969 if (setregid(SAVED_GROUP_ID, 0) < 0) rb_sys_fail(0);
05970 SAVED_GROUP_ID = 0;
05971 if (setregid(gid, gid) < 0) rb_sys_fail(0);
05972 SAVED_GROUP_ID = gid;
05973 }
05974 else {
05975 if (setregid(0, 0) < 0) rb_sys_fail(0);
05976 SAVED_GROUP_ID = 0;
05977 if (setregid(gid, gid) < 0) rb_sys_fail(0);
05978 SAVED_GROUP_ID = gid;
05979 }
05980 }
05981 }
05982 else {
05983 if (setregid(gid, gid) < 0) rb_sys_fail(0);
05984 SAVED_GROUP_ID = gid;
05985 }
05986 #elif defined(HAVE_SETRGID) && defined (HAVE_SETEGID)
05987 if (getgid() == gid) {
05988 if (SAVED_GROUP_ID == gid) {
05989 if (setegid(gid) < 0) rb_sys_fail(0);
05990 }
05991 else {
05992 if (gid == 0) {
05993 if (setegid(gid) < 0) rb_sys_fail(0);
05994 if (setrgid(SAVED_GROUP_ID) < 0) rb_sys_fail(0);
05995 SAVED_GROUP_ID = 0;
05996 if (setrgid(0) < 0) rb_sys_fail(0);
05997 }
05998 else {
05999 if (setrgid(0) < 0) rb_sys_fail(0);
06000 SAVED_GROUP_ID = 0;
06001 if (setegid(gid) < 0) rb_sys_fail(0);
06002 if (setrgid(gid) < 0) rb_sys_fail(0);
06003 SAVED_GROUP_ID = gid;
06004 }
06005 }
06006 }
06007 else {
06008 if (setegid(gid) < 0) rb_sys_fail(0);
06009 if (setrgid(gid) < 0) rb_sys_fail(0);
06010 SAVED_GROUP_ID = gid;
06011 }
06012 #else
06013 rb_notimplement();
06014 #endif
06015 }
06016 else {
06017 #if defined(HAVE_SETRESGID)
06018 if (setresgid((getgid() == gid)? (rb_gid_t)-1: gid,
06019 (getegid() == gid)? (rb_gid_t)-1: gid,
06020 (SAVED_GROUP_ID == gid)? (rb_gid_t)-1: gid) < 0) rb_sys_fail(0);
06021 SAVED_GROUP_ID = gid;
06022 #elif defined(HAVE_SETREGID) && !defined(OBSOLETE_SETREGID)
06023 if (SAVED_GROUP_ID == gid) {
06024 if (setregid((getgid() == gid)? (rb_uid_t)-1: gid,
06025 (getegid() == gid)? (rb_uid_t)-1: gid) < 0)
06026 rb_sys_fail(0);
06027 }
06028 else if (getgid() != gid) {
06029 if (setregid(gid, (getegid() == gid)? (rb_uid_t)-1: gid) < 0)
06030 rb_sys_fail(0);
06031 SAVED_GROUP_ID = gid;
06032 }
06033 else if ( getegid() != gid) {
06034 if (setregid(getegid(), gid) < 0) rb_sys_fail(0);
06035 SAVED_GROUP_ID = gid;
06036 if (setregid(gid, -1) < 0) rb_sys_fail(0);
06037 }
06038 else {
06039 if (setregid(-1, SAVED_GROUP_ID) < 0) rb_sys_fail(0);
06040 if (setregid(SAVED_GROUP_ID, gid) < 0) rb_sys_fail(0);
06041 SAVED_GROUP_ID = gid;
06042 if (setregid(gid, -1) < 0) rb_sys_fail(0);
06043 }
06044 #elif defined(HAVE_SETRGID) && defined(HAVE_SETEGID)
06045 if (SAVED_GROUP_ID == gid) {
06046 if (getegid() != gid && setegid(gid) < 0) rb_sys_fail(0);
06047 if (getgid() != gid && setrgid(gid) < 0) rb_sys_fail(0);
06048 }
06049 else if ( getegid() == gid) {
06050 if (getgid() != gid) {
06051 if (setrgid(gid) < 0) rb_sys_fail(0);
06052 SAVED_GROUP_ID = gid;
06053 }
06054 else {
06055 if (setrgid(SAVED_GROUP_ID) < 0) rb_sys_fail(0);
06056 SAVED_GROUP_ID = gid;
06057 if (setrgid(gid) < 0) rb_sys_fail(0);
06058 }
06059 }
06060 else if ( getgid() == gid) {
06061 if (setegid(gid) < 0) rb_sys_fail(0);
06062 if (setrgid(SAVED_GROUP_ID) < 0) rb_sys_fail(0);
06063 SAVED_GROUP_ID = gid;
06064 if (setrgid(gid) < 0) rb_sys_fail(0);
06065 }
06066 else {
06067 errno = EPERM;
06068 rb_sys_fail(0);
06069 }
06070 #elif defined HAVE_44BSD_SETGID
06071 if (getgid() == gid) {
06072
06073 if (setgid(gid) < 0) rb_sys_fail(0);
06074 SAVED_GROUP_ID = gid;
06075 }
06076 else {
06077 errno = EPERM;
06078 rb_sys_fail(0);
06079 }
06080 #elif defined HAVE_SETEGID
06081 if (getgid() == gid && SAVED_GROUP_ID == gid) {
06082 if (setegid(gid) < 0) rb_sys_fail(0);
06083 }
06084 else {
06085 errno = EPERM;
06086 rb_sys_fail(0);
06087 }
06088 #elif defined HAVE_SETGID
06089 if (getgid() == gid && SAVED_GROUP_ID == gid) {
06090 if (setgid(gid) < 0) rb_sys_fail(0);
06091 }
06092 else {
06093 errno = EPERM;
06094 rb_sys_fail(0);
06095 }
06096 #else
06097 (void)gid;
06098 rb_notimplement();
06099 #endif
06100 }
06101 return id;
06102 }
06103
06104
06105
06106
06107
06108
06109
06110
06111
06112
06113
06114
06115
06116 static VALUE
06117 proc_geteuid(VALUE obj)
06118 {
06119 rb_uid_t euid = geteuid();
06120 return UIDT2NUM(euid);
06121 }
06122
06123 #if defined(HAVE_SETRESUID) || defined(HAVE_SETREUID) || defined(HAVE_SETEUID) || defined(HAVE_SETUID) || defined(_POSIX_SAVED_IDS)
06124 static void
06125 proc_seteuid(rb_uid_t uid)
06126 {
06127 #if defined(HAVE_SETRESUID)
06128 if (setresuid(-1, uid, -1) < 0) rb_sys_fail(0);
06129 #elif defined HAVE_SETREUID
06130 if (setreuid(-1, uid) < 0) rb_sys_fail(0);
06131 #elif defined HAVE_SETEUID
06132 if (seteuid(uid) < 0) rb_sys_fail(0);
06133 #elif defined HAVE_SETUID
06134 if (uid == getuid()) {
06135 if (setuid(uid) < 0) rb_sys_fail(0);
06136 }
06137 else {
06138 rb_notimplement();
06139 }
06140 #else
06141 rb_notimplement();
06142 #endif
06143 }
06144 #endif
06145
06146 #if defined(HAVE_SETRESUID) || defined(HAVE_SETREUID) || defined(HAVE_SETEUID) || defined(HAVE_SETUID)
06147
06148
06149
06150
06151
06152
06153
06154
06155 static VALUE
06156 proc_seteuid_m(VALUE mod, VALUE euid)
06157 {
06158 check_uid_switch();
06159 proc_seteuid(OBJ2UID(euid));
06160 return euid;
06161 }
06162 #else
06163 #define proc_seteuid_m rb_f_notimplement
06164 #endif
06165
06166 static rb_uid_t
06167 rb_seteuid_core(rb_uid_t euid)
06168 {
06169 #if defined(HAVE_SETRESUID) || (defined(HAVE_SETREUID) && !defined(OBSOLETE_SETREUID))
06170 rb_uid_t uid;
06171 #endif
06172
06173 check_uid_switch();
06174
06175 #if defined(HAVE_SETRESUID) || (defined(HAVE_SETREUID) && !defined(OBSOLETE_SETREUID))
06176 uid = getuid();
06177 #endif
06178
06179 #if defined(HAVE_SETRESUID)
06180 if (uid != euid) {
06181 if (setresuid(-1,euid,euid) < 0) rb_sys_fail(0);
06182 SAVED_USER_ID = euid;
06183 }
06184 else {
06185 if (setresuid(-1,euid,-1) < 0) rb_sys_fail(0);
06186 }
06187 #elif defined(HAVE_SETREUID) && !defined(OBSOLETE_SETREUID)
06188 if (setreuid(-1, euid) < 0) rb_sys_fail(0);
06189 if (uid != euid) {
06190 if (setreuid(euid,uid) < 0) rb_sys_fail(0);
06191 if (setreuid(uid,euid) < 0) rb_sys_fail(0);
06192 SAVED_USER_ID = euid;
06193 }
06194 #elif defined HAVE_SETEUID
06195 if (seteuid(euid) < 0) rb_sys_fail(0);
06196 #elif defined HAVE_SETUID
06197 if (geteuid() == 0) rb_sys_fail(0);
06198 if (setuid(euid) < 0) rb_sys_fail(0);
06199 #else
06200 rb_notimplement();
06201 #endif
06202 return euid;
06203 }
06204
06205
06206
06207
06208
06209
06210
06211
06212
06213
06214
06215
06216
06217
06218
06219
06220 static VALUE
06221 p_uid_grant_privilege(VALUE obj, VALUE id)
06222 {
06223 rb_seteuid_core(OBJ2UID(id));
06224 return id;
06225 }
06226
06227
06228
06229
06230
06231
06232
06233
06234
06235
06236
06237
06238
06239
06240 static VALUE
06241 proc_getegid(VALUE obj)
06242 {
06243 rb_gid_t egid = getegid();
06244
06245 return GIDT2NUM(egid);
06246 }
06247
06248 #if defined(HAVE_SETRESGID) || defined(HAVE_SETREGID) || defined(HAVE_SETEGID) || defined(HAVE_SETGID) || defined(_POSIX_SAVED_IDS)
06249
06250
06251
06252
06253
06254
06255
06256
06257 static VALUE
06258 proc_setegid(VALUE obj, VALUE egid)
06259 {
06260 #if defined(HAVE_SETRESGID) || defined(HAVE_SETREGID) || defined(HAVE_SETEGID) || defined(HAVE_SETGID)
06261 rb_gid_t gid;
06262 #endif
06263
06264 check_gid_switch();
06265
06266 #if defined(HAVE_SETRESGID) || defined(HAVE_SETREGID) || defined(HAVE_SETEGID) || defined(HAVE_SETGID)
06267 gid = OBJ2GID(egid);
06268 #endif
06269
06270 #if defined(HAVE_SETRESGID)
06271 if (setresgid(-1, gid, -1) < 0) rb_sys_fail(0);
06272 #elif defined HAVE_SETREGID
06273 if (setregid(-1, gid) < 0) rb_sys_fail(0);
06274 #elif defined HAVE_SETEGID
06275 if (setegid(gid) < 0) rb_sys_fail(0);
06276 #elif defined HAVE_SETGID
06277 if (gid == getgid()) {
06278 if (setgid(gid) < 0) rb_sys_fail(0);
06279 }
06280 else {
06281 rb_notimplement();
06282 }
06283 #else
06284 rb_notimplement();
06285 #endif
06286 return egid;
06287 }
06288 #endif
06289
06290 #if defined(HAVE_SETRESGID) || defined(HAVE_SETREGID) || defined(HAVE_SETEGID) || defined(HAVE_SETGID)
06291 #define proc_setegid_m proc_setegid
06292 #else
06293 #define proc_setegid_m rb_f_notimplement
06294 #endif
06295
06296 static rb_gid_t
06297 rb_setegid_core(rb_gid_t egid)
06298 {
06299 #if defined(HAVE_SETRESGID) || (defined(HAVE_SETREGID) && !defined(OBSOLETE_SETREGID))
06300 rb_gid_t gid;
06301 #endif
06302
06303 check_gid_switch();
06304
06305 #if defined(HAVE_SETRESGID) || (defined(HAVE_SETREGID) && !defined(OBSOLETE_SETREGID))
06306 gid = getgid();
06307 #endif
06308
06309 #if defined(HAVE_SETRESGID)
06310 if (gid != egid) {
06311 if (setresgid(-1,egid,egid) < 0) rb_sys_fail(0);
06312 SAVED_GROUP_ID = egid;
06313 }
06314 else {
06315 if (setresgid(-1,egid,-1) < 0) rb_sys_fail(0);
06316 }
06317 #elif defined(HAVE_SETREGID) && !defined(OBSOLETE_SETREGID)
06318 if (setregid(-1, egid) < 0) rb_sys_fail(0);
06319 if (gid != egid) {
06320 if (setregid(egid,gid) < 0) rb_sys_fail(0);
06321 if (setregid(gid,egid) < 0) rb_sys_fail(0);
06322 SAVED_GROUP_ID = egid;
06323 }
06324 #elif defined HAVE_SETEGID
06325 if (setegid(egid) < 0) rb_sys_fail(0);
06326 #elif defined HAVE_SETGID
06327 if (geteuid() == 0 ) rb_sys_fail(0);
06328 if (setgid(egid) < 0) rb_sys_fail(0);
06329 #else
06330 rb_notimplement();
06331 #endif
06332 return egid;
06333 }
06334
06335
06336
06337
06338
06339
06340
06341
06342
06343
06344
06345
06346
06347
06348
06349
06350 static VALUE
06351 p_gid_grant_privilege(VALUE obj, VALUE id)
06352 {
06353 rb_setegid_core(OBJ2GID(id));
06354 return id;
06355 }
06356
06357
06358
06359
06360
06361
06362
06363
06364
06365
06366
06367 static VALUE
06368 p_uid_exchangeable(void)
06369 {
06370 #if defined(HAVE_SETRESUID)
06371 return Qtrue;
06372 #elif defined(HAVE_SETREUID) && !defined(OBSOLETE_SETREUID)
06373 return Qtrue;
06374 #else
06375 return Qfalse;
06376 #endif
06377 }
06378
06379
06380
06381
06382
06383
06384
06385
06386
06387
06388
06389
06390
06391
06392 static VALUE
06393 p_uid_exchange(VALUE obj)
06394 {
06395 rb_uid_t uid;
06396 #if defined(HAVE_SETRESUID) || (defined(HAVE_SETREUID) && !defined(OBSOLETE_SETREUID))
06397 rb_uid_t euid;
06398 #endif
06399
06400 check_uid_switch();
06401
06402 uid = getuid();
06403 #if defined(HAVE_SETRESUID) || (defined(HAVE_SETREUID) && !defined(OBSOLETE_SETREUID))
06404 euid = geteuid();
06405 #endif
06406
06407 #if defined(HAVE_SETRESUID)
06408 if (setresuid(euid, uid, uid) < 0) rb_sys_fail(0);
06409 SAVED_USER_ID = uid;
06410 #elif defined(HAVE_SETREUID) && !defined(OBSOLETE_SETREUID)
06411 if (setreuid(euid,uid) < 0) rb_sys_fail(0);
06412 SAVED_USER_ID = uid;
06413 #else
06414 rb_notimplement();
06415 #endif
06416 return UIDT2NUM(uid);
06417 }
06418
06419
06420
06421
06422
06423
06424
06425
06426
06427
06428
06429 static VALUE
06430 p_gid_exchangeable(void)
06431 {
06432 #if defined(HAVE_SETRESGID)
06433 return Qtrue;
06434 #elif defined(HAVE_SETREGID) && !defined(OBSOLETE_SETREGID)
06435 return Qtrue;
06436 #else
06437 return Qfalse;
06438 #endif
06439 }
06440
06441
06442
06443
06444
06445
06446
06447
06448
06449
06450
06451
06452
06453
06454 static VALUE
06455 p_gid_exchange(VALUE obj)
06456 {
06457 rb_gid_t gid;
06458 #if defined(HAVE_SETRESGID) || (defined(HAVE_SETREGID) && !defined(OBSOLETE_SETREGID))
06459 rb_gid_t egid;
06460 #endif
06461
06462 check_gid_switch();
06463
06464 gid = getgid();
06465 #if defined(HAVE_SETRESGID) || (defined(HAVE_SETREGID) && !defined(OBSOLETE_SETREGID))
06466 egid = getegid();
06467 #endif
06468
06469 #if defined(HAVE_SETRESGID)
06470 if (setresgid(egid, gid, gid) < 0) rb_sys_fail(0);
06471 SAVED_GROUP_ID = gid;
06472 #elif defined(HAVE_SETREGID) && !defined(OBSOLETE_SETREGID)
06473 if (setregid(egid,gid) < 0) rb_sys_fail(0);
06474 SAVED_GROUP_ID = gid;
06475 #else
06476 rb_notimplement();
06477 #endif
06478 return GIDT2NUM(gid);
06479 }
06480
06481
06482
06483
06484
06485
06486
06487
06488
06489
06490
06491
06492 static VALUE
06493 p_uid_have_saved_id(void)
06494 {
06495 #if defined(HAVE_SETRESUID) || defined(HAVE_SETEUID) || defined(_POSIX_SAVED_IDS)
06496 return Qtrue;
06497 #else
06498 return Qfalse;
06499 #endif
06500 }
06501
06502
06503 #if defined(HAVE_SETRESUID) || defined(HAVE_SETEUID) || defined(_POSIX_SAVED_IDS)
06504 static VALUE
06505 p_uid_sw_ensure(rb_uid_t id)
06506 {
06507 under_uid_switch = 0;
06508 id = rb_seteuid_core(id);
06509 return UIDT2NUM(id);
06510 }
06511
06512
06513
06514
06515
06516
06517
06518
06519
06520
06521
06522
06523
06524
06525
06526 static VALUE
06527 p_uid_switch(VALUE obj)
06528 {
06529 rb_uid_t uid, euid;
06530
06531 check_uid_switch();
06532
06533 uid = getuid();
06534 euid = geteuid();
06535
06536 if (uid != euid) {
06537 proc_seteuid(uid);
06538 if (rb_block_given_p()) {
06539 under_uid_switch = 1;
06540 return rb_ensure(rb_yield, Qnil, p_uid_sw_ensure, SAVED_USER_ID);
06541 }
06542 else {
06543 return UIDT2NUM(euid);
06544 }
06545 }
06546 else if (euid != SAVED_USER_ID) {
06547 proc_seteuid(SAVED_USER_ID);
06548 if (rb_block_given_p()) {
06549 under_uid_switch = 1;
06550 return rb_ensure(rb_yield, Qnil, p_uid_sw_ensure, euid);
06551 }
06552 else {
06553 return UIDT2NUM(uid);
06554 }
06555 }
06556 else {
06557 errno = EPERM;
06558 rb_sys_fail(0);
06559 }
06560
06561 UNREACHABLE;
06562 }
06563 #else
06564 static VALUE
06565 p_uid_sw_ensure(VALUE obj)
06566 {
06567 under_uid_switch = 0;
06568 return p_uid_exchange(obj);
06569 }
06570
06571 static VALUE
06572 p_uid_switch(VALUE obj)
06573 {
06574 rb_uid_t uid, euid;
06575
06576 check_uid_switch();
06577
06578 uid = getuid();
06579 euid = geteuid();
06580
06581 if (uid == euid) {
06582 errno = EPERM;
06583 rb_sys_fail(0);
06584 }
06585 p_uid_exchange(obj);
06586 if (rb_block_given_p()) {
06587 under_uid_switch = 1;
06588 return rb_ensure(rb_yield, Qnil, p_uid_sw_ensure, obj);
06589 }
06590 else {
06591 return UIDT2NUM(euid);
06592 }
06593 }
06594 #endif
06595
06596
06597
06598
06599
06600
06601
06602
06603
06604
06605
06606
06607
06608 static VALUE
06609 p_gid_have_saved_id(void)
06610 {
06611 #if defined(HAVE_SETRESGID) || defined(HAVE_SETEGID) || defined(_POSIX_SAVED_IDS)
06612 return Qtrue;
06613 #else
06614 return Qfalse;
06615 #endif
06616 }
06617
06618 #if defined(HAVE_SETRESGID) || defined(HAVE_SETEGID) || defined(_POSIX_SAVED_IDS)
06619 static VALUE
06620 p_gid_sw_ensure(rb_gid_t id)
06621 {
06622 under_gid_switch = 0;
06623 id = rb_setegid_core(id);
06624 return GIDT2NUM(id);
06625 }
06626
06627
06628
06629
06630
06631
06632
06633
06634
06635
06636
06637
06638
06639
06640
06641 static VALUE
06642 p_gid_switch(VALUE obj)
06643 {
06644 rb_gid_t gid, egid;
06645
06646 check_gid_switch();
06647
06648 gid = getgid();
06649 egid = getegid();
06650
06651 if (gid != egid) {
06652 proc_setegid(obj, GIDT2NUM(gid));
06653 if (rb_block_given_p()) {
06654 under_gid_switch = 1;
06655 return rb_ensure(rb_yield, Qnil, p_gid_sw_ensure, SAVED_GROUP_ID);
06656 }
06657 else {
06658 return GIDT2NUM(egid);
06659 }
06660 }
06661 else if (egid != SAVED_GROUP_ID) {
06662 proc_setegid(obj, GIDT2NUM(SAVED_GROUP_ID));
06663 if (rb_block_given_p()) {
06664 under_gid_switch = 1;
06665 return rb_ensure(rb_yield, Qnil, p_gid_sw_ensure, egid);
06666 }
06667 else {
06668 return GIDT2NUM(gid);
06669 }
06670 }
06671 else {
06672 errno = EPERM;
06673 rb_sys_fail(0);
06674 }
06675
06676 UNREACHABLE;
06677 }
06678 #else
06679 static VALUE
06680 p_gid_sw_ensure(VALUE obj)
06681 {
06682 under_gid_switch = 0;
06683 return p_gid_exchange(obj);
06684 }
06685
06686 static VALUE
06687 p_gid_switch(VALUE obj)
06688 {
06689 rb_gid_t gid, egid;
06690
06691 check_gid_switch();
06692
06693 gid = getgid();
06694 egid = getegid();
06695
06696 if (gid == egid) {
06697 errno = EPERM;
06698 rb_sys_fail(0);
06699 }
06700 p_gid_exchange(obj);
06701 if (rb_block_given_p()) {
06702 under_gid_switch = 1;
06703 return rb_ensure(rb_yield, Qnil, p_gid_sw_ensure, obj);
06704 }
06705 else {
06706 return GIDT2NUM(egid);
06707 }
06708 }
06709 #endif
06710
06711
06712 #if defined(HAVE_TIMES)
06713 static long
06714 get_clk_tck(void)
06715 {
06716 long hertz =
06717 #ifdef HAVE__SC_CLK_TCK
06718 (double)sysconf(_SC_CLK_TCK);
06719 #else
06720 #ifndef HZ
06721 # ifdef CLK_TCK
06722 # define HZ CLK_TCK
06723 # else
06724 # define HZ 60
06725 # endif
06726 #endif
06727 HZ;
06728 #endif
06729 return hertz;
06730 }
06731
06732
06733
06734
06735
06736
06737
06738
06739
06740
06741
06742
06743
06744 VALUE
06745 rb_proc_times(VALUE obj)
06746 {
06747 const double hertz = get_clk_tck();
06748 struct tms buf;
06749 VALUE utime, stime, cutime, cstime, ret;
06750
06751 times(&buf);
06752 utime = DBL2NUM(buf.tms_utime / hertz);
06753 stime = DBL2NUM(buf.tms_stime / hertz);
06754 cutime = DBL2NUM(buf.tms_cutime / hertz);
06755 cstime = DBL2NUM(buf.tms_cstime / hertz);
06756 ret = rb_struct_new(rb_cProcessTms, utime, stime, cutime, cstime);
06757 RB_GC_GUARD(utime);
06758 RB_GC_GUARD(stime);
06759 RB_GC_GUARD(cutime);
06760 RB_GC_GUARD(cstime);
06761 return ret;
06762 }
06763 #else
06764 #define rb_proc_times rb_f_notimplement
06765 #endif
06766
06767 #ifdef HAVE_LONG_LONG
06768 typedef LONG_LONG timetick_int_t;
06769 #define TIMETICK_INT_MIN LLONG_MIN
06770 #define TIMETICK_INT_MAX LLONG_MAX
06771 #define TIMETICK_INT2NUM(v) LL2NUM(v)
06772 #else
06773 typedef long timetick_int_t;
06774 #define TIMETICK_INT_MIN LONG_MIN
06775 #define TIMETICK_INT_MAX LONG_MAX
06776 #define TIMETICK_INT2NUM(v) LONG2NUM(v)
06777 #endif
06778
06779 static timetick_int_t
06780 gcd_timetick_int(timetick_int_t a, timetick_int_t b)
06781 {
06782 timetick_int_t t;
06783
06784 if (a < b) {
06785 t = a;
06786 a = b;
06787 b = t;
06788 }
06789
06790 while (1) {
06791 t = a % b;
06792 if (t == 0)
06793 return b;
06794 a = b;
06795 b = t;
06796 }
06797 }
06798
06799 static void
06800 reduce_fraction(timetick_int_t *np, timetick_int_t *dp)
06801 {
06802 timetick_int_t gcd = gcd_timetick_int(*np, *dp);
06803 if (gcd != 1) {
06804 *np /= gcd;
06805 *dp /= gcd;
06806 }
06807 }
06808
06809 static void
06810 reduce_factors(timetick_int_t *numerators, int num_numerators,
06811 timetick_int_t *denominators, int num_denominators)
06812 {
06813 int i, j;
06814 for (i = 0; i < num_numerators; i++) {
06815 if (numerators[i] == 1)
06816 continue;
06817 for (j = 0; j < num_denominators; j++) {
06818 if (denominators[j] == 1)
06819 continue;
06820 reduce_fraction(&numerators[i], &denominators[j]);
06821 }
06822 }
06823 }
06824
06825 struct timetick {
06826 timetick_int_t giga_count;
06827 int32_t count;
06828 };
06829
06830 static VALUE
06831 timetick2dblnum(struct timetick *ttp,
06832 timetick_int_t *numerators, int num_numerators,
06833 timetick_int_t *denominators, int num_denominators)
06834 {
06835 double d;
06836 int i;
06837
06838 reduce_factors(numerators, num_numerators,
06839 denominators, num_denominators);
06840
06841 d = ttp->giga_count * 1e9 + ttp->count;
06842
06843 for (i = 0; i < num_numerators; i++)
06844 d *= numerators[i];
06845 for (i = 0; i < num_denominators; i++)
06846 d /= denominators[i];
06847
06848 return DBL2NUM(d);
06849 }
06850
06851 static VALUE
06852 timetick2dblnum_reciprocal(struct timetick *ttp,
06853 timetick_int_t *numerators, int num_numerators,
06854 timetick_int_t *denominators, int num_denominators)
06855 {
06856 double d;
06857 int i;
06858
06859 reduce_factors(numerators, num_numerators,
06860 denominators, num_denominators);
06861
06862 d = 1.0;
06863 for (i = 0; i < num_denominators; i++)
06864 d *= denominators[i];
06865 for (i = 0; i < num_numerators; i++)
06866 d /= numerators[i];
06867 d /= ttp->giga_count * 1e9 + ttp->count;
06868
06869 return DBL2NUM(d);
06870 }
06871
06872 #define NDIV(x,y) (-(-((x)+1)/(y))-1)
06873 #define DIV(n,d) ((n)<0 ? NDIV((n),(d)) : (n)/(d))
06874
06875 static VALUE
06876 timetick2integer(struct timetick *ttp,
06877 timetick_int_t *numerators, int num_numerators,
06878 timetick_int_t *denominators, int num_denominators)
06879 {
06880 VALUE v;
06881 int i;
06882
06883 reduce_factors(numerators, num_numerators,
06884 denominators, num_denominators);
06885
06886 if (!MUL_OVERFLOW_SIGNED_INTEGER_P(1000000000, ttp->giga_count,
06887 TIMETICK_INT_MIN, TIMETICK_INT_MAX-ttp->count)) {
06888 timetick_int_t t = ttp->giga_count * 1000000000 + ttp->count;
06889 for (i = 0; i < num_numerators; i++) {
06890 timetick_int_t factor = numerators[i];
06891 if (MUL_OVERFLOW_SIGNED_INTEGER_P(factor, t,
06892 TIMETICK_INT_MIN, TIMETICK_INT_MAX))
06893 goto generic;
06894 t *= factor;
06895 }
06896 for (i = 0; i < num_denominators; i++) {
06897 t = DIV(t, denominators[i]);
06898 }
06899 return TIMETICK_INT2NUM(t);
06900 }
06901
06902 generic:
06903 v = TIMETICK_INT2NUM(ttp->giga_count);
06904 v = rb_funcall(v, '*', 1, LONG2FIX(1000000000));
06905 v = rb_funcall(v, '+', 1, LONG2FIX(ttp->count));
06906 for (i = 0; i < num_numerators; i++) {
06907 timetick_int_t factor = numerators[i];
06908 if (factor == 1)
06909 continue;
06910 v = rb_funcall(v, '*', 1, TIMETICK_INT2NUM(factor));
06911 }
06912 for (i = 0; i < num_denominators; i++) {
06913 v = rb_funcall(v, '/', 1, TIMETICK_INT2NUM(denominators[i]));
06914 }
06915 return v;
06916 }
06917
06918 static VALUE
06919 make_clock_result(struct timetick *ttp,
06920 timetick_int_t *numerators, int num_numerators,
06921 timetick_int_t *denominators, int num_denominators,
06922 VALUE unit)
06923 {
06924 if (unit == ID2SYM(rb_intern("nanosecond"))) {
06925 numerators[num_numerators++] = 1000000000;
06926 return timetick2integer(ttp, numerators, num_numerators, denominators, num_denominators);
06927 }
06928 else if (unit == ID2SYM(rb_intern("microsecond"))) {
06929 numerators[num_numerators++] = 1000000;
06930 return timetick2integer(ttp, numerators, num_numerators, denominators, num_denominators);
06931 }
06932 else if (unit == ID2SYM(rb_intern("millisecond"))) {
06933 numerators[num_numerators++] = 1000;
06934 return timetick2integer(ttp, numerators, num_numerators, denominators, num_denominators);
06935 }
06936 else if (unit == ID2SYM(rb_intern("second"))) {
06937 return timetick2integer(ttp, numerators, num_numerators, denominators, num_denominators);
06938 }
06939 else if (unit == ID2SYM(rb_intern("float_microsecond"))) {
06940 numerators[num_numerators++] = 1000000;
06941 return timetick2dblnum(ttp, numerators, num_numerators, denominators, num_denominators);
06942 }
06943 else if (unit == ID2SYM(rb_intern("float_millisecond"))) {
06944 numerators[num_numerators++] = 1000;
06945 return timetick2dblnum(ttp, numerators, num_numerators, denominators, num_denominators);
06946 }
06947 else if (NIL_P(unit) || unit == ID2SYM(rb_intern("float_second"))) {
06948 return timetick2dblnum(ttp, numerators, num_numerators, denominators, num_denominators);
06949 }
06950 else
06951 rb_raise(rb_eArgError, "unexpected unit: %"PRIsVALUE, unit);
06952 }
06953
06954 #ifdef __APPLE__
06955 static mach_timebase_info_data_t *
06956 get_mach_timebase_info(void)
06957 {
06958 static mach_timebase_info_data_t sTimebaseInfo;
06959
06960 if ( sTimebaseInfo.denom == 0 ) {
06961 (void) mach_timebase_info(&sTimebaseInfo);
06962 }
06963
06964 return &sTimebaseInfo;
06965 }
06966 #endif
06967
06968
06969
06970
06971
06972
06973
06974
06975
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 VALUE
07092 rb_clock_gettime(int argc, VALUE *argv)
07093 {
07094 VALUE clk_id, unit;
07095 int ret;
07096
07097 struct timetick tt;
07098 timetick_int_t numerators[2];
07099 timetick_int_t denominators[2];
07100 int num_numerators = 0;
07101 int num_denominators = 0;
07102
07103 rb_scan_args(argc, argv, "11", &clk_id, &unit);
07104
07105 if (SYMBOL_P(clk_id)) {
07106
07107
07108
07109
07110
07111
07112
07113 #define RUBY_GETTIMEOFDAY_BASED_CLOCK_REALTIME ID2SYM(rb_intern("GETTIMEOFDAY_BASED_CLOCK_REALTIME"))
07114 if (clk_id == RUBY_GETTIMEOFDAY_BASED_CLOCK_REALTIME) {
07115 struct timeval tv;
07116 ret = gettimeofday(&tv, 0);
07117 if (ret != 0)
07118 rb_sys_fail("gettimeofday");
07119 tt.giga_count = tv.tv_sec;
07120 tt.count = (int32_t)tv.tv_usec * 1000;
07121 denominators[num_denominators++] = 1000000000;
07122 goto success;
07123 }
07124
07125 #define RUBY_TIME_BASED_CLOCK_REALTIME ID2SYM(rb_intern("TIME_BASED_CLOCK_REALTIME"))
07126 if (clk_id == RUBY_TIME_BASED_CLOCK_REALTIME) {
07127 time_t t;
07128 t = time(NULL);
07129 if (t == (time_t)-1)
07130 rb_sys_fail("time");
07131 tt.giga_count = t;
07132 tt.count = 0;
07133 denominators[num_denominators++] = 1000000000;
07134 goto success;
07135 }
07136
07137 #ifdef HAVE_TIMES
07138 #define RUBY_TIMES_BASED_CLOCK_MONOTONIC \
07139 ID2SYM(rb_intern("TIMES_BASED_CLOCK_MONOTONIC"))
07140 if (clk_id == RUBY_TIMES_BASED_CLOCK_MONOTONIC) {
07141 struct tms buf;
07142 clock_t c;
07143 unsigned_clock_t uc;
07144 c = times(&buf);
07145 if (c == (clock_t)-1)
07146 rb_sys_fail("times");
07147 uc = (unsigned_clock_t)c;
07148 tt.count = (int32_t)(uc % 1000000000);
07149 tt.giga_count = (uc / 1000000000);
07150 denominators[num_denominators++] = get_clk_tck();
07151 goto success;
07152 }
07153 #endif
07154
07155 #ifdef RUSAGE_SELF
07156 #define RUBY_GETRUSAGE_BASED_CLOCK_PROCESS_CPUTIME_ID \
07157 ID2SYM(rb_intern("GETRUSAGE_BASED_CLOCK_PROCESS_CPUTIME_ID"))
07158 if (clk_id == RUBY_GETRUSAGE_BASED_CLOCK_PROCESS_CPUTIME_ID) {
07159 struct rusage usage;
07160 int32_t usec;
07161 ret = getrusage(RUSAGE_SELF, &usage);
07162 if (ret != 0)
07163 rb_sys_fail("getrusage");
07164 tt.giga_count = usage.ru_utime.tv_sec + usage.ru_stime.tv_sec;
07165 usec = (int32_t)(usage.ru_utime.tv_usec + usage.ru_stime.tv_usec);
07166 if (1000000 <= usec) {
07167 tt.giga_count++;
07168 usec -= 1000000;
07169 }
07170 tt.count = usec * 1000;
07171 denominators[num_denominators++] = 1000000000;
07172 goto success;
07173 }
07174 #endif
07175
07176 #ifdef HAVE_TIMES
07177 #define RUBY_TIMES_BASED_CLOCK_PROCESS_CPUTIME_ID \
07178 ID2SYM(rb_intern("TIMES_BASED_CLOCK_PROCESS_CPUTIME_ID"))
07179 if (clk_id == RUBY_TIMES_BASED_CLOCK_PROCESS_CPUTIME_ID) {
07180 struct tms buf;
07181 unsigned_clock_t utime, stime;
07182 if (times(&buf) == (clock_t)-1)
07183 rb_sys_fail("times");
07184 utime = (unsigned_clock_t)buf.tms_utime;
07185 stime = (unsigned_clock_t)buf.tms_stime;
07186 tt.count = (int32_t)((utime % 1000000000) + (stime % 1000000000));
07187 tt.giga_count = (utime / 1000000000) + (stime / 1000000000);
07188 if (1000000000 <= tt.count) {
07189 tt.count -= 1000000000;
07190 tt.giga_count++;
07191 }
07192 denominators[num_denominators++] = get_clk_tck();
07193 goto success;
07194 }
07195 #endif
07196
07197 #define RUBY_CLOCK_BASED_CLOCK_PROCESS_CPUTIME_ID \
07198 ID2SYM(rb_intern("CLOCK_BASED_CLOCK_PROCESS_CPUTIME_ID"))
07199 if (clk_id == RUBY_CLOCK_BASED_CLOCK_PROCESS_CPUTIME_ID) {
07200 clock_t c;
07201 unsigned_clock_t uc;
07202 errno = 0;
07203 c = clock();
07204 if (c == (clock_t)-1)
07205 rb_sys_fail("clock");
07206 uc = (unsigned_clock_t)c;
07207 tt.count = (int32_t)(uc % 1000000000);
07208 tt.giga_count = uc / 1000000000;
07209 denominators[num_denominators++] = CLOCKS_PER_SEC;
07210 goto success;
07211 }
07212
07213 #ifdef __APPLE__
07214 #define RUBY_MACH_ABSOLUTE_TIME_BASED_CLOCK_MONOTONIC ID2SYM(rb_intern("MACH_ABSOLUTE_TIME_BASED_CLOCK_MONOTONIC"))
07215 if (clk_id == RUBY_MACH_ABSOLUTE_TIME_BASED_CLOCK_MONOTONIC) {
07216 mach_timebase_info_data_t *info = get_mach_timebase_info();
07217 uint64_t t = mach_absolute_time();
07218 tt.count = (int32_t)(t % 1000000000);
07219 tt.giga_count = t / 1000000000;
07220 numerators[num_numerators++] = info->numer;
07221 denominators[num_denominators++] = info->denom;
07222 denominators[num_denominators++] = 1000000000;
07223 goto success;
07224 }
07225 #endif
07226 }
07227 else {
07228 #if defined(HAVE_CLOCK_GETTIME)
07229 struct timespec ts;
07230 clockid_t c;
07231 c = NUM2CLOCKID(clk_id);
07232 ret = clock_gettime(c, &ts);
07233 if (ret == -1)
07234 rb_sys_fail("clock_gettime");
07235 tt.count = (int32_t)ts.tv_nsec;
07236 tt.giga_count = ts.tv_sec;
07237 denominators[num_denominators++] = 1000000000;
07238 goto success;
07239 #endif
07240 }
07241
07242 errno = EINVAL;
07243 rb_sys_fail(0);
07244
07245 success:
07246 return make_clock_result(&tt, numerators, num_numerators, denominators, num_denominators, unit);
07247 }
07248
07249
07250
07251
07252
07253
07254
07255
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 VALUE
07288 rb_clock_getres(int argc, VALUE *argv)
07289 {
07290 VALUE clk_id, unit;
07291
07292 struct timetick tt;
07293 timetick_int_t numerators[2];
07294 timetick_int_t denominators[2];
07295 int num_numerators = 0;
07296 int num_denominators = 0;
07297
07298 rb_scan_args(argc, argv, "11", &clk_id, &unit);
07299
07300 if (SYMBOL_P(clk_id)) {
07301 #ifdef RUBY_GETTIMEOFDAY_BASED_CLOCK_REALTIME
07302 if (clk_id == RUBY_GETTIMEOFDAY_BASED_CLOCK_REALTIME) {
07303 tt.giga_count = 0;
07304 tt.count = 1000;
07305 denominators[num_denominators++] = 1000000000;
07306 goto success;
07307 }
07308 #endif
07309
07310 #ifdef RUBY_TIME_BASED_CLOCK_REALTIME
07311 if (clk_id == RUBY_TIME_BASED_CLOCK_REALTIME) {
07312 tt.giga_count = 1;
07313 tt.count = 0;
07314 denominators[num_denominators++] = 1000000000;
07315 goto success;
07316 }
07317 #endif
07318
07319 #ifdef RUBY_TIMES_BASED_CLOCK_MONOTONIC
07320 if (clk_id == RUBY_TIMES_BASED_CLOCK_MONOTONIC) {
07321 tt.count = 1;
07322 tt.giga_count = 0;
07323 denominators[num_denominators++] = get_clk_tck();
07324 goto success;
07325 }
07326 #endif
07327
07328 #ifdef RUBY_GETRUSAGE_BASED_CLOCK_PROCESS_CPUTIME_ID
07329 if (clk_id == RUBY_GETRUSAGE_BASED_CLOCK_PROCESS_CPUTIME_ID) {
07330 tt.giga_count = 0;
07331 tt.count = 1000;
07332 denominators[num_denominators++] = 1000000000;
07333 goto success;
07334 }
07335 #endif
07336
07337 #ifdef RUBY_TIMES_BASED_CLOCK_PROCESS_CPUTIME_ID
07338 if (clk_id == RUBY_TIMES_BASED_CLOCK_PROCESS_CPUTIME_ID) {
07339 tt.count = 1;
07340 tt.giga_count = 0;
07341 denominators[num_denominators++] = get_clk_tck();
07342 goto success;
07343 }
07344 #endif
07345
07346 #ifdef RUBY_CLOCK_BASED_CLOCK_PROCESS_CPUTIME_ID
07347 if (clk_id == RUBY_CLOCK_BASED_CLOCK_PROCESS_CPUTIME_ID) {
07348 tt.count = 1;
07349 tt.giga_count = 0;
07350 denominators[num_denominators++] = CLOCKS_PER_SEC;
07351 goto success;
07352 }
07353 #endif
07354
07355 #ifdef RUBY_MACH_ABSOLUTE_TIME_BASED_CLOCK_MONOTONIC
07356 if (clk_id == RUBY_MACH_ABSOLUTE_TIME_BASED_CLOCK_MONOTONIC) {
07357 mach_timebase_info_data_t *info = get_mach_timebase_info();
07358 tt.count = 1;
07359 tt.giga_count = 0;
07360 numerators[num_numerators++] = info->numer;
07361 denominators[num_denominators++] = info->denom;
07362 denominators[num_denominators++] = 1000000000;
07363 goto success;
07364 }
07365 #endif
07366 }
07367 else {
07368 #if defined(HAVE_CLOCK_GETRES)
07369 struct timespec ts;
07370 clockid_t c = NUM2CLOCKID(clk_id);
07371 int ret = clock_getres(c, &ts);
07372 if (ret == -1)
07373 rb_sys_fail("clock_getres");
07374 tt.count = (int32_t)ts.tv_nsec;
07375 tt.giga_count = ts.tv_sec;
07376 denominators[num_denominators++] = 1000000000;
07377 goto success;
07378 #endif
07379 }
07380
07381 errno = EINVAL;
07382 rb_sys_fail(0);
07383
07384 success:
07385 if (unit == ID2SYM(rb_intern("hertz"))) {
07386 return timetick2dblnum_reciprocal(&tt, numerators, num_numerators, denominators, num_denominators);
07387 }
07388 else {
07389 return make_clock_result(&tt, numerators, num_numerators, denominators, num_denominators, unit);
07390 }
07391 }
07392
07393 VALUE rb_mProcess;
07394 VALUE rb_mProcUID;
07395 VALUE rb_mProcGID;
07396 VALUE rb_mProcID_Syscall;
07397
07398
07399
07400
07401
07402
07403
07404 void
07405 Init_process(void)
07406 {
07407 #undef rb_intern
07408 #define rb_intern(str) rb_intern_const(str)
07409 rb_define_virtual_variable("$?", rb_last_status_get, 0);
07410 rb_define_virtual_variable("$$", get_pid, 0);
07411 rb_define_global_function("exec", rb_f_exec, -1);
07412 rb_define_global_function("fork", rb_f_fork, 0);
07413 rb_define_global_function("exit!", rb_f_exit_bang, -1);
07414 rb_define_global_function("system", rb_f_system, -1);
07415 rb_define_global_function("spawn", rb_f_spawn, -1);
07416 rb_define_global_function("sleep", rb_f_sleep, -1);
07417 rb_define_global_function("exit", rb_f_exit, -1);
07418 rb_define_global_function("abort", rb_f_abort, -1);
07419
07420 rb_mProcess = rb_define_module("Process");
07421
07422 #ifdef WNOHANG
07423
07424 rb_define_const(rb_mProcess, "WNOHANG", INT2FIX(WNOHANG));
07425 #else
07426
07427 rb_define_const(rb_mProcess, "WNOHANG", INT2FIX(0));
07428 #endif
07429 #ifdef WUNTRACED
07430
07431 rb_define_const(rb_mProcess, "WUNTRACED", INT2FIX(WUNTRACED));
07432 #else
07433
07434 rb_define_const(rb_mProcess, "WUNTRACED", INT2FIX(0));
07435 #endif
07436
07437 rb_define_singleton_method(rb_mProcess, "exec", rb_f_exec, -1);
07438 rb_define_singleton_method(rb_mProcess, "fork", rb_f_fork, 0);
07439 rb_define_singleton_method(rb_mProcess, "spawn", rb_f_spawn, -1);
07440 rb_define_singleton_method(rb_mProcess, "exit!", rb_f_exit_bang, -1);
07441 rb_define_singleton_method(rb_mProcess, "exit", rb_f_exit, -1);
07442 rb_define_singleton_method(rb_mProcess, "abort", rb_f_abort, -1);
07443
07444 rb_define_module_function(rb_mProcess, "kill", rb_f_kill, -1);
07445 rb_define_module_function(rb_mProcess, "wait", proc_wait, -1);
07446 rb_define_module_function(rb_mProcess, "wait2", proc_wait2, -1);
07447 rb_define_module_function(rb_mProcess, "waitpid", proc_wait, -1);
07448 rb_define_module_function(rb_mProcess, "waitpid2", proc_wait2, -1);
07449 rb_define_module_function(rb_mProcess, "waitall", proc_waitall, 0);
07450 rb_define_module_function(rb_mProcess, "detach", proc_detach, 1);
07451
07452 rb_cProcessStatus = rb_define_class_under(rb_mProcess, "Status", rb_cObject);
07453 rb_undef_method(CLASS_OF(rb_cProcessStatus), "new");
07454
07455 rb_define_method(rb_cProcessStatus, "==", pst_equal, 1);
07456 rb_define_method(rb_cProcessStatus, "&", pst_bitand, 1);
07457 rb_define_method(rb_cProcessStatus, ">>", pst_rshift, 1);
07458 rb_define_method(rb_cProcessStatus, "to_i", pst_to_i, 0);
07459 rb_define_method(rb_cProcessStatus, "to_s", pst_to_s, 0);
07460 rb_define_method(rb_cProcessStatus, "inspect", pst_inspect, 0);
07461
07462 rb_define_method(rb_cProcessStatus, "pid", pst_pid, 0);
07463
07464 rb_define_method(rb_cProcessStatus, "stopped?", pst_wifstopped, 0);
07465 rb_define_method(rb_cProcessStatus, "stopsig", pst_wstopsig, 0);
07466 rb_define_method(rb_cProcessStatus, "signaled?", pst_wifsignaled, 0);
07467 rb_define_method(rb_cProcessStatus, "termsig", pst_wtermsig, 0);
07468 rb_define_method(rb_cProcessStatus, "exited?", pst_wifexited, 0);
07469 rb_define_method(rb_cProcessStatus, "exitstatus", pst_wexitstatus, 0);
07470 rb_define_method(rb_cProcessStatus, "success?", pst_success_p, 0);
07471 rb_define_method(rb_cProcessStatus, "coredump?", pst_wcoredump, 0);
07472
07473 rb_define_module_function(rb_mProcess, "pid", get_pid, 0);
07474 rb_define_module_function(rb_mProcess, "ppid", get_ppid, 0);
07475
07476 rb_define_module_function(rb_mProcess, "getpgrp", proc_getpgrp, 0);
07477 rb_define_module_function(rb_mProcess, "setpgrp", proc_setpgrp, 0);
07478 rb_define_module_function(rb_mProcess, "getpgid", proc_getpgid, 1);
07479 rb_define_module_function(rb_mProcess, "setpgid", proc_setpgid, 2);
07480
07481 rb_define_module_function(rb_mProcess, "getsid", proc_getsid, -1);
07482 rb_define_module_function(rb_mProcess, "setsid", proc_setsid, 0);
07483
07484 rb_define_module_function(rb_mProcess, "getpriority", proc_getpriority, 2);
07485 rb_define_module_function(rb_mProcess, "setpriority", proc_setpriority, 3);
07486
07487 #ifdef HAVE_GETPRIORITY
07488
07489 rb_define_const(rb_mProcess, "PRIO_PROCESS", INT2FIX(PRIO_PROCESS));
07490
07491 rb_define_const(rb_mProcess, "PRIO_PGRP", INT2FIX(PRIO_PGRP));
07492
07493 rb_define_const(rb_mProcess, "PRIO_USER", INT2FIX(PRIO_USER));
07494 #endif
07495
07496 rb_define_module_function(rb_mProcess, "getrlimit", proc_getrlimit, 1);
07497 rb_define_module_function(rb_mProcess, "setrlimit", proc_setrlimit, -1);
07498 #if defined(RLIM2NUM) && defined(RLIM_INFINITY)
07499 {
07500 VALUE inf = RLIM2NUM(RLIM_INFINITY);
07501 #ifdef RLIM_SAVED_MAX
07502 {
07503 VALUE v = RLIM_INFINITY == RLIM_SAVED_MAX ? inf : RLIM2NUM(RLIM_SAVED_MAX);
07504
07505 rb_define_const(rb_mProcess, "RLIM_SAVED_MAX", v);
07506 }
07507 #endif
07508
07509 rb_define_const(rb_mProcess, "RLIM_INFINITY", inf);
07510 #ifdef RLIM_SAVED_CUR
07511 {
07512 VALUE v = RLIM_INFINITY == RLIM_SAVED_CUR ? inf : RLIM2NUM(RLIM_SAVED_CUR);
07513
07514 rb_define_const(rb_mProcess, "RLIM_SAVED_CUR", v);
07515 }
07516 #endif
07517 }
07518 #ifdef RLIMIT_AS
07519
07520
07521
07522
07523 rb_define_const(rb_mProcess, "RLIMIT_AS", INT2FIX(RLIMIT_AS));
07524 #endif
07525 #ifdef RLIMIT_CORE
07526
07527
07528
07529
07530 rb_define_const(rb_mProcess, "RLIMIT_CORE", INT2FIX(RLIMIT_CORE));
07531 #endif
07532 #ifdef RLIMIT_CPU
07533
07534
07535
07536
07537 rb_define_const(rb_mProcess, "RLIMIT_CPU", INT2FIX(RLIMIT_CPU));
07538 #endif
07539 #ifdef RLIMIT_DATA
07540
07541
07542
07543
07544 rb_define_const(rb_mProcess, "RLIMIT_DATA", INT2FIX(RLIMIT_DATA));
07545 #endif
07546 #ifdef RLIMIT_FSIZE
07547
07548
07549
07550
07551 rb_define_const(rb_mProcess, "RLIMIT_FSIZE", INT2FIX(RLIMIT_FSIZE));
07552 #endif
07553 #ifdef RLIMIT_MEMLOCK
07554
07555
07556
07557
07558 rb_define_const(rb_mProcess, "RLIMIT_MEMLOCK", INT2FIX(RLIMIT_MEMLOCK));
07559 #endif
07560 #ifdef RLIMIT_MSGQUEUE
07561
07562
07563
07564
07565
07566 rb_define_const(rb_mProcess, "RLIMIT_MSGQUEUE", INT2FIX(RLIMIT_MSGQUEUE));
07567 #endif
07568 #ifdef RLIMIT_NICE
07569
07570
07571
07572
07573 rb_define_const(rb_mProcess, "RLIMIT_NICE", INT2FIX(RLIMIT_NICE));
07574 #endif
07575 #ifdef RLIMIT_NOFILE
07576
07577
07578
07579
07580
07581 rb_define_const(rb_mProcess, "RLIMIT_NOFILE", INT2FIX(RLIMIT_NOFILE));
07582 #endif
07583 #ifdef RLIMIT_NPROC
07584
07585
07586
07587
07588
07589 rb_define_const(rb_mProcess, "RLIMIT_NPROC", INT2FIX(RLIMIT_NPROC));
07590 #endif
07591 #ifdef RLIMIT_RSS
07592
07593
07594
07595
07596 rb_define_const(rb_mProcess, "RLIMIT_RSS", INT2FIX(RLIMIT_RSS));
07597 #endif
07598 #ifdef RLIMIT_RTPRIO
07599
07600
07601
07602
07603 rb_define_const(rb_mProcess, "RLIMIT_RTPRIO", INT2FIX(RLIMIT_RTPRIO));
07604 #endif
07605 #ifdef RLIMIT_RTTIME
07606
07607
07608
07609
07610
07611 rb_define_const(rb_mProcess, "RLIMIT_RTTIME", INT2FIX(RLIMIT_RTTIME));
07612 #endif
07613 #ifdef RLIMIT_SBSIZE
07614
07615
07616 rb_define_const(rb_mProcess, "RLIMIT_SBSIZE", INT2FIX(RLIMIT_SBSIZE));
07617 #endif
07618 #ifdef RLIMIT_SIGPENDING
07619
07620
07621
07622
07623
07624 rb_define_const(rb_mProcess, "RLIMIT_SIGPENDING", INT2FIX(RLIMIT_SIGPENDING));
07625 #endif
07626 #ifdef RLIMIT_STACK
07627
07628
07629
07630
07631 rb_define_const(rb_mProcess, "RLIMIT_STACK", INT2FIX(RLIMIT_STACK));
07632 #endif
07633 #endif
07634
07635 rb_define_module_function(rb_mProcess, "uid", proc_getuid, 0);
07636 rb_define_module_function(rb_mProcess, "uid=", proc_setuid, 1);
07637 rb_define_module_function(rb_mProcess, "gid", proc_getgid, 0);
07638 rb_define_module_function(rb_mProcess, "gid=", proc_setgid, 1);
07639 rb_define_module_function(rb_mProcess, "euid", proc_geteuid, 0);
07640 rb_define_module_function(rb_mProcess, "euid=", proc_seteuid_m, 1);
07641 rb_define_module_function(rb_mProcess, "egid", proc_getegid, 0);
07642 rb_define_module_function(rb_mProcess, "egid=", proc_setegid_m, 1);
07643 rb_define_module_function(rb_mProcess, "initgroups", proc_initgroups, 2);
07644 rb_define_module_function(rb_mProcess, "groups", proc_getgroups, 0);
07645 rb_define_module_function(rb_mProcess, "groups=", proc_setgroups, 1);
07646 rb_define_module_function(rb_mProcess, "maxgroups", proc_getmaxgroups, 0);
07647 rb_define_module_function(rb_mProcess, "maxgroups=", proc_setmaxgroups, 1);
07648
07649 rb_define_module_function(rb_mProcess, "daemon", proc_daemon, -1);
07650
07651 rb_define_module_function(rb_mProcess, "times", rb_proc_times, 0);
07652
07653 #ifdef CLOCK_REALTIME
07654 rb_define_const(rb_mProcess, "CLOCK_REALTIME", CLOCKID2NUM(CLOCK_REALTIME));
07655 #elif defined(RUBY_GETTIMEOFDAY_BASED_CLOCK_REALTIME)
07656 rb_define_const(rb_mProcess, "CLOCK_REALTIME", RUBY_GETTIMEOFDAY_BASED_CLOCK_REALTIME);
07657 #endif
07658 #ifdef CLOCK_MONOTONIC
07659 rb_define_const(rb_mProcess, "CLOCK_MONOTONIC", CLOCKID2NUM(CLOCK_MONOTONIC));
07660 #elif defined(RUBY_MACH_ABSOLUTE_TIME_BASED_CLOCK_MONOTONIC)
07661 rb_define_const(rb_mProcess, "CLOCK_MONOTONIC", RUBY_MACH_ABSOLUTE_TIME_BASED_CLOCK_MONOTONIC);
07662 #endif
07663 #ifdef CLOCK_PROCESS_CPUTIME_ID
07664 rb_define_const(rb_mProcess, "CLOCK_PROCESS_CPUTIME_ID", CLOCKID2NUM(CLOCK_PROCESS_CPUTIME_ID));
07665 #elif defined(RUBY_GETRUSAGE_BASED_CLOCK_PROCESS_CPUTIME_ID)
07666 rb_define_const(rb_mProcess, "CLOCK_PROCESS_CPUTIME_ID", RUBY_GETRUSAGE_BASED_CLOCK_PROCESS_CPUTIME_ID);
07667 #endif
07668 #ifdef CLOCK_THREAD_CPUTIME_ID
07669 rb_define_const(rb_mProcess, "CLOCK_THREAD_CPUTIME_ID", CLOCKID2NUM(CLOCK_THREAD_CPUTIME_ID));
07670 #endif
07671 #ifdef CLOCK_VIRTUAL
07672 rb_define_const(rb_mProcess, "CLOCK_VIRTUAL", CLOCKID2NUM(CLOCK_VIRTUAL));
07673 #endif
07674 #ifdef CLOCK_PROF
07675 rb_define_const(rb_mProcess, "CLOCK_PROF", CLOCKID2NUM(CLOCK_PROF));
07676 #endif
07677 #ifdef CLOCK_REALTIME_FAST
07678 rb_define_const(rb_mProcess, "CLOCK_REALTIME_FAST", CLOCKID2NUM(CLOCK_REALTIME_FAST));
07679 #endif
07680 #ifdef CLOCK_REALTIME_PRECISE
07681 rb_define_const(rb_mProcess, "CLOCK_REALTIME_PRECISE", CLOCKID2NUM(CLOCK_REALTIME_PRECISE));
07682 #endif
07683 #ifdef CLOCK_REALTIME_COARSE
07684 rb_define_const(rb_mProcess, "CLOCK_REALTIME_COARSE", CLOCKID2NUM(CLOCK_REALTIME_COARSE));
07685 #endif
07686 #ifdef CLOCK_REALTIME_ALARM
07687 rb_define_const(rb_mProcess, "CLOCK_REALTIME_ALARM", CLOCKID2NUM(CLOCK_REALTIME_ALARM));
07688 #endif
07689 #ifdef CLOCK_MONOTONIC_FAST
07690 rb_define_const(rb_mProcess, "CLOCK_MONOTONIC_FAST", CLOCKID2NUM(CLOCK_MONOTONIC_FAST));
07691 #endif
07692 #ifdef CLOCK_MONOTONIC_PRECISE
07693 rb_define_const(rb_mProcess, "CLOCK_MONOTONIC_PRECISE", CLOCKID2NUM(CLOCK_MONOTONIC_PRECISE));
07694 #endif
07695 #ifdef CLOCK_MONOTONIC_RAW
07696 rb_define_const(rb_mProcess, "CLOCK_MONOTONIC_RAW", CLOCKID2NUM(CLOCK_MONOTONIC_RAW));
07697 #endif
07698 #ifdef CLOCK_MONOTONIC_COARSE
07699 rb_define_const(rb_mProcess, "CLOCK_MONOTONIC_COARSE", CLOCKID2NUM(CLOCK_MONOTONIC_COARSE));
07700 #endif
07701 #ifdef CLOCK_BOOTTIME
07702 rb_define_const(rb_mProcess, "CLOCK_BOOTTIME", CLOCKID2NUM(CLOCK_BOOTTIME));
07703 #endif
07704 #ifdef CLOCK_BOOTTIME_ALARM
07705 rb_define_const(rb_mProcess, "CLOCK_BOOTTIME_ALARM", CLOCKID2NUM(CLOCK_BOOTTIME_ALARM));
07706 #endif
07707 #ifdef CLOCK_UPTIME
07708 rb_define_const(rb_mProcess, "CLOCK_UPTIME", CLOCKID2NUM(CLOCK_UPTIME));
07709 #endif
07710 #ifdef CLOCK_UPTIME_FAST
07711 rb_define_const(rb_mProcess, "CLOCK_UPTIME_FAST", CLOCKID2NUM(CLOCK_UPTIME_FAST));
07712 #endif
07713 #ifdef CLOCK_UPTIME_PRECISE
07714 rb_define_const(rb_mProcess, "CLOCK_UPTIME_PRECISE", CLOCKID2NUM(CLOCK_UPTIME_PRECISE));
07715 #endif
07716 #ifdef CLOCK_SECOND
07717 rb_define_const(rb_mProcess, "CLOCK_SECOND", CLOCKID2NUM(CLOCK_SECOND));
07718 #endif
07719 rb_define_module_function(rb_mProcess, "clock_gettime", rb_clock_gettime, -1);
07720 rb_define_module_function(rb_mProcess, "clock_getres", rb_clock_getres, -1);
07721
07722 #if defined(HAVE_TIMES) || defined(_WIN32)
07723 rb_cProcessTms = rb_struct_define_under(rb_mProcess, "Tms", "utime", "stime", "cutime", "cstime", NULL);
07724 rb_define_const(rb_cStruct, "Tms", rb_cProcessTms);
07725 #endif
07726
07727 SAVED_USER_ID = geteuid();
07728 SAVED_GROUP_ID = getegid();
07729
07730 rb_mProcUID = rb_define_module_under(rb_mProcess, "UID");
07731 rb_mProcGID = rb_define_module_under(rb_mProcess, "GID");
07732
07733 rb_define_module_function(rb_mProcUID, "rid", proc_getuid, 0);
07734 rb_define_module_function(rb_mProcGID, "rid", proc_getgid, 0);
07735 rb_define_module_function(rb_mProcUID, "eid", proc_geteuid, 0);
07736 rb_define_module_function(rb_mProcGID, "eid", proc_getegid, 0);
07737 rb_define_module_function(rb_mProcUID, "change_privilege", p_uid_change_privilege, 1);
07738 rb_define_module_function(rb_mProcGID, "change_privilege", p_gid_change_privilege, 1);
07739 rb_define_module_function(rb_mProcUID, "grant_privilege", p_uid_grant_privilege, 1);
07740 rb_define_module_function(rb_mProcGID, "grant_privilege", p_gid_grant_privilege, 1);
07741 rb_define_alias(rb_singleton_class(rb_mProcUID), "eid=", "grant_privilege");
07742 rb_define_alias(rb_singleton_class(rb_mProcGID), "eid=", "grant_privilege");
07743 rb_define_module_function(rb_mProcUID, "re_exchange", p_uid_exchange, 0);
07744 rb_define_module_function(rb_mProcGID, "re_exchange", p_gid_exchange, 0);
07745 rb_define_module_function(rb_mProcUID, "re_exchangeable?", p_uid_exchangeable, 0);
07746 rb_define_module_function(rb_mProcGID, "re_exchangeable?", p_gid_exchangeable, 0);
07747 rb_define_module_function(rb_mProcUID, "sid_available?", p_uid_have_saved_id, 0);
07748 rb_define_module_function(rb_mProcGID, "sid_available?", p_gid_have_saved_id, 0);
07749 rb_define_module_function(rb_mProcUID, "switch", p_uid_switch, 0);
07750 rb_define_module_function(rb_mProcGID, "switch", p_gid_switch, 0);
07751 #ifdef p_uid_from_name
07752 rb_define_module_function(rb_mProcUID, "from_name", p_uid_from_name, 1);
07753 #endif
07754 #ifdef p_gid_from_name
07755 rb_define_module_function(rb_mProcGID, "from_name", p_gid_from_name, 1);
07756 #endif
07757
07758 rb_mProcID_Syscall = rb_define_module_under(rb_mProcess, "Sys");
07759
07760 rb_define_module_function(rb_mProcID_Syscall, "getuid", proc_getuid, 0);
07761 rb_define_module_function(rb_mProcID_Syscall, "geteuid", proc_geteuid, 0);
07762 rb_define_module_function(rb_mProcID_Syscall, "getgid", proc_getgid, 0);
07763 rb_define_module_function(rb_mProcID_Syscall, "getegid", proc_getegid, 0);
07764
07765 rb_define_module_function(rb_mProcID_Syscall, "setuid", p_sys_setuid, 1);
07766 rb_define_module_function(rb_mProcID_Syscall, "setgid", p_sys_setgid, 1);
07767
07768 rb_define_module_function(rb_mProcID_Syscall, "setruid", p_sys_setruid, 1);
07769 rb_define_module_function(rb_mProcID_Syscall, "setrgid", p_sys_setrgid, 1);
07770
07771 rb_define_module_function(rb_mProcID_Syscall, "seteuid", p_sys_seteuid, 1);
07772 rb_define_module_function(rb_mProcID_Syscall, "setegid", p_sys_setegid, 1);
07773
07774 rb_define_module_function(rb_mProcID_Syscall, "setreuid", p_sys_setreuid, 2);
07775 rb_define_module_function(rb_mProcID_Syscall, "setregid", p_sys_setregid, 2);
07776
07777 rb_define_module_function(rb_mProcID_Syscall, "setresuid", p_sys_setresuid, 3);
07778 rb_define_module_function(rb_mProcID_Syscall, "setresgid", p_sys_setresgid, 3);
07779 rb_define_module_function(rb_mProcID_Syscall, "issetugid", p_sys_issetugid, 0);
07780 }
07781