summaryrefslogtreecommitdiff
path: root/process.c
diff options
context:
space:
mode:
Diffstat (limited to 'process.c')
-rw-r--r--process.c849
1 files changed, 849 insertions, 0 deletions
diff --git a/process.c b/process.c
new file mode 100644
index 0000000000..7a1dd398c5
--- /dev/null
+++ b/process.c
@@ -0,0 +1,849 @@
+/************************************************
+
+ process.c -
+
+ $Author: matz $
+ $Date: 1994/06/17 14:23:50 $
+ created at: Tue Aug 10 14:30:50 JST 1993
+
+ Copyright (C) 1994 Yukihiro Matsumoto
+
+************************************************/
+
+#include "ruby.h"
+#include <stdio.h>
+#include <errno.h>
+#include <ctype.h>
+#include <signal.h>
+#include <sys/time.h>
+#include <sys/resource.h>
+#include "st.h"
+VALUE rb_readonly_hook();
+
+static VALUE
+get_pid()
+{
+ return INT2FIX(getpid());
+}
+
+static VALUE
+get_ppid()
+{
+ return INT2FIX(getppid());
+}
+
+static VALUE status;
+
+#if !defined(HAVE_WAITPID) && !defined(HAVE_WAIT4)
+static st_table *pid_tbl;
+#else
+# define WAIT_CALL
+#endif
+
+int
+rb_waitpid(pid, flags)
+ int pid;
+ int flags;
+{
+ int result, st;
+
+#ifdef HAVE_WAITPID
+ result = waitpid(pid, &st, flags);
+#else
+#ifdef HAVE_WAIT4
+ result = wait4(pid, &st, flags, NULL);
+#else
+ if (pid_tbl && st_lookup(pid_tbl, pid, &st)) {
+ status = INT2FIX(st);
+ st_delete(pid_tbl, &pid, NULL);
+ return pid;
+ }
+
+ if (flags)
+ Fail("Can't do waitpid with flags");
+
+ for (;;) {
+ result = wait(&st);
+ if (result < 0) return -1;
+ if (result == pid) {
+ break;
+ }
+ if (!pid_tbl)
+ pid_tbl = st_init_table(ST_NUMCMP, ST_NUMHASH);
+ st_insert(pid_tbl, pid, st);
+ }
+#endif
+#endif
+ status = INT2FIX(st);
+ return result;
+}
+
+#ifndef WAIT_CALL
+static int wait_pid;
+static int wait_status;
+
+static wait_each(key, value)
+ int key, value;
+{
+ wait_pid = key;
+ wait_status = value;
+ return ST_DELETE;
+}
+#endif
+
+static VALUE
+Fwait(obj)
+{
+ int pid, state;
+
+#ifndef WAIT_CALL
+ wait_status = -1;
+ st_foreach(pid_tbl, wait_each, NULL);
+ if (wait_status != -1) {
+ status = wait_status;
+ return wait_pid;
+ }
+#endif
+
+ if ((pid = wait(&state)) < 0) {
+ if (errno == ECHILD) return Qnil;
+ rb_sys_fail(Qnil);
+ }
+ status = INT2FIX(state);
+ return INT2FIX(pid);
+}
+
+static VALUE
+Fwaitpid(obj, vpid, vflags)
+ VALUE obj, vpid, vflags;
+{
+ int pid, flags;
+
+ if (vflags == Qnil) flags = Qnil;
+ else flags = FIX2UINT(vflags);
+
+ if ((pid = rb_waitpid(FIX2UINT(vpid), flags)) < 0)
+ rb_sys_fail(Qnil);
+ return INT2FIX(pid);
+}
+
+char *strtok();
+
+rb_proc_exec(str)
+ char *str;
+{
+ char *s = str, *t;
+ char **argv, **a;
+
+ for (s=str; *s; s++) {
+ if (*s != ' ' && !isalpha(*s) && index("*?{}[]<>()~&|\\$;'`\"\n",*s)) {
+ execl("/bin/sh", "sh", "-c", str, (char *)NULL);
+ return -1;
+ }
+ }
+ a = argv = (char**)alloca(((s - str)/2+2)*sizeof(char*));
+ s = (char*)alloca(s - str + 1);
+ strcpy(s, str);
+ if (*a++ = strtok(s, " \t")) {
+ while (t = strtok(NULL, " \t")) {
+ *a++ = t;
+ }
+ *a = NULL;
+ }
+ if (argv[0]) {
+ execvp(argv[0], argv);
+ }
+ return -1;
+}
+
+static VALUE
+Fexec(obj, str)
+ VALUE obj;
+ struct RString *str;
+{
+ Check_Type(str, T_STRING);
+ rb_proc_exec(str->ptr);
+ rb_sys_fail(str->ptr);
+}
+
+static VALUE
+Ffork(obj)
+ VALUE obj;
+{
+ int pid;
+
+ switch (pid = fork()) {
+ case 0:
+ return Qnil;
+
+ case -1:
+ rb_sys_fail(Qnil);
+ break;
+
+ default:
+ return INT2FIX(pid);
+ }
+}
+
+static VALUE
+F_exit(obj, status)
+ VALUE obj, status;
+{
+ int code = -1;
+
+ if (FIXNUM_P(status)) {
+ code = INT2FIX(status);
+ }
+
+ _exit(code);
+
+ /* not reached */
+ return Qnil;
+}
+
+void
+rb_syswait(pid)
+ int pid;
+{
+ RETSIGTYPE (*hfunc)(), (*ifunc)(), (*qfunc)();
+
+ hfunc = signal(SIGHUP, SIG_IGN);
+ ifunc = signal(SIGINT, SIG_IGN);
+ qfunc = signal(SIGQUIT, SIG_IGN);
+
+ if (rb_waitpid(pid, 0) < 0) rb_sys_fail("wait");
+
+ signal(SIGHUP, hfunc);
+ signal(SIGINT, ifunc);
+ signal(SIGQUIT, qfunc);
+}
+
+static VALUE
+Fsystem(obj, str)
+ VALUE obj;
+ struct RString *str;
+{
+ int pid, w;
+
+ Check_Type(str, T_STRING);
+
+ fflush(stdin); /* is it really needed? */
+ fflush(stdout);
+ fflush(stderr);
+ if (*str->ptr == '\0') return INT2FIX(0);
+
+ retry:
+ switch (pid = vfork()) {
+ case 0:
+ rb_proc_exec(str->ptr);
+ _exit(127);
+ break; /* not reached */
+
+ case -1:
+ if (errno == EAGAIN) {
+ sleep(5);
+ goto retry;
+ }
+ rb_sys_fail(str->ptr);
+ break;
+
+ default:
+ rb_syswait(pid);
+ }
+
+ return status;
+}
+
+static struct signals {
+ char *signm;
+ int signo;
+} siglist [] = {
+#ifdef SIGHUP
+ "HUP", SIGHUP,
+#endif
+#ifdef SIGINT
+ "INT", SIGINT,
+#endif
+#ifdef SIGQUIT
+ "QUIT", SIGQUIT,
+#endif
+#ifdef SIGILL
+ "ILL", SIGILL,
+#endif
+#ifdef SIGTRAP
+ "TRAP", SIGTRAP,
+#endif
+#ifdef SIGIOT
+ "IOT", SIGIOT,
+#endif
+#ifdef SIGABRT
+ "ABRT", SIGABRT,
+#endif
+#ifdef SIGEMT
+ "EMT", SIGEMT,
+#endif
+#ifdef SIGFPE
+ "FPE", SIGFPE,
+#endif
+#ifdef SIGKILL
+ "KILL", SIGKILL,
+#endif
+#ifdef SIGBUS
+ "BUS", SIGBUS,
+#endif
+#ifdef SIGSEGV
+ "SEGV", SIGSEGV,
+#endif
+#ifdef SIGSYS
+ "SYS", SIGSYS,
+#endif
+#ifdef SIGPIPE
+ "PIPE", SIGPIPE,
+#endif
+#ifdef SIGALRM
+ "ALRM", SIGALRM,
+#endif
+#ifdef SIGTERM
+ "TERM", SIGTERM,
+#endif
+#ifdef SIGURG
+ "URG", SIGURG,
+#endif
+#ifdef SIGSTOP
+ "STOP", SIGSTOP,
+#endif
+#ifdef SIGTSTP
+ "TSTP", SIGTSTP,
+#endif
+#ifdef SIGCONT
+ "CONT", SIGCONT,
+#endif
+#ifdef SIGCHLD
+ "CHLD", SIGCHLD,
+#endif
+#ifdef SIGCLD
+ "CLD", SIGCLD,
+#else
+# ifdef SIGCHLD
+ "CLD", SIGCHLD,
+# endif
+#endif
+#ifdef SIGTTIN
+ "TTIN", SIGTTIN,
+#endif
+#ifdef SIGTTOU
+ "TTOU", SIGTTOU,
+#endif
+#ifdef SIGIO
+ "IO", SIGIO,
+#endif
+#ifdef SIGXCPU
+ "XCPU", SIGXCPU,
+#endif
+#ifdef SIGXFSZ
+ "XFSZ", SIGXFSZ,
+#endif
+#ifdef SIGVTALRM
+ "VTALRM", SIGVTALRM,
+#endif
+#ifdef SIGPROF
+ "PROF", SIGPROF,
+#endif
+#ifdef SIGWINCH
+ "WINCH", SIGWINCH,
+#endif
+#ifdef SIGUSR1
+ "USR1", SIGUSR1,
+#endif
+#ifdef SIGUSR2
+ "USR2", SIGUSR2,
+#endif
+#ifdef SIGLOST
+ "LOST", SIGLOST,
+#endif
+#ifdef SIGMSG
+ "MSG", SIGMSG,
+#endif
+#ifdef SIGPWR
+ "PWR", SIGPWR,
+#endif
+#ifdef SIGPOLL
+ "POLL", SIGPOLL,
+#endif
+#ifdef SIGDANGER
+ "DANGER", SIGDANGER,
+#endif
+#ifdef SIGMIGRATE
+ "MIGRATE", SIGMIGRATE,
+#endif
+#ifdef SIGPRE
+ "PRE", SIGPRE,
+#endif
+#ifdef SIGGRANT
+ "GRANT", SIGGRANT,
+#endif
+#ifdef SIGRETRACT
+ "RETRACT", SIGRETRACT,
+#endif
+#ifdef SIGSOUND
+ "SOUND", SIGSOUND,
+#endif
+ NULL, 0,
+};
+
+static int
+signm2signo(nm)
+ char *nm;
+{
+ struct signals *sigs;
+
+ for (sigs = siglist; sigs->signm; sigs++)
+ if (strcmp(sigs->signm, nm) == 0)
+ return sigs->signo;
+ return 0;
+}
+
+static VALUE
+Fkill(argc, argv)
+ int argc;
+ VALUE *argv;
+{
+ int sig;
+ int i;
+
+ if (argc < 3)
+ Fail("wrong # of arguments -- kill(sig, pid...)");
+ switch (TYPE(argv[1])) {
+ case T_FIXNUM:
+ sig = FIX2UINT(argv[1]);
+ break;
+
+ case T_STRING:
+ {
+ int negative = 0;
+
+ char *s = RSTRING(argv[1])->ptr;
+ if (*s == '-') {
+ negative++;
+ s++;
+ }
+ if (strncmp("SIG", s, 3) == 0)
+ s += 3;
+ if((sig = signm2signo(s)) == 0)
+ Fail("Unrecognized signal name `%s'", s);
+
+ if (negative)
+ sig = -sig;
+ }
+ break;
+
+ default:
+ Fail("bad signal type %s", rb_class2name(CLASS_OF(argv[1])));
+ break;
+ }
+
+ if (sig < 0) {
+ sig = -sig;
+ for (i=2; i<argc; i++) {
+ int pid = NUM2INT(argv[i]);
+#ifdef HAS_KILLPG
+ if (killpg(pid, sig) < 0)
+#else
+ if (kill(-pid, sig) < 0)
+#endif
+ rb_sys_fail(Qnil);
+ }
+ }
+ else {
+ for (i=2; i<argc; i++) {
+ Check_Type(argv[i], T_FIXNUM);
+ if (kill(FIX2UINT(argv[i]), sig) < 0)
+ rb_sys_fail(Qnil);
+ }
+ }
+ return INT2FIX(i-2);
+}
+
+static VALUE trap_list[NSIG];
+#ifdef SAFE_SIGHANDLE
+static int trap_pending_list[NSIG];
+int trap_pending;
+static int trap_immediate;
+#endif
+
+void
+mark_trap_list()
+{
+ int i;
+
+ for (i=0; i<NSIG; i++) {
+ if (trap_list[i])
+ mark(trap_list[i]);
+ }
+}
+
+static RETSIGTYPE
+sighandle(sig)
+ int sig;
+{
+ if (sig >= NSIG || trap_list[sig] == Qnil)
+ Fail("trap_handler: Bad signal %d", sig);
+
+#ifndef HAVE_BSD_SIGNALS
+ signal(sig, sighandle);
+#endif
+
+#ifdef SAFE_SIGHANDLE
+ if (trap_immediate)
+ rb_trap_eval(trap_list[sig]);
+ else {
+ trap_pending++;
+ trap_pending_list[sig]++;
+ }
+#else
+ rb_trap_eval(trap_list[sig]);
+#endif
+}
+
+void
+rb_trap_exit()
+{
+ if (trap_list[0])
+ rb_trap_eval(trap_list[0]);
+}
+
+#if defined(SAFE_SIGHANDLE)
+rb_trap_exec()
+{
+ int i;
+
+ trap_pending = 0;
+ for (i=0; i<NSIG; i++) {
+ if (trap_pending_list[i]) {
+ trap_pending_list[i] = 0;
+ rb_trap_eval(trap_list[i]);
+ }
+ }
+}
+
+#ifdef HAVE_SYSCALL_H
+#include <syscall.h>
+
+#ifdef SYS_read
+int
+read(fd, buf, nbytes)
+ int fd, nbytes;
+ char *buf;
+{
+ int res;
+
+ trap_immediate++;
+ res = syscall(SYS_read, fd, buf, nbytes);
+ trap_immediate = 0;
+ return res;
+}
+#endif /* SYS_read */
+
+#ifdef SYS_wait
+int
+wait(status)
+ union wait *status;
+{
+ int res;
+
+ trap_immediate++;
+ res = syscall(SYS_wait, status);
+ trap_immediate =0;
+ return res;
+}
+#endif /* SYS_wait */
+
+#ifdef SYS_sigpause
+int
+sigpause(mask)
+ int mask;
+{
+ int res;
+
+ trap_immediate++;
+ res = syscall(SYS_sigpause, mask);
+ trap_immediate =0;
+ return res;
+}
+#endif /* SYS_sigpause */
+
+/* linux syscall(select) doesn't work file. */
+#if defined(SYS_select) && !defined(linux)
+#include <sys/types.h>
+
+int
+select(nfds, readfds, writefds, exceptfds, timeout)
+ int nfds;
+ fd_set *readfds, *writefds, *exceptfds;
+ struct timeval *timeout;
+{
+ int res;
+
+ trap_immediate++;
+ res = syscall(SYS_select, nfds, readfds, writefds, exceptfds, timeout);
+ trap_immediate =0;
+ return res;
+}
+#endif /* SYS_select */
+
+#endif /* HAVE_SYSCALL_H */
+#endif /* SAFE_SIGHANDLE */
+
+static VALUE
+Ftrap(argc, argv)
+ int argc;
+ VALUE *argv;
+{
+ RETSIGTYPE (*func)();
+ VALUE command;
+ int i, sig;
+ int mask;
+
+ if (argc < 3)
+ Fail("wrong # of arguments -- kill(cmd, sig...)");
+
+ /* disable interrupt */
+ mask = sigblock(~0);
+
+ func = sighandle;
+
+ if (argv[1] == Qnil) {
+ func = SIG_IGN;
+ command = Qnil;
+ }
+ else {
+ Check_Type(argv[1], T_STRING);
+ command = argv[1];
+ if (RSTRING(argv[1])->len == 0) {
+ func = SIG_IGN;
+ }
+ else if (RSTRING(argv[1])->len == 7) {
+ if (strncmp(RSTRING(argv[1])->ptr, "SIG_IGN", 7) == 0) {
+ func = SIG_IGN;
+ }
+ else if (strncmp(RSTRING(argv[1])->ptr, "SIG_DFL", 7) == 0) {
+ func = SIG_DFL;
+ }
+ else if (strncmp(RSTRING(argv[1])->ptr, "DEFAULT", 7) == 0) {
+ func = SIG_DFL;
+ }
+ }
+ else if (RSTRING(argv[1])->len == 6) {
+ if (strncmp(RSTRING(argv[1])->ptr, "IGNORE", 6) == 0) {
+ func = SIG_IGN;
+ }
+ }
+ }
+ if (func == SIG_IGN || func == SIG_DFL)
+ command = Qnil;
+
+ for (i=2; i<argc; i++) {
+ if (TYPE(argv[i]) == T_STRING) {
+ char *s = RSTRING(argv[i])->ptr;
+
+ if (strncmp("SIG", s, 3) == 0)
+ s += 3;
+ sig = signm2signo(s);
+ if (sig == 0 && strcmp(s, "EXIT") != 0)
+ Fail("Invalid signal SIG%s", s);
+ }
+ else {
+ sig = NUM2INT(argv[i]);
+ }
+ if (i < 0 || i > NSIG)
+ Fail("Invalid signal no %d", sig);
+
+ signal(sig, sighandle);
+ trap_list[sig] = command;
+ /* enable at least specified signal. */
+ mask &= ~sigmask(sig);
+ }
+ sigsetmask(mask);
+ return Qnil;
+}
+
+Fsleep(argc, argv)
+ int argc;
+ VALUE *argv;
+{
+ int beg, end;
+
+ beg = time(0);
+ if (argc == 1) {
+ sleep((32767<<16)+32767);
+ }
+ else if (argc == 2) {
+ sleep(NUM2INT(argv[1]));
+ }
+ else {
+ Fail("wrong # of arguments");
+ }
+
+ end = time(0) - beg;
+
+ return int2inum(end);
+}
+
+static VALUE
+Fproc_getpgrp(obj, args)
+ VALUE obj, args;
+{
+ VALUE vpid;
+ int pid, pgrp;
+
+ rb_scan_args(args, "01", &vpid);
+ if (vpid == Qnil) {
+ pid = 0;
+ }
+ else {
+ pid = NUM2INT(vpid);
+ }
+
+ pgrp = getpgrp(pid);
+ return INT2FIX(pgrp);
+}
+
+static VALUE
+Fproc_setpgrp(obj, pid, pgrp)
+ VALUE obj, pid, pgrp;
+{
+ int ipid, ipgrp;
+
+ ipid = NUM2INT(pid);
+ ipgrp = NUM2INT(pgrp);
+
+ if (getpgrp(ipid, ipgrp) == -1) rb_sys_fail(Qnil);
+
+ return Qnil;
+}
+
+static VALUE
+Fproc_getpriority(obj, which, who)
+ VALUE obj, which, who;
+{
+ int prio, iwhich, iwho;
+
+ iwhich = NUM2INT(which);
+ iwho = NUM2INT(who);
+
+ prio = getpriority(iwhich, iwho);
+ if (prio == -1) rb_sys_fail(Qnil);
+ return INT2FIX(prio);
+}
+
+static VALUE
+Fproc_setpriority(obj, which, who, prio)
+ VALUE obj, which, who, prio;
+{
+ int iwhich, iwho, iprio;
+
+ iwhich = NUM2INT(which);
+ iwho = NUM2INT(who);
+ iprio = NUM2INT(prio);
+
+ if (setpriority(iwhich, iwho, iprio) == -1)
+ rb_sys_fail(Qnil);
+ return Qnil;
+}
+
+static VALUE
+Fproc_getuid(obj)
+ VALUE obj;
+{
+ int uid = getuid();
+ return INT2FIX(uid);
+}
+
+static VALUE
+Fproc_setuid(obj, id)
+ VALUE obj, id;
+{
+ int uid;
+
+ uid = NUM2INT(id);
+#ifdef HAVE_SETRUID
+ setruid(uid);
+#else
+#ifdef HAVE_SETREUID
+ setreuid(uid, -1);
+#else
+ {
+ if (geteuid() == uid)
+ setuid(uid);
+ else
+ Fail("getruid not implemented");
+ }
+#endif
+#endif
+ return INT2FIX(uid);
+}
+
+static VALUE
+Fproc_geteuid(obj)
+ VALUE obj;
+{
+ int euid = geteuid();
+ return INT2FIX(euid);
+}
+
+static VALUE
+Fproc_seteuid(obj, euid)
+ VALUE obj, euid;
+{
+ if (seteuid(NUM2INT(euid)) == -1)
+ rb_sys_fail(Qnil);
+ return euid;
+}
+
+VALUE M_Process;
+Init_process()
+{
+ extern VALUE C_Kernel;
+
+ rb_define_variable("$$", Qnil, get_pid, rb_readonly_hook);
+ rb_define_variable("$?", &status, Qnil, rb_readonly_hook);
+ rb_define_func(C_Kernel, "exec", Fexec, 1);
+ rb_define_func(C_Kernel, "fork", Ffork, 0);
+ rb_define_func(C_Kernel, "_exit", Ffork, 1);
+ rb_define_func(C_Kernel, "wait", Fwait, 0);
+ rb_define_func(C_Kernel, "waitpid", Fwaitpid, 2);
+ rb_define_func(C_Kernel, "system", Fsystem, 1);
+ rb_define_func(C_Kernel, "kill", Fkill, -1);
+ rb_define_func(C_Kernel, "trap", Ftrap, -1);
+ rb_define_func(C_Kernel, "sleep", Fsleep, -1);
+
+ M_Process = rb_define_module("Process");
+
+ rb_define_single_method(M_Process, "fork", Ffork, 0);
+ rb_define_single_method(M_Process, "_exit", Ffork, 1);
+ rb_define_single_method(M_Process, "wait", Fwait, 0);
+ rb_define_single_method(M_Process, "waitpid", Fwaitpid, 2);
+ rb_define_single_method(M_Process, "kill", Fkill, -1);
+
+ rb_define_mfunc(M_Process, "pid", get_pid, 0);
+ rb_define_mfunc(M_Process, "ppid", get_ppid, 0);
+
+ rb_define_mfunc(M_Process, "getpgrp", Fproc_getpgrp, -2);
+ rb_define_mfunc(M_Process, "setpgrp", Fproc_setpgrp, 2);
+
+ rb_define_mfunc(M_Process, "getpriority", Fproc_getpriority, 2);
+ rb_define_mfunc(M_Process, "setpriority", Fproc_setpriority, 3);
+
+ rb_define_const(M_Process, "%PRIO_PROCESS", INT2FIX(PRIO_PROCESS));
+ rb_define_const(M_Process, "%PRIO_PGRP", INT2FIX(PRIO_PGRP));
+ rb_define_const(M_Process, "%PRIO_USER", INT2FIX(PRIO_USER));
+
+ rb_define_single_method(M_Process, "uid", Fproc_getuid, 0);
+ rb_define_method(M_Process, "uid", Fproc_getuid, 0);
+ rb_define_single_method(M_Process, "uid=", Fproc_setuid, 1);
+ rb_define_method(M_Process, "uid=", Fproc_setuid, 1);
+ rb_define_single_method(M_Process, "euid", Fproc_geteuid, 0);
+ rb_define_method(M_Process, "euid", Fproc_geteuid, 0);
+ rb_define_single_method(M_Process, "euid=", Fproc_seteuid, 1);
+ rb_define_method(M_Process, "euid=", Fproc_seteuid, 1);
+}