]> Devi Nivas Git - cs3210-lab1.git/commitdiff
i/o redirection in sh
authorkaashoek <kaashoek>
Wed, 23 Aug 2006 01:09:24 +0000 (01:09 +0000)
committerkaashoek <kaashoek>
Wed, 23 Aug 2006 01:09:24 +0000 (01:09 +0000)
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?

15 files changed:
Notes
cat.c
console.c
defs.h
echo.c
lapic.c
ls.c
proc.c
sh.c
syscall.c
syscall.h
ulib.c
user.h
userfs.c
usys.S

diff --git a/Notes b/Notes
index dd81f1b9c9c42a226ffb15bb81a9076ebd88fa73..4c9855dd67904435d4dc731dd02b2ac6c9b1c88b 100644 (file)
--- a/Notes
+++ b/Notes
@@ -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
diff --git a/cat.c b/cat.c
index 8154ae2bc80308061792e8ea33704f5973faf804..631bd0982764d10cfbe7e0ac76e6ade6ed20c76d 100644 (file)
--- a/cat.c
+++ b/cat.c
@@ -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();
 }
index 3d19a8e2f8024641542f51b7c40ed2a5685201ab..d1741ddce43ec803bfb8a63caac0500a9a378fd1 100644 (file)
--- a/console.c
+++ b/console.c
@@ -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;
diff --git a/defs.h b/defs.h
index 292842834d897b8eca225da6c8703929f43ff8c0..b8b7b84e0d93e136e5cb65cfdf0b8339675c105f 100644 (file)
--- a/defs.h
+++ b/defs.h
@@ -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);
diff --git a/echo.c b/echo.c
index 5d0c5a488e71787fcdae2a90e0e74305ea0b8cb8..7bf3a45fe316dcd14b7c9ee85173af719c05de44 100644 (file)
--- a/echo.c
+++ b/echo.c
@@ -1,3 +1,5 @@
+#include "types.h"
+#include "stat.h"
 #include "user.h"
 
 int
diff --git a/lapic.c b/lapic.c
index 161d0a52d70ac313197c1ed73f86ea7e6a0d221e..0d389f1af91bf97d7df38d251cbab898276917aa 100644 (file)
--- a/lapic.c
+++ b/lapic.c
@@ -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);
 }
 
diff --git a/ls.c b/ls.c
index 3441eba9343be7b8aa8a10891c14cd36b6f1d926..34fac2a1d97ea3e9a0570bcfdbc6e3f35996fafc 100644 (file)
--- a/ls.c
+++ b/ls.c
@@ -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();
 }
diff --git a/proc.c b/proc.c
index 9f7064f668d1578c1c750757445a251948323d17..7382add8b2ba61399717f8b759558472bb797d06 100644 (file)
--- a/proc.c
+++ b/proc.c
@@ -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:
diff --git a/sh.c b/sh.c
index 9e0cb3f73bca2b2c93f1d1ca2ddcfa025c75ee15..2f2d2976b88fe8a7ee9b658fa36f6c92b5628863 100644 (file)
--- a/sh.c
+++ b/sh.c
 #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';
+}
+
index 80d5d8ebff97dd511a0d2e9cdbccd36256d936a1..39c6821f1d5130bdd797fd3795f4d5b36c6cde36 100644 (file)
--- a/syscall.c
+++ b/syscall.c
@@ -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;
@@ -449,6 +451,27 @@ sys_link(void)
   return r;
 }
 
+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)
 {
@@ -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
index c89d5a34d5a015a82c5442442272e87d708844ca..4efd2555f5e22309fd168c01db7e22eca8fc154d 100644 (file)
--- a/syscall.h
+++ b/syscall.h
@@ -15,4 +15,6 @@
 #define SYS_mkdir 16
 #define SYS_chdir 17
 #define SYS_dup 18
+#define SYS_getpid 19
+#define SYS_sbrk 20
 
diff --git a/ulib.c b/ulib.c
index 004b934209fdb08a86b2e2257e21ab52be95197f..c6c7f19973ea494f7dfe1f191d2cb3d4fbadf8d7 100644 (file)
--- a/ulib.c
+++ b/ulib.c
@@ -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)
 {
@@ -40,6 +48,15 @@ memset(void *dst, int c, unsigned int n)
   return dst;
 }
 
+char *
+strchr(const char *s, char c)
+{
+       for (; *s; s++)
+               if (*s == c)
+                       return (char *) s;
+       return 0;
+}
+
 char *
 gets(char *buf, int max)
 {
diff --git a/user.h b/user.h
index 26d984c95268f291197b446c5076757701c57b93..cc82ccf076b3b34a9123760417b1f29792124fa6 100644 (file)
--- a/user.h
+++ b/user.h
@@ -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 *);
index 25dfaf55950dbcc991f6a66990d4cb94934db385..d1cd49ee8ab31998980fd1556cf16730a7c96cf7 100644 (file)
--- a/userfs.c
+++ b/userfs.c
@@ -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");
diff --git a/usys.S b/usys.S
index c7a162ce6116dcccd63ce7136674aeb8256fe09f..617fdc5f319f24683495d008c2089af9fb90053d 100644 (file)
--- a/usys.S
+++ b/usys.S
@@ -25,3 +25,5 @@ STUB(link)
 STUB(mkdir)
 STUB(chdir)
 STUB(dup)
+STUB(getpid)
+STUB(sbrk)