|
|
Initial revision
/*************************************************************************
* This program is copyright (C) 1985, 1986 by Jonathan Payne. It is *
* provided to you without charge for use only on a licensed Unix *
* system. You may copy JOVE provided that this notice is included with *
* the copy. You may not sell copies of this program or versions *
* modified for use on microcomputer systems, unless the copies are *
* included with a Unix system distribution and the source is provided. *
*************************************************************************/
#ifdef BSD4_2
# include <sys/wait.h>
#else
# include <wait.h>
#endif
#include <signal.h>
#include <sgtty.h>
typedef struct process Process;
#define DEAD 1 /* Dead but haven't informed user yet */
#define STOPPED 2 /* Job stopped */
#define RUNNING 3 /* Just running */
#define NEW 4 /* This process is brand new */
/* If process is dead, flags says how. */
#define EXITED 1
#define KILLED 2
#define isdead(p) (p == 0 || proc_state(p) == DEAD || p->p_toproc == -1)
#define proc_buf(p) (p->p_buffer->b_name)
#define proc_cmd(p) (p->p_name)
#define proc_state(p) (p->p_state)
struct process {
Process *p_next;
int p_toproc, /* read p_fromproc and write p_toproc */
p_portpid, /* Pid of child (the portsrv) */
p_pid; /* Pid of real child i.e. not portsrv */
Buffer *p_buffer; /* Add output to end of this buffer */
char *p_name; /* ... */
char p_state, /* State */
p_howdied, /* Killed? or Exited? */
p_reason, /* If signaled, p_reason is the signal; else
it is the the exit code */
p_eof; /* Received EOF, so can be free'd up */
Mark *p_mark; /* Where output left us. */
data_obj
*p_cmd; /* Command to call when process dies */
} *procs = 0,
*cur_proc = 0;
char proc_prompt[80] = "% ";
int ProcInput,
ProcOutput,
NumProcs = 0;
static char *
pstate(p)
Process *p;
{
switch (proc_state(p)) {
case NEW:
return "Pre-birth";
case STOPPED:
return "Stopped";
case RUNNING:
return "Running";
case DEAD:
if (p->p_howdied == EXITED) {
if (p->p_reason == 0)
return "Done";
return sprint("[Exit %d]", p->p_reason);
}
return sprint("[Killed %d]", p->p_reason);
default:
return "Unknown state.";
}
}
static Process *
proc_pid(pid)
{
register Process *p;
for (p = procs; p != 0; p = p->p_next)
if (p->p_portpid == pid)
break;
return p;
}
procs_read()
{
struct header {
int pid;
int nbytes;
} header;
int n;
long nbytes;
static int here = 0;
if (here)
return;
sighold(SIGCHLD); /* Block any other children. */
here++;
for (;;) {
(void) ioctl(ProcInput, FIONREAD, (struct sgttyb *) &nbytes);
if (nbytes < sizeof header)
break;
n = read(ProcInput, (char *) &header, sizeof header);
if (n != sizeof header)
finish(1);
read_proc(header.pid, header.nbytes);
}
redisplay();
here = 0;
sigrelse(SIGCHLD);
}
read_proc(pid, nbytes)
int pid;
register int nbytes;
{
register Process *p;
int n;
char ibuf[512];
if ((p = proc_pid(pid)) == 0) {
printf("\riproc: unknown pid (%d)", pid);
return;
}
if (proc_state(p) == NEW) {
int rpid;
/* Pid of real child, not of portsrv. */
doread(ProcInput, (char *) &rpid, nbytes);
nbytes -= sizeof rpid;
p->p_pid = rpid;
p->p_state = RUNNING;
}
if (nbytes == EOF) { /* Okay to clean up this process */
p->p_eof = 1;
NumProcs--; /* As far as getch() in main is concerned */
return;
}
while (nbytes > 0) {
n = min((sizeof ibuf) - 1, nbytes);
doread(ProcInput, ibuf, n);
ibuf[n] = 0; /* Null terminate for convenience */
nbytes -= n;
proc_rec(p, ibuf);
}
}
ProcKill()
{
proc_kill(cur_proc, SIGKILL);
}
ProcInt()
{
proc_kill(cur_proc, SIGINT);
}
ProcQuit()
{
proc_kill(cur_proc, SIGQUIT);
}
static
proc_close(p)
Process *p;
{
(void) close(p->p_toproc);
p->p_toproc = -1; /* Writes will fail. */
}
do_rtp(mp)
register Mark *mp;
{
register Process *p = cur_proc;
Line *line1 = curline,
*line2 = mp->m_line;
int char1 = curchar,
char2 = mp->m_char;
char *gp;
if (isdead(p) || p->p_buffer != curbuf)
return;
(void) fixorder(&line1, &char1, &line2, &char2);
while (line1 != line2->l_next) {
gp = ltobuf(line1, genbuf) + char1;
if (line1 == line2)
gp[char2] = '\0';
else
strcat(gp, "\n");
(void) write(p->p_toproc, gp, strlen(gp));
line1 = line1->l_next;
char1 = 0;
}
}
/* VARARGS2 */
static
proc_strt(bufname, procname, cmd)
char *bufname,
*procname,
*cmd;
{
Window *owind = curwind;
int toproc[2],
pid;
Process *newp;
Buffer *bp;
char *args[25],
**cp,
foo[10],
cmdbuf[128];
int i;
bp = buf_exists(bufname);
if (bp != 0 && IsModified(bp) && bp->b_type != B_IPROCESS && bp->b_type != B_PROCESS)
complain("Command would over-write buffer %s.", procname, bufname);
pop_wind(bufname, 1, B_IPROCESS);
dopipe(toproc);
switch (pid = fork()) {
case -1:
pclose(toproc);
complain("[Fork failed.]");
case 0:
args[0] = "portsrv";
args[1] = foo;
sprintf(foo, "%d", ProcInput);
for (i = 0, cp = &cmd; cp[i] != 0; i++)
args[2 + i] = cp[i];
args[2 + i] = 0;
(void) dup2(toproc[0], 0);
(void) dup2(ProcOutput, 1);
(void) dup2(ProcOutput, 2);
pclose(toproc);
execv(PORTSRV, args);
printf("Execl failed.\n");
_exit(1);
}
sighold(SIGCHLD);
cur_proc = newp = (Process *) malloc(sizeof *newp);
newp->p_next = procs;
newp->p_state = NEW;
newp->p_mark = MakeMark(curline, curchar, FLOATER);
newp->p_cmd = 0;
cp = &cmd + 1;
cmdbuf[0] = '\0';
while (*cp != 0)
sprintf(&cmdbuf[strlen(cmdbuf)], "%s ", *cp++);
newp->p_name = copystr(cmdbuf);
procs = newp;
newp->p_portpid = pid;
newp->p_pid = -1;
newp->p_buffer = curbuf;
newp->p_toproc = toproc[1];
newp->p_reason = 0;
newp->p_eof = 0;
NumProcs++;
(void) close(toproc[0]);
sigrelse(SIGCHLD);
SetWind(owind);
}
pinit()
{
int p[2];
(void) signal(SIGCHLD, proc_child);
(void) pipe(p);
ProcInput = p[0];
ProcOutput = p[1];
(void) signal(INPUT_SIG, procs_read);
sighold(INPUT_SIG); /* Released during terminal read */
}
doread(fd, buf, n)
char *buf;
{
int nread;
if ((nread = read(fd, buf, n)) != n)
complain("Cannot read %d (got %d) bytes.", n, nread);
}
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.