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