📄 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 10struct 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.voidruncmd(struct cmd *cmd){ int p[2]; struct backcmd *bcmd; struct execcmd *ecmd; struct listcmd *lcmd; struct pipecmd *pcmd; struct redircmd *rcmd; if(cmd == 0) exit(); switch(cmd->type){ default: panic("runcmd"); case EXEC: ecmd = (struct execcmd*)cmd; if(ecmd->argv[0] == 0) exit(); exec(ecmd->argv[0], ecmd->argv); printf(2, "exec %s failed\n", ecmd->argv[0]); break; case REDIR: rcmd = (struct redircmd*)cmd; close(rcmd->fd); if(open(rcmd->file, rcmd->mode) < 0){ printf(2, "open %s failed\n", rcmd->file); exit(); } runcmd(rcmd->cmd); break; case LIST: lcmd = (struct listcmd*)cmd; if(fork1() == 0) runcmd(lcmd->left); wait(); runcmd(lcmd->right); break; case PIPE: pcmd = (struct pipecmd*)cmd; if(pipe(p) < 0) panic("pipe"); if(fork1() == 0){ close(1); dup(p[1]); close(p[0]); close(p[1]); runcmd(pcmd->left); } if(fork1() == 0){ close(0); dup(p[0]); close(p[0]); close(p[1]); runcmd(pcmd->right); } close(p[0]); close(p[1]); wait(); wait(); break; case BACK: bcmd = (struct backcmd*)cmd; if(fork1() == 0) runcmd(bcmd->cmd); break; } exit();}intgetcmd(char *buf, int nbuf){ printf(2, "$ "); memset(buf, 0, nbuf); gets(buf, nbuf); if(buf[0] == 0) // EOF return -1; return 0;}intmain(void){ static char buf[100]; int fd; // Assumes three file descriptors open. while((fd = open("console", O_RDWR)) >= 0){ if(fd >= 3){ close(fd); break; } } // Read and run input commands. while(getcmd(buf, sizeof(buf)) >= 0){ if(buf[0] == 'c' && buf[1] == 'd' && buf[2] == ' '){ // Clumsy but will have to do for now. // Chdir has no effect on the parent if run in the child. buf[strlen(buf)-1] = 0; // chop \n if(chdir(buf+3) < 0) printf(2, "cannot cd %s\n", buf+3); continue; } if(fork1() == 0) runcmd(parsecmd(buf)); wait(); } exit();}voidpanic(char *s){ printf(2, "%s\n", s); exit();}intfork1(void){ int pid; pid = fork(); if(pid == -1) panic("fork"); return pid;}// Constructorsstruct cmd*execcmd(void){ struct execcmd *cmd; cmd = malloc(sizeof(*cmd)); memset(cmd, 0, 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, 0, 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, 0, 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, 0, 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, 0, sizeof(*cmd)); cmd->type = BACK; cmd->cmd = subcmd; return (struct cmd*)cmd;}// Parsingchar whitespace[] = " \t\r\n\v";char symbols[] = "<|>&;()";intgettoken(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 0: 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;}intpeek(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(2, "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, 0, 0); cmd = backcmd(cmd); } if(peek(ps, es, ";")){ gettoken(ps, es, 0, 0); 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, 0, 0); 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, 0, 0); if(gettoken(ps, es, &q, &eq) != 'a') panic("missing file for redirection"); switch(tok){ case '<': cmd = redircmd(cmd, q, eq, O_RDONLY, 0); break; case '>': cmd = redircmd(cmd, q, eq, O_WRONLY|O_CREATE, 1); break; case '+': // >> cmd = redircmd(cmd, q, eq, O_WRONLY|O_CREATE, 1); break; } } return cmd;}struct cmd*parseblock(char **ps, char *es){ struct cmd *cmd; if(!peek(ps, es, "(")) panic("parseblock"); gettoken(ps, es, 0, 0); cmd = parseline(ps, es); if(!peek(ps, es, ")")) panic("syntax - missing )"); gettoken(ps, es, 0, 0); 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 = 0; ret = parseredirs(ret, ps, es); while(!peek(ps, es, "|)&;")){ if((tok=gettoken(ps, es, &q, &eq)) == 0) 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] = 0; cmd->eargv[argc] = 0; 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 == 0) return 0; switch(cmd->type){ case EXEC: ecmd = (struct execcmd*)cmd; for(i=0; ecmd->argv[i]; i++) *ecmd->eargv[i] = 0; break; case REDIR: rcmd = (struct redircmd*)cmd; nulterminate(rcmd->cmd); *rcmd->efile = 0; 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;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -