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?
This commit is contained in:
kaashoek 2006-08-23 01:09:24 +00:00
parent f18ab5c04e
commit 8b58e81077
15 changed files with 433 additions and 74 deletions

8
Notes
View file

@ -131,3 +131,11 @@ maybe get rid of per-proc gdt and ts
one per cpu one per cpu
refresh it when needed refresh it when needed
setupsegs(proc *) 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)

37
cat.c
View file

@ -1,17 +1,32 @@
#include "types.h"
#include "stat.h"
#include "user.h" #include "user.h"
char buf[513]; char buf[513];
void
rfile(int fd)
{
int cc;
while((cc = read(fd, buf, sizeof(buf) - 1)) > 0){
buf[cc] = '\0';
puts(buf);
}
if(cc < 0){
puts("cat: read error\n");
exit();
}
}
int int
main(int argc, char *argv[]) main(int argc, char *argv[])
{ {
int fd, i, cc; int fd, i;
if(argc < 2){
puts("Usage: cat files...\n");
exit();
}
if (argc <= 1) {
rfile(0);
} else {
for(i = 1; i < argc; i++){ for(i = 1; i < argc; i++){
fd = open(argv[i], 0); fd = open(argv[i], 0);
if(fd < 0){ if(fd < 0){
@ -20,16 +35,10 @@ main(int argc, char *argv[])
puts("\n"); puts("\n");
exit(); exit();
} }
while((cc = read(fd, buf, sizeof(buf) - 1)) > 0){ rfile(fd);
buf[cc] = '\0';
puts(buf);
}
if(cc < 0){
puts("cat: read error\n");
exit();
}
close(fd); close(fd);
} }
}
exit(); exit();
} }

View file

