Fix some warnings; improve the stdio emulation.

diff --git a/assert.c b/assert.c
index 71782ab..6d3ff23 100644
--- a/assert.c
+++ b/assert.c
@@ -4,6 +4,7 @@
 
 #include <stdlib.h>
 #include <stdio.h>
+#include <assert.h>
 
 void __assert_fail(const char *expr, const char *file, unsigned int line)
 {
diff --git a/fopen.c b/fopen.c
new file mode 100644
index 0000000..9a87e41
--- /dev/null
+++ b/fopen.c
@@ -0,0 +1,46 @@
+/*
+ * fopen.c
+ */
+
+#include <stdio.h>
+#include <unistd.h>
+#include <fcntl.h>
+
+/* This depends on O_RDONLY == 0, O_WRONLY == 1, O_RDWR == 2 */
+
+
+FILE *fopen(const char *file, const char *mode)
+{
+  int flags = O_RDONLY;
+  int plus = 0;
+  int fd;
+
+  while ( *mode ) {
+    switch ( *mode ) {
+    case 'r':
+      flags = O_RDONLY;
+      break;
+    case 'w':
+      flags = O_WRONLY|O_CREAT|O_TRUNC;
+      break;
+    case 'a':
+      flags = O_WRONLY|O_CREAT|O_APPEND;
+      break;
+    case '+':
+      plus = 1;
+      break;
+    }
+    mode++;
+  }
+
+  if ( plus ) {
+    flags = (flags & ~(O_RDONLY|O_WRONLY)) | O_RDWR;
+  }
+
+  fd = open(file, flags, 0666);
+
+  if ( fd < 0 )
+    return NULL;
+  else
+    return __create_file(fd);
+}
diff --git a/fread.c b/fread.c
index f061089..b8ddd8d 100644
--- a/fread.c
+++ b/fread.c
@@ -18,7 +18,7 @@
       if ( errno == EINTR )
 	continue;
       else
-	return bytes ? bytes : -1;
+	break;
     } else if ( rv == 0 ) {
       break;
     }
diff --git a/include/stdio.h b/include/stdio.h
index 99cef29..92ed478 100644
--- a/include/stdio.h
+++ b/include/stdio.h
@@ -8,6 +8,7 @@
 #include <klibc/extern.h>
 #include <stdarg.h>
 #include <stddef.h>
+#include <sys/types.h>
 
 /* This structure doesn't really exist, but it gives us something
    to define FILE * with */
@@ -22,13 +23,43 @@
 # define EOF (-1)
 #endif
 
-static __inline__
-int fileno(FILE *__f)
+#ifndef BUFSIZ
+# define BUFSIZ 4096
+#endif
+
+#define SEEK_SET 0
+#define SEEK_CUR 1
+#define SEEK_END 2
+
+static __inline__ int fileno(FILE *__f)
 {
   /* This should really be intptr_t, but size_t should be the same size */
   return (int)(size_t)__f;
 }
 
+static __inline__ FILE * __create_file(int __fd)
+{
+  return (FILE *)__fd;
+}
+
+__extern FILE *fopen(const char *, const char *);
+
+static __inline__ int fclose(FILE *__f)
+{
+  extern int close(int);
+  return close(fileno(__f));
+}
+static __inline__ int fseek(FILE *__f, off_t __o, int __w)
+{
+  extern off_t lseek(int, off_t, int);
+  return (lseek(fileno(__f), __o, __w) == (off_t)-1) ? -1 : 0;
+}
+static __inline__ off_t ftell(FILE *__f)
+{
+  extern off_t lseek(int, off_t, int);
+  return lseek(fileno(__f), 0, SEEK_CUR);
+}
+
 __extern int fputs(const char *, FILE *);
 __extern int puts(const char *);
 
