xv6/sh.c

时间:2023-03-10 02:09:00
xv6/sh.c
 // Shell.

 #include "types.h"
#include "user.h"
#include "fcntl.h" // Parsed command representation
#define EXEC 1
#define REDIR 2
#define PIPE 3
#define LIST 4
#define BACK 5 #define MAXARGS 10 struct cmd {
int type;
}; struct execcmd {
int type;
char *argv[MAXARGS];
char *eargv[MAXARGS];
}; struct redircmd {
int type;
struct cmd *cmd;
char *file;
char *efile;
int mode;
int fd;
}; struct pipecmd {
int type;
struct cmd *left;
struct cmd *right;
}; struct listcmd {
int type;
struct cmd *left;
struct cmd *right;
}; struct backcmd {
int type;
struct cmd *cmd;
};
int fork1(void); // Fork but panics on failure.
void panic(char*);
struct cmd *parsecmd(char*); // Execute cmd. Never returns.
void
runcmd(struct cmd *cmd)
{
int p[];
struct backcmd *bcmd;
struct execcmd *ecmd;
struct listcmd *lcmd;
struct pipecmd *pcmd;
struct redircmd *rcmd; if(cmd == )
exit(); switch(cmd->type){
default:
panic("runcmd"); case EXEC:
ecmd = (struct execcmd*)cmd;
if(ecmd->argv[] == )
exit();
exec(ecmd->argv[], ecmd->argv);
printf(, "exec %s failed\n", ecmd->argv[]);
break; case REDIR:
rcmd = (struct redircmd*)cmd;
close(rcmd->fd);
if(open(rcmd->file, rcmd->mode) < ){
printf(, "open %s failed\n", rcmd->file);
exit();
}
runcmd(rcmd->cmd);
break; case LIST:
lcmd = (struct listcmd*)cmd;
if(fork1() == )
runcmd(lcmd->left);
wait();
runcmd(lcmd->right);
break; case PIPE:
pcmd = (struct pipecmd*)cmd;
if(pipe(p) < )
panic("pipe");
if(fork1() == ){
close();
dup(p[]);
close(p[]);
close(p[]);
runcmd(pcmd->left);
}
if(fork1() == ){
close();
dup(p[]);
close(p[]);
close(p[]);
runcmd(pcmd->right);
}
close(p[]);
close(p[]);
wait();
wait();
break; case BACK:
bcmd = (struct backcmd*)cmd;
if(fork1() == )
runcmd(bcmd->cmd);
break;
}
exit();
} int
getcmd(char *buf, int nbuf)
{
printf(, "$ ");
memset(buf, , nbuf);
gets(buf, nbuf);
if(buf[] == ) // EOF
return -;
return ;
} int
main(void)
{
static char buf[];
int fd; // Assumes three file descriptors open.
while((fd = open("console", O_RDWR)) >= ){
if(fd >= ){
close(fd);
break;
}
} // Read and run input commands.
while(getcmd(buf, sizeof(buf)) >= ){
if(buf[] == ’c’ && buf[] == ’d’ && buf[] == ’ ’){
// Clumsy but will have to do for now.
// Chdir has no effect on the parent if run in the child.
buf[strlen(buf)-] = ; // chop \n
if(chdir(buf+) < )
printf(, "cannot cd %s\n", buf+);
continue;
}
if(fork1() == )
runcmd(parsecmd(buf));
wait();
}
exit();
} void
panic(char *s)
{
printf(, "%s\n", s);
exit();
} int
fork1(void)
{
int pid; pid = fork();
if(pid == -)
panic("fork");
return pid;
} // Constructors struct cmd*
execcmd(void)
{
struct execcmd *cmd; cmd = malloc(sizeof(*cmd));
memset(cmd, , sizeof(*cmd));
cmd->type = EXEC;
return (struct cmd*)cmd;
} struct cmd*
redircmd(struct cmd *subcmd, char *file, char *efile, int mode, int fd)
{
struct redircmd *cmd; cmd = malloc(sizeof(*cmd));
memset(cmd, , sizeof(*cmd));
cmd->type = REDIR;
cmd->cmd = subcmd;
cmd->file = file;
cmd->efile = efile;
cmd->mode = mode;
cmd->fd = fd;
return (struct cmd*)cmd;
} struct cmd*
pipecmd(struct cmd *left, struct cmd *right)
{
struct pipecmd *cmd; cmd = malloc(sizeof(*cmd));
memset(cmd, , sizeof(*cmd));
cmd->type = PIPE;
cmd->left = left;
cmd->right = right;
return (struct cmd*)cmd;
} struct cmd*
listcmd(struct cmd *left, struct cmd *right)
{
struct listcmd *cmd; cmd = malloc(sizeof(*cmd));
memset(cmd, , sizeof(*cmd));
cmd->type = LIST;
cmd->left = left;
cmd->right = right;
return (struct cmd*)cmd;
} struct cmd*
backcmd(struct cmd *subcmd)
{
struct backcmd *cmd; cmd = malloc(sizeof(*cmd));
memset(cmd, , sizeof(*cmd));
cmd->type = BACK;
cmd->cmd = subcmd;
return (struct cmd*)cmd;
} // Parsing char whitespace[] = " \t\r\n\v";
char symbols[] = "<|>&;()"; int
gettoken(char **ps, char *es, char **q, char **eq)
{
char *s;
int ret; s = *ps;
while(s < es && strchr(whitespace, *s))
s++;
if(q)
*q = s;
ret = *s;
switch(*s){
case :
break;
case ’|’:
case ’(’:
case ’)’:
case ’;’:
case ’&’:
case ’<’:
s++;
break;
case ’>’:
s++;
if(*s == ’>’){
ret = ’+’;
s++;
}
break;
default:
ret = ’a’;
while(s < es && !strchr(whitespace, *s) && !strchr(symbols, *s))
s++;
break;
}
if(eq)
*eq = s; while(s < es && strchr(whitespace, *s))
s++;
*ps = s;
return ret;
} int
peek(char **ps, char *es, char *toks)
{
char *s; s = *ps;
while(s < es && strchr(whitespace, *s))
s++;
*ps = s;
return *s && strchr(toks, *s);
} struct cmd *parseline(char**, char*);
struct cmd *parsepipe(char**, char*);
struct cmd *parseexec(char**, char*);
struct cmd *nulterminate(struct cmd*); struct cmd*
parsecmd(char *s)
{
char *es;
struct cmd *cmd; es = s + strlen(s);
cmd = parseline(&s, es);
peek(&s, es, "");
if(s != es){
printf(, "leftovers: %s\n", s);
panic("syntax");
}
nulterminate(cmd);
return cmd;
} struct cmd*
parseline(char **ps, char *es)
{
struct cmd *cmd; cmd = parsepipe(ps, es);
while(peek(ps, es, "&")){
gettoken(ps, es, , );
cmd = backcmd(cmd);
}
if(peek(ps, es, ";")){
gettoken(ps, es, , );
cmd = listcmd(cmd, parseline(ps, es));
}
return cmd;
} struct cmd*
parsepipe(char **ps, char *es)
{
struct cmd *cmd; cmd = parseexec(ps, es);
if(peek(ps, es, "|")){
gettoken(ps, es, , );
cmd = pipecmd(cmd, parsepipe(ps, es));
}
return cmd;
} struct cmd*
parseredirs(struct cmd *cmd, char **ps, char *es)
{
int tok;
char *q, *eq; while(peek(ps, es, "<>")){
tok = gettoken(ps, es, , );
if(gettoken(ps, es, &q, &eq) != ’a’)
panic("missing file for redirection");
switch(tok){
case ’<’:
cmd = redircmd(cmd, q, eq, O_RDONLY, );
break;
case ’>’:
cmd = redircmd(cmd, q, eq, O_WRONLY|O_CREATE, );
break;
case ’+’: // >>
cmd = redircmd(cmd, q, eq, O_WRONLY|O_CREATE, );
break;
}
}
return cmd;
} struct cmd*
parseblock(char **ps, char *es)
{
struct cmd *cmd; if(!peek(ps, es, "("))
panic("parseblock");
gettoken(ps, es, , );
cmd = parseline(ps, es);
if(!peek(ps, es, ")"))
panic("syntax - missing )");
gettoken(ps, es, , );
cmd = parseredirs(cmd, ps, es);
return cmd;
} struct cmd*
parseexec(char **ps, char *es)
{
char *q, *eq;
int tok, argc;
struct execcmd *cmd;
struct cmd *ret; if(peek(ps, es, "("))
return parseblock(ps, es); ret = execcmd();
cmd = (struct execcmd*)ret; argc = ;
ret = parseredirs(ret, ps, es);
while(!peek(ps, es, "|)&;")){
if((tok=gettoken(ps, es, &q, &eq)) == )
break;
if(tok != ’a’)
panic("syntax");
cmd->argv[argc] = q;
cmd->eargv[argc] = eq;
argc++;
if(argc >= MAXARGS)
panic("too many args");
ret = parseredirs(ret, ps, es);
}
cmd->argv[argc] = ;
cmd->eargv[argc] = ;
return ret;
} // NUL-terminate all the counted strings.
struct cmd*
nulterminate(struct cmd *cmd)
{
int i;
struct backcmd *bcmd;
struct execcmd *ecmd;
struct listcmd *lcmd;
struct pipecmd *pcmd;
struct redircmd *rcmd; if(cmd == )
return ; switch(cmd->type){
case EXEC:
ecmd = (struct execcmd*)cmd;
for(i=; ecmd->argv[i]; i++)
*ecmd->eargv[i] = ;
break; case REDIR:
rcmd = (struct redircmd*)cmd;
nulterminate(rcmd->cmd);
*rcmd->efile = ;
break; case PIPE:
pcmd = (struct pipecmd*)cmd;
nulterminate(pcmd->left);
nulterminate(pcmd->right);
break; case LIST:
lcmd = (struct listcmd*)cmd;
nulterminate(lcmd->left);
nulterminate(lcmd->right);
break; case BACK:
bcmd = (struct backcmd*)cmd;
nulterminate(bcmd->cmd);
break;
}
return cmd;
}