This commit is contained in:
Anish Athalye
2018-10-24 20:44:45 -04:00
parent da1f8392b1
commit c67463e23c
71 changed files with 4734 additions and 18 deletions

View File

@@ -10,7 +10,8 @@ $(OBJDIR)/user/%.o: user/%.c $(OBJDIR)/.vars.USER_CFLAGS
$(OBJDIR)/user/%: $(OBJDIR)/user/%.o $(OBJDIR)/lib/entry.o $(USERLIBS:%=$(OBJDIR)/lib/lib%.a) user/user.ld
@echo + ld $@
$(V)$(LD) -o $@ $(ULDFLAGS) $(LDFLAGS) -nostdlib $(OBJDIR)/lib/entry.o $@.o -L$(OBJDIR)/lib $(USERLIBS:%=-l%) $(GCC_LIB)
$(V)$(OBJDUMP) -S $@ > $@.asm
$(V)$(NM) -n $@ > $@.sym
$(V)$(LD) -o $@.debug $(ULDFLAGS) $(LDFLAGS) -nostdlib $(OBJDIR)/lib/entry.o $@.o -L$(OBJDIR)/lib $(USERLIBS:%=-l%) $(GCC_LIB)
$(V)$(OBJDUMP) -S $@.debug > $@.asm
$(V)$(NM) -n $@.debug > $@.sym
$(V)$(OBJCOPY) -R .stab -R .stabstr --add-gnu-debuglink=$(basename $@.debug) $@.debug $@

36
user/cat.c Normal file
View File

@@ -0,0 +1,36 @@
#include <inc/lib.h>
char buf[8192];
void
cat(int f, char *s)
{
long n;
int r;
while ((n = read(f, buf, (long)sizeof(buf))) > 0)
if ((r = write(1, buf, n)) != n)
panic("write error copying %s: %e", s, r);
if (n < 0)
panic("error reading %s: %e", s, n);
}
void
umain(int argc, char **argv)
{
int f, i;
binaryname = "cat";
if (argc == 1)
cat(0, "<stdin>");
else
for (i = 1; i < argc; i++) {
f = open(argv[i], O_RDONLY);
if (f < 0)
printf("can't open %s: %e\n", argv[i], f);
else {
cat(f, argv[i]);
close(f);
}
}
}

21
user/echo.c Normal file
View File

@@ -0,0 +1,21 @@
#include <inc/lib.h>
void
umain(int argc, char **argv)
{
int i, nflag;
nflag = 0;
if (argc > 1 && strcmp(argv[1], "-n") == 0) {
nflag = 1;
argc--;
argv++;
}
for (i = 1; i < argc; i++) {
if (i > 1)
write(1, " ", 1);
write(1, argv[i], strlen(argv[i]));
}
if (!nflag)
write(1, "\n", 1);
}

22
user/faultio.c Normal file
View File

@@ -0,0 +1,22 @@
// test user-level fault handler -- alloc pages to fix faults
#include <inc/lib.h>
#include <inc/x86.h>
void
umain(int argc, char **argv)
{
int x, r;
int nsecs = 1;
int secno = 0;
int diskno = 1;
if (read_eflags() & FL_IOPL_3)
cprintf("eflags wrong\n");
// this outb to select disk 1 should result in a general protection
// fault, because user-level code shouldn't be able to use the io space.
outb(0x1F6, 0xE0 | (1<<4));
cprintf("%s: made it here --- bug\n");
}

29
user/icode.c Normal file
View File

@@ -0,0 +1,29 @@
#include <inc/lib.h>
void
umain(int argc, char **argv)
{
int fd, n, r;
char buf[512+1];
binaryname = "icode";
cprintf("icode startup\n");
cprintf("icode: open /motd\n");
if ((fd = open("/motd", O_RDONLY)) < 0)
panic("icode: open /motd: %e", fd);
cprintf("icode: read /motd\n");
while ((n = read(fd, buf, sizeof buf-1)) > 0)
sys_cputs(buf, n);
cprintf("icode: close /motd\n");
close(fd);
cprintf("icode: spawn /init\n");
if ((r = spawnl("/init", "init", "initarg1", "initarg2", (char*)0)) < 0)
panic("icode: spawn /init: %e", r);
cprintf("icode: exiting\n");
}

69
user/init.c Normal file
View File

