Ruby  2.0.0p353(2013-11-22revision43784)
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 {
278  rb_thread_t *th = GET_THREAD();
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
1318 mark_exec_arg(void *ptr)
1319 {
1320  struct rb_execarg *eargp = ptr;
1321  if (eargp->use_shell)
1322  rb_gc_mark(eargp->invoke.sh.shell_script);
1323  else {
1324  rb_gc_mark(eargp->invoke.cmd.command_name);
1325  rb_gc_mark(eargp->invoke.cmd.command_abspath);
1326  rb_gc_mark(eargp->invoke.cmd.argv_str);
1327  rb_gc_mark(eargp->invoke.cmd.argv_buf);
1328  }
1329  rb_gc_mark(eargp->redirect_fds);
1330  rb_gc_mark(eargp->envp_str);
1331  rb_gc_mark(eargp->envp_buf);
1332  rb_gc_mark(eargp->dup2_tmpbuf);
1333  rb_gc_mark(eargp->rlimit_limits);
1334  rb_gc_mark(eargp->fd_dup2);
1335  rb_gc_mark(eargp->fd_close);
1336  rb_gc_mark(eargp->fd_open);
1337  rb_gc_mark(eargp->fd_dup2_child);
1338  rb_gc_mark(eargp->env_modification);
1339  rb_gc_mark(eargp->chdir_dir);
1340 }
1341 
1342 static void
1343 free_exec_arg(void *ptr)
1344 {
1345  xfree(ptr);
1346 }
1347 
1348 static size_t
1349 memsize_exec_arg(const void *ptr)
1350 {
1351  return ptr ? sizeof(struct rb_execarg) : 0;
1352 }
1353 
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
3012 rb_run_exec_options(const struct rb_exec_arg *e, struct rb_exec_arg *s)
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  pid = retry_fork(status, ep, chfunc_is_async_signal_safe);
3332  if (pid < 0)
3333  return pid;
3334  if (!pid) {
3335  int ret;
3336  forked_child = 1;
3337  close(ep[0]);
3338  if (chfunc_is_async_signal_safe)
3339  ret = chfunc(charg, errmsg, errmsg_buflen);
3340  else {
3341  struct chfunc_protect_t arg;
3342  arg.chfunc = chfunc;
3343  arg.arg = charg;
3344  arg.errmsg = errmsg;
3345  arg.buflen = errmsg_buflen;
3346  ret = (int)rb_protect(chfunc_protect, (VALUE)&arg, &state);
3347  }
3348  if (!ret) _exit(EXIT_SUCCESS);
3349  send_child_error(ep[1], state, errmsg, errmsg_buflen, chfunc_is_async_signal_safe);
3350 #if EXIT_SUCCESS == 127
3351  _exit(EXIT_FAILURE);
3352 #else
3353  _exit(127);
3354 #endif
3355  }
3356  close(ep[1]);
3357  error_occured = recv_child_error(ep[0], &state, &exc, &err, errmsg, errmsg_buflen, chfunc_is_async_signal_safe);
3358  if (state || error_occured) {
3359  if (status) {
3360  rb_protect(proc_syswait, (VALUE)pid, status);
3361  if (state) *status = state;
3362  }
3363  else {
3364  rb_syswait(pid);
3365  if (state) rb_exc_raise(exc);
3366  }
3367  errno = err;
3368  return -1;
3369  }
3370  return pid;
3371  }
3372 }
3373 
3374 rb_pid_t
3375 rb_fork_err(int *status, int (*chfunc)(void*, char *, size_t), void *charg, VALUE fds,
3376  char *errmsg, size_t errmsg_buflen)
3377 {
3378  return rb_fork_internal(status, chfunc, charg, FALSE, fds, errmsg, errmsg_buflen);
3379 }
3380 
3381 rb_pid_t
3382 rb_fork_async_signal_safe(int *status, int (*chfunc)(void*, char *, size_t), void *charg, VALUE fds,
3383  char *errmsg, size_t errmsg_buflen)
3384 {
3385  return rb_fork_internal(status, chfunc, charg, TRUE, fds, errmsg, errmsg_buflen);
3386 }
3387 
3388 struct chfunc_wrapper_t {
3389  int (*chfunc)(void*);
3390  void *arg;
3391 };
3392 
3393 static int
3394 chfunc_wrapper(void *arg_, char *errmsg, size_t errmsg_buflen)
3395 {
3396  struct chfunc_wrapper_t *arg = arg_;
3397  return arg->chfunc(arg->arg);
3398 }
3399 
3400 rb_pid_t
3401 rb_fork(int *status, int (*chfunc)(void*), void *charg, VALUE fds)
3402 {
3403  if (chfunc) {
3404  struct chfunc_wrapper_t warg;
3405  warg.chfunc = chfunc;
3406  warg.arg = charg;
3407  return rb_fork_internal(status, chfunc_wrapper, &warg, FALSE, fds, NULL, 0);
3408  }
3409  else {
3410  return rb_fork_internal(status, NULL, NULL, FALSE, fds, NULL, 0);
3411  }
3412 
3413 }
3414 
3415 rb_pid_t
3416 rb_fork_ruby(int *status)
3417 {
3418  return rb_fork_internal(status, NULL, NULL, FALSE, Qnil, NULL, 0);
3419 }
3420 
3421 #endif
3422 
3423 #if defined(HAVE_FORK) && !defined(CANNOT_FORK_WITH_PTHREAD)
3424 /*
3425  * call-seq:
3426  * Kernel.fork [{ block }] -> fixnum or nil
3427  * Process.fork [{ block }] -> fixnum or nil
3428  *
3429  * Creates a subprocess. If a block is specified, that block is run
3430  * in the subprocess, and the subprocess terminates with a status of
3431  * zero. Otherwise, the +fork+ call returns twice, once in
3432  * the parent, returning the process ID of the child, and once in
3433  * the child, returning _nil_. The child process can exit using
3434  * <code>Kernel.exit!</code> to avoid running any
3435  * <code>at_exit</code> functions. The parent process should
3436  * use <code>Process.wait</code> to collect the termination statuses
3437  * of its children or use <code>Process.detach</code> to register
3438  * disinterest in their status; otherwise, the operating system
3439  * may accumulate zombie processes.
3440  *
3441  * The thread calling fork is the only thread in the created child process.
3442  * fork doesn't copy other threads.
3443  *
3444  * If fork is not usable, Process.respond_to?(:fork) returns false.
3445  */
3446 
3447 static VALUE
3448 rb_f_fork(VALUE obj)
3449 {
3450  rb_pid_t pid;
3451 
3452  rb_secure(2);
3453 
3454  switch (pid = rb_fork_ruby(NULL)) {
3455  case 0:
3456  rb_thread_atfork();
3457  if (rb_block_given_p()) {
3458  int status;
3459 
3460  rb_protect(rb_yield, Qundef, &status);
3461  ruby_stop(status);
3462  }
3463  return Qnil;
3464 
3465  case -1:
3466  rb_sys_fail("fork(2)");
3467  return Qnil;
3468 
3469  default:
3470  return PIDT2NUM(pid);
3471  }
3472 }
3473 #else
3474 #define rb_f_fork rb_f_notimplement
3475 #endif
3476 
3477 static int
3479 {
3480  int istatus;
3481 
3482  switch (status) {
3483  case Qtrue:
3484  istatus = EXIT_SUCCESS;
3485  break;
3486  case Qfalse:
3487  istatus = EXIT_FAILURE;
3488  break;
3489  default:
3490  istatus = NUM2INT(status);
3491 #if EXIT_SUCCESS != 0
3492  if (istatus == 0)
3493  istatus = EXIT_SUCCESS;
3494 #endif
3495  break;
3496  }
3497  return istatus;
3498 }
3499 
3500 /*
3501  * call-seq:
3502  * Process.exit!(status=false)
3503  *
3504  * Exits the process immediately. No exit handlers are
3505  * run. <em>status</em> is returned to the underlying system as the
3506  * exit status.
3507  *
3508  * Process.exit!(true)
3509  */
3510 
3511 static VALUE
3512 rb_f_exit_bang(int argc, VALUE *argv, VALUE obj)
3513 {
3514  VALUE status;
3515  int istatus;
3516 
3517  rb_secure(4);
3518  if (argc > 0 && rb_scan_args(argc, argv, "01", &status) == 1) {
3519  istatus = exit_status_code(status);
3520  }
3521  else {
3522  istatus = EXIT_FAILURE;
3523  }
3524  _exit(istatus);
3525 
3526  UNREACHABLE;
3527 }
3528 
3529 void
3530 rb_exit(int status)
3531 {
3532  if (GET_THREAD()->tag) {
3533  VALUE args[2];
3534 
3535  args[0] = INT2NUM(status);
3536  args[1] = rb_str_new2("exit");
3538  }
3539  ruby_finalize();
3540  exit(status);
3541 }
3542 
3543 
3544 /*
3545  * call-seq:
3546  * exit(status=true)
3547  * Kernel::exit(status=true)
3548  * Process::exit(status=true)
3549  *
3550  * Initiates the termination of the Ruby script by raising the
3551  * <code>SystemExit</code> exception. This exception may be caught. The
3552  * optional parameter is used to return a status code to the invoking
3553  * environment.
3554  * +true+ and +FALSE+ of _status_ means success and failure
3555  * respectively. The interpretation of other integer values are
3556  * system dependent.
3557  *
3558  * begin
3559  * exit
3560  * puts "never get here"
3561  * rescue SystemExit
3562  * puts "rescued a SystemExit exception"
3563  * end
3564  * puts "after begin block"
3565  *
3566  * <em>produces:</em>
3567  *
3568  * rescued a SystemExit exception
3569  * after begin block
3570  *
3571  * Just prior to termination, Ruby executes any <code>at_exit</code> functions
3572  * (see Kernel::at_exit) and runs any object finalizers (see
3573  * ObjectSpace::define_finalizer).
3574  *
3575  * at_exit { puts "at_exit function" }
3576  * ObjectSpace.define_finalizer("string", proc { puts "in finalizer" })
3577  * exit
3578  *
3579  * <em>produces:</em>
3580  *
3581  * at_exit function
3582  * in finalizer
3583  */
3584 
3585 VALUE
3586 rb_f_exit(int argc, VALUE *argv)
3587 {
3588  VALUE status;
3589  int istatus;
3590 
3591  rb_secure(4);
3592  if (argc > 0 && rb_scan_args(argc, argv, "01", &status) == 1) {
3593  istatus = exit_status_code(status);
3594  }
3595  else {
3596  istatus = EXIT_SUCCESS;
3597  }
3598  rb_exit(istatus);
3599 
3600  UNREACHABLE;
3601 }
3602 
3603 
3604 /*
3605  * call-seq:
3606  * abort
3607  * Kernel::abort([msg])
3608  * Process::abort([msg])
3609  *
3610  * Terminate execution immediately, effectively by calling
3611  * <code>Kernel.exit(false)</code>. If _msg_ is given, it is written
3612  * to STDERR prior to terminating.
3613  */
3614 
3615 VALUE
3616 rb_f_abort(int argc, VALUE *argv)
3617 {
3618  rb_secure(4);
3619  if (argc == 0) {
3620  if (!NIL_P(GET_THREAD()->errinfo)) {
3621  ruby_error_print();
3622  }
3624  }
3625  else {
3626  VALUE args[2];
3627 
3628  rb_scan_args(argc, argv, "1", &args[1]);
3629  StringValue(argv[0]);
3630  rb_io_puts(argc, argv, rb_stderr);
3631  args[0] = INT2NUM(EXIT_FAILURE);
3633  }
3634 
3635  UNREACHABLE;
3636 }
3637 
3638 void
3639 rb_syswait(rb_pid_t pid)
3640 {
3641  int status;
3642 
3643  rb_waitpid(pid, &status, 0);
3644 }
3645 
3646 static rb_pid_t
3647 rb_spawn_process(struct rb_execarg *eargp, char *errmsg, size_t errmsg_buflen)
3648 {
3649  rb_pid_t pid;
3650 #if !USE_SPAWNV
3651  int status;
3652 #endif
3653 #if !defined HAVE_FORK || USE_SPAWNV
3654  VALUE prog;
3655  struct rb_execarg sarg;
3656 #endif
3657 
3658 #if defined HAVE_FORK && !USE_SPAWNV
3659  pid = rb_fork_async_signal_safe(&status, rb_exec_atfork, eargp, eargp->redirect_fds, errmsg, errmsg_buflen);
3660 #else
3661  prog = eargp->use_shell ? eargp->invoke.sh.shell_script : eargp->invoke.cmd.command_name;
3662 
3663  if (rb_execarg_run_options(eargp, &sarg, errmsg, errmsg_buflen) < 0) {
3664  return -1;
3665  }
3666 
3667  if (prog && !eargp->use_shell) {
3668  char **argv = ARGVSTR2ARGV(eargp->invoke.cmd.argv_str);
3669  argv[0] = RSTRING_PTR(prog);
3670  }
3671 # if defined HAVE_SPAWNV
3672  if (eargp->use_shell) {
3673  pid = proc_spawn_sh(RSTRING_PTR(prog));
3674  }
3675  else {
3676  char **argv = ARGVSTR2ARGV(eargp->invoke.cmd.argv_str);
3677  pid = proc_spawn_cmd(argv, prog, eargp);
3678  }
3679 # if defined(_WIN32)
3680  if (pid == -1)
3681  rb_last_status_set(0x7f << 8, 0);
3682 # endif
3683 # else
3684  if (!eargp->use_shell) {
3685  char **argv = ARGVSTR2ARGV(eargp->invoke.cmd.argv_str);
3686  int argc = ARGVSTR2ARGC(eargp->invoke.cmd.argv_str);
3687  prog = rb_ary_join(rb_ary_new4(argc, argv), rb_str_new2(" "));
3688  }
3689  status = system(StringValuePtr(prog));
3690  rb_last_status_set((status & 0xff) << 8, 0);
3691 # endif
3692 
3693  rb_execarg_run_options(&sarg, NULL, errmsg, errmsg_buflen);
3694 #endif
3695  return pid;
3696 }
3697 
3698 static rb_pid_t
3699 rb_spawn_internal(int argc, VALUE *argv, char *errmsg, size_t errmsg_buflen)
3700 {
3701  VALUE execarg_obj;
3702  struct rb_execarg *eargp;
3703  rb_pid_t ret;
3704 
3705  execarg_obj = rb_execarg_new(argc, argv, TRUE);
3706  eargp = rb_execarg_get(execarg_obj);
3707  rb_execarg_fixup(execarg_obj);
3708  ret = rb_spawn_process(eargp, errmsg, errmsg_buflen);
3709  RB_GC_GUARD(execarg_obj);
3710  return ret;
3711 }
3712 
3713 rb_pid_t
3714 rb_spawn_err(int argc, VALUE *argv, char *errmsg, size_t errmsg_buflen)
3715 {
3716  return rb_spawn_internal(argc, argv, errmsg, errmsg_buflen);
3717 }
3718 
3719 rb_pid_t
3720 rb_spawn(int argc, VALUE *argv)
3721 {
3722  return rb_spawn_internal(argc, argv, NULL, 0);
3723 }
3724 
3725 /*
3726  * call-seq:
3727  * system([env,] command... [,options]) -> true, false or nil
3728  *
3729  * Executes _command..._ in a subshell.
3730  * _command..._ is one of following forms.
3731  *
3732  * commandline : command line string which is passed to the standard shell
3733  * cmdname, arg1, ... : command name and one or more arguments (no shell)
3734  * [cmdname, argv0], arg1, ... : command name, argv[0] and zero or more arguments (no shell)
3735  *
3736  * system returns +true+ if the command gives zero exit status,
3737  * +false+ for non zero exit status.
3738  * Returns +nil+ if command execution fails.
3739  * An error status is available in <code>$?</code>.
3740  * The arguments are processed in the same way as
3741  * for <code>Kernel.spawn</code>.
3742  *
3743  * The hash arguments, env and options, are same as
3744  * <code>exec</code> and <code>spawn</code>.
3745  * See <code>Kernel.spawn</code> for details.
3746  *
3747  * system("echo *")
3748  * system("echo", "*")
3749  *
3750  * <em>produces:</em>
3751  *
3752  * config.h main.rb
3753  * *
3754  *
3755  * See <code>Kernel.exec</code> for the standard shell.
3756  */
3757 
3758 static VALUE
3760 {
3761  rb_pid_t pid;
3762  int status;
3763 
3764 #if defined(SIGCLD) && !defined(SIGCHLD)
3765 # define SIGCHLD SIGCLD
3766 #endif
3767 
3768 #ifdef SIGCHLD
3769  RETSIGTYPE (*chfunc)(int);
3770 
3772  chfunc = signal(SIGCHLD, SIG_DFL);
3773 #endif
3774  pid = rb_spawn_internal(argc, argv, NULL, 0);
3775 #if defined(HAVE_FORK) || defined(HAVE_SPAWNV)
3776  if (pid > 0) {
3777  int ret, status;
3778  ret = rb_waitpid(pid, &status, 0);
3779  if (ret == (rb_pid_t)-1)
3780  rb_sys_fail("Another thread waited the process started by system().");
3781  }
3782 #endif
3783 #ifdef SIGCHLD
3784  signal(SIGCHLD, chfunc);
3785 #endif
3786  if (pid < 0) {
3787  return Qnil;
3788  }
3789  status = PST2INT(rb_last_status_get());
3790  if (status == EXIT_SUCCESS) return Qtrue;
3791  return Qfalse;
3792 }
3793 
3794 /*
3795  * call-seq:
3796  * spawn([env,] command... [,options]) -> pid
3797  * Process.spawn([env,] command... [,options]) -> pid
3798  *
3799  * spawn executes specified command and return its pid.
3800  *
3801  * This method doesn't wait for end of the command.
3802  * The parent process should
3803  * use <code>Process.wait</code> to collect
3804  * the termination status of its child or
3805  * use <code>Process.detach</code> to register
3806  * disinterest in their status;
3807  * otherwise, the operating system may accumulate zombie processes.
3808  *
3809  * spawn has bunch of options to specify process attributes:
3810  *
3811  * env: hash
3812  * name => val : set the environment variable
3813  * name => nil : unset the environment variable
3814  * command...:
3815  * commandline : command line string which is passed to the standard shell
3816  * cmdname, arg1, ... : command name and one or more arguments (no shell)
3817  * [cmdname, argv0], arg1, ... : command name, argv[0] and zero or more arguments (no shell)
3818  * options: hash
3819  * clearing environment variables:
3820  * :unsetenv_others => true : clear environment variables except specified by env
3821  * :unsetenv_others => false : don't clear (default)
3822  * process group:
3823  * :pgroup => true or 0 : make a new process group
3824  * :pgroup => pgid : join to specified process group
3825  * :pgroup => nil : don't change the process group (default)
3826  * create new process group: Windows only
3827  * :new_pgroup => true : the new process is the root process of a new process group
3828  * :new_pgroup => false : don't create a new process group (default)
3829  * resource limit: resourcename is core, cpu, data, etc. See Process.setrlimit.
3830  * :rlimit_resourcename => limit
3831  * :rlimit_resourcename => [cur_limit, max_limit]
3832  * umask:
3833  * :umask => int
3834  * redirection:
3835  * key:
3836  * FD : single file descriptor in child process
3837  * [FD, FD, ...] : multiple file descriptor in child process
3838  * value:
3839  * FD : redirect to the file descriptor in parent process
3840  * string : redirect to file with open(string, "r" or "w")
3841  * [string] : redirect to file with open(string, File::RDONLY)
3842  * [string, open_mode] : redirect to file with open(string, open_mode, 0644)
3843  * [string, open_mode, perm] : redirect to file with open(string, open_mode, perm)
3844  * [:child, FD] : redirect to the redirected file descriptor
3845  * :close : close the file descriptor in child process
3846  * FD is one of follows
3847  * :in : the file descriptor 0 which is the standard input
3848  * :out : the file descriptor 1 which is the standard output
3849  * :err : the file descriptor 2 which is the standard error
3850  * integer : the file descriptor of specified the integer
3851  * io : the file descriptor specified as io.fileno
3852  * file descriptor inheritance: close non-redirected non-standard fds (3, 4, 5, ...) or not
3853  * :close_others => true : don't inherit
3854  * current directory:
3855  * :chdir => str
3856  *
3857  * If a hash is given as +env+, the environment is
3858  * updated by +env+ before <code>exec(2)</code> in the child process.
3859  * If a pair in +env+ has nil as the value, the variable is deleted.
3860  *
3861  * # set FOO as BAR and unset BAZ.
3862  * pid = spawn({"FOO"=>"BAR", "BAZ"=>nil}, command)
3863  *
3864  * If a hash is given as +options+,
3865  * it specifies
3866  * process group,
3867  * create new process group,
3868  * resource limit,
3869  * current directory,
3870  * umask and
3871  * redirects for the child process.
3872  * Also, it can be specified to clear environment variables.
3873  *
3874  * The <code>:unsetenv_others</code> key in +options+ specifies
3875  * to clear environment variables, other than specified by +env+.
3876  *
3877  * pid = spawn(command, :unsetenv_others=>true) # no environment variable
3878  * pid = spawn({"FOO"=>"BAR"}, command, :unsetenv_others=>true) # FOO only
3879  *
3880  * The <code>:pgroup</code> key in +options+ specifies a process group.
3881  * The corresponding value should be true, zero or positive integer.
3882  * true and zero means the process should be a process leader of a new
3883  * process group.
3884  * Other values specifies a process group to be belongs.
3885  *
3886  * pid = spawn(command, :pgroup=>true) # process leader
3887  * pid = spawn(command, :pgroup=>10) # belongs to the process group 10
3888  *
3889  * The <code>:new_pgroup</code> key in +options+ specifies to pass
3890  * +CREATE_NEW_PROCESS_GROUP+ flag to <code>CreateProcessW()</code> that is
3891  * Windows API. This option is only for Windows.
3892  * true means the new process is the root process of the new process group.
3893  * The new process has CTRL+C disabled. This flag is necessary for
3894  * <code>Process.kill(:SIGINT, pid)</code> on the subprocess.
3895  * :new_pgroup is false by default.
3896  *
3897  * pid = spawn(command, :new_pgroup=>true) # new process group
3898  * pid = spawn(command, :new_pgroup=>false) # same process group
3899  *
3900  * The <code>:rlimit_</code><em>foo</em> key specifies a resource limit.
3901  * <em>foo</em> should be one of resource types such as <code>core</code>.
3902  * The corresponding value should be an integer or an array which have one or
3903  * two integers: same as cur_limit and max_limit arguments for
3904  * Process.setrlimit.
3905  *
3906  * cur, max = Process.getrlimit(:CORE)
3907  * pid = spawn(command, :rlimit_core=>[0,max]) # disable core temporary.
3908  * pid = spawn(command, :rlimit_core=>max) # enable core dump
3909  * pid = spawn(command, :rlimit_core=>0) # never dump core.
3910  *
3911  * The <code>:umask</code> key in +options+ specifies the umask.
3912  *
3913  * pid = spawn(command, :umask=>077)
3914  *
3915  * The :in, :out, :err, a fixnum, an IO and an array key specifies a redirection.
3916  * The redirection maps a file descriptor in the child process.
3917  *
3918  * For example, stderr can be merged into stdout as follows:
3919  *
3920  * pid = spawn(command, :err=>:out)
3921  * pid = spawn(command, 2=>1)
3922  * pid = spawn(command, STDERR=>:out)
3923  * pid = spawn(command, STDERR=>STDOUT)
3924  *
3925  * The hash keys specifies a file descriptor
3926  * in the child process started by <code>spawn</code>.
3927  * :err, 2 and STDERR specifies the standard error stream (stderr).
3928  *
3929  * The hash values specifies a file descriptor
3930  * in the parent process which invokes <code>spawn</code>.
3931  * :out, 1 and STDOUT specifies the standard output stream (stdout).
3932  *
3933  * In the above example,
3934  * the standard output in the child process is not specified.
3935  * So it is inherited from the parent process.
3936  *
3937  * The standard input stream (stdin) can be specified by :in, 0 and STDIN.
3938  *
3939  * A filename can be specified as a hash value.
3940  *
3941  * pid = spawn(command, :in=>"/dev/null") # read mode
3942  * pid = spawn(command, :out=>"/dev/null") # write mode
3943  * pid = spawn(command, :err=>"log") # write mode
3944  * pid = spawn(command, 3=>"/dev/null") # read mode
3945  *
3946  * For stdout and stderr,
3947  * it is opened in write mode.
3948  * Otherwise read mode is used.
3949  *
3950  * For specifying flags and permission of file creation explicitly,
3951  * an array is used instead.
3952  *
3953  * pid = spawn(command, :in=>["file"]) # read mode is assumed
3954  * pid = spawn(command, :in=>["file", "r"])
3955  * pid = spawn(command, :out=>["log", "w"]) # 0644 assumed
3956  * pid = spawn(command, :out=>["log", "w", 0600])
3957  * pid = spawn(command, :out=>["log", File::WRONLY|File::EXCL|File::CREAT, 0600])
3958  *
3959  * The array specifies a filename, flags and permission.
3960  * The flags can be a string or an integer.
3961  * If the flags is omitted or nil, File::RDONLY is assumed.
3962  * The permission should be an integer.
3963  * If the permission is omitted or nil, 0644 is assumed.
3964  *
3965  * If an array of IOs and integers are specified as a hash key,
3966  * all the elements are redirected.
3967  *
3968  * # stdout and stderr is redirected to log file.
3969  * # The file "log" is opened just once.
3970  * pid = spawn(command, [:out, :err]=>["log", "w"])
3971  *
3972  * Another way to merge multiple file descriptors is [:child, fd].
3973  * \[:child, fd] means the file descriptor in the child process.
3974  * This is different from fd.
3975  * For example, :err=>:out means redirecting child stderr to parent stdout.
3976  * But :err=>[:child, :out] means redirecting child stderr to child stdout.
3977  * They differ if stdout is redirected in the child process as follows.
3978  *
3979  * # stdout and stderr is redirected to log file.
3980  * # The file "log" is opened just once.
3981  * pid = spawn(command, :out=>["log", "w"], :err=>[:child, :out])
3982  *
3983  * \[:child, :out] can be used to merge stderr into stdout in IO.popen.
3984  * In this case, IO.popen redirects stdout to a pipe in the child process
3985  * and [:child, :out] refers the redirected stdout.
3986  *
3987  * io = IO.popen(["sh", "-c", "echo out; echo err >&2", :err=>[:child, :out]])
3988  * p io.read #=> "out\nerr\n"
3989  *
3990  * The <code>:chdir</code> key in +options+ specifies the current directory.
3991  *
3992  * pid = spawn(command, :chdir=>"/var/tmp")
3993  *
3994  * spawn closes all non-standard unspecified descriptors by default.
3995  * The "standard" descriptors are 0, 1 and 2.
3996  * This behavior is specified by :close_others option.
3997  * :close_others doesn't affect the standard descriptors which are
3998  * closed only if :close is specified explicitly.
3999  *
4000  * pid = spawn(command, :close_others=>true) # close 3,4,5,... (default)
4001  * pid = spawn(command, :close_others=>false) # don't close 3,4,5,...
4002  *
4003  * :close_others is true by default for spawn and IO.popen.
4004  *
4005  * Note that fds which close-on-exec flag is already set are closed
4006  * regardless of :close_others option.
4007  *
4008  * So IO.pipe and spawn can be used as IO.popen.
4009  *
4010  * # similar to r = IO.popen(command)
4011  * r, w = IO.pipe
4012  * pid = spawn(command, :out=>w) # r, w is closed in the child process.
4013  * w.close
4014  *
4015  * :close is specified as a hash value to close a fd individually.
4016  *
4017  * f = open(foo)
4018  * system(command, f=>:close) # don't inherit f.
4019  *
4020  * If a file descriptor need to be inherited,
4021  * io=>io can be used.
4022  *
4023  * # valgrind has --log-fd option for log destination.
4024  * # log_w=>log_w indicates log_w.fileno inherits to child process.
4025  * log_r, log_w = IO.pipe
4026  * pid = spawn("valgrind", "--log-fd=#{log_w.fileno}", "echo", "a", log_w=>log_w)
4027  * log_w.close
4028  * p log_r.read
4029  *
4030  * It is also possible to exchange file descriptors.
4031  *
4032  * pid = spawn(command, :out=>:err, :err=>:out)
4033  *
4034  * The hash keys specify file descriptors in the child process.
4035  * The hash values specifies file descriptors in the parent process.
4036  * So the above specifies exchanging stdout and stderr.
4037  * Internally, +spawn+ uses an extra file descriptor to resolve such cyclic
4038  * file descriptor mapping.
4039  *
4040  * See <code>Kernel.exec</code> for the standard shell.
4041  */
4042 
4043 static VALUE
4044 rb_f_spawn(int argc, VALUE *argv)
4045 {
4046  rb_pid_t pid;
4047  char errmsg[CHILD_ERRMSG_BUFLEN] = { '\0' };
4048  VALUE execarg_obj, fail_str;
4049  struct rb_execarg *eargp;
4050 
4051  execarg_obj = rb_execarg_new(argc, argv, TRUE);
4052  eargp = rb_execarg_get(execarg_obj);
4053  rb_execarg_fixup(execarg_obj);
4054  fail_str = eargp->use_shell ? eargp->invoke.sh.shell_script : eargp->invoke.cmd.command_name;
4055 
4056  pid = rb_spawn_process(eargp, errmsg, sizeof(errmsg));
4057  RB_GC_GUARD(execarg_obj);
4058 
4059  if (pid == -1) {
4060  const char *prog = errmsg;
4061  if (!prog[0]) {
4062  rb_sys_fail_str(fail_str);
4063  }
4064  rb_sys_fail(prog);
4065  }
4066 #if defined(HAVE_FORK) || defined(HAVE_SPAWNV)
4067  return PIDT2NUM(pid);
4068 #else
4069  return Qnil;
4070 #endif
4071 }
4072 
4073 /*
4074  * call-seq:
4075  * sleep([duration]) -> fixnum
4076  *
4077  * Suspends the current thread for _duration_ seconds (which may be any number,
4078  * including a +Float+ with fractional seconds). Returns the actual number of
4079  * seconds slept (rounded), which may be less than that asked for if another
4080  * thread calls <code>Thread#run</code>. Called without an argument, sleep()
4081  * will sleep forever.
4082  *
4083  * Time.new #=> 2008-03-08 19:56:19 +0900
4084  * sleep 1.2 #=> 1
4085  * Time.new #=> 2008-03-08 19:56:20 +0900
4086  * sleep 1.9 #=> 2
4087  * Time.new #=> 2008-03-08 19:56:22 +0900
4088  */
4089 
4090 static VALUE
4091 rb_f_sleep(int argc, VALUE *argv)
4092 {
4093  time_t beg, end;
4094 
4095  beg = time(0);
4096  if (argc == 0) {
4098  }
4099  else {
4100  rb_check_arity(argc, 0, 1);
4102  }
4103 
4104  end = time(0) - beg;
4105 
4106  return INT2FIX(end);
4107 }
4108 
4109 
4110 #if (defined(HAVE_GETPGRP) && defined(GETPGRP_VOID)) || defined(HAVE_GETPGID)
4111 /*
4112  * call-seq:
4113  * Process.getpgrp -> integer
4114  *
4115  * Returns the process group ID for this process. Not available on
4116  * all platforms.
4117  *
4118  * Process.getpgid(0) #=> 25527
4119  * Process.getpgrp #=> 25527
4120  */
4121 
4122 static VALUE
4123 proc_getpgrp(void)
4124 {
4125  rb_pid_t pgrp;
4126 
4127  rb_secure(2);
4128 #if defined(HAVE_GETPGRP) && defined(GETPGRP_VOID)
4129  pgrp = getpgrp();
4130  if (pgrp < 0) rb_sys_fail(0);
4131  return PIDT2NUM(pgrp);
4132 #else /* defined(HAVE_GETPGID) */
4133  pgrp = getpgid(0);
4134  if (pgrp < 0) rb_sys_fail(0);
4135  return PIDT2NUM(pgrp);
4136 #endif
4137 }
4138 #else
4139 #define proc_getpgrp rb_f_notimplement
4140 #endif
4141 
4142 
4143 #if defined(HAVE_SETPGID) || (defined(HAVE_SETPGRP) && defined(SETPGRP_VOID))
4144 /*
4145  * call-seq:
4146  * Process.setpgrp -> 0
4147  *
4148  * Equivalent to <code>setpgid(0,0)</code>. Not available on all
4149  * platforms.
4150  */
4151 
4152 static VALUE
4153 proc_setpgrp(void)
4154 {
4155  rb_secure(2);
4156  /* check for posix setpgid() first; this matches the posix */
4157  /* getpgrp() above. It appears that configure will set SETPGRP_VOID */
4158  /* even though setpgrp(0,0) would be preferred. The posix call avoids */
4159  /* this confusion. */
4160 #ifdef HAVE_SETPGID
4161  if (setpgid(0,0) < 0) rb_sys_fail(0);
4162 #elif defined(HAVE_SETPGRP) && defined(SETPGRP_VOID)
4163  if (setpgrp() < 0) rb_sys_fail(0);
4164 #endif
4165  return INT2FIX(0);
4166 }
4167 #else
4168 #define proc_setpgrp rb_f_notimplement
4169 #endif
4170 
4171 
4172 #if defined(HAVE_GETPGID)
4173 /*
4174  * call-seq:
4175  * Process.getpgid(pid) -> integer
4176  *
4177  * Returns the process group ID for the given process id. Not
4178  * available on all platforms.
4179  *
4180  * Process.getpgid(Process.ppid()) #=> 25527
4181  */
4182 
4183 static VALUE
4184 proc_getpgid(VALUE obj, VALUE pid)
4185 {
4186  rb_pid_t i;
4187 
4188  rb_secure(2);
4189  i = getpgid(NUM2PIDT(pid));
4190  if (i < 0) rb_sys_fail(0);
4191  return PIDT2NUM(i);
4192 }
4193 #else
4194 #define proc_getpgid rb_f_notimplement
4195 #endif
4196 
4197 
4198 #ifdef HAVE_SETPGID
4199 /*
4200  * call-seq:
4201  * Process.setpgid(pid, integer) -> 0
4202  *
4203  * Sets the process group ID of _pid_ (0 indicates this
4204  * process) to <em>integer</em>. Not available on all platforms.
4205  */
4206 
4207 static VALUE
4208 proc_setpgid(VALUE obj, VALUE pid, VALUE pgrp)
4209 {
4210  rb_pid_t ipid, ipgrp;
4211 
4212  rb_secure(2);
4213  ipid = NUM2PIDT(pid);
4214  ipgrp = NUM2PIDT(pgrp);
4215 
4216  if (setpgid(ipid, ipgrp) < 0) rb_sys_fail(0);
4217  return INT2FIX(0);
4218 }
4219 #else
4220 #define proc_setpgid rb_f_notimplement
4221 #endif
4222 
4223 
4224 #ifdef HAVE_GETSID
4225 /*
4226  * call-seq:
4227  * Process.getsid() -> integer
4228  * Process.getsid(pid) -> integer
4229  *
4230  * Returns the session ID for for the given process id. If not give,
4231  * return current process sid. Not available on all platforms.
4232  *
4233  * Process.getsid() #=> 27422
4234  * Process.getsid(0) #=> 27422
4235  * Process.getsid(Process.pid()) #=> 27422
4236  */
4237 static VALUE
4238 proc_getsid(int argc, VALUE *argv)
4239 {
4240  rb_pid_t sid;
4241  VALUE pid;
4242 
4243  rb_secure(2);
4244  rb_scan_args(argc, argv, "01", &pid);
4245 
4246  if (NIL_P(pid))
4247  pid = INT2NUM(0);
4248 
4249  sid = getsid(NUM2PIDT(pid));
4250  if (sid < 0) rb_sys_fail(0);
4251  return PIDT2NUM(sid);
4252 }
4253 #else
4254 #define proc_getsid rb_f_notimplement
4255 #endif
4256 
4257 
4258 #if defined(HAVE_SETSID) || (defined(HAVE_SETPGRP) && defined(TIOCNOTTY))
4259 #if !defined(HAVE_SETSID)
4260 static rb_pid_t ruby_setsid(void);
4261 #define setsid() ruby_setsid()
4262 #endif
4263 /*
4264  * call-seq:
4265  * Process.setsid -> fixnum
4266  *
4267  * Establishes this process as a new session and process group
4268  * leader, with no controlling tty. Returns the session id. Not
4269  * available on all platforms.
4270  *
4271  * Process.setsid #=> 27422
4272  */
4273 
4274 static VALUE
4275 proc_setsid(void)
4276 {
4277  rb_pid_t pid;
4278 
4279  rb_secure(2);
4280  pid = setsid();
4281  if (pid < 0) rb_sys_fail(0);
4282  return PIDT2NUM(pid);
4283 }
4284 
4285 #if !defined(HAVE_SETSID)
4286 #define HAVE_SETSID 1
4287 static rb_pid_t
4288 ruby_setsid(void)
4289 {
4290  rb_pid_t pid;
4291  int ret;
4292 
4293  pid = getpid();
4294 #if defined(SETPGRP_VOID)
4295  ret = setpgrp();
4296  /* If `pid_t setpgrp(void)' is equivalent to setsid(),
4297  `ret' will be the same value as `pid', and following open() will fail.
4298  In Linux, `int setpgrp(void)' is equivalent to setpgid(0, 0). */
4299 #else
4300  ret = setpgrp(0, pid);
4301 #endif
4302  if (ret == -1) return -1;
4303 
4304  if ((fd = rb_cloexec_open("/dev/tty", O_RDWR, 0)) >= 0) {
4305  rb_update_max_fd(fd);
4306  ioctl(fd, TIOCNOTTY, NULL);
4307  close(fd);
4308  }
4309  return pid;
4310 }
4311 #endif
4312 #else
4313 #define proc_setsid rb_f_notimplement
4314 #endif
4315 
4316 
4317 #ifdef HAVE_GETPRIORITY
4318 /*
4319  * call-seq:
4320  * Process.getpriority(kind, integer) -> fixnum
4321  *
4322  * Gets the scheduling priority for specified process, process group,
4323  * or user. <em>kind</em> indicates the kind of entity to find: one
4324  * of <code>Process::PRIO_PGRP</code>,
4325  * <code>Process::PRIO_USER</code>, or
4326  * <code>Process::PRIO_PROCESS</code>. _integer_ is an id
4327  * indicating the particular process, process group, or user (an id
4328  * of 0 means _current_). Lower priorities are more favorable
4329  * for scheduling. Not available on all platforms.
4330  *
4331  * Process.getpriority(Process::PRIO_USER, 0) #=> 19
4332  * Process.getpriority(Process::PRIO_PROCESS, 0) #=> 19
4333  */
4334 
4335 static VALUE
4336 proc_getpriority(VALUE obj, VALUE which, VALUE who)
4337 {
4338  int prio, iwhich, iwho;
4339 
4340  rb_secure(2);
4341  iwhich = NUM2INT(which);
4342  iwho = NUM2INT(who);
4343 
4344  errno = 0;
4345  prio = getpriority(iwhich, iwho);
4346  if (errno) rb_sys_fail(0);
4347  return INT2FIX(prio);
4348 }
4349 #else
4350 #define proc_getpriority rb_f_notimplement
4351 #endif
4352 
4353 
4354 #ifdef HAVE_GETPRIORITY
4355 /*
4356  * call-seq:
4357  * Process.setpriority(kind, integer, priority) -> 0
4358  *
4359  * See <code>Process#getpriority</code>.
4360  *
4361  * Process.setpriority(Process::PRIO_USER, 0, 19) #=> 0
4362  * Process.setpriority(Process::PRIO_PROCESS, 0, 19) #=> 0
4363  * Process.getpriority(Process::PRIO_USER, 0) #=> 19
4364  * Process.getpriority(Process::PRIO_PROCESS, 0) #=> 19
4365  */
4366 
4367 static VALUE
4368 proc_setpriority(VALUE obj, VALUE which, VALUE who, VALUE prio)
4369 {
4370  int iwhich, iwho, iprio;
4371 
4372  rb_secure(2);
4373  iwhich = NUM2INT(which);
4374  iwho = NUM2INT(who);
4375  iprio = NUM2INT(prio);
4376 
4377  if (setpriority(iwhich, iwho, iprio) < 0)
4378  rb_sys_fail(0);
4379  return INT2FIX(0);
4380 }
4381 #else
4382 #define proc_setpriority rb_f_notimplement
4383 #endif
4384 
4385 #if defined(HAVE_SETRLIMIT) && defined(NUM2RLIM)
4386 static int
4387 rlimit_resource_name2int(const char *name, int casetype)
4388 {
4389  int resource;
4390  const char *p;
4391 #define RESCHECK(r) \
4392  do { \
4393  if (STRCASECMP(name, #r) == 0) { \
4394  resource = RLIMIT_##r; \
4395  goto found; \
4396  } \
4397  } while (0)
4398 
4399  switch (TOUPPER(*name)) {
4400  case 'A':
4401 #ifdef RLIMIT_AS
4402  RESCHECK(AS);
4403 #endif
4404  break;
4405 
4406  case 'C':
4407 #ifdef RLIMIT_CORE
4408  RESCHECK(CORE);
4409 #endif
4410 #ifdef RLIMIT_CPU
4411  RESCHECK(CPU);
4412 #endif
4413  break;
4414 
4415  case 'D':
4416 #ifdef RLIMIT_DATA
4417  RESCHECK(DATA);
4418 #endif
4419  break;
4420 
4421  case 'F':
4422 #ifdef RLIMIT_FSIZE
4423  RESCHECK(FSIZE);
4424 #endif
4425  break;
4426 
4427  case 'M':
4428 #ifdef RLIMIT_MEMLOCK
4429  RESCHECK(MEMLOCK);
4430 #endif
4431 #ifdef RLIMIT_MSGQUEUE
4432  RESCHECK(MSGQUEUE);
4433 #endif
4434  break;
4435 
4436  case 'N':
4437 #ifdef RLIMIT_NOFILE
4438  RESCHECK(NOFILE);
4439 #endif
4440 #ifdef RLIMIT_NPROC
4441  RESCHECK(NPROC);
4442 #endif
4443 #ifdef RLIMIT_NICE
4444  RESCHECK(NICE);
4445 #endif
4446  break;
4447 
4448  case 'R':
4449 #ifdef RLIMIT_RSS
4450  RESCHECK(RSS);
4451 #endif
4452 #ifdef RLIMIT_RTPRIO
4453  RESCHECK(RTPRIO);
4454 #endif
4455 #ifdef RLIMIT_RTTIME
4456  RESCHECK(RTTIME);
4457 #endif
4458  break;
4459 
4460  case 'S':
4461 #ifdef RLIMIT_STACK
4462  RESCHECK(STACK);
4463 #endif
4464 #ifdef RLIMIT_SBSIZE
4465  RESCHECK(SBSIZE);
4466 #endif
4467 #ifdef RLIMIT_SIGPENDING
4468  RESCHECK(SIGPENDING);
4469 #endif
4470  break;
4471  }
4472  return -1;
4473 
4474  found:
4475  switch (casetype) {
4476  case 0:
4477  for (p = name; *p; p++)
4478  if (!ISUPPER(*p))
4479  return -1;
4480  break;
4481 
4482  case 1:
4483  for (p = name; *p; p++)
4484  if (!ISLOWER(*p))
4485  return -1;
4486  break;
4487 
4488  default:
4489  rb_bug("unexpected casetype");
4490  }
4491  return resource;
4492 #undef RESCHECK
4493 }
4494 
4495 static int
4496 rlimit_type_by_hname(const char *name)
4497 {
4498  return rlimit_resource_name2int(name, 0);
4499 }
4500 
4501 static int
4502 rlimit_type_by_lname(const char *name)
4503 {
4504  return rlimit_resource_name2int(name, 1);
4505 }
4506 
4507 static int
4508 rlimit_resource_type(VALUE rtype)
4509 {
4510  const char *name;
4511  VALUE v;
4512  int r;
4513 
4514  switch (TYPE(rtype)) {
4515  case T_SYMBOL:
4516  name = rb_id2name(SYM2ID(rtype));
4517  break;
4518 
4519  default:
4520  v = rb_check_string_type(rtype);
4521  if (!NIL_P(v)) {
4522  rtype = v;
4523  case T_STRING:
4524  name = StringValueCStr(rtype);
4525  break;
4526  }
4527  /* fall through */
4528 
4529  case T_FIXNUM:
4530  case T_BIGNUM:
4531  return NUM2INT(rtype);
4532  }
4533 
4534  r = rlimit_type_by_hname(name);
4535  if (r != -1)
4536  return r;
4537 
4538  rb_raise(rb_eArgError, "invalid resource name: %s", name);
4539 
4540  UNREACHABLE;
4541 }
4542 
4543 static rlim_t
4544 rlimit_resource_value(VALUE rval)
4545 {
4546  const char *name;
4547  VALUE v;
4548 
4549  switch (TYPE(rval)) {
4550  case T_SYMBOL:
4551  name = rb_id2name(SYM2ID(rval));
4552  break;
4553 
4554  default:
4555  v = rb_check_string_type(rval);
4556  if (!NIL_P(v)) {
4557  rval = v;
4558  case T_STRING:
4559  name = StringValueCStr(rval);
4560  break;
4561  }
4562  /* fall through */
4563 
4564  case T_FIXNUM:
4565  case T_BIGNUM:
4566  return NUM2RLIM(rval);
4567  }
4568 
4569 #ifdef RLIM_INFINITY
4570  if (strcmp(name, "INFINITY") == 0) return RLIM_INFINITY;
4571 #endif
4572 #ifdef RLIM_SAVED_MAX
4573  if (strcmp(name, "SAVED_MAX") == 0) return RLIM_SAVED_MAX;
4574 #endif
4575 #ifdef RLIM_SAVED_CUR
4576  if (strcmp(name, "SAVED_CUR") == 0) return RLIM_SAVED_CUR;
4577 #endif
4578  rb_raise(rb_eArgError, "invalid resource value: %s", name);
4579 
4580  UNREACHABLE;
4581 }
4582 #endif
4583 
4584 #if defined(HAVE_GETRLIMIT) && defined(RLIM2NUM)
4585 /*
4586  * call-seq:
4587  * Process.getrlimit(resource) -> [cur_limit, max_limit]
4588  *
4589  * Gets the resource limit of the process.
4590  * _cur_limit_ means current (soft) limit and
4591  * _max_limit_ means maximum (hard) limit.
4592  *
4593  * _resource_ indicates the kind of resource to limit.
4594  * It is specified as a symbol such as <code>:CORE</code>,
4595  * a string such as <code>"CORE"</code> or
4596  * a constant such as <code>Process::RLIMIT_CORE</code>.
4597  * See Process.setrlimit for details.
4598  *
4599  * _cur_limit_ and _max_limit_ may be <code>Process::RLIM_INFINITY</code>,
4600  * <code>Process::RLIM_SAVED_MAX</code> or
4601  * <code>Process::RLIM_SAVED_CUR</code>.
4602  * See Process.setrlimit and the system getrlimit(2) manual for details.
4603  */
4604 
4605 static VALUE
4606 proc_getrlimit(VALUE obj, VALUE resource)
4607 {
4608  struct rlimit rlim;
4609 
4610  rb_secure(2);
4611 
4612  if (getrlimit(rlimit_resource_type(resource), &rlim) < 0) {
4613  rb_sys_fail("getrlimit");
4614  }
4615  return rb_assoc_new(RLIM2NUM(rlim.rlim_cur), RLIM2NUM(rlim.rlim_max));
4616 }
4617 #else
4618 #define proc_getrlimit rb_f_notimplement
4619 #endif
4620 
4621 #if defined(HAVE_SETRLIMIT) && defined(NUM2RLIM)
4622 /*
4623  * call-seq:
4624  * Process.setrlimit(resource, cur_limit, max_limit) -> nil
4625  * Process.setrlimit(resource, cur_limit) -> nil
4626  *
4627  * Sets the resource limit of the process.
4628  * _cur_limit_ means current (soft) limit and
4629  * _max_limit_ means maximum (hard) limit.
4630  *
4631  * If _max_limit_ is not given, _cur_limit_ is used.
4632  *
4633  * _resource_ indicates the kind of resource to limit.
4634  * It should be a symbol such as <code>:CORE</code>,
4635  * a string such as <code>"CORE"</code> or
4636  * a constant such as <code>Process::RLIMIT_CORE</code>.
4637  * The available resources are OS dependent.
4638  * Ruby may support following resources.
4639  *
4640  * [AS] total available memory (bytes) (SUSv3, NetBSD, FreeBSD, OpenBSD but 4.4BSD-Lite)
4641  * [CORE] core size (bytes) (SUSv3)
4642  * [CPU] CPU time (seconds) (SUSv3)
4643  * [DATA] data segment (bytes) (SUSv3)
4644  * [FSIZE] file size (bytes) (SUSv3)
4645  * [MEMLOCK] total size for mlock(2) (bytes) (4.4BSD, GNU/Linux)
4646  * [MSGQUEUE] allocation for POSIX message queues (bytes) (GNU/Linux)
4647  * [NICE] ceiling on process's nice(2) value (number) (GNU/Linux)
4648  * [NOFILE] file descriptors (number) (SUSv3)
4649  * [NPROC] number of processes for the user (number) (4.4BSD, GNU/Linux)
4650  * [RSS] resident memory size (bytes) (4.2BSD, GNU/Linux)
4651  * [RTPRIO] ceiling on the process's real-time priority (number) (GNU/Linux)
4652  * [RTTIME] CPU time for real-time process (us) (GNU/Linux)
4653  * [SBSIZE] all socket buffers (bytes) (NetBSD, FreeBSD)
4654  * [SIGPENDING] number of queued signals allowed (signals) (GNU/Linux)
4655  * [STACK] stack size (bytes) (SUSv3)
4656  *
4657  * _cur_limit_ and _max_limit_ may be
4658  * <code>:INFINITY</code>, <code>"INFINITY"</code> or
4659  * <code>Process::RLIM_INFINITY</code>,
4660  * which means that the resource is not limited.
4661  * They may be <code>Process::RLIM_SAVED_MAX</code>,
4662  * <code>Process::RLIM_SAVED_CUR</code> and
4663  * corresponding symbols and strings too.
4664  * See system setrlimit(2) manual for details.
4665  *
4666  * The following example raises the soft limit of core size to
4667  * the hard limit to try to make core dump possible.
4668  *
4669  * Process.setrlimit(:CORE, Process.getrlimit(:CORE)[1])
4670  *
4671  */
4672 
4673 static VALUE
4674 proc_setrlimit(int argc, VALUE *argv, VALUE obj)
4675 {
4676  VALUE resource, rlim_cur, rlim_max;
4677  struct rlimit rlim;
4678 
4679  rb_secure(2);
4680 
4681  rb_scan_args(argc, argv, "21", &resource, &rlim_cur, &rlim_max);
4682  if (rlim_max == Qnil)
4683  rlim_max = rlim_cur;
4684 
4685  rlim.rlim_cur = rlimit_resource_value(rlim_cur);
4686  rlim.rlim_max = rlimit_resource_value(rlim_max);
4687 
4688  if (setrlimit(rlimit_resource_type(resource), &rlim) < 0) {
4689  rb_sys_fail("setrlimit");
4690  }
4691  return Qnil;
4692 }
4693 #else
4694 #define proc_setrlimit rb_f_notimplement
4695 #endif
4696 
4697 static int under_uid_switch = 0;
4698 static void
4700 {
4701  rb_secure(2);
4702  if (under_uid_switch) {
4703  rb_raise(rb_eRuntimeError, "can't handle UID while evaluating block given to Process::UID.switch method");
4704  }
4705 }
4706 
4707 static int under_gid_switch = 0;
4708 static void
4710 {
4711  rb_secure(2);
4712  if (under_gid_switch) {
4713  rb_raise(rb_eRuntimeError, "can't handle GID while evaluating block given to Process::UID.switch method");
4714  }
4715 }
4716 
4717 
4718 /*********************************************************************
4719  * Document-class: Process::Sys
4720  *
4721  * The <code>Process::Sys</code> module contains UID and GID
4722  * functions which provide direct bindings to the system calls of the
4723  * same names instead of the more-portable versions of the same
4724  * functionality found in the <code>Process</code>,
4725  * <code>Process::UID</code>, and <code>Process::GID</code> modules.
4726  */
4727 
4728 #if defined(HAVE_PWD_H)
4729 static rb_uid_t
4730 obj2uid(VALUE id
4731 # ifdef USE_GETPWNAM_R
4732  , char *getpw_buf, size_t getpw_buf_len
4733 # endif
4734  )
4735 {
4736  rb_uid_t uid;
4737  VALUE tmp;
4738 
4739  if (FIXNUM_P(id) || NIL_P(tmp = rb_check_string_type(id))) {
4740  uid = NUM2UIDT(id);
4741  }
4742  else {
4743  const char *usrname = StringValueCStr(id);
4744  struct passwd *pwptr;
4745 #ifdef USE_GETPWNAM_R
4746  struct passwd pwbuf;
4747  if (getpwnam_r(usrname, &pwbuf, getpw_buf, getpw_buf_len, &pwptr))
4748  rb_sys_fail("getpwnam_r");
4749 #else
4750  pwptr = getpwnam(usrname);
4751 #endif
4752  if (!pwptr) {
4753 #ifndef USE_GETPWNAM_R
4754  endpwent();
4755 #endif
4756  rb_raise(rb_eArgError, "can't find user for %s", usrname);
4757  }
4758  uid = pwptr->pw_uid;
4759 #ifndef USE_GETPWNAM_R
4760  endpwent();
4761 #endif
4762  }
4763  return uid;
4764 }
4765 
4766 # ifdef p_uid_from_name
4767 static VALUE
4768 p_uid_from_name(VALUE self, VALUE id)
4769 {
4771  return UIDT2NUM(OBJ2UID(id));
4772 }
4773 # endif
4774 #endif
4775 
4776 #if defined(HAVE_GRP_H)
4777 static rb_gid_t
4778 obj2gid(VALUE id
4779 # ifdef USE_GETGRNAM_R
4780  , char *getgr_buf, size_t getgr_buf_len
4781 # endif
4782  )
4783 {
4784  rb_gid_t gid;
4785  VALUE tmp;
4786 
4787  if (FIXNUM_P(id) || NIL_P(tmp = rb_check_string_type(id))) {
4788  gid = NUM2GIDT(id);
4789  }
4790  else {
4791  const char *grpname = StringValueCStr(id);
4792  struct group *grptr;
4793 #ifdef USE_GETGRNAM_R
4794  struct group grbuf;
4795  if (getgrnam_r(grpname, &grbuf, getgr_buf, getgr_buf_len, &grptr))
4796  rb_sys_fail("getgrnam_r");
4797 #else
4798  grptr = getgrnam(grpname);
4799 #endif
4800  if (!grptr) {
4801 #ifndef USE_GETGRNAM_R
4802  endgrent();
4803 #endif
4804  rb_raise(rb_eArgError, "can't find group for %s", grpname);
4805  }
4806  gid = grptr->gr_gid;
4807 #ifndef USE_GETGRNAM_R
4808  endgrent();
4809 #endif
4810  }
4811  return gid;
4812 }
4813 
4814 # ifdef p_gid_from_name
4815 static VALUE
4816 p_gid_from_name(VALUE self, VALUE id)
4817 {
4819  return GIDT2NUM(OBJ2GID(id));
4820 }
4821 # endif
4822 #endif
4823 
4824 #if defined HAVE_SETUID
4825 /*
4826  * call-seq:
4827  * Process::Sys.setuid(user) -> nil
4828  *
4829  * Set the user ID of the current process to _user_. Not
4830  * available on all platforms.
4831  *
4832  */
4833 
4834 static VALUE
4835 p_sys_setuid(VALUE obj, VALUE id)
4836 {
4838  check_uid_switch();
4839  if (setuid(OBJ2UID(id)) != 0) rb_sys_fail(0);
4840  return Qnil;
4841 }
4842 #else
4843 #define p_sys_setuid rb_f_notimplement
4844 #endif
4845 
4846 
4847 #if defined HAVE_SETRUID
4848 /*
4849  * call-seq:
4850  * Process::Sys.setruid(user) -> nil
4851  *
4852  * Set the real user ID of the calling process to _user_.
4853  * Not available on all platforms.
4854  *
4855  */
4856 
4857 static VALUE
4858 p_sys_setruid(VALUE obj, VALUE id)
4859 {
4861  check_uid_switch();
4862  if (setruid(OBJ2UID(id)) != 0) rb_sys_fail(0);
4863  return Qnil;
4864 }
4865 #else
4866 #define p_sys_setruid rb_f_notimplement
4867 #endif
4868 
4869 
4870 #if defined HAVE_SETEUID
4871 /*
4872  * call-seq:
4873  * Process::Sys.seteuid(user) -> nil
4874  *
4875  * Set the effective user ID of the calling process to
4876  * _user_. Not available on all platforms.
4877  *
4878  */
4879 
4880 static VALUE
4881 p_sys_seteuid(VALUE obj, VALUE id)
4882 {
4884  check_uid_switch();
4885  if (seteuid(OBJ2UID(id)) != 0) rb_sys_fail(0);
4886  return Qnil;
4887 }
4888 #else
4889 #define p_sys_seteuid rb_f_notimplement
4890 #endif
4891 
4892 
4893 #if defined HAVE_SETREUID
4894 /*
4895  * call-seq:
4896  * Process::Sys.setreuid(rid, eid) -> nil
4897  *
4898  * Sets the (user) real and/or effective user IDs of the current
4899  * process to _rid_ and _eid_, respectively. A value of
4900  * <code>-1</code> for either means to leave that ID unchanged. Not
4901  * available on all platforms.
4902  *
4903  */
4904 
4905 static VALUE
4906 p_sys_setreuid(VALUE obj, VALUE rid, VALUE eid)
4907 {
4909  check_uid_switch();
4910  if (setreuid(OBJ2UID(rid), OBJ2UID(eid)) != 0) rb_sys_fail(0);
4911  return Qnil;
4912 }
4913 #else
4914 #define p_sys_setreuid rb_f_notimplement
4915 #endif
4916 
4917 
4918 #if defined HAVE_SETRESUID
4919 /*
4920  * call-seq:
4921  * Process::Sys.setresuid(rid, eid, sid) -> nil
4922  *
4923  * Sets the (user) real, effective, and saved user IDs of the
4924  * current process to _rid_, _eid_, and _sid_ respectively. A
4925  * value of <code>-1</code> for any value means to
4926  * leave that ID unchanged. Not available on all platforms.
4927  *
4928  */
4929 
4930 static VALUE
4931 p_sys_setresuid(VALUE obj, VALUE rid, VALUE eid, VALUE sid)
4932 {
4934  check_uid_switch();
4935  if (setresuid(OBJ2UID(rid), OBJ2UID(eid), OBJ2UID(sid)) != 0) rb_sys_fail(0);
4936  return Qnil;
4937 }
4938 #else
4939 #define p_sys_setresuid rb_f_notimplement
4940 #endif
4941 
4942 
4943 /*
4944  * call-seq:
4945  * Process.uid -> fixnum
4946  * Process::UID.rid -> fixnum
4947  * Process::Sys.getuid -> fixnum
4948  *
4949  * Returns the (real) user ID of this process.
4950  *
4951  * Process.uid #=> 501
4952  */
4953 
4954 static VALUE
4956 {
4957  rb_uid_t uid = getuid();
4958  return UIDT2NUM(uid);
4959 }
4960 
4961 
4962 #if defined(HAVE_SETRESUID) || defined(HAVE_SETREUID) || defined(HAVE_SETRUID) || defined(HAVE_SETUID)
4963 /*
4964  * call-seq:
4965  * Process.uid= user -> numeric
4966  *
4967  * Sets the (user) user ID for this process. Not available on all
4968  * platforms.
4969  */
4970 
4971 static VALUE
4972 proc_setuid(VALUE obj, VALUE id)
4973 {
4974  rb_uid_t uid;
4976 
4977  check_uid_switch();
4978 
4979  uid = OBJ2UID(id);
4980 #if defined(HAVE_SETRESUID)
4981  if (setresuid(uid, -1, -1) < 0) rb_sys_fail(0);
4982 #elif defined HAVE_SETREUID
4983  if (setreuid(uid, -1) < 0) rb_sys_fail(0);
4984 #elif defined HAVE_SETRUID
4985  if (setruid(uid) < 0) rb_sys_fail(0);
4986 #elif defined HAVE_SETUID
4987  {
4988  if (geteuid() == uid) {
4989  if (setuid(uid) < 0) rb_sys_fail(0);
4990  }
4991  else {
4992  rb_notimplement();
4993  }
4994  }
4995 #endif
4996  return id;
4997 }
4998 #else
4999 #define proc_setuid rb_f_notimplement
5000 #endif
5001 
5002 
5003 /********************************************************************
5004  *
5005  * Document-class: Process::UID
5006  *
5007  * The <code>Process::UID</code> module contains a collection of
5008  * module functions which can be used to portably get, set, and
5009  * switch the current process's real, effective, and saved user IDs.
5010  *
5011  */
5012 
5013 static rb_uid_t SAVED_USER_ID = -1;
5014 
5015 #ifdef BROKEN_SETREUID
5016 int
5017 setreuid(rb_uid_t ruid, rb_uid_t euid)
5018 {
5019  if (ruid != (rb_uid_t)-1 && ruid != getuid()) {
5020  if (euid == (rb_uid_t)-1) euid = geteuid();
5021  if (setuid(ruid) < 0) return -1;
5022  }
5023  if (euid != (rb_uid_t)-1 && euid != geteuid()) {
5024  if (seteuid(euid) < 0) return -1;
5025  }
5026  return 0;
5027 }
5028 #endif
5029 
5030 /*
5031  * call-seq:
5032  * Process::UID.change_privilege(user) -> fixnum
5033  *
5034  * Change the current process's real and effective user ID to that
5035  * specified by _user_. Returns the new user ID. Not
5036  * available on all platforms.
5037  *
5038  * [Process.uid, Process.euid] #=> [0, 0]
5039  * Process::UID.change_privilege(31) #=> 31
5040  * [Process.uid, Process.euid] #=> [31, 31]
5041  */
5042 
5043 static VALUE
5045 {
5046  rb_uid_t uid;
5048 
5049  check_uid_switch();
5050 
5051  uid = OBJ2UID(id);
5052 
5053  if (geteuid() == 0) { /* root-user */
5054 #if defined(HAVE_SETRESUID)
5055  if (setresuid(uid, uid, uid) < 0) rb_sys_fail(0);
5056  SAVED_USER_ID = uid;
5057 #elif defined(HAVE_SETUID)
5058  if (setuid(uid) < 0) rb_sys_fail(0);
5059  SAVED_USER_ID = uid;
5060 #elif defined(HAVE_SETREUID) && !defined(OBSOLETE_SETREUID)
5061  if (getuid() == uid) {
5062  if (SAVED_USER_ID == uid) {
5063  if (setreuid(-1, uid) < 0) rb_sys_fail(0);
5064  }
5065  else {
5066  if (uid == 0) { /* (r,e,s) == (root, root, x) */
5067  if (setreuid(-1, SAVED_USER_ID) < 0) rb_sys_fail(0);
5068  if (setreuid(SAVED_USER_ID, 0) < 0) rb_sys_fail(0);
5069  SAVED_USER_ID = 0; /* (r,e,s) == (x, root, root) */
5070  if (setreuid(uid, uid) < 0) rb_sys_fail(0);
5071  SAVED_USER_ID = uid;
5072  }
5073  else {
5074  if (setreuid(0, -1) < 0) rb_sys_fail(0);
5075  SAVED_USER_ID = 0;
5076  if (setreuid(uid, uid) < 0) rb_sys_fail(0);
5077  SAVED_USER_ID = uid;
5078  }
5079  }
5080  }
5081  else {
5082  if (setreuid(uid, uid) < 0) rb_sys_fail(0);
5083  SAVED_USER_ID = uid;
5084  }
5085 #elif defined(HAVE_SETRUID) && defined(HAVE_SETEUID)
5086  if (getuid() == uid) {
5087  if (SAVED_USER_ID == uid) {
5088  if (seteuid(uid) < 0) rb_sys_fail(0);
5089  }
5090  else {
5091  if (uid == 0) {
5092  if (setruid(SAVED_USER_ID) < 0) rb_sys_fail(0);
5093  SAVED_USER_ID = 0;
5094  if (setruid(0) < 0) rb_sys_fail(0);
5095  }
5096  else {
5097  if (setruid(0) < 0) rb_sys_fail(0);
5098  SAVED_USER_ID = 0;
5099  if (seteuid(uid) < 0) rb_sys_fail(0);
5100  if (setruid(uid) < 0) rb_sys_fail(0);
5101  SAVED_USER_ID = uid;
5102  }
5103  }
5104  }
5105  else {
5106  if (seteuid(uid) < 0) rb_sys_fail(0);
5107  if (setruid(uid) < 0) rb_sys_fail(0);
5108  SAVED_USER_ID = uid;
5109  }
5110 #else
5111  (void)uid;
5112  rb_notimplement();
5113 #endif
5114  }
5115  else { /* unprivileged user */
5116 #if defined(HAVE_SETRESUID)
5117  if (setresuid((getuid() == uid)? (rb_uid_t)-1: uid,
5118  (geteuid() == uid)? (rb_uid_t)-1: uid,
5119  (SAVED_USER_ID == uid)? (rb_uid_t)-1: uid) < 0) rb_sys_fail(0);
5120  SAVED_USER_ID = uid;
5121 #elif defined(HAVE_SETREUID) && !defined(OBSOLETE_SETREUID)
5122  if (SAVED_USER_ID == uid) {
5123  if (setreuid((getuid() == uid)? (rb_uid_t)-1: uid,
5124  (geteuid() == uid)? (rb_uid_t)-1: uid) < 0)
5125  rb_sys_fail(0);
5126  }
5127  else if (getuid() != uid) {
5128  if (setreuid(uid, (geteuid() == uid)? (rb_uid_t)-1: uid) < 0)
5129  rb_sys_fail(0);
5130  SAVED_USER_ID = uid;
5131  }
5132  else if (/* getuid() == uid && */ geteuid() != uid) {
5133  if (setreuid(geteuid(), uid) < 0) rb_sys_fail(0);
5134  SAVED_USER_ID = uid;
5135  if (setreuid(uid, -1) < 0) rb_sys_fail(0);
5136  }
5137  else { /* getuid() == uid && geteuid() == uid */
5138  if (setreuid(-1, SAVED_USER_ID) < 0) rb_sys_fail(0);
5139  if (setreuid(SAVED_USER_ID, uid) < 0) rb_sys_fail(0);
5140  SAVED_USER_ID = uid;
5141  if (setreuid(uid, -1) < 0) rb_sys_fail(0);
5142  }
5143 #elif defined(HAVE_SETRUID) && defined(HAVE_SETEUID)
5144  if (SAVED_USER_ID == uid) {
5145  if (geteuid() != uid && seteuid(uid) < 0) rb_sys_fail(0);
5146  if (getuid() != uid && setruid(uid) < 0) rb_sys_fail(0);
5147  }
5148  else if (/* SAVED_USER_ID != uid && */ geteuid() == uid) {
5149  if (getuid() != uid) {
5150  if (setruid(uid) < 0) rb_sys_fail(0);
5151  SAVED_USER_ID = uid;
5152  }
5153  else {
5154  if (setruid(SAVED_USER_ID) < 0) rb_sys_fail(0);
5155  SAVED_USER_ID = uid;
5156  if (setruid(uid) < 0) rb_sys_fail(0);
5157  }
5158  }
5159  else if (/* geteuid() != uid && */ getuid() == uid) {
5160  if (seteuid(uid) < 0) rb_sys_fail(0);
5161  if (setruid(SAVED_USER_ID) < 0) rb_sys_fail(0);
5162  SAVED_USER_ID = uid;
5163  if (setruid(uid) < 0) rb_sys_fail(0);
5164  }
5165  else {
5166  errno = EPERM;
5167  rb_sys_fail(0);
5168  }
5169 #elif defined HAVE_44BSD_SETUID
5170  if (getuid() == uid) {
5171  /* (r,e,s)==(uid,?,?) ==> (uid,uid,uid) */
5172  if (setuid(uid) < 0) rb_sys_fail(0);
5173  SAVED_USER_ID = uid;
5174  }
5175  else {
5176  errno = EPERM;
5177  rb_sys_fail(0);
5178  }
5179 #elif defined HAVE_SETEUID
5180  if (getuid() == uid && SAVED_USER_ID == uid) {
5181  if (seteuid(uid) < 0) rb_sys_fail(0);
5182  }
5183  else {
5184  errno = EPERM;
5185  rb_sys_fail(0);
5186  }
5187 #elif defined HAVE_SETUID
5188  if (getuid() == uid && SAVED_USER_ID == uid) {
5189  if (setuid(uid) < 0) rb_sys_fail(0);
5190  }
5191  else {
5192  errno = EPERM;
5193  rb_sys_fail(0);
5194  }
5195 #else
5196  rb_notimplement();
5197 #endif
5198  }
5199  return id;
5200 }
5201 
5202 
5203 
5204 #if defined HAVE_SETGID
5205 /*
5206  * call-seq:
5207  * Process::Sys.setgid(group) -> nil
5208  *
5209  * Set the group ID of the current process to _group_. Not
5210  * available on all platforms.
5211  *
5212  */
5213 
5214 static VALUE
5215 p_sys_setgid(VALUE obj, VALUE id)
5216 {
5218  check_gid_switch();
5219  if (setgid(OBJ2GID(id)) != 0) rb_sys_fail(0);
5220  return Qnil;
5221 }
5222 #else
5223 #define p_sys_setgid rb_f_notimplement
5224 #endif
5225 
5226 
5227 #if defined HAVE_SETRGID
5228 /*
5229  * call-seq:
5230  * Process::Sys.setrgid(group) -> nil
5231  *
5232  * Set the real group ID of the calling process to _group_.
5233  * Not available on all platforms.
5234  *
5235  */
5236 
5237 static VALUE
5238 p_sys_setrgid(VALUE obj, VALUE id)
5239 {
5241  check_gid_switch();
5242  if (setrgid(OBJ2GID(id)) != 0) rb_sys_fail(0);
5243  return Qnil;
5244 }
5245 #else
5246 #define p_sys_setrgid rb_f_notimplement
5247 #endif
5248 
5249 
5250 #if defined HAVE_SETEGID
5251 /*
5252  * call-seq:
5253  * Process::Sys.setegid(group) -> nil
5254  *
5255  * Set the effective group ID of the calling process to
5256  * _group_. Not available on all platforms.
5257  *
5258  */
5259 
5260 static VALUE
5261 p_sys_setegid(VALUE obj, VALUE id)
5262 {
5264  check_gid_switch();
5265  if (setegid(OBJ2GID(id)) != 0) rb_sys_fail(0);
5266  return Qnil;
5267 }
5268 #else
5269 #define p_sys_setegid rb_f_notimplement
5270 #endif
5271 
5272 
5273 #if defined HAVE_SETREGID
5274 /*
5275  * call-seq:
5276  * Process::Sys.setregid(rid, eid) -> nil
5277  *
5278  * Sets the (group) real and/or effective group IDs of the current
5279  * process to <em>rid</em> and <em>eid</em>, respectively. A value of
5280  * <code>-1</code> for either means to leave that ID unchanged. Not
5281  * available on all platforms.
5282  *
5283  */
5284 
5285 static VALUE
5286 p_sys_setregid(VALUE obj, VALUE rid, VALUE eid)
5287 {
5289  check_gid_switch();
5290  if (setregid(OBJ2GID(rid), OBJ2GID(eid)) != 0) rb_sys_fail(0);
5291  return Qnil;
5292 }
5293 #else
5294 #define p_sys_setregid rb_f_notimplement
5295 #endif
5296 
5297 #if defined HAVE_SETRESGID
5298 /*
5299  * call-seq:
5300  * Process::Sys.setresgid(rid, eid, sid) -> nil
5301  *
5302  * Sets the (group) real, effective, and saved user IDs of the
5303  * current process to <em>rid</em>, <em>eid</em>, and <em>sid</em>
5304  * respectively. A value of <code>-1</code> for any value means to
5305  * leave that ID unchanged. Not available on all platforms.
5306  *
5307  */
5308 
5309 static VALUE
5310 p_sys_setresgid(VALUE obj, VALUE rid, VALUE eid, VALUE sid)
5311 {
5313  check_gid_switch();
5314  if (setresgid(OBJ2GID(rid), OBJ2GID(eid), OBJ2GID(sid)) != 0) rb_sys_fail(0);
5315  return Qnil;
5316 }
5317 #else
5318 #define p_sys_setresgid rb_f_notimplement
5319 #endif
5320 
5321 
5322 #if defined HAVE_ISSETUGID
5323 /*
5324  * call-seq:
5325  * Process::Sys.issetugid -> true or false
5326  *
5327  * Returns +true+ if the process was created as a result
5328  * of an execve(2) system call which had either of the setuid or
5329  * setgid bits set (and extra privileges were given as a result) or
5330  * if it has changed any of its real, effective or saved user or
5331  * group IDs since it began execution.
5332  *
5333  */
5334 
5335 static VALUE
5337 {
5338  rb_secure(2);
5339  if (issetugid()) {
5340  return Qtrue;
5341  }
5342  else {
5343  return Qfalse;
5344  }
5345 }
5346 #else
5347 #define p_sys_issetugid rb_f_notimplement
5348 #endif
5349 
5350 
5351 /*
5352  * call-seq:
5353  * Process.gid -> fixnum
5354  * Process::GID.rid -> fixnum
5355  * Process::Sys.getgid -> fixnum
5356  *
5357  * Returns the (real) group ID for this process.
5358  *
5359  * Process.gid #=> 500
5360  */
5361 
5362 static VALUE
5364 {
5365  rb_gid_t gid = getgid();
5366  return GIDT2NUM(gid);
5367 }
5368 
5369 
5370 #if defined(HAVE_SETRESGID) || defined(HAVE_SETREGID) || defined(HAVE_SETRGID) || defined(HAVE_SETGID)
5371 /*
5372  * call-seq:
5373  * Process.gid= fixnum -> fixnum
5374  *
5375  * Sets the group ID for this process.
5376  */
5377 
5378 static VALUE
5379 proc_setgid(VALUE obj, VALUE id)
5380 {
5381  rb_gid_t gid;
5383 
5384  check_gid_switch();
5385 
5386  gid = OBJ2GID(id);
5387 #if defined(HAVE_SETRESGID)
5388  if (setresgid(gid, -1, -1) < 0) rb_sys_fail(0);
5389 #elif defined HAVE_SETREGID
5390  if (setregid(gid, -1) < 0) rb_sys_fail(0);
5391 #elif defined HAVE_SETRGID
5392  if (setrgid(gid) < 0) rb_sys_fail(0);
5393 #elif defined HAVE_SETGID
5394  {
5395  if (getegid() == gid) {
5396  if (setgid(gid) < 0) rb_sys_fail(0);
5397  }
5398  else {
5399  rb_notimplement();
5400  }
5401  }
5402 #endif
5403  return GIDT2NUM(gid);
5404 }
5405 #else
5406 #define proc_setgid rb_f_notimplement
5407 #endif
5408 
5409 
5410 #if defined(HAVE_SETGROUPS) || defined(HAVE_GETGROUPS)
5411 /*
5412  * Maximum supplementary groups are platform dependent.
5413  * FWIW, 65536 is enough big for our supported OSs.
5414  *
5415  * OS Name max groups
5416  * -----------------------------------------------
5417  * Linux Kernel >= 2.6.3 65536
5418  * Linux Kernel < 2.6.3 32
5419  * IBM AIX 5.2 64
5420  * IBM AIX 5.3 ... 6.1 128
5421  * IBM AIX 7.1 128 (can be configured to be up to 2048)
5422  * OpenBSD, NetBSD 16
5423  * FreeBSD < 8.0 16
5424  * FreeBSD >=8.0 1023
5425  * Darwin (Mac OS X) 16
5426  * Sun Solaris 7,8,9,10 16
5427  * Sun Solaris 11 / OpenSolaris 1024
5428  * HP-UX 20
5429  * Windows 1015
5430  */
5431 static int _maxgroups = -1;
5432 static int
5433 get_sc_ngroups_max(void)
5434 {
5435 #ifdef _SC_NGROUPS_MAX
5436  return (int)sysconf(_SC_NGROUPS_MAX);
5437 #elif defined(NGROUPS_MAX)
5438  return (int)NGROUPS_MAX;
5439 #else
5440  return -1;
5441 #endif
5442 }
5443 static int
5444 maxgroups(void)
5445 {
5446  if (_maxgroups < 0) {
5447  _maxgroups = get_sc_ngroups_max();
5448  if (_maxgroups < 0)
5449  _maxgroups = RB_MAX_GROUPS;
5450  }
5451 
5452  return _maxgroups;
5453 }
5454 #endif
5455 
5456 
5457 
5458 #ifdef HAVE_GETGROUPS
5459 /*
5460  * call-seq:
5461  * Process.groups -> array
5462  *
5463  * Get an <code>Array</code> of the gids of groups in the
5464  * supplemental group access list for this process.
5465  *
5466  * Process.groups #=> [27, 6, 10, 11]
5467  *
5468  */
5469 
5470 static VALUE
5471 proc_getgroups(VALUE obj)
5472 {
5473  VALUE ary;
5474  int i, ngroups;
5475  rb_gid_t *groups;
5476 
5477  ngroups = getgroups(0, NULL);
5478  if (ngroups == -1)
5479  rb_sys_fail(0);
5480 
5481  groups = ALLOCA_N(rb_gid_t, ngroups);
5482 
5483  ngroups = getgroups(ngroups, groups);
5484  if (ngroups == -1)
5485  rb_sys_fail(0);
5486 
5487  ary = rb_ary_new();
5488  for (i = 0; i < ngroups; i++)
5489  rb_ary_push(ary, GIDT2NUM(groups[i]));
5490 
5491  return ary;
5492 }
5493 #else
5494 #define proc_getgroups rb_f_notimplement
5495 #endif
5496 
5497 
5498 #ifdef HAVE_SETGROUPS
5499 /*
5500  * call-seq:
5501  * Process.groups= array -> array
5502  *
5503  * Set the supplemental group access list to the given
5504  * <code>Array</code> of group IDs.
5505  *
5506  * Process.groups #=> [0, 1, 2, 3, 4, 6, 10, 11, 20, 26, 27]
5507  * Process.groups = [27, 6, 10, 11] #=> [27, 6, 10, 11]
5508  * Process.groups #=> [27, 6, 10, 11]
5509  *
5510  */
5511 
5512 static VALUE
5513 proc_setgroups(VALUE obj, VALUE ary)
5514 {
5515  int ngroups, i;
5516  rb_gid_t *groups;
5518 
5519  Check_Type(ary, T_ARRAY);
5520 
5521  ngroups = RARRAY_LENINT(ary);
5522  if (ngroups > maxgroups())
5523  rb_raise(rb_eArgError, "too many groups, %d max", maxgroups());
5524 
5525  groups = ALLOCA_N(rb_gid_t, ngroups);
5526 
5527  for (i = 0; i < ngroups; i++) {
5528  VALUE g = RARRAY_PTR(ary)[i];
5529 
5530  groups[i] = OBJ2GID(g);
5531  }
5532 
5533  if (setgroups(ngroups, groups) == -1) /* ngroups <= maxgroups */
5534  rb_sys_fail(0);
5535 
5536  return proc_getgroups(obj);
5537 }
5538 #else
5539 #define proc_setgroups rb_f_notimplement
5540 #endif
5541 
5542 
5543 #ifdef HAVE_INITGROUPS
5544 /*
5545  * call-seq:
5546  * Process.initgroups(username, gid) -> array
5547  *
5548  * Initializes the supplemental group access list by reading the
5549  * system group database and using all groups of which the given user
5550  * is a member. The group with the specified <em>gid</em> is also
5551  * added to the list. Returns the resulting <code>Array</code> of the
5552  * gids of all the groups in the supplementary group access list. Not
5553  * available on all platforms.
5554  *
5555  * Process.groups #=> [0, 1, 2, 3, 4, 6, 10, 11, 20, 26, 27]
5556  * Process.initgroups( "mgranger", 30 ) #=> [30, 6, 10, 11]
5557  * Process.groups #=> [30, 6, 10, 11]
5558  *
5559  */
5560 
5561 static VALUE
5562 proc_initgroups(VALUE obj, VALUE uname, VALUE base_grp)
5563 {
5565  if (initgroups(StringValuePtr(uname), OBJ2GID(base_grp)) != 0) {
5566  rb_sys_fail(0);
5567  }
5568  return proc_getgroups(obj);
5569 }
5570 #else
5571 #define proc_initgroups rb_f_notimplement
5572 #endif
5573 
5574 #if defined(_SC_NGROUPS_MAX) || defined(NGROUPS_MAX)
5575 /*
5576  * call-seq:
5577  * Process.maxgroups -> fixnum
5578  *
5579  * Returns the maximum number of gids allowed in the supplemental
5580  * group access list.
5581  *
5582  * Process.maxgroups #=> 32
5583  */
5584 
5585 static VALUE
5587 {
5588  return INT2FIX(maxgroups());
5589 }
5590 #else
5591 #define proc_getmaxgroups rb_f_notimplement
5592 #endif
5593 
5594 #ifdef HAVE_SETGROUPS
5595 /*
5596  * call-seq:
5597  * Process.maxgroups= fixnum -> fixnum
5598  *
5599  * Sets the maximum number of gids allowed in the supplemental group
5600  * access list.
5601  */
5602 
5603 static VALUE
5605 {
5606  int ngroups = FIX2INT(val);
5607  int ngroups_max = get_sc_ngroups_max();
5608 
5609  if (ngroups <= 0)
5610  rb_raise(rb_eArgError, "maxgroups %d shold be positive", ngroups);
5611 
5612  if (ngroups > RB_MAX_GROUPS)
5613  ngroups = RB_MAX_GROUPS;
5614 
5615  if (ngroups_max > 0 && ngroups > ngroups_max)
5616  ngroups = ngroups_max;
5617 
5618  _maxgroups = ngroups;
5619 
5620  return INT2FIX(_maxgroups);
5621 }
5622 #else
5623 #define proc_setmaxgroups rb_f_notimplement
5624 #endif
5625 
5626 #if defined(HAVE_DAEMON) || (defined(HAVE_FORK) && defined(HAVE_SETSID))
5627 static int rb_daemon(int nochdir, int noclose);
5628 
5629 /*
5630  * call-seq:
5631  * Process.daemon() -> 0
5632  * Process.daemon(nochdir=nil,noclose=nil) -> 0
5633  *
5634  * Detach the process from controlling terminal and run in
5635  * the background as system daemon. Unless the argument
5636  * nochdir is true (i.e. non false), it changes the current
5637  * working directory to the root ("/"). Unless the argument
5638  * noclose is true, daemon() will redirect standard input,
5639  * standard output and standard error to /dev/null.
5640  * Return zero on success, or raise one of Errno::*.
5641  */
5642 
5643 static VALUE
5644 proc_daemon(int argc, VALUE *argv)
5645 {
5646  VALUE nochdir, noclose;
5647  int n;
5648 
5649  rb_secure(2);
5650  rb_scan_args(argc, argv, "02", &nochdir, &noclose);
5651 
5652  prefork();
5653  n = rb_daemon(RTEST(nochdir), RTEST(noclose));
5654  if (n < 0) rb_sys_fail("daemon");
5655  return INT2FIX(n);
5656 }
5657 
5658 static int
5659 rb_daemon(int nochdir, int noclose)
5660 {
5661  int err = 0;
5662 #ifdef HAVE_DAEMON
5663  before_fork();
5664  err = daemon(nochdir, noclose);
5665  after_fork();
5666  rb_thread_atfork();
5667 #else
5668  int n;
5669 
5670 #define fork_daemon() \
5671  switch (rb_fork_ruby(NULL)) { \
5672  case -1: return -1; \
5673  case 0: rb_thread_atfork(); break; \
5674  default: _exit(EXIT_SUCCESS); \
5675  }
5676 
5677  fork_daemon();
5678 
5679  if (setsid() < 0) return -1;
5680 
5681  /* must not be process-leader */
5682  fork_daemon();
5683 
5684  if (!nochdir)
5685  err = chdir("/");
5686 
5687  if (!noclose && (n = rb_cloexec_open("/dev/null", O_RDWR, 0)) != -1) {
5688  rb_update_max_fd(n);
5689  (void)dup2(n, 0);
5690  (void)dup2(n, 1);
5691  (void)dup2(n, 2);
5692  if (n > 2)
5693  (void)close (n);
5694  }
5695 #endif
5696  return err;
5697 }
5698 #else
5699 #define proc_daemon rb_f_notimplement
5700 #endif
5701 
5702 /********************************************************************
5703  *
5704  * Document-class: Process::GID
5705  *
5706  * The <code>Process::GID</code> module contains a collection of
5707  * module functions which can be used to portably get, set, and
5708  * switch the current process's real, effective, and saved group IDs.
5709  *
5710  */
5711 
5712 static rb_gid_t SAVED_GROUP_ID = -1;
5713 
5714 #ifdef BROKEN_SETREGID
5715 int
5716 setregid(rb_gid_t rgid, rb_gid_t egid)
5717 {
5718  if (rgid != (rb_gid_t)-1 && rgid != getgid()) {
5719  if (egid == (rb_gid_t)-1) egid = getegid();
5720  if (setgid(rgid) < 0) return -1;
5721  }
5722  if (egid != (rb_gid_t)-1 && egid != getegid()) {
5723  if (setegid(egid) < 0) return -1;
5724  }
5725  return 0;
5726 }
5727 #endif
5728 
5729 /*
5730  * call-seq:
5731  * Process::GID.change_privilege(group) -> fixnum
5732  *
5733  * Change the current process's real and effective group ID to that
5734  * specified by _group_. Returns the new group ID. Not
5735  * available on all platforms.
5736  *
5737  * [Process.gid, Process.egid] #=> [0, 0]
5738  * Process::GID.change_privilege(33) #=> 33
5739  * [Process.gid, Process.egid] #=> [33, 33]
5740  */
5741 
5742 static VALUE
5744 {
5745  rb_gid_t gid;
5747 
5748  check_gid_switch();
5749 
5750  gid = OBJ2GID(id);
5751 
5752  if (geteuid() == 0) { /* root-user */
5753 #if defined(HAVE_SETRESGID)
5754  if (setresgid(gid, gid, gid) < 0) rb_sys_fail(0);
5755  SAVED_GROUP_ID = gid;
5756 #elif defined HAVE_SETGID
5757  if (setgid(gid) < 0) rb_sys_fail(0);
5758  SAVED_GROUP_ID = gid;
5759 #elif defined(HAVE_SETREGID) && !defined(OBSOLETE_SETREGID)
5760  if (getgid() == gid) {
5761  if (SAVED_GROUP_ID == gid) {
5762  if (setregid(-1, gid) < 0) rb_sys_fail(0);
5763  }
5764  else {
5765  if (gid == 0) { /* (r,e,s) == (root, y, x) */
5766  if (setregid(-1, SAVED_GROUP_ID) < 0) rb_sys_fail(0);
5767  if (setregid(SAVED_GROUP_ID, 0) < 0) rb_sys_fail(0);
5768  SAVED_GROUP_ID = 0; /* (r,e,s) == (x, root, root) */
5769  if (setregid(gid, gid) < 0) rb_sys_fail(0);
5770  SAVED_GROUP_ID = gid;
5771  }
5772  else { /* (r,e,s) == (z, y, x) */
5773  if (setregid(0, 0) < 0) rb_sys_fail(0);
5774  SAVED_GROUP_ID = 0;
5775  if (setregid(gid, gid) < 0) rb_sys_fail(0);
5776  SAVED_GROUP_ID = gid;
5777  }
5778  }
5779  }
5780  else {
5781  if (setregid(gid, gid) < 0) rb_sys_fail(0);
5782  SAVED_GROUP_ID = gid;
5783  }
5784 #elif defined(HAVE_SETRGID) && defined (HAVE_SETEGID)
5785  if (getgid() == gid) {
5786  if (SAVED_GROUP_ID == gid) {
5787  if (setegid(gid) < 0) rb_sys_fail(0);
5788  }
5789  else {
5790  if (gid == 0) {
5791  if (setegid(gid) < 0) rb_sys_fail(0);
5792  if (setrgid(SAVED_GROUP_ID) < 0) rb_sys_fail(0);
5793  SAVED_GROUP_ID = 0;
5794  if (setrgid(0) < 0) rb_sys_fail(0);
5795  }
5796  else {
5797  if (setrgid(0) < 0) rb_sys_fail(0);
5798  SAVED_GROUP_ID = 0;
5799  if (setegid(gid) < 0) rb_sys_fail(0);
5800  if (setrgid(gid) < 0) rb_sys_fail(0);
5801  SAVED_GROUP_ID = gid;
5802  }
5803  }
5804  }
5805  else {
5806  if (setegid(gid) < 0) rb_sys_fail(0);
5807  if (setrgid(gid) < 0) rb_sys_fail(0);
5808  SAVED_GROUP_ID = gid;
5809  }
5810 #else
5811  rb_notimplement();
5812 #endif
5813  }
5814  else { /* unprivileged user */
5815 #if defined(HAVE_SETRESGID)
5816  if (setresgid((getgid() == gid)? (rb_gid_t)-1: gid,
5817  (getegid() == gid)? (rb_gid_t)-1: gid,
5818  (SAVED_GROUP_ID == gid)? (rb_gid_t)-1: gid) < 0) rb_sys_fail(0);
5819  SAVED_GROUP_ID = gid;
5820 #elif defined(HAVE_SETREGID) && !defined(OBSOLETE_SETREGID)
5821  if (SAVED_GROUP_ID == gid) {
5822  if (setregid((getgid() == gid)? (rb_uid_t)-1: gid,
5823  (getegid() == gid)? (rb_uid_t)-1: gid) < 0)
5824  rb_sys_fail(0);
5825  }
5826  else if (getgid() != gid) {
5827  if (setregid(gid, (getegid() == gid)? (rb_uid_t)-1: gid) < 0)
5828  rb_sys_fail(0);
5829  SAVED_GROUP_ID = gid;
5830  }
5831  else if (/* getgid() == gid && */ getegid() != gid) {
5832  if (setregid(getegid(), gid) < 0) rb_sys_fail(0);
5833  SAVED_GROUP_ID = gid;
5834  if (setregid(gid, -1) < 0) rb_sys_fail(0);
5835  }
5836  else { /* getgid() == gid && getegid() == gid */
5837  if (setregid(-1, SAVED_GROUP_ID) < 0) rb_sys_fail(0);
5838  if (setregid(SAVED_GROUP_ID, gid) < 0) rb_sys_fail(0);
5839  SAVED_GROUP_ID = gid;
5840  if (setregid(gid, -1) < 0) rb_sys_fail(0);
5841  }
5842 #elif defined(HAVE_SETRGID) && defined(HAVE_SETEGID)
5843  if (SAVED_GROUP_ID == gid) {
5844  if (getegid() != gid && setegid(gid) < 0) rb_sys_fail(0);
5845  if (getgid() != gid && setrgid(gid) < 0) rb_sys_fail(0);
5846  }
5847  else if (/* SAVED_GROUP_ID != gid && */ getegid() == gid) {
5848  if (getgid() != gid) {
5849  if (setrgid(gid) < 0) rb_sys_fail(0);
5850  SAVED_GROUP_ID = gid;
5851  }
5852  else {
5853  if (setrgid(SAVED_GROUP_ID) < 0) rb_sys_fail(0);
5854  SAVED_GROUP_ID = gid;
5855  if (setrgid(gid) < 0) rb_sys_fail(0);
5856  }
5857  }
5858  else if (/* getegid() != gid && */ getgid() == gid) {
5859  if (setegid(gid) < 0) rb_sys_fail(0);
5860  if (setrgid(SAVED_GROUP_ID) < 0) rb_sys_fail(0);
5861  SAVED_GROUP_ID = gid;
5862  if (setrgid(gid) < 0) rb_sys_fail(0);
5863  }
5864  else {
5865  errno = EPERM;
5866  rb_sys_fail(0);
5867  }
5868 #elif defined HAVE_44BSD_SETGID
5869  if (getgid() == gid) {
5870  /* (r,e,s)==(gid,?,?) ==> (gid,gid,gid) */
5871  if (setgid(gid) < 0) rb_sys_fail(0);
5872  SAVED_GROUP_ID = gid;
5873  }
5874  else {
5875  errno = EPERM;
5876  rb_sys_fail(0);
5877  }
5878 #elif defined HAVE_SETEGID
5879  if (getgid() == gid && SAVED_GROUP_ID == gid) {
5880  if (setegid(gid) < 0) rb_sys_fail(0);
5881  }
5882  else {
5883  errno = EPERM;
5884  rb_sys_fail(0);
5885  }
5886 #elif defined HAVE_SETGID
5887  if (getgid() == gid && SAVED_GROUP_ID == gid) {
5888  if (setgid(gid) < 0) rb_sys_fail(0);
5889  }
5890  else {
5891  errno = EPERM;
5892  rb_sys_fail(0);
5893  }
5894 #else
5895  (void)gid;
5896  rb_notimplement();
5897 #endif
5898  }
5899  return id;
5900 }
5901 
5902 
5903 /*
5904  * call-seq:
5905  * Process.euid -> fixnum
5906  * Process::UID.eid -> fixnum
5907  * Process::Sys.geteuid -> fixnum
5908  *
5909  * Returns the effective user ID for this process.
5910  *
5911  * Process.euid #=> 501
5912  */
5913 
5914 static VALUE
5916 {
5917  rb_uid_t euid = geteuid();
5918  return UIDT2NUM(euid);
5919 }
5920 
5921 #if defined(HAVE_SETRESUID) || defined(HAVE_SETREUID) || defined(HAVE_SETEUID) || defined(HAVE_SETUID) || defined(_POSIX_SAVED_IDS)
5922 static void
5923 proc_seteuid(rb_uid_t uid)
5924 {
5925 #if defined(HAVE_SETRESUID)
5926  if (setresuid(-1, uid, -1) < 0) rb_sys_fail(0);
5927 #elif defined HAVE_SETREUID
5928  if (setreuid(-1, uid) < 0) rb_sys_fail(0);
5929 #elif defined HAVE_SETEUID
5930  if (seteuid(uid) < 0) rb_sys_fail(0);
5931 #elif defined HAVE_SETUID
5932  if (uid == getuid()) {
5933  if (setuid(uid) < 0) rb_sys_fail(0);
5934  }
5935  else {
5936  rb_notimplement();
5937  }
5938 #else
5939  rb_notimplement();
5940 #endif
5941 }
5942 #endif
5943 
5944 #if defined(HAVE_SETRESUID) || defined(HAVE_SETREUID) || defined(HAVE_SETEUID) || defined(HAVE_SETUID)
5945 /*
5946  * call-seq:
5947  * Process.euid= user
5948  *
5949  * Sets the effective user ID for this process. Not available on all
5950  * platforms.
5951  */
5952 
5953 static VALUE
5955 {
5957  check_uid_switch();
5958  proc_seteuid(OBJ2UID(euid));
5959  return euid;
5960 }
5961 #else
5962 #define proc_seteuid_m rb_f_notimplement
5963 #endif
5964 
5965 static rb_uid_t
5966 rb_seteuid_core(rb_uid_t euid)
5967 {
5968 #if defined(HAVE_SETRESUID) || (defined(HAVE_SETREUID) && !defined(OBSOLETE_SETREUID))
5969  rb_uid_t uid;
5970 #endif
5971 
5972  check_uid_switch();
5973 
5974 #if defined(HAVE_SETRESUID) || (defined(HAVE_SETREUID) && !defined(OBSOLETE_SETREUID))
5975  uid = getuid();
5976 #endif
5977 
5978 #if defined(HAVE_SETRESUID)
5979  if (uid != euid) {
5980  if (setresuid(-1,euid,euid) < 0) rb_sys_fail(0);
5981  SAVED_USER_ID = euid;
5982  }
5983  else {
5984  if (setresuid(-1,euid,-1) < 0) rb_sys_fail(0);
5985  }
5986 #elif defined(HAVE_SETREUID) && !defined(OBSOLETE_SETREUID)
5987  if (setreuid(-1, euid) < 0) rb_sys_fail(0);
5988  if (uid != euid) {
5989  if (setreuid(euid,uid) < 0) rb_sys_fail(0);
5990  if (setreuid(uid,euid) < 0) rb_sys_fail(0);
5991  SAVED_USER_ID = euid;
5992  }
5993 #elif defined HAVE_SETEUID
5994  if (seteuid(euid) < 0) rb_sys_fail(0);
5995 #elif defined HAVE_SETUID
5996  if (geteuid() == 0) rb_sys_fail(0);
5997  if (setuid(euid) < 0) rb_sys_fail(0);
5998 #else
5999  rb_notimplement();
6000 #endif
6001  return euid;
6002 }
6003 
6004 
6005 /*
6006  * call-seq:
6007  * Process::UID.grant_privilege(user) -> fixnum
6008  * Process::UID.eid= user -> fixnum
6009  *
6010  * Set the effective user ID, and if possible, the saved user ID of
6011  * the process to the given _user_. Returns the new
6012  * effective user ID. Not available on all platforms.
6013  *
6014  * [Process.uid, Process.euid] #=> [0, 0]
6015  * Process::UID.grant_privilege(31) #=> 31
6016  * [Process.uid, Process.euid] #=> [0, 31]
6017  */
6018 
6019 static VALUE
6021 {
6023  rb_seteuid_core(OBJ2UID(id));
6024  return id;
6025 }
6026 
6027 
6028 /*
6029  * call-seq:
6030  * Process.egid -> fixnum
6031  * Process::GID.eid -> fixnum
6032  * Process::Sys.geteid -> fixnum
6033  *
6034  * Returns the effective group ID for this process. Not available on
6035  * all platforms.
6036  *
6037  * Process.egid #=> 500
6038  */
6039 
6040 static VALUE
6042 {
6043  rb_gid_t egid = getegid();
6044 
6045  return GIDT2NUM(egid);
6046 }
6047 
6048 #if defined(HAVE_SETRESGID) || defined(HAVE_SETREGID) || defined(HAVE_SETEGID) || defined(HAVE_SETGID) || defined(_POSIX_SAVED_IDS)
6049 /*
6050  * call-seq:
6051  * Process.egid = fixnum -> fixnum
6052  *
6053  * Sets the effective group ID for this process. Not available on all
6054  * platforms.
6055  */
6056 
6057 static VALUE
6058 proc_setegid(VALUE obj, VALUE egid)
6059 {
6060 #if defined(HAVE_SETRESGID) || defined(HAVE_SETREGID) || defined(HAVE_SETEGID) || defined(HAVE_SETGID)
6061  rb_gid_t gid;
6063 #endif
6064 
6065  check_gid_switch();
6066 
6067 #if defined(HAVE_SETRESGID) || defined(HAVE_SETREGID) || defined(HAVE_SETEGID) || defined(HAVE_SETGID)
6068  gid = OBJ2GID(egid);
6069 #endif
6070 
6071 #if defined(HAVE_SETRESGID)
6072  if (setresgid(-1, gid, -1) < 0) rb_sys_fail(0);
6073 #elif defined HAVE_SETREGID
6074  if (setregid(-1, gid) < 0) rb_sys_fail(0);
6075 #elif defined HAVE_SETEGID
6076  if (setegid(gid) < 0) rb_sys_fail(0);
6077 #elif defined HAVE_SETGID
6078  if (gid == getgid()) {
6079  if (setgid(gid) < 0) rb_sys_fail(0);
6080  }
6081  else {
6082  rb_notimplement();
6083  }
6084 #else
6085  rb_notimplement();
6086 #endif
6087  return egid;
6088 }
6089 #endif
6090 
6091 #if defined(HAVE_SETRESGID) || defined(HAVE_SETREGID) || defined(HAVE_SETEGID) || defined(HAVE_SETGID)
6092 #define proc_setegid_m proc_setegid
6093 #else
6094 #define proc_setegid_m rb_f_notimplement
6095 #endif
6096 
6097 static rb_gid_t
6098 rb_setegid_core(rb_gid_t egid)
6099 {
6100 #if defined(HAVE_SETRESGID) || (defined(HAVE_SETREGID) && !defined(OBSOLETE_SETREGID))
6101  rb_gid_t gid;
6102 #endif
6103 
6104  check_gid_switch();
6105 
6106 #if defined(HAVE_SETRESGID) || (defined(HAVE_SETREGID) && !defined(OBSOLETE_SETREGID))
6107  gid = getgid();
6108 #endif
6109 
6110 #if defined(HAVE_SETRESGID)
6111  if (gid != egid) {
6112  if (setresgid(-1,egid,egid) < 0) rb_sys_fail(0);
6113  SAVED_GROUP_ID = egid;
6114  }
6115  else {
6116  if (setresgid(-1,egid,-1) < 0) rb_sys_fail(0);
6117  }
6118 #elif defined(HAVE_SETREGID) && !defined(OBSOLETE_SETREGID)
6119  if (setregid(-1, egid) < 0) rb_sys_fail(0);
6120  if (gid != egid) {
6121  if (setregid(egid,gid) < 0) rb_sys_fail(0);
6122  if (setregid(gid,egid) < 0) rb_sys_fail(0);
6123  SAVED_GROUP_ID = egid;
6124  }
6125 #elif defined HAVE_SETEGID
6126  if (setegid(egid) < 0) rb_sys_fail(0);
6127 #elif defined HAVE_SETGID
6128  if (geteuid() == 0 /* root user */) rb_sys_fail(0);
6129  if (setgid(egid) < 0) rb_sys_fail(0);
6130 #else
6131  rb_notimplement();
6132 #endif
6133  return egid;
6134 }
6135 
6136 
6137 /*
6138  * call-seq:
6139  * Process::GID.grant_privilege(group) -> fixnum
6140  * Process::GID.eid = group -> fixnum
6141  *
6142  * Set the effective group ID, and if possible, the saved group ID of
6143  * the process to the given _group_. Returns the new
6144  * effective group ID. Not available on all platforms.
6145  *
6146  * [Process.gid, Process.egid] #=> [0, 0]
6147  * Process::GID.grant_privilege(31) #=> 33
6148  * [Process.gid, Process.egid] #=> [0, 33]
6149  */
6150 
6151 static VALUE
6153 {
6155  rb_setegid_core(OBJ2GID(id));
6156  return id;
6157 }
6158 
6159 
6160 /*
6161  * call-seq:
6162  * Process::UID.re_exchangeable? -> true or false
6163  *
6164  * Returns +true+ if the real and effective user IDs of a
6165  * process may be exchanged on the current platform.
6166  *
6167  */
6168 
6169 static VALUE
6171 {
6172 #if defined(HAVE_SETRESUID)
6173  return Qtrue;
6174 #elif defined(HAVE_SETREUID) && !defined(OBSOLETE_SETREUID)
6175  return Qtrue;
6176 #else
6177  return Qfalse;
6178 #endif
6179 }
6180 
6181 
6182 /*
6183  * call-seq:
6184  * Process::UID.re_exchange -> fixnum
6185  *
6186  * Exchange real and effective user IDs and return the new effective
6187  * user ID. Not available on all platforms.
6188  *
6189  * [Process.uid, Process.euid] #=> [0, 31]
6190  * Process::UID.re_exchange #=> 0
6191  * [Process.uid, Process.euid] #=> [31, 0]
6192  */
6193 
6194 static VALUE
6196 {
6197  rb_uid_t uid;
6198 #if defined(HAVE_SETRESUID) || (defined(HAVE_SETREUID) && !defined(OBSOLETE_SETREUID))
6199  rb_uid_t euid;
6200 #endif
6201 
6202  check_uid_switch();
6203 
6204  uid = getuid();
6205 #if defined(HAVE_SETRESUID) || (defined(HAVE_SETREUID) && !defined(OBSOLETE_SETREUID))
6206  euid = geteuid();
6207 #endif
6208 
6209 #if defined(HAVE_SETRESUID)
6210  if (setresuid(euid, uid, uid) < 0) rb_sys_fail(0);
6211  SAVED_USER_ID = uid;
6212 #elif defined(HAVE_SETREUID) && !defined(OBSOLETE_SETREUID)
6213  if (setreuid(euid,uid) < 0) rb_sys_fail(0);
6214  SAVED_USER_ID = uid;
6215 #else
6216  rb_notimplement();
6217 #endif
6218  return UIDT2NUM(uid);
6219 }
6220 
6221 
6222 /*
6223  * call-seq:
6224  * Process::GID.re_exchangeable? -> true or false
6225  *
6226  * Returns +true+ if the real and effective group IDs of a
6227  * process may be exchanged on the current platform.
6228  *
6229  */
6230 
6231 static VALUE
6233 {
6234 #if defined(HAVE_SETRESGID)
6235  return Qtrue;
6236 #elif defined(HAVE_SETREGID) && !defined(OBSOLETE_SETREGID)
6237  return Qtrue;
6238 #else
6239  return Qfalse;
6240 #endif
6241 }
6242 
6243 
6244 /*
6245  * call-seq:
6246  * Process::GID.re_exchange -> fixnum
6247  *
6248  * Exchange real and effective group IDs and return the new effective
6249  * group ID. Not available on all platforms.
6250  *
6251  * [Process.gid, Process.egid] #=> [0, 33]
6252  * Process::GID.re_exchange #=> 0
6253  * [Process.gid, Process.egid] #=> [33, 0]
6254  */
6255 
6256 static VALUE
6258 {
6259  rb_gid_t gid;
6260 #if defined(HAVE_SETRESGID) || (defined(HAVE_SETREGID) && !defined(OBSOLETE_SETREGID))
6261  rb_gid_t egid;
6262 #endif
6263 
6264  check_gid_switch();
6265 
6266  gid = getgid();
6267 #if defined(HAVE_SETRESGID) || (defined(HAVE_SETREGID) && !defined(OBSOLETE_SETREGID))
6268  egid = getegid();
6269 #endif
6270 
6271 #if defined(HAVE_SETRESGID)
6272  if (setresgid(egid, gid, gid) < 0) rb_sys_fail(0);
6273  SAVED_GROUP_ID = gid;
6274 #elif defined(HAVE_SETREGID) && !defined(OBSOLETE_SETREGID)
6275  if (setregid(egid,gid) < 0) rb_sys_fail(0);
6276  SAVED_GROUP_ID = gid;
6277 #else
6278  rb_notimplement();
6279 #endif
6280  return GIDT2NUM(gid);
6281 }
6282 
6283 /* [MG] :FIXME: Is this correct? I'm not sure how to phrase this. */
6284 
6285 /*
6286  * call-seq:
6287  * Process::UID.sid_available? -> true or false
6288  *
6289  * Returns +true+ if the current platform has saved user
6290  * ID functionality.
6291  *
6292  */
6293 
6294 static VALUE
6296 {
6297 #if defined(HAVE_SETRESUID) || defined(HAVE_SETEUID) || defined(_POSIX_SAVED_IDS)
6298  return Qtrue;
6299 #else
6300  return Qfalse;
6301 #endif
6302 }
6303 
6304 
6305 #if defined(HAVE_SETRESUID) || defined(HAVE_SETEUID) || defined(_POSIX_SAVED_IDS)
6306 static VALUE
6307 p_uid_sw_ensure(rb_uid_t id)
6308 {
6309  under_uid_switch = 0;
6310  id = rb_seteuid_core(id);
6311  return UIDT2NUM(id);
6312 }
6313 
6314 
6315 /*
6316  * call-seq:
6317  * Process::UID.switch -> fixnum
6318  * Process::UID.switch {|| block} -> object
6319  *
6320  * Switch the effective and real user IDs of the current process. If
6321  * a <em>block</em> is given, the user IDs will be switched back
6322  * after the block is executed. Returns the new effective user ID if
6323  * called without a block, and the return value of the block if one
6324  * is given.
6325  *
6326  */
6327 
6328 static VALUE
6329 p_uid_switch(VALUE obj)
6330 {
6331  rb_uid_t uid, euid;
6332 
6333  check_uid_switch();
6334 
6335  uid = getuid();
6336  euid = geteuid();
6337 
6338  if (uid != euid) {
6339  proc_seteuid(uid);
6340  if (rb_block_given_p()) {
6341  under_uid_switch = 1;
6342  return rb_ensure(rb_yield, Qnil, p_uid_sw_ensure, SAVED_USER_ID);
6343  }
6344  else {
6345  return UIDT2NUM(euid);
6346  }
6347  }
6348  else if (euid != SAVED_USER_ID) {
6349  proc_seteuid(SAVED_USER_ID);
6350  if (rb_block_given_p()) {
6351  under_uid_switch = 1;
6352  return rb_ensure(rb_yield, Qnil, p_uid_sw_ensure, euid);
6353  }
6354  else {
6355  return UIDT2NUM(uid);
6356  }
6357  }
6358  else {
6359  errno = EPERM;
6360  rb_sys_fail(0);
6361  }
6362 
6363  UNREACHABLE;
6364 }
6365 #else
6366 static VALUE
6368 {
6369  under_uid_switch = 0;
6370  return p_uid_exchange(obj);
6371 }
6372 
6373 static VALUE
6375 {
6376  rb_uid_t uid, euid;
6377 
6378  check_uid_switch();
6379 
6380  uid = getuid();
6381  euid = geteuid();
6382 
6383  if (uid == euid) {
6384  errno = EPERM;
6385  rb_sys_fail(0);
6386  }
6387  p_uid_exchange(obj);
6388  if (rb_block_given_p()) {
6389  under_uid_switch = 1;
6390  return rb_ensure(rb_yield, Qnil, p_uid_sw_ensure, obj);
6391  }
6392  else {
6393  return UIDT2NUM(euid);
6394  }
6395 }
6396 #endif
6397 
6398 
6399 /* [MG] :FIXME: Is this correct? I'm not sure how to phrase this. */
6400 
6401 /*
6402  * call-seq:
6403  * Process::GID.sid_available? -> true or false
6404  *
6405  * Returns +true+ if the current platform has saved group
6406  * ID functionality.
6407  *
6408  */
6409 
6410 static VALUE
6412 {
6413 #if defined(HAVE_SETRESGID) || defined(HAVE_SETEGID) || defined(_POSIX_SAVED_IDS)
6414  return Qtrue;
6415 #else
6416  return Qfalse;
6417 #endif
6418 }
6419 
6420 #if defined(HAVE_SETRESGID) || defined(HAVE_SETEGID) || defined(_POSIX_SAVED_IDS)
6421 static VALUE
6422 p_gid_sw_ensure(rb_gid_t id)
6423 {
6424  under_gid_switch = 0;
6425  id = rb_setegid_core(id);
6426  return GIDT2NUM(id);
6427 }
6428 
6429 
6430 /*
6431  * call-seq:
6432  * Process::GID.switch -> fixnum
6433  * Process::GID.switch {|| block} -> object
6434  *
6435  * Switch the effective and real group IDs of the current process. If
6436  * a <em>block</em> is given, the group IDs will be switched back
6437  * after the block is executed. Returns the new effective group ID if
6438  * called without a block, and the return value of the block if one
6439  * is given.
6440  *
6441  */
6442 
6443 static VALUE
6444 p_gid_switch(VALUE obj)
6445 {
6446  rb_gid_t gid, egid;
6447 
6448  check_gid_switch();
6449 
6450  gid = getgid();
6451  egid = getegid();
6452 
6453  if (gid != egid) {
6454  proc_setegid(obj, GIDT2NUM(gid));
6455  if (rb_block_given_p()) {
6456  under_gid_switch = 1;
6457  return rb_ensure(rb_yield, Qnil, p_gid_sw_ensure, SAVED_GROUP_ID);
6458  }
6459  else {
6460  return GIDT2NUM(egid);
6461  }
6462  }
6463  else if (egid != SAVED_GROUP_ID) {
6464  proc_setegid(obj, GIDT2NUM(SAVED_GROUP_ID));
6465  if (rb_block_given_p()) {
6466  under_gid_switch = 1;
6467  return rb_ensure(rb_yield, Qnil, p_gid_sw_ensure, egid);
6468  }
6469  else {
6470  return GIDT2NUM(gid);
6471  }
6472  }
6473  else {
6474  errno = EPERM;
6475  rb_sys_fail(0);
6476  }
6477 
6478  UNREACHABLE;
6479 }
6480 #else
6481 static VALUE
6483 {
6484  under_gid_switch = 0;
6485  return p_gid_exchange(obj);
6486 }
6487 
6488 static VALUE
6490 {
6491  rb_gid_t gid, egid;
6492 
6493  check_gid_switch();
6494 
6495  gid = getgid();
6496  egid = getegid();
6497 
6498  if (gid == egid) {
6499  errno = EPERM;
6500  rb_sys_fail(0);
6501  }
6502  p_gid_exchange(obj);
6503  if (rb_block_given_p()) {
6504  under_gid_switch = 1;
6505  return rb_ensure(rb_yield, Qnil, p_gid_sw_ensure, obj);
6506  }
6507  else {
6508  return GIDT2NUM(egid);
6509  }
6510 }
6511 #endif
6512 
6513 
6514 #if defined(HAVE_TIMES)
6515 /*
6516  * call-seq:
6517  * Process.times -> aStructTms
6518  *
6519  * Returns a <code>Tms</code> structure (see <code>Struct::Tms</code>)
6520  * that contains user and system CPU times for this process,
6521  * and also for children processes.
6522  *
6523  * t = Process.times
6524  * [ t.utime, t.stime, t.cutime, t.cstime ] #=> [0.0, 0.02, 0.00, 0.00]
6525  */
6526 
6527 VALUE
6528 rb_proc_times(VALUE obj)
6529 {
6530  const double hertz =
6531 #ifdef HAVE__SC_CLK_TCK
6532  (double)sysconf(_SC_CLK_TCK);
6533 #else
6534 #ifndef HZ
6535 # ifdef CLK_TCK
6536 # define HZ CLK_TCK
6537 # else
6538 # define HZ 60
6539 # endif
6540 #endif /* HZ */
6541  HZ;
6542 #endif
6543  struct tms buf;
6544  volatile VALUE utime, stime, cutime, sctime;
6545 
6546  times(&buf);
6547  return rb_struct_new(rb_cProcessTms,
6548  utime = DBL2NUM(buf.tms_utime / hertz),
6549  stime = DBL2NUM(buf.tms_stime / hertz),
6550  cutime = DBL2NUM(buf.tms_cutime / hertz),
6551  sctime = DBL2NUM(buf.tms_cstime / hertz));
6552 }
6553 #else
6554 #define rb_proc_times rb_f_notimplement
6555 #endif
6556 
6561 
6562 
6563 /*
6564  * The <code>Process</code> module is a collection of methods used to
6565  * manipulate processes.
6566  */
6567 
6568 void
6570 {
6573  rb_define_global_function("exec", rb_f_exec, -1);
6576  rb_define_global_function("system", rb_f_system, -1);
6577  rb_define_global_function("spawn", rb_f_spawn, -1);
6578  rb_define_global_function("sleep", rb_f_sleep, -1);
6579  rb_define_global_function("exit", rb_f_exit, -1);
6580  rb_define_global_function("abort", rb_f_abort, -1);
6581 
6582  rb_mProcess = rb_define_module("Process");
6583 
6584 #ifdef WNOHANG
6585  /* see Process.wait */
6586  rb_define_const(rb_mProcess, "WNOHANG", INT2FIX(WNOHANG));
6587 #else
6588  /* see Process.wait */
6589  rb_define_const(rb_mProcess, "WNOHANG", INT2FIX(0));
6590 #endif
6591 #ifdef WUNTRACED
6592  /* see Process.wait */
6593  rb_define_const(rb_mProcess, "WUNTRACED", INT2FIX(WUNTRACED));
6594 #else
6595  /* see Process.wait */
6596  rb_define_const(rb_mProcess, "WUNTRACED", INT2FIX(0));
6597 #endif
6598 
6599  rb_define_singleton_method(rb_mProcess, "exec", rb_f_exec, -1);
6600  rb_define_singleton_method(rb_mProcess, "fork", rb_f_fork, 0);
6601  rb_define_singleton_method(rb_mProcess, "spawn", rb_f_spawn, -1);
6602  rb_define_singleton_method(rb_mProcess, "exit!", rb_f_exit_bang, -1);
6603  rb_define_singleton_method(rb_mProcess, "exit", rb_f_exit, -1);
6604  rb_define_singleton_method(rb_mProcess, "abort", rb_f_abort, -1);
6605 
6606  rb_define_module_function(rb_mProcess, "kill", rb_f_kill, -1); /* in signal.c */
6607  rb_define_module_function(rb_mProcess, "wait", proc_wait, -1);
6608  rb_define_module_function(rb_mProcess, "wait2", proc_wait2, -1);
6609  rb_define_module_function(rb_mProcess, "waitpid", proc_wait, -1);
6610  rb_define_module_function(rb_mProcess, "waitpid2", proc_wait2, -1);
6611  rb_define_module_function(rb_mProcess, "waitall", proc_waitall, 0);
6612  rb_define_module_function(rb_mProcess, "detach", proc_detach, 1);
6613 
6614  rb_cProcessStatus = rb_define_class_under(rb_mProcess, "Status", rb_cObject);
6616 
6623 
6625 
6634 
6635  rb_define_module_function(rb_mProcess, "pid", get_pid, 0);
6636  rb_define_module_function(rb_mProcess, "ppid", get_ppid, 0);
6637 
6638  rb_define_module_function(rb_mProcess, "getpgrp", proc_getpgrp, 0);
6639  rb_define_module_function(rb_mProcess, "setpgrp", proc_setpgrp, 0);
6640  rb_define_module_function(rb_mProcess, "getpgid", proc_getpgid, 1);
6641  rb_define_module_function(rb_mProcess, "setpgid", proc_setpgid, 2);
6642 
6643  rb_define_module_function(rb_mProcess, "getsid", proc_getsid, -1);
6644  rb_define_module_function(rb_mProcess, "setsid", proc_setsid, 0);
6645 
6646  rb_define_module_function(rb_mProcess, "getpriority", proc_getpriority, 2);
6647  rb_define_module_function(rb_mProcess, "setpriority", proc_setpriority, 3);
6648 
6649 #ifdef HAVE_GETPRIORITY
6650  /* see Process.setpriority */
6651  rb_define_const(rb_mProcess, "PRIO_PROCESS", INT2FIX(PRIO_PROCESS));
6652  /* see Process.setpriority */
6653  rb_define_const(rb_mProcess, "PRIO_PGRP", INT2FIX(PRIO_PGRP));
6654  /* see Process.setpriority */
6655  rb_define_const(rb_mProcess, "PRIO_USER", INT2FIX(PRIO_USER));
6656 #endif
6657 
6658  rb_define_module_function(rb_mProcess, "getrlimit", proc_getrlimit, 1);
6659  rb_define_module_function(rb_mProcess, "setrlimit", proc_setrlimit, -1);
6660 #if defined(RLIM2NUM) && defined(RLIM_INFINITY)
6661  {
6662  VALUE inf = RLIM2NUM(RLIM_INFINITY);
6663 #ifdef RLIM_SAVED_MAX
6664  {
6665  VALUE v = RLIM_INFINITY == RLIM_SAVED_MAX ? inf : RLIM2NUM(RLIM_SAVED_MAX);
6666  /* see Process.setrlimit */
6667  rb_define_const(rb_mProcess, "RLIM_SAVED_MAX", v);
6668  }
6669 #endif
6670  /* see Process.setrlimit */
6671  rb_define_const(rb_mProcess, "RLIM_INFINITY", inf);
6672 #ifdef RLIM_SAVED_CUR
6673  {
6674  VALUE v = RLIM_INFINITY == RLIM_SAVED_CUR ? inf : RLIM2NUM(RLIM_SAVED_CUR);
6675  /* see Process.setrlimit */
6676  rb_define_const(rb_mProcess, "RLIM_SAVED_CUR", v);
6677  }
6678 #endif
6679  }
6680 #ifdef RLIMIT_AS
6681  /* Maximum size of the process's virtual memory (address space) in bytes.
6682  *
6683  * see the system getrlimit(2) manual for details.
6684  */
6685  rb_define_const(rb_mProcess, "RLIMIT_AS", INT2FIX(RLIMIT_AS));
6686 #endif
6687 #ifdef RLIMIT_CORE
6688  /* Maximum size of the core file.
6689  *
6690  * see the system getrlimit(2) manual for details.
6691  */
6692  rb_define_const(rb_mProcess, "RLIMIT_CORE", INT2FIX(RLIMIT_CORE));
6693 #endif
6694 #ifdef RLIMIT_CPU
6695  /* CPU time limit in seconds.
6696  *
6697  * see the system getrlimit(2) manual for details.
6698  */
6699  rb_define_const(rb_mProcess, "RLIMIT_CPU", INT2FIX(RLIMIT_CPU));
6700 #endif
6701 #ifdef RLIMIT_DATA
6702  /* Maximum size of the process's data segment.
6703  *
6704  * see the system getrlimit(2) manual for details.
6705  */
6706  rb_define_const(rb_mProcess, "RLIMIT_DATA", INT2FIX(RLIMIT_DATA));
6707 #endif
6708 #ifdef RLIMIT_FSIZE
6709  /* Maximum size of files that the process may create.
6710  *
6711  * see the system getrlimit(2) manual for details.
6712  */
6713  rb_define_const(rb_mProcess, "RLIMIT_FSIZE", INT2FIX(RLIMIT_FSIZE));
6714 #endif
6715 #ifdef RLIMIT_MEMLOCK
6716  /* Maximum number of bytes of memory that may be locked into RAM.
6717  *
6718  * see the system getrlimit(2) manual for details.
6719  */
6720  rb_define_const(rb_mProcess, "RLIMIT_MEMLOCK", INT2FIX(RLIMIT_MEMLOCK));
6721 #endif
6722 #ifdef RLIMIT_MSGQUEUE
6723  /* Specifies the limit on the number of bytes that can be allocated
6724  * for POSIX message queues for the real user ID of the calling process.
6725  *
6726  * see the system getrlimit(2) manual for details.
6727  */
6728  rb_define_const(rb_mProcess, "RLIMIT_MSGQUEUE", INT2FIX(RLIMIT_MSGQUEUE));
6729 #endif
6730 #ifdef RLIMIT_NICE
6731  /* Specifies a ceiling to which the process's nice value can be raised.
6732  *
6733  * see the system getrlimit(2) manual for details.
6734  */
6735  rb_define_const(rb_mProcess, "RLIMIT_NICE", INT2FIX(RLIMIT_NICE));
6736 #endif
6737 #ifdef RLIMIT_NOFILE
6738  /* Specifies a value one greater than the maximum file descriptor
6739  * number that can be opened by this process.
6740  *
6741  * see the system getrlimit(2) manual for details.
6742  */
6743  rb_define_const(rb_mProcess, "RLIMIT_NOFILE", INT2FIX(RLIMIT_NOFILE));
6744 #endif
6745 #ifdef RLIMIT_NPROC
6746  /* The maximum number of processes that can be created for the
6747  * real user ID of the calling process.
6748  *
6749  * see the system getrlimit(2) manual for details.
6750  */
6751  rb_define_const(rb_mProcess, "RLIMIT_NPROC", INT2FIX(RLIMIT_NPROC));
6752 #endif
6753 #ifdef RLIMIT_RSS
6754  /* Specifies the limit (in pages) of the process's resident set.
6755  *
6756  * see the system getrlimit(2) manual for details.
6757  */
6758  rb_define_const(rb_mProcess, "RLIMIT_RSS", INT2FIX(RLIMIT_RSS));
6759 #endif
6760 #ifdef RLIMIT_RTPRIO
6761  /* Specifies a ceiling on the real-time priority that may be set for this process.
6762  *
6763  * see the system getrlimit(2) manual for details.
6764  */
6765  rb_define_const(rb_mProcess, "RLIMIT_RTPRIO", INT2FIX(RLIMIT_RTPRIO));
6766 #endif
6767 #ifdef RLIMIT_RTTIME
6768  /* Specifies limit on CPU time this process scheduled under a real-time
6769  * scheduling policy can consume.
6770  *
6771  * see the system getrlimit(2) manual for details.
6772  */
6773  rb_define_const(rb_mProcess, "RLIMIT_RTTIME", INT2FIX(RLIMIT_RTTIME));
6774 #endif
6775 #ifdef RLIMIT_SBSIZE
6776  /* Maximum size of the socket buffer.
6777  */
6778  rb_define_const(rb_mProcess, "RLIMIT_SBSIZE", INT2FIX(RLIMIT_SBSIZE));
6779 #endif
6780 #ifdef RLIMIT_SIGPENDING
6781  /* Specifies a limit on the number of signals that may be queued for
6782  * the real user ID of the calling process.
6783  *
6784  * see the system getrlimit(2) manual for details.
6785  */
6786  rb_define_const(rb_mProcess, "RLIMIT_SIGPENDING", INT2FIX(RLIMIT_SIGPENDING));
6787 #endif
6788 #ifdef RLIMIT_STACK
6789  /* Maximum size of the stack, in bytes.
6790  *
6791  * see the system getrlimit(2) manual for details.
6792  */
6793  rb_define_const(rb_mProcess, "RLIMIT_STACK", INT2FIX(RLIMIT_STACK));
6794 #endif
6795 #endif
6796 
6797  rb_define_module_function(rb_mProcess, "uid", proc_getuid, 0);
6798  rb_define_module_function(rb_mProcess, "uid=", proc_setuid, 1);
6799  rb_define_module_function(rb_mProcess, "gid", proc_getgid, 0);
6800  rb_define_module_function(rb_mProcess, "gid=", proc_setgid, 1);
6801  rb_define_module_function(rb_mProcess, "euid", proc_geteuid, 0);
6802  rb_define_module_function(rb_mProcess, "euid=", proc_seteuid_m, 1);
6803  rb_define_module_function(rb_mProcess, "egid", proc_getegid, 0);
6804  rb_define_module_function(rb_mProcess, "egid=", proc_setegid_m, 1);
6805  rb_define_module_function(rb_mProcess, "initgroups", proc_initgroups, 2);
6806  rb_define_module_function(rb_mProcess, "groups", proc_getgroups, 0);
6807  rb_define_module_function(rb_mProcess, "groups=", proc_setgroups, 1);
6808  rb_define_module_function(rb_mProcess, "maxgroups", proc_getmaxgroups, 0);
6809  rb_define_module_function(rb_mProcess, "maxgroups=", proc_setmaxgroups, 1);
6810 
6811  rb_define_module_function(rb_mProcess, "daemon", proc_daemon, -1);
6812 
6813  rb_define_module_function(rb_mProcess, "times", rb_proc_times, 0);
6814 
6815 #if defined(HAVE_TIMES) || defined(_WIN32)
6816  rb_cProcessTms = rb_struct_define("Tms", "utime", "stime", "cutime", "cstime", NULL);
6817 #endif
6818 
6819  SAVED_USER_ID = geteuid();
6820  SAVED_GROUP_ID = getegid();
6821 
6822  rb_mProcUID = rb_define_module_under(rb_mProcess, "UID");
6823  rb_mProcGID = rb_define_module_under(rb_mProcess, "GID");
6824 
6825  rb_define_module_function(rb_mProcUID, "rid", proc_getuid, 0);
6826  rb_define_module_function(rb_mProcGID, "rid", proc_getgid, 0);
6827  rb_define_module_function(rb_mProcUID, "eid", proc_geteuid, 0);
6828  rb_define_module_function(rb_mProcGID, "eid", proc_getegid, 0);
6829  rb_define_module_function(rb_mProcUID, "change_privilege", p_uid_change_privilege, 1);
6830  rb_define_module_function(rb_mProcGID, "change_privilege", p_gid_change_privilege, 1);
6831  rb_define_module_function(rb_mProcUID, "grant_privilege", p_uid_grant_privilege, 1);
6832  rb_define_module_function(rb_mProcGID, "grant_privilege", p_gid_grant_privilege, 1);
6833  rb_define_alias(rb_singleton_class(rb_mProcUID), "eid=", "grant_privilege");
6834  rb_define_alias(rb_singleton_class(rb_mProcGID), "eid=", "grant_privilege");
6835  rb_define_module_function(rb_mProcUID, "re_exchange", p_uid_exchange, 0);
6836  rb_define_module_function(rb_mProcGID, "re_exchange", p_gid_exchange, 0);
6837  rb_define_module_function(rb_mProcUID, "re_exchangeable?", p_uid_exchangeable, 0);
6838  rb_define_module_function(rb_mProcGID, "re_exchangeable?", p_gid_exchangeable, 0);
6839  rb_define_module_function(rb_mProcUID, "sid_available?", p_uid_have_saved_id, 0);
6840  rb_define_module_function(rb_mProcGID, "sid_available?", p_gid_have_saved_id, 0);
6841  rb_define_module_function(rb_mProcUID, "switch", p_uid_switch, 0);
6842  rb_define_module_function(rb_mProcGID, "switch", p_gid_switch, 0);
6843 #ifdef p_uid_from_name
6844  rb_define_module_function(rb_mProcUID, "from_name", p_uid_from_name, 1);
6845 #endif
6846 #ifdef p_gid_from_name
6847  rb_define_module_function(rb_mProcGID, "from_name", p_gid_from_name, 1);
6848 #endif
6849 
6850  rb_mProcID_Syscall = rb_define_module_under(rb_mProcess, "Sys");
6851 
6852  rb_define_module_function(rb_mProcID_Syscall, "getuid", proc_getuid, 0);
6853  rb_define_module_function(rb_mProcID_Syscall, "geteuid", proc_geteuid, 0);
6854  rb_define_module_function(rb_mProcID_Syscall, "getgid", proc_getgid, 0);
6855  rb_define_module_function(rb_mProcID_Syscall, "getegid", proc_getegid, 0);
6856 
6857  rb_define_module_function(rb_mProcID_Syscall, "setuid", p_sys_setuid, 1);
6858  rb_define_module_function(rb_mProcID_Syscall, "setgid", p_sys_setgid, 1);
6859 
6860  rb_define_module_function(rb_mProcID_Syscall, "setruid", p_sys_setruid, 1);
6861  rb_define_module_function(rb_mProcID_Syscall, "setrgid", p_sys_setrgid, 1);
6862 
6863  rb_define_module_function(rb_mProcID_Syscall, "seteuid", p_sys_seteuid, 1);
6864  rb_define_module_function(rb_mProcID_Syscall, "setegid", p_sys_setegid, 1);
6865 
6866  rb_define_module_function(rb_mProcID_Syscall, "setreuid", p_sys_setreuid, 2);
6867  rb_define_module_function(rb_mProcID_Syscall, "setregid", p_sys_setregid, 2);
6868 
6869  rb_define_module_function(rb_mProcID_Syscall, "setresuid", p_sys_setresuid, 3);
6870  rb_define_module_function(rb_mProcID_Syscall, "setresgid", p_sys_setresgid, 3);
6871  rb_define_module_function(rb_mProcID_Syscall, "issetugid", p_sys_issetugid, 0);
6872 }
VALUE fd_dup2
Definition: internal.h:239
#define p_sys_setreuid
Definition: process.c:4914
#define proc_setegid_m
Definition: process.c:6094
static VALUE p_uid_have_saved_id(void)
Definition: process.c:6295
static int run_exec_close(VALUE ary, char *errmsg, size_t errmsg_buflen)
Definition: process.c:2683
struct timeval rb_time_interval(VALUE num)
Definition: time.c:2492
void rb_syswait(rb_pid_t pid)
Definition: process.c:3639
#define WNOHANG
Definition: win32.h:109
#define T_SYMBOL
Definition: ruby.h:502
#define proc_setpgid
Definition: process.c:4220
#define NUM2UIDT(v)
Definition: ruby.h:338
void rb_thread_schedule(void)
Definition: thread.c:1138
static VALUE rb_cProcessStatus
Definition: process.c:267
#define RUBY_VM_CHECK_INTS(th)
Definition: vm_core.h:948
Definition: st.h:108
#define redirect_close(fd)
Definition: process.c:2488
static void before_exec_async_signal_safe(void)
Definition: process.c:1054
RUBY_EXTERN VALUE rb_cData
Definition: ruby.h:1433
static VALUE proc_getgid(VALUE obj)
Definition: process.c:5363
void rb_thread_atfork(void)
Definition: thread.c:3845
static void check_exec_redirect(VALUE key, VALUE val, struct rb_execarg *eargp)
Definition: process.c:1512
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
int rb_cloexec_fcntl_dupfd(int fd, int minfd)
Definition: io.c:308
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
#define RARRAY_LEN(a)
Definition: ruby.h:899
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:4382
#define rb_hash_lookup
Definition: tcltklib.c:268
size_t strlen(const char *)
#define INT2NUM(x)
Definition: ruby.h:1178
void rb_update_max_fd(int fd)
Definition: io.c:164
int i
Definition: win32ole.c:784
struct rb_execarg * rb_execarg_get(VALUE execarg_obj)
Definition: process.c:2201
#define redirect_open(pathname, flags, perm)
Definition: process.c:2489
#define T_FIXNUM
Definition: ruby.h:497
Definition: st.h:77
#define proc_getpriority
Definition: process.c:4350
Definition: st.h:108
static VALUE save_env_i(VALUE i, VALUE ary, int argc, VALUE *argv)
Definition: process.c:2845
rb_pid_t rb_spawn_err(int argc, VALUE *argv, char *errmsg, size_t errmsg_buflen)
Definition: process.c:3714
void ruby_finalize(void)
Runs the VM finalization processes.
Definition: eval.c:138
void rb_define_virtual_variable(const char *, VALUE(*)(ANYARGS), void(*)(ANYARGS))
Definition: variable.c:606
static VALUE hide_obj(VALUE obj)
Definition: process.c:1442
static VALUE p_uid_exchange(VALUE obj)
Definition: process.c:6195
#define p_sys_setrgid
Definition: process.c:5246
#define NUM2INT(x)
Definition: ruby.h:622
#define NUM2UINT(x)
Definition: ruby.h:623
static void after_exec(void)
Definition: process.c:1108
#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:1497
static VALUE rb_f_system(int argc, VALUE *argv)
Definition: process.c:3759
int rb_io_modestr_oflags(const char *modestr)
Definition: io.c:4845
static int under_gid_switch
Definition: process.c:4707
unsigned umask_given
Definition: internal.h:224
static VALUE pst_bitand(VALUE st1, VALUE st2)
Definition: process.c:451
#define NUM2PIDT(v)
Definition: ruby.h:332
#define FilePathValue(v)
Definition: ruby.h:567
VALUE rb_mProcGID
Definition: process.c:6559
size_t len
Definition: process.c:2005
#define CLASS_OF(v)
Definition: ruby.h:448
int rb_cloexec_open(const char *pathname, int flags, mode_t mode)
Definition: io.c:209
#define WIFEXITED(w)
Definition: process.c:90
#define proc_getgroups
Definition: process.c:5494
static VALUE p_uid_exchangeable(void)
Definition: process.c:6170
#define PIDT2NUM(v)
Definition: ruby.h:329
static VALUE pst_to_s(VALUE st)
Definition: process.c:375
int rb_execarg_run_options(const struct rb_execarg *eargp, struct rb_execarg *sargp, char *errmsg, size_t errmsg_buflen)
Definition: process.c:2872
void rb_execarg_setenv(VALUE execarg_obj, VALUE env)
Definition: process.c:2228
static VALUE detach_process_pid(VALUE thread)
Definition: process.c:958
#define Qtrue
Definition: ruby.h:434
int st_insert(st_table *, st_data_t, st_data_t)
VALUE rlimit_limits
Definition: internal.h:235
static long run_exec_dup2_tmpbuf_size(long n)
Definition: process.c:2544
#define WIFSTOPPED(w)
Definition: process.c:96
unsigned uid_given
Definition: internal.h:232
Definition: io.h:63
#define proc_setpgrp
Definition: process.c:4168
VALUE rb_io_flush(VALUE)
Definition: io.c:1470
struct rb_execarg::@87::@89 cmd
int rb_env_path_tainted(void)
Definition: hash.c:2336
#define TypedData_Get_Struct(obj, type, data_type, sval)
Definition: ruby.h:1030
const int id
Definition: nkf.c:209
unsigned unsetenv_others_given
Definition: internal.h:225
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
static int check_exec_fds_1(struct rb_execarg *eargp, VALUE h, int maxhint, VALUE ary)
Definition: process.c:1811
static rb_gid_t SAVED_GROUP_ID
Definition: process.c:5712
SOCKET rb_w32_get_osfhandle(int)
Definition: win32.c:958
static VALUE p_uid_sw_ensure(VALUE obj)
Definition: process.c:6367
int execl(const char *path, const char *arg0,...)
Definition: missing-pips.c:27
int close_others_maxhint
Definition: internal.h:243
static VALUE proc_waitall(void)
Definition: process.c:908
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
VALUE rb_mProcID_Syscall
Definition: process.c:6560
VALUE rb_struct_new(VALUE,...)
Definition: struct.c:421
int rb_proc_exec(const char *str)
Definition: process.c:1308
VALUE rb_ary_push(VALUE ary, VALUE item)
Definition: array.c:822
void rb_close_before_exec(int lowfd, int maxhint, VALUE noclose_fds)
int rb_proc_exec_n(int argc, VALUE *argv, const char *prog)
Definition: process.c:1234
int fcntl(int, int,...)
Definition: win32.c:3835
int rb_thread_alone(void)
Definition: thread.c:2904
#define SYM2ID(x)
Definition: ruby.h:364
rb_pid_t rb_w32_aspawn_flags(int, const char *, char *const *, DWORD)
Definition: win32.c:1287
#define p_sys_setresuid
Definition: process.c:4939
static VALUE p_gid_have_saved_id(void)
Definition: process.c:6411
static VALUE p_gid_exchangeable(void)
Definition: process.c:6232
#define p_sys_seteuid
Definition: process.c:4889
rb_pid_t rb_fork_ruby(int *status)
void rb_str_set_len(VALUE, long)
Definition: string.c:1837
VALUE rb_protect(VALUE(*proc)(VALUE), VALUE data, int *state)
Definition: eval.c:771
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_to_int(VALUE)
Definition: object.c:2431
#define Check_Type(v, t)
Definition: ruby.h:539
void rb_raise(VALUE exc, const char *fmt,...)
Definition: error.c:1780
#define proc_daemon
Definition: process.c:5699
static int run_exec_dup2(VALUE ary, VALUE tmpbuf, struct rb_execarg *sargp, char *errmsg, size_t errmsg_buflen)
Definition: process.c:2551
rb_pid_t rb_waitpid(rb_pid_t pid, int *st, int flags)
Definition: process.c:707
static void check_gid_switch(void)
Definition: process.c:4709
VALUE rb_convert_type(VALUE, int, const char *, const char *)
Definition: object.c:2368
#define RB_GC_GUARD(v)
Definition: ruby.h:530
int rb_exec(const struct rb_exec_arg *e)
Definition: process.c:3068
#define rb_f_fork
Definition: process.c:3474
#define T_HASH
Definition: ruby.h:493
static VALUE p_gid_change_privilege(VALUE obj, VALUE id)
Definition: process.c:5743
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_f_exit(int argc, VALUE *argv)
Definition: process.c:3586
VALUE rb_eSecurityError
Definition: error.c:520
#define proc_initgroups
Definition: process.c:5571
VALUE env_modification
Definition: internal.h:244
VALUE last_status
Definition: vm_core.h:503
#define ALLOC_ARGV(n, v)
int rb_pipe(int *pipes)
Definition: io.c:5557
void rb_gc_mark(VALUE ptr)
Definition: gc.c:2598
VALUE execarg_obj
Definition: intern.h:598
#define T_ARRAY
Definition: ruby.h:492
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:1526
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
static VALUE proc_wait(int argc, VALUE *argv)
Definition: process.c:834
static void * rb_waitpid_blocking(void *data)
Definition: process.c:688
VALUE rb_block_call(VALUE, ID, int, VALUE *, VALUE(*)(ANYARGS), VALUE)
Definition: vm_eval.c:1131
static const rb_data_type_t exec_arg_data_type
Definition: process.c:1354
#define proc_getpgrp
Definition: process.c:4139
int rb_exec_err(const struct rb_exec_arg *e, char *errmsg, size_t errmsg_buflen)
Definition: process.c:3062
#define FIXNUM_P(f)
Definition: ruby.h:355
#define EXIT_SUCCESS
Definition: process.c:41
static VALUE pst_wtermsig(VALUE st)
Definition: process.c:550
void rb_undef_method(VALUE klass, const char *name)
Definition: class.c:1362
int wait(int *status)
Definition: win32.c:4255
#define GetOpenFile(obj, fp)
Definition: io.h:120
VALUE envp_str
Definition: internal.h:220
#define before_fork()
Definition: process.c:1114
void rb_thread_start_timer_thread(void)
Definition: thread.c:3782
#define p_sys_setegid
Definition: process.c:5269
#define RHASH_TBL(h)
Definition: ruby.h:928
static VALUE envtbl
Definition: hash.c:43
static VALUE pst_wstopsig(VALUE st)
Definition: process.c:510
static double inf(void)
Definition: isinf.c:53
VALUE rb_thread_local_aref(VALUE, ID)
Definition: thread.c:2663
VALUE rb_str_buf_cat(VALUE, const char *, long)
Definition: string.c:1947
Win32OLEIDispatch * p
Definition: win32ole.c:786
static VALUE pst_wifsignaled(VALUE st)
Definition: process.c:529
void rb_exc_raise(VALUE mesg)
Definition: eval.c:527
unsigned unsetenv_others_do
Definition: internal.h:226
int args
Definition: win32ole.c:785
static rb_pid_t rb_spawn_process(struct rb_execarg *eargp, char *errmsg, size_t errmsg_buflen)
Definition: process.c:3647
VALUE rb_singleton_class(VALUE obj)
Returns the singleton class of obj.
Definition: class.c:1470
#define preserving_errno(stmts)
Definition: process.c:136
rb_gid_t getegid(void)
Definition: win32.c:2413
#define RB_TYPE_P(obj, type)
Definition: ruby.h:1537
#define fail()
VALUE rb_last_status_get(void)
Definition: process.c:270
#define MEMZERO(p, type, n)
Definition: ruby.h:1241
static void before_exec_non_async_signal_safe(void)
Definition: process.c:1068
void rb_execarg_fixup(VALUE execarg_obj)
Definition: process.c:2254
static VALUE proc_wait2(int argc, VALUE *argv)
Definition: process.c:879
#define proc_setsid
Definition: process.c:4313
static rb_gid_t rb_setegid_core(rb_gid_t egid)
Definition: process.c:6098
void rb_thread_sleep(int)
Definition: thread.c:1115
static void mark_exec_arg(void *ptr)
Definition: process.c:1318
VALUE rb_marshal_dump(VALUE, VALUE)
Definition: marshal.c:2111
rb_gid_t gid
Definition: internal.h:238
VALUE rb_class_new_instance(int, VALUE *, VALUE)
Definition: object.c:1775
int execv(const char *path, char *const argv[])
Definition: missing-pips.c:32
static VALUE rb_f_exit_bang(int argc, VALUE *argv, VALUE obj)
Definition: process.c:3512
#define ALLOC_N(type, n)
Definition: ruby.h:1223
int rb_block_given_p(void)
Definition: eval.c:672
int getrlimit(int resource, struct rlimit *rlp)
Definition: missing-pips.c:48
#define val
RUBY_EXTERN VALUE rb_cObject
Definition: ruby.h:1426
static VALUE rb_f_spawn(int argc, VALUE *argv)
Definition: process.c:4044
static rb_uid_t SAVED_USER_ID
Definition: process.c:5013
VALUE rb_eRuntimeError
Definition: error.c:510
IUnknown DWORD
Definition: win32ole.c:149
#define proc_getmaxgroups
Definition: process.c:5591
static VALUE proc_detach(VALUE obj, VALUE pid)
Definition: process.c:1033
const char * ruby_signal_name(int)
Definition: signal.c:237
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
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_str_cat2(VALUE, const char *)
Definition: string.c:1982
VALUE rb_ary_new(void)
Definition: array.c:424
VALUE rb_str_buf_cat2(VALUE, const char *)
Definition: string.c:1957
static void after_exec_async_signal_safe(void)
Definition: process.c:1091
#define p_gid_from_name
Definition: process.c:191
static VALUE pst_wifexited(VALUE st)
Definition: process.c:570
VALUE rb_iv_get(VALUE, const char *)
Definition: variable.c:2583
rb_uid_t uid
Definition: internal.h:237
#define NIL_P(v)
Definition: ruby.h:446
static void after_exec_non_async_signal_safe(void)
Definition: process.c:1099
void rb_thread_stop_timer_thread(int close_anyway)
Definition: thread.c:3768
int st_delete(st_table *, st_data_t *, st_data_t *)
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: internal.h:234
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)
void rb_define_const(VALUE, const char *, VALUE)
Definition: variable.c:2202
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
#define TOUPPER(c)
Definition: ruby.h:1640
void rb_sys_fail_str(VALUE mesg)
Definition: error.c:1905
static VALUE rb_check_exec_env(VALUE hash)
Definition: process.c:1929
#define TYPE(x)
Definition: ruby.h:513
int argc
Definition: ruby.c:130
int setegid(pid_t pid)
#define Qfalse
Definition: ruby.h:433
#define rb_sourcefile()
Definition: tcltklib.c:97
mode_t umask(mode_t mask)
#define ALLOCA_N(type, n)
Definition: ruby.h:1227
#define proc_getrlimit
Definition: process.c:4618
#define RUBY_UBF_PROCESS
Definition: intern.h:844
void rb_exit(int status)
Definition: process.c:3530
#define T_BIGNUM
Definition: ruby.h:495
int seteuid(pid_t pid)
#define ISUPPER(c)
Definition: ruby.h:1633
void ruby_stop(int ex)
Calls ruby_cleanup() and exits the process.
Definition: eval.c:261
VALUE rb_obj_alloc(VALUE)
Definition: object.c:1721
int err
Definition: win32.c:87
#define ISLOWER(c)
Definition: ruby.h:1634
static size_t memsize_exec_arg(const void *ptr)
Definition: process.c:1349
#define ALLOCV_END(v)
Definition: ruby.h:1239
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:5915
void * rb_thread_call_without_gvl(void *(*func)(void *), void *data1, rb_unblock_function_t *ubf, void *data2)
int rb_exec_async_signal_safe(const struct rb_execarg *eargp, char *errmsg, size_t errmsg_buflen)
Definition: process.c:3019
rb_pid_t pid
Definition: process.c:658
static void free_exec_arg(void *ptr)
Definition: process.c:1343
#define WSTOPSIG
Definition: process.c:105
static void before_exec(void)
Definition: process.c:1083
VALUE rb_const_get(VALUE, ID)
Definition: variable.c:1876
VALUE rb_thread_local_aset(VALUE, ID, VALUE)
Definition: thread.c:2748
void rb_define_alias(VALUE klass, const char *name1, const char *name2)
Defines an alias of a method.
Definition: class.c:1539
int rb_execarg_addopt(VALUE execarg_obj, VALUE key, VALUE val)
Definition: process.c:1606
#define RSTRING_LEN(str)
Definition: ruby.h:862
void rb_define_module_function(VALUE module, const char *name, VALUE(*func)(ANYARGS), int argc)
Defines a module function for module.
Definition: class.c:1512
static rb_pid_t rb_spawn_internal(int argc, VALUE *argv, char *errmsg, size_t errmsg_buflen)
Definition: process.c:3699
VALUE rb_yield(VALUE)
Definition: vm_eval.c:934
#define proc_getpgid
Definition: process.c:4194
VALUE rb_io_fdopen(int, int, const char *)
Definition: io.c:7126
unsigned close_others_given
Definition: internal.h:227
static int compare_posix_sh(const void *key, const void *el)
Definition: process.c:2009
#define p_sys_setruid
Definition: process.c:4866
int errno
#define TRUE
Definition: nkf.h:175
#define proc_seteuid_m
Definition: process.c:5962
static VALUE p_uid_switch(VALUE obj)
Definition: process.c:6374
static VALUE pst_wcoredump(VALUE st)
Definition: process.c:639
#define p_sys_setresgid
Definition: process.c:5318
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:4697
#define proc_setgid
Definition: process.c:5406
#define const
Definition: strftime.c:102
static int proc_exec_cmd(const char *prog, VALUE argv_str, VALUE envp_str)
Definition: process.c:1150
#define EXIT_FAILURE
Definition: process.c:44
VALUE rb_hash_new(void)
Definition: hash.c:234
VALUE rb_iv_set(VALUE, const char *, VALUE)
Definition: variable.c:2591
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:1570
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
VALUE redirect_fds
Definition: internal.h:219
VALUE rb_check_hash_type(VALUE hash)
Definition: hash.c:461
unsigned char buf[MIME_BUF_SIZE]
Definition: nkf.c:4308
unsigned close_others_do
Definition: internal.h:228
VALUE rb_assoc_new(VALUE car, VALUE cdr)
Definition: array.c:545
#define PRIsVALUE
Definition: ruby.h:147
unsigned long ID
Definition: ruby.h:105
int setgid(rb_gid_t)
Definition: win32.c:2427
#define RHASH_SIZE(h)
Definition: ruby.h:931
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
#define Qnil
Definition: ruby.h:435
unsigned new_pgroup_given
Definition: internal.h:230
const char * ptr
Definition: process.c:2004
#define mode_t
Definition: win32.h:100
static VALUE p_gid_switch(VALUE obj)
Definition: process.c:6489
VALUE rb_io_close(VALUE)
Definition: io.c:4221
#define p_sys_setregid
Definition: process.c:5294
unsigned long VALUE
Definition: ruby.h:104
VALUE rb_mProcUID
Definition: process.c:6558
rb_uid_t geteuid(void)
Definition: win32.c:2399
static VALUE result
Definition: nkf.c:40
#define RBASIC(obj)
Definition: ruby.h:1094
#define CHILD_ERRMSG_BUFLEN
const char * rb_class2name(VALUE)
Definition: variable.c:389
char * strchr(char *, char)
#define FIX2INT(x)
Definition: ruby.h:624
#define NUM2GIDT(v)
Definition: ruby.h:344
#define p_sys_setgid
Definition: process.c:5223
#define EPERM
Definition: _sdbm.c:94
mode_t umask_mask
Definition: internal.h:236
VALUE rb_ensure(VALUE(*b_proc)(ANYARGS), VALUE data1, VALUE(*e_proc)(ANYARGS), VALUE data2)
Definition: eval.c:804
unsigned pgroup_given
Definition: internal.h:223
#define proc_setmaxgroups
Definition: process.c:5623
VALUE rb_str_new_cstr(const char *)
Definition: string.c:447
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
#define RARRAY_LENINT(ary)
Definition: ruby.h:908
st_table * st_init_numtable(void)
Definition: st.c:272
VALUE fd_dup2_child
Definition: internal.h:242
void rb_sys_fail(const char *mesg)
Definition: error.c:1899
static int intcmp(const void *a, const void *b)
Definition: process.c:2525
void rb_jump_tag(int tag)
Definition: eval.c:666
VALUE rb_str_dup(VALUE)
Definition: string.c:946
void ruby_error_print(void)
Definition: eval_error.c:200
#define PREPARE_GETGRNAM
Definition: process.c:187
#define proc_setuid
Definition: process.c:4999
void xfree(void *)
#define ERRMSG(str)
Definition: process.c:2411
VALUE rb_mProcess
Definition: process.c:6557
static void security(const char *str)
Definition: process.c:1120
#define my_getcwd()
Definition: util.h:72
union rb_execarg::@87 invoke
VALUE rb_define_module_under(VALUE outer, const char *name)
Definition: class.c:637
#define StringValueCStr(v)
Definition: ruby.h:548
Definition: win32.h:709
VALUE fd_open
Definition: internal.h:241
static int check_exec_options_i(st_data_t st_key, st_data_t st_val, st_data_t arg)
Definition: process.c:1781
#define RSTRING_PTR(str)
Definition: ruby.h:866
static rb_uid_t rb_seteuid_core(rb_uid_t euid)
Definition: process.c:5966
static VALUE p_gid_grant_privilege(VALUE obj, VALUE id)
Definition: process.c:6152
VALUE rb_f_abort(int argc, VALUE *argv)
Definition: process.c:3616
void rb_thread_wait_for(struct timeval)
Definition: thread.c:1066
VALUE rb_execarg_extract_options(VALUE execarg_obj, VALUE opthash)
Definition: process.c:1897
#define try_with_sh(prog, argv, envp)
Definition: process.c:1145
static st_table * pid_tbl
Definition: process.c:655
VALUE rb_equal(VALUE, VALUE)
Definition: object.c:56
RUBY_EXTERN VALUE rb_stderr
Definition: ruby.h:1500
int size
Definition: encoding.c:52
#define rb_check_arity(argc, min, max)
Definition: intern.h:277
#define INT2FIX(i)
Definition: ruby.h:241
#define UNLIMITED_ARGUMENTS
Definition: intern.h:54
int rb_sourceline(void)
Definition: vm.c:816
sighandler_t signal(int signum, sighandler_t handler)
void rb_last_status_set(int status, rb_pid_t pid)
Definition: process.c:276
int utime(const char *filename, const struct utimbuf *times)
VALUE dup2_tmpbuf
Definition: internal.h:222
VALUE fd_close
Definition: internal.h:240
unsigned gid_given
Definition: internal.h:233
static VALUE pst_wifstopped(VALUE st)
Definition: process.c:490
VALUE rb_check_convert_type(VALUE, int, const char *, const char *)
Definition: object.c:2383
#define redirect_dup2(oldfd, newfd)
Definition: process.c:2465
static VALUE p_gid_exchange(VALUE obj)
Definition: process.c:6257
void rb_set_errinfo(VALUE err)
Definition: eval.c:1436
static VALUE p_uid_grant_privilege(VALUE obj, VALUE id)
Definition: process.c:6020
VALUE envp_buf
Definition: internal.h:221
VALUE rb_execarg_init(int argc, VALUE *argv, int accept_shell, VALUE execarg_obj)
Definition: process.c:2209
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:4843
static void check_uid_switch(void)
Definition: process.c:4699
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 RARRAY_PTR(a)
Definition: ruby.h:904
#define MAXPATHLEN
Definition: process.c:57
VALUE rb_str_catf(VALUE str, const char *format,...)
Definition: sprintf.c:1310
unsigned chdir_given
Definition: internal.h:229
#define GIDT2NUM(v)
Definition: ruby.h:341
void rb_thread_reset_timer_thread(void)
Definition: thread.c:3776
VALUE rb_f_kill(int, VALUE *)
Definition: signal.c:364
VALUE rb_check_string_type(VALUE)
Definition: string.c:1508
static VALUE proc_getegid(VALUE obj)
Definition: process.c:6041
static int forked_child
Definition: process.c:1039
uint8_t key[16]
Definition: random.c:1370
static VALUE get_ppid(void)
Definition: process.c:230
#define ARGVSTR2ARGV(argv_str)
Definition: internal.h:253
static int exit_status_code(VALUE status)
Definition: process.c:3478
#define RTEST(v)
Definition: ruby.h:445
#define T_STRING
Definition: ruby.h:490
int use_shell
Definition: internal.h:207
VALUE chdir_dir
Definition: internal.h:245
VALUE rb_execarg_new(int argc, VALUE *argv, int accept_shell)
Definition: process.c:2190
#define proc_setrlimit
Definition: process.c:4694
#define rb_proc_times
Definition: process.c:6554
v
Definition: win32ole.c:798
#define EWOULDBLOCK
Definition: rubysocket.h:90
#define T_FILE
Definition: ruby.h:496
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:6482
static VALUE pst_inspect(VALUE st)
Definition: process.c:402
VALUE rb_marshal_load(VALUE)
Definition: marshal.c:2123
#define TypedData_Make_Struct(klass, type, data_type, sval)
Definition: ruby.h:1019
VALUE rb_ary_dup(VALUE ary)
Definition: array.c:1778
VALUE rb_io_puts(int, VALUE *, VALUE)
Definition: io.c:6890
void rb_notimplement(void)
Definition: error.c:1826
void rb_last_status_clear(void)
Definition: process.c:285
static unsigned int hash(const char *str, unsigned int len)
Definition: lex.c:56
#define SafeStringValue(v)
Definition: ruby.h:552
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:4091
static int proc_exec_sh(const char *str, VALUE envp_str)
Definition: process.c:1263
#define rb_safe_level()
Definition: tcltklib.c:94
const char * name
Definition: nkf.c:208
static VALUE p_uid_change_privilege(VALUE obj, VALUE id)
Definition: process.c:5044
#define NUM2MODET(v)
Definition: ruby.h:347
static VALUE rb_exec_getargs(int *argc_p, VALUE **argv_p, int accept_shell, VALUE *env_ret, VALUE *opthash_ret)
Definition: process.c:1971
const char * rb_id2name(ID id)
Definition: ripper.c:17005
#define rb_errinfo()
Definition: tcltklib.c:89
unsigned long st_data_t
Definition: st.h:35
#define StringValuePtr(v)
Definition: ruby.h:547
#define redirect_dup(oldfd)
Definition: process.c:2448
static char fbuf[MAXPATHLEN]
Definition: dln_find.c:105
RUBY_EXTERN int dup2(int, int)
Definition: dup2.c:27
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
VALUE rb_str_new_frozen(VALUE)
Definition: string.c:713
#define STRCASECMP(s1, s2)
Definition: ruby.h:1645
#define RB_MAX_GROUPS
Definition: internal.h:204
#define tmpbuf(n, size)
Definition: array.c:4539
#define PREPARE_GETPWNAM
Definition: process.c:163
#define UIDT2NUM(v)
Definition: ruby.h:335
VALUE rb_env_clear(void)
Definition: hash.c:2866
rb_gid_t getgid(void)
Definition: win32.c:2406
void rb_secure(int)
Definition: safe.c:79
#define CONST_ID(var, str)
Definition: ruby.h:1318
static VALUE proc_getuid(VALUE obj)
Definition: process.c:4955
#define proc_setgroups
Definition: process.c:5539
VALUE rb_struct_define(const char *,...)
Definition: struct.c:264
static ID id_pid(void)
Definition: process.c:950
#define proc_getsid
Definition: process.c:4254
int rb_run_exec_options(const struct rb_exec_arg *e, struct rb_exec_arg *s)
Definition: process.c:3012
#define RHASH_EMPTY_P(h)
Definition: ruby.h:932
VALUE rb_define_module(const char *name)
Definition: class.c:617
#define p_uid_from_name
Definition: process.c:167
rb_pid_t rb_spawn(int argc, VALUE *argv)
Definition: process.c:3720
static VALUE check_exec_redirect1(VALUE ary, VALUE key, VALUE param)
Definition: process.c:1490
#define rb_intern(str)
#define ARGVSTR2ARGC(argv_str)
Definition: internal.h:252
VALUE rb_str_buf_new(long)
Definition: string.c:777
unsigned new_pgroup_flag
Definition: internal.h:231
#define SYMBOL_P(x)
Definition: ruby.h:362
#define mod(x, y)
Definition: date_strftime.c:28
int status
Definition: process.c:659
VALUE rb_detach_process(rb_pid_t pid)
Definition: process.c:976
#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
#define Qundef
Definition: ruby.h:436
VALUE rb_hash_aset(VALUE, VALUE, VALUE)
#define p_sys_issetugid
Definition: process.c:5347
struct rb_execarg::@87::@88 sh
VALUE rb_thread_create(VALUE(*)(ANYARGS), void *)
Definition: thread.c:722
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:1344
int st_foreach(st_table *, int(*)(ANYARGS), st_data_t)
Definition: st.c:1000
void ruby_setenv(const char *name, const char *value)
Definition: hash.c:2388
#define NOFILE
Definition: io.c:76
int setuid(rb_uid_t)
Definition: win32.c:2420
VALUE rb_str_new2(const char *)
void rb_warn(const char *fmt,...)
Definition: error.c:216
static VALUE pst_wexitstatus(VALUE st)
Definition: process.c:601
VALUE rb_eArgError
Definition: error.c:512
#define O_BINARY
Definition: _sdbm.c:89
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
VALUE rb_attr_get(VALUE, ID)
Definition: variable.c:1122
static int wait_each(rb_pid_t pid, int status, struct wait_data *data)
Definition: process.c:663
char * strrchr(const char *, const char)
char ** argv
Definition: ruby.c:131
#define DBL2NUM(dbl)
Definition: ruby.h:837
#define StringValue(v)
Definition: ruby.h:546
#define numberof(array)
Definition: process.c:83
void Init_process(void)
Definition: process.c:6569
void rb_thread_sleep_forever(void)
Definition: thread.c:1020
VALUE rb_str_new(const char *, long)
Definition: string.c:425
VALUE rb_f_exec(int argc, VALUE *argv)
Definition: process.c:2387