@ -304,26 +304,31 @@ char kbd_buf[KBD_BUF];
int kbd_r; int kbd_r;
int kbd_w; int kbd_w;
struct spinlock kbd_lock; struct spinlock kbd_lock;
static uint shift;
void void
kbd_intr() kbd_intr()
{ {
uint st, data, c; uint st, data, c;
static uint shift;
acquire(&kbd_lock);
st = inb(KBSTATP); st = inb(KBSTATP);
if ((st & KBS_DIB) == 0){ if ((st & KBS_DIB) == 0){
release(&kbd_lock);
return; return;
} }
data = inb(KBDATAP); data = inb(KBDATAP);
if (data == 0xE0) { if (data == 0xE0) {
shift |= E0ESC; shift |= E0ESC;
release(&kbd_lock);
return; return;
} else if (data & 0x80) { } else if (data & 0x80) {
// Key released // Key released
data = (shift & E0ESC ? data : data & 0x7F); data = (shift & E0ESC ? data : data & 0x7F);
shift &= ~(shiftcode[data] | E0ESC); shift &= ~(shiftcode[data] | E0ESC);
release(&kbd_lock);
return; return;
} else if (shift & E0ESC) { } else if (shift & E0ESC) {
// Last character was an E0 escape; or with 0x80 // Last character was an E0 escape; or with 0x80
@ -341,8 +346,12 @@ kbd_intr()
else if ('A' <= c && c <= 'Z') else if ('A' <= c && c <= 'Z')
c += 'a' - 'A'; c += 'a' - 'A';
} }
acquire(&kbd_lock); // xxx hack
if (c == 0x0) {
release(&kbd_lock);
return;
}
if(((kbd_w + 1) % KBD_BUF) != kbd_r){ if(((kbd_w + 1) % KBD_BUF) != kbd_r){
kbd_buf[kbd_w++] = c; kbd_buf[kbd_w++] = c;
@ -367,7 +376,7 @@ console_read(int minor, char *dst, int n)
sleep(&kbd_r, &kbd_lock); sleep(&kbd_r, &kbd_lock);
while(n > 0 && kbd_w != kbd_r){ while(n > 0 && kbd_w != kbd_r){
*dst = kbd_buf[kbd_r]; *dst = (kbd_buf[kbd_r]) & 0xff;
cons_putc(*dst & 0xff); cons_putc(*dst & 0xff);
dst++; dst++;
--n; --n;

1
defs.h
View file

@ -16,6 +16,7 @@ struct jmpbuf;
void setupsegs(struct proc *); void setupsegs(struct proc *);
struct proc * copyproc(struct proc*); struct proc * copyproc(struct proc*);
struct spinlock; struct spinlock;
int growproc(int);
void sleep(void *, struct spinlock *); void sleep(void *, struct spinlock *);
void wakeup(void *); void wakeup(void *);
void scheduler(void); void scheduler(void);

2
echo.c
View file

@ -1,3 +1,5 @@
#include "types.h"
#include "stat.h"
#include "user.h" #include "user.h"
int int

View file

@ -120,7 +120,7 @@ lapic_timerinit(void)
void void
lapic_timerintr(void) lapic_timerintr(void)
{ {
cprintf("cpu%d: timer interrupt!\n", cpu()); // cprintf("cpu%d: timer interrupt!\n", cpu());
lapic_write (LAPIC_EOI, 0); lapic_write (LAPIC_EOI, 0);
} }

57
ls.c
View file

@ -7,13 +7,24 @@ char buf[512];
struct stat st; struct stat st;
struct dirent dirent; 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 int
main(int argc, char *argv[]) main(int argc, char *argv[])
{ {
int fd; int fd;
uint off; uint off;
uint sz; uint sz;
int i;
if(argc > 2){ if(argc > 2){
puts("Usage: ls [dir]\n"); puts("Usage: ls [dir]\n");
@ -23,7 +34,7 @@ main(int argc, char *argv[])
if (argc == 2) { if (argc == 2) {
fd = open(argv[1], 0); fd = open(argv[1], 0);
if(fd < 0){ if(fd < 0){
printf(2, "ls: cannot open dir %s\n", argv[1]); printf(2, "ls: cannot open %s\n", argv[1]);
exit(); exit();
} }
} else { } else {
@ -38,31 +49,31 @@ main(int argc, char *argv[])
printf(2, "ls: cannot stat dir\n"); printf(2, "ls: cannot stat dir\n");
exit(); exit();
} }
if (st.st_type != T_DIR) {
printf(2, "ls: dir is not a directory\n"); switch (st.st_type) {
} case T_FILE:
sz = st.st_size; pname(argv[1]);
for(off = 0; off < sz; off += sizeof(struct dirent)) { printf(1, "%d %d %d\n", st.st_type, st.st_ino, st.st_size);
if (read(fd, &dirent, sizeof(struct dirent)) != sizeof(struct dirent)) { break;
printf(1, "ls: read error\n"); case T_DIR:
break; sz = st.st_size;
} for(off = 0; off < sz; off += sizeof(struct dirent)) {
if (dirent.inum != 0) { if (read(fd, &dirent, sizeof(struct dirent)) != sizeof(struct dirent)) {
// xxx prepend to name the pathname supplied to ls (e.g. .. in ls ..) printf(1, "ls: read error\n");
if (stat (dirent.name, &st) < 0) { break;
printf(1, "stat: failed %s\n", dirent.name);
continue;
} }
for (i = 0; i < DIRSIZ; i++) { if (dirent.inum != 0) {
if (dirent.name[i] != '\0') // xxx prepend to name the pathname supplied to ls (e.g. .. in ls ..)
printf(1, "%c", dirent.name[i]); if (stat (dirent.name, &st) < 0) {
else printf(1, "stat: failed %s\n", dirent.name);
printf(1, " "); 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); close(fd);
exit(); exit();
} }

18
proc.c
View file

@ -138,6 +138,24 @@ copyproc(struct proc* p)
return np; 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. // Per-CPU process scheduler.
// Each CPU calls scheduler() after setting itself up. // Each CPU calls scheduler() after setting itself up.
// Scheduler never returns. It loops, doing: // Scheduler never returns. It loops, doing:

308
sh.c
View file

@ -4,52 +4,296 @@
#include "fs.h" #include "fs.h"
#include "fcntl.h" #include "fcntl.h"
char *args[100]; #define BUFSIZ 512
void parse(char buf[]); #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 int
main(void) main(void)
{ {
char buf[128];
int pid;
while(1){ while(1){
puts("$ "); puts("$ ");
memset (buf, '\0', sizeof(buf)); memset (buf, '\0', sizeof(buf));
gets(buf, sizeof(buf)); gets(buf, sizeof(buf));
if(buf[0] == '\0') if (parse(buf) < 0)
continue; continue;
pid = fork(); runcmd();
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();
}
}
if(pid > 0)
wait();
} }
} }
void int
parse(char buf[]) parse(char *s)
{ {
int j = 1; char *t;
int i; int c;
args[0] = buf;
for (i = 0; buf[i] != '\0'; i++) { gettoken(s, 0);
if (buf[i] == ' ') {
buf[i] = '\0'; argc = 0;
args[j++] = buf + i + 1; nextnode = 0;
if (j >= 100) { while (1) {
printf(2, "too many args\n"); switch ((c = gettoken(0, &t))) {
exit();
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;
} }
} }
args[j] = '\0';
} }
void
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 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;
}
}
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';
}

View file

@ -140,6 +140,7 @@ sys_write(void)
return -1; return -1;
if(addr + n > p->sz) if(addr + n > p->sz)
return -1; return -1;
ret = fd_write(p->fds[fd], p->mem + addr, n); ret = fd_write(p->fds[fd], p->mem + addr, n);
return ret; return ret;
} }
@ -421,6 +422,7 @@ sys_dup(void)
fd_close(fd1); fd_close(fd1);
return -1; return -1;
} }
cp->fds[ufd1] = fd1;
fd1->type = cp->fds[fd]->type; fd1->type = cp->fds[fd]->type;
fd1->readable = cp->fds[fd]->readable; fd1->readable = cp->fds[fd]->readable;
fd1->writeable = cp->fds[fd]->writeable; fd1->writeable = cp->fds[fd]->writeable;
@ -449,6 +451,27 @@ sys_link(void)
return r; 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 int
sys_exec(void) sys_exec(void)
{ {
@ -638,6 +661,12 @@ syscall(void)
case SYS_dup: case SYS_dup:
ret = sys_dup(); ret = sys_dup();
break; break;
case SYS_getpid:
ret = sys_getpid();
break;
case SYS_sbrk:
ret = sys_sbrk();
break;
default: default:
cprintf("unknown sys call %d\n", num); cprintf("unknown sys call %d\n", num);
// XXX fault // XXX fault

View file

@ -15,4 +15,6 @@
#define SYS_mkdir 16 #define SYS_mkdir 16
#define SYS_chdir 17 #define SYS_chdir 17
#define SYS_dup 18 #define SYS_dup 18
#define SYS_getpid 19
#define SYS_sbrk 20

17
ulib.c
View file

@ -20,6 +20,14 @@ strcpy(char *s, char *t)
return os; 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 unsigned int
strlen(char *s) strlen(char *s)
{ {
@ -40,6 +48,15 @@ memset(void *dst, int c, unsigned int n)
return dst; return dst;
} }
char *
strchr(const char *s, char c)
{
for (; *s; s++)
if (*s == c)
return (char *) s;
return 0;
}
char * char *
gets(char *buf, int max) gets(char *buf, int max)
{ {

3
user.h
View file

@ -18,10 +18,13 @@ int link(char *, char *);
int mkdir(char *); int mkdir(char *);
int chdir(char *); int chdir(char *);
int dup(int); int dup(int);
int getpid();
int stat(char *, struct stat *stat); int stat(char *, struct stat *stat);
int puts(char*); int puts(char*);
char* strcpy(char*, 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, ...); void printf(int fd, char *fmt, ...);
char *gets(char *, int max); char *gets(char *, int max);
unsigned int strlen(char *); unsigned int strlen(char *);

View file

@ -20,6 +20,10 @@ main(void)
printf(stdout, "userfs is running\n"); printf(stdout, "userfs is running\n");
if (sbrk(4096) < 0) {
printf(stdout, "sbrk failed\n");
}
fd = open("echo", 0); fd = open("echo", 0);
if(fd >= 0){ if(fd >= 0){
printf(stdout, "open echo ok\n"); printf(stdout, "open echo ok\n");

2
usys.S
View file

@ -25,3 +25,5 @@ STUB(link)
STUB(mkdir) STUB(mkdir)
STUB(chdir) STUB(chdir)
STUB(dup) STUB(dup)
STUB(getpid)
STUB(sbrk)