@@ -0,0 +1,69 @@
#include <inc/lib.h>
struct {
char msg1[5000];
char msg2[1000];
} data = {
"this is initialized data",
"so is this"
};
char bss[6000];
int
sum(const char *s, int n)
{
int i, tot = 0;
for (i = 0; i < n; i++)
tot ^= i * s[i];
return tot;
}
void
umain(int argc, char **argv)
{
int i, r, x, want;
char args[256];
cprintf("init: running\n");
want = 0xf989e;
if ((x = sum((char*)&data, sizeof data)) != want)
cprintf("init: data is not initialized: got sum %08x wanted %08x\n",
x, want);
else
cprintf("init: data seems okay\n");
if ((x = sum(bss, sizeof bss)) != 0)
cprintf("bss is not initialized: wanted sum 0 got %08x\n", x);
else
cprintf("init: bss seems okay\n");
// output in one syscall per line to avoid output interleaving
strcat(args, "init: args:");
for (i = 0; i < argc; i++) {
strcat(args, " '");
strcat(args, argv[i]);
strcat(args, "'");
}
cprintf("%s\n", args);
cprintf("init: running sh\n");
// being run directly from kernel, so no file descriptors open yet
close(0);
if ((r = opencons()) < 0)
panic("opencons: %e", r);
if (r != 0)
panic("first opencons used fd %d", r);
if ((r = dup(0, 1)) < 0)
panic("dup: %e", r);
while (1) {
cprintf("init: starting sh\n");
r = spawnl("/sh", "sh", (char*)0);
if (r < 0) {
cprintf("init: spawn sh: %e\n", r);
continue;
}
wait(r);
}
}

27
user/initsh.c Normal file
View File

@@ -0,0 +1,27 @@
#include <inc/lib.h>
void
umain(int argc, char **argv)
{
int i, r, x, want;
cprintf("initsh: running sh\n");
// being run directly from kernel, so no file descriptors open yet
close(0);
if ((r = opencons()) < 0)
panic("opencons: %e", r);
if (r != 0)
panic("first opencons used fd %d", r);
if ((r = dup(0, 1)) < 0)
panic("dup: %e", r);
while (1) {
cprintf("init: starting sh\n");
r = spawnl("/sh", "sh", (char*)0);
if (r < 0) {
cprintf("init: spawn sh: %e\n", r);
continue;
}
wait(r);
}
}

91
user/ls.c Normal file
View File

@@ -0,0 +1,91 @@
#include <inc/lib.h>
int flag[256];
void lsdir(const char*, const char*);
void ls1(const char*, bool, off_t, const char*);
void
ls(const char *path, const char *prefix)
{
int r;
struct Stat st;
if ((r = stat(path, &st)) < 0)
panic("stat %s: %e", path, r);
if (st.st_isdir && !flag['d'])
lsdir(path, prefix);
else
ls1(0, st.st_isdir, st.st_size, path);
}
void
lsdir(const char *path, const char *prefix)
{
int fd, n;
struct File f;
if ((fd = open(path, O_RDONLY)) < 0)
panic("open %s: %e", path, fd);
while ((n = readn(fd, &f, sizeof f)) == sizeof f)
if (f.f_name[0])
ls1(prefix, f.f_type==FTYPE_DIR, f.f_size, f.f_name);
if (n > 0)
panic("short read in directory %s", path);
if (n < 0)
panic("error reading directory %s: %e", path, n);
}
void
ls1(const char *prefix, bool isdir, off_t size, const char *name)
{
const char *sep;
if(flag['l'])
printf("%11d %c ", size, isdir ? 'd' : '-');
if(prefix) {
if (prefix[0] && prefix[strlen(prefix)-1] != '/')
sep = "/";
else
sep = "";
printf("%s%s", prefix, sep);
}
printf("%s", name);
if(flag['F'] && isdir)
printf("/");
printf("\n");
}
void
usage(void)
{
printf("usage: ls [-dFl] [file...]\n");
exit();
}
void
umain(int argc, char **argv)
{
int i;
struct Argstate args;
argstart(&argc, argv, &args);
while ((i = argnext(&args)) >= 0)
switch (i) {
case 'd':
case 'F':
case 'l':
flag[i]++;
break;
default:
usage();
}
if (argc == 1)
ls("/", "");
else {
for (i = 1; i < argc; i++)
ls(argv[i], argv[i]);
}
}

35
user/lsfd.c Normal file
View File

@@ -0,0 +1,35 @@
#include <inc/lib.h>
void
usage(void)
{
cprintf("usage: lsfd [-1]\n");
exit();
}
void
umain(int argc, char **argv)
{
int i, usefprint = 0;
struct Stat st;
struct Argstate args;
argstart(&argc, argv, &args);
while ((i = argnext(&args)) >= 0)
if (i == '1')
usefprint = 1;
else
usage();
for (i = 0; i < 32; i++)
if (fstat(i, &st) >= 0) {
if (usefprint)
fprintf(1, "fd %d: name %s isdir %d size %d dev %s\n",
i, st.st_name, st.st_isdir,
st.st_size, st.st_dev->dev_name);
else
cprintf("fd %d: name %s isdir %d size %d dev %s\n",
i, st.st_name, st.st_isdir,
st.st_size, st.st_dev->dev_name);
}
}

47
user/num.c Normal file
View File

