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