aboutsummaryrefslogtreecommitdiff
path: root/user
diff options
context:
space:
mode:
authornthnluu <nate1299@me.com>2024-01-28 21:20:27 -0500
committernthnluu <nate1299@me.com>2024-01-28 21:20:27 -0500
commitc63f340d90800895f007de64b7d2d14624263331 (patch)
tree2c0849fa597dd6da831c8707b6f2603403778d7b /user
Created student weenix repository
Diffstat (limited to 'user')
-rw-r--r--user/.gitignore8
-rw-r--r--user/Makefile210
-rw-r--r--user/README3
-rw-r--r--user/bin/.gitignore4
-rw-r--r--user/bin/ed.c1757
-rw-r--r--user/bin/hd.c90
-rw-r--r--user/bin/ls.c108
-rw-r--r--user/bin/sh.c1910
-rw-r--r--user/bin/sl.c502
-rw-r--r--user/bin/sleep.c44
-rw-r--r--user/bin/stat.c49
-rw-r--r--user/bin/uname.c93
-rw-r--r--user/hamlet7882
l---------user/include/ctype.h1
l---------user/include/dirent.h1
l---------user/include/errno.h1
l---------user/include/fcntl.h1
l---------user/include/limits.h1
l---------user/include/lseek.h1
-rw-r--r--user/include/pthread/pthread.h137
l---------user/include/stdarg.h1
-rw-r--r--user/include/stddef.h28
-rw-r--r--user/include/stdio.h63
-rw-r--r--user/include/stdlib.h60
-rw-r--r--user/include/string.h47
l---------user/include/sys/mman.h1
l---------user/include/sys/stat.h1
l---------user/include/sys/types.h1
l---------user/include/sys/utsname.h1
-rw-r--r--user/include/test/test.h51
-rw-r--r--user/include/unistd.h101
l---------user/include/weenix/config.h1
-rw-r--r--user/include/weenix/debug.h12
l---------user/include/weenix/syscall.h1
-rw-r--r--user/include/weenix/trap.h26
-rw-r--r--user/lib/ld-weenix/asm.h37
-rw-r--r--user/lib/ld-weenix/bs_x86_64.S58
-rw-r--r--user/lib/ld-weenix/elf.h2597
-rw-r--r--user/lib/ld-weenix/ldalloc.c66
-rw-r--r--user/lib/ld-weenix/ldalloc.h4
-rw-r--r--user/lib/ld-weenix/ldnames.c63
-rw-r--r--user/lib/ld-weenix/ldnames.h23
-rw-r--r--user/lib/ld-weenix/ldreloc_x86_64.c184
-rw-r--r--user/lib/ld-weenix/ldresolve.c119
-rw-r--r--user/lib/ld-weenix/ldresolve.h35
-rw-r--r--user/lib/ld-weenix/ldstart.c573
-rw-r--r--user/lib/ld-weenix/ldtypes.h60
-rw-r--r--user/lib/ld-weenix/ldutil.c72
-rw-r--r--user/lib/ld-weenix/ldutil.h39
-rw-r--r--user/lib/ld-weenix/smacros.h40
-rw-r--r--user/lib/libc/entry.S17
-rw-r--r--user/lib/libc/errno.c3
-rw-r--r--user/lib/libc/malloc.c1326
-rw-r--r--user/lib/libc/printf.c169
-rw-r--r--user/lib/libc/quad.c414
-rw-r--r--user/lib/libc/rand.c22
-rw-r--r--user/lib/libc/scanf.c73
-rw-r--r--user/lib/libc/stream.c11
-rw-r--r--user/lib/libc/string.c509
-rw-r--r--user/lib/libc/strtol.c162
-rw-r--r--user/lib/libc/syscall.c391
-rw-r--r--user/lib/libc/vsnprintf.c566
-rw-r--r--user/lib/libc/vsscanf.c447
-rw-r--r--user/lib/libtest/test.c202
-rw-r--r--user/sbin/.gitignore2
-rw-r--r--user/sbin/halt.c7
-rw-r--r--user/sbin/init.c115
-rw-r--r--user/test/stuff3
-rw-r--r--user/usr/bin/args.c36
-rw-r--r--user/usr/bin/hello.c17
-rw-r--r--user/usr/bin/kshell.c8
-rw-r--r--user/usr/bin/segfault.S12
-rw-r--r--user/usr/bin/spin.c10
-rw-r--r--user/usr/bin/tests/eatinodes.c90
-rw-r--r--user/usr/bin/tests/eatmem.c190
-rw-r--r--user/usr/bin/tests/elf_test-64.c38
-rw-r--r--user/usr/bin/tests/forkbomb.c84
-rw-r--r--user/usr/bin/tests/forktest.c19
-rw-r--r--user/usr/bin/tests/linkermagic.h232
-rw-r--r--user/usr/bin/tests/memtest.c816
l---------user/usr/bin/tests/mm.h1
l---------user/usr/bin/tests/page.h1
-rw-r--r--user/usr/bin/tests/pipetest.c191
-rw-r--r--user/usr/bin/tests/prime.c107
-rw-r--r--user/usr/bin/tests/s5fstest.c332
-rw-r--r--user/usr/bin/tests/stress.c476
-rw-r--r--user/usr/bin/tests/vfstest.c1172
-rw-r--r--user/usr/bin/wc.c114
88 files changed, 25553 insertions, 0 deletions
diff --git a/user/.gitignore b/user/.gitignore
new file mode 100644
index 0000000..e19f6c3
--- /dev/null
+++ b/user/.gitignore
@@ -0,0 +1,8 @@
+# cscope
+cscope.files
+cscope.in.out
+cscope.out
+cscope.po.out
+
+disk*.img
+*.exec
diff --git a/user/Makefile b/user/Makefile
new file mode 100644
index 0000000..e2f0418
--- /dev/null
+++ b/user/Makefile
@@ -0,0 +1,210 @@
+SHELL := /bin/sh
+
+# XXX why is this here?
+CFLAGS :=
+
+include ../Global.mk
+
+DISK_IMAGE := disk0.img
+STAGING_DIR := .staging
+
+.PHONY: all clean
+
+all: $(DISK_IMAGE)
+
+########
+# compile step
+########
+
+# CFLAGS_LIB: separate set of CFLAGS used for shared libraries (which, for
+# example, need -fpic to build, but other executables can't be built with
+# -fpic)
+CFLAGS_LIB := $(CFLAGS) -fpic
+
+# XXX is this being defined multiple times?
+ASFLAGS := -D__ASSEMBLY__
+ASFLAGS := $(ASFLAGS) -D__x86_64__
+
+
+# - all source files are compiled to an object file of the same name
+# (no .c file and .S file shares the same prefix, so we have no conflicts)
+# - for each .o, make picks the appropriate rule to generate it (only one of
+# the two rules has dependencies that exist)
+# - pass -fpic only to shared libraries
+
+lib/%.o: lib/%.c
+ @ echo " Compiling \"user/$<\"..."
+ @ $(CC) -c $< -o $@ $(CFLAGS_LIB)
+
+%.o: %.c
+ @ echo " Compiling \"user/$<\"..."
+ @ $(CC) -c $< -o $@ $(CFLAGS)
+
+lib/%.o: lib/%.S
+ @ echo " Compiling \"user/$<\"..."
+ @ $(CC) -c $< -o $@ $(ASFLAGS) $(CFLAGS_LIB)
+
+%.o: %.S
+ @ echo " Compiling \"user/$<\"..."
+ @ $(CC) -c $< -o $@ $(ASFLAGS) $(CFLAGS)
+
+########
+# link step for static libraries and shared libraries
+########
+LDFLAGS := -m elf_x86_64 -z nodefaultlib -Llib
+
+# - there are 3 libraries: libc, ld-weenix, libtest
+# - each library is built from the set of object files contained in its
+# directory; this set is generated from the list of sources by replacing
+# the .c suffix (or .S suffix) with a .o suffix
+# - shared libraries are built with ld -shared, static libraries are built
+# with ar
+
+# 1. libc
+
+LIBC_SOURCES := $(wildcard lib/libc/*.[cS])
+LIBC_OBJECTS := $(addsuffix .o,$(basename $(LIBC_SOURCES)))
+
+lib/libc.so: $(LIBC_OBJECTS)
+ @ echo " Linking for \"user/$@\"..."
+ @ $(LD) -o $@ $^ $(LDFLAGS) -shared -soname=/lib/libc.so \
+--dynamic-linker /lib/ld-weenix.so
+
+lib/libc.a: $(LIBC_OBJECTS)
+ @ echo " Creating \"user/$@\"..."
+ @ $(AR) crs $@ $^
+
+# 2. libtest
+
+LIBTEST_SOURCES := $(wildcard lib/libtest/*.[cS])
+LIBTEST_OBJECTS := $(addsuffix .o,$(basename $(LIBTEST_SOURCES)))
+
+lib/libtest.so: $(LIBTEST_OBJECTS) lib/libc.so
+ @ echo " Linking for \"user/$@\"..."
+ @ $(LD) -o $@ $^ $(LDFLAGS) -shared -soname=/lib/libtest.so -lc
+
+lib/libtest.a: $(LIBTEST_OBJECTS)
+ @ echo " Creating \"user/$@\"..."
+ @ $(AR) crs $@ $^
+
+# 3. ld-weenix
+
+LDWEENIX_SOURCES := $(wildcard lib/ld-weenix/*.[cS])
+LDWEENIX_OBJECTS := $(addsuffix .o,$(basename $(LDWEENIX_SOURCES)))
+
+lib/ld-weenix.so: $(LDWEENIX_OBJECTS) lib/libc.a
+ @ echo " Linking for \"user/$@\"..."
+ @ $(LD) -o $@ $(LDWEENIX_OBJECTS) $(LDFLAGS) -shared \
+-soname=/lib/ld-weenix.so -Bsymbolic -e _bootstrap -static -lc
+
+########
+# link step for executables
+########
+
+# - all executables are generated from a single .o file
+# - executables are either statically or dynamically linked, and get built
+# with a ".exec" suffix (the suffix makes the rule definition easier, and
+# gets removed in the staging step)
+# - all executables build with libc
+# - statically-linked executables build with entry.o
+
+# 1. executables that require libtest:
+
+ifeq ($(DYNAMIC),0)
+usr/bin/%.exec: usr/bin/tests/%.o lib/libc.a lib/libc/entry.o lib/libtest.a
+ @ echo " Linking for \"user/$@\" (static)..."
+ @ $(LD) -o $@ $< lib/libc/entry.o $(LDFLAGS) -static \
+-e __libc_static_entry -lc -ltest
+else
+usr/bin/%.exec: usr/bin/tests/%.o lib/libc.so lib/libtest.so
+ @ echo " Linking for \"user/$@\" (dynamic)..."
+ @ $(LD) -o $@ $< $(LDFLAGS) -e main --dynamic-linker /lib/ld-weenix.so \
+-lc -ltest
+endif
+
+# 2. all other executables
+
+ifeq ($(DYNAMIC),0)
+%.exec: %.o lib/libc.a lib/libc/entry.o
+ @ echo " Linking for \"user/$@\" (static)..."
+ @ $(LD) -o $@ $< lib/libc/entry.o $(LDFLAGS) -static \
+-e __libc_static_entry -lc
+else
+%.exec: %.o lib/libc.so
+ @ echo " Linking for \"user/$@\" (dynamic)..."
+ @ $(LD) -o $@ $< $(LDFLAGS) -e main --dynamic-linker /lib/ld-weenix.so \
+-lc
+endif
+
+########
+# generate the disk image layout
+########
+
+# - below is an explicit list of files that will reside on the disk image
+# - all of these files get staged in the staging directory
+# - executables get their ".exec" suffix stripped off in this step
+
+# TODO also create make /tmp directory (some userspace test expects it)
+BASE_TARGETS := README hamlet test/stuff
+ifeq ($(DYNAMIC),0)
+LIB_TARGETS := lib/libc.a lib/libtest.a
+else
+LIB_TARGETS := lib/ld-weenix.so lib/libc.a lib/libc.so lib/libtest.a \
+lib/libtest.so
+endif
+
+EXEC_TARGETS := bin/ed bin/ls bin/sl bin/sleep bin/sh bin/uname bin/hd bin/stat \
+sbin/halt sbin/init \
+usr/bin/args usr/bin/hello usr/bin/kshell usr/bin/segfault usr/bin/spin \
+usr/bin/eatmem usr/bin/forkbomb usr/bin/memtest usr/bin/stress usr/bin/vfstest \
+usr/bin/wc usr/bin/forktest usr/bin/eatinodes usr/bin/pipetest usr/bin/s5fstest \
+usr/bin/elf_test-64 usr/bin/prime
+DIR_TARGETS := tmp
+
+EXEC_SUFFIX := .exec
+EXEC_TARGETS_WITH_SUFFIX := $(addsuffix $(EXEC_SUFFIX),$(EXEC_TARGETS))
+
+# don't include any executables in the disk until VM
+ifeq ($(VM),1)
+TARGETS := $(BASE_TARGETS) $(LIB_TARGETS) $(EXEC_TARGETS_WITH_SUFFIX) $(DIR_TARGETS)
+else
+TARGETS := $(BASE_TARGETS)
+endif
+
+# TODO get rid of "mkdir -p", "cp --parents" (they are not portable)
+$(STAGING_DIR): $(TARGETS)
+ @ echo " Staging initial disk contents..."
+ @ mkdir -p $(STAGING_DIR)
+ @ touch $(STAGING_DIR)
+ @ cp --parents --recursive -- $? $(STAGING_DIR)
+# below: strip .exec suffix from binaries
+# (portable implementation of "rename 's/\.exec//' $?")
+ @ cd $(STAGING_DIR) \
+&& for i in `ls $? | grep "\.exec"`; do \
+mv $$i `echo $$i | cut -f1 -d.`; \
+done
+
+$(DIR_TARGETS) :
+ @ echo " Creating directory \"$@\"..."
+ @ mkdir -p $@
+
+########
+# build the disk image
+########
+
+$(DISK_IMAGE): $(STAGING_DIR)
+ @ echo " Running fsmaker to create \"user/$@\"..."
+ @ echo " Disk Blocks: $(DISK_BLOCKS)"
+ @ echo " Disk Inodes: $(DISK_INODES)"
+ @ $(PYTHON) ../tools/fsmaker/sh.py $@ -e "format -b $(DISK_BLOCKS) -i $(DISK_INODES) -d $<"
+ @ rm "../$(DISK_IMAGE)" 2>/dev/null && echo " Removing obsolete $(DISK_IMAGE)" || true
+
+########
+# clean
+########
+
+clean:
+ find . -name "*.o" -type f -delete
+ rm -f $(DISK_IMAGE) $(LIB_TARGETS) $(EXEC_TARGETS_WITH_SUFFIX)
+ rmdir $(DIR_TARGETS) || true
+ rm -rf $(STAGING_DIR)
diff --git a/user/README b/user/README
new file mode 100644
index 0000000..d7f3b01
--- /dev/null
+++ b/user/README
@@ -0,0 +1,3 @@
+Congratulations! If you're reading this using your own
+file system, you've made it pretty far. Keep on truckin'.
+ --Your staff
diff --git a/user/bin/.gitignore b/user/bin/.gitignore
new file mode 100644
index 0000000..19a3fd8
--- /dev/null
+++ b/user/bin/.gitignore
@@ -0,0 +1,4 @@
+sh
+ls
+ed
+uname
diff --git a/user/bin/ed.c b/user/bin/ed.c
new file mode 100644
index 0000000..5510876
--- /dev/null
+++ b/user/bin/ed.c
@@ -0,0 +1,1757 @@
+/*
+ * ed is the standard text editor.
+ *
+ * I think that Keith was the one who ported ed to weenix. Thanks Keith.
+ * Note: dap also helped in 2007, but it still doesn't work.
+ * Working version added in 2010.
+ */
+
+/* Just for fun:
+ * From: patl@athena.mit.edu (Patrick J. LoPresti)
+ * Subject: The True Path (long)
+ * Date: 11 Jul 91 03:17:31 GMT
+ * Newsgroups: alt.religion.emacs,alt.slack
+ *
+ * When I log into my Xenix system with my 110 baud teletype, both vi
+ * *and* Emacs are just too damn slow. They print useless messages like,
+ * 'C-h for help' and '"foo" File is read only'. So I use the editor
+ * that doesn't waste my VALUABLE time.
+ *
+ * Ed, man! !man ed
+ *
+ * ED(1) UNIX Programmer's Manual ED(1)
+ *
+ * NAME
+ * ed - text editor
+ *
+ * SYNOPSIS
+ * ed [ - ] [ -x ] [ name ]
+ * DESCRIPTION
+ * Ed is the standard text editor.
+ * ---
+ *
+ * Computer Scientists love ed, not just because it comes first
+ * alphabetically, but because it's the standard. Everyone else loves ed
+ * because it's ED!
+ *
+ * "Ed is the standard text editor."
+ *
+ * And ed doesn't waste space on my Timex Sinclair. Just look:
+ *
+ * -rwxr-xr-x 1 root 24 Oct 29 1929 /bin/ed
+ * -rwxr-xr-t 4 root 1310720 Jan 1 1970 /usr/ucb/vi
+ * -rwxr-xr-x 1 root 5.89824e37 Oct 22 1990 /usr/bin/emacs
+ *
+ * Of course, on the system *I* administrate, vi is symlinked to ed.
+ * Emacs has been replaced by a shell script which 1) Generates a syslog
+ * message at level LOG_EMERG; 2) reduces the user's disk quota by 100K;
+ * and 3) RUNS ED!!!!!!
+ *
+ * "Ed is the standard text editor."
+ *
+ * Let's look at a typical novice's session with the mighty ed:
+ *
+ * golem> ed
+ *
+ * ?
+ * help
+ * ?
+ * ?
+ * ?
+ * quit
+ * ?
+ * exit
+ * ?
+ * bye
+ * ?
+ * hello?
+ * ?
+ * eat flaming death
+ * ?
+ * ^C
+ * ?
+ * ^C
+ * ?
+ * ^D
+ * ?
+ *
+ * ---
+ * Note the consistent user interface and error reportage. Ed is
+ * generous enough to flag errors, yet prudent enough not to overwhelm
+ * the novice with verbosity.
+ *
+ * "Ed is the standard text editor."
+ *
+ * Ed, the greatest WYGIWYG editor of all.
+ *
+ * ED IS THE TRUE PATH TO NIRVANA! ED HAS BEEN THE CHOICE OF EDUCATED
+ * AND IGNORANT ALIKE FOR CENTURIES! ED WILL NOT CORRUPT YOUR PRECIOUS
+ * BODILY FLUIDS!! ED IS THE STANDARD TEXT EDITOR! ED MAKES THE SUN
+ * SHINE AND THE BIRDS SING AND THE GRASS GREEN!!
+ *
+ * When I use an editor, I don't want eight extra KILOBYTES of worthless
+ * help screens and cursor positioning code! I just want an EDitor!!
+ * Not a "viitor". Not a "emacsitor". Those aren't even WORDS!!!! ED!
+ * ED! ED IS THE STANDARD!!!
+ *
+ * TEXT EDITOR.
+ *
+ * When IBM, in its ever-present omnipotence, needed to base their
+ * "edlin" on a UNIX standard, did they mimic vi? No. Emacs? Surely
+ * you jest. They chose the most karmic editor of all. The standard.
+ *
+ * Ed is for those who can *remember* what they are working on. If you
+ * are an idiot, you should use Emacs. If you are an Emacs, you should
+ * not be vi. If you use ED, you are on THE PATH TO REDEMPTION. THE
+ * SO-CALLED "VISUAL" EDITORS HAVE BEEN PLACED HERE BY ED TO TEMPT THE
+ * FAITHLESS. DO NOT GIVE IN!!! THE MIGHTY ED HAS SPOKEN!!!
+ *
+ * ?
+ *
+ */
+
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+/*
+ * Editor
+ */
+
+#define SIGHUP 1
+#define SIGINTR 2
+#define SIGQUIT 3
+#define FNSIZE 64
+#define LBSIZE 512
+#define ESIZE 128
+#define GBSIZE 256
+#define NBRA 5
+
+#define CBRA 1
+#define CCHR 2
+#define CDOT 4
+#define CCL 6
+#define NCCL 8
+#define CDOL 10
+#define CEOF 11
+#define CKET 12
+
+#define STAR 01
+
+#define error errfunc()
+#define READ 0
+#define WRITE 1
+
+char peekc;
+char lastc;
+char savedfile[FNSIZE];
+char file[FNSIZE];
+char linebuf[LBSIZE];
+char rhsbuf[LBSIZE / 2];
+char expbuf[ESIZE + 4];
+int circfl;
+int *zero;
+int *dot;
+int *dol;
+int *endcore;
+int *fendcore;
+int *addr1;
+int *addr2;
+char genbuf[LBSIZE];
+int count[2];
+char *nextip;
+char *linebp;
+int ninbuf;
+int io;
+int pflag;
+int onhup;
+int onquit;
+int vflag = 1;
+int listf;
+int col;
+char *globp;
+int tfile = -1;
+int tline;
+char tfname[] = "/tmp/exxxxx";
+char *loc1;
+char *loc2;
+char *locs;
+char ibuff[512];
+int iblock = -1;
+char obuff[512];
+int oblock = -1;
+int ichanged;
+int nleft;
+
+void errfunc();
+
+/* int *errlab=(int*)errfunc; */
+char TMPERR[] = "TMP";
+int names[26];
+char *braslist[NBRA];
+char *braelist[NBRA];
+
+void init();
+
+void commands();
+
+int *address();
+
+void setdot();
+
+void newline();
+
+int append(int (*f)(), int *a);
+
+void delete ();
+
+void setnoaddr();
+
+void filename();
+
+int gettty();
+
+void global(int k);
+
+void nonzero();
+
+void move(int cflag);
+
+char *getline(int tl);
+
+void setall();
+
+void exfile();
+
+void substitute(long inglob);
+
+void putfile();
+
+void putd();
+
+void dounix();
+
+void compile(int c);
+
+int execute(int gf, int *addr);
+
+int putline();
+
+char *getblock(int atl, int iof);
+
+int getchar();
+
+void blkio(int b, char *buf, void *);
+
+int compsub();
+
+void dosub();
+
+char *place(char *asp, char *al1, char *al2);
+
+void reverse(int *aa1, int *aa2);
+
+int advance(char *alp, char *aep);
+
+int cclass(char *aset, int ac, int af);
+
+void puts(char *as);
+
+void putchar(char ac);
+
+void reset();
+
+void setexit();
+
+extern int strlen(const char *s);
+
+int creat(const char *fname, mode_t mode) { return open(fname, O_CREAT, mode); }
+
+int signal(int a1, ...) { return 0; }
+
+int main(int argc, char **argv)
+{
+ register char *p1, *p2;
+
+ onquit = signal(SIGQUIT, 1);
+ onhup = signal(SIGHUP, 1);
+ argv++;
+ if (argc > 1 && **argv == '-')
+ {
+ vflag = 0;
+ /* allow debugging quits? */
+ if ((*argv)[1] == 'q')
+ {
+ signal(SIGQUIT, 0);
+ vflag++;
+ }
+ argv++;
+ argc--;
+ }
+ if (argc > 1)
+ {
+ p1 = *argv;
+ p2 = savedfile;
+ while ((*p2++ = *p1++))
+ ;
+ globp = "r";
+ }
+ fendcore = sbrk(0);
+ init();
+ /* setexit(); */
+ commands();
+ unlink(tfname);
+ return 0;
+}
+
+int getfile();
+
+void commands()
+{
+ register int *a1, c;
+
+ for (;;)
+ {
+ if (pflag)
+ {
+ pflag = 0;
+ addr1 = addr2 = dot;
+ goto print;
+ }
+ addr1 = 0;
+ addr2 = 0;
+ do
+ {
+ addr1 = addr2;
+ if ((a1 = address()) == 0)
+ {
+ c = getchar();
+ break;
+ }
+ addr2 = a1;
+ if ((c = getchar()) == ';')
+ {
+ c = ',';
+ dot = a1;
+ }
+ } while (c == ',');
+ if (addr1 == 0)
+ {
+ addr1 = addr2;
+ }
+ switch (c)
+ {
+ case 'a':
+ setdot();
+ newline();
+ append(gettty, addr2);
+ continue;
+
+ case 'c':
+ delete ();
+ append(gettty, addr1 - 1);
+ continue;
+
+ case 'd':
+ delete ();
+ continue;
+
+ case 'e':
+ setnoaddr();
+ if ((peekc = getchar()) != ' ')
+ error;
+ savedfile[0] = 0;
+ init();
+ addr2 = zero;
+ goto caseread;
+
+ case 'f':
+ setnoaddr();
+ if ((c = getchar()) != '\n')
+ {
+ peekc = c;
+ savedfile[0] = 0;
+ filename();
+ }
+ puts(savedfile);
+ continue;
+
+ case 'g':
+ global(1);
+ continue;
+
+ case 'i':
+ setdot();
+ nonzero();
+ newline();
+ append(gettty, addr2 - 1);
+ continue;
+
+ case 'k':
+ if ((c = getchar()) < 'a' || c > 'z')
+ error;
+ newline();
+ setdot();
+ nonzero();
+ names[c - 'a'] = *addr2 | 01;
+ continue;
+
+ case 'm':
+ move(0);
+ continue;
+
+ case '\n':
+ if (addr2 == 0)
+ {
+ addr2 = dot + 1;
+ }
+ addr1 = addr2;
+ goto print;
+
+ case 'l':
+ listf++;
+ newline();
+ goto print;
+ case 'p':
+ newline();
+ print:
+ setdot();
+ nonzero();
+ a1 = addr1;
+ do
+ puts(getline(*a1++));
+ while (a1 <= addr2);
+ dot = addr2;
+ listf = 0;
+ continue;
+
+ case 'q':
+ setnoaddr();
+ newline();
+ unlink(tfname);
+ exit(0);
+
+ case 'r':
+ caseread:
+ filename();
+ if ((io = open(file, O_RDONLY, 0)) < 0)
+ {
+ lastc = '\n';
+ error;
+ }
+ setall();
+ ninbuf = 0;
+ append(getfile, addr2);
+ exfile();
+ continue;
+
+ case 's':
+ setdot();
+ nonzero();
+ substitute((long)globp);
+ continue;
+
+ case 't':
+ move(1);
+ continue;
+
+ case 'v':
+ global(0);
+ continue;
+
+ case 'w':
+ setall();
+ nonzero();
+ filename();
+ if ((io = open(file, O_CREAT | O_RDWR | O_TRUNC, 0666)) < 0)
+ error;
+ putfile();
+ exfile();
+ continue;
+
+ case '=':
+ setall();
+ newline();
+ count[1] = (addr2 - zero) & 077777;
+ putd();
+ putchar('\n');
+ continue;
+
+ case '!':
+ dounix();
+ continue;
+
+ case EOF:
+ return;
+ }
+ error;
+ }
+}
+
+int *address()
+{
+ register int *a1, minus, c;
+ int n, relerr;
+
+ minus = 0;
+ a1 = 0;
+ for (;;)
+ {
+ c = getchar();
+ if ('0' <= c && c <= '9')
+ {
+ n = 0;
+ do
+ {
+ n *= 10;
+ n += c - '0';
+ } while ((c = getchar()) >= '0' && c <= '9');
+ peekc = c;
+ if (a1 == 0)
+ {
+ a1 = zero;
+ }
+ if (minus < 0)
+ {
+ n = -n;
+ }
+ a1 += n;
+ minus = 0;
+ continue;
+ }
+ relerr = 0;
+ if (a1 || minus)
+ {
+ relerr++;
+ }
+ switch (c)
+ {
+ case ' ':
+ case '\t':
+ continue;
+
+ case '+':
+ minus++;
+ if (a1 == 0)
+ {
+ a1 = dot;
+ }
+ continue;
+
+ case '-':
+ case '^':
+ minus--;
+ if (a1 == 0)
+ {
+ a1 = dot;
+ }
+ continue;
+
+ case '?':
+ case '/':
+ compile(c);
+ a1 = dot;
+ for (;;)
+ {
+ if (c == '/')
+ {
+ a1++;
+ if (a1 > dol)
+ {
+ a1 = zero;
+ }
+ }
+ else
+ {
+ a1--;
+ if (a1 < zero)
+ {
+ a1 = dol;
+ }
+ }
+ if (execute(0, a1))
+ {
+ break;
+ }
+ if (a1 == dot)
+ error;
+ }
+ break;
+
+ case '$':
+ a1 = dol;
+ break;
+
+ case '.':
+ a1 = dot;
+ break;
+
+ case '\'':
+ if ((c = getchar()) < 'a' || c > 'z')
+ error;
+ for (a1 = zero; a1 <= dol; a1++)
+ {
+ if (names[c - 'a'] == (*a1 | 01))
+ {
+ break;
+ }
+ }
+ break;
+
+ default:
+ peekc = c;
+ if (a1 == 0)
+ {
+ return (0);
+ }
+ a1 += minus;
+ if (a1 < zero || a1 > dol)
+ error;
+ return (a1);
+ }
+ if (relerr)
+ error;
+ }
+}
+
+void setdot()
+{
+ if (addr2 == 0)
+ {
+ addr1 = addr2 = dot;
+ }
+ if (addr1 > addr2)
+ error;
+}
+
+void setall()
+{
+ if (addr2 == 0)
+ {
+ addr1 = zero + 1;
+ addr2 = dol;
+ if (dol == zero)
+ {
+ addr1 = zero;
+ }
+ }
+ setdot();
+}
+
+void setnoaddr()
+{
+ if (addr2)
+ error;
+}
+
+void nonzero()
+{
+ if (addr1 <= zero || addr2 > dol)
+ error;
+}
+
+void newline()
+{
+ register int c;
+
+ if ((c = getchar()) == '\n')
+ {
+ return;
+ }
+ if (c == 'p' || c == 'l')
+ {
+ pflag++;
+ if (c == 'l')
+ {
+ listf++;
+ }
+ if (getchar() == '\n')
+ {
+ return;
+ }
+ }
+ error;
+}
+
+void filename()
+{
+ register char *p1, *p2;
+ register int c;
+
+ count[1] = 0;
+ c = getchar();
+ if (c == '\n' || c == EOF)
+ {
+ p1 = savedfile;
+ if (*p1 == 0)
+ error;
+ p2 = file;
+ while ((*p2++ = *p1++))
+ ;
+ return;
+ }
+ if (c != ' ')
+ error;
+ while ((c = getchar()) == ' ')
+ ;
+ if (c == '\n')
+ error;
+ p1 = file;
+ do
+ {
+ *p1++ = c;
+ } while ((c = getchar()) != '\n');
+ *p1++ = 0;
+ if (savedfile[0] == 0)
+ {
+ p1 = savedfile;
+ p2 = file;
+ while ((*p1++ = *p2++))
+ ;
+ }
+}
+
+void exfile()
+{
+ close(io);
+ io = -1;
+ if (vflag)
+ {
+ putd();
+ putchar('\n');
+ }
+}
+
+void errfunc(void)
+{
+ register int c;
+
+ listf = 0;
+ puts("?");
+ count[0] = 0;
+ lseek(0, 0, 2);
+ pflag = 0;
+ if (globp)
+ {
+ lastc = '\n';
+ }
+ globp = 0;
+ peekc = lastc;
+ while ((c = getchar()) != '\n' && c != EOF)
+ ;
+ if (io > 0)
+ {
+ close(io);
+ io = -1;
+ }
+ /* reset(); */
+}
+
+int getchar()
+{
+ if ((lastc = peekc))
+ {
+ peekc = 0;
+ return (lastc);
+ }
+ if (globp)
+ {
+ if ((lastc = *globp++) != 0)
+ {
+ return (lastc);
+ }
+ globp = 0;
+ return (EOF);
+ }
+ if (read(0, &lastc, 1) <= 0)
+ {
+ return (lastc = EOF);
+ }
+ lastc &= 0177;
+ return (lastc);
+}
+
+int gettty()
+{
+ register long c, gf;
+ register char *p;
+
+ p = linebuf;
+ gf = (long)globp;
+ while ((c = getchar()) != '\n')
+ {
+ if (c == EOF)
+ {
+ if (gf)
+ {
+ peekc = c;
+ }
+ return (int)(c);
+ }
+ if ((c &= 0177) == 0)
+ {
+ continue;
+ }
+ *p++ = c;
+ if (p >= &linebuf[LBSIZE - 2])
+ error;
+ }
+ *p++ = 0;
+ if (linebuf[0] == '.' && linebuf[1] == 0)
+ {
+ return (EOF);
+ }
+ return (0);
+}
+
+int getfile()
+{
+ register int c;
+ register char *lp, *fp;
+
+ lp = linebuf;
+ fp = nextip;
+ do
+ {
+ if (--ninbuf < 0)
+ {
+ if ((ninbuf = read(io, genbuf, LBSIZE) - 1) < 0)
+ {
+ return (EOF);
+ }
+ fp = genbuf;
+ }
+ if (lp >= &linebuf[LBSIZE])
+ error;
+ if ((*lp++ = c = *fp++ & 0177) == 0)
+ {
+ lp--;
+ continue;
+ }
+ if (++count[1] == 0)
+ {
+ ++count[0];
+ }
+ } while (c != '\n');
+ *--lp = 0;
+ nextip = fp;
+ return (0);
+}
+
+void putfile()
+{
+ int *a1;
+ register char *fp, *lp;
+ register int nib;
+
+ nib = 512;
+ fp = genbuf;
+ a1 = addr1;
+ do
+ {
+ lp = getline(*a1++);
+ for (;;)
+ {
+ if (--nib < 0)
+ {
+ write(io, genbuf, fp - genbuf);
+ nib = 511;
+ fp = genbuf;
+ }
+ if (++count[1] == 0)
+ {
+ ++count[0];
+ }
+ if ((*fp++ = *lp++) == 0)
+ {
+ fp[-1] = '\n';
+ break;
+ }
+ }
+ } while (a1 <= addr2);
+ write(io, genbuf, fp - genbuf);
+}
+
+int append(f, a) int (*f)();
+int *a;
+{
+ register int *a1, *a2, *rdot;
+ int nline, tl;
+ int *corep = (int *)endcore;
+ struct core
+ {
+ int integer;
+ };
+
+ nline = 0;
+ dot = a;
+ while ((*f)() == 0)
+ {
+ if (dol >= endcore)
+ {
+ if (sbrk(1024) == (char *)-1)
+ error;
+ *corep += 1024;
+ }
+ tl = putline();
+ nline++;
+ a1 = ++dol;
+ a2 = a1 + 1;
+ rdot = ++dot;
+ while (a1 > rdot)
+ *--a2 = *--a1;
+ *rdot = tl;
+ }
+ return (nline);
+}
+
+void dounix()
+{
+ register int savint, pid, rpid;
+ int retcode;
+
+ setnoaddr();
+ if ((pid = fork()) == 0)
+ {
+ char *argv[] = {"/bin/sh", 0};
+ char *envp[] = {"PATH=/bin", 0};
+
+ signal(SIGHUP, onhup);
+ signal(SIGQUIT, onquit);
+ execve("/bin/sh", argv, envp);
+ exit(-1);
+ }
+ savint = signal(SIGINTR, 1);
+ while ((rpid = wait(&retcode)) != pid && rpid != -1)
+ ;
+ signal(SIGINTR, savint);
+ puts("!");
+}
+
+void delete ()
+{
+ register int *a1, *a2, *a3;
+
+ setdot();
+ newline();
+ nonzero();
+ a1 = addr1;
+ a2 = addr2 + 1;
+ a3 = dol;
+ dol -= a2 - a1;
+ do
+ *a1++ = *a2++;
+ while (a2 <= a3);
+ a1 = addr1;
+ if (a1 > dol)
+ {
+ a1 = dol;
+ }
+ dot = a1;
+}
+
+char *getline(int tl)
+{
+ register char *bp, *lp;
+ register int nl;
+
+ lp = linebuf;
+ bp = getblock(tl, READ);
+ nl = nleft;
+ tl &= ~0377;
+ while ((*lp++ = *bp++))
+ if (--nl == 0)
+ {
+ bp = getblock(tl += 0400, READ);
+ nl = nleft;
+ }
+ return (linebuf);
+}
+
+int putline()
+{
+ register char *bp, *lp;
+ register int nl;
+ int tl;
+
+ lp = linebuf;
+ tl = tline;
+ bp = getblock(tl, WRITE);
+ nl = nleft;
+ tl &= ~0377;
+ while ((*bp = *lp++))
+ {
+ if (*bp++ == '\n')
+ {
+ *--bp = 0;
+ linebp = lp;
+ break;
+ }
+ if (--nl == 0)
+ {
+ bp = getblock(tl += 0400, WRITE);
+ nl = nleft;
+ }
+ }
+ nl = tline;
+ tline += (((lp - linebuf) + 03) >> 1) & 077776;
+ return (nl);
+}
+
+char *getblock(int atl, int iof)
+{
+ register int bno, off;
+
+ bno = (atl >> 8) & 0377;
+ off = (atl << 1) & 0774;
+ if (bno >= 255)
+ {
+ puts(TMPERR);
+ error;
+ }
+ nleft = 512 - off;
+ if (bno == iblock)
+ {
+ ichanged |= iof;
+ return (ibuff + off);
+ }
+ if (bno == oblock)
+ {
+ return (obuff + off);
+ }
+ if (iof == READ)
+ {
+ if (ichanged)
+ {
+ blkio(iblock, ibuff, (void *)write);
+ }
+ ichanged = 0;
+ iblock = bno;
+ blkio(bno, ibuff, (void *)read);
+ return (ibuff + off);
+ }
+ if (oblock >= 0)
+ {
+ blkio(oblock, obuff, (void *)write);
+ }
+ oblock = bno;
+ return (obuff + off);
+}
+
+void blkio(int b, char *buf, void *iofcn)
+{
+ int (*iof)(int f, char *b, int len) =
+ (int (*)(int f, char *b, int len))iofcn;
+ lseek(tfile, b, SEEK_SET);
+ if ((*iof)(tfile, buf, 512) != 512)
+ {
+ puts(TMPERR);
+ error;
+ }
+}
+
+void init()
+{
+ register char *p;
+ register int pid;
+
+ close(tfile);
+ tline = 0;
+ iblock = -1;
+ oblock = -1;
+ ichanged = 0;
+ pid = getpid();
+ for (p = &tfname[11]; p > &tfname[6];)
+ {
+ *--p = (pid & 07) + '0';
+ pid >>= 3;
+ }
+ close(creat(tfname, 0600));
+ tfile = open(tfname, O_RDWR, 0);
+ brk(fendcore);
+ dot = zero = dol = fendcore;
+ endcore = fendcore - 2;
+}
+
+void global(int k)
+{
+ register char *gp;
+ register int c;
+ register int *a1;
+ char globuf[GBSIZE];
+
+ if (globp)
+ error;
+ setall();
+ nonzero();
+ if ((c = getchar()) == '\n')
+ error;
+ compile(c);
+ gp = globuf;
+ while ((c = getchar()) != '\n')
+ {
+ if (c == EOF)
+ error;
+ if (c == '\\')
+ {
+ c = getchar();
+ if (c != '\n')
+ {
+ *gp++ = '\\';
+ }
+ }
+ *gp++ = c;
+ if (gp >= &globuf[GBSIZE - 2])
+ error;
+ }
+ *gp++ = '\n';
+ *gp++ = 0;
+ for (a1 = zero; a1 <= dol; a1++)
+ {
+ *a1 &= ~01;
+ if (a1 >= addr1 && a1 <= addr2 && execute(0, a1) == k)
+ {
+ *a1 |= 01;
+ }
+ }
+ for (a1 = zero; a1 <= dol; a1++)
+ {
+ if (*a1 & 01)
+ {
+ *a1 &= ~01;
+ dot = a1;
+ globp = globuf;
+ commands();
+ a1 = zero;
+ }
+ }
+}
+
+int getsub();
+
+void substitute(long inglob)
+{
+ register int gsubf, *a1, nl;
+
+ gsubf = compsub();
+ for (a1 = addr1; a1 <= addr2; a1++)
+ {
+ if (execute(0, a1) == 0)
+ {
+ continue;
+ }
+ inglob |= 01;
+ dosub();
+ if (gsubf)
+ {
+ while (*loc2)
+ {
+ if (execute(1, 0) == 0)
+ {
+ break;
+ }
+ dosub();
+ }
+ }
+ *a1 = putline();
+ nl = append(getsub, a1);
+ a1 += nl;
+ addr2 += nl;
+ }
+ if (inglob == 0)
+ error;
+}
+
+int compsub()
+{
+ register int seof, c;
+ register char *p;
+
+ if ((seof = getchar()) == '\n')
+ error;
+ compile(seof);
+ p = rhsbuf;
+ for (;;)
+ {
+ c = getchar();
+ if (c == '\\')
+ {
+ c = getchar() | 0200;
+ }
+ if (c == '\n')
+ error;
+ if (c == seof)
+ {
+ break;
+ }
+ *p++ = c;
+ if (p >= &rhsbuf[LBSIZE / 2])
+ error;
+ }
+ *p++ = 0;
+ if ((peekc = getchar()) == 'g')
+ {
+ peekc = 0;
+ newline();
+ return (1);
+ }
+ newline();
+ return (0);
+}
+
+int getsub()
+{
+ register char *p1, *p2;
+
+ p1 = linebuf;
+ if ((p2 = linebp) == 0)
+ {
+ return (EOF);
+ }
+ while ((*p1++ = *p2++))
+ ;
+ linebp = 0;
+ return (0);
+}
+
+void dosub()
+{
+ register char *lp, *sp, *rp;
+ int c;
+
+ lp = linebuf;
+ sp = genbuf;
+ rp = rhsbuf;
+ while (lp < loc1)
+ *sp++ = *lp++;
+ while ((c = *rp++))
+ {
+ if (c == '&')
+ {
+ sp = place(sp, loc1, loc2);
+ continue;
+ }
+ else if (c < 0 && (c &= 0177) >= '1' && c < NBRA + '1')
+ {
+ sp = place(sp, braslist[c - '1'], braelist[c - '1']);
+ continue;
+ }
+ *sp++ = c & 0177;
+ if (sp >= &genbuf[LBSIZE])
+ error;
+ }
+ lp = loc2;
+ loc2 = sp + (long)linebuf - (long)genbuf;
+ while ((*sp++ = *lp++))
+ if (sp >= &genbuf[LBSIZE])
+ error;
+ lp = linebuf;
+ sp = genbuf;
+ while ((*lp++ = *sp++))
+ ;
+}
+
+char *place(char *asp, char *al1, char *al2)
+{
+ register char *sp, *l1, *l2;
+
+ sp = asp;
+ l1 = al1;
+ l2 = al2;
+ while (l1 < l2)
+ {
+ *sp++ = *l1++;
+ if (sp >= &genbuf[LBSIZE])
+ error;
+ }
+ return (sp);
+}
+
+int getcopy();
+
+void move(int cflag)
+{
+ register int *adt, *ad1, *ad2;
+
+ setdot();
+ nonzero();
+ if ((adt = address()) == 0)
+ error;
+ newline();
+ ad1 = addr1;
+ ad2 = addr2;
+ if (cflag)
+ {
+ ad1 = dol;
+ append(getcopy, ad1++);
+ ad2 = dol;
+ }
+ ad2++;
+ if (adt < ad1)
+ {
+ dot = adt + (ad2 - ad1);
+ if ((++adt) == ad1)
+ {
+ return;
+ }
+ reverse(adt, ad1);
+ reverse(ad1, ad2);
+ reverse(adt, ad2);
+ }
+ else if (adt >= ad2)
+ {
+ dot = adt++;
+ reverse(ad1, ad2);
+ reverse(ad2, adt);
+ reverse(ad1, adt);
+ }
+ else
+ error;
+}
+
+void reverse(int *aa1, int *aa2)
+{
+ register int *a1, *a2, t;
+
+ a1 = aa1;
+ a2 = aa2;
+ for (;;)
+ {
+ t = *--a2;
+ if (a2 <= a1)
+ {
+ return;
+ }
+ *a2 = *a1;
+ *a1++ = t;
+ }
+}
+
+int getcopy()
+{
+ if (addr1 > addr2)
+ {
+ return (EOF);
+ }
+ getline(*addr1++);
+ return (0);
+}
+
+void compile(int aeof)
+{
+ register int eof, c;
+ register char *ep;
+ char *lastep;
+ char bracket[NBRA], *bracketp;
+ int nbra;
+ int cclcnt;
+
+ ep = expbuf;
+ eof = aeof;
+ bracketp = bracket;
+ nbra = 0;
+ if ((c = getchar()) == eof)
+ {
+ if (*ep == 0)
+ error;
+ return;
+ }
+ circfl = 0;
+ if (c == '^')
+ {
+ c = getchar();
+ circfl++;
+ }
+ if (c == '*')
+ {
+ goto cerror;
+ }
+ peekc = c;
+ for (;;)
+ {
+ if (ep >= &expbuf[ESIZE])
+ {
+ goto cerror;
+ }
+ c = getchar();
+ if (c == eof)
+ {
+ *ep++ = CEOF;
+ return;
+ }
+ if (c != '*')
+ {
+ lastep = ep;
+ }
+ switch (c)
+ {
+ case '\\':
+ if ((c = getchar()) == '(')
+ {
+ if (nbra >= NBRA)
+ {
+ goto cerror;
+ }
+ *bracketp++ = nbra;
+ *ep++ = CBRA;
+ *ep++ = nbra++;
+ continue;
+ }
+ if (c == ')')
+ {
+ if (bracketp <= bracket)
+ {
+ goto cerror;
+ }
+ *ep++ = CKET;
+ *ep++ = *--bracketp;
+ continue;
+ }
+ *ep++ = CCHR;
+ if (c == '\n')
+ {
+ goto cerror;
+ }
+ *ep++ = c;
+ continue;
+
+ case '.':
+ *ep++ = CDOT;
+ continue;
+
+ case '\n':
+ goto cerror;
+
+ case '*':
+ if (*lastep == CBRA || *lastep == CKET)
+ error;
+ *lastep |= STAR;
+ continue;
+
+ case '$':
+ if ((peekc = getchar()) != eof)
+ {
+ goto defchar;
+ }
+ *ep++ = CDOL;
+ continue;
+
+ case '[':
+ *ep++ = CCL;
+ *ep++ = 0;
+ cclcnt = 1;
+ if ((c = getchar()) == '^')
+ {
+ c = getchar();
+ ep[-2] = NCCL;
+ }
+ do
+ {
+ if (c == '\n')
+ {
+ goto cerror;
+ }
+ *ep++ = c;
+ cclcnt++;
+ if (ep >= &expbuf[ESIZE])
+ {
+ goto cerror;
+ }
+ } while ((c = getchar()) != ']');
+ lastep[1] = cclcnt;
+ continue;
+
+ defchar:
+ default:
+ *ep++ = CCHR;
+ *ep++ = c;
+ }
+ }
+cerror:
+ expbuf[0] = 0;
+ error;
+}
+
+int execute(gf, addr) int gf;
+int *addr;
+{
+ register char *p1, *p2, c;
+
+ if (gf)
+ {
+ if (circfl)
+ {
+ return (0);
+ }
+ p1 = linebuf;
+ p2 = genbuf;
+ while ((*p1++ = *p2++))
+ ;
+ locs = p1 = loc2;
+ }
+ else
+ {
+ if (addr == zero)
+ {
+ return (0);
+ }
+ p1 = getline(*addr);
+ locs = 0;
+ }
+ p2 = expbuf;
+ if (circfl)
+ {
+ loc1 = p1;
+ return (advance(p1, p2));
+ }
+ /* fast check for first character */
+ if (*p2 == CCHR)
+ {
+ c = p2[1];
+ do
+ {
+ if (*p1 != c)
+ {
+ continue;
+ }
+ if (advance(p1, p2))
+ {
+ loc1 = p1;
+ return (1);
+ }
+ } while (*p1++);
+ return (0);
+ }
+ /* regular algorithm */
+ do
+ {
+ if (advance(p1, p2))
+ {
+ loc1 = p1;
+ return (1);
+ }
+ } while (*p1++);
+ return (0);
+}
+
+int advance(char *alp, char *aep)
+{
+ register char *lp, *ep, *curlp;
+
+ lp = alp;
+ ep = aep;
+ for (;;)
+ {
+ switch (*ep++)
+ {
+ case CCHR:
+ if (*ep++ == *lp++)
+ {
+ continue;
+ }
+ return (0);
+
+ case CDOT:
+ if (*lp++)
+ {
+ continue;
+ }
+ return (0);
+
+ case CDOL:
+ if (*lp == 0)
+ {
+ continue;
+ }
+ return (0);
+
+ case CEOF:
+ loc2 = lp;
+ return (1);
+
+ case CCL:
+ if (cclass(ep, *lp++, 1))
+ {
+ ep += *ep;
+ continue;
+ }
+ return (0);
+
+ case NCCL:
+ if (cclass(ep, *lp++, 0))
+ {
+ ep += *ep;
+ continue;
+ }
+ return (0);
+
+ case CBRA:
+ braslist[(int)*ep++] = lp;
+ continue;
+
+ case CKET:
+ braelist[(int)*ep++] = lp;
+ continue;
+
+ case CDOT | STAR:
+ curlp = lp;
+ while (*lp++)
+ ;
+ goto star;
+
+ case CCHR | STAR:
+ curlp = lp;
+ while (*lp++ == *ep)
+ ;
+ ep++;
+ goto star;
+
+ case CCL | STAR:
+ case NCCL | STAR:
+ curlp = lp;
+ while (cclass(ep, *lp++, ep[-1] == (CCL | STAR)))
+ ;
+ ep += *ep;
+ goto star;
+
+ star:
+ do
+ {
+ lp--;
+ if (lp == locs)
+ {
+ break;
+ }
+ if (advance(lp, ep))
+ {
+ return (1);
+ }
+ } while (lp > curlp);
+ return (0);
+
+ default:
+ error;
+ }
+ }
+}
+
+int cclass(char *aset, int ac, int af)
+{
+ register char *set, c;
+ register int n;
+
+ set = aset;
+ if ((c = ac) == 0)
+ {
+ return (0);
+ }
+ n = *set++;
+ while (--n)
+ if (*set++ == c)
+ {
+ return (af);
+ }
+ return (!af);
+}
+
+void putd()
+{
+#if 0
+ register r;
+ extern ldivr;
+
+ count[1] = ldiv(count[0], count[1], 10);
+ count[0] = 0;
+ r = ldivr;
+ if (count[1])
+ putd();
+ putchar(r + '0');
+#else
+ printf("%d", count[1]);
+#endif
+}
+
+void puts(char *as)
+{
+ register char *sp;
+
+ sp = as;
+ col = 0;
+ while (*sp)
+ putchar(*sp++);
+ putchar('\n');
+}
+
+char line[80];
+char *linp = line;
+
+void putchar(char ac)
+{
+ register char *lp;
+ register int c;
+
+ lp = linp;
+ c = ac;
+ if (listf)
+ {
+ col++;
+ if (col >= 72)
+ {
+ col = 0;
+ *lp++ = '\\';
+ *lp++ = '\n';
+ }
+ if (c == '\t')
+ {
+ c = '>';
+ goto esc;
+ }
+ if (c == '\b')
+ {
+ c = '<';
+ esc:
+ *lp++ = '-';
+ *lp++ = '\b';
+ *lp++ = c;
+ goto out;
+ }
+ if (c < ' ' && c != '\n')
+ {
+ *lp++ = '\\';
+ *lp++ = (c >> 3) + '0';
+ *lp++ = (c & 07) + '0';
+ col += 2;
+ goto out;
+ }
+ }
+ *lp++ = c;
+out:
+ if (c == '\n' || lp >= &line[64])
+ {
+ linp = line;
+ write(1, line, lp - line);
+ return;
+ }
+ linp = lp;
+}
+
+/*
+ * Get process ID routine if system call is unavailable.
+
+getpid()
+{
+ register f;
+ int b[1];
+
+ f = open("/dev/kmem", 0);
+ if(f < 0)
+ return(-1);
+ seek(f, 0140074, 0);
+ read(f, b, 2);
+ seek(f, b[0]+8, 0);
+ read(f, b, 2);
+ close(f);
+ return(b[0]);
+}
+ */
diff --git a/user/bin/hd.c b/user/bin/hd.c
new file mode 100644
index 0000000..4b5b81c
--- /dev/null
+++ b/user/bin/hd.c
@@ -0,0 +1,90 @@
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#define LINE_LEN 16
+
+int main(int argc, char **argv)
+{
+ int readfd = 0;
+ if (argc == 2)
+ {
+ readfd = open(argv[1], O_RDONLY, 0666);
+ if (readfd < 0)
+ {
+ fprintf(stderr, "open: %s\n", strerror(errno));
+ return 1;
+ }
+ }
+ else if (argc > 2)
+ {
+ printf("usage: hd [file]\n");
+ return 1;
+ }
+
+ char lastbuf[LINE_LEN];
+ char curbuf[LINE_LEN];
+ int off = 0;
+ int lastrep = 0;
+ int bytes;
+
+ int i;
+ while ((bytes = read(readfd, curbuf, LINE_LEN)) > 0)
+ {
+ if (off > 0 && !memcmp(lastbuf, curbuf, LINE_LEN))
+ {
+ if (!lastrep)
+ {
+ printf("*\n");
+ lastrep = 1;
+ }
+ off += bytes;
+ continue;
+ }
+ lastrep = 0;
+ printf("%08x ", off);
+ off += bytes;
+ /* print bytes */
+ for (i = 0; i < LINE_LEN; ++i)
+ {
+ if (i < bytes)
+ {
+ printf("%02x ", (unsigned char)curbuf[i]);
+ }
+ else
+ {
+ printf(" ");
+ }
+ if (i == 7)
+ {
+ printf(" ");
+ }
+ }
+ /* show printable characters */
+ printf("|");
+ for (i = 0; i < bytes; ++i)
+ {
+ char c = curbuf[i];
+ if (c < 32 || c > 126)
+ {
+ printf(".");
+ }
+ else
+ {
+ printf("%c", c);
+ }
+ }
+ printf("|\n");
+ memcpy(lastbuf, curbuf, LINE_LEN);
+ }
+ printf("%08x\n", off);
+
+ if (readfd > 0)
+ {
+ close(readfd);
+ }
+ return 0;
+}
diff --git a/user/bin/ls.c b/user/bin/ls.c
new file mode 100644
index 0000000..e04b39f
--- /dev/null
+++ b/user/bin/ls.c
@@ -0,0 +1,108 @@
+#include <dirent.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <unistd.h>
+
+#include <errno.h>
+
+static int do_ls(const char *dir)
+{
+ int fd;
+ struct dirent *dirent;
+ int nbytes;
+ char tmpbuf[256];
+ stat_t sbuf;
+
+ union {
+ struct dirent dirent;
+ char buf[4096];
+ } lsb;
+
+ fd = open(dir, O_RDONLY, 0600);
+ if (fd < 0)
+ {
+ fprintf(stderr, "ls: unable to open \"%s\": errno %d\n", dir, errno);
+ return 1;
+ }
+
+ while ((nbytes = getdents(fd, &lsb.dirent, sizeof(lsb))) > 0)
+ {
+ dirent = &lsb.dirent;
+
+ if (nbytes % sizeof(struct dirent))
+ {
+ fprintf(stderr,
+ "ls: incorrect return value from getdents (%d):"
+ " not a multiple of sizeof(struct dirent) (%ld)\n",
+ nbytes, sizeof(struct dirent));
+ return 1;
+ }
+ do
+ {
+ int reclen;
+ int size;
+
+ snprintf(tmpbuf, sizeof(tmpbuf), "%s/%s", dir, dirent->d_name);
+ if (0 == stat(tmpbuf, &sbuf))
+ {
+ size = sbuf.st_size;
+ }
+ else
+ {
+ size = 0;
+ }
+
+ reclen = sizeof(struct dirent);
+ fprintf(stdout, "%7d %-20s %d\n", size, dirent->d_name,
+ dirent->d_ino);
+ dirent = (struct dirent *)(((char *)dirent) + reclen);
+ nbytes -= reclen;
+ } while (nbytes);
+ }
+ if (nbytes < 0)
+ {
+ if (errno == ENOTDIR)
+ {
+ fprintf(stdout, "%s\n", dir);
+ }
+ else
+ {
+ fprintf(stderr, "ls: couldn't list %s: errno %d\n", dir, errno);
+ }
+ }
+
+ if (close(fd) < 0)
+ {
+ fprintf(stderr, "ls: close %s: errno %d\n", dir, errno);
+ }
+ return 0;
+}
+
+int main(int argc, char **argv)
+{
+ int ret;
+
+ if (argc < 2)
+ {
+ ret = do_ls(".");
+ }
+ else if (argc < 3)
+ {
+ ret = do_ls(argv[1]);
+ }
+ else
+ {
+ int error;
+ int argn;
+
+ error = 0;
+ for (argn = 1; argn < argc; argn++)
+ {
+ fprintf(stdout, "%s:\n", argv[argn]);
+ error += do_ls(argv[argn]);
+ fprintf(stdout, "\n");
+ }
+ ret = error;
+ }
+ return ret;
+}
diff --git a/user/bin/sh.c b/user/bin/sh.c
new file mode 100644
index 0000000..e38a7f2
--- /dev/null
+++ b/user/bin/sh.c
@@ -0,0 +1,1910 @@
+#undef DEBUG_SH
+
+#ifdef DEBUG_SH
+#define dbg(x) fprintf x
+#else
+#define dbg(x)
+#endif
+
+#include <ctype.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/mman.h>
+#include <unistd.h>
+
+#define ROOT "/"
+
+#define HOME ROOT "."
+#define TMP ROOT "tmp"
+
+#define ARGV_MAX 256
+#define REDIR_MAX 10
+
+typedef struct redirect
+{
+ int r_sfd;
+ int r_dfd;
+} redirect_t;
+
+typedef struct redirect_map
+{
+ int rm_nfds;
+ redirect_t rm_redir[REDIR_MAX];
+} redirect_map_t;
+
+typedef struct ioenv
+{
+ int io_map_fd[3];
+#define io_map_file io_map_fd
+} ioenv_t;
+
+static char **my_envp;
+
+static void parse(char *line);
+
+static int execute(int argc, char *argv[], redirect_map_t *map);
+
+static void add_redirect(redirect_map_t *map, int sfd, int dfd);
+
+#define DECL_CMD(x) static int cmd_##x(int argc, char *argv[], ioenv_t *io)
+
+DECL_CMD(env);
+
+DECL_CMD(cd);
+
+DECL_CMD(help);
+
+DECL_CMD(exit);
+
+DECL_CMD(mkdir);
+
+DECL_CMD(rmdir);
+
+DECL_CMD(clear);
+
+DECL_CMD(ln);
+
+DECL_CMD(rm);
+
+DECL_CMD(mv);
+
+DECL_CMD(cat);
+
+DECL_CMD(echo);
+
+DECL_CMD(cp);
+
+DECL_CMD(sync);
+
+DECL_CMD(check);
+
+DECL_CMD(repeat);
+
+DECL_CMD(parallel);
+
+DECL_CMD(time);
+
+typedef struct
+{
+ const char *cmd_name;
+
+ int (*cmd_func)(int argc, char *argv[], ioenv_t *io);
+
+ const char *cmd_helptext;
+} cmd_t;
+
+static cmd_t builtin_cmds[] = {
+ {"?", cmd_help, "list shell commands"},
+ {"cat", cmd_cat, "display file"},
+ {"env", cmd_env, "display environment"},
+ {"cd", cmd_cd, "change directory"},
+ {"check", cmd_check, "test operating system"},
+ {"clear", cmd_clear, "clear screen"},
+ {"cp", cmd_cp, "copy file"},
+ {"echo", cmd_echo, "print arguments"},
+ {"exit", cmd_exit, "exit shell"},
+ {"help", cmd_help, "list shell commands"},
+ {"ln", cmd_ln, "link file"},
+ {"mkdir", cmd_mkdir, "create a directory"},
+ {"mv", cmd_mv, "move file"},
+ {"quit", cmd_exit, "exit shell"},
+ {"rm", cmd_rm, "remove file(s)"},
+ {"rmdir", cmd_rmdir, "remove a directory"},
+ {"sync", cmd_sync, "sync filesystems"},
+ {"repeat", cmd_repeat, "repeat a command"},
+ {"parallel", cmd_parallel, "run multiple commands in parallel"},
+ {"time", cmd_time, "time a command"},
+ {NULL, NULL, NULL}};
+
+#define builtin_stdin (&io->io_map_file[0])
+#define builtin_stdout (&io->io_map_file[1])
+#define builtin_stderr (&io->io_map_file[2])
+
+#define is_std_stream(fd) ((fd) >= 0 && (fd) <= 2)
+
+DECL_CMD(chk_sparse);
+
+DECL_CMD(chk_unlink);
+
+DECL_CMD(chk_wrnoent);
+
+DECL_CMD(chk_sbrk);
+
+DECL_CMD(chk_zero);
+
+DECL_CMD(chk_null);
+
+DECL_CMD(chk_priv);
+
+DECL_CMD(chk_malloc);
+
+static cmd_t check_cmds[] = {
+ {"null", cmd_chk_null, "read and write /dev/null"},
+ {"sbrk", cmd_chk_sbrk, "memory allocation - sbrk"},
+ {"sparse", cmd_chk_sparse, "sparse mmap writes"},
+ {"unlink", cmd_chk_unlink, "create and unlink a file"},
+ {"wrnoent", cmd_chk_wrnoent, "write to an unlinked file"},
+ {"zero", cmd_chk_zero, "read and map /dev/zero"},
+ {"priv", cmd_chk_priv, "writes to MAP_PRIVATE mapping"},
+ {"malloc", cmd_chk_malloc, "memory allocation - malloc"},
+ {NULL, NULL, NULL}};
+
+static int check_failed(const char *test, const char *cmd)
+{
+ fprintf(stderr, "%s: %s failed: %s\n", test, cmd, strerror(errno));
+ /*fprintf(stderr, "%s: %s failed: errno %d\n", test, cmd, errno);*/
+ return 1;
+}
+
+static int check_exists(const char *file)
+{
+ int fd;
+
+ fd = open(file, O_RDONLY, 0);
+ if (fd >= 0)
+ {
+ close(fd);
+ return 1;
+ }
+ else
+ {
+ return 0;
+ }
+}
+
+char *strdup(const char *); // darmanio: for some reason, gcc complains if I
+ // don't re-forward declare it here...
+static char **copy_args(int argc, char *argv[])
+{
+ char **args = malloc(sizeof(char *) * (argc + 1));
+ args[argc] = NULL;
+ while (--argc >= 0)
+ args[argc] = strdup(argv[argc]);
+ return args;
+}
+
+static void free_args(int argc, char *argv[])
+{
+ while (--argc >= 0)
+ free(argv[argc]);
+ free(argv);
+}
+
+DECL_CMD(chk_priv)
+{
+ const char *test = argv[0];
+ const char *tmpfile = TMP "/priv";
+ int fd;
+ void *addr;
+ const char *str = "Hello there.\n";
+ int error;
+ char *tmpstr;
+ size_t len;
+ uint32_t ii;
+ char tmpbuf[256];
+
+ if (check_exists(tmpfile))
+ {
+ fprintf(stderr, "%s: file exists: %s\n", test, tmpfile);
+ return 1;
+ }
+
+ /* Create a file with some data.
+ */
+
+ fd = open(tmpfile, O_CREAT | O_RDWR, 0);
+ if (fd < 0)
+ {
+ return check_failed(test, "open");
+ }
+
+ if (write(fd, str, strlen(str)) != (ssize_t)strlen(str))
+ {
+ error = check_failed(test, "write");
+ goto err_close;
+ }
+
+ /* Map the file MAP_PRIVATE.
+ */
+
+ len = strlen(str);
+ addr = mmap(0, len, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0);
+ if (addr == MAP_FAILED)
+ {
+ error = check_failed(test, "mmap");
+ goto err_close;
+ }
+
+ tmpstr = (char *)addr;
+
+ /* Verify that the string is initially in the mapping.
+ */
+
+ if (strncmp(tmpstr, str, strlen(str)))
+ {
+ fprintf(stderr, "%s: file doesn't have string\n", test);
+ error = 1;
+ goto err_unmap;
+ }
+
+ memset(addr, 0, strlen(str));
+
+ /* Verify that the string has been overwritten in the mapping.
+ */
+
+ for (ii = 0; ii < len; ii++)
+ {
+ if (tmpstr[ii] != 0)
+ {
+ fprintf(stderr, "%s: didn't write to mapping\n", test);
+ error = 1;
+ goto err_unmap;
+ }
+ }
+
+ /* Verify that the file still contains the original string.
+ */
+
+ if (lseek(fd, 0, SEEK_SET) != 0)
+ {
+ error = check_failed(test, "lseek");
+ goto err_unmap;
+ }
+
+ if ((ii = read(fd, tmpbuf, sizeof(tmpbuf))) != len)
+ {
+ fprintf(stderr, "%s: read returned %d, expecting %lu.\n", test, ii,
+ len);
+ error = 1;
+ goto err_unmap;
+ }
+
+ if (strncmp(tmpbuf, str, strlen(str)))
+ {
+ fprintf(stderr, "%s: file was changed by MAP_PRIVATE?!\n", test);
+ error = 1;
+ goto err_unmap;
+ }
+
+ error = 0;
+
+err_unmap:
+ if (munmap(addr, len) < 0)
+ {
+ error = check_failed(test, "munmap");
+ }
+err_close:
+ if (close(fd) < 0)
+ {
+ error = check_failed(test, "close");
+ }
+ if (unlink(tmpfile) < 0)
+ {
+ error = check_failed(test, "unlink");
+ }
+ return error;
+}
+
+DECL_CMD(chk_null)
+{
+ const char *test = argv[0];
+ const char *null = "/dev/null";
+ int fd;
+ int nbytes;
+ char buf[256];
+ int error;
+
+ fd = open(null, O_RDWR, 0600);
+ if (fd < 0)
+ {
+ return check_failed(test, "open");
+ }
+
+ memset(buf, 0xCC, sizeof(buf));
+
+ /* Try writing to /dev/null. Should return buffer size.
+ */
+
+ nbytes = write(fd, buf, sizeof(buf));
+ if (nbytes != sizeof(buf))
+ {
+ error = check_failed(test, "write");
+ goto err_close;
+ }
+
+ /* Try reading from /dev/null. Should return zero.
+ */
+
+ nbytes = read(fd, buf, sizeof(buf));
+ if (nbytes != 0)
+ {
+ error = check_failed(test, "read");
+ goto err_close;
+ }
+
+ error = 0;
+
+err_close:
+ if (close(fd) < 0)
+ {
+ error = check_failed(test, "close");
+ }
+ return error;
+}
+
+DECL_CMD(chk_zero)
+{
+ const char *test = argv[0];
+ void *addr;
+ int fd;
+ const char *zero = "/dev/zero";
+ char buf[256];
+ int nbytes;
+ int error;
+ uint32_t ii;
+ size_t len;
+ unsigned long *lp;
+ unsigned char *cp;
+
+ fd = open(zero, O_RDWR, 0600);
+ if (fd < 0)
+ {
+ return check_failed(test, "open");
+ }
+
+ /* Set buffer to a non-zero value, then read from /dev/zero
+ * and make sure that the buffer is cleared.
+ */
+
+ memset(buf, 0xCC, sizeof(buf));
+
+ nbytes = read(fd, buf, sizeof(buf));
+ if (nbytes != sizeof(buf))
+ {
+ error = check_failed(test, "read");
+ goto err_close;
+ }
+
+ for (ii = 0; ii < sizeof(buf); ii++)
+ {
+ if (buf[ii] != 0)
+ {
+ error = check_failed(test, "verify read");
+ goto err_close;
+ }
+ }
+
+ /* Map /dev/zero and make sure all pages are initially zero.
+ */
+
+ len = 8192 * 5;
+
+ addr = mmap(0, len, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0);
+ if (addr == MAP_FAILED)
+ {
+ error = check_failed(test, "mmap");
+ goto err_close;
+ }
+
+ cp = (unsigned char *)addr;
+ for (ii = 0; ii < len; ii++, cp++)
+ {
+ if (*cp != 0)
+ {
+ error = check_failed(test, "verify mmap zeros");
+ goto err_unmap;
+ }
+ }
+
+ /* ... make sure writes are allowed.
+ */
+
+ lp = (unsigned long *)addr;
+ for (ii = 0; ii < (len / sizeof(*lp)); ii++, lp++)
+ {
+ *lp = ii;
+ }
+
+ lp = (unsigned long *)addr;
+ for (ii = 0; ii < (len / sizeof(*lp)); ii++, lp++)
+ {
+ if (*lp != ii)
+ {
+ error = check_failed(test, "verify map write");
+ goto err_unmap;
+ }
+ }
+
+ error = 0;
+
+err_unmap:
+ if (munmap(addr, len) < 0)
+ {
+ error = check_failed(test, "munmap");
+ }
+err_close:
+ if (close(fd) < 0)
+ {
+ error = check_failed(test, "close");
+ }
+ return error;
+}
+
+DECL_CMD(chk_malloc)
+{
+ const char *test = argv[0];
+ void *addr;
+ int len;
+ int *tmp;
+ uint32_t ii;
+ int error;
+
+ len = 8192 + 128;
+ addr = malloc(len);
+ if (!addr)
+ {
+ return check_failed(test, "malloc");
+ }
+
+ /* Try writing to the memory.
+ */
+ tmp = (int *)addr;
+ for (ii = 0; ii < (len / sizeof(int)); ii++)
+ {
+ *tmp++ = ii;
+ }
+
+ /* Verify what we've written.
+ */
+ tmp = (int *)addr;
+ for (ii = 0; ii < (len / sizeof(int)); ii++)
+ {
+ if (*tmp++ != (int)ii)
+ {
+ fprintf(stderr, "%s: verify failed at 0x%lx\n", test,
+ (unsigned long)tmp);
+ error = 1;
+ goto out_free;
+ }
+ }
+
+ error = 0;
+out_free:
+ free(addr);
+ return error;
+}
+
+DECL_CMD(chk_sbrk)
+{
+ void *oldbrk1, *oldbrk2;
+ const void *brk_failed = (void *)-1;
+ const char *test = argv[0];
+ int len;
+ int *tmp;
+ uint32_t ii;
+
+ /* A length which is not a page multiple, yet a multiple of 8.
+ */
+ len = 8192 * 5 + 128;
+
+ /* Try allocating some memory.
+ */
+ oldbrk1 = sbrk(len);
+ if (oldbrk1 == brk_failed)
+ {
+ return check_failed(test, "sbrk alloc");
+ }
+
+ /* Try writing to the memory.
+ */
+ tmp = (int *)oldbrk1;
+ for (ii = 0; ii < (len / sizeof(int)); ii++)
+ {
+ *tmp++ = ii;
+ }
+
+ /* Try verifying what we wrote.
+ */
+ tmp = (int *)oldbrk1;
+ for (ii = 0; ii < (len / sizeof(int)); ii++)
+ {
+ if (*tmp++ != (int)ii)
+ {
+ fprintf(stderr, "%s: verify failed at 0x%lx\n", test,
+ (unsigned long)tmp);
+ return 1;
+ }
+ }
+
+ /* Try freeing the memory.
+ */
+ oldbrk2 = sbrk(-len);
+ if (oldbrk2 == brk_failed)
+ {
+ return check_failed(test, "sbrk dealloc");
+ }
+
+ /* oldbrk2 should be at least "len" greater than oldbrk1.
+ */
+ if ((unsigned long)oldbrk2 < ((unsigned long)oldbrk1 + len))
+ {
+ fprintf(stderr, "%s: sbrk didn't return old brk??\n", test);
+ return 1;
+ }
+
+ return 0;
+}
+
+DECL_CMD(chk_wrnoent)
+{
+ int fd;
+ int error;
+ int nfd;
+ const char *tmpfile = TMP "/chk_wrnoent";
+ const char *test = argv[0];
+ const char *teststr = "Hello World!";
+ char buf[256];
+
+ /* Verify that file doesn't exist.
+ */
+ if (check_exists(tmpfile))
+ {
+ fprintf(stderr, "%s: tmpfile exists\n", test);
+ return 1;
+ }
+
+ /* Create file.
+ */
+ fd = open(tmpfile, O_CREAT | O_RDWR, 0600);
+ if (fd < 0)
+ {
+ return check_failed(test, "create");
+ }
+
+ /* Unlink file.
+ */
+ error = unlink(tmpfile);
+ if (error < 0)
+ {
+ error = check_failed(test, "unlink");
+ goto out_close;
+ }
+
+ /* Verify that file is gone.
+ */
+ nfd = open(tmpfile, O_RDONLY, 0);
+ if (nfd >= 0)
+ {
+ error = check_failed(test, "open nonexistent");
+ goto out_close;
+ }
+
+ /* Try writing a string to the file and reading it back.
+ */
+ error = write(fd, teststr, strlen(teststr));
+ if (error != (ssize_t)strlen(teststr))
+ {
+ error = check_failed(test, "write teststr");
+ goto out_close;
+ }
+ error = lseek(fd, 0, SEEK_SET);
+ if (error != 0)
+ {
+ error = check_failed(test, "lseek begin");
+ goto out_close;
+ }
+ error = read(fd, buf, strlen(teststr));
+ if (error != (ssize_t)strlen(teststr))
+ {
+ error = check_failed(test, "read teststr");
+ goto out_close;
+ }
+
+ /* Verify string.
+ */
+ if (strncmp(buf, teststr, strlen(teststr)))
+ {
+ fprintf(stderr, "%s: verify string failed\n", test);
+ error = 1;
+ goto out_close;
+ }
+
+ error = 0;
+out_close:
+ if (close(fd) < 0)
+ {
+ error = check_failed(test, "close");
+ }
+ return error;
+}
+
+DECL_CMD(chk_unlink)
+{
+ int fd;
+ int error;
+ int nfd;
+ const char *tmpfile = TMP "/chk_unlink";
+ const char *test = argv[0];
+
+ /* Verify that file doesn't exist.
+ */
+ if (check_exists(tmpfile))
+ {
+ fprintf(stderr, "%s: tmpfile exists\n", test);
+ return 1;
+ }
+
+ /* Create file.
+ */
+ fd = open(tmpfile, O_CREAT | O_RDONLY, 0600);
+ if (fd < 0)
+ {
+ return check_failed(test, "create");
+ }
+
+ /* Unlink file.
+ */
+ error = unlink(tmpfile);
+ if (error < 0)
+ {
+ error = check_failed(test, "unlink");
+ goto out_close;
+ }
+
+ /* Verify that file is gone.
+ */
+ nfd = open(tmpfile, O_RDONLY, 0);
+ if (nfd >= 0)
+ {
+ error = check_failed(test, "open nonexistent");
+ goto out_close;
+ }
+
+ error = 0;
+out_close:
+ if (close(fd) < 0)
+ {
+ error = check_failed(test, "close");
+ }
+ return error;
+}
+
+DECL_CMD(chk_sparse)
+{
+ int fd;
+ const char *tmpfile = TMP "/chk_sparse";
+ const char *test = argv[0];
+ int error;
+ int seek;
+ int len = 5 * 8192;
+ void *map;
+ const char *teststr = "Hello there?";
+ char *map_ch;
+ const char *tmpstr;
+ char buf[256];
+ int ii;
+
+ /* Verify that file doesn't exist.
+ */
+ if (check_exists(tmpfile))
+ {
+ fprintf(stderr, "%s: tmpfile exists\n", test);
+ return 1;
+ }
+
+ /* Create file.
+ */
+ fd = open(tmpfile, O_CREAT | O_RDWR, 0600);
+ if (fd < 0)
+ {
+ return check_failed(test, "create");
+ }
+
+ /* Extend length, so that there's a really big set of zero
+ * blocks.
+ */
+ seek = lseek(fd, len, SEEK_SET);
+ if (seek != len)
+ {
+ error = check_failed(test, "lseek len");
+ goto out_close;
+ }
+ error = write(fd, &fd, 1);
+ if (error < 0)
+ {
+ error = check_failed(test, "write");
+ goto out_close;
+ }
+
+ /* Verify that the first few bytes are zero. This should be
+ * true, since the file should be sparse.
+ */
+ seek = lseek(fd, 0, SEEK_SET);
+ if (seek != 0)
+ {
+ error = check_failed(test, "lseek begin");
+ goto out_close;
+ }
+ error = read(fd, buf, strlen(teststr));
+ if (error != (ssize_t)strlen(teststr))
+ {
+ error = check_failed(test, "read zeros");
+ goto out_close;
+ }
+ for (ii = strlen(teststr), tmpstr = buf; ii; ii--)
+ {
+ if (*tmpstr++)
+ {
+ fprintf(stderr, "%s: verify zeros failed\n", test);
+ error = 1;
+ goto out_close;
+ }
+ }
+
+ /* Map file.
+ */
+ map = mmap(NULL, len, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
+ if (map == MAP_FAILED)
+ {
+ error = check_failed(test, "mmap");
+ goto out_close;
+ }
+
+ /* Write to first page of the mapping, which should be a zero
+ * block.
+ */
+ map_ch = (char *)map;
+ tmpstr = teststr;
+ while (*tmpstr)
+ *map_ch++ = *tmpstr++;
+
+ /* Unmap the file.
+ */
+ if (munmap(map, len) < 0)
+ {
+ error = check_failed(test, "munmap");
+ }
+
+ /* Read from the first page.
+ */
+ seek = lseek(fd, 0, SEEK_SET);
+ if (seek != 0)
+ {
+ error = check_failed(test, "lseek begin");
+ goto out_close;
+ }
+ error = read(fd, buf, strlen(teststr));
+ if (error != (ssize_t)strlen(teststr))
+ {
+ error = check_failed(test, "read teststr");
+ goto out_close;
+ }
+ buf[strlen(teststr)] = 0;
+
+ /* Verify the data.
+ */
+ if (strcmp(teststr, buf))
+ {
+ fprintf(stderr, "%s: verify data failed\n", test);
+ fprintf(stderr, "%s: teststr \"%s\", buf \"%s\"\n", test, teststr, buf);
+ error = 1;
+ goto out_close;
+ }
+
+ error = 0;
+out_close:
+ if (close(fd) < 0)
+ {
+ error = check_failed(test, "close");
+ }
+ if (unlink(tmpfile) < 0)
+ {
+ error = check_failed(test, "unlink");
+ }
+ return error;
+}
+
+static int check_run_one(cmd_t *cmd, ioenv_t *io)
+{
+ int retval;
+ char *argv[2];
+
+ argv[0] = (char *)cmd->cmd_name;
+ argv[1] = NULL;
+
+ fprintf(stdout, "%10s ... ", cmd->cmd_name);
+ fflush(NULL);
+ retval = (*cmd->cmd_func)(1, argv, io);
+ fprintf(stdout, "%s\n", retval ? "FAILED" : "SUCCESS");
+
+ return retval;
+}
+
+DECL_CMD(check)
+{
+ int argn;
+ cmd_t *cmd;
+ int errors;
+
+ if (argc < 2)
+ {
+ fprintf(stderr, "usage: check <test> [...]\n\n");
+
+ fprintf(stderr, "Where <test> is either \"all\" or one of:\n");
+ for (cmd = check_cmds; cmd->cmd_name; cmd++)
+ {
+ fprintf(stderr, "%20s - %s\n", cmd->cmd_name, cmd->cmd_helptext);
+ }
+ fprintf(stderr, "\n");
+ return 1;
+ }
+
+ errors = 0;
+
+ fprintf(stdout, "Running tests:\n");
+
+ if (argc == 2 && !strcmp(argv[1], "all"))
+ {
+ for (cmd = check_cmds; cmd->cmd_name; cmd++)
+ {
+ errors += check_run_one(cmd, io);
+ }
+ return errors;
+ }
+
+ for (argn = 1; argn < argc; argn++)
+ {
+ const char *test;
+
+ test = argv[argn];
+
+ for (cmd = check_cmds; cmd->cmd_name; cmd++)
+ {
+ if (!strcmp(cmd->cmd_name, test))
+ {
+ break;
+ }
+ }
+ if (!cmd->cmd_name)
+ {
+ fprintf(stderr, "Unknown test: %s\n", test);
+ errors++;
+ continue;
+ }
+
+ errors += check_run_one(cmd, io);
+ }
+
+ return errors;
+}
+
+DECL_CMD(env)
+{
+ int i = 0;
+ if (my_envp)
+ {
+ while (my_envp[i])
+ {
+ printf("env: %s\n", my_envp[i++]);
+ }
+ }
+ return 0;
+}
+
+DECL_CMD(sync)
+{
+ sync();
+ return 0;
+}
+
+static int do_cp(ioenv_t *io, const char *cmd, const char *in_file, int in_fd,
+ const char *out_file, int out_fd)
+{
+#define buffer_sz 32768
+
+ static char buffer[buffer_sz];
+ int nbytes_in;
+ int nbytes_out;
+
+ if (is_std_stream(in_fd))
+ {
+ in_fd = io->io_map_fd[in_fd];
+ }
+ if (is_std_stream(out_fd))
+ {
+ out_fd = io->io_map_fd[out_fd];
+ }
+
+ while ((nbytes_in = read(in_fd, buffer, buffer_sz)) > 0)
+ {
+ if ((nbytes_out = write(out_fd, buffer, nbytes_in)) < 0)
+ {
+ fprintf(stderr, "%s: unable to write to %s: %s\n", cmd, out_file,
+ strerror(errno));
+ return 0;
+ }
+ }
+ if (nbytes_in < 0)
+ {
+ fprintf(stderr, "%s: unable to read from %s: %s\n", cmd, in_file,
+ strerror(errno));
+ return 0;
+ }
+ return 1;
+
+#undef buffer_sz
+}
+
+DECL_CMD(cp)
+{
+ const char *src;
+ const char *dest;
+ int src_fd;
+ int dest_fd;
+ int error;
+
+ if (argc != 3)
+ {
+ fprintf(stderr, "usage: cp <src> <dest>\n");
+ return 1;
+ }
+
+ src = argv[1];
+ dest = argv[2];
+
+ src_fd = open(src, O_RDONLY, 0);
+ if (src_fd < 0)
+ {
+ fprintf(stderr, "cp: unable to open %s: %s\n", src, strerror(errno));
+ return 1;
+ }
+
+ dest_fd = open(dest, O_WRONLY | O_CREAT | O_TRUNC, 0666);
+ if (dest_fd < 0)
+ {
+ fprintf(stderr, "cp: unable to open %s: %s\n", dest, strerror(errno));
+ return 1;
+ }
+
+ error = 0;
+ if (!do_cp(io, "cp", src, src_fd, dest, dest_fd))
+ {
+ error = 1;
+ }
+
+ close(src_fd);
+ close(dest_fd);
+ return error;
+}
+
+DECL_CMD(echo)
+{
+ int argn;
+ int out_fd = io->io_map_fd[STDOUT_FILENO];
+ ssize_t error;
+
+ // Note: We use 128 here because it is the size of the line discipline buffer.
+ // I.e., as large as any of the arguments to echo could be.
+#define ECHO_BUF_SIZE 128
+ char buf[ECHO_BUF_SIZE];
+
+ // If *no* arguments are passed to echo, write a single newline.
+ if (argc == 1)
+ {
+ error = write(out_fd, "\n", 1);
+ if (error < 0)
+ {
+ fprintf(stderr, "echo: unable to write `\\n`\n");
+ return error;
+ }
+ }
+
+ // Loop over provided arguments, printing each with a trailing space (except
+ // the final argument, which has a trailing newline)
+ for (argn = 1; argn < argc; argn++)
+ {
+ char *trailing = argn == argc - 1 ? "\n" : " ";
+ snprintf(buf, ECHO_BUF_SIZE, "%s%s", argv[argn], trailing);
+
+ error = write(out_fd, buf, strlen(buf));
+ if (error < 0)
+ {
+ fprintf(stderr, "echo: unable to write `%s`\n", buf);
+ return error;
+ }
+ }
+
+#undef ECHO_BUF_SIZE
+ return 0;
+}
+
+DECL_CMD(cat)
+{
+ const char *file;
+ int argn;
+ int fd;
+ int error;
+
+ if (argc == 1)
+ {
+ return !do_cp(io, "cat", "<stdin>", 0, "<stdout>", 1);
+ }
+
+ error = 0;
+
+ for (argn = 1; argn < argc; argn++)
+ {
+ file = argv[argn];
+ fd = open(file, O_RDONLY, 0);
+ if (fd < 0)
+ {
+ fprintf(stderr, "cat: unable to open %s: %s\n", file,
+ strerror(errno));
+ error = 1;
+ continue;
+ }
+ if (!do_cp(io, "cat", file, fd, "<stdout>", 1))
+ {
+ error = 1;
+ }
+ close(fd);
+ }
+
+ return error;
+}
+
+DECL_CMD(mv)
+{
+ const char *src;
+ const char *dest;
+
+ if (argc != 3)
+ {
+ fprintf(stderr, "usage: mv <src> <dest>\n");
+ return 1;
+ }
+
+ src = argv[1];
+ dest = argv[2];
+
+ if (rename(src, dest) < 0)
+ {
+ fprintf(stderr, "mv: unable to move %s to %s: %s\n", src, dest,
+ strerror(errno));
+ return 1;
+ }
+ return 0;
+}
+
+DECL_CMD(rm)
+{
+ int argn;
+ const char *file;
+ int error = 0;
+
+ if (argc == 1)
+ {
+ fprintf(stderr, "usage: rm <file> [...]\n");
+ return 1;
+ }
+
+ for (argn = 1; argn < argc; argn++)
+ {
+ file = argv[argn];
+ if (unlink(file) < 0)
+ {
+ fprintf(stderr, "rm: unable to remove %s: %s\n", file,
+ strerror(errno));
+ error = 1;
+ }
+ }
+ return error;
+}
+
+DECL_CMD(ln)
+{
+ const char *src;
+ const char *dest;
+
+ if (argc != 3)
+ {
+ fprintf(stderr, "usage: ln <src> <dest>\n");
+ return 1;
+ }
+
+ src = argv[1];
+ dest = argv[2];
+
+ if (link(src, dest) < 0)
+ {
+ fprintf(stderr, "ln: couldn't link %s to %s: %s\n", dest, src,
+ strerror(errno));
+ return 1;
+ }
+ return 0;
+}
+
+DECL_CMD(mkdir)
+{
+ const char *dir;
+
+ if (argc != 2)
+ {
+ fprintf(stderr, "usage: mkdir <directory>\n");
+ return 1;
+ }
+
+ dir = argv[1];
+ if (mkdir(dir, 0777) < 0)
+ {
+ fprintf(stderr, "mkdir: couldn't create %s: %s\n", dir,
+ strerror(errno));
+ return 1;
+ }
+ return 0;
+}
+
+DECL_CMD(clear)
+{
+#define ESC "\x1B"
+ fprintf(stdout, ESC "[H" ESC "[J");
+#undef ESC
+ return 0;
+}
+
+DECL_CMD(rmdir)
+{
+ const char *dir;
+
+ if (argc != 2)
+ {
+ fprintf(stderr, "usage: rmdir <directory>\n");
+ return 1;
+ }
+
+ dir = argv[1];
+ if (rmdir(dir) < 0)
+ {
+ fprintf(stderr, "rmdir: couldn't remove %s: %s\n", dir,
+ strerror(errno));
+ return 1;
+ }
+ return 0;
+}
+
+DECL_CMD(exit)
+{
+ exit(0);
+ return 1;
+}
+
+DECL_CMD(help)
+{
+ cmd_t *cmd;
+
+ fprintf(stdout, "Shell commands:\n");
+
+ for (cmd = builtin_cmds; cmd->cmd_name; cmd++)
+ {
+ fprintf(stdout, "%20s - %s\n", cmd->cmd_name, cmd->cmd_helptext);
+ }
+
+ return 0;
+}
+
+DECL_CMD(cd)
+{
+ const char *dir;
+
+ if (argc > 2)
+ {
+ fprintf(stderr, "usage: cd <dir>\n");
+ return 1;
+ }
+
+ if (argc == 1)
+ {
+ dir = HOME;
+ }
+ else
+ {
+ dir = argv[1];
+ }
+
+ if (chdir(dir) < 0)
+ {
+ fprintf(stderr, "sh: couldn't cd to %s: %s\n", dir, strerror(errno));
+ return 1;
+ }
+ return 0;
+}
+
+DECL_CMD(repeat)
+{
+ long ntimes;
+
+ if (argc < 3)
+ {
+ fprintf(stderr, "usage: repeat <ntimes> command [args ...]\n");
+ return 1;
+ }
+
+ ntimes = strtol(argv[1], NULL, 10);
+ if (ntimes <= 0)
+ {
+ fprintf(stderr, "repeat: <ntimes> must be non-zero\n");
+ return 1;
+ }
+
+ while (ntimes--)
+ {
+ redirect_map_t map;
+ int ii;
+
+ char **new_argv = copy_args(argc - 2, &argv[2]);
+ map.rm_nfds = 0;
+
+ for (ii = 0; ii < 3; ii++)
+ {
+ int fd;
+
+ fd = dup(io->io_map_fd[ii]);
+ if (fd < 0)
+ {
+ fprintf(stderr,
+ "repeat: dup(%d) failed: "
+ "%s\n",
+ io->io_map_fd[ii], strerror(errno));
+ return 1;
+ }
+
+ add_redirect(&map, fd, ii);
+ }
+
+ execute(argc - 2, new_argv, &map);
+
+ free_args(argc - 2, new_argv);
+ }
+
+ return 0;
+}
+
+DECL_CMD(parallel)
+{
+ int i, cmdbegin, ncmds = 0;
+ char **cmd_argvs[32];
+ int cmd_argcs[32];
+ int cmd_pids[32];
+
+ if (argc < 2)
+ {
+ fprintf(stderr,
+ "usage: parallel <cmd1> [args] -- <cmd2> [args] [-- ...]\n");
+ return 1;
+ }
+
+ /* Parse commands, dividing up argv */
+ for (cmdbegin = (i = 1); i < argc; i++)
+ {
+ if (!strcmp(argv[i], "--"))
+ {
+ /* Command delimiter - make sure command non-empty */
+ if (cmdbegin == i)
+ {
+ fprintf(stderr, "empty command\n");
+ return 1;
+ }
+ argv[i] = NULL;
+
+ cmd_argcs[ncmds] = i - cmdbegin;
+ cmd_argvs[ncmds] = &argv[cmdbegin];
+ ncmds++;
+ if (ncmds > 32)
+ {
+ fprintf(stderr, "too many commands\n");
+ return 1;
+ }
+ cmdbegin = i + 1;
+ }
+ }
+ if (cmdbegin == argc)
+ {
+ fprintf(stderr, "empty command\n");
+ return 1;
+ }
+ cmd_argcs[ncmds] = argc - cmdbegin;
+ cmd_argvs[ncmds] = &argv[cmdbegin];
+ ncmds++;
+ if (ncmds > 32)
+ {
+ fprintf(stderr, "too many commands\n");
+ return 1;
+ }
+
+ /* Fork and execute each command */
+ for (i = 0; i < ncmds; i++)
+ {
+ if (0 == (cmd_pids[i] = fork()))
+ {
+ int status, fd, ii;
+ /* Build weird map thing (as in repeat) */
+ redirect_map_t map;
+ map.rm_nfds = 0;
+ for (ii = 0; ii < 3; ii++)
+ {
+ if (0 > (fd = dup(io->io_map_fd[ii])))
+ {
+ exit(1);
+ }
+ add_redirect(&map, fd, ii);
+ }
+ /* Execute and return its status */
+ exit(execute(cmd_argcs[i], cmd_argvs[i], &map));
+ }
+ }
+ /* Wait for each command */
+ int status;
+ for (i = 0; i < ncmds; i++)
+ {
+ wait(&status);
+ }
+ /* Return last status */
+ return status;
+}
+
+DECL_CMD(time)
+{
+ if (argc < 1)
+ {
+ fprintf(stderr, "usage: time [cmd]\n");
+ return 1;
+ }
+ if (argc == 1)
+ {
+ fprintf(stdout, "time: %lu units\n", time(NULL));
+ return 0;
+ }
+
+ redirect_map_t map;
+ ;
+ map.rm_nfds = 0;
+ for (unsigned i = 0; i < 3; i++)
+ {
+ int fd = dup(io->io_map_fd[i]);
+ if (fd < 0)
+ exit(fd);
+ add_redirect(&map, fd, i);
+ }
+
+ time_t start = time(NULL);
+ int ret = execute(argc - 1, &argv[1], &map);
+ time_t end = time(NULL);
+
+ fprintf(stdout, "time: %lu units\n", end - start);
+ return ret;
+}
+
+static int do_redirect(redirect_map_t *map)
+{
+ int ii;
+ int newfd, oldfd;
+
+ for (ii = 0; ii < map->rm_nfds; ii++)
+ {
+ oldfd = map->rm_redir[ii].r_sfd;
+ newfd = map->rm_redir[ii].r_dfd;
+
+ dbg((stderr, "do_redirect: dup2(%d,%d)\n", oldfd, newfd));
+
+ if (dup2(oldfd, newfd) < 0)
+ {
+ fprintf(stderr,
+ "do_redirect: dup2() failed: "
+ "%s\n",
+ strerror(errno));
+ return -1;
+ }
+ close(oldfd);
+ }
+ return 0;
+}
+
+static void cleanup_redirects(redirect_map_t *map)
+{
+ int ii;
+
+ for (ii = 0; ii < map->rm_nfds; ii++)
+ {
+ close(map->rm_redir[ii].r_sfd);
+ }
+}
+
+static void build_ioenv(redirect_map_t *map, ioenv_t *io)
+{
+ int ii;
+
+ /* Map stdin, stdout, stderr to themselves. */
+ for (ii = 0; ii < 3; ii++)
+ {
+ io->io_map_fd[ii] = ii;
+ }
+
+ /* Execute redirection mappings. */
+ for (ii = 0; ii < map->rm_nfds; ii++)
+ {
+ int sfd = map->rm_redir[ii].r_sfd;
+ int dfd = map->rm_redir[ii].r_dfd;
+ if (dfd >= 0 && dfd <= 2)
+ {
+ io->io_map_fd[dfd] = sfd;
+ }
+ }
+}
+
+static void destroy_ioenv(ioenv_t *io) {}
+
+static int builtin_exec(cmd_t *cmd, int argc, char *argv[], ioenv_t *io)
+{
+ return (*cmd->cmd_func)(argc, argv, io);
+}
+
+static int execute(int argc, char *argv[], redirect_map_t *map)
+{
+ int status, pid;
+ cmd_t *cmd;
+
+ for (cmd = builtin_cmds; cmd->cmd_name; cmd++)
+ {
+ if (!strcmp(cmd->cmd_name, argv[0]))
+ {
+ break;
+ }
+ }
+ if (cmd->cmd_name)
+ {
+ ioenv_t io;
+
+ build_ioenv(map, &io);
+ status = builtin_exec(cmd, argc, argv, &io);
+ destroy_ioenv(&io);
+ cleanup_redirects(map);
+ return 0;
+ }
+
+ if (!(pid = fork()))
+ {
+ if (do_redirect(map) < 0)
+ {
+ exit(1);
+ }
+
+ execve(argv[0], argv, my_envp);
+
+ char *search_directories[] = {"/usr/bin/", "/bin/", "/sbin/"};
+ char buf[256];
+
+ for (unsigned i = 0;
+ errno == ENOENT && i < sizeof(search_directories) / sizeof(char *);
+ i++)
+ {
+ snprintf(buf, sizeof(buf), "%s/%s", search_directories[i], argv[0]);
+ execve(buf, argv, my_envp);
+ }
+ if (errno == ENOENT)
+ {
+ fprintf(stderr, "sh: command not found: %s\n", argv[0]);
+ }
+ else
+ {
+ fprintf(stderr, "sh: exec failed for %s: %s\n", argv[0],
+ strerror(errno));
+ }
+ exit(errno);
+ }
+ else
+ {
+ if (0 > pid)
+ {
+ fprintf(stderr, "sh: fork failed errno = %d\n", errno);
+ }
+ }
+
+ cleanup_redirects(map);
+ int ret = wait(&status);
+ if (status == EFAULT)
+ {
+ fprintf(stderr, "sh: child process accessed invalid memory\n");
+ }
+ // free_args(argc, argv);
+
+ return ret;
+}
+
+#define sh_isredirect(ch) ((ch) == '>' || (ch) == '<')
+
+static int parse_redirect_dfd(char *line, char **start_p)
+{
+ char *start;
+
+ start = *start_p;
+
+ if (start == line)
+ {
+ return -1;
+ }
+
+ /* Skip redirect symbol. */
+ *start = 0;
+ start--;
+
+ /* Go backwards, skipping whitespace. */
+ while ((start != line) && isspace(*start))
+ start--;
+ if (start == line)
+ {
+ return -1;
+ }
+
+ /* Go backwards, scanning digits. */
+ while ((start != line) && isdigit(*start))
+ start--;
+ if (!(isspace(*start) || isdigit(*start)))
+ {
+ return -1;
+ }
+
+ /* This is the descriptor number. */
+ *start_p = start;
+ return strtol(start, NULL, 10);
+}
+
+static int redirect_default_fd(int type)
+{
+ if (type == '<')
+ {
+ return 0;
+ }
+ else if (type == '>')
+ {
+ return 1;
+ }
+ else
+ {
+ fprintf(stderr, "redirect_default_fd: Eh?\n");
+ return -1;
+ }
+}
+
+static void add_redirect(redirect_map_t *map, int sfd, int dfd)
+{
+ dbg((stderr, "add_redirect: %d -> %d\n", sfd, dfd));
+ map->rm_redir[map->rm_nfds].r_sfd = sfd;
+ map->rm_redir[map->rm_nfds].r_dfd = dfd;
+ ++map->rm_nfds;
+}
+
+static int parse_redirect_dup(char *line, redirect_map_t *map, int dfd,
+ int mode, char *start, char **end_p)
+{
+ int real_sfd, sfd;
+ char *sfdstr;
+
+ /* Skip whitespace. */
+ while (*start && isspace(*start))
+ start++;
+ if (!*start)
+ {
+ fprintf(stderr, "sh: bad redirect at end of line\n");
+ return -1;
+ }
+
+ sfdstr = start;
+
+ /* Scan digits. */
+ if (!isdigit(*start))
+ {
+ fprintf(stderr, "sh: parse error in dup redirect: 1\n");
+ return -1;
+ }
+ while (*start && isdigit(*start))
+ start++;
+ if (*start && !isspace(*start))
+ {
+ fprintf(stderr, "sh: parse error in dup redirect: 2\n");
+ return -1;
+ }
+
+ /* Got a descriptor. */
+ *start = 0;
+ real_sfd = strtol(sfdstr, NULL, 10);
+
+ dbg((stderr, "redirect_dup: %d -> %d\n", real_sfd, dfd));
+
+ sfd = dup(real_sfd);
+ if (sfd < 0)
+ {
+ fprintf(stderr, "sh: invalid file descriptor: %d\n", real_sfd);
+ return -1;
+ }
+
+ add_redirect(map, sfd, dfd);
+
+ *end_p = start + 1;
+ return 0;
+}
+
+static int parse_redirect_norm(char *line, redirect_map_t *map, int dfd,
+ int mode, char *start, char **end_p)
+{
+ int sfd;
+ char *path;
+
+ /* Skip initial whitespace. */
+ while (*start && isspace(*start))
+ start++;
+ if (!*start)
+ {
+ fprintf(stderr, "sh: bad redirect at end of line\n");
+ return -1;
+ }
+
+ path = start;
+
+ /* Scan pathname. */
+ while (*start && !isspace(*start))
+ start++;
+ *start = 0;
+
+ dbg((stderr, "redirect_norm: %s -> %d\n", path, dfd));
+
+ sfd = open(path, mode, 0666);
+ if (sfd < 0)
+ {
+ fprintf(stderr, "sh: unable to open %s: %s\n", path, strerror(errno));
+ return -1;
+ }
+
+ add_redirect(map, sfd, dfd);
+
+ *end_p = start + 1;
+ return 0;
+}
+
+static int parse_redirects(char *line, redirect_map_t *map)
+{
+ char *tmp;
+
+ map->rm_nfds = 0;
+
+ tmp = line;
+ for (;;)
+ {
+ char *start, *end;
+ int type, dup, append;
+ int mode;
+ int dfd;
+
+ dup = 0;
+ append = 0;
+
+ /* Find first redirect symbol. */
+ while (*tmp && !sh_isredirect(*tmp))
+ tmp++;
+ if (!*tmp)
+ {
+ break;
+ }
+
+ start = tmp;
+ type = *tmp;
+
+ /* Parse the redirect.
+ */
+
+ /* Destination file descriptor.
+ */
+ dfd = parse_redirect_dfd(line, &start);
+ if (dfd < 0)
+ {
+ dfd = redirect_default_fd(type);
+ }
+
+ /* Look for append or dup.
+ */
+ tmp++;
+ if (*tmp == '>')
+ {
+ if (type != '>')
+ {
+ fprintf(stderr, "sh: parse error at %c%c\n", type, *tmp);
+ return -1;
+ }
+ append = 1;
+ tmp++;
+ }
+ if (*tmp == '&')
+ {
+ dup = 1;
+ tmp++;
+ }
+
+ /* Calculate open mode for file.
+ */
+ if (type == '<')
+ {
+ mode = O_RDONLY;
+ }
+ else if (type == '>')
+ {
+ mode = O_WRONLY | O_CREAT;
+ if (append)
+ {
+ mode |= O_APPEND;
+ }
+ else
+ {
+ mode |= O_TRUNC;
+ }
+ }
+ else
+ {
+ fprintf(stderr, "sh: bad type in redirect: %c\n", type);
+ return -1;
+ }
+
+ /* Parse the rest of the redirection.
+ */
+ if (dup)
+ {
+ if (parse_redirect_dup(line, map, dfd, mode, tmp, &end) < 0)
+ {
+ return -1;
+ }
+ }
+ else
+ {
+ if (parse_redirect_norm(line, map, dfd, mode, tmp, &end) < 0)
+ {
+ return -1;
+ }
+ }
+
+ /* Clear the redirect from the string.
+ */
+ while (start < end)
+ *start++ = ' ';
+
+ tmp = end;
+ }
+
+ return 0;
+}
+
+static void parse(char *line)
+{
+ char *argv[ARGV_MAX];
+ int argc;
+ char *tmp;
+ size_t len;
+ redirect_map_t map;
+
+ argc = 0;
+ tmp = line;
+
+ len = strlen(line);
+ if (line[len - 1] == '\n')
+ {
+ line[len - 1] = 0;
+ }
+
+ if (parse_redirects(line, &map) < 0)
+ {
+ return;
+ }
+
+ for (;;)
+ {
+ /* Ignore leading whitespace.
+ */
+ while (*tmp && isspace(*tmp))
+ tmp++;
+ if (!*tmp)
+ {
+ break;
+ }
+
+ argv[argc++] = tmp;
+
+ /* Token is everything up to trailing whitespace.
+ */
+ while (*tmp && !isspace(*tmp))
+ tmp++;
+ if (!*tmp)
+ {
+ break;
+ }
+
+ /* Null-terminate token.
+ */
+ *tmp++ = 0;
+ }
+
+ argv[argc] = NULL;
+
+ if (!argc)
+ {
+ return;
+ }
+
+ execute(argc, argv, &map);
+}
+
+#define LINEBUF_SIZE 1024
+static char buf1[LINEBUF_SIZE] = {NULL};
+static char buf2[LINEBUF_SIZE] = {NULL};
+
+int main(int argc, char *argv[], char *envp[])
+{
+ static char *linebuf = buf1;
+ static char *prev_linebuf = buf2;
+
+ ssize_t nbytes;
+ char prompt[64];
+
+ my_envp = envp;
+
+ snprintf(prompt, sizeof(prompt), "weenix -> ");
+
+ fprintf(stdout, "%s", prompt);
+ fflush(NULL);
+ while ((nbytes = read(0, linebuf, LINEBUF_SIZE)) > 0)
+ {
+ linebuf[nbytes] = 0;
+
+ if (nbytes == 3 && linebuf[0] == '!' && linebuf[1] == '!' &&
+ linebuf[2] == '\n')
+ {
+ fprintf(stdout, "%s\n", prev_linebuf);
+ parse(prev_linebuf);
+ }
+ else
+ {
+ parse(linebuf);
+ char *tmp = linebuf;
+ linebuf = prev_linebuf;
+ prev_linebuf = tmp;
+ }
+ fprintf(stdout, "%s", prompt);
+ fflush(NULL);
+ }
+
+ fprintf(stdout, "exit\n");
+
+#ifdef __static__
+ exit(0);
+#endif
+ return 0;
+}
diff --git a/user/bin/sl.c b/user/bin/sl.c
new file mode 100644
index 0000000..a8f62c7
--- /dev/null
+++ b/user/bin/sl.c
@@ -0,0 +1,502 @@
+/*========================================
+ * sl.c: SL version 5.03
+ * Copyright 1993,1998,2014-2015
+ * Toyoda Masashi
+ * (mtoyoda@acm.org)
+ * Last Modified: 2014/06/03
+ *========================================
+ */
+/* sl version 5.03 : Fix some more compiler warnings. */
+/* by Ryan Jacobs 2015/01/19 */
+/* sl version 5.02 : Fix compiler warnings. */
+/* by Jeff Schwab 2014/06/03 */
+/* sl version 5.01 : removed cursor and handling of IO */
+/* by Chris Seymour 2014/01/03 */
+/* sl version 5.00 : add -c option */
+/* by Toyoda Masashi 2013/05/05 */
+/* sl version 4.00 : add C51, usleep(40000) */
+/* by Toyoda Masashi 2002/12/31 */
+/* sl version 3.03 : add usleep(20000) */
+/* by Toyoda Masashi 1998/07/22 */
+/* sl version 3.02 : D51 flies! Change options. */
+/* by Toyoda Masashi 1993/01/19 */
+/* sl version 3.01 : Wheel turns smoother */
+/* by Toyoda Masashi 1992/12/25 */
+/* sl version 3.00 : Add d(D51) option */
+/* by Toyoda Masashi 1992/12/24 */
+/* sl version 2.02 : Bug fixed.(dust remains in screen) */
+/* by Toyoda Masashi 1992/12/17 */
+/* sl version 2.01 : Smoke run and disappear. */
+/* Change '-a' to accident option. */
+/* by Toyoda Masashi 1992/12/16 */
+/* sl version 2.00 : Add a(all),l(long),F(Fly!) options. */
+/* by Toyoda Masashi 1992/12/15 */
+/* sl version 1.02 : Add turning wheel. */
+/* by Toyoda Masashi 1992/12/14 */
+/* sl version 1.01 : Add more complex smoke. */
+/* by Toyoda Masashi 1992/12/14 */
+/* sl version 1.00 : SL runs vomiting out smoke. */
+/* by Toyoda Masashi 1992/12/11 */
+
+/*========================================
+ * sl.h: SL version 5.02
+ * Copyright 1993,2002,2014
+ * Toyoda Masashi
+ * (mtoyoda@acm.org)
+ * Last Modified: 2014/06/03
+ *========================================
+ */
+#include <stdio.h>
+#include <unistd.h>
+
+#define ERR 0
+#define OK 1
+#define LINES 25
+#define COLS 80
+
+#define D51HEIGHT 10
+#define D51FUNNEL 7
+#define D51LENGTH 83
+#define D51PATTERNS 6
+
+#define D51STR1 " ==== ________ ___________ "
+#define D51STR2 " _D _| |_______/ \\__I_I_____===__|_________| "
+#define D51STR3 " |(_)--- | H\\________/ | | =|___ ___| "
+#define D51STR4 " / | | H | | | | ||_| |_|| "
+#define D51STR5 " | | | H |__--------------------| [___] | "
+#define D51STR6 " | ________|___H__/__|_____/[][]~\\_______| | "
+#define D51STR7 " |/ | |-----------I_____I [][] [] D |=======|__ "
+
+#define D51WHL11 "__/ =| o |=-~~\\ /~~\\ /~~\\ /~~\\ ____Y___________|__ "
+#define D51WHL12 " |/-=|___|= || || || |_____/~\\___/ "
+#define D51WHL13 " \\_/ \\O=====O=====O=====O_/ \\_/ "
+
+#define D51WHL21 "__/ =| o |=-~~\\ /~~\\ /~~\\ /~~\\ ____Y___________|__ "
+#define D51WHL22 " |/-=|___|=O=====O=====O=====O |_____/~\\___/ "
+#define D51WHL23 " \\_/ \\__/ \\__/ \\__/ \\__/ \\_/ "
+
+#define D51WHL31 "__/ =| o |=-O=====O=====O=====O \\ ____Y___________|__ "
+#define D51WHL32 " |/-=|___|= || || || |_____/~\\___/ "
+#define D51WHL33 " \\_/ \\__/ \\__/ \\__/ \\__/ \\_/ "
+
+#define D51WHL41 "__/ =| o |=-~O=====O=====O=====O\\ ____Y___________|__ "
+#define D51WHL42 " |/-=|___|= || || || |_____/~\\___/ "
+#define D51WHL43 " \\_/ \\__/ \\__/ \\__/ \\__/ \\_/ "
+
+#define D51WHL51 "__/ =| o |=-~~\\ /~~\\ /~~\\ /~~\\ ____Y___________|__ "
+#define D51WHL52 " |/-=|___|= O=====O=====O=====O|_____/~\\___/ "
+#define D51WHL53 " \\_/ \\__/ \\__/ \\__/ \\__/ \\_/ "
+
+#define D51WHL61 "__/ =| o |=-~~\\ /~~\\ /~~\\ /~~\\ ____Y___________|__ "
+#define D51WHL62 " |/-=|___|= || || || |_____/~\\___/ "
+#define D51WHL63 " \\_/ \\_O=====O=====O=====O/ \\_/ "
+
+#define D51DEL " "
+
+#define COAL01 " "
+#define COAL02 " "
+#define COAL03 " _________________ "
+#define COAL04 " _| \\_____A "
+#define COAL05 " =| | "
+#define COAL06 " -| | "
+#define COAL07 "__|________________________|_ "
+#define COAL08 "|__________________________|_ "
+#define COAL09 " |_D__D__D_| |_D__D__D_| "
+#define COAL10 " \\_/ \\_/ \\_/ \\_/ "
+
+#define COALDEL " "
+
+#define LOGOHEIGHT 6
+#define LOGOFUNNEL 4
+#define LOGOLENGTH 84
+#define LOGOPATTERNS 6
+
+#define LOGO1 " ++ +------ "
+#define LOGO2 " || |+-+ | "
+#define LOGO3 " /---------|| | | "
+#define LOGO4 " + ======== +-+ | "
+
+#define LWHL11 " _|--O========O~\\-+ "
+#define LWHL12 "//// \\_/ \\_/ "
+
+#define LWHL21 " _|--/O========O\\-+ "
+#define LWHL22 "//// \\_/ \\_/ "
+
+#define LWHL31 " _|--/~O========O-+ "
+#define LWHL32 "//// \\_/ \\_/ "
+
+#define LWHL41 " _|--/~\\------/~\\-+ "
+#define LWHL42 "//// \\_O========O "
+
+#define LWHL51 " _|--/~\\------/~\\-+ "
+#define LWHL52 "//// \\O========O/ "
+
+#define LWHL61 " _|--/~\\------/~\\-+ "
+#define LWHL62 "//// O========O_/ "
+
+#define LCOAL1 "____ "
+#define LCOAL2 "| \\@@@@@@@@@@@ "
+#define LCOAL3 "| \\@@@@@@@@@@@@@_ "
+#define LCOAL4 "| | "
+#define LCOAL5 "|__________________| "
+#define LCOAL6 " (O) (O) "
+
+#define LCAR1 "____________________ "
+#define LCAR2 "| ___ ___ ___ ___ | "
+#define LCAR3 "| |_| |_| |_| |_| | "
+#define LCAR4 "|__________________| "
+#define LCAR5 "|__________________| "
+#define LCAR6 " (O) (O) "
+
+#define DELLN " "
+
+#define C51HEIGHT 11
+#define C51FUNNEL 7
+#define C51LENGTH 87
+#define C51PATTERNS 6
+
+#define C51DEL " "
+
+#define C51STR1 " ___ "
+#define C51STR2 " _|_|_ _ __ __ ___________"
+#define C51STR3 " D__/ \\_(_)___| |__H__| |_____I_Ii_()|_________|"
+#define C51STR4 " | `---' |:: `--' H `--' | |___ ___| "
+#define C51STR5 " +|~~~~~~~~++::~~~~~~~H~~+=====+~~~~~~|~~||_| |_|| "
+#define C51STR6 " || | :: H +=====+ | |:: ...| "
+#define C51STR7 "| | _______|_::-----------------[][]-----| | "
+
+#define C51WH61 "| /~~ || |-----/~~~~\\ /[I_____I][][] --|||_______|__"
+#define C51WH62 "------'|oOo|==[]=- || || | ||=======_|__"
+#define C51WH63 "/~\\____|___|/~\\_| O=======O=======O |__|+-/~\\_| "
+#define C51WH64 "\\_/ \\_/ \\____/ \\____/ \\____/ \\_/ "
+
+#define C51WH51 "| /~~ || |-----/~~~~\\ /[I_____I][][] --|||_______|__"
+#define C51WH52 "------'|oOo|===[]=- || || | ||=======_|__"
+#define C51WH53 "/~\\____|___|/~\\_| O=======O=======O |__|+-/~\\_| "
+#define C51WH54 "\\_/ \\_/ \\____/ \\____/ \\____/ \\_/ "
+
+#define C51WH41 "| /~~ || |-----/~~~~\\ /[I_____I][][] --|||_______|__"
+#define C51WH42 "------'|oOo|===[]=- O=======O=======O | ||=======_|__"
+#define C51WH43 "/~\\____|___|/~\\_| || || |__|+-/~\\_| "
+#define C51WH44 "\\_/ \\_/ \\____/ \\____/ \\____/ \\_/ "
+
+#define C51WH31 "| /~~ || |-----/~~~~\\ /[I_____I][][] --|||_______|__"
+#define C51WH32 "------'|oOo|==[]=- O=======O=======O | ||=======_|__"
+#define C51WH33 "/~\\____|___|/~\\_| || || |__|+-/~\\_| "
+#define C51WH34 "\\_/ \\_/ \\____/ \\____/ \\____/ \\_/ "
+
+#define C51WH21 "| /~~ || |-----/~~~~\\ /[I_____I][][] --|||_______|__"
+#define C51WH22 "------'|oOo|=[]=- O=======O=======O | ||=======_|__"
+#define C51WH23 "/~\\____|___|/~\\_| || || |__|+-/~\\_| "
+#define C51WH24 "\\_/ \\_/ \\____/ \\____/ \\____/ \\_/ "
+
+#define C51WH11 "| /~~ || |-----/~~~~\\ /[I_____I][][] --|||_______|__"
+#define C51WH12 "------'|oOo|=[]=- || || | ||=======_|__"
+#define C51WH13 "/~\\____|___|/~\\_| O=======O=======O |__|+-/~\\_| "
+#define C51WH14 "\\_/ \\_/ \\____/ \\____/ \\____/ \\_/ "
+
+void add_smoke(int y, int x);
+void add_man(int y, int x);
+int add_C51(int x);
+int add_D51(int x);
+int add_sl(int x);
+void option(char *str);
+int my_mvaddstr(int y, int x, char *str);
+
+int ACCIDENT = 0;
+int LOGO = 0;
+int FLY = 0;
+int C51 = 0;
+
+int mvaddch(int y, int x, char c)
+{
+ printf("\033[%d;%dH%c", y, x, c);
+ // fflush(stdout);
+
+ return OK;
+}
+
+int my_mvaddstr(int y, int x, char *str)
+{
+ for (; x < 0; ++x, ++str)
+ if (*str == '\0')
+ return ERR;
+ for (; *str != '\0'; ++str, ++x)
+ if (mvaddch(y, x, *str) == ERR)
+ return ERR;
+ return OK;
+}
+
+void option(char *str)
+{
+ while (*str != '\0')
+ {
+ switch (*str++)
+ {
+ case 'a':
+ ACCIDENT = 1;
+ break;
+ case 'F':
+ FLY = 1;
+ break;
+ case 'l':
+ LOGO = 1;
+ break;
+ case 'c':
+ C51 = 1;
+ break;
+ default:
+ break;
+ }
+ }
+}
+
+int main(int argc, char *argv[])
+{
+ int x, i;
+
+ for (i = 1; i < argc; ++i)
+ {
+ if (*argv[i] == '-')
+ {
+ option(argv[i] + 1);
+ }
+ }
+
+ printf("\033[?25l");
+ // initscr();
+ // signal(SIGINT, SIG_IGN);
+ // noecho();
+ // curs_set(0);
+ // nodelay(stdscr, TRUE);
+ // leaveok(stdscr, TRUE);
+ // scrollok(stdscr, FALSE);
+
+ for (x = COLS - 1;; --x)
+ {
+ if (LOGO == 1)
+ {
+ if (add_sl(x) == ERR)
+ break;
+ }
+ else if (C51 == 1)
+ {
+ if (add_C51(x) == ERR)
+ break;
+ }
+ else
+ {
+ if (add_D51(x) == ERR)
+ break;
+ }
+ // getch();
+ // refresh();
+ fflush(stdout);
+ //size_t x = time(NULL);
+ // while(time(NULL) < x) {__asm__ ( "pause;" );}
+
+ /*for (int i = 0; i < 5000; i++)
+ {
+ __asm__("pause;");
+ }*/
+ usleep(200000);
+
+ printf("\033[2J\033[1;1H");
+ fflush(stdout);
+ }
+
+ printf("\033[?25h");
+ fflush(stdout);
+ // mvcur(0, COLS - 1, LINES - 1, 0);
+ // endwin();
+
+ return 0;
+}
+
+int add_sl(int x)
+{
+ static char *sl[LOGOPATTERNS][LOGOHEIGHT + 1] = {
+ {LOGO1, LOGO2, LOGO3, LOGO4, LWHL11, LWHL12, DELLN},
+ {LOGO1, LOGO2, LOGO3, LOGO4, LWHL21, LWHL22, DELLN},
+ {LOGO1, LOGO2, LOGO3, LOGO4, LWHL31, LWHL32, DELLN},
+ {LOGO1, LOGO2, LOGO3, LOGO4, LWHL41, LWHL42, DELLN},
+ {LOGO1, LOGO2, LOGO3, LOGO4, LWHL51, LWHL52, DELLN},
+ {LOGO1, LOGO2, LOGO3, LOGO4, LWHL61, LWHL62, DELLN}};
+
+ static char *coal[LOGOHEIGHT + 1] = {LCOAL1, LCOAL2, LCOAL3, LCOAL4,
+ LCOAL5, LCOAL6, DELLN};
+
+ static char *car[LOGOHEIGHT + 1] = {LCAR1, LCAR2, LCAR3, LCAR4,
+ LCAR5, LCAR6, DELLN};
+
+ int i, y, py1 = 0, py2 = 0, py3 = 0;
+
+ if (x < -LOGOLENGTH)
+ return ERR;
+ y = LINES / 2 - 3;
+
+ if (FLY == 1)
+ {
+ y = (x / 6) + LINES - (COLS / 6) - LOGOHEIGHT;
+ py1 = 2;
+ py2 = 4;
+ py3 = 6;
+ }
+ for (i = 0; i <= LOGOHEIGHT; ++i)
+ {
+ my_mvaddstr(y + i, x, sl[(LOGOLENGTH + x) / 3 % LOGOPATTERNS][i]);
+ my_mvaddstr(y + i + py1, x + 21, coal[i]);
+ my_mvaddstr(y + i + py2, x + 42, car[i]);
+ my_mvaddstr(y + i + py3, x + 63, car[i]);
+ }
+ if (ACCIDENT == 1)
+ {
+ add_man(y + 1, x + 14);
+ add_man(y + 1 + py2, x + 45);
+ add_man(y + 1 + py2, x + 53);
+ add_man(y + 1 + py3, x + 66);
+ add_man(y + 1 + py3, x + 74);
+ }
+ add_smoke(y - 1, x + LOGOFUNNEL);
+ return OK;
+}
+
+int add_D51(int x)
+{
+ static char *d51[D51PATTERNS][D51HEIGHT + 1] = {
+ {D51STR1, D51STR2, D51STR3, D51STR4, D51STR5, D51STR6, D51STR7,
+ D51WHL11, D51WHL12, D51WHL13, D51DEL},
+ {D51STR1, D51STR2, D51STR3, D51STR4, D51STR5, D51STR6, D51STR7,
+ D51WHL21, D51WHL22, D51WHL23, D51DEL},
+ {D51STR1, D51STR2, D51STR3, D51STR4, D51STR5, D51STR6, D51STR7,
+ D51WHL31, D51WHL32, D51WHL33, D51DEL},
+ {D51STR1, D51STR2, D51STR3, D51STR4, D51STR5, D51STR6, D51STR7,
+ D51WHL41, D51WHL42, D51WHL43, D51DEL},
+ {D51STR1, D51STR2, D51STR3, D51STR4, D51STR5, D51STR6, D51STR7,
+ D51WHL51, D51WHL52, D51WHL53, D51DEL},
+ {D51STR1, D51STR2, D51STR3, D51STR4, D51STR5, D51STR6, D51STR7,
+ D51WHL61, D51WHL62, D51WHL63, D51DEL}};
+ static char *coal[D51HEIGHT + 1] = {COAL01, COAL02, COAL03, COAL04,
+ COAL05, COAL06, COAL07, COAL08,
+ COAL09, COAL10, COALDEL};
+
+ int y, i, dy = 0;
+
+ if (x < -D51LENGTH)
+ return ERR;
+ y = LINES / 2 - 5;
+
+ if (FLY == 1)
+ {
+ y = (x / 7) + LINES - (COLS / 7) - D51HEIGHT;
+ dy = 1;
+ }
+ for (i = 0; i <= D51HEIGHT; ++i)
+ {
+ my_mvaddstr(y + i, x, d51[(D51LENGTH + x) % D51PATTERNS][i]);
+ my_mvaddstr(y + i + dy, x + 53, coal[i]);
+ }
+ if (ACCIDENT == 1)
+ {
+ add_man(y + 2, x + 43);
+ add_man(y + 2, x + 47);
+ }
+ add_smoke(y - 1, x + D51FUNNEL);
+ return OK;
+}
+
+int add_C51(int x)
+{
+ static char *c51[C51PATTERNS][C51HEIGHT + 1] = {
+ {C51STR1, C51STR2, C51STR3, C51STR4, C51STR5, C51STR6, C51STR7, C51WH11,
+ C51WH12, C51WH13, C51WH14, C51DEL},
+ {C51STR1, C51STR2, C51STR3, C51STR4, C51STR5, C51STR6, C51STR7, C51WH21,
+ C51WH22, C51WH23, C51WH24, C51DEL},
+ {C51STR1, C51STR2, C51STR3, C51STR4, C51STR5, C51STR6, C51STR7, C51WH31,
+ C51WH32, C51WH33, C51WH34, C51DEL},
+ {C51STR1, C51STR2, C51STR3, C51STR4, C51STR5, C51STR6, C51STR7, C51WH41,
+ C51WH42, C51WH43, C51WH44, C51DEL},
+ {C51STR1, C51STR2, C51STR3, C51STR4, C51STR5, C51STR6, C51STR7, C51WH51,
+ C51WH52, C51WH53, C51WH54, C51DEL},
+ {C51STR1, C51STR2, C51STR3, C51STR4, C51STR5, C51STR6, C51STR7, C51WH61,
+ C51WH62, C51WH63, C51WH64, C51DEL}};
+ static char *coal[C51HEIGHT + 1] = {COALDEL, COAL01, COAL02, COAL03,
+ COAL04, COAL05, COAL06, COAL07,
+ COAL08, COAL09, COAL10, COALDEL};
+
+ int y, i, dy = 0;
+
+ if (x < -C51LENGTH)
+ return ERR;
+ y = LINES / 2 - 5;
+
+ if (FLY == 1)
+ {
+ y = (x / 7) + LINES - (COLS / 7) - C51HEIGHT;
+ dy = 1;
+ }
+ for (i = 0; i <= C51HEIGHT; ++i)
+ {
+ my_mvaddstr(y + i, x, c51[(C51LENGTH + x) % C51PATTERNS][i]);
+ my_mvaddstr(y + i + dy, x + 55, coal[i]);
+ }
+ if (ACCIDENT == 1)
+ {
+ add_man(y + 3, x + 45);
+ add_man(y + 3, x + 49);
+ }
+ add_smoke(y - 1, x + C51FUNNEL);
+ return OK;
+}
+
+void add_man(int y, int x)
+{
+ static char *man[2][2] = {{"", "(O)"}, {"Help!", "\\O/"}};
+ int i;
+
+ for (i = 0; i < 2; ++i)
+ {
+ my_mvaddstr(y + i, x, man[(LOGOLENGTH + x) / 12 % 2][i]);
+ }
+}
+
+void add_smoke(int y, int x)
+#define SMOKEPTNS 16
+{
+ static struct smokes
+ {
+ int y, x;
+ int ptrn, kind;
+ } S[1000];
+ static int sum = 0;
+ static char *Smoke[2][SMOKEPTNS] = {
+ {"( )", "( )", "( )", "( )", "( )", "( )", "( )", "( )",
+ "()", "()", "O", "O", "O", "O", "O", " "},
+ {"(@@@)", "(@@@@)", "(@@@@)", "(@@@)", "(@@)", "(@@)", "(@)", "(@)",
+ "@@", "@@", "@", "@", "@", "@", "@", " "}};
+ static char *Eraser[SMOKEPTNS] = {
+ " ", " ", " ", " ", " ", " ", " ", " ",
+ " ", " ", " ", " ", " ", " ", " ", " "};
+ static int dy[SMOKEPTNS] = {2, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+ static int dx[SMOKEPTNS] = {-2, -1, 0, 1, 1, 1, 1, 1,
+ 2, 2, 2, 2, 2, 3, 3, 3};
+ int i;
+
+ if (x % 4 == 0)
+ {
+ for (i = 0; i < sum; ++i)
+ {
+ my_mvaddstr(S[i].y, S[i].x, Eraser[S[i].ptrn]);
+ S[i].y -= dy[S[i].ptrn];
+ S[i].x += dx[S[i].ptrn];
+ S[i].ptrn += (S[i].ptrn < SMOKEPTNS - 1) ? 1 : 0;
+ my_mvaddstr(S[i].y, S[i].x, Smoke[S[i].kind][S[i].ptrn]);
+ }
+ my_mvaddstr(y, x, Smoke[sum % 2][0]);
+ S[sum].y = y;
+ S[sum].x = x;
+ S[sum].ptrn = 0;
+ S[sum].kind = sum % 2;
+ sum++;
+ }
+} \ No newline at end of file
diff --git a/user/bin/sleep.c b/user/bin/sleep.c
new file mode 100644
index 0000000..6b0d485
--- /dev/null
+++ b/user/bin/sleep.c
@@ -0,0 +1,44 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#define SECONDS_TO_MICROSECONDS 1000000
+
+void help(int argc, char *argv[])
+{
+ fprintf(stderr, "usage: %s [-u (micrseconds)] <time>\n", argv[0]);
+ exit(1);
+}
+
+int main(int argc, char *argv[])
+{
+ if (argc > 3 || argc == 1)
+ {
+ help(argc, argv);
+ }
+
+ uint64_t tm = 0;
+
+ int use_usec = 0;
+ if (argc > 2)
+ {
+ if (strcmp(argv[1], "-u") == 0)
+ {
+ tm = atoi(argv[2]);
+ use_usec = 1;
+ }
+ else
+ {
+ help(argc, argv);
+ }
+ }
+
+ if (!use_usec)
+ {
+ tm = atoi(argv[1]);
+ tm *= SECONDS_TO_MICROSECONDS;
+ }
+
+ return usleep(tm);
+} \ No newline at end of file
diff --git a/user/bin/stat.c b/user/bin/stat.c
new file mode 100644
index 0000000..b9fe47f
--- /dev/null
+++ b/user/bin/stat.c
@@ -0,0 +1,49 @@
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+const char *modestr(int mode)
+{
+ switch (mode)
+ {
+ case S_IFCHR:
+ return "Character device";
+ case S_IFBLK:
+ return "Block device";
+ case S_IFDIR:
+ return "Directory";
+ case S_IFREG:
+ return "Regular file";
+ case S_IFLNK:
+ return "Symbolic link";
+ default:
+ return "Unknown";
+ }
+}
+
+int main(int argc, char **argv)
+{
+ if (argc != 2)
+ {
+ printf("usage: stat file\n");
+ return 1;
+ }
+
+ stat_t ss;
+ int rc = stat(argv[1], &ss);
+ if (rc == -1)
+ {
+ printf("stat: %s\n", strerror(errno));
+ return 1;
+ }
+
+ printf(" File: %s\n", argv[1]);
+ printf(" Type: %s\n", modestr(ss.st_mode));
+ printf(" Inode: %d\n", ss.st_ino);
+ printf("Link count: %d\n", ss.st_nlink);
+ printf(" Size: %d\n", ss.st_size);
+ printf(" Blocks: %d\n", ss.st_blocks);
+ return 0;
+}
diff --git a/user/bin/uname.c b/user/bin/uname.c
new file mode 100644
index 0000000..942f330
--- /dev/null
+++ b/user/bin/uname.c
@@ -0,0 +1,93 @@
+/*
+ * FILE: uname.c
+ * AUTHOR: kma
+ * DESCR: uname. whee!
+ */
+
+#include <stdio.h>
+#include <sys/utsname.h>
+
+char *TAS =
+ "weenix brought to you by:\n"
+ "1998: jal, dep, kma, mcc, cd, tor\n"
+ "1999: mbe, tc, kma, mahrens, tor\n"
+ "2000: ahl, mahrens, mba, pdemoreu, it\n"
+ "2001: pgriess, pdemoreu, gc3, rmanches, dg\n"
+ "2002: kit, eschrock\n"
+ "2005: afenn\n"
+ "2006: afenn\n"
+ "2007: dap, joel\n"
+ "and the number 0xe\n";
+
+static int doflag(int c);
+
+static struct utsname un;
+
+int main(int argc, char **argv)
+{
+ int ii;
+
+ uname(&un);
+
+ for (ii = 1; ii < argc; ii++)
+ {
+ if (argv[ii][0] == '-')
+ {
+ char *str;
+ str = &argv[ii][1];
+ while (*str)
+ {
+ if (doflag(*str++) < 0)
+ {
+ goto usage;
+ }
+ }
+ }
+ }
+
+ if (argc == 1)
+ {
+ doflag('s');
+ }
+ fprintf(stdout, "\n");
+ return 0;
+
+usage:
+ return 1;
+}
+
+static int doflag(int c)
+{
+ switch (c)
+ {
+ case 'a':
+ printf("%s", TAS);
+ printf("%s ", un.sysname);
+ printf("%s ", un.nodename);
+ printf("%s ", un.release);
+ printf("%s ", un.version);
+ printf("%s ", un.machine);
+ break;
+ case 's':
+ printf("%s", un.sysname);
+ break;
+ case 'n':
+ printf("%s", un.nodename);
+ break;
+ case 'r':
+ printf("%s", un.release);
+ break;
+ case 'T':
+ printf("%s", TAS);
+ break;
+ case 'v':
+ printf("%s", un.version);
+ break;
+ case 'm':
+ printf("%s", un.machine);
+ break;
+ default:
+ return -1;
+ }
+ return 0;
+}
diff --git a/user/hamlet b/user/hamlet
new file mode 100644
index 0000000..4209472
--- /dev/null
+++ b/user/hamlet
@@ -0,0 +1,7882 @@
+ACT I
+SCENE I. Elsinore. A platform before the castle.
+
+ FRANCISCO at his post. Enter to him BERNARDO
+
+BERNARDO
+
+ Who's there?
+
+FRANCISCO
+
+ Nay, answer me: stand, and unfold yourself.
+
+BERNARDO
+
+ Long live the king!
+
+FRANCISCO
+
+ Bernardo?
+
+BERNARDO
+
+ He.
+
+FRANCISCO
+
+ You come most carefully upon your hour.
+
+BERNARDO
+
+ 'Tis now struck twelve; get thee to bed, Francisco.
+
+FRANCISCO
+
+ For this relief much thanks: 'tis bitter cold,
+ And I am sick at heart.
+
+BERNARDO
+
+ Have you had quiet guard?
+
+FRANCISCO
+
+ Not a mouse stirring.
+
+BERNARDO
+
+ Well, good night.
+ If you do meet Horatio and Marcellus,
+ The rivals of my watch, bid them make haste.
+
+FRANCISCO
+
+ I think I hear them. Stand, ho! Who's there?
+
+ Enter HORATIO and MARCELLUS
+
+HORATIO
+
+ Friends to this ground.
+
+MARCELLUS
+
+ And liegemen to the Dane.
+
+FRANCISCO
+
+ Give you good night.
+
+MARCELLUS
+
+ O, farewell, honest soldier:
+ Who hath relieved you?
+
+FRANCISCO
+
+ Bernardo has my place.
+ Give you good night.
+
+ Exit
+
+MARCELLUS
+
+ Holla! Bernardo!
+
+BERNARDO
+
+ Say,
+ What, is Horatio there?
+
+HORATIO
+
+ A piece of him.
+
+BERNARDO
+
+ Welcome, Horatio: welcome, good Marcellus.
+
+MARCELLUS
+
+ What, has this thing appear'd again to-night?
+
+BERNARDO
+
+ I have seen nothing.
+
+MARCELLUS
+
+ Horatio says 'tis but our fantasy,
+ And will not let belief take hold of him
+ Touching this dreaded sight, twice seen of us:
+ Therefore I have entreated him along
+ With us to watch the minutes of this night;
+ That if again this apparition come,
+ He may approve our eyes and speak to it.
+
+HORATIO
+
+ Tush, tush, 'twill not appear.
+
+BERNARDO
+
+ Sit down awhile;
+ And let us once again assail your ears,
+ That are so fortified against our story
+ What we have two nights seen.
+
+HORATIO
+
+ Well, sit we down,
+ And let us hear Bernardo speak of this.
+
+BERNARDO
+
+ Last night of all,
+ When yond same star that's westward from the pole
+ Had made his course to illume that part of heaven
+ Where now it burns, Marcellus and myself,
+ The bell then beating one,--
+
+ Enter Ghost
+
+MARCELLUS
+
+ Peace, break thee off; look, where it comes again!
+
+BERNARDO
+
+ In the same figure, like the king that's dead.
+
+MARCELLUS
+
+ Thou art a scholar; speak to it, Horatio.
+
+BERNARDO
+
+ Looks it not like the king? mark it, Horatio.
+
+HORATIO
+
+ Most like: it harrows me with fear and wonder.
+
+BERNARDO
+
+ It would be spoke to.
+
+MARCELLUS
+
+ Question it, Horatio.
+
+HORATIO
+
+ What art thou that usurp'st this time of night,
+ Together with that fair and warlike form
+ In which the majesty of buried Denmark
+ Did sometimes march? by heaven I charge thee, speak!
+
+MARCELLUS
+
+ It is offended.
+
+BERNARDO
+
+ See, it stalks away!
+
+HORATIO
+
+ Stay! speak, speak! I charge thee, speak!
+
+ Exit Ghost
+
+MARCELLUS
+
+ 'Tis gone, and will not answer.
+
+BERNARDO
+
+ How now, Horatio! you tremble and look pale:
+ Is not this something more than fantasy?
+ What think you on't?
+
+HORATIO
+
+ Before my God, I might not this believe
+ Without the sensible and true avouch
+ Of mine own eyes.
+
+MARCELLUS
+
+ Is it not like the king?
+
+HORATIO
+
+ As thou art to thyself:
+ Such was the very armour he had on
+ When he the ambitious Norway combated;
+ So frown'd he once, when, in an angry parle,
+ He smote the sledded Polacks on the ice.
+ 'Tis strange.
+
+MARCELLUS
+
+ Thus twice before, and jump at this dead hour,
+ With martial stalk hath he gone by our watch.
+
+HORATIO
+
+ In what particular thought to work I know not;
+ But in the gross and scope of my opinion,
+ This bodes some strange eruption to our state.
+
+MARCELLUS
+
+ Good now, sit down, and tell me, he that knows,
+ Why this same strict and most observant watch
+ So nightly toils the subject of the land,
+ And why such daily cast of brazen cannon,
+ And foreign mart for implements of war;
+ Why such impress of shipwrights, whose sore task
+ Does not divide the Sunday from the week;
+ What might be toward, that this sweaty haste
+ Doth make the night joint-labourer with the day:
+ Who is't that can inform me?
+
+HORATIO
+
+ That can I;
+ At least, the whisper goes so. Our last king,
+ Whose image even but now appear'd to us,
+ Was, as you know, by Fortinbras of Norway,
+ Thereto prick'd on by a most emulate pride,
+ Dared to the combat; in which our valiant Hamlet--
+ For so this side of our known world esteem'd him--
+ Did slay this Fortinbras; who by a seal'd compact,
+ Well ratified by law and heraldry,
+ Did forfeit, with his life, all those his lands
+ Which he stood seized of, to the conqueror:
+ Against the which, a moiety competent
+ Was gaged by our king; which had return'd
+ To the inheritance of Fortinbras,
+ Had he been vanquisher; as, by the same covenant,
+ And carriage of the article design'd,
+ His fell to Hamlet. Now, sir, young Fortinbras,
+ Of unimproved mettle hot and full,
+ Hath in the skirts of Norway here and there
+ Shark'd up a list of lawless resolutes,
+ For food and diet, to some enterprise
+ That hath a stomach in't; which is no other--
+ As it doth well appear unto our state--
+ But to recover of us, by strong hand
+ And terms compulsatory, those foresaid lands
+ So by his father lost: and this, I take it,
+ Is the main motive of our preparations,
+ The source of this our watch and the chief head
+ Of this post-haste and romage in the land.
+
+BERNARDO
+
+ I think it be no other but e'en so:
+ Well may it sort that this portentous figure
+ Comes armed through our watch; so like the king
+ That was and is the question of these wars.
+
+HORATIO
+
+ A mote it is to trouble the mind's eye.
+ In the most high and palmy state of Rome,
+ A little ere the mightiest Julius fell,
+ The graves stood tenantless and the sheeted dead
+ Did squeak and gibber in the Roman streets:
+ As stars with trains of fire and dews of blood,
+ Disasters in the sun; and the moist star
+ Upon whose influence Neptune's empire stands
+ Was sick almost to doomsday with eclipse:
+ And even the like precurse of fierce events,
+ As harbingers preceding still the fates
+ And prologue to the omen coming on,
+ Have heaven and earth together demonstrated
+ Unto our climatures and countrymen.--
+ But soft, behold! lo, where it comes again!
+
+ Re-enter Ghost
+ I'll cross it, though it blast me. Stay, illusion!
+ If thou hast any sound, or use of voice,
+ Speak to me:
+ If there be any good thing to be done,
+ That may to thee do ease and grace to me,
+ Speak to me:
+
+ Cock crows
+ If thou art privy to thy country's fate,
+ Which, happily, foreknowing may avoid, O, speak!
+ Or if thou hast uphoarded in thy life
+ Extorted treasure in the womb of earth,
+ For which, they say, you spirits oft walk in death,
+ Speak of it: stay, and speak! Stop it, Marcellus.
+
+MARCELLUS
+
+ Shall I strike at it with my partisan?
+
+HORATIO
+
+ Do, if it will not stand.
+
+BERNARDO
+
+ 'Tis here!
+
+HORATIO
+
+ 'Tis here!
+
+MARCELLUS
+
+ 'Tis gone!
+
+ Exit Ghost
+ We do it wrong, being so majestical,
+ To offer it the show of violence;
+ For it is, as the air, invulnerable,
+ And our vain blows malicious mockery.
+
+BERNARDO
+
+ It was about to speak, when the cock crew.
+
+HORATIO
+
+ And then it started like a guilty thing
+ Upon a fearful summons. I have heard,
+ The cock, that is the trumpet to the morn,
+ Doth with his lofty and shrill-sounding throat
+ Awake the god of day; and, at his warning,
+ Whether in sea or fire, in earth or air,
+ The extravagant and erring spirit hies
+ To his confine: and of the truth herein
+ This present object made probation.
+
+MARCELLUS
+
+ It faded on the crowing of the cock.
+ Some say that ever 'gainst that season comes
+ Wherein our Saviour's birth is celebrated,
+ The bird of dawning singeth all night long:
+ And then, they say, no spirit dares stir abroad;
+ The nights are wholesome; then no planets strike,
+ No fairy takes, nor witch hath power to charm,
+ So hallow'd and so gracious is the time.
+
+HORATIO
+
+ So have I heard and do in part believe it.
+ But, look, the morn, in russet mantle clad,
+ Walks o'er the dew of yon high eastward hill:
+ Break we our watch up; and by my advice,
+ Let us impart what we have seen to-night
+ Unto young Hamlet; for, upon my life,
+ This spirit, dumb to us, will speak to him.
+ Do you consent we shall acquaint him with it,
+ As needful in our loves, fitting our duty?
+
+MARCELLUS
+
+ Let's do't, I pray; and I this morning know
+ Where we shall find him most conveniently.
+
+ Exeunt
+
+SCENE II. A room of state in the castle.
+
+ Enter KING CLAUDIUS, QUEEN GERTRUDE, HAMLET, POLONIUS, LAERTES, VOLTIMAND, CORNELIUS, Lords, and Attendants
+
+KING CLAUDIUS
+
+ Though yet of Hamlet our dear brother's death
+ The memory be green, and that it us befitted
+ To bear our hearts in grief and our whole kingdom
+ To be contracted in one brow of woe,
+ Yet so far hath discretion fought with nature
+ That we with wisest sorrow think on him,
+ Together with remembrance of ourselves.
+ Therefore our sometime sister, now our queen,
+ The imperial jointress to this warlike state,
+ Have we, as 'twere with a defeated joy,--
+ With an auspicious and a dropping eye,
+ With mirth in funeral and with dirge in marriage,
+ In equal scale weighing delight and dole,--
+ Taken to wife: nor have we herein barr'd
+ Your better wisdoms, which have freely gone
+ With this affair along. For all, our thanks.
+ Now follows, that you know, young Fortinbras,
+ Holding a weak supposal of our worth,
+ Or thinking by our late dear brother's death
+ Our state to be disjoint and out of frame,
+ Colleagued with the dream of his advantage,
+ He hath not fail'd to pester us with message,
+ Importing the surrender of those lands
+ Lost by his father, with all bonds of law,
+ To our most valiant brother. So much for him.
+ Now for ourself and for this time of meeting:
+ Thus much the business is: we have here writ
+ To Norway, uncle of young Fortinbras,--
+ Who, impotent and bed-rid, scarcely hears
+ Of this his nephew's purpose,--to suppress
+ His further gait herein; in that the levies,
+ The lists and full proportions, are all made
+ Out of his subject: and we here dispatch
+ You, good Cornelius, and you, Voltimand,
+ For bearers of this greeting to old Norway;
+ Giving to you no further personal power
+ To business with the king, more than the scope
+ Of these delated articles allow.
+ Farewell, and let your haste commend your duty.
+
+CORNELIUS VOLTIMAND
+
+ In that and all things will we show our duty.
+
+KING CLAUDIUS
+
+ We doubt it nothing: heartily farewell.
+
+ Exeunt VOLTIMAND and CORNELIUS
+ And now, Laertes, what's the news with you?
+ You told us of some suit; what is't, Laertes?
+ You cannot speak of reason to the Dane,
+ And loose your voice: what wouldst thou beg, Laertes,
+ That shall not be my offer, not thy asking?
+ The head is not more native to the heart,
+ The hand more instrumental to the mouth,
+ Than is the throne of Denmark to thy father.
+ What wouldst thou have, Laertes?
+
+LAERTES
+
+ My dread lord,
+ Your leave and favour to return to France;
+ From whence though willingly I came to Denmark,
+ To show my duty in your coronation,
+ Yet now, I must confess, that duty done,
+ My thoughts and wishes bend again toward France
+ And bow them to your gracious leave and pardon.
+
+KING CLAUDIUS
+
+ Have you your father's leave? What says Polonius?
+
+LORD POLONIUS
+
+ He hath, my lord, wrung from me my slow leave
+ By laboursome petition, and at last
+ Upon his will I seal'd my hard consent:
+ I do beseech you, give him leave to go.
+
+KING CLAUDIUS
+
+ Take thy fair hour, Laertes; time be thine,
+ And thy best graces spend it at thy will!
+ But now, my cousin Hamlet, and my son,--
+
+HAMLET
+
+ [Aside] A little more than kin, and less than kind.
+
+KING CLAUDIUS
+
+ How is it that the clouds still hang on you?
+
+HAMLET
+
+ Not so, my lord; I am too much i' the sun.
+
+QUEEN GERTRUDE
+
+ Good Hamlet, cast thy nighted colour off,
+ And let thine eye look like a friend on Denmark.
+ Do not for ever with thy vailed lids
+ Seek for thy noble father in the dust:
+ Thou know'st 'tis common; all that lives must die,
+ Passing through nature to eternity.
+
+HAMLET
+
+ Ay, madam, it is common.
+
+QUEEN GERTRUDE
+
+ If it be,
+ Why seems it so particular with thee?
+
+HAMLET
+
+ Seems, madam! nay it is; I know not 'seems.'
+ 'Tis not alone my inky cloak, good mother,
+ Nor customary suits of solemn black,
+ Nor windy suspiration of forced breath,
+ No, nor the fruitful river in the eye,
+ Nor the dejected 'havior of the visage,
+ Together with all forms, moods, shapes of grief,
+ That can denote me truly: these indeed seem,
+ For they are actions that a man might play:
+ But I have that within which passeth show;
+ These but the trappings and the suits of woe.
+
+KING CLAUDIUS
+
+ 'Tis sweet and commendable in your nature, Hamlet,
+ To give these mourning duties to your father:
+ But, you must know, your father lost a father;
+ That father lost, lost his, and the survivor bound
+ In filial obligation for some term
+ To do obsequious sorrow: but to persever
+ In obstinate condolement is a course
+ Of impious stubbornness; 'tis unmanly grief;
+ It shows a will most incorrect to heaven,
+ A heart unfortified, a mind impatient,
+ An understanding simple and unschool'd:
+ For what we know must be and is as common
+ As any the most vulgar thing to sense,
+ Why should we in our peevish opposition
+ Take it to heart? Fie! 'tis a fault to heaven,
+ A fault against the dead, a fault to nature,
+ To reason most absurd: whose common theme
+ Is death of fathers, and who still hath cried,
+ From the first corse till he that died to-day,
+ 'This must be so.' We pray you, throw to earth
+ This unprevailing woe, and think of us
+ As of a father: for let the world take note,
+ You are the most immediate to our throne;
+ And with no less nobility of love
+ Than that which dearest father bears his son,
+ Do I impart toward you. For your intent
+ In going back to school in Wittenberg,
+ It is most retrograde to our desire:
+ And we beseech you, bend you to remain
+ Here, in the cheer and comfort of our eye,
+ Our chiefest courtier, cousin, and our son.
+
+QUEEN GERTRUDE
+
+ Let not thy mother lose her prayers, Hamlet:
+ I pray thee, stay with us; go not to Wittenberg.
+
+HAMLET
+
+ I shall in all my best obey you, madam.
+
+KING CLAUDIUS
+
+ Why, 'tis a loving and a fair reply:
+ Be as ourself in Denmark. Madam, come;
+ This gentle and unforced accord of Hamlet
+ Sits smiling to my heart: in grace whereof,
+ No jocund health that Denmark drinks to-day,
+ But the great cannon to the clouds shall tell,
+ And the king's rouse the heavens all bruit again,
+ Re-speaking earthly thunder. Come away.
+
+ Exeunt all but HAMLET
+
+HAMLET
+
+ O, that this too too solid flesh would melt
+ Thaw and resolve itself into a dew!
+ Or that the Everlasting had not fix'd
+ His canon 'gainst self-slaughter! O God! God!
+ How weary, stale, flat and unprofitable,
+ Seem to me all the uses of this world!
+ Fie on't! ah fie! 'tis an unweeded garden,
+ That grows to seed; things rank and gross in nature
+ Possess it merely. That it should come to this!
+ But two months dead: nay, not so much, not two:
+ So excellent a king; that was, to this,
+ Hyperion to a satyr; so loving to my mother
+ That he might not beteem the winds of heaven
+ Visit her face too roughly. Heaven and earth!
+ Must I remember? why, she would hang on him,
+ As if increase of appetite had grown
+ By what it fed on: and yet, within a month--
+ Let me not think on't--Frailty, thy name is woman!--
+ A little month, or ere those shoes were old
+ With which she follow'd my poor father's body,
+ Like Niobe, all tears:--why she, even she--
+ O, God! a beast, that wants discourse of reason,
+ Would have mourn'd longer--married with my uncle,
+ My father's brother, but no more like my father
+ Than I to Hercules: within a month:
+ Ere yet the salt of most unrighteous tears
+ Had left the flushing in her galled eyes,
+ She married. O, most wicked speed, to post
+ With such dexterity to incestuous sheets!
+ It is not nor it cannot come to good:
+ But break, my heart; for I must hold my tongue.
+
+ Enter HORATIO, MARCELLUS, and BERNARDO
+
+HORATIO
+
+ Hail to your lordship!
+
+HAMLET
+
+ I am glad to see you well:
+ Horatio,--or I do forget myself.
+
+HORATIO
+
+ The same, my lord, and your poor servant ever.
+
+HAMLET
+
+ Sir, my good friend; I'll change that name with you:
+ And what make you from Wittenberg, Horatio? Marcellus?
+
+MARCELLUS
+
+ My good lord--
+
+HAMLET
+
+ I am very glad to see you. Good even, sir.
+ But what, in faith, make you from Wittenberg?
+
+HORATIO
+
+ A truant disposition, good my lord.
+
+HAMLET
+
+ I would not hear your enemy say so,
+ Nor shall you do mine ear that violence,
+ To make it truster of your own report
+ Against yourself: I know you are no truant.
+ But what is your affair in Elsinore?
+ We'll teach you to drink deep ere you depart.
+
+HORATIO
+
+ My lord, I came to see your father's funeral.
+
+HAMLET
+
+ I pray thee, do not mock me, fellow-student;
+ I think it was to see my mother's wedding.
+
+HORATIO
+
+ Indeed, my lord, it follow'd hard upon.
+
+HAMLET
+
+ Thrift, thrift, Horatio! the funeral baked meats
+ Did coldly furnish forth the marriage tables.
+ Would I had met my dearest foe in heaven
+ Or ever I had seen that day, Horatio!
+ My father!--methinks I see my father.
+
+HORATIO
+
+ Where, my lord?
+
+HAMLET
+
+ In my mind's eye, Horatio.
+
+HORATIO
+
+ I saw him once; he was a goodly king.
+
+HAMLET
+
+ He was a man, take him for all in all,
+ I shall not look upon his like again.
+
+HORATIO
+
+ My lord, I think I saw him yesternight.
+
+HAMLET
+
+ Saw? who?
+
+HORATIO
+
+ My lord, the king your father.
+
+HAMLET
+
+ The king my father!
+
+HORATIO
+
+ Season your admiration for awhile
+ With an attent ear, till I may deliver,
+ Upon the witness of these gentlemen,
+ This marvel to you.
+
+HAMLET
+
+ For God's love, let me hear.
+
+HORATIO
+
+ Two nights together had these gentlemen,
+ Marcellus and Bernardo, on their watch,
+ In the dead vast and middle of the night,
+ Been thus encounter'd. A figure like your father,
+ Armed at point exactly, id-a-pe,
+ Appears before them, and with solemn march
+ Goes slow and stately by them: thrice he walk'd
+ By their oppress'd and fear-surprised eyes,
+ Within his truncheon's length; whilst they, distilled
+ Almost to jelly with the act of fear,
+ Stand dumb and speak not to him. This to me
+ In dreadful secrecy impart they did;
+ And I with them the third night kept the watch;
+ Where, as they had deliver'd, both in time,
+ Form of the thing, each word made true and good,
+ The apparition comes: I knew your father;
+ These hands are not more like.
+
+HAMLET
+
+ But where was this?
+
+MARCELLUS
+
+ My lord, upon the platform where we watch'd.
+
+HAMLET
+
+ Did you not speak to it?
+
+HORATIO
+
+ My lord, I did;
+ But answer made it none: yet once methought
+ It lifted up its head and did address
+ Itself to motion, like as it would speak;
+ But even then the morning cock crew loud,
+ And at the sound it shrunk in haste away,
+ And vanish'd from our sight.
+
+HAMLET
+
+ 'Tis very strange.
+
+HORATIO
+
+ As I do live, my honour'd lord, 'tis true;
+ And we did think it writ down in our duty
+ To let you know of it.
+
+HAMLET
+
+ Indeed, indeed, sirs, but this troubles me.
+ Hold you the watch to-night?
+
+MARCELLUS BERNARDO
+
+ We do, my lord.
+
+HAMLET
+
+ Arm'd, say you?
+
+MARCELLUS BERNARDO
+
+ Arm'd, my lord.
+
+HAMLET
+
+ From top to toe?
+
+MARCELLUS BERNARDO
+
+ My lord, from head to foot.
+
+HAMLET
+
+ Then saw you not his face?
+
+HORATIO
+
+ O, yes, my lord; he wore his beaver up.
+
+HAMLET
+
+ What, look'd he frowningly?
+
+HORATIO
+
+ A countenance more in sorrow than in anger.
+
+HAMLET
+
+ Pale or red?
+
+HORATIO
+
+ Nay, very pale.
+
+HAMLET
+
+ And fix'd his eyes upon you?
+
+HORATIO
+
+ Most constantly.
+
+HAMLET
+
+ I would I had been there.
+
+HORATIO
+
+ It would have much amazed you.
+
+HAMLET
+
+ Very like, very like. Stay'd it long?
+
+HORATIO
+
+ While one with moderate haste might tell a hundred.
+
+MARCELLUS BERNARDO
+
+ Longer, longer.
+
+HORATIO
+
+ Not when I saw't.
+
+HAMLET
+
+ His beard was grizzled--no?
+
+HORATIO
+
+ It was, as I have seen it in his life,
+ A sable silver'd.
+
+HAMLET
+
+ I will watch to-night;
+ Perchance 'twill walk again.
+
+HORATIO
+
+ I warrant it will.
+
+HAMLET
+
+ If it assume my noble father's person,
+ I'll speak to it, though hell itself should gape
+ And bid me hold my peace. I pray you all,
+ If you have hitherto conceal'd this sight,
+ Let it be tenable in your silence still;
+ And whatsoever else shall hap to-night,
+ Give it an understanding, but no tongue:
+ I will requite your loves. So, fare you well:
+ Upon the platform, 'twixt eleven and twelve,
+ I'll visit you.
+
+All
+
+ Our duty to your honour.
+
+HAMLET
+
+ Your loves, as mine to you: farewell.
+
+ Exeunt all but HAMLET
+ My father's spirit in arms! all is not well;
+ I doubt some foul play: would the night were come!
+ Till then sit still, my soul: foul deeds will rise,
+ Though all the earth o'erwhelm them, to men's eyes.
+
+ Exit
+
+SCENE III. A room in Polonius' house.
+
+ Enter LAERTES and OPHELIA
+
+LAERTES
+
+ My necessaries are embark'd: farewell:
+ And, sister, as the winds give benefit
+ And convoy is assistant, do not sleep,
+ But let me hear from you.
+
+OPHELIA
+
+ Do you doubt that?
+
+LAERTES
+
+ For Hamlet and the trifling of his favour,
+ Hold it a fashion and a toy in blood,
+ A violet in the youth of primy nature,
+ Forward, not permanent, sweet, not lasting,
+ The perfume and suppliance of a minute; No more.
+
+OPHELIA
+
+ No more but so?
+
+LAERTES
+
+ Think it no more;
+ For nature, crescent, does not grow alone
+ In thews and bulk, but, as this temple waxes,
+ The inward service of the mind and soul
+ Grows wide withal. Perhaps he loves you now,
+ And now no soil nor cautel doth besmirch
+ The virtue of his will: but you must fear,
+ His greatness weigh'd, his will is not his own;
+ For he himself is subject to his birth:
+ He may not, as unvalued persons do,
+ Carve for himself; for on his choice depends
+ The safety and health of this whole state;
+ And therefore must his choice be circumscribed
+ Unto the voice and yielding of that body
+ Whereof he is the head. Then if he says he loves you,
+ It fits your wisdom so far to believe it
+ As he in his particular act and place
+ May give his saying deed; which is no further
+ Than the main voice of Denmark goes withal.
+ Then weigh what loss your honour may sustain,
+ If with too credent ear you list his songs,
+ Or lose your heart, or your chaste treasure open
+ To his unmaster'd importunity.
+ Fear it, Ophelia, fear it, my dear sister,
+ And keep you in the rear of your affection,
+ Out of the shot and danger of desire.
+ The chariest maid is prodigal enough,
+ If she unmask her beauty to the moon:
+ Virtue itself 'scapes not calumnious strokes:
+ The canker galls the infants of the spring,
+ Too oft before their buttons be disclosed,
+ And in the morn and liquid dew of youth
+ Contagious blastments are most imminent.
+ Be wary then; best safety lies in fear:
+ Youth to itself rebels, though none else near.
+
+OPHELIA
+
+ I shall the effect of this good lesson keep,
+ As watchman to my heart. But, good my brother,
+ Do not, as some ungracious pastors do,
+ Show me the steep and thorny way to heaven;
+ Whiles, like a puff'd and reckless libertine,
+ Himself the primrose path of dalliance treads,
+ And recks not his own rede.
+
+LAERTES
+
+ O, fear me not.
+ I stay too long: but here my father comes.
+
+ Enter POLONIUS
+ A double blessing is a double grace,
+ Occasion smiles upon a second leave.
+
+LORD POLONIUS
+
+ Yet here, Laertes! aboard, aboard, for shame!
+ The wind sits in the shoulder of your sail,
+ And you are stay'd for. There; my blessing with thee!
+ And these few precepts in thy memory
+ See thou character. Give thy thoughts no tongue,
+ Nor any unproportioned thought his act.
+ Be thou familiar, but by no means vulgar.
+ Those friends thou hast, and their adoption tried,
+ Grapple them to thy soul with hoops of steel;
+ But do not dull thy palm with entertainment
+ Of each new-hatch'd, unfledged comrade. Beware
+ Of entrance to a quarrel, but being in,
+ Bear't that the opposed may beware of thee.
+ Give every man thy ear, but few thy voice;
+ Take each man's censure, but reserve thy judgment.
+ Costly thy habit as thy purse can buy,
+ But not express'd in fancy; rich, not gaudy;
+ For the apparel oft proclaims the man,
+ And they in France of the best rank and station
+ Are of a most select and generous chief in that.
+ Neither a borrower nor a lender be;
+ For loan oft loses both itself and friend,
+ And borrowing dulls the edge of husbandry.
+ This above all: to thine ownself be true,
+ And it must follow, as the night the day,
+ Thou canst not then be false to any man.
+ Farewell: my blessing season this in thee!
+
+LAERTES
+
+ Most humbly do I take my leave, my lord.
+
+LORD POLONIUS
+
+ The time invites you; go; your servants tend.
+
+LAERTES
+
+ Farewell, Ophelia; and remember well
+ What I have said to you.
+
+OPHELIA
+
+ 'Tis in my memory lock'd,
+ And you yourself shall keep the key of it.
+
+LAERTES
+
+ Farewell.
+
+ Exit
+
+LORD POLONIUS
+
+ What is't, Ophelia, be hath said to you?
+
+OPHELIA
+
+ So please you, something touching the Lord Hamlet.
+
+LORD POLONIUS
+
+ Marry, well bethought:
+ 'Tis told me, he hath very oft of late
+ Given private time to you; and you yourself
+ Have of your audience been most free and bounteous:
+ If it be so, as so 'tis put on me,
+ And that in way of caution, I must tell you,
+ You do not understand yourself so clearly
+ As it behoves my daughter and your honour.
+ What is between you? give me up the truth.
+
+OPHELIA
+
+ He hath, my lord, of late made many tenders
+ Of his affection to me.
+
+LORD POLONIUS
+
+ Affection! pooh! you speak like a green girl,
+ Unsifted in such perilous circumstance.
+ Do you believe his tenders, as you call them?
+
+OPHELIA
+
+ I do not know, my lord, what I should think.
+
+LORD POLONIUS
+
+ Marry, I'll teach you: think yourself a baby;
+ That you have ta'en these tenders for true pay,
+ Which are not sterling. Tender yourself more dearly;
+ Or--not to crack the wind of the poor phrase,
+ Running it thus--you'll tender me a fool.
+
+OPHELIA
+
+ My lord, he hath importuned me with love
+ In honourable fashion.
+
+LORD POLONIUS
+
+ Ay, fashion you may call it; go to, go to.
+
+OPHELIA
+
+ And hath given countenance to his speech, my lord,
+ With almost all the holy vows of heaven.
+
+LORD POLONIUS
+
+ Ay, springes to catch woodcocks. I do know,
+ When the blood burns, how prodigal the soul
+ Lends the tongue vows: these blazes, daughter,
+ Giving more light than heat, extinct in both,
+ Even in their promise, as it is a-making,
+ You must not take for fire. From this time
+ Be somewhat scanter of your maiden presence;
+ Set your entreatments at a higher rate
+ Than a command to parley. For Lord Hamlet,
+ Believe so much in him, that he is young
+ And with a larger tether may he walk
+ Than may be given you: in few, Ophelia,
+ Do not believe his vows; for they are brokers,
+ Not of that dye which their investments show,
+ But mere implorators of unholy suits,
+ Breathing like sanctified and pious bawds,
+ The better to beguile. This is for all:
+ I would not, in plain terms, from this time forth,
+ Have you so slander any moment leisure,
+ As to give words or talk with the Lord Hamlet.
+ Look to't, I charge you: come your ways.
+
+OPHELIA
+
+ I shall obey, my lord.
+
+ Exeunt
+
+SCENE IV. The platform.
+
+ Enter HAMLET, HORATIO, and MARCELLUS
+
+HAMLET
+
+ The air bites shrewdly; it is very cold.
+
+HORATIO
+
+ It is a nipping and an eager air.
+
+HAMLET
+
+ What hour now?
+
+HORATIO
+
+ I think it lacks of twelve.
+
+HAMLET
+
+ No, it is struck.
+
+HORATIO
+
+ Indeed? I heard it not: then it draws near the season
+ Wherein the spirit held his wont to walk.
+
+ A flourish of trumpets, and ordnance shot off, within
+ What does this mean, my lord?
+
+HAMLET
+
+ The king doth wake to-night and takes his rouse,
+ Keeps wassail, and the swaggering up-spring reels;
+ And, as he drains his draughts of Rhenish down,
+ The kettle-drum and trumpet thus bray out
+ The triumph of his pledge.
+
+HORATIO
+
+ Is it a custom?
+
+HAMLET
+
+ Ay, marry, is't:
+ But to my mind, though I am native here
+ And to the manner born, it is a custom
+ More honour'd in the breach than the observance.
+ This heavy-headed revel east and west
+ Makes us traduced and tax'd of other nations:
+ They clepe us drunkards, and with swinish phrase
+ Soil our addition; and indeed it takes
+ From our achievements, though perform'd at height,
+ The pith and marrow of our attribute.
+ So, oft it chances in particular men,
+ That for some vicious mole of nature in them,
+ As, in their birth--wherein they are not guilty,
+ Since nature cannot choose his origin--
+ By the o'ergrowth of some complexion,
+ Oft breaking down the pales and forts of reason,
+ Or by some habit that too much o'er-leavens
+ The form of plausive manners, that these men,
+ Carrying, I say, the stamp of one defect,
+ Being nature's livery, or fortune's star,--
+ Their virtues else--be they as pure as grace,
+ As infinite as man may undergo--
+ Shall in the general censure take corruption
+ From that particular fault: the dram of eale
+ Doth all the noble substance of a doubt
+ To his own scandal.
+
+HORATIO
+
+ Look, my lord, it comes!
+
+ Enter Ghost
+
+HAMLET
+
+ Angels and ministers of grace defend us!
+ Be thou a spirit of health or goblin damn'd,
+ Bring with thee airs from heaven or blasts from hell,
+ Be thy intents wicked or charitable,
+ Thou comest in such a questionable shape
+ That I will speak to thee: I'll call thee Hamlet,
+ King, father, royal Dane: O, answer me!
+ Let me not burst in ignorance; but tell
+ Why thy canonized bones, hearsed in death,
+ Have burst their cerements; why the sepulchre,
+ Wherein we saw thee quietly inurn'd,
+ Hath oped his ponderous and marble jaws,
+ To cast thee up again. What may this mean,
+ That thou, dead corse, again in complete steel
+ Revisit'st thus the glimpses of the moon,
+ Making night hideous; and we fools of nature
+ So horridly to shake our disposition
+ With thoughts beyond the reaches of our souls?
+ Say, why is this? wherefore? what should we do?
+
+ Ghost beckons HAMLET
+
+HORATIO
+
+ It beckons you to go away with it,
+ As if it some impartment did desire
+ To you alone.
+
+MARCELLUS
+
+ Look, with what courteous action
+ It waves you to a more removed ground:
+ But do not go with it.
+
+HORATIO
+
+ No, by no means.
+
+HAMLET
+
+ It will not speak; then I will follow it.
+
+HORATIO
+
+ Do not, my lord.
+
+HAMLET
+
+ Why, what should be the fear?
+ I do not set my life in a pin's fee;
+ And for my soul, what can it do to that,
+ Being a thing immortal as itself?
+ It waves me forth again: I'll follow it.
+
+HORATIO
+
+ What if it tempt you toward the flood, my lord,
+ Or to the dreadful summit of the cliff
+ That beetles o'er his base into the sea,
+ And there assume some other horrible form,
+ Which might deprive your sovereignty of reason
+ And draw you into madness? think of it:
+ The very place puts toys of desperation,
+ Without more motive, into every brain
+ That looks so many fathoms to the sea
+ And hears it roar beneath.
+
+HAMLET
+
+ It waves me still.
+ Go on; I'll follow thee.
+
+MARCELLUS
+
+ You shall not go, my lord.
+
+HAMLET
+
+ Hold off your hands.
+
+HORATIO
+
+ Be ruled; you shall not go.
+
+HAMLET
+
+ My fate cries out,
+ And makes each petty artery in this body
+ As hardy as the Nemean lion's nerve.
+ Still am I call'd. Unhand me, gentlemen.
+ By heaven, I'll make a ghost of him that lets me!
+ I say, away! Go on; I'll follow thee.
+
+ Exeunt Ghost and HAMLET
+
+HORATIO
+
+ He waxes desperate with imagination.
+
+MARCELLUS
+
+ Let's follow; 'tis not fit thus to obey him.
+
+HORATIO
+
+ Have after. To what issue will this come?
+
+MARCELLUS
+
+ Something is rotten in the state of Denmark.
+
+HORATIO
+
+ Heaven will direct it.
+
+MARCELLUS
+
+ Nay, let's follow him.
+
+ Exeunt
+
+SCENE V. Another part of the platform.
+
+ Enter GHOST and HAMLET
+
+HAMLET
+
+ Where wilt thou lead me? speak; I'll go no further.
+
+Ghost
+
+ Mark me.
+
+HAMLET
+
+ I will.
+
+Ghost
+
+ My hour is almost come,
+ When I to sulphurous and tormenting flames
+ Must render up myself.
+
+HAMLET
+
+ Alas, poor ghost!
+
+Ghost
+
+ Pity me not, but lend thy serious hearing
+ To what I shall unfold.
+
+HAMLET
+
+ Speak; I am bound to hear.
+
+Ghost
+
+ So art thou to revenge, when thou shalt hear.
+
+HAMLET
+
+ What?
+
+Ghost
+
+ I am thy father's spirit,
+ Doom'd for a certain term to walk the night,
+ And for the day confined to fast in fires,
+ Till the foul crimes done in my days of nature
+ Are burnt and purged away. But that I am forbid
+ To tell the secrets of my prison-house,
+ I could a tale unfold whose lightest word
+ Would harrow up thy soul, freeze thy young blood,
+ Make thy two eyes, like stars, start from their spheres,
+ Thy knotted and combined locks to part
+ And each particular hair to stand on end,
+ Like quills upon the fretful porpentine:
+ But this eternal blazon must not be
+ To ears of flesh and blood. List, list, O, list!
+ If thou didst ever thy dear father love--
+
+HAMLET
+
+ O God!
+
+Ghost
+
+ Revenge his foul and most unnatural murder.
+
+HAMLET
+
+ Murder!
+
+Ghost
+
+ Murder most foul, as in the best it is;
+ But this most foul, strange and unnatural.
+
+HAMLET
+
+ Haste me to know't, that I, with wings as swift
+ As meditation or the thoughts of love,
+ May sweep to my revenge.
+
+Ghost
+
+ I find thee apt;
+ And duller shouldst thou be than the fat weed
+ That roots itself in ease on Lethe wharf,
+ Wouldst thou not stir in this. Now, Hamlet, hear:
+ 'Tis given out that, sleeping in my orchard,
+ A serpent stung me; so the whole ear of Denmark
+ Is by a forged process of my death
+ Rankly abused: but know, thou noble youth,
+ The serpent that did sting thy father's life
+ Now wears his crown.
+
+HAMLET
+
+ O my prophetic soul! My uncle!
+
+Ghost
+
+ Ay, that incestuous, that adulterate beast,
+ With witchcraft of his wit, with traitorous gifts,--
+ O wicked wit and gifts, that have the power
+ So to seduce!--won to his shameful lust
+ The will of my most seeming-virtuous queen:
+ O Hamlet, what a falling-off was there!
+ From me, whose love was of that dignity
+ That it went hand in hand even with the vow
+ I made to her in marriage, and to decline
+ Upon a wretch whose natural gifts were poor
+ To those of mine!
+ But virtue, as it never will be moved,
+ Though lewdness court it in a shape of heaven,
+ So lust, though to a radiant angel link'd,
+ Will sate itself in a celestial bed,
+ And prey on garbage.
+ But, soft! methinks I scent the morning air;
+ Brief let me be. Sleeping within my orchard,
+ My custom always of the afternoon,
+ Upon my secure hour thy uncle stole,
+ With juice of cursed hebenon in a vial,
+ And in the porches of my ears did pour
+ The leperous distilment; whose effect
+ Holds such an enmity with blood of man
+ That swift as quicksilver it courses through
+ The natural gates and alleys of the body,
+ And with a sudden vigour doth posset
+ And curd, like eager droppings into milk,
+ The thin and wholesome blood: so did it mine;
+ And a most instant tetter bark'd about,
+ Most lazar-like, with vile and loathsome crust,
+ All my smooth body.
+ Thus was I, sleeping, by a brother's hand
+ Of life, of crown, of queen, at once dispatch'd:
+ Cut off even in the blossoms of my sin,
+ Unhousel'd, disappointed, unanel'd,
+ No reckoning made, but sent to my account
+ With all my imperfections on my head:
+ O, horrible! O, horrible! most horrible!
+ If thou hast nature in thee, bear it not;
+ Let not the royal bed of Denmark be
+ A couch for luxury and damned incest.
+ But, howsoever thou pursuest this act,
+ Taint not thy mind, nor let thy soul contrive
+ Against thy mother aught: leave her to heaven
+ And to those thorns that in her bosom lodge,
+ To prick and sting her. Fare thee well at once!
+ The glow-worm shows the matin to be near,
+ And 'gins to pale his uneffectual fire:
+ Adieu, adieu! Hamlet, remember me.
+
+ Exit
+
+HAMLET
+
+ O all you host of heaven! O earth! what else?
+ And shall I couple hell? O, fie! Hold, hold, my heart;
+ And you, my sinews, grow not instant old,
+ But bear me stiffly up. Remember thee!
+ Ay, thou poor ghost, while memory holds a seat
+ In this distracted globe. Remember thee!
+ Yea, from the table of my memory
+ I'll wipe away all trivial fond records,
+ All saws of books, all forms, all pressures past,
+ That youth and observation copied there;
+ And thy commandment all alone shall live
+ Within the book and volume of my brain,
+ Unmix'd with baser matter: yes, by heaven!
+ O most pernicious woman!
+ O villain, villain, smiling, damned villain!
+ My tables,--meet it is I set it down,
+ That one may smile, and smile, and be a villain;
+ At least I'm sure it may be so in Denmark:
+
+ Writing
+ So, uncle, there you are. Now to my word;
+ It is 'Adieu, adieu! remember me.'
+ I have sworn 't.
+
+MARCELLUS HORATIO
+
+ [Within] My lord, my lord,--
+
+MARCELLUS
+
+ [Within] Lord Hamlet,--
+
+HORATIO
+
+ [Within] Heaven secure him!
+
+HAMLET
+
+ So be it!
+
+HORATIO
+
+ [Within] Hillo, ho, ho, my lord!
+
+HAMLET
+
+ Hillo, ho, ho, boy! come, bird, come.
+
+ Enter HORATIO and MARCELLUS
+
+MARCELLUS
+
+ How is't, my noble lord?
+
+HORATIO
+
+ What news, my lord?
+
+HAMLET
+
+ O, wonderful!
+
+HORATIO
+
+ Good my lord, tell it.
+
+HAMLET
+
+ No; you'll reveal it.
+
+HORATIO
+
+ Not I, my lord, by heaven.
+
+MARCELLUS
+
+ Nor I, my lord.
+
+HAMLET
+
+ How say you, then; would heart of man once think it?
+ But you'll be secret?
+
+HORATIO MARCELLUS
+
+ Ay, by heaven, my lord.
+
+HAMLET
+
+ There's ne'er a villain dwelling in all Denmark
+ But he's an arrant knave.
+
+HORATIO
+
+ There needs no ghost, my lord, come from the grave
+ To tell us this.
+
+HAMLET
+
+ Why, right; you are i' the right;
+ And so, without more circumstance at all,
+ I hold it fit that we shake hands and part:
+ You, as your business and desire shall point you;
+ For every man has business and desire,
+ Such as it is; and for mine own poor part,
+ Look you, I'll go pray.
+
+HORATIO
+
+ These are but wild and whirling words, my lord.
+
+HAMLET
+
+ I'm sorry they offend you, heartily;
+ Yes, 'faith heartily.
+
+HORATIO
+
+ There's no offence, my lord.
+
+HAMLET
+
+ Yes, by Saint Patrick, but there is, Horatio,
+ And much offence too. Touching this vision here,
+ It is an honest ghost, that let me tell you:
+ For your desire to know what is between us,
+ O'ermaster 't as you may. And now, good friends,
+ As you are friends, scholars and soldiers,
+ Give me one poor request.
+
+HORATIO
+
+ What is't, my lord? we will.
+
+HAMLET
+
+ Never make known what you have seen to-night.
+
+HORATIO MARCELLUS
+
+ My lord, we will not.
+
+HAMLET
+
+ Nay, but swear't.
+
+HORATIO
+
+ In faith,
+ My lord, not I.
+
+MARCELLUS
+
+ Nor I, my lord, in faith.
+
+HAMLET
+
+ Upon my sword.
+
+MARCELLUS
+
+ We have sworn, my lord, already.
+
+HAMLET
+
+ Indeed, upon my sword, indeed.
+
+Ghost
+
+ [Beneath] Swear.
+
+HAMLET
+
+ Ah, ha, boy! say'st thou so? art thou there,
+ truepenny?
+ Come on--you hear this fellow in the cellarage--
+ Consent to swear.
+
+HORATIO
+
+ Propose the oath, my lord.
+
+HAMLET
+
+ Never to speak of this that you have seen,
+ Swear by my sword.
+
+Ghost
+
+ [Beneath] Swear.
+
+HAMLET
+
+ Hic et ubique? then we'll shift our ground.
+ Come hither, gentlemen,
+ And lay your hands again upon my sword:
+ Never to speak of this that you have heard,
+ Swear by my sword.
+
+Ghost
+
+ [Beneath] Swear.
+
+HAMLET
+
+ Well said, old mole! canst work i' the earth so fast?
+ A worthy pioner! Once more remove, good friends.
+
+HORATIO
+
+ O day and night, but this is wondrous strange!
+
+HAMLET
+
+ And therefore as a stranger give it welcome.
+ There are more things in heaven and earth, Horatio,
+ Than are dreamt of in your philosophy. But come;
+ Here, as before, never, so help you mercy,
+ How strange or odd soe'er I bear myself,
+ As I perchance hereafter shall think meet
+ To put an antic disposition on,
+ That you, at such times seeing me, never shall,
+ With arms encumber'd thus, or this headshake,
+ Or by pronouncing of some doubtful phrase,
+ As 'Well, well, we know,' or 'We could, an if we would,'
+ Or 'If we list to speak,' or 'There be, an if they might,'
+ Or such ambiguous giving out, to note
+ That you know aught of me: this not to do,
+ So grace and mercy at your most need help you, Swear.
+
+Ghost
+
+ [Beneath] Swear.
+
+HAMLET
+
+ Rest, rest, perturbed spirit!
+
+ They swear
+ So, gentlemen,
+ With all my love I do commend me to you:
+ And what so poor a man as Hamlet is
+ May do, to express his love and friending to you,
+ God willing, shall not lack. Let us go in together;
+ And still your fingers on your lips, I pray.
+ The time is out of joint: O cursed spite,
+ That ever I was born to set it right!
+ Nay, come, let's go together.
+
+ Exeunt
+
+ACT II
+SCENE I. A room in POLONIUS' house.
+
+ Enter POLONIUS and REYNALDO
+
+LORD POLONIUS
+
+ Give him this money and these notes, Reynaldo.
+
+REYNALDO
+
+ I will, my lord.
+
+LORD POLONIUS
+
+ You shall do marvellous wisely, good Reynaldo,
+ Before you visit him, to make inquire
+ Of his behavior.
+
+REYNALDO
+
+ My lord, I did intend it.
+
+LORD POLONIUS
+
+ Marry, well said; very well said. Look you, sir,
+ Inquire me first what Danskers are in Paris;
+ And how, and who, what means, and where they keep,
+ What company, at what expense; and finding
+ By this encompassment and drift of question
+ That they do know my son, come you more nearer
+ Than your particular demands will touch it:
+ Take you, as 'twere, some distant knowledge of him;
+ As thus, 'I know his father and his friends,
+ And in part him: ' do you mark this, Reynaldo?
+
+REYNALDO
+
+ Ay, very well, my lord.
+
+LORD POLONIUS
+
+ 'And in part him; but' you may say 'not well:
+ But, if't be he I mean, he's very wild;
+ Addicted so and so:' and there put on him
+ What forgeries you please; marry, none so rank
+ As may dishonour him; take heed of that;
+ But, sir, such wanton, wild and usual slips
+ As are companions noted and most known
+ To youth and liberty.
+
+REYNALDO
+
+ As gaming, my lord.
+
+LORD POLONIUS
+
+ Ay, or drinking, fencing, swearing, quarrelling,
+ Drabbing: you may go so far.
+
+REYNALDO
+
+ My lord, that would dishonour him.
+
+LORD POLONIUS
+
+ 'Faith, no; as you may season it in the charge
+ You must not put another scandal on him,
+ That he is open to incontinency;
+ That's not my meaning: but breathe his faults so quaintly
+ That they may seem the taints of liberty,
+ The flash and outbreak of a fiery mind,
+ A savageness in unreclaimed blood,
+ Of general assault.
+
+REYNALDO
+
+ But, my good lord,--
+
+LORD POLONIUS
+
+ Wherefore should you do this?
+
+REYNALDO
+
+ Ay, my lord,
+ I would know that.
+
+LORD POLONIUS
+
+ Marry, sir, here's my drift;
+ And I believe, it is a fetch of wit:
+ You laying these slight sullies on my son,
+ As 'twere a thing a little soil'd i' the working, Mark you,
+ Your party in converse, him you would sound,
+ Having ever seen in the prenominate crimes
+ The youth you breathe of guilty, be assured
+ He closes with you in this consequence;
+ 'Good sir,' or so, or 'friend,' or 'gentleman,'
+ According to the phrase or the addition
+ Of man and country.
+
+REYNALDO
+
+ Very good, my lord.
+
+LORD POLONIUS
+
+ And then, sir, does he this--he does--what was I
+ about to say? By the mass, I was about to say
+ something: where did I leave?
+
+REYNALDO
+
+ At 'closes in the consequence,' at 'friend or so,'
+ and 'gentleman.'
+
+LORD POLONIUS
+
+ At 'closes in the consequence,' ay, marry;
+ He closes thus: 'I know the gentleman;
+ I saw him yesterday, or t' other day,
+ Or then, or then; with such, or such; and, as you say,
+ There was a' gaming; there o'ertook in's rouse;
+ There falling out at tennis:' or perchance,
+ 'I saw him enter such a house of sale,'
+ Videlicet, a brothel, or so forth.
+ See you now;
+ Your bait of falsehood takes this carp of truth:
+ And thus do we of wisdom and of reach,
+ With windlasses and with assays of bias,
+ By indirections find directions out:
+ So by my former lecture and advice,
+ Shall you my son. You have me, have you not?
+
+REYNALDO
+
+ My lord, I have.
+
+LORD POLONIUS
+
+ God be wi' you; fare you well.
+
+REYNALDO
+
+ Good my lord!
+
+LORD POLONIUS
+
+ Observe his inclination in yourself.
+
+REYNALDO
+
+ I shall, my lord.
+
+LORD POLONIUS
+
+ And let him ply his music.
+
+REYNALDO
+
+ Well, my lord.
+
+LORD POLONIUS
+
+ Farewell!
+
+ Exit REYNALDO
+
+ Enter OPHELIA
+ How now, Ophelia! what's the matter?
+
+OPHELIA
+
+ O, my lord, my lord, I have been so affrighted!
+
+LORD POLONIUS
+
+ With what, i' the name of God?
+
+OPHELIA
+
+ My lord, as I was sewing in my closet,
+ Lord Hamlet, with his doublet all unbraced;
+ No hat upon his head; his stockings foul'd,
+ Ungarter'd, and down-gyved to his ancle;
+ Pale as his shirt; his knees knocking each other;
+ And with a look so piteous in purport
+ As if he had been loosed out of hell
+ To speak of horrors,--he comes before me.
+
+LORD POLONIUS
+
+ Mad for thy love?
+
+OPHELIA
+
+ My lord, I do not know;
+ But truly, I do fear it.
+
+LORD POLONIUS
+
+ What said he?
+
+OPHELIA
+
+ He took me by the wrist and held me hard;
+ Then goes he to the length of all his arm;
+ And, with his other hand thus o'er his brow,
+ He falls to such perusal of my face
+ As he would draw it. Long stay'd he so;
+ At last, a little shaking of mine arm
+ And thrice his head thus waving up and down,
+ He raised a sigh so piteous and profound
+ As it did seem to shatter all his bulk
+ And end his being: that done, he lets me go:
+ And, with his head over his shoulder turn'd,
+ He seem'd to find his way without his eyes;
+ For out o' doors he went without their helps,
+ And, to the last, bended their light on me.
+
+LORD POLONIUS
+
+ Come, go with me: I will go seek the king.
+ This is the very ecstasy of love,
+ Whose violent property fordoes itself
+ And leads the will to desperate undertakings
+ As oft as any passion under heaven
+ That does afflict our natures. I am sorry.
+ What, have you given him any hard words of late?
+
+OPHELIA
+
+ No, my good lord, but, as you did command,
+ I did repel his fetters and denied
+ His access to me.
+
+LORD POLONIUS
+
+ That hath made him mad.
+ I am sorry that with better heed and judgment
+ I had not quoted him: I fear'd he did but trifle,
+ And meant to wreck thee; but, beshrew my jealousy!
+ By heaven, it is as proper to our age
+ To cast beyond ourselves in our opinions
+ As it is common for the younger sort
+ To lack discretion. Come, go we to the king:
+ This must be known; which, being kept close, might
+ move
+ More grief to hide than hate to utter love.
+
+ Exeunt
+
+SCENE II. A room in the castle.
+
+ Enter KING CLAUDIUS, QUEEN GERTRUDE, ROSENCRANTZ, GUILDENSTERN, and Attendants
+
+KING CLAUDIUS
+
+ Welcome, dear Rosencrantz and Guildenstern!
+ Moreover that we much did long to see you,
+ The need we have to use you did provoke
+ Our hasty sending. Something have you heard
+ Of Hamlet's transformation; so call it,
+ Sith nor the exterior nor the inward man
+ Resembles that it was. What it should be,
+ More than his father's death, that thus hath put him
+ So much from the understanding of himself,
+ I cannot dream of: I entreat you both,
+ That, being of so young days brought up with him,
+ And sith so neighbour'd to his youth and havior,
+ That you vouchsafe your rest here in our court
+ Some little time: so by your companies
+ To draw him on to pleasures, and to gather,
+ So much as from occasion you may glean,
+ Whether aught, to us unknown, afflicts him thus,
+ That, open'd, lies within our remedy.
+
+QUEEN GERTRUDE
+
+ Good gentlemen, he hath much talk'd of you;
+ And sure I am two men there are not living
+ To whom he more adheres. If it will please you
+ To show us so much gentry and good will
+ As to expend your time with us awhile,
+ For the supply and profit of our hope,
+ Your visitation shall receive such thanks
+ As fits a king's remembrance.
+
+ROSENCRANTZ
+
+ Both your majesties
+ Might, by the sovereign power you have of us,
+ Put your dread pleasures more into command
+ Than to entreaty.
+
+GUILDENSTERN
+
+ But we both obey,
+ And here give up ourselves, in the full bent
+ To lay our service freely at your feet,
+ To be commanded.
+
+KING CLAUDIUS
+
+ Thanks, Rosencrantz and gentle Guildenstern.
+
+QUEEN GERTRUDE
+
+ Thanks, Guildenstern and gentle Rosencrantz:
+ And I beseech you instantly to visit
+ My too much changed son. Go, some of you,
+ And bring these gentlemen where Hamlet is.
+
+GUILDENSTERN
+
+ Heavens make our presence and our practises
+ Pleasant and helpful to him!
+
+QUEEN GERTRUDE
+
+ Ay, amen!
+
+ Exeunt ROSENCRANTZ, GUILDENSTERN, and some Attendants
+
+ Enter POLONIUS
+
+LORD POLONIUS
+
+ The ambassadors from Norway, my good lord,
+ Are joyfully return'd.
+
+KING CLAUDIUS
+
+ Thou still hast been the father of good news.
+
+LORD POLONIUS
+
+ Have I, my lord? I assure my good liege,
+ I hold my duty, as I hold my soul,
+ Both to my God and to my gracious king:
+ And I do think, or else this brain of mine
+ Hunts not the trail of policy so sure
+ As it hath used to do, that I have found
+ The very cause of Hamlet's lunacy.
+
+KING CLAUDIUS
+
+ O, speak of that; that do I long to hear.
+
+LORD POLONIUS
+
+ Give first admittance to the ambassadors;
+ My news shall be the fruit to that great feast.
+
+KING CLAUDIUS
+
+ Thyself do grace to them, and bring them in.
+
+ Exit POLONIUS
+ He tells me, my dear Gertrude, he hath found
+ The head and source of all your son's distemper.
+
+QUEEN GERTRUDE
+
+ I doubt it is no other but the main;
+ His father's death, and our o'erhasty marriage.
+
+KING CLAUDIUS
+
+ Well, we shall sift him.
+
+ Re-enter POLONIUS, with VOLTIMAND and CORNELIUS
+ Welcome, my good friends!
+ Say, Voltimand, what from our brother Norway?
+
+VOLTIMAND
+
+ Most fair return of greetings and desires.
+ Upon our first, he sent out to suppress
+ His nephew's levies; which to him appear'd
+ To be a preparation 'gainst the Polack;
+ But, better look'd into, he truly found
+ It was against your highness: whereat grieved,
+ That so his sickness, age and impotence
+ Was falsely borne in hand, sends out arrests
+ On Fortinbras; which he, in brief, obeys;
+ Receives rebuke from Norway, and in fine
+ Makes vow before his uncle never more
+ To give the assay of arms against your majesty.
+ Whereon old Norway, overcome with joy,
+ Gives him three thousand crowns in annual fee,
+ And his commission to employ those soldiers,
+ So levied as before, against the Polack:
+ With an entreaty, herein further shown,
+
+ Giving a paper
+ That it might please you to give quiet pass
+ Through your dominions for this enterprise,
+ On such regards of safety and allowance
+ As therein are set down.
+
+KING CLAUDIUS
+
+ It likes us well;
+ And at our more consider'd time well read,
+ Answer, and think upon this business.
+ Meantime we thank you for your well-took labour:
+ Go to your rest; at night we'll feast together:
+ Most welcome home!
+
+ Exeunt VOLTIMAND and CORNELIUS
+
+LORD POLONIUS
+
+ This business is well ended.
+ My liege, and madam, to expostulate
+ What majesty should be, what duty is,
+ Why day is day, night night, and time is time,
+ Were nothing but to waste night, day and time.
+ Therefore, since brevity is the soul of wit,
+ And tediousness the limbs and outward flourishes,
+ I will be brief: your noble son is mad:
+ Mad call I it; for, to define true madness,
+ What is't but to be nothing else but mad?
+ But let that go.
+
+QUEEN GERTRUDE
+
+ More matter, with less art.
+
+LORD POLONIUS
+
+ Madam, I swear I use no art at all.
+ That he is mad, 'tis true: 'tis true 'tis pity;
+ And pity 'tis 'tis true: a foolish figure;
+ But farewell it, for I will use no art.
+ Mad let us grant him, then: and now remains
+ That we find out the cause of this effect,
+ Or rather say, the cause of this defect,
+ For this effect defective comes by cause:
+ Thus it remains, and the remainder thus. Perpend.
+ I have a daughter--have while she is mine--
+ Who, in her duty and obedience, mark,
+ Hath given me this: now gather, and surmise.
+
+ Reads
+ 'To the celestial and my soul's idol, the most
+ beautified Ophelia,'--
+ That's an ill phrase, a vile phrase; 'beautified' is
+ a vile phrase: but you shall hear. Thus:
+
+ Reads
+ 'In her excellent white bosom, these, & c.'
+
+QUEEN GERTRUDE
+
+ Came this from Hamlet to her?
+
+LORD POLONIUS
+
+ Good madam, stay awhile; I will be faithful.
+
+ Reads
+ 'Doubt thou the stars are fire;
+ Doubt that the sun doth move;
+ Doubt truth to be a liar;
+ But never doubt I love.
+ 'O dear Ophelia, I am ill at these numbers;
+ I have not art to reckon my groans: but that
+ I love thee best, O most best, believe it. Adieu.
+ 'Thine evermore most dear lady, whilst
+ this machine is to him, HAMLET.'
+ This, in obedience, hath my daughter shown me,
+ And more above, hath his solicitings,
+ As they fell out by time, by means and place,
+ All given to mine ear.
+
+KING CLAUDIUS
+
+ But how hath she
+ Received his love?
+
+LORD POLONIUS
+
+ What do you think of me?
+
+KING CLAUDIUS
+
+ As of a man faithful and honourable.
+
+LORD POLONIUS
+
+ I would fain prove so. But what might you think,
+ When I had seen this hot love on the wing--
+ As I perceived it, I must tell you that,
+ Before my daughter told me--what might you,
+ Or my dear majesty your queen here, think,
+ If I had play'd the desk or table-book,
+ Or given my heart a winking, mute and dumb,
+ Or look'd upon this love with idle sight;
+ What might you think? No, I went round to work,
+ And my young mistress thus I did bespeak:
+ 'Lord Hamlet is a prince, out of thy star;
+ This must not be:' and then I precepts gave her,
+ That she should lock herself from his resort,
+ Admit no messengers, receive no tokens.
+ Which done, she took the fruits of my advice;
+ And he, repulsed--a short tale to make--
+ Fell into a sadness, then into a fast,
+ Thence to a watch, thence into a weakness,
+ Thence to a lightness, and, by this declension,
+ Into the madness wherein now he raves,
+ And all we mourn for.
+
+KING CLAUDIUS
+
+ Do you think 'tis this?
+
+QUEEN GERTRUDE
+
+ It may be, very likely.
+
+LORD POLONIUS
+
+ Hath there been such a time--I'd fain know that--
+ That I have positively said 'Tis so,'
+ When it proved otherwise?
+
+KING CLAUDIUS
+
+ Not that I know.
+
+LORD POLONIUS
+
+ [Pointing to his head and shoulder]
+ Take this from this, if this be otherwise:
+ If circumstances lead me, I will find
+ Where truth is hid, though it were hid indeed
+ Within the centre.
+
+KING CLAUDIUS
+
+ How may we try it further?
+
+LORD POLONIUS
+
+ You know, sometimes he walks four hours together
+ Here in the lobby.
+
+QUEEN GERTRUDE
+
+ So he does indeed.
+
+LORD POLONIUS
+
+ At such a time I'll loose my daughter to him:
+ Be you and I behind an arras then;
+ Mark the encounter: if he love her not
+ And be not from his reason fall'n thereon,
+ Let me be no assistant for a state,
+ But keep a farm and carters.
+
+KING CLAUDIUS
+
+ We will try it.
+
+QUEEN GERTRUDE
+
+ But, look, where sadly the poor wretch comes reading.
+
+LORD POLONIUS
+
+ Away, I do beseech you, both away:
+ I'll board him presently.
+
+ Exeunt KING CLAUDIUS, QUEEN GERTRUDE, and Attendants
+
+ Enter HAMLET, reading
+ O, give me leave:
+ How does my good Lord Hamlet?
+
+HAMLET
+
+ Well, God-a-mercy.
+
+LORD POLONIUS
+
+ Do you know me, my lord?
+
+HAMLET
+
+ Excellent well; you are a fishmonger.
+
+LORD POLONIUS
+
+ Not I, my lord.
+
+HAMLET
+
+ Then I would you were so honest a man.
+
+LORD POLONIUS
+
+ Honest, my lord!
+
+HAMLET
+
+ Ay, sir; to be honest, as this world goes, is to be
+ one man picked out of ten thousand.
+
+LORD POLONIUS
+
+ That's very true, my lord.
+
+HAMLET
+
+ For if the sun breed maggots in a dead dog, being a
+ god kissing carrion,--Have you a daughter?
+
+LORD POLONIUS
+
+ I have, my lord.
+
+HAMLET
+
+ Let her not walk i' the sun: conception is a
+ blessing: but not as your daughter may conceive.
+ Friend, look to 't.
+
+LORD POLONIUS
+
+ [Aside] How say you by that? Still harping on my
+ daughter: yet he knew me not at first; he said I
+ was a fishmonger: he is far gone, far gone: and
+ truly in my youth I suffered much extremity for
+ love; very near this. I'll speak to him again.
+ What do you read, my lord?
+
+HAMLET
+
+ Words, words, words.
+
+LORD POLONIUS
+
+ What is the matter, my lord?
+
+HAMLET
+
+ Between who?
+
+LORD POLONIUS
+
+ I mean, the matter that you read, my lord.
+
+HAMLET
+
+ Slanders, sir: for the satirical rogue says here
+ that old men have grey beards, that their faces are
+ wrinkled, their eyes purging thick amber and
+ plum-tree gum and that they have a plentiful lack of
+ wit, together with most weak hams: all which, sir,
+ though I most powerfully and potently believe, yet
+ I hold it not honesty to have it thus set down, for
+ yourself, sir, should be old as I am, if like a crab
+ you could go backward.
+
+LORD POLONIUS
+
+ [Aside] Though this be madness, yet there is method
+ in 't. Will you walk out of the air, my lord?
+
+HAMLET
+
+ Into my grave.
+
+LORD POLONIUS
+
+ Indeed, that is out o' the air.
+
+ Aside
+ How pregnant sometimes his replies are! a happiness
+ that often madness hits on, which reason and sanity
+ could not so prosperously be delivered of. I will
+ leave him, and suddenly contrive the means of
+ meeting between him and my daughter.--My honourable
+ lord, I will most humbly take my leave of you.
+
+HAMLET
+
+ You cannot, sir, take from me any thing that I will
+ more willingly part withal: except my life, except
+ my life, except my life.
+
+LORD POLONIUS
+
+ Fare you well, my lord.
+
+HAMLET
+
+ These tedious old fools!
+
+ Enter ROSENCRANTZ and GUILDENSTERN
+
+LORD POLONIUS
+
+ You go to seek the Lord Hamlet; there he is.
+
+ROSENCRANTZ
+
+ [To POLONIUS] God save you, sir!
+
+ Exit POLONIUS
+
+GUILDENSTERN
+
+ My honoured lord!
+
+ROSENCRANTZ
+
+ My most dear lord!
+
+HAMLET
+
+ My excellent good friends! How dost thou,
+ Guildenstern? Ah, Rosencrantz! Good lads, how do ye both?
+
+ROSENCRANTZ
+
+ As the indifferent children of the earth.
+
+GUILDENSTERN
+
+ Happy, in that we are not over-happy;
+ On fortune's id we are not the very button.
+
+HAMLET
+
+ Nor the soles of her shoe?
+
+ROSENCRANTZ
+
+ Neither, my lord.
+
+HAMLET
+
+ Then you live about her waist, or in the middle of
+ her favours?
+
+GUILDENSTERN
+
+ 'Faith, her privates we.
+
+HAMLET
+
+ In the secret parts of fortune? O, most true; she
+ is a strumpet. What's the news?
+
+ROSENCRANTZ
+
+ None, my lord, but that the world's grown honest.
+
+HAMLET
+
+ Then is doomsday near: but your news is not true.
+ Let me question more in particular: what have you,
+ my good friends, deserved at the hands of fortune,
+ that she sends you to prison hither?
+
+GUILDENSTERN
+
+ Prison, my lord!
+
+HAMLET
+
+ Denmark's a prison.
+
+ROSENCRANTZ
+
+ Then is the world one.
+
+HAMLET
+
+ A goodly one; in which there are many confines,
+ wards and dungeons, Denmark being one o' the worst.
+
+ROSENCRANTZ
+
+ We think not so, my lord.
+
+HAMLET
+
+ Why, then, 'tis none to you; for there is nothing
+ either good or bad, but thinking makes it so: to me
+ it is a prison.
+
+ROSENCRANTZ
+
+ Why then, your ambition makes it one; 'tis too
+ narrow for your mind.
+
+HAMLET
+
+ O God, I could be bounded in a nut shell and count
+ myself a king of infinite space, were it not that I
+ have bad dreams.
+
+GUILDENSTERN
+
+ Which dreams indeed are ambition, for the very
+ substance of the ambitious is merely the shadow of a dream.
+
+HAMLET
+
+ A dream itself is but a shadow.
+
+ROSENCRANTZ
+
+ Truly, and I hold ambition of so airy and light a
+ quality that it is but a shadow's shadow.
+
+HAMLET
+
+ Then are our beggars bodies, and our monarchs and
+ outstretched heroes the beggars' shadows. Shall we
+ to the court? for, by my fay, I cannot reason.
+
+ROSENCRANTZ GUILDENSTERN
+
+ We'll wait upon you.
+
+HAMLET
+
+ No such matter: I will not sort you with the rest
+ of my servants, for, to speak to you like an honest
+ man, I am most dreadfully attended. But, in the
+ beaten way of friendship, what make you at Elsinore?
+
+ROSENCRANTZ
+
+ To visit you, my lord; no other occasion.
+
+HAMLET
+
+ Beggar that I am, I am even poor in thanks; but I
+ thank you: and sure, dear friends, my thanks are
+ too dear a halfpenny. Were you not sent for? Is it
+ your own inclining? Is it a free visitation? Come,
+ deal justly with me: come, come; nay, speak.
+
+GUILDENSTERN
+
+ What should we say, my lord?
+
+HAMLET
+
+ Why, any thing, but to the purpose. You were sent
+ for; and there is a kind of confession in your looks
+ which your modesties have not craft enough to colour:
+ I know the good king and queen have sent for you.
+
+ROSENCRANTZ
+
+ To what end, my lord?
+
+HAMLET
+
+ That you must teach me. But let me conjure you, by
+ the rights of our fellowship, by the consonancy of
+ our youth, by the obligation of our ever-preserved
+ love, and by what more dear a better proposer could
+ charge you withal, be even and direct with me,
+ whether you were sent for, or no?
+
+ROSENCRANTZ
+
+ [Aside to GUILDENSTERN] What say you?
+
+HAMLET
+
+ [Aside] Nay, then, I have an eye of you.--If you
+ love me, hold not off.
+
+GUILDENSTERN
+
+ My lord, we were sent for.
+
+HAMLET
+
+ I will tell you why; so shall my anticipation
+ prevent your discovery, and your secrecy to the king
+ and queen moult no feather. I have of late--but
+ wherefore I know not--lost all my mirth, forgone all
+ custom of exercises; and indeed it goes so heavily
+ with my disposition that this goodly frame, the
+ earth, seems to me a sterile promontory, this most
+ excellent canopy, the air, look you, this brave
+ o'erhanging firmament, this majestical roof fretted
+ with golden fire, why, it appears no other thing to
+ me than a foul and pestilent congregation of vapours.
+ What a piece of work is a man! how noble in reason!
+ how infinite in faculty! in form and moving how
+ express and admirable! in action how like an angel!
+ in apprehension how like a god! the beauty of the
+ world! the paragon of animals! And yet, to me,
+ what is this quintessence of dust? man delights not
+ me: no, nor woman neither, though by your smiling
+ you seem to say so.
+
+ROSENCRANTZ
+
+ My lord, there was no such stuff in my thoughts.
+
+HAMLET
+
+ Why did you laugh then, when I said 'man delights not me'?
+
+ROSENCRANTZ
+
+ To think, my lord, if you delight not in man, what
+ lenten entertainment the players shall receive from
+ you: we coted them on the way; and hither are they
+ coming, to offer you service.
+
+HAMLET
+
+ He that plays the king shall be welcome; his majesty
+ shall have tribute of me; the adventurous knight
+ shall use his foil and target; the lover shall not
+ sigh gratis; the humourous man shall end his part
+ in peace; the clown shall make those laugh whose
+ lungs are tickled o' the sere; and the lady shall
+ say her mind freely, or the blank verse shall halt
+ for't. What players are they?
+
+ROSENCRANTZ
+
+ Even those you were wont to take delight in, the
+ tragedians of the city.
+
+HAMLET
+
+ How chances it they travel? their residence, both
+ in reputation and profit, was better both ways.
+
+ROSENCRANTZ
+
+ I think their inhibition comes by the means of the
+ late innovation.
+
+HAMLET
+
+ Do they hold the same estimation they did when I was
+ in the city? are they so followed?
+
+ROSENCRANTZ
+
+ No, indeed, are they not.
+
+HAMLET
+
+ How comes it? do they grow rusty?
+
+ROSENCRANTZ
+
+ Nay, their endeavour keeps in the wonted pace: but
+ there is, sir, an aery of children, little eyases,
+ that cry out on the top of question, and are most
+ tyrannically clapped for't: these are now the
+ fashion, and so berattle the common stages--so they
+ call them--that many wearing rapiers are afraid of
+ goose-quills and dare scarce come thither.
+
+HAMLET
+
+ What, are they children? who maintains 'em? how are
+ they escoted? Will they pursue the quality no
+ longer than they can sing? will they not say
+ afterwards, if they should grow themselves to common
+ players--as it is most like, if their means are no
+ better--their writers do them wrong, to make them
+ exclaim against their own succession?
+
+ROSENCRANTZ
+
+ 'Faith, there has been much to do on both sides; and
+ the nation holds it no sin to tarre them to
+ controversy: there was, for a while, no money bid
+ for argument, unless the poet and the player went to
+ cuffs in the question.
+
+HAMLET
+
+ Is't possible?
+
+GUILDENSTERN
+
+ O, there has been much throwing about of brains.
+
+HAMLET
+
+ Do the boys carry it away?
+
+ROSENCRANTZ
+
+ Ay, that they do, my lord; Hercules and his load too.
+
+HAMLET
+
+ It is not very strange; for mine uncle is king of
+ Denmark, and those that would make mows at him while
+ my father lived, give twenty, forty, fifty, an
+ hundred ducats a-piece for his picture in little.
+ 'Sblood, there is something in this more than
+ natural, if philosophy could find it out.
+
+ Flourish of trumpets within
+
+GUILDENSTERN
+
+ There are the players.
+
+HAMLET
+
+ Gentlemen, you are welcome to Elsinore. Your hands,
+ come then: the appurtenance of welcome is fashion
+ and ceremony: let me comply with you in this garb,
+ lest my extent to the players, which, I tell you,
+ must show fairly outward, should more appear like
+ entertainment than yours. You are welcome: but my
+ uncle-father and aunt-mother are deceived.
+
+GUILDENSTERN
+
+ In what, my dear lord?
+
+HAMLET
+
+ I am but mad north-north-west: when the wind is
+ southerly I know a hawk from a handsaw.
+
+ Enter POLONIUS
+
+LORD POLONIUS
+
+ Well be with you, gentlemen!
+
+HAMLET
+
+ Hark you, Guildenstern; and you too: at each ear a
+ hearer: that great baby you see there is not yet
+ out of his swaddling-clouts.
+
+ROSENCRANTZ
+
+ Happily he's the second time come to them; for they
+ say an old man is twice a child.
+
+HAMLET
+
+ I will prophesy he comes to tell me of the players;
+ mark it. You say right, sir: o' Monday morning;
+ 'twas so indeed.
+
+LORD POLONIUS
+
+ My lord, I have news to tell you.
+
+HAMLET
+
+ My lord, I have news to tell you.
+ When Roscius was an actor in Rome,--
+
+LORD POLONIUS
+
+ The actors are come hither, my lord.
+
+HAMLET
+
+ Buz, buz!
+
+LORD POLONIUS
+
+ Upon mine honour,--
+
+HAMLET
+
+ Then came each actor on his ass,--
+
+LORD POLONIUS
+
+ The best actors in the world, either for tragedy,
+ comedy, history, pastoral, pastoral-comical,
+ historical-pastoral, tragical-historical, tragical-
+ comical-historical-pastoral, scene individable, or
+ poem unlimited: Seneca cannot be too heavy, nor
+ Plautus too light. For the law of writ and the
+ liberty, these are the only men.
+
+HAMLET
+
+ O Jephthah, judge of Israel, what a treasure hadst thou!
+
+LORD POLONIUS
+
+ What a treasure had he, my lord?
+
+HAMLET
+
+ Why,
+ 'One fair daughter and no more,
+ The which he loved passing well.'
+
+LORD POLONIUS
+
+ [Aside] Still on my daughter.
+
+HAMLET
+
+ Am I not i' the right, old Jephthah?
+
+LORD POLONIUS
+
+ If you call me Jephthah, my lord, I have a daughter
+ that I love passing well.
+
+HAMLET
+
+ Nay, that follows not.
+
+LORD POLONIUS
+
+ What follows, then, my lord?
+
+HAMLET
+
+ Why,
+ 'As by lot, God wot,'
+ and then, you know,
+ 'It came to pass, as most like it was,'--
+ the first row of the pious chanson will show you
+ more; for look, where my abridgement comes.
+
+ Enter four or five Players
+ You are welcome, masters; welcome, all. I am glad
+ to see thee well. Welcome, good friends. O, my old
+ friend! thy face is valenced since I saw thee last:
+ comest thou to beard me in Denmark? What, my young
+ lady and mistress! By'r lady, your ladyship is
+ nearer to heaven than when I saw you last, by the
+ altitude of a chopine. Pray God, your voice, like
+ apiece of uncurrent gold, be not cracked within the
+ ring. Masters, you are all welcome. We'll e'en
+ to't like French falconers, fly at any thing we see:
+ we'll have a speech straight: come, give us a taste
+ of your quality; come, a passionate speech.
+
+First Player
+
+ What speech, my lord?
+
+HAMLET
+
+ I heard thee speak me a speech once, but it was
+ never acted; or, if it was, not above once; for the
+ play, I remember, pleased not the million; 'twas
+ caviare to the general: but it was--as I received
+ it, and others, whose judgments in such matters
+ cried in the top of mine--an excellent play, well
+ digested in the scenes, set down with as much
+ modesty as cunning. I remember, one said there
+ were no sallets in the lines to make the matter
+ savoury, nor no matter in the phrase that might
+ indict the author of affectation; but called it an
+ honest method, as wholesome as sweet, and by very
+ much more handsome than fine. One speech in it I
+ chiefly loved: 'twas Aeneas' tale to Dido; and
+ thereabout of it especially, where he speaks of
+ Priam's slaughter: if it live in your memory, begin
+ at this line: let me see, let me see--
+ 'The rugged Pyrrhus, like the Hyrcanian beast,'--
+ it is not so:--it begins with Pyrrhus:--
+ 'The rugged Pyrrhus, he whose sable arms,
+ Black as his purpose, did the night resemble
+ When he lay couched in the ominous horse,
+ Hath now this dread and black complexion smear'd
+ With heraldry more dismal; head to foot
+ Now is he total gules; horridly trick'd
+ With blood of fathers, mothers, daughters, sons,
+ Baked and impasted with the parching streets,
+ That lend a tyrannous and damned light
+ To their lord's murder: roasted in wrath and fire,
+ And thus o'er-sized with coagulate gore,
+ With eyes like carbuncles, the hellish Pyrrhus
+ Old grandsire Priam seeks.'
+ So, proceed you.
+
+LORD POLONIUS
+
+ 'Fore God, my lord, well spoken, with good accent and
+ good discretion.
+
+First Player
+
+ 'Anon he finds him
+ Striking too short at Greeks; his antique sword,
+ Rebellious to his arm, lies where it falls,
+ Repugnant to command: unequal match'd,
+ Pyrrhus at Priam drives; in rage strikes wide;
+ But with the whiff and wind of his fell sword
+ The unnerved father falls. Then senseless Ilium,
+ Seeming to feel this blow, with flaming top
+ Stoops to his base, and with a hideous crash
+ Takes prisoner Pyrrhus' ear: for, lo! his sword,
+ Which was declining on the milky head
+ Of reverend Priam, seem'd i' the air to stick:
+ So, as a painted tyrant, Pyrrhus stood,
+ And like a neutral to his will and matter,
+ Did nothing.
+ But, as we often see, against some storm,
+ A silence in the heavens, the rack stand still,
+ The bold winds speechless and the orb below
+ As hush as death, anon the dreadful thunder
+ Doth rend the region, so, after Pyrrhus' pause,
+ Aroused vengeance sets him new a-work;
+ And never did the Cyclops' hammers fall
+ On Mars's armour forged for proof eterne
+ With less remorse than Pyrrhus' bleeding sword
+ Now falls on Priam.
+ Out, out, thou strumpet, Fortune! All you gods,
+ In general synod 'take away her power;
+ Break all the spokes and fellies from her wheel,
+ And bowl the round nave down the hill of heaven,
+ As low as to the fiends!'
+
+LORD POLONIUS
+
+ This is too long.
+
+HAMLET
+
+ It shall to the barber's, with your beard. Prithee,
+ say on: he's for a jig or a tale of bawdry, or he
+ sleeps: say on: come to Hecuba.
+
+First Player
+
+ 'But who, O, who had seen the mobled queen--'
+
+HAMLET
+
+ 'The mobled queen?'
+
+LORD POLONIUS
+
+ That's good; 'mobled queen' is good.
+
+First Player
+
+ 'Run barefoot up and down, threatening the flames
+ With bisson rheum; a clout upon that head
+ Where late the diadem stood, and for a robe,
+ About her lank and all o'er-teemed loins,
+ A blanket, in the alarm of fear caught up;
+ Who this had seen, with tongue in venom steep'd,
+ 'Gainst Fortune's state would treason have
+ pronounced:
+ But if the gods themselves did see her then
+ When she saw Pyrrhus make malicious sport
+ In mincing with his sword her husband's limbs,
+ The instant burst of clamour that she made,
+ Unless things mortal move them not at all,
+ Would have made milch the burning eyes of heaven,
+ And passion in the gods.'
+
+LORD POLONIUS
+
+ Look, whether he has not turned his colour and has
+ tears in's eyes. Pray you, no more.
+
+HAMLET
+
+ 'Tis well: I'll have thee speak out the rest soon.
+ Good my lord, will you see the players well
+ bestowed? Do you hear, let them be well used; for
+ they are the abstract and brief chronicles of the
+ time: after your death you were better have a bad
+ epitaph than their ill report while you live.
+
+LORD POLONIUS
+
+ My lord, I will use them according to their desert.
+
+HAMLET
+
+ God's bodykins, man, much better: use every man
+ after his desert, and who should 'scape whipping?
+ Use them after your own honour and dignity: the less
+ they deserve, the more merit is in your bounty.
+ Take them in.
+
+LORD POLONIUS
+
+ Come, sirs.
+
+HAMLET
+
+ Follow him, friends: we'll hear a play to-morrow.
+
+ Exit POLONIUS with all the Players but the First
+ Dost thou hear me, old friend; can you play the
+ Murder of Gonzago?
+
+First Player
+
+ Ay, my lord.
+
+HAMLET
+
+ We'll ha't to-morrow night. You could, for a need,
+ study a speech of some dozen or sixteen lines, which
+ I would set down and insert in't, could you not?
+
+First Player
+
+ Ay, my lord.
+
+HAMLET
+
+ Very well. Follow that lord; and look you mock him
+ not.
+
+ Exit First Player
+ My good friends, I'll leave you till night: you are
+ welcome to Elsinore.
+
+ROSENCRANTZ
+
+ Good my lord!
+
+HAMLET
+
+ Ay, so, God be wi' ye;
+
+ Exeunt ROSENCRANTZ and GUILDENSTERN
+ Now I am alone.
+ O, what a rogue and peasant slave am I!
+ Is it not monstrous that this player here,
+ But in a fiction, in a dream of passion,
+ Could force his soul so to his own conceit
+ That from her working all his visage wann'd,
+ Tears in his eyes, distraction in's aspect,
+ A broken voice, and his whole function suiting
+ With forms to his conceit? and all for nothing!
+ For Hecuba!
+ What's Hecuba to him, or he to Hecuba,
+ That he should weep for her? What would he do,
+ Had he the motive and the cue for passion
+ That I have? He would drown the stage with tears
+ And cleave the general ear with horrid speech,
+ Make mad the guilty and appal the free,
+ Confound the ignorant, and amaze indeed
+ The very faculties of eyes and ears. Yet I,
+ A dull and muddy-mettled rascal, peak,
+ Like John-a-dreams, unpregnant of my cause,
+ And can say nothing; no, not for a king,
+ Upon whose property and most dear life
+ A damn'd defeat was made. Am I a coward?
+ Who calls me villain? breaks my pate across?
+ Plucks off my beard, and blows it in my face?
+ Tweaks me by the nose? gives me the lie i' the throat,
+ As deep as to the lungs? who does me this?
+ Ha!
+ 'Swounds, I should take it: for it cannot be
+ But I am pigeon-liver'd and lack gall
+ To make oppression bitter, or ere this
+ I should have fatted all the region kites
+ With this slave's offal: bloody, bawdy villain!
+ Remorseless, treacherous, lecherous, kindless villain!
+ O, vengeance!
+ Why, what an ass am I! This is most brave,
+ That I, the son of a dear father murder'd,
+ Prompted to my revenge by heaven and hell,
+ Must, like a whore, unpack my heart with words,
+ And fall a-cursing, like a very drab,
+ A scullion!
+ Fie upon't! foh! About, my brain! I have heard
+ That guilty creatures sitting at a play
+ Have by the very cunning of the scene
+ Been struck so to the soul that presently
+ They have proclaim'd their malefactions;
+ For murder, though it have no tongue, will speak
+ With most miraculous organ. I'll have these players
+ Play something like the murder of my father
+ Before mine uncle: I'll observe his looks;
+ I'll tent him to the quick: if he but blench,
+ I know my course. The spirit that I have seen
+ May be the devil: and the devil hath power
+ To assume a pleasing shape; yea, and perhaps
+ Out of my weakness and my melancholy,
+ As he is very potent with such spirits,
+ Abuses me to damn me: I'll have grounds
+ More relative than this: the play 's the thing
+ Wherein I'll catch the conscience of the king.
+
+ Exit
+
+ACT III
+SCENE I. A room in the castle.
+
+ Enter KING CLAUDIUS, QUEEN GERTRUDE, POLONIUS, OPHELIA, ROSENCRANTZ, and GUILDENSTERN
+
+KING CLAUDIUS
+
+ And can you, by no drift of circumstance,
+ Get from him why he puts on this confusion,
+ Grating so harshly all his days of quiet
+ With turbulent and dangerous lunacy?
+
+ROSENCRANTZ
+
+ He does confess he feels himself distracted;
+ But from what cause he will by no means speak.
+
+GUILDENSTERN
+
+ Nor do we find him forward to be sounded,
+ But, with a crafty madness, keeps aloof,
+ When we would bring him on to some confession
+ Of his true state.
+
+QUEEN GERTRUDE
+
+ Did he receive you well?
+
+ROSENCRANTZ
+
+ Most like a gentleman.
+
+GUILDENSTERN
+
+ But with much forcing of his disposition.
+
+ROSENCRANTZ
+
+ Niggard of question; but, of our demands,
+ Most free in his reply.
+
+QUEEN GERTRUDE
+
+ Did you assay him?
+ To any pastime?
+
+ROSENCRANTZ
+
+ Madam, it so fell out, that certain players
+ We o'er-raught on the way: of these we told him;
+ And there did seem in him a kind of joy
+ To hear of it: they are about the court,
+ And, as I think, they have already order
+ This night to play before him.
+
+LORD POLONIUS
+
+ 'Tis most true:
+ And he beseech'd me to entreat your majesties
+ To hear and see the matter.
+
+KING CLAUDIUS
+
+ With all my heart; and it doth much content me
+ To hear him so inclined.
+ Good gentlemen, give him a further edge,
+ And drive his purpose on to these delights.
+
+ROSENCRANTZ
+
+ We shall, my lord.
+
+ Exeunt ROSENCRANTZ and GUILDENSTERN
+
+KING CLAUDIUS
+
+ Sweet Gertrude, leave us too;
+ For we have closely sent for Hamlet hither,
+ That he, as 'twere by accident, may here
+ Affront Ophelia:
+ Her father and myself, lawful espials,
+ Will so bestow ourselves that, seeing, unseen,
+ We may of their encounter frankly judge,
+ And gather by him, as he is behaved,
+ If 't be the affliction of his love or no
+ That thus he suffers for.
+
+QUEEN GERTRUDE
+
+ I shall obey you.
+ And for your part, Ophelia, I do wish
+ That your good beauties be the happy cause
+ Of Hamlet's wildness: so shall I hope your virtues
+ Will bring him to his wonted way again,
+ To both your honours.
+
+OPHELIA
+
+ Madam, I wish it may.
+
+ Exit QUEEN GERTRUDE
+
+LORD POLONIUS
+
+ Ophelia, walk you here. Gracious, so please you,
+ We will bestow ourselves.
+
+ To OPHELIA
+ Read on this book;
+ That show of such an exercise may colour
+ Your loneliness. We are oft to blame in this,--
+ 'Tis too much proved--that with devotion's visage
+ And pious action we do sugar o'er
+ The devil himself.
+
+KING CLAUDIUS
+
+ [Aside] O, 'tis too true!
+ How smart a lash that speech doth give my conscience!
+ The harlot's cheek, beautied with plastering art,
+ Is not more ugly to the thing that helps it
+ Than is my deed to my most painted word:
+ O heavy burthen!
+
+LORD POLONIUS
+
+ I hear him coming: let's withdraw, my lord.
+
+ Exeunt KING CLAUDIUS and POLONIUS
+
+ Enter HAMLET
+
+HAMLET
+
+ To be, or not to be: that is the question:
+ Whether 'tis nobler in the mind to suffer
+ The slings and arrows of outrageous fortune,
+ Or to take arms against a sea of troubles,
+ And by opposing end them? To die: to sleep;
+ No more; and by a sleep to say we end
+ The heart-ache and the thousand natural shocks
+ That flesh is heir to, 'tis a consummation
+ Devoutly to be wish'd. To die, to sleep;
+ To sleep: perchance to dream: ay, there's the rub;
+ For in that sleep of death what dreams may come
+ When we have shuffled off this mortal coil,
+ Must give us pause: there's the respect
+ That makes calamity of so long life;
+ For who would bear the whips and scorns of time,
+ The oppressor's wrong, the proud man's contumely,
+ The pangs of despised love, the law's delay,
+ The insolence of office and the spurns
+ That patient merit of the unworthy takes,
+ When he himself might his quietus make
+ With a bare bodkin? who would fardels bear,
+ To grunt and sweat under a weary life,
+ But that the dread of something after death,
+ The undiscover'd country from whose bourn
+ No traveller returns, puzzles the will
+ And makes us rather bear those ills we have
+ Than fly to others that we know not of?
+ Thus conscience does make cowards of us all;
+ And thus the native hue of resolution
+ Is sicklied o'er with the pale cast of thought,
+ And enterprises of great pith and moment
+ With this regard their currents turn awry,
+ And lose the name of action.--Soft you now!
+ The fair Ophelia! Nymph, in thy orisons
+ Be all my sins remember'd.
+
+OPHELIA
+
+ Good my lord,
+ How does your honour for this many a day?
+
+HAMLET
+
+ I humbly thank you; well, well, well.
+
+OPHELIA
+
+ My lord, I have remembrances of yours,
+ That I have longed long to re-deliver;
+ I pray you, now receive them.
+
+HAMLET
+
+ No, not I;
+ I never gave you aught.
+
+OPHELIA
+
+ My honour'd lord, you know right well you did;
+ And, with them, words of so sweet breath composed
+ As made the things more rich: their perfume lost,
+ Take these again; for to the noble mind
+ Rich gifts wax poor when givers prove unkind.
+ There, my lord.
+
+HAMLET
+
+ Ha, ha! are you honest?
+
+OPHELIA
+
+ My lord?
+
+HAMLET
+
+ Are you fair?
+
+OPHELIA
+
+ What means your lordship?
+
+HAMLET
+
+ That if you be honest and fair, your honesty should
+ admit no discourse to your beauty.
+
+OPHELIA
+
+ Could beauty, my lord, have better commerce than
+ with honesty?
+
+HAMLET
+
+ Ay, truly; for the power of beauty will sooner
+ transform honesty from what it is to a bawd than the
+ force of honesty can translate beauty into his
+ likeness: this was sometime a paradox, but now the
+ time gives it proof. I did love you once.
+
+OPHELIA
+
+ Indeed, my lord, you made me believe so.
+
+HAMLET
+
+ You should not have believed me; for virtue cannot
+ so inoculate our old stock but we shall relish of
+ it: I loved you not.
+
+OPHELIA
+
+ I was the more deceived.
+
+HAMLET
+
+ Get thee to a nunnery: why wouldst thou be a
+ breeder of sinners? I am myself indifferent honest;
+ but yet I could accuse me of such things that it
+ were better my mother had not borne me: I am very
+ proud, revengeful, ambitious, with more offences at
+ my beck than I have thoughts to put them in,
+ imagination to give them shape, or time to act them
+ in. What should such fellows as I do crawling
+ between earth and heaven? We are arrant knaves,
+ all; believe none of us. Go thy ways to a nunnery.
+ Where's your father?
+
+OPHELIA
+
+ At home, my lord.
+
+HAMLET
+
+ Let the doors be shut upon him, that he may play the
+ fool no where but in's own house. Farewell.
+
+OPHELIA
+
+ O, help him, you sweet heavens!
+
+HAMLET
+
+ If thou dost marry, I'll give thee this plague for
+ thy dowry: be thou as chaste as ice, as pure as
+ snow, thou shalt not escape calumny. Get thee to a
+ nunnery, go: farewell. Or, if thou wilt needs
+ marry, marry a fool; for wise men know well enough
+ what monsters you make of them. To a nunnery, go,
+ and quickly too. Farewell.
+
+OPHELIA
+
+ O heavenly powers, restore him!
+
+HAMLET
+
+ I have heard of your paintings too, well enough; God
+ has given you one face, and you make yourselves
+ another: you jig, you amble, and you lisp, and
+ nick-name God's creatures, and make your wantonness
+ your ignorance. Go to, I'll no more on't; it hath
+ made me mad. I say, we will have no more marriages:
+ those that are married already, all but one, shall
+ live; the rest shall keep as they are. To a
+ nunnery, go.
+
+ Exit
+
+OPHELIA
+
+ O, what a noble mind is here o'erthrown!
+ The courtier's, soldier's, scholar's, eye, tongue, sword;
+ The expectancy and rose of the fair state,
+ The glass of fashion and the mould of form,
+ The observed of all observers, quite, quite down!
+ And I, of ladies most deject and wretched,
+ That suck'd the honey of his music vows,
+ Now see that noble and most sovereign reason,
+ Like sweet bells jangled, out of tune and harsh;
+ That unmatch'd form and feature of blown youth
+ Blasted with ecstasy: O, woe is me,
+ To have seen what I have seen, see what I see!
+
+ Re-enter KING CLAUDIUS and POLONIUS
+
+KING CLAUDIUS
+
+ Love! his affections do not that way tend;
+ Nor what he spake, though it lack'd form a little,
+ Was not like madness. There's something in his soul,
+ O'er which his melancholy sits on brood;
+ And I do doubt the hatch and the disclose
+ Will be some danger: which for to prevent,
+ I have in quick determination
+ Thus set it down: he shall with speed to England,
+ For the demand of our neglected tribute
+ Haply the seas and countries different
+ With variable objects shall expel
+ This something-settled matter in his heart,
+ Whereon his brains still beating puts him thus
+ From fashion of himself. What think you on't?
+
+LORD POLONIUS
+
+ It shall do well: but yet do I believe
+ The origin and commencement of his grief
+ Sprung from neglected love. How now, Ophelia!
+ You need not tell us what Lord Hamlet said;
+ We heard it all. My lord, do as you please;
+ But, if you hold it fit, after the play
+ Let his queen mother all alone entreat him
+ To show his grief: let her be round with him;
+ And I'll be placed, so please you, in the ear
+ Of all their conference. If she find him not,
+ To England send him, or confine him where
+ Your wisdom best shall think.
+
+KING CLAUDIUS
+
+ It shall be so:
+ Madness in great ones must not unwatch'd go.
+
+ Exeunt
+
+SCENE II. A hall in the castle.
+
+ Enter HAMLET and Players
+
+HAMLET
+
+ Speak the speech, I pray you, as I pronounced it to
+ you, trippingly on the tongue: but if you mouth it,
+ as many of your players do, I had as lief the
+ town-crier spoke my lines. Nor do not saw the air
+ too much with your hand, thus, but use all gently;
+ for in the very torrent, tempest, and, as I may say,
+ the whirlwind of passion, you must acquire and beget
+ a temperance that may give it smoothness. O, it
+ offends me to the soul to hear a robustious
+ periwig-pated fellow tear a passion to tatters, to
+ very rags, to split the ears of the groundlings, who
+ for the most part are capable of nothing but
+ inexplicable dumbshows and noise: I would have such
+ a fellow whipped for o'erdoing Termagant; it
+ out-herods Herod: pray you, avoid it.
+
+First Player
+
+ I warrant your honour.
+
+HAMLET
+
+ Be not too tame neither, but let your own discretion
+ be your tutor: suit the action to the word, the
+ word to the action; with this special o'erstep not
+ the modesty of nature: for any thing so overdone is
+ from the purpose of playing, whose end, both at the
+ first and now, was and is, to hold, as 'twere, the
+ mirror up to nature; to show virtue her own feature,
+ scorn her own image, and the very age and body of
+ the time his form and pressure. Now this overdone,
+ or come tardy off, though it make the unskilful
+ laugh, cannot but make the judicious grieve; the
+ censure of the which one must in your allowance
+ o'erweigh a whole theatre of others. O, there be
+ players that I have seen play, and heard others
+ praise, and that highly, not to speak it profanely,
+ that, neither having the accent of Christians nor
+ the gait of Christian, pagan, nor man, have so
+ strutted and bellowed that I have thought some of
+ nature's journeymen had made men and not made them
+ well, they imitated humanity so abominably.
+
+First Player
+
+ I hope we have reformed that indifferently with us,
+ sir.
+
+HAMLET
+
+ O, reform it altogether. And let those that play
+ your clowns speak no more than is set down for them;
+ for there be of them that will themselves laugh, to
+ set on some quantity of barren spectators to laugh
+ too; though, in the mean time, some necessary
+ question of the play be then to be considered:
+ that's villanous, and shows a most pitiful ambition
+ in the fool that uses it. Go, make you ready.
+
+ Exeunt Players
+
+ Enter POLONIUS, ROSENCRANTZ, and GUILDENSTERN
+ How now, my lord! I will the king hear this piece of work?
+
+LORD POLONIUS
+
+ And the queen too, and that presently.
+
+HAMLET
+
+ Bid the players make haste.
+
+ Exit POLONIUS
+ Will you two help to hasten them?
+
+ROSENCRANTZ GUILDENSTERN
+
+ We will, my lord.
+
+ Exeunt ROSENCRANTZ and GUILDENSTERN
+
+HAMLET
+
+ What ho! Horatio!
+
+ Enter HORATIO
+
+HORATIO
+
+ Here, sweet lord, at your service.
+
+HAMLET
+
+ Horatio, thou art e'en as just a man
+ As e'er my conversation coped withal.
+
+HORATIO
+
+ O, my dear lord,--
+
+HAMLET
+
+ Nay, do not think I flatter;
+ For what advancement may I hope from thee
+ That no revenue hast but thy good spirits,
+ To feed and clothe thee? Why should the poor be flatter'd?
+ No, let the candied tongue lick absurd pomp,
+ And crook the pregnant hinges of the knee
+ Where thrift may follow fawning. Dost thou hear?
+ Since my dear soul was mistress of her choice
+ And could of men distinguish, her election
+ Hath seal'd thee for herself; for thou hast been
+ As one, in suffering all, that suffers nothing,
+ A man that fortune's buffets and rewards
+ Hast ta'en with equal thanks: and blest are those
+ Whose blood and judgment are so well commingled,
+ That they are not a pipe for fortune's finger
+ To sound what stop she please. Give me that man
+ That is not passion's slave, and I will wear him
+ In my heart's core, ay, in my heart of heart,
+ As I do thee.--Something too much of this.--
+ There is a play to-night before the king;
+ One scene of it comes near the circumstance
+ Which I have told thee of my father's death:
+ I prithee, when thou seest that act afoot,
+ Even with the very comment of thy soul
+ Observe mine uncle: if his occulted guilt
+ Do not itself unkennel in one speech,
+ It is a damned ghost that we have seen,
+ And my imaginations are as foul
+ As Vulcan's stithy. Give him heedful note;
+ For I mine eyes will rivet to his face,
+ And after we will both our judgments join
+ In censure of his seeming.
+
+HORATIO
+
+ Well, my lord:
+ If he steal aught the whilst this play is playing,
+ And 'scape detecting, I will pay the theft.
+
+HAMLET
+
+ They are coming to the play; I must be idle:
+ Get you a place.
+
+ Danish march. A flourish. Enter KING CLAUDIUS, QUEEN GERTRUDE, POLONIUS, OPHELIA, ROSENCRANTZ, GUILDENSTERN, and others
+
+KING CLAUDIUS
+
+ How fares our cousin Hamlet?
+
+HAMLET
+
+ Excellent, i' faith; of the chameleon's dish: I eat
+ the air, promise-crammed: you cannot feed capons so.
+
+KING CLAUDIUS
+
+ I have nothing with this answer, Hamlet; these words
+ are not mine.
+
+HAMLET
+
+ No, nor mine now.
+
+ To POLONIUS
+ My lord, you played once i' the university, you say?
+
+LORD POLONIUS
+
+ That did I, my lord; and was accounted a good actor.
+
+HAMLET
+
+ What did you enact?
+
+LORD POLONIUS
+
+ I did enact Julius Caesar: I was killed i' the
+ Capitol; Brutus killed me.
+
+HAMLET
+
+ It was a brute part of him to kill so capital a calf
+ there. Be the players ready?
+
+ROSENCRANTZ
+
+ Ay, my lord; they stay upon your patience.
+
+QUEEN GERTRUDE
+
+ Come hither, my dear Hamlet, sit by me.
+
+HAMLET
+
+ No, good mother, here's metal more attractive.
+
+LORD POLONIUS
+
+ [To KING CLAUDIUS] O, ho! do you mark that?
+
+HAMLET
+
+ Lady, shall I lie in your lap?
+
+ Lying down at OPHELIA's feet
+
+OPHELIA
+
+ No, my lord.
+
+HAMLET
+
+ I mean, my head upon your lap?
+
+OPHELIA
+
+ Ay, my lord.
+
+HAMLET
+
+ Do you think I meant country matters?
+
+OPHELIA
+
+ I think nothing, my lord.
+
+HAMLET
+
+ That's a fair thought to lie between maids' legs.
+
+OPHELIA
+
+ What is, my lord?
+
+HAMLET
+
+ Nothing.
+
+OPHELIA
+
+ You are merry, my lord.
+
+HAMLET
+
+ Who, I?
+
+OPHELIA
+
+ Ay, my lord.
+
+HAMLET
+
+ O God, your only jig-maker. What should a man do
+ but be merry? for, look you, how cheerfully my
+ mother looks, and my father died within these two hours.
+
+OPHELIA
+
+ Nay, 'tis twice two months, my lord.
+
+HAMLET
+
+ So long? Nay then, let the devil wear black, for
+ I'll have a suit of sables. O heavens! die two
+ months ago, and not forgotten yet? Then there's
+ hope a great man's memory may outlive his life half
+ a year: but, by'r lady, he must build churches,
+ then; or else shall he suffer not thinking on, with
+ the hobby-horse, whose epitaph is 'For, O, for, O,
+ the hobby-horse is forgot.'
+
+ Hautboys play. The dumb-show enters
+
+ Enter a King and a Queen very lovingly; the Queen embracing him, and he her. She kneels, and makes show of protestation unto him. He takes her up, and declines his head upon her neck: lays him down upon a bank of flowers: she, seeing him asleep, leaves him. Anon comes in a fellow, takes off his crown, kisses it, and pours poison in the King's ears, and exit. The Queen returns; finds the King dead, and makes passionate action. The Poisoner, with some two or three Mutes, comes in again, seeming to lament with her. The dead body is carried away. The Poisoner wooes the Queen with gifts: she seems loath and unwilling awhile, but in the end accepts his love
+
+ Exeunt
+
+OPHELIA
+
+ What means this, my lord?
+
+HAMLET
+
+ Marry, this is miching mallecho; it means mischief.
+
+OPHELIA
+
+ Belike this show imports the argument of the play.
+
+ Enter Prologue
+
+HAMLET
+
+ We shall know by this fellow: the players cannot
+ keep counsel; they'll tell all.
+
+OPHELIA
+
+ Will he tell us what this show meant?
+
+HAMLET
+
+ Ay, or any show that you'll show him: be not you
+ ashamed to show, he'll not shame to tell you what it means.
+
+OPHELIA
+
+ You are naught, you are naught: I'll mark the play.
+
+Prologue
+
+ For us, and for our tragedy,
+ Here stooping to your clemency,
+ We beg your hearing patiently.
+
+ Exit
+
+HAMLET
+
+ Is this a prologue, or the posy of a ring?
+
+OPHELIA
+
+ 'Tis brief, my lord.
+
+HAMLET
+
+ As woman's love.
+
+ Enter two Players, King and Queen
+
+Player King
+
+ Full thirty times hath Phoebus' cart gone round
+ Neptune's salt wash and Tellus' orbed ground,
+ And thirty dozen moons with borrow'd sheen
+ About the world have times twelve thirties been,
+ Since love our hearts and Hymen did our hands
+ Unite commutual in most sacred bands.
+
+Player Queen
+
+ So many journeys may the sun and moon
+ Make us again count o'er ere love be done!
+ But, woe is me, you are so sick of late,
+ So far from cheer and from your former state,
+ That I distrust you. Yet, though I distrust,
+ Discomfort you, my lord, it nothing must:
+ For women's fear and love holds quantity;
+ In neither aught, or in extremity.
+ Now, what my love is, proof hath made you know;
+ And as my love is sized, my fear is so:
+ Where love is great, the littlest doubts are fear;
+ Where little fears grow great, great love grows there.
+
+Player King
+
+ 'Faith, I must leave thee, love, and shortly too;
+ My operant powers their functions leave to do:
+ And thou shalt live in this fair world behind,
+ Honour'd, beloved; and haply one as kind
+ For husband shalt thou--
+
+Player Queen
+
+ O, confound the rest!
+ Such love must needs be treason in my breast:
+ In second husband let me be accurst!
+ None wed the second but who kill'd the first.
+
+HAMLET
+
+ [Aside] Wormwood, wormwood.
+
+Player Queen
+
+ The instances that second marriage move
+ Are base respects of thrift, but none of love:
+ A second time I kill my husband dead,
+ When second husband kisses me in bed.
+
+Player King
+
+ I do believe you think what now you speak;
+ But what we do determine oft we break.
+ Purpose is but the slave to memory,
+ Of violent birth, but poor validity;
+ Which now, like fruit unripe, sticks on the tree;
+ But fall, unshaken, when they mellow be.
+ Most necessary 'tis that we forget
+ To pay ourselves what to ourselves is debt:
+ What to ourselves in passion we propose,
+ The passion ending, doth the purpose lose.
+ The violence of either grief or joy
+ Their own enactures with themselves destroy:
+ Where joy most revels, grief doth most lament;
+ Grief joys, joy grieves, on slender accident.
+ This world is not for aye, nor 'tis not strange
+ That even our loves should with our fortunes change;
+ For 'tis a question left us yet to prove,
+ Whether love lead fortune, or else fortune love.
+ The great man down, you mark his favourite flies;
+ The poor advanced makes friends of enemies.
+ And hitherto doth love on fortune tend;
+ For who not needs shall never lack a friend,
+ And who in want a hollow friend doth try,
+ Directly seasons him his enemy.
+ But, orderly to end where I begun,
+ Our wills and fates do so contrary run
+ That our devices still are overthrown;
+ Our thoughts are ours, their ends none of our own:
+ So think thou wilt no second husband wed;
+ But die thy thoughts when thy first lord is dead.
+
+Player Queen
+
+ Nor earth to me give food, nor heaven light!
+ Sport and repose lock from me day and night!
+ To desperation turn my trust and hope!
+ An anchor's cheer in prison be my scope!
+ Each opposite that blanks the face of joy
+ Meet what I would have well and it destroy!
+ Both here and hence pursue me lasting strife,
+ If, once a widow, ever I be wife!
+
+HAMLET
+
+ If she should break it now!
+
+Player King
+
+ 'Tis deeply sworn. Sweet, leave me here awhile;
+ My spirits grow dull, and fain I would beguile
+ The tedious day with sleep.
+
+ Sleeps
+
+Player Queen
+
+ Sleep rock thy brain,
+ And never come mischance between us twain!
+
+ Exit
+
+HAMLET
+
+ Madam, how like you this play?
+
+QUEEN GERTRUDE
+
+ The lady protests too much, methinks.
+
+HAMLET
+
+ O, but she'll keep her word.
+
+KING CLAUDIUS
+
+ Have you heard the argument? Is there no offence in 't?
+
+HAMLET
+
+ No, no, they do but jest, poison in jest; no offence
+ i' the world.
+
+KING CLAUDIUS
+
+ What do you call the play?
+
+HAMLET
+
+ The Mouse-trap. Marry, how? Tropically. This play
+ is the image of a murder done in Vienna: Gonzago is
+ the duke's name; his wife, Baptista: you shall see
+ anon; 'tis a knavish piece of work: but what o'
+ that? your majesty and we that have free souls, it
+ touches us not: let the galled jade wince, our
+ withers are unwrung.
+
+ Enter LUCIANUS
+ This is one Lucianus, nephew to the king.
+
+OPHELIA
+
+ You are as good as a chorus, my lord.
+
+HAMLET
+
+ I could interpret between you and your love, if I
+ could see the puppets dallying.
+
+OPHELIA
+
+ You are keen, my lord, you are keen.
+
+HAMLET
+
+ It would cost you a groaning to take off my edge.
+
+OPHELIA
+
+ Still better, and worse.
+
+HAMLET
+
+ So you must take your husbands. Begin, murderer;
+ pox, leave thy damnable faces, and begin. Come:
+ 'the croaking raven doth bellow for revenge.'
+
+LUCIANUS
+
+ Thoughts black, hands apt, drugs fit, and time agreeing;
+ Confederate season, else no creature seeing;
+ Thou mixture rank, of midnight weeds collected,
+ With Hecate's ban thrice blasted, thrice infected,
+ Thy natural magic and dire property,
+ On wholesome life usurp immediately.
+
+ Pours the poison into the sleeper's ears
+
+HAMLET
+
+ He poisons him i' the garden for's estate. His
+ name's Gonzago: the story is extant, and writ in
+ choice Italian: you shall see anon how the murderer
+ gets the love of Gonzago's wife.
+
+OPHELIA
+
+ The king rises.
+
+HAMLET
+
+ What, frighted with false fire!
+
+QUEEN GERTRUDE
+
+ How fares my lord?
+
+LORD POLONIUS
+
+ Give o'er the play.
+
+KING CLAUDIUS
+
+ Give me some light: away!
+
+All
+
+ Lights, lights, lights!
+
+ Exeunt all but HAMLET and HORATIO
+
+HAMLET
+
+ Why, let the stricken deer go weep,
+ The hart ungalled play;
+ For some must watch, while some must sleep:
+ So runs the world away.
+ Would not this, sir, and a forest of feathers-- if
+ the rest of my fortunes turn Turk with me--with two
+ Provincial roses on my razed shoes, get me a
+ fellowship in a cry of players, sir?
+
+HORATIO
+
+ Half a share.
+
+HAMLET
+
+ A whole one, I.
+ For thou dost know, O Damon dear,
+ This realm dismantled was
+ Of Jove himself; and now reigns here
+ A very, very--pajock.
+
+HORATIO
+
+ You might have rhymed.
+
+HAMLET
+
+ O good Horatio, I'll take the ghost's word for a
+ thousand pound. Didst perceive?
+
+HORATIO
+
+ Very well, my lord.
+
+HAMLET
+
+ Upon the talk of the poisoning?
+
+HORATIO
+
+ I did very well note him.
+
+HAMLET
+
+ Ah, ha! Come, some music! come, the recorders!
+ For if the king like not the comedy,
+ Why then, belike, he likes it not, perdy.
+ Come, some music!
+
+ Re-enter ROSENCRANTZ and GUILDENSTERN
+
+GUILDENSTERN
+
+ Good my lord, vouchsafe me a word with you.
+
+HAMLET
+
+ Sir, a whole history.
+
+GUILDENSTERN
+
+ The king, sir,--
+
+HAMLET
+
+ Ay, sir, what of him?
+
+GUILDENSTERN
+
+ Is in his retirement marvellous distempered.
+
+HAMLET
+
+ With drink, sir?
+
+GUILDENSTERN
+
+ No, my lord, rather with choler.
+
+HAMLET
+
+ Your wisdom should show itself more richer to
+ signify this to his doctor; for, for me to put him
+ to his purgation would perhaps plunge him into far
+ more choler.
+
+GUILDENSTERN
+
+ Good my lord, put your discourse into some frame and
+ start not so wildly from my affair.
+
+HAMLET
+
+ I am tame, sir: pronounce.
+
+GUILDENSTERN
+
+ The queen, your mother, in most great affliction of
+ spirit, hath sent me to you.
+
+HAMLET
+
+ You are welcome.
+
+GUILDENSTERN
+
+ Nay, good my lord, this courtesy is not of the right
+ breed. If it shall please you to make me a
+ wholesome answer, I will do your mother's
+ commandment: if not, your pardon and my return
+ shall be the end of my business.
+
+HAMLET
+
+ Sir, I cannot.
+
+GUILDENSTERN
+
+ What, my lord?
+
+HAMLET
+
+ Make you a wholesome answer; my wit's diseased: but,
+ sir, such answer as I can make, you shall command;
+ or, rather, as you say, my mother: therefore no
+ more, but to the matter: my mother, you say,--
+
+ROSENCRANTZ
+
+ Then thus she says; your behavior hath struck her
+ into amazement and admiration.
+
+HAMLET
+
+ O wonderful son, that can so astonish a mother! But
+ is there no sequel at the heels of this mother's
+ admiration? Impart.
+
+ROSENCRANTZ
+
+ She desires to speak with you in her closet, ere you
+ go to bed.
+
+HAMLET
+
+ We shall obey, were she ten times our mother. Have
+ you any further trade with us?
+
+ROSENCRANTZ
+
+ My lord, you once did love me.
+
+HAMLET
+
+ So I do still, by these pickers and stealers.
+
+ROSENCRANTZ
+
+ Good my lord, what is your cause of distemper? you
+ do, surely, bar the door upon your own liberty, if
+ you deny your griefs to your friend.
+
+HAMLET
+
+ Sir, I lack advancement.
+
+ROSENCRANTZ
+
+ How can that be, when you have the voice of the king
+ himself for your succession in Denmark?
+
+HAMLET
+
+ Ay, but sir, 'While the grass grows,'--the proverb
+ is something musty.
+
+ Re-enter Players with recorders
+ O, the recorders! let me see one. To withdraw with
+ you:--why do you go about to recover the wind of me,
+ as if you would drive me into a toil?
+
+GUILDENSTERN
+
+ O, my lord, if my duty be too bold, my love is too
+ unmannerly.
+
+HAMLET
+
+ I do not well understand that. Will you play upon
+ this pipe?
+
+GUILDENSTERN
+
+ My lord, I cannot.
+
+HAMLET
+
+ I pray you.
+
+GUILDENSTERN
+
+ Believe me, I cannot.
+
+HAMLET
+
+ I do beseech you.
+
+GUILDENSTERN
+
+ I know no touch of it, my lord.
+
+HAMLET
+
+ 'Tis as easy as lying: govern these ventages with
+ your lingers and thumb, give it breath with your
+ mouth, and it will discourse most eloquent music.
+ Look you, these are the stops.
+
+GUILDENSTERN
+
+ But these cannot I command to any utterance of
+ harmony; I have not the skill.
+
+HAMLET
+
+ Why, look you now, how unworthy a thing you make of
+ me! You would play upon me; you would seem to know
+ my stops; you would pluck out the heart of my
+ mystery; you would sound me from my lowest note to
+ the top of my compass: and there is much music,
+ excellent voice, in this little organ; yet cannot
+ you make it speak. 'Sblood, do you think I am
+ easier to be played on than a pipe? Call me what
+ instrument you will, though you can fret me, yet you
+ cannot play upon me.
+
+ Enter POLONIUS
+ God bless you, sir!
+
+LORD POLONIUS
+
+ My lord, the queen would speak with you, and
+ presently.
+
+HAMLET
+
+ Do you see yonder cloud that's almost in shape of a camel?
+
+LORD POLONIUS
+
+ By the mass, and 'tis like a camel, indeed.
+
+HAMLET
+
+ Methinks it is like a weasel.
+
+LORD POLONIUS
+
+ It is backed like a weasel.
+
+HAMLET
+
+ Or like a whale?
+
+LORD POLONIUS
+
+ Very like a whale.
+
+HAMLET
+
+ Then I will come to my mother by and by. They fool
+ me to the top of my bent. I will come by and by.
+
+LORD POLONIUS
+
+ I will say so.
+
+HAMLET
+
+ By and by is easily said.
+
+ Exit POLONIUS
+ Leave me, friends.
+
+ Exeunt all but HAMLET
+ Tis now the very witching time of night,
+ When churchyards yawn and hell itself breathes out
+ Contagion to this world: now could I drink hot blood,
+ And do such bitter business as the day
+ Would quake to look on. Soft! now to my mother.
+ O heart, lose not thy nature; let not ever
+ The soul of Nero enter this firm bosom:
+ Let me be cruel, not unnatural:
+ I will speak daggers to her, but use none;
+ My tongue and soul in this be hypocrites;
+ How in my words soever she be shent,
+ To give them seals never, my soul, consent!
+
+ Exit
+
+SCENE III. A room in the castle.
+
+ Enter KING CLAUDIUS, ROSENCRANTZ, and GUILDENSTERN
+
+KING CLAUDIUS
+
+ I like him not, nor stands it safe with us
+ To let his madness range. Therefore prepare you;
+ I your commission will forthwith dispatch,
+ And he to England shall along with you:
+ The terms of our estate may not endure
+ Hazard so dangerous as doth hourly grow
+ Out of his lunacies.
+
+GUILDENSTERN
+
+ We will ourselves provide:
+ Most holy and religious fear it is
+ To keep those many many bodies safe
+ That live and feed upon your majesty.
+
+ROSENCRANTZ
+
+ The single and peculiar life is bound,
+ With all the strength and armour of the mind,
+ To keep itself from noyance; but much more
+ That spirit upon whose weal depend and rest
+ The lives of many. The cease of majesty
+ Dies not alone; but, like a gulf, doth draw
+ What's near it with it: it is a massy wheel,
+ Fix'd on the summit of the highest mount,
+ To whose huge spokes ten thousand lesser things
+ Are mortised and adjoin'd; which, when it falls,
+ Each small annexment, petty consequence,
+ Attends the boisterous ruin. Never alone
+ Did the king sigh, but with a general groan.
+
+KING CLAUDIUS
+
+ Arm you, I pray you, to this speedy voyage;
+ For we will fetters put upon this fear,
+ Which now goes too free-footed.
+
+ROSENCRANTZ GUILDENSTERN
+
+ We will haste us.
+
+ Exeunt ROSENCRANTZ and GUILDENSTERN
+
+ Enter POLONIUS
+
+LORD POLONIUS
+
+ My lord, he's going to his mother's closet:
+ Behind the arras I'll convey myself,
+ To hear the process; and warrant she'll tax him home:
+ And, as you said, and wisely was it said,
+ 'Tis meet that some more audience than a mother,
+ Since nature makes them partial, should o'erhear
+ The speech, of vantage. Fare you well, my liege:
+ I'll call upon you ere you go to bed,
+ And tell you what I know.
+
+KING CLAUDIUS
+
+ Thanks, dear my lord.
+
+ Exit POLONIUS
+ O, my offence is rank it smells to heaven;
+ It hath the primal eldest curse upon't,
+ A brother's murder. Pray can I not,
+ Though inclination be as sharp as will:
+ My stronger guilt defeats my strong intent;
+ And, like a man to double business bound,
+ I stand in pause where I shall first begin,
+ And both neglect. What if this cursed hand
+ Were thicker than itself with brother's blood,
+ Is there not rain enough in the sweet heavens
+ To wash it white as snow? Whereto serves mercy
+ But to confront the visage of offence?
+ And what's in prayer but this two-fold force,
+ To be forestalled ere we come to fall,
+ Or pardon'd being down? Then I'll look up;
+ My fault is past. But, O, what form of prayer
+ Can serve my turn? 'Forgive me my foul murder'?
+ That cannot be; since I am still possess'd
+ Of those effects for which I did the murder,
+ My crown, mine own ambition and my queen.
+ May one be pardon'd and retain the offence?
+ In the corrupted currents of this world
+ Offence's gilded hand may shove by justice,
+ And oft 'tis seen the wicked prize itself
+ Buys out the law: but 'tis not so above;
+ There is no shuffling, there the action lies
+ In his true nature; and we ourselves compell'd,
+ Even to the teeth and forehead of our faults,
+ To give in evidence. What then? what rests?
+ Try what repentance can: what can it not?
+ Yet what can it when one can not repent?
+ O wretched state! O bosom black as death!
+ O limed soul, that, struggling to be free,
+ Art more engaged! Help, angels! Make assay!
+ Bow, stubborn knees; and, heart with strings of steel,
+ Be soft as sinews of the newborn babe!
+ All may be well.
+
+ Retires and kneels
+
+ Enter HAMLET
+
+HAMLET
+
+ Now might I do it pat, now he is praying;
+ And now I'll do't. And so he goes to heaven;
+ And so am I revenged. That would be scann'd:
+ A villain kills my father; and for that,
+ I, his sole son, do this same villain send
+ To heaven.
+ O, this is hire and salary, not revenge.
+ He took my father grossly, full of bread;
+ With all his crimes broad blown, as flush as May;
+ And how his audit stands who knows save heaven?
+ But in our circumstance and course of thought,
+ 'Tis heavy with him: and am I then revenged,
+ To take him in the purging of his soul,
+ When he is fit and season'd for his passage?
+ No!
+ Up, sword; and know thou a more horrid hent:
+ When he is drunk asleep, or in his rage,
+ Or in the incestuous pleasure of his bed;
+ At gaming, swearing, or about some act
+ That has no relish of salvation in't;
+ Then trip him, that his heels may kick at heaven,
+ And that his soul may be as damn'd and black
+ As hell, whereto it goes. My mother stays:
+ This physic but prolongs thy sickly days.
+
+ Exit
+
+KING CLAUDIUS
+
+ [Rising] My words fly up, my thoughts remain below:
+ Words without thoughts never to heaven go.
+
+ Exit
+
+SCENE IV. The Queen's closet.
+
+ Enter QUEEN MARGARET and POLONIUS
+
+LORD POLONIUS
+
+ He will come straight. Look you lay home to him:
+ Tell him his pranks have been too broad to bear with,
+ And that your grace hath screen'd and stood between
+ Much heat and him. I'll sconce me even here.
+ Pray you, be round with him.
+
+HAMLET
+
+ [Within] Mother, mother, mother!
+
+QUEEN GERTRUDE
+
+ I'll warrant you,
+ Fear me not: withdraw, I hear him coming.
+
+ POLONIUS hides behind the arras
+
+ Enter HAMLET
+
+HAMLET
+
+ Now, mother, what's the matter?
+
+QUEEN GERTRUDE
+
+ Hamlet, thou hast thy father much offended.
+
+HAMLET
+
+ Mother, you have my father much offended.
+
+QUEEN GERTRUDE
+
+ Come, come, you answer with an idle tongue.
+
+HAMLET
+
+ Go, go, you question with a wicked tongue.
+
+QUEEN GERTRUDE
+
+ Why, how now, Hamlet!
+
+HAMLET
+
+ What's the matter now?
+
+QUEEN GERTRUDE
+
+ Have you forgot me?
+
+HAMLET
+
+ No, by the rood, not so:
+ You are the queen, your husband's brother's wife;
+ And--would it were not so!--you are my mother.
+
+QUEEN GERTRUDE
+
+ Nay, then, I'll set those to you that can speak.
+
+HAMLET
+
+ Come, come, and sit you down; you shall not budge;
+ You go not till I set you up a glass
+ Where you may see the inmost part of you.
+
+QUEEN GERTRUDE
+
+ What wilt thou do? thou wilt not murder me?
+ Help, help, ho!
+
+LORD POLONIUS
+
+ [Behind] What, ho! help, help, help!
+
+HAMLET
+
+ [Drawing] How now! a rat? Dead, for a ducat, dead!
+
+ Makes a pass through the arras
+
+LORD POLONIUS
+
+ [Behind] O, I am slain!
+
+ Falls and dies
+
+QUEEN GERTRUDE
+
+ O me, what hast thou done?
+
+HAMLET
+
+ Nay, I know not:
+ Is it the king?
+
+QUEEN GERTRUDE
+
+ O, what a rash and bloody deed is this!
+
+HAMLET
+
+ A bloody deed! almost as bad, good mother,
+ As kill a king, and marry with his brother.
+
+QUEEN GERTRUDE
+
+ As kill a king!
+
+HAMLET
+
+ Ay, lady, 'twas my word.
+
+ Lifts up the array and discovers POLONIUS
+ Thou wretched, rash, intruding fool, farewell!
+ I took thee for thy better: take thy fortune;
+ Thou find'st to be too busy is some danger.
+ Leave wringing of your hands: peace! sit you down,
+ And let me wring your heart; for so I shall,
+ If it be made of penetrable stuff,
+ If damned custom have not brass'd it so
+ That it is proof and bulwark against sense.
+
+QUEEN GERTRUDE
+
+ What have I done, that thou darest wag thy tongue
+ In noise so rude against me?
+
+HAMLET
+
+ Such an act
+ That blurs the grace and blush of modesty,
+ Calls virtue hypocrite, takes off the rose
+ From the fair forehead of an innocent love
+ And sets a blister there, makes marriage-vows
+ As false as dicers' oaths: O, such a deed
+ As from the body of contraction plucks
+ The very soul, and sweet religion makes
+ A rhapsody of words: heaven's face doth glow:
+ Yea, this solidity and compound mass,
+ With tristful visage, as against the doom,
+ Is thought-sick at the act.
+
+QUEEN GERTRUDE
+
+ Ay me, what act,
+ That roars so loud, and thunders in the index?
+
+HAMLET
+
+ Look here, upon this picture, and on this,
+ The counterfeit presentment of two brothers.
+ See, what a grace was seated on this brow;
+ Hyperion's curls; the front of Jove himself;
+ An eye like Mars, to threaten and command;
+ A station like the herald Mercury
+ New-lighted on a heaven-kissing hill;
+ A combination and a form indeed,
+ Where every god did seem to set his seal,
+ To give the world assurance of a man:
+ This was your husband. Look you now, what follows:
+ Here is your husband; like a mildew'd ear,
+ Blasting his wholesome brother. Have you eyes?
+ Could you on this fair mountain leave to feed,
+ And batten on this moor? Ha! have you eyes?
+ You cannot call it love; for at your age
+ The hey-day in the blood is tame, it's humble,
+ And waits upon the judgment: and what judgment
+ Would step from this to this? Sense, sure, you have,
+ Else could you not have motion; but sure, that sense
+ Is apoplex'd; for madness would not err,
+ Nor sense to ecstasy was ne'er so thrall'd
+ But it reserved some quantity of choice,
+ To serve in such a difference. What devil was't
+ That thus hath cozen'd you at hoodman-blind?
+ Eyes without feeling, feeling without sight,
+ Ears without hands or eyes, smelling sans all,
+ Or but a sickly part of one true sense
+ Could not so mope.
+ O shame! where is thy blush? Rebellious hell,
+ If thou canst mutine in a matron's bones,
+ To flaming youth let virtue be as wax,
+ And melt in her own fire: proclaim no shame
+ When the compulsive ardour gives the charge,
+ Since frost itself as actively doth burn
+ And reason panders will.
+
+QUEEN GERTRUDE
+
+ O Hamlet, speak no more:
+ Thou turn'st mine eyes into my very soul;
+ And there I see such black and grained spots
+ As will not leave their tinct.
+
+HAMLET
+
+ Nay, but to live
+ In the rank sweat of an enseamed bed,
+ Stew'd in corruption, honeying and making love
+ Over the nasty sty,--
+
+QUEEN GERTRUDE
+
+ O, speak to me no more;
+ These words, like daggers, enter in mine ears;
+ No more, sweet Hamlet!
+
+HAMLET
+
+ A murderer and a villain;
+ A slave that is not twentieth part the tithe
+ Of your precedent lord; a vice of kings;
+ A cutpurse of the empire and the rule,
+ That from a shelf the precious diadem stole,
+ And put it in his pocket!
+
+QUEEN GERTRUDE
+
+ No more!
+
+HAMLET
+
+ A king of shreds and patches,--
+
+ Enter Ghost
+ Save me, and hover o'er me with your wings,
+ You heavenly guards! What would your gracious figure?
+
+QUEEN GERTRUDE
+
+ Alas, he's mad!
+
+HAMLET
+
+ Do you not come your tardy son to chide,
+ That, lapsed in time and passion, lets go by
+ The important acting of your dread command? O, say!
+
+Ghost
+
+ Do not forget: this visitation
+ Is but to whet thy almost blunted purpose.
+ But, look, amazement on thy mother sits:
+ O, step between her and her fighting soul:
+ Conceit in weakest bodies strongest works:
+ Speak to her, Hamlet.
+
+HAMLET
+
+ How is it with you, lady?
+
+QUEEN GERTRUDE
+
+ Alas, how is't with you,
+ That you do bend your eye on vacancy
+ And with the incorporal air do hold discourse?
+ Forth at your eyes your spirits wildly peep;
+ And, as the sleeping soldiers in the alarm,
+ Your bedded hair, like life in excrements,
+ Starts up, and stands on end. O gentle son,
+ Upon the heat and flame of thy distemper
+ Sprinkle cool patience. Whereon do you look?
+
+HAMLET
+
+ On him, on him! Look you, how pale he glares!
+ His form and cause conjoin'd, preaching to stones,
+ Would make them capable. Do not look upon me;
+ Lest with this piteous action you convert
+ My stern effects: then what I have to do
+ Will want true colour; tears perchance for blood.
+
+QUEEN GERTRUDE
+
+ To whom do you speak this?
+
+HAMLET
+
+ Do you see nothing there?
+
+QUEEN GERTRUDE
+
+ Nothing at all; yet all that is I see.
+
+HAMLET
+
+ Nor did you nothing hear?
+
+QUEEN GERTRUDE
+
+ No, nothing but ourselves.
+
+HAMLET
+
+ Why, look you there! look, how it steals away!
+ My father, in his habit as he lived!
+ Look, where he goes, even now, out at the portal!
+
+ Exit Ghost
+
+QUEEN GERTRUDE
+
+ This the very coinage of your brain:
+ This bodiless creation ecstasy
+ Is very cunning in.
+
+HAMLET
+
+ Ecstasy!
+ My pulse, as yours, doth temperately keep time,
+ And makes as healthful music: it is not madness
+ That I have utter'd: bring me to the test,
+ And I the matter will re-word; which madness
+ Would gambol from. Mother, for love of grace,
+ Lay not that mattering unction to your soul,
+ That not your trespass, but my madness speaks:
+ It will but skin and film the ulcerous place,
+ Whilst rank corruption, mining all within,
+ Infects unseen. Confess yourself to heaven;
+ Repent what's past; avoid what is to come;
+ And do not spread the compost on the weeds,
+ To make them ranker. Forgive me this my virtue;
+ For in the fatness of these pursy times
+ Virtue itself of vice must pardon beg,
+ Yea, curb and woo for leave to do him good.
+
+QUEEN GERTRUDE
+
+ O Hamlet, thou hast cleft my heart in twain.
+
+HAMLET
+
+ O, throw away the worser part of it,
+ And live the purer with the other half.
+ Good night: but go not to mine uncle's bed;
+ Assume a virtue, if you have it not.
+ That monster, custom, who all sense doth eat,
+ Of habits devil, is angel yet in this,
+ That to the use of actions fair and good
+ He likewise gives a frock or livery,
+ That aptly is put on. Refrain to-night,
+ And that shall lend a kind of easiness
+ To the next abstinence: the next more easy;
+ For use almost can change the stamp of nature,
+ And either [ ] the devil, or throw him out
+ With wondrous potency. Once more, good night:
+ And when you are desirous to be bless'd,
+ I'll blessing beg of you. For this same lord,
+
+ Pointing to POLONIUS
+ I do repent: but heaven hath pleased it so,
+ To punish me with this and this with me,
+ That I must be their scourge and minister.
+ I will bestow him, and will answer well
+ The death I gave him. So, again, good night.
+ I must be cruel, only to be kind:
+ Thus bad begins and worse remains behind.
+ One word more, good lady.
+
+QUEEN GERTRUDE
+
+ What shall I do?
+
+HAMLET
+
+ Not this, by no means, that I bid you do:
+ Let the bloat king tempt you again to bed;
+ Pinch wanton on your cheek; call you his mouse;
+ And let him, for a pair of reechy kisses,
+ Or paddling in your neck with his damn'd fingers,
+ Make you to ravel all this matter out,
+ That I essentially am not in madness,
+ But mad in craft. 'Twere good you let him know;
+ For who, that's but a queen, fair, sober, wise,
+ Would from a paddock, from a bat, a gib,
+ Such dear concernings hide? who would do so?
+ No, in despite of sense and secrecy,
+ Unpeg the basket on the house's top.
+ Let the birds fly, and, like the famous ape,
+ To try conclusions, in the basket creep,
+ And break your own neck down.
+
+QUEEN GERTRUDE
+
+ Be thou assured, if words be made of breath,
+ And breath of life, I have no life to breathe
+ What thou hast said to me.
+
+HAMLET
+
+ I must to England; you know that?
+
+QUEEN GERTRUDE
+
+ Alack,
+ I had forgot: 'tis so concluded on.
+
+HAMLET
+
+ There's letters seal'd: and my two schoolfellows,
+ Whom I will trust as I will adders fang'd,
+ They bear the mandate; they must sweep my way,
+ And marshal me to knavery. Let it work;
+ For 'tis the sport to have the engineer
+ Hoist with his own petard: and 't shall go hard
+ But I will delve one yard below their mines,
+ And blow them at the moon: O, 'tis most sweet,
+ When in one line two crafts directly meet.
+ This man shall set me packing:
+ I'll lug the guts into the neighbour room.
+ Mother, good night. Indeed this counsellor
+ Is now most still, most secret and most grave,
+ Who was in life a foolish prating knave.
+ Come, sir, to draw toward an end with you.
+ Good night, mother.
+
+ Exeunt severally; HAMLET dragging in POLONIUS
+
+ACT IV
+SCENE I. A room in the castle.
+
+ Enter KING CLAUDIUS, QUEEN GERTRUDE, ROSENCRANTZ, and GUILDENSTERN
+
+KING CLAUDIUS
+
+ There's matter in these sighs, these profound heaves:
+ You must translate: 'tis fit we understand them.
+ Where is your son?
+
+QUEEN GERTRUDE
+
+ Bestow this place on us a little while.
+
+ Exeunt ROSENCRANTZ and GUILDENSTERN
+ Ah, my good lord, what have I seen to-night!
+
+KING CLAUDIUS
+
+ What, Gertrude? How does Hamlet?
+
+QUEEN GERTRUDE
+
+ Mad as the sea and wind, when both contend
+ Which is the mightier: in his lawless fit,
+ Behind the arras hearing something stir,
+ Whips out his rapier, cries, 'A rat, a rat!'
+ And, in this brainish apprehension, kills
+ The unseen good old man.
+
+KING CLAUDIUS
+
+ O heavy deed!
+ It had been so with us, had we been there:
+ His liberty is full of threats to all;
+ To you yourself, to us, to every one.
+ Alas, how shall this bloody deed be answer'd?
+ It will be laid to us, whose providence
+ Should have kept short, restrain'd and out of haunt,
+ This mad young man: but so much was our love,
+ We would not understand what was most fit;
+ But, like the owner of a foul disease,
+ To keep it from divulging, let it feed
+ Even on the pith of Life. Where is he gone?
+
+QUEEN GERTRUDE
+
+ To draw apart the body he hath kill'd:
+ O'er whom his very madness, like some ore
+ Among a mineral of metals base,
+ Shows itself pure; he weeps for what is done.
+
+KING CLAUDIUS
+
+ O Gertrude, come away!
+ The sun no sooner shall the mountains touch,
+ But we will ship him hence: and this vile deed
+ We must, with all our majesty and skill,
+ Both countenance and excuse. Ho, Guildenstern!
+
+ Re-enter ROSENCRANTZ and GUILDENSTERN
+ Friends both, go join you with some further aid:
+ Hamlet in madness hath Polonius slain,
+ And from his mother's closet hath he dragg'd him:
+ Go seek him out; speak fair, and bring the body
+ Into the chapel. I pray you, haste in this.
+
+ Exeunt ROSENCRANTZ and GUILDENSTERN
+ Come, Gertrude, we'll call up our wisest friends;
+ And let them know, both what we mean to do,
+ And what's untimely done. O, come away!
+ My soul is full of discord and dismay.
+
+ Exeunt
+
+SCENE II. Another room in the castle.
+
+ Enter HAMLET
+
+HAMLET
+
+ Safely stowed.
+
+ROSENCRANTZ: GUILDENSTERN:
+
+ [Within] Hamlet! Lord Hamlet!
+
+HAMLET
+
+ What noise? who calls on Hamlet?
+ O, here they come.
+
+ Enter ROSENCRANTZ and GUILDENSTERN
+
+ROSENCRANTZ
+
+ What have you done, my lord, with the dead body?
+
+HAMLET
+
+ Compounded it with dust, whereto 'tis kin.
+
+ROSENCRANTZ
+
+ Tell us where 'tis, that we may take it thence
+ And bear it to the chapel.
+
+HAMLET
+
+ Do not believe it.
+
+ROSENCRANTZ
+
+ Believe what?
+
+HAMLET
+
+ That I can keep your counsel and not mine own.
+ Besides, to be demanded of a sponge! what
+ replication should be made by the son of a king?
+
+ROSENCRANTZ
+
+ Take you me for a sponge, my lord?
+
+HAMLET
+
+ Ay, sir, that soaks up the king's countenance, his
+ rewards, his authorities. But such officers do the
+ king best service in the end: he keeps them, like
+ an ape, in the corner of his jaw; first mouthed, to
+ be last swallowed: when he needs what you have
+ gleaned, it is but squeezing you, and, sponge, you
+ shall be dry again.
+
+ROSENCRANTZ
+
+ I understand you not, my lord.
+
+HAMLET
+
+ I am glad of it: a knavish speech sleeps in a
+ foolish ear.
+
+ROSENCRANTZ
+
+ My lord, you must tell us where the body is, and go
+ with us to the king.
+
+HAMLET
+
+ The body is with the king, but the king is not with
+ the body. The king is a thing--
+
+GUILDENSTERN
+
+ A thing, my lord!
+
+HAMLET
+
+ Of nothing: bring me to him. Hide fox, and all after.
+
+ Exeunt
+
+SCENE III. Another room in the castle.
+
+ Enter KING CLAUDIUS, attended
+
+KING CLAUDIUS
+
+ I have sent to seek him, and to find the body.
+ How dangerous is it that this man goes loose!
+ Yet must not we put the strong law on him:
+ He's loved of the distracted multitude,
+ Who like not in their judgment, but their eyes;
+ And where tis so, the offender's scourge is weigh'd,
+ But never the offence. To bear all smooth and even,
+ This sudden sending him away must seem
+ Deliberate pause: diseases desperate grown
+ By desperate appliance are relieved,
+ Or not at all.
+
+ Enter ROSENCRANTZ
+ How now! what hath befall'n?
+
+ROSENCRANTZ
+
+ Where the dead body is bestow'd, my lord,
+ We cannot get from him.
+
+KING CLAUDIUS
+
+ But where is he?
+
+ROSENCRANTZ
+
+ Without, my lord; guarded, to know your pleasure.
+
+KING CLAUDIUS
+
+ Bring him before us.
+
+ROSENCRANTZ
+
+ Ho, Guildenstern! bring in my lord.
+
+ Enter HAMLET and GUILDENSTERN
+
+KING CLAUDIUS
+
+ Now, Hamlet, where's Polonius?
+
+HAMLET
+
+ At supper.
+
+KING CLAUDIUS
+
+ At supper! where?
+
+HAMLET
+
+ Not where he eats, but where he is eaten: a certain
+ convocation of politic worms are e'en at him. Your
+ worm is your only emperor for diet: we fat all
+ creatures else to fat us, and we fat ourselves for
+ maggots: your fat king and your lean beggar is but
+ variable service, two dishes, but to one table:
+ that's the end.
+
+KING CLAUDIUS
+
+ Alas, alas!
+
+HAMLET
+
+ A man may fish with the worm that hath eat of a
+ king, and cat of the fish that hath fed of that worm.
+
+KING CLAUDIUS
+
+ What dost you mean by this?
+
+HAMLET
+
+ Nothing but to show you how a king may go a
+ progress through the guts of a beggar.
+
+KING CLAUDIUS
+
+ Where is Polonius?
+
+HAMLET
+
+ In heaven; send hither to see: if your messenger
+ find him not there, seek him i' the other place
+ yourself. But indeed, if you find him not within
+ this month, you shall nose him as you go up the
+ stairs into the lobby.
+
+KING CLAUDIUS
+
+ Go seek him there.
+
+ To some Attendants
+
+HAMLET
+
+ He will stay till ye come.
+
+ Exeunt Attendants
+
+KING CLAUDIUS
+
+ Hamlet, this deed, for thine especial safety,--
+ Which we do tender, as we dearly grieve
+ For that which thou hast done,--must send thee hence
+ With fiery quickness: therefore prepare thyself;
+ The bark is ready, and the wind at help,
+ The associates tend, and every thing is bent
+ For England.
+
+HAMLET
+
+ For England!
+
+KING CLAUDIUS
+
+ Ay, Hamlet.
+
+HAMLET
+
+ Good.
+
+KING CLAUDIUS
+
+ So is it, if thou knew'st our purposes.
+
+HAMLET
+
+ I see a cherub that sees them. But, come; for
+ England! Farewell, dear mother.
+
+KING CLAUDIUS
+
+ Thy loving father, Hamlet.
+
+HAMLET
+
+ My mother: father and mother is man and wife; man
+ and wife is one flesh; and so, my mother. Come, for England!
+
+ Exit
+
+KING CLAUDIUS
+
+ Follow him at foot; tempt him with speed aboard;
+ Delay it not; I'll have him hence to-night:
+ Away! for every thing is seal'd and done
+ That else leans on the affair: pray you, make haste.
+
+ Exeunt ROSENCRANTZ and GUILDENSTERN
+ And, England, if my love thou hold'st at aught--
+ As my great power thereof may give thee sense,
+ Since yet thy cicatrice looks raw and red
+ After the Danish sword, and thy free awe
+ Pays homage to us--thou mayst not coldly set
+ Our sovereign process; which imports at full,
+ By letters congruing to that effect,
+ The present death of Hamlet. Do it, England;
+ For like the hectic in my blood he rages,
+ And thou must cure me: till I know 'tis done,
+ Howe'er my haps, my joys were ne'er begun.
+
+ Exit
+
+SCENE IV. A plain in Denmark.
+
+ Enter FORTINBRAS, a Captain, and Soldiers, marching
+
+PRINCE FORTINBRAS
+
+ Go, captain, from me greet the Danish king;
+ Tell him that, by his licence, Fortinbras
+ Craves the conveyance of a promised march
+ Over his kingdom. You know the rendezvous.
+ If that his majesty would aught with us,
+ We shall express our duty in his eye;
+ And let him know so.
+
+Captain
+
+ I will do't, my lord.
+
+PRINCE FORTINBRAS
+
+ Go softly on.
+
+ Exeunt FORTINBRAS and Soldiers
+
+ Enter HAMLET, ROSENCRANTZ, GUILDENSTERN, and others
+
+HAMLET
+
+ Good sir, whose powers are these?
+
+Captain
+
+ They are of Norway, sir.
+
+HAMLET
+
+ How purposed, sir, I pray you?
+
+Captain
+
+ Against some part of Poland.
+
+HAMLET
+
+ Who commands them, sir?
+
+Captain
+
+ The nephews to old Norway, Fortinbras.
+
+HAMLET
+
+ Goes it against the main of Poland, sir,
+ Or for some frontier?
+
+Captain
+
+ Truly to speak, and with no addition,
+ We go to gain a little patch of ground
+ That hath in it no profit but the name.
+ To pay five ducats, five, I would not farm it;
+ Nor will it yield to Norway or the Pole
+ A ranker rate, should it be sold in fee.
+
+HAMLET
+
+ Why, then the Polack never will defend it.
+
+Captain
+
+ Yes, it is already garrison'd.
+
+HAMLET
+
+ Two thousand souls and twenty thousand ducats
+ Will not debate the question of this straw:
+ This is the imposthume of much wealth and peace,
+ That inward breaks, and shows no cause without
+ Why the man dies. I humbly thank you, sir.
+
+Captain
+
+ God be wi' you, sir.
+
+ Exit
+
+ROSENCRANTZ
+
+ Wilt please you go, my lord?
+
+HAMLET
+
+ I'll be with you straight go a little before.
+
+ Exeunt all except HAMLET
+ How all occasions do inform against me,
+ And spur my dull revenge! What is a man,
+ If his chief good and market of his time
+ Be but to sleep and feed? a beast, no more.
+ Sure, he that made us with such large discourse,
+ Looking before and after, gave us not
+ That control and god-like reason
+ To fust in us unused. Now, whether it be
+ Bestial oblivion, or some craven scruple
+ Of thinking too precisely on the event,
+ A thought which, quarter'd, hath but one part wisdom
+ And ever three parts coward, I do not know
+ Why yet I live to say 'This thing's to do;'
+ Sith I have cause and will and strength and means
+ To do't. Examples gross as earth exhort me:
+ Witness this army of such mass and charge
+ Led by a delicate and tender prince,
+ Whose spirit with divine ambition puff'd
+ Makes mouths at the invisible event,
+ Exposing what is mortal and unsure
+ To all that fortune, death and danger dare,
+ Even for an egg-shell. Rightly to be great
+ Is not to stir without great argument,
+ But greatly to find quarrel in a straw
+ When honour's at the stake. How stand I then,
+ That have a father kill'd, a mother stain'd,
+ Excitements of my reason and my blood,
+ And let all sleep? while, to my shame, I see
+ The imminent death of twenty thousand men,
+ That, for a fantasy and trick of fame,
+ Go to their graves like beds, fight for a plot
+ Whereon the numbers cannot try the cause,
+ Which is not tomb enough and continent
+ To hide the slain? O, from this time forth,
+ My thoughts be bloody, or be nothing worth!
+
+ Exit
+
+SCENE V. Elsinore. A room in the castle.
+
+ Enter QUEEN GERTRUDE, HORATIO, and a Gentleman
+
+QUEEN GERTRUDE
+
+ I will not speak with her.
+
+Gentleman
+
+ She is importunate, indeed distract:
+ Her mood will needs be pitied.
+
+QUEEN GERTRUDE
+
+ What would she have?
+
+Gentleman
+
+ She speaks much of her father; says she hears
+ There's tricks i' the world; and hems, and beats her heart;
+ Spurns enviously at straws; speaks things in doubt,
+ That carry but half sense: her speech is nothing,
+ Yet the unshaped use of it doth move
+ The hearers to collection; they aim at it,
+ And botch the words up fit to their own thoughts;
+ Which, as her winks, and nods, and gestures
+ yield them,
+ Indeed would make one think there might be thought,
+ Though nothing sure, yet much unhappily.
+
+HORATIO
+
+ 'Twere good she were spoken with; for she may strew
+ Dangerous conjectures in ill-breeding minds.
+
+QUEEN GERTRUDE
+
+ Let her come in.
+
+ Exit HORATIO
+ To my sick soul, as sin's true nature is,
+ Each toy seems prologue to some great amiss:
+ So full of artless jealousy is guilt,
+ It spills itself in fearing to be spilt.
+
+ Re-enter HORATIO, with OPHELIA
+
+OPHELIA
+
+ Where is the beauteous majesty of Denmark?
+
+QUEEN GERTRUDE
+
+ How now, Ophelia!
+
+OPHELIA
+
+ [Sings]
+ How should I your true love know
+ From another one?
+ By his cockle hat and staff,
+ And his sandal shoon.
+
+QUEEN GERTRUDE
+
+ Alas, sweet lady, what imports this song?
+
+OPHELIA
+
+ Say you? nay, pray you, mark.
+
+ Sings
+ He is dead and gone, lady,
+ He is dead and gone;
+ At his head a grass-green turf,
+ At his heels a stone.
+
+QUEEN GERTRUDE
+
+ Nay, but, Ophelia,--
+
+OPHELIA
+
+ Pray you, mark.
+
+ Sings
+ White his shroud as the mountain snow,--
+
+ Enter KING CLAUDIUS
+
+QUEEN GERTRUDE
+
+ Alas, look here, my lord.
+
+OPHELIA
+
+ [Sings]
+ Larded with sweet flowers
+ Which bewept to the grave did go
+ With true-love showers.
+
+KING CLAUDIUS
+
+ How do you, pretty lady?
+
+OPHELIA
+
+ Well, God 'ild you! They say the owl was a baker's
+ daughter. Lord, we know what we are, but know not
+ what we may be. God be at your table!
+
+KING CLAUDIUS
+
+ Conceit upon her father.
+
+OPHELIA
+
+ Pray you, let's have no words of this; but when they
+ ask you what it means, say you this:
+
+ Sings
+ To-morrow is Saint Valentine's day,
+ All in the morning betime,
+ And I a maid at your window,
+ To be your Valentine.
+ Then up he rose, and donn'd his clothes,
+ And dupp'd the chamber-door;
+ Let in the maid, that out a maid
+ Never departed more.
+
+KING CLAUDIUS
+
+ Pretty Ophelia!
+
+OPHELIA
+
+ Indeed, la, without an oath, I'll make an end on't:
+
+ Sings
+ By Gis and by Saint Charity,
+ Alack, and fie for shame!
+ Young men will do't, if they come to't;
+ By cock, they are to blame.
+ Quoth she, before you tumbled me,
+ You promised me to wed.
+ So would I ha' done, by yonder sun,
+ An thou hadst not come to my bed.
+
+KING CLAUDIUS
+
+ How long hath she been thus?
+
+OPHELIA
+
+ I hope all will be well. We must be patient: but I
+ cannot choose but weep, to think they should lay him
+ i' the cold ground. My brother shall know of it:
+ and so I thank you for your good counsel. Come, my
+ coach! Good night, ladies; good night, sweet ladies;
+ good night, good night.
+
+ Exit
+
+KING CLAUDIUS
+
+ Follow her close; give her good watch,
+ I pray you.
+
+ Exit HORATIO
+ O, this is the poison of deep grief; it springs
+ All from her father's death. O Gertrude, Gertrude,
+ When sorrows come, they come not single spies
+ But in battalions. First, her father slain:
+ Next, your son gone; and he most violent author
+ Of his own just remove: the people muddied,
+ Thick and unwholesome in their thoughts and whispers,
+ For good Polonius' death; and we have done but greenly,
+ In hugger-mugger to inter him: poor Ophelia
+ Divided from herself and her fair judgment,
+ Without the which we are pictures, or mere beasts:
+ Last, and as much containing as all these,
+ Her brother is in secret come from France;
+ Feeds on his wonder, keeps himself in clouds,
+ And wants not buzzers to infect his ear
+ With pestilent speeches of his father's death;
+ Wherein necessity, of matter beggar'd,
+ Will nothing stick our person to arraign
+ In ear and ear. O my dear Gertrude, this,
+ Like to a murdering-piece, in many places
+ Gives me superfluous death.
+
+ A noise within
+
+QUEEN GERTRUDE
+
+ Alack, what noise is this?
+
+KING CLAUDIUS
+
+ Where are my Switzers? Let them guard the door.
+
+ Enter another Gentleman
+ What is the matter?
+
+Gentleman
+
+ Save yourself, my lord:
+ The ocean, overpeering of his list,
+ Eats not the flats with more impetuous haste
+ Than young Laertes, in a riotous head,
+ O'erbears your officers. The rabble call him lord;
+ And, as the world were now but to begin,
+ Antiquity forgot, custom not known,
+ The ratifiers and props of every word,
+ They cry 'Choose we: Laertes shall be king:'
+ Caps, hands, and tongues, applaud it to the clouds:
+ 'Laertes shall be king, Laertes king!'
+
+QUEEN GERTRUDE
+
+ How cheerfully on the false trail they cry!
+ O, this is counter, you false Danish dogs!
+
+KING CLAUDIUS
+
+ The doors are broke.
+
+ Noise within
+
+ Enter LAERTES, armed; Danes following
+
+LAERTES
+
+ Where is this king? Sirs, stand you all without.
+
+Danes
+
+ No, let's come in.
+
+LAERTES
+
+ I pray you, give me leave.
+
+Danes
+
+ We will, we will.
+
+ They retire without the door
+
+LAERTES
+
+ I thank you: keep the door. O thou vile king,
+ Give me my father!
+
+QUEEN GERTRUDE
+
+ Calmly, good Laertes.
+
+LAERTES
+
+ That drop of blood that's calm proclaims me bastard,
+ Cries cuckold to my father, brands the harlot
+ Even here, between the chaste unsmirched brow
+ Of my true mother.
+
+KING CLAUDIUS
+
+ What is the cause, Laertes,
+ That thy rebellion looks so giant-like?
+ Let him go, Gertrude; do not fear our person:
+ There's such divinity doth hedge a king,
+ That treason can but peep to what it would,
+ Acts little of his will. Tell me, Laertes,
+ Why thou art thus incensed. Let him go, Gertrude.
+ Speak, man.
+
+LAERTES
+
+ Where is my father?
+
+KING CLAUDIUS
+
+ Dead.
+
+QUEEN GERTRUDE
+
+ But not by him.
+
+KING CLAUDIUS
+
+ Let him demand his fill.
+
+LAERTES
+
+ How came he dead? I'll not be juggled with:
+ To hell, allegiance! vows, to the blackest devil!
+ Conscience and grace, to the profoundest pit!
+ I dare damnation. To this point I stand,
+ That both the worlds I give to negligence,
+ Let come what comes; only I'll be revenged
+ Most thoroughly for my father.
+
+KING CLAUDIUS
+
+ Who shall stay you?
+
+LAERTES
+
+ My will, not all the world:
+ And for my means, I'll husband them so well,
+ They shall go far with little.
+
+KING CLAUDIUS
+
+ Good Laertes,
+ If you desire to know the certainty
+ Of your dear father's death, is't writ in your revenge,
+ That, swoopstake, you will draw both friend and foe,
+ Winner and loser?
+
+LAERTES
+
+ None but his enemies.
+
+KING CLAUDIUS
+
+ Will you know them then?
+
+LAERTES
+
+ To his good friends thus wide I'll ope my arms;
+ And like the kind life-rendering pelican,
+ Repast them with my blood.
+
+KING CLAUDIUS
+
+ Why, now you speak
+ Like a good child and a true gentleman.
+ That I am guiltless of your father's death,
+ And am most sensible in grief for it,
+ It shall as level to your judgment pierce
+ As day does to your eye.
+
+Danes
+
+ [Within] Let her come in.
+
+LAERTES
+
+ How now! what noise is that?
+
+ Re-enter OPHELIA
+ O heat, dry up my brains! tears seven times salt,
+ Burn out the sense and virtue of mine eye!
+ By heaven, thy madness shall be paid by weight,
+ Till our scale turn the beam. O rose of May!
+ Dear maid, kind sister, sweet Ophelia!
+ O heavens! is't possible, a young maid's wits
+ Should be as moral as an old man's life?
+ Nature is fine in love, and where 'tis fine,
+ It sends some precious instance of itself
+ After the thing it loves.
+
+OPHELIA
+
+ [Sings]
+ They bore him barefaced on the bier;
+ Hey non nonny, nonny, hey nonny;
+ And in his grave rain'd many a tear:--
+ Fare you well, my dove!
+
+LAERTES
+
+ Hadst thou thy wits, and didst persuade revenge,
+ It could not move thus.
+
+OPHELIA
+
+ [Sings]
+ You must sing a-down a-down,
+ An you call him a-down-a.
+ O, how the wheel becomes it! It is the false
+ steward, that stole his master's daughter.
+
+LAERTES
+
+ This nothing's more than matter.
+
+OPHELIA
+
+ There's rosemary, that's for remembrance; pray,
+ love, remember: and there is pansies. that's for thoughts.
+
+LAERTES
+
+ A document in madness, thoughts and remembrance fitted.
+
+OPHELIA
+
+ There's fennel for you, and columbines: there's rue
+ for you; and here's some for me: we may call it
+ herb-grace o' Sundays: O you must wear your rue with
+ a difference. There's a daisy: I would give you
+ some violets, but they withered all when my father
+ died: they say he made a good end,--
+
+ Sings
+ For bonny sweet Robin is all my joy.
+
+LAERTES
+
+ Thought and affliction, passion, hell itself,
+ She turns to favour and to prettiness.
+
+OPHELIA
+
+ [Sings]
+ And will he not come again?
+ And will he not come again?
+ No, no, he is dead:
+ Go to thy death-bed:
+ He never will come again.
+ His beard was as white as snow,
+ All flaxen was his poll:
+ He is gone, he is gone,
+ And we cast away moan:
+ God ha' mercy on his soul!
+ And of all Christian souls, I pray God. God be wi' ye.
+
+ Exit
+
+LAERTES
+
+ Do you see this, O God?
+
+KING CLAUDIUS
+
+ Laertes, I must commune with your grief,
+ Or you deny me right. Go but apart,
+ Make choice of whom your wisest friends you will.
+ And they shall hear and judge 'twixt you and me:
+ If by direct or by collateral hand
+ They find us touch'd, we will our kingdom give,
+ Our crown, our life, and all that we can ours,
+ To you in satisfaction; but if not,
+ Be you content to lend your patience to us,
+ And we shall jointly labour with your soul
+ To give it due content.
+
+LAERTES
+
+ Let this be so;
+ His means of death, his obscure funeral--
+ No trophy, sword, nor hatchment o'er his bones,
+ No noble rite nor formal ostentation--
+ Cry to be heard, as 'twere from heaven to earth,
+ That I must call't in question.
+
+KING CLAUDIUS
+
+ So you shall;
+ And where the offence is let the great axe fall.
+ I pray you, go with me.
+
+ Exeunt
+
+SCENE VI. Another room in the castle.
+
+ Enter HORATIO and a Servant
+
+HORATIO
+
+ What are they that would speak with me?
+
+Servant
+
+ Sailors, sir: they say they have letters for you.
+
+HORATIO
+
+ Let them come in.
+
+ Exit Servant
+ I do not know from what part of the world
+ I should be greeted, if not from Lord Hamlet.
+
+ Enter Sailors
+
+First Sailor
+
+ God bless you, sir.
+
+HORATIO
+
+ Let him bless thee too.
+
+First Sailor
+
+ He shall, sir, an't please him. There's a letter for
+ you, sir; it comes from the ambassador that was
+ bound for England; if your name be Horatio, as I am
+ let to know it is.
+
+HORATIO
+
+ [Reads] 'Horatio, when thou shalt have overlooked
+ this, give these fellows some means to the king:
+ they have letters for him. Ere we were two days old
+ at sea, a pirate of very warlike appointment gave us
+ chase. Finding ourselves too slow of sail, we put on
+ a compelled valour, and in the grapple I boarded
+ them: on the instant they got clear of our ship; so
+ I alone became their prisoner. They have dealt with
+ me like thieves of mercy: but they knew what they
+ did; I am to do a good turn for them. Let the king
+ have the letters I have sent; and repair thou to me
+ with as much speed as thou wouldst fly death. I
+ have words to speak in thine ear will make thee
+ dumb; yet are they much too light for the bore of
+ the matter. These good fellows will bring thee
+ where I am. Rosencrantz and Guildenstern hold their
+ course for England: of them I have much to tell
+ thee. Farewell.
+ 'He that thou knowest thine, HAMLET.'
+ Come, I will make you way for these your letters;
+ And do't the speedier, that you may direct me
+ To him from whom you brought them.
+
+ Exeunt
+
+SCENE VII. Another room in the castle.
+
+ Enter KING CLAUDIUS and LAERTES
+
+KING CLAUDIUS
+
+ Now must your conscience my acquaintance seal,
+ And you must put me in your heart for friend,
+ Sith you have heard, and with a knowing ear,
+ That he which hath your noble father slain
+ Pursued my life.
+
+LAERTES
+
+ It well appears: but tell me
+ Why you proceeded not against these feats,
+ So crimeful and so capital in nature,
+ As by your safety, wisdom, all things else,
+ You mainly were stirr'd up.
+
+KING CLAUDIUS
+
+ O, for two special reasons;
+ Which may to you, perhaps, seem much unsinew'd,
+ But yet to me they are strong. The queen his mother
+ Lives almost by his looks; and for myself--
+ My virtue or my plague, be it either which--
+ She's so conjunctive to my life and soul,
+ That, as the star moves not but in his sphere,
+ I could not but by her. The other motive,
+ Why to a public count I might not go,
+ Is the great love the general gender bear him;
+ Who, dipping all his faults in their affection,
+ Would, like the spring that turneth wood to stone,
+ Convert his gyves to graces; so that my arrows,
+ Too slightly timber'd for so loud a wind,
+ Would have reverted to my bow again,
+ And not where I had aim'd them.
+
+LAERTES
+
+ And so have I a noble father lost;
+ A sister driven into desperate terms,
+ Whose worth, if praises may go back again,
+ Stood challenger on mount of all the age
+ For her perfections: but my revenge will come.
+
+KING CLAUDIUS
+
+ Break not your sleeps for that: you must not think
+ That we are made of stuff so flat and dull
+ That we can let our beard be shook with danger
+ And think it pastime. You shortly shall hear more:
+ I loved your father, and we love ourself;
+ And that, I hope, will teach you to imagine--
+
+ Enter a Messenger
+ How now! what news?
+
+Messenger
+
+ Letters, my lord, from Hamlet:
+ This to your majesty; this to the queen.
+
+KING CLAUDIUS
+
+ From Hamlet! who brought them?
+
+Messenger
+
+ Sailors, my lord, they say; I saw them not:
+ They were given me by Claudio; he received them
+ Of him that brought them.
+
+KING CLAUDIUS
+
+ Laertes, you shall hear them. Leave us.
+
+ Exit Messenger
+
+ Reads
+ 'High and mighty, You shall know I am set naked on
+ your kingdom. To-morrow shall I beg leave to see
+ your kingly eyes: when I shall, first asking your
+ pardon thereunto, recount the occasion of my sudden
+ and more strange return. 'HAMLET.'
+ What should this mean? Are all the rest come back?
+ Or is it some abuse, and no such thing?
+
+LAERTES
+
+ Know you the hand?
+
+KING CLAUDIUS
+
+ 'Tis Hamlets character. 'Naked!
+ And in a postscript here, he says 'alone.'
+ Can you advise me?
+
+LAERTES
+
+ I'm lost in it, my lord. But let him come;
+ It warms the very sickness in my heart,
+ That I shall live and tell him to his teeth,
+ 'Thus didest thou.'
+
+KING CLAUDIUS
+
+ If it be so, Laertes--
+ As how should it be so? how otherwise?--
+ Will you be ruled by me?
+
+LAERTES
+
+ Ay, my lord;
+ So you will not o'errule me to a peace.
+
+KING CLAUDIUS
+
+ To thine own peace. If he be now return'd,
+ As checking at his voyage, and that he means
+ No more to undertake it, I will work him
+ To an exploit, now ripe in my device,
+ Under the which he shall not choose but fall:
+ And for his death no wind of blame shall breathe,
+ But even his mother shall uncharge the practise
+ And call it accident.
+
+LAERTES
+
+ My lord, I will be ruled;
+ The rather, if you could devise it so
+ That I might be the organ.
+
+KING CLAUDIUS
+
+ It falls right.
+ You have been talk'd of since your travel much,
+ And that in Hamlet's hearing, for a quality
+ Wherein, they say, you shine: your sum of parts
+ Did not together pluck such envy from him
+ As did that one, and that, in my regard,
+ Of the unworthiest siege.
+
+LAERTES
+
+ What part is that, my lord?
+
+KING CLAUDIUS
+
+ A very riband in the id of youth,
+ Yet needful too; for youth no less becomes
+ The light and careless livery that it wears
+ Than settled age his sables and his weeds,
+ Importing health and graveness. Two months since,
+ Here was a gentleman of Normandy:--
+ I've seen myself, and served against, the French,
+ And they can well on horseback: but this gallant
+ Had witchcraft in't; he grew unto his seat;
+ And to such wondrous doing brought his horse,
+ As he had been incorpsed and demi-natured
+ With the brave beast: so far he topp'd my thought,
+ That I, in forgery of shapes and tricks,
+ Come short of what he did.
+
+LAERTES
+
+ A Norman was't?
+
+KING CLAUDIUS
+
+ A Norman.
+
+LAERTES
+
+ Upon my life, Lamond.
+
+KING CLAUDIUS
+
+ The very same.
+
+LAERTES
+
+ I know him well: he is the brooch indeed
+ And gem of all the nation.
+
+KING CLAUDIUS
+
+ He made confession of you,
+ And gave you such a masterly report
+ For art and exercise in your defence
+ And for your rapier most especially,
+ That he cried out, 'twould be a sight indeed,
+ If one could match you: the scrimers of their nation,
+ He swore, had had neither motion, guard, nor eye,
+ If you opposed them. Sir, this report of his
+ Did Hamlet so envenom with his envy
+ That he could nothing do but wish and beg
+ Your sudden coming o'er, to play with him.
+ Now, out of this,--
+
+LAERTES
+
+ What out of this, my lord?
+
+KING CLAUDIUS
+
+ Laertes, was your father dear to you?
+ Or are you like the painting of a sorrow,
+ A face without a heart?
+
+LAERTES
+
+ Why ask you this?
+
+KING CLAUDIUS
+
+ Not that I think you did not love your father;
+ But that I know love is begun by time;
+ And that I see, in passages of proof,
+ Time qualifies the spark and fire of it.
+ There lives within the very flame of love
+ A kind of wick or snuff that will abate it;
+ And nothing is at a like goodness still;
+ For goodness, growing to a plurisy,
+ Dies in his own too much: that we would do
+ We should do when we would; for this 'would' changes
+ And hath abatements and delays as many
+ As there are tongues, are hands, are accidents;
+ And then this 'should' is like a spendthrift sigh,
+ That hurts by easing. But, to the quick o' the ulcer:--
+ Hamlet comes back: what would you undertake,
+ To show yourself your father's son in deed
+ More than in words?
+
+LAERTES
+
+ To cut his throat i' the church.
+
+KING CLAUDIUS
+
+ No place, indeed, should murder sanctuarize;
+ Revenge should have no bounds. But, good Laertes,
+ Will you do this, keep close within your chamber.
+ Hamlet return'd shall know you are come home:
+ We'll put on those shall praise your excellence
+ And set a double varnish on the fame
+ The Frenchman gave you, bring you in fine together
+ And wager on your heads: he, being remiss,
+ Most generous and free from all contriving,
+ Will not peruse the foils; so that, with ease,
+ Or with a little shuffling, you may choose
+ A sword unbated, and in a pass of practise
+ Requite him for your father.
+
+LAERTES
+
+ I will do't:
+ And, for that purpose, I'll anoint my sword.
+ I bought an unction of a mountebank,
+ So mortal that, but dip a knife in it,
+ Where it draws blood no cataplasm so rare,
+ Collected from all simples that have virtue
+ Under the moon, can save the thing from death
+ That is but scratch'd withal: I'll touch my point
+ With this contagion, that, if I gall him slightly,
+ It may be death.
+
+KING CLAUDIUS
+
+ Let's further think of this;
+ Weigh what convenience both of time and means
+ May fit us to our shape: if this should fail,
+ And that our drift look through our bad performance,
+ 'Twere better not assay'd: therefore this project
+ Should have a back or second, that might hold,
+ If this should blast in proof. Soft! let me see:
+ We'll make a solemn wager on your cunnings: I ha't.
+ When in your motion you are hot and dry--
+ As make your bouts more violent to that end--
+ And that he calls for drink, I'll have prepared him
+ A chalice for the nonce, whereon but sipping,
+ If he by chance escape your venom'd stuck,
+ Our purpose may hold there.
+
+ Enter QUEEN GERTRUDE
+ How now, sweet queen!
+
+QUEEN GERTRUDE
+
+ One woe doth tread upon another's heel,
+ So fast they follow; your sister's drown'd, Laertes.
+
+LAERTES
+
+ Drown'd! O, where?
+
+QUEEN GERTRUDE
+
+ There is a willow grows aslant a brook,
+ That shows his hoar leaves in the glassy stream;
+ There with fantastic garlands did she come
+ Of crow-flowers, nettles, daisies, and long purples
+ That liberal shepherds give a grosser name,
+ But our cold maids do dead men's fingers call them:
+ There, on the pendent boughs her coronet weeds
+ Clambering to hang, an envious sliver broke;
+ When down her weedy trophies and herself
+ Fell in the weeping brook. Her clothes spread wide;
+ And, mermaid-like, awhile they bore her up:
+ Which time she chanted snatches of old tunes;
+ As one incapable of her own distress,
+ Or like a creature native and indued
+ Unto that element: but long it could not be
+ Till that her garments, heavy with their drink,
+ Pull'd the poor wretch from her melodious lay
+ To muddy death.
+
+LAERTES
+
+ Alas, then, she is drown'd?
+
+QUEEN GERTRUDE
+
+ Drown'd, drown'd.
+
+LAERTES
+
+ Too much of water hast thou, poor Ophelia,
+ And therefore I forbid my tears: but yet
+ It is our trick; nature her custom holds,
+ Let shame say what it will: when these are gone,
+ The woman will be out. Adieu, my lord:
+ I have a speech of fire, that fain would blaze,
+ But that this folly douts it.
+
+ Exit
+
+KING CLAUDIUS
+
+ Let's follow, Gertrude:
+ How much I had to do to calm his rage!
+ Now fear I this will give it start again;
+ Therefore let's follow.
+
+ Exeunt
+
+ACT V
+SCENE I. A churchyard.
+
+ Enter two Clowns, with spades, & c
+
+First Clown
+
+ Is she to be buried in Christian burial that
+ wilfully seeks her own salvation?
+
+Second Clown
+
+ I tell thee she is: and therefore make her grave
+ straight: the crowner hath sat on her, and finds it
+ Christian burial.
+
+First Clown
+
+ How can that be, unless she drowned herself in her
+ own defence?
+
+Second Clown
+
+ Why, 'tis found so.
+
+First Clown
+
+ It must be 'se offendendo;' it cannot be else. For
+ here lies the point: if I drown myself wittingly,
+ it argues an act: and an act hath three branches: it
+ is, to act, to do, to perform: argal, she drowned
+ herself wittingly.
+
+Second Clown
+
+ Nay, but hear you, goodman delver,--
+
+First Clown
+
+ Give me leave. Here lies the water; good: here
+ stands the man; good; if the man go to this water,
+ and drown himself, it is, will he, nill he, he
+ goes,--mark you that; but if the water come to him
+ and drown him, he drowns not himself: argal, he
+ that is not guilty of his own death shortens not his own life.
+
+Second Clown
+
+ But is this law?
+
+First Clown
+
+ Ay, marry, is't; crowner's quest law.
+
+Second Clown
+
+ Will you ha' the truth on't? If this had not been
+ a gentlewoman, she should have been buried out o'
+ Christian burial.
+
+First Clown
+
+ Why, there thou say'st: and the more pity that
+ great folk should have countenance in this world to
+ drown or hang themselves, more than their even
+ Christian. Come, my spade. There is no ancient
+ gentleman but gardeners, ditchers, and grave-makers:
+ they hold up Adam's profession.
+
+Second Clown
+
+ Was he a gentleman?
+
+First Clown
+
+ He was the first that ever bore arms.
+
+Second Clown
+
+ Why, he had none.
+
+First Clown
+
+ What, art a heathen? How dost thou understand the
+ Scripture? The Scripture says 'Adam digged:'
+ could he dig without arms? I'll put another
+ question to thee: if thou answerest me not to the
+ purpose, confess thyself--
+
+Second Clown
+
+ Go to.
+
+First Clown
+
+ What is he that builds stronger than either the
+ mason, the shipwright, or the carpenter?
+
+Second Clown
+
+ The gallows-maker; for that frame outlives a
+ thousand tenants.
+
+First Clown
+
+ I like thy wit well, in good faith: the gallows
+ does well; but how does it well? it does well to
+ those that do in: now thou dost ill to say the
+ gallows is built stronger than the church: argal,
+ the gallows may do well to thee. To't again, come.
+
+Second Clown
+
+ 'Who builds stronger than a mason, a shipwright, or
+ a carpenter?'
+
+First Clown
+
+ Ay, tell me that, and unyoke.
+
+Second Clown
+
+ Marry, now I can tell.
+
+First Clown
+
+ To't.
+
+Second Clown
+
+ Mass, I cannot tell.
+
+ Enter HAMLET and HORATIO, at a distance
+
+First Clown
+
+ Cudgel thy brains no more about it, for your dull
+ ass will not mend his pace with beating; and, when
+ you are asked this question next, say 'a
+ grave-maker: 'the houses that he makes last till
+ doomsday. Go, get thee to Yaughan: fetch me a
+ stoup of liquor.
+
+ Exit Second Clown
+
+ He digs and sings
+ In youth, when I did love, did love,
+ Methought it was very sweet,
+ To contract, O, the time, for, ah, my behove,
+ O, methought, there was nothing meet.
+
+HAMLET
+
+ Has this fellow no feeling of his business, that he
+ sings at grave-making?
+
+HORATIO
+
+ Custom hath made it in him a property of easiness.
+
+HAMLET
+
+ 'Tis e'en so: the hand of little employment hath
+ the daintier sense.
+
+First Clown
+
+ [Sings]
+ But age, with his stealing steps,
+ Hath claw'd me in his clutch,
+ And hath shipped me intil the land,
+ As if I had never been such.
+
+ Throws up a skull
+
+HAMLET
+
+ That skull had a tongue in it, and could sing once:
+ how the knave jowls it to the ground, as if it were
+ Cain's jaw-bone, that did the first murder! It
+ might be the pate of a politician, which this ass
+ now o'er-reaches; one that would circumvent God,
+ might it not?
+
+HORATIO
+
+ It might, my lord.
+
+HAMLET
+
+ Or of a courtier; which could say 'Good morrow,
+ sweet lord! How dost thou, good lord?' This might
+ be my lord such-a-one, that praised my lord
+ such-a-one's horse, when he meant to beg it; might it not?
+
+HORATIO
+
+ Ay, my lord.
+
+HAMLET
+
+ Why, e'en so: and now my Lady Worm's; chapless, and
+ knocked about the mazzard with a sexton's spade:
+ here's fine revolution, an we had the trick to
+ see't. Did these bones cost no more the breeding,
+ but to play at loggats with 'em? mine ache to think on't.
+
+First Clown
+
+ [Sings]
+ A pick-axe, and a spade, a spade,
+ For and a shrouding sheet:
+ O, a pit of clay for to be made
+ For such a guest is meet.
+
+ Throws up another skull
+
+HAMLET
+
+ There's another: why may not that be the skull of a
+ lawyer? Where be his quiddities now, his quillets,
+ his cases, his tenures, and his tricks? why does he
+ suffer this rude knave now to knock him about the
+ sconce with a dirty shovel, and will not tell him of
+ his action of battery? Hum! This fellow might be
+ in's time a great buyer of land, with his statutes,
+ his recognizances, his fines, his double vouchers,
+ his recoveries: is this the fine of his fines, and
+ the recovery of his recoveries, to have his fine
+ pate full of fine dirt? will his vouchers vouch him
+ no more of his purchases, and double ones too, than
+ the length and breadth of a pair of indentures? The
+ very conveyances of his lands will hardly lie in
+ this box; and must the inheritor himself have no more, ha?
+
+HORATIO
+
+ Not a jot more, my lord.
+
+HAMLET
+
+ Is not parchment made of sheepskins?
+
+HORATIO
+
+ Ay, my lord, and of calf-skins too.
+
+HAMLET
+
+ They are sheep and calves which seek out assurance
+ in that. I will speak to this fellow. Whose
+ grave's this, sirrah?
+
+First Clown
+
+ Mine, sir.
+
+ Sings
+ O, a pit of clay for to be made
+ For such a guest is meet.
+
+HAMLET
+
+ I think it be thine, indeed; for thou liest in't.
+
+First Clown
+
+ You lie out on't, sir, and therefore it is not
+ yours: for my part, I do not lie in't, and yet it is mine.
+
+HAMLET
+
+ 'Thou dost lie in't, to be in't and say it is thine:
+ 'tis for the dead, not for the quick; therefore thou liest.
+
+First Clown
+
+ 'Tis a quick lie, sir; 'twill away gain, from me to
+ you.
+
+HAMLET
+
+ What man dost thou dig it for?
+
+First Clown
+
+ For no man, sir.
+
+HAMLET
+
+ What woman, then?
+
+First Clown
+
+ For none, neither.
+
+HAMLET
+
+ Who is to be buried in't?
+
+First Clown
+
+ One that was a woman, sir; but, rest her soul, she's dead.
+
+HAMLET
+
+ How absolute the knave is! we must speak by the
+ card, or equivocation will undo us. By the Lord,
+ Horatio, these three years I have taken a note of
+ it; the age is grown so picked that the toe of the
+ peasant comes so near the heel of the courtier, he
+ gaffs his kibe. How long hast thou been a
+ grave-maker?
+
+First Clown
+
+ Of all the days i' the year, I came to't that day
+ that our last king Hamlet overcame Fortinbras.
+
+HAMLET
+
+ How long is that since?
+
+First Clown
+
+ Cannot you tell that? every fool can tell that: it
+ was the very day that young Hamlet was born; he that
+ is mad, and sent into England.
+
+HAMLET
+
+ Ay, marry, why was he sent into England?
+
+First Clown
+
+ Why, because he was mad: he shall recover his wits
+ there; or, if he do not, it's no great matter there.
+
+HAMLET
+
+ Why?
+
+First Clown
+
+ 'Twill, a not be seen in him there; there the men
+ are as mad as he.
+
+HAMLET
+
+ How came he mad?
+
+First Clown
+
+ Very strangely, they say.
+
+HAMLET
+
+ How strangely?
+
+First Clown
+
+ Faith, e'en with losing his wits.
+
+HAMLET
+
+ Upon what ground?
+
+First Clown
+
+ Why, here in Denmark: I have been sexton here, man
+ and boy, thirty years.
+
+HAMLET
+
+ How long will a man lie i' the earth ere he rot?
+
+First Clown
+
+ I' faith, if he be not rotten before he die--as we
+ have many pocky corses now-a-days, that will scarce
+ hold the laying in--he will last you some eight year
+ or nine year: a tanner will last you nine year.
+
+HAMLET
+
+ Why he more than another?
+
+First Clown
+
+ Why, sir, his hide is so tanned with his trade, that
+ he will keep out water a great while; and your water
+ is a sore decayer of your whoreson dead body.
+ Here's a skull now; this skull has lain in the earth
+ three and twenty years.
+
+HAMLET
+
+ Whose was it?
+
+First Clown
+
+ A whoreson mad fellow's it was: whose do you think it was?
+
+HAMLET
+
+ Nay, I know not.
+
+First Clown
+
+ A pestilence on him for a mad rogue! a' poured a
+ flagon of Rhenish on my head once. This same skull,
+ sir, was Yorick's skull, the king's jester.
+
+HAMLET
+
+ This?
+
+First Clown
+
+ E'en that.
+
+HAMLET
+
+ Let me see.
+
+ Takes the skull
+ Alas, poor Yorick! I knew him, Horatio: a fellow
+ of infinite jest, of most excellent fancy: he hath
+ borne me on his back a thousand times; and now, how
+ abhorred in my imagination it is! my gorge rims at
+ it. Here hung those lips that I have kissed I know
+ not how oft. Where be your gibes now? your
+ gambols? your songs? your flashes of merriment,
+ that were wont to set the table on a roar? Not one
+ now, to mock your own grinning? quite chap-fallen?
+ Now get you to my lady's chamber, and tell her, let
+ her paint an inch thick, to this favour she must
+ come; make her laugh at that. Prithee, Horatio, tell
+ me one thing.
+
+HORATIO
+
+ What's that, my lord?
+
+HAMLET
+
+ Dost thou think Alexander looked o' this fashion i'
+ the earth?
+
+HORATIO
+
+ E'en so.
+
+HAMLET
+
+ And smelt so? pah!
+
+ Puts down the skull
+
+HORATIO
+
+ E'en so, my lord.
+
+HAMLET
+
+ To what base uses we may return, Horatio! Why may
+ not imagination trace the noble dust of Alexander,
+ till he find it stopping a bung-hole?
+
+HORATIO
+
+ 'Twere to consider too curiously, to consider so.
+
+HAMLET
+
+ No, faith, not a jot; but to follow him thither with
+ modesty enough, and likelihood to lead it: as
+ thus: Alexander died, Alexander was buried,
+ Alexander returneth into dust; the dust is earth; of
+ earth we make loam; and why of that loam, whereto he
+ was converted, might they not stop a beer-barrel?
+ Imperious Caesar, dead and turn'd to clay,
+ Might stop a hole to keep the wind away:
+ O, that that earth, which kept the world in awe,
+ Should patch a wall to expel the winter flaw!
+ But soft! but soft! aside: here comes the king.
+
+ Enter Priest, & c. in procession; the Corpse of OPHELIA, LAERTES and Mourners following; KING CLAUDIUS, QUEEN GERTRUDE, their trains, & c
+ The queen, the courtiers: who is this they follow?
+ And with such maimed rites? This doth betoken
+ The corse they follow did with desperate hand
+ Fordo its own life: 'twas of some estate.
+ Couch we awhile, and mark.
+
+ Retiring with HORATIO
+
+LAERTES
+
+ What ceremony else?
+
+HAMLET
+
+ That is Laertes,
+ A very noble youth: mark.
+
+LAERTES
+
+ What ceremony else?
+
+First Priest
+
+ Her obsequies have been as far enlarged
+ As we have warrantise: her death was doubtful;
+ And, but that great command o'ersways the order,
+ She should in ground unsanctified have lodged
+ Till the last trumpet: for charitable prayers,
+ Shards, flints and pebbles should be thrown on her;
+ Yet here she is allow'd her virgin crants,
+ Her maiden strewments and the bringing home
+ Of bell and burial.
+
+LAERTES
+
+ Must there no more be done?
+
+First Priest
+
+ No more be done:
+ We should profane the service of the dead
+ To sing a requiem and such rest to her
+ As to peace-parted souls.
+
+LAERTES
+
+ Lay her i' the earth:
+ And from her fair and unpolluted flesh
+ May violets spring! I tell thee, churlish priest,
+ A ministering angel shall my sister be,
+ When thou liest howling.
+
+HAMLET
+
+ What, the fair Ophelia!
+
+QUEEN GERTRUDE
+
+ Sweets to the sweet: farewell!
+
+ Scattering flowers
+ I hoped thou shouldst have been my Hamlet's wife;
+ I thought thy bride-bed to have deck'd, sweet maid,
+ And not have strew'd thy grave.
+
+LAERTES
+
+ O, treble woe
+ Fall ten times treble on that cursed head,
+ Whose wicked deed thy most ingenious sense
+ Deprived thee of! Hold off the earth awhile,
+ Till I have caught her once more in mine arms:
+
+ Leaps into the grave
+ Now pile your dust upon the quick and dead,
+ Till of this flat a mountain you have made,
+ To o'ertop old Pelion, or the skyish head
+ Of blue Olympus.
+
+HAMLET
+
+ [Advancing] What is he whose grief
+ Bears such an emphasis? whose phrase of sorrow
+ Conjures the wandering stars, and makes them stand
+ Like wonder-wounded hearers? This is I,
+ Hamlet the Dane.
+
+ Leaps into the grave
+
+LAERTES
+
+ The devil take thy soul!
+
+ Grappling with him
+
+HAMLET
+
+ Thou pray'st not well.
+ I prithee, take thy fingers from my throat;
+ For, though I am not splenitive and rash,
+ Yet have I something in me dangerous,
+ Which let thy wiseness fear: hold off thy hand.
+
+KING CLAUDIUS
+
+ Pluck them asunder.
+
+QUEEN GERTRUDE
+
+ Hamlet, Hamlet!
+
+All
+
+ Gentlemen,--
+
+HORATIO
+
+ Good my lord, be quiet.
+
+ The Attendants part them, and they come out of the grave
+
+HAMLET
+
+ Why I will fight with him upon this theme
+ Until my eyelids will no longer wag.
+
+QUEEN GERTRUDE
+
+ O my son, what theme?
+
+HAMLET
+
+ I loved Ophelia: forty thousand brothers
+ Could not, with all their quantity of love,
+ Make up my sum. What wilt thou do for her?
+
+KING CLAUDIUS
+
+ O, he is mad, Laertes.
+
+QUEEN GERTRUDE
+
+ For love of God, forbear him.
+
+HAMLET
+
+ 'Swounds, show me what thou'lt do:
+ Woo't weep? woo't fight? woo't fast? woo't tear thyself?
+ Woo't drink up eisel? eat a crocodile?
+ I'll do't. Dost thou come here to whine?
+ To outface me with leaping in her grave?
+ Be buried quick with her, and so will I:
+ And, if thou prate of mountains, let them throw
+ Millions of acres on us, till our ground,
+ Singeing his pate against the burning zone,
+ Make Ossa like a wart! Nay, an thou'lt mouth,
+ I'll rant as well as thou.
+
+QUEEN GERTRUDE
+
+ This is mere madness:
+ And thus awhile the fit will work on him;
+ Anon, as patient as the female dove,
+ When that her golden couplets are disclosed,
+ His silence will sit drooping.
+
+HAMLET
+
+ Hear you, sir;
+ What is the reason that you use me thus?
+ I loved you ever: but it is no matter;
+ Let Hercules himself do what he may,
+ The cat will mew and dog will have his day.
+
+ Exit
+
+KING CLAUDIUS
+
+ I pray you, good Horatio, wait upon him.
+
+ Exit HORATIO
+
+ To LAERTES
+ Strengthen your patience in our last night's speech;
+ We'll put the matter to the present push.
+ Good Gertrude, set some watch over your son.
+ This grave shall have a living monument:
+ An hour of quiet shortly shall we see;
+ Till then, in patience our proceeding be.
+
+ Exeunt
+
+SCENE II. A hall in the castle.
+
+ Enter HAMLET and HORATIO
+
+HAMLET
+
+ So much for this, sir: now shall you see the other;
+ You do remember all the circumstance?
+
+HORATIO
+
+ Remember it, my lord?
+
+HAMLET
+
+ Sir, in my heart there was a kind of fighting,
+ That would not let me sleep: methought I lay
+ Worse than the mutines in the bilboes. Rashly,
+ And praised be rashness for it, let us know,
+ Our indiscretion sometimes serves us well,
+ When our deep plots do pall: and that should teach us
+ There's a divinity that shapes our ends,
+ Rough-hew them how we will,--
+
+HORATIO
+
+ That is most certain.
+
+HAMLET
+
+ Up from my cabin,
+ My sea-gown scarf'd about me, in the dark
+ Groped I to find out them; had my desire.
+ Finger'd their packet, and in fine withdrew
+ To mine own room again; making so bold,
+ My fears forgetting manners, to unseal
+ Their grand commission; where I found, Horatio,--
+ O royal knavery!--an exact command,
+ Larded with many several sorts of reasons
+ Importing Denmark's health and England's too,
+ With, ho! such bugs and goblins in my life,
+ That, on the supervise, no leisure bated,
+ No, not to stay the grinding of the axe,
+ My head should be struck off.
+
+HORATIO
+
+ Is't possible?
+
+HAMLET
+
+ Here's the commission: read it at more leisure.
+ But wilt thou hear me how I did proceed?
+
+HORATIO
+
+ I beseech you.
+
+HAMLET
+
+ Being thus be-netted round with villanies,--
+ Ere I could make a prologue to my brains,
+ They had begun the play--I sat me down,
+ Devised a new commission, wrote it fair:
+ I once did hold it, as our statists do,
+ A baseness to write fair and labour'd much
+ How to forget that learning, but, sir, now
+ It did me yeoman's service: wilt thou know
+ The effect of what I wrote?
+
+HORATIO
+
+ Ay, good my lord.
+
+HAMLET
+
+ An earnest conjuration from the king,
+ As England was his faithful tributary,
+ As love between them like the palm might flourish,
+ As peace should stiff her wheaten garland wear
+ And stand a comma 'tween their amities,
+ And many such-like 'As'es of great charge,
+ That, on the view and knowing of these contents,
+ Without debatement further, more or less,
+ He should the bearers put to sudden death,
+ Not shriving-time allow'd.
+
+HORATIO
+
+ How was this seal'd?
+
+HAMLET
+
+ Why, even in that was heaven ordinant.
+ I had my father's signet in my purse,
+ Which was the model of that Danish seal;
+ Folded the writ up in form of the other,
+ Subscribed it, gave't the impression, placed it safely,
+ The changeling never known. Now, the next day
+ Was our sea-fight; and what to this was sequent
+ Thou know'st already.
+
+HORATIO
+
+ So Guildenstern and Rosencrantz go to't.
+
+HAMLET
+
+ Why, man, they did make love to this employment;
+ They are not near my conscience; their defeat
+ Does by their own insinuation grow:
+ 'Tis dangerous when the baser nature comes
+ Between the pass and fell incensed points
+ Of mighty opposites.
+
+HORATIO
+
+ Why, what a king is this!
+
+HAMLET
+
+ Does it not, think'st thee, stand me now upon--
+ He that hath kill'd my king and whored my mother,
+ Popp'd in between the election and my hopes,
+ Thrown out his angle for my proper life,
+ And with such cozenage--is't not perfect conscience,
+ To quit him with this arm? and is't not to be damn'd,
+ To let this canker of our nature come
+ In further evil?
+
+HORATIO
+
+ It must be shortly known to him from England
+ What is the issue of the business there.
+
+HAMLET
+
+ It will be short: the interim is mine;
+ And a man's life's no more than to say 'One.'
+ But I am very sorry, good Horatio,
+ That to Laertes I forgot myself;
+ For, by the image of my cause, I see
+ The portraiture of his: I'll court his favours.
+ But, sure, the bravery of his grief did put me
+ Into a towering passion.
+
+HORATIO
+
+ Peace! who comes here?
+
+ Enter OSRIC
+
+OSRIC
+
+ Your lordship is right welcome back to Denmark.
+
+HAMLET
+
+ I humbly thank you, sir. Dost know this water-fly?
+
+HORATIO
+
+ No, my good lord.
+
+HAMLET
+
+ Thy state is the more gracious; for 'tis a vice to
+ know him. He hath much land, and fertile: let a
+ beast be lord of beasts, and his crib shall stand at
+ the king's mess: 'tis a chough; but, as I say,
+ spacious in the possession of dirt.
+
+OSRIC
+
+ Sweet lord, if your lordship were at leisure, I
+ should impart a thing to you from his majesty.
+
+HAMLET
+
+ I will receive it, sir, with all diligence of
+ spirit. Put your bonnet to his right use; 'tis for the head.
+
+OSRIC
+
+ I thank your lordship, it is very hot.
+
+HAMLET
+
+ No, believe me, 'tis very cold; the wind is
+ northerly.
+
+OSRIC
+
+ It is indifferent cold, my lord, indeed.
+
+HAMLET
+
+ But yet methinks it is very sultry and hot for my
+ complexion.
+
+OSRIC
+
+ Exceedingly, my lord; it is very sultry,--as
+ 'twere,--I cannot tell how. But, my lord, his
+ majesty bade me signify to you that he has laid a
+ great wager on your head: sir, this is the matter,--
+
+HAMLET
+
+ I beseech you, remember--
+
+ HAMLET moves him to put on his hat
+
+OSRIC
+
+ Nay, good my lord; for mine ease, in good faith.
+ Sir, here is newly come to court Laertes; believe
+ me, an absolute gentleman, full of most excellent
+ differences, of very soft society and great showing:
+ indeed, to speak feelingly of him, he is the card or
+ calendar of gentry, for you shall find in him the
+ continent of what part a gentleman would see.
+
+HAMLET
+
+ Sir, his definement suffers no perdition in you;
+ though, I know, to divide him inventorially would
+ dizzy the arithmetic of memory, and yet but yaw
+ neither, in respect of his quick sail. But, in the
+ verity of extolment, I take him to be a soul of
+ great article; and his infusion of such dearth and
+ rareness, as, to make true diction of him, his
+ semblable is his mirror; and who else would trace
+ him, his umbrage, nothing more.
+
+OSRIC
+
+ Your lordship speaks most infallibly of him.
+
+HAMLET
+
+ The concernancy, sir? why do we wrap the gentleman
+ in our more rawer breath?
+
+OSRIC
+
+ Sir?
+
+HORATIO
+
+ Is't not possible to understand in another tongue?
+ You will do't, sir, really.
+
+HAMLET
+
+ What imports the nomination of this gentleman?
+
+OSRIC
+
+ Of Laertes?
+
+HORATIO
+
+ His purse is empty already; all's golden words are spent.
+
+HAMLET
+
+ Of him, sir.
+
+OSRIC
+
+ I know you are not ignorant--
+
+HAMLET
+
+ I would you did, sir; yet, in faith, if you did,
+ it would not much approve me. Well, sir?
+
+OSRIC
+
+ You are not ignorant of what excellence Laertes is--
+
+HAMLET
+
+ I dare not confess that, lest I should compare with
+ him in excellence; but, to know a man well, were to
+ know himself.
+
+OSRIC
+
+ I mean, sir, for his weapon; but in the imputation
+ laid on him by them, in his meed he's unfellowed.
+
+HAMLET
+
+ What's his weapon?
+
+OSRIC
+
+ Rapier and dagger.
+
+HAMLET
+
+ That's two of his weapons: but, well.
+
+OSRIC
+
+ The king, sir, hath wagered with him six Barbary
+ horses: against the which he has imponed, as I take
+ it, six French rapiers and poniards, with their
+ assigns, as girdle, hangers, and so: three of the
+ carriages, in faith, are very dear to fancy, very
+ responsive to the hilts, most delicate carriages,
+ and of very liberal conceit.
+
+HAMLET
+
+ What call you the carriages?
+
+HORATIO
+
+ I knew you must be edified by the margent ere you had done.
+
+OSRIC
+
+ The carriages, sir, are the hangers.
+
+HAMLET
+
+ The phrase would be more german to the matter, if we
+ could carry cannon by our sides: I would it might
+ be hangers till then. But, on: six Barbary horses
+ against six French swords, their assigns, and three
+ liberal-conceited carriages; that's the French bet
+ against the Danish. Why is this 'imponed,' as you call it?
+
+OSRIC
+
+ The king, sir, hath laid, that in a dozen passes
+ between yourself and him, he shall not exceed you
+ three hits: he hath laid on twelve for nine; and it
+ would come to immediate trial, if your lordship
+ would vouchsafe the answer.
+
+HAMLET
+
+ How if I answer 'no'?
+
+OSRIC
+
+ I mean, my lord, the opposition of your person in trial.
+
+HAMLET
+
+ Sir, I will walk here in the hall: if it please his
+ majesty, 'tis the breathing time of day with me; let
+ the foils be brought, the gentleman willing, and the
+ king hold his purpose, I will win for him an I can;
+ if not, I will gain nothing but my shame and the odd hits.
+
+OSRIC
+
+ Shall I re-deliver you e'en so?
+
+HAMLET
+
+ To this effect, sir; after what flourish your nature will.
+
+OSRIC
+
+ I commend my duty to your lordship.
+
+HAMLET
+
+ Yours, yours.
+
+ Exit OSRIC
+ He does well to commend it himself; there are no
+ tongues else for's turn.
+
+HORATIO
+
+ This lapwing runs away with the shell on his head.
+
+HAMLET
+
+ He did comply with his dug, before he sucked it.
+ Thus has he--and many more of the same bevy that I
+ know the dressy age dotes on--only got the tune of
+ the time and outward habit of encounter; a kind of
+ yesty collection, which carries them through and
+ through the most fond and winnowed opinions; and do
+ but blow them to their trial, the bubbles are out.
+
+ Enter a Lord
+
+Lord
+
+ My lord, his majesty commended him to you by young
+ Osric, who brings back to him that you attend him in
+ the hall: he sends to know if your pleasure hold to
+ play with Laertes, or that you will take longer time.
+
+HAMLET
+
+ I am constant to my purpose; they follow the king's
+ pleasure: if his fitness speaks, mine is ready; now
+ or whensoever, provided I be so able as now.
+
+Lord
+
+ The king and queen and all are coming down.
+
+HAMLET
+
+ In happy time.
+
+Lord
+
+ The queen desires you to use some gentle
+ entertainment to Laertes before you fall to play.
+
+HAMLET
+
+ She well instructs me.
+
+ Exit Lord
+
+HORATIO
+
+ You will lose this wager, my lord.
+
+HAMLET
+
+ I do not think so: since he went into France, I
+ have been in continual practise: I shall win at the
+ odds. But thou wouldst not think how ill all's here
+ about my heart: but it is no matter.
+
+HORATIO
+
+ Nay, good my lord,--
+
+HAMLET
+
+ It is but foolery; but it is such a kind of
+ gain-giving, as would perhaps trouble a woman.
+
+HORATIO
+
+ If your mind dislike any thing, obey it: I will
+ forestall their repair hither, and say you are not
+ fit.
+
+HAMLET
+
+ Not a whit, we defy augury: there's a special
+ providence in the fall of a sparrow. If it be now,
+ 'tis not to come; if it be not to come, it will be
+ now; if it be not now, yet it will come: the
+ readiness is all: since no man has aught of what he
+ leaves, what is't to leave betimes?
+
+ Enter KING CLAUDIUS, QUEEN GERTRUDE, LAERTES, Lords, OSRIC, and Attendants with foils, & c
+
+KING CLAUDIUS
+
+ Come, Hamlet, come, and take this hand from me.
+
+ KING CLAUDIUS puts LAERTES' hand into HAMLET's
+
+HAMLET
+
+ Give me your pardon, sir: I've done you wrong;
+ But pardon't, as you are a gentleman.
+ This presence knows,
+ And you must needs have heard, how I am punish'd
+ With sore distraction. What I have done,
+ That might your nature, honour and exception
+ Roughly awake, I here proclaim was madness.
+ Was't Hamlet wrong'd Laertes? Never Hamlet:
+ If Hamlet from himself be ta'en away,
+ And when he's not himself does wrong Laertes,
+ Then Hamlet does it not, Hamlet denies it.
+ Who does it, then? His madness: if't be so,
+ Hamlet is of the faction that is wrong'd;
+ His madness is poor Hamlet's enemy.
+ Sir, in this audience,
+ Let my disclaiming from a purposed evil
+ Free me so far in your most generous thoughts,
+ That I have shot mine arrow o'er the house,
+ And hurt my brother.
+
+LAERTES
+
+ I am satisfied in nature,
+ Whose motive, in this case, should stir me most
+ To my revenge: but in my terms of honour
+ I stand aloof; and will no reconcilement,
+ Till by some elder masters, of known honour,
+ I have a voice and precedent of peace,
+ To keep my name ungored. But till that time,
+ I do receive your offer'd love like love,
+ And will not wrong it.
+
+HAMLET
+
+ I embrace it freely;
+ And will this brother's wager frankly play.
+ Give us the foils. Come on.
+
+LAERTES
+
+ Come, one for me.
+
+HAMLET
+
+ I'll be your foil, Laertes: in mine ignorance
+ Your skill shall, like a star i' the darkest night,
+ Stick fiery off indeed.
+
+LAERTES
+
+ You mock me, sir.
+
+HAMLET
+
+ No, by this hand.
+
+KING CLAUDIUS
+
+ Give them the foils, young Osric. Cousin Hamlet,
+ You know the wager?
+
+HAMLET
+
+ Very well, my lord
+ Your grace hath laid the odds o' the weaker side.
+
+KING CLAUDIUS
+
+ I do not fear it; I have seen you both:
+ But since he is better'd, we have therefore odds.
+
+LAERTES
+
+ This is too heavy, let me see another.
+
+HAMLET
+
+ This likes me well. These foils have all a length?
+
+ They prepare to play
+
+OSRIC
+
+ Ay, my good lord.
+
+KING CLAUDIUS
+
+ Set me the stoops of wine upon that table.
+ If Hamlet give the first or second hit,
+ Or quit in answer of the third exchange,
+ Let all the battlements their ordnance fire:
+ The king shall drink to Hamlet's better breath;
+ And in the cup an union shall he throw,
+ Richer than that which four successive kings
+ In Denmark's crown have worn. Give me the cups;
+ And let the kettle to the trumpet speak,
+ The trumpet to the cannoneer without,
+ The cannons to the heavens, the heavens to earth,
+ 'Now the king dunks to Hamlet.' Come, begin:
+ And you, the judges, bear a wary eye.
+
+HAMLET
+
+ Come on, sir.
+
+LAERTES
+
+ Come, my lord.
+
+ They play
+
+HAMLET
+
+ One.
+
+LAERTES
+
+ No.
+
+HAMLET
+
+ Judgment.
+
+OSRIC
+
+ A hit, a very palpable hit.
+
+LAERTES
+
+ Well; again.
+
+KING CLAUDIUS
+
+ Stay; give me drink. Hamlet, this pearl is thine;
+ Here's to thy health.
+
+ Trumpets sound, and cannon shot off within
+ Give him the cup.
+
+HAMLET
+
+ I'll play this bout first; set it by awhile. Come.
+
+ They play
+ Another hit; what say you?
+
+LAERTES
+
+ A touch, a touch, I do confess.
+
+KING CLAUDIUS
+
+ Our son shall win.
+
+QUEEN GERTRUDE
+
+ He's fat, and scant of breath.
+ Here, Hamlet, take my napkin, rub thy brows;
+ The queen carouses to thy fortune, Hamlet.
+
+HAMLET
+
+ Good madam!
+
+KING CLAUDIUS
+
+ Gertrude, do not drink.
+
+QUEEN GERTRUDE
+
+ I will, my lord; I pray you, pardon me.
+
+KING CLAUDIUS
+
+ [Aside] It is the poison'd cup: it is too late.
+
+HAMLET
+
+ I dare not drink yet, madam; by and by.
+
+QUEEN GERTRUDE
+
+ Come, let me wipe thy face.
+
+LAERTES
+
+ My lord, I'll hit him now.
+
+KING CLAUDIUS
+
+ I do not think't.
+
+LAERTES
+
+ [Aside] And yet 'tis almost 'gainst my conscience.
+
+HAMLET
+
+ Come, for the third, Laertes: you but dally;
+ I pray you, pass with your best violence;
+ I am afeard you make a wanton of me.
+
+LAERTES
+
+ Say you so? come on.
+
+ They play
+
+OSRIC
+
+ Nothing, neither way.
+
+LAERTES
+
+ Have at you now!
+
+ LAERTES wounds HAMLET; then in scuffling, they change rapiers, and HAMLET wounds LAERTES
+
+KING CLAUDIUS
+
+ Part them; they are incensed.
+
+HAMLET
+
+ Nay, come, again.
+
+ QUEEN GERTRUDE falls
+
+OSRIC
+
+ Look to the queen there, ho!
+
+HORATIO
+
+ They bleed on both sides. How is it, my lord?
+
+OSRIC
+
+ How is't, Laertes?
+
+LAERTES
+
+ Why, as a woodcock to mine own springe, Osric;
+ I am justly kill'd with mine own treachery.
+
+HAMLET
+
+ How does the queen?
+
+KING CLAUDIUS
+
+ She swounds to see them bleed.
+
+QUEEN GERTRUDE
+
+ No, no, the drink, the drink,--O my dear Hamlet,--
+ The drink, the drink! I am poison'd.
+
+ Dies
+
+HAMLET
+
+ O villany! Ho! let the door be lock'd:
+ Treachery! Seek it out.
+
+LAERTES
+
+ It is here, Hamlet: Hamlet, thou art slain;
+ No medicine in the world can do thee good;
+ In thee there is not half an hour of life;
+ The treacherous instrument is in thy hand,
+ Unbated and envenom'd: the foul practise
+ Hath turn'd itself on me lo, here I lie,
+ Never to rise again: thy mother's poison'd:
+ I can no more: the king, the king's to blame.
+
+HAMLET
+
+ The point!--envenom'd too!
+ Then, venom, to thy work.
+
+ Stabs KING CLAUDIUS
+
+All
+
+ Treason! treason!
+
+KING CLAUDIUS
+
+ O, yet defend me, friends; I am but hurt.
+
+HAMLET
+
+ Here, thou incestuous, murderous, damned Dane,
+ Drink off this potion. Is thy union here?
+ Follow my mother.
+
+ KING CLAUDIUS dies
+
+LAERTES
+
+ He is justly served;
+ It is a poison temper'd by himself.
+ Exchange forgiveness with me, noble Hamlet:
+ Mine and my father's death come not upon thee,
+ Nor thine on me.
+
+ Dies
+
+HAMLET
+
+ Heaven make thee free of it! I follow thee.
+ I am dead, Horatio. Wretched queen, adieu!
+ You that look pale and tremble at this chance,
+ That are but mutes or audience to this act,
+ Had I but time--as this fell sergeant, death,
+ Is strict in his arrest--O, I could tell you--
+ But let it be. Horatio, I am dead;
+ Thou livest; report me and my cause aright
+ To the unsatisfied.
+
+HORATIO
+
+ Never believe it:
+ I am more an antique Roman than a Dane:
+ Here's yet some liquor left.
+
+HAMLET
+
+ As thou'rt a man,
+ Give me the cup: let go; by heaven, I'll have't.
+ O good Horatio, what a wounded name,
+ Things standing thus unknown, shall live behind me!
+ If thou didst ever hold me in thy heart
+ Absent thee from felicity awhile,
+ And in this harsh world draw thy breath in pain,
+ To tell my story.
+
+ March afar off, and shot within
+ What warlike noise is this?
+
+OSRIC
+
+ Young Fortinbras, with conquest come from Poland,
+ To the ambassadors of England gives
+ This warlike volley.
+
+HAMLET
+
+ O, I die, Horatio;
+ The potent poison quite o'er-crows my spirit:
+ I cannot live to hear the news from England;
+ But I do prophesy the election lights
+ On Fortinbras: he has my dying voice;
+ So tell him, with the occurrents, more and less,
+ Which have solicited. The rest is silence.
+
+ Dies
+
+HORATIO
+
+ Now cracks a noble heart. Good night sweet prince:
+ And flights of angels sing thee to thy rest!
+ Why does the drum come hither?
+
+ March within
+
+ Enter FORTINBRAS, the English Ambassadors, and others
+
+PRINCE FORTINBRAS
+
+ Where is this sight?
+
+HORATIO
+
+ What is it ye would see?
+ If aught of woe or wonder, cease your search.
+
+PRINCE FORTINBRAS
+
+ This quarry cries on havoc. O proud death,
+ What feast is toward in thine eternal cell,
+ That thou so many princes at a shot
+ So bloodily hast struck?
+
+First Ambassador
+
+ The sight is dismal;
+ And our affairs from England come too late:
+ The ears are senseless that should give us hearing,
+ To tell him his commandment is fulfill'd,
+ That Rosencrantz and Guildenstern are dead:
+ Where should we have our thanks?
+
+HORATIO
+
+ Not from his mouth,
+ Had it the ability of life to thank you:
+ He never gave commandment for their death.
+ But since, so jump upon this bloody question,
+ You from the Polack wars, and you from England,
+ Are here arrived give order that these bodies
+ High on a stage be placed to the view;
+ And let me speak to the yet unknowing world
+ How these things came about: so shall you hear
+ Of carnal, bloody, and unnatural acts,
+ Of accidental judgments, casual slaughters,
+ Of deaths put on by cunning and forced cause,
+ And, in this upshot, purposes mistook
+ Fall'n on the inventors' reads: all this can I
+ Truly deliver.
+
+PRINCE FORTINBRAS
+
+ Let us haste to hear it,
+ And call the noblest to the audience.
+ For me, with sorrow I embrace my fortune:
+ I have some rights of memory in this kingdom,
+ Which now to claim my vantage doth invite me.
+
+HORATIO
+
+ Of that I shall have also cause to speak,
+ And from his mouth whose voice will draw on more;
+ But let this same be presently perform'd,
+ Even while men's minds are wild; lest more mischance
+ On plots and errors, happen.
+
+PRINCE FORTINBRAS
+
+ Let four captains
+ Bear Hamlet, like a soldier, to the stage;
+ For he was likely, had he been put on,
+ To have proved most royally: and, for his passage,
+ The soldiers' music and the rites of war
+ Speak loudly for him.
+ Take up the bodies: such a sight as this
+ Becomes the field, but here shows much amiss.
+ Go, bid the soldiers shoot.
+
+ A dead march. Exeunt, bearing off the dead bodies; after which a peal of ordnance is shot off
+
diff --git a/user/include/ctype.h b/user/include/ctype.h
new file mode 120000
index 0000000..103c55e
--- /dev/null
+++ b/user/include/ctype.h
@@ -0,0 +1 @@
+../../kernel/include/ctype.h \ No newline at end of file
diff --git a/user/include/dirent.h b/user/include/dirent.h
new file mode 120000
index 0000000..04e02c1
--- /dev/null
+++ b/user/include/dirent.h
@@ -0,0 +1 @@
+../../kernel/include/fs/dirent.h \ No newline at end of file
diff --git a/user/include/errno.h b/user/include/errno.h
new file mode 120000
index 0000000..0539180
--- /dev/null
+++ b/user/include/errno.h
@@ -0,0 +1 @@
+../../kernel/include/errno.h \ No newline at end of file
diff --git a/user/include/fcntl.h b/user/include/fcntl.h
new file mode 120000
index 0000000..3711d2c
--- /dev/null
+++ b/user/include/fcntl.h
@@ -0,0 +1 @@
+../../kernel/include/fs/fcntl.h \ No newline at end of file
diff --git a/user/include/limits.h b/user/include/limits.h
new file mode 120000
index 0000000..3b53358
--- /dev/null
+++ b/user/include/limits.h
@@ -0,0 +1 @@
+../../kernel/include/limits.h \ No newline at end of file
diff --git a/user/include/lseek.h b/user/include/lseek.h
new file mode 120000
index 0000000..3cd2501
--- /dev/null
+++ b/user/include/lseek.h
@@ -0,0 +1 @@
+../../kernel/include/fs/lseek.h \ No newline at end of file
diff --git a/user/include/pthread/pthread.h b/user/include/pthread/pthread.h
new file mode 100644
index 0000000..1d92c41
--- /dev/null
+++ b/user/include/pthread/pthread.h
@@ -0,0 +1,137 @@
+#pragma once
+
+struct pthread;
+struct pthread_cond;
+struct pthread_mutex;
+
+typedef struct pthread *pthread_t;
+typedef struct pthread_mutex *pthread_mutex_t;
+typedef struct pthread_cond *pthread_cond_t;
+
+/* Attributes NYI */
+typedef int pthread_attr_t;
+typedef int pthread_mutexattr_t;
+typedef int pthread_condattr_t;
+
+void pthread_cleanup_pop(int);
+
+void pthread_cleanup_push(void (*)(void *), void *routine_arg);
+
+int pthread_cond_broadcast(pthread_cond_t *cond);
+
+int pthread_cond_destroy(pthread_cond_t *cond);
+
+int pthread_cond_init(pthread_cond_t *cond, const pthread_condattr_t *);
+
+int pthread_cond_signal(pthread_cond_t *cond);
+
+int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mtx);
+
+int pthread_create(pthread_t *thr, const pthread_attr_t *, void *(*)(void *),
+ void *);
+
+int pthread_detach(pthread_t thr);
+
+int pthread_equal(pthread_t, pthread_t);
+
+void pthread_exit(void *retval);
+
+int pthread_join(pthread_t thr, void **retval);
+
+int pthread_mutex_init(pthread_mutex_t *mtx, const pthread_mutexattr_t *);
+
+int pthread_mutex_lock(pthread_mutex_t *mtx);
+
+int pthread_mutex_trylock(pthread_mutex_t *mtx);
+
+int pthread_mutex_unlock(pthread_mutex_t *mtx);
+
+void pthread_yield(void);
+
+int pthread_cancel(pthread_t thr);
+
+/* Everything below NYI */
+#if 0
+int pthread_kill(pthread_t thr, int);
+int pthread_setcancelstate(int, int *);
+int pthread_setcanceltype(int, int *);
+void pthread_testcancel(void);
+int pthread_once(pthread_once_t *, void ( *)(void));
+int pthread_cond_timedwait(pthread_cond_t *,
+ pthread_mutex_t *, const struct timespec *);
+void *pthread_getspecific(pthread_key_t);
+int pthread_key_create(pthread_key_t *,
+ void ( *)(void *));
+int pthread_key_delete(pthread_key_t);
+int pthread_atfork(void ( *)(void), void ( *)(void), void ( *)(void));
+int pthread_attr_destroy(pthread_attr_t *);
+int pthread_attr_getstack(const pthread_attr_t *,
+ void **, size_t *);
+int pthread_mutexattr_init(pthread_mutexattr_t *);
+int pthread_mutexattr_destroy(pthread_mutexattr_t *);
+int pthread_mutexattr_gettype(pthread_mutexattr_t *, int *);
+int pthread_mutexattr_settype(pthread_mutexattr_t *, int);
+int pthread_mutex_destroy(pthread_mutex_t *);
+int pthread_attr_getstacksize(const pthread_attr_t *, size_t *);
+int pthread_attr_getstackaddr(const pthread_attr_t *, void **);
+int pthread_attr_getguardsize(const pthread_attr_t *, size_t *);
+int pthread_attr_getdetachstate(const pthread_attr_t *, int *);
+int pthread_attr_init(pthread_attr_t *);
+int pthread_attr_setstacksize(pthread_attr_t *, size_t);
+int pthread_attr_setstack(pthread_attr_t *, void *, size_t);
+int pthread_attr_setstackaddr(pthread_attr_t *, void *);
+int pthread_attr_setguardsize(pthread_attr_t *, size_t);
+int pthread_attr_setdetachstate(pthread_attr_t *, int);
+int pthread_condattr_destroy(pthread_condattr_t *);
+int pthread_condattr_init(pthread_condattr_t *);
+int pthread_rwlock_destroy(pthread_rwlock_t *);
+int pthread_rwlock_init(pthread_rwlock_t *,
+ const pthread_rwlockattr_t *);
+int pthread_rwlock_rdlock(pthread_rwlock_t *);
+int pthread_rwlock_timedrdlock(pthread_rwlock_t *,
+ const struct timespec *);
+int pthread_rwlock_timedwrlock(pthread_rwlock_t *,
+ const struct timespec *);
+int pthread_rwlock_tryrdlock(pthread_rwlock_t *);
+int pthread_rwlock_trywrlock(pthread_rwlock_t *);
+int pthread_rwlock_unlock(pthread_rwlock_t *);
+int pthread_rwlock_wrlock(pthread_rwlock_t *);
+int pthread_rwlockattr_init(pthread_rwlockattr_t *);
+int pthread_rwlockattr_getpshared(const pthread_rwlockattr_t *,
+ int *);
+int pthread_rwlockattr_setpshared(pthread_rwlockattr_t *, int);
+int pthread_rwlockattr_destroy(pthread_rwlockattr_t *);
+pthread_t pthread_self(void);
+int pthread_setspecific(pthread_key_t, const void *);
+int pthread_sigmask(int, const sigset_t *, sigset_t *);
+
+int pthread_getprio(pthread_t);
+int pthread_setprio(pthread_t, int);
+
+int pthread_mutexattr_getprioceiling(pthread_mutexattr_t *,
+ int *);
+int pthread_mutexattr_setprioceiling(pthread_mutexattr_t *,
+ int);
+int pthread_mutex_getprioceiling(pthread_mutex_t *, int *);
+int pthread_mutex_setprioceiling(pthread_mutex_t *, int, int *);
+
+int pthread_mutexattr_getprotocol(pthread_mutexattr_t *, int *);
+int pthread_mutexattr_setprotocol(pthread_mutexattr_t *, int);
+
+int pthread_attr_getinheritsched(const pthread_attr_t *, int *);
+int pthread_attr_getschedparam(const pthread_attr_t *,
+ struct sched_param *);
+int pthread_attr_getschedpolicy(const pthread_attr_t *, int *);
+int pthread_attr_getscope(const pthread_attr_t *, int *);
+int pthread_attr_setinheritsched(pthread_attr_t *, int);
+int pthread_attr_setschedparam(pthread_attr_t *,
+ const struct sched_param *);
+int pthread_attr_setschedpolicy(pthread_attr_t *, int);
+int pthread_attr_setscope(pthread_attr_t *, int);
+int pthread_getschedparam(pthread_t pthread, int *,
+ struct sched_param *);
+int pthread_setschedparam(pthread_t, int,
+ const struct sched_param *);
+int pthread_getconcurrency(void);
+int pthread_setconcurrency(int);
+#endif
diff --git a/user/include/stdarg.h b/user/include/stdarg.h
new file mode 120000
index 0000000..0e3c432
--- /dev/null
+++ b/user/include/stdarg.h
@@ -0,0 +1 @@
+../../kernel/include/stdarg.h \ No newline at end of file
diff --git a/user/include/stddef.h b/user/include/stddef.h
new file mode 100644
index 0000000..39b5af5
--- /dev/null
+++ b/user/include/stddef.h
@@ -0,0 +1,28 @@
+#pragma once
+
+#include "sys/types.h"
+
+#define inline __attribute__((always_inline, used))
+
+#define offsetof(type, member) \
+ ((uintptr_t)((char *)&((type *)(0))->member - (char *)0))
+
+#ifndef MIN
+#define MIN(a, b) ((a) < (b) ? (a) : (b))
+#endif
+#ifndef MAX
+#define MAX(a, b) ((a) > (b) ? (a) : (b))
+#endif
+
+#define CONTAINER_OF(obj, type, member) \
+ ((type *)((char *)(obj)-offsetof(type, member)))
+
+/* This truly atrocious macro hack taken from the wikipedia article on the C
+ * preprocessor, use to "quote" the value (or name) of another macro:
+ * QUOTE_BY_NAME(NTERMS) -> "NTERMS"
+ * QUOTE(NTERMS) -> "3"
+ */
+#define QUOTE_BY_NAME(x) #x
+#define QUOTE_BY_VALUE(x) QUOTE_BY_NAME(x)
+/* By default, we quote by value */
+#define QUOTE(x) QUOTE_BY_NAME(x)
diff --git a/user/include/stdio.h b/user/include/stdio.h
new file mode 100644
index 0000000..d138990
--- /dev/null
+++ b/user/include/stdio.h
@@ -0,0 +1,63 @@
+#pragma once
+
+#include "lseek.h"
+#include "stdarg.h"
+#include "stddef.h"
+#include "sys/types.h"
+
+/* Output not buffered */
+#define __IONBF 1
+
+#ifndef EOF
+#define EOF (-1)
+#endif
+
+#ifndef NULL
+#define NULL 0
+#endif
+
+/* For now, just store a file descriptor */
+typedef struct
+{
+ int fd;
+ int offset;
+ char buffer[8192];
+} FILE;
+typedef off_t fpos_t;
+extern FILE *stdin;
+extern FILE *stdout;
+extern FILE *stderr;
+
+/* ANSI C89 */
+int printf(const char *fmt, ...) __attribute__((__format__(printf, 1, 2)))
+__attribute__((__nonnull__(1)));
+
+int fprintf(FILE *stream, const char *fmt, ...)
+ __attribute__((__format__(printf, 2, 3))) __attribute__((__nonnull__(2)));
+
+int sprintf(char *buf, const char *fmt, ...)
+ __attribute__((__format__(printf, 2, 3))) __attribute__((__nonnull__(2)));
+
+int fflush(FILE *stream);
+
+int vprintf(const char *fmt, va_list args)
+ __attribute__((__format__(printf, 1, 0))) __attribute__((__nonnull__(1)));
+
+int vfprintf(FILE *stream, const char *fmt, va_list args)
+ __attribute__((__format__(printf, 2, 0))) __attribute__((__nonnull__(2)));
+
+int vsprintf(char *buf, const char *fmt, va_list args)
+ __attribute__((__format__(printf, 2, 0))) __attribute__((__nonnull__(2)));
+
+/* Other */
+int snprintf(char *buf, size_t size, const char *fmt, ...)
+ __attribute__((__format__(printf, 3, 4))) __attribute__((__nonnull__(3)));
+
+int vsnprintf(char *buf, size_t size, const char *fmt, va_list args)
+ __attribute__((__format__(printf, 3, 0))) __attribute__((__nonnull__(3)));
+
+int sscanf(const char *buf, const char *fmt, ...)
+ __attribute__((__format__(scanf, 2, 3))) __attribute__((__nonnull__(2)));
+
+int vsscanf(const char *buf, const char *fmt, va_list args)
+ __attribute__((__nonnull__(2)));
diff --git a/user/include/stdlib.h b/user/include/stdlib.h
new file mode 100644
index 0000000..31de474
--- /dev/null
+++ b/user/include/stdlib.h
@@ -0,0 +1,60 @@
+#pragma once
+
+#include "limits.h"
+#include "sys/types.h"
+
+#ifndef NULL
+#define NULL 0
+#endif
+
+#ifndef EXIT_SUCCESS
+#define EXIT_SUCCESS 0
+#endif
+
+#ifndef EXIT_FAILURE
+#define EXIT_FAILURE 1
+#endif
+
+/* Exit */
+__attribute__((noreturn)) void exit(int status);
+
+int atexit(void (*func)(void));
+void _Exit(int status); /* NYI */
+
+/* string to num conversion */
+int atoi(const char *val);
+
+/* --- NYI --- */
+long atol(const char *val);
+
+float atof(const char *val);
+
+#define atoi(val) ((int)strtol(val, NULL, 10))
+#define atol(val) strtol(val, NULL, 10)
+#define atolf(val) strtof(val, NULL)
+
+long strtol(const char *nptr, char **endptr, int base);
+
+long long strtoll(const char *nptr, char **endptr, int base);
+
+double strtod(const char *nptr, char **endptr);
+
+float strtof(const char *nptr, char **endptr);
+
+long double strtold(const char *nptr, char **endptr);
+/* --- END NYI --- */
+
+/* Malloc library */
+void *malloc(size_t size);
+
+void free(void *ptr);
+
+void *realloc(void *ptr, size_t size);
+
+void *calloc(size_t nelem, size_t elsize);
+
+#define RAND_MAX INT_MAX
+
+int rand(void);
+
+void srand(unsigned int seed);
diff --git a/user/include/string.h b/user/include/string.h
new file mode 100644
index 0000000..aa99792
--- /dev/null
+++ b/user/include/string.h
@@ -0,0 +1,47 @@
+#pragma once
+
+#include "errno.h"
+#include "stddef.h"
+
+/* ANSI C89 */
+void *memchr(const void *, int, size_t); /* NYI */
+int memcmp(const void *cs, const void *ct, size_t count);
+
+void *memcpy(void *dest, const void *src, size_t count);
+
+void *memmove(void *dest, const void *src, size_t count);
+
+void *memset(void *s, int c, size_t count);
+
+char *strcpy(char *dest, const char *src);
+
+char *strncpy(char *dest, const char *src, size_t count);
+
+char *strcat(char *dest, const char *src);
+
+char *strncat(char *, const char *, size_t); /* NYI */
+
+int strcmp(const char *cs, const char *ct);
+
+int strncmp(const char *cs, const char *ct, size_t count);
+
+char *strchr(const char *s, int c);
+
+char *strrchr(const char *s, int c);
+
+size_t strspn(const char *s, const char *accept);
+
+size_t strcspn(const char *, const char *); /* NYI */
+
+char *strpbrk(const char *string, const char *brkset);
+
+char *strstr(const char *s1, const char *s2);
+
+size_t strlen(const char *s);
+
+char *strerror(int errnum);
+
+char *strtok(char *s, const char *sepset);
+
+/* Other */
+size_t strnlen(const char *s, size_t count);
diff --git a/user/include/sys/mman.h b/user/include/sys/mman.h
new file mode 120000
index 0000000..f1f1ecb
--- /dev/null
+++ b/user/include/sys/mman.h
@@ -0,0 +1 @@
+../../../kernel/include/mm/mman.h \ No newline at end of file
diff --git a/user/include/sys/stat.h b/user/include/sys/stat.h
new file mode 120000
index 0000000..1360a3a
--- /dev/null
+++ b/user/include/sys/stat.h
@@ -0,0 +1 @@
+../../../kernel/include/fs/stat.h \ No newline at end of file
diff --git a/user/include/sys/types.h b/user/include/sys/types.h
new file mode 120000
index 0000000..3d6b779
--- /dev/null
+++ b/user/include/sys/types.h
@@ -0,0 +1 @@
+../../../kernel/include/types.h \ No newline at end of file
diff --git a/user/include/sys/utsname.h b/user/include/sys/utsname.h
new file mode 120000
index 0000000..89a9374
--- /dev/null
+++ b/user/include/sys/utsname.h
@@ -0,0 +1 @@
+../../../kernel/include/api/utsname.h \ No newline at end of file
diff --git a/user/include/test/test.h b/user/include/test/test.h
new file mode 100644
index 0000000..3d2296f
--- /dev/null
+++ b/user/include/test/test.h
@@ -0,0 +1,51 @@
+#pragma once
+
+#ifndef __KERNEL__
+
+#include "sys/types.h"
+#include "unistd.h"
+
+#else
+#include "types.h"
+#endif
+
+#include <stdarg.h>
+
+#define test_assert(expr, fmt, args...) \
+ _test_assert(expr, __FILE__, __LINE__, #expr, fmt, ##args)
+
+#ifndef __KERNEL__
+#define test_fork_begin() \
+ do \
+ { \
+ pid_t __test_pid = fork(); \
+ if (0 == __test_pid) \
+ { \
+ do
+
+#define test_fork_end(status) \
+ while (0) \
+ ; \
+ exit(0); \
+ } /* if */ \
+ waitpid(__test_pid, status, 0); \
+ } \
+ while (0) \
+ ;
+#endif
+
+void test_init(void);
+
+void test_fini(void);
+
+const char *test_errstr(int err);
+
+typedef void (*test_pass_func_t)(int val, const char *file, int line,
+ const char *name, const char *fmt,
+ va_list args);
+
+typedef void (*test_fail_func_t)(const char *file, int line, const char *name,
+ const char *fmt, va_list args);
+
+int _test_assert(int val, const char *file, int line, const char *name,
+ const char *fmt, ...);
diff --git a/user/include/unistd.h b/user/include/unistd.h
new file mode 100644
index 0000000..ab82669
--- /dev/null
+++ b/user/include/unistd.h
@@ -0,0 +1,101 @@
+/*
+ * unistd.h - Standard Weenix System Interface
+ */
+#pragma once
+
+#include "lseek.h"
+#include "stdarg.h"
+#include "sys/stat.h"
+#include "sys/types.h"
+#include "weenix/config.h"
+
+#ifndef NULL
+#define NULL 0
+#endif
+
+struct dirent;
+
+/* User exec-related */
+int fork(void);
+
+int execl(const char *filename, const char *arg, ...); /* NYI */
+int execle(const char *filename, const char *arg, ...); /* NYI */
+int execv(const char *filename, char *const argv[]); /* NYI */
+int execve(const char *filename, char *const argv[], char *const envp[]);
+
+/* Kern-related */
+pid_t wait(int *status);
+
+pid_t waitpid(pid_t pid, int *status, int options);
+
+void thr_exit(int status);
+
+int thr_errno(void);
+
+void thr_set_errno(int n);
+
+int sched_yield(void);
+
+pid_t getpid(void);
+
+int halt(void);
+
+void sync(void);
+
+size_t get_free_mem(void);
+
+/* VFS-related */
+int open(const char *filename, int flags, int mode);
+
+int close(int fd);
+
+ssize_t read(int fd, void *buf, size_t count);
+
+ssize_t write(int fd, const void *buf, size_t count);
+
+off_t lseek(int fd, off_t offset, int whence);
+
+int dup(int fd);
+
+int dup2(int ofd, int nfd);
+
+int mkdir(const char *path, int mode);
+
+int rmdir(const char *path);
+
+int unlink(const char *path);
+
+int link(const char *oldpath, const char *newpath);
+
+int rename(const char *oldpath, const char *newpath);
+
+int chdir(const char *path);
+
+int getdents(int fd, struct dirent *dir, size_t size);
+
+int stat(const char *path, struct stat *buf);
+
+int pipe(int pipefd[2]);
+
+/* VM-related */
+void *mmap(void *addr, size_t len, int prot, int flags, int fd, off_t off);
+
+int munmap(void *addr, size_t len);
+
+int brk(void *addr);
+
+void *sbrk(intptr_t incr);
+
+/* Mounting */
+int mount(const char *source, const char *target, const char *filesystemtype,
+ unsigned long mountflags, const void *data);
+
+int umount(const char *target);
+
+time_t time(time_t *tloc);
+
+long usleep(useconds_t usec);
+
+#define STDIN_FILENO 0
+#define STDOUT_FILENO 1
+#define STDERR_FILENO 2
diff --git a/user/include/weenix/config.h b/user/include/weenix/config.h
new file mode 120000
index 0000000..a92e33c
--- /dev/null
+++ b/user/include/weenix/config.h
@@ -0,0 +1 @@
+../../../kernel/include/config.h \ No newline at end of file
diff --git a/user/include/weenix/debug.h b/user/include/weenix/debug.h
new file mode 100644
index 0000000..a30641e
--- /dev/null
+++ b/user/include/weenix/debug.h
@@ -0,0 +1,12 @@
+#include "stdio.h"
+
+int debug(const char *str);
+
+#define dbg(fmt, args...) \
+ do \
+ { \
+ char temp[2048]; \
+ snprintf(temp, sizeof(temp), "%s:%d %s(): " fmt, __FILE__, __LINE__, \
+ __func__, ##args); \
+ debug(temp); \
+ } while (0);
diff --git a/user/include/weenix/syscall.h b/user/include/weenix/syscall.h
new file mode 120000
index 0000000..0a85ee5
--- /dev/null
+++ b/user/include/weenix/syscall.h
@@ -0,0 +1 @@
+../../../kernel/include/api/syscall.h \ No newline at end of file
diff --git a/user/include/weenix/trap.h b/user/include/weenix/trap.h
new file mode 100644
index 0000000..fade1eb
--- /dev/null
+++ b/user/include/weenix/trap.h
@@ -0,0 +1,26 @@
+#pragma once
+
+#include "errno.h"
+#include "stddef.h"
+#include "sys/types.h"
+#include "weenix/syscall.h"
+
+#define TRAP_INTR_STRING QUOTE(INTR_SYSCALL)
+
+/* ssize_t will be 32 bits or 64 bits wide as appropriate.
+ args are passed via %(r/e)ax and %(r/e)dx, so they need
+ to be the size of a register. */
+
+static inline ssize_t trap(ssize_t num, ssize_t arg)
+{
+ ssize_t ret;
+ __asm__ volatile("int $" TRAP_INTR_STRING
+ : "=a"(ret)
+ : "a"(num), "d"(arg));
+
+ /* Copy in errno */
+ __asm__ volatile("int $" TRAP_INTR_STRING
+ : "=a"(errno)
+ : "a"(SYS_errno));
+ return ret;
+}
diff --git a/user/lib/ld-weenix/asm.h b/user/lib/ld-weenix/asm.h
new file mode 100644
index 0000000..e17d5e5
--- /dev/null
+++ b/user/lib/ld-weenix/asm.h
@@ -0,0 +1,37 @@
+/* Assembler macros for x86-64.
+ Copyright (C) 2018-2019 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
+
+#ifndef _ASM_H
+#define _ASM_H 1
+
+/* ELF uses byte-counts for .align, most others use log2 of count of bytes. */
+#define ALIGNARG(log2) 1 << log2
+#define ASM_SIZE_DIRECTIVE(name) .size name, .- name;
+
+/* Define an entry point visible from C. */
+#define ENTRY(name) \
+ .globl name; \
+ .type name, @function; \
+ .align ALIGNARG(4); \
+ name## :.cfi_startproc;
+
+#define END(name) \
+ .cfi_endproc; \
+ ASM_SIZE_DIRECTIVE(name)
+
+#endif /* _ASM_H */
diff --git a/user/lib/ld-weenix/bs_x86_64.S b/user/lib/ld-weenix/bs_x86_64.S
new file mode 100644
index 0000000..452272b
--- /dev/null
+++ b/user/lib/ld-weenix/bs_x86_64.S
@@ -0,0 +1,58 @@
+/*
+ * File: bs_x86_64.S
+ * Date: 26 Mar 2019
+ * Acct: Sandy Harvie (charvie)
+ * Desc: Bootstrap routine for x86-64 ELF dynamic linker
+ */
+
+#include "asm.h"
+
+.globl _bootstrap
+
+_bootstrap:
+ movq 8(%rsp), %rdi # Pass argc
+ movq 16(%rsp), %rsi # Pass argv
+ movq 24(%rsp), %rdx # Pass envp
+ movq 32(%rsp), %rcx # Pass auxv
+ call _ldloadrtld # Dynamic linking!
+
+ movq 8(%rsp), %rdi # Pass argc
+ movq 16(%rsp), %rsi # Pass argv
+ movq 24(%rsp), %rdx # Pass envp
+ movq 32(%rsp), %rcx # Pass auxv
+ call *%rax # Call main
+
+ movq %rax, %rdi # Pass return value of main
+ call _ldcleanup # Clean up and exit
+
+ENTRY(_ld_bind)
+ pushfq # Save RFLAGS
+ pushq %rax # Save %rax
+ pushq %rcx # Save %rcx
+ pushq %rdx # Save %rdx
+ pushq %rdi # Save %rdi
+ pushq %rsi # Save %rsi
+ pushq %r8 # Save %r8
+ pushq %r9 # Save %r9
+ pushq %r10 # Save %r10
+ pushq %r11 # Save %r11
+
+ movq 80(%rsp), %rdi # Copy module argument
+ movq 88(%rsp), %rsi # Copy reloff argument
+ call _rtresolve@PLT # Transfer control to binder
+ movq %rax, 88(%rsp) # Store target over reloff argument
+
+ popq %r11 # Restore %r11
+ popq %r10 # Restore %r10
+ popq %r9 # Restore %r9
+ popq %r8 # Restore %r8
+ popq %rsi # Restore %rsi
+ popq %rdi # Restore %rdi
+ popq %rdx # Restore %rdx
+ popq %rcx # Restore %rcx
+ popq %rax # Restore %rax
+ popfq # Restore RFLAGS
+
+ leaq 8(%rsp), %rsp # Discard module without changing RFLAGSs
+ ret # Return to target address
+END(_ld_bind)
diff --git a/user/lib/ld-weenix/elf.h b/user/lib/ld-weenix/elf.h
new file mode 100644
index 0000000..1a8f596
--- /dev/null
+++ b/user/lib/ld-weenix/elf.h
@@ -0,0 +1,2597 @@
+/* This file defines standard ELF types, structures, and macros.
+ Copyright (C) 1995-2003, 2004 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#pragma once
+
+/* __BEGIN_DECLS */
+
+/* Standard ELF types. */
+
+#ifdef __KERNEL__
+#include "types.h"
+#else
+
+#include <sys/types.h>
+
+#endif
+
+/* Type for a 16-bit quantity. */
+typedef uint16_t Elf32_Half;
+typedef uint16_t Elf64_Half;
+
+/* Types for signed and unsigned 32-bit quantities. */
+typedef uint32_t Elf32_Word;
+typedef int32_t Elf32_Sword;
+typedef uint32_t Elf64_Word;
+typedef int32_t Elf64_Sword;
+
+/* Types for signed and unsigned 64-bit quantities. */
+typedef uint64_t Elf32_Xword;
+typedef int64_t Elf32_Sxword;
+typedef uint64_t Elf64_Xword;
+typedef int64_t Elf64_Sxword;
+
+/* Type of addresses. */
+typedef uint32_t Elf32_Addr;
+typedef uint64_t Elf64_Addr;
+
+/* Type of file offsets. */
+typedef uint32_t Elf32_Off;
+typedef uint64_t Elf64_Off;
+
+/* Type for section indices, which are 16-bit quantities. */
+typedef uint16_t Elf32_Section;
+typedef uint16_t Elf64_Section;
+
+/* Type for version symbol information. */
+typedef Elf32_Half Elf32_Versym;
+typedef Elf64_Half Elf64_Versym;
+
+/* The ELF file header. This appears at the start of every ELF file. */
+
+#define EI_NIDENT (16)
+
+typedef struct
+{
+ unsigned char e_ident[EI_NIDENT]; /* Magic number and other info */
+ Elf32_Half e_type; /* Object file type */
+ Elf32_Half e_machine; /* Architecture */
+ Elf32_Word e_version; /* Object file version */
+ Elf32_Addr e_entry; /* Entry point virtual address */
+ Elf32_Off e_phoff; /* Program header table file offset */
+ Elf32_Off e_shoff; /* Section header table file offset */
+ Elf32_Word e_flags; /* Processor-specific flags */
+ Elf32_Half e_ehsize; /* ELF header size in bytes */
+ Elf32_Half e_phentsize; /* Program header table entry size */
+ Elf32_Half e_phnum; /* Program header table entry count */
+ Elf32_Half e_shentsize; /* Section header table entry size */
+ Elf32_Half e_shnum; /* Section header table entry count */
+ Elf32_Half e_shstrndx; /* Section header string table index */
+} Elf32_Ehdr;
+
+typedef struct
+{
+ unsigned char e_ident[EI_NIDENT]; /* Magic number and other info */
+ Elf64_Half e_type; /* Object file type */
+ Elf64_Half e_machine; /* Architecture */
+ Elf64_Word e_version; /* Object file version */
+ Elf64_Addr e_entry; /* Entry point virtual address */
+ Elf64_Off e_phoff; /* Program header table file offset */
+ Elf64_Off e_shoff; /* Section header table file offset */
+ Elf64_Word e_flags; /* Processor-specific flags */
+ Elf64_Half e_ehsize; /* ELF header size in bytes */
+ Elf64_Half e_phentsize; /* Program header table entry size */
+ Elf64_Half e_phnum; /* Program header table entry count */
+ Elf64_Half e_shentsize; /* Section header table entry size */
+ Elf64_Half e_shnum; /* Section header table entry count */
+ Elf64_Half e_shstrndx; /* Section header string table index */
+} Elf64_Ehdr;
+
+/* Fields in the e_ident array. The EI_* macros are indices into the
+ array. The macros under each EI_* macro are the values the byte
+ may have. */
+
+#define EI_MAG0 0 /* File identification byte 0 index */
+#define ELFMAG0 0x7f /* Magic number byte 0 */
+
+#define EI_MAG1 1 /* File identification byte 1 index */
+#define ELFMAG1 'E' /* Magic number byte 1 */
+
+#define EI_MAG2 2 /* File identification byte 2 index */
+#define ELFMAG2 'L' /* Magic number byte 2 */
+
+#define EI_MAG3 3 /* File identification byte 3 index */
+#define ELFMAG3 'F' /* Magic number byte 3 */
+
+/* Conglomeration of the identification bytes, for easy testing as a word. */
+#define ELFMAG "\177ELF"
+#define SELFMAG 4
+
+#define EI_CLASS 4 /* File class byte index */
+#define ELFCLASSNONE 0 /* Invalid class */
+#define ELFCLASS32 1 /* 32-bit objects */
+#define ELFCLASS64 2 /* 64-bit objects */
+#define ELFCLASSNUM 3
+
+#define EI_DATA 5 /* Data encoding byte index */
+#define ELFDATANONE 0 /* Invalid data encoding */
+#define ELFDATA2LSB 1 /* 2's complement, little endian */
+#define ELFDATA2MSB 2 /* 2's complement, big endian */
+#define ELFDATANUM 3
+
+#define EI_VERSION 6 /* File version byte index */
+/* Value must be EV_CURRENT */
+
+#define EI_OSABI 7 /* OS ABI identification */
+#define ELFOSABI_NONE 0 /* UNIX System V ABI */
+#define ELFOSABI_SYSV 0 /* Alias. */
+#define ELFOSABI_HPUX 1 /* HP-UX */
+#define ELFOSABI_NETBSD 2 /* NetBSD. */
+#define ELFOSABI_LINUX 3 /* Linux. */
+#define ELFOSABI_SOLARIS 6 /* Sun Solaris. */
+#define ELFOSABI_AIX 7 /* IBM AIX. */
+#define ELFOSABI_IRIX 8 /* SGI Irix. */
+#define ELFOSABI_FREEBSD 9 /* FreeBSD. */
+#define ELFOSABI_TRU64 10 /* Compaq TRU64 UNIX. */
+#define ELFOSABI_MODESTO 11 /* Novell Modesto. */
+#define ELFOSABI_OPENBSD 12 /* OpenBSD. */
+#define ELFOSABI_ARM 97 /* ARM */
+#define ELFOSABI_STANDALONE 255 /* Standalone (embedded) application */
+
+#define EI_ABIVERSION 8 /* ABI version */
+
+#define EI_PAD 9 /* Byte index of padding bytes */
+
+/* Legal values for e_type (object file type). */
+
+#define ET_NONE 0 /* No file type */
+#define ET_REL 1 /* Relocatable file */
+#define ET_EXEC 2 /* Executable file */
+#define ET_DYN 3 /* Shared object file */
+#define ET_CORE 4 /* Core file */
+#define ET_NUM 5 /* Number of defined types */
+#define ET_LOOS 0xfe00 /* OS-specific range start */
+#define ET_HIOS 0xfeff /* OS-specific range end */
+#define ET_LOPROC 0xff00 /* Processor-specific range start */
+#define ET_HIPROC 0xffff /* Processor-specific range end */
+
+/* Legal values for e_machine (architecture). */
+
+#define EM_NONE 0 /* No machine */
+#define EM_M32 1 /* AT&T WE 32100 */
+#define EM_SPARC 2 /* SUN SPARC */
+#define EM_386 3 /* Intel 80386 */
+#define EM_68K 4 /* Motorola m68k family */
+#define EM_88K 5 /* Motorola m88k family */
+#define EM_860 7 /* Intel 80860 */
+#define EM_MIPS 8 /* MIPS R3000 big-endian */
+#define EM_S370 9 /* IBM System/370 */
+#define EM_MIPS_RS3_LE 10 /* MIPS R3000 little-endian */
+
+#define EM_PARISC 15 /* HPPA */
+#define EM_VPP500 17 /* Fujitsu VPP500 */
+#define EM_SPARC32PLUS 18 /* Sun's "v8plus" */
+#define EM_960 19 /* Intel 80960 */
+#define EM_PPC 20 /* PowerPC */
+#define EM_PPC64 21 /* PowerPC 64-bit */
+#define EM_S390 22 /* IBM S390 */
+
+#define EM_V800 36 /* NEC V800 series */
+#define EM_FR20 37 /* Fujitsu FR20 */
+#define EM_RH32 38 /* TRW RH-32 */
+#define EM_RCE 39 /* Motorola RCE */
+#define EM_ARM 40 /* ARM */
+#define EM_FAKE_ALPHA 41 /* Digital Alpha */
+#define EM_SH 42 /* Hitachi SH */
+#define EM_SPARCV9 43 /* SPARC v9 64-bit */
+#define EM_TRICORE 44 /* Siemens Tricore */
+#define EM_ARC 45 /* Argonaut RISC Core */
+#define EM_H8_300 46 /* Hitachi H8/300 */
+#define EM_H8_300H 47 /* Hitachi H8/300H */
+#define EM_H8S 48 /* Hitachi H8S */
+#define EM_H8_500 49 /* Hitachi H8/500 */
+#define EM_IA_64 50 /* Intel Merced */
+#define EM_MIPS_X 51 /* Stanford MIPS-X */
+#define EM_COLDFIRE 52 /* Motorola Coldfire */
+#define EM_68HC12 53 /* Motorola M68HC12 */
+#define EM_MMA 54 /* Fujitsu MMA Multimedia Accelerator*/
+#define EM_PCP 55 /* Siemens PCP */
+#define EM_NCPU 56 /* Sony nCPU embeeded RISC */
+#define EM_NDR1 57 /* Denso NDR1 microprocessor */
+#define EM_STARCORE 58 /* Motorola Start*Core processor */
+#define EM_ME16 59 /* Toyota ME16 processor */
+#define EM_ST100 60 /* STMicroelectronic ST100 processor */
+#define EM_TINYJ 61 /* Advanced Logic Corp. Tinyj emb.fam*/
+#define EM_X86_64 62 /* AMD x86-64 architecture */
+#define EM_PDSP 63 /* Sony DSP Processor */
+
+#define EM_FX66 66 /* Siemens FX66 microcontroller */
+#define EM_ST9PLUS 67 /* STMicroelectronics ST9+ 8/16 mc */
+#define EM_ST7 68 /* STmicroelectronics ST7 8 bit mc */
+#define EM_68HC16 69 /* Motorola MC68HC16 microcontroller */
+#define EM_68HC11 70 /* Motorola MC68HC11 microcontroller */
+#define EM_68HC08 71 /* Motorola MC68HC08 microcontroller */
+#define EM_68HC05 72 /* Motorola MC68HC05 microcontroller */
+#define EM_SVX 73 /* Silicon Graphics SVx */
+#define EM_ST19 74 /* STMicroelectronics ST19 8 bit mc */
+#define EM_VAX 75 /* Digital VAX */
+#define EM_CRIS 76 /* Axis Communications 32-bit embedded processor */
+#define EM_JAVELIN 77 /* Infineon Technologies 32-bit embedded processor */
+#define EM_FIREPATH 78 /* Element 14 64-bit DSP Processor */
+#define EM_ZSP 79 /* LSI Logic 16-bit DSP Processor */
+#define EM_MMIX 80 /* Donald Knuth's educational 64-bit processor */
+#define EM_HUANY 81 /* Harvard University machine-independent object files */
+#define EM_PRISM 82 /* SiTera Prism */
+#define EM_AVR 83 /* Atmel AVR 8-bit microcontroller */
+#define EM_FR30 84 /* Fujitsu FR30 */
+#define EM_D10V 85 /* Mitsubishi D10V */
+#define EM_D30V 86 /* Mitsubishi D30V */
+#define EM_V850 87 /* NEC v850 */
+#define EM_M32R 88 /* Mitsubishi M32R */
+#define EM_MN10300 89 /* Matsushita MN10300 */
+#define EM_MN10200 90 /* Matsushita MN10200 */
+#define EM_PJ 91 /* picoJava */
+#define EM_OPENRISC 92 /* OpenRISC 32-bit embedded processor */
+#define EM_ARC_A5 93 /* ARC Cores Tangent-A5 */
+#define EM_XTENSA 94 /* Tensilica Xtensa Architecture */
+#define EM_NUM 95
+
+/* If it is necessary to assign new unofficial EM_* values, please
+ pick large random numbers (0x8523, 0xa7f2, etc.) to minimize the
+ chances of collision with official or non-GNU unofficial values. */
+
+#define EM_ALPHA 0x9026
+
+/* Legal values for e_version (version). */
+
+#define EV_NONE 0 /* Invalid ELF version */
+#define EV_CURRENT 1 /* Current version */
+#define EV_NUM 2
+
+/* Section header. */
+
+typedef struct
+{
+ Elf32_Word sh_name; /* Section name (string tbl index) */
+ Elf32_Word sh_type; /* Section type */
+ Elf32_Word sh_flags; /* Section flags */
+ Elf32_Addr sh_addr; /* Section virtual addr at execution */
+ Elf32_Off sh_offset; /* Section file offset */
+ Elf32_Word sh_size; /* Section size in bytes */
+ Elf32_Word sh_link; /* Link to another section */
+ Elf32_Word sh_info; /* Additional section information */
+ Elf32_Word sh_addralign; /* Section alignment */
+ Elf32_Word sh_entsize; /* Entry size if section holds table */
+} Elf32_Shdr;
+
+typedef struct
+{
+ Elf64_Word sh_name; /* Section name (string tbl index) */
+ Elf64_Word sh_type; /* Section type */
+ Elf64_Xword sh_flags; /* Section flags */
+ Elf64_Addr sh_addr; /* Section virtual addr at execution */
+ Elf64_Off sh_offset; /* Section file offset */
+ Elf64_Xword sh_size; /* Section size in bytes */
+ Elf64_Word sh_link; /* Link to another section */
+ Elf64_Word sh_info; /* Additional section information */
+ Elf64_Xword sh_addralign; /* Section alignment */
+ Elf64_Xword sh_entsize; /* Entry size if section holds table */
+} Elf64_Shdr;
+
+/* Special section indices. */
+
+#define SHN_UNDEF 0 /* Undefined section */
+#define SHN_LORESERVE 0xff00 /* Start of reserved indices */
+#define SHN_LOPROC 0xff00 /* Start of processor-specific */
+#define SHN_BEFORE \
+ 0xff00 /* Order section before all others \
+(Solaris). */
+#define SHN_AFTER \
+ 0xff01 /* Order section after all others \
+(Solaris). */
+#define SHN_HIPROC 0xff1f /* End of processor-specific */
+#define SHN_LOOS 0xff20 /* Start of OS-specific */
+#define SHN_HIOS 0xff3f /* End of OS-specific */
+#define SHN_ABS 0xfff1 /* Associated symbol is absolute */
+#define SHN_COMMON 0xfff2 /* Associated symbol is common */
+#define SHN_XINDEX 0xffff /* Index is in extra table. */
+#define SHN_HIRESERVE 0xffff /* End of reserved indices */
+
+/* Legal values for sh_type (section type). */
+
+#define SHT_NULL 0 /* Section header table entry unused */
+#define SHT_PROGBITS 1 /* Program data */
+#define SHT_SYMTAB 2 /* Symbol table */
+#define SHT_STRTAB 3 /* String table */
+#define SHT_RELA 4 /* Relocation entries with addends */
+#define SHT_HASH 5 /* Symbol hash table */
+#define SHT_DYNAMIC 6 /* Dynamic linking information */
+#define SHT_NOTE 7 /* Notes */
+#define SHT_NOBITS 8 /* Program space with no data (bss) */
+#define SHT_REL 9 /* Relocation entries, no addends */
+#define SHT_SHLIB 10 /* Reserved */
+#define SHT_DYNSYM 11 /* Dynamic linker symbol table */
+#define SHT_INIT_ARRAY 14 /* Array of constructors */
+#define SHT_FINI_ARRAY 15 /* Array of destructors */
+#define SHT_PREINIT_ARRAY 16 /* Array of pre-constructors */
+#define SHT_GROUP 17 /* Section group */
+#define SHT_SYMTAB_SHNDX 18 /* Extended section indeces */
+#define SHT_NUM 19 /* Number of defined types. */
+#define SHT_LOOS 0x60000000 /* Start OS-specific */
+#define SHT_GNU_LIBLIST 0x6ffffff7 /* Prelink library list */
+#define SHT_CHECKSUM 0x6ffffff8 /* Checksum for DSO content. */
+#define SHT_LOSUNW 0x6ffffffa /* Sun-specific low bound. */
+#define SHT_SUNW_move 0x6ffffffa
+#define SHT_SUNW_COMDAT 0x6ffffffb
+#define SHT_SUNW_syminfo 0x6ffffffc
+#define SHT_GNU_verdef 0x6ffffffd /* Version definition section. */
+#define SHT_GNU_verneed 0x6ffffffe /* Version needs section. */
+#define SHT_GNU_versym 0x6fffffff /* Version symbol table. */
+#define SHT_HISUNW 0x6fffffff /* Sun-specific high bound. */
+#define SHT_HIOS 0x6fffffff /* End OS-specific type */
+#define SHT_LOPROC 0x70000000 /* Start of processor-specific */
+#define SHT_HIPROC 0x7fffffff /* End of processor-specific */
+#define SHT_LOUSER 0x80000000 /* Start of application-specific */
+#define SHT_HIUSER 0x8fffffff /* End of application-specific */
+
+/* Legal values for sh_flags (section flags). */
+
+#define SHF_WRITE (1 << 0) /* Writable */
+#define SHF_ALLOC (1 << 1) /* Occupies memory during execution */
+#define SHF_EXECINSTR (1 << 2) /* Executable */
+#define SHF_MERGE (1 << 4) /* Might be merged */
+#define SHF_STRINGS (1 << 5) /* Contains nul-terminated strings */
+#define SHF_INFO_LINK (1 << 6) /* `sh_info' contains SHT index */
+#define SHF_LINK_ORDER (1 << 7) /* Preserve order after combining */
+#define SHF_OS_NONCONFORMING \
+ (1 << 8) /* Non-standard OS specific handling \
+required */
+#define SHF_GROUP (1 << 9) /* Section is member of a group. */
+#define SHF_TLS (1 << 10) /* Section hold thread-local data. */
+#define SHF_MASKOS 0x0ff00000 /* OS-specific. */
+#define SHF_MASKPROC 0xf0000000 /* Processor-specific */
+#define SHF_ORDERED \
+ (1 << 30) /* Special ordering requirement \
+(Solaris). */
+#define SHF_EXCLUDE \
+ (1 << 31) /* Section is excluded unless \
+referenced or allocated (Solaris).*/
+
+/* Section group handling. */
+#define GRP_COMDAT 0x1 /* Mark group as COMDAT. */
+
+/* Symbol table entry. */
+
+typedef struct
+{
+ Elf32_Word st_name; /* Symbol name (string tbl index) */
+ Elf32_Addr st_value; /* Symbol value */
+ Elf32_Word st_size; /* Symbol size */
+ unsigned char st_info; /* Symbol type and binding */
+ unsigned char st_other; /* Symbol visibility */
+ Elf32_Section st_shndx; /* Section index */
+} Elf32_Sym;
+
+typedef struct
+{
+ Elf64_Word st_name; /* Symbol name (string tbl index) */
+ unsigned char st_info; /* Symbol type and binding */
+ unsigned char st_other; /* Symbol visibility */
+ Elf64_Section st_shndx; /* Section index */
+ Elf64_Addr st_value; /* Symbol value */
+ Elf64_Xword st_size; /* Symbol size */
+} Elf64_Sym;
+
+/* The syminfo section if available contains additional information about
+ every dynamic symbol. */
+
+typedef struct
+{
+ Elf32_Half si_boundto; /* Direct bindings, symbol bound to */
+ Elf32_Half si_flags; /* Per symbol flags */
+} Elf32_Syminfo;
+
+typedef struct
+{
+ Elf64_Half si_boundto; /* Direct bindings, symbol bound to */
+ Elf64_Half si_flags; /* Per symbol flags */
+} Elf64_Syminfo;
+
+/* Possible values for si_boundto. */
+#define SYMINFO_BT_SELF 0xffff /* Symbol bound to self */
+#define SYMINFO_BT_PARENT 0xfffe /* Symbol bound to parent */
+#define SYMINFO_BT_LOWRESERVE 0xff00 /* Beginning of reserved entries */
+
+/* Possible bitmasks for si_flags. */
+#define SYMINFO_FLG_DIRECT 0x0001 /* Direct bound symbol */
+#define SYMINFO_FLG_PASSTHRU 0x0002 /* Pass-thru symbol for translator */
+#define SYMINFO_FLG_COPY 0x0004 /* Symbol is a copy-reloc */
+#define SYMINFO_FLG_LAZYLOAD \
+ 0x0008 /* Symbol bound to object to be lazy loaded */
+/* Syminfo version values. */
+#define SYMINFO_NONE 0
+#define SYMINFO_CURRENT 1
+#define SYMINFO_NUM 2
+
+/* How to extract and insert information held in the st_info field. */
+
+#define ELF32_ST_BIND(val) (((unsigned char)(val)) >> 4)
+#define ELF32_ST_TYPE(val) ((val)&0xf)
+#define ELF32_ST_INFO(bind, type) (((bind) << 4) + ((type)&0xf))
+
+/* Both Elf32_Sym and Elf64_Sym use the same one-byte st_info field. */
+#define ELF64_ST_BIND(val) ELF32_ST_BIND(val)
+#define ELF64_ST_TYPE(val) ELF32_ST_TYPE(val)
+#define ELF64_ST_INFO(bind, type) ELF32_ST_INFO((bind), (type))
+
+/* Legal values for ST_BIND subfield of st_info (symbol binding). */
+
+#define STB_LOCAL 0 /* Local symbol */
+#define STB_GLOBAL 1 /* Global symbol */
+#define STB_WEAK 2 /* Weak symbol */
+#define STB_NUM 3 /* Number of defined types. */
+#define STB_LOOS 10 /* Start of OS-specific */
+#define STB_HIOS 12 /* End of OS-specific */
+#define STB_LOPROC 13 /* Start of processor-specific */
+#define STB_HIPROC 15 /* End of processor-specific */
+
+/* Legal values for ST_TYPE subfield of st_info (symbol type). */
+
+#define STT_NOTYPE 0 /* Symbol type is unspecified */
+#define STT_OBJECT 1 /* Symbol is a data object */
+#define STT_FUNC 2 /* Symbol is a code object */
+#define STT_SECTION 3 /* Symbol associated with a section */
+#define STT_FILE 4 /* Symbol's name is file name */
+#define STT_COMMON 5 /* Symbol is a common data object */
+#define STT_TLS 6 /* Symbol is thread-local data object*/
+#define STT_NUM 7 /* Number of defined types. */
+#define STT_LOOS 10 /* Start of OS-specific */
+#define STT_HIOS 12 /* End of OS-specific */
+#define STT_LOPROC 13 /* Start of processor-specific */
+#define STT_HIPROC 15 /* End of processor-specific */
+
+/* Symbol table indices are found in the hash buckets and chain table
+ of a symbol hash table section. This special index value indicates
+ the end of a chain, meaning no further symbols are found in that bucket. */
+
+#define STN_UNDEF 0 /* End of a chain. */
+
+/* How to extract and insert information held in the st_other field. */
+
+#define ELF32_ST_VISIBILITY(o) ((o)&0x03)
+
+/* For ELF64 the definitions are the same. */
+#define ELF64_ST_VISIBILITY(o) ELF32_ST_VISIBILITY(o)
+
+/* Symbol visibility specification encoded in the st_other field. */
+#define STV_DEFAULT 0 /* Default symbol visibility rules */
+#define STV_INTERNAL 1 /* Processor specific hidden class */
+#define STV_HIDDEN 2 /* Sym unavailable in other modules */
+#define STV_PROTECTED 3 /* Not preemptible, not exported */
+
+/* Relocation table entry without addend (in section of type SHT_REL). */
+
+typedef struct
+{
+ Elf32_Addr r_offset; /* Address */
+ Elf32_Word r_info; /* Relocation type and symbol index */
+} Elf32_Rel;
+
+/* I have seen two different definitions of the Elf64_Rel and
+ Elf64_Rela structures, so we'll leave them out until Novell (or
+ whoever) gets their act together. */
+/* The following, at least, is used on Sparc v9, MIPS, and Alpha. */
+
+typedef struct
+{
+ Elf64_Addr r_offset; /* Address */
+ Elf64_Xword r_info; /* Relocation type and symbol index */
+} Elf64_Rel;
+
+/* Relocation table entry with addend (in section of type SHT_RELA). */
+
+typedef struct
+{
+ Elf32_Addr r_offset; /* Address */
+ Elf32_Word r_info; /* Relocation type and symbol index */
+ Elf32_Sword r_addend; /* Addend */
+} Elf32_Rela;
+
+typedef struct
+{
+ Elf64_Addr r_offset; /* Address */
+ Elf64_Xword r_info; /* Relocation type and symbol index */
+ Elf64_Sxword r_addend; /* Addend */
+} Elf64_Rela;
+
+/* How to extract and insert information held in the r_info field. */
+
+#define ELF32_R_SYM(val) ((val) >> 8)
+#define ELF32_R_TYPE(val) ((val)&0xff)
+#define ELF32_R_INFO(sym, type) (((sym) << 8) + ((type)&0xff))
+
+#define ELF64_R_SYM(i) ((i) >> 32)
+#define ELF64_R_TYPE(i) ((i)&0xffffffff)
+#define ELF64_R_INFO(sym, type) ((((Elf64_Xword)(sym)) << 32) + (type))
+
+/* Program segment header. */
+
+typedef struct
+{
+ Elf32_Word p_type; /* Segment type */
+ Elf32_Off p_offset; /* Segment file offset */
+ Elf32_Addr p_vaddr; /* Segment virtual address */
+ Elf32_Addr p_paddr; /* Segment physical address */
+ Elf32_Word p_filesz; /* Segment size in file */
+ Elf32_Word p_memsz; /* Segment size in memory */
+ Elf32_Word p_flags; /* Segment flags */
+ Elf32_Word p_align; /* Segment alignment */
+} Elf32_Phdr;
+
+typedef struct
+{
+ Elf64_Word p_type; /* Segment type */
+ Elf64_Word p_flags; /* Segment flags */
+ Elf64_Off p_offset; /* Segment file offset */
+ Elf64_Addr p_vaddr; /* Segment virtual address */
+ Elf64_Addr p_paddr; /* Segment physical address */
+ Elf64_Xword p_filesz; /* Segment size in file */
+ Elf64_Xword p_memsz; /* Segment size in memory */
+ Elf64_Xword p_align; /* Segment alignment */
+} Elf64_Phdr;
+
+/* Legal values for p_type (segment type). */
+
+#define PT_NULL 0 /* Program header table entry unused */
+#define PT_LOAD 1 /* Loadable program segment */
+#define PT_DYNAMIC 2 /* Dynamic linking information */
+#define PT_INTERP 3 /* Program interpreter */
+#define PT_NOTE 4 /* Auxiliary information */
+#define PT_SHLIB 5 /* Reserved */
+#define PT_PHDR 6 /* Entry for header table itself */
+#define PT_TLS 7 /* Thread-local storage segment */
+#define PT_NUM 8 /* Number of defined types */
+#define PT_LOOS 0x60000000 /* Start of OS-specific */
+#define PT_GNU_EH_FRAME 0x6474e550 /* GCC .eh_frame_hdr segment */
+#define PT_GNU_STACK 0x6474e551 /* Indicates stack executability */
+#define PT_GNU_RELRO 0x6474e552 /* Read-only after relocation */
+#define PT_LOSUNW 0x6ffffffa
+#define PT_SUNWBSS 0x6ffffffa /* Sun Specific segment */
+#define PT_SUNWSTACK 0x6ffffffb /* Stack segment */
+#define PT_HISUNW 0x6fffffff
+#define PT_HIOS 0x6fffffff /* End of OS-specific */
+#define PT_LOPROC 0x70000000 /* Start of processor-specific */
+#define PT_HIPROC 0x7fffffff /* End of processor-specific */
+
+/* Legal values for p_flags (segment flags). */
+
+#define PF_X (1 << 0) /* Segment is executable */
+#define PF_W (1 << 1) /* Segment is writable */
+#define PF_R (1 << 2) /* Segment is readable */
+#define PF_MASKOS 0x0ff00000 /* OS-specific */
+#define PF_MASKPROC 0xf0000000 /* Processor-specific */
+
+/* Legal values for note segment descriptor types for core files. */
+
+#define NT_PRSTATUS 1 /* Contains copy of prstatus struct */
+#define NT_FPREGSET 2 /* Contains copy of fpregset struct */
+#define NT_PRPSINFO 3 /* Contains copy of prpsinfo struct */
+#define NT_PRXREG 4 /* Contains copy of prxregset struct */
+#define NT_TASKSTRUCT 4 /* Contains copy of task structure */
+#define NT_PLATFORM 5 /* String from sysinfo(SI_PLATFORM) */
+#define NT_AUXV 6 /* Contains copy of auxv array */
+#define NT_GWINDOWS 7 /* Contains copy of gwindows struct */
+#define NT_ASRS 8 /* Contains copy of asrset struct */
+#define NT_PSTATUS 10 /* Contains copy of pstatus struct */
+#define NT_PSINFO 13 /* Contains copy of psinfo struct */
+#define NT_PRCRED 14 /* Contains copy of prcred struct */
+#define NT_UTSNAME 15 /* Contains copy of utsname struct */
+#define NT_LWPSTATUS 16 /* Contains copy of lwpstatus struct */
+#define NT_LWPSINFO 17 /* Contains copy of lwpinfo struct */
+#define NT_PRFPXREG 20 /* Contains copy of fprxregset struct*/
+
+/* Legal values for the note segment descriptor types for object files. */
+
+#define NT_VERSION 1 /* Contains a version string. */
+
+/* Dynamic section entry. */
+
+typedef struct
+{
+ Elf32_Sword d_tag; /* Dynamic entry type */
+ union {
+ Elf32_Word d_val; /* Integer value */
+ Elf32_Addr d_ptr; /* Address value */
+ } d_un;
+} Elf32_Dyn;
+
+typedef struct
+{
+ Elf64_Sxword d_tag; /* Dynamic entry type */
+ union {
+ Elf64_Xword d_val; /* Integer value */
+ Elf64_Addr d_ptr; /* Address value */
+ } d_un;
+} Elf64_Dyn;
+
+/* Legal values for d_tag (dynamic entry type). */
+
+#define DT_NULL 0 /* Marks end of dynamic section */
+#define DT_NEEDED 1 /* Name of needed library */
+#define DT_PLTRELSZ 2 /* Size in bytes of PLT relocs */
+#define DT_PLTGOT 3 /* Processor defined value */
+#define DT_HASH 4 /* Address of symbol hash table */
+#define DT_STRTAB 5 /* Address of string table */
+#define DT_SYMTAB 6 /* Address of symbol table */
+#define DT_RELA 7 /* Address of Rela relocs */
+#define DT_RELASZ 8 /* Total size of Rela relocs */
+#define DT_RELAENT 9 /* Size of one Rela reloc */
+#define DT_STRSZ 10 /* Size of string table */
+#define DT_SYMENT 11 /* Size of one symbol table entry */
+#define DT_INIT 12 /* Address of init function */
+#define DT_FINI 13 /* Address of termination function */
+#define DT_SONAME 14 /* Name of shared object */
+#define DT_RPATH 15 /* Library search path (deprecated) */
+#define DT_SYMBOLIC 16 /* Start symbol search here */
+#define DT_REL 17 /* Address of Rel relocs */
+#define DT_RELSZ 18 /* Total size of Rel relocs */
+#define DT_RELENT 19 /* Size of one Rel reloc */
+#define DT_PLTREL 20 /* Type of reloc in PLT */
+#define DT_DEBUG 21 /* For debugging; unspecified */
+#define DT_TEXTREL 22 /* Reloc might modify .text */
+#define DT_JMPREL 23 /* Address of PLT relocs */
+#define DT_BIND_NOW 24 /* Process relocations of object */
+#define DT_INIT_ARRAY 25 /* Array with addresses of init fct */
+#define DT_FINI_ARRAY 26 /* Array with addresses of fini fct */
+#define DT_INIT_ARRAYSZ 27 /* Size in bytes of DT_INIT_ARRAY */
+#define DT_FINI_ARRAYSZ 28 /* Size in bytes of DT_FINI_ARRAY */
+#define DT_RUNPATH 29 /* Library search path */
+#define DT_FLAGS 30 /* Flags for the object being loaded */
+#define DT_ENCODING 32 /* Start of encoded range */
+#define DT_PREINIT_ARRAY 32 /* Array with addresses of preinit fct*/
+#define DT_PREINIT_ARRAYSZ 33 /* size in bytes of DT_PREINIT_ARRAY */
+#define DT_NUM 34 /* Number used */
+#define DT_LOOS 0x6000000d /* Start of OS-specific */
+#define DT_HIOS 0x6ffff000 /* End of OS-specific */
+#define DT_LOPROC 0x70000000 /* Start of processor-specific */
+#define DT_HIPROC 0x7fffffff /* End of processor-specific */
+#define DT_PROCNUM DT_MIPS_NUM /* Most used by any processor */
+
+/* DT_* entries which fall between DT_VALRNGHI & DT_VALRNGLO use the
+ Dyn.d_un.d_val field of the Elf*_Dyn structure. This follows Sun's
+ approach. */
+#define DT_VALRNGLO 0x6ffffd00
+#define DT_GNU_PRELINKED 0x6ffffdf5 /* Prelinking timestamp */
+#define DT_GNU_CONFLICTSZ 0x6ffffdf6 /* Size of conflict section */
+#define DT_GNU_LIBLISTSZ 0x6ffffdf7 /* Size of library list */
+#define DT_CHECKSUM 0x6ffffdf8
+#define DT_PLTPADSZ 0x6ffffdf9
+#define DT_MOVEENT 0x6ffffdfa
+#define DT_MOVESZ 0x6ffffdfb
+#define DT_FEATURE_1 0x6ffffdfc /* Feature selection (DTF_*). */
+#define DT_POSFLAG_1 \
+ 0x6ffffdfd /* Flags for DT_* entries, effecting \
+the following DT_* entry. */
+#define DT_SYMINSZ 0x6ffffdfe /* Size of syminfo table (in bytes) */
+#define DT_SYMINENT 0x6ffffdff /* Entry size of syminfo */
+#define DT_VALRNGHI 0x6ffffdff
+#define DT_VALTAGIDX(tag) (DT_VALRNGHI - (tag)) /* Reverse order! */
+#define DT_VALNUM 12
+
+/* DT_* entries which fall between DT_ADDRRNGHI & DT_ADDRRNGLO use the
+ Dyn.d_un.d_ptr field of the Elf*_Dyn structure.
+
+ If any adjustment is made to the ELF object after it has been
+ built these entries will need to be adjusted. */
+#define DT_ADDRRNGLO 0x6ffffe00
+#define DT_GNU_CONFLICT 0x6ffffef8 /* Start of conflict section */
+#define DT_GNU_LIBLIST 0x6ffffef9 /* Library list */
+#define DT_CONFIG 0x6ffffefa /* Configuration information. */
+#define DT_DEPAUDIT 0x6ffffefb /* Dependency auditing. */
+#define DT_AUDIT 0x6ffffefc /* Object auditing. */
+#define DT_PLTPAD 0x6ffffefd /* PLT padding. */
+#define DT_MOVETAB 0x6ffffefe /* Move table. */
+#define DT_SYMINFO 0x6ffffeff /* Syminfo table. */
+#define DT_ADDRRNGHI 0x6ffffeff
+#define DT_ADDRTAGIDX(tag) (DT_ADDRRNGHI - (tag)) /* Reverse order! */
+#define DT_ADDRNUM 10
+
+/* The versioning entry types. The next are defined as part of the
+ GNU extension. */
+#define DT_VERSYM 0x6ffffff0
+
+#define DT_RELACOUNT 0x6ffffff9
+#define DT_RELCOUNT 0x6ffffffa
+
+/* These were chosen by Sun. */
+#define DT_FLAGS_1 0x6ffffffb /* State flags, see DF_1_* below. */
+#define DT_VERDEF \
+ 0x6ffffffc /* Address of version definition \
+table */
+#define DT_VERDEFNUM 0x6ffffffd /* Number of version definitions */
+#define DT_VERNEED \
+ 0x6ffffffe /* Address of table with needed \
+ versions */
+#define DT_VERNEEDNUM 0x6fffffff /* Number of needed versions */
+#define DT_VERSIONTAGIDX(tag) (DT_VERNEEDNUM - (tag)) /* Reverse order! */
+#define DT_VERSIONTAGNUM 16
+
+/* Sun added these machine-independent extensions in the "processor-specific"
+ range. Be compatible. */
+#define DT_AUXILIARY 0x7ffffffd /* Shared object to load before self */
+#define DT_FILTER 0x7fffffff /* Shared object to get values from */
+#define DT_EXTRATAGIDX(tag) ((Elf32_Word) - ((Elf32_Sword)(tag) << 1 >> 1) - 1)
+#define DT_EXTRANUM 3
+
+/* Values of `d_un.d_val' in the DT_FLAGS entry. */
+#define DF_ORIGIN 0x00000001 /* Object may use DF_ORIGIN */
+#define DF_SYMBOLIC 0x00000002 /* Symbol resolutions starts here */
+#define DF_TEXTREL 0x00000004 /* Object contains text relocations */
+#define DF_BIND_NOW 0x00000008 /* No lazy binding for this object */
+#define DF_STATIC_TLS 0x00000010 /* Module uses the static TLS model */
+
+/* State flags selectable in the `d_un.d_val' element of the DT_FLAGS_1
+ entry in the dynamic section. */
+#define DF_1_NOW 0x00000001 /* Set RTLD_NOW for this object. */
+#define DF_1_GLOBAL 0x00000002 /* Set RTLD_GLOBAL for this object. */
+#define DF_1_GROUP 0x00000004 /* Set RTLD_GROUP for this object. */
+#define DF_1_NODELETE 0x00000008 /* Set RTLD_NODELETE for this object.*/
+#define DF_1_LOADFLTR 0x00000010 /* Trigger filtee loading at runtime.*/
+#define DF_1_INITFIRST 0x00000020 /* Set RTLD_INITFIRST for this object*/
+#define DF_1_NOOPEN 0x00000040 /* Set RTLD_NOOPEN for this object. */
+#define DF_1_ORIGIN 0x00000080 /* $ORIGIN must be handled. */
+#define DF_1_DIRECT 0x00000100 /* Direct binding enabled. */
+#define DF_1_TRANS 0x00000200
+#define DF_1_INTERPOSE 0x00000400 /* Object is used to interpose. */
+#define DF_1_NODEFLIB 0x00000800 /* Ignore default lib search path. */
+#define DF_1_NODUMP 0x00001000 /* Object can't be dldump'ed. */
+#define DF_1_CONFALT 0x00002000 /* Configuration alternative created.*/
+#define DF_1_ENDFILTEE 0x00004000 /* Filtee terminates filters search. */
+#define DF_1_DISPRELDNE 0x00008000 /* Disp reloc applied at build time. */
+#define DF_1_DISPRELPND 0x00010000 /* Disp reloc applied at run-time. */
+
+/* Flags for the feature selection in DT_FEATURE_1. */
+#define DTF_1_PARINIT 0x00000001
+#define DTF_1_CONFEXP 0x00000002
+
+/* Flags in the DT_POSFLAG_1 entry effecting only the next DT_* entry. */
+#define DF_P1_LAZYLOAD 0x00000001 /* Lazyload following object. */
+#define DF_P1_GROUPPERM \
+ 0x00000002 /* Symbols from next object are not \
+generally available. */
+
+/* Version definition sections. */
+
+typedef struct
+{
+ Elf32_Half vd_version; /* Version revision */
+ Elf32_Half vd_flags; /* Version information */
+ Elf32_Half vd_ndx; /* Version Index */
+ Elf32_Half vd_cnt; /* Number of associated aux entries */
+ Elf32_Word vd_hash; /* Version name hash value */
+ Elf32_Word vd_aux; /* Offset in bytes to verdaux array */
+ Elf32_Word vd_next; /* Offset in bytes to next verdef
+ entry */
+} Elf32_Verdef;
+
+typedef struct
+{
+ Elf64_Half vd_version; /* Version revision */
+ Elf64_Half vd_flags; /* Version information */
+ Elf64_Half vd_ndx; /* Version Index */
+ Elf64_Half vd_cnt; /* Number of associated aux entries */
+ Elf64_Word vd_hash; /* Version name hash value */
+ Elf64_Word vd_aux; /* Offset in bytes to verdaux array */
+ Elf64_Word vd_next; /* Offset in bytes to next verdef
+ entry */
+} Elf64_Verdef;
+
+/* Legal values for vd_version (version revision). */
+#define VER_DEF_NONE 0 /* No version */
+#define VER_DEF_CURRENT 1 /* Current version */
+#define VER_DEF_NUM 2 /* Given version number */
+
+/* Legal values for vd_flags (version information flags). */
+#define VER_FLG_BASE 0x1 /* Version definition of file itself */
+#define VER_FLG_WEAK 0x2 /* Weak version identifier */
+
+/* Versym symbol index values. */
+#define VER_NDX_LOCAL 0 /* Symbol is local. */
+#define VER_NDX_GLOBAL 1 /* Symbol is global. */
+#define VER_NDX_LORESERVE 0xff00 /* Beginning of reserved entries. */
+#define VER_NDX_ELIMINATE 0xff01 /* Symbol is to be eliminated. */
+
+/* Auxialiary version information. */
+
+typedef struct
+{
+ Elf32_Word vda_name; /* Version or dependency names */
+ Elf32_Word vda_next; /* Offset in bytes to next verdaux
+ entry */
+} Elf32_Verdaux;
+
+typedef struct
+{
+ Elf64_Word vda_name; /* Version or dependency names */
+ Elf64_Word vda_next; /* Offset in bytes to next verdaux
+ entry */
+} Elf64_Verdaux;
+
+/* Version dependency section. */
+
+typedef struct
+{
+ Elf32_Half vn_version; /* Version of structure */
+ Elf32_Half vn_cnt; /* Number of associated aux entries */
+ Elf32_Word vn_file; /* Offset of filename for this
+ dependency */
+ Elf32_Word vn_aux; /* Offset in bytes to vernaux array */
+ Elf32_Word vn_next; /* Offset in bytes to next verneed
+ entry */
+} Elf32_Verneed;
+
+typedef struct
+{
+ Elf64_Half vn_version; /* Version of structure */
+ Elf64_Half vn_cnt; /* Number of associated aux entries */
+ Elf64_Word vn_file; /* Offset of filename for this
+ dependency */
+ Elf64_Word vn_aux; /* Offset in bytes to vernaux array */
+ Elf64_Word vn_next; /* Offset in bytes to next verneed
+ entry */
+} Elf64_Verneed;
+
+/* Legal values for vn_version (version revision). */
+#define VER_NEED_NONE 0 /* No version */
+#define VER_NEED_CURRENT 1 /* Current version */
+#define VER_NEED_NUM 2 /* Given version number */
+
+/* Auxiliary needed version information. */
+
+typedef struct
+{
+ Elf32_Word vna_hash; /* Hash value of dependency name */
+ Elf32_Half vna_flags; /* Dependency specific information */
+ Elf32_Half vna_other; /* Unused */
+ Elf32_Word vna_name; /* Dependency name string offset */
+ Elf32_Word vna_next; /* Offset in bytes to next vernaux
+ entry */
+} Elf32_Vernaux;
+
+typedef struct
+{
+ Elf64_Word vna_hash; /* Hash value of dependency name */
+ Elf64_Half vna_flags; /* Dependency specific information */
+ Elf64_Half vna_other; /* Unused */
+ Elf64_Word vna_name; /* Dependency name string offset */
+ Elf64_Word vna_next; /* Offset in bytes to next vernaux
+ entry */
+} Elf64_Vernaux;
+
+/* Legal values for vna_flags. */
+#define VER_FLG_WEAK 0x2 /* Weak version identifier */
+
+/* Auxiliary vector. */
+
+/* This vector is normally only used by the program interpreter. The
+ usual definition in an ABI supplement uses the name auxv_t. The
+ vector is not usually defined in a standard <elf.h> file, but it
+ can't hurt. We rename it to avoid conflicts. The sizes of these
+ types are an arrangement between the exec server and the program
+ interpreter, so we don't fully specify them here. */
+
+typedef struct
+{
+ int a_type; /* Entry type */
+ union {
+ long int a_val; /* Integer value */
+ void *a_ptr; /* Pointer value */
+ void (*a_fcn)(void); /* Function pointer value */
+ } a_un;
+} Elf32_auxv_t;
+
+typedef struct
+{
+ long int a_type; /* Entry type */
+ union {
+ long int a_val; /* Integer value */
+ void *a_ptr; /* Pointer value */
+ void (*a_fcn)(void); /* Function pointer value */
+ } a_un;
+} Elf64_auxv_t;
+
+/* Legal values for a_type (entry type). */
+
+#define AT_NULL 0 /* End of vector */
+#define AT_IGNORE 1 /* Entry should be ignored */
+#define AT_EXECFD 2 /* File descriptor of program */
+#define AT_PHDR 3 /* Program headers for program */
+#define AT_PHENT 4 /* Size of program header entry */
+#define AT_PHNUM 5 /* Number of program headers */
+#define AT_PAGESZ 6 /* System page size */
+#define AT_BASE 7 /* Base address of interpreter */
+#define AT_FLAGS 8 /* Flags */
+#define AT_ENTRY 9 /* Entry point of program */
+#define AT_NOTELF 10 /* Program is not ELF */
+#define AT_UID 11 /* Real uid */
+#define AT_EUID 12 /* Effective uid */
+#define AT_GID 13 /* Real gid */
+#define AT_EGID 14 /* Effective gid */
+#define AT_CLKTCK 17 /* Frequency of times() */
+
+/* Some more special a_type values describing the hardware. */
+#define AT_PLATFORM 15 /* String identifying platform. */
+#define AT_HWCAP \
+ 16 /* Machine dependent hints about \
+processor capabilities. */
+
+/* This entry gives some information about the FPU initialization
+ performed by the kernel. */
+#define AT_FPUCW 18 /* Used FPU control word. */
+
+/* Cache block sizes. */
+#define AT_DCACHEBSIZE 19 /* Data cache block size. */
+#define AT_ICACHEBSIZE 20 /* Instruction cache block size. */
+#define AT_UCACHEBSIZE 21 /* Unified cache block size. */
+
+/* A special ignored value for PPC, used by the kernel to control the
+ interpretation of the AUXV. Must be > 16. */
+#define AT_IGNOREPPC 22 /* Entry should be ignored. */
+
+#define AT_SECURE 23 /* Boolean, was exec setuid-like? */
+
+/* Pointer to the global system page used for system calls and other
+ nice things. */
+#define AT_SYSINFO 32
+#define AT_SYSINFO_EHDR 33
+
+/* Shapes of the caches. Bits 0-3 contains associativity; bits 4-7 contains
+ log2 of line size; mask those to get cache size. */
+#define AT_L1I_CACHESHAPE 34
+#define AT_L1D_CACHESHAPE 35
+#define AT_L2_CACHESHAPE 36
+#define AT_L3_CACHESHAPE 37
+
+/* Note section contents. Each entry in the note section begins with
+ a header of a fixed form. */
+
+typedef struct
+{
+ Elf32_Word n_namesz; /* Length of the note's name. */
+ Elf32_Word n_descsz; /* Length of the note's descriptor. */
+ Elf32_Word n_type; /* Type of the note. */
+} Elf32_Nhdr;
+
+typedef struct
+{
+ Elf64_Word n_namesz; /* Length of the note's name. */
+ Elf64_Word n_descsz; /* Length of the note's descriptor. */
+ Elf64_Word n_type; /* Type of the note. */
+} Elf64_Nhdr;
+
+/* Known names of notes. */
+
+/* Solaris entries in the note section have this name. */
+#define ELF_NOTE_SOLARIS "SUNW Solaris"
+
+/* Note entries for GNU systems have this name. */
+#define ELF_NOTE_GNU "GNU"
+
+/* Defined types of notes for Solaris. */
+
+/* Value of descriptor (one word) is desired pagesize for the binary. */
+#define ELF_NOTE_PAGESIZE_HINT 1
+
+/* Defined note types for GNU systems. */
+
+/* ABI information. The descriptor consists of words:
+ word 0: OS descriptor
+ word 1: major version of the ABI
+ word 2: minor version of the ABI
+ word 3: subminor version of the ABI
+*/
+#define ELF_NOTE_ABI 1
+
+/* Known OSes. These value can appear in word 0 of an ELF_NOTE_ABI
+ note section entry. */
+#define ELF_NOTE_OS_LINUX 0
+#define ELF_NOTE_OS_GNU 1
+#define ELF_NOTE_OS_SOLARIS2 2
+#define ELF_NOTE_OS_FREEBSD 3
+
+/* Move records. */
+typedef struct
+{
+ Elf32_Xword m_value; /* Symbol value. */
+ Elf32_Word m_info; /* Size and index. */
+ Elf32_Word m_poffset; /* Symbol offset. */
+ Elf32_Half m_repeat; /* Repeat count. */
+ Elf32_Half m_stride; /* Stride info. */
+} Elf32_Move;
+
+typedef struct
+{
+ Elf64_Xword m_value; /* Symbol value. */
+ Elf64_Xword m_info; /* Size and index. */
+ Elf64_Xword m_poffset; /* Symbol offset. */
+ Elf64_Half m_repeat; /* Repeat count. */
+ Elf64_Half m_stride; /* Stride info. */
+} Elf64_Move;
+
+/* Macro to construct move records. */
+#define ELF32_M_SYM(info) ((info) >> 8)
+#define ELF32_M_SIZE(info) ((unsigned char)(info))
+#define ELF32_M_INFO(sym, size) (((sym) << 8) + (unsigned char)(size))
+
+#define ELF64_M_SYM(info) ELF32_M_SYM(info)
+#define ELF64_M_SIZE(info) ELF32_M_SIZE(info)
+#define ELF64_M_INFO(sym, size) ELF32_M_INFO(sym, size)
+
+/* Motorola 68k specific definitions. */
+
+/* Values for Elf32_Ehdr.e_flags. */
+#define EF_CPU32 0x00810000
+
+/* m68k relocs. */
+
+#define R_68K_NONE 0 /* No reloc */
+#define R_68K_32 1 /* Direct 32 bit */
+#define R_68K_16 2 /* Direct 16 bit */
+#define R_68K_8 3 /* Direct 8 bit */
+#define R_68K_PC32 4 /* PC relative 32 bit */
+#define R_68K_PC16 5 /* PC relative 16 bit */
+#define R_68K_PC8 6 /* PC relative 8 bit */
+#define R_68K_GOT32 7 /* 32 bit PC relative GOT entry */
+#define R_68K_GOT16 8 /* 16 bit PC relative GOT entry */
+#define R_68K_GOT8 9 /* 8 bit PC relative GOT entry */
+#define R_68K_GOT32O 10 /* 32 bit GOT offset */
+#define R_68K_GOT16O 11 /* 16 bit GOT offset */
+#define R_68K_GOT8O 12 /* 8 bit GOT offset */
+#define R_68K_PLT32 13 /* 32 bit PC relative PLT address */
+#define R_68K_PLT16 14 /* 16 bit PC relative PLT address */
+#define R_68K_PLT8 15 /* 8 bit PC relative PLT address */
+#define R_68K_PLT32O 16 /* 32 bit PLT offset */
+#define R_68K_PLT16O 17 /* 16 bit PLT offset */
+#define R_68K_PLT8O 18 /* 8 bit PLT offset */
+#define R_68K_COPY 19 /* Copy symbol at runtime */
+#define R_68K_GLOB_DAT 20 /* Create GOT entry */
+#define R_68K_JMP_SLOT 21 /* Create PLT entry */
+#define R_68K_RELATIVE 22 /* Adjust by program base */
+/* Keep this the last entry. */
+#define R_68K_NUM 23
+
+/* Intel 80386 specific definitions. */
+
+/* i386 relocs. */
+
+#define R_386_NONE 0 /* No reloc */
+#define R_386_32 1 /* Direct 32 bit */
+#define R_386_PC32 2 /* PC relative 32 bit */
+#define R_386_GOT32 3 /* 32 bit GOT entry */
+#define R_386_PLT32 4 /* 32 bit PLT address */
+#define R_386_COPY 5 /* Copy symbol at runtime */
+#define R_386_GLOB_DAT 6 /* Create GOT entry */
+#define R_386_JMP_SLOT 7 /* Create PLT entry */
+#define R_386_RELATIVE 8 /* Adjust by program base */
+#define R_386_GOTOFF 9 /* 32 bit offset to GOT */
+#define R_386_GOTPC 10 /* 32 bit PC relative offset to GOT */
+#define R_386_32PLT 11
+#define R_386_TLS_TPOFF 14 /* Offset in static TLS block */
+#define R_386_TLS_IE \
+ 15 /* Address of GOT entry for static TLS \
+block offset */
+#define R_386_TLS_GOTIE \
+ 16 /* GOT entry for static TLS block \
+offset */
+#define R_386_TLS_LE \
+ 17 /* Offset relative to static TLS \
+block */
+#define R_386_TLS_GD \
+ 18 /* Direct 32 bit for GNU version of \
+general dynamic thread local data */
+#define R_386_TLS_LDM \
+ 19 /* Direct 32 bit for GNU version of \
+local dynamic thread local data \
+in LE code */
+#define R_386_16 20
+#define R_386_PC16 21
+#define R_386_8 22
+#define R_386_PC8 23
+#define R_386_TLS_GD_32 \
+ 24 /* Direct 32 bit for general dynamic \
+thread local data */
+#define R_386_TLS_GD_PUSH 25 /* Tag for pushl in GD TLS code */
+#define R_386_TLS_GD_CALL \
+ 26 /* Relocation for call to \
+__tls_get_addr() */
+#define R_386_TLS_GD_POP 27 /* Tag for popl in GD TLS code */
+#define R_386_TLS_LDM_32 \
+ 28 /* Direct 32 bit for local dynamic \
+thread local data in LE code */
+#define R_386_TLS_LDM_PUSH 29 /* Tag for pushl in LDM TLS code */
+#define R_386_TLS_LDM_CALL \
+ 30 /* Relocation for call to \
+__tls_get_addr() in LDM code */
+#define R_386_TLS_LDM_POP 31 /* Tag for popl in LDM TLS code */
+#define R_386_TLS_LDO_32 32 /* Offset relative to TLS block */
+#define R_386_TLS_IE_32 \
+ 33 /* GOT entry for negated static TLS \
+block offset */
+#define R_386_TLS_LE_32 \
+ 34 /* Negated offset relative to static \
+TLS block */
+#define R_386_TLS_DTPMOD32 35 /* ID of module containing symbol */
+#define R_386_TLS_DTPOFF32 36 /* Offset in TLS block */
+#define R_386_TLS_TPOFF32 37 /* Negated offset in static TLS block */
+/* Keep this the last entry. */
+#define R_386_NUM 38
+
+/* SUN SPARC specific definitions. */
+
+/* Legal values for ST_TYPE subfield of st_info (symbol type). */
+
+#define STT_SPARC_REGISTER 13 /* Global register reserved to app. */
+
+/* Values for Elf64_Ehdr.e_flags. */
+
+#define EF_SPARCV9_MM 3
+#define EF_SPARCV9_TSO 0
+#define EF_SPARCV9_PSO 1
+#define EF_SPARCV9_RMO 2
+#define EF_SPARC_LEDATA 0x800000 /* little endian data */
+#define EF_SPARC_EXT_MASK 0xFFFF00
+#define EF_SPARC_32PLUS 0x000100 /* generic V8+ features */
+#define EF_SPARC_SUN_US1 0x000200 /* Sun UltraSPARC1 extensions */
+#define EF_SPARC_HAL_R1 0x000400 /* HAL R1 extensions */
+#define EF_SPARC_SUN_US3 0x000800 /* Sun UltraSPARCIII extensions */
+
+/* SPARC relocs. */
+
+#define R_SPARC_NONE 0 /* No reloc */
+#define R_SPARC_8 1 /* Direct 8 bit */
+#define R_SPARC_16 2 /* Direct 16 bit */
+#define R_SPARC_32 3 /* Direct 32 bit */
+#define R_SPARC_DISP8 4 /* PC relative 8 bit */
+#define R_SPARC_DISP16 5 /* PC relative 16 bit */
+#define R_SPARC_DISP32 6 /* PC relative 32 bit */
+#define R_SPARC_WDISP30 7 /* PC relative 30 bit shifted */
+#define R_SPARC_WDISP22 8 /* PC relative 22 bit shifted */
+#define R_SPARC_HI22 9 /* High 22 bit */
+#define R_SPARC_22 10 /* Direct 22 bit */
+#define R_SPARC_13 11 /* Direct 13 bit */
+#define R_SPARC_LO10 12 /* Truncated 10 bit */
+#define R_SPARC_GOT10 13 /* Truncated 10 bit GOT entry */
+#define R_SPARC_GOT13 14 /* 13 bit GOT entry */
+#define R_SPARC_GOT22 15 /* 22 bit GOT entry shifted */
+#define R_SPARC_PC10 16 /* PC relative 10 bit truncated */
+#define R_SPARC_PC22 17 /* PC relative 22 bit shifted */
+#define R_SPARC_WPLT30 18 /* 30 bit PC relative PLT address */
+#define R_SPARC_COPY 19 /* Copy symbol at runtime */
+#define R_SPARC_GLOB_DAT 20 /* Create GOT entry */
+#define R_SPARC_JMP_SLOT 21 /* Create PLT entry */
+#define R_SPARC_RELATIVE 22 /* Adjust by program base */
+#define R_SPARC_UA32 23 /* Direct 32 bit unaligned */
+
+/* Additional Sparc64 relocs. */
+
+#define R_SPARC_PLT32 24 /* Direct 32 bit ref to PLT entry */
+#define R_SPARC_HIPLT22 25 /* High 22 bit PLT entry */
+#define R_SPARC_LOPLT10 26 /* Truncated 10 bit PLT entry */
+#define R_SPARC_PCPLT32 27 /* PC rel 32 bit ref to PLT entry */
+#define R_SPARC_PCPLT22 28 /* PC rel high 22 bit PLT entry */
+#define R_SPARC_PCPLT10 29 /* PC rel trunc 10 bit PLT entry */
+#define R_SPARC_10 30 /* Direct 10 bit */
+#define R_SPARC_11 31 /* Direct 11 bit */
+#define R_SPARC_64 32 /* Direct 64 bit */
+#define R_SPARC_OLO10 33 /* 10bit with secondary 13bit addend */
+#define R_SPARC_HH22 34 /* Top 22 bits of direct 64 bit */
+#define R_SPARC_HM10 35 /* High middle 10 bits of ... */
+#define R_SPARC_LM22 36 /* Low middle 22 bits of ... */
+#define R_SPARC_PC_HH22 37 /* Top 22 bits of pc rel 64 bit */
+#define R_SPARC_PC_HM10 38 /* High middle 10 bit of ... */
+#define R_SPARC_PC_LM22 39 /* Low miggle 22 bits of ... */
+#define R_SPARC_WDISP16 40 /* PC relative 16 bit shifted */
+#define R_SPARC_WDISP19 41 /* PC relative 19 bit shifted */
+#define R_SPARC_7 43 /* Direct 7 bit */
+#define R_SPARC_5 44 /* Direct 5 bit */
+#define R_SPARC_6 45 /* Direct 6 bit */
+#define R_SPARC_DISP64 46 /* PC relative 64 bit */
+#define R_SPARC_PLT64 47 /* Direct 64 bit ref to PLT entry */
+#define R_SPARC_HIX22 48 /* High 22 bit complemented */
+#define R_SPARC_LOX10 49 /* Truncated 11 bit complemented */
+#define R_SPARC_H44 50 /* Direct high 12 of 44 bit */
+#define R_SPARC_M44 51 /* Direct mid 22 of 44 bit */
+#define R_SPARC_L44 52 /* Direct low 10 of 44 bit */
+#define R_SPARC_REGISTER 53 /* Global register usage */
+#define R_SPARC_UA64 54 /* Direct 64 bit unaligned */
+#define R_SPARC_UA16 55 /* Direct 16 bit unaligned */
+#define R_SPARC_TLS_GD_HI22 56
+#define R_SPARC_TLS_GD_LO10 57
+#define R_SPARC_TLS_GD_ADD 58
+#define R_SPARC_TLS_GD_CALL 59
+#define R_SPARC_TLS_LDM_HI22 60
+#define R_SPARC_TLS_LDM_LO10 61
+#define R_SPARC_TLS_LDM_ADD 62
+#define R_SPARC_TLS_LDM_CALL 63
+#define R_SPARC_TLS_LDO_HIX22 64
+#define R_SPARC_TLS_LDO_LOX10 65
+#define R_SPARC_TLS_LDO_ADD 66
+#define R_SPARC_TLS_IE_HI22 67
+#define R_SPARC_TLS_IE_LO10 68
+#define R_SPARC_TLS_IE_LD 69
+#define R_SPARC_TLS_IE_LDX 70
+#define R_SPARC_TLS_IE_ADD 71
+#define R_SPARC_TLS_LE_HIX22 72
+#define R_SPARC_TLS_LE_LOX10 73
+#define R_SPARC_TLS_DTPMOD32 74
+#define R_SPARC_TLS_DTPMOD64 75
+#define R_SPARC_TLS_DTPOFF32 76
+#define R_SPARC_TLS_DTPOFF64 77
+#define R_SPARC_TLS_TPOFF32 78
+#define R_SPARC_TLS_TPOFF64 79
+/* Keep this the last entry. */
+#define R_SPARC_NUM 80
+
+/* For Sparc64, legal values for d_tag of Elf64_Dyn. */
+
+#define DT_SPARC_REGISTER 0x70000001
+#define DT_SPARC_NUM 2
+
+/* Bits present in AT_HWCAP, primarily for Sparc32. */
+
+#define HWCAP_SPARC_FLUSH 1 /* The cpu supports flush insn. */
+#define HWCAP_SPARC_STBAR 2
+#define HWCAP_SPARC_SWAP 4
+#define HWCAP_SPARC_MULDIV 8
+#define HWCAP_SPARC_V9 16 /* The cpu is v9, so v8plus is ok. */
+#define HWCAP_SPARC_ULTRA3 32
+
+/* MIPS R3000 specific definitions. */
+
+/* Legal values for e_flags field of Elf32_Ehdr. */
+
+#define EF_MIPS_NOREORDER 1 /* A .noreorder directive was used */
+#define EF_MIPS_PIC 2 /* Contains PIC code */
+#define EF_MIPS_CPIC 4 /* Uses PIC calling sequence */
+#define EF_MIPS_XGOT 8
+#define EF_MIPS_64BIT_WHIRL 16
+#define EF_MIPS_ABI2 32
+#define EF_MIPS_ABI_ON32 64
+#define EF_MIPS_ARCH 0xf0000000 /* MIPS architecture level */
+
+/* Legal values for MIPS architecture level. */
+
+#define EF_MIPS_ARCH_1 0x00000000 /* -mips1 code. */
+#define EF_MIPS_ARCH_2 0x10000000 /* -mips2 code. */
+#define EF_MIPS_ARCH_3 0x20000000 /* -mips3 code. */
+#define EF_MIPS_ARCH_4 0x30000000 /* -mips4 code. */
+#define EF_MIPS_ARCH_5 0x40000000 /* -mips5 code. */
+#define EF_MIPS_ARCH_32 0x60000000 /* MIPS32 code. */
+#define EF_MIPS_ARCH_64 0x70000000 /* MIPS64 code. */
+
+/* The following are non-official names and should not be used. */
+
+#define E_MIPS_ARCH_1 0x00000000 /* -mips1 code. */
+#define E_MIPS_ARCH_2 0x10000000 /* -mips2 code. */
+#define E_MIPS_ARCH_3 0x20000000 /* -mips3 code. */
+#define E_MIPS_ARCH_4 0x30000000 /* -mips4 code. */
+#define E_MIPS_ARCH_5 0x40000000 /* -mips5 code. */
+#define E_MIPS_ARCH_32 0x60000000 /* MIPS32 code. */
+#define E_MIPS_ARCH_64 0x70000000 /* MIPS64 code. */
+
+/* Special section indices. */
+
+#define SHN_MIPS_ACOMMON 0xff00 /* Allocated common symbols */
+#define SHN_MIPS_TEXT 0xff01 /* Allocated test symbols. */
+#define SHN_MIPS_DATA 0xff02 /* Allocated data symbols. */
+#define SHN_MIPS_SCOMMON 0xff03 /* Small common symbols */
+#define SHN_MIPS_SUNDEFINED 0xff04 /* Small undefined symbols */
+
+/* Legal values for sh_type field of Elf32_Shdr. */
+
+#define SHT_MIPS_LIBLIST 0x70000000 /* Shared objects used in link */
+#define SHT_MIPS_MSYM 0x70000001
+#define SHT_MIPS_CONFLICT 0x70000002 /* Conflicting symbols */
+#define SHT_MIPS_GPTAB 0x70000003 /* Global data area sizes */
+#define SHT_MIPS_UCODE 0x70000004 /* Reserved for SGI/MIPS compilers */
+#define SHT_MIPS_DEBUG 0x70000005 /* MIPS ECOFF debugging information*/
+#define SHT_MIPS_REGINFO 0x70000006 /* Register usage information */
+#define SHT_MIPS_PACKAGE 0x70000007
+#define SHT_MIPS_PACKSYM 0x70000008
+#define SHT_MIPS_RELD 0x70000009
+#define SHT_MIPS_IFACE 0x7000000b
+#define SHT_MIPS_CONTENT 0x7000000c
+#define SHT_MIPS_OPTIONS 0x7000000d /* Miscellaneous options. */
+#define SHT_MIPS_SHDR 0x70000010
+#define SHT_MIPS_FDESC 0x70000011
+#define SHT_MIPS_EXTSYM 0x70000012
+#define SHT_MIPS_DENSE 0x70000013
+#define SHT_MIPS_PDESC 0x70000014
+#define SHT_MIPS_LOCSYM 0x70000015
+#define SHT_MIPS_AUXSYM 0x70000016
+#define SHT_MIPS_OPTSYM 0x70000017
+#define SHT_MIPS_LOCSTR 0x70000018
+#define SHT_MIPS_LINE 0x70000019
+#define SHT_MIPS_RFDESC 0x7000001a
+#define SHT_MIPS_DELTASYM 0x7000001b
+#define SHT_MIPS_DELTAINST 0x7000001c
+#define SHT_MIPS_DELTACLASS 0x7000001d
+#define SHT_MIPS_DWARF 0x7000001e /* DWARF debugging information. */
+#define SHT_MIPS_DELTADECL 0x7000001f
+#define SHT_MIPS_SYMBOL_LIB 0x70000020
+#define SHT_MIPS_EVENTS 0x70000021 /* Event section. */
+#define SHT_MIPS_TRANSLATE 0x70000022
+#define SHT_MIPS_PIXIE 0x70000023
+#define SHT_MIPS_XLATE 0x70000024
+#define SHT_MIPS_XLATE_DEBUG 0x70000025
+#define SHT_MIPS_WHIRL 0x70000026
+#define SHT_MIPS_EH_REGION 0x70000027
+#define SHT_MIPS_XLATE_OLD 0x70000028
+#define SHT_MIPS_PDR_EXCEPTION 0x70000029
+
+/* Legal values for sh_flags field of Elf32_Shdr. */
+
+#define SHF_MIPS_GPREL 0x10000000 /* Must be part of global data area */
+#define SHF_MIPS_MERGE 0x20000000
+#define SHF_MIPS_ADDR 0x40000000
+#define SHF_MIPS_STRINGS 0x80000000
+#define SHF_MIPS_NOSTRIP 0x08000000
+#define SHF_MIPS_LOCAL 0x04000000
+#define SHF_MIPS_NAMES 0x02000000
+#define SHF_MIPS_NODUPE 0x01000000
+
+/* Symbol tables. */
+
+/* MIPS specific values for `st_other'. */
+#define STO_MIPS_DEFAULT 0x0
+#define STO_MIPS_INTERNAL 0x1
+#define STO_MIPS_HIDDEN 0x2
+#define STO_MIPS_PROTECTED 0x3
+#define STO_MIPS_SC_ALIGN_UNUSED 0xff
+
+/* MIPS specific values for `st_info'. */
+#define STB_MIPS_SPLIT_COMMON 13
+
+/* Entries found in sections of type SHT_MIPS_GPTAB. */
+
+typedef union {
+ struct
+ {
+ Elf32_Word gt_current_g_value; /* -G value used for compilation */
+ Elf32_Word gt_unused; /* Not used */
+ } gt_header; /* First entry in section */
+ struct
+ {
+ Elf32_Word gt_g_value; /* If this value were used for -G */
+ Elf32_Word gt_bytes; /* This many bytes would be used */
+ } gt_entry; /* Subsequent entries in section */
+} Elf32_gptab;
+
+/* Entry found in sections of type SHT_MIPS_REGINFO. */
+
+typedef struct
+{
+ Elf32_Word ri_gprmask; /* General registers used */
+ Elf32_Word ri_cprmask[4]; /* Coprocessor registers used */
+ Elf32_Sword ri_gp_value; /* $gp register value */
+} Elf32_RegInfo;
+
+/* Entries found in sections of type SHT_MIPS_OPTIONS. */
+
+typedef struct
+{
+ unsigned char kind; /* Determines interpretation of the
+ variable part of descriptor. */
+ unsigned char size; /* Size of descriptor, including header. */
+ Elf32_Section section; /* Section header index of section affected,
+ 0 for global options. */
+ Elf32_Word info; /* Kind-specific information. */
+} Elf_Options;
+
+/* Values for `kind' field in Elf_Options. */
+
+#define ODK_NULL 0 /* Undefined. */
+#define ODK_REGINFO 1 /* Register usage information. */
+#define ODK_EXCEPTIONS 2 /* Exception processing options. */
+#define ODK_PAD 3 /* Section padding options. */
+#define ODK_HWPATCH 4 /* Hardware workarounds performed */
+#define ODK_FILL 5 /* record the fill value used by the linker. */
+#define ODK_TAGS 6 /* reserve space for desktop tools to write. */
+#define ODK_HWAND 7 /* HW workarounds. 'AND' bits when merging. */
+#define ODK_HWOR 8 /* HW workarounds. 'OR' bits when merging. */
+
+/* Values for `info' in Elf_Options for ODK_EXCEPTIONS entries. */
+
+#define OEX_FPU_MIN 0x1f /* FPE's which MUST be enabled. */
+#define OEX_FPU_MAX 0x1f00 /* FPE's which MAY be enabled. */
+#define OEX_PAGE0 0x10000 /* page zero must be mapped. */
+#define OEX_SMM 0x20000 /* Force sequential memory mode? */
+#define OEX_FPDBUG 0x40000 /* Force floating point debug mode? */
+#define OEX_PRECISEFP OEX_FPDBUG
+#define OEX_DISMISS 0x80000 /* Dismiss invalid address faults? */
+
+#define OEX_FPU_INVAL 0x10
+#define OEX_FPU_DIV0 0x08
+#define OEX_FPU_OFLO 0x04
+#define OEX_FPU_UFLO 0x02
+#define OEX_FPU_INEX 0x01
+
+/* Masks for `info' in Elf_Options for an ODK_HWPATCH entry. */
+
+#define OHW_R4KEOP 0x1 /* R4000 end-of-page patch. */
+#define OHW_R8KPFETCH 0x2 /* may need R8000 prefetch patch. */
+#define OHW_R5KEOP 0x4 /* R5000 end-of-page patch. */
+#define OHW_R5KCVTL 0x8 /* R5000 cvt.[ds].l bug. clean=1. */
+
+#define OPAD_PREFIX 0x1
+#define OPAD_POSTFIX 0x2
+#define OPAD_SYMBOL 0x4
+
+/* Entry found in `.options' section. */
+
+typedef struct
+{
+ Elf32_Word hwp_flags1; /* Extra flags. */
+ Elf32_Word hwp_flags2; /* Extra flags. */
+} Elf_Options_Hw;
+
+/* Masks for `info' in ElfOptions for ODK_HWAND and ODK_HWOR entries. */
+
+#define OHWA0_R4KEOP_CHECKED 0x00000001
+#define OHWA1_R4KEOP_CLEAN 0x00000002
+
+/* MIPS relocs. */
+
+#define R_MIPS_NONE 0 /* No reloc */
+#define R_MIPS_16 1 /* Direct 16 bit */
+#define R_MIPS_32 2 /* Direct 32 bit */
+#define R_MIPS_REL32 3 /* PC relative 32 bit */
+#define R_MIPS_26 4 /* Direct 26 bit shifted */
+#define R_MIPS_HI16 5 /* High 16 bit */
+#define R_MIPS_LO16 6 /* Low 16 bit */
+#define R_MIPS_GPREL16 7 /* GP relative 16 bit */
+#define R_MIPS_LITERAL 8 /* 16 bit literal entry */
+#define R_MIPS_GOT16 9 /* 16 bit GOT entry */
+#define R_MIPS_PC16 10 /* PC relative 16 bit */
+#define R_MIPS_CALL16 11 /* 16 bit GOT entry for function */
+#define R_MIPS_GPREL32 12 /* GP relative 32 bit */
+
+#define R_MIPS_SHIFT5 16
+#define R_MIPS_SHIFT6 17
+#define R_MIPS_64 18
+#define R_MIPS_GOT_DISP 19
+#define R_MIPS_GOT_PAGE 20
+#define R_MIPS_GOT_OFST 21
+#define R_MIPS_GOT_HI16 22
+#define R_MIPS_GOT_LO16 23
+#define R_MIPS_SUB 24
+#define R_MIPS_INSERT_A 25
+#define R_MIPS_INSERT_B 26
+#define R_MIPS_DELETE 27
+#define R_MIPS_HIGHER 28
+#define R_MIPS_HIGHEST 29
+#define R_MIPS_CALL_HI16 30
+#define R_MIPS_CALL_LO16 31
+#define R_MIPS_SCN_DISP 32
+#define R_MIPS_REL16 33
+#define R_MIPS_ADD_IMMEDIATE 34
+#define R_MIPS_PJUMP 35
+#define R_MIPS_RELGOT 36
+#define R_MIPS_JALR 37
+/* Keep this the last entry. */
+#define R_MIPS_NUM 38
+
+/* Legal values for p_type field of Elf32_Phdr. */
+
+#define PT_MIPS_REGINFO 0x70000000 /* Register usage information */
+#define PT_MIPS_RTPROC 0x70000001 /* Runtime procedure table. */
+#define PT_MIPS_OPTIONS 0x70000002
+
+/* Special program header types. */
+
+#define PF_MIPS_LOCAL 0x10000000
+
+/* Legal values for d_tag field of Elf32_Dyn. */
+
+#define DT_MIPS_RLD_VERSION 0x70000001 /* Runtime linker interface version */
+#define DT_MIPS_TIME_STAMP 0x70000002 /* Timestamp */
+#define DT_MIPS_ICHECKSUM 0x70000003 /* Checksum */
+#define DT_MIPS_IVERSION 0x70000004 /* Version string (string tbl index) */
+#define DT_MIPS_FLAGS 0x70000005 /* Flags */
+#define DT_MIPS_BASE_ADDRESS 0x70000006 /* Base address */
+#define DT_MIPS_MSYM 0x70000007
+#define DT_MIPS_CONFLICT 0x70000008 /* Address of CONFLICT section */
+#define DT_MIPS_LIBLIST 0x70000009 /* Address of LIBLIST section */
+#define DT_MIPS_LOCAL_GOTNO 0x7000000a /* Number of local GOT entries */
+#define DT_MIPS_CONFLICTNO 0x7000000b /* Number of CONFLICT entries */
+#define DT_MIPS_LIBLISTNO 0x70000010 /* Number of LIBLIST entries */
+#define DT_MIPS_SYMTABNO 0x70000011 /* Number of DYNSYM entries */
+#define DT_MIPS_UNREFEXTNO 0x70000012 /* First external DYNSYM */
+#define DT_MIPS_GOTSYM 0x70000013 /* First GOT entry in DYNSYM */
+#define DT_MIPS_HIPAGENO 0x70000014 /* Number of GOT page table entries */
+#define DT_MIPS_RLD_MAP 0x70000016 /* Address of run time loader map. */
+#define DT_MIPS_DELTA_CLASS 0x70000017 /* Delta C++ class definition. */
+#define DT_MIPS_DELTA_CLASS_NO \
+ 0x70000018 /* Number of entries in \
+DT_MIPS_DELTA_CLASS. */
+#define DT_MIPS_DELTA_INSTANCE 0x70000019 /* Delta C++ class instances. */
+#define DT_MIPS_DELTA_INSTANCE_NO \
+ 0x7000001a /* Number of entries in \
+DT_MIPS_DELTA_INSTANCE. */
+#define DT_MIPS_DELTA_RELOC 0x7000001b /* Delta relocations. */
+#define DT_MIPS_DELTA_RELOC_NO \
+ 0x7000001c /* Number of entries in \
+DT_MIPS_DELTA_RELOC. */
+#define DT_MIPS_DELTA_SYM \
+ 0x7000001d /* Delta symbols that Delta \
+relocations refer to. */
+#define DT_MIPS_DELTA_SYM_NO \
+ 0x7000001e /* Number of entries in \
+DT_MIPS_DELTA_SYM. */
+#define DT_MIPS_DELTA_CLASSSYM \
+ 0x70000020 /* Delta symbols that hold the \
+class declaration. */
+#define DT_MIPS_DELTA_CLASSSYM_NO \
+ 0x70000021 /* Number of entries in \
+DT_MIPS_DELTA_CLASSSYM. */
+#define DT_MIPS_CXX_FLAGS 0x70000022 /* Flags indicating for C++ flavor. */
+#define DT_MIPS_PIXIE_INIT 0x70000023
+#define DT_MIPS_SYMBOL_LIB 0x70000024
+#define DT_MIPS_LOCALPAGE_GOTIDX 0x70000025
+#define DT_MIPS_LOCAL_GOTIDX 0x70000026
+#define DT_MIPS_HIDDEN_GOTIDX 0x70000027
+#define DT_MIPS_PROTECTED_GOTIDX 0x70000028
+#define DT_MIPS_OPTIONS 0x70000029 /* Address of .options. */
+#define DT_MIPS_INTERFACE 0x7000002a /* Address of .interface. */
+#define DT_MIPS_DYNSTR_ALIGN 0x7000002b
+#define DT_MIPS_INTERFACE_SIZE \
+ 0x7000002c /* Size of the .interface section. \
+ */
+#define DT_MIPS_RLD_TEXT_RESOLVE_ADDR \
+ 0x7000002d /* Address of rld_text_rsolve \
+function stored in GOT. */
+#define DT_MIPS_PERF_SUFFIX \
+ 0x7000002e /* Default suffix of dso to be added \
+by rld on dlopen() calls. */
+#define DT_MIPS_COMPACT_SIZE \
+ 0x7000002f /* (O32)Size of compact rel section. \
+ */
+#define DT_MIPS_GP_VALUE 0x70000030 /* GP value for aux GOTs. */
+#define DT_MIPS_AUX_DYNAMIC 0x70000031 /* Address of aux .dynamic. */
+#define DT_MIPS_NUM 0x32
+
+/* Legal values for DT_MIPS_FLAGS Elf32_Dyn entry. */
+
+#define RHF_NONE 0 /* No flags */
+#define RHF_QUICKSTART (1 << 0) /* Use quickstart */
+#define RHF_NOTPOT (1 << 1) /* Hash size not power of 2 */
+#define RHF_NO_LIBRARY_REPLACEMENT (1 << 2) /* Ignore LD_LIBRARY_PATH */
+#define RHF_NO_MOVE (1 << 3)
+#define RHF_SGI_ONLY (1 << 4)
+#define RHF_GUARANTEE_INIT (1 << 5)
+#define RHF_DELTA_C_PLUS_PLUS (1 << 6)
+#define RHF_GUARANTEE_START_INIT (1 << 7)
+#define RHF_PIXIE (1 << 8)
+#define RHF_DEFAULT_DELAY_LOAD (1 << 9)
+#define RHF_REQUICKSTART (1 << 10)
+#define RHF_REQUICKSTARTED (1 << 11)
+#define RHF_CORD (1 << 12)
+#define RHF_NO_UNRES_UNDEF (1 << 13)
+#define RHF_RLD_ORDER_SAFE (1 << 14)
+
+/* Entries found in sections of type SHT_MIPS_LIBLIST. */
+
+typedef struct
+{
+ Elf32_Word l_name; /* Name (string table index) */
+ Elf32_Word l_time_stamp; /* Timestamp */
+ Elf32_Word l_checksum; /* Checksum */
+ Elf32_Word l_version; /* Interface version */
+ Elf32_Word l_flags; /* Flags */
+} Elf32_Lib;
+
+typedef struct
+{
+ Elf64_Word l_name; /* Name (string table index) */
+ Elf64_Word l_time_stamp; /* Timestamp */
+ Elf64_Word l_checksum; /* Checksum */
+ Elf64_Word l_version; /* Interface version */
+ Elf64_Word l_flags; /* Flags */
+} Elf64_Lib;
+
+/* Legal values for l_flags. */
+
+#define LL_NONE 0
+#define LL_EXACT_MATCH (1 << 0) /* Require exact match */
+#define LL_IGNORE_INT_VER (1 << 1) /* Ignore interface version */
+#define LL_REQUIRE_MINOR (1 << 2)
+#define LL_EXPORTS (1 << 3)
+#define LL_DELAY_LOAD (1 << 4)
+#define LL_DELTA (1 << 5)
+
+/* Entries found in sections of type SHT_MIPS_CONFLICT. */
+
+typedef Elf32_Addr Elf32_Conflict;
+
+/* HPPA specific definitions. */
+
+/* Legal values for e_flags field of Elf32_Ehdr. */
+
+#define EF_PARISC_TRAPNIL 0x00010000 /* Trap nil pointer dereference. */
+#define EF_PARISC_EXT 0x00020000 /* Program uses arch. extensions. */
+#define EF_PARISC_LSB 0x00040000 /* Program expects little endian. */
+#define EF_PARISC_WIDE 0x00080000 /* Program expects wide mode. */
+#define EF_PARISC_NO_KABP \
+ 0x00100000 /* No kernel assisted branch \
+prediction. */
+#define EF_PARISC_LAZYSWAP 0x00400000 /* Allow lazy swapping. */
+#define EF_PARISC_ARCH 0x0000ffff /* Architecture version. */
+
+/* Defined values for `e_flags & EF_PARISC_ARCH' are: */
+
+#define EFA_PARISC_1_0 0x020b /* PA-RISC 1.0 big-endian. */
+#define EFA_PARISC_1_1 0x0210 /* PA-RISC 1.1 big-endian. */
+#define EFA_PARISC_2_0 0x0214 /* PA-RISC 2.0 big-endian. */
+
+/* Additional section indeces. */
+
+#define SHN_PARISC_ANSI_COMMON \
+ 0xff00 /* Section for tenatively declared \
+symbols in ANSI C. */
+#define SHN_PARISC_HUGE_COMMON 0xff01 /* Common blocks in huge model. */
+
+/* Legal values for sh_type field of Elf32_Shdr. */
+
+#define SHT_PARISC_EXT 0x70000000 /* Contains product specific ext. */
+#define SHT_PARISC_UNWIND 0x70000001 /* Unwind information. */
+#define SHT_PARISC_DOC 0x70000002 /* Debug info for optimized code. */
+
+/* Legal values for sh_flags field of Elf32_Shdr. */
+
+#define SHF_PARISC_SHORT 0x20000000 /* Section with short addressing. */
+#define SHF_PARISC_HUGE 0x40000000 /* Section far from gp. */
+#define SHF_PARISC_SBP 0x80000000 /* Static branch prediction code. */
+
+/* Legal values for ST_TYPE subfield of st_info (symbol type). */
+
+#define STT_PARISC_MILLICODE 13 /* Millicode function entry point. */
+
+#define STT_HP_OPAQUE (STT_LOOS + 0x1)
+#define STT_HP_STUB (STT_LOOS + 0x2)
+
+/* HPPA relocs. */
+
+#define R_PARISC_NONE 0 /* No reloc. */
+#define R_PARISC_DIR32 1 /* Direct 32-bit reference. */
+#define R_PARISC_DIR21L 2 /* Left 21 bits of eff. address. */
+#define R_PARISC_DIR17R 3 /* Right 17 bits of eff. address. */
+#define R_PARISC_DIR17F 4 /* 17 bits of eff. address. */
+#define R_PARISC_DIR14R 6 /* Right 14 bits of eff. address. */
+#define R_PARISC_PCREL32 9 /* 32-bit rel. address. */
+#define R_PARISC_PCREL21L 10 /* Left 21 bits of rel. address. */
+#define R_PARISC_PCREL17R 11 /* Right 17 bits of rel. address. */
+#define R_PARISC_PCREL17F 12 /* 17 bits of rel. address. */
+#define R_PARISC_PCREL14R 14 /* Right 14 bits of rel. address. */
+#define R_PARISC_DPREL21L 18 /* Left 21 bits of rel. address. */
+#define R_PARISC_DPREL14R 22 /* Right 14 bits of rel. address. */
+#define R_PARISC_GPREL21L 26 /* GP-relative, left 21 bits. */
+#define R_PARISC_GPREL14R 30 /* GP-relative, right 14 bits. */
+#define R_PARISC_LTOFF21L 34 /* LT-relative, left 21 bits. */
+#define R_PARISC_LTOFF14R 38 /* LT-relative, right 14 bits. */
+#define R_PARISC_SECREL32 41 /* 32 bits section rel. address. */
+#define R_PARISC_SEGBASE 48 /* No relocation, set segment base. */
+#define R_PARISC_SEGREL32 49 /* 32 bits segment rel. address. */
+#define R_PARISC_PLTOFF21L 50 /* PLT rel. address, left 21 bits. */
+#define R_PARISC_PLTOFF14R 54 /* PLT rel. address, right 14 bits. */
+#define R_PARISC_LTOFF_FPTR32 57 /* 32 bits LT-rel. function pointer. */
+#define R_PARISC_LTOFF_FPTR21L 58 /* LT-rel. fct ptr, left 21 bits. */
+#define R_PARISC_LTOFF_FPTR14R 62 /* LT-rel. fct ptr, right 14 bits. */
+#define R_PARISC_FPTR64 64 /* 64 bits function address. */
+#define R_PARISC_PLABEL32 65 /* 32 bits function address. */
+#define R_PARISC_PLABEL21L 66 /* Left 21 bits of fct ptr. */
+#define R_PARISC_PLABEL14R 70 /* Left 21 bits of fct ptr. */
+#define R_PARISC_PCREL64 72 /* 64 bits PC-rel. address. */
+#define R_PARISC_PCREL22F 74 /* 22 bits PC-rel. address. */
+#define R_PARISC_PCREL14WR 75 /* PC-rel. address, right 14 bits. */
+#define R_PARISC_PCREL14DR 76 /* PC rel. address, right 14 bits. */
+#define R_PARISC_PCREL16F 77 /* 16 bits PC-rel. address. */
+#define R_PARISC_PCREL16WF 78 /* 16 bits PC-rel. address. */
+#define R_PARISC_PCREL16DF 79 /* 16 bits PC-rel. address. */
+#define R_PARISC_DIR64 80 /* 64 bits of eff. address. */
+#define R_PARISC_DIR14WR 83 /* 14 bits of eff. address. */
+#define R_PARISC_DIR14DR 84 /* 14 bits of eff. address. */
+#define R_PARISC_DIR16F 85 /* 16 bits of eff. address. */
+#define R_PARISC_DIR16WF 86 /* 16 bits of eff. address. */
+#define R_PARISC_DIR16DF 87 /* 16 bits of eff. address. */
+#define R_PARISC_GPREL64 88 /* 64 bits of GP-rel. address. */
+#define R_PARISC_GPREL14WR 91 /* GP-rel. address, right 14 bits. */
+#define R_PARISC_GPREL14DR 92 /* GP-rel. address, right 14 bits. */
+#define R_PARISC_GPREL16F 93 /* 16 bits GP-rel. address. */
+#define R_PARISC_GPREL16WF 94 /* 16 bits GP-rel. address. */
+#define R_PARISC_GPREL16DF 95 /* 16 bits GP-rel. address. */
+#define R_PARISC_LTOFF64 96 /* 64 bits LT-rel. address. */
+#define R_PARISC_LTOFF14WR 99 /* LT-rel. address, right 14 bits. */
+#define R_PARISC_LTOFF14DR 100 /* LT-rel. address, right 14 bits. */
+#define R_PARISC_LTOFF16F 101 /* 16 bits LT-rel. address. */
+#define R_PARISC_LTOFF16WF 102 /* 16 bits LT-rel. address. */
+#define R_PARISC_LTOFF16DF 103 /* 16 bits LT-rel. address. */
+#define R_PARISC_SECREL64 104 /* 64 bits section rel. address. */
+#define R_PARISC_SEGREL64 112 /* 64 bits segment rel. address. */
+#define R_PARISC_PLTOFF14WR 115 /* PLT-rel. address, right 14 bits. */
+#define R_PARISC_PLTOFF14DR 116 /* PLT-rel. address, right 14 bits. */
+#define R_PARISC_PLTOFF16F 117 /* 16 bits LT-rel. address. */
+#define R_PARISC_PLTOFF16WF 118 /* 16 bits PLT-rel. address. */
+#define R_PARISC_PLTOFF16DF 119 /* 16 bits PLT-rel. address. */
+#define R_PARISC_LTOFF_FPTR64 120 /* 64 bits LT-rel. function ptr. */
+#define R_PARISC_LTOFF_FPTR14WR 123 /* LT-rel. fct. ptr., right 14 bits. */
+#define R_PARISC_LTOFF_FPTR14DR 124 /* LT-rel. fct. ptr., right 14 bits. */
+#define R_PARISC_LTOFF_FPTR16F 125 /* 16 bits LT-rel. function ptr. */
+#define R_PARISC_LTOFF_FPTR16WF 126 /* 16 bits LT-rel. function ptr. */
+#define R_PARISC_LTOFF_FPTR16DF 127 /* 16 bits LT-rel. function ptr. */
+#define R_PARISC_LORESERVE 128
+#define R_PARISC_COPY 128 /* Copy relocation. */
+#define R_PARISC_IPLT 129 /* Dynamic reloc, imported PLT */
+#define R_PARISC_EPLT 130 /* Dynamic reloc, exported PLT */
+#define R_PARISC_TPREL32 153 /* 32 bits TP-rel. address. */
+#define R_PARISC_TPREL21L 154 /* TP-rel. address, left 21 bits. */
+#define R_PARISC_TPREL14R 158 /* TP-rel. address, right 14 bits. */
+#define R_PARISC_LTOFF_TP21L 162 /* LT-TP-rel. address, left 21 bits. */
+#define R_PARISC_LTOFF_TP14R 166 /* LT-TP-rel. address, right 14 bits.*/
+#define R_PARISC_LTOFF_TP14F 167 /* 14 bits LT-TP-rel. address. */
+#define R_PARISC_TPREL64 216 /* 64 bits TP-rel. address. */
+#define R_PARISC_TPREL14WR 219 /* TP-rel. address, right 14 bits. */
+#define R_PARISC_TPREL14DR 220 /* TP-rel. address, right 14 bits. */
+#define R_PARISC_TPREL16F 221 /* 16 bits TP-rel. address. */
+#define R_PARISC_TPREL16WF 222 /* 16 bits TP-rel. address. */
+#define R_PARISC_TPREL16DF 223 /* 16 bits TP-rel. address. */
+#define R_PARISC_LTOFF_TP64 224 /* 64 bits LT-TP-rel. address. */
+#define R_PARISC_LTOFF_TP14WR 227 /* LT-TP-rel. address, right 14 bits.*/
+#define R_PARISC_LTOFF_TP14DR 228 /* LT-TP-rel. address, right 14 bits.*/
+#define R_PARISC_LTOFF_TP16F 229 /* 16 bits LT-TP-rel. address. */
+#define R_PARISC_LTOFF_TP16WF 230 /* 16 bits LT-TP-rel. address. */
+#define R_PARISC_LTOFF_TP16DF 231 /* 16 bits LT-TP-rel. address. */
+#define R_PARISC_HIRESERVE 255
+
+/* Legal values for p_type field of Elf32_Phdr/Elf64_Phdr. */
+
+#define PT_HP_TLS (PT_LOOS + 0x0)
+#define PT_HP_CORE_NONE (PT_LOOS + 0x1)
+#define PT_HP_CORE_VERSION (PT_LOOS + 0x2)
+#define PT_HP_CORE_KERNEL (PT_LOOS + 0x3)
+#define PT_HP_CORE_COMM (PT_LOOS + 0x4)
+#define PT_HP_CORE_PROC (PT_LOOS + 0x5)
+#define PT_HP_CORE_LOADABLE (PT_LOOS + 0x6)
+#define PT_HP_CORE_STACK (PT_LOOS + 0x7)
+#define PT_HP_CORE_SHM (PT_LOOS + 0x8)
+#define PT_HP_CORE_MMF (PT_LOOS + 0x9)
+#define PT_HP_PARALLEL (PT_LOOS + 0x10)
+#define PT_HP_FASTBIND (PT_LOOS + 0x11)
+#define PT_HP_OPT_ANNOT (PT_LOOS + 0x12)
+#define PT_HP_HSL_ANNOT (PT_LOOS + 0x13)
+#define PT_HP_STACK (PT_LOOS + 0x14)
+
+#define PT_PARISC_ARCHEXT 0x70000000
+#define PT_PARISC_UNWIND 0x70000001
+
+/* Legal values for p_flags field of Elf32_Phdr/Elf64_Phdr. */
+
+#define PF_PARISC_SBP 0x08000000
+
+#define PF_HP_PAGE_SIZE 0x00100000
+#define PF_HP_FAR_SHARED 0x00200000
+#define PF_HP_NEAR_SHARED 0x00400000
+#define PF_HP_CODE 0x01000000
+#define PF_HP_MODIFY 0x02000000
+#define PF_HP_LAZYSWAP 0x04000000
+#define PF_HP_SBP 0x08000000
+
+/* Alpha specific definitions. */
+
+/* Legal values for e_flags field of Elf64_Ehdr. */
+
+#define EF_ALPHA_32BIT 1 /* All addresses must be < 2GB. */
+#define EF_ALPHA_CANRELAX 2 /* Relocations for relaxing exist. */
+
+/* Legal values for sh_type field of Elf64_Shdr. */
+
+/* These two are primerily concerned with ECOFF debugging info. */
+#define SHT_ALPHA_DEBUG 0x70000001
+#define SHT_ALPHA_REGINFO 0x70000002
+
+/* Legal values for sh_flags field of Elf64_Shdr. */
+
+#define SHF_ALPHA_GPREL 0x10000000
+
+/* Legal values for st_other field of Elf64_Sym. */
+#define STO_ALPHA_NOPV 0x80 /* No PV required. */
+#define STO_ALPHA_STD_GPLOAD 0x88 /* PV only used for initial ldgp. */
+
+/* Alpha relocs. */
+
+#define R_ALPHA_NONE 0 /* No reloc */
+#define R_ALPHA_REFLONG 1 /* Direct 32 bit */
+#define R_ALPHA_REFQUAD 2 /* Direct 64 bit */
+#define R_ALPHA_GPREL32 3 /* GP relative 32 bit */
+#define R_ALPHA_LITERAL 4 /* GP relative 16 bit w/optimization */
+#define R_ALPHA_LITUSE 5 /* Optimization hint for LITERAL */
+#define R_ALPHA_GPDISP 6 /* Add displacement to GP */
+#define R_ALPHA_BRADDR 7 /* PC+4 relative 23 bit shifted */
+#define R_ALPHA_HINT 8 /* PC+4 relative 16 bit shifted */
+#define R_ALPHA_SREL16 9 /* PC relative 16 bit */
+#define R_ALPHA_SREL32 10 /* PC relative 32 bit */
+#define R_ALPHA_SREL64 11 /* PC relative 64 bit */
+#define R_ALPHA_GPRELHIGH 17 /* GP relative 32 bit, high 16 bits */
+#define R_ALPHA_GPRELLOW 18 /* GP relative 32 bit, low 16 bits */
+#define R_ALPHA_GPREL16 19 /* GP relative 16 bit */
+#define R_ALPHA_COPY 24 /* Copy symbol at runtime */
+#define R_ALPHA_GLOB_DAT 25 /* Create GOT entry */
+#define R_ALPHA_JMP_SLOT 26 /* Create PLT entry */
+#define R_ALPHA_RELATIVE 27 /* Adjust by program base */
+#define R_ALPHA_TLS_GD_HI 28
+#define R_ALPHA_TLSGD 29
+#define R_ALPHA_TLS_LDM 30
+#define R_ALPHA_DTPMOD64 31
+#define R_ALPHA_GOTDTPREL 32
+#define R_ALPHA_DTPREL64 33
+#define R_ALPHA_DTPRELHI 34
+#define R_ALPHA_DTPRELLO 35
+#define R_ALPHA_DTPREL16 36
+#define R_ALPHA_GOTTPREL 37
+#define R_ALPHA_TPREL64 38
+#define R_ALPHA_TPRELHI 39
+#define R_ALPHA_TPRELLO 40
+#define R_ALPHA_TPREL16 41
+/* Keep this the last entry. */
+#define R_ALPHA_NUM 46
+
+/* Magic values of the LITUSE relocation addend. */
+#define LITUSE_ALPHA_ADDR 0
+#define LITUSE_ALPHA_BASE 1
+#define LITUSE_ALPHA_BYTOFF 2
+#define LITUSE_ALPHA_JSR 3
+#define LITUSE_ALPHA_TLS_GD 4
+#define LITUSE_ALPHA_TLS_LDM 5
+
+/* PowerPC specific declarations */
+
+/* Values for Elf32/64_Ehdr.e_flags. */
+#define EF_PPC_EMB 0x80000000 /* PowerPC embedded flag */
+
+/* Cygnus local bits below */
+#define EF_PPC_RELOCATABLE 0x00010000 /* PowerPC -mrelocatable flag*/
+#define EF_PPC_RELOCATABLE_LIB \
+ 0x00008000 /* PowerPC -mrelocatable-lib \
+flag */
+
+/* PowerPC relocations defined by the ABIs */
+#define R_PPC_NONE 0
+#define R_PPC_ADDR32 1 /* 32bit absolute address */
+#define R_PPC_ADDR24 2 /* 26bit address, 2 bits ignored. */
+#define R_PPC_ADDR16 3 /* 16bit absolute address */
+#define R_PPC_ADDR16_LO 4 /* lower 16bit of absolute address */
+#define R_PPC_ADDR16_HI 5 /* high 16bit of absolute address */
+#define R_PPC_ADDR16_HA 6 /* adjusted high 16bit */
+#define R_PPC_ADDR14 7 /* 16bit address, 2 bits ignored */
+#define R_PPC_ADDR14_BRTAKEN 8
+#define R_PPC_ADDR14_BRNTAKEN 9
+#define R_PPC_REL24 10 /* PC relative 26 bit */
+#define R_PPC_REL14 11 /* PC relative 16 bit */
+#define R_PPC_REL14_BRTAKEN 12
+#define R_PPC_REL14_BRNTAKEN 13
+#define R_PPC_GOT16 14
+#define R_PPC_GOT16_LO 15
+#define R_PPC_GOT16_HI 16
+#define R_PPC_GOT16_HA 17
+#define R_PPC_PLTREL24 18
+#define R_PPC_COPY 19
+#define R_PPC_GLOB_DAT 20
+#define R_PPC_JMP_SLOT 21
+#define R_PPC_RELATIVE 22
+#define R_PPC_LOCAL24PC 23
+#define R_PPC_UADDR32 24
+#define R_PPC_UADDR16 25
+#define R_PPC_REL32 26
+#define R_PPC_PLT32 27
+#define R_PPC_PLTREL32 28
+#define R_PPC_PLT16_LO 29
+#define R_PPC_PLT16_HI 30
+#define R_PPC_PLT16_HA 31
+#define R_PPC_SDAREL16 32
+#define R_PPC_SECTOFF 33
+#define R_PPC_SECTOFF_LO 34
+#define R_PPC_SECTOFF_HI 35
+#define R_PPC_SECTOFF_HA 36
+
+/* PowerPC relocations defined for the TLS access ABI. */
+#define R_PPC_TLS 67 /* none (sym+add)@tls */
+#define R_PPC_DTPMOD32 68 /* word32 (sym+add)@dtpmod */
+#define R_PPC_TPREL16 69 /* half16* (sym+add)@tprel */
+#define R_PPC_TPREL16_LO 70 /* half16 (sym+add)@tprel@l */
+#define R_PPC_TPREL16_HI 71 /* half16 (sym+add)@tprel@h */
+#define R_PPC_TPREL16_HA 72 /* half16 (sym+add)@tprel@ha */
+#define R_PPC_TPREL32 73 /* word32 (sym+add)@tprel */
+#define R_PPC_DTPREL16 74 /* half16* (sym+add)@dtprel */
+#define R_PPC_DTPREL16_LO 75 /* half16 (sym+add)@dtprel@l */
+#define R_PPC_DTPREL16_HI 76 /* half16 (sym+add)@dtprel@h */
+#define R_PPC_DTPREL16_HA 77 /* half16 (sym+add)@dtprel@ha */
+#define R_PPC_DTPREL32 78 /* word32 (sym+add)@dtprel */
+#define R_PPC_GOT_TLSGD16 79 /* half16* (sym+add)@got@tlsgd */
+#define R_PPC_GOT_TLSGD16_LO 80 /* half16 (sym+add)@got@tlsgd@l */
+#define R_PPC_GOT_TLSGD16_HI 81 /* half16 (sym+add)@got@tlsgd@h */
+#define R_PPC_GOT_TLSGD16_HA 82 /* half16 (sym+add)@got@tlsgd@ha */
+#define R_PPC_GOT_TLSLD16 83 /* half16* (sym+add)@got@tlsld */
+#define R_PPC_GOT_TLSLD16_LO 84 /* half16 (sym+add)@got@tlsld@l */
+#define R_PPC_GOT_TLSLD16_HI 85 /* half16 (sym+add)@got@tlsld@h */
+#define R_PPC_GOT_TLSLD16_HA 86 /* half16 (sym+add)@got@tlsld@ha */
+#define R_PPC_GOT_TPREL16 87 /* half16* (sym+add)@got@tprel */
+#define R_PPC_GOT_TPREL16_LO 88 /* half16 (sym+add)@got@tprel@l */
+#define R_PPC_GOT_TPREL16_HI 89 /* half16 (sym+add)@got@tprel@h */
+#define R_PPC_GOT_TPREL16_HA 90 /* half16 (sym+add)@got@tprel@ha */
+#define R_PPC_GOT_DTPREL16 91 /* half16* (sym+add)@got@dtprel */
+#define R_PPC_GOT_DTPREL16_LO 92 /* half16* (sym+add)@got@dtprel@l */
+#define R_PPC_GOT_DTPREL16_HI 93 /* half16* (sym+add)@got@dtprel@h */
+#define R_PPC_GOT_DTPREL16_HA 94 /* half16* (sym+add)@got@dtprel@ha */
+
+/* Keep this the last entry. */
+#define R_PPC_NUM 95
+
+/* The remaining relocs are from the Embedded ELF ABI, and are not
+ in the SVR4 ELF ABI. */
+#define R_PPC_EMB_NADDR32 101
+#define R_PPC_EMB_NADDR16 102
+#define R_PPC_EMB_NADDR16_LO 103
+#define R_PPC_EMB_NADDR16_HI 104
+#define R_PPC_EMB_NADDR16_HA 105
+#define R_PPC_EMB_SDAI16 106
+#define R_PPC_EMB_SDA2I16 107
+#define R_PPC_EMB_SDA2REL 108
+#define R_PPC_EMB_SDA21 109 /* 16 bit offset in SDA */
+#define R_PPC_EMB_MRKREF 110
+#define R_PPC_EMB_RELSEC16 111
+#define R_PPC_EMB_RELST_LO 112
+#define R_PPC_EMB_RELST_HI 113
+#define R_PPC_EMB_RELST_HA 114
+#define R_PPC_EMB_BIT_FLD 115
+#define R_PPC_EMB_RELSDA 116 /* 16 bit relative offset in SDA */
+
+/* Diab tool relocations. */
+#define R_PPC_DIAB_SDA21_LO 180 /* like EMB_SDA21, but lower 16 bit */
+#define R_PPC_DIAB_SDA21_HI 181 /* like EMB_SDA21, but high 16 bit */
+#define R_PPC_DIAB_SDA21_HA 182 /* like EMB_SDA21, adjusted high 16 */
+#define R_PPC_DIAB_RELSDA_LO 183 /* like EMB_RELSDA, but lower 16 bit */
+#define R_PPC_DIAB_RELSDA_HI 184 /* like EMB_RELSDA, but high 16 bit */
+#define R_PPC_DIAB_RELSDA_HA 185 /* like EMB_RELSDA, adjusted high 16 */
+
+/* This is a phony reloc to handle any old fashioned TOC16 references
+ that may still be in object files. */
+#define R_PPC_TOC16 255
+
+/* PowerPC64 relocations defined by the ABIs */
+#define R_PPC64_NONE R_PPC_NONE
+#define R_PPC64_ADDR32 R_PPC_ADDR32 /* 32bit absolute address */
+#define R_PPC64_ADDR24 R_PPC_ADDR24 /* 26bit address, word aligned */
+#define R_PPC64_ADDR16 R_PPC_ADDR16 /* 16bit absolute address */
+#define R_PPC64_ADDR16_LO R_PPC_ADDR16_LO /* lower 16bits of address */
+#define R_PPC64_ADDR16_HI R_PPC_ADDR16_HI /* high 16bits of address. */
+#define R_PPC64_ADDR16_HA R_PPC_ADDR16_HA /* adjusted high 16bits. */
+#define R_PPC64_ADDR14 R_PPC_ADDR14 /* 16bit address, word aligned */
+#define R_PPC64_ADDR14_BRTAKEN R_PPC_ADDR14_BRTAKEN
+#define R_PPC64_ADDR14_BRNTAKEN R_PPC_ADDR14_BRNTAKEN
+#define R_PPC64_REL24 R_PPC_REL24 /* PC-rel. 26 bit, word aligned */
+#define R_PPC64_REL14 R_PPC_REL14 /* PC relative 16 bit */
+#define R_PPC64_REL14_BRTAKEN R_PPC_REL14_BRTAKEN
+#define R_PPC64_REL14_BRNTAKEN R_PPC_REL14_BRNTAKEN
+#define R_PPC64_GOT16 R_PPC_GOT16
+#define R_PPC64_GOT16_LO R_PPC_GOT16_LO
+#define R_PPC64_GOT16_HI R_PPC_GOT16_HI
+#define R_PPC64_GOT16_HA R_PPC_GOT16_HA
+
+#define R_PPC64_COPY R_PPC_COPY
+#define R_PPC64_GLOB_DAT R_PPC_GLOB_DAT
+#define R_PPC64_JMP_SLOT R_PPC_JMP_SLOT
+#define R_PPC64_RELATIVE R_PPC_RELATIVE
+
+#define R_PPC64_UADDR32 R_PPC_UADDR32
+#define R_PPC64_UADDR16 R_PPC_UADDR16
+#define R_PPC64_REL32 R_PPC_REL32
+#define R_PPC64_PLT32 R_PPC_PLT32
+#define R_PPC64_PLTREL32 R_PPC_PLTREL32
+#define R_PPC64_PLT16_LO R_PPC_PLT16_LO
+#define R_PPC64_PLT16_HI R_PPC_PLT16_HI
+#define R_PPC64_PLT16_HA R_PPC_PLT16_HA
+
+#define R_PPC64_SECTOFF R_PPC_SECTOFF
+#define R_PPC64_SECTOFF_LO R_PPC_SECTOFF_LO
+#define R_PPC64_SECTOFF_HI R_PPC_SECTOFF_HI
+#define R_PPC64_SECTOFF_HA R_PPC_SECTOFF_HA
+#define R_PPC64_ADDR30 37 /* word30 (S + A - P) >> 2 */
+#define R_PPC64_ADDR64 38 /* doubleword64 S + A */
+#define R_PPC64_ADDR16_HIGHER 39 /* half16 #higher(S + A) */
+#define R_PPC64_ADDR16_HIGHERA 40 /* half16 #highera(S + A) */
+#define R_PPC64_ADDR16_HIGHEST 41 /* half16 #highest(S + A) */
+#define R_PPC64_ADDR16_HIGHESTA 42 /* half16 #highesta(S + A) */
+#define R_PPC64_UADDR64 43 /* doubleword64 S + A */
+#define R_PPC64_REL64 44 /* doubleword64 S + A - P */
+#define R_PPC64_PLT64 45 /* doubleword64 L + A */
+#define R_PPC64_PLTREL64 46 /* doubleword64 L + A - P */
+#define R_PPC64_TOC16 47 /* half16* S + A - .TOC */
+#define R_PPC64_TOC16_LO 48 /* half16 #lo(S + A - .TOC.) */
+#define R_PPC64_TOC16_HI 49 /* half16 #hi(S + A - .TOC.) */
+#define R_PPC64_TOC16_HA 50 /* half16 #ha(S + A - .TOC.) */
+#define R_PPC64_TOC 51 /* doubleword64 .TOC */
+#define R_PPC64_PLTGOT16 52 /* half16* M + A */
+#define R_PPC64_PLTGOT16_LO 53 /* half16 #lo(M + A) */
+#define R_PPC64_PLTGOT16_HI 54 /* half16 #hi(M + A) */
+#define R_PPC64_PLTGOT16_HA 55 /* half16 #ha(M + A) */
+
+#define R_PPC64_ADDR16_DS 56 /* half16ds* (S + A) >> 2 */
+#define R_PPC64_ADDR16_LO_DS 57 /* half16ds #lo(S + A) >> 2 */
+#define R_PPC64_GOT16_DS 58 /* half16ds* (G + A) >> 2 */
+#define R_PPC64_GOT16_LO_DS 59 /* half16ds #lo(G + A) >> 2 */
+#define R_PPC64_PLT16_LO_DS 60 /* half16ds #lo(L + A) >> 2 */
+#define R_PPC64_SECTOFF_DS 61 /* half16ds* (R + A) >> 2 */
+#define R_PPC64_SECTOFF_LO_DS 62 /* half16ds #lo(R + A) >> 2 */
+#define R_PPC64_TOC16_DS 63 /* half16ds* (S + A - .TOC.) >> 2 */
+#define R_PPC64_TOC16_LO_DS 64 /* half16ds #lo(S + A - .TOC.) >> 2 */
+#define R_PPC64_PLTGOT16_DS 65 /* half16ds* (M + A) >> 2 */
+#define R_PPC64_PLTGOT16_LO_DS 66 /* half16ds #lo(M + A) >> 2 */
+
+/* PowerPC64 relocations defined for the TLS access ABI. */
+#define R_PPC64_TLS 67 /* none (sym+add)@tls */
+#define R_PPC64_DTPMOD64 68 /* doubleword64 (sym+add)@dtpmod */
+#define R_PPC64_TPREL16 69 /* half16* (sym+add)@tprel */
+#define R_PPC64_TPREL16_LO 70 /* half16 (sym+add)@tprel@l */
+#define R_PPC64_TPREL16_HI 71 /* half16 (sym+add)@tprel@h */
+#define R_PPC64_TPREL16_HA 72 /* half16 (sym+add)@tprel@ha */
+#define R_PPC64_TPREL64 73 /* doubleword64 (sym+add)@tprel */
+#define R_PPC64_DTPREL16 74 /* half16* (sym+add)@dtprel */
+#define R_PPC64_DTPREL16_LO 75 /* half16 (sym+add)@dtprel@l */
+#define R_PPC64_DTPREL16_HI 76 /* half16 (sym+add)@dtprel@h */
+#define R_PPC64_DTPREL16_HA 77 /* half16 (sym+add)@dtprel@ha */
+#define R_PPC64_DTPREL64 78 /* doubleword64 (sym+add)@dtprel */
+#define R_PPC64_GOT_TLSGD16 79 /* half16* (sym+add)@got@tlsgd */
+#define R_PPC64_GOT_TLSGD16_LO 80 /* half16 (sym+add)@got@tlsgd@l */
+#define R_PPC64_GOT_TLSGD16_HI 81 /* half16 (sym+add)@got@tlsgd@h */
+#define R_PPC64_GOT_TLSGD16_HA 82 /* half16 (sym+add)@got@tlsgd@ha */
+#define R_PPC64_GOT_TLSLD16 83 /* half16* (sym+add)@got@tlsld */
+#define R_PPC64_GOT_TLSLD16_LO 84 /* half16 (sym+add)@got@tlsld@l */
+#define R_PPC64_GOT_TLSLD16_HI 85 /* half16 (sym+add)@got@tlsld@h */
+#define R_PPC64_GOT_TLSLD16_HA 86 /* half16 (sym+add)@got@tlsld@ha */
+#define R_PPC64_GOT_TPREL16_DS 87 /* half16ds* (sym+add)@got@tprel */
+#define R_PPC64_GOT_TPREL16_LO_DS 88 /* half16ds (sym+add)@got@tprel@l */
+#define R_PPC64_GOT_TPREL16_HI 89 /* half16 (sym+add)@got@tprel@h */
+#define R_PPC64_GOT_TPREL16_HA 90 /* half16 (sym+add)@got@tprel@ha */
+#define R_PPC64_GOT_DTPREL16_DS 91 /* half16ds* (sym+add)@got@dtprel */
+#define R_PPC64_GOT_DTPREL16_LO_DS 92 /* half16ds (sym+add)@got@dtprel@l */
+#define R_PPC64_GOT_DTPREL16_HI 93 /* half16 (sym+add)@got@dtprel@h */
+#define R_PPC64_GOT_DTPREL16_HA 94 /* half16 (sym+add)@got@dtprel@ha */
+#define R_PPC64_TPREL16_DS 95 /* half16ds* (sym+add)@tprel */
+#define R_PPC64_TPREL16_LO_DS 96 /* half16ds (sym+add)@tprel@l */
+#define R_PPC64_TPREL16_HIGHER 97 /* half16 (sym+add)@tprel@higher */
+#define R_PPC64_TPREL16_HIGHERA 98 /* half16 (sym+add)@tprel@highera */
+#define R_PPC64_TPREL16_HIGHEST 99 /* half16 (sym+add)@tprel@highest */
+#define R_PPC64_TPREL16_HIGHESTA 100 /* half16 (sym+add)@tprel@highesta */
+#define R_PPC64_DTPREL16_DS 101 /* half16ds* (sym+add)@dtprel */
+#define R_PPC64_DTPREL16_LO_DS 102 /* half16ds (sym+add)@dtprel@l */
+#define R_PPC64_DTPREL16_HIGHER 103 /* half16 (sym+add)@dtprel@higher */
+#define R_PPC64_DTPREL16_HIGHERA 104 /* half16 (sym+add)@dtprel@highera */
+#define R_PPC64_DTPREL16_HIGHEST 105 /* half16 (sym+add)@dtprel@highest */
+#define R_PPC64_DTPREL16_HIGHESTA 106 /* half16 (sym+add)@dtprel@highesta */
+
+/* Keep this the last entry. */
+#define R_PPC64_NUM 107
+
+/* PowerPC64 specific values for the Dyn d_tag field. */
+#define DT_PPC64_GLINK (DT_LOPROC + 0)
+#define DT_PPC64_OPD (DT_LOPROC + 1)
+#define DT_PPC64_OPDSZ (DT_LOPROC + 2)
+#define DT_PPC64_NUM 3
+
+/* ARM specific declarations */
+
+/* Processor specific flags for the ELF header e_flags field. */
+#define EF_ARM_RELEXEC 0x01
+#define EF_ARM_HASENTRY 0x02
+#define EF_ARM_INTERWORK 0x04
+#define EF_ARM_APCS_26 0x08
+#define EF_ARM_APCS_FLOAT 0x10
+#define EF_ARM_PIC 0x20
+#define EF_ARM_ALIGN8 0x40 /* 8-bit structure alignment is in use */
+#define EF_ARM_NEW_ABI 0x80
+#define EF_ARM_OLD_ABI 0x100
+
+/* Other constants defined in the ARM ELF spec. version B-01. */
+/* NB. These conflict with values defined above. */
+#define EF_ARM_SYMSARESORTED 0x04
+#define EF_ARM_DYNSYMSUSESEGIDX 0x08
+#define EF_ARM_MAPSYMSFIRST 0x10
+#define EF_ARM_EABIMASK 0XFF000000
+
+#define EF_ARM_EABI_VERSION(flags) ((flags)&EF_ARM_EABIMASK)
+#define EF_ARM_EABI_UNKNOWN 0x00000000
+#define EF_ARM_EABI_VER1 0x01000000
+#define EF_ARM_EABI_VER2 0x02000000
+
+/* Additional symbol types for Thumb */
+#define STT_ARM_TFUNC 0xd
+
+/* ARM-specific values for sh_flags */
+#define SHF_ARM_ENTRYSECT 0x10000000 /* Section contains an entry point */
+#define SHF_ARM_COMDEF \
+ 0x80000000 /* Section may be multiply defined \
+in the input to a link step */
+
+/* ARM-specific program header flags */
+#define PF_ARM_SB \
+ 0x10000000 /* Segment contains the location \
+addressed by the static base */
+
+/* ARM relocs. */
+#define R_ARM_NONE 0 /* No reloc */
+#define R_ARM_PC24 1 /* PC relative 26 bit branch */
+#define R_ARM_ABS32 2 /* Direct 32 bit */
+#define R_ARM_REL32 3 /* PC relative 32 bit */
+#define R_ARM_PC13 4
+#define R_ARM_ABS16 5 /* Direct 16 bit */
+#define R_ARM_ABS12 6 /* Direct 12 bit */
+#define R_ARM_THM_ABS5 7
+#define R_ARM_ABS8 8 /* Direct 8 bit */
+#define R_ARM_SBREL32 9
+#define R_ARM_THM_PC22 10
+#define R_ARM_THM_PC8 11
+#define R_ARM_AMP_VCALL9 12
+#define R_ARM_SWI24 13
+#define R_ARM_THM_SWI8 14
+#define R_ARM_XPC25 15
+#define R_ARM_THM_XPC22 16
+#define R_ARM_COPY 20 /* Copy symbol at runtime */
+#define R_ARM_GLOB_DAT 21 /* Create GOT entry */
+#define R_ARM_JUMP_SLOT 22 /* Create PLT entry */
+#define R_ARM_RELATIVE 23 /* Adjust by program base */
+#define R_ARM_GOTOFF 24 /* 32 bit offset to GOT */
+#define R_ARM_GOTPC 25 /* 32 bit PC relative offset to GOT */
+#define R_ARM_GOT32 26 /* 32 bit GOT entry */
+#define R_ARM_PLT32 27 /* 32 bit PLT address */
+#define R_ARM_ALU_PCREL_7_0 32
+#define R_ARM_ALU_PCREL_15_8 33
+#define R_ARM_ALU_PCREL_23_15 34
+#define R_ARM_LDR_SBREL_11_0 35
+#define R_ARM_ALU_SBREL_19_12 36
+#define R_ARM_ALU_SBREL_27_20 37
+#define R_ARM_GNU_VTENTRY 100
+#define R_ARM_GNU_VTINHERIT 101
+#define R_ARM_THM_PC11 102 /* thumb unconditional branch */
+#define R_ARM_THM_PC9 103 /* thumb conditional branch */
+#define R_ARM_RXPC25 249
+#define R_ARM_RSBREL32 250
+#define R_ARM_THM_RPC22 251
+#define R_ARM_RREL32 252
+#define R_ARM_RABS22 253
+#define R_ARM_RPC24 254
+#define R_ARM_RBASE 255
+/* Keep this the last entry. */
+#define R_ARM_NUM 256
+
+/* IA-64 specific declarations. */
+
+/* Processor specific flags for the Ehdr e_flags field. */
+#define EF_IA_64_MASKOS 0x0000000f /* os-specific flags */
+#define EF_IA_64_ABI64 0x00000010 /* 64-bit ABI */
+#define EF_IA_64_ARCH 0xff000000 /* arch. version mask */
+
+/* Processor specific values for the Phdr p_type field. */
+#define PT_IA_64_ARCHEXT (PT_LOPROC + 0) /* arch extension bits */
+#define PT_IA_64_UNWIND (PT_LOPROC + 1) /* ia64 unwind bits */
+#define PT_IA_64_HP_OPT_ANOT (PT_LOOS + 0x12)
+#define PT_IA_64_HP_HSL_ANOT (PT_LOOS + 0x13)
+#define PT_IA_64_HP_STACK (PT_LOOS + 0x14)
+
+/* Processor specific flags for the Phdr p_flags field. */
+#define PF_IA_64_NORECOV 0x80000000 /* spec insns w/o recovery */
+
+/* Processor specific values for the Shdr sh_type field. */
+#define SHT_IA_64_EXT (SHT_LOPROC + 0) /* extension bits */
+#define SHT_IA_64_UNWIND (SHT_LOPROC + 1) /* unwind bits */
+
+/* Processor specific flags for the Shdr sh_flags field. */
+#define SHF_IA_64_SHORT 0x10000000 /* section near gp */
+#define SHF_IA_64_NORECOV 0x20000000 /* spec insns w/o recovery */
+
+/* Processor specific values for the Dyn d_tag field. */
+#define DT_IA_64_PLT_RESERVE (DT_LOPROC + 0)
+#define DT_IA_64_NUM 1
+
+/* IA-64 relocations. */
+#define R_IA64_NONE 0x00 /* none */
+#define R_IA64_IMM14 0x21 /* symbol + addend, add imm14 */
+#define R_IA64_IMM22 0x22 /* symbol + addend, add imm22 */
+#define R_IA64_IMM64 0x23 /* symbol + addend, mov imm64 */
+#define R_IA64_DIR32MSB 0x24 /* symbol + addend, data4 MSB */
+#define R_IA64_DIR32LSB 0x25 /* symbol + addend, data4 LSB */
+#define R_IA64_DIR64MSB 0x26 /* symbol + addend, data8 MSB */
+#define R_IA64_DIR64LSB 0x27 /* symbol + addend, data8 LSB */
+#define R_IA64_GPREL22 0x2a /* @gprel(sym + add), add imm22 */
+#define R_IA64_GPREL64I 0x2b /* @gprel(sym + add), mov imm64 */
+#define R_IA64_GPREL32MSB 0x2c /* @gprel(sym + add), data4 MSB */
+#define R_IA64_GPREL32LSB 0x2d /* @gprel(sym + add), data4 LSB */
+#define R_IA64_GPREL64MSB 0x2e /* @gprel(sym + add), data8 MSB */
+#define R_IA64_GPREL64LSB 0x2f /* @gprel(sym + add), data8 LSB */
+#define R_IA64_LTOFF22 0x32 /* @ltoff(sym + add), add imm22 */
+#define R_IA64_LTOFF64I 0x33 /* @ltoff(sym + add), mov imm64 */
+#define R_IA64_PLTOFF22 0x3a /* @pltoff(sym + add), add imm22 */
+#define R_IA64_PLTOFF64I 0x3b /* @pltoff(sym + add), mov imm64 */
+#define R_IA64_PLTOFF64MSB 0x3e /* @pltoff(sym + add), data8 MSB */
+#define R_IA64_PLTOFF64LSB 0x3f /* @pltoff(sym + add), data8 LSB */
+#define R_IA64_FPTR64I 0x43 /* @fptr(sym + add), mov imm64 */
+#define R_IA64_FPTR32MSB 0x44 /* @fptr(sym + add), data4 MSB */
+#define R_IA64_FPTR32LSB 0x45 /* @fptr(sym + add), data4 LSB */
+#define R_IA64_FPTR64MSB 0x46 /* @fptr(sym + add), data8 MSB */
+#define R_IA64_FPTR64LSB 0x47 /* @fptr(sym + add), data8 LSB */
+#define R_IA64_PCREL60B 0x48 /* @pcrel(sym + add), brl */
+#define R_IA64_PCREL21B 0x49 /* @pcrel(sym + add), ptb, call */
+#define R_IA64_PCREL21M 0x4a /* @pcrel(sym + add), chk.s */
+#define R_IA64_PCREL21F 0x4b /* @pcrel(sym + add), fchkf */
+#define R_IA64_PCREL32MSB 0x4c /* @pcrel(sym + add), data4 MSB */
+#define R_IA64_PCREL32LSB 0x4d /* @pcrel(sym + add), data4 LSB */
+#define R_IA64_PCREL64MSB 0x4e /* @pcrel(sym + add), data8 MSB */
+#define R_IA64_PCREL64LSB 0x4f /* @pcrel(sym + add), data8 LSB */
+#define R_IA64_LTOFF_FPTR22 0x52 /* @ltoff(@fptr(s+a)), imm22 */
+#define R_IA64_LTOFF_FPTR64I 0x53 /* @ltoff(@fptr(s+a)), imm64 */
+#define R_IA64_LTOFF_FPTR32MSB 0x54 /* @ltoff(@fptr(s+a)), data4 MSB */
+#define R_IA64_LTOFF_FPTR32LSB 0x55 /* @ltoff(@fptr(s+a)), data4 LSB */
+#define R_IA64_LTOFF_FPTR64MSB 0x56 /* @ltoff(@fptr(s+a)), data8 MSB */
+#define R_IA64_LTOFF_FPTR64LSB 0x57 /* @ltoff(@fptr(s+a)), data8 LSB */
+#define R_IA64_SEGREL32MSB 0x5c /* @segrel(sym + add), data4 MSB */
+#define R_IA64_SEGREL32LSB 0x5d /* @segrel(sym + add), data4 LSB */
+#define R_IA64_SEGREL64MSB 0x5e /* @segrel(sym + add), data8 MSB */
+#define R_IA64_SEGREL64LSB 0x5f /* @segrel(sym + add), data8 LSB */
+#define R_IA64_SECREL32MSB 0x64 /* @secrel(sym + add), data4 MSB */
+#define R_IA64_SECREL32LSB 0x65 /* @secrel(sym + add), data4 LSB */
+#define R_IA64_SECREL64MSB 0x66 /* @secrel(sym + add), data8 MSB */
+#define R_IA64_SECREL64LSB 0x67 /* @secrel(sym + add), data8 LSB */
+#define R_IA64_REL32MSB 0x6c /* data 4 + REL */
+#define R_IA64_REL32LSB 0x6d /* data 4 + REL */
+#define R_IA64_REL64MSB 0x6e /* data 8 + REL */
+#define R_IA64_REL64LSB 0x6f /* data 8 + REL */
+#define R_IA64_LTV32MSB 0x74 /* symbol + addend, data4 MSB */
+#define R_IA64_LTV32LSB 0x75 /* symbol + addend, data4 LSB */
+#define R_IA64_LTV64MSB 0x76 /* symbol + addend, data8 MSB */
+#define R_IA64_LTV64LSB 0x77 /* symbol + addend, data8 LSB */
+#define R_IA64_PCREL21BI 0x79 /* @pcrel(sym + add), 21bit inst */
+#define R_IA64_PCREL22 0x7a /* @pcrel(sym + add), 22bit inst */
+#define R_IA64_PCREL64I 0x7b /* @pcrel(sym + add), 64bit inst */
+#define R_IA64_IPLTMSB 0x80 /* dynamic reloc, imported PLT, MSB */
+#define R_IA64_IPLTLSB 0x81 /* dynamic reloc, imported PLT, LSB */
+#define R_IA64_COPY 0x84 /* copy relocation */
+#define R_IA64_SUB 0x85 /* Addend and symbol difference */
+#define R_IA64_LTOFF22X 0x86 /* LTOFF22, relaxable. */
+#define R_IA64_LDXMOV 0x87 /* Use of LTOFF22X. */
+#define R_IA64_TPREL14 0x91 /* @tprel(sym + add), imm14 */
+#define R_IA64_TPREL22 0x92 /* @tprel(sym + add), imm22 */
+#define R_IA64_TPREL64I 0x93 /* @tprel(sym + add), imm64 */
+#define R_IA64_TPREL64MSB 0x96 /* @tprel(sym + add), data8 MSB */
+#define R_IA64_TPREL64LSB 0x97 /* @tprel(sym + add), data8 LSB */
+#define R_IA64_LTOFF_TPREL22 0x9a /* @ltoff(@tprel(s+a)), imm2 */
+#define R_IA64_DTPMOD64MSB 0xa6 /* @dtpmod(sym + add), data8 MSB */
+#define R_IA64_DTPMOD64LSB 0xa7 /* @dtpmod(sym + add), data8 LSB */
+#define R_IA64_LTOFF_DTPMOD22 0xaa /* @ltoff(@dtpmod(sym + add)), imm22 */
+#define R_IA64_DTPREL14 0xb1 /* @dtprel(sym + add), imm14 */
+#define R_IA64_DTPREL22 0xb2 /* @dtprel(sym + add), imm22 */
+#define R_IA64_DTPREL64I 0xb3 /* @dtprel(sym + add), imm64 */
+#define R_IA64_DTPREL32MSB 0xb4 /* @dtprel(sym + add), data4 MSB */
+#define R_IA64_DTPREL32LSB 0xb5 /* @dtprel(sym + add), data4 LSB */
+#define R_IA64_DTPREL64MSB 0xb6 /* @dtprel(sym + add), data8 MSB */
+#define R_IA64_DTPREL64LSB 0xb7 /* @dtprel(sym + add), data8 LSB */
+#define R_IA64_LTOFF_DTPREL22 0xba /* @ltoff(@dtprel(s+a)), imm22 */
+
+/* SH specific declarations */
+
+/* SH relocs. */
+#define R_SH_NONE 0
+#define R_SH_DIR32 1
+#define R_SH_REL32 2
+#define R_SH_DIR8WPN 3
+#define R_SH_IND12W 4
+#define R_SH_DIR8WPL 5
+#define R_SH_DIR8WPZ 6
+#define R_SH_DIR8BP 7
+#define R_SH_DIR8W 8
+#define R_SH_DIR8L 9
+#define R_SH_SWITCH16 25
+#define R_SH_SWITCH32 26
+#define R_SH_USES 27
+#define R_SH_COUNT 28
+#define R_SH_ALIGN 29
+#define R_SH_CODE 30
+#define R_SH_DATA 31
+#define R_SH_LABEL 32
+#define R_SH_SWITCH8 33
+#define R_SH_GNU_VTINHERIT 34
+#define R_SH_GNU_VTENTRY 35
+#define R_SH_TLS_GD_32 144
+#define R_SH_TLS_LD_32 145
+#define R_SH_TLS_LDO_32 146
+#define R_SH_TLS_IE_32 147
+#define R_SH_TLS_LE_32 148
+#define R_SH_TLS_DTPMOD32 149
+#define R_SH_TLS_DTPOFF32 150
+#define R_SH_TLS_TPOFF32 151
+#define R_SH_GOT32 160
+#define R_SH_PLT32 161
+#define R_SH_COPY 162
+#define R_SH_GLOB_DAT 163
+#define R_SH_JMP_SLOT 164
+#define R_SH_RELATIVE 165
+#define R_SH_GOTOFF 166
+#define R_SH_GOTPC 167
+/* Keep this the last entry. */
+#define R_SH_NUM 256
+
+/* Additional s390 relocs */
+
+#define R_390_NONE 0 /* No reloc. */
+#define R_390_8 1 /* Direct 8 bit. */
+#define R_390_12 2 /* Direct 12 bit. */
+#define R_390_16 3 /* Direct 16 bit. */
+#define R_390_32 4 /* Direct 32 bit. */
+#define R_390_PC32 5 /* PC relative 32 bit. */
+#define R_390_GOT12 6 /* 12 bit GOT offset. */
+#define R_390_GOT32 7 /* 32 bit GOT offset. */
+#define R_390_PLT32 8 /* 32 bit PC relative PLT address. */
+#define R_390_COPY 9 /* Copy symbol at runtime. */
+#define R_390_GLOB_DAT 10 /* Create GOT entry. */
+#define R_390_JMP_SLOT 11 /* Create PLT entry. */
+#define R_390_RELATIVE 12 /* Adjust by program base. */
+#define R_390_GOTOFF32 13 /* 32 bit offset to GOT. */
+#define R_390_GOTPC 14 /* 32 bit PC relative offset to GOT. */
+#define R_390_GOT16 15 /* 16 bit GOT offset. */
+#define R_390_PC16 16 /* PC relative 16 bit. */
+#define R_390_PC16DBL 17 /* PC relative 16 bit shifted by 1. */
+#define R_390_PLT16DBL 18 /* 16 bit PC rel. PLT shifted by 1. */
+#define R_390_PC32DBL 19 /* PC relative 32 bit shifted by 1. */
+#define R_390_PLT32DBL 20 /* 32 bit PC rel. PLT shifted by 1. */
+#define R_390_GOTPCDBL 21 /* 32 bit PC rel. GOT shifted by 1. */
+#define R_390_64 22 /* Direct 64 bit. */
+#define R_390_PC64 23 /* PC relative 64 bit. */
+#define R_390_GOT64 24 /* 64 bit GOT offset. */
+#define R_390_PLT64 25 /* 64 bit PC relative PLT address. */
+#define R_390_GOTENT 26 /* 32 bit PC rel. to GOT entry >> 1. */
+#define R_390_GOTOFF16 27 /* 16 bit offset to GOT. */
+#define R_390_GOTOFF64 28 /* 64 bit offset to GOT. */
+#define R_390_GOTPLT12 29 /* 12 bit offset to jump slot. */
+#define R_390_GOTPLT16 30 /* 16 bit offset to jump slot. */
+#define R_390_GOTPLT32 31 /* 32 bit offset to jump slot. */
+#define R_390_GOTPLT64 32 /* 64 bit offset to jump slot. */
+#define R_390_GOTPLTENT 33 /* 32 bit rel. offset to jump slot. */
+#define R_390_PLTOFF16 34 /* 16 bit offset from GOT to PLT. */
+#define R_390_PLTOFF32 35 /* 32 bit offset from GOT to PLT. */
+#define R_390_PLTOFF64 36 /* 16 bit offset from GOT to PLT. */
+#define R_390_TLS_LOAD 37 /* Tag for load insn in TLS code. */
+#define R_390_TLS_GDCALL \
+ 38 /* Tag for function call in general \
+dynamic TLS code. */
+#define R_390_TLS_LDCALL \
+ 39 /* Tag for function call in local \
+dynamic TLS code. */
+#define R_390_TLS_GD32 \
+ 40 /* Direct 32 bit for general dynamic \
+thread local data. */
+#define R_390_TLS_GD64 \
+ 41 /* Direct 64 bit for general dynamic \
+thread local data. */
+#define R_390_TLS_GOTIE12 \
+ 42 /* 12 bit GOT offset for static TLS \
+block offset. */
+#define R_390_TLS_GOTIE32 \
+ 43 /* 32 bit GOT offset for static TLS \
+block offset. */
+#define R_390_TLS_GOTIE64 \
+ 44 /* 64 bit GOT offset for static TLS \
+block offset. */
+#define R_390_TLS_LDM32 \
+ 45 /* Direct 32 bit for local dynamic \
+thread local data in LE code. */
+#define R_390_TLS_LDM64 \
+ 46 /* Direct 64 bit for local dynamic \
+thread local data in LE code. */
+#define R_390_TLS_IE32 \
+ 47 /* 32 bit address of GOT entry for \
+negated static TLS block offset. */
+#define R_390_TLS_IE64 \
+ 48 /* 64 bit address of GOT entry for \
+negated static TLS block offset. */
+#define R_390_TLS_IEENT \
+ 49 /* 32 bit rel. offset to GOT entry for \
+negated static TLS block offset. */
+#define R_390_TLS_LE32 \
+ 50 /* 32 bit negated offset relative to \
+static TLS block. */
+#define R_390_TLS_LE64 \
+ 51 /* 64 bit negated offset relative to \
+static TLS block. */
+#define R_390_TLS_LDO32 \
+ 52 /* 32 bit offset relative to TLS \
+block. */
+#define R_390_TLS_LDO64 \
+ 53 /* 64 bit offset relative to TLS \
+block. */
+#define R_390_TLS_DTPMOD 54 /* ID of module containing symbol. */
+#define R_390_TLS_DTPOFF 55 /* Offset in TLS block. */
+#define R_390_TLS_TPOFF \
+ 56 /* Negated offset in static TLS \
+block. */
+#define R_390_20 57 /* Direct 20 bit. */
+#define R_390_GOT20 58 /* 20 bit GOT offset. */
+#define R_390_GOTPLT20 59 /* 20 bit offset to jump slot. */
+#define R_390_TLS_GOTIE20 \
+ 60 /* 20 bit GOT offset for static TLS \
+block offset. */
+/* Keep this the last entry. */
+#define R_390_NUM 61
+
+/* CRIS relocations. */
+#define R_CRIS_NONE 0
+#define R_CRIS_8 1
+#define R_CRIS_16 2
+#define R_CRIS_32 3
+#define R_CRIS_8_PCREL 4
+#define R_CRIS_16_PCREL 5
+#define R_CRIS_32_PCREL 6
+#define R_CRIS_GNU_VTINHERIT 7
+#define R_CRIS_GNU_VTENTRY 8
+#define R_CRIS_COPY 9
+#define R_CRIS_GLOB_DAT 10
+#define R_CRIS_JUMP_SLOT 11
+#define R_CRIS_RELATIVE 12
+#define R_CRIS_16_GOT 13
+#define R_CRIS_32_GOT 14
+#define R_CRIS_16_GOTPLT 15
+#define R_CRIS_32_GOTPLT 16
+#define R_CRIS_32_GOTREL 17
+#define R_CRIS_32_PLT_GOTREL 18
+#define R_CRIS_32_PLT_PCREL 19
+
+#define R_CRIS_NUM 20
+
+/* AMD x86-64 relocations. */
+#define R_X86_64_NONE 0 /* No reloc */
+#define R_X86_64_64 1 /* Direct 64 bit */
+#define R_X86_64_PC32 2 /* PC relative 32 bit signed */
+#define R_X86_64_GOT32 3 /* 32 bit GOT entry */
+#define R_X86_64_PLT32 4 /* 32 bit PLT address */
+#define R_X86_64_COPY 5 /* Copy symbol at runtime */
+#define R_X86_64_GLOB_DAT 6 /* Create GOT entry */
+#define R_X86_64_JUMP_SLOT 7 /* Create PLT entry */
+#define R_X86_64_RELATIVE 8 /* Adjust by program base */
+#define R_X86_64_GOTPCREL \
+ 9 /* 32 bit signed PC relative \
+offset to GOT */
+#define R_X86_64_32 10 /* Direct 32 bit zero extended */
+#define R_X86_64_32S 11 /* Direct 32 bit sign extended */
+#define R_X86_64_16 12 /* Direct 16 bit zero extended */
+#define R_X86_64_PC16 13 /* 16 bit sign extended pc relative */
+#define R_X86_64_8 14 /* Direct 8 bit sign extended */
+#define R_X86_64_PC8 15 /* 8 bit sign extended pc relative */
+#define R_X86_64_DTPMOD64 16 /* ID of module containing symbol */
+#define R_X86_64_DTPOFF64 17 /* Offset in module's TLS block */
+#define R_X86_64_TPOFF64 18 /* Offset in initial TLS block */
+#define R_X86_64_TLSGD \
+ 19 /* 32 bit signed PC relative offset \
+to two GOT entries for GD symbol */
+#define R_X86_64_TLSLD \
+ 20 /* 32 bit signed PC relative offset \
+to two GOT entries for LD symbol */
+#define R_X86_64_DTPOFF32 21 /* Offset in TLS block */
+#define R_X86_64_GOTTPOFF \
+ 22 /* 32 bit signed PC relative offset \
+to GOT entry for IE symbol */
+#define R_X86_64_TPOFF32 23 /* Offset in initial TLS block */
+
+#define R_X86_64_NUM 24
+
+/* AM33 relocations. */
+#define R_MN10300_NONE 0 /* No reloc. */
+#define R_MN10300_32 1 /* Direct 32 bit. */
+#define R_MN10300_16 2 /* Direct 16 bit. */
+#define R_MN10300_8 3 /* Direct 8 bit. */
+#define R_MN10300_PCREL32 4 /* PC-relative 32-bit. */
+#define R_MN10300_PCREL16 5 /* PC-relative 16-bit signed. */
+#define R_MN10300_PCREL8 6 /* PC-relative 8-bit signed. */
+#define R_MN10300_GNU_VTINHERIT 7 /* Ancient C++ vtable garbage... */
+#define R_MN10300_GNU_VTENTRY 8 /* ... collection annotation. */
+#define R_MN10300_24 9 /* Direct 24 bit. */
+#define R_MN10300_GOTPC32 10 /* 32-bit PCrel offset to GOT. */
+#define R_MN10300_GOTPC16 11 /* 16-bit PCrel offset to GOT. */
+#define R_MN10300_GOTOFF32 12 /* 32-bit offset from GOT. */
+#define R_MN10300_GOTOFF24 13 /* 24-bit offset from GOT. */
+#define R_MN10300_GOTOFF16 14 /* 16-bit offset from GOT. */
+#define R_MN10300_PLT32 15 /* 32-bit PCrel to PLT entry. */
+#define R_MN10300_PLT16 16 /* 16-bit PCrel to PLT entry. */
+#define R_MN10300_GOT32 17 /* 32-bit offset to GOT entry. */
+#define R_MN10300_GOT24 18 /* 24-bit offset to GOT entry. */
+#define R_MN10300_GOT16 19 /* 16-bit offset to GOT entry. */
+#define R_MN10300_COPY 20 /* Copy symbol at runtime. */
+#define R_MN10300_GLOB_DAT 21 /* Create GOT entry. */
+#define R_MN10300_JMP_SLOT 22 /* Create PLT entry. */
+#define R_MN10300_RELATIVE 23 /* Adjust by program base. */
+
+#define R_MN10300_NUM 24
+
+/* M32R relocs. */
+#define R_M32R_NONE 0 /* No reloc. */
+#define R_M32R_16 1 /* Direct 16 bit. */
+#define R_M32R_32 2 /* Direct 32 bit. */
+#define R_M32R_24 3 /* Direct 24 bit. */
+#define R_M32R_10_PCREL 4 /* PC relative 10 bit shifted. */
+#define R_M32R_18_PCREL 5 /* PC relative 18 bit shifted. */
+#define R_M32R_26_PCREL 6 /* PC relative 26 bit shifted. */
+#define R_M32R_HI16_ULO 7 /* High 16 bit with unsigned low. */
+#define R_M32R_HI16_SLO 8 /* High 16 bit with signed low. */
+#define R_M32R_LO16 9 /* Low 16 bit. */
+#define R_M32R_SDA16 10 /* 16 bit offset in SDA. */
+#define R_M32R_GNU_VTINHERIT 11
+#define R_M32R_GNU_VTENTRY 12
+/* M32R relocs use SHT_RELA. */
+#define R_M32R_16_RELA 33 /* Direct 16 bit. */
+#define R_M32R_32_RELA 34 /* Direct 32 bit. */
+#define R_M32R_24_RELA 35 /* Direct 24 bit. */
+#define R_M32R_10_PCREL_RELA 36 /* PC relative 10 bit shifted. */
+#define R_M32R_18_PCREL_RELA 37 /* PC relative 18 bit shifted. */
+#define R_M32R_26_PCREL_RELA 38 /* PC relative 26 bit shifted. */
+#define R_M32R_HI16_ULO_RELA 39 /* High 16 bit with unsigned low */
+#define R_M32R_HI16_SLO_RELA 40 /* High 16 bit with signed low */
+#define R_M32R_LO16_RELA 41 /* Low 16 bit */
+#define R_M32R_SDA16_RELA 42 /* 16 bit offset in SDA */
+#define R_M32R_RELA_GNU_VTINHERIT 43
+#define R_M32R_RELA_GNU_VTENTRY 44
+
+#define R_M32R_GOT24 48 /* 24 bit GOT entry */
+#define R_M32R_26_PLTREL 49 /* 26 bit PC relative to PLT shifted */
+#define R_M32R_COPY 50 /* Copy symbol at runtime */
+#define R_M32R_GLOB_DAT 51 /* Create GOT entry */
+#define R_M32R_JMP_SLOT 52 /* Create PLT entry */
+#define R_M32R_RELATIVE 53 /* Adjust by program base */
+#define R_M32R_GOTOFF 54 /* 24 bit offset to GOT */
+#define R_M32R_GOTPC24 55 /* 24 bit PC relative offset to GOT */
+#define R_M32R_GOT16_HI_ULO \
+ 56 /* High 16 bit GOT entry with unsigned \
+low */
+#define R_M32R_GOT16_HI_SLO \
+ 57 /* High 16 bit GOT entry with signed \
+ low */
+#define R_M32R_GOT16_LO 58 /* Low 16 bit GOT entry */
+#define R_M32R_GOTPC_HI_ULO \
+ 59 /* High 16 bit PC relative offset to \
+GOT with unsigned low */
+#define R_M32R_GOTPC_HI_SLO \
+ 60 /* High 16 bit PC relative offset to \
+GOT with signed low */
+#define R_M32R_GOTPC_LO \
+ 61 /* Low 16 bit PC relative offset to \
+GOT */
+#define R_M32R_GOTOFF_HI_ULO \
+ 62 /* High 16 bit offset to GOT \
+with unsigned low */
+#define R_M32R_GOTOFF_HI_SLO \
+ 63 /* High 16 bit offset to GOT \
+ with signed low */
+#define R_M32R_GOTOFF_LO 64 /* Low 16 bit offset to GOT */
+#define R_M32R_NUM 256 /* Keep this the last entry. */
+
+/* __END_DECLS */
diff --git a/user/lib/ld-weenix/ldalloc.c b/user/lib/ld-weenix/ldalloc.c
new file mode 100644
index 0000000..c5e79e7
--- /dev/null
+++ b/user/lib/ld-weenix/ldalloc.c
@@ -0,0 +1,66 @@
+/*
+ * File: ldalloc.c
+ * Date: 28 March 1998
+ * Acct: David Powell (dep)
+ * Desc: simple allocation routines
+ */
+
+#include "ldalloc.h"
+#include "ldutil.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/mman.h>
+#include <unistd.h>
+
+static unsigned long start;
+static unsigned long pos;
+static unsigned long amount;
+
+/* This function initializes the simple memory allocator. We basically
+ * allocate a specified number of pages to use as scratch memory for
+ * the linker itself. No deallocation functionality is provided; the
+ * amount of memory used should be small, and is usually needed for the
+ * duration of the program's execution, anyway.
+ *
+ * All this function does is mmap the specified number of pages of
+ * /dev/zero to provide the memory for our little memory-wading-pool. */
+
+void _ldainit(unsigned long pagesize, unsigned long pages)
+{
+ amount = pagesize * pages;
+ pos = 0;
+
+ start = (unsigned long)mmap(NULL, amount, PROT_READ | PROT_WRITE,
+ MAP_PRIVATE | MAP_ANON, -1, 0);
+ if (start == (unsigned long)MAP_FAILED)
+ {
+ fprintf(stderr, "ld-weenix: panic - unable to map /dev/zero\n");
+ exit(1);
+ }
+}
+
+/* This function allocates a block of memory of the specified size from
+ * our memory pool. The memory is word-aligned, and cannot be freed. */
+
+void *_ldalloc(unsigned long size)
+{
+ unsigned long next;
+
+ if (size & 3)
+ {
+ size = (size & ~3) + 4;
+ }
+
+ if (pos + size > amount)
+ {
+ fprintf(stderr,
+ "ld.so.1: panic - unable to allocate %lu bytes (_ldalloc)\n",
+ size);
+ exit(1);
+ }
+
+ next = start + pos;
+ pos += size;
+
+ return (void *)next;
+}
diff --git a/user/lib/ld-weenix/ldalloc.h b/user/lib/ld-weenix/ldalloc.h
new file mode 100644
index 0000000..40e54d4
--- /dev/null
+++ b/user/lib/ld-weenix/ldalloc.h
@@ -0,0 +1,4 @@
+#pragma once
+
+void _ldainit(unsigned long pagesize, unsigned long pages);
+void *_ldalloc(unsigned long size);
diff --git a/user/lib/ld-weenix/ldnames.c b/user/lib/ld-weenix/ldnames.c
new file mode 100644
index 0000000..b94486b
--- /dev/null
+++ b/user/lib/ld-weenix/ldnames.c
@@ -0,0 +1,63 @@
+/*
+ * File: ldnames.c
+ * Date: 30 March 1998
+ * Acct: David Powell (dep)
+ * Desc:
+ */
+
+#include "sys/types.h"
+
+#include "stdlib.h"
+#include "string.h"
+
+#include "ldalloc.h"
+#include "ldnames.h"
+
+typedef struct modent modent_t;
+struct modent
+{
+ const char *name;
+ modent_t *next;
+};
+
+static modent_t *names = NULL;
+
+/* This function adds a name to the global name list. This is intended
+ * for keeping track of what libraries have already been loaded so that
+ * circular/multiple dependencies don't result in a collosal mess.
+ *
+ * _ldaddname has the caveat that names passed must stick around; this
+ * works fine for names located in the dynstr section and are
+ * referenced in the dynamic section */
+
+void _ldaddname(const char *name)
+{
+ modent_t *newent;
+
+ newent = (modent_t *)_ldalloc(sizeof(*newent));
+ newent->name = name;
+ newent->next = names;
+ names = newent;
+}
+
+/* This function checks to see if the specified name has already been
+ * added to the name list (via _ldaddname). If so, 1 is returned.
+ * Otherwise, 0 is returned. */
+
+int _ldchkname(const char *name)
+{
+ /* Just does a linear search - nothing fancy here */
+
+ modent_t *curent;
+
+ curent = names;
+ while (curent)
+ {
+ if (strcmp(curent->name, name))
+ curent = curent->next;
+ else
+ return 1;
+ }
+
+ return 0;
+}
diff --git a/user/lib/ld-weenix/ldnames.h b/user/lib/ld-weenix/ldnames.h
new file mode 100644
index 0000000..6ddec73
--- /dev/null
+++ b/user/lib/ld-weenix/ldnames.h
@@ -0,0 +1,23 @@
+/*
+ * File: ldnames.h
+ * Date: 30 March 1998
+ * Acct: David Powell (dep)
+ * Desc:
+ */
+
+#ifndef _ldnames_h_
+#define _ldnames_h_
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+ void _ldaddname(const char *name);
+ int _ldchkname(const char *name);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _ldnames_h_ */
diff --git a/user/lib/ld-weenix/ldreloc_x86_64.c b/user/lib/ld-weenix/ldreloc_x86_64.c
new file mode 100644
index 0000000..dddd418
--- /dev/null
+++ b/user/lib/ld-weenix/ldreloc_x86_64.c
@@ -0,0 +1,184 @@
+/*
+ * File: ldreloc_x86_64.c
+ * Date: Mar 26 2019
+ * Acct: Sandy Harvie (charvie)
+ * Desc: x86-64 ELF dynamic linker
+ */
+
+#include "stdio.h"
+#include "stdlib.h"
+#include "string.h"
+#include "sys/types.h"
+
+#include "ldresolve.h"
+#include "ldtypes.h"
+#include "ldutil.h"
+
+extern void _ld_bind(void);
+
+ldinit_t _ldloadrtld(int argc, char **argv, char **envp, Elf64_auxv_t *auxv)
+{
+ /* Find our own base address in the auxiliary vector */
+ Elf64_Addr base = 0;
+ for (size_t i = 0; auxv[i].a_type != AT_NULL; i++)
+ {
+ if (auxv[i].a_type == AT_BASE)
+ {
+ base = (Elf64_Addr)auxv[i].a_un.a_val;
+ break;
+ }
+ }
+ if (!base)
+ exit(1);
+
+ /* Make sure we are ourselves */
+ Elf64_Ehdr *hdr = (Elf64_Ehdr *)base;
+ if (hdr->e_ident[EI_MAG0] != ELFMAG0 || hdr->e_ident[EI_MAG1] != ELFMAG1 ||
+ hdr->e_ident[EI_MAG2] != ELFMAG2 || hdr->e_ident[EI_MAG3] != ELFMAG3)
+ {
+ exit(1);
+ }
+
+ /* Find our program header */
+ Elf64_Phdr *phdr = (Elf64_Phdr *)(base + hdr->e_phoff);
+
+ /* Find our dynamic segment */
+ while (phdr->p_type != PT_DYNAMIC)
+ {
+ phdr++;
+ }
+
+ /* Find relocation entries in the dynamic segment */
+ size_t d_reloff = 0;
+ size_t d_relcount = 0;
+ Elf64_Dyn *dyn = (Elf64_Dyn *)(base + phdr->p_vaddr);
+ for (; dyn->d_tag != DT_NULL; dyn++)
+ {
+ if (dyn->d_tag == DT_RELA)
+ {
+ d_reloff = dyn->d_un.d_ptr;
+ }
+ else if (dyn->d_tag == DT_RELACOUNT)
+ {
+ d_relcount = dyn->d_un.d_val;
+ }
+ }
+
+ /* Relocate ourselves */
+ Elf64_Rela *rel = (Elf64_Rela *)(base + d_reloff);
+ for (size_t i = 0; i < d_relcount; i++)
+ {
+ size_t type = ELF64_R_TYPE(rel[i].r_info);
+ if (type == R_X86_64_RELATIVE)
+ {
+ Elf64_Addr *addr = (Elf64_Addr *)(base + rel[i].r_offset);
+ *addr = base + rel[i].r_addend;
+ }
+ else
+ {
+ fprintf(stderr, "_ldloadrtld: unsupported relocation type: %lu\n",
+ type);
+ exit(1);
+ }
+ }
+
+ /* Relocate the executable */
+ return _ldstart(envp, auxv);
+}
+
+void _ldrelocobj(module_t *module)
+{
+ Elf64_Addr base = module->base;
+
+ for (size_t i = 0; i < module->nreloc; i++)
+ {
+ Elf64_Rela rel = module->reloc[i];
+
+ uint64_t sym = ELF64_R_SYM(rel.r_info);
+ uint64_t type = ELF64_R_TYPE(rel.r_info);
+ const char *name = module->dynstr + module->dynsym[sym].st_name;
+ void *addr = (void *)(base + rel.r_offset);
+
+ Elf64_Word size;
+ ldsym_t symbol;
+ switch (type)
+ {
+ case R_X86_64_RELATIVE:
+ *(Elf64_Addr *)addr = base + rel.r_addend;
+ break;
+ case R_X86_64_COPY:
+ symbol = _ldresolve(module, name, -1, &size, 1);
+ memcpy(addr, symbol, size);
+ break;
+ case R_X86_64_JUMP_SLOT:
+ case R_X86_64_GLOB_DAT:
+ symbol = _ldresolve(module, name, -1, 0, 0);
+ *(Elf64_Addr *)addr = (Elf64_Addr)symbol;
+ break;
+ case R_X86_64_32:
+ symbol = _ldresolve(module, name, -1, 0, 0);
+ *(Elf64_Addr *)addr = (Elf64_Addr)symbol + rel.r_addend;
+ break;
+ case R_X86_64_PC32:
+ symbol = _ldresolve(module, name, -1, 0, 0);
+ *(Elf64_Addr *)addr =
+ (Elf64_Addr)symbol + rel.r_addend - (Elf64_Addr)addr;
+ break;
+ default:
+ fprintf(stderr,
+ "_ldrelocobj: unsupported relocation type: %lu\n",
+ type);
+ exit(1);
+ }
+ }
+}
+
+void _ldrelocplt(module_t *module)
+{
+ for (size_t i = 0; i < module->npltreloc; i++)
+ {
+ Elf64_Rela rel = module->pltreloc[i];
+
+ uint64_t type = ELF64_R_TYPE(rel.r_info);
+ if (type != R_X86_64_JUMP_SLOT)
+ {
+ fprintf(stderr, "_ldrelocplt: unsupported relocation type: %lu\n",
+ type);
+ exit(1);
+ }
+
+ *(Elf64_Addr *)(module->base + rel.r_offset) += module->base;
+ }
+}
+
+void _ldpltgot_init(module_t *module)
+{
+ Elf64_Addr *pltbase = module->pltgot;
+ pltbase[1] = (Elf64_Addr)module;
+ pltbase[2] = (Elf64_Addr)&_ld_bind;
+}
+
+void _ldbindnow(module_t *module)
+{
+ Elf64_Addr base = module->base;
+
+ for (size_t i = 0; i < module->npltreloc; i++)
+ {
+ Elf64_Rela rel = module->pltreloc[i];
+
+ uint64_t sym = ELF64_R_SYM(rel.r_info);
+ uint64_t type = ELF64_R_TYPE(rel.r_info);
+ const char *name = module->dynstr + module->dynsym[sym].st_name;
+ void *addr = (void *)(base + rel.r_offset);
+
+ if (type != R_X86_64_JUMP_SLOT)
+ {
+ fprintf(stderr, "_ldbindnow: unsupported relocation type: %lu\n",
+ type);
+ exit(1);
+ }
+
+ ldsym_t symbol = _ldresolve(module, name, -1, 0, 0);
+ *(Elf64_Addr *)addr = (Elf64_Addr)symbol;
+ }
+}
diff --git a/user/lib/ld-weenix/ldresolve.c b/user/lib/ld-weenix/ldresolve.c
new file mode 100644
index 0000000..db1da80
--- /dev/null
+++ b/user/lib/ld-weenix/ldresolve.c
@@ -0,0 +1,119 @@
+/*
+ * File: ldresolve.c
+ * Date: 12 April 1998
+ * Acct: David Powell (dep)
+ * Desc: Various symbol resolution functions
+ *
+ *
+ * Acct: Sandy Harvie (charvie)
+ * Date: 27 March 2019
+ * Desc: Modified for x86-64
+ */
+
+#include "string.h"
+
+#include "ldresolve.h"
+#include "ldutil.h"
+
+#define H_nbucket 0
+#define H_nchain 1
+#define H_bucket 2
+
+/* This function looks up the specified symbol in the specified
+ * module. If the symbol is present, it returns the symbol's index in
+ * the dynamic symbol table, otherwise STN_UNDEF is returned. */
+
+int _ldlookup(module_t *module, const char *name)
+{
+ unsigned long hashval;
+ unsigned long y;
+
+ hashval = _ldelfhash(name);
+ hashval %= module->hash[H_nbucket];
+
+ y = module->hash[H_bucket + hashval];
+
+ while ((y != STN_UNDEF) &&
+ strcmp(module->dynstr + module->dynsym[y].st_name, name))
+ {
+ y = module->hash[H_bucket + module->hash[H_nbucket] + y];
+ }
+
+ return y;
+}
+
+/* This looks up the specified symbol in the given module, subject to
+ * the provided binding and type restrictions (a value of -1 will
+ * function as a wildcard for both the 'binding' and 'type'
+ * parameters). The symbol's size will be placed in the memory
+ * location pointed to by 'size', if it is non-null. 0 is returned if
+ * a symbol matching all the requirements is not found. */
+
+ldsym_t _ldsymbol(module_t *module, const char *name, int binding, int type,
+ Elf64_Word *size)
+{
+ int result;
+
+ /* LINTED */
+ if (((result = _ldlookup(module, name)) != STN_UNDEF) &&
+ ((binding < 0) ||
+ (ELF64_ST_BIND(module->dynsym[result].st_info) == binding)) &&
+ ((type < 0) ||
+ (ELF64_ST_TYPE(module->dynsym[result].st_info) == type)) &&
+ (module->dynsym[result].st_shndx != SHN_UNDEF))
+ {
+ if (size)
+ *size = module->dynsym[result].st_size;
+ return (ldsym_t)((uintptr_t)module->base +
+ (uintptr_t)module->dynsym[result].st_value);
+ }
+
+ return 0;
+}
+
+/* Given a module and a symbol name, this function attempts to find the
+ * symbol through the process' link chain. It first checks for its
+ * presence as a global symbol, then as a weak symbol, and finally as a
+ * local symbol in the specified module. A type restriction can be
+ * specified, and if 'size' is non-null, the memory location to which
+ * it points will hold the size of the resolved symbol. 0 is returned
+ * if the symbol cannot be found. */
+
+ldsym_t _ldresolve(module_t *module, const char *name, int type,
+ Elf64_Word *size, int exclude)
+{
+ module_t *curmod;
+ ldsym_t sym;
+
+ curmod = module->first;
+
+ while (curmod)
+ {
+ if (!exclude || curmod != module)
+ {
+ if ((sym = _ldsymbol(curmod, name, STB_GLOBAL, type, size)))
+ return sym;
+ }
+ curmod = curmod->next;
+ }
+
+ curmod = module->first;
+ while (curmod)
+ {
+ if ((sym = _ldsymbol(curmod, name, STB_WEAK, type, size)))
+ return sym;
+ curmod = curmod->next;
+ }
+
+ return _ldsymbol(module, name, STB_LOCAL, type, size);
+}
+
+Elf64_Addr _rtresolve(module_t *mod, Elf64_Word reloff)
+{
+ Elf64_Rela *rel = mod->pltreloc + reloff;
+ int sym = ELF64_R_SYM(rel->r_info);
+ const char *name = mod->dynstr + mod->dynsym[sym].st_name;
+ ldsym_t symbol = _ldresolve(mod, name, -1, 0, 0);
+ *(Elf64_Addr *)(mod->base + rel->r_offset) = (Elf64_Addr)symbol;
+ return (Elf64_Addr)symbol;
+}
diff --git a/user/lib/ld-weenix/ldresolve.h b/user/lib/ld-weenix/ldresolve.h
new file mode 100644
index 0000000..d86543b
--- /dev/null
+++ b/user/lib/ld-weenix/ldresolve.h
@@ -0,0 +1,35 @@
+/*
+ * File: ldresolve.h
+ * Date: 12 April 1998
+ * Acct: David Powell (dep)
+ * Desc: Various symbol resolution functions
+ *
+ *
+ * Acct: Sandy Harvie (charvie)
+ * Date: 27 March 2019
+ * Desc: Modified for x86-64
+ */
+
+#ifndef _ldresolve_h_
+#define _ldresolve_h_
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#include "ldtypes.h"
+
+ int _ldlookup(module_t *module, const char *name);
+ ldsym_t _ldsymbol(module_t *module, const char *name, int binding, int type,
+ Elf64_Word *size);
+ ldsym_t _ldresolve(module_t *module, const char *name, int type,
+ Elf64_Word *size, int copy);
+ ldsym_t _ldexresolve(module_t *module, const char *name, int type,
+ Elf64_Word *size);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _ldresolve_h_ */
diff --git a/user/lib/ld-weenix/ldstart.c b/user/lib/ld-weenix/ldstart.c
new file mode 100644
index 0000000..85fe4ec
--- /dev/null
+++ b/user/lib/ld-weenix/ldstart.c
@@ -0,0 +1,573 @@
+/*
+ * File: ldstart.c
+ * Date: 14 March 1998
+ * Acct: David Powell (dep)
+ * Desc: A run time linker
+ *
+ *
+ * Acct: Rob Manchester (rmanches)
+ * Desc: Added x86 Elf Compatability
+ *
+ *
+ * Acct: Sandy Harvie (charvie)
+ * Date: 27 March 2019
+ * Desc: Modified for x86-64
+ */
+
+#include "fcntl.h"
+#include "stdio.h"
+#include "stdlib.h"
+#include "string.h"
+#include "sys/mman.h"
+#include "sys/types.h"
+#include "unistd.h"
+
+#include "elf.h"
+
+#include "ldalloc.h"
+#include "ldnames.h"
+#include "ldutil.h"
+
+#ifndef DEFAULT_RUNPATH
+#define DEFAULT_RUNPATH "/lib:/usr/lib"
+#endif
+
+extern int _ldbindnow(module_t *curmod);
+
+static const char *default_runpath = DEFAULT_RUNPATH;
+
+static const char *err_cantfind =
+ "ld.so.1: panic - unable to find library \"%s\"\n";
+static const char *err_noentry = "ld.so.1: panic - no entry point\n";
+static const char *err_mapping =
+ "ld.so.1: panic - failure to map section of length 0x%x at 0x%x\n";
+static const char *err_zeromap = "ld.so.1: panic - failure to map /dev/zero\n";
+
+static module_t *_ldfirst;
+static module_t **_ldlast;
+
+static size_t pagesize;
+static char **env;
+ldenv_t _ldenv;
+
+#define trunc_page(x) ((x) & ~(pagesize - 1))
+#define round_page(x) (((x) + pagesize - 1) & ~(pagesize - 1))
+
+static const char *_ldgetenv(const char *var)
+{
+ char **e = env;
+ while (*e)
+ {
+ const char *p = *e;
+ while (*p == *var)
+ p++, var++;
+ if (*p == '=' && *var == 0)
+ {
+ return p++;
+ }
+ e++;
+ }
+ return 0;
+}
+
+static void _ldenv_init(char **environ)
+{
+ env = environ;
+ if (_ldgetenv("LD_BIND_NOW"))
+ {
+ _ldenv.ld_bind_now = 1;
+ }
+ if (_ldgetenv("LD_DEBUG"))
+ {
+ _ldenv.ld_debug = 1;
+ }
+ _ldenv.ld_preload = _ldgetenv("LD_PRELOAD");
+ _ldenv.ld_library_path = _ldgetenv("LD_LIBRARY_PATH");
+}
+
+static module_t *_ldlinkobj(module_t *info, const char *baseaddr,
+ Elf64_Dyn *dyn)
+{
+ Elf64_Dyn *curdyn;
+ module_t **curmod;
+ char *name;
+
+ /* uint64_t d_needed = 0; */
+ uint64_t d_rpath = 0;
+ uint64_t d_relocsz = 0;
+ uint64_t d_relocent = 0;
+
+ uint64_t d_plttype = 0;
+ uint64_t d_pltsize = 0;
+
+ /* create an info structure if we weren't passed one */
+ if (!info)
+ {
+ info = (module_t *)_ldalloc(sizeof(*info));
+ memset(info, 0, sizeof(*info));
+ _ldfirst = info->first = info;
+ curmod = &(info->next);
+ }
+ else
+ {
+ curmod = _ldlast;
+ }
+
+ info->base = (unsigned long)baseaddr;
+
+ for (curdyn = dyn; curdyn->d_tag != DT_NULL; curdyn++)
+ {
+ switch (curdyn->d_tag)
+ {
+ case DT_HASH:
+ info->hash = (void *)(info->base + curdyn->d_un.d_ptr);
+ break;
+ case DT_SYMTAB:
+ info->dynsym = (void *)(info->base + curdyn->d_un.d_ptr);
+ break;
+ case DT_STRTAB:
+ info->dynstr = (char *)(info->base + curdyn->d_un.d_ptr);
+ break;
+ case DT_JMPREL:
+ info->pltreloc = (void *)(info->base + curdyn->d_un.d_ptr);
+ break;
+ case DT_RELA:
+ case DT_REL:
+ info->reloc = (void *)(info->base + curdyn->d_un.d_ptr);
+ break;
+ case DT_INIT:
+ info->init = (ldfunc_t)(info->base + curdyn->d_un.d_ptr);
+ break;
+ case DT_FINI:
+ info->fini = (ldfunc_t)(info->base + curdyn->d_un.d_ptr);
+ break;
+ case DT_NEEDED:
+ /* d_needed = curdyn->d_un.d_val; */
+ break;
+ case DT_RPATH:
+ d_rpath = curdyn->d_un.d_val;
+ break;
+ case DT_PLTGOT:
+ info->pltgot = (void *)(info->base + curdyn->d_un.d_ptr);
+ break;
+ case DT_PLTRELSZ:
+ d_pltsize = curdyn->d_un.d_val;
+ break;
+ case DT_PLTREL:
+ d_plttype = curdyn->d_un.d_val;
+ break;
+ case DT_BIND_NOW:
+ _ldenv.ld_bind_now = 1;
+ break;
+ case DT_RELENT:
+ case DT_RELAENT:
+ d_relocent = curdyn->d_un.d_val;
+ break;
+ case DT_RELSZ:
+ case DT_RELASZ:
+ d_relocsz = curdyn->d_un.d_val;
+ break;
+ default:
+ break;
+ }
+ }
+
+ if (info->reloc)
+ {
+ info->nreloc = d_relocsz / d_relocent;
+ }
+
+ if (info->pltreloc)
+ {
+ /* bytes per element */
+ size_t bpe =
+ d_plttype == DT_REL ? sizeof(Elf64_Rel) : sizeof(Elf64_Rela);
+ info->npltreloc = d_pltsize / bpe;
+ }
+
+ /* Set up plt */
+ if (info->pltgot)
+ {
+ _ldpltgot_init(info);
+ }
+
+ /* create modules for dependencies */
+ for (curdyn = dyn; curdyn->d_tag != DT_NULL; curdyn++)
+ {
+ if (curdyn->d_tag == DT_NEEDED)
+ {
+ name = info->dynstr + curdyn->d_un.d_val;
+ if (_ldchkname(name))
+ break;
+ _ldaddname(name);
+ *curmod = (module_t *)_ldalloc(sizeof(module_t));
+ (**curmod).name = name;
+ _ldaddname((**curmod).name);
+ if (d_rpath)
+ {
+ (**curmod).runpath = info->dynstr + d_rpath;
+ }
+ else
+ {
+ (**curmod).runpath = NULL;
+ }
+ (**curmod).next = NULL;
+ (**curmod).first = _ldfirst;
+ curmod = &((**curmod).next);
+ }
+ }
+ _ldlast = curmod;
+
+ return info;
+}
+
+/* Given a filename and a colon-delimited path, this function attempts
+ * to open the named file using each element of the path as a prefix
+ * for the file. The result of the first successful open is returned,
+ * otherwise -1 is returned */
+
+int _ldtryopen(const char *filename, const char *path)
+{
+ char buffer[2048]; /* shouldn't be overflown */
+ const char *pos, *oldpos;
+ size_t len, flen;
+ int fd;
+
+ if (!path || !*path)
+ return -1;
+
+ flen = strlen(filename) + 1;
+
+ oldpos = pos = path;
+
+ /* ADDED: try w/ no prefix first */
+ strncpy(buffer, filename, flen);
+ fd = open(buffer, O_RDONLY, 0);
+ if (fd >= 0)
+ {
+ return fd;
+ }
+ /* END ADDED */
+
+ while (*pos)
+ {
+ while (*pos && *pos != ':')
+ pos++;
+
+ len = pos - oldpos;
+ strncpy(buffer, oldpos, len + 1);
+ buffer[len] = '/';
+ strncpy(buffer + len + 1, filename, flen);
+
+ fd = open(buffer, O_RDONLY, 0);
+ if (fd >= 0)
+ {
+ return fd;
+ }
+
+ oldpos = ++pos;
+ }
+
+ return -1;
+}
+
+/* This function maps the specified section of a shared library. It
+ * also handles the special cases involving the bss and other
+ * anonymously mapped areas. */
+
+/*
+ * ----------------------- top
+ * | | (+phdr->p_memsz)
+ * | anonymous mapping |
+ * | (bss) |
+ * | |
+ * ----------------------- mid2
+ * ----------------------- ztop
+ * | zeroed out file |
+ * ----------------------- zbegin (+phdr->p_filesz)
+ * | | mid1
+ * | mapped file |
+ * | |
+ * | |
+ * ----------------------- bottom (+0)
+ */
+
+void _ldmapsect(int fd, unsigned long baseaddr, Elf64_Phdr *phdr, int textrel)
+{
+ uintptr_t vmaddr = ((uintptr_t)phdr->p_vaddr) + baseaddr;
+ uintptr_t offset = phdr->p_offset;
+ uintptr_t memsz = phdr->p_memsz;
+ uintptr_t filsz = phdr->p_filesz;
+
+ uintptr_t map_addr = trunc_page(vmaddr);
+ uintptr_t file_addr = trunc_page(offset);
+ uintptr_t map_len;
+ uintptr_t copy_len;
+ int perms = 0;
+
+ if (phdr->p_flags & PF_R)
+ perms |= PROT_READ;
+ if (phdr->p_flags & PF_W)
+ perms |= PROT_WRITE;
+ if (phdr->p_flags & PF_X)
+ perms |= PROT_EXEC;
+
+ /* Check if read-only sections will need relocation */
+ if (textrel)
+ perms |= PROT_WRITE;
+
+ if (memsz > filsz)
+ {
+ map_len = trunc_page(offset + filsz) - file_addr;
+ }
+ else
+ {
+ map_len = round_page(offset + filsz) - file_addr;
+ }
+
+ if (map_len != 0)
+ {
+ if (mmap((char *)map_addr, map_len, perms,
+ ((perms & PROT_WRITE) ? MAP_PRIVATE : MAP_SHARED) | MAP_FIXED,
+ fd, file_addr) == MAP_FAILED)
+ {
+ printf(err_mapping, map_len, map_addr);
+ exit(1);
+ }
+ }
+
+ if (memsz == filsz)
+ {
+ return;
+ }
+
+ file_addr = trunc_page(offset + filsz);
+ copy_len = (offset + filsz) - file_addr;
+ map_addr = trunc_page(vmaddr + filsz);
+ map_len = round_page(vmaddr + memsz) - map_addr;
+
+ if (map_len != 0)
+ {
+ void *addr;
+ int zfd = _ldzero();
+ addr = mmap((char *)map_addr, map_len, perms, MAP_PRIVATE | MAP_FIXED,
+ zfd, 0);
+ if (addr == MAP_FAILED)
+ {
+ printf("%s", err_zeromap);
+ exit(1);
+ }
+ close(zfd);
+
+ if (copy_len != 0)
+ {
+ lseek(fd, file_addr, SEEK_SET);
+ read(fd, addr, copy_len);
+ }
+ }
+}
+
+/* This function finds and maps the shared object associated with the
+ * specified module. When it is done, it calls _ldlinkobj to perform
+ * additional operations pertaining to the object's dependencies as
+ * well as the managment of the object at runtime */
+
+void _ldloadobj(module_t *module)
+{
+ unsigned long bottom, top, size;
+ Elf64_Ehdr *hdr;
+ Elf64_Phdr *phdr;
+ Elf64_Dyn *dyn = 0;
+ char *loc;
+ int fd;
+
+ /* attempt to open library */
+ fd = _ldtryopen(module->name, _ldenv.ld_library_path);
+ if (fd == -1)
+ fd = _ldtryopen(module->name, module->runpath);
+ if (fd == -1)
+ fd = _ldtryopen(module->name, default_runpath);
+ if (fd == -1)
+ {
+ printf(err_cantfind, module->name);
+ exit(1);
+ }
+
+ /* compute image size */
+ hdr = (Elf64_Ehdr *)mmap(0, pagesize, PROT_READ | PROT_EXEC, MAP_SHARED, fd,
+ 0);
+ phdr = (Elf64_Phdr *)(hdr->e_phoff + (unsigned long)hdr);
+
+ bottom = (unsigned long)-1;
+ top = 0;
+ for (size_t i = 0; i < hdr->e_phnum; i++)
+ {
+ if (phdr[i].p_type == PT_LOAD)
+ {
+ if (phdr[i].p_vaddr < bottom)
+ bottom = phdr[i].p_vaddr;
+ if (phdr[i].p_vaddr + phdr[i].p_memsz > top)
+ top = phdr[i].p_vaddr + phdr[i].p_memsz;
+ }
+ }
+
+ bottom = trunc_page(bottom);
+ top = round_page(top);
+ size = top - bottom;
+
+ loc = (char *)mmap(NULL, size, PROT_NONE, MAP_SHARED, fd, 0);
+ munmap(loc, size);
+
+ /* Figure out whether or not things marked readonly need to
+ * be writeable (find DT_TEXTREL). This is kind of a mess,
+ * as we have to do this before we've mapped in the dynamic
+ * section (need to read from file directly). */
+ off_t dynoff = 0;
+ Elf64_Dyn curdyn;
+ int textrel = 0;
+ for (size_t i = 0; i < hdr->e_phnum; i++)
+ {
+ if (phdr[i].p_type == PT_DYNAMIC)
+ {
+ dynoff = phdr[i].p_offset;
+ break;
+ }
+ }
+ lseek(fd, dynoff, SEEK_SET);
+ do
+ {
+ if ((ssize_t)sizeof(curdyn) > read(fd, &curdyn, sizeof(curdyn)))
+ exit(1);
+
+ if (curdyn.d_tag == DT_TEXTREL)
+ {
+ textrel = 1;
+ break;
+ }
+ } while (curdyn.d_tag != DT_NULL);
+
+ for (size_t i = 0; i < hdr->e_phnum; i++)
+ {
+ if (phdr[i].p_type == PT_LOAD)
+ _ldmapsect(fd, (unsigned long)loc - bottom, phdr + i, textrel);
+ else if (phdr[i].p_type == PT_DYNAMIC)
+ dyn = (Elf64_Dyn *)(loc + phdr[i].p_vaddr);
+ }
+ munmap(hdr, pagesize);
+ close(fd);
+
+ /* set up additional module information */
+ _ldlinkobj(module, loc - bottom, dyn);
+}
+
+void _ldcleanup(int status)
+{
+ module_t *curmod;
+
+ /* Call .fini functions */ /* XXX: fix ordering */
+ curmod = _ldfirst->next;
+ while (curmod)
+ {
+ if (curmod->fini)
+ curmod->fini();
+ curmod = curmod->next;
+ }
+
+ exit(status);
+}
+
+/* This is function is about as close to a 'mainline' as you will find
+ * in the linker loader. We initiate the process of
+ * evaluating and loading the dependencies of the executable. Next we
+ * relocate all the loaded modules, followed by calling the _init
+ * function of all the dependencies. Lastly, we return the entry point
+ * to the calling function (the bootstrap code), which runs the now
+ * linked process
+ */
+
+ldinit_t _ldstart(char **environ, auxv_t *auxv)
+{
+ uint64_t abuf[10];
+ module_t *curmod;
+ Elf64_Phdr *phdr;
+
+ /* Populate the auxv array */
+ memset(abuf, 0, 10 * sizeof(unsigned long));
+ for (size_t i = 0; auxv[i].a_type != AT_NULL; i++)
+ {
+ if (auxv[i].a_type < 10)
+ {
+ abuf[auxv[i].a_type] = (uint64_t)auxv[i].a_un.a_val;
+ }
+ }
+
+ pagesize = abuf[AT_PAGESZ];
+
+ /* Set up memory pool */
+ _ldainit(pagesize, 1);
+
+ _ldenv_init(environ);
+ /* Load the executable and all of it's dependencies */
+ phdr = (Elf64_Phdr *)abuf[AT_PHDR];
+
+ for (size_t i = 0; i < abuf[AT_PHNUM]; i++)
+ {
+ if (phdr[i].p_type == PT_DYNAMIC)
+ {
+ _ldlinkobj(NULL, (char *)0, (Elf64_Dyn *)phdr[i].p_vaddr);
+ break;
+ }
+ }
+
+ curmod = _ldfirst->next;
+ while (curmod)
+ {
+ _ldloadobj(curmod);
+ curmod = curmod->next;
+ }
+
+ /* Perform all necessary relocations */
+ /* We relocate the current module (executable) last, as it is the only one
+ * that will contain R_386_COPY entries, and we need to make sure the things
+ * being copied are correctly relocated (they are probably R_386_RELATIVE)
+ * prior to copying */
+ curmod = _ldfirst->next; /* Assume at least one module... */
+ while (curmod)
+ {
+ _ldrelocobj(curmod);
+ curmod = curmod->next;
+ }
+ _ldrelocobj(_ldfirst);
+
+ curmod = _ldfirst;
+ while (curmod)
+ {
+ _ldrelocplt(curmod);
+ curmod = curmod->next;
+ }
+
+ if (_ldenv.ld_bind_now)
+ {
+ curmod = _ldfirst;
+ while (curmod)
+ {
+ _ldbindnow(curmod);
+ curmod = curmod->next;
+ }
+ }
+
+ /* Call .init functions */ /* XXX: fix ordering */
+ curmod = _ldfirst->next;
+ while (curmod)
+ {
+ if (curmod->init)
+ {
+ curmod->init();
+ }
+ curmod = curmod->next;
+ }
+
+ /* Jump to the linkee's entry point */
+ _ldverify(!abuf[AT_ENTRY], err_noentry);
+ return (ldinit_t)abuf[AT_ENTRY];
+}
diff --git a/user/lib/ld-weenix/ldtypes.h b/user/lib/ld-weenix/ldtypes.h
new file mode 100644
index 0000000..c25c3b7
--- /dev/null
+++ b/user/lib/ld-weenix/ldtypes.h
@@ -0,0 +1,60 @@
+/*
+ * File: ldtypes.h
+ * Date: 12 April 1998
+ * Acct: David Powell (dep)
+ * Desc:
+ *
+ *
+ * Acct: Sandy Harvie (charvie)
+ * Date: 26 March 2019
+ * Desc: Modified for x86-64
+ */
+
+#ifndef _ldtypes_h_
+#define _ldtypes_h_
+
+#include "elf.h"
+
+#define LD_ERR_EXIT 13
+
+typedef Elf64_auxv_t auxv_t; /* linux is funky */
+
+typedef int (*ldfunc_t)();
+typedef void *ldsym_t;
+typedef void (*ldinit_t)(int argc, char **argv, char **envp, auxv_t *auxv);
+
+typedef struct ldenv_t
+{
+ int ld_bind_now;
+ int ld_debug;
+ const char *ld_preload;
+ const char *ld_library_path;
+} ldenv_t;
+
+extern ldenv_t _ldenv;
+
+typedef struct module
+{
+ char *name; /* the filename */
+ char *runpath; /* the run path to use */
+
+ unsigned long base; /* base address of module */
+ Elf64_Word *hash; /* the module's hash table */
+ Elf64_Sym *dynsym; /* the dynamic symbol table */
+ char *dynstr; /* the dynamic string table */
+
+ ldfunc_t init; /* module initialization fcn. */
+ ldfunc_t fini; /* module shutdown fcn. */
+
+ Elf64_Rela *pltreloc; /* PLT relocations */
+ Elf64_Rela *reloc; /* normal relocations */
+
+ size_t nreloc; /* number of relocation entries */
+ size_t npltreloc; /* number of relocation entries */
+
+ struct module *next; /* the next module in the chain */
+ struct module *first; /* the first module */
+ Elf64_Addr *pltgot; /* base of plt */
+} module_t;
+
+#endif /* _ldtypes.h_ */
diff --git a/user/lib/ld-weenix/ldutil.c b/user/lib/ld-weenix/ldutil.c
new file mode 100644
index 0000000..b6509a3
--- /dev/null
+++ b/user/lib/ld-weenix/ldutil.c
@@ -0,0 +1,72 @@
+/*
+ * File: ldutil.c
+ * Date: 15 March 1998
+ * Acct: David Powell (dep)
+ * Desc: Functions that didn't fit anywhere else
+ *
+ *
+ * Acct: Sandy Harvie (charvie)
+ * Date: 27 March 2019
+ * Desc: Modified for x86-64
+ */
+
+/* LINTLIBRARY */
+
+#include "fcntl.h"
+#include "stdio.h"
+#include "stdlib.h"
+#include "string.h"
+#include "unistd.h"
+
+#include "ldtypes.h"
+#include "ldutil.h"
+
+static const char *err_zero = "ld.so.1: panic - unable to open /dev/zero\n";
+
+/* I wrote this back before I had printf... maybe it should disappear. */
+
+void _ldverify(int test, const char *msg)
+{
+ if (test)
+ {
+ (void)write(STDERR_FILENO, msg, strlen(msg));
+ exit(LD_ERR_EXIT);
+ }
+}
+
+/* This function simply attempts to open /dev/zero, exiting if the call
+ * to open failed. The file descriptor of the newly opened file is
+ * returned. */
+
+int _ldzero()
+{
+ int zfd;
+
+ if ((zfd = open("/dev/zero", O_RDONLY, 0)) < 0)
+ {
+ printf("%s", err_zero);
+ exit(1);
+ }
+
+ return zfd;
+}
+
+/* This is the hash operation used for the string-to-symbol hash
+ * table in dynamic ELF binaries. This function is taken more or less
+ * directly from the LLM */
+
+unsigned long _ldelfhash(const char *name)
+{
+ uint32_t h = 0, g;
+
+ while (*name)
+ {
+ h = (h << 4) + *name++;
+ /* LINTED */
+ if ((g = h & 0xf0000000))
+ h ^= g >> 24;
+ h &= ~g;
+ }
+
+ return h;
+}
diff --git a/user/lib/ld-weenix/ldutil.h b/user/lib/ld-weenix/ldutil.h
new file mode 100644
index 0000000..2313625
--- /dev/null
+++ b/user/lib/ld-weenix/ldutil.h
@@ -0,0 +1,39 @@
+/*
+ * File: ldutil.h
+ * Date: 15 March 1998
+ * Acct: David Powell (dep)
+ * Desc: Miscellanious utility functions
+ *
+ *
+ * Acct: Sandy Harvie (charvie)
+ * Date: 27 March 2019
+ * Desc: Modified for x86-64
+ */
+
+#ifndef _ldutil_h_
+#define _ldutil_h_
+#include "ldtypes.h"
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+ void _ldverify(int test, const char *msg);
+ int _ldzero();
+
+ unsigned long _ldelfhash(const char *name);
+ int _ldtryopen(const char *filename, const char *path);
+ void _ldmapsect(int fd, unsigned long baseaddr, Elf64_Phdr *phdr, int textrel);
+ void _ldloadobj(module_t *module);
+ void _ldrelocobj(module_t *module);
+ void _ldcleanup();
+ ldinit_t _ldstart(char **environ, auxv_t *auxv);
+
+ void _ldrelocplt(module_t *module);
+ void _ldpltgot_init(module_t *module);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _ldutil_h_ */
diff --git a/user/lib/ld-weenix/smacros.h b/user/lib/ld-weenix/smacros.h
new file mode 100644
index 0000000..416b1f2
--- /dev/null
+++ b/user/lib/ld-weenix/smacros.h
@@ -0,0 +1,40 @@
+/*
+ * File: smacros.h
+ * Date: 14 March 1998
+ * Acct: David Powell (dep)
+ * Desc: Some additional SPARC assembly macros
+ */
+
+#ifndef _smacros_h_
+#define _smacros_h_
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+ /* Local entry points */
+
+#define LENTRY(x) \
+ .section ".text"; \
+ .align 4; \
+ .type x, #function; \
+ x:
+
+#define ALTLENTRY(x) \
+ .type x, #function; \
+ x:
+
+ /* This macro assumes you don't care what happens to %o7 */
+
+#define GET_GOT(x) \
+ call 1f; \
+ sethi % hi(_GLOBAL_OFFSET_TABLE_ + 4), x; \
+ 1 : or x, % lo(_GLOBAL_OFFSET_TABLE_ + 8), x; \
+ add % o7, x, x
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _smacros_h_ */
diff --git a/user/lib/libc/entry.S b/user/lib/libc/entry.S
new file mode 100644
index 0000000..e642fe4
--- /dev/null
+++ b/user/lib/libc/entry.S
@@ -0,0 +1,17 @@
+#ifndef __DYNAMIC__
+
+.globl __libc_static_entry
+
+__libc_static_entry:
+ add $8, %rsp /* Make sure when we overwrite dummy return address
+ with the correct one, so args will be in the right
+ place when we call main */
+ movq (%rsp), %rdi /* Copy arguments from stack into registers */
+ movq 8(%rsp), %rsi
+ movq 16(%rsp), %rdx
+ movq 24(%rsp), %rcx
+ call main
+ mov %rax, %rdi
+ call exit
+
+#endif
diff --git a/user/lib/libc/errno.c b/user/lib/libc/errno.c
new file mode 100644
index 0000000..c3d6594
--- /dev/null
+++ b/user/lib/libc/errno.c
@@ -0,0 +1,3 @@
+#include <errno.h>
+
+int _libc_errno;
diff --git a/user/lib/libc/malloc.c b/user/lib/libc/malloc.c
new file mode 100644
index 0000000..3498dc8
--- /dev/null
+++ b/user/lib/libc/malloc.c
@@ -0,0 +1,1326 @@
+/*
+ * ----------------------------------------------------------------------------
+ * "THE BEER-WARE LICENSE" (Revision 42):
+ * <phk@FreeBSD.ORG> wrote this file. As long as you retain this notice you
+ * can do whatever you want with this stuff. If we meet some day, and you think
+ * this stuff is worth it, you can buy me a beer in return. Poul-Henning Kamp
+ * ----------------------------------------------------------------------------
+ *
+ */
+#include "fcntl.h"
+#include "stddef.h"
+#include "stdlib.h"
+#include "string.h"
+#include "sys/mman.h"
+#include "sys/types.h"
+#include "unistd.h"
+
+#define __inline__ inline
+
+/* Necessary BSD types and functions */
+typedef unsigned short u_short;
+typedef unsigned char u_char;
+typedef unsigned int u_int;
+typedef unsigned long u_long;
+#define _open open
+#define _write write
+
+/*
+ * Defining EXTRA_SANITY will enable extra checks which are related
+ * to internal conditions and consistency in malloc.c. This has a
+ * noticeable runtime performance hit, and generally will not do you
+ * any good unless you fiddle with the internals of malloc or want
+ * to catch random pointer corruption as early as possible.
+ */
+#ifndef MALLOC_EXTRA_SANITY
+#undef MALLOC_EXTRA_SANITY
+#endif
+
+/*
+ * What to use for Junk. This is the byte value we use to fill with
+ * when the 'J' option is enabled.
+ */
+#define SOME_JUNK 0xd0 /* as in "Duh" :-) */
+
+/*
+ * The basic parameters you can tweak.
+ *
+ * malloc_pageshift pagesize = 1 << malloc_pageshift
+ * It's probably best if this is the native
+ * page size, but it doesn't have to be.
+ *
+ * malloc_minsize minimum size of an allocation in bytes.
+ * If this is too small it's too much work
+ * to manage them. This is also the smallest
+ * unit of alignment used for the storage
+ * returned by malloc/realloc.
+ *
+ */
+#define malloc_pageshift 12U
+#define malloc_minsize 16U
+
+static int fdzero;
+#define MMAP_FD fdzero
+#define INIT_MMAP() \
+ { \
+ if ((fdzero = _open("/dev/zero", O_RDWR, 0000)) == -1) \
+ wrterror("open of /dev/zero"); \
+ }
+#define MADV_FREE MADV_DONTNEED
+
+/*
+ * No user serviceable parts behind this point.
+ */
+
+/*
+ * This structure describes a page worth of chunks.
+ */
+
+struct pginfo
+{
+ struct pginfo *next; /* next on the free list */
+ void *page; /* Pointer to the page */
+ u_short size; /* size of this page's chunks */
+ u_short shift; /* How far to shift for this size chunks */
+ u_short free; /* How many free chunks */
+ u_short total; /* How many chunk */
+ u_int bits[1]; /* Which chunks are free */
+};
+
+/*
+ * This structure describes a number of free pages.
+ */
+
+struct pgfree
+{
+ struct pgfree *next; /* next run of free pages */
+ struct pgfree *prev; /* prev run of free pages */
+ void *page; /* pointer to free pages */
+ void *end; /* pointer to end of free pages */
+ size_t size; /* number of bytes free */
+};
+
+/*
+ * How many bits per u_int in the bitmap.
+ * Change only if not 8 bits/byte
+ */
+#define MALLOC_BITS (8 * sizeof(u_int))
+
+/*
+ * Magic values to put in the page_directory
+ */
+#define MALLOC_NOT_MINE ((struct pginfo *)0)
+#define MALLOC_FREE ((struct pginfo *)1)
+#define MALLOC_FIRST ((struct pginfo *)2)
+#define MALLOC_FOLLOW ((struct pginfo *)3)
+#define MALLOC_MAGIC ((struct pginfo *)4)
+
+#ifndef malloc_pageshift
+#define malloc_pageshift 12U
+#endif
+
+#ifndef malloc_minsize
+#define malloc_minsize 16U
+#endif
+
+#if !defined(malloc_pagesize)
+#define malloc_pagesize (1UL << malloc_pageshift)
+#endif
+
+#if ((1 << malloc_pageshift) != malloc_pagesize)
+#error "(1<<malloc_pageshift) != malloc_pagesize"
+#endif
+
+#ifndef malloc_maxsize
+#define malloc_maxsize ((malloc_pagesize) >> 1)
+#endif
+
+/* A mask for the offset inside a page. */
+#define malloc_pagemask ((malloc_pagesize)-1)
+
+#define pageround(foo) (((foo) + (malloc_pagemask)) & (~(malloc_pagemask)))
+#define ptr2index(foo) (((u_long)(foo) >> malloc_pageshift) - malloc_origo)
+
+#ifndef THREAD_LOCK
+#define THREAD_LOCK()
+#endif
+
+#ifndef THREAD_UNLOCK
+#define THREAD_UNLOCK()
+#endif
+
+#ifndef MMAP_FD
+#define MMAP_FD (-1)
+#endif
+
+#ifndef INIT_MMAP
+#define INIT_MMAP()
+#endif
+
+/* Set when initialization has been done */
+static unsigned malloc_started;
+
+/* Recusion flag for public interface. */
+static int malloc_active;
+
+/* Number of free pages we cache */
+static unsigned malloc_cache = 16;
+
+/* The offset from pagenumber to index into the page directory */
+static u_long malloc_origo;
+
+/* The last index in the page directory we care about */
+static u_long last_index;
+
+/* Pointer to page directory. Allocated "as if with" malloc */
+static struct pginfo **page_dir;
+
+/* How many slots in the page directory */
+static unsigned malloc_ninfo;
+
+/* Free pages line up here */
+static struct pgfree free_list;
+
+/* Abort(), user doesn't handle problems. */
+static int malloc_abort;
+
+/* Are we trying to die ? */
+static int suicide;
+
+/* always realloc ? */
+static int malloc_realloc;
+
+/* pass the kernel a hint on free pages ? */
+static int malloc_hint = 0;
+
+/* xmalloc behaviour ? */
+static int malloc_xmalloc;
+
+/* sysv behaviour for malloc(0) ? */
+static int malloc_sysv;
+
+/* zero fill ? */
+static int malloc_zero;
+
+/* junk fill ? */
+static int malloc_junk;
+
+#ifdef HAS_UTRACE
+
+/* utrace ? */
+static int malloc_utrace;
+
+struct ut
+{
+ void *p;
+ size_t s;
+ void *r;
+};
+
+void utrace __P((struct ut *, int));
+
+#define UTRACE(a, b, c) \
+ if (malloc_utrace) \
+ { \
+ struct ut u; \
+ u.p = a; \
+ u.s = b; \
+ u.r = c; \
+ utrace(&u, sizeof u); \
+ }
+#else /* !HAS_UTRACE */
+#define UTRACE(a, b, c)
+#endif /* HAS_UTRACE */
+
+/* my last break. */
+static void *malloc_brk;
+
+/* one location cache for free-list holders */
+static struct pgfree *px;
+
+/* compile-time options */
+char *malloc_options;
+typedef char *caddr_t;
+/* Name of the current public function */
+static char *malloc_func;
+
+/* Macro for mmap */
+#define MMAP(size) \
+ mmap(0, (size), PROT_READ | PROT_WRITE, MAP_PRIVATE, MMAP_FD, 0);
+
+/*
+ * Necessary function declarations
+ */
+static int extend_pgdir(u_long index);
+
+static void *imalloc(size_t size);
+
+static void ifree(void *ptr);
+
+static void *irealloc(void *ptr, size_t size);
+
+#ifdef HAS_PROGNAME
+extern char *__progname;
+#else
+static char *__progname = "";
+#endif
+
+#ifndef HAS_ABORT
+#define abort() exit(1)
+#endif
+
+static void wrterror(char *p)
+{
+ char *q = " error: ";
+ _write(STDERR_FILENO, __progname, strlen(__progname));
+ _write(STDERR_FILENO, malloc_func, strlen(malloc_func));
+ _write(STDERR_FILENO, q, strlen(q));
+ _write(STDERR_FILENO, p, strlen(p));
+ suicide = 1;
+ abort();
+}
+
+static void wrtwarning(char *p)
+{
+ char *q = " warning: ";
+ if (malloc_abort)
+ {
+ wrterror(p);
+ }
+ _write(STDERR_FILENO, __progname, strlen(__progname));
+ _write(STDERR_FILENO, malloc_func, strlen(malloc_func));
+ _write(STDERR_FILENO, q, strlen(q));
+ _write(STDERR_FILENO, p, strlen(p));
+}
+
+/*
+ * Allocate a number of pages from the OS
+ */
+static void *map_pages(int pages)
+{
+ caddr_t result, tail;
+
+ result = (caddr_t)pageround((u_long)sbrk(0));
+ tail = result + (pages << malloc_pageshift);
+
+ if (brk(tail))
+ {
+#ifdef EXTRA_SANITY
+ wrterror("(ES): map_pages fails\n");
+#endif /* EXTRA_SANITY */
+ return 0;
+ }
+
+ last_index = ptr2index(tail) - 1;
+ malloc_brk = tail;
+
+ if ((last_index + 1) >= malloc_ninfo && !extend_pgdir(last_index))
+ {
+ return 0;
+ };
+
+ return result;
+}
+
+/*
+ * Extend page directory
+ */
+static int extend_pgdir(u_long index)
+{
+ struct pginfo **new, **old;
+ int i, oldlen;
+
+ /* Make it this many pages */
+ i = index * sizeof *page_dir;
+ i /= malloc_pagesize;
+ i += 2;
+
+ /* remember the old mapping size */
+ oldlen = malloc_ninfo * sizeof *page_dir;
+
+ /*
+ * NOTE: we allocate new pages and copy the directory rather than tempt
+ * fate by trying to "grow" the region.. There is nothing to prevent
+ * us from accidently re-mapping space that's been allocated by our caller
+ * via dlopen() or other mmap().
+ *
+ * The copy problem is not too bad, as there is 4K of page index per
+ * 4MB of malloc arena.
+ *
+ * We can totally avoid the copy if we open a file descriptor to associate
+ * the anon mappings with. Then, when we remap the pages at the new
+ * address, the old pages will be "magically" remapped.. But this means
+ * keeping open a "secret" file descriptor.....
+ */
+
+ /* Get new pages */
+ new = (struct pginfo **)MMAP(i * malloc_pagesize);
+ if (new == (struct pginfo **)-1)
+ {
+ return 0;
+ }
+
+ /* Copy the old stuff */
+ memcpy(new, page_dir, malloc_ninfo * sizeof *page_dir);
+
+ /* register the new size */
+ malloc_ninfo = i * malloc_pagesize / sizeof *page_dir;
+
+ /* swap the pointers */
+ old = page_dir;
+ page_dir = new;
+
+ /* Now free the old stuff */
+ munmap((char *)old, oldlen);
+ return 1;
+}
+
+/*
+ * Initialize the world
+ */
+static void malloc_init()
+{
+ char *p;
+ int i, j;
+
+ INIT_MMAP();
+
+#ifdef EXTRA_SANITY
+ malloc_junk = 1;
+#endif /* EXTRA_SANITY */
+
+ for (i = 0; i < 3; i++)
+ {
+ if (i == 0)
+ {
+#ifdef HAS_READLINK
+ errnosave = errno;
+ j = readlink("/etc/malloc.conf", b, sizeof b - 1);
+ errno = errnosave;
+ if (j <= 0)
+ continue;
+ b[j] = '\0';
+ p = b;
+#else
+ p = NULL;
+#endif
+ }
+ else if (i == 1)
+ {
+#ifdef HAS_GETENV
+ p = getenv("MALLOC_OPTIONS");
+#else
+ p = NULL;
+#endif
+ }
+ else
+ {
+ p = malloc_options;
+ }
+ for (; p && *p; p++)
+ {
+ switch (*p)
+ {
+ case '>':
+ malloc_cache <<= 1;
+ break;
+ case '<':
+ malloc_cache >>= 1;
+ break;
+ case 'a':
+ malloc_abort = 0;
+ break;
+ case 'A':
+ malloc_abort = 1;
+ break;
+ case 'h':
+ malloc_hint = 0;
+ break;
+ case 'H':
+ malloc_hint = 1;
+ break;
+ case 'r':
+ malloc_realloc = 0;
+ break;
+ case 'R':
+ malloc_realloc = 1;
+ break;
+ case 'j':
+ malloc_junk = 0;
+ break;
+ case 'J':
+ malloc_junk = 1;
+ break;
+#ifdef HAS_UTRACE
+ case 'u':
+ malloc_utrace = 0;
+ break;
+ case 'U':
+ malloc_utrace = 1;
+ break;
+#endif
+ case 'v':
+ malloc_sysv = 0;
+ break;
+ case 'V':
+ malloc_sysv = 1;
+ break;
+ case 'x':
+ malloc_xmalloc = 0;
+ break;
+ case 'X':
+ malloc_xmalloc = 1;
+ break;
+ case 'z':
+ malloc_zero = 0;
+ break;
+ case 'Z':
+ malloc_zero = 1;
+ break;
+ default:
+ j = malloc_abort;
+ malloc_abort = 0;
+ wrtwarning("unknown char in MALLOC_OPTIONS\n");
+ malloc_abort = j;
+ break;
+ }
+ }
+ }
+
+ UTRACE(0, 0, 0);
+
+ /*
+ * We want junk in the entire allocation, and zero only in the part
+ * the user asked for.
+ */
+ if (malloc_zero)
+ {
+ malloc_junk = 1;
+ }
+
+ /*
+ * If we run with junk (or implicitly from above: zero), we want to
+ * force realloc() to get new storage, so we can DTRT with it.
+ */
+ if (malloc_junk)
+ {
+ malloc_realloc = 1;
+ }
+
+ /* Allocate one page for the page directory */
+ page_dir = (struct pginfo **)MMAP(malloc_pagesize);
+
+ if (page_dir == (struct pginfo **)-1)
+ {
+ wrterror("mmap(2) failed, check limits\n");
+ }
+
+ /*
+ * We need a maximum of malloc_pageshift buckets, steal these from the
+ * front of the page_directory;
+ */
+ malloc_origo = ((u_long)pageround((u_long)sbrk(0))) >> malloc_pageshift;
+ malloc_origo -= malloc_pageshift;
+
+ malloc_ninfo = malloc_pagesize / sizeof *page_dir;
+
+ /* Recalculate the cache size in bytes, and make sure it's nonzero */
+
+ if (!malloc_cache)
+ {
+ malloc_cache++;
+ }
+
+ malloc_cache <<= malloc_pageshift;
+
+ /*
+ * This is a nice hack from Kaleb Keithly (kaleb@x.org).
+ * We can sbrk(2) further back when we keep this on a low address.
+ */
+ px = (struct pgfree *)imalloc(sizeof *px);
+
+ /* Been here, done that */
+ malloc_started++;
+}
+
+/*
+ * Allocate a number of complete pages
+ */
+static void *malloc_pages(size_t size)
+{
+ void *p, *delay_free = 0;
+ unsigned int i;
+ struct pgfree *pf;
+ u_long index;
+
+ size = pageround(size);
+
+ p = 0;
+
+ /* Look for free pages before asking for more */
+ for (pf = free_list.next; pf; pf = pf->next)
+ {
+#ifdef EXTRA_SANITY
+ if (pf->size & malloc_pagemask)
+ wrterror("(ES): junk length entry on free_list\n");
+ if (!pf->size)
+ wrterror("(ES): zero length entry on free_list\n");
+ if (pf->page == pf->end)
+ wrterror("(ES): zero entry on free_list\n");
+ if (pf->page > pf->end)
+ wrterror("(ES): sick entry on free_list\n");
+ if ((void *)pf->page >= (void *)sbrk(0))
+ wrterror("(ES): entry on free_list past brk\n");
+ if (page_dir[ptr2index(pf->page)] != MALLOC_FREE)
+ wrterror("(ES): non-free first page on free-list\n");
+ if (page_dir[ptr2index(pf->end) - 1] != MALLOC_FREE)
+ wrterror("(ES): non-free last page on free-list\n");
+#endif /* EXTRA_SANITY */
+
+ if (pf->size < size)
+ {
+ continue;
+ }
+
+ if (pf->size == size)
+ {
+ p = pf->page;
+ if (pf->next)
+ {
+ pf->next->prev = pf->prev;
+ }
+ pf->prev->next = pf->next;
+ delay_free = pf;
+ break;
+ }
+
+ p = pf->page;
+ pf->page = (char *)pf->page + size;
+ pf->size -= size;
+ break;
+ }
+
+#ifdef EXTRA_SANITY
+ if (p && page_dir[ptr2index(p)] != MALLOC_FREE)
+ wrterror("(ES): allocated non-free page on free-list\n");
+#endif /* EXTRA_SANITY */
+
+ size >>= malloc_pageshift;
+
+ /* Map new pages */
+ if (!p)
+ {
+ p = map_pages(size);
+ }
+
+ if (p)
+ {
+ index = ptr2index(p);
+ page_dir[index] = MALLOC_FIRST;
+ for (i = 1; i < size; i++)
+ {
+ page_dir[index + i] = MALLOC_FOLLOW;
+ }
+
+ if (malloc_junk)
+ {
+ memset(p, SOME_JUNK, size << malloc_pageshift);
+ }
+ }
+
+ if (delay_free)
+ {
+ if (!px)
+ {
+ px = delay_free;
+ }
+ else
+ {
+ ifree(delay_free);
+ }
+ }
+
+ return p;
+}
+
+/*
+ * Allocate a page of fragments
+ */
+
+static __inline__ int malloc_make_chunks(int bits)
+{
+ struct pginfo *bp;
+ void *pp;
+ int i, k, l;
+
+ /* Allocate a new bucket */
+ pp = malloc_pages(malloc_pagesize);
+ if (!pp)
+ {
+ return 0;
+ }
+
+ /* Find length of admin structure */
+ l = offsetof(struct pginfo, bits[0]);
+ l += sizeof bp->bits[0] *
+ (((malloc_pagesize >> bits) + MALLOC_BITS - 1) / MALLOC_BITS);
+
+ /* Don't waste more than two chunks on this */
+ if ((1 << bits) <= l + l)
+ {
+ bp = (struct pginfo *)pp;
+ }
+ else
+ {
+ bp = (struct pginfo *)imalloc(l);
+ if (!bp)
+ {
+ ifree(pp);
+ return 0;
+ }
+ }
+
+ bp->size = (1 << bits);
+ bp->shift = bits;
+ bp->total = bp->free = malloc_pagesize >> bits;
+ bp->page = pp;
+
+ /* set all valid bits in the bitmap */
+ k = bp->total;
+ i = 0;
+
+ /* Do a bunch at a time */
+ for (; k - i >= (int)MALLOC_BITS; i += MALLOC_BITS)
+ {
+ bp->bits[i / MALLOC_BITS] = ~0;
+ }
+
+ for (; i < k; i++)
+ {
+ bp->bits[i / MALLOC_BITS] |= 1 << (i % MALLOC_BITS);
+ }
+
+ if (bp == bp->page)
+ {
+ /* Mark the ones we stole for ourselves */
+ for (i = 0; l > 0; i++)
+ {
+ bp->bits[i / MALLOC_BITS] &= ~(1 << (i % MALLOC_BITS));
+ bp->free--;
+ bp->total--;
+ l -= (1 << bits);
+ }
+ }
+
+ /* MALLOC_LOCK */
+
+ page_dir[ptr2index(pp)] = bp;
+
+ bp->next = page_dir[bits];
+ page_dir[bits] = bp;
+
+ /* MALLOC_UNLOCK */
+
+ return 1;
+}
+
+/*
+ * Allocate a fragment
+ */
+static void *malloc_bytes(size_t size)
+{
+ int i, j;
+ u_int u;
+ struct pginfo *bp;
+ int k;
+ u_int *lp;
+
+ /* Don't bother with anything less than this */
+ if (size < malloc_minsize)
+ {
+ size = malloc_minsize;
+ }
+
+ /* Find the right bucket */
+ j = 1;
+ i = size - 1;
+ while (i >>= 1)
+ j++;
+
+ /* If it's empty, make a page more of that size chunks */
+ if (!page_dir[j] && !malloc_make_chunks(j))
+ {
+ return 0;
+ }
+
+ bp = page_dir[j];
+
+ /* Find first word of bitmap which isn't empty */
+ for (lp = bp->bits; !*lp; lp++)
+ ;
+
+ /* Find that bit, and tweak it */
+ u = 1;
+ k = 0;
+ while (!(*lp & u))
+ {
+ u += u;
+ k++;
+ }
+ *lp ^= u;
+
+ /* If there are no more free, remove from free-list */
+ if (!--bp->free)
+ {
+ page_dir[j] = bp->next;
+ bp->next = 0;
+ }
+
+ /* Adjust to the real offset of that chunk */
+ k += (lp - bp->bits) * MALLOC_BITS;
+ k <<= bp->shift;
+
+ if (malloc_junk)
+ {
+ memset((u_char *)bp->page + k, SOME_JUNK, bp->size);
+ }
+
+ return (u_char *)bp->page + k;
+}
+
+/*
+ * Allocate a piece of memory
+ */
+static void *imalloc(size_t size)
+{
+ void *result;
+
+ if (suicide)
+ abort();
+
+ if ((size + malloc_pagesize) < size)
+ { /* Check for overflow */
+ result = 0;
+ }
+ else if (size <= malloc_maxsize)
+ {
+ result = malloc_bytes(size);
+ }
+ else
+ {
+ result = malloc_pages(size);
+ }
+
+ if (malloc_abort && !result)
+ {
+ wrterror("allocation failed.\n");
+ }
+
+ if (malloc_zero && result)
+ {
+ memset(result, 0, size);
+ }
+
+ return result;
+}
+
+/*
+ * Change the size of an allocation.
+ */
+static void *irealloc(void *ptr, size_t size)
+{
+ void *p;
+ u_long osize, index;
+ struct pginfo **mp;
+ int i;
+
+ if (suicide)
+ abort();
+
+ index = ptr2index(ptr);
+
+ if (index < malloc_pageshift)
+ {
+ wrtwarning("junk pointer, too low to make sense.\n");
+ return 0;
+ }
+
+ if (index > last_index)
+ {
+ wrtwarning("junk pointer, too high to make sense.\n");
+ return 0;
+ }
+
+ mp = &page_dir[index];
+
+ if (*mp == MALLOC_FIRST)
+ { /* Page allocation */
+
+ /* Check the pointer */
+ if ((u_long)ptr & malloc_pagemask)
+ {
+ wrtwarning("modified (page-) pointer.\n");
+ return 0;
+ }
+
+ /* Find the size in bytes */
+ for (osize = malloc_pagesize; *++mp == MALLOC_FOLLOW;)
+ {
+ osize += malloc_pagesize;
+ }
+
+ if (!malloc_realloc && /* unless we have to, */
+ size <= osize && /* .. or are too small, */
+ size > (osize - malloc_pagesize))
+ { /* .. or can free a page, */
+ return ptr; /* don't do anything. */
+ }
+ }
+ else if (*mp >= MALLOC_MAGIC)
+ { /* Chunk allocation */
+
+ /* Check the pointer for sane values */
+ if (((u_long)ptr & ((*mp)->size - 1)))
+ {
+ wrtwarning("modified (chunk-) pointer.\n");
+ return 0;
+ }
+
+ /* Find the chunk index in the page */
+ i = ((u_long)ptr & malloc_pagemask) >> (*mp)->shift;
+
+ /* Verify that it isn't a free chunk already */
+ if ((*mp)->bits[i / MALLOC_BITS] & (1 << (i % MALLOC_BITS)))
+ {
+ wrtwarning("chunk is already free.\n");
+ return 0;
+ }
+
+ osize = (*mp)->size;
+
+ if (!malloc_realloc && /* Unless we have to, */
+ size < osize && /* ..or are too small, */
+ (size > osize / 2 || /* ..or could use a smaller size, */
+ osize == malloc_minsize))
+ { /* ..(if there is one) */
+ return ptr; /* ..Don't do anything */
+ }
+ }
+ else
+ {
+ wrtwarning("pointer to wrong page.\n");
+ return 0;
+ }
+
+ p = imalloc(size);
+
+ if (p)
+ {
+ /* copy the lesser of the two sizes, and free the old one */
+ if (!size || !osize)
+ {
+ }
+ else if (osize < size)
+ {
+ memcpy(p, ptr, osize);
+ }
+ else
+ {
+ memcpy(p, ptr, size);
+ }
+ ifree(ptr);
+ }
+ return p;
+}
+
+/*
+ * Free a sequence of pages
+ */
+
+static __inline__ void free_pages(void *ptr, int index, struct pginfo *info)
+{
+ unsigned int i;
+ struct pgfree *pf, *pt = 0;
+ u_long l;
+ void *tail;
+
+ if (info == MALLOC_FREE)
+ {
+ wrtwarning("page is already free.\n");
+ return;
+ }
+
+ if (info != MALLOC_FIRST)
+ {
+ wrtwarning("pointer to wrong page.\n");
+ return;
+ }
+
+ if ((u_long)ptr & malloc_pagemask)
+ {
+ wrtwarning("modified (page-) pointer.\n");
+ return;
+ }
+
+ /* Count how many pages and mark them free at the same time */
+ page_dir[index] = MALLOC_FREE;
+ for (i = 1; page_dir[index + i] == MALLOC_FOLLOW; i++)
+ {
+ page_dir[index + i] = MALLOC_FREE;
+ }
+
+ l = i << malloc_pageshift;
+
+ if (malloc_junk)
+ {
+ memset(ptr, SOME_JUNK, l);
+ }
+
+#ifdef HAS_MADVISE
+ if (malloc_hint)
+ madvise(ptr, l, MADV_FREE);
+#endif
+
+ tail = (char *)ptr + l;
+
+ /* add to free-list */
+ if (!px)
+ {
+ px = imalloc(sizeof *pt);
+ } /* This cannot fail... */
+ px->page = ptr;
+ px->end = tail;
+ px->size = l;
+ if (!free_list.next)
+ {
+ /* Nothing on free list, put this at head */
+ px->next = free_list.next;
+ px->prev = &free_list;
+ free_list.next = px;
+ pf = px;
+ px = 0;
+ }
+ else
+ {
+ /* Find the right spot, leave pf pointing to the modified entry. */
+ tail = (char *)ptr + l;
+
+ for (pf = free_list.next; pf->end < ptr && pf->next; pf = pf->next)
+ ; /* Race ahead here */
+
+ if (pf->page > tail)
+ {
+ /* Insert before entry */
+ px->next = pf;
+ px->prev = pf->prev;
+ pf->prev = px;
+ px->prev->next = px;
+ pf = px;
+ px = 0;
+ }
+ else if (pf->end == ptr)
+ {
+ /* Append to the previous entry */
+ pf->end = (char *)pf->end + l;
+ pf->size += l;
+ if (pf->next && pf->end == pf->next->page)
+ {
+ /* And collapse the next too. */
+ pt = pf->next;
+ pf->end = pt->end;
+ pf->size += pt->size;
+ pf->next = pt->next;
+ if (pf->next)
+ pf->next->prev = pf;
+ }
+ }
+ else if (pf->page == tail)
+ {
+ /* Prepend to entry */
+ pf->size += l;
+ pf->page = ptr;
+ }
+ else if (!pf->next)
+ {
+ /* Append at tail of chain */
+ px->next = 0;
+ px->prev = pf;
+ pf->next = px;
+ pf = px;
+ px = 0;
+ }
+ else
+ {
+ wrterror("freelist is destroyed.\n");
+ }
+ }
+
+ /* Return something to OS ? */
+ if (!pf->next && /* If we're the last one, */
+ pf->size > malloc_cache && /* ..and the cache is full, */
+ pf->end == malloc_brk && /* ..and none behind us, */
+ malloc_brk == sbrk(0))
+ { /* ..and it's OK to do... */
+
+ /*
+ * Keep the cache intact. Notice that the '>' above guarantees that
+ * the pf will always have at least one page afterwards.
+ */
+ pf->end = (char *)pf->page + malloc_cache;
+ pf->size = malloc_cache;
+
+ brk(pf->end);
+ malloc_brk = pf->end;
+
+ index = ptr2index(pf->end);
+ last_index = index - 1;
+
+ for (i = index; i <= last_index;)
+ page_dir[i++] = MALLOC_NOT_MINE;
+
+ /* XXX: We could realloc/shrink the pagedir here I guess. */
+ }
+ if (pt)
+ ifree(pt);
+}
+
+/*
+ * Free a chunk, and possibly the page it's on, if the page becomes empty.
+ */
+
+static __inline__ void free_bytes(void *ptr, int index, struct pginfo *info)
+{
+ int i;
+ struct pginfo **mp;
+ void *vp;
+
+ /* Find the chunk number on the page */
+ i = ((u_long)ptr & malloc_pagemask) >> info->shift;
+
+ if (((u_long)ptr & (info->size - 1)))
+ {
+ wrtwarning("modified (chunk-) pointer.\n");
+ return;
+ }
+
+ if (info->bits[i / MALLOC_BITS] & (1 << (i % MALLOC_BITS)))
+ {
+ wrtwarning("chunk is already free.\n");
+ return;
+ }
+
+ if (malloc_junk)
+ {
+ memset(ptr, SOME_JUNK, info->size);
+ }
+
+ info->bits[i / MALLOC_BITS] |= 1 << (i % MALLOC_BITS);
+ info->free++;
+
+ mp = page_dir + info->shift;
+
+ if (info->free == 1)
+ {
+ /* Page became non-full */
+
+ mp = page_dir + info->shift;
+ /* Insert in address order */
+ while (*mp && (*mp)->next && (*mp)->next->page < info->page)
+ mp = &(*mp)->next;
+ info->next = *mp;
+ *mp = info;
+ return;
+ }
+
+ if (info->free != info->total)
+ {
+ return;
+ }
+
+ /* Find & remove this page in the queue */
+ while (*mp != info)
+ {
+ mp = &((*mp)->next);
+#ifdef EXTRA_SANITY
+ if (!*mp)
+ wrterror("(ES): Not on queue\n");
+#endif /* EXTRA_SANITY */
+ }
+ *mp = info->next;
+
+ /* Free the page & the info structure if need be */
+ page_dir[ptr2index(info->page)] = MALLOC_FIRST;
+ vp = info->page; /* Order is important ! */
+ if (vp != (void *)info)
+ {
+ ifree(info);
+ }
+ ifree(vp);
+}
+
+static void ifree(void *ptr)
+{
+ struct pginfo *info;
+ unsigned int index;
+
+ /* This is legal */
+ if (!ptr)
+ {
+ return;
+ }
+
+ if (!malloc_started)
+ {
+ wrtwarning("malloc() has never been called.\n");
+ return;
+ }
+
+ /* If we're already sinking, don't make matters any worse. */
+ if (suicide)
+ {
+ return;
+ }
+
+ index = ptr2index(ptr);
+
+ if (index < malloc_pageshift)
+ {
+ wrtwarning("junk pointer, too low to make sense.\n");
+ return;
+ }
+
+ if (index > last_index)
+ {
+ wrtwarning("junk pointer, too high to make sense.\n");
+ return;
+ }
+
+ info = page_dir[index];
+
+ if (info < MALLOC_MAGIC)
+ {
+ free_pages(ptr, index, info);
+ }
+ else
+ {
+ free_bytes(ptr, index, info);
+ }
+ return;
+}
+
+/*
+ * These are the public exported interface routines.
+ */
+
+void *malloc(size_t size)
+{
+ register void *r;
+
+ THREAD_LOCK();
+ malloc_func = " in malloc():";
+ if (malloc_active++)
+ {
+ wrtwarning("recursive call.\n");
+ malloc_active--;
+ return (0);
+ }
+ if (!malloc_started)
+ {
+ malloc_init();
+ }
+ if (malloc_sysv && !size)
+ {
+ r = 0;
+ }
+ else
+ {
+ r = imalloc(size);
+ }
+ UTRACE(0, size, r);
+ malloc_active--;
+ THREAD_UNLOCK();
+ if (malloc_xmalloc && !r)
+ {
+ wrterror("out of memory.\n");
+ }
+ return (r);
+}
+
+void free(void *ptr)
+{
+ THREAD_LOCK();
+ malloc_func = " in free():";
+ if (malloc_active++)
+ {
+ wrtwarning("recursive call.\n");
+ malloc_active--;
+ return;
+ }
+ else
+ {
+ ifree(ptr);
+ UTRACE(ptr, 0, 0);
+ }
+ malloc_active--;
+ THREAD_UNLOCK();
+ return;
+}
+
+void *realloc(void *ptr, size_t size)
+{
+ register void *r;
+
+ THREAD_LOCK();
+ malloc_func = " in realloc():";
+ if (malloc_active++)
+ {
+ wrtwarning("recursive call.\n");
+ malloc_active--;
+ return (0);
+ }
+ if (ptr && !malloc_started)
+ {
+ wrtwarning("malloc() has never been called.\n");
+ ptr = 0;
+ }
+ if (!malloc_started)
+ {
+ malloc_init();
+ }
+ if (malloc_sysv && !size)
+ {
+ ifree(ptr);
+ r = 0;
+ }
+ else if (!ptr)
+ {
+ r = imalloc(size);
+ }
+ else
+ {
+ r = irealloc(ptr, size);
+ }
+ UTRACE(ptr, size, r);
+ malloc_active--;
+ THREAD_UNLOCK();
+ if (malloc_xmalloc && !r)
+ {
+ wrterror("out of memory.\n");
+ }
+ return (r);
+}
+
+/* Added */
+void *calloc(size_t nelem, size_t elsize)
+{
+ void *tmp;
+ if (NULL == (tmp = malloc(nelem * elsize)))
+ {
+ return NULL;
+ }
+ else
+ {
+ memset(tmp, 0, nelem * elsize);
+ return tmp;
+ }
+}
diff --git a/user/lib/libc/printf.c b/user/lib/libc/printf.c
new file mode 100644
index 0000000..609ff37
--- /dev/null
+++ b/user/lib/libc/printf.c
@@ -0,0 +1,169 @@
+/*
+ ****************************************************************************
+ * (C) 2003 - Rolf Neugebauer - Intel Research Cambridge
+ ****************************************************************************
+ *
+ * File: printf.c
+ * Author: Rolf Neugebauer (neugebar@dcs.gla.ac.uk)
+ * Changes: Grzegorz Milos (gm281@cam.ac.uk)
+ *
+ * Date: Aug 2003, Aug 2005
+ *
+ * Environment: Xen Minimal OS
+ * Description: Library functions for printing
+ * (freebsd port, mainly sys/subr_prf.c)
+ *
+ ****************************************************************************
+ *
+ *-
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This software was developed by the Computer Systems Engineering group
+ * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
+ * contributed to Berkeley.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD: src/sys/libkern/divdi3.c,v 1.6 1999/08/28 00:46:31 peter Exp $
+ */
+
+#include "stdio.h"
+#include "unistd.h"
+
+int printf(const char *fmt, ...)
+{
+ va_list args;
+ int i;
+
+ va_start(args, fmt);
+ i = vprintf(fmt, args);
+ va_end(args);
+ return i;
+}
+
+int fprintf(FILE *stream, const char *fmt, ...)
+{
+ va_list args;
+ int i;
+
+ va_start(args, fmt);
+ i = vfprintf(stream, fmt, args);
+ va_end(args);
+ return i;
+}
+
+int sprintf(char *buf, const char *fmt, ...)
+{
+ va_list args;
+ int i;
+
+ va_start(args, fmt);
+ i = vsprintf(buf, fmt, args);
+ va_end(args);
+ return i;
+}
+
+int snprintf(char *buf, size_t size, const char *fmt, ...)
+{
+ va_list args;
+ int i;
+
+ va_start(args, fmt);
+ i = vsnprintf(buf, size, fmt, args);
+ va_end(args);
+ return i;
+}
+
+int vprintf(const char *fmt, va_list args)
+{
+ return vfprintf(stdout, fmt, args);
+}
+
+#define __LIBC_PRINTF_BUFSIZE 1024
+
+int vfprintf(FILE *stream, const char *fmt, va_list args)
+{
+ /* I'm really lazy */
+ char buf[__LIBC_PRINTF_BUFSIZE];
+ int ret = vsnprintf(buf, __LIBC_PRINTF_BUFSIZE, fmt, args);
+ if (ret > 0)
+ {
+ // write(stream->fd, buf, ret);
+
+#if 1
+ /* slow but simple */
+ for (int i = 0; i < ret; i++)
+ {
+ stream->buffer[stream->offset++] = buf[i];
+ if (stream->offset == sizeof(stream->buffer) || buf[i] == '\n')
+ {
+ // flush
+ fflush(stream);
+ }
+ }
+#endif
+ }
+ return ret;
+}
+
+int vsprintf(char *buf, const char *fmt, va_list args)
+{
+ return vsnprintf(buf, 0xffffffffUL, fmt, args);
+}
+
+void __do_fflush(FILE *stream)
+{
+ if (!stream)
+ {
+ return;
+ }
+
+ if (stream->offset > 0)
+ {
+ write(stream->fd, stream->buffer, stream->offset);
+ stream->offset = 0;
+ }
+}
+
+int fflush(FILE *stream)
+{
+ if (!stream)
+ {
+ __do_fflush(stdin);
+ __do_fflush(stdout);
+ __do_fflush(stderr);
+ }
+ else
+ {
+ __do_fflush(stream);
+ }
+
+ return 0;
+}
diff --git a/user/lib/libc/quad.c b/user/lib/libc/quad.c
new file mode 100644
index 0000000..2cf944c
--- /dev/null
+++ b/user/lib/libc/quad.c
@@ -0,0 +1,414 @@
+/* Arithmetic with 64-bit integers. This is not supported natively */
+
+/* -*- Mode:C; c-basic-offset:4; tab-width:4 -*-
+ ****************************************************************************
+ * (C) 2003 - Rolf Neugebauer - Intel Research Cambridge
+ ****************************************************************************
+ *
+ * File: math.c
+ * Author: Rolf Neugebauer (neugebar@dcs.gla.ac.uk)
+ * Changes:
+ *
+ * Date: Aug 2003
+ *
+ * Environment: Xen Minimal OS
+ * Description: Library functions for 64bit arith and other
+ * from freebsd, files in sys/libkern/ (qdivrem.c, etc)
+ *
+ ****************************************************************************
+ * $Id: c-insert.c,v 1.7 2002/11/08 16:04:34 rn Exp $
+ ****************************************************************************
+ *-
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This software was developed by the Computer Systems Engineering group
+ * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
+ * contributed to Berkeley.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD: src/sys/libkern/divdi3.c,v 1.6 1999/08/28 00:46:31 peter Exp $
+ */
+
+/*
+ * Depending on the desired operation, we view a `long long' (aka quad_t) in
+ * one or more of the following formats.
+ */
+union uu {
+ long long q; /* as a (signed) quad */
+ long long uq; /* as an unsigned quad */
+ long sl[2]; /* as two signed longs */
+ unsigned long ul[2]; /* as two unsigned longs */
+};
+/* XXX RN: Yuck hardcoded endianess :) */
+#define _QUAD_HIGHWORD 1
+#define _QUAD_LOWWORD 0
+/*
+ * Define high and low longwords.
+ */
+#define H _QUAD_HIGHWORD
+#define L _QUAD_LOWWORD
+
+/*
+ * Total number of bits in a quad_t and in the pieces that make it up.
+ * These are used for shifting, and also below for halfword extraction
+ * and assembly.
+ */
+#define CHAR_BIT 8 /* number of bits in a char */
+#define QUAD_BITS (sizeof(long long) * CHAR_BIT)
+#define LONG_BITS (sizeof(long) * CHAR_BIT)
+#define HALF_BITS (sizeof(long) * CHAR_BIT / 2)
+
+/*
+ * Extract high and low shortwords from longword, and move low shortword of
+ * longword to upper half of long, i.e., produce the upper longword of
+ * ((quad_t)(x) << (number_of_bits_in_long/2)). (`x' must actually be u_long.)
+ *
+ * These are used in the multiply code, to split a longword into upper
+ * and lower halves, and to reassemble a product as a quad_t, shifted left
+ * (sizeof(long)*CHAR_BIT/2).
+ */
+#define HHALF(x) ((x) >> HALF_BITS)
+#define LHALF(x) ((x) & ((1UL << HALF_BITS) - 1))
+#define LHUP(x) ((x) << HALF_BITS)
+
+/*
+ * Multiprecision divide. This algorithm is from Knuth vol. 2 (2nd ed),
+ * section 4.3.1, pp. 257--259.
+ */
+#define B (1UL << HALF_BITS) /* digit base */
+
+/* Combine two `digits' to make a single two-digit number. */
+#define COMBINE(a, b) (((unsigned long)(a) << HALF_BITS) | (b))
+
+/* select a type for digits in base B: use unsigned short if they fit */
+/* #if ULONG_MAX == 0xffffffff && USHORT_MAX >= 0xffff
+typedef unsigned short digit;
+#else */
+typedef unsigned long digit;
+/* #endif */
+
+/*
+ * Shift p[0]..p[len] left `sh' bits, ignoring any bits that
+ * `fall out' the left (there never will be any such anyway).
+ * We may assume len >= 0. NOTE THAT THIS WRITES len+1 DIGITS.
+ */
+static void shl(register digit *p, register int len, register int sh)
+{
+ register int i;
+
+ for (i = 0; i < len; i++)
+ {
+ p[i] = LHALF(p[i] << sh) | (p[i + 1] >> (HALF_BITS - sh));
+ }
+ p[i] = LHALF(p[i] << sh);
+}
+
+/*
+ * __qdivrem(u, v, rem) returns u/v and, optionally, sets *rem to u%v.
+ *
+ * We do this in base 2-sup-HALF_BITS, so that all intermediate products
+ * fit within u_long. As a consequence, the maximum length dividend and
+ * divisor are 4 `digits' in this base (they are shorter if they have
+ * leading zeros).
+ */
+unsigned long long __qdivrem(unsigned long long uq, unsigned long long vq,
+ unsigned long long *arq)
+{
+ union uu tmp = {.q = 0};
+ digit *u, *v, *q;
+ register digit v1, v2;
+ unsigned long qhat, rhat, t;
+ int m, n, d, j, i;
+ digit uspace[5], vspace[5], qspace[5];
+
+ /*
+ * Take care of special cases: divide by zero, and u < v.
+ */
+ if (vq == 0)
+ {
+ /* divide by zero. */
+ static volatile const unsigned int zero = 0;
+
+ tmp.ul[H] = tmp.ul[L] = 1 / zero;
+ if (arq)
+ {
+ *arq = uq;
+ }
+ return (tmp.q);
+ }
+ if (uq < vq)
+ {
+ if (arq)
+ {
+ *arq = uq;
+ }
+ return (0);
+ }
+ u = &uspace[0];
+ v = &vspace[0];
+ q = &qspace[0];
+
+ /*
+ * Break dividend and divisor into digits in base B, then
+ * count leading zeros to determine m and n. When done, we
+ * will have:
+ * u = (u[1]u[2]...u[m+n]) sub B
+ * v = (v[1]v[2]...v[n]) sub B
+ * v[1] != 0
+ * 1 < n <= 4 (if n = 1, we use a different division algorithm)
+ * m >= 0 (otherwise u < v, which we already checked)
+ * m + n = 4
+ * and thus
+ * m = 4 - n <= 2
+ */
+ tmp.uq = uq;
+ u[0] = 0;
+ u[1] = HHALF(tmp.ul[H]);
+ u[2] = LHALF(tmp.ul[H]);
+ u[3] = HHALF(tmp.ul[L]);
+ u[4] = LHALF(tmp.ul[L]);
+ tmp.uq = vq;
+ v[1] = HHALF(tmp.ul[H]);
+ v[2] = LHALF(tmp.ul[H]);
+ v[3] = HHALF(tmp.ul[L]);
+ v[4] = LHALF(tmp.ul[L]);
+ for (n = 4; v[1] == 0; v++)
+ {
+ if (--n == 1)
+ {
+ unsigned long rbj; /* r*B+u[j] (not root boy jim) */
+ digit q1, q2, q3, q4;
+
+ /*
+ * Change of plan, per exercise 16.
+ * r = 0;
+ * for j = 1..4:
+ * q[j] = floor((r*B + u[j]) / v),
+ * r = (r*B + u[j]) % v;
+ * We unroll this completely here.
+ */
+ t = v[2]; /* nonzero, by definition */
+ q1 = u[1] / t;
+ rbj = COMBINE(u[1] % t, u[2]);
+ q2 = rbj / t;
+ rbj = COMBINE(rbj % t, u[3]);
+ q3 = rbj / t;
+ rbj = COMBINE(rbj % t, u[4]);
+ q4 = rbj / t;
+ if (arq)
+ {
+ *arq = rbj % t;
+ }
+ tmp.ul[H] = COMBINE(q1, q2);
+ tmp.ul[L] = COMBINE(q3, q4);
+ return (tmp.q);
+ }
+ }
+
+ /*
+ * By adjusting q once we determine m, we can guarantee that
+ * there is a complete four-digit quotient at &qspace[1] when
+ * we finally stop.
+ */
+ for (m = 4 - n; u[1] == 0; u++)
+ {
+ m--;
+ }
+ for (i = 4 - m; --i >= 0;)
+ {
+ q[i] = 0;
+ }
+ q += 4 - m;
+
+ /*
+ * Here we run Program D, translated from MIX to C and acquiring
+ * a few minor changes.
+ *
+ * D1: choose multiplier 1 << d to ensure v[1] >= B/2.
+ */
+ d = 0;
+ for (t = v[1]; t < B / 2; t <<= 1)
+ {
+ d++;
+ }
+ if (d > 0)
+ {
+ shl(&u[0], m + n, d); /* u <<= d */
+ shl(&v[1], n - 1, d); /* v <<= d */
+ }
+ /*
+ * D2: j = 0.
+ */
+ j = 0;
+ v1 = v[1]; /* for D3 -- note that v[1..n] are constant */
+ v2 = v[2]; /* for D3 */
+ do
+ {
+ register digit uj0, uj1, uj2;
+
+ /*
+ * D3: Calculate qhat (\^q, in TeX notation).
+ * Let qhat = min((u[j]*B + u[j+1])/v[1], B-1), and
+ * let rhat = (u[j]*B + u[j+1]) mod v[1].
+ * While rhat < B and v[2]*qhat > rhat*B+u[j+2],
+ * decrement qhat and increase rhat correspondingly.
+ * Note that if rhat >= B, v[2]*qhat < rhat*B.
+ */
+ uj0 = u[j + 0]; /* for D3 only -- note that u[j+...] change */
+ uj1 = u[j + 1]; /* for D3 only */
+ uj2 = u[j + 2]; /* for D3 only */
+ if (uj0 == v1)
+ {
+ qhat = B;
+ rhat = uj1;
+ goto qhat_too_big;
+ }
+ else
+ {
+ unsigned long nn = COMBINE(uj0, uj1);
+ qhat = nn / v1;
+ rhat = nn % v1;
+ }
+ while (v2 * qhat > COMBINE(rhat, uj2))
+ {
+ qhat_too_big:
+ qhat--;
+ if ((rhat += v1) >= B)
+ {
+ break;
+ }
+ }
+ /*
+ * D4: Multiply and subtract.
+ * The variable `t' holds any borrows across the loop.
+ * We split this up so that we do not require v[0] = 0,
+ * and to eliminate a final special case.
+ */
+ for (t = 0, i = n; i > 0; i--)
+ {
+ t = u[i + j] - v[i] * qhat - t;
+ u[i + j] = LHALF(t);
+ t = (B - HHALF(t)) & (B - 1);
+ }
+ t = u[j] - t;
+ u[j] = LHALF(t);
+ /*
+ * D5: test remainder.
+ * There is a borrow if and only if HHALF(t) is nonzero;
+ * in that (rare) case, qhat was too large (by exactly 1).
+ * Fix it by adding v[1..n] to u[j..j+n].
+ */
+ if (HHALF(t))
+ {
+ qhat--;
+ for (t = 0, i = n; i > 0; i--)
+ { /* D6: add back. */
+ t += u[i + j] + v[i];
+ u[i + j] = LHALF(t);
+ t = HHALF(t);
+ }
+ u[j] = LHALF(u[j] + t);
+ }
+ q[j] = qhat;
+ } while (++j <= m); /* D7: loop on j. */
+
+ /*
+ * If caller wants the remainder, we have to calculate it as
+ * u[m..m+n] >> d (this is at most n digits and thus fits in
+ * u[m+1..m+n], but we may need more source digits).
+ */
+ if (arq)
+ {
+ if (d)
+ {
+ for (i = m + n; i > m; --i)
+ {
+ u[i] = (u[i] >> d) | LHALF(u[i - 1] << (HALF_BITS - d));
+ }
+ u[i] = 0;
+ }
+ tmp.ul[H] = COMBINE(uspace[1], uspace[2]);
+ tmp.ul[L] = COMBINE(uspace[3], uspace[4]);
+ *arq = tmp.q;
+ }
+
+ tmp.ul[H] = COMBINE(qspace[1], qspace[2]);
+ tmp.ul[L] = COMBINE(qspace[3], qspace[4]);
+ return (tmp.q);
+}
+
+/*
+ * Divide two signed quads.
+ * ??? if -1/2 should produce -1 on this machine, this code is wrong
+ */
+long long __divdi3(long long a, long long b)
+{
+ unsigned long long ua, ub, uq;
+ int neg;
+
+ if (a < 0)
+ {
+ ua = -(unsigned long long)a, neg = 1;
+ }
+ else
+ {
+ ua = a, neg = 0;
+ }
+ if (b < 0)
+ {
+ ub = -(unsigned long long)b, neg ^= 1;
+ }
+ else
+ {
+ ub = b;
+ }
+ uq = __qdivrem(ua, ub, (unsigned long long *)0);
+ return (neg ? -uq : uq);
+}
+
+/*
+ * Divide two unsigned quads.
+ */
+unsigned long long __udivdi3(unsigned long long a, unsigned long long b)
+{
+ return (__qdivrem(a, b, (unsigned long long *)0));
+}
+
+/*
+ * Return remainder after dividing two unsigned quads.
+ */
+unsigned long long __umoddi3(unsigned long long a, unsigned long long b)
+{
+ unsigned long long r;
+
+ (void)__qdivrem(a, b, &r);
+ return (r);
+}
diff --git a/user/lib/libc/rand.c b/user/lib/libc/rand.c
new file mode 100644
index 0000000..711ae8e
--- /dev/null
+++ b/user/lib/libc/rand.c
@@ -0,0 +1,22 @@
+#include <stdlib.h>
+
+/* Random int between lo and hi inclusive */
+
+/* TODO Fix the rand/srand implementation to use the implementation in the
+ * (unused) macro which actually has decent pseudo-randomness properties. (No,
+ * you can't just change the mod base and expect it to still work fine...) */
+
+#define RANDOM(lo, hi) \
+ ((lo) + \
+ (((hi) - (lo) + 1) * (randseed = (randseed * 4096 + 150889) % 714025)) / \
+ 714025)
+
+static unsigned long long randseed = 123456L;
+
+int rand(void)
+{
+ randseed = (randseed * 4096 + 150889) % RAND_MAX;
+ return randseed;
+}
+
+void srand(unsigned int seed) { randseed = seed; }
diff --git a/user/lib/libc/scanf.c b/user/lib/libc/scanf.c
new file mode 100644
index 0000000..c7faf27
--- /dev/null
+++ b/user/lib/libc/scanf.c
@@ -0,0 +1,73 @@
+/*
+ ****************************************************************************
+ * (C) 2003 - Rolf Neugebauer - Intel Research Cambridge
+ ****************************************************************************
+ *
+ * File: printf.c
+ * Author: Rolf Neugebauer (neugebar@dcs.gla.ac.uk)
+ * Changes: Grzegorz Milos (gm281@cam.ac.uk)
+ *
+ * Date: Aug 2003, Aug 2005
+ *
+ * Environment: Xen Minimal OS
+ * Description: Library functions for printing
+ * (freebsd port, mainly sys/subr_prf.c)
+ *
+ ****************************************************************************
+ *
+ *-
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This software was developed by the Computer Systems Engineering group
+ * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
+ * contributed to Berkeley.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD: src/sys/libkern/divdi3.c,v 1.6 1999/08/28 00:46:31 peter Exp $
+ */
+#include "stdio.h"
+
+/**
+ * sscanf - Unformat a buffer into a list of arguments
+ * @buf: input buffer
+ * @fmt: formatting of buffer
+ * @...: resulting arguments
+ */
+int sscanf(const char *buf, const char *fmt, ...)
+{
+ va_list args;
+ int i;
+
+ va_start(args, fmt);
+ i = vsscanf(buf, fmt, args);
+ va_end(args);
+ return i;
+}
diff --git a/user/lib/libc/stream.c b/user/lib/libc/stream.c
new file mode 100644
index 0000000..049ee4e
--- /dev/null
+++ b/user/lib/libc/stream.c
@@ -0,0 +1,11 @@
+#include "stdio.h"
+
+static FILE stdstreams[3] = {
+ {.fd = 0, .offset = 0},
+ {.fd = 1, .offset = 0},
+ {.fd = 2, .offset = 0},
+};
+
+FILE *stdin = &stdstreams[0];
+FILE *stdout = &stdstreams[1];
+FILE *stderr = &stdstreams[2];
diff --git a/user/lib/libc/string.c b/user/lib/libc/string.c
new file mode 100644
index 0000000..ae3042d
--- /dev/null
+++ b/user/lib/libc/string.c
@@ -0,0 +1,509 @@
+#include "string.h"
+#include "errno.h"
+#include "sys/types.h"
+#include <stdlib.h>
+
+int memcmp(const void *cs, const void *ct, size_t count)
+{
+ const unsigned char *su1, *su2;
+ signed char res = 0;
+
+ for (su1 = cs, su2 = ct; 0 < count; ++su1, ++su2, count--)
+ {
+ if ((res = *su1 - *su2) != 0)
+ {
+ break;
+ }
+ }
+ return res;
+}
+
+void *memcpy(void *dest, const void *src, size_t count)
+{
+ char *tmp = (char *)dest;
+ const char *s = src;
+
+ while (count--)
+ *tmp++ = *s++;
+
+ return dest;
+}
+
+int strncmp(const char *cs, const char *ct, size_t count)
+{
+ register signed char __res = 0;
+
+ while (count)
+ {
+ if ((__res = *cs - *ct++) != 0 || !*cs++)
+ {
+ break;
+ }
+ count--;
+ }
+
+ return __res;
+}
+
+int strcmp(const char *cs, const char *ct)
+{
+ register signed char __res;
+
+ while (1)
+ {
+ if ((__res = *cs - *ct++) != 0 || !*cs++)
+ {
+ break;
+ }
+ }
+
+ return __res;
+}
+
+char *strcpy(char *dest, const char *src)
+{
+ char *tmp = dest;
+
+ while ((*dest++ = *src++) != '\0') /* nothing */
+ ;
+ return tmp;
+}
+
+char *strncpy(char *dest, const char *src, size_t count)
+{
+ char *tmp = dest;
+
+ while (count)
+ {
+ if ((*dest = *src) != 0)
+ src++;
+ dest++;
+ count--;
+ }
+
+ return tmp;
+}
+
+void *memset(void *s, int c, size_t count)
+{
+ char *xs = (char *)s;
+
+ while (count--)
+ *xs++ = c;
+
+ return s;
+}
+
+size_t strnlen(const char *s, size_t count)
+{
+ const char *sc;
+
+ for (sc = s; count-- && *sc != '\0'; ++sc)
+ {
+ /* nothing */}
+ return sc - s;
+}
+
+char *strcat(char *dest, const char *src)
+{
+ char *tmp = dest;
+
+ while (*dest)
+ dest++;
+
+ while ((*dest++ = *src++) != '\0')
+ ;
+
+ return tmp;
+}
+
+size_t strlen(const char *s)
+{
+ const char *sc;
+
+ for (sc = s; *sc != '\0'; ++sc)
+ {
+ /* nothing */}
+ return sc - s;
+}
+
+char *strchr(const char *s, int c)
+{
+ for (; *s != (char)c; ++s)
+ {
+ if (*s == '\0')
+ {
+ return NULL;
+ }
+ }
+ return (char *)s;
+}
+
+char *strrchr(const char *s, int c)
+{
+ char *r = NULL;
+ for (; *s; ++s)
+ {
+ if (*s == (char)c)
+ {
+ r = (char *)s;
+ }
+ }
+ return r;
+}
+
+char *strstr(const char *s1, const char *s2)
+{
+ int l1, l2;
+
+ l2 = strlen(s2);
+ if (!l2)
+ {
+ return (char *)s1;
+ }
+ l1 = strlen(s1);
+ while (l1 >= l2)
+ {
+ l1--;
+ if (!memcmp(s1, s2, l2))
+ {
+ return (char *)s1;
+ }
+ s1++;
+ }
+ return NULL;
+}
+
+char *strdup(const char *s)
+{
+ size_t len = strlen(s) + 1;
+ char *str = (char *)malloc(len);
+ memcpy(str, s, len);
+ return str;
+}
+
+/*
+ * The following three functions were ripped out of OpenSolaris. Legally, they
+ * might have to be in a separate file. Leaving it here out of laziness.
+ * Got this from /onnv-gate/usr/src/common/uti/string.c.
+ */
+
+char *strpbrk(const char *string, const char *brkset)
+{
+ const char *p;
+
+ do
+ {
+ for (p = brkset; *p != '\0' && *p != *string; ++p)
+ ;
+ if (*p != '\0')
+ {
+ return ((char *)string);
+ }
+ } while (*string++);
+
+ return (NULL);
+}
+
+size_t strspn(const char *string, const char *charset)
+{
+ const char *p, *q;
+
+ for (q = string; *q != '\0'; ++q)
+ {
+ for (p = charset; *p != '\0' && *p != *q; ++p)
+ ;
+ if (*p == '\0')
+ {
+ break;
+ }
+ }
+
+ return (q - string);
+}
+
+char *strtok(char *string, const char *sepset)
+{
+ char *p, *q, *r;
+ static char *savept;
+
+ /*
+ * Set `p' to our current location in the string.
+ */
+ p = (string == NULL) ? savept : string;
+ if (p == NULL)
+ {
+ return (NULL);
+ }
+
+ /*
+ * Skip leading separators; bail if no tokens remain.
+ */
+ q = p + strspn(p, sepset);
+ if (*q == '\0')
+ {
+ return (NULL);
+ }
+
+ /*
+ * Mark the end of the token and set `savept' for the next iteration.
+ */
+ if ((r = strpbrk(q, sepset)) == NULL)
+ {
+ savept = NULL;
+ }
+ else
+ {
+ *r = '\0';
+ savept = ++r;
+ }
+
+ return (q);
+}
+
+/* created with the help of:
+ * perl -p -e 's/#define\s+(\w+)\s+\d+\s+\/\* ([^\t\*]+)\s*\*\/\s*$/case $1:
+ * return "$2";\n/' < /usr/include/sys/errno.h
+ */
+char *strerror(int errnum)
+{
+ switch (errnum)
+ {
+ case EPERM:
+ return "Not super-user";
+ case ENOENT:
+ return "No such file or directory";
+ case ESRCH:
+ return "No such process";
+ case EINTR:
+ return "interrupted system call";
+ case EIO:
+ return "I/O error";
+ case ENXIO:
+ return "No such device or address";
+ case E2BIG:
+ return "Arg list too long";
+ case ENOEXEC:
+ return "Exec format error";
+ case EBADF:
+ return "Bad file number";
+ case ECHILD:
+ return "No children";
+ case EAGAIN:
+ return "Resource temporarily unavailable";
+ case ENOMEM:
+ return "Not enough core";
+ case EACCES:
+ return "Permission denied";
+ case EFAULT:
+ return "Bad address";
+ case ENOTBLK:
+ return "Block device required";
+ case EBUSY:
+ return "Mount device busy";
+ case EEXIST:
+ return "File exists";
+ case EXDEV:
+ return "Cross-device link";
+ case ENODEV:
+ return "No such device";
+ case ENOTDIR:
+ return "Not a directory";
+ case EISDIR:
+ return "Is a directory";
+ case EINVAL:
+ return "Invalid argument";
+ case ENFILE:
+ return "File table overflow";
+ case EMFILE:
+ return "Too many open files";
+ case ENOTTY:
+ return "Inappropriate ioctl for device";
+ case ETXTBSY:
+ return "Text file busy";
+ case EFBIG:
+ return "File too large";
+ case ENOSPC:
+ return "No space left on device";
+ case ESPIPE:
+ return "Illegal seek";
+ case EROFS:
+ return "Read only file system";
+ case EMLINK:
+ return "Too many links";
+ case EPIPE:
+ return "Broken pipe";
+ case EDOM:
+ return "Math arg out of domain of func";
+ case ERANGE:
+ return "Math result not representable";
+ case ENOMSG:
+ return "No message of desired type";
+ case EIDRM:
+ return "Identifier removed";
+ case ECHRNG:
+ return "Channel number out of range";
+ case EL2NSYNC:
+ return "Level 2 not synchronized";
+ case EL3HLT:
+ return "Level 3 halted";
+ case EL3RST:
+ return "Level 3 reset";
+ case ELNRNG:
+ return "Link number out of range";
+ case EUNATCH:
+ return "Protocol driver not attached";
+ case ENOCSI:
+ return "No CSI structure available";
+ case EL2HLT:
+ return "Level 2 halted";
+ case EDEADLK:
+ return "Deadlock condition.";
+ case ENOLCK:
+ return "No record locks available.";
+ case ECANCELED:
+ return "Operation canceled";
+ case ENOTSUP:
+ return "Operation not supported";
+ case EDQUOT:
+ return "Disc quota exceeded";
+ case EBADE:
+ return "invalid exchange";
+ case EBADR:
+ return "invalid request descriptor";
+ case EXFULL:
+ return "exchange full";
+ case ENOANO:
+ return "no anode";
+ case EBADRQC:
+ return "invalid request code";
+ case EBADSLT:
+ return "invalid slot";
+ case EBFONT:
+ return "bad font file fmt";
+ case EOWNERDEAD:
+ return "process died with the lock";
+ case ENOTRECOVERABLE:
+ return "lock is not recoverable";
+ case ENOSTR:
+ return "Device not a stream";
+ case ENODATA:
+ return "no data (for no delay io)";
+ case ETIME:
+ return "timer expired";
+ case ENOSR:
+ return "out of streams resources";
+ case ENONET:
+ return "Machine is not on the network";
+ case ENOPKG:
+ return "Package not installed";
+ case EREMOTE:
+ return "The object is remote";
+ case ENOLINK:
+ return "the link has been severed";
+ case EADV:
+ return "advertise error";
+ case ESRMNT:
+ return "srmount error";
+ case ECOMM:
+ return "Communication error on send";
+ case EPROTO:
+ return "Protocol error";
+ case EMULTIHOP:
+ return "multihop attempted";
+ case EBADMSG:
+ return "trying to read unreadable message";
+ case ENAMETOOLONG:
+ return "path name is too long";
+ case EOVERFLOW:
+ return "value too large to be stored in data type";
+ case ENOTUNIQ:
+ return "given log. name not unique";
+ case EBADFD:
+ return "f.d. invalid for this operation";
+ case EREMCHG:
+ return "Remote address changed";
+ case ELIBACC:
+ return "Can't access a needed shared lib.";
+ case ELIBBAD:
+ return "Accessing a corrupted shared lib.";
+ case ELIBSCN:
+ return ".lib section in a.out corrupted.";
+ case ELIBMAX:
+ return "Attempting to link in too many libs.";
+ case ELIBEXEC:
+ return "Attempting to exec a shared library.";
+ case EILSEQ:
+ return "Illegal byte sequence.";
+ case ENOSYS:
+ return "Unsupported file system operation";
+ case ELOOP:
+ return "Symbolic link loop";
+ case ERESTART:
+ return "Restartable system call";
+ case ESTRPIPE:
+ return "if pipe/FIFO, don't sleep in stream head";
+ case ENOTEMPTY:
+ return "directory not empty";
+ case EUSERS:
+ return "Too many users (for UFS)";
+ case ENOTSOCK:
+ return "Socket operation on non-socket";
+ case EDESTADDRREQ:
+ return "Destination address required";
+ case EMSGSIZE:
+ return "Message too long";
+ case EPROTOTYPE:
+ return "Protocol wrong type for socket";
+ case ENOPROTOOPT:
+ return "Protocol not available";
+ case EPROTONOSUPPORT:
+ return "Protocol not supported";
+ case ESOCKTNOSUPPORT:
+ return "Socket type not supported";
+ case EPFNOSUPPORT:
+ return "Protocol family not supported";
+ case EAFNOSUPPORT:
+ return "Address family not supported by protocol family";
+ case EADDRINUSE:
+ return "Address already in use";
+ case EADDRNOTAVAIL:
+ return "Can't assign requested address";
+ case ENETDOWN:
+ return "Network is down";
+ case ENETUNREACH:
+ return "Network is unreachable";
+ case ENETRESET:
+ return "Network dropped connection because of reset";
+ case ECONNABORTED:
+ return "Software caused connection abort";
+ case ECONNRESET:
+ return "Connection reset by peer";
+ case ENOBUFS:
+ return "No buffer space available";
+ case EISCONN:
+ return "Socket is already connected";
+ case ENOTCONN:
+ return "Socket is not connected";
+ case ESHUTDOWN:
+ return "Can't send after socket shutdown";
+ case ETOOMANYREFS:
+ return "Too many references: can't splice";
+ case ETIMEDOUT:
+ return "Connection timed out";
+ case ECONNREFUSED:
+ return "Connection refused";
+ case EHOSTDOWN:
+ return "Host is down";
+ case EHOSTUNREACH:
+ return "No route to host";
+ case EALREADY:
+ return "operation already in progress";
+ case EINPROGRESS:
+ return "operation now in progress";
+ case ESTALE:
+ return "Stale NFS file handle";
+ default:
+ return 0;
+ }
+}
diff --git a/user/lib/libc/strtol.c b/user/lib/libc/strtol.c
new file mode 100644
index 0000000..f33a3ae
--- /dev/null
+++ b/user/lib/libc/strtol.c
@@ -0,0 +1,162 @@
+/*-
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <ctype.h>
+#include <errno.h>
+#include <limits.h>
+#include <stdlib.h>
+
+/*
+ * Convert a string to a long integer.
+ *
+ * Assumes that the upper and lower case
+ * alphabets and digits are each contiguous.
+ */
+long strtol(const char *__restrict nptr, char **__restrict endptr, int base)
+{
+ const char *s;
+ unsigned long acc;
+ char c;
+ unsigned long cutoff;
+ int neg, any, cutlim;
+
+ /*
+ * Skip white space and pick up leading +/- sign if any.
+ * If base is 0, allow 0x for hex and 0 for octal, else
+ * assume decimal; if base is already 16, allow 0x.
+ */
+ s = nptr;
+ do
+ {
+ c = *s++;
+ } while (isspace((unsigned char)c));
+ if (c == '-')
+ {
+ neg = 1;
+ c = *s++;
+ }
+ else
+ {
+ neg = 0;
+ if (c == '+')
+ {
+ c = *s++;
+ }
+ }
+ if ((base == 0 || base == 16) && c == '0' && (*s == 'x' || *s == 'X') &&
+ ((s[1] >= '0' && s[1] <= '9') || (s[1] >= 'A' && s[1] <= 'F') ||
+ (s[1] >= 'a' && s[1] <= 'f')))
+ {
+ c = s[1];
+ s += 2;
+ base = 16;
+ }
+ if (base == 0)
+ {
+ base = c == '0' ? 8 : 10;
+ }
+ acc = any = 0;
+ if (base < 2 || base > 36)
+ {
+ goto noconv;
+ }
+
+ /*
+ * Compute the cutoff value between legal numbers and illegal
+ * numbers. That is the largest legal value, divided by the
+ * base. An input number that is greater than this value, if
+ * followed by a legal input character, is too big. One that
+ * is equal to this value may be valid or not; the limit
+ * between valid and invalid numbers is then based on the last
+ * digit. For instance, if the range for longs is
+ * [-2147483648..2147483647] and the input base is 10,
+ * cutoff will be set to 214748364 and cutlim to either
+ * 7 (neg==0) or 8 (neg==1), meaning that if we have accumulated
+ * a value > 214748364, or equal but the next digit is > 7 (or 8),
+ * the number is too big, and we will return a range error.
+ *
+ * Set 'any' if any `digits' consumed; make it negative to indicate
+ * overflow.
+ */
+ cutoff = neg ? (unsigned long)-(LONG_MIN + LONG_MAX) + LONG_MAX : LONG_MAX;
+ cutlim = cutoff % base;
+ cutoff /= base;
+ for (;; c = *s++)
+ {
+ if (c >= '0' && c <= '9')
+ {
+ c -= '0';
+ }
+ else if (c >= 'A' && c <= 'Z')
+ {
+ c -= 'A' - 10;
+ }
+ else if (c >= 'a' && c <= 'z')
+ {
+ c -= 'a' - 10;
+ }
+ else
+ {
+ break;
+ }
+ if (c >= base)
+ {
+ break;
+ }
+ if (any < 0 || acc > cutoff || (acc == cutoff && c > cutlim))
+ {
+ any = -1;
+ }
+ else
+ {
+ any = 1;
+ acc *= base;
+ acc += c;
+ }
+ }
+ if (any < 0)
+ {
+ acc = neg ? LONG_MIN : LONG_MAX;
+ errno = ERANGE;
+ }
+ else if (!any)
+ {
+ noconv:
+ errno = EINVAL;
+ }
+ else if (neg)
+ {
+ acc = -acc;
+ }
+ if (endptr != NULL)
+ {
+ *endptr = (char *)(any ? s - 1 : nptr);
+ }
+ return (acc);
+}
diff --git a/user/lib/libc/syscall.c b/user/lib/libc/syscall.c
new file mode 100644
index 0000000..3d921d1
--- /dev/null
+++ b/user/lib/libc/syscall.c
@@ -0,0 +1,391 @@
+#include "sys/types.h"
+
+#include "stdlib.h"
+#include "string.h"
+#include "unistd.h"
+
+#include "stdio.h"
+#include "weenix/trap.h"
+
+#include "dirent.h"
+
+static void *__curbrk = NULL;
+#define MAX_EXIT_HANDLERS 32
+
+static void (*atexit_func[MAX_EXIT_HANDLERS])();
+
+static int atexit_handlers = 0;
+
+void *sbrk(intptr_t incr)
+{
+ uintptr_t oldbrk;
+
+ /* If we don't have a saved break, find it from the kernel */
+ if (!__curbrk)
+ {
+ if (0 > (long)(__curbrk = (void *)trap(SYS_brk, (uintptr_t)NULL)))
+ {
+ return (void *)-1;
+ }
+ }
+
+ oldbrk = (uintptr_t)__curbrk;
+
+ /* Increment or decrement the saved break */
+
+ if (incr < 0)
+ {
+ if ((uintptr_t)-incr > oldbrk)
+ {
+ return (void *)-1;
+ }
+ else if (brk((void *)(oldbrk - (uintptr_t)-incr)) < 0)
+ {
+ return (void *)-1;
+ }
+ }
+ else if (incr > 0)
+ {
+ if (brk((void *)(oldbrk + (uintptr_t)incr)) < 0)
+ {
+ return (void *)-1;
+ }
+ }
+ return (void *)oldbrk;
+}
+
+int brk(void *addr)
+{
+ if (NULL == addr)
+ {
+ return -1;
+ }
+ void *newbrk = (void *)trap(SYS_brk, (uintptr_t)addr);
+ if (newbrk == (void *)-1)
+ {
+ return -1;
+ }
+ __curbrk = newbrk;
+ return 0;
+}
+
+pid_t fork(void) { return (pid_t)trap(SYS_fork, 0); }
+
+int atexit(void (*func)(void))
+{
+ if (atexit_handlers < MAX_EXIT_HANDLERS)
+ {
+ atexit_func[atexit_handlers++] = func;
+ return 0;
+ }
+
+ return 1;
+}
+
+__attribute__((noreturn)) void exit(int status)
+{
+ while (atexit_handlers--)
+ {
+ atexit_func[atexit_handlers]();
+ }
+
+ fflush(NULL);
+ trap(SYS_exit, (ssize_t)status);
+ __builtin_unreachable();
+}
+
+void _Exit(int status)
+{
+ trap(SYS_exit, (ssize_t)status);
+ __builtin_unreachable();
+}
+
+int sched_yield(void) { return (int)trap(SYS_sched_yield, NULL); }
+
+pid_t wait(int *status)
+{
+ waitpid_args_t args;
+
+ args.wpa_pid = -1;
+ args.wpa_options = 0;
+ args.wpa_status = status;
+
+ return (int)trap(SYS_waitpid, (uintptr_t)&args);
+}
+
+pid_t waitpid(pid_t pid, int *status, int options)
+{
+ waitpid_args_t args;
+
+ args.wpa_pid = pid;
+ args.wpa_status = status;
+ args.wpa_options = options;
+
+ return (int)trap(SYS_waitpid, (uintptr_t)&args);
+}
+
+void thr_exit(int status) { trap(SYS_thr_exit, (ssize_t)status); }
+
+pid_t getpid(void) { return (int)trap(SYS_getpid, 0); }
+
+int halt(void) { return (int)trap(SYS_halt, 0); }
+
+void *mmap(void *addr, size_t len, int prot, int flags, int fd, off_t off)
+{
+ mmap_args_t args;
+
+ args.mma_addr = addr;
+ args.mma_len = len;
+ args.mma_prot = prot;
+ args.mma_flags = flags;
+ args.mma_fd = fd;
+ args.mma_off = off;
+
+ return (void *)trap(SYS_mmap, (uintptr_t)&args);
+}
+
+int munmap(void *addr, size_t len)
+{
+ munmap_args_t args;
+
+ args.addr = addr;
+ args.len = len;
+
+ return (int)trap(SYS_munmap, (uintptr_t)&args);
+}
+
+int debug(const char *str)
+{
+ argstr_t argstr;
+ argstr.as_len = strlen(str);
+ argstr.as_str = str;
+ return (int)trap(SYS_debug, (uintptr_t)&argstr);
+}
+
+void sync(void) { trap(SYS_sync, NULL); }
+
+int open(const char *filename, int flags, int mode)
+{
+ open_args_t args;
+
+ args.filename.as_len = strlen(filename);
+ args.filename.as_str = filename;
+ args.flags = flags;
+ args.mode = mode;
+
+ return (int)trap(SYS_open, (uintptr_t)&args);
+}
+
+off_t lseek(int fd, off_t offset, int whence)
+{
+ lseek_args_t args;
+
+ args.fd = fd;
+ args.offset = offset;
+ args.whence = whence;
+
+ return (int)trap(SYS_lseek, (uintptr_t)&args);
+}
+
+ssize_t read(int fd, void *buf, size_t nbytes)
+{
+ read_args_t args;
+
+ args.fd = fd;
+ args.buf = buf;
+ args.nbytes = nbytes;
+
+ return trap(SYS_read, (uintptr_t)&args);
+}
+
+ssize_t write(int fd, const void *buf, size_t nbytes)
+{
+ write_args_t args;
+
+ args.fd = fd;
+ args.buf = (void *)buf;
+ args.nbytes = nbytes;
+
+ return trap(SYS_write, (uintptr_t)&args);
+}
+
+int close(int fd) { return (int)trap(SYS_close, (ssize_t)fd); }
+
+int dup(int fd) { return (int)trap(SYS_dup, (ssize_t)fd); }
+
+int dup2(int ofd, int nfd)
+{
+ dup2_args_t args;
+
+ args.ofd = ofd;
+ args.nfd = nfd;
+
+ return (int)trap(SYS_dup2, (uintptr_t)&args);
+}
+
+int mkdir(const char *path, int mode)
+{
+ mkdir_args_t args;
+
+ args.path.as_len = strlen(path);
+ args.path.as_str = path;
+ args.mode = mode;
+
+ return (int)trap(SYS_mkdir, (uintptr_t)&args);
+}
+
+int rmdir(const char *path)
+{
+ argstr_t args;
+ args.as_len = strlen(path);
+ args.as_str = path;
+ return (int)trap(SYS_rmdir, (uintptr_t)&args);
+}
+
+int unlink(const char *path)
+{
+ argstr_t args;
+ args.as_len = strlen(path);
+ args.as_str = path;
+ return (int)trap(SYS_unlink, (uintptr_t)&args);
+}
+
+int link(const char *from, const char *to)
+{
+ link_args_t args;
+
+ args.from.as_len = strlen(from);
+ args.from.as_str = from;
+ args.to.as_len = strlen(to);
+ args.to.as_str = to;
+
+ return (int)trap(SYS_link, (uintptr_t)&args);
+}
+
+int rename(const char *oldpath, const char *newpath)
+{
+ rename_args_t args;
+
+ args.oldpath.as_len = strlen(oldpath);
+ args.oldpath.as_str = oldpath;
+ args.newpath.as_len = strlen(newpath);
+ args.newpath.as_str = newpath;
+
+ return (int)trap(SYS_rename, (uintptr_t)&args);
+}
+
+int chdir(const char *path)
+{
+ argstr_t args;
+ args.as_len = strlen(path);
+ args.as_str = path;
+ return (int)trap(SYS_chdir, (uintptr_t)&args);
+}
+
+size_t get_free_mem(void) { return (size_t)trap(SYS_get_free_mem, 0); }
+
+int execve(const char *filename, char *const argv[], char *const envp[])
+{
+ execve_args_t args;
+
+ size_t i;
+
+ args.filename.as_len = strlen(filename);
+ args.filename.as_str = filename;
+
+ /* Build argv vector */
+ for (i = 0; argv[i] != NULL; i++)
+ ;
+ args.argv.av_len = i;
+ args.argv.av_vec = malloc((args.argv.av_len + 1) * sizeof(argstr_t));
+ for (i = 0; argv[i] != NULL; i++)
+ {
+ args.argv.av_vec[i].as_len = strlen(argv[i]);
+ args.argv.av_vec[i].as_str = argv[i];
+ }
+ args.argv.av_vec[i].as_len = 0;
+ args.argv.av_vec[i].as_str = NULL;
+
+ /* Build envp vector */
+ for (i = 0; envp[i] != NULL; i++)
+ ;
+ args.envp.av_len = i;
+ args.envp.av_vec = malloc((args.envp.av_len + 1) * sizeof(argstr_t));
+ for (i = 0; envp[i] != NULL; i++)
+ {
+ args.envp.av_vec[i].as_len = strlen(envp[i]);
+ args.envp.av_vec[i].as_str = envp[i];
+ }
+ args.envp.av_vec[i].as_len = 0;
+ args.envp.av_vec[i].as_str = NULL;
+
+ /* Note that we don't need to worry about freeing since we are going to exec
+ * (so all our memory will be cleaned up) */
+
+ return (int)trap(SYS_execve, (uintptr_t)&args);
+}
+
+void thr_set_errno(int n) { trap(SYS_set_errno, (ssize_t)n); }
+
+int thr_errno(void) { return (int)trap(SYS_errno, 0); }
+
+int getdents(int fd, dirent_t *dir, size_t size)
+{
+ getdents_args_t args;
+
+ args.fd = fd;
+ args.dirp = dir;
+ args.count = size;
+
+ return (int)trap(SYS_getdents, (uintptr_t)&args);
+}
+
+#ifdef __MOUNTING__
+int mount(const char *spec, const char *dir, const char *fstype)
+{
+ mount_args_t args;
+
+ args.spec.as_len = strlen(spec);
+ args.spec.as_str = spec;
+ args.dir.as_len = strlen(dir);
+ args.dir.as_str = dir;
+ args.fstype.as_len = strlen(fstype);
+ args.fstype.as_str = fstype;
+
+ return (int)trap(SYS_mount, (uintptr_t)&args);
+}
+
+int umount(const char *path)
+{
+ argstr_t argstr;
+
+ argstr.as_len = strlen(path);
+ argstr.as_str = path;
+
+ return (int)trap(SYS_umount, (uintptr_t)&argstr);
+}
+#endif /* MOUNTING */
+
+int stat(const char *path, stat_t *buf)
+{
+ stat_args_t args;
+
+ args.path.as_len = strlen(path);
+ args.path.as_str = path;
+ args.buf = buf;
+
+ return (int)trap(SYS_stat, (uintptr_t)&args);
+}
+
+int pipe(int pipefd[2]) { return (int)trap(SYS_pipe, (uintptr_t)pipefd); }
+
+int uname(struct utsname *buf) { return (int)trap(SYS_uname, (uintptr_t)buf); }
+
+time_t time(time_t *tloc) { return (time_t)trap(SYS_time, (uintptr_t)tloc); }
+
+long usleep(useconds_t usec)
+{
+ usleep_args_t args;
+ args.usec = usec;
+ return (long)trap(SYS_usleep, (uintptr_t)&args);
+} \ No newline at end of file
diff --git a/user/lib/libc/vsnprintf.c b/user/lib/libc/vsnprintf.c
new file mode 100644
index 0000000..a73c75e
--- /dev/null
+++ b/user/lib/libc/vsnprintf.c
@@ -0,0 +1,566 @@
+/*
+ ****************************************************************************
+ * (C) 2003 - Rolf Neugebauer - Intel Research Cambridge
+ ****************************************************************************
+ *
+ * File: printf.c
+ * Author: Rolf Neugebauer (neugebar@dcs.gla.ac.uk)
+ * Changes: Grzegorz Milos (gm281@cam.ac.uk)
+ *
+ * Date: Aug 2003, Aug 2005
+ *
+ * Environment: Xen Minimal OS
+ * Description: Library functions for printing
+ * (freebsd port, mainly sys/subr_prf.c)
+ *
+ ****************************************************************************
+ *
+ *-
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This software was developed by the Computer Systems Engineering group
+ * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
+ * contributed to Berkeley.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD: src/sys/libkern/divdi3.c,v 1.6 1999/08/28 00:46:31 peter Exp $
+ */
+
+#include "ctype.h"
+#include "stdarg.h"
+#include "stdio.h"
+#include "string.h"
+
+static int skip_atoi(const char **s)
+{
+ int i = 0;
+
+ while (isdigit(**s))
+ i = i * 10 + *((*s)++) - '0';
+ return i;
+}
+
+#define ZEROPAD 1 /* pad with zero */
+#define SIGN 2 /* unsigned/signed long */
+#define PLUS 4 /* show plus */
+#define SPACE 8 /* space if plus */
+#define LEFT 16 /* left justified */
+#define SPECIAL 32 /* 0x */
+#define LARGE 64 /* use 'ABCDEF' instead of 'abcdef' */
+
+static char *number(char *buf, char *end, long long num, int base, int size,
+ int precision, int type)
+{
+ char c, sign, tmp[66];
+ const char *digits;
+ const char small_digits[] = "0123456789abcdefghijklmnopqrstuvwxyz";
+ const char large_digits[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
+ int i;
+
+ digits = (type & LARGE) ? large_digits : small_digits;
+ if (type & LEFT)
+ {
+ type &= ~ZEROPAD;
+ }
+ if (base < 2 || base > 36)
+ {
+ return buf;
+ }
+ c = (type & ZEROPAD) ? '0' : ' ';
+ sign = 0;
+ if (type & SIGN)
+ {
+ if (num < 0)
+ {
+ sign = '-';
+ num = -num;
+ size--;
+ }
+ else if (type & PLUS)
+ {
+ sign = '+';
+ size--;
+ }
+ else if (type & SPACE)
+ {
+ sign = ' ';
+ size--;
+ }
+ }
+ if (type & SPECIAL)
+ {
+ if (base == 16)
+ {
+ size -= 2;
+ }
+ else if (base == 8)
+ {
+ size--;
+ }
+ }
+ i = 0;
+ if (num == 0)
+ {
+ tmp[i++] = '0';
+ }
+ else
+ {
+ /* XXX KAF: force unsigned mod and div. */
+ /* XXX kernel does not support long long division */
+ unsigned long long num2 = (unsigned long long)num;
+ unsigned int base2 = (unsigned int)base;
+ while (num2 != 0)
+ {
+ tmp[i++] = digits[num2 % base2];
+ num2 /= base2;
+ }
+ }
+ if (i > precision)
+ {
+ precision = i;
+ }
+ size -= precision;
+ if (!(type & (ZEROPAD + LEFT)))
+ {
+ while (size-- > 0)
+ {
+ if (buf <= end)
+ {
+ *buf = ' ';
+ }
+ ++buf;
+ }
+ }
+ if (sign)
+ {
+ if (buf <= end)
+ {
+ *buf = sign;
+ }
+ ++buf;
+ }
+ if (type & SPECIAL)
+ {
+ if (base == 8)
+ {
+ if (buf <= end)
+ {
+ *buf = '0';
+ }
+ ++buf;
+ }
+ else if (base == 16)
+ {
+ if (buf <= end)
+ {
+ *buf = '0';
+ }
+ ++buf;
+ if (buf <= end)
+ {
+ *buf = digits[33];
+ }
+ ++buf;
+ }
+ }
+ if (!(type & LEFT))
+ {
+ while (size-- > 0)
+ {
+ if (buf <= end)
+ {
+ *buf = c;
+ }
+ ++buf;
+ }
+ }
+ while (i < precision--)
+ {
+ if (buf <= end)
+ {
+ *buf = '0';
+ }
+ ++buf;
+ }
+ while (i-- > 0)
+ {
+ if (buf <= end)
+ {
+ *buf = tmp[i];
+ }
+ ++buf;
+ }
+ while (size-- > 0)
+ {
+ if (buf <= end)
+ {
+ *buf = ' ';
+ }
+ ++buf;
+ }
+ return buf;
+}
+
+/* TODO This is a copy of the kernel vsnprintf. It has (almost)
+ * no error checking. It also is completely unable to handle
+ * floating point. - alvin */
+/**
+ * vsnprintf - Format a string and place it in a buffer
+ * @buf: The buffer to place the result into
+ * @size: The size of the buffer, including the trailing null space
+ * @fmt: The format string to use
+ * @args: Arguments for the format string
+ *
+ * Call this function if you are already dealing with a va_list.
+ * You probably want snprintf instead.
+ */
+int vsnprintf(char *buf, size_t size, const char *fmt, va_list args)
+{
+ int len;
+ unsigned long long num;
+ int i, base;
+ char *str, *end, c;
+ const char *s;
+
+ int flags; /* flags to number() */
+
+ int field_width; /* width of output field */
+ int precision; /* min. # of digits for integers; max
+ number of chars for from string */
+ int qualifier; /* 'h', 'l', or 'L' for integer fields */
+ /* 'z' support added 23/7/1999 S.H. */
+ /* 'z' changed to 'Z' --davidm 1/25/99 */
+
+ str = buf;
+ end = buf + size - 1;
+
+ if (end < buf - 1)
+ {
+ end = ((void *)-1);
+ size = end - buf + 1;
+ }
+
+ for (; *fmt; ++fmt)
+ {
+ if (*fmt != '%')
+ {
+ if (str <= end)
+ {
+ *str = *fmt;
+ }
+ ++str;
+ continue;
+ }
+
+ /* process flags */
+ flags = 0;
+ repeat:
+ ++fmt; /* this also skips first '%' */
+ switch (*fmt)
+ {
+ case '-':
+ flags |= LEFT;
+ goto repeat;
+ case '+':
+ flags |= PLUS;
+ goto repeat;
+ case ' ':
+ flags |= SPACE;
+ goto repeat;
+ case '#':
+ flags |= SPECIAL;
+ goto repeat;
+ case '0':
+ flags |= ZEROPAD;
+ goto repeat;
+ }
+
+ /* get field width */
+ field_width = -1;
+ if (isdigit(*fmt))
+ {
+ field_width = skip_atoi(&fmt);
+ }
+ else if (*fmt == '*')
+ {
+ ++fmt;
+ /* it's the next argument */
+ field_width = va_arg(args, int);
+ if (field_width < 0)
+ {
+ field_width = -field_width;
+ flags |= LEFT;
+ }
+ }
+
+ /* get the precision */
+ precision = -1;
+ if (*fmt == '.')
+ {
+ ++fmt;
+ if (isdigit(*fmt))
+ {
+ precision = skip_atoi(&fmt);
+ }
+ else if (*fmt == '*')
+ {
+ ++fmt;
+ /* it's the next argument */
+ precision = va_arg(args, int);
+ }
+ if (precision < 0)
+ {
+ precision = 0;
+ }
+ }
+
+ /* get the conversion qualifier */
+ qualifier = -1;
+ if (*fmt == 'h' || *fmt == 'l' || *fmt == 'L' || *fmt == 'Z')
+ {
+ qualifier = *fmt;
+ ++fmt;
+ if (qualifier == 'l' && *fmt == 'l')
+ {
+ qualifier = 'L';
+ ++fmt;
+ }
+ }
+ if (*fmt == 'q')
+ {
+ qualifier = 'L';
+ ++fmt;
+ }
+
+ /* default base */
+ base = 10;
+
+ switch (*fmt)
+ {
+ case 'c':
+ if (!(flags & LEFT))
+ {
+ while (--field_width > 0)
+ {
+ if (str <= end)
+ {
+ *str = ' ';
+ }
+ ++str;
+ }
+ }
+ c = (unsigned char)va_arg(args, int);
+ if (str <= end)
+ {
+ *str = c;
+ }
+ ++str;
+ while (--field_width > 0)
+ {
+ if (str <= end)
+ {
+ *str = ' ';
+ }
+ ++str;
+ }
+ continue;
+
+ case 's':
+ s = va_arg(args, char *);
+ if (!s)
+ {
+ s = "<NULL>";
+ }
+
+ len = strnlen(s, precision);
+
+ if (!(flags & LEFT))
+ {
+ while (len < field_width--)
+ {
+ if (str <= end)
+ {
+ *str = ' ';
+ }
+ ++str;
+ }
+ }
+ for (i = 0; i < len; ++i)
+ {
+ if (str <= end)
+ {
+ *str = *s;
+ }
+ ++str;
+ ++s;
+ }
+ while (len < field_width--)
+ {
+ if (str <= end)
+ {
+ *str = ' ';
+ }
+ ++str;
+ }
+ continue;
+
+ case 'p':
+ if (field_width == -1)
+ {
+ field_width = 2 * sizeof(void *);
+ flags |= ZEROPAD;
+ }
+ str = number(str, end, (unsigned long)va_arg(args, void *), 16,
+ field_width, precision, flags);
+ continue;
+
+ case 'n':
+ /* FIXME:
+ * What does C99 say about the overflow case here? */
+ if (qualifier == 'l')
+ {
+ long *ip = va_arg(args, long *);
+ *ip = (str - buf);
+ }
+ else if (qualifier == 'Z')
+ {
+ size_t *ip = va_arg(args, size_t *);
+ *ip = (str - buf);
+ }
+ else
+ {
+ int *ip = va_arg(args, int *);
+ *ip = (str - buf);
+ }
+ continue;
+
+ case '%':
+ if (str <= end)
+ {
+ *str = '%';
+ }
+ ++str;
+ continue;
+
+ /* integer number formats - set up the flags and "break" */
+ case 'o':
+ base = 8;
+ break;
+
+ case 'X':
+ flags |= LARGE;
+ base = 16;
+ break;
+ case 'x':
+ base = 16;
+ break;
+
+ case 'd':
+ case 'i':
+ flags |= SIGN;
+ case 'u':
+ break;
+ /* Added - TODO - alvin */
+ case 'f':
+ case 'F':
+ case 'g':
+ case 'G':
+ return -1;
+
+ default:
+ if (str <= end)
+ {
+ *str = '%';
+ }
+ ++str;
+ if (*fmt)
+ {
+ if (str <= end)
+ {
+ *str = *fmt;
+ }
+ ++str;
+ }
+ else
+ {
+ --fmt;
+ }
+ continue;
+ }
+ if (qualifier == 'L')
+ {
+ num = va_arg(args, long long);
+ }
+ else if (qualifier == 'l')
+ {
+ num = va_arg(args, unsigned long);
+ if (flags & SIGN)
+ {
+ num = (signed long)num;
+ }
+ }
+ else if (qualifier == 'Z')
+ {
+ num = va_arg(args, size_t);
+ }
+ else if (qualifier == 'h')
+ {
+ num = (unsigned short)va_arg(args, int);
+ if (flags & SIGN)
+ {
+ num = (signed short)num;
+ }
+ }
+ else
+ {
+ num = va_arg(args, unsigned int);
+ if (flags & SIGN)
+ {
+ num = (signed int)num;
+ }
+ }
+
+ str = number(str, end, num, base, field_width, precision, flags);
+ }
+ if (str <= end)
+ {
+ *str = '\0';
+ }
+ else if (size > 0)
+ {
+ /* don't write out a null byte if the buf size is zero */
+ *end = '\0';
+ }
+ /* the trailing null byte doesn't count towards the total
+ * ++str;
+ */
+ return str - buf;
+}
diff --git a/user/lib/libc/vsscanf.c b/user/lib/libc/vsscanf.c
new file mode 100644
index 0000000..ab3beac
--- /dev/null
+++ b/user/lib/libc/vsscanf.c
@@ -0,0 +1,447 @@
+/*
+ ****************************************************************************
+ * (C) 2003 - Rolf Neugebauer - Intel Research Cambridge
+ ****************************************************************************
+ *
+ * File: printf.c
+ * Author: Rolf Neugebauer (neugebar@dcs.gla.ac.uk)
+ * Changes: Grzegorz Milos (gm281@cam.ac.uk)
+ *
+ * Date: Aug 2003, Aug 2005
+ *
+ * Environment: Xen Minimal OS
+ * Description: Library functions for printing
+ * (freebsd port, mainly sys/subr_prf.c)
+ *
+ ****************************************************************************
+ *
+ *-
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This software was developed by the Computer Systems Engineering group
+ * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
+ * contributed to Berkeley.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD: src/sys/libkern/divdi3.c,v 1.6 1999/08/28 00:46:31 peter Exp $
+ */
+#include "ctype.h"
+#include "limits.h"
+#include "stdarg.h"
+#include "stddef.h"
+
+static int skip_atoi(const char **s)
+{
+ int i = 0;
+
+ while (isdigit(**s))
+ i = i * 10 + *((*s)++) - '0';
+ return i;
+}
+
+/**
+ * simple_strtoul - convert a string to an unsigned long
+ * @cp: The start of the string
+ * @endp: A pointer to the end of the parsed string will be placed here
+ * @base: The number base to use
+ */
+unsigned long simple_strtoul(const char *cp, char **endp, unsigned int base)
+{
+ unsigned long result = 0, value;
+
+ if (!base)
+ {
+ base = 10;
+ if (*cp == '0')
+ {
+ base = 8;
+ cp++;
+ if ((*cp == 'x') && isxdigit(cp[1]))
+ {
+ cp++;
+ base = 16;
+ }
+ }
+ }
+ while (isxdigit(*cp) &&
+ (value = isdigit(*cp) ? *cp - '0' : toupper(*cp) - 'A' + 10) <
+ base)
+ {
+ result = result * base + value;
+ cp++;
+ }
+ if (endp)
+ {
+ *endp = (char *)cp;
+ }
+ return result;
+}
+
+/**
+ * simple_strtol - convert a string to a signed long
+ * @cp: The start of the string
+ * @endp: A pointer to the end of the parsed string will be placed here
+ * @base: The number base to use
+ */
+long simple_strtol(const char *cp, char **endp, unsigned int base)
+{
+ if (*cp == '-')
+ {
+ return -simple_strtoul(cp + 1, endp, base);
+ }
+ return simple_strtoul(cp, endp, base);
+}
+
+/**
+ * simple_strtoull - convert a string to an unsigned long long
+ * @cp: The start of the string
+ * @endp: A pointer to the end of the parsed string will be placed here
+ * @base: The number base to use
+ */
+unsigned long long simple_strtoull(const char *cp, char **endp,
+ unsigned int base)
+{
+ unsigned long long result = 0, value;
+
+ if (!base)
+ {
+ base = 10;
+ if (*cp == '0')
+ {
+ base = 8;
+ cp++;
+ if ((*cp == 'x') && isxdigit(cp[1]))
+ {
+ cp++;
+ base = 16;
+ }
+ }
+ }
+ while (isxdigit(*cp) &&
+ (value = isdigit(*cp) ? *cp - '0'
+ : (islower(*cp) ? toupper(*cp) : *cp) - 'A' +
+ 10) < base)
+ {
+ result = result * base + value;
+ cp++;
+ }
+ if (endp)
+ {
+ *endp = (char *)cp;
+ }
+ return result;
+}
+
+/**
+ * simple_strtoll - convert a string to a signed long long
+ * @cp: The start of the string
+ * @endp: A pointer to the end of the parsed string will be placed here
+ * @base: The number base to use
+ */
+long long simple_strtoll(const char *cp, char **endp, unsigned int base)
+{
+ if (*cp == '-')
+ {
+ return -simple_strtoull(cp + 1, endp, base);
+ }
+ return simple_strtoull(cp, endp, base);
+}
+
+/**
+ * vsscanf - Unformat a buffer into a list of arguments
+ * @buf: input buffer
+ * @fmt: format of buffer
+ * @args: arguments
+ */
+int vsscanf(const char *buf, const char *fmt, va_list args)
+{
+ const char *str = buf;
+ char *next;
+ char digit;
+ int num = 0;
+ int qualifier;
+ int base;
+ int field_width;
+ int is_sign = 0;
+
+ while (*fmt && *str)
+ {
+ /* skip any white space in format */
+ /* white space in format matchs any amount of
+ * white space, including none, in the input.
+ */
+ if (isspace(*fmt))
+ {
+ while (isspace(*fmt))
+ ++fmt;
+ while (isspace(*str))
+ ++str;
+ }
+
+ /* anything that is not a conversion must match exactly */
+ if (*fmt != '%' && *fmt)
+ {
+ if (*fmt++ != *str++)
+ {
+ break;
+ }
+ continue;
+ }
+
+ if (!*fmt)
+ {
+ break;
+ }
+ ++fmt;
+
+ /* skip this conversion.
+ * advance both strings to next white space
+ */
+ if (*fmt == '*')
+ {
+ while (!isspace(*fmt) && *fmt)
+ fmt++;
+ while (!isspace(*str) && *str)
+ str++;
+ continue;
+ }
+
+ /* get field width */
+ field_width = -1;
+ if (isdigit(*fmt))
+ {
+ field_width = skip_atoi(&fmt);
+ }
+
+ /* get conversion qualifier */
+ qualifier = -1;
+ if (*fmt == 'h' || *fmt == 'l' || *fmt == 'L' || *fmt == 'Z' ||
+ *fmt == 'z')
+ {
+ qualifier = *fmt++;
+ if (qualifier == *fmt)
+ {
+ if (qualifier == 'h')
+ {
+ qualifier = 'H';
+ fmt++;
+ }
+ else if (qualifier == 'l')
+ {
+ qualifier = 'L';
+ fmt++;
+ }
+ }
+ }
+ base = 10;
+ is_sign = 0;
+
+ if (!*fmt || !*str)
+ {
+ break;
+ }
+
+ switch (*fmt++)
+ {
+ case 'c':
+ {
+ char *s = (char *)va_arg(args, char *);
+ if (field_width == -1)
+ {
+ field_width = 1;
+ }
+ do
+ {
+ *s++ = *str++;
+ } while (--field_width > 0 && *str);
+ num++;
+ }
+ continue;
+ case 's':
+ {
+ char *s = (char *)va_arg(args, char *);
+ if (field_width == -1)
+ {
+ field_width = INT_MAX;
+ }
+ /* first, skip leading white space in buffer */
+ while (isspace(*str))
+ str++;
+
+ /* now copy until next white space */
+ while (*str && !isspace(*str) && field_width--)
+ {
+ *s++ = *str++;
+ }
+ *s = '\0';
+ num++;
+ }
+ continue;
+ case 'n':
+ /* return number of characters read so far */
+ {
+ int *i = (int *)va_arg(args, int *);
+ *i = str - buf;
+ }
+ continue;
+ case 'o':
+ base = 8;
+ break;
+ case 'x':
+ case 'X':
+ base = 16;
+ break;
+ case 'i':
+ base = 0;
+ is_sign = 1;
+ break;
+ case 'd':
+ is_sign = 1;
+ break;
+ case 'u':
+ break;
+ case '%':
+ /* looking for '%' in str */
+ if (*str++ != '%')
+ {
+ return num;
+ }
+ continue;
+ default:
+ /* invalid format; stop here */
+ return num;
+ }
+
+ /* have some sort of integer conversion.
+ * first, skip white space in buffer.
+ */
+ while (isspace(*str))
+ str++;
+
+ digit = *str;
+ if (is_sign && digit == '-')
+ {
+ digit = *(str + 1);
+ }
+
+ if (!digit || (base == 16 && !isxdigit(digit)) ||
+ (base == 10 && !isdigit(digit)) ||
+ (base == 8 && (!isdigit(digit) || digit > '7')) ||
+ (base == 0 && !isdigit(digit)))
+ {
+ break;
+ }
+
+ switch (qualifier)
+ {
+ case 'H': /* that's 'hh' in format */
+ if (is_sign)
+ {
+ signed char *s = (signed char *)va_arg(args, signed char *);
+ *s = (signed char)simple_strtol(str, &next, base);
+ }
+ else
+ {
+ unsigned char *s =
+ (unsigned char *)va_arg(args, unsigned char *);
+ *s = (unsigned char)simple_strtoul(str, &next, base);
+ }
+ break;
+ case 'h':
+ if (is_sign)
+ {
+ short *s = (short *)va_arg(args, short *);
+ *s = (short)simple_strtol(str, &next, base);
+ }
+ else
+ {
+ unsigned short *s =
+ (unsigned short *)va_arg(args, unsigned short *);
+ *s = (unsigned short)simple_strtoul(str, &next, base);
+ }
+ break;
+ case 'l':
+ if (is_sign)
+ {
+ long *l = (long *)va_arg(args, long *);
+ *l = simple_strtol(str, &next, base);
+ }
+ else
+ {
+ unsigned long *l =
+ (unsigned long *)va_arg(args, unsigned long *);
+ *l = simple_strtoul(str, &next, base);
+ }
+ break;
+ case 'L':
+ if (is_sign)
+ {
+ long long *l = (long long *)va_arg(args, long long *);
+ *l = simple_strtoll(str, &next, base);
+ }
+ else
+ {
+ unsigned long long *l = (unsigned long long *)va_arg(
+ args, unsigned long long *);
+ *l = simple_strtoull(str, &next, base);
+ }
+ break;
+ case 'Z':
+ case 'z':
+ {
+ size_t *s = (size_t *)va_arg(args, size_t *);
+ *s = (size_t)simple_strtoul(str, &next, base);
+ }
+ break;
+ default:
+ if (is_sign)
+ {
+ int *i = (int *)va_arg(args, int *);
+ *i = (int)simple_strtol(str, &next, base);
+ }
+ else
+ {
+ unsigned int *i =
+ (unsigned int *)va_arg(args, unsigned int *);
+ *i = (unsigned int)simple_strtoul(str, &next, base);
+ }
+ break;
+ }
+ num++;
+
+ if (!next)
+ {
+ break;
+ }
+ str = next;
+ }
+ return num;
+}
diff --git a/user/lib/libtest/test.c b/user/lib/libtest/test.c
new file mode 100644
index 0000000..eeac059
--- /dev/null
+++ b/user/lib/libtest/test.c
@@ -0,0 +1,202 @@
+#include <test/test.h>
+
+#include <fcntl.h>
+#include <sys/mman.h>
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+typedef struct test_data
+{
+ int td_passed;
+ int td_failed;
+} test_data_t;
+
+static void _default_test_fail(const char *file, int line, const char *name,
+ const char *fmt, va_list args);
+
+static void _default_test_pass(int val, const char *file, int line,
+ const char *name, const char *fmt, va_list args);
+
+static test_data_t *_test_data = NULL;
+static test_pass_func_t _pass_func = _default_test_pass;
+static test_fail_func_t _fail_func = _default_test_fail;
+
+void test_init(void)
+{
+ int zfd = -1;
+
+ if (0 > (zfd = open("/dev/zero", O_RDWR, 0)))
+ {
+ printf("test_init: open(\"/dev/zero\"): %s\n", strerror(errno));
+ goto failed;
+ }
+
+ if (MAP_FAILED ==
+ (_test_data = mmap(NULL, sizeof(*_test_data), PROT_READ | PROT_WRITE,
+ MAP_SHARED, zfd, 0)))
+ {
+ printf("test_init: mmap(\"/dev/zero\"): %s\n", strerror(errno));
+ goto failed;
+ }
+
+ if (0 > close(zfd))
+ {
+ printf("test_init: close(\"/dev/zero\"): %s\n", strerror(errno));
+ goto failed;
+ }
+
+ _test_data->td_passed = 0;
+ _test_data->td_failed = 0;
+ return;
+
+failed:
+ printf("could not initialize testing library, exiting\n");
+ exit(-1);
+}
+
+void test_fini(void)
+{
+ printf("tests completed:\n");
+ printf("%d passed\n", _test_data->td_passed);
+ printf("%d failed\n", _test_data->td_failed);
+}
+
+const char *test_errstr(int err)
+{
+ switch (err)
+ {
+ case 1:
+ return "EPERM";
+ case 2:
+ return "ENOENT";
+ case 3:
+ return "ESRCH";
+ case 4:
+ return "EINTR";
+ case 5:
+ return "EIO";
+ case 6:
+ return "ENXIO";
+ case 7:
+ return "E2BIG";
+ case 8:
+ return "ENOEXEC";
+ case 9:
+ return "EBADF";
+ case 10:
+ return "ECHILD";
+ case 11:
+ return "EAGAIN";
+ case 12:
+ return "ENOMEM";
+ case 13:
+ return "EACCES";
+ case 14:
+ return "EFAULT";
+ case 15:
+ return "ENOTBLK";
+ case 16:
+ return "EBUSY";
+ case 17:
+ return "EEXIST";
+ case 18:
+ return "EXDEV";
+ case 19:
+ return "ENODEV";
+ case 20:
+ return "ENOTDIR";
+ case 21:
+ return "EISDIR";
+ case 22:
+ return "EINVAL";
+ case 23:
+ return "ENFILE";
+ case 24:
+ return "EMFILE";
+ case 25:
+ return "ENOTTY";
+ case 26:
+ return "ETXTBSY";
+ case 27:
+ return "EFBIG";
+ case 28:
+ return "ENOSPC";
+ case 29:
+ return "ESPIPE";
+ case 30:
+ return "EROFS";
+ case 31:
+ return "EMLINK";
+ case 32:
+ return "EPIPE";
+ case 33:
+ return "EDOM";
+ case 34:
+ return "ERANGE";
+ case 35:
+ return "EDEADLK";
+ case 36:
+ return "ENAMETOOLONG";
+ case 37:
+ return "ENOLCK";
+ case 38:
+ return "ENOSYS";
+ case 39:
+ return "ENOTEMPTY";
+ case 40:
+ return "ELOOP";
+ default:
+ return "UNKNOWN";
+ }
+}
+
+static void _default_test_fail(const char *file, int line, const char *name,
+ const char *fmt, va_list args)
+{
+ _test_data->td_failed++;
+ if (NULL == fmt)
+ {
+ printf("FAILED: %s(%d): %s\n", file, line, name);
+ }
+ else
+ {
+ printf("FAILED: %s(%d): %s: ", file, line, name);
+ vprintf(fmt, args);
+ printf("\n");
+ }
+}
+
+static void _default_test_pass(int val, const char *file, int line,
+ const char *name, const char *fmt,
+ va_list args)
+{
+ _test_data->td_passed++;
+}
+
+int _test_assert(int val, const char *file, int line, const char *name,
+ const char *fmt, ...)
+{
+ va_list args;
+ va_start(args, fmt);
+
+ if (0 == val)
+ {
+ if (NULL != _fail_func)
+ {
+ _fail_func(file, line, name, fmt, args);
+ }
+ }
+ else
+ {
+ if (NULL != _pass_func)
+ {
+ _pass_func(val, file, line, name, fmt, args);
+ }
+ }
+
+ va_end(args);
+ return val;
+}
diff --git a/user/sbin/.gitignore b/user/sbin/.gitignore
new file mode 100644
index 0000000..ad61759
--- /dev/null
+++ b/user/sbin/.gitignore
@@ -0,0 +1,2 @@
+halt
+init
diff --git a/user/sbin/halt.c b/user/sbin/halt.c
new file mode 100644
index 0000000..b8ae416
--- /dev/null
+++ b/user/sbin/halt.c
@@ -0,0 +1,7 @@
+#include <unistd.h>
+
+int main(int argc, char **argv)
+{
+ halt();
+ return 0;
+}
diff --git a/user/sbin/init.c b/user/sbin/init.c
new file mode 100644
index 0000000..6bfe6ae
--- /dev/null
+++ b/user/sbin/init.c
@@ -0,0 +1,115 @@
+/*
+ * Forks a shell for each terminal and waits for them.
+ * This is the final thing you should be executing
+ * (with kernel_execve) in kernel-land once everything works.
+ */
+
+#include <dirent.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+char *empty[] = {NULL};
+
+const char *hi = "init: starting shell on ";
+const char *sh = "/bin/sh";
+const char *ttystr = "tty";
+const char *home = "/";
+const char *alldone = "init: no remaining processes\n";
+
+static int open_tty(char *tty)
+{
+ if (-1 == open(tty, O_RDONLY, 0))
+ {
+ return -1;
+ }
+ else if (-1 == open(tty, O_WRONLY, 0))
+ {
+ return -1;
+ }
+ else if (2 != dup(1))
+ {
+ return -1;
+ }
+ else
+ {
+ return 0;
+ }
+}
+
+static int canary = 0x12345678;
+
+static void spawn_shell_on(char *tty)
+{
+ if (!fork())
+ {
+ close(0);
+ close(1);
+ close(2);
+ if (-1 == open_tty(tty))
+ {
+ exit(1);
+ }
+
+ chdir(home);
+
+ printf("%s%s\n", hi, tty);
+
+ execve(sh, empty, empty);
+ fprintf(stderr, "exec failed!\n");
+ }
+}
+
+int main(int argc, char **argv, char **envp)
+{
+ int devdir, ii;
+ dirent_t d;
+ int status;
+
+ for (ii = 0; ii < NFILES; ii++)
+ {
+ close(ii);
+ }
+ ii = ii;
+
+ if (-1 == open_tty("/dev/tty0"))
+ {
+ exit(1);
+ }
+
+ chdir("/dev");
+
+ devdir = open("/dev", O_RDONLY, 0);
+ while (getdents(devdir, &d, sizeof(d)) > 0)
+ {
+ if (0 == strncmp(d.d_name, ttystr, strlen(ttystr)))
+ {
+ spawn_shell_on(d.d_name);
+ }
+ }
+ close(devdir);
+
+ int pid;
+ while (0 <= (pid = wait(&status)))
+ {
+ if (EFAULT == status)
+ {
+ printf("process %i faulted\n", pid);
+ }
+ }
+
+ if (ECHILD != errno)
+ {
+ printf("error: wait: %s\n", strerror(errno));
+ return 1;
+ }
+ else
+ {
+ printf("%s", alldone);
+ return 0;
+ }
+}
diff --git a/user/test/stuff b/user/test/stuff
new file mode 100644
index 0000000..b52f5f1
--- /dev/null
+++ b/user/test/stuff
@@ -0,0 +1,3 @@
+Remember to check things like linking and unlinking
+and sparseness of files.
+ --Guess who
diff --git a/user/usr/bin/args.c b/user/usr/bin/args.c
new file mode 100644
index 0000000..e10e821
--- /dev/null
+++ b/user/usr/bin/args.c
@@ -0,0 +1,36 @@
+/*
+ * Does some basic checks to make sure arguments are
+ * being passed to userland programs correctly.
+ */
+
+#include <fcntl.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+
+int main(int argc, char **argv, char **envp)
+{
+ int i;
+ char buf[100];
+
+ open("/dev/tty0", O_RDONLY, 0);
+ open("/dev/tty0", O_WRONLY, 0);
+
+ snprintf(buf, sizeof(buf), "Arguments: (argc = %d, argv = %p)\n", argc,
+ argv);
+ write(1, buf, strlen(buf));
+ for (i = 0; argv[i]; i++)
+ {
+ snprintf(buf, sizeof(buf), " %d \"%s\"\n", i, argv[i]);
+ write(1, buf, strlen(buf));
+ }
+ snprintf(buf, sizeof(buf), "Environment: (envp = %p)\n", envp);
+ write(1, buf, strlen(buf));
+ for (i = 0; envp[i]; i++)
+ {
+ snprintf(buf, sizeof(buf), " %d \"%s\"\n", i, envp[i]);
+ write(1, buf, strlen(buf));
+ }
+
+ return 0;
+}
diff --git a/user/usr/bin/hello.c b/user/usr/bin/hello.c
new file mode 100644
index 0000000..894f062
--- /dev/null
+++ b/user/usr/bin/hello.c
@@ -0,0 +1,17 @@
+/*
+ * The classic hello world program.
+ * If you can run this successfully, you should high-five
+ * everyone nearby. You can also shout loudly. People
+ * will understand.
+ */
+
+#include <fcntl.h>
+#include <unistd.h>
+
+int main(int argc, char **argv)
+{
+ open("/dev/tty0", O_RDONLY, 0);
+ open("/dev/tty0", O_WRONLY, 0);
+ write(1, "Hello, world!\n", 14);
+ return 0;
+}
diff --git a/user/usr/bin/kshell.c b/user/usr/bin/kshell.c
new file mode 100644
index 0000000..c22cff0
--- /dev/null
+++ b/user/usr/bin/kshell.c
@@ -0,0 +1,8 @@
+/*
+ * Runs the in-kernel shell.
+ */
+
+#include "weenix/syscall.h"
+#include "weenix/trap.h"
+
+int main(int argc, char **argv) { return (int)trap(SYS_kshell, (uint32_t)0); }
diff --git a/user/usr/bin/segfault.S b/user/usr/bin/segfault.S
new file mode 100644
index 0000000..e37f39a
--- /dev/null
+++ b/user/usr/bin/segfault.S
@@ -0,0 +1,12 @@
+/*
+ * An extremely simple test binary. It relies on your
+ * process text and stack being mapped in (and hence vmmap_map
+ * code working) but otherwise has even fewer dependencies than
+ * hello. It should almost immediately segfault.
+ */
+
+.globl main
+main:
+ xor %eax, %eax;
+ mov (%eax), %eax;
+ ret;
diff --git a/user/usr/bin/spin.c b/user/usr/bin/spin.c
new file mode 100644
index 0000000..e0ff1df
--- /dev/null
+++ b/user/usr/bin/spin.c
@@ -0,0 +1,10 @@
+/*
+ * Spins.
+ */
+
+int main(int argc, char **argv)
+{
+ while (1)
+ ;
+ return 0;
+}
diff --git a/user/usr/bin/tests/eatinodes.c b/user/usr/bin/tests/eatinodes.c
new file mode 100644
index 0000000..7e6f8a1
--- /dev/null
+++ b/user/usr/bin/tests/eatinodes.c
@@ -0,0 +1,90 @@
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <fcntl.h>
+#include <stdio.h>
+#include <unistd.h>
+
+static char root_dir[64];
+
+static void eatinodes_start(void)
+{
+ int err;
+
+ root_dir[0] = '\0';
+ do
+ {
+ snprintf(root_dir, sizeof(root_dir), "eatinodes-%d", rand());
+ err = mkdir(root_dir, 0777);
+ if (err && errno != EEXIST)
+ {
+ printf("Failed to make test root directory: %s\n", strerror(errno));
+ exit(errno);
+ }
+ } while (err != 0);
+ printf("Created test root directory: ./%s\n", root_dir);
+
+ err = chdir(root_dir);
+ if (err < 0)
+ {
+ printf("Could not cd into test directory\n");
+ exit(1);
+ }
+}
+
+static void eatinodes(void)
+{
+ int i;
+ int fd;
+ int err = 0;
+ char fname[32];
+
+ for (i = 0; !err; ++i)
+ {
+ snprintf(fname, sizeof(fname), "test-%d", i);
+ fd = open(fname, O_CREAT | O_TRUNC | O_WRONLY, 0666);
+ if (fd < 0)
+ {
+ printf("Could not open file %d: %s\n", i, strerror(errno));
+ break;
+ }
+ err = close(fd);
+ if (err < 0)
+ {
+ printf("Could not close fd %d: %s\n", fd, strerror(errno));
+ break;
+ }
+ printf("Created %d files\n", i);
+ }
+ int j;
+ printf("Cleaning up...\n");
+ for (j = 0; j < i; ++j)
+ {
+ snprintf(fname, sizeof(fname), "test-%d", j);
+ err = unlink(fname);
+ if (err < 0)
+ {
+ printf("Could not remove file %d: %s\n", j, strerror(errno));
+ }
+ }
+}
+
+static void eatinodes_end(void)
+{
+ chdir("..");
+ int err = rmdir(root_dir);
+ if (err < 0)
+ {
+ printf("Could not remove test directory: %s\n", strerror(errno));
+ }
+}
+
+int main(int argc, char **argv)
+{
+ eatinodes_start();
+ eatinodes();
+ eatinodes_end();
+
+ return 0;
+}
diff --git a/user/usr/bin/tests/eatmem.c b/user/usr/bin/tests/eatmem.c
new file mode 100644
index 0000000..f4735aa
--- /dev/null
+++ b/user/usr/bin/tests/eatmem.c
@@ -0,0 +1,190 @@
+/*
+ * Eats kernel memory. Lots of it.
+ */
+
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <stdio.h>
+#include <sys/mman.h>
+#include <unistd.h>
+
+#include <test/test.h>
+
+#define PAGE_SIZE 4096
+
+static void eat(void *addr, int *count, int *num)
+{
+ int status;
+ test_fork_begin()
+ {
+ if (*num <= 0)
+ {
+ /* Eat the memory until we die */
+ while (1)
+ {
+ char foo = *((char *)addr + ((*count)++ * PAGE_SIZE));
+ if ((*count & 0x7f) == 0)
+ {
+ printf("Ate %d pages\n", *count);
+ }
+ }
+ }
+ else
+ {
+ /* Eat until we have the necessary number of pages */
+ while (*count < *num)
+ {
+ char foo = *((char *)addr + ((*count)++ * PAGE_SIZE));
+ if ((*count & 0x7f) == 0)
+ {
+ printf("Ate %d pages\n", *count);
+ }
+ }
+ }
+ }
+ test_fork_end(&status);
+ if (*num <= 0 && EFAULT != status)
+ {
+ fprintf(stderr, "Child process didn't segfault!\n");
+ exit(1);
+ }
+ if (*num < 0)
+ {
+ /* Free the required number of pages */
+ munmap(addr, PAGE_SIZE * (-*num));
+ printf("Gave back %d pages\n", -*num);
+ *count += *num;
+ }
+}
+
+#define FLAG_DAEMON "-d"
+#define FLAG_INFINITE "-i"
+#define FLAG_ITER "-y"
+#define FLAG_NUM "-#"
+
+#define OPT_DAEMON 1
+#define OPT_INFINITE 2
+#define OPT_ITER 4
+#define OPT_NUM 8
+
+int parse_args(int argc, char **argv, int *opts, int *iter, int *num)
+{
+ int i;
+ *opts = *iter = *num = 0;
+ for (i = 1; i < argc; i++)
+ {
+ if (!strcmp(FLAG_DAEMON, argv[i]))
+ {
+ *opts |= OPT_DAEMON;
+ }
+ else if (!strcmp(FLAG_INFINITE, argv[i]))
+ {
+ *opts |= OPT_INFINITE;
+ }
+ else if (!strcmp(FLAG_ITER, argv[i]))
+ {
+ *opts |= OPT_ITER;
+ if (++i >= argc ||
+ (errno = 0, *iter = strtol(argv[i], NULL, 0), 0 != errno))
+ {
+ return -1;
+ }
+ }
+ else if (!strcmp(FLAG_NUM, argv[i]))
+ {
+ *opts |= OPT_NUM;
+ if (++i >= argc ||
+ (errno = 0, *num = strtol(argv[i], NULL, 0), 0 != errno))
+ {
+ return -1;
+ }
+ }
+ else
+ {
+ return -1;
+ }
+ }
+ return 0;
+}
+
+int main(int argc, char **argv)
+{
+ int status;
+ void *addr;
+ int *count;
+ int *opts, *iter, *num;
+
+ /* Get our huge mess of space. We map this as a bunch of regions at the
+ * beginning so that unmapping (above) actually does something. */
+ if (MAP_FAILED ==
+ (addr = mmap(NULL, PAGE_SIZE * 10000, PROT_READ | PROT_WRITE,
+ MAP_SHARED | MAP_ANON, -1, 0)))
+ {
+ return 1;
+ }
+
+ int i;
+ for (i = 0; i < 40; i++)
+ {
+ if (MAP_FAILED == mmap((char *)addr + PAGE_SIZE * 25 * i,
+ PAGE_SIZE * 25, PROT_READ | PROT_WRITE,
+ MAP_FIXED | MAP_SHARED | MAP_ANON, -1, 0))
+ {
+ return 1;
+ }
+ }
+
+ /* Set the initial count */
+ count = addr;
+ *count = 0;
+ opts = count + 1;
+ iter = count + 2;
+ num = count + 3;
+
+ if (0 > parse_args(argc, argv, opts, iter, num))
+ {
+ fprintf(
+ stderr,
+ "USAGE: eatmem [options]\n" FLAG_DAEMON
+ " run as daemon\n" FLAG_INFINITE
+ " run forever\n" FLAG_ITER
+ " [num] number of iterations to yield\n" FLAG_NUM
+ " [num] number of pages to eat (if negative, to relinquish)\n");
+ return 1;
+ }
+
+ addr = (char *)addr + PAGE_SIZE;
+
+ printf("OM NOM NOM NOM\n");
+
+ if (*opts & OPT_DAEMON)
+ {
+ if (fork())
+ {
+ exit(0);
+ }
+ }
+
+ eat(addr, count, num);
+
+ printf("Ate %d pages in total\n", *count);
+
+ if (*opts & OPT_INFINITE)
+ {
+ while (1)
+ {
+ sched_yield();
+ }
+ }
+ else if (*opts & OPT_ITER)
+ {
+ while (--iter)
+ {
+ sched_yield();
+ }
+ }
+ printf("Giving memory back now\n");
+ return 0;
+}
diff --git a/user/usr/bin/tests/elf_test-64.c b/user/usr/bin/tests/elf_test-64.c
new file mode 100644
index 0000000..9385ac1
--- /dev/null
+++ b/user/usr/bin/tests/elf_test-64.c
@@ -0,0 +1,38 @@
+#include <stdio.h>
+
+typedef struct
+{
+ long int a_type; /* Entry type */
+ union {
+ long int a_val; /* Integer value */
+ void *a_ptr; /* Pointer value */
+ void (*a_fcn)(void); /* Function pointer value */
+ } a_un;
+} Elf64_auxv_t;
+
+int main(int argc, char **argv, char **envp, Elf64_auxv_t *auxv)
+{
+ // print argument count
+ printf("argc: %d\n", argc);
+
+ // print argument vector
+ int i;
+ for (i = 0; argv[i] != 0; i++)
+ {
+ printf("argv[%d] (%p): %s\n", i, argv[i], argv[i]);
+ }
+
+ // print environment vector
+ for (i = 0; envp[i] != 0; i++)
+ {
+ printf("envp[%d] (%p): %s\n", i, envp[i], envp[i]);
+ }
+
+ // print auxiliary vector
+ for (i = 0; auxv[i].a_type != 0; i++)
+ {
+ printf("auxv[%d]: type %ld\n", i, auxv[i].a_type);
+ }
+
+ return 0;
+} \ No newline at end of file
diff --git a/user/usr/bin/tests/forkbomb.c b/user/usr/bin/tests/forkbomb.c
new file mode 100644
index 0000000..543990c
--- /dev/null
+++ b/user/usr/bin/tests/forkbomb.c
@@ -0,0 +1,84 @@
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+/* TODO add options for different ways of forkbombing
+ (kind of low priority but would be fun) */
+
+int main(int argc, char **argv)
+{
+ int n = 1;
+ pid_t pid;
+
+ open("/dev/tty0", O_RDONLY, 0);
+ open("/dev/tty0", O_WRONLY, 0);
+ printf("Forking up a storm!\n");
+ printf("If this runs for 10 minutes without crashing, then you ");
+ printf("probably aren't \nleaking resources\n");
+
+ if (fork())
+ {
+ for (;;)
+ {
+ printf("Fork number : %d\n", n);
+ if ((pid = fork()))
+ {
+ if (pid == -1)
+ {
+ printf("Fork %d failed. Forkbomb stopping.\n", n);
+ exit(1);
+ }
+ int status;
+ sched_yield();
+ wait(&status);
+ if (status != 0)
+ {
+ printf("Test failed. Child exit with status %d\n", status);
+ exit(1);
+ }
+ }
+ else
+ {
+ int a = 0;
+ sched_yield();
+ exit(0);
+ }
+ n++;
+ }
+ }
+
+#if 0
+// Old forkbomb
+ if (!fork())
+ {
+ for (;;)
+ {
+ printf("I am fork number %d\n", n);
+ if ((pid = fork()))
+ {
+ if (-1 != pid)
+ {
+ exit(0);
+ }
+ else
+ {
+ printf(
+ "%d-th fork failed. "
+ "forkbomb stopping.",
+ n);
+ exit(1);
+ }
+ }
+ ++n;
+ }
+ }
+ else
+ {
+ int status;
+ while (wait(&status) > 0)
+ ;
+ }
+#endif
+ return 0;
+}
diff --git a/user/usr/bin/tests/forktest.c b/user/usr/bin/tests/forktest.c
new file mode 100644
index 0000000..6e1475e
--- /dev/null
+++ b/user/usr/bin/tests/forktest.c
@@ -0,0 +1,19 @@
+#include <errno.h>
+#include <stdio.h>
+#include <unistd.h>
+
+int main(int argc, char *argv[], char *envp[])
+{
+ printf("pid %d: Entering forktest\n", getpid());
+ int pid = fork();
+ printf("pid %d: Fork returned %d\n", getpid(), pid);
+ printf("pid %d: About to enter waitpid\n", getpid());
+ int rc = waitpid(-1, 0, 0);
+ printf("pid %d: Waitpid returned %d\n", getpid(), rc);
+ if (rc == -1)
+ {
+ printf("pid %d: ERRNO = %d\n", getpid(), errno);
+ }
+ printf("pid %d: Exiting\n", getpid());
+ return 0;
+}
diff --git a/user/usr/bin/tests/linkermagic.h b/user/usr/bin/tests/linkermagic.h
new file mode 100644
index 0000000..2dfdd4f
--- /dev/null
+++ b/user/usr/bin/tests/linkermagic.h
@@ -0,0 +1,232 @@
+#pragma once
+
+/* Linker variables */
+extern void *__executable_start;
+extern void *_etext;
+extern void *_edata;
+extern void *_end;
+
+#define text_start ((void *)&__executable_start)
+#define text_end ((void *)&_etext)
+#define data_start ((void *)&_etext)
+#define data_end ((void *)&_edata)
+#define bss_start ((void *)&_edata)
+#define bss_end ((void *)&_end)
+
+/* The following is the default linux linker script, for reference */
+#if 0
+/*
+GNU ld (GNU Binutils for Debian) 2.18.0.20080103
+ Supported emulations:
+ elf_i386
+ i386linux
+ elf_x86_64
+using internal linker script:
+==================================================
+*/
+/* Script for -z combreloc: combine and sort reloc sections */
+OUTPUT_FORMAT("elf32-i386", "elf32-i386",
+ "elf32-i386")
+OUTPUT_ARCH(i386)
+ENTRY(_start)
+SEARCH_DIR("/usr/i486-linux-gnu/lib32"); SEARCH_DIR("/usr/local/lib32"); SEARCH_DIR("/lib32"); SEARCH_DIR("/usr/lib32"); SEARCH_DIR("/usr/i486-linux-gnu/lib"); SEARCH_DIR("/usr/local/lib"); SEARCH_DIR("/lib"); SEARCH_DIR("/usr/lib");
+SECTIONS {
+ /* Read-only sections, merged into text segment: */
+ PROVIDE(__executable_start = 0x08048000); . = 0x08048000 + SIZEOF_HEADERS;
+.interp : { *(.interp) }
+.note.gnu.build - id : { *(.note.gnu.build - id) }
+.hash : { *(.hash) }
+.gnu.hash : { *(.gnu.hash) }
+.dynsym : { *(.dynsym) }
+.dynstr : { *(.dynstr) }
+.gnu.version : { *(.gnu.version) }
+.gnu.version_d : { *(.gnu.version_d) }
+.gnu.version_r : { *(.gnu.version_r) }
+.rel.dyn :
+ {
+ *(.rel.init)
+ *(.rel.text .rel.text.* .rel.gnu.linkonce.t.*)
+ *(.rel.fini)
+ *(.rel.rodata .rel.rodata.* .rel.gnu.linkonce.r.*)
+ *(.rel.data.rel.ro *.rel.gnu.linkonce.d.rel.ro.*)
+ *(.rel.data .rel.data.* .rel.gnu.linkonce.d.*)
+ *(.rel.tdata .rel.tdata.* .rel.gnu.linkonce.td.*)
+ *(.rel.tbss .rel.tbss.* .rel.gnu.linkonce.tb.*)
+ *(.rel.ctors)
+ *(.rel.dtors)
+ *(.rel.got)
+ *(.rel.bss .rel.bss.* .rel.gnu.linkonce.b.*)
+ }
+.rela.dyn :
+ {
+ *(.rela.init)
+ *(.rela.text .rela.text.* .rela.gnu.linkonce.t.*)
+ *(.rela.fini)
+ *(.rela.rodata .rela.rodata.* .rela.gnu.linkonce.r.*)
+ *(.rela.data .rela.data.* .rela.gnu.linkonce.d.*)
+ *(.rela.tdata .rela.tdata.* .rela.gnu.linkonce.td.*)
+ *(.rela.tbss .rela.tbss.* .rela.gnu.linkonce.tb.*)
+ *(.rela.ctors)
+ *(.rela.dtors)
+ *(.rela.got)
+ *(.rela.bss .rela.bss.* .rela.gnu.linkonce.b.*)
+ }
+.rel.plt : { *(.rel.plt) }
+.rela.plt : { *(.rela.plt) }
+.init :
+ {
+ KEEP(*(.init))
+ } = 0x90909090
+.plt : { *(.plt) }
+.text :
+ {
+ *(.text .stub .text.* .gnu.linkonce.t.*)
+ KEEP(*(.text.*personality *))
+ /* .gnu.warning sections are handled specially by elf32.em. */
+ *(.gnu.warning)
+ } = 0x90909090
+.fini :
+ {
+ KEEP(*(.fini))
+ } = 0x90909090
+ PROVIDE(__etext = .);
+ PROVIDE(_etext = .);
+ PROVIDE(etext = .);
+.rodata : { *(.rodata .rodata.* .gnu.linkonce.r.*) }
+.rodata1 : { *(.rodata1) }
+.eh_frame_hdr : { *(.eh_frame_hdr) }
+.eh_frame : ONLY_IF_RO { KEEP(*(.eh_frame)) }
+.gcc_except_table : ONLY_IF_RO { *(.gcc_except_table .gcc_except_table.*) }
+ /* Adjust the address for the data segment. We want to adjust up to
+ the same address within the page on the next page up. */
+ . = ALIGN(CONSTANT(MAXPAGESIZE)) - ((CONSTANT(MAXPAGESIZE) - .) & (CONSTANT(MAXPAGESIZE) - 1)); . = DATA_SEGMENT_ALIGN(CONSTANT(MAXPAGESIZE), CONSTANT(COMMONPAGESIZE));
+ /* Exception handling */
+.eh_frame : ONLY_IF_RW { KEEP(*(.eh_frame)) }
+.gcc_except_table : ONLY_IF_RW { *(.gcc_except_table .gcc_except_table.*) }
+ /* Thread Local Storage sections */
+.tdata : { *(.tdata .tdata.* .gnu.linkonce.td.*) }
+.tbss : { *(.tbss .tbss.* .gnu.linkonce.tb.*) *(.tcommon) }
+.preinit_array :
+ {
+ PROVIDE_HIDDEN(__preinit_array_start = .);
+ KEEP(*(.preinit_array))
+ PROVIDE_HIDDEN(__preinit_array_end = .);
+ }
+.init_array :
+ {
+ PROVIDE_HIDDEN(__init_array_start = .);
+ KEEP(*(SORT(.init_array.*)))
+ KEEP(*(.init_array))
+ PROVIDE_HIDDEN(__init_array_end = .);
+ }
+.fini_array :
+ {
+ PROVIDE_HIDDEN(__fini_array_start = .);
+ KEEP(*(.fini_array))
+ KEEP(*(SORT(.fini_array.*)))
+ PROVIDE_HIDDEN(__fini_array_end = .);
+ }
+.ctors :
+ {
+ /* gcc uses crtbegin.o to find the start of
+ the constructors, so we make sure it is
+ first. Because this is a wildcard, it
+ doesn't matter if the user does not
+ actually link against crtbegin.o; the
+ linker won't look for a file to match a
+ wildcard. The wildcard also means that it
+ doesn't matter which directory crtbegin.o
+ is in. */
+ KEEP(*crtbegin.o(.ctors))
+ KEEP(*crtbegin ? .o(.ctors))
+ /* We don't want to include the .ctor section from
+ the crtend.o file until after the sorted ctors.
+ The .ctor section from the crtend file contains the
+ end of ctors marker and it must be last */
+ KEEP(*(EXCLUDE_FILE(*crtend.o *crtend ? .o) .ctors))
+ KEEP(*(SORT(.ctors.*)))
+ KEEP(*(.ctors))
+ }
+.dtors :
+ {
+ KEEP(*crtbegin.o(.dtors))
+ KEEP(*crtbegin ? .o(.dtors))
+ KEEP(*(EXCLUDE_FILE(*crtend.o *crtend ? .o) .dtors))
+ KEEP(*(SORT(.dtors.*)))
+ KEEP(*(.dtors))
+ }
+.jcr : { KEEP(*(.jcr)) }
+.data.rel.ro : { *(.data.rel.ro.local *.gnu.linkonce.d.rel.ro.local.*) *(.data.rel.ro *.gnu.linkonce.d.rel.ro.*) }
+.dynamic : { *(.dynamic) }
+.got : { *(.got) }
+ . = DATA_SEGMENT_RELRO_END(12, .);
+.got.plt : { *(.got.plt) }
+.data :
+ {
+ *(.data .data.* .gnu.linkonce.d.*)
+ KEEP(*(.gnu.linkonce.d.*personality *))
+ SORT(CONSTRUCTORS)
+ }
+.data1 : { *(.data1) }
+ _edata = .; PROVIDE(edata = .);
+ __bss_start = .;
+.bss :
+ {
+ *(.dynbss)
+ *(.bss .bss.* .gnu.linkonce.b.*)
+ *(COMMON)
+ /* Align here to ensure that the .bss section occupies space up to
+ _end. Align after .bss to ensure correct alignment even if the
+ .bss section disappears because there are no input sections.
+ FIXME: Why do we need it? When there is no .bss section, we don't
+ pad the .data section. */
+ . = ALIGN(. != 0 ? 32 / 8 : 1);
+ }
+ . = ALIGN(32 / 8);
+ . = ALIGN(32 / 8);
+ _end = .; PROVIDE(end = .);
+ . = DATA_SEGMENT_END(.);
+ /* Stabs debugging sections. */
+.stab 0 : { *(.stab) }
+.stabstr 0 : { *(.stabstr) }
+.stab.excl 0 : { *(.stab.excl) }
+.stab.exclstr 0 : { *(.stab.exclstr) }
+.stab.index 0 : { *(.stab.index) }
+.stab.indexstr 0 : { *(.stab.indexstr) }
+.comment 0 : { *(.comment) }
+ /* DWARF debug sections.
+ Symbols in the DWARF debugging sections are relative to the beginning
+ of the section so we begin them at 0. */
+ /* DWARF 1 */
+.debug 0 : { *(.debug) }
+.line 0 : { *(.line) }
+ /* GNU DWARF 1 extensions */
+.debug_srcinfo 0 : { *(.debug_srcinfo) }
+.debug_sfnames 0 : { *(.debug_sfnames) }
+ /* DWARF 1.1 and DWARF 2 */
+.debug_aranges 0 : { *(.debug_aranges) }
+.debug_pubnames 0 : { *(.debug_pubnames) }
+ /* DWARF 2 */
+.debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) }
+.debug_abbrev 0 : { *(.debug_abbrev) }
+.debug_line 0 : { *(.debug_line) }
+.debug_frame 0 : { *(.debug_frame) }
+.debug_str 0 : { *(.debug_str) }
+.debug_loc 0 : { *(.debug_loc) }
+.debug_macinfo 0 : { *(.debug_macinfo) }
+ /* SGI/MIPS DWARF 2 extensions */
+.debug_weaknames 0 : { *(.debug_weaknames) }
+.debug_funcnames 0 : { *(.debug_funcnames) }
+.debug_typenames 0 : { *(.debug_typenames) }
+.debug_varnames 0 : { *(.debug_varnames) }
+ /* DWARF 3 */
+.debug_pubtypes 0 : { *(.debug_pubtypes) }
+.debug_ranges 0 : { *(.debug_ranges) }
+.gnu.attributes 0 : { KEEP(*(.gnu.attributes)) }
+/ DISCARD / : { *(.note.GNU - stack) *(.gnu_debuglink) }
+}
+/*
+
+==================================================
+*/
+#endif
diff --git a/user/usr/bin/tests/memtest.c b/user/usr/bin/tests/memtest.c
new file mode 100644
index 0000000..eee16ed
--- /dev/null
+++ b/user/usr/bin/tests/memtest.c
@@ -0,0 +1,816 @@
+/*
+ * Test correct user space memory management, particularly segfaults
+ * Tests fun cases of mmap, munmap, and brk
+ * -- Alvin Kerber (alvin)
+ *
+ * Modified by twd in 7/2018 to work with improved address space layout.
+ */
+
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <dirent.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <sys/mman.h>
+#include <unistd.h>
+#include <weenix/syscall.h>
+
+#include <test/test.h>
+
+/* Shared header trickery */
+#include "page.h"
+
+#include "linkermagic.h"
+
+#define syscall_success(expr) \
+ test_assert(0 <= (expr), "\nunexpected error: %s (%d)", \
+ test_errstr(errno), errno)
+
+/* Helpful defines */
+#define assert_fault(statement, msg) \
+ do \
+ { \
+ int __status; \
+ test_fork_begin() \
+ { \
+ statement; \
+ return 0; \
+ } \
+ test_fork_end(&__status); \
+ test_assert(EFAULT == __status, \
+ "Unexpected lack of segfault on " #statement " : " msg); \
+ } while (0);
+
+#define assert_nofault(statement, msg) \
+ do \
+ { \
+ int __status; \
+ test_fork_begin() \
+ { \
+ statement; \
+ return 0; \
+ } \
+ test_fork_end(&__status); \
+ test_assert(0 == __status, \
+ "Unexpected segfault on " #statement " : " msg); \
+ } while (0);
+
+static char root_dir[64];
+
+/* Overflow the stack */
+static void overflow(void)
+{
+ int junk[1000];
+ overflow();
+}
+
+static int test_overflow(void)
+{
+ printf("Testing stack overflow\n");
+ assert_fault(overflow(), "Stack overflow");
+ return 0;
+}
+
+static int test_mmap_bounds(void)
+{
+ int fd, status;
+ void *addr;
+
+ printf("Testing boundaries and permissions of mmap()\n");
+
+ test_assert(0 < (fd = open("/dev/zero", O_RDWR, 0)), NULL);
+ test_assert(
+ MAP_FAILED != (addr = mmap(NULL, PAGE_SIZE * 3, PROT_READ | PROT_WRITE,
+ MAP_PRIVATE, fd, 0)),
+ NULL);
+ /* Make sure we can actually access these addresses */
+ test_assert('\0' == *(char *)addr, NULL);
+ test_assert('\0' == *((char *)addr + PAGE_SIZE), NULL);
+ test_assert('\0' == *((char *)addr + PAGE_SIZE * 2), NULL);
+ test_assert('\0' == *((char *)addr + PAGE_SIZE * 3 - 1), NULL);
+
+ /* Unmap the ends */
+ test_assert(0 == munmap(addr, PAGE_SIZE), NULL);
+ test_assert(0 == munmap((char *)addr + PAGE_SIZE * 2, PAGE_SIZE), NULL);
+
+ /* Adjust to center, now surrounded by unmapped regions */
+ addr = (char *)addr + PAGE_SIZE;
+
+ /* Make sure we didn't unmap the middle */
+ test_assert('\0' == *((char *)addr), NULL);
+ test_assert('\0' == *((char *)addr + PAGE_SIZE - 1), NULL);
+ assert_nofault(*(char *)addr = 'a', "");
+ assert_nofault(*((char *)addr + PAGE_SIZE - 1) = 'b', "");
+
+ /* Regions around it are unmapped */
+ assert_fault(char foo = *((char *)addr + PAGE_SIZE), "");
+ assert_fault(char foo = *((char *)addr - PAGE_SIZE), "");
+ assert_fault(char foo = *((char *)addr - 1), "");
+ assert_fault(*((char *)addr + PAGE_SIZE) = 'a', "");
+ assert_fault(*((char *)addr - 1) = 'a', "");
+ assert_fault(*((char *)addr + PAGE_SIZE * 2 - 1) = 'a', "");
+
+ /* Remap as read-only */
+ test_assert(
+ addr == mmap(addr, 1, PROT_READ, MAP_PRIVATE | MAP_FIXED, fd, 0), NULL);
+
+ assert_fault(*((char *)addr) = 'a', "");
+ assert_fault(*((char *)addr + PAGE_SIZE - 1) = 'a', "");
+
+ /* "Unmap" */
+ test_assert(0 == munmap((char *)addr - PAGE_SIZE, PAGE_SIZE), NULL);
+ test_assert(0 == munmap((char *)addr + PAGE_SIZE, PAGE_SIZE), NULL);
+
+ /* Make sure it's still there, also that it's overwritten */
+ test_assert('\0' == *((char *)addr), NULL);
+ test_assert('\0' == *((char *)addr + PAGE_SIZE - 1), NULL);
+
+ /* Unmap for real */
+ test_assert(0 == munmap(addr, 1), NULL);
+
+ assert_fault(char foo = *(char *)addr, "");
+ assert_fault(char foo = *((char *)addr + PAGE_SIZE - 1), "");
+
+ /* Test fun permissions */
+ test_assert(addr == mmap(addr, PAGE_SIZE, PROT_EXEC,
+ MAP_PRIVATE | MAP_FIXED, fd, 0),
+ NULL);
+ assert_fault(char foo = *(char *)addr, "");
+ assert_fault(char foo = *((char *)addr + PAGE_SIZE - 1), "");
+ assert_fault(*((char *)addr) = 'a', "");
+
+ test_assert(
+ addr == mmap(addr, PAGE_SIZE, 0, MAP_PRIVATE | MAP_FIXED, fd, 0), NULL);
+ assert_fault(char foo = *(char *)addr, "");
+ assert_fault(char foo = *((char *)addr + PAGE_SIZE - 1), "");
+ assert_fault(*((char *)addr) = 'a', "");
+
+ return 0;
+}
+
+static int test_brk_bounds(void)
+{
+ void *oldbrk, *newbrk;
+ int status;
+
+ printf("Testing boundaries and permissions of brk()\n");
+
+ /* "Stabilize" our old brk at a page boundary */
+ test_assert((void *)-1 != (oldbrk = sbrk(0)), NULL);
+ oldbrk = PAGE_ALIGN_UP(oldbrk);
+ test_assert(0 == brk(oldbrk), NULL);
+
+ /* Look at next page-aligned addr */
+ newbrk = (char *)oldbrk + PAGE_SIZE;
+
+ assert_fault(char foo = *(char *)newbrk, "");
+ assert_fault(*(char *)newbrk = 'a', "");
+
+ /* Move brk to next page-aligned addr */
+ test_assert(0 == brk(newbrk), NULL);
+
+ /* Access the new memory */
+ test_assert('\0' == *(char *)oldbrk, NULL);
+ test_assert('\0' == *((char *)newbrk - 1), NULL);
+ *((char *)newbrk - 1) = 'a';
+
+ assert_fault(char foo = *(char *)newbrk, "");
+ assert_fault(*(char *)newbrk = 'a', "");
+
+ /* Move brk up by 1 byte */
+ test_assert(0 == brk((char *)newbrk + 1), NULL);
+
+ /* Access the new memory */
+ test_assert('\0' == *(char *)newbrk, NULL);
+ test_assert('\0' == *((char *)newbrk + PAGE_SIZE - 1), NULL);
+ assert_nofault(*(char *)newbrk = 'b', "");
+
+ /* Old memory didn't change */
+ test_assert('a' == *((char *)newbrk - 1), NULL);
+
+ /* Move it back */
+ test_assert(0 == brk(newbrk), NULL);
+
+ assert_fault(char foo = *(char *)newbrk, "");
+ assert_fault(*(char *)newbrk = 'a', "");
+
+ /* Move it up, make sure region wiped. Note that the actual wipe test is
+ * 'evil' and is in eviltest. This just checks to make sure the brk region
+ * is private mapped (modified in subprocesses) */
+ test_assert(0 == brk((char *)newbrk + PAGE_SIZE), NULL);
+ test_assert('\0' == *(char *)newbrk, NULL);
+ test_assert('\0' == *((char *)newbrk + PAGE_SIZE - 1), NULL);
+
+ /* Move it down by 1 byte */
+ test_assert(0 == brk((char *)newbrk - 1), NULL);
+
+ /* Access still-accessible memory */
+ test_assert('a' == *((char *)newbrk - 1), NULL);
+ *((char *)newbrk - 2) = 'z';
+
+ /* Move brk to multiple addrs on same page, make sure page remains */
+ test_assert(0 == brk((char *)newbrk - 1000), NULL);
+ test_assert('z' == *((char *)newbrk - 2), NULL);
+ test_assert(0 == brk((char *)oldbrk + 1), NULL);
+ test_assert('z' == *((char *)newbrk - 2), NULL);
+ test_assert(0 == brk((char *)oldbrk + 1000), NULL);
+ test_assert('a' == *((char *)newbrk - 1), NULL);
+
+ return 0;
+}
+
+static int test_munmap(void)
+{
+ char *addr, *middle;
+
+ printf("Testing munmap()\n");
+
+ /* Map lots of areas. We're kind of lazy, so for now they're all anonymous
+ */
+ test_assert(
+ MAP_FAILED != (addr = mmap(NULL, PAGE_SIZE * 20, PROT_READ | PROT_WRITE,
+ MAP_PRIVATE | MAP_ANON, -1, 0)),
+ NULL);
+
+ *(addr + PAGE_SIZE * 8) = '^';
+ *(addr + PAGE_SIZE * 12) = '$';
+
+ /* Make sure TLB / page tables are cleared on unmap */
+ assert_fault(*addr = 'a'; munmap(addr, PAGE_SIZE); char foo = *addr;, "");
+ assert_fault(*addr = 'a'; munmap(addr, PAGE_SIZE * 20); char foo = *addr;
+ , "");
+ assert_fault(*(addr + PAGE_SIZE * 10) = 'a';
+ munmap(addr + PAGE_SIZE * 10, PAGE_SIZE * 5);
+ char foo = *(addr + PAGE_SIZE * 10);, "");
+
+ /* Overwrite middle of area (implicit unmap) */
+ test_assert(
+ MAP_FAILED != (middle = mmap(addr + PAGE_SIZE * 10, PAGE_SIZE,
+ PROT_READ | PROT_WRITE,
+ MAP_SHARED | MAP_ANON | MAP_FIXED, -1, 0)),
+ NULL);
+
+ /* Make sure we overwrote the middle but not the whole thing */
+ test_assert('\0' == *middle, NULL);
+ assert_nofault(*middle = 'a', "");
+ test_assert('a' == *middle, NULL);
+
+ test_assert('\0' == *(addr + PAGE_SIZE * 9), NULL);
+ assert_nofault(*(addr + PAGE_SIZE * 9) = 'a', "");
+ test_assert('\0' == *(addr + PAGE_SIZE * 9), NULL);
+
+ test_assert('\0' == *(addr + PAGE_SIZE * 11), NULL);
+ assert_nofault(*(addr + PAGE_SIZE * 11) = 'a', "");
+ test_assert('\0' == *(addr + PAGE_SIZE * 11), NULL);
+
+ test_assert('\0' == *addr, NULL);
+ test_assert('\0' == *(addr + PAGE_SIZE * 20 - 1), NULL);
+
+ /* Make sure the offsets are appropriate */
+ test_assert('^' == *(addr + PAGE_SIZE * 8), NULL);
+ test_assert('$' == *(addr + PAGE_SIZE * 12), NULL);
+
+ /* Unmap a weird overlapping region */
+ test_assert(0 == munmap(addr + PAGE_SIZE * 9, PAGE_SIZE * 3), NULL);
+
+ /* Make sure everything's gone */
+ assert_fault(char foo = *(addr + PAGE_SIZE * 9), "");
+ assert_fault(char foo = *(addr + PAGE_SIZE * 10), "");
+ assert_fault(char foo = *(addr + PAGE_SIZE * 12 - 1), "");
+
+ /* Make sure offsets are still correct */
+ test_assert('^' == *(addr + PAGE_SIZE * 8), NULL);
+ test_assert('$' == *(addr + PAGE_SIZE * 12), NULL);
+
+ /* Unmap nothing at all */
+ test_assert(0 == munmap(addr + PAGE_SIZE * 10, PAGE_SIZE), NULL);
+ test_assert(0 == munmap(addr + PAGE_SIZE * 9, PAGE_SIZE * 3), NULL);
+
+ /* Unmap almost the whole (remaining) thing */
+ test_assert(0 == munmap(addr + PAGE_SIZE, PAGE_SIZE * 19), NULL);
+
+ /* Make sure the beginning's still there */
+ test_assert('\0' == *addr, NULL);
+
+ /* Finish up, make sure everything's gone */
+ test_assert(0 == munmap(addr, PAGE_SIZE * 15), NULL);
+ assert_fault(char foo = *(addr + PAGE_SIZE), "");
+ assert_fault(char foo = *(addr), "");
+ assert_fault(char foo = *(addr + PAGE_SIZE * 20 - 1), "");
+
+ return 0;
+}
+
+static int test_start_brk(void)
+{
+ printf("Testing using brk() near starting brk\n");
+ test_assert(bss_end == sbrk(0), "brk should not have moved yet");
+ test_assert(!PAGE_ALIGNED(bss_end) && !PAGE_ALIGNED((char *)bss_end + 1),
+ "starting brk is page aligned; test is too easy...");
+
+ /* Up to next page boundary should already be accessible (end of bss) */
+ char *oldbrk = PAGE_ALIGN_UP(bss_end);
+ test_assert('\0' == *(oldbrk - 1), NULL);
+ *(oldbrk - 1) = 'a';
+ assert_fault(char foo = *oldbrk, "");
+
+ /* Move brk up to next page boundary */
+ test_assert(0 == brk(oldbrk), NULL);
+ test_assert('a' == *(oldbrk - 1), NULL);
+ *(oldbrk - 1) = 'b';
+ assert_fault(char foo = *oldbrk, "");
+ assert_fault(char foo = *(oldbrk + PAGE_SIZE), "");
+
+ /* Try to move before starting brk */
+ test_assert(0 != brk((char *)bss_end - 1), NULL);
+ test_assert(0 != brk(PAGE_ALIGN_DOWN(bss_end)), NULL);
+
+ /* Move it up another page */
+ char *newbrk = oldbrk + PAGE_SIZE;
+ test_assert(0 == brk(newbrk), NULL);
+
+ /* Make sure everything accessible (read/write) */
+ test_assert('b' == *(oldbrk - 1), NULL);
+ test_assert('\0' == *oldbrk, NULL);
+ test_assert('\0' == *(newbrk - 1), NULL);
+ *oldbrk = 'z';
+ *(newbrk - 1) = 'y';
+ assert_fault(char foo = *newbrk, "");
+ assert_fault(char foo = *(newbrk + PAGE_SIZE), "");
+
+ /* Try to move before starting brk */
+ test_assert(0 != brk((char *)bss_end - 1), NULL);
+ test_assert(0 != brk(PAGE_ALIGN_DOWN(bss_end)), NULL);
+
+ /* Move back to starting brk */
+ test_assert(0 == brk((char *)bss_end + 1), NULL);
+ /* Make sure region is gone */
+ test_assert('b' == *(oldbrk - 1), NULL);
+ assert_fault(char foo = *oldbrk, "");
+ assert_fault(char foo = *newbrk, "");
+
+ /* Move it up, make sure we have new clean region */
+ test_assert(0 == brk(oldbrk + 1), NULL);
+ /* This behavior is undefined, this represents how it
+ * works on Linux but these need not pass
+ */
+ /*test_assert('\0' == *oldbrk, NULL);
+ test_assert('\0' == *(newbrk - 1), NULL);*/
+ assert_fault(char foo = *newbrk, "");
+
+ /* Move back and finish */
+ test_assert(0 == brk(bss_end), NULL);
+ test_assert('b' == *(oldbrk - 1), NULL);
+
+ return 0;
+}
+
+static int test_brk_mmap(void)
+{
+ printf("Testing interactions of brk() and mmap()\n");
+ test_assert(bss_end == sbrk(0), "brk should not have moved yet");
+ char *oldbrk = PAGE_ALIGN_UP(bss_end);
+
+ /* Put a mapping in the way */
+ test_assert(MAP_FAILED != mmap(oldbrk, PAGE_SIZE * 2, PROT_READ,
+ MAP_ANON | MAP_FIXED | MAP_PRIVATE, -1, 0),
+ NULL);
+ /* Mapping is there */
+ test_assert('\0' == *oldbrk, NULL);
+ test_assert('\0' == *(oldbrk - 1), NULL);
+
+ /* Moving brk without getting area is fine */
+ test_assert(0 == brk(oldbrk), NULL);
+ test_assert('\0' == *oldbrk, NULL);
+ test_assert('\0' == *(oldbrk - 1), NULL);
+ test_assert(0 == brk((char *)bss_end + 1), NULL);
+ test_assert('\0' == *oldbrk, NULL);
+ test_assert('\0' == *(oldbrk - 1), NULL);
+
+ /* But can't move it up at all */
+ test_assert(0 != brk(oldbrk + 1), NULL);
+ test_assert(0 != brk(oldbrk + PAGE_SIZE), NULL);
+ test_assert(0 != brk(oldbrk + PAGE_SIZE * 2), NULL);
+ test_assert(0 != brk(oldbrk + PAGE_SIZE * 3), NULL);
+
+ /* Make it smaller */
+ test_assert(0 == munmap(oldbrk, PAGE_SIZE), NULL);
+ /* Region inaccessible */
+ assert_fault(char foo = *oldbrk, "");
+ assert_fault(char foo = *(oldbrk + PAGE_SIZE - 1), "");
+
+ /* Expand brk accordingly */
+ test_assert(0 == brk(oldbrk + PAGE_SIZE), NULL);
+ test_assert('\0' == *oldbrk, NULL);
+ test_assert('\0' == *(oldbrk + PAGE_SIZE - 1), NULL);
+ *oldbrk = 'a';
+
+ /* Can't go too far */
+ test_assert(0 != brk(oldbrk + PAGE_SIZE + 1), NULL);
+ test_assert(0 != brk(oldbrk + PAGE_SIZE * 2), NULL);
+ test_assert(0 != brk(oldbrk + PAGE_SIZE * 3), NULL);
+
+ return 0;
+}
+
+static int test_mmap_fill(void)
+{
+ printf("Testing filling up virtual address space\n");
+ char *hi, *lo, *addr;
+ /* map something and remove it to find out how high we can go */
+ test_assert(
+ MAP_FAILED != (hi = mmap(NULL, 1, 0, MAP_ANON | MAP_PRIVATE, -1, 0)),
+ NULL);
+ test_assert(0 == munmap(hi, 1), NULL);
+ hi += PAGE_SIZE;
+
+ test_assert(bss_end == sbrk(0), NULL);
+ lo = PAGE_ALIGN_UP(bss_end);
+
+ /* Fill this up with 2 mappings */
+#define MID_ADDR ((char *)0x80000000)
+ if (MID_ADDR > lo)
+ {
+ test_assert(
+ MID_ADDR == mmap(NULL,
+ (size_t)((uintptr_t)hi - (uintptr_t)MID_ADDR), 0,
+ MAP_ANON | MAP_PRIVATE, -1, 0),
+ NULL);
+ }
+ if (MID_ADDR < hi)
+ {
+ test_assert(
+ lo == mmap(NULL, (size_t)((uintptr_t)MID_ADDR - (uintptr_t)lo), 0,
+ MAP_ANON | MAP_PRIVATE, -1, 0),
+ NULL);
+ }
+
+ /* mmap file below stack */
+ test_assert(MAP_FAILED != (addr = mmap(NULL, 1, PROT_READ,
+ MAP_ANON | MAP_PRIVATE, -1, 0)),
+ NULL);
+ test_assert((uintptr_t)addr < (uintptr_t)&addr, NULL);
+ test_assert('\0' == *addr, NULL);
+ /* mmap fixed on top of it */
+ test_assert(MAP_FAILED != mmap(addr, 1, PROT_READ,
+ MAP_FIXED | MAP_ANON | MAP_PRIVATE, -1, 0),
+ NULL);
+ test_assert('\0' == *addr, NULL);
+
+ /* Try something too big */
+ test_assert(MAP_FAILED ==
+ mmap(NULL, (size_t)addr, 0, MAP_ANON | MAP_PRIVATE, -1, 0),
+ NULL);
+
+ /* Fill up the entire remaining space */
+#ifdef old
+ test_assert(
+ MAP_FAILED != mmap(NULL,
+ (size_t)((uintptr_t)addr - (uintptr_t)USER_MEM_LOW),
+ 0, MAP_ANON | MAP_PRIVATE, -1, 0),
+ NULL);
+#else
+ // all space beyond break is already taken
+#endif
+
+#ifdef old
+ /* No space left */
+ test_assert(MAP_FAILED == mmap(NULL, 1, 0, MAP_ANON | MAP_PRIVATE, -1, 0),
+ NULL);
+
+ /* Make some space, we should fill it */
+ test_assert(0 == munmap(addr, 1), NULL);
+ test_assert(addr == mmap(NULL, 1, PROT_READ, MAP_ANON | MAP_PRIVATE, -1, 0),
+ NULL);
+ test_assert('\0' == *addr, NULL);
+
+ test_assert(MAP_FAILED == mmap(NULL, 1, 0, MAP_ANON | MAP_PRIVATE, -1, 0),
+ NULL);
+#endif
+
+ /* Clean out some more space */
+ test_assert(0 == munmap(MID_ADDR - PAGE_SIZE, PAGE_SIZE * 2), NULL);
+ test_assert(MID_ADDR - PAGE_SIZE == mmap(NULL, PAGE_SIZE * 2, PROT_READ,
+ MAP_ANON | MAP_PRIVATE, -1, 0),
+ NULL);
+ test_assert('\0' == *MID_ADDR, NULL);
+ test_assert('\0' == *(MID_ADDR - PAGE_SIZE), NULL);
+ test_assert('\0' == *(MID_ADDR + PAGE_SIZE - 1), NULL);
+
+ /* Cut into pieces, access each of them */
+ char *p;
+ for (p = lo + PAGE_SIZE; p < lo + PAGE_SIZE * 20; p += PAGE_SIZE * 2)
+ {
+ test_assert(
+ MAP_FAILED != mmap(p, 1, PROT_READ | PROT_WRITE,
+ MAP_ANON | MAP_PRIVATE | MAP_FIXED, -1, 0),
+ NULL);
+ test_assert('\0' == *p, NULL);
+ *p = 'a';
+ assert_fault(char foo = *(p + PAGE_SIZE), "");
+ }
+
+ // there still should be a few pages available in low memory
+ test_assert(MAP_FAILED != mmap(NULL, 1, 0, MAP_ANON | MAP_PRIVATE, -1, 0),
+ NULL);
+
+ /* Try brk too */
+ test_assert(0 == brk(lo), NULL);
+ test_assert(0 != brk(lo + 1), NULL);
+
+ /* Clean it all up */
+ test_assert(0 == munmap(lo, (size_t)((uintptr_t)hi - (uintptr_t)lo)), NULL);
+ return 0;
+}
+
+static int test_mmap_repeat(void)
+{
+#define MMAP_REPEAT_FILE "mmaprepeattest"
+#define REPEAT_STR "FooFooFoo"
+
+ int fd, i;
+ char *addrs[10];
+ printf("Testing repeated mmap() of same file\n");
+
+ /* Set up test file */
+ test_assert(-1 != (fd = open(MMAP_REPEAT_FILE, O_RDWR | O_CREAT, 0)), NULL);
+ test_assert(10 == write(fd, REPEAT_STR, 10), NULL);
+ test_assert(0 == unlink(MMAP_REPEAT_FILE), NULL);
+
+ /* map it private many times */
+ for (i = 0; i < 10; i++)
+ {
+ test_assert(MAP_FAILED != (addrs[i] = mmap(NULL, PAGE_SIZE,
+ PROT_READ | PROT_WRITE,
+ MAP_PRIVATE, fd, 0)),
+ NULL);
+ test_assert(!strcmp(addrs[i], REPEAT_STR), NULL);
+ }
+ /* Make sure changes don't propagate */
+ *addrs[0] = 'Z';
+ *(addrs[0] + PAGE_SIZE - 1) = 'Q';
+ for (i = 1; i < 10; i++)
+ {
+ test_assert(!strcmp(addrs[i], REPEAT_STR), NULL);
+ test_assert('\0' == *(addrs[i] + PAGE_SIZE - 1), NULL);
+ }
+
+ /* map it shared many times */
+ for (i = 0; i < 10; i++)
+ {
+ test_assert(MAP_FAILED != (addrs[i] = mmap(NULL, PAGE_SIZE,
+ PROT_READ | PROT_WRITE,
+ MAP_SHARED, fd, 0)),
+ NULL);
+ test_assert(!strcmp(addrs[i], REPEAT_STR), NULL);
+ }
+ /* Make sure changes propagate */
+ *addrs[3] = 'Z';
+ *(addrs[5] + PAGE_SIZE - 1) = 'Q';
+ for (i = 0; i < 10; i++)
+ {
+ test_assert('Z' == *addrs[i], NULL);
+ test_assert('Q' == *(addrs[i] + PAGE_SIZE - 1), NULL);
+ }
+
+ return 0;
+}
+
+static int test_mmap_beyond(void)
+{
+ /* <insert evil laughter here> */
+#define MMAP_BEYOND_FILE "mmapbeyondtest"
+#define BEYOND_STR "FOOBAR!"
+
+ int fd;
+ char *addr, *addr2;
+ int status;
+
+ printf("Testing mmap() beyond end of backing object\n");
+
+ /* Set up test file */
+ test_assert(-1 != (fd = open(MMAP_BEYOND_FILE, O_RDWR | O_CREAT, 0)), NULL);
+ test_assert(8 == write(fd, BEYOND_STR, 8), NULL);
+ test_assert(0 == unlink(MMAP_BEYOND_FILE), NULL);
+
+ /* Set up test mmap */
+ test_assert(
+ MAP_FAILED != (addr = mmap(NULL, PAGE_SIZE * 10, PROT_READ | PROT_WRITE,
+ MAP_SHARED, fd, 0)),
+ NULL);
+ /* make sure it's there */
+ test_assert(!strcmp(addr, BEYOND_STR), NULL);
+
+ /* Do it again, but with private mapping. */
+ test_assert(MAP_FAILED !=
+ (addr2 = mmap(NULL, PAGE_SIZE * 10, PROT_READ | PROT_WRITE,
+ MAP_PRIVATE, fd, 0)),
+ NULL);
+ /* make sure it's there */
+ test_assert(!strcmp(addr2, BEYOND_STR), NULL);
+ *addr2 = 'a';
+
+ /* Can't go too far on either */
+ assert_fault(char foo = *(addr + PAGE_SIZE), "");
+ assert_fault(char foo = *(addr + PAGE_SIZE * 5), "");
+ assert_fault(*((char *)addr + PAGE_SIZE * 5) = 'a', "");
+
+ assert_fault(char foo = *(addr2 + PAGE_SIZE), "");
+ assert_fault(char foo = *(addr2 + PAGE_SIZE * 5), "");
+ assert_fault(*(addr2 + PAGE_SIZE * 5) = 'a', "");
+
+ /* Write more to it */
+ test_assert(PAGE_SIZE * 3 == lseek(fd, PAGE_SIZE * 3, SEEK_SET), NULL);
+ test_assert(8 == write(fd, BEYOND_STR, 8), NULL);
+
+ /* Can go up to new location */
+ test_assert(!strcmp(addr, BEYOND_STR), NULL);
+ test_assert('\0' == *(addr + PAGE_SIZE), NULL);
+ test_assert('\0' == *(addr + PAGE_SIZE * 2), NULL);
+ test_assert(!strcmp(addr + PAGE_SIZE * 3, BEYOND_STR), NULL);
+
+ test_assert('a' == *addr2, NULL);
+ test_assert('\0' == *(addr2 + PAGE_SIZE), NULL);
+ test_assert('\0' == *(addr2 + PAGE_SIZE * 2), NULL);
+
+ /* Can't go beyond it */
+ assert_fault(char foo = *(addr + PAGE_SIZE * 4), "");
+ assert_fault(char foo = *(addr + PAGE_SIZE * 8), "");
+ assert_fault(*(addr + PAGE_SIZE * 5) = 'a', "");
+
+ assert_fault(char foo = *(addr2 + PAGE_SIZE * 4), "");
+ assert_fault(char foo = *(addr2 + PAGE_SIZE * 8), "");
+ assert_fault(*(addr2 + PAGE_SIZE * 5) = 'a', "");
+
+ return 0;
+}
+
+/* TODO Figure out a way to not have these be repeated. */
+/* Copied from vfstest. Linking stuff prevents use of the same file. */
+static void make_rootdir(void)
+{
+ int err;
+
+ root_dir[0] = '\0';
+ do
+ {
+ snprintf(root_dir, sizeof(root_dir), "memtest-%d", rand());
+ err = mkdir(root_dir, 0777);
+ if (err && errno != EEXIST)
+ {
+ printf("Failed to make test root directory: %s\n", strerror(errno));
+ exit(errno);
+ }
+ } while (err != 0);
+ printf("Created test root directory: ./%s\n", root_dir);
+}
+
+/* Copied from vfstest. Linking stuff prevents use of the same file. */
+static int getdent(const char *dir, dirent_t *dirent)
+{
+ int ret, fd = -1;
+
+ if (0 > (fd = open(dir, O_RDONLY, 0777)))
+ {
+ return -1;
+ }
+
+ ret = 1;
+ while (ret != 0)
+ {
+ if (0 > (ret = getdents(fd, dirent, sizeof(*dirent))))
+ {
+ return -1;
+ }
+ if (0 != strcmp(".", dirent->d_name) &&
+ 0 != strcmp("..", dirent->d_name))
+ {
+ close(fd);
+ return 1;
+ }
+ }
+
+ close(fd);
+ return 0;
+}
+
+/* Copied from vfstest. Linking stuff prevents use of the same file. */
+static int removeall(const char *dir)
+{
+ int ret, fd = -1;
+ dirent_t dirent;
+ stat_t status;
+
+ if (0 > chdir(dir))
+ {
+ goto error;
+ }
+
+ ret = 1;
+ while (ret != 0)
+ {
+ if (0 > (ret = getdent(".", &dirent)))
+ {
+ goto error;
+ }
+ if (0 == ret)
+ {
+ break;
+ }
+
+ if (0 > stat(dirent.d_name, &status))
+ {
+ goto error;
+ }
+
+ if (S_ISDIR(status.st_mode))
+ {
+ if (0 > removeall(dirent.d_name))
+ {
+ goto error;
+ }
+ }
+ else
+ {
+ if (0 > unlink(dirent.d_name))
+ {
+ goto error;
+ }
+ }
+ }
+
+ if (0 > chdir(".."))
+ {
+ return errno;
+ }
+
+ if (0 > rmdir(dir))
+ {
+ return errno;
+ }
+
+ close(fd);
+ return 0;
+
+error:
+ if (0 <= fd)
+ {
+ close(fd);
+ }
+
+ return errno;
+}
+
+/* Copied from vfstest. Linking stuff prevents use of the same file. */
+static void destroy_rootdir(void)
+{
+ if (0 != removeall(root_dir))
+ {
+ fprintf(stderr, "ERROR: could not remove testing root %s: %s\n",
+ root_dir, strerror(errno));
+ exit(-1);
+ }
+ printf("Removed test root directory: ./%s\n", root_dir);
+}
+
+int main(int argc, char **argv)
+{
+ if (argc != 1)
+ {
+ fprintf(stderr, "USAGE: memtest\n");
+ return 1;
+ }
+ int status;
+
+ /* Make sure we found out if anything segfaults that shouldn't */
+#define childtest(fun) \
+ do \
+ { \
+ test_fork_begin() { return fun(); } \
+ test_fork_end(&status); \
+ test_assert(EFAULT != status, "Test process shouldn't segfault!"); \
+ test_assert(0 == status, "Test process returned error"); \
+ } while (0)
+
+ /* printf("Linker magic: start 0x%p, text end 0x%p, data end 0x%p, bss end
+ 0x%p\n", text_start, text_end, data_end, bss_end); */
+ test_init();
+ make_rootdir();
+ syscall_success(chdir(root_dir));
+ childtest(test_overflow);
+ childtest(test_mmap_bounds);
+ childtest(test_brk_bounds);
+ childtest(test_munmap);
+ childtest(test_start_brk);
+ childtest(test_brk_mmap);
+ // childtest(test_mmap_fill); // [+] TODO UPDATE FOR 64 BIT
+ childtest(test_mmap_repeat);
+ childtest(test_mmap_beyond);
+ syscall_success(chdir(".."));
+ destroy_rootdir();
+ test_fini();
+
+ return 0;
+}
diff --git a/user/usr/bin/tests/mm.h b/user/usr/bin/tests/mm.h
new file mode 120000
index 0000000..4859984
--- /dev/null
+++ b/user/usr/bin/tests/mm.h
@@ -0,0 +1 @@
+../../../../kernel/include/mm/mm.h \ No newline at end of file
diff --git a/user/usr/bin/tests/page.h b/user/usr/bin/tests/page.h
new file mode 120000
index 0000000..9c8100b
--- /dev/null
+++ b/user/usr/bin/tests/page.h
@@ -0,0 +1 @@
+../../../../kernel/include/mm/page.h \ No newline at end of file
diff --git a/user/usr/bin/tests/pipetest.c b/user/usr/bin/tests/pipetest.c
new file mode 100644
index 0000000..e588bd7
--- /dev/null
+++ b/user/usr/bin/tests/pipetest.c
@@ -0,0 +1,191 @@
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#define IMAX 256
+#define JMAX 16
+#define KMAX 16
+#define ISTEP (JMAX * KMAX)
+
+#define WAIT \
+ do \
+ { \
+ while (waitpid(-1, &status, 0) > 0) \
+ { \
+ if (status == 0) \
+ { \
+ passed++; \
+ } \
+ else \
+ { \
+ failed++; \
+ } \
+ } \
+ } while (0)
+
+int main(int argc, char **argv)
+{
+ int passed = 0;
+ int failed = 0;
+
+ int status;
+ int pipefd[2];
+
+ /* First test: normal operation.
+ * The writer writes a specific sequence of 64K
+ * bytes into the pipe, and the reader expects
+ * the same bytes out.
+ */
+ printf("Testing normal operation...\n");
+ int ret = pipe(pipefd);
+
+ if (ret < 0)
+ {
+ fprintf(stderr, "pipe: %s\n", strerror(errno));
+ exit(1);
+ }
+
+ int i, j, k;
+ unsigned char buf[KMAX];
+
+ if (!fork())
+ {
+ close(pipefd[0]);
+ for (i = 0; i < IMAX; ++i)
+ {
+ for (j = 0; j < JMAX; ++j)
+ {
+ for (k = 0; k < KMAX; ++k)
+ {
+ buf[k] = i ^ (j * KMAX + k);
+ }
+ if (write(pipefd[1], buf, KMAX) < 0)
+ {
+ printf("Write to pipe failed\n");
+ exit(1);
+ }
+ }
+ }
+ exit(0);
+ }
+
+ if (!fork())
+ {
+ close(pipefd[1]);
+ for (i = 0; i < IMAX; ++i)
+ {
+ for (j = 0; j < JMAX; ++j)
+ {
+ if (read(pipefd[0], buf, KMAX) == 0)
+ {
+ printf("Unexpected end of pipe\n");
+ exit(1);
+ }
+ for (k = 0; k < KMAX; ++k)
+ {
+ if (buf[k] != (i ^ (j * KMAX + k)))
+ {
+ printf("Byte %d incorrect (expected %2x, got %2x)\n",
+ i * ISTEP + j * KMAX + k, (i ^ (j * KMAX + k)),
+ buf[k]);
+ exit(1);
+ }
+ }
+ }
+ }
+ exit(0);
+ }
+
+ close(pipefd[0]);
+ close(pipefd[1]);
+
+ WAIT;
+
+ /* Second test: broken pipe.
+ * All readers quit immediately. The writer should get EPIPE.
+ */
+ printf("Testing with no readers...\n");
+ ret = pipe(pipefd);
+
+ if (ret < 0)
+ {
+ fprintf(stderr, "pipe: %s\n", strerror(errno));
+ exit(1);
+ }
+
+ if (!fork())
+ {
+ close(pipefd[0]);
+ for (i = 0; i < IMAX; ++i)
+ {
+ for (j = 0; j < JMAX; ++j)
+ {
+ for (k = 0; k < KMAX; ++k)
+ {
+ buf[k] = i ^ (j * KMAX + k);
+ }
+ if (write(pipefd[1], buf, KMAX) < 0)
+ {
+ if (errno == EPIPE)
+ {
+ exit(0);
+ }
+ else
+ {
+ printf("Write to pipe failed\n");
+ exit(1);
+ }
+ }
+ }
+ }
+ exit(1);
+ }
+
+ close(pipefd[0]);
+ close(pipefd[1]);
+
+ WAIT;
+
+ /* Third test: writers quit.
+ * The readers should get no bytes, and this program
+ * should not block in the kernel forever.
+ */
+ printf("Testing with no writers...\n");
+ ret = pipe(pipefd);
+
+ if (ret < 0)
+ {
+ fprintf(stderr, "pipe: %s\n", strerror(errno));
+ exit(1);
+ }
+
+ if (!fork())
+ {
+ close(pipefd[1]);
+ if (read(pipefd[0], buf, KMAX) == 0)
+ {
+ exit(0);
+ }
+ exit(1);
+ }
+
+ if (!fork())
+ {
+ close(pipefd[1]);
+ if (read(pipefd[0], buf, KMAX) == 0)
+ {
+ exit(0);
+ }
+ exit(1);
+ }
+
+ close(pipefd[0]);
+ close(pipefd[1]);
+
+ WAIT;
+
+ printf("%d passed. %d failed.\n", passed, failed);
+ return 0;
+}
diff --git a/user/usr/bin/tests/prime.c b/user/usr/bin/tests/prime.c
new file mode 100644
index 0000000..2e00bd1
--- /dev/null
+++ b/user/usr/bin/tests/prime.c
@@ -0,0 +1,107 @@
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+typedef uint64_t bitmask_word_t;
+#define BITMASK_WORD_BITWIDTH 64
+#define BITMASK_WORD_BITWIDTH_LOG2 6
+#define BITMASK_IDX(x) ((x) >> BITMASK_WORD_BITWIDTH_LOG2)
+#define BITMASK_POS(x) ((x) & ~(~0UL << BITMASK_WORD_BITWIDTH_LOG2))
+
+// 7 6 5 4 3 2 1 0 | 15 14 13 12 11 10 9 8
+#define BITMASK_POS_MASK(x) (1UL << BITMASK_POS(x))
+
+#define BITMASK_MAX_IDX(x) (BITMASK_IDX((x)-1UL) + 1UL)
+#define BITMASK_SIZE(x) (sizeof(bitmask_word_t) * BITMASK_MAX_IDX(x))
+#define GET_BIT(bitmask, x) \
+ (((bitmask_word_t *)bitmask)[BITMASK_IDX(x)] & BITMASK_POS_MASK(x))
+#define SET_BIT(bitmask, x) \
+ (((bitmask_word_t *)bitmask)[BITMASK_IDX(x)] |= BITMASK_POS_MASK(x))
+#define UNSET_BIT(bitmask, x) \
+ (((bitmask_word_t *)bitmask)[BITMASK_IDX(x)] &= ~BITMASK_POS_MASK(x))
+
+inline uint64_t *find_ne64(const uint64_t not, const uint64_t *start,
+ size_t count)
+{
+ uint64_t *ret;
+ __asm__ volatile(
+ "cld; repe; scasq; xor %%rax, %%rax; setz %%al; add %%rax, %%rcx;"
+ : "=D"(ret), "=c"(count)
+ : "A"(not), "D"(start), "c"(count)
+ : "cc");
+ return count ? (ret - 1) : NULL;
+}
+
+size_t next_set_bit(const bitmask_word_t *bitmask, size_t start,
+ size_t max_idx)
+{
+ size_t idx = BITMASK_IDX(start);
+ bitmask_word_t copy = (bitmask[idx++] >> BITMASK_POS(start)) - 1;
+ if (copy)
+ {
+ return start + __builtin_ctzl(copy);
+ }
+ if (idx < max_idx)
+ {
+ uint64_t *end = find_ne64(0, bitmask + idx, max_idx - idx);
+ if (end)
+ return (((end - bitmask) << BITMASK_WORD_BITWIDTH_LOG2) +
+ (unsigned)__builtin_ctzl(*end));
+ }
+ return ~0UL;
+}
+
+long compute_largest_prime(long n)
+{
+ if (n <= 1)
+ return -1;
+ if (n <= 3)
+ return n;
+ n = (n - 1) >> 1;
+
+ bitmask_word_t *bitmask =
+ malloc(BITMASK_SIZE(n)); // GET_BIT(i) --> is 2 * i + 1 prime?
+ size_t max_idx = BITMASK_MAX_IDX(n);
+ memset(bitmask, 0xff, BITMASK_SIZE(n));
+
+ UNSET_BIT(bitmask, 0);
+ size_t prime_idx = 1;
+
+ while (1)
+ {
+ long increment = (prime_idx << 1) | 1; // prime_idx * 2 + 1
+ for (long multiple = prime_idx + increment; multiple <= n;
+ multiple += increment)
+ {
+ UNSET_BIT(bitmask, multiple);
+ }
+ // size_t next_prime_idx = prime_idx + 1;
+ // while (!GET_BIT(bitmask, next_prime_idx) && next_prime_idx <=
+ // n)
+ // next_prime_idx++;
+
+ size_t next_prime_idx = next_set_bit(bitmask, prime_idx, max_idx);
+
+ if (next_prime_idx > (size_t)n)
+ break;
+ prime_idx = next_prime_idx;
+ }
+
+ free(bitmask);
+ return (prime_idx << 1) | 1;
+}
+
+int main(int argc, char *argv[], char *envp[])
+{
+ if (argc <= 1)
+ {
+ fprintf(stderr,
+ "USAGE: \"prime <n>\" to compute the largest prime <= n\n");
+ exit(1);
+ }
+ long n = strtol(argv[1], NULL, 0);
+ fprintf(stdout, "%ld\n", compute_largest_prime(n));
+ return 0;
+}
diff --git a/user/usr/bin/tests/s5fstest.c b/user/usr/bin/tests/s5fstest.c
new file mode 100644
index 0000000..e2441ac
--- /dev/null
+++ b/user/usr/bin/tests/s5fstest.c
@@ -0,0 +1,332 @@
+//
+// Tests some edge cases of s5fs
+// Ported to user mode by twd in 7/2018
+//
+
+#ifdef __KERNEL__
+
+#include "config.h"
+#include "errno.h"
+#include "globals.h"
+#include "limits.h"
+
+#include "test/usertest.h"
+
+#include "util/debug.h"
+#include "util/printf.h"
+#include "util/string.h"
+
+#include "fs/fcntl.h"
+#include "fs/lseek.h"
+#include "fs/s5fs/s5fs.h"
+#include "fs/vfs_syscall.h"
+
+#else
+
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <test/test.h>
+#include <unistd.h>
+
+#define do_write write
+#define do_read read
+#define do_lseek lseek
+#define do_open(x, y) open((x), (y), 0777)
+#define do_link link
+#define do_unlink unlink
+#define do_mknod mknod
+#define do_close close
+#define do_mkdir(x) mkdir((x), 0777)
+#define do_chdir chdir
+#define do_rmdir rmdir
+
+#define S5_BLOCK_SIZE 4096
+#define S5_MAX_FILE_BLOCKS 1052
+
+#define KASSERT(x) test_assert(x, NULL)
+#define dbg(code, fmt, args...) printf(fmt, ##args)
+
+#endif
+
+#define BUFSIZE 256
+#define BIG_BUFSIZE 2056
+
+#define S5_MAX_FILE_SIZE S5_BLOCK_SIZE *S5_MAX_FILE_BLOCKS
+
+static void get_file_name(char *buf, size_t sz, int fileno)
+{
+ snprintf(buf, sz, "file%d", fileno);
+}
+
+// Write to a fail forever until it is either filled up or we get an error.
+static int write_until_fail(int fd)
+{
+ size_t total_written = 0;
+ char buf[BIG_BUFSIZE] = {42};
+ while (total_written < S5_MAX_FILE_SIZE)
+ {
+ int res = do_write(fd, buf, BIG_BUFSIZE);
+ if (res < 0)
+ {
+ return res;
+ }
+ total_written += res;
+ }
+ KASSERT(total_written == S5_MAX_FILE_SIZE);
+ KASSERT(do_lseek(fd, 0, SEEK_END) == S5_MAX_FILE_SIZE);
+
+ return 0;
+}
+
+// Read n bytes from the file, and check they're all 0
+// We do this in increments of big_bufsize because we might want to read
+// like a million bytes from the file
+static int is_first_n_bytes_zero(int fd, int n)
+{
+ int total_read = 0;
+ while (total_read < n)
+ {
+ int amt_to_read = MIN(BIG_BUFSIZE, n - total_read);
+ char buf[BIG_BUFSIZE] = {1};
+ int res = do_read(fd, buf, amt_to_read);
+ if (res != amt_to_read)
+ {
+ dbg(DBG_TESTFAIL, "do_read result was %d\n", res);
+ return 0;
+ // KASSERT("Could not read from file" && 0);
+ }
+ total_read += res;
+
+ // Check everything that we read is indeed 0
+ for (int i = 0; i < amt_to_read; ++i)
+ {
+ if (buf[i] != 0)
+ {
+ dbg(DBG_TESTFAIL, "buf contains char %d\n", (int)buf[i]);
+ return 0;
+ }
+ }
+ }
+
+ return 1;
+}
+
+static void test_running_out_of_inodes()
+{
+ // Open a ton of files until we get an error
+ int res = -1;
+ int fileno = 0;
+ char filename[BUFSIZE];
+
+ // open files til we get an error
+ while (1)
+ {
+ get_file_name(filename, BUFSIZE, fileno);
+ res = do_open(filename, O_RDONLY | O_CREAT);
+ if (res >= 0)
+ {
+ fileno++;
+ test_assert(do_close(res) == 0, "couldn't close");
+ }
+ else
+ {
+ break;
+ }
+ }
+#ifdef __KERNEL__
+ test_assert(res == -ENOSPC, "Did not get ENOSPC error");
+#else
+ test_assert(errno == ENOSPC, "Did not get ENOSPC error");
+#endif
+
+ // make sure mkdir fails now that we're out of inodes
+ test_assert(do_mkdir("directory") < 0, "do_mkdir worked!?");
+#ifdef __KERNEL__
+ test_assert(res == -ENOSPC, "unexpected error");
+#else
+ test_assert(errno == ENOSPC, "unexpected error");
+#endif
+
+#ifdef __KERNEL__
+ test_assert(do_mknod("nod", S_IFCHR, 123) != 0, "mknod worked!?");
+ test_assert(res == -ENOSPC, "wrong error code");
+#endif
+
+ // the last file we tried to open failed
+ fileno--;
+
+ do
+ {
+ get_file_name(filename, BUFSIZE, fileno);
+ res = do_unlink(filename);
+ test_assert(res == 0, "couldnt unlink");
+ fileno--;
+ } while (fileno >= 0);
+
+ // Now we've freed all the files, try to create another file
+ int fd = do_open("file", O_RDONLY | O_CREAT);
+ test_assert(fd >= 0, "Still cannot create files");
+ test_assert(do_close(fd) == 0, "Could not do_close fd");
+ test_assert(do_unlink("file") == 0, "Could not remove file");
+}
+
+static void test_filling_file()
+{
+ int res = 0;
+ int fd = do_open("hugefile", O_RDWR | O_CREAT);
+ KASSERT(fd >= 0);
+
+ res = write_until_fail(fd);
+ test_assert(res == 0, "Did not write to entire file");
+
+ // make sure all other writes are unsuccessful/dont complete
+ char buf[BIG_BUFSIZE] = {0};
+ res = do_write(fd, buf, sizeof(buf));
+ test_assert(res < 0, "Able to write although the file is full");
+#ifdef __KERNEL__
+ test_assert(res == -EFBIG || res == -EINVAL, "Wrong error code");
+#else
+ test_assert(errno == EFBIG || errno == EINVAL, "Wrong error code");
+#endif
+
+ test_assert(do_close(fd) == 0, "couldnt close hugefile");
+ test_assert(do_unlink("hugefile") == 0, "couldnt unlink hugefile");
+}
+
+// Fill up the disk. Apparently to do this, we should need to fill up one
+// entire file, then start to fill up another. We should eventually get
+// the ENOSPC error
+static void test_running_out_of_blocks()
+{
+ int res = 0;
+
+ int fd1 = do_open("fullfile", O_RDWR | O_CREAT);
+
+ res = write_until_fail(fd1);
+ test_assert(res == 0, "Ran out of space quicker than we expected");
+
+ int fd2 = do_open("partiallyfullfile", O_RDWR | O_CREAT);
+ res = write_until_fail(fd2);
+#ifdef __KERNEL__
+ test_assert(res == -ENOSPC, "Did not get nospc error");
+#else
+ test_assert(errno == ENOSPC, "Did not get nospc error");
+#endif
+
+ test_assert(do_close(fd1) == 0, "could not close");
+ test_assert(do_close(fd2) == 0, "could not close");
+
+ test_assert(do_unlink("fullfile") == 0, "couldnt do_unlink file");
+ test_assert(do_unlink("partiallyfullfile") == 0, "couldnt do_unlink file");
+}
+
+// Open a new file, write to some random address in the file,
+// and make sure everything up to that is all 0s.
+static int test_sparseness_direct_blocks()
+{
+ const char *filename = "sparsefile";
+ int fd = do_open(filename, O_RDWR | O_CREAT);
+
+ // Now write to some random address that'll be in a direct block
+ const int addr = 10000;
+ const char *b = "iboros";
+ const int sz = strlen(b);
+
+ test_assert(do_lseek(fd, addr, SEEK_SET) == addr, "couldnt seek");
+ test_assert(do_write(fd, b, sz) == sz, "couldnt write to random address");
+
+ test_assert(do_lseek(fd, 0, SEEK_SET) == 0, "couldnt seek back to begin");
+ test_assert(is_first_n_bytes_zero(fd, addr) == 1, "sparseness don't work");
+
+ // Get rid of this file
+ test_assert(do_close(fd) == 0, "couldn't close file");
+ test_assert(do_unlink(filename) == 0, "couldnt unlink file");
+
+ return 0;
+}
+
+/*
+ * Fixed by twd to do a better test in 7/2018
+ */
+static int test_sparseness_indirect_blocks()
+{
+ const char *filename = "bigsparsefile";
+ int fd = do_open(filename, O_RDWR | O_CREAT);
+
+ // first partially fill the first block of the file
+ char randomgarbage[4050];
+ test_assert(do_write(fd, randomgarbage, 4050) == 4050,
+ "couldn't write to first block");
+
+ // Now write to some random address that'll be in an indirect block
+ const int addr = 1000000;
+ const char *b = "iboros";
+ const int sz = strlen(b);
+
+ test_assert(do_lseek(fd, addr, SEEK_SET) == addr, "couldnt seek");
+ test_assert(do_write(fd, b, sz) == sz, "couldnt write to random address");
+
+ test_assert(do_lseek(fd, 4050, SEEK_SET) == 4050,
+ "couldnt seek back to begin");
+ test_assert(is_first_n_bytes_zero(fd, addr - 4050) == 1,
+ "sparseness don't work");
+
+ // Get rid of this file
+ test_assert(do_close(fd) == 0, "couldn't close file");
+ test_assert(do_unlink(filename) == 0, "couldnt unlink file");
+
+ return 0;
+}
+
+#ifdef __KERNEL__
+extern uint64_t jiffies;
+#endif
+
+static void seed_randomness()
+{
+#ifdef __KERNEL__
+ srand(jiffies);
+#else
+ srand(time(NULL));
+#endif
+ rand();
+}
+
+#ifdef __KERNEL__
+int s5fstest_main()
+#else
+
+int main()
+#endif
+{
+ dbg(DBG_TEST, "Starting S5FS test\n");
+
+ test_init();
+ seed_randomness();
+
+ KASSERT(do_mkdir("s5fstest") == 0);
+ KASSERT(do_chdir("s5fstest") == 0);
+ dbg(DBG_TEST, "Test dir initialized\n");
+
+ dbg(DBG_TEST, "Testing sparseness for direct blocks\n");
+ test_sparseness_direct_blocks();
+ dbg(DBG_TEST, "Testing sparseness for indirect blocks\n");
+ test_sparseness_indirect_blocks();
+
+ dbg(DBG_TEST, "Testing running out of inodes\n");
+ test_running_out_of_inodes();
+ dbg(DBG_TEST, "Testing filling a file to max capacity\n");
+ test_filling_file();
+ dbg(DBG_TEST, "Testing using all available blocks on disk\n");
+ test_running_out_of_blocks();
+
+ test_assert(do_chdir("..") == 0, "");
+ test_assert(do_rmdir("s5fstest") == 0, "");
+
+ test_fini();
+
+ return 0;
+}
diff --git a/user/usr/bin/tests/stress.c b/user/usr/bin/tests/stress.c
new file mode 100644
index 0000000..1920fcd
--- /dev/null
+++ b/user/usr/bin/tests/stress.c
@@ -0,0 +1,476 @@
+/*
+ * File: stress.c
+ * Date: 16 November 1998
+ * Acct: David Powell (dep)
+ * Desc: Miscellaneous VM tests
+ */
+
+#include "mm.h"
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/mman.h>
+#include <unistd.h>
+
+static void check_failed(const char *cmd)
+{
+ (void)printf("stress: %s failed: errno %d\n", cmd, errno);
+ exit(1);
+}
+
+static int myfork()
+{
+ int result;
+
+ result = fork();
+ if (result == -1)
+ {
+ (void)printf("Fork failed (errno=%d)\n", errno);
+ exit(1);
+ }
+
+ sched_yield();
+ return result;
+}
+
+static void fork_test()
+{
+ (void)printf("-- Fork torture test start\n");
+
+ (void)printf(
+ "The final test: forking up a storm.\n"
+ "If this doesn't crash your kernel, "
+ "you might be in good shape\n");
+ (void)printf("(note that this is running in the background)\n");
+ if (!myfork())
+ {
+ for (;;)
+ {
+ if (myfork())
+ {
+ exit(0);
+ }
+ }
+ }
+}
+
+static void cow_fork()
+{
+ int status;
+ int foo = 0;
+
+ (void)printf("-- COW fork test start\n");
+
+ if (!myfork())
+ {
+ /* We are in the child process, and should be accessing
+ * our own memory
+ */
+ foo = 1;
+ exit(0);
+ }
+
+ if (wait(&status) == -1)
+ {
+ (void)printf("wait failed (errno=%d)\n", errno);
+ exit(1);
+ }
+
+ if (foo)
+ {
+ (void)printf(
+ "Data changed in child affected parent.\n"
+ "Make sure you mark writable private mappings copy-on-write.\n");
+ (void)printf("Copy-on-write failed.\n");
+ exit(1);
+ }
+
+ (void)printf("-- COW fork test passed\n");
+}
+
+static void fault_test()
+{
+ int status;
+
+ (void)printf("-- fault test start\n");
+
+ (void)printf(
+ "Fault test. If this hangs, check your page fault handler...\n");
+ (void)printf("Do you properly kill processes that segv? ");
+
+ if (!myfork())
+ {
+ *(int *)0 = 0;
+ printf("P%d didn't fault!\n", getpid());
+ exit(0);
+ }
+
+ if (wait(&status) == -1)
+ {
+ (void)printf("wait failed (errno=%d)\n", errno);
+ exit(1);
+ }
+ if (status)
+ {
+ (void)printf("yes\n");
+ ;
+ }
+ else
+ {
+ (void)printf("no\n");
+ exit(1);
+ }
+
+ (void)printf("-- fault test passed\n");
+}
+
+void mmap_test()
+{
+ int fd;
+ void *addr1, *addr2;
+ const char *str1 = "Coconuts!!!!\n";
+ const char *str2 = "Hello there.\n";
+ size_t len;
+
+ (void)printf("-- mmap test start\n");
+
+ /* Create a file with some data. */
+
+ fd = open("/test/stress0", O_RDWR | O_CREAT, 0);
+ if (fd < 0)
+ {
+ check_failed("open");
+ }
+
+ /* Give us some space */
+ if (1 > write(fd, "\0", 1))
+ {
+ check_failed("write");
+ }
+
+ /* Map the file MAP_PRIVATE */
+
+ printf("MAP_PRIVATE test\n");
+ len = strlen(str1) + 1;
+ addr1 = mmap(0, len, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
+ if (addr1 == MAP_FAILED)
+ {
+ check_failed("mmap");
+ }
+ addr2 = mmap(0, len, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0);
+ if (addr2 == MAP_FAILED)
+ {
+ check_failed("mmap");
+ }
+
+ if (close(fd))
+ {
+ check_failed("close");
+ }
+
+ printf("writing into %p\n", addr1);
+ (void)snprintf((char *)addr1, len, "%s", str1);
+
+ /* Read from the private mapped page for good measure
+ * (this _shouldn't_ do anything) */
+ printf("reading from privmap page\n");
+
+ /* Verify that the string is initially in the mapping. */
+
+ printf("making sure string in mapping okay\n");
+ if (strcmp(str1, (char *)addr1))
+ {
+ (void)printf("stress: write to shared mapping failed\n");
+ exit(1);
+ }
+ if (strcmp(str1, (char *)addr2))
+ {
+ (void)printf("stress: private mapping prematurely copied\n");
+ exit(1);
+ }
+
+ (void)snprintf((char *)addr2, len, "%s", str2);
+
+ /* Verify that the string has been overwritten in the mapping. */
+
+ printf("making sure overwriting okay\n");
+ if (strcmp(str2, (char *)addr2))
+ {
+ (void)printf("stress: write to private mapping failed\n");
+ exit(1);
+ }
+
+ if (!strcmp(str2, (char *)addr1))
+ {
+ (void)printf("stress: wrote through private mapping!\n");
+ exit(1);
+ }
+
+ printf("unmapping at %p\n", addr1);
+ if (munmap(addr1, len))
+ {
+ check_failed("munmap");
+ }
+ printf("unmapping at %p\n", addr2);
+ if (munmap(addr2, len))
+ {
+ check_failed("munmap");
+ }
+
+ if (!munmap((void *)USER_MEM_HIGH, 15) || (errno != EINVAL))
+ {
+ printf("munmap bad one fail errno=%d einval=%d\n", errno, EINVAL);
+ exit(1);
+ }
+
+ if (!munmap(0, 0) || (errno != EINVAL))
+ {
+ printf("munmap bad two fail errno=%d einval=%d\n", errno, EINVAL);
+ exit(1);
+ }
+
+ if (!munmap((void *)137, 100) || (errno != EINVAL))
+ {
+ printf("munmap bad three fail errno=%d einval=%d\n", errno, EINVAL);
+ exit(1);
+ }
+
+ (void)printf("-- mmap test passed\n");
+}
+
+void null_test()
+{
+ int fd;
+ int nbytes;
+ char buf[256];
+
+ (void)printf("-- null test start\n");
+
+ fd = open("/dev/null", O_RDWR, 0600);
+ if (fd < 0)
+ {
+ check_failed("open");
+ }
+
+ (void)memset(buf, 0xCC, sizeof(buf));
+
+ /* Try writing to /dev/null. Should return buffer size.
+ */
+
+ nbytes = write(fd, buf, sizeof(buf));
+ if (nbytes != sizeof(buf))
+ {
+ check_failed("write");
+ }
+
+ /* Try reading from /dev/null. Should return zero.
+ */
+
+ nbytes = read(fd, buf, sizeof(buf));
+ if (nbytes != 0)
+ {
+ check_failed("read");
+ }
+
+ if (close(fd))
+ {
+ check_failed("close");
+ }
+
+ (void)printf("-- null test passed\n");
+}
+
+void zero_test()
+{
+ void *addr;
+ int fd;
+ char buf[256];
+ int nbytes;
+ unsigned int ii;
+ size_t len;
+ unsigned long *lp;
+ unsigned char *cp;
+
+ (void)printf("-- zero test start\n");
+
+ fd = open("/dev/zero", O_RDWR, 0600);
+ if (fd < 0)
+ {
+ check_failed("open");
+ }
+
+ /* Set buffer to a non-zero value, then read from /dev/zero
+ * and make sure that the buffer is cleared.
+ */
+
+ memset(buf, 0xCC, sizeof(buf));
+
+ nbytes = read(fd, buf, sizeof(buf));
+ if (nbytes != sizeof(buf))
+ {
+ check_failed("read");
+ }
+
+ for (ii = 0; ii < sizeof(buf); ii++)
+ {
+ if (buf[ii] != 0)
+ {
+ printf("read %x not zero\n", buf[ii]);
+ check_failed("verify read");
+ }
+ }
+
+ /* Map /dev/zero and make sure all pages are initially zero.
+ */
+
+ len = 8192 * 5;
+
+ addr = mmap(0, len, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0);
+ if (addr == MAP_FAILED)
+ {
+ check_failed("mmap");
+ }
+
+ if (close(fd))
+ {
+ check_failed("close");
+ }
+
+ cp = (unsigned char *)addr;
+ for (ii = 0; ii < len; ii++, cp++)
+ {
+ if (*cp != 0)
+ {
+ check_failed("verify mmap zeros");
+ }
+ }
+
+ /* ... make sure writes are allowed.
+ */
+
+ lp = (unsigned long *)addr;
+ for (ii = 0; ii < (len / sizeof(*lp)); ii++, lp++)
+ {
+ *lp = ii;
+ }
+
+ lp = (unsigned long *)addr;
+ for (ii = 0; ii < (len / sizeof(*lp)); ii++, lp++)
+ {
+ if (*lp != ii)
+ {
+ check_failed("verify map write");
+ }
+ }
+
+ if (munmap(addr, len))
+ {
+ check_failed("munmap");
+ }
+
+ (void)printf("-- zero test passed\n");
+}
+
+void wait_test()
+{
+ int status;
+
+ (void)printf("-- wait test start\n");
+
+ if (!wait(&status) || (errno != ECHILD))
+ {
+ (void)printf(
+ "error: wait() didn't return an error of "
+ "ECHILD when no children existed!\n");
+ exit(1);
+ }
+
+ (void)printf("-- wait test passed\n");
+}
+
+void brk_test()
+{
+ void *oldbrk1, *oldbrk2;
+ const void *brk_failed = (void *)-1;
+ int len;
+ unsigned int *tmp;
+ unsigned int ii;
+
+ (void)printf("-- brk test start\n");
+
+ /* A length which is not a page multiple, yet a multiple of 8.
+ */
+ len = 8192 * 5 + 128;
+
+ /* Try allocating some memory.
+ */
+ oldbrk1 = sbrk(len);
+ if (oldbrk1 == brk_failed)
+ {
+ check_failed("sbrk alloc");
+ }
+
+ /* Try writing to the memory.
+ */
+ printf("writing to memory at %p\n", oldbrk1);
+ tmp = (unsigned int *)oldbrk1;
+ for (ii = 0; ii < (len / sizeof(int)); ii++)
+ {
+ *tmp++ = ii;
+ }
+
+ /* Try verifying what we wrote.
+ */
+ printf("verifying memory\n");
+ tmp = (unsigned int *)oldbrk1;
+ for (ii = 0; ii < (len / sizeof(int)); ii++)
+ {
+ if (*tmp++ != ii)
+ {
+ (void)printf("verify failed at 0x%lx\n", (unsigned long)tmp);
+ exit(1);
+ }
+ }
+
+ /* Try freeing the memory.
+ */
+ printf("freeing memory\n");
+ oldbrk2 = sbrk(-len);
+ if (oldbrk2 == brk_failed)
+ {
+ check_failed("sbrk dealloc");
+ }
+
+ /* oldbrk2 should be at least "len" greater than oldbrk1.
+ */
+ if ((unsigned long)oldbrk2 < ((unsigned long)oldbrk1 + len))
+ {
+ (void)printf("sbrk didn't return old brk??\n");
+ exit(1);
+ }
+
+ (void)printf("-- brk test passed\n");
+}
+
+int main(int argc, char **argv)
+{
+ (void)printf("Congrats! You're running this executable.\n");
+ (void)printf("Now let's see how you handle the tests...\n");
+
+ mmap_test();
+
+ null_test();
+ zero_test();
+ brk_test();
+
+ fault_test();
+
+ wait_test();
+ cow_fork();
+
+ fork_test();
+
+ return 0;
+}
diff --git a/user/usr/bin/tests/vfstest.c b/user/usr/bin/tests/vfstest.c
new file mode 100644
index 0000000..ed9ca44
--- /dev/null
+++ b/user/usr/bin/tests/vfstest.c
@@ -0,0 +1,1172 @@
+#ifdef __KERNEL__
+
+#include "config.h"
+#include "errno.h"
+#include "globals.h"
+#include "kernel.h"
+#include "limits.h"
+
+#include "util/debug.h"
+#include "util/printf.h"
+#include "util/string.h"
+
+#include "proc/kthread.h"
+#include "proc/proc.h"
+
+#include "fs/dirent.h"
+#include "fs/fcntl.h"
+#include "fs/lseek.h"
+#include "fs/stat.h"
+#include "fs/vfs_syscall.h"
+#include "mm/kmalloc.h"
+#include "mm/mman.h"
+
+#include "test/usertest.h"
+#include "test/vfstest/vfstest.h"
+
+#undef __VM__
+
+#else
+
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <dirent.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <weenix/syscall.h>
+
+#include <test/test.h>
+
+#endif
+
+/* Some helpful strings */
+#define LONGNAME "supercalifragilisticexpialidocious" /* Longer than NAME_LEN \
+ */
+
+#define TESTSTR \
+ "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do " \
+ "eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad " \
+ "minim " \
+ "veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea " \
+ "commodo " \
+ "consequat. Duis aute irure dolor in reprehenderit in voluptate velit " \
+ "esse cillum " \
+ "dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non " \
+ "proident, " \
+ "sunt in culpa qui officia deserunt mollit anim id est laborum."
+
+#define SHORTSTR "Quidquid latine dictum, altum videtur"
+
+static char root_dir[64];
+
+static int makedirs(const char *dir)
+{
+ int ret = 0;
+ char *d, *p;
+
+ if (NULL == (d = malloc(strlen(dir) + 1)))
+ {
+ return ENOMEM;
+ }
+ strcpy(d, dir);
+
+ p = d;
+ while (NULL != (p = strchr(p + 1, '/')))
+ {
+ *p = '\0';
+ if (0 != mkdir(d, 0777) && EEXIST != errno)
+ {
+ ret = errno;
+ goto error;
+ }
+ *p = '/';
+ }
+ if (0 != mkdir(d, 0777) && EEXIST != errno)
+ {
+ ret = errno;
+ goto error;
+ }
+
+error:
+ free(d);
+ return ret;
+}
+
+static int getdent(const char *dir, dirent_t *dirent)
+{
+ int ret, fd = -1;
+
+ if (0 > (fd = open(dir, O_RDONLY, 0777)))
+ {
+ return -1;
+ }
+
+ ret = 1;
+ while (ret != 0)
+ {
+ if (0 > (ret = getdents(fd, dirent, sizeof(*dirent))))
+ {
+ return -1;
+ }
+ if (0 != strcmp(".", dirent->d_name) &&
+ 0 != strcmp("..", dirent->d_name))
+ {
+ close(fd);
+ return 1;
+ }
+ }
+
+ close(fd);
+ return 0;
+}
+
+static int removeall(const char *dir)
+{
+ int ret;
+ dirent_t dirent;
+ stat_t status;
+
+ if (0 > chdir(dir))
+ {
+ return errno;
+ }
+
+ ret = 1;
+ while (ret != 0)
+ {
+ if (0 > (ret = getdent(".", &dirent)))
+ {
+ return errno;
+ }
+ if (0 == ret)
+ {
+ break;
+ }
+
+ if (0 > stat(dirent.d_name, &status))
+ {
+ return errno;
+ }
+
+ if (S_ISDIR(status.st_mode))
+ {
+ if (0 > removeall(dirent.d_name))
+ {
+ return errno;
+ }
+ }
+ else
+ {
+ if (0 > unlink(dirent.d_name))
+ {
+ return errno;
+ }
+ }
+ }
+
+ if (0 > chdir(".."))
+ {
+ return errno;
+ }
+
+ if (0 > rmdir(dir))
+ {
+ return errno;
+ }
+
+ return 0;
+}
+
+static void vfstest_start(void)
+{
+ int err;
+
+ root_dir[0] = '\0';
+ do
+ {
+ snprintf(root_dir, sizeof(root_dir), "vfstest-%d-%d", getpid(), rand());
+ err = mkdir(root_dir, 0777);
+
+ if (errno == EEXIST)
+ {
+ break;
+ }
+
+ if (err && errno != EEXIST)
+ {
+ printf("Failed to make test root directory: %s\n", strerror(errno));
+ exit(errno);
+ }
+ } while (err != 0);
+ printf("Created test root directory: ./%s\n", root_dir);
+}
+
+/*
+ * Terminates the testing environment
+ */
+static void vfstest_term(void)
+{
+ if (0 != removeall(root_dir))
+ {
+ fprintf(stderr, "ERROR: could not remove testing root %s: %s\n",
+ root_dir, strerror(errno));
+ exit(-1);
+ }
+ printf("Removed test root directory: ./%s\n", root_dir);
+}
+
+#define paths_equal(p1, p2) \
+ do \
+ { \
+ int __r; \
+ stat_t __s1, __s2; \
+ if (__r = makedirs(p1), !test_assert(0 == __r, "makedirs(\"%s\"): %s", \
+ p1, test_errstr(__r))) \
+ break; \
+ if (__r = stat(p1, &__s1), !test_assert(0 == __r, "stat(\"%s\"): %s", \
+ p1, test_errstr(errno))) \
+ break; \
+ if (__r = stat(p2, &__s2), !test_assert(0 == __r, "stat(\"%s\"): %s", \
+ p2, test_errstr(errno))) \
+ break; \
+ test_assert(__s1.st_ino == __s2.st_ino, \
+ "paths_equals(\"%s\" (ino %d), \"%s\" (ino %d))", p1, \
+ __s1.st_ino, p2, __s2.st_ino); \
+ } while (0);
+
+#define syscall_fail(expr, err) \
+ (test_assert((errno = 0, -1 == (expr)), \
+ "\nunexpected success, wanted %s (%d)", test_errstr(err), \
+ err) \
+ ? test_assert((expr, errno == err), \
+ "\nexpected %s (%d)" \
+ "\ngot %s (%d)", \
+ test_errstr(err), err, test_errstr(errno), errno) \
+ : 0)
+#define syscall_success(expr) \
+ test_assert(0 <= (expr), "\nunexpected error: %s (%d)", \
+ test_errstr(errno), errno)
+
+#define create_file(file) \
+ do \
+ { \
+ int __fd; \
+ if (syscall_success(__fd = open((file), O_RDONLY | O_CREAT, 0777))) \
+ { \
+ syscall_success(close(__fd)); \
+ } \
+ } while (0);
+#define read_fd(fd, size, goal) \
+ do \
+ { \
+ char __buf[64]; \
+ test_assert((ssize_t)strlen(goal) == read(fd, __buf, size), \
+ "\nread unexpected number of bytes"); \
+ test_assert(0 == memcmp(__buf, goal, strlen(goal)), \
+ "\nread data incorrect"); \
+ } while (0);
+#define test_fpos(fd, exp) \
+ do \
+ { \
+ int __g, __e = (exp); \
+ syscall_success(__g = lseek(fd, 0, SEEK_CUR)); \
+ test_assert((__g == __e), "fd %d fpos at %d, expected %d", fd, __g, \
+ __e); \
+ } while (0);
+
+static void vfstest_notdir(void)
+{
+ int fd;
+ stat_t s;
+ syscall_success(mkdir("realdir", 0));
+ syscall_success(fd = open("realdir/file", O_RDWR | O_CREAT, 0));
+ syscall_success(close(fd));
+ syscall_success(fd = open("realdir/file2", O_RDWR | O_CREAT, 0));
+ syscall_success(close(fd));
+
+ syscall_fail(open("realdir/file/nope", O_CREAT | O_RDWR, 0), ENOTDIR);
+ syscall_fail(link("realdir/file2", "realdir/file/nope"), ENOTDIR);
+ syscall_fail(link("realdir/file/nope", "realdir/file3"), ENOTDIR);
+ syscall_fail(unlink("realdir/file/nope"), ENOTDIR);
+ syscall_fail(rmdir("realdir/file/nope"), ENOTDIR);
+ syscall_fail(stat("realdir/file/nope", &s), ENOTDIR);
+ syscall_fail(rename("realdir/file2", "realdir/file/nope"), ENOTDIR);
+ syscall_fail(rename("realdir/file/nope", "realdir/file3"), ENOTDIR);
+
+ /* Cleanup */
+ syscall_success(unlink("realdir/file"));
+ syscall_success(unlink("realdir/file2"));
+ syscall_success(rmdir("realdir"));
+}
+
+static void vfstest_stat(void)
+{
+ int fd;
+ stat_t s;
+
+ syscall_success(mkdir("stat", 0));
+ syscall_success(chdir("stat"));
+
+ syscall_success(stat(".", &s));
+ test_assert(S_ISDIR(s.st_mode), NULL);
+
+ create_file("file");
+ syscall_success(stat("file", &s));
+ test_assert(S_ISREG(s.st_mode), NULL);
+
+ /* file size is correct */
+ syscall_success(fd = open("file", O_RDWR, 0));
+ syscall_success(write(fd, "foobar", 6));
+ syscall_success(stat("file", &s));
+ test_assert(s.st_size == 6, "unexpected file size");
+ syscall_success(close(fd));
+
+ /* error cases */
+#ifdef __VM__
+ syscall_fail(stat(".", NULL), EFAULT);
+#endif
+ syscall_fail(stat("noent", &s), ENOENT);
+
+ syscall_success(chdir(".."));
+}
+
+static void vfstest_mkdir(void)
+{
+ syscall_success(mkdir("mkdir", 0777));
+ syscall_success(chdir("mkdir"));
+
+ /* mkdir an existing file or directory */
+ create_file("file");
+ syscall_fail(mkdir("file", 0777), EEXIST);
+ syscall_success(mkdir("dir", 0777));
+ syscall_fail(mkdir("dir", 0777), EEXIST);
+
+ /* mkdir an invalid path */
+ syscall_fail(mkdir(LONGNAME, 0777), ENAMETOOLONG);
+ syscall_fail(mkdir("file/dir", 0777), ENOTDIR);
+ syscall_fail(mkdir("noent/dir", 0777), ENOENT);
+ syscall_fail(rmdir("file/dir"), ENOTDIR);
+ syscall_fail(rmdir("noent/dir"), ENOENT);
+ syscall_fail(rmdir("noent"), ENOENT);
+ syscall_fail(rmdir("."), EINVAL);
+ syscall_fail(rmdir(".."), ENOTEMPTY);
+ syscall_fail(rmdir("dir/."), EINVAL);
+ syscall_fail(rmdir("dir/.."), ENOTEMPTY);
+ syscall_fail(rmdir("noent/."), ENOENT);
+ syscall_fail(rmdir("noent/.."), ENOENT);
+
+ /* unlink and rmdir the inappropriate types */
+ syscall_fail(rmdir("file"), ENOTDIR);
+ syscall_fail(unlink("dir"), EPERM);
+
+ /* remove non-empty directory */
+ create_file("dir/file");
+ syscall_fail(rmdir("dir"), ENOTEMPTY);
+
+ /* remove empty directory */
+ syscall_success(unlink("dir/file"));
+ syscall_success(rmdir("dir"));
+
+ syscall_success(chdir(".."));
+}
+
+static void vfstest_chdir(void)
+{
+#define CHDIR_TEST_DIR "chdir"
+
+ stat_t ssrc, sdest, sparent, sdir;
+ stat_t rsrc, rdir;
+
+ /* chdir back and forth to CHDIR_TEST_DIR */
+ syscall_success(mkdir(CHDIR_TEST_DIR, 0777));
+ syscall_success(stat(".", &ssrc));
+ syscall_success(stat(CHDIR_TEST_DIR, &sdir));
+
+ test_assert(ssrc.st_ino != sdir.st_ino, NULL);
+
+ syscall_success(chdir(CHDIR_TEST_DIR));
+ syscall_success(stat(".", &sdest));
+ syscall_success(stat("..", &sparent));
+
+ test_assert(sdest.st_ino == sdir.st_ino, NULL);
+ test_assert(ssrc.st_ino == sparent.st_ino, NULL);
+ test_assert(ssrc.st_ino != sdest.st_ino, NULL);
+
+ syscall_success(chdir(".."));
+ syscall_success(stat(".", &rsrc));
+ syscall_success(stat(CHDIR_TEST_DIR, &rdir));
+
+ test_assert(rsrc.st_ino == ssrc.st_ino, NULL);
+ test_assert(rdir.st_ino == sdir.st_ino, NULL);
+
+ /* can't chdir into non-directory */
+ syscall_success(chdir(CHDIR_TEST_DIR));
+ create_file("file");
+ syscall_fail(chdir("file"), ENOTDIR);
+ syscall_fail(chdir("noent"), ENOENT);
+ syscall_success(chdir(".."));
+}
+
+static void vfstest_paths(void)
+{
+#define PATHS_TEST_DIR "paths"
+
+ stat_t s;
+
+ syscall_success(mkdir(PATHS_TEST_DIR, 0777));
+ syscall_success(chdir(PATHS_TEST_DIR));
+
+ syscall_fail(stat("", &s), EINVAL);
+
+ paths_equal(".", ".");
+ paths_equal("1/2/3", "1/2/3");
+ paths_equal("4/5/6", "4/5/6");
+
+ /* root directory */
+ paths_equal("/", "/");
+ paths_equal("/", "/..");
+ paths_equal("/", "/../");
+ paths_equal("/", "/../.");
+
+ /* . and .. */
+ paths_equal(".", "./.");
+ paths_equal(".", "1/..");
+ paths_equal(".", "1/../");
+ paths_equal(".", "1/2/../..");
+ paths_equal(".", "1/2/../..");
+ paths_equal(".", "1/2/3/../../..");
+ paths_equal(".", "1/../1/..");
+ paths_equal(".", "1/../4/..");
+ paths_equal(".", "1/../1/..");
+ paths_equal(".", "1/2/3/../../../4/5/6/../../..");
+ paths_equal(".", "1/./2/./3/./.././.././.././4/./5/./6/./.././.././..");
+
+ /* extra slashes */
+ paths_equal("1/2/3", "1/2/3/");
+ paths_equal("1/2/3", "1//2/3");
+ paths_equal("1/2/3", "1/2//3");
+ paths_equal("1/2/3", "1//2//3");
+ paths_equal("1/2/3", "1//2//3/");
+ paths_equal("1/2/3", "1///2///3///");
+
+ /* strange names */
+ paths_equal("-", "-");
+ paths_equal(" ", " ");
+ paths_equal("\\", "\\");
+ paths_equal("0", "0");
+
+ stat_t st;
+
+ /* error cases */
+ syscall_fail(stat("asdf", &st), ENOENT);
+ syscall_fail(stat("1/asdf", &st), ENOENT);
+ syscall_fail(stat("1/../asdf", &st), ENOENT);
+ syscall_fail(stat("1/2/asdf", &st), ENOENT);
+
+ create_file("1/file");
+ syscall_fail(open("1/file/other", O_RDONLY, 0777), ENOTDIR);
+ syscall_fail(open("1/file/other", O_RDONLY | O_CREAT, 0777), ENOTDIR);
+
+ syscall_success(chdir(".."));
+}
+
+static void vfstest_fd(void)
+{
+#define FD_BUFSIZE 5
+#define BAD_FD 20
+#define HUGE_FD 9999
+
+ int fd1, fd2;
+ char buf[FD_BUFSIZE];
+ struct dirent d;
+
+ syscall_success(mkdir("fd", 0));
+ syscall_success(chdir("fd"));
+
+ /* read/write/close/getdents/dup nonexistent file descriptors */
+ syscall_fail(read(BAD_FD, buf, FD_BUFSIZE), EBADF);
+ syscall_fail(read(HUGE_FD, buf, FD_BUFSIZE), EBADF);
+ syscall_fail(read(-1, buf, FD_BUFSIZE), EBADF);
+
+ syscall_fail(write(BAD_FD, buf, FD_BUFSIZE), EBADF);
+ syscall_fail(write(HUGE_FD, buf, FD_BUFSIZE), EBADF);
+ syscall_fail(write(-1, buf, FD_BUFSIZE), EBADF);
+
+ syscall_fail(close(BAD_FD), EBADF);
+ syscall_fail(close(HUGE_FD), EBADF);
+ syscall_fail(close(-1), EBADF);
+
+ syscall_fail(lseek(BAD_FD, 0, SEEK_SET), EBADF);
+ syscall_fail(lseek(HUGE_FD, 0, SEEK_SET), EBADF);
+ syscall_fail(lseek(-1, 0, SEEK_SET), EBADF);
+
+ syscall_fail(getdents(BAD_FD, &d, sizeof(d)), EBADF);
+ syscall_fail(getdents(HUGE_FD, &d, sizeof(d)), EBADF);
+ syscall_fail(getdents(-1, &d, sizeof(d)), EBADF);
+
+ syscall_fail(dup(BAD_FD), EBADF);
+ syscall_fail(dup(HUGE_FD), EBADF);
+ syscall_fail(dup(-1), EBADF);
+
+ syscall_fail(dup2(BAD_FD, 25), EBADF);
+ syscall_fail(dup2(HUGE_FD, 25), EBADF);
+ syscall_fail(dup2(-1, 25), EBADF);
+
+ /* dup2 has some extra cases since it takes a second fd */
+ syscall_fail(dup2(0, HUGE_FD), EBADF);
+ syscall_fail(dup2(0, -1), EBADF);
+
+ /* if the fds are equal, but the first is invalid or out of the
+ * allowed range */
+ syscall_fail(dup2(BAD_FD, BAD_FD), EBADF);
+ syscall_fail(dup2(HUGE_FD, HUGE_FD), EBADF);
+ syscall_fail(dup2(-1, -1), EBADF);
+
+ /* dup works properly in normal usage */
+ create_file("file01");
+ syscall_success(fd1 = open("file01", O_RDWR, 0));
+ syscall_success(fd2 = dup(fd1));
+ test_assert(fd1 < fd2, "dup(%d) returned %d", fd1, fd2);
+ syscall_success(write(fd2, "hello", 5));
+ test_fpos(fd1, 5);
+ test_fpos(fd2, 5);
+ syscall_success(lseek(fd2, 0, SEEK_SET));
+ test_fpos(fd1, 0);
+ test_fpos(fd2, 0);
+ read_fd(fd1, 5, "hello");
+ test_fpos(fd1, 5);
+ test_fpos(fd2, 5);
+ syscall_success(close(fd2));
+
+ /* dup2 works properly in normal usage */
+ syscall_success(fd2 = dup2(fd1, 25));
+ test_assert(25 == fd2, "dup2(%d, 25) returned %d", fd1, fd2);
+ test_fpos(fd1, 5);
+ test_fpos(fd2, 5);
+ syscall_success(lseek(fd2, 0, SEEK_SET));
+ test_fpos(fd1, 0);
+ test_fpos(fd2, 0);
+ syscall_success(close(fd2));
+
+ /* dup2-ing a file to itself works */
+ syscall_success(fd2 = dup2(fd1, fd1));
+ test_assert(fd1 == fd2, "dup2(%d, %d) returned %d", fd1, fd1, fd2);
+
+ /* dup2 closes previous file */
+ int fd3;
+ create_file("file02");
+ syscall_success(fd3 = open("file02", O_RDWR, 0));
+ syscall_success(fd2 = dup2(fd1, fd3));
+ test_assert(fd2 == fd3, "dup2(%d, %d) returned %d", fd1, fd3, fd2);
+ test_fpos(fd1, 0);
+ test_fpos(fd2, 0);
+ syscall_success(lseek(fd2, 5, SEEK_SET));
+ test_fpos(fd1, 5);
+ test_fpos(fd2, 5);
+ syscall_success(close(fd2));
+ syscall_success(close(fd1));
+
+ syscall_success(chdir(".."));
+}
+
+static void vfstest_memdev(void)
+{
+ int res, fd;
+ char def = 'a';
+ char buf[4096];
+
+ res = 1;
+
+ memset(buf, def, sizeof(buf));
+
+ syscall_success(fd = open("/dev/null", O_RDWR, 0));
+ syscall_success(res = write(fd, buf, sizeof(buf)));
+ test_assert(sizeof(buf) == res, "write of %d bytes /dev/null returned %d",
+ sizeof(buf), res);
+ syscall_success(res = read(fd, buf, sizeof(buf)));
+ test_assert(0 == res, "read of %d bytes /dev/null returned %d", sizeof(buf),
+ res);
+ test_assert(buf[sizeof(buf) / 2] == def,
+ "read from /dev/null changed buffer");
+ syscall_success(close(fd));
+
+ memset(buf, def, sizeof(buf));
+
+ syscall_success(fd = open("/dev/zero", O_RDWR, 0));
+ syscall_success(res = write(fd, buf, sizeof(buf)));
+ test_assert(sizeof(buf) == res, "write of %d bytes /dev/zero returned %d",
+ sizeof(buf), res);
+ syscall_success(res = read(fd, buf, sizeof(buf)));
+ test_assert(sizeof(buf) == res, "read of %d bytes /dev/zero returned %d",
+ sizeof(buf), res);
+ test_assert(buf[sizeof(buf) / 2] == 0,
+ "read from /dev/zero doesn't zero buffer");
+ syscall_success(close(fd));
+}
+
+static void vfstest_write(void)
+{
+#define CHUNK_SIZE 25
+#define NUM_CHUNKS 4
+ int fd, i, res;
+ stat_t s;
+ const char *str = "hello world";
+
+ char chunk[CHUNK_SIZE];
+ memcpy(chunk, str, strlen(str));
+ memset(chunk + strlen(str), 0, 25 - strlen(str));
+
+ syscall_success(mkdir("write", 0));
+ syscall_success(chdir("write"));
+
+ create_file("file");
+ syscall_success(fd = open("file", O_RDWR, 0));
+ for (i = 0; i < NUM_CHUNKS * CHUNK_SIZE; i += CHUNK_SIZE)
+ {
+ syscall_success(lseek(fd, i, SEEK_SET));
+ syscall_success(res = write(fd, str, strlen(str)));
+ test_assert((int)strlen(str) == res, "write of %d bytes returned %d",
+ strlen(str), res);
+ }
+ syscall_success(lseek(fd, 0, SEEK_SET));
+ for (i = 0; i < NUM_CHUNKS - 1; ++i)
+ {
+ char __buf[64];
+ test_assert(CHUNK_SIZE == read(fd, __buf, CHUNK_SIZE),
+ "\nread unexpected number of bytes");
+ test_assert(0 == memcmp(__buf, chunk, CHUNK_SIZE),
+ "\nread data incorrect");
+ }
+ char __buf[64];
+ test_assert((int)strlen(str) == read(fd, __buf, strlen(str)),
+ "\nread unexpected number of bytes");
+ test_assert(0 == memcmp(__buf, chunk, strlen(str)),
+ "\nread data incorrect");
+
+ const char *new_str = "testing";
+ const int loc = 37;
+ // writing to middle of file
+ // make sure file size doesn't change and the write is done at the correct
+ // location
+ syscall_success(lseek(fd, loc, SEEK_SET));
+ syscall_success(res = write(fd, new_str, strlen(new_str)));
+ test_assert((int)strlen(new_str) == res, "write of %d bytes returned %d",
+ strlen(new_str), res);
+ syscall_success(lseek(fd, loc, SEEK_SET));
+ read_fd(fd, strlen(new_str), new_str);
+ test_assert(lseek(fd, 0, SEEK_END) ==
+ (NUM_CHUNKS - 1) * CHUNK_SIZE + (int)strlen(str),
+ "file is not the right size");
+
+ syscall_success(close(fd));
+ syscall_success(unlink("file"));
+
+ syscall_success(chdir(".."));
+ syscall_success(rmdir("write"));
+}
+
+/* These operations should run for a long time and halt when the file
+ * descriptor overflows. */
+static void vfstest_infinite(void)
+{
+ int res, fd;
+ char buf[4096];
+
+ res = 1;
+ syscall_success(fd = open("/dev/null", O_WRONLY, 0));
+ for (int i = 0; i < 1000000; i++)
+ {
+ syscall_success(res = write(fd, buf, sizeof(buf)));
+ }
+ syscall_success(close(fd));
+
+ res = 1;
+ syscall_success(fd = open("/dev/zero", O_RDONLY, 0));
+ while (0 < res)
+ {
+ syscall_success(res = read(fd, buf, sizeof(buf)));
+ }
+ syscall_success(close(fd));
+}
+
+/*
+ * Tests open(), close(), and unlink()
+ * - Accepts only valid combinations of flags
+ * - Cannot open nonexistent file without O_CREAT
+ * - Cannot write to readonly file
+ * - Cannot read from writeonly file
+ * - Cannot close non-existent file descriptor
+ * - Lowest file descriptor is always selected
+ * - Cannot unlink a directory
+ # - Cannot unlink a non-existent file
+ * - Cannot open a directory for writing
+ * - File descriptors are correctly released when a proc exits
+ */
+static void vfstest_open(void)
+{
+#define OPEN_BUFSIZE 5
+
+ char buf[OPEN_BUFSIZE];
+ int fd, fd2;
+ stat_t s;
+
+ syscall_success(mkdir("open", 0777));
+ syscall_success(chdir("open"));
+
+ /* No invalid combinations of O_RDONLY, O_WRONLY, and O_RDWR. Since
+ * O_RDONLY is stupidly defined as 0, the only invalid possible
+ * combination is O_WRONLY|O_RDWR. */
+ syscall_fail(open("file01", O_WRONLY | O_RDWR | O_CREAT, 0), EINVAL);
+ syscall_fail(open("file01", O_RDONLY | O_RDWR | O_WRONLY | O_CREAT, 0),
+ EINVAL);
+
+ /* Cannot open nonexistent file without O_CREAT */
+ syscall_fail(open("file02", O_WRONLY, 0), ENOENT);
+ syscall_success(fd = open("file02", O_RDONLY | O_CREAT, 0));
+ syscall_success(close(fd));
+ syscall_success(unlink("file02"));
+ syscall_fail(stat("file02", &s), ENOENT);
+
+ /* Cannot create invalid files */
+ create_file("tmpfile");
+ syscall_fail(open("tmpfile/test", O_RDONLY | O_CREAT, 0), ENOTDIR);
+ syscall_fail(open("noent/test", O_RDONLY | O_CREAT, 0), ENOENT);
+ syscall_fail(open(LONGNAME, O_RDONLY | O_CREAT, 0), ENAMETOOLONG);
+
+ /* Cannot write to readonly file */
+ syscall_success(fd = open("file03", O_RDONLY | O_CREAT, 0));
+ syscall_fail(write(fd, "hello", 5), EBADF);
+ syscall_success(close(fd));
+
+ /* Cannot read from writeonly file. Note that we do not unlink() it
+ * from above, so we do not need O_CREAT set. */
+ syscall_success(fd = open("file03", O_WRONLY, 0));
+ syscall_fail(read(fd, buf, OPEN_BUFSIZE), EBADF);
+ syscall_success(close(fd));
+ syscall_success(unlink("file03"));
+ syscall_fail(stat("file03", &s), ENOENT);
+
+ /* Lowest file descriptor is always selected. */
+ syscall_success(fd = open("file04", O_RDONLY | O_CREAT, 0));
+ syscall_success(fd2 = open("file04", O_RDONLY, 0));
+ test_assert(fd2 > fd, "open() did not return lowest fd");
+ syscall_success(close(fd));
+ syscall_success(close(fd2));
+ syscall_success(fd2 = open("file04", O_WRONLY, 0));
+ test_assert(fd2 == fd, "open() did not return correct fd");
+ syscall_success(close(fd2));
+ syscall_success(unlink("file04"));
+ syscall_fail(stat("file04", &s), ENOENT);
+
+ /* Cannot open a directory for writing */
+ syscall_success(mkdir("file05", 0));
+ syscall_fail(open("file05", O_WRONLY, 0), EISDIR);
+ syscall_fail(open("file05", O_RDWR, 0), EISDIR);
+ syscall_success(rmdir("file05"));
+
+ /* Cannot unlink a directory */
+ syscall_success(mkdir("file06", 0));
+ syscall_fail(unlink("file06"), EPERM);
+ syscall_success(rmdir("file06"));
+ syscall_fail(unlink("."), EPERM);
+ syscall_fail(unlink(".."), EPERM);
+
+ /* Cannot unlink a non-existent file */
+ syscall_fail(unlink("file07"), ENOENT);
+
+ /* Cannot open a file as a directory */
+ create_file("file08");
+ syscall_fail(open("file08/", O_RDONLY, 0), ENOTDIR);
+ syscall_success(mkdir("dirA", 0777));
+ syscall_success(chdir("dirA"));
+ create_file("file09");
+ syscall_success(chdir(".."));
+ syscall_fail(open("dirA/file09/", O_RDONLY, 0), ENOTDIR);
+
+ /* Succeeds with trailing slash */
+ syscall_success(mkdir("dirB", 0777));
+ syscall_success(mkdir("dirB/dirC", 0777));
+ syscall_success(fd = open("dirB/", O_RDONLY, 0));
+ syscall_success(close(fd));
+ syscall_success(fd = open("dirB/dirC/", O_RDONLY, 0));
+ syscall_success(close(fd));
+
+ syscall_success(chdir(".."));
+}
+
+static void vfstest_read(void)
+{
+#define READ_BUFSIZE 256
+
+ int fd, ret;
+ char buf[READ_BUFSIZE];
+ stat_t s;
+
+ syscall_success(mkdir("read", 0777));
+ syscall_success(chdir("read"));
+
+ /* Can read and write to a file */
+ syscall_success(fd = open("file01", O_RDWR | O_CREAT, 0));
+ syscall_success(ret = write(fd, "hello", 5));
+ test_assert(5 == ret, "write(%d, \"hello\", 5) returned %d", fd, ret);
+ syscall_success(ret = lseek(fd, 0, SEEK_SET));
+ test_assert(0 == ret, "lseek(%d, 0, SEEK_SET) returned %d", fd, ret);
+ read_fd(fd, READ_BUFSIZE, "hello");
+ syscall_success(close(fd));
+
+ /* cannot read from a directory */
+ syscall_success(mkdir("dir01", 0));
+ syscall_success(fd = open("dir01", O_RDONLY, 0));
+ syscall_fail(read(fd, buf, READ_BUFSIZE), EISDIR);
+ syscall_success(close(fd));
+
+ /* Can seek to beginning, middle, and end of file */
+ syscall_success(fd = open("file02", O_RDWR | O_CREAT, 0));
+ syscall_success(write(fd, "hello", 5));
+
+#define test_lseek(expr, res) \
+ do \
+ { \
+ int __r = (expr); \
+ test_assert((res) == __r, #expr " returned %d, expected %d", __r, \
+ res); \
+ } while (0);
+
+ test_lseek(lseek(fd, 0, SEEK_CUR), 5);
+ read_fd(fd, 10, "");
+ test_lseek(lseek(fd, -1, SEEK_CUR), 4);
+ read_fd(fd, 10, "o");
+ test_lseek(lseek(fd, 2, SEEK_CUR), 7);
+ read_fd(fd, 10, "");
+ syscall_fail(lseek(fd, -8, SEEK_CUR), EINVAL);
+
+ test_lseek(lseek(fd, 0, SEEK_SET), 0);
+ read_fd(fd, 10, "hello");
+ test_lseek(lseek(fd, 3, SEEK_SET), 3);
+ read_fd(fd, 10, "lo");
+ test_lseek(lseek(fd, 7, SEEK_SET), 7);
+ read_fd(fd, 10, "");
+ syscall_fail(lseek(fd, -1, SEEK_SET), EINVAL);
+
+ test_lseek(lseek(fd, 0, SEEK_END), 5);
+ read_fd(fd, 10, "");
+ test_lseek(lseek(fd, -2, SEEK_END), 3);
+ read_fd(fd, 10, "lo");
+ test_lseek(lseek(fd, 3, SEEK_END), 8);
+ read_fd(fd, 10, "");
+ syscall_fail(lseek(fd, -8, SEEK_END), EINVAL);
+
+ syscall_fail(lseek(fd, 0, SEEK_SET + SEEK_CUR + SEEK_END), EINVAL);
+ syscall_success(close(fd));
+
+ /* O_APPEND works properly */
+ create_file("file03");
+ syscall_success(fd = open("file03", O_RDWR, 0));
+ test_fpos(fd, 0);
+ syscall_success(write(fd, "hello", 5));
+ test_fpos(fd, 5);
+ syscall_success(close(fd));
+
+ syscall_success(fd = open("file03", O_RDWR | O_APPEND, 0));
+ test_fpos(fd, 0);
+ syscall_success(write(fd, "hello", 5));
+ test_fpos(fd, 10);
+
+ syscall_success(lseek(fd, 0, SEEK_SET));
+ test_fpos(fd, 0);
+ read_fd(fd, 10, "hellohello");
+ syscall_success(lseek(fd, 5, SEEK_SET));
+ test_fpos(fd, 5);
+ syscall_success(write(fd, "again", 5));
+ test_fpos(fd, 15);
+ syscall_success(lseek(fd, 0, SEEK_SET));
+ test_fpos(fd, 0);
+ read_fd(fd, 15, "hellohelloagain");
+ syscall_success(close(fd));
+
+ /* seek and write beyond end of file */
+ create_file("file04");
+ syscall_success(fd = open("file04", O_RDWR, 0));
+ syscall_success(write(fd, "hello", 5));
+ test_fpos(fd, 5);
+ test_lseek(lseek(fd, 10, SEEK_SET), 10);
+ syscall_success(write(fd, "again", 5));
+ syscall_success(stat("file04", &s));
+ test_assert(s.st_size == 15, "actual size: %d", s.st_size);
+ test_lseek(lseek(fd, 0, SEEK_SET), 0);
+ test_assert(15 == read(fd, buf, READ_BUFSIZE),
+ "unexpected number of bytes read");
+ test_assert(0 == memcmp(buf, "hello\0\0\0\0\0again", 15),
+ "unexpected data read");
+ syscall_success(close(fd));
+
+ syscall_success(chdir(".."));
+}
+
+static void vfstest_getdents(void)
+{
+ int fd, ret;
+ dirent_t dirents[4];
+
+ syscall_success(mkdir("getdents", 0));
+ syscall_success(chdir("getdents"));
+
+ /* getdents works */
+ syscall_success(mkdir("dir01", 0));
+ syscall_success(mkdir("dir01/1", 0));
+ create_file("dir01/2");
+
+ syscall_success(fd = open("dir01", O_RDONLY, 0));
+ syscall_success(ret = getdents(fd, dirents, 4 * sizeof(dirent_t)));
+ test_assert(4 * sizeof(dirent_t) == ret, NULL);
+
+ syscall_success(ret = getdents(fd, dirents, sizeof(dirent_t)));
+ test_assert(0 == ret, NULL);
+
+ syscall_success(lseek(fd, 0, SEEK_SET));
+ test_fpos(fd, 0);
+ syscall_success(ret = getdents(fd, dirents, 2 * sizeof(dirent_t)));
+ test_assert(2 * sizeof(dirent_t) == ret, NULL);
+ syscall_success(ret = getdents(fd, dirents, 2 * sizeof(dirent_t)));
+ test_assert(2 * sizeof(dirent_t) == ret, NULL);
+ syscall_success(ret = getdents(fd, dirents, sizeof(dirent_t)));
+ test_assert(0 == ret, NULL);
+ syscall_success(close(fd));
+
+ /* Cannot call getdents on regular file */
+ create_file("file01");
+ syscall_success(fd = open("file01", O_RDONLY, 0));
+ syscall_fail(getdents(fd, dirents, 4 * sizeof(dirent_t)), ENOTDIR);
+ syscall_success(close(fd));
+
+ syscall_success(chdir(".."));
+}
+
+#ifdef __VM__
+/*
+ * Tests link(), rename(), and mmap() (and munmap, and brk).
+ * These functions are not supported on testfs, and not included in kernel-land
+ * vfs privtest (hence the name)
+ */
+
+static void vfstest_s5fs_vm(void)
+{
+ int fd, newfd, ret;
+ char buf[2048];
+ stat_t oldstatbuf, newstatbuf;
+ void *addr;
+ memset(&oldstatbuf, '\0', sizeof(stat_t));
+ memset(&newstatbuf, '\0', sizeof(stat_t));
+
+ syscall_success(mkdir("s5fs", 0));
+ syscall_success(chdir("s5fs"));
+
+ /* Open some stuff */
+ syscall_success(fd = open("oldchld", O_RDWR | O_CREAT, 0));
+ syscall_success(mkdir("parent", 0));
+
+ /* link/unlink tests */
+ syscall_success(link("oldchld", "newchld"));
+
+ /* Make sure stats match */
+ syscall_success(stat("oldchld", &oldstatbuf));
+ syscall_success(stat("newchld", &newstatbuf));
+ test_assert(0 == memcmp(&oldstatbuf, &newstatbuf, sizeof(stat_t)), NULL);
+
+ /* Make sure contents match */
+ syscall_success(newfd = open("newchld", O_RDWR, 0));
+ syscall_success(ret = write(fd, TESTSTR, strlen(TESTSTR)));
+ test_assert(ret == (int)strlen(TESTSTR), NULL);
+ syscall_success(ret = read(newfd, buf, strlen(TESTSTR)));
+ test_assert(ret == (int)strlen(TESTSTR), NULL);
+ test_assert(0 == strncmp(buf, TESTSTR, strlen(TESTSTR)),
+ "string is %.*s, expected %s", strlen(TESTSTR), buf, TESTSTR);
+
+ syscall_success(close(fd));
+ syscall_success(close(newfd));
+
+ /* Remove one, make sure the other remains */
+ syscall_success(unlink("oldchld"));
+ syscall_fail(mkdir("newchld", 0), EEXIST);
+ syscall_success(link("newchld", "oldchld"));
+
+ /* Link/unlink error cases */
+ syscall_fail(link("oldchld", "newchld"), EEXIST);
+ syscall_fail(link("oldchld", LONGNAME), ENAMETOOLONG);
+ syscall_fail(link("parent", "newchld"), EPERM);
+
+ /* only rename test */
+ /*syscall_success(rename("oldchld", "newchld"));*/
+
+ /* mmap/munmap tests */
+ syscall_success(fd = open("newchld", O_RDWR, 0));
+ test_assert(
+ MAP_FAILED != (addr = mmap(0, strlen(TESTSTR), PROT_READ | PROT_WRITE,
+ MAP_PRIVATE, fd, 0)),
+ NULL);
+ /* Check contents of memory */
+ test_assert(0 == memcmp(addr, TESTSTR, strlen(TESTSTR)), NULL);
+
+ /* Write to it -> we shouldn't pagefault */
+ memcpy(addr, SHORTSTR, strlen(SHORTSTR));
+ test_assert(0 == memcmp(addr, SHORTSTR, strlen(SHORTSTR)), NULL);
+
+ /* mmap the same thing on top of it, but shared */
+ test_assert(
+ MAP_FAILED != mmap(addr, strlen(TESTSTR), PROT_READ | PROT_WRITE,
+ MAP_SHARED | MAP_FIXED, fd, 0),
+ NULL);
+ /* Make sure the old contents were restored (the mapping was private) */
+ test_assert(0 == memcmp(addr, TESTSTR, strlen(TESTSTR)), NULL);
+
+ /* Now change the contents */
+ memcpy(addr, SHORTSTR, strlen(SHORTSTR));
+ /* mmap it on, private, on top again */
+ test_assert(
+ MAP_FAILED != mmap(addr, strlen(TESTSTR), PROT_READ | PROT_WRITE,
+ MAP_PRIVATE | MAP_FIXED, fd, 0),
+ NULL);
+ /* Make sure it changed */
+ test_assert(0 == memcmp(addr, SHORTSTR, strlen(SHORTSTR)), NULL);
+
+ /* Fork and try changing things */
+ if (!fork())
+ {
+ /* Child changes private mapping */
+ memcpy(addr, TESTSTR, strlen(TESTSTR));
+ exit(0);
+ }
+
+ /* Wait until child is done */
+ syscall_success(wait(0));
+
+ /* Make sure it's actually private */
+ test_assert(0 == memcmp(addr, SHORTSTR, strlen(SHORTSTR)), NULL);
+
+ /* Unmap it */
+ syscall_success(munmap(addr, 2048));
+
+ /* mmap errors */
+ test_assert(MAP_FAILED == mmap(0, 1024, PROT_READ, MAP_PRIVATE, 12, 0),
+ NULL);
+ test_assert(MAP_FAILED == mmap(0, 1024, PROT_READ, MAP_PRIVATE, -1, 0),
+ NULL);
+ test_assert(MAP_FAILED == mmap(0, 1024, PROT_READ, 0, fd, 0), NULL);
+ test_assert(MAP_FAILED == mmap(0, 1024, PROT_READ, MAP_FIXED, fd, 0), NULL);
+ test_assert(
+ MAP_FAILED == mmap(0, 1024, PROT_READ, MAP_FIXED | MAP_PRIVATE, fd, 0),
+ NULL);
+ test_assert(
+ MAP_FAILED == mmap(0, 1024, PROT_READ, MAP_PRIVATE, fd, 0x12345), NULL);
+ test_assert(MAP_FAILED == mmap((void *)0x12345, 1024, PROT_READ,
+ MAP_PRIVATE | MAP_FIXED, fd, 0),
+ NULL);
+ test_assert(MAP_FAILED == mmap(0, 0, PROT_READ, MAP_PRIVATE, fd, 0), NULL);
+ test_assert(MAP_FAILED == mmap(0, -1, PROT_READ, MAP_PRIVATE, fd, 0), NULL);
+ test_assert(
+ MAP_FAILED == mmap(0, 1024, PROT_READ, MAP_PRIVATE | MAP_FIXED, fd, 0),
+ NULL);
+ syscall_success(close(fd));
+
+ syscall_success(fd = open("newchld", O_RDONLY, 0));
+ test_assert(
+ MAP_FAILED == mmap(0, 1024, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0),
+ NULL);
+ syscall_success(close(fd));
+
+ /* TODO ENODEV (mmap a terminal)
+ EOVERFLOW (mmap SO MUCH of /dev/zero that fpointer would overflow) */
+
+ /* Also should test opening too many file descriptors somewhere */
+
+ /* munmap errors */
+ syscall_fail(munmap((void *)0x12345, 15), EINVAL);
+ syscall_fail(munmap(0x0, 15), EINVAL);
+ syscall_fail(munmap(addr, 0), EINVAL);
+ syscall_fail(munmap(addr, -1), EINVAL);
+
+ /* brk tests */
+ /* Set the break, and use the memory in question */
+ test_assert((void *)-1 != (addr = sbrk(128)), NULL);
+ memcpy(addr, TESTSTR, 128);
+ test_assert(0 == memcmp(addr, TESTSTR, 128), NULL);
+
+ /* Make sure that the brk is being saved properly */
+ test_assert((void *)((unsigned long)addr + 128) == sbrk(0), NULL);
+ /* Knock the break back down */
+ syscall_success(brk(addr));
+
+ /* brk errors */
+ syscall_fail(brk((void *)(&"brk")), ENOMEM);
+ syscall_fail(brk((void *)1), ENOMEM);
+ syscall_fail(brk((void *)&addr), ENOMEM);
+
+ syscall_success(chdir(".."));
+}
+#endif
+
+#ifdef __KERNEL__
+extern uint64_t jiffies;
+#endif
+
+static void seed_randomness()
+{
+#ifdef __KERNEL__
+ srand(jiffies);
+#else
+ srand(time(NULL));
+#endif
+ rand();
+}
+
+/*
+ * Finally, the main function.
+ */
+#ifndef __KERNEL__
+
+int main(int argc, char **argv)
+#else
+int vfstest_main(int argc, char **argv)
+#endif
+{
+ if (argc != 1)
+ {
+ fprintf(stderr, "USAGE: vfstest\n");
+ return 1;
+ }
+
+ seed_randomness();
+
+ test_init();
+ vfstest_start();
+
+ syscall_success(chdir(root_dir));
+
+ vfstest_notdir();
+ vfstest_stat();
+ vfstest_chdir();
+ vfstest_mkdir();
+ vfstest_paths();
+ vfstest_fd();
+ vfstest_open();
+ vfstest_read();
+ vfstest_getdents();
+ vfstest_memdev();
+ vfstest_write();
+
+#ifdef __VM__
+ vfstest_s5fs_vm();
+#endif
+
+ syscall_success(chdir(".."));
+
+ vfstest_term();
+ test_fini();
+
+ return 0;
+}
diff --git a/user/usr/bin/wc.c b/user/usr/bin/wc.c
new file mode 100644
index 0000000..f622614
--- /dev/null
+++ b/user/usr/bin/wc.c
@@ -0,0 +1,114 @@
+#include <ctype.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+
+#define BUFFER_SIZE 1024
+
+typedef struct count_results
+{
+ unsigned long long n_chars;
+ unsigned long long n_words;
+ unsigned long long n_lines;
+} count_results_t;
+
+char buf[BUFFER_SIZE];
+
+void print_counts(count_results_t *results, char *name)
+{
+ if (name)
+ {
+ printf("%10llu %10llu %10llu %10s\n", results->n_lines,
+ results->n_words, results->n_chars, name);
+ }
+ else
+ {
+ printf("%10llu %10llu %10llu\n", results->n_lines, results->n_words,
+ results->n_chars);
+ }
+}
+
+void count(int fd, char *name, count_results_t *results)
+{
+ size_t bytes_read;
+ unsigned int in_word, i;
+
+ in_word = 0;
+ while ((bytes_read = read(fd, buf, BUFFER_SIZE)) > 0)
+ {
+ for (i = 0; i < bytes_read; ++i)
+ {
+ if (isspace(buf[i]))
+ {
+ if (in_word)
+ {
+ results->n_words++;
+ in_word = 0;
+ }
+ }
+ else
+ {
+ in_word = 1;
+ }
+
+ if (buf[i] == '\n')
+ {
+ results->n_lines++;
+ }
+ }
+
+ results->n_chars += bytes_read;
+ }
+
+ print_counts(results, name);
+}
+
+int main(int argc, char **argv)
+{
+ int f, fd;
+ count_results_t total_counts = {.n_chars = 0, .n_words = 0, .n_lines = 0};
+ count_results_t local_counts = {.n_chars = 0, .n_words = 0, .n_lines = 0};
+
+ if (argc == 1)
+ {
+ /* Reading from standard input. */
+ count(0, 0, &total_counts);
+ }
+ else
+ {
+ /* Reading files, not standard input. */
+ for (f = 1; f < argc; ++f)
+ {
+ fd = open(argv[f], O_RDONLY, 0);
+ if (fd < 0)
+ {
+ /* Error opening file. */
+ fprintf(stderr, "wc: %s: open: %s\n", argv[f], strerror(errno));
+ }
+ else
+ {
+ /* Opened the file. */
+ count(fd, argv[f], &local_counts);
+
+ total_counts.n_chars += local_counts.n_chars;
+ total_counts.n_words += local_counts.n_words;
+ total_counts.n_lines += local_counts.n_lines;
+
+ /* Reset the local counts. */
+ local_counts.n_chars = local_counts.n_words =
+ local_counts.n_lines = 0;
+
+ close(fd);
+ }
+ }
+
+ if (argc > 2)
+ {
+ /* They provided multiple files. We should print the total too. */
+ print_counts(&total_counts, "total");
+ }
+ }
+
+ return 0;
+}