@@ -0,0 +1,47 @@
#include <inc/lib.h>
int bol = 1;
int line = 0;
void
num(int f, const char *s)
{
long n;
int r;
char c;
while ((n = read(f, &c, 1)) > 0) {
if (bol) {
printf("%5d ", ++line);
bol = 0;
}
if ((r = write(1, &c, 1)) != 1)
panic("write error copying %s: %e", s, r);
if (c == '\n')
bol = 1;
}
if (n < 0)
panic("error reading %s: %e", s, n);
}
void
umain(int argc, char **argv)
{
int f, i;
binaryname = "num";
if (argc == 1)
num(0, "<stdin>");
else
for (i = 1; i < argc; i++) {
f = open(argv[i], O_RDONLY);
if (f < 0)
panic("can't open %s: %e", argv[i], f);
else {
num(f, argv[i]);
close(f);
}
}
exit();
}

76
user/primespipe.c Normal file
View File

@@ -0,0 +1,76 @@
// Concurrent version of prime sieve of Eratosthenes.
// Invented by Doug McIlroy, inventor of Unix pipes.
// See http://swtch.com/~rsc/thread/.
// The picture halfway down the page and the text surrounding it
// explain what's going on here.
//
// Since NENV is 1024, we can print 1022 primes before running out.
// The remaining two environments are the integer generator at the bottom
// of main and user/idle.
#include <inc/lib.h>
unsigned
primeproc(int fd)
{
int i, id, p, pfd[2], wfd, r;
// fetch a prime from our left neighbor
top:
if ((r = readn(fd, &p, 4)) != 4)
panic("primeproc could not read initial prime: %d, %e", r, r >= 0 ? 0 : r);
cprintf("%d\n", p);
// fork a right neighbor to continue the chain
if ((i=pipe(pfd)) < 0)
panic("pipe: %e", i);
if ((id = fork()) < 0)
panic("fork: %e", id);
if (id == 0) {
close(fd);
close(pfd[1]);
fd = pfd[0];
goto top;
}
close(pfd[0]);
wfd = pfd[1];
// filter out multiples of our prime
for (;;) {
if ((r=readn(fd, &i, 4)) != 4)
panic("primeproc %d readn %d %d %e", p, fd, r, r >= 0 ? 0 : r);
if (i%p)
if ((r=write(wfd, &i, 4)) != 4)
panic("primeproc %d write: %d %e", p, r, r >= 0 ? 0 : r);
}
}
void
umain(int argc, char **argv)
{
int i, id, p[2], r;
binaryname = "primespipe";
if ((i=pipe(p)) < 0)
panic("pipe: %e", i);
// fork the first prime process in the chain
if ((id=fork()) < 0)
panic("fork: %e", id);
if (id == 0) {
close(p[1]);
primeproc(p[0]);
}
close(p[0]);
// feed all the integers through
for (i=2;; i++)
if ((r=write(p[1], &i, 4)) != 4)
panic("generator write: %d, %e", r, r >= 0 ? 0 : r);
}

322
user/sh.c Normal file
View File