diff --git a/include/stdlib.h b/include/stdlib.h
index f265eea..4d885a9 100644
--- a/include/stdlib.h
+++ b/include/stdlib.h
@@ -14,6 +14,7 @@
 static __inline__ __noreturn _Exit(int __n) {
   __extern __noreturn _exit(int);
   _exit(__n);
+  for(;;);			/* Some gcc versions are stupid */
 }
 __extern __noreturn abort(void);
 static __inline__ int abs(int __n) {
@@ -41,6 +42,7 @@
 #endif
 
 __extern __attribute_malloc void *malloc(size_t);
+__extern __attribute_malloc void *calloc(size_t, size_t);
 __extern void *realloc(void *, size_t);
 __extern long strtol(const char *, char **, int);
 __extern long long strtoll(const char *, char **, int);
diff --git a/klibc/MCONFIG b/klibc/MCONFIG
index e6222e2..03a940b 100644
--- a/klibc/MCONFIG
+++ b/klibc/MCONFIG
@@ -10,7 +10,7 @@
 REQFLAGS = -nostdinc -iwithprefix include -I. \
 	  -I./arch/$(ARCH)/include -I./include/bits$(BITSIZE) \
 	  -DBITSIZE=$(BITSIZE) -I./include -I./linux/include \
-	  -Wall
+	  -W -Wpointer-arith -Wwrite-strings -Wstrict-prototypes -Winline
 CFLAGS  = $(OPTFLAGS) $(REQFLAGS)
 LDFLAGS =
 AR      = $(CROSS)ar
diff --git a/klibc/Makefile b/klibc/Makefile
index 11cfe07..7579f58 100644
--- a/klibc/Makefile
+++ b/klibc/Makefile
@@ -18,7 +18,7 @@
 	  execl.o execle.o execv.o execvpe.o execvp.o execlp.o execlpe.o \
 	  fork.o wait.o wait3.o waitpid.o setpgrp.o \
 	  printf.o vprintf.o fprintf.o vfprintf.o \
-	  fread.o fread2.o fwrite.o fwrite2.o fputs.o puts.o \
+	  fopen.o fread.o fread2.o fwrite.o fwrite2.o fputs.o puts.o \
 	  sleep.o usleep.o raise.o abort.o assert.o alarm.o pause.o \
 	  signal.o sigaction.o sigpending.o sigprocmask.o sigsuspend.o \
 	  brk.o sbrk.o malloc.o realloc.o calloc.o mmap.o \
diff --git a/klibc/README b/klibc/README
index 85ba28f..52272c1 100644
--- a/klibc/README
+++ b/klibc/README
@@ -10,7 +10,10 @@
 a) Create a symlink called "linux" pointing to a reasonably recent
    Linux kernel tree (2.4 or 2.5 should be OK.)  This tree must have
    the include/asm symlink set up for the architecture you're
-   compiling for, and include/linux/autoconf.h must exist.
+   compiling for, and include/linux/autoconf.h must exist.  The
+   easiest way to make sure of all of these is to do a "make config"
+   or any of its variants on the kernel tree is question, followed by
+   a "make dep".
 
 b) Change ARCH in the main Makefile to match your architecture.
    If you're cross-compiling, set CROSS to your toolchain prefix.
diff --git a/klibc/assert.c b/klibc/assert.c
index 71782ab..6d3ff23 100644
--- a/klibc/assert.c
+++ b/klibc/assert.c
@@ -4,6 +4,7 @@
 
 #include <stdlib.h>
 #include <stdio.h>
+#include <assert.h>
 
 void __assert_fail(const char *expr, const char *file, unsigned int line)
 {
diff --git a/klibc/fopen.c b/klibc/fopen.c
new file mode 100644
index 0000000..9a87e41
--- /dev/null
+++ b/klibc/fopen.c
@@ -0,0 +1,46 @@
+/*
+ * fopen.c
+ */
+
+#include <stdio.h>
+#include <unistd.h>
+#include <fcntl.h>
+
+/* This depends on O_RDONLY == 0, O_WRONLY == 1, O_RDWR == 2 */
+
+
+FILE *fopen(const char *file, const char *mode)
+{
+  int flags = O_RDONLY;
+  int plus = 0;
+  int fd;
+
+  while ( *mode ) {
+    switch ( *mode ) {
+    case 'r':
+      flags = O_RDONLY;
+      break;
+    case 'w':
+      flags = O_WRONLY|O_CREAT|O_TRUNC;
+      break;
+    case 'a':
+      flags = O_WRONLY|O_CREAT|O_APPEND;
+      break;
+    case '+':
+      plus = 1;
+      break;
+    }
+    mode++;
+  }
+
+  if ( plus ) {
+    flags = (flags & ~(O_RDONLY|O_WRONLY)) | O_RDWR;
+  }
+
+  fd = open(file, flags, 0666);
+
+  if ( fd < 0 )
+    return NULL;
+  else
+    return __create_file(fd);
+}
diff --git a/klibc/fread.c b/klibc/fread.c
index f061089..b8ddd8d 100644
--- a/klibc/fread.c
+++ b/klibc/fread.c
@@ -18,7 +18,7 @@
       if ( errno == EINTR )
 	continue;
       else
-	return bytes ? bytes : -1;
+	break;
     } else if ( rv == 0 ) {
       break;
     }
diff --git a/klibc/include/stdio.h b/klibc/include/stdio.h
index 99cef29..92ed478 100644
--- a/klibc/include/stdio.h
+++ b/klibc/include/stdio.h
@@ -8,6 +8,7 @@
 #include <klibc/extern.h>
 #include <stdarg.h>
 #include <stddef.h>
+#include <sys/types.h>
 
 /* This structure doesn't really exist, but it gives us something
    to define FILE * with */
@@ -22,13 +23,43 @@
 # define EOF (-1)
 #endif
 
-static __inline__
-int fileno(FILE *__f)
+#ifndef BUFSIZ
+# define BUFSIZ 4096
+#endif
+
+#define SEEK_SET 0
+#define SEEK_CUR 1
+#define SEEK_END 2
+
+static __inline__ int fileno(FILE *__f)
 {
   /* This should really be intptr_t, but size_t should be the same size */
   return (int)(size_t)__f;
 }
 
