Lab 5
This commit is contained in:
@@ -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
36
user/cat.c
Normal 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
21
user/echo.c
Normal 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
22
user/faultio.c
Normal 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
29
user/icode.c
Normal 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
69
user/init.c
Normal 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
27
user/initsh.c
Normal 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
91
user/ls.c
Normal 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
35
user/lsfd.c
Normal 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
47
user/num.c
Normal 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
76
user/primespipe.c
Normal 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
322
user/sh.c
Normal 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
10
user/spawnfaultio.c
Normal 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
10
user/spawnhello.c
Normal 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
10
user/spawninit.c
Normal 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
38
user/testfdsharing.c
Normal 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
128
user/testfile.c
Normal 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
30
user/testkbd.c
Normal 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
24
user/testmalloc.c
Normal 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
64
user/testpipe.c
Normal 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
66
user/testpiperace.c
Normal 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
69
user/testpiperace2.c
Normal 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
42
user/testptelibrary.c
Normal 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
45
user/testpteshare.c
Normal 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
85
user/testshell.c
Normal 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
40
user/writemotd.c
Normal 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);
|
||||
}
|
||||
Reference in New Issue
Block a user