@@ -0,0 +1,322 @@
#include <inc/lib.h>
#define BUFSIZ 1024 /* Find the buffer overrun bug! */
int debug = 0;
// 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 **token);
// Parse a shell command from string 's' and execute it.
// Do not return until the shell command is finished.
// runcmd() is called in a forked child,
// so it's OK to manipulate file descriptor state.
#define MAXARGS 16
void
runcmd(char* s)
{
char *argv[MAXARGS], *t, argv0buf[BUFSIZ];
int argc, c, i, r, p[2], fd, pipe_child;
pipe_child = 0;
gettoken(s, 0);
again:
argc = 0;
while (1) {
switch ((c = gettoken(0, &t))) {
case 'w': // Add an argument
if (argc == MAXARGS) {
cprintf("too many arguments\n");
exit();
}
argv[argc++] = t;
break;
case '<': // Input redirection
// Grab the filename from the argument list
if (gettoken(0, &t) != 'w') {
cprintf("syntax error: < not followed by word\n");
exit();
}
// Open 't' for reading as file descriptor 0
// (which environments use as standard input).
// We can't open a file onto a particular descriptor,
// so open the file as 'fd',
// then check whether 'fd' is 0.
// If not, dup 'fd' onto file descriptor 0,
// then close the original 'fd'.
// LAB 5: Your code here.
panic("< redirection not implemented");
break;
case '>': // Output redirection
// Grab the filename from the argument list
if (gettoken(0, &t) != 'w') {
cprintf("syntax error: > not followed by word\n");
exit();
}
if ((fd = open(t, O_WRONLY|O_CREAT|O_TRUNC)) < 0) {
cprintf("open %s for write: %e", t, fd);
exit();
}
if (fd != 1) {
dup(fd, 1);
close(fd);
}
break;
case '|': // Pipe
if ((r = pipe(p)) < 0) {
cprintf("pipe: %e", r);
exit();
}
if (debug)
cprintf("PIPE: %d %d\n", p[0], p[1]);
if ((r = fork()) < 0) {
cprintf("fork: %e", r);
exit();
}
if (r == 0) {
if (p[0] != 0) {
dup(p[0], 0);
close(p[0]);
}
close(p[1]);
goto again;
} else {
pipe_child = r;
if (p[1] != 1) {
dup(p[1], 1);
close(p[1]);
}
close(p[0]);
goto runit;
}
panic("| not implemented");
break;
case 0: // String is complete
// Run the current command!
goto runit;
default:
panic("bad return %d from gettoken", c);
break;
}
}
runit:
// Return immediately if command line was empty.
if(argc == 0) {
if (debug)
cprintf("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) {
cprintf("[%08x] SPAWN:", thisenv->env_id);
for (i = 0; argv[i]; i++)
cprintf(" %s", argv[i]);
cprintf("\n");
}
// Spawn the command!
if ((r = spawn(argv[0], (const char**) argv)) < 0)
cprintf("spawn %s: %e\n", argv[0], r);
// In the parent, close all file descriptors and wait for the
// spawned command to exit.
close_all();
if (r >= 0) {
if (debug)
cprintf("[%08x] WAIT %s %08x\n", thisenv->env_id, argv[0], r);
wait(r);
if (debug)
cprintf("[%08x] wait finished\n", thisenv->env_id);
}
// If we were the left-hand part of a pipe,
// wait for the right-hand part to finish.
if (pipe_child) {
if (debug)
cprintf("[%08x] WAIT pipe_child %08x\n", thisenv->env_id, pipe_child);
wait(pipe_child);
if (debug)
cprintf("[%08x] wait finished\n", thisenv->env_id);
}
// Done!
exit();
}
// 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)
cprintf("GETTOKEN NULL\n");
return 0;
}
if (debug > 1)
cprintf("GETTOKEN: %s\n", s);
*p1 = 0;
*p2 = 0;
while (strchr(WHITESPACE, *s))
*s++ = 0;
if (*s == 0) {
if (debug > 1)
cprintf("EOL\n");
return 0;
}
if (strchr(SYMBOLS, *s)) {
t = *s;
*p1 = s;
*s++ = 0;
*p2 = s;
if (debug > 1)
cprintf("TOK %c\n", t);
return t;
}
*p1 = s;
while (*s && !strchr(WHITESPACE SYMBOLS, *s))
s++;
*p2 = s;
if (debug > 1) {
t = **p2;
**p2 = 0;
cprintf("WORD: %s\n", *p1);
**p2 = t;
}
return 'w';
}
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;
}
void
usage(void)
{
cprintf("usage: sh [-dix] [command-file]\n");
exit();
}
void
umain(int argc, char **argv)
{
int r, interactive, echocmds;
struct Argstate args;
interactive = '?';
echocmds = 0;
argstart(&argc, argv, &args);
while ((r = argnext(&args)) >= 0)
switch (r) {
case 'd':
debug++;
break;
case 'i':
interactive = 1;
break;
case 'x':
echocmds = 1;
break;
default:
usage();
}
if (argc > 2)
usage();
if (argc == 2) {
close(0);
if ((r = open(argv[1], O_RDONLY)) < 0)
panic("open %s: %e", argv[1], r);
assert(r == 0);
}
if (interactive == '?')
interactive = iscons(0);
while (1) {
char *buf;
buf = readline(interactive ? "$ " : NULL);
if (buf == NULL) {
if (debug)
cprintf("EXITING\n");
exit(); // end of file
}
if (debug)
cprintf("LINE: %s\n", buf);
if (buf[0] == '#')
continue;
if (echocmds)
printf("# %s\n", buf);
if (debug)
cprintf("BEFORE FORK\n");
if ((r = fork()) < 0)
panic("fork: %e", r);
if (debug)
cprintf("FORK: %d\n", r);
if (r == 0) {
runcmd(buf);
exit();
} else
wait(r);
}
}

10
user/spawnfaultio.c Normal file
View File

@@ -0,0 +1,10 @@
#include <inc/lib.h>
void
umain(int argc, char **argv)
{
int r;
cprintf("i am parent environment %08x\n", thisenv->env_id);
if ((r = spawnl("faultio", "faultio", 0)) < 0)
panic("spawn(faultio) failed: %e", r);
}

10
user/spawnhello.c Normal file
View File

@@ -0,0 +1,10 @@
#include <inc/lib.h>
void
umain(int argc, char **argv)
{
int r;
cprintf("i am parent environment %08x\n", thisenv->env_id);
if ((r = spawnl("hello", "hello", 0)) < 0)
panic("spawn(hello) failed: %e", r);
}

10
user/spawninit.c Normal file
View File

@@ -0,0 +1,10 @@
#include <inc/lib.h>
void
umain(int argc, char **argv)
{
int r;
cprintf("i am parent environment %08x\n", thisenv->env_id);
if ((r = spawnl("init", "init", "one", "two", 0)) < 0)
panic("spawnl(init) failed: %e", r);
}