+static __inline__ FILE * __create_file(int __fd)
+{
+  return (FILE *)__fd;
+}
+
+__extern FILE *fopen(const char *, const char *);
+
+static __inline__ int fclose(FILE *__f)
+{
+  extern int close(int);
+  return close(fileno(__f));
+}
+static __inline__ int fseek(FILE *__f, off_t __o, int __w)
+{
+  extern off_t lseek(int, off_t, int);
+  return (lseek(fileno(__f), __o, __w) == (off_t)-1) ? -1 : 0;
+}
+static __inline__ off_t ftell(FILE *__f)
+{
+  extern off_t lseek(int, off_t, int);
+  return lseek(fileno(__f), 0, SEEK_CUR);
+}
+
 __extern int fputs(const char *, FILE *);
 __extern int puts(const char *);
 
diff --git a/klibc/include/stdlib.h b/klibc/include/stdlib.h
index f265eea..4d885a9 100644
--- a/klibc/include/stdlib.h
+++ b/klibc/include/stdlib.h
@@ -14,6 +14,7 @@
 static __inline__ __noreturn _Exit(int __n) {
   __extern __noreturn _exit(int);
   _exit(__n);
+  for(;;);			/* Some gcc versions are stupid */
 }
 __extern __noreturn abort(void);
 static __inline__ int abs(int __n) {
@@ -41,6 +42,7 @@
 #endif
 
 __extern __attribute_malloc void *malloc(size_t);
+__extern __attribute_malloc void *calloc(size_t, size_t);
 __extern void *realloc(void *, size_t);
 __extern long strtol(const char *, char **, int);
 __extern long long strtoll(const char *, char **, int);
diff --git a/klibc/memmem.c b/klibc/memmem.c
index 827e13d..0f59938 100644
--- a/klibc/memmem.c
+++ b/klibc/memmem.c
@@ -16,7 +16,10 @@
   const unsigned char *y = (const unsigned char *)haystack;
   const unsigned char *x = (const unsigned char *)needle;
 
-  int j, k, l;
+  size_t j, k, l;
+
+  if ( m > n )
+    return NULL;
 
   if ( x[0] == x[1] ) {
     k = 2;
diff --git a/klibc/qsort.c b/klibc/qsort.c
index 95715d4..9dee46f 100644
--- a/klibc/qsort.c
+++ b/klibc/qsort.c
@@ -22,7 +22,8 @@
 void qsort(void *base, size_t nmemb, size_t size, int (*compar)(const void *, const void *))
 {
   int gap = nmemb;
-  int swapped, i, j;
+  int swapped;
+  size_t i, j;
   void *p1, *p2;
   char tmp[size];
 
diff --git a/klibc/seed48.c b/klibc/seed48.c
index ba36932..f8353c8 100644
--- a/klibc/seed48.c
+++ b/klibc/seed48.c
@@ -4,6 +4,7 @@
 
 #include <stdlib.h>
 #include <stdint.h>
+#include <string.h>
 
 extern unsigned short __rand48_seed[3];
 
diff --git a/klibc/vsnprintf.c b/klibc/vsnprintf.c
index 4c1f2ee..5cb9331 100644
--- a/klibc/vsnprintf.c
+++ b/klibc/vsnprintf.c
@@ -10,6 +10,7 @@
 #include <inttypes.h>
 #include <string.h>
 #include <limits.h>
+#include <stdio.h>
 
 enum flags {
   FL_ZERO   = 0x01,		/* Zero modifier */
diff --git a/memmem.c b/memmem.c
index 827e13d..0f59938 100644
--- a/memmem.c
+++ b/memmem.c
@@ -16,7 +16,10 @@
   const unsigned char *y = (const unsigned char *)haystack;
   const unsigned char *x = (const unsigned char *)needle;
 
-  int j, k, l;
+  size_t j, k, l;
+
+  if ( m > n )
+    return NULL;
 
   if ( x[0] == x[1] ) {
     k = 2;
diff --git a/qsort.c b/qsort.c
index 95715d4..9dee46f 100644
--- a/qsort.c
+++ b/qsort.c
@@ -22,7 +22,8 @@
 void qsort(void *base, size_t nmemb, size_t size, int (*compar)(const void *, const void *))
 {
   int gap = nmemb;
-  int swapped, i, j;
+  int swapped;
+  size_t i, j;
   void *p1, *p2;
   char tmp[size];
 
diff --git a/seed48.c b/seed48.c
index ba36932..f8353c8 100644
--- a/seed48.c
+++ b/seed48.c
@@ -4,6 +4,7 @@
 
 #include <stdlib.h>
 #include <stdint.h>
+#include <string.h>
 
 extern unsigned short __rand48_seed[3];
 
diff --git a/vsnprintf.c b/vsnprintf.c
index 4c1f2ee..5cb9331 100644
--- a/vsnprintf.c
+++ b/vsnprintf.c
@@ -10,6 +10,7 @@
 #include <inttypes.h>
 #include <string.h>
 #include <limits.h>
+#include <stdio.h>
 
 enum flags {
   FL_ZERO   = 0x01,		/* Zero modifier */