Xinu7/src/serve11/sys/shell/shell.c
/* shell.c - shell */
#include <conf.h>
#include <kernel.h>
#include <proc.h>
#include <shell.h>
#include <cmd.h>
#include <tty.h>
struct shvars Shl; /* globals used by Xinu shell */
struct cmdent cmds[] = {CMDS}; /* shell commands */
LOCAL char errhd[] = "Syntax error\n";/* global error messages */
LOCAL char fmt[] = "Cannot open %s\n";
LOCAL char fmt2[] = "[%d]\n";
/*------------------------------------------------------------------------
* shell - Xinu shell with file redirection and background processing
*------------------------------------------------------------------------
*/
shell(dev)
int dev;
{
int ntokens;
int i, j, len;
int com;
char *outnam, *innam;
int stdin, stdout, stderr;
Bool backgnd;
char ch, mach[SHMLEN];
int child;
Shl.shncmds = sizeof(cmds)/sizeof(struct cmdent);
for (getname(mach) ; TRUE ; ) {
fprintf(dev, "%s %% ", mach);
getutim(&Shl.shlast);
if ( (len = read(dev, Shl.shbuf, SHBUFLEN)) == 0)
len = read(dev, Shl.shbuf, SHBUFLEN);
if (len == EOF)
break;
Shl.shbuf[len-1] = NULLCH;
if ( (ntokens=lexan(Shl.shbuf)) == SYSERR) {
fprintf(dev, errhd);
continue;
} else if (ntokens == 0)
continue;
outnam = innam = NULL;
backgnd = FALSE;
/* handle '&' */
if (Shl.shtktyp[ntokens-1] == '&') {
ntokens-- ;
backgnd = TRUE;
}
/* scan tokens, accumulating length; handling redirect */
for (len=0,i=0 ; i<ntokens ; ) {
if ((ch = Shl.shtktyp[i]) == '&') {
ntokens = -1;
break;
} else if (ch == '>') {
if (outnam != NULL || i >= --ntokens) {
ntokens = -1;
break;
}
outnam = Shl.shtok[i+1];
for (ntokens--,j=i ; j<ntokens ; j++) {
Shl.shtktyp[j] = Shl.shtktyp[j+2];
Shl.shtok [j] = Shl.shtok [j+2];
}
continue;
} else if (ch == '<') {
if (innam != NULL || i >= --ntokens) {
ntokens = -1;
break;
}
innam = Shl.shtok[i+1];
for (ntokens--,j=i ; j < ntokens ; j++) {
Shl.shtktyp[j] = Shl.shtktyp[j+2];
Shl.shtok [j] = Shl.shtok [j+2];
}
continue;
} else {
len += strlen(Shl.shtok[i++]);
}
}
if (ntokens <= 0) {
fprintf(dev, errhd);
continue;
}
stdin = stdout = stderr = dev;
/* Look up command in table */
for (com=0 ; com<Shl.shncmds ; com++) {
if (strcmp(cmds[com].cmdnam,Shl.shtok[0]) == 0)
break;
}
if (com >= Shl.shncmds) {
fprintf(dev, "%s: not found\n", Shl.shtok[0]);
continue;
}
/* handle built-in commands with procedure call */
if (cmds[com].cbuiltin) {
if (innam != NULL || outnam != NULL || backgnd)
fprintf(dev, errhd);
else if ( (*cmds[com].cproc)(stdin, stdout,
stderr, ntokens, Shl.shtok) == SHEXIT)
break;
continue;
}
/* Open files and redirect I/O if specified */
if (innam != NULL && (stdin=open(NAMESPACE,innam,"ro"))
== SYSERR) {
fprintf(dev, fmt, innam);
continue;
}
if (outnam != NULL && (stdout=open(NAMESPACE,outnam,"w"))
== SYSERR) {
fprintf(dev, fmt, outnam);
continue;
}
/* compute space needed for string args. (in bytes) */
len += (ntokens+2) * (sizeof(char *) + sizeof(char));
if (isodd(len))
len--;
control(dev, TCINT, getpid());
/* create process to execute conventional command */
if ( (child = create(cmds[com].cproc, SHCMDSTK, SHCMDPRI,
Shl.shtok[0],(len/sizeof(int)) + 4,
stdin, stdout, stderr, ntokens))
== SYSERR) {
fprintf(dev, "Cannot create\n");
close(stdout);
close(stdin);
continue;
}
addarg(child, ntokens, len);
setdev(child, stdin, stdout);
if (backgnd) {
fprintf(dev, fmt2, child);
resume(child);
} else {
setnok(getpid(), child);
recvclr();
resume(child);
if (receive() == INTRMSG) {
setnok(BADPID, child);
fprintf(dev, fmt2, child);
}
}
}
return(OK);
}