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