38
user/testfdsharing.c Normal file
View File

@@ -0,0 +1,38 @@
#include <inc/x86.h>
#include <inc/lib.h>
char buf[512], buf2[512];
void
umain(int argc, char **argv)
{
int fd, r, n, n2;
if ((fd = open("motd", O_RDONLY)) < 0)
panic("open motd: %e", fd);
seek(fd, 0);
if ((n = readn(fd, buf, sizeof buf)) <= 0)
panic("readn: %e", n);
if ((r = fork()) < 0)
panic("fork: %e", r);
if (r == 0) {
seek(fd, 0);
cprintf("going to read in child (might page fault if your sharing is buggy)\n");
if ((n2 = readn(fd, buf2, sizeof buf2)) != n)
panic("read in parent got %d, read in child got %d", n, n2);
if (memcmp(buf, buf2, n) != 0)
panic("read in parent got different bytes from read in child");
cprintf("read in child succeeded\n");
seek(fd, 0);
close(fd);
exit();
}
wait(r);
if ((n2 = readn(fd, buf2, sizeof buf2)) != n)
panic("read in parent got %d, then got %d", n, n2);
cprintf("read in parent succeeded\n");
close(fd);
breakpoint();
}

128
user/testfile.c Normal file
View File

@@ -0,0 +1,128 @@
#include <inc/lib.h>
const char *msg = "This is the NEW message of the day!\n\n";
#define FVA ((struct Fd*)0xCCCCC000)
static int
xopen(const char *path, int mode)
{
extern union Fsipc fsipcbuf;
envid_t fsenv;
strcpy(fsipcbuf.open.req_path, path);
fsipcbuf.open.req_omode = mode;
fsenv = ipc_find_env(ENV_TYPE_FS);
ipc_send(fsenv, FSREQ_OPEN, &fsipcbuf, PTE_P | PTE_W | PTE_U);
return ipc_recv(NULL, FVA, NULL);
}
void
umain(int argc, char **argv)
{
int r, f, i;
struct Fd *fd;
struct Fd fdcopy;
struct Stat st;
char buf[512];
// We open files manually first, to avoid the FD layer
if ((r = xopen("/not-found", O_RDONLY)) < 0 && r != -E_NOT_FOUND)
panic("serve_open /not-found: %e", r);
else if (r >= 0)
panic("serve_open /not-found succeeded!");
if ((r = xopen("/newmotd", O_RDONLY)) < 0)
panic("serve_open /newmotd: %e", r);
if (FVA->fd_dev_id != 'f' || FVA->fd_offset != 0 || FVA->fd_omode != O_RDONLY)
panic("serve_open did not fill struct Fd correctly\n");
cprintf("serve_open is good\n");
if ((r = devfile.dev_stat(FVA, &st)) < 0)
panic("file_stat: %e", r);
if (strlen(msg) != st.st_size)
panic("file_stat returned size %d wanted %d\n", st.st_size, strlen(msg));
cprintf("file_stat is good\n");
memset(buf, 0, sizeof buf);
if ((r = devfile.dev_read(FVA, buf, sizeof buf)) < 0)
panic("file_read: %e", r);
if (strcmp(buf, msg) != 0)
panic("file_read returned wrong data");
cprintf("file_read is good\n");
if ((r = devfile.dev_close(FVA)) < 0)
panic("file_close: %e", r);
cprintf("file_close is good\n");
// We're about to unmap the FD, but still need a way to get
// the stale filenum to serve_read, so we make a local copy.
// The file server won't think it's stale until we unmap the
// FD page.
fdcopy = *FVA;
sys_page_unmap(0, FVA);
if ((r = devfile.dev_read(&fdcopy, buf, sizeof buf)) != -E_INVAL)
panic("serve_read does not handle stale fileids correctly: %e", r);
cprintf("stale fileid is good\n");
// Try writing
if ((r = xopen("/new-file", O_RDWR|O_CREAT)) < 0)
panic("serve_open /new-file: %e", r);
if ((r = devfile.dev_write(FVA, msg, strlen(msg))) != strlen(msg))
panic("file_write: %e", r);
cprintf("file_write is good\n");
FVA->fd_offset = 0;
memset(buf, 0, sizeof buf);
if ((r = devfile.dev_read(FVA, buf, sizeof buf)) < 0)
panic("file_read after file_write: %e", r);
if (r != strlen(msg))
panic("file_read after file_write returned wrong length: %d", r);
if (strcmp(buf, msg) != 0)
panic("file_read after file_write returned wrong data");
cprintf("file_read after file_write is good\n");
// Now we'll try out open
if ((r = open("/not-found", O_RDONLY)) < 0 && r != -E_NOT_FOUND)
panic("open /not-found: %e", r);
else if (r >= 0)
panic("open /not-found succeeded!");
if ((r = open("/newmotd", O_RDONLY)) < 0)
panic("open /newmotd: %e", r);
fd = (struct Fd*) (0xD0000000 + r*PGSIZE);
if (fd->fd_dev_id != 'f' || fd->fd_offset != 0 || fd->fd_omode != O_RDONLY)
panic("open did not fill struct Fd correctly\n");
cprintf("open is good\n");
// Try files with indirect blocks
if ((f = open("/big", O_WRONLY|O_CREAT)) < 0)
panic("creat /big: %e", f);
memset(buf, 0, sizeof(buf));
for (i = 0; i < (NDIRECT*3)*BLKSIZE; i += sizeof(buf)) {
*(int*)buf = i;
if ((r = write(f, buf, sizeof(buf))) < 0)
panic("write /big@%d: %e", i, r);
}
close(f);
if ((f = open("/big", O_RDONLY)) < 0)
panic("open /big: %e", f);
for (i = 0; i < (NDIRECT*3)*BLKSIZE; i += sizeof(buf)) {
*(int*)buf = i;
if ((r = readn(f, buf, sizeof(buf))) < 0)
panic("read /big@%d: %e", i, r);
if (r != sizeof(buf))
panic("read /big from %d returned %d < %d bytes",
i, r, sizeof(buf));
if (*(int*)buf != i)
panic("read /big from %d returned bad data %d",
i, *(int*)buf);
}
close(f);
cprintf("large file is good\n");
}

