home *** CD-ROM | disk | FTP | other *** search
- /* unix_processes.c -- Subprocess handling for Unix
- Copyright (C) 1993, 1994 John Harper <jsh@ukc.ac.uk>
-
- This file is part of Jade.
-
- Jade is free software; you can redistribute it and/or modify it
- under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2, or (at your option)
- any later version.
-
- Jade is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with Jade; see the file COPYING. If not, write to
- the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
-
- #include "jade.h"
- #include "jade_protos.h"
-
- #include <sys/types.h>
- #include <sys/wait.h>
- #include <sys/signal.h>
- #include <sys/fcntl.h>
- #include <sys/time.h>
- #include <sys/stat.h>
- #include <sys/ioctl.h>
- #include <errno.h>
- #include <unistd.h>
- #include <termios.h>
-
- _PR void protect_procs(void);
- _PR void unprotect_procs(void);
- _PR void readfromproc(int);
- _PR int writetoproc(VALUE, u_char *);
- _PR void proc_mark(VALUE);
- _PR void proc_sweep(void);
- _PR void proc_prin(VALUE, VALUE);
- _PR void sys_proc_init(void);
- _PR void sys_proc_kill(void);
-
- #define USE_SIGACTION
-
- #ifdef USE_SIGACTION
- static struct sigaction ChldAct;
- static sigset_t ChldSet;
- #endif
-
- struct Proc
- {
- u_char pr_Type;
- char pr_Status; /* PR_?? value */
- struct Proc *pr_Next;
- pid_t pr_Pid;
- /* pr_Stdin is where we write, pr_Stdout where we read, they may be the
- same. */
- int pr_Stdin, pr_Stdout;
- VALUE pr_OutputStream;
- int pr_ExitStatus;
- VALUE pr_ExitFunc;
- VALUE pr_File;
- VALUE pr_Argv;
- };
-
- /* <= 0 means process not running, > 0 means could be running... */
- #define PR_STOPPED 2 /* waiting to be continued */
- #define PR_RUNNING 1 /* running merrily */
- #define PR_DEAD 0 /* nothing happening on this obj */
- #define PR_EXITED -1 /* process dead but no EOF from pty */
-
- /* Handy debugging macro */
- #if 0
- # define DB(x) fprintf x
- #else
- # define DB(x)
- #endif
-
- static struct Proc *ProcChain;
- static int ProcRunCount;
-
- static void
- callexitfunc(struct Proc *pr)
- {
- if(!NILP(pr->pr_ExitFunc))
- {
- int oldgci = GCinhibit;
- GCinhibit = TRUE;
- calllisp1(pr->pr_ExitFunc, pr);
- GCinhibit = oldgci;
- }
- }
-
- /*
- * Checks if any of my children are zombies, takes appropriate action.
- */
- static void
- checkforzombies(void)
- {
- int status;
- pid_t pid;
- if(!ProcRunCount)
- return;
- while((pid = waitpid(-1, &status, WNOHANG | WUNTRACED)) > 0)
- {
- struct Proc *pr = ProcChain;
- #ifdef DEBUG
- settitlefmt("SIGCHLD: pid %d -- status 0x%x", pid, status);
- #endif
- while(pr)
- {
- if((pr->pr_Status > 0) && (pr->pr_Pid == pid))
- break;
- pr = pr->pr_Next;
- }
- if(pr)
- {
- if(WIFSTOPPED(status))
- pr->pr_Status = PR_STOPPED;
- else
- {
- pr->pr_ExitStatus = status;
- ProcRunCount--;
- #if 0
- if(pr->pr_Stdout)
- close(pr->pr_Stdout);
- if(pr->pr_Stdin && (pr->pr_Stdin != pr->pr_Stdout))
- close(pr->pr_Stdin);
- pr->pr_Stdout = pr->pr_Stdin = 0;
- pr->pr_Status = PR_DEAD;
- #else
- /* It seems that I can't just nuke the pty once the child's
- dead -- there can be data pending on it still. So, I set
- pr_Status to an in-between value and hope to get an eof
- over pr_Stdin RSN
- Another consideration is what happens if the process I ran
- on the pty forked another process which is still using
- my pty. This means that I don't get an EOF until it
- exits (if it does). hmmm... */
-
- if(pr->pr_Stdout || pr->pr_Stdin)
- pr->pr_Status = PR_EXITED;
- else
- {
- pr->pr_Status = PR_DEAD;
- callexitfunc(pr);
- pr->pr_File = pr->pr_Argv = sym_nil;
- }
- #endif
- }
- }
- }
- }
-
- /*
- * This semaphorey thing protects all operations done on process structures
- * from SIGCHLD and the process reaping it causes.
- */
- static int ProcMutex = -1;
- static bool GotSig;
- INLINE void
- protect_procs(void)
- {
- ProcMutex++;
- }
- void
- unprotect_procs(void)
- {
- if((ProcMutex == 0) && GotSig)
- {
- /* Have to leave (ProcMutex == 0) while looking for zombies. */
- GotSig = FALSE;
- checkforzombies();
- }
- ProcMutex--;
- }
-
- static void
- sigchld_handler(int sig)
- {
- if(ProcMutex < 0)
- checkforzombies();
- else
- GotSig = TRUE;
- #ifndef USE_SIGACTION
- signal(SIGCHLD, sigchld_handler);
- #endif
- }
-
- void
- readfromproc(int fd)
- {
- struct Proc *pr = ProcChain;
- protect_procs();
- while(pr)
- {
- if((pr->pr_Status != PR_DEAD) && (pr->pr_Stdout == fd))
- break;
- pr = pr->pr_Next;
- }
- if(pr)
- {
- u_char buf[1025];
- int actual;
- cursor(CurrVW, CURS_OFF);
- do {
- if((actual = read(fd, buf, 1024)) > 0)
- {
- buf[actual] = 0;
- streamputs(pr->pr_OutputStream, buf, FALSE);
- }
- } while((actual > 0) || (errno == EINTR));
-
- /* what happens when a child closes the pty slave (or dies)???
- it seems that I get EIO on Linux. This might handle most
- situations (or should I change !EWOULDBLOCK to EIO??) */
- if((actual <= 0) && (errno != EWOULDBLOCK) && (errno != EAGAIN))
- {
- /* assume eof */
- FD_CLR(pr->pr_Stdout, &FdReadSet);
- FdReadAction[pr->pr_Stdout] = NULL;
- close(pr->pr_Stdout);
- if(pr->pr_Stdin && (pr->pr_Stdin != pr->pr_Stdout))
- close(pr->pr_Stdin);
- pr->pr_Stdout = pr->pr_Stdin = 0;
-
- /* This means that the process has already exited and we were
- just waiting for the dregs of its output. */
- if(pr->pr_Status < 0)
- {
- pr->pr_Status = PR_DEAD;
- callexitfunc(pr);
- pr->pr_File = pr->pr_Argv = sym_nil;
- }
- }
- refreshworld();
- cursor(CurrVW, CURS_ON);
- }
- unprotect_procs();
- }
-
- int
- writetoproc(VALUE pr, u_char *buf)
- {
- int act = 0;
- if(!PROCESSP(pr))
- return(0);
- protect_procs();
- if(VPROC(pr)->pr_Status == PR_RUNNING)
- {
- if(VPROC(pr)->pr_Stdin)
- {
- /* This will block. Needs to handle EINTR as well (oh well...) */
- act = write(VPROC(pr)->pr_Stdin, buf, strlen(buf));
- }
- if(act < 0)
- {
- settitlefmt("Error: %s", VSTR(geterrstring()));
- act = 0;
- }
- }
- else
- cmd_signal(sym_process_error, list_2(pr, MKSTR("Not running")));
- unprotect_procs();
- return(act);
- }
-
- static bool
- signalprocess(struct Proc *pr, int sig)
- {
- bool rc = TRUE;
- protect_procs();
- if(pr->pr_Stdin)
- {
- pid_t gid;
- #ifdef SIGNALS_VIA_CHARS
- switch(sig)
- {
- struct termios term;
- case SIGINT:
- tcgetattr(pr->pr_Stdin, &term);
- write(pr->pr_Stdin, &term.c_cc[VINTR], 1);
- break;
- case SIGQUIT:
- tcgetattr(pr->pr_Stdin, &term);
- write(pr->pr_Stdin, &term.c_cc[VQUIT], 1);
- break;
- case SIGTSTP:
- /* This doesn't work?? sending SIGSTOP directly does :) */
- tcgetattr(pr->pr_Stdin, &term);
- write(pr->pr_Stdin, &term.c_cc[VSUSP], 1);
- break;
- default:
- #endif
- gid = tcgetpgrp(pr->pr_Stdin);
- if(gid != -1)
- killpg(gid, sig);
- else if(pr->pr_Status != PR_DEAD)
- killpg(pr->pr_Pid, sig);
- else
- rc = FALSE;
- #ifdef SIGNALS_VIA_CHARS
- }
- #endif
- }
- else if(pr->pr_Status != PR_DEAD)
- killpg(pr->pr_Pid, sig);
- else
- rc = FALSE;
- unprotect_procs();
- return(rc);
- }
-
- /*
- * This is only called during GC, when the process isn't being referenced.
- * it will already have been taken out of the chain
- */
- static void
- killproc(struct Proc *pr)
- {
- protect_procs();
- if(pr->pr_Status != PR_DEAD)
- {
- if(pr->pr_Status == PR_RUNNING)
- {
- /* is this too heavy-handed?? */
- if(!signalprocess(pr, SIGKILL))
- killpg(pr->pr_Pid, SIGKILL);
- waitpid(pr->pr_Pid, &pr->pr_ExitStatus, 0);
- ProcRunCount--;
- }
- if(pr->pr_Stdout)
- {
- FD_CLR(pr->pr_Stdout, &FdReadSet);
- FdReadAction[pr->pr_Stdout] = NULL;
- close(pr->pr_Stdout);
- }
- if(pr->pr_Stdin && (pr->pr_Stdin != pr->pr_Stdout))
- close(pr->pr_Stdin);
- }
- mystrfree(pr);
- unprotect_procs();
- }
-
- static int
- getpty(char *slavenam)
- {
- char c;
- int i, master;
- struct stat statb;
- for(c = FIRST_PTY_LETTER; c < 'z'; c++)
- {
- for(i = 0; i < 16; i++)
- {
- sprintf(slavenam, "/dev/pty%c%x", c, i);
- if(stat(slavenam, &statb) < 0)
- goto none;
- if((master = open(slavenam, O_RDWR)) >= 0)
- {
- slavenam[sizeof("/dev/")-1] = 't';
- if(access(slavenam, R_OK | W_OK) == 0)
- return(master);
- close(master);
- }
- }
- }
- none:
- cmd_signal(sym_process_error, LIST_1(MKSTR("Can't find spare pty")));
- return(-1);
- }
-
- /*
- * does the dirty stuff of getting the process running. if `async' is
- * TRUE then return straight away, otherwise shovel all output to
- * the correct stream and return when the process dies.
- */
- static bool
- runproc(struct Proc *pr, u_char *file, char **argv, bool async)
- {
- bool rc = FALSE;
- protect_procs();
- if(pr->pr_Status == PR_DEAD)
- {
- int master;
- char slavenam[32];
- pr->pr_ExitStatus = -1;
- if((master = getpty(slavenam)) >= 0)
- {
- switch(pr->pr_Pid = fork())
- {
- int slave;
- struct termios st;
- case 0:
- if(setsid() < 0)
- {
- perror("child: setsid()");
- exit(255);
- }
- if((slave = open(slavenam, O_RDWR)) < 0)
- {
- perror("child: open(slave)");
- exit(255);
- }
- close(master);
- dup2(slave, 0);
- dup2(slave, 1);
- dup2(slave, 2);
- if(slave > 2)
- close(slave);
- #ifdef TIOCSCTTY
- ioctl(slave, TIOCSCTTY, 0);
- #endif
- tcgetattr(0, &st);
- st.c_iflag = 0;
- st.c_oflag = 0;
- st.c_cflag = B9600 | CS8 | CREAD;
- st.c_lflag = ISIG;
- st.c_cc[VMIN] = 1;
- st.c_cc[VTIME] = 0;
- tcsetattr(0, TCSANOW, &st);
- execvp(file, (char **)argv);
- perror("child: execvp");
- exit(255);
- case -1:
- perror("fork()");
- break;
- default:
- pr->pr_Stdout = master;
- pr->pr_Stdin = master;
- pr->pr_Status = PR_RUNNING;
- if(async)
- {
- /* So that write's to the process block, set up another
- fd for writing to. */
- if((pr->pr_Stdin = dup(master)) < 0)
- {
- perror("dup(master)");
- pr->pr_Stdin = master;
- }
- else
- fcntl(pr->pr_Stdin, F_SETFD, 1);
- fcntl(master, F_SETFD, 1);
- fcntl(master, F_SETFL, O_NONBLOCK);
- FD_SET(master, &FdReadSet);
- FdReadAction[master] = readfromproc;
- ProcRunCount++;
- }
- else
- {
- u_char buf[1025];
- int actual;
- do {
- actual = read(master, buf, 1024);
- if(actual > 0)
- {
- buf[actual] = 0;
- streamputs(&pr->pr_OutputStream, buf, FALSE);
- }
- } while((actual > 0) || (errno == EINTR));
- waitpid(pr->pr_Pid, &pr->pr_ExitStatus, 0);
- close(pr->pr_Stdout);
- if(pr->pr_Stdin && (pr->pr_Stdin != pr->pr_Stdout))
- close(pr->pr_Stdin);
- pr->pr_Stdin = pr->pr_Stdout = 0;
- pr->pr_Status = PR_DEAD;
- callexitfunc(pr);
- }
- rc = TRUE;
- break;
- }
- }
- }
- else
- cmd_signal(sym_process_error, list_2(pr, MKSTR("Already running")));
- unprotect_procs();
- return(rc);
- }
-
- void
- proc_mark(VALUE pr)
- {
- MARKVAL(VPROC(pr)->pr_OutputStream);
- MARKVAL(VPROC(pr)->pr_ExitFunc);
- MARKVAL(VPROC(pr)->pr_File);
- MARKVAL(VPROC(pr)->pr_Argv);
- }
- void
- proc_sweep(void)
- {
- struct Proc *pr = ProcChain;
- ProcChain = NULL;
- while(pr)
- {
- struct Proc *nxt = pr->pr_Next;
- if(!GC_MARKEDP(pr))
- killproc(pr);
- else
- {
- GC_CLR(pr);
- pr->pr_Next = ProcChain;
- ProcChain = pr;
- }
- pr = nxt;
- }
- }
- void
- proc_prin(VALUE strm, VALUE obj)
- {
- struct Proc *pr = VPROC(obj);
- u_char buf[40];
- streamputs(strm, "#<process", FALSE);
- protect_procs();
- switch(pr->pr_Status)
- {
- case PR_RUNNING:
- streamputs(strm, " running: ", FALSE);
- streamputs(strm, VSTR(pr->pr_File), TRUE);
- break;
- case PR_STOPPED:
- streamputs(strm, " stopped: ", FALSE);
- streamputs(strm, VSTR(pr->pr_File), TRUE);
- break;
- case PR_DEAD:
- case PR_EXITED:
- if(pr->pr_ExitStatus != -1)
- {
- sprintf(buf, " exited: 0x%x", pr->pr_ExitStatus);
- streamputs(strm, buf, FALSE);
- if(pr->pr_Status == PR_EXITED)
- streamputs(strm, " [waiting for eof]", FALSE);
- }
- break;
- }
- unprotect_procs();
- streamputc(strm, '>');
- }
-
- _PR VALUE cmd_make_process(VALUE stream, VALUE exitfn);
- DEFUN("make-process", cmd_make_process, subr_make_process, (VALUE stream, VALUE exitfn), V_Subr2, DOC_make_process) /*
- ::doc:make_process::
- (make-process [OUTPUT-STREAM] [EXIT-FUNCTION]) <UNIX-ONLY>
- Creates a new process-object, OUTPUT-STREAM is where all output from this
- process goes, EXIT-FUNCTION is a function to call each time a process running
- on this object exits.
- ::end:: */
- {
- struct Proc *pr = mystralloc(sizeof(struct Proc));
- if(pr)
- {
- pr->pr_Type = V_Process;
- pr->pr_Next = ProcChain;
- ProcChain = pr;
- pr->pr_Status = PR_DEAD;
- pr->pr_Pid = 0;
- pr->pr_Stdin = pr->pr_Stdout = 0;
- pr->pr_OutputStream = sym_nil;
- pr->pr_ExitStatus = -1;
- pr->pr_File = sym_nil;
- pr->pr_Argv = sym_nil;
- pr->pr_OutputStream = stream;
- pr->pr_ExitFunc = exitfn;
- return(pr);
- }
- return(NULL);
- }
-
- _PR VALUE cmd_fork_process(VALUE proc, VALUE file, VALUE vargv);
- DEFUN("fork-process", cmd_fork_process, subr_fork_process, (VALUE proc, VALUE file, VALUE vargv), V_Subr3, DOC_fork_process) /*
- ::doc:fork_process::
- (fork-process PROCESS FILE-NAME ARGV) <UNIX-ONLY>
- Starts a process running on process-object PROCESS. The child-process runs
- asynchronously with the editor.
-
- FILE-NAME is the filename of the binary image, it will be searched for in
- all directories listed in the `PATH' environment variable.
- ARGV is a vector of all arguments to give to the process (including
- argument zero, normally the name of the process).
- ::end:: */
- {
- char **argv;
- VALUE res = sym_nil;
- DECLARE1(proc, PROCESSP);
- DECLARE2(file, STRINGP);
- DECLARE3(vargv, VECTORP);
- protect_procs();
- argv = mystralloc(sizeof(char *) * (VVECT(vargv)->vc_Size + 1));
- if(argv)
- {
- int i;
- for(i = 0; i < VVECT(vargv)->vc_Size; i++)
- {
- if(STRINGP(VVECT(vargv)->vc_Array[i]))
- argv[i] = VSTR(VVECT(vargv)->vc_Array[i]);
- else
- argv[i] = "";
- }
- argv[i] = NULL;
- if(runproc(VPROC(proc), VSTR(file), argv, TRUE))
- {
- VPROC(proc)->pr_File = file;
- VPROC(proc)->pr_Argv = vargv;
- res = proc;
- }
- mystrfree(argv);
- }
- unprotect_procs();
- return(res);
- }
- _PR VALUE cmd_run_process(VALUE proc, VALUE file, VALUE vargv);
- DEFUN("run-process", cmd_run_process, subr_run_process, (VALUE proc, VALUE file, VALUE vargv), V_Subr3, DOC_run_process) /*
- ::doc:run_process::
- (run-process PROCESS FILE-NAME ARGV) <UNIX-ONLY>
- Starts a process running on process-object PROCESS. Waits for the child to
- exit, then returns the exit-value of the child.
-
- FILE-NAME is the filename of the binary image, it will be searched for in
- all directories listed in the `PATH' environment variable.
- ARGV is a vector of all arguments to give to the process (including
- argument zero, normally the name of the process).
- ::end:: */
- {
- char **argv;
- VALUE res = sym_nil;
- DECLARE1(proc, PROCESSP);
- DECLARE2(file, STRINGP);
- DECLARE3(vargv, VECTORP);
- protect_procs();
- argv = mystralloc(sizeof(char *) * (VVECT(vargv)->vc_Size + 1));
- if(argv)
- {
- int i;
- for(i = 0; i < VVECT(vargv)->vc_Size; i++)
- {
- if(STRINGP(VVECT(vargv)->vc_Array[i]))
- argv[i] = VSTR(VVECT(vargv)->vc_Array[i]);
- else
- argv[i] = "";
- }
- argv[i] = NULL;
- if(runproc(VPROC(proc), VSTR(file), argv, FALSE))
- res = newnumber(VPROC(proc)->pr_ExitStatus);
- mystrfree(argv);
- }
- unprotect_procs();
- return(res);
- }
-
- _PR VALUE cmd_signal_process(VALUE proc, VALUE sig);
- DEFUN("signal-process", cmd_signal_process, subr_signal_process, (VALUE proc, VALUE sig), V_Subr2, DOC_signal_process) /*
- ::doc:signal_process::
- (signal-process PROCESS SIGNAL) <UNIX-ONLY>
- If PROCESS is running asynchronously (or has been, and the pty is still being
- used by a child) then send signal number SIGNAL to all processes running under
- PROCESS's pseudo-terminal (if the process-group of the pseudo-terminal is
- unobtainable, send the signal to the process group with PROCESS as leader).
- ::end:: */
- {
- VALUE res = sym_nil;
- DECLARE1(proc, PROCESSP);
- DECLARE2(sig, NUMBERP);
- protect_procs();
- if(VPROC(proc)->pr_Status > 0)
- {
- if(signalprocess(VPROC(proc), VNUM(sig)))
- res = sym_t;
- }
- else
- res = cmd_signal(sym_process_error, list_2(proc, MKSTR("Not running")));
- unprotect_procs();
- return(res);
- }
-
- _PR VALUE cmd_interrupt_process(VALUE proc);
- DEFUN("interrupt-process", cmd_interrupt_process, subr_interrupt_process, (VALUE proc), V_Subr1, DOC_interrupt_process) /*
- ::doc:interrupt_process::
- (interrupt-process PROCESS) <UNIX-ONLY>
- Do (signal-process PROCESS SIGINT) or equivalent.
- ::end:: */
- {
- return(cmd_signal_process(proc, newnumber(SIGINT)));
- }
-
- _PR VALUE cmd_kill_process(VALUE proc);
- DEFUN("kill-process", cmd_kill_process, subr_kill_process, (VALUE proc), V_Subr1, DOC_kill_process) /*
- ::doc:kill_process::
- (kill-process PROCESS) <UNIX-ONLY>
- Do (signal-process PROCESS SIGKILL) or equivalent.
- ::end:: */
- {
- return(cmd_signal_process(proc, newnumber(SIGKILL)));
- }
-
- _PR VALUE cmd_stop_process(VALUE proc);
- DEFUN("stop-process", cmd_stop_process, subr_stop_process, (VALUE proc), V_Subr1, DOC_stop_process) /*
- ::doc:stop_process::
- (stop-process PROCESS) <UNIX-ONLY>
- Suspends execution of PROCESS, see `continue-process'.
- ::end:: */
- {
- return(cmd_signal_process(proc, newnumber(SIGSTOP)));
- }
-
- _PR VALUE cmd_continue_process(VALUE proc);
- DEFUN("continue-process", cmd_continue_process, subr_continue_process, (VALUE proc), V_Subr1, DOC_continue_process) /*
- ::doc:continue_process::
- (continue-process PROCESS) <UNIX-ONLY>
- Restarts PROCESS after it has been stopped (via `stop-process').
- ::end:: */
- {
- VALUE res = sym_t;
- DECLARE1(proc, PROCESSP);
- protect_procs();
- if(VPROC(proc)->pr_Status == PR_STOPPED)
- {
- if(signalprocess(VPROC(proc), SIGCONT))
- {
- VPROC(proc)->pr_Status = PR_RUNNING;
- res = sym_t;
- }
- }
- else
- res = cmd_signal(sym_process_error, list_2(proc, MKSTR("Not stopped")));
- unprotect_procs();
- return(res);
- }
-
- _PR VALUE cmd_process_exit_status(VALUE proc);
- DEFUN("process-exit-status", cmd_process_exit_status, subr_process_exit_status, (VALUE proc), V_Subr1, DOC_process_exit_status) /*
- ::doc:process_exit_status::
- (process-exit-status PROCESS) <UNIX-ONLY>
- Returns the unprocessed exit-status of the last process to be run on the
- process-object PROCESS. If PROCESS is currently running, return nil.
- ::end:: */
- {
- VALUE res = sym_nil;
- DECLARE1(proc, PROCESSP);
- protect_procs();
- if(VPROC(proc)->pr_Status <= 0)
- {
- if(VPROC(proc)->pr_ExitStatus != -1)
- res = newnumber(VPROC(proc)->pr_ExitStatus);
- }
- unprotect_procs();
- return(res);
- }
-
- _PR VALUE cmd_process_exit_value(VALUE proc);
- DEFUN("process-exit-value", cmd_process_exit_value, subr_process_exit_value, (VALUE proc), V_Subr1, DOC_process_exit_value) /*
- ::doc:process_exit_value::
- (process-exit-value PROCESS) <UNIX-ONLY>
- Returns the return-value of the last process to be run on PROCESS, or nil if:
- a) no process has run on PROCESS
- b) PROCESS is still running
- c) PROCESS exited abnormally
- ::end:: */
- {
- VALUE res = sym_nil;
- DECLARE1(proc, PROCESSP);
- protect_procs();
- if((VPROC(proc)->pr_Status <= 0) && (VPROC(proc)->pr_ExitStatus != -1))
- res = newnumber(WEXITSTATUS(VPROC(proc)->pr_ExitStatus));
- unprotect_procs();
- return(res);
- }
-
- _PR VALUE cmd_process_id(VALUE proc);
- DEFUN("process-id", cmd_process_id, subr_process_id, (VALUE proc), V_Subr1, DOC_process_id) /*
- ::doc:process_id::
- (process-id PROCESS) <UNIX-ONLY>
- If PROCESS is running, return the process-identifier associated with it
- (ie, its pid).
- ::end:: */
- {
- VALUE res = sym_nil;
- DECLARE1(proc, PROCESSP);
- protect_procs();
- if(VPROC(proc)->pr_Status > 0)
- res = newnumber(VPROC(proc)->pr_Pid);
- unprotect_procs();
- return(res);
- }
-
- _PR VALUE cmd_process_running_p(VALUE proc);
- DEFUN("process-running-p", cmd_process_running_p, subr_process_running_p, (VALUE proc), V_Subr1, DOC_process_running_p) /*
- ::doc:process_running_p::
- (process-running-p PROCESS) <UNIX-ONLY>
- Return t if PROCESS is running.
- ::end:: */
- {
- VALUE res;
- DECLARE1(proc, PROCESSP);
- protect_procs();
- if(VPROC(proc)->pr_Status == PR_RUNNING)
- res = sym_t;
- else
- res = sym_nil;
- unprotect_procs();
- return(res);
- }
-
- _PR VALUE cmd_process_stopped_p(VALUE proc);
- DEFUN("process-stopped-p", cmd_process_stopped_p, subr_process_stopped_p, (VALUE proc), V_Subr1, DOC_process_stopped_p) /*
- ::doc:process_stopped_p::
- (process-stopped-p PROCESS) <UNIX-ONLY>
- Return t if PROCESS has been stopped.
- ::end:: */
- {
- VALUE res;
- DECLARE1(proc, PROCESSP);
- protect_procs();
- if(VPROC(proc)->pr_Status == PR_STOPPED)
- res = sym_t;
- else
- res = sym_nil;
- unprotect_procs();
- return(res);
- }
-
- _PR VALUE cmd_process_in_use_p(VALUE proc);
- DEFUN("process-in-use-p", cmd_process_in_use_p, subr_process_in_use_p, (VALUE proc), V_Subr1, DOC_process_in_use_p) /*
- ::doc:process_in_use_p::
- (process-in-use-p PROCESS) <UNIX-ONLY>
- Similar to `process-running-p' except that this returns t even when the
- process has stopped, or has exited but the pty connected to `PROCESS' is still
- in use.
- ::end:: */
- {
- VALUE res;
- DECLARE1(proc, PROCESSP);
- protect_procs();
- if(VPROC(proc)->pr_Status != PR_DEAD)
- res = sym_t;
- else
- res = sym_nil;
- unprotect_procs();
- return(res);
- }
-
- _PR VALUE cmd_process_p(VALUE arg);
- DEFUN("process-p", cmd_process_p, subr_process_p, (VALUE arg), V_Subr1, DOC_process_p) /*
- ::doc:process_p::
- (process-p ARG) <UNIX-ONLY>
- Return t is ARG is a process-object.
- ::end:: */
- {
- if(PROCESSP(arg))
- return(sym_t);
- return(sym_nil);
- }
-
- _PR VALUE cmd_process_name(VALUE proc);
- DEFUN("process-name", cmd_process_name, subr_process_name, (VALUE proc), V_Subr1, DOC_process_name) /*
- ::doc:process_name::
- (process-name PROCESS) <UNIX-ONLY>
- Return the name of the program running on PROCESS.
- ::end:: */
- {
- VALUE res;
- DECLARE1(proc, PROCESSP);
- protect_procs();
- res = VPROC(proc)->pr_File;
- unprotect_procs();
- return(res);
- }
- _PR VALUE cmd_process_argv(VALUE proc);
- DEFUN("process-argv", cmd_process_argv, subr_process_argv, (VALUE proc), V_Subr1, DOC_process_argv) /*
- ::doc:process_argv::
- (process-argv PROCESS) <UNIX-ONLY>
- Return the arguments of the process running on PROCESS.
- ::end:: */
- {
- VALUE res;
- DECLARE1(proc, PROCESSP);
- protect_procs();
- res = VPROC(proc)->pr_Argv;
- unprotect_procs();
- return(res);
- }
-
- _PR VALUE cmd_process_output_stream(VALUE proc);
- DEFUN("process-output-stream", cmd_process_output_stream, subr_process_output_stream, (VALUE proc), V_Subr1, DOC_process_output_stream) /*
- ::doc:process_output_stream::
- (process-output-stream PROCESS) <UNIX-ONLY>
- Return the stream to which all output from PROCESS is sent.
- ::end:: */
- {
- VALUE res;
- DECLARE1(proc, PROCESSP);
- protect_procs();
- res = VPROC(proc)->pr_OutputStream;
- unprotect_procs();
- return(res);
- }
-
- _PR VALUE cmd_set_process_output_stream(VALUE proc, VALUE stream);
- DEFUN("set-process-output-stream", cmd_set_process_output_stream, subr_set_process_output_stream, (VALUE proc, VALUE stream), V_Subr2, DOC_set_process_output_stream) /*
- ::doc:set_process_output_stream::
- (set-process-output-stream PROCESS STREAM) <UNIX-ONLY>
- Set the output-stream of PROCESS to STREAM.
- ::end:: */
- {
- DECLARE1(proc, PROCESSP);
- protect_procs();
- VPROC(proc)->pr_OutputStream = stream;
- unprotect_procs();
- return(stream);
- }
-
- _PR VALUE cmd_process_exit_function(VALUE proc);
- DEFUN("process-exit-function", cmd_process_exit_function, subr_process_exit_function, (VALUE proc), V_Subr1, DOC_process_exit_function) /*
- ::doc:process_exit_function::
- (process-exit-function PROCESS) <UNIX-ONLY>
- Return the function which is called when PROCESS exits.
- ::end:: */
- {
- VALUE res;
- DECLARE1(proc, PROCESSP);
- protect_procs();
- res = VPROC(proc)->pr_ExitFunc;
- unprotect_procs();
- return(res);
- }
-
- _PR VALUE cmd_set_process_exit_function(VALUE proc, VALUE fn);
- DEFUN("set-process-exit-function", cmd_set_process_exit_function, subr_set_process_exit_function, (VALUE proc, VALUE fn), V_Subr2, DOC_set_process_exit_function) /*
- ::doc:set_process_exit_function::
- (set-process-exit-function PROCESS FUNCTION) <UNIX-ONLY>
- Set the function which is called when PROCESS exits to FUNCTION.
- ::end:: */
- {
- DECLARE1(proc, PROCESSP);
- protect_procs();
- VPROC(proc)->pr_ExitFunc = fn;
- unprotect_procs();
- return(fn);
- }
-
- void
- sys_proc_init(void)
- {
- #ifdef USE_SIGACTION
- /* Setup SIGCHLD stuff. */
- sigemptyset(&ChldSet);
- sigaddset(&ChldSet, SIGCHLD);
- ChldAct.sa_handler = sigchld_handler;
- ChldAct.sa_mask = ChldSet;
- # ifdef SA_RESTART
- ChldAct.sa_flags = SA_RESTART;
- # else
- ChldAct.sa_flags = 0;
- # endif
- sigaction(SIGCHLD, &ChldAct, NULL);
- #else
- signal(SIGCHLD, sigchld_handler);
- #endif
-
- /* Is this necessary?? Better safe than core-dumped ;-) */
- signal(SIGPIPE, SIG_IGN);
-
- setpgrp();
-
- ADD_SUBR(subr_make_process);
- ADD_SUBR(subr_fork_process);
- ADD_SUBR(subr_run_process);
- ADD_SUBR(subr_signal_process);
- ADD_SUBR(subr_interrupt_process);
- ADD_SUBR(subr_kill_process);
- ADD_SUBR(subr_stop_process);
- ADD_SUBR(subr_continue_process);
- ADD_SUBR(subr_process_exit_status);
- ADD_SUBR(subr_process_exit_value);
- ADD_SUBR(subr_process_id);
- ADD_SUBR(subr_process_running_p);
- ADD_SUBR(subr_process_stopped_p);
- ADD_SUBR(subr_process_in_use_p);
- ADD_SUBR(subr_process_output_stream);
- ADD_SUBR(subr_set_process_output_stream);
- ADD_SUBR(subr_process_exit_function);
- ADD_SUBR(subr_set_process_exit_function);
- }
- void
- sys_proc_kill(void)
- {
- struct Proc *pr = ProcChain;
- protect_procs();
- while(pr)
- {
- struct Proc *nxt = pr->pr_Next;
- killproc(pr);
- pr = nxt;
- }
- unprotect_procs();
- signal(SIGCHLD, SIG_IGN);
- }
-