Ruby 2.0.0p247(2013-06-27revision41674)

- Main Page
- Modules
- Data Structures
- Files

- File List
- Globals

process.c
Go to the documentation of this file.
1 /**********************************************************************
2
3 process.c -
4
5 $Author: nagachika $
6 created at: Tue Aug 10 14:30:50 JST 1993
7
8 Copyright (C) 1993-2007 Yukihiro Matsumoto
9 Copyright (C) 2000 Network Applied Communication Laboratory, Inc.
10 Copyright (C) 2000 Information-technology Promotion Agency, Japan
11
12 **********************************************************************/
13
14 #include "ruby/ruby.h"
15 #include "ruby/io.h"
16 #include "ruby/thread.h"
17 #include "ruby/util.h"
18 #include "internal.h"
19 #include "vm_core.h"
20
21 #include <stdio.h>
22 #include <errno.h>
23 #include <signal.h>
24 #ifdef HAVE_STDLIB_H
25 #include <stdlib.h>
26 #endif
27 #ifdef HAVE_UNISTD_H
28 #include <unistd.h>
29 #endif
30 #ifdef HAVE_FCNTL_H
31 #include <fcntl.h>
32 #endif
33 #ifdef HAVE_PROCESS_H
34 #include <process.h>
35 #endif
36
37 #include <time.h>
38 #include <ctype.h>
39
40 #ifndef EXIT_SUCCESS
41 #define EXIT_SUCCESS 0
42 #endif
43 #ifndef EXIT_FAILURE
44 #define EXIT_FAILURE 1
45 #endif
46
47 #ifdef HAVE_SYS_WAIT_H
48 # include <sys/wait.h>
49 #endif
50 #ifdef HAVE_SYS_RESOURCE_H
51 # include <sys/resource.h>
52 #endif
53 #ifdef HAVE_SYS_PARAM_H
54 # include <sys/param.h>
55 #endif
56 #ifndef MAXPATHLEN
57 # define MAXPATHLEN 1024
58 #endif
59 #include "ruby/st.h"
60
61 #ifdef __EMX__
62 #undef HAVE_GETPGRP
63 #endif
64
65 #include <sys/stat.h>
66 #if defined(__native_client__) && defined(NACL_NEWLIB)
67 # include "nacl/stat.h"
68 # include "nacl/unistd.h"
69 #endif
70
71
72 #ifdef HAVE_SYS_TIMES_H
73 #include <sys/times.h>
74 #endif
75
76 #ifdef HAVE_PWD_H
77 #include <pwd.h>
78 #endif
79 #ifdef HAVE_GRP_H
80 #include <grp.h>
81 #endif
82
83 #define numberof(array) (int)(sizeof(array)/sizeof((array)[0]))
84
85 #if defined(HAVE_TIMES) || defined(_WIN32)
86 static VALUE rb_cProcessTms;
87 #endif
88
89 #ifndef WIFEXITED
90 #define WIFEXITED(w) (((w) & 0xff) == 0)
91 #endif
92 #ifndef WIFSIGNALED
93 #define WIFSIGNALED(w) (((w) & 0x7f) > 0 && (((w) & 0x7f) < 0x7f))
94 #endif
95 #ifndef WIFSTOPPED
96 #define WIFSTOPPED(w) (((w) & 0xff) == 0x7f)
97 #endif
98 #ifndef WEXITSTATUS
99 #define WEXITSTATUS(w) (((w) >> 8) & 0xff)
100 #endif
101 #ifndef WTERMSIG
102 #define WTERMSIG(w) ((w) & 0x7f)
103 #endif
104 #ifndef WSTOPSIG
105 #define WSTOPSIG WEXITSTATUS
106 #endif
107
108 #if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__bsdi__)
109 #define HAVE_44BSD_SETUID 1
110 #define HAVE_44BSD_SETGID 1
111 #endif
112
113 #ifdef __NetBSD__
114 #undef HAVE_SETRUID
115 #undef HAVE_SETRGID
116 #endif
117
118 #ifdef BROKEN_SETREUID
119 #define setreuid ruby_setreuid
120 int setreuid(rb_uid_t ruid, rb_uid_t euid);
121 #endif
122 #ifdef BROKEN_SETREGID
123 #define setregid ruby_setregid
124 int setregid(rb_gid_t rgid, rb_gid_t egid);
125 #endif
126
127 #if defined(HAVE_44BSD_SETUID) || defined(__APPLE__)
128 #if !defined(USE_SETREUID) && !defined(BROKEN_SETREUID)
129 #define OBSOLETE_SETREUID 1
130 #endif
131 #if !defined(USE_SETREGID) && !defined(BROKEN_SETREGID)
132 #define OBSOLETE_SETREGID 1
133 #endif
134 #endif
135
136 #define preserving_errno(stmts) \
137 do {int saved_errno = errno; stmts; errno = saved_errno;} while (0)
138
139 static void check_uid_switch(void);
140 static void check_gid_switch(void);
141
142 #if 1
143 #define p_uid_from_name p_uid_from_name
144 #define p_gid_from_name p_gid_from_name
145 #endif
146
147 #if defined(HAVE_PWD_H)
148 # if defined(HAVE_GETPWNAM_R) && defined(_SC_GETPW_R_SIZE_MAX)
149 # define USE_GETPWNAM_R 1
150 # endif
151 # ifdef USE_GETPWNAM_R
152 # define PREPARE_GETPWNAM \
153 long getpw_buf_len = sysconf(_SC_GETPW_R_SIZE_MAX); \
154 char *getpw_buf = ALLOCA_N(char, (getpw_buf_len < 0 ? (getpw_buf_len = 4096) : getpw_buf_len));
155 # define OBJ2UID(id) obj2uid((id), getpw_buf, getpw_buf_len)
156 static rb_uid_t obj2uid(VALUE id, char *getpw_buf, size_t getpw_buf_len);
157 # else
158 # define PREPARE_GETPWNAM /* do nothing */
159 # define OBJ2UID(id) obj2uid((id))
160 static rb_uid_t obj2uid(VALUE id);
161 # endif
162 #else
163 # define PREPARE_GETPWNAM /* do nothing */
164 # define OBJ2UID(id) NUM2UIDT(id)
165 # ifdef p_uid_from_name
166 # undef p_uid_from_name
167 # define p_uid_from_name rb_f_notimplement
168 # endif
169 #endif
170
171 #if defined(HAVE_GRP_H)
172 # if defined(HAVE_GETGRNAM_R) && defined(_SC_GETGR_R_SIZE_MAX)
173 # define USE_GETGRNAM_R
174 # endif
175 # ifdef USE_GETGRNAM_R
176 # define PREPARE_GETGRNAM \
177 long getgr_buf_len = sysconf(_SC_GETGR_R_SIZE_MAX); \
178 char *getgr_buf = ALLOCA_N(char, (getgr_buf_len < 0 ? (getgr_buf_len = 4096) : getgr_buf_len));
179 # define OBJ2GID(id) obj2gid((id), getgr_buf, getgr_buf_len)
180 static rb_gid_t obj2gid(VALUE id, char *getgr_buf, size_t getgr_buf_len);
181 # else
182 # define PREPARE_GETGRNAM /* do nothing */
183 # define OBJ2GID(id) obj2gid((id))
184 static rb_gid_t obj2gid(VALUE id);
185 # endif
186 #else
187 # define PREPARE_GETGRNAM /* do nothing */
188 # define OBJ2GID(id) NUM2GIDT(id)
189 # ifdef p_gid_from_name
190 # undef p_gid_from_name
191 # define p_gid_from_name rb_f_notimplement
192 # endif
193 #endif
194
195 /*
196 * call-seq:
197 * Process.pid -> fixnum
198 *
199 * Returns the process id of this process. Not available on all
200 * platforms.
201 *
202 * Process.pid #=> 27415
203 */
204
205 static VALUE
206 get_pid(void)
207 {
208 rb_secure(2);
209 return PIDT2NUM(getpid());
210 }
211
212
213 /*
214 * call-seq:
215 * Process.ppid -> fixnum
216 *
217 * Returns the process id of the parent of this process. Returns
218 * untrustworthy value on Win32/64. Not available on all platforms.
219 *
220 * puts "I am #{Process.pid}"
221 * Process.fork { puts "Dad is #{Process.ppid}" }
222 *
223 * <em>produces:</em>
224 *
225 * I am 27417
226 * Dad is 27417
227 */
228
229 static VALUE
230 get_ppid(void)
231 {
232 rb_secure(2);
233 return PIDT2NUM(getppid());
234 }
235
236
237 /*********************************************************************
238 *
239 * Document-class: Process::Status
240 *
241 * <code>Process::Status</code> encapsulates the information on the
242 * status of a running or terminated system process. The built-in
243 * variable <code>$?</code> is either +nil+ or a
244 * <code>Process::Status</code> object.
245 *
246 * fork { exit 99 } #=> 26557
247 * Process.wait #=> 26557
248 * $?.class #=> Process::Status
249 * $?.to_i #=> 25344
250 * $? >> 8 #=> 99
251 * $?.stopped? #=> false
252 * $?.exited? #=> true
253 * $?.exitstatus #=> 99
254 *
255 * Posix systems record information on processes using a 16-bit
256 * integer. The lower bits record the process status (stopped,
257 * exited, signaled) and the upper bits possibly contain additional
258 * information (for example the program's return code in the case of
259 * exited processes). Pre Ruby 1.8, these bits were exposed directly
260 * to the Ruby program. Ruby now encapsulates these in a
261 * <code>Process::Status</code> object. To maximize compatibility,
262 * however, these objects retain a bit-oriented interface. In the
263 * descriptions that follow, when we talk about the integer value of
264 * _stat_, we're referring to this 16 bit value.
265 */
266
267 static VALUE rb_cProcessStatus;
268
269 VALUE
270 rb_last_status_get(void)
271 {
272 return GET_THREAD()->last_status;
273 }
274
275 void
276 rb_last_status_set(int status, rb_pid_t pid)
277 {
278 rb_thread_t *th = GET_THREAD();
279 th->last_status = rb_obj_alloc(rb_cProcessStatus);
280 rb_iv_set(th->last_status, "status", INT2FIX(status));
281 rb_iv_set(th->last_status, "pid", PIDT2NUM(pid));
282 }
283
284 void
285 rb_last_status_clear(void)
286 {
287 GET_THREAD()->last_status = Qnil;
288 }
289
290 /*
291 * call-seq:
292 * stat.to_i -> fixnum
293 * stat.to_int -> fixnum
294 *
295 * Returns the bits in _stat_ as a <code>Fixnum</code>. Poking
296 * around in these bits is platform dependent.
297 *
298 * fork { exit 0xab } #=> 26566
299 * Process.wait #=> 26566
300 * sprintf('%04x', $?.to_i) #=> "ab00"
301 */
302
303 static VALUE
304 pst_to_i(VALUE st)
305 {
306 return rb_iv_get(st, "status");
307 }
308
309 #define PST2INT(st) NUM2INT(pst_to_i(st))
310
311 /*
312 * call-seq:
313 * stat.pid -> fixnum
314 *
315 * Returns the process ID that this status object represents.
316 *
317 * fork { exit } #=> 26569
318 * Process.wait #=> 26569
319 * $?.pid #=> 26569
320 */
321
322 static VALUE
323 pst_pid(VALUE st)
324 {
325 return rb_attr_get(st, rb_intern("pid"));
326 }
327
328 static void
329 pst_message(VALUE str, rb_pid_t pid, int status)
330 {
331 rb_str_catf(str, "pid %ld", (long)pid);
332 if (WIFSTOPPED(status)) {
333 int stopsig = WSTOPSIG(status);
334 const char *signame = ruby_signal_name(stopsig);
335 if (signame) {
336 rb_str_catf(str, " stopped SIG%s (signal %d)", signame, stopsig);
337 }
338 else {
339 rb_str_catf(str, " stopped signal %d", stopsig);
340 }
341 }
342 if (WIFSIGNALED(status)) {
343 int termsig = WTERMSIG(status);
344 const char *signame = ruby_signal_name(termsig);
345 if (signame) {
346 rb_str_catf(str, " SIG%s (signal %d)", signame, termsig);
347 }
348 else {
349 rb_str_catf(str, " signal %d", termsig);
350 }
351 }
352 if (WIFEXITED(status)) {
353 rb_str_catf(str, " exit %d", WEXITSTATUS(status));
354 }
355 #ifdef WCOREDUMP
356 if (WCOREDUMP(status)) {
357 rb_str_cat2(str, " (core dumped)");
358 }
359 #endif
360 }
361
362
363 /*
364 * call-seq:
365 * stat.to_s -> string
366 *
367 * Show pid and exit status as a string.
368 *
369 * system("false")
370 * p $?.to_s #=> "pid 12766 exit 1"
371 *
372 */
373
374 static VALUE
375 pst_to_s(VALUE st)
376 {
377 rb_pid_t pid;
378 int status;
379 VALUE str;
380
381 pid = NUM2PIDT(pst_pid(st));
382 status = PST2INT(st);
383
384 str = rb_str_buf_new(0);
385 pst_message(str, pid, status);
386 return str;
387 }
388
389
390 /*
391 * call-seq:
392 * stat.inspect -> string
393 *
394 * Override the inspection method.
395 *
396 * system("false")
397 * p $?.inspect #=> "#<Process::Status: pid 12861 exit 1>"
398 *
399 */
400
401 static VALUE
402 pst_inspect(VALUE st)
403 {
404 rb_pid_t pid;
405 int status;
406 VALUE vpid, str;
407
408 vpid = pst_pid(st);
409 if (NIL_P(vpid)) {
410 return rb_sprintf("#<%s: uninitialized>", rb_class2name(CLASS_OF(st)));
411 }
412 pid = NUM2PIDT(vpid);
413 status = PST2INT(st);
414
415 str = rb_sprintf("#<%s: ", rb_class2name(CLASS_OF(st)));
416 pst_message(str, pid, status);
417 rb_str_cat2(str, ">");
418 return str;
419 }
420
421
422 /*
423 * call-seq:
424 * stat == other -> true or false
425 *
426 * Returns +true+ if the integer value of _stat_
427 * equals <em>other</em>.
428 */
429
430 static VALUE
431 pst_equal(VALUE st1, VALUE st2)
432 {
433 if (st1 == st2) return Qtrue;
434 return rb_equal(pst_to_i(st1), st2);
435 }
436
437
438 /*
439 * call-seq:
440 * stat & num -> fixnum
441 *
442 * Logical AND of the bits in _stat_ with <em>num</em>.
443 *
444 * fork { exit 0x37 }
445 * Process.wait
446 * sprintf('%04x', $?.to_i) #=> "3700"
447 * sprintf('%04x', $? & 0x1e00) #=> "1600"
448 */
449
450 static VALUE
451 pst_bitand(VALUE st1, VALUE st2)
452 {
453 int status = PST2INT(st1) & NUM2INT(st2);
454
455 return INT2NUM(status);
456 }
457
458
459 /*
460 * call-seq:
461 * stat >> num -> fixnum
462 *
463 * Shift the bits in _stat_ right <em>num</em> places.
464 *
465 * fork { exit 99 } #=> 26563
466 * Process.wait #=> 26563
467 * $?.to_i #=> 25344
468 * $? >> 8 #=> 99
469 */
470
471 static VALUE
472 pst_rshift(VALUE st1, VALUE st2)
473 {
474 int status = PST2INT(st1) >> NUM2INT(st2);
475
476 return INT2NUM(status);
477 }
478
479
480 /*
481 * call-seq:
482 * stat.stopped? -> true or false
483 *
484 * Returns +true+ if this process is stopped. This is only
485 * returned if the corresponding <code>wait</code> call had the
486 * <code>WUNTRACED</code> flag set.
487 */
488
489 static VALUE
490 pst_wifstopped(VALUE st)
491 {
492 int status = PST2INT(st);
493
494 if (WIFSTOPPED(status))
495 return Qtrue;
496 else
497 return Qfalse;
498 }
499
500
501 /*
502 * call-seq:
503 * stat.stopsig -> fixnum or nil
504 *
505 * Returns the number of the signal that caused _stat_ to stop
506 * (or +nil+ if self is not stopped).
507 */
508
509 static VALUE
510 pst_wstopsig(VALUE st)
511 {
512 int status = PST2INT(st);
513
514 if (WIFSTOPPED(status))
515 return INT2NUM(WSTOPSIG(status));
516 return Qnil;
517 }
518
519
520 /*
521 * call-seq:
522 * stat.signaled? -> true or false
523 *
524 * Returns +true+ if _stat_ terminated because of
525 * an uncaught signal.
526 */
527
528 static VALUE
529 pst_wifsignaled(VALUE st)
530 {
531 int status = PST2INT(st);
532
533 if (WIFSIGNALED(status))
534 return Qtrue;
535 else
536 return Qfalse;
537 }
538
539
540 /*
541 * call-seq:
542 * stat.termsig -> fixnum or nil
543 *
544 * Returns the number of the signal that caused _stat_ to
545 * terminate (or +nil+ if self was not terminated by an
546 * uncaught signal).
547 */
548
549 static VALUE
550 pst_wtermsig(VALUE st)
551 {
552 int status = PST2INT(st);
553
554 if (WIFSIGNALED(status))
555 return INT2NUM(WTERMSIG(status));
556 return Qnil;
557 }
558
559
560 /*
561 * call-seq:
562 * stat.exited? -> true or false
563 *
564 * Returns +true+ if _stat_ exited normally (for
565 * example using an <code>exit()</code> call or finishing the
566 * program).
567 */
568
569 static VALUE
570 pst_wifexited(VALUE st)
571 {
572 int status = PST2INT(st);
573
574 if (WIFEXITED(status))
575 return Qtrue;
576 else
577 return Qfalse;
578 }
579
580
581 /*
582 * call-seq:
583 * stat.exitstatus -> fixnum or nil
584 *
585 * Returns the least significant eight bits of the return code of
586 * _stat_. Only available if <code>exited?</code> is
587 * +true+.
588 *
589 * fork { } #=> 26572
590 * Process.wait #=> 26572
591 * $?.exited? #=> true
592 * $?.exitstatus #=> 0
593 *
594 * fork { exit 99 } #=> 26573
595 * Process.wait #=> 26573
596 * $?.exited? #=> true
597 * $?.exitstatus #=> 99
598 */
599
600 static VALUE
601 pst_wexitstatus(VALUE st)
602 {
603 int status = PST2INT(st);
604
605 if (WIFEXITED(status))
606 return INT2NUM(WEXITSTATUS(status));
607 return Qnil;
608 }
609
610
611 /*
612 * call-seq:
613 * stat.success? -> true, false or nil
614 *
615 * Returns +true+ if _stat_ is successful, +false+ if not.
616 * Returns +nil+ if <code>exited?</code> is not +true+.
617 */
618
619 static VALUE
620 pst_success_p(VALUE st)
621 {
622 int status = PST2INT(st);
623
624 if (!WIFEXITED(status))
625 return Qnil;
626 return WEXITSTATUS(status) == EXIT_SUCCESS ? Qtrue : Qfalse;
627 }
628
629
630 /*
631 * call-seq:
632 * stat.coredump? -> true or false
633 *
634 * Returns +true+ if _stat_ generated a coredump
635 * when it terminated. Not available on all platforms.
636 */
637
638 static VALUE
639 pst_wcoredump(VALUE st)
640 {
641 #ifdef WCOREDUMP
642 int status = PST2INT(st);
643
644 if (WCOREDUMP(status))
645 return Qtrue;
646 else
647 return Qfalse;
648 #else
649 return Qfalse;
650 #endif
651 }
652
653 #if !defined(HAVE_WAITPID) && !defined(HAVE_WAIT4)
654 #define NO_WAITPID
655 static st_table *pid_tbl;
656
657 struct wait_data {
658 rb_pid_t pid;
659 int status;
660 };
661
662 static int
663 wait_each(rb_pid_t pid, int status, struct wait_data *data)
664 {
665 if (data->status != -1) return ST_STOP;
666
667 data->pid = pid;
668 data->status = status;
669 return ST_DELETE;
670 }
671
672 static int
673 waitall_each(rb_pid_t pid, int status, VALUE ary)
674 {
675 rb_last_status_set(status, pid);
676 rb_ary_push(ary, rb_assoc_new(PIDT2NUM(pid), rb_last_status_get()));
677 return ST_DELETE;
678 }
679 #else
680 struct waitpid_arg {
681 rb_pid_t pid;
682 int *st;
683 int flags;
684 };
685 #endif
686
687 static void *
688 rb_waitpid_blocking(void *data)
689 {
690 rb_pid_t result;
691 #ifndef NO_WAITPID
692 struct waitpid_arg *arg = data;
693 #endif
694
695 #if defined NO_WAITPID
696 result = wait(data);
697 #elif defined HAVE_WAITPID
698 result = waitpid(arg->pid, arg->st, arg->flags);
699 #else /* HAVE_WAIT4 */
700 result = wait4(arg->pid, arg->st, arg->flags, NULL);
701 #endif
702
703 return (void *)(VALUE)result;
704 }
705
706 rb_pid_t
707 rb_waitpid(rb_pid_t pid, int *st, int flags)
708 {
709 rb_pid_t result;
710 #ifndef NO_WAITPID
711 struct waitpid_arg arg;
712
713 retry:
714 arg.pid = pid;
715 arg.st = st;
716 arg.flags = flags;
717 result = (rb_pid_t)(VALUE)rb_thread_call_without_gvl(rb_waitpid_blocking, &arg,
718 RUBY_UBF_PROCESS, 0);
719 if (result < 0) {
720 if (errno == EINTR) {
721 RUBY_VM_CHECK_INTS(GET_THREAD());
722 goto retry;
723 }
724 return (rb_pid_t)-1;
725 }
726 #else /* NO_WAITPID */
727 if (pid_tbl) {
728 st_data_t status, piddata = (st_data_t)pid;
729 if (pid == (rb_pid_t)-1) {
730 struct wait_data data;
731 data.pid = (rb_pid_t)-1;
732 data.status = -1;
733 st_foreach(pid_tbl, wait_each, (st_data_t)&data);
734 if (data.status != -1) {
735 rb_last_status_set(data.status, data.pid);
736 return data.pid;
737 }
738 }
739 else if (st_delete(pid_tbl, &piddata, &status)) {
740 rb_last_status_set(*st = (int)status, pid);
741 return pid;
742 }
743 }
744
745 if (flags) {
746 rb_raise(rb_eArgError, "can't do waitpid with flags");
747 }
748
749 for (;;) {
750 result = (rb_pid_t)(VALUE)rb_thread_blocking_region(rb_waitpid_blocking,
751 st, RUBY_UBF_PROCESS, 0);
752 if (result < 0) {
753 if (errno == EINTR) {
754 rb_thread_schedule();
755 continue;
756 }
757 return (rb_pid_t)-1;
758 }
759 if (result == pid || pid == (rb_pid_t)-1) {
760 break;
761 }
762 if (!pid_tbl)
763 pid_tbl = st_init_numtable();
764 st_insert(pid_tbl, pid, (st_data_t)st);
765 if (!rb_thread_alone()) rb_thread_schedule();
766 }
767 #endif
768 if (result > 0) {
769 rb_last_status_set(*st, result);
770 }
771 return result;
772 }
773
774
775 /* [MG]:FIXME: I wasn't sure how this should be done, since ::wait()
776 has historically been documented as if it didn't take any arguments
777 despite the fact that it's just an alias for ::waitpid(). The way I
778 have it below is more truthful, but a little confusing.
779
780 I also took the liberty of putting in the pid values, as they're
781 pretty useful, and it looked as if the original 'ri' output was
782 supposed to contain them after "[...]depending on the value of
783 aPid:".
784
785 The 'ansi' and 'bs' formats of the ri output don't display the
786 definition list for some reason, but the plain text one does.
787 */
788
789 /*
790 * call-seq:
791 * Process.wait() -> fixnum
792 * Process.wait(pid=-1, flags=0) -> fixnum
793 * Process.waitpid(pid=-1, flags=0) -> fixnum
794 *
795 * Waits for a child process to exit, returns its process id, and
796 * sets <code>$?</code> to a <code>Process::Status</code> object
797 * containing information on that process. Which child it waits on
798 * depends on the value of _pid_:
799 *
800 * > 0:: Waits for the child whose process ID equals _pid_.
801 *
802 * 0:: Waits for any child whose process group ID equals that of the
803 * calling process.
804 *
805 * -1:: Waits for any child process (the default if no _pid_ is
806 * given).
807 *
808 * < -1:: Waits for any child whose process group ID equals the absolute
809 * value of _pid_.
810 *
811 * The _flags_ argument may be a logical or of the flag values
812 * <code>Process::WNOHANG</code> (do not block if no child available)
813 * or <code>Process::WUNTRACED</code> (return stopped children that
814 * haven't been reported). Not all flags are available on all
815 * platforms, but a flag value of zero will work on all platforms.
816 *
817 * Calling this method raises a SystemCallError if there are no child
818 * processes. Not available on all platforms.
819 *
820 * include Process
821 * fork { exit 99 } #=> 27429
822 * wait #=> 27429
823 * $?.exitstatus #=> 99
824 *
825 * pid = fork { sleep 3 } #=> 27440
826 * Time.now #=> 2008-03-08 19:56:16 +0900
827 * waitpid(pid, Process::WNOHANG) #=> nil
828 * Time.now #=> 2008-03-08 19:56:16 +0900
829 * waitpid(pid, 0) #=> 27440
830 * Time.now #=> 2008-03-08 19:56:19 +0900
831 */
832
833 static VALUE
834 proc_wait(int argc, VALUE *argv)
835 {
836 VALUE vpid, vflags;
837 rb_pid_t pid;
838 int flags, status;
839
840 rb_secure(2);
841 flags = 0;
842 if (argc == 0) {
843 pid = -1;
844 }
845 else {
846 rb_scan_args(argc, argv, "02", &vpid, &vflags);
847 pid = NUM2PIDT(vpid);
848 if (argc == 2 && !NIL_P(vflags)) {
849 flags = NUM2UINT(vflags);
850 }
851 }
852 if ((pid = rb_waitpid(pid, &status, flags)) < 0)
853 rb_sys_fail(0);
854 if (pid == 0) {
855 rb_last_status_clear();
856 return Qnil;
857 }
858 return PIDT2NUM(pid);
859 }
860
861
862 /*
863 * call-seq:
864 * Process.wait2(pid=-1, flags=0) -> [pid, status]
865 * Process.waitpid2(pid=-1, flags=0) -> [pid, status]
866 *
867 * Waits for a child process to exit (see Process::waitpid for exact
868 * semantics) and returns an array containing the process id and the
869 * exit status (a <code>Process::Status</code> object) of that
870 * child. Raises a SystemCallError if there are no child processes.
871 *
872 * Process.fork { exit 99 } #=> 27437
873 * pid, status = Process.wait2
874 * pid #=> 27437
875 * status.exitstatus #=> 99
876 */
877
878 static VALUE
879 proc_wait2(int argc, VALUE *argv)
880 {
881 VALUE pid = proc_wait(argc, argv);
882 if (NIL_P(pid)) return Qnil;
883 return rb_assoc_new(pid, rb_last_status_get());
884 }
885
886
887 /*
888 * call-seq:
889 * Process.waitall -> [ [pid1,status1], ...]
890 *
891 * Waits for all children, returning an array of
892 * _pid_/_status_ pairs (where _status_ is a
893 * <code>Process::Status</code> object).
894 *
895 * fork { sleep 0.2; exit 2 } #=> 27432
896 * fork { sleep 0.1; exit 1 } #=> 27433
897 * fork { exit 0 } #=> 27434
898 * p Process.waitall
899 *
900 * <em>produces</em>:
901 *
902 * [[30982, #<Process::Status: pid 30982 exit 0>],
903 * [30979, #<Process::Status: pid 30979 exit 1>],
904 * [30976, #<Process::Status: pid 30976 exit 2>]]
905 */
906
907 static VALUE
908 proc_waitall(void)
909 {
910 VALUE result;
911 rb_pid_t pid;
912 int status;
913
914 rb_secure(2);
915 result = rb_ary_new();
916 #ifdef NO_WAITPID
917 if (pid_tbl) {
918 st_foreach(pid_tbl, waitall_each, result);
919 }
920 #else
921 rb_last_status_clear();
922 #endif
923
924 for (pid = -1;;) {
925 #ifdef NO_WAITPID
926 pid = wait(&status);
927 #else
928 pid = rb_waitpid(-1, &status, 0);
929 #endif
930 if (pid == -1) {
931 if (errno == ECHILD)
932 break;
933 #ifdef NO_WAITPID
934 if (errno == EINTR) {
935 rb_thread_schedule();
936 continue;
937 }
938 #endif
939 rb_sys_fail(0);
940 }
941 #ifdef NO_WAITPID
942 rb_last_status_set(status, pid);
943 #endif
944 rb_ary_push(result, rb_assoc_new(PIDT2NUM(pid), rb_last_status_get()));
945 }
946 return result;
947 }
948
949 static inline ID
950 id_pid(void)
951 {
952 ID pid;
953 CONST_ID(pid, "pid");
954 return pid;
955 }
956
957 static VALUE
958 detach_process_pid(VALUE thread)
959 {
960 return rb_thread_local_aref(thread, id_pid());
961 }
962
963 static VALUE
964 detach_process_watcher(void *arg)
965 {
966 rb_pid_t cpid, pid = (rb_pid_t)(VALUE)arg;
967 int status;
968
969 while ((cpid = rb_waitpid(pid, &status, 0)) == 0) {
970 /* wait while alive */
971 }
972 return rb_last_status_get();
973 }
974
975 VALUE
976 rb_detach_process(rb_pid_t pid)
977 {
978 VALUE watcher = rb_thread_create(detach_process_watcher, (void*)(VALUE)pid);
979 rb_thread_local_aset(watcher, id_pid(), PIDT2NUM(pid));
980 rb_define_singleton_method(watcher, "pid", detach_process_pid, 0);
981 return watcher;
982 }
983
984
985 /*
986 * call-seq:
987 * Process.detach(pid) -> thread
988 *
989 * Some operating systems retain the status of terminated child
990 * processes until the parent collects that status (normally using
991 * some variant of <code>wait()</code>. If the parent never collects
992 * this status, the child stays around as a <em>zombie</em> process.
993 * <code>Process::detach</code> prevents this by setting up a
994 * separate Ruby thread whose sole job is to reap the status of the
995 * process _pid_ when it terminates. Use <code>detach</code>
996 * only when you do not intent to explicitly wait for the child to
997 * terminate.
998 *
999 * The waiting thread returns the exit status of the detached process
1000 * when it terminates, so you can use <code>Thread#join</code> to
1001 * know the result. If specified _pid_ is not a valid child process
1002 * ID, the thread returns +nil+ immediately.
1003 *
1004 * The waiting thread has <code>pid</code> method which returns the pid.
1005 *
1006 * In this first example, we don't reap the first child process, so
1007 * it appears as a zombie in the process status display.
1008 *
1009 * p1 = fork { sleep 0.1 }
1010 * p2 = fork { sleep 0.2 }
1011 * Process.waitpid(p2)
1012 * sleep 2
1013 * system("ps -ho pid,state -p #{p1}")
1014 *
1015 * <em>produces:</em>
1016 *
1017 * 27389 Z
1018 *
1019 * In the next example, <code>Process::detach</code> is used to reap
1020 * the child automatically.
1021 *
1022 * p1 = fork { sleep 0.1 }
1023 * p2 = fork { sleep 0.2 }
1024 * Process.detach(p1)
1025 * Process.waitpid(p2)
1026 * sleep 2
1027 * system("ps -ho pid,state -p #{p1}")
1028 *
1029 * <em>(produces no output)</em>
1030 */
1031
1032 static VALUE
1033 proc_detach(VALUE obj, VALUE pid)
1034 {
1035 rb_secure(2);
1036 return rb_detach_process(NUM2PIDT(pid));
1037 }
1038
1039 static int forked_child = 0;
1040
1041 #ifdef SIGPIPE
1042 static RETSIGTYPE (*saved_sigpipe_handler)(int) = 0;
1043 #endif
1044
1045 #ifdef SIGPIPE
1046 static RETSIGTYPE
1047 sig_do_nothing(int sig)
1048 {
1049 }
1050 #endif
1051
1052 /* This function should be async-signal-safe. Actually it is. */
1053 static void
1054 before_exec_async_signal_safe(void)
1055 {
1056 #ifdef SIGPIPE
1057 /*
1058 * Some OS commands don't initialize signal handler properly. Thus we have
1059 * to reset signal handler before exec(). Otherwise, system() and similar
1060 * child process interaction might fail. (e.g. ruby -e "system 'yes | ls'")
1061 * [ruby-dev:12261]
1062 */
1063 saved_sigpipe_handler = signal(SIGPIPE, sig_do_nothing); /* async-signal-safe */
1064 #endif
1065 }
1066
1067 static void
1068 before_exec_non_async_signal_safe(void)
1069 {
1070 if (!forked_child) {
1071 /*
1072 * On Mac OS X 10.5.x (Leopard) or earlier, exec() may return ENOTSUPP
1073 * if the process have multiple threads. Therefore we have to kill
1074 * internal threads temporary. [ruby-core:10583]
1075 * This is also true on Haiku. It returns Errno::EPERM against exec()
1076 * in multiple threads.
1077 */
1078 rb_thread_stop_timer_thread(0);
1079 }
1080 }
1081
1082 static void
1083 before_exec(void)
1084 {
1085 before_exec_non_async_signal_safe();
1086 before_exec_async_signal_safe();
1087 }
1088
1089 /* This function should be async-signal-safe. Actually it is. */
1090 static void
1091 after_exec_async_signal_safe(void)
1092 {
1093 #ifdef SIGPIPE
1094 signal(SIGPIPE, saved_sigpipe_handler); /* async-signal-safe */
1095 #endif
1096 }
1097
1098 static void
1099 after_exec_non_async_signal_safe(void)
1100 {
1101 rb_thread_reset_timer_thread();
1102 rb_thread_start_timer_thread();
1103
1104 forked_child = 0;
1105 }
1106
1107 static void
1108 after_exec(void)
1109 {
1110 after_exec_async_signal_safe();
1111 after_exec_non_async_signal_safe();
1112 }
1113
1114 #define before_fork() before_exec()
1115 #define after_fork() (rb_threadptr_pending_interrupt_clear(GET_THREAD()), after_exec())
1116
1117 #include "dln.h"
1118
1119 static void
1120 security(const char *str)
1121 {
1122 if (rb_env_path_tainted()) {
1123 if (rb_safe_level() > 0) {
1124 rb_raise(rb_eSecurityError, "Insecure PATH - %s", str);
1125 }
1126 }
1127 }
1128
1129 #if defined(HAVE_FORK) && !defined(__native_client__)
1130
1131 /* try_with_sh and exec_with_sh should be async-signal-safe. Actually it is.*/
1132 #define try_with_sh(prog, argv, envp) ((saved_errno == ENOEXEC) ? exec_with_sh((prog), (argv), (envp)) : (void)0)
1133 static void
1134 exec_with_sh(const char *prog, char **argv, char **envp)
1135 {
1136 *argv = (char *)prog;
1137 *--argv = (char *)"sh";
1138 if (envp)
1139 execve("/bin/sh", argv, envp); /* async-signal-safe */
1140 else
1141 execv("/bin/sh", argv); /* async-signal-safe */
1142 }
1143
1144 #else
1145 #define try_with_sh(prog, argv, envp) (void)0
1146 #endif
1147
1148 /* This function should be async-signal-safe. Actually it is. */
1149 static int
1150 proc_exec_cmd(const char *prog, VALUE argv_str, VALUE envp_str)
1151 {
1152 #ifdef __native_client__
1153 rb_notimplement();
1154 UNREACHABLE;
1155 #else
1156 char **argv;
1157 char **envp;
1158 # if defined(__EMX__) || defined(OS2)
1159 char **new_argv = NULL;
1160 # endif
1161
1162 argv = ARGVSTR2ARGV(argv_str);
1163
1164 if (!prog) {
1165 errno = ENOENT;
1166 return -1;
1167 }
1168
1169 # if defined(__EMX__) || defined(OS2)
1170 {
1171 # define COMMAND "cmd.exe"
1172 char *extension;
1173
1174 if ((extension = strrchr(prog, '.')) != NULL && STRCASECMP(extension, ".bat") == 0) {
1175 char *p;
1176 int n;
1177
1178 for (n = 0; argv[n]; n++)
1179 /* no-op */;
1180 new_argv = ALLOC_N(char*, n + 2);
1181 for (; n > 0; n--)
1182 new_argv[n + 1] = argv[n];
1183 new_argv[1] = strcpy(ALLOC_N(char, strlen(argv[0]) + 1), argv[0]);
1184 for (p = new_argv[1]; *p != '\0'; p++)
1185 if (*p == '/')
1186 *p = '\\';
1187 new_argv[0] = COMMAND;
1188 argv = new_argv;
1189 prog = dln_find_exe_r(argv[0], 0, fbuf, sizeof(fbuf));
1190 if (!prog) {
1191 errno = ENOENT;
1192 return -1;
1193 }
1194 }
1195 }
1196 # endif /* __EMX__ */
1197 envp = envp_str ? (char **)RSTRING_PTR(envp_str) : NULL;
1198 if (envp_str)
1199 execve(prog, argv, envp); /* async-signal-safe */
1200 else
1201 execv(prog, argv); /* async-signal-safe */
1202 preserving_errno(try_with_sh(prog, argv, envp)); /* try_with_sh() is async-signal-safe. */
1203 # if defined(__EMX__) || defined(OS2)
1204 if (new_argv) {
1205 xfree(new_argv[0]);
1206 xfree(new_argv);
1207 }
1208 # endif
1209 return -1;
1210 #endif
1211 }
1212
1213 /* deprecated */
1214 static int
1215 proc_exec_v(char **argv, const char *prog)
1216 {
1217 char fbuf[MAXPATHLEN];
1218
1219 if (!prog)
1220 prog = argv[0];
1221 prog = dln_find_exe_r(prog, 0, fbuf, sizeof(fbuf));
1222 if (!prog) {
1223 errno = ENOENT;
1224 return -1;
1225 }
1226 before_exec();
1227 execv(prog, argv);
1228 preserving_errno(try_with_sh(prog, argv, 0); after_exec());
1229 return -1;
1230 }
1231
1232 /* deprecated */
1233 int
1234 rb_proc_exec_n(int argc, VALUE *argv, const char *prog)
1235 {
1236 #define ARGV_COUNT(n) ((n)+1)
1237 #define ARGV_SIZE(n) (sizeof(char*) * ARGV_COUNT(n))
1238 #define ALLOC_ARGV(n, v) ALLOCV_N(char*, (v), ARGV_COUNT(n))
1239
1240 char **args;
1241 int i;
1242 int ret = -1;
1243 VALUE v;
1244
1245 args = ALLOC_ARGV(argc+1, v);
1246 for (i=0; i<argc; i++) {
1247 args[i] = RSTRING_PTR(argv[i]);
1248 }
1249 args[i] = 0;
1250 if (args[0]) {
1251 ret = proc_exec_v(args, prog);
1252 }
1253 ALLOCV_END(v);
1254 return ret;
1255
1256 #undef ARGV_COUNT
1257 #undef ARGV_SIZE
1258 #undef ALLOC_ARGV
1259 }
1260
1261 /* This function should be async-signal-safe. Actually it is. */
1262 static int
1263 proc_exec_sh(const char *str, VALUE envp_str)
1264 {
1265 #ifdef __native_client__
1266 rb_notimplement();
1267 UNREACHABLE;
1268 #else
1269 const char *s;
1270
1271 s = str;
1272 while (*s == ' ' || *s == '\t' || *s == '\n')
1273 s++;
1274
1275 if (!*s) {
1276 errno = ENOENT;
1277 return -1;
1278 }
1279
1280 #ifdef _WIN32
1281 rb_w32_spawn(P_OVERLAY, (char *)str, 0);
1282 return -1;
1283 #else
1284 #if defined(__CYGWIN32__) || defined(__EMX__)
1285 {
1286 char fbuf[MAXPATHLEN];
1287 char *shell = dln_find_exe_r("sh", 0, fbuf, sizeof(fbuf));
1288 int status = -1;
1289 if (shell)
1290 execl(shell, "sh", "-c", str, (char *) NULL);
1291 else
1292 status = system(str);
1293 if (status != -1)
1294 exit(status);
1295 }
1296 #else
1297 if (envp_str)
1298 execle("/bin/sh", "sh", "-c", str, (char *)NULL, (char **)RSTRING_PTR(envp_str)); /* async-signal-safe */
1299 else
1300 execl("/bin/sh", "sh", "-c", str, (char *)NULL); /* async-signal-safe */
1301 #endif
1302 return -1;
1303 #endif /* _WIN32 */
1304 #endif
1305 }
1306
1307 int
1308 rb_proc_exec(const char *str)
1309 {
1310 int ret;
1311 before_exec();
1312 ret = proc_exec_sh(str, Qfalse);
1313 preserving_errno(after_exec());
1314 return ret;
1315 }
1316
1317 static void
1318 mark_exec_arg(void *ptr)
1319 {
1320 struct rb_execarg *eargp = ptr;
1321 if (eargp->use_shell)
1322 rb_gc_mark(eargp->invoke.sh.shell_script);
1323 else {
1324 rb_gc_mark(eargp->invoke.cmd.command_name);
1325 rb_gc_mark(eargp->invoke.cmd.command_abspath);
1326 rb_gc_mark(eargp->invoke.cmd.argv_str);
1327 rb_gc_mark(eargp->invoke.cmd.argv_buf);
1328 }
1329 rb_gc_mark(eargp->redirect_fds);
1330 rb_gc_mark(eargp->envp_str);
1331 rb_gc_mark(eargp->envp_buf);
1332 rb_gc_mark(eargp->dup2_tmpbuf);
1333 rb_gc_mark(eargp->rlimit_limits);
1334 rb_gc_mark(eargp->fd_dup2);
1335 rb_gc_mark(eargp->fd_close);
1336 rb_gc_mark(eargp->fd_open);
1337 rb_gc_mark(eargp->fd_dup2_child);
1338 rb_gc_mark(eargp->env_modification);
1339 rb_gc_mark(eargp->chdir_dir);
1340 }
1341
1342 static void
1343 free_exec_arg(void *ptr)
1344 {
1345 xfree(ptr);
1346 }
1347
1348 static size_t
1349 memsize_exec_arg(const void *ptr)
1350 {
1351 return ptr ? sizeof(struct rb_execarg) : 0;
1352 }
1353
1354 static const rb_data_type_t exec_arg_data_type = {
1355 "exec_arg",
1356 {mark_exec_arg, free_exec_arg, memsize_exec_arg},
1357 };
1358
1359 #if defined(_WIN32)
1360 #define HAVE_SPAWNV 1
1361 #endif
1362
1363 #if !defined(HAVE_FORK) && defined(HAVE_SPAWNV)
1364 # define USE_SPAWNV 1
1365 #else
1366 # define USE_SPAWNV 0
1367 #endif
1368 #ifndef P_NOWAIT
1369 # define P_NOWAIT _P_NOWAIT
1370 #endif
1371
1372 #if USE_SPAWNV
1373 #if defined(_WIN32)
1374 #define proc_spawn_cmd_internal(argv, prog) rb_w32_aspawn(P_NOWAIT, (prog), (argv))
1375 #else
1376 static rb_pid_t
1377 proc_spawn_cmd_internal(char **argv, char *prog)
1378 {
1379 char fbuf[MAXPATHLEN];
1380 rb_pid_t status;
1381
1382 if (!prog)
1383 prog = argv[0];
1384 security(prog);
1385 prog = dln_find_exe_r(prog, 0, fbuf, sizeof(fbuf));
1386 if (!prog)
1387 return -1;
1388
1389 before_exec();
1390 status = spawnv(P_NOWAIT, prog, (const char **)argv);
1391 if (status == -1 && errno == ENOEXEC) {
1392 *argv = (char *)prog;
1393 *--argv = (char *)"sh";
1394 status = spawnv(P_NOWAIT, "/bin/sh", (const char **)argv);
1395 after_exec();
1396 if (status == -1) errno = ENOEXEC;
1397 }
1398 rb_last_status_set(status == -1 ? 127 : status, 0);
1399 return status;
1400 }
1401 #endif
1402
1403 static rb_pid_t
1404 proc_spawn_cmd(char **argv, VALUE prog, struct rb_execarg *eargp)
1405 {
1406 rb_pid_t pid = -1;
1407
1408 if (argv[0]) {
1409 #if defined(_WIN32)
1410 DWORD flags = 0;
1411 if (eargp->new_pgroup_given && eargp->new_pgroup_flag) {
1412 flags = CREATE_NEW_PROCESS_GROUP;
1413 }
1414 pid = rb_w32_aspawn_flags(P_NOWAIT, prog ? RSTRING_PTR(prog) : 0, argv, flags);
1415 #else
1416 pid = proc_spawn_cmd_internal(argv, prog ? RSTRING_PTR(prog) : 0);
1417 #endif
1418 }
1419 return pid;
1420 }
1421
1422 #if defined(_WIN32)
1423 #define proc_spawn_sh(str) rb_w32_spawn(P_NOWAIT, (str), 0)
1424 #else
1425 static rb_pid_t
1426 proc_spawn_sh(char *str)
1427 {
1428 char fbuf[MAXPATHLEN];
1429 rb_pid_t status;
1430
1431 char *shell = dln_find_exe_r("sh", 0, fbuf, sizeof(fbuf));
1432 before_exec();
1433 status = spawnl(P_NOWAIT, (shell ? shell : "/bin/sh"), "sh", "-c", str, (char*)NULL);
1434 rb_last_status_set(status == -1 ? 127 : status, 0);
1435 after_exec();
1436 return status;
1437 }
1438 #endif
1439 #endif
1440
1441 static VALUE
1442 hide_obj(VALUE obj)
1443 {
1444 RBASIC(obj)->klass = 0;
1445 return obj;
1446 }
1447
1448 static VALUE
1449 check_exec_redirect_fd(VALUE v, int iskey)
1450 {
1451 VALUE tmp;
1452 int fd;
1453 if (FIXNUM_P(v)) {
1454 fd = FIX2INT(v);
1455 }
1456 else if (SYMBOL_P(v)) {
1457 ID id = SYM2ID(v);
1458 if (id == rb_intern("in"))
1459 fd = 0;
1460 else if (id == rb_intern("out"))
1461 fd = 1;
1462 else if (id == rb_intern("err"))
1463 fd = 2;
1464 else
1465 goto wrong;
1466 }
1467 else if (!NIL_P(tmp = rb_check_convert_type(v, T_FILE, "IO", "to_io"))) {
1468 rb_io_t *fptr;
1469 GetOpenFile(tmp, fptr);
1470 if (fptr->tied_io_for_writing)
1471 rb_raise(rb_eArgError, "duplex IO redirection");
1472 fd = fptr->fd;
1473 }
1474 else {
1475 rb_raise(rb_eArgError, "wrong exec redirect");
1476 }
1477 if (fd < 0) {
1478 wrong:
1479 rb_raise(rb_eArgError, "negative file descriptor");
1480 }
1481 #ifdef _WIN32
1482 else if (fd >= 3 && iskey) {
1483 rb_raise(rb_eArgError, "wrong file descriptor (%d)", fd);
1484 }
1485 #endif
1486 return INT2FIX(fd);
1487 }
1488
1489 static VALUE
1490 check_exec_redirect1(VALUE ary, VALUE key, VALUE param)
1491 {
1492 if (ary == Qfalse) {
1493 ary = hide_obj(rb_ary_new());
1494 }
1495 if (!RB_TYPE_P(key, T_ARRAY)) {
1496 VALUE fd = check_exec_redirect_fd(key, !NIL_P(param));
1497 rb_ary_push(ary, hide_obj(rb_assoc_new(fd, param)));
1498 }
1499 else {
1500 int i, n=0;
1501 for (i = 0 ; i < RARRAY_LEN(key); i++) {
1502 VALUE v = RARRAY_PTR(key)[i];
1503 VALUE fd = check_exec_redirect_fd(v, !NIL_P(param));
1504 rb_ary_push(ary, hide_obj(rb_assoc_new(fd, param)));
1505 n++;
1506 }
1507 }
1508 return ary;
1509 }
1510
1511 static void
1512 check_exec_redirect(VALUE key, VALUE val, struct rb_execarg *eargp)
1513 {
1514 VALUE param;
1515 VALUE path, flags, perm;
1516 VALUE tmp;
1517 ID id;
1518
1519 switch (TYPE(val)) {
1520 case T_SYMBOL:
1521 id = SYM2ID(val);
1522 if (id == rb_intern("close")) {
1523 param = Qnil;
1524 eargp->fd_close = check_exec_redirect1(eargp->fd_close, key, param);
1525 }
1526 else if (id == rb_intern("in")) {
1527 param = INT2FIX(0);
1528 eargp->fd_dup2 = check_exec_redirect1(eargp->fd_dup2, key, param);
1529 }
1530 else if (id == rb_intern("out")) {
1531 param = INT2FIX(1);
1532 eargp->fd_dup2 = check_exec_redirect1(eargp->fd_dup2, key, param);
1533 }
1534 else if (id == rb_intern("err")) {
1535 param = INT2FIX(2);
1536 eargp->fd_dup2 = check_exec_redirect1(eargp->fd_dup2, key, param);
1537 }
1538 else {
1539 rb_raise(rb_eArgError, "wrong exec redirect symbol: %s",
1540 rb_id2name(id));
1541 }
1542 break;
1543
1544 case T_FILE:
1545 io:
1546 val = check_exec_redirect_fd(val, 0);
1547 /* fall through */
1548 case T_FIXNUM:
1549 param = val;
1550 eargp->fd_dup2 = check_exec_redirect1(eargp->fd_dup2, key, param);
1551 break;
1552
1553 case T_ARRAY:
1554 path = rb_ary_entry(val, 0);
1555 if (RARRAY_LEN(val) == 2 && SYMBOL_P(path) &&
1556 SYM2ID(path) == rb_intern("child")) {
1557 param = check_exec_redirect_fd(rb_ary_entry(val, 1), 0);
1558 eargp->fd_dup2_child = check_exec_redirect1(eargp->fd_dup2_child, key, param);
1559 }
1560 else {
1561 FilePathValue(path);
1562 flags = rb_ary_entry(val, 1);
1563 if (NIL_P(flags))
1564 flags = INT2NUM(O_RDONLY);
1565 else if (RB_TYPE_P(flags, T_STRING))
1566 flags = INT2NUM(rb_io_modestr_oflags(StringValueCStr(flags)));
1567 else
1568 flags = rb_to_int(flags);
1569 perm = rb_ary_entry(val, 2);
1570 perm = NIL_P(perm) ? INT2FIX(0644) : rb_to_int(perm);
1571 param = hide_obj(rb_ary_new3(3, hide_obj(rb_str_dup(path)),
1572 flags, perm));
1573 eargp->fd_open = check_exec_redirect1(eargp->fd_open, key, param);
1574 }
1575 break;
1576
1577 case T_STRING:
1578 path = val;
1579 FilePathValue(path);
1580 if (RB_TYPE_P(key, T_FILE))
1581 key = check_exec_redirect_fd(key, 1);
1582 if (FIXNUM_P(key) && (FIX2INT(key) == 1 || FIX2INT(key) == 2))
1583 flags = INT2NUM(O_WRONLY|O_CREAT|O_TRUNC);
1584 else
1585 flags = INT2NUM(O_RDONLY);
1586 perm = INT2FIX(0644);
1587 param = hide_obj(rb_ary_new3(3, hide_obj(rb_str_dup(path)),
1588 flags, perm));
1589 eargp->fd_open = check_exec_redirect1(eargp->fd_open, key, param);
1590 break;
1591
1592 default:
1593 tmp = val;
1594 val = rb_io_check_io(tmp);
1595 if (!NIL_P(val)) goto io;
1596 rb_raise(rb_eArgError, "wrong exec redirect action");
1597 }
1598
1599 }
1600
1601 #if defined(HAVE_SETRLIMIT) && defined(NUM2RLIM)
1602 static int rlimit_type_by_lname(const char *name);
1603 #endif
1604
1605 int
1606 rb_execarg_addopt(VALUE execarg_obj, VALUE key, VALUE val)
1607 {
1608 struct rb_execarg *eargp = rb_execarg_get(execarg_obj);
1609
1610 ID id;
1611 #if defined(HAVE_SETRLIMIT) && defined(NUM2RLIM)
1612 int rtype;
1613 #endif
1614
1615 rb_secure(2);
1616
1617 switch (TYPE(key)) {
1618 case T_SYMBOL:
1619 id = SYM2ID(key);
1620 #ifdef HAVE_SETPGID
1621 if (id == rb_intern("pgroup")) {
1622 pid_t pgroup;
1623 if (eargp->pgroup_given) {
1624 rb_raise(rb_eArgError, "pgroup option specified twice");
1625 }
1626 if (!RTEST(val))
1627 pgroup = -1; /* asis(-1) means "don't call setpgid()". */
1628 else if (val == Qtrue)
1629 pgroup = 0; /* new process group. */
1630 else {
1631 pgroup = NUM2PIDT(val);
1632 if (pgroup < 0) {
1633 rb_raise(rb_eArgError, "negative process group ID : %ld", (long)pgroup);
1634 }
1635 }
1636 eargp->pgroup_given = 1;
1637 eargp->pgroup_pgid = pgroup;
1638 }
1639 else
1640 #endif
1641 #ifdef _WIN32
1642 if (id == rb_intern("new_pgroup")) {
1643 if (eargp->new_pgroup_given) {
1644 rb_raise(rb_eArgError, "new_pgroup option specified twice");
1645 }
1646 eargp->new_pgroup_given = 1;
1647 eargp->new_pgroup_flag = RTEST(val) ? 1 : 0;
1648 }
1649 else
1650 #endif
1651 #if defined(HAVE_SETRLIMIT) && defined(NUM2RLIM)
1652 if (strncmp("rlimit_", rb_id2name(id), 7) == 0 &&
1653 (rtype = rlimit_type_by_lname(rb_id2name(id)+7)) != -1) {
1654 VALUE ary = eargp->rlimit_limits;
1655 VALUE tmp, softlim, hardlim;
1656 if (eargp->rlimit_limits == Qfalse)
1657 ary = eargp->rlimit_limits = hide_obj(rb_ary_new());
1658 else
1659 ary = eargp->rlimit_limits;
1660 tmp = rb_check_array_type(val);
1661 if (!NIL_P(tmp)) {
1662 if (RARRAY_LEN(tmp) == 1)
1663 softlim = hardlim = rb_to_int(rb_ary_entry(tmp, 0));
1664 else if (RARRAY_LEN(tmp) == 2) {
1665 softlim = rb_to_int(rb_ary_entry(tmp, 0));
1666 hardlim = rb_to_int(rb_ary_entry(tmp, 1));
1667 }
1668 else {
1669 rb_raise(rb_eArgError, "wrong exec rlimit option");
1670 }
1671 }
1672 else {
1673 softlim = hardlim = rb_to_int(val);
1674 }
1675 tmp = hide_obj(rb_ary_new3(3, INT2NUM(rtype), softlim, hardlim));
1676 rb_ary_push(ary, tmp);
1677 }
1678 else
1679 #endif
1680 if (id == rb_intern("unsetenv_others")) {
1681 if (eargp->unsetenv_others_given) {
1682 rb_raise(rb_eArgError, "unsetenv_others option specified twice");
1683 }
1684 eargp->unsetenv_others_given = 1;
1685 eargp->unsetenv_others_do = RTEST(val) ? 1 : 0;
1686 }
1687 else if (id == rb_intern("chdir")) {
1688 if (eargp->chdir_given) {
1689 rb_raise(rb_eArgError, "chdir option specified twice");
1690 }
1691 FilePathValue(val);
1692 eargp->chdir_given = 1;
1693 eargp->chdir_dir = hide_obj(rb_str_dup(val));
1694 }
1695 else if (id == rb_intern("umask")) {
1696 mode_t cmask = NUM2MODET(val);
1697 if (eargp->umask_given) {
1698 rb_raise(rb_eArgError, "umask option specified twice");
1699 }
1700 eargp->umask_given = 1;
1701 eargp->umask_mask = cmask;
1702 }
1703 else if (id == rb_intern("close_others")) {
1704 if (eargp->close_others_given) {
1705 rb_raise(rb_eArgError, "close_others option specified twice");
1706 }
1707 eargp->close_others_given = 1;
1708 eargp->close_others_do = RTEST(val) ? 1 : 0;
1709 }
1710 else if (id == rb_intern("in")) {
1711 key = INT2FIX(0);
1712 goto redirect;
1713 }
1714 else if (id == rb_intern("out")) {
1715 key = INT2FIX(1);
1716 goto redirect;
1717 }
1718 else if (id == rb_intern("err")) {
1719 key = INT2FIX(2);
1720 goto redirect;
1721 }
1722 else if (id == rb_intern("uid")) {
1723 #ifdef HAVE_SETUID
1724 if (eargp->uid_given) {
1725 rb_raise(rb_eArgError, "uid option specified twice");
1726 }
1727 check_uid_switch();
1728 {
1729 PREPARE_GETPWNAM;
1730 eargp->uid = OBJ2UID(val);
1731 eargp->uid_given = 1;
1732 }
1733 #else
1734 rb_raise(rb_eNotImpError,
1735 "uid option is unimplemented on this machine");
1736 #endif
1737 }
1738 else if (id == rb_intern("gid")) {
1739 #ifdef HAVE_SETGID
1740 if (eargp->gid_given) {
1741 rb_raise(rb_eArgError, "gid option specified twice");
1742 }
1743 check_gid_switch();
1744 {
1745 PREPARE_GETGRNAM;
1746 eargp->gid = OBJ2GID(val);
1747 eargp->gid_given = 1;
1748 }
1749 #else
1750 rb_raise(rb_eNotImpError,
1751 "gid option is unimplemented on this machine");
1752 #endif
1753 }
1754 else {
1755 return ST_STOP;
1756 }
1757 break;
1758
1759 case T_FIXNUM:
1760 case T_FILE:
1761 case T_ARRAY:
1762 redirect:
1763 check_exec_redirect(key, val, eargp);
1764 break;
1765
1766 default:
1767 return ST_STOP;
1768 }
1769
1770 RB_GC_GUARD(execarg_obj);
1771 return ST_CONTINUE;
1772 }
1773
1774 int
1775 rb_exec_arg_addopt(struct rb_exec_arg *e, VALUE key, VALUE val)
1776 {
1777 return rb_execarg_addopt(e->execarg_obj, key, val);
1778 }
1779
1780 static int
1781 check_exec_options_i(st_data_t st_key, st_data_t st_val, st_data_t arg)
1782 {
1783 VALUE key = (VALUE)st_key;
1784 VALUE val = (VALUE)st_val;
1785 VALUE execarg_obj = (VALUE)arg;
1786 if (rb_execarg_addopt(execarg_obj, key, val) != ST_CONTINUE) {
1787 if (SYMBOL_P(key))
1788 rb_raise(rb_eArgError, "wrong exec option symbol: %"PRIsVALUE,
1789 key);
1790 rb_raise(rb_eArgError, "wrong exec option");
1791 }
1792 return ST_CONTINUE;
1793 }
1794
1795 static int
1796 check_exec_options_i_extract(st_data_t st_key, st_data_t st_val, st_data_t arg)
1797 {
1798 VALUE key = (VALUE)st_key;
1799 VALUE val = (VALUE)st_val;
1800 VALUE *args = (VALUE *)arg;
1801 VALUE execarg_obj = args[0];
1802 if (rb_execarg_addopt(execarg_obj, key, val) != ST_CONTINUE) {
1803 VALUE nonopts = args[1];
1804 if (NIL_P(nonopts)) args[1] = nonopts = rb_hash_new();
1805 rb_hash_aset(nonopts, key, val);
1806 }
1807 return ST_CONTINUE;
1808 }
1809
1810 static int
1811 check_exec_fds_1(struct rb_execarg *eargp, VALUE h, int maxhint, VALUE ary)
1812 {
1813 long i;
1814
1815 if (ary != Qfalse) {
1816 for (i = 0; i < RARRAY_LEN(ary); i++) {
1817 VALUE elt = RARRAY_PTR(ary)[i];
1818 int fd = FIX2INT(RARRAY_PTR(elt)[0]);
1819 if (RTEST(rb_hash_lookup(h, INT2FIX(fd)))) {
1820 rb_raise(rb_eArgError, "fd %d specified twice", fd);
1821 }
1822 if (ary == eargp->fd_open || ary == eargp->fd_dup2)
1823 rb_hash_aset(h, INT2FIX(fd), Qtrue);
1824 else if (ary == eargp->fd_dup2_child)
1825 rb_hash_aset(h, INT2FIX(fd), RARRAY_PTR(elt)[1]);
1826 else /* ary == eargp->fd_close */
1827 rb_hash_aset(h, INT2FIX(fd), INT2FIX(-1));
1828 if (maxhint < fd)
1829 maxhint = fd;
1830 if (ary == eargp->fd_dup2 || ary == eargp->fd_dup2_child) {
1831 fd = FIX2INT(RARRAY_PTR(elt)[1]);
1832 if (maxhint < fd)
1833 maxhint = fd;
1834 }
1835 }
1836 }
1837 return maxhint;
1838 }
1839
1840 static VALUE
1841 check_exec_fds(struct rb_execarg *eargp)
1842 {
1843 VALUE h = rb_hash_new();
1844 VALUE ary;
1845 int maxhint = -1;
1846 long i;
1847
1848 maxhint = check_exec_fds_1(eargp, h, maxhint, eargp->fd_dup2);
1849 maxhint = check_exec_fds_1(eargp, h, maxhint, eargp->fd_close);
1850 maxhint = check_exec_fds_1(eargp, h, maxhint, eargp->fd_open);
1851 maxhint = check_exec_fds_1(eargp, h, maxhint, eargp->fd_dup2_child);
1852
1853 if (eargp->fd_dup2_child) {
1854 ary = eargp->fd_dup2_child;
1855 for (i = 0; i < RARRAY_LEN(ary); i++) {
1856 VALUE elt = RARRAY_PTR(ary)[i];
1857 int newfd = FIX2INT(RARRAY_PTR(elt)[0]);
1858 int oldfd = FIX2INT(RARRAY_PTR(elt)[1]);
1859 int lastfd = oldfd;
1860 VALUE val = rb_hash_lookup(h, INT2FIX(lastfd));
1861 long depth = 0;
1862 while (FIXNUM_P(val) && 0 <= FIX2INT(val)) {
1863 lastfd = FIX2INT(val);
1864 val = rb_hash_lookup(h, val);
1865 if (RARRAY_LEN(ary) < depth)
1866 rb_raise(rb_eArgError, "cyclic child fd redirection from %d", oldfd);
1867 depth++;
1868 }
1869 if (val != Qtrue)
1870 rb_raise(rb_eArgError, "child fd %d is not redirected", oldfd);
1871 if (oldfd != lastfd) {
1872 VALUE val2;
1873 rb_ary_store(elt, 1, INT2FIX(lastfd));
1874 rb_hash_aset(h, INT2FIX(newfd), INT2FIX(lastfd));
1875 val = INT2FIX(oldfd);
1876 while (FIXNUM_P(val2 = rb_hash_lookup(h, val))) {
1877 rb_hash_aset(h, val, INT2FIX(lastfd));
1878 val = val2;
1879 }
1880 }
1881 }
1882 }
1883
1884 eargp->close_others_maxhint = maxhint;
1885 return h;
1886 }
1887
1888 static void
1889 rb_check_exec_options(VALUE opthash, VALUE execarg_obj)
1890 {
1891 if (RHASH_EMPTY_P(opthash))
1892 return;
1893 st_foreach(RHASH_TBL(opthash), check_exec_options_i, (st_data_t)execarg_obj);
1894 }
1895
1896 VALUE
1897 rb_execarg_extract_options(VALUE execarg_obj, VALUE opthash)
1898 {
1899 VALUE args[2];
1900 if (RHASH_EMPTY_P(opthash))
1901 return Qnil;
1902 args[0] = execarg_obj;
1903 args[1] = Qnil;
1904 st_foreach(RHASH_TBL(opthash), check_exec_options_i_extract, (st_data_t)args);
1905 return args[1];
1906 }
1907
1908 static int
1909 check_exec_env_i(st_data_t st_key, st_data_t st_val, st_data_t arg)
1910 {
1911 VALUE key = (VALUE)st_key;
1912 VALUE val = (VALUE)st_val;
1913 VALUE env = (VALUE)arg;
1914 char *k;
1915
1916 k = StringValueCStr(key);
1917 if (strchr(k, '='))
1918 rb_raise(rb_eArgError, "environment name contains a equal : %s", k);
1919
1920 if (!NIL_P(val))
1921 StringValueCStr(val);
1922
1923 rb_ary_push(env, hide_obj(rb_assoc_new(key, val)));
1924
1925 return ST_CONTINUE;
1926 }
1927
1928 static VALUE
1929 rb_check_exec_env(VALUE hash)
1930 {
1931 VALUE env;
1932
1933 env = hide_obj(rb_ary_new());
1934 st_foreach(RHASH_TBL(hash), check_exec_env_i, (st_data_t)env);
1935
1936 return env;
1937 }
1938
1939 static VALUE
1940 rb_check_argv(int argc, VALUE *argv)
1941 {
1942 VALUE tmp, prog;
1943 int i;
1944 const char *name = 0;
1945
1946 rb_check_arity(argc, 1, UNLIMITED_ARGUMENTS);
1947
1948 prog = 0;
1949 tmp = rb_check_array_type(argv[0]);
1950 if (!NIL_P(tmp)) {
1951 if (RARRAY_LEN(tmp) != 2) {
1952 rb_raise(rb_eArgError, "wrong first argument");
1953 }
1954 prog = RARRAY_PTR(tmp)[0];
1955 argv[0] = RARRAY_PTR(tmp)[1];
1956 SafeStringValue(prog);
1957 StringValueCStr(prog);
1958 prog = rb_str_new_frozen(prog);
1959 name = RSTRING_PTR(prog);
1960 }
1961 for (i = 0; i < argc; i++) {
1962 SafeStringValue(argv[i]);
1963 argv[i] = rb_str_new_frozen(argv[i]);
1964 StringValueCStr(argv[i]);
1965 }
1966 security(name ? name : RSTRING_PTR(argv[0]));
1967 return prog;
1968 }
1969
1970 static VALUE
1971 rb_exec_getargs(int *argc_p, VALUE **argv_p, int accept_shell, VALUE *env_ret, VALUE *opthash_ret)
1972 {
1973 VALUE hash, prog;
1974
1975 if (0 < *argc_p) {
1976 hash = rb_check_hash_type((*argv_p)[*argc_p-1]);
1977 if (!NIL_P(hash)) {
1978 *opthash_ret = hash;
1979 (*argc_p)--;
1980 }
1981 }
1982
1983 if (0 < *argc_p) {
1984 hash = rb_check_hash_type((*argv_p)[0]);
1985 if (!NIL_P(hash)) {
1986 *env_ret = hash;
1987 (*argc_p)--;
1988 (*argv_p)++;
1989 }
1990 }
1991 prog = rb_check_argv(*argc_p, *argv_p);
1992 if (!prog) {
1993 prog = (*argv_p)[0];
1994 if (accept_shell && *argc_p == 1) {
1995 *argc_p = 0;
1996 *argv_p = 0;
1997 }
1998 }
1999 return prog;
2000 }
2001
2002 #ifndef _WIN32
2003 struct string_part {
2004 const char *ptr;
2005 size_t len;
2006 };
2007
2008 static int
2009 compare_posix_sh(const void *key, const void *el)
2010 {
2011 const struct string_part *word = key;
2012 int ret = strncmp(word->ptr, el, word->len);
2013 if (!ret && ((const char *)el)[word->len]) ret = -1;
2014 return ret;
2015 }
2016 #endif
2017
2018 static void
2019 rb_exec_fillarg(VALUE prog, int argc, VALUE *argv, VALUE env, VALUE opthash, VALUE execarg_obj)
2020 {
2021 struct rb_execarg *eargp = rb_execarg_get(execarg_obj);
2022 char fbuf[MAXPATHLEN];
2023
2024 MEMZERO(eargp, struct rb_execarg, 1);
2025
2026 if (!NIL_P(opthash)) {
2027 rb_check_exec_options(opthash, execarg_obj);
2028 }
2029 if (!NIL_P(env)) {
2030 env = rb_check_exec_env(env);
2031 eargp->env_modification = env;
2032 }
2033
2034 eargp->use_shell = argc == 0;
2035 if (eargp->use_shell)
2036 eargp->invoke.sh.shell_script = prog;
2037 else
2038 eargp->invoke.cmd.command_name = prog;
2039
2040 #ifndef _WIN32
2041 if (eargp->use_shell) {
2042 static const char posix_sh_cmds[][9] = {
2043 "!", /* reserved */
2044 ".", /* special built-in */
2045 ":", /* special built-in */
2046 "break", /* special built-in */
2047 "case", /* reserved */
2048 "continue", /* special built-in */
2049 "do", /* reserved */
2050 "done", /* reserved */
2051 "elif", /* reserved */
2052 "else", /* reserved */
2053 "esac", /* reserved */
2054 "eval", /* special built-in */
2055 "exec", /* special built-in */
2056 "exit", /* special built-in */
2057 "export", /* special built-in */
2058 "fi", /* reserved */
2059 "for", /* reserved */
2060 "if", /* reserved */
2061 "in", /* reserved */
2062 "readonly", /* special built-in */
2063 "return", /* special built-in */
2064 "set", /* special built-in */
2065 "shift", /* special built-in */
2066 "then", /* reserved */
2067 "times", /* special built-in */
2068 "trap", /* special built-in */
2069 "unset", /* special built-in */
2070 "until", /* reserved */
2071 "while", /* reserved */
2072 };
2073 const char *p;
2074 struct string_part first = {0, 0};
2075 int has_meta = 0;
2076 /*
2077 * meta characters:
2078 *
2079 * * Pathname Expansion
2080 * ? Pathname Expansion
2081 * {} Grouping Commands
2082 * [] Pathname Expansion
2083 * <> Redirection
2084 * () Grouping Commands
2085 * ~ Tilde Expansion
2086 * & AND Lists, Asynchronous Lists
2087 * | OR Lists, Pipelines
2088 * \ Escape Character
2089 * $ Parameter Expansion
2090 * ; Sequential Lists
2091 * ' Single-Quotes
2092 * ` Command Substitution
2093 * " Double-Quotes
2094 * \n Lists
2095 *
2096 * # Comment
2097 * = Assignment preceding command name
2098 * % (used in Parameter Expansion)
2099 */
2100 for (p = RSTRING_PTR(prog); *p; p++) {
2101 if (*p == ' ' || *p == '\t') {
2102 if (first.ptr && !first.len) first.len = p - first.ptr;
2103 }
2104 else {
2105 if (!first.ptr) first.ptr = p;
2106 }
2107 if (!has_meta && strchr("*?{}[]<>()~&|\\$;'`\"\n#", *p))
2108 has_meta = 1;
2109 if (!first.len) {
2110 if (*p == '=') {
2111 has_meta = 1;
2112 }
2113 else if (*p == '/') {
2114 first.len = 0x100; /* longer than any posix_sh_cmds */
2115 }
2116 }
2117 if (has_meta)
2118 break;
2119 }
2120 if (!has_meta && first.ptr) {
2121 if (!first.len) first.len = p - first.ptr;
2122 if (first.len > 0 && first.len <= sizeof(posix_sh_cmds[0]) &&
2123 bsearch(&first, posix_sh_cmds, numberof(posix_sh_cmds), sizeof(posix_sh_cmds[0]), compare_posix_sh))
2124 has_meta = 1;
2125 }
2126 if (!has_meta) {
2127 /* avoid shell since no shell meta charactor found. */
2128 eargp->use_shell = 0;
2129 }
2130 if (!eargp->use_shell) {
2131 VALUE argv_buf;
2132 argv_buf = hide_obj(rb_str_buf_new(0));
2133 p = RSTRING_PTR(prog);
2134 while (*p) {
2135 while (*p == ' ' || *p == '\t')
2136 p++;
2137 if (*p) {
2138 const char *w = p;
2139 while (*p && *p != ' ' && *p != '\t')
2140 p++;
2141 rb_str_buf_cat(argv_buf, w, p-w);
2142 rb_str_buf_cat(argv_buf, "", 1); /* append '\0' */
2143 }
2144 }
2145 eargp->invoke.cmd.argv_buf = argv_buf;
2146 eargp->invoke.cmd.command_name = hide_obj(rb_str_new_cstr(RSTRING_PTR(argv_buf)));
2147 }
2148 }
2149 #endif
2150
2151 if (!eargp->use_shell) {
2152 const char *abspath;
2153 abspath = dln_find_exe_r(RSTRING_PTR(eargp->invoke.cmd.command_name), 0, fbuf, sizeof(fbuf));
2154 if (abspath)
2155 eargp->invoke.cmd.command_abspath = rb_str_new_cstr(abspath);
2156 else
2157 eargp->invoke.cmd.command_abspath = Qnil;
2158 }
2159
2160 if (!eargp->use_shell && !eargp->invoke.cmd.argv_buf) {
2161 int i;
2162 VALUE argv_buf;
2163 argv_buf = rb_str_buf_new(0);
2164 hide_obj(argv_buf);
2165 for (i = 0; i < argc; i++) {
2166 rb_str_buf_cat2(argv_buf, StringValueCStr(argv[i]));
2167 rb_str_buf_cat(argv_buf, "", 1); /* append '\0' */
2168 }
2169 eargp->invoke.cmd.argv_buf = argv_buf;
2170 }
2171
2172 if (!eargp->use_shell) {
2173 const char *p, *ep, *null=NULL;
2174 VALUE argv_str;
2175 argv_str = hide_obj(rb_str_buf_new(sizeof(char*) * (argc + 2)));
2176 rb_str_buf_cat(argv_str, (char *)&null, sizeof(null)); /* place holder for /bin/sh of try_with_sh. */
2177 p = RSTRING_PTR(eargp->invoke.cmd.argv_buf);
2178 ep = p + RSTRING_LEN(eargp->invoke.cmd.argv_buf);
2179 while (p < ep) {
2180 rb_str_buf_cat(argv_str, (char *)&p, sizeof(p));
2181 p += strlen(p) + 1;
2182 }
2183 rb_str_buf_cat(argv_str, (char *)&null, sizeof(null)); /* terminator for execve. */
2184 eargp->invoke.cmd.argv_str = argv_str;
2185 }
2186 RB_GC_GUARD(execarg_obj);
2187 }
2188
2189 VALUE
2190 rb_execarg_new(int argc, VALUE *argv, int accept_shell)
2191 {
2192 VALUE execarg_obj;
2193 struct rb_execarg *eargp;
2194 execarg_obj = TypedData_Make_Struct(rb_cData, struct rb_execarg, &exec_arg_data_type, eargp);
2195 hide_obj(execarg_obj);
2196 rb_execarg_init(argc, argv, accept_shell, execarg_obj);
2197 return execarg_obj;
2198 }
2199
2200 struct rb_execarg
2201 *rb_execarg_get(VALUE execarg_obj)
2202 {
2203 struct rb_execarg *eargp;
2204 TypedData_Get_Struct(execarg_obj, struct rb_execarg, &exec_arg_data_type, eargp);
2205 return eargp;
2206 }
2207
2208 VALUE
2209 rb_execarg_init(int argc, VALUE *argv, int accept_shell, VALUE execarg_obj)
2210 {
2211 struct rb_execarg *eargp = rb_execarg_get(execarg_obj);
2212 VALUE prog, ret;
2213 VALUE env = Qnil, opthash = Qnil;
2214 prog = rb_exec_getargs(&argc, &argv, accept_shell, &env, &opthash);
2215 rb_exec_fillarg(prog, argc, argv, env, opthash, execarg_obj);
2216 ret = eargp->use_shell ? eargp->invoke.sh.shell_script : eargp->invoke.cmd.command_name;
2217 RB_GC_GUARD(execarg_obj);
2218 return ret;
2219 }
2220
2221 VALUE
2222 rb_exec_arg_init(int argc, VALUE *argv, int accept_shell, struct rb_exec_arg *e)
2223 {
2224 return rb_execarg_init(argc, argv, accept_shell, e->execarg_obj);
2225 }
2226
2227 void
2228 rb_execarg_setenv(VALUE execarg_obj, VALUE env)
2229 {
2230 struct rb_execarg *eargp = rb_execarg_get(execarg_obj);
2231 env = !NIL_P(env) ? rb_check_exec_env(env) : Qfalse;
2232 eargp->env_modification = env;
2233 }
2234
2235 static int
2236 fill_envp_buf_i(st_data_t st_key, st_data_t st_val, st_data_t arg)
2237 {
2238 VALUE key = (VALUE)st_key;
2239 VALUE val = (VALUE)st_val;
2240 VALUE envp_buf = (VALUE)arg;
2241
2242 rb_str_buf_cat2(envp_buf, StringValueCStr(key));
2243 rb_str_buf_cat2(envp_buf, "=");
2244 rb_str_buf_cat2(envp_buf, StringValueCStr(val));
2245 rb_str_buf_cat(envp_buf, "", 1); /* append '\0' */
2246
2247 return ST_CONTINUE;
2248 }
2249
2250
2251 static long run_exec_dup2_tmpbuf_size(long n);
2252
2253 void
2254 rb_execarg_fixup(VALUE execarg_obj)
2255 {
2256 struct rb_execarg *eargp = rb_execarg_get(execarg_obj);
2257 int unsetenv_others;
2258 VALUE envopts;
2259 VALUE ary;
2260
2261 eargp->redirect_fds = check_exec_fds(eargp);
2262
2263 ary = eargp->fd_dup2;
2264 if (ary != Qfalse) {
2265 size_t len = run_exec_dup2_tmpbuf_size(RARRAY_LEN(ary));
2266 VALUE tmpbuf = hide_obj(rb_str_new(0, len));
2267 rb_str_set_len(tmpbuf, len);
2268 eargp->dup2_tmpbuf = tmpbuf;
2269 }
2270
2271 unsetenv_others = eargp->unsetenv_others_given && eargp->unsetenv_others_do;
2272 envopts = eargp->env_modification;
2273 if (unsetenv_others || envopts != Qfalse) {
2274 VALUE envtbl, envp_str, envp_buf;
2275 char *p, *ep;
2276 if (unsetenv_others) {
2277 envtbl = rb_hash_new();
2278 }
2279 else {
2280 envtbl = rb_const_get(rb_cObject, rb_intern("ENV"));
2281 envtbl = rb_convert_type(envtbl, T_HASH, "Hash", "to_hash");
2282 }
2283 hide_obj(envtbl);
2284 if (envopts != Qfalse) {
2285 st_table *stenv = RHASH_TBL(envtbl);
2286 long i;
2287 for (i = 0; i < RARRAY_LEN(envopts); i++) {
2288 VALUE pair = RARRAY_PTR(envopts)[i];
2289 VALUE key = RARRAY_PTR(pair)[0];
2290 VALUE val = RARRAY_PTR(pair)[1];
2291 if (NIL_P(val)) {
2292 st_data_t stkey = (st_data_t)key;
2293 st_delete(stenv, &stkey, NULL);
2294 }
2295 else {
2296 st_insert(stenv, (st_data_t)key, (st_data_t)val);
2297 }
2298 }
2299 }
2300 envp_buf = rb_str_buf_new(0);
2301 hide_obj(envp_buf);
2302 st_foreach(RHASH_TBL(envtbl), fill_envp_buf_i, (st_data_t)envp_buf);
2303 envp_str = rb_str_buf_new(sizeof(char*) * (RHASH_SIZE(envtbl) + 1));
2304 hide_obj(envp_str);
2305 p = RSTRING_PTR(envp_buf);
2306 ep = p + RSTRING_LEN(envp_buf);
2307 while (p < ep) {
2308 rb_str_buf_cat(envp_str, (char *)&p, sizeof(p));
2309 p += strlen(p) + 1;
2310 }
2311 p = NULL;
2312 rb_str_buf_cat(envp_str, (char *)&p, sizeof(p));
2313 eargp->envp_str = envp_str;
2314 eargp->envp_buf = envp_buf;
2315
2316 /*
2317 char **tmp_envp = (char **)RSTRING_PTR(envp_str);
2318 while (*tmp_envp) {
2319 printf("%s\n", *tmp_envp);
2320 tmp_envp++;
2321 }
2322 */
2323 }
2324 RB_GC_GUARD(execarg_obj);
2325 }
2326
2327 void
2328 rb_exec_arg_fixup(struct rb_exec_arg *e)
2329 {
2330 rb_execarg_fixup(e->execarg_obj);
2331 }
2332
2333 static int rb_exec_without_timer_thread(const struct rb_execarg *eargp, char *errmsg, size_t errmsg_buflen);
2334
2335 /*
2336 * call-seq:
2337 * exec([env,] command... [,options])
2338 *
2339 * Replaces the current process by running the given external _command_.
2340 * _command..._ is one of following forms.
2341 *
2342 * commandline : command line string which is passed to the standard shell
2343 * cmdname, arg1, ... : command name and one or more arguments (no shell)
2344 * [cmdname, argv0], arg1, ... : command name, argv[0] and zero or more arguments (no shell)
2345 *
2346 * If single string is given as the command,
2347 * it is taken as a command line that is subject to shell expansion before being executed.
2348 *
2349 * The standard shell means always <code>"/bin/sh"</code> on Unix-like systems,
2350 * <code>ENV["RUBYSHELL"]</code> or <code>ENV["COMSPEC"]</code> on Windows NT series, and
2351 * similar.
2352 *
2353 * If two or more +string+ given,
2354 * the first is taken as a command name and
2355 * the rest are passed as parameters to command with no shell expansion.
2356 *
2357 * If a two-element array at the beginning of the command,
2358 * the first element is the command to be executed,
2359 * and the second argument is used as the <code>argv[0]</code> value,
2360 * which may show up in process listings.
2361 *
2362 * In order to execute the command, one of the <code>exec(2)</code>
2363 * system calls is used, so the running command may inherit some of the environment
2364 * of the original program (including open file descriptors).
2365 * This behavior is modified by env and options.
2366 * See <code>spawn</code> for details.
2367 *
2368 * Raises SystemCallError if the command couldn't execute (typically
2369 * <code>Errno::ENOENT</code> when it was not found).
2370 *
2371 * This method modifies process attributes according to _options_
2372 * (details described in <code>spawn</code>)
2373 * before <code>exec(2)</code> system call.
2374 * The modified attributes may be retained when <code>exec(2)</code> system call fails.
2375 * For example, hard resource limits is not restorable.
2376 * If it is not acceptable, consider to create a child process using <code>spawn</code> or <code>system</code>.
2377 *
2378 * exec "echo *" # echoes list of files in current directory
2379 * # never get here
2380 *
2381 *
2382 * exec "echo", "*" # echoes an asterisk
2383 * # never get here
2384 */
2385
2386 VALUE
2387 rb_f_exec(int argc, VALUE *argv)
2388 {
2389 VALUE execarg_obj, fail_str;
2390 struct rb_execarg *eargp;
2391 #define CHILD_ERRMSG_BUFLEN 80
2392 char errmsg[CHILD_ERRMSG_BUFLEN] = { '\0' };
2393
2394 execarg_obj = rb_execarg_new(argc, argv, TRUE);
2395 eargp = rb_execarg_get(execarg_obj);
2396 rb_execarg_fixup(execarg_obj);
2397 fail_str = eargp->use_shell ? eargp->invoke.sh.shell_script : eargp->invoke.cmd.command_name;
2398
2399 #if defined(__APPLE__) || defined(__HAIKU__)
2400 rb_exec_without_timer_thread(eargp, errmsg, sizeof(errmsg));
2401 #else
2402 rb_exec_async_signal_safe(eargp, errmsg, sizeof(errmsg));
2403 #endif
2404 RB_GC_GUARD(execarg_obj);
2405 if (errmsg[0])
2406 rb_sys_fail(errmsg);
2407 rb_sys_fail_str(fail_str);
2408 return Qnil; /* dummy */
2409 }
2410
2411 #define ERRMSG(str) do { if (errmsg && 0 < errmsg_buflen) strlcpy(errmsg, (str), errmsg_buflen); } while (0)
2412
2413 /*#define DEBUG_REDIRECT*/
2414 #if defined(DEBUG_REDIRECT)
2415
2416 #include <stdarg.h>
2417
2418 static void
2419 ttyprintf(const char *fmt, ...)
2420 {
2421 va_list ap;
2422 FILE *tty;
2423 int save = errno;
2424 #ifdef _WIN32
2425 tty = fopen("con", "w");
2426 #else
2427 tty = fopen("/dev/tty", "w");
2428 #endif
2429 if (!tty)
2430 return;
2431
2432 va_start(ap, fmt);
2433 vfprintf(tty, fmt, ap);
2434 va_end(ap);
2435 fclose(tty);
2436 errno = save;
2437 }
2438
2439 static int
2440 redirect_dup(int oldfd)
2441 {
2442 int ret;
2443 ret = dup(oldfd);
2444 ttyprintf("dup(%d) => %d\n", oldfd, ret);
2445 return ret;
2446 }
2447 #else
2448 #define redirect_dup(oldfd) dup(oldfd)
2449 #endif
2450
2451 #if defined(DEBUG_REDIRECT) || defined(_WIN32)
2452 static int
2453 redirect_dup2(int oldfd, int newfd)
2454 {
2455 int ret;
2456 ret = dup2(oldfd, newfd);
2457 if (newfd >= 0 && newfd <= 2)
2458 SetStdHandle(newfd == 0 ? STD_INPUT_HANDLE : newfd == 1 ? STD_OUTPUT_HANDLE : STD_ERROR_HANDLE, (HANDLE)rb_w32_get_osfhandle(newfd));
2459 #if defined(DEBUG_REDIRECT)
2460 ttyprintf("dup2(%d, %d)\n", oldfd, newfd);
2461 #endif
2462 return ret;
2463 }
2464 #else
2465 #define redirect_dup2(oldfd, newfd) dup2((oldfd), (newfd))
2466 #endif
2467
2468 #if defined(DEBUG_REDIRECT)
2469 static int
2470 redirect_close(int fd)
2471 {
2472 int ret;
2473 ret = close(fd);
2474 ttyprintf("close(%d)\n", fd);
2475 return ret;
2476 }
2477
2478 static int
2479 redirect_open(const char *pathname, int flags, mode_t perm)
2480 {
2481 int ret;
2482 ret = open(pathname, flags, perm);
2483 ttyprintf("open(\"%s\", 0x%x, 0%o) => %d\n", pathname, flags, perm, ret);
2484 return ret;
2485 }
2486
2487 #else
2488 #define redirect_close(fd) close(fd)
2489 #define redirect_open(pathname, flags, perm) open((pathname), (flags), (perm))
2490 #endif
2491
2492 static int
2493 save_redirect_fd(int fd, struct rb_execarg *sargp, char *errmsg, size_t errmsg_buflen)
2494 {
2495 if (sargp) {
2496 VALUE newary;
2497 int save_fd = redirect_dup(fd);
2498 if (save_fd == -1) {
2499 if (errno == EBADF)
2500 return 0;
2501 ERRMSG("dup");
2502 return -1;
2503 }
2504 rb_update_max_fd(save_fd);
2505 newary = sargp->fd_dup2;
2506 if (newary == Qfalse) {
2507 newary = hide_obj(rb_ary_new());
2508 sargp->fd_dup2 = newary;
2509 }
2510 rb_ary_push(newary,
2511 hide_obj(rb_assoc_new(INT2FIX(fd), INT2FIX(save_fd))));
2512
2513 newary = sargp->fd_close;
2514 if (newary == Qfalse) {
2515 newary = hide_obj(rb_ary_new());
2516 sargp->fd_close = newary;
2517 }
2518 rb_ary_push(newary, hide_obj(rb_assoc_new(INT2FIX(save_fd), Qnil)));
2519 }
2520
2521 return 0;
2522 }
2523
2524 static int
2525 intcmp(const void *a, const void *b)
2526 {
2527 return *(int*)a - *(int*)b;
2528 }
2529
2530 static int
2531 intrcmp(const void *a, const void *b)
2532 {
2533 return *(int*)b - *(int*)a;
2534 }
2535
2536 struct run_exec_dup2_fd_pair {
2537 int oldfd;
2538 int newfd;
2539 long older_index;
2540 long num_newer;
2541 };
2542
2543 static long
2544 run_exec_dup2_tmpbuf_size(long n)
2545 {
2546 return sizeof(struct run_exec_dup2_fd_pair) * n;
2547 }
2548
2549 /* This function should be async-signal-safe when sargp is NULL. Hopefully it is. */
2550 static int
2551 run_exec_dup2(VALUE ary, VALUE tmpbuf, struct rb_execarg *sargp, char *errmsg, size_t errmsg_buflen)
2552 {
2553 long n, i;
2554 int ret;
2555 int extra_fd = -1;
2556 struct run_exec_dup2_fd_pair *pairs = 0;
2557
2558 n = RARRAY_LEN(ary);
2559 pairs = (struct run_exec_dup2_fd_pair *)RSTRING_PTR(tmpbuf);
2560
2561 /* initialize oldfd and newfd: O(n) */
2562 for (i = 0; i < n; i++) {
2563 VALUE elt = RARRAY_PTR(ary)[i];
2564 pairs[i].oldfd = FIX2INT(RARRAY_PTR(elt)[1]);
2565 pairs[i].newfd = FIX2INT(RARRAY_PTR(elt)[0]); /* unique */
2566 pairs[i].older_index = -1;
2567 }
2568
2569 /* sort the table by oldfd: O(n log n) */
2570 if (!sargp)
2571 qsort(pairs, n, sizeof(struct run_exec_dup2_fd_pair), intcmp); /* hopefully async-signal-safe */
2572 else
2573 qsort(pairs, n, sizeof(struct run_exec_dup2_fd_pair), intrcmp);
2574
2575 /* initialize older_index and num_newer: O(n log n) */
2576 for (i = 0; i < n; i++) {
2577 int newfd = pairs[i].newfd;
2578 struct run_exec_dup2_fd_pair key, *found;
2579 key.oldfd = newfd;
2580 found = bsearch(&key, pairs, n, sizeof(struct run_exec_dup2_fd_pair), intcmp); /* hopefully async-signal-safe */
2581 pairs[i].num_newer = 0;
2582 if (found) {
2583 while (pairs < found && (found-1)->oldfd == newfd)
2584 found--;
2585 while (found < pairs+n && found->oldfd == newfd) {
2586 pairs[i].num_newer++;
2587 found->older_index = i;
2588 found++;
2589 }
2590 }
2591 }
2592
2593 /* non-cyclic redirection: O(n) */
2594 for (i = 0; i < n; i++) {
2595 long j = i;
2596 while (j != -1 && pairs[j].oldfd != -1 && pairs[j].num_newer == 0) {
2597 if (save_redirect_fd(pairs[j].newfd, sargp, errmsg, errmsg_buflen) < 0) /* async-signal-safe */
2598 goto fail;
2599 ret = redirect_dup2(pairs[j].oldfd, pairs[j].newfd); /* async-signal-safe */
2600 if (ret == -1) {
2601 ERRMSG("dup2");
2602 goto fail;
2603 }
2604 rb_update_max_fd(pairs[j].newfd); /* async-signal-safe but don't need to call it in a child process. */
2605 pairs[j].oldfd = -1;
2606 j = pairs[j].older_index;
2607 if (j != -1)
2608 pairs[j].num_newer--;
2609 }
2610 }
2611
2612 /* cyclic redirection: O(n) */
2613 for (i = 0; i < n; i++) {
2614 long j;
2615 if (pairs[i].oldfd == -1)
2616 continue;
2617 if (pairs[i].oldfd == pairs[i].newfd) { /* self cycle */
2618 #ifdef F_GETFD
2619 int fd = pairs[i].oldfd;
2620 ret = fcntl(fd, F_GETFD); /* async-signal-safe */
2621 if (ret == -1) {
2622 ERRMSG("fcntl(F_GETFD)");
2623 goto fail;
2624 }
2625 if (ret & FD_CLOEXEC) {
2626 ret &= ~FD_CLOEXEC;
2627 ret = fcntl(fd, F_SETFD, ret); /* async-signal-safe */
2628 if (ret == -1) {
2629 ERRMSG("fcntl(F_SETFD)");
2630 goto fail;
2631 }
2632 }
2633 #endif
2634 pairs[i].oldfd = -1;
2635 continue;
2636 }
2637 if (extra_fd == -1) {
2638 extra_fd = redirect_dup(pairs[i].oldfd); /* async-signal-safe */
2639 if (extra_fd == -1) {
2640 ERRMSG("dup");
2641 goto fail;
2642 }
2643 rb_update_max_fd(extra_fd);
2644 }
2645 else {
2646 ret = redirect_dup2(pairs[i].oldfd, extra_fd); /* async-signal-safe */
2647 if (ret == -1) {
2648 ERRMSG("dup2");
2649 goto fail;
2650 }
2651 rb_update_max_fd(extra_fd);
2652 }
2653 pairs[i].oldfd = extra_fd;
2654 j = pairs[i].older_index;
2655 pairs[i].older_index = -1;
2656 while (j != -1) {
2657 ret = redirect_dup2(pairs[j].oldfd, pairs[j].newfd); /* async-signal-safe */
2658 if (ret == -1) {
2659 ERRMSG("dup2");
2660 goto fail;
2661 }
2662 rb_update_max_fd(ret);
2663 pairs[j].oldfd = -1;
2664 j = pairs[j].older_index;
2665 }
2666 }
2667 if (extra_fd != -1) {
2668 ret = redirect_close(extra_fd); /* async-signal-safe */
2669 if (ret == -1) {
2670 ERRMSG("close");
2671 goto fail;
2672 }
2673 }
2674
2675 return 0;
2676
2677 fail:
2678 return -1;
2679 }
2680
2681 /* This function should be async-signal-safe. Actually it is. */
2682 static int
2683 run_exec_close(VALUE ary, char *errmsg, size_t errmsg_buflen)
2684 {
2685 long i;
2686 int ret;
2687
2688 for (i = 0; i < RARRAY_LEN(ary); i++) {
2689 VALUE elt = RARRAY_PTR(ary)[i];
2690 int fd = FIX2INT(RARRAY_PTR(elt)[0]);
2691 ret = redirect_close(fd); /* async-signal-safe */
2692 if (ret == -1) {
2693 ERRMSG("close");
2694 return -1;
2695 }
2696 }
2697 return 0;
2698 }
2699
2700 /* This function should be async-signal-safe when sargp is NULL. Actually it is. */
2701 static int
2702 run_exec_open(VALUE ary, struct rb_execarg *sargp, char *errmsg, size_t errmsg_buflen)
2703 {
2704 long i;
2705 int ret;
2706
2707 for (i = 0; i < RARRAY_LEN(ary);) {
2708 VALUE elt = RARRAY_PTR(ary)[i];
2709 int fd = FIX2INT(RARRAY_PTR(elt)[0]);
2710 VALUE param = RARRAY_PTR(elt)[1];
2711 char *path = RSTRING_PTR(RARRAY_PTR(param)[0]);
2712 int flags = NUM2INT(RARRAY_PTR(param)[1]);
2713 int perm = NUM2INT(RARRAY_PTR(param)[2]);
2714 int need_close = 1;
2715 int fd2 = redirect_open(path, flags, perm); /* async-signal-safe */
2716 if (fd2 == -1) {
2717 ERRMSG("open");
2718 return -1;
2719 }
2720 rb_update_max_fd(fd2);
2721 while (i < RARRAY_LEN(ary) &&
2722 (elt = RARRAY_PTR(ary)[i], RARRAY_PTR(elt)[1] == param)) {
2723 fd = FIX2INT(RARRAY_PTR(elt)[0]);
2724 if (fd == fd2) {
2725 need_close = 0;
2726 }
2727 else {
2728 if (save_redirect_fd(fd, sargp, errmsg, errmsg_buflen) < 0) /* async-signal-safe */
2729 return -1;
2730 ret = redirect_dup2(fd2, fd); /* async-signal-safe */
2731 if (ret == -1) {
2732 ERRMSG("dup2");
2733 return -1;
2734 }
2735 rb_update_max_fd(fd);
2736 }
2737 i++;
2738 }
2739 if (need_close) {
2740 ret = redirect_close(fd2); /* async-signal-safe */
2741 if (ret == -1) {
2742 ERRMSG("close");
2743 return -1;
2744 }
2745 }
2746 }
2747 return 0;
2748 }
2749
2750 /* This function should be async-signal-safe when sargp is NULL. Actually it is. */
2751 static int
2752 run_exec_dup2_child(VALUE ary, struct rb_execarg *sargp, char *errmsg, size_t errmsg_buflen)
2753 {
2754 long i;
2755 int ret;
2756
2757 for (i = 0; i < RARRAY_LEN(ary); i++) {
2758 VALUE elt = RARRAY_PTR(ary)[i];
2759 int newfd = FIX2INT(RARRAY_PTR(elt)[0]);
2760 int oldfd = FIX2INT(RARRAY_PTR(elt)[1]);
2761
2762 if (save_redirect_fd(newfd, sargp, errmsg, errmsg_buflen) < 0) /* async-signal-safe */
2763 return -1;
2764 ret = redirect_dup2(oldfd, newfd); /* async-signal-safe */
2765 if (ret == -1) {
2766 ERRMSG("dup2");
2767 return -1;
2768 }
2769 rb_update_max_fd(newfd);
2770 }
2771 return 0;
2772 }
2773
2774 #ifdef HAVE_SETPGID
2775 /* This function should be async-signal-safe when sargp is NULL. Actually it is. */
2776 static int
2777 run_exec_pgroup(const struct rb_execarg *eargp, struct rb_execarg *sargp, char *errmsg, size_t errmsg_buflen)
2778 {
2779 /*
2780 * If FD_CLOEXEC is available, rb_fork waits the child's execve.
2781 * So setpgid is done in the child when rb_fork is returned in the parent.
2782 * No race condition, even without setpgid from the parent.
2783 * (Is there an environment which has setpgid but no FD_CLOEXEC?)
2784 */
2785 int ret;
2786 pid_t pgroup;
2787
2788 pgroup = eargp->pgroup_pgid;
2789 if (pgroup == -1)
2790 return 0;
2791
2792 if (sargp) {
2793 /* maybe meaningless with no fork environment... */
2794 sargp->pgroup_given = 1;
2795 sargp->pgroup_pgid = getpgrp();
2796 }
2797
2798 if (pgroup == 0) {
2799 pgroup = getpid(); /* async-signal-safe */
2800 }
2801 ret = setpgid(getpid(), pgroup); /* async-signal-safe */
2802 if (ret == -1) ERRMSG("setpgid");
2803 return ret;
2804 }
2805 #endif
2806
2807 #if defined(HAVE_SETRLIMIT) && defined(RLIM2NUM)
2808 /* This function should be async-signal-safe when sargp is NULL. Hopefully it is. */
2809 static int
2810 run_exec_rlimit(VALUE ary, struct rb_execarg *sargp, char *errmsg, size_t errmsg_buflen)
2811 {
2812 long i;
2813 for (i = 0; i < RARRAY_LEN(ary); i++) {
2814 VALUE elt = RARRAY_PTR(ary)[i];
2815 int rtype = NUM2INT(RARRAY_PTR(elt)[0]);
2816 struct rlimit rlim;
2817 if (sargp) {
2818 VALUE tmp, newary;
2819 if (getrlimit(rtype, &rlim) == -1) {
2820 ERRMSG("getrlimit");
2821 return -1;
2822 }
2823 tmp = hide_obj(rb_ary_new3(3, RARRAY_PTR(elt)[0],
2824 RLIM2NUM(rlim.rlim_cur),
2825 RLIM2NUM(rlim.rlim_max)));
2826 if (sargp->rlimit_limits == Qfalse)
2827 newary = sargp->rlimit_limits = hide_obj(rb_ary_new());
2828 else
2829 newary = sargp->rlimit_limits;
2830 rb_ary_push(newary, tmp);
2831 }
2832 rlim.rlim_cur = NUM2RLIM(RARRAY_PTR(elt)[1]);
2833 rlim.rlim_max = NUM2RLIM(RARRAY_PTR(elt)[2]);
2834 if (setrlimit(rtype, &rlim) == -1) { /* hopefully async-signal-safe */
2835 ERRMSG("setrlimit");
2836 return -1;
2837 }
2838 }
2839 return 0;
2840 }
2841 #endif
2842
2843 #if !defined(HAVE_FORK)
2844 static VALUE
2845 save_env_i(VALUE i, VALUE ary, int argc, VALUE *argv)
2846 {
2847 rb_ary_push(ary, hide_obj(rb_ary_dup(argv[0])));
2848 return Qnil;
2849 }
2850
2851 static void
2852 save_env(struct rb_execarg *sargp)
2853 {
2854 if (!sargp)
2855 return;
2856 if (sargp->env_modification == Qfalse) {
2857 VALUE env = rb_const_get(rb_cObject, rb_intern("ENV"));
2858 if (RTEST(env)) {
2859 VALUE ary = hide_obj(rb_ary_new());
2860 rb_block_call(env, idEach, 0, 0, save_env_i,
2861 (VALUE)ary);
2862 sargp->env_modification = ary;
2863 }
2864 sargp->unsetenv_others_given = 1;
2865 sargp->unsetenv_others_do = 1;
2866 }
2867 }
2868 #endif
2869
2870 /* This function should be async-signal-safe when sargp is NULL. Hopefully it is. */
2871 int
2872 rb_execarg_run_options(const struct rb_execarg *eargp, struct rb_execarg *sargp, char *errmsg, size_t errmsg_buflen)
2873 {
2874 VALUE obj;
2875
2876 if (sargp) {
2877 /* assume that sargp is always NULL on fork-able environments */
2878 MEMZERO(sargp, struct rb_execarg, 1);
2879 sargp->redirect_fds = Qnil;
2880 }
2881
2882 #ifdef HAVE_SETPGID
2883 if (eargp->pgroup_given) {
2884 if (run_exec_pgroup(eargp, sargp, errmsg, errmsg_buflen) == -1) /* async-signal-safe */
2885 return -1;
2886 }
2887 #endif
2888
2889 #if defined(HAVE_SETRLIMIT) && defined(RLIM2NUM)
2890 obj = eargp->rlimit_limits;
2891 if (obj != Qfalse) {
2892 if (run_exec_rlimit(obj, sargp, errmsg, errmsg_buflen) == -1) /* hopefully async-signal-safe */
2893 return -1;
2894 }
2895 #endif
2896
2897 #if !defined(HAVE_FORK)
2898 if (eargp->unsetenv_others_given && eargp->unsetenv_others_do) {
2899 save_env(sargp);
2900 rb_env_clear();
2901 }
2902
2903 obj = eargp->env_modification;
2904 if (obj != Qfalse) {
2905 long i;
2906 save_env(sargp);
2907 for (i = 0; i < RARRAY_LEN(obj); i++) {
2908 VALUE pair = RARRAY_PTR(obj)[i];
2909 VALUE key = RARRAY_PTR(pair)[0];
2910 VALUE val = RARRAY_PTR(pair)[1];
2911 if (NIL_P(val))
2912 ruby_setenv(StringValueCStr(key), 0);
2913 else
2914 ruby_setenv(StringValueCStr(key), StringValueCStr(val));
2915 }
2916 }
2917 #endif
2918
2919 if (eargp->umask_given) {
2920 mode_t mask = eargp->umask_mask;
2921 mode_t oldmask = umask(mask); /* never fail */ /* async-signal-safe */
2922 if (sargp) {
2923 sargp->umask_given = 1;
2924 sargp->umask_mask = oldmask;
2925 }
2926 }
2927
2928 obj = eargp->fd_dup2;
2929 if (obj != Qfalse) {
2930 if (run_exec_dup2(obj, eargp->dup2_tmpbuf, sargp, errmsg, errmsg_buflen) == -1) /* hopefully async-signal-safe */
2931 return -1;
2932 }
2933
2934 obj = eargp->fd_close;
2935 if (obj != Qfalse) {
2936 if (sargp)
2937 rb_warn("cannot close fd before spawn");
2938 else {
2939 if (run_exec_close(obj, errmsg, errmsg_buflen) == -1) /* async-signal-safe */
2940 return -1;
2941 }
2942 }
2943
2944 #ifdef HAVE_FORK
2945 if (!eargp->close_others_given || eargp->close_others_do) {
2946 rb_close_before_exec(3, eargp->close_others_maxhint, eargp->redirect_fds); /* async-signal-safe */
2947 }
2948 #endif
2949
2950 obj = eargp->fd_open;
2951 if (obj != Qfalse) {
2952 if (run_exec_open(obj, sargp, errmsg, errmsg_buflen) == -1) /* async-signal-safe */
2953 return -1;
2954 }
2955
2956 obj = eargp->fd_dup2_child;
2957 if (obj != Qfalse) {
2958 if (run_exec_dup2_child(obj, sargp, errmsg, errmsg_buflen) == -1) /* async-signal-safe */
2959 return -1;
2960 }
2961
2962 if (eargp->chdir_given) {
2963 if (sargp) {
2964 char *cwd = my_getcwd();
2965 sargp->chdir_given = 1;
2966 sargp->chdir_dir = hide_obj(rb_str_new2(cwd));
2967 xfree(cwd);
2968 }
2969 if (chdir(RSTRING_PTR(eargp->chdir_dir)) == -1) { /* async-signal-safe */
2970 ERRMSG("chdir");
2971 return -1;
2972 }
2973 }
2974
2975 #ifdef HAVE_SETGID
2976 if (eargp->gid_given) {
2977 if (setgid(eargp->gid) < 0) {
2978 ERRMSG("setgid");
2979 return -1;
2980 }
2981 }
2982 #endif
2983 #ifdef HAVE_SETUID
2984 if (eargp->uid_given) {
2985 if (setuid(eargp->uid) < 0) {
2986 ERRMSG("setuid");
2987 return -1;
2988 }
2989 }
2990 #endif
2991
2992 if (sargp) {
2993 VALUE ary = sargp->fd_dup2;
2994 if (ary != Qfalse) {
2995 size_t len = run_exec_dup2_tmpbuf_size(RARRAY_LEN(ary));
2996 VALUE tmpbuf = hide_obj(rb_str_new(0, len));
2997 rb_str_set_len(tmpbuf, len);
2998 sargp->dup2_tmpbuf = tmpbuf;
2999 }
3000 }
3001
3002 return 0;
3003 }
3004
3005 int
3006 rb_run_exec_options_err(const struct rb_exec_arg *e, struct rb_exec_arg *s, char *errmsg, size_t errmsg_buflen)
3007 {
3008 return rb_execarg_run_options(rb_execarg_get(e->execarg_obj), rb_execarg_get(s->execarg_obj), errmsg, errmsg_buflen);
3009 }
3010
3011 int
3012 rb_run_exec_options(const struct rb_exec_arg *e, struct rb_exec_arg *s)
3013 {
3014 return rb_execarg_run_options(rb_execarg_get(e->execarg_obj), rb_execarg_get(s->execarg_obj), NULL, 0);
3015 }
3016
3017 /* This function should be async-signal-safe. Hopefully it is. */
3018 int
3019 rb_exec_async_signal_safe(const struct rb_execarg *eargp, char *errmsg, size_t errmsg_buflen)
3020 {
3021 #if !defined(HAVE_FORK)
3022 struct rb_execarg sarg, *const sargp = &sarg;
3023 #else
3024 struct rb_execarg *const sargp = NULL;
3025 #endif
3026
3027 before_exec_async_signal_safe(); /* async-signal-safe */
3028
3029 if (rb_execarg_run_options(eargp, sargp, errmsg, errmsg_buflen) < 0) { /* hopefully async-signal-safe */
3030 goto failure;
3031 }
3032
3033 if (eargp->use_shell) {
3034 proc_exec_sh(RSTRING_PTR(eargp->invoke.sh.shell_script), eargp->envp_str); /* async-signal-safe */
3035 }
3036 else {
3037 char *abspath = NULL;
3038 if (!NIL_P(eargp->invoke.cmd.command_abspath))
3039 abspath = RSTRING_PTR(eargp->invoke.cmd.command_abspath);
3040 proc_exec_cmd(abspath, eargp->invoke.cmd.argv_str, eargp->envp_str); /* async-signal-safe */
3041 }
3042 #if !defined(HAVE_FORK)
3043 preserving_errno(rb_execarg_run_options(sargp, NULL, errmsg, errmsg_buflen));
3044 #endif
3045
3046 failure:
3047 preserving_errno(after_exec_async_signal_safe()); /* async-signal-safe */
3048 return -1;
3049 }
3050
3051 static int
3052 rb_exec_without_timer_thread(const struct rb_execarg *eargp, char *errmsg, size_t errmsg_buflen)
3053 {
3054 int ret;
3055 before_exec_non_async_signal_safe(); /* async-signal-safe if forked_child is true */
3056 ret = rb_exec_async_signal_safe(eargp, errmsg, errmsg_buflen); /* hopefully async-signal-safe */
3057 preserving_errno(after_exec_non_async_signal_safe()); /* not async-signal-safe because it calls rb_thread_start_timer_thread. */
3058 return ret;
3059 }
3060
3061 int
3062 rb_exec_err(const struct rb_exec_arg *e, char *errmsg, size_t errmsg_buflen)
3063 {
3064 return rb_exec_without_timer_thread(rb_execarg_get(e->execarg_obj), errmsg, errmsg_buflen);
3065 }
3066
3067 int
3068 rb_exec(const struct rb_exec_arg *e)
3069 {
3070 #if !defined FD_CLOEXEC && !defined HAVE_SPAWNV
3071 char errmsg[80] = { '\0' };
3072 int ret = rb_exec_without_timer_thread(rb_execarg_get(e->execarg_obj), errmsg, sizeof(errmsg));
3073 preserving_errno(
3074 if (errmsg[0]) {
3075 fprintf(stderr, "%s\n", errmsg);
3076 }
3077 else {
3078 fprintf(stderr, "%s:%d: command not found: %s\n",
3079 rb_sourcefile(), rb_sourceline(),
3080 RSTRING_PTR(e->use_shell ? e->invoke.sh.shell_script : e->invoke.cmd.command_name));
3081 }
3082 );
3083 return ret;
3084 #else
3085 return rb_exec_without_timer_thread(rb_execarg_get(e->execarg_obj), NULL, 0);
3086 #endif
3087 }
3088
3089 #ifdef HAVE_FORK
3090 /* This function should be async-signal-safe. Hopefully it is. */
3091 static int
3092 rb_exec_atfork(void* arg, char *errmsg, size_t errmsg_buflen)
3093 {
3094 return rb_exec_async_signal_safe(arg, errmsg, errmsg_buflen); /* hopefully async-signal-safe */
3095 }
3096 #endif
3097
3098 #ifdef HAVE_FORK
3099 #if SIZEOF_INT == SIZEOF_LONG
3100 #define proc_syswait (VALUE (*)(VALUE))rb_syswait
3101 #else
3102 static VALUE
3103 proc_syswait(VALUE pid)
3104 {
3105 rb_syswait((int)pid);
3106 return Qnil;
3107 }
3108 #endif
3109
3110 static int
3111 move_fds_to_avoid_crash(int *fdp, int n, VALUE fds)
3112 {
3113 int min = 0;
3114 int i;
3115 for (i = 0; i < n; i++) {
3116 int ret;
3117 while (RTEST(rb_hash_lookup(fds, INT2FIX(fdp[i])))) {
3118 if (min <= fdp[i])
3119 min = fdp[i]+1;
3120 while (RTEST(rb_hash_lookup(fds, INT2FIX(min))))
3121 min++;
3122 ret = rb_cloexec_fcntl_dupfd(fdp[i], min);
3123 if (ret == -1)
3124 return -1;
3125 rb_update_max_fd(ret);
3126 close(fdp[i]);
3127 fdp[i] = ret;
3128 }
3129 }
3130 return 0;
3131 }
3132
3133 static int
3134 pipe_nocrash(int filedes[2], VALUE fds)
3135 {
3136 int ret;
3137 ret = rb_pipe(filedes);
3138 if (ret == -1)
3139 return -1;
3140 if (RTEST(fds)) {
3141 int save = errno;
3142 if (move_fds_to_avoid_crash(filedes, 2, fds) == -1) {
3143 close(filedes[0]);
3144 close(filedes[1]);
3145 return -1;
3146 }
3147 errno = save;
3148 }
3149 return ret;
3150 }
3151
3152 struct chfunc_protect_t {
3153 int (*chfunc)(void*, char *, size_t);
3154 void *arg;
3155 char *errmsg;
3156 size_t buflen;
3157 };
3158
3159 static VALUE
3160 chfunc_protect(VALUE arg)
3161 {
3162 struct chfunc_protect_t *p = (struct chfunc_protect_t *)arg;
3163
3164 return (VALUE)(*p->chfunc)(p->arg, p->errmsg, p->buflen);
3165 }
3166
3167 #ifndef O_BINARY
3168 #define O_BINARY 0
3169 #endif
3170
3171 /*
3172 * Forks child process, and returns the process ID in the parent
3173 * process.
3174 *
3175 * If +status+ is given, protects from any exceptions and sets the
3176 * jump status to it, and returns -1. If failed to fork new process
3177 * but no exceptions occurred, sets 0 to it. Otherwise, if forked
3178 * successfully, the value of +status+ is undetermined.
3179 *
3180 * In the child process, just returns 0 if +chfunc+ is +NULL+.
3181 * Otherwise +chfunc+ will be called with +charg+, and then the child
3182 * process exits with +EXIT_SUCCESS+ when it returned zero.
3183 *
3184 * In the case of the function is called and returns non-zero value,
3185 * the child process exits with non-+EXIT_SUCCESS+ value (normally
3186 * 127). And, on the platforms where +FD_CLOEXEC+ is available,
3187 * +errno+ is propagated to the parent process, and this function
3188 * returns -1 in the parent process. On the other platforms, just
3189 * returns pid.
3190 *
3191 * If fds is not Qnil, internal pipe for the errno propagation is
3192 * arranged to avoid conflicts of the hash keys in +fds+.
3193 *
3194 * +chfunc+ must not raise any exceptions.
3195 */
3196
3197 static rb_pid_t
3198 retry_fork(int *status, int *ep, int chfunc_is_async_signal_safe)
3199 {
3200 rb_pid_t pid;
3201 int state = 0;
3202
3203 #define prefork() ( \
3204 rb_io_flush(rb_stdout), \
3205 rb_io_flush(rb_stderr) \
3206 )
3207
3208 while (1) {
3209 prefork();
3210 if (!chfunc_is_async_signal_safe)
3211 before_fork();
3212 pid = fork();
3213 if (pid == 0) /* fork succeed, child process */
3214 return pid;
3215 if (!chfunc_is_async_signal_safe)
3216 preserving_errno(after_fork());
3217 if (0 < pid) /* fork succeed, parent process */
3218 return pid;
3219 /* fork failed */
3220 switch (errno) {
3221 case EAGAIN:
3222 #if defined(EWOULDBLOCK) && EWOULDBLOCK != EAGAIN
3223 case EWOULDBLOCK:
3224 #endif
3225 if (!status && !ep) {
3226 rb_thread_sleep(1);
3227 continue;
3228 }
3229 else {
3230 rb_protect((VALUE (*)())rb_thread_sleep, 1, &state);
3231 if (status) *status = state;
3232 if (!state) continue;
3233 }
3234 /* fall through */
3235 default:
3236 if (ep) {
3237 preserving_errno((close(ep[0]), close(ep[1])));
3238 }
3239 if (state && !status) rb_jump_tag(state);
3240 return -1;
3241 }
3242 }
3243 }
3244
3245 static void
3246 send_child_error(int fd, int state, char *errmsg, size_t errmsg_buflen, int chfunc_is_async_signal_safe)
3247 {
3248 VALUE io = Qnil;
3249 int err;
3250
3251 if (!chfunc_is_async_signal_safe) {
3252 if (write(fd, &state, sizeof(state)) == sizeof(state) && state) {
3253 VALUE errinfo = rb_errinfo();
3254 io = rb_io_fdopen(fd, O_WRONLY|O_BINARY, NULL);
3255 rb_marshal_dump(errinfo, io);
3256 rb_io_flush(io);
3257 }
3258 }
3259 err = errno;
3260 if (write(fd, &err, sizeof(err)) < 0) err = errno;
3261 if (errmsg && 0 < errmsg_buflen) {
3262 errmsg[errmsg_buflen-1] = '\0';
3263 errmsg_buflen = strlen(errmsg);
3264 if (errmsg_buflen > 0 && write(fd, errmsg, errmsg_buflen) < 0)
3265 err = errno;
3266 }
3267 if (!NIL_P(io)) rb_io_close(io);
3268 }
3269
3270 static int
3271 recv_child_error(int fd, int *statep, VALUE *excp, int *errp, char *errmsg, size_t errmsg_buflen, int chfunc_is_async_signal_safe)
3272 {
3273 int err, state = 0;
3274 VALUE io = Qnil;
3275 ssize_t size;
3276 VALUE exc = Qnil;
3277 if (!chfunc_is_async_signal_safe) {
3278 if ((read(fd, &state, sizeof(state))) == sizeof(state) && state) {
3279 io = rb_io_fdopen(fd, O_RDONLY|O_BINARY, NULL);
3280 exc = rb_marshal_load(io);
3281 rb_set_errinfo(exc);
3282 }
3283 if (!*statep && state) *statep = state;
3284 *excp = exc;
3285 }
3286 #define READ_FROM_CHILD(ptr, len) \
3287 (NIL_P(io) ? read(fd, (ptr), (len)) : rb_io_bufread(io, (ptr), (len)))
3288 if ((size = READ_FROM_CHILD(&err, sizeof(err))) < 0) {
3289 err = errno;
3290 }
3291 *errp = err;
3292 if (size == sizeof(err) &&
3293 errmsg && 0 < errmsg_buflen) {
3294 ssize_t ret = READ_FROM_CHILD(errmsg, errmsg_buflen-1);
3295 if (0 <= ret) {
3296 errmsg[ret] = '\0';
3297 }
3298 }
3299 if (NIL_P(io))
3300 close(fd);
3301 else
3302 rb_io_close(io);
3303 return size != 0;
3304 }
3305
3306 static rb_pid_t
3307 rb_fork_internal(int *status, int (*chfunc)(void*, char *, size_t), void *charg,
3308 int chfunc_is_async_signal_safe, VALUE fds,
3309 char *errmsg, size_t errmsg_buflen)
3310 {
3311 rb_pid_t pid;
3312 int err, state = 0;
3313 int ep[2];
3314 VALUE exc = Qnil;
3315 int error_occured;
3316
3317 if (status) *status = 0;
3318
3319 if (!chfunc) {
3320 pid = retry_fork(status, NULL, FALSE);
3321 if (pid < 0)
3322 return pid;
3323 if (!pid) {
3324 forked_child = 1;
3325 after_fork();
3326 }
3327 return pid;
3328 }
3329 else {
3330 if (pipe_nocrash(ep, fds)) return -1;
3331 if (fcntl(ep[1], F_SETFD, FD_CLOEXEC)) {
3332 preserving_errno((close(ep[0]), close(ep[1])));
3333 return -1;
3334 }
3335 pid = retry_fork(status, ep, chfunc_is_async_signal_safe);
3336 if (pid < 0)
3337 return pid;
3338 if (!pid) {
3339 int ret;
3340 forked_child = 1;
3341 close(ep[0]);
3342 if (chfunc_is_async_signal_safe)
3343 ret = chfunc(charg, errmsg, errmsg_buflen);
3344 else {
3345 struct chfunc_protect_t arg;
3346 arg.chfunc = chfunc;
3347 arg.arg = charg;
3348 arg.errmsg = errmsg;
3349 arg.buflen = errmsg_buflen;
3350 ret = (int)rb_protect(chfunc_protect, (VALUE)&arg, &state);
3351 }
3352 if (!ret) _exit(EXIT_SUCCESS);
3353 send_child_error(ep[1], state, errmsg, errmsg_buflen, chfunc_is_async_signal_safe);
3354 #if EXIT_SUCCESS == 127
3355 _exit(EXIT_FAILURE);
3356 #else
3357 _exit(127);
3358 #endif
3359 }
3360 close(ep[1]);
3361 error_occured = recv_child_error(ep[0], &state, &exc, &err, errmsg, errmsg_buflen, chfunc_is_async_signal_safe);
3362 if (state || error_occured) {
3363 if (status) {
3364 rb_protect(proc_syswait, (VALUE)pid, status);
3365 if (state) *status = state;
3366 }
3367 else {
3368 rb_syswait(pid);
3369 if (state) rb_exc_raise(exc);
3370 }
3371 errno = err;
3372 return -1;
3373 }
3374 return pid;
3375 }
3376 }
3377
3378 rb_pid_t
3379 rb_fork_err(int *status, int (*chfunc)(void*, char *, size_t), void *charg, VALUE fds,
3380 char *errmsg, size_t errmsg_buflen)
3381 {
3382 return rb_fork_internal(status, chfunc, charg, FALSE, fds, errmsg, errmsg_buflen);
3383 }
3384
3385 rb_pid_t
3386 rb_fork_async_signal_safe(int *status, int (*chfunc)(void*, char *, size_t), void *charg, VALUE fds,
3387 char *errmsg, size_t errmsg_buflen)
3388 {
3389 return rb_fork_internal(status, chfunc, charg, TRUE, fds, errmsg, errmsg_buflen);
3390 }
3391
3392 struct chfunc_wrapper_t {
3393 int (*chfunc)(void*);
3394 void *arg;
3395 };
3396
3397 static int
3398 chfunc_wrapper(void *arg_, char *errmsg, size_t errmsg_buflen)
3399 {
3400 struct chfunc_wrapper_t *arg = arg_;
3401 return arg->chfunc(arg->arg);
3402 }
3403
3404 rb_pid_t
3405 rb_fork(int *status, int (*chfunc)(void*), void *charg, VALUE fds)
3406 {
3407 if (chfunc) {
3408 struct chfunc_wrapper_t warg;
3409 warg.chfunc = chfunc;
3410 warg.arg = charg;
3411 return rb_fork_internal(status, chfunc_wrapper, &warg, FALSE, fds, NULL, 0);
3412 }
3413 else {
3414 return rb_fork_internal(status, NULL, NULL, FALSE, fds, NULL, 0);
3415 }
3416
3417 }
3418
3419 rb_pid_t
3420 rb_fork_ruby(int *status)
3421 {
3422 return rb_fork_internal(status, NULL, NULL, FALSE, Qnil, NULL, 0);
3423 }
3424
3425 #endif
3426
3427 #if defined(HAVE_FORK) && !defined(CANNOT_FORK_WITH_PTHREAD)
3428 /*
3429 * call-seq:
3430 * Kernel.fork [{ block }] -> fixnum or nil
3431 * Process.fork [{ block }] -> fixnum or nil
3432 *
3433 * Creates a subprocess. If a block is specified, that block is run
3434 * in the subprocess, and the subprocess terminates with a status of
3435 * zero. Otherwise, the +fork+ call returns twice, once in
3436 * the parent, returning the process ID of the child, and once in
3437 * the child, returning _nil_. The child process can exit using
3438 * <code>Kernel.exit!</code> to avoid running any
3439 * <code>at_exit</code> functions. The parent process should
3440 * use <code>Process.wait</code> to collect the termination statuses
3441 * of its children or use <code>Process.detach</code> to register
3442 * disinterest in their status; otherwise, the operating system
3443 * may accumulate zombie processes.
3444 *
3445 * The thread calling fork is the only thread in the created child process.
3446 * fork doesn't copy other threads.
3447 *
3448 * If fork is not usable, Process.respond_to?(:fork) returns false.
3449 */
3450
3451 static VALUE
3452 rb_f_fork(VALUE obj)
3453 {
3454 rb_pid_t pid;
3455
3456 rb_secure(2);
3457
3458 switch (pid = rb_fork_ruby(NULL)) {
3459 case 0:
3460 rb_thread_atfork();
3461 if (rb_block_given_p()) {
3462 int status;
3463
3464 rb_protect(rb_yield, Qundef, &status);
3465 ruby_stop(status);
3466 }
3467 return Qnil;
3468
3469 case -1:
3470 rb_sys_fail("fork(2)");
3471 return Qnil;
3472
3473 default:
3474 return PIDT2NUM(pid);
3475 }
3476 }
3477 #else
3478 #define rb_f_fork rb_f_notimplement
3479 #endif
3480
3481 static int
3482 exit_status_code(VALUE status)
3483 {
3484 int istatus;
3485
3486 switch (status) {
3487 case Qtrue:
3488 istatus = EXIT_SUCCESS;
3489 break;
3490 case Qfalse:
3491 istatus = EXIT_FAILURE;
3492 break;
3493 default:
3494 istatus = NUM2INT(status);
3495 #if EXIT_SUCCESS != 0
3496 if (istatus == 0)
3497 istatus = EXIT_SUCCESS;
3498 #endif
3499 break;
3500 }
3501 return istatus;
3502 }
3503
3504 /*
3505 * call-seq:
3506 * Process.exit!(status=false)
3507 *
3508 * Exits the process immediately. No exit handlers are
3509 * run. <em>status</em> is returned to the underlying system as the
3510 * exit status.
3511 *
3512 * Process.exit!(true)
3513 */
3514
3515 static VALUE
3516 rb_f_exit_bang(int argc, VALUE *argv, VALUE obj)
3517 {
3518 VALUE status;
3519 int istatus;
3520
3521 rb_secure(4);
3522 if (argc > 0 && rb_scan_args(argc, argv, "01", &status) == 1) {
3523 istatus = exit_status_code(status);
3524 }
3525 else {
3526 istatus = EXIT_FAILURE;
3527 }
3528 _exit(istatus);
3529
3530 UNREACHABLE;
3531 }
3532
3533 void
3534 rb_exit(int status)
3535 {
3536 if (GET_THREAD()->tag) {
3537 VALUE args[2];
3538
3539 args[0] = INT2NUM(status);
3540 args[1] = rb_str_new2("exit");
3541 rb_exc_raise(rb_class_new_instance(2, args, rb_eSystemExit));
3542 }
3543 ruby_finalize();
3544 exit(status);
3545 }
3546
3547
3548 /*
3549 * call-seq:
3550 * exit(status=true)
3551 * Kernel::exit(status=true)
3552 * Process::exit(status=true)
3553 *
3554 * Initiates the termination of the Ruby script by raising the
3555 * <code>SystemExit</code> exception. This exception may be caught. The
3556 * optional parameter is used to return a status code to the invoking
3557 * environment.
3558 * +true+ and +FALSE+ of _status_ means success and failure
3559 * respectively. The interpretation of other integer values are
3560 * system dependent.
3561 *
3562 * begin
3563 * exit
3564 * puts "never get here"
3565 * rescue SystemExit
3566 * puts "rescued a SystemExit exception"
3567 * end
3568 * puts "after begin block"
3569 *
3570 * <em>produces:</em>
3571 *
3572 * rescued a SystemExit exception
3573 * after begin block
3574 *
3575 * Just prior to termination, Ruby executes any <code>at_exit</code> functions
3576 * (see Kernel::at_exit) and runs any object finalizers (see
3577 * ObjectSpace::define_finalizer).
3578 *
3579 * at_exit { puts "at_exit function" }
3580 * ObjectSpace.define_finalizer("string", proc { puts "in finalizer" })
3581 * exit
3582 *
3583 * <em>produces:</em>
3584 *
3585 * at_exit function
3586 * in finalizer
3587 */
3588
3589 VALUE
3590 rb_f_exit(int argc, VALUE *argv)
3591 {
3592 VALUE status;
3593 int istatus;
3594
3595 rb_secure(4);
3596 if (argc > 0 && rb_scan_args(argc, argv, "01", &status) == 1) {
3597 istatus = exit_status_code(status);
3598 }
3599 else {
3600 istatus = EXIT_SUCCESS;
3601 }
3602 rb_exit(istatus);
3603
3604 UNREACHABLE;
3605 }
3606
3607
3608 /*
3609 * call-seq:
3610 * abort
3611 * Kernel::abort([msg])
3612 * Process::abort([msg])
3613 *
3614 * Terminate execution immediately, effectively by calling
3615 * <code>Kernel.exit(false)</code>. If _msg_ is given, it is written
3616 * to STDERR prior to terminating.
3617 */
3618
3619 VALUE
3620 rb_f_abort(int argc, VALUE *argv)
3621 {
3622 rb_secure(4);
3623 if (argc == 0) {
3624 if (!NIL_P(GET_THREAD()->errinfo)) {
3625 ruby_error_print();
3626 }
3627 rb_exit(EXIT_FAILURE);
3628 }
3629 else {
3630 VALUE args[2];
3631
3632 rb_scan_args(argc, argv, "1", &args[1]);
3633 StringValue(argv[0]);
3634 rb_io_puts(argc, argv, rb_stderr);
3635 args[0] = INT2NUM(EXIT_FAILURE);
3636 rb_exc_raise(rb_class_new_instance(2, args, rb_eSystemExit));
3637 }
3638
3639 UNREACHABLE;
3640 }
3641
3642 void
3643 rb_syswait(rb_pid_t pid)
3644 {
3645 int status;
3646
3647 rb_waitpid(pid, &status, 0);
3648 }
3649
3650 static rb_pid_t
3651 rb_spawn_process(struct rb_execarg *eargp, char *errmsg, size_t errmsg_buflen)
3652 {
3653 rb_pid_t pid;
3654 #if !USE_SPAWNV
3655 int status;
3656 #endif
3657 #if !defined HAVE_FORK || USE_SPAWNV
3658 VALUE prog;
3659 struct rb_execarg sarg;
3660 #endif
3661
3662 #if defined HAVE_FORK && !USE_SPAWNV
3663 pid = rb_fork_async_signal_safe(&status, rb_exec_atfork, eargp, eargp->redirect_fds, errmsg, errmsg_buflen);
3664 #else
3665 prog = eargp->use_shell ? eargp->invoke.sh.shell_script : eargp->invoke.cmd.command_name;
3666
3667 if (rb_execarg_run_options(eargp, &sarg, errmsg, errmsg_buflen) < 0) {
3668 return -1;
3669 }
3670
3671 if (prog && !eargp->use_shell) {
3672 char **argv = ARGVSTR2ARGV(eargp->invoke.cmd.argv_str);
3673 argv[0] = RSTRING_PTR(prog);
3674 }
3675 # if defined HAVE_SPAWNV
3676 if (eargp->use_shell) {
3677 pid = proc_spawn_sh(RSTRING_PTR(prog));
3678 }
3679 else {
3680 char **argv = ARGVSTR2ARGV(eargp->invoke.cmd.argv_str);
3681 pid = proc_spawn_cmd(argv, prog, eargp);
3682 }
3683 # if defined(_WIN32)
3684 if (pid == -1)
3685 rb_last_status_set(0x7f << 8, 0);
3686 # endif
3687 # else
3688 if (!eargp->use_shell) {
3689 char **argv = ARGVSTR2ARGV(eargp->invoke.cmd.argv_str);
3690 int argc = ARGVSTR2ARGC(eargp->invoke.cmd.argv_str);
3691 prog = rb_ary_join(rb_ary_new4(argc, argv), rb_str_new2(" "));
3692 }
3693 status = system(StringValuePtr(prog));
3694 rb_last_status_set((status & 0xff) << 8, 0);
3695 # endif
3696
3697 rb_execarg_run_options(&sarg, NULL, errmsg, errmsg_buflen);
3698 #endif
3699 return pid;
3700 }
3701
3702 static rb_pid_t
3703 rb_spawn_internal(int argc, VALUE *argv, char *errmsg, size_t errmsg_buflen)
3704 {
3705 VALUE execarg_obj;
3706 struct rb_execarg *eargp;
3707 rb_pid_t ret;
3708
3709 execarg_obj = rb_execarg_new(argc, argv, TRUE);
3710 eargp = rb_execarg_get(execarg_obj);
3711 rb_execarg_fixup(execarg_obj);
3712 ret = rb_spawn_process(eargp, errmsg, errmsg_buflen);
3713 RB_GC_GUARD(execarg_obj);
3714 return ret;
3715 }
3716
3717 rb_pid_t
3718 rb_spawn_err(int argc, VALUE *argv, char *errmsg, size_t errmsg_buflen)
3719 {
3720 return rb_spawn_internal(argc, argv, errmsg, errmsg_buflen);
3721 }
3722
3723 rb_pid_t
3724 rb_spawn(int argc, VALUE *argv)
3725 {
3726 return rb_spawn_internal(argc, argv, NULL, 0);
3727 }
3728
3729 /*
3730 * call-seq:
3731 * system([env,] command... [,options]) -> true, false or nil
3732 *
3733 * Executes _command..._ in a subshell.
3734 * _command..._ is one of following forms.
3735 *
3736 * commandline : command line string which is passed to the standard shell
3737 * cmdname, arg1, ... : command name and one or more arguments (no shell)
3738 * [cmdname, argv0], arg1, ... : command name, argv[0] and zero or more arguments (no shell)
3739 *
3740 * system returns +true+ if the command gives zero exit status,
3741 * +false+ for non zero exit status.
3742 * Returns +nil+ if command execution fails.
3743 * An error status is available in <code>$?</code>.
3744 * The arguments are processed in the same way as
3745 * for <code>Kernel.spawn</code>.
3746 *
3747 * The hash arguments, env and options, are same as
3748 * <code>exec</code> and <code>spawn</code>.
3749 * See <code>Kernel.spawn</code> for details.
3750 *
3751 * system("echo *")
3752 * system("echo", "*")
3753 *
3754 * <em>produces:</em>
3755 *
3756 * config.h main.rb
3757 * *
3758 *
3759 * See <code>Kernel.exec</code> for the standard shell.
3760 */
3761
3762 static VALUE
3763 rb_f_system(int argc, VALUE *argv)
3764 {
3765 rb_pid_t pid;
3766 int status;
3767
3768 #if defined(SIGCLD) && !defined(SIGCHLD)
3769 # define SIGCHLD SIGCLD
3770 #endif
3771
3772 #ifdef SIGCHLD
3773 RETSIGTYPE (*chfunc)(int);
3774
3775 rb_last_status_clear();
3776 chfunc = signal(SIGCHLD, SIG_DFL);
3777 #endif
3778 pid = rb_spawn_internal(argc, argv, NULL, 0);
3779 #if defined(HAVE_FORK) || defined(HAVE_SPAWNV)
3780 if (pid > 0) {
3781 int ret, status;
3782 ret = rb_waitpid(pid, &status, 0);
3783 if (ret == (rb_pid_t)-1)
3784 rb_sys_fail("Another thread waited the process started by system().");
3785 }
3786 #endif
3787 #ifdef SIGCHLD
3788 signal(SIGCHLD, chfunc);
3789 #endif
3790 if (pid < 0) {
3791 return Qnil;
3792 }
3793 status = PST2INT(rb_last_status_get());
3794 if (status == EXIT_SUCCESS) return Qtrue;
3795 return Qfalse;
3796 }
3797
3798 /*
3799 * call-seq:
3800 * spawn([env,] command... [,options]) -> pid
3801 * Process.spawn([env,] command... [,options]) -> pid
3802 *
3803 * spawn executes specified command and return its pid.
3804 *
3805 * This method doesn't wait for end of the command.
3806 * The parent process should
3807 * use <code>Process.wait</code> to collect
3808 * the termination status of its child or
3809 * use <code>Process.detach</code> to register
3810 * disinterest in their status;
3811 * otherwise, the operating system may accumulate zombie processes.
3812 *
3813 * spawn has bunch of options to specify process attributes:
3814 *
3815 * env: hash
3816 * name => val : set the environment variable
3817 * name => nil : unset the environment variable
3818 * command...:
3819 * commandline : command line string which is passed to the standard shell
3820 * cmdname, arg1, ... : command name and one or more arguments (no shell)
3821 * [cmdname, argv0], arg1, ... : command name, argv[0] and zero or more arguments (no shell)
3822 * options: hash
3823 * clearing environment variables:
3824 * :unsetenv_others => true : clear environment variables except specified by env
3825 * :unsetenv_others => false : don't clear (default)
3826 * process group:
3827 * :pgroup => true or 0 : make a new process group
3828 * :pgroup => pgid : join to specified process group
3829 * :pgroup => nil : don't change the process group (default)
3830 * create new process group: Windows only
3831 * :new_pgroup => true : the new process is the root process of a new process group
3832 * :new_pgroup => false : don't create a new process group (default)
3833 * resource limit: resourcename is core, cpu, data, etc. See Process.setrlimit.
3834 * :rlimit_resourcename => limit
3835 * :rlimit_resourcename => [cur_limit, max_limit]
3836 * umask:
3837 * :umask => int
3838 * redirection:
3839 * key:
3840 * FD : single file descriptor in child process
3841 * [FD, FD, ...] : multiple file descriptor in child process
3842 * value:
3843 * FD : redirect to the file descriptor in parent process
3844 * string : redirect to file with open(string, "r" or "w")
3845 * [string] : redirect to file with open(string, File::RDONLY)
3846 * [string, open_mode] : redirect to file with open(string, open_mode, 0644)
3847 * [string, open_mode, perm] : redirect to file with open(string, open_mode, perm)
3848 * [:child, FD] : redirect to the redirected file descriptor
3849 * :close : close the file descriptor in child process
3850 * FD is one of follows
3851 * :in : the file descriptor 0 which is the standard input
3852 * :out : the file descriptor 1 which is the standard output
3853 * :err : the file descriptor 2 which is the standard error
3854 * integer : the file descriptor of specified the integer
3855 * io : the file descriptor specified as io.fileno
3856 * file descriptor inheritance: close non-redirected non-standard fds (3, 4, 5, ...) or not
3857 * :close_others => true : don't inherit
3858 * current directory:
3859 * :chdir => str
3860 *
3861 * If a hash is given as +env+, the environment is
3862 * updated by +env+ before <code>exec(2)</code> in the child process.
3863 * If a pair in +env+ has nil as the value, the variable is deleted.
3864 *
3865 * # set FOO as BAR and unset BAZ.
3866 * pid = spawn({"FOO"=>"BAR", "BAZ"=>nil}, command)
3867 *
3868 * If a hash is given as +options+,
3869 * it specifies
3870 * process group,
3871 * create new process group,
3872 * resource limit,
3873 * current directory,
3874 * umask and
3875 * redirects for the child process.
3876 * Also, it can be specified to clear environment variables.
3877 *
3878 * The <code>:unsetenv_others</code> key in +options+ specifies
3879 * to clear environment variables, other than specified by +env+.
3880 *
3881 * pid = spawn(command, :unsetenv_others=>true) # no environment variable
3882 * pid = spawn({"FOO"=>"BAR"}, command, :unsetenv_others=>true) # FOO only
3883 *
3884 * The <code>:pgroup</code> key in +options+ specifies a process group.
3885 * The corresponding value should be true, zero or positive integer.
3886 * true and zero means the process should be a process leader of a new
3887 * process group.
3888 * Other values specifies a process group to be belongs.
3889 *
3890 * pid = spawn(command, :pgroup=>true) # process leader
3891 * pid = spawn(command, :pgroup=>10) # belongs to the process group 10
3892 *
3893 * The <code>:new_pgroup</code> key in +options+ specifies to pass
3894 * +CREATE_NEW_PROCESS_GROUP+ flag to <code>CreateProcessW()</code> that is
3895 * Windows API. This option is only for Windows.
3896 * true means the new process is the root process of the new process group.
3897 * The new process has CTRL+C disabled. This flag is necessary for
3898 * <code>Process.kill(:SIGINT, pid)</code> on the subprocess.
3899 * :new_pgroup is false by default.
3900 *
3901 * pid = spawn(command, :new_pgroup=>true) # new process group
3902 * pid = spawn(command, :new_pgroup=>false) # same process group
3903 *
3904 * The <code>:rlimit_</code><em>foo</em> key specifies a resource limit.
3905 * <em>foo</em> should be one of resource types such as <code>core</code>.
3906 * The corresponding value should be an integer or an array which have one or
3907 * two integers: same as cur_limit and max_limit arguments for
3908 * Process.setrlimit.
3909 *
3910 * cur, max = Process.getrlimit(:CORE)
3911 * pid = spawn(command, :rlimit_core=>[0,max]) # disable core temporary.
3912 * pid = spawn(command, :rlimit_core=>max) # enable core dump
3913 * pid = spawn(command, :rlimit_core=>0) # never dump core.
3914 *
3915 * The <code>:umask</code> key in +options+ specifies the umask.
3916 *
3917 * pid = spawn(command, :umask=>077)
3918 *
3919 * The :in, :out, :err, a fixnum, an IO and an array key specifies a redirection.
3920 * The redirection maps a file descriptor in the child process.
3921 *
3922 * For example, stderr can be merged into stdout as follows:
3923 *
3924 * pid = spawn(command, :err=>:out)
3925 * pid = spawn(command, 2=>1)
3926 * pid = spawn(command, STDERR=>:out)
3927 * pid = spawn(command, STDERR=>STDOUT)
3928 *
3929 * The hash keys specifies a file descriptor
3930 * in the child process started by <code>spawn</code>.
3931 * :err, 2 and STDERR specifies the standard error stream (stderr).
3932 *
3933 * The hash values specifies a file descriptor
3934 * in the parent process which invokes <code>spawn</code>.
3935 * :out, 1 and STDOUT specifies the standard output stream (stdout).
3936 *
3937 * In the above example,
3938 * the standard output in the child process is not specified.
3939 * So it is inherited from the parent process.
3940 *
3941 * The standard input stream (stdin) can be specified by :in, 0 and STDIN.
3942 *
3943 * A filename can be specified as a hash value.
3944 *
3945 * pid = spawn(command, :in=>"/dev/null") # read mode
3946 * pid = spawn(command, :out=>"/dev/null") # write mode
3947 * pid = spawn(command, :err=>"log") # write mode
3948 * pid = spawn(command, 3=>"/dev/null") # read mode
3949 *
3950 * For stdout and stderr,
3951 * it is opened in write mode.
3952 * Otherwise read mode is used.
3953 *
3954 * For specifying flags and permission of file creation explicitly,
3955 * an array is used instead.
3956 *
3957 * pid = spawn(command, :in=>["file"]) # read mode is assumed
3958 * pid = spawn(command, :in=>["file", "r"])
3959 * pid = spawn(command, :out=>["log", "w"]) # 0644 assumed
3960 * pid = spawn(command, :out=>["log", "w", 0600])
3961 * pid = spawn(command, :out=>["log", File::WRONLY|File::EXCL|File::CREAT, 0600])
3962 *
3963 * The array specifies a filename, flags and permission.
3964 * The flags can be a string or an integer.
3965 * If the flags is omitted or nil, File::RDONLY is assumed.
3966 * The permission should be an integer.
3967 * If the permission is omitted or nil, 0644 is assumed.
3968 *
3969 * If an array of IOs and integers are specified as a hash key,
3970 * all the elements are redirected.
3971 *
3972 * # stdout and stderr is redirected to log file.
3973 * # The file "log" is opened just once.
3974 * pid = spawn(command, [:out, :err]=>["log", "w"])
3975 *
3976 * Another way to merge multiple file descriptors is [:child, fd].
3977 * \[:child, fd] means the file descriptor in the child process.
3978 * This is different from fd.
3979 * For example, :err=>:out means redirecting child stderr to parent stdout.
3980 * But :err=>[:child, :out] means redirecting child stderr to child stdout.
3981 * They differ if stdout is redirected in the child process as follows.
3982 *
3983 * # stdout and stderr is redirected to log file.
3984 * # The file "log" is opened just once.
3985 * pid = spawn(command, :out=>["log", "w"], :err=>[:child, :out])
3986 *
3987 * \[:child, :out] can be used to merge stderr into stdout in IO.popen.
3988 * In this case, IO.popen redirects stdout to a pipe in the child process
3989 * and [:child, :out] refers the redirected stdout.
3990 *
3991 * io = IO.popen(["sh", "-c", "echo out; echo err >&2", :err=>[:child, :out]])
3992 * p io.read #=> "out\nerr\n"
3993 *
3994 * The <code>:chdir</code> key in +options+ specifies the current directory.
3995 *
3996 * pid = spawn(command, :chdir=>"/var/tmp")
3997 *
3998 * spawn closes all non-standard unspecified descriptors by default.
3999 * The "standard" descriptors are 0, 1 and 2.
4000 * This behavior is specified by :close_others option.
4001 * :close_others doesn't affect the standard descriptors which are
4002 * closed only if :close is specified explicitly.
4003 *
4004 * pid = spawn(command, :close_others=>true) # close 3,4,5,... (default)
4005 * pid = spawn(command, :close_others=>false) # don't close 3,4,5,...
4006 *
4007 * :close_others is true by default for spawn and IO.popen.
4008 *
4009 * Note that fds which close-on-exec flag is already set are closed
4010 * regardless of :close_others option.
4011 *
4012 * So IO.pipe and spawn can be used as IO.popen.
4013 *
4014 * # similar to r = IO.popen(command)
4015 * r, w = IO.pipe
4016 * pid = spawn(command, :out=>w) # r, w is closed in the child process.
4017 * w.close
4018 *
4019 * :close is specified as a hash value to close a fd individually.
4020 *
4021 * f = open(foo)
4022 * system(command, f=>:close) # don't inherit f.
4023 *
4024 * If a file descriptor need to be inherited,
4025 * io=>io can be used.
4026 *
4027 * # valgrind has --log-fd option for log destination.
4028 * # log_w=>log_w indicates log_w.fileno inherits to child process.
4029 * log_r, log_w = IO.pipe
4030 * pid = spawn("valgrind", "--log-fd=#{log_w.fileno}", "echo", "a", log_w=>log_w)
4031 * log_w.close
4032 * p log_r.read
4033 *
4034 * It is also possible to exchange file descriptors.
4035 *
4036 * pid = spawn(command, :out=>:err, :err=>:out)
4037 *
4038 * The hash keys specify file descriptors in the child process.
4039 * The hash values specifies file descriptors in the parent process.
4040 * So the above specifies exchanging stdout and stderr.
4041 * Internally, +spawn+ uses an extra file descriptor to resolve such cyclic
4042 * file descriptor mapping.
4043 *
4044 * See <code>Kernel.exec</code> for the standard shell.
4045 */
4046
4047 static VALUE
4048 rb_f_spawn(int argc, VALUE *argv)
4049 {
4050 rb_pid_t pid;
4051 char errmsg[CHILD_ERRMSG_BUFLEN] = { '\0' };
4052 VALUE execarg_obj, fail_str;
4053 struct rb_execarg *eargp;
4054
4055 execarg_obj = rb_execarg_new(argc, argv, TRUE);
4056 eargp = rb_execarg_get(execarg_obj);
4057 rb_execarg_fixup(execarg_obj);
4058 fail_str = eargp->use_shell ? eargp->invoke.sh.shell_script : eargp->invoke.cmd.command_name;
4059
4060 pid = rb_spawn_process(eargp, errmsg, sizeof(errmsg));
4061 RB_GC_GUARD(execarg_obj);
4062
4063 if (pid == -1) {
4064 const char *prog = errmsg;
4065 if (!prog[0]) {
4066 rb_sys_fail_str(fail_str);
4067 }
4068 rb_sys_fail(prog);
4069 }
4070 #if defined(HAVE_FORK) || defined(HAVE_SPAWNV)
4071 return PIDT2NUM(pid);
4072 #else
4073 return Qnil;
4074 #endif
4075 }
4076
4077 /*
4078 * call-seq:
4079 * sleep([duration]) -> fixnum
4080 *
4081 * Suspends the current thread for _duration_ seconds (which may be any number,
4082 * including a +Float+ with fractional seconds). Returns the actual number of
4083 * seconds slept (rounded), which may be less than that asked for if another
4084 * thread calls <code>Thread#run</code>. Called without an argument, sleep()
4085 * will sleep forever.
4086 *
4087 * Time.new #=> 2008-03-08 19:56:19 +0900
4088 * sleep 1.2 #=> 1
4089 * Time.new #=> 2008-03-08 19:56:20 +0900
4090 * sleep 1.9 #=> 2
4091 * Time.new #=> 2008-03-08 19:56:22 +0900
4092 */
4093
4094 static VALUE
4095 rb_f_sleep(int argc, VALUE *argv)
4096 {
4097 time_t beg, end;
4098
4099 beg = time(0);
4100 if (argc == 0) {
4101 rb_thread_sleep_forever();
4102 }
4103 else {
4104 rb_check_arity(argc, 0, 1);
4105 rb_thread_wait_for(rb_time_interval(argv[0]));
4106 }
4107
4108 end = time(0) - beg;
4109
4110 return INT2FIX(end);
4111 }
4112
4113
4114 #if (defined(HAVE_GETPGRP) && defined(GETPGRP_VOID)) || defined(HAVE_GETPGID)
4115 /*
4116 * call-seq:
4117 * Process.getpgrp -> integer
4118 *
4119 * Returns the process group ID for this process. Not available on
4120 * all platforms.
4121 *
4122 * Process.getpgid(0) #=> 25527
4123 * Process.getpgrp #=> 25527
4124 */
4125
4126 static VALUE
4127 proc_getpgrp(void)
4128 {
4129 rb_pid_t pgrp;
4130
4131 rb_secure(2);
4132 #if defined(HAVE_GETPGRP) && defined(GETPGRP_VOID)
4133 pgrp = getpgrp();
4134 if (pgrp < 0) rb_sys_fail(0);
4135 return PIDT2NUM(pgrp);
4136 #else /* defined(HAVE_GETPGID) */
4137 pgrp = getpgid(0);
4138 if (pgrp < 0) rb_sys_fail(0);
4139 return PIDT2NUM(pgrp);
4140 #endif
4141 }
4142 #else
4143 #define proc_getpgrp rb_f_notimplement
4144 #endif
4145
4146
4147 #if defined(HAVE_SETPGID) || (defined(HAVE_SETPGRP) && defined(SETPGRP_VOID))
4148 /*
4149 * call-seq:
4150 * Process.setpgrp -> 0
4151 *
4152 * Equivalent to <code>setpgid(0,0)</code>. Not available on all
4153 * platforms.
4154 */
4155
4156 static VALUE
4157 proc_setpgrp(void)
4158 {
4159 rb_secure(2);
4160 /* check for posix setpgid() first; this matches the posix */
4161 /* getpgrp() above. It appears that configure will set SETPGRP_VOID */
4162 /* even though setpgrp(0,0) would be preferred. The posix call avoids */
4163 /* this confusion. */
4164 #ifdef HAVE_SETPGID
4165 if (setpgid(0,0) < 0) rb_sys_fail(0);
4166 #elif defined(HAVE_SETPGRP) && defined(SETPGRP_VOID)
4167 if (setpgrp() < 0) rb_sys_fail(0);
4168 #endif
4169 return INT2FIX(0);
4170 }
4171 #else
4172 #define proc_setpgrp rb_f_notimplement
4173 #endif
4174
4175
4176 #if defined(HAVE_GETPGID)
4177 /*
4178 * call-seq:
4179 * Process.getpgid(pid) -> integer
4180 *
4181 * Returns the process group ID for the given process id. Not
4182 * available on all platforms.
4183 *
4184 * Process.getpgid(Process.ppid()) #=> 25527
4185 */
4186
4187 static VALUE
4188 proc_getpgid(VALUE obj, VALUE pid)
4189 {
4190 rb_pid_t i;
4191
4192 rb_secure(2);
4193 i = getpgid(NUM2PIDT(pid));
4194 if (i < 0) rb_sys_fail(0);
4195 return PIDT2NUM(i);
4196 }
4197 #else
4198 #define proc_getpgid rb_f_notimplement
4199 #endif
4200
4201
4202 #ifdef HAVE_SETPGID
4203 /*
4204 * call-seq:
4205 * Process.setpgid(pid, integer) -> 0
4206 *
4207 * Sets the process group ID of _pid_ (0 indicates this
4208 * process) to <em>integer</em>. Not available on all platforms.
4209 */
4210
4211 static VALUE
4212 proc_setpgid(VALUE obj, VALUE pid, VALUE pgrp)
4213 {
4214 rb_pid_t ipid, ipgrp;
4215
4216 rb_secure(2);
4217 ipid = NUM2PIDT(pid);
4218 ipgrp = NUM2PIDT(pgrp);
4219
4220 if (setpgid(ipid, ipgrp) < 0) rb_sys_fail(0);
4221 return INT2FIX(0);
4222 }
4223 #else
4224 #define proc_setpgid rb_f_notimplement
4225 #endif
4226
4227
4228 #ifdef HAVE_GETSID
4229 /*
4230 * call-seq:
4231 * Process.getsid() -> integer
4232 * Process.getsid(pid) -> integer
4233 *
4234 * Returns the session ID for for the given process id. If not give,
4235 * return current process sid. Not available on all platforms.
4236 *
4237 * Process.getsid() #=> 27422
4238 * Process.getsid(0) #=> 27422
4239 * Process.getsid(Process.pid()) #=> 27422
4240 */
4241 static VALUE
4242 proc_getsid(int argc, VALUE *argv)
4243 {
4244 rb_pid_t sid;
4245 VALUE pid;
4246
4247 rb_secure(2);
4248 rb_scan_args(argc, argv, "01", &pid);
4249
4250 if (NIL_P(pid))
4251 pid = INT2NUM(0);
4252
4253 sid = getsid(NUM2PIDT(pid));
4254 if (sid < 0) rb_sys_fail(0);
4255 return PIDT2NUM(sid);
4256 }
4257 #else
4258 #define proc_getsid rb_f_notimplement
4259 #endif
4260
4261
4262 #if defined(HAVE_SETSID) || (defined(HAVE_SETPGRP) && defined(TIOCNOTTY))
4263 #if !defined(HAVE_SETSID)
4264 static rb_pid_t ruby_setsid(void);
4265 #define setsid() ruby_setsid()
4266 #endif
4267 /*
4268 * call-seq:
4269 * Process.setsid -> fixnum
4270 *
4271 * Establishes this process as a new session and process group
4272 * leader, with no controlling tty. Returns the session id. Not
4273 * available on all platforms.
4274 *
4275 * Process.setsid #=> 27422
4276 */
4277
4278 static VALUE
4279 proc_setsid(void)
4280 {
4281 rb_pid_t pid;
4282
4283 rb_secure(2);
4284 pid = setsid();
4285 if (pid < 0) rb_sys_fail(0);
4286 return PIDT2NUM(pid);
4287 }
4288
4289 #if !defined(HAVE_SETSID)
4290 #define HAVE_SETSID 1
4291 static rb_pid_t
4292 ruby_setsid(void)
4293 {
4294 rb_pid_t pid;
4295 int ret;
4296
4297 pid = getpid();
4298 #if defined(SETPGRP_VOID)
4299 ret = setpgrp();
4300 /* If `pid_t setpgrp(void)' is equivalent to setsid(),
4301 `ret' will be the same value as `pid', and following open() will fail.
4302 In Linux, `int setpgrp(void)' is equivalent to setpgid(0, 0). */
4303 #else
4304 ret = setpgrp(0, pid);
4305 #endif
4306 if (ret == -1) return -1;
4307
4308 if ((fd = rb_cloexec_open("/dev/tty", O_RDWR, 0)) >= 0) {
4309 rb_update_max_fd(fd);
4310 ioctl(fd, TIOCNOTTY, NULL);
4311 close(fd);
4312 }
4313 return pid;
4314 }
4315 #endif
4316 #else
4317 #define proc_setsid rb_f_notimplement
4318 #endif
4319
4320
4321 #ifdef HAVE_GETPRIORITY
4322 /*
4323 * call-seq:
4324 * Process.getpriority(kind, integer) -> fixnum
4325 *
4326 * Gets the scheduling priority for specified process, process group,
4327 * or user. <em>kind</em> indicates the kind of entity to find: one
4328 * of <code>Process::PRIO_PGRP</code>,
4329 * <code>Process::PRIO_USER</code>, or
4330 * <code>Process::PRIO_PROCESS</code>. _integer_ is an id
4331 * indicating the particular process, process group, or user (an id
4332 * of 0 means _current_). Lower priorities are more favorable
4333 * for scheduling. Not available on all platforms.
4334 *
4335 * Process.getpriority(Process::PRIO_USER, 0) #=> 19
4336 * Process.getpriority(Process::PRIO_PROCESS, 0) #=> 19
4337 */
4338
4339 static VALUE
4340 proc_getpriority(VALUE obj, VALUE which, VALUE who)
4341 {
4342 int prio, iwhich, iwho;
4343
4344 rb_secure(2);
4345 iwhich = NUM2INT(which);
4346 iwho = NUM2INT(who);
4347
4348 errno = 0;
4349 prio = getpriority(iwhich, iwho);
4350 if (errno) rb_sys_fail(0);
4351 return INT2FIX(prio);
4352 }
4353 #else
4354 #define proc_getpriority rb_f_notimplement
4355 #endif
4356
4357
4358 #ifdef HAVE_GETPRIORITY
4359 /*
4360 * call-seq:
4361 * Process.setpriority(kind, integer, priority) -> 0
4362 *
4363 * See <code>Process#getpriority</code>.
4364 *
4365 * Process.setpriority(Process::PRIO_USER, 0, 19) #=> 0
4366 * Process.setpriority(Process::PRIO_PROCESS, 0, 19) #=> 0
4367 * Process.getpriority(Process::PRIO_USER, 0) #=> 19
4368 * Process.getpriority(Process::PRIO_PROCESS, 0) #=> 19
4369 */
4370
4371 static VALUE
4372 proc_setpriority(VALUE obj, VALUE which, VALUE who, VALUE prio)
4373 {
4374 int iwhich, iwho, iprio;
4375
4376 rb_secure(2);
4377 iwhich = NUM2INT(which);
4378 iwho = NUM2INT(who);
4379 iprio = NUM2INT(prio);
4380
4381 if (setpriority(iwhich, iwho, iprio) < 0)
4382 rb_sys_fail(0);
4383 return INT2FIX(0);
4384 }
4385 #else
4386 #define proc_setpriority rb_f_notimplement
4387 #endif
4388
4389 #if defined(HAVE_SETRLIMIT) && defined(NUM2RLIM)
4390 static int
4391 rlimit_resource_name2int(const char *name, int casetype)
4392 {
4393 int resource;
4394 const char *p;
4395 #define RESCHECK(r) \
4396 do { \
4397 if (STRCASECMP(name, #r) == 0) { \
4398 resource = RLIMIT_##r; \
4399 goto found; \
4400 } \
4401 } while (0)
4402
4403 switch (TOUPPER(*name)) {
4404 case 'A':
4405 #ifdef RLIMIT_AS
4406 RESCHECK(AS);
4407 #endif
4408 break;
4409
4410 case 'C':
4411 #ifdef RLIMIT_CORE
4412 RESCHECK(CORE);
4413 #endif
4414 #ifdef RLIMIT_CPU
4415 RESCHECK(CPU);
4416 #endif
4417 break;
4418
4419 case 'D':
4420 #ifdef RLIMIT_DATA
4421 RESCHECK(DATA);
4422 #endif
4423 break;
4424
4425 case 'F':
4426 #ifdef RLIMIT_FSIZE
4427 RESCHECK(FSIZE);
4428 #endif
4429 break;
4430
4431 case 'M':
4432 #ifdef RLIMIT_MEMLOCK
4433 RESCHECK(MEMLOCK);
4434 #endif
4435 #ifdef RLIMIT_MSGQUEUE
4436 RESCHECK(MSGQUEUE);
4437 #endif
4438 break;
4439
4440 case 'N':
4441 #ifdef RLIMIT_NOFILE
4442 RESCHECK(NOFILE);
4443 #endif
4444 #ifdef RLIMIT_NPROC
4445 RESCHECK(NPROC);
4446 #endif
4447 #ifdef RLIMIT_NICE
4448 RESCHECK(NICE);
4449 #endif
4450 break;
4451
4452 case 'R':
4453 #ifdef RLIMIT_RSS
4454 RESCHECK(RSS);
4455 #endif
4456 #ifdef RLIMIT_RTPRIO
4457 RESCHECK(RTPRIO);
4458 #endif
4459 #ifdef RLIMIT_RTTIME
4460 RESCHECK(RTTIME);
4461 #endif
4462 break;
4463
4464 case 'S':
4465 #ifdef RLIMIT_STACK
4466 RESCHECK(STACK);
4467 #endif
4468 #ifdef RLIMIT_SBSIZE
4469 RESCHECK(SBSIZE);
4470 #endif
4471 #ifdef RLIMIT_SIGPENDING
4472 RESCHECK(SIGPENDING);
4473 #endif
4474 break;
4475 }
4476 return -1;
4477
4478 found:
4479 switch (casetype) {
4480 case 0:
4481 for (p = name; *p; p++)
4482 if (!ISUPPER(*p))
4483 return -1;
4484 break;
4485
4486 case 1:
4487 for (p = name; *p; p++)
4488 if (!ISLOWER(*p))
4489 return -1;
4490 break;
4491
4492 default:
4493 rb_bug("unexpected casetype");
4494 }
4495 return resource;
4496 #undef RESCHECK
4497 }
4498
4499 static int
4500 rlimit_type_by_hname(const char *name)
4501 {
4502 return rlimit_resource_name2int(name, 0);
4503 }
4504
4505 static int
4506 rlimit_type_by_lname(const char *name)
4507 {
4508 return rlimit_resource_name2int(name, 1);
4509 }
4510
4511 static int
4512 rlimit_resource_type(VALUE rtype)
4513 {
4514 const char *name;
4515 VALUE v;
4516 int r;
4517
4518 switch (TYPE(rtype)) {
4519 case T_SYMBOL:
4520 name = rb_id2name(SYM2ID(rtype));
4521 break;
4522
4523 default:
4524 v = rb_check_string_type(rtype);
4525 if (!NIL_P(v)) {
4526 rtype = v;
4527 case T_STRING:
4528 name = StringValueCStr(rtype);
4529 break;
4530 }
4531 /* fall through */
4532
4533 case T_FIXNUM:
4534 case T_BIGNUM:
4535 return NUM2INT(rtype);
4536 }
4537
4538 r = rlimit_type_by_hname(name);
4539 if (r != -1)
4540 return r;
4541
4542 rb_raise(rb_eArgError, "invalid resource name: %s", name);
4543
4544 UNREACHABLE;
4545 }
4546
4547 static rlim_t
4548 rlimit_resource_value(VALUE rval)
4549 {
4550 const char *name;
4551 VALUE v;
4552
4553 switch (TYPE(rval)) {
4554 case T_SYMBOL:
4555 name = rb_id2name(SYM2ID(rval));
4556 break;
4557
4558 default:
4559 v = rb_check_string_type(rval);
4560 if (!NIL_P(v)) {
4561 rval = v;
4562 case T_STRING:
4563 name = StringValueCStr(rval);
4564 break;
4565 }
4566 /* fall through */
4567
4568 case T_FIXNUM:
4569 case T_BIGNUM:
4570 return NUM2RLIM(rval);
4571 }
4572
4573 #ifdef RLIM_INFINITY
4574 if (strcmp(name, "INFINITY") == 0) return RLIM_INFINITY;
4575 #endif
4576 #ifdef RLIM_SAVED_MAX
4577 if (strcmp(name, "SAVED_MAX") == 0) return RLIM_SAVED_MAX;
4578 #endif
4579 #ifdef RLIM_SAVED_CUR
4580 if (strcmp(name, "SAVED_CUR") == 0) return RLIM_SAVED_CUR;
4581 #endif
4582 rb_raise(rb_eArgError, "invalid resource value: %s", name);
4583
4584 UNREACHABLE;
4585 }
4586 #endif
4587
4588 #if defined(HAVE_GETRLIMIT) && defined(RLIM2NUM)
4589 /*
4590 * call-seq:
4591 * Process.getrlimit(resource) -> [cur_limit, max_limit]
4592 *
4593 * Gets the resource limit of the process.
4594 * _cur_limit_ means current (soft) limit and
4595 * _max_limit_ means maximum (hard) limit.
4596 *
4597 * _resource_ indicates the kind of resource to limit.
4598 * It is specified as a symbol such as <code>:CORE</code>,
4599 * a string such as <code>"CORE"</code> or
4600 * a constant such as <code>Process::RLIMIT_CORE</code>.
4601 * See Process.setrlimit for details.
4602 *
4603 * _cur_limit_ and _max_limit_ may be <code>Process::RLIM_INFINITY</code>,
4604 * <code>Process::RLIM_SAVED_MAX</code> or
4605 * <code>Process::RLIM_SAVED_CUR</code>.
4606 * See Process.setrlimit and the system getrlimit(2) manual for details.
4607 */
4608
4609 static VALUE
4610 proc_getrlimit(VALUE obj, VALUE resource)
4611 {
4612 struct rlimit rlim;
4613
4614 rb_secure(2);
4615
4616 if (getrlimit(rlimit_resource_type(resource), &rlim) < 0) {
4617 rb_sys_fail("getrlimit");
4618 }
4619 return rb_assoc_new(RLIM2NUM(rlim.rlim_cur), RLIM2NUM(rlim.rlim_max));
4620 }
4621 #else
4622 #define proc_getrlimit rb_f_notimplement
4623 #endif
4624
4625 #if defined(HAVE_SETRLIMIT) && defined(NUM2RLIM)
4626 /*
4627 * call-seq:
4628 * Process.setrlimit(resource, cur_limit, max_limit) -> nil
4629 * Process.setrlimit(resource, cur_limit) -> nil
4630 *
4631 * Sets the resource limit of the process.
4632 * _cur_limit_ means current (soft) limit and
4633 * _max_limit_ means maximum (hard) limit.
4634 *
4635 * If _max_limit_ is not given, _cur_limit_ is used.
4636 *
4637 * _resource_ indicates the kind of resource to limit.
4638 * It should be a symbol such as <code>:CORE</code>,
4639 * a string such as <code>"CORE"</code> or
4640 * a constant such as <code>Process::RLIMIT_CORE</code>.
4641 * The available resources are OS dependent.
4642 * Ruby may support following resources.
4643 *
4644 * [AS] total available memory (bytes) (SUSv3, NetBSD, FreeBSD, OpenBSD but 4.4BSD-Lite)
4645 * [CORE] core size (bytes) (SUSv3)
4646 * [CPU] CPU time (seconds) (SUSv3)
4647 * [DATA] data segment (bytes) (SUSv3)
4648 * [FSIZE] file size (bytes) (SUSv3)
4649 * [MEMLOCK] total size for mlock(2) (bytes) (4.4BSD, GNU/Linux)
4650 * [MSGQUEUE] allocation for POSIX message queues (bytes) (GNU/Linux)
4651 * [NICE] ceiling on process's nice(2) value (number) (GNU/Linux)
4652 * [NOFILE] file descriptors (number) (SUSv3)
4653 * [NPROC] number of processes for the user (number) (4.4BSD, GNU/Linux)
4654 * [RSS] resident memory size (bytes) (4.2BSD, GNU/Linux)
4655 * [RTPRIO] ceiling on the process's real-time priority (number) (GNU/Linux)
4656 * [RTTIME] CPU time for real-time process (us) (GNU/Linux)
4657 * [SBSIZE] all socket buffers (bytes) (NetBSD, FreeBSD)
4658 * [SIGPENDING] number of queued signals allowed (signals) (GNU/Linux)
4659 * [STACK] stack size (bytes) (SUSv3)
4660 *
4661 * _cur_limit_ and _max_limit_ may be
4662 * <code>:INFINITY</code>, <code>"INFINITY"</code> or
4663 * <code>Process::RLIM_INFINITY</code>,
4664 * which means that the resource is not limited.
4665 * They may be <code>Process::RLIM_SAVED_MAX</code>,
4666 * <code>Process::RLIM_SAVED_CUR</code> and
4667 * corresponding symbols and strings too.
4668 * See system setrlimit(2) manual for details.
4669 *
4670 * The following example raises the soft limit of core size to
4671 * the hard limit to try to make core dump possible.
4672 *
4673 * Process.setrlimit(:CORE, Process.getrlimit(:CORE)[1])
4674 *
4675 */
4676
4677 static VALUE
4678 proc_setrlimit(int argc, VALUE *argv, VALUE obj)
4679 {
4680 VALUE resource, rlim_cur, rlim_max;
4681 struct rlimit rlim;
4682
4683 rb_secure(2);
4684
4685 rb_scan_args(argc, argv, "21", &resource, &rlim_cur, &rlim_max);
4686 if (rlim_max == Qnil)
4687 rlim_max = rlim_cur;
4688
4689 rlim.rlim_cur = rlimit_resource_value(rlim_cur);
4690 rlim.rlim_max = rlimit_resource_value(rlim_max);
4691
4692 if (setrlimit(rlimit_resource_type(resource), &rlim) < 0) {
4693 rb_sys_fail("setrlimit");
4694 }
4695 return Qnil;
4696 }
4697 #else
4698 #define proc_setrlimit rb_f_notimplement
4699 #endif
4700
4701 static int under_uid_switch = 0;
4702 static void
4703 check_uid_switch(void)
4704 {
4705 rb_secure(2);
4706 if (under_uid_switch) {
4707 rb_raise(rb_eRuntimeError, "can't handle UID while evaluating block given to Process::UID.switch method");
4708 }
4709 }
4710
4711 static int under_gid_switch = 0;
4712 static void
4713 check_gid_switch(void)
4714 {
4715 rb_secure(2);
4716 if (under_gid_switch) {
4717 rb_raise(rb_eRuntimeError, "can't handle GID while evaluating block given to Process::UID.switch method");
4718 }
4719 }
4720
4721
4722 /*********************************************************************
4723 * Document-class: Process::Sys
4724 *
4725 * The <code>Process::Sys</code> module contains UID and GID
4726 * functions which provide direct bindings to the system calls of the
4727 * same names instead of the more-portable versions of the same
4728 * functionality found in the <code>Process</code>,
4729 * <code>Process::UID</code>, and <code>Process::GID</code> modules.
4730 */
4731
4732 #if defined(HAVE_PWD_H)
4733 static rb_uid_t
4734 obj2uid(VALUE id
4735 # ifdef USE_GETPWNAM_R
4736 , char *getpw_buf, size_t getpw_buf_len
4737 # endif
4738 )
4739 {
4740 rb_uid_t uid;
4741 VALUE tmp;
4742
4743 if (FIXNUM_P(id) || NIL_P(tmp = rb_check_string_type(id))) {
4744 uid = NUM2UIDT(id);
4745 }
4746 else {
4747 const char *usrname = StringValueCStr(id);
4748 struct passwd *pwptr;
4749 #ifdef USE_GETPWNAM_R
4750 struct passwd pwbuf;
4751 if (getpwnam_r(usrname, &pwbuf, getpw_buf, getpw_buf_len, &pwptr))
4752 rb_sys_fail("getpwnam_r");
4753 #else
4754 pwptr = getpwnam(usrname);
4755 #endif
4756 if (!pwptr) {
4757 #ifndef USE_GETPWNAM_R
4758 endpwent();
4759 #endif
4760 rb_raise(rb_eArgError, "can't find user for %s", usrname);
4761 }
4762 uid = pwptr->pw_uid;
4763 #ifndef USE_GETPWNAM_R
4764 endpwent();
4765 #endif
4766 }
4767 return uid;
4768 }
4769
4770 # ifdef p_uid_from_name
4771 static VALUE
4772 p_uid_from_name(VALUE self, VALUE id)
4773 {
4774 PREPARE_GETPWNAM
4775 return UIDT2NUM(OBJ2UID(id));
4776 }
4777 # endif
4778 #endif
4779
4780 #if defined(HAVE_GRP_H)
4781 static rb_gid_t
4782 obj2gid(VALUE id
4783 # ifdef USE_GETGRNAM_R
4784 , char *getgr_buf, size_t getgr_buf_len
4785 # endif
4786 )
4787 {
4788 rb_gid_t gid;
4789 VALUE tmp;
4790
4791 if (FIXNUM_P(id) || NIL_P(tmp = rb_check_string_type(id))) {
4792 gid = NUM2GIDT(id);
4793 }
4794 else {
4795 const char *grpname = StringValueCStr(id);
4796 struct group *grptr;
4797 #ifdef USE_GETGRNAM_R
4798 struct group grbuf;
4799 if (getgrnam_r(grpname, &grbuf, getgr_buf, getgr_buf_len, &grptr))
4800 rb_sys_fail("getgrnam_r");
4801 #else
4802 grptr = getgrnam(grpname);
4803 #endif
4804 if (!grptr) {
4805 #ifndef USE_GETGRNAM_R
4806 endgrent();
4807 #endif
4808 rb_raise(rb_eArgError, "can't find group for %s", grpname);
4809 }
4810 gid = grptr->gr_gid;
4811 #ifndef USE_GETGRNAM_R
4812 endgrent();
4813 #endif
4814 }
4815 return gid;
4816 }
4817
4818 # ifdef p_gid_from_name
4819 static VALUE
4820 p_gid_from_name(VALUE self, VALUE id)
4821 {
4822 PREPARE_GETGRNAM;
4823 return GIDT2NUM(OBJ2GID(id));
4824 }
4825 # endif
4826 #endif
4827
4828 #if defined HAVE_SETUID
4829 /*
4830 * call-seq:
4831 * Process::Sys.setuid(user) -> nil
4832 *
4833 * Set the user ID of the current process to _user_. Not
4834 * available on all platforms.
4835 *
4836 */
4837
4838 static VALUE
4839 p_sys_setuid(VALUE obj, VALUE id)
4840 {
4841 PREPARE_GETPWNAM;
4842 check_uid_switch();
4843 if (setuid(OBJ2UID(id)) != 0) rb_sys_fail(0);
4844 return Qnil;
4845 }
4846 #else
4847 #define p_sys_setuid rb_f_notimplement
4848 #endif
4849
4850
4851 #if defined HAVE_SETRUID
4852 /*
4853 * call-seq:
4854 * Process::Sys.setruid(user) -> nil
4855 *
4856 * Set the real user ID of the calling process to _user_.
4857 * Not available on all platforms.
4858 *
4859 */
4860
4861 static VALUE
4862 p_sys_setruid(VALUE obj, VALUE id)
4863 {
4864 PREPARE_GETPWNAM;
4865 check_uid_switch();
4866 if (setruid(OBJ2UID(id)) != 0) rb_sys_fail(0);
4867 return Qnil;
4868 }
4869 #else
4870 #define p_sys_setruid rb_f_notimplement
4871 #endif
4872
4873
4874 #if defined HAVE_SETEUID
4875 /*
4876 * call-seq:
4877 * Process::Sys.seteuid(user) -> nil
4878 *
4879 * Set the effective user ID of the calling process to
4880 * _user_. Not available on all platforms.
4881 *
4882 */
4883
4884 static VALUE
4885 p_sys_seteuid(VALUE obj, VALUE id)
4886 {
4887 PREPARE_GETPWNAM;
4888 check_uid_switch();
4889 if (seteuid(OBJ2UID(id)) != 0) rb_sys_fail(0);
4890 return Qnil;
4891 }
4892 #else
4893 #define p_sys_seteuid rb_f_notimplement
4894 #endif
4895
4896
4897 #if defined HAVE_SETREUID
4898 /*
4899 * call-seq:
4900 * Process::Sys.setreuid(rid, eid) -> nil
4901 *
4902 * Sets the (user) real and/or effective user IDs of the current
4903 * process to _rid_ and _eid_, respectively. A value of
4904 * <code>-1</code> for either means to leave that ID unchanged. Not
4905 * available on all platforms.
4906 *
4907 */
4908
4909 static VALUE
4910 p_sys_setreuid(VALUE obj, VALUE rid, VALUE eid)
4911 {
4912 PREPARE_GETPWNAM;
4913 check_uid_switch();
4914 if (setreuid(OBJ2UID(rid), OBJ2UID(eid)) != 0) rb_sys_fail(0);
4915 return Qnil;
4916 }
4917 #else
4918 #define p_sys_setreuid rb_f_notimplement
4919 #endif
4920
4921
4922 #if defined HAVE_SETRESUID
4923 /*
4924 * call-seq:
4925 * Process::Sys.setresuid(rid, eid, sid) -> nil
4926 *
4927 * Sets the (user) real, effective, and saved user IDs of the
4928 * current process to _rid_, _eid_, and _sid_ respectively. A
4929 * value of <code>-1</code> for any value means to
4930 * leave that ID unchanged. Not available on all platforms.
4931 *
4932 */
4933
4934 static VALUE
4935 p_sys_setresuid(VALUE obj, VALUE rid, VALUE eid, VALUE sid)
4936 {
4937 PREPARE_GETPWNAM;
4938 check_uid_switch();
4939 if (setresuid(OBJ2UID(rid), OBJ2UID(eid), OBJ2UID(sid)) != 0) rb_sys_fail(0);
4940 return Qnil;
4941 }
4942 #else
4943 #define p_sys_setresuid rb_f_notimplement
4944 #endif
4945
4946
4947 /*
4948 * call-seq:
4949 * Process.uid -> fixnum
4950 * Process::UID.rid -> fixnum
4951 * Process::Sys.getuid -> fixnum
4952 *
4953 * Returns the (real) user ID of this process.
4954 *
4955 * Process.uid #=> 501
4956 */
4957
4958 static VALUE
4959 proc_getuid(VALUE obj)
4960 {
4961 rb_uid_t uid = getuid();
4962 return UIDT2NUM(uid);
4963 }
4964
4965
4966 #if defined(HAVE_SETRESUID) || defined(HAVE_SETREUID) || defined(HAVE_SETRUID) || defined(HAVE_SETUID)
4967 /*
4968 * call-seq:
4969 * Process.uid= user -> numeric
4970 *
4971 * Sets the (user) user ID for this process. Not available on all
4972 * platforms.
4973 */
4974
4975 static VALUE
4976 proc_setuid(VALUE obj, VALUE id)
4977 {
4978 rb_uid_t uid;
4979 PREPARE_GETPWNAM;
4980
4981 check_uid_switch();
4982
4983 uid = OBJ2UID(id);
4984 #if defined(HAVE_SETRESUID)
4985 if (setresuid(uid, -1, -1) < 0) rb_sys_fail(0);
4986 #elif defined HAVE_SETREUID
4987 if (setreuid(uid, -1) < 0) rb_sys_fail(0);
4988 #elif defined HAVE_SETRUID
4989 if (setruid(uid) < 0) rb_sys_fail(0);
4990 #elif defined HAVE_SETUID
4991 {
4992 if (geteuid() == uid) {
4993 if (setuid(uid) < 0) rb_sys_fail(0);
4994 }
4995 else {
4996 rb_notimplement();
4997 }
4998 }
4999 #endif
5000 return id;
5001 }
5002 #else
5003 #define proc_setuid rb_f_notimplement
5004 #endif
5005
5006
5007 /********************************************************************
5008 *
5009 * Document-class: Process::UID
5010 *
5011 * The <code>Process::UID</code> module contains a collection of
5012 * module functions which can be used to portably get, set, and
5013 * switch the current process's real, effective, and saved user IDs.
5014 *
5015 */
5016
5017 static rb_uid_t SAVED_USER_ID = -1;
5018
5019 #ifdef BROKEN_SETREUID
5020 int
5021 setreuid(rb_uid_t ruid, rb_uid_t euid)
5022 {
5023 if (ruid != (rb_uid_t)-1 && ruid != getuid()) {
5024 if (euid == (rb_uid_t)-1) euid = geteuid();
5025 if (setuid(ruid) < 0) return -1;
5026 }
5027 if (euid != (rb_uid_t)-1 && euid != geteuid()) {
5028 if (seteuid(euid) < 0) return -1;
5029 }
5030 return 0;
5031 }
5032 #endif
5033
5034 /*
5035 * call-seq:
5036 * Process::UID.change_privilege(user) -> fixnum
5037 *
5038 * Change the current process's real and effective user ID to that
5039 * specified by _user_. Returns the new user ID. Not
5040 * available on all platforms.
5041 *
5042 * [Process.uid, Process.euid] #=> [0, 0]
5043 * Process::UID.change_privilege(31) #=> 31
5044 * [Process.uid, Process.euid] #=> [31, 31]
5045 */
5046
5047 static VALUE
5048 p_uid_change_privilege(VALUE obj, VALUE id)
5049 {
5050 rb_uid_t uid;
5051 PREPARE_GETPWNAM;
5052
5053 check_uid_switch();
5054
5055 uid = OBJ2UID(id);
5056
5057 if (geteuid() == 0) { /* root-user */
5058 #if defined(HAVE_SETRESUID)
5059 if (setresuid(uid, uid, uid) < 0) rb_sys_fail(0);
5060 SAVED_USER_ID = uid;
5061 #elif defined(HAVE_SETUID)
5062 if (setuid(uid) < 0) rb_sys_fail(0);
5063 SAVED_USER_ID = uid;
5064 #elif defined(HAVE_SETREUID) && !defined(OBSOLETE_SETREUID)
5065 if (getuid() == uid) {
5066 if (SAVED_USER_ID == uid) {
5067 if (setreuid(-1, uid) < 0) rb_sys_fail(0);
5068 }
5069 else {
5070 if (uid == 0) { /* (r,e,s) == (root, root, x) */
5071 if (setreuid(-1, SAVED_USER_ID) < 0) rb_sys_fail(0);
5072 if (setreuid(SAVED_USER_ID, 0) < 0) rb_sys_fail(0);
5073 SAVED_USER_ID = 0; /* (r,e,s) == (x, root, root) */
5074 if (setreuid(uid, uid) < 0) rb_sys_fail(0);
5075 SAVED_USER_ID = uid;
5076 }
5077 else {
5078 if (setreuid(0, -1) < 0) rb_sys_fail(0);
5079 SAVED_USER_ID = 0;
5080 if (setreuid(uid, uid) < 0) rb_sys_fail(0);
5081 SAVED_USER_ID = uid;
5082 }
5083 }
5084 }
5085 else {
5086 if (setreuid(uid, uid) < 0) rb_sys_fail(0);
5087 SAVED_USER_ID = uid;
5088 }
5089 #elif defined(HAVE_SETRUID) && defined(HAVE_SETEUID)
5090 if (getuid() == uid) {
5091 if (SAVED_USER_ID == uid) {
5092 if (seteuid(uid) < 0) rb_sys_fail(0);
5093 }
5094 else {
5095 if (uid == 0) {
5096 if (setruid(SAVED_USER_ID) < 0) rb_sys_fail(0);
5097 SAVED_USER_ID = 0;
5098 if (setruid(0) < 0) rb_sys_fail(0);
5099 }
5100 else {
5101 if (setruid(0) < 0) rb_sys_fail(0);
5102 SAVED_USER_ID = 0;
5103 if (seteuid(uid) < 0) rb_sys_fail(0);
5104 if (setruid(uid) < 0) rb_sys_fail(0);
5105 SAVED_USER_ID = uid;
5106 }
5107 }
5108 }
5109 else {
5110 if (seteuid(uid) < 0) rb_sys_fail(0);
5111 if (setruid(uid) < 0) rb_sys_fail(0);
5112 SAVED_USER_ID = uid;
5113 }
5114 #else
5115 (void)uid;
5116 rb_notimplement();
5117 #endif
5118 }
5119 else { /* unprivileged user */
5120 #if defined(HAVE_SETRESUID)
5121 if (setresuid((getuid() == uid)? (rb_uid_t)-1: uid,
5122 (geteuid() == uid)? (rb_uid_t)-1: uid,
5123 (SAVED_USER_ID == uid)? (rb_uid_t)-1: uid) < 0) rb_sys_fail(0);
5124 SAVED_USER_ID = uid;
5125 #elif defined(HAVE_SETREUID) && !defined(OBSOLETE_SETREUID)
5126 if (SAVED_USER_ID == uid) {
5127 if (setreuid((getuid() == uid)? (rb_uid_t)-1: uid,
5128 (geteuid() == uid)? (rb_uid_t)-1: uid) < 0)
5129 rb_sys_fail(0);
5130 }
5131 else if (getuid() != uid) {
5132 if (setreuid(uid, (geteuid() == uid)? (rb_uid_t)-1: uid) < 0)
5133 rb_sys_fail(0);
5134 SAVED_USER_ID = uid;
5135 }
5136 else if (/* getuid() == uid && */ geteuid() != uid) {
5137 if (setreuid(geteuid(), uid) < 0) rb_sys_fail(0);
5138 SAVED_USER_ID = uid;
5139 if (setreuid(uid, -1) < 0) rb_sys_fail(0);
5140 }
5141 else { /* getuid() == uid && geteuid() == uid */
5142 if (setreuid(-1, SAVED_USER_ID) < 0) rb_sys_fail(0);
5143 if (setreuid(SAVED_USER_ID, uid) < 0) rb_sys_fail(0);
5144 SAVED_USER_ID = uid;
5145 if (setreuid(uid, -1) < 0) rb_sys_fail(0);
5146 }
5147 #elif defined(HAVE_SETRUID) && defined(HAVE_SETEUID)
5148 if (SAVED_USER_ID == uid) {
5149 if (geteuid() != uid && seteuid(uid) < 0) rb_sys_fail(0);
5150 if (getuid() != uid && setruid(uid) < 0) rb_sys_fail(0);
5151 }
5152 else if (/* SAVED_USER_ID != uid && */ geteuid() == uid) {
5153 if (getuid() != uid) {
5154 if (setruid(uid) < 0) rb_sys_fail(0);
5155 SAVED_USER_ID = uid;
5156 }
5157 else {
5158 if (setruid(SAVED_USER_ID) < 0) rb_sys_fail(0);
5159 SAVED_USER_ID = uid;
5160 if (setruid(uid) < 0) rb_sys_fail(0);
5161 }
5162 }
5163 else if (/* geteuid() != uid && */ getuid() == uid) {
5164 if (seteuid(uid) < 0) rb_sys_fail(0);
5165 if (setruid(SAVED_USER_ID) < 0) rb_sys_fail(0);
5166 SAVED_USER_ID = uid;
5167 if (setruid(uid) < 0) rb_sys_fail(0);
5168 }
5169 else {
5170 errno = EPERM;
5171 rb_sys_fail(0);
5172 }
5173 #elif defined HAVE_44BSD_SETUID
5174 if (getuid() == uid) {
5175 /* (r,e,s)==(uid,?,?) ==> (uid,uid,uid) */
5176 if (setuid(uid) < 0) rb_sys_fail(0);
5177 SAVED_USER_ID = uid;
5178 }
5179 else {
5180 errno = EPERM;
5181 rb_sys_fail(0);
5182 }
5183 #elif defined HAVE_SETEUID
5184 if (getuid() == uid && SAVED_USER_ID == uid) {
5185 if (seteuid(uid) < 0) rb_sys_fail(0);
5186 }
5187 else {
5188 errno = EPERM;
5189 rb_sys_fail(0);
5190 }
5191 #elif defined HAVE_SETUID
5192 if (getuid() == uid && SAVED_USER_ID == uid) {
5193 if (setuid(uid) < 0) rb_sys_fail(0);
5194 }
5195 else {
5196 errno = EPERM;
5197 rb_sys_fail(0);
5198 }
5199 #else
5200 rb_notimplement();
5201 #endif
5202 }
5203 return id;
5204 }
5205
5206
5207
5208 #if defined HAVE_SETGID
5209 /*
5210 * call-seq:
5211 * Process::Sys.setgid(group) -> nil
5212 *
5213 * Set the group ID of the current process to _group_. Not
5214 * available on all platforms.
5215 *
5216 */
5217
5218 static VALUE
5219 p_sys_setgid(VALUE obj, VALUE id)
5220 {
5221 PREPARE_GETGRNAM;
5222 check_gid_switch();
5223 if (setgid(OBJ2GID(id)) != 0) rb_sys_fail(0);
5224 return Qnil;
5225 }
5226 #else
5227 #define p_sys_setgid rb_f_notimplement
5228 #endif
5229
5230
5231 #if defined HAVE_SETRGID
5232 /*
5233 * call-seq:
5234 * Process::Sys.setrgid(group) -> nil
5235 *
5236 * Set the real group ID of the calling process to _group_.
5237 * Not available on all platforms.
5238 *
5239 */
5240
5241 static VALUE
5242 p_sys_setrgid(VALUE obj, VALUE id)
5243 {
5244 PREPARE_GETGRNAM;
5245 check_gid_switch();
5246 if (setrgid(OBJ2GID(id)) != 0) rb_sys_fail(0);
5247 return Qnil;
5248 }
5249 #else
5250 #define p_sys_setrgid rb_f_notimplement
5251 #endif
5252
5253
5254 #if defined HAVE_SETEGID
5255 /*
5256 * call-seq:
5257 * Process::Sys.setegid(group) -> nil
5258 *
5259 * Set the effective group ID of the calling process to
5260 * _group_. Not available on all platforms.
5261 *
5262 */
5263
5264 static VALUE
5265 p_sys_setegid(VALUE obj, VALUE id)
5266 {
5267 PREPARE_GETGRNAM;
5268 check_gid_switch();
5269 if (setegid(OBJ2GID(id)) != 0) rb_sys_fail(0);
5270 return Qnil;
5271 }
5272 #else
5273 #define p_sys_setegid rb_f_notimplement
5274 #endif
5275
5276
5277 #if defined HAVE_SETREGID
5278 /*
5279 * call-seq:
5280 * Process::Sys.setregid(rid, eid) -> nil
5281 *
5282 * Sets the (group) real and/or effective group IDs of the current
5283 * process to <em>rid</em> and <em>eid</em>, respectively. A value of
5284 * <code>-1</code> for either means to leave that ID unchanged. Not
5285 * available on all platforms.
5286 *
5287 */
5288
5289 static VALUE
5290 p_sys_setregid(VALUE obj, VALUE rid, VALUE eid)
5291 {
5292 PREPARE_GETGRNAM;
5293 check_gid_switch();
5294 if (setregid(OBJ2GID(rid), OBJ2GID(eid)) != 0) rb_sys_fail(0);
5295 return Qnil;
5296 }
5297 #else
5298 #define p_sys_setregid rb_f_notimplement
5299 #endif
5300
5301 #if defined HAVE_SETRESGID
5302 /*
5303 * call-seq:
5304 * Process::Sys.setresgid(rid, eid, sid) -> nil
5305 *
5306 * Sets the (group) real, effective, and saved user IDs of the
5307 * current process to <em>rid</em>, <em>eid</em>, and <em>sid</em>
5308 * respectively. A value of <code>-1</code> for any value means to
5309 * leave that ID unchanged. Not available on all platforms.
5310 *
5311 */
5312
5313 static VALUE
5314 p_sys_setresgid(VALUE obj, VALUE rid, VALUE eid, VALUE sid)
5315 {
5316 PREPARE_GETGRNAM;
5317 check_gid_switch();
5318 if (setresgid(OBJ2GID(rid), OBJ2GID(eid), OBJ2GID(sid)) != 0) rb_sys_fail(0);
5319 return Qnil;
5320 }
5321 #else
5322 #define p_sys_setresgid rb_f_notimplement
5323 #endif
5324
5325
5326 #if defined HAVE_ISSETUGID
5327 /*
5328 * call-seq:
5329 * Process::Sys.issetugid -> true or false
5330 *
5331 * Returns +true+ if the process was created as a result
5332 * of an execve(2) system call which had either of the setuid or
5333 * setgid bits set (and extra privileges were given as a result) or
5334 * if it has changed any of its real, effective or saved user or
5335 * group IDs since it began execution.
5336 *
5337 */
5338
5339 static VALUE
5340 p_sys_issetugid(VALUE obj)
5341 {
5342 rb_secure(2);
5343 if (issetugid()) {
5344 return Qtrue;
5345 }
5346 else {
5347 return Qfalse;
5348 }
5349 }
5350 #else
5351 #define p_sys_issetugid rb_f_notimplement
5352 #endif
5353
5354
5355 /*
5356 * call-seq:
5357 * Process.gid -> fixnum
5358 * Process::GID.rid -> fixnum
5359 * Process::Sys.getgid -> fixnum
5360 *
5361 * Returns the (real) group ID for this process.
5362 *
5363 * Process.gid #=> 500
5364 */
5365
5366 static VALUE
5367 proc_getgid(VALUE obj)
5368 {
5369 rb_gid_t gid = getgid();
5370 return GIDT2NUM(gid);
5371 }
5372
5373
5374 #if defined(HAVE_SETRESGID) || defined(HAVE_SETREGID) || defined(HAVE_SETRGID) || defined(HAVE_SETGID)
5375 /*
5376 * call-seq:
5377 * Process.gid= fixnum -> fixnum
5378 *
5379 * Sets the group ID for this process.
5380 */
5381
5382 static VALUE
5383 proc_setgid(VALUE obj, VALUE id)
5384 {
5385 rb_gid_t gid;
5386 PREPARE_GETGRNAM;
5387
5388 check_gid_switch();
5389
5390 gid = OBJ2GID(id);
5391 #if defined(HAVE_SETRESGID)
5392 if (setresgid(gid, -1, -1) < 0) rb_sys_fail(0);
5393 #elif defined HAVE_SETREGID
5394 if (setregid(gid, -1) < 0) rb_sys_fail(0);
5395 #elif defined HAVE_SETRGID
5396 if (setrgid(gid) < 0) rb_sys_fail(0);
5397 #elif defined HAVE_SETGID
5398 {
5399 if (getegid() == gid) {
5400 if (setgid(gid) < 0) rb_sys_fail(0);
5401 }
5402 else {
5403 rb_notimplement();
5404 }
5405 }
5406 #endif
5407 return GIDT2NUM(gid);
5408 }
5409 #else
5410 #define proc_setgid rb_f_notimplement
5411 #endif
5412
5413
5414 #if defined(HAVE_SETGROUPS) || defined(HAVE_GETGROUPS)
5415 /*
5416 * Maximum supplementary groups are platform dependent.
5417 * FWIW, 65536 is enough big for our supported OSs.
5418 *
5419 * OS Name max groups
5420 * -----------------------------------------------
5421 * Linux Kernel >= 2.6.3 65536
5422 * Linux Kernel < 2.6.3 32
5423 * IBM AIX 5.2 64
5424 * IBM AIX 5.3 ... 6.1 128
5425 * IBM AIX 7.1 128 (can be configured to be up to 2048)
5426 * OpenBSD, NetBSD 16
5427 * FreeBSD < 8.0 16
5428 * FreeBSD >=8.0 1023
5429 * Darwin (Mac OS X) 16
5430 * Sun Solaris 7,8,9,10 16
5431 * Sun Solaris 11 / OpenSolaris 1024
5432 * HP-UX 20
5433 * Windows 1015
5434 */
5435 static int _maxgroups = -1;
5436 static int
5437 get_sc_ngroups_max(void)
5438 {
5439 #ifdef _SC_NGROUPS_MAX
5440 return (int)sysconf(_SC_NGROUPS_MAX);
5441 #elif defined(NGROUPS_MAX)
5442 return (int)NGROUPS_MAX;
5443 #else
5444 return -1;
5445 #endif
5446 }
5447 static int
5448 maxgroups(void)
5449 {
5450 if (_maxgroups < 0) {
5451 _maxgroups = get_sc_ngroups_max();
5452 if (_maxgroups < 0)
5453 _maxgroups = RB_MAX_GROUPS;
5454 }
5455
5456 return _maxgroups;
5457 }
5458 #endif
5459
5460
5461
5462 #ifdef HAVE_GETGROUPS
5463 /*
5464 * call-seq:
5465 * Process.groups -> array
5466 *
5467 * Get an <code>Array</code> of the gids of groups in the
5468 * supplemental group access list for this process.
5469 *
5470 * Process.groups #=> [27, 6, 10, 11]
5471 *
5472 */
5473
5474 static VALUE
5475 proc_getgroups(VALUE obj)
5476 {
5477 VALUE ary;
5478 int i, ngroups;
5479 rb_gid_t *groups;
5480
5481 ngroups = getgroups(0, NULL);
5482 if (ngroups == -1)
5483 rb_sys_fail(0);
5484
5485 groups = ALLOCA_N(rb_gid_t, ngroups);
5486
5487 ngroups = getgroups(ngroups, groups);
5488 if (ngroups == -1)
5489 rb_sys_fail(0);
5490
5491 ary = rb_ary_new();
5492 for (i = 0; i < ngroups; i++)
5493 rb_ary_push(ary, GIDT2NUM(groups[i]));
5494
5495 return ary;
5496 }
5497 #else
5498 #define proc_getgroups rb_f_notimplement
5499 #endif
5500
5501
5502 #ifdef HAVE_SETGROUPS
5503 /*
5504 * call-seq:
5505 * Process.groups= array -> array
5506 *
5507 * Set the supplemental group access list to the given
5508 * <code>Array</code> of group IDs.
5509 *
5510 * Process.groups #=> [0, 1, 2, 3, 4, 6, 10, 11, 20, 26, 27]
5511 * Process.groups = [27, 6, 10, 11] #=> [27, 6, 10, 11]
5512 * Process.groups #=> [27, 6, 10, 11]
5513 *
5514 */
5515
5516 static VALUE
5517 proc_setgroups(VALUE obj, VALUE ary)
5518 {
5519 int ngroups, i;
5520 rb_gid_t *groups;
5521 PREPARE_GETGRNAM;
5522
5523 Check_Type(ary, T_ARRAY);
5524
5525 ngroups = RARRAY_LENINT(ary);
5526 if (ngroups > maxgroups())
5527 rb_raise(rb_eArgError, "too many groups, %d max", maxgroups());
5528
5529 groups = ALLOCA_N(rb_gid_t, ngroups);
5530
5531 for (i = 0; i < ngroups; i++) {
5532 VALUE g = RARRAY_PTR(ary)[i];
5533
5534 groups[i] = OBJ2GID(g);
5535 }
5536
5537 if (setgroups(ngroups, groups) == -1) /* ngroups <= maxgroups */
5538 rb_sys_fail(0);
5539
5540 return proc_getgroups(obj);
5541 }
5542 #else
5543 #define proc_setgroups rb_f_notimplement
5544 #endif
5545
5546
5547 #ifdef HAVE_INITGROUPS
5548 /*
5549 * call-seq:
5550 * Process.initgroups(username, gid) -> array
5551 *
5552 * Initializes the supplemental group access list by reading the
5553 * system group database and using all groups of which the given user
5554 * is a member. The group with the specified <em>gid</em> is also
5555 * added to the list. Returns the resulting <code>Array</code> of the
5556 * gids of all the groups in the supplementary group access list. Not
5557 * available on all platforms.
5558 *
5559 * Process.groups #=> [0, 1, 2, 3, 4, 6, 10, 11, 20, 26, 27]
5560 * Process.initgroups( "mgranger", 30 ) #=> [30, 6, 10, 11]
5561 * Process.groups #=> [30, 6, 10, 11]
5562 *
5563 */
5564
5565 static VALUE
5566 proc_initgroups(VALUE obj, VALUE uname, VALUE base_grp)
5567 {
5568 PREPARE_GETGRNAM;
5569 if (initgroups(StringValuePtr(uname), OBJ2GID(base_grp)) != 0) {
5570 rb_sys_fail(0);
5571 }
5572 return proc_getgroups(obj);
5573 }
5574 #else
5575 #define proc_initgroups rb_f_notimplement
5576 #endif
5577
5578 #if defined(_SC_NGROUPS_MAX) || defined(NGROUPS_MAX)
5579 /*
5580 * call-seq:
5581 * Process.maxgroups -> fixnum
5582 *
5583 * Returns the maximum number of gids allowed in the supplemental
5584 * group access list.
5585 *
5586 * Process.maxgroups #=> 32
5587 */
5588
5589 static VALUE
5590 proc_getmaxgroups(VALUE obj)
5591 {
5592 return INT2FIX(maxgroups());
5593 }
5594 #else
5595 #define proc_getmaxgroups rb_f_notimplement
5596 #endif
5597
5598 #ifdef HAVE_SETGROUPS
5599 /*
5600 * call-seq:
5601 * Process.maxgroups= fixnum -> fixnum
5602 *
5603 * Sets the maximum number of gids allowed in the supplemental group
5604 * access list.
5605 */
5606
5607 static VALUE
5608 proc_setmaxgroups(VALUE obj, VALUE val)
5609 {
5610 int ngroups = FIX2INT(val);
5611 int ngroups_max = get_sc_ngroups_max();
5612
5613 if (ngroups <= 0)
5614 rb_raise(rb_eArgError, "maxgroups %d shold be positive", ngroups);
5615
5616 if (ngroups > RB_MAX_GROUPS)
5617 ngroups = RB_MAX_GROUPS;
5618
5619 if (ngroups_max > 0 && ngroups > ngroups_max)
5620 ngroups = ngroups_max;
5621
5622 _maxgroups = ngroups;
5623
5624 return INT2FIX(_maxgroups);
5625 }
5626 #else
5627 #define proc_setmaxgroups rb_f_notimplement
5628 #endif
5629
5630 #if defined(HAVE_DAEMON) || (defined(HAVE_FORK) && defined(HAVE_SETSID))
5631 static int rb_daemon(int nochdir, int noclose);
5632
5633 /*
5634 * call-seq:
5635 * Process.daemon() -> 0
5636 * Process.daemon(nochdir=nil,noclose=nil) -> 0
5637 *
5638 * Detach the process from controlling terminal and run in
5639 * the background as system daemon. Unless the argument
5640 * nochdir is true (i.e. non false), it changes the current
5641 * working directory to the root ("/"). Unless the argument
5642 * noclose is true, daemon() will redirect standard input,
5643 * standard output and standard error to /dev/null.
5644 * Return zero on success, or raise one of Errno::*.
5645 */
5646
5647 static VALUE
5648 proc_daemon(int argc, VALUE *argv)
5649 {
5650 VALUE nochdir, noclose;
5651 int n;
5652
5653 rb_secure(2);
5654 rb_scan_args(argc, argv, "02", &nochdir, &noclose);
5655
5656 prefork();
5657 n = rb_daemon(RTEST(nochdir), RTEST(noclose));
5658 if (n < 0) rb_sys_fail("daemon");
5659 return INT2FIX(n);
5660 }
5661
5662 static int
5663 rb_daemon(int nochdir, int noclose)
5664 {
5665 int err = 0;
5666 #ifdef HAVE_DAEMON
5667 before_fork();
5668 err = daemon(nochdir, noclose);
5669 after_fork();
5670 #else
5671 int n;
5672
5673 switch (rb_fork_ruby(NULL)) {
5674 case -1:
5675 rb_sys_fail("daemon");
5676 case 0:
5677 break;
5678 default:
5679 _exit(EXIT_SUCCESS);
5680 }
5681
5682 proc_setsid();
5683
5684 /* must not be process-leader */
5685 switch (rb_fork_ruby(NULL)) {
5686 case -1:
5687 return -1;
5688 case 0:
5689 break;
5690 default:
5691 _exit(EXIT_SUCCESS);
5692 }
5693
5694 if (!nochdir)
5695 err = chdir("/");
5696
5697 if (!noclose && (n = rb_cloexec_open("/dev/null", O_RDWR, 0)) != -1) {
5698 rb_update_max_fd(n);
5699 (void)dup2(n, 0);
5700 (void)dup2(n, 1);
5701 (void)dup2(n, 2);
5702 if (n > 2)
5703 (void)close (n);
5704 }
5705 #endif
5706 return err;
5707 }
5708 #else
5709 #define proc_daemon rb_f_notimplement
5710 #endif
5711
5712 /********************************************************************
5713 *
5714 * Document-class: Process::GID
5715 *
5716 * The <code>Process::GID</code> module contains a collection of
5717 * module functions which can be used to portably get, set, and
5718 * switch the current process's real, effective, and saved group IDs.
5719 *
5720 */
5721
5722 static rb_gid_t SAVED_GROUP_ID = -1;
5723
5724 #ifdef BROKEN_SETREGID
5725 int
5726 setregid(rb_gid_t rgid, rb_gid_t egid)
5727 {
5728 if (rgid != (rb_gid_t)-1 && rgid != getgid()) {
5729 if (egid == (rb_gid_t)-1) egid = getegid();
5730 if (setgid(rgid) < 0) return -1;
5731 }
5732 if (egid != (rb_gid_t)-1 && egid != getegid()) {
5733 if (setegid(egid) < 0) return -1;
5734 }
5735 return 0;
5736 }
5737 #endif
5738
5739 /*
5740 * call-seq:
5741 * Process::GID.change_privilege(group) -> fixnum
5742 *
5743 * Change the current process's real and effective group ID to that
5744 * specified by _group_. Returns the new group ID. Not
5745 * available on all platforms.
5746 *
5747 * [Process.gid, Process.egid] #=> [0, 0]
5748 * Process::GID.change_privilege(33) #=> 33
5749 * [Process.gid, Process.egid] #=> [33, 33]
5750 */
5751
5752 static VALUE
5753 p_gid_change_privilege(VALUE obj, VALUE id)
5754 {
5755 rb_gid_t gid;
5756 PREPARE_GETGRNAM;
5757
5758 check_gid_switch();
5759
5760 gid = OBJ2GID(id);
5761
5762 if (geteuid() == 0) { /* root-user */
5763 #if defined(HAVE_SETRESGID)
5764 if (setresgid(gid, gid, gid) < 0) rb_sys_fail(0);
5765 SAVED_GROUP_ID = gid;
5766 #elif defined HAVE_SETGID
5767 if (setgid(gid) < 0) rb_sys_fail(0);
5768 SAVED_GROUP_ID = gid;
5769 #elif defined(HAVE_SETREGID) && !defined(OBSOLETE_SETREGID)
5770 if (getgid() == gid) {
5771 if (SAVED_GROUP_ID == gid) {
5772 if (setregid(-1, gid) < 0) rb_sys_fail(0);
5773 }
5774 else {
5775 if (gid == 0) { /* (r,e,s) == (root, y, x) */
5776 if (setregid(-1, SAVED_GROUP_ID) < 0) rb_sys_fail(0);
5777 if (setregid(SAVED_GROUP_ID, 0) < 0) rb_sys_fail(0);
5778 SAVED_GROUP_ID = 0; /* (r,e,s) == (x, root, root) */
5779 if (setregid(gid, gid) < 0) rb_sys_fail(0);
5780 SAVED_GROUP_ID = gid;
5781 }
5782 else { /* (r,e,s) == (z, y, x) */
5783 if (setregid(0, 0) < 0) rb_sys_fail(0);
5784 SAVED_GROUP_ID = 0;
5785 if (setregid(gid, gid) < 0) rb_sys_fail(0);
5786 SAVED_GROUP_ID = gid;
5787 }
5788 }
5789 }
5790 else {
5791 if (setregid(gid, gid) < 0) rb_sys_fail(0);
5792 SAVED_GROUP_ID = gid;
5793 }
5794 #elif defined(HAVE_SETRGID) && defined (HAVE_SETEGID)
5795 if (getgid() == gid) {
5796 if (SAVED_GROUP_ID == gid) {
5797 if (setegid(gid) < 0) rb_sys_fail(0);
5798 }
5799 else {
5800 if (gid == 0) {
5801 if (setegid(gid) < 0) rb_sys_fail(0);
5802 if (setrgid(SAVED_GROUP_ID) < 0) rb_sys_fail(0);
5803 SAVED_GROUP_ID = 0;
5804 if (setrgid(0) < 0) rb_sys_fail(0);
5805 }
5806 else {
5807 if (setrgid(0) < 0) rb_sys_fail(0);
5808 SAVED_GROUP_ID = 0;
5809 if (setegid(gid) < 0) rb_sys_fail(0);
5810 if (setrgid(gid) < 0) rb_sys_fail(0);
5811 SAVED_GROUP_ID = gid;
5812 }
5813 }
5814 }
5815 else {
5816 if (setegid(gid) < 0) rb_sys_fail(0);
5817 if (setrgid(gid) < 0) rb_sys_fail(0);
5818 SAVED_GROUP_ID = gid;
5819 }
5820 #else
5821 rb_notimplement();
5822 #endif
5823 }
5824 else { /* unprivileged user */
5825 #if defined(HAVE_SETRESGID)
5826 if (setresgid((getgid() == gid)? (rb_gid_t)-1: gid,
5827 (getegid() == gid)? (rb_gid_t)-1: gid,
5828 (SAVED_GROUP_ID == gid)? (rb_gid_t)-1: gid) < 0) rb_sys_fail(0);
5829 SAVED_GROUP_ID = gid;
5830 #elif defined(HAVE_SETREGID) && !defined(OBSOLETE_SETREGID)
5831 if (SAVED_GROUP_ID == gid) {
5832 if (setregid((getgid() == gid)? (rb_uid_t)-1: gid,
5833 (getegid() == gid)? (rb_uid_t)-1: gid) < 0)
5834 rb_sys_fail(0);
5835 }
5836 else if (getgid() != gid) {
5837 if (setregid(gid, (getegid() == gid)? (rb_uid_t)-1: gid) < 0)
5838 rb_sys_fail(0);
5839 SAVED_GROUP_ID = gid;
5840 }
5841 else if (/* getgid() == gid && */ getegid() != gid) {
5842 if (setregid(getegid(), gid) < 0) rb_sys_fail(0);
5843 SAVED_GROUP_ID = gid;
5844 if (setregid(gid, -1) < 0) rb_sys_fail(0);
5845 }
5846 else { /* getgid() == gid && getegid() == gid */
5847 if (setregid(-1, SAVED_GROUP_ID) < 0) rb_sys_fail(0);
5848 if (setregid(SAVED_GROUP_ID, gid) < 0) rb_sys_fail(0);
5849 SAVED_GROUP_ID = gid;
5850 if (setregid(gid, -1) < 0) rb_sys_fail(0);
5851 }
5852 #elif defined(HAVE_SETRGID) && defined(HAVE_SETEGID)
5853 if (SAVED_GROUP_ID == gid) {
5854 if (getegid() != gid && setegid(gid) < 0) rb_sys_fail(0);
5855 if (getgid() != gid && setrgid(gid) < 0) rb_sys_fail(0);
5856 }
5857 else if (/* SAVED_GROUP_ID != gid && */ getegid() == gid) {
5858 if (getgid() != gid) {
5859 if (setrgid(gid) < 0) rb_sys_fail(0);
5860 SAVED_GROUP_ID = gid;
5861 }
5862 else {
5863 if (setrgid(SAVED_GROUP_ID) < 0) rb_sys_fail(0);
5864 SAVED_GROUP_ID = gid;
5865 if (setrgid(gid) < 0) rb_sys_fail(0);
5866 }
5867 }
5868 else if (/* getegid() != gid && */ getgid() == gid) {
5869 if (setegid(gid) < 0) rb_sys_fail(0);
5870 if (setrgid(SAVED_GROUP_ID) < 0) rb_sys_fail(0);
5871 SAVED_GROUP_ID = gid;
5872 if (setrgid(gid) < 0) rb_sys_fail(0);
5873 }
5874 else {
5875 errno = EPERM;
5876 rb_sys_fail(0);
5877 }
5878 #elif defined HAVE_44BSD_SETGID
5879 if (getgid() == gid) {
5880 /* (r,e,s)==(gid,?,?) ==> (gid,gid,gid) */
5881 if (setgid(gid) < 0) rb_sys_fail(0);
5882 SAVED_GROUP_ID = gid;
5883 }
5884 else {
5885 errno = EPERM;
5886 rb_sys_fail(0);
5887 }
5888 #elif defined HAVE_SETEGID
5889 if (getgid() == gid && SAVED_GROUP_ID == gid) {
5890 if (setegid(gid) < 0) rb_sys_fail(0);
5891 }
5892 else {
5893 errno = EPERM;
5894 rb_sys_fail(0);
5895 }
5896 #elif defined HAVE_SETGID
5897 if (getgid() == gid && SAVED_GROUP_ID == gid) {
5898 if (setgid(gid) < 0) rb_sys_fail(0);
5899 }
5900 else {
5901 errno = EPERM;
5902 rb_sys_fail(0);
5903 }
5904 #else
5905 (void)gid;
5906 rb_notimplement();
5907 #endif
5908 }
5909 return id;
5910 }
5911
5912
5913 /*
5914 * call-seq:
5915 * Process.euid -> fixnum
5916 * Process::UID.eid -> fixnum
5917 * Process::Sys.geteuid -> fixnum
5918 *
5919 * Returns the effective user ID for this process.
5920 *
5921 * Process.euid #=> 501
5922 */
5923
5924 static VALUE
5925 proc_geteuid(VALUE obj)
5926 {
5927 rb_uid_t euid = geteuid();
5928 return UIDT2NUM(euid);
5929 }
5930
5931 #if defined(HAVE_SETRESUID) || defined(HAVE_SETREUID) || defined(HAVE_SETEUID) || defined(HAVE_SETUID) || defined(_POSIX_SAVED_IDS)
5932 static void
5933 proc_seteuid(rb_uid_t uid)
5934 {
5935 #if defined(HAVE_SETRESUID)
5936 if (setresuid(-1, uid, -1) < 0) rb_sys_fail(0);
5937 #elif defined HAVE_SETREUID
5938 if (setreuid(-1, uid) < 0) rb_sys_fail(0);
5939 #elif defined HAVE_SETEUID
5940 if (seteuid(uid) < 0) rb_sys_fail(0);
5941 #elif defined HAVE_SETUID
5942 if (uid == getuid()) {
5943 if (setuid(uid) < 0) rb_sys_fail(0);
5944 }
5945 else {
5946 rb_notimplement();
5947 }
5948 #else
5949 rb_notimplement();
5950 #endif
5951 }
5952 #endif
5953
5954 #if defined(HAVE_SETRESUID) || defined(HAVE_SETREUID) || defined(HAVE_SETEUID) || defined(HAVE_SETUID)
5955 /*
5956 * call-seq:
5957 * Process.euid= user
5958 *
5959 * Sets the effective user ID for this process. Not available on all
5960 * platforms.
5961 */
5962
5963 static VALUE
5964 proc_seteuid_m(VALUE mod, VALUE euid)
5965 {
5966 PREPARE_GETPWNAM;
5967 check_uid_switch();
5968 proc_seteuid(OBJ2UID(euid));
5969 return euid;
5970 }
5971 #else
5972 #define proc_seteuid_m rb_f_notimplement
5973 #endif
5974
5975 static rb_uid_t
5976 rb_seteuid_core(rb_uid_t euid)
5977 {
5978 #if defined(HAVE_SETRESUID) || (defined(HAVE_SETREUID) && !defined(OBSOLETE_SETREUID))
5979 rb_uid_t uid;
5980 #endif
5981
5982 check_uid_switch();
5983
5984 #if defined(HAVE_SETRESUID) || (defined(HAVE_SETREUID) && !defined(OBSOLETE_SETREUID))
5985 uid = getuid();
5986 #endif
5987
5988 #if defined(HAVE_SETRESUID)
5989 if (uid != euid) {
5990 if (setresuid(-1,euid,euid) < 0) rb_sys_fail(0);
5991 SAVED_USER_ID = euid;
5992 }
5993 else {
5994 if (setresuid(-1,euid,-1) < 0) rb_sys_fail(0);
5995 }
5996 #elif defined(HAVE_SETREUID) && !defined(OBSOLETE_SETREUID)
5997 if (setreuid(-1, euid) < 0) rb_sys_fail(0);
5998 if (uid != euid) {
5999 if (setreuid(euid,uid) < 0) rb_sys_fail(0);
6000 if (setreuid(uid,euid) < 0) rb_sys_fail(0);
6001 SAVED_USER_ID = euid;
6002 }
6003 #elif defined HAVE_SETEUID
6004 if (seteuid(euid) < 0) rb_sys_fail(0);
6005 #elif defined HAVE_SETUID
6006 if (geteuid() == 0) rb_sys_fail(0);
6007 if (setuid(euid) < 0) rb_sys_fail(0);
6008 #else
6009 rb_notimplement();
6010 #endif
6011 return euid;
6012 }
6013
6014
6015 /*
6016 * call-seq:
6017 * Process::UID.grant_privilege(user) -> fixnum
6018 * Process::UID.eid= user -> fixnum
6019 *
6020 * Set the effective user ID, and if possible, the saved user ID of
6021 * the process to the given _user_. Returns the new
6022 * effective user ID. Not available on all platforms.
6023 *
6024 * [Process.uid, Process.euid] #=> [0, 0]
6025 * Process::UID.grant_privilege(31) #=> 31
6026 * [Process.uid, Process.euid] #=> [0, 31]
6027 */
6028
6029 static VALUE
6030 p_uid_grant_privilege(VALUE obj, VALUE id)
6031 {
6032 PREPARE_GETPWNAM;
6033 rb_seteuid_core(OBJ2UID(id));
6034 return id;
6035 }
6036
6037
6038 /*
6039 * call-seq:
6040 * Process.egid -> fixnum
6041 * Process::GID.eid -> fixnum
6042 * Process::Sys.geteid -> fixnum
6043 *
6044 * Returns the effective group ID for this process. Not available on
6045 * all platforms.
6046 *
6047 * Process.egid #=> 500
6048 */
6049
6050 static VALUE
6051 proc_getegid(VALUE obj)
6052 {
6053 rb_gid_t egid = getegid();
6054
6055 return GIDT2NUM(egid);
6056 }
6057
6058 #if defined(HAVE_SETRESGID) || defined(HAVE_SETREGID) || defined(HAVE_SETEGID) || defined(HAVE_SETGID) || defined(_POSIX_SAVED_IDS)
6059 /*
6060 * call-seq:
6061 * Process.egid = fixnum -> fixnum
6062 *
6063 * Sets the effective group ID for this process. Not available on all
6064 * platforms.
6065 */
6066
6067 static VALUE
6068 proc_setegid(VALUE obj, VALUE egid)
6069 {
6070 #if defined(HAVE_SETRESGID) || defined(HAVE_SETREGID) || defined(HAVE_SETEGID) || defined(HAVE_SETGID)
6071 rb_gid_t gid;
6072 PREPARE_GETGRNAM;
6073 #endif
6074
6075 check_gid_switch();
6076
6077 #if defined(HAVE_SETRESGID) || defined(HAVE_SETREGID) || defined(HAVE_SETEGID) || defined(HAVE_SETGID)
6078 gid = OBJ2GID(egid);
6079 #endif
6080
6081 #if defined(HAVE_SETRESGID)
6082 if (setresgid(-1, gid, -1) < 0) rb_sys_fail(0);
6083 #elif defined HAVE_SETREGID
6084 if (setregid(-1, gid) < 0) rb_sys_fail(0);
6085 #elif defined HAVE_SETEGID
6086 if (setegid(gid) < 0) rb_sys_fail(0);
6087 #elif defined HAVE_SETGID
6088 if (gid == getgid()) {
6089 if (setgid(gid) < 0) rb_sys_fail(0);
6090 }
6091 else {
6092 rb_notimplement();
6093 }
6094 #else
6095 rb_notimplement();
6096 #endif
6097 return egid;
6098 }
6099 #endif
6100
6101 #if defined(HAVE_SETRESGID) || defined(HAVE_SETREGID) || defined(HAVE_SETEGID) || defined(HAVE_SETGID)
6102 #define proc_setegid_m proc_setegid
6103 #else
6104 #define proc_setegid_m rb_f_notimplement
6105 #endif
6106
6107 static rb_gid_t
6108 rb_setegid_core(rb_gid_t egid)
6109 {
6110 #if defined(HAVE_SETRESGID) || (defined(HAVE_SETREGID) && !defined(OBSOLETE_SETREGID))
6111 rb_gid_t gid;
6112 #endif
6113
6114 check_gid_switch();
6115
6116 #if defined(HAVE_SETRESGID) || (defined(HAVE_SETREGID) && !defined(OBSOLETE_SETREGID))
6117 gid = getgid();
6118 #endif
6119
6120 #if defined(HAVE_SETRESGID)
6121 if (gid != egid) {
6122 if (setresgid(-1,egid,egid) < 0) rb_sys_fail(0);
6123 SAVED_GROUP_ID = egid;
6124 }
6125 else {
6126 if (setresgid(-1,egid,-1) < 0) rb_sys_fail(0);
6127 }
6128 #elif defined(HAVE_SETREGID) && !defined(OBSOLETE_SETREGID)
6129 if (setregid(-1, egid) < 0) rb_sys_fail(0);
6130 if (gid != egid) {
6131 if (setregid(egid,gid) < 0) rb_sys_fail(0);
6132 if (setregid(gid,egid) < 0) rb_sys_fail(0);
6133 SAVED_GROUP_ID = egid;
6134 }
6135 #elif defined HAVE_SETEGID
6136 if (setegid(egid) < 0) rb_sys_fail(0);
6137 #elif defined HAVE_SETGID
6138 if (geteuid() == 0 /* root user */) rb_sys_fail(0);
6139 if (setgid(egid) < 0) rb_sys_fail(0);
6140 #else
6141 rb_notimplement();
6142 #endif
6143 return egid;
6144 }
6145
6146
6147 /*
6148 * call-seq:
6149 * Process::GID.grant_privilege(group) -> fixnum
6150 * Process::GID.eid = group -> fixnum
6151 *
6152 * Set the effective group ID, and if possible, the saved group ID of
6153 * the process to the given _group_. Returns the new
6154 * effective group ID. Not available on all platforms.
6155 *
6156 * [Process.gid, Process.egid] #=> [0, 0]
6157 * Process::GID.grant_privilege(31) #=> 33
6158 * [Process.gid, Process.egid] #=> [0, 33]
6159 */
6160
6161 static VALUE
6162 p_gid_grant_privilege(VALUE obj, VALUE id)
6163 {
6164 PREPARE_GETGRNAM;
6165 rb_setegid_core(OBJ2GID(id));
6166 return id;
6167 }
6168
6169
6170 /*
6171 * call-seq:
6172 * Process::UID.re_exchangeable? -> true or false
6173 *
6174 * Returns +true+ if the real and effective user IDs of a
6175 * process may be exchanged on the current platform.
6176 *
6177 */
6178
6179 static VALUE
6180 p_uid_exchangeable(void)
6181 {
6182 #if defined(HAVE_SETRESUID)
6183 return Qtrue;
6184 #elif defined(HAVE_SETREUID) && !defined(OBSOLETE_SETREUID)
6185 return Qtrue;
6186 #else
6187 return Qfalse;
6188 #endif
6189 }
6190
6191
6192 /*
6193 * call-seq:
6194 * Process::UID.re_exchange -> fixnum
6195 *
6196 * Exchange real and effective user IDs and return the new effective
6197 * user ID. Not available on all platforms.
6198 *
6199 * [Process.uid, Process.euid] #=> [0, 31]
6200 * Process::UID.re_exchange #=> 0
6201 * [Process.uid, Process.euid] #=> [31, 0]
6202 */
6203
6204 static VALUE
6205 p_uid_exchange(VALUE obj)
6206 {
6207 rb_uid_t uid;
6208 #if defined(HAVE_SETRESUID) || (defined(HAVE_SETREUID) && !defined(OBSOLETE_SETREUID))
6209 rb_uid_t euid;
6210 #endif
6211
6212 check_uid_switch();
6213
6214 uid = getuid();
6215 #if defined(HAVE_SETRESUID) || (defined(HAVE_SETREUID) && !defined(OBSOLETE_SETREUID))
6216 euid = geteuid();
6217 #endif
6218
6219 #if defined(HAVE_SETRESUID)
6220 if (setresuid(euid, uid, uid) < 0) rb_sys_fail(0);
6221 SAVED_USER_ID = uid;
6222 #elif defined(HAVE_SETREUID) && !defined(OBSOLETE_SETREUID)
6223 if (setreuid(euid,uid) < 0) rb_sys_fail(0);
6224 SAVED_USER_ID = uid;
6225 #else
6226 rb_notimplement();
6227 #endif
6228 return UIDT2NUM(uid);
6229 }
6230
6231
6232 /*
6233 * call-seq:
6234 * Process::GID.re_exchangeable? -> true or false
6235 *
6236 * Returns +true+ if the real and effective group IDs of a
6237 * process may be exchanged on the current platform.
6238 *
6239 */
6240
6241 static VALUE
6242 p_gid_exchangeable(void)
6243 {
6244 #if defined(HAVE_SETRESGID)
6245 return Qtrue;
6246 #elif defined(HAVE_SETREGID) && !defined(OBSOLETE_SETREGID)
6247 return Qtrue;
6248 #else
6249 return Qfalse;
6250 #endif
6251 }
6252
6253
6254 /*
6255 * call-seq:
6256 * Process::GID.re_exchange -> fixnum
6257 *
6258 * Exchange real and effective group IDs and return the new effective
6259 * group ID. Not available on all platforms.
6260 *
6261 * [Process.gid, Process.egid] #=> [0, 33]
6262 * Process::GID.re_exchange #=> 0
6263 * [Process.gid, Process.egid] #=> [33, 0]
6264 */
6265
6266 static VALUE
6267 p_gid_exchange(VALUE obj)
6268 {
6269 rb_gid_t gid;
6270 #if defined(HAVE_SETRESGID) || (defined(HAVE_SETREGID) && !defined(OBSOLETE_SETREGID))
6271 rb_gid_t egid;
6272 #endif
6273
6274 check_gid_switch();
6275
6276 gid = getgid();
6277 #if defined(HAVE_SETRESGID) || (defined(HAVE_SETREGID) && !defined(OBSOLETE_SETREGID))
6278 egid = getegid();
6279 #endif
6280
6281 #if defined(HAVE_SETRESGID)
6282 if (setresgid(egid, gid, gid) < 0) rb_sys_fail(0);
6283 SAVED_GROUP_ID = gid;
6284 #elif defined(HAVE_SETREGID) && !defined(OBSOLETE_SETREGID)
6285 if (setregid(egid,gid) < 0) rb_sys_fail(0);
6286 SAVED_GROUP_ID = gid;
6287 #else
6288 rb_notimplement();
6289 #endif
6290 return GIDT2NUM(gid);
6291 }
6292
6293 /* [MG] :FIXME: Is this correct? I'm not sure how to phrase this. */
6294
6295 /*
6296 * call-seq:
6297 * Process::UID.sid_available? -> true or false
6298 *
6299 * Returns +true+ if the current platform has saved user
6300 * ID functionality.
6301 *
6302 */
6303
6304 static VALUE
6305 p_uid_have_saved_id(void)
6306 {
6307 #if defined(HAVE_SETRESUID) || defined(HAVE_SETEUID) || defined(_POSIX_SAVED_IDS)
6308 return Qtrue;
6309 #else
6310 return Qfalse;
6311 #endif
6312 }
6313
6314
6315 #if defined(HAVE_SETRESUID) || defined(HAVE_SETEUID) || defined(_POSIX_SAVED_IDS)
6316 static VALUE
6317 p_uid_sw_ensure(rb_uid_t id)
6318 {
6319 under_uid_switch = 0;
6320 id = rb_seteuid_core(id);
6321 return UIDT2NUM(id);
6322 }
6323
6324
6325 /*
6326 * call-seq:
6327 * Process::UID.switch -> fixnum
6328 * Process::UID.switch {|| block} -> object
6329 *
6330 * Switch the effective and real user IDs of the current process. If
6331 * a <em>block</em> is given, the user IDs will be switched back
6332 * after the block is executed. Returns the new effective user ID if
6333 * called without a block, and the return value of the block if one
6334 * is given.
6335 *
6336 */
6337
6338 static VALUE
6339 p_uid_switch(VALUE obj)
6340 {
6341 rb_uid_t uid, euid;
6342
6343 check_uid_switch();
6344
6345 uid = getuid();
6346 euid = geteuid();
6347
6348 if (uid != euid) {
6349 proc_seteuid(uid);
6350 if (rb_block_given_p()) {
6351 under_uid_switch = 1;
6352 return rb_ensure(rb_yield, Qnil, p_uid_sw_ensure, SAVED_USER_ID);
6353 }
6354 else {
6355 return UIDT2NUM(euid);
6356 }
6357 }
6358 else if (euid != SAVED_USER_ID) {
6359 proc_seteuid(SAVED_USER_ID);
6360 if (rb_block_given_p()) {
6361 under_uid_switch = 1;
6362 return rb_ensure(rb_yield, Qnil, p_uid_sw_ensure, euid);
6363 }
6364 else {
6365 return UIDT2NUM(uid);
6366 }
6367 }
6368 else {
6369 errno = EPERM;
6370 rb_sys_fail(0);
6371 }
6372
6373 UNREACHABLE;
6374 }
6375 #else
6376 static VALUE
6377 p_uid_sw_ensure(VALUE obj)
6378 {
6379 under_uid_switch = 0;
6380 return p_uid_exchange(obj);
6381 }
6382
6383 static VALUE
6384 p_uid_switch(VALUE obj)
6385 {
6386 rb_uid_t uid, euid;
6387
6388 check_uid_switch();
6389
6390 uid = getuid();
6391 euid = geteuid();
6392
6393 if (uid == euid) {
6394 errno = EPERM;
6395 rb_sys_fail(0);
6396 }
6397 p_uid_exchange(obj);
6398 if (rb_block_given_p()) {
6399 under_uid_switch = 1;
6400 return rb_ensure(rb_yield, Qnil, p_uid_sw_ensure, obj);
6401 }
6402 else {
6403 return UIDT2NUM(euid);
6404 }
6405 }
6406 #endif
6407
6408
6409 /* [MG] :FIXME: Is this correct? I'm not sure how to phrase this. */
6410
6411 /*
6412 * call-seq:
6413 * Process::GID.sid_available? -> true or false
6414 *
6415 * Returns +true+ if the current platform has saved group
6416 * ID functionality.
6417 *
6418 */
6419
6420 static VALUE
6421 p_gid_have_saved_id(void)
6422 {
6423 #if defined(HAVE_SETRESGID) || defined(HAVE_SETEGID) || defined(_POSIX_SAVED_IDS)
6424 return Qtrue;
6425 #else
6426 return Qfalse;
6427 #endif
6428 }
6429
6430 #if defined(HAVE_SETRESGID) || defined(HAVE_SETEGID) || defined(_POSIX_SAVED_IDS)
6431 static VALUE
6432 p_gid_sw_ensure(rb_gid_t id)
6433 {
6434 under_gid_switch = 0;
6435 id = rb_setegid_core(id);
6436 return GIDT2NUM(id);
6437 }
6438
6439
6440 /*
6441 * call-seq:
6442 * Process::GID.switch -> fixnum
6443 * Process::GID.switch {|| block} -> object
6444 *
6445 * Switch the effective and real group IDs of the current process. If
6446 * a <em>block</em> is given, the group IDs will be switched back
6447 * after the block is executed. Returns the new effective group ID if
6448 * called without a block, and the return value of the block if one
6449 * is given.
6450 *
6451 */
6452
6453 static VALUE
6454 p_gid_switch(VALUE obj)
6455 {
6456 rb_gid_t gid, egid;
6457
6458 check_gid_switch();
6459
6460 gid = getgid();
6461 egid = getegid();
6462
6463 if (gid != egid) {
6464 proc_setegid(obj, GIDT2NUM(gid));
6465 if (rb_block_given_p()) {
6466 under_gid_switch = 1;
6467 return rb_ensure(rb_yield, Qnil, p_gid_sw_ensure, SAVED_GROUP_ID);
6468 }
6469 else {
6470 return GIDT2NUM(egid);
6471 }
6472 }
6473 else if (egid != SAVED_GROUP_ID) {
6474 proc_setegid(obj, GIDT2NUM(SAVED_GROUP_ID));
6475 if (rb_block_given_p()) {
6476 under_gid_switch = 1;
6477 return rb_ensure(rb_yield, Qnil, p_gid_sw_ensure, egid);
6478 }
6479 else {
6480 return GIDT2NUM(gid);
6481 }
6482 }
6483 else {
6484 errno = EPERM;
6485 rb_sys_fail(0);
6486 }
6487
6488 UNREACHABLE;
6489 }
6490 #else
6491 static VALUE
6492 p_gid_sw_ensure(VALUE obj)
6493 {
6494 under_gid_switch = 0;
6495 return p_gid_exchange(obj);
6496 }
6497
6498 static VALUE
6499 p_gid_switch(VALUE obj)
6500 {
6501 rb_gid_t gid, egid;
6502
6503 check_gid_switch();
6504
6505 gid = getgid();
6506 egid = getegid();
6507
6508 if (gid == egid) {
6509 errno = EPERM;
6510 rb_sys_fail(0);
6511 }
6512 p_gid_exchange(obj);
6513 if (rb_block_given_p()) {
6514 under_gid_switch = 1;
6515 return rb_ensure(rb_yield, Qnil, p_gid_sw_ensure, obj);
6516 }
6517 else {
6518 return GIDT2NUM(egid);
6519 }
6520 }
6521 #endif
6522
6523
6524 #if defined(HAVE_TIMES)
6525 /*
6526 * call-seq:
6527 * Process.times -> aStructTms
6528 *
6529 * Returns a <code>Tms</code> structure (see <code>Struct::Tms</code>)
6530 * that contains user and system CPU times for this process,
6531 * and also for children processes.
6532 *
6533 * t = Process.times
6534 * [ t.utime, t.stime, t.cutime, t.cstime ] #=> [0.0, 0.02, 0.00, 0.00]
6535 */
6536
6537 VALUE
6538 rb_proc_times(VALUE obj)
6539 {
6540 const double hertz =
6541 #ifdef HAVE__SC_CLK_TCK
6542 (double)sysconf(_SC_CLK_TCK);
6543 #else
6544 #ifndef HZ
6545 # ifdef CLK_TCK
6546 # define HZ CLK_TCK
6547 # else
6548 # define HZ 60
6549 # endif
6550 #endif /* HZ */
6551 HZ;
6552 #endif
6553 struct tms buf;
6554 volatile VALUE utime, stime, cutime, sctime;
6555
6556 times(&buf);
6557 return rb_struct_new(rb_cProcessTms,
6558 utime = DBL2NUM(buf.tms_utime / hertz),
6559 stime = DBL2NUM(buf.tms_stime / hertz),
6560 cutime = DBL2NUM(buf.tms_cutime / hertz),
6561 sctime = DBL2NUM(buf.tms_cstime / hertz));
6562 }
6563 #else
6564 #define rb_proc_times rb_f_notimplement
6565 #endif
6566
6567 VALUE rb_mProcess;
6568 VALUE rb_mProcUID;
6569 VALUE rb_mProcGID;
6570 VALUE rb_mProcID_Syscall;
6571
6572
6573 /*
6574 * The <code>Process</code> module is a collection of methods used to
6575 * manipulate processes.
6576 */
6577
6578 void
6579 Init_process(void)
6580 {
6581 rb_define_virtual_variable("$?", rb_last_status_get, 0);
6582 rb_define_virtual_variable("$$", get_pid, 0);
6583 rb_define_global_function("exec", rb_f_exec, -1);
6584 rb_define_global_function("fork", rb_f_fork, 0);
6585 rb_define_global_function("exit!", rb_f_exit_bang, -1);
6586 rb_define_global_function("system", rb_f_system, -1);
6587 rb_define_global_function("spawn", rb_f_spawn, -1);
6588 rb_define_global_function("sleep", rb_f_sleep, -1);
6589 rb_define_global_function("exit", rb_f_exit, -1);
6590 rb_define_global_function("abort", rb_f_abort, -1);
6591
6592 rb_mProcess = rb_define_module("Process");
6593
6594 #ifdef WNOHANG
6595 /* see Process.wait */
6596 rb_define_const(rb_mProcess, "WNOHANG", INT2FIX(WNOHANG));
6597 #else
6598 /* see Process.wait */
6599 rb_define_const(rb_mProcess, "WNOHANG", INT2FIX(0));
6600 #endif
6601 #ifdef WUNTRACED
6602 /* see Process.wait */
6603 rb_define_const(rb_mProcess, "WUNTRACED", INT2FIX(WUNTRACED));
6604 #else
6605 /* see Process.wait */
6606 rb_define_const(rb_mProcess, "WUNTRACED", INT2FIX(0));
6607 #endif
6608
6609 rb_define_singleton_method(rb_mProcess, "exec", rb_f_exec, -1);
6610 rb_define_singleton_method(rb_mProcess, "fork", rb_f_fork, 0);
6611 rb_define_singleton_method(rb_mProcess, "spawn", rb_f_spawn, -1);
6612 rb_define_singleton_method(rb_mProcess, "exit!", rb_f_exit_bang, -1);
6613 rb_define_singleton_method(rb_mProcess, "exit", rb_f_exit, -1);
6614 rb_define_singleton_method(rb_mProcess, "abort", rb_f_abort, -1);
6615
6616 rb_define_module_function(rb_mProcess, "kill", rb_f_kill, -1); /* in signal.c */
6617 rb_define_module_function(rb_mProcess, "wait", proc_wait, -1);
6618 rb_define_module_function(rb_mProcess, "wait2", proc_wait2, -1);
6619 rb_define_module_function(rb_mProcess, "waitpid", proc_wait, -1);
6620 rb_define_module_function(rb_mProcess, "waitpid2", proc_wait2, -1);
6621 rb_define_module_function(rb_mProcess, "waitall", proc_waitall, 0);
6622 rb_define_module_function(rb_mProcess, "detach", proc_detach, 1);
6623
6624 rb_cProcessStatus = rb_define_class_under(rb_mProcess, "Status", rb_cObject);
6625 rb_undef_method(CLASS_OF(rb_cProcessStatus), "new");
6626
6627 rb_define_method(rb_cProcessStatus, "==", pst_equal, 1);
6628 rb_define_method(rb_cProcessStatus, "&", pst_bitand, 1);
6629 rb_define_method(rb_cProcessStatus, ">>", pst_rshift, 1);
6630 rb_define_method(rb_cProcessStatus, "to_i", pst_to_i, 0);
6631 rb_define_method(rb_cProcessStatus, "to_s", pst_to_s, 0);
6632 rb_define_method(rb_cProcessStatus, "inspect", pst_inspect, 0);
6633
6634 rb_define_method(rb_cProcessStatus, "pid", pst_pid, 0);
6635
6636 rb_define_method(rb_cProcessStatus, "stopped?", pst_wifstopped, 0);
6637 rb_define_method(rb_cProcessStatus, "stopsig", pst_wstopsig, 0);
6638 rb_define_method(rb_cProcessStatus, "signaled?", pst_wifsignaled, 0);
6639 rb_define_method(rb_cProcessStatus, "termsig", pst_wtermsig, 0);
6640 rb_define_method(rb_cProcessStatus, "exited?", pst_wifexited, 0);
6641 rb_define_method(rb_cProcessStatus, "exitstatus", pst_wexitstatus, 0);
6642 rb_define_method(rb_cProcessStatus, "success?", pst_success_p, 0);
6643 rb_define_method(rb_cProcessStatus, "coredump?", pst_wcoredump, 0);
6644
6645 rb_define_module_function(rb_mProcess, "pid", get_pid, 0);
6646 rb_define_module_function(rb_mProcess, "ppid", get_ppid, 0);
6647
6648 rb_define_module_function(rb_mProcess, "getpgrp", proc_getpgrp, 0);
6649 rb_define_module_function(rb_mProcess, "setpgrp", proc_setpgrp, 0);
6650 rb_define_module_function(rb_mProcess, "getpgid", proc_getpgid, 1);
6651 rb_define_module_function(rb_mProcess, "setpgid", proc_setpgid, 2);
6652
6653 rb_define_module_function(rb_mProcess, "getsid", proc_getsid, -1);
6654 rb_define_module_function(rb_mProcess, "setsid", proc_setsid, 0);
6655
6656 rb_define_module_function(rb_mProcess, "getpriority", proc_getpriority, 2);
6657 rb_define_module_function(rb_mProcess, "setpriority", proc_setpriority, 3);
6658
6659 #ifdef HAVE_GETPRIORITY
6660 /* see Process.setpriority */
6661 rb_define_const(rb_mProcess, "PRIO_PROCESS", INT2FIX(PRIO_PROCESS));
6662 /* see Process.setpriority */
6663 rb_define_const(rb_mProcess, "PRIO_PGRP", INT2FIX(PRIO_PGRP));
6664 /* see Process.setpriority */
6665 rb_define_const(rb_mProcess, "PRIO_USER", INT2FIX(PRIO_USER));
6666 #endif
6667
6668 rb_define_module_function(rb_mProcess, "getrlimit", proc_getrlimit, 1);
6669 rb_define_module_function(rb_mProcess, "setrlimit", proc_setrlimit, -1);
6670 #if defined(RLIM2NUM) && defined(RLIM_INFINITY)
6671 {
6672 VALUE inf = RLIM2NUM(RLIM_INFINITY);
6673 #ifdef RLIM_SAVED_MAX
6674 {
6675 VALUE v = RLIM_INFINITY == RLIM_SAVED_MAX ? inf : RLIM2NUM(RLIM_SAVED_MAX);
6676 /* see Process.setrlimit */
6677 rb_define_const(rb_mProcess, "RLIM_SAVED_MAX", v);
6678 }
6679 #endif
6680 /* see Process.setrlimit */
6681 rb_define_const(rb_mProcess, "RLIM_INFINITY", inf);
6682 #ifdef RLIM_SAVED_CUR
6683 {
6684 VALUE v = RLIM_INFINITY == RLIM_SAVED_CUR ? inf : RLIM2NUM(RLIM_SAVED_CUR);
6685 /* see Process.setrlimit */
6686 rb_define_const(rb_mProcess, "RLIM_SAVED_CUR", v);
6687 }
6688 #endif
6689 }
6690 #ifdef RLIMIT_AS
6691 /* Maximum size of the process's virtual memory (address space) in bytes.
6692 *
6693 * see the system getrlimit(2) manual for details.
6694 */
6695 rb_define_const(rb_mProcess, "RLIMIT_AS", INT2FIX(RLIMIT_AS));
6696 #endif
6697 #ifdef RLIMIT_CORE
6698 /* Maximum size of the core file.
6699 *
6700 * see the system getrlimit(2) manual for details.
6701 */
6702 rb_define_const(rb_mProcess, "RLIMIT_CORE", INT2FIX(RLIMIT_CORE));
6703 #endif
6704 #ifdef RLIMIT_CPU
6705 /* CPU time limit in seconds.
6706 *
6707 * see the system getrlimit(2) manual for details.
6708 */
6709 rb_define_const(rb_mProcess, "RLIMIT_CPU", INT2FIX(RLIMIT_CPU));
6710 #endif
6711 #ifdef RLIMIT_DATA
6712 /* Maximum size of the process's data segment.
6713 *
6714 * see the system getrlimit(2) manual for details.
6715 */
6716 rb_define_const(rb_mProcess, "RLIMIT_DATA", INT2FIX(RLIMIT_DATA));
6717 #endif
6718 #ifdef RLIMIT_FSIZE
6719 /* Maximum size of files that the process may create.
6720 *
6721 * see the system getrlimit(2) manual for details.
6722 */
6723 rb_define_const(rb_mProcess, "RLIMIT_FSIZE", INT2FIX(RLIMIT_FSIZE));
6724 #endif
6725 #ifdef RLIMIT_MEMLOCK
6726 /* Maximum number of bytes of memory that may be locked into RAM.
6727 *
6728 * see the system getrlimit(2) manual for details.
6729 */
6730 rb_define_const(rb_mProcess, "RLIMIT_MEMLOCK", INT2FIX(RLIMIT_MEMLOCK));
6731 #endif
6732 #ifdef RLIMIT_MSGQUEUE
6733 /* Specifies the limit on the number of bytes that can be allocated
6734 * for POSIX message queues for the real user ID of the calling process.
6735 *
6736 * see the system getrlimit(2) manual for details.
6737 */
6738 rb_define_const(rb_mProcess, "RLIMIT_MSGQUEUE", INT2FIX(RLIMIT_MSGQUEUE));
6739 #endif
6740 #ifdef RLIMIT_NICE
6741 /* Specifies a ceiling to which the process's nice value can be raised.
6742 *
6743 * see the system getrlimit(2) manual for details.
6744 */
6745 rb_define_const(rb_mProcess, "RLIMIT_NICE", INT2FIX(RLIMIT_NICE));
6746 #endif
6747 #ifdef RLIMIT_NOFILE
6748 /* Specifies a value one greater than the maximum file descriptor
6749 * number that can be opened by this process.
6750 *
6751 * see the system getrlimit(2) manual for details.
6752 */
6753 rb_define_const(rb_mProcess, "RLIMIT_NOFILE", INT2FIX(RLIMIT_NOFILE));
6754 #endif
6755 #ifdef RLIMIT_NPROC
6756 /* The maximum number of processes that can be created for the
6757 * real user ID of the calling process.
6758 *
6759 * see the system getrlimit(2) manual for details.
6760 */
6761 rb_define_const(rb_mProcess, "RLIMIT_NPROC", INT2FIX(RLIMIT_NPROC));
6762 #endif
6763 #ifdef RLIMIT_RSS
6764 /* Specifies the limit (in pages) of the process's resident set.
6765 *
6766 * see the system getrlimit(2) manual for details.
6767 */
6768 rb_define_const(rb_mProcess, "RLIMIT_RSS", INT2FIX(RLIMIT_RSS));
6769 #endif
6770 #ifdef RLIMIT_RTPRIO
6771 /* Specifies a ceiling on the real-time priority that may be set for this process.
6772 *
6773 * see the system getrlimit(2) manual for details.
6774 */
6775 rb_define_const(rb_mProcess, "RLIMIT_RTPRIO", INT2FIX(RLIMIT_RTPRIO));
6776 #endif
6777 #ifdef RLIMIT_RTTIME
6778 /* Specifies limit on CPU time this process scheduled under a real-time
6779 * scheduling policy can consume.
6780 *
6781 * see the system getrlimit(2) manual for details.
6782 */
6783 rb_define_const(rb_mProcess, "RLIMIT_RTTIME", INT2FIX(RLIMIT_RTTIME));
6784 #endif
6785 #ifdef RLIMIT_SBSIZE
6786 /* Maximum size of the socket buffer.
6787 */
6788 rb_define_const(rb_mProcess, "RLIMIT_SBSIZE", INT2FIX(RLIMIT_SBSIZE));
6789 #endif
6790 #ifdef RLIMIT_SIGPENDING
6791 /* Specifies a limit on the number of signals that may be queued for
6792 * the real user ID of the calling process.
6793 *
6794 * see the system getrlimit(2) manual for details.
6795 */
6796 rb_define_const(rb_mProcess, "RLIMIT_SIGPENDING", INT2FIX(RLIMIT_SIGPENDING));
6797 #endif
6798 #ifdef RLIMIT_STACK
6799 /* Maximum size of the stack, in bytes.
6800 *
6801 * see the system getrlimit(2) manual for details.
6802 */
6803 rb_define_const(rb_mProcess, "RLIMIT_STACK", INT2FIX(RLIMIT_STACK));
6804 #endif
6805 #endif
6806
6807 rb_define_module_function(rb_mProcess, "uid", proc_getuid, 0);
6808 rb_define_module_function(rb_mProcess, "uid=", proc_setuid, 1);
6809 rb_define_module_function(rb_mProcess, "gid", proc_getgid, 0);
6810 rb_define_module_function(rb_mProcess, "gid=", proc_setgid, 1);
6811 rb_define_module_function(rb_mProcess, "euid", proc_geteuid, 0);
6812 rb_define_module_function(rb_mProcess, "euid=", proc_seteuid_m, 1);
6813 rb_define_module_function(rb_mProcess, "egid", proc_getegid, 0);
6814 rb_define_module_function(rb_mProcess, "egid=", proc_setegid_m, 1);
6815 rb_define_module_function(rb_mProcess, "initgroups", proc_initgroups, 2);
6816 rb_define_module_function(rb_mProcess, "groups", proc_getgroups, 0);
6817 rb_define_module_function(rb_mProcess, "groups=", proc_setgroups, 1);
6818 rb_define_module_function(rb_mProcess, "maxgroups", proc_getmaxgroups, 0);
6819 rb_define_module_function(rb_mProcess, "maxgroups=", proc_setmaxgroups, 1);
6820
6821 rb_define_module_function(rb_mProcess, "daemon", proc_daemon, -1);
6822
6823 rb_define_module_function(rb_mProcess, "times", rb_proc_times, 0);
6824
6825 #if defined(HAVE_TIMES) || defined(_WIN32)
6826 rb_cProcessTms = rb_struct_define("Tms", "utime", "stime", "cutime", "cstime", NULL);
6827 #endif
6828
6829 SAVED_USER_ID = geteuid();
6830 SAVED_GROUP_ID = getegid();
6831
6832 rb_mProcUID = rb_define_module_under(rb_mProcess, "UID");
6833 rb_mProcGID = rb_define_module_under(rb_mProcess, "GID");
6834
6835 rb_define_module_function(rb_mProcUID, "rid", proc_getuid, 0);
6836 rb_define_module_function(rb_mProcGID, "rid", proc_getgid, 0);
6837 rb_define_module_function(rb_mProcUID, "eid", proc_geteuid, 0);
6838 rb_define_module_function(rb_mProcGID, "eid", proc_getegid, 0);
6839 rb_define_module_function(rb_mProcUID, "change_privilege", p_uid_change_privilege, 1);
6840 rb_define_module_function(rb_mProcGID, "change_privilege", p_gid_change_privilege, 1);
6841 rb_define_module_function(rb_mProcUID, "grant_privilege", p_uid_grant_privilege, 1);
6842 rb_define_module_function(rb_mProcGID, "grant_privilege", p_gid_grant_privilege, 1);
6843 rb_define_alias(rb_singleton_class(rb_mProcUID), "eid=", "grant_privilege");
6844 rb_define_alias(rb_singleton_class(rb_mProcGID), "eid=", "grant_privilege");
6845 rb_define_module_function(rb_mProcUID, "re_exchange", p_uid_exchange, 0);
6846 rb_define_module_function(rb_mProcGID, "re_exchange", p_gid_exchange, 0);
6847 rb_define_module_function(rb_mProcUID, "re_exchangeable?", p_uid_exchangeable, 0);
6848 rb_define_module_function(rb_mProcGID, "re_exchangeable?", p_gid_exchangeable, 0);
6849 rb_define_module_function(rb_mProcUID, "sid_available?", p_uid_have_saved_id, 0);
6850 rb_define_module_function(rb_mProcGID, "sid_available?", p_gid_have_saved_id, 0);
6851 rb_define_module_function(rb_mProcUID, "switch", p_uid_switch, 0);
6852 rb_define_module_function(rb_mProcGID, "switch", p_gid_switch, 0);
6853 #ifdef p_uid_from_name
6854 rb_define_module_function(rb_mProcUID, "from_name", p_uid_from_name, 1);
6855 #endif
6856 #ifdef p_gid_from_name
6857 rb_define_module_function(rb_mProcGID, "from_name", p_gid_from_name, 1);
6858 #endif
6859
6860 rb_mProcID_Syscall = rb_define_module_under(rb_mProcess, "Sys");
6861
6862 rb_define_module_function(rb_mProcID_Syscall, "getuid", proc_getuid, 0);
6863 rb_define_module_function(rb_mProcID_Syscall, "geteuid", proc_geteuid, 0);
6864 rb_define_module_function(rb_mProcID_Syscall, "getgid", proc_getgid, 0);
6865 rb_define_module_function(rb_mProcID_Syscall, "getegid", proc_getegid, 0);
6866
6867 rb_define_module_function(rb_mProcID_Syscall, "setuid", p_sys_setuid, 1);
6868 rb_define_module_function(rb_mProcID_Syscall, "setgid", p_sys_setgid, 1);
6869
6870 rb_define_module_function(rb_mProcID_Syscall, "setruid", p_sys_setruid, 1);
6871 rb_define_module_function(rb_mProcID_Syscall, "setrgid", p_sys_setrgid, 1);
6872
6873 rb_define_module_function(rb_mProcID_Syscall, "seteuid", p_sys_seteuid, 1);
6874 rb_define_module_function(rb_mProcID_Syscall, "setegid", p_sys_setegid, 1);
6875
6876 rb_define_module_function(rb_mProcID_Syscall, "setreuid", p_sys_setreuid, 2);
6877 rb_define_module_function(rb_mProcID_Syscall, "setregid", p_sys_setregid, 2);
6878
6879 rb_define_module_function(rb_mProcID_Syscall, "setresuid", p_sys_setresuid, 3);
6880 rb_define_module_function(rb_mProcID_Syscall, "setresgid", p_sys_setresgid, 3);
6881 rb_define_module_function(rb_mProcID_Syscall, "issetugid", p_sys_issetugid, 0);
6882 }
6883