30
user/testkbd.c Normal file
View File

@@ -0,0 +1,30 @@
#include <inc/lib.h>
void
umain(int argc, char **argv)
{
int i, r;
// Spin for a bit to let the console quiet
for (i = 0; i < 10; ++i)
sys_yield();
close(0);
if ((r = opencons()) < 0)
panic("opencons: %e", r);
if (r != 0)
panic("first opencons used fd %d", r);
if ((r = dup(0, 1)) < 0)
panic("dup: %e", r);
for(;;){
char *buf;
buf = readline("Type a line: ");
if (buf != NULL)
fprintf(1, "%s\n", buf);
else
fprintf(1, "(end of file received)\n");
}
}

24
user/testmalloc.c Normal file
View File

@@ -0,0 +1,24 @@
#include <inc/lib.h>
void
umain(int argc, char **argv)
{
char *buf;
int n;
void *v;
while (1) {
buf = readline("> ");
if (buf == 0)
exit();
if (memcmp(buf, "free ", 5) == 0) {
v = (void*) strtol(buf + 5, 0, 0);
free(v);
} else if (memcmp(buf, "malloc ", 7) == 0) {
n = strtol(buf + 7, 0, 0);
v = malloc(n);
printf("\t0x%x\n", (uintptr_t) v);
} else
printf("?unknown command\n");
}
}

64
user/testpipe.c Normal file
View File

@@ -0,0 +1,64 @@
#include <inc/lib.h>
char *msg = "Now is the time for all good men to come to the aid of their party.";
void
umain(int argc, char **argv)
{
char buf[100];
int i, pid, p[2];
binaryname = "pipereadeof";
if ((i = pipe(p)) < 0)
panic("pipe: %e", i);
if ((pid = fork()) < 0)
panic("fork: %e", i);
if (pid == 0) {
cprintf("[%08x] pipereadeof close %d\n", thisenv->env_id, p[1]);
close(p[1]);
cprintf("[%08x] pipereadeof readn %d\n", thisenv->env_id, p[0]);
i = readn(p[0], buf, sizeof buf-1);
if (i < 0)
panic("read: %e", i);
buf[i] = 0;
if (strcmp(buf, msg) == 0)
cprintf("\npipe read closed properly\n");
else
cprintf("\ngot %d bytes: %s\n", i, buf);
exit();
} else {
cprintf("[%08x] pipereadeof close %d\n", thisenv->env_id, p[0]);
close(p[0]);
cprintf("[%08x] pipereadeof write %d\n", thisenv->env_id, p[1]);
if ((i = write(p[1], msg, strlen(msg))) != strlen(msg))
panic("write: %e", i);
close(p[1]);
}
wait(pid);
binaryname = "pipewriteeof";
if ((i = pipe(p)) < 0)
panic("pipe: %e", i);
if ((pid = fork()) < 0)
panic("fork: %e", i);
if (pid == 0) {
close(p[0]);
while (1) {
cprintf(".");
if (write(p[1], "x", 1) != 1)
break;
}
cprintf("\npipe write closed properly\n");
exit();
}
close(p[0]);
close(p[1]);
wait(pid);
cprintf("pipe tests passed\n");
}

66
user/testpiperace.c Normal file
View File

