XV6_SHELLパイプとリダイレクト

8594 ワード


#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
// Simplifed xv6 shell.

#define MAXARGS 10

// All commands have at least a type. Have looked at the type, the code
// typically casts the *cmd to some specific cmd type.
struct cmd {
  int type;          //  ' ' (exec), | (pipe), '' for redirection
};

struct execcmd {//     
  int type;              // ' '
  char *argv[MAXARGS];   // arguments to the command to be exec-ed
};

struct redircmd {
  int type;          // < or > 
  struct cmd *cmd;   // the command to be run (e.g., an execcmd)
  char *file;        // the input/output file
  int mode;          // the mode to open the file with
  int fd;            // the file descriptor number to use for the file
};

struct pipecmd {
  int type;          // |
  struct cmd *left;  // left side of pipe,  
  struct cmd *right; // right side of pipe,  
};

int fork1(void);  // Fork but exits on failure.
struct cmd *parsecmd(char*);

// Execute cmd.  Never returns.
void runcmd(struct cmd *cmd)
{
  int p[2], r;
  struct execcmd *ecmd;
  struct pipecmd *pcmd;
  struct redircmd *rcmd;

  if(cmd == 0)
    exit(0);
  
  switch(cmd->type){
  default:
    fprintf(stderr, "unknown runcmd
"); exit(-1); case ' ':// ecmd = (struct execcmd*)cmd; if(ecmd->argv[0] == 0) exit(0); // fprintf(stderr, "exec not implemented
"); // Your code here .. if (access(ecmd->argv[0], F_OK) == 0)//access ,mode_>R_OK( ),W_OK( ),X_OK( ),F_OK( ) 0, -1,execv , pathname ID ,execv(pathname,argv[]) { execv(ecmd->argv[0], ecmd->argv);//pathname ,argv , , NULL } else { const char *binPath = "/bin/"; int pathLen = strlen(binPath) + strlen(ecmd->argv[0]); char *abs_path = (char *)malloc((pathLen+1)*sizeof(char)); strcpy(abs_path, binPath);// strcat(abs_path, ecmd->argv[0]);// if(access(abs_path, F_OK)==0) { execv(abs_path, ecmd->argv); } else fprintf(stderr, "%s: Command not found
", ecmd->argv[0]); } break; case '>': case 'fd);// ,fd if(open(rcmd->file, rcmd->mode, 0644) < 0)// { fprintf(stderr, "Unable to open file: %s
", rcmd->file); exit(0); } runcmd(rcmd->cmd); break; case '|': pcmd = (struct pipecmd*)cmd; //fprintf(stderr, "pipe not implemented
"); // Your code here ... // pipe , fd , p[0] ,p[1] // dup(old_fd) fd, old-fd , fd if(pipe(p) < 0) { fprintf(stderr, "pipe failed
"); //exit(0); } if(fork1() == 0) { close(1);// dup(p[1]);// p[1] , // close(p[0]); close(p[1]); //left , 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(&r); wait(&r); break; } exit(0); } int getcmd(char *buf, int nbuf)// { if (isatty(fileno(stdin)))// fprintf(stdout, "$ ");// memset(buf, 0, nbuf); fgets(buf, nbuf, stdin);// nbuf buf if(buf[0] == 0) // EOF return -1; return 0; } int main(void) { static char buf[100]; int fd, r; // Read and run input commands. while(getcmd(buf, sizeof(buf)) >= 0){ if(buf[0] == 'c' && buf[1] == 'd' && buf[2] == ' '){// cd , // 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
, 0 if(chdir(buf+3) < 0)//chdir is the same as cd,when sucess, it will return 0, if not, it will return -1 fprintf(stderr, "cannot cd %s
", buf+3);//print the message to the file sterr(stream) continue; } if(fork1() == 0)//the conmad is not cd, then fork runcmd(parsecmd(buf));//child process,parsecmd buf, runcmd wait(&r);// } exit(0); } int fork1(void) { int pid; pid = fork(); if(pid == -1) perror("fork"); return pid; } struct cmd* execcmd(void) { struct execcmd *cmd; cmd = malloc(sizeof(*cmd)); memset(cmd, 0, sizeof(*cmd)); cmd->type = ' '; return (struct cmd*)cmd; } struct cmd* redircmd(struct cmd *subcmd, char *file, int type) { struct redircmd *cmd; cmd = malloc(sizeof(*cmd)); memset(cmd, 0, sizeof(*cmd)); cmd->type = type; cmd->cmd = subcmd; cmd->file = file; cmd->mode = (type == 'fd = (type == 'type = '|'; cmd->left = left; cmd->right = right; return (struct cmd*)cmd; } // Parsing char whitespace[] = " \t\r
\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 0:// break; case '|': case '':// s++; break; default: ret = 'a'; while(s < es && !strchr(whitespace, *s) && !strchr(symbols, *s)) s++;//s symbols break; } if(eq) *eq = s; //q eq symbols while(s < es && strchr(whitespace, *s)) s++;// *ps = s; return ret; } int peek(char **ps, char *es, char *toks)// , toks 1 { char *s; s = *ps; while(s < es && strchr(whitespace, *s))// s++; *ps = s; return *s && strchr(toks, *s);// tock } struct cmd *parseline(char**, char*); struct cmd *parsepipe(char**, char*); struct cmd *parseexec(char**, char*); // make a copy of the characters in the input buffer, starting from s through es. // null-terminate the copy to make it a string. char *mkcopy(char *s, char *es) { int n = es - s; char *c = malloc(n+1); assert(c); strncpy(c, s, n); c[n] = 0; return c; } struct cmd* parsecmd(char *s) {// char *es; struct cmd *cmd; es = s + strlen(s);//es points to the last blank char cmd = parseline(&s, es); peek(&s, es, "");//s if(s != es){ fprintf(stderr, "leftovers: %s
", s); exit(-1); } return cmd; } struct cmd* parseline(char **ps, char *es)// {// struct cmd *cmd; cmd = parsepipe(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') {// fprintf(stderr, "missing file for redirection
"); exit(-1); } switch(tok){ case '': cmd = redircmd(cmd, mkcopy(q, eq), '>'); break; } } return cmd; } struct cmd* parseexec(char **ps, char *es)// {// char *q, *eq; int tok, argc; struct execcmd *cmd; struct cmd *ret; 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') { fprintf(stderr, "syntax error
"); exit(-1); } cmd->argv[argc] = mkcopy(q, eq); argc++; if(argc >= MAXARGS) { fprintf(stderr, "too many args
"); exit(-1); } ret = parseredirs(ret, ps, es); } cmd->argv[argc] = 0; return ret; }