diff options
| author | kaashoek <kaashoek> | 2006-08-23 01:09:24 +0000 | 
|---|---|---|
| committer | kaashoek <kaashoek> | 2006-08-23 01:09:24 +0000 | 
| commit | 8b58e81077abf4e843873f16c03077e2fafce52d (patch) | |
| tree | 9613a801fc9b3421ee79725782e3ef9bb4650574 | |
| parent | f18ab5c04e5380e0fb27f63e8335e5d621315c1d (diff) | |
| download | xv6-labs-8b58e81077abf4e843873f16c03077e2fafce52d.tar.gz xv6-labs-8b58e81077abf4e843873f16c03077e2fafce52d.tar.bz2 xv6-labs-8b58e81077abf4e843873f16c03077e2fafce52d.zip | |
i/o redirection in sh
better parsing of sh commands (copied from jos sh)
cat: read from 1 if no args
sbrk system call, but untested
getpid system call
moved locks in keyboard intr, but why do we get intr w. null characters from keyboard?
| -rw-r--r-- | Notes | 8 | ||||
| -rw-r--r-- | cat.c | 35 | ||||
| -rw-r--r-- | console.c | 17 | ||||
| -rw-r--r-- | defs.h | 1 | ||||
| -rw-r--r-- | echo.c | 2 | ||||
| -rw-r--r-- | lapic.c | 2 | ||||
| -rw-r--r-- | ls.c | 57 | ||||
| -rw-r--r-- | proc.c | 18 | ||||
| -rw-r--r-- | sh.c | 300 | ||||
| -rw-r--r-- | syscall.c | 29 | ||||
| -rw-r--r-- | syscall.h | 2 | ||||
| -rw-r--r-- | ulib.c | 17 | ||||
| -rw-r--r-- | user.h | 3 | ||||
| -rw-r--r-- | userfs.c | 4 | ||||
| -rw-r--r-- | usys.S | 2 | 
15 files changed, 428 insertions, 69 deletions
| @@ -131,3 +131,11 @@ maybe get rid of per-proc gdt and ts    one per cpu    refresh it when needed    setupsegs(proc *) + +why do we get 0 characters from keyboard? +are the locks in the right place in keyboardintr? + +sh: support pipes?  leave it for the class? +sh: dynamic memory allocation? +sh: should sh support ; () &  --- need malloc +sh: stop stdin on ctrl-d (for cat > y)
\ No newline at end of file @@ -1,17 +1,32 @@ +#include "types.h" +#include "stat.h"  #include "user.h"  char buf[513]; -int -main(int argc, char *argv[]) +void +rfile(int fd)  { -  int fd, i, cc; +  int cc; -  if(argc < 2){ -    puts("Usage: cat files...\n"); +  while((cc = read(fd, buf, sizeof(buf) - 1)) > 0){ +    buf[cc] = '\0'; +    puts(buf); +  } +  if(cc < 0){ +    puts("cat: read error\n");      exit();    } +} + +int +main(int argc, char *argv[]) +{ +  int fd, i; +  if (argc <= 1) { +    rfile(0); +  } else {    for(i = 1; i < argc; i++){      fd = open(argv[i], 0);      if(fd < 0){ @@ -20,16 +35,10 @@ main(int argc, char *argv[])        puts("\n");        exit();      } -    while((cc = read(fd, buf, sizeof(buf) - 1)) > 0){ -      buf[cc] = '\0'; -      puts(buf); -    } -    if(cc < 0){ -      puts("cat: read error\n"); -      exit(); -    } +    rfile(fd);      close(fd);    } +  }    exit();  } @@ -304,26 +304,31 @@ char kbd_buf[KBD_BUF];  int kbd_r;  int kbd_w;  struct spinlock kbd_lock; +static uint shift;  void  kbd_intr()  {    uint st, data, c; -  static uint shift; + +  acquire(&kbd_lock);    st = inb(KBSTATP);    if ((st & KBS_DIB) == 0){ +    release(&kbd_lock);      return;    }    data = inb(KBDATAP);    if (data == 0xE0) {      shift |= E0ESC; +    release(&kbd_lock);      return;    } else if (data & 0x80) {      // Key released      data = (shift & E0ESC ? data : data & 0x7F);      shift &= ~(shiftcode[data] | E0ESC); +    release(&kbd_lock);      return;    } else if (shift & E0ESC) {      // Last character was an E0 escape; or with 0x80 @@ -341,8 +346,12 @@ kbd_intr()      else if ('A' <= c && c <= 'Z')        c += 'a' - 'A';    } -   -  acquire(&kbd_lock); + +  // xxx hack +  if (c == 0x0) { +    release(&kbd_lock); +    return; +  }    if(((kbd_w + 1) % KBD_BUF) != kbd_r){      kbd_buf[kbd_w++] = c; @@ -367,7 +376,7 @@ console_read(int minor, char *dst, int n)      sleep(&kbd_r, &kbd_lock);    while(n > 0 && kbd_w != kbd_r){ -    *dst = kbd_buf[kbd_r]; +    *dst = (kbd_buf[kbd_r]) & 0xff;      cons_putc(*dst & 0xff);      dst++;      --n; @@ -16,6 +16,7 @@ struct jmpbuf;  void setupsegs(struct proc *);  struct proc * copyproc(struct proc*);  struct spinlock; +int growproc(int);  void sleep(void *, struct spinlock *);  void wakeup(void *);  void scheduler(void); @@ -1,3 +1,5 @@ +#include "types.h" +#include "stat.h"  #include "user.h"  int @@ -120,7 +120,7 @@ lapic_timerinit(void)  void  lapic_timerintr(void)  { -  cprintf("cpu%d: timer interrupt!\n", cpu()); +  // cprintf("cpu%d: timer interrupt!\n", cpu());    lapic_write (LAPIC_EOI, 0);  } @@ -7,13 +7,24 @@ char buf[512];  struct stat st;  struct dirent dirent; +void +pname(char *n) +{ +  int i; + +  for (i = 0; (i < DIRSIZ) && (n[i] != '\0') ; i++) { +      printf(1, "%c", n[i]); +  } +  for (; i < DIRSIZ; i++) +    printf(1, " "); +} +  int  main(int argc, char *argv[])  {    int fd;    uint off;    uint sz; -  int i;    if(argc > 2){      puts("Usage: ls [dir]\n"); @@ -23,7 +34,7 @@ main(int argc, char *argv[])    if (argc == 2) {      fd = open(argv[1], 0);      if(fd < 0){ -      printf(2, "ls: cannot open dir %s\n", argv[1]); +      printf(2, "ls: cannot open %s\n", argv[1]);        exit();      }     } else { @@ -38,31 +49,31 @@ main(int argc, char *argv[])      printf(2, "ls: cannot stat dir\n");      exit();    } -  if (st.st_type != T_DIR) { -    printf(2, "ls: dir is not a directory\n"); -  } -  sz = st.st_size; -  for(off = 0; off < sz; off += sizeof(struct dirent)) { -    if (read(fd, &dirent, sizeof(struct dirent)) != sizeof(struct dirent)) { -      printf(1, "ls: read error\n"); -      break; -    } -    if (dirent.inum != 0) { -      // xxx prepend to name the pathname supplied to ls (e.g. .. in ls ..) -      if (stat (dirent.name, &st) < 0)  { -	printf(1, "stat: failed %s\n", dirent.name); -	continue; + +  switch (st.st_type) { +  case T_FILE: +    pname(argv[1]); +    printf(1, "%d %d %d\n", st.st_type, st.st_ino, st.st_size); +    break; +  case T_DIR: +    sz = st.st_size; +    for(off = 0; off < sz; off += sizeof(struct dirent)) { +      if (read(fd, &dirent, sizeof(struct dirent)) != sizeof(struct dirent)) { +	printf(1, "ls: read error\n"); +	break;        } -      for (i = 0; i < DIRSIZ; i++) { -	if (dirent.name[i] != '\0') -	  printf(1, "%c", dirent.name[i]); -	else -	  printf(1, " "); +      if (dirent.inum != 0) { +	// xxx prepend to name the pathname supplied to ls (e.g. .. in ls ..) +	if (stat (dirent.name, &st) < 0)  { +	  printf(1, "stat: failed %s\n", dirent.name); +	  continue; +	} +	pname(dirent.name); +	printf(1, "%d %d %d\n", st.st_type, dirent.inum, st.st_size);        } -      printf(1, "%d %d %d\n", st.st_type, dirent.inum, st.st_size);      } +    break;    }    close(fd); -    exit();  } @@ -138,6 +138,24 @@ copyproc(struct proc* p)    return np;  } +int +growproc(int n) +{ +  struct proc *cp = curproc[cpu()]; +  char *newmem, *oldmem; + +  newmem = kalloc(cp->sz + n); +  if(newmem == 0) return -1; +  memmove(newmem, cp->mem, cp->sz); +  memset(newmem + cp->sz, 0, n); +  oldmem = cp->mem; +  cp->mem = newmem; +  kfree(oldmem, cp->sz); +  cp->sz += n; +  cprintf("growproc: added %d bytes\n", n); +  return 0; +} +  // Per-CPU process scheduler.   // Each CPU calls scheduler() after setting itself up.  // Scheduler never returns.  It loops, doing: @@ -4,52 +4,296 @@  #include "fs.h"  #include "fcntl.h" -char *args[100]; -void parse(char buf[]); +#define BUFSIZ  512 +#define MAXARGS  10 +#define MAXNODE 2 + +// only allocate nodes for i/o redir; at some point we may have to build a  +// a real parse tree. +struct node { +  int token; +  char *s; +}; +struct node list[MAXNODE]; +int nextnode; + +char buf[BUFSIZ]; +char *argv[MAXARGS]; +char argv0buf[BUFSIZ]; +int argc; + +int debug = 1; + +int parse(char *s); +void runcmd(void); +int ioredirection(void); +int gettoken(char *s, char **token); +int _gettoken(char *s, char **p1, char **p2); +void addnode(int token, char *s);  int  main(void)  { -  char buf[128]; -  int pid; -    while(1){      puts("$ ");      memset (buf, '\0', sizeof(buf));      gets(buf, sizeof(buf)); -    if(buf[0] == '\0') +    if (parse(buf) < 0)        continue; -    pid = fork(); -    if(pid == 0){ -      parse(buf); -      if (buf[0] == 'c' && buf[1] == 'd' && buf[2] == '\0') {  // cd -	chdir(&buf[3]); -      } else { -	exec(buf, args); -	printf(1, "%s: not found\n", buf); -	exit(); +    runcmd(); +  } +} + +int  +parse(char *s) +{ +  char *t; +  int c; + +  gettoken(s, 0); + +  argc = 0; +  nextnode = 0; +  while (1) { +    switch ((c = gettoken(0, &t))) { + +    case 'w':	// Add an argument +      if (argc == MAXARGS) { +	printf(2, "too many arguments\n"); +	return -1;        } +      argv[argc++] = t; +      break; +			 +    case '<':	// Input redirection +      // Grab the filename from the argument list +      if (gettoken(0, &t) != 'w') { +	printf(2, "syntax error: < not followed by word\n"); +	return -1; +      } +      addnode('<', t); +      break; +			 +    case '>':	// Output redirection +      // Grab the filename from the argument list +      if (gettoken(0, &t) != 'w') { +	printf(2, "syntax error: > not followed by word\n"); +	return -1; +      } +      addnode('>', t); +      break; + +    case 0:		// String is complete +      return 0; +			 +    default: +      printf(2, "syntax error: bad return %d from gettoken", c); +      return -1; +			      } -    if(pid > 0) -      wait();    }  } +  void -parse(char buf[]) +runcmd(void) +{ +  int i, r, pid; + +  // Return immediately if command line was empty. +  if(argc == 0) { +    if (debug) +      printf(2, "EMPTY COMMAND\n"); +    return; +  } + +  // Clean up command line. +  // Read all commands from the filesystem: add an initial '/' to +  // the command name. +  // This essentially acts like 'PATH=/'. +  if (argv[0][0] != '/') { +    argv0buf[0] = '/'; +    strcpy(argv0buf + 1, argv[0]); +    argv[0] = argv0buf; +  } +  argv[argc] = 0; +	 +  // Print the command. +  if (debug) { +    printf(2, "[%d] SPAWN:", getpid()); +    for (i = 0; argv[i]; i++) +      printf(2, " %s", argv[i]); +    for (i = 0; i < nextnode; i++) { +      printf(2, "%c %s", list[i].token, list[i].s); +    } +    printf(2, "\n"); +  } + +  if (strcmp(argv[0], "/cd") == 0) { +    if (debug) printf (2, "/cd %s is build in\n", argv[1]); +    chdir(argv[1]); +    return; +  } + +  pid = fork(); +  if (pid == 0) { +    if (ioredirection() < 0) +      exit(); +    if ((r = exec(argv0buf, (char**) argv)) < 0) { +      printf(2, "exec %s: %d\n", argv[0], r); +      exit(); +    } +  } + +  if (pid > 0) { +    if (debug) +      printf(2, "[%d] WAIT %s\n", getpid(), argv[0]); +    wait(); +    if (debug) +      printf(2, "[%d] wait finished\n", getpid()); +  } +} + +int +ioredirection(void)  { -  int j = 1; -  int i; -  args[0] = buf; -  for (i = 0; buf[i] != '\0'; i++) { -    if (buf[i] == ' ') { -      buf[i] = '\0'; -      args[j++] = buf + i + 1; -      if (j >= 100) { -	printf(2, "too many args\n"); +  int i, fd, dfd; + +  for (i = 0; i < nextnode; i++) { +    switch (list[i].token) { +    case '<': +      if ((fd = open(list[i].s, O_RDONLY)) < 0) { +	printf(2, "failed to open %s for read: %d", list[i].s, fd); +	return -1; +      } + +      if (debug) +	printf(2, "redirect 0 from %s\n", list[i].s); + +      close(0); +      if ((dfd = dup(fd)) < 0) +	printf(2, "dup failed\n"); +      if (debug) +	printf(2, "dup returns %d\n", dfd); +      close(fd); +      break; +    case '>': +      if ((fd = open(list[i].s, O_WRONLY|O_CREATE)) < 0) { +	printf(2, "failed to open %s for write: %d", list[i].s, fd);  	exit();        } + +      if (debug) +	printf(2, "redirect 1 to %s\n", list[i].s); + +      if (close(1) < 0) +	printf(2, "close 1 failed\n"); +      if ((dfd = dup(fd)) < 0) +	printf(2, "dup failed\n"); +      if (debug) +	printf(2, "dup returns %d\n", dfd); +      close(fd); +      break;      }    } -  args[j] = '\0'; +  return 0; +} + +void +addnode(int token, char *s) +{ +  if (nextnode >= MAXNODE) { +    printf(2, "addnode: ran out of nodes\n"); +    return; +  } +     +  list[nextnode].token = token; +  list[nextnode].s = s; +  nextnode++; +} + + +// gettoken(s, 0) prepares gettoken for subsequent calls and returns 0. +// gettoken(0, token) parses a shell token from the previously set string, +// null-terminates that token, stores the token pointer in '*token', +// and returns a token ID (0, '<', '>', '|', or 'w'). +// Subsequent calls to 'gettoken(0, token)' will return subsequent +// tokens from the string. + +int +gettoken(char *s, char **p1) +{ +  static int c, nc; +  static char* np1, *np2; + +  if (s) { +    nc = _gettoken(s, &np1, &np2); +    return 0; +  } +  c = nc; +  *p1 = np1; +  nc = _gettoken(np2, &np1, &np2); +  return c;  } + + +// Get the next token from string s. +// Set *p1 to the beginning of the token and *p2 just past the token. +// Returns +//	0 for end-of-string; +//	< for <; +//	> for >; +//	| for |; +//	w for a word. +// +// Eventually (once we parse the space where the \0 will go), +// words get nul-terminated. +#define WHITESPACE " \t\r\n" +#define SYMBOLS "<|>&;()" + +int +_gettoken(char *s, char **p1, char **p2) +{ +  int t; + +  if (s == 0) { +    if (debug > 1) +      printf(2, "GETTOKEN NULL\n"); +    return 0; +  } + +  if (debug > 1) +    printf(2, "GETTOKEN: %s\n", s); + +  *p1 = 0; +  *p2 = 0; + +  while (strchr(WHITESPACE, *s)) +    *s++ = 0; +  if (*s == 0) { +    if (debug > 1) +      printf(2, "EOL\n"); +    return 0; +  } +  if (strchr(SYMBOLS, *s)) { +    t = *s; +    *p1 = s; +    *s++ = 0; +    *p2 = s; +    if (debug > 1) +      printf(2, "TOK %c\n", t); +    return t; +  } +  *p1 = s; +  while (*s && !strchr(WHITESPACE SYMBOLS, *s)) +    s++; +  *p2 = s; +  if (debug > 1) { +    t = **p2; +    **p2 = 0; +    printf(2, "WORD: %s\n", *p1); +    **p2 = t; +  } +  return 'w'; +} + @@ -140,6 +140,7 @@ sys_write(void)      return -1;    if(addr + n > p->sz)      return -1; +    ret = fd_write(p->fds[fd], p->mem + addr, n);    return ret;  } @@ -421,6 +422,7 @@ sys_dup(void)      fd_close(fd1);      return -1;    } +  cp->fds[ufd1] = fd1;    fd1->type = cp->fds[fd]->type;    fd1->readable = cp->fds[fd]->readable;    fd1->writeable = cp->fds[fd]->writeable; @@ -450,6 +452,27 @@ sys_link(void)  }  int +sys_getpid(void) +{ +  struct proc *cp = curproc[cpu()]; +  return cp->pid; +} + + +int +sys_sbrk(void) +{ +  int r, n; +  struct proc *cp = curproc[cpu()]; + +  if(fetcharg(0, &n) < 0) +    return -1; +  r = growproc(n); +  setupsegs(cp);   +  return r; +} + +int  sys_exec(void)  {    struct proc *cp = curproc[cpu()]; @@ -638,6 +661,12 @@ syscall(void)    case SYS_dup:      ret = sys_dup();      break; +  case SYS_getpid: +    ret = sys_getpid(); +    break; +  case SYS_sbrk: +    ret = sys_sbrk(); +    break;    default:      cprintf("unknown sys call %d\n", num);      // XXX fault @@ -15,4 +15,6 @@  #define SYS_mkdir 16  #define SYS_chdir 17  #define SYS_dup 18 +#define SYS_getpid 19 +#define SYS_sbrk 20 @@ -20,6 +20,14 @@ strcpy(char *s, char *t)  	return os;  } +int +strcmp(const char *p, const char *q) +{ +	while (*p && *p == *q) +		p++, q++; +	return (int) ((unsigned char) *p - (unsigned char) *q); +} +  unsigned int  strlen(char *s)  { @@ -41,6 +49,15 @@ memset(void *dst, int c, unsigned int n)  }  char * +strchr(const char *s, char c) +{ +	for (; *s; s++) +		if (*s == c) +			return (char *) s; +	return 0; +} + +char *  gets(char *buf, int max)  {    int i = 0, cc; @@ -18,10 +18,13 @@ int link(char *, char *);  int mkdir(char *);  int chdir(char *);  int dup(int); +int getpid();  int stat(char *, struct stat *stat);  int puts(char*);  char* strcpy(char*, char*); +char *strchr(const char *s, char c); +int strcmp(const char *p, const char *q);  void printf(int fd, char *fmt, ...);  char *gets(char *, int max);  unsigned int strlen(char *); @@ -20,6 +20,10 @@ main(void)    printf(stdout, "userfs is running\n"); +  if (sbrk(4096) < 0) { +    printf(stdout, "sbrk failed\n"); +  } +    fd = open("echo", 0);    if(fd >= 0){      printf(stdout, "open echo ok\n"); @@ -25,3 +25,5 @@ STUB(link)  STUB(mkdir)  STUB(chdir)  STUB(dup) +STUB(getpid) +STUB(sbrk) | 