@@ -0,0 +1,66 @@
#include <inc/lib.h>
void
umain(int argc, char **argv)
{
int p[2], r, pid, i, max;
void *va;
struct Fd *fd;
const volatile struct Env *kid;
cprintf("testing for dup race...\n");
if ((r = pipe(p)) < 0)
panic("pipe: %e", r);
max = 200;
if ((r = fork()) < 0)
panic("fork: %e", r);
if (r == 0) {
close(p[1]);
//
// Now the ref count for p[0] will toggle between 2 and 3
// as the parent dups and closes it (there's a close implicit in dup).
//
// The ref count for p[1] is 1.
// Thus the ref count for the underlying pipe structure
// will toggle between 3 and 4.
//
// If a clock interrupt catches close between unmapping
// the pipe structure and unmapping the fd, we'll have
// a ref count for p[0] of 3, a ref count for p[1] of 1,
// and a ref count for the pipe structure of 3, which is
// a no-no.
//
// If a clock interrupt catches dup between mapping the
// fd and mapping the pipe structure, we'll have the same
// ref counts, still a no-no.
//
for (i=0; i<max; i++) {
if(pipeisclosed(p[0])){
cprintf("RACE: pipe appears closed\n");
exit();
}
sys_yield();
}
// do something to be not runnable besides exiting
ipc_recv(0,0,0);
}
pid = r;
cprintf("pid is %d\n", pid);
va = 0;
kid = &envs[ENVX(pid)];
cprintf("kid is %d\n", kid-envs);
dup(p[0], 10);
while (kid->env_status == ENV_RUNNABLE)
dup(p[0], 10);
cprintf("child done with loop\n");
if (pipeisclosed(p[0]))
panic("somehow the other end of p[0] got closed!");
if ((r = fd_lookup(p[0], &fd)) < 0)
panic("cannot look up p[0]: %e", r);
va = fd2data(fd);
if (pageref(va) != 3+1)
cprintf("\nchild detected race\n");
else
cprintf("\nrace didn't happen\n", max);
}

69
user/testpiperace2.c Normal file
View File

@@ -0,0 +1,69 @@
#include <inc/lib.h>
void
umain(int argc, char **argv)
{
int p[2], r, i;
struct Fd *fd;
const volatile struct Env *kid;
cprintf("testing for pipeisclosed race...\n");
if ((r = pipe(p)) < 0)
panic("pipe: %e", r);
if ((r = fork()) < 0)
panic("fork: %e", r);
if (r == 0) {
// child just dups and closes repeatedly,
// yielding so the parent can see
// the fd state between the two.
close(p[1]);
for (i = 0; i < 200; i++) {
if (i % 10 == 0)
cprintf("%d.", i);
// dup, then close. yield so that other guy will
// see us while we're between them.
dup(p[0], 10);
sys_yield();
close(10);
sys_yield();
}
exit();
}
// We hold both p[0] and p[1] open, so pipeisclosed should
// never return false.
//
// Now the ref count for p[0] will toggle between 2 and 3
// as the child dups and closes it.
// The ref count for p[1] is 1.
// Thus the ref count for the underlying pipe structure
// will toggle between 3 and 4.
//
// If pipeisclosed checks pageref(p[0]) and gets 3, and
// then the child closes, and then pipeisclosed checks
// pageref(pipe structure) and gets 3, then it will return true
// when it shouldn't.
//
// If pipeisclosed checks pageref(pipe structure) and gets 3,
// and then the child dups, and then pipeisclosed checks
// pageref(p[0]) and gets 3, then it will return true when
// it shouldn't.
//
// So either way, pipeisclosed is going give a wrong answer.
//
kid = &envs[ENVX(r)];
while (kid->env_status == ENV_RUNNABLE)
if (pipeisclosed(p[0]) != 0) {
cprintf("\nRACE: pipe appears closed\n");
sys_env_destroy(r);
exit();
}
cprintf("child done with loop\n");
if (pipeisclosed(p[0]))
panic("somehow the other end of p[0] got closed!");
if ((r = fd_lookup(p[0], &fd)) < 0)
panic("cannot look up p[0]: %e", r);
(void) fd2data(fd);
cprintf("race didn't happen\n");
}

42
user/testptelibrary.c Normal file
View File

@@ -0,0 +1,42 @@
#include <inc/lib.h>
#define VA ((char *) 0xA0000000)
const char *msg = "hello, world\n";
const char *msg2 = "goodbye, world\n";
void childofspawn(void);
void
umain(int argc, char **argv)
{
int r;
if (argc != 0)
childofspawn();
if ((r = sys_page_alloc(0, VA, PTE_P|PTE_W|PTE_U|PTE_SHARE)) < 0)
panic("sys_page_alloc: %e", r);
// check fork
if ((r = fork()) < 0)
panic("fork: %e", r);
if (r == 0) {
strcpy(VA, msg);
exit();
}
wait(r);
cprintf("fork handles PTE_SHARE %s\n", strcmp(VA, msg) == 0 ? "right" : "wrong");
// check spawn
if ((r = spawnl("/testptelibrary", "testptelibrary", "arg", 0)) < 0)
panic("spawn: %e", r);
wait(r);
cprintf("spawn handles PTE_SHARE %s\n", strcmp(VA, msg2) == 0 ? "right" : "wrong");
}
void
childofspawn(void)
{
strcpy(VA, msg2);
exit();
}

45
user/testpteshare.c Normal file
View File

@@ -0,0 +1,45 @@
#include <inc/x86.h>
#include <inc/lib.h>
#define VA ((char *) 0xA0000000)
const char *msg = "hello, world\n";
const char *msg2 = "goodbye, world\n";
void childofspawn(void);
void
umain(int argc, char **argv)
{
int r;
if (argc != 0)
childofspawn();
if ((r = sys_page_alloc(0, VA, PTE_P|PTE_W|PTE_U|PTE_SHARE)) < 0)
panic("sys_page_alloc: %e", r);
// check fork
if ((r = fork()) < 0)
panic("fork: %e", r);
if (r == 0) {
strcpy(VA, msg);
exit();
}
wait(r);
cprintf("fork handles PTE_SHARE %s\n", strcmp(VA, msg) == 0 ? "right" : "wrong");
// check spawn
if ((r = spawnl("/testpteshare", "testpteshare", "arg", 0)) < 0)
panic("spawn: %e", r);
wait(r);
cprintf("spawn handles PTE_SHARE %s\n", strcmp(VA, msg2) == 0 ? "right" : "wrong");
breakpoint();
}
void
childofspawn(void)
{
strcpy(VA, msg2);
exit();
}

85
user/testshell.c Normal file
View File

@@ -0,0 +1,85 @@
#include <inc/x86.h>
#include <inc/lib.h>
void wrong(int, int, int);
void
umain(int argc, char **argv)
{
char c1, c2;
int r, rfd, wfd, kfd, n1, n2, off, nloff;
int pfds[2];
close(0);
close(1);
opencons();
opencons();
if ((rfd = open("testshell.sh", O_RDONLY)) < 0)
panic("open testshell.sh: %e", rfd);
if ((wfd = pipe(pfds)) < 0)
panic("pipe: %e", wfd);
wfd = pfds[1];
cprintf("running sh -x < testshell.sh | cat\n");
if ((r = fork()) < 0)
panic("fork: %e", r);
if (r == 0) {
dup(rfd, 0);
dup(wfd, 1);
close(rfd);
close(wfd);
if ((r = spawnl("/sh", "sh", "-x", 0)) < 0)
panic("spawn: %e", r);
close(0);
close(1);
wait(r);
exit();
}
close(rfd);
close(wfd);
rfd = pfds[0];
if ((kfd = open("testshell.key", O_RDONLY)) < 0)
panic("open testshell.key for reading: %e", kfd);
nloff = 0;
for (off=0;; off++) {
n1 = read(rfd, &c1, 1);
n2 = read(kfd, &c2, 1);
if (n1 < 0)
panic("reading testshell.out: %e", n1);
if (n2 < 0)
panic("reading testshell.key: %e", n2);
if (n1 == 0 && n2 == 0)
break;
if (n1 != 1 || n2 != 1 || c1 != c2)
wrong(rfd, kfd, nloff);
if (c1 == '\n')
nloff = off+1;
}
cprintf("shell ran correctly\n");
breakpoint();
}
void
wrong(int rfd, int kfd, int off)
{
char buf[100];
int n;
seek(rfd, off);
seek(kfd, off);
cprintf("shell produced incorrect output.\n");
cprintf("expected:\n===\n");
while ((n = read(kfd, buf, sizeof buf-1)) > 0)
sys_cputs(buf, n);
cprintf("===\ngot:\n===\n");
while ((n = read(rfd, buf, sizeof buf-1)) > 0)
sys_cputs(buf, n);
cprintf("===\n");
exit();
}

40
user/writemotd.c Normal file
View File

@@ -0,0 +1,40 @@
#include <inc/lib.h>
void
umain(int argc, char **argv)
{
int rfd, wfd;
char buf[512];
int n, r;
if ((rfd = open("/newmotd", O_RDONLY)) < 0)
panic("open /newmotd: %e", rfd);
if ((wfd = open("/motd", O_RDWR)) < 0)
panic("open /motd: %e", wfd);
cprintf("file descriptors %d %d\n", rfd, wfd);
if (rfd == wfd)
panic("open /newmotd and /motd give same file descriptor");
cprintf("OLD MOTD\n===\n");
while ((n = read(wfd, buf, sizeof buf-1)) > 0)
sys_cputs(buf, n);
cprintf("===\n");
seek(wfd, 0);
if ((r = ftruncate(wfd, 0)) < 0)
panic("truncate /motd: %e", r);
cprintf("NEW MOTD\n===\n");
while ((n = read(rfd, buf, sizeof buf-1)) > 0) {
sys_cputs(buf, n);
if ((r = write(wfd, buf, n)) != n)
panic("write /motd: %e", r);
}
cprintf("===\n");
if (n < 0)
panic("read /newmotd: %e", n);
close(rfd);
close(wfd);
}