Merge with v2.6.22-rc1

Conflicts:

	fs/nfs/mount_clnt.c
	fs/nfs/nfsroot.c
	init/do_mounts.c
	init/do_mounts_initrd.c
	net/ipv4/ipconfig.c
	scripts/gen_initramfs_list.sh
diff --git a/MAINTAINERS b/MAINTAINERS
index 68a56ad..cbc7bb7 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -2085,6 +2085,13 @@
 L:	kexec@lists.infradead.org
 S:	Maintained
 
+KLIBC/KINIT
+P:	H. Peter Anvin
+M:	hpa@zytor.com
+L:	klibc@zytor.com
+T:	git kernel.org:pub/scm/linux/kernel/git/hpa/linux-2.6-klibc.git
+S:	Maintained
+
 KPROBES
 P:	Prasanna S Panchamukhi
 M:	prasanna@in.ibm.com
diff --git a/Makefile b/Makefile
index e6990e2..645e318 100644
--- a/Makefile
+++ b/Makefile
@@ -186,7 +186,16 @@
 CROSS_COMPILE	?=
 
 # Architecture as present in compile.h
-UTS_MACHINE := $(ARCH)
+UTS_MACHINE	:= $(ARCH)
+
+# Architecture used to compile user-space code
+KLIBCARCH	?= $(ARCH)
+KLIBCARCHDIR	?= $(KLIBCARCH)
+
+# klibc definitions
+export KLIBCINC := usr/include
+export KLIBCSRC := $(srctree)/usr/klibc
+export KLIBCOBJ := $(objtree)/usr/klibc
 
 KCONFIG_CONFIG	?= .config
 
@@ -284,6 +293,7 @@
 CC		= $(CROSS_COMPILE)gcc
 CPP		= $(CC) -E
 AR		= $(CROSS_COMPILE)ar
+RANLIB		= $(CROSS_COMPILE)ranlib
 NM		= $(CROSS_COMPILE)nm
 STRIP		= $(CROSS_COMPILE)strip
 OBJCOPY		= $(CROSS_COMPILE)objcopy
@@ -324,6 +334,7 @@
 export ARCH CONFIG_SHELL HOSTCC HOSTCFLAGS CROSS_COMPILE AS LD CC
 export CPP AR NM STRIP OBJCOPY OBJDUMP MAKE AWK GENKSYMS PERL UTS_MACHINE
 export HOSTCXX HOSTCXXFLAGS LDFLAGS_MODULE CHECK CHECKFLAGS
+export RANLIB KLIBCARCH KLIBCARCHDIR
 
 export CPPFLAGS NOSTDINC_FLAGS LINUXINCLUDE OBJCOPYFLAGS LDFLAGS
 export CFLAGS CFLAGS_KERNEL CFLAGS_MODULE
@@ -1411,41 +1422,44 @@
 # - build whith mixed source and output
 # - build with separate output dir 'make O=...'
 # - external modules
+# - klibc library and klibc programs (everything under usr/)
 #
 #  target-dir => where to store outputfile
 #  build-dir  => directory in kernel source tree to use
 
 ifeq ($(KBUILD_EXTMOD),)
+        singlebld  = $(if $(filter usr/%,$(dir $@)),$(klibc),$(build))
         build-dir  = $(patsubst %/,%,$(dir $@))
         target-dir = $(dir $@)
 else
+        singlebld  = $(build)
         zap-slash=$(filter-out .,$(patsubst %/,%,$(dir $@)))
         build-dir  = $(KBUILD_EXTMOD)$(if $(zap-slash),/$(zap-slash))
         target-dir = $(if $(KBUILD_EXTMOD),$(dir $<),$(dir $@))
 endif
 
 %.s: %.c prepare scripts FORCE
-	$(Q)$(MAKE) $(build)=$(build-dir) $(target-dir)$(notdir $@)
+	$(Q)$(MAKE) $(singlebld)=$(build-dir) $(target-dir)$(notdir $@)
 %.i: %.c prepare scripts FORCE
-	$(Q)$(MAKE) $(build)=$(build-dir) $(target-dir)$(notdir $@)
+	$(Q)$(MAKE) $(singlebld)=$(build-dir) $(target-dir)$(notdir $@)
 %.o: %.c prepare scripts FORCE
-	$(Q)$(MAKE) $(build)=$(build-dir) $(target-dir)$(notdir $@)
+	$(Q)$(MAKE) $(singlebld)=$(build-dir) $(target-dir)$(notdir $@)
 %.lst: %.c prepare scripts FORCE
-	$(Q)$(MAKE) $(build)=$(build-dir) $(target-dir)$(notdir $@)
+	$(Q)$(MAKE) $(singlebld)=$(build-dir) $(target-dir)$(notdir $@)
 %.s: %.S prepare scripts FORCE
-	$(Q)$(MAKE) $(build)=$(build-dir) $(target-dir)$(notdir $@)
+	$(Q)$(MAKE) $(singlebld)=$(build-dir) $(target-dir)$(notdir $@)
 %.o: %.S prepare scripts FORCE
-	$(Q)$(MAKE) $(build)=$(build-dir) $(target-dir)$(notdir $@)
+	$(Q)$(MAKE) $(singlebld)=$(build-dir) $(target-dir)$(notdir $@)
 %.symtypes: %.c prepare scripts FORCE
 	$(Q)$(MAKE) $(build)=$(build-dir) $(target-dir)$(notdir $@)
 
 # Modules
 / %/: prepare scripts FORCE
 	$(Q)$(MAKE) KBUILD_MODULES=$(if $(CONFIG_MODULES),1) \
-	$(build)=$(build-dir)
+	$(singlebld)=$(build-dir)
 %.ko: prepare scripts FORCE
 	$(Q)$(MAKE) KBUILD_MODULES=$(if $(CONFIG_MODULES),1)   \
-	$(build)=$(build-dir) $(@:.ko=.o)
+	$(singlebld)=$(build-dir) $(@:.ko=.o)
 	$(Q)$(MAKE) -f $(srctree)/scripts/Makefile.modpost
 
 # FIXME Should go into a make.lib or something 
diff --git a/arch/arm/kernel/setup.c b/arch/arm/kernel/setup.c
index 0453dcc..7578fe1 100644
--- a/arch/arm/kernel/setup.c
+++ b/arch/arm/kernel/setup.c
@@ -56,7 +56,6 @@
 
 extern void paging_init(struct meminfo *, struct machine_desc *desc);
 extern void reboot_setup(char *str);
-extern int root_mountflags;
 extern void _stext, _text, _etext, __data_start, _edata, _end;
 
 unsigned int processor_id;
@@ -520,20 +519,31 @@
 	*cmdline_p = command_line;
 }
 
-static void __init
-setup_ramdisk(int doload, int prompt, int image_start, unsigned int rd_sz)
+/*
+ * Generate /arch.cmd, which contains command-line equivalent options
+ * for kinit.  We do this in two steps: save into a buffer, and then
+ * write out the file, since the first step will typically be done
+ * very early, and the second step needs to be done after rootfs is fully
+ * operational.
+ */
+static char __initdata arch_cmd_buffer[256];
+static int __initdata arch_cmd_len;
+
+static int __init write_arch_init_command(void)
 {
-#ifdef CONFIG_BLK_DEV_RAM
-	extern int rd_size, rd_image_start, rd_prompt, rd_doload;
+	int fd;
 
-	rd_image_start = image_start;
-	rd_prompt = prompt;
-	rd_doload = doload;
+	fd = sys_open("/arch.cmd", O_WRONLY|O_CREAT|O_APPEND, 0666);
+	if (fd < 0)
+		return fd;
 
-	if (rd_sz)
-		rd_size = rd_sz;
-#endif
+	sys_write(fd, arch_cmd_buffer, arch_cmd_len);
+	sys_close(fd);
+
+	return 0;
 }
+	
+late_initcall(write_arch_init_command);
 
 static void __init
 request_standard_resources(struct meminfo *mi, struct machine_desc *mdesc)
@@ -599,13 +609,27 @@
  * a param_struct).  The list is terminated with a zero-length tag (this tag
  * is not parsed in any way).
  */
+
+
 static int __init parse_tag_core(const struct tag *tag)
 {
+	char *buf = arch_cmd_buffer + arch_cmd_len;
+	char *end = arch_cmd_buffer + sizeof arch_cmd_buffer;
+
+	if (end-buf <= 3)
+		return -ENOMEM;
+
+	*buf++ = 'r';
+	*buf = 'o';
 	if (tag->hdr.size > 2) {
 		if ((tag->u.core.flags & 1) == 0)
-			root_mountflags &= ~MS_RDONLY;
+			*buf = 'w';
 		ROOT_DEV = old_decode_dev(tag->u.core.rootdev);
 	}
+	buf++;
+	*buf++ = '\n';
+
+	arch_cmd_len = end-buf;
 	return 0;
 }
 
@@ -654,11 +678,35 @@
 
 static int __init parse_tag_ramdisk(const struct tag *tag)
 {
-	setup_ramdisk((tag->u.ramdisk.flags & 1) == 0,
-		      (tag->u.ramdisk.flags & 2) == 0,
-		      tag->u.ramdisk.start, tag->u.ramdisk.size);
+#ifdef CONFIG_BLK_DEV_RAM
+	char *buf = arch_cmd_buffer + arch_cmd_len;
+	char *end = arch_cmd_buffer + sizeof arch_cmd_buffer;
+	int len;
+	
+	len = snprintf(buf, end-buf,
+		       "ramdisk_start=%u\n"
+		       "load_ramdisk=%d\n"
+		       "prompt_ramdisk=%d\n",
+		       tag->u.ramdisk.start,
+		       tag->u.ramdisk.flags & 1 ? 0 : 1,
+		       tag->u.ramdisk.flags & 2 ? 0 : 1);
+	if (len >= end-buf)
+		return -ENOMEM;
+	buf += len;
+
+	if (tag->u.ramdisk.size) {
+		len = snprintf(buf, end-buf,
+			       "ramdisk_size=%u\n",
+			       tag->u.ramdisk.size);
+		if (len >= end-buf)
+			return -ENOMEM;
+		buf += len;
+	}
+
+	arch_cmd_len = end-buf;
+#endif
 	return 0;
-}
+}	
 
 __tagtable(ATAG_RAMDISK, parse_tag_ramdisk);
 
diff --git a/arch/i386/kernel/setup.c b/arch/i386/kernel/setup.c
index 698c24f..86e6a26 100644
--- a/arch/i386/kernel/setup.c
+++ b/arch/i386/kernel/setup.c
@@ -124,7 +124,6 @@
 #endif
 
 extern void early_cpu_init(void);
-extern int root_mountflags;
 
 unsigned long saved_videomode;
 
@@ -542,11 +541,6 @@
 	}
 	bootloader_type = LOADER_TYPE;
 
-#ifdef CONFIG_BLK_DEV_RAM
-	rd_image_start = RAMDISK_FLAGS & RAMDISK_IMAGE_START_MASK;
-	rd_prompt = ((RAMDISK_FLAGS & RAMDISK_PROMPT_FLAG) != 0);
-	rd_doload = ((RAMDISK_FLAGS & RAMDISK_LOAD_FLAG) != 0);
-#endif
 	ARCH_SETUP
 	if (efi_enabled)
 		efi_init();
@@ -557,8 +551,6 @@
 
 	copy_edd();
 
-	if (!MOUNT_ROOT_RDONLY)
-		root_mountflags &= ~MS_RDONLY;
 	init_mm.start_code = (unsigned long) _text;
 	init_mm.end_code = (unsigned long) _etext;
 	init_mm.end_data = (unsigned long) _edata;
diff --git a/arch/powerpc/Makefile b/arch/powerpc/Makefile
index d6014a6..5fe1027 100644
--- a/arch/powerpc/Makefile
+++ b/arch/powerpc/Makefile
@@ -53,6 +53,7 @@
 endif
 
 UTS_MACHINE := $(OLDARCH)
+KLIBCARCH   := $(OLDARCH)
 
 ifeq ($(HAS_BIARCH),y)
 override AS	+= -a$(SZ)
diff --git a/arch/s390/Makefile b/arch/s390/Makefile
index 68441e0..0b1e91a 100644
--- a/arch/s390/Makefile
+++ b/arch/s390/Makefile
@@ -20,6 +20,7 @@
 UTS_MACHINE	:= s390
 STACK_SIZE	:= 8192
 CHECKFLAGS	+= -D__s390__
+KLIBCARCH	:= s390
 else
 LDFLAGS		:= -m elf64_s390
 MODFLAGS	+= -fpic -D__PIC__
@@ -28,8 +29,11 @@
 UTS_MACHINE	:= s390x
 STACK_SIZE	:= 16384
 CHECKFLAGS	+= -D__s390__ -D__s390x__
+KLIBCARCH	:= s390x
 endif
 
+KLIBCARCHDIR	:= s390
+
 cflags-$(CONFIG_MARCH_G5)   += $(call cc-option,-march=g5)
 cflags-$(CONFIG_MARCH_Z900) += $(call cc-option,-march=z900)
 cflags-$(CONFIG_MARCH_Z990) += $(call cc-option,-march=z990)
diff --git a/arch/sparc/kernel/setup.c b/arch/sparc/kernel/setup.c
index 64c0ed9..2b089d7 100644
--- a/arch/sparc/kernel/setup.c
+++ b/arch/sparc/kernel/setup.c
@@ -228,8 +228,6 @@
 #define RAMDISK_PROMPT_FLAG		0x8000
 #define RAMDISK_LOAD_FLAG		0x4000
 
-extern int root_mountflags;
-
 char reboot_command[COMMAND_LINE_SIZE];
 enum sparc_cpu sparc_cpu_model;
 
@@ -316,14 +314,7 @@
 	}
 	pfn_base = phys_base >> PAGE_SHIFT;
 
-	if (!root_flags)
-		root_mountflags &= ~MS_RDONLY;
 	ROOT_DEV = old_decode_dev(root_dev);
-#ifdef CONFIG_BLK_DEV_RAM
-	rd_image_start = ram_flags & RAMDISK_IMAGE_START_MASK;
-	rd_prompt = ((ram_flags & RAMDISK_PROMPT_FLAG) != 0);
-	rd_doload = ((ram_flags & RAMDISK_LOAD_FLAG) != 0);	
-#endif
 
 	prom_setsync(prom_sync_me);
 
@@ -376,6 +367,44 @@
 }
 console_initcall(set_preferred_console);
 
+/*
+ * Platform-specific configuration commands which don't come from
+ * the actual kernel command line.  Write them into a file in rootfs
+ * so kinit can pick them up.
+ */
+static int __init set_arch_init_commands(void)
+{
+	int fd = sys_open("/arch.cmd", O_WRONLY|O_CREAT|O_APPEND, 0666);
+	char buffer[256];
+	int len = 0;
+
+	if (fd < 0)
+		return fd;
+
+	buffer[0] = 'r';
+	buffer[1] = root_flags ? 'o' : 'w';
+	buffer[2] = '\n';
+	len = 3;
+
+#ifdef CONFIG_BLK_DEV_RAM
+	len += min((int)(sizeof buffer - 1 - len),
+		   snprintf(buffer+len, sizeof buffer - len,
+			    "ramdisk_start=%u\n"
+			    "prompt_ramdisk=%d\n"
+			    "load_ramdisk=%d\n",
+			    ram_flags & RAMDISK_IMAGE_START_MASK,
+			    !!(ram_flags & RAMDISK_PROMPT_FLAG),
+			    !!(ram_flags & RAMDISK_LOAD_FLAG)));
+#endif
+
+	sys_write(fd, buffer, len);
+	sys_close(fd);
+
+	return 0;
+}
+
+late_initcall(set_arch_init_commands);
+
 extern char *sparc_cpu_type;
 extern char *sparc_fpu_type;
 
diff --git a/arch/sparc64/kernel/setup.c b/arch/sparc64/kernel/setup.c
index 4510283..0f28d9d 100644
--- a/arch/sparc64/kernel/setup.c
+++ b/arch/sparc64/kernel/setup.c
@@ -31,6 +31,7 @@
 #include <linux/interrupt.h>
 #include <linux/cpu.h>
 #include <linux/initrd.h>
+#include <linux/fcntl.h>
 
 #include <asm/system.h>
 #include <asm/io.h>
@@ -90,6 +91,16 @@
 {
 }
 
+int obp_system_intr(void)
+{
+	if (boot_flags & BOOTME_DEBUG) {
+		printk("OBP: system interrupted\n");
+		prom_halt();
+		return 1;
+	}
+	return 0;
+}
+
 /* 
  * Process kernel command line switches that are specific to the
  * SPARC or that require special low-level processing.
@@ -201,8 +212,6 @@
 #define RAMDISK_PROMPT_FLAG		0x8000
 #define RAMDISK_LOAD_FLAG		0x4000
 
-extern int root_mountflags;
-
 char reboot_command[COMMAND_LINE_SIZE];
 
 static struct pt_regs fake_swapper_regs = { { 0, }, 0, 0, 0, 0 };
@@ -302,6 +311,64 @@
 	}
 }
 
+/*
+ * Platform-specific configuration commands which don't come from
+ * the actual kernel command line.  Write them into a file in rootfs
+ * so kinit can pick them up.
+ */
+static int __init set_arch_init_commands(void)
+{
+	int fd = sys_open("/arch.cmd", O_WRONLY|O_CREAT|O_APPEND, 0666);
+	int chosen;
+	u32 cl, sv, gw;
+	char buffer[256];
+	int len = 0;
+
+	if (fd < 0)
+		return fd;
+
+	buffer[0] = 'r';
+	buffer[1] = root_flags ? 'o' : 'w';
+	buffer[2] = '\n';
+	len = 3;
+
+#ifdef CONFIG_BLK_DEV_RAM
+	len += min((int)(sizeof buffer - 1 - len),
+		   snprintf(buffer+len, sizeof buffer - len,
+			    "ramdisk_start=%u\n"
+			    "prompt_ramdisk=%d\n"
+			    "load_ramdisk=%d\n",
+			    ram_flags & RAMDISK_IMAGE_START_MASK,
+			    !!(ram_flags & RAMDISK_PROMPT_FLAG),
+			    !!(ram_flags & RAMDISK_LOAD_FLAG)));
+#endif
+
+	chosen = prom_finddevice("/chosen");
+	cl = prom_getintdefault(chosen, "client-ip", 0);
+	sv = prom_getintdefault(chosen, "server-ip", 0);
+	gw = prom_getintdefault(chosen, "gateway-ip", 0);
+
+	if (cl && sv) {
+		len += min((int)(sizeof buffer - 1 - len),
+			   snprintf(buffer+len, sizeof buffer - len,
+				    "ip=%u.%u.%u.%u:%u.%u.%u.%u:"
+				    "%u.%u.%u.%u\n",
+				    (u8)(cl >> 24), (u8)(cl >> 16),
+				    (u8)(cl >> 8), (u8)cl,
+				    (u8)(sv >> 24), (u8)(sv >> 16),
+				    (u8)(sv >> 8), (u8)sv,
+				    (u8)(gw >> 24), (u8)(gw >> 16),
+				    (u8)(gw >> 8), (u8)gw));
+	}
+
+	sys_write(fd, buffer, len);
+	sys_close(fd);
+
+	return 0;
+}
+
+late_initcall(set_arch_init_commands);
+
 #ifdef CONFIG_SMP
 void __init boot_cpu_id_too_large(int cpu)
 {
@@ -332,37 +399,10 @@
 
 	idprom_init();
 
-	if (!root_flags)
-		root_mountflags &= ~MS_RDONLY;
 	ROOT_DEV = old_decode_dev(root_dev);
-#ifdef CONFIG_BLK_DEV_RAM
-	rd_image_start = ram_flags & RAMDISK_IMAGE_START_MASK;
-	rd_prompt = ((ram_flags & RAMDISK_PROMPT_FLAG) != 0);
-	rd_doload = ((ram_flags & RAMDISK_LOAD_FLAG) != 0);	
-#endif
 
 	task_thread_info(&init_task)->kregs = &fake_swapper_regs;
 
-#ifdef CONFIG_IP_PNP
-	if (!ic_set_manually) {
-		int chosen = prom_finddevice ("/chosen");
-		u32 cl, sv, gw;
-		
-		cl = prom_getintdefault (chosen, "client-ip", 0);
-		sv = prom_getintdefault (chosen, "server-ip", 0);
-		gw = prom_getintdefault (chosen, "gateway-ip", 0);
-		if (cl && sv) {
-			ic_myaddr = cl;
-			ic_servaddr = sv;
-			if (gw)
-				ic_gateway = gw;
-#if defined(CONFIG_IP_PNP_BOOTP) || defined(CONFIG_IP_PNP_RARP)
-			ic_proto_enabled = 0;
-#endif
-		}
-	}
-#endif
-
 	/* Get boot processor trap_block[] setup.  */
 	init_cur_cpu_trap(current_thread_info());
 
@@ -425,7 +465,7 @@
 
 static int show_cpuinfo(struct seq_file *m, void *__unused)
 {
-	seq_printf(m, 
+	seq_printf(m,
 		   "cpu\t\t: %s\n"
 		   "fpu\t\t: %s\n"
 		   "prom\t\t: %s\n"
diff --git a/arch/um/Makefile b/arch/um/Makefile
index 5d5ed72..b3ca7be 100644
--- a/arch/um/Makefile
+++ b/arch/um/Makefile
@@ -50,6 +50,8 @@
 endif
 SYS_DIR		:= $(ARCH_DIR)/include/sysdep-$(SUBARCH)
 
+KLIBCARCH	:= $(SUBARCH)
+
 # -Dvmap=kernel_vmap prevents anything from referencing the libpcap.o symbol so
 # named - it's a common symbol in libpcap, so we get a binary which crashes.
 #
diff --git a/arch/x86_64/kernel/setup.c b/arch/x86_64/kernel/setup.c
index eb6524f..47aef34 100644
--- a/arch/x86_64/kernel/setup.c
+++ b/arch/x86_64/kernel/setup.c
@@ -231,16 +231,9 @@
 	saved_video_mode = SAVED_VIDEO_MODE;
 	bootloader_type = LOADER_TYPE;
 
-#ifdef CONFIG_BLK_DEV_RAM
-	rd_image_start = RAMDISK_FLAGS & RAMDISK_IMAGE_START_MASK;
-	rd_prompt = ((RAMDISK_FLAGS & RAMDISK_PROMPT_FLAG) != 0);
-	rd_doload = ((RAMDISK_FLAGS & RAMDISK_LOAD_FLAG) != 0);
-#endif
 	setup_memory_region();
 	copy_edd();
 
-	if (!MOUNT_ROOT_RDONLY)
-		root_mountflags &= ~MS_RDONLY;
 	init_mm.start_code = (unsigned long) &_text;
 	init_mm.end_code = (unsigned long) &_etext;
 	init_mm.end_data = (unsigned long) &_edata;
diff --git a/fs/Kconfig b/fs/Kconfig
index 0fa0c11..4a5bdff 100644
--- a/fs/Kconfig
+++ b/fs/Kconfig
@@ -1690,20 +1690,6 @@
 	  TCP connections usually perform better than the default UDP when
 	  the network is lossy or congested.  If unsure, say Y.
 
-config ROOT_NFS
-	bool "Root file system on NFS"
-	depends on NFS_FS=y && IP_PNP
-	help
-	  If you want your Linux box to mount its whole root file system (the
-	  one containing the directory /) from some other computer over the
-	  net via NFS (presumably because your box doesn't have a hard disk),
-	  say Y. Read <file:Documentation/nfsroot.txt> for details. It is
-	  likely that in this case, you also want to say Y to "Kernel level IP
-	  autoconfiguration" so that your box can discover its network address
-	  at boot time.
-
-	  Most people say N here.
-
 config LOCKD
 	tristate
 
diff --git a/fs/nfs/Makefile b/fs/nfs/Makefile
index f4580b4..98b9cd3 100644
--- a/fs/nfs/Makefile
+++ b/fs/nfs/Makefile
@@ -7,7 +7,6 @@
 nfs-y 			:= client.o dir.o file.o getroot.o inode.o super.o nfs2xdr.o \
 			   pagelist.o proc.o read.o symlink.o unlink.o \
 			   write.o namespace.o
-nfs-$(CONFIG_ROOT_NFS)	+= nfsroot.o mount_clnt.o      
 nfs-$(CONFIG_NFS_V3)	+= nfs3proc.o nfs3xdr.o
 nfs-$(CONFIG_NFS_V3_ACL)	+= nfs3acl.o
 nfs-$(CONFIG_NFS_V4)	+= nfs4proc.o nfs4xdr.o nfs4state.o nfs4renewd.o \
diff --git a/fs/nfs/mount_clnt.c b/fs/nfs/mount_clnt.c
deleted file mode 100644
index ca5a266..0000000
--- a/fs/nfs/mount_clnt.c
+++ /dev/null
@@ -1,190 +0,0 @@
-/*
- * linux/fs/nfs/mount_clnt.c
- *
- * MOUNT client to support NFSroot.
- *
- * Copyright (C) 1997, Olaf Kirch <okir@monad.swb.de>
- */
-
-#include <linux/types.h>
-#include <linux/socket.h>
-#include <linux/kernel.h>
-#include <linux/errno.h>
-#include <linux/uio.h>
-#include <linux/net.h>
-#include <linux/in.h>
-#include <linux/sunrpc/clnt.h>
-#include <linux/sunrpc/sched.h>
-#include <linux/nfs_fs.h>
-
-#ifdef RPC_DEBUG
-# define NFSDBG_FACILITY	NFSDBG_ROOT
-#endif
-
-/*
-#define MOUNT_PROGRAM		100005
-#define MOUNT_VERSION		1
-#define MOUNT_MNT		1
-#define MOUNT_UMNT		3
- */
-
-static struct rpc_clnt *	mnt_create(char *, struct sockaddr_in *,
-								int, int);
-static struct rpc_program	mnt_program;
-
-struct mnt_fhstatus {
-	unsigned int		status;
-	struct nfs_fh *		fh;
-};
-
-/*
- * Obtain an NFS file handle for the given host and path
- */
-int
-nfsroot_mount(struct sockaddr_in *addr, char *path, struct nfs_fh *fh,
-		int version, int protocol)
-{
-	struct rpc_clnt		*mnt_clnt;
-	struct mnt_fhstatus	result = {
-		.fh		= fh
-	};
-	struct rpc_message msg	= {
-		.rpc_argp	= path,
-		.rpc_resp	= &result,
-	};
-	char			hostname[32];
-	int			status;
-
-	dprintk("NFS:      nfs_mount(%08x:%s)\n",
-			(unsigned)ntohl(addr->sin_addr.s_addr), path);
-
-	sprintf(hostname, "%u.%u.%u.%u", NIPQUAD(addr->sin_addr.s_addr));
-	mnt_clnt = mnt_create(hostname, addr, version, protocol);
-	if (IS_ERR(mnt_clnt))
-		return PTR_ERR(mnt_clnt);
-
-	if (version == NFS_MNT3_VERSION)
-		msg.rpc_proc = &mnt_clnt->cl_procinfo[MOUNTPROC3_MNT];
-	else
-		msg.rpc_proc = &mnt_clnt->cl_procinfo[MNTPROC_MNT];
-
-	status = rpc_call_sync(mnt_clnt, &msg, 0);
-	return status < 0? status : (result.status? -EACCES : 0);
-}
-
-static struct rpc_clnt *
-mnt_create(char *hostname, struct sockaddr_in *srvaddr, int version,
-		int protocol)
-{
-	struct rpc_create_args args = {
-		.protocol	= protocol,
-		.address	= (struct sockaddr *)srvaddr,
-		.addrsize	= sizeof(*srvaddr),
-		.servername	= hostname,
-		.program	= &mnt_program,
-		.version	= version,
-		.authflavor	= RPC_AUTH_UNIX,
-		.flags		= (RPC_CLNT_CREATE_ONESHOT |
-				   RPC_CLNT_CREATE_INTR),
-	};
-
-	return rpc_create(&args);
-}
-
-/*
- * XDR encode/decode functions for MOUNT
- */
-static int
-xdr_encode_dirpath(struct rpc_rqst *req, __be32 *p, const char *path)
-{
-	p = xdr_encode_string(p, path);
-
-	req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
-	return 0;
-}
-
-static int
-xdr_decode_fhstatus(struct rpc_rqst *req, __be32 *p, struct mnt_fhstatus *res)
-{
-	struct nfs_fh *fh = res->fh;
-
-	if ((res->status = ntohl(*p++)) == 0) {
-		fh->size = NFS2_FHSIZE;
-		memcpy(fh->data, p, NFS2_FHSIZE);
-	}
-	return 0;
-}
-
-static int
-xdr_decode_fhstatus3(struct rpc_rqst *req, __be32 *p, struct mnt_fhstatus *res)
-{
-	struct nfs_fh *fh = res->fh;
-
-	if ((res->status = ntohl(*p++)) == 0) {
-		int size = ntohl(*p++);
-		if (size <= NFS3_FHSIZE) {
-			fh->size = size;
-			memcpy(fh->data, p, size);
-		} else
-			res->status = -EBADHANDLE;
-	}
-	return 0;
-}
-
-#define MNT_dirpath_sz		(1 + 256)
-#define MNT_fhstatus_sz		(1 + 8)
-#define MNT_fhstatus3_sz	(1 + 16)
-
-static struct rpc_procinfo	mnt_procedures[] = {
-[MNTPROC_MNT] = {
-	  .p_proc		= MNTPROC_MNT,
-	  .p_encode		= (kxdrproc_t) xdr_encode_dirpath,	
-	  .p_decode		= (kxdrproc_t) xdr_decode_fhstatus,
-	  .p_arglen		= MNT_dirpath_sz,
-	  .p_replen		= MNT_fhstatus_sz,
-	  .p_statidx		= MNTPROC_MNT,
-	  .p_name		= "MOUNT",
-	},
-};
-
-static struct rpc_procinfo mnt3_procedures[] = {
-[MOUNTPROC3_MNT] = {
-	  .p_proc		= MOUNTPROC3_MNT,
-	  .p_encode		= (kxdrproc_t) xdr_encode_dirpath,
-	  .p_decode		= (kxdrproc_t) xdr_decode_fhstatus3,
-	  .p_arglen		= MNT_dirpath_sz,
-	  .p_replen		= MNT_fhstatus3_sz,
-	  .p_statidx		= MOUNTPROC3_MNT,
-	  .p_name		= "MOUNT",
-	},
-};
-
-
-static struct rpc_version	mnt_version1 = {
-		.number		= 1,
-		.nrprocs 	= 2,
-		.procs 		= mnt_procedures
-};
-
-static struct rpc_version       mnt_version3 = {
-		.number		= 3,
-		.nrprocs	= 2,
-		.procs		= mnt3_procedures
-};
-
-static struct rpc_version *	mnt_version[] = {
-	NULL,
-	&mnt_version1,
-	NULL,
-	&mnt_version3,
-};
-
-static struct rpc_stat		mnt_stats;
-
-static struct rpc_program	mnt_program = {
-	.name		= "mount",
-	.number		= NFS_MNT_PROGRAM,
-	.nrvers		= ARRAY_SIZE(mnt_version),
-	.version	= mnt_version,
-	.stats		= &mnt_stats,
-};
diff --git a/fs/nfs/nfsroot.c b/fs/nfs/nfsroot.c
deleted file mode 100644
index 49d1008..0000000
--- a/fs/nfs/nfsroot.c
+++ /dev/null
@@ -1,523 +0,0 @@
-/*
- *  $Id: nfsroot.c,v 1.45 1998/03/07 10:44:46 mj Exp $
- *
- *  Copyright (C) 1995, 1996  Gero Kuhlmann <gero@gkminix.han.de>
- *
- *  Allow an NFS filesystem to be mounted as root. The way this works is:
- *     (1) Use the IP autoconfig mechanism to set local IP addresses and routes.
- *     (2) Handle RPC negotiation with the system which replied to RARP or
- *         was reported as a boot server by BOOTP or manually.
- *     (3) The actual mounting is done later, when init() is running.
- *
- *
- *	Changes:
- *
- *	Alan Cox	:	Removed get_address name clash with FPU.
- *	Alan Cox	:	Reformatted a bit.
- *	Gero Kuhlmann	:	Code cleanup
- *	Michael Rausch  :	Fixed recognition of an incoming RARP answer.
- *	Martin Mares	: (2.0)	Auto-configuration via BOOTP supported.
- *	Martin Mares	:	Manual selection of interface & BOOTP/RARP.
- *	Martin Mares	:	Using network routes instead of host routes,
- *				allowing the default configuration to be used
- *				for normal operation of the host.
- *	Martin Mares	:	Randomized timer with exponential backoff
- *				installed to minimize network congestion.
- *	Martin Mares	:	Code cleanup.
- *	Martin Mares	: (2.1)	BOOTP and RARP made configuration options.
- *	Martin Mares	:	Server hostname generation fixed.
- *	Gerd Knorr	:	Fixed wired inode handling
- *	Martin Mares	: (2.2)	"0.0.0.0" addresses from command line ignored.
- *	Martin Mares	:	RARP replies not tested for server address.
- *	Gero Kuhlmann	: (2.3) Some bug fixes and code cleanup again (please
- *				send me your new patches _before_ bothering
- *				Linus so that I don' always have to cleanup
- *				_afterwards_ - thanks)
- *	Gero Kuhlmann	:	Last changes of Martin Mares undone.
- *	Gero Kuhlmann	: 	RARP replies are tested for specified server
- *				again. However, it's now possible to have
- *				different RARP and NFS servers.
- *	Gero Kuhlmann	:	"0.0.0.0" addresses from command line are
- *				now mapped to INADDR_NONE.
- *	Gero Kuhlmann	:	Fixed a bug which prevented BOOTP path name
- *				from being used (thanks to Leo Spiekman)
- *	Andy Walker	:	Allow to specify the NFS server in nfs_root
- *				without giving a path name
- *	Swen Thümmler	:	Allow to specify the NFS options in nfs_root
- *				without giving a path name. Fix BOOTP request
- *				for domainname (domainname is NIS domain, not
- *				DNS domain!). Skip dummy devices for BOOTP.
- *	Jacek Zapala	:	Fixed a bug which prevented server-ip address
- *				from nfsroot parameter from being used.
- *	Olaf Kirch	:	Adapted to new NFS code.
- *	Jakub Jelinek	:	Free used code segment.
- *	Marko Kohtala	:	Fixed some bugs.
- *	Martin Mares	:	Debug message cleanup
- *	Martin Mares	:	Changed to use the new generic IP layer autoconfig
- *				code. BOOTP and RARP moved there.
- *	Martin Mares	:	Default path now contains host name instead of
- *				host IP address (but host name defaults to IP
- *				address anyway).
- *	Martin Mares	:	Use root_server_addr appropriately during setup.
- *	Martin Mares	:	Rewrote parameter parsing, now hopefully giving
- *				correct overriding.
- *	Trond Myklebust :	Add in preliminary support for NFSv3 and TCP.
- *				Fix bug in root_nfs_addr(). nfs_data.namlen
- *				is NOT for the length of the hostname.
- *	Hua Qin		:	Support for mounting root file system via
- *				NFS over TCP.
- *	Fabian Frederick:	Option parser rebuilt (using parser lib)
-*/
-
-#include <linux/types.h>
-#include <linux/string.h>
-#include <linux/kernel.h>
-#include <linux/time.h>
-#include <linux/fs.h>
-#include <linux/init.h>
-#include <linux/sunrpc/clnt.h>
-#include <linux/nfs.h>
-#include <linux/nfs_fs.h>
-#include <linux/nfs_mount.h>
-#include <linux/in.h>
-#include <linux/major.h>
-#include <linux/utsname.h>
-#include <linux/inet.h>
-#include <linux/root_dev.h>
-#include <net/ipconfig.h>
-#include <linux/parser.h>
-
-/* Define this to allow debugging output */
-#undef NFSROOT_DEBUG
-#define NFSDBG_FACILITY NFSDBG_ROOT
-
-/* Default path we try to mount. "%s" gets replaced by our IP address */
-#define NFS_ROOT		"/tftpboot/%s"
-
-/* Parameters passed from the kernel command line */
-static char nfs_root_name[256] __initdata = "";
-
-/* Address of NFS server */
-static __be32 servaddr __initdata = 0;
-
-/* Name of directory to mount */
-static char nfs_path[NFS_MAXPATHLEN] __initdata = { 0, };
-
-/* NFS-related data */
-static struct nfs_mount_data nfs_data __initdata = { 0, };/* NFS mount info */
-static int nfs_port __initdata = 0;		/* Port to connect to for NFS */
-static int mount_port __initdata = 0;		/* Mount daemon port number */
-
-
-/***************************************************************************
-
-			     Parsing of options
-
- ***************************************************************************/
-
-enum {
-	/* Options that take integer arguments */
-	Opt_port, Opt_rsize, Opt_wsize, Opt_timeo, Opt_retrans, Opt_acregmin,
-	Opt_acregmax, Opt_acdirmin, Opt_acdirmax,
-	/* Options that take no arguments */
-	Opt_soft, Opt_hard, Opt_intr,
-	Opt_nointr, Opt_posix, Opt_noposix, Opt_cto, Opt_nocto, Opt_ac, 
-	Opt_noac, Opt_lock, Opt_nolock, Opt_v2, Opt_v3, Opt_udp, Opt_tcp,
-	Opt_acl, Opt_noacl,
-	/* Error token */
-	Opt_err
-};
-
-static match_table_t __initdata tokens = {
-	{Opt_port, "port=%u"},
-	{Opt_rsize, "rsize=%u"},
-	{Opt_wsize, "wsize=%u"},
-	{Opt_timeo, "timeo=%u"},
-	{Opt_retrans, "retrans=%u"},
-	{Opt_acregmin, "acregmin=%u"},
-	{Opt_acregmax, "acregmax=%u"},
-	{Opt_acdirmin, "acdirmin=%u"},
-	{Opt_acdirmax, "acdirmax=%u"},
-	{Opt_soft, "soft"},
-	{Opt_hard, "hard"},
-	{Opt_intr, "intr"},
-	{Opt_nointr, "nointr"},
-	{Opt_posix, "posix"},
-	{Opt_noposix, "noposix"},
-	{Opt_cto, "cto"},
-	{Opt_nocto, "nocto"},
-	{Opt_ac, "ac"},
-	{Opt_noac, "noac"},
-	{Opt_lock, "lock"},
-	{Opt_nolock, "nolock"},
-	{Opt_v2, "nfsvers=2"},
-	{Opt_v2, "v2"},
-	{Opt_v3, "nfsvers=3"},
-	{Opt_v3, "v3"},
-	{Opt_udp, "proto=udp"},
-	{Opt_udp, "udp"},
-	{Opt_tcp, "proto=tcp"},
-	{Opt_tcp, "tcp"},
-	{Opt_acl, "acl"},
-	{Opt_noacl, "noacl"},
-	{Opt_err, NULL}
-	
-};
-
-/*
- *  Parse option string.
- */
-
-static int __init root_nfs_parse(char *name, char *buf)
-{
-
-	char *p;
-	substring_t args[MAX_OPT_ARGS];
-	int option;
-
-	if (!name)
-		return 1;
-
-	/* Set the NFS remote path */
-	p = strsep(&name, ",");
-	if (p[0] != '\0' && strcmp(p, "default") != 0)
-		strlcpy(buf, p, NFS_MAXPATHLEN);
-
-	while ((p = strsep (&name, ",")) != NULL) {
-		int token; 
-		if (!*p)
-			continue;
-		token = match_token(p, tokens, args);
-
-		/* %u tokens only. Beware if you add new tokens! */
-		if (token < Opt_soft && match_int(&args[0], &option))
-			return 0;
-		switch (token) {
-			case Opt_port:
-				nfs_port = option;
-				break;
-			case Opt_rsize:
-				nfs_data.rsize = option;
-				break;
-			case Opt_wsize:
-				nfs_data.wsize = option;
-				break;
-			case Opt_timeo:
-				nfs_data.timeo = option;
-				break;
-			case Opt_retrans:
-				nfs_data.retrans = option;
-				break;
-			case Opt_acregmin:
-				nfs_data.acregmin = option;
-				break;
-			case Opt_acregmax:
-				nfs_data.acregmax = option;
-				break;
-			case Opt_acdirmin:
-				nfs_data.acdirmin = option;
-				break;
-			case Opt_acdirmax:
-				nfs_data.acdirmax = option;
-				break;
-			case Opt_soft:
-				nfs_data.flags |= NFS_MOUNT_SOFT;
-				break;
-			case Opt_hard:
-				nfs_data.flags &= ~NFS_MOUNT_SOFT;
-				break;
-			case Opt_intr:
-				nfs_data.flags |= NFS_MOUNT_INTR;
-				break;
-			case Opt_nointr:
-				nfs_data.flags &= ~NFS_MOUNT_INTR;
-				break;
-			case Opt_posix:
-				nfs_data.flags |= NFS_MOUNT_POSIX;
-				break;
-			case Opt_noposix:
-				nfs_data.flags &= ~NFS_MOUNT_POSIX;
-				break;
-			case Opt_cto:
-				nfs_data.flags &= ~NFS_MOUNT_NOCTO;
-				break;
-			case Opt_nocto:
-				nfs_data.flags |= NFS_MOUNT_NOCTO;
-				break;
-			case Opt_ac:
-				nfs_data.flags &= ~NFS_MOUNT_NOAC;
-				break;
-			case Opt_noac:
-				nfs_data.flags |= NFS_MOUNT_NOAC;
-				break;
-			case Opt_lock:
-				nfs_data.flags &= ~NFS_MOUNT_NONLM;
-				break;
-			case Opt_nolock:
-				nfs_data.flags |= NFS_MOUNT_NONLM;
-				break;
-			case Opt_v2:
-				nfs_data.flags &= ~NFS_MOUNT_VER3;
-				break;
-			case Opt_v3:
-				nfs_data.flags |= NFS_MOUNT_VER3;
-				break;
-			case Opt_udp:
-				nfs_data.flags &= ~NFS_MOUNT_TCP;
-				break;
-			case Opt_tcp:
-				nfs_data.flags |= NFS_MOUNT_TCP;
-				break;
-			case Opt_acl:
-				nfs_data.flags &= ~NFS_MOUNT_NOACL;
-				break;
-			case Opt_noacl:
-				nfs_data.flags |= NFS_MOUNT_NOACL;
-				break;
-			default:
-				printk(KERN_WARNING "Root-NFS: unknown "
-					"option: %s\n", p);
-				return 0;
-		}
-	}
-
-	return 1;
-}
-
-/*
- *  Prepare the NFS data structure and parse all options.
- */
-static int __init root_nfs_name(char *name)
-{
-	static char buf[NFS_MAXPATHLEN] __initdata;
-	char *cp;
-
-	/* Set some default values */
-	memset(&nfs_data, 0, sizeof(nfs_data));
-	nfs_port          = -1;
-	nfs_data.version  = NFS_MOUNT_VERSION;
-	nfs_data.flags    = NFS_MOUNT_NONLM;	/* No lockd in nfs root yet */
-	nfs_data.rsize    = NFS_DEF_FILE_IO_SIZE;
-	nfs_data.wsize    = NFS_DEF_FILE_IO_SIZE;
-	nfs_data.acregmin = 3;
-	nfs_data.acregmax = 60;
-	nfs_data.acdirmin = 30;
-	nfs_data.acdirmax = 60;
-	strcpy(buf, NFS_ROOT);
-
-	/* Process options received from the remote server */
-	root_nfs_parse(root_server_path, buf);
-
-	/* Override them by options set on kernel command-line */
-	root_nfs_parse(name, buf);
-
-	cp = utsname()->nodename;
-	if (strlen(buf) + strlen(cp) > NFS_MAXPATHLEN) {
-		printk(KERN_ERR "Root-NFS: Pathname for remote directory too long.\n");
-		return -1;
-	}
-	sprintf(nfs_path, buf, cp);
-
-	return 1;
-}
-
-
-/*
- *  Get NFS server address.
- */
-static int __init root_nfs_addr(void)
-{
-	if ((servaddr = root_server_addr) == htonl(INADDR_NONE)) {
-		printk(KERN_ERR "Root-NFS: No NFS server available, giving up.\n");
-		return -1;
-	}
-
-	snprintf(nfs_data.hostname, sizeof(nfs_data.hostname),
-		 "%u.%u.%u.%u", NIPQUAD(servaddr));
-	return 0;
-}
-
-/*
- *  Tell the user what's going on.
- */
-#ifdef NFSROOT_DEBUG
-static void __init root_nfs_print(void)
-{
-	printk(KERN_NOTICE "Root-NFS: Mounting %s on server %s as root\n",
-		nfs_path, nfs_data.hostname);
-	printk(KERN_NOTICE "Root-NFS:     rsize = %d, wsize = %d, timeo = %d, retrans = %d\n",
-		nfs_data.rsize, nfs_data.wsize, nfs_data.timeo, nfs_data.retrans);
-	printk(KERN_NOTICE "Root-NFS:     acreg (min,max) = (%d,%d), acdir (min,max) = (%d,%d)\n",
-		nfs_data.acregmin, nfs_data.acregmax,
-		nfs_data.acdirmin, nfs_data.acdirmax);
-	printk(KERN_NOTICE "Root-NFS:     nfsd port = %d, mountd port = %d, flags = %08x\n",
-		nfs_port, mount_port, nfs_data.flags);
-}
-#endif
-
-
-static int __init root_nfs_init(void)
-{
-#ifdef NFSROOT_DEBUG
-	nfs_debug |= NFSDBG_ROOT;
-#endif
-
-	/*
-	 * Decode the root directory path name and NFS options from
-	 * the kernel command line. This has to go here in order to
-	 * be able to use the client IP address for the remote root
-	 * directory (necessary for pure RARP booting).
-	 */
-	if (root_nfs_name(nfs_root_name) < 0 ||
-	    root_nfs_addr() < 0)
-		return -1;
-
-#ifdef NFSROOT_DEBUG
-	root_nfs_print();
-#endif
-
-	return 0;
-}
-
-
-/*
- *  Parse NFS server and directory information passed on the kernel
- *  command line.
- */
-static int __init nfs_root_setup(char *line)
-{
-	ROOT_DEV = Root_NFS;
-	if (line[0] == '/' || line[0] == ',' || (line[0] >= '0' && line[0] <= '9')) {
-		strlcpy(nfs_root_name, line, sizeof(nfs_root_name));
-	} else {
-		int n = strlen(line) + sizeof(NFS_ROOT) - 1;
-		if (n >= sizeof(nfs_root_name))
-			line[sizeof(nfs_root_name) - sizeof(NFS_ROOT) - 2] = '\0';
-		sprintf(nfs_root_name, NFS_ROOT, line);
-	}
-	root_server_addr = root_nfs_parse_addr(nfs_root_name);
-	return 1;
-}
-
-__setup("nfsroot=", nfs_root_setup);
-
-/***************************************************************************
-
-	       Routines to actually mount the root directory
-
- ***************************************************************************/
-
-/*
- *  Construct sockaddr_in from address and port number.
- */
-static inline void
-set_sockaddr(struct sockaddr_in *sin, __be32 addr, __be16 port)
-{
-	sin->sin_family = AF_INET;
-	sin->sin_addr.s_addr = addr;
-	sin->sin_port = port;
-}
-
-/*
- *  Query server portmapper for the port of a daemon program.
- */
-static int __init root_nfs_getport(int program, int version, int proto)
-{
-	struct sockaddr_in sin;
-
-	printk(KERN_NOTICE "Looking up port of RPC %d/%d on %u.%u.%u.%u\n",
-		program, version, NIPQUAD(servaddr));
-	set_sockaddr(&sin, servaddr, 0);
-	return rpcb_getport_external(&sin, program, version, proto);
-}
-
-
-/*
- *  Use portmapper to find mountd and nfsd port numbers if not overriden
- *  by the user. Use defaults if portmapper is not available.
- *  XXX: Is there any nfs server with no portmapper?
- */
-static int __init root_nfs_ports(void)
-{
-	int port;
-	int nfsd_ver, mountd_ver;
-	int nfsd_port, mountd_port;
-	int proto;
-
-	if (nfs_data.flags & NFS_MOUNT_VER3) {
-		nfsd_ver = NFS3_VERSION;
-		mountd_ver = NFS_MNT3_VERSION;
-		nfsd_port = NFS_PORT;
-		mountd_port = NFS_MNT_PORT;
-	} else {
-		nfsd_ver = NFS2_VERSION;
-		mountd_ver = NFS_MNT_VERSION;
-		nfsd_port = NFS_PORT;
-		mountd_port = NFS_MNT_PORT;
-	}
-
-	proto = (nfs_data.flags & NFS_MOUNT_TCP) ? IPPROTO_TCP : IPPROTO_UDP;
-
-	if (nfs_port < 0) {
-		if ((port = root_nfs_getport(NFS_PROGRAM, nfsd_ver, proto)) < 0) {
-			printk(KERN_ERR "Root-NFS: Unable to get nfsd port "
-					"number from server, using default\n");
-			port = nfsd_port;
-		}
-		nfs_port = port;
-		dprintk("Root-NFS: Portmapper on server returned %d "
-			"as nfsd port\n", port);
-	}
-
-	if ((port = root_nfs_getport(NFS_MNT_PROGRAM, mountd_ver, proto)) < 0) {
-		printk(KERN_ERR "Root-NFS: Unable to get mountd port "
-				"number from server, using default\n");
-		port = mountd_port;
-	}
-	mount_port = port;
-	dprintk("Root-NFS: mountd port is %d\n", port);
-
-	return 0;
-}
-
-
-/*
- *  Get a file handle from the server for the directory which is to be
- *  mounted.
- */
-static int __init root_nfs_get_handle(void)
-{
-	struct nfs_fh fh;
-	struct sockaddr_in sin;
-	int status;
-	int protocol = (nfs_data.flags & NFS_MOUNT_TCP) ?
-					IPPROTO_TCP : IPPROTO_UDP;
-	int version = (nfs_data.flags & NFS_MOUNT_VER3) ?
-					NFS_MNT3_VERSION : NFS_MNT_VERSION;
-
-	set_sockaddr(&sin, servaddr, htons(mount_port));
-	status = nfsroot_mount(&sin, nfs_path, &fh, version, protocol);
-	if (status < 0)
-		printk(KERN_ERR "Root-NFS: Server returned error %d "
-				"while mounting %s\n", status, nfs_path);
-	else {
-		nfs_data.root.size = fh.size;
-		memcpy(nfs_data.root.data, fh.data, fh.size);
-	}
-
-	return status;
-}
-
-/*
- *  Get the NFS port numbers and file handle, and return the prepared 'data'
- *  argument for mount() if everything went OK. Return NULL otherwise.
- */
-void * __init nfs_root_data(void)
-{
-	if (root_nfs_init() < 0
-	 || root_nfs_ports() < 0
-	 || root_nfs_get_handle() < 0)
-		return NULL;
-	set_sockaddr((struct sockaddr_in *) &nfs_data.addr, servaddr, htons(nfs_port));
-	return (void*)&nfs_data;
-}
diff --git a/include/linux/mount.h b/include/linux/mount.h
index 6d3047d..fa89ece 100644
--- a/include/linux/mount.h
+++ b/include/linux/mount.h
@@ -101,7 +101,6 @@
 extern void shrink_submounts(struct vfsmount *mountpoint, struct list_head *mounts);
 
 extern spinlock_t vfsmount_lock;
-extern dev_t name_to_dev_t(char *name);
 
 #endif
 #endif /* _LINUX_MOUNT_H */
diff --git a/init/Makefile b/init/Makefile
index 0154aea..acfdb2c 100644
--- a/init/Makefile
+++ b/init/Makefile
@@ -2,19 +2,9 @@
 # Makefile for the linux kernel.
 #
 
-obj-y                          := main.o version.o mounts.o
-ifneq ($(CONFIG_BLK_DEV_INITRD),y)
-obj-y                          += noinitramfs.o
-else
-obj-$(CONFIG_BLK_DEV_INITRD)   += initramfs.o
-endif
+obj-y				:= main.o version.o initramfs.o
 obj-$(CONFIG_GENERIC_CALIBRATE_DELAY) += calibrate.o
 
-mounts-y			:= do_mounts.o
-mounts-$(CONFIG_BLK_DEV_RAM)	+= do_mounts_rd.o
-mounts-$(CONFIG_BLK_DEV_INITRD)	+= do_mounts_initrd.o
-mounts-$(CONFIG_BLK_DEV_MD)	+= do_mounts_md.o
-
 # files to be removed upon make clean
 clean-files := ../include/linux/compile.h
 
diff --git a/init/do_mounts.c b/init/do_mounts.c
deleted file mode 100644
index 46fe407..0000000
--- a/init/do_mounts.c
+++ /dev/null
@@ -1,455 +0,0 @@
-#include <linux/module.h>
-#include <linux/sched.h>
-#include <linux/ctype.h>
-#include <linux/fd.h>
-#include <linux/tty.h>
-#include <linux/suspend.h>
-#include <linux/root_dev.h>
-#include <linux/security.h>
-#include <linux/delay.h>
-#include <linux/genhd.h>
-#include <linux/mount.h>
-#include <linux/device.h>
-#include <linux/init.h>
-
-#include <linux/nfs_fs.h>
-#include <linux/nfs_fs_sb.h>
-#include <linux/nfs_mount.h>
-
-#include "do_mounts.h"
-
-extern int get_filesystem_list(char * buf);
-
-int __initdata rd_doload;	/* 1 = load RAM disk, 0 = don't load */
-
-int root_mountflags = MS_RDONLY | MS_SILENT;
-char * __initdata root_device_name;
-static char __initdata saved_root_name[64];
-
-dev_t ROOT_DEV;
-
-static int __init load_ramdisk(char *str)
-{
-	rd_doload = simple_strtol(str,NULL,0) & 3;
-	return 1;
-}
-__setup("load_ramdisk=", load_ramdisk);
-
-static int __init readonly(char *str)
-{
-	if (*str)
-		return 0;
-	root_mountflags |= MS_RDONLY;
-	return 1;
-}
-
-static int __init readwrite(char *str)
-{
-	if (*str)
-		return 0;
-	root_mountflags &= ~MS_RDONLY;
-	return 1;
-}
-
-__setup("ro", readonly);
-__setup("rw", readwrite);
-
-static dev_t try_name(char *name, int part)
-{
-	char path[64];
-	char buf[32];
-	int range;
-	dev_t res;
-	char *s;
-	int len;
-	int fd;
-	unsigned int maj, min;
-
-	/* read device number from .../dev */
-
-	sprintf(path, "/sys/block/%s/dev", name);
-	fd = sys_open(path, 0, 0);
-	if (fd < 0)
-		goto fail;
-	len = sys_read(fd, buf, 32);
-	sys_close(fd);
-	if (len <= 0 || len == 32 || buf[len - 1] != '\n')
-		goto fail;
-	buf[len - 1] = '\0';
-	if (sscanf(buf, "%u:%u", &maj, &min) == 2) {
-		/*
-		 * Try the %u:%u format -- see print_dev_t()
-		 */
-		res = MKDEV(maj, min);
-		if (maj != MAJOR(res) || min != MINOR(res))
-			goto fail;
-	} else {
-		/*
-		 * Nope.  Try old-style "0321"
-		 */
-		res = new_decode_dev(simple_strtoul(buf, &s, 16));
-		if (*s)
-			goto fail;
-	}
-
-	/* if it's there and we are not looking for a partition - that's it */
-	if (!part)
-		return res;
-
-	/* otherwise read range from .../range */
-	sprintf(path, "/sys/block/%s/range", name);
-	fd = sys_open(path, 0, 0);
-	if (fd < 0)
-		goto fail;
-	len = sys_read(fd, buf, 32);
-	sys_close(fd);
-	if (len <= 0 || len == 32 || buf[len - 1] != '\n')
-		goto fail;
-	buf[len - 1] = '\0';
-	range = simple_strtoul(buf, &s, 10);
-	if (*s)
-		goto fail;
-
-	/* if partition is within range - we got it */
-	if (part < range)
-		return res + part;
-fail:
-	return 0;
-}
-
-/*
- *	Convert a name into device number.  We accept the following variants:
- *
- *	1) device number in hexadecimal	represents itself
- *	2) /dev/nfs represents Root_NFS (0xff)
- *	3) /dev/<disk_name> represents the device number of disk
- *	4) /dev/<disk_name><decimal> represents the device number
- *         of partition - device number of disk plus the partition number
- *	5) /dev/<disk_name>p<decimal> - same as the above, that form is
- *	   used when disk name of partitioned disk ends on a digit.
- *
- *	If name doesn't have fall into the categories above, we return 0.
- *	Sysfs is used to check if something is a disk name - it has
- *	all known disks under bus/block/devices.  If the disk name
- *	contains slashes, name of sysfs node has them replaced with
- *	bangs.  try_name() does the actual checks, assuming that sysfs
- *	is mounted on rootfs /sys.
- */
-
-dev_t name_to_dev_t(char *name)
-{
-	char s[32];
-	char *p;
-	dev_t res = 0;
-	int part;
-
-#ifdef CONFIG_SYSFS
-	int mkdir_err = sys_mkdir("/sys", 0700);
-	if (sys_mount("sysfs", "/sys", "sysfs", 0, NULL) < 0)
-		goto out;
-#endif
-
-	if (strncmp(name, "/dev/", 5) != 0) {
-		unsigned maj, min;
-
-		if (sscanf(name, "%u:%u", &maj, &min) == 2) {
-			res = MKDEV(maj, min);
-			if (maj != MAJOR(res) || min != MINOR(res))
-				goto fail;
-		} else {
-			res = new_decode_dev(simple_strtoul(name, &p, 16));
-			if (*p)
-				goto fail;
-		}
-		goto done;
-	}
-	name += 5;
-	res = Root_NFS;
-	if (strcmp(name, "nfs") == 0)
-		goto done;
-	res = Root_RAM0;
-	if (strcmp(name, "ram") == 0)
-		goto done;
-
-	if (strlen(name) > 31)
-		goto fail;
-	strcpy(s, name);
-	for (p = s; *p; p++)
-		if (*p == '/')
-			*p = '!';
-	res = try_name(s, 0);
-	if (res)
-		goto done;
-
-	while (p > s && isdigit(p[-1]))
-		p--;
-	if (p == s || !*p || *p == '0')
-		goto fail;
-	part = simple_strtoul(p, NULL, 10);
-	*p = '\0';
-	res = try_name(s, part);
-	if (res)
-		goto done;
-
-	if (p < s + 2 || !isdigit(p[-2]) || p[-1] != 'p')
-		goto fail;
-	p[-1] = '\0';
-	res = try_name(s, part);
-done:
-#ifdef CONFIG_SYSFS
-	sys_umount("/sys", 0);
-out:
-	if (!mkdir_err)
-		sys_rmdir("/sys");
-#endif
-	return res;
-fail:
-	res = 0;
-	goto done;
-}
-
-static int __init root_dev_setup(char *line)
-{
-	strlcpy(saved_root_name, line, sizeof(saved_root_name));
-	return 1;
-}
-
-__setup("root=", root_dev_setup);
-
-static char * __initdata root_mount_data;
-static int __init root_data_setup(char *str)
-{
-	root_mount_data = str;
-	return 1;
-}
-
-static char * __initdata root_fs_names;
-static int __init fs_names_setup(char *str)
-{
-	root_fs_names = str;
-	return 1;
-}
-
-static unsigned int __initdata root_delay;
-static int __init root_delay_setup(char *str)
-{
-	root_delay = simple_strtoul(str, NULL, 0);
-	return 1;
-}
-
-__setup("rootflags=", root_data_setup);
-__setup("rootfstype=", fs_names_setup);
-__setup("rootdelay=", root_delay_setup);
-
-static void __init get_fs_names(char *page)
-{
-	char *s = page;
-
-	if (root_fs_names) {
-		strcpy(page, root_fs_names);
-		while (*s++) {
-			if (s[-1] == ',')
-				s[-1] = '\0';
-		}
-	} else {
-		int len = get_filesystem_list(page);
-		char *p, *next;
-
-		page[len] = '\0';
-		for (p = page-1; p; p = next) {
-			next = strchr(++p, '\n');
-			if (*p++ != '\t')
-				continue;
-			while ((*s++ = *p++) != '\n')
-				;
-			s[-1] = '\0';
-		}
-	}
-	*s = '\0';
-}
-
-static int __init do_mount_root(char *name, char *fs, int flags, void *data)
-{
-	int err = sys_mount(name, "/root", fs, flags, data);
-	if (err)
-		return err;
-
-	sys_chdir("/root");
-	ROOT_DEV = current->fs->pwdmnt->mnt_sb->s_dev;
-	printk("VFS: Mounted root (%s filesystem)%s.\n",
-	       current->fs->pwdmnt->mnt_sb->s_type->name,
-	       current->fs->pwdmnt->mnt_sb->s_flags & MS_RDONLY ? 
-	       " readonly" : "");
-	return 0;
-}
-
-void __init mount_block_root(char *name, int flags)
-{
-	char *fs_names = __getname();
-	char *p;
-#ifdef CONFIG_BLOCK
-	char b[BDEVNAME_SIZE];
-#else
-	const char *b = name;
-#endif
-
-	get_fs_names(fs_names);
-retry:
-	for (p = fs_names; *p; p += strlen(p)+1) {
-		int err = do_mount_root(name, p, flags, root_mount_data);
-		switch (err) {
-			case 0:
-				goto out;
-			case -EACCES:
-				flags |= MS_RDONLY;
-				goto retry;
-			case -EINVAL:
-				continue;
-		}
-	        /*
-		 * Allow the user to distinguish between failed sys_open
-		 * and bad superblock on root device.
-		 * and give them a list of the available devices
-		 */
-#ifdef CONFIG_BLOCK
-		__bdevname(ROOT_DEV, b);
-#endif
-		printk("VFS: Cannot open root device \"%s\" or %s\n",
-				root_device_name, b);
-		printk("Please append a correct \"root=\" boot option; here are the available partitions:\n");
-
-		printk_all_partitions();
-		panic("VFS: Unable to mount root fs on %s", b);
-	}
-
-	printk("List of all partitions:\n");
-	printk_all_partitions();
-	printk("No filesystem could mount root, tried: ");
-	for (p = fs_names; *p; p += strlen(p)+1)
-		printk(" %s", p);
-	printk("\n");
-#ifdef CONFIG_BLOCK
-	__bdevname(ROOT_DEV, b);
-#endif
-	panic("VFS: Unable to mount root fs on %s", b);
-out:
-	putname(fs_names);
-}
- 
-#ifdef CONFIG_ROOT_NFS
-static int __init mount_nfs_root(void)
-{
-	void *data = nfs_root_data();
-
-	create_dev("/dev/root", ROOT_DEV);
-	if (data &&
-	    do_mount_root("/dev/root", "nfs", root_mountflags, data) == 0)
-		return 1;
-	return 0;
-}
-#endif
-
-#if defined(CONFIG_BLK_DEV_RAM) || defined(CONFIG_BLK_DEV_FD)
-void __init change_floppy(char *fmt, ...)
-{
-	struct termios termios;
-	char buf[80];
-	char c;
-	int fd;
-	va_list args;
-	va_start(args, fmt);
-	vsprintf(buf, fmt, args);
-	va_end(args);
-	fd = sys_open("/dev/root", O_RDWR | O_NDELAY, 0);
-	if (fd >= 0) {
-		sys_ioctl(fd, FDEJECT, 0);
-		sys_close(fd);
-	}
-	printk(KERN_NOTICE "VFS: Insert %s and press ENTER\n", buf);
-	fd = sys_open("/dev/console", O_RDWR, 0);
-	if (fd >= 0) {
-		sys_ioctl(fd, TCGETS, (long)&termios);
-		termios.c_lflag &= ~ICANON;
-		sys_ioctl(fd, TCSETSF, (long)&termios);
-		sys_read(fd, &c, 1);
-		termios.c_lflag |= ICANON;
-		sys_ioctl(fd, TCSETSF, (long)&termios);
-		sys_close(fd);
-	}
-}
-#endif
-
-void __init mount_root(void)
-{
-#ifdef CONFIG_ROOT_NFS
-	if (MAJOR(ROOT_DEV) == UNNAMED_MAJOR) {
-		if (mount_nfs_root())
-			return;
-
-		printk(KERN_ERR "VFS: Unable to mount root fs via NFS, trying floppy.\n");
-		ROOT_DEV = Root_FD0;
-	}
-#endif
-#ifdef CONFIG_BLK_DEV_FD
-	if (MAJOR(ROOT_DEV) == FLOPPY_MAJOR) {
-		/* rd_doload is 2 for a dual initrd/ramload setup */
-		if (rd_doload==2) {
-			if (rd_load_disk(1)) {
-				ROOT_DEV = Root_RAM1;
-				root_device_name = NULL;
-			}
-		} else
-			change_floppy("root floppy");
-	}
-#endif
-#ifdef CONFIG_BLOCK
-	create_dev("/dev/root", ROOT_DEV);
-	mount_block_root("/dev/root", root_mountflags);
-#endif
-}
-
-/*
- * Prepare the namespace - decide what/where to mount, load ramdisks, etc.
- */
-void __init prepare_namespace(void)
-{
-	int is_floppy;
-
-	if (root_delay) {
-		printk(KERN_INFO "Waiting %dsec before mounting root device...\n",
-		       root_delay);
-		ssleep(root_delay);
-	}
-
-	/* wait for the known devices to complete their probing */
-	while (driver_probe_done() != 0)
-		msleep(100);
-
-	md_run_setup();
-
-	if (saved_root_name[0]) {
-		root_device_name = saved_root_name;
-		if (!strncmp(root_device_name, "mtd", 3)) {
-			mount_block_root(root_device_name, root_mountflags);
-			goto out;
-		}
-		ROOT_DEV = name_to_dev_t(root_device_name);
-		if (strncmp(root_device_name, "/dev/", 5) == 0)
-			root_device_name += 5;
-	}
-
-	is_floppy = MAJOR(ROOT_DEV) == FLOPPY_MAJOR;
-
-	if (initrd_load())
-		goto out;
-
-	if (is_floppy && rd_doload && rd_load_disk(0))
-		ROOT_DEV = Root_RAM0;
-
-	mount_root();
-out:
-	sys_mount(".", "/", NULL, MS_MOVE, NULL);
-	sys_chroot(".");
-	security_sb_post_mountroot();
-}
-
diff --git a/init/do_mounts.h b/init/do_mounts.h
deleted file mode 100644
index 735705d..0000000
--- a/init/do_mounts.h
+++ /dev/null
@@ -1,76 +0,0 @@
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/syscalls.h>
-#include <linux/unistd.h>
-#include <linux/slab.h>
-#include <linux/mount.h>
-#include <linux/major.h>
-#include <linux/root_dev.h>
-
-void  change_floppy(char *fmt, ...);
-void  mount_block_root(char *name, int flags);
-void  mount_root(void);
-extern int root_mountflags;
-extern char *root_device_name;
-
-static inline int create_dev(char *name, dev_t dev)
-{
-	sys_unlink(name);
-	return sys_mknod(name, S_IFBLK|0600, new_encode_dev(dev));
-}
-
-#if BITS_PER_LONG == 32
-static inline u32 bstat(char *name)
-{
-	struct stat64 stat;
-	if (sys_stat64(name, &stat) != 0)
-		return 0;
-	if (!S_ISBLK(stat.st_mode))
-		return 0;
-	if (stat.st_rdev != (u32)stat.st_rdev)
-		return 0;
-	return stat.st_rdev;
-}
-#else
-static inline u32 bstat(char *name)
-{
-	struct stat stat;
-	if (sys_newstat(name, &stat) != 0)
-		return 0;
-	if (!S_ISBLK(stat.st_mode))
-		return 0;
-	return stat.st_rdev;
-}
-#endif
-
-#ifdef CONFIG_BLK_DEV_RAM
-
-int __init rd_load_disk(int n);
-int __init rd_load_image(char *from);
-
-#else
-
-static inline int rd_load_disk(int n) { return 0; }
-static inline int rd_load_image(char *from) { return 0; }
-
-#endif
-
-#ifdef CONFIG_BLK_DEV_INITRD
-
-int __init initrd_load(void);
-
-#else
-
-static inline int initrd_load(void) { return 0; }
-
-#endif
-
-#ifdef CONFIG_BLK_DEV_MD
-
-void md_run_setup(void);
-
-#else
-
-static inline void md_run_setup(void) {}
-
-#endif
diff --git a/init/do_mounts_initrd.c b/init/do_mounts_initrd.c
deleted file mode 100644
index b222ce9..0000000
--- a/init/do_mounts_initrd.c
+++ /dev/null
@@ -1,124 +0,0 @@
-#include <linux/unistd.h>
-#include <linux/kernel.h>
-#include <linux/fs.h>
-#include <linux/minix_fs.h>
-#include <linux/ext2_fs.h>
-#include <linux/romfs_fs.h>
-#include <linux/initrd.h>
-#include <linux/sched.h>
-#include <linux/freezer.h>
-
-#include "do_mounts.h"
-
-unsigned long initrd_start, initrd_end;
-int initrd_below_start_ok;
-unsigned int real_root_dev;	/* do_proc_dointvec cannot handle kdev_t */
-static int __initdata old_fd, root_fd;
-static int __initdata mount_initrd = 1;
-
-static int __init no_initrd(char *str)
-{
-	mount_initrd = 0;
-	return 1;
-}
-
-__setup("noinitrd", no_initrd);
-
-static int __init do_linuxrc(void * shell)
-{
-	static char *argv[] = { "linuxrc", NULL, };
-	extern char * envp_init[];
-
-	sys_close(old_fd);sys_close(root_fd);
-	sys_close(0);sys_close(1);sys_close(2);
-	sys_setsid();
-	(void) sys_open("/dev/console",O_RDWR,0);
-	(void) sys_dup(0);
-	(void) sys_dup(0);
-	return kernel_execve(shell, argv, envp_init);
-}
-
-static void __init handle_initrd(void)
-{
-	int error;
-	int pid;
-
-	real_root_dev = new_encode_dev(ROOT_DEV);
-	create_dev("/dev/root.old", Root_RAM0);
-	/* mount initrd on rootfs' /root */
-	mount_block_root("/dev/root.old", root_mountflags & ~MS_RDONLY);
-	sys_mkdir("/old", 0700);
-	root_fd = sys_open("/", 0, 0);
-	old_fd = sys_open("/old", 0, 0);
-	/* move initrd over / and chdir/chroot in initrd root */
-	sys_chdir("/root");
-	sys_mount(".", "/", NULL, MS_MOVE, NULL);
-	sys_chroot(".");
-
-	pid = kernel_thread(do_linuxrc, "/linuxrc", SIGCHLD);
-	if (pid > 0) {
-		while (pid != sys_wait4(-1, NULL, 0, NULL)) {
-			try_to_freeze();
-			yield();
-		}
-	}
-
-	/* move initrd to rootfs' /old */
-	sys_fchdir(old_fd);
-	sys_mount("/", ".", NULL, MS_MOVE, NULL);
-	/* switch root and cwd back to / of rootfs */
-	sys_fchdir(root_fd);
-	sys_chroot(".");
-	sys_close(old_fd);
-	sys_close(root_fd);
-
-	if (new_decode_dev(real_root_dev) == Root_RAM0) {
-		sys_chdir("/old");
-		return;
-	}
-
-	ROOT_DEV = new_decode_dev(real_root_dev);
-	mount_root();
-
-	printk(KERN_NOTICE "Trying to move old root to /initrd ... ");
-	error = sys_mount("/old", "/root/initrd", NULL, MS_MOVE, NULL);
-	if (!error)
-		printk("okay\n");
-	else {
-		int fd = sys_open("/dev/root.old", O_RDWR, 0);
-		if (error == -ENOENT)
-			printk("/initrd does not exist. Ignored.\n");
-		else
-			printk("failed\n");
-		printk(KERN_NOTICE "Unmounting old root\n");
-		sys_umount("/old", MNT_DETACH);
-		printk(KERN_NOTICE "Trying to free ramdisk memory ... ");
-		if (fd < 0) {
-			error = fd;
-		} else {
-			error = sys_ioctl(fd, BLKFLSBUF, 0);
-			sys_close(fd);
-		}
-		printk(!error ? "okay\n" : "failed\n");
-	}
-}
-
-int __init initrd_load(void)
-{
-	if (mount_initrd) {
-		create_dev("/dev/ram", Root_RAM0);
-		/*
-		 * Load the initrd data into /dev/ram0. Execute it as initrd
-		 * unless /dev/ram0 is supposed to be our actual root device,
-		 * in that case the ram disk is just set up here, and gets
-		 * mounted in the normal path.
-		 */
-		if (rd_load_image("/initrd.image") && ROOT_DEV != Root_RAM0) {
-			sys_unlink("/initrd.image");
-			handle_initrd();
-			return 1;
-		}
-	}
-	sys_unlink("/initrd.image");
-	return 0;
-}
diff --git a/init/do_mounts_md.c b/init/do_mounts_md.c
deleted file mode 100644
index 753dc54..0000000
--- a/init/do_mounts_md.c
+++ /dev/null
@@ -1,281 +0,0 @@
-
-#include <linux/raid/md.h>
-
-#include "do_mounts.h"
-
-/*
- * When md (and any require personalities) are compiled into the kernel
- * (not a module), arrays can be assembles are boot time using with AUTODETECT
- * where specially marked partitions are registered with md_autodetect_dev(),
- * and with MD_BOOT where devices to be collected are given on the boot line
- * with md=.....
- * The code for that is here.
- */
-
-static int __initdata raid_noautodetect, raid_autopart;
-
-static struct {
-	int minor;
-	int partitioned;
-	int level;
-	int chunk;
-	char *device_names;
-} md_setup_args[256] __initdata;
-
-static int md_setup_ents __initdata;
-
-extern int mdp_major;
-/*
- * Parse the command-line parameters given our kernel, but do not
- * actually try to invoke the MD device now; that is handled by
- * md_setup_drive after the low-level disk drivers have initialised.
- *
- * 27/11/1999: Fixed to work correctly with the 2.3 kernel (which
- *             assigns the task of parsing integer arguments to the
- *             invoked program now).  Added ability to initialise all
- *             the MD devices (by specifying multiple "md=" lines)
- *             instead of just one.  -- KTK
- * 18May2000: Added support for persistent-superblock arrays:
- *             md=n,0,factor,fault,device-list   uses RAID0 for device n
- *             md=n,-1,factor,fault,device-list  uses LINEAR for device n
- *             md=n,device-list      reads a RAID superblock from the devices
- *             elements in device-list are read by name_to_kdev_t so can be
- *             a hex number or something like /dev/hda1 /dev/sdb
- * 2001-06-03: Dave Cinege <dcinege@psychosis.com>
- *		Shifted name_to_kdev_t() and related operations to md_set_drive()
- *		for later execution. Rewrote section to make devfs compatible.
- */
-static int __init md_setup(char *str)
-{
-	int minor, level, factor, fault, partitioned = 0;
-	char *pername = "";
-	char *str1;
-	int ent;
-
-	if (*str == 'd') {
-		partitioned = 1;
-		str++;
-	}
-	if (get_option(&str, &minor) != 2) {	/* MD Number */
-		printk(KERN_WARNING "md: Too few arguments supplied to md=.\n");
-		return 0;
-	}
-	str1 = str;
-	for (ent=0 ; ent< md_setup_ents ; ent++)
-		if (md_setup_args[ent].minor == minor &&
-		    md_setup_args[ent].partitioned == partitioned) {
-			printk(KERN_WARNING "md: md=%s%d, Specified more than once. "
-			       "Replacing previous definition.\n", partitioned?"d":"", minor);
-			break;
-		}
-	if (ent >= ARRAY_SIZE(md_setup_args)) {
-		printk(KERN_WARNING "md: md=%s%d - too many md initialisations\n", partitioned?"d":"", minor);
-		return 0;
-	}
-	if (ent >= md_setup_ents)
-		md_setup_ents++;
-	switch (get_option(&str, &level)) {	/* RAID level */
-	case 2: /* could be 0 or -1.. */
-		if (level == 0 || level == LEVEL_LINEAR) {
-			if (get_option(&str, &factor) != 2 ||	/* Chunk Size */
-					get_option(&str, &fault) != 2) {
-				printk(KERN_WARNING "md: Too few arguments supplied to md=.\n");
-				return 0;
-			}
-			md_setup_args[ent].level = level;
-			md_setup_args[ent].chunk = 1 << (factor+12);
-			if (level ==  LEVEL_LINEAR)
-				pername = "linear";
-			else
-				pername = "raid0";
-			break;
-		}
-		/* FALL THROUGH */
-	case 1: /* the first device is numeric */
-		str = str1;
-		/* FALL THROUGH */
-	case 0:
-		md_setup_args[ent].level = LEVEL_NONE;
-		pername="super-block";
-	}
-
-	printk(KERN_INFO "md: Will configure md%d (%s) from %s, below.\n",
-		minor, pername, str);
-	md_setup_args[ent].device_names = str;
-	md_setup_args[ent].partitioned = partitioned;
-	md_setup_args[ent].minor = minor;
-
-	return 1;
-}
-
-#define MdpMinorShift 6
-
-static void __init md_setup_drive(void)
-{
-	int minor, i, ent, partitioned;
-	dev_t dev;
-	dev_t devices[MD_SB_DISKS+1];
-
-	for (ent = 0; ent < md_setup_ents ; ent++) {
-		int fd;
-		int err = 0;
-		char *devname;
-		mdu_disk_info_t dinfo;
-		char name[16];
-
-		minor = md_setup_args[ent].minor;
-		partitioned = md_setup_args[ent].partitioned;
-		devname = md_setup_args[ent].device_names;
-
-		sprintf(name, "/dev/md%s%d", partitioned?"_d":"", minor);
-		if (partitioned)
-			dev = MKDEV(mdp_major, minor << MdpMinorShift);
-		else
-			dev = MKDEV(MD_MAJOR, minor);
-		create_dev(name, dev);
-		for (i = 0; i < MD_SB_DISKS && devname != 0; i++) {
-			char *p;
-			char comp_name[64];
-			u32 rdev;
-
-			p = strchr(devname, ',');
-			if (p)
-				*p++ = 0;
-
-			dev = name_to_dev_t(devname);
-			if (strncmp(devname, "/dev/", 5) == 0)
-				devname += 5;
-			snprintf(comp_name, 63, "/dev/%s", devname);
-			rdev = bstat(comp_name);
-			if (rdev)
-				dev = new_decode_dev(rdev);
-			if (!dev) {
-				printk(KERN_WARNING "md: Unknown device name: %s\n", devname);
-				break;
-			}
-
-			devices[i] = dev;
-
-			devname = p;
-		}
-		devices[i] = 0;
-
-		if (!i)
-			continue;
-
-		printk(KERN_INFO "md: Loading md%s%d: %s\n",
-			partitioned ? "_d" : "", minor,
-			md_setup_args[ent].device_names);
-
-		fd = sys_open(name, 0, 0);
-		if (fd < 0) {
-			printk(KERN_ERR "md: open failed - cannot start "
-					"array %s\n", name);
-			continue;
-		}
-		if (sys_ioctl(fd, SET_ARRAY_INFO, 0) == -EBUSY) {
-			printk(KERN_WARNING
-			       "md: Ignoring md=%d, already autodetected. (Use raid=noautodetect)\n",
-			       minor);
-			sys_close(fd);
-			continue;
-		}
-
-		if (md_setup_args[ent].level != LEVEL_NONE) {
-			/* non-persistent */
-			mdu_array_info_t ainfo;
-			ainfo.level = md_setup_args[ent].level;
-			ainfo.size = 0;
-			ainfo.nr_disks =0;
-			ainfo.raid_disks =0;
-			while (devices[ainfo.raid_disks])
-				ainfo.raid_disks++;
-			ainfo.md_minor =minor;
-			ainfo.not_persistent = 1;
-
-			ainfo.state = (1 << MD_SB_CLEAN);
-			ainfo.layout = 0;
-			ainfo.chunk_size = md_setup_args[ent].chunk;
-			err = sys_ioctl(fd, SET_ARRAY_INFO, (long)&ainfo);
-			for (i = 0; !err && i <= MD_SB_DISKS; i++) {
-				dev = devices[i];
-				if (!dev)
-					break;
-				dinfo.number = i;
-				dinfo.raid_disk = i;
-				dinfo.state = (1<<MD_DISK_ACTIVE)|(1<<MD_DISK_SYNC);
-				dinfo.major = MAJOR(dev);
-				dinfo.minor = MINOR(dev);
-				err = sys_ioctl(fd, ADD_NEW_DISK, (long)&dinfo);
-			}
-		} else {
-			/* persistent */
-			for (i = 0; i <= MD_SB_DISKS; i++) {
-				dev = devices[i];
-				if (!dev)
-					break;
-				dinfo.major = MAJOR(dev);
-				dinfo.minor = MINOR(dev);
-				sys_ioctl(fd, ADD_NEW_DISK, (long)&dinfo);
-			}
-		}
-		if (!err)
-			err = sys_ioctl(fd, RUN_ARRAY, 0);
-		if (err)
-			printk(KERN_WARNING "md: starting md%d failed\n", minor);
-		else {
-			/* reread the partition table.
-			 * I (neilb) and not sure why this is needed, but I cannot
-			 * boot a kernel with devfs compiled in from partitioned md
-			 * array without it
-			 */
-			sys_close(fd);
-			fd = sys_open(name, 0, 0);
-			sys_ioctl(fd, BLKRRPART, 0);
-		}
-		sys_close(fd);
-	}
-}
-
-static int __init raid_setup(char *str)
-{
-	int len, pos;
-
-	len = strlen(str) + 1;
-	pos = 0;
-
-	while (pos < len) {
-		char *comma = strchr(str+pos, ',');
-		int wlen;
-		if (comma)
-			wlen = (comma-str)-pos;
-		else	wlen = (len-1)-pos;
-
-		if (!strncmp(str, "noautodetect", wlen))
-			raid_noautodetect = 1;
-		if (strncmp(str, "partitionable", wlen)==0)
-			raid_autopart = 1;
-		if (strncmp(str, "part", wlen)==0)
-			raid_autopart = 1;
-		pos += wlen+1;
-	}
-	return 1;
-}
-
-__setup("raid=", raid_setup);
-__setup("md=", md_setup);
-
-void __init md_run_setup(void)
-{
-	create_dev("/dev/md0", MKDEV(MD_MAJOR, 0));
-	if (raid_noautodetect)
-		printk(KERN_INFO "md: Skipping autodetection of RAID arrays. (raid=noautodetect)\n");
-	else {
-		int fd = sys_open("/dev/md0", 0, 0);
-		if (fd >= 0) {
-			sys_ioctl(fd, RAID_AUTORUN, raid_autopart);
-			sys_close(fd);
-		}
-	}
-	md_setup_drive();
-}
diff --git a/init/do_mounts_rd.c b/init/do_mounts_rd.c
deleted file mode 100644
index ed652f4..0000000
--- a/init/do_mounts_rd.c
+++ /dev/null
@@ -1,429 +0,0 @@
-
-#include <linux/kernel.h>
-#include <linux/fs.h>
-#include <linux/minix_fs.h>
-#include <linux/ext2_fs.h>
-#include <linux/romfs_fs.h>
-#include <linux/cramfs_fs.h>
-#include <linux/initrd.h>
-#include <linux/string.h>
-
-#include "do_mounts.h"
-
-#define BUILD_CRAMDISK
-
-int __initdata rd_prompt = 1;/* 1 = prompt for RAM disk, 0 = don't prompt */
-
-static int __init prompt_ramdisk(char *str)
-{
-	rd_prompt = simple_strtol(str,NULL,0) & 1;
-	return 1;
-}
-__setup("prompt_ramdisk=", prompt_ramdisk);
-
-int __initdata rd_image_start;		/* starting block # of image */
-
-static int __init ramdisk_start_setup(char *str)
-{
-	rd_image_start = simple_strtol(str,NULL,0);
-	return 1;
-}
-__setup("ramdisk_start=", ramdisk_start_setup);
-
-static int __init crd_load(int in_fd, int out_fd);
-
-/*
- * This routine tries to find a RAM disk image to load, and returns the
- * number of blocks to read for a non-compressed image, 0 if the image
- * is a compressed image, and -1 if an image with the right magic
- * numbers could not be found.
- *
- * We currently check for the following magic numbers:
- * 	minix
- * 	ext2
- *	romfs
- *	cramfs
- * 	gzip
- */
-static int __init 
-identify_ramdisk_image(int fd, int start_block)
-{
-	const int size = 512;
-	struct minix_super_block *minixsb;
-	struct ext2_super_block *ext2sb;
-	struct romfs_super_block *romfsb;
-	struct cramfs_super *cramfsb;
-	int nblocks = -1;
-	unsigned char *buf;
-
-	buf = kmalloc(size, GFP_KERNEL);
-	if (buf == 0)
-		return -1;
-
-	minixsb = (struct minix_super_block *) buf;
-	ext2sb = (struct ext2_super_block *) buf;
-	romfsb = (struct romfs_super_block *) buf;
-	cramfsb = (struct cramfs_super *) buf;
-	memset(buf, 0xe5, size);
-
-	/*
-	 * Read block 0 to test for gzipped kernel
-	 */
-	sys_lseek(fd, start_block * BLOCK_SIZE, 0);
-	sys_read(fd, buf, size);
-
-	/*
-	 * If it matches the gzip magic numbers, return -1
-	 */
-	if (buf[0] == 037 && ((buf[1] == 0213) || (buf[1] == 0236))) {
-		printk(KERN_NOTICE
-		       "RAMDISK: Compressed image found at block %d\n",
-		       start_block);
-		nblocks = 0;
-		goto done;
-	}
-
-	/* romfs is at block zero too */
-	if (romfsb->word0 == ROMSB_WORD0 &&
-	    romfsb->word1 == ROMSB_WORD1) {
-		printk(KERN_NOTICE
-		       "RAMDISK: romfs filesystem found at block %d\n",
-		       start_block);
-		nblocks = (ntohl(romfsb->size)+BLOCK_SIZE-1)>>BLOCK_SIZE_BITS;
-		goto done;
-	}
-
-	if (cramfsb->magic == CRAMFS_MAGIC) {
-		printk(KERN_NOTICE
-		       "RAMDISK: cramfs filesystem found at block %d\n",
-		       start_block);
-		nblocks = (cramfsb->size + BLOCK_SIZE - 1) >> BLOCK_SIZE_BITS;
-		goto done;
-	}
-
-	/*
-	 * Read block 1 to test for minix and ext2 superblock
-	 */
-	sys_lseek(fd, (start_block+1) * BLOCK_SIZE, 0);
-	sys_read(fd, buf, size);
-
-	/* Try minix */
-	if (minixsb->s_magic == MINIX_SUPER_MAGIC ||
-	    minixsb->s_magic == MINIX_SUPER_MAGIC2) {
-		printk(KERN_NOTICE
-		       "RAMDISK: Minix filesystem found at block %d\n",
-		       start_block);
-		nblocks = minixsb->s_nzones << minixsb->s_log_zone_size;
-		goto done;
-	}
-
-	/* Try ext2 */
-	if (ext2sb->s_magic == cpu_to_le16(EXT2_SUPER_MAGIC)) {
-		printk(KERN_NOTICE
-		       "RAMDISK: ext2 filesystem found at block %d\n",
-		       start_block);
-		nblocks = le32_to_cpu(ext2sb->s_blocks_count) <<
-			le32_to_cpu(ext2sb->s_log_block_size);
-		goto done;
-	}
-
-	printk(KERN_NOTICE
-	       "RAMDISK: Couldn't find valid RAM disk image starting at %d.\n",
-	       start_block);
-	
-done:
-	sys_lseek(fd, start_block * BLOCK_SIZE, 0);
-	kfree(buf);
-	return nblocks;
-}
-
-int __init rd_load_image(char *from)
-{
-	int res = 0;
-	int in_fd, out_fd;
-	unsigned long rd_blocks, devblocks;
-	int nblocks, i, disk;
-	char *buf = NULL;
-	unsigned short rotate = 0;
-#if !defined(CONFIG_S390) && !defined(CONFIG_PPC_ISERIES)
-	char rotator[4] = { '|' , '/' , '-' , '\\' };
-#endif
-
-	out_fd = sys_open("/dev/ram", O_RDWR, 0);
-	if (out_fd < 0)
-		goto out;
-
-	in_fd = sys_open(from, O_RDONLY, 0);
-	if (in_fd < 0)
-		goto noclose_input;
-
-	nblocks = identify_ramdisk_image(in_fd, rd_image_start);
-	if (nblocks < 0)
-		goto done;
-
-	if (nblocks == 0) {
-#ifdef BUILD_CRAMDISK
-		if (crd_load(in_fd, out_fd) == 0)
-			goto successful_load;
-#else
-		printk(KERN_NOTICE
-		       "RAMDISK: Kernel does not support compressed "
-		       "RAM disk images\n");
-#endif
-		goto done;
-	}
-
-	/*
-	 * NOTE NOTE: nblocks is not actually blocks but
-	 * the number of kibibytes of data to load into a ramdisk.
-	 * So any ramdisk block size that is a multiple of 1KiB should
-	 * work when the appropriate ramdisk_blocksize is specified
-	 * on the command line.
-	 *
-	 * The default ramdisk_blocksize is 1KiB and it is generally
-	 * silly to use anything else, so make sure to use 1KiB
-	 * blocksize while generating ext2fs ramdisk-images.
-	 */
-	if (sys_ioctl(out_fd, BLKGETSIZE, (unsigned long)&rd_blocks) < 0)
-		rd_blocks = 0;
-	else
-		rd_blocks >>= 1;
-
-	if (nblocks > rd_blocks) {
-		printk("RAMDISK: image too big! (%dKiB/%ldKiB)\n",
-		       nblocks, rd_blocks);
-		goto done;
-	}
-		
-	/*
-	 * OK, time to copy in the data
-	 */
-	if (sys_ioctl(in_fd, BLKGETSIZE, (unsigned long)&devblocks) < 0)
-		devblocks = 0;
-	else
-		devblocks >>= 1;
-
-	if (strcmp(from, "/initrd.image") == 0)
-		devblocks = nblocks;
-
-	if (devblocks == 0) {
-		printk(KERN_ERR "RAMDISK: could not determine device size\n");
-		goto done;
-	}
-
-	buf = kmalloc(BLOCK_SIZE, GFP_KERNEL);
-	if (buf == 0) {
-		printk(KERN_ERR "RAMDISK: could not allocate buffer\n");
-		goto done;
-	}
-
-	printk(KERN_NOTICE "RAMDISK: Loading %dKiB [%ld disk%s] into ram disk... ",
-		nblocks, ((nblocks-1)/devblocks)+1, nblocks>devblocks ? "s" : "");
-	for (i = 0, disk = 1; i < nblocks; i++) {
-		if (i && (i % devblocks == 0)) {
-			printk("done disk #%d.\n", disk++);
-			rotate = 0;
-			if (sys_close(in_fd)) {
-				printk("Error closing the disk.\n");
-				goto noclose_input;
-			}
-			change_floppy("disk #%d", disk);
-			in_fd = sys_open(from, O_RDONLY, 0);
-			if (in_fd < 0)  {
-				printk("Error opening disk.\n");
-				goto noclose_input;
-			}
-			printk("Loading disk #%d... ", disk);
-		}
-		sys_read(in_fd, buf, BLOCK_SIZE);
-		sys_write(out_fd, buf, BLOCK_SIZE);
-#if !defined(CONFIG_S390) && !defined(CONFIG_PPC_ISERIES)
-		if (!(i % 16)) {
-			printk("%c\b", rotator[rotate & 0x3]);
-			rotate++;
-		}
-#endif
-	}
-	printk("done.\n");
-
-successful_load:
-	res = 1;
-done:
-	sys_close(in_fd);
-noclose_input:
-	sys_close(out_fd);
-out:
-	kfree(buf);
-	sys_unlink("/dev/ram");
-	return res;
-}
-
-int __init rd_load_disk(int n)
-{
-	if (rd_prompt)
-		change_floppy("root floppy disk to be loaded into RAM disk");
-	create_dev("/dev/root", ROOT_DEV);
-	create_dev("/dev/ram", MKDEV(RAMDISK_MAJOR, n));
-	return rd_load_image("/dev/root");
-}
-
-#ifdef BUILD_CRAMDISK
-
-/*
- * gzip declarations
- */
-
-#define OF(args)  args
-
-#ifndef memzero
-#define memzero(s, n)     memset ((s), 0, (n))
-#endif
-
-typedef unsigned char  uch;
-typedef unsigned short ush;
-typedef unsigned long  ulg;
-
-#define INBUFSIZ 4096
-#define WSIZE 0x8000    /* window size--must be a power of two, and */
-			/*  at least 32K for zip's deflate method */
-
-static uch *inbuf;
-static uch *window;
-
-static unsigned insize;  /* valid bytes in inbuf */
-static unsigned inptr;   /* index of next byte to be processed in inbuf */
-static unsigned outcnt;  /* bytes in output buffer */
-static int exit_code;
-static int unzip_error;
-static long bytes_out;
-static int crd_infd, crd_outfd;
-
-#define get_byte()  (inptr < insize ? inbuf[inptr++] : fill_inbuf())
-		
-/* Diagnostic functions (stubbed out) */
-#define Assert(cond,msg)
-#define Trace(x)
-#define Tracev(x)
-#define Tracevv(x)
-#define Tracec(c,x)
-#define Tracecv(c,x)
-
-#define STATIC static
-#define INIT __init
-
-static int  __init fill_inbuf(void);
-static void __init flush_window(void);
-static void __init *malloc(size_t size);
-static void __init free(void *where);
-static void __init error(char *m);
-static void __init gzip_mark(void **);
-static void __init gzip_release(void **);
-
-#include "../lib/inflate.c"
-
-static void __init *malloc(size_t size)
-{
-	return kmalloc(size, GFP_KERNEL);
-}
-
-static void __init free(void *where)
-{
-	kfree(where);
-}
-
-static void __init gzip_mark(void **ptr)
-{
-}
-
-static void __init gzip_release(void **ptr)
-{
-}
-
-
-/* ===========================================================================
- * Fill the input buffer. This is called only when the buffer is empty
- * and at least one byte is really needed.
- * Returning -1 does not guarantee that gunzip() will ever return.
- */
-static int __init fill_inbuf(void)
-{
-	if (exit_code) return -1;
-	
-	insize = sys_read(crd_infd, inbuf, INBUFSIZ);
-	if (insize == 0) {
-		error("RAMDISK: ran out of compressed data");
-		return -1;
-	}
-
-	inptr = 1;
-
-	return inbuf[0];
-}
-
-/* ===========================================================================
- * Write the output window window[0..outcnt-1] and update crc and bytes_out.
- * (Used for the decompressed data only.)
- */
-static void __init flush_window(void)
-{
-    ulg c = crc;         /* temporary variable */
-    unsigned n, written;
-    uch *in, ch;
-    
-    written = sys_write(crd_outfd, window, outcnt);
-    if (written != outcnt && unzip_error == 0) {
-	printk(KERN_ERR "RAMDISK: incomplete write (%d != %d) %ld\n",
-	       written, outcnt, bytes_out);
-	unzip_error = 1;
-    }
-    in = window;
-    for (n = 0; n < outcnt; n++) {
-	    ch = *in++;
-	    c = crc_32_tab[((int)c ^ ch) & 0xff] ^ (c >> 8);
-    }
-    crc = c;
-    bytes_out += (ulg)outcnt;
-    outcnt = 0;
-}
-
-static void __init error(char *x)
-{
-	printk(KERN_ERR "%s\n", x);
-	exit_code = 1;
-	unzip_error = 1;
-}
-
-static int __init crd_load(int in_fd, int out_fd)
-{
-	int result;
-
-	insize = 0;		/* valid bytes in inbuf */
-	inptr = 0;		/* index of next byte to be processed in inbuf */
-	outcnt = 0;		/* bytes in output buffer */
-	exit_code = 0;
-	bytes_out = 0;
-	crc = (ulg)0xffffffffL; /* shift register contents */
-
-	crd_infd = in_fd;
-	crd_outfd = out_fd;
-	inbuf = kmalloc(INBUFSIZ, GFP_KERNEL);
-	if (inbuf == 0) {
-		printk(KERN_ERR "RAMDISK: Couldn't allocate gzip buffer\n");
-		return -1;
-	}
-	window = kmalloc(WSIZE, GFP_KERNEL);
-	if (window == 0) {
-		printk(KERN_ERR "RAMDISK: Couldn't allocate gzip window\n");
-		kfree(inbuf);
-		return -1;
-	}
-	makecrc();
-	result = gunzip();
-	if (unzip_error)
-		result = 1;
-	kfree(inbuf);
-	kfree(window);
-	return result;
-}
-
-#endif  /* BUILD_CRAMDISK */
diff --git a/init/initramfs.c b/init/initramfs.c
index 00eff7a..1de5cad 100644
--- a/init/initramfs.c
+++ b/init/initramfs.c
@@ -7,6 +7,9 @@
 #include <linux/string.h>
 #include <linux/syscalls.h>
 
+unsigned long __initdata initrd_start, initrd_end;
+int __initdata initrd_below_start_ok;
+
 static __initdata char *message;
 static void __init error(char *x)
 {
diff --git a/init/main.c b/init/main.c
index 1940fa7..6a3151b 100644
--- a/init/main.c
+++ b/init/main.c
@@ -7,6 +7,8 @@
  *  Added initrd & change_root: Werner Almesberger & Hans Lermen, Feb '96
  *  Moan early if gcc is old, avoiding bogus kernels - Paul Gortmaker, May '96
  *  Simplified starting of init:  Michael A. Griffith <grif@acm.org> 
+ *
+ *  2006-02-12 H. Peter Anvin: Eliminated in-kernel root mounting.
  */
 
 #include <linux/types.h>
@@ -48,6 +50,7 @@
 #include <linux/rmap.h>
 #include <linux/mempolicy.h>
 #include <linux/key.h>
+#include <linux/root_dev.h>
 #include <linux/unwind.h>
 #include <linux/buffer_head.h>
 #include <linux/debug_locks.h>
@@ -135,6 +138,11 @@
 /* Setup configured maximum number of CPUs to activate */
 static unsigned int max_cpus = NR_CPUS;
 
+/* ROOT_DEV contains any architecture-specific default root device. */
+/* real_root_dev is used (via sysctl) to communicate ROOT_DEV to kinit. */
+dev_t ROOT_DEV;
+unsigned int real_root_dev;
+
 /*
  * If set, this is an indication to the drivers that reset the underlying
  * device before going ahead with the initialization otherwise driver might
@@ -753,35 +761,15 @@
 	system_state = SYSTEM_RUNNING;
 	numa_default_policy();
 
+	/* This could be done by (k)init as well... */
 	if (sys_open((const char __user *) "/dev/console", O_RDWR, 0) < 0)
 		printk(KERN_WARNING "Warning: unable to open an initial console.\n");
 
 	(void) sys_dup(0);
 	(void) sys_dup(0);
 
-	if (ramdisk_execute_command) {
-		run_init_process(ramdisk_execute_command);
-		printk(KERN_WARNING "Failed to execute %s\n",
-				ramdisk_execute_command);
-	}
-
-	/*
-	 * We try each of these until one succeeds.
-	 *
-	 * The Bourne shell can be used instead of init if we are
-	 * trying to recover a really broken machine.
-	 */
-	if (execute_command) {
-		run_init_process(execute_command);
-		printk(KERN_WARNING "Failed to execute %s.  Attempting "
-					"defaults...\n", execute_command);
-	}
-	run_init_process("/sbin/init");
-	run_init_process("/etc/init");
-	run_init_process("/bin/init");
-	run_init_process("/bin/sh");
-
-	panic("No init found.  Try passing init= option to kernel.");
+	run_init_process(ramdisk_execute_command);
+	panic("Failed to execute %s", ramdisk_execute_command);
 }
 
 static int __init kernel_init(void * unused)
@@ -816,6 +804,12 @@
 	do_basic_setup();
 
 	/*
+	 * If we have a root device set by architecture-specific means,
+	 * let kinit know about it.
+	 */
+	real_root_dev = new_encode_dev(ROOT_DEV);
+
+	/*
 	 * check if there is an early userspace init.  If yes, let it do all
 	 * the work
 	 */
@@ -823,11 +817,6 @@
 	if (!ramdisk_execute_command)
 		ramdisk_execute_command = "/init";
 
-	if (sys_access((const char __user *) ramdisk_execute_command, 0) != 0) {
-		ramdisk_execute_command = NULL;
-		prepare_namespace();
-	}
-
 	/*
 	 * Ok, we have completed the initial bootup, and
 	 * we're essentially up and running. Get rid of the
diff --git a/init/noinitramfs.c b/init/noinitramfs.c
deleted file mode 100644
index f4c1a3a..0000000
--- a/init/noinitramfs.c
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * init/noinitramfs.c
- *
- * Copyright (C) 2006, NXP Semiconductors, All Rights Reserved
- * Author: Jean-Paul Saman <jean-paul.saman@nxp.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * This program 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 General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-#include <linux/init.h>
-#include <linux/stat.h>
-#include <linux/kdev_t.h>
-#include <linux/syscalls.h>
-
-/*
- * Create a simple rootfs that is similar to the default initramfs
- */
-static int __init default_rootfs(void)
-{
-	int err;
-
-	err = sys_mkdir("/dev", 0755);
-	if (err < 0)
-		goto out;
-
-	err = sys_mknod((const char __user *) "/dev/console",
-			S_IFCHR | S_IRUSR | S_IWUSR,
-			new_encode_dev(MKDEV(5, 1)));
-	if (err < 0)
-		goto out;
-
-	err = sys_mkdir("/root", 0700);
-	if (err < 0)
-		goto out;
-
-	return 0;
-
-out:
-	printk(KERN_WARNING "Failed to create a rootfs\n");
-	return err;
-}
-rootfs_initcall(default_rootfs);
diff --git a/kernel/power/disk.c b/kernel/power/disk.c
index b5f0543..6ba97df 100644
--- a/kernel/power/disk.c
+++ b/kernel/power/disk.c
@@ -25,8 +25,6 @@
 #include "power.h"
 
 
-static int noresume = 0;
-char resume_file[256] = CONFIG_PM_STD_PARTITION;
 dev_t swsusp_resume_device;
 sector_t swsusp_resume_block;
 
@@ -256,26 +254,13 @@
 
 	mutex_lock(&pm_mutex);
 	if (!swsusp_resume_device) {
-		if (!strlen(resume_file)) {
-			mutex_unlock(&pm_mutex);
-			return -ENOENT;
-		}
-		swsusp_resume_device = name_to_dev_t(resume_file);
-		pr_debug("swsusp: Resume From Partition %s\n", resume_file);
-	} else {
-		pr_debug("swsusp: Resume From Partition %d:%d\n",
-			 MAJOR(swsusp_resume_device), MINOR(swsusp_resume_device));
-	}
-
-	if (noresume) {
-		/**
-		 * FIXME: If noresume is specified, we need to find the partition
-		 * and reset it back to normal swap space.
-		 */
-		mutex_unlock(&pm_mutex);
+		pr_debug("swsusp: No device given!\n");
 		return 0;
 	}
 
+	pr_debug("swsusp: Resume From Partition %d:%d\n",
+		 MAJOR(swsusp_resume_device), MINOR(swsusp_resume_device));
+
 	pr_debug("PM: Checking swsusp image.\n");
 	error = swsusp_check();
 	if (error)
@@ -336,8 +321,6 @@
 	return 0;
 }
 
-late_initcall(software_resume);
-
 
 static const char * const hibernation_modes[] = {
 	[HIBERNATION_PLATFORM]	= "platform",
@@ -458,8 +441,9 @@
 	unsigned int maj, min;
 	dev_t res;
 	int ret = -EINVAL;
+	unsigned long long offset = 0;
 
-	if (sscanf(buf, "%u:%u", &maj, &min) != 2)
+	if (sscanf(buf, "%u:%u:%llu", &maj, &min, &offset) < 2)
 		goto out;
 
 	res = MKDEV(maj,min);
@@ -468,9 +452,9 @@
 
 	mutex_lock(&pm_mutex);
 	swsusp_resume_device = res;
+	swsusp_resume_block = offset;
 	mutex_unlock(&pm_mutex);
 	printk("Attempting manual resume\n");
-	noresume = 0;
 	software_resume();
 	ret = n;
  out:
@@ -517,36 +501,3 @@
 }
 
 core_initcall(pm_disk_init);
-
-
-static int __init resume_setup(char *str)
-{
-	if (noresume)
-		return 1;
-
-	strncpy( resume_file, str, 255 );
-	return 1;
-}
-
-static int __init resume_offset_setup(char *str)
-{
-	unsigned long long offset;
-
-	if (noresume)
-		return 1;
-
-	if (sscanf(str, "%llu", &offset) == 1)
-		swsusp_resume_block = offset;
-
-	return 1;
-}
-
-static int __init noresume_setup(char *str)
-{
-	noresume = 1;
-	return 1;
-}
-
-__setup("noresume", noresume_setup);
-__setup("resume_offset=", resume_offset_setup);
-__setup("resume=", resume_setup);
diff --git a/net/ipv4/Makefile b/net/ipv4/Makefile
index 4ff6c15..f917e95 100644
--- a/net/ipv4/Makefile
+++ b/net/ipv4/Makefile
@@ -28,7 +28,6 @@
 obj-$(CONFIG_INET_TUNNEL) += tunnel4.o
 obj-$(CONFIG_INET_XFRM_MODE_TRANSPORT) += xfrm4_mode_transport.o
 obj-$(CONFIG_INET_XFRM_MODE_TUNNEL) += xfrm4_mode_tunnel.o
-obj-$(CONFIG_IP_PNP) += ipconfig.o
 obj-$(CONFIG_IP_ROUTE_MULTIPATH_RR) += multipath_rr.o
 obj-$(CONFIG_IP_ROUTE_MULTIPATH_RANDOM) += multipath_random.o
 obj-$(CONFIG_IP_ROUTE_MULTIPATH_WRANDOM) += multipath_wrandom.o
diff --git a/net/ipv4/ipconfig.c b/net/ipv4/ipconfig.c
deleted file mode 100644
index 342ca8d..0000000
--- a/net/ipv4/ipconfig.c
+++ /dev/null
@@ -1,1511 +0,0 @@
-/*
- *  $Id: ipconfig.c,v 1.46 2002/02/01 22:01:04 davem Exp $
- *
- *  Automatic Configuration of IP -- use DHCP, BOOTP, RARP, or
- *  user-supplied information to configure own IP address and routes.
- *
- *  Copyright (C) 1996-1998 Martin Mares <mj@atrey.karlin.mff.cuni.cz>
- *
- *  Derived from network configuration code in fs/nfs/nfsroot.c,
- *  originally Copyright (C) 1995, 1996 Gero Kuhlmann and me.
- *
- *  BOOTP rewritten to construct and analyse packets itself instead
- *  of misusing the IP layer. num_bugs_causing_wrong_arp_replies--;
- *					     -- MJ, December 1998
- *
- *  Fixed ip_auto_config_setup calling at startup in the new "Linker Magic"
- *  initialization scheme.
- *	- Arnaldo Carvalho de Melo <acme@conectiva.com.br>, 08/11/1999
- *
- *  DHCP support added.  To users this looks like a whole separate
- *  protocol, but we know it's just a bag on the side of BOOTP.
- *		-- Chip Salzenberg <chip@valinux.com>, May 2000
- *
- *  Ported DHCP support from 2.2.16 to 2.4.0-test4
- *              -- Eric Biederman <ebiederman@lnxi.com>, 30 Aug 2000
- *
- *  Merged changes from 2.2.19 into 2.4.3
- *              -- Eric Biederman <ebiederman@lnxi.com>, 22 April Aug 2001
- *
- *  Multiple Nameservers in /proc/net/pnp
- *              --  Josef Siemes <jsiemes@web.de>, Aug 2002
- */
-
-#include <linux/types.h>
-#include <linux/string.h>
-#include <linux/kernel.h>
-#include <linux/jiffies.h>
-#include <linux/random.h>
-#include <linux/init.h>
-#include <linux/utsname.h>
-#include <linux/in.h>
-#include <linux/if.h>
-#include <linux/inet.h>
-#include <linux/inetdevice.h>
-#include <linux/netdevice.h>
-#include <linux/if_arp.h>
-#include <linux/skbuff.h>
-#include <linux/ip.h>
-#include <linux/socket.h>
-#include <linux/route.h>
-#include <linux/udp.h>
-#include <linux/proc_fs.h>
-#include <linux/seq_file.h>
-#include <linux/major.h>
-#include <linux/root_dev.h>
-#include <linux/delay.h>
-#include <linux/nfs_fs.h>
-#include <net/arp.h>
-#include <net/ip.h>
-#include <net/ipconfig.h>
-#include <net/route.h>
-
-#include <asm/uaccess.h>
-#include <net/checksum.h>
-#include <asm/processor.h>
-
-/* Define this to allow debugging output */
-#undef IPCONFIG_DEBUG
-
-#ifdef IPCONFIG_DEBUG
-#define DBG(x) printk x
-#else
-#define DBG(x) do { } while(0)
-#endif
-
-#if defined(CONFIG_IP_PNP_DHCP)
-#define IPCONFIG_DHCP
-#endif
-#if defined(CONFIG_IP_PNP_BOOTP) || defined(CONFIG_IP_PNP_DHCP)
-#define IPCONFIG_BOOTP
-#endif
-#if defined(CONFIG_IP_PNP_RARP)
-#define IPCONFIG_RARP
-#endif
-#if defined(IPCONFIG_BOOTP) || defined(IPCONFIG_RARP)
-#define IPCONFIG_DYNAMIC
-#endif
-
-/* Define the friendly delay before and after opening net devices */
-#define CONF_PRE_OPEN		500	/* Before opening: 1/2 second */
-#define CONF_POST_OPEN		1	/* After opening: 1 second */
-
-/* Define the timeout for waiting for a DHCP/BOOTP/RARP reply */
-#define CONF_OPEN_RETRIES 	2	/* (Re)open devices twice */
-#define CONF_SEND_RETRIES 	6	/* Send six requests per open */
-#define CONF_INTER_TIMEOUT	(HZ/2)	/* Inter-device timeout: 1/2 second */
-#define CONF_BASE_TIMEOUT	(HZ*2)	/* Initial timeout: 2 seconds */
-#define CONF_TIMEOUT_RANDOM	(HZ)	/* Maximum amount of randomization */
-#define CONF_TIMEOUT_MULT	*7/4	/* Rate of timeout growth */
-#define CONF_TIMEOUT_MAX	(HZ*30)	/* Maximum allowed timeout */
-#define CONF_NAMESERVERS_MAX   3       /* Maximum number of nameservers
-					   - '3' from resolv.h */
-
-#define NONE __constant_htonl(INADDR_NONE)
-
-/*
- * Public IP configuration
- */
-
-/* This is used by platforms which might be able to set the ipconfig
- * variables using firmware environment vars.  If this is set, it will
- * ignore such firmware variables.
- */
-int ic_set_manually __initdata = 0;		/* IPconfig parameters set manually */
-
-static int ic_enable __initdata = 0;		/* IP config enabled? */
-
-/* Protocol choice */
-int ic_proto_enabled __initdata = 0
-#ifdef IPCONFIG_BOOTP
-			| IC_BOOTP
-#endif
-#ifdef CONFIG_IP_PNP_DHCP
-			| IC_USE_DHCP
-#endif
-#ifdef IPCONFIG_RARP
-			| IC_RARP
-#endif
-			;
-
-static int ic_host_name_set __initdata = 0;	/* Host name set by us? */
-
-__be32 ic_myaddr = NONE;		/* My IP address */
-static __be32 ic_netmask = NONE;	/* Netmask for local subnet */
-__be32 ic_gateway = NONE;	/* Gateway IP address */
-
-__be32 ic_servaddr = NONE;	/* Boot server IP address */
-
-__be32 root_server_addr = NONE;	/* Address of NFS server */
-u8 root_server_path[256] = { 0, };	/* Path to mount as root */
-
-/* Persistent data: */
-
-static int ic_proto_used;			/* Protocol used, if any */
-static __be32 ic_nameservers[CONF_NAMESERVERS_MAX]; /* DNS Server IP addresses */
-static u8 ic_domain[64];		/* DNS (not NIS) domain name */
-
-/*
- * Private state.
- */
-
-/* Name of user-selected boot device */
-static char user_dev_name[IFNAMSIZ] __initdata = { 0, };
-
-/* Protocols supported by available interfaces */
-static int ic_proto_have_if __initdata = 0;
-
-#ifdef IPCONFIG_DYNAMIC
-static DEFINE_SPINLOCK(ic_recv_lock);
-static volatile int ic_got_reply __initdata = 0;    /* Proto(s) that replied */
-#endif
-#ifdef IPCONFIG_DHCP
-static int ic_dhcp_msgtype __initdata = 0;	/* DHCP msg type received */
-#endif
-
-
-/*
- *	Network devices
- */
-
-struct ic_device {
-	struct ic_device *next;
-	struct net_device *dev;
-	unsigned short flags;
-	short able;
-	__be32 xid;
-};
-
-static struct ic_device *ic_first_dev __initdata = NULL;/* List of open device */
-static struct net_device *ic_dev __initdata = NULL;	/* Selected device */
-
-static int __init ic_open_devs(void)
-{
-	struct ic_device *d, **last;
-	struct net_device *dev;
-	unsigned short oflags;
-
-	last = &ic_first_dev;
-	rtnl_lock();
-
-	/* bring loopback device up first */
-	if (dev_change_flags(&loopback_dev, loopback_dev.flags | IFF_UP) < 0)
-		printk(KERN_ERR "IP-Config: Failed to open %s\n", loopback_dev.name);
-
-	for_each_netdev(dev) {
-		if (dev == &loopback_dev)
-			continue;
-		if (user_dev_name[0] ? !strcmp(dev->name, user_dev_name) :
-		    (!(dev->flags & IFF_LOOPBACK) &&
-		     (dev->flags & (IFF_POINTOPOINT|IFF_BROADCAST)) &&
-		     strncmp(dev->name, "dummy", 5))) {
-			int able = 0;
-			if (dev->mtu >= 364)
-				able |= IC_BOOTP;
-			else
-				printk(KERN_WARNING "DHCP/BOOTP: Ignoring device %s, MTU %d too small", dev->name, dev->mtu);
-			if (!(dev->flags & IFF_NOARP))
-				able |= IC_RARP;
-			able &= ic_proto_enabled;
-			if (ic_proto_enabled && !able)
-				continue;
-			oflags = dev->flags;
-			if (dev_change_flags(dev, oflags | IFF_UP) < 0) {
-				printk(KERN_ERR "IP-Config: Failed to open %s\n", dev->name);
-				continue;
-			}
-			if (!(d = kmalloc(sizeof(struct ic_device), GFP_KERNEL))) {
-				rtnl_unlock();
-				return -1;
-			}
-			d->dev = dev;
-			*last = d;
-			last = &d->next;
-			d->flags = oflags;
-			d->able = able;
-			if (able & IC_BOOTP)
-				get_random_bytes(&d->xid, sizeof(__be32));
-			else
-				d->xid = 0;
-			ic_proto_have_if |= able;
-			DBG(("IP-Config: %s UP (able=%d, xid=%08x)\n",
-				dev->name, able, d->xid));
-		}
-	}
-	rtnl_unlock();
-
-	*last = NULL;
-
-	if (!ic_first_dev) {
-		if (user_dev_name[0])
-			printk(KERN_ERR "IP-Config: Device `%s' not found.\n", user_dev_name);
-		else
-			printk(KERN_ERR "IP-Config: No network devices available.\n");
-		return -1;
-	}
-	return 0;
-}
-
-static void __init ic_close_devs(void)
-{
-	struct ic_device *d, *next;
-	struct net_device *dev;
-
-	rtnl_lock();
-	next = ic_first_dev;
-	while ((d = next)) {
-		next = d->next;
-		dev = d->dev;
-		if (dev != ic_dev) {
-			DBG(("IP-Config: Downing %s\n", dev->name));
-			dev_change_flags(dev, d->flags);
-		}
-		kfree(d);
-	}
-	rtnl_unlock();
-}
-
-/*
- *	Interface to various network functions.
- */
-
-static inline void
-set_sockaddr(struct sockaddr_in *sin, __be32 addr, __be16 port)
-{
-	sin->sin_family = AF_INET;
-	sin->sin_addr.s_addr = addr;
-	sin->sin_port = port;
-}
-
-static int __init ic_dev_ioctl(unsigned int cmd, struct ifreq *arg)
-{
-	int res;
-
-	mm_segment_t oldfs = get_fs();
-	set_fs(get_ds());
-	res = devinet_ioctl(cmd, (struct ifreq __user *) arg);
-	set_fs(oldfs);
-	return res;
-}
-
-static int __init ic_route_ioctl(unsigned int cmd, struct rtentry *arg)
-{
-	int res;
-
-	mm_segment_t oldfs = get_fs();
-	set_fs(get_ds());
-	res = ip_rt_ioctl(cmd, (void __user *) arg);
-	set_fs(oldfs);
-	return res;
-}
-
-/*
- *	Set up interface addresses and routes.
- */
-
-static int __init ic_setup_if(void)
-{
-	struct ifreq ir;
-	struct sockaddr_in *sin = (void *) &ir.ifr_ifru.ifru_addr;
-	int err;
-
-	memset(&ir, 0, sizeof(ir));
-	strcpy(ir.ifr_ifrn.ifrn_name, ic_dev->name);
-	set_sockaddr(sin, ic_myaddr, 0);
-	if ((err = ic_dev_ioctl(SIOCSIFADDR, &ir)) < 0) {
-		printk(KERN_ERR "IP-Config: Unable to set interface address (%d).\n", err);
-		return -1;
-	}
-	set_sockaddr(sin, ic_netmask, 0);
-	if ((err = ic_dev_ioctl(SIOCSIFNETMASK, &ir)) < 0) {
-		printk(KERN_ERR "IP-Config: Unable to set interface netmask (%d).\n", err);
-		return -1;
-	}
-	set_sockaddr(sin, ic_myaddr | ~ic_netmask, 0);
-	if ((err = ic_dev_ioctl(SIOCSIFBRDADDR, &ir)) < 0) {
-		printk(KERN_ERR "IP-Config: Unable to set interface broadcast address (%d).\n", err);
-		return -1;
-	}
-	return 0;
-}
-
-static int __init ic_setup_routes(void)
-{
-	/* No need to setup device routes, only the default route... */
-
-	if (ic_gateway != NONE) {
-		struct rtentry rm;
-		int err;
-
-		memset(&rm, 0, sizeof(rm));
-		if ((ic_gateway ^ ic_myaddr) & ic_netmask) {
-			printk(KERN_ERR "IP-Config: Gateway not on directly connected network.\n");
-			return -1;
-		}
-		set_sockaddr((struct sockaddr_in *) &rm.rt_dst, 0, 0);
-		set_sockaddr((struct sockaddr_in *) &rm.rt_genmask, 0, 0);
-		set_sockaddr((struct sockaddr_in *) &rm.rt_gateway, ic_gateway, 0);
-		rm.rt_flags = RTF_UP | RTF_GATEWAY;
-		if ((err = ic_route_ioctl(SIOCADDRT, &rm)) < 0) {
-			printk(KERN_ERR "IP-Config: Cannot add default route (%d).\n", err);
-			return -1;
-		}
-	}
-
-	return 0;
-}
-
-/*
- *	Fill in default values for all missing parameters.
- */
-
-static int __init ic_defaults(void)
-{
-	/*
-	 *	At this point we have no userspace running so need not
-	 *	claim locks on system_utsname
-	 */
-
-	if (!ic_host_name_set)
-		sprintf(init_utsname()->nodename, "%u.%u.%u.%u", NIPQUAD(ic_myaddr));
-
-	if (root_server_addr == NONE)
-		root_server_addr = ic_servaddr;
-
-	if (ic_netmask == NONE) {
-		if (IN_CLASSA(ntohl(ic_myaddr)))
-			ic_netmask = htonl(IN_CLASSA_NET);
-		else if (IN_CLASSB(ntohl(ic_myaddr)))
-			ic_netmask = htonl(IN_CLASSB_NET);
-		else if (IN_CLASSC(ntohl(ic_myaddr)))
-			ic_netmask = htonl(IN_CLASSC_NET);
-		else {
-			printk(KERN_ERR "IP-Config: Unable to guess netmask for address %u.%u.%u.%u\n",
-				NIPQUAD(ic_myaddr));
-			return -1;
-		}
-		printk("IP-Config: Guessing netmask %u.%u.%u.%u\n", NIPQUAD(ic_netmask));
-	}
-
-	return 0;
-}
-
-/*
- *	RARP support.
- */
-
-#ifdef IPCONFIG_RARP
-
-static int ic_rarp_recv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt, struct net_device *orig_dev);
-
-static struct packet_type rarp_packet_type __initdata = {
-	.type =	__constant_htons(ETH_P_RARP),
-	.func =	ic_rarp_recv,
-};
-
-static inline void ic_rarp_init(void)
-{
-	dev_add_pack(&rarp_packet_type);
-}
-
-static inline void ic_rarp_cleanup(void)
-{
-	dev_remove_pack(&rarp_packet_type);
-}
-
-/*
- *  Process received RARP packet.
- */
-static int __init
-ic_rarp_recv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt, struct net_device *orig_dev)
-{
-	struct arphdr *rarp;
-	unsigned char *rarp_ptr;
-	__be32 sip, tip;
-	unsigned char *sha, *tha;		/* s for "source", t for "target" */
-	struct ic_device *d;
-
-	if ((skb = skb_share_check(skb, GFP_ATOMIC)) == NULL)
-		return NET_RX_DROP;
-
-	if (!pskb_may_pull(skb, sizeof(struct arphdr)))
-		goto drop;
-
-	/* Basic sanity checks can be done without the lock.  */
-	rarp = (struct arphdr *)skb_transport_header(skb);
-
-	/* If this test doesn't pass, it's not IP, or we should
-	 * ignore it anyway.
-	 */
-	if (rarp->ar_hln != dev->addr_len || dev->type != ntohs(rarp->ar_hrd))
-		goto drop;
-
-	/* If it's not a RARP reply, delete it. */
-	if (rarp->ar_op != htons(ARPOP_RREPLY))
-		goto drop;
-
-	/* If it's not Ethernet, delete it. */
-	if (rarp->ar_pro != htons(ETH_P_IP))
-		goto drop;
-
-	if (!pskb_may_pull(skb,
-			   sizeof(struct arphdr) +
-			   (2 * dev->addr_len) +
-			   (2 * 4)))
-		goto drop;
-
-	/* OK, it is all there and looks valid, process... */
-	rarp = (struct arphdr *)skb_transport_header(skb);
-	rarp_ptr = (unsigned char *) (rarp + 1);
-
-	/* One reply at a time, please. */
-	spin_lock(&ic_recv_lock);
-
-	/* If we already have a reply, just drop the packet */
-	if (ic_got_reply)
-		goto drop_unlock;
-
-	/* Find the ic_device that the packet arrived on */
-	d = ic_first_dev;
-	while (d && d->dev != dev)
-		d = d->next;
-	if (!d)
-		goto drop_unlock;	/* should never happen */
-
-	/* Extract variable-width fields */
-	sha = rarp_ptr;
-	rarp_ptr += dev->addr_len;
-	memcpy(&sip, rarp_ptr, 4);
-	rarp_ptr += 4;
-	tha = rarp_ptr;
-	rarp_ptr += dev->addr_len;
-	memcpy(&tip, rarp_ptr, 4);
-
-	/* Discard packets which are not meant for us. */
-	if (memcmp(tha, dev->dev_addr, dev->addr_len))
-		goto drop_unlock;
-
-	/* Discard packets which are not from specified server. */
-	if (ic_servaddr != NONE && ic_servaddr != sip)
-		goto drop_unlock;
-
-	/* We have a winner! */
-	ic_dev = dev;
-	if (ic_myaddr == NONE)
-		ic_myaddr = tip;
-	ic_servaddr = sip;
-	ic_got_reply = IC_RARP;
-
-drop_unlock:
-	/* Show's over.  Nothing to see here.  */
-	spin_unlock(&ic_recv_lock);
-
-drop:
-	/* Throw the packet out. */
-	kfree_skb(skb);
-	return 0;
-}
-
-
-/*
- *  Send RARP request packet over a single interface.
- */
-static void __init ic_rarp_send_if(struct ic_device *d)
-{
-	struct net_device *dev = d->dev;
-	arp_send(ARPOP_RREQUEST, ETH_P_RARP, 0, dev, 0, NULL,
-		 dev->dev_addr, dev->dev_addr);
-}
-#endif
-
-/*
- *	DHCP/BOOTP support.
- */
-
-#ifdef IPCONFIG_BOOTP
-
-struct bootp_pkt {		/* BOOTP packet format */
-	struct iphdr iph;	/* IP header */
-	struct udphdr udph;	/* UDP header */
-	u8 op;			/* 1=request, 2=reply */
-	u8 htype;		/* HW address type */
-	u8 hlen;		/* HW address length */
-	u8 hops;		/* Used only by gateways */
-	__be32 xid;		/* Transaction ID */
-	__be16 secs;		/* Seconds since we started */
-	__be16 flags;		/* Just what it says */
-	__be32 client_ip;		/* Client's IP address if known */
-	__be32 your_ip;		/* Assigned IP address */
-	__be32 server_ip;		/* (Next, e.g. NFS) Server's IP address */
-	__be32 relay_ip;		/* IP address of BOOTP relay */
-	u8 hw_addr[16];		/* Client's HW address */
-	u8 serv_name[64];	/* Server host name */
-	u8 boot_file[128];	/* Name of boot file */
-	u8 exten[312];		/* DHCP options / BOOTP vendor extensions */
-};
-
-/* packet ops */
-#define BOOTP_REQUEST	1
-#define BOOTP_REPLY	2
-
-/* DHCP message types */
-#define DHCPDISCOVER	1
-#define DHCPOFFER	2
-#define DHCPREQUEST	3
-#define DHCPDECLINE	4
-#define DHCPACK		5
-#define DHCPNAK		6
-#define DHCPRELEASE	7
-#define DHCPINFORM	8
-
-static int ic_bootp_recv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt, struct net_device *orig_dev);
-
-static struct packet_type bootp_packet_type __initdata = {
-	.type =	__constant_htons(ETH_P_IP),
-	.func =	ic_bootp_recv,
-};
-
-
-/*
- *  Initialize DHCP/BOOTP extension fields in the request.
- */
-
-static const u8 ic_bootp_cookie[4] = { 99, 130, 83, 99 };
-
-#ifdef IPCONFIG_DHCP
-
-static void __init
-ic_dhcp_init_options(u8 *options)
-{
-	u8 mt = ((ic_servaddr == NONE)
-		 ? DHCPDISCOVER : DHCPREQUEST);
-	u8 *e = options;
-
-#ifdef IPCONFIG_DEBUG
-	printk("DHCP: Sending message type %d\n", mt);
-#endif
-
-	memcpy(e, ic_bootp_cookie, 4);	/* RFC1048 Magic Cookie */
-	e += 4;
-
-	*e++ = 53;		/* DHCP message type */
-	*e++ = 1;
-	*e++ = mt;
-
-	if (mt == DHCPREQUEST) {
-		*e++ = 54;	/* Server ID (IP address) */
-		*e++ = 4;
-		memcpy(e, &ic_servaddr, 4);
-		e += 4;
-
-		*e++ = 50;	/* Requested IP address */
-		*e++ = 4;
-		memcpy(e, &ic_myaddr, 4);
-		e += 4;
-	}
-
-	/* always? */
-	{
-		static const u8 ic_req_params[] = {
-			1,	/* Subnet mask */
-			3,	/* Default gateway */
-			6,	/* DNS server */
-			12,	/* Host name */
-			15,	/* Domain name */
-			17,	/* Boot path */
-			40,	/* NIS domain name */
-		};
-
-		*e++ = 55;	/* Parameter request list */
-		*e++ = sizeof(ic_req_params);
-		memcpy(e, ic_req_params, sizeof(ic_req_params));
-		e += sizeof(ic_req_params);
-	}
-
-	*e++ = 255;	/* End of the list */
-}
-
-#endif /* IPCONFIG_DHCP */
-
-static void __init ic_bootp_init_ext(u8 *e)
-{
-	memcpy(e, ic_bootp_cookie, 4);	/* RFC1048 Magic Cookie */
-	e += 4;
-	*e++ = 1;		/* Subnet mask request */
-	*e++ = 4;
-	e += 4;
-	*e++ = 3;		/* Default gateway request */
-	*e++ = 4;
-	e += 4;
-	*e++ = 5;		/* Name server request */
-	*e++ = 8;
-	e += 8;
-	*e++ = 12;		/* Host name request */
-	*e++ = 32;
-	e += 32;
-	*e++ = 40;		/* NIS Domain name request */
-	*e++ = 32;
-	e += 32;
-	*e++ = 17;		/* Boot path */
-	*e++ = 40;
-	e += 40;
-
-	*e++ = 57;		/* set extension buffer size for reply */
-	*e++ = 2;
-	*e++ = 1;		/* 128+236+8+20+14, see dhcpd sources */
-	*e++ = 150;
-
-	*e++ = 255;		/* End of the list */
-}
-
-
-/*
- *  Initialize the DHCP/BOOTP mechanism.
- */
-static inline void ic_bootp_init(void)
-{
-	int i;
-
-	for (i = 0; i < CONF_NAMESERVERS_MAX; i++)
-		ic_nameservers[i] = NONE;
-
-	dev_add_pack(&bootp_packet_type);
-}
-
-
-/*
- *  DHCP/BOOTP cleanup.
- */
-static inline void ic_bootp_cleanup(void)
-{
-	dev_remove_pack(&bootp_packet_type);
-}
-
-
-/*
- *  Send DHCP/BOOTP request to single interface.
- */
-static void __init ic_bootp_send_if(struct ic_device *d, unsigned long jiffies_diff)
-{
-	struct net_device *dev = d->dev;
-	struct sk_buff *skb;
-	struct bootp_pkt *b;
-	int hh_len = LL_RESERVED_SPACE(dev);
-	struct iphdr *h;
-
-	/* Allocate packet */
-	skb = alloc_skb(sizeof(struct bootp_pkt) + hh_len + 15, GFP_KERNEL);
-	if (!skb)
-		return;
-	skb_reserve(skb, hh_len);
-	b = (struct bootp_pkt *) skb_put(skb, sizeof(struct bootp_pkt));
-	memset(b, 0, sizeof(struct bootp_pkt));
-
-	/* Construct IP header */
-	skb_reset_network_header(skb);
-	h = ip_hdr(skb);
-	h->version = 4;
-	h->ihl = 5;
-	h->tot_len = htons(sizeof(struct bootp_pkt));
-	h->frag_off = htons(IP_DF);
-	h->ttl = 64;
-	h->protocol = IPPROTO_UDP;
-	h->daddr = htonl(INADDR_BROADCAST);
-	h->check = ip_fast_csum((unsigned char *) h, h->ihl);
-
-	/* Construct UDP header */
-	b->udph.source = htons(68);
-	b->udph.dest = htons(67);
-	b->udph.len = htons(sizeof(struct bootp_pkt) - sizeof(struct iphdr));
-	/* UDP checksum not calculated -- explicitly allowed in BOOTP RFC */
-
-	/* Construct DHCP/BOOTP header */
-	b->op = BOOTP_REQUEST;
-	if (dev->type < 256) /* check for false types */
-		b->htype = dev->type;
-	else if (dev->type == ARPHRD_IEEE802_TR) /* fix for token ring */
-		b->htype = ARPHRD_IEEE802;
-	else if (dev->type == ARPHRD_FDDI)
-		b->htype = ARPHRD_ETHER;
-	else {
-		printk("Unknown ARP type 0x%04x for device %s\n", dev->type, dev->name);
-		b->htype = dev->type; /* can cause undefined behavior */
-	}
-	b->hlen = dev->addr_len;
-	b->your_ip = NONE;
-	b->server_ip = NONE;
-	memcpy(b->hw_addr, dev->dev_addr, dev->addr_len);
-	b->secs = htons(jiffies_diff / HZ);
-	b->xid = d->xid;
-
-	/* add DHCP options or BOOTP extensions */
-#ifdef IPCONFIG_DHCP
-	if (ic_proto_enabled & IC_USE_DHCP)
-		ic_dhcp_init_options(b->exten);
-	else
-#endif
-		ic_bootp_init_ext(b->exten);
-
-	/* Chain packet down the line... */
-	skb->dev = dev;
-	skb->protocol = htons(ETH_P_IP);
-	if ((dev->hard_header &&
-	     dev->hard_header(skb, dev, ntohs(skb->protocol), dev->broadcast, dev->dev_addr, skb->len) < 0) ||
-	    dev_queue_xmit(skb) < 0)
-		printk("E");
-}
-
-
-/*
- *  Copy BOOTP-supplied string if not already set.
- */
-static int __init ic_bootp_string(char *dest, char *src, int len, int max)
-{
-	if (!len)
-		return 0;
-	if (len > max-1)
-		len = max-1;
-	memcpy(dest, src, len);
-	dest[len] = '\0';
-	return 1;
-}
-
-
-/*
- *  Process BOOTP extensions.
- */
-static void __init ic_do_bootp_ext(u8 *ext)
-{
-       u8 servers;
-       int i;
-
-#ifdef IPCONFIG_DEBUG
-	u8 *c;
-
-	printk("DHCP/BOOTP: Got extension %d:",*ext);
-	for (c=ext+2; c<ext+2+ext[1]; c++)
-		printk(" %02x", *c);
-	printk("\n");
-#endif
-
-	switch (*ext++) {
-		case 1:		/* Subnet mask */
-			if (ic_netmask == NONE)
-				memcpy(&ic_netmask, ext+1, 4);
-			break;
-		case 3:		/* Default gateway */
-			if (ic_gateway == NONE)
-				memcpy(&ic_gateway, ext+1, 4);
-			break;
-		case 6:		/* DNS server */
-			servers= *ext/4;
-			if (servers > CONF_NAMESERVERS_MAX)
-				servers = CONF_NAMESERVERS_MAX;
-			for (i = 0; i < servers; i++) {
-				if (ic_nameservers[i] == NONE)
-					memcpy(&ic_nameservers[i], ext+1+4*i, 4);
-			}
-			break;
-		case 12:	/* Host name */
-			ic_bootp_string(utsname()->nodename, ext+1, *ext, __NEW_UTS_LEN);
-			ic_host_name_set = 1;
-			break;
-		case 15:	/* Domain name (DNS) */
-			ic_bootp_string(ic_domain, ext+1, *ext, sizeof(ic_domain));
-			break;
-		case 17:	/* Root path */
-			if (!root_server_path[0])
-				ic_bootp_string(root_server_path, ext+1, *ext, sizeof(root_server_path));
-			break;
-		case 40:	/* NIS Domain name (_not_ DNS) */
-			ic_bootp_string(utsname()->domainname, ext+1, *ext, __NEW_UTS_LEN);
-			break;
-	}
-}
-
-
-/*
- *  Receive BOOTP reply.
- */
-static int __init ic_bootp_recv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt, struct net_device *orig_dev)
-{
-	struct bootp_pkt *b;
-	struct iphdr *h;
-	struct ic_device *d;
-	int len, ext_len;
-
-	/* Perform verifications before taking the lock.  */
-	if (skb->pkt_type == PACKET_OTHERHOST)
-		goto drop;
-
-	if ((skb = skb_share_check(skb, GFP_ATOMIC)) == NULL)
-		return NET_RX_DROP;
-
-	if (!pskb_may_pull(skb,
-			   sizeof(struct iphdr) +
-			   sizeof(struct udphdr)))
-		goto drop;
-
-	b = (struct bootp_pkt *)skb_network_header(skb);
-	h = &b->iph;
-
-	if (h->ihl != 5 || h->version != 4 || h->protocol != IPPROTO_UDP)
-		goto drop;
-
-	/* Fragments are not supported */
-	if (h->frag_off & htons(IP_OFFSET | IP_MF)) {
-		if (net_ratelimit())
-			printk(KERN_ERR "DHCP/BOOTP: Ignoring fragmented "
-			       "reply.\n");
-		goto drop;
-	}
-
-	if (skb->len < ntohs(h->tot_len))
-		goto drop;
-
-	if (ip_fast_csum((char *) h, h->ihl))
-		goto drop;
-
-	if (b->udph.source != htons(67) || b->udph.dest != htons(68))
-		goto drop;
-
-	if (ntohs(h->tot_len) < ntohs(b->udph.len) + sizeof(struct iphdr))
-		goto drop;
-
-	len = ntohs(b->udph.len) - sizeof(struct udphdr);
-	ext_len = len - (sizeof(*b) -
-			 sizeof(struct iphdr) -
-			 sizeof(struct udphdr) -
-			 sizeof(b->exten));
-	if (ext_len < 0)
-		goto drop;
-
-	/* Ok the front looks good, make sure we can get at the rest.  */
-	if (!pskb_may_pull(skb, skb->len))
-		goto drop;
-
-	b = (struct bootp_pkt *)skb_network_header(skb);
-	h = &b->iph;
-
-	/* One reply at a time, please. */
-	spin_lock(&ic_recv_lock);
-
-	/* If we already have a reply, just drop the packet */
-	if (ic_got_reply)
-		goto drop_unlock;
-
-	/* Find the ic_device that the packet arrived on */
-	d = ic_first_dev;
-	while (d && d->dev != dev)
-		d = d->next;
-	if (!d)
-		goto drop_unlock;  /* should never happen */
-
-	/* Is it a reply to our BOOTP request? */
-	if (b->op != BOOTP_REPLY ||
-	    b->xid != d->xid) {
-		if (net_ratelimit())
-			printk(KERN_ERR "DHCP/BOOTP: Reply not for us, "
-			       "op[%x] xid[%x]\n",
-			       b->op, b->xid);
-		goto drop_unlock;
-	}
-
-	/* Parse extensions */
-	if (ext_len >= 4 &&
-	    !memcmp(b->exten, ic_bootp_cookie, 4)) { /* Check magic cookie */
-		u8 *end = (u8 *) b + ntohs(b->iph.tot_len);
-		u8 *ext;
-
-#ifdef IPCONFIG_DHCP
-		if (ic_proto_enabled & IC_USE_DHCP) {
-			__be32 server_id = NONE;
-			int mt = 0;
-
-			ext = &b->exten[4];
-			while (ext < end && *ext != 0xff) {
-				u8 *opt = ext++;
-				if (*opt == 0)	/* Padding */
-					continue;
-				ext += *ext + 1;
-				if (ext >= end)
-					break;
-				switch (*opt) {
-				case 53:	/* Message type */
-					if (opt[1])
-						mt = opt[2];
-					break;
-				case 54:	/* Server ID (IP address) */
-					if (opt[1] >= 4)
-						memcpy(&server_id, opt + 2, 4);
-					break;
-				}
-			}
-
-#ifdef IPCONFIG_DEBUG
-			printk("DHCP: Got message type %d\n", mt);
-#endif
-
-			switch (mt) {
-			case DHCPOFFER:
-				/* While in the process of accepting one offer,
-				 * ignore all others.
-				 */
-				if (ic_myaddr != NONE)
-					goto drop_unlock;
-
-				/* Let's accept that offer. */
-				ic_myaddr = b->your_ip;
-				ic_servaddr = server_id;
-#ifdef IPCONFIG_DEBUG
-				printk("DHCP: Offered address %u.%u.%u.%u",
-				       NIPQUAD(ic_myaddr));
-				printk(" by server %u.%u.%u.%u\n",
-				       NIPQUAD(ic_servaddr));
-#endif
-				/* The DHCP indicated server address takes
-				 * precedence over the bootp header one if
-				 * they are different.
-				 */
-				if ((server_id != NONE) &&
-				    (b->server_ip != server_id))
-					b->server_ip = ic_servaddr;
-				break;
-
-			case DHCPACK:
-				if (memcmp(dev->dev_addr, b->hw_addr, dev->addr_len) != 0)
-					goto drop_unlock;
-
-				/* Yeah! */
-				break;
-
-			default:
-				/* Urque.  Forget it*/
-				ic_myaddr = NONE;
-				ic_servaddr = NONE;
-				goto drop_unlock;
-			}
-
-			ic_dhcp_msgtype = mt;
-
-		}
-#endif /* IPCONFIG_DHCP */
-
-		ext = &b->exten[4];
-		while (ext < end && *ext != 0xff) {
-			u8 *opt = ext++;
-			if (*opt == 0)	/* Padding */
-				continue;
-			ext += *ext + 1;
-			if (ext < end)
-				ic_do_bootp_ext(opt);
-		}
-	}
-
-	/* We have a winner! */
-	ic_dev = dev;
-	ic_myaddr = b->your_ip;
-	ic_servaddr = b->server_ip;
-	if (ic_gateway == NONE && b->relay_ip)
-		ic_gateway = b->relay_ip;
-	if (ic_nameservers[0] == NONE)
-		ic_nameservers[0] = ic_servaddr;
-	ic_got_reply = IC_BOOTP;
-
-drop_unlock:
-	/* Show's over.  Nothing to see here.  */
-	spin_unlock(&ic_recv_lock);
-
-drop:
-	/* Throw the packet out. */
-	kfree_skb(skb);
-
-	return 0;
-}
-
-
-#endif
-
-
-/*
- *	Dynamic IP configuration -- DHCP, BOOTP, RARP.
- */
-
-#ifdef IPCONFIG_DYNAMIC
-
-static int __init ic_dynamic(void)
-{
-	int retries;
-	struct ic_device *d;
-	unsigned long start_jiffies, timeout, jiff;
-	int do_bootp = ic_proto_have_if & IC_BOOTP;
-	int do_rarp = ic_proto_have_if & IC_RARP;
-
-	/*
-	 * If none of DHCP/BOOTP/RARP was selected, return with an error.
-	 * This routine gets only called when some pieces of information
-	 * are missing, and without DHCP/BOOTP/RARP we are unable to get it.
-	 */
-	if (!ic_proto_enabled) {
-		printk(KERN_ERR "IP-Config: Incomplete network configuration information.\n");
-		return -1;
-	}
-
-#ifdef IPCONFIG_BOOTP
-	if ((ic_proto_enabled ^ ic_proto_have_if) & IC_BOOTP)
-		printk(KERN_ERR "DHCP/BOOTP: No suitable device found.\n");
-#endif
-#ifdef IPCONFIG_RARP
-	if ((ic_proto_enabled ^ ic_proto_have_if) & IC_RARP)
-		printk(KERN_ERR "RARP: No suitable device found.\n");
-#endif
-
-	if (!ic_proto_have_if)
-		/* Error message already printed */
-		return -1;
-
-	/*
-	 * Setup protocols
-	 */
-#ifdef IPCONFIG_BOOTP
-	if (do_bootp)
-		ic_bootp_init();
-#endif
-#ifdef IPCONFIG_RARP
-	if (do_rarp)
-		ic_rarp_init();
-#endif
-
-	/*
-	 * Send requests and wait, until we get an answer. This loop
-	 * seems to be a terrible waste of CPU time, but actually there is
-	 * only one process running at all, so we don't need to use any
-	 * scheduler functions.
-	 * [Actually we could now, but the nothing else running note still
-	 *  applies.. - AC]
-	 */
-	printk(KERN_NOTICE "Sending %s%s%s requests .",
-	       do_bootp
-		? ((ic_proto_enabled & IC_USE_DHCP) ? "DHCP" : "BOOTP") : "",
-	       (do_bootp && do_rarp) ? " and " : "",
-	       do_rarp ? "RARP" : "");
-
-	start_jiffies = jiffies;
-	d = ic_first_dev;
-	retries = CONF_SEND_RETRIES;
-	get_random_bytes(&timeout, sizeof(timeout));
-	timeout = CONF_BASE_TIMEOUT + (timeout % (unsigned) CONF_TIMEOUT_RANDOM);
-	for (;;) {
-#ifdef IPCONFIG_BOOTP
-		if (do_bootp && (d->able & IC_BOOTP))
-			ic_bootp_send_if(d, jiffies - start_jiffies);
-#endif
-#ifdef IPCONFIG_RARP
-		if (do_rarp && (d->able & IC_RARP))
-			ic_rarp_send_if(d);
-#endif
-
-		jiff = jiffies + (d->next ? CONF_INTER_TIMEOUT : timeout);
-		while (time_before(jiffies, jiff) && !ic_got_reply)
-			schedule_timeout_uninterruptible(1);
-#ifdef IPCONFIG_DHCP
-		/* DHCP isn't done until we get a DHCPACK. */
-		if ((ic_got_reply & IC_BOOTP)
-		    && (ic_proto_enabled & IC_USE_DHCP)
-		    && ic_dhcp_msgtype != DHCPACK)
-		{
-			ic_got_reply = 0;
-			printk(",");
-			continue;
-		}
-#endif /* IPCONFIG_DHCP */
-
-		if (ic_got_reply) {
-			printk(" OK\n");
-			break;
-		}
-
-		if ((d = d->next))
-			continue;
-
-		if (! --retries) {
-			printk(" timed out!\n");
-			break;
-		}
-
-		d = ic_first_dev;
-
-		timeout = timeout CONF_TIMEOUT_MULT;
-		if (timeout > CONF_TIMEOUT_MAX)
-			timeout = CONF_TIMEOUT_MAX;
-
-		printk(".");
-	}
-
-#ifdef IPCONFIG_BOOTP
-	if (do_bootp)
-		ic_bootp_cleanup();
-#endif
-#ifdef IPCONFIG_RARP
-	if (do_rarp)
-		ic_rarp_cleanup();
-#endif
-
-	if (!ic_got_reply) {
-		ic_myaddr = NONE;
-		return -1;
-	}
-
-	printk("IP-Config: Got %s answer from %u.%u.%u.%u, ",
-		((ic_got_reply & IC_RARP) ? "RARP"
-		 : (ic_proto_enabled & IC_USE_DHCP) ? "DHCP" : "BOOTP"),
-		NIPQUAD(ic_servaddr));
-	printk("my address is %u.%u.%u.%u\n", NIPQUAD(ic_myaddr));
-
-	return 0;
-}
-
-#endif /* IPCONFIG_DYNAMIC */
-
-#ifdef CONFIG_PROC_FS
-
-static int pnp_seq_show(struct seq_file *seq, void *v)
-{
-	int i;
-
-	if (ic_proto_used & IC_PROTO)
-		seq_printf(seq, "#PROTO: %s\n",
-			   (ic_proto_used & IC_RARP) ? "RARP"
-			   : (ic_proto_used & IC_USE_DHCP) ? "DHCP" : "BOOTP");
-	else
-		seq_puts(seq, "#MANUAL\n");
-
-	if (ic_domain[0])
-		seq_printf(seq,
-			   "domain %s\n", ic_domain);
-	for (i = 0; i < CONF_NAMESERVERS_MAX; i++) {
-		if (ic_nameservers[i] != NONE)
-			seq_printf(seq,
-				   "nameserver %u.%u.%u.%u\n",
-				   NIPQUAD(ic_nameservers[i]));
-	}
-	if (ic_servaddr != NONE)
-		seq_printf(seq,
-			   "bootserver %u.%u.%u.%u\n",
-			   NIPQUAD(ic_servaddr));
-	return 0;
-}
-
-static int pnp_seq_open(struct inode *indoe, struct file *file)
-{
-	return single_open(file, pnp_seq_show, NULL);
-}
-
-static const struct file_operations pnp_seq_fops = {
-	.owner		= THIS_MODULE,
-	.open		= pnp_seq_open,
-	.read		= seq_read,
-	.llseek		= seq_lseek,
-	.release	= single_release,
-};
-#endif /* CONFIG_PROC_FS */
-
-/*
- *  Extract IP address from the parameter string if needed. Note that we
- *  need to have root_server_addr set _before_ IPConfig gets called as it
- *  can override it.
- */
-__be32 __init root_nfs_parse_addr(char *name)
-{
-	__be32 addr;
-	int octets = 0;
-	char *cp, *cq;
-
-	cp = cq = name;
-	while (octets < 4) {
-		while (*cp >= '0' && *cp <= '9')
-			cp++;
-		if (cp == cq || cp - cq > 3)
-			break;
-		if (*cp == '.' || octets == 3)
-			octets++;
-		if (octets < 4)
-			cp++;
-		cq = cp;
-	}
-	if (octets == 4 && (*cp == ':' || *cp == '\0')) {
-		if (*cp == ':')
-			*cp++ = '\0';
-		addr = in_aton(name);
-		memmove(name, cp, strlen(cp) + 1);
-	} else
-		addr = NONE;
-
-	return addr;
-}
-
-/*
- *	IP Autoconfig dispatcher.
- */
-
-static int __init ip_auto_config(void)
-{
-	__be32 addr;
-
-#ifdef CONFIG_PROC_FS
-	proc_net_fops_create("pnp", S_IRUGO, &pnp_seq_fops);
-#endif /* CONFIG_PROC_FS */
-
-	if (!ic_enable)
-		return 0;
-
-	DBG(("IP-Config: Entered.\n"));
-#ifdef IPCONFIG_DYNAMIC
- try_try_again:
-#endif
-	/* Give hardware a chance to settle */
-	msleep(CONF_PRE_OPEN);
-
-	/* Setup all network devices */
-	if (ic_open_devs() < 0)
-		return -1;
-
-	/* Give drivers a chance to settle */
-	ssleep(CONF_POST_OPEN);
-
-	/*
-	 * If the config information is insufficient (e.g., our IP address or
-	 * IP address of the boot server is missing or we have multiple network
-	 * interfaces and no default was set), use BOOTP or RARP to get the
-	 * missing values.
-	 */
-	if (ic_myaddr == NONE ||
-#ifdef CONFIG_ROOT_NFS
-	    (MAJOR(ROOT_DEV) == UNNAMED_MAJOR
-	     && root_server_addr == NONE
-	     && ic_servaddr == NONE) ||
-#endif
-	    ic_first_dev->next) {
-#ifdef IPCONFIG_DYNAMIC
-
-		int retries = CONF_OPEN_RETRIES;
-
-		if (ic_dynamic() < 0) {
-			ic_close_devs();
-
-			/*
-			 * I don't know why, but sometimes the
-			 * eepro100 driver (at least) gets upset and
-			 * doesn't work the first time it's opened.
-			 * But then if you close it and reopen it, it
-			 * works just fine.  So we need to try that at
-			 * least once before giving up.
-			 *
-			 * Also, if the root will be NFS-mounted, we
-			 * have nowhere to go if DHCP fails.  So we
-			 * just have to keep trying forever.
-			 *
-			 * 				-- Chip
-			 */
-#ifdef CONFIG_ROOT_NFS
-			if (ROOT_DEV ==  Root_NFS) {
-				printk(KERN_ERR
-					"IP-Config: Retrying forever (NFS root)...\n");
-				goto try_try_again;
-			}
-#endif
-
-			if (--retries) {
-				printk(KERN_ERR
-				       "IP-Config: Reopening network devices...\n");
-				goto try_try_again;
-			}
-
-			/* Oh, well.  At least we tried. */
-			printk(KERN_ERR "IP-Config: Auto-configuration of network failed.\n");
-			return -1;
-		}
-#else /* !DYNAMIC */
-		printk(KERN_ERR "IP-Config: Incomplete network configuration information.\n");
-		ic_close_devs();
-		return -1;
-#endif /* IPCONFIG_DYNAMIC */
-	} else {
-		/* Device selected manually or only one device -> use it */
-		ic_dev = ic_first_dev->dev;
-	}
-
-	addr = root_nfs_parse_addr(root_server_path);
-	if (root_server_addr == NONE)
-		root_server_addr = addr;
-
-	/*
-	 * Use defaults whereever applicable.
-	 */
-	if (ic_defaults() < 0)
-		return -1;
-
-	/*
-	 * Close all network devices except the device we've
-	 * autoconfigured and set up routes.
-	 */
-	ic_close_devs();
-	if (ic_setup_if() < 0 || ic_setup_routes() < 0)
-		return -1;
-
-	/*
-	 * Record which protocol was actually used.
-	 */
-#ifdef IPCONFIG_DYNAMIC
-	ic_proto_used = ic_got_reply | (ic_proto_enabled & IC_USE_DHCP);
-#endif
-
-#ifndef IPCONFIG_SILENT
-	/*
-	 * Clue in the operator.
-	 */
-	printk("IP-Config: Complete:");
-	printk("\n      device=%s", ic_dev->name);
-	printk(", addr=%u.%u.%u.%u", NIPQUAD(ic_myaddr));
-	printk(", mask=%u.%u.%u.%u", NIPQUAD(ic_netmask));
-	printk(", gw=%u.%u.%u.%u", NIPQUAD(ic_gateway));
-	printk(",\n     host=%s, domain=%s, nis-domain=%s",
-	       utsname()->nodename, ic_domain, utsname()->domainname);
-	printk(",\n     bootserver=%u.%u.%u.%u", NIPQUAD(ic_servaddr));
-	printk(", rootserver=%u.%u.%u.%u", NIPQUAD(root_server_addr));
-	printk(", rootpath=%s", root_server_path);
-	printk("\n");
-#endif /* !SILENT */
-
-	return 0;
-}
-
-late_initcall(ip_auto_config);
-
-
-/*
- *  Decode any IP configuration options in the "ip=" or "nfsaddrs=" kernel
- *  command line parameter. It consists of option fields separated by colons in
- *  the following order:
- *
- *  <client-ip>:<server-ip>:<gw-ip>:<netmask>:<host name>:<device>:<PROTO>
- *
- *  Any of the fields can be empty which means to use a default value:
- *	<client-ip>	- address given by BOOTP or RARP
- *	<server-ip>	- address of host returning BOOTP or RARP packet
- *	<gw-ip>		- none, or the address returned by BOOTP
- *	<netmask>	- automatically determined from <client-ip>, or the
- *			  one returned by BOOTP
- *	<host name>	- <client-ip> in ASCII notation, or the name returned
- *			  by BOOTP
- *	<device>	- use all available devices
- *	<PROTO>:
- *	   off|none	    - don't do autoconfig at all (DEFAULT)
- *	   on|any           - use any configured protocol
- *	   dhcp|bootp|rarp  - use only the specified protocol
- *	   both             - use both BOOTP and RARP (not DHCP)
- */
-static int __init ic_proto_name(char *name)
-{
-	if (!strcmp(name, "on") || !strcmp(name, "any")) {
-		return 1;
-	}
-#ifdef CONFIG_IP_PNP_DHCP
-	else if (!strcmp(name, "dhcp")) {
-		ic_proto_enabled &= ~IC_RARP;
-		return 1;
-	}
-#endif
-#ifdef CONFIG_IP_PNP_BOOTP
-	else if (!strcmp(name, "bootp")) {
-		ic_proto_enabled &= ~(IC_RARP | IC_USE_DHCP);
-		return 1;
-	}
-#endif
-#ifdef CONFIG_IP_PNP_RARP
-	else if (!strcmp(name, "rarp")) {
-		ic_proto_enabled &= ~(IC_BOOTP | IC_USE_DHCP);
-		return 1;
-	}
-#endif
-#ifdef IPCONFIG_DYNAMIC
-	else if (!strcmp(name, "both")) {
-		ic_proto_enabled &= ~IC_USE_DHCP; /* backward compat :-( */
-		return 1;
-	}
-#endif
-	return 0;
-}
-
-static int __init ip_auto_config_setup(char *addrs)
-{
-	char *cp, *ip, *dp;
-	int num = 0;
-
-	ic_set_manually = 1;
-
-	ic_enable = (*addrs &&
-		(strcmp(addrs, "off") != 0) &&
-		(strcmp(addrs, "none") != 0));
-	if (!ic_enable)
-		return 1;
-
-	if (ic_proto_name(addrs))
-		return 1;
-
-	/* Parse the whole string */
-	ip = addrs;
-	while (ip && *ip) {
-		if ((cp = strchr(ip, ':')))
-			*cp++ = '\0';
-		if (strlen(ip) > 0) {
-			DBG(("IP-Config: Parameter #%d: `%s'\n", num, ip));
-			switch (num) {
-			case 0:
-				if ((ic_myaddr = in_aton(ip)) == INADDR_ANY)
-					ic_myaddr = NONE;
-				break;
-			case 1:
-				if ((ic_servaddr = in_aton(ip)) == INADDR_ANY)
-					ic_servaddr = NONE;
-				break;
-			case 2:
-				if ((ic_gateway = in_aton(ip)) == INADDR_ANY)
-					ic_gateway = NONE;
-				break;
-			case 3:
-				if ((ic_netmask = in_aton(ip)) == INADDR_ANY)
-					ic_netmask = NONE;
-				break;
-			case 4:
-				if ((dp = strchr(ip, '.'))) {
-					*dp++ = '\0';
-					strlcpy(utsname()->domainname, dp,
-						sizeof(utsname()->domainname));
-				}
-				strlcpy(utsname()->nodename, ip,
-					sizeof(utsname()->nodename));
-				ic_host_name_set = 1;
-				break;
-			case 5:
-				strlcpy(user_dev_name, ip, sizeof(user_dev_name));
-				break;
-			case 6:
-				ic_proto_name(ip);
-				break;
-			}
-		}
-		ip = cp;
-		num++;
-	}
-
-	return 1;
-}
-
-static int __init nfsaddrs_config_setup(char *addrs)
-{
-	return ip_auto_config_setup(addrs);
-}
-
-__setup("ip=", ip_auto_config_setup);
-__setup("nfsaddrs=", nfsaddrs_config_setup);
diff --git a/scripts/Kbuild.include b/scripts/Kbuild.include
index 06c1a37..ad543a5 100644
--- a/scripts/Kbuild.include
+++ b/scripts/Kbuild.include
@@ -120,6 +120,11 @@
 # $(Q)$(MAKE) $(build)=dir
 build := -f $(if $(KBUILD_SRC),$(srctree)/)scripts/Makefile.build obj
 
+# Shorthand for $(Q)$(MAKE) -f scripts/Kbuild.klibc obj=
+# Usage:
+# $(Q)$(MAKE) $(klibc)=dir
+klibc := -f $(srctree)/scripts/Kbuild.klibc obj
+
 # Prefix -I with $(srctree) if it is not an absolute path.
 addtree = $(if $(filter-out -I/%,$(1)),$(patsubst -I%,-I$(srctree)/%,$(1))) $(1)
 
diff --git a/scripts/Kbuild.klibc b/scripts/Kbuild.klibc
new file mode 100644
index 0000000..227b9bd
--- /dev/null
+++ b/scripts/Kbuild.klibc
@@ -0,0 +1,418 @@
+# ==========================================================================
+# Support for building klibc programs and klibc library
+# ==========================================================================
+#
+# To create a kbuild file for a userspace program do the following:
+#
+# Kbuild:
+#
+# static-y := cat
+# # This will compile a file named cat.c -> the executable 'cat'
+# # The executable will be linked statically
+#
+# shared-y := cats
+# # This will compile a file named cats.c -> the executable 'cats'
+# # The executable will be linked shared
+#
+# If the userspace program consist of composite files do the following:
+# Kbuild:
+#
+# static-y := kinit
+# kinit-y  := main.o netdev.c
+# So kinit will be linked statically using the two .o files
+# specified with kinit-y.
+#
+# Are part of the program located in a sub-directory do like this:
+# kinit-y += ipconfig/
+#
+# And in the subdirectory:
+# ipconfig/Kbuild:
+# lib-y := packet.o dhcp_proto.o
+# # All .o files listed with lib-y will be used to create a single .a file.
+# # The .a file is created before any subdirectories are visited so it
+# # may be used in the sub-directory programs.
+#
+#####
+# For a klibc libary file do like this
+# klibc/Kbuild
+# klib-y := error.o pipe.o zlib/
+#
+#####
+# Handling of compiler/linker options
+#
+# To set directory wide CFLAGS use:
+# EXTRA_KLIBCCFLAGS := -DDEBUG
+# To set directory wide AFLAGS use:
+# EXTRA_KLIBCAFLAGS := -DDEBUG
+#
+# To set target specific CFLAGS (for .c files) use
+# KLIBCCFLAGS-main.o := -DDEBUG=3
+# To set target specific AFLAGS (for .s files) use
+# KLIBCAFLAGS-main.o := -DDEBUG=3
+
+src := $(obj)
+# Preset target and make sure it is a ':=' variable
+targets :=
+
+.phony: __build
+__build:
+
+# Read .config if it exist, otherwise ignore
+-include .config
+
+# Generic Kbuild routines
+include $(srctree)/scripts/Kbuild.include
+
+# Defines used when compiling early userspace (klibc programs)
+# ---------------------------------------------------------------------------
+
+KLIBCREQFLAGS     := $(call cc-option, -fno-stack-protector, )
+KLIBCARCHREQFLAGS :=
+KLIBCOPTFLAGS     :=
+KLIBCWARNFLAGS    := -W -Wall -Wno-sign-compare -Wno-unused-parameter
+KLIBCSHAREDFLAGS  :=
+KLIBCBITSIZE      :=
+KLIBCLDFLAGS      :=
+KLIBCCFLAGS       :=
+
+# Arch specific definitions for klibc
+include $(KLIBCSRC)/arch/$(KLIBCARCHDIR)/MCONFIG
+
+# include/asm-* architecture
+KLIBCASMARCH	  ?= $(KLIBCARCH)
+
+# klibc version
+KLIBCMAJOR        := $(shell cut -d. -f1 $(srctree)/usr/klibc/version)
+KLIBCMINOR        := $(shell cut -d. -f2 $(srctree)/usr/klibc/version)
+
+# binutils
+KLIBCLD          := $(LD)
+KLIBCCC          := $(CC)
+KLIBCAR          := $(AR)
+KLIBCRANLIB      := $(RANLIB)
+KLIBCSTRIP       := $(STRIP)
+KLIBCNM          := $(NM)
+KLIBCOBJCOPY	 := $(OBJCOPY)
+KLIBCOBJDUMP	 := $(OBJDUMP)
+
+# klibc include paths
+KLIBCCPPFLAGS    := -nostdinc -iwithprefix include \
+		    -I$(KLIBCINC)/arch/$(KLIBCARCHDIR)	\
+                    -I$(KLIBCINC)/bits$(KLIBCBITSIZE)	\
+		    -I$(KLIBCOBJ)/../include		\
+                    -I$(KLIBCINC)
+# kernel include paths
+KLIBCKERNELSRC	 ?= $(srctree)/
+KLIBCCPPFLAGS    += -I$(KLIBCKERNELSRC)include		\
+                     $(if $(KBUILD_SRC),-I$(KLIBCKERNELOBJ)include2 -I$(KLIBCKERNELOBJ)include -I$(srctree)/include)    \
+		     $(KLIBCARCHINCFLAGS)
+
+# klibc definitions
+KLIBCDEFS        += -D__KLIBC__=$(KLIBCMAJOR)          \
+		    -D__KLIBC_MINOR__=$(KLIBCMINOR)    \
+		    -D_BITSIZE=$(KLIBCBITSIZE)
+KLIBCCPPFLAGS    += $(KLIBCDEFS)
+KLIBCCFLAGS      += $(KLIBCCPPFLAGS) $(KLIBCREQFLAGS) $(KLIBCARCHREQFLAGS)  \
+                    $(KLIBCOPTFLAGS) $(KLIBCWARNFLAGS)
+KLIBCAFLAGS      += -D__ASSEMBLY__ $(KLIBCCFLAGS)
+KLIBCSTRIPFLAGS  += --strip-all -R .comment -R .note
+
+KLIBCLIBGCC_DEF  := $(shell $(KLIBCCC) $(KLIBCCFLAGS) --print-libgcc)
+KLIBCLIBGCC	 ?= $(KLIBCLIBGCC_DEF)
+KLIBCCRT0        := $(KLIBCOBJ)/arch/$(KLIBCARCHDIR)/crt0.o
+KLIBCLIBC        := $(KLIBCOBJ)/libc.a
+KLIBCCRTSHARED   := $(KLIBCOBJ)/interp.o
+KLIBCLIBCSHARED  := $(KLIBCOBJ)/libc.so
+# How to tell the linker main() is the entrypoint
+KLIBCEMAIN	 ?= -e main
+
+#
+# This indicates the location of the final version of the shared library.
+# THIS MUST BE AN ABSOLUTE PATH WITH NO FINAL SLASH.
+# Leave this empty to make it the root.
+#
+SHLIBDIR = /lib
+
+export KLIBCLD KLIBCCC KLIBCAR KLIBCSTRIP KLIBCNM
+export KLIBCCFLAGS KLIBCAFLAGS KLIBCLIBGCC KLIBCSHAREDFLAGS KLIBCSTRIPFLAGS
+export KLIBCCRT0 KLIBCLIBC SHLIBDIR
+
+# kernel configuration
+include .config
+
+# Add $(obj)/ for paths that is not absolute
+objectify = $(foreach o,$(1),$(if $(filter /%,$(o)),$(o),$(obj)/$(o)))
+
+# Kbuild file in the directory that is being build
+include $(obj)/Kbuild
+
+#####
+# static-y + shared-y handling
+kprogs := $(static-y) $(shared-y)
+# kprogs based on a single .o file (with same name + .o)
+kprog-objs := $(foreach p, $(kprogs), $(if $($(p)-y),,$(p)))
+kprog-objs := $(addsuffix .o, $(kprog-objs))
+# kprogs which is based on several .o files
+kprog-multi := $(foreach p, $(kprogs), $(if $($(p)-y),$(p)))
+# objects used for kprogs with more then one .o file
+kprog-objs += $(foreach p, $(kprog-multi), $($(p)-y))
+# objects build in this dir
+kprog-real-objs := $(patsubst %/,,$(kprog-objs))
+# Directories we need to visit before kprogs-objs are up-to-date
+kprog-dirs :=  $(patsubst %/,%,$(filter %/, $(kprog-objs)))
+# replace all dir/ with dir/lib.a
+kprog-objs := $(patsubst %/, %/lib.a, $(kprog-objs))
+
+targets += $(static-y) $(shared-y)
+
+#####
+# klib-y handling
+# .o files to build in this dir
+klib-real-objs := $(patsubst %/,,$(klib-y))
+# Directories we need to visit before libs are up-to-date
+klib-dirs := $(patsubst %/,%,$(filter %/, $(klib-y)))
+# replace all dir/ with dir/klib.list
+klib-objs := $(patsubst %/, %/klib.list, $(klib-y))
+
+# $(output-dirs) are a list of directories that contain object files
+output-dirs := $(dir $(kprog-dirs) $(kprog-objs))
+output-dirs += $(foreach f, $(hostprogs-y) $(targets), \
+               $(if $(dir $(f)), $(dir $(f))))
+output-dirs += $(dir $(klib-objs))
+output-dirs := $(strip $(sort $(filter-out ./,$(output-dirs))))
+
+# prefix so we get full dir
+static-y        := $(addprefix $(obj)/,$(static-y))
+shared-y        := $(addprefix $(obj)/,$(shared-y))
+kprog-objs      := $(addprefix $(obj)/,$(kprog-objs))
+kprog-real-objs := $(addprefix $(obj)/,$(kprog-real-objs))
+output-dirs     := $(addprefix $(obj)/,$(output-dirs))
+kprog-dirs      := $(addprefix $(obj)/,$(kprog-dirs))
+subdir-y        := $(addprefix $(obj)/,$(subdir-y))
+always          := $(addprefix $(obj)/,$(always))
+targets         := $(addprefix $(obj)/,$(targets))
+lib-y           := $(addprefix $(obj)/,$(lib-y))
+klib-y          := $(addprefix $(obj)/,$(klib-y))
+klib-objs       := $(addprefix $(obj)/,$(klib-objs))
+klib-real-objs  := $(addprefix $(obj)/,$(klib-real-objs))
+klib-dirs       := $(addprefix $(obj)/,$(klib-dirs))
+
+#####
+# Handle options to gcc. Support building with separate output directory
+
+__klibccflags    = $(KLIBCCFLAGS) $(EXTRA_KLIBCCFLAGS) $(KLIBCCFLAGS_$(*F).o)
+__klibcaflags    = $(KLIBCAFLAGS) $(EXTRA_KLIBCAFLAGS) $(KLIBCAFLAGS_$(*F).o)
+
+ifeq ($(KBUILD_SRC),)
+_klibccflags    = $(__klibccflags)
+_klibcaflags    = $(__klibcaflags)
+else
+_klibccflags    = $(call flags,__klibccflags)
+_klibcaflags    = $(call flags,__klibcaflags)
+endif
+
+klibccflags     = -Wp,-MD,$(depfile) $(NOSTDINC_FLAGS) $(_klibccflags)
+klibcaflags     = -Wp,-MD,$(depfile) $(NOSTDINC_FLAGS) $(_klibcaflags)
+
+# Create output directory if not already present
+_dummy := $(shell [ -d $(obj) ] || mkdir -p $(obj))
+
+# Create directories for object files if directory does not exist
+# Needed when lib-y := dir/file.o syntax is used
+_dummy := $(foreach d,$(output-dirs), $(shell [ -d $(d) ] || mkdir -p $(d)))
+
+# Do we have to make a lib.a in this dir?
+ifneq ($(strip $(lib-y) $(lib-n) $(lib-)),)
+lib-target := $(obj)/lib.a
+endif
+
+__build: $(subdir-y) $(lib-target) $(always)
+	$(Q):
+
+# Compile C sources (.c)
+# ---------------------------------------------------------------------------
+
+quiet_cmd_cc_s_c = KLIBCCC $@
+      cmd_cc_s_c = $(KLIBCCC) $(klibccflags) -S -o $@ $<
+
+%.s: %.c FORCE
+	$(call if_changed_dep,cc_s_c)
+
+quiet_cmd_cc_o_c = KLIBCCC $@
+      cmd_cc_o_c = $(KLIBCCC) $(klibccflags) -c -o $@ $<
+
+%.o: %.c FORCE
+	$(call if_changed_dep,cc_o_c)
+
+quiet_cmd_cc_i_c = CPP     $@
+      cmd_cc_i_c = $(KLIBCCC) -E $(klibccflags) -o $@ $<
+%.i: %.c FORCE
+	$(call if_changed_dep,cc_i_c)
+
+# Compile assembler sources (.S)
+# ---------------------------------------------------------------------------
+
+quiet_cmd_as_o_S = KLIBCAS $@
+      cmd_as_o_S = $(KLIBCCC) $(klibcaflags) -c -o $@ $<
+
+%.o: %.S FORCE
+	$(call if_changed_dep,as_o_S)
+
+targets += $(real-objs-y)
+
+#
+# Rule to compile a set of .o files into one .o file
+#
+ifdef lib-target
+quiet_cmd_link_o_target = LD      $@
+# If the list of objects to link is empty, just create an empty lib.a
+cmd_link_o_target = $(if $(strip $(lib-y)),\
+                    rm -f $@; $(KLIBCAR) cru $@ $(filter $(lib-y), $^),\
+                    rm -f $@; $(KLIBCAR) crs $@)
+
+$(lib-target): $(lib-y) FORCE
+	$(call if_changed,link_o_target)
+targets += $(lib-target) $(lib-y)
+endif # lib-target
+
+#
+# Create klib.list
+#
+# Do we have to create a klibc library file in this dir?
+ifneq ($(strip $(klib-y) $(klib-n) $(klib-)),)
+klib-target := $(obj)/klib.list
+endif
+
+ifdef klib-target
+# include this in build
+__build: $(klib-target) $(klib-dirs)
+
+# descend if needed
+$(sort $(addsuffix /klib.list,$(klib-dirs))): $(klib-dirs) ;
+
+# create klib.list
+quiet_cmd_klib-list = LIST    $@
+      cmd_klib-list = echo $(klib-real-objs) > $@
+$(klib-target): $(klib-objs) FORCE
+	$(call if_changed,klib-list)
+targets += $(klib-target) $(klib-real-objs)
+endif # klib-target
+
+ifdef kprogs
+# Compile klibc-programs for the target
+# ===========================================================================
+
+__build : $(kprog-dirs) $(static-y) $(shared-y)
+
+# Descend if needed
+$(sort $(addsuffix /lib.a,$(kprog-dirs))): $(kprog-dirs) ;
+
+# Define dependencies for link of progs
+# For the simple program:
+#	file.o => file
+# A program with multiple objects
+#	filea.o, fileb.o => file
+# A program with .o files in another dir
+#	dir/lib.a filea.o => file
+
+stripobj  = $(subst $(obj)/,,$@)
+addliba   = $(addprefix $(obj)/, $(patsubst %/, %/lib.a, $(1)))
+link-deps = $(if $($(stripobj)-y), $(call addliba, $($(stripobj)-y)), $@.o) \
+	    $(call objectify,$($(stripobj)-lib))
+
+quiet_cmd_ld-static = KLIBCLD $@
+      cmd_ld-static = $(KLIBCLD) $(KLIBCLDFLAGS) -o $@		\
+                       $(EXTRA_KLIBCLDFLAGS)			\
+                       $(KLIBCCRT0)				\
+		       --start-group				\
+                       $(link-deps)				\
+                       $(KLIBCLIBC)				\
+		       $(KLIBCLIBGCC)				\
+		       --end-group ;				\
+                      cp -f $@ $@.g ;				\
+                      $(KLIBCSTRIP) $(KLIBCSTRIPFLAGS) $@
+
+
+$(static-y): $(kprog-objs) $(lib-target) $(KLIBCCRT0) $(KLIBCLIBC) FORCE
+	$(call if_changed,ld-static)
+
+quiet_cmd_ld-shared = KLIBCLD $@
+      cmd_ld-shared = $(KLIBCLD) $(KLIBCLDFLAGS) -o $@		\
+                       $(EXTRA_KLIBCLDFLAGS)			\
+                       $(KLIBCEMAIN) $(KLIBCCRTSHARED)		\
+                       --start-group				\
+                       $(link-deps)				\
+                       -R $(KLIBCLIBCSHARED)			\
+	               $(KLIBCLIBGCC)				\
+		       --end-group ;				\
+                      cp -f $@ $@.g ;				\
+                      $(KLIBCSTRIP) $(KLIBCSTRIPFLAGS) $@
+
+
+$(shared-y): $(kprog-objs) $(lib-target) $(KLIBCCRTSHARED) \
+                                         $(KLIBCLIBCSHARED) FORCE
+	$(call if_changed,ld-shared)
+
+# Do not try to build KLIBC libaries if we are building klibc
+ifeq ($(klibc-build),)
+$(KLIBCCRT0) $(KLIBCLIBC): ;
+$(KLIBCCRTSHARED) $(KLIBCLIBCSHARED): ;
+endif
+
+targets += $(kprog-real-objs)
+endif
+
+# Compile programs on the host
+# ===========================================================================
+ifdef hostprogs-y
+include $(srctree)/scripts/Makefile.host
+endif
+
+# Descending
+# ---------------------------------------------------------------------------
+
+.PHONY: $(subdir-y) $(kprog-dirs) $(klib-dirs)
+$(sort $(subdir-y) $(kprog-dirs) $(klib-dirs)): $(lib-target)
+	$(Q)$(MAKE) $(klibc)=$@
+
+# Add FORCE to the prequisites of a target to force it to be always rebuilt.
+# ---------------------------------------------------------------------------
+
+.PHONY: FORCE
+
+FORCE:
+
+# Linking
+# Create a reloctable composite object file
+# ---------------------------------------------------------------------------
+quiet_cmd_klibcld = KLIBCLD $@
+      cmd_klibcld = $(KLIBCLD) -r $(KLIBCLDFLAGS) \
+                                $(EXTRA_KLIBCLDFLAGS) $(KLIBCLDFLAGS_$(@F)) \
+                                $(filter-out FORCE,$^) -o $@
+
+
+# Link target to a new name
+# ---------------------------------------------------------------------------
+quiet_cmd_ln = LN      $@
+      cmd_ln = rm -f $@ && ln $< $@
+
+# Strip target (remove all debugging info)
+quiet_cmd_strip = STRIP   $@
+      cmd_strip = $(KLIBCSTRIP) $(KLIBCSTRIPFLAGS) $< -o $@
+
+
+# Read all saved command lines and dependencies for the $(targets) we
+# may be building above, using $(if_changed{,_dep}). As an
+# optimization, we don't need to read them if the target does not
+# exist, we will rebuild anyway in that case.
+targets := $(wildcard $(sort $(targets)))
+cmd_files := $(wildcard $(foreach f,$(targets),$(dir $(f)).$(notdir $(f)).cmd))
+
+ifneq ($(cmd_files),)
+  include $(cmd_files)
+endif
+
+# Shorthand for $(Q)$(MAKE) -f scripts/Kbuild.klibc obj
+# Usage:
+# $(Q)$(MAKE) $(klibc)=dir
+klibc := -rR -f $(if $(KBUILD_SRC),$(srctree)/)scripts/Kbuild.klibc obj
diff --git a/scripts/Makefile.clean b/scripts/Makefile.clean
index cff3349..2d84222 100644
--- a/scripts/Makefile.clean
+++ b/scripts/Makefile.clean
@@ -19,23 +19,18 @@
 # Figure out what we need to build from the various variables
 # ==========================================================================
 
-__subdir-y	:= $(patsubst %/,%,$(filter %/, $(obj-y)))
-subdir-y	+= $(__subdir-y)
-__subdir-m	:= $(patsubst %/,%,$(filter %/, $(obj-m)))
-subdir-m	+= $(__subdir-m)
-__subdir-n	:= $(patsubst %/,%,$(filter %/, $(obj-n)))
-subdir-n	+= $(__subdir-n)
-__subdir-	:= $(patsubst %/,%,$(filter %/, $(obj-)))
-subdir-		+= $(__subdir-)
+subdirs := $(subdir-y) $(subdir-m) $(subdir-n) $(subdir-)
+subdirs += $(patsubst %/,%,$(filter %/, $(obj-y)))
+subdirs += $(patsubst %/,%,$(filter %/, $(obj-m)))
+subdirs += $(patsubst %/,%,$(filter %/, $(obj-n)))
+subdirs += $(patsubst %/,%,$(filter %/, $(obj-)))
+
+subdirs += $(patsubst %/,%,$(filter %/, $(klib-y)))
+subdirs += $(patsubst %/,%,$(filter %/, $(klib-)))
 
 # Subdirectories we need to descend into
+subdirs := $(addprefix $(obj)/,$(sort $(subdirs)))
 
-subdir-ym	:= $(sort $(subdir-y) $(subdir-m))
-subdir-ymn      := $(sort $(subdir-ym) $(subdir-n) $(subdir-))
-
-# Add subdir path
-
-subdir-ymn	:= $(addprefix $(obj)/,$(subdir-ymn))
 
 # build a list of files to remove, usually releative to the current
 # directory
@@ -43,7 +38,8 @@
 __clean-files	:= $(extra-y) $(EXTRA_TARGETS) $(always) \
 		   $(targets) $(clean-files)             \
 		   $(host-progs)                         \
-		   $(hostprogs-y) $(hostprogs-m) $(hostprogs-)
+		   $(hostprogs-y) $(hostprogs-m) $(hostprogs-) \
+		   klib.list
 
 # as clean-files is given relative to the current directory, this adds
 # a $(obj) prefix, except for absolute paths
@@ -67,7 +63,7 @@
       cmd_cleandir = rm -rf $(__clean-dirs)
 
 
-__clean: $(subdir-ymn)
+__clean: $(subdirs)
 ifneq ($(strip $(__clean-files)),)
 	+$(call cmd,clean)
 endif
@@ -87,8 +83,8 @@
 # Descending
 # ---------------------------------------------------------------------------
 
-PHONY += $(subdir-ymn)
-$(subdir-ymn):
+.PHONY: $(subdirs)
+$(subdirs):
 	$(Q)$(MAKE) $(clean)=$@
 
 # If quiet is set, only print short version of command
diff --git a/scripts/gen_initramfs_list.sh b/scripts/gen_initramfs_list.sh
index 683eb12..d25b38f 100644
--- a/scripts/gen_initramfs_list.sh
+++ b/scripts/gen_initramfs_list.sh
@@ -15,7 +15,7 @@
 usage() {
 cat << EOF
 Usage:
-$0 [-o <file>] [-u <uid>] [-g <gid>] {-d | <cpio_source>} ...
+$0 [-o <file>] [-u <uid>] [-g <gid>] <cpio_source> ...
 	-o <file>      Create gzipped initramfs file named <file> using
 		       gen_init_cpio and gzip
 	-u <uid>       User ID to map to user ID 0 (root).
@@ -27,7 +27,6 @@
 	<cpio_source>  File list or directory for cpio archive.
 		       If <cpio_source> is a .cpio file it will be used
 		       as direct input to initramfs.
-	-d             Output the default cpio list.
 
 All options except -o and -l may be repeated and are interpreted
 sequentially and immediately.  -u and -g states are preserved across
@@ -36,29 +35,6 @@
 EOF
 }
 
-# awk style field access
-# $1 - field number; rest is argument string
-field() {
-	shift $1 ; echo $1
-}
-
-list_default_initramfs() {
-	# echo usr/kinit/kinit
-	:
-}
-
-default_initramfs() {
-	cat <<-EOF >> ${output}
-		# This is a very simple, default initramfs
-
-		dir /dev 0755 0 0
-		nod /dev/console 0600 0 0 c 5 1
-		dir /root 0700 0 0
-		# file /kinit usr/kinit/kinit 0755 0 0
-		# slink /init kinit 0755 0 0
-	EOF
-}
-
 filetype() {
 	local argv1="$1"
 
@@ -168,8 +144,6 @@
 
 # process one directory (incl sub-directories)
 dir_filelist() {
-	${dep_list}header "$1"
-
 	srcdir=$(echo "$1" | sed -e 's://*:/:g')
 	dirlist=$(find "${srcdir}" -printf "%p %m %U %G\n")
 
@@ -188,7 +162,6 @@
 # if a directory is specified then add all files in given direcotry to fs
 # if a regular file is specified assume it is in gen_initramfs format
 input_file() {
-	source="$1"
 	if [ -f "$1" ]; then
 		${dep_list}header "$1"
 		is_cpio="$(echo "$1" | sed 's/^.*\.cpio\(\..*\)\?/cpio/')"
@@ -216,6 +189,15 @@
 	fi
 }
 
+# input file/dir - process it
+process_file() {
+	if [ -z ${print_header} ]; then
+		${dep_list}header "$1"
+	fi
+	print_header=y
+	input_file "$1" "$2"
+}
+
 prog=$0
 root_uid=0
 root_gid=0
@@ -253,27 +235,29 @@
 			root_gid="$1"
 			shift
 			;;
-		"-d")	# display default initramfs list
-			default_list="$arg"
-			${dep_list}default_initramfs
-			;;
 		"-h")
 			usage
 			exit 0
 			;;
 		*)
 			case "$arg" in
-				"-"*)
-					unknown_option
+				"-"*)	unknown_option
 					;;
-				*)	# input file/dir - process it
-					input_file "$arg" "$#"
+				*)	process_file "$arg" "$#"
 					;;
 			esac
 			;;
 	esac
 done
 
+# trailer of dependency list
+if [ ! -z ${dep_list} ]; then
+	echo ""
+	echo "initramfs: \$(deps_initramfs)"
+	echo "\$(deps_initramfs): ;"
+	echo ""
+fi
+
 # If output_file is set we will generate cpio archive and gzip it
 # we are carefull to delete tmp files
 if [ ! -z ${output_file} ]; then
diff --git a/usr/Kbuild b/usr/Kbuild
new file mode 100644
index 0000000..cc0a047
--- /dev/null
+++ b/usr/Kbuild
@@ -0,0 +1,75 @@
+#
+# kbuild file for usr/ - including initramfs image and klibc
+#
+
+CONFIG_KLIBC := 1
+
+include-subdir := include
+klibc-subdir := klibc
+usr-subdirs  := kinit utils dash gzip
+subdir-      := $(include-subdir) $(klibc-subdir) $(usr-subdirs)
+
+usr-subdirs  := $(addprefix _usr_,$(usr-subdirs))
+klibc-subdir := $(addprefix _usr_,$(klibc-subdir))
+
+# Klibc binaries
+ifdef CONFIG_KLIBC
+
+# .initramfs_data.cpio.gz.d is used to identify all files included
+# in initramfs and to detect if any files are added/removed.
+# Removed files are identified by directory timestamp being updated
+# The dependency list is generated by gen_initramfs.sh -l
+ifneq ($(wildcard $(obj)/.initramfs_data.cpio.gz.d),)
+	include $(obj)/.initramfs_data.cpio.gz.d
+endif
+
+# build klibc library before the klibc programs
+# build klibc programs before cpio.gz
+.PHONY: initramfs $(usr-subdirs) $(klibc-subdir) $(include-subdir)
+initramfs:         $(usr-subdirs) $(klibc-subdir) $(include-subdir)
+$(deps_initramfs): $(usr-subdirs) $(klibc-subdir) $(include-subdir)
+
+$(usr-subdirs): $(klibc-subdir)
+	$(Q)$(MAKE) $(klibc)=$(src)/$(patsubst _usr_%,%,$(@))
+
+$(klibc-subdir): $(include-subdir)
+	$(Q)$(MAKE) $(klibc)=$(src)/$(patsubst _usr_%,%,$(@))
+
+$(include-subdir):
+	$(Q)$(MAKE) $(klibc)=$(src)/$(patsubst _usr_%,%,$(@))
+endif
+
+
+# Generate builtin.o based on initramfs_data.o
+obj-$(CONFIG_BLK_DEV_INITRD) := initramfs_data.o
+
+# initramfs_data.o contains the initramfs_data.cpio.gz image.
+# The image is included using .incbin, a dependency which is not
+# tracked automatically.
+$(obj)/initramfs_data.o: $(obj)/initramfs_data.cpio.gz FORCE
+
+#####
+# Generate the initramfs cpio archive
+
+hostprogs-y := gen_init_cpio
+ginitramfs  := $(CONFIG_SHELL) $(srctree)/scripts/gen_initramfs_list.sh
+ramfs-def   := $(srctree)/$(src)/initramfs.default
+ramfs-input := $(shell echo $(CONFIG_INITRAMFS_SOURCE))
+ramfs-input := $(if $(ramfs-input), $(ramfs-input), $(ramfs-def))
+
+ramfs-args  := \
+        $(if $(CONFIG_INITRAMFS_ROOT_UID), -u $(CONFIG_INITRAMFS_ROOT_UID)) \
+        $(if $(CONFIG_INITRAMFS_ROOT_GID), -g $(CONFIG_INITRAMFS_ROOT_GID))
+
+quiet_cmd_initfs = GEN     $@
+      cmd_initfs = $(ginitramfs) -o $@ $(ramfs-args) $(ramfs-input)
+
+targets := initramfs_data.cpio.gz
+# We rebuild initramfs_data.cpio.gz if:
+# 1) Any included file is newer then initramfs_data.cpio.gz
+# 2) There are changes in which files are included (added or deleted)
+# 3) If gen_init_cpio are newer than initramfs_data.cpio.gz
+# 4) arguments to gen_initramfs.sh changes
+$(obj)/initramfs_data.cpio.gz: $(obj)/gen_init_cpio $(deps_initramfs) initramfs
+	$(Q)$(ginitramfs) -l $(ramfs-input) > $(obj)/.initramfs_data.cpio.gz.d
+	$(call if_changed,initfs)
diff --git a/usr/Kconfig b/usr/Kconfig
index 86cecb5..7f5847a 100644
--- a/usr/Kconfig
+++ b/usr/Kconfig
@@ -44,3 +44,24 @@
 	  owned by group root in the initial ramdisk image.
 
 	  If you are not sure, leave it set to "0".
+
+config KLIBC_ERRLIST
+	bool "Early userspace real error messages" if EMBEDDED
+	default y
+	help
+	  If this is set, kinit (and other klibc-derived binaries)
+	  will have the standard list of error messages built in, and
+	  thus will report, for example, "No such file or directory"
+	  instead of "Error 1".  Leaving it out will save
+	  approximately 4K from each static binary (one, unless you
+	  have a different initramfs_source.txt) or the shared
+	  library.
+
+	  If you are not sure, "Y" is highly recommended.
+
+config KLIBC_ZLIB
+	bool
+	default y
+	help
+	  This builds the zlib portion of klibc.  This is currently
+	  required.
diff --git a/usr/Makefile b/usr/Makefile
deleted file mode 100644
index 201f27f..0000000
--- a/usr/Makefile
+++ /dev/null
@@ -1,52 +0,0 @@
-#
-# kbuild file for usr/ - including initramfs image
-#
-
-klibcdirs:;
-PHONY += klibcdirs
-
-
-# Generate builtin.o based on initramfs_data.o
-obj-$(CONFIG_BLK_DEV_INITRD) := initramfs_data.o
-
-# initramfs_data.o contains the initramfs_data.cpio.gz image.
-# The image is included using .incbin, a dependency which is not
-# tracked automatically.
-$(obj)/initramfs_data.o: $(obj)/initramfs_data.cpio.gz FORCE
-
-#####
-# Generate the initramfs cpio archive
-
-hostprogs-y := gen_init_cpio
-initramfs   := $(CONFIG_SHELL) $(srctree)/scripts/gen_initramfs_list.sh
-ramfs-input := $(if $(filter-out "",$(CONFIG_INITRAMFS_SOURCE)), \
-			$(shell echo $(CONFIG_INITRAMFS_SOURCE)),-d)
-ramfs-args  := \
-        $(if $(CONFIG_INITRAMFS_ROOT_UID), -u $(CONFIG_INITRAMFS_ROOT_UID)) \
-        $(if $(CONFIG_INITRAMFS_ROOT_GID), -g $(CONFIG_INITRAMFS_ROOT_GID))
-
-# .initramfs_data.cpio.gz.d is used to identify all files included
-# in initramfs and to detect if any files are added/removed.
-# Removed files are identified by directory timestamp being updated
-# The dependency list is generated by gen_initramfs.sh -l
-ifneq ($(wildcard $(obj)/.initramfs_data.cpio.gz.d),)
-	include $(obj)/.initramfs_data.cpio.gz.d
-endif
-
-quiet_cmd_initfs = GEN     $@
-      cmd_initfs = $(initramfs) -o $@ $(ramfs-args) $(ramfs-input)
-
-targets := initramfs_data.cpio.gz
-# do not try to update files included in initramfs
-$(deps_initramfs): ;
-
-$(deps_initramfs): klibcdirs
-# We rebuild initramfs_data.cpio.gz if:
-# 1) Any included file is newer then initramfs_data.cpio.gz
-# 2) There are changes in which files are included (added or deleted)
-# 3) If gen_init_cpio are newer than initramfs_data.cpio.gz
-# 4) arguments to gen_initramfs.sh changes
-$(obj)/initramfs_data.cpio.gz: $(obj)/gen_init_cpio $(deps_initramfs) klibcdirs
-	$(Q)$(initramfs) -l $(ramfs-input) > $(obj)/.initramfs_data.cpio.gz.d
-	$(call if_changed,initfs)
-
diff --git a/usr/dash/Kbuild b/usr/dash/Kbuild
new file mode 100644
index 0000000..edaa93f
--- /dev/null
+++ b/usr/dash/Kbuild
@@ -0,0 +1,111 @@
+#
+# Kbuild file for dash
+#
+
+config-cppflags := -DBSD=1 -DSMALL -DJOBS=0 -DHAVE_CONFIG_H -DSHELL
+config-cppflags += -DGLOB_BROKEN -DIFS_BROKEN
+
+EXTRA_KLIBCCFLAGS := -I$(srctree)/$(src) -I$(objtree)/$(obj)
+EXTRA_KLIBCCFLAGS += -include $(srctree)/$(src)/config.h
+EXTRA_KLIBCCFLAGS += $(config-cppflags)
+
+HOST_EXTRACFLAGS  := $(config-cppflags)
+
+init-o-files := alias.o arith_yylex.o cd.o error.o eval.o exec.o expand.o \
+		histedit.o input.o jobs.o mail.o main.o memalloc.o miscbltin.o \
+		mystring.o options.o parser.o redir.o show.o trap.o output.o \
+		bltin/printf.o system.o bltin/test.o var.o
+
+gen-o-files := arith.o builtins.o init.o nodes.o syntax.o
+
+sh-y := $(init-o-files) $(gen-o-files)
+
+hostprogs-y := mkinit mksyntax mknodes mksignames
+gen-h-files := arith.h builtins.h nodes.h syntax.h token.h
+
+static-y := sh
+
+# The shared binary
+shared-y    := sh.shared
+sh.shared-y := $(sh-y)
+
+# For cleaning
+targets := sh sh.g sh.shared sh.shared.g $(gen-o-files)
+
+# explicit dependency for all generated files
+$(addprefix $(obj)/, $(sh-y)): $(addprefix $(obj)/, $(gen-h-files))
+
+# Generate token.h
+targets += token.h
+quiet_cmd_mktokens = GEN     $@
+      cmd_mktokens = sh $< > $@
+$(obj)/token.h: $(src)/mktokens
+	$(call if_changed,mktokens)
+
+# Generate builtins.def
+targets += builtins.def
+quiet_cmd_mkbuiltins_def = GEN     $@
+      cmd_mkbuiltins_def = $(HOSTCC) $(hostc_flags) -x c -E -o $@ $<
+$(obj)/builtins.def: $(src)/builtins.def.in $(src)/config.h
+	$(call if_changed,mkbuiltins_def)
+
+# Generate builtins{.c + .h}
+targets += builtins.c builtins.h
+quiet_cmd_mkbuiltins = GEN     $@
+      cmd_mkbuiltins = mkdir -p $(obj)/bltin && cd $(obj) && \
+                       sh $(srctree)/$(src)/mkbuiltins builtins.def
+$(obj)/builtins.c: $(src)/mkbuiltins $(obj)/builtins.def
+	$(call cmd,mkbuiltins)
+
+# side effect..
+$(obj)/builtins.h: $(obj)/builtins.c
+	$(Q):
+
+# Generate init.c
+targets += init.c
+init-c-files := $(addprefix $(srctree)/$(src)/, $(init-o-files:.o=.c))
+quiet_cmd_mkinit = GEN     $@
+      cmd_mkinit = cd $(obj) && ./mkinit $(init-c-files)
+$(obj)/init.c: $(obj)/mkinit $(init-c-files)
+	$(call cmd,mkinit)
+
+# Generate nodes{.c + .h}
+targets += nodes.c nodes.h
+quiet_cmd_mknodes = GEN     $@
+      cmd_mknodes = cd $(obj) && ./mknodes $(srctree)/$(src)/nodetypes \
+			       $(srctree)/$(src)/nodes.c.pat
+$(obj)/nodes.c: $(obj)/mknodes $(src)/nodetypes $(src)/nodes.c.pat
+	$(call cmd,mknodes)
+
+# side effect..
+$(obj)/nodes.h: $(obj)/nodes.c
+	$(Q):
+
+# Generate syntax{.c + .h}
+targets += syntax.c syntax.h
+quiet_cmd_mksyntax = GEN     $@
+      cmd_mksyntax = cd $(obj) && ./mksyntax
+$(obj)/syntax.c: $(obj)/mksyntax
+	$(call cmd,mksyntax)
+
+# side effect..
+$(obj)/syntax.h: $(obj)/syntax.c
+	$(Q):
+
+# Generate arith parser - arith{.c + .h}
+targets += arith.c arith.h
+# Prefer bison, but BSD yacc should work as well
+YACC ?= bison
+
+quiet_cmd_yacc	= YACC    $@
+      cmd_yacc = $(YACC) -d -o $(@:.h=.c) $<
+
+$(obj)/arith.h: $(src)/arith.y
+	$(call if_changed,yacc)
+
+# side effect..
+$(obj)/arith.c: $(obj)/arith.h
+	$(Q):
+
+# Targets to install
+install-y := sh.shared
diff --git a/usr/dash/README.klibc b/usr/dash/README.klibc
new file mode 100644
index 0000000..0394fb0
--- /dev/null
+++ b/usr/dash/README.klibc
@@ -0,0 +1,7 @@
+This version of dash was obtained from
+
+http://gondor.apana.org.au/~herbert/dash/dash.git/
+
+It corresponds to changeset 3c98399cdf8d376b2c1ebd9cd32ca5d8c84f3ac9.
+
+The only changes made are the addition of config.h and a new Makefile.
diff --git a/usr/dash/TOUR b/usr/dash/TOUR
new file mode 100644
index 0000000..0c60e2a
--- /dev/null
+++ b/usr/dash/TOUR
@@ -0,0 +1,356 @@
+#	@(#)TOUR	8.1 (Berkeley) 5/31/93
+
+NOTE -- This is the original TOUR paper distributed with ash and
+does not represent the current state of the shell.  It is provided anyway
+since it provides helpful information for how the shell is structured,
+but be warned that things have changed -- the current shell is
+still under development.
+
+================================================================
+
+                       A Tour through Ash
+
+               Copyright 1989 by Kenneth Almquist.
+
+
+DIRECTORIES:  The subdirectory bltin contains commands which can
+be compiled stand-alone.  The rest of the source is in the main
+ash directory.
+
+SOURCE CODE GENERATORS:  Files whose names begin with "mk" are
+programs that generate source code.  A complete list of these
+programs is:
+
+        program         intput files        generates
+        -------         ------------        ---------
+        mkbuiltins      builtins            builtins.h builtins.c
+        mkinit          *.c                 init.c
+        mknodes         nodetypes           nodes.h nodes.c
+        mksignames          -               signames.h signames.c
+        mksyntax            -               syntax.h syntax.c
+        mktokens            -               token.h
+        bltin/mkexpr    unary_op binary_op  operators.h operators.c
+
+There are undoubtedly too many of these.  Mkinit searches all the
+C source files for entries looking like:
+
+        INIT {
+              x = 1;    /* executed during initialization */
+        }
+
+        RESET {
+              x = 2;    /* executed when the shell does a longjmp
+                           back to the main command loop */
+        }
+
+        SHELLPROC {
+              x = 3;    /* executed when the shell runs a shell procedure */
+        }
+
+It pulls this code out into routines which are when particular
+events occur.  The intent is to improve modularity by isolating
+the information about which modules need to be explicitly
+initialized/reset within the modules themselves.
+
+Mkinit recognizes several constructs for placing declarations in
+the init.c file.
+        INCLUDE "file.h"
+includes a file.  The storage class MKINIT makes a declaration
+available in the init.c file, for example:
+        MKINIT int funcnest;    /* depth of function calls */
+MKINIT alone on a line introduces a structure or union declara-
+tion:
+        MKINIT
+        struct redirtab {
+              short renamed[10];
+        };
+Preprocessor #define statements are copied to init.c without any
+special action to request this.
+
+INDENTATION:  The ash source is indented in multiples of six
+spaces.  The only study that I have heard of on the subject con-
+cluded that the optimal amount to indent is in the range of four
+to six spaces.  I use six spaces since it is not too big a jump
+from the widely used eight spaces.  If you really hate six space
+indentation, use the adjind (source included) program to change
+it to something else.
+
+EXCEPTIONS:  Code for dealing with exceptions appears in
+exceptions.c.  The C language doesn't include exception handling,
+so I implement it using setjmp and longjmp.  The global variable
+exception contains the type of exception.  EXERROR is raised by
+calling error.  EXINT is an interrupt.  EXSHELLPROC is an excep-
+tion which is raised when a shell procedure is invoked.  The pur-
+pose of EXSHELLPROC is to perform the cleanup actions associated
+with other exceptions.  After these cleanup actions, the shell
+can interpret a shell procedure itself without exec'ing a new
+copy of the shell.
+
+INTERRUPTS:  In an interactive shell, an interrupt will cause an
+EXINT exception to return to the main command loop.  (Exception:
+EXINT is not raised if the user traps interrupts using the trap
+command.)  The INTOFF and INTON macros (defined in exception.h)
+provide uninterruptable critical sections.  Between the execution
+of INTOFF and the execution of INTON, interrupt signals will be
+held for later delivery.  INTOFF and INTON can be nested.
+
+MEMALLOC.C:  Memalloc.c defines versions of malloc and realloc
+which call error when there is no memory left.  It also defines a
+stack oriented memory allocation scheme.  Allocating off a stack
+is probably more efficient than allocation using malloc, but the
+big advantage is that when an exception occurs all we have to do
+to free up the memory in use at the time of the exception is to
+restore the stack pointer.  The stack is implemented using a
+linked list of blocks.
+
+STPUTC:  If the stack were contiguous, it would be easy to store
+strings on the stack without knowing in advance how long the
+string was going to be:
+        p = stackptr;
+        *p++ = c;       /* repeated as many times as needed */
+        stackptr = p;
+The folloing three macros (defined in memalloc.h) perform these
+operations, but grow the stack if you run off the end:
+        STARTSTACKSTR(p);
+        STPUTC(c, p);   /* repeated as many times as needed */
+        grabstackstr(p);
+
+We now start a top-down look at the code:
+
+MAIN.C:  The main routine performs some initialization, executes
+the user's profile if necessary, and calls cmdloop.  Cmdloop is
+repeatedly parses and executes commands.
+
+OPTIONS.C:  This file contains the option processing code.  It is
+called from main to parse the shell arguments when the shell is
+invoked, and it also contains the set builtin.  The -i and -j op-
+tions (the latter turns on job control) require changes in signal
+handling.  The routines setjobctl (in jobs.c) and setinteractive
+(in trap.c) are called to handle changes to these options.
+
+PARSING:  The parser code is all in parser.c.  A recursive des-
+cent parser is used.  Syntax tables (generated by mksyntax) are
+used to classify characters during lexical analysis.  There are
+three tables:  one for normal use, one for use when inside single
+quotes, and one for use when inside double quotes.  The tables
+are machine dependent because they are indexed by character vari-
+ables and the range of a char varies from machine to machine.
+
+PARSE OUTPUT:  The output of the parser consists of a tree of
+nodes.  The various types of nodes are defined in the file node-
+types.
+
+Nodes of type NARG are used to represent both words and the con-
+tents of here documents.  An early version of ash kept the con-
+tents of here documents in temporary files, but keeping here do-
+cuments in memory typically results in significantly better per-
+formance.  It would have been nice to make it an option to use
+temporary files for here documents, for the benefit of small
+machines, but the code to keep track of when to delete the tem-
+porary files was complex and I never fixed all the bugs in it.
+(AT&T has been maintaining the Bourne shell for more than ten
+years, and to the best of my knowledge they still haven't gotten
+it to handle temporary files correctly in obscure cases.)
+
+The text field of a NARG structure points to the text of the
+word.  The text consists of ordinary characters and a number of
+special codes defined in parser.h.  The special codes are:
+
+        CTLVAR              Variable substitution
+        CTLENDVAR           End of variable substitution
+        CTLBACKQ            Command substitution
+        CTLBACKQ|CTLQUOTE   Command substitution inside double quotes
+        CTLESC              Escape next character
+
+A variable substitution contains the following elements:
+
+        CTLVAR type name '=' [ alternative-text CTLENDVAR ]
+
+The type field is a single character specifying the type of sub-
+stitution.  The possible types are:
+
+        VSNORMAL            $var
+        VSMINUS             ${var-text}
+        VSMINUS|VSNUL       ${var:-text}
+        VSPLUS              ${var+text}
+        VSPLUS|VSNUL        ${var:+text}
+        VSQUESTION          ${var?text}
+        VSQUESTION|VSNUL    ${var:?text}
+        VSASSIGN            ${var=text}
+        VSASSIGN|VSNUL      ${var=text}
+
+In addition, the type field will have the VSQUOTE flag set if the
+variable is enclosed in double quotes.  The name of the variable
+comes next, terminated by an equals sign.  If the type is not
+VSNORMAL, then the text field in the substitution follows, ter-
+minated by a CTLENDVAR byte.
+
+Commands in back quotes are parsed and stored in a linked list.
+The locations of these commands in the string are indicated by
+CTLBACKQ and CTLBACKQ+CTLQUOTE characters, depending upon whether
+the back quotes were enclosed in double quotes.
+
+The character CTLESC escapes the next character, so that in case
+any of the CTL characters mentioned above appear in the input,
+they can be passed through transparently.  CTLESC is also used to
+escape '*', '?', '[', and '!' characters which were quoted by the
+user and thus should not be used for file name generation.
+
+CTLESC characters have proved to be particularly tricky to get
+right.  In the case of here documents which are not subject to
+variable and command substitution, the parser doesn't insert any
+CTLESC characters to begin with (so the contents of the text
+field can be written without any processing).  Other here docu-
+ments, and words which are not subject to splitting and file name
+generation, have the CTLESC characters removed during the vari-
+able and command substitution phase.  Words which are subject
+splitting and file name generation have the CTLESC characters re-
+moved as part of the file name phase.
+
+EXECUTION:  Command execution is handled by the following files:
+        eval.c     The top level routines.
+        redir.c    Code to handle redirection of input and output.
+        jobs.c     Code to handle forking, waiting, and job control.
+        exec.c     Code to to path searches and the actual exec sys call.
+        expand.c   Code to evaluate arguments.
+        var.c      Maintains the variable symbol table.  Called from expand.c.
+
+EVAL.C:  Evaltree recursively executes a parse tree.  The exit
+status is returned in the global variable exitstatus.  The alter-
+native entry evalbackcmd is called to evaluate commands in back
+quotes.  It saves the result in memory if the command is a buil-
+tin; otherwise it forks off a child to execute the command and
+connects the standard output of the child to a pipe.
+
+JOBS.C:  To create a process, you call makejob to return a job
+structure, and then call forkshell (passing the job structure as
+an argument) to create the process.  Waitforjob waits for a job
+to complete.  These routines take care of process groups if job
+control is defined.
+
+REDIR.C:  Ash allows file descriptors to be redirected and then
+restored without forking off a child process.  This is accom-
+plished by duplicating the original file descriptors.  The redir-
+tab structure records where the file descriptors have be dupli-
+cated to.
+
+EXEC.C:  The routine find_command locates a command, and enters
+the command in the hash table if it is not already there.  The
+third argument specifies whether it is to print an error message
+if the command is not found.  (When a pipeline is set up,
+find_command is called for all the commands in the pipeline be-
+fore any forking is done, so to get the commands into the hash
+table of the parent process.  But to make command hashing as
+transparent as possible, we silently ignore errors at that point
+and only print error messages if the command cannot be found
+later.)
+
+The routine shellexec is the interface to the exec system call.
+
+EXPAND.C:  Arguments are processed in three passes.  The first
+(performed by the routine argstr) performs variable and command
+substitution.  The second (ifsbreakup) performs word splitting
+and the third (expandmeta) performs file name generation.  If the
+"/u" directory is simulated, then when "/u/username" is replaced
+by the user's home directory, the flag "didudir" is set.  This
+tells the cd command that it should print out the directory name,
+just as it would if the "/u" directory were implemented using
+symbolic links.
+
+VAR.C:  Variables are stored in a hash table.  Probably we should
+switch to extensible hashing.  The variable name is stored in the
+same string as the value (using the format "name=value") so that
+no string copying is needed to create the environment of a com-
+mand.  Variables which the shell references internally are preal-
+located so that the shell can reference the values of these vari-
+ables without doing a lookup.
+
+When a program is run, the code in eval.c sticks any environment
+variables which precede the command (as in "PATH=xxx command") in
+the variable table as the simplest way to strip duplicates, and
+then calls "environment" to get the value of the environment.
+There are two consequences of this.  First, if an assignment to
+PATH precedes the command, the value of PATH before the assign-
+ment must be remembered and passed to shellexec.  Second, if the
+program turns out to be a shell procedure, the strings from the
+environment variables which preceded the command must be pulled
+out of the table and replaced with strings obtained from malloc,
+since the former will automatically be freed when the stack (see
+the entry on memalloc.c) is emptied.
+
+BUILTIN COMMANDS:  The procedures for handling these are scat-
+tered throughout the code, depending on which location appears
+most appropriate.  They can be recognized because their names al-
+ways end in "cmd".  The mapping from names to procedures is
+specified in the file builtins, which is processed by the mkbuil-
+tins command.
+
+A builtin command is invoked with argc and argv set up like a
+normal program.  A builtin command is allowed to overwrite its
+arguments.  Builtin routines can call nextopt to do option pars-
+ing.  This is kind of like getopt, but you don't pass argc and
+argv to it.  Builtin routines can also call error.  This routine
+normally terminates the shell (or returns to the main command
+loop if the shell is interactive), but when called from a builtin
+command it causes the builtin command to terminate with an exit
+status of 2.
+
+The directory bltins contains commands which can be compiled in-
+dependently but can also be built into the shell for efficiency
+reasons.  The makefile in this directory compiles these programs
+in the normal fashion (so that they can be run regardless of
+whether the invoker is ash), but also creates a library named
+bltinlib.a which can be linked with ash.  The header file bltin.h
+takes care of most of the differences between the ash and the
+stand-alone environment.  The user should call the main routine
+"main", and #define main to be the name of the routine to use
+when the program is linked into ash.  This #define should appear
+before bltin.h is included; bltin.h will #undef main if the pro-
+gram is to be compiled stand-alone.
+
+CD.C:  This file defines the cd and pwd builtins.  The pwd com-
+mand runs /bin/pwd the first time it is invoked (unless the user
+has already done a cd to an absolute pathname), but then
+remembers the current directory and updates it when the cd com-
+mand is run, so subsequent pwd commands run very fast.  The main
+complication in the cd command is in the docd command, which
+resolves symbolic links into actual names and informs the user
+where the user ended up if he crossed a symbolic link.
+
+SIGNALS:  Trap.c implements the trap command.  The routine set-
+signal figures out what action should be taken when a signal is
+received and invokes the signal system call to set the signal ac-
+tion appropriately.  When a signal that a user has set a trap for
+is caught, the routine "onsig" sets a flag.  The routine dotrap
+is called at appropriate points to actually handle the signal.
+When an interrupt is caught and no trap has been set for that
+signal, the routine "onint" in error.c is called.
+
+OUTPUT:  Ash uses it's own output routines.  There are three out-
+put structures allocated.  "Output" represents the standard out-
+put, "errout" the standard error, and "memout" contains output
+which is to be stored in memory.  This last is used when a buil-
+tin command appears in backquotes, to allow its output to be col-
+lected without doing any I/O through the UNIX operating system.
+The variables out1 and out2 normally point to output and errout,
+respectively, but they are set to point to memout when appropri-
+ate inside backquotes.
+
+INPUT:  The basic input routine is pgetc, which reads from the
+current input file.  There is a stack of input files; the current
+input file is the top file on this stack.  The code allows the
+input to come from a string rather than a file.  (This is for the
+-c option and the "." and eval builtin commands.)  The global
+variable plinno is saved and restored when files are pushed and
+popped from the stack.  The parser routines store the number of
+the current line in this variable.
+
+DEBUGGING:  If DEBUG is defined in shell.h, then the shell will
+write debugging information to the file $HOME/trace.  Most of
+this is done using the TRACE macro, which takes a set of printf
+arguments inside two sets of parenthesis.  Example:
+"TRACE(("n=%d0, n))".  The double parenthesis are necessary be-
+cause the preprocessor can't handle functions with a variable
+number of arguments.  Defining DEBUG also causes the shell to
+generate a core dump if it is sent a quit signal.  The tracing
+code is in show.c.
diff --git a/usr/dash/alias.c b/usr/dash/alias.c
new file mode 100644
index 0000000..daeacbb
--- /dev/null
+++ b/usr/dash/alias.c
@@ -0,0 +1,227 @@
+/*-
+ * Copyright (c) 1993
+ *	The Regents of the University of California.  All rights reserved.
+ * Copyright (c) 1997-2005
+ *	Herbert Xu <herbert@gondor.apana.org.au>.  All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Kenneth Almquist.
+ *
+ * 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. 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 <stdlib.h>
+#include "shell.h"
+#include "input.h"
+#include "output.h"
+#include "error.h"
+#include "memalloc.h"
+#include "mystring.h"
+#include "alias.h"
+#include "options.h"	/* XXX for argptr (should remove?) */
+
+#define ATABSIZE 39
+
+struct alias *atab[ATABSIZE];
+
+STATIC void setalias(const char *, const char *);
+STATIC struct alias *freealias(struct alias *);
+STATIC struct alias **__lookupalias(const char *);
+
+STATIC
+void
+setalias(const char *name, const char *val)
+{
+	struct alias *ap, **app;
+
+	app = __lookupalias(name);
+	ap = *app;
+	INTOFF;
+	if (ap) {
+		if (!(ap->flag & ALIASINUSE)) {
+			ckfree(ap->val);
+		}
+		ap->val	= savestr(val);
+		ap->flag &= ~ALIASDEAD;
+	} else {
+		/* not found */
+		ap = ckmalloc(sizeof (struct alias));
+		ap->name = savestr(name);
+		ap->val = savestr(val);
+		ap->flag = 0;
+		ap->next = 0;
+		*app = ap;
+	}
+	INTON;
+}
+
+int
+unalias(const char *name)
+{
+	struct alias **app;
+
+	app = __lookupalias(name);
+
+	if (*app) {
+		INTOFF;
+		*app = freealias(*app);
+		INTON;
+		return (0);
+	}
+
+	return (1);
+}
+
+void
+rmaliases(void)
+{
+	struct alias *ap, **app;
+	int i;
+
+	INTOFF;
+	for (i = 0; i < ATABSIZE; i++) {
+		app = &atab[i];
+		for (ap = *app; ap; ap = *app) {
+			*app = freealias(*app);
+			if (ap == *app) {
+				app = &ap->next;
+			}
+		}
+	}
+	INTON;
+}
+
+struct alias *
+lookupalias(const char *name, int check)
+{
+	struct alias *ap = *__lookupalias(name);
+
+	if (check && ap && (ap->flag & ALIASINUSE))
+		return (NULL);
+	return (ap);
+}
+
+/*
+ * TODO - sort output
+ */
+int
+aliascmd(int argc, char **argv)
+{
+	char *n, *v;
+	int ret = 0;
+	struct alias *ap;
+
+	if (argc == 1) {
+		int i;
+
+		for (i = 0; i < ATABSIZE; i++)
+			for (ap = atab[i]; ap; ap = ap->next) {
+				printalias(ap);
+			}
+		return (0);
+	}
+	while ((n = *++argv) != NULL) {
+		if ((v = strchr(n+1, '=')) == NULL) { /* n+1: funny ksh stuff */
+			if ((ap = *__lookupalias(n)) == NULL) {
+				outfmt(out2, "%s: %s not found\n", "alias", n);
+				ret = 1;
+			} else
+				printalias(ap);
+		} else {
+			*v++ = '\0';
+			setalias(n, v);
+		}
+	}
+
+	return (ret);
+}
+
+int
+unaliascmd(int argc, char **argv)
+{
+	int i;
+
+	while ((i = nextopt("a")) != '\0') {
+		if (i == 'a') {
+			rmaliases();
+			return (0);
+		}
+	}
+	for (i = 0; *argptr; argptr++) {
+		if (unalias(*argptr)) {
+			outfmt(out2, "%s: %s not found\n", "unalias", *argptr);
+			i = 1;
+		}
+	}
+
+	return (i);
+}
+
+STATIC struct alias *
+freealias(struct alias *ap) {
+	struct alias *next;
+
+	if (ap->flag & ALIASINUSE) {
+		ap->flag |= ALIASDEAD;
+		return ap;
+	}
+
+	next = ap->next;
+	ckfree(ap->name);
+	ckfree(ap->val);
+	ckfree(ap);
+	return next;
+}
+
+void
+printalias(const struct alias *ap) {
+	out1fmt("%s=%s\n", ap->name, single_quote(ap->val));
+}
+
+STATIC struct alias **
+__lookupalias(const char *name) {
+	unsigned int hashval;
+	struct alias **app;
+	const char *p;
+	unsigned int ch;
+
+	p = name;
+
+	ch = (unsigned char)*p;
+	hashval = ch << 4;
+	while (ch) {
+		hashval += ch;
+		ch = (unsigned char)*++p;
+	}
+	app = &atab[hashval % ATABSIZE];
+
+	for (; *app; app = &(*app)->next) {
+		if (equal(name, (*app)->name)) {
+			break;
+		}
+	}
+
+	return app;
+}
diff --git a/usr/dash/alias.h b/usr/dash/alias.h
new file mode 100644
index 0000000..fb841d6
--- /dev/null
+++ b/usr/dash/alias.h
@@ -0,0 +1,52 @@
+/*-
+ * Copyright (c) 1993
+ *	The Regents of the University of California.  All rights reserved.
+ * Copyright (c) 1997-2005
+ *	Herbert Xu <herbert@gondor.apana.org.au>.  All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Kenneth Almquist.
+ *
+ * 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. 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.
+ *
+ *	@(#)alias.h	8.2 (Berkeley) 5/4/95
+ */
+
+#define ALIASINUSE	1
+#define ALIASDEAD	2
+
+struct alias {
+	struct alias *next;
+	char *name;
+	char *val;
+	int flag;
+};
+
+struct alias *lookupalias(const char *, int);
+int aliascmd(int, char **);
+int unaliascmd(int, char **);
+void rmaliases(void);
+int unalias(const char *);
+void printalias(const struct alias *);
diff --git a/usr/dash/arith.y b/usr/dash/arith.y
new file mode 100644
index 0000000..07b0b39
--- /dev/null
+++ b/usr/dash/arith.y
@@ -0,0 +1,155 @@
+%{
+/*-
+ * Copyright (c) 1993
+ *	The Regents of the University of California.  All rights reserved.
+ * Copyright (c) 1997-2005
+ *	Herbert Xu <herbert@gondor.apana.org.au>.  All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Kenneth Almquist.
+ *
+ * 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. 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 <stdlib.h>
+#include "expand.h"
+#include "shell.h"
+#include "error.h"
+#include "output.h"
+#include "memalloc.h"
+
+const char *arith_buf, *arith_startbuf;
+
+#ifndef YYBISON
+int yyparse(void);
+#endif
+void yyerror(const char *);
+#ifdef TESTARITH
+int main(int , char *[]);
+int sh_error(char *);
+#endif
+
+%}
+%token ARITH_NUM ARITH_LPAREN ARITH_RPAREN
+
+%left ARITH_OR
+%left ARITH_AND
+%left ARITH_BOR
+%left ARITH_BXOR
+%left ARITH_BAND
+%left ARITH_EQ ARITH_NE
+%left ARITH_LT ARITH_GT ARITH_GE ARITH_LE
+%left ARITH_LSHIFT ARITH_RSHIFT
+%left ARITH_ADD ARITH_SUB
+%left ARITH_MUL ARITH_DIV ARITH_REM
+%left ARITH_UNARYMINUS ARITH_UNARYPLUS ARITH_NOT ARITH_BNOT
+%%
+
+exp:	expr {
+			return ($1);
+	}
+	;
+
+
+expr:	ARITH_LPAREN expr ARITH_RPAREN { $$ = $2; }
+	| expr ARITH_OR expr	{ $$ = $1 || $3; }
+	| expr ARITH_AND expr	{ $$ = $1 && $3; }
+	| expr ARITH_BOR expr	{ $$ = $1 | $3; }
+	| expr ARITH_BXOR expr	{ $$ = $1 ^ $3; }
+	| expr ARITH_BAND expr	{ $$ = $1 & $3; }
+	| expr ARITH_EQ expr	{ $$ = $1 == $3; }
+	| expr ARITH_GT expr	{ $$ = $1 > $3; }
+	| expr ARITH_GE expr	{ $$ = $1 >= $3; }
+	| expr ARITH_LT expr	{ $$ = $1 < $3; }
+	| expr ARITH_LE expr	{ $$ = $1 <= $3; }
+	| expr ARITH_NE expr	{ $$ = $1 != $3; }
+	| expr ARITH_LSHIFT expr { $$ = $1 << $3; }
+	| expr ARITH_RSHIFT expr { $$ = $1 >> $3; }
+	| expr ARITH_ADD expr	{ $$ = $1 + $3; }
+	| expr ARITH_SUB expr	{ $$ = $1 - $3; }
+	| expr ARITH_MUL expr	{ $$ = $1 * $3; }
+	| expr ARITH_DIV expr	{
+			if ($3 == 0)
+				yyerror("division by zero");
+			$$ = $1 / $3;
+		}
+	| expr ARITH_REM expr   {
+			if ($3 == 0)
+				yyerror("division by zero");
+			$$ = $1 % $3;
+		}
+	| ARITH_NOT expr	{ $$ = !($2); }
+	| ARITH_BNOT expr	{ $$ = ~($2); }
+	| ARITH_SUB expr %prec ARITH_UNARYMINUS { $$ = -($2); }
+	| ARITH_ADD expr %prec ARITH_UNARYPLUS { $$ = $2; }
+	| ARITH_NUM
+	;
+%%
+int
+arith(s)
+	const char *s;
+{
+	long result;
+
+	arith_buf = arith_startbuf = s;
+
+	INTOFF;
+	result = yyparse();
+	arith_lex_reset();	/* reprime lex */
+	INTON;
+
+	return (result);
+}
+
+
+/*************************/
+#ifdef TEST_ARITH
+#include <stdio.h>
+main(argc, argv)
+	char *argv[];
+{
+	printf("%d\n", exp(argv[1]));
+}
+sh_error(s)
+	char *s;
+{
+	fprintf(stderr, "exp: %s\n", s);
+	exit(1);
+}
+#endif
+
+void
+yyerror(s)
+	const char *s;
+{
+
+#ifndef YYBISON
+	yyerrok;
+#endif
+	yyclearin;
+	arith_lex_reset();	/* reprime lex */
+	sh_error("arithmetic expression: %s: \"%s\"", s, arith_startbuf);
+	/* NOTREACHED */
+}
diff --git a/usr/dash/arith_yylex.c b/usr/dash/arith_yylex.c
new file mode 100644
index 0000000..4fa2051
--- /dev/null
+++ b/usr/dash/arith_yylex.c
@@ -0,0 +1,163 @@
+/*-
+ * Copyright (c) 2002
+ *	Herbert Xu.
+ * Copyright (c) 1993
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Kenneth Almquist.
+ *
+ * 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. 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 <stdlib.h>
+#include "arith.h"
+#include "expand.h"
+#include "error.h"
+
+extern int yylval;
+extern const char *arith_buf, *arith_startbuf;
+
+int
+yylex()
+{
+	int value;
+	const char *buf = arith_buf;
+
+	for (;;) {
+		switch (*buf) {
+		case ' ':
+		case '\t':
+		case '\n':
+			buf++;
+			continue;
+		default:
+err:
+			sh_error("arith: syntax error: \"%s\"", arith_startbuf);
+			/* NOTREACHED */
+		case '0':
+		case '1':
+		case '2':
+		case '3':
+		case '4':
+		case '5':
+		case '6':
+		case '7':
+		case '8':
+		case '9':
+			yylval = strtoll(buf, (char **) &arith_buf, 0);
+			return ARITH_NUM;
+		case '=':
+			if (*++buf != '=') {
+				goto err;
+			}
+			value = ARITH_EQ;
+			break;
+		case '>':
+			switch (*++buf) {
+			case '=':
+				value = ARITH_GE;
+				break;
+			case '>':
+				value = ARITH_RSHIFT;
+				break;
+			default:
+				value = ARITH_GT;
+				goto out;
+			}
+			break;
+		case '<':
+			switch (*++buf) {
+			case '=':
+				value = ARITH_LE;
+				break;
+			case '<':
+				value = ARITH_LSHIFT;
+				break;
+			default:
+				value = ARITH_LT;
+				goto out;
+			}
+			break;
+		case '|':
+			if (*++buf != '|') {
+				value = ARITH_BOR;
+				goto out;
+			}
+			value = ARITH_OR;
+			break;
+		case '&':
+			if (*++buf != '&') {
+				value = ARITH_BAND;
+				goto out;
+			}
+			value = ARITH_AND;
+			break;
+		case '!':
+			if (*++buf != '=') {
+				value = ARITH_NOT;
+				goto out;
+			}
+			value = ARITH_NE;
+			break;
+		case 0:
+			value = 0;
+			goto out;
+		case '(':
+			value = ARITH_LPAREN;
+			break;
+		case ')':
+			value = ARITH_RPAREN;
+			break;
+		case '*':
+			value = ARITH_MUL;
+			break;
+		case '/':
+			value = ARITH_DIV;
+			break;
+		case '%':
+			value = ARITH_REM;
+			break;
+		case '+':
+			value = ARITH_ADD;
+			break;
+		case '-':
+			value = ARITH_SUB;
+			break;
+		case '~':
+			value = ARITH_BNOT;
+			break;
+		case '^':
+			value = ARITH_BXOR;
+			break;
+		}
+		break;
+	}
+
+	buf++;
+out:
+	arith_buf = buf;
+	return value;
+}
diff --git a/usr/dash/bltin/bltin.h b/usr/dash/bltin/bltin.h
new file mode 100644
index 0000000..f5ac06f
--- /dev/null
+++ b/usr/dash/bltin/bltin.h
@@ -0,0 +1,89 @@
+/*-
+ * Copyright (c) 1991, 1993
+ *	The Regents of the University of California.  All rights reserved.
+ * Copyright (c) 1997-2005
+ *	Herbert Xu <herbert@gondor.apana.org.au>.  All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Kenneth Almquist.
+ *
+ * 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. 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.
+ *
+ *	@(#)bltin.h	8.1 (Berkeley) 5/31/93
+ */
+
+/*
+ * This file is included by programs which are optionally built into the
+ * shell.  If SHELL is defined, we try to map the standard UNIX library
+ * routines to ash routines using defines.
+ */
+
+#include "../shell.h"
+#include "../mystring.h"
+#include "../options.h"
+#ifdef SHELL
+#include "../memalloc.h"
+#include "../output.h"
+#include "../error.h"
+#ifndef USE_GLIBC_STDIO
+#undef stdout
+#undef stderr
+#undef putc
+#undef putchar
+#undef fileno
+#define stdout out1
+#define stderr out2
+#define printf out1fmt
+#define putc(c, file)	outc(c, file)
+#define putchar(c)	out1c(c)
+#define FILE struct output
+#define fprintf outfmt
+#define fputs outstr
+#define fflush flushout
+#define fileno(f) ((f)->fd)
+#define ferror outerr
+#endif
+#define INITARGS(argv)
+#define	error sh_error
+#define	warn sh_warn
+#define	warnx sh_warnx
+#define exit sh_exit
+#define setprogname(s)
+#define getprogname() commandname
+#define setlocate(l,s) 0
+
+#define getenv(p) bltinlookup((p),0)
+
+#else
+#undef NULL
+#include <stdio.h>
+#undef main
+#define INITARGS(argv)	if ((commandname = argv[0]) == NULL) {fputs("Argc is zero\n", stderr); exit(2);} else
+#endif
+
+int echocmd(int, char **);
+
+
+extern const char *commandname;
diff --git a/usr/dash/bltin/echo.1 b/usr/dash/bltin/echo.1
new file mode 100644
index 0000000..fbc7fb4
--- /dev/null
+++ b/usr/dash/bltin/echo.1
@@ -0,0 +1,109 @@
+.\" Copyright (c) 1991, 1993
+.\"	The Regents of the University of California.  All rights reserved.
+.\" Copyright (c) 1997-2005
+.\"	Herbert Xu <herbert@gondor.apana.org.au>.  All rights reserved.
+.\"
+.\" This code is derived from software contributed to Berkeley by
+.\" Kenneth Almquist.
+.\" Copyright 1989 by Kenneth Almquist
+.\"
+.\" 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. 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.
+.\"
+.\"	@(#)echo.1	8.1 (Berkeley) 5/31/93
+.\"
+.Dd May 31, 1993
+.Dt ECHO 1
+.Os
+.Sh NAME
+.Nm echo
+.Nd produce message in a shell script
+.Sh SYNOPSIS
+.Nm
+.Op Fl n | Fl e
+.Ar args ...
+.Sh DESCRIPTION
+.Nm
+prints its arguments on the standard output, separated by spaces.
+Unless the
+.Fl n
+option is present, a newline is output following the arguments.
+The
+.Fl e
+option causes
+.Nm
+to treat the escape sequences specially, as described in the following
+paragraph.
+The
+.Fl e
+option is the default, and is provided solely for compatibility with
+other systems.
+Only one of the options
+.Fl n
+and
+.Fl e
+may be given.
+.Pp
+If any of the following sequences of characters is encountered during
+output, the sequence is not output.  Instead, the specified action is
+performed:
+.Bl -tag -width indent
+.It Li \eb
+A backspace character is output.
+.It Li \ec
+Subsequent output is suppressed.  This is normally used at the end of the
+last argument to suppress the trailing newline that
+.Nm
+would otherwise output.
+.It Li \ef
+Output a form feed.
+.It Li \en
+Output a newline character.
+.It Li \er
+Output a carriage return.
+.It Li \et
+Output a (horizontal) tab character.
+.It Li \ev
+Output a vertical tab.
+.It Li \e0 Ns Ar digits
+Output the character whose value is given by zero to three digits.
+If there are zero digits, a nul character is output.
+.It Li \e\e
+Output a backslash.
+.El
+.Sh HINTS
+Remember that backslash is special to the shell and needs to be escaped.
+To output a message to standard error, say
+.Pp
+.D1  echo message \*[Gt]\*[Am]2
+.Sh BUGS
+The octal character escape mechanism
+.Pq Li \e0 Ns Ar digits
+differs from the
+C language mechanism.
+.Pp
+There is no way to force
+.Nm
+to treat its arguments literally, rather than interpreting them as
+options and escape sequences.
diff --git a/usr/dash/bltin/printf.1 b/usr/dash/bltin/printf.1
new file mode 100644
index 0000000..b1265a5
--- /dev/null
+++ b/usr/dash/bltin/printf.1
@@ -0,0 +1,354 @@
+.\" Copyright (c) 1989, 1990, 1993
+.\"	The Regents of the University of California.  All rights reserved.
+.\" Copyright (c) 1997-2005
+.\"	Herbert Xu <herbert@gondor.apana.org.au>.  All rights reserved.
+.\"
+.\" This code is derived from software contributed to Berkeley by
+.\" the Institute of Electrical and Electronics Engineers, Inc.
+.\"
+.\" 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. 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.
+.\"
+.\"	from: @(#)printf.1	8.1 (Berkeley) 6/6/93
+.\"
+.Dd November 5, 1993
+.Dt PRINTF 1
+.Os
+.Sh NAME
+.Nm printf
+.Nd formatted output
+.Sh SYNOPSIS
+.Nm
+.Ar format
+.Op Ar arguments  ...
+.Sh DESCRIPTION
+.Nm
+formats and prints its arguments, after the first, under control
+of the
+.Ar format  .
+The
+.Ar format
+is a character string which contains three types of objects: plain characters,
+which are simply copied to standard output, character escape sequences which
+are converted and copied to the standard output, and format specifications,
+each of which causes printing of the next successive
+.Ar argument  .
+.Pp
+The
+.Ar arguments
+after the first are treated as strings if the corresponding format is
+either
+.Cm b ,
+.Cm B ,
+.Cm c
+or
+.Cm s ;
+otherwise it is evaluated as a C constant, with the following extensions:
+.Pp
+.Bl -bullet -offset indent -compact
+.It
+A leading plus or minus sign is allowed.
+.It
+If the leading character is a single or double quote, the value is the
+.Tn ASCII
+code of the next character.
+.El
+.Pp
+The format string is reused as often as necessary to satisfy the
+.Ar arguments  .
+Any extra format specifications are evaluated with zero or the null
+string.
+.Pp
+Character escape sequences are in backslash notation as defined in
+.St -ansiC .
+The characters and their meanings are as follows:
+.Bl -tag -width Ds -offset indent
+.It Cm \ee
+Write an \*[Lt]escape\*[Gt] character.
+.It Cm \ea
+Write a \*[Lt]bell\*[Gt] character.
+.It Cm \eb
+Write a \*[Lt]backspace\*[Gt] character.
+.It Cm \ef
+Write a \*[Lt]form-feed\*[Gt] character.
+.It Cm \en
+Write a \*[Lt]new-line\*[Gt] character.
+.It Cm \er
+Write a \*[Lt]carriage return\*[Gt] character.
+.It Cm \et
+Write a \*[Lt]tab\*[Gt] character.
+.It Cm \ev
+Write a \*[Lt]vertical tab\*[Gt] character.
+.It Cm \e\'
+Write a \*[Lt]single quote\*[Gt] character.
+.It Cm \e"
+Write a \*[Lt]double quote\*[Gt] character.
+.It Cm \e\e
+Write a backslash character.
+.It Cm \e Ns Ar num
+Write an 8\-bit character whose
+.Tn ASCII
+value is the 1\-, 2\-, or 3\-digit octal number
+.Ar num .
+.It Cm \ex Ns Ar xx
+Write an 8\-bit character whose
+.Tn ASCII
+value is the 1\- or 2\-digit hexadecimal number
+.Ar xx .
+.El
+.Pp
+Each format specification is introduced by the percent character
+(``%'').
+The remainder of the format specification includes,
+in the following order:
+.Bl -tag -width Ds
+.It "Zero or more of the following flags:"
+.Bl -tag -width Ds
+.It Cm #
+A `#' character
+specifying that the value should be printed in an ``alternative form''.
+For
+.Cm b ,
+.Cm c ,
+.Cm d ,
+and
+.Cm s
+formats, this option has no effect.
+For the
+.Cm o
+format the precision of the number is increased to force the first
+character of the output string to a zero.
+For the
+.Cm x
+.Pq Cm X
+format, a non-zero result has the string
+.Li 0x
+.Pq Li 0X
+prepended to it.
+For
+.Cm e  ,
+.Cm E ,
+.Cm f  ,
+.Cm g ,
+and
+.Cm G
+formats, the result will always contain a decimal point, even if no
+digits follow the point (normally, a decimal point only appears in the
+results of those formats if a digit follows the decimal point).
+For
+.Cm g
+and
+.Cm G
+formats, trailing zeros are not removed from the result as they
+would otherwise be.
+.\" I turned this off - decided it isn't a valid use of '#'
+.\" For the
+.\" .Cm B
+.\" format, backslash-escape sequences are expanded first;
+.It Cm \&\-
+A minus sign `\-' which specifies
+.Em left adjustment
+of the output in the indicated field;
+.It Cm \&+
+A `+' character specifying that there should always be
+a sign placed before the number when using signed formats.
+.It Sq \&\ \&
+A space specifying that a blank should be left before a positive number
+for a signed format.
+A `+' overrides a space if both are used;
+.It Cm \&0
+A zero `0' character indicating that zero-padding should be used
+rather than blank-padding.
+A `\-' overrides a `0' if both are used;
+.El
+.It "Field Width:"
+An optional digit string specifying a
+.Em field width ;
+if the output string has fewer characters than the field width it will
+be blank-padded on the left (or right, if the left-adjustment indicator
+has been given) to make up the field width (note that a leading zero
+is a flag, but an embedded zero is part of a field width);
+.It Precision :
+An optional period,
+.Sq Cm \&.\& ,
+followed by an optional digit string giving a
+.Em precision
+which specifies the number of digits to appear after the decimal point,
+for
+.Cm e
+and
+.Cm f
+formats, or the maximum number of characters to be printed
+from a string
+.Sm off
+.Pf ( Cm b No ,
+.Sm on
+.Cm B
+and
+.Cm s
+formats); if the digit string is missing, the precision is treated
+as zero;
+.It Format :
+A character which indicates the type of format to use (one of
+.Cm diouxXfwEgGbBcs ) .
+.El
+.Pp
+A field width or precision may be
+.Sq Cm \&*
+instead of a digit string.
+In this case an
+.Ar argument
+supplies the field width or precision.
+.Pp
+The format characters and their meanings are:
+.Bl -tag -width Fl
+.It Cm diouXx
+The
+.Ar argument
+is printed as a signed decimal (d or i), unsigned octal, unsigned decimal,
+or unsigned hexadecimal (X or x), respectively.
+.It Cm f
+The
+.Ar argument
+is printed in the style
+.Sm off
+.Pf [\-]ddd Cm \&. No ddd
+.Sm on
+where the number of d's
+after the decimal point is equal to the precision specification for
+the argument.
+If the precision is missing, 6 digits are given; if the precision
+is explicitly 0, no digits and no decimal point are printed.
+.It Cm eE
+The
+.Ar argument
+is printed in the style
+.Sm off
+.Pf [\-]d Cm \&. No ddd Cm e No \\*(Pmdd
+.Sm on
+where there
+is one digit before the decimal point and the number after is equal to
+the precision specification for the argument; when the precision is
+missing, 6 digits are produced.
+An upper-case E is used for an `E' format.
+.It Cm gG
+The
+.Ar argument
+is printed in style
+.Cm f
+or in style
+.Cm e
+.Pq Cm E
+whichever gives full precision in minimum space.
+.It Cm b
+Characters from the string
+.Ar argument
+are printed with backslash-escape sequences expanded.
+.br
+The following additional backslash-escape sequences are supported:
+.Bl -tag -width Ds
+.It Cm \ec
+Causes
+.Nm
+to ignore any remaining characters in the string operand containing it,
+any remaining string operands, and any additional characters in
+the format operand.
+.It Cm \e0 Ns Ar num
+Write an 8\-bit character whose
+.Tn ASCII
+value is the 1\-, 2\-, or 3\-digit
+octal number
+.Ar num .
+.It Cm \e^ Ns Ar c
+Write the control character
+.Ar c .
+Generates characters `\e000' through `\e037`, and `\e177' (from `\e^?').
+.It Cm \eM\- Ns Ar c
+Write the character
+.Ar c
+with the 8th bit set.
+Generates characters `\e241' through `\e376`.
+.It Cm \eM^ Ns Ar c
+Write the control character
+.Ar c
+with the 8th bit set.
+Generates characters `\e000' through `\e037`, and `\e177' (from `\eM^?').
+.El
+.It Cm B
+Characters from the string
+.Ar argument
+are printed with unprintable characters backslash-escaped using the
+.Sm off
+.Pf ` Cm \e Ar c No ',
+.Pf ` Cm \e^ Ar c No ',
+.Pf ` Cm \eM\- Ar c No '
+or
+.Pf ` Cm \eM^ Ar c No ',
+.Sm on
+formats described above.
+.It Cm c
+The first character of
+.Ar argument
+is printed.
+.It Cm s
+Characters from the string
+.Ar argument
+are printed until the end is reached or until the number of characters
+indicated by the precision specification is reached; if the
+precision is omitted, all characters in the string are printed.
+.It Cm \&%
+Print a `%'; no argument is used.
+.El
+.Pp
+In no case does a non-existent or small field width cause truncation of
+a field; padding takes place only if the specified field width exceeds
+the actual width.
+.Sh EXIT STATUS
+.Nm
+exits 0 on success, 1 on failure.
+.Sh SEE ALSO
+.Xr echo 1 ,
+.Xr printf 3 ,
+.Xr printf 9
+.Xr vis 3
+.Sh STANDARDS
+The
+.Nm
+utility conforms to
+.St -p1003.1-2001 .
+.Pp
+Support for the floating point formats and `*' as a field width and precision
+are optional in POSIX.
+.Pp
+The behaviour of the %B format and the \e', \e", \exxx, \ee and
+\e[M][\-|^]c escape sequences are undefined in POSIX.
+.Sh BUGS
+Since the floating point numbers are translated from
+.Tn ASCII
+to floating-point and
+then back again, floating-point precision may be lost.
+.Pp
+Hexadecimal character constants are restricted to, and should be specified
+as, two character constants.  This is contrary to the ISO C standard but
+does guarantee detection of the end of the constant.
diff --git a/usr/dash/bltin/printf.c b/usr/dash/bltin/printf.c
new file mode 100644
index 0000000..75ba40d
--- /dev/null
+++ b/usr/dash/bltin/printf.c
@@ -0,0 +1,476 @@
+/*
+ * Copyright (c) 1989, 1993
+ *	The Regents of the University of California.  All rights reserved.
+ * Copyright (c) 1997-2005
+ *	Herbert Xu <herbert@gondor.apana.org.au>.  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.
+ * 3. 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 <sys/types.h>
+
+#include <ctype.h>
+#include <errno.h>
+#include <inttypes.h>
+#include <limits.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+static char	*conv_escape_str(char *);
+static char	*conv_escape(char *, int *);
+static int	 getchr(void);
+static intmax_t	 getintmax(void);
+static uintmax_t getuintmax(void);
+static char	*getstr(void);
+static char	*mklong(const char *, const char *);
+static void      check_conversion(const char *, const char *);
+#ifdef HAVE_STRTOD
+static double	 getdouble(void);
+#endif
+
+static int	rval;
+static char  **gargv;
+
+#define isodigit(c)	((c) >= '0' && (c) <= '7')
+#define octtobin(c)	((c) - '0')
+
+#include "bltin.h"
+#include "system.h"
+
+#define PF(f, func) { \
+	switch ((char *)param - (char *)array) { \
+	default: \
+		(void)printf(f, array[0], array[1], func); \
+		break; \
+	case sizeof(*param): \
+		(void)printf(f, array[0], func); \
+		break; \
+	case 0: \
+		(void)printf(f, func); \
+		break; \
+	} \
+}
+
+int printfcmd(int argc, char *argv[])
+{
+	char *fmt;
+	char *format;
+	int ch;
+
+	rval = 0;
+
+	nextopt(nullstr);
+
+	argv = argptr;
+	format = *argv;
+
+	if (!format) {
+		warnx("usage: printf format [arg ...]");
+		goto err;
+	}
+
+	gargv = ++argv;
+
+#define SKIP1	"#-+ 0"
+#define SKIP2	"*0123456789"
+	do {
+		/*
+		 * Basic algorithm is to scan the format string for conversion
+		 * specifications -- once one is found, find out if the field
+		 * width or precision is a '*'; if it is, gather up value.
+		 * Note, format strings are reused as necessary to use up the
+		 * provided arguments, arguments of zero/null string are
+		 * provided to use up the format string.
+		 */
+
+		/* find next format specification */
+		for (fmt = format; (ch = *fmt++) ;) {
+			char *start;
+			char nextch;
+			int array[2];
+			int *param;
+
+			if (ch == '\\') {
+				int c_ch;
+				fmt = conv_escape(fmt, &c_ch);
+				ch = c_ch;
+				goto pc;
+			}
+			if (ch != '%' || (*fmt == '%' && (++fmt || 1))) {
+pc:
+				putchar(ch);
+				continue;
+			}
+
+			/* Ok - we've found a format specification,
+			   Save its address for a later printf(). */
+			start = fmt - 1;
+			param = array;
+
+			/* skip to field width */
+			fmt += strspn(fmt, SKIP1);
+			if (*fmt == '*')
+				*param++ = getintmax();
+
+			/* skip to possible '.', get following precision */
+			fmt += strspn(fmt, SKIP2);
+			if (*fmt == '.')
+				++fmt;
+			if (*fmt == '*')
+				*param++ = getintmax();
+
+			fmt += strspn(fmt, SKIP2);
+
+			ch = *fmt;
+			if (!ch) {
+				warnx("missing format character");
+				goto err;
+			}
+			/* null terminate format string to we can use it
+			   as an argument to printf. */
+			nextch = fmt[1];
+			fmt[1] = 0;
+			switch (ch) {
+
+			case 'b': {
+				char *p = conv_escape_str(getstr());
+				*fmt = 's';
+				PF(start, p);
+				/* escape if a \c was encountered */
+				if (rval & 0x100)
+					goto out;
+				*fmt = 'b';
+				break;
+			}
+			case 'c': {
+				int p = getchr();
+				PF(start, p);
+				break;
+			}
+			case 's': {
+				char *p = getstr();
+				PF(start, p);
+				break;
+			}
+			case 'd':
+			case 'i': {
+				intmax_t p = getintmax();
+				char *f = mklong(start, fmt);
+				PF(f, p);
+				break;
+			}
+			case 'o':
+			case 'u':
+			case 'x':
+			case 'X': {
+				uintmax_t p = getuintmax();
+				char *f = mklong(start, fmt);
+				PF(f, p);
+				break;
+			}
+#ifdef HAVE_STRTOD
+			case 'e':
+			case 'E':
+			case 'f':
+			case 'g':
+			case 'G': {
+				double p = getdouble();
+				PF(start, p);
+				break;
+			}
+#endif
+			default:
+				warnx("%s: invalid directive", start);
+				goto err;
+			}
+			*++fmt = nextch;
+		}
+	} while (gargv != argv && *gargv);
+
+out:
+	return (rval & ~0x100);
+err:
+	return 1;
+}
+
+
+/*
+ * Print SysV echo(1) style escape string
+ *	Halts processing string if a \c escape is encountered.
+ */
+static char *
+conv_escape_str(char *str)
+{
+	int ch;
+	char *cp;
+
+	/* convert string into a temporary buffer... */
+	STARTSTACKSTR(cp);
+
+	do {
+		int c;
+
+		ch = *str++;
+		if (ch != '\\')
+			continue;
+
+		ch = *str++;
+		if (ch == 'c') {
+			/* \c as in SYSV echo - abort all processing.... */
+			rval |= 0x100;
+			ch = 0;
+			continue;
+		}
+
+		/*
+		 * %b string octal constants are not like those in C.
+		 * They start with a \0, and are followed by 0, 1, 2,
+		 * or 3 octal digits.
+		 */
+		if (ch == '0') {
+			unsigned char i;
+			i = 3;
+			ch = 0;
+			do {
+				unsigned k = octtobin(*str);
+				if (k > 7)
+					break;
+				str++;
+				ch <<= 3;
+				ch += k;
+			} while (--i);
+			continue;
+		}
+
+		/* Finally test for sequences valid in the format string */
+		str = conv_escape(str - 1, &c);
+		ch = c;
+	} while (STPUTC(ch, cp), ch);
+
+	return stackblock();
+}
+
+/*
+ * Print "standard" escape characters
+ */
+static char *
+conv_escape(char *str, int *conv_ch)
+{
+	int value;
+	int ch;
+
+	ch = *str;
+
+	switch (ch) {
+	default:
+	case 0:
+		value = '\\';
+		goto out;
+
+	case '0': case '1': case '2': case '3':
+	case '4': case '5': case '6': case '7':
+		ch = 3;
+		value = 0;
+		do {
+			value <<= 3;
+			value += octtobin(*str++);
+		} while (isodigit(*str) && --ch);
+		goto out;
+
+	case '\\':	value = '\\';	break;	/* backslash */
+	case 'a':	value = '\a';	break;	/* alert */
+	case 'b':	value = '\b';	break;	/* backspace */
+	case 'f':	value = '\f';	break;	/* form-feed */
+	case 'n':	value = '\n';	break;	/* newline */
+	case 'r':	value = '\r';	break;	/* carriage-return */
+	case 't':	value = '\t';	break;	/* tab */
+	case 'v':	value = '\v';	break;	/* vertical-tab */
+	}
+
+	str++;
+out:
+	*conv_ch = value;
+	return str;
+}
+
+static char *
+mklong(const char *str, const char *ch)
+{
+	char *copy;
+	size_t len;
+
+	len = ch - str + 3;
+	STARTSTACKSTR(copy);
+	copy = makestrspace(len, copy);
+	memcpy(copy, str, len - 3);
+	copy[len - 3] = 'j';
+	copy[len - 2] = *ch;
+	copy[len - 1] = '\0';
+	return (copy);
+}
+
+static int
+getchr(void)
+{
+	int val = 0;
+
+	if (*gargv)
+		val = **gargv++;
+	return val;
+}
+
+static char *
+getstr(void)
+{
+	char *val = nullstr;
+
+	if (*gargv)
+		val = *gargv++;
+	return val;
+}
+
+static intmax_t
+getintmax(void)
+{
+	intmax_t val = 0;
+	char *cp, *ep;
+
+	cp = *gargv;
+	if (cp == NULL)
+		goto out;
+	gargv++;
+
+	val = (unsigned char) cp[1];
+	if (*cp == '\"' || *cp == '\'')
+		goto out;
+
+	errno = 0;
+	val = strtoimax(cp, &ep, 0);
+	check_conversion(cp, ep);
+out:
+	return val;
+}
+
+static uintmax_t
+getuintmax(void)
+{
+	uintmax_t val = 0;
+	char *cp, *ep;
+
+	cp = *gargv;
+	if (cp == NULL)
+		goto out;
+	gargv++;
+
+	val = (unsigned char) cp[1];
+	if (*cp == '\"' || *cp == '\'')
+		goto out;
+
+	errno = 0;
+	val = strtoumax(cp, &ep, 0);
+	check_conversion(cp, ep);
+out:
+	return val;
+}
+
+#ifdef HAVE_STRTOD
+static double
+getdouble(void)
+{
+	double val;
+	char *cp, *ep;
+
+	cp = *gargv;
+	if (cp == NULL)
+		return 0;
+	gargv++;
+
+	if (*cp == '\"' || *cp == '\'')
+		return (unsigned char) cp[1];
+
+	errno = 0;
+	val = strtod(cp, &ep);
+	check_conversion(cp, ep);
+	return val;
+}
+#endif
+
+static void
+check_conversion(const char *s, const char *ep)
+{
+	if (*ep) {
+		if (ep == s)
+			warnx("%s: expected numeric value", s);
+		else
+			warnx("%s: not completely converted", s);
+		rval = 1;
+	} else if (errno == ERANGE) {
+		warnx("%s: %s", s, strerror(ERANGE));
+		rval = 1;
+	}
+}
+
+int
+echocmd(int argc, char **argv)
+{
+	int nonl = 0;
+	struct output *outs = out1;
+
+	if (!*++argv)
+		goto end;
+	if (equal(*argv, "-n")) {
+		nonl = ~nonl;
+		if (!*++argv)
+			goto end;
+	}
+
+	do {
+		char c;
+
+		c = *(*argv)++;
+		if (!c)
+			goto next;
+		if (c != '\\')
+			goto print;
+
+		outstr(conv_escape_str(*argv - 1), outs);
+		if (rval & 0x100)
+			break;
+next:
+		c = ' ';
+		if (!*++argv) {
+end:
+			if (nonl) {
+				break;
+			}
+			c = '\n';
+		}
+print:
+		outc(c, outs);
+	} while (*argv);
+	return 0;
+}
diff --git a/usr/dash/bltin/test.1 b/usr/dash/bltin/test.1
new file mode 100644
index 0000000..42435fb
--- /dev/null
+++ b/usr/dash/bltin/test.1
@@ -0,0 +1,309 @@
+.\" Copyright (c) 1991, 1993
+.\"	The Regents of the University of California.  All rights reserved.
+.\" Copyright (c) 1997-2005
+.\"	Herbert Xu <herbert@gondor.apana.org.au>.  All rights reserved.
+.\"
+.\" This code is derived from software contributed to Berkeley by
+.\" the Institute of Electrical and Electronics Engineers, Inc.
+.\"
+.\" 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. 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.
+.\"
+.\"     @(#)test.1	8.1 (Berkeley) 5/31/93
+.\"
+.Dd May 31, 1993
+.Dt TEST 1
+.Os
+.Sh NAME
+.Nm test ,
+.Nm \&[
+.Nd condition evaluation utility
+.Sh SYNOPSIS
+.Nm test
+.Ar expression
+.Nm \&[
+.Ar expression Cm ]
+.Sh DESCRIPTION
+The
+.Nm test
+utility evaluates the expression and, if it evaluates
+to true, returns a zero (true) exit status; otherwise
+it returns 1 (false).
+If there is no expression, test also
+returns 1 (false).
+.Pp
+All operators and flags are separate arguments to the
+.Nm test
+utility.
+.Pp
+The following primaries are used to construct expression:
+.Bl -tag -width Ar
+.It Fl b Ar file
+True if
+.Ar file
+exists and is a block special
+file.
+.It Fl c Ar file
+True if
+.Ar file
+exists and is a character
+special file.
+.It Fl d Ar file
+True if
+.Ar file
+exists and is a directory.
+.It Fl e Ar file
+True if
+.Ar file
+exists (regardless of type).
+.It Fl f Ar file
+True if
+.Ar file
+exists and is a regular file.
+.It Fl g Ar file
+True if
+.Ar file
+exists and its set group ID flag
+is set.
+.It Fl h Ar file
+True if
+.Ar file
+exists and is a symbolic link.
+.It Fl k Ar file
+True if
+.Ar file
+exists and its sticky bit is set.
+.It Fl n Ar string
+True if the length of
+.Ar string
+is nonzero.
+.It Fl p Ar file
+True if
+.Ar file
+is a named pipe
+.Po Tn FIFO Pc .
+.It Fl r Ar file
+True if
+.Ar file
+exists and is readable.
+.It Fl s Ar file
+True if
+.Ar file
+exists and has a size greater
+than zero.
+.It Fl t Ar file_descriptor
+True if the file whose file descriptor number
+is
+.Ar file_descriptor
+is open and is associated with a terminal.
+.It Fl u Ar file
+True if
+.Ar file
+exists and its set user ID flag
+is set.
+.It Fl w Ar file
+True if
+.Ar file
+exists and is writable.
+True
+indicates only that the write flag is on.
+The file is not writable on a read-only file
+system even if this test indicates true.
+.It Fl x Ar file
+True if
+.Ar file
+exists and is executable.
+True
+indicates only that the execute flag is on.
+If
+.Ar file
+is a directory, true indicates that
+.Ar file
+can be searched.
+.It Fl z Ar string
+True if the length of
+.Ar string
+is zero.
+.It Fl L Ar file
+True if
+.Ar file
+exists and is a symbolic link.
+This operator is retained for compatibility with previous versions of
+this program.
+Do not rely on its existence; use
+.Fl h
+instead.
+.It Fl O Ar file
+True if
+.Ar file
+exists and its owner matches the effective user id of this process.
+.It Fl G Ar file
+True if
+.Ar file
+exists and its group matches the effective group id of this process.
+.It Fl S Ar file
+True if
+.Ar file
+exists and is a socket.
+.It Ar file1 Fl nt Ar file2
+True if
+.Ar file1
+exists and is newer than
+.Ar file2 .
+.It Ar file1 Fl ot Ar file2
+True if
+.Ar file1
+exists and is older than
+.Ar file2 .
+.It Ar file1 Fl ef Ar file2
+True if
+.Ar file1
+and
+.Ar file2
+exist and refer to the same file.
+.It Ar string
+True if
+.Ar string
+is not the null
+string.
+.It Ar \&s\&1 Cm \&= Ar \&s\&2
+True if the strings
+.Ar \&s\&1
+and
+.Ar \&s\&2
+are identical.
+.It Ar \&s\&1 Cm \&!= Ar \&s\&2
+True if the strings
+.Ar \&s\&1
+and
+.Ar \&s\&2
+are not identical.
+.It Ar \&s\&1 Cm \&\*[Lt] Ar \&s\&2
+True if string
+.Ar \&s\&1
+comes before
+.Ar \&s\&2
+based on the ASCII value of their characters.
+.It Ar \&s\&1 Cm \&\*[Gt] Ar \&s\&2
+True if string
+.Ar \&s\&1
+comes after
+.Ar \&s\&2
+based on the ASCII value of their characters.
+.It Ar \&n\&1 Fl \&eq Ar \&n\&2
+True if the integers
+.Ar \&n\&1
+and
+.Ar \&n\&2
+are algebraically
+equal.
+.It Ar \&n\&1 Fl \&ne Ar \&n\&2
+True if the integers
+.Ar \&n\&1
+and
+.Ar \&n\&2
+are not
+algebraically equal.
+.It Ar \&n\&1 Fl \&gt Ar \&n\&2
+True if the integer
+.Ar \&n\&1
+is algebraically
+greater than the integer
+.Ar \&n\&2 .
+.It Ar \&n\&1 Fl \&ge Ar \&n\&2
+True if the integer
+.Ar \&n\&1
+is algebraically
+greater than or equal to the integer
+.Ar \&n\&2 .
+.It Ar \&n\&1 Fl \&lt Ar \&n\&2
+True if the integer
+.Ar \&n\&1
+is algebraically less
+than the integer
+.Ar \&n\&2 .
+.It Ar \&n\&1 Fl \&le Ar \&n\&2
+True if the integer
+.Ar \&n\&1
+is algebraically less
+than or equal to the integer
+.Ar \&n\&2 .
+.El
+.Pp
+These primaries can be combined with the following operators:
+.Bl -tag -width Ar
+.It Cm \&! Ar expression
+True if
+.Ar expression
+is false.
+.It Ar expression1 Fl a Ar expression2
+True if both
+.Ar expression1
+and
+.Ar expression2
+are true.
+.It Ar expression1 Fl o Ar expression2
+True if either
+.Ar expression1
+or
+.Ar expression2
+are true.
+.It Cm \&( Ns Ar expression Ns Cm \&)
+True if expression is true.
+.El
+.Pp
+The
+.Fl a
+operator has higher precedence than the
+.Fl o
+operator.
+.Sh GRAMMAR AMBIGUITY
+The
+.Nm test
+grammar is inherently ambiguous.
+In order to assure a degree of consistency, the cases described in
+.St -p1003.2
+section 4.62.4,
+are evaluated consistently according to the rules specified in the
+standards document.
+All other cases are subject to the ambiguity in the command semantics.
+.Sh EXIT STATUS
+The
+.Nm test
+utility exits with one of the following values:
+.Bl -tag -width Ds
+.It 0
+expression evaluated to true.
+.It 1
+expression evaluated to false or expression was
+missing.
+.It \*[Gt]1
+An error occurred.
+.El
+.Sh STANDARDS
+The
+.Nm test
+utility implements a superset of the
+.St -p1003.2
+specification.
diff --git a/usr/dash/bltin/test.c b/usr/dash/bltin/test.c
new file mode 100644
index 0000000..77949de
--- /dev/null
+++ b/usr/dash/bltin/test.c
@@ -0,0 +1,500 @@
+/*
+ * test(1); version 7-like  --  author Erik Baalbergen
+ * modified by Eric Gisin to be used as built-in.
+ * modified by Arnold Robbins to add SVR3 compatibility
+ * (-x -c -b -p -u -g -k) plus Korn's -L -nt -ot -ef and new -S (socket).
+ * modified by J.T. Conklin for NetBSD.
+ *
+ * This program is in the Public Domain.
+ */
+
+#include <sys/stat.h>
+#include <sys/types.h>
+
+#include <ctype.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <stdarg.h>
+#include "bltin.h"
+
+/* test(1) accepts the following grammar:
+	oexpr	::= aexpr | aexpr "-o" oexpr ;
+	aexpr	::= nexpr | nexpr "-a" aexpr ;
+	nexpr	::= primary | "!" primary
+	primary	::= unary-operator operand
+		| operand binary-operator operand
+		| operand
+		| "(" oexpr ")"
+		;
+	unary-operator ::= "-r"|"-w"|"-x"|"-f"|"-d"|"-c"|"-b"|"-p"|
+		"-u"|"-g"|"-k"|"-s"|"-t"|"-z"|"-n"|"-o"|"-O"|"-G"|"-L"|"-S";
+
+	binary-operator ::= "="|"!="|"-eq"|"-ne"|"-ge"|"-gt"|"-le"|"-lt"|
+			"-nt"|"-ot"|"-ef";
+	operand ::= <any legal UNIX file name>
+*/
+
+enum token {
+	EOI,
+	FILRD,
+	FILWR,
+	FILEX,
+	FILEXIST,
+	FILREG,
+	FILDIR,
+	FILCDEV,
+	FILBDEV,
+	FILFIFO,
+	FILSOCK,
+	FILSYM,
+	FILGZ,
+	FILTT,
+	FILSUID,
+	FILSGID,
+	FILSTCK,
+	FILNT,
+	FILOT,
+	FILEQ,
+	FILUID,
+	FILGID,
+	STREZ,
+	STRNZ,
+	STREQ,
+	STRNE,
+	STRLT,
+	STRGT,
+	INTEQ,
+	INTNE,
+	INTGE,
+	INTGT,
+	INTLE,
+	INTLT,
+	UNOT,
+	BAND,
+	BOR,
+	LPAREN,
+	RPAREN,
+	OPERAND
+};
+
+enum token_types {
+	UNOP,
+	BINOP,
+	BUNOP,
+	BBINOP,
+	PAREN
+};
+
+static struct t_op {
+	const char *op_text;
+	short op_num, op_type;
+} const ops [] = {
+	{"-r",	FILRD,	UNOP},
+	{"-w",	FILWR,	UNOP},
+	{"-x",	FILEX,	UNOP},
+	{"-e",	FILEXIST,UNOP},
+	{"-f",	FILREG,	UNOP},
+	{"-d",	FILDIR,	UNOP},
+	{"-c",	FILCDEV,UNOP},
+	{"-b",	FILBDEV,UNOP},
+	{"-p",	FILFIFO,UNOP},
+	{"-u",	FILSUID,UNOP},
+	{"-g",	FILSGID,UNOP},
+	{"-k",	FILSTCK,UNOP},
+	{"-s",	FILGZ,	UNOP},
+	{"-t",	FILTT,	UNOP},
+	{"-z",	STREZ,	UNOP},
+	{"-n",	STRNZ,	UNOP},
+	{"-h",	FILSYM,	UNOP},		/* for backwards compat */
+	{"-O",	FILUID,	UNOP},
+	{"-G",	FILGID,	UNOP},
+	{"-L",	FILSYM,	UNOP},
+	{"-S",	FILSOCK,UNOP},
+	{"=",	STREQ,	BINOP},
+	{"!=",	STRNE,	BINOP},
+	{"<",	STRLT,	BINOP},
+	{">",	STRGT,	BINOP},
+	{"-eq",	INTEQ,	BINOP},
+	{"-ne",	INTNE,	BINOP},
+	{"-ge",	INTGE,	BINOP},
+	{"-gt",	INTGT,	BINOP},
+	{"-le",	INTLE,	BINOP},
+	{"-lt",	INTLT,	BINOP},
+	{"-nt",	FILNT,	BINOP},
+	{"-ot",	FILOT,	BINOP},
+	{"-ef",	FILEQ,	BINOP},
+	{"!",	UNOT,	BUNOP},
+	{"-a",	BAND,	BBINOP},
+	{"-o",	BOR,	BBINOP},
+	{"(",	LPAREN,	PAREN},
+	{")",	RPAREN,	PAREN},
+	{0,	0,	0}
+};
+
+static char **t_wp;
+static struct t_op const *t_wp_op;
+
+static void syntax(const char *, const char *);
+static int oexpr(enum token);
+static int aexpr(enum token);
+static int nexpr(enum token);
+static int primary(enum token);
+static int binop(void);
+static int filstat(char *, enum token);
+static enum token t_lex(char *);
+static int isoperand(void);
+static int getn(const char *);
+static int newerf(const char *, const char *);
+static int olderf(const char *, const char *);
+static int equalf(const char *, const char *);
+static int test_st_mode(const struct stat64 *, int);
+static int bash_group_member(gid_t);
+
+int
+testcmd(int argc, char **argv)
+{
+	int res;
+
+	if (strcmp(argv[0], "[") == 0) {
+		if (strcmp(argv[--argc], "]"))
+			error("missing ]");
+		argv[argc] = NULL;
+	}
+
+	if (argc < 2)
+		return 1;
+
+	t_wp = &argv[1];
+	res = !oexpr(t_lex(*t_wp));
+
+	if (*t_wp != NULL && *++t_wp != NULL)
+		syntax(*t_wp, "unexpected operator");
+
+	return res;
+}
+
+static void
+syntax(const char *op, const char *msg)
+{
+	if (op && *op)
+		error("%s: %s", op, msg);
+	else
+		error("%s", msg);
+}
+
+static int
+oexpr(enum token n)
+{
+	int res;
+
+	res = aexpr(n);
+	if (t_lex(*++t_wp) == BOR)
+		return oexpr(t_lex(*++t_wp)) || res;
+	t_wp--;
+	return res;
+}
+
+static int
+aexpr(enum token n)
+{
+	int res;
+
+	res = nexpr(n);
+	if (t_lex(*++t_wp) == BAND)
+		return aexpr(t_lex(*++t_wp)) && res;
+	t_wp--;
+	return res;
+}
+
+static int
+nexpr(enum token n)
+{
+	if (n == UNOT)
+		return !nexpr(t_lex(*++t_wp));
+	return primary(n);
+}
+
+static int
+primary(enum token n)
+{
+	enum token nn;
+	int res;
+
+	if (n == EOI)
+		return 0;		/* missing expression */
+	if (n == LPAREN) {
+		if ((nn = t_lex(*++t_wp)) == RPAREN)
+			return 0;	/* missing expression */
+		res = oexpr(nn);
+		if (t_lex(*++t_wp) != RPAREN)
+			syntax(NULL, "closing paren expected");
+		return res;
+	}
+	if (t_wp_op && t_wp_op->op_type == UNOP) {
+		/* unary expression */
+		if (*++t_wp == NULL)
+			syntax(t_wp_op->op_text, "argument expected");
+		switch (n) {
+		case STREZ:
+			return strlen(*t_wp) == 0;
+		case STRNZ:
+			return strlen(*t_wp) != 0;
+		case FILTT:
+			return isatty(getn(*t_wp));
+		default:
+			return filstat(*t_wp, n);
+		}
+	}
+
+	if (t_lex(t_wp[1]), t_wp_op && t_wp_op->op_type == BINOP) {
+		return binop();
+	}
+
+	return strlen(*t_wp) > 0;
+}
+
+static int
+binop(void)
+{
+	const char *opnd1, *opnd2;
+	struct t_op const *op;
+
+	opnd1 = *t_wp;
+	(void) t_lex(*++t_wp);
+	op = t_wp_op;
+
+	if ((opnd2 = *++t_wp) == (char *)0)
+		syntax(op->op_text, "argument expected");
+
+	switch (op->op_num) {
+	default:
+#ifdef DEBUG
+		abort();
+		/* NOTREACHED */
+#endif
+	case STREQ:
+		return strcmp(opnd1, opnd2) == 0;
+	case STRNE:
+		return strcmp(opnd1, opnd2) != 0;
+	case STRLT:
+		return strcmp(opnd1, opnd2) < 0;
+	case STRGT:
+		return strcmp(opnd1, opnd2) > 0;
+	case INTEQ:
+		return getn(opnd1) == getn(opnd2);
+	case INTNE:
+		return getn(opnd1) != getn(opnd2);
+	case INTGE:
+		return getn(opnd1) >= getn(opnd2);
+	case INTGT:
+		return getn(opnd1) > getn(opnd2);
+	case INTLE:
+		return getn(opnd1) <= getn(opnd2);
+	case INTLT:
+		return getn(opnd1) < getn(opnd2);
+	case FILNT:
+		return newerf (opnd1, opnd2);
+	case FILOT:
+		return olderf (opnd1, opnd2);
+	case FILEQ:
+		return equalf (opnd1, opnd2);
+	}
+}
+
+static int
+filstat(char *nm, enum token mode)
+{
+	struct stat64 s;
+
+	if (mode == FILSYM ? lstat64(nm, &s) : stat64(nm, &s))
+		return 0;
+
+	switch (mode) {
+	case FILRD:
+		return test_st_mode(&s, R_OK);
+	case FILWR:
+		return test_st_mode(&s, W_OK);
+	case FILEX:
+		return test_st_mode(&s, X_OK);
+	case FILEXIST:
+		return 1;
+	case FILREG:
+		return S_ISREG(s.st_mode);
+	case FILDIR:
+		return S_ISDIR(s.st_mode);
+	case FILCDEV:
+		return S_ISCHR(s.st_mode);
+	case FILBDEV:
+		return S_ISBLK(s.st_mode);
+	case FILFIFO:
+		return S_ISFIFO(s.st_mode);
+	case FILSOCK:
+		return S_ISSOCK(s.st_mode);
+	case FILSYM:
+		return S_ISLNK(s.st_mode);
+	case FILSUID:
+		return (s.st_mode & S_ISUID) != 0;
+	case FILSGID:
+		return (s.st_mode & S_ISGID) != 0;
+	case FILSTCK:
+		return (s.st_mode & S_ISVTX) != 0;
+	case FILGZ:
+		return !!s.st_size;
+	case FILUID:
+		return s.st_uid == geteuid();
+	case FILGID:
+		return s.st_gid == getegid();
+	default:
+		return 1;
+	}
+}
+
+static enum token
+t_lex(char *s)
+{
+	struct t_op const *op;
+
+	op = ops;
+
+	if (s == 0) {
+		t_wp_op = (struct t_op *)0;
+		return EOI;
+	}
+	while (op->op_text) {
+		if (strcmp(s, op->op_text) == 0) {
+			if ((op->op_type == UNOP && isoperand()) ||
+			    (op->op_num == LPAREN && *(t_wp+1) == 0))
+				break;
+			t_wp_op = op;
+			return op->op_num;
+		}
+		op++;
+	}
+	t_wp_op = (struct t_op *)0;
+	return OPERAND;
+}
+
+static int
+isoperand(void)
+{
+	struct t_op const *op;
+	char *s, *t;
+
+	op = ops;
+	if ((s  = *(t_wp+1)) == 0)
+		return 1;
+	if ((t = *(t_wp+2)) == 0)
+		return 0;
+	while (op->op_text) {
+		if (strcmp(s, op->op_text) == 0)
+	    		return op->op_type == BINOP &&
+	    		    (t[0] != ')' || t[1] != '\0');
+		op++;
+	}
+	return 0;
+}
+
+/* atoi with error detection */
+static int
+getn(const char *s)
+{
+	char *p;
+	long r;
+
+	errno = 0;
+	r = strtol(s, &p, 10);
+
+	if (errno != 0)
+	      error("%s: out of range", s);
+
+	while (isspace((unsigned char)*p))
+	      p++;
+
+	if (*p)
+	      error("%s: bad number", s);
+
+	return (int) r;
+}
+
+static int
+newerf (const char *f1, const char *f2)
+{
+	struct stat b1, b2;
+
+	return (stat (f1, &b1) == 0 &&
+		stat (f2, &b2) == 0 &&
+		b1.st_mtime > b2.st_mtime);
+}
+
+static int
+olderf (const char *f1, const char *f2)
+{
+	struct stat b1, b2;
+
+	return (stat (f1, &b1) == 0 &&
+		stat (f2, &b2) == 0 &&
+		b1.st_mtime < b2.st_mtime);
+}
+
+static int
+equalf (const char *f1, const char *f2)
+{
+	struct stat b1, b2;
+
+	return (stat (f1, &b1) == 0 &&
+		stat (f2, &b2) == 0 &&
+		b1.st_dev == b2.st_dev &&
+		b1.st_ino == b2.st_ino);
+}
+
+/*
+ * Similar to what access(2) does, but uses the effective uid and gid.
+ * Doesn't make the mistake of telling root that any file is executable.
+ * Returns non-zero if the file is accessible.
+ */
+static int
+test_st_mode(const struct stat64 *st, int mode)
+{
+	int euid = geteuid();
+
+	if (euid == 0) {
+		/* Root can read or write any file. */
+		if (mode != X_OK)
+			return 1;
+
+		/* Root can execute any file that has any one of the execute
+		   bits set. */
+		mode = S_IXUSR | S_IXGRP | S_IXOTH;
+	} else if (st->st_uid == euid)
+		mode <<= 6;
+	else if (bash_group_member(st->st_gid))
+		mode <<= 3;
+
+	return st->st_mode & mode;
+}
+
+/* Return non-zero if GID is one that we have in our groups list. */
+static int
+bash_group_member(gid_t gid)
+{
+	register int i;
+	gid_t *group_array;
+	int ngroups;
+
+	/* Short-circuit if possible, maybe saving a call to getgroups(). */
+	if (gid == getgid() || gid == getegid())
+		return (1);
+
+	ngroups = getgroups(0, NULL);
+	group_array = stalloc(ngroups * sizeof(gid_t));
+	getgroups(ngroups, group_array);
+
+	/* Search through the list looking for GID. */
+	for (i = 0; i < ngroups; i++)
+		if (gid == group_array[i])
+			return (1);
+
+	return (0);
+}
diff --git a/usr/dash/builtins.def.in b/usr/dash/builtins.def.in
new file mode 100644
index 0000000..cfb69d7
--- /dev/null
+++ b/usr/dash/builtins.def.in
@@ -0,0 +1,92 @@
+/*
+ * Copyright (c) 1991, 1993
+ *	The Regents of the University of California.  All rights reserved.
+ * Copyright (c) 1997-2005
+ *	Herbert Xu <herbert@gondor.apana.org.au>.  All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Kenneth Almquist.
+ *
+ * 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. 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.
+ *
+ *	@(#)builtins.def	8.4 (Berkeley) 5/4/95
+ */
+
+/*
+ * This file lists all the builtin commands.  The first column is the name
+ * of a C routine.
+ * The -a flag specifies that this is a posix 'assignment builtin' command.
+ * The -s flag specifies that this is a posix 'special builtin' command.
+ * The -u flag specifies that this is a posix 'standard utility'.
+ * The rest of the line specifies the command name or names used to run
+ * the command.
+ */
+
+#ifndef JOBS
+#define JOBS 1
+#endif
+
+#if JOBS
+bgcmd		-u bg
+fgcmd		-u fg
+#endif
+
+#ifndef SMALL
+histcmd		-u fc
+#endif
+
+breakcmd	-s break -s continue
+cdcmd		-u cd chdir
+commandcmd	-u command
+dotcmd		-s .
+echocmd		echo
+evalcmd		-s eval
+execcmd		-s exec
+exitcmd		-s exit
+exportcmd	-as export -as readonly
+falsecmd	-u false
+getoptscmd	-u getopts
+hashcmd		hash
+jobscmd		-u jobs
+localcmd	-a local
+printfcmd	printf
+pwdcmd		pwd
+readcmd		-u read
+returncmd	-s return
+setcmd		-s set
+shiftcmd	-s shift
+trapcmd		-s trap
+truecmd		-s : -u true
+typecmd		type
+umaskcmd	-u umask
+unaliascmd	-u unalias
+unsetcmd	-s unset
+waitcmd		-u wait
+aliascmd	-au alias
+#ifdef HAVE_GETRLIMIT
+ulimitcmd	ulimit
+#endif
+testcmd		test [
+killcmd		-u kill
diff --git a/usr/dash/cd.c b/usr/dash/cd.c
new file mode 100644
index 0000000..567393f
--- /dev/null
+++ b/usr/dash/cd.c
@@ -0,0 +1,304 @@
+/*-
+ * Copyright (c) 1991, 1993
+ *	The Regents of the University of California.  All rights reserved.
+ * Copyright (c) 1997-2005
+ *	Herbert Xu <herbert@gondor.apana.org.au>.  All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Kenneth Almquist.
+ *
+ * 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. 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 <sys/types.h>
+#include <sys/stat.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+/*
+ * The cd and pwd commands.
+ */
+
+#include "shell.h"
+#include "var.h"
+#include "nodes.h"	/* for jobs.h */
+#include "jobs.h"
+#include "options.h"
+#include "output.h"
+#include "memalloc.h"
+#include "error.h"
+#include "exec.h"
+#include "redir.h"
+#include "mystring.h"
+#include "show.h"
+#include "cd.h"
+
+#define CD_PHYSICAL 1
+#define CD_PRINT 2
+
+STATIC int docd(const char *, int);
+STATIC const char *updatepwd(const char *);
+STATIC char *getpwd(void);
+STATIC int cdopt(void);
+
+STATIC char *curdir = nullstr;		/* current working directory */
+STATIC char *physdir = nullstr;		/* physical working directory */
+
+STATIC int
+cdopt()
+{
+	int flags = 0;
+	int i, j;
+
+	j = 'L';
+	while ((i = nextopt("LP"))) {
+		if (i != j) {
+			flags ^= CD_PHYSICAL;
+			j = i;
+		}
+	}
+
+	return flags;
+}
+
+int
+cdcmd(int argc, char **argv)
+{
+	const char *dest;
+	const char *path;
+	const char *p;
+	char c;
+	struct stat statb;
+	int flags;
+
+	flags = cdopt();
+	dest = *argptr;
+	if (!dest)
+		dest = bltinlookup(homestr);
+	else if (dest[0] == '-' && dest[1] == '\0') {
+		dest = bltinlookup("OLDPWD");
+		flags |= CD_PRINT;
+	}
+	if (!dest)
+		dest = nullstr;
+	if (*dest == '/')
+		goto step7;
+	if (*dest == '.') {
+		c = dest[1];
+dotdot:
+		switch (c) {
+		case '\0':
+		case '/':
+			goto step6;
+		case '.':
+			c = dest[2];
+			if (c != '.')
+				goto dotdot;
+		}
+	}
+	if (!*dest)
+		dest = ".";
+	if (!(path = bltinlookup("CDPATH"))) {
+step6:
+step7:
+		p = dest;
+		goto docd;
+	}
+	do {
+		c = *path;
+		p = padvance(&path, dest);
+		if (stat(p, &statb) >= 0 && S_ISDIR(statb.st_mode)) {
+			if (c && c != ':')
+				flags |= CD_PRINT;
+docd:
+			if (!docd(p, flags))
+				goto out;
+			break;
+		}
+	} while (path);
+	sh_error("can't cd to %s", dest);
+	/* NOTREACHED */
+out:
+	if (flags & CD_PRINT)
+		out1fmt(snlfmt, curdir);
+	return 0;
+}
+
+
+/*
+ * Actually do the chdir.  We also call hashcd to let the routines in exec.c
+ * know that the current directory has changed.
+ */
+
+STATIC int
+docd(const char *dest, int flags)
+{
+	const char *dir = 0;
+	int err;
+
+	TRACE(("docd(\"%s\", %d) called\n", dest, flags));
+
+	INTOFF;
+	if (!(flags & CD_PHYSICAL)) {
+		dir = updatepwd(dest);
+		if (dir)
+			dest = dir;
+	}
+	err = chdir(dest);
+	if (err)
+		goto out;
+	setpwd(dir, 1);
+	hashcd();
+out:
+	INTON;
+	return err;
+}
+
+
+/*
+ * Update curdir (the name of the current directory) in response to a
+ * cd command.
+ */
+
+STATIC const char *
+updatepwd(const char *dir)
+{
+	char *new;
+	char *p;
+	char *cdcomppath;
+	const char *lim;
+
+	cdcomppath = sstrdup(dir);
+	STARTSTACKSTR(new);
+	if (*dir != '/') {
+		if (curdir == nullstr)
+			return 0;
+		new = stputs(curdir, new);
+	}
+	new = makestrspace(strlen(dir) + 2, new);
+	lim = stackblock() + 1;
+	if (*dir != '/') {
+		if (new[-1] != '/')
+			USTPUTC('/', new);
+		if (new > lim && *lim == '/')
+			lim++;
+	} else {
+		USTPUTC('/', new);
+		cdcomppath++;
+		if (dir[1] == '/' && dir[2] != '/') {
+			USTPUTC('/', new);
+			cdcomppath++;
+			lim++;
+		}
+	}
+	p = strtok(cdcomppath, "/");
+	while (p) {
+		switch(*p) {
+		case '.':
+			if (p[1] == '.' && p[2] == '\0') {
+				while (new > lim) {
+					STUNPUTC(new);
+					if (new[-1] == '/')
+						break;
+				}
+				break;
+			} else if (p[1] == '\0')
+				break;
+			/* fall through */
+		default:
+			new = stputs(p, new);
+			USTPUTC('/', new);
+		}
+		p = strtok(0, "/");
+	}
+	if (new > lim)
+		STUNPUTC(new);
+	*new = 0;
+	return stackblock();
+}
+
+
+#define MAXPWD 256
+
+/*
+ * Find out what the current directory is. If we already know the current
+ * directory, this routine returns immediately.
+ */
+inline
+STATIC char *
+getpwd()
+{
+	char buf[PATH_MAX];
+	char *dir = getcwd(buf, sizeof(buf));
+	return dir ? savestr(dir) : nullstr;
+}
+
+int
+pwdcmd(int argc, char **argv)
+{
+	int flags;
+	const char *dir = curdir;
+
+	flags = cdopt();
+	if (flags) {
+		if (physdir == nullstr)
+			setpwd(dir, 0);
+		dir = physdir;
+	}
+	out1fmt(snlfmt, dir);
+	return 0;
+}
+
+void
+setpwd(const char *val, int setold)
+{
+	char *oldcur, *dir;
+
+	oldcur = dir = curdir;
+
+	if (setold) {
+		setvar("OLDPWD", oldcur, VEXPORT);
+	}
+	INTOFF;
+	if (physdir != nullstr) {
+		if (physdir != oldcur)
+			free(physdir);
+		physdir = nullstr;
+	}
+	if (oldcur == val || !val) {
+		char *s = getpwd();
+		physdir = s;
+		if (!val)
+			dir = s;
+	} else
+		dir = savestr(val);
+	if (oldcur != dir && oldcur != nullstr) {
+		free(oldcur);
+	}
+	curdir = dir;
+	INTON;
+	setvar("PWD", dir, VEXPORT);
+}
diff --git a/usr/dash/cd.h b/usr/dash/cd.h
new file mode 100644
index 0000000..8763161
--- /dev/null
+++ b/usr/dash/cd.h
@@ -0,0 +1,35 @@
+/*-
+ * Copyright (c) 1995
+ *	The Regents of the University of California.  All rights reserved.
+ * Copyright (c) 1997-2005
+ *	Herbert Xu <herbert@gondor.apana.org.au>.  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.
+ * 3. 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.
+ *
+ */
+
+int	cdcmd(int, char **);
+int	pwdcmd(int, char **);
+void	setpwd(const char *, int);
diff --git a/usr/dash/config.h b/usr/dash/config.h
new file mode 100644
index 0000000..1b587cc
--- /dev/null
+++ b/usr/dash/config.h
@@ -0,0 +1,85 @@
+/* config.h.  Generated by configure.  */
+/* config.h.in.  Generated from configure.ac by autoheader.  */
+
+/* Define to 1 if you have the `bsearch' function. */
+#define HAVE_BSEARCH 1
+
+/* Define to 1 if you have the `getpwnam' function. */
+/* #undef HAVE_GETPWNAM */
+
+/* Define to 1 if you have the `getrlimit' function. */
+/* #undef HAVE_GETRLIMIT */
+
+/* Define to 1 if you have the `isalpha' function. */
+#define HAVE_ISALPHA 1
+
+/* Define to 1 if you have the `killpg' function. */
+/* #undef HAVE_KILLPG */
+
+/* Define to 1 if you have the `mempcpy' function. */
+/* #undef HAVE_MEMPCPY */
+
+/* Define to 1 if you have the `sigsetmask' function. */
+/* #undef HAVE_SIGSETMASK */
+
+/* Define to 1 if you have the `stpcpy' function. */
+/* #undef HAVE_STPCPY */
+
+/* Define to 1 if you have the `strchrnul' function. */
+/* #undef HAVE_STRCHRNUL */
+
+/* Define to 1 if you have the `strsignal' function. */
+#define HAVE_STRSIGNAL 1
+
+/* Define to 1 if you have the `strtod' function. */
+/* #undef HAVE_STRTOD */
+
+/* Define to 1 if you have the `strtoimax' function. */
+#define HAVE_STRTOIMAX 1
+
+/* Define to 1 if you have the `strtoumax' function. */
+#define HAVE_STRTOUMAX 1
+
+/* Define to 1 if you have the `sysconf' function. */
+/* #undef HAVE_SYSCONF */
+
+/* Name of package */
+#define PACKAGE "dash"
+
+/* Define to the address where bug reports for this package should be sent. */
+#define PACKAGE_BUGREPORT ""
+
+/* Define to the full name of this package. */
+#define PACKAGE_NAME "dash"
+
+/* Define to the full name and version of this package. */
+#define PACKAGE_STRING "dash 0.5.2"
+
+/* Define to the one symbol short name of this package. */
+#define PACKAGE_TARNAME "dash"
+
+/* Define to the version of this package. */
+#define PACKAGE_VERSION "0.5.2"
+
+/* Version number of package */
+#define VERSION "0.5.2"
+
+/* Enable GNU extensions on systems that have them.  */
+#ifndef _GNU_SOURCE
+# define _GNU_SOURCE 1
+#endif
+
+/* 64-bit operations are the same as 32-bit */
+#define fstat64 fstat
+
+/* 64-bit operations are the same as 32-bit */
+#define lstat64 lstat
+
+/* 64-bit operations are the same as 32-bit */
+#define open64 open
+
+/* klibc has bsd_signal instead of signal */
+#define signal bsd_signal
+
+/* 64-bit operations are the same as 32-bit */
+#define stat64 stat
diff --git a/usr/dash/error.c b/usr/dash/error.c
new file mode 100644
index 0000000..338243d
--- /dev/null
+++ b/usr/dash/error.c
@@ -0,0 +1,233 @@
+/*-
+ * Copyright (c) 1991, 1993
+ *	The Regents of the University of California.  All rights reserved.
+ * Copyright (c) 1997-2005
+ *	Herbert Xu <herbert@gondor.apana.org.au>.  All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Kenneth Almquist.
+ *
+ * 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. 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.
+ */
+
+/*
+ * Errors and exceptions.
+ */
+
+#include <signal.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "shell.h"
+#include "main.h"
+#include "options.h"
+#include "output.h"
+#include "error.h"
+#include "show.h"
+#include "eval.h"
+#include "parser.h"
+#include "trap.h"
+#include "system.h"
+
+
+/*
+ * Code to handle exceptions in C.
+ */
+
+struct jmploc *handler;
+int exception;
+int suppressint;
+volatile sig_atomic_t intpending;
+
+
+static void exverror(int, const char *, va_list)
+    __attribute__((__noreturn__));
+
+/*
+ * Called to raise an exception.  Since C doesn't include exceptions, we
+ * just do a longjmp to the exception handler.  The type of exception is
+ * stored in the global variable "exception".
+ */
+
+void
+exraise(int e)
+{
+#ifdef DEBUG
+	if (handler == NULL)
+		abort();
+#endif
+	INTOFF;
+
+	exception = e;
+	longjmp(handler->loc, 1);
+}
+
+
+/*
+ * Called from trap.c when a SIGINT is received.  (If the user specifies
+ * that SIGINT is to be trapped or ignored using the trap builtin, then
+ * this routine is not called.)  Suppressint is nonzero when interrupts
+ * are held using the INTOFF macro.  (The test for iflag is just
+ * defensive programming.)
+ */
+
+void
+onint(void) {
+	int i;
+
+	intpending = 0;
+	sigclearmask();
+	i = EXSIG;
+	if (gotsig[SIGINT - 1] && !trap[SIGINT]) {
+		if (!(rootshell && iflag)) {
+			signal(SIGINT, SIG_DFL);
+			raise(SIGINT);
+		}
+		i = EXINT;
+	}
+	exraise(i);
+	/* NOTREACHED */
+}
+
+static void
+exvwarning2(const char *msg, va_list ap)
+{
+	struct output *errs;
+	const char *name;
+	const char *fmt;
+
+	errs = out2;
+	name = arg0;
+	fmt = "%s: ";
+	if (commandname) {
+		name = commandname;
+		fmt = "%s: %d: ";
+	}
+	outfmt(errs, fmt, name, startlinno);
+	doformat(errs, msg, ap);
+#if FLUSHERR
+	outc('\n', errs);
+#else
+	outcslow('\n', errs);
+#endif
+}
+
+#define exvwarning(a, b, c) exvwarning2(b, c)
+
+/*
+ * Exverror is called to raise the error exception.  If the second argument
+ * is not NULL then error prints an error message using printf style
+ * formatting.  It then raises the error exception.
+ */
+static void
+exverror(int cond, const char *msg, va_list ap)
+{
+#ifdef DEBUG
+	if (msg) {
+		TRACE(("exverror(%d, \"", cond));
+		TRACEV((msg, ap));
+		TRACE(("\") pid=%d\n", getpid()));
+	} else
+		TRACE(("exverror(%d, NULL) pid=%d\n", cond, getpid()));
+	if (msg)
+#endif
+		exvwarning(-1, msg, ap);
+
+	flushall();
+	exraise(cond);
+	/* NOTREACHED */
+}
+
+
+void
+sh_error(const char *msg, ...)
+{
+	va_list ap;
+
+	va_start(ap, msg);
+	exverror(EXERROR, msg, ap);
+	/* NOTREACHED */
+	va_end(ap);
+}
+
+
+void
+exerror(int cond, const char *msg, ...)
+{
+	va_list ap;
+
+	va_start(ap, msg);
+	exverror(cond, msg, ap);
+	/* NOTREACHED */
+	va_end(ap);
+}
+
+/*
+ * error/warning routines for external builtins
+ */
+
+void
+sh_warnx(const char *fmt, ...)
+{
+	va_list ap;
+
+	va_start(ap, fmt);
+	exvwarning(-1, fmt, ap);
+	va_end(ap);
+}
+
+
+/*
+ * Return a string describing an error.  The returned string may be a
+ * pointer to a static buffer that will be overwritten on the next call.
+ * Action describes the operation that got the error.
+ */
+
+const char *
+errmsg(int e, int action)
+{
+	if (e != ENOENT && e != ENOTDIR)
+		return strerror(e);
+
+	if (action & E_OPEN)
+		return "No such file";
+	else if (action & E_CREAT)
+		return "Directory nonexistent";
+	else
+		return "not found";
+}
+
+
+#ifdef REALLY_SMALL
+void
+__inton() {
+	if (--suppressint == 0 && intpending) {
+		onint();
+	}
+}
+#endif
diff --git a/usr/dash/error.h b/usr/dash/error.h
new file mode 100644
index 0000000..326600b
--- /dev/null
+++ b/usr/dash/error.h
@@ -0,0 +1,145 @@
+/*-
+ * Copyright (c) 1991, 1993
+ *	The Regents of the University of California.  All rights reserved.
+ * Copyright (c) 1997-2005
+ *	Herbert Xu <herbert@gondor.apana.org.au>.  All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Kenneth Almquist.
+ *
+ * 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. 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.
+ *
+ *	@(#)error.h	8.2 (Berkeley) 5/4/95
+ */
+
+#ifndef DASH_ERROR_H
+#define DASH_ERROR_H
+
+#include <setjmp.h>
+#include <signal.h>
+
+/*
+ * Types of operations (passed to the errmsg routine).
+ */
+
+#define E_OPEN 01	/* opening a file */
+#define E_CREAT 02	/* creating a file */
+#define E_EXEC 04	/* executing a program */
+
+
+/*
+ * We enclose jmp_buf in a structure so that we can declare pointers to
+ * jump locations.  The global variable handler contains the location to
+ * jump to when an exception occurs, and the global variable exception
+ * contains a code identifying the exeception.  To implement nested
+ * exception handlers, the user should save the value of handler on entry
+ * to an inner scope, set handler to point to a jmploc structure for the
+ * inner scope, and restore handler on exit from the scope.
+ */
+
+struct jmploc {
+	jmp_buf loc;
+};
+
+extern struct jmploc *handler;
+extern int exception;
+
+/* exceptions */
+#define EXINT 0		/* SIGINT received */
+#define EXERROR 1	/* a generic error */
+#define EXSHELLPROC 2	/* execute a shell procedure */
+#define EXEXEC 3	/* command execution failed */
+#define EXEXIT 4	/* exit the shell */
+#define EXSIG 5		/* trapped signal in wait(1) */
+
+
+/*
+ * These macros allow the user to suspend the handling of interrupt signals
+ * over a period of time.  This is similar to SIGHOLD to or sigblock, but
+ * much more efficient and portable.  (But hacking the kernel is so much
+ * more fun than worrying about efficiency and portability. :-))
+ */
+
+extern int suppressint;
+extern volatile sig_atomic_t intpending;
+extern int exsig;
+
+#define barrier() ({ __asm__ __volatile__ ("": : :"memory"); })
+#define INTOFF \
+	({ \
+		suppressint++; \
+		barrier(); \
+		0; \
+	})
+#ifdef REALLY_SMALL
+void __inton(void);
+#define INTON __inton()
+#else
+#define INTON \
+	({ \
+		barrier(); \
+		if (--suppressint == 0 && intpending) onint(); \
+		0; \
+	})
+#endif
+#define FORCEINTON \
+	({ \
+		barrier(); \
+		suppressint = 0; \
+		if (intpending) onint(); \
+		0; \
+	})
+#define SAVEINT(v) ((v) = suppressint)
+#define RESTOREINT(v) \
+	({ \
+		barrier(); \
+		if ((suppressint = (v)) == 0 && intpending) onint(); \
+		0; \
+	})
+#define CLEAR_PENDING_INT intpending = 0
+#define int_pending() intpending
+#define EXSIGON() \
+	({ \
+		exsig++; \
+		barrier(); \
+		if (pendingsigs) \
+			exraise(EXSIG); \
+		0; \
+	})
+/* EXSIG is turned off by evalbltin(). */
+
+void exraise(int) __attribute__((__noreturn__));
+#ifdef USE_NORETURN
+void onint(void) __attribute__((__noreturn__));
+#else
+void onint(void);
+#endif
+void sh_error(const char *, ...) __attribute__((__noreturn__));
+void exerror(int, const char *, ...) __attribute__((__noreturn__));
+const char *errmsg(int, int);
+
+void sh_warnx(const char *, ...);
+
+#endif		/* DASH_ERROR_H */
diff --git a/usr/dash/eval.c b/usr/dash/eval.c
new file mode 100644
index 0000000..44ba850
--- /dev/null
+++ b/usr/dash/eval.c
@@ -0,0 +1,1100 @@
+/*-
+ * Copyright (c) 1993
+ *	The Regents of the University of California.  All rights reserved.
+ * Copyright (c) 1997-2005
+ *	Herbert Xu <herbert@gondor.apana.org.au>.  All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Kenneth Almquist.
+ *
+ * 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. 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 <stdlib.h>
+#include <signal.h>
+#include <unistd.h>
+#include <sys/types.h>
+
+/*
+ * Evaluate a command.
+ */
+
+#include "shell.h"
+#include "nodes.h"
+#include "syntax.h"
+#include "expand.h"
+#include "parser.h"
+#include "jobs.h"
+#include "eval.h"
+#include "builtins.h"
+#include "options.h"
+#include "exec.h"
+#include "redir.h"
+#include "input.h"
+#include "output.h"
+#include "trap.h"
+#include "var.h"
+#include "memalloc.h"
+#include "error.h"
+#include "show.h"
+#include "mystring.h"
+#ifndef SMALL
+#include "myhistedit.h"
+#endif
+
+
+/* flags in argument to evaltree */
+#define EV_EXIT 01		/* exit after evaluating tree */
+#define EV_TESTED 02		/* exit status is checked; ignore -e flag */
+#define EV_BACKCMD 04		/* command executing within back quotes */
+
+int evalskip;			/* set if we are skipping commands */
+STATIC int skipcount;		/* number of levels to skip */
+MKINIT int loopnest;		/* current loop nesting level */
+static int funcnest;		/* depth of function calls */
+
+
+char *commandname;
+struct strlist *cmdenviron;
+int exitstatus;			/* exit status of last command */
+int back_exitstatus;		/* exit status of backquoted command */
+
+
+#if !defined(__alpha__) || (defined(__GNUC__) && __GNUC__ >= 3)
+STATIC
+#endif
+void evaltreenr(union node *, int) __attribute__ ((__noreturn__));
+STATIC void evalloop(union node *, int);
+STATIC void evalfor(union node *, int);
+STATIC void evalcase(union node *, int);
+STATIC void evalsubshell(union node *, int);
+STATIC void expredir(union node *);
+STATIC void evalpipe(union node *, int);
+#ifdef notyet
+STATIC void evalcommand(union node *, int, struct backcmd *);
+#else
+STATIC void evalcommand(union node *, int);
+#endif
+STATIC int evalbltin(const struct builtincmd *, int, char **);
+STATIC int evalfun(struct funcnode *, int, char **, int);
+STATIC void prehash(union node *);
+STATIC int eprintlist(struct output *, struct strlist *, int);
+STATIC int bltincmd(int, char **);
+
+
+STATIC const struct builtincmd bltin = {
+	name: nullstr,
+	builtin: bltincmd
+};
+
+
+/*
+ * Called to reset things after an exception.
+ */
+
+#ifdef mkinit
+INCLUDE "eval.h"
+
+RESET {
+	evalskip = 0;
+	loopnest = 0;
+}
+#endif
+
+
+
+/*
+ * The eval commmand.
+ */
+
+int
+evalcmd(int argc, char **argv)
+{
+        char *p;
+        char *concat;
+        char **ap;
+
+        if (argc > 1) {
+                p = argv[1];
+                if (argc > 2) {
+                        STARTSTACKSTR(concat);
+                        ap = argv + 2;
+                        for (;;) {
+                        	concat = stputs(p, concat);
+                                if ((p = *ap++) == NULL)
+                                        break;
+                                STPUTC(' ', concat);
+                        }
+                        STPUTC('\0', concat);
+                        p = grabstackstr(concat);
+                }
+                evalstring(p, ~SKIPEVAL);
+
+        }
+        return exitstatus;
+}
+
+
+/*
+ * Execute a command or commands contained in a string.
+ */
+
+int
+evalstring(char *s, int mask)
+{
+	union node *n;
+	struct stackmark smark;
+	int skip;
+
+	setinputstring(s);
+	setstackmark(&smark);
+
+	skip = 0;
+	while ((n = parsecmd(0)) != NEOF) {
+		evaltree(n, 0);
+		popstackmark(&smark);
+		skip = evalskip;
+		if (skip)
+			break;
+	}
+	popfile();
+
+	skip &= mask;
+	evalskip = skip;
+	return skip;
+}
+
+
+
+/*
+ * Evaluate a parse tree.  The value is left in the global variable
+ * exitstatus.
+ */
+
+void
+evaltree(union node *n, int flags)
+{
+	int checkexit = 0;
+	void (*evalfn)(union node *, int);
+	unsigned isor;
+	int status;
+	if (n == NULL) {
+		TRACE(("evaltree(NULL) called\n"));
+		goto out;
+	}
+#ifndef SMALL
+	displayhist = 1;	/* show history substitutions done with fc */
+#endif
+	TRACE(("pid %d, evaltree(%p: %d, %d) called\n",
+	    getpid(), n, n->type, flags));
+	switch (n->type) {
+	default:
+#ifdef DEBUG
+		out1fmt("Node type = %d\n", n->type);
+#ifndef USE_GLIBC_STDIO
+		flushout(out1);
+#endif
+		break;
+#endif
+	case NNOT:
+		evaltree(n->nnot.com, EV_TESTED);
+		status = !exitstatus;
+		goto setstatus;
+	case NREDIR:
+		expredir(n->nredir.redirect);
+		status = redirectsafe(n->nredir.redirect, REDIR_PUSH);
+		if (!status) {
+			evaltree(n->nredir.n, flags & EV_TESTED);
+			status = exitstatus;
+		}
+		popredir(0);
+		goto setstatus;
+	case NCMD:
+#ifdef notyet
+		if (eflag && !(flags & EV_TESTED))
+			checkexit = ~0;
+		evalcommand(n, flags, (struct backcmd *)NULL);
+		break;
+#else
+		evalfn = evalcommand;
+checkexit:
+		if (eflag && !(flags & EV_TESTED))
+			checkexit = ~0;
+		goto calleval;
+#endif
+	case NFOR:
+		evalfn = evalfor;
+		goto calleval;
+	case NWHILE:
+	case NUNTIL:
+		evalfn = evalloop;
+		goto calleval;
+	case NSUBSHELL:
+	case NBACKGND:
+		evalfn = evalsubshell;
+		goto calleval;
+	case NPIPE:
+		evalfn = evalpipe;
+#ifdef notyet
+		if (eflag && !(flags & EV_TESTED))
+			checkexit = ~0;
+		goto calleval;
+#else
+		goto checkexit;
+#endif
+	case NCASE:
+		evalfn = evalcase;
+		goto calleval;
+	case NAND:
+	case NOR:
+	case NSEMI:
+#if NAND + 1 != NOR
+#error NAND + 1 != NOR
+#endif
+#if NOR + 1 != NSEMI
+#error NOR + 1 != NSEMI
+#endif
+		isor = n->type - NAND;
+		evaltree(
+			n->nbinary.ch1,
+			(flags | ((isor >> 1) - 1)) & EV_TESTED
+		);
+		if (!exitstatus == isor)
+			break;
+		if (!evalskip) {
+			n = n->nbinary.ch2;
+evaln:
+			evalfn = evaltree;
+calleval:
+			evalfn(n, flags);
+			break;
+		}
+		break;
+	case NIF:
+		evaltree(n->nif.test, EV_TESTED);
+		if (evalskip)
+			break;
+		if (exitstatus == 0) {
+			n = n->nif.ifpart;
+			goto evaln;
+		} else if (n->nif.elsepart) {
+			n = n->nif.elsepart;
+			goto evaln;
+		}
+		goto success;
+	case NDEFUN:
+		defun(n->narg.text, n->narg.next);
+success:
+		status = 0;
+setstatus:
+		exitstatus = status;
+		break;
+	}
+out:
+	if ((checkexit & exitstatus))
+		evalskip |= SKIPEVAL;
+	else if (pendingsigs && dotrap())
+		goto exexit;
+
+	if (flags & EV_EXIT) {
+exexit:
+		exraise(EXEXIT);
+	}
+}
+
+
+#if !defined(__alpha__) || (defined(__GNUC__) && __GNUC__ >= 3)
+STATIC
+#endif
+void evaltreenr(union node *, int) __attribute__ ((alias("evaltree")));
+
+
+STATIC void
+evalloop(union node *n, int flags)
+{
+	int status;
+
+	loopnest++;
+	status = 0;
+	flags &= EV_TESTED;
+	for (;;) {
+		int i;
+
+		evaltree(n->nbinary.ch1, EV_TESTED);
+		if (evalskip) {
+skipping:	  if (evalskip == SKIPCONT && --skipcount <= 0) {
+				evalskip = 0;
+				continue;
+			}
+			if (evalskip == SKIPBREAK && --skipcount <= 0)
+				evalskip = 0;
+			break;
+		}
+		i = exitstatus;
+		if (n->type != NWHILE)
+			i = !i;
+		if (i != 0)
+			break;
+		evaltree(n->nbinary.ch2, flags);
+		status = exitstatus;
+		if (evalskip)
+			goto skipping;
+	}
+	loopnest--;
+	exitstatus = status;
+}
+
+
+
+STATIC void
+evalfor(union node *n, int flags)
+{
+	struct arglist arglist;
+	union node *argp;
+	struct strlist *sp;
+	struct stackmark smark;
+
+	setstackmark(&smark);
+	arglist.lastp = &arglist.list;
+	for (argp = n->nfor.args ; argp ; argp = argp->narg.next) {
+		expandarg(argp, &arglist, EXP_FULL | EXP_TILDE | EXP_RECORD);
+		/* XXX */
+		if (evalskip)
+			goto out;
+	}
+	*arglist.lastp = NULL;
+
+	exitstatus = 0;
+	loopnest++;
+	flags &= EV_TESTED;
+	for (sp = arglist.list ; sp ; sp = sp->next) {
+		setvar(n->nfor.var, sp->text, 0);
+		evaltree(n->nfor.body, flags);
+		if (evalskip) {
+			if (evalskip == SKIPCONT && --skipcount <= 0) {
+				evalskip = 0;
+				continue;
+			}
+			if (evalskip == SKIPBREAK && --skipcount <= 0)
+				evalskip = 0;
+			break;
+		}
+	}
+	loopnest--;
+out:
+	popstackmark(&smark);
+}
+
+
+
+STATIC void
+evalcase(union node *n, int flags)
+{
+	union node *cp;
+	union node *patp;
+	struct arglist arglist;
+	struct stackmark smark;
+
+	setstackmark(&smark);
+	arglist.lastp = &arglist.list;
+	expandarg(n->ncase.expr, &arglist, EXP_TILDE);
+	exitstatus = 0;
+	for (cp = n->ncase.cases ; cp && evalskip == 0 ; cp = cp->nclist.next) {
+		for (patp = cp->nclist.pattern ; patp ; patp = patp->narg.next) {
+			if (casematch(patp, arglist.list->text)) {
+				if (evalskip == 0) {
+					evaltree(cp->nclist.body, flags);
+				}
+				goto out;
+			}
+		}
+	}
+out:
+	popstackmark(&smark);
+}
+
+
+
+/*
+ * Kick off a subshell to evaluate a tree.
+ */
+
+STATIC void
+evalsubshell(union node *n, int flags)
+{
+	struct job *jp;
+	int backgnd = (n->type == NBACKGND);
+	int status;
+
+	expredir(n->nredir.redirect);
+	if (!backgnd && flags & EV_EXIT && !trap[0])
+		goto nofork;
+	INTOFF;
+	jp = makejob(n, 1);
+	if (forkshell(jp, n, backgnd) == 0) {
+		INTON;
+		flags |= EV_EXIT;
+		if (backgnd)
+			flags &=~ EV_TESTED;
+nofork:
+		redirect(n->nredir.redirect, 0);
+		evaltreenr(n->nredir.n, flags);
+		/* never returns */
+	}
+	status = 0;
+	if (! backgnd)
+		status = waitforjob(jp);
+	exitstatus = status;
+	INTON;
+}
+
+
+
+/*
+ * Compute the names of the files in a redirection list.
+ */
+
+STATIC void
+expredir(union node *n)
+{
+	union node *redir;
+
+	for (redir = n ; redir ; redir = redir->nfile.next) {
+		struct arglist fn;
+		fn.lastp = &fn.list;
+		switch (redir->type) {
+		case NFROMTO:
+		case NFROM:
+		case NTO:
+		case NCLOBBER:
+		case NAPPEND:
+			expandarg(redir->nfile.fname, &fn, EXP_TILDE | EXP_REDIR);
+			redir->nfile.expfname = fn.list->text;
+			break;
+		case NFROMFD:
+		case NTOFD:
+			if (redir->ndup.vname) {
+				expandarg(redir->ndup.vname, &fn, EXP_FULL | EXP_TILDE);
+				fixredir(redir, fn.list->text, 1);
+			}
+			break;
+		}
+	}
+}
+
+
+
+/*
+ * Evaluate a pipeline.  All the processes in the pipeline are children
+ * of the process creating the pipeline.  (This differs from some versions
+ * of the shell, which make the last process in a pipeline the parent
+ * of all the rest.)
+ */
+
+STATIC void
+evalpipe(union node *n, int flags)
+{
+	struct job *jp;
+	struct nodelist *lp;
+	int pipelen;
+	int prevfd;
+	int pip[2];
+
+	TRACE(("evalpipe(0x%lx) called\n", (long)n));
+	pipelen = 0;
+	for (lp = n->npipe.cmdlist ; lp ; lp = lp->next)
+		pipelen++;
+	flags |= EV_EXIT;
+	INTOFF;
+	jp = makejob(n, pipelen);
+	prevfd = -1;
+	for (lp = n->npipe.cmdlist ; lp ; lp = lp->next) {
+		prehash(lp->n);
+		pip[1] = -1;
+		if (lp->next) {
+			if (pipe(pip) < 0) {
+				close(prevfd);
+				sh_error("Pipe call failed");
+			}
+		}
+		if (forkshell(jp, lp->n, n->npipe.backgnd) == 0) {
+			INTON;
+			if (pip[1] >= 0) {
+				close(pip[0]);
+			}
+			if (prevfd > 0) {
+				dup2(prevfd, 0);
+				close(prevfd);
+			}
+			if (pip[1] > 1) {
+				dup2(pip[1], 1);
+				close(pip[1]);
+			}
+			evaltreenr(lp->n, flags);
+			/* never returns */
+		}
+		if (prevfd >= 0)
+			close(prevfd);
+		prevfd = pip[0];
+		close(pip[1]);
+	}
+	if (n->npipe.backgnd == 0) {
+		exitstatus = waitforjob(jp);
+		TRACE(("evalpipe:  job done exit status %d\n", exitstatus));
+	}
+	INTON;
+}
+
+
+
+/*
+ * Execute a command inside back quotes.  If it's a builtin command, we
+ * want to save its output in a block obtained from malloc.  Otherwise
+ * we fork off a subprocess and get the output of the command via a pipe.
+ * Should be called with interrupts off.
+ */
+
+void
+evalbackcmd(union node *n, struct backcmd *result)
+{
+	int saveherefd;
+
+	result->fd = -1;
+	result->buf = NULL;
+	result->nleft = 0;
+	result->jp = NULL;
+	if (n == NULL) {
+		goto out;
+	}
+
+	saveherefd = herefd;
+	herefd = -1;
+
+#ifdef notyet
+	/*
+	 * For now we disable executing builtins in the same
+	 * context as the shell, because we are not keeping
+	 * enough state to recover from changes that are
+	 * supposed only to affect subshells. eg. echo "`cd /`"
+	 */
+	if (n->type == NCMD) {
+		struct ifsregion saveifs;
+		struct ifsregion *savelastp;
+		struct nodelist *saveargbackq;
+
+		saveifs = ifsfirst;
+		savelastp = ifslastp;
+		saveargbackq = argbackq;
+
+		exitstatus = oexitstatus;
+		evalcommand(n, EV_BACKCMD, result);
+
+		ifsfirst = saveifs;
+		ifslastp = savelastp;
+		argbackq = saveargbackq;
+	} else
+#endif
+	{
+		int pip[2];
+		struct job *jp;
+
+		if (pipe(pip) < 0)
+			sh_error("Pipe call failed");
+		jp = makejob(n, 1);
+		if (forkshell(jp, n, FORK_NOJOB) == 0) {
+			FORCEINTON;
+			close(pip[0]);
+			if (pip[1] != 1) {
+				close(1);
+				copyfd(pip[1], 1);
+				close(pip[1]);
+			}
+			eflag = 0;
+			evaltreenr(n, EV_EXIT);
+			/* NOTREACHED */
+		}
+		close(pip[1]);
+		result->fd = pip[0];
+		result->jp = jp;
+	}
+	herefd = saveherefd;
+out:
+	TRACE(("evalbackcmd done: fd=%d buf=0x%x nleft=%d jp=0x%x\n",
+		result->fd, result->buf, result->nleft, result->jp));
+}
+
+static char **
+parse_command_args(char **argv, const char **path)
+{
+	char *cp, c;
+
+	for (;;) {
+		cp = *++argv;
+		if (!cp)
+			return 0;
+		if (*cp++ != '-')
+			break;
+		if (!(c = *cp++))
+			break;
+		if (c == '-' && !*cp) {
+			argv++;
+			break;
+		}
+		do {
+			switch (c) {
+			case 'p':
+				*path = defpath;
+				break;
+			default:
+				/* run 'typecmd' for other options */
+				return 0;
+			}
+		} while ((c = *cp++));
+	}
+	return argv;
+}
+
+
+
+/*
+ * Execute a simple command.
+ */
+
+STATIC void
+#ifdef notyet
+evalcommand(union node *cmd, int flags, struct backcmd *backcmd)
+#else
+evalcommand(union node *cmd, int flags)
+#endif
+{
+	struct stackmark smark;
+	union node *argp;
+	struct arglist arglist;
+	struct arglist varlist;
+	char **argv;
+	int argc;
+	struct strlist *sp;
+#ifdef notyet
+	int pip[2];
+#endif
+	struct cmdentry cmdentry;
+	struct job *jp;
+	char *lastarg;
+	const char *path;
+	int spclbltin;
+	int execcmd;
+	int status;
+	char **nargv;
+
+	/* First expand the arguments. */
+	TRACE(("evalcommand(0x%lx, %d) called\n", (long)cmd, flags));
+	setstackmark(&smark);
+	back_exitstatus = 0;
+
+	cmdentry.cmdtype = CMDBUILTIN;
+	cmdentry.u.cmd = &bltin;
+	varlist.lastp = &varlist.list;
+	*varlist.lastp = NULL;
+	arglist.lastp = &arglist.list;
+	*arglist.lastp = NULL;
+
+	argc = 0;
+	for (argp = cmd->ncmd.args; argp; argp = argp->narg.next) {
+		struct strlist **spp;
+
+		spp = arglist.lastp;
+		expandarg(argp, &arglist, EXP_FULL | EXP_TILDE);
+		for (sp = *spp; sp; sp = sp->next)
+			argc++;
+	}
+
+	argv = nargv = stalloc(sizeof (char *) * (argc + 1));
+	for (sp = arglist.list ; sp ; sp = sp->next) {
+		TRACE(("evalcommand arg: %s\n", sp->text));
+		*nargv++ = sp->text;
+	}
+	*nargv = NULL;
+
+	lastarg = NULL;
+	if (iflag && funcnest == 0 && argc > 0)
+		lastarg = nargv[-1];
+
+	preverrout.fd = 2;
+	expredir(cmd->ncmd.redirect);
+	status = redirectsafe(cmd->ncmd.redirect, REDIR_PUSH|REDIR_SAVEFD2);
+
+	path = vpath.text;
+	for (argp = cmd->ncmd.assign; argp; argp = argp->narg.next) {
+		struct strlist **spp;
+		char *p;
+
+		spp = varlist.lastp;
+		expandarg(argp, &varlist, EXP_VARTILDE);
+
+		/*
+		 * Modify the command lookup path, if a PATH= assignment
+		 * is present
+		 */
+		p = (*spp)->text;
+		if (varequal(p, path))
+			path = p;
+	}
+
+	/* Print the command if xflag is set. */
+	if (xflag) {
+		struct output *out;
+		int sep;
+
+		out = &preverrout;
+		outstr(expandstr(ps4val()), out);
+		sep = 0;
+		sep = eprintlist(out, varlist.list, sep);
+		eprintlist(out, arglist.list, sep);
+		outcslow('\n', out);
+#ifdef FLUSHERR
+		flushout(out);
+#endif
+	}
+
+	execcmd = 0;
+	spclbltin = -1;
+
+	/* Now locate the command. */
+	if (argc) {
+		const char *oldpath;
+		int cmd_flag = DO_ERR;
+
+		path += 5;
+		oldpath = path;
+		for (;;) {
+			find_command(argv[0], &cmdentry, cmd_flag, path);
+			if (cmdentry.cmdtype == CMDUNKNOWN) {
+				status = 127;
+#ifdef FLUSHERR
+				flushout(&errout);
+#endif
+				goto bail;
+			}
+
+			/* implement bltin and command here */
+			if (cmdentry.cmdtype != CMDBUILTIN)
+				break;
+			if (spclbltin < 0)
+				spclbltin =
+					cmdentry.u.cmd->flags &
+					BUILTIN_SPECIAL
+				;
+			if (cmdentry.u.cmd == EXECCMD)
+				execcmd++;
+			if (cmdentry.u.cmd != COMMANDCMD)
+				break;
+
+			path = oldpath;
+			nargv = parse_command_args(argv, &path);
+			if (!nargv)
+				break;
+			argc -= nargv - argv;
+			argv = nargv;
+			cmd_flag |= DO_NOFUNC;
+		}
+	}
+
+	if (status) {
+		/* We have a redirection error. */
+		if (spclbltin > 0)
+			exraise(EXERROR);
+bail:
+		exitstatus = status;
+		goto out;
+	}
+
+	/* Execute the command. */
+	switch (cmdentry.cmdtype) {
+	default:
+		/* Fork off a child process if necessary. */
+		if (!(flags & EV_EXIT) || trap[0]) {
+			INTOFF;
+			jp = makejob(cmd, 1);
+			if (forkshell(jp, cmd, FORK_FG) != 0) {
+				exitstatus = waitforjob(jp);
+				INTON;
+				break;
+			}
+			FORCEINTON;
+		}
+		listsetvar(varlist.list, VEXPORT|VSTACK);
+		shellexec(argv, path, cmdentry.u.index);
+		/* NOTREACHED */
+
+	case CMDBUILTIN:
+		cmdenviron = varlist.list;
+		if (cmdenviron) {
+			struct strlist *list = cmdenviron;
+			int i = VNOSET;
+			if (spclbltin > 0 || argc == 0) {
+				i = 0;
+				if (execcmd && argc > 1)
+					i = VEXPORT;
+			}
+			listsetvar(list, i);
+		}
+		if (evalbltin(cmdentry.u.cmd, argc, argv)) {
+			int status;
+			int i, j;
+
+			i = exception;
+			if (i == EXEXIT)
+				goto raise;
+
+			status = 2;
+			j = 0;
+			if (i == EXINT)
+				j = SIGINT;
+			if (i == EXSIG)
+				j = pendingsigs;
+			if (j)
+				status = j + 128;
+			exitstatus = status;
+
+			if (i == EXINT || spclbltin > 0) {
+raise:
+				longjmp(handler->loc, 1);
+			}
+			FORCEINTON;
+		}
+		break;
+
+	case CMDFUNCTION:
+		listsetvar(varlist.list, 0);
+		if (evalfun(cmdentry.u.func, argc, argv, flags))
+			goto raise;
+		break;
+	}
+
+out:
+	popredir(execcmd);
+	if (lastarg)
+		/* dsl: I think this is intended to be used to support
+		 * '_' in 'vi' command mode during line editing...
+		 * However I implemented that within libedit itself.
+		 */
+		setvar("_", lastarg, 0);
+	popstackmark(&smark);
+}
+
+STATIC int
+evalbltin(const struct builtincmd *cmd, int argc, char **argv) {
+	char *volatile savecmdname;
+	struct jmploc *volatile savehandler;
+	struct jmploc jmploc;
+	int i;
+
+	savecmdname = commandname;
+	if ((i = setjmp(jmploc.loc)))
+		goto cmddone;
+	savehandler = handler;
+	handler = &jmploc;
+	commandname = argv[0];
+	argptr = argv + 1;
+	optptr = NULL;			/* initialize nextopt */
+	exitstatus = (*cmd->builtin)(argc, argv);
+	flushall();
+cmddone:
+	exitstatus |= outerr(out1);
+	freestdout();
+	commandname = savecmdname;
+	exsig = 0;
+	handler = savehandler;
+
+	return i;
+}
+
+STATIC int
+evalfun(struct funcnode *func, int argc, char **argv, int flags)
+{
+	volatile struct shparam saveparam;
+	struct localvar *volatile savelocalvars;
+	struct jmploc *volatile savehandler;
+	struct jmploc jmploc;
+	int e;
+
+	saveparam = shellparam;
+	savelocalvars = localvars;
+	if ((e = setjmp(jmploc.loc))) {
+		goto funcdone;
+	}
+	INTOFF;
+	savehandler = handler;
+	handler = &jmploc;
+	localvars = NULL;
+	shellparam.malloc = 0;
+	func->count++;
+	funcnest++;
+	INTON;
+	shellparam.nparam = argc - 1;
+	shellparam.p = argv + 1;
+	shellparam.optind = 1;
+	shellparam.optoff = -1;
+	evaltree(&func->n, flags & EV_TESTED);
+funcdone:
+	INTOFF;
+	funcnest--;
+	freefunc(func);
+	poplocalvars();
+	localvars = savelocalvars;
+	freeparam(&shellparam);
+	shellparam = saveparam;
+	handler = savehandler;
+	INTON;
+	evalskip &= ~SKIPFUNC;
+	return e;
+}
+
+
+/*
+ * Search for a command.  This is called before we fork so that the
+ * location of the command will be available in the parent as well as
+ * the child.  The check for "goodname" is an overly conservative
+ * check that the name will not be subject to expansion.
+ */
+
+STATIC void
+prehash(union node *n)
+{
+	struct cmdentry entry;
+
+	if (n->type == NCMD && n->ncmd.args)
+		if (goodname(n->ncmd.args->narg.text))
+			find_command(n->ncmd.args->narg.text, &entry, 0,
+				     pathval());
+}
+
+
+
+/*
+ * Builtin commands.  Builtin commands whose functions are closely
+ * tied to evaluation are implemented here.
+ */
+
+/*
+ * No command given.
+ */
+
+STATIC int
+bltincmd(int argc, char **argv)
+{
+	/*
+	 * Preserve exitstatus of a previous possible redirection
+	 * as POSIX mandates
+	 */
+	return back_exitstatus;
+}
+
+
+/*
+ * Handle break and continue commands.  Break, continue, and return are
+ * all handled by setting the evalskip flag.  The evaluation routines
+ * above all check this flag, and if it is set they start skipping
+ * commands rather than executing them.  The variable skipcount is
+ * the number of loops to break/continue, or the number of function
+ * levels to return.  (The latter is always 1.)  It should probably
+ * be an error to break out of more loops than exist, but it isn't
+ * in the standard shell so we don't make it one here.
+ */
+
+int
+breakcmd(int argc, char **argv)
+{
+	int n = argc > 1 ? number(argv[1]) : 1;
+
+	if (n <= 0)
+		sh_error(illnum, argv[1]);
+	if (n > loopnest)
+		n = loopnest;
+	if (n > 0) {
+		evalskip = (**argv == 'c')? SKIPCONT : SKIPBREAK;
+		skipcount = n;
+	}
+	return 0;
+}
+
+
+/*
+ * The return command.
+ */
+
+int
+returncmd(int argc, char **argv)
+{
+	/*
+	 * If called outside a function, do what ksh does;
+	 * skip the rest of the file.
+	 */
+	evalskip = funcnest ? SKIPFUNC : SKIPFILE;
+	return argv[1] ? number(argv[1]) : exitstatus;
+}
+
+
+int
+falsecmd(int argc, char **argv)
+{
+	return 1;
+}
+
+
+int
+truecmd(int argc, char **argv)
+{
+	return 0;
+}
+
+
+int
+execcmd(int argc, char **argv)
+{
+	if (argc > 1) {
+		iflag = 0;		/* exit on error */
+		mflag = 0;
+		optschanged();
+		shellexec(argv + 1, pathval(), 0);
+	}
+	return 0;
+}
+
+
+STATIC int
+eprintlist(struct output *out, struct strlist *sp, int sep)
+{
+	while (sp) {
+		const char *p;
+
+		p = " %s" + (1 - sep);
+		sep |= 1;
+		outfmt(out, p, sp->text);
+		sp = sp->next;
+	}
+
+	return sep;
+}
diff --git a/usr/dash/eval.h b/usr/dash/eval.h
new file mode 100644
index 0000000..005620d
--- /dev/null
+++ b/usr/dash/eval.h
@@ -0,0 +1,62 @@
+/*-
+ * Copyright (c) 1991, 1993
+ *	The Regents of the University of California.  All rights reserved.
+ * Copyright (c) 1997-2005
+ *	Herbert Xu <herbert@gondor.apana.org.au>.  All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Kenneth Almquist.
+ *
+ * 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. 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.
+ *
+ *	@(#)eval.h	8.2 (Berkeley) 5/4/95
+ */
+
+extern char *commandname;	/* currently executing command */
+extern int exitstatus;		/* exit status of last command */
+extern int back_exitstatus;	/* exit status of backquoted command */
+extern struct strlist *cmdenviron;  /* environment for builtin command */
+
+
+struct backcmd {		/* result of evalbackcmd */
+	int fd;			/* file descriptor to read from */
+	char *buf;		/* buffer */
+	int nleft;		/* number of chars in buffer */
+	struct job *jp;		/* job structure for command */
+};
+
+int evalstring(char *, int);
+union node;	/* BLETCH for ansi C */
+void evaltree(union node *, int);
+void evalbackcmd(union node *, struct backcmd *);
+
+extern int evalskip;
+
+/* reasons for skipping commands (see comment on breakcmd routine) */
+#define SKIPBREAK	(1 << 0)
+#define SKIPCONT	(1 << 1)
+#define SKIPFUNC	(1 << 2)
+#define SKIPFILE	(1 << 3)
+#define SKIPEVAL	(1 << 4)
diff --git a/usr/dash/exec.c b/usr/dash/exec.c
new file mode 100644
index 0000000..417ba8a
--- /dev/null
+++ b/usr/dash/exec.c
@@ -0,0 +1,869 @@
+/*-
+ * Copyright (c) 1991, 1993
+ *	The Regents of the University of California.  All rights reserved.
+ * Copyright (c) 1997-2005
+ *	Herbert Xu <herbert@gondor.apana.org.au>.  All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Kenneth Almquist.
+ *
+ * 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. 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 <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <paths.h>
+
+/*
+ * When commands are first encountered, they are entered in a hash table.
+ * This ensures that a full path search will not have to be done for them
+ * on each invocation.
+ *
+ * We should investigate converting to a linear search, even though that
+ * would make the command name "hash" a misnomer.
+ */
+
+#include "shell.h"
+#include "main.h"
+#include "nodes.h"
+#include "parser.h"
+#include "redir.h"
+#include "eval.h"
+#include "exec.h"
+#include "builtins.h"
+#include "var.h"
+#include "options.h"
+#include "output.h"
+#include "syntax.h"
+#include "memalloc.h"
+#include "error.h"
+#include "init.h"
+#include "mystring.h"
+#include "show.h"
+#include "jobs.h"
+#include "alias.h"
+#include "system.h"
+
+
+#define CMDTABLESIZE 31		/* should be prime */
+#define ARB 1			/* actual size determined at run time */
+
+
+
+struct tblentry {
+	struct tblentry *next;	/* next entry in hash chain */
+	union param param;	/* definition of builtin function */
+	short cmdtype;		/* index identifying command */
+	char rehash;		/* if set, cd done since entry created */
+	char cmdname[ARB];	/* name of command */
+};
+
+
+STATIC struct tblentry *cmdtable[CMDTABLESIZE];
+STATIC int builtinloc = -1;		/* index in path of %builtin, or -1 */
+
+
+STATIC void tryexec(char *, char **, char **);
+STATIC void printentry(struct tblentry *);
+STATIC void clearcmdentry(int);
+STATIC struct tblentry *cmdlookup(const char *, int);
+STATIC void delete_cmd_entry(void);
+STATIC void addcmdentry(char *, struct cmdentry *);
+STATIC int describe_command(struct output *, char *, int);
+
+
+/*
+ * Exec a program.  Never returns.  If you change this routine, you may
+ * have to change the find_command routine as well.
+ */
+
+void
+shellexec(char **argv, const char *path, int idx)
+{
+	char *cmdname;
+	int e;
+	char **envp;
+	int exerrno;
+
+	clearredir(1);
+	envp = environment();
+	if (strchr(argv[0], '/') != NULL) {
+		tryexec(argv[0], argv, envp);
+		e = errno;
+	} else {
+		e = ENOENT;
+		while ((cmdname = padvance(&path, argv[0])) != NULL) {
+			if (--idx < 0 && pathopt == NULL) {
+				tryexec(cmdname, argv, envp);
+				if (errno != ENOENT && errno != ENOTDIR)
+					e = errno;
+			}
+			stunalloc(cmdname);
+		}
+	}
+
+	/* Map to POSIX errors */
+	switch (e) {
+	case EACCES:
+		exerrno = 126;
+		break;
+	case ENOENT:
+		exerrno = 127;
+		break;
+	default:
+		exerrno = 2;
+		break;
+	}
+	exitstatus = exerrno;
+	TRACE(("shellexec failed for %s, errno %d, suppressint %d\n",
+		argv[0], e, suppressint ));
+	exerror(EXEXEC, "%s: %s", argv[0], errmsg(e, E_EXEC));
+	/* NOTREACHED */
+}
+
+
+STATIC void
+tryexec(char *cmd, char **argv, char **envp)
+{
+	int repeated = 0;
+#if !defined(BSD) && !defined(linux)
+	char *p;
+#endif
+
+repeat:
+#ifdef SYSV
+	do {
+		execve(cmd, argv, envp);
+	} while (errno == EINTR);
+#else
+	execve(cmd, argv, envp);
+#endif
+	if (repeated++) {
+		ckfree(argv);
+	} else if (errno == ENOEXEC) {
+		char **ap;
+		char **new;
+
+		for (ap = argv; *ap; ap++)
+			;
+		ap = new = ckmalloc((ap - argv + 2) * sizeof(char *));
+		*ap++ = cmd = _PATH_BSHELL;
+		while ((*ap++ = *argv++))
+			;
+		argv = new;
+		goto repeat;
+	}
+}
+
+
+
+/*
+ * Do a path search.  The variable path (passed by reference) should be
+ * set to the start of the path before the first call; padvance will update
+ * this value as it proceeds.  Successive calls to padvance will return
+ * the possible path expansions in sequence.  If an option (indicated by
+ * a percent sign) appears in the path entry then the global variable
+ * pathopt will be set to point to it; otherwise pathopt will be set to
+ * NULL.
+ */
+
+const char *pathopt;
+
+char *
+padvance(const char **path, const char *name)
+{
+	const char *p;
+	char *q;
+	const char *start;
+	size_t len;
+
+	if (*path == NULL)
+		return NULL;
+	start = *path;
+	for (p = start ; *p && *p != ':' && *p != '%' ; p++);
+	len = p - start + strlen(name) + 2;	/* "2" is for '/' and '\0' */
+	while (stackblocksize() < len)
+		growstackblock();
+	q = stackblock();
+	if (p != start) {
+		memcpy(q, start, p - start);
+		q += p - start;
+		*q++ = '/';
+	}
+	strcpy(q, name);
+	pathopt = NULL;
+	if (*p == '%') {
+		pathopt = ++p;
+		while (*p && *p != ':')  p++;
+	}
+	if (*p == ':')
+		*path = p + 1;
+	else
+		*path = NULL;
+	return stalloc(len);
+}
+
+
+
+/*** Command hashing code ***/
+
+
+int
+hashcmd(int argc, char **argv)
+{
+	struct tblentry **pp;
+	struct tblentry *cmdp;
+	int c;
+	struct cmdentry entry;
+	char *name;
+
+	while ((c = nextopt("r")) != '\0') {
+		clearcmdentry(0);
+		return 0;
+	}
+	if (*argptr == NULL) {
+		for (pp = cmdtable ; pp < &cmdtable[CMDTABLESIZE] ; pp++) {
+			for (cmdp = *pp ; cmdp ; cmdp = cmdp->next) {
+				if (cmdp->cmdtype == CMDNORMAL)
+					printentry(cmdp);
+			}
+		}
+		return 0;
+	}
+	c = 0;
+	while ((name = *argptr) != NULL) {
+		if ((cmdp = cmdlookup(name, 0)) != NULL
+		 && (cmdp->cmdtype == CMDNORMAL
+		     || (cmdp->cmdtype == CMDBUILTIN && builtinloc >= 0)))
+			delete_cmd_entry();
+		find_command(name, &entry, DO_ERR, pathval());
+		if (entry.cmdtype == CMDUNKNOWN)
+			c = 1;
+		argptr++;
+	}
+	return c;
+}
+
+
+STATIC void
+printentry(struct tblentry *cmdp)
+{
+	int idx;
+	const char *path;
+	char *name;
+
+	idx = cmdp->param.index;
+	path = pathval();
+	do {
+		name = padvance(&path, cmdp->cmdname);
+		stunalloc(name);
+	} while (--idx >= 0);
+	out1str(name);
+	out1fmt(snlfmt, cmdp->rehash ? "*" : nullstr);
+}
+
+
+
+/*
+ * Resolve a command name.  If you change this routine, you may have to
+ * change the shellexec routine as well.
+ */
+
+void
+find_command(char *name, struct cmdentry *entry, int act, const char *path)
+{
+	struct tblentry *cmdp;
+	int idx;
+	int prev;
+	char *fullname;
+	struct stat64 statb;
+	int e;
+	int updatetbl;
+	struct builtincmd *bcmd;
+
+	/* If name contains a slash, don't use PATH or hash table */
+	if (strchr(name, '/') != NULL) {
+		entry->u.index = -1;
+		if (act & DO_ABS) {
+			while (stat64(name, &statb) < 0) {
+#ifdef SYSV
+				if (errno == EINTR)
+					continue;
+#endif
+				entry->cmdtype = CMDUNKNOWN;
+				return;
+			}
+		}
+		entry->cmdtype = CMDNORMAL;
+		return;
+	}
+
+	updatetbl = (path == pathval());
+	if (!updatetbl) {
+		act |= DO_ALTPATH;
+		if (strstr(path, "%builtin") != NULL)
+			act |= DO_ALTBLTIN;
+	}
+
+	/* If name is in the table, check answer will be ok */
+	if ((cmdp = cmdlookup(name, 0)) != NULL) {
+		int bit;
+
+		switch (cmdp->cmdtype) {
+		default:
+#if DEBUG
+			abort();
+#endif
+		case CMDNORMAL:
+			bit = DO_ALTPATH;
+			break;
+		case CMDFUNCTION:
+			bit = DO_NOFUNC;
+			break;
+		case CMDBUILTIN:
+			bit = DO_ALTBLTIN;
+			break;
+		}
+		if (act & bit) {
+			updatetbl = 0;
+			cmdp = NULL;
+		} else if (cmdp->rehash == 0)
+			/* if not invalidated by cd, we're done */
+			goto success;
+	}
+
+	/* If %builtin not in path, check for builtin next */
+	bcmd = find_builtin(name);
+	if (bcmd && (bcmd->flags & BUILTIN_REGULAR || (
+		act & DO_ALTPATH ? !(act & DO_ALTBLTIN) : builtinloc <= 0
+	)))
+		goto builtin_success;
+
+	/* We have to search path. */
+	prev = -1;		/* where to start */
+	if (cmdp && cmdp->rehash) {	/* doing a rehash */
+		if (cmdp->cmdtype == CMDBUILTIN)
+			prev = builtinloc;
+		else
+			prev = cmdp->param.index;
+	}
+
+	e = ENOENT;
+	idx = -1;
+loop:
+	while ((fullname = padvance(&path, name)) != NULL) {
+		stunalloc(fullname);
+		idx++;
+		if (pathopt) {
+			if (prefix(pathopt, "builtin")) {
+				if (bcmd)
+					goto builtin_success;
+				continue;
+			} else if (!(act & DO_NOFUNC) &&
+				   prefix(pathopt, "func")) {
+				/* handled below */
+			} else {
+				/* ignore unimplemented options */
+				continue;
+			}
+		}
+		/* if rehash, don't redo absolute path names */
+		if (fullname[0] == '/' && idx <= prev) {
+			if (idx < prev)
+				continue;
+			TRACE(("searchexec \"%s\": no change\n", name));
+			goto success;
+		}
+		while (stat64(fullname, &statb) < 0) {
+#ifdef SYSV
+			if (errno == EINTR)
+				continue;
+#endif
+			if (errno != ENOENT && errno != ENOTDIR)
+				e = errno;
+			goto loop;
+		}
+		e = EACCES;	/* if we fail, this will be the error */
+		if (!S_ISREG(statb.st_mode))
+			continue;
+		if (pathopt) {		/* this is a %func directory */
+			stalloc(strlen(fullname) + 1);
+			readcmdfile(fullname);
+			if ((cmdp = cmdlookup(name, 0)) == NULL ||
+			    cmdp->cmdtype != CMDFUNCTION)
+				sh_error("%s not defined in %s", name,
+					 fullname);
+			stunalloc(fullname);
+			goto success;
+		}
+#ifdef notdef
+		/* XXX this code stops root executing stuff, and is buggy
+		   if you need a group from the group list. */
+		if (statb.st_uid == geteuid()) {
+			if ((statb.st_mode & 0100) == 0)
+				goto loop;
+		} else if (statb.st_gid == getegid()) {
+			if ((statb.st_mode & 010) == 0)
+				goto loop;
+		} else {
+			if ((statb.st_mode & 01) == 0)
+				goto loop;
+		}
+#endif
+		TRACE(("searchexec \"%s\" returns \"%s\"\n", name, fullname));
+		if (!updatetbl) {
+			entry->cmdtype = CMDNORMAL;
+			entry->u.index = idx;
+			return;
+		}
+		INTOFF;
+		cmdp = cmdlookup(name, 1);
+		cmdp->cmdtype = CMDNORMAL;
+		cmdp->param.index = idx;
+		INTON;
+		goto success;
+	}
+
+	/* We failed.  If there was an entry for this command, delete it */
+	if (cmdp && updatetbl)
+		delete_cmd_entry();
+	if (act & DO_ERR)
+		sh_warnx("%s: %s", name, errmsg(e, E_EXEC));
+	entry->cmdtype = CMDUNKNOWN;
+	return;
+
+builtin_success:
+	if (!updatetbl) {
+		entry->cmdtype = CMDBUILTIN;
+		entry->u.cmd = bcmd;
+		return;
+	}
+	INTOFF;
+	cmdp = cmdlookup(name, 1);
+	cmdp->cmdtype = CMDBUILTIN;
+	cmdp->param.cmd = bcmd;
+	INTON;
+success:
+	cmdp->rehash = 0;
+	entry->cmdtype = cmdp->cmdtype;
+	entry->u = cmdp->param;
+}
+
+
+
+/*
+ * Search the table of builtin commands.
+ */
+
+struct builtincmd *
+find_builtin(const char *name)
+{
+	struct builtincmd *bp;
+
+	bp = bsearch(
+		&name, builtincmd, NUMBUILTINS, sizeof(struct builtincmd),
+		pstrcmp
+	);
+	return bp;
+}
+
+
+
+/*
+ * Called when a cd is done.  Marks all commands so the next time they
+ * are executed they will be rehashed.
+ */
+
+void
+hashcd(void)
+{
+	struct tblentry **pp;
+	struct tblentry *cmdp;
+
+	for (pp = cmdtable ; pp < &cmdtable[CMDTABLESIZE] ; pp++) {
+		for (cmdp = *pp ; cmdp ; cmdp = cmdp->next) {
+			if (cmdp->cmdtype == CMDNORMAL || (
+				cmdp->cmdtype == CMDBUILTIN &&
+				!(cmdp->param.cmd->flags & BUILTIN_REGULAR) &&
+				builtinloc > 0
+			))
+				cmdp->rehash = 1;
+		}
+	}
+}
+
+
+
+/*
+ * Fix command hash table when PATH changed.
+ * Called before PATH is changed.  The argument is the new value of PATH;
+ * pathval() still returns the old value at this point.
+ * Called with interrupts off.
+ */
+
+void
+changepath(const char *newval)
+{
+	const char *old, *new;
+	int idx;
+	int firstchange;
+	int bltin;
+
+	old = pathval();
+	new = newval;
+	firstchange = 9999;	/* assume no change */
+	idx = 0;
+	bltin = -1;
+	for (;;) {
+		if (*old != *new) {
+			firstchange = idx;
+			if ((*old == '\0' && *new == ':')
+			 || (*old == ':' && *new == '\0'))
+				firstchange++;
+			old = new;	/* ignore subsequent differences */
+		}
+		if (*new == '\0')
+			break;
+		if (*new == '%' && bltin < 0 && prefix(new + 1, "builtin"))
+			bltin = idx;
+		if (*new == ':') {
+			idx++;
+		}
+		new++, old++;
+	}
+	if (builtinloc < 0 && bltin >= 0)
+		builtinloc = bltin;		/* zap builtins */
+	if (builtinloc >= 0 && bltin < 0)
+		firstchange = 0;
+	clearcmdentry(firstchange);
+	builtinloc = bltin;
+}
+
+
+/*
+ * Clear out command entries.  The argument specifies the first entry in
+ * PATH which has changed.
+ */
+
+STATIC void
+clearcmdentry(int firstchange)
+{
+	struct tblentry **tblp;
+	struct tblentry **pp;
+	struct tblentry *cmdp;
+
+	INTOFF;
+	for (tblp = cmdtable ; tblp < &cmdtable[CMDTABLESIZE] ; tblp++) {
+		pp = tblp;
+		while ((cmdp = *pp) != NULL) {
+			if ((cmdp->cmdtype == CMDNORMAL &&
+			     cmdp->param.index >= firstchange)
+			 || (cmdp->cmdtype == CMDBUILTIN &&
+			     builtinloc >= firstchange)) {
+				*pp = cmdp->next;
+				ckfree(cmdp);
+			} else {
+				pp = &cmdp->next;
+			}
+		}
+	}
+	INTON;
+}
+
+
+
+/*
+ * Locate a command in the command hash table.  If "add" is nonzero,
+ * add the command to the table if it is not already present.  The
+ * variable "lastcmdentry" is set to point to the address of the link
+ * pointing to the entry, so that delete_cmd_entry can delete the
+ * entry.
+ *
+ * Interrupts must be off if called with add != 0.
+ */
+
+struct tblentry **lastcmdentry;
+
+
+STATIC struct tblentry *
+cmdlookup(const char *name, int add)
+{
+	unsigned int hashval;
+	const char *p;
+	struct tblentry *cmdp;
+	struct tblentry **pp;
+
+	p = name;
+	hashval = (unsigned char)*p << 4;
+	while (*p)
+		hashval += (unsigned char)*p++;
+	hashval &= 0x7FFF;
+	pp = &cmdtable[hashval % CMDTABLESIZE];
+	for (cmdp = *pp ; cmdp ; cmdp = cmdp->next) {
+		if (equal(cmdp->cmdname, name))
+			break;
+		pp = &cmdp->next;
+	}
+	if (add && cmdp == NULL) {
+		cmdp = *pp = ckmalloc(sizeof (struct tblentry) - ARB
+					+ strlen(name) + 1);
+		cmdp->next = NULL;
+		cmdp->cmdtype = CMDUNKNOWN;
+		strcpy(cmdp->cmdname, name);
+	}
+	lastcmdentry = pp;
+	return cmdp;
+}
+
+/*
+ * Delete the command entry returned on the last lookup.
+ */
+
+STATIC void
+delete_cmd_entry(void)
+{
+	struct tblentry *cmdp;
+
+	INTOFF;
+	cmdp = *lastcmdentry;
+	*lastcmdentry = cmdp->next;
+	if (cmdp->cmdtype == CMDFUNCTION)
+		freefunc(cmdp->param.func);
+	ckfree(cmdp);
+	INTON;
+}
+
+
+
+#ifdef notdef
+void
+getcmdentry(char *name, struct cmdentry *entry)
+{
+	struct tblentry *cmdp = cmdlookup(name, 0);
+
+	if (cmdp) {
+		entry->u = cmdp->param;
+		entry->cmdtype = cmdp->cmdtype;
+	} else {
+		entry->cmdtype = CMDUNKNOWN;
+		entry->u.index = 0;
+	}
+}
+#endif
+
+
+/*
+ * Add a new command entry, replacing any existing command entry for
+ * the same name - except special builtins.
+ */
+
+STATIC void
+addcmdentry(char *name, struct cmdentry *entry)
+{
+	struct tblentry *cmdp;
+
+	cmdp = cmdlookup(name, 1);
+	if (cmdp->cmdtype == CMDFUNCTION) {
+		freefunc(cmdp->param.func);
+	}
+	cmdp->cmdtype = entry->cmdtype;
+	cmdp->param = entry->u;
+	cmdp->rehash = 0;
+}
+
+
+/*
+ * Define a shell function.
+ */
+
+void
+defun(char *name, union node *func)
+{
+	struct cmdentry entry;
+
+	INTOFF;
+	entry.cmdtype = CMDFUNCTION;
+	entry.u.func = copyfunc(func);
+	addcmdentry(name, &entry);
+	INTON;
+}
+
+
+/*
+ * Delete a function if it exists.
+ */
+
+void
+unsetfunc(const char *name)
+{
+	struct tblentry *cmdp;
+
+	if ((cmdp = cmdlookup(name, 0)) != NULL &&
+	    cmdp->cmdtype == CMDFUNCTION)
+		delete_cmd_entry();
+}
+
+/*
+ * Locate and print what a word is...
+ */
+
+int
+typecmd(int argc, char **argv)
+{
+	int i;
+	int err = 0;
+
+	for (i = 1; i < argc; i++) {
+		err |= describe_command(out1, argv[i], 1);
+	}
+	return err;
+}
+
+STATIC int
+describe_command(out, command, verbose)
+	struct output *out;
+	char *command;
+	int verbose;
+{
+	struct cmdentry entry;
+	struct tblentry *cmdp;
+	const struct alias *ap;
+	const char *path = pathval();
+
+	if (verbose) {
+		outstr(command, out);
+	}
+
+	/* First look at the keywords */
+	if (findkwd(command)) {
+		outstr(verbose ? " is a shell keyword" : command, out);
+		goto out;
+	}
+
+	/* Then look at the aliases */
+	if ((ap = lookupalias(command, 0)) != NULL) {
+		if (verbose) {
+			outfmt(out, " is an alias for %s", ap->val);
+		} else {
+			outstr("alias ", out);
+			printalias(ap);
+			return 0;
+		}
+		goto out;
+	}
+
+	/* Then check if it is a tracked alias */
+	if ((cmdp = cmdlookup(command, 0)) != NULL) {
+		entry.cmdtype = cmdp->cmdtype;
+		entry.u = cmdp->param;
+	} else {
+		/* Finally use brute force */
+		find_command(command, &entry, DO_ABS, path);
+	}
+
+	switch (entry.cmdtype) {
+	case CMDNORMAL: {
+		int j = entry.u.index;
+		char *p;
+		if (j == -1) {
+			p = command;
+		} else {
+			do {
+				p = padvance(&path, command);
+				stunalloc(p);
+			} while (--j >= 0);
+		}
+		if (verbose) {
+			outfmt(
+				out, " is%s %s",
+				cmdp ? " a tracked alias for" : nullstr, p
+			);
+		} else {
+			outstr(p, out);
+		}
+		break;
+	}
+
+	case CMDFUNCTION:
+		if (verbose) {
+			outstr(" is a shell function", out);
+		} else {
+			outstr(command, out);
+		}
+		break;
+
+	case CMDBUILTIN:
+		if (verbose) {
+			outfmt(
+				out, " is a %sshell builtin",
+				entry.u.cmd->flags & BUILTIN_SPECIAL ?
+					"special " : nullstr
+			);
+		} else {
+			outstr(command, out);
+		}
+		break;
+
+	default:
+		if (verbose) {
+			outstr(": not found\n", out);
+		}
+		return 127;
+	}
+
+out:
+	outc('\n', out);
+	return 0;
+}
+
+int
+commandcmd(argc, argv)
+	int argc;
+	char **argv;
+{
+	int c;
+	enum {
+		VERIFY_BRIEF = 1,
+		VERIFY_VERBOSE = 2,
+	} verify = 0;
+
+	while ((c = nextopt("pvV")) != '\0')
+		if (c == 'V')
+			verify |= VERIFY_VERBOSE;
+		else if (c == 'v')
+			verify |= VERIFY_BRIEF;
+#ifdef DEBUG
+		else if (c != 'p')
+			abort();
+#endif
+
+	if (verify)
+		return describe_command(out1, *argptr, verify - VERIFY_BRIEF);
+
+	return 0;
+}
diff --git a/usr/dash/exec.h b/usr/dash/exec.h
new file mode 100644
index 0000000..daa6f10
--- /dev/null
+++ b/usr/dash/exec.h
@@ -0,0 +1,77 @@
+/*-
+ * Copyright (c) 1991, 1993
+ *	The Regents of the University of California.  All rights reserved.
+ * Copyright (c) 1997-2005
+ *	Herbert Xu <herbert@gondor.apana.org.au>.  All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Kenneth Almquist.
+ *
+ * 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. 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.
+ *
+ *	@(#)exec.h	8.3 (Berkeley) 6/8/95
+ */
+
+/* values of cmdtype */
+#define CMDUNKNOWN	-1	/* no entry in table for command */
+#define CMDNORMAL	0	/* command is an executable program */
+#define CMDFUNCTION	1	/* command is a shell function */
+#define CMDBUILTIN	2	/* command is a shell builtin */
+
+
+struct cmdentry {
+	int cmdtype;
+	union param {
+		int index;
+		const struct builtincmd *cmd;
+		struct funcnode *func;
+	} u;
+};
+
+
+/* action to find_command() */
+#define DO_ERR		0x01	/* prints errors */
+#define DO_ABS		0x02	/* checks absolute paths */
+#define DO_NOFUNC	0x04	/* don't return shell functions, for command */
+#define DO_ALTPATH	0x08	/* using alternate path */
+#define DO_ALTBLTIN	0x20	/* %builtin in alt. path */
+
+extern const char *pathopt;	/* set by padvance */
+
+void shellexec(char **, const char *, int)
+    __attribute__((__noreturn__));
+char *padvance(const char **, const char *);
+int hashcmd(int, char **);
+void find_command(char *, struct cmdentry *, int, const char *);
+struct builtincmd *find_builtin(const char *);
+void hashcd(void);
+void changepath(const char *);
+#ifdef notdef
+void getcmdentry(char *, struct cmdentry *);
+#endif
+void defun(char *, union node *);
+void unsetfunc(const char *);
+int typecmd(int, char **);
+int commandcmd(int, char **);
diff --git a/usr/dash/expand.c b/usr/dash/expand.c
new file mode 100644
index 0000000..2eb726e
--- /dev/null
+++ b/usr/dash/expand.c
@@ -0,0 +1,1744 @@
+/*-
+ * Copyright (c) 1991, 1993
+ *	The Regents of the University of California.  All rights reserved.
+ * Copyright (c) 1997-2005
+ *	Herbert Xu <herbert@gondor.apana.org.au>.  All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Kenneth Almquist.
+ *
+ * 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. 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 <sys/types.h>
+#include <sys/time.h>
+#include <sys/stat.h>
+#include <dirent.h>
+#include <unistd.h>
+#ifdef HAVE_GETPWNAM
+#include <pwd.h>
+#endif
+#include <stdlib.h>
+#include <stdio.h>
+#include <limits.h>
+#include <string.h>
+#if defined(__GLIBC__)
+#if !defined(FNMATCH_BROKEN)
+#include <fnmatch.h>
+#if !defined(GLOB_BROKEN)
+#include <glob.h>
+#endif
+#else
+#include <ctype.h>
+#endif
+#endif
+
+/*
+ * Routines to expand arguments to commands.  We have to deal with
+ * backquotes, shell variables, and file metacharacters.
+ */
+
+#include "shell.h"
+#include "main.h"
+#include "nodes.h"
+#include "eval.h"
+#include "expand.h"
+#include "syntax.h"
+#include "parser.h"
+#include "jobs.h"
+#include "options.h"
+#include "var.h"
+#include "output.h"
+#include "memalloc.h"
+#include "error.h"
+#include "mystring.h"
+#include "show.h"
+#include "system.h"
+
+/*
+ * _rmescape() flags
+ */
+#define RMESCAPE_ALLOC	0x1	/* Allocate a new string */
+#define RMESCAPE_GLOB	0x2	/* Add backslashes for glob */
+#define RMESCAPE_QUOTED	0x4	/* Remove CTLESC unless in quotes */
+#define RMESCAPE_GROW	0x8	/* Grow strings instead of stalloc */
+#define RMESCAPE_HEAP	0x10	/* Malloc strings instead of stalloc */
+
+/* Add CTLESC when necessary. */
+#define QUOTES_ESC	(EXP_FULL | EXP_CASE)
+/* Do not skip NUL characters. */
+#define QUOTES_KEEPNUL	EXP_TILDE
+
+/*
+ * Structure specifying which parts of the string should be searched
+ * for IFS characters.
+ */
+
+struct ifsregion {
+	struct ifsregion *next;	/* next region in list */
+	int begoff;		/* offset of start of region */
+	int endoff;		/* offset of end of region */
+	int nulonly;		/* search for nul bytes only */
+};
+
+/* output of current string */
+static char *expdest;
+/* list of back quote expressions */
+static struct nodelist *argbackq;
+/* first struct in list of ifs regions */
+static struct ifsregion ifsfirst;
+/* last struct in list */
+static struct ifsregion *ifslastp;
+/* holds expanded arg list */
+static struct arglist exparg;
+
+STATIC void argstr(char *, int);
+STATIC char *exptilde(char *, char *, int);
+STATIC void expbackq(union node *, int, int);
+STATIC const char *subevalvar(char *, char *, int, int, int, int, int);
+STATIC char *evalvar(char *, int);
+STATIC size_t strtodest(const char *, const char *, int);
+STATIC void memtodest(const char *, size_t, const char *, int);
+STATIC ssize_t varvalue(char *, int, int);
+STATIC void recordregion(int, int, int);
+STATIC void removerecordregions(int);
+STATIC void ifsbreakup(char *, struct arglist *);
+STATIC void ifsfree(void);
+STATIC void expandmeta(struct strlist *, int);
+#if defined(__GLIBC__) && !defined(FNMATCH_BROKEN) && !defined(GLOB_BROKEN)
+STATIC void addglob(const glob_t *);
+#else
+STATIC void expmeta(char *, char *);
+#endif
+STATIC void addfname(char *);
+#if !(defined(__GLIBC__) && !defined(FNMATCH_BROKEN) && !defined(GLOB_BROKEN))
+STATIC struct strlist *expsort(struct strlist *);
+STATIC struct strlist *msort(struct strlist *, int);
+#endif
+STATIC int patmatch(char *, const char *);
+#if !defined(__GLIBC__) || defined(FNMATCH_BROKEN)
+STATIC int pmatch(const char *, const char *);
+#else
+#define pmatch(a, b) !fnmatch((a), (b), 0)
+#endif
+STATIC int cvtnum(long);
+STATIC size_t esclen(const char *, const char *);
+STATIC char *scanleft(char *, char *, char *, char *, int, int);
+STATIC char *scanright(char *, char *, char *, char *, int, int);
+STATIC void varunset(const char *, const char *, const char *, int)
+	__attribute__((__noreturn__));
+
+
+/*
+ * Prepare a pattern for a glob(3) call.
+ *
+ * Returns an stalloced string.
+ */
+
+STATIC inline char *
+preglob(const char *pattern, int quoted, int flag) {
+	flag |= RMESCAPE_GLOB;
+	if (quoted) {
+		flag |= RMESCAPE_QUOTED;
+	}
+	return _rmescapes((char *)pattern, flag);
+}
+
+
+STATIC size_t
+esclen(const char *start, const char *p) {
+	size_t esc = 0;
+
+	while (p > start && *--p == (char)CTLESC) {
+		esc++;
+	}
+	return esc;
+}
+
+
+static inline const char *getpwhome(const char *name)
+{
+#ifdef HAVE_GETPWNAM
+	struct passwd *pw = getpwnam(name);
+	return pw ? pw->pw_dir : 0;
+#else
+	return 0;
+#endif
+}
+
+
+/*
+ * Expand shell variables and backquotes inside a here document.
+ */
+
+void
+expandhere(union node *arg, int fd)
+{
+	herefd = fd;
+	expandarg(arg, (struct arglist *)NULL, 0);
+	xwrite(fd, stackblock(), expdest - (char *)stackblock());
+}
+
+
+/*
+ * Perform variable substitution and command substitution on an argument,
+ * placing the resulting list of arguments in arglist.  If EXP_FULL is true,
+ * perform splitting and file name expansion.  When arglist is NULL, perform
+ * here document expansion.
+ */
+
+void
+expandarg(union node *arg, struct arglist *arglist, int flag)
+{
+	struct strlist *sp;
+	char *p;
+
+	argbackq = arg->narg.backquote;
+	STARTSTACKSTR(expdest);
+	ifsfirst.next = NULL;
+	ifslastp = NULL;
+	argstr(arg->narg.text, flag);
+	p = _STPUTC('\0', expdest);
+	expdest = p - 1;
+	if (arglist == NULL) {
+		return;			/* here document expanded */
+	}
+	p = grabstackstr(p);
+	exparg.lastp = &exparg.list;
+	/*
+	 * TODO - EXP_REDIR
+	 */
+	if (flag & EXP_FULL) {
+		ifsbreakup(p, &exparg);
+		*exparg.lastp = NULL;
+		exparg.lastp = &exparg.list;
+		expandmeta(exparg.list, flag);
+	} else {
+		if (flag & EXP_REDIR) /*XXX - for now, just remove escapes */
+			rmescapes(p);
+		sp = (struct strlist *)stalloc(sizeof (struct strlist));
+		sp->text = p;
+		*exparg.lastp = sp;
+		exparg.lastp = &sp->next;
+	}
+	if (ifsfirst.next)
+		ifsfree();
+	*exparg.lastp = NULL;
+	if (exparg.list) {
+		*arglist->lastp = exparg.list;
+		arglist->lastp = exparg.lastp;
+	}
+}
+
+
+
+/*
+ * Perform variable and command substitution.  If EXP_FULL is set, output CTLESC
+ * characters to allow for further processing.  Otherwise treat
+ * $@ like $* since no splitting will be performed.
+ */
+
+STATIC void
+argstr(char *p, int flag)
+{
+	static const char spclchars[] = {
+		'=',
+		':',
+		CTLQUOTEMARK,
+		CTLENDVAR,
+		CTLESC,
+		CTLVAR,
+		CTLBACKQ,
+		CTLBACKQ | CTLQUOTE,
+		CTLENDARI,
+		0
+	};
+	const char *reject = spclchars;
+	int c;
+	int quotes = flag & QUOTES_ESC;
+	int breakall = flag & EXP_WORD;
+	int inquotes;
+	size_t length;
+	int startloc;
+
+	if (!(flag & EXP_VARTILDE)) {
+		reject += 2;
+	} else if (flag & EXP_VARTILDE2) {
+		reject++;
+	}
+	inquotes = 0;
+	length = 0;
+	if (flag & EXP_TILDE) {
+		char *q;
+
+		flag &= ~EXP_TILDE;
+tilde:
+		q = p;
+		if (*q == (char)CTLESC && (flag & EXP_QWORD))
+			q++;
+		if (*q == '~')
+			p = exptilde(p, q, flag);
+	}
+start:
+	startloc = expdest - (char *)stackblock();
+	for (;;) {
+		length += strcspn(p + length, reject);
+		c = (signed char)p[length];
+		if (c && (!(c & 0x80) || c == CTLENDARI)) {
+			/* c == '=' || c == ':' || c == CTLENDARI */
+			length++;
+		}
+		if (length > 0) {
+			int newloc;
+			expdest = stnputs(p, length, expdest);
+			newloc = expdest - (char *)stackblock();
+			if (breakall && !inquotes && newloc > startloc) {
+				recordregion(startloc, newloc, 0);
+			}
+			startloc = newloc;
+		}
+		p += length + 1;
+		length = 0;
+
+		switch (c) {
+		case '\0':
+			goto breakloop;
+		case '=':
+			if (flag & EXP_VARTILDE2) {
+				p--;
+				continue;
+			}
+			flag |= EXP_VARTILDE2;
+			reject++;
+			/* fall through */
+		case ':':
+			/*
+			 * sort of a hack - expand tildes in variable
+			 * assignments (after the first '=' and after ':'s).
+			 */
+			if (*--p == '~') {
+				goto tilde;
+			}
+			continue;
+		}
+
+		switch (c) {
+		case CTLENDVAR: /* ??? */
+			goto breakloop;
+		case CTLQUOTEMARK:
+			/* "$@" syntax adherence hack */
+			if (
+				!inquotes &&
+				!memcmp(p, dolatstr, DOLATSTRLEN) &&
+				(p[4] == (char)CTLQUOTEMARK || (
+					p[4] == (char)CTLENDVAR &&
+					p[5] == (char)CTLQUOTEMARK
+				))
+			) {
+				p = evalvar(p + 1, flag) + 1;
+				goto start;
+			}
+			inquotes = !inquotes;
+addquote:
+			if (quotes) {
+				p--;
+				length++;
+				startloc++;
+			}
+			break;
+		case CTLESC:
+			startloc++;
+			length++;
+			goto addquote;
+		case CTLVAR:
+			p = evalvar(p, flag);
+			goto start;
+		case CTLBACKQ:
+			c = 0;
+		case CTLBACKQ|CTLQUOTE:
+			expbackq(argbackq->n, c, quotes);
+			argbackq = argbackq->next;
+			goto start;
+		case CTLENDARI:
+			p--;
+			expari(quotes);
+			goto start;
+		}
+	}
+breakloop:
+	;
+}
+
+STATIC char *
+exptilde(char *startp, char *p, int flag)
+{
+	signed char c;
+	char *name;
+	const char *home;
+	int quotes = flag & QUOTES_ESC;
+	int startloc;
+
+	name = p + 1;
+
+	while ((c = *++p) != '\0') {
+		switch(c) {
+		case CTLESC:
+			return (startp);
+		case CTLQUOTEMARK:
+			return (startp);
+		case ':':
+			if (flag & EXP_VARTILDE)
+				goto done;
+			break;
+		case '/':
+		case CTLENDVAR:
+			goto done;
+		}
+	}
+done:
+	*p = '\0';
+	if (*name == '\0') {
+		home = lookupvar(homestr);
+	} else {
+		home = getpwhome(name);
+	}
+	if (!home || !*home)
+		goto lose;
+	*p = c;
+	startloc = expdest - (char *)stackblock();
+	strtodest(home, SQSYNTAX, quotes);
+	recordregion(startloc, expdest - (char *)stackblock(), 0);
+	return (p);
+lose:
+	*p = c;
+	return (startp);
+}
+
+
+STATIC void
+removerecordregions(int endoff)
+{
+	if (ifslastp == NULL)
+		return;
+
+	if (ifsfirst.endoff > endoff) {
+		while (ifsfirst.next != NULL) {
+			struct ifsregion *ifsp;
+			INTOFF;
+			ifsp = ifsfirst.next->next;
+			ckfree(ifsfirst.next);
+			ifsfirst.next = ifsp;
+			INTON;
+		}
+		if (ifsfirst.begoff > endoff)
+			ifslastp = NULL;
+		else {
+			ifslastp = &ifsfirst;
+			ifsfirst.endoff = endoff;
+		}
+		return;
+	}
+
+	ifslastp = &ifsfirst;
+	while (ifslastp->next && ifslastp->next->begoff < endoff)
+		ifslastp=ifslastp->next;
+	while (ifslastp->next != NULL) {
+		struct ifsregion *ifsp;
+		INTOFF;
+		ifsp = ifslastp->next->next;
+		ckfree(ifslastp->next);
+		ifslastp->next = ifsp;
+		INTON;
+	}
+	if (ifslastp->endoff > endoff)
+		ifslastp->endoff = endoff;
+}
+
+
+/*
+ * Expand arithmetic expression.  Backup to start of expression,
+ * evaluate, place result in (backed up) result, adjust string position.
+ */
+void
+expari(int quotes)
+{
+	char *p, *start;
+	int begoff;
+	int flag;
+	int len;
+
+	/*	ifsfree(); */
+
+	/*
+	 * This routine is slightly over-complicated for
+	 * efficiency.  Next we scan backwards looking for the
+	 * start of arithmetic.
+	 */
+	start = stackblock();
+	p = expdest - 1;
+	*p = '\0';
+	p--;
+	do {
+		int esc;
+
+		while (*p != (char)CTLARI) {
+			p--;
+#ifdef DEBUG
+			if (p < start) {
+				sh_error("missing CTLARI (shouldn't happen)");
+			}
+#endif
+		}
+
+		esc = esclen(start, p);
+		if (!(esc % 2)) {
+			break;
+		}
+
+		p -= esc + 1;
+	} while (1);
+
+	begoff = p - start;
+
+	removerecordregions(begoff);
+
+	flag = p[1];
+
+	expdest = p;
+
+	if (quotes)
+		rmescapes(p + 2);
+
+	len = cvtnum(arith(p + 2));
+
+	if (flag != '"')
+		recordregion(begoff, begoff + len, 0);
+}
+
+
+/*
+ * Expand stuff in backwards quotes.
+ */
+
+STATIC void
+expbackq(union node *cmd, int quoted, int quotes)
+{
+	struct backcmd in;
+	int i;
+	char buf[128];
+	char *p;
+	char *dest;
+	int startloc;
+	char const *syntax = quoted? DQSYNTAX : BASESYNTAX;
+	struct stackmark smark;
+
+	INTOFF;
+	setstackmark(&smark);
+	dest = expdest;
+	startloc = dest - (char *)stackblock();
+	grabstackstr(dest);
+	evalbackcmd(cmd, (struct backcmd *) &in);
+	popstackmark(&smark);
+
+	p = in.buf;
+	i = in.nleft;
+	if (i == 0)
+		goto read;
+	for (;;) {
+		memtodest(p, i, syntax, quotes);
+read:
+		if (in.fd < 0)
+			break;
+		do {
+			i = read(in.fd, buf, sizeof buf);
+		} while (i < 0 && errno == EINTR);
+		TRACE(("expbackq: read returns %d\n", i));
+		if (i <= 0)
+			break;
+		p = buf;
+	}
+
+	if (in.buf)
+		ckfree(in.buf);
+	if (in.fd >= 0) {
+		close(in.fd);
+		back_exitstatus = waitforjob(in.jp);
+	}
+	INTON;
+
+	/* Eat all trailing newlines */
+	dest = expdest;
+	for (; dest > (char *)stackblock() && dest[-1] == '\n';)
+		STUNPUTC(dest);
+	expdest = dest;
+
+	if (quoted == 0)
+		recordregion(startloc, dest - (char *)stackblock(), 0);
+	TRACE(("evalbackq: size=%d: \"%.*s\"\n",
+		(dest - (char *)stackblock()) - startloc,
+		(dest - (char *)stackblock()) - startloc,
+		stackblock() + startloc));
+}
+
+
+STATIC char *
+scanleft(
+	char *startp, char *rmesc, char *rmescend, char *str, int quotes,
+	int zero
+) {
+	char *loc;
+	char *loc2;
+	char c;
+
+	loc = startp;
+	loc2 = rmesc;
+	do {
+		int match;
+		const char *s = loc2;
+		c = *loc2;
+		if (zero) {
+			*loc2 = '\0';
+			s = rmesc;
+		}
+		match = pmatch(str, s);
+		*loc2 = c;
+		if (match)
+			return loc;
+		if (quotes && *loc == (char)CTLESC)
+			loc++;
+		loc++;
+		loc2++;
+	} while (c);
+	return 0;
+}
+
+
+STATIC char *
+scanright(
+	char *startp, char *rmesc, char *rmescend, char *str, int quotes,
+	int zero
+) {
+	int esc = 0;
+	char *loc;
+	char *loc2;
+
+	for (loc = str - 1, loc2 = rmescend; loc >= startp; loc2--) {
+		int match;
+		char c = *loc2;
+		const char *s = loc2;
+		if (zero) {
+			*loc2 = '\0';
+			s = rmesc;
+		}
+		match = pmatch(str, s);
+		*loc2 = c;
+		if (match)
+			return loc;
+		loc--;
+		if (quotes) {
+			if (--esc < 0) {
+				esc = esclen(startp, loc);
+			}
+			if (esc % 2) {
+				esc--;
+				loc--;
+			}
+		}
+	}
+	return 0;
+}
+
+STATIC const char *
+subevalvar(char *p, char *str, int strloc, int subtype, int startloc, int varflags, int quotes)
+{
+	char *startp;
+	char *loc;
+	int saveherefd = herefd;
+	struct nodelist *saveargbackq = argbackq;
+	int amount;
+	char *rmesc, *rmescend;
+	int zero;
+	char *(*scan)(char *, char *, char *, char *, int , int);
+
+	herefd = -1;
+	argstr(p, subtype != VSASSIGN && subtype != VSQUESTION ? EXP_CASE : 0);
+	STPUTC('\0', expdest);
+	herefd = saveherefd;
+	argbackq = saveargbackq;
+	startp = stackblock() + startloc;
+
+	switch (subtype) {
+	case VSASSIGN:
+		setvar(str, startp, 0);
+		amount = startp - expdest;
+		STADJUST(amount, expdest);
+		return startp;
+
+	case VSQUESTION:
+		varunset(p, str, startp, varflags);
+		/* NOTREACHED */
+	}
+
+	subtype -= VSTRIMRIGHT;
+#ifdef DEBUG
+	if (subtype < 0 || subtype > 3)
+		abort();
+#endif
+
+	rmesc = startp;
+	rmescend = stackblock() + strloc;
+	if (quotes) {
+		rmesc = _rmescapes(startp, RMESCAPE_ALLOC | RMESCAPE_GROW);
+		if (rmesc != startp) {
+			rmescend = expdest;
+			startp = stackblock() + startloc;
+		}
+	}
+	rmescend--;
+	str = stackblock() + strloc;
+	preglob(str, varflags & VSQUOTE, 0);
+
+	/* zero = subtype == VSTRIMLEFT || subtype == VSTRIMLEFTMAX */
+	zero = subtype >> 1;
+	/* VSTRIMLEFT/VSTRIMRIGHTMAX -> scanleft */
+	scan = (subtype & 1) ^ zero ? scanleft : scanright;
+
+	loc = scan(startp, rmesc, rmescend, str, quotes, zero);
+	if (loc) {
+		if (zero) {
+			memmove(startp, loc, str - loc);
+			loc = startp + (str - loc) - 1;
+		}
+		*loc = '\0';
+		amount = loc - expdest;
+		STADJUST(amount, expdest);
+	}
+	return loc;
+}
+
+
+/*
+ * Expand a variable, and return a pointer to the next character in the
+ * input string.
+ */
+STATIC char *
+evalvar(char *p, int flag)
+{
+	int subtype;
+	int varflags;
+	char *var;
+	int patloc;
+	int c;
+	int startloc;
+	ssize_t varlen;
+	int easy;
+	int quotes;
+	int quoted;
+
+	quotes = flag & QUOTES_ESC;
+	varflags = *p++;
+	subtype = varflags & VSTYPE;
+	quoted = varflags & VSQUOTE;
+	var = p;
+	easy = (!quoted || (*var == '@' && shellparam.nparam));
+	startloc = expdest - (char *)stackblock();
+	p = strchr(p, '=') + 1;
+
+again:
+	varlen = varvalue(var, varflags, flag);
+	if (varflags & VSNUL)
+		varlen--;
+
+	if (subtype == VSPLUS) {
+		varlen = -1 - varlen;
+		goto vsplus;
+	}
+
+	if (subtype == VSMINUS) {
+vsplus:
+		if (varlen < 0) {
+			argstr(
+				p, flag | EXP_TILDE |
+					(quoted ?  EXP_QWORD : EXP_WORD)
+			);
+			goto end;
+		}
+		if (easy)
+			goto record;
+		goto end;
+	}
+
+	if (subtype == VSASSIGN || subtype == VSQUESTION) {
+		if (varlen < 0) {
+			if (subevalvar(p, var, 0, subtype, startloc,
+				       varflags, 0)) {
+				varflags &= ~VSNUL;
+				/*
+				 * Remove any recorded regions beyond
+				 * start of variable
+				 */
+				removerecordregions(startloc);
+				goto again;
+			}
+			goto end;
+		}
+		if (easy)
+			goto record;
+		goto end;
+	}
+
+	if (varlen < 0 && uflag)
+		varunset(p, var, 0, 0);
+
+	if (subtype == VSLENGTH) {
+		cvtnum(varlen > 0 ? varlen : 0);
+		goto record;
+	}
+
+	if (subtype == VSNORMAL) {
+		if (!easy)
+			goto end;
+record:
+		recordregion(startloc, expdest - (char *)stackblock(), quoted);
+		goto end;
+	}
+
+#ifdef DEBUG
+	switch (subtype) {
+	case VSTRIMLEFT:
+	case VSTRIMLEFTMAX:
+	case VSTRIMRIGHT:
+	case VSTRIMRIGHTMAX:
+		break;
+	default:
+		abort();
+	}
+#endif
+
+	if (varlen >= 0) {
+		/*
+		 * Terminate the string and start recording the pattern
+		 * right after it
+		 */
+		STPUTC('\0', expdest);
+		patloc = expdest - (char *)stackblock();
+		if (subevalvar(p, NULL, patloc, subtype,
+			       startloc, varflags, quotes) == 0) {
+			int amount = expdest - (
+				(char *)stackblock() + patloc - 1
+			);
+			STADJUST(-amount, expdest);
+		}
+		/* Remove any recorded regions beyond start of variable */
+		removerecordregions(startloc);
+		goto record;
+	}
+
+end:
+	if (subtype != VSNORMAL) {	/* skip to end of alternative */
+		int nesting = 1;
+		for (;;) {
+			if ((c = (signed char)*p++) == CTLESC)
+				p++;
+			else if (c == CTLBACKQ || c == (CTLBACKQ|CTLQUOTE)) {
+				if (varlen >= 0)
+					argbackq = argbackq->next;
+			} else if (c == CTLVAR) {
+				if ((*p++ & VSTYPE) != VSNORMAL)
+					nesting++;
+			} else if (c == CTLENDVAR) {
+				if (--nesting == 0)
+					break;
+			}
+		}
+	}
+	return p;
+}
+
+
+/*
+ * Put a string on the stack.
+ */
+
+STATIC void
+memtodest(const char *p, size_t len, const char *syntax, int quotes) {
+	char *q;
+
+	if (unlikely(!len))
+		return;
+
+	q = makestrspace(len * 2, expdest);
+
+	do {
+		int c = (signed char)*p++;
+		if (c) {
+			if ((quotes & QUOTES_ESC) &&
+			    (syntax[c] == CCTL || syntax[c] == CBACK))
+				USTPUTC(CTLESC, q);
+		} else if (!(quotes & QUOTES_KEEPNUL))
+			continue;
+		USTPUTC(c, q);
+	} while (--len);
+
+	expdest = q;
+}
+
+
+STATIC size_t
+strtodest(p, syntax, quotes)
+	const char *p;
+	const char *syntax;
+	int quotes;
+{
+	size_t len = strlen(p);
+	memtodest(p, len, syntax, quotes);
+	return len;
+}
+
+
+
+/*
+ * Add the value of a specialized variable to the stack string.
+ */
+
+STATIC ssize_t
+varvalue(char *name, int varflags, int flags)
+{
+	int num;
+	char *p;
+	int i;
+	int sep;
+	char sepc;
+	char **ap;
+	char const *syntax;
+	int quoted = varflags & VSQUOTE;
+	int subtype = varflags & VSTYPE;
+	int discard = subtype == VSPLUS || subtype == VSLENGTH;
+	int quotes = (discard ? 0 : (flags & QUOTES_ESC)) | QUOTES_KEEPNUL;
+	ssize_t len = 0;
+
+	sep = quoted ? ((flags & EXP_FULL) << CHAR_BIT) : 0;
+	syntax = quoted ? DQSYNTAX : BASESYNTAX;
+
+	switch (*name) {
+	case '$':
+		num = rootpid;
+		goto numvar;
+	case '?':
+		num = exitstatus;
+		goto numvar;
+	case '#':
+		num = shellparam.nparam;
+		goto numvar;
+	case '!':
+		num = backgndpid;
+		if (num == 0)
+			return -1;
+numvar:
+		len = cvtnum(num);
+		break;
+	case '-':
+		p = makestrspace(NOPTS, expdest);
+		for (i = NOPTS - 1; i >= 0; i--) {
+			if (optlist[i]) {
+				USTPUTC(optletters[i], p);
+				len++;
+			}
+		}
+		expdest = p;
+		break;
+	case '@':
+		if (sep)
+			goto param;
+		/* fall through */
+	case '*':
+		sep = ifsset() ? ifsval()[0] : ' ';
+param:
+		if (!(ap = shellparam.p))
+			return -1;
+		sepc = sep;
+		while ((p = *ap++)) {
+			len += strtodest(p, syntax, quotes);
+
+			if (*ap && sep) {
+				len++;
+				memtodest(&sepc, 1, syntax, quotes);
+			}
+		}
+		break;
+	case '0':
+	case '1':
+	case '2':
+	case '3':
+	case '4':
+	case '5':
+	case '6':
+	case '7':
+	case '8':
+	case '9':
+		num = atoi(name);
+		if (num < 0 || num > shellparam.nparam)
+			return -1;
+		p = num ? shellparam.p[num - 1] : arg0;
+		goto value;
+	default:
+		p = lookupvar(name);
+value:
+		if (!p)
+			return -1;
+
+		len = strtodest(p, syntax, quotes);
+		break;
+	}
+
+	if (discard)
+		STADJUST(-len, expdest);
+	return len;
+}
+
+
+
+/*
+ * Record the fact that we have to scan this region of the
+ * string for IFS characters.
+ */
+
+STATIC void
+recordregion(int start, int end, int nulonly)
+{
+	struct ifsregion *ifsp;
+
+	if (ifslastp == NULL) {
+		ifsp = &ifsfirst;
+	} else {
+		INTOFF;
+		ifsp = (struct ifsregion *)ckmalloc(sizeof (struct ifsregion));
+		ifsp->next = NULL;
+		ifslastp->next = ifsp;
+		INTON;
+	}
+	ifslastp = ifsp;
+	ifslastp->begoff = start;
+	ifslastp->endoff = end;
+	ifslastp->nulonly = nulonly;
+}
+
+
+
+/*
+ * Break the argument string into pieces based upon IFS and add the
+ * strings to the argument list.  The regions of the string to be
+ * searched for IFS characters have been stored by recordregion.
+ */
+STATIC void
+ifsbreakup(char *string, struct arglist *arglist)
+{
+	struct ifsregion *ifsp;
+	struct strlist *sp;
+	char *start;
+	char *p;
+	char *q;
+	const char *ifs, *realifs;
+	int ifsspc;
+	int nulonly;
+
+
+	start = string;
+	if (ifslastp != NULL) {
+		ifsspc = 0;
+		nulonly = 0;
+		realifs = ifsset() ? ifsval() : defifs;
+		ifsp = &ifsfirst;
+		do {
+			p = string + ifsp->begoff;
+			nulonly = ifsp->nulonly;
+			ifs = nulonly ? nullstr : realifs;
+			ifsspc = 0;
+			while (p < string + ifsp->endoff) {
+				q = p;
+				if (*p == (char)CTLESC)
+					p++;
+				if (strchr(ifs, *p)) {
+					if (!nulonly)
+						ifsspc = (strchr(defifs, *p) != NULL);
+					/* Ignore IFS whitespace at start */
+					if (q == start && ifsspc) {
+						p++;
+						start = p;
+						continue;
+					}
+					*q = '\0';
+					sp = (struct strlist *)stalloc(sizeof *sp);
+					sp->text = start;
+					*arglist->lastp = sp;
+					arglist->lastp = &sp->next;
+					p++;
+					if (!nulonly) {
+						for (;;) {
+							if (p >= string + ifsp->endoff) {
+								break;
+							}
+							q = p;
+							if (*p == (char)CTLESC)
+								p++;
+							if (strchr(ifs, *p) == NULL ) {
+								p = q;
+								break;
+							} else if (strchr(defifs, *p) == NULL) {
+								if (ifsspc) {
+									p++;
+									ifsspc = 0;
+								} else {
+									p = q;
+									break;
+								}
+							} else
+								p++;
+						}
+					}
+					start = p;
+				} else
+					p++;
+			}
+		} while ((ifsp = ifsp->next) != NULL);
+		if (nulonly)
+			goto add;
+	}
+
+	if (!*start)
+		return;
+
+add:
+	sp = (struct strlist *)stalloc(sizeof *sp);
+	sp->text = start;
+	*arglist->lastp = sp;
+	arglist->lastp = &sp->next;
+}
+
+STATIC void
+ifsfree(void)
+{
+	struct ifsregion *p;
+
+	INTOFF;
+	p = ifsfirst.next;
+	do {
+		struct ifsregion *ifsp;
+		ifsp = p->next;
+		ckfree(p);
+		p = ifsp;
+	} while (p);
+	ifslastp = NULL;
+	ifsfirst.next = NULL;
+	INTON;
+}
+
+
+
+/*
+ * Expand shell metacharacters.  At this point, the only control characters
+ * should be escapes.  The results are stored in the list exparg.
+ */
+
+#if defined(__GLIBC__) && !defined(FNMATCH_BROKEN) && !defined(GLOB_BROKEN)
+STATIC void
+expandmeta(str, flag)
+	struct strlist *str;
+	int flag;
+{
+	/* TODO - EXP_REDIR */
+
+	while (str) {
+		const char *p;
+		glob_t pglob;
+		int i;
+
+		if (fflag)
+			goto nometa;
+		INTOFF;
+		p = preglob(str->text, 0, RMESCAPE_ALLOC | RMESCAPE_HEAP);
+		i = glob(p, GLOB_NOMAGIC, 0, &pglob);
+		if (p != str->text)
+			ckfree(p);
+		switch (i) {
+		case 0:
+			if (!(pglob.gl_flags & GLOB_MAGCHAR))
+				goto nometa2;
+			addglob(&pglob);
+			globfree(&pglob);
+			INTON;
+			break;
+		case GLOB_NOMATCH:
+nometa2:
+			globfree(&pglob);
+			INTON;
+nometa:
+			*exparg.lastp = str;
+			rmescapes(str->text);
+			exparg.lastp = &str->next;
+			break;
+		default:	/* GLOB_NOSPACE */
+			sh_error("Out of space");
+		}
+		str = str->next;
+	}
+}
+
+
+/*
+ * Add the result of glob(3) to the list.
+ */
+
+STATIC void
+addglob(pglob)
+	const glob_t *pglob;
+{
+	char **p = pglob->gl_pathv;
+
+	do {
+		addfname(*p);
+	} while (*++p);
+}
+
+
+#else	/* defined(__GLIBC__) && !defined(FNMATCH_BROKEN) && !defined(GLOB_BROKEN) */
+STATIC char *expdir;
+
+
+STATIC void
+expandmeta(struct strlist *str, int flag)
+{
+	static const char metachars[] = {
+		'*', '?', '[', 0
+	};
+	/* TODO - EXP_REDIR */
+
+	while (str) {
+		struct strlist **savelastp;
+		struct strlist *sp;
+		char *p;
+
+		if (fflag)
+			goto nometa;
+		if (!strpbrk(str->text, metachars))
+			goto nometa;
+		savelastp = exparg.lastp;
+
+		INTOFF;
+		p = preglob(str->text, 0, RMESCAPE_ALLOC | RMESCAPE_HEAP);
+		{
+			int i = strlen(str->text);
+			expdir = ckmalloc(i < 2048 ? 2048 : i); /* XXX */
+		}
+
+		expmeta(expdir, p);
+		ckfree(expdir);
+		if (p != str->text)
+			ckfree(p);
+		INTON;
+		if (exparg.lastp == savelastp) {
+			/*
+			 * no matches
+			 */
+nometa:
+			*exparg.lastp = str;
+			rmescapes(str->text);
+			exparg.lastp = &str->next;
+		} else {
+			*exparg.lastp = NULL;
+			*savelastp = sp = expsort(*savelastp);
+			while (sp->next != NULL)
+				sp = sp->next;
+			exparg.lastp = &sp->next;
+		}
+		str = str->next;
+	}
+}
+
+
+/*
+ * Do metacharacter (i.e. *, ?, [...]) expansion.
+ */
+
+STATIC void
+expmeta(char *enddir, char *name)
+{
+	char *p;
+	const char *cp;
+	char *start;
+	char *endname;
+	int metaflag;
+	struct stat64 statb;
+	DIR *dirp;
+	struct dirent *dp;
+	int atend;
+	int matchdot;
+
+	metaflag = 0;
+	start = name;
+	for (p = name; *p; p++) {
+		if (*p == '*' || *p == '?')
+			metaflag = 1;
+		else if (*p == '[') {
+			char *q = p + 1;
+			if (*q == '!')
+				q++;
+			for (;;) {
+				if (*q == '\\')
+					q++;
+				if (*q == '/' || *q == '\0')
+					break;
+				if (*++q == ']') {
+					metaflag = 1;
+					break;
+				}
+			}
+		} else if (*p == '\\')
+			p++;
+		else if (*p == '/') {
+			if (metaflag)
+				goto out;
+			start = p + 1;
+		}
+	}
+out:
+	if (metaflag == 0) {	/* we've reached the end of the file name */
+		if (enddir != expdir)
+			metaflag++;
+		p = name;
+		do {
+			if (*p == '\\')
+				p++;
+			*enddir++ = *p;
+		} while (*p++);
+		if (metaflag == 0 || lstat64(expdir, &statb) >= 0)
+			addfname(expdir);
+		return;
+	}
+	endname = p;
+	if (name < start) {
+		p = name;
+		do {
+			if (*p == '\\')
+				p++;
+			*enddir++ = *p++;
+		} while (p < start);
+	}
+	if (enddir == expdir) {
+		cp = ".";
+	} else if (enddir == expdir + 1 && *expdir == '/') {
+		cp = "/";
+	} else {
+		cp = expdir;
+		enddir[-1] = '\0';
+	}
+	if ((dirp = opendir(cp)) == NULL)
+		return;
+	if (enddir != expdir)
+		enddir[-1] = '/';
+	if (*endname == 0) {
+		atend = 1;
+	} else {
+		atend = 0;
+		*endname++ = '\0';
+	}
+	matchdot = 0;
+	p = start;
+	if (*p == '\\')
+		p++;
+	if (*p == '.')
+		matchdot++;
+	while (! int_pending() && (dp = readdir(dirp)) != NULL) {
+		if (dp->d_name[0] == '.' && ! matchdot)
+			continue;
+		if (pmatch(start, dp->d_name)) {
+			if (atend) {
+				scopy(dp->d_name, enddir);
+				addfname(expdir);
+			} else {
+				for (p = enddir, cp = dp->d_name;
+				     (*p++ = *cp++) != '\0';)
+					continue;
+				p[-1] = '/';
+				expmeta(p, endname);
+			}
+		}
+	}
+	closedir(dirp);
+	if (! atend)
+		endname[-1] = '/';
+}
+#endif	/* defined(__GLIBC__) && !defined(FNMATCH_BROKEN) && !defined(GLOB_BROKEN) */
+
+
+/*
+ * Add a file name to the list.
+ */
+
+STATIC void
+addfname(char *name)
+{
+	struct strlist *sp;
+
+	sp = (struct strlist *)stalloc(sizeof *sp);
+	sp->text = sstrdup(name);
+	*exparg.lastp = sp;
+	exparg.lastp = &sp->next;
+}
+
+
+#if !(defined(__GLIBC__) && !defined(FNMATCH_BROKEN) && !defined(GLOB_BROKEN))
+/*
+ * Sort the results of file name expansion.  It calculates the number of
+ * strings to sort and then calls msort (short for merge sort) to do the
+ * work.
+ */
+
+STATIC struct strlist *
+expsort(struct strlist *str)
+{
+	int len;
+	struct strlist *sp;
+
+	len = 0;
+	for (sp = str ; sp ; sp = sp->next)
+		len++;
+	return msort(str, len);
+}
+
+
+STATIC struct strlist *
+msort(struct strlist *list, int len)
+{
+	struct strlist *p, *q = NULL;
+	struct strlist **lpp;
+	int half;
+	int n;
+
+	if (len <= 1)
+		return list;
+	half = len >> 1;
+	p = list;
+	for (n = half ; --n >= 0 ; ) {
+		q = p;
+		p = p->next;
+	}
+	q->next = NULL;			/* terminate first half of list */
+	q = msort(list, half);		/* sort first half of list */
+	p = msort(p, len - half);		/* sort second half */
+	lpp = &list;
+	for (;;) {
+		if (strcmp(p->text, q->text) < 0) {
+			*lpp = p;
+			lpp = &p->next;
+			if ((p = *lpp) == NULL) {
+				*lpp = q;
+				break;
+			}
+		} else {
+			*lpp = q;
+			lpp = &q->next;
+			if ((q = *lpp) == NULL) {
+				*lpp = p;
+				break;
+			}
+		}
+	}
+	return list;
+}
+#endif
+
+
+/*
+ * Returns true if the pattern matches the string.
+ */
+
+STATIC inline int
+patmatch(char *pattern, const char *string)
+{
+	return pmatch(preglob(pattern, 0, 0), string);
+}
+
+
+#if !defined(__GLIBC__) || defined(FNMATCH_BROKEN)
+STATIC int ccmatch(const char *p, int chr, const char **r)
+{
+	static const struct class {
+		char name[10];
+		int (*fn)(int);
+	} classes[] = {
+		{ .name = ":alnum:]", .fn = isalnum },
+		{ .name = ":cntrl:]", .fn = iscntrl },
+		{ .name = ":lower:]", .fn = islower },
+		{ .name = ":space:]", .fn = isspace },
+		{ .name = ":alpha:]", .fn = isalpha },
+		{ .name = ":digit:]", .fn = isdigit },
+		{ .name = ":print:]", .fn = isprint },
+		{ .name = ":upper:]", .fn = isupper },
+		{ .name = ":blank:]", .fn = isblank },
+		{ .name = ":graph:]", .fn = isgraph },
+		{ .name = ":punct:]", .fn = ispunct },
+		{ .name = ":xdigit:]", .fn = isxdigit },
+	};
+	const struct class *class, *end;
+
+	end = classes + sizeof(classes) / sizeof(classes[0]);
+	for (class = classes; class < end; class++) {
+		const char *q;
+
+		q = prefix(p, class->name);
+		if (!q)
+			continue;
+		*r = q;
+		return class->fn(chr);
+	}
+
+	*r = 0;
+	return 0;
+}
+
+STATIC int
+pmatch(const char *pattern, const char *string)
+{
+	const char *p, *q;
+	char c;
+
+	p = pattern;
+	q = string;
+	for (;;) {
+		switch (c = *p++) {
+		case '\0':
+			goto breakloop;
+		case '\\':
+			if (*p) {
+				c = *p++;
+			}
+			goto dft;
+		case '?':
+			if (*q++ == '\0')
+				return 0;
+			break;
+		case '*':
+			c = *p;
+			while (c == '*')
+				c = *++p;
+			if (c != '\\' && c != '?' && c != '*' && c != '[') {
+				while (*q != c) {
+					if (*q == '\0')
+						return 0;
+					q++;
+				}
+			}
+			do {
+				if (pmatch(p, q))
+					return 1;
+			} while (*q++ != '\0');
+			return 0;
+		case '[': {
+			const char *startp;
+			int invert, found;
+			char chr;
+
+			startp = p;
+			invert = 0;
+			if (*p == '!') {
+				invert++;
+				p++;
+			}
+			found = 0;
+			chr = *q++;
+			if (chr == '\0')
+				return 0;
+			c = *p++;
+			do {
+				if (!c) {
+					p = startp;
+					c = *p;
+					goto dft;
+				}
+				if (c == '[') {
+					const char *r;
+
+					found |= ccmatch(p, chr, &r);
+					if (r) {
+						p = r;
+						continue;
+					}
+				} else if (c == '\\')
+					c = *p++;
+				if (*p == '-' && p[1] != ']') {
+					p++;
+					if (*p == '\\')
+						p++;
+					if (chr >= c && chr <= *p)
+						found = 1;
+					p++;
+				} else {
+					if (chr == c)
+						found = 1;
+				}
+			} while ((c = *p++) != ']');
+			if (found == invert)
+				return 0;
+			break;
+		}
+dft:	        default:
+			if (*q++ != c)
+				return 0;
+			break;
+		}
+	}
+breakloop:
+	if (*q != '\0')
+		return 0;
+	return 1;
+}
+#endif
+
+
+
+/*
+ * Remove any CTLESC characters from a string.
+ */
+
+char *
+_rmescapes(char *str, int flag)
+{
+	char *p, *q, *r;
+	static const char qchars[] = { CTLESC, CTLQUOTEMARK, 0 };
+	unsigned inquotes;
+	int notescaped;
+	int globbing;
+
+	p = strpbrk(str, qchars);
+	if (!p) {
+		return str;
+	}
+	q = p;
+	r = str;
+	if (flag & RMESCAPE_ALLOC) {
+		size_t len = p - str;
+		size_t fulllen = len + strlen(p) + 1;
+
+		if (flag & RMESCAPE_GROW) {
+			r = makestrspace(fulllen, expdest);
+		} else if (flag & RMESCAPE_HEAP) {
+			r = ckmalloc(fulllen);
+		} else {
+			r = stalloc(fulllen);
+		}
+		q = r;
+		if (len > 0) {
+			q = mempcpy(q, str, len);
+		}
+	}
+	inquotes = (flag & RMESCAPE_QUOTED) ^ RMESCAPE_QUOTED;
+	globbing = flag & RMESCAPE_GLOB;
+	notescaped = globbing;
+	while (*p) {
+		if (*p == (char)CTLQUOTEMARK) {
+			inquotes = ~inquotes;
+			p++;
+			notescaped = globbing;
+			continue;
+		}
+		if (*p == '\\') {
+			/* naked back slash */
+			notescaped = 0;
+			goto copy;
+		}
+		if (*p == (char)CTLESC) {
+			p++;
+			if (notescaped && inquotes && *p != '/') {
+				*q++ = '\\';
+			}
+		}
+		notescaped = globbing;
+copy:
+		*q++ = *p++;
+	}
+	*q = '\0';
+	if (flag & RMESCAPE_GROW) {
+		expdest = r;
+		STADJUST(q - r + 1, expdest);
+	}
+	return r;
+}
+
+
+
+/*
+ * See if a pattern matches in a case statement.
+ */
+
+int
+casematch(union node *pattern, char *val)
+{
+	struct stackmark smark;
+	int result;
+
+	setstackmark(&smark);
+	argbackq = pattern->narg.backquote;
+	STARTSTACKSTR(expdest);
+	ifslastp = NULL;
+	argstr(pattern->narg.text, EXP_TILDE | EXP_CASE);
+	STACKSTRNUL(expdest);
+	result = patmatch(stackblock(), val);
+	popstackmark(&smark);
+	return result;
+}
+
+/*
+ * Our own itoa().
+ */
+
+STATIC int
+cvtnum(long num)
+{
+	int len;
+
+	expdest = makestrspace(32, expdest);
+	len = fmtstr(expdest, 32, "%ld", num);
+	STADJUST(len, expdest);
+	return len;
+}
+
+STATIC void
+varunset(const char *end, const char *var, const char *umsg, int varflags)
+{
+	const char *msg;
+	const char *tail;
+
+	tail = nullstr;
+	msg = "parameter not set";
+	if (umsg) {
+		if (*end == (char)CTLENDVAR) {
+			if (varflags & VSNUL)
+				tail = " or null";
+		} else
+			msg = umsg;
+	}
+	sh_error("%.*s: %s%s", end - var - 1, var, msg, tail);
+}
diff --git a/usr/dash/expand.h b/usr/dash/expand.h
new file mode 100644
index 0000000..d304595
--- /dev/null
+++ b/usr/dash/expand.h
@@ -0,0 +1,83 @@
+/*-
+ * Copyright (c) 1991, 1993
+ *	The Regents of the University of California.  All rights reserved.
+ * Copyright (c) 1997-2005
+ *	Herbert Xu <herbert@gondor.apana.org.au>.  All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Kenneth Almquist.
+ *
+ * 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. 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.
+ *
+ *	@(#)expand.h	8.2 (Berkeley) 5/4/95
+ */
+
+#ifndef DASH_STRLIST_H
+#define DASH_STRLIST_H
+
+struct strlist {
+	struct strlist *next;
+	char *text;
+};
+
+
+struct arglist {
+	struct strlist *list;
+	struct strlist **lastp;
+};
+
+/*
+ * expandarg() flags
+ */
+#define EXP_FULL	0x1	/* perform word splitting & file globbing */
+#define EXP_TILDE	0x2	/* do normal tilde expansion */
+#define	EXP_VARTILDE	0x4	/* expand tildes in an assignment */
+#define	EXP_REDIR	0x8	/* file glob for a redirection (1 match only) */
+#define EXP_CASE	0x10	/* keeps quotes around for CASE pattern */
+#define EXP_RECORD	0x20	/* need to record arguments for ifs breakup */
+#define EXP_VARTILDE2	0x40	/* expand tildes after colons only */
+#define EXP_WORD	0x80	/* expand word in parameter expansion */
+#define EXP_QWORD	0x100	/* expand word in quoted parameter expansion */
+
+
+union node;
+void expandhere(union node *, int);
+void expandarg(union node *, struct arglist *, int);
+void expari(int);
+#define rmescapes(p) _rmescapes((p), 0)
+char *_rmescapes(char *, int);
+int casematch(union node *, char *);
+
+/* From arith.y */
+int arith(const char *);
+int expcmd(int , char **);
+#ifdef USE_LEX
+void arith_lex_reset(void);
+#else
+#define arith_lex_reset()
+#endif
+int yylex(void);
+
+#endif		/* DASH_STRLIST_H */
diff --git a/usr/dash/funcs/cmv b/usr/dash/funcs/cmv
new file mode 100644
index 0000000..91a67c5
--- /dev/null
+++ b/usr/dash/funcs/cmv
@@ -0,0 +1,47 @@
+# Copyright (c) 1991, 1993
+#	The Regents of the University of California.  All rights reserved.
+# Copyright (c) 1997-2005
+#	Herbert Xu <herbert@gondor.apana.org.au>.  All rights reserved.
+#
+# This code is derived from software contributed to Berkeley by
+# Kenneth Almquist.
+#
+# 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. 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.
+#
+#	@(#)cmv	8.2 (Berkeley) 5/4/95
+
+# Conditional move--don't replace an existing file.
+
+cmv() {
+	if test $# != 2
+	then	echo "cmv: arg count"
+		return 2
+	fi
+	if test -f "$2" -o -w "$2"
+	then	echo "$2 exists"
+		return 2
+	fi
+	/bin/mv "$1" "$2"
+}
diff --git a/usr/dash/funcs/dirs b/usr/dash/funcs/dirs
new file mode 100644
index 0000000..7d840eb
--- /dev/null
+++ b/usr/dash/funcs/dirs
@@ -0,0 +1,71 @@
+# Copyright (c) 1991, 1993
+#	The Regents of the University of California.  All rights reserved.
+# Copyright (c) 1997-2005
+#	Herbert Xu <herbert@gondor.apana.org.au>.  All rights reserved.
+#
+# This code is derived from software contributed to Berkeley by
+# Kenneth Almquist.
+#
+# 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. 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.
+#
+#	@(#)dirs	8.2 (Berkeley) 5/4/95
+
+# pushd, popd, and dirs --- written by Chris Bertin
+# Pixel Computer Inc. ...!wjh12!pixel!pixutl!chris
+# as modified by Patrick Elam of GTRI and Kenneth Almquist at UW
+
+pushd () {
+	SAVE=`pwd`
+	if [ "$1" = "" ]
+	then	if [ "$DSTACK" = "" ]
+		then	echo "pushd: directory stack empty."
+			return 1
+		fi
+		set $DSTACK
+		cd $1 || return
+		shift 1
+		DSTACK="$*"
+	else	cd $1 > /dev/null || return
+	fi
+	DSTACK="$SAVE $DSTACK"
+	dirs
+}
+
+popd () {
+	if [ "$DSTACK" = "" ]
+	then	echo "popd: directory stack empty."
+		return 1
+	fi
+	set $DSTACK
+	cd $1
+	shift
+	DSTACK=$*
+	dirs
+}
+
+dirs () {
+	echo "`pwd` $DSTACK"
+	return 0
+}
diff --git a/usr/dash/funcs/kill b/usr/dash/funcs/kill
new file mode 100644
index 0000000..c5df95f
--- /dev/null
+++ b/usr/dash/funcs/kill
@@ -0,0 +1,47 @@
+# Copyright (c) 1991, 1993
+#	The Regents of the University of California.  All rights reserved.
+# Copyright (c) 1997-2005
+#	Herbert Xu <herbert@gondor.apana.org.au>.  All rights reserved.
+#
+# This code is derived from software contributed to Berkeley by
+# Kenneth Almquist.
+#
+# 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. 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.
+#
+#	@(#)kill	8.2 (Berkeley) 5/4/95
+
+# Convert job names to process ids and then run /bin/kill.
+
+kill() {
+	local args x
+	args=
+	for x in "$@"
+	do	case $x in
+		%*)	x=`jobid "$x"` ;;
+		esac
+		args="$args $x"
+	done
+	/bin/kill $args
+}
diff --git a/usr/dash/funcs/login b/usr/dash/funcs/login
new file mode 100644
index 0000000..215e535
--- /dev/null
+++ b/usr/dash/funcs/login
@@ -0,0 +1,36 @@
+# Copyright (c) 1991, 1993
+#	The Regents of the University of California.  All rights reserved.
+# Copyright (c) 1997-2005
+#	Herbert Xu <herbert@gondor.apana.org.au>.  All rights reserved.
+#
+# This code is derived from software contributed to Berkeley by
+# Kenneth Almquist.
+#
+# 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. 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.
+#
+#	@(#)login	8.2 (Berkeley) 5/4/95
+
+# replaces the login builtin in the BSD shell
+login () exec login "$@"
diff --git a/usr/dash/funcs/newgrp b/usr/dash/funcs/newgrp
new file mode 100644
index 0000000..ec0e7e5
--- /dev/null
+++ b/usr/dash/funcs/newgrp
@@ -0,0 +1,35 @@
+# Copyright (c) 1991, 1993
+#	The Regents of the University of California.  All rights reserved.
+# Copyright (c) 1997-2005
+#	Herbert Xu <herbert@gondor.apana.org.au>.  All rights reserved.
+#
+# This code is derived from software contributed to Berkeley by
+# Kenneth Almquist.
+#
+# 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. 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.
+#
+#	@(#)newgrp	8.2 (Berkeley) 5/4/95
+
+newgrp() exec newgrp "$@"
diff --git a/usr/dash/funcs/popd b/usr/dash/funcs/popd
new file mode 100644
index 0000000..3b1ab46
--- /dev/null
+++ b/usr/dash/funcs/popd
@@ -0,0 +1,71 @@
+# Copyright (c) 1991, 1993
+#	The Regents of the University of California.  All rights reserved.
+# Copyright (c) 1997-2005
+#	Herbert Xu <herbert@gondor.apana.org.au>.  All rights reserved.
+#
+# This code is derived from software contributed to Berkeley by
+# Kenneth Almquist.
+#
+# 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. 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.
+#
+#	@(#)popd	8.2 (Berkeley) 5/4/95
+
+# pushd, popd, and dirs --- written by Chris Bertin
+# Pixel Computer Inc. ...!wjh12!pixel!pixutl!chris
+# as modified by Patrick Elam of GTRI and Kenneth Almquist at UW
+
+pushd () {
+	SAVE=`pwd`
+	if [ "$1" = "" ]
+	then	if [ "$DSTACK" = "" ]
+		then	echo "pushd: directory stack empty."
+			return 1
+		fi
+		set $DSTACK
+		cd $1 || return
+		shift 1
+		DSTACK="$*"
+	else	cd $1 > /dev/null || return
+	fi
+	DSTACK="$SAVE $DSTACK"
+	dirs
+}
+
+popd () {
+	if [ "$DSTACK" = "" ]
+	then	echo "popd: directory stack empty."
+		return 1
+	fi
+	set $DSTACK
+	cd $1
+	shift
+	DSTACK=$*
+	dirs
+}
+
+dirs () {
+	echo "`pwd` $DSTACK"
+	return 0
+}
diff --git a/usr/dash/funcs/pushd b/usr/dash/funcs/pushd
new file mode 100644
index 0000000..483d358
--- /dev/null
+++ b/usr/dash/funcs/pushd
@@ -0,0 +1,71 @@
+# Copyright (c) 1991, 1993
+#	The Regents of the University of California.  All rights reserved.
+# Copyright (c) 1997-2005
+#	Herbert Xu <herbert@gondor.apana.org.au>.  All rights reserved.
+#
+# This code is derived from software contributed to Berkeley by
+# Kenneth Almquist.
+#
+# 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. 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.
+#
+#	@(#)pushd	8.2 (Berkeley) 5/4/95
+
+# pushd, popd, and dirs --- written by Chris Bertin
+# Pixel Computer Inc. ...!wjh12!pixel!pixutl!chris
+# as modified by Patrick Elam of GTRI and Kenneth Almquist at UW
+
+pushd () {
+	SAVE=`pwd`
+	if [ "$1" = "" ]
+	then	if [ "$DSTACK" = "" ]
+		then	echo "pushd: directory stack empty."
+			return 1
+		fi
+		set $DSTACK
+		cd $1 || return
+		shift 1
+		DSTACK="$*"
+	else	cd $1 > /dev/null || return
+	fi
+	DSTACK="$SAVE $DSTACK"
+	dirs
+}
+
+popd () {
+	if [ "$DSTACK" = "" ]
+	then	echo "popd: directory stack empty."
+		return 1
+	fi
+	set $DSTACK
+	cd $1
+	shift
+	DSTACK=$*
+	dirs
+}
+
+dirs () {
+	echo "`pwd` $DSTACK"
+	return 0
+}
diff --git a/usr/dash/funcs/suspend b/usr/dash/funcs/suspend
new file mode 100644
index 0000000..4484467
--- /dev/null
+++ b/usr/dash/funcs/suspend
@@ -0,0 +1,39 @@
+# Copyright (c) 1991, 1993
+#	The Regents of the University of California.  All rights reserved.
+# Copyright (c) 1997-2005
+#	Herbert Xu <herbert@gondor.apana.org.au>.  All rights reserved.
+#
+# This code is derived from software contributed to Berkeley by
+# Kenneth Almquist.
+#
+# 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. 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.
+#
+#	@(#)suspend	8.2 (Berkeley) 5/4/95
+
+suspend() {
+	local -
+	set +j
+	kill -TSTP 0
+}
diff --git a/usr/dash/gendeps.pl b/usr/dash/gendeps.pl
new file mode 100755
index 0000000..e6797de
--- /dev/null
+++ b/usr/dash/gendeps.pl
@@ -0,0 +1,38 @@
+#!/usr/bin/perl
+#
+# Generate dependencies for *generated* header files.  Generated
+# header files have to use #include "foo.h" syntax.
+#
+
+($src, $obj, @build_headers) = @ARGV;
+%build_headers = map { $_ => 1 } @build_headers;
+
+open(GENDEPS, "> $obj/.gendeps\0")
+    or die "$0: Cannot create $obj/.gendeps: $!\n";
+
+opendir(DIR, $src) or die "$0: Cannot opendir $src: $!\n";
+while ( defined($file = readdir(DIR)) ) {
+    if ( $file =~ /^(.*)\.c$/ ) {
+	$basename = $1;
+	@hdrs = ();
+	open(FILE, "< $src/$file\0")
+	    or die "$0: Cannot open $src/$file: $!\n";
+	while ( defined($line = <FILE>) ) {
+	    if ( $line =~ /^\s*\#\s*include\s+\"(.*)\"/ ) {
+		$header = $1;
+
+		if ( $build_headers{$header} ) {
+		    push(@hdrs, "\$(obj)/$header");
+		}
+	    }
+	}
+	close(FILE);
+
+	if (scalar(@hdrs)) {
+	    print GENDEPS "\$(obj)/$basename.o: ", join(' ', @hdrs), "\n";
+	}
+    }
+}
+
+closedir(DIR);
+close(GENDEPS);
diff --git a/usr/dash/hetio.c b/usr/dash/hetio.c
new file mode 100644
index 0000000..f7d175f
--- /dev/null
+++ b/usr/dash/hetio.c
@@ -0,0 +1,397 @@
+/*
+ * Termios command line History and Editting for NetBSD sh (ash)
+ * Copyright (c) 1999
+ *	Main code:	Adam Rogoyski <rogoyski@cs.utexas.edu>
+ *	Etc:		Dave Cinege <dcinege@psychosis.com>
+ *
+ * You may use this code as you wish, so long as the original author(s)
+ * are attributed in any redistributions of the source code.
+ * This code is 'as is' with no warranty.
+ * This code may safely be consumed by a BSD or GPL license.
+ *
+ * v 0.5  19990328	Initial release
+ *
+ * Future plans: Simple file and path name completion. (like BASH)
+ *
+ */
+
+/*
+Usage and Known bugs:
+	Terminal key codes are not extensive, and more will probably
+	need to be added. This version was created on Debian GNU/Linux 2.x.
+	Delete, Backspace, Home, End, and the arrow keys were tested
+	to work in an Xterm and console. Ctrl-A also works as Home.
+	Ctrl-E also works as End. Ctrl-D and Ctrl-U perform their respective
+	functions. The binary size increase is <3K.
+
+	Editting will not display correctly for lines greater then the
+	terminal width. (more then one line.) However, history will.
+*/
+
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <termios.h>
+#include <ctype.h>
+#include <sys/ioctl.h>
+
+#include "input.h"
+#include "output.h"
+
+#include "hetio.h"
+
+
+#define  MAX_HISTORY   15			/* Maximum length of the linked list for the command line history */
+
+#define ESC	27
+#define DEL	127
+
+static struct history *his_front = NULL;	/* First element in command line list */
+static struct history *his_end = NULL;		/* Last element in command line list */
+static struct termios old_term, new_term;	/* Current termio and the previous termio before starting ash */
+
+static int history_counter = 0;			/* Number of commands in history list */
+static int reset_term = 0;			/* Set to true if the terminal needs to be reset upon exit */
+static int hetio_inter = 0;
+
+struct history
+{
+   char *s;
+   struct history *p;
+   struct history *n;
+};
+
+
+void input_delete    (int);
+void input_home      (int *);
+void input_end       (int *, int);
+void input_backspace (int *, int *);
+
+
+
+void hetio_init(void)
+{
+	hetio_inter = 1;
+}
+
+
+void hetio_reset_term(void)
+{
+	if (reset_term)
+		tcsetattr(1, TCSANOW, &old_term);
+}
+
+
+void setIO(struct termios *new, struct termios *old)	/* Set terminal IO to canonical mode, and save old term settings. */
+{
+	tcgetattr(0, old);
+	memcpy(new, old, sizeof(*new));
+	new->c_cc[VMIN] = 1;
+	new->c_cc[VTIME] = 0;
+	new->c_lflag &= ~ICANON; /* unbuffered input */
+	new->c_lflag &= ~ECHO;
+	tcsetattr(0, TCSANOW, new);
+}
+
+void input_home(int *cursor)				/* Command line input routines */
+{
+ 	while (*cursor > 0) {
+		out1c('\b');
+		--*cursor;
+	}
+	flushout(out1);
+}
+
+
+void input_delete(int cursor)
+{
+	int j = 0;
+
+	memmove(parsenextc + cursor, parsenextc + cursor + 1,
+		BUFSIZ - cursor - 1);
+	for (j = cursor; j < (BUFSIZ - 1); j++) {
+		if (!*(parsenextc + j))
+			break;
+		else
+			out1c(*(parsenextc + j));
+	}
+
+	out1str(" \b");
+
+	while (j-- > cursor)
+		out1c('\b');
+	flushout(out1);
+}
+
+
+void input_end(int *cursor, int len)
+{
+	while (*cursor < len) {
+		out1str("\033[C");
+		++*cursor;
+	}
+	flushout(out1);
+}
+
+
+void
+input_backspace(int *cursor, int *len)
+{
+	int j = 0;
+
+	if (*cursor > 0) {
+		out1str("\b \b");
+		--*cursor;
+		memmove(parsenextc + *cursor, parsenextc + *cursor + 1,
+			BUFSIZ - *cursor + 1);
+
+		for (j = *cursor; j < (BUFSIZ - 1); j++) {
+			if (!*(parsenextc + j))
+				break;
+			else
+				out1c(*(parsenextc + j));
+		}
+
+		out1str(" \b");
+
+		while (j-- > *cursor)
+			out1c('\b');
+
+		--*len;
+		flushout(out1);
+	}
+}
+
+int hetio_read_input(int fd)
+{
+	int nr = 0;
+
+	/* Are we an interactive shell? */
+	if (!hetio_inter || fd) {
+		return -255;
+	} else {
+		int len = 0;
+		int j = 0;
+		int cursor = 0;
+		int break_out = 0;
+		int ret = 0;
+		char c = 0;
+		struct history *hp = his_end;
+
+		if (!reset_term) {
+			setIO(&new_term, &old_term);
+			reset_term = 1;
+		} else {
+			tcsetattr(0, TCSANOW, &new_term);
+		}
+
+		memset(parsenextc, 0, BUFSIZ);
+
+		while (1) {
+			if ((ret = read(fd, &c, 1)) < 1)
+				return ret;
+
+			switch (c) {
+   				case 1:		/* Control-A Beginning of line */
+   					input_home(&cursor);
+					break;
+				case 5:		/* Control-E EOL */
+					input_end(&cursor, len);
+					break;
+				case 4:		/* Control-D */
+					if (!len)
+						exitshell(0);
+					break;
+				case 21: 	/* Control-U */
+					/* Return to begining of line. */
+					for (; cursor > 0; cursor--)
+						out1c('\b');
+					/* Erase old command. */
+					for (j = 0; j < len; j++) {
+						/*
+						 * Clear buffer while we're at
+						 * it.
+						 */
+						parsenextc[j] = 0;
+						out1c(' ');
+					}
+					/* return to begining of line */
+					for (; len > 0; len--)
+						out1c('\b');
+					flushout(out1);
+					break;
+				case '\b':	/* Backspace */
+				case DEL:
+					input_backspace(&cursor, &len);
+					break;
+				case '\n':	/* Enter */
+					*(parsenextc + len++ + 1) = c;
+					out1c(c);
+					flushout(out1);
+					break_out = 1;
+					break;
+				case ESC:	/* escape sequence follows */
+					if ((ret = read(fd, &c, 1)) < 1)
+						return ret;
+
+					if (c == '[' ) {    /* 91 */
+						if ((ret = read(fd, &c, 1)) < 1)
+							return ret;
+
+						switch (c) {
+							case 'A':
+								if (hp && hp->p) {		/* Up */
+									hp = hp->p;
+									goto hop;
+								}
+								break;
+							case 'B':
+								if (hp && hp->n && hp->n->s) {	/* Down */
+									hp = hp->n;
+									goto hop;
+								}
+								break;
+
+hop:						/* hop */
+								len = strlen(parsenextc);
+
+								for (; cursor > 0; cursor--)		/* return to begining of line */
+									out1c('\b');
+
+		   						for (j = 0; j < len; j++)		/* erase old command */
+									out1c(' ');
+
+								for (; j > 0; j--)		/* return to begining of line */
+									out1c('\b');
+
+								strcpy (parsenextc, hp->s);		/* write new command */
+								len = strlen (hp->s);
+								out1str(parsenextc);
+								flushout(out1);
+								cursor = len;
+								break;
+							case 'C':		/* Right */
+								if (cursor < len) {
+									out1str("\033[C");
+									cursor++;
+									flushout(out1);
+						 		}
+								break;
+							case 'D':		/* Left */
+								if (cursor > 0) {
+									out1str("\033[D");
+									cursor--;
+									flushout(out1);
+								}
+								break;
+							case '3':		/* Delete */
+								if (cursor != len) {
+									input_delete(cursor);
+									len--;
+								}
+								break;
+							case '1':		/* Home (Ctrl-A) */
+								input_home(&cursor);
+								break;
+							case '4':		/* End (Ctrl-E) */
+								input_end(&cursor, len);
+								break;
+						}
+						if (c == '1' || c == '3' || c == '4')
+							if ((ret = read(fd, &c, 1)) < 1)
+								return ret;  /* read 126 (~) */
+					}
+
+					if (c == 'O') {	/* 79 */
+						if ((ret = read(fd, &c, 1)) < 1)
+							return ret;
+						switch (c) {
+							case 'H':		/* Home (xterm) */
+      								input_home(&cursor);
+								break;
+							case 'F':		/* End (xterm_ */
+								input_end(&cursor, len);
+								break;
+						}
+					}
+
+					c = 0;
+					break;
+
+				default:				/* If it's regular input, do the normal thing */
+					if (!isprint(c))		/* Skip non-printable characters */
+						break;
+
+	       				if (len >= (BUFSIZ - 2))	/* Need to leave space for enter */
+		  				break;
+
+					len++;
+
+					if (cursor == (len - 1)) {	/* Append if at the end of the line */
+						*(parsenextc + cursor) = c;
+					} else {			/* Insert otherwise */
+						memmove(parsenextc + cursor + 1, parsenextc + cursor,
+							len - cursor - 1);
+
+						*(parsenextc + cursor) = c;
+
+						for (j = cursor; j < len; j++)
+							out1c(*(parsenextc + j));
+						for (; j > cursor; j--)
+							out1str("\033[D");
+					}
+
+					cursor++;
+					out1c(c);
+					flushout(out1);
+					break;
+			}
+
+			if (break_out)		/* Enter is the command terminator, no more input. */
+				break;
+		}
+
+		nr = len + 1;
+		tcsetattr(0, TCSANOW, &old_term);
+
+		if (*(parsenextc)) {		/* Handle command history log */
+			struct history *h = his_end;
+
+			if (!h) {       /* No previous history */
+				h = his_front = malloc(sizeof (struct history));
+				h->n = malloc(sizeof (struct history));
+				h->p = NULL;
+				h->s = strdup(parsenextc);
+
+				h->n->p = h;
+				h->n->n = NULL;
+				h->n->s = NULL;
+				his_end = h->n;
+				history_counter++;
+			} else {	/* Add a new history command */
+
+				h->n = malloc(sizeof (struct history));
+
+				h->n->p = h;
+				h->n->n = NULL;
+				h->n->s = NULL;
+				h->s = strdup(parsenextc);
+				his_end = h->n;
+
+				if (history_counter >= MAX_HISTORY) {	/* After max history, remove the last known command */
+					struct history *p = his_front->n;
+
+					p->p = NULL;
+					free(his_front->s);
+					free(his_front);
+					his_front = p;
+				} else {
+					history_counter++;
+				}
+			}
+		}
+	}
+
+	return nr;
+}
diff --git a/usr/dash/hetio.h b/usr/dash/hetio.h
new file mode 100644
index 0000000..5f49713
--- /dev/null
+++ b/usr/dash/hetio.h
@@ -0,0 +1,22 @@
+/*
+ * Termios command line History and Editting for NetBSD sh (ash)
+ * Copyright (c) 1999
+ *	Main code:	Adam Rogoyski <rogoyski@cs.utexas.edu>
+ *	Etc:		Dave Cinege <dcinege@psychosis.com>
+ *
+ * You may use this code as you wish, so long as the original author(s)
+ * are attributed in any redistributions of the source code.
+ * This code is 'as is' with no warranty.
+ * This code may safely be consumed by a BSD or GPL license.
+ *
+ * v 0.5  19990328	Initial release
+ *
+ * Future plans: Simple file and path name completion. (like BASH)
+ *
+ */
+
+void hetio_init(void);
+int hetio_read_input(int fd);
+void hetio_reset_term(void);
+
+extern int hetio_inter;
diff --git a/usr/dash/histedit.c b/usr/dash/histedit.c
new file mode 100644
index 0000000..36d7937
--- /dev/null
+++ b/usr/dash/histedit.c
@@ -0,0 +1,492 @@
+/*-
+ * Copyright (c) 1993
+ *	The Regents of the University of California.  All rights reserved.
+ * Copyright (c) 1997-2005
+ *	Herbert Xu <herbert@gondor.apana.org.au>.  All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Kenneth Almquist.
+ *
+ * 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. 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 <sys/param.h>
+#include <paths.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+/*
+ * Editline and history functions (and glue).
+ */
+#include "shell.h"
+#include "parser.h"
+#include "var.h"
+#include "options.h"
+#include "main.h"
+#include "output.h"
+#include "mystring.h"
+#include "error.h"
+#ifndef SMALL
+#include "myhistedit.h"
+#include "eval.h"
+#include "memalloc.h"
+
+#define MAXHISTLOOPS	4	/* max recursions through fc */
+#define DEFEDITOR	"ed"	/* default editor *should* be $EDITOR */
+
+History *hist;	/* history cookie */
+EditLine *el;	/* editline cookie */
+int displayhist;
+static FILE *el_in, *el_out;
+
+STATIC const char *fc_replace(const char *, char *, char *);
+
+#ifdef DEBUG
+extern FILE *tracefile;
+#endif
+
+/*
+ * Set history and editing status.  Called whenever the status may
+ * have changed (figures out what to do).
+ */
+void
+histedit(void)
+{
+	FILE *el_err;
+
+#define editing (Eflag || Vflag)
+
+	if (iflag) {
+		if (!hist) {
+			/*
+			 * turn history on
+			 */
+			INTOFF;
+			hist = history_init();
+			INTON;
+
+			if (hist != NULL)
+				sethistsize(histsizeval());
+			else
+				out2str("sh: can't initialize history\n");
+		}
+		if (editing && !el && isatty(0)) { /* && isatty(2) ??? */
+			/*
+			 * turn editing on
+			 */
+			INTOFF;
+			if (el_in == NULL)
+				el_in = fdopen(0, "r");
+			if (el_out == NULL)
+				el_out = fdopen(2, "w");
+			if (el_in == NULL || el_out == NULL)
+				goto bad;
+			el_err = el_out;
+#if DEBUG
+			if (tracefile)
+				el_err = tracefile;
+#endif
+			el = el_init(arg0, el_in, el_out, el_err);
+			if (el != NULL) {
+				if (hist)
+					el_set(el, EL_HIST, history, hist);
+				el_set(el, EL_PROMPT, getprompt);
+			} else {
+bad:
+				out2str("sh: can't initialize editing\n");
+			}
+			INTON;
+		} else if (!editing && el) {
+			INTOFF;
+			el_end(el);
+			el = NULL;
+			INTON;
+		}
+		if (el) {
+			if (Vflag)
+				el_set(el, EL_EDITOR, "vi");
+			else if (Eflag)
+				el_set(el, EL_EDITOR, "emacs");
+			el_source(el, NULL);
+		}
+	} else {
+		INTOFF;
+		if (el) {	/* no editing if not interactive */
+			el_end(el);
+			el = NULL;
+		}
+		if (hist) {
+			history_end(hist);
+			hist = NULL;
+		}
+		INTON;
+	}
+}
+
+
+void
+sethistsize(const char *hs)
+{
+	int histsize;
+	HistEvent he;
+
+	if (hist != NULL) {
+		if (hs == NULL || *hs == '\0' ||
+		   (histsize = atoi(hs)) < 0)
+			histsize = 100;
+		history(hist, &he, H_SETSIZE, histsize);
+	}
+}
+
+void
+setterm(const char *term)
+{
+	if (el != NULL && term != NULL)
+		if (el_set(el, EL_TERMINAL, term) != 0) {
+			outfmt(out2, "sh: Can't set terminal type %s\n", term);
+			outfmt(out2, "sh: Using dumb terminal settings.\n");
+		}
+}
+
+/*
+ *  This command is provided since POSIX decided to standardize
+ *  the Korn shell fc command.  Oh well...
+ */
+int
+histcmd(int argc, char **argv)
+{
+	int ch;
+	const char *editor = NULL;
+	HistEvent he;
+	int lflg = 0, nflg = 0, rflg = 0, sflg = 0;
+	int i, retval;
+	const char *firststr, *laststr;
+	int first, last, direction;
+	char *pat = NULL, *repl;	/* ksh "fc old=new" crap */
+	static int active = 0;
+	struct jmploc jmploc;
+	struct jmploc *volatile savehandler;
+	char editfile[MAXPATHLEN + 1];
+	FILE *efp;
+#ifdef __GNUC__
+	/* Avoid longjmp clobbering */
+	(void) &editor;
+	(void) &lflg;
+	(void) &nflg;
+	(void) &rflg;
+	(void) &sflg;
+	(void) &firststr;
+	(void) &laststr;
+	(void) &pat;
+	(void) &repl;
+	(void) &efp;
+	(void) &argc;
+	(void) &argv;
+#endif
+
+	if (hist == NULL)
+		sh_error("history not active");
+
+	if (argc == 1)
+		sh_error("missing history argument");
+
+#ifdef __GLIBC__
+	optind = 0;
+#else
+	optreset = 1; optind = 1; /* initialize getopt */
+#endif
+	while (not_fcnumber(argv[optind]) &&
+	      (ch = getopt(argc, argv, ":e:lnrs")) != -1)
+		switch ((char)ch) {
+		case 'e':
+			editor = optionarg;
+			break;
+		case 'l':
+			lflg = 1;
+			break;
+		case 'n':
+			nflg = 1;
+			break;
+		case 'r':
+			rflg = 1;
+			break;
+		case 's':
+			sflg = 1;
+			break;
+		case ':':
+			sh_error("option -%c expects argument", optopt);
+			/* NOTREACHED */
+		case '?':
+		default:
+			sh_error("unknown option: -%c", optopt);
+			/* NOTREACHED */
+		}
+	argc -= optind, argv += optind;
+
+	/*
+	 * If executing...
+	 */
+	if (lflg == 0 || editor || sflg) {
+		lflg = 0;	/* ignore */
+		editfile[0] = '\0';
+		/*
+		 * Catch interrupts to reset active counter and
+		 * cleanup temp files.
+		 */
+		if (setjmp(jmploc.loc)) {
+			active = 0;
+			if (*editfile)
+				unlink(editfile);
+			handler = savehandler;
+			longjmp(handler->loc, 1);
+		}
+		savehandler = handler;
+		handler = &jmploc;
+		if (++active > MAXHISTLOOPS) {
+			active = 0;
+			displayhist = 0;
+			sh_error("called recursively too many times");
+		}
+		/*
+		 * Set editor.
+		 */
+		if (sflg == 0) {
+			if (editor == NULL &&
+			    (editor = bltinlookup("FCEDIT")) == NULL &&
+			    (editor = bltinlookup("EDITOR")) == NULL)
+				editor = DEFEDITOR;
+			if (editor[0] == '-' && editor[1] == '\0') {
+				sflg = 1;	/* no edit */
+				editor = NULL;
+			}
+		}
+	}
+
+	/*
+	 * If executing, parse [old=new] now
+	 */
+	if (lflg == 0 && argc > 0 &&
+	     ((repl = strchr(argv[0], '=')) != NULL)) {
+		pat = argv[0];
+		*repl++ = '\0';
+		argc--, argv++;
+	}
+	/*
+	 * determine [first] and [last]
+	 */
+	switch (argc) {
+	case 0:
+		firststr = lflg ? "-16" : "-1";
+		laststr = "-1";
+		break;
+	case 1:
+		firststr = argv[0];
+		laststr = lflg ? "-1" : argv[0];
+		break;
+	case 2:
+		firststr = argv[0];
+		laststr = argv[1];
+		break;
+	default:
+		sh_error("too many args");
+		/* NOTREACHED */
+	}
+	/*
+	 * Turn into event numbers.
+	 */
+	first = str_to_event(firststr, 0);
+	last = str_to_event(laststr, 1);
+
+	if (rflg) {
+		i = last;
+		last = first;
+		first = i;
+	}
+	/*
+	 * XXX - this should not depend on the event numbers
+	 * always increasing.  Add sequence numbers or offset
+	 * to the history element in next (diskbased) release.
+	 */
+	direction = first < last ? H_PREV : H_NEXT;
+
+	/*
+	 * If editing, grab a temp file.
+	 */
+	if (editor) {
+		int fd;
+		INTOFF;		/* easier */
+		sprintf(editfile, "%s_shXXXXXX", _PATH_TMP);
+		if ((fd = mkstemp(editfile)) < 0)
+			sh_error("can't create temporary file %s", editfile);
+		if ((efp = fdopen(fd, "w")) == NULL) {
+			close(fd);
+			sh_error("can't allocate stdio buffer for temp");
+		}
+	}
+
+	/*
+	 * Loop through selected history events.  If listing or executing,
+	 * do it now.  Otherwise, put into temp file and call the editor
+	 * after.
+	 *
+	 * The history interface needs rethinking, as the following
+	 * convolutions will demonstrate.
+	 */
+	history(hist, &he, H_FIRST);
+	retval = history(hist, &he, H_NEXT_EVENT, first);
+	for (;retval != -1; retval = history(hist, &he, direction)) {
+		if (lflg) {
+			if (!nflg)
+				out1fmt("%5d ", he.num);
+			out1str(he.str);
+		} else {
+			const char *s = pat ?
+			   fc_replace(he.str, pat, repl) : he.str;
+
+			if (sflg) {
+				if (displayhist) {
+					out2str(s);
+				}
+
+				evalstring(strcpy(stalloc(strlen(s) + 1), s),
+					   ~0);
+				if (displayhist && hist) {
+					/*
+					 *  XXX what about recursive and
+					 *  relative histnums.
+					 */
+					history(hist, &he, H_ENTER, s);
+				}
+			} else
+				fputs(s, efp);
+		}
+		/*
+		 * At end?  (if we were to lose last, we'd sure be
+		 * messed up).
+		 */
+		if (he.num == last)
+			break;
+	}
+	if (editor) {
+		char *editcmd;
+
+		fclose(efp);
+		editcmd = stalloc(strlen(editor) + strlen(editfile) + 2);
+		sprintf(editcmd, "%s %s", editor, editfile);
+		/* XXX - should use no JC command */
+		evalstring(editcmd, ~0);
+		INTON;
+		readcmdfile(editfile);	/* XXX - should read back - quick tst */
+		unlink(editfile);
+	}
+
+	if (lflg == 0 && active > 0)
+		--active;
+	if (displayhist)
+		displayhist = 0;
+	return 0;
+}
+
+STATIC const char *
+fc_replace(const char *s, char *p, char *r)
+{
+	char *dest;
+	int plen = strlen(p);
+
+	STARTSTACKSTR(dest);
+	while (*s) {
+		if (*s == *p && strncmp(s, p, plen) == 0) {
+			while (*r)
+				STPUTC(*r++, dest);
+			s += plen;
+			*p = '\0';	/* so no more matches */
+		} else
+			STPUTC(*s++, dest);
+	}
+	STACKSTRNUL(dest);
+	dest = grabstackstr(dest);
+
+	return (dest);
+}
+
+int
+not_fcnumber(char *s)
+{
+	if (s == NULL)
+		return 0;
+        if (*s == '-')
+                s++;
+	return (!is_number(s));
+}
+
+int
+str_to_event(const char *str, int last)
+{
+	HistEvent he;
+	const char *s = str;
+	int relative = 0;
+	int i, retval;
+
+	retval = history(hist, &he, H_FIRST);
+	switch (*s) {
+	case '-':
+		relative = 1;
+		/*FALLTHROUGH*/
+	case '+':
+		s++;
+	}
+	if (is_number(s)) {
+		i = atoi(s);
+		if (relative) {
+			while (retval != -1 && i--) {
+				retval = history(hist, &he, H_NEXT);
+			}
+			if (retval == -1)
+				retval = history(hist, &he, H_LAST);
+		} else {
+			retval = history(hist, &he, H_NEXT_EVENT, i);
+			if (retval == -1) {
+				/*
+				 * the notion of first and last is
+				 * backwards to that of the history package
+				 */
+				retval = history(hist, &he,
+						last ? H_FIRST : H_LAST);
+			}
+		}
+		if (retval == -1)
+			sh_error("history number %s not found (internal error)",
+				 str);
+	} else {
+		/*
+		 * pattern
+		 */
+		retval = history(hist, &he, H_PREV_STR, str);
+		if (retval == -1)
+			sh_error("history pattern not found: %s", str);
+	}
+	return (he.num);
+}
+#endif
diff --git a/usr/dash/init.h b/usr/dash/init.h
new file mode 100644
index 0000000..e026e86
--- /dev/null
+++ b/usr/dash/init.h
@@ -0,0 +1,39 @@
+/*-
+ * Copyright (c) 1991, 1993
+ *	The Regents of the University of California.  All rights reserved.
+ * Copyright (c) 1997-2005
+ *	Herbert Xu <herbert@gondor.apana.org.au>.  All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Kenneth Almquist.
+ *
+ * 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. 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.
+ *
+ *	@(#)init.h	8.2 (Berkeley) 5/4/95
+ */
+
+void init(void);
+void reset(void);
+void initshellproc(void);
diff --git a/usr/dash/input.c b/usr/dash/input.c
new file mode 100644
index 0000000..057da71
--- /dev/null
+++ b/usr/dash/input.c
@@ -0,0 +1,563 @@
+/*-
+ * Copyright (c) 1991, 1993
+ *	The Regents of the University of California.  All rights reserved.
+ * Copyright (c) 1997-2005
+ *	Herbert Xu <herbert@gondor.apana.org.au>.  All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Kenneth Almquist.
+ *
+ * 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. 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 <stdio.h>	/* defines BUFSIZ */
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+
+/*
+ * This file implements the input routines used by the parser.
+ */
+
+#include "shell.h"
+#include "redir.h"
+#include "syntax.h"
+#include "input.h"
+#include "output.h"
+#include "options.h"
+#include "memalloc.h"
+#include "error.h"
+#include "alias.h"
+#include "parser.h"
+#include "main.h"
+#ifndef SMALL
+#include "myhistedit.h"
+#endif
+
+#ifdef HETIO
+#include "hetio.h"
+#endif
+
+#define EOF_NLEFT -99		/* value of parsenleft when EOF pushed back */
+#define IBUFSIZ (BUFSIZ + 1)
+
+MKINIT
+struct strpush {
+	struct strpush *prev;	/* preceding string on stack */
+	char *prevstring;
+	int prevnleft;
+	struct alias *ap;	/* if push was associated with an alias */
+	char *string;		/* remember the string since it may change */
+};
+
+/*
+ * The parsefile structure pointed to by the global variable parsefile
+ * contains information about the current file being read.
+ */
+
+MKINIT
+struct parsefile {
+	struct parsefile *prev;	/* preceding file on stack */
+	int linno;		/* current line */
+	int fd;			/* file descriptor (or -1 if string) */
+	int nleft;		/* number of chars left in this line */
+	int lleft;		/* number of chars left in this buffer */
+	char *nextc;		/* next char in buffer */
+	char *buf;		/* input buffer */
+	struct strpush *strpush; /* for pushing strings at this level */
+	struct strpush basestrpush; /* so pushing one is fast */
+};
+
+
+int plinno = 1;			/* input line number */
+int parsenleft;			/* copy of parsefile->nleft */
+MKINIT int parselleft;		/* copy of parsefile->lleft */
+char *parsenextc;		/* copy of parsefile->nextc */
+MKINIT struct parsefile basepf;	/* top level input file */
+MKINIT char basebuf[IBUFSIZ];	/* buffer for top level input file */
+struct parsefile *parsefile = &basepf;	/* current input file */
+int whichprompt;		/* 1 == PS1, 2 == PS2 */
+
+#ifndef SMALL
+EditLine *el;			/* cookie for editline package */
+#endif
+
+STATIC void pushfile(void);
+static int preadfd(void);
+
+#ifdef mkinit
+INCLUDE <stdio.h>
+INCLUDE "input.h"
+INCLUDE "error.h"
+
+INIT {
+	basepf.nextc = basepf.buf = basebuf;
+}
+
+RESET {
+	parselleft = parsenleft = 0;	/* clear input buffer */
+	popallfiles();
+}
+#endif
+
+
+/*
+ * Read a line from the script.
+ */
+
+char *
+pfgets(char *line, int len)
+{
+	char *p = line;
+	int nleft = len;
+	int c;
+
+	while (--nleft > 0) {
+		c = pgetc2();
+		if (c == PEOF) {
+			if (p == line)
+				return NULL;
+			break;
+		}
+		*p++ = c;
+		if (c == '\n')
+			break;
+	}
+	*p = '\0';
+	return line;
+}
+
+
+/*
+ * Read a character from the script, returning PEOF on end of file.
+ * Nul characters in the input are silently discarded.
+ */
+
+int
+pgetc(void)
+{
+	return pgetc_macro();
+}
+
+
+/*
+ * Same as pgetc(), but ignores PEOA.
+ */
+
+int
+pgetc2()
+{
+	int c;
+	do {
+		c = pgetc_macro();
+	} while (c == PEOA);
+	return c;
+}
+
+
+static int
+preadfd(void)
+{
+	int nr;
+	char *buf =  parsefile->buf;
+	parsenextc = buf;
+
+retry:
+#ifndef SMALL
+	if (parsefile->fd == 0 && el) {
+		static const char *rl_cp;
+		static int el_len;
+
+		if (rl_cp == NULL)
+			rl_cp = el_gets(el, &el_len);
+		if (rl_cp == NULL)
+			nr = 0;
+		else {
+			nr = el_len;
+			if (nr > IBUFSIZ - 1)
+				nr = IBUFSIZ - 1;
+			memcpy(buf, rl_cp, nr);
+			if (nr != el_len) {
+				el_len -= nr;
+				rl_cp += nr;
+			} else
+				rl_cp = 0;
+		}
+
+	} else
+#endif
+
+#ifdef HETIO
+		nr = hetio_read_input(parsefile->fd);
+		if (nr == -255)
+#endif
+		nr = read(parsefile->fd, buf, IBUFSIZ - 1);
+
+
+	if (nr < 0) {
+		if (errno == EINTR)
+			goto retry;
+		if (parsefile->fd == 0 && errno == EWOULDBLOCK) {
+			int flags = fcntl(0, F_GETFL, 0);
+			if (flags >= 0 && flags & O_NONBLOCK) {
+				flags &=~ O_NONBLOCK;
+				if (fcntl(0, F_SETFL, flags) >= 0) {
+					out2str("sh: turning off NDELAY mode\n");
+					goto retry;
+				}
+			}
+		}
+	}
+	return nr;
+}
+
+/*
+ * Refill the input buffer and return the next input character:
+ *
+ * 1) If a string was pushed back on the input, pop it;
+ * 2) If an EOF was pushed back (parsenleft == EOF_NLEFT) or we are reading
+ *    from a string so we can't refill the buffer, return EOF.
+ * 3) If the is more stuff in this buffer, use it else call read to fill it.
+ * 4) Process input up to the next newline, deleting nul characters.
+ */
+
+int
+preadbuffer(void)
+{
+	char *q;
+	int more;
+#ifndef SMALL
+	int something;
+#endif
+	char savec;
+
+	while (unlikely(parsefile->strpush)) {
+		if (
+			parsenleft == -1 && parsefile->strpush->ap &&
+			parsenextc[-1] != ' ' && parsenextc[-1] != '\t'
+		) {
+			return PEOA;
+		}
+		popstring();
+		if (--parsenleft >= 0)
+			return (signed char)*parsenextc++;
+	}
+	if (unlikely(parsenleft == EOF_NLEFT || parsefile->buf == NULL))
+		return PEOF;
+	flushout(&output);
+#ifdef FLUSHERR
+	flushout(&errout);
+#endif
+
+	more = parselleft;
+	if (more <= 0) {
+again:
+		if ((more = preadfd()) <= 0) {
+			parselleft = parsenleft = EOF_NLEFT;
+			return PEOF;
+		}
+	}
+
+	q = parsenextc;
+
+	/* delete nul characters */
+#ifndef SMALL
+	something = 0;
+#endif
+	for (;;) {
+		int c;
+
+		more--;
+		c = *q;
+
+		if (!c)
+			memmove(q, q + 1, more);
+		else {
+			q++;
+
+			if (c == '\n') {
+				parsenleft = q - parsenextc - 1;
+				break;
+			}
+
+#ifndef SMALL
+			switch (c) {
+			default:
+				something = 1;
+				/* fall through */
+			case '\t':
+			case ' ':
+				break;
+			}
+#endif
+		}
+
+		if (more <= 0) {
+			parsenleft = q - parsenextc - 1;
+			if (parsenleft < 0)
+				goto again;
+			break;
+		}
+	}
+	parselleft = more;
+
+	savec = *q;
+	*q = '\0';
+
+#ifndef SMALL
+	if (parsefile->fd == 0 && hist && something) {
+		HistEvent he;
+		INTOFF;
+		history(hist, &he, whichprompt == 1? H_ENTER : H_APPEND,
+		    parsenextc);
+		INTON;
+	}
+#endif
+
+	if (vflag) {
+		out2str(parsenextc);
+#ifdef FLUSHERR
+		flushout(out2);
+#endif
+	}
+
+	*q = savec;
+
+	return (signed char)*parsenextc++;
+}
+
+/*
+ * Undo the last call to pgetc.  Only one character may be pushed back.
+ * PEOF may be pushed back.
+ */
+
+void
+pungetc(void)
+{
+	parsenleft++;
+	parsenextc--;
+}
+
+/*
+ * Push a string back onto the input at this current parsefile level.
+ * We handle aliases this way.
+ */
+void
+pushstring(char *s, void *ap)
+{
+	struct strpush *sp;
+	size_t len;
+
+	len = strlen(s);
+	INTOFF;
+/*dprintf("*** calling pushstring: %s, %d\n", s, len);*/
+	if (parsefile->strpush) {
+		sp = ckmalloc(sizeof (struct strpush));
+		sp->prev = parsefile->strpush;
+		parsefile->strpush = sp;
+	} else
+		sp = parsefile->strpush = &(parsefile->basestrpush);
+	sp->prevstring = parsenextc;
+	sp->prevnleft = parsenleft;
+	sp->ap = (struct alias *)ap;
+	if (ap) {
+		((struct alias *)ap)->flag |= ALIASINUSE;
+		sp->string = s;
+	}
+	parsenextc = s;
+	parsenleft = len;
+	INTON;
+}
+
+void
+popstring(void)
+{
+	struct strpush *sp = parsefile->strpush;
+
+	INTOFF;
+	if (sp->ap) {
+		if (parsenextc[-1] == ' ' || parsenextc[-1] == '\t') {
+			checkkwd |= CHKALIAS;
+		}
+		if (sp->string != sp->ap->val) {
+			ckfree(sp->string);
+		}
+		sp->ap->flag &= ~ALIASINUSE;
+		if (sp->ap->flag & ALIASDEAD) {
+			unalias(sp->ap->name);
+		}
+	}
+	parsenextc = sp->prevstring;
+	parsenleft = sp->prevnleft;
+/*dprintf("*** calling popstring: restoring to '%s'\n", parsenextc);*/
+	parsefile->strpush = sp->prev;
+	if (sp != &(parsefile->basestrpush))
+		ckfree(sp);
+	INTON;
+}
+
+/*
+ * Set the input to take input from a file.  If push is set, push the
+ * old input onto the stack first.
+ */
+
+int
+setinputfile(const char *fname, int flags)
+{
+	int fd;
+	int fd2;
+
+	INTOFF;
+	if ((fd = open(fname, O_RDONLY)) < 0) {
+		if (flags & INPUT_NOFILE_OK)
+			goto out;
+		sh_error("Can't open %s", fname);
+	}
+	if (fd < 10) {
+		fd2 = copyfd(fd, 10);
+		close(fd);
+		if (fd2 < 0)
+			sh_error("Out of file descriptors");
+		fd = fd2;
+	}
+	setinputfd(fd, flags & INPUT_PUSH_FILE);
+out:
+	INTON;
+	return fd;
+}
+
+
+/*
+ * Like setinputfile, but takes an open file descriptor.  Call this with
+ * interrupts off.
+ */
+
+void
+setinputfd(int fd, int push)
+{
+	(void) fcntl(fd, F_SETFD, FD_CLOEXEC);
+	if (push) {
+		pushfile();
+		parsefile->buf = 0;
+	}
+	parsefile->fd = fd;
+	if (parsefile->buf == NULL)
+		parsefile->buf = ckmalloc(IBUFSIZ);
+	parselleft = parsenleft = 0;
+	plinno = 1;
+}
+
+
+/*
+ * Like setinputfile, but takes input from a string.
+ */
+
+void
+setinputstring(char *string)
+{
+	INTOFF;
+	pushfile();
+	parsenextc = string;
+	parsenleft = strlen(string);
+	parsefile->buf = NULL;
+	plinno = 1;
+	INTON;
+}
+
+
+
+/*
+ * To handle the "." command, a stack of input files is used.  Pushfile
+ * adds a new entry to the stack and popfile restores the previous level.
+ */
+
+STATIC void
+pushfile(void)
+{
+	struct parsefile *pf;
+
+	parsefile->nleft = parsenleft;
+	parsefile->lleft = parselleft;
+	parsefile->nextc = parsenextc;
+	parsefile->linno = plinno;
+	pf = (struct parsefile *)ckmalloc(sizeof (struct parsefile));
+	pf->prev = parsefile;
+	pf->fd = -1;
+	pf->strpush = NULL;
+	pf->basestrpush.prev = NULL;
+	parsefile = pf;
+}
+
+
+void
+popfile(void)
+{
+	struct parsefile *pf = parsefile;
+
+	INTOFF;
+	if (pf->fd >= 0)
+		close(pf->fd);
+	if (pf->buf)
+		ckfree(pf->buf);
+	while (pf->strpush)
+		popstring();
+	parsefile = pf->prev;
+	ckfree(pf);
+	parsenleft = parsefile->nleft;
+	parselleft = parsefile->lleft;
+	parsenextc = parsefile->nextc;
+	plinno = parsefile->linno;
+	INTON;
+}
+
+
+/*
+ * Return to top level.
+ */
+
+void
+popallfiles(void)
+{
+	while (parsefile != &basepf)
+		popfile();
+}
+
+
+
+/*
+ * Close the file(s) that the shell is reading commands from.  Called
+ * after a fork is done.
+ */
+
+void
+closescript(void)
+{
+	popallfiles();
+	if (parsefile->fd > 0) {
+		close(parsefile->fd);
+		parsefile->fd = 0;
+	}
+}
diff --git a/usr/dash/input.h b/usr/dash/input.h
new file mode 100644
index 0000000..1ed9ddf
--- /dev/null
+++ b/usr/dash/input.h
@@ -0,0 +1,68 @@
+/*-
+ * Copyright (c) 1991, 1993
+ *	The Regents of the University of California.  All rights reserved.
+ * Copyright (c) 1997-2005
+ *	Herbert Xu <herbert@gondor.apana.org.au>.  All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Kenneth Almquist.
+ *
+ * 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. 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.
+ *
+ *	@(#)input.h	8.2 (Berkeley) 5/4/95
+ */
+
+/* PEOF (the end of file marker) is defined in syntax.h */
+
+enum {
+	INPUT_PUSH_FILE = 1,
+	INPUT_NOFILE_OK = 2,
+};
+
+/*
+ * The input line number.  Input.c just defines this variable, and saves
+ * and restores it when files are pushed and popped.  The user of this
+ * package must set its value.
+ */
+extern int plinno;
+extern int parsenleft;		/* number of characters left in input buffer */
+extern char *parsenextc;	/* next character in input buffer */
+
+char *pfgets(char *, int);
+int pgetc(void);
+int pgetc2(void);
+int preadbuffer(void);
+void pungetc(void);
+void pushstring(char *, void *);
+void popstring(void);
+int setinputfile(const char *, int);
+void setinputfd(int, int);
+void setinputstring(char *);
+void popfile(void);
+void popallfiles(void);
+void closescript(void);
+
+#define pgetc_macro() \
+	(--parsenleft >= 0 ? (signed char)*parsenextc++ : preadbuffer())
diff --git a/usr/dash/jobs.c b/usr/dash/jobs.c
new file mode 100644
index 0000000..77ed7791
--- /dev/null
+++ b/usr/dash/jobs.c
@@ -0,0 +1,1499 @@
+/*-
+ * Copyright (c) 1991, 1993
+ *	The Regents of the University of California.  All rights reserved.
+ * Copyright (c) 1997-2005
+ *	Herbert Xu <herbert@gondor.apana.org.au>.  All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Kenneth Almquist.
+ *
+ * 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. 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 <fcntl.h>
+#include <signal.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <paths.h>
+#include <sys/types.h>
+#include <sys/param.h>
+#ifdef BSD
+#include <sys/wait.h>
+#include <sys/time.h>
+#include <sys/resource.h>
+#endif
+#include <sys/ioctl.h>
+
+#include "shell.h"
+#if JOBS
+#include <termios.h>
+#undef CEOF			/* syntax.h redefines this */
+#endif
+#include "redir.h"
+#include "show.h"
+#include "main.h"
+#include "parser.h"
+#include "nodes.h"
+#include "jobs.h"
+#include "options.h"
+#include "trap.h"
+#include "syntax.h"
+#include "input.h"
+#include "output.h"
+#include "memalloc.h"
+#include "error.h"
+#include "mystring.h"
+#include "system.h"
+
+/* mode flags for set_curjob */
+#define CUR_DELETE 2
+#define CUR_RUNNING 1
+#define CUR_STOPPED 0
+
+/* mode flags for dowait */
+#define DOWAIT_NORMAL 0
+#define DOWAIT_BLOCK 1
+
+/* array of jobs */
+static struct job *jobtab;
+/* size of array */
+static unsigned njobs;
+/* pid of last background process */
+pid_t backgndpid;
+
+#if JOBS
+/* pgrp of shell on invocation */
+static int initialpgrp;
+/* control terminal */
+static int ttyfd = -1;
+#endif
+
+/* current job */
+static struct job *curjob;
+/* number of presumed living untracked jobs */
+static int jobless;
+
+STATIC void set_curjob(struct job *, unsigned);
+STATIC int jobno(const struct job *);
+STATIC int sprint_status(char *, int, int);
+STATIC void freejob(struct job *);
+STATIC struct job *getjob(const char *, int);
+STATIC struct job *growjobtab(void);
+STATIC void forkchild(struct job *, union node *, int);
+STATIC void forkparent(struct job *, union node *, int, pid_t);
+STATIC int dowait(int, struct job *);
+#ifdef SYSV
+STATIC int onsigchild(void);
+#endif
+STATIC int waitproc(int, int *);
+STATIC char *commandtext(union node *);
+STATIC void cmdtxt(union node *);
+STATIC void cmdlist(union node *, int);
+STATIC void cmdputs(const char *);
+STATIC void showpipe(struct job *, struct output *);
+STATIC int getstatus(struct job *);
+
+#if JOBS
+static int restartjob(struct job *, int);
+static void xtcsetpgrp(int, pid_t);
+#endif
+
+STATIC void
+set_curjob(struct job *jp, unsigned mode)
+{
+	struct job *jp1;
+	struct job **jpp, **curp;
+
+	/* first remove from list */
+	jpp = curp = &curjob;
+	do {
+		jp1 = *jpp;
+		if (jp1 == jp)
+			break;
+		jpp = &jp1->prev_job;
+	} while (1);
+	*jpp = jp1->prev_job;
+
+	/* Then re-insert in correct position */
+	jpp = curp;
+	switch (mode) {
+	default:
+#ifdef DEBUG
+		abort();
+#endif
+	case CUR_DELETE:
+		/* job being deleted */
+		break;
+	case CUR_RUNNING:
+		/* newly created job or backgrounded job,
+		   put after all stopped jobs. */
+		do {
+			jp1 = *jpp;
+			if (!JOBS || !jp1 || jp1->state != JOBSTOPPED)
+				break;
+			jpp = &jp1->prev_job;
+		} while (1);
+		/* FALLTHROUGH */
+#if JOBS
+	case CUR_STOPPED:
+#endif
+		/* newly stopped job - becomes curjob */
+		jp->prev_job = *jpp;
+		*jpp = jp;
+		break;
+	}
+}
+
+#if JOBS
+/*
+ * Turn job control on and off.
+ *
+ * Note:  This code assumes that the third arg to ioctl is a character
+ * pointer, which is true on Berkeley systems but not System V.  Since
+ * System V doesn't have job control yet, this isn't a problem now.
+ *
+ * Called with interrupts off.
+ */
+
+int jobctl;
+
+void
+setjobctl(int on)
+{
+	int fd;
+	int pgrp;
+
+	if (on == jobctl || rootshell == 0)
+		return;
+	if (on) {
+		int ofd;
+		ofd = fd = open(_PATH_TTY, O_RDWR);
+		if (fd < 0) {
+			fd += 3;
+			while (!isatty(fd) && --fd >= 0)
+				;
+		}
+		fd = fcntl(fd, F_DUPFD, 10);
+		close(ofd);
+		if (fd < 0)
+			goto out;
+		fcntl(fd, F_SETFD, FD_CLOEXEC);
+		do { /* while we are in the background */
+			if ((pgrp = tcgetpgrp(fd)) < 0) {
+out:
+				sh_warnx("can't access tty; job control turned off");
+				mflag = on = 0;
+				goto close;
+			}
+			if (pgrp == getpgrp())
+				break;
+			killpg(0, SIGTTIN);
+		} while (1);
+		initialpgrp = pgrp;
+
+		setsignal(SIGTSTP);
+		setsignal(SIGTTOU);
+		setsignal(SIGTTIN);
+		pgrp = rootpid;
+		setpgid(0, pgrp);
+		xtcsetpgrp(fd, pgrp);
+	} else {
+		/* turning job control off */
+		fd = ttyfd;
+		pgrp = initialpgrp;
+		xtcsetpgrp(fd, pgrp);
+		setpgid(0, pgrp);
+		setsignal(SIGTSTP);
+		setsignal(SIGTTOU);
+		setsignal(SIGTTIN);
+close:
+		close(fd);
+		fd = -1;
+	}
+	ttyfd = fd;
+	jobctl = on;
+}
+#endif
+
+
+int
+killcmd(argc, argv)
+	int argc;
+	char **argv;
+{
+	int signo = -1;
+	int list = 0;
+	int i;
+	pid_t pid;
+	struct job *jp;
+
+	if (argc <= 1) {
+usage:
+		sh_error(
+"Usage: kill [-s sigspec | -signum | -sigspec] [pid | job]... or\n"
+"kill -l [exitstatus]"
+		);
+	}
+
+	if (**++argv == '-') {
+		signo = decode_signal(*argv + 1, 1);
+		if (signo < 0) {
+			int c;
+
+			while ((c = nextopt("ls:")) != '\0')
+				switch (c) {
+				default:
+#ifdef DEBUG
+					abort();
+#endif
+				case 'l':
+					list = 1;
+					break;
+				case 's':
+					signo = decode_signal(optionarg, 1);
+					if (signo < 0) {
+						sh_error(
+							"invalid signal number or name: %s",
+							optionarg
+						);
+					}
+		                        break;
+				}
+			argv = argptr;
+		} else
+			argv++;
+	}
+
+	if (!list && signo < 0)
+		signo = SIGTERM;
+
+	if ((signo < 0 || !*argv) ^ list) {
+		goto usage;
+	}
+
+	if (list) {
+		struct output *out;
+
+		out = out1;
+		if (!*argv) {
+			outstr("0\n", out);
+			for (i = 1; i < NSIG; i++) {
+				outfmt(out, snlfmt, signal_name(i));
+			}
+			return 0;
+		}
+		signo = number(*argv);
+		if (signo > 128)
+			signo -= 128;
+		if (0 < signo && signo < NSIG)
+			outfmt(out, snlfmt, signal_name(signo));
+		else
+			sh_error("invalid signal number or exit status: %s",
+				 *argv);
+		return 0;
+	}
+
+	i = 0;
+	do {
+		if (**argv == '%') {
+			jp = getjob(*argv, 0);
+			pid = -jp->ps[0].pid;
+		} else
+			pid = **argv == '-' ?
+				-number(*argv + 1) : number(*argv);
+		if (kill(pid, signo) != 0) {
+			sh_warnx("%s\n", strerror(errno));
+			i = 1;
+		}
+	} while (*++argv);
+
+	return i;
+}
+
+STATIC int
+jobno(const struct job *jp)
+{
+	return jp - jobtab + 1;
+}
+
+#if JOBS
+int
+fgcmd(int argc, char **argv)
+{
+	struct job *jp;
+	struct output *out;
+	int mode;
+	int retval;
+
+	mode = (**argv == 'f') ? FORK_FG : FORK_BG;
+	nextopt(nullstr);
+	argv = argptr;
+	out = out1;
+	do {
+		jp = getjob(*argv, 1);
+		if (mode == FORK_BG) {
+			set_curjob(jp, CUR_RUNNING);
+			outfmt(out, "[%d] ", jobno(jp));
+		}
+		outstr(jp->ps->cmd, out);
+		showpipe(jp, out);
+		retval = restartjob(jp, mode);
+	} while (*argv && *++argv);
+	return retval;
+}
+
+int bgcmd(int, char **) __attribute__((__alias__("fgcmd")));
+
+
+STATIC int
+restartjob(struct job *jp, int mode)
+{
+	struct procstat *ps;
+	int i;
+	int status;
+	pid_t pgid;
+
+	INTOFF;
+	if (jp->state == JOBDONE)
+		goto out;
+	jp->state = JOBRUNNING;
+	pgid = jp->ps->pid;
+	if (mode == FORK_FG)
+		xtcsetpgrp(ttyfd, pgid);
+	killpg(pgid, SIGCONT);
+	ps = jp->ps;
+	i = jp->nprocs;
+	do {
+		if (WIFSTOPPED(ps->status)) {
+			ps->status = -1;
+		}
+	} while (ps++, --i);
+out:
+	status = (mode == FORK_FG) ? waitforjob(jp) : 0;
+	INTON;
+	return status;
+}
+#endif
+
+STATIC int
+sprint_status(char *s, int status, int sigonly)
+{
+	int col;
+	int st;
+
+	col = 0;
+	st = WEXITSTATUS(status);
+	if (!WIFEXITED(status)) {
+#if JOBS
+		st = WSTOPSIG(status);
+		if (!WIFSTOPPED(status))
+#endif
+			st = WTERMSIG(status);
+		if (sigonly) {
+			if (st == SIGINT || st == SIGPIPE)
+				goto out;
+#if JOBS
+			if (WIFSTOPPED(status))
+				goto out;
+#endif
+		}
+		col = fmtstr(s, 32, strsignal(st));
+		if (WCOREDUMP(status)) {
+			col += fmtstr(s + col, 16, " (core dumped)");
+		}
+	} else if (!sigonly) {
+		if (st)
+			col = fmtstr(s, 16, "Done(%d)", st);
+		else
+			col = fmtstr(s, 16, "Done");
+	}
+
+out:
+	return col;
+}
+
+static void
+showjob(struct output *out, struct job *jp, int mode)
+{
+	struct procstat *ps;
+	struct procstat *psend;
+	int col;
+	int indent;
+	char s[80];
+
+	ps = jp->ps;
+
+	if (mode & SHOW_PGID) {
+		/* just output process (group) id of pipeline */
+		outfmt(out, "%d\n", ps->pid);
+		return;
+	}
+
+	col = fmtstr(s, 16, "[%d]   ", jobno(jp));
+	indent = col;
+
+	if (jp == curjob)
+		s[col - 2] = '+';
+	else if (curjob && jp == curjob->prev_job)
+		s[col - 2] = '-';
+
+	if (mode & SHOW_PID)
+		col += fmtstr(s + col, 16, "%d ", ps->pid);
+
+	psend = ps + jp->nprocs;
+
+	if (jp->state == JOBRUNNING) {
+		scopy("Running", s + col);
+		col += strlen("Running");
+	} else {
+		int status = psend[-1].status;
+#if JOBS
+		if (jp->state == JOBSTOPPED)
+			status = jp->stopstatus;
+#endif
+		col += sprint_status(s + col, status, 0);
+	}
+
+	goto start;
+
+	do {
+		/* for each process */
+		col = fmtstr(s, 48, " |\n%*c%d ", indent, ' ', ps->pid) - 3;
+
+start:
+		outfmt(
+			out, "%s%*c%s",
+			s, 33 - col >= 0 ? 33 - col : 0, ' ', ps->cmd
+		);
+		if (!(mode & SHOW_PID)) {
+			showpipe(jp, out);
+			break;
+		}
+		if (++ps == psend) {
+			outcslow('\n', out);
+			break;
+		}
+	} while (1);
+
+	jp->changed = 0;
+
+	if (jp->state == JOBDONE) {
+		TRACE(("showjob: freeing job %d\n", jobno(jp)));
+		freejob(jp);
+	}
+}
+
+
+int
+jobscmd(int argc, char **argv)
+{
+	int mode, m;
+	struct output *out;
+
+	mode = 0;
+	while ((m = nextopt("lp")))
+		if (m == 'l')
+			mode = SHOW_PID;
+		else
+			mode = SHOW_PGID;
+
+	out = out1;
+	argv = argptr;
+	if (*argv)
+		do
+			showjob(out, getjob(*argv,0), mode);
+		while (*++argv);
+	else
+		showjobs(out, mode);
+
+	return 0;
+}
+
+
+/*
+ * Print a list of jobs.  If "change" is nonzero, only print jobs whose
+ * statuses have changed since the last call to showjobs.
+ */
+
+void
+showjobs(struct output *out, int mode)
+{
+	struct job *jp;
+
+	TRACE(("showjobs(%x) called\n", mode));
+
+	/* If not even one one job changed, there is nothing to do */
+	while (dowait(DOWAIT_NORMAL, NULL) > 0)
+		continue;
+
+	for (jp = curjob; jp; jp = jp->prev_job) {
+		if (!(mode & SHOW_CHANGED) || jp->changed)
+			showjob(out, jp, mode);
+	}
+}
+
+/*
+ * Mark a job structure as unused.
+ */
+
+STATIC void
+freejob(struct job *jp)
+{
+	struct procstat *ps;
+	int i;
+
+	INTOFF;
+	for (i = jp->nprocs, ps = jp->ps ; --i >= 0 ; ps++) {
+		if (ps->cmd != nullstr)
+			ckfree(ps->cmd);
+	}
+	if (jp->ps != &jp->ps0)
+		ckfree(jp->ps);
+	jp->used = 0;
+	set_curjob(jp, CUR_DELETE);
+	INTON;
+}
+
+
+
+int
+waitcmd(int argc, char **argv)
+{
+	struct job *job;
+	int retval;
+	struct job *jp;
+
+	EXSIGON();
+
+	nextopt(nullstr);
+	retval = 0;
+
+	argv = argptr;
+	if (!*argv) {
+		/* wait for all jobs */
+		for (;;) {
+			jp = curjob;
+			while (1) {
+				if (!jp) {
+					/* no running procs */
+					goto out;
+				}
+				if (jp->state == JOBRUNNING)
+					break;
+				jp->waited = 1;
+				jp = jp->prev_job;
+			}
+			dowait(DOWAIT_BLOCK, 0);
+		}
+	}
+
+	retval = 127;
+	do {
+		if (**argv != '%') {
+			pid_t pid = number(*argv);
+			job = curjob;
+			goto start;
+			do {
+				if (job->ps[job->nprocs - 1].pid == pid)
+					break;
+				job = job->prev_job;
+start:
+				if (!job)
+					goto repeat;
+			} while (1);
+		} else
+			job = getjob(*argv, 0);
+		/* loop until process terminated or stopped */
+		while (job->state == JOBRUNNING)
+			dowait(DOWAIT_BLOCK, 0);
+		job->waited = 1;
+		retval = getstatus(job);
+repeat:
+		;
+	} while (*++argv);
+
+out:
+	return retval;
+}
+
+
+
+/*
+ * Convert a job name to a job structure.
+ */
+
+STATIC struct job *
+getjob(const char *name, int getctl)
+{
+	struct job *jp;
+	struct job *found;
+	const char *err_msg = "No such job: %s";
+	unsigned num;
+	int c;
+	const char *p;
+	char *(*match)(const char *, const char *);
+
+	jp = curjob;
+	p = name;
+	if (!p)
+		goto currentjob;
+
+	if (*p != '%')
+		goto err;
+
+	c = *++p;
+	if (!c)
+		goto currentjob;
+
+	if (!p[1]) {
+		if (c == '+' || c == '%') {
+currentjob:
+			err_msg = "No current job";
+			goto check;
+		} else if (c == '-') {
+			if (jp)
+				jp = jp->prev_job;
+			err_msg = "No previous job";
+check:
+			if (!jp)
+				goto err;
+			goto gotit;
+		}
+	}
+
+	if (is_number(p)) {
+		num = atoi(p);
+		if (num < njobs) {
+			jp = jobtab + num - 1;
+			if (jp->used)
+				goto gotit;
+			goto err;
+		}
+	}
+
+	match = prefix;
+	if (*p == '?') {
+		match = strstr;
+		p++;
+	}
+
+	found = 0;
+	while (1) {
+		if (!jp)
+			goto err;
+		if (match(jp->ps[0].cmd, p)) {
+			if (found)
+				goto err;
+			found = jp;
+			err_msg = "%s: ambiguous";
+		}
+		jp = jp->prev_job;
+	}
+
+gotit:
+#if JOBS
+	err_msg = "job %s not created under job control";
+	if (getctl && jp->jobctl == 0)
+		goto err;
+#endif
+	return jp;
+err:
+	sh_error(err_msg, name);
+}
+
+
+
+/*
+ * Return a new job structure.
+ * Called with interrupts off.
+ */
+
+struct job *
+makejob(union node *node, int nprocs)
+{
+	int i;
+	struct job *jp;
+
+	for (i = njobs, jp = jobtab ; ; jp++) {
+		if (--i < 0) {
+			jp = growjobtab();
+			break;
+		}
+		if (jp->used == 0)
+			break;
+		if (jp->state != JOBDONE || !jp->waited)
+			continue;
+		if (jobctl)
+			continue;
+		freejob(jp);
+		break;
+	}
+	memset(jp, 0, sizeof(*jp));
+#if JOBS
+	if (jobctl)
+		jp->jobctl = 1;
+#endif
+	jp->prev_job = curjob;
+	curjob = jp;
+	jp->used = 1;
+	jp->ps = &jp->ps0;
+	if (nprocs > 1) {
+		jp->ps = ckmalloc(nprocs * sizeof (struct procstat));
+	}
+	TRACE(("makejob(0x%lx, %d) returns %%%d\n", (long)node, nprocs,
+	    jobno(jp)));
+	return jp;
+}
+
+STATIC struct job *
+growjobtab(void)
+{
+	size_t len;
+	ptrdiff_t offset;
+	struct job *jp, *jq;
+
+	len = njobs * sizeof(*jp);
+	jq = jobtab;
+	jp = ckrealloc(jq, len + 4 * sizeof(*jp));
+
+	offset = (char *)jp - (char *)jq;
+	if (offset) {
+		/* Relocate pointers */
+		size_t l = len;
+
+		jq = (struct job *)((char *)jq + l);
+		while (l) {
+			l -= sizeof(*jp);
+			jq--;
+#define joff(p) ((struct job *)((char *)(p) + l))
+#define jmove(p) (p) = (void *)((char *)(p) + offset)
+			if (likely(joff(jp)->ps == &jq->ps0))
+				jmove(joff(jp)->ps);
+			if (joff(jp)->prev_job)
+				jmove(joff(jp)->prev_job);
+		}
+		if (curjob)
+			jmove(curjob);
+#undef joff
+#undef jmove
+	}
+
+	njobs += 4;
+	jobtab = jp;
+	jp = (struct job *)((char *)jp + len);
+	jq = jp + 3;
+	do {
+		jq->used = 0;
+	} while (--jq >= jp);
+	return jp;
+}
+
+
+/*
+ * Fork off a subshell.  If we are doing job control, give the subshell its
+ * own process group.  Jp is a job structure that the job is to be added to.
+ * N is the command that will be evaluated by the child.  Both jp and n may
+ * be NULL.  The mode parameter can be one of the following:
+ *	FORK_FG - Fork off a foreground process.
+ *	FORK_BG - Fork off a background process.
+ *	FORK_NOJOB - Like FORK_FG, but don't give the process its own
+ *		     process group even if job control is on.
+ *
+ * When job control is turned off, background processes have their standard
+ * input redirected to /dev/null (except for the second and later processes
+ * in a pipeline).
+ *
+ * Called with interrupts off.
+ */
+
+STATIC inline void
+forkchild(struct job *jp, union node *n, int mode)
+{
+	int oldlvl;
+
+	TRACE(("Child shell %d\n", getpid()));
+	oldlvl = shlvl;
+	shlvl++;
+
+	closescript();
+	clear_traps();
+#if JOBS
+	/* do job control only in root shell */
+	jobctl = 0;
+	if (mode != FORK_NOJOB && jp->jobctl && !oldlvl) {
+		pid_t pgrp;
+
+		if (jp->nprocs == 0)
+			pgrp = getpid();
+		else
+			pgrp = jp->ps[0].pid;
+		/* This can fail because we are doing it in the parent also */
+		(void)setpgid(0, pgrp);
+		if (mode == FORK_FG)
+			xtcsetpgrp(ttyfd, pgrp);
+		setsignal(SIGTSTP);
+		setsignal(SIGTTOU);
+	} else
+#endif
+	if (mode == FORK_BG) {
+		ignoresig(SIGINT);
+		ignoresig(SIGQUIT);
+		if (jp->nprocs == 0) {
+			close(0);
+			if (open(_PATH_DEVNULL, O_RDONLY) != 0)
+				sh_error("Can't open %s", _PATH_DEVNULL);
+		}
+	}
+	if (!oldlvl && iflag) {
+		setsignal(SIGINT);
+		setsignal(SIGQUIT);
+		setsignal(SIGTERM);
+	}
+	for (jp = curjob; jp; jp = jp->prev_job)
+		freejob(jp);
+	jobless = 0;
+}
+
+STATIC inline void
+forkparent(struct job *jp, union node *n, int mode, pid_t pid)
+{
+	TRACE(("In parent shell:  child = %d\n", pid));
+	if (!jp) {
+		while (jobless && dowait(DOWAIT_NORMAL, 0) > 0);
+		jobless++;
+		return;
+	}
+#if JOBS
+	if (mode != FORK_NOJOB && jp->jobctl) {
+		int pgrp;
+
+		if (jp->nprocs == 0)
+			pgrp = pid;
+		else
+			pgrp = jp->ps[0].pid;
+		/* This can fail because we are doing it in the child also */
+		(void)setpgid(pid, pgrp);
+	}
+#endif
+	if (mode == FORK_BG) {
+		backgndpid = pid;		/* set $! */
+		set_curjob(jp, CUR_RUNNING);
+	}
+	if (jp) {
+		struct procstat *ps = &jp->ps[jp->nprocs++];
+		ps->pid = pid;
+		ps->status = -1;
+		ps->cmd = nullstr;
+		if (jobctl && n)
+			ps->cmd = commandtext(n);
+	}
+}
+
+int
+forkshell(struct job *jp, union node *n, int mode)
+{
+	int pid;
+
+	TRACE(("forkshell(%%%d, %p, %d) called\n", jobno(jp), n, mode));
+	pid = fork();
+	if (pid < 0) {
+		TRACE(("Fork failed, errno=%d", errno));
+		if (jp)
+			freejob(jp);
+		sh_error("Cannot fork");
+	}
+	if (pid == 0)
+		forkchild(jp, n, mode);
+	else
+		forkparent(jp, n, mode, pid);
+	return pid;
+}
+
+/*
+ * Wait for job to finish.
+ *
+ * Under job control we have the problem that while a child process is
+ * running interrupts generated by the user are sent to the child but not
+ * to the shell.  This means that an infinite loop started by an inter-
+ * active user may be hard to kill.  With job control turned off, an
+ * interactive user may place an interactive program inside a loop.  If
+ * the interactive program catches interrupts, the user doesn't want
+ * these interrupts to also abort the loop.  The approach we take here
+ * is to have the shell ignore interrupt signals while waiting for a
+ * forground process to terminate, and then send itself an interrupt
+ * signal if the child process was terminated by an interrupt signal.
+ * Unfortunately, some programs want to do a bit of cleanup and then
+ * exit on interrupt; unless these processes terminate themselves by
+ * sending a signal to themselves (instead of calling exit) they will
+ * confuse this approach.
+ *
+ * Called with interrupts off.
+ */
+
+int
+waitforjob(struct job *jp)
+{
+	int st;
+
+	TRACE(("waitforjob(%%%d) called\n", jobno(jp)));
+	while (jp->state == JOBRUNNING) {
+		dowait(DOWAIT_BLOCK, jp);
+	}
+	st = getstatus(jp);
+#if JOBS
+	if (jp->jobctl) {
+		xtcsetpgrp(ttyfd, rootpid);
+		/*
+		 * This is truly gross.
+		 * If we're doing job control, then we did a TIOCSPGRP which
+		 * caused us (the shell) to no longer be in the controlling
+		 * session -- so we wouldn't have seen any ^C/SIGINT.  So, we
+		 * intuit from the subprocess exit status whether a SIGINT
+		 * occurred, and if so interrupt ourselves.  Yuck.  - mycroft
+		 */
+		if (jp->sigint)
+			raise(SIGINT);
+	}
+#endif
+	if (! JOBS || jp->state == JOBDONE)
+		freejob(jp);
+	return st;
+}
+
+
+
+/*
+ * Wait for a process to terminate.
+ */
+
+STATIC int
+dowait(int block, struct job *job)
+{
+	int pid;
+	int status;
+	struct job *jp;
+	struct job *thisjob;
+	int state;
+
+	TRACE(("dowait(%d) called\n", block));
+	pid = waitproc(block, &status);
+	TRACE(("wait returns pid %d, status=%d\n", pid, status));
+	if (pid <= 0)
+		return pid;
+	INTOFF;
+	thisjob = NULL;
+	for (jp = curjob; jp; jp = jp->prev_job) {
+		struct procstat *sp;
+		struct procstat *spend;
+		if (jp->state == JOBDONE)
+			continue;
+		state = JOBDONE;
+		spend = jp->ps + jp->nprocs;
+		sp = jp->ps;
+		do {
+			if (sp->pid == pid) {
+				TRACE(("Job %d: changing status of proc %d from 0x%x to 0x%x\n", jobno(jp), pid, sp->status, status));
+				sp->status = status;
+				thisjob = jp;
+			}
+			if (sp->status == -1)
+				state = JOBRUNNING;
+#if JOBS
+			if (state == JOBRUNNING)
+				continue;
+			if (WIFSTOPPED(sp->status)) {
+				jp->stopstatus = sp->status;
+				state = JOBSTOPPED;
+			}
+#endif
+		} while (++sp < spend);
+		if (thisjob)
+			goto gotjob;
+	}
+	if (!JOBS || !WIFSTOPPED(status))
+		jobless--;
+	goto out;
+
+gotjob:
+	if (state != JOBRUNNING) {
+		thisjob->changed = 1;
+
+		if (thisjob->state != state) {
+			TRACE(("Job %d: changing state from %d to %d\n", jobno(thisjob), thisjob->state, state));
+			thisjob->state = state;
+#if JOBS
+			if (state == JOBSTOPPED) {
+				set_curjob(thisjob, CUR_STOPPED);
+			}
+#endif
+		}
+	}
+
+out:
+	INTON;
+
+	if (thisjob && thisjob == job) {
+		char s[48 + 1];
+		int len;
+
+		len = sprint_status(s, status, 1);
+		if (len) {
+			s[len] = '\n';
+			s[len + 1] = 0;
+			outstr(s, out2);
+		}
+	}
+	return pid;
+}
+
+
+
+/*
+ * Do a wait system call.  If job control is compiled in, we accept
+ * stopped processes.  If block is zero, we return a value of zero
+ * rather than blocking.
+ *
+ * System V doesn't have a non-blocking wait system call.  It does
+ * have a SIGCLD signal that is sent to a process when one of it's
+ * children dies.  The obvious way to use SIGCLD would be to install
+ * a handler for SIGCLD which simply bumped a counter when a SIGCLD
+ * was received, and have waitproc bump another counter when it got
+ * the status of a process.  Waitproc would then know that a wait
+ * system call would not block if the two counters were different.
+ * This approach doesn't work because if a process has children that
+ * have not been waited for, System V will send it a SIGCLD when it
+ * installs a signal handler for SIGCLD.  What this means is that when
+ * a child exits, the shell will be sent SIGCLD signals continuously
+ * until is runs out of stack space, unless it does a wait call before
+ * restoring the signal handler.  The code below takes advantage of
+ * this (mis)feature by installing a signal handler for SIGCLD and
+ * then checking to see whether it was called.  If there are any
+ * children to be waited for, it will be.
+ *
+ * If neither SYSV nor BSD is defined, we don't implement nonblocking
+ * waits at all.  In this case, the user will not be informed when
+ * a background process until the next time she runs a real program
+ * (as opposed to running a builtin command or just typing return),
+ * and the jobs command may give out of date information.
+ */
+
+#ifdef SYSV
+STATIC int gotsigchild;
+
+STATIC int onsigchild() {
+	gotsigchild = 1;
+}
+#endif
+
+
+STATIC int
+waitproc(int block, int *status)
+{
+#ifdef BSD
+	int flags = 0;
+
+#if JOBS
+	if (jobctl)
+		flags |= WUNTRACED;
+#endif
+	if (block == 0)
+		flags |= WNOHANG;
+	return wait3(status, flags, (struct rusage *)NULL);
+#else
+#ifdef SYSV
+	int (*save)();
+
+	if (block == 0) {
+		gotsigchild = 0;
+		save = signal(SIGCLD, onsigchild);
+		signal(SIGCLD, save);
+		if (gotsigchild == 0)
+			return 0;
+	}
+	return wait(status);
+#else
+	if (block == 0)
+		return 0;
+	return wait(status);
+#endif
+#endif
+}
+
+/*
+ * return 1 if there are stopped jobs, otherwise 0
+ */
+int job_warning;
+int
+stoppedjobs(void)
+{
+	struct job *jp;
+	int retval;
+
+	retval = 0;
+	if (job_warning)
+		goto out;
+	jp = curjob;
+	if (jp && jp->state == JOBSTOPPED) {
+		out2str("You have stopped jobs.\n");
+		job_warning = 2;
+		retval++;
+	}
+
+out:
+	return retval;
+}
+
+/*
+ * Return a string identifying a command (to be printed by the
+ * jobs command).
+ */
+
+STATIC char *cmdnextc;
+
+STATIC char *
+commandtext(union node *n)
+{
+	char *name;
+
+	STARTSTACKSTR(cmdnextc);
+	cmdtxt(n);
+	name = stackblock();
+	TRACE(("commandtext: name %p, end %p\n\t\"%s\"\n",
+		name, cmdnextc, ps->cmd));
+	return savestr(name);
+}
+
+
+STATIC void
+cmdtxt(union node *n)
+{
+	union node *np;
+	struct nodelist *lp;
+	const char *p;
+	char s[2];
+
+	if (!n)
+		return;
+	switch (n->type) {
+	default:
+#if DEBUG
+		abort();
+#endif
+	case NPIPE:
+		lp = n->npipe.cmdlist;
+		for (;;) {
+			cmdtxt(lp->n);
+			lp = lp->next;
+			if (!lp)
+				break;
+			cmdputs(" | ");
+		}
+		break;
+	case NSEMI:
+		p = "; ";
+		goto binop;
+	case NAND:
+		p = " && ";
+		goto binop;
+	case NOR:
+		p = " || ";
+binop:
+		cmdtxt(n->nbinary.ch1);
+		cmdputs(p);
+		n = n->nbinary.ch2;
+		goto donode;
+	case NREDIR:
+	case NBACKGND:
+		n = n->nredir.n;
+		goto donode;
+	case NNOT:
+		cmdputs("!");
+		n = n->nnot.com;
+donode:
+		cmdtxt(n);
+		break;
+	case NIF:
+		cmdputs("if ");
+		cmdtxt(n->nif.test);
+		cmdputs("; then ");
+		n = n->nif.ifpart;
+		if (n->nif.elsepart) {
+			cmdtxt(n);
+			cmdputs("; else ");
+			n = n->nif.elsepart;
+		}
+		p = "; fi";
+		goto dotail;
+	case NSUBSHELL:
+		cmdputs("(");
+		n = n->nredir.n;
+		p = ")";
+		goto dotail;
+	case NWHILE:
+		p = "while ";
+		goto until;
+	case NUNTIL:
+		p = "until ";
+until:
+		cmdputs(p);
+		cmdtxt(n->nbinary.ch1);
+		n = n->nbinary.ch2;
+		p = "; done";
+dodo:
+		cmdputs("; do ");
+dotail:
+		cmdtxt(n);
+		goto dotail2;
+	case NFOR:
+		cmdputs("for ");
+		cmdputs(n->nfor.var);
+		cmdputs(" in ");
+		cmdlist(n->nfor.args, 1);
+		n = n->nfor.body;
+		p = "; done";
+		goto dodo;
+	case NDEFUN:
+		cmdputs(n->narg.text);
+		p = "() { ... }";
+		goto dotail2;
+	case NCMD:
+		cmdlist(n->ncmd.args, 1);
+		cmdlist(n->ncmd.redirect, 0);
+		break;
+	case NARG:
+		p = n->narg.text;
+dotail2:
+		cmdputs(p);
+		break;
+	case NHERE:
+	case NXHERE:
+		p = "<<...";
+		goto dotail2;
+	case NCASE:
+		cmdputs("case ");
+		cmdputs(n->ncase.expr->narg.text);
+		cmdputs(" in ");
+		for (np = n->ncase.cases; np; np = np->nclist.next) {
+			cmdtxt(np->nclist.pattern);
+			cmdputs(") ");
+			cmdtxt(np->nclist.body);
+			cmdputs(";; ");
+		}
+		p = "esac";
+		goto dotail2;
+	case NTO:
+		p = ">";
+		goto redir;
+	case NCLOBBER:
+		p = ">|";
+		goto redir;
+	case NAPPEND:
+		p = ">>";
+		goto redir;
+	case NTOFD:
+		p = ">&";
+		goto redir;
+	case NFROM:
+		p = "<";
+		goto redir;
+	case NFROMFD:
+		p = "<&";
+		goto redir;
+	case NFROMTO:
+		p = "<>";
+redir:
+		s[0] = n->nfile.fd + '0';
+		s[1] = '\0';
+		cmdputs(s);
+		cmdputs(p);
+		if (n->type == NTOFD || n->type == NFROMFD) {
+			s[0] = n->ndup.dupfd + '0';
+			p = s;
+			goto dotail2;
+		} else {
+			n = n->nfile.fname;
+			goto donode;
+		}
+	}
+}
+
+STATIC void
+cmdlist(union node *np, int sep)
+{
+	for (; np; np = np->narg.next) {
+		if (!sep)
+			cmdputs(spcstr);
+		cmdtxt(np);
+		if (sep && np->narg.next)
+			cmdputs(spcstr);
+	}
+}
+
+
+STATIC void
+cmdputs(const char *s)
+{
+	const char *p, *str;
+	char cc[2] = " ";
+	char *nextc;
+	signed char c;
+	int subtype = 0;
+	int quoted = 0;
+	static const char vstype[VSTYPE + 1][4] = {
+		"", "}", "-", "+", "?", "=",
+		"%", "%%", "#", "##",
+	};
+
+	nextc = makestrspace((strlen(s) + 1) * 8, cmdnextc);
+	p = s;
+	while ((c = *p++) != 0) {
+		str = 0;
+		switch (c) {
+		case CTLESC:
+			c = *p++;
+			break;
+		case CTLVAR:
+			subtype = *p++;
+			if ((subtype & VSTYPE) == VSLENGTH)
+				str = "${#";
+			else
+				str = "${";
+			if (!(subtype & VSQUOTE) != !(quoted & 1)) {
+				quoted ^= 1;
+				c = '"';
+			} else
+				goto dostr;
+			break;
+		case CTLENDVAR:
+			str = "\"}" + !(quoted & 1);
+			quoted >>= 1;
+			subtype = 0;
+			goto dostr;
+		case CTLBACKQ:
+			str = "$(...)";
+			goto dostr;
+		case CTLBACKQ+CTLQUOTE:
+			str = "\"$(...)\"";
+			goto dostr;
+		case CTLARI:
+			str = "$((";
+			goto dostr;
+		case CTLENDARI:
+			str = "))";
+			goto dostr;
+		case CTLQUOTEMARK:
+			quoted ^= 1;
+			c = '"';
+			break;
+		case '=':
+			if (subtype == 0)
+				break;
+			if ((subtype & VSTYPE) != VSNORMAL)
+				quoted <<= 1;
+			str = vstype[subtype & VSTYPE];
+			if (subtype & VSNUL)
+				c = ':';
+			else
+				goto checkstr;
+			break;
+		case '\'':
+		case '\\':
+		case '"':
+		case '$':
+			/* These can only happen inside quotes */
+			cc[0] = c;
+			str = cc;
+			c = '\\';
+			break;
+		default:
+			break;
+		}
+		USTPUTC(c, nextc);
+checkstr:
+		if (!str)
+			continue;
+dostr:
+		while ((c = *str++)) {
+			USTPUTC(c, nextc);
+		}
+	}
+	if (quoted & 1) {
+		USTPUTC('"', nextc);
+	}
+	*nextc = 0;
+	cmdnextc = nextc;
+}
+
+
+STATIC void
+showpipe(struct job *jp, struct output *out)
+{
+	struct procstat *sp;
+	struct procstat *spend;
+
+	spend = jp->ps + jp->nprocs;
+	for (sp = jp->ps + 1; sp < spend; sp++)
+		outfmt(out, " | %s", sp->cmd);
+	outcslow('\n', out);
+	flushall();
+}
+
+
+#if JOBS
+STATIC void
+xtcsetpgrp(int fd, pid_t pgrp)
+{
+	if (tcsetpgrp(fd, pgrp))
+		sh_error("Cannot set tty process group (%s)", strerror(errno));
+}
+#endif
+
+
+STATIC int
+getstatus(struct job *job) {
+	int status;
+	int retval;
+
+	status = job->ps[job->nprocs - 1].status;
+	retval = WEXITSTATUS(status);
+	if (!WIFEXITED(status)) {
+#if JOBS
+		retval = WSTOPSIG(status);
+		if (!WIFSTOPPED(status))
+#endif
+		{
+			/* XXX: limits number of signals */
+			retval = WTERMSIG(status);
+#if JOBS
+			if (retval == SIGINT)
+				job->sigint = 1;
+#endif
+		}
+		retval += 128;
+	}
+	TRACE(("getstatus: job %d, nproc %d, status %x, retval %x\n",
+		jobno(job), job->nprocs, status, retval));
+	return retval;
+}
diff --git a/usr/dash/jobs.h b/usr/dash/jobs.h
new file mode 100644
index 0000000..26e421d
--- /dev/null
+++ b/usr/dash/jobs.h
@@ -0,0 +1,109 @@
+/*-
+ * Copyright (c) 1991, 1993
+ *	The Regents of the University of California.  All rights reserved.
+ * Copyright (c) 1997-2005
+ *	Herbert Xu <herbert@gondor.apana.org.au>.  All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Kenneth Almquist.
+ *
+ * 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. 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.
+ *
+ *	@(#)jobs.h	8.2 (Berkeley) 5/4/95
+ */
+
+#include <stdint.h>
+#include <sys/types.h>
+
+/* Mode argument to forkshell.  Don't change FORK_FG or FORK_BG. */
+#define FORK_FG 0
+#define FORK_BG 1
+#define FORK_NOJOB 2
+
+/* mode flags for showjob(s) */
+#define	SHOW_PGID	0x01	/* only show pgid - for jobs -p */
+#define	SHOW_PID	0x04	/* include process pid */
+#define	SHOW_CHANGED	0x08	/* only jobs whose state has changed */
+
+
+/*
+ * A job structure contains information about a job.  A job is either a
+ * single process or a set of processes contained in a pipeline.  In the
+ * latter case, pidlist will be non-NULL, and will point to a -1 terminated
+ * array of pids.
+ */
+
+struct procstat {
+	pid_t	pid;		/* process id */
+ 	int	status;		/* last process status from wait() */
+ 	char	*cmd;		/* text of command being run */
+};
+
+struct job {
+	struct procstat ps0;	/* status of process */
+	struct procstat *ps;	/* status or processes when more than one */
+#if JOBS
+	int stopstatus;		/* status of a stopped job */
+#endif
+	uint32_t
+		nprocs: 16,	/* number of processes */
+		state: 8,
+#define	JOBRUNNING	0	/* at least one proc running */
+#define	JOBSTOPPED	1	/* all procs are stopped */
+#define	JOBDONE		2	/* all procs are completed */
+#if JOBS
+		sigint: 1,	/* job was killed by SIGINT */
+		jobctl: 1,	/* job running under job control */
+#endif
+		waited: 1,	/* true if this entry has been waited for */
+		used: 1,	/* true if this entry is in used */
+		changed: 1;	/* true if status has changed */
+	struct job *prev_job;	/* previous job */
+};
+
+extern pid_t backgndpid;	/* pid of last background process */
+extern int job_warning;		/* user was warned about stopped jobs */
+#if JOBS
+extern int jobctl;		/* true if doing job control */
+#else
+#define jobctl 0
+#endif
+
+void setjobctl(int);
+int killcmd(int, char **);
+int fgcmd(int, char **);
+int bgcmd(int, char **);
+int jobscmd(int, char **);
+struct output;
+void showjobs(struct output *, int);
+int waitcmd(int, char **);
+struct job *makejob(union node *, int);
+int forkshell(struct job *, union node *, int);
+int waitforjob(struct job *);
+int stoppedjobs(void);
+
+#if ! JOBS
+#define setjobctl(on)	/* do nothing */
+#endif
diff --git a/usr/dash/machdep.h b/usr/dash/machdep.h
new file mode 100644
index 0000000..b1ca07a
--- /dev/null
+++ b/usr/dash/machdep.h
@@ -0,0 +1,53 @@
+/*-
+ * Copyright (c) 1991, 1993
+ *	The Regents of the University of California.  All rights reserved.
+ * Copyright (c) 1997-2005
+ *	Herbert Xu <herbert@gondor.apana.org.au>.  All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Kenneth Almquist.
+ *
+ * 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. 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.
+ *
+ *	@(#)machdep.h	8.2 (Berkeley) 5/4/95
+ */
+
+#include "config.h"
+
+/*
+ * Most machines require the value returned from malloc to be aligned
+ * in some way.  The following macro will get this right on many machines.
+ */
+#ifdef HAVE_STRTOD
+# define SHELL_SIZE (sizeof(union {int i; char *cp; double d; }) - 1)
+#else
+# define SHELL_SIZE (sizeof(union {int i; char *cp;}) - 1)
+#endif
+
+/*
+ * It appears that grabstackstr() will barf with such alignments
+ * because stalloc() will return a string allocated in a new stackblock.
+ */
+#define SHELL_ALIGN(nbytes) (((nbytes) + SHELL_SIZE) & ~SHELL_SIZE)
diff --git a/usr/dash/mail.c b/usr/dash/mail.c
new file mode 100644
index 0000000..02e07f7
--- /dev/null
+++ b/usr/dash/mail.c
@@ -0,0 +1,112 @@
+/*-
+ * Copyright (c) 1991, 1993
+ *	The Regents of the University of California.  All rights reserved.
+ * Copyright (c) 1997-2005
+ *	Herbert Xu <herbert@gondor.apana.org.au>.  All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Kenneth Almquist.
+ *
+ * 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. 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.
+ */
+
+/*
+ * Routines to check for mail.  (Perhaps make part of main.c?)
+ */
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <stdlib.h>
+
+#include "shell.h"
+#include "nodes.h"
+#include "exec.h"	/* defines padvance() */
+#include "var.h"
+#include "output.h"
+#include "memalloc.h"
+#include "error.h"
+#include "mail.h"
+#include "mystring.h"
+
+
+#define MAXMBOXES 10
+
+/* times of mailboxes */
+static time_t mailtime[MAXMBOXES];
+/* Set if MAIL or MAILPATH is changed. */
+static int changed;
+
+
+
+/*
+ * Print appropriate message(s) if mail has arrived.  If changed is set,
+ * then the value of MAIL has changed, so we just update the values.
+ */
+
+void
+chkmail(void)
+{
+	const char *mpath;
+	char *p;
+	char *q;
+	time_t *mtp;
+	struct stackmark smark;
+	struct stat64 statb;
+
+	setstackmark(&smark);
+	mpath = mpathset() ? mpathval() : mailval();
+	for (mtp = mailtime; mtp < mailtime + MAXMBOXES; mtp++) {
+		p = padvance(&mpath, nullstr);
+		if (p == NULL)
+			break;
+		if (*p == '\0')
+			continue;
+		for (q = p ; *q ; q++);
+#ifdef DEBUG
+		if (q[-1] != '/')
+			abort();
+#endif
+		q[-1] = '\0';			/* delete trailing '/' */
+		if (stat64(p, &statb) < 0) {
+			*mtp = 0;
+			continue;
+		}
+		if (!changed && statb.st_mtime != *mtp) {
+			outfmt(
+				&errout, snlfmt,
+				pathopt ? pathopt : "you have mail"
+			);
+		}
+		*mtp = statb.st_mtime;
+	}
+	changed = 0;
+	popstackmark(&smark);
+}
+
+
+void
+changemail(const char *val)
+{
+	changed++;
+}
diff --git a/usr/dash/mail.h b/usr/dash/mail.h
new file mode 100644
index 0000000..3c6b21d
--- /dev/null
+++ b/usr/dash/mail.h
@@ -0,0 +1,38 @@
+/*-
+ * Copyright (c) 1991, 1993
+ *	The Regents of the University of California.  All rights reserved.
+ * Copyright (c) 1997-2005
+ *	Herbert Xu <herbert@gondor.apana.org.au>.  All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Kenneth Almquist.
+ *
+ * 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. 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.
+ *
+ *	@(#)mail.h	8.2 (Berkeley) 5/4/95
+ */
+
+void chkmail(void);
+void changemail(const char *);
diff --git a/usr/dash/main.c b/usr/dash/main.c
new file mode 100644
index 0000000..b421e4f
--- /dev/null
+++ b/usr/dash/main.c
@@ -0,0 +1,349 @@
+/*-
+ * Copyright (c) 1991, 1993
+ *	The Regents of the University of California.  All rights reserved.
+ * Copyright (c) 1997-2005
+ *	Herbert Xu <herbert@gondor.apana.org.au>.  All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Kenneth Almquist.
+ *
+ * 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. 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 <stdio.h>
+#include <signal.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <fcntl.h>
+
+
+#include "shell.h"
+#include "main.h"
+#include "mail.h"
+#include "options.h"
+#include "output.h"
+#include "parser.h"
+#include "nodes.h"
+#include "expand.h"
+#include "eval.h"
+#include "jobs.h"
+#include "input.h"
+#include "trap.h"
+#include "var.h"
+#include "show.h"
+#include "memalloc.h"
+#include "error.h"
+#include "init.h"
+#include "mystring.h"
+#include "exec.h"
+#include "cd.h"
+
+#ifdef HETIO
+#include "hetio.h"
+#endif
+
+#define PROFILE 0
+
+int rootpid;
+int shlvl;
+#ifdef __GLIBC__
+int *dash_errno;
+#endif
+#if PROFILE
+short profile_buf[16384];
+extern int etext();
+#endif
+
+STATIC void read_profile(const char *);
+STATIC char *find_dot_file(char *);
+static int cmdloop(int);
+int main(int, char **);
+
+/*
+ * Main routine.  We initialize things, parse the arguments, execute
+ * profiles if we're a login shell, and then call cmdloop to execute
+ * commands.  The setjmp call sets up the location to jump to when an
+ * exception occurs.  When an exception occurs the variable "state"
+ * is used to figure out how far we had gotten.
+ */
+
+int
+main(int argc, char **argv)
+{
+	char *shinit;
+	volatile int state;
+	struct jmploc jmploc;
+	struct stackmark smark;
+
+#ifdef __GLIBC__
+	dash_errno = __errno_location();
+#endif
+
+#if PROFILE
+	monitor(4, etext, profile_buf, sizeof profile_buf, 50);
+#endif
+	state = 0;
+	if (unlikely(setjmp(jmploc.loc))) {
+		int e;
+		int s;
+
+		reset();
+
+		e = exception;
+		if (e == EXERROR)
+			exitstatus = 2;
+
+		s = state;
+		if (e == EXEXIT || s == 0 || iflag == 0 || shlvl)
+			exitshell();
+
+		if (e == EXINT
+#if ATTY
+		 && (! attyset() || equal(termval(), "emacs"))
+#endif
+		 ) {
+			out2c('\n');
+#ifdef FLUSHERR
+			flushout(out2);
+#endif
+		}
+		popstackmark(&smark);
+		FORCEINTON;				/* enable interrupts */
+		if (s == 1)
+			goto state1;
+		else if (s == 2)
+			goto state2;
+		else if (s == 3)
+			goto state3;
+		else
+			goto state4;
+	}
+	handler = &jmploc;
+#ifdef DEBUG
+	opentrace();
+	trputs("Shell args:  ");  trargs(argv);
+#endif
+	rootpid = getpid();
+	init();
+	setstackmark(&smark);
+	procargs(argc, argv);
+	if (argv[0] && argv[0][0] == '-') {
+		state = 1;
+		read_profile("/etc/profile");
+state1:
+		state = 2;
+		read_profile(".profile");
+	}
+state2:
+	state = 3;
+	if (
+#ifndef linux
+		getuid() == geteuid() && getgid() == getegid() &&
+#endif
+		iflag
+	) {
+		if ((shinit = lookupvar("ENV")) != NULL && *shinit != '\0') {
+			read_profile(shinit);
+		}
+	}
+state3:
+	state = 4;
+	if (minusc)
+		evalstring(minusc, 0);
+
+	if (sflag || minusc == NULL) {
+state4:	/* XXX ??? - why isn't this before the "if" statement */
+		cmdloop(1);
+	}
+#if PROFILE
+	monitor(0);
+#endif
+#if GPROF
+	{
+		extern void _mcleanup(void);
+		_mcleanup();
+	}
+#endif
+	exitshell();
+	/* NOTREACHED */
+}
+
+
+/*
+ * Read and execute commands.  "Top" is nonzero for the top level command
+ * loop; it turns on prompting if the shell is interactive.
+ */
+
+static int
+cmdloop(int top)
+{
+	union node *n;
+	struct stackmark smark;
+	int inter;
+	int numeof = 0;
+
+	TRACE(("cmdloop(%d) called\n", top));
+#ifdef HETIO
+	if(iflag && top)
+		hetio_init();
+#endif
+	for (;;) {
+		int skip;
+
+		setstackmark(&smark);
+		if (jobctl)
+			showjobs(out2, SHOW_CHANGED);
+		inter = 0;
+		if (iflag && top) {
+			inter++;
+			chkmail();
+		}
+		n = parsecmd(inter);
+		/* showtree(n); DEBUG */
+		if (n == NEOF) {
+			if (!top || numeof >= 50)
+				break;
+			if (!stoppedjobs()) {
+				if (!Iflag)
+					break;
+				out2str("\nUse \"exit\" to leave shell.\n");
+			}
+			numeof++;
+		} else if (nflag == 0) {
+			job_warning = (job_warning == 2) ? 1 : 0;
+			numeof = 0;
+			evaltree(n, 0);
+		}
+		popstackmark(&smark);
+
+		skip = evalskip;
+		if (skip) {
+			evalskip = 0;
+			return skip & SKIPEVAL;
+		}
+	}
+
+	return 0;
+}
+
+
+
+/*
+ * Read /etc/profile or .profile.  Return on error.
+ */
+
+STATIC void
+read_profile(const char *name)
+{
+	int skip;
+
+	if (setinputfile(name, INPUT_PUSH_FILE | INPUT_NOFILE_OK) < 0)
+		return;
+
+	skip = cmdloop(0);
+	popfile();
+
+	if (skip)
+		exitshell();
+}
+
+
+
+/*
+ * Read a file containing shell functions.
+ */
+
+void
+readcmdfile(char *name)
+{
+	setinputfile(name, INPUT_PUSH_FILE);
+	cmdloop(0);
+	popfile();
+}
+
+
+
+/*
+ * Take commands from a file.  To be compatible we should do a path
+ * search for the file, which is necessary to find sub-commands.
+ */
+
+
+STATIC char *
+find_dot_file(char *basename)
+{
+	char *fullname;
+	const char *path = pathval();
+	struct stat statb;
+
+	/* don't try this for absolute or relative paths */
+	if (strchr(basename, '/'))
+		return basename;
+
+	while ((fullname = padvance(&path, basename)) != NULL) {
+		if ((stat(fullname, &statb) == 0) && S_ISREG(statb.st_mode)) {
+			/*
+			 * Don't bother freeing here, since it will
+			 * be freed by the caller.
+			 */
+			return fullname;
+		}
+		stunalloc(fullname);
+	}
+
+	/* not found in the PATH */
+	sh_error("%s: not found", basename);
+	/* NOTREACHED */
+}
+
+int
+dotcmd(int argc, char **argv)
+{
+	int status = 0;
+
+	if (argc >= 2) {		/* That's what SVR2 does */
+		char *fullname;
+
+		fullname = find_dot_file(argv[1]);
+		setinputfile(fullname, INPUT_PUSH_FILE);
+		commandname = fullname;
+		cmdloop(0);
+		popfile();
+		status = exitstatus;
+	}
+	return status;
+}
+
+
+int
+exitcmd(int argc, char **argv)
+{
+	if (stoppedjobs())
+		return 0;
+	if (argc > 1)
+		exitstatus = number(argv[1]);
+	exraise(EXEXIT);
+	/* NOTREACHED */
+}
diff --git a/usr/dash/main.h b/usr/dash/main.h
new file mode 100644
index 0000000..19e4983
--- /dev/null
+++ b/usr/dash/main.h
@@ -0,0 +1,54 @@
+/*-
+ * Copyright (c) 1991, 1993
+ *	The Regents of the University of California.  All rights reserved.
+ * Copyright (c) 1997-2005
+ *	Herbert Xu <herbert@gondor.apana.org.au>.  All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Kenneth Almquist.
+ *
+ * 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. 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.
+ *
+ *	@(#)main.h	8.2 (Berkeley) 5/4/95
+ */
+
+#include <errno.h>
+
+/* pid of main shell */
+extern int rootpid;
+/* shell level: 0 for the main shell, 1 for its children, and so on */
+extern int shlvl;
+#define rootshell (!shlvl)
+
+#ifdef __GLIBC__
+/* glibc sucks */
+extern int *dash_errno;
+#undef errno
+#define errno (*dash_errno)
+#endif
+
+void readcmdfile(char *);
+int dotcmd(int, char **);
+int exitcmd(int, char **);
diff --git a/usr/dash/memalloc.c b/usr/dash/memalloc.c
new file mode 100644
index 0000000..1b1b323
--- /dev/null
+++ b/usr/dash/memalloc.c
@@ -0,0 +1,329 @@
+/*-
+ * Copyright (c) 1991, 1993
+ *	The Regents of the University of California.  All rights reserved.
+ * Copyright (c) 1997-2005
+ *	Herbert Xu <herbert@gondor.apana.org.au>.  All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Kenneth Almquist.
+ *
+ * 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. 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 <stdlib.h>
+#include <unistd.h>
+
+#include "shell.h"
+#include "output.h"
+#include "memalloc.h"
+#include "error.h"
+#include "machdep.h"
+#include "mystring.h"
+#include "system.h"
+
+/*
+ * Like malloc, but returns an error when out of space.
+ */
+
+pointer
+ckmalloc(size_t nbytes)
+{
+	pointer p;
+
+	p = malloc(nbytes);
+	if (p == NULL)
+		sh_error("Out of space");
+	return p;
+}
+
+
+/*
+ * Same for realloc.
+ */
+
+pointer
+ckrealloc(pointer p, size_t nbytes)
+{
+	p = realloc(p, nbytes);
+	if (p == NULL)
+		sh_error("Out of space");
+	return p;
+}
+
+
+/*
+ * Make a copy of a string in safe storage.
+ */
+
+char *
+savestr(const char *s)
+{
+	char *p = strdup(s);
+	if (!p)
+		sh_error("Out of space");
+	return p;
+}
+
+
+/*
+ * Parse trees for commands are allocated in lifo order, so we use a stack
+ * to make this more efficient, and also to avoid all sorts of exception
+ * handling code to handle interrupts in the middle of a parse.
+ *
+ * The size 504 was chosen because the Ultrix malloc handles that size
+ * well.
+ */
+
+/* minimum size of a block */
+#define MINSIZE SHELL_ALIGN(504)
+
+struct stack_block {
+	struct stack_block *prev;
+	char space[MINSIZE];
+};
+
+struct stack_block stackbase;
+struct stack_block *stackp = &stackbase;
+struct stackmark *markp;
+char *stacknxt = stackbase.space;
+size_t stacknleft = MINSIZE;
+char *sstrend = stackbase.space + MINSIZE;
+int herefd = -1;
+
+pointer
+stalloc(size_t nbytes)
+{
+	char *p;
+	size_t aligned;
+
+	aligned = SHELL_ALIGN(nbytes);
+	if (aligned > stacknleft) {
+		size_t len;
+		size_t blocksize;
+		struct stack_block *sp;
+
+		blocksize = aligned;
+		if (blocksize < MINSIZE)
+			blocksize = MINSIZE;
+		len = sizeof(struct stack_block) - MINSIZE + blocksize;
+		if (len < blocksize)
+			sh_error("Out of space");
+		INTOFF;
+		sp = ckmalloc(len);
+		sp->prev = stackp;
+		stacknxt = sp->space;
+		stacknleft = blocksize;
+		sstrend = stacknxt + blocksize;
+		stackp = sp;
+		INTON;
+	}
+	p = stacknxt;
+	stacknxt += aligned;
+	stacknleft -= aligned;
+	return p;
+}
+
+
+void
+stunalloc(pointer p)
+{
+#ifdef DEBUG
+	if (!p || (stacknxt < (char *)p) || ((char *)p < stackp->space)) {
+		write(2, "stunalloc\n", 10);
+		abort();
+	}
+#endif
+	stacknleft += stacknxt - (char *)p;
+	stacknxt = p;
+}
+
+
+
+void
+setstackmark(struct stackmark *mark)
+{
+	mark->stackp = stackp;
+	mark->stacknxt = stacknxt;
+	mark->stacknleft = stacknleft;
+	mark->marknext = markp;
+	markp = mark;
+}
+
+
+void
+popstackmark(struct stackmark *mark)
+{
+	struct stack_block *sp;
+
+	INTOFF;
+	markp = mark->marknext;
+	while (stackp != mark->stackp) {
+		sp = stackp;
+		stackp = sp->prev;
+		ckfree(sp);
+	}
+	stacknxt = mark->stacknxt;
+	stacknleft = mark->stacknleft;
+	sstrend = mark->stacknxt + mark->stacknleft;
+	INTON;
+}
+
+
+/*
+ * When the parser reads in a string, it wants to stick the string on the
+ * stack and only adjust the stack pointer when it knows how big the
+ * string is.  Stackblock (defined in stack.h) returns a pointer to a block
+ * of space on top of the stack and stackblocklen returns the length of
+ * this block.  Growstackblock will grow this space by at least one byte,
+ * possibly moving it (like realloc).  Grabstackblock actually allocates the
+ * part of the block that has been used.
+ */
+
+void
+growstackblock(void)
+{
+	size_t newlen;
+
+ 	newlen = stacknleft * 2;
+	if (newlen < stacknleft)
+		sh_error("Out of space");
+	if (newlen < 128)
+		newlen += 128;
+
+	if (stacknxt == stackp->space && stackp != &stackbase) {
+		struct stack_block *oldstackp;
+		struct stackmark *xmark;
+		struct stack_block *sp;
+		struct stack_block *prevstackp;
+		size_t grosslen;
+
+		INTOFF;
+		oldstackp = stackp;
+		sp = stackp;
+		prevstackp = sp->prev;
+		grosslen = newlen + sizeof(struct stack_block) - MINSIZE;
+		sp = ckrealloc((pointer)sp, grosslen);
+		sp->prev = prevstackp;
+		stackp = sp;
+		stacknxt = sp->space;
+		stacknleft = newlen;
+		sstrend = sp->space + newlen;
+
+		/*
+		 * Stack marks pointing to the start of the old block
+		 * must be relocated to point to the new block
+		 */
+		xmark = markp;
+		while (xmark != NULL && xmark->stackp == oldstackp) {
+			xmark->stackp = stackp;
+			xmark->stacknxt = stacknxt;
+			xmark->stacknleft = stacknleft;
+			xmark = xmark->marknext;
+		}
+		INTON;
+	} else {
+		char *oldspace = stacknxt;
+		int oldlen = stacknleft;
+		char *p = stalloc(newlen);
+
+		/* free the space we just allocated */
+		stacknxt = memcpy(p, oldspace, oldlen);
+		stacknleft += newlen;
+	}
+}
+
+void
+grabstackblock(size_t len)
+{
+	len = SHELL_ALIGN(len);
+	stacknxt += len;
+	stacknleft -= len;
+}
+
+/*
+ * The following routines are somewhat easier to use than the above.
+ * The user declares a variable of type STACKSTR, which may be declared
+ * to be a register.  The macro STARTSTACKSTR initializes things.  Then
+ * the user uses the macro STPUTC to add characters to the string.  In
+ * effect, STPUTC(c, p) is the same as *p++ = c except that the stack is
+ * grown as necessary.  When the user is done, she can just leave the
+ * string there and refer to it using stackblock().  Or she can allocate
+ * the space for it using grabstackstr().  If it is necessary to allow
+ * someone else to use the stack temporarily and then continue to grow
+ * the string, the user should use grabstack to allocate the space, and
+ * then call ungrabstr(p) to return to the previous mode of operation.
+ *
+ * USTPUTC is like STPUTC except that it doesn't check for overflow.
+ * CHECKSTACKSPACE can be called before USTPUTC to ensure that there
+ * is space for at least one character.
+ */
+
+void *
+growstackstr(void)
+{
+	size_t len = stackblocksize();
+	if (herefd >= 0 && len >= 1024) {
+		xwrite(herefd, stackblock(), len);
+		return stackblock();
+	}
+	growstackblock();
+	return stackblock() + len;
+}
+
+/*
+ * Called from CHECKSTRSPACE.
+ */
+
+char *
+makestrspace(size_t newlen, char *p)
+{
+	size_t len = p - stacknxt;
+	size_t size = stackblocksize();
+
+	for (;;) {
+		size_t nleft;
+
+		size = stackblocksize();
+		nleft = size - len;
+		if (nleft >= newlen)
+			break;
+		growstackblock();
+	}
+	return stackblock() + len;
+}
+
+char *
+stnputs(const char *s, size_t n, char *p)
+{
+	p = makestrspace(n, p);
+	p = mempcpy(p, s, n);
+	return p;
+}
+
+char *
+stputs(const char *s, char *p)
+{
+	return stnputs(s, strlen(s), p);
+}
diff --git a/usr/dash/memalloc.h b/usr/dash/memalloc.h
new file mode 100644
index 0000000..1691d13
--- /dev/null
+++ b/usr/dash/memalloc.h
@@ -0,0 +1,97 @@
+/*-
+ * Copyright (c) 1991, 1993
+ *	The Regents of the University of California.  All rights reserved.
+ * Copyright (c) 1997-2005
+ *	Herbert Xu <herbert@gondor.apana.org.au>.  All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Kenneth Almquist.
+ *
+ * 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. 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.
+ *
+ *	@(#)memalloc.h	8.2 (Berkeley) 5/4/95
+ */
+
+#include <stddef.h>
+
+struct stackmark {
+	struct stack_block *stackp;
+	char *stacknxt;
+	size_t stacknleft;
+	struct stackmark *marknext;
+};
+
+
+extern char *stacknxt;
+extern size_t stacknleft;
+extern char *sstrend;
+extern int herefd;
+
+pointer ckmalloc(size_t);
+pointer ckrealloc(pointer, size_t);
+char *savestr(const char *);
+pointer stalloc(size_t);
+void stunalloc(pointer);
+void setstackmark(struct stackmark *);
+void popstackmark(struct stackmark *);
+void growstackblock(void);
+void grabstackblock(size_t);
+void *growstackstr(void);
+char *makestrspace(size_t, char *);
+char *stnputs(const char *, size_t, char *);
+char *stputs(const char *, char *);
+
+
+static inline char *_STPUTC(char c, char *p) {
+	if (p == sstrend)
+		p = growstackstr();
+	*p++ = c;
+	return p;
+}
+
+#define stackblock() ((void *)stacknxt)
+#define stackblocksize() stacknleft
+#define STARTSTACKSTR(p) ((p) = stackblock())
+#define STPUTC(c, p) ((p) = _STPUTC((c), (p)))
+#define CHECKSTRSPACE(n, p) \
+	({ \
+		char *q = (p); \
+		size_t l = (n); \
+		size_t m = sstrend - q; \
+		if (l > m) \
+			(p) = makestrspace(l, q); \
+		0; \
+	})
+#define USTPUTC(c, p)	(*p++ = (c))
+#define STACKSTRNUL(p)	((p) == sstrend? (p = growstackstr(), *p = '\0') : (*p = '\0'))
+#define STUNPUTC(p)	(--p)
+#define STTOPC(p)	p[-1]
+#define STADJUST(amount, p)	(p += (amount))
+
+#define grabstackstr(p)	stalloc((char *)(p) - (char *)stackblock())
+#define ungrabstackstr(s, p) stunalloc((s))
+#define stackstrend() ((void *)sstrend)
+
+#define ckfree(p)	free((pointer)(p))
diff --git a/usr/dash/miscbltin.c b/usr/dash/miscbltin.c
new file mode 100644
index 0000000..811cd1f
--- /dev/null
+++ b/usr/dash/miscbltin.c
@@ -0,0 +1,512 @@
+/*-
+ * Copyright (c) 1991, 1993
+ *	The Regents of the University of California.  All rights reserved.
+ * Copyright (c) 1997-2005
+ *	Herbert Xu <herbert@gondor.apana.org.au>.  All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Kenneth Almquist.
+ *
+ * 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. 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.
+ */
+
+/*
+ * Miscelaneous builtins.
+ */
+
+#include <sys/types.h>		/* quad_t */
+#include <sys/param.h>		/* BSD4_4 */
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <sys/resource.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <stdint.h>
+#include <time.h>		/* strtotimeval() */
+
+#include "shell.h"
+#include "options.h"
+#include "var.h"
+#include "output.h"
+#include "memalloc.h"
+#include "error.h"
+#include "miscbltin.h"
+#include "mystring.h"
+#include "main.h"
+
+#undef rflag
+
+
+
+/*
+ * The read builtin.  The -e option causes backslashes to escape the
+ * following character.
+ *
+ * This uses unbuffered input, which may be avoidable in some cases.
+ */
+
+int
+readcmd(int argc, char **argv)
+{
+	char **ap;
+	int backslash;
+	char c;
+	int rflag;
+	char *prompt;
+	const char *ifs;
+	char *p;
+	int startword;
+	int status;
+	int timeout;
+	int i;
+	fd_set set;
+	struct timeval ts, t0, t1, to;
+
+	ts.tv_sec = ts.tv_usec = 0;
+
+	rflag = 0;
+	timeout = 0;
+	prompt = NULL;
+	while ((i = nextopt("p:rt:")) != '\0') {
+		switch(i) {
+		case 'p':
+			prompt = optionarg;
+			break;
+		case 't':
+			p = strtotimeval(optionarg, &ts);
+			if (*p || (!ts.tv_sec && !ts.tv_usec))
+				sh_error("invalid timeout");
+			timeout = 1;
+			break;
+		case 'r':
+			rflag = 1;
+			break;
+		default:
+			break;
+		}
+	}
+	if (prompt && isatty(0)) {
+		out2str(prompt);
+#ifdef FLUSHERR
+		flushall();
+#endif
+	}
+	if (*(ap = argptr) == NULL)
+		sh_error("arg count");
+	if ((ifs = bltinlookup("IFS")) == NULL)
+		ifs = defifs;
+	status = 0;
+	startword = 1;
+	backslash = 0;
+	if (timeout) {
+		gettimeofday(&t0, NULL);
+
+		/* ts += t0; */
+		ts.tv_usec += t0.tv_usec;
+		while (ts.tv_usec >= 1000000) {
+			ts.tv_sec++;
+			ts.tv_usec -= 1000000;
+		}
+		ts.tv_sec += t0.tv_sec;
+	}
+	STARTSTACKSTR(p);
+	for (;;) {
+		if (timeout) {
+			gettimeofday(&t1, NULL);
+			if (t1.tv_sec > ts.tv_sec ||
+			    (t1.tv_sec == ts.tv_sec &&
+			     t1.tv_usec >= ts.tv_usec)) {
+				status = 1;
+				break;	/* Timeout! */
+			}
+
+			/* to = ts - t1; */
+			if (ts.tv_usec >= t1.tv_usec) {
+				to.tv_usec = ts.tv_usec - t1.tv_usec;
+				to.tv_sec  = ts.tv_sec - t1.tv_sec;
+			} else {
+				to.tv_usec = ts.tv_usec - t1.tv_usec + 1000000;
+				to.tv_sec  = ts.tv_sec - t1.tv_sec - 1;
+			}
+
+			FD_ZERO(&set);
+			FD_SET(0, &set);
+			if (select(1, &set, NULL, NULL, &to) != 1) {
+				status = 1;
+				break; /* Timeout! */
+			}
+		}
+		if (read(0, &c, 1) != 1) {
+			status = 1;
+			break;
+		}
+		if (c == '\0')
+			continue;
+		if (backslash) {
+			backslash = 0;
+			if (c != '\n')
+				goto put;
+			continue;
+		}
+		if (!rflag && c == '\\') {
+			backslash++;
+			continue;
+		}
+		if (c == '\n')
+			break;
+		if (startword && *ifs == ' ' && strchr(ifs, c)) {
+			continue;
+		}
+		startword = 0;
+		if (ap[1] != NULL && strchr(ifs, c) != NULL) {
+			STACKSTRNUL(p);
+			setvar(*ap, stackblock(), 0);
+			ap++;
+			startword = 1;
+			STARTSTACKSTR(p);
+		} else {
+put:
+			STPUTC(c, p);
+		}
+	}
+	STACKSTRNUL(p);
+	/* Remove trailing blanks */
+	while ((char *)stackblock() <= --p && strchr(ifs, *p) != NULL)
+		*p = '\0';
+	setvar(*ap, stackblock(), 0);
+	while (*++ap != NULL)
+		setvar(*ap, nullstr, 0);
+	return status;
+}
+
+
+
+/*
+ * umask builtin
+ *
+ * This code was ripped from pdksh 5.2.14 and hacked for use with
+ * dash by Herbert Xu.
+ *
+ * Public domain.
+ */
+
+int
+umaskcmd(int argc, char **argv)
+{
+	char *ap;
+	int mask;
+	int i;
+	int symbolic_mode = 0;
+
+	while ((i = nextopt("S")) != '\0') {
+		symbolic_mode = 1;
+	}
+
+	INTOFF;
+	mask = umask(0);
+	umask(mask);
+	INTON;
+
+	if ((ap = *argptr) == NULL) {
+		if (symbolic_mode) {
+			char buf[18];
+			int j;
+
+			mask = ~mask;
+			ap = buf;
+			for (i = 0; i < 3; i++) {
+				*ap++ = "ugo"[i];
+				*ap++ = '=';
+				for (j = 0; j < 3; j++)
+					if (mask & (1 << (8 - (3*i + j))))
+						*ap++ = "rwx"[j];
+				*ap++ = ',';
+			}
+			ap[-1] = '\0';
+			out1fmt("%s\n", buf);
+		} else {
+			out1fmt("%.4o\n", mask);
+		}
+	} else {
+		int new_mask;
+
+		if (isdigit(*ap)) {
+			new_mask = 0;
+			do {
+				if (*ap >= '8' || *ap < '0')
+					sh_error(illnum, *argptr);
+				new_mask = (new_mask << 3) + (*ap - '0');
+			} while (*++ap != '\0');
+		} else {
+			int positions, new_val;
+			char op;
+
+			mask = ~mask;
+			new_mask = mask;
+			positions = 0;
+			while (*ap) {
+				while (*ap && strchr("augo", *ap))
+					switch (*ap++) {
+					case 'a': positions |= 0111; break;
+					case 'u': positions |= 0100; break;
+					case 'g': positions |= 0010; break;
+					case 'o': positions |= 0001; break;
+					}
+				if (!positions)
+					positions = 0111; /* default is a */
+				if (!strchr("=+-", op = *ap))
+					break;
+				ap++;
+				new_val = 0;
+				while (*ap && strchr("rwxugoXs", *ap))
+					switch (*ap++) {
+					case 'r': new_val |= 04; break;
+					case 'w': new_val |= 02; break;
+					case 'x': new_val |= 01; break;
+					case 'u': new_val |= mask >> 6;
+						  break;
+					case 'g': new_val |= mask >> 3;
+						  break;
+					case 'o': new_val |= mask >> 0;
+						  break;
+					case 'X': if (mask & 0111)
+							new_val |= 01;
+						  break;
+					case 's': /* ignored */
+						  break;
+					}
+				new_val = (new_val & 07) * positions;
+				switch (op) {
+				case '-':
+					new_mask &= ~new_val;
+					break;
+				case '=':
+					new_mask = new_val
+					    | (new_mask & ~(positions * 07));
+					break;
+				case '+':
+					new_mask |= new_val;
+				}
+				if (*ap == ',') {
+					positions = 0;
+					ap++;
+				} else if (!strchr("=+-", *ap))
+					break;
+			}
+			if (*ap) {
+				sh_error("Illegal mode: %s", *argptr);
+				return 1;
+			}
+			new_mask = ~new_mask;
+		}
+		umask(new_mask);
+	}
+	return 0;
+}
+
+#ifdef HAVE_GETRLIMIT
+/*
+ * ulimit builtin
+ *
+ * This code, originally by Doug Gwyn, Doug Kingston, Eric Gisin, and
+ * Michael Rendell was ripped from pdksh 5.0.8 and hacked for use with
+ * ash by J.T. Conklin.
+ *
+ * Public domain.
+ */
+
+struct limits {
+	const char *name;
+	int	cmd;
+	int	factor;	/* multiply by to get rlim_{cur,max} values */
+	char	option;
+};
+
+static const struct limits limits[] = {
+#ifdef RLIMIT_CPU
+	{ "time(seconds)",		RLIMIT_CPU,	   1, 't' },
+#endif
+#ifdef RLIMIT_FSIZE
+	{ "file(blocks)",		RLIMIT_FSIZE,	 512, 'f' },
+#endif
+#ifdef RLIMIT_DATA
+	{ "data(kbytes)",		RLIMIT_DATA,	1024, 'd' },
+#endif
+#ifdef RLIMIT_STACK
+	{ "stack(kbytes)",		RLIMIT_STACK,	1024, 's' },
+#endif
+#ifdef RLIMIT_CORE
+	{ "coredump(blocks)",		RLIMIT_CORE,	 512, 'c' },
+#endif
+#ifdef RLIMIT_RSS
+	{ "memory(kbytes)",		RLIMIT_RSS,	1024, 'm' },
+#endif
+#ifdef RLIMIT_MEMLOCK
+	{ "locked memory(kbytes)",	RLIMIT_MEMLOCK, 1024, 'l' },
+#endif
+#ifdef RLIMIT_NPROC
+	{ "process",			RLIMIT_NPROC,      1, 'p' },
+#endif
+#ifdef RLIMIT_NOFILE
+	{ "nofiles",			RLIMIT_NOFILE,     1, 'n' },
+#endif
+#ifdef RLIMIT_AS
+	{ "vmemory(kbytes)",		RLIMIT_AS,	1024, 'v' },
+#endif
+#ifdef RLIMIT_LOCKS
+	{ "locks",			RLIMIT_LOCKS,	   1, 'w' },
+#endif
+	{ (char *) 0,			0,		   0,  '\0' }
+};
+
+enum limtype { SOFT = 0x1, HARD = 0x2 };
+
+static void printlim(enum limtype how, const struct rlimit *limit,
+		     const struct limits *l)
+{
+	rlim_t val;
+
+	val = limit->rlim_max;
+	if (how & SOFT)
+		val = limit->rlim_cur;
+
+	if (val == RLIM_INFINITY)
+		out1fmt("unlimited\n");
+	else {
+		val /= l->factor;
+		out1fmt("%jd\n", (intmax_t) val);
+	}
+}
+
+int
+ulimitcmd(int argc, char **argv)
+{
+	int	c;
+	rlim_t val = 0;
+	enum limtype how = SOFT | HARD;
+	const struct limits	*l;
+	int		set, all = 0;
+	int		optc, what;
+	struct rlimit	limit;
+
+	what = 'f';
+	while ((optc = nextopt("HSa"
+#ifdef RLIMIT_CPU
+			       "t"
+#endif
+#ifdef RLIMIT_FSIZE
+			       "f"
+#endif
+#ifdef RLIMIT_DATA
+			       "d"
+#endif
+#ifdef RLIMIT_STACK
+			       "s"
+#endif
+#ifdef RLIMIT_CORE
+			       "c"
+#endif
+#ifdef RLIMIT_RSS
+			       "m"
+#endif
+#ifdef RLIMIT_MEMLOCK
+			       "l"
+#endif
+#ifdef RLIMIT_NPROC
+			       "p"
+#endif
+#ifdef RLIMIT_NOFILE
+			       "n"
+#endif
+#ifdef RLIMIT_AS
+			       "v"
+#endif
+#ifdef RLIMIT_LOCKS
+			       "w"
+#endif
+	)) != '\0')
+		switch (optc) {
+		case 'H':
+			how = HARD;
+			break;
+		case 'S':
+			how = SOFT;
+			break;
+		case 'a':
+			all = 1;
+			break;
+		default:
+			what = optc;
+		}
+
+	for (l = limits; l->option != what; l++)
+		;
+
+	set = *argptr ? 1 : 0;
+	if (set) {
+		char *p = *argptr;
+
+		if (all || argptr[1])
+			sh_error("too many arguments");
+		if (strcmp(p, "unlimited") == 0)
+			val = RLIM_INFINITY;
+		else {
+			val = (rlim_t) 0;
+
+			while ((c = *p++) >= '0' && c <= '9')
+			{
+				val = (val * 10) + (long)(c - '0');
+				if (val < (rlim_t) 0)
+					break;
+			}
+			if (c)
+				sh_error("bad number");
+			val *= l->factor;
+		}
+	}
+	if (all) {
+		for (l = limits; l->name; l++) {
+			getrlimit(l->cmd, &limit);
+			out1fmt("%-20s ", l->name);
+			printlim(how, &limit, l);
+		}
+		return 0;
+	}
+
+	getrlimit(l->cmd, &limit);
+	if (set) {
+		if (how & HARD)
+			limit.rlim_max = val;
+		if (how & SOFT)
+			limit.rlim_cur = val;
+		if (setrlimit(l->cmd, &limit) < 0)
+			sh_error("error setting limit (%s)", strerror(errno));
+	} else {
+		printlim(how, &limit, l);
+	}
+	return 0;
+}
+#endif
diff --git a/usr/dash/miscbltin.h b/usr/dash/miscbltin.h
new file mode 100644
index 0000000..dd9a8d1
--- /dev/null
+++ b/usr/dash/miscbltin.h
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 1997 Christos Zoulas.  All rights reserved.
+ * Copyright (c) 1997-2005
+ *	Herbert Xu <herbert@gondor.apana.org.au>.  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.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
+ */
+
+int readcmd(int, char **);
+int umaskcmd(int, char **);
+int ulimitcmd(int, char **);
diff --git a/usr/dash/mkbuiltins b/usr/dash/mkbuiltins
new file mode 100644
index 0000000..3833052
--- /dev/null
+++ b/usr/dash/mkbuiltins
@@ -0,0 +1,101 @@
+#!/bin/sh -
+#	$NetBSD: mkbuiltins,v 1.17 2002/11/24 22:35:41 christos Exp $
+#
+# Copyright (c) 1991, 1993
+#	The Regents of the University of California.  All rights reserved.
+# Copyright (c) 1997-2005
+#	Herbert Xu <herbert@gondor.apana.org.au>.  All rights reserved.
+#
+# This code is derived from software contributed to Berkeley by
+# Kenneth Almquist.
+#
+# 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. 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.
+#
+#	@(#)mkbuiltins	8.2 (Berkeley) 5/4/95
+
+tempfile=tempfile
+if ! type tempfile > /dev/null 2>&1; then
+	tempfile="mktemp ${TMPDIR:-/tmp}/builtin.XXXXXX"
+fi
+
+trap 'rm -f $temp $temp2' EXIT
+temp=$($tempfile)
+temp2=$($tempfile)
+
+builtins=$1
+
+exec > builtins.c
+cat <<\!
+/*
+ * This file was generated by the mkbuiltins program.
+ */
+
+#include "shell.h"
+#include "builtins.h"
+
+!
+< $builtins sed '/^#/d; /^$/d' > $temp
+awk '{	printf "int %s(int, char **);\n", $1}' $temp
+echo '
+const struct builtincmd builtincmd[] = {'
+awk '{	for (i = 2 ; i <= NF ; i++) {
+		line = $i "\t" $1
+		if ($i ~ /^-/)
+			line = $(++i) "\t" line
+		print line
+	}}' $temp | sort -k 1,1 | tee $temp2 | awk '{
+		opt = ""
+		if (NF > 2) {
+			opt = substr($2, 2)
+			$2 = $3
+		}
+		printf "\t{ \"%s\", %s, %d },\n", $1, $2,
+			(opt ~ /s/) + (opt ~ /[su]/) * 2 + (opt ~ /a/) * 4
+	}'
+echo '};'
+
+exec > builtins.h
+cat <<\!
+/*
+ * This file was generated by the mkbuiltins program.
+ */
+
+!
+sed 's/	-[a-z]*//' $temp2 | nl -v 0 | sort -u -k 3,3 |
+tr abcdefghijklmnopqrstuvwxyz ABCDEFGHIJKLMNOPQRSTUVWXYZ |
+	awk '{	printf "#define %s (builtincmd + %d)\n", $3, $1}'
+printf '\n#define NUMBUILTINS %d\n' $(wc -l < $temp2)
+echo '
+#define BUILTIN_SPECIAL 0x1
+#define BUILTIN_REGULAR 0x2
+#define BUILTIN_ASSIGN 0x4
+
+struct builtincmd {
+	const char *name;
+	int (*builtin)(int, char **);
+	unsigned flags;
+};
+
+extern const struct builtincmd builtincmd[];'
diff --git a/usr/dash/mkinit.c b/usr/dash/mkinit.c
new file mode 100644
index 0000000..e803751
--- /dev/null
+++ b/usr/dash/mkinit.c
@@ -0,0 +1,476 @@
+/*-
+ * Copyright (c) 1991, 1993
+ *	The Regents of the University of California.  All rights reserved.
+ * Copyright (c) 1997-2005
+ *	Herbert Xu <herbert@gondor.apana.org.au>.  All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Kenneth Almquist.
+ *
+ * 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. 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.
+ */
+
+/*
+ * This program scans all the source files for code to handle various
+ * special events and combines this code into one file.  This (allegedly)
+ * improves the structure of the program since there is no need for
+ * anyone outside of a module to know that that module performs special
+ * operations on particular events.
+ *
+ * Usage:  mkinit sourcefile...
+ */
+
+
+#include <sys/types.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+
+/*
+ * OUTFILE is the name of the output file.  Output is initially written
+ * to the file OUTTEMP, which is then moved to OUTFILE.
+ */
+
+#define OUTFILE "init.c"
+#define OUTTEMP "init.c.new"
+
+
+/*
+ * A text structure is basicly just a string that grows as more characters
+ * are added onto the end of it.  It is implemented as a linked list of
+ * blocks of characters.  The routines addstr and addchar append a string
+ * or a single character, respectively, to a text structure.  Writetext
+ * writes the contents of a text structure to a file.
+ */
+
+#define BLOCKSIZE 512
+
+struct text {
+	char *nextc;
+	int nleft;
+	struct block *start;
+	struct block *last;
+};
+
+struct block {
+	struct block *next;
+	char text[BLOCKSIZE];
+};
+
+
+/*
+ * There is one event structure for each event that mkinit handles.
+ */
+
+struct event {
+	char *name;		/* name of event (e.g. INIT) */
+	char *routine;		/* name of routine called on event */
+	char *comment;		/* comment describing routine */
+	struct text code;	/* code for handling event */
+};
+
+
+char writer[] = "\
+/*\n\
+ * This file was generated by the mkinit program.\n\
+ */\n\
+\n";
+
+char init[] = "\
+/*\n\
+ * Initialization code.\n\
+ */\n";
+
+char reset[] = "\
+/*\n\
+ * This routine is called when an error or an interrupt occurs in an\n\
+ * interactive shell and control is returned to the main command loop.\n\
+ */\n";
+
+
+struct event event[] = {
+	{"INIT", "init", init},
+	{"RESET", "reset", reset},
+	{NULL, NULL}
+};
+
+
+char *curfile;				/* current file */
+int linno;				/* current line */
+char *header_files[200];		/* list of header files */
+struct text defines;			/* #define statements */
+struct text decls;			/* declarations */
+int amiddecls;				/* for formatting */
+
+
+void readfile(char *);
+int match(char *, char *);
+int gooddefine(char *);
+void doevent(struct event *, FILE *, char *);
+void doinclude(char *);
+void dodecl(char *, FILE *);
+void output(void);
+void addstr(char *, struct text *);
+void addchar(int, struct text *);
+void writetext(struct text *, FILE *);
+FILE *ckfopen(char *, char *);
+void *ckmalloc(int);
+char *savestr(char *);
+static void error(char *);
+int main(int, char **);
+
+#define equal(s1, s2)	(strcmp(s1, s2) == 0)
+
+int
+main(int argc, char **argv)
+{
+	char **ap;
+
+	header_files[0] = "\"shell.h\"";
+	header_files[1] = "\"mystring.h\"";
+	header_files[2] = "\"init.h\"";
+	for (ap = argv + 1 ; *ap ; ap++)
+		readfile(*ap);
+	output();
+	rename(OUTTEMP, OUTFILE);
+	exit(0);
+	/* NOTREACHED */
+}
+
+
+/*
+ * Parse an input file.
+ */
+
+void
+readfile(char *fname)
+{
+	FILE *fp;
+	char line[1024];
+	struct event *ep;
+
+	fp = ckfopen(fname, "r");
+	curfile = fname;
+	linno = 0;
+	amiddecls = 0;
+	while (fgets(line, sizeof line, fp) != NULL) {
+		linno++;
+		for (ep = event ; ep->name ; ep++) {
+			if (line[0] == ep->name[0] && match(ep->name, line)) {
+				doevent(ep, fp, fname);
+				break;
+			}
+		}
+		if (line[0] == 'I' && match("INCLUDE", line))
+			doinclude(line);
+		if (line[0] == 'M' && match("MKINIT", line))
+			dodecl(line, fp);
+		if (line[0] == '#' && gooddefine(line)) {
+		        char *cp;
+			char line2[1024];
+			static const char undef[] = "#undef ";
+
+			strcpy(line2, line);
+			memcpy(line2, undef, sizeof(undef) - 1);
+			cp = line2 + sizeof(undef) - 1;
+			while(*cp && (*cp == ' ' || *cp == '\t'))
+			        cp++;
+			while(*cp && *cp != ' ' && *cp != '\t' && *cp != '\n')
+			        cp++;
+			*cp++ = '\n'; *cp = '\0';
+			addstr(line2, &defines);
+			addstr(line, &defines);
+		}
+	}
+	fclose(fp);
+}
+
+
+int
+match(char *name, char *line)
+{
+	char *p, *q;
+
+	p = name, q = line;
+	while (*p) {
+		if (*p++ != *q++)
+			return 0;
+	}
+	if (*q != '{' && *q != ' ' && *q != '\t' && *q != '\n')
+		return 0;
+	return 1;
+}
+
+
+int
+gooddefine(char *line)
+{
+	char *p;
+
+	if (! match("#define", line))
+		return 0;			/* not a define */
+	p = line + 7;
+	while (*p == ' ' || *p == '\t')
+		p++;
+	while (*p != ' ' && *p != '\t') {
+		if (*p == '(')
+			return 0;		/* macro definition */
+		p++;
+	}
+	while (*p != '\n' && *p != '\0')
+		p++;
+	if (p[-1] == '\\')
+		return 0;			/* multi-line definition */
+	return 1;
+}
+
+
+void
+doevent(struct event *ep, FILE *fp, char *fname)
+{
+	char line[1024];
+	int indent;
+	char *p;
+
+	sprintf(line, "\n      /* from %s: */\n", fname);
+	addstr(line, &ep->code);
+	addstr("      {\n", &ep->code);
+	for (;;) {
+		linno++;
+		if (fgets(line, sizeof line, fp) == NULL)
+			error("Unexpected EOF");
+		if (equal(line, "}\n"))
+			break;
+		indent = 6;
+		for (p = line ; *p == '\t' ; p++)
+			indent += 8;
+		for ( ; *p == ' ' ; p++)
+			indent++;
+		if (*p == '\n' || *p == '#')
+			indent = 0;
+		while (indent >= 8) {
+			addchar('\t', &ep->code);
+			indent -= 8;
+		}
+		while (indent > 0) {
+			addchar(' ', &ep->code);
+			indent--;
+		}
+		addstr(p, &ep->code);
+	}
+	addstr("      }\n", &ep->code);
+}
+
+
+void
+doinclude(char *line)
+{
+	char *p;
+	char *name;
+	char **pp;
+
+	for (p = line ; *p != '"' && *p != '<' && *p != '\0' ; p++);
+	if (*p == '\0')
+		error("Expecting '\"' or '<'");
+	name = p;
+	while (*p != ' ' && *p != '\t' && *p != '\n')
+		p++;
+	if (p[-1] != '"' && p[-1] != '>')
+		error("Missing terminator");
+	*p = '\0';
+
+	/* name now contains the name of the include file */
+	for (pp = header_files ; *pp && ! equal(*pp, name) ; pp++);
+	if (*pp == NULL)
+		*pp = savestr(name);
+}
+
+
+void
+dodecl(char *line1, FILE *fp)
+{
+	char line[1024];
+	char *p, *q;
+
+	if (strcmp(line1, "MKINIT\n") == 0) { /* start of struct/union decl */
+		addchar('\n', &decls);
+		do {
+			linno++;
+			if (fgets(line, sizeof line, fp) == NULL)
+				error("Unterminated structure declaration");
+			addstr(line, &decls);
+		} while (line[0] != '}');
+		amiddecls = 0;
+	} else {
+		if (! amiddecls)
+			addchar('\n', &decls);
+		q = NULL;
+		for (p = line1 + 6 ; *p && strchr("=/\n", *p) == NULL; p++)
+			continue;
+		if (*p == '=') {		/* eliminate initialization */
+			for (q = p ; *q && *q != ';' ; q++);
+			if (*q == '\0')
+				q = NULL;
+			else {
+				while (p[-1] == ' ')
+					p--;
+				*p = '\0';
+			}
+		}
+		addstr("extern", &decls);
+		addstr(line1 + 6, &decls);
+		if (q != NULL)
+			addstr(q, &decls);
+		amiddecls = 1;
+	}
+}
+
+
+
+/*
+ * Write the output to the file OUTTEMP.
+ */
+
+void
+output(void)
+{
+	FILE *fp;
+	char **pp;
+	struct event *ep;
+
+	fp = ckfopen(OUTTEMP, "w");
+	fputs(writer, fp);
+	for (pp = header_files ; *pp ; pp++)
+		fprintf(fp, "#include %s\n", *pp);
+	fputs("\n\n\n", fp);
+	writetext(&defines, fp);
+	fputs("\n\n", fp);
+	writetext(&decls, fp);
+	for (ep = event ; ep->name ; ep++) {
+		fputs("\n\n\n", fp);
+		fputs(ep->comment, fp);
+		fprintf(fp, "\nvoid\n%s() {\n", ep->routine);
+		writetext(&ep->code, fp);
+		fprintf(fp, "}\n");
+	}
+	fclose(fp);
+}
+
+
+/*
+ * A text structure is simply a block of text that is kept in memory.
+ * Addstr appends a string to the text struct, and addchar appends a single
+ * character.
+ */
+
+void
+addstr(char *s, struct text *text)
+{
+	while (*s) {
+		if (--text->nleft < 0)
+			addchar(*s++, text);
+		else
+			*text->nextc++ = *s++;
+	}
+}
+
+
+void
+addchar(int c, struct text *text)
+{
+	struct block *bp;
+
+	if (--text->nleft < 0) {
+		bp = ckmalloc(sizeof *bp);
+		if (text->start == NULL)
+			text->start = bp;
+		else
+			text->last->next = bp;
+		text->last = bp;
+		text->nextc = bp->text;
+		text->nleft = BLOCKSIZE - 1;
+	}
+	*text->nextc++ = c;
+}
+
+/*
+ * Write the contents of a text structure to a file.
+ */
+void
+writetext(struct text *text, FILE *fp)
+{
+	struct block *bp;
+
+	if (text->start != NULL) {
+		for (bp = text->start ; bp != text->last ; bp = bp->next)
+			fwrite(bp->text, sizeof (char), BLOCKSIZE, fp);
+		fwrite(bp->text, sizeof (char), BLOCKSIZE - text->nleft, fp);
+	}
+}
+
+FILE *
+ckfopen(char *file, char *mode)
+{
+	FILE *fp;
+
+	if ((fp = fopen(file, mode)) == NULL) {
+		fprintf(stderr, "Can't open %s\n", file);
+		exit(2);
+	}
+	return fp;
+}
+
+void *
+ckmalloc(int nbytes)
+{
+	char *p;
+
+	if ((p = malloc(nbytes)) == NULL)
+		error("Out of space");
+	return p;
+}
+
+char *
+savestr(char *s)
+{
+	char *p;
+
+	p = ckmalloc(strlen(s) + 1);
+	strcpy(p, s);
+	return p;
+}
+
+static void
+error(char *msg)
+{
+	if (curfile != NULL)
+		fprintf(stderr, "%s:%d: ", curfile, linno);
+	fprintf(stderr, "%s\n", msg);
+	exit(2);
+	/* NOTREACHED */
+}
diff --git a/usr/dash/mknodes.c b/usr/dash/mknodes.c
new file mode 100644
index 0000000..1903a60
--- /dev/null
+++ b/usr/dash/mknodes.c
@@ -0,0 +1,448 @@
+/*-
+ * Copyright (c) 1991, 1993
+ *	The Regents of the University of California.  All rights reserved.
+ * Copyright (c) 1997-2005
+ *	Herbert Xu <herbert@gondor.apana.org.au>.  All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Kenneth Almquist.
+ *
+ * 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. 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.
+ */
+
+/*
+ * This program reads the nodetypes file and nodes.c.pat file.  It generates
+ * the files nodes.h and nodes.c.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdarg.h>
+
+#define MAXTYPES 50		/* max number of node types */
+#define MAXFIELDS 20		/* max fields in a structure */
+#define BUFLEN 100		/* size of character buffers */
+
+/* field types */
+#define T_NODE 1		/* union node *field */
+#define T_NODELIST 2		/* struct nodelist *field */
+#define T_STRING 3
+#define T_INT 4			/* int field */
+#define T_OTHER 5		/* other */
+#define T_TEMP 6		/* don't copy this field */
+
+
+struct field {			/* a structure field */
+	char *name;		/* name of field */
+	int type;			/* type of field */
+	char *decl;		/* declaration of field */
+};
+
+
+struct str {			/* struct representing a node structure */
+	char *tag;		/* structure tag */
+	int nfields;		/* number of fields in the structure */
+	struct field field[MAXFIELDS];	/* the fields of the structure */
+	int done;			/* set if fully parsed */
+};
+
+
+static int ntypes;			/* number of node types */
+static char *nodename[MAXTYPES];	/* names of the nodes */
+static struct str *nodestr[MAXTYPES];	/* type of structure used by the node */
+static int nstr;			/* number of structures */
+static struct str str[MAXTYPES];	/* the structures */
+static struct str *curstr;		/* current structure */
+static FILE *infp;
+static char line[1024];
+static int linno;
+static char *linep;
+
+static void parsenode(void);
+static void parsefield(void);
+static void output(char *);
+static void outsizes(FILE *);
+static void outfunc(FILE *, int);
+static void indent(int, FILE *);
+static int nextfield(char *);
+static void skipbl(void);
+static int readline(void);
+static void error(const char *, ...);
+static char *savestr(const char *);
+int main(int, char **);
+
+
+int
+main(int argc, char **argv)
+{
+
+	/*
+	 * some versions of linux complain: initializer element is not
+	 * constant if this is done at compile time.
+	 */
+	infp = stdin;
+
+	if (argc != 3)
+		error("usage: mknodes file");
+	if ((infp = fopen(argv[1], "r")) == NULL)
+		error("Can't open %s", argv[1]);
+	while (readline()) {
+		if (line[0] == ' ' || line[0] == '\t')
+			parsefield();
+		else if (line[0] != '\0')
+			parsenode();
+	}
+	output(argv[2]);
+	exit(0);
+	/* NOTREACHED */
+}
+
+
+
+static void
+parsenode(void)
+{
+	char name[BUFLEN];
+	char tag[BUFLEN];
+	struct str *sp;
+
+	if (curstr && curstr->nfields > 0)
+		curstr->done = 1;
+	nextfield(name);
+	if (! nextfield(tag))
+		error("Tag expected");
+	if (*linep != '\0')
+		error("Garbage at end of line");
+	nodename[ntypes] = savestr(name);
+	for (sp = str ; sp < str + nstr ; sp++) {
+		if (strcmp(sp->tag, tag) == 0)
+			break;
+	}
+	if (sp >= str + nstr) {
+		sp->tag = savestr(tag);
+		sp->nfields = 0;
+		curstr = sp;
+		nstr++;
+	}
+	nodestr[ntypes] = sp;
+	ntypes++;
+}
+
+
+static void
+parsefield(void)
+{
+	char name[BUFLEN];
+	char type[BUFLEN];
+	char decl[2 * BUFLEN];
+	struct field *fp;
+
+	if (curstr == NULL || curstr->done)
+		error("No current structure to add field to");
+	if (! nextfield(name))
+		error("No field name");
+	if (! nextfield(type))
+		error("No field type");
+	fp = &curstr->field[curstr->nfields];
+	fp->name = savestr(name);
+	if (strcmp(type, "nodeptr") == 0) {
+		fp->type = T_NODE;
+		sprintf(decl, "union node *%s", name);
+	} else if (strcmp(type, "nodelist") == 0) {
+		fp->type = T_NODELIST;
+		sprintf(decl, "struct nodelist *%s", name);
+	} else if (strcmp(type, "string") == 0) {
+		fp->type = T_STRING;
+		sprintf(decl, "char *%s", name);
+	} else if (strcmp(type, "int") == 0) {
+		fp->type = T_INT;
+		sprintf(decl, "int %s", name);
+	} else if (strcmp(type, "other") == 0) {
+		fp->type = T_OTHER;
+	} else if (strcmp(type, "temp") == 0) {
+		fp->type = T_TEMP;
+	} else {
+		error("Unknown type %s", type);
+	}
+	if (fp->type == T_OTHER || fp->type == T_TEMP) {
+		skipbl();
+		fp->decl = savestr(linep);
+	} else {
+		if (*linep)
+			error("Garbage at end of line");
+		fp->decl = savestr(decl);
+	}
+	curstr->nfields++;
+}
+
+
+char writer[] = "\
+/*\n\
+ * This file was generated by the mknodes program.\n\
+ */\n\
+\n";
+
+static void
+output(char *file)
+{
+	FILE *hfile;
+	FILE *cfile;
+	FILE *patfile;
+	int i;
+	struct str *sp;
+	struct field *fp;
+	char *p;
+
+	if ((patfile = fopen(file, "r")) == NULL)
+		error("Can't open %s", file);
+	if ((hfile = fopen("nodes.h", "w")) == NULL)
+		error("Can't create nodes.h");
+	if ((cfile = fopen("nodes.c", "w")) == NULL)
+		error("Can't create nodes.c");
+	fputs(writer, hfile);
+	for (i = 0 ; i < ntypes ; i++)
+		fprintf(hfile, "#define %s %d\n", nodename[i], i);
+	fputs("\n\n\n", hfile);
+	for (sp = str ; sp < &str[nstr] ; sp++) {
+		fprintf(hfile, "struct %s {\n", sp->tag);
+		for (i = sp->nfields, fp = sp->field ; --i >= 0 ; fp++) {
+			fprintf(hfile, "      %s;\n", fp->decl);
+		}
+		fputs("};\n\n\n", hfile);
+	}
+	fputs("union node {\n", hfile);
+	fprintf(hfile, "      int type;\n");
+	for (sp = str ; sp < &str[nstr] ; sp++) {
+		fprintf(hfile, "      struct %s %s;\n", sp->tag, sp->tag);
+	}
+	fputs("};\n\n\n", hfile);
+	fputs("struct nodelist {\n", hfile);
+	fputs("\tstruct nodelist *next;\n", hfile);
+	fputs("\tunion node *n;\n", hfile);
+	fputs("};\n\n\n", hfile);
+	fputs("struct funcnode {\n", hfile);
+	fputs("\tint count;\n", hfile);
+	fputs("\tunion node n;\n", hfile);
+	fputs("};\n\n\n", hfile);
+	fputs("struct funcnode *copyfunc(union node *);\n", hfile);
+	fputs("void freefunc(struct funcnode *);\n", hfile);
+
+	fputs(writer, cfile);
+	while (fgets(line, sizeof line, patfile) != NULL) {
+		for (p = line ; *p == ' ' || *p == '\t' ; p++);
+		if (strcmp(p, "%SIZES\n") == 0)
+			outsizes(cfile);
+		else if (strcmp(p, "%CALCSIZE\n") == 0)
+			outfunc(cfile, 1);
+		else if (strcmp(p, "%COPY\n") == 0)
+			outfunc(cfile, 0);
+		else
+			fputs(line, cfile);
+	}
+}
+
+
+
+static void
+outsizes(FILE *cfile)
+{
+	int i;
+
+	fprintf(cfile, "static const short nodesize[%d] = {\n", ntypes);
+	for (i = 0 ; i < ntypes ; i++) {
+		fprintf(cfile, "      SHELL_ALIGN(sizeof (struct %s)),\n",
+		    nodestr[i]->tag);
+	}
+	fprintf(cfile, "};\n");
+}
+
+
+static void
+outfunc(FILE *cfile, int calcsize)
+{
+	struct str *sp;
+	struct field *fp;
+	int i;
+
+	fputs("      if (n == NULL)\n", cfile);
+	if (calcsize)
+		fputs("	    return;\n", cfile);
+	else
+		fputs("	    return NULL;\n", cfile);
+	if (calcsize)
+		fputs("      funcblocksize += nodesize[n->type];\n", cfile);
+	else {
+		fputs("      new = funcblock;\n", cfile);
+		fputs("      funcblock = (char *) funcblock + nodesize[n->type];\n", cfile);
+	}
+	fputs("      switch (n->type) {\n", cfile);
+	for (sp = str ; sp < &str[nstr] ; sp++) {
+		for (i = 0 ; i < ntypes ; i++) {
+			if (nodestr[i] == sp)
+				fprintf(cfile, "      case %s:\n", nodename[i]);
+		}
+		for (i = sp->nfields ; --i >= 1 ; ) {
+			fp = &sp->field[i];
+			switch (fp->type) {
+			case T_NODE:
+				if (calcsize) {
+					indent(12, cfile);
+					fprintf(cfile, "calcsize(n->%s.%s);\n",
+						sp->tag, fp->name);
+				} else {
+					indent(12, cfile);
+					fprintf(cfile, "new->%s.%s = copynode(n->%s.%s);\n",
+						sp->tag, fp->name, sp->tag, fp->name);
+				}
+				break;
+			case T_NODELIST:
+				if (calcsize) {
+					indent(12, cfile);
+					fprintf(cfile, "sizenodelist(n->%s.%s);\n",
+						sp->tag, fp->name);
+				} else {
+					indent(12, cfile);
+					fprintf(cfile, "new->%s.%s = copynodelist(n->%s.%s);\n",
+						sp->tag, fp->name, sp->tag, fp->name);
+				}
+				break;
+			case T_STRING:
+				if (calcsize) {
+					indent(12, cfile);
+					fprintf(cfile, "funcstringsize += strlen(n->%s.%s) + 1;\n",
+						sp->tag, fp->name);
+				} else {
+					indent(12, cfile);
+					fprintf(cfile, "new->%s.%s = nodesavestr(n->%s.%s);\n",
+						sp->tag, fp->name, sp->tag, fp->name);
+				}
+				break;
+			case T_INT:
+			case T_OTHER:
+				if (! calcsize) {
+					indent(12, cfile);
+					fprintf(cfile, "new->%s.%s = n->%s.%s;\n",
+						sp->tag, fp->name, sp->tag, fp->name);
+				}
+				break;
+			}
+		}
+		indent(12, cfile);
+		fputs("break;\n", cfile);
+	}
+	fputs("      };\n", cfile);
+	if (! calcsize)
+		fputs("      new->type = n->type;\n", cfile);
+}
+
+
+static void
+indent(int amount, FILE *fp)
+{
+	while (amount >= 8) {
+		putc('\t', fp);
+		amount -= 8;
+	}
+	while (--amount >= 0) {
+		putc(' ', fp);
+	}
+}
+
+
+static int
+nextfield(char *buf)
+{
+	char *p, *q;
+
+	p = linep;
+	while (*p == ' ' || *p == '\t')
+		p++;
+	q = buf;
+	while (*p != ' ' && *p != '\t' && *p != '\0')
+		*q++ = *p++;
+	*q = '\0';
+	linep = p;
+	return (q > buf);
+}
+
+
+static void
+skipbl(void)
+{
+	while (*linep == ' ' || *linep == '\t')
+		linep++;
+}
+
+
+static int
+readline(void)
+{
+	char *p;
+
+	if (fgets(line, 1024, infp) == NULL)
+		return 0;
+	for (p = line ; *p != '#' && *p != '\n' && *p != '\0' ; p++);
+	while (p > line && (p[-1] == ' ' || p[-1] == '\t'))
+		p--;
+	*p = '\0';
+	linep = line;
+	linno++;
+	if (p - line > BUFLEN)
+		error("Line too long");
+	return 1;
+}
+
+
+
+static void
+error(const char *msg, ...)
+{
+	va_list va;
+
+	va_start(va, msg);
+
+	(void) fprintf(stderr, "line %d: ", linno);
+	(void) vfprintf(stderr, msg, va);
+	(void) fputc('\n', stderr);
+
+	va_end(va);
+
+	exit(2);
+	/* NOTREACHED */
+}
+
+
+
+static char *
+savestr(const char *s)
+{
+	char *p;
+
+	if ((p = malloc(strlen(s) + 1)) == NULL)
+		error("Out of space");
+	(void) strcpy(p, s);
+	return p;
+}
diff --git a/usr/dash/mksyntax.c b/usr/dash/mksyntax.c
new file mode 100644
index 0000000..7a8a9ae
--- /dev/null
+++ b/usr/dash/mksyntax.c
@@ -0,0 +1,315 @@
+/*-
+ * Copyright (c) 1991, 1993
+ *	The Regents of the University of California.  All rights reserved.
+ * Copyright (c) 1997-2005
+ *	Herbert Xu <herbert@gondor.apana.org.au>.  All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Kenneth Almquist.
+ *
+ * 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. 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.
+ */
+
+/*
+ * This program creates syntax.h and syntax.c.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include "parser.h"
+
+
+struct synclass {
+	char *name;
+	char *comment;
+};
+
+/* Syntax classes */
+struct synclass synclass[] = {
+	{ "CWORD",	"character is nothing special" },
+	{ "CNL",	"newline character" },
+	{ "CBACK",	"a backslash character" },
+	{ "CSQUOTE",	"single quote" },
+	{ "CDQUOTE",	"double quote" },
+	{ "CENDQUOTE",	"a terminating quote" },
+	{ "CBQUOTE",	"backwards single quote" },
+	{ "CVAR",	"a dollar sign" },
+	{ "CENDVAR",	"a '}' character" },
+	{ "CLP",	"a left paren in arithmetic" },
+	{ "CRP",	"a right paren in arithmetic" },
+	{ "CEOF",	"end of file" },
+	{ "CCTL",	"like CWORD, except it must be escaped" },
+	{ "CSPCL",	"these terminate a word" },
+	{ "CIGN",	"character should be ignored" },
+	{ NULL,		NULL }
+};
+
+
+/*
+ * Syntax classes for is_ functions.  Warning:  if you add new classes
+ * you may have to change the definition of the is_in_name macro.
+ */
+struct synclass is_entry[] = {
+	{ "ISDIGIT",	"a digit" },
+	{ "ISUPPER",	"an upper case letter" },
+	{ "ISLOWER",	"a lower case letter" },
+	{ "ISUNDER",	"an underscore" },
+	{ "ISSPECL",	"the name of a special parameter" },
+	{ NULL, 	NULL }
+};
+
+static char writer[] = "\
+/*\n\
+ * This file was generated by the mksyntax program.\n\
+ */\n\
+\n";
+
+
+static FILE *cfile;
+static FILE *hfile;
+static char *syntax[513];
+
+static void filltable(char *);
+static void init(void);
+static void add(char *, char *);
+static void print(char *);
+static void output_type_macros(void);
+int main(int, char **);
+
+int
+main(int argc, char **argv)
+{
+	int i;
+	char buf[80];
+	int pos;
+
+	/* Create output files */
+	if ((cfile = fopen("syntax.c", "w")) == NULL) {
+		perror("syntax.c");
+		exit(2);
+	}
+	if ((hfile = fopen("syntax.h", "w")) == NULL) {
+		perror("syntax.h");
+		exit(2);
+	}
+	fputs(writer, hfile);
+	fputs(writer, cfile);
+
+	fputs("#include <ctype.h>\n", hfile);
+	fputs("\n", hfile);
+	fputs("#ifdef CEOF\n", hfile);
+	fputs("#undef CEOF\n", hfile);
+	fputs("#endif\n", hfile);
+	fputs("\n", hfile);
+
+	/* Generate the #define statements in the header file */
+	fputs("/* Syntax classes */\n", hfile);
+	for (i = 0 ; synclass[i].name ; i++) {
+		sprintf(buf, "#define %s %d", synclass[i].name, i);
+		fputs(buf, hfile);
+		for (pos = strlen(buf) ; pos < 32 ; pos = (pos + 8) & ~07)
+			putc('\t', hfile);
+		fprintf(hfile, "/* %s */\n", synclass[i].comment);
+	}
+	putc('\n', hfile);
+	fputs("/* Syntax classes for is_ functions */\n", hfile);
+	for (i = 0 ; is_entry[i].name ; i++) {
+		sprintf(buf, "#define %s %#o", is_entry[i].name, 1 << i);
+		fputs(buf, hfile);
+		for (pos = strlen(buf) ; pos < 32 ; pos = (pos + 8) & ~07)
+			putc('\t', hfile);
+		fprintf(hfile, "/* %s */\n", is_entry[i].comment);
+	}
+	putc('\n', hfile);
+	fprintf(hfile, "#define SYNBASE %d\n", 130);
+	fprintf(hfile, "#define PEOF %d\n\n", -130);
+	fprintf(hfile, "#define PEOA %d\n\n", -129);
+	putc('\n', hfile);
+	fputs("#define BASESYNTAX (basesyntax + SYNBASE)\n", hfile);
+	fputs("#define DQSYNTAX (dqsyntax + SYNBASE)\n", hfile);
+	fputs("#define SQSYNTAX (sqsyntax + SYNBASE)\n", hfile);
+	fputs("#define ARISYNTAX (arisyntax + SYNBASE)\n", hfile);
+	putc('\n', hfile);
+	output_type_macros();		/* is_digit, etc. */
+	putc('\n', hfile);
+
+	/* Generate the syntax tables. */
+	fputs("#include \"shell.h\"\n", cfile);
+	fputs("#include \"syntax.h\"\n\n", cfile);
+	init();
+	fputs("/* syntax table used when not in quotes */\n", cfile);
+	add("\n", "CNL");
+	add("\\", "CBACK");
+	add("'", "CSQUOTE");
+	add("\"", "CDQUOTE");
+	add("`", "CBQUOTE");
+	add("$", "CVAR");
+	add("}", "CENDVAR");
+	add("<>();&| \t", "CSPCL");
+	syntax[1] = "CSPCL";
+	print("basesyntax");
+	init();
+	fputs("\n/* syntax table used when in double quotes */\n", cfile);
+	add("\n", "CNL");
+	add("\\", "CBACK");
+	add("\"", "CENDQUOTE");
+	add("`", "CBQUOTE");
+	add("$", "CVAR");
+	add("}", "CENDVAR");
+	/* ':/' for tilde expansion, '-' for [a\-x] pattern ranges */
+	add("!*?[=~:/-]", "CCTL");
+	print("dqsyntax");
+	init();
+	fputs("\n/* syntax table used when in single quotes */\n", cfile);
+	add("\n", "CNL");
+	add("'", "CENDQUOTE");
+	/* ':/' for tilde expansion, '-' for [a\-x] pattern ranges */
+	add("!*?[=~:/-]\\", "CCTL");
+	print("sqsyntax");
+	init();
+	fputs("\n/* syntax table used when in arithmetic */\n", cfile);
+	add("\n", "CNL");
+	add("\\", "CBACK");
+	add("`", "CBQUOTE");
+	add("$", "CVAR");
+	add("}", "CENDVAR");
+	add("(", "CLP");
+	add(")", "CRP");
+	print("arisyntax");
+	filltable("0");
+	fputs("\n/* character classification table */\n", cfile);
+	add("0123456789", "ISDIGIT");
+	add("abcdefghijklmnopqrstucvwxyz", "ISLOWER");
+	add("ABCDEFGHIJKLMNOPQRSTUCVWXYZ", "ISUPPER");
+	add("_", "ISUNDER");
+	add("#?$!-*@", "ISSPECL");
+	print("is_type");
+	exit(0);
+	/* NOTREACHED */
+}
+
+
+
+/*
+ * Clear the syntax table.
+ */
+
+static void
+filltable(char *dftval)
+{
+	int i;
+
+	for (i = 0 ; i < 257; i++)
+		syntax[i] = dftval;
+}
+
+
+/*
+ * Initialize the syntax table with default values.
+ */
+
+static void
+init(void)
+{
+	int ctl;
+
+	filltable("CWORD");
+	syntax[0] = "CEOF";
+	syntax[1] = "CIGN";
+	for (ctl = CTL_FIRST; ctl <= CTL_LAST; ctl++ )
+		syntax[130 + ctl] = "CCTL";
+}
+
+
+/*
+ * Add entries to the syntax table.
+ */
+
+static void
+add(char *p, char *type)
+{
+	while (*p)
+		syntax[(signed char)*p++ + 130] = type;
+}
+
+
+
+/*
+ * Output the syntax table.
+ */
+
+static void
+print(char *name)
+{
+	int i;
+	int col;
+
+	fprintf(hfile, "extern const char %s[];\n", name);
+	fprintf(cfile, "const char %s[%d] = {\n", name, 257);
+	col = 0;
+	for (i = 0 ; i < 257; i++) {
+		if (i == 0) {
+			fputs("      ", cfile);
+		} else if ((i & 03) == 0) {
+			fputs(",\n      ", cfile);
+			col = 0;
+		} else {
+			putc(',', cfile);
+			while (++col < 9 * (i & 03))
+				putc(' ', cfile);
+		}
+		fputs(syntax[i], cfile);
+		col += strlen(syntax[i]);
+	}
+	fputs("\n};\n", cfile);
+}
+
+
+
+/*
+ * Output character classification macros (e.g. is_digit).  If digits are
+ * contiguous, we can test for them quickly.
+ */
+
+static char *macro[] = {
+	"#define is_digit(c)\t((unsigned)((c) - '0') <= 9)\n",
+	"#define is_alpha(c)\tisalpha((unsigned char)(c))\n",
+	"#define is_name(c)\t((c) == '_' || isalpha((unsigned char)(c)))\n",
+	"#define is_in_name(c)\t((c) == '_' || isalnum((unsigned char)(c)))\n",
+	"#define is_special(c)\t((is_type+SYNBASE)[(signed char)(c)] & (ISSPECL|ISDIGIT))\n",
+	NULL
+};
+
+static void
+output_type_macros(void)
+{
+	char **pp;
+
+	for (pp = macro ; *pp ; pp++)
+		fputs(*pp, hfile);
+	fputs("#define digit_val(c)\t((c) - '0')\n", hfile);
+}
diff --git a/usr/dash/mktokens b/usr/dash/mktokens
new file mode 100644
index 0000000..8fbcef1
--- /dev/null
+++ b/usr/dash/mktokens
@@ -0,0 +1,92 @@
+#!/bin/sh -
+# Copyright (c) 1991, 1993
+#	The Regents of the University of California.  All rights reserved.
+# Copyright (c) 1997-2005
+#	Herbert Xu <herbert@gondor.apana.org.au>.  All rights reserved.
+#
+# This code is derived from software contributed to Berkeley by
+# Kenneth Almquist.
+#
+# 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. 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.
+#
+#	@(#)mktokens	8.1 (Berkeley) 5/31/93
+
+# The following is a list of tokens.  The second column is nonzero if the
+# token marks the end of a list.  The third column is the name to print in
+# error messages.
+
+cat > /tmp/ka$$ <<\!
+TEOF	1	end of file
+TNL	0	newline
+TSEMI	0	";"
+TBACKGND 0	"&"
+TAND	0	"&&"
+TOR	0	"||"
+TPIPE	0	"|"
+TLP	0	"("
+TRP	1	")"
+TENDCASE 1	";;"
+TENDBQUOTE 1	"`"
+TREDIR	0	redirection
+TWORD	0	word
+TNOT	0	"!"
+TCASE	0	"case"
+TDO	1	"do"
+TDONE	1	"done"
+TELIF	1	"elif"
+TELSE	1	"else"
+TESAC	1	"esac"
+TFI	1	"fi"
+TFOR	0	"for"
+TIF	0	"if"
+TIN	0	"in"
+TTHEN	1	"then"
+TUNTIL	0	"until"
+TWHILE	0	"while"
+TBEGIN	0	"{"
+TEND	1	"}"
+!
+nl=`wc -l /tmp/ka$$`
+
+awk '{print "#define " $1 " " NR-1}' /tmp/ka$$
+echo '
+/* Array indicating which tokens mark the end of a list */
+const char tokendlist[] = {'
+awk '{print "\t" $2 ","}' /tmp/ka$$
+echo '};
+
+const char *const tokname[] = {'
+sed -e 's/"/\\"/g' \
+    -e 's/[^	 ]*[	 ][	 ]*[^	 ]*[	 ][	 ]*\(.*\)/	"\1",/' \
+    /tmp/ka$$
+echo '};
+'
+sed 's/"//g' /tmp/ka$$ | awk '
+/TNOT/{print "#define KWDOFFSET " NR-1; print "";
+      print "STATIC const char *const parsekwd[] = {"}
+/TNOT/,/neverfound/{if (last) print "	\"" last "\","; last = $3}
+END{print "	\"" last "\"\n};"}'
+
+rm /tmp/ka$$
diff --git a/usr/dash/myhistedit.h b/usr/dash/myhistedit.h
new file mode 100644
index 0000000..5888088
--- /dev/null
+++ b/usr/dash/myhistedit.h
@@ -0,0 +1,45 @@
+/*-
+ * Copyright (c) 1993
+ *	The Regents of the University of California.  All rights reserved.
+ * Copyright (c) 1997-2005
+ *	Herbert Xu <herbert@gondor.apana.org.au>.  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.
+ * 3. 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.
+ *
+ *	@(#)myhistedit.h	8.2 (Berkeley) 5/4/95
+ */
+
+#include <histedit.h>
+
+extern History *hist;
+extern EditLine *el;
+extern int displayhist;
+
+void histedit(void);
+void sethistsize(const char *);
+void setterm(const char *);
+int histcmd(int, char **);
+int not_fcnumber(char *);
+int str_to_event(const char *, int);
diff --git a/usr/dash/mystring.c b/usr/dash/mystring.c
new file mode 100644
index 0000000..49201a9
--- /dev/null
+++ b/usr/dash/mystring.c
@@ -0,0 +1,209 @@
+/*-
+ * Copyright (c) 1991, 1993
+ *	The Regents of the University of California.  All rights reserved.
+ * Copyright (c) 1997-2005
+ *	Herbert Xu <herbert@gondor.apana.org.au>.  All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Kenneth Almquist.
+ *
+ * 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. 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.
+ */
+
+/*
+ * String functions.
+ *
+ *	equal(s1, s2)		Return true if strings are equal.
+ *	scopy(from, to)		Copy a string.
+ *	scopyn(from, to, n)	Like scopy, but checks for overflow.
+ *	number(s)		Convert a string of digits to an integer.
+ *	is_number(s)		Return true if s is a string of digits.
+ */
+
+#include <stdlib.h>
+#include "shell.h"
+#include "syntax.h"
+#include "error.h"
+#include "mystring.h"
+#include "memalloc.h"
+#include "parser.h"
+#include "system.h"
+
+
+char nullstr[1];		/* zero length string */
+const char spcstr[] = " ";
+const char snlfmt[] = "%s\n";
+const char dolatstr[] = { CTLVAR, VSNORMAL|VSQUOTE, '@', '=', '\0' };
+const char illnum[] = "Illegal number: %s";
+const char homestr[] = "HOME";
+
+/*
+ * equal - #defined in mystring.h
+ */
+
+/*
+ * scopy - #defined in mystring.h
+ */
+
+
+#if 0
+/*
+ * scopyn - copy a string from "from" to "to", truncating the string
+ *		if necessary.  "To" is always nul terminated, even if
+ *		truncation is performed.  "Size" is the size of "to".
+ */
+
+void
+scopyn(const char *from, char *to, int size)
+{
+
+	while (--size > 0) {
+		if ((*to++ = *from++) == '\0')
+			return;
+	}
+	*to = '\0';
+}
+#endif
+
+
+/*
+ * prefix -- see if pfx is a prefix of string.
+ */
+
+char *
+prefix(const char *string, const char *pfx)
+{
+	while (*pfx) {
+		if (*pfx++ != *string++)
+			return 0;
+	}
+	return (char *) string;
+}
+
+
+/*
+ * Convert a string of digits to an integer, printing an error message on
+ * failure.
+ */
+
+int
+number(const char *s)
+{
+
+	if (! is_number(s))
+		sh_error(illnum, s);
+	return atoi(s);
+}
+
+
+
+/*
+ * Check for a valid number.  This should be elsewhere.
+ */
+
+int
+is_number(const char *p)
+{
+	do {
+		if (! is_digit(*p))
+			return 0;
+	} while (*++p != '\0');
+	return 1;
+}
+
+
+/*
+ * Produce a possibly single quoted string suitable as input to the shell.
+ * The return string is allocated on the stack.
+ */
+
+char *
+single_quote(const char *s) {
+	char *p;
+
+	STARTSTACKSTR(p);
+
+	do {
+		char *q;
+		size_t len;
+
+		len = strchrnul(s, '\'') - s;
+
+		q = p = makestrspace(len + 3, p);
+
+		*q++ = '\'';
+		q = mempcpy(q, s, len);
+		*q++ = '\'';
+		s += len;
+
+		STADJUST(q - p, p);
+
+		len = strspn(s, "'");
+		if (!len)
+			break;
+
+		q = p = makestrspace(len + 3, p);
+
+		*q++ = '"';
+		q = mempcpy(q, s, len);
+		*q++ = '"';
+		s += len;
+
+		STADJUST(q - p, p);
+	} while (*s);
+
+	USTPUTC(0, p);
+
+	return stackblock();
+}
+
+/*
+ * Like strdup but works with the ash stack.
+ */
+
+char *
+sstrdup(const char *p)
+{
+	size_t len = strlen(p) + 1;
+	return memcpy(stalloc(len), p, len);
+}
+
+/*
+ * Wrapper around strcmp for qsort/bsearch/...
+ */
+int
+pstrcmp(const void *a, const void *b)
+{
+	return strcmp(*(const char *const *) a, *(const char *const *) b);
+}
+
+/*
+ * Find a string is in a sorted array.
+ */
+const char *const *
+findstring(const char *s, const char *const *array, size_t nmemb)
+{
+	return bsearch(&s, array, nmemb, sizeof(const char *), pstrcmp);
+}
diff --git a/usr/dash/mystring.h b/usr/dash/mystring.h
new file mode 100644
index 0000000..44fd7e4
--- /dev/null
+++ b/usr/dash/mystring.h
@@ -0,0 +1,58 @@
+/*-
+ * Copyright (c) 1991, 1993
+ *	The Regents of the University of California.  All rights reserved.
+ * Copyright (c) 1997-2005
+ *	Herbert Xu <herbert@gondor.apana.org.au>.  All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Kenneth Almquist.
+ *
+ * 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. 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.
+ *
+ *	@(#)mystring.h	8.2 (Berkeley) 5/4/95
+ */
+
+#include <string.h>
+
+extern const char snlfmt[];
+extern const char spcstr[];
+extern const char dolatstr[];
+#define DOLATSTRLEN 4
+extern const char illnum[];
+extern const char homestr[];
+
+#if 0
+void scopyn(const char *, char *, int);
+#endif
+char *prefix(const char *, const char *);
+int number(const char *);
+int is_number(const char *);
+char *single_quote(const char *);
+char *sstrdup(const char *);
+int pstrcmp(const void *, const void *);
+const char *const *findstring(const char *, const char *const *, size_t);
+
+#define equal(s1, s2)	(strcmp(s1, s2) == 0)
+#define scopy(s1, s2)	((void)strcpy(s2, s1))
diff --git a/usr/dash/nodes.c.pat b/usr/dash/nodes.c.pat
new file mode 100644
index 0000000..9125bc7
--- /dev/null
+++ b/usr/dash/nodes.c.pat
@@ -0,0 +1,166 @@
+/*-
+ * Copyright (c) 1991, 1993
+ *	The Regents of the University of California.  All rights reserved.
+ * Copyright (c) 1997-2005
+ *	Herbert Xu <herbert@gondor.apana.org.au>.  All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Kenneth Almquist.
+ *
+ * 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. 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.
+ *
+ *	@(#)nodes.c.pat	8.2 (Berkeley) 5/4/95
+ */
+
+#include <stdlib.h>
+/*
+ * Routine for dealing with parsed shell commands.
+ */
+
+#include "shell.h"
+#include "nodes.h"
+#include "memalloc.h"
+#include "machdep.h"
+#include "mystring.h"
+#include "system.h"
+
+
+int     funcblocksize;		/* size of structures in function */
+int     funcstringsize;		/* size of strings in node */
+pointer funcblock;		/* block to allocate function from */
+char   *funcstring;		/* block to allocate strings from */
+
+%SIZES
+
+
+STATIC void calcsize(union node *);
+STATIC void sizenodelist(struct nodelist *);
+STATIC union node *copynode(union node *);
+STATIC struct nodelist *copynodelist(struct nodelist *);
+STATIC char *nodesavestr(char *);
+
+
+
+/*
+ * Make a copy of a parse tree.
+ */
+
+struct funcnode *
+copyfunc(union node *n)
+{
+	struct funcnode *f;
+	size_t blocksize;
+
+	funcblocksize = offsetof(struct funcnode, n);
+	funcstringsize = 0;
+	calcsize(n);
+	blocksize = funcblocksize;
+	f = ckmalloc(blocksize + funcstringsize);
+	funcblock = (char *) f + offsetof(struct funcnode, n);
+	funcstring = (char *) f + blocksize;
+	copynode(n);
+	f->count = 0;
+	return f;
+}
+
+
+
+STATIC void
+calcsize(n)
+	union node *n;
+{
+	%CALCSIZE
+}
+
+
+
+STATIC void
+sizenodelist(lp)
+	struct nodelist *lp;
+{
+	while (lp) {
+		funcblocksize += SHELL_ALIGN(sizeof(struct nodelist));
+		calcsize(lp->n);
+		lp = lp->next;
+	}
+}
+
+
+
+STATIC union node *
+copynode(n)
+	union node *n;
+{
+	union node *new;
+
+	%COPY
+	return new;
+}
+
+
+STATIC struct nodelist *
+copynodelist(lp)
+	struct nodelist *lp;
+{
+	struct nodelist *start;
+	struct nodelist **lpp;
+
+	lpp = &start;
+	while (lp) {
+		*lpp = funcblock;
+		funcblock = (char *) funcblock +
+		    SHELL_ALIGN(sizeof(struct nodelist));
+		(*lpp)->n = copynode(lp->n);
+		lp = lp->next;
+		lpp = &(*lpp)->next;
+	}
+	*lpp = NULL;
+	return start;
+}
+
+
+
+STATIC char *
+nodesavestr(s)
+	char   *s;
+{
+	char   *rtn = funcstring;
+
+	funcstring = stpcpy(funcstring, s) + 1;
+	return rtn;
+}
+
+
+
+/*
+ * Free a parse tree.
+ */
+
+void
+freefunc(struct funcnode *f)
+{
+	if (f && --f->count < 0)
+		ckfree(f);
+}
diff --git a/usr/dash/nodetypes b/usr/dash/nodetypes
new file mode 100644
index 0000000..17a7b3c
--- /dev/null
+++ b/usr/dash/nodetypes
@@ -0,0 +1,144 @@
+# Copyright (c) 1991, 1993
+#	The Regents of the University of California.  All rights reserved.
+# Copyright (c) 1997-2005
+#	Herbert Xu <herbert@gondor.apana.org.au>.  All rights reserved.
+#
+# This code is derived from software contributed to Berkeley by
+# Kenneth Almquist.
+#
+# 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. 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.
+#
+#	@(#)nodetypes	8.2 (Berkeley) 5/4/95
+
+# This file describes the nodes used in parse trees.  Unindented lines
+# contain a node type followed by a structure tag.  Subsequent indented
+# lines specify the fields of the structure.  Several node types can share
+# the same structure, in which case the fields of the structure should be
+# specified only once.
+#
+# A field of a structure is described by the name of the field followed
+# by a type.  The currently implemented types are:
+#	nodeptr - a pointer to a node
+#	nodelist - a pointer to a list of nodes
+#	string - a pointer to a nul terminated string
+#	int - an integer
+#	other - any type that can be copied by assignment
+#	temp - a field that doesn't have to be copied when the node is copied
+# The last two types should be followed by the text of a C declaration for
+# the field.
+
+NCMD ncmd			# a simple command
+	type	  int
+	assign    nodeptr		# variable assignments
+	args	  nodeptr		# the arguments
+	redirect  nodeptr		# list of file redirections
+
+NPIPE npipe			# a pipeline
+	type	  int
+	backgnd	  int			# set to run pipeline in background
+	cmdlist	  nodelist		# the commands in the pipeline
+
+NREDIR nredir			# redirection (of a complex command)
+	type	  int
+	n	  nodeptr		# the command
+	redirect  nodeptr		# list of file redirections
+
+NBACKGND nredir			# run command in background
+NSUBSHELL nredir		# run command in a subshell
+
+NAND nbinary			# the && operator
+NOR nbinary			# the || operator
+
+NSEMI nbinary			# two commands separated by a semicolon
+	type	  int
+	ch1	  nodeptr		# the first child
+	ch2	  nodeptr		# the second child
+
+NIF nif				# the if statement.  Elif clauses are handled
+	type	  int		    # using multiple if nodes.
+	test	  nodeptr		# if test
+	ifpart	  nodeptr		# then ifpart
+	elsepart  nodeptr		# else elsepart
+
+NWHILE nbinary			# the while statement.  First child is the test
+NUNTIL nbinary			# the until statement
+
+NFOR nfor			# the for statement
+	type	  int
+	args	  nodeptr		# for var in args
+	body	  nodeptr		# do body; done
+	var	  string		# the for variable
+
+NCASE ncase			# a case statement
+	type	  int
+	expr	  nodeptr		# the word to switch on
+	cases	  nodeptr		# the list of cases (NCLIST nodes)
+
+NCLIST nclist			# a case
+	type	  int
+	next	  nodeptr		# the next case in list
+	pattern	  nodeptr		# list of patterns for this case
+	body	  nodeptr		# code to execute for this case
+
+
+NDEFUN narg			# define a function.  The "next" field contains
+				# the body of the function.
+
+NARG narg			# represents a word
+	type	  int
+	next	  nodeptr		# next word in list
+	text	  string		# the text of the word
+	backquote nodelist		# list of commands in back quotes
+
+NTO nfile			# fd> fname
+NCLOBBER nfile			# fd>| fname
+NFROM nfile			# fd< fname
+NFROMTO nfile			# fd<> fname
+NAPPEND nfile			# fd>> fname
+	type	  int
+	next	  nodeptr		# next redirection in list
+	fd	  int			# file descriptor being redirected
+	fname	  nodeptr		# file name, in a NARG node
+	expfname  temp	char *expfname	# actual file name
+
+NTOFD ndup			# fd<&dupfd
+NFROMFD ndup			# fd>&dupfd
+	type	  int
+	next	  nodeptr		# next redirection in list
+	fd	  int			# file descriptor being redirected
+	dupfd	  int			# file descriptor to duplicate
+	vname	  nodeptr		# file name if fd>&$var
+
+
+NHERE nhere			# fd<<\!
+NXHERE nhere			# fd<<!
+	type	  int
+	next	  nodeptr		# next redirection in list
+	fd	  int			# file descriptor being redirected
+	doc	  nodeptr		# input to command (NARG node)
+
+NNOT nnot			# ! command  (actually pipeline)
+	type	int
+	com	nodeptr
diff --git a/usr/dash/options.c b/usr/dash/options.c
new file mode 100644
index 0000000..23aa609
--- /dev/null
+++ b/usr/dash/options.c
@@ -0,0 +1,547 @@
+/*-
+ * Copyright (c) 1991, 1993
+ *	The Regents of the University of California.  All rights reserved.
+ * Copyright (c) 1997-2005
+ *	Herbert Xu <herbert@gondor.apana.org.au>.  All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Kenneth Almquist.
+ *
+ * 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. 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 <signal.h>
+#include <unistd.h>
+#include <stdlib.h>
+
+#include "shell.h"
+#define DEFINE_OPTIONS
+#include "options.h"
+#undef DEFINE_OPTIONS
+#include "nodes.h"	/* for other header files */
+#include "eval.h"
+#include "jobs.h"
+#include "input.h"
+#include "output.h"
+#include "trap.h"
+#include "var.h"
+#include "memalloc.h"
+#include "error.h"
+#include "mystring.h"
+#ifndef SMALL
+#include "myhistedit.h"
+#endif
+#include "show.h"
+
+char *arg0;			/* value of $0 */
+struct shparam shellparam;	/* current positional parameters */
+char **argptr;			/* argument list for builtin commands */
+char *optionarg;		/* set by nextopt (like getopt) */
+char *optptr;			/* used by nextopt */
+
+char *minusc;			/* argument to -c option */
+
+static const char *const optnames[NOPTS] = {
+	"errexit",
+	"noglob",
+	"ignoreeof",
+	"interactive",
+	"monitor",
+	"noexec",
+	"stdin",
+	"xtrace",
+	"verbose",
+	"vi",
+	"emacs",
+	"noclobber",
+	"allexport",
+	"notify",
+	"nounset",
+	"nolog",
+	"debug",
+};
+
+const char optletters[NOPTS] = {
+	'e',
+	'f',
+	'I',
+	'i',
+	'm',
+	'n',
+	's',
+	'x',
+	'v',
+	'V',
+	'E',
+	'C',
+	'a',
+	'b',
+	'u',
+	0,
+	0,
+};
+
+char optlist[NOPTS];
+
+
+STATIC void options(int);
+STATIC void minus_o(char *, int);
+STATIC void setoption(int, int);
+STATIC int getopts(char *, char *, char **, int *, int *);
+
+
+/*
+ * Process the shell command line arguments.
+ */
+
+void
+procargs(int argc, char **argv)
+{
+	int i;
+	const char *xminusc;
+	char **xargv;
+
+	xargv = argv;
+	arg0 = xargv[0];
+	if (argc > 0)
+		xargv++;
+	for (i = 0; i < NOPTS; i++)
+		optlist[i] = 2;
+	argptr = xargv;
+	options(1);
+	xargv = argptr;
+	xminusc = minusc;
+	if (*xargv == NULL) {
+		if (xminusc)
+			sh_error("-c requires an argument");
+		sflag = 1;
+	}
+	if (iflag == 2 && sflag == 1 && isatty(0) && isatty(1))
+		iflag = 1;
+	if (mflag == 2)
+		mflag = iflag;
+	for (i = 0; i < NOPTS; i++)
+		if (optlist[i] == 2)
+			optlist[i] = 0;
+#if DEBUG == 2
+	debug = 1;
+#endif
+	/* POSIX 1003.2: first arg after -c cmd is $0, remainder $1... */
+	if (xminusc) {
+		minusc = *xargv++;
+		if (*xargv)
+			goto setarg0;
+	} else if (!sflag) {
+		setinputfile(*xargv, 0);
+setarg0:
+		arg0 = *xargv++;
+		commandname = arg0;
+	}
+
+	shellparam.p = xargv;
+	shellparam.optind = 1;
+	shellparam.optoff = -1;
+	/* assert(shellparam.malloc == 0 && shellparam.nparam == 0); */
+	while (*xargv) {
+		shellparam.nparam++;
+		xargv++;
+	}
+	optschanged();
+}
+
+
+void
+optschanged(void)
+{
+#ifdef DEBUG
+	opentrace();
+#endif
+	setinteractive(iflag);
+#ifndef SMALL
+	histedit();
+#endif
+	setjobctl(mflag);
+}
+
+/*
+ * Process shell options.  The global variable argptr contains a pointer
+ * to the argument list; we advance it past the options.
+ */
+
+STATIC void
+options(int cmdline)
+{
+	char *p;
+	int val;
+	int c;
+
+	if (cmdline)
+		minusc = NULL;
+	while ((p = *argptr) != NULL) {
+		argptr++;
+		if ((c = *p++) == '-') {
+			val = 1;
+                        if (p[0] == '\0' || (p[0] == '-' && p[1] == '\0')) {
+                                if (!cmdline) {
+                                        /* "-" means turn off -x and -v */
+                                        if (p[0] == '\0')
+                                                xflag = vflag = 0;
+                                        /* "--" means reset params */
+                                        else if (*argptr == NULL)
+						setparam(argptr);
+                                }
+				break;	  /* "-" or  "--" terminates options */
+			}
+		} else if (c == '+') {
+			val = 0;
+		} else {
+			argptr--;
+			break;
+		}
+		while ((c = *p++) != '\0') {
+			if (c == 'c' && cmdline) {
+				minusc = p;	/* command is after shell args*/
+			} else if (c == 'o') {
+				minus_o(*argptr, val);
+				if (*argptr)
+					argptr++;
+			} else {
+				setoption(c, val);
+			}
+		}
+	}
+}
+
+STATIC void
+minus_o(char *name, int val)
+{
+	int i;
+
+	if (name == NULL) {
+		out1str("Current option settings\n");
+		for (i = 0; i < NOPTS; i++)
+			out1fmt("%-16s%s\n", optnames[i],
+				optlist[i] ? "on" : "off");
+	} else {
+		for (i = 0; i < NOPTS; i++)
+			if (equal(name, optnames[i])) {
+				optlist[i] = val;
+				return;
+			}
+		sh_error("Illegal option -o %s", name);
+	}
+}
+
+
+STATIC void
+setoption(int flag, int val)
+{
+	int i;
+
+	for (i = 0; i < NOPTS; i++)
+		if (optletters[i] == flag) {
+			optlist[i] = val;
+			if (val) {
+				/* #%$ hack for ksh semantics */
+				if (flag == 'V')
+					Eflag = 0;
+				else if (flag == 'E')
+					Vflag = 0;
+			}
+			return;
+		}
+	sh_error("Illegal option -%c", flag);
+	/* NOTREACHED */
+}
+
+
+
+/*
+ * Set the shell parameters.
+ */
+
+void
+setparam(char **argv)
+{
+	char **newparam;
+	char **ap;
+	int nparam;
+
+	for (nparam = 0 ; argv[nparam] ; nparam++);
+	ap = newparam = ckmalloc((nparam + 1) * sizeof *ap);
+	while (*argv) {
+		*ap++ = savestr(*argv++);
+	}
+	*ap = NULL;
+	freeparam(&shellparam);
+	shellparam.malloc = 1;
+	shellparam.nparam = nparam;
+	shellparam.p = newparam;
+	shellparam.optind = 1;
+	shellparam.optoff = -1;
+}
+
+
+/*
+ * Free the list of positional parameters.
+ */
+
+void
+freeparam(volatile struct shparam *param)
+{
+	char **ap;
+
+	if (param->malloc) {
+		for (ap = param->p ; *ap ; ap++)
+			ckfree(*ap);
+		ckfree(param->p);
+	}
+}
+
+
+
+/*
+ * The shift builtin command.
+ */
+
+int
+shiftcmd(int argc, char **argv)
+{
+	int n;
+	char **ap1, **ap2;
+
+	n = 1;
+	if (argc > 1)
+		n = number(argv[1]);
+	if (n > shellparam.nparam)
+		sh_error("can't shift that many");
+	INTOFF;
+	shellparam.nparam -= n;
+	for (ap1 = shellparam.p ; --n >= 0 ; ap1++) {
+		if (shellparam.malloc)
+			ckfree(*ap1);
+	}
+	ap2 = shellparam.p;
+	while ((*ap2++ = *ap1++) != NULL);
+	shellparam.optind = 1;
+	shellparam.optoff = -1;
+	INTON;
+	return 0;
+}
+
+
+
+/*
+ * The set command builtin.
+ */
+
+int
+setcmd(int argc, char **argv)
+{
+	if (argc == 1)
+		return showvars(nullstr, 0, VUNSET);
+	INTOFF;
+	options(0);
+	optschanged();
+	if (*argptr != NULL) {
+		setparam(argptr);
+	}
+	INTON;
+	return 0;
+}
+
+
+void
+getoptsreset(value)
+	const char *value;
+{
+	shellparam.optind = number(value);
+	shellparam.optoff = -1;
+}
+
+/*
+ * The getopts builtin.  Shellparam.optnext points to the next argument
+ * to be processed.  Shellparam.optptr points to the next character to
+ * be processed in the current argument.  If shellparam.optnext is NULL,
+ * then it's the first time getopts has been called.
+ */
+
+int
+getoptscmd(int argc, char **argv)
+{
+	char **optbase;
+
+	if (argc < 3)
+		sh_error("Usage: getopts optstring var [arg]");
+	else if (argc == 3) {
+		optbase = shellparam.p;
+		if (shellparam.optind > shellparam.nparam + 1) {
+			shellparam.optind = 1;
+			shellparam.optoff = -1;
+		}
+	}
+	else {
+		optbase = &argv[3];
+		if (shellparam.optind > argc - 2) {
+			shellparam.optind = 1;
+			shellparam.optoff = -1;
+		}
+	}
+
+	return getopts(argv[1], argv[2], optbase, &shellparam.optind,
+		       &shellparam.optoff);
+}
+
+STATIC int
+getopts(char *optstr, char *optvar, char **optfirst, int *optind, int *optoff)
+{
+	char *p, *q;
+	char c = '?';
+	int done = 0;
+	int err = 0;
+	char s[12];
+	char **optnext;
+
+	if (*optind < 1)
+		return 1;
+	optnext = optfirst + *optind - 1;
+
+	if (*optind <= 1 || *optoff < 0 || strlen(optnext[-1]) < *optoff)
+		p = NULL;
+	else
+		p = optnext[-1] + *optoff;
+	if (p == NULL || *p == '\0') {
+		/* Current word is done, advance */
+		p = *optnext;
+		if (p == NULL || *p != '-' || *++p == '\0') {
+atend:
+			p = NULL;
+			done = 1;
+			goto out;
+		}
+		optnext++;
+		if (p[0] == '-' && p[1] == '\0')	/* check for "--" */
+			goto atend;
+	}
+
+	c = *p++;
+	for (q = optstr; *q != c; ) {
+		if (*q == '\0') {
+			if (optstr[0] == ':') {
+				s[0] = c;
+				s[1] = '\0';
+				err |= setvarsafe("OPTARG", s, 0);
+			} else {
+				outfmt(&errout, "Illegal option -%c\n", c);
+				(void) unsetvar("OPTARG");
+			}
+			c = '?';
+			goto out;
+		}
+		if (*++q == ':')
+			q++;
+	}
+
+	if (*++q == ':') {
+		if (*p == '\0' && (p = *optnext) == NULL) {
+			if (optstr[0] == ':') {
+				s[0] = c;
+				s[1] = '\0';
+				err |= setvarsafe("OPTARG", s, 0);
+				c = ':';
+			} else {
+				outfmt(&errout, "No arg for -%c option\n", c);
+				(void) unsetvar("OPTARG");
+				c = '?';
+			}
+			goto out;
+		}
+
+		if (p == *optnext)
+			optnext++;
+		err |= setvarsafe("OPTARG", p, 0);
+		p = NULL;
+	} else
+		err |= setvarsafe("OPTARG", nullstr, 0);
+
+out:
+	*optoff = p ? p - *(optnext - 1) : -1;
+	*optind = optnext - optfirst + 1;
+	fmtstr(s, sizeof(s), "%d", *optind);
+	err |= setvarsafe("OPTIND", s, VNOFUNC);
+	s[0] = c;
+	s[1] = '\0';
+	err |= setvarsafe(optvar, s, 0);
+	if (err) {
+		*optind = 1;
+		*optoff = -1;
+		flushall();
+		exraise(EXERROR);
+	}
+	return done;
+}
+
+/*
+ * XXX - should get rid of.  have all builtins use getopt(3).  the
+ * library getopt must have the BSD extension static variable "optreset"
+ * otherwise it can't be used within the shell safely.
+ *
+ * Standard option processing (a la getopt) for builtin routines.  The
+ * only argument that is passed to nextopt is the option string; the
+ * other arguments are unnecessary.  It return the character, or '\0' on
+ * end of input.
+ */
+
+int
+nextopt(const char *optstring)
+{
+	char *p;
+	const char *q;
+	char c;
+
+	if ((p = optptr) == NULL || *p == '\0') {
+		p = *argptr;
+		if (p == NULL || *p != '-' || *++p == '\0')
+			return '\0';
+		argptr++;
+		if (p[0] == '-' && p[1] == '\0')	/* check for "--" */
+			return '\0';
+	}
+	c = *p++;
+	for (q = optstring ; *q != c ; ) {
+		if (*q == '\0')
+			sh_error("Illegal option -%c", c);
+		if (*++q == ':')
+			q++;
+	}
+	if (*++q == ':') {
+		if (*p == '\0' && (p = *argptr++) == NULL)
+			sh_error("No arg for -%c option", c);
+		optionarg = p;
+		p = NULL;
+	}
+	optptr = p;
+	return c;
+}
diff --git a/usr/dash/options.h b/usr/dash/options.h
new file mode 100644
index 0000000..45bbe5a
--- /dev/null
+++ b/usr/dash/options.h
@@ -0,0 +1,86 @@
+/*-
+ * Copyright (c) 1991, 1993
+ *	The Regents of the University of California.  All rights reserved.
+ * Copyright (c) 1997-2005
+ *	Herbert Xu <herbert@gondor.apana.org.au>.  All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Kenneth Almquist.
+ *
+ * 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. 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.
+ *
+ *	@(#)options.h	8.2 (Berkeley) 5/4/95
+ */
+
+struct shparam {
+	int nparam;		/* # of positional parameters (without $0) */
+	unsigned char malloc;	/* if parameter list dynamically allocated */
+	char **p;		/* parameter list */
+	int optind;		/* next parameter to be processed by getopts */
+	int optoff;		/* used by getopts */
+};
+
+
+
+#define eflag optlist[0]
+#define fflag optlist[1]
+#define Iflag optlist[2]
+#define iflag optlist[3]
+#define mflag optlist[4]
+#define nflag optlist[5]
+#define sflag optlist[6]
+#define xflag optlist[7]
+#define vflag optlist[8]
+#define Vflag optlist[9]
+#define	Eflag optlist[10]
+#define	Cflag optlist[11]
+#define	aflag optlist[12]
+#define	bflag optlist[13]
+#define	uflag optlist[14]
+#define	nolog optlist[15]
+#define	debug optlist[16]
+
+#define NOPTS	17
+
+extern const char optletters[NOPTS];
+extern char optlist[NOPTS];
+
+
+extern char *minusc;		/* argument to -c option */
+extern char *arg0;		/* $0 */
+extern struct shparam shellparam;  /* $@ */
+extern char **argptr;		/* argument list for builtin commands */
+extern char *optionarg;		/* set by nextopt */
+extern char *optptr;		/* used by nextopt */
+
+void procargs(int, char **);
+void optschanged(void);
+void setparam(char **);
+void freeparam(volatile struct shparam *);
+int shiftcmd(int, char **);
+int setcmd(int, char **);
+int getoptscmd(int, char **);
+int nextopt(const char *);
+void getoptsreset(const char *);
diff --git a/usr/dash/output.c b/usr/dash/output.c
new file mode 100644
index 0000000..2f9b5c4
--- /dev/null
+++ b/usr/dash/output.c
@@ -0,0 +1,385 @@
+/*-
+ * Copyright (c) 1991, 1993
+ *	The Regents of the University of California.  All rights reserved.
+ * Copyright (c) 1997-2005
+ *	Herbert Xu <herbert@gondor.apana.org.au>.  All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Kenneth Almquist.
+ *
+ * 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. 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.
+ */
+
+/*
+ * Shell output routines.  We use our own output routines because:
+ *	When a builtin command is interrupted we have to discard
+ *		any pending output.
+ *	When a builtin command appears in back quotes, we want to
+ *		save the output of the command in a region obtained
+ *		via malloc, rather than doing a fork and reading the
+ *		output of the command via a pipe.
+ *	Our output routines may be smaller than the stdio routines.
+ */
+
+#include <sys/types.h>		/* quad_t */
+#include <sys/param.h>		/* BSD4_4 */
+#include <sys/ioctl.h>
+
+#include <stdio.h>	/* defines BUFSIZ */
+#include <string.h>
+#include <unistd.h>
+#include <stdlib.h>
+#ifdef USE_GLIBC_STDIO
+#include <fcntl.h>
+#endif
+#include <limits.h>
+
+#include "shell.h"
+#include "syntax.h"
+#include "output.h"
+#include "memalloc.h"
+#include "error.h"
+#include "main.h"
+#include "system.h"
+
+
+#define OUTBUFSIZ BUFSIZ
+#define MEM_OUT -3		/* output to dynamically allocated memory */
+
+
+#ifdef USE_GLIBC_STDIO
+struct output output = {
+	stream: 0, nextc: 0, end: 0, buf: 0, bufsize: 0, fd: 1, flags: 0
+};
+struct output errout = {
+	stream: 0, nextc: 0, end: 0, buf: 0, bufsize: 0, fd: 2, flags: 0
+}
+#ifdef notyet
+struct output memout = {
+	stream: 0, nextc: 0, end: 0, buf: 0, bufsize: 0, fd: MEM_OUT, flags: 0
+};
+#endif
+#else
+struct output output = {
+	nextc: 0, end: 0, buf: 0, bufsize: OUTBUFSIZ, fd: 1, flags: 0
+};
+struct output errout = {
+	nextc: 0, end: 0, buf: 0, bufsize: 0, fd: 2, flags: 0
+};
+struct output preverrout;
+#ifdef notyet
+struct output memout = {
+	nextc: 0, end: 0, buf: 0, bufsize: 0, fd: MEM_OUT, flags: 0
+};
+#endif
+#endif
+struct output *out1 = &output;
+struct output *out2 = &errout;
+
+
+#ifndef USE_GLIBC_STDIO
+static void __outstr(const char *, size_t, struct output *);
+#endif
+static int xvsnprintf(char *, size_t, const char *, va_list);
+
+
+#ifdef mkinit
+
+INCLUDE "output.h"
+INCLUDE "memalloc.h"
+
+INIT {
+#ifdef USE_GLIBC_STDIO
+	initstreams();
+#endif
+}
+
+RESET {
+#ifdef notyet
+	out1 = &output;
+	out2 = &errout;
+#ifdef USE_GLIBC_STDIO
+	if (memout.stream != NULL)
+		__closememout();
+#endif
+	if (memout.buf != NULL) {
+		ckfree(memout.buf);
+		memout.buf = NULL;
+	}
+#endif
+}
+
+#endif
+
+
+#ifndef USE_GLIBC_STDIO
+static void
+__outstr(const char *p, size_t len, struct output *dest)
+{
+	size_t bufsize;
+	size_t offset;
+	size_t nleft;
+
+	nleft = dest->end - dest->nextc;
+	if (nleft >= len) {
+buffered:
+		dest->nextc = mempcpy(dest->nextc, p, len);
+		return;
+	}
+
+	bufsize = dest->bufsize;
+	if (!bufsize) {
+		;
+	} else if (dest->buf == NULL) {
+		if (dest->fd == MEM_OUT && len > bufsize) {
+			bufsize = len;
+		}
+		offset = 0;
+		goto alloc;
+	} else if (dest->fd == MEM_OUT) {
+		offset = bufsize;
+		if (bufsize >= len) {
+			bufsize <<= 1;
+		} else {
+			bufsize += len;
+		}
+		if (bufsize < offset)
+			goto err;
+alloc:
+		INTOFF;
+		dest->buf = ckrealloc(dest->buf, bufsize);
+		dest->bufsize = bufsize;
+		dest->end = dest->buf + bufsize;
+		dest->nextc = dest->buf + offset;
+		INTON;
+	} else {
+		flushout(dest);
+	}
+
+	nleft = dest->end - dest->nextc;
+	if (nleft > len)
+		goto buffered;
+
+	if ((xwrite(dest->fd, p, len))) {
+err:
+		dest->flags |= OUTPUT_ERR;
+	}
+}
+#endif
+
+
+void
+outstr(const char *p, struct output *file)
+{
+#ifdef USE_GLIBC_STDIO
+	INTOFF;
+	fputs(p, file->stream);
+	INTON;
+#else
+	size_t len;
+
+	len = strlen(p);
+	__outstr(p, len, file);
+#endif
+}
+
+
+#ifndef USE_GLIBC_STDIO
+
+
+void
+outcslow(int c, struct output *dest)
+{
+	char buf = c;
+	__outstr(&buf, 1, dest);
+}
+#endif
+
+
+void
+flushall(void)
+{
+	flushout(&output);
+#ifdef FLUSHERR
+	flushout(&errout);
+#endif
+}
+
+
+void
+flushout(struct output *dest)
+{
+#ifdef USE_GLIBC_STDIO
+	INTOFF;
+	fflush(dest->stream);
+	INTON;
+#else
+	size_t len;
+
+	len = dest->nextc - dest->buf;
+	if (!len || dest->fd < 0)
+		return;
+	dest->nextc = dest->buf;
+	if ((xwrite(dest->fd, dest->buf, len)))
+		dest->flags |= OUTPUT_ERR;
+#endif
+}
+
+
+void
+outfmt(struct output *file, const char *fmt, ...)
+{
+	va_list ap;
+
+	va_start(ap, fmt);
+	doformat(file, fmt, ap);
+	va_end(ap);
+}
+
+
+void
+out1fmt(const char *fmt, ...)
+{
+	va_list ap;
+
+	va_start(ap, fmt);
+	doformat(out1, fmt, ap);
+	va_end(ap);
+}
+
+
+int
+fmtstr(char *outbuf, size_t length, const char *fmt, ...)
+{
+	va_list ap;
+	int ret;
+
+	va_start(ap, fmt);
+	ret = xvsnprintf(outbuf, length, fmt, ap);
+	va_end(ap);
+	return ret;
+}
+
+
+#ifndef USE_GLIBC_STDIO
+void
+doformat(struct output *dest, const char *f, va_list ap)
+{
+	struct stackmark smark;
+	char *s;
+	int len, ret;
+	size_t size;
+	va_list ap2;
+
+	va_copy(ap2, ap);
+	size = dest->end - dest->nextc;
+	len = xvsnprintf(dest->nextc, size, f, ap2);
+	va_end(ap2);
+	if (len < 0) {
+		dest->flags |= OUTPUT_ERR;
+		return;
+	}
+	if (len < size) {
+		dest->nextc += len;
+		return;
+	}
+	setstackmark(&smark);
+	s = stalloc((len >= stackblocksize() ? len : stackblocksize()) + 1);
+	ret = xvsnprintf(s, len + 1, f, ap);
+	if (ret == len)
+		__outstr(s, len, dest);
+	else
+		dest->flags |= OUTPUT_ERR;
+	popstackmark(&smark);
+}
+#endif
+
+
+
+/*
+ * Version of write which resumes after a signal is caught.
+ */
+
+int
+xwrite(int fd, const void *p, size_t n)
+{
+	const char *buf = p;
+
+	while (n) {
+		ssize_t i;
+		size_t m;
+
+		m = n;
+		if (m > SSIZE_MAX)
+			m = SSIZE_MAX;
+		do {
+			i = write(fd, buf, m);
+		} while (i < 0 && errno == EINTR);
+		if (i < 0)
+			return -1;
+		buf += i;
+		n -= i;
+	}
+	return 0;
+}
+
+
+#ifdef notyet
+#ifdef USE_GLIBC_STDIO
+void initstreams() {
+	output.stream = stdout;
+	errout.stream = stderr;
+}
+
+
+void
+openmemout(void) {
+	INTOFF;
+	memout.stream = open_memstream(&memout.buf, &memout.bufsize);
+	INTON;
+}
+
+
+int
+__closememout(void) {
+	int error;
+	error = fclose(memout.stream);
+	memout.stream = NULL;
+	return error;
+}
+#endif
+#endif
+
+
+static int
+xvsnprintf(char *outbuf, size_t length, const char *fmt, va_list ap)
+{
+	int ret;
+
+	INTOFF;
+	ret = vsnprintf(outbuf, length, fmt, ap);
+	INTON;
+	return ret;
+}
diff --git a/usr/dash/output.h b/usr/dash/output.h
new file mode 100644
index 0000000..d123301
--- /dev/null
+++ b/usr/dash/output.h
@@ -0,0 +1,112 @@
+/*-
+ * Copyright (c) 1991, 1993
+ *	The Regents of the University of California.  All rights reserved.
+ * Copyright (c) 1997-2005
+ *	Herbert Xu <herbert@gondor.apana.org.au>.  All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Kenneth Almquist.
+ *
+ * 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. 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.
+ *
+ *	@(#)output.h	8.2 (Berkeley) 5/4/95
+ */
+
+#ifndef OUTPUT_INCL
+
+#include <stdarg.h>
+#ifdef USE_GLIBC_STDIO
+#include <stdio.h>
+#endif
+#include <sys/types.h>
+
+struct output {
+#ifdef USE_GLIBC_STDIO
+	FILE *stream;
+#endif
+	char *nextc;
+	char *end;
+	char *buf;
+	size_t bufsize;
+	int fd;
+	int flags;
+};
+
+extern struct output output;
+extern struct output errout;
+extern struct output preverrout;
+#ifdef notyet
+extern struct output memout;
+#endif
+extern struct output *out1;
+extern struct output *out2;
+
+void outstr(const char *, struct output *);
+#ifndef USE_GLIBC_STDIO
+void outcslow(int, struct output *);
+#endif
+void flushall(void);
+void flushout(struct output *);
+void outfmt(struct output *, const char *, ...)
+    __attribute__((__format__(__printf__,2,3)));
+void out1fmt(const char *, ...)
+    __attribute__((__format__(__printf__,1,2)));
+int fmtstr(char *, size_t, const char *, ...)
+    __attribute__((__format__(__printf__,3,4)));
+#ifndef USE_GLIBC_STDIO
+void doformat(struct output *, const char *, va_list);
+#endif
+int xwrite(int, const void *, size_t);
+#ifdef notyet
+#ifdef USE_GLIBC_STDIO
+void initstreams(void);
+void openmemout(void);
+int __closememout(void);
+#endif
+#endif
+
+static inline void
+freestdout()
+{
+	output.nextc = output.buf;
+	output.flags = 0;
+}
+
+#define OUTPUT_ERR 01		/* error occurred on output */
+
+#ifdef USE_GLIBC_STDIO
+#define outc(c, o)	putc((c), (o)->stream)
+#define doformat(d, f, a)	vfprintf((d)->stream, (f), (a))
+#else
+#define outc(c, file)	((file)->nextc == (file)->end ? outcslow((c), (file)) : (*(file)->nextc = (c), (file)->nextc++))
+#endif
+#define out1c(c)	outc((c), out1)
+#define out2c(c)	outcslow((c), out2)
+#define out1str(s)	outstr((s), out1)
+#define out2str(s)	outstr((s), out2)
+#define outerr(f)	(f)->flags
+
+#define OUTPUT_INCL
+#endif
diff --git a/usr/dash/parser.c b/usr/dash/parser.c
new file mode 100644
index 0000000..91f019e
--- /dev/null
+++ b/usr/dash/parser.c
@@ -0,0 +1,1556 @@
+/*-
+ * Copyright (c) 1991, 1993
+ *	The Regents of the University of California.  All rights reserved.
+ * Copyright (c) 1997-2005
+ *	Herbert Xu <herbert@gondor.apana.org.au>.  All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Kenneth Almquist.
+ *
+ * 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. 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 <alloca.h>
+#include <stdlib.h>
+
+#include "shell.h"
+#include "parser.h"
+#include "nodes.h"
+#include "expand.h"	/* defines rmescapes() */
+#include "redir.h"	/* defines copyfd() */
+#include "exec.h"	/* defines find_builtin() */
+#include "syntax.h"
+#include "options.h"
+#include "input.h"
+#include "output.h"
+#include "var.h"
+#include "error.h"
+#include "memalloc.h"
+#include "mystring.h"
+#include "alias.h"
+#include "show.h"
+#include "builtins.h"
+#ifndef SMALL
+#include "myhistedit.h"
+#endif
+
+/*
+ * Shell command parser.
+ */
+
+#define EOFMARKLEN 79
+
+/* values returned by readtoken */
+#include "token.h"
+
+
+
+struct heredoc {
+	struct heredoc *next;	/* next here document in list */
+	union node *here;		/* redirection node */
+	char *eofmark;		/* string indicating end of input */
+	int striptabs;		/* if set, strip leading tabs */
+};
+
+
+
+struct heredoc *heredoclist;	/* list of here documents to read */
+int doprompt;			/* if set, prompt the user */
+int needprompt;			/* true if interactive and at start of line */
+int lasttoken;			/* last token read */
+MKINIT int tokpushback;		/* last token pushed back */
+char *wordtext;			/* text of last word returned by readtoken */
+int checkkwd;
+struct nodelist *backquotelist;
+union node *redirnode;
+struct heredoc *heredoc;
+int quoteflag;			/* set if (part of) last token was quoted */
+int startlinno;			/* line # where last token started */
+
+
+STATIC union node *list(int);
+STATIC union node *andor(void);
+STATIC union node *pipeline(void);
+STATIC union node *command(void);
+STATIC union node *simplecmd(void);
+STATIC union node *makename(void);
+STATIC void parsefname(void);
+STATIC void parseheredoc(void);
+STATIC int peektoken(void);
+STATIC int readtoken(void);
+STATIC int xxreadtoken(void);
+STATIC int readtoken1(int, char const *, char *, int);
+STATIC int noexpand(char *);
+STATIC void synexpect(int) __attribute__((__noreturn__));
+STATIC void synerror(const char *) __attribute__((__noreturn__));
+STATIC void setprompt(int);
+
+
+static inline int
+isassignment(const char *p)
+{
+	const char *q = endofname(p);
+	if (p == q)
+		return 0;
+	return *q == '=';
+}
+
+
+/*
+ * Read and parse a command.  Returns NEOF on end of file.  (NULL is a
+ * valid parse tree indicating a blank line.)
+ */
+
+union node *
+parsecmd(int interact)
+{
+	int t;
+
+	tokpushback = 0;
+	doprompt = interact;
+	if (doprompt)
+		setprompt(doprompt);
+	needprompt = 0;
+	t = readtoken();
+	if (t == TEOF)
+		return NEOF;
+	if (t == TNL)
+		return NULL;
+	tokpushback++;
+	return list(1);
+}
+
+
+STATIC union node *
+list(int nlflag)
+{
+	union node *n1, *n2, *n3;
+	int tok;
+
+	checkkwd = CHKNL | CHKKWD | CHKALIAS;
+	if (nlflag == 2 && tokendlist[peektoken()])
+		return NULL;
+	n1 = NULL;
+	for (;;) {
+		n2 = andor();
+		tok = readtoken();
+		if (tok == TBACKGND) {
+			if (n2->type == NPIPE) {
+				n2->npipe.backgnd = 1;
+			} else {
+				if (n2->type != NREDIR) {
+					n3 = stalloc(sizeof(struct nredir));
+					n3->nredir.n = n2;
+					n3->nredir.redirect = NULL;
+					n2 = n3;
+				}
+				n2->type = NBACKGND;
+			}
+		}
+		if (n1 == NULL) {
+			n1 = n2;
+		}
+		else {
+			n3 = (union node *)stalloc(sizeof (struct nbinary));
+			n3->type = NSEMI;
+			n3->nbinary.ch1 = n1;
+			n3->nbinary.ch2 = n2;
+			n1 = n3;
+		}
+		switch (tok) {
+		case TBACKGND:
+		case TSEMI:
+			tok = readtoken();
+			/* fall through */
+		case TNL:
+			if (tok == TNL) {
+				parseheredoc();
+				if (nlflag == 1)
+					return n1;
+			} else {
+				tokpushback++;
+			}
+			checkkwd = CHKNL | CHKKWD | CHKALIAS;
+			if (tokendlist[peektoken()])
+				return n1;
+			break;
+		case TEOF:
+			if (heredoclist)
+				parseheredoc();
+			else
+				pungetc();		/* push back EOF on input */
+			return n1;
+		default:
+			if (nlflag == 1)
+				synexpect(-1);
+			tokpushback++;
+			return n1;
+		}
+	}
+}
+
+
+
+STATIC union node *
+andor(void)
+{
+	union node *n1, *n2, *n3;
+	int t;
+
+	n1 = pipeline();
+	for (;;) {
+		if ((t = readtoken()) == TAND) {
+			t = NAND;
+		} else if (t == TOR) {
+			t = NOR;
+		} else {
+			tokpushback++;
+			return n1;
+		}
+		checkkwd = CHKNL | CHKKWD | CHKALIAS;
+		n2 = pipeline();
+		n3 = (union node *)stalloc(sizeof (struct nbinary));
+		n3->type = t;
+		n3->nbinary.ch1 = n1;
+		n3->nbinary.ch2 = n2;
+		n1 = n3;
+	}
+}
+
+
+
+STATIC union node *
+pipeline(void)
+{
+	union node *n1, *n2, *pipenode;
+	struct nodelist *lp, *prev;
+	int negate;
+
+	negate = 0;
+	TRACE(("pipeline: entered\n"));
+	if (readtoken() == TNOT) {
+		negate = !negate;
+		checkkwd = CHKKWD | CHKALIAS;
+	} else
+		tokpushback++;
+	n1 = command();
+	if (readtoken() == TPIPE) {
+		pipenode = (union node *)stalloc(sizeof (struct npipe));
+		pipenode->type = NPIPE;
+		pipenode->npipe.backgnd = 0;
+		lp = (struct nodelist *)stalloc(sizeof (struct nodelist));
+		pipenode->npipe.cmdlist = lp;
+		lp->n = n1;
+		do {
+			prev = lp;
+			lp = (struct nodelist *)stalloc(sizeof (struct nodelist));
+			checkkwd = CHKNL | CHKKWD | CHKALIAS;
+			lp->n = command();
+			prev->next = lp;
+		} while (readtoken() == TPIPE);
+		lp->next = NULL;
+		n1 = pipenode;
+	}
+	tokpushback++;
+	if (negate) {
+		n2 = (union node *)stalloc(sizeof (struct nnot));
+		n2->type = NNOT;
+		n2->nnot.com = n1;
+		return n2;
+	} else
+		return n1;
+}
+
+
+
+STATIC union node *
+command(void)
+{
+	union node *n1, *n2;
+	union node *ap, **app;
+	union node *cp, **cpp;
+	union node *redir, **rpp;
+	union node **rpp2;
+	int t;
+
+	redir = NULL;
+	rpp2 = &redir;
+
+	switch (readtoken()) {
+	default:
+		synexpect(-1);
+		/* NOTREACHED */
+	case TIF:
+		n1 = (union node *)stalloc(sizeof (struct nif));
+		n1->type = NIF;
+		n1->nif.test = list(0);
+		if (readtoken() != TTHEN)
+			synexpect(TTHEN);
+		n1->nif.ifpart = list(0);
+		n2 = n1;
+		while (readtoken() == TELIF) {
+			n2->nif.elsepart = (union node *)stalloc(sizeof (struct nif));
+			n2 = n2->nif.elsepart;
+			n2->type = NIF;
+			n2->nif.test = list(0);
+			if (readtoken() != TTHEN)
+				synexpect(TTHEN);
+			n2->nif.ifpart = list(0);
+		}
+		if (lasttoken == TELSE)
+			n2->nif.elsepart = list(0);
+		else {
+			n2->nif.elsepart = NULL;
+			tokpushback++;
+		}
+		t = TFI;
+		break;
+	case TWHILE:
+	case TUNTIL: {
+		int got;
+		n1 = (union node *)stalloc(sizeof (struct nbinary));
+		n1->type = (lasttoken == TWHILE)? NWHILE : NUNTIL;
+		n1->nbinary.ch1 = list(0);
+		if ((got=readtoken()) != TDO) {
+TRACE(("expecting DO got %s %s\n", tokname[got], got == TWORD ? wordtext : ""));
+			synexpect(TDO);
+		}
+		n1->nbinary.ch2 = list(0);
+		t = TDONE;
+		break;
+	}
+	case TFOR:
+		if (readtoken() != TWORD || quoteflag || ! goodname(wordtext))
+			synerror("Bad for loop variable");
+		n1 = (union node *)stalloc(sizeof (struct nfor));
+		n1->type = NFOR;
+		n1->nfor.var = wordtext;
+		checkkwd = CHKKWD | CHKALIAS;
+		if (readtoken() == TIN) {
+			app = &ap;
+			while (readtoken() == TWORD) {
+				n2 = (union node *)stalloc(sizeof (struct narg));
+				n2->type = NARG;
+				n2->narg.text = wordtext;
+				n2->narg.backquote = backquotelist;
+				*app = n2;
+				app = &n2->narg.next;
+			}
+			*app = NULL;
+			n1->nfor.args = ap;
+			if (lasttoken != TNL && lasttoken != TSEMI)
+				synexpect(-1);
+		} else {
+			n2 = (union node *)stalloc(sizeof (struct narg));
+			n2->type = NARG;
+			n2->narg.text = (char *)dolatstr;
+			n2->narg.backquote = NULL;
+			n2->narg.next = NULL;
+			n1->nfor.args = n2;
+			/*
+			 * Newline or semicolon here is optional (but note
+			 * that the original Bourne shell only allowed NL).
+			 */
+			if (lasttoken != TNL && lasttoken != TSEMI)
+				tokpushback++;
+		}
+		checkkwd = CHKNL | CHKKWD | CHKALIAS;
+		if (readtoken() != TDO)
+			synexpect(TDO);
+		n1->nfor.body = list(0);
+		t = TDONE;
+		break;
+	case TCASE:
+		n1 = (union node *)stalloc(sizeof (struct ncase));
+		n1->type = NCASE;
+		if (readtoken() != TWORD)
+			synexpect(TWORD);
+		n1->ncase.expr = n2 = (union node *)stalloc(sizeof (struct narg));
+		n2->type = NARG;
+		n2->narg.text = wordtext;
+		n2->narg.backquote = backquotelist;
+		n2->narg.next = NULL;
+		do {
+			checkkwd = CHKKWD | CHKALIAS;
+		} while (readtoken() == TNL);
+		if (lasttoken != TIN)
+			synexpect(TIN);
+		cpp = &n1->ncase.cases;
+next_case:
+		checkkwd = CHKNL | CHKKWD;
+		t = readtoken();
+		while(t != TESAC) {
+			if (lasttoken == TLP)
+				readtoken();
+			*cpp = cp = (union node *)stalloc(sizeof (struct nclist));
+			cp->type = NCLIST;
+			app = &cp->nclist.pattern;
+			for (;;) {
+				*app = ap = (union node *)stalloc(sizeof (struct narg));
+				ap->type = NARG;
+				ap->narg.text = wordtext;
+				ap->narg.backquote = backquotelist;
+				if (readtoken() != TPIPE)
+					break;
+				app = &ap->narg.next;
+				readtoken();
+			}
+			ap->narg.next = NULL;
+			if (lasttoken != TRP)
+				synexpect(TRP);
+			cp->nclist.body = list(2);
+
+			cpp = &cp->nclist.next;
+
+			checkkwd = CHKNL | CHKKWD;
+			if ((t = readtoken()) != TESAC) {
+				if (t != TENDCASE)
+					synexpect(TENDCASE);
+				else
+					goto next_case;
+			}
+		}
+		*cpp = NULL;
+		goto redir;
+	case TLP:
+		n1 = (union node *)stalloc(sizeof (struct nredir));
+		n1->type = NSUBSHELL;
+		n1->nredir.n = list(0);
+		n1->nredir.redirect = NULL;
+		t = TRP;
+		break;
+	case TBEGIN:
+		n1 = list(0);
+		t = TEND;
+		break;
+	case TWORD:
+	case TREDIR:
+		tokpushback++;
+		return simplecmd();
+	}
+
+	if (readtoken() != t)
+		synexpect(t);
+
+redir:
+	/* Now check for redirection which may follow command */
+	checkkwd = CHKKWD | CHKALIAS;
+	rpp = rpp2;
+	while (readtoken() == TREDIR) {
+		*rpp = n2 = redirnode;
+		rpp = &n2->nfile.next;
+		parsefname();
+	}
+	tokpushback++;
+	*rpp = NULL;
+	if (redir) {
+		if (n1->type != NSUBSHELL) {
+			n2 = (union node *)stalloc(sizeof (struct nredir));
+			n2->type = NREDIR;
+			n2->nredir.n = n1;
+			n1 = n2;
+		}
+		n1->nredir.redirect = redir;
+	}
+
+	return n1;
+}
+
+
+STATIC union node *
+simplecmd(void) {
+	union node *args, **app;
+	union node *n = NULL;
+	union node *vars, **vpp;
+	union node **rpp, *redir;
+	int savecheckkwd;
+
+	args = NULL;
+	app = &args;
+	vars = NULL;
+	vpp = &vars;
+	redir = NULL;
+	rpp = &redir;
+
+	savecheckkwd = CHKALIAS;
+	for (;;) {
+		checkkwd = savecheckkwd;
+		switch (readtoken()) {
+		case TWORD:
+			n = (union node *)stalloc(sizeof (struct narg));
+			n->type = NARG;
+			n->narg.text = wordtext;
+			n->narg.backquote = backquotelist;
+			if (savecheckkwd && isassignment(wordtext)) {
+				*vpp = n;
+				vpp = &n->narg.next;
+			} else {
+				*app = n;
+				app = &n->narg.next;
+				savecheckkwd = 0;
+			}
+			break;
+		case TREDIR:
+			*rpp = n = redirnode;
+			rpp = &n->nfile.next;
+			parsefname();	/* read name of redirection file */
+			break;
+		case TLP:
+			if (
+				args && app == &args->narg.next &&
+				!vars && !redir
+			) {
+				struct builtincmd *bcmd;
+				const char *name;
+
+				/* We have a function */
+				if (readtoken() != TRP)
+					synexpect(TRP);
+				name = n->narg.text;
+				if (
+					!goodname(name) || (
+						(bcmd = find_builtin(name)) &&
+						bcmd->flags & BUILTIN_SPECIAL
+					)
+				)
+					synerror("Bad function name");
+				n->type = NDEFUN;
+				checkkwd = CHKNL | CHKKWD | CHKALIAS;
+				n->narg.next = command();
+				return n;
+			}
+			/* fall through */
+		default:
+			tokpushback++;
+			goto out;
+		}
+	}
+out:
+	*app = NULL;
+	*vpp = NULL;
+	*rpp = NULL;
+	n = (union node *)stalloc(sizeof (struct ncmd));
+	n->type = NCMD;
+	n->ncmd.args = args;
+	n->ncmd.assign = vars;
+	n->ncmd.redirect = redir;
+	return n;
+}
+
+STATIC union node *
+makename(void)
+{
+	union node *n;
+
+	n = (union node *)stalloc(sizeof (struct narg));
+	n->type = NARG;
+	n->narg.next = NULL;
+	n->narg.text = wordtext;
+	n->narg.backquote = backquotelist;
+	return n;
+}
+
+void fixredir(union node *n, const char *text, int err)
+	{
+	TRACE(("Fix redir %s %d\n", text, err));
+	if (!err)
+		n->ndup.vname = NULL;
+
+	if (is_digit(text[0]) && text[1] == '\0')
+		n->ndup.dupfd = digit_val(text[0]);
+	else if (text[0] == '-' && text[1] == '\0')
+		n->ndup.dupfd = -1;
+	else {
+
+		if (err)
+			synerror("Bad fd number");
+		else
+			n->ndup.vname = makename();
+	}
+}
+
+
+STATIC void
+parsefname(void)
+{
+	union node *n = redirnode;
+
+	if (readtoken() != TWORD)
+		synexpect(-1);
+	if (n->type == NHERE) {
+		struct heredoc *here = heredoc;
+		struct heredoc *p;
+		int i;
+
+		if (quoteflag == 0)
+			n->type = NXHERE;
+		TRACE(("Here document %d\n", n->type));
+		if (! noexpand(wordtext) || (i = strlen(wordtext)) == 0 || i > EOFMARKLEN)
+			synerror("Illegal eof marker for << redirection");
+		rmescapes(wordtext);
+		here->eofmark = wordtext;
+		here->next = NULL;
+		if (heredoclist == NULL)
+			heredoclist = here;
+		else {
+			for (p = heredoclist ; p->next ; p = p->next);
+			p->next = here;
+		}
+	} else if (n->type == NTOFD || n->type == NFROMFD) {
+		fixredir(n, wordtext, 0);
+	} else {
+		n->nfile.fname = makename();
+	}
+}
+
+
+/*
+ * Input any here documents.
+ */
+
+STATIC void
+parseheredoc(void)
+{
+	struct heredoc *here;
+	union node *n;
+
+	here = heredoclist;
+	heredoclist = 0;
+
+	while (here) {
+		if (needprompt) {
+			setprompt(2);
+		}
+		readtoken1(pgetc(), here->here->type == NHERE? SQSYNTAX : DQSYNTAX,
+				here->eofmark, here->striptabs);
+		n = (union node *)stalloc(sizeof (struct narg));
+		n->narg.type = NARG;
+		n->narg.next = NULL;
+		n->narg.text = wordtext;
+		n->narg.backquote = backquotelist;
+		here->here->nhere.doc = n;
+		here = here->next;
+	}
+}
+
+STATIC int
+peektoken(void)
+{
+	int t;
+
+	t = readtoken();
+	tokpushback++;
+	return (t);
+}
+
+STATIC int
+readtoken(void)
+{
+	int t;
+#ifdef DEBUG
+	int alreadyseen = tokpushback;
+#endif
+
+top:
+	t = xxreadtoken();
+
+	/*
+	 * eat newlines
+	 */
+	if (checkkwd & CHKNL) {
+		while (t == TNL) {
+			parseheredoc();
+			t = xxreadtoken();
+		}
+	}
+
+	if (t != TWORD || quoteflag) {
+		goto out;
+	}
+
+	/*
+	 * check for keywords
+	 */
+	if (checkkwd & CHKKWD) {
+		const char *const *pp;
+
+		if ((pp = findkwd(wordtext))) {
+			lasttoken = t = pp - parsekwd + KWDOFFSET;
+			TRACE(("keyword %s recognized\n", tokname[t]));
+			goto out;
+		}
+	}
+
+	if (checkkwd & CHKALIAS) {
+		struct alias *ap;
+		if ((ap = lookupalias(wordtext, 1)) != NULL) {
+			if (*ap->val) {
+				pushstring(ap->val, ap);
+			}
+			goto top;
+		}
+	}
+out:
+	checkkwd = 0;
+#ifdef DEBUG
+	if (!alreadyseen)
+	    TRACE(("token %s %s\n", tokname[t], t == TWORD ? wordtext : ""));
+	else
+	    TRACE(("reread token %s %s\n", tokname[t], t == TWORD ? wordtext : ""));
+#endif
+	return (t);
+}
+
+
+/*
+ * Read the next input token.
+ * If the token is a word, we set backquotelist to the list of cmds in
+ *	backquotes.  We set quoteflag to true if any part of the word was
+ *	quoted.
+ * If the token is TREDIR, then we set redirnode to a structure containing
+ *	the redirection.
+ * In all cases, the variable startlinno is set to the number of the line
+ *	on which the token starts.
+ *
+ * [Change comment:  here documents and internal procedures]
+ * [Readtoken shouldn't have any arguments.  Perhaps we should make the
+ *  word parsing code into a separate routine.  In this case, readtoken
+ *  doesn't need to have any internal procedures, but parseword does.
+ *  We could also make parseoperator in essence the main routine, and
+ *  have parseword (readtoken1?) handle both words and redirection.]
+ */
+
+#define RETURN(token)	return lasttoken = token
+
+STATIC int
+xxreadtoken(void)
+{
+	int c;
+
+	if (tokpushback) {
+		tokpushback = 0;
+		return lasttoken;
+	}
+	if (needprompt) {
+		setprompt(2);
+	}
+	startlinno = plinno;
+	for (;;) {	/* until token or start of word found */
+		c = pgetc_macro();
+		switch (c) {
+		case ' ': case '\t':
+		case PEOA:
+			continue;
+		case '#':
+			while ((c = pgetc()) != '\n' && c != PEOF);
+			pungetc();
+			continue;
+		case '\\':
+			if (pgetc() == '\n') {
+				startlinno = ++plinno;
+				if (doprompt)
+					setprompt(2);
+				continue;
+			}
+			pungetc();
+			goto breakloop;
+		case '\n':
+			plinno++;
+			needprompt = doprompt;
+			RETURN(TNL);
+		case PEOF:
+			RETURN(TEOF);
+		case '&':
+			if (pgetc() == '&')
+				RETURN(TAND);
+			pungetc();
+			RETURN(TBACKGND);
+		case '|':
+			if (pgetc() == '|')
+				RETURN(TOR);
+			pungetc();
+			RETURN(TPIPE);
+		case ';':
+			if (pgetc() == ';')
+				RETURN(TENDCASE);
+			pungetc();
+			RETURN(TSEMI);
+		case '(':
+			RETURN(TLP);
+		case ')':
+			RETURN(TRP);
+		default:
+			goto breakloop;
+		}
+	}
+breakloop:
+	return readtoken1(c, BASESYNTAX, (char *)NULL, 0);
+#undef RETURN
+}
+
+
+
+/*
+ * If eofmark is NULL, read a word or a redirection symbol.  If eofmark
+ * is not NULL, read a here document.  In the latter case, eofmark is the
+ * word which marks the end of the document and striptabs is true if
+ * leading tabs should be stripped from the document.  The argument firstc
+ * is the first character of the input token or document.
+ *
+ * Because C does not have internal subroutines, I have simulated them
+ * using goto's to implement the subroutine linkage.  The following macros
+ * will run code that appears at the end of readtoken1.
+ */
+
+#define CHECKEND()	{goto checkend; checkend_return:;}
+#define PARSEREDIR()	{goto parseredir; parseredir_return:;}
+#define PARSESUB()	{goto parsesub; parsesub_return:;}
+#define PARSEBACKQOLD()	{oldstyle = 1; goto parsebackq; parsebackq_oldreturn:;}
+#define PARSEBACKQNEW()	{oldstyle = 0; goto parsebackq; parsebackq_newreturn:;}
+#define	PARSEARITH()	{goto parsearith; parsearith_return:;}
+
+STATIC int
+readtoken1(int firstc, char const *syntax, char *eofmark, int striptabs)
+{
+	int c = firstc;
+	char *out;
+	int len;
+	char line[EOFMARKLEN + 1];
+	struct nodelist *bqlist;
+	int quotef;
+	int dblquote;
+	int varnest;	/* levels of variables expansion */
+	int arinest;	/* levels of arithmetic expansion */
+	int parenlevel;	/* levels of parens in arithmetic */
+	int dqvarnest;	/* levels of variables expansion within double quotes */
+	int oldstyle;
+	char const *prevsyntax = NULL; /* syntax before arithmetic */
+
+	startlinno = plinno;
+	dblquote = 0;
+	if (syntax == DQSYNTAX)
+		dblquote = 1;
+	quotef = 0;
+	bqlist = NULL;
+	varnest = 0;
+	arinest = 0;
+	parenlevel = 0;
+	dqvarnest = 0;
+
+	STARTSTACKSTR(out);
+	loop: {	/* for each line, until end of word */
+#if ATTY
+		if (c == '\034' && doprompt
+		 && attyset() && ! equal(termval(), "emacs")) {
+			attyline();
+			if (syntax == BASESYNTAX)
+				return readtoken();
+			c = pgetc();
+			goto loop;
+		}
+#endif
+		CHECKEND();	/* set c to PEOF if at end of here document */
+		for (;;) {	/* until end of line or end of word */
+			CHECKSTRSPACE(4, out);	/* permit 4 calls to USTPUTC */
+			switch(syntax[c]) {
+			case CNL:	/* '\n' */
+				if (syntax == BASESYNTAX)
+					goto endword;	/* exit outer loop */
+				USTPUTC(c, out);
+				plinno++;
+				if (doprompt)
+					setprompt(2);
+				c = pgetc();
+				goto loop;		/* continue outer loop */
+			case CWORD:
+				USTPUTC(c, out);
+				break;
+			case CCTL:
+				if (eofmark == NULL || dblquote)
+					USTPUTC(CTLESC, out);
+				USTPUTC(c, out);
+				break;
+			case CBACK:	/* backslash */
+				c = pgetc2();
+				if (c == PEOF) {
+					USTPUTC(CTLESC, out);
+					USTPUTC('\\', out);
+					pungetc();
+				} else if (c == '\n') {
+					if (doprompt)
+						setprompt(2);
+				} else {
+					if (
+						dblquote &&
+						c != '\\' && c != '`' &&
+						c != '$' && (
+							c != '"' ||
+							eofmark != NULL
+						)
+					) {
+						USTPUTC(CTLESC, out);
+						USTPUTC('\\', out);
+					}
+					if (SQSYNTAX[c] == CCTL)
+						USTPUTC(CTLESC, out);
+					USTPUTC(c, out);
+					quotef++;
+				}
+				break;
+			case CSQUOTE:
+				syntax = SQSYNTAX;
+quotemark:
+				if (eofmark == NULL) {
+					USTPUTC(CTLQUOTEMARK, out);
+				}
+				break;
+			case CDQUOTE:
+				syntax = DQSYNTAX;
+				dblquote = 1;
+				goto quotemark;
+			case CENDQUOTE:
+				if (eofmark != NULL && arinest == 0 &&
+				    varnest == 0) {
+					USTPUTC(c, out);
+				} else {
+					if (dqvarnest == 0) {
+						syntax = BASESYNTAX;
+						dblquote = 0;
+					}
+					quotef++;
+					goto quotemark;
+				}
+				break;
+			case CVAR:	/* '$' */
+				PARSESUB();		/* parse substitution */
+				break;
+			case CENDVAR:	/* '}' */
+				if (varnest > 0) {
+					varnest--;
+					if (dqvarnest > 0) {
+						dqvarnest--;
+					}
+					USTPUTC(CTLENDVAR, out);
+				} else {
+					USTPUTC(c, out);
+				}
+				break;
+			case CLP:	/* '(' in arithmetic */
+				parenlevel++;
+				USTPUTC(c, out);
+				break;
+			case CRP:	/* ')' in arithmetic */
+				if (parenlevel > 0) {
+					USTPUTC(c, out);
+					--parenlevel;
+				} else {
+					if (pgetc() == ')') {
+						if (--arinest == 0) {
+							USTPUTC(CTLENDARI, out);
+							syntax = prevsyntax;
+							if (syntax == DQSYNTAX)
+								dblquote = 1;
+							else
+								dblquote = 0;
+						} else
+							USTPUTC(')', out);
+					} else {
+						/*
+						 * unbalanced parens
+						 *  (don't 2nd guess - no error)
+						 */
+						pungetc();
+						USTPUTC(')', out);
+					}
+				}
+				break;
+			case CBQUOTE:	/* '`' */
+				PARSEBACKQOLD();
+				break;
+			case CEOF:
+				goto endword;		/* exit outer loop */
+			case CIGN:
+				break;
+			default:
+				if (varnest == 0)
+					goto endword;	/* exit outer loop */
+				if (c != PEOA) {
+					USTPUTC(c, out);
+				}
+			}
+			c = pgetc_macro();
+		}
+	}
+endword:
+	if (syntax == ARISYNTAX)
+		synerror("Missing '))'");
+	if (syntax != BASESYNTAX && eofmark == NULL)
+		synerror("Unterminated quoted string");
+	if (varnest != 0) {
+		startlinno = plinno;
+		/* { */
+		synerror("Missing '}'");
+	}
+	USTPUTC('\0', out);
+	len = out - (char *)stackblock();
+	out = stackblock();
+	if (eofmark == NULL) {
+		if ((c == '>' || c == '<')
+		 && quotef == 0
+		 && len <= 2
+		 && (*out == '\0' || is_digit(*out))) {
+			PARSEREDIR();
+			return lasttoken = TREDIR;
+		} else {
+			pungetc();
+		}
+	}
+	quoteflag = quotef;
+	backquotelist = bqlist;
+	grabstackblock(len);
+	wordtext = out;
+	return lasttoken = TWORD;
+/* end of readtoken routine */
+
+
+
+/*
+ * Check to see whether we are at the end of the here document.  When this
+ * is called, c is set to the first character of the next input line.  If
+ * we are at the end of the here document, this routine sets the c to PEOF.
+ */
+
+checkend: {
+	if (eofmark) {
+		if (c == PEOA) {
+			c = pgetc2();
+		}
+		if (striptabs) {
+			while (c == '\t') {
+				c = pgetc2();
+			}
+		}
+		if (c == *eofmark) {
+			if (pfgets(line, sizeof line) != NULL) {
+				char *p, *q;
+
+				p = line;
+				for (q = eofmark + 1 ; *q && *p == *q ; p++, q++);
+				if (*p == '\n' && *q == '\0') {
+					c = PEOF;
+					plinno++;
+					needprompt = doprompt;
+				} else {
+					pushstring(line, NULL);
+				}
+			}
+		}
+	}
+	goto checkend_return;
+}
+
+
+/*
+ * Parse a redirection operator.  The variable "out" points to a string
+ * specifying the fd to be redirected.  The variable "c" contains the
+ * first character of the redirection operator.
+ */
+
+parseredir: {
+	char fd = *out;
+	union node *np;
+
+	np = (union node *)stalloc(sizeof (struct nfile));
+	if (c == '>') {
+		np->nfile.fd = 1;
+		c = pgetc();
+		if (c == '>')
+			np->type = NAPPEND;
+		else if (c == '|')
+			np->type = NCLOBBER;
+		else if (c == '&')
+			np->type = NTOFD;
+		else {
+			np->type = NTO;
+			pungetc();
+		}
+	} else {	/* c == '<' */
+		np->nfile.fd = 0;
+		switch (c = pgetc()) {
+		case '<':
+			if (sizeof (struct nfile) != sizeof (struct nhere)) {
+				np = (union node *)stalloc(sizeof (struct nhere));
+				np->nfile.fd = 0;
+			}
+			np->type = NHERE;
+			heredoc = (struct heredoc *)stalloc(sizeof (struct heredoc));
+			heredoc->here = np;
+			if ((c = pgetc()) == '-') {
+				heredoc->striptabs = 1;
+			} else {
+				heredoc->striptabs = 0;
+				pungetc();
+			}
+			break;
+
+		case '&':
+			np->type = NFROMFD;
+			break;
+
+		case '>':
+			np->type = NFROMTO;
+			break;
+
+		default:
+			np->type = NFROM;
+			pungetc();
+			break;
+		}
+	}
+	if (fd != '\0')
+		np->nfile.fd = digit_val(fd);
+	redirnode = np;
+	goto parseredir_return;
+}
+
+
+/*
+ * Parse a substitution.  At this point, we have read the dollar sign
+ * and nothing else.
+ */
+
+parsesub: {
+	int subtype;
+	int typeloc;
+	int flags;
+	char *p;
+	static const char types[] = "}-+?=";
+
+	c = pgetc();
+	if (
+		c <= PEOA  ||
+		(c != '(' && c != '{' && !is_name(c) && !is_special(c))
+	) {
+		USTPUTC('$', out);
+		pungetc();
+	} else if (c == '(') {	/* $(command) or $((arith)) */
+		if (pgetc() == '(') {
+			PARSEARITH();
+		} else {
+			pungetc();
+			PARSEBACKQNEW();
+		}
+	} else {
+		USTPUTC(CTLVAR, out);
+		typeloc = out - (char *)stackblock();
+		USTPUTC(VSNORMAL, out);
+		subtype = VSNORMAL;
+		if (c == '{') {
+			c = pgetc();
+			if (c == '#') {
+				if ((c = pgetc()) == '}')
+					c = '#';
+				else
+					subtype = VSLENGTH;
+			}
+			else
+				subtype = 0;
+		}
+		if (c > PEOA && is_name(c)) {
+			do {
+				STPUTC(c, out);
+				c = pgetc();
+			} while (c > PEOA && is_in_name(c));
+		} else if (is_digit(c)) {
+			do {
+				STPUTC(c, out);
+				c = pgetc();
+			} while (is_digit(c));
+		}
+		else if (is_special(c)) {
+			USTPUTC(c, out);
+			c = pgetc();
+		}
+		else
+badsub:			synerror("Bad substitution");
+
+		STPUTC('=', out);
+		flags = 0;
+		if (subtype == 0) {
+			switch (c) {
+			case ':':
+				flags = VSNUL;
+				c = pgetc();
+				/*FALLTHROUGH*/
+			default:
+				p = strchr(types, c);
+				if (p == NULL)
+					goto badsub;
+				subtype = p - types + VSNORMAL;
+				break;
+			case '%':
+			case '#':
+				{
+					int cc = c;
+					subtype = c == '#' ? VSTRIMLEFT :
+							     VSTRIMRIGHT;
+					c = pgetc();
+					if (c == cc)
+						subtype++;
+					else
+						pungetc();
+					break;
+				}
+			}
+		} else {
+			pungetc();
+		}
+		if (dblquote || arinest)
+			flags |= VSQUOTE;
+		*((char *)stackblock() + typeloc) = subtype | flags;
+		if (subtype != VSNORMAL) {
+			varnest++;
+			if (dblquote || arinest) {
+				dqvarnest++;
+			}
+		}
+	}
+	goto parsesub_return;
+}
+
+
+/*
+ * Called to parse command substitutions.  Newstyle is set if the command
+ * is enclosed inside $(...); nlpp is a pointer to the head of the linked
+ * list of commands (passed by reference), and savelen is the number of
+ * characters on the top of the stack which must be preserved.
+ */
+
+parsebackq: {
+	struct nodelist **nlpp;
+	union node *n;
+	char *str;
+	size_t savelen;
+	int saveprompt = 0;
+
+	str = NULL;
+	savelen = out - (char *)stackblock();
+	if (savelen > 0) {
+		str = alloca(savelen);
+		memcpy(str, stackblock(), savelen);
+	}
+        if (oldstyle) {
+                /* We must read until the closing backquote, giving special
+                   treatment to some slashes, and then push the string and
+                   reread it as input, interpreting it normally.  */
+                char *pout;
+                int pc;
+                size_t psavelen;
+                char *pstr;
+
+
+                STARTSTACKSTR(pout);
+		for (;;) {
+			if (needprompt) {
+				setprompt(2);
+			}
+			switch (pc = pgetc()) {
+			case '`':
+				goto done;
+
+			case '\\':
+                                if ((pc = pgetc()) == '\n') {
+					plinno++;
+					if (doprompt)
+						setprompt(2);
+					/*
+					 * If eating a newline, avoid putting
+					 * the newline into the new character
+					 * stream (via the STPUTC after the
+					 * switch).
+					 */
+					continue;
+				}
+                                if (pc != '\\' && pc != '`' && pc != '$'
+                                    && (!dblquote || pc != '"'))
+                                        STPUTC('\\', pout);
+				if (pc > PEOA) {
+					break;
+				}
+				/* fall through */
+
+			case PEOF:
+			case PEOA:
+			        startlinno = plinno;
+				synerror("EOF in backquote substitution");
+
+			case '\n':
+				plinno++;
+				needprompt = doprompt;
+				break;
+
+			default:
+				break;
+			}
+			STPUTC(pc, pout);
+                }
+done:
+                STPUTC('\0', pout);
+                psavelen = pout - (char *)stackblock();
+                if (psavelen > 0) {
+			pstr = grabstackstr(pout);
+			setinputstring(pstr);
+                }
+        }
+	nlpp = &bqlist;
+	while (*nlpp)
+		nlpp = &(*nlpp)->next;
+	*nlpp = (struct nodelist *)stalloc(sizeof (struct nodelist));
+	(*nlpp)->next = NULL;
+
+	if (oldstyle) {
+		saveprompt = doprompt;
+		doprompt = 0;
+	}
+
+	n = list(2);
+
+	if (oldstyle)
+		doprompt = saveprompt;
+	else {
+		if (readtoken() != TRP)
+			synexpect(TRP);
+	}
+
+	(*nlpp)->n = n;
+        if (oldstyle) {
+		/*
+		 * Start reading from old file again, ignoring any pushed back
+		 * tokens left from the backquote parsing
+		 */
+                popfile();
+		tokpushback = 0;
+	}
+	while (stackblocksize() <= savelen)
+		growstackblock();
+	STARTSTACKSTR(out);
+	if (str) {
+		memcpy(out, str, savelen);
+		STADJUST(savelen, out);
+	}
+	if (arinest || dblquote)
+		USTPUTC(CTLBACKQ | CTLQUOTE, out);
+	else
+		USTPUTC(CTLBACKQ, out);
+	if (oldstyle)
+		goto parsebackq_oldreturn;
+	else
+		goto parsebackq_newreturn;
+}
+
+/*
+ * Parse an arithmetic expansion (indicate start of one and set state)
+ */
+parsearith: {
+
+	if (++arinest == 1) {
+		prevsyntax = syntax;
+		syntax = ARISYNTAX;
+		USTPUTC(CTLARI, out);
+		if (dblquote)
+			USTPUTC('"',out);
+		else
+			USTPUTC(' ',out);
+	} else {
+		/*
+		 * we collapse embedded arithmetic expansion to
+		 * parenthesis, which should be equivalent
+		 */
+		USTPUTC('(', out);
+	}
+	goto parsearith_return;
+}
+
+} /* end of readtoken */
+
+
+
+#ifdef mkinit
+INCLUDE "parser.h"
+RESET {
+	tokpushback = 0;
+	checkkwd = 0;
+}
+#endif
+
+/*
+ * Returns true if the text contains nothing to expand (no dollar signs
+ * or backquotes).
+ */
+
+STATIC int
+noexpand(char *text)
+{
+	char *p;
+	signed char c;
+
+	p = text;
+	while ((c = *p++) != '\0') {
+		if (c == CTLQUOTEMARK)
+			continue;
+		if (c == CTLESC)
+			p++;
+		else if (BASESYNTAX[(int)c] == CCTL)
+			return 0;
+	}
+	return 1;
+}
+
+
+/*
+ * Return of a legal variable name (a letter or underscore followed by zero or
+ * more letters, underscores, and digits).
+ */
+
+char *
+endofname(const char *name)
+	{
+	char *p;
+
+	p = (char *) name;
+	if (! is_name(*p))
+		return p;
+	while (*++p) {
+		if (! is_in_name(*p))
+			break;
+	}
+	return p;
+}
+
+
+/*
+ * Called when an unexpected token is read during the parse.  The argument
+ * is the token that is expected, or -1 if more than one type of token can
+ * occur at this point.
+ */
+
+STATIC void
+synexpect(int token)
+{
+	char msg[64];
+
+	if (token >= 0) {
+		fmtstr(msg, 64, "%s unexpected (expecting %s)",
+			tokname[lasttoken], tokname[token]);
+	} else {
+		fmtstr(msg, 64, "%s unexpected", tokname[lasttoken]);
+	}
+	synerror(msg);
+	/* NOTREACHED */
+}
+
+
+STATIC void
+synerror(const char *msg)
+{
+	sh_error("Syntax error: %s", msg);
+	/* NOTREACHED */
+}
+
+STATIC void
+setprompt(int which)
+{
+	struct stackmark smark;
+	int show;
+
+	needprompt = 0;
+	whichprompt = which;
+
+#ifdef SMALL
+	show = 1;
+#else
+	show = !el;
+#endif
+	if (show) {
+		setstackmark(&smark);
+		stalloc(stackblocksize());
+		out2str(getprompt(NULL));
+		popstackmark(&smark);
+	}
+}
+
+const char *
+expandstr(const char *ps)
+{
+	union node n;
+
+	/* XXX Fix (char *) cast. */
+	setinputstring((char *)ps);
+	readtoken1(pgetc(), DQSYNTAX, nullstr, 0);
+	popfile();
+
+	n.narg.type = NARG;
+	n.narg.next = NULL;
+	n.narg.text = wordtext;
+	n.narg.backquote = backquotelist;
+
+	expandarg(&n, NULL, 0);
+	return stackblock();
+}
+
+/*
+ * called by editline -- any expansions to the prompt
+ *    should be added here.
+ */
+const char *
+getprompt(void *unused)
+{
+	const char *prompt;
+
+	switch (whichprompt) {
+	default:
+#ifdef DEBUG
+		return "<internal prompt error>";
+#endif
+	case 0:
+		return nullstr;
+	case 1:
+		prompt = ps1val();
+		break;
+	case 2:
+		prompt = ps2val();
+		break;
+	}
+
+	return expandstr(prompt);
+}
+
+const char *const *
+findkwd(const char *s)
+{
+	return findstring(
+		s, parsekwd, sizeof(parsekwd) / sizeof(const char *)
+	);
+}
diff --git a/usr/dash/parser.h b/usr/dash/parser.h
new file mode 100644
index 0000000..d0cf440
--- /dev/null
+++ b/usr/dash/parser.h
@@ -0,0 +1,96 @@
+/*-
+ * Copyright (c) 1991, 1993
+ *	The Regents of the University of California.  All rights reserved.
+ * Copyright (c) 1997-2005
+ *	Herbert Xu <herbert@gondor.apana.org.au>.  All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Kenneth Almquist.
+ *
+ * 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. 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.
+ *
+ *	@(#)parser.h	8.3 (Berkeley) 5/4/95
+ */
+
+/* control characters in argument strings */
+#define CTL_FIRST -127		/* first 'special' character */
+#define CTLESC -127		/* escape next character */
+#define CTLVAR -126		/* variable defn */
+#define CTLENDVAR -125
+#define CTLBACKQ -124
+#define CTLQUOTE 01		/* ored with CTLBACKQ code if in quotes */
+/*	CTLBACKQ | CTLQUOTE == 133 */
+#define	CTLARI -122		/* arithmetic expression */
+#define	CTLENDARI -121
+#define	CTLQUOTEMARK -120
+#define	CTL_LAST -120		/* last 'special' character */
+
+/* variable substitution byte (follows CTLVAR) */
+#define VSTYPE	0x0f		/* type of variable substitution */
+#define VSNUL	0x10		/* colon--treat the empty string as unset */
+#define VSQUOTE 0x80		/* inside double quotes--suppress splitting */
+
+/* values of VSTYPE field */
+#define VSNORMAL	0x1		/* normal variable:  $var or ${var} */
+#define VSMINUS		0x2		/* ${var-text} */
+#define VSPLUS		0x3		/* ${var+text} */
+#define VSQUESTION	0x4		/* ${var?message} */
+#define VSASSIGN	0x5		/* ${var=text} */
+#define VSTRIMRIGHT	0x6		/* ${var%pattern} */
+#define VSTRIMRIGHTMAX 	0x7		/* ${var%%pattern} */
+#define VSTRIMLEFT	0x8		/* ${var#pattern} */
+#define VSTRIMLEFTMAX	0x9		/* ${var##pattern} */
+#define VSLENGTH	0xa		/* ${#var} */
+
+/* values of checkkwd variable */
+#define CHKALIAS	0x1
+#define CHKKWD		0x2
+#define CHKNL		0x4
+
+
+/*
+ * NEOF is returned by parsecmd when it encounters an end of file.  It
+ * must be distinct from NULL, so we use the address of a variable that
+ * happens to be handy.
+ */
+extern int tokpushback;
+#define NEOF ((union node *)&tokpushback)
+extern int whichprompt;		/* 1 == PS1, 2 == PS2 */
+extern int checkkwd;
+extern int startlinno;		/* line # where last token started */
+
+
+union node *parsecmd(int);
+void fixredir(union node *, const char *, int);
+const char *getprompt(void *);
+const char *const *findkwd(const char *);
+char *endofname(const char *);
+const char *expandstr(const char *);
+
+static inline int
+goodname(const char *p)
+{
+	return !*endofname(p);
+}
diff --git a/usr/dash/redir.c b/usr/dash/redir.c
new file mode 100644
index 0000000..2bd8e9f
--- /dev/null
+++ b/usr/dash/redir.c
@@ -0,0 +1,475 @@
+/*-
+ * Copyright (c) 1991, 1993
+ *	The Regents of the University of California.  All rights reserved.
+ * Copyright (c) 1997-2005
+ *	Herbert Xu <herbert@gondor.apana.org.au>.  All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Kenneth Almquist.
+ *
+ * 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. 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 <sys/stat.h>
+#include <sys/types.h>
+#include <sys/param.h>	/* PIPE_BUF */
+#include <signal.h>
+#include <string.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdlib.h>
+
+/*
+ * Code for dealing with input/output redirection.
+ */
+
+#include "main.h"
+#include "shell.h"
+#include "nodes.h"
+#include "jobs.h"
+#include "options.h"
+#include "expand.h"
+#include "redir.h"
+#include "output.h"
+#include "memalloc.h"
+#include "error.h"
+
+
+#define EMPTY -2		/* marks an unused slot in redirtab */
+#ifndef PIPE_BUF
+# define PIPESIZE 4096		/* amount of buffering in a pipe */
+#else
+# define PIPESIZE PIPE_BUF
+#endif
+
+
+MKINIT
+struct redirtab {
+	struct redirtab *next;
+	int renamed[10];
+	int nullredirs;
+};
+
+
+MKINIT struct redirtab *redirlist;
+MKINIT int nullredirs;
+
+STATIC int openredirect(union node *);
+#ifdef notyet
+STATIC void dupredirect(union node *, int, char[10]);
+#else
+STATIC void dupredirect(union node *, int);
+#endif
+STATIC int openhere(union node *);
+STATIC int noclobberopen(const char *);
+
+
+/*
+ * Process a list of redirection commands.  If the REDIR_PUSH flag is set,
+ * old file descriptors are stashed away so that the redirection can be
+ * undone by calling popredir.  If the REDIR_BACKQ flag is set, then the
+ * standard output, and the standard error if it becomes a duplicate of
+ * stdout, is saved in memory.
+ */
+
+void
+redirect(union node *redir, int flags)
+{
+	union node *n;
+	struct redirtab *sv;
+	int i;
+	int fd;
+	int newfd;
+	int *p;
+#if notyet
+	char memory[10];	/* file descriptors to write to memory */
+
+	for (i = 10 ; --i >= 0 ; )
+		memory[i] = 0;
+	memory[1] = flags & REDIR_BACKQ;
+#endif
+	nullredirs++;
+	if (!redir) {
+		return;
+	}
+	sv = NULL;
+	INTOFF;
+	if (flags & REDIR_PUSH) {
+		struct redirtab *q;
+		q = ckmalloc(sizeof (struct redirtab));
+		q->next = redirlist;
+		redirlist = q;
+		q->nullredirs = nullredirs - 1;
+		for (i = 0 ; i < 10 ; i++)
+			q->renamed[i] = EMPTY;
+		nullredirs = 0;
+		sv = q;
+	}
+	n = redir;
+	do {
+		fd = n->nfile.fd;
+		if ((n->nfile.type == NTOFD || n->nfile.type == NFROMFD) &&
+		    n->ndup.dupfd == fd)
+			continue; /* redirect from/to same file descriptor */
+
+		newfd = openredirect(n);
+		if (fd == newfd)
+			continue;
+		if (sv && *(p = &sv->renamed[fd]) == EMPTY) {
+			int i = fcntl(fd, F_DUPFD, 10);
+			if (i == -1) {
+				i = errno;
+				if (i != EBADF) {
+					const char *m = strerror(i);
+					close(newfd);
+					sh_error("%d: %s", fd, m);
+					/* NOTREACHED */
+				}
+			} else {
+				*p = i;
+				close(fd);
+			}
+		} else {
+			close(fd);
+		}
+#ifdef notyet
+		dupredirect(n, newfd, memory);
+#else
+		dupredirect(n, newfd);
+#endif
+	} while ((n = n->nfile.next));
+	INTON;
+#ifdef notyet
+	if (memory[1])
+		out1 = &memout;
+	if (memory[2])
+		out2 = &memout;
+#endif
+	if (flags & REDIR_SAVEFD2 && sv && sv->renamed[2] >= 0)
+		preverrout.fd = sv->renamed[2];
+}
+
+
+STATIC int
+openredirect(union node *redir)
+{
+	char *fname;
+	int f;
+
+	switch (redir->nfile.type) {
+	case NFROM:
+		fname = redir->nfile.expfname;
+		if ((f = open64(fname, O_RDONLY)) < 0)
+			goto eopen;
+		break;
+	case NFROMTO:
+		fname = redir->nfile.expfname;
+		if ((f = open64(fname, O_RDWR|O_CREAT|O_TRUNC, 0666)) < 0)
+			goto ecreate;
+		break;
+	case NTO:
+		/* Take care of noclobber mode. */
+		if (Cflag) {
+			fname = redir->nfile.expfname;
+			if ((f = noclobberopen(fname)) < 0)
+				goto ecreate;
+			break;
+		}
+		/* FALLTHROUGH */
+	case NCLOBBER:
+		fname = redir->nfile.expfname;
+		if ((f = open64(fname, O_WRONLY|O_CREAT|O_TRUNC, 0666)) < 0)
+			goto ecreate;
+		break;
+	case NAPPEND:
+		fname = redir->nfile.expfname;
+		if ((f = open64(fname, O_WRONLY|O_CREAT|O_APPEND, 0666)) < 0)
+			goto ecreate;
+		break;
+	default:
+#ifdef DEBUG
+		abort();
+#endif
+		/* Fall through to eliminate warning. */
+	case NTOFD:
+	case NFROMFD:
+		f = -1;
+		break;
+	case NHERE:
+	case NXHERE:
+		f = openhere(redir);
+		break;
+	}
+
+	return f;
+ecreate:
+	sh_error("cannot create %s: %s", fname, errmsg(errno, E_CREAT));
+eopen:
+	sh_error("cannot open %s: %s", fname, errmsg(errno, E_OPEN));
+}
+
+
+STATIC void
+#ifdef notyet
+dupredirect(redir, f, memory)
+#else
+dupredirect(redir, f)
+#endif
+	union node *redir;
+	int f;
+#ifdef notyet
+	char memory[10];
+#endif
+	{
+	int fd = redir->nfile.fd;
+
+#ifdef notyet
+	memory[fd] = 0;
+#endif
+	if (redir->nfile.type == NTOFD || redir->nfile.type == NFROMFD) {
+		if (redir->ndup.dupfd >= 0) {	/* if not ">&-" */
+#ifdef notyet
+			if (memory[redir->ndup.dupfd])
+				memory[fd] = 1;
+			else
+#endif
+				copyfd(redir->ndup.dupfd, fd);
+		}
+		return;
+	}
+
+	if (f != fd) {
+		copyfd(f, fd);
+		close(f);
+	}
+	return;
+}
+
+
+/*
+ * Handle here documents.  Normally we fork off a process to write the
+ * data to a pipe.  If the document is short, we can stuff the data in
+ * the pipe without forking.
+ */
+
+STATIC int
+openhere(union node *redir)
+{
+	int pip[2];
+	size_t len = 0;
+
+	if (pipe(pip) < 0)
+		sh_error("Pipe call failed");
+	if (redir->type == NHERE) {
+		len = strlen(redir->nhere.doc->narg.text);
+		if (len <= PIPESIZE) {
+			xwrite(pip[1], redir->nhere.doc->narg.text, len);
+			goto out;
+		}
+	}
+	if (forkshell((struct job *)NULL, (union node *)NULL, FORK_NOJOB) == 0) {
+		close(pip[0]);
+		signal(SIGINT, SIG_IGN);
+		signal(SIGQUIT, SIG_IGN);
+		signal(SIGHUP, SIG_IGN);
+#ifdef SIGTSTP
+		signal(SIGTSTP, SIG_IGN);
+#endif
+		signal(SIGPIPE, SIG_DFL);
+		if (redir->type == NHERE)
+			xwrite(pip[1], redir->nhere.doc->narg.text, len);
+		else
+			expandhere(redir->nhere.doc, pip[1]);
+		_exit(0);
+	}
+out:
+	close(pip[1]);
+	return pip[0];
+}
+
+
+
+/*
+ * Undo the effects of the last redirection.
+ */
+
+void
+popredir(int drop)
+{
+	struct redirtab *rp;
+	int i;
+
+	if (--nullredirs >= 0)
+		return;
+	INTOFF;
+	rp = redirlist;
+	for (i = 0 ; i < 10 ; i++) {
+		if (rp->renamed[i] != EMPTY) {
+			if (!drop) {
+				close(i);
+				copyfd(rp->renamed[i], i);
+			}
+			close(rp->renamed[i]);
+		}
+	}
+	redirlist = rp->next;
+	nullredirs = rp->nullredirs;
+	ckfree(rp);
+	INTON;
+}
+
+/*
+ * Undo all redirections.  Called on error or interrupt.
+ */
+
+#ifdef mkinit
+
+INCLUDE "redir.h"
+
+RESET {
+	clearredir(0);
+}
+
+#endif
+
+/*
+ * Discard all saved file descriptors.
+ */
+
+void
+clearredir(int drop)
+{
+	for (;;) {
+		nullredirs = 0;
+		if (!redirlist)
+			break;
+		popredir(drop);
+	}
+}
+
+
+
+/*
+ * Copy a file descriptor to be >= to.  Returns -1
+ * if the source file descriptor is closed, EMPTY if there are no unused
+ * file descriptors left.
+ */
+
+int
+copyfd(int from, int to)
+{
+	int newfd;
+
+	newfd = fcntl(from, F_DUPFD, to);
+	if (newfd < 0) {
+		int errno2 = errno;
+		if (errno2 == EMFILE)
+			return EMPTY;
+		else
+			sh_error("%d: %s", from, strerror(errno2));
+	}
+	return newfd;
+}
+
+
+/*
+ * Open a file in noclobber mode.
+ * The code was copied from bash.
+ */
+int
+noclobberopen(fname)
+	const char *fname;
+{
+	int r, fd;
+	struct stat64 finfo, finfo2;
+
+	/*
+	 * If the file exists and is a regular file, return an error
+	 * immediately.
+	 */
+	r = stat64(fname, &finfo);
+	if (r == 0 && S_ISREG(finfo.st_mode)) {
+		errno = EEXIST;
+		return -1;
+	}
+
+	/*
+	 * If the file was not present (r != 0), make sure we open it
+	 * exclusively so that if it is created before we open it, our open
+	 * will fail.  Make sure that we do not truncate an existing file.
+	 * Note that we don't turn on O_EXCL unless the stat failed -- if the
+	 * file was not a regular file, we leave O_EXCL off.
+	 */
+	if (r != 0)
+		return open64(fname, O_WRONLY|O_CREAT|O_EXCL, 0666);
+	fd = open64(fname, O_WRONLY|O_CREAT, 0666);
+
+	/* If the open failed, return the file descriptor right away. */
+	if (fd < 0)
+		return fd;
+
+	/*
+	 * OK, the open succeeded, but the file may have been changed from a
+	 * non-regular file to a regular file between the stat and the open.
+	 * We are assuming that the O_EXCL open handles the case where FILENAME
+	 * did not exist and is symlinked to an existing file between the stat
+	 * and open.
+	 */
+
+	/*
+	 * If we can open it and fstat the file descriptor, and neither check
+	 * revealed that it was a regular file, and the file has not been
+	 * replaced, return the file descriptor.
+	 */
+	 if (fstat64(fd, &finfo2) == 0 && !S_ISREG(finfo2.st_mode) &&
+	     finfo.st_dev == finfo2.st_dev && finfo.st_ino == finfo2.st_ino)
+	 	return fd;
+
+	/* The file has been replaced.  badness. */
+	close(fd);
+	errno = EEXIST;
+	return -1;
+}
+
+
+int
+redirectsafe(union node *redir, int flags)
+{
+	int err;
+	volatile int saveint;
+	struct jmploc *volatile savehandler = handler;
+	struct jmploc jmploc;
+
+	SAVEINT(saveint);
+	if (!(err = setjmp(jmploc.loc) * 2)) {
+		handler = &jmploc;
+		redirect(redir, flags);
+	}
+	handler = savehandler;
+	if (err && exception != EXERROR)
+		longjmp(handler->loc, 1);
+	RESTOREINT(saveint);
+	return err;
+}
diff --git a/usr/dash/redir.h b/usr/dash/redir.h
new file mode 100644
index 0000000..3297f6a
--- /dev/null
+++ b/usr/dash/redir.h
@@ -0,0 +1,49 @@
+/*-
+ * Copyright (c) 1991, 1993
+ *	The Regents of the University of California.  All rights reserved.
+ * Copyright (c) 1997-2005
+ *	Herbert Xu <herbert@gondor.apana.org.au>.  All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Kenneth Almquist.
+ *
+ * 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. 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.
+ *
+ *	@(#)redir.h	8.2 (Berkeley) 5/4/95
+ */
+
+/* flags passed to redirect */
+#define REDIR_PUSH 01		/* save previous values of file descriptors */
+#ifdef notyet
+#define REDIR_BACKQ 02		/* save the command output in memory */
+#endif
+#define REDIR_SAVEFD2 03	/* set preverrout */
+
+union node;
+void redirect(union node *, int);
+void popredir(int);
+void clearredir(int);
+int copyfd(int, int);
+int redirectsafe(union node *, int);
diff --git a/usr/dash/sh.1 b/usr/dash/sh.1
new file mode 100644
index 0000000..ff5881a
--- /dev/null
+++ b/usr/dash/sh.1
@@ -0,0 +1,2332 @@
+.\" Copyright (c) 1991, 1993
+.\"	The Regents of the University of California.  All rights reserved.
+.\" Copyright (c) 1997-2005
+.\"	Herbert Xu <herbert@gondor.apana.org.au>.  All rights reserved.
+.\"
+.\" This code is derived from software contributed to Berkeley by
+.\" Kenneth Almquist.
+.\"
+.\" 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. 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.
+.\"
+.\"	@(#)sh.1	8.6 (Berkeley) 5/4/95
+.\"
+.Dd January 19, 2003
+.Os
+.Dt SH 1
+.Sh NAME
+.Nm sh
+.Nd command interpreter (shell)
+.Sh SYNOPSIS
+.Nm
+.Bk -words
+.Op Fl aCefnuvxIimqVEb
+.Op Cm +aCefnuvxIimqVEb
+.Ek
+.Bk -words
+.Op Fl o Ar option_name
+.Op Cm +o Ar option_name
+.Ek
+.Bk -words
+.Op Ar command_file Oo Ar argument ... Oc
+.Ek
+.Nm
+.Fl c
+.Bk -words
+.Op Fl aCefnuvxIimqVEb
+.Op Cm +aCefnuvxIimqVEb
+.Ek
+.Bk -words
+.Op Fl o Ar option_name
+.Op Cm +o Ar option_name
+.Ek
+.Bk -words
+.Ar command_string
+.Op Ar command_name Oo Ar argument ... Oc
+.Ek
+.Nm
+.Fl s
+.Bk -words
+.Op Fl aCefnuvxIimqVEb
+.Op Cm +aCefnuvxIimqVEb
+.Ek
+.Bk -words
+.Op Fl o Ar option_name
+.Op Cm +o Ar option_name
+.Ek
+.Bk -words
+.Op Ar argument ...
+.Ek
+.Sh DESCRIPTION
+.Nm
+is the standard command interpreter for the system.
+The current version of
+.Nm
+is in the process of being changed to conform with the
+.Tn POSIX
+1003.2 and 1003.2a specifications for the shell.
+This version has many
+features which make it appear similar in some respects to the Korn shell,
+but it is not a Korn shell clone (see
+.Xr ksh 1 ) .
+Only features designated by
+.Tn POSIX ,
+plus a few Berkeley extensions, are being incorporated into this shell.
+We expect
+.Tn POSIX
+conformance by the time 4.4 BSD is released.
+This man page is not intended
+to be a tutorial or a complete specification of the shell.
+.Ss Overview
+The shell is a command that reads lines from either a file or the
+terminal, interprets them, and generally executes other commands.
+It is the program that is running when a user logs into the system
+(although a user can select a different shell with the
+.Xr chsh 1
+command).
+The shell implements a language that has flow control
+constructs, a macro facility that provides a variety of features in
+addition to data storage, along with built in history and line editing
+capabilities.
+It incorporates many features to aid interactive use and
+has the advantage that the interpretative language is common to both
+interactive and non-interactive use (shell scripts).
+That is, commands
+can be typed directly to the running shell or can be put into a file and
+the file can be executed directly by the shell.
+.Ss Invocation
+If no args are present and if the standard input of the shell
+is connected to a terminal (or if the
+.Fl i
+flag is set),
+and the
+.Fl c
+option is not present, the shell is considered an interactive shell.
+An interactive shell generally prompts before each command and handles
+programming and command errors differently (as described below).
+When first starting,
+the shell inspects argument 0, and if it begins with a dash
+.Sq - ,
+the shell is also considered
+a login shell.
+This is normally done automatically by the system
+when the user first logs in.
+A login shell first reads commands
+from the files
+.Pa /etc/profile
+and
+.Pa .profile
+if they exist.
+If the environment variable
+.Ev ENV
+is set on entry to an interactive shell, or is set in the
+.Pa .profile
+of a login shell, the shell next reads
+commands from the file named in
+.Ev ENV .
+Therefore, a user should place commands that are to be executed only at
+login time in the
+.Pa .profile
+file, and commands that are executed for every interactive shell inside the
+.Ev ENV
+file.
+To set the
+.Ev ENV
+variable to some file, place the following line in your
+.Pa .profile
+of your home directory
+.Pp
+.Dl ENV=$HOME/.shinit; export ENV
+.Pp
+substituting for
+.Dq .shinit
+any filename you wish.
+.Pp
+If command line arguments besides the options have been specified, then
+the shell treats the first argument as the name of a file from which to
+read commands (a shell script), and the remaining arguments are set as the
+positional parameters of the shell ($1, $2, etc).
+Otherwise, the shell
+reads commands from its standard input.
+.Ss Argument List Processing
+All of the single letter options have a corresponding name that can be
+used as an argument to the
+.Fl o
+option.
+The set
+.Fl o
+name is provided next to the single letter option in
+the description below.
+Specifying a dash
+.Dq -
+turns the option on, while using a plus
+.Dq +
+disables the option.
+The following options can be set from the command line or
+with the
+.Ic set
+builtin (described later).
+.Bl -tag -width aaaallexportfoo -offset indent
+.It Fl a Em allexport
+Export all variables assigned to.
+.It Fl c
+Read commands from the
+.Ar command_string
+operand instead of from the standard input.
+Special parameter 0 will be set from the
+.Ar command_name
+operand and the positional parameters ($1, $2, etc.)
+set from the remaining argument operands.
+.It Fl C Em noclobber
+Don't overwrite existing files with
+.Dq \*[Gt] .
+.It Fl e Em errexit
+If not interactive, exit immediately if any untested command fails.
+The exit status of a command is considered to be
+explicitly tested if the command is used to control an
+.Ic if ,
+.Ic elif ,
+.Ic while ,
+or
+.Ic until ;
+or if the command is the left hand operand of an
+.Dq &&
+or
+.Dq ||
+operator.
+.It Fl f Em noglob
+Disable pathname expansion.
+.It Fl n Em noexec
+If not interactive, read commands but do not execute them.
+This is useful for checking the syntax of shell scripts.
+.It Fl u Em nounset
+Write a message to standard error when attempting to expand a variable
+that is not set, and if the shell is not interactive, exit immediately.
+.It Fl v Em verbose
+The shell writes its input to standard error as it is read.
+Useful for debugging.
+.It Fl x Em xtrace
+Write each command to standard error (preceded by a
+.Sq +\  )
+before it is executed.
+Useful for debugging.
+.It Fl I Em ignoreeof
+Ignore EOF's from input when interactive.
+.It Fl i Em interactive
+Force the shell to behave interactively.
+.It Fl m Em monitor
+Turn on job control (set automatically when interactive).
+.It Fl s Em stdin
+Read commands from standard input (set automatically if no file arguments
+are present).
+This option has no effect when set after the shell has
+already started running (i.e. with
+.Ic set ) .
+.It Fl V Em vi
+Enable the built-in
+.Xr vi 1
+command line editor (disables
+.Fl E
+if it has been set).
+.It Fl E Em emacs
+Enable the built-in
+.Xr emacs 1
+command line editor (disables
+.Fl V
+if it has been set).
+.It Fl b Em notify
+Enable asynchronous notification of background job completion.
+(UNIMPLEMENTED for 4.4alpha)
+.El
+.Ss Lexical Structure
+The shell reads input in terms of lines from a file and breaks it up into
+words at whitespace (blanks and tabs), and at certain sequences of
+characters that are special to the shell called
+.Dq operators .
+There are two types of operators: control operators and redirection
+operators (their meaning is discussed later).
+Following is a list of operators:
+.Bl -ohang -offset indent
+.It "Control operators:"
+.Dl &  &&  \&(  \&)  \&;  ;; | || \*[Lt]newline\*[Gt]
+.It "Redirection operators:"
+.Dl \*[Lt]  \*[Gt]  \*[Gt]|  \*[Lt]\*[Lt]  \*[Gt]\*[Gt]  \*[Lt]&  \*[Gt]&  \*[Lt]\*[Lt]-  \*[Lt]\*[Gt]
+.El
+.Ss Quoting
+Quoting is used to remove the special meaning of certain characters or
+words to the shell, such as operators, whitespace, or keywords.
+There are three types of quoting: matched single quotes,
+matched double quotes, and backslash.
+.Ss Backslash
+A backslash preserves the literal meaning of the following
+character, with the exception of
+.Aq newline .
+A backslash preceding a
+.Aq newline
+is treated as a line continuation.
+.Ss Single Quotes
+Enclosing characters in single quotes preserves the literal meaning of all
+the characters (except single quotes, making it impossible to put
+single-quotes in a single-quoted string).
+.Ss Double Quotes
+Enclosing characters within double quotes preserves the literal
+meaning of all characters except dollarsign
+.Pq $ ,
+backquote
+.Pq ` ,
+and backslash
+.Pq \e .
+The backslash inside double quotes is historically weird, and serves to
+quote only the following characters:
+.Dl $  `  \*q  \e  \*[Lt]newline\*[Gt] .
+Otherwise it remains literal.
+.Ss Reserved Words
+Reserved words are words that have special meaning to the
+shell and are recognized at the beginning of a line and
+after a control operator.
+The following are reserved words:
+.Bl -column while while while while while -offset indent
+.It ! Ta elif Ta fi Ta while Ta case
+.It else Ta for Ta then Ta { Ta }
+.It do Ta done Ta until Ta if Ta esac
+.El
+.Pp
+Their meaning is discussed later.
+.Ss Aliases
+An alias is a name and corresponding value set using the
+.Xr alias 1
+builtin command.
+Whenever a reserved word may occur (see above),
+and after checking for reserved words, the shell
+checks the word to see if it matches an alias.
+If it does, it replaces it in the input stream with its value.
+For example, if there is an alias called
+.Dq lf
+with the value
+.Dq "ls -F" ,
+then the input:
+.Pp
+.Dl lf foobar Aq return
+.Pp
+would become
+.Pp
+.Dl ls -F foobar Aq return
+.Pp
+Aliases provide a convenient way for naive users to create shorthands for
+commands without having to learn how to create functions with arguments.
+They can also be used to create lexically obscure code.
+This use is discouraged.
+.Ss Commands
+The shell interprets the words it reads according to a language, the
+specification of which is outside the scope of this man page (refer to the
+BNF in the
+.Tn POSIX
+1003.2 document).
+Essentially though, a line is read and if the first
+word of the line (or after a control operator) is not a reserved word,
+then the shell has recognized a simple command.
+Otherwise, a complex
+command or some other special construct may have been recognized.
+.Ss Simple Commands
+If a simple command has been recognized, the shell performs
+the following actions:
+.Bl -enum -offset indent
+.It
+Leading words of the form
+.Dq name=value
+are stripped off and assigned to the environment of the simple command.
+Redirection operators and their arguments (as described below) are
+stripped off and saved for processing.
+.It
+The remaining words are expanded as described in
+the section called
+.Dq Expansions ,
+and the first remaining word is considered the command name and the
+command is located.
+The remaining words are considered the arguments of the command.
+If no command name resulted, then the
+.Dq name=value
+variable assignments recognized in item 1 affect the current shell.
+.It
+Redirections are performed as described in the next section.
+.El
+.Ss Redirections
+Redirections are used to change where a command reads its input or sends
+its output.
+In general, redirections open, close, or duplicate an
+existing reference to a file.
+The overall format used for redirection is:
+.Pp
+.Dl [n] Va redir-op Ar file
+.Pp
+where
+.Va redir-op
+is one of the redirection operators mentioned previously.
+Following is a list of the possible redirections.
+The
+.Bq n
+is an optional number, as in
+.Sq 3
+(not
+.Sq Bq 3 ,
+that refers to a file descriptor.
+.Bl -tag -width aaabsfiles -offset indent
+.It [n] Ns \*[Gt] file
+Redirect standard output (or n) to file.
+.It [n] Ns \*[Gt]| file
+Same, but override the
+.Fl C
+option.
+.It [n] Ns \*[Gt]\*[Gt] file
+Append standard output (or n) to file.
+.It [n] Ns \*[Lt] file
+Redirect standard input (or n) from file.
+.It [n1] Ns \*[Lt]& Ns n2
+Duplicate standard input (or n1) from file descriptor n2.
+.It [n] Ns \*[Lt]&-
+Close standard input (or n).
+.It [n1] Ns \*[Gt]& Ns n2
+Duplicate standard output (or n1) to n2.
+.It [n] Ns \*[Gt]&-
+Close standard output (or n).
+.It [n] Ns \*[Lt]\*[Gt] file
+Open file for reading and writing on standard input (or n).
+.El
+.Pp
+The following redirection is often called a
+.Dq here-document .
+.Bl -item -offset indent
+.It
+.Li [n]\*[Lt]\*[Lt] delimiter
+.Dl here-doc-text ...
+.Li delimiter
+.El
+.Pp
+All the text on successive lines up to the delimiter is saved away and
+made available to the command on standard input, or file descriptor n if
+it is specified.
+If the delimiter as specified on the initial line is
+quoted, then the here-doc-text is treated literally, otherwise the text is
+subjected to parameter expansion, command substitution, and arithmetic
+expansion (as described in the section on
+.Dq Expansions ) .
+If the operator is
+.Dq \*[Lt]\*[Lt]-
+instead of
+.Dq \*[Lt]\*[Lt] ,
+then leading tabs in the here-doc-text are stripped.
+.Ss Search and Execution
+There are three types of commands: shell functions, builtin commands, and
+normal programs -- and the command is searched for (by name) in that order.
+They each are executed in a different way.
+.Pp
+When a shell function is executed, all of the shell positional parameters
+(except $0, which remains unchanged) are set to the arguments of the shell
+function.
+The variables which are explicitly placed in the environment of
+the command (by placing assignments to them before the function name) are
+made local to the function and are set to the values given.
+Then the command given in the function definition is executed.
+The positional parameters are restored to their original values
+when the command completes.
+This all occurs within the current shell.
+.Pp
+Shell builtins are executed internally to the shell, without spawning a
+new process.
+.Pp
+Otherwise, if the command name doesn't match a function or builtin, the
+command is searched for as a normal program in the file system (as
+described in the next section).
+When a normal program is executed, the shell runs the program,
+passing the arguments and the environment to the program.
+If the program is not a normal executable file (i.e., if it does
+not begin with the "magic number" whose
+.Tn ASCII
+representation is "#!", so
+.Xr execve 2
+returns
+.Er ENOEXEC
+then) the shell will interpret the program in a subshell.
+The child shell will reinitialize itself in this case,
+so that the effect will be as if a
+new shell had been invoked to handle the ad-hoc shell script, except that
+the location of hashed commands located in the parent shell will be
+remembered by the child.
+.Pp
+Note that previous versions of this document and the source code itself
+misleadingly and sporadically refer to a shell script without a magic
+number as a "shell procedure".
+.Ss Path Search
+When locating a command, the shell first looks to see if it has a shell
+function by that name.
+Then it looks for a builtin command by that name.
+If a builtin command is not found, one of two things happen:
+.Bl -enum
+.It
+Command names containing a slash are simply executed without performing
+any searches.
+.It
+The shell searches each entry in
+.Ev PATH
+in turn for the command.
+The value of the
+.Ev PATH
+variable should be a series of entries separated by colons.
+Each entry consists of a directory name.
+The current directory may be indicated
+implicitly by an empty directory name, or explicitly by a single period.
+.El
+.Ss Command Exit Status
+Each command has an exit status that can influence the behaviour
+of other shell commands.
+The paradigm is that a command exits
+with zero for normal or success, and non-zero for failure,
+error, or a false indication.
+The man page for each command
+should indicate the various exit codes and what they mean.
+Additionally, the builtin commands return exit codes, as does
+an executed shell function.
+.Pp
+If a command consists entirely of variable assignments then the
+exit status of the command is that of the last command substitution
+if any, otherwise 0.
+.Ss Complex Commands
+Complex commands are combinations of simple commands with control
+operators or reserved words, together creating a larger complex command.
+More generally, a command is one of the following:
+.Bl -bullet
+.It
+simple command
+.It
+pipeline
+.It
+list or compound-list
+.It
+compound command
+.It
+function definition
+.El
+.Pp
+Unless otherwise stated, the exit status of a command is that of the last
+simple command executed by the command.
+.Ss Pipelines
+A pipeline is a sequence of one or more commands separated
+by the control operator |.
+The standard output of all but
+the last command is connected to the standard input
+of the next command.
+The standard output of the last
+command is inherited from the shell, as usual.
+.Pp
+The format for a pipeline is:
+.Pp
+.Dl [!] command1 [ | command2 ...]
+.Pp
+The standard output of command1 is connected to the standard input of
+command2.
+The standard input, standard output, or both of a command is
+considered to be assigned by the pipeline before any redirection specified
+by redirection operators that are part of the command.
+.Pp
+If the pipeline is not in the background (discussed later), the shell
+waits for all commands to complete.
+.Pp
+If the reserved word ! does not precede the pipeline, the exit status is
+the exit status of the last command specified in the pipeline.
+Otherwise, the exit status is the logical NOT of the exit status of the
+last command.
+That is, if the last command returns zero, the exit status
+is 1; if the last command returns greater than zero, the exit status is
+zero.
+.Pp
+Because pipeline assignment of standard input or standard output or both
+takes place before redirection, it can be modified by redirection.
+For example:
+.Pp
+.Dl $ command1 2\*[Gt]&1 | command2
+.Pp
+sends both the standard output and standard error of command1
+to the standard input of command2.
+.Pp
+A ; or
+.Aq newline
+terminator causes the preceding AND-OR-list (described
+next) to be executed sequentially; a & causes asynchronous execution of
+the preceding AND-OR-list.
+.Pp
+Note that unlike some other shells, each process in the pipeline is a
+child of the invoking shell (unless it is a shell builtin, in which case
+it executes in the current shell -- but any effect it has on the
+environment is wiped).
+.Ss Background Commands -- &
+If a command is terminated by the control operator ampersand (&), the
+shell executes the command asynchronously -- that is, the shell does not
+wait for the command to finish before executing the next command.
+.Pp
+The format for running a command in background is:
+.Pp
+.Dl command1 & [command2 & ...]
+.Pp
+If the shell is not interactive, the standard input of an asynchronous
+command is set to
+.Pa /dev/null .
+.Ss Lists -- Generally Speaking
+A list is a sequence of zero or more commands separated by newlines,
+semicolons, or ampersands, and optionally terminated by one of these three
+characters.
+The commands in a list are executed in the order they are written.
+If command is followed by an ampersand, the shell starts the
+command and immediately proceed onto the next command; otherwise it waits
+for the command to terminate before proceeding to the next one.
+.Ss Short-Circuit List Operators
+.Dq &&
+and
+.Dq ||
+are AND-OR list operators.
+.Dq &&
+executes the first command, and then executes the second command iff the
+exit status of the first command is zero.
+.Dq ||
+is similar, but executes the second command iff the exit status of the first
+command is nonzero.
+.Dq &&
+and
+.Dq ||
+both have the same priority.
+.Ss Flow-Control Constructs -- if, while, for, case
+The syntax of the if command is
+.Bd -literal -offset indent
+if list
+then list
+[ elif list
+then    list ] ...
+[ else list ]
+fi
+.Ed
+.Pp
+The syntax of the while command is
+.Bd -literal -offset indent
+while list
+do   list
+done
+.Ed
+.Pp
+The two lists are executed repeatedly while the exit status of the
+first list is zero.
+The until command is similar, but has the word
+until in place of while, which causes it to
+repeat until the exit status of the first list is zero.
+.Pp
+The syntax of the for command is
+.Bd -literal -offset indent
+for variable in word ...
+do   list
+done
+.Ed
+.Pp
+The words are expanded, and then the list is executed repeatedly with the
+variable set to each word in turn.
+do and done may be replaced with
+.Dq {
+and
+.Dq } .
+.Pp
+The syntax of the break and continue command is
+.Bd -literal -offset indent
+break [ num ]
+continue [ num ]
+.Ed
+.Pp
+Break terminates the num innermost for or while loops.
+Continue continues with the next iteration of the innermost loop.
+These are implemented as builtin commands.
+.Pp
+The syntax of the case command is
+.Bd -literal -offset indent
+case word in
+pattern) list ;;
+\&...
+esac
+.Ed
+.Pp
+The pattern can actually be one or more patterns (see
+.Sx Shell Patterns
+described later), separated by
+.Dq \*(Ba
+characters.
+.Ss Grouping Commands Together
+Commands may be grouped by writing either
+.Pp
+.Dl (list)
+.Pp
+or
+.Pp
+.Dl { list; }
+.Pp
+The first of these executes the commands in a subshell.
+Builtin commands grouped into a (list) will not affect the current shell.
+The second form does not fork another shell so is slightly more efficient.
+Grouping commands together this way allows you to redirect
+their output as though they were one program:
+.Pp
+.Bd -literal -offset indent
+{ printf \*q hello \*q ; printf \*q world\\n" ; } \*[Gt] greeting
+.Ed
+.Pp
+Note that
+.Dq }
+must follow a control operator (here,
+.Dq \&; )
+so that it is recognized as a reserved word and not as another command argument.
+.Ss Functions
+The syntax of a function definition is
+.Pp
+.Dl name ( ) command
+.Pp
+A function definition is an executable statement; when executed it
+installs a function named name and returns an exit status of zero.
+The command is normally a list enclosed between
+.Dq {
+and
+.Dq } .
+.Pp
+Variables may be declared to be local to a function by using a local
+command.
+This should appear as the first statement of a function, and the syntax is
+.Pp
+.Dl local [ variable | - ] ...
+.Pp
+Local is implemented as a builtin command.
+.Pp
+When a variable is made local, it inherits the initial value and exported
+and readonly flags from the variable with the same name in the surrounding
+scope, if there is one.
+Otherwise, the variable is initially unset.
+The shell uses dynamic scoping, so that if you make the variable x local to
+function f, which then calls function g, references to the variable x made
+inside g will refer to the variable x declared inside f, not to the global
+variable named x.
+.Pp
+The only special parameter that can be made local is
+.Dq - .
+Making
+.Dq -
+local any shell options that are changed via the set command inside the
+function to be restored to their original values when the function
+returns.
+.Pp
+The syntax of the return command is
+.Pp
+.Dl return [ exitstatus ]
+.Pp
+It terminates the currently executing function.
+Return is implemented as a builtin command.
+.Ss Variables and Parameters
+The shell maintains a set of parameters.
+A parameter denoted by a name is called a variable.
+When starting up, the shell turns all the environment
+variables into shell variables.
+New variables can be set using the form
+.Pp
+.Dl name=value
+.Pp
+Variables set by the user must have a name consisting solely of
+alphabetics, numerics, and underscores - the first of which must not be
+numeric.
+A parameter can also be denoted by a number or a special
+character as explained below.
+.Ss Positional Parameters
+A positional parameter is a parameter denoted by a number (n \*[Gt] 0).
+The shell sets these initially to the values of its command line arguments
+that follow the name of the shell script.
+The
+.Ic set
+builtin can also be used to set or reset them.
+.Ss Special Parameters
+A special parameter is a parameter denoted by one of the following special
+characters.
+The value of the parameter is listed next to its character.
+.Bl -tag -width thinhyphena
+.It *
+Expands to the positional parameters, starting from one.
+When the
+expansion occurs within a double-quoted string it expands to a single
+field with the value of each parameter separated by the first character of
+the
+.Ev IFS
+variable, or by a
+.Aq space
+if
+.Ev IFS
+is unset.
+.It @
+Expands to the positional parameters, starting from one.
+When the expansion occurs within double-quotes, each positional
+parameter expands as a separate argument.
+If there are no positional parameters, the
+expansion of @ generates zero arguments, even when @ is
+double-quoted.
+What this basically means, for example, is
+if $1 is
+.Dq abc
+and $2 is
+.Dq def ghi ,
+then
+.Qq $@
+expands to
+the two arguments:
+.Pp
+.Sm off
+.Dl \*q abc \*q \  \*q def\ ghi \*q
+.Sm on
+.It #
+Expands to the number of positional parameters.
+.It ?
+Expands to the exit status of the most recent pipeline.
+.It - (Hyphen.)
+Expands to the current option flags (the single-letter
+option names concatenated into a string) as specified on
+invocation, by the set builtin command, or implicitly
+by the shell.
+.It $
+Expands to the process ID of the invoked shell.
+A subshell retains the same value of $ as its parent.
+.It !
+Expands to the process ID of the most recent background
+command executed from the current shell.
+For a pipeline, the process ID is that of the last command in the pipeline.
+.It 0 (Zero.)
+Expands to the name of the shell or shell script.
+.El
+.Ss Word Expansions
+This clause describes the various expansions that are performed on words.
+Not all expansions are performed on every word, as explained later.
+.Pp
+Tilde expansions, parameter expansions, command substitutions, arithmetic
+expansions, and quote removals that occur within a single word expand to a
+single field.
+It is only field splitting or pathname expansion that can
+create multiple fields from a single word.
+The single exception to this
+rule is the expansion of the special parameter @ within double-quotes, as
+was described above.
+.Pp
+The order of word expansion is:
+.Bl -enum
+.It
+Tilde Expansion, Parameter Expansion, Command Substitution,
+Arithmetic Expansion (these all occur at the same time).
+.It
+Field Splitting is performed on fields
+generated by step (1) unless the
+.Ev IFS
+variable is null.
+.It
+Pathname Expansion (unless set
+.Fl f
+is in effect).
+.It
+Quote Removal.
+.El
+.Pp
+The $ character is used to introduce parameter expansion, command
+substitution, or arithmetic evaluation.
+.Ss Tilde Expansion (substituting a user's home directory)
+A word beginning with an unquoted tilde character (~) is
+subjected to tilde expansion.
+All the characters up to
+a slash (/) or the end of the word are treated as a username
+and are replaced with the user's home directory.
+If the username is missing (as in
+.Pa ~/foobar ) ,
+the tilde is replaced with the value of the
+.Va HOME
+variable (the current user's home directory).
+.Ss Parameter Expansion
+The format for parameter expansion is as follows:
+.Pp
+.Dl ${expression}
+.Pp
+where expression consists of all characters until the matching
+.Dq } .
+Any
+.Dq }
+escaped by a backslash or within a quoted string, and characters in
+embedded arithmetic expansions, command substitutions, and variable
+expansions, are not examined in determining the matching
+.Dq } .
+.Pp
+The simplest form for parameter expansion is:
+.Pp
+.Dl ${parameter}
+.Pp
+The value, if any, of parameter is substituted.
+.Pp
+The parameter name or symbol can be enclosed in braces, which are
+optional except for positional parameters with more than one digit or
+when parameter is followed by a character that could be interpreted as
+part of the name.
+If a parameter expansion occurs inside double-quotes:
+.Bl -enum
+.It
+Pathname expansion is not performed on the results of the expansion.
+.It
+Field splitting is not performed on the results of the
+expansion, with the exception of @.
+.El
+.Pp
+In addition, a parameter expansion can be modified by using one of the
+following formats.
+.Bl -tag -width aaparameterwordaaaaa
+.It ${parameter:-word}
+Use Default Values.
+If parameter is unset or null, the expansion of word
+is substituted; otherwise, the value of parameter is substituted.
+.It ${parameter:=word}
+Assign Default Values.
+If parameter is unset or null, the expansion of
+word is assigned to parameter.
+In all cases, the final value of parameter is substituted.
+Only variables, not positional parameters or special
+parameters, can be assigned in this way.
+.It ${parameter:?[word]}
+Indicate Error if Null or Unset.
+If parameter is unset or null, the
+expansion of word (or a message indicating it is unset if word is omitted)
+is written to standard error and the shell exits with a nonzero exit status.
+Otherwise, the value of parameter is substituted.
+An interactive shell need not exit.
+.It ${parameter:+word}
+Use Alternative Value.
+If parameter is unset or null, null is
+substituted; otherwise, the expansion of word is substituted.
+.El
+.Pp
+In the parameter expansions shown previously, use of the colon in the
+format results in a test for a parameter that is unset or null; omission
+of the colon results in a test for a parameter that is only unset.
+.Bl -tag -width aaparameterwordaaaaa
+.It ${#parameter}
+String Length.
+The length in characters of the value of parameter.
+.El
+.Pp
+The following four varieties of parameter expansion provide for substring
+processing.
+In each case, pattern matching notation (see
+.Sx Shell Patterns ) ,
+rather than regular expression notation, is used to evaluate the patterns.
+If parameter is * or @, the result of the expansion is unspecified.
+Enclosing the full parameter expansion string in double-quotes does not
+cause the following four varieties of pattern characters to be quoted,
+whereas quoting characters within the braces has this effect.
+.Bl -tag -width aaparameterwordaaaaa
+.It ${parameter%word}
+Remove Smallest Suffix Pattern.
+The word is expanded to produce a pattern.
+The parameter expansion then results in parameter, with the
+smallest portion of the suffix matched by the pattern deleted.
+.It ${parameter%%word}
+Remove Largest Suffix Pattern.
+The word is expanded to produce a pattern.
+The parameter expansion then results in parameter, with the largest
+portion of the suffix matched by the pattern deleted.
+.It ${parameter#word}
+Remove Smallest Prefix Pattern.
+The word is expanded to produce a pattern.
+The parameter expansion then results in parameter, with the
+smallest portion of the prefix matched by the pattern deleted.
+.It ${parameter##word}
+Remove Largest Prefix Pattern.
+The word is expanded to produce a pattern.
+The parameter expansion then results in parameter, with the largest
+portion of the prefix matched by the pattern deleted.
+.El
+.Ss Command Substitution
+Command substitution allows the output of a command to be substituted in
+place of the command name itself.
+Command substitution occurs when the command is enclosed as follows:
+.Pp
+.Dl $(command)
+.Pp
+or
+.Po
+.Dq backquoted
+version
+.Pc :
+.Pp
+.Dl `command`
+.Pp
+The shell expands the command substitution by executing command in a
+subshell environment and replacing the command substitution with the
+standard output of the command, removing sequences of one or more
+.Ao newline Ac Ns s
+at the end of the substitution.
+(Embedded
+.Ao newline Ac Ns s
+before
+the end of the output are not removed; however, during field splitting,
+they may be translated into
+.Ao space Ac Ns s ,
+depending on the value of
+.Ev IFS
+and quoting that is in effect.)
+.Ss Arithmetic Expansion
+Arithmetic expansion provides a mechanism for evaluating an arithmetic
+expression and substituting its value.
+The format for arithmetic expansion is as follows:
+.Pp
+.Dl $((expression))
+.Pp
+The expression is treated as if it were in double-quotes, except
+that a double-quote inside the expression is not treated specially.
+The shell expands all tokens in the expression for parameter expansion,
+command substitution, and quote removal.
+.Pp
+Next, the shell treats this as an arithmetic expression and
+substitutes the value of the expression.
+.Ss White Space Splitting (Field Splitting)
+After parameter expansion, command substitution, and
+arithmetic expansion the shell scans the results of
+expansions and substitutions that did not occur in double-quotes for
+field splitting and multiple fields can result.
+.Pp
+The shell treats each character of the
+.Ev IFS
+as a delimiter and uses the delimiters to split the results of parameter
+expansion and command substitution into fields.
+.Ss Pathname Expansion (File Name Generation)
+Unless the
+.Fl f
+flag is set, file name generation is performed after word splitting is
+complete.
+Each word is viewed as a series of patterns, separated by slashes.
+The process of expansion replaces the word with the names of all
+existing files whose names can be formed by replacing each pattern with a
+string that matches the specified pattern.
+There are two restrictions on
+this: first, a pattern cannot match a string containing a slash, and
+second, a pattern cannot match a string starting with a period unless the
+first character of the pattern is a period.
+The next section describes the
+patterns used for both Pathname Expansion and the
+.Ic case
+command.
+.Ss Shell Patterns
+A pattern consists of normal characters, which match themselves,
+and meta-characters.
+The meta-characters are
+.Dq \&! ,
+.Dq * ,
+.Dq \&? ,
+and
+.Dq \&[ .
+These characters lose their special meanings if they are quoted.
+When command or variable substitution is performed
+and the dollar sign or back quotes are not double quoted,
+the value of the variable or the output of
+the command is scanned for these characters and they are turned into
+meta-characters.
+.Pp
+An asterisk
+.Pq Dq *
+matches any string of characters.
+A question mark matches any single character.
+A left bracket
+.Pq Dq \&[
+introduces a character class.
+The end of the character class is indicated by a
+.Pq Dq \&] ;
+if the
+.Dq \&]
+is missing then the
+.Dq \&[
+matches a
+.Dq \&[
+rather than introducing a character class.
+A character class matches any of the characters between the square brackets.
+A range of characters may be specified using a minus sign.
+The character class may be complemented
+by making an exclamation point the first character of the character class.
+.Pp
+To include a
+.Dq \&]
+in a character class, make it the first character listed (after the
+.Dq \&! ,
+if any).
+To include a minus sign, make it the first or last character listed.
+.Ss Builtins
+This section lists the builtin commands which are builtin because they
+need to perform some operation that can't be performed by a separate
+process.
+In addition to these, there are several other commands that may
+be builtin for efficiency (e.g.
+.Xr printf 1 ,
+.Xr echo 1 ,
+.Xr test 1 ,
+etc).
+.Bl -tag -width 5n
+.It :
+.It true
+A null command that returns a 0 (true) exit value.
+.It \&. file
+The commands in the specified file are read and executed by the shell.
+.It alias Op Ar name Ns Op Ar "=string ..."
+If
+.Ar name=string
+is specified, the shell defines the alias
+.Ar name
+with value
+.Ar string .
+If just
+.Ar name
+is specified, the value of the alias
+.Ar name
+is printed.
+With no arguments, the
+.Ic alias
+builtin prints the
+names and values of all defined aliases (see
+.Ic unalias ) .
+.It bg [ Ar job ] ...
+Continue the specified jobs (or the current job if no
+jobs are given) in the background.
+.It Xo command
+.Op Fl p
+.Op Fl v
+.Op Fl V
+.Ar command
+.Op Ar arg ...
+.Xc
+Execute the specified command but ignore shell functions when searching
+for it.
+(This is useful when you
+have a shell function with the same name as a builtin command.)
+.Bl -tag -width 5n
+.It Fl p
+search for command using a
+.Ev PATH
+that guarantees to find all the standard utilities.
+.It Fl V
+Do not execute the command but
+search for the command and print the resolution of the
+command search.
+This is the same as the type builtin.
+.It Fl v
+Do not execute the command but
+search for the command and print the absolute pathname
+of utilities, the name for builtins or the expansion of aliases.
+.El
+.It cd Ar -
+.It Xo cd Op Fl LP
+.Op Ar directory
+.Xc
+Switch to the specified directory (default
+.Ev HOME ) .
+If an entry for
+.Ev CDPATH
+appears in the environment of the
+.Ic cd
+command or the shell variable
+.Ev CDPATH
+is set and the directory name does not begin with a slash, then the
+directories listed in
+.Ev CDPATH
+will be searched for the specified directory.
+The format of
+.Ev CDPATH
+is the same as that of
+.Ev PATH .
+If a single dash is specified as the argument, it will be replaced by the
+value of
+.Ev OLDPWD .
+The
+.Ic cd
+command will print out the name of the
+directory that it actually switched to if this is different from the name
+that the user gave.
+These may be different either because the
+.Ev CDPATH
+mechanism was used or because the argument is a single dash.
+The
+.Fl P
+option causes the physical directory structure to be used, that is, all
+symbolic links are resolved to their respective values.  The
+.Fl L
+option turns off the effect of any preceding
+.Fl P
+options.
+.It Xo echo Op Fl n
+.Ar args...
+.Xc
+Print the arguments on the standard output, separated by spaces.
+Unless the
+.Fl n
+option is present, a newline is output following the arguments.
+.Pp
+If any of the following sequences of characters is encountered during
+output, the sequence is not output.  Instead, the specified action is
+performed:
+.Bl -tag -width indent
+.It Li \eb
+A backspace character is output.
+.It Li \ec
+Subsequent output is suppressed.  This is normally used at the end of the
+last argument to suppress the trailing newline that
+.Ic echo
+would otherwise output.
+.It Li \ef
+Output a form feed.
+.It Li \en
+Output a newline character.
+.It Li \er
+Output a carriage return.
+.It Li \et
+Output a (horizontal) tab character.
+.It Li \ev
+Output a vertical tab.
+.It Li \e0 Ns Ar digits
+Output the character whose value is given by zero to three octal digits.
+If there are zero digits, a nul character is output.
+.It Li \e\e
+Output a backslash.
+.El
+.Pp
+All other backslash sequences elicit undefined behaviour.
+.It eval Ar string ...
+Concatenate all the arguments with spaces.
+Then re-parse and execute the command.
+.It exec Op Ar command arg ...
+Unless command is omitted, the shell process is replaced with the
+specified program (which must be a real program, not a shell builtin or
+function).
+Any redirections on the
+.Ic exec
+command are marked as permanent, so that they are not undone when the
+.Ic exec
+command finishes.
+.It exit Op Ar exitstatus
+Terminate the shell process.
+If
+.Ar exitstatus
+is given it is used as the exit status of the shell; otherwise the
+exit status of the preceding command is used.
+.It export Ar name ...
+.It export Fl p
+The specified names are exported so that they will appear in the
+environment of subsequent commands.
+The only way to un-export a variable is to unset it.
+The shell allows the value of a variable to be set at the
+same time it is exported by writing
+.Pp
+.Dl export name=value
+.Pp
+With no arguments the export command lists the names of all exported variables.
+With the
+.Fl p
+option specified the output will be formatted suitably for non-interactive use.
+.It Xo fc Op Fl e Ar editor
+.Op Ar first Op Ar last
+.Xc
+.It Xo fc Fl l
+.Op Fl nr
+.Op Ar first Op Ar last
+.Xc
+.It Xo fc Fl s Op Ar old=new
+.Op Ar first
+.Xc
+The
+.Ic fc
+builtin lists, or edits and re-executes, commands previously entered
+to an interactive shell.
+.Bl -tag -width 5n
+.It Fl e No editor
+Use the editor named by editor to edit the commands.
+The editor string is a command name, subject to search via the
+.Ev PATH
+variable.
+The value in the
+.Ev FCEDIT
+variable is used as a default when
+.Fl e
+is not specified.
+If
+.Ev FCEDIT
+is null or unset, the value of the
+.Ev EDITOR
+variable is used.
+If
+.Ev EDITOR
+is null or unset,
+.Xr ed 1
+is used as the editor.
+.It Fl l No (ell)
+List the commands rather than invoking an editor on them.
+The commands are written in the sequence indicated by
+the first and last operands, as affected by
+.Fl r ,
+with each command preceded by the command number.
+.It Fl n
+Suppress command numbers when listing with -l.
+.It Fl r
+Reverse the order of the commands listed (with
+.Fl l )
+or edited (with neither
+.Fl l
+nor
+.Fl s ) .
+.It Fl s
+Re-execute the command without invoking an editor.
+.It first
+.It last
+Select the commands to list or edit.
+The number of previous commands that
+can be accessed are determined by the value of the
+.Ev HISTSIZE
+variable.
+The value of first or last or both are one of the following:
+.Bl -tag -width 5n
+.It [+]number
+A positive number representing a command number; command numbers can be
+displayed with the
+.Fl l
+option.
+.It Fl number
+A negative decimal number representing the command that was executed
+number of commands previously.
+For example, \-1 is the immediately previous command.
+.El
+.It string
+A string indicating the most recently entered command that begins with
+that string.
+If the old=new operand is not also specified with
+.Fl s ,
+the string form of the first operand cannot contain an embedded equal sign.
+.El
+.Pp
+The following environment variables affect the execution of fc:
+.Bl -tag -width HISTSIZE
+.It Ev FCEDIT
+Name of the editor to use.
+.It Ev HISTSIZE
+The number of previous commands that are accessible.
+.El
+.It fg Op Ar job
+Move the specified job or the current job to the foreground.
+.It getopts Ar optstring var
+The
+.Tn POSIX
+.Ic getopts
+command, not to be confused with the
+.Em Bell Labs
+-derived
+.Xr getopt 1 .
+.Pp
+The first argument should be a series of letters, each of which may be
+optionally followed by a colon to indicate that the option requires an
+argument.
+The variable specified is set to the parsed option.
+.Pp
+The
+.Ic getopts
+command deprecates the older
+.Xr getopt 1
+utility due to its handling of arguments containing whitespace.
+.Pp
+The
+.Ic getopts
+builtin may be used to obtain options and their arguments
+from a list of parameters.
+When invoked,
+.Ic getopts
+places the value of the next option from the option string in the list in
+the shell variable specified by
+.Va var
+and its index in the shell variable
+.Ev OPTIND .
+When the shell is invoked,
+.Ev OPTIND
+is initialized to 1.
+For each option that requires an argument, the
+.Ic getopts
+builtin will place it in the shell variable
+.Ev OPTARG .
+If an option is not allowed for in the
+.Va optstring ,
+then
+.Ev OPTARG
+will be unset.
+.Pp
+.Va optstring
+is a string of recognized option letters (see
+.Xr getopt 3 ) .
+If a letter is followed by a colon, the option is expected to have an
+argument which may or may not be separated from it by white space.
+If an option character is not found where expected,
+.Ic getopts
+will set the variable
+.Va var
+to a
+.Dq \&? ;
+.Ic getopts
+will then unset
+.Ev OPTARG
+and write output to standard error.
+By specifying a colon as the first character of
+.Va optstring
+all errors will be ignored.
+.Pp
+A nonzero value is returned when the last option is reached.
+If there are no remaining arguments,
+.Ic getopts
+will set
+.Va var
+to the special option,
+.Dq -- ,
+otherwise, it will set
+.Va var
+to
+.Dq \&? .
+.Pp
+The following code fragment shows how one might process the arguments
+for a command that can take the options
+.Op a
+and
+.Op b ,
+and the option
+.Op c ,
+which requires an argument.
+.Pp
+.Bd -literal -offset indent
+while getopts abc: f
+do
+	case $f in
+	a | b)	flag=$f;;
+	c)	carg=$OPTARG;;
+	\\?)	echo $USAGE; exit 1;;
+	esac
+done
+shift `expr $OPTIND - 1`
+.Ed
+.Pp
+This code will accept any of the following as equivalent:
+.Pp
+.Bd -literal -offset indent
+cmd \-acarg file file
+cmd \-a \-c arg file file
+cmd \-carg -a file file
+cmd \-a \-carg \-\- file file
+.Ed
+.It hash Fl rv Ar command ...
+The shell maintains a hash table which remembers the
+locations of commands.
+With no arguments whatsoever,
+the
+.Ic hash
+command prints out the contents of this table.
+Entries which have not been looked at since the last
+.Ic cd
+command are marked with an asterisk; it is possible for these entries
+to be invalid.
+.Pp
+With arguments, the
+.Ic hash
+command removes the specified commands from the hash table (unless
+they are functions) and then locates them.
+With the
+.Fl v
+option, hash prints the locations of the commands as it finds them.
+The
+.Fl r
+option causes the hash command to delete all the entries in the hash table
+except for functions.
+.It pwd Op Fl LP
+builtin command remembers what the current directory
+is rather than recomputing it each time.
+This makes it faster.
+However, if the current directory is renamed, the builtin version of
+.Ic pwd
+will continue to print the old name for the directory.
+The
+.Fl P
+option causes the physical value of the current working directory to be shown,
+that is, all symbolic links are resolved to their respective values.  The
+.Fl L
+option turns off the effect of any preceding
+.Fl P
+options.
+.It Xo read Op Fl p Ar prompt
+.Op Fl r
+.Ar variable
+.Op Ar ...
+.Xc
+The prompt is printed if the
+.Fl p
+option is specified and the standard input is a terminal.
+Then a line is read from the standard input.
+The trailing newline is deleted from the
+line and the line is split as described in the section on word splitting
+above, and the pieces are assigned to the variables in order.
+At least one variable must be specified.
+If there are more pieces than variables, the remaining pieces
+(along with the characters in
+.Ev IFS
+that separated them) are assigned to the last variable.
+If there are more variables than pieces,
+the remaining variables are assigned the null string.
+The
+.Ic read
+builtin will indicate success unless EOF is encountered on input, in
+which case failure is returned.
+.Pp
+By default, unless the
+.Fl r
+option is specified, the backslash
+.Dq \e
+acts as an escape character, causing the following character to be treated
+literally.
+If a backslash is followed by a newline, the backslash and the
+newline will be deleted.
+.It readonly Ar name ...
+.It readonly Fl p
+The specified names are marked as read only, so that they cannot be
+subsequently modified or unset.
+The shell allows the value of a variable
+to be set at the same time it is marked read only by writing
+.Pp
+.Dl readonly name=value
+.Pp
+With no arguments the readonly command lists the names of all read only
+variables.
+With the
+.Fl p
+option specified the output will be formatted suitably for non-interactive use.
+.Pp
+.It Xo printf Ar format
+.Op Ar arguments  ...
+.Xc
+.Ic printf
+formats and prints its arguments, after the first, under control
+of the
+.Ar format  .
+The
+.Ar format
+is a character string which contains three types of objects: plain characters,
+which are simply copied to standard output, character escape sequences which
+are converted and copied to the standard output, and format specifications,
+each of which causes printing of the next successive
+.Ar argument  .
+.Pp
+The
+.Ar arguments
+after the first are treated as strings if the corresponding format is
+either
+.Cm b ,
+.Cm c
+or
+.Cm s ;
+otherwise it is evaluated as a C constant, with the following extensions:
+.Pp
+.Bl -bullet -offset indent -compact
+.It
+A leading plus or minus sign is allowed.
+.It
+If the leading character is a single or double quote, the value is the
+.Tn ASCII
+code of the next character.
+.El
+.Pp
+The format string is reused as often as necessary to satisfy the
+.Ar arguments  .
+Any extra format specifications are evaluated with zero or the null
+string.
+.Pp
+Character escape sequences are in backslash notation as defined in
+.St -ansiC .
+The characters and their meanings are as follows:
+.Bl -tag -width Ds -offset indent
+.It Cm \ea
+Write a \*[Lt]bell\*[Gt] character.
+.It Cm \eb
+Write a \*[Lt]backspace\*[Gt] character.
+.It Cm \ef
+Write a \*[Lt]form-feed\*[Gt] character.
+.It Cm \en
+Write a \*[Lt]new-line\*[Gt] character.
+.It Cm \er
+Write a \*[Lt]carriage return\*[Gt] character.
+.It Cm \et
+Write a \*[Lt]tab\*[Gt] character.
+.It Cm \ev
+Write a \*[Lt]vertical tab\*[Gt] character.
+.It Cm \e\e
+Write a backslash character.
+.It Cm \e Ns Ar num
+Write an 8\-bit character whose
+.Tn ASCII
+value is the 1\-, 2\-, or 3\-digit
+octal number
+.Ar num .
+.El
+.Pp
+Each format specification is introduced by the percent character
+(``%'').
+The remainder of the format specification includes,
+in the following order:
+.Bl -tag -width Ds
+.It "Zero or more of the following flags:"
+.Bl -tag -width Ds
+.It Cm #
+A `#' character
+specifying that the value should be printed in an ``alternative form''.
+For
+.Cm b ,
+.Cm c ,
+.Cm d ,
+and
+.Cm s
+formats, this option has no effect.
+For the
+.Cm o
+format the precision of the number is increased to force the first
+character of the output string to a zero.
+For the
+.Cm x
+.Pq Cm X
+format, a non-zero result has the string
+.Li 0x
+.Pq Li 0X
+prepended to it.
+For
+.Cm e  ,
+.Cm E ,
+.Cm f  ,
+.Cm g ,
+and
+.Cm G
+formats, the result will always contain a decimal point, even if no
+digits follow the point (normally, a decimal point only appears in the
+results of those formats if a digit follows the decimal point).
+For
+.Cm g
+and
+.Cm G
+formats, trailing zeros are not removed from the result as they
+would otherwise be.
+.It Cm \&\-
+A minus sign `\-' which specifies
+.Em left adjustment
+of the output in the indicated field;
+.It Cm \&+
+A `+' character specifying that there should always be
+a sign placed before the number when using signed formats.
+.It Sq \&\ \&
+A space specifying that a blank should be left before a positive number
+for a signed format.
+A `+' overrides a space if both are used;
+.It Cm \&0
+A zero `0' character indicating that zero-padding should be used
+rather than blank-padding.
+A `\-' overrides a `0' if both are used;
+.El
+.It "Field Width:"
+An optional digit string specifying a
+.Em field width ;
+if the output string has fewer characters than the field width it will
+be blank-padded on the left (or right, if the left-adjustment indicator
+has been given) to make up the field width (note that a leading zero
+is a flag, but an embedded zero is part of a field width);
+.It Precision :
+An optional period,
+.Sq Cm \&.\& ,
+followed by an optional digit string giving a
+.Em precision
+which specifies the number of digits to appear after the decimal point,
+for
+.Cm e
+and
+.Cm f
+formats, or the maximum number of characters to be printed
+from a string
+.Sm off
+.Pf ( Cm b
+.Sm on
+and
+.Cm s
+formats); if the digit string is missing, the precision is treated
+as zero;
+.It Format :
+A character which indicates the type of format to use (one of
+.Cm diouxXfwEgGbcs ) .
+.El
+.Pp
+A field width or precision may be
+.Sq Cm \&*
+instead of a digit string.
+In this case an
+.Ar argument
+supplies the field width or precision.
+.Pp
+The format characters and their meanings are:
+.Bl -tag -width Fl
+.It Cm diouXx
+The
+.Ar argument
+is printed as a signed decimal (d or i), unsigned octal, unsigned decimal,
+or unsigned hexadecimal (X or x), respectively.
+.It Cm f
+The
+.Ar argument
+is printed in the style
+.Sm off
+.Pf [\-]ddd Cm \&. No ddd
+.Sm on
+where the number of d's
+after the decimal point is equal to the precision specification for
+the argument.
+If the precision is missing, 6 digits are given; if the precision
+is explicitly 0, no digits and no decimal point are printed.
+.It Cm eE
+The
+.Ar argument
+is printed in the style
+.Sm off
+.Pf [\-]d Cm \&. No ddd Cm e No \\*(Pmdd
+.Sm on
+where there
+is one digit before the decimal point and the number after is equal to
+the precision specification for the argument; when the precision is
+missing, 6 digits are produced.
+An upper-case E is used for an `E' format.
+.It Cm gG
+The
+.Ar argument
+is printed in style
+.Cm f
+or in style
+.Cm e
+.Pq Cm E
+whichever gives full precision in minimum space.
+.It Cm b
+Characters from the string
+.Ar argument
+are printed with backslash-escape sequences expanded.
+.br
+The following additional backslash-escape sequences are supported:
+.Bl -tag -width Ds
+.It Cm \ec
+Causes
+.Nm
+to ignore any remaining characters in the string operand containing it,
+any remaining string operands, and any additional characters in
+the format operand.
+.It Cm \e0 Ns Ar num
+Write an 8\-bit character whose
+.Tn ASCII
+value is the 1\-, 2\-, or 3\-digit
+octal number
+.Ar num .
+.El
+.It Cm c
+The first character of
+.Ar argument
+is printed.
+.It Cm s
+Characters from the string
+.Ar argument
+are printed until the end is reached or until the number of characters
+indicated by the precision specification is reached; if the
+precision is omitted, all characters in the string are printed.
+.It Cm \&%
+Print a `%'; no argument is used.
+.El
+.Pp
+In no case does a non-existent or small field width cause truncation of
+a field; padding takes place only if the specified field width exceeds
+the actual width.
+.It Xo set
+.Oo {
+.Fl options | Cm +options | Cm -- }
+.Oc Ar arg ...
+.Xc
+The
+.Ic set
+command performs three different functions.
+.Pp
+With no arguments, it lists the values of all shell variables.
+.Pp
+If options are given, it sets the specified option
+flags, or clears them as described in the section called
+.Sx Argument List Processing .
+.Pp
+The third use of the set command is to set the values of the shell's
+positional parameters to the specified args.
+To change the positional
+parameters without changing any options, use
+.Dq --
+as the first argument to set.
+If no args are present, the set command
+will clear all the positional parameters (equivalent to executing
+.Dq shift $# . )
+.It shift Op Ar n
+Shift the positional parameters n times.
+A
+.Ic shift
+sets the value of
+.Va $1
+to the value of
+.Va $2 ,
+the value of
+.Va $2
+to the value of
+.Va $3 ,
+and so on, decreasing
+the value of
+.Va $#
+by one.
+If n is greater than the number of positional parameters,
+.Ic shift
+will issue an error message, and exit with return status 2.
+.It test Ar expression
+.It \&[ Ar expression Cm ]
+The
+.Ic test
+utility evaluates the expression and, if it evaluates
+to true, returns a zero (true) exit status; otherwise
+it returns 1 (false).
+If there is no expression, test also
+returns 1 (false).
+.Pp
+All operators and flags are separate arguments to the
+.Ic test
+utility.
+.Pp
+The following primaries are used to construct expression:
+.Bl -tag -width Ar
+.It Fl b Ar file
+True if
+.Ar file
+exists and is a block special
+file.
+.It Fl c Ar file
+True if
+.Ar file
+exists and is a character
+special file.
+.It Fl d Ar file
+True if
+.Ar file
+exists and is a directory.
+.It Fl e Ar file
+True if
+.Ar file
+exists (regardless of type).
+.It Fl f Ar file
+True if
+.Ar file
+exists and is a regular file.
+.It Fl g Ar file
+True if
+.Ar file
+exists and its set group ID flag
+is set.
+.It Fl h Ar file
+True if
+.Ar file
+exists and is a symbolic link.
+.It Fl k Ar file
+True if
+.Ar file
+exists and its sticky bit is set.
+.It Fl n Ar string
+True if the length of
+.Ar string
+is nonzero.
+.It Fl p Ar file
+True if
+.Ar file
+is a named pipe
+.Po Tn FIFO Pc .
+.It Fl r Ar file
+True if
+.Ar file
+exists and is readable.
+.It Fl s Ar file
+True if
+.Ar file
+exists and has a size greater
+than zero.
+.It Fl t Ar file_descriptor
+True if the file whose file descriptor number
+is
+.Ar file_descriptor
+is open and is associated with a terminal.
+.It Fl u Ar file
+True if
+.Ar file
+exists and its set user ID flag
+is set.
+.It Fl w Ar file
+True if
+.Ar file
+exists and is writable.
+True
+indicates only that the write flag is on.
+The file is not writable on a read-only file
+system even if this test indicates true.
+.It Fl x Ar file
+True if
+.Ar file
+exists and is executable.
+True
+indicates only that the execute flag is on.
+If
+.Ar file
+is a directory, true indicates that
+.Ar file
+can be searched.
+.It Fl z Ar string
+True if the length of
+.Ar string
+is zero.
+.It Fl L Ar file
+True if
+.Ar file
+exists and is a symbolic link.
+This operator is retained for compatibility with previous versions of
+this program.
+Do not rely on its existence; use
+.Fl h
+instead.
+.It Fl O Ar file
+True if
+.Ar file
+exists and its owner matches the effective user id of this process.
+.It Fl G Ar file
+True if
+.Ar file
+exists and its group matches the effective group id of this process.
+.It Fl S Ar file
+True if
+.Ar file
+exists and is a socket.
+.It Ar file1 Fl nt Ar file2
+True if
+.Ar file1
+exists and is newer than
+.Ar file2 .
+.It Ar file1 Fl ot Ar file2
+True if
+.Ar file1
+exists and is older than
+.Ar file2 .
+.It Ar file1 Fl ef Ar file2
+True if
+.Ar file1
+and
+.Ar file2
+exist and refer to the same file.
+.It Ar string
+True if
+.Ar string
+is not the null
+string.
+.It Ar \&s\&1 Cm \&= Ar \&s\&2
+True if the strings
+.Ar \&s\&1
+and
+.Ar \&s\&2
+are identical.
+.It Ar \&s\&1 Cm \&!= Ar \&s\&2
+True if the strings
+.Ar \&s\&1
+and
+.Ar \&s\&2
+are not identical.
+.It Ar \&s\&1 Cm \&\*[Lt] Ar \&s\&2
+True if string
+.Ar \&s\&1
+comes before
+.Ar \&s\&2
+based on the ASCII value of their characters.
+.It Ar \&s\&1 Cm \&\*[Gt] Ar \&s\&2
+True if string
+.Ar \&s\&1
+comes after
+.Ar \&s\&2
+based on the ASCII value of their characters.
+.It Ar \&n\&1 Fl \&eq Ar \&n\&2
+True if the integers
+.Ar \&n\&1
+and
+.Ar \&n\&2
+are algebraically
+equal.
+.It Ar \&n\&1 Fl \&ne Ar \&n\&2
+True if the integers
+.Ar \&n\&1
+and
+.Ar \&n\&2
+are not
+algebraically equal.
+.It Ar \&n\&1 Fl \&gt Ar \&n\&2
+True if the integer
+.Ar \&n\&1
+is algebraically
+greater than the integer
+.Ar \&n\&2 .
+.It Ar \&n\&1 Fl \&ge Ar \&n\&2
+True if the integer
+.Ar \&n\&1
+is algebraically
+greater than or equal to the integer
+.Ar \&n\&2 .
+.It Ar \&n\&1 Fl \&lt Ar \&n\&2
+True if the integer
+.Ar \&n\&1
+is algebraically less
+than the integer
+.Ar \&n\&2 .
+.It Ar \&n\&1 Fl \&le Ar \&n\&2
+True if the integer
+.Ar \&n\&1
+is algebraically less
+than or equal to the integer
+.Ar \&n\&2 .
+.El
+.Pp
+These primaries can be combined with the following operators:
+.Bl -tag -width Ar
+.It Cm \&! Ar expression
+True if
+.Ar expression
+is false.
+.It Ar expression1 Fl a Ar expression2
+True if both
+.Ar expression1
+and
+.Ar expression2
+are true.
+.It Ar expression1 Fl o Ar expression2
+True if either
+.Ar expression1
+or
+.Ar expression2
+are true.
+.It Cm \&( Ns Ar expression Ns Cm \&)
+True if expression is true.
+.El
+.Pp
+The
+.Fl a
+operator has higher precedence than the
+.Fl o
+operator.
+.It times
+Print the accumulated user and system times for the shell and for processes
+run from the shell.  The return status is 0.
+.It Xo trap
+.Op Ar action Ar signal ...
+.Xc
+Cause the shell to parse and execute action when any of the specified
+signals are received.
+The signals are specified by signal number or as the name of the signal.
+If
+.Ar signal
+is
+.Li 0 ,
+the action is executed when the shell exits.
+.Ar action
+may be null, which cause the specified signals to be ignored.
+With
+.Ar action
+omitted or set to `-' the specified signals are set to their default action.
+When the shell forks off a subshell, it resets trapped (but not ignored)
+signals to the default action.
+The
+.Ic trap
+command has no effect on signals that were
+ignored on entry to the shell.
+.Ic trap
+without any arguments cause it to write a list of signals and their
+associated action to the standard output in a format that is suitable
+as an input to the shell that achieves the same trapping results.
+.Pp
+Examples:
+.Pp
+.Dl trap
+.Pp
+List trapped signals and their corresponding action
+.Pp
+.Dl trap '' INT QUIT tstp 30
+.Pp
+Ignore signals INT QUIT TSTP USR1
+.Pp
+.Dl trap date INT
+.Pp
+Print date upon receiving signal INT
+.It type Op Ar name ...
+Interpret each name as a command and print the resolution of the command
+search.
+Possible resolutions are:
+shell keyword, alias, shell builtin,
+command, tracked alias and not found.
+For aliases the alias expansion is
+printed; for commands and tracked aliases the complete pathname of the
+command is printed.
+.It ulimit Xo
+.Op Fl H \*(Ba Fl S
+.Op Fl a \*(Ba Fl tfdscmlpn Op Ar value
+.Xc
+Inquire about or set the hard or soft limits on processes or set new
+limits.
+The choice between hard limit (which no process is allowed to
+violate, and which may not be raised once it has been lowered) and soft
+limit (which causes processes to be signaled but not necessarily killed,
+and which may be raised) is made with these flags:
+.Bl -tag -width Fl
+.It Fl H
+set or inquire about hard limits
+.It Fl S
+set or inquire about soft limits.
+If neither
+.Fl H
+nor
+.Fl S
+is specified, the soft limit is displayed or both limits are set.
+If both are specified, the last one wins.
+.El
+.Pp
+.Bl -tag -width Fl
+The limit to be interrogated or set, then, is chosen by specifying
+any one of these flags:
+.It Fl a
+show all the current limits
+.It Fl t
+show or set the limit on CPU time (in seconds)
+.It Fl f
+show or set the limit on the largest file that can be created
+(in 512-byte blocks)
+.It Fl d
+show or set the limit on the data segment size of a process (in kilobytes)
+.It Fl s
+show or set the limit on the stack size of a process (in kilobytes)
+.It Fl c
+show or set the limit on the largest core dump size that can be produced
+(in 512-byte blocks)
+.It Fl m
+show or set the limit on the total physical memory that can be
+in use by a process (in kilobytes)
+.It Fl l
+show or set the limit on how much memory a process can lock with
+.Xr mlock 2
+(in kilobytes)
+.It Fl p
+show or set the limit on the number of processes this user can
+have at one time
+.It Fl n
+show or set the limit on the number files a process can have open at once
+.El
+.Pp
+If none of these is specified, it is the limit on file size that is shown
+or set.
+If value is specified, the limit is set to that number; otherwise
+the current limit is displayed.
+.Pp
+Limits of an arbitrary process can be displayed or set using the
+.Xr sysctl 8
+utility.
+.Pp
+.It umask Op Ar mask
+Set the value of umask (see
+.Xr umask 2 )
+to the specified octal value.
+If the argument is omitted, the umask value is printed.
+.It unalias Xo
+.Op Fl a
+.Op Ar name
+.Xc
+If
+.Ar name
+is specified, the shell removes that alias.
+If
+.Fl a
+is specified, all aliases are removed.
+.It unset Xo
+.Op Fl fv
+.Ar name ...
+.Xc
+The specified variables and functions are unset and unexported.
+If
+.Fl f
+or
+.Fl v
+is specified, the corresponding function or variable is unset, respectively.
+If a given name corresponds to both a variable and a function, and no
+options are given, only the variable is unset.
+.It wait Op Ar job
+Wait for the specified job to complete and return the exit status of the
+last process in the job.
+If the argument is omitted, wait for all jobs to
+complete and the return an exit status of zero.
+.El
+.Ss Command Line Editing
+When
+.Nm
+is being used interactively from a terminal, the current command
+and the command history (see
+.Ic fc
+in
+.Sx Builtins )
+can be edited using vi-mode command-line editing.
+This mode uses commands, described below,
+similar to a subset of those described in the vi man page.
+The command
+.Ql set -o vi
+enables vi-mode editing and place sh into vi insert mode.
+With vi-mode
+enabled, sh can be switched between insert mode and command mode.
+The editor is not described in full here, but will be in a later document.
+It's similar to vi: typing
+.Aq ESC
+will throw you into command VI command mode.
+Hitting
+.Aq return
+while in command mode will pass the line to the shell.
+.Sh EXIT STATUS
+Errors that are detected by the shell, such as a syntax error, will cause the
+shell to exit with a non-zero exit status.
+If the shell is not an
+interactive shell, the execution of the shell file will be aborted.
+Otherwise
+the shell will return the exit status of the last command executed, or
+if the exit builtin is used with a numeric argument, it will return the
+argument.
+.Sh ENVIRONMENT
+.Bl -tag -width MAILCHECK
+.It Ev HOME
+Set automatically by
+.Xr login 1
+from the user's login directory in the password file
+.Pq Xr passwd 4 .
+This environment variable also functions as the default argument for the
+cd builtin.
+.It Ev PATH
+The default search path for executables.
+See the above section
+.Sx Path Search .
+.It Ev CDPATH
+The search path used with the cd builtin.
+.It Ev MAIL
+The name of a mail file, that will be checked for the arrival of new mail.
+Overridden by
+.Ev MAILPATH .
+.It Ev MAILCHECK
+The frequency in seconds that the shell checks for the arrival of mail
+in the files specified by the
+.Ev MAILPATH
+or the
+.Ev MAIL
+file.
+If set to 0, the check will occur at each prompt.
+.It Ev MAILPATH
+A colon
+.Dq \&:
+separated list of file names, for the shell to check for incoming mail.
+This environment setting overrides the
+.Ev MAIL
+setting.
+There is a maximum of 10 mailboxes that can be monitored at once.
+.It Ev PS1
+The primary prompt string, which defaults to
+.Dq $ \  ,
+unless you are the superuser, in which case it defaults to
+.Dq # \  .
+.It Ev PS2
+The secondary prompt string, which defaults to
+.Dq \*[Gt] \  .
+.It Ev PS4
+Output before each line when execution trace (set -x) is enabled,
+defaults to
+.Dq + \  .
+.It Ev IFS
+Input Field Separators.
+This is normally set to
+.Aq space ,
+.Aq tab ,
+and
+.Aq newline .
+See the
+.Sx White Space Splitting
+section for more details.
+.It Ev TERM
+The default terminal setting for the shell.
+This is inherited by
+children of the shell, and is used in the history editing modes.
+.It Ev HISTSIZE
+The number of lines in the history buffer for the shell.
+.It Ev PWD
+The logical value of the current working directory.  This is set by the
+.Ic cd
+command.
+.It Ev OLDPWD
+The previous logical value of the current working directory.  This is set by
+the
+.Ic cd
+command.
+.It Ev PPID
+The process ID of the parent process of the shell.
+.El
+.Sh FILES
+.Bl -item -width HOMEprofilexxxx
+.It
+.Pa $HOME/.profile
+.It
+.Pa /etc/profile
+.El
+.Sh SEE ALSO
+.Xr csh 1 ,
+.Xr echo 1 ,
+.Xr getopt 1 ,
+.Xr ksh 1 ,
+.Xr login 1 ,
+.Xr printf 1 ,
+.Xr test 1 ,
+.Xr getopt 3 ,
+.Xr passwd 5 ,
+.\" .Xr profile 4 ,
+.Xr environ 7 ,
+.Xr sysctl 8
+.Sh HISTORY
+A
+.Nm
+command appeared in
+.At v1 .
+It was, however, unmaintainable so we wrote this one.
+.Sh BUGS
+Setuid shell scripts should be avoided at all costs, as they are a
+significant security risk.
+.Pp
+PS1, PS2, and PS4 should be subject to parameter expansion before
+being displayed.
diff --git a/usr/dash/shell.h b/usr/dash/shell.h
new file mode 100644
index 0000000..9b67696
--- /dev/null
+++ b/usr/dash/shell.h
@@ -0,0 +1,94 @@
+/*-
+ * Copyright (c) 1991, 1993
+ *	The Regents of the University of California.  All rights reserved.
+ * Copyright (c) 1997-2005
+ *	Herbert Xu <herbert@gondor.apana.org.au>.  All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Kenneth Almquist.
+ *
+ * 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. 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.
+ *
+ *	@(#)shell.h	8.2 (Berkeley) 5/4/95
+ */
+
+/*
+ * The follow should be set to reflect the type of system you have:
+ *	JOBS -> 1 if you have Berkeley job control, 0 otherwise.
+ *	SHORTNAMES -> 1 if your linker cannot handle long names.
+ *	define BSD if you are running 4.2 BSD or later.
+ *	define SYSV if you are running under System V.
+ *	define DEBUG=1 to compile in debugging ('set -o debug' to turn on)
+ *	define DEBUG=2 to compile in and turn on debugging.
+ *	define DO_SHAREDVFORK to indicate that vfork(2) shares its address
+ *	       with its parent.
+ *
+ * When debugging is on, debugging info will be written to ./trace and
+ * a quit signal will generate a core dump.
+ */
+
+#include <sys/param.h>
+
+#ifndef JOBS
+#define JOBS 1
+#endif
+#ifndef BSD
+#define BSD 1
+#endif
+
+#ifndef DO_SHAREDVFORK
+#if __NetBSD_Version__ >= 104000000
+#define DO_SHAREDVFORK
+#endif
+#endif
+
+typedef void *pointer;
+#ifndef NULL
+#define NULL (void *)0
+#endif
+#define STATIC static
+#define MKINIT	/* empty */
+
+extern char nullstr[1];		/* null string */
+
+
+#ifdef DEBUG
+#define TRACE(param)	trace param
+#define TRACEV(param)	tracev param
+#else
+#define TRACE(param)
+#define TRACEV(param)
+#endif
+
+#if defined(__GNUC__) && __GNUC__ < 3
+#define va_copy __va_copy
+#endif
+
+#if !defined(__GNUC__) || (__GNUC__ == 2 && __GNUC_MINOR__ < 96)
+#define __builtin_expect(x, expected_value) (x)
+#endif
+
+#define likely(x)	__builtin_expect(!!(x),1)
+#define unlikely(x)	__builtin_expect(!!(x),0)
diff --git a/usr/dash/show.c b/usr/dash/show.c
new file mode 100644
index 0000000..1b58de1
--- /dev/null
+++ b/usr/dash/show.c
@@ -0,0 +1,403 @@
+/*-
+ * Copyright (c) 1991, 1993
+ *	The Regents of the University of California.  All rights reserved.
+ * Copyright (c) 1997-2005
+ *	Herbert Xu <herbert@gondor.apana.org.au>.  All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Kenneth Almquist.
+ *
+ * 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. 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 <stdio.h>
+#include <stdarg.h>
+
+#include "shell.h"
+#include "parser.h"
+#include "nodes.h"
+#include "mystring.h"
+#include "show.h"
+#include "options.h"
+
+
+#ifdef DEBUG
+static void shtree(union node *, int, char *, FILE*);
+static void shcmd(union node *, FILE *);
+static void sharg(union node *, FILE *);
+static void indent(int, char *, FILE *);
+static void trstring(char *);
+
+
+void
+showtree(union node *n)
+{
+	trputs("showtree called\n");
+	shtree(n, 1, NULL, stdout);
+}
+
+
+static void
+shtree(union node *n, int ind, char *pfx, FILE *fp)
+{
+	struct nodelist *lp;
+	const char *s;
+
+	if (n == NULL)
+		return;
+
+	indent(ind, pfx, fp);
+	switch(n->type) {
+	case NSEMI:
+		s = "; ";
+		goto binop;
+	case NAND:
+		s = " && ";
+		goto binop;
+	case NOR:
+		s = " || ";
+binop:
+		shtree(n->nbinary.ch1, ind, NULL, fp);
+	   /*    if (ind < 0) */
+			fputs(s, fp);
+		shtree(n->nbinary.ch2, ind, NULL, fp);
+		break;
+	case NCMD:
+		shcmd(n, fp);
+		if (ind >= 0)
+			putc('\n', fp);
+		break;
+	case NPIPE:
+		for (lp = n->npipe.cmdlist ; lp ; lp = lp->next) {
+			shcmd(lp->n, fp);
+			if (lp->next)
+				fputs(" | ", fp);
+		}
+		if (n->npipe.backgnd)
+			fputs(" &", fp);
+		if (ind >= 0)
+			putc('\n', fp);
+		break;
+	default:
+		fprintf(fp, "<node type %d>", n->type);
+		if (ind >= 0)
+			putc('\n', fp);
+		break;
+	}
+}
+
+
+
+static void
+shcmd(union node *cmd, FILE *fp)
+{
+	union node *np;
+	int first;
+	const char *s;
+	int dftfd;
+
+	first = 1;
+	for (np = cmd->ncmd.args ; np ; np = np->narg.next) {
+		if (! first)
+			putchar(' ');
+		sharg(np, fp);
+		first = 0;
+	}
+	for (np = cmd->ncmd.redirect ; np ; np = np->nfile.next) {
+		if (! first)
+			putchar(' ');
+		switch (np->nfile.type) {
+			case NTO:	s = ">";  dftfd = 1; break;
+			case NCLOBBER:	s = ">|"; dftfd = 1; break;
+			case NAPPEND:	s = ">>"; dftfd = 1; break;
+			case NTOFD:	s = ">&"; dftfd = 1; break;
+			case NFROM:	s = "<";  dftfd = 0; break;
+			case NFROMFD:	s = "<&"; dftfd = 0; break;
+			case NFROMTO:	s = "<>"; dftfd = 0; break;
+			default:  	s = "*error*"; dftfd = 0; break;
+		}
+		if (np->nfile.fd != dftfd)
+			fprintf(fp, "%d", np->nfile.fd);
+		fputs(s, fp);
+		if (np->nfile.type == NTOFD || np->nfile.type == NFROMFD) {
+			fprintf(fp, "%d", np->ndup.dupfd);
+		} else {
+			sharg(np->nfile.fname, fp);
+		}
+		first = 0;
+	}
+}
+
+
+
+static void
+sharg(union node *arg, FILE *fp)
+{
+	char *p;
+	struct nodelist *bqlist;
+	int subtype;
+
+	if (arg->type != NARG) {
+		printf("<node type %d>\n", arg->type);
+		abort();
+	}
+	bqlist = arg->narg.backquote;
+	for (p = arg->narg.text ; *p ; p++) {
+		switch ((signed char)*p) {
+		case CTLESC:
+			putc(*++p, fp);
+			break;
+		case CTLVAR:
+			putc('$', fp);
+			putc('{', fp);
+			subtype = *++p;
+			if (subtype == VSLENGTH)
+				putc('#', fp);
+
+			while (*p != '=')
+				putc(*p++, fp);
+
+			if (subtype & VSNUL)
+				putc(':', fp);
+
+			switch (subtype & VSTYPE) {
+			case VSNORMAL:
+				putc('}', fp);
+				break;
+			case VSMINUS:
+				putc('-', fp);
+				break;
+			case VSPLUS:
+				putc('+', fp);
+				break;
+			case VSQUESTION:
+				putc('?', fp);
+				break;
+			case VSASSIGN:
+				putc('=', fp);
+				break;
+			case VSTRIMLEFT:
+				putc('#', fp);
+				break;
+			case VSTRIMLEFTMAX:
+				putc('#', fp);
+				putc('#', fp);
+				break;
+			case VSTRIMRIGHT:
+				putc('%', fp);
+				break;
+			case VSTRIMRIGHTMAX:
+				putc('%', fp);
+				putc('%', fp);
+				break;
+			case VSLENGTH:
+				break;
+			default:
+				printf("<subtype %d>", subtype);
+			}
+			break;
+		case CTLENDVAR:
+		     putc('}', fp);
+		     break;
+		case CTLBACKQ:
+		case CTLBACKQ|CTLQUOTE:
+			putc('$', fp);
+			putc('(', fp);
+			shtree(bqlist->n, -1, NULL, fp);
+			putc(')', fp);
+			break;
+		default:
+			putc(*p, fp);
+			break;
+		}
+	}
+}
+
+
+static void
+indent(int amount, char *pfx, FILE *fp)
+{
+	int i;
+
+	for (i = 0 ; i < amount ; i++) {
+		if (pfx && i == amount - 1)
+			fputs(pfx, fp);
+		putc('\t', fp);
+	}
+}
+
+
+
+/*
+ * Debugging stuff.
+ */
+
+
+FILE *tracefile;
+
+
+void
+trputc(int c)
+{
+	if (debug != 1)
+		return;
+	putc(c, tracefile);
+}
+
+void
+trace(const char *fmt, ...)
+{
+	va_list va;
+
+	if (debug != 1)
+		return;
+	va_start(va, fmt);
+	(void) vfprintf(tracefile, fmt, va);
+	va_end(va);
+}
+
+void
+tracev(const char *fmt, va_list va)
+{
+	if (debug != 1)
+		return;
+	(void) vfprintf(tracefile, fmt, va);
+}
+
+
+void
+trputs(const char *s)
+{
+	if (debug != 1)
+		return;
+	fputs(s, tracefile);
+}
+
+
+static void
+trstring(char *s)
+{
+	char *p;
+	char c;
+
+	if (debug != 1)
+		return;
+	putc('"', tracefile);
+	for (p = s ; *p ; p++) {
+		switch ((signed char)*p) {
+		case '\n':  c = 'n';  goto backslash;
+		case '\t':  c = 't';  goto backslash;
+		case '\r':  c = 'r';  goto backslash;
+		case '"':  c = '"';  goto backslash;
+		case '\\':  c = '\\';  goto backslash;
+		case CTLESC:  c = 'e';  goto backslash;
+		case CTLVAR:  c = 'v';  goto backslash;
+		case CTLVAR+CTLQUOTE:  c = 'V';  goto backslash;
+		case CTLBACKQ:  c = 'q';  goto backslash;
+		case CTLBACKQ+CTLQUOTE:  c = 'Q';  goto backslash;
+backslash:	  putc('\\', tracefile);
+			putc(c, tracefile);
+			break;
+		default:
+			if (*p >= ' ' && *p <= '~')
+				putc(*p, tracefile);
+			else {
+				putc('\\', tracefile);
+				putc(*p >> 6 & 03, tracefile);
+				putc(*p >> 3 & 07, tracefile);
+				putc(*p & 07, tracefile);
+			}
+			break;
+		}
+	}
+	putc('"', tracefile);
+}
+
+
+void
+trargs(char **ap)
+{
+	if (debug != 1)
+		return;
+	while (*ap) {
+		trstring(*ap++);
+		if (*ap)
+			putc(' ', tracefile);
+		else
+			putc('\n', tracefile);
+	}
+}
+
+
+void
+opentrace(void)
+{
+	char s[100];
+#ifdef O_APPEND
+	int flags;
+#endif
+
+	if (debug != 1) {
+		if (tracefile)
+			fflush(tracefile);
+		/* leave open because libedit might be using it */
+		return;
+	}
+#ifdef not_this_way
+	{
+		char *p;
+		if ((p = getenv(homestr)) == NULL) {
+			if (geteuid() == 0)
+				p = "/";
+			else
+				p = "/tmp";
+		}
+		scopy(p, s);
+		strcat(s, "/trace");
+	}
+#else
+	scopy("./trace", s);
+#endif /* not_this_way */
+	if (tracefile) {
+		if (!freopen(s, "a", tracefile)) {
+			fprintf(stderr, "Can't re-open %s\n", s);
+			debug = 0;
+			return;
+		}
+	} else {
+		if ((tracefile = fopen(s, "a")) == NULL) {
+			fprintf(stderr, "Can't open %s\n", s);
+			debug = 0;
+			return;
+		}
+	}
+#ifdef O_APPEND
+	if ((flags = fcntl(fileno(tracefile), F_GETFL, 0)) >= 0)
+		fcntl(fileno(tracefile), F_SETFL, flags | O_APPEND);
+#endif
+	setlinebuf(tracefile);
+	fputs("\nTracing started.\n", tracefile);
+}
+#endif /* DEBUG */
diff --git a/usr/dash/show.h b/usr/dash/show.h
new file mode 100644
index 0000000..d0ccac7
--- /dev/null
+++ b/usr/dash/show.h
@@ -0,0 +1,45 @@
+/*-
+ * Copyright (c) 1995
+ *      The Regents of the University of California.  All rights reserved.
+ * Copyright (c) 1997-2005
+ *	Herbert Xu <herbert@gondor.apana.org.au>.  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.
+ * 3. 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.
+ *
+ *	@(#)show.h	1.1 (Berkeley) 5/4/95
+ */
+
+#include <stdarg.h>
+
+#ifdef DEBUG
+union node;
+void showtree(union node *);
+void trace(const char *, ...);
+void tracev(const char *, va_list);
+void trargs(char **);
+void trputc(int);
+void trputs(const char *);
+void opentrace(void);
+#endif
diff --git a/usr/dash/system.c b/usr/dash/system.c
new file mode 100644
index 0000000..e5bcddc
--- /dev/null
+++ b/usr/dash/system.c
@@ -0,0 +1,191 @@
+/*
+ * Copyright (c) 2004
+ *	Herbert Xu <herbert@gondor.apana.org.au>.  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.
+ * 3. The name of the author may not 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.
+ */
+
+#ifndef HAVE_ISALPHA
+#define isalnum _isalnum
+#define iscntrl _iscntrl
+#define islower _islower
+#define isspace _isspace
+#define isalpha _isalpha
+#define isdigit _isdigit
+#define isprint _isprint
+#define isupper _isupper
+#define isblank _isblank
+#define isgraph _isgraph
+#define ispunct _ispunct
+#define isxdigit _isxdigit
+#include <ctype.h>
+#undef isalnum
+#undef iscntrl
+#undef islower
+#undef isspace
+#undef isalpha
+#undef isdigit
+#undef isprint
+#undef isupper
+#undef isblank
+#undef isgraph
+#undef ispunct
+#undef isxdigit
+#endif
+
+#include <signal.h>
+#include <string.h>
+
+#include "error.h"
+#include "output.h"
+#include "system.h"
+
+#ifndef HAVE_MEMPCPY
+void *mempcpy(void *dest, const void *src, size_t n)
+{
+	return memcpy(dest, src, n) + n;
+}
+#endif
+
+#ifndef HAVE_STPCPY
+char *stpcpy(char *dest, const char *src)
+{
+	size_t len = strlen(src);
+	dest[len] = 0;
+	return mempcpy(dest, src, len);
+}
+#endif
+
+#ifndef HAVE_STRCHRNUL
+char *strchrnul(const char *s, int c)
+{
+	char *p = strchr(s, c);
+	if (!p)
+		p = (char *)s + strlen(s);
+	return p;
+}
+#endif
+
+#ifndef HAVE_STRSIGNAL
+char *strsignal(int sig)
+{
+	static char buf[19];
+
+	if ((unsigned)sig < NSIG && sys_siglist[sig])
+		return (char *)sys_siglist[sig];
+	fmtstr(buf, sizeof(buf), "Signal %d", sig);
+	return buf;
+}
+#endif
+
+#ifndef HAVE_BSEARCH
+void *bsearch(const void *key, const void *base, size_t nmemb,
+	      size_t size, int (*cmp)(const void *, const void *))
+{
+	while (nmemb) {
+		size_t mididx = nmemb / 2;
+		const void *midobj = base + mididx * size;
+		int diff = cmp(key, midobj);
+
+		if (diff == 0)
+			return (void *)midobj;
+
+		if (diff > 0) {
+			base = midobj + size;
+			nmemb -= mididx + 1;
+		} else
+			nmemb = mididx;
+	}
+
+	return 0;
+}
+#endif
+
+#ifndef HAVE_SYSCONF
+long sysconf(int name)
+{
+	sh_error("no sysconf for: %d", name);
+}
+#endif
+
+#ifndef HAVE_ISALPHA
+int isalnum(int c) {
+	return _isalnum(c);
+}
+
+
+int iscntrl(int c) {
+	return _iscntrl(c);
+}
+
+
+int islower(int c) {
+	return _islower(c);
+}
+
+
+int isspace(int c) {
+	return _isspace(c);
+}
+
+
+int isalpha(int c) {
+	return _isalpha(c);
+}
+
+
+int isdigit(int c) {
+	return _isdigit(c);
+}
+
+
+int isprint(int c) {
+	return _isprint(c);
+}
+
+
+int isupper(int c) {
+	return _isupper(c);
+}
+
+
+int isblank(int c) {
+	return _isblank(c);
+}
+
+
+int isgraph(int c) {
+	return _isgraph(c);
+}
+
+
+int ispunct(int c) {
+	return _ispunct(c);
+}
+
+
+int isxdigit(int c) {
+	return _isxdigit(c);
+}
+#endif
diff --git a/usr/dash/system.h b/usr/dash/system.h
new file mode 100644
index 0000000..828eec5
--- /dev/null
+++ b/usr/dash/system.h
@@ -0,0 +1,91 @@
+/*
+ * Copyright (c) 2004
+ *	Herbert Xu <herbert@gondor.apana.org.au>.  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.
+ * 3. The name of the author may not 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 <limits.h>
+#include <signal.h>
+#include <sys/types.h>
+
+#ifndef SSIZE_MAX
+#define SSIZE_MAX ((ssize_t)((size_t)-1 >> 1))
+#endif
+
+static inline void sigclearmask(void)
+{
+#ifdef HAVE_SIGSETMASK
+	sigsetmask(0);
+#else
+	sigset_t set;
+	sigemptyset(&set);
+	sigprocmask(SIG_SETMASK, &set, 0);
+#endif
+}
+
+#ifndef HAVE_MEMPCPY
+void *mempcpy(void *, const void *, size_t);
+#endif
+
+#ifndef HAVE_STPCPY
+char *stpcpy(char *, const char *);
+#endif
+
+#ifndef HAVE_STRCHRNUL
+char *strchrnul(const char *, int);
+#endif
+
+#ifndef HAVE_STRSIGNAL
+char *strsignal(int);
+#endif
+
+#ifndef HAVE_STRTOIMAX
+#define strtoimax strtoll
+#endif
+
+#ifndef HAVE_STRTOUMAX
+#define strtoumax strtoull
+#endif
+
+#ifndef HAVE_BSEARCH
+void *bsearch(const void *, const void *, size_t, size_t,
+	      int (*)(const void *, const void *));
+#endif
+
+#ifndef HAVE_KILLPG
+static inline int killpg(pid_t pid, int signal)
+{
+#ifdef DEBUG
+	if (pid < 0)
+		abort();
+#endif
+	return kill(-pid, signal);
+}
+#endif
+
+#ifndef HAVE_SYSCONF
+#define _SC_CLK_TCK 2
+long sysconf(int) __attribute__((__noreturn__));
+#endif
diff --git a/usr/dash/trap.c b/usr/dash/trap.c
new file mode 100644
index 0000000..51e1d56
--- /dev/null
+++ b/usr/dash/trap.c
@@ -0,0 +1,443 @@
+/*-
+ * Copyright (c) 1991, 1993
+ *	The Regents of the University of California.  All rights reserved.
+ * Copyright (c) 1997-2005
+ *	Herbert Xu <herbert@gondor.apana.org.au>.  All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Kenneth Almquist.
+ *
+ * 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. 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 <signal.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+
+#include "shell.h"
+#include "main.h"
+#include "nodes.h"	/* for other headers */
+#include "eval.h"
+#include "jobs.h"
+#include "show.h"
+#include "options.h"
+#include "syntax.h"
+#include "output.h"
+#include "memalloc.h"
+#include "error.h"
+#include "trap.h"
+#include "mystring.h"
+
+#ifdef HETIO
+#include "hetio.h"
+#endif
+
+/*
+ * Sigmode records the current value of the signal handlers for the various
+ * modes.  A value of zero means that the current handler is not known.
+ * S_HARD_IGN indicates that the signal was ignored on entry to the shell,
+ */
+
+#define S_DFL 1			/* default signal handling (SIG_DFL) */
+#define S_CATCH 2		/* signal is caught */
+#define S_IGN 3			/* signal is ignored (SIG_IGN) */
+#define S_HARD_IGN 4		/* signal is ignored permenantly */
+#define S_RESET 5		/* temporary - to reset a hard ignored sig */
+
+
+/* trap handler commands */
+char *trap[NSIG];
+/* current value of signal */
+static char sigmode[NSIG - 1];
+/* indicates specified signal received */
+char gotsig[NSIG - 1];
+/* last pending signal */
+volatile sig_atomic_t pendingsigs;
+/* do we generate EXSIG events */
+int exsig;
+
+#ifdef mkinit
+INCLUDE <signal.h>
+INIT {
+	signal(SIGCHLD, SIG_DFL);
+}
+#endif
+
+/*
+ * The trap builtin.
+ */
+
+int
+trapcmd(int argc, char **argv)
+{
+	char *action;
+	char **ap;
+	int signo;
+
+	nextopt(nullstr);
+	ap = argptr;
+	if (!*ap) {
+		for (signo = 0 ; signo < NSIG ; signo++) {
+			if (trap[signo] != NULL) {
+				out1fmt(
+					"trap -- %s %s\n",
+					single_quote(trap[signo]),
+					signal_name(signo)
+				);
+			}
+		}
+		return 0;
+	}
+	if (!ap[1])
+		action = NULL;
+	else
+		action = *ap++;
+	while (*ap) {
+		if ((signo = decode_signal(*ap, 0)) < 0)
+			sh_error("%s: bad trap", *ap);
+		INTOFF;
+		if (action) {
+			if (action[0] == '-' && action[1] == '\0')
+				action = NULL;
+			else
+				action = savestr(action);
+		}
+		if (trap[signo])
+			ckfree(trap[signo]);
+		trap[signo] = action;
+		if (signo != 0)
+			setsignal(signo);
+		INTON;
+		ap++;
+	}
+	return 0;
+}
+
+
+
+/*
+ * Clear traps on a fork.
+ */
+
+void
+clear_traps(void)
+{
+	char **tp;
+
+	for (tp = trap ; tp < &trap[NSIG] ; tp++) {
+		if (*tp && **tp) {	/* trap not NULL or SIG_IGN */
+			INTOFF;
+			ckfree(*tp);
+			*tp = NULL;
+			if (tp != &trap[0])
+				setsignal(tp - trap);
+			INTON;
+		}
+	}
+}
+
+
+
+/*
+ * Set the signal handler for the specified signal.  The routine figures
+ * out what it should be set to.
+ */
+
+void
+setsignal(int signo)
+{
+	int action;
+	char *t, tsig;
+	struct sigaction act;
+
+	if ((t = trap[signo]) == NULL)
+		action = S_DFL;
+	else if (*t != '\0')
+		action = S_CATCH;
+	else
+		action = S_IGN;
+	if (rootshell && action == S_DFL) {
+		switch (signo) {
+		case SIGINT:
+			if (iflag || minusc || sflag == 0)
+				action = S_CATCH;
+			break;
+		case SIGQUIT:
+#ifdef DEBUG
+			if (debug)
+				break;
+#endif
+			/* FALLTHROUGH */
+		case SIGTERM:
+			if (iflag)
+				action = S_IGN;
+			break;
+#if JOBS
+		case SIGTSTP:
+		case SIGTTOU:
+			if (mflag)
+				action = S_IGN;
+			break;
+#endif
+		}
+	}
+
+	t = &sigmode[signo - 1];
+	tsig = *t;
+	if (tsig == 0) {
+		/*
+		 * current setting unknown
+		 */
+		if (sigaction(signo, 0, &act) == -1) {
+			/*
+			 * Pretend it worked; maybe we should give a warning
+			 * here, but other shells don't. We don't alter
+			 * sigmode, so that we retry every time.
+			 */
+			return;
+		}
+		if (act.sa_handler == SIG_IGN) {
+			if (mflag && (signo == SIGTSTP ||
+			     signo == SIGTTIN || signo == SIGTTOU)) {
+				tsig = S_IGN;	/* don't hard ignore these */
+			} else
+				tsig = S_HARD_IGN;
+		} else {
+			tsig = S_RESET;	/* force to be set */
+		}
+	}
+	if (tsig == S_HARD_IGN || tsig == action)
+		return;
+	switch (action) {
+	case S_CATCH:
+		act.sa_handler = onsig;
+		break;
+	case S_IGN:
+		act.sa_handler = SIG_IGN;
+		break;
+	default:
+		act.sa_handler = SIG_DFL;
+	}
+	*t = action;
+	act.sa_flags = 0;
+	sigfillset(&act.sa_mask);
+	sigaction(signo, &act, 0);
+}
+
+/*
+ * Ignore a signal.
+ */
+
+void
+ignoresig(int signo)
+{
+	if (sigmode[signo - 1] != S_IGN && sigmode[signo - 1] != S_HARD_IGN) {
+		signal(signo, SIG_IGN);
+	}
+	sigmode[signo - 1] = S_HARD_IGN;
+}
+
+
+
+/*
+ * Signal handler.
+ */
+
+void
+onsig(int signo)
+{
+	gotsig[signo - 1] = 1;
+	pendingsigs = signo;
+
+	if (exsig || (signo == SIGINT && !trap[SIGINT])) {
+		if (!suppressint)
+			onint();
+		intpending = 1;
+	}
+}
+
+
+
+/*
+ * Called to execute a trap.  Perhaps we should avoid entering new trap
+ * handlers while we are executing a trap handler.
+ */
+
+int
+dotrap(void)
+{
+	char *p;
+	char *q;
+	int i;
+	int savestatus;
+	int skip = 0;
+
+	savestatus = exitstatus;
+	pendingsigs = 0;
+	barrier();
+
+	for (i = 0, q = gotsig; i < NSIG - 1; i++, q++) {
+		if (!*q)
+			continue;
+		*q = 0;
+
+		p = trap[i + 1];
+		if (!p)
+			continue;
+		skip = evalstring(p, SKIPEVAL);
+		exitstatus = savestatus;
+		if (skip)
+			break;
+	}
+
+	return skip;
+}
+
+
+
+/*
+ * Controls whether the shell is interactive or not.
+ */
+
+
+void
+setinteractive(int on)
+{
+	static int is_interactive;
+
+	if (++on == is_interactive)
+		return;
+	is_interactive = on;
+	setsignal(SIGINT);
+	setsignal(SIGQUIT);
+	setsignal(SIGTERM);
+}
+
+
+
+/*
+ * Called to exit the shell.
+ */
+
+void
+exitshell(void)
+{
+	struct jmploc loc;
+	char *p;
+	int status;
+
+#ifdef HETIO
+	hetio_reset_term();
+#endif
+	status = exitstatus;
+	TRACE(("pid %d, exitshell(%d)\n", getpid(), status));
+	if (setjmp(loc.loc)) {
+		if (exception == EXEXIT)
+			_exit(exitstatus);
+		goto out;
+	}
+	handler = &loc;
+	if ((p = trap[0])) {
+		trap[0] = NULL;
+		evalstring(p, 0);
+	}
+	flushall();
+out:
+	_exit(status);
+	/* NOTREACHED */
+}
+
+/*
+ * Decode a signal name
+ */
+int decode_signal(const char *string, int minsig)
+{
+	int i;
+
+	if (is_number(string)) {
+		i = atoi(string);
+		if (i >= NSIG) {
+			return -1;
+		}
+		return i;
+	}
+
+	for ( i = minsig ; i < NSIG ; i++ ) {
+		if ( sys_sigabbrev[i] &&
+		     !strcasecmp(string, sys_sigabbrev[i]) )
+			return i;
+	}
+
+#ifdef SIGRTMIN
+	if ( !strncasecmp(string, "RTMIN", 5) ) {
+		char *ep;
+
+		if ( string[5] && string[5] != '+' )
+			return -1;
+		i = SIGRTMIN + strtol(string+5, &ep, 10);
+		if ( *ep || i < SIGRTMIN || i > SIGRTMAX )
+			return -1;
+		return i;
+	}
+
+	if ( !strncasecmp(string, "RTMAX", 5) ) {
+		char *ep;
+
+		if ( string[5] && string[5] != '-' )
+			return -1;
+		i = SIGRTMAX + strtol(string+5, &ep, 10);
+		if ( *ep || i < SIGRTMIN || i > SIGRTMAX )
+			return -1;
+		return i;
+	}
+#endif
+
+	return -1;
+}
+
+/*
+ * Human-readable signal name
+ */
+const char *
+signal_name(int sig)
+{
+	static char buf[64];
+
+	if ( sig < 0 || sig >= NSIG ) {
+		return NULL;
+	} else if ( sys_sigabbrev[sig] ) {
+		return sys_sigabbrev[sig];
+#ifdef SIGRTMIN
+	} else if ( sig >= SIGRTMIN && sig <= SIGRTMAX ) {
+		snprintf(buf, sizeof buf, "RTMIN+%d", sig-SIGRTMIN);
+		return buf;
+#endif
+	} else {
+		snprintf(buf, sizeof buf, "%d", sig);
+		return buf;
+	}
+}
diff --git a/usr/dash/trap.h b/usr/dash/trap.h
new file mode 100644
index 0000000..295de5d
--- /dev/null
+++ b/usr/dash/trap.h
@@ -0,0 +1,52 @@
+/*-
+ * Copyright (c) 1991, 1993
+ *	The Regents of the University of California.  All rights reserved.
+ * Copyright (c) 1997-2005
+ *	Herbert Xu <herbert@gondor.apana.org.au>.  All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Kenneth Almquist.
+ *
+ * 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. 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.
+ *
+ *	@(#)trap.h	8.3 (Berkeley) 6/5/95
+ */
+
+#include <signal.h>
+
+extern char *trap[];
+extern char gotsig[];
+extern volatile sig_atomic_t pendingsigs;
+
+int trapcmd(int, char **);
+void clear_traps(void);
+void setsignal(int);
+void ignoresig(int);
+void onsig(int);
+int dotrap(void);
+void setinteractive(int);
+void exitshell(void) __attribute__((__noreturn__));
+int decode_signal(const char *, int);
+const char *signal_name(int);
diff --git a/usr/dash/var.c b/usr/dash/var.c
new file mode 100644
index 0000000..3263dc5
--- /dev/null
+++ b/usr/dash/var.c
@@ -0,0 +1,676 @@
+/*-
+ * Copyright (c) 1991, 1993
+ *	The Regents of the University of California.  All rights reserved.
+ * Copyright (c) 1997-2005
+ *	Herbert Xu <herbert@gondor.apana.org.au>.  All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Kenneth Almquist.
+ *
+ * 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. 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 <unistd.h>
+#include <stdlib.h>
+#include <paths.h>
+
+/*
+ * Shell variables.
+ */
+
+#include "shell.h"
+#include "output.h"
+#include "expand.h"
+#include "nodes.h"	/* for other headers */
+#include "eval.h"	/* defines cmdenviron */
+#include "exec.h"
+#include "syntax.h"
+#include "options.h"
+#include "mail.h"
+#include "var.h"
+#include "memalloc.h"
+#include "error.h"
+#include "mystring.h"
+#include "parser.h"
+#include "show.h"
+#ifndef SMALL
+#include "myhistedit.h"
+#endif
+#include "system.h"
+
+
+#define VTABSIZE 39
+
+
+struct localvar *localvars;
+
+const char defpathvar[] =
+	"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin";
+#ifdef IFS_BROKEN
+const char defifsvar[] = "IFS= \t\n";
+#else
+const char defifs[] = " \t\n";
+#endif
+
+struct var varinit[] = {
+#if ATTY
+	{ 0,	VSTRFIXED|VTEXTFIXED|VUNSET,	"ATTY\0",	0 },
+#endif
+#ifdef IFS_BROKEN
+	{ 0,	VSTRFIXED|VTEXTFIXED,		defifsvar,	0 },
+#else
+	{ 0,	VSTRFIXED|VTEXTFIXED|VUNSET,	"IFS\0",	0 },
+#endif
+	{ 0,	VSTRFIXED|VTEXTFIXED|VUNSET,	"MAIL\0",	changemail },
+	{ 0,	VSTRFIXED|VTEXTFIXED|VUNSET,	"MAILPATH\0",	changemail },
+	{ 0,	VSTRFIXED|VTEXTFIXED,		defpathvar,	changepath },
+	{ 0,	VSTRFIXED|VTEXTFIXED,		"PS1=$ ",	0 },
+	{ 0,	VSTRFIXED|VTEXTFIXED,		"PS2=> ",	0 },
+	{ 0,	VSTRFIXED|VTEXTFIXED,		"PS4=+ ",	0 },
+	{ 0,	VSTRFIXED|VTEXTFIXED,		"OPTIND=1",	getoptsreset },
+#ifndef SMALL
+	{ 0,	VSTRFIXED|VTEXTFIXED|VUNSET,	"TERM\0",	0 },
+	{ 0,	VSTRFIXED|VTEXTFIXED|VUNSET,	"HISTSIZE\0",	sethistsize },
+#endif
+};
+
+STATIC struct var *vartab[VTABSIZE];
+
+STATIC void mklocal(char *);
+STATIC struct var **hashvar(const char *);
+STATIC int vpcmp(const void *, const void *);
+STATIC struct var **findvar(struct var **, const char *);
+
+/*
+ * Initialize the varable symbol tables and import the environment
+ */
+
+#ifdef mkinit
+INCLUDE <unistd.h>
+INCLUDE <sys/types.h>
+INCLUDE <sys/stat.h>
+INCLUDE "cd.h"
+INCLUDE "output.h"
+INCLUDE "var.h"
+MKINIT char **environ;
+INIT {
+	char **envp;
+	static char ppid[32] = "PPID=";
+	const char *p;
+	struct stat st1, st2;
+
+	initvar();
+	for (envp = environ ; *envp ; envp++) {
+		if (strchr(*envp, '=')) {
+			setvareq(*envp, VEXPORT|VTEXTFIXED);
+		}
+	}
+
+	fmtstr(ppid + 5, sizeof(ppid) - 5, "%ld", (long) getppid());
+	setvareq(ppid, VTEXTFIXED);
+
+	p = lookupvar("PWD");
+	if (p)
+		if (*p != '/' || stat(p, &st1) || stat(".", &st2) ||
+		    st1.st_dev != st2.st_dev || st1.st_ino != st2.st_ino)
+			p = 0;
+	setpwd(p, 0);
+}
+#endif
+
+
+/*
+ * This routine initializes the builtin variables.  It is called when the
+ * shell is initialized.
+ */
+
+void
+initvar(void)
+{
+	struct var *vp;
+	struct var *end;
+	struct var **vpp;
+
+	vp = varinit;
+	end = vp + sizeof(varinit) / sizeof(varinit[0]);
+	do {
+		vpp = hashvar(vp->text);
+		vp->next = *vpp;
+		*vpp = vp;
+	} while (++vp < end);
+	/*
+	 * PS1 depends on uid
+	 */
+	if (!geteuid())
+		vps1.text = "PS1=# ";
+}
+
+/*
+ * Safe version of setvar, returns 1 on success 0 on failure.
+ */
+
+int
+setvarsafe(const char *name, const char *val, int flags)
+{
+	int err;
+	volatile int saveint;
+	struct jmploc *volatile savehandler = handler;
+	struct jmploc jmploc;
+
+	SAVEINT(saveint);
+	if (setjmp(jmploc.loc))
+		err = 1;
+	else {
+		handler = &jmploc;
+		setvar(name, val, flags);
+		err = 0;
+	}
+	handler = savehandler;
+	RESTOREINT(saveint);
+	return err;
+}
+
+/*
+ * Set the value of a variable.  The flags argument is ored with the
+ * flags of the variable.  If val is NULL, the variable is unset.
+ */
+
+void
+setvar(const char *name, const char *val, int flags)
+{
+	char *p, *q;
+	size_t namelen;
+	char *nameeq;
+	size_t vallen;
+
+	q = endofname(name);
+	p = strchrnul(q, '=');
+	namelen = p - name;
+	if (!namelen || p != q)
+		sh_error("%.*s: bad variable name", namelen, name);
+	vallen = 0;
+	if (val == NULL) {
+		flags |= VUNSET;
+	} else {
+		vallen = strlen(val);
+	}
+	INTOFF;
+	p = mempcpy(nameeq = ckmalloc(namelen + vallen + 2), name, namelen);
+	if (val) {
+		*p++ = '=';
+		p = mempcpy(p, val, vallen);
+	}
+	*p = '\0';
+	setvareq(nameeq, flags | VNOSAVE);
+	INTON;
+}
+
+
+
+/*
+ * Same as setvar except that the variable and value are passed in
+ * the first argument as name=value.  Since the first argument will
+ * be actually stored in the table, it should not be a string that
+ * will go away.
+ * Called with interrupts off.
+ */
+
+void
+setvareq(char *s, int flags)
+{
+	struct var *vp, **vpp;
+
+	vpp = hashvar(s);
+	flags |= (VEXPORT & (((unsigned) (1 - aflag)) - 1));
+	vp = *findvar(vpp, s);
+	if (vp) {
+		if (vp->flags & VREADONLY) {
+			const char *n;
+
+			if (flags & VNOSAVE)
+				free(s);
+			n = vp->text;
+			sh_error("%.*s: is read only", strchrnul(n, '=') - n,
+				 n);
+		}
+
+		if (flags & VNOSET)
+			return;
+
+		if (vp->func && (flags & VNOFUNC) == 0)
+			(*vp->func)(strchrnul(s, '=') + 1);
+
+		if ((vp->flags & (VTEXTFIXED|VSTACK)) == 0)
+			ckfree(vp->text);
+
+		flags |= vp->flags & ~(VTEXTFIXED|VSTACK|VNOSAVE|VUNSET);
+	} else {
+		if (flags & VNOSET)
+			return;
+		/* not found */
+		vp = ckmalloc(sizeof (*vp));
+		vp->next = *vpp;
+		vp->func = NULL;
+		*vpp = vp;
+	}
+	if (!(flags & (VTEXTFIXED|VSTACK|VNOSAVE)))
+		s = savestr(s);
+	vp->text = s;
+	vp->flags = flags;
+}
+
+
+
+/*
+ * Process a linked list of variable assignments.
+ */
+
+void
+listsetvar(struct strlist *list, int flags)
+{
+	struct strlist *lp;
+
+	lp = list;
+	if (!lp)
+		return;
+	INTOFF;
+	do {
+		setvareq(lp->text, flags);
+	} while ((lp = lp->next));
+	INTON;
+}
+
+
+/*
+ * Find the value of a variable.  Returns NULL if not set.
+ */
+
+char *
+lookupvar(const char *name)
+{
+	struct var *v;
+
+	if ((v = *findvar(hashvar(name), name)) && !(v->flags & VUNSET)) {
+		return strchrnul(v->text, '=') + 1;
+	}
+	return NULL;
+}
+
+
+
+/*
+ * Search the environment of a builtin command.
+ */
+
+char *
+bltinlookup(const char *name)
+{
+	struct strlist *sp;
+
+	for (sp = cmdenviron ; sp ; sp = sp->next) {
+		if (varequal(sp->text, name))
+			return strchrnul(sp->text, '=') + 1;
+	}
+	return lookupvar(name);
+}
+
+
+
+/*
+ * Generate a list of variables satisfying the given conditions.
+ */
+
+char **
+listvars(int on, int off, char ***end)
+{
+	struct var **vpp;
+	struct var *vp;
+	char **ep;
+	int mask;
+
+	STARTSTACKSTR(ep);
+	vpp = vartab;
+	mask = on | off;
+	do {
+		for (vp = *vpp ; vp ; vp = vp->next)
+			if ((vp->flags & mask) == on) {
+				if (ep == stackstrend())
+					ep = growstackstr();
+				*ep++ = (char *) vp->text;
+			}
+	} while (++vpp < vartab + VTABSIZE);
+	if (ep == stackstrend())
+		ep = growstackstr();
+	if (end)
+		*end = ep;
+	*ep++ = NULL;
+	return grabstackstr(ep);
+}
+
+
+
+/*
+ * POSIX requires that 'set' (but not export or readonly) output the
+ * variables in lexicographic order - by the locale's collating order (sigh).
+ * Maybe we could keep them in an ordered balanced binary tree
+ * instead of hashed lists.
+ * For now just roll 'em through qsort for printing...
+ */
+
+int
+showvars(const char *prefix, int on, int off)
+{
+	const char *sep;
+	char **ep, **epend;
+
+	ep = listvars(on, off, &epend);
+	qsort(ep, epend - ep, sizeof(char *), vpcmp);
+
+	sep = *prefix ? spcstr : prefix;
+
+	for (; ep < epend; ep++) {
+		const char *p;
+		const char *q;
+
+		p = strchrnul(*ep, '=');
+		q = nullstr;
+		if (*p)
+			q = single_quote(++p);
+
+		out1fmt("%s%s%.*s%s\n", prefix, sep, (int)(p - *ep), *ep, q);
+	}
+
+	return 0;
+}
+
+
+
+/*
+ * The export and readonly commands.
+ */
+
+int
+exportcmd(int argc, char **argv)
+{
+	struct var *vp;
+	char *name;
+	const char *p;
+	char **aptr;
+	int flag = argv[0][0] == 'r'? VREADONLY : VEXPORT;
+	int notp;
+
+	notp = nextopt("p") - 'p';
+	if (notp && ((name = *(aptr = argptr)))) {
+		do {
+			if ((p = strchr(name, '=')) != NULL) {
+				p++;
+			} else {
+				if ((vp = *findvar(hashvar(name), name))) {
+					vp->flags |= flag;
+					continue;
+				}
+			}
+			setvar(name, p, flag);
+		} while ((name = *++aptr) != NULL);
+	} else {
+		showvars(argv[0], flag, 0);
+	}
+	return 0;
+}
+
+
+/*
+ * The "local" command.
+ */
+
+int
+localcmd(int argc, char **argv)
+{
+	char *name;
+
+	argv = argptr;
+	while ((name = *argv++) != NULL) {
+		mklocal(name);
+	}
+	return 0;
+}
+
+
+/*
+ * Make a variable a local variable.  When a variable is made local, it's
+ * value and flags are saved in a localvar structure.  The saved values
+ * will be restored when the shell function returns.  We handle the name
+ * "-" as a special case.
+ */
+
+STATIC void
+mklocal(char *name)
+{
+	struct localvar *lvp;
+	struct var **vpp;
+	struct var *vp;
+
+	INTOFF;
+	lvp = ckmalloc(sizeof (struct localvar));
+	if (name[0] == '-' && name[1] == '\0') {
+		char *p;
+		p = ckmalloc(sizeof(optlist));
+		lvp->text = memcpy(p, optlist, sizeof(optlist));
+		vp = NULL;
+	} else {
+		char *eq;
+
+		vpp = hashvar(name);
+		vp = *findvar(vpp, name);
+		eq = strchr(name, '=');
+		if (vp == NULL) {
+			if (eq)
+				setvareq(name, VSTRFIXED);
+			else
+				setvar(name, NULL, VSTRFIXED);
+			vp = *vpp;	/* the new variable */
+			lvp->flags = VUNSET;
+		} else {
+			lvp->text = vp->text;
+			lvp->flags = vp->flags;
+			vp->flags |= VSTRFIXED|VTEXTFIXED;
+			if (eq)
+				setvareq(name, 0);
+		}
+	}
+	lvp->vp = vp;
+	lvp->next = localvars;
+	localvars = lvp;
+	INTON;
+}
+
+
+/*
+ * Called after a function returns.
+ * Interrupts must be off.
+ */
+
+void
+poplocalvars(void)
+{
+	struct localvar *lvp;
+	struct var *vp;
+
+	while ((lvp = localvars) != NULL) {
+		localvars = lvp->next;
+		vp = lvp->vp;
+		TRACE(("poplocalvar %s", vp ? vp->text : "-"));
+		if (vp == NULL) {	/* $- saved */
+			memcpy(optlist, lvp->text, sizeof(optlist));
+			ckfree(lvp->text);
+			optschanged();
+		} else if ((lvp->flags & (VUNSET|VSTRFIXED)) == VUNSET) {
+			unsetvar(vp->text);
+		} else {
+			if (vp->func)
+				(*vp->func)(strchrnul(lvp->text, '=') + 1);
+			if ((vp->flags & (VTEXTFIXED|VSTACK)) == 0)
+				ckfree(vp->text);
+			vp->flags = lvp->flags;
+			vp->text = lvp->text;
+		}
+		ckfree(lvp);
+	}
+}
+
+
+/*
+ * The unset builtin command.  We unset the function before we unset the
+ * variable to allow a function to be unset when there is a readonly variable
+ * with the same name.
+ */
+
+int
+unsetcmd(int argc, char **argv)
+{
+	char **ap;
+	int i;
+	int flag = 0;
+	int ret = 0;
+
+	while ((i = nextopt("vf")) != '\0') {
+		flag = i;
+	}
+
+	for (ap = argptr; *ap ; ap++) {
+		if (flag != 'f') {
+			i = unsetvar(*ap);
+			ret |= i;
+			if (!(i & 2))
+				continue;
+		}
+		if (flag != 'v')
+			unsetfunc(*ap);
+	}
+	return ret & 1;
+}
+
+
+/*
+ * Unset the specified variable.
+ */
+
+int
+unsetvar(const char *s)
+{
+	struct var **vpp;
+	struct var *vp;
+	int retval;
+
+	vpp = findvar(hashvar(s), s);
+	vp = *vpp;
+	retval = 2;
+	if (vp) {
+		int flags = vp->flags;
+
+		retval = 1;
+		if (flags & VREADONLY)
+			goto out;
+		if (flags & VUNSET)
+			goto ok;
+		if ((flags & VSTRFIXED) == 0) {
+			INTOFF;
+			if ((flags & (VTEXTFIXED|VSTACK)) == 0)
+				ckfree(vp->text);
+			*vpp = vp->next;
+			ckfree(vp);
+			INTON;
+		} else {
+			setvar(s, 0, 0);
+			vp->flags &= ~VEXPORT;
+		}
+ok:
+		retval = 0;
+	}
+
+out:
+	return retval;
+}
+
+
+
+/*
+ * Find the appropriate entry in the hash table from the name.
+ */
+
+STATIC struct var **
+hashvar(const char *p)
+{
+	unsigned int hashval;
+
+	hashval = ((unsigned char) *p) << 4;
+	while (*p && *p != '=')
+		hashval += (unsigned char) *p++;
+	return &vartab[hashval % VTABSIZE];
+}
+
+
+
+/*
+ * Compares two strings up to the first = or '\0'.  The first
+ * string must be terminated by '='; the second may be terminated by
+ * either '=' or '\0'.
+ */
+
+int
+varcmp(const char *p, const char *q)
+{
+	int c, d;
+
+	while ((c = *p) == (d = *q)) {
+		if (!c || c == '=')
+			goto out;
+		p++;
+		q++;
+	}
+	if (c == '=')
+		c = 0;
+	if (d == '=')
+		d = 0;
+out:
+	return c - d;
+}
+
+STATIC int
+vpcmp(const void *a, const void *b)
+{
+	return varcmp(*(const char **)a, *(const char **)b);
+}
+
+STATIC struct var **
+findvar(struct var **vpp, const char *name)
+{
+	for (; *vpp; vpp = &(*vpp)->next) {
+		if (varequal((*vpp)->text, name)) {
+			break;
+		}
+	}
+	return vpp;
+}
diff --git a/usr/dash/var.h b/usr/dash/var.h
new file mode 100644
index 0000000..c3c2ca7
--- /dev/null
+++ b/usr/dash/var.h
@@ -0,0 +1,146 @@
+/*-
+ * Copyright (c) 1991, 1993
+ *	The Regents of the University of California.  All rights reserved.
+ * Copyright (c) 1997-2005
+ *	Herbert Xu <herbert@gondor.apana.org.au>.  All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Kenneth Almquist.
+ *
+ * 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. 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.
+ *
+ *	@(#)var.h	8.2 (Berkeley) 5/4/95
+ */
+
+/*
+ * Shell variables.
+ */
+
+/* flags */
+#define VEXPORT		0x01	/* variable is exported */
+#define VREADONLY	0x02	/* variable cannot be modified */
+#define VSTRFIXED	0x04	/* variable struct is statically allocated */
+#define VTEXTFIXED	0x08	/* text is statically allocated */
+#define VSTACK		0x10	/* text is allocated on the stack */
+#define VUNSET		0x20	/* the variable is not set */
+#define VNOFUNC		0x40	/* don't call the callback function */
+#define VNOSET		0x80	/* do not set variable - just readonly test */
+#define VNOSAVE		0x100	/* when text is on the heap before setvareq */
+
+
+struct var {
+	struct var *next;		/* next entry in hash list */
+	int flags;			/* flags are defined above */
+	const char *text;		/* name=value */
+	void (*func)(const char *);
+					/* function to be called when  */
+					/* the variable gets set/unset */
+};
+
+
+struct localvar {
+	struct localvar *next;		/* next local variable in list */
+	struct var *vp;			/* the variable that was made local */
+	int flags;			/* saved flags */
+	const char *text;		/* saved text */
+};
+
+
+extern struct localvar *localvars;
+extern struct var varinit[];
+
+#if ATTY
+#define vatty varinit[0]
+#define vifs varinit[1]
+#else
+#define vifs varinit[0]
+#endif
+#define vmail (&vifs)[1]
+#define vmpath (&vmail)[1]
+#define vpath (&vmpath)[1]
+#define vps1 (&vpath)[1]
+#define vps2 (&vps1)[1]
+#define vps4 (&vps2)[1]
+#define voptind (&vps4)[1]
+#ifndef SMALL
+#define vterm (&voptind)[1]
+#define vhistsize (&vterm)[1]
+#endif
+
+#ifdef IFS_BROKEN
+extern const char defifsvar[];
+#define defifs (defifsvar + 4)
+#else
+extern const char defifs[];
+#endif
+extern const char defpathvar[];
+#define defpath (defpathvar + 5)
+
+/*
+ * The following macros access the values of the above variables.
+ * They have to skip over the name.  They return the null string
+ * for unset variables.
+ */
+
+#define ifsval()	(vifs.text + 4)
+#define ifsset()	((vifs.flags & VUNSET) == 0)
+#define mailval()	(vmail.text + 5)
+#define mpathval()	(vmpath.text + 9)
+#define pathval()	(vpath.text + 5)
+#define ps1val()	(vps1.text + 4)
+#define ps2val()	(vps2.text + 4)
+#define ps4val()	(vps4.text + 4)
+#define optindval()	(voptind.text + 7)
+#ifndef SMALL
+#define histsizeval()	(vhistsize.text + 9)
+#define termval()	(vterm.text + 5)
+#endif
+
+#if ATTY
+#define attyset()	((vatty.flags & VUNSET) == 0)
+#endif
+#define mpathset()	((vmpath.flags & VUNSET) == 0)
+
+void initvar(void);
+void setvar(const char *, const char *, int);
+void setvareq(char *, int);
+struct strlist;
+void listsetvar(struct strlist *, int);
+char *lookupvar(const char *);
+char *bltinlookup(const char *);
+char **listvars(int, int, char ***);
+#define environment() listvars(VEXPORT, VUNSET, 0)
+int showvars(const char *, int, int);
+int exportcmd(int, char **);
+int localcmd(int, char **);
+void poplocalvars(void);
+int unsetcmd(int, char **);
+int unsetvar(const char *);
+int setvarsafe(const char *, const char *, int);
+int varcmp(const char *, const char *);
+
+static inline int varequal(const char *a, const char *b) {
+	return !varcmp(a, b);
+}
diff --git a/usr/gzip/COPYING b/usr/gzip/COPYING
new file mode 100644
index 0000000..a43ea21
--- /dev/null
+++ b/usr/gzip/COPYING
@@ -0,0 +1,339 @@
+		    GNU GENERAL PUBLIC LICENSE
+		       Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+                          675 Mass Ave, Cambridge, MA 02139, USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+			    Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users.  This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it.  (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.)  You can apply it to
+your programs, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+  To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+  For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have.  You must make sure that they, too, receive or can get the
+source code.  And you must show them these terms so they know their
+rights.
+
+  We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+  Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software.  If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+  Finally, any free program is threatened constantly by software
+patents.  We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary.  To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+
+		    GNU GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License.  The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language.  (Hereinafter, translation is included without limitation in
+the term "modification".)  Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+  1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+  2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) You must cause the modified files to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    b) You must cause any work that you distribute or publish, that in
+    whole or in part contains or is derived from the Program or any
+    part thereof, to be licensed as a whole at no charge to all third
+    parties under the terms of this License.
+
+    c) If the modified program normally reads commands interactively
+    when run, you must cause it, when started running for such
+    interactive use in the most ordinary way, to print or display an
+    announcement including an appropriate copyright notice and a
+    notice that there is no warranty (or else, saying that you provide
+    a warranty) and that users may redistribute the program under
+    these conditions, and telling the user how to view a copy of this
+    License.  (Exception: if the Program itself is interactive but
+    does not normally print such an announcement, your work based on
+    the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+    a) Accompany it with the complete corresponding machine-readable
+    source code, which must be distributed under the terms of Sections
+    1 and 2 above on a medium customarily used for software interchange; or,
+
+    b) Accompany it with a written offer, valid for at least three
+    years, to give any third party, for a charge no more than your
+    cost of physically performing source distribution, a complete
+    machine-readable copy of the corresponding source code, to be
+    distributed under the terms of Sections 1 and 2 above on a medium
+    customarily used for software interchange; or,
+
+    c) Accompany it with the information you received as to the offer
+    to distribute corresponding source code.  (This alternative is
+    allowed only for noncommercial distribution and only if you
+    received the program in object code or executable form with such
+    an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it.  For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable.  However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+  4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License.  Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+  5. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Program or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+  6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+  7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+  8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded.  In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+  9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time.  Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation.  If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+  10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission.  For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this.  Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+			    NO WARRANTY
+
+  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+		     END OF TERMS AND CONDITIONS
+
+	Appendix: How to Apply These Terms to Your New Programs
+
+  If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+  To do so, attach the following notices to the program.  It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the program's name and a brief idea of what it does.>
+    Copyright (C) 19yy  <name of author>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program 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 General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+    Gnomovision version 69, Copyright (C) 19yy name of author
+    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+    This is free software, and you are welcome to redistribute it
+    under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License.  Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+  `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+  <signature of Ty Coon>, 1 April 1989
+  Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs.  If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library.  If this is what you want to do, use the GNU Library General
+Public License instead of this License.
diff --git a/usr/gzip/Kbuild b/usr/gzip/Kbuild
new file mode 100644
index 0000000..64fae04
--- /dev/null
+++ b/usr/gzip/Kbuild
@@ -0,0 +1,25 @@
+#
+# Kbuild file for gzip
+#
+
+# The gzip executable
+static-y := gzip
+gzip-y   := gzip.o util.o unzip.o inflate.o
+
+# Additional targets
+always := gunzip zcat
+
+# Optional ZIP support
+gzip-$(CONFIG_KLIB_ZIP)   += zip.o deflate.o trees.o bits.o
+cflags-$(CONFIG_KLIB_ZIP) += -DSUPPORT_ZIP
+EXTRA_KLIBCCFLAGS := $(cflags-y)
+
+# Additionally linked targets
+$(obj)/gunzip $(obj)/zcat: $(obj)/gzip
+	$(call cmd,ln)
+
+# Cleaning
+targets := gzip gzip.g gunzip zcat
+
+# Targets to install
+install-y := gzip gunzip zcat
diff --git a/usr/gzip/README b/usr/gzip/README
new file mode 100644
index 0000000..fdd7311
--- /dev/null
+++ b/usr/gzip/README
@@ -0,0 +1,144 @@
+This is the file README for the gzip distribution, version 1.2.4.
+
+gzip (GNU zip) is a compression utility designed to be a replacement
+for 'compress'. Its main advantages over compress are much better
+compression and freedom from patented algorithms.  The GNU Project
+uses it as the standard compression program for its system.
+
+gzip currently uses by default the LZ77 algorithm used in zip 1.9 (the
+portable pkzip compatible archiver). The gzip format was however
+designed to accommodate several compression algorithms. See below
+for a comparison of zip and gzip.
+
+gunzip can currently decompress files created by gzip, compress or
+pack. The detection of the input format is automatic.  For the
+gzip format, gunzip checks a 32 bit CRC. For pack, gunzip checks the
+uncompressed length.  The 'compress' format was not designed to allow
+consistency checks. However gunzip is sometimes able to detect a bad
+.Z file because there is some redundancy in the .Z compression format.
+If you get an error when uncompressing a .Z file, do not assume that
+the .Z file is correct simply because the standard uncompress does not
+complain.  This generally means that the standard uncompress does not
+check its input, and happily generates garbage output.
+
+gzip produces files with a .gz extension. Previous versions of gzip
+used the .z extension, which was already used by the 'pack'
+Huffman encoder. gunzip is able to decompress .z files (packed
+or gzip'ed).
+
+Several planned features are not yet supported (see the file TODO).
+See the file NEWS for a summary of changes since 0.5.  See the file
+INSTALL for installation instructions. Some answers to frequently
+asked questions are given in the file INSTALL, please read it. (In
+particular, please don't ask me once more for an /etc/magic entry.)
+
+WARNING: on several systems, compiler bugs cause gzip to fail, in
+particular when optimization options are on.  See the section "Special
+targets" at the end of the INSTALL file for a list of known problems.
+For all machines, use "make check" to check that gzip was compiled
+correctly.  Try compiling gzip without any optimization if you have a
+problem.
+
+Please send all comments and bug reports by electronic mail to:
+   Jean-loup Gailly <jloup@chorus.fr>
+
+or, if this fails, to bug-gnu-utils@prep.ai.mit.edu.
+Bug reports should ideally include:
+
+    * The complete output of "gzip -V" (or the contents of revision.h
+      if you can't get gzip to compile)
+    * The hardware and operating system (try "uname -a")
+    * The compiler used to compile (if it is gcc, use "gcc -v")
+    * A description of the bug behavior
+    * The input to gzip, that triggered the bug
+
+If you send me patches for machines I don't have access to, please test them
+very carefully. gzip is used for backups, it must be extremely reliable.
+
+The package crypt++.el is highly recommended to manipulate gzip'ed
+file from emacs. It recognizes automatically encrypted and compressed
+files when they are first visited or written. It is available via
+anonymous ftp to roebling.poly.edu [128.238.5.31] in /pub/crypt++.el.
+The same directory contains also patches to dired, ange-ftp and info.
+GNU tar 1.11.2 has a -z option to invoke directly gzip, so you don't have to
+patch it. The package ftp.uu.net:/languages/emacs-lisp/misc/jka-compr19.el.Z
+also supports gzip'ed files.
+
+The znew and gzexe shell scripts provided with gzip benefit from
+(but do not require) the cpmod utility to transfer file attributes.
+It is available by anonymous ftp on gatekeeper.dec.com in
+/.0/usenet/comp.sources.unix/volume11/cpmod.Z.
+
+The sample programs zread.c, sub.c and add.c in subdirectory sample
+are provided as examples of useful complements to gzip. Read the
+comments inside each source file.  The perl script ztouch is also
+provided as example (not installed by default since it relies on perl).
+
+
+gzip is free software, you can redistribute it and/or modify it under
+the terms of the GNU General Public License, a copy of which is
+provided under the name COPYING. The latest version of gzip are always
+available by ftp in prep.ai.mit.edu:/pub/gnu, or in any of the prep
+mirror sites:
+
+- sources in gzip-*.tar (or .shar or .tar.gz).
+- Solaris 2 executables in sparc-sun-solaris2/gzip-binaries-*.tar
+- MSDOS lha self-extracting exe in gzip-msdos-*.exe. Once extracted,
+  copy gzip.exe to gunzip.exe and zcat.exe, or use "gzip -d" to decompress.
+  gzip386.exe runs much faster but only on 386 and above; it is compiled with
+  djgpp 1.10 available in directory omnigate.clarkson.edu:/pub/msdos/djgpp.
+
+A VMS executable is available in ftp.spc.edu:[.macro32.savesets]gzip-1-*.zip
+(use [.macro32]unzip.exe to extract). A PRIMOS executable is available
+in ftp.lysator.liu.se:/pub/primos/run/gzip.run.
+OS/2 executables (16 and 32 bits versions) are available in
+ftp.tu-muenchen.de:/pub/comp/os/os2/archiver/gz*-[16,32].zip
+
+Some ftp servers can automatically make a tar.Z from a tar file. If
+you are getting gzip for the first time, you can ask for a tar.Z file
+instead of the much larger tar file.
+
+Many thanks to those who provided me with bug reports and feedback.
+See the files THANKS and ChangeLog for more details.
+
+
+		Note about zip vs. gzip:
+
+The name 'gzip' was a very unfortunate choice, because zip and gzip
+are two really different programs, although the actual compression and
+decompression sources were written by the same persons. A different
+name should have been used for gzip, but it is too late to change now.
+
+zip is an archiver: it compresses several files into a single archive
+file. gzip is a simple compressor: each file is compressed separately.
+Both share the same compression and decompression code for the
+'deflate' method.  unzip can also decompress old zip archives
+(implode, shrink and reduce methods). gunzip can also decompress files
+created by compress and pack. zip 1.9 and gzip do not support
+compression methods other than deflation. (zip 1.0 supports shrink and
+implode). Better compression methods may be added in future versions
+of gzip. zip will always stick to absolute compatibility with pkzip,
+it is thus constrained by PKWare, which is a commercial company.  The
+gzip header format is deliberately different from that of pkzip to
+avoid such a constraint.
+
+On Unix, gzip is mostly useful in combination with tar. GNU tar
+1.11.2 has a -z option to invoke gzip automatically.  "tar -z"
+compresses better than zip, since gzip can then take advantage of
+redundancy between distinct files. The drawback is that you must
+scan the whole tar.gz file in order to extract a single file near
+the end; unzip can directly seek to the end of the zip file. There
+is no overhead when you extract the whole archive anyway.
+If a member of a .zip archive is damaged, other files can still
+be recovered. If a .tar.gz file is damaged, files beyond the failure
+point cannot be recovered. (Future versions of gzip will have
+error recovery features.)
+
+gzip and gunzip are distributed as a single program. zip and unzip
+are, for historical reasons, two separate programs, although the
+authors of these two programs work closely together in the info-zip
+team. zip and unzip are not associated with the GNU project.
+The sources are available by ftp in
+
+	 oak.oakland.edu:/pub/misc/unix/zip19p1.zip
+	 oak.oakland.edu:/pub/misc/unix/unz50p1.tar-z
diff --git a/usr/gzip/bits.c b/usr/gzip/bits.c
new file mode 100644
index 0000000..4707a08
--- /dev/null
+++ b/usr/gzip/bits.c
@@ -0,0 +1,200 @@
+/* bits.c -- output variable-length bit strings
+ * Copyright (C) 1992-1993 Jean-loup Gailly
+ * This is free software; you can redistribute it and/or modify it under the
+ * terms of the GNU General Public License, see the file COPYING.
+ */
+
+
+/*
+ *  PURPOSE
+ *
+ *      Output variable-length bit strings. Compression can be done
+ *      to a file or to memory. (The latter is not supported in this version.)
+ *
+ *  DISCUSSION
+ *
+ *      The PKZIP "deflate" file format interprets compressed file data
+ *      as a sequence of bits.  Multi-bit strings in the file may cross
+ *      byte boundaries without restriction.
+ *
+ *      The first bit of each byte is the low-order bit.
+ *
+ *      The routines in this file allow a variable-length bit value to
+ *      be output right-to-left (useful for literal values). For
+ *      left-to-right output (useful for code strings from the tree routines),
+ *      the bits must have been reversed first with bi_reverse().
+ *
+ *      For in-memory compression, the compressed bit stream goes directly
+ *      into the requested output buffer. The input data is read in blocks
+ *      by the mem_read() function. The buffer is limited to 64K on 16 bit
+ *      machines.
+ *
+ *  INTERFACE
+ *
+ *      void bi_init (FILE *zipfile)
+ *          Initialize the bit string routines.
+ *
+ *      void send_bits (int value, int length)
+ *          Write out a bit string, taking the source bits right to
+ *          left.
+ *
+ *      int bi_reverse (int value, int length)
+ *          Reverse the bits of a bit string, taking the source bits left to
+ *          right and emitting them right to left.
+ *
+ *      void bi_windup (void)
+ *          Write out any remaining bits in an incomplete byte.
+ *
+ *      void copy_block(char *buf, unsigned len, int header)
+ *          Copy a stored block to the zip file, storing first the length and
+ *          its one's complement if requested.
+ *
+ */
+
+#include "tailor.h"
+#include "gzip.h"
+
+#ifdef DEBUG
+#  include <stdio.h>
+#endif
+
+#ifdef RCSID
+static char rcsid[] = "$Id: bits.c,v 1.1 2002/08/18 00:59:21 hpa Exp $";
+#endif
+
+/* ===========================================================================
+ * Local data used by the "bit string" routines.
+ */
+
+local file_t zfile; /* output gzip file */
+
+local unsigned short bi_buf;
+/* Output buffer. bits are inserted starting at the bottom (least significant
+ * bits).
+ */
+
+#define Buf_size (8 * 2*sizeof(char))
+/* Number of bits used within bi_buf. (bi_buf might be implemented on
+ * more than 16 bits on some systems.)
+ */
+
+local int bi_valid;
+/* Number of valid bits in bi_buf.  All bits above the last valid bit
+ * are always zero.
+ */
+
+int (*read_buf) OF((char *buf, unsigned size));
+/* Current input function. Set to mem_read for in-memory compression */
+
+#ifdef DEBUG
+  ulg bits_sent;   /* bit length of the compressed data */
+#endif
+
+/* ===========================================================================
+ * Initialize the bit string routines.
+ */
+void bi_init (zipfile)
+    file_t zipfile; /* output zip file, NO_FILE for in-memory compression */
+{
+    zfile  = zipfile;
+    bi_buf = 0;
+    bi_valid = 0;
+#ifdef DEBUG
+    bits_sent = 0L;
+#endif
+
+    /* Set the defaults for file compression. They are set by memcompress
+     * for in-memory compression.
+     */
+    if (zfile != NO_FILE) {
+	read_buf  = file_read;
+    }
+}
+
+/* ===========================================================================
+ * Send a value on a given number of bits.
+ * IN assertion: length <= 16 and value fits in length bits.
+ */
+void send_bits(value, length)
+    int value;  /* value to send */
+    int length; /* number of bits */
+{
+#ifdef DEBUG
+    Tracev((stderr," l %2d v %4x ", length, value));
+    Assert(length > 0 && length <= 15, "invalid length");
+    bits_sent += (ulg)length;
+#endif
+    /* If not enough room in bi_buf, use (valid) bits from bi_buf and
+     * (16 - bi_valid) bits from value, leaving (width - (16-bi_valid))
+     * unused bits in value.
+     */
+    if (bi_valid > (int)Buf_size - length) {
+        bi_buf |= (value << bi_valid);
+        put_short(bi_buf);
+        bi_buf = (ush)value >> (Buf_size - bi_valid);
+        bi_valid += length - Buf_size;
+    } else {
+        bi_buf |= value << bi_valid;
+        bi_valid += length;
+    }
+}
+
+/* ===========================================================================
+ * Reverse the first len bits of a code, using straightforward code (a faster
+ * method would use a table)
+ * IN assertion: 1 <= len <= 15
+ */
+unsigned bi_reverse(code, len)
+    unsigned code; /* the value to invert */
+    int len;       /* its bit length */
+{
+    register unsigned res = 0;
+    do {
+        res |= code & 1;
+        code >>= 1, res <<= 1;
+    } while (--len > 0);
+    return res >> 1;
+}
+
+/* ===========================================================================
+ * Write out any remaining bits in an incomplete byte.
+ */
+void bi_windup()
+{
+    if (bi_valid > 8) {
+        put_short(bi_buf);
+    } else if (bi_valid > 0) {
+        put_byte(bi_buf);
+    }
+    bi_buf = 0;
+    bi_valid = 0;
+#ifdef DEBUG
+    bits_sent = (bits_sent+7) & ~7;
+#endif
+}
+
+/* ===========================================================================
+ * Copy a stored block to the zip file, storing first the length and its
+ * one's complement if requested.
+ */
+void copy_block(buf, len, header)
+    char     *buf;    /* the input data */
+    unsigned len;     /* its length */
+    int      header;  /* true if block header must be written */
+{
+    bi_windup();              /* align on byte boundary */
+
+    if (header) {
+        put_short((ush)len);
+        put_short((ush)~len);
+#ifdef DEBUG
+        bits_sent += 2*16;
+#endif
+    }
+#ifdef DEBUG
+    bits_sent += (ulg)len<<3;
+#endif
+    while (len--) {
+	put_byte(*buf++);
+    }
+}
diff --git a/usr/gzip/deflate.c b/usr/gzip/deflate.c
new file mode 100644
index 0000000..1db44fd
--- /dev/null
+++ b/usr/gzip/deflate.c
@@ -0,0 +1,759 @@
+/* deflate.c -- compress data using the deflation algorithm
+ * Copyright (C) 1992-1993 Jean-loup Gailly
+ * This is free software; you can redistribute it and/or modify it under the
+ * terms of the GNU General Public License, see the file COPYING.
+ */
+
+/*
+ *  PURPOSE
+ *
+ *      Identify new text as repetitions of old text within a fixed-
+ *      length sliding window trailing behind the new text.
+ *
+ *  DISCUSSION
+ *
+ *      The "deflation" process depends on being able to identify portions
+ *      of the input text which are identical to earlier input (within a
+ *      sliding window trailing behind the input currently being processed).
+ *
+ *      The most straightforward technique turns out to be the fastest for
+ *      most input files: try all possible matches and select the longest.
+ *      The key feature of this algorithm is that insertions into the string
+ *      dictionary are very simple and thus fast, and deletions are avoided
+ *      completely. Insertions are performed at each input character, whereas
+ *      string matches are performed only when the previous match ends. So it
+ *      is preferable to spend more time in matches to allow very fast string
+ *      insertions and avoid deletions. The matching algorithm for small
+ *      strings is inspired from that of Rabin & Karp. A brute force approach
+ *      is used to find longer strings when a small match has been found.
+ *      A similar algorithm is used in comic (by Jan-Mark Wams) and freeze
+ *      (by Leonid Broukhis).
+ *         A previous version of this file used a more sophisticated algorithm
+ *      (by Fiala and Greene) which is guaranteed to run in linear amortized
+ *      time, but has a larger average cost, uses more memory and is patented.
+ *      However the F&G algorithm may be faster for some highly redundant
+ *      files if the parameter max_chain_length (described below) is too large.
+ *
+ *  ACKNOWLEDGEMENTS
+ *
+ *      The idea of lazy evaluation of matches is due to Jan-Mark Wams, and
+ *      I found it in 'freeze' written by Leonid Broukhis.
+ *      Thanks to many info-zippers for bug reports and testing.
+ *
+ *  REFERENCES
+ *
+ *      APPNOTE.TXT documentation file in PKZIP 1.93a distribution.
+ *
+ *      A description of the Rabin and Karp algorithm is given in the book
+ *         "Algorithms" by R. Sedgewick, Addison-Wesley, p252.
+ *
+ *      Fiala,E.R., and Greene,D.H.
+ *         Data Compression with Finite Windows, Comm.ACM, 32,4 (1989) 490-595
+ *
+ *  INTERFACE
+ *
+ *      void lm_init (int pack_level, ush *flags)
+ *          Initialize the "longest match" routines for a new file
+ *
+ *      ulg deflate (void)
+ *          Processes a new input file and return its compressed length. Sets
+ *          the compressed length, crc, deflate flags and internal file
+ *          attributes.
+ */
+
+#include <stdio.h>
+
+#include "tailor.h"
+#include "gzip.h"
+
+#ifdef RCSID
+static char rcsid[] = "$Id: deflate.c,v 1.1 2002/08/18 00:59:21 hpa Exp $";
+#endif
+
+/* ===========================================================================
+ * Configuration parameters
+ */
+
+/* Compile with MEDIUM_MEM to reduce the memory requirements or
+ * with SMALL_MEM to use as little memory as possible. Use BIG_MEM if the
+ * entire input file can be held in memory (not possible on 16 bit systems).
+ * Warning: defining these symbols affects HASH_BITS (see below) and thus
+ * affects the compression ratio. The compressed output
+ * is still correct, and might even be smaller in some cases.
+ */
+
+#ifdef SMALL_MEM
+#   define HASH_BITS  13  /* Number of bits used to hash strings */
+#endif
+#ifdef MEDIUM_MEM
+#   define HASH_BITS  14
+#endif
+#ifndef HASH_BITS
+#   define HASH_BITS  15
+   /* For portability to 16 bit machines, do not use values above 15. */
+#endif
+
+/* To save space (see unlzw.c), we overlay prev+head with tab_prefix and
+ * window with tab_suffix. Check that we can do this:
+ */
+#if (WSIZE<<1) > (1<<BITS)
+   error: cannot overlay window with tab_suffix and prev with tab_prefix0
+#endif
+#if HASH_BITS > BITS-1
+   error: cannot overlay head with tab_prefix1
+#endif
+
+#define HASH_SIZE (unsigned)(1<<HASH_BITS)
+#define HASH_MASK (HASH_SIZE-1)
+#define WMASK     (WSIZE-1)
+/* HASH_SIZE and WSIZE must be powers of two */
+
+#define NIL 0
+/* Tail of hash chains */
+
+#define FAST 4
+#define SLOW 2
+/* speed options for the general purpose bit flag */
+
+#ifndef TOO_FAR
+#  define TOO_FAR 4096
+#endif
+/* Matches of length 3 are discarded if their distance exceeds TOO_FAR */
+
+/* ===========================================================================
+ * Local data used by the "longest match" routines.
+ */
+
+typedef ush Pos;
+typedef unsigned IPos;
+/* A Pos is an index in the character window. We use short instead of int to
+ * save space in the various tables. IPos is used only for parameter passing.
+ */
+
+/* DECLARE(uch, window, 2L*WSIZE); */
+/* Sliding window. Input bytes are read into the second half of the window,
+ * and move to the first half later to keep a dictionary of at least WSIZE
+ * bytes. With this organization, matches are limited to a distance of
+ * WSIZE-MAX_MATCH bytes, but this ensures that IO is always
+ * performed with a length multiple of the block size. Also, it limits
+ * the window size to 64K, which is quite useful on MSDOS.
+ * To do: limit the window size to WSIZE+BSZ if SMALL_MEM (the code would
+ * be less efficient).
+ */
+
+/* DECLARE(Pos, prev, WSIZE); */
+/* Link to older string with same hash index. To limit the size of this
+ * array to 64K, this link is maintained only for the last 32K strings.
+ * An index in this array is thus a window index modulo 32K.
+ */
+
+/* DECLARE(Pos, head, 1<<HASH_BITS); */
+/* Heads of the hash chains or NIL. */
+
+ulg window_size = (ulg)2*WSIZE;
+/* window size, 2*WSIZE except for MMAP or BIG_MEM, where it is the
+ * input file length plus MIN_LOOKAHEAD.
+ */
+
+long block_start;
+/* window position at the beginning of the current output block. Gets
+ * negative when the window is moved backwards.
+ */
+
+local unsigned ins_h;  /* hash index of string to be inserted */
+
+#define H_SHIFT  ((HASH_BITS+MIN_MATCH-1)/MIN_MATCH)
+/* Number of bits by which ins_h and del_h must be shifted at each
+ * input step. It must be such that after MIN_MATCH steps, the oldest
+ * byte no longer takes part in the hash key, that is:
+ *   H_SHIFT * MIN_MATCH >= HASH_BITS
+ */
+
+unsigned int prev_length;
+/* Length of the best match at previous step. Matches not greater than this
+ * are discarded. This is used in the lazy match evaluation.
+ */
+
+      unsigned      strstart;      /* start of string to insert */
+      unsigned      match_start;   /* start of matching string */
+local int           eofile;        /* flag set at end of input file */
+local unsigned      lookahead;     /* number of valid bytes ahead in window */
+
+unsigned max_chain_length;
+/* To speed up deflation, hash chains are never searched beyond this length.
+ * A higher limit improves compression ratio but degrades the speed.
+ */
+
+local unsigned int max_lazy_match;
+/* Attempt to find a better match only when the current match is strictly
+ * smaller than this value. This mechanism is used only for compression
+ * levels >= 4.
+ */
+#define max_insert_length  max_lazy_match
+/* Insert new strings in the hash table only if the match length
+ * is not greater than this length. This saves time but degrades compression.
+ * max_insert_length is used only for compression levels <= 3.
+ */
+
+local int compr_level;
+/* compression level (1..9) */
+
+unsigned good_match;
+/* Use a faster search when the previous match is longer than this */
+
+
+/* Values for max_lazy_match, good_match and max_chain_length, depending on
+ * the desired pack level (0..9). The values given below have been tuned to
+ * exclude worst case performance for pathological files. Better values may be
+ * found for specific files.
+ */
+
+typedef struct config {
+   ush good_length; /* reduce lazy search above this match length */
+   ush max_lazy;    /* do not perform lazy search above this match length */
+   ush nice_length; /* quit search above this match length */
+   ush max_chain;
+} config;
+
+#ifdef  FULL_SEARCH
+# define nice_match MAX_MATCH
+#else
+  int nice_match; /* Stop searching when current match exceeds this */
+#endif
+
+local config configuration_table[10] = {
+/*      good lazy nice chain */
+/* 0 */ {0,    0,  0,    0},  /* store only */
+/* 1 */ {4,    4,  8,    4},  /* maximum speed, no lazy matches */
+/* 2 */ {4,    5, 16,    8},
+/* 3 */ {4,    6, 32,   32},
+
+/* 4 */ {4,    4, 16,   16},  /* lazy matches */
+/* 5 */ {8,   16, 32,   32},
+/* 6 */ {8,   16, 128, 128},
+/* 7 */ {8,   32, 128, 256},
+/* 8 */ {32, 128, 258, 1024},
+/* 9 */ {32, 258, 258, 4096}}; /* maximum compression */
+
+/* Note: the deflate() code requires max_lazy >= MIN_MATCH and max_chain >= 4
+ * For deflate_fast() (levels <= 3) good is ignored and lazy has a different
+ * meaning.
+ */
+
+#define EQUAL 0
+/* result of memcmp for equal strings */
+
+/* ===========================================================================
+ *  Prototypes for local functions.
+ */
+local void fill_window   OF((void));
+local ulg deflate_fast   OF((void));
+
+      int  longest_match OF((IPos cur_match));
+#ifdef ASMV
+      void match_init OF((void)); /* asm code initialization */
+#endif
+
+#ifdef DEBUG
+local  void check_match OF((IPos start, IPos match, int length));
+#endif
+
+/* ===========================================================================
+ * Update a hash value with the given input byte
+ * IN  assertion: all calls to to UPDATE_HASH are made with consecutive
+ *    input characters, so that a running hash key can be computed from the
+ *    previous key instead of complete recalculation each time.
+ */
+#define UPDATE_HASH(h,c) (h = (((h)<<H_SHIFT) ^ (c)) & HASH_MASK)
+
+/* ===========================================================================
+ * Insert string s in the dictionary and set match_head to the previous head
+ * of the hash chain (the most recent string with same hash key). Return
+ * the previous length of the hash chain.
+ * IN  assertion: all calls to to INSERT_STRING are made with consecutive
+ *    input characters and the first MIN_MATCH bytes of s are valid
+ *    (except for the last MIN_MATCH-1 bytes of the input file).
+ */
+#define INSERT_STRING(s, match_head) \
+   (UPDATE_HASH(ins_h, window[(s) + MIN_MATCH-1]), \
+    prev[(s) & WMASK] = match_head = head[ins_h], \
+    head[ins_h] = (s))
+
+/* ===========================================================================
+ * Initialize the "longest match" routines for a new file
+ */
+void lm_init (pack_level, flags)
+    int pack_level; /* 0: store, 1: best speed, 9: best compression */
+    ush *flags;     /* general purpose bit flag */
+{
+    register unsigned j;
+
+    if (pack_level < 1 || pack_level > 9) error("bad pack level");
+    compr_level = pack_level;
+
+    /* Initialize the hash table. */
+    memzero((char*)head, HASH_SIZE*sizeof(*head));
+
+    /* prev will be initialized on the fly */
+
+    /* Set the default configuration parameters:
+     */
+    max_lazy_match   = configuration_table[pack_level].max_lazy;
+    good_match       = configuration_table[pack_level].good_length;
+#ifndef FULL_SEARCH
+    nice_match       = configuration_table[pack_level].nice_length;
+#endif
+    max_chain_length = configuration_table[pack_level].max_chain;
+    if (pack_level == 1) {
+       *flags |= FAST;
+    } else if (pack_level == 9) {
+       *flags |= SLOW;
+    }
+    /* ??? reduce max_chain_length for binary files */
+
+    strstart = 0;
+    block_start = 0L;
+#ifdef ASMV
+    match_init(); /* initialize the asm code */
+#endif
+
+    lookahead = read_buf((char*)window,
+			 sizeof(int) <= 2 ? (unsigned)WSIZE : 2*WSIZE);
+
+    if (lookahead == 0 || lookahead == (unsigned)EOF) {
+       eofile = 1, lookahead = 0;
+       return;
+    }
+    eofile = 0;
+    /* Make sure that we always have enough lookahead. This is important
+     * if input comes from a device such as a tty.
+     */
+    while (lookahead < MIN_LOOKAHEAD && !eofile) fill_window();
+
+    ins_h = 0;
+    for (j=0; j<MIN_MATCH-1; j++) UPDATE_HASH(ins_h, window[j]);
+    /* If lookahead < MIN_MATCH, ins_h is garbage, but this is
+     * not important since only literal bytes will be emitted.
+     */
+}
+
+/* ===========================================================================
+ * Set match_start to the longest match starting at the given string and
+ * return its length. Matches shorter or equal to prev_length are discarded,
+ * in which case the result is equal to prev_length and match_start is
+ * garbage.
+ * IN assertions: cur_match is the head of the hash chain for the current
+ *   string (strstart) and its distance is <= MAX_DIST, and prev_length >= 1
+ */
+#ifndef ASMV
+/* For MSDOS, OS/2 and 386 Unix, an optimized version is in match.asm or
+ * match.s. The code is functionally equivalent, so you can use the C version
+ * if desired.
+ */
+int longest_match(cur_match)
+    IPos cur_match;                             /* current match */
+{
+    unsigned chain_length = max_chain_length;   /* max hash chain length */
+    register uch *scan = window + strstart;     /* current string */
+    register uch *match;                        /* matched string */
+    register int len;                           /* length of current match */
+    int best_len = prev_length;                 /* best match length so far */
+    IPos limit = strstart > (IPos)MAX_DIST ? strstart - (IPos)MAX_DIST : NIL;
+    /* Stop when cur_match becomes <= limit. To simplify the code,
+     * we prevent matches with the string of window index 0.
+     */
+
+/* The code is optimized for HASH_BITS >= 8 and MAX_MATCH-2 multiple of 16.
+ * It is easy to get rid of this optimization if necessary.
+ */
+#if HASH_BITS < 8 || MAX_MATCH != 258
+   error: Code too clever
+#endif
+
+#ifdef UNALIGNED_OK
+    /* Compare two bytes at a time. Note: this is not always beneficial.
+     * Try with and without -DUNALIGNED_OK to check.
+     */
+    register uch *strend = window + strstart + MAX_MATCH - 1;
+    register ush scan_start = *(ush*)scan;
+    register ush scan_end   = *(ush*)(scan+best_len-1);
+#else
+    register uch *strend = window + strstart + MAX_MATCH;
+    register uch scan_end1  = scan[best_len-1];
+    register uch scan_end   = scan[best_len];
+#endif
+
+    /* Do not waste too much time if we already have a good match: */
+    if (prev_length >= good_match) {
+        chain_length >>= 2;
+    }
+    Assert(strstart <= window_size-MIN_LOOKAHEAD, "insufficient lookahead");
+
+    do {
+        Assert(cur_match < strstart, "no future");
+        match = window + cur_match;
+
+        /* Skip to next match if the match length cannot increase
+         * or if the match length is less than 2:
+         */
+#if (defined(UNALIGNED_OK) && MAX_MATCH == 258)
+        /* This code assumes sizeof(unsigned short) == 2. Do not use
+         * UNALIGNED_OK if your compiler uses a different size.
+         */
+        if (*(ush*)(match+best_len-1) != scan_end ||
+            *(ush*)match != scan_start) continue;
+
+        /* It is not necessary to compare scan[2] and match[2] since they are
+         * always equal when the other bytes match, given that the hash keys
+         * are equal and that HASH_BITS >= 8. Compare 2 bytes at a time at
+         * strstart+3, +5, ... up to strstart+257. We check for insufficient
+         * lookahead only every 4th comparison; the 128th check will be made
+         * at strstart+257. If MAX_MATCH-2 is not a multiple of 8, it is
+         * necessary to put more guard bytes at the end of the window, or
+         * to check more often for insufficient lookahead.
+         */
+        scan++, match++;
+        do {
+        } while (*(ush*)(scan+=2) == *(ush*)(match+=2) &&
+                 *(ush*)(scan+=2) == *(ush*)(match+=2) &&
+                 *(ush*)(scan+=2) == *(ush*)(match+=2) &&
+                 *(ush*)(scan+=2) == *(ush*)(match+=2) &&
+                 scan < strend);
+        /* The funny "do {}" generates better code on most compilers */
+
+        /* Here, scan <= window+strstart+257 */
+        Assert(scan <= window+(unsigned)(window_size-1), "wild scan");
+        if (*scan == *match) scan++;
+
+        len = (MAX_MATCH - 1) - (int)(strend-scan);
+        scan = strend - (MAX_MATCH-1);
+
+#else /* UNALIGNED_OK */
+
+        if (match[best_len]   != scan_end  ||
+            match[best_len-1] != scan_end1 ||
+            *match            != *scan     ||
+            *++match          != scan[1])      continue;
+
+        /* The check at best_len-1 can be removed because it will be made
+         * again later. (This heuristic is not always a win.)
+         * It is not necessary to compare scan[2] and match[2] since they
+         * are always equal when the other bytes match, given that
+         * the hash keys are equal and that HASH_BITS >= 8.
+         */
+        scan += 2, match++;
+
+        /* We check for insufficient lookahead only every 8th comparison;
+         * the 256th check will be made at strstart+258.
+         */
+        do {
+        } while (*++scan == *++match && *++scan == *++match &&
+                 *++scan == *++match && *++scan == *++match &&
+                 *++scan == *++match && *++scan == *++match &&
+                 *++scan == *++match && *++scan == *++match &&
+                 scan < strend);
+
+        len = MAX_MATCH - (int)(strend - scan);
+        scan = strend - MAX_MATCH;
+
+#endif /* UNALIGNED_OK */
+
+        if (len > best_len) {
+            match_start = cur_match;
+            best_len = len;
+            if (len >= nice_match) break;
+#ifdef UNALIGNED_OK
+            scan_end = *(ush*)(scan+best_len-1);
+#else
+            scan_end1  = scan[best_len-1];
+            scan_end   = scan[best_len];
+#endif
+        }
+    } while ((cur_match = prev[cur_match & WMASK]) > limit
+	     && --chain_length != 0);
+
+    return best_len;
+}
+#endif /* ASMV */
+
+#ifdef DEBUG
+/* ===========================================================================
+ * Check that the match at match_start is indeed a match.
+ */
+local void check_match(start, match, length)
+    IPos start, match;
+    int length;
+{
+    /* check that the match is indeed a match */
+    if (memcmp((char*)window + match,
+                (char*)window + start, length) != EQUAL) {
+        fprintf(stderr,
+            " start %d, match %d, length %d\n",
+            start, match, length);
+        error("invalid match");
+    }
+    if (verbose > 1) {
+        fprintf(stderr,"\\[%d,%d]", start-match, length);
+        do { putc(window[start++], stderr); } while (--length != 0);
+    }
+}
+#else
+#  define check_match(start, match, length)
+#endif
+
+/* ===========================================================================
+ * Fill the window when the lookahead becomes insufficient.
+ * Updates strstart and lookahead, and sets eofile if end of input file.
+ * IN assertion: lookahead < MIN_LOOKAHEAD && strstart + lookahead > 0
+ * OUT assertions: at least one byte has been read, or eofile is set;
+ *    file reads are performed for at least two bytes (required for the
+ *    translate_eol option).
+ */
+local void fill_window()
+{
+    register unsigned n, m;
+    unsigned more = (unsigned)(window_size - (ulg)lookahead - (ulg)strstart);
+    /* Amount of free space at the end of the window. */
+
+    /* If the window is almost full and there is insufficient lookahead,
+     * move the upper half to the lower one to make room in the upper half.
+     */
+    if (more == (unsigned)EOF) {
+        /* Very unlikely, but possible on 16 bit machine if strstart == 0
+         * and lookahead == 1 (input done one byte at time)
+         */
+        more--;
+    } else if (strstart >= WSIZE+MAX_DIST) {
+        /* By the IN assertion, the window is not empty so we can't confuse
+         * more == 0 with more == 64K on a 16 bit machine.
+         */
+        Assert(window_size == (ulg)2*WSIZE, "no sliding with BIG_MEM");
+
+        memcpy((char*)window, (char*)window+WSIZE, (unsigned)WSIZE);
+        match_start -= WSIZE;
+        strstart    -= WSIZE; /* we now have strstart >= MAX_DIST: */
+
+        block_start -= (long) WSIZE;
+
+        for (n = 0; n < HASH_SIZE; n++) {
+            m = head[n];
+            head[n] = (Pos)(m >= WSIZE ? m-WSIZE : NIL);
+        }
+        for (n = 0; n < WSIZE; n++) {
+            m = prev[n];
+            prev[n] = (Pos)(m >= WSIZE ? m-WSIZE : NIL);
+            /* If n is not on any hash chain, prev[n] is garbage but
+             * its value will never be used.
+             */
+        }
+        more += WSIZE;
+    }
+    /* At this point, more >= 2 */
+    if (!eofile) {
+        n = read_buf((char*)window+strstart+lookahead, more);
+        if (n == 0 || n == (unsigned)EOF) {
+            eofile = 1;
+        } else {
+            lookahead += n;
+        }
+    }
+}
+
+/* ===========================================================================
+ * Flush the current block, with given end-of-file flag.
+ * IN assertion: strstart is set to the end of the current match.
+ */
+#define FLUSH_BLOCK(eof) \
+   flush_block(block_start >= 0L ? (char*)&window[(unsigned)block_start] : \
+                (char*)NULL, (long)strstart - block_start, (eof))
+
+/* ===========================================================================
+ * Processes a new input file and return its compressed length. This
+ * function does not perform lazy evaluationof matches and inserts
+ * new strings in the dictionary only for unmatched strings or for short
+ * matches. It is used only for the fast compression options.
+ */
+local ulg deflate_fast()
+{
+    IPos hash_head; /* head of the hash chain */
+    int flush;      /* set if current block must be flushed */
+    unsigned match_length = 0;  /* length of best match */
+
+    prev_length = MIN_MATCH-1;
+    while (lookahead != 0) {
+        /* Insert the string window[strstart .. strstart+2] in the
+         * dictionary, and set hash_head to the head of the hash chain:
+         */
+        INSERT_STRING(strstart, hash_head);
+
+        /* Find the longest match, discarding those <= prev_length.
+         * At this point we have always match_length < MIN_MATCH
+         */
+        if (hash_head != NIL && strstart - hash_head <= MAX_DIST) {
+            /* To simplify the code, we prevent matches with the string
+             * of window index 0 (in particular we have to avoid a match
+             * of the string with itself at the start of the input file).
+             */
+            match_length = longest_match (hash_head);
+            /* longest_match() sets match_start */
+            if (match_length > lookahead) match_length = lookahead;
+        }
+        if (match_length >= MIN_MATCH) {
+            check_match(strstart, match_start, match_length);
+
+            flush = ct_tally(strstart-match_start, match_length - MIN_MATCH);
+
+            lookahead -= match_length;
+
+	    /* Insert new strings in the hash table only if the match length
+             * is not too large. This saves time but degrades compression.
+             */
+            if (match_length <= max_insert_length) {
+                match_length--; /* string at strstart already in hash table */
+                do {
+                    strstart++;
+                    INSERT_STRING(strstart, hash_head);
+                    /* strstart never exceeds WSIZE-MAX_MATCH, so there are
+                     * always MIN_MATCH bytes ahead. If lookahead < MIN_MATCH
+                     * these bytes are garbage, but it does not matter since
+                     * the next lookahead bytes will be emitted as literals.
+                     */
+                } while (--match_length != 0);
+	        strstart++;
+            } else {
+	        strstart += match_length;
+	        match_length = 0;
+	        ins_h = window[strstart];
+	        UPDATE_HASH(ins_h, window[strstart+1]);
+#if MIN_MATCH != 3
+                Call UPDATE_HASH() MIN_MATCH-3 more times
+#endif
+            }
+        } else {
+            /* No match, output a literal byte */
+            Tracevv((stderr,"%c",window[strstart]));
+            flush = ct_tally (0, window[strstart]);
+            lookahead--;
+	    strstart++;
+        }
+        if (flush) FLUSH_BLOCK(0), block_start = strstart;
+
+        /* Make sure that we always have enough lookahead, except
+         * at the end of the input file. We need MAX_MATCH bytes
+         * for the next match, plus MIN_MATCH bytes to insert the
+         * string following the next match.
+         */
+        while (lookahead < MIN_LOOKAHEAD && !eofile) fill_window();
+
+    }
+    return FLUSH_BLOCK(1); /* eof */
+}
+
+/* ===========================================================================
+ * Same as above, but achieves better compression. We use a lazy
+ * evaluation for matches: a match is finally adopted only if there is
+ * no better match at the next window position.
+ */
+ulg deflate()
+{
+    IPos hash_head;          /* head of hash chain */
+    IPos prev_match;         /* previous match */
+    int flush;               /* set if current block must be flushed */
+    int match_available = 0; /* set if previous match exists */
+    register unsigned match_length = MIN_MATCH-1; /* length of best match */
+#ifdef DEBUG
+    extern long isize;        /* byte length of input file, for debug only */
+#endif
+
+    if (compr_level <= 3) return deflate_fast(); /* optimized for speed */
+
+    /* Process the input block. */
+    while (lookahead != 0) {
+        /* Insert the string window[strstart .. strstart+2] in the
+         * dictionary, and set hash_head to the head of the hash chain:
+         */
+        INSERT_STRING(strstart, hash_head);
+
+        /* Find the longest match, discarding those <= prev_length.
+         */
+        prev_length = match_length, prev_match = match_start;
+        match_length = MIN_MATCH-1;
+
+        if (hash_head != NIL && prev_length < max_lazy_match &&
+            strstart - hash_head <= MAX_DIST) {
+            /* To simplify the code, we prevent matches with the string
+             * of window index 0 (in particular we have to avoid a match
+             * of the string with itself at the start of the input file).
+             */
+            match_length = longest_match (hash_head);
+            /* longest_match() sets match_start */
+            if (match_length > lookahead) match_length = lookahead;
+
+            /* Ignore a length 3 match if it is too distant: */
+            if (match_length == MIN_MATCH && strstart-match_start > TOO_FAR){
+                /* If prev_match is also MIN_MATCH, match_start is garbage
+                 * but we will ignore the current match anyway.
+                 */
+                match_length--;
+            }
+        }
+        /* If there was a match at the previous step and the current
+         * match is not better, output the previous match:
+         */
+        if (prev_length >= MIN_MATCH && match_length <= prev_length) {
+
+            check_match(strstart-1, prev_match, prev_length);
+
+            flush = ct_tally(strstart-1-prev_match, prev_length - MIN_MATCH);
+
+            /* Insert in hash table all strings up to the end of the match.
+             * strstart-1 and strstart are already inserted.
+             */
+            lookahead -= prev_length-1;
+            prev_length -= 2;
+            do {
+                strstart++;
+                INSERT_STRING(strstart, hash_head);
+                /* strstart never exceeds WSIZE-MAX_MATCH, so there are
+                 * always MIN_MATCH bytes ahead. If lookahead < MIN_MATCH
+                 * these bytes are garbage, but it does not matter since the
+                 * next lookahead bytes will always be emitted as literals.
+                 */
+            } while (--prev_length != 0);
+            match_available = 0;
+            match_length = MIN_MATCH-1;
+            strstart++;
+            if (flush) FLUSH_BLOCK(0), block_start = strstart;
+
+        } else if (match_available) {
+            /* If there was no match at the previous position, output a
+             * single literal. If there was a match but the current match
+             * is longer, truncate the previous match to a single literal.
+             */
+            Tracevv((stderr,"%c",window[strstart-1]));
+            if (ct_tally (0, window[strstart-1])) {
+                FLUSH_BLOCK(0), block_start = strstart;
+            }
+            strstart++;
+            lookahead--;
+        } else {
+            /* There is no previous match to compare with, wait for
+             * the next step to decide.
+             */
+            match_available = 1;
+            strstart++;
+            lookahead--;
+        }
+        Assert (strstart <= isize && lookahead <= isize, "a bit too far");
+
+        /* Make sure that we always have enough lookahead, except
+         * at the end of the input file. We need MAX_MATCH bytes
+         * for the next match, plus MIN_MATCH bytes to insert the
+         * string following the next match.
+         */
+        while (lookahead < MIN_LOOKAHEAD && !eofile) fill_window();
+    }
+    if (match_available) ct_tally (0, window[strstart-1]);
+
+    return FLUSH_BLOCK(1); /* eof */
+}
diff --git a/usr/gzip/gzip.c b/usr/gzip/gzip.c
new file mode 100644
index 0000000..8f4c121
--- /dev/null
+++ b/usr/gzip/gzip.c
@@ -0,0 +1,1214 @@
+/* gzip (GNU zip) -- compress files with zip algorithm and 'compress' interface
+ * Copyright (C) 1992-1993 Jean-loup Gailly
+ * The unzip code was written and put in the public domain by Mark Adler.
+ * Portions of the lzw code are derived from the public domain 'compress'
+ * written by Spencer Thomas, Joe Orost, James Woods, Jim McKie, Steve Davies,
+ * Ken Turkowski, Dave Mack and Peter Jannesen.
+ *
+ * See the license_msg below and the file COPYING for the software license.
+ * See the file algorithm.doc for the compression algorithms and file formats.
+ */
+
+static char  *license_msg[] = {
+"   Copyright (C) 1992-1993 Jean-loup Gailly",
+"   This program is free software; you can redistribute it and/or modify",
+"   it under the terms of the GNU General Public License as published by",
+"   the Free Software Foundation; either version 2, or (at your option)",
+"   any later version.",
+"",
+"   This program 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 General Public License for more details.",
+"",
+"   You should have received a copy of the GNU General Public License",
+"   along with this program; if not, write to the Free Software",
+"   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.",
+0};
+
+/* Compress files with zip algorithm and 'compress' interface.
+ * See usage() and help() functions below for all options.
+ * Outputs:
+ *        file.gz:   compressed file with same mode, owner, and utimes
+ *     or stdout with -c option or if stdin used as input.
+ * If the output file name had to be truncated, the original name is kept
+ * in the compressed file.
+ * On MSDOS, file.tmp -> file.tmz. On VMS, file.tmp -> file.tmp-gz.
+ *
+ * Using gz on MSDOS would create too many file name conflicts. For
+ * example, foo.txt -> foo.tgz (.tgz must be reserved as shorthand for
+ * tar.gz). Similarly, foo.dir and foo.doc would both be mapped to foo.dgz.
+ * I also considered 12345678.txt -> 12345txt.gz but this truncates the name
+ * too heavily. There is no ideal solution given the MSDOS 8+3 limitation.
+ *
+ * For the meaning of all compilation flags, see comments in Makefile.in.
+ */
+
+#ifdef RCSID
+static char rcsid[] = "$Id: gzip.c,v 1.3 2005/02/12 21:03:28 olh Exp $";
+#endif
+
+#include <ctype.h>
+#include <sys/types.h>
+#include <signal.h>
+#include <sys/stat.h>
+#include <errno.h>
+
+#include "tailor.h"
+#include "gzip.h"
+#include "revision.h"
+
+#include <time.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdlib.h>
+
+#include <utime.h>
+
+typedef void (*sig_type) OF((int));
+
+#define RW_USER (S_IRUSR | S_IWUSR)  /* creation mode for open() */
+
+#ifndef MAX_PATH_LEN
+#  define MAX_PATH_LEN   1024 /* max pathname length */
+#endif
+
+		/* global buffers */
+
+DECLARE(uch, inbuf,  INBUFSIZ +INBUF_EXTRA);
+DECLARE(uch, outbuf, OUTBUFSIZ+OUTBUF_EXTRA);
+DECLARE(ush, d_buf,  DIST_BUFSIZE);
+DECLARE(uch, window, 2L*WSIZE);
+DECLARE(ush, tab_prefix, 1L<<BITS);
+
+		/* local variables */
+
+#ifndef SUPPORT_ZIP
+#define decompress 1
+#else
+int level = 6;        /* compression level */
+#endif
+
+int to_stdout;        /* output to stdout (-c) */
+#ifndef decompress
+int decompress;       /* decompress (-d) */
+#endif
+int force;            /* don't ask questions, compress links (-f) */
+int no_name = -1;     /* don't save or restore the original file name */
+int no_time = -1;     /* don't save or restore the original file time */
+int verbose;          /* be verbose (-v) */
+int quiet;            /* be very quiet (-q) */
+int test;             /* test .gz file integrity */
+int foreground;       /* set if program run in foreground */
+char *progname;       /* program name */
+int method = DEFLATED;/* compression method */
+int exit_code = OK;   /* program exit code */
+int save_orig_name;   /* set if original name must be saved */
+int last_member;      /* set for .zip and .Z files */
+int part_nb;          /* number of parts in .gz file */
+time_t time_stamp; /* original time stamp (modification time) */
+long ifile_size;      /* input file size, -1 for devices (debug only) */
+char *env;            /* contents of GZIP env variable */
+char **args = NULL;   /* argv pointer if GZIP env variable defined */
+char z_suffix[MAX_SUFFIX+1]; /* default suffix (can be set with --suffix) */
+int  z_len;           /* strlen(z_suffix) */
+
+long header_bytes;	   /* number of bytes in gzip header */
+long bytes_in;             /* number of input bytes */
+long bytes_out;            /* number of output bytes */
+long total_in;             /* input bytes for all files */
+long total_out;            /* output bytes for all files */
+char ifname[MAX_PATH_LEN]; /* input file name */
+char ofname[MAX_PATH_LEN]; /* output file name */
+int  remove_ofname;	   /* remove output file on error */
+struct stat istat;         /* status for input file */
+int  ifd;                  /* input file descriptor */
+int  ofd;                  /* output file descriptor */
+unsigned insize;           /* valid bytes in inbuf */
+unsigned inptr;            /* index of next byte to be processed in inbuf */
+unsigned outcnt;           /* bytes in output buffer */
+
+/* local functions */
+
+local void usage        OF((void));
+local void help         OF((void));
+local void license      OF((void));
+local void version      OF((void));
+local void treat_stdin  OF((void));
+local void treat_file   OF((char *iname));
+local int create_outfile OF((void));
+local int  do_stat      OF((char *name, struct stat *sbuf));
+local char *get_suffix  OF((char *name));
+local int  get_istat    OF((char *iname, struct stat *sbuf));
+local int  make_ofname  OF((void));
+local int  same_file    OF((struct stat *stat1, struct stat *stat2));
+local int name_too_long OF((char *name, struct stat *statb));
+local void shorten_name  OF((char *name));
+local int  get_method   OF((void));
+local int  check_ofname OF((void));
+local void copy_stat    OF((struct stat *ifstat));
+local void do_exit      OF((int exitcode));
+      int main          OF((int argc, char **argv));
+int (*work) OF((int infile, int outfile))
+#ifdef SUPPORT_ZIP
+ = zip; /* function to call */
+#else
+ = unzip;
+#endif
+local void reset_times  OF((char *name, struct stat *statb));
+
+#define strequ(s1, s2) (strcmp((s1),(s2)) == 0)
+
+/* ======================================================================== */
+local void usage()
+{
+    fprintf(stderr, "usage: %s [-cdfhlLnNtvV19] [-S suffix] [file ...]\n",
+	    progname);
+}
+
+/* ======================================================================== */
+local void help()
+{
+    static char  *help_msg[] = {
+ " -c --stdout      write on standard output, keep original files unchanged",
+ " -d --decompress  decompress",
+ " -f --force       force overwrite of output file and compress links",
+ " -h --help        give this help",
+ " -L --license     display software license",
+#ifdef UNDOCUMENTED
+ " -m --no-time     do not save or restore the original modification time",
+ " -M --time        save or restore the original modification time",
+#endif
+ " -n --no-name     do not save or restore the original name and time stamp",
+ " -N --name        save or restore the original name and time stamp",
+ " -q --quiet       suppress all warnings",
+ " -S .suf  --suffix .suf     use suffix .suf on compressed files",
+ " -t --test        test compressed file integrity",
+ " -v --verbose     verbose mode",
+ " -V --version     display version number",
+#ifdef SUPPORT_ZIP
+ " -1 --fast        compress faster",
+ " -9 --best        compress better",
+ " file...          files to (de)compress. If none given, use standard input.",
+#else
+ " file...          files to decompress. If none given, use standard input.",
+#endif
+  0};
+    char **p = help_msg;
+
+    fprintf(stderr,"%s %s (%s)\n", progname, VERSION, REVDATE);
+    usage();
+    while (*p) fprintf(stderr, "%s\n", *p++);
+}
+
+/* ======================================================================== */
+local void license()
+{
+    char **p = license_msg;
+
+    fprintf(stderr,"%s %s (%s)\n", progname, VERSION, REVDATE);
+    while (*p) fprintf(stderr, "%s\n", *p++);
+}
+
+/* ======================================================================== */
+local void version()
+{
+    fprintf(stderr,"%s %s (%s)\n", progname, VERSION, REVDATE);
+
+    fprintf(stderr, "Compilation options: UTIME STDC_HEADERS"
+#ifndef SUPPORT_ZIP
+	" DECOMPRESS_ONLY"
+#endif
+	"\n");
+}
+
+/* ======================================================================== */
+int main (argc, argv)
+    int argc;
+    char **argv;
+{
+    int file_count;     /* number of files to precess */
+    int proglen;        /* length of progname */
+    int optc;           /* current option */
+
+    progname = basename(argv[0]);
+    proglen = strlen(progname);
+
+    /* Add options in GZIP environment variable if there is one */
+    env = add_envopt(&argc, &argv, OPTIONS_VAR);
+    if (env != NULL) args = argv;
+
+    foreground = sysv_signal(SIGINT, SIG_IGN) != SIG_IGN;
+    if (foreground) {
+	(void) sysv_signal(SIGINT, (sig_type)abort_gzip);
+    }
+#ifdef SIGTERM
+    if (sysv_signal(SIGTERM, SIG_IGN) != SIG_IGN) {
+	(void) sysv_signal(SIGTERM, (sig_type)abort_gzip);
+    }
+#endif
+#ifdef SIGHUP
+    if (sysv_signal(SIGHUP, SIG_IGN) != SIG_IGN) {
+	(void) sysv_signal(SIGHUP,  (sig_type)abort_gzip);
+    }
+#endif
+
+#ifndef GNU_STANDARD
+    /* For compatibility with old compress, use program name as an option.
+     * If you compile with -DGNU_STANDARD, this program will behave as
+     * gzip even if it is invoked under the name gunzip or zcat.
+     *
+     * Systems which do not support links can still use -d or -dc.
+     * Ignore an .exe extension for MSDOS, OS/2 and VMS.
+     */
+#ifndef decompress
+    if (  strncmp(progname, "un",  2) == 0     /* ungzip, uncompress */
+       || strncmp(progname, "gun", 3) == 0) {  /* gunzip */
+	decompress = 1;
+    }
+#endif
+    if (strequ(progname+1, "cat")       /* zcat, pcat, gcat */
+	|| strequ(progname, "gzcat")) {    /* gzcat */
+#ifndef decompress
+	decompress = 1;
+#endif
+	to_stdout = 1;
+    }
+#endif
+
+    strncpy(z_suffix, Z_SUFFIX, sizeof(z_suffix)-1);
+    z_len = strlen(z_suffix);
+
+    while ((optc = getopt(argc, argv, "cdfhH?LmMnNqrS:tvV123456789")) != EOF) {
+	switch (optc) {
+	case 'c':
+	    to_stdout = 1; break;
+	case 'd':
+#ifndef decompress
+	    decompress = 1;
+#endif
+	    break;
+	case 'f':
+	    force++; break;
+	case 'h': case 'H': case '?':
+	    help(); do_exit(OK); break;
+	case 'L':
+	    license(); do_exit(OK); break;
+	case 'm': /* undocumented, may change later */
+	    no_time = 1; break;
+	case 'M': /* undocumented, may change later */
+	    no_time = 0; break;
+	case 'n':
+	    no_name = no_time = 1; break;
+	case 'N':
+	    no_name = no_time = 0; break;
+	case 'q':
+	    quiet = 1; verbose = 0; break;
+	case 'S':
+            z_len = strlen(optarg);
+            strcpy(z_suffix, optarg);
+            break;
+	case 't':
+	    test = to_stdout = 1;
+#ifndef decompress
+	    decompress = 1;
+#endif
+	    break;
+	case 'v':
+	    verbose++; quiet = 0; break;
+	case 'V':
+	    version(); do_exit(OK); break;
+#ifdef SUPPORT_ZIP
+	case '1':  case '2':  case '3':  case '4':
+	case '5':  case '6':  case '7':  case '8':  case '9':
+	    level = optc - '0';
+	    break;
+#endif
+	default:
+	    /* Error message already emitted by getopt_long. */
+	    usage();
+	    do_exit(ERROR);
+	}
+    } /* loop on all arguments */
+
+    /* By default, save name and timestamp on compression but do not
+     * restore them on decompression.
+     */
+    if (no_time < 0) no_time = decompress;
+    if (no_name < 0) no_name = decompress;
+
+    file_count = argc - optind;
+
+    if ((z_len == 0 && !decompress) || z_len > MAX_SUFFIX) {
+        fprintf(stderr, "%s: incorrect suffix '%s'\n",
+                progname, optarg);
+        do_exit(ERROR);
+    }
+
+    /* Allocate all global buffers (for DYN_ALLOC option) */
+    ALLOC(uch, inbuf,  INBUFSIZ +INBUF_EXTRA);
+    ALLOC(uch, outbuf, OUTBUFSIZ+OUTBUF_EXTRA);
+    ALLOC(ush, d_buf,  DIST_BUFSIZE);
+    ALLOC(uch, window, 2L*WSIZE);
+    ALLOC(ush, tab_prefix, 1L<<BITS);
+
+    /* And get to work */
+    if (file_count != 0) {
+        while (optind < argc) {
+	    treat_file(argv[optind++]);
+	}
+    } else {  /* Standard input */
+	treat_stdin();
+    }
+    do_exit(exit_code);
+    return exit_code; /* just to avoid lint warning */
+}
+
+/* ========================================================================
+ * Compress or decompress stdin
+ */
+local void treat_stdin()
+{
+    if (!force &&
+	isatty(fileno((FILE *)(decompress ? stdin : stdout)))) {
+	/* Do not send compressed data to the terminal or read it from
+	 * the terminal. We get here when user invoked the program
+	 * without parameters, so be helpful. According to the GNU standards:
+	 *
+	 *   If there is one behavior you think is most useful when the output
+	 *   is to a terminal, and another that you think is most useful when
+	 *   the output is a file or a pipe, then it is usually best to make
+	 *   the default behavior the one that is useful with output to a
+	 *   terminal, and have an option for the other behavior.
+	 *
+	 * Here we use the --force option to get the other behavior.
+	 */
+	fprintf(stderr,
+    "%s: compressed data not %s a terminal. Use -f to force %scompression.\n",
+		progname, decompress ? "read from" : "written to",
+		decompress ? "de" : "");
+	fprintf(stderr,"For help, type: %s -h\n", progname);
+	do_exit(ERROR);
+    }
+
+    strcpy(ifname, "stdin");
+    strcpy(ofname, "stdout");
+
+    /* Get the time stamp on the input file. */
+    time_stamp = 0; /* time unknown by default */
+
+    if (!no_time) {
+	if (fstat(fileno(stdin), &istat) != 0) {
+	    error("fstat(stdin)");
+	}
+	time_stamp = istat.st_mtime;
+    }
+    ifile_size = -1L; /* convention for unknown size */
+
+    clear_bufs(); /* clear input and output buffers */
+    to_stdout = 1;
+    part_nb = 0;
+
+    if (decompress) {
+	method = get_method();
+	if (method < 0) {
+	    do_exit(exit_code); /* error message already emitted */
+	}
+    }
+
+    /* Actually do the compression/decompression. Loop over zipped members.
+     */
+    for (;;) {
+	if ((*work)(fileno(stdin), fileno(stdout)) != OK) return;
+
+	if (!decompress || last_member || inptr == insize) break;
+	/* end of file */
+
+	method = get_method();
+	if (method < 0) return; /* error message already emitted */
+	bytes_out = 0;            /* required for length check */
+    }
+
+    if (verbose) {
+	if (test) {
+	    fprintf(stderr, " OK\n");
+
+	} else if (!decompress) {
+	    display_ratio(bytes_in-(bytes_out-header_bytes), bytes_in, stderr);
+	    fprintf(stderr, "\n");
+#ifdef DISPLAY_STDIN_RATIO
+	} else {
+	    display_ratio(bytes_out-(bytes_in-header_bytes), bytes_out,stderr);
+	    fprintf(stderr, "\n");
+#endif
+	}
+    }
+}
+
+/* ========================================================================
+ * Compress or decompress the given file
+ */
+local void treat_file(iname)
+    char *iname;
+{
+    /* Accept "-" as synonym for stdin */
+    if (strequ(iname, "-")) {
+	int cflag = to_stdout;
+	treat_stdin();
+	to_stdout = cflag;
+	return;
+    }
+
+    /* Check if the input file is present, set ifname and istat: */
+    if (get_istat(iname, &istat) != OK) return;
+
+    /* If the input name is that of a directory, recurse or ignore: */
+    if (S_ISDIR(istat.st_mode)) {
+	WARN((stderr,"%s: %s is a directory -- ignored\n", progname, ifname));
+	return;
+    }
+    if (!S_ISREG(istat.st_mode)) {
+	WARN((stderr,
+	      "%s: %s is not a directory or a regular file - ignored\n",
+	      progname, ifname));
+	return;
+    }
+    if (istat.st_nlink > 1 && !to_stdout && !force) {
+	WARN((stderr, "%s: %s has %d other link%c -- unchanged\n",
+	      progname, ifname,
+	      (int)istat.st_nlink - 1, istat.st_nlink > 2 ? 's' : ' '));
+	return;
+    }
+
+    ifile_size = istat.st_size;
+    time_stamp = no_time ? 0 : istat.st_mtime;
+
+    /* Generate output file name. For -r and (-t or -l), skip files
+     * without a valid gzip suffix (check done in make_ofname).
+     */
+    if (to_stdout && !test) {
+	strcpy(ofname, "stdout");
+
+    } else if (make_ofname() != OK) {
+	return;
+    }
+
+    /* Open the input file and determine compression method. The mode
+     * parameter is ignored but required by some systems (VMS) and forbidden
+     * on other systems (MacOS).
+     */
+    ifd = open(ifname, !decompress ? O_RDONLY : O_RDONLY,
+	       RW_USER);
+    if (ifd == -1) {
+	fprintf(stderr, "%s: ", progname);
+	perror(ifname);
+	exit_code = ERROR;
+	return;
+    }
+    clear_bufs(); /* clear input and output buffers */
+    part_nb = 0;
+
+    if (decompress) {
+	method = get_method(); /* updates ofname if original given */
+	if (method < 0) {
+	    close(ifd);
+	    return;               /* error message already emitted */
+	}
+    }
+
+    /* If compressing to a file, check if ofname is not ambiguous
+     * because the operating system truncates names. Otherwise, generate
+     * a new ofname and save the original name in the compressed file.
+     */
+    if (to_stdout) {
+	ofd = fileno(stdout);
+	/* keep remove_ofname as zero */
+    } else {
+	if (create_outfile() != OK) return;
+
+	if (!decompress && save_orig_name && !verbose && !quiet) {
+	    fprintf(stderr, "%s: %s compressed to %s\n",
+		    progname, ifname, ofname);
+	}
+    }
+    /* Keep the name even if not truncated except with --no-name: */
+    if (!save_orig_name) save_orig_name = !no_name;
+
+    if (verbose) {
+	fprintf(stderr, "%s:\t%s", ifname, (int)strlen(ifname) >= 15 ?
+		"" : ((int)strlen(ifname) >= 7 ? "\t" : "\t\t"));
+    }
+
+    /* Actually do the compression/decompression. Loop over zipped members.
+     */
+    for (;;) {
+	if ((*work)(ifd, ofd) != OK) {
+	    method = -1; /* force cleanup */
+	    break;
+	}
+	if (!decompress || last_member || inptr == insize) break;
+	/* end of file */
+
+	method = get_method();
+	if (method < 0) break;    /* error message already emitted */
+	bytes_out = 0;            /* required for length check */
+    }
+
+    close(ifd);
+    if (!to_stdout && close(ofd)) {
+	write_error();
+    }
+    if (method == -1) {
+	if (!to_stdout) unlink (ofname);
+	return;
+    }
+    /* Display statistics */
+    if(verbose) {
+	if (test) {
+	    fprintf(stderr, " OK");
+	} else if (decompress) {
+	    display_ratio(bytes_out-(bytes_in-header_bytes), bytes_out,stderr);
+	} else {
+	    display_ratio(bytes_in-(bytes_out-header_bytes), bytes_in, stderr);
+	}
+	if (!test && !to_stdout) {
+	    fprintf(stderr, " -- replaced with %s", ofname);
+	}
+	fprintf(stderr, "\n");
+    }
+    /* Copy modes, times, ownership, and remove the input file */
+    if (!to_stdout) {
+	copy_stat(&istat);
+    }
+}
+
+/* ========================================================================
+ * Create the output file. Return OK or ERROR.
+ * Try several times if necessary to avoid truncating the z_suffix. For
+ * example, do not create a compressed file of name "1234567890123."
+ * Sets save_orig_name to true if the file name has been truncated.
+ * IN assertions: the input file has already been open (ifd is set) and
+ *   ofname has already been updated if there was an original name.
+ * OUT assertions: ifd and ofd are closed in case of error.
+ */
+local int create_outfile()
+{
+    struct stat	ostat; /* stat for ofname */
+    int flags = O_WRONLY | O_CREAT | O_EXCL;
+
+    for (;;) {
+	/* Make sure that ofname is not an existing file */
+	if (check_ofname() != OK) {
+	    close(ifd);
+	    return ERROR;
+	}
+	/* Create the output file */
+	remove_ofname = 1;
+	ofd = open(ofname, flags, RW_USER);
+	if (ofd == -1) {
+	    perror(ofname);
+	    close(ifd);
+	    exit_code = ERROR;
+	    return ERROR;
+	}
+
+	/* Check for name truncation on new file (1234567890123.gz) */
+	if (fstat(ofd, &ostat) != 0) {
+	    fprintf(stderr, "%s: ", progname);
+	    perror(ofname);
+	    close(ifd); close(ofd);
+	    unlink(ofname);
+	    exit_code = ERROR;
+	    return ERROR;
+	}
+	if (!name_too_long(ofname, &ostat)) return OK;
+
+	if (decompress) {
+	    /* name might be too long if an original name was saved */
+	    WARN((stderr, "%s: %s: warning, name truncated\n",
+		  progname, ofname));
+	    return OK;
+	}
+	close(ofd);
+	unlink(ofname);
+	shorten_name(ofname);
+    }
+}
+
+/* ========================================================================
+ * Use lstat if available, except for -c or -f. Use stat otherwise.
+ * This allows links when not removing the original file.
+ */
+local int do_stat(name, sbuf)
+    char *name;
+    struct stat *sbuf;
+{
+    errno = 0;
+    if (!to_stdout && !force) {
+	return lstat(name, sbuf);
+    }
+    return stat(name, sbuf);
+}
+
+/* ========================================================================
+ * Return a pointer to the 'z' suffix of a file name, or NULL. For all
+ * systems, ".gz", ".z", ".Z", ".taz", ".tgz", "-gz", "-z" and "_z" are
+ * accepted suffixes, in addition to the value of the --suffix option.
+ * ".tgz" is a useful convention for tar.z files on systems limited
+ * to 3 characters extensions. On such systems, ".?z" and ".??z" are
+ * also accepted suffixes. For Unix, we do not want to accept any
+ * .??z suffix as indicating a compressed file; some people use .xyz
+ * to denote volume data.
+ *   On systems allowing multiple versions of the same file (such as VMS),
+ * this function removes any version suffix in the given name.
+ */
+local char *get_suffix(name)
+    char *name;
+{
+    int nlen, slen;
+    char suffix[MAX_SUFFIX+3]; /* last chars of name, forced to lower case */
+    static char *known_suffixes[] =
+       {z_suffix, ".gz", ".z", ".taz", ".tgz", "-gz", "-z", "_z",
+          NULL};
+    char **suf = known_suffixes;
+
+    if (strequ(z_suffix, "z")) suf++; /* check long suffixes first */
+
+    nlen = strlen(name);
+    if (nlen <= MAX_SUFFIX+2) {
+        strcpy(suffix, name);
+    } else {
+        strcpy(suffix, name+nlen-MAX_SUFFIX-2);
+    }
+    strlwr(suffix);
+    slen = strlen(suffix);
+    do {
+       int s = strlen(*suf);
+       if (slen > s && suffix[slen-s-1] != PATH_SEP
+           && strequ(suffix + slen - s, *suf)) {
+           return name+nlen-s;
+       }
+    } while (*++suf != NULL);
+
+    return NULL;
+}
+
+
+/* ========================================================================
+ * Set ifname to the input file name (with a suffix appended if necessary)
+ * and istat to its stats. For decompression, if no file exists with the
+ * original name, try adding successively z_suffix, .gz, .z, -z and .Z.
+ * For MSDOS, we try only z_suffix and z.
+ * Return OK or ERROR.
+ */
+local int get_istat(iname, sbuf)
+    char *iname;
+    struct stat *sbuf;
+{
+    int ilen;  /* strlen(ifname) */
+    static char *suffixes[] = {z_suffix, ".gz", ".z", "-z", ".Z", NULL};
+    char **suf = suffixes;
+    char *s;
+
+    strcpy(ifname, iname);
+
+    /* If input file exists, return OK. */
+    if (do_stat(ifname, sbuf) == 0) return OK;
+
+    if (!decompress || errno != ENOENT) {
+	perror(ifname);
+	exit_code = ERROR;
+	return ERROR;
+    }
+    /* file.ext doesn't exist, try adding a suffix (after removing any
+     * version number for VMS).
+     */
+    s = get_suffix(ifname);
+    if (s != NULL) {
+	perror(ifname); /* ifname already has z suffix and does not exist */
+	exit_code = ERROR;
+	return ERROR;
+    }
+    ilen = strlen(ifname);
+    if (strequ(z_suffix, ".gz")) suf++;
+
+    /* Search for all suffixes */
+    do {
+        s = *suf;
+        strcat(ifname, s);
+        if (do_stat(ifname, sbuf) == 0) return OK;
+	ifname[ilen] = '\0';
+    } while (*++suf != NULL);
+
+    /* No suffix found, complain using z_suffix: */
+    strcat(ifname, z_suffix);
+    perror(ifname);
+    exit_code = ERROR;
+    return ERROR;
+}
+
+/* ========================================================================
+ * Generate ofname given ifname. Return OK, or WARNING if file must be skipped.
+ * Sets save_orig_name to true if the file name has been truncated.
+ */
+local int make_ofname()
+{
+    char *suff;            /* ofname z suffix */
+
+    strcpy(ofname, ifname);
+    /* strip a version number if any and get the gzip suffix if present: */
+    suff = get_suffix(ofname);
+
+    if (decompress) {
+	if (suff == NULL) {
+	    /* Whith -t or -l, try all files (even without .gz suffix)
+	     * except with -r (behave as with just -dr).
+             */
+            if (test) return OK;
+
+	    /* Avoid annoying messages with -r */
+	    if (verbose || !quiet) {
+		WARN((stderr,"%s: %s: unknown suffix -- ignored\n",
+		      progname, ifname));
+	    }
+	    return WARNING;
+	}
+	/* Make a special case for .tgz and .taz: */
+	strlwr(suff);
+	if (strequ(suff, ".tgz") || strequ(suff, ".taz")) {
+	    strcpy(suff, ".tar");
+	} else {
+	    *suff = '\0'; /* strip the z suffix */
+	}
+        /* ofname might be changed later if infile contains an original name */
+
+    } else if (suff != NULL) {
+	/* Avoid annoying messages with -r (see treat_dir()) */
+	if (verbose || !quiet) {
+	    fprintf(stderr, "%s: %s already has %s suffix -- unchanged\n",
+		    progname, ifname, suff);
+	}
+	if (exit_code == OK) exit_code = WARNING;
+	return WARNING;
+    } else {
+        save_orig_name = 0;
+	strcat(ofname, z_suffix);
+
+    } /* decompress ? */
+    return OK;
+}
+
+
+/* ========================================================================
+ * Check the magic number of the input file and update ofname if an
+ * original name was given and to_stdout is not set.
+ * Return the compression method, -1 for error, -2 for warning.
+ * Set inptr to the offset of the next byte to be processed.
+ * Updates time_stamp if there is one and --no-time is not used.
+ * This function may be called repeatedly for an input file consisting
+ * of several contiguous gzip'ed members.
+ * IN assertions: there is at least one remaining compressed member.
+ *   If the member is a zip file, it must be the only one.
+ */
+local int get_method()
+{
+    uch flags;     /* compression flags */
+    char magic[2]; /* magic header */
+    ulg stamp;     /* time stamp */
+
+    /* If --force and --stdout, zcat == cat, so do not complain about
+     * premature end of file: use try_byte instead of get_byte.
+     */
+    if (force && to_stdout) {
+	magic[0] = (char)try_byte();
+	magic[1] = (char)try_byte();
+	/* If try_byte returned EOF, magic[1] == 0xff */
+    } else {
+	magic[0] = (char)get_byte();
+	magic[1] = (char)get_byte();
+    }
+    method = -1;                 /* unknown yet */
+    part_nb++;                   /* number of parts in gzip file */
+    header_bytes = 0;
+    last_member = RECORD_IO;
+    /* assume multiple members in gzip file except for record oriented I/O */
+
+    if (memcmp(magic, GZIP_MAGIC, 2) == 0
+        || memcmp(magic, OLD_GZIP_MAGIC, 2) == 0) {
+
+	method = (int)get_byte();
+	if (method != DEFLATED) {
+	    fprintf(stderr,
+		    "%s: %s: unknown method %d -- get newer version of gzip\n",
+		    progname, ifname, method);
+	    exit_code = ERROR;
+	    return -1;
+	}
+	work = unzip;
+	flags  = (uch)get_byte();
+
+	if ((flags & ENCRYPTED) != 0) {
+	    fprintf(stderr,
+		    "%s: %s is encrypted -- get newer version of gzip\n",
+		    progname, ifname);
+	    exit_code = ERROR;
+	    return -1;
+	}
+	if ((flags & CONTINUATION) != 0) {
+	    fprintf(stderr,
+	   "%s: %s is a a multi-part gzip file -- get newer version of gzip\n",
+		    progname, ifname);
+	    exit_code = ERROR;
+	    if (force <= 1) return -1;
+	}
+	if ((flags & RESERVED) != 0) {
+	    fprintf(stderr,
+		    "%s: %s has flags 0x%x -- get newer version of gzip\n",
+		    progname, ifname, flags);
+	    exit_code = ERROR;
+	    if (force <= 1) return -1;
+	}
+	stamp  = (ulg)get_byte();
+	stamp |= ((ulg)get_byte()) << 8;
+	stamp |= ((ulg)get_byte()) << 16;
+	stamp |= ((ulg)get_byte()) << 24;
+	if (stamp != 0 && !no_time) time_stamp = stamp;
+
+	(void)get_byte();  /* Ignore extra flags for the moment */
+	(void)get_byte();  /* Ignore OS type for the moment */
+
+	if ((flags & CONTINUATION) != 0) {
+	    unsigned part = (unsigned)get_byte();
+	    part |= ((unsigned)get_byte())<<8;
+	    if (verbose) {
+		fprintf(stderr,"%s: %s: part number %u\n",
+			progname, ifname, part);
+	    }
+	}
+	if ((flags & EXTRA_FIELD) != 0) {
+	    unsigned len = (unsigned)get_byte();
+	    len |= ((unsigned)get_byte())<<8;
+	    if (verbose) {
+		fprintf(stderr,"%s: %s: extra field of %u bytes ignored\n",
+			progname, ifname, len);
+	    }
+	    while (len--) (void)get_byte();
+	}
+
+	/* Get original file name if it was truncated */
+	if ((flags & ORIG_NAME) != 0) {
+	    if (no_name || to_stdout || part_nb > 1) {
+		/* Discard the old name */
+		char c; /* dummy used for NeXTstep 3.0 cc optimizer bug */
+		do {c=get_byte();} while (c != 0);
+	    } else {
+		/* Copy the base name. Keep a directory prefix intact. */
+                char *p = basename(ofname);
+		for (;;) {
+		    *p = (char)get_char();
+		    if (*p++ == '\0') break;
+		    if (p >= ofname+sizeof(ofname)) {
+			error("corrupted input -- file name too large");
+		    }
+		}
+	    } /* no_name || to_stdout */
+	} /* ORIG_NAME */
+
+	/* Discard file comment if any */
+	if ((flags & COMMENT) != 0) {
+	    while (get_char() != 0) /* null */ ;
+	}
+	if (part_nb == 1) {
+	    header_bytes = inptr + 2*sizeof(long); /* include crc and size */
+	}
+    } else if (force && to_stdout) { /* pass input unchanged */
+	method = STORED;
+	work = copy;
+        inptr = 0;
+	last_member = 1;
+    }
+    if (method >= 0) return method;
+
+    if (part_nb == 1) {
+	fprintf(stderr, "\n%s: %s: not in gzip format\n", progname, ifname);
+	exit_code = ERROR;
+	return -1;
+    } else {
+	WARN((stderr, "\n%s: %s: decompression OK, trailing garbage ignored\n",
+	      progname, ifname));
+	return -2;
+    }
+}
+
+
+/* ========================================================================
+ * Return true if the two stat structures correspond to the same file.
+ */
+local int same_file(stat1, stat2)
+    struct stat *stat1;
+    struct stat *stat2;
+{
+    return stat1->st_ino   == stat2->st_ino
+	&& stat1->st_dev   == stat2->st_dev
+#ifdef NO_ST_INO
+        /* Can't rely on st_ino and st_dev, use other fields: */
+	&& stat1->st_mode  == stat2->st_mode
+	&& stat1->st_uid   == stat2->st_uid
+	&& stat1->st_gid   == stat2->st_gid
+	&& stat1->st_size  == stat2->st_size
+	&& stat1->st_atime == stat2->st_atime
+	&& stat1->st_mtime == stat2->st_mtime
+	&& stat1->st_ctime == stat2->st_ctime
+#endif
+	    ;
+}
+
+/* ========================================================================
+ * Return true if a file name is ambiguous because the operating system
+ * truncates file names.
+ */
+local int name_too_long(name, statb)
+    char *name;           /* file name to check */
+    struct stat *statb;   /* stat buf for this file name */
+{
+    int s = strlen(name);
+    char c = name[s-1];
+    struct stat	tstat; /* stat for truncated name */
+    int res;
+
+    tstat = *statb;      /* Just in case OS does not fill all fields */
+    name[s-1] = '\0';
+    res = stat(name, &tstat) == 0 && same_file(statb, &tstat);
+    name[s-1] = c;
+    Trace((stderr, " too_long(%s) => %d\n", name, res));
+    return res;
+}
+
+/* ========================================================================
+ * Shorten the given name by one character, or replace a .tar extension
+ * with .tgz. Truncate the last part of the name which is longer than
+ * MIN_PART characters: 1234.678.012.gz -> 123.678.012.gz. If the name
+ * has only parts shorter than MIN_PART truncate the longest part.
+ * For decompression, just remove the last character of the name.
+ *
+ * IN assertion: for compression, the suffix of the given name is z_suffix.
+ */
+local void shorten_name(name)
+    char *name;
+{
+    int len;                 /* length of name without z_suffix */
+    char *trunc = NULL;      /* character to be truncated */
+    int plen;                /* current part length */
+    int min_part = MIN_PART; /* current minimum part length */
+    char *p;
+
+    len = strlen(name);
+    if (decompress) {
+	if (len <= 1) error("name too short");
+	name[len-1] = '\0';
+	return;
+    }
+    p = get_suffix(name);
+    if (p == NULL) error("can't recover suffix\n");
+    *p = '\0';
+    save_orig_name = 1;
+
+    /* compress 1234567890.tar to 1234567890.tgz */
+    if (len > 4 && strequ(p-4, ".tar")) {
+	strcpy(p-4, ".tgz");
+	return;
+    }
+    /* Try keeping short extensions intact:
+     * 1234.678.012.gz -> 123.678.012.gz
+     */
+    do {
+	p = strrchr(name, PATH_SEP);
+	p = p ? p+1 : name;
+	while (*p) {
+	    plen = strcspn(p, ".");
+	    p += plen;
+	    if (plen > min_part) trunc = p-1;
+	    if (*p) p++;
+	}
+    } while (trunc == NULL && --min_part != 0);
+
+    if (trunc != NULL) {
+	do {
+	    trunc[0] = trunc[1];
+	} while (*trunc++);
+	trunc--;
+    } else {
+	trunc = strrchr(name, '.');
+	if (trunc == NULL) error("internal error in shorten_name");
+	if (trunc[1] == '\0') trunc--; /* force truncation */
+    }
+    strcpy(trunc, z_suffix);
+}
+
+/* ========================================================================
+ * If compressing to a file, check if ofname is not ambiguous
+ * because the operating system truncates names. Otherwise, generate
+ * a new ofname and save the original name in the compressed file.
+ * If the compressed file already exists, ask for confirmation.
+ *    The check for name truncation is made dynamically, because different
+ * file systems on the same OS might use different truncation rules (on SVR4
+ * s5 truncates to 14 chars and ufs does not truncate).
+ *    This function returns -1 if the file must be skipped, and
+ * updates save_orig_name if necessary.
+ * IN assertions: save_orig_name is already set if ofname has been
+ * already truncated because of NO_MULTIPLE_DOTS. The input file has
+ * already been open and istat is set.
+ */
+local int check_ofname()
+{
+    struct stat	ostat; /* stat for ofname */
+
+#ifdef ENAMETOOLONG
+    /* Check for strictly conforming Posix systems (which return ENAMETOOLONG
+     * instead of silently truncating filenames).
+     */
+    errno = 0;
+    while (stat(ofname, &ostat) != 0) {
+        if (errno != ENAMETOOLONG) return 0; /* ofname does not exist */
+	shorten_name(ofname);
+    }
+#else
+    if (stat(ofname, &ostat) != 0) return 0;
+#endif
+    /* Check for name truncation on existing file. Do this even on systems
+     * defining ENAMETOOLONG, because on most systems the strict Posix
+     * behavior is disabled by default (silent name truncation allowed).
+     */
+    if (!decompress && name_too_long(ofname, &ostat)) {
+	shorten_name(ofname);
+	if (stat(ofname, &ostat) != 0) return 0;
+    }
+
+    /* Check that the input and output files are different (could be
+     * the same by name truncation or links).
+     */
+    if (same_file(&istat, &ostat)) {
+	if (strequ(ifname, ofname)) {
+	    fprintf(stderr, "%s: %s: cannot %scompress onto itself\n",
+		    progname, ifname, decompress ? "de" : "");
+	} else {
+	    fprintf(stderr, "%s: %s and %s are the same file\n",
+		    progname, ifname, ofname);
+	}
+	exit_code = ERROR;
+	return ERROR;
+    }
+    /* Ask permission to overwrite the existing file */
+    if (!force) {
+#if 0
+	char response[80];
+	strcpy(response,"n");
+	fprintf(stderr, "%s: %s already exists;", progname, ofname);
+	if (foreground && isatty(fileno(stdin))) {
+	    fprintf(stderr, " do you wish to overwrite (y or n)? ");
+	    (void)fgets(response, sizeof(response)-1, stdin);
+	}
+	if (tolow(*response) != 'y') {
+	    fprintf(stderr, "\tnot overwritten\n");
+#endif
+	    if (exit_code == OK) exit_code = WARNING;
+	    return ERROR;
+#if 0
+	}
+#endif
+    }
+    (void) chmod(ofname, 0777);
+    if (unlink(ofname)) {
+	fprintf(stderr, "%s: ", progname);
+	perror(ofname);
+	exit_code = ERROR;
+	return ERROR;
+    }
+    return OK;
+}
+
+
+/* ========================================================================
+ * Set the access and modification times from the given stat buffer.
+ */
+local void reset_times (name, statb)
+    char *name;
+    struct stat *statb;
+{
+    struct utimbuf	timep;
+
+    /* Copy the time stamp */
+    timep.actime  = statb->st_atime;
+    timep.modtime = statb->st_mtime;
+
+    /* Some systems (at least OS/2) do not support utime on directories */
+    if (utime(name, &timep) && !S_ISDIR(statb->st_mode)) {
+	WARN((stderr, "%s: ", progname));
+	if (!quiet) perror(ofname);
+    }
+}
+
+
+/* ========================================================================
+ * Copy modes, times, ownership from input file to output file.
+ * IN assertion: to_stdout is false.
+ */
+local void copy_stat(ifstat)
+    struct stat *ifstat;
+{
+    if (decompress && time_stamp != 0 && ifstat->st_mtime != time_stamp) {
+	ifstat->st_mtime = time_stamp;
+	if (verbose > 1) {
+	    fprintf(stderr, "%s: time stamp restored\n", ofname);
+	}
+    }
+    reset_times(ofname, ifstat);
+
+    /* Copy the protection modes */
+    if (chmod(ofname, ifstat->st_mode & 07777)) {
+	WARN((stderr, "%s: ", progname));
+	if (!quiet) perror(ofname);
+    }
+
+    chown(ofname, ifstat->st_uid, ifstat->st_gid);  /* Copy ownership */
+
+    remove_ofname = 0;
+    /* It's now safe to remove the input file: */
+    (void) chmod(ifname, 0777);
+    if (unlink(ifname)) {
+	WARN((stderr, "%s: ", progname));
+	if (!quiet) perror(ifname);
+    }
+}
+
+/* ========================================================================
+ * Free all dynamically allocated variables and exit with the given code.
+ */
+local void do_exit(exitcode)
+    int exitcode;
+{
+    static int in_exit = 0;
+
+    if (in_exit) exit(exitcode);
+    in_exit = 1;
+    if (env != NULL)  free(env),  env  = NULL;
+    if (args != NULL) free((char*)args), args = NULL;
+    FREE(inbuf);
+    FREE(outbuf);
+    FREE(d_buf);
+    FREE(window);
+    FREE(tab_prefix);
+    exit(exitcode);
+}
+
+/* ========================================================================
+ * Signal and error handler.
+ */
+void abort_gzip()
+{
+   if (remove_ofname) {
+       close(ofd);
+       unlink (ofname);
+   }
+   do_exit(ERROR);
+}
diff --git a/usr/gzip/gzip.h b/usr/gzip/gzip.h
new file mode 100644
index 0000000..7cd2fbd
--- /dev/null
+++ b/usr/gzip/gzip.h
@@ -0,0 +1,298 @@
+/* gzip.h -- common declarations for all gzip modules
+ * Copyright (C) 1992-1993 Jean-loup Gailly.
+ * This is free software; you can redistribute it and/or modify it under the
+ * terms of the GNU General Public License, see the file COPYING.
+ */
+
+#if defined(__STDC__) || defined(PROTO)
+#  define OF(args)  args
+#else
+#  define OF(args)  ()
+#endif
+
+#ifdef __STDC__
+   typedef void *voidp;
+#else
+   typedef char *voidp;
+#endif
+
+/* I don't like nested includes, but the string and io functions are used
+ * too often
+ */
+#include <stdio.h>
+#include <string.h>
+#define memzero(s, n)     memset ((voidp)(s), 0, (n))
+
+#define local static
+
+typedef unsigned char  uch;
+typedef unsigned short ush;
+typedef unsigned long  ulg;
+
+/* Return codes from gzip */
+#define OK      0
+#define ERROR   1
+#define WARNING 2
+
+/* Compression methods (see algorithm.doc) */
+#define STORED      0
+#define COMPRESSED  1
+#define PACKED      2
+#define LZHED       3
+/* methods 4 to 7 reserved */
+#define DEFLATED    8
+#define MAX_METHODS 9
+extern int method;         /* compression method */
+
+/* To save memory for 16 bit systems, some arrays are overlaid between
+ * the various modules:
+ * deflate:  prev+head   window      d_buf  l_buf  outbuf
+ * unlzw:    tab_prefix  tab_suffix  stack  inbuf  outbuf
+ * inflate:              window             inbuf
+ * unpack:               window             inbuf  prefix_len
+ * unlzh:    left+right  window      c_table inbuf c_len
+ * For compression, input is done in window[]. For decompression, output
+ * is done in window except for unlzw.
+ */
+
+#ifndef	INBUFSIZ
+#  ifdef SMALL_MEM
+#    define INBUFSIZ  0x2000  /* input buffer size */
+#  else
+#    define INBUFSIZ  0x8000  /* input buffer size */
+#  endif
+#endif
+#define INBUF_EXTRA  64     /* required by unlzw() */
+
+#ifndef	OUTBUFSIZ
+#  ifdef SMALL_MEM
+#    define OUTBUFSIZ   8192  /* output buffer size */
+#  else
+#    define OUTBUFSIZ  16384  /* output buffer size */
+#  endif
+#endif
+#define OUTBUF_EXTRA 2048   /* required by unlzw() */
+
+#ifndef DIST_BUFSIZE
+#  ifdef SMALL_MEM
+#    define DIST_BUFSIZE 0x2000 /* buffer for distances, see trees.c */
+#  else
+#    define DIST_BUFSIZE 0x8000 /* buffer for distances, see trees.c */
+#  endif
+#endif
+
+#ifdef DYN_ALLOC
+#  define EXTERN(type, array)  extern type * near array
+#  define DECLARE(type, array, size)  type * near array
+#  define ALLOC(type, array, size) { \
+      array = (type*)fcalloc((size_t)(((size)+1L)/2), 2*sizeof(type)); \
+      if (array == NULL) error("insufficient memory"); \
+   }
+#  define FREE(array) {if (array != NULL) fcfree(array), array=NULL;}
+#else
+#  define EXTERN(type, array)  extern type array[]
+#  define DECLARE(type, array, size)  type array[size]
+#  define ALLOC(type, array, size)
+#  define FREE(array)
+#endif
+
+EXTERN(uch, inbuf);          /* input buffer */
+EXTERN(uch, outbuf);         /* output buffer */
+EXTERN(ush, d_buf);          /* buffer for distances, see trees.c */
+EXTERN(uch, window);         /* Sliding window and suffix table (unlzw) */
+#define tab_suffix window
+#ifndef MAXSEG_64K
+#  define tab_prefix prev    /* hash link (see deflate.c) */
+#  define head (prev+WSIZE)  /* hash head (see deflate.c) */
+   EXTERN(ush, tab_prefix);  /* prefix code (see unlzw.c) */
+#else
+#  define tab_prefix0 prev
+#  define head tab_prefix1
+   EXTERN(ush, tab_prefix0); /* prefix for even codes */
+   EXTERN(ush, tab_prefix1); /* prefix for odd  codes */
+#endif
+
+extern unsigned insize; /* valid bytes in inbuf */
+extern unsigned inptr;  /* index of next byte to be processed in inbuf */
+extern unsigned outcnt; /* bytes in output buffer */
+
+extern long bytes_in;   /* number of input bytes */
+extern long bytes_out;  /* number of output bytes */
+extern long header_bytes;/* number of bytes in gzip header */
+
+#define isize bytes_in
+/* for compatibility with old zip sources (to be cleaned) */
+
+extern int  ifd;        /* input file descriptor */
+extern int  ofd;        /* output file descriptor */
+extern char ifname[];   /* input file name or "stdin" */
+extern char ofname[];   /* output file name or "stdout" */
+extern char *progname;  /* program name */
+
+extern time_t time_stamp; /* original time stamp (modification time) */
+extern long ifile_size; /* input file size, -1 for devices (debug only) */
+
+typedef int file_t;     /* Do not use stdio */
+#define NO_FILE  (-1)   /* in memory compression */
+
+
+#define	PACK_MAGIC     "\037\036" /* Magic header for packed files */
+#define	GZIP_MAGIC     "\037\213" /* Magic header for gzip files, 1F 8B */
+#define	OLD_GZIP_MAGIC "\037\236" /* Magic header for gzip 0.5 = freeze 1.x */
+#define	LZH_MAGIC      "\037\240" /* Magic header for SCO LZH Compress files*/
+#define PKZIP_MAGIC    "\120\113\003\004" /* Magic header for pkzip files */
+
+/* gzip flag byte */
+#define ASCII_FLAG   0x01 /* bit 0 set: file probably ascii text */
+#define CONTINUATION 0x02 /* bit 1 set: continuation of multi-part gzip file */
+#define EXTRA_FIELD  0x04 /* bit 2 set: extra field present */
+#define ORIG_NAME    0x08 /* bit 3 set: original file name present */
+#define COMMENT      0x10 /* bit 4 set: file comment present */
+#define ENCRYPTED    0x20 /* bit 5 set: file is encrypted */
+#define RESERVED     0xC0 /* bit 6,7:   reserved */
+
+/* internal file attribute */
+#define UNKNOWN 0xffff
+#define BINARY  0
+#define ASCII   1
+
+#ifndef WSIZE
+#  define WSIZE 0x8000     /* window size--must be a power of two, and */
+#endif                     /*  at least 32K for zip's deflate method */
+
+#define MIN_MATCH  3
+#define MAX_MATCH  258
+/* The minimum and maximum match lengths */
+
+#define MIN_LOOKAHEAD (MAX_MATCH+MIN_MATCH+1)
+/* Minimum amount of lookahead, except at the end of the input file.
+ * See deflate.c for comments about the MIN_MATCH+1.
+ */
+
+#define MAX_DIST  (WSIZE-MIN_LOOKAHEAD)
+/* In order to simplify the code, particularly on 16 bit machines, match
+ * distances are limited to MAX_DIST instead of WSIZE.
+ */
+
+extern int decrypt;        /* flag to turn on decryption */
+extern int exit_code;      /* program exit code */
+extern int verbose;        /* be verbose (-v) */
+extern int quiet;          /* be quiet (-q) */
+extern int level;          /* compression level */
+extern int test;           /* check .z file integrity */
+extern int to_stdout;      /* output to stdout (-c) */
+extern int save_orig_name; /* set if original name must be saved */
+
+#define get_byte()  (inptr < insize ? inbuf[inptr++] : fill_inbuf(0))
+#define try_byte()  (inptr < insize ? inbuf[inptr++] : fill_inbuf(1))
+
+/* put_byte is used for the compressed output, put_ubyte for the
+ * uncompressed output. However unlzw() uses window for its
+ * suffix table instead of its output buffer, so it does not use put_ubyte
+ * (to be cleaned up).
+ */
+#define put_byte(c) {outbuf[outcnt++]=(uch)(c); if (outcnt==OUTBUFSIZ)\
+   flush_outbuf();}
+#define put_ubyte(c) {window[outcnt++]=(uch)(c); if (outcnt==WSIZE)\
+   flush_window();}
+
+/* Output a 16 bit value, lsb first */
+#define put_short(w) \
+{ if (outcnt < OUTBUFSIZ-2) { \
+    outbuf[outcnt++] = (uch) ((w) & 0xff); \
+    outbuf[outcnt++] = (uch) ((ush)(w) >> 8); \
+  } else { \
+    put_byte((uch)((w) & 0xff)); \
+    put_byte((uch)((ush)(w) >> 8)); \
+  } \
+}
+
+/* Output a 32 bit value to the bit stream, lsb first */
+#define put_long(n) { \
+    put_short((n) & 0xffff); \
+    put_short(((ulg)(n)) >> 16); \
+}
+
+#define seekable()    0  /* force sequential output */
+#define translate_eol 0  /* no option -a yet */
+
+#define tolow(c)  (isupper(c) ? (c)-'A'+'a' : (c))    /* force to lower case */
+
+/* Macros for getting two-byte and four-byte header values */
+#define SH(p) ((ush)(uch)((p)[0]) | ((ush)(uch)((p)[1]) << 8))
+#define LG(p) ((ulg)(SH(p)) | ((ulg)(SH((p)+2)) << 16))
+
+/* Diagnostic functions */
+#ifdef DEBUG
+#  define Assert(cond,msg) {if(!(cond)) error(msg);}
+#  define Trace(x) fprintf x
+#  define Tracev(x) {if (verbose) fprintf x ;}
+#  define Tracevv(x) {if (verbose>1) fprintf x ;}
+#  define Tracec(c,x) {if (verbose && (c)) fprintf x ;}
+#  define Tracecv(c,x) {if (verbose>1 && (c)) fprintf x ;}
+#else
+#  define Assert(cond,msg)
+#  define Trace(x)
+#  define Tracev(x)
+#  define Tracevv(x)
+#  define Tracec(c,x)
+#  define Tracecv(c,x)
+#endif
+
+#define WARN(msg) {if (!quiet) fprintf msg ; \
+		   if (exit_code == OK) exit_code = WARNING;}
+
+	/* in zip.c: */
+extern int zip        OF((int in, int out));
+extern int file_read  OF((char *buf,  unsigned size));
+
+	/* in unzip.c */
+extern int unzip      OF((int in, int out));
+extern int check_zipfile OF((int in));
+
+	/* in gzip.c */
+void abort_gzip OF((void));
+
+        /* in deflate.c */
+void lm_init OF((int pack_level, ush *flags));
+ulg  deflate OF((void));
+
+        /* in trees.c */
+void ct_init     OF((ush *attr, int *method));
+int  ct_tally    OF((int dist, int lc));
+ulg  flush_block OF((char *buf, ulg stored_len, int eof));
+
+        /* in bits.c */
+void     bi_init    OF((file_t zipfile));
+void     send_bits  OF((int value, int length));
+unsigned bi_reverse OF((unsigned value, int length));
+void     bi_windup  OF((void));
+void     copy_block OF((char *buf, unsigned len, int header));
+extern   int (*read_buf) OF((char *buf, unsigned size));
+
+	/* in util.c: */
+extern int copy           OF((int in, int out));
+extern ulg  updcrc        OF((uch *s, unsigned n));
+extern void clear_bufs    OF((void));
+extern int  fill_inbuf    OF((int eof_ok));
+extern void flush_outbuf  OF((void));
+extern void flush_window  OF((void));
+extern void write_buf     OF((int fd, voidp buf, unsigned cnt));
+extern char *strlwr       OF((char *s));
+extern char *basename     OF((char *fname));
+extern void make_simple_name OF((char *name));
+extern char *add_envopt   OF((int *argcp, char ***argvp, char *env));
+extern void error         OF((char *m));
+extern void warn          OF((char *a, char *b));
+extern void read_error    OF((void));
+extern void write_error   OF((void));
+extern void display_ratio OF((long num, long den, FILE *file));
+extern voidp xmalloc      OF((unsigned int size));
+
+	/* in inflate.c */
+extern int inflate OF((void));
+
+/* stuff from lzw.h */
+#ifndef BITS
+#  define BITS 16
+#endif
diff --git a/usr/gzip/inflate.c b/usr/gzip/inflate.c
new file mode 100644
index 0000000..a540538
--- /dev/null
+++ b/usr/gzip/inflate.c
@@ -0,0 +1,950 @@
+/* inflate.c -- Not copyrighted 1992 by Mark Adler
+   version c10p1, 10 January 1993 */
+
+/* You can do whatever you like with this source file, though I would
+   prefer that if you modify it and redistribute it that you include
+   comments to that effect with your name and the date.  Thank you.
+   [The history has been moved to the file ChangeLog.]
+ */
+
+/*
+   Inflate deflated (PKZIP's method 8 compressed) data.  The compression
+   method searches for as much of the current string of bytes (up to a
+   length of 258) in the previous 32K bytes.  If it doesn't find any
+   matches (of at least length 3), it codes the next byte.  Otherwise, it
+   codes the length of the matched string and its distance backwards from
+   the current position.  There is a single Huffman code that codes both
+   single bytes (called "literals") and match lengths.  A second Huffman
+   code codes the distance information, which follows a length code.  Each
+   length or distance code actually represents a base value and a number
+   of "extra" (sometimes zero) bits to get to add to the base value.  At
+   the end of each deflated block is a special end-of-block (EOB) literal/
+   length code.  The decoding process is basically: get a literal/length
+   code; if EOB then done; if a literal, emit the decoded byte; if a
+   length then get the distance and emit the referred-to bytes from the
+   sliding window of previously emitted data.
+
+   There are (currently) three kinds of inflate blocks: stored, fixed, and
+   dynamic.  The compressor deals with some chunk of data at a time, and
+   decides which method to use on a chunk-by-chunk basis.  A chunk might
+   typically be 32K or 64K.  If the chunk is uncompressible, then the
+   "stored" method is used.  In this case, the bytes are simply stored as
+   is, eight bits per byte, with none of the above coding.  The bytes are
+   preceded by a count, since there is no longer an EOB code.
+
+   If the data is compressible, then either the fixed or dynamic methods
+   are used.  In the dynamic method, the compressed data is preceded by
+   an encoding of the literal/length and distance Huffman codes that are
+   to be used to decode this block.  The representation is itself Huffman
+   coded, and so is preceded by a description of that code.  These code
+   descriptions take up a little space, and so for small blocks, there is
+   a predefined set of codes, called the fixed codes.  The fixed method is
+   used if the block codes up smaller that way (usually for quite small
+   chunks), otherwise the dynamic method is used.  In the latter case, the
+   codes are customized to the probabilities in the current block, and so
+   can code it much better than the pre-determined fixed codes.
+
+   The Huffman codes themselves are decoded using a mutli-level table
+   lookup, in order to maximize the speed of decoding plus the speed of
+   building the decoding tables.  See the comments below that precede the
+   lbits and dbits tuning parameters.
+ */
+
+
+/*
+   Notes beyond the 1.93a appnote.txt:
+
+   1. Distance pointers never point before the beginning of the output
+      stream.
+   2. Distance pointers can point back across blocks, up to 32k away.
+   3. There is an implied maximum of 7 bits for the bit length table and
+      15 bits for the actual data.
+   4. If only one code exists, then it is encoded using one bit.  (Zero
+      would be more efficient, but perhaps a little confusing.)  If two
+      codes exist, they are coded using one bit each (0 and 1).
+   5. There is no way of sending zero distance codes--a dummy must be
+      sent if there are none.  (History: a pre 2.0 version of PKZIP would
+      store blocks with no distance codes, but this was discovered to be
+      too harsh a criterion.)  Valid only for 1.93a.  2.04c does allow
+      zero distance codes, which is sent as one code of zero bits in
+      length.
+   6. There are up to 286 literal/length codes.  Code 256 represents the
+      end-of-block.  Note however that the static length tree defines
+      288 codes just to fill out the Huffman codes.  Codes 286 and 287
+      cannot be used though, since there is no length base or extra bits
+      defined for them.  Similarly, there are up to 30 distance codes.
+      However, static trees define 32 codes (all 5 bits) to fill out the
+      Huffman codes, but the last two had better not show up in the data.
+   7. Unzip can check dynamic Huffman blocks for complete code sets.
+      The exception is that a single code would not be complete (see #4).
+   8. The five bits following the block type is really the number of
+      literal codes sent minus 257.
+   9. Length codes 8,16,16 are interpreted as 13 length codes of 8 bits
+      (1+6+6).  Therefore, to output three times the length, you output
+      three codes (1+1+1), whereas to output four times the same length,
+      you only need two codes (1+3).  Hmm.
+  10. In the tree reconstruction algorithm, Code = Code + Increment
+      only if BitLength(i) is not zero.  (Pretty obvious.)
+  11. Correction: 4 Bits: # of Bit Length codes - 4     (4 - 19)
+  12. Note: length code 284 can represent 227-258, but length code 285
+      really is 258.  The last length deserves its own, short code
+      since it gets used a lot in very redundant files.  The length
+      258 is special since 258 - 3 (the min match length) is 255.
+  13. The literal/length and distance code bit lengths are read as a
+      single stream of lengths.  It is possible (and advantageous) for
+      a repeat code (16, 17, or 18) to go across the boundary between
+      the two sets of lengths.
+ */
+
+#ifdef RCSID
+static char rcsid[] = "$Id: inflate.c,v 1.1 2002/08/18 00:59:21 hpa Exp $";
+#endif
+
+#include <sys/types.h>
+#include <stdlib.h>
+
+#include "tailor.h"
+#include "gzip.h"
+#define slide window
+
+/* Huffman code lookup table entry--this entry is four bytes for machines
+   that have 16-bit pointers (e.g. PC's in the small or medium model).
+   Valid extra bits are 0..13.  e == 15 is EOB (end of block), e == 16
+   means that v is a literal, 16 < e < 32 means that v is a pointer to
+   the next table, which codes e - 16 bits, and lastly e == 99 indicates
+   an unused code.  If a code with e == 99 is looked up, this implies an
+   error in the data. */
+struct huft {
+  uch e;                /* number of extra bits or operation */
+  uch b;                /* number of bits in this code or subcode */
+  union {
+    ush n;              /* literal, length base, or distance base */
+    struct huft *t;     /* pointer to next level of table */
+  } v;
+};
+
+
+/* Function prototypes */
+int huft_build OF((unsigned *, unsigned, unsigned, ush *, ush *,
+                   struct huft **, int *));
+int huft_free OF((struct huft *));
+int inflate_codes OF((struct huft *, struct huft *, int, int));
+int inflate_stored OF((void));
+int inflate_fixed OF((void));
+int inflate_dynamic OF((void));
+int inflate_block OF((int *));
+int inflate OF((void));
+
+
+/* The inflate algorithm uses a sliding 32K byte window on the uncompressed
+   stream to find repeated byte strings.  This is implemented here as a
+   circular buffer.  The index is updated simply by incrementing and then
+   and'ing with 0x7fff (32K-1). */
+/* It is left to other modules to supply the 32K area.  It is assumed
+   to be usable as if it were declared "uch slide[32768];" or as just
+   "uch *slide;" and then malloc'ed in the latter case.  The definition
+   must be in unzip.h, included above. */
+/* unsigned wp;             current position in slide */
+#define wp outcnt
+#define flush_output(w) (wp=(w),flush_window())
+
+/* Tables for deflate from PKZIP's appnote.txt. */
+static unsigned border[] = {    /* Order of the bit length code lengths */
+        16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15};
+static ush cplens[] = {         /* Copy lengths for literal codes 257..285 */
+        3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31,
+        35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0};
+        /* note: see note #13 above about the 258 in this list. */
+static ush cplext[] = {         /* Extra bits for literal codes 257..285 */
+        0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2,
+        3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0, 99, 99}; /* 99==invalid */
+static ush cpdist[] = {         /* Copy offsets for distance codes 0..29 */
+        1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193,
+        257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145,
+        8193, 12289, 16385, 24577};
+static ush cpdext[] = {         /* Extra bits for distance codes */
+        0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6,
+        7, 7, 8, 8, 9, 9, 10, 10, 11, 11,
+        12, 12, 13, 13};
+
+
+
+/* Macros for inflate() bit peeking and grabbing.
+   The usage is:
+
+        NEEDBITS(j)
+        x = b & mask_bits[j];
+        DUMPBITS(j)
+
+   where NEEDBITS makes sure that b has at least j bits in it, and
+   DUMPBITS removes the bits from b.  The macros use the variable k
+   for the number of bits in b.  Normally, b and k are register
+   variables for speed, and are initialized at the beginning of a
+   routine that uses these macros from a global bit buffer and count.
+
+   If we assume that EOB will be the longest code, then we will never
+   ask for bits with NEEDBITS that are beyond the end of the stream.
+   So, NEEDBITS should not read any more bytes than are needed to
+   meet the request.  Then no bytes need to be "returned" to the buffer
+   at the end of the last block.
+
+   However, this assumption is not true for fixed blocks--the EOB code
+   is 7 bits, but the other literal/length codes can be 8 or 9 bits.
+   (The EOB code is shorter than other codes because fixed blocks are
+   generally short.  So, while a block always has an EOB, many other
+   literal/length codes have a significantly lower probability of
+   showing up at all.)  However, by making the first table have a
+   lookup of seven bits, the EOB code will be found in that first
+   lookup, and so will not require that too many bits be pulled from
+   the stream.
+ */
+
+ulg bb;                         /* bit buffer */
+unsigned bk;                    /* bits in bit buffer */
+
+ush mask_bits[] = {
+    0x0000,
+    0x0001, 0x0003, 0x0007, 0x000f, 0x001f, 0x003f, 0x007f, 0x00ff,
+    0x01ff, 0x03ff, 0x07ff, 0x0fff, 0x1fff, 0x3fff, 0x7fff, 0xffff
+};
+
+#ifdef CRYPT
+  uch cc;
+#  define NEXTBYTE() \
+     (decrypt ? (cc = get_byte(), cc) : get_byte())
+#else
+#  define NEXTBYTE()  (uch)get_byte()
+#endif
+#define NEEDBITS(n) {while(k<(n)){b|=((ulg)NEXTBYTE())<<k;k+=8;}}
+#define DUMPBITS(n) {b>>=(n);k-=(n);}
+
+
+/*
+   Huffman code decoding is performed using a multi-level table lookup.
+   The fastest way to decode is to simply build a lookup table whose
+   size is determined by the longest code.  However, the time it takes
+   to build this table can also be a factor if the data being decoded
+   is not very long.  The most common codes are necessarily the
+   shortest codes, so those codes dominate the decoding time, and hence
+   the speed.  The idea is you can have a shorter table that decodes the
+   shorter, more probable codes, and then point to subsidiary tables for
+   the longer codes.  The time it costs to decode the longer codes is
+   then traded against the time it takes to make longer tables.
+
+   This results of this trade are in the variables lbits and dbits
+   below.  lbits is the number of bits the first level table for literal/
+   length codes can decode in one step, and dbits is the same thing for
+   the distance codes.  Subsequent tables are also less than or equal to
+   those sizes.  These values may be adjusted either when all of the
+   codes are shorter than that, in which case the longest code length in
+   bits is used, or when the shortest code is *longer* than the requested
+   table size, in which case the length of the shortest code in bits is
+   used.
+
+   There are two different values for the two tables, since they code a
+   different number of possibilities each.  The literal/length table
+   codes 286 possible values, or in a flat code, a little over eight
+   bits.  The distance table codes 30 possible values, or a little less
+   than five bits, flat.  The optimum values for speed end up being
+   about one bit more than those, so lbits is 8+1 and dbits is 5+1.
+   The optimum values may differ though from machine to machine, and
+   possibly even between compilers.  Your mileage may vary.
+ */
+
+
+int lbits = 9;          /* bits in base literal/length lookup table */
+int dbits = 6;          /* bits in base distance lookup table */
+
+
+/* If BMAX needs to be larger than 16, then h and x[] should be ulg. */
+#define BMAX 16         /* maximum bit length of any code (16 for explode) */
+#define N_MAX 288       /* maximum number of codes in any set */
+
+
+unsigned hufts;         /* track memory usage */
+
+
+int huft_build(b, n, s, d, e, t, m)
+unsigned *b;            /* code lengths in bits (all assumed <= BMAX) */
+unsigned n;             /* number of codes (assumed <= N_MAX) */
+unsigned s;             /* number of simple-valued codes (0..s-1) */
+ush *d;                 /* list of base values for non-simple codes */
+ush *e;                 /* list of extra bits for non-simple codes */
+struct huft **t;        /* result: starting table */
+int *m;                 /* maximum lookup bits, returns actual */
+/* Given a list of code lengths and a maximum table size, make a set of
+   tables to decode that set of codes.  Return zero on success, one if
+   the given code set is incomplete (the tables are still built in this
+   case), two if the input is invalid (all zero length codes or an
+   oversubscribed set of lengths), and three if not enough memory. */
+{
+  unsigned a;                   /* counter for codes of length k */
+  unsigned c[BMAX+1];           /* bit length count table */
+  unsigned f;                   /* i repeats in table every f entries */
+  int g;                        /* maximum code length */
+  int h;                        /* table level */
+  register unsigned i;          /* counter, current code */
+  register unsigned j;          /* counter */
+  register int k;               /* number of bits in current code */
+  int l;                        /* bits per table (returned in m) */
+  register unsigned *p;         /* pointer into c[], b[], or v[] */
+  register struct huft *q;      /* points to current table */
+  struct huft r;                /* table entry for structure assignment */
+  struct huft *u[BMAX];         /* table stack */
+  unsigned v[N_MAX];            /* values in order of bit length */
+  register int w;               /* bits before this table == (l * h) */
+  unsigned x[BMAX+1];           /* bit offsets, then code stack */
+  unsigned *xp;                 /* pointer into x */
+  int y;                        /* number of dummy codes added */
+  unsigned z;                   /* number of entries in current table */
+
+
+  /* Generate counts for each bit length */
+  memzero(c, sizeof(c));
+  p = b;  i = n;
+  do {
+    Tracecv(*p, (stderr, (n-i >= ' ' && n-i <= '~' ? "%c %d\n" : "0x%x %d\n"),
+	    n-i, *p));
+    c[*p]++;                    /* assume all entries <= BMAX */
+    p++;                      /* Can't combine with above line (Solaris bug) */
+  } while (--i);
+  if (c[0] == n)                /* null input--all zero length codes */
+  {
+    *t = (struct huft *)NULL;
+    *m = 0;
+    return 0;
+  }
+
+
+  /* Find minimum and maximum length, bound *m by those */
+  l = *m;
+  for (j = 1; j <= BMAX; j++)
+    if (c[j])
+      break;
+  k = j;                        /* minimum code length */
+  if ((unsigned)l < j)
+    l = j;
+  for (i = BMAX; i; i--)
+    if (c[i])
+      break;
+  g = i;                        /* maximum code length */
+  if ((unsigned)l > i)
+    l = i;
+  *m = l;
+
+
+  /* Adjust last length count to fill out codes, if needed */
+  for (y = 1 << j; j < i; j++, y <<= 1)
+    if ((y -= c[j]) < 0)
+      return 2;                 /* bad input: more codes than bits */
+  if ((y -= c[i]) < 0)
+    return 2;
+  c[i] += y;
+
+
+  /* Generate starting offsets into the value table for each length */
+  x[1] = j = 0;
+  p = c + 1;  xp = x + 2;
+  while (--i) {                 /* note that i == g from above */
+    *xp++ = (j += *p++);
+  }
+
+
+  /* Make a table of values in order of bit lengths */
+  p = b;  i = 0;
+  do {
+    if ((j = *p++) != 0)
+      v[x[j]++] = i;
+  } while (++i < n);
+
+
+  /* Generate the Huffman codes and for each, make the table entries */
+  x[0] = i = 0;                 /* first Huffman code is zero */
+  p = v;                        /* grab values in bit order */
+  h = -1;                       /* no tables yet--level -1 */
+  w = -l;                       /* bits decoded == (l * h) */
+  u[0] = (struct huft *)NULL;   /* just to keep compilers happy */
+  q = (struct huft *)NULL;      /* ditto */
+  z = 0;                        /* ditto */
+
+  /* go through the bit lengths (k already is bits in shortest code) */
+  for (; k <= g; k++)
+  {
+    a = c[k];
+    while (a--)
+    {
+      /* here i is the Huffman code of length k bits for value *p */
+      /* make tables up to required level */
+      while (k > w + l)
+      {
+        h++;
+        w += l;                 /* previous table always l bits */
+
+        /* compute minimum size table less than or equal to l bits */
+        z = (z = g - w) > (unsigned)l ? (unsigned)l : z;  /* upper limit on table size */
+        if ((f = 1 << (j = k - w)) > a + 1)     /* try a k-w bit table */
+        {                       /* too few codes for k-w bit table */
+          f -= a + 1;           /* deduct codes from patterns left */
+          xp = c + k;
+          while (++j < z)       /* try smaller tables up to z bits */
+          {
+            if ((f <<= 1) <= *++xp)
+              break;            /* enough codes to use up j bits */
+            f -= *xp;           /* else deduct codes from patterns */
+          }
+        }
+        z = 1 << j;             /* table entries for j-bit table */
+
+        /* allocate and link in new table */
+        if ((q = (struct huft *)malloc((z + 1)*sizeof(struct huft))) ==
+            (struct huft *)NULL)
+        {
+          if (h)
+            huft_free(u[0]);
+          return 3;             /* not enough memory */
+        }
+        hufts += z + 1;         /* track memory usage */
+        *t = q + 1;             /* link to list for huft_free() */
+        *(t = &(q->v.t)) = (struct huft *)NULL;
+        u[h] = ++q;             /* table starts after link */
+
+        /* connect to last table, if there is one */
+        if (h)
+        {
+          x[h] = i;             /* save pattern for backing up */
+          r.b = (uch)l;         /* bits to dump before this table */
+          r.e = (uch)(16 + j);  /* bits in this table */
+          r.v.t = q;            /* pointer to this table */
+          j = i >> (w - l);     /* (get around Turbo C bug) */
+          u[h-1][j] = r;        /* connect to last table */
+        }
+      }
+
+      /* set up table entry in r */
+      r.b = (uch)(k - w);
+      if (p >= v + n)
+        r.e = 99;               /* out of values--invalid code */
+      else if (*p < s)
+      {
+        r.e = (uch)(*p < 256 ? 16 : 15);    /* 256 is end-of-block code */
+        r.v.n = (ush)(*p);             /* simple code is just the value */
+	p++;                           /* one compiler does not like *p++ */
+      }
+      else
+      {
+        r.e = (uch)e[*p - s];   /* non-simple--look up in lists */
+        r.v.n = d[*p++ - s];
+      }
+
+      /* fill code-like entries with r */
+      f = 1 << (k - w);
+      for (j = i >> w; j < z; j += f)
+        q[j] = r;
+
+      /* backwards increment the k-bit code i */
+      for (j = 1 << (k - 1); i & j; j >>= 1)
+        i ^= j;
+      i ^= j;
+
+      /* backup over finished tables */
+      while ((i & ((1 << w) - 1)) != x[h])
+      {
+        h--;                    /* don't need to update q */
+        w -= l;
+      }
+    }
+  }
+
+
+  /* Return true (1) if we were given an incomplete table */
+  return y != 0 && g != 1;
+}
+
+
+
+int huft_free(t)
+struct huft *t;         /* table to free */
+/* Free the malloc'ed tables built by huft_build(), which makes a linked
+   list of the tables it made, with the links in a dummy first entry of
+   each table. */
+{
+  register struct huft *p, *q;
+
+
+  /* Go through linked list, freeing from the malloced (t[-1]) address. */
+  p = t;
+  while (p != (struct huft *)NULL)
+  {
+    q = (--p)->v.t;
+    free((char*)p);
+    p = q;
+  }
+  return 0;
+}
+
+
+int inflate_codes(tl, td, bl, bd)
+struct huft *tl, *td;   /* literal/length and distance decoder tables */
+int bl, bd;             /* number of bits decoded by tl[] and td[] */
+/* inflate (decompress) the codes in a deflated (compressed) block.
+   Return an error code or zero if it all goes ok. */
+{
+  register unsigned e;  /* table entry flag/number of extra bits */
+  unsigned n, d;        /* length and index for copy */
+  unsigned w;           /* current window position */
+  struct huft *t;       /* pointer to table entry */
+  unsigned ml, md;      /* masks for bl and bd bits */
+  register ulg b;       /* bit buffer */
+  register unsigned k;  /* number of bits in bit buffer */
+
+
+  /* make local copies of globals */
+  b = bb;                       /* initialize bit buffer */
+  k = bk;
+  w = wp;                       /* initialize window position */
+
+  /* inflate the coded data */
+  ml = mask_bits[bl];           /* precompute masks for speed */
+  md = mask_bits[bd];
+  for (;;)                      /* do until end of block */
+  {
+    NEEDBITS((unsigned)bl)
+    if ((e = (t = tl + ((unsigned)b & ml))->e) > 16)
+      do {
+        if (e == 99)
+          return 1;
+        DUMPBITS(t->b)
+        e -= 16;
+        NEEDBITS(e)
+      } while ((e = (t = t->v.t + ((unsigned)b & mask_bits[e]))->e) > 16);
+    DUMPBITS(t->b)
+    if (e == 16)                /* then it's a literal */
+    {
+      slide[w++] = (uch)t->v.n;
+      Tracevv((stderr, "%c", slide[w-1]));
+      if (w == WSIZE)
+      {
+        flush_output(w);
+        w = 0;
+      }
+    }
+    else                        /* it's an EOB or a length */
+    {
+      /* exit if end of block */
+      if (e == 15)
+        break;
+
+      /* get length of block to copy */
+      NEEDBITS(e)
+      n = t->v.n + ((unsigned)b & mask_bits[e]);
+      DUMPBITS(e);
+
+      /* decode distance of block to copy */
+      NEEDBITS((unsigned)bd)
+      if ((e = (t = td + ((unsigned)b & md))->e) > 16)
+        do {
+          if (e == 99)
+            return 1;
+          DUMPBITS(t->b)
+          e -= 16;
+          NEEDBITS(e)
+        } while ((e = (t = t->v.t + ((unsigned)b & mask_bits[e]))->e) > 16);
+      DUMPBITS(t->b)
+      NEEDBITS(e)
+      d = w - t->v.n - ((unsigned)b & mask_bits[e]);
+      DUMPBITS(e)
+      Tracevv((stderr,"\\[%d,%d]", w-d, n));
+
+      /* do the copy */
+      do {
+        n -= (e = (e = WSIZE - ((d &= WSIZE-1) > w ? d : w)) > n ? n : e);
+#if !defined(NOMEMCPY) && !defined(DEBUG)
+        if (w - d >= e)         /* (this test assumes unsigned comparison) */
+        {
+          memcpy(slide + w, slide + d, e);
+          w += e;
+          d += e;
+        }
+        else                      /* do it slow to avoid memcpy() overlap */
+#endif /* !NOMEMCPY */
+          do {
+            slide[w++] = slide[d++];
+	    Tracevv((stderr, "%c", slide[w-1]));
+          } while (--e);
+        if (w == WSIZE)
+        {
+          flush_output(w);
+          w = 0;
+        }
+      } while (n);
+    }
+  }
+
+
+  /* restore the globals from the locals */
+  wp = w;                       /* restore global window pointer */
+  bb = b;                       /* restore global bit buffer */
+  bk = k;
+
+  /* done */
+  return 0;
+}
+
+
+
+int inflate_stored()
+/* "decompress" an inflated type 0 (stored) block. */
+{
+  unsigned n;           /* number of bytes in block */
+  unsigned w;           /* current window position */
+  register ulg b;       /* bit buffer */
+  register unsigned k;  /* number of bits in bit buffer */
+
+
+  /* make local copies of globals */
+  b = bb;                       /* initialize bit buffer */
+  k = bk;
+  w = wp;                       /* initialize window position */
+
+
+  /* go to byte boundary */
+  n = k & 7;
+  DUMPBITS(n);
+
+
+  /* get the length and its complement */
+  NEEDBITS(16)
+  n = ((unsigned)b & 0xffff);
+  DUMPBITS(16)
+  NEEDBITS(16)
+  if (n != (unsigned)((~b) & 0xffff))
+    return 1;                   /* error in compressed data */
+  DUMPBITS(16)
+
+
+  /* read and output the compressed data */
+  while (n--)
+  {
+    NEEDBITS(8)
+    slide[w++] = (uch)b;
+    if (w == WSIZE)
+    {
+      flush_output(w);
+      w = 0;
+    }
+    DUMPBITS(8)
+  }
+
+
+  /* restore the globals from the locals */
+  wp = w;                       /* restore global window pointer */
+  bb = b;                       /* restore global bit buffer */
+  bk = k;
+  return 0;
+}
+
+
+
+int inflate_fixed()
+/* decompress an inflated type 1 (fixed Huffman codes) block.  We should
+   either replace this with a custom decoder, or at least precompute the
+   Huffman tables. */
+{
+  int i;                /* temporary variable */
+  struct huft *tl;      /* literal/length code table */
+  struct huft *td;      /* distance code table */
+  int bl;               /* lookup bits for tl */
+  int bd;               /* lookup bits for td */
+  unsigned l[288];      /* length list for huft_build */
+
+
+  /* set up literal table */
+  for (i = 0; i < 144; i++)
+    l[i] = 8;
+  for (; i < 256; i++)
+    l[i] = 9;
+  for (; i < 280; i++)
+    l[i] = 7;
+  for (; i < 288; i++)          /* make a complete, but wrong code set */
+    l[i] = 8;
+  bl = 7;
+  if ((i = huft_build(l, 288, 257, cplens, cplext, &tl, &bl)) != 0)
+    return i;
+
+
+  /* set up distance table */
+  for (i = 0; i < 30; i++)      /* make an incomplete code set */
+    l[i] = 5;
+  bd = 5;
+  if ((i = huft_build(l, 30, 0, cpdist, cpdext, &td, &bd)) > 1)
+  {
+    huft_free(tl);
+    return i;
+  }
+
+
+  /* decompress until an end-of-block code */
+  if (inflate_codes(tl, td, bl, bd))
+    return 1;
+
+
+  /* free the decoding tables, return */
+  huft_free(tl);
+  huft_free(td);
+  return 0;
+}
+
+
+
+int inflate_dynamic()
+/* decompress an inflated type 2 (dynamic Huffman codes) block. */
+{
+  int i;                /* temporary variables */
+  unsigned j;
+  unsigned l;           /* last length */
+  unsigned m;           /* mask for bit lengths table */
+  unsigned n;           /* number of lengths to get */
+  struct huft *tl;      /* literal/length code table */
+  struct huft *td;      /* distance code table */
+  int bl;               /* lookup bits for tl */
+  int bd;               /* lookup bits for td */
+  unsigned nb;          /* number of bit length codes */
+  unsigned nl;          /* number of literal/length codes */
+  unsigned nd;          /* number of distance codes */
+#ifdef PKZIP_BUG_WORKAROUND
+  unsigned ll[288+32];  /* literal/length and distance code lengths */
+#else
+  unsigned ll[286+30];  /* literal/length and distance code lengths */
+#endif
+  register ulg b;       /* bit buffer */
+  register unsigned k;  /* number of bits in bit buffer */
+
+
+  /* make local bit buffer */
+  b = bb;
+  k = bk;
+
+
+  /* read in table lengths */
+  NEEDBITS(5)
+  nl = 257 + ((unsigned)b & 0x1f);      /* number of literal/length codes */
+  DUMPBITS(5)
+  NEEDBITS(5)
+  nd = 1 + ((unsigned)b & 0x1f);        /* number of distance codes */
+  DUMPBITS(5)
+  NEEDBITS(4)
+  nb = 4 + ((unsigned)b & 0xf);         /* number of bit length codes */
+  DUMPBITS(4)
+#ifdef PKZIP_BUG_WORKAROUND
+  if (nl > 288 || nd > 32)
+#else
+  if (nl > 286 || nd > 30)
+#endif
+    return 1;                   /* bad lengths */
+
+
+  /* read in bit-length-code lengths */
+  for (j = 0; j < nb; j++)
+  {
+    NEEDBITS(3)
+    ll[border[j]] = (unsigned)b & 7;
+    DUMPBITS(3)
+  }
+  for (; j < 19; j++)
+    ll[border[j]] = 0;
+
+
+  /* build decoding table for trees--single level, 7 bit lookup */
+  bl = 7;
+  if ((i = huft_build(ll, 19, 19, NULL, NULL, &tl, &bl)) != 0)
+  {
+    if (i == 1)
+      huft_free(tl);
+    return i;                   /* incomplete code set */
+  }
+
+
+  /* read in literal and distance code lengths */
+  n = nl + nd;
+  m = mask_bits[bl];
+  i = l = 0;
+  while ((unsigned)i < n)
+  {
+    NEEDBITS((unsigned)bl)
+    j = (td = tl + ((unsigned)b & m))->b;
+    DUMPBITS(j)
+    j = td->v.n;
+    if (j < 16)                 /* length of code in bits (0..15) */
+      ll[i++] = l = j;          /* save last length in l */
+    else if (j == 16)           /* repeat last length 3 to 6 times */
+    {
+      NEEDBITS(2)
+      j = 3 + ((unsigned)b & 3);
+      DUMPBITS(2)
+      if ((unsigned)i + j > n)
+        return 1;
+      while (j--)
+        ll[i++] = l;
+    }
+    else if (j == 17)           /* 3 to 10 zero length codes */
+    {
+      NEEDBITS(3)
+      j = 3 + ((unsigned)b & 7);
+      DUMPBITS(3)
+      if ((unsigned)i + j > n)
+        return 1;
+      while (j--)
+        ll[i++] = 0;
+      l = 0;
+    }
+    else                        /* j == 18: 11 to 138 zero length codes */
+    {
+      NEEDBITS(7)
+      j = 11 + ((unsigned)b & 0x7f);
+      DUMPBITS(7)
+      if ((unsigned)i + j > n)
+        return 1;
+      while (j--)
+        ll[i++] = 0;
+      l = 0;
+    }
+  }
+
+
+  /* free decoding table for trees */
+  huft_free(tl);
+
+
+  /* restore the global bit buffer */
+  bb = b;
+  bk = k;
+
+
+  /* build the decoding tables for literal/length and distance codes */
+  bl = lbits;
+  if ((i = huft_build(ll, nl, 257, cplens, cplext, &tl, &bl)) != 0)
+  {
+    if (i == 1) {
+      fprintf(stderr, " incomplete literal tree\n");
+      huft_free(tl);
+    }
+    return i;                   /* incomplete code set */
+  }
+  bd = dbits;
+  if ((i = huft_build(ll + nl, nd, 0, cpdist, cpdext, &td, &bd)) != 0)
+  {
+    if (i == 1) {
+      fprintf(stderr, " incomplete distance tree\n");
+#ifdef PKZIP_BUG_WORKAROUND
+      i = 0;
+    }
+#else
+      huft_free(td);
+    }
+    huft_free(tl);
+    return i;                   /* incomplete code set */
+#endif
+  }
+
+
+  /* decompress until an end-of-block code */
+  if (inflate_codes(tl, td, bl, bd))
+    return 1;
+
+
+  /* free the decoding tables, return */
+  huft_free(tl);
+  huft_free(td);
+  return 0;
+}
+
+
+
+int inflate_block(e)
+int *e;                 /* last block flag */
+/* decompress an inflated block */
+{
+  unsigned t;           /* block type */
+  register ulg b;       /* bit buffer */
+  register unsigned k;  /* number of bits in bit buffer */
+
+
+  /* make local bit buffer */
+  b = bb;
+  k = bk;
+
+
+  /* read in last block bit */
+  NEEDBITS(1)
+  *e = (int)b & 1;
+  DUMPBITS(1)
+
+
+  /* read in block type */
+  NEEDBITS(2)
+  t = (unsigned)b & 3;
+  DUMPBITS(2)
+
+
+  /* restore the global bit buffer */
+  bb = b;
+  bk = k;
+
+
+  /* inflate that block type */
+  if (t == 2)
+    return inflate_dynamic();
+  if (t == 0)
+    return inflate_stored();
+  if (t == 1)
+    return inflate_fixed();
+
+
+  /* bad block type */
+  return 2;
+}
+
+
+
+int inflate()
+/* decompress an inflated entry */
+{
+  int e;                /* last block flag */
+  int r;                /* result code */
+  unsigned h;           /* maximum struct huft's malloc'ed */
+
+
+  /* initialize window, bit buffer */
+  wp = 0;
+  bk = 0;
+  bb = 0;
+
+
+  /* decompress until the last block */
+  h = 0;
+  do {
+    hufts = 0;
+    if ((r = inflate_block(&e)) != 0)
+      return r;
+    if (hufts > h)
+      h = hufts;
+  } while (!e);
+
+  /* Undo too much lookahead. The next read will be byte aligned so we
+   * can discard unused bits in the last meaningful byte.
+   */
+  while (bk >= 8) {
+    bk -= 8;
+    inptr--;
+  }
+
+  /* flush out slide */
+  flush_output(wp);
+
+
+  /* return success */
+#ifdef DEBUG
+  fprintf(stderr, "<%u> ", h);
+#endif /* DEBUG */
+  return 0;
+}
diff --git a/usr/gzip/revision.h b/usr/gzip/revision.h
new file mode 100644
index 0000000..736020b
--- /dev/null
+++ b/usr/gzip/revision.h
@@ -0,0 +1,11 @@
+/* revision.h -- define the version number
+ * Copyright (C) 1992-1993 Jean-loup Gailly.
+ * This is free software; you can redistribute it and/or modify it under the
+ * terms of the GNU General Public License, see the file COPYING.
+ */
+
+#define VERSION "1.2.4"
+#define PATCHLEVEL 0
+#define REVDATE "18 Aug 93"
+
+/* $Id: revision.h,v 1.1 2002/08/18 00:59:21 hpa Exp $ */
diff --git a/usr/gzip/tailor.h b/usr/gzip/tailor.h
new file mode 100644
index 0000000..849e589
--- /dev/null
+++ b/usr/gzip/tailor.h
@@ -0,0 +1,50 @@
+/* tailor.h -- target dependent definitions
+ * Copyright (C) 1992-1993 Jean-loup Gailly.
+ * This is free software; you can redistribute it and/or modify it under the
+ * terms of the GNU General Public License, see the file COPYING.
+ */
+
+/* The target dependent definitions should be defined here only.
+ * The target dependent functions should be defined in tailor.c.
+ */
+
+/* $Id: tailor.h,v 1.1 2002/08/18 00:59:21 hpa Exp $ */
+
+	/* Common defaults */
+
+#ifndef OS_CODE
+#  define OS_CODE  0x03  /* assume Unix */
+#endif
+
+#define PATH_SEP '/'
+
+#ifndef casemap
+#  define casemap(c) (c)
+#endif
+
+#ifndef OPTIONS_VAR
+#  define OPTIONS_VAR "GZIP"
+#endif
+
+#ifndef Z_SUFFIX
+#  define Z_SUFFIX ".gz"
+#endif
+
+#define MAX_SUFFIX  30
+
+#ifndef MIN_PART
+#  define MIN_PART 3
+   /* keep at least MIN_PART chars between dots in a file name. */
+#endif
+
+#ifndef RECORD_IO
+#  define RECORD_IO 0
+#endif
+
+#ifndef get_char
+#  define get_char() get_byte()
+#endif
+
+#ifndef put_char
+#  define put_char(c) put_byte(c)
+#endif
diff --git a/usr/gzip/trees.c b/usr/gzip/trees.c
new file mode 100644
index 0000000..75efc97
--- /dev/null
+++ b/usr/gzip/trees.c
@@ -0,0 +1,1075 @@
+/* trees.c -- output deflated data using Huffman coding
+ * Copyright (C) 1992-1993 Jean-loup Gailly
+ * This is free software; you can redistribute it and/or modify it under the
+ * terms of the GNU General Public License, see the file COPYING.
+ */
+
+/*
+ *  PURPOSE
+ *
+ *      Encode various sets of source values using variable-length
+ *      binary code trees.
+ *
+ *  DISCUSSION
+ *
+ *      The PKZIP "deflation" process uses several Huffman trees. The more
+ *      common source values are represented by shorter bit sequences.
+ *
+ *      Each code tree is stored in the ZIP file in a compressed form
+ *      which is itself a Huffman encoding of the lengths of
+ *      all the code strings (in ascending order by source values).
+ *      The actual code strings are reconstructed from the lengths in
+ *      the UNZIP process, as described in the "application note"
+ *      (APPNOTE.TXT) distributed as part of PKWARE's PKZIP program.
+ *
+ *  REFERENCES
+ *
+ *      Lynch, Thomas J.
+ *          Data Compression:  Techniques and Applications, pp. 53-55.
+ *          Lifetime Learning Publications, 1985.  ISBN 0-534-03418-7.
+ *
+ *      Storer, James A.
+ *          Data Compression:  Methods and Theory, pp. 49-50.
+ *          Computer Science Press, 1988.  ISBN 0-7167-8156-5.
+ *
+ *      Sedgewick, R.
+ *          Algorithms, p290.
+ *          Addison-Wesley, 1983. ISBN 0-201-06672-6.
+ *
+ *  INTERFACE
+ *
+ *      void ct_init (ush *attr, int *methodp)
+ *          Allocate the match buffer, initialize the various tables and save
+ *          the location of the internal file attribute (ascii/binary) and
+ *          method (DEFLATE/STORE)
+ *
+ *      void ct_tally (int dist, int lc);
+ *          Save the match info and tally the frequency counts.
+ *
+ *      long flush_block (char *buf, ulg stored_len, int eof)
+ *          Determine the best encoding for the current block: dynamic trees,
+ *          static trees or store, and output the encoded block to the zip
+ *          file. Returns the total compressed length for the file so far.
+ *
+ */
+
+#include <ctype.h>
+
+#include "tailor.h"
+#include "gzip.h"
+
+#ifdef RCSID
+static char rcsid[] = "$Id: trees.c,v 1.1 2002/08/18 00:59:21 hpa Exp $";
+#endif
+
+/* ===========================================================================
+ * Constants
+ */
+
+#define MAX_BITS 15
+/* All codes must not exceed MAX_BITS bits */
+
+#define MAX_BL_BITS 7
+/* Bit length codes must not exceed MAX_BL_BITS bits */
+
+#define LENGTH_CODES 29
+/* number of length codes, not counting the special END_BLOCK code */
+
+#define LITERALS  256
+/* number of literal bytes 0..255 */
+
+#define END_BLOCK 256
+/* end of block literal code */
+
+#define L_CODES (LITERALS+1+LENGTH_CODES)
+/* number of Literal or Length codes, including the END_BLOCK code */
+
+#define D_CODES   30
+/* number of distance codes */
+
+#define BL_CODES  19
+/* number of codes used to transfer the bit lengths */
+
+
+local int extra_lbits[LENGTH_CODES] /* extra bits for each length code */
+   = {0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0};
+
+local int extra_dbits[D_CODES] /* extra bits for each distance code */
+   = {0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13};
+
+local int extra_blbits[BL_CODES]/* extra bits for each bit length code */
+   = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,7};
+
+#define STORED_BLOCK 0
+#define STATIC_TREES 1
+#define DYN_TREES    2
+/* The three kinds of block type */
+
+#ifndef LIT_BUFSIZE
+#  ifdef SMALL_MEM
+#    define LIT_BUFSIZE  0x2000
+#  else
+#  ifdef MEDIUM_MEM
+#    define LIT_BUFSIZE  0x4000
+#  else
+#    define LIT_BUFSIZE  0x8000
+#  endif
+#  endif
+#endif
+#ifndef DIST_BUFSIZE
+#  define DIST_BUFSIZE  LIT_BUFSIZE
+#endif
+/* Sizes of match buffers for literals/lengths and distances.  There are
+ * 4 reasons for limiting LIT_BUFSIZE to 64K:
+ *   - frequencies can be kept in 16 bit counters
+ *   - if compression is not successful for the first block, all input data is
+ *     still in the window so we can still emit a stored block even when input
+ *     comes from standard input.  (This can also be done for all blocks if
+ *     LIT_BUFSIZE is not greater than 32K.)
+ *   - if compression is not successful for a file smaller than 64K, we can
+ *     even emit a stored file instead of a stored block (saving 5 bytes).
+ *   - creating new Huffman trees less frequently may not provide fast
+ *     adaptation to changes in the input data statistics. (Take for
+ *     example a binary file with poorly compressible code followed by
+ *     a highly compressible string table.) Smaller buffer sizes give
+ *     fast adaptation but have of course the overhead of transmitting trees
+ *     more frequently.
+ *   - I can't count above 4
+ * The current code is general and allows DIST_BUFSIZE < LIT_BUFSIZE (to save
+ * memory at the expense of compression). Some optimizations would be possible
+ * if we rely on DIST_BUFSIZE == LIT_BUFSIZE.
+ */
+#if LIT_BUFSIZE > INBUFSIZ
+    error cannot overlay l_buf and inbuf
+#endif
+
+#define REP_3_6      16
+/* repeat previous bit length 3-6 times (2 bits of repeat count) */
+
+#define REPZ_3_10    17
+/* repeat a zero length 3-10 times  (3 bits of repeat count) */
+
+#define REPZ_11_138  18
+/* repeat a zero length 11-138 times  (7 bits of repeat count) */
+
+/* ===========================================================================
+ * Local data
+ */
+
+/* Data structure describing a single value and its code string. */
+typedef struct ct_data {
+    union {
+        ush  freq;       /* frequency count */
+        ush  code;       /* bit string */
+    } fc;
+    union {
+        ush  dad;        /* father node in Huffman tree */
+        ush  len;        /* length of bit string */
+    } dl;
+} ct_data;
+
+#define Freq fc.freq
+#define Code fc.code
+#define Dad  dl.dad
+#define Len  dl.len
+
+#define HEAP_SIZE (2*L_CODES+1)
+/* maximum heap size */
+
+local ct_data dyn_ltree[HEAP_SIZE];   /* literal and length tree */
+local ct_data dyn_dtree[2*D_CODES+1]; /* distance tree */
+
+local ct_data static_ltree[L_CODES+2];
+/* The static literal tree. Since the bit lengths are imposed, there is no
+ * need for the L_CODES extra codes used during heap construction. However
+ * The codes 286 and 287 are needed to build a canonical tree (see ct_init
+ * below).
+ */
+
+local ct_data static_dtree[D_CODES];
+/* The static distance tree. (Actually a trivial tree since all codes use
+ * 5 bits.)
+ */
+
+local ct_data bl_tree[2*BL_CODES+1];
+/* Huffman tree for the bit lengths */
+
+typedef struct tree_desc {
+    ct_data *dyn_tree;      /* the dynamic tree */
+    ct_data *static_tree;   /* corresponding static tree or NULL */
+    int     *extra_bits;    /* extra bits for each code or NULL */
+    int     extra_base;          /* base index for extra_bits */
+    int     elems;               /* max number of elements in the tree */
+    int     max_length;          /* max bit length for the codes */
+    int     max_code;            /* largest code with non zero frequency */
+} tree_desc;
+
+local tree_desc l_desc =
+{dyn_ltree, static_ltree, extra_lbits, LITERALS+1, L_CODES, MAX_BITS, 0};
+
+local tree_desc d_desc =
+{dyn_dtree, static_dtree, extra_dbits, 0,          D_CODES, MAX_BITS, 0};
+
+local tree_desc bl_desc =
+{bl_tree, (ct_data *)0, extra_blbits, 0,      BL_CODES, MAX_BL_BITS, 0};
+
+
+local ush bl_count[MAX_BITS+1];
+/* number of codes at each bit length for an optimal tree */
+
+local uch bl_order[BL_CODES]
+   = {16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15};
+/* The lengths of the bit length codes are sent in order of decreasing
+ * probability, to avoid transmitting the lengths for unused bit length codes.
+ */
+
+local int heap[2*L_CODES+1]; /* heap used to build the Huffman trees */
+local int heap_len;               /* number of elements in the heap */
+local int heap_max;               /* element of largest frequency */
+/* The sons of heap[n] are heap[2*n] and heap[2*n+1]. heap[0] is not used.
+ * The same heap array is used to build all trees.
+ */
+
+local uch depth[2*L_CODES+1];
+/* Depth of each subtree used as tie breaker for trees of equal frequency */
+
+local uch length_code[MAX_MATCH-MIN_MATCH+1];
+/* length code for each normalized match length (0 == MIN_MATCH) */
+
+local uch dist_code[512];
+/* distance codes. The first 256 values correspond to the distances
+ * 3 .. 258, the last 256 values correspond to the top 8 bits of
+ * the 15 bit distances.
+ */
+
+local int base_length[LENGTH_CODES];
+/* First normalized length for each code (0 = MIN_MATCH) */
+
+local int base_dist[D_CODES];
+/* First normalized distance for each code (0 = distance of 1) */
+
+#define l_buf inbuf
+/* DECLARE(uch, l_buf, LIT_BUFSIZE);  buffer for literals or lengths */
+
+/* DECLARE(ush, d_buf, DIST_BUFSIZE); buffer for distances */
+
+local uch flag_buf[(LIT_BUFSIZE/8)];
+/* flag_buf is a bit array distinguishing literals from lengths in
+ * l_buf, thus indicating the presence or absence of a distance.
+ */
+
+local unsigned last_lit;    /* running index in l_buf */
+local unsigned last_dist;   /* running index in d_buf */
+local unsigned last_flags;  /* running index in flag_buf */
+local uch flags;            /* current flags not yet saved in flag_buf */
+local uch flag_bit;         /* current bit used in flags */
+/* bits are filled in flags starting at bit 0 (least significant).
+ * Note: these flags are overkill in the current code since we don't
+ * take advantage of DIST_BUFSIZE == LIT_BUFSIZE.
+ */
+
+local ulg opt_len;        /* bit length of current block with optimal trees */
+local ulg static_len;     /* bit length of current block with static trees */
+
+local ulg compressed_len; /* total bit length of compressed file */
+
+local ulg input_len;      /* total byte length of input file */
+/* input_len is for debugging only since we can get it by other means. */
+
+ush *file_type;        /* pointer to UNKNOWN, BINARY or ASCII */
+int *file_method;      /* pointer to DEFLATE or STORE */
+
+#ifdef DEBUG
+extern ulg bits_sent;  /* bit length of the compressed data */
+extern long isize;     /* byte length of input file */
+#endif
+
+extern long block_start;       /* window offset of current block */
+extern unsigned strstart; /* window offset of current string */
+
+/* ===========================================================================
+ * Local (static) routines in this file.
+ */
+
+local void init_block     OF((void));
+local void pqdownheap     OF((ct_data *tree, int k));
+local void gen_bitlen     OF((tree_desc *desc));
+local void gen_codes      OF((ct_data *tree, int max_code));
+local void build_tree     OF((tree_desc *desc));
+local void scan_tree      OF((ct_data *tree, int max_code));
+local void send_tree      OF((ct_data *tree, int max_code));
+local int  build_bl_tree  OF((void));
+local void send_all_trees OF((int lcodes, int dcodes, int blcodes));
+local void compress_block OF((ct_data *ltree, ct_data *dtree));
+local void set_file_type  OF((void));
+
+
+#ifndef DEBUG
+#  define send_code(c, tree) send_bits(tree[c].Code, tree[c].Len)
+   /* Send a code of the given tree. c and tree must not have side effects */
+
+#else /* DEBUG */
+#  define send_code(c, tree) \
+     { if (verbose>1) fprintf(stderr,"\ncd %3d ",(c)); \
+       send_bits(tree[c].Code, tree[c].Len); }
+#endif
+
+#define d_code(dist) \
+   ((dist) < 256 ? dist_code[dist] : dist_code[256+((dist)>>7)])
+/* Mapping from a distance to a distance code. dist is the distance - 1 and
+ * must not have side effects. dist_code[256] and dist_code[257] are never
+ * used.
+ */
+
+#define MAX(a,b) (a >= b ? a : b)
+/* the arguments must not have side effects */
+
+/* ===========================================================================
+ * Allocate the match buffer, initialize the various tables and save the
+ * location of the internal file attribute (ascii/binary) and method
+ * (DEFLATE/STORE).
+ */
+void ct_init(attr, methodp)
+    ush  *attr;   /* pointer to internal file attribute */
+    int  *methodp; /* pointer to compression method */
+{
+    int n;        /* iterates over tree elements */
+    int bits;     /* bit counter */
+    int length;   /* length value */
+    int code;     /* code value */
+    int dist;     /* distance index */
+
+    file_type = attr;
+    file_method = methodp;
+    compressed_len = input_len = 0L;
+
+    if (static_dtree[0].Len != 0) return; /* ct_init already called */
+
+    /* Initialize the mapping length (0..255) -> length code (0..28) */
+    length = 0;
+    for (code = 0; code < LENGTH_CODES-1; code++) {
+        base_length[code] = length;
+        for (n = 0; n < (1<<extra_lbits[code]); n++) {
+            length_code[length++] = (uch)code;
+        }
+    }
+    Assert (length == 256, "ct_init: length != 256");
+    /* Note that the length 255 (match length 258) can be represented
+     * in two different ways: code 284 + 5 bits or code 285, so we
+     * overwrite length_code[255] to use the best encoding:
+     */
+    length_code[length-1] = (uch)code;
+
+    /* Initialize the mapping dist (0..32K) -> dist code (0..29) */
+    dist = 0;
+    for (code = 0 ; code < 16; code++) {
+        base_dist[code] = dist;
+        for (n = 0; n < (1<<extra_dbits[code]); n++) {
+            dist_code[dist++] = (uch)code;
+        }
+    }
+    Assert (dist == 256, "ct_init: dist != 256");
+    dist >>= 7; /* from now on, all distances are divided by 128 */
+    for ( ; code < D_CODES; code++) {
+        base_dist[code] = dist << 7;
+        for (n = 0; n < (1<<(extra_dbits[code]-7)); n++) {
+            dist_code[256 + dist++] = (uch)code;
+        }
+    }
+    Assert (dist == 256, "ct_init: 256+dist != 512");
+
+    /* Construct the codes of the static literal tree */
+    for (bits = 0; bits <= MAX_BITS; bits++) bl_count[bits] = 0;
+    n = 0;
+    while (n <= 143) static_ltree[n++].Len = 8, bl_count[8]++;
+    while (n <= 255) static_ltree[n++].Len = 9, bl_count[9]++;
+    while (n <= 279) static_ltree[n++].Len = 7, bl_count[7]++;
+    while (n <= 287) static_ltree[n++].Len = 8, bl_count[8]++;
+    /* Codes 286 and 287 do not exist, but we must include them in the
+     * tree construction to get a canonical Huffman tree (longest code
+     * all ones)
+     */
+    gen_codes((ct_data *)static_ltree, L_CODES+1);
+
+    /* The static distance tree is trivial: */
+    for (n = 0; n < D_CODES; n++) {
+        static_dtree[n].Len = 5;
+        static_dtree[n].Code = bi_reverse(n, 5);
+    }
+
+    /* Initialize the first block of the first file: */
+    init_block();
+}
+
+/* ===========================================================================
+ * Initialize a new block.
+ */
+local void init_block()
+{
+    int n; /* iterates over tree elements */
+
+    /* Initialize the trees. */
+    for (n = 0; n < L_CODES;  n++) dyn_ltree[n].Freq = 0;
+    for (n = 0; n < D_CODES;  n++) dyn_dtree[n].Freq = 0;
+    for (n = 0; n < BL_CODES; n++) bl_tree[n].Freq = 0;
+
+    dyn_ltree[END_BLOCK].Freq = 1;
+    opt_len = static_len = 0L;
+    last_lit = last_dist = last_flags = 0;
+    flags = 0; flag_bit = 1;
+}
+
+#define SMALLEST 1
+/* Index within the heap array of least frequent node in the Huffman tree */
+
+
+/* ===========================================================================
+ * Remove the smallest element from the heap and recreate the heap with
+ * one less element. Updates heap and heap_len.
+ */
+#define pqremove(tree, top) \
+{\
+    top = heap[SMALLEST]; \
+    heap[SMALLEST] = heap[heap_len--]; \
+    pqdownheap(tree, SMALLEST); \
+}
+
+/* ===========================================================================
+ * Compares to subtrees, using the tree depth as tie breaker when
+ * the subtrees have equal frequency. This minimizes the worst case length.
+ */
+#define smaller(tree, n, m) \
+   (tree[n].Freq < tree[m].Freq || \
+   (tree[n].Freq == tree[m].Freq && depth[n] <= depth[m]))
+
+/* ===========================================================================
+ * Restore the heap property by moving down the tree starting at node k,
+ * exchanging a node with the smallest of its two sons if necessary, stopping
+ * when the heap property is re-established (each father smaller than its
+ * two sons).
+ */
+local void pqdownheap(tree, k)
+    ct_data *tree;  /* the tree to restore */
+    int k;               /* node to move down */
+{
+    int v = heap[k];
+    int j = k << 1;  /* left son of k */
+    while (j <= heap_len) {
+        /* Set j to the smallest of the two sons: */
+        if (j < heap_len && smaller(tree, heap[j+1], heap[j])) j++;
+
+        /* Exit if v is smaller than both sons */
+        if (smaller(tree, v, heap[j])) break;
+
+        /* Exchange v with the smallest son */
+        heap[k] = heap[j];  k = j;
+
+        /* And continue down the tree, setting j to the left son of k */
+        j <<= 1;
+    }
+    heap[k] = v;
+}
+
+/* ===========================================================================
+ * Compute the optimal bit lengths for a tree and update the total bit length
+ * for the current block.
+ * IN assertion: the fields freq and dad are set, heap[heap_max] and
+ *    above are the tree nodes sorted by increasing frequency.
+ * OUT assertions: the field len is set to the optimal bit length, the
+ *     array bl_count contains the frequencies for each bit length.
+ *     The length opt_len is updated; static_len is also updated if stree is
+ *     not null.
+ */
+local void gen_bitlen(desc)
+    tree_desc *desc; /* the tree descriptor */
+{
+    ct_data *tree  = desc->dyn_tree;
+    int *extra     = desc->extra_bits;
+    int base            = desc->extra_base;
+    int max_code        = desc->max_code;
+    int max_length      = desc->max_length;
+    ct_data *stree = desc->static_tree;
+    int h;              /* heap index */
+    int n, m;           /* iterate over the tree elements */
+    int bits;           /* bit length */
+    int xbits;          /* extra bits */
+    ush f;              /* frequency */
+    int overflow = 0;   /* number of elements with bit length too large */
+
+    for (bits = 0; bits <= MAX_BITS; bits++) bl_count[bits] = 0;
+
+    /* In a first pass, compute the optimal bit lengths (which may
+     * overflow in the case of the bit length tree).
+     */
+    tree[heap[heap_max]].Len = 0; /* root of the heap */
+
+    for (h = heap_max+1; h < HEAP_SIZE; h++) {
+        n = heap[h];
+        bits = tree[tree[n].Dad].Len + 1;
+        if (bits > max_length) bits = max_length, overflow++;
+        tree[n].Len = (ush)bits;
+        /* We overwrite tree[n].Dad which is no longer needed */
+
+        if (n > max_code) continue; /* not a leaf node */
+
+        bl_count[bits]++;
+        xbits = 0;
+        if (n >= base) xbits = extra[n-base];
+        f = tree[n].Freq;
+        opt_len += (ulg)f * (bits + xbits);
+        if (stree) static_len += (ulg)f * (stree[n].Len + xbits);
+    }
+    if (overflow == 0) return;
+
+    Trace((stderr,"\nbit length overflow\n"));
+    /* This happens for example on obj2 and pic of the Calgary corpus */
+
+    /* Find the first bit length which could increase: */
+    do {
+        bits = max_length-1;
+        while (bl_count[bits] == 0) bits--;
+        bl_count[bits]--;      /* move one leaf down the tree */
+        bl_count[bits+1] += 2; /* move one overflow item as its brother */
+        bl_count[max_length]--;
+        /* The brother of the overflow item also moves one step up,
+         * but this does not affect bl_count[max_length]
+         */
+        overflow -= 2;
+    } while (overflow > 0);
+
+    /* Now recompute all bit lengths, scanning in increasing frequency.
+     * h is still equal to HEAP_SIZE. (It is simpler to reconstruct all
+     * lengths instead of fixing only the wrong ones. This idea is taken
+     * from 'ar' written by Haruhiko Okumura.)
+     */
+    for (bits = max_length; bits != 0; bits--) {
+        n = bl_count[bits];
+        while (n != 0) {
+            m = heap[--h];
+            if (m > max_code) continue;
+            if (tree[m].Len != (unsigned) bits) {
+                Trace((stderr,"code %d bits %d->%d\n", m, tree[m].Len, bits));
+                opt_len += ((long)bits-(long)tree[m].Len)*(long)tree[m].Freq;
+                tree[m].Len = (ush)bits;
+            }
+            n--;
+        }
+    }
+}
+
+/* ===========================================================================
+ * Generate the codes for a given tree and bit counts (which need not be
+ * optimal).
+ * IN assertion: the array bl_count contains the bit length statistics for
+ * the given tree and the field len is set for all tree elements.
+ * OUT assertion: the field code is set for all tree elements of non
+ *     zero code length.
+ */
+local void gen_codes (tree, max_code)
+    ct_data *tree;        /* the tree to decorate */
+    int max_code;              /* largest code with non zero frequency */
+{
+    ush next_code[MAX_BITS+1]; /* next code value for each bit length */
+    ush code = 0;              /* running code value */
+    int bits;                  /* bit index */
+    int n;                     /* code index */
+
+    /* The distribution counts are first used to generate the code values
+     * without bit reversal.
+     */
+    for (bits = 1; bits <= MAX_BITS; bits++) {
+        next_code[bits] = code = (code + bl_count[bits-1]) << 1;
+    }
+    /* Check that the bit counts in bl_count are consistent. The last code
+     * must be all ones.
+     */
+    Assert (code + bl_count[MAX_BITS]-1 == (1<<MAX_BITS)-1,
+            "inconsistent bit counts");
+    Tracev((stderr,"\ngen_codes: max_code %d ", max_code));
+
+    for (n = 0;  n <= max_code; n++) {
+        int len = tree[n].Len;
+        if (len == 0) continue;
+        /* Now reverse the bits */
+        tree[n].Code = bi_reverse(next_code[len]++, len);
+
+        Tracec(tree != static_ltree, (stderr,"\nn %3d %c l %2d c %4x (%x) ",
+             n, (isgraph(n) ? n : ' '), len, tree[n].Code, next_code[len]-1));
+    }
+}
+
+/* ===========================================================================
+ * Construct one Huffman tree and assigns the code bit strings and lengths.
+ * Update the total bit length for the current block.
+ * IN assertion: the field freq is set for all tree elements.
+ * OUT assertions: the fields len and code are set to the optimal bit length
+ *     and corresponding code. The length opt_len is updated; static_len is
+ *     also updated if stree is not null. The field max_code is set.
+ */
+local void build_tree(desc)
+    tree_desc *desc; /* the tree descriptor */
+{
+    ct_data *tree   = desc->dyn_tree;
+    ct_data *stree  = desc->static_tree;
+    int elems            = desc->elems;
+    int n, m;          /* iterate over heap elements */
+    int max_code = -1; /* largest code with non zero frequency */
+    int node = elems;  /* next internal node of the tree */
+
+    /* Construct the initial heap, with least frequent element in
+     * heap[SMALLEST]. The sons of heap[n] are heap[2*n] and heap[2*n+1].
+     * heap[0] is not used.
+     */
+    heap_len = 0, heap_max = HEAP_SIZE;
+
+    for (n = 0; n < elems; n++) {
+        if (tree[n].Freq != 0) {
+            heap[++heap_len] = max_code = n;
+            depth[n] = 0;
+        } else {
+            tree[n].Len = 0;
+        }
+    }
+
+    /* The pkzip format requires that at least one distance code exists,
+     * and that at least one bit should be sent even if there is only one
+     * possible code. So to avoid special checks later on we force at least
+     * two codes of non zero frequency.
+     */
+    while (heap_len < 2) {
+        int new = heap[++heap_len] = (max_code < 2 ? ++max_code : 0);
+        tree[new].Freq = 1;
+        depth[new] = 0;
+        opt_len--; if (stree) static_len -= stree[new].Len;
+        /* new is 0 or 1 so it does not have extra bits */
+    }
+    desc->max_code = max_code;
+
+    /* The elements heap[heap_len/2+1 .. heap_len] are leaves of the tree,
+     * establish sub-heaps of increasing lengths:
+     */
+    for (n = heap_len/2; n >= 1; n--) pqdownheap(tree, n);
+
+    /* Construct the Huffman tree by repeatedly combining the least two
+     * frequent nodes.
+     */
+    do {
+        pqremove(tree, n);   /* n = node of least frequency */
+        m = heap[SMALLEST];  /* m = node of next least frequency */
+
+        heap[--heap_max] = n; /* keep the nodes sorted by frequency */
+        heap[--heap_max] = m;
+
+        /* Create a new node father of n and m */
+        tree[node].Freq = tree[n].Freq + tree[m].Freq;
+        depth[node] = (uch) (MAX(depth[n], depth[m]) + 1);
+        tree[n].Dad = tree[m].Dad = (ush)node;
+#ifdef DUMP_BL_TREE
+        if (tree == bl_tree) {
+            fprintf(stderr,"\nnode %d(%d), sons %d(%d) %d(%d)",
+                    node, tree[node].Freq, n, tree[n].Freq, m, tree[m].Freq);
+        }
+#endif
+        /* and insert the new node in the heap */
+        heap[SMALLEST] = node++;
+        pqdownheap(tree, SMALLEST);
+
+    } while (heap_len >= 2);
+
+    heap[--heap_max] = heap[SMALLEST];
+
+    /* At this point, the fields freq and dad are set. We can now
+     * generate the bit lengths.
+     */
+    gen_bitlen((tree_desc *)desc);
+
+    /* The field len is now set, we can generate the bit codes */
+    gen_codes ((ct_data *)tree, max_code);
+}
+
+/* ===========================================================================
+ * Scan a literal or distance tree to determine the frequencies of the codes
+ * in the bit length tree. Updates opt_len to take into account the repeat
+ * counts. (The contribution of the bit length codes will be added later
+ * during the construction of bl_tree.)
+ */
+local void scan_tree (tree, max_code)
+    ct_data *tree; /* the tree to be scanned */
+    int max_code;       /* and its largest code of non zero frequency */
+{
+    int n;                     /* iterates over all tree elements */
+    int prevlen = -1;          /* last emitted length */
+    int curlen;                /* length of current code */
+    int nextlen = tree[0].Len; /* length of next code */
+    int count = 0;             /* repeat count of the current code */
+    int max_count = 7;         /* max repeat count */
+    int min_count = 4;         /* min repeat count */
+
+    if (nextlen == 0) max_count = 138, min_count = 3;
+    tree[max_code+1].Len = (ush)0xffff; /* guard */
+
+    for (n = 0; n <= max_code; n++) {
+        curlen = nextlen; nextlen = tree[n+1].Len;
+        if (++count < max_count && curlen == nextlen) {
+            continue;
+        } else if (count < min_count) {
+            bl_tree[curlen].Freq += count;
+        } else if (curlen != 0) {
+            if (curlen != prevlen) bl_tree[curlen].Freq++;
+            bl_tree[REP_3_6].Freq++;
+        } else if (count <= 10) {
+            bl_tree[REPZ_3_10].Freq++;
+        } else {
+            bl_tree[REPZ_11_138].Freq++;
+        }
+        count = 0; prevlen = curlen;
+        if (nextlen == 0) {
+            max_count = 138, min_count = 3;
+        } else if (curlen == nextlen) {
+            max_count = 6, min_count = 3;
+        } else {
+            max_count = 7, min_count = 4;
+        }
+    }
+}
+
+/* ===========================================================================
+ * Send a literal or distance tree in compressed form, using the codes in
+ * bl_tree.
+ */
+local void send_tree (tree, max_code)
+    ct_data *tree; /* the tree to be scanned */
+    int max_code;       /* and its largest code of non zero frequency */
+{
+    int n;                     /* iterates over all tree elements */
+    int prevlen = -1;          /* last emitted length */
+    int curlen;                /* length of current code */
+    int nextlen = tree[0].Len; /* length of next code */
+    int count = 0;             /* repeat count of the current code */
+    int max_count = 7;         /* max repeat count */
+    int min_count = 4;         /* min repeat count */
+
+    /* tree[max_code+1].Len = -1; */  /* guard already set */
+    if (nextlen == 0) max_count = 138, min_count = 3;
+
+    for (n = 0; n <= max_code; n++) {
+        curlen = nextlen; nextlen = tree[n+1].Len;
+        if (++count < max_count && curlen == nextlen) {
+            continue;
+        } else if (count < min_count) {
+            do { send_code(curlen, bl_tree); } while (--count != 0);
+
+        } else if (curlen != 0) {
+            if (curlen != prevlen) {
+                send_code(curlen, bl_tree); count--;
+            }
+            Assert(count >= 3 && count <= 6, " 3_6?");
+            send_code(REP_3_6, bl_tree); send_bits(count-3, 2);
+
+        } else if (count <= 10) {
+            send_code(REPZ_3_10, bl_tree); send_bits(count-3, 3);
+
+        } else {
+            send_code(REPZ_11_138, bl_tree); send_bits(count-11, 7);
+        }
+        count = 0; prevlen = curlen;
+        if (nextlen == 0) {
+            max_count = 138, min_count = 3;
+        } else if (curlen == nextlen) {
+            max_count = 6, min_count = 3;
+        } else {
+            max_count = 7, min_count = 4;
+        }
+    }
+}
+
+/* ===========================================================================
+ * Construct the Huffman tree for the bit lengths and return the index in
+ * bl_order of the last bit length code to send.
+ */
+local int build_bl_tree()
+{
+    int max_blindex;  /* index of last bit length code of non zero freq */
+
+    /* Determine the bit length frequencies for literal and distance trees */
+    scan_tree((ct_data *)dyn_ltree, l_desc.max_code);
+    scan_tree((ct_data *)dyn_dtree, d_desc.max_code);
+
+    /* Build the bit length tree: */
+    build_tree((tree_desc *)(&bl_desc));
+    /* opt_len now includes the length of the tree representations, except
+     * the lengths of the bit lengths codes and the 5+5+4 bits for the counts.
+     */
+
+    /* Determine the number of bit length codes to send. The pkzip format
+     * requires that at least 4 bit length codes be sent. (appnote.txt says
+     * 3 but the actual value used is 4.)
+     */
+    for (max_blindex = BL_CODES-1; max_blindex >= 3; max_blindex--) {
+        if (bl_tree[bl_order[max_blindex]].Len != 0) break;
+    }
+    /* Update opt_len to include the bit length tree and counts */
+    opt_len += 3*(max_blindex+1) + 5+5+4;
+    Tracev((stderr, "\ndyn trees: dyn %ld, stat %ld", opt_len, static_len));
+
+    return max_blindex;
+}
+
+/* ===========================================================================
+ * Send the header for a block using dynamic Huffman trees: the counts, the
+ * lengths of the bit length codes, the literal tree and the distance tree.
+ * IN assertion: lcodes >= 257, dcodes >= 1, blcodes >= 4.
+ */
+local void send_all_trees(lcodes, dcodes, blcodes)
+    int lcodes, dcodes, blcodes; /* number of codes for each tree */
+{
+    int rank;                    /* index in bl_order */
+
+    Assert (lcodes >= 257 && dcodes >= 1 && blcodes >= 4, "not enough codes");
+    Assert (lcodes <= L_CODES && dcodes <= D_CODES && blcodes <= BL_CODES,
+            "too many codes");
+    Tracev((stderr, "\nbl counts: "));
+    send_bits(lcodes-257, 5); /* not +255 as stated in appnote.txt */
+    send_bits(dcodes-1,   5);
+    send_bits(blcodes-4,  4); /* not -3 as stated in appnote.txt */
+    for (rank = 0; rank < blcodes; rank++) {
+        Tracev((stderr, "\nbl code %2d ", bl_order[rank]));
+        send_bits(bl_tree[bl_order[rank]].Len, 3);
+    }
+    Tracev((stderr, "\nbl tree: sent %ld", bits_sent));
+
+    send_tree((ct_data *)dyn_ltree, lcodes-1); /* send the literal tree */
+    Tracev((stderr, "\nlit tree: sent %ld", bits_sent));
+
+    send_tree((ct_data *)dyn_dtree, dcodes-1); /* send the distance tree */
+    Tracev((stderr, "\ndist tree: sent %ld", bits_sent));
+}
+
+/* ===========================================================================
+ * Determine the best encoding for the current block: dynamic trees, static
+ * trees or store, and output the encoded block to the zip file. This function
+ * returns the total compressed length for the file so far.
+ */
+ulg flush_block(buf, stored_len, eof)
+    char *buf;        /* input block, or NULL if too old */
+    ulg stored_len;   /* length of input block */
+    int eof;          /* true if this is the last block for a file */
+{
+    ulg opt_lenb, static_lenb; /* opt_len and static_len in bytes */
+    int max_blindex;  /* index of last bit length code of non zero freq */
+
+    flag_buf[last_flags] = flags; /* Save the flags for the last 8 items */
+
+     /* Check if the file is ascii or binary */
+    if (*file_type == (ush)UNKNOWN) set_file_type();
+
+    /* Construct the literal and distance trees */
+    build_tree((tree_desc *)(&l_desc));
+    Tracev((stderr, "\nlit data: dyn %ld, stat %ld", opt_len, static_len));
+
+    build_tree((tree_desc *)(&d_desc));
+    Tracev((stderr, "\ndist data: dyn %ld, stat %ld", opt_len, static_len));
+    /* At this point, opt_len and static_len are the total bit lengths of
+     * the compressed block data, excluding the tree representations.
+     */
+
+    /* Build the bit length tree for the above two trees, and get the index
+     * in bl_order of the last bit length code to send.
+     */
+    max_blindex = build_bl_tree();
+
+    /* Determine the best encoding. Compute first the block length in bytes */
+    opt_lenb = (opt_len+3+7)>>3;
+    static_lenb = (static_len+3+7)>>3;
+    input_len += stored_len; /* for debugging only */
+
+    Trace((stderr, "\nopt %lu(%lu) stat %lu(%lu) stored %lu lit %u dist %u ",
+            opt_lenb, opt_len, static_lenb, static_len, stored_len,
+            last_lit, last_dist));
+
+    if (static_lenb <= opt_lenb) opt_lenb = static_lenb;
+
+    /* If compression failed and this is the first and last block,
+     * and if the zip file can be seeked (to rewrite the local header),
+     * the whole file is transformed into a stored file:
+     */
+#ifdef FORCE_METHOD
+    if (level == 1 && eof && compressed_len == 0L) { /* force stored file */
+#else
+    if (stored_len <= opt_lenb && eof && compressed_len == 0L && seekable()) {
+#endif
+        /* Since LIT_BUFSIZE <= 2*WSIZE, the input data must be there: */
+        if (buf == (char*)0) error ("block vanished");
+
+        copy_block(buf, (unsigned)stored_len, 0); /* without header */
+        compressed_len = stored_len << 3;
+        *file_method = STORED;
+
+#ifdef FORCE_METHOD
+    } else if (level == 2 && buf != (char*)0) { /* force stored block */
+#else
+    } else if (stored_len+4 <= opt_lenb && buf != (char*)0) {
+                       /* 4: two words for the lengths */
+#endif
+        /* The test buf != NULL is only necessary if LIT_BUFSIZE > WSIZE.
+         * Otherwise we can't have processed more than WSIZE input bytes since
+         * the last block flush, because compression would have been
+         * successful. If LIT_BUFSIZE <= WSIZE, it is never too late to
+         * transform a block into a stored block.
+         */
+        send_bits((STORED_BLOCK<<1)+eof, 3);  /* send block type */
+        compressed_len = (compressed_len + 3 + 7) & ~7L;
+        compressed_len += (stored_len + 4) << 3;
+
+        copy_block(buf, (unsigned)stored_len, 1); /* with header */
+
+#ifdef FORCE_METHOD
+    } else if (level == 3) { /* force static trees */
+#else
+    } else if (static_lenb == opt_lenb) {
+#endif
+        send_bits((STATIC_TREES<<1)+eof, 3);
+        compress_block((ct_data *)static_ltree, (ct_data *)static_dtree);
+        compressed_len += 3 + static_len;
+    } else {
+        send_bits((DYN_TREES<<1)+eof, 3);
+        send_all_trees(l_desc.max_code+1, d_desc.max_code+1, max_blindex+1);
+        compress_block((ct_data *)dyn_ltree, (ct_data *)dyn_dtree);
+        compressed_len += 3 + opt_len;
+    }
+    Assert (compressed_len == bits_sent, "bad compressed size");
+    init_block();
+
+    if (eof) {
+        Assert (input_len == isize, "bad input size");
+        bi_windup();
+        compressed_len += 7;  /* align on byte boundary */
+    }
+    Tracev((stderr,"\ncomprlen %lu(%lu) ", compressed_len>>3,
+           compressed_len-7*eof));
+
+    return compressed_len >> 3;
+}
+
+/* ===========================================================================
+ * Save the match info and tally the frequency counts. Return true if
+ * the current block must be flushed.
+ */
+int ct_tally (dist, lc)
+    int dist;  /* distance of matched string */
+    int lc;    /* match length-MIN_MATCH or unmatched char (if dist==0) */
+{
+    l_buf[last_lit++] = (uch)lc;
+    if (dist == 0) {
+        /* lc is the unmatched char */
+        dyn_ltree[lc].Freq++;
+    } else {
+        /* Here, lc is the match length - MIN_MATCH */
+        dist--;             /* dist = match distance - 1 */
+        Assert((ush)dist < (ush)MAX_DIST &&
+               (ush)lc <= (ush)(MAX_MATCH-MIN_MATCH) &&
+               (ush)d_code(dist) < (ush)D_CODES,  "ct_tally: bad match");
+
+        dyn_ltree[length_code[lc]+LITERALS+1].Freq++;
+        dyn_dtree[d_code(dist)].Freq++;
+
+        d_buf[last_dist++] = (ush)dist;
+        flags |= flag_bit;
+    }
+    flag_bit <<= 1;
+
+    /* Output the flags if they fill a byte: */
+    if ((last_lit & 7) == 0) {
+        flag_buf[last_flags++] = flags;
+        flags = 0, flag_bit = 1;
+    }
+    /* Try to guess if it is profitable to stop the current block here */
+    if (level > 2 && (last_lit & 0xfff) == 0) {
+        /* Compute an upper bound for the compressed length */
+        ulg out_length = (ulg)last_lit*8L;
+        ulg in_length = (ulg)strstart-block_start;
+        int dcode;
+        for (dcode = 0; dcode < D_CODES; dcode++) {
+            out_length += (ulg)dyn_dtree[dcode].Freq*(5L+extra_dbits[dcode]);
+        }
+        out_length >>= 3;
+        Trace((stderr,"\nlast_lit %u, last_dist %u, in %ld, out ~%ld(%ld%%) ",
+               last_lit, last_dist, in_length, out_length,
+               100L - out_length*100L/in_length));
+        if (last_dist < last_lit/2 && out_length < in_length/2) return 1;
+    }
+    return (last_lit == LIT_BUFSIZE-1 || last_dist == DIST_BUFSIZE);
+    /* We avoid equality with LIT_BUFSIZE because of wraparound at 64K
+     * on 16 bit machines and because stored blocks are restricted to
+     * 64K-1 bytes.
+     */
+}
+
+/* ===========================================================================
+ * Send the block data compressed using the given Huffman trees
+ */
+local void compress_block(ltree, dtree)
+    ct_data *ltree; /* literal tree */
+    ct_data *dtree; /* distance tree */
+{
+    unsigned dist;      /* distance of matched string */
+    int lc;             /* match length or unmatched char (if dist == 0) */
+    unsigned lx = 0;    /* running index in l_buf */
+    unsigned dx = 0;    /* running index in d_buf */
+    unsigned fx = 0;    /* running index in flag_buf */
+    uch flag = 0;       /* current flags */
+    unsigned code;      /* the code to send */
+    int extra;          /* number of extra bits to send */
+
+    if (last_lit != 0) do {
+        if ((lx & 7) == 0) flag = flag_buf[fx++];
+        lc = l_buf[lx++];
+        if ((flag & 1) == 0) {
+            send_code(lc, ltree); /* send a literal byte */
+            Tracecv(isgraph(lc), (stderr," '%c' ", lc));
+        } else {
+            /* Here, lc is the match length - MIN_MATCH */
+            code = length_code[lc];
+            send_code(code+LITERALS+1, ltree); /* send the length code */
+            extra = extra_lbits[code];
+            if (extra != 0) {
+                lc -= base_length[code];
+                send_bits(lc, extra);        /* send the extra length bits */
+            }
+            dist = d_buf[dx++];
+            /* Here, dist is the match distance - 1 */
+            code = d_code(dist);
+            Assert (code < D_CODES, "bad d_code");
+
+            send_code(code, dtree);       /* send the distance code */
+            extra = extra_dbits[code];
+            if (extra != 0) {
+                dist -= base_dist[code];
+                send_bits(dist, extra);   /* send the extra distance bits */
+            }
+        } /* literal or match pair ? */
+        flag >>= 1;
+    } while (lx < last_lit);
+
+    send_code(END_BLOCK, ltree);
+}
+
+/* ===========================================================================
+ * Set the file type to ASCII or BINARY, using a crude approximation:
+ * binary if more than 20% of the bytes are <= 6 or >= 128, ascii otherwise.
+ * IN assertion: the fields freq of dyn_ltree are set and the total of all
+ * frequencies does not exceed 64K (to fit in an int on 16 bit machines).
+ */
+local void set_file_type()
+{
+    int n = 0;
+    unsigned ascii_freq = 0;
+    unsigned bin_freq = 0;
+    while (n < 7)        bin_freq += dyn_ltree[n++].Freq;
+    while (n < 128)    ascii_freq += dyn_ltree[n++].Freq;
+    while (n < LITERALS) bin_freq += dyn_ltree[n++].Freq;
+    *file_type = bin_freq > (ascii_freq >> 2) ? BINARY : ASCII;
+    if (*file_type == BINARY && translate_eol) {
+        warn("-l used on binary file", "");
+    }
+}
diff --git a/usr/gzip/unzip.c b/usr/gzip/unzip.c
new file mode 100644
index 0000000..c8e14a3
--- /dev/null
+++ b/usr/gzip/unzip.c
@@ -0,0 +1,77 @@
+/* unzip.c -- decompress files in gzip or pkzip format.
+ * Copyright (C) 1992-1993 Jean-loup Gailly
+ * This is free software; you can redistribute it and/or modify it under the
+ * terms of the GNU General Public License, see the file COPYING.
+ *
+ * The code in this file is derived from the file funzip.c written
+ * and put in the public domain by Mark Adler.
+ */
+
+/*
+   This version can extract files in gzip format.
+   Only the first entry is extracted, and it has to be
+   either deflated or stored.
+ */
+
+#ifdef RCSID
+static char rcsid[] = "$Id: unzip.c,v 1.1 2002/08/18 00:59:21 hpa Exp $";
+#endif
+
+#include "tailor.h"
+#include "gzip.h"
+
+/* ===========================================================================
+ * Unzip in to out.  This routine works on gzip files only.
+ *
+ * IN assertions: the buffer inbuf contains already the beginning of
+ *   the compressed data, from offsets inptr to insize-1 included.
+ *   The magic header has already been checked. The output buffer is cleared.
+ */
+int unzip(in, out)
+    int in, out;   /* input and output file descriptors */
+{
+    ulg orig_crc = 0;       /* original crc */
+    ulg orig_len = 0;       /* original uncompressed length */
+    int n;
+    uch buf[8];        /* extended local header */
+
+    ifd = in;
+    ofd = out;
+
+    updcrc(NULL, 0);           /* initialize crc */
+
+    /* Decompress */
+    if (method == DEFLATED)  {
+
+	int res = inflate();
+
+	if (res == 3) {
+	    error("out of memory");
+	} else if (res != 0) {
+	    error("invalid compressed data--format violated");
+	}
+
+    } else {
+	error("internal error, invalid method");
+    }
+
+    /* Get the crc and original length */
+    /* crc32  (see algorithm.doc)
+     * uncompressed input size modulo 2^32
+     */
+    for (n = 0; n < 8; n++) {
+	buf[n] = (uch)get_byte(); /* may cause an error if EOF */
+    }
+    orig_crc = LG(buf);
+    orig_len = LG(buf+4);
+
+    /* Validate decompression */
+    if (orig_crc != updcrc(outbuf, 0)) {
+	error("invalid compressed data--crc error");
+    }
+    if (orig_len != (ulg)bytes_out) {
+	error("invalid compressed data--length error");
+    }
+
+    return OK;
+}
diff --git a/usr/gzip/util.c b/usr/gzip/util.c
new file mode 100644
index 0000000..22ff6e5
--- /dev/null
+++ b/usr/gzip/util.c
@@ -0,0 +1,372 @@
+/* util.c -- utility functions for gzip support
+ * Copyright (C) 1992-1993 Jean-loup Gailly
+ * This is free software; you can redistribute it and/or modify it under the
+ * terms of the GNU General Public License, see the file COPYING.
+ */
+
+#ifdef RCSID
+static char rcsid[] = "$Id: util.c,v 1.1 2002/08/18 00:59:21 hpa Exp $";
+#endif
+
+#include <ctype.h>
+#include <errno.h>
+#include <sys/types.h>
+
+#include "tailor.h"
+
+#include <unistd.h>
+#include <fcntl.h>
+#include <stdlib.h>
+
+#include "gzip.h"
+
+extern ulg crc_32_tab[];   /* crc table, defined below */
+
+/* ===========================================================================
+ * Copy input to output unchanged: zcat == cat with --force.
+ * IN assertion: insize bytes have already been read in inbuf.
+ */
+int copy(in, out)
+    int in, out;   /* input and output file descriptors */
+{
+    errno = 0;
+    while (insize != 0 && (int)insize != EOF) {
+	write_buf(out, (char*)inbuf, insize);
+	bytes_out += insize;
+	insize = read(in, (char*)inbuf, INBUFSIZ);
+    }
+    if ((int)insize == EOF && errno != 0) {
+	read_error();
+    }
+    bytes_in = bytes_out;
+    return OK;
+}
+
+/* ===========================================================================
+ * Run a set of bytes through the crc shift register.  If s is a NULL
+ * pointer, then initialize the crc shift register contents instead.
+ * Return the current crc in either case.
+ */
+ulg updcrc(s, n)
+    uch *s;                 /* pointer to bytes to pump through */
+    unsigned n;             /* number of bytes in s[] */
+{
+    register ulg c;         /* temporary variable */
+
+    static ulg crc = (ulg)0xffffffffL; /* shift register contents */
+
+    if (s == NULL) {
+	c = 0xffffffffL;
+    } else {
+	c = crc;
+        if (n) do {
+            c = crc_32_tab[((int)c ^ (*s++)) & 0xff] ^ (c >> 8);
+        } while (--n);
+    }
+    crc = c;
+    return c ^ 0xffffffffL;       /* (instead of ~c for 64-bit machines) */
+}
+
+/* ===========================================================================
+ * Clear input and output buffers
+ */
+void clear_bufs()
+{
+    outcnt = 0;
+    insize = inptr = 0;
+    bytes_in = bytes_out = 0L;
+}
+
+/* ===========================================================================
+ * Fill the input buffer. This is called only when the buffer is empty.
+ */
+int fill_inbuf(eof_ok)
+    int eof_ok;          /* set if EOF acceptable as a result */
+{
+    int len;
+
+    /* Read as much as possible */
+    insize = 0;
+    errno = 0;
+    do {
+	len = read(ifd, (char*)inbuf+insize, INBUFSIZ-insize);
+        if (len == 0 || len == EOF) break;
+	insize += len;
+    } while (insize < INBUFSIZ);
+
+    if (insize == 0) {
+	if (eof_ok) return EOF;
+	read_error();
+    }
+    bytes_in += (ulg)insize;
+    inptr = 1;
+    return inbuf[0];
+}
+
+/* ===========================================================================
+ * Write the output buffer outbuf[0..outcnt-1] and update bytes_out.
+ * (used for the compressed data only)
+ */
+void flush_outbuf()
+{
+    if (outcnt == 0) return;
+
+    write_buf(ofd, (char *)outbuf, outcnt);
+    bytes_out += (ulg)outcnt;
+    outcnt = 0;
+}
+
+/* ===========================================================================
+ * Write the output window window[0..outcnt-1] and update crc and bytes_out.
+ * (Used for the decompressed data only.)
+ */
+void flush_window()
+{
+    if (outcnt == 0) return;
+    updcrc(window, outcnt);
+
+    if (!test) {
+	write_buf(ofd, (char *)window, outcnt);
+    }
+    bytes_out += (ulg)outcnt;
+    outcnt = 0;
+}
+
+/* ===========================================================================
+ * Does the same as write(), but also handles partial pipe writes and checks
+ * for error return.
+ */
+void write_buf(fd, buf, cnt)
+    int       fd;
+    voidp     buf;
+    unsigned  cnt;
+{
+    unsigned  n;
+
+    while ((n = write(fd, buf, cnt)) != cnt) {
+	if (n == (unsigned)(-1)) {
+	    write_error();
+	}
+	cnt -= n;
+	buf = (voidp)((char*)buf+n);
+    }
+}
+
+/* ========================================================================
+ * Put string s in lower case, return s.
+ */
+char *strlwr(s)
+    char *s;
+{
+    char *t;
+    for (t = s; *t; t++) *t = tolow(*t);
+    return s;
+}
+
+/* ========================================================================
+ * Return the base name of a file (remove any directory prefix and
+ * any version suffix). For systems with file names that are not
+ * case sensitive, force the base name to lower case.
+ */
+char *basename(fname)
+    char *fname;
+{
+    char *p;
+
+    if ((p = strrchr(fname, PATH_SEP))  != NULL) fname = p+1;
+    if (casemap('A') == 'a') strlwr(fname);
+    return fname;
+}
+
+/* ========================================================================
+ * Add an environment variable (if any) before argv, and update argc.
+ * Return the expanded environment variable to be freed later, or NULL
+ * if no options were added to argv.
+ */
+#define SEPARATOR	" \t"	/* separators in env variable */
+
+char *add_envopt(argcp, argvp, env)
+    int *argcp;          /* pointer to argc */
+    char ***argvp;       /* pointer to argv */
+    char *env;           /* name of environment variable */
+{
+    char *p;             /* running pointer through env variable */
+    char **oargv;        /* runs through old argv array */
+    char **nargv;        /* runs through new argv array */
+    int	 oargc = *argcp; /* old argc */
+    int  nargc = 0;      /* number of arguments in env variable */
+
+    env = (char*)getenv(env);
+    if (env == NULL) return NULL;
+
+    p = (char*)xmalloc(strlen(env)+1);
+    env = strcpy(p, env);                    /* keep env variable intact */
+
+    for (p = env; *p; nargc++ ) {            /* move through env */
+	p += strspn(p, SEPARATOR);	     /* skip leading separators */
+	if (*p == '\0') break;
+
+	p += strcspn(p, SEPARATOR);	     /* find end of word */
+	if (*p) *p++ = '\0';		     /* mark it */
+    }
+    if (nargc == 0) {
+	free(env);
+	return NULL;
+    }
+    *argcp += nargc;
+    /* Allocate the new argv array, with an extra element just in case
+     * the original arg list did not end with a NULL.
+     */
+    nargv = (char**)calloc(*argcp+1, sizeof(char *));
+    if (nargv == NULL) error("out of memory");
+    oargv  = *argvp;
+    *argvp = nargv;
+
+    /* Copy the program name first */
+    if (oargc-- < 0) error("argc<=0");
+    *(nargv++) = *(oargv++);
+
+    /* Then copy the environment args */
+    for (p = env; nargc > 0; nargc--) {
+	p += strspn(p, SEPARATOR);	     /* skip separators */
+	*(nargv++) = p;			     /* store start */
+	while (*p++) ;			     /* skip over word */
+    }
+
+    /* Finally copy the old args and add a NULL (usual convention) */
+    while (oargc--) *(nargv++) = *(oargv++);
+    *nargv = NULL;
+    return env;
+}
+
+/* ========================================================================
+ * Error handlers.
+ */
+void error(m)
+    char *m;
+{
+    fprintf(stderr, "\n%s: %s: %s\n", progname, ifname, m);
+    abort_gzip();
+}
+
+void warn(a, b)
+    char *a, *b;            /* message strings juxtaposed in output */
+{
+    WARN((stderr, "%s: %s: warning: %s%s\n", progname, ifname, a, b));
+}
+
+void read_error()
+{
+    fprintf(stderr, "\n%s: ", progname);
+    if (errno != 0) {
+	perror(ifname);
+    } else {
+	fprintf(stderr, "%s: unexpected end of file\n", ifname);
+    }
+    abort_gzip();
+}
+
+void write_error()
+{
+    fprintf(stderr, "\n%s: ", progname);
+    perror(ofname);
+    abort_gzip();
+}
+
+/* ========================================================================
+ * Display compression ratio on the given stream on 6 characters.
+ */
+void display_ratio(num, den, file)
+    long num;
+    long den;
+    FILE *file;
+{
+    long ratio;  /* 1000 times the compression ratio */
+    char sign;
+
+    if (den == 0) {
+	ratio = 0; /* no compression */
+    } else if (den < 2147483L) { /* (2**31 -1)/1000 */
+	ratio = 1000L*num/den;
+    } else {
+	ratio = num/(den/1000L);
+    }
+    if (ratio < 0) {
+	sign = '-';
+	ratio = -ratio;
+    } else {
+	sign = ' ';
+    }
+    fprintf(file, "%c%2ld.%1ld%%", sign, ratio / 10L, ratio % 10L);
+}
+
+
+/* ========================================================================
+ * Semi-safe malloc -- never returns NULL.
+ */
+voidp xmalloc (size)
+    unsigned size;
+{
+    voidp cp = (voidp)malloc (size);
+
+    if (cp == NULL) error("out of memory");
+    return cp;
+}
+
+/* ========================================================================
+ * Table of CRC-32's of all single-byte values (made by makecrc.c)
+ */
+ulg crc_32_tab[] = {
+  0x00000000L, 0x77073096L, 0xee0e612cL, 0x990951baL, 0x076dc419L,
+  0x706af48fL, 0xe963a535L, 0x9e6495a3L, 0x0edb8832L, 0x79dcb8a4L,
+  0xe0d5e91eL, 0x97d2d988L, 0x09b64c2bL, 0x7eb17cbdL, 0xe7b82d07L,
+  0x90bf1d91L, 0x1db71064L, 0x6ab020f2L, 0xf3b97148L, 0x84be41deL,
+  0x1adad47dL, 0x6ddde4ebL, 0xf4d4b551L, 0x83d385c7L, 0x136c9856L,
+  0x646ba8c0L, 0xfd62f97aL, 0x8a65c9ecL, 0x14015c4fL, 0x63066cd9L,
+  0xfa0f3d63L, 0x8d080df5L, 0x3b6e20c8L, 0x4c69105eL, 0xd56041e4L,
+  0xa2677172L, 0x3c03e4d1L, 0x4b04d447L, 0xd20d85fdL, 0xa50ab56bL,
+  0x35b5a8faL, 0x42b2986cL, 0xdbbbc9d6L, 0xacbcf940L, 0x32d86ce3L,
+  0x45df5c75L, 0xdcd60dcfL, 0xabd13d59L, 0x26d930acL, 0x51de003aL,
+  0xc8d75180L, 0xbfd06116L, 0x21b4f4b5L, 0x56b3c423L, 0xcfba9599L,
+  0xb8bda50fL, 0x2802b89eL, 0x5f058808L, 0xc60cd9b2L, 0xb10be924L,
+  0x2f6f7c87L, 0x58684c11L, 0xc1611dabL, 0xb6662d3dL, 0x76dc4190L,
+  0x01db7106L, 0x98d220bcL, 0xefd5102aL, 0x71b18589L, 0x06b6b51fL,
+  0x9fbfe4a5L, 0xe8b8d433L, 0x7807c9a2L, 0x0f00f934L, 0x9609a88eL,
+  0xe10e9818L, 0x7f6a0dbbL, 0x086d3d2dL, 0x91646c97L, 0xe6635c01L,
+  0x6b6b51f4L, 0x1c6c6162L, 0x856530d8L, 0xf262004eL, 0x6c0695edL,
+  0x1b01a57bL, 0x8208f4c1L, 0xf50fc457L, 0x65b0d9c6L, 0x12b7e950L,
+  0x8bbeb8eaL, 0xfcb9887cL, 0x62dd1ddfL, 0x15da2d49L, 0x8cd37cf3L,
+  0xfbd44c65L, 0x4db26158L, 0x3ab551ceL, 0xa3bc0074L, 0xd4bb30e2L,
+  0x4adfa541L, 0x3dd895d7L, 0xa4d1c46dL, 0xd3d6f4fbL, 0x4369e96aL,
+  0x346ed9fcL, 0xad678846L, 0xda60b8d0L, 0x44042d73L, 0x33031de5L,
+  0xaa0a4c5fL, 0xdd0d7cc9L, 0x5005713cL, 0x270241aaL, 0xbe0b1010L,
+  0xc90c2086L, 0x5768b525L, 0x206f85b3L, 0xb966d409L, 0xce61e49fL,
+  0x5edef90eL, 0x29d9c998L, 0xb0d09822L, 0xc7d7a8b4L, 0x59b33d17L,
+  0x2eb40d81L, 0xb7bd5c3bL, 0xc0ba6cadL, 0xedb88320L, 0x9abfb3b6L,
+  0x03b6e20cL, 0x74b1d29aL, 0xead54739L, 0x9dd277afL, 0x04db2615L,
+  0x73dc1683L, 0xe3630b12L, 0x94643b84L, 0x0d6d6a3eL, 0x7a6a5aa8L,
+  0xe40ecf0bL, 0x9309ff9dL, 0x0a00ae27L, 0x7d079eb1L, 0xf00f9344L,
+  0x8708a3d2L, 0x1e01f268L, 0x6906c2feL, 0xf762575dL, 0x806567cbL,
+  0x196c3671L, 0x6e6b06e7L, 0xfed41b76L, 0x89d32be0L, 0x10da7a5aL,
+  0x67dd4accL, 0xf9b9df6fL, 0x8ebeeff9L, 0x17b7be43L, 0x60b08ed5L,
+  0xd6d6a3e8L, 0xa1d1937eL, 0x38d8c2c4L, 0x4fdff252L, 0xd1bb67f1L,
+  0xa6bc5767L, 0x3fb506ddL, 0x48b2364bL, 0xd80d2bdaL, 0xaf0a1b4cL,
+  0x36034af6L, 0x41047a60L, 0xdf60efc3L, 0xa867df55L, 0x316e8eefL,
+  0x4669be79L, 0xcb61b38cL, 0xbc66831aL, 0x256fd2a0L, 0x5268e236L,
+  0xcc0c7795L, 0xbb0b4703L, 0x220216b9L, 0x5505262fL, 0xc5ba3bbeL,
+  0xb2bd0b28L, 0x2bb45a92L, 0x5cb36a04L, 0xc2d7ffa7L, 0xb5d0cf31L,
+  0x2cd99e8bL, 0x5bdeae1dL, 0x9b64c2b0L, 0xec63f226L, 0x756aa39cL,
+  0x026d930aL, 0x9c0906a9L, 0xeb0e363fL, 0x72076785L, 0x05005713L,
+  0x95bf4a82L, 0xe2b87a14L, 0x7bb12baeL, 0x0cb61b38L, 0x92d28e9bL,
+  0xe5d5be0dL, 0x7cdcefb7L, 0x0bdbdf21L, 0x86d3d2d4L, 0xf1d4e242L,
+  0x68ddb3f8L, 0x1fda836eL, 0x81be16cdL, 0xf6b9265bL, 0x6fb077e1L,
+  0x18b74777L, 0x88085ae6L, 0xff0f6a70L, 0x66063bcaL, 0x11010b5cL,
+  0x8f659effL, 0xf862ae69L, 0x616bffd3L, 0x166ccf45L, 0xa00ae278L,
+  0xd70dd2eeL, 0x4e048354L, 0x3903b3c2L, 0xa7672661L, 0xd06016f7L,
+  0x4969474dL, 0x3e6e77dbL, 0xaed16a4aL, 0xd9d65adcL, 0x40df0b66L,
+  0x37d83bf0L, 0xa9bcae53L, 0xdebb9ec5L, 0x47b2cf7fL, 0x30b5ffe9L,
+  0xbdbdf21cL, 0xcabac28aL, 0x53b39330L, 0x24b4a3a6L, 0xbad03605L,
+  0xcdd70693L, 0x54de5729L, 0x23d967bfL, 0xb3667a2eL, 0xc4614ab8L,
+  0x5d681b02L, 0x2a6f2b94L, 0xb40bbe37L, 0xc30c8ea1L, 0x5a05df1bL,
+  0x2d02ef8dL
+};
diff --git a/usr/gzip/zip.c b/usr/gzip/zip.c
new file mode 100644
index 0000000..d0394c2
--- /dev/null
+++ b/usr/gzip/zip.c
@@ -0,0 +1,110 @@
+/* zip.c -- compress files to the gzip or pkzip format
+ * Copyright (C) 1992-1993 Jean-loup Gailly
+ * This is free software; you can redistribute it and/or modify it under the
+ * terms of the GNU General Public License, see the file COPYING.
+ */
+
+#ifdef RCSID
+static char rcsid[] = "$Id: zip.c,v 1.1 2002/08/18 00:59:21 hpa Exp $";
+#endif
+
+#include <ctype.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <fcntl.h>
+
+#include "tailor.h"
+#include "gzip.h"
+
+local ulg crc;       /* crc on uncompressed file data */
+
+/* ===========================================================================
+ * Deflate in to out.
+ * IN assertions: the input and output buffers are cleared.
+ *   The variables time_stamp and save_orig_name are initialized.
+ */
+int zip(in, out)
+    int in, out;            /* input and output file descriptors */
+{
+    uch  flags = 0;         /* general purpose bit flags */
+    ush  attr = 0;          /* ascii/binary flag */
+    ush  deflate_flags = 0; /* pkzip -es, -en or -ex equivalent */
+
+    ifd = in;
+    ofd = out;
+    outcnt = 0;
+
+    /* Write the header to the gzip file. See algorithm.doc for the format */
+
+    method = DEFLATED;
+    put_byte(GZIP_MAGIC[0]); /* magic header */
+    put_byte(GZIP_MAGIC[1]);
+    put_byte(DEFLATED);      /* compression method */
+
+    if (save_orig_name) {
+	flags |= ORIG_NAME;
+    }
+    put_byte(flags);         /* general flags */
+    put_long(time_stamp);
+
+    /* Write deflated file to zip file */
+    crc = updcrc(0, 0);
+
+    bi_init(out);
+    ct_init(&attr, &method);
+    lm_init(level, &deflate_flags);
+
+    put_byte((uch)deflate_flags); /* extra flags */
+    put_byte(OS_CODE);            /* OS identifier */
+
+    if (save_orig_name) {
+	char *p = basename(ifname); /* Don't save the directory part. */
+	do {
+	    put_char(*p);
+	} while (*p++);
+    }
+    header_bytes = (long)outcnt;
+
+    (void)deflate();
+
+#if !defined(NO_SIZE_CHECK) && !defined(RECORD_IO)
+  /* Check input size (but not in VMS -- variable record lengths mess it up)
+   * and not on MSDOS -- diet in TSR mode reports an incorrect file size)
+   */
+    if (ifile_size != -1L && isize != (ulg)ifile_size) {
+	Trace((stderr, " actual=%ld, read=%ld ", ifile_size, isize));
+	fprintf(stderr, "%s: %s: file size changed while zipping\n",
+		progname, ifname);
+    }
+#endif
+
+    /* Write the crc and uncompressed size */
+    put_long(crc);
+    put_long(isize);
+    header_bytes += 2*sizeof(long);
+
+    flush_outbuf();
+    return OK;
+}
+
+
+/* ===========================================================================
+ * Read a new buffer from the current input file, perform end-of-line
+ * translation, and update the crc and input file size.
+ * IN assertion: size >= 2 (for end-of-line translation)
+ */
+int file_read(buf, size)
+    char *buf;
+    unsigned size;
+{
+    unsigned len;
+
+    Assert(insize == 0, "inbuf not empty");
+
+    len = read(ifd, buf, size);
+    if (len == (unsigned)(-1) || len == 0) return (int)len;
+
+    crc = updcrc((uch*)buf, len);
+    isize += (ulg)len;
+    return (int)len;
+}
diff --git a/usr/include/Kbuild b/usr/include/Kbuild
new file mode 100644
index 0000000..3f20026
--- /dev/null
+++ b/usr/include/Kbuild
@@ -0,0 +1,11 @@
+always := asm
+
+$(obj)/asm:
+	@echo '  SYMLINK $@ -> include/asm-$(KLIBCASMARCH)'
+	$(Q)if [ '$(KLIBCKERNELSRC).' -ef '$(obj)/../..' ]; then \
+		ln -fsn ../../include/asm-$(KLIBCASMARCH) $@; \
+	 else \
+		ln -fsn $(KLIBCKERNELSRC)./include/asm-$(KLIBCASMARCH) $@; \
+	 fi
+
+clean-files := asm
diff --git a/usr/include/alloca.h b/usr/include/alloca.h
new file mode 100644
index 0000000..91ef4c0
--- /dev/null
+++ b/usr/include/alloca.h
@@ -0,0 +1,12 @@
+/*
+ * alloca.h
+ *
+ * Just call the builtin alloca() function
+ */
+
+#ifndef _ALLOCA_H
+#define _ALLOCA_H
+
+#define alloca(size) __builtin_alloca(size)
+
+#endif				/* _ALLOCA_H */
diff --git a/usr/include/arch/alpha/klibc/archconfig.h b/usr/include/arch/alpha/klibc/archconfig.h
new file mode 100644
index 0000000..272fee0
--- /dev/null
+++ b/usr/include/arch/alpha/klibc/archconfig.h
@@ -0,0 +1,15 @@
+/*
+ * include/arch/alpha/klibc/archconfig.h
+ *
+ * See include/klibc/sysconfig.h for the options that can be set in
+ * this file.
+ *
+ */
+
+#ifndef _KLIBC_ARCHCONFIG_H
+#define _KLIBC_ARCHCONFIG_H
+
+#define _KLIBC_USE_RT_SIG 1
+#define _KLIBC_STATFS_F_TYPE_64 0
+
+#endif				/* _KLIBC_ARCHCONFIG_H */
diff --git a/usr/include/arch/alpha/klibc/archsetjmp.h b/usr/include/arch/alpha/klibc/archsetjmp.h
new file mode 100644
index 0000000..47638b3
--- /dev/null
+++ b/usr/include/arch/alpha/klibc/archsetjmp.h
@@ -0,0 +1,33 @@
+/*
+ * arch/alpha/include/klibc/archsetjmp.h
+ */
+
+#ifndef _KLIBC_ARCHSETJMP_H
+#define _KLIBC_ARCHSETJMP_H
+
+struct __jmp_buf {
+	unsigned long __s0;
+	unsigned long __s1;
+	unsigned long __s2;
+	unsigned long __s3;
+	unsigned long __s4;
+	unsigned long __s5;
+	unsigned long __fp;
+	unsigned long __ra;
+	unsigned long __gp;
+	unsigned long __sp;
+
+	unsigned long __f2;
+	unsigned long __f3;
+	unsigned long __f4;
+	unsigned long __f5;
+	unsigned long __f6;
+	unsigned long __f7;
+	unsigned long __f8;
+	unsigned long __f9;
+};
+
+/* Must be an array so it will decay to a pointer when a function is called */
+typedef struct __jmp_buf jmp_buf[1];
+
+#endif				/* _KLIBC_ARCHSETJMP_H */
diff --git a/usr/include/arch/alpha/klibc/archsignal.h b/usr/include/arch/alpha/klibc/archsignal.h
new file mode 100644
index 0000000..2193a35
--- /dev/null
+++ b/usr/include/arch/alpha/klibc/archsignal.h
@@ -0,0 +1,14 @@
+/*
+ * arch/alpha/include/klibc/archsignal.h
+ *
+ * Architecture-specific signal definitions
+ *
+ */
+
+#ifndef _KLIBC_ARCHSIGNAL_H
+#define _KLIBC_ARCHSIGNAL_H
+
+#include <asm/signal.h>
+/* No special stuff for this architecture */
+
+#endif
diff --git a/usr/include/arch/alpha/klibc/archstat.h b/usr/include/arch/alpha/klibc/archstat.h
new file mode 100644
index 0000000..66e29be
--- /dev/null
+++ b/usr/include/arch/alpha/klibc/archstat.h
@@ -0,0 +1,28 @@
+#ifndef _KLIBC_ARCHSTAT_H
+#define _KLIBC_ARCHSTAT_H
+
+#include <klibc/stathelp.h>
+
+#define _STATBUF_ST_NSEC
+
+struct stat {
+	__stdev64	(st_dev);
+	unsigned long	st_ino;
+	__stdev64	(st_rdev);
+	long		st_size;
+	unsigned long	st_blocks;
+
+	unsigned int	st_mode;
+	unsigned int	st_uid;
+	unsigned int	st_gid;
+	unsigned int	st_blksize;
+	unsigned int	st_nlink;
+	unsigned int	__pad0;
+
+	struct timespec st_atim;
+	struct timespec st_mtim;
+	struct timespec st_ctim;
+  	long		__unused[3];
+};
+
+#endif
diff --git a/usr/include/arch/alpha/machine/asm.h b/usr/include/arch/alpha/machine/asm.h
new file mode 100644
index 0000000..c2ae4ed
--- /dev/null
+++ b/usr/include/arch/alpha/machine/asm.h
@@ -0,0 +1,44 @@
+/*
+ * machine/asm.h
+ */
+
+#ifndef _MACHINE_ASM_H
+#define _MACHINE_ASM_H
+
+/* Standard aliases for Alpha register names */
+
+#define v0	$0
+#define t0	$1
+#define t1	$2
+#define t2	$3
+#define t3	$4
+#define t4	$5
+#define t5	$6
+#define t6	$7
+#define t7	$8
+#define s0	$9
+#define s1	$10
+#define s2	$11
+#define s3	$12
+#define s4	$13
+#define s5	$14
+#define fp	$15
+#define a0	$16
+#define a1	$17
+#define a2	$18
+#define a3	$19
+#define a4	$20
+#define a5	$21
+#define t8	$22
+#define t9	$23
+#define t10	$24
+#define t11	$25
+#define ra	$26
+#define t12	$27		/* t12 and pv are both used for $27 */
+#define pv	$27		/* t12 and pv are both used for $27 */
+#define at	$28
+#define gp	$29
+#define sp	$30
+#define zero	$31
+
+#endif				/* _MACHINE_ASM_H */
diff --git a/usr/include/arch/arm/klibc/archconfig.h b/usr/include/arch/arm/klibc/archconfig.h
new file mode 100644
index 0000000..e34bdb7
--- /dev/null
+++ b/usr/include/arch/arm/klibc/archconfig.h
@@ -0,0 +1,14 @@
+/*
+ * include/arch/arm/klibc/archconfig.h
+ *
+ * See include/klibc/sysconfig.h for the options that can be set in
+ * this file.
+ *
+ */
+
+#ifndef _KLIBC_ARCHCONFIG_H
+#define _KLIBC_ARCHCONFIG_H
+
+/* All defaults */
+
+#endif				/* _KLIBC_ARCHCONFIG_H */
diff --git a/usr/include/arch/arm/klibc/archsetjmp.h b/usr/include/arch/arm/klibc/archsetjmp.h
new file mode 100644
index 0000000..88db8a1
--- /dev/null
+++ b/usr/include/arch/arm/klibc/archsetjmp.h
@@ -0,0 +1,14 @@
+/*
+ * arch/i386/include/klibc/archsetjmp.h
+ */
+
+#ifndef _KLIBC_ARCHSETJMP_H
+#define _KLIBC_ARCHSETJMP_H
+
+struct __jmp_buf {
+	unsigned int regs[10];
+};
+
+typedef struct __jmp_buf jmp_buf[1];
+
+#endif				/* _SETJMP_H */
diff --git a/usr/include/arch/arm/klibc/archsignal.h b/usr/include/arch/arm/klibc/archsignal.h
new file mode 100644
index 0000000..a589527
--- /dev/null
+++ b/usr/include/arch/arm/klibc/archsignal.h
@@ -0,0 +1,14 @@
+/*
+ * arch/arm/include/klibc/archsignal.h
+ *
+ * Architecture-specific signal definitions
+ *
+ */
+
+#ifndef _KLIBC_ARCHSIGNAL_H
+#define _KLIBC_ARCHSIGNAL_H
+
+#include <asm/signal.h>
+/* No special stuff for this architecture */
+
+#endif
diff --git a/usr/include/arch/arm/klibc/archstat.h b/usr/include/arch/arm/klibc/archstat.h
new file mode 100644
index 0000000..95bbc9e
--- /dev/null
+++ b/usr/include/arch/arm/klibc/archstat.h
@@ -0,0 +1,40 @@
+#ifndef _KLIBC_ARCHSTAT_H
+#define _KLIBC_ARCHSTAT_H
+
+#include <klibc/stathelp.h>
+
+#define _STATBUF_ST_NSEC
+
+/* This matches struct stat64 in glibc2.1, hence the absolutely
+ * insane amounts of padding around dev_t's.
+ * Note: The kernel zero's the padded region because glibc might read them
+ * in the hope that the kernel has stretched to using larger sizes.
+ */
+
+struct stat {
+	__stdev64	(st_dev);
+	unsigned char   __pad0[4];
+
+	unsigned long	__st_ino;
+	unsigned int	st_mode;
+	unsigned int	st_nlink;
+
+	unsigned long	st_uid;
+	unsigned long	st_gid;
+
+	__stdev64	(st_rdev);
+	unsigned char   __pad3[4];
+
+	long long	st_size;
+	unsigned long	st_blksize;
+
+	unsigned long long  st_blocks;	/* Number 512-byte blocks allocated. */
+
+	struct timespec st_atim;
+	struct timespec st_mtim;
+	struct timespec st_ctim;
+
+	unsigned long long	st_ino;
+};
+
+#endif
diff --git a/usr/include/arch/arm/klibc/asmmacros.h b/usr/include/arch/arm/klibc/asmmacros.h
new file mode 100644
index 0000000..8a21c94
--- /dev/null
+++ b/usr/include/arch/arm/klibc/asmmacros.h
@@ -0,0 +1,30 @@
+/*
+ * usr/include/arch/arm/klibc/asmmacros.h
+ *
+ * Assembly macros used by ARM system call stubs
+ */
+
+#ifndef _KLIBC_ASMMACROS_H
+#define _KLIBC_ASMMACROS_H
+
+/* An immediate in ARM can be any 8-bit value rotated by an even number of bits */
+
+#define ARM_VALID_IMM(x)	\
+	((((x) & ~0x000000ff) == 0) || \
+	 (((x) & ~0x000003fc) == 0) || \
+	 (((x) & ~0x00000ff0) == 0) || \
+	 (((x) & ~0x00003fc0) == 0) || \
+	 (((x) & ~0x0000ff00) == 0) || \
+	 (((x) & ~0x0003fc00) == 0) || \
+	 (((x) & ~0x000ff000) == 0) || \
+	 (((x) & ~0x003fc000) == 0) || \
+	 (((x) & ~0x00ff0000) == 0) || \
+	 (((x) & ~0x03fc0000) == 0) || \
+	 (((x) & ~0x0ff00000) == 0) || \
+	 (((x) & ~0x3fc00000) == 0) || \
+	 (((x) & ~0xff000000) == 0) || \
+	 (((x) & ~0xfc000003) == 0) || \
+	 (((x) & ~0xf000000f) == 0) || \
+	 (((x) & ~0xc000003f) == 0))
+
+#endif /* _KLIBC_ASMMACROS_H */
diff --git a/usr/include/arch/cris/klibc/archconfig.h b/usr/include/arch/cris/klibc/archconfig.h
new file mode 100644
index 0000000..0206078
--- /dev/null
+++ b/usr/include/arch/cris/klibc/archconfig.h
@@ -0,0 +1,15 @@
+/*
+ * include/arch/cris/klibc/archconfig.h
+ *
+ * See include/klibc/sysconfig.h for the options that can be set in
+ * this file.
+ *
+ */
+
+#ifndef _KLIBC_ARCHCONFIG_H
+#define _KLIBC_ARCHCONFIG_H
+
+/* cris uses 13 as the page shift factor for sys_mmap2 */
+#define _KLIBC_MMAP2_SHIFT	13
+
+#endif				/* _KLIBC_ARCHCONFIG_H */
diff --git a/usr/include/arch/cris/klibc/archsetjmp.h b/usr/include/arch/cris/klibc/archsetjmp.h
new file mode 100644
index 0000000..d345ccb
--- /dev/null
+++ b/usr/include/arch/cris/klibc/archsetjmp.h
@@ -0,0 +1,24 @@
+/*
+ * arch/cris/include/klibc/archsetjmp.h
+ */
+
+#ifndef _KLIBC_ARCHSETJMP_H
+#define _KLIBC_ARCHSETJMP_H
+
+struct __jmp_buf {
+	unsigned long __r0;
+	unsigned long __r1;
+	unsigned long __r2;
+	unsigned long __r3;
+	unsigned long __r4;
+	unsigned long __r5;
+	unsigned long __r6;
+	unsigned long __r7;
+	unsigned long __r8;
+	unsigned long __sp;
+	unsigned long __srp;
+};
+
+typedef struct __jmp_buf jmp_buf[1];
+
+#endif				/* _KLIBC_ARCHSETJMP_H */
diff --git a/usr/include/arch/cris/klibc/archsignal.h b/usr/include/arch/cris/klibc/archsignal.h
new file mode 100644
index 0000000..7fa7454
--- /dev/null
+++ b/usr/include/arch/cris/klibc/archsignal.h
@@ -0,0 +1,14 @@
+/*
+ * arch/cris/include/klibc/archsignal.h
+ *
+ * Architecture-specific signal definitions
+ *
+ */
+
+#ifndef _KLIBC_ARCHSIGNAL_H
+#define _KLIBC_ARCHSIGNAL_H
+
+#include <asm/signal.h>
+/* No special stuff for this architecture */
+
+#endif
diff --git a/usr/include/arch/cris/klibc/archstat.h b/usr/include/arch/cris/klibc/archstat.h
new file mode 100644
index 0000000..09d3ade
--- /dev/null
+++ b/usr/include/arch/cris/klibc/archstat.h
@@ -0,0 +1,39 @@
+#ifndef _KLIBC_ARCHSTAT_H
+#define _KLIBC_ARCHSTAT_H
+
+#include <klibc/stathelp.h>
+
+#define _STATBUF_ST_NSEC
+
+/* This matches struct stat64 in glibc2.1, hence the absolutely
+ * insane amounts of padding around dev_t's.
+ */
+struct stat {
+	__stdev64	(st_dev);
+	unsigned char	__pad0[4];
+
+	unsigned long	__st_ino;
+
+	unsigned int	st_mode;
+	unsigned int	st_nlink;
+
+	unsigned long	st_uid;
+	unsigned long	st_gid;
+
+	__stdev64	(st_rdev);
+	unsigned char	__pad3[4];
+
+	long long	st_size;
+	unsigned long	st_blksize;
+
+	unsigned long	st_blocks;	/* Number 512-byte blocks allocated. */
+	unsigned long	__pad4;		/* future possible st_blocks high bits */
+
+	struct timespec st_atim;
+	struct timespec st_mtim;
+	struct timespec st_ctim;
+
+	unsigned long long	st_ino;
+};
+
+#endif
diff --git a/usr/include/arch/i386/klibc/archconfig.h b/usr/include/arch/i386/klibc/archconfig.h
new file mode 100644
index 0000000..37a4c8a
--- /dev/null
+++ b/usr/include/arch/i386/klibc/archconfig.h
@@ -0,0 +1,15 @@
+/*
+ * include/arch/i386/klibc/archconfig.h
+ *
+ * See include/klibc/sysconfig.h for the options that can be set in
+ * this file.
+ *
+ */
+
+#ifndef _KLIBC_ARCHCONFIG_H
+#define _KLIBC_ARCHCONFIG_H
+
+/* On i386, only half the signals are accessible using the legacy calls. */
+#define _KLIBC_USE_RT_SIG 1
+
+#endif				/* _KLIBC_ARCHCONFIG_H */
diff --git a/usr/include/arch/i386/klibc/archsetjmp.h b/usr/include/arch/i386/klibc/archsetjmp.h
new file mode 100644
index 0000000..ea1ba3d
--- /dev/null
+++ b/usr/include/arch/i386/klibc/archsetjmp.h
@@ -0,0 +1,19 @@
+/*
+ * arch/i386/include/klibc/archsetjmp.h
+ */
+
+#ifndef _KLIBC_ARCHSETJMP_H
+#define _KLIBC_ARCHSETJMP_H
+
+struct __jmp_buf {
+	unsigned int __ebx;
+	unsigned int __esp;
+	unsigned int __ebp;
+	unsigned int __esi;
+	unsigned int __edi;
+	unsigned int __eip;
+};
+
+typedef struct __jmp_buf jmp_buf[1];
+
+#endif				/* _SETJMP_H */
diff --git a/usr/include/arch/i386/klibc/archsignal.h b/usr/include/arch/i386/klibc/archsignal.h
new file mode 100644
index 0000000..6c942db
--- /dev/null
+++ b/usr/include/arch/i386/klibc/archsignal.h
@@ -0,0 +1,114 @@
+/*
+ * arch/i386/include/klibc/archsignal.h
+ *
+ * Architecture-specific signal definitions
+ *
+ */
+
+#ifndef _KLIBC_ARCHSIGNAL_H
+#define _KLIBC_ARCHSIGNAL_H
+
+/* The in-kernel headers for i386 still have libc5
+   crap in them.  Reconsider using <asm/signal.h>
+   when/if it gets cleaned up; for now, duplicate
+   the definitions here. */
+
+#define _NSIG           64
+#define _NSIG_BPW       32
+#define _NSIG_WORDS     (_NSIG / _NSIG_BPW)
+
+typedef struct {
+	unsigned long sig[_NSIG_WORDS];
+} sigset_t;
+
+#define SIGHUP           1
+#define SIGINT           2
+#define SIGQUIT          3
+#define SIGILL           4
+#define SIGTRAP          5
+#define SIGABRT          6
+#define SIGIOT           6
+#define SIGBUS           7
+#define SIGFPE           8
+#define SIGKILL          9
+#define SIGUSR1         10
+#define SIGSEGV         11
+#define SIGUSR2         12
+#define SIGPIPE         13
+#define SIGALRM         14
+#define SIGTERM         15
+#define SIGSTKFLT       16
+#define SIGCHLD         17
+#define SIGCONT         18
+#define SIGSTOP         19
+#define SIGTSTP         20
+#define SIGTTIN         21
+#define SIGTTOU         22
+#define SIGURG          23
+#define SIGXCPU         24
+#define SIGXFSZ         25
+#define SIGVTALRM       26
+#define SIGPROF         27
+#define SIGWINCH        28
+#define SIGIO           29
+#define SIGPOLL         SIGIO
+#define SIGPWR          30
+#define SIGSYS          31
+#define SIGUNUSED       31
+
+#define SIGRTMIN        32
+#define SIGRTMAX        (_NSIG-1)
+
+/*
+ * SA_FLAGS values:
+ *
+ * SA_ONSTACK indicates that a registered stack_t will be used.
+ * SA_INTERRUPT is a no-op, but left due to historical reasons. Use the
+ * SA_RESTART flag to get restarting signals (which were the default long ago)
+ * SA_NOCLDSTOP flag to turn off SIGCHLD when children stop.
+ * SA_RESETHAND clears the handler when the signal is delivered.
+ * SA_NOCLDWAIT flag on SIGCHLD to inhibit zombies.
+ * SA_NODEFER prevents the current signal from being masked in the handler.
+ *
+ * SA_ONESHOT and SA_NOMASK are the historical Linux names for the Single
+ * Unix names RESETHAND and NODEFER respectively.
+ */
+#define SA_NOCLDSTOP	0x00000001u
+#define SA_NOCLDWAIT	0x00000002u
+#define SA_SIGINFO	0x00000004u
+#define SA_ONSTACK	0x08000000u
+#define SA_RESTART	0x10000000u
+#define SA_NODEFER	0x40000000u
+#define SA_RESETHAND	0x80000000u
+
+#define SA_NOMASK	SA_NODEFER
+#define SA_ONESHOT	SA_RESETHAND
+#define SA_INTERRUPT	0x20000000	/* dummy -- ignored */
+
+#define SA_RESTORER	0x04000000
+
+/*
+ * sigaltstack controls
+ */
+#define SS_ONSTACK	1
+#define SS_DISABLE	2
+
+#define MINSIGSTKSZ	2048
+#define SIGSTKSZ	8192
+
+#include <asm-generic/signal.h>
+
+/* This uses gcc anonymous union support... */
+struct siginfo;
+
+struct sigaction {
+	union {
+		__sighandler_t sa_handler;
+		void (*sa_sigaction)(int, struct siginfo *, void *);
+	};
+	unsigned long	sa_flags;
+	__sigrestore_t 	sa_restorer;
+	sigset_t	sa_mask;
+};
+
+#endif
diff --git a/usr/include/arch/i386/klibc/archstat.h b/usr/include/arch/i386/klibc/archstat.h
new file mode 100644
index 0000000..c00f955
--- /dev/null
+++ b/usr/include/arch/i386/klibc/archstat.h
@@ -0,0 +1,38 @@
+#ifndef _KLIBC_ARCHSTAT_H
+#define _KLIBC_ARCHSTAT_H
+
+#include <klibc/stathelp.h>
+
+#define _STATBUF_ST_NSEC
+
+/* This matches struct stat64 in glibc2.1, hence the absolutely
+ * insane amounts of padding around dev_t's.
+ */
+struct stat {
+	__stdev64	(st_dev);
+	unsigned char	__pad0[4];
+
+	unsigned long	__st_ino;
+
+	unsigned int	st_mode;
+	unsigned int	st_nlink;
+
+	unsigned long	st_uid;
+	unsigned long	st_gid;
+
+	__stdev64	(st_rdev);
+	unsigned char	__pad3[4];
+
+	long long	st_size;
+	unsigned long	st_blksize;
+
+	unsigned long long st_blocks;	/* Number 512-byte blocks allocated. */
+
+	struct timespec st_atim;
+	struct timespec st_mtim;
+	struct timespec st_ctim;
+
+	unsigned long long	st_ino;
+};
+
+#endif
diff --git a/usr/include/arch/i386/klibc/diverr.h b/usr/include/arch/i386/klibc/diverr.h
new file mode 100644
index 0000000..fa238ac
--- /dev/null
+++ b/usr/include/arch/i386/klibc/diverr.h
@@ -0,0 +1,15 @@
+/*
+ * arch/i386/include/klibc/diverr.h
+ */
+
+#ifndef _KLIBC_DIVERR_H
+#define _KLIBC_DIVERR_H
+
+#include <signal.h>
+
+static __inline__ void __divide_error(void)
+{
+	asm volatile ("int $0");
+}
+
+#endif				/* _KLIBC_DIVERR_H */
diff --git a/usr/include/arch/i386/sys/io.h b/usr/include/arch/i386/sys/io.h
new file mode 100644
index 0000000..cf31b97
--- /dev/null
+++ b/usr/include/arch/i386/sys/io.h
@@ -0,0 +1,127 @@
+/* ----------------------------------------------------------------------- *
+ *
+ *   Copyright 2004 H. Peter Anvin - All Rights Reserved
+ *
+ *   Permission is hereby granted, free of charge, to any person
+ *   obtaining a copy of this software and associated documentation
+ *   files (the "Software"), to deal in the Software without
+ *   restriction, including without limitation the rights to use,
+ *   copy, modify, merge, publish, distribute, sublicense, and/or
+ *   sell copies of the Software, and to permit persons to whom
+ *   the Software is furnished to do so, subject to the following
+ *   conditions:
+ *
+ *   The above copyright notice and this permission notice shall
+ *   be included in all copies or substantial portions of the Software.
+ *
+ *   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ *   EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ *   OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ *   NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ *   HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ *   WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ *   FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ *   OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * ----------------------------------------------------------------------- */
+
+/*
+ * sys/io.h for the i386 architecture
+ *
+ * Basic I/O macros
+ */
+
+#ifndef _SYS_IO_H
+#define _SYS_IO_H 1
+
+/* I/O-related system calls */
+
+int iopl(int);
+int ioperm(unsigned long, unsigned long, int);
+
+/* Basic I/O macros */
+
+static __inline__ void outb(unsigned char __v, unsigned short __p)
+{
+	asm volatile ("outb %0,%1" : : "a" (__v), "dN" (__p));
+}
+
+static __inline__ void outw(unsigned short __v, unsigned short __p)
+{
+	asm volatile ("outw %0,%1" : : "a" (__v), "dN" (__p));
+}
+
+static __inline__ void outl(unsigned int __v, unsigned short __p)
+{
+	asm volatile ("outl %0,%1" : : "a" (__v), "dN" (__p));
+}
+
+static __inline__ unsigned char inb(unsigned short __p)
+{
+	unsigned char __v;
+	asm volatile ("inb %1,%0" : "=a" (__v) : "dN" (__p));
+	return __v;
+}
+
+static __inline__ unsigned short inw(unsigned short __p)
+{
+	unsigned short __v;
+	asm volatile ("inw %1,%0" : "=a" (__v) : "dN" (__p));
+	return __v;
+}
+
+static __inline__ unsigned int inl(unsigned short __p)
+{
+	unsigned int __v;
+	asm volatile ("inl %1,%0" : "=a" (__v) : "dN" (__p));
+	return __v;
+}
+
+/* String I/O macros */
+
+static __inline__ void
+outsb(unsigned short __p, const void *__d, unsigned long __n)
+{
+	asm volatile ("cld; rep; outsb"
+		      : "+S" (__d), "+c" (__n)
+		      : "d" (__p));
+}
+
+static __inline__ void
+outsw(unsigned short __p, const void *__d, unsigned long __n)
+{
+	asm volatile ("cld; rep; outsw"
+		      : "+S" (__d), "+c" (__n)
+		      : "d" (__p));
+}
+
+static __inline__ void
+outsl(unsigned short __p, const void *__d, unsigned long __n)
+{
+	asm volatile ("cld; rep; outsl"
+		      : "+S" (__d), "+c"(__n)
+		      : "d" (__p));
+}
+
+static __inline__ void insb(unsigned short __p, void *__d, unsigned long __n)
+{
+	asm volatile ("cld; rep; insb"
+		      : "+D" (__d), "+c" (__n)
+		      : "d" (__p));
+}
+
+static __inline__ void insw(unsigned short __p, void *__d, unsigned long __n)
+{
+	asm volatile ("cld; rep; insw"
+		      : "+D" (__d), "+c" (__n)
+		      : "d" (__p));
+}
+
+static __inline__ void insl(unsigned short __p, void *__d, unsigned long __n)
+{
+	asm volatile ("cld; rep; insl"
+		      : "+D" (__d), "+c" (__n)
+		      : "d" (__p));
+}
+
+#endif				/* _SYS_IO_H */
diff --git a/usr/include/arch/i386/sys/vm86.h b/usr/include/arch/i386/sys/vm86.h
new file mode 100644
index 0000000..c4651cd
--- /dev/null
+++ b/usr/include/arch/i386/sys/vm86.h
@@ -0,0 +1,40 @@
+/* ----------------------------------------------------------------------- *
+ *
+ *   Copyright 2004 H. Peter Anvin - All Rights Reserved
+ *
+ *   Permission is hereby granted, free of charge, to any person
+ *   obtaining a copy of this software and associated documentation
+ *   files (the "Software"), to deal in the Software without
+ *   restriction, including without limitation the rights to use,
+ *   copy, modify, merge, publish, distribute, sublicense, and/or
+ *   sell copies of the Software, and to permit persons to whom
+ *   the Software is furnished to do so, subject to the following
+ *   conditions:
+ *
+ *   The above copyright notice and this permission notice shall
+ *   be included in all copies or substantial portions of the Software.
+ *
+ *   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ *   EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ *   OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ *   NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ *   HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ *   WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ *   FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ *   OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * ----------------------------------------------------------------------- */
+
+/*
+ * sys/vm86.h for i386
+ */
+
+#ifndef _SYS_VM86_H
+#define _SYS_VM86_H 1
+
+#include <asm/vm86.h>
+
+/* Actual system call */
+int vm86(struct vm86_struct *);
+
+#endif
diff --git a/usr/include/arch/ia64/klibc/archconfig.h b/usr/include/arch/ia64/klibc/archconfig.h
new file mode 100644
index 0000000..adbd1ee
--- /dev/null
+++ b/usr/include/arch/ia64/klibc/archconfig.h
@@ -0,0 +1,17 @@
+/*
+ * include/arch/ia64/klibc/archconfig.h
+ *
+ * See include/klibc/sysconfig.h for the options that can be set in
+ * this file.
+ *
+ */
+
+#ifndef _KLIBC_ARCHCONFIG_H
+#define _KLIBC_ARCHCONFIG_H
+
+/* IA64 doesn't have sys_fork, but it does have an MMU */
+#define _KLIBC_NO_MMU 0
+/* IA64 doesn't have sys_vfork, it has architecture-specific code */
+#define _KLIBC_REAL_VFORK 1
+
+#endif				/* _KLIBC_ARCHCONFIG_H */
diff --git a/usr/include/arch/ia64/klibc/archsetjmp.h b/usr/include/arch/ia64/klibc/archsetjmp.h
new file mode 100644
index 0000000..43564ee
--- /dev/null
+++ b/usr/include/arch/ia64/klibc/archsetjmp.h
@@ -0,0 +1,17 @@
+/*
+ * arch/ia64/include/klibc/archsetjmp.h
+ *
+ * Code borrowed from the FreeBSD kernel.
+ *
+ */
+
+#ifndef _KLIBC_ARCHSETJMP_H
+#define _KLIBC_ARCHSETJMP_H
+
+/* User code must not depend on the internal representation of jmp_buf. */
+#define _JBLEN 0x200
+
+/* guaranteed 128-bit alignment! */
+typedef char jmp_buf[_JBLEN] __attribute__ ((aligned(16)));
+
+#endif
diff --git a/usr/include/arch/ia64/klibc/archsignal.h b/usr/include/arch/ia64/klibc/archsignal.h
new file mode 100644
index 0000000..fbc961b
--- /dev/null
+++ b/usr/include/arch/ia64/klibc/archsignal.h
@@ -0,0 +1,32 @@
+/*
+ * arch/ia64/include/klibc/archsignal.h
+ *
+ * Architecture-specific signal definitions.
+ *
+ */
+
+#ifndef _KLIBC_ARCHSIGNAL_H
+#define _KLIBC_ARCHSIGNAL_H
+
+#include <asm/signal.h>
+#define _NSIG        64
+#define _NSIG_BPW    64
+#define _NSIG_WORDS (_NSIG / _NSIG_BPW)
+
+typedef struct {
+	unsigned long sig[_NSIG_WORDS];
+} sigset_t;
+
+struct sigaction {
+	union {
+		__sighandler_t _sa_handler;
+		void (*_sa_sigaction) (int, struct siginfo *, void *);
+	} _u;
+	sigset_t sa_mask;
+	int sa_flags;
+};
+
+#define sa_handler      _u._sa_handler
+#define sa_sigaction    _u._sa_sigaction
+
+#endif
diff --git a/usr/include/arch/ia64/klibc/archstat.h b/usr/include/arch/ia64/klibc/archstat.h
new file mode 100644
index 0000000..ff38e41
--- /dev/null
+++ b/usr/include/arch/ia64/klibc/archstat.h
@@ -0,0 +1,26 @@
+#ifndef _KLIBC_ARCHSTAT_H
+#define _KLIBC_ARCHSTAT_H
+
+#include <klibc/stathelp.h>
+
+#define _STATBUF_ST_NSEC
+
+struct stat {
+	__stdev64	(st_dev);
+	unsigned long	st_ino;
+	unsigned long	st_nlink;
+	unsigned int	st_mode;
+	unsigned int	st_uid;
+	unsigned int	st_gid;
+	unsigned int	__pad0;
+	__stdev64	(st_rdev);
+	unsigned long	st_size;
+	struct timespec st_atim;
+	struct timespec st_mtim;
+	struct timespec st_ctim;
+	unsigned long	st_blksize;
+	long		st_blocks;
+	unsigned long	__unused[3];
+};
+
+#endif
diff --git a/usr/include/arch/ia64/klibc/archsys.h b/usr/include/arch/ia64/klibc/archsys.h
new file mode 100644
index 0000000..6007821
--- /dev/null
+++ b/usr/include/arch/ia64/klibc/archsys.h
@@ -0,0 +1,217 @@
+/*
+ * arch/ia64/include/klibc/archsys.h
+ *
+ * Architecture-specific syscall definitions
+ */
+
+#ifndef _KLIBC_ARCHSYS_H
+#define _KLIBC_ARCHSYS_H
+
+#define __IA64_BREAK "break 0x100000;;\n\t"
+
+#define _syscall0(type,name)                                            \
+type                                                                    \
+name (void)                                                             \
+{                                                                       \
+       register long _r8 asm ("r8");					\
+       register long _r10 asm ("r10");                                  \
+       register long _r15 asm ("r15") = __NR_##name;                    \
+       long _retval;                                                    \
+       __asm __volatile (__IA64_BREAK                                   \
+                         : "=r" (_r8), "=r" (_r10), "=r" (_r15)         \
+                         : "2" (_r15) ASM_ARGS_0                        \
+                         : "memory" ASM_CLOBBERS_0);                    \
+       _retval = _r8;                                                   \
+       if (_r10 == -1) {                                                \
+               errno = (_retval);                                       \
+               _retval = -1;                                            \
+       }                                                                \
+       return (type)_retval;                                                  \
+}
+
+#define _syscall1(type,name,type1,arg1)                                 \
+type                                                                    \
+name (type1 arg1)                                                       \
+{                                                                       \
+       register long _r8 asm ("r8");					\
+       register long _r10 asm ("r10");                                  \
+       register long _r15 asm ("r15") = __NR_##name;                    \
+       long _retval;                                                    \
+       LOAD_ARGS_1(arg1);                                               \
+       __asm __volatile (__IA64_BREAK                                   \
+                         : "=r" (_r8), "=r" (_r10), "=r" (_r15),        \
+                           ASM_OUTARGS_1                                \
+                         : "2" (_r15) ASM_ARGS_1                        \
+                         : "memory" ASM_CLOBBERS_1);                    \
+       _retval = _r8;                                                   \
+       if (_r10 == -1) {                                                \
+               errno = (_retval);                                       \
+               _retval = -1;                                            \
+       }                                                                \
+       return (type)_retval;                                                  \
+}
+
+#define _syscall2(type,name,type1,arg1,type2,arg2)                      \
+type                                                                    \
+name (type1 arg1, type2 arg2)                                           \
+{                                                                       \
+       register long _r8 asm ("r8");					\
+       register long _r10 asm ("r10");                                  \
+       register long _r15 asm ("r15") = __NR_##name;                    \
+       long _retval;                                                    \
+       LOAD_ARGS_2(arg1, arg2);                                         \
+       __asm __volatile (__IA64_BREAK                                   \
+                         : "=r" (_r8), "=r" (_r10), "=r" (_r15),        \
+                           ASM_OUTARGS_2                                \
+                         : "2" (_r15) ASM_ARGS_2                        \
+                         : "memory" ASM_CLOBBERS_2);                    \
+       _retval = _r8;                                                   \
+       if (_r10 == -1) {                                                \
+               errno = (_retval);                                       \
+               _retval = -1;                                            \
+       }                                                                \
+       return (type)_retval;                                                  \
+}
+
+#define _syscall3(type,name,type1,arg1,type2,arg2,type3,arg3)           \
+type                                                                    \
+name (type1 arg1, type2 arg2, type3 arg3)                               \
+{                                                                       \
+       register long _r8 asm ("r8");					\
+       register long _r10 asm ("r10");                                  \
+       register long _r15 asm ("r15") = __NR_##name;                    \
+       long _retval;                                                    \
+       LOAD_ARGS_3(arg1, arg2, arg3);                                   \
+       __asm __volatile (__IA64_BREAK                                   \
+                         : "=r" (_r8), "=r" (_r10), "=r" (_r15),        \
+                           ASM_OUTARGS_3                                \
+                         : "2" (_r15) ASM_ARGS_3                        \
+                         : "memory" ASM_CLOBBERS_3);                    \
+       _retval = _r8;                                                   \
+       if (_r10 == -1) {                                                \
+               errno = (_retval);                                       \
+               _retval = -1;                                            \
+       }                                                                \
+       return (type)_retval;                                                  \
+}
+
+#define _syscall4(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4) \
+type                                                                    \
+name (type1 arg1, type2 arg2, type3 arg3, type4 arg4)                   \
+{                                                                       \
+       register long _r8 asm ("r8");					\
+       register long _r10 asm ("r10");                                  \
+       register long _r15 asm ("r15") = __NR_##name;                    \
+       long _retval;                                                    \
+       LOAD_ARGS_4(arg1, arg2, arg3, arg4);                             \
+       __asm __volatile (__IA64_BREAK                                   \
+                         : "=r" (_r8), "=r" (_r10), "=r" (_r15),        \
+                           ASM_OUTARGS_4                                \
+                         : "2" (_r15) ASM_ARGS_4                        \
+                         : "memory" ASM_CLOBBERS_4);                    \
+       _retval = _r8;                                                   \
+       if (_r10 == -1) {                                                \
+               errno = (_retval);                                       \
+               _retval = -1;                                            \
+       }                                                                \
+       return (type)_retval;                                                  \
+}
+
+#define _syscall5(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4,type5,arg5) \
+type                                                                    \
+name (type1 arg1, type2 arg2, type3 arg3, type4 arg4, type5 arg5)       \
+{                                                                       \
+       register long _r8 asm ("r8");					\
+       register long _r10 asm ("r10");                                  \
+       register long _r15 asm ("r15") = __NR_##name;                    \
+       long _retval;                                                    \
+       LOAD_ARGS_5(arg1, arg2, arg3, arg4, arg5);                       \
+       __asm __volatile (__IA64_BREAK                                   \
+                         : "=r" (_r8), "=r" (_r10), "=r" (_r15),        \
+                           ASM_OUTARGS_5                                \
+                         : "2" (_r15) ASM_ARGS_5                        \
+                         : "memory" ASM_CLOBBERS_5);                    \
+       _retval = _r8;                                                   \
+       if (_r10 == -1) {                                                \
+               errno = (_retval);                                       \
+               _retval = -1;                                            \
+       }                                                                \
+       return (type)_retval;                                                  \
+}
+
+#define _syscall6(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4,type5,arg5,type6,arg6) \
+type                                                                    \
+name (type1 arg1, type2 arg2, type3 arg3, type4 arg4, type5 arg5, type6 arg6)       \
+{                                                                       \
+       register long _r8 asm ("r8");					\
+       register long _r10 asm ("r10");                                  \
+       register long _r15 asm ("r15") = __NR_##name;                    \
+       long _retval;                                                    \
+       LOAD_ARGS_6(arg1, arg2, arg3, arg4, arg5, arg6);                 \
+       __asm __volatile (__IA64_BREAK                                   \
+                         : "=r" (_r8), "=r" (_r10), "=r" (_r15),        \
+                           ASM_OUTARGS_6                                \
+                         : "2" (_r15) ASM_ARGS_6                        \
+                         : "memory" ASM_CLOBBERS_6);                    \
+       _retval = _r8;                                                   \
+       if (_r10 == -1) {                                                \
+               errno = (_retval);                                       \
+               _retval = -1;                                            \
+       }                                                                \
+       return (type)_retval;                                                  \
+}
+
+#define LOAD_ARGS_0()   do { } while (0)
+#define LOAD_ARGS_1(out0)				\
+  register long _out0 asm ("out0") = (long) (out0);	\
+  LOAD_ARGS_0 ()
+#define LOAD_ARGS_2(out0, out1)				\
+  register long _out1 asm ("out1") = (long) (out1);	\
+  LOAD_ARGS_1 (out0)
+#define LOAD_ARGS_3(out0, out1, out2)			\
+  register long _out2 asm ("out2") = (long) (out2);	\
+  LOAD_ARGS_2 (out0, out1)
+#define LOAD_ARGS_4(out0, out1, out2, out3)		\
+  register long _out3 asm ("out3") = (long) (out3);	\
+  LOAD_ARGS_3 (out0, out1, out2)
+#define LOAD_ARGS_5(out0, out1, out2, out3, out4)	\
+  register long _out4 asm ("out4") = (long) (out4);	\
+  LOAD_ARGS_4 (out0, out1, out2, out3)
+#define LOAD_ARGS_6(out0, out1, out2, out3, out4, out5)	\
+  register long _out5 asm ("out5") = (long) (out5);	\
+  LOAD_ARGS_5 (out0, out1, out2, out3, out4)
+
+#define ASM_OUTARGS_1	"=r" (_out0)
+#define ASM_OUTARGS_2	ASM_OUTARGS_1, "=r" (_out1)
+#define ASM_OUTARGS_3	ASM_OUTARGS_2, "=r" (_out2)
+#define ASM_OUTARGS_4	ASM_OUTARGS_3, "=r" (_out3)
+#define ASM_OUTARGS_5	ASM_OUTARGS_4, "=r" (_out4)
+#define ASM_OUTARGS_6	ASM_OUTARGS_5, "=r" (_out5)
+
+#define ASM_ARGS_0
+#define ASM_ARGS_1	ASM_ARGS_0, "3" (_out0)
+#define ASM_ARGS_2	ASM_ARGS_1, "4" (_out1)
+#define ASM_ARGS_3	ASM_ARGS_2, "5" (_out2)
+#define ASM_ARGS_4	ASM_ARGS_3, "6" (_out3)
+#define ASM_ARGS_5	ASM_ARGS_4, "7" (_out4)
+#define ASM_ARGS_6	ASM_ARGS_5, "8" (_out5)
+
+#define ASM_CLOBBERS_0	ASM_CLOBBERS_1, "out0"
+#define ASM_CLOBBERS_1	ASM_CLOBBERS_2, "out1"
+#define ASM_CLOBBERS_2	ASM_CLOBBERS_3, "out2"
+#define ASM_CLOBBERS_3	ASM_CLOBBERS_4, "out3"
+#define ASM_CLOBBERS_4	ASM_CLOBBERS_5, "out4"
+#define ASM_CLOBBERS_5	ASM_CLOBBERS_6, "out5"
+#define ASM_CLOBBERS_6	, "out6", "out7",				\
+  /* Non-stacked integer registers, minus r8, r10, r15.  */		\
+  "r2", "r3", "r9", "r11", "r12", "r13", "r14", "r16", "r17", "r18",	\
+  "r19", "r20", "r21", "r22", "r23", "r24", "r25", "r26", "r27",	\
+  "r28", "r29", "r30", "r31",						\
+  /* Predicate registers.  */						\
+  "p6", "p7", "p8", "p9", "p10", "p11", "p12", "p13", "p14", "p15",	\
+  /* Non-rotating fp registers.  */					\
+  "f6", "f7", "f8", "f9", "f10", "f11", "f12", "f13", "f14", "f15",	\
+  /* Branch registers.  */						\
+  "b6", "b7"
+
+#endif				/* _KLIBC_ARCHSYS_H */
diff --git a/usr/include/arch/m32r/klibc/archconfig.h b/usr/include/arch/m32r/klibc/archconfig.h
new file mode 100644
index 0000000..9489877
--- /dev/null
+++ b/usr/include/arch/m32r/klibc/archconfig.h
@@ -0,0 +1,14 @@
+/*
+ * include/arch/m32r/klibc/archconfig.h
+ *
+ * See include/klibc/sysconfig.h for the options that can be set in
+ * this file.
+ *
+ */
+
+#ifndef _KLIBC_ARCHCONFIG_H
+#define _KLIBC_ARCHCONFIG_H
+
+/* All defaults */
+
+#endif				/* _KLIBC_ARCHCONFIG_H */
diff --git a/usr/include/arch/m32r/klibc/archsetjmp.h b/usr/include/arch/m32r/klibc/archsetjmp.h
new file mode 100644
index 0000000..d82df9c
--- /dev/null
+++ b/usr/include/arch/m32r/klibc/archsetjmp.h
@@ -0,0 +1,21 @@
+/*
+ * arch/m32r/include/klibc/archsetjmp.h
+ */
+
+#ifndef _KLIBC_ARCHSETJMP_H
+#define _KLIBC_ARCHSETJMP_H
+
+struct __jmp_buf {
+	unsigned long __r8;
+	unsigned long __r9;
+	unsigned long __r10;
+	unsigned long __r11;
+	unsigned long __r12;
+	unsigned long __r13;
+	unsigned long __r14;
+	unsigned long __r15;
+};
+
+typedef struct __jmp_buf jmp_buf[1];
+
+#endif				/* _KLIBC_ARCHSETJMP_H */
diff --git a/usr/include/arch/m32r/klibc/archsignal.h b/usr/include/arch/m32r/klibc/archsignal.h
new file mode 100644
index 0000000..b753026
--- /dev/null
+++ b/usr/include/arch/m32r/klibc/archsignal.h
@@ -0,0 +1,14 @@
+/*
+ * arch/m32r/include/klibc/archsignal.h
+ *
+ * Architecture-specific signal definitions
+ *
+ */
+
+#ifndef _KLIBC_ARCHSIGNAL_H
+#define _KLIBC_ARCHSIGNAL_H
+
+#include <asm/signal.h>
+/* No special stuff for this architecture */
+
+#endif
diff --git a/usr/include/arch/m32r/klibc/archstat.h b/usr/include/arch/m32r/klibc/archstat.h
new file mode 100644
index 0000000..09d3ade
--- /dev/null
+++ b/usr/include/arch/m32r/klibc/archstat.h
@@ -0,0 +1,39 @@
+#ifndef _KLIBC_ARCHSTAT_H
+#define _KLIBC_ARCHSTAT_H
+
+#include <klibc/stathelp.h>
+
+#define _STATBUF_ST_NSEC
+
+/* This matches struct stat64 in glibc2.1, hence the absolutely
+ * insane amounts of padding around dev_t's.
+ */
+struct stat {
+	__stdev64	(st_dev);
+	unsigned char	__pad0[4];
+
+	unsigned long	__st_ino;
+
+	unsigned int	st_mode;
+	unsigned int	st_nlink;
+
+	unsigned long	st_uid;
+	unsigned long	st_gid;
+
+	__stdev64	(st_rdev);
+	unsigned char	__pad3[4];
+
+	long long	st_size;
+	unsigned long	st_blksize;
+
+	unsigned long	st_blocks;	/* Number 512-byte blocks allocated. */
+	unsigned long	__pad4;		/* future possible st_blocks high bits */
+
+	struct timespec st_atim;
+	struct timespec st_mtim;
+	struct timespec st_ctim;
+
+	unsigned long long	st_ino;
+};
+
+#endif
diff --git a/usr/include/arch/m68k/klibc/archconfig.h b/usr/include/arch/m68k/klibc/archconfig.h
new file mode 100644
index 0000000..10ef62e
--- /dev/null
+++ b/usr/include/arch/m68k/klibc/archconfig.h
@@ -0,0 +1,15 @@
+/*
+ * include/arch/m68k/klibc/archconfig.h
+ *
+ * See include/klibc/sysconfig.h for the options that can be set in
+ * this file.
+ *
+ */
+
+#ifndef _KLIBC_ARCHCONFIG_H
+#define _KLIBC_ARCHCONFIG_H
+
+/* On m68k, sys_mmap2 uses the current page size as the shift factor */
+#define _KLIBC_MMAP2_SHIFT	__getpageshift()
+
+#endif				/* _KLIBC_ARCHCONFIG_H */
diff --git a/usr/include/arch/m68k/klibc/archsetjmp.h b/usr/include/arch/m68k/klibc/archsetjmp.h
new file mode 100644
index 0000000..e85c810
--- /dev/null
+++ b/usr/include/arch/m68k/klibc/archsetjmp.h
@@ -0,0 +1,26 @@
+/*
+ * usr/include/arch/m68k/klibc/archsetjmp.h
+ */
+
+#ifndef _KLIBC_ARCHSETJMP_H
+#define _KLIBC_ARCHSETJMP_H
+
+struct __jmp_buf {
+	unsigned int __d2;
+	unsigned int __d3;
+	unsigned int __d4;
+	unsigned int __d5;
+	unsigned int __d6;
+	unsigned int __d7;
+	unsigned int __a2;
+	unsigned int __a3;
+	unsigned int __a4;
+	unsigned int __a5;
+	unsigned int __fp;	/* a6 */
+	unsigned int __sp;	/* a7 */
+	unsigned int __retaddr;
+};
+
+typedef struct __jmp_buf jmp_buf[1];
+
+#endif				/* _KLBIC_ARCHSETJMP_H */
diff --git a/usr/include/arch/m68k/klibc/archsignal.h b/usr/include/arch/m68k/klibc/archsignal.h
new file mode 100644
index 0000000..bf7912a
--- /dev/null
+++ b/usr/include/arch/m68k/klibc/archsignal.h
@@ -0,0 +1,14 @@
+/*
+ * arch/m68k/include/klibc/archsignal.h
+ *
+ * Architecture-specific signal definitions
+ *
+ */
+
+#ifndef _KLIBC_ARCHSIGNAL_H
+#define _KLIBC_ARCHSIGNAL_H
+
+#include <asm/signal.h>
+/* No special stuff for this architecture */
+
+#endif
diff --git a/usr/include/arch/m68k/klibc/archstat.h b/usr/include/arch/m68k/klibc/archstat.h
new file mode 100644
index 0000000..dce25f9
--- /dev/null
+++ b/usr/include/arch/m68k/klibc/archstat.h
@@ -0,0 +1,38 @@
+#ifndef _KLIBC_ARCHSTAT_H
+#define _KLIBC_ARCHSTAT_H
+
+#include <klibc/stathelp.h>
+
+#define _STATBUF_ST_NSEC
+
+/* This matches struct stat64 in glibc2.1, hence the absolutely
+ * insane padding around dev_t's.
+ */
+struct stat {
+	__stdev64	(st_dev);
+	unsigned char	__pad1[2];
+
+	unsigned long	__st_ino;
+
+	unsigned int	st_mode;
+	unsigned int	st_nlink;
+
+	unsigned long	st_uid;
+	unsigned long	st_gid;
+
+	__stdev64	(st_rdev);
+	unsigned char	__pad3[2];
+
+	long long	st_size;
+	unsigned long	st_blksize;
+
+	unsigned long long	st_blocks;	/* Number 512-byte blocks allocated. */
+
+	struct timespec st_atim;
+	struct timespec st_mtim;
+	struct timespec st_ctim;
+
+	unsigned long long	st_ino;
+};
+
+#endif
diff --git a/usr/include/arch/mips/klibc/archconfig.h b/usr/include/arch/mips/klibc/archconfig.h
new file mode 100644
index 0000000..ff0afb5
--- /dev/null
+++ b/usr/include/arch/mips/klibc/archconfig.h
@@ -0,0 +1,21 @@
+/*
+ * include/arch/mips/klibc/archconfig.h
+ *
+ * See include/klibc/sysconfig.h for the options that can be set in
+ * this file.
+ *
+ */
+
+#ifndef _KLIBC_ARCHCONFIG_H
+#define _KLIBC_ARCHCONFIG_H
+
+/* MIPS has architecture-specific code for vfork() */
+#define _KLIBC_REAL_VFORK 1
+
+/* MIPS defines it's own statfs */
+#define _KLIBC_STATFS_F_TYPE_32B 1
+
+/* MIPS has nonstandard socket definitions */
+#define _KLIBC_HAS_ARCHSOCKET_H 1
+
+#endif				/* _KLIBC_ARCHCONFIG_H */
diff --git a/usr/include/arch/mips/klibc/archfcntl.h b/usr/include/arch/mips/klibc/archfcntl.h
new file mode 100644
index 0000000..1f61822
--- /dev/null
+++ b/usr/include/arch/mips/klibc/archfcntl.h
@@ -0,0 +1,86 @@
+/*
+ * arch/mips/include/klibc/archfcntl.h
+ *
+ * On MIPS, <asm/fcntl.h> isn't usable (compiling struct stat with
+ * the correct definitions doesn't "just work"), so we need to provide
+ * our own definitions.
+ */
+
+#ifndef _KLIBC_ARCHFCNTL_H
+#define _KLIBC_ARCHFCNTL_H
+
+#ifdef _ASM_FCNTL_H		/* We were too late! */
+# error "<asm/fcntl.h> included before <klibc/archfcntl.h>"
+#endif
+#define _ASM_FCNTL_H		/* Keep <asm/fcntl.h> from getting included */
+
+#define O_ACCMODE	0x0003
+#define O_RDONLY	0x0000
+#define O_WRONLY	0x0001
+#define O_RDWR		0x0002
+#define O_APPEND	0x0008
+#define O_SYNC		0x0010
+#define O_NONBLOCK	0x0080
+#define O_CREAT         0x0100
+#define O_TRUNC		0x0200
+#define O_EXCL		0x0400
+#define O_NOCTTY	0x0800
+#define FASYNC		0x1000
+#define O_LARGEFILE	0x2000
+#define O_DIRECT	0x8000
+#define O_DIRECTORY	0x10000
+#define O_NOFOLLOW	0x20000
+#define O_NOATIME	0x40000
+
+#define O_NDELAY	O_NONBLOCK
+
+#define F_DUPFD		0
+#define F_GETFD		1
+#define F_SETFD		2
+#define F_GETFL		3
+#define F_SETFL		4
+#define F_GETLK		14
+#define F_SETLK		6
+#define F_SETLKW	7
+
+#define F_SETOWN	24
+#define F_GETOWN	23
+#define F_SETSIG	10
+#define F_GETSIG	11
+
+#define F_GETLK64	33
+#define F_SETLK64	34
+#define F_SETLKW64	35
+
+#define FD_CLOEXEC	1
+
+#define F_RDLCK		0
+#define F_WRLCK		1
+#define F_UNLCK		2
+
+#define F_EXLCK		4
+#define F_SHLCK		8
+
+#define F_INPROGRESS	16
+
+#define LOCK_SH		1
+#define LOCK_EX		2
+#define LOCK_NB		4
+#define LOCK_UN		8
+
+#define LOCK_MAND	32
+#define LOCK_READ	64
+#define LOCK_WRITE	128
+#define LOCK_RW		192
+
+typedef struct flock {
+	short	l_type;
+	short	l_whence;
+	loff_t	l_start;
+	loff_t	l_len;
+	pid_t	l_pid;
+} flock_t;
+
+#define F_LINUX_SPECIFIC_BASE	1024
+
+#endif				/* _KLIBC_ARCHFCNTL_H */
diff --git a/usr/include/arch/mips/klibc/archsetjmp.h b/usr/include/arch/mips/klibc/archsetjmp.h
new file mode 100644
index 0000000..1fbe83e
--- /dev/null
+++ b/usr/include/arch/mips/klibc/archsetjmp.h
@@ -0,0 +1,39 @@
+/*
+ * arch/mips/include/klibc/archsetjmp.h
+ */
+
+#ifndef _KLIBC_ARCHSETJMP_H
+#define _KLIBC_ARCHSETJMP_H
+
+struct __jmp_buf {
+	unsigned long __s0;
+	unsigned long __s1;
+	unsigned long __s2;
+	unsigned long __s3;
+	unsigned long __s4;
+	unsigned long __s5;
+	unsigned long __s6;
+	unsigned long __s7;
+	unsigned long __gp;
+	unsigned long __sp;
+	unsigned long __s8;
+	unsigned long __ra;
+	unsigned long __f20;
+	unsigned long __f21;
+	unsigned long __f22;
+	unsigned long __f23;
+	unsigned long __f24;
+	unsigned long __f25;
+	unsigned long __f26;
+	unsigned long __f27;
+	unsigned long __f28;
+	unsigned long __f29;
+	unsigned long __f30;
+	unsigned long __f31;
+	unsigned long __fcr31;
+	unsigned long __unused;
+} __attribute__ ((aligned(8)));
+
+typedef struct __jmp_buf jmp_buf[1];
+
+#endif				/* _KLIBC_ARCHSETJMP_H */
diff --git a/usr/include/arch/mips/klibc/archsignal.h b/usr/include/arch/mips/klibc/archsignal.h
new file mode 100644
index 0000000..b9ca756
--- /dev/null
+++ b/usr/include/arch/mips/klibc/archsignal.h
@@ -0,0 +1,14 @@
+/*
+ * arch/mips/include/klibc/archsignal.h
+ *
+ * Architecture-specific signal definitions
+ *
+ */
+
+#ifndef _KLIBC_ARCHSIGNAL_H
+#define _KLIBC_ARCHSIGNAL_H
+
+#include <asm/signal.h>
+/* No special stuff for this architecture */
+
+#endif
diff --git a/usr/include/arch/mips/klibc/archsocket.h b/usr/include/arch/mips/klibc/archsocket.h
new file mode 100644
index 0000000..d6daf1b
--- /dev/null
+++ b/usr/include/arch/mips/klibc/archsocket.h
@@ -0,0 +1,17 @@
+/*
+ * arch/mips/klibc/archsocket.h
+ */
+
+#ifndef _KLIBC_ARCHSOCKET_H
+#define _KLIBC_ARCHSOCKET_H
+
+#ifndef SOCK_STREAM
+# define SOCK_DGRAM     1
+# define SOCK_STREAM    2
+# define SOCK_RAW       3
+# define SOCK_RDM       4
+# define SOCK_SEQPACKET 5
+# define SOCK_PACKET    10
+#endif
+
+#endif /* _KLIBC_ARCHSOCKET_H */
diff --git a/usr/include/arch/mips/klibc/archstat.h b/usr/include/arch/mips/klibc/archstat.h
new file mode 100644
index 0000000..c1d60d9
--- /dev/null
+++ b/usr/include/arch/mips/klibc/archstat.h
@@ -0,0 +1,40 @@
+#ifndef _KLIBC_ARCHSTAT_H
+#define _KLIBC_ARCHSTAT_H
+
+#define _STATBUF_ST_NSEC
+
+/*
+ * This matches struct stat64 in glibc2.1, hence the absolutely insane
+ * amounts of padding around dev_t's.  The memory layout is the same as of
+ * struct stat of the 64-bit kernel, which makes this one of the sanest
+ * 32-bit struct stats.
+ */
+
+struct stat {
+	unsigned int	st_dev;
+	unsigned long	st_pad0[3];	/* Reserved for st_dev expansion  */
+
+	unsigned long long	st_ino;
+
+	mode_t		st_mode;
+	nlink_t		st_nlink;
+
+	uid_t		st_uid;
+	gid_t		st_gid;
+
+	unsigned int	st_rdev;
+	unsigned long	st_pad1[3];	/* Reserved for st_rdev expansion  */
+
+	long long	st_size;
+
+	struct timespec		st_atim;
+	struct timespec		st_mtim;
+	struct timespec		st_ctim;
+
+	unsigned long	st_blksize;
+	unsigned long	st_pad2;
+
+	long long	st_blocks;
+};
+
+#endif
diff --git a/usr/include/arch/mips/machine/asm.h b/usr/include/arch/mips/machine/asm.h
new file mode 100644
index 0000000..f524bc6
--- /dev/null
+++ b/usr/include/arch/mips/machine/asm.h
@@ -0,0 +1,11 @@
+/*
+ * arch/mips/include/machine/asm.h
+ */
+
+#ifndef _MACHINE_ASM_H
+#define _MACHINE_ASM_H
+
+#include <asm/regdef.h>
+#include <asm/asm.h>
+
+#endif				/* _MACHINE_ASM_H */
diff --git a/usr/include/arch/mips/sgidefs.h b/usr/include/arch/mips/sgidefs.h
new file mode 100644
index 0000000..fba8ae8
--- /dev/null
+++ b/usr/include/arch/mips/sgidefs.h
@@ -0,0 +1,20 @@
+/*
+ * arch/mips/include/sgidefs.h
+ */
+
+/* Some ABI constants */
+
+#ifndef _SGIDEFS_H
+#define _SGIDEFS_H
+
+#define _MIPS_ISA_MIPS1 1
+#define _MIPS_ISA_MIPS2 2
+#define _MIPS_ISA_MIPS3 3
+#define _MIPS_ISA_MIPS4 4
+#define _MIPS_ISA_MIPS5 5
+
+#define _MIPS_SIM_ABI32         1
+#define _MIPS_SIM_NABI32        2
+#define _MIPS_SIM_ABI64         3
+
+#endif				/* _SGIDEFS_H */
diff --git a/usr/include/arch/mips/spaces.h b/usr/include/arch/mips/spaces.h
new file mode 100644
index 0000000..b5f530b
--- /dev/null
+++ b/usr/include/arch/mips/spaces.h
@@ -0,0 +1 @@
+/* Included by <asm/page.h> but not actually needed */
diff --git a/usr/include/arch/mips64/klibc/archconfig.h b/usr/include/arch/mips64/klibc/archconfig.h
new file mode 100644
index 0000000..9071cb4
--- /dev/null
+++ b/usr/include/arch/mips64/klibc/archconfig.h
@@ -0,0 +1,15 @@
+/*
+ * include/arch/mips64/klibc/archconfig.h
+ *
+ * See include/klibc/sysconfig.h for the options that can be set in
+ * this file.
+ *
+ */
+
+#ifndef _KLIBC_ARCHCONFIG_H
+#define _KLIBC_ARCHCONFIG_H
+
+/* MIPS has nonstandard socket definitions */
+#define _KLIBC_HAS_ARCHSOCKET_H 1
+
+#endif				/* _KLIBC_ARCHCONFIG_H */
diff --git a/usr/include/arch/mips64/klibc/archsignal.h b/usr/include/arch/mips64/klibc/archsignal.h
new file mode 100644
index 0000000..f350af9
--- /dev/null
+++ b/usr/include/arch/mips64/klibc/archsignal.h
@@ -0,0 +1,14 @@
+/*
+ * arch/mips64/include/klibc/archsignal.h
+ *
+ * Architecture-specific signal definitions
+ *
+ */
+
+#ifndef _KLIBC_ARCHSIGNAL_H
+#define _KLIBC_ARCHSIGNAL_H
+
+#include <asm/signal.h>
+/* No special stuff for this architecture */
+
+#endif
diff --git a/usr/include/arch/mips64/klibc/archsocket.h b/usr/include/arch/mips64/klibc/archsocket.h
new file mode 100644
index 0000000..6c3947d
--- /dev/null
+++ b/usr/include/arch/mips64/klibc/archsocket.h
@@ -0,0 +1,17 @@
+/*
+ * arch/mips64/klibc/archsocket.h
+ */
+
+#ifndef _KLIBC_ARCHSOCKET_H
+#define _KLIBC_ARCHSOCKET_H
+
+#ifndef SOCK_STREAM
+# define SOCK_DGRAM     1
+# define SOCK_STREAM    2
+# define SOCK_RAW       3
+# define SOCK_RDM       4
+# define SOCK_SEQPACKET 5
+# define SOCK_PACKET    10
+#endif
+
+#endif /* _KLIBC_ARCHSOCKET_H */
diff --git a/usr/include/arch/mips64/klibc/archstat.h b/usr/include/arch/mips64/klibc/archstat.h
new file mode 100644
index 0000000..577f9ad
--- /dev/null
+++ b/usr/include/arch/mips64/klibc/archstat.h
@@ -0,0 +1,33 @@
+#ifndef _KLIBC_ARCHSTAT_H
+#define _KLIBC_ARCHSTAT_H
+
+#define _STATBUF_ST_NSEC
+
+struct stat {
+	unsigned int		st_dev;
+	unsigned int		st_pad0[3]; /* Reserved for st_dev expansion */
+
+	unsigned long		st_ino;
+
+	mode_t			st_mode;
+	nlink_t			st_nlink;
+
+	uid_t			st_uid;
+	gid_t			st_gid;
+
+	unsigned int		st_rdev;
+	unsigned int		st_pad1[3]; /* Reserved for st_rdev expansion */
+
+	off_t			st_size;
+
+	struct timespec		st_atim;
+	struct timespec		st_mtim;
+	struct timespec		st_ctim;
+
+	unsigned int		st_blksize;
+	unsigned int		st_pad2;
+
+	unsigned long		st_blocks;
+};
+
+#endif
diff --git a/usr/include/arch/parisc/klibc/archconfig.h b/usr/include/arch/parisc/klibc/archconfig.h
new file mode 100644
index 0000000..f8ba9e2
--- /dev/null
+++ b/usr/include/arch/parisc/klibc/archconfig.h
@@ -0,0 +1,14 @@
+/*
+ * include/arch/parisc/klibc/archconfig.h
+ *
+ * See include/klibc/sysconfig.h for the options that can be set in
+ * this file.
+ *
+ */
+
+#ifndef _KLIBC_ARCHCONFIG_H
+#define _KLIBC_ARCHCONFIG_H
+
+/* All defaults */
+
+#endif				/* _KLIBC_ARCHCONFIG_H */
diff --git a/usr/include/arch/parisc/klibc/archsetjmp.h b/usr/include/arch/parisc/klibc/archsetjmp.h
new file mode 100644
index 0000000..05e943e
--- /dev/null
+++ b/usr/include/arch/parisc/klibc/archsetjmp.h
@@ -0,0 +1,14 @@
+/*
+ * arch/parisc/include/klibc/archsetjmp.h
+ */
+
+#ifndef _KLIBC_ARCHSETJMP_H
+#define _KLIBC_ARCHSETJMP_H
+
+struct __jmp_buf {
+	double regs[21];
+};
+
+typedef struct __jmp_buf jmp_buf[1];
+
+#endif				/* _SETJMP_H */
diff --git a/usr/include/arch/parisc/klibc/archsignal.h b/usr/include/arch/parisc/klibc/archsignal.h
new file mode 100644
index 0000000..256aeea
--- /dev/null
+++ b/usr/include/arch/parisc/klibc/archsignal.h
@@ -0,0 +1,25 @@
+/*
+ * arch/parisc/include/klibc/archsignal.h
+ *
+ * Architecture-specific signal definitions
+ *
+ */
+
+#ifndef _KLIBC_ARCHSIGNAL_H
+#define _KLIBC_ARCHSIGNAL_H
+
+#include <asm/signal.h>
+#define _NSIG    64
+#define _NSIG_SZ (_NSIG / LONG_BIT)
+
+typedef struct {
+	unsigned long sig[_NSIG_SZ];
+} sigset_t;
+
+struct sigaction {
+	__sighandler_t	sa_handler;
+	unsigned long	sa_flags;
+	sigset_t	sa_mask;
+};
+
+#endif
diff --git a/usr/include/arch/parisc/klibc/archstat.h b/usr/include/arch/parisc/klibc/archstat.h
new file mode 100644
index 0000000..0b8ef8d
--- /dev/null
+++ b/usr/include/arch/parisc/klibc/archstat.h
@@ -0,0 +1,29 @@
+#ifndef _KLIBC_ARCHSTAT_H
+#define _KLIBC_ARCHSTAT_H
+
+#include <klibc/stathelp.h>
+
+#define _STATBUF_ST_NSEC
+
+struct stat {
+	__stdev64		(st_dev);
+	unsigned int		__pad1;
+
+	unsigned int		__st_ino;	/* Not actually filled in */
+	unsigned int		st_mode;
+	unsigned int		st_nlink;
+	unsigned int		st_uid;
+	unsigned int		st_gid;
+	__stdev64		(st_rdev);
+	unsigned int		__pad2;
+	signed long long	st_size;
+	signed int		st_blksize;
+
+	signed long long	st_blocks;
+	struct timespec		st_atim;
+	struct timespec		st_mtim;
+	struct timespec		st_ctim;
+	unsigned long long	st_ino;
+};
+
+#endif
diff --git a/usr/include/arch/ppc/klibc/archconfig.h b/usr/include/arch/ppc/klibc/archconfig.h
new file mode 100644
index 0000000..ce04eee
--- /dev/null
+++ b/usr/include/arch/ppc/klibc/archconfig.h
@@ -0,0 +1,14 @@
+/*
+ * include/arch/ppc/klibc/archconfig.h
+ *
+ * See include/klibc/sysconfig.h for the options that can be set in
+ * this file.
+ *
+ */
+
+#ifndef _KLIBC_ARCHCONFIG_H
+#define _KLIBC_ARCHCONFIG_H
+
+/* All defaults */
+
+#endif				/* _KLIBC_ARCHCONFIG_H */
diff --git a/usr/include/arch/ppc/klibc/archsetjmp.h b/usr/include/arch/ppc/klibc/archsetjmp.h
new file mode 100644
index 0000000..4be9ed6
--- /dev/null
+++ b/usr/include/arch/ppc/klibc/archsetjmp.h
@@ -0,0 +1,36 @@
+/*
+ * arch/ppc/include/klibc/archsetjmp.h
+ */
+
+#ifndef _KLIBC_ARCHSETJMP_H
+#define _KLIBC_ARCHSETJMP_H
+
+struct __jmp_buf {
+	unsigned long __r2;
+	unsigned long __sp;
+	unsigned long __lr;
+	unsigned long __cr;
+	unsigned long __r13;
+	unsigned long __r14;
+	unsigned long __r15;
+	unsigned long __r16;
+	unsigned long __r17;
+	unsigned long __r18;
+	unsigned long __r19;
+	unsigned long __r20;
+	unsigned long __r21;
+	unsigned long __r22;
+	unsigned long __r23;
+	unsigned long __r24;
+	unsigned long __r25;
+	unsigned long __r26;
+	unsigned long __r27;
+	unsigned long __r28;
+	unsigned long __r29;
+	unsigned long __r30;
+	unsigned long __r31;
+};
+
+typedef struct __jmp_buf jmp_buf[1];
+
+#endif				/* _SETJMP_H */
diff --git a/usr/include/arch/ppc/klibc/archsignal.h b/usr/include/arch/ppc/klibc/archsignal.h
new file mode 100644
index 0000000..9c3ac92
--- /dev/null
+++ b/usr/include/arch/ppc/klibc/archsignal.h
@@ -0,0 +1,14 @@
+/*
+ * arch/ppc/include/klibc/archsignal.h
+ *
+ * Architecture-specific signal definitions
+ *
+ */
+
+#ifndef _KLIBC_ARCHSIGNAL_H
+#define _KLIBC_ARCHSIGNAL_H
+
+#include <asm/signal.h>
+/* No special stuff for this architecture */
+
+#endif
diff --git a/usr/include/arch/ppc/klibc/archstat.h b/usr/include/arch/ppc/klibc/archstat.h
new file mode 100644
index 0000000..9e31f4a
--- /dev/null
+++ b/usr/include/arch/ppc/klibc/archstat.h
@@ -0,0 +1,30 @@
+#ifndef _KLIBC_ARCHSTAT_H
+#define _KLIBC_ARCHSTAT_H
+
+#include <klibc/stathelp.h>
+
+#define _STATBUF_ST_NSEC
+
+/* This matches struct stat64 in glibc2.1.
+ */
+struct stat {
+	__stdev64 (st_dev);		/* Device. */
+	unsigned long long st_ino;	/* File serial number.  */
+	unsigned int st_mode;		/* File mode.  */
+	unsigned int st_nlink;		/* Link count.  */
+	unsigned int st_uid;		/* User ID of the file's owner.  */
+	unsigned int st_gid;		/* Group ID of the file's group. */
+	__stdev64 (st_rdev); 		/* Device number, if device.  */
+	unsigned short int __pad2;
+	long long st_size;		/* Size of file, in bytes.  */
+	long st_blksize;		/* Optimal block size for I/O.  */
+
+	long long st_blocks;		/* Number 512-byte blocks allocated. */
+	struct timespec st_atim;	/* Time of last access.  */
+	struct timespec st_mtim;	/* Time of last modification.  */
+	struct timespec st_ctim;	/* Time of last status change.  */
+	unsigned long int __unused4;
+	unsigned long int __unused5;
+};
+
+#endif
diff --git a/usr/include/arch/ppc64/klibc/archconfig.h b/usr/include/arch/ppc64/klibc/archconfig.h
new file mode 100644
index 0000000..27c5630
--- /dev/null
+++ b/usr/include/arch/ppc64/klibc/archconfig.h
@@ -0,0 +1,12 @@
+/*
+ * include/arch/ppc64/klibc/archconfig.h
+ *
+ * See include/klibc/sysconfig.h for the options that can be set in this file.
+ */
+
+#ifndef _KLIBC_ARCHCONFIG_H
+#define _KLIBC_ARCHCONFIG_H
+
+#define _KLIBC_USE_RT_SIG 1
+
+#endif				/* _KLIBC_ARCHCONFIG_H */
diff --git a/usr/include/arch/ppc64/klibc/archsetjmp.h b/usr/include/arch/ppc64/klibc/archsetjmp.h
new file mode 100644
index 0000000..d227728
--- /dev/null
+++ b/usr/include/arch/ppc64/klibc/archsetjmp.h
@@ -0,0 +1,36 @@
+/*
+ * arch/ppc64/include/klibc/archsetjmp.h
+ */
+
+#ifndef _KLIBC_ARCHSETJMP_H
+#define _KLIBC_ARCHSETJMP_H
+
+struct __jmp_buf {
+	unsigned long __r2;
+	unsigned long __sp;
+	unsigned long __lr;
+	unsigned long __cr;
+	unsigned long __r13;
+	unsigned long __r14;
+	unsigned long __r15;
+	unsigned long __r16;
+	unsigned long __r17;
+	unsigned long __r18;
+	unsigned long __r19;
+	unsigned long __r20;
+	unsigned long __r21;
+	unsigned long __r22;
+	unsigned long __r23;
+	unsigned long __r24;
+	unsigned long __r25;
+	unsigned long __r26;
+	unsigned long __r27;
+	unsigned long __r28;
+	unsigned long __r29;
+	unsigned long __r30;
+	unsigned long __r31;
+};
+
+typedef struct __jmp_buf jmp_buf[1];
+
+#endif				/* _SETJMP_H */
diff --git a/usr/include/arch/ppc64/klibc/archsignal.h b/usr/include/arch/ppc64/klibc/archsignal.h
new file mode 100644
index 0000000..2c4cef0
--- /dev/null
+++ b/usr/include/arch/ppc64/klibc/archsignal.h
@@ -0,0 +1,14 @@
+/*
+ * arch/ppc64/include/klibc/archsignal.h
+ *
+ * Architecture-specific signal definitions
+ *
+ */
+
+#ifndef _KLIBC_ARCHSIGNAL_H
+#define _KLIBC_ARCHSIGNAL_H
+
+#include <asm/signal.h>
+/* No special stuff for this architecture */
+
+#endif
diff --git a/usr/include/arch/ppc64/klibc/archstat.h b/usr/include/arch/ppc64/klibc/archstat.h
new file mode 100644
index 0000000..491316c
--- /dev/null
+++ b/usr/include/arch/ppc64/klibc/archstat.h
@@ -0,0 +1,27 @@
+#ifndef _KLIBC_ARCHSTAT_H
+#define _KLIBC_ARCHSTAT_H
+
+#include <klibc/stathelp.h>
+
+#define _STATBUF_ST_NSEC
+
+struct stat {
+	__stdev64	(st_dev);
+	ino_t		st_ino;
+	nlink_t		st_nlink;
+	mode_t		st_mode;
+	uid_t 		st_uid;
+	gid_t 		st_gid;
+	__stdev64	(st_rdev);
+	off_t		st_size;
+	unsigned long  	st_blksize;
+	unsigned long  	st_blocks;
+	struct timespec st_atim;	/* Time of last access.  */
+	struct timespec st_mtim;	/* Time of last modification.  */
+	struct timespec st_ctim;	/* Time of last status change.  */
+	unsigned long  	__unused4;
+	unsigned long  	__unused5;
+	unsigned long  	__unused6;
+};
+
+#endif
diff --git a/usr/include/arch/s390/klibc/archconfig.h b/usr/include/arch/s390/klibc/archconfig.h
new file mode 100644
index 0000000..d7a71a4
--- /dev/null
+++ b/usr/include/arch/s390/klibc/archconfig.h
@@ -0,0 +1,15 @@
+/*
+ * include/arch/s390/klibc/archconfig.h
+ *
+ * See include/klibc/sysconfig.h for the options that can be set in
+ * this file.
+ *
+ */
+
+#ifndef _KLIBC_ARCHCONFIG_H
+#define _KLIBC_ARCHCONFIG_H
+
+/* Both s390 and s390x use the "32-bit" version of this structure */
+#define _KLIBC_STATFS_F_TYPE_64 0
+
+#endif				/* _KLIBC_ARCHCONFIG_H */
diff --git a/usr/include/arch/s390/klibc/archsetjmp.h b/usr/include/arch/s390/klibc/archsetjmp.h
new file mode 100644
index 0000000..728780a
--- /dev/null
+++ b/usr/include/arch/s390/klibc/archsetjmp.h
@@ -0,0 +1,26 @@
+/*
+ * arch/s390/include/klibc/archsetjmp.h
+ */
+
+#ifndef _KLIBC_ARCHSETJMP_H
+#define _KLIBC_ARCHSETJMP_H
+
+#ifndef __s390x__
+
+struct __jmp_buf {
+	uint32_t __gregs[10];	/* general registers r6-r15 */
+	uint64_t __fpregs[2];	/* fp registers f4 and f6   */
+};
+
+#else /* __s390x__ */
+
+struct __jmp_buf {
+	uint64_t __gregs[10]; /* general registers r6-r15 */
+	uint64_t __fpregs[4]; /* fp registers f1, f3, f5, f7 */
+};
+
+#endif /* __s390x__ */
+
+typedef struct __jmp_buf jmp_buf[1];
+
+#endif				/* _SETJMP_H */
diff --git a/usr/include/arch/s390/klibc/archsignal.h b/usr/include/arch/s390/klibc/archsignal.h
new file mode 100644
index 0000000..a16b977
--- /dev/null
+++ b/usr/include/arch/s390/klibc/archsignal.h
@@ -0,0 +1,14 @@
+/*
+ * arch/s390/include/klibc/archsignal.h
+ *
+ * Architecture-specific signal definitions
+ *
+ */
+
+#ifndef _KLIBC_ARCHSIGNAL_H
+#define _KLIBC_ARCHSIGNAL_H
+
+#include <asm/signal.h>
+/* No special stuff for this architecture */
+
+#endif
diff --git a/usr/include/arch/s390/klibc/archstat.h b/usr/include/arch/s390/klibc/archstat.h
new file mode 100644
index 0000000..ca4c822
--- /dev/null
+++ b/usr/include/arch/s390/klibc/archstat.h
@@ -0,0 +1,56 @@
+#ifndef _KLIBC_ARCHSTAT_H
+#define _KLIBC_ARCHSTAT_H
+
+#include <klibc/stathelp.h>
+
+#define _STATBUF_ST_NSEC
+
+#ifndef __s390x__
+
+/* This matches struct stat64 in glibc2.1, hence the absolutely
+ * insane amounts of padding around dev_t's.
+ */
+struct stat {
+	__stdev64	(st_dev);
+	unsigned int	__pad1;
+#define STAT64_HAS_BROKEN_ST_INO	1
+	unsigned long	__st_ino;
+	unsigned int	st_mode;
+	unsigned int	st_nlink;
+	unsigned long	st_uid;
+	unsigned long	st_gid;
+	__stdev64	(st_rdev);
+	unsigned int	__pad3;
+	long long	st_size;
+	unsigned long	st_blksize;
+	unsigned char	__pad4[4];
+	unsigned long	__pad5;     /* future possible st_blocks high bits */
+	unsigned long	st_blocks;  /* Number 512-byte blocks allocated. */
+	struct timespec st_atim;
+	struct timespec st_mtim;
+	struct timespec st_ctim;
+	unsigned long long	st_ino;
+};
+
+#else /* __s390x__ */
+
+struct stat {
+	__stdev64	(st_dev);
+	unsigned long	st_ino;
+	unsigned long	st_nlink;
+	unsigned int	st_mode;
+	unsigned int	st_uid;
+	unsigned int	st_gid;
+	unsigned int	__pad1;
+	__stdev64	(st_rdev);
+	unsigned long	st_size;
+	struct timespec	st_atim;
+	struct timespec	st_mtim;
+	struct timespec	st_ctim;
+	unsigned long	st_blksize;
+	long		st_blocks;
+	unsigned long	__unused[3];
+};
+
+#endif /* __s390x__ */
+#endif
diff --git a/usr/include/arch/sh/klibc/archconfig.h b/usr/include/arch/sh/klibc/archconfig.h
new file mode 100644
index 0000000..9c9e3d8
--- /dev/null
+++ b/usr/include/arch/sh/klibc/archconfig.h
@@ -0,0 +1,14 @@
+/*
+ * include/arch/sh/klibc/archconfig.h
+ *
+ * See include/klibc/sysconfig.h for the options that can be set in
+ * this file.
+ *
+ */
+
+#ifndef _KLIBC_ARCHCONFIG_H
+#define _KLIBC_ARCHCONFIG_H
+
+/* All defaults */
+
+#endif				/* _KLIBC_ARCHCONFIG_H */
diff --git a/usr/include/arch/sh/klibc/archsetjmp.h b/usr/include/arch/sh/klibc/archsetjmp.h
new file mode 100644
index 0000000..bb97167
--- /dev/null
+++ b/usr/include/arch/sh/klibc/archsetjmp.h
@@ -0,0 +1,22 @@
+/*
+ * arch/sh/include/klibc/archsetjmp.h
+ */
+
+#ifndef _KLIBC_ARCHSETJMP_H
+#define _KLIBC_ARCHSETJMP_H
+
+struct __jmp_buf {
+	unsigned long __r8;
+	unsigned long __r9;
+	unsigned long __r10;
+	unsigned long __r11;
+	unsigned long __r12;
+	unsigned long __r13;
+	unsigned long __r14;
+	unsigned long __r15;
+	unsigned long __pr;
+};
+
+typedef struct __jmp_buf jmp_buf[1];
+
+#endif				/* _KLIBC_ARCHSETJMP_H */
diff --git a/usr/include/arch/sh/klibc/archsignal.h b/usr/include/arch/sh/klibc/archsignal.h
new file mode 100644
index 0000000..8e48e51
--- /dev/null
+++ b/usr/include/arch/sh/klibc/archsignal.h
@@ -0,0 +1,14 @@
+/*
+ * arch/sh/include/klibc/archsignal.h
+ *
+ * Architecture-specific signal definitions
+ *
+ */
+
+#ifndef _KLIBC_ARCHSIGNAL_H
+#define _KLIBC_ARCHSIGNAL_H
+
+#include <asm/signal.h>
+/* No special stuff for this architecture */
+
+#endif
diff --git a/usr/include/arch/sh/klibc/archstat.h b/usr/include/arch/sh/klibc/archstat.h
new file mode 100644
index 0000000..4f39181
--- /dev/null
+++ b/usr/include/arch/sh/klibc/archstat.h
@@ -0,0 +1,38 @@
+#ifndef _KLIBC_ARCHSTAT_H
+#define _KLIBC_ARCHSTAT_H
+
+#include <klibc/stathelp.h>
+
+#define _STATBUF_ST_NSEC
+
+/* This matches struct stat64 in glibc2.1, hence the absolutely
+ * insane amounts of padding around dev_t's.
+ */
+struct stat {
+	__stdev64	(st_dev);
+	unsigned char	__pad0[4];
+
+	unsigned long	st_ino;
+	unsigned int	st_mode;
+	unsigned int	st_nlink;
+
+	unsigned long	st_uid;
+	unsigned long	st_gid;
+
+	__stdev64	(st_rdev);
+	unsigned char	__pad3[4];
+
+	long long	st_size;
+	unsigned long	st_blksize;
+
+	unsigned long long st_blocks;
+
+	struct timespec	st_atim;
+	struct timespec st_mtim;
+	struct timespec st_ctim;
+
+	unsigned long	__unused1;
+	unsigned long	__unused2;
+};
+
+#endif
diff --git a/usr/include/arch/sparc/klibc/archconfig.h b/usr/include/arch/sparc/klibc/archconfig.h
new file mode 100644
index 0000000..90a6c49
--- /dev/null
+++ b/usr/include/arch/sparc/klibc/archconfig.h
@@ -0,0 +1,14 @@
+/*
+ * include/arch/sparc/klibc/archconfig.h
+ *
+ * See include/klibc/sysconfig.h for the options that can be set in
+ * this file.
+ *
+ */
+
+#ifndef _KLIBC_ARCHCONFIG_H
+#define _KLIBC_ARCHCONFIG_H
+
+#define _KLIBC_USE_RT_SIG 1	/* Use rt_* signals */
+
+#endif				/* _KLIBC_ARCHCONFIG_H */
diff --git a/usr/include/arch/sparc/klibc/archsetjmp.h b/usr/include/arch/sparc/klibc/archsetjmp.h
new file mode 100644
index 0000000..9b4d6a2
--- /dev/null
+++ b/usr/include/arch/sparc/klibc/archsetjmp.h
@@ -0,0 +1,16 @@
+/*
+ * arch/sparc/include/klibc/archsetjmp.h
+ */
+
+#ifndef _KLIBC_ARCHSETJMP_H
+#define _KLIBC_ARCHSETJMP_H
+
+struct __jmp_buf {
+	unsigned long __sp;
+	unsigned long __fp;
+	unsigned long __pc;
+};
+
+typedef struct __jmp_buf jmp_buf[1];
+
+#endif				/* _SETJMP_H */
diff --git a/usr/include/arch/sparc/klibc/archsignal.h b/usr/include/arch/sparc/klibc/archsignal.h
new file mode 100644
index 0000000..6e845a8
--- /dev/null
+++ b/usr/include/arch/sparc/klibc/archsignal.h
@@ -0,0 +1,24 @@
+/*
+ * arch/sparc/include/klibc/archsignal.h
+ *
+ * Architecture-specific signal definitions
+ *
+ */
+
+#ifndef _KLIBC_ARCHSIGNAL_H
+#define _KLIBC_ARCHSIGNAL_H
+
+#define __WANT_POSIX1B_SIGNALS__
+#include <asm/signal.h>
+
+struct sigaction {
+	__sighandler_t	sa_handler;
+	unsigned long	sa_flags;
+	void		(*sa_restorer)(void);	/* Not used by Linux/SPARC */
+	sigset_t	sa_mask;
+};
+
+/* Not actually used by the kernel... */
+#define SA_RESTORER	0x80000000
+
+#endif
diff --git a/usr/include/arch/sparc/klibc/archstat.h b/usr/include/arch/sparc/klibc/archstat.h
new file mode 100644
index 0000000..203d40b
--- /dev/null
+++ b/usr/include/arch/sparc/klibc/archstat.h
@@ -0,0 +1,37 @@
+#ifndef _KLIBC_ARCHSTAT_H
+#define _KLIBC_ARCHSTAT_H
+
+#include <klibc/stathelp.h>
+
+#define _STATBUF_ST_NSEC
+
+struct stat {
+	__stdev64	(st_dev);
+
+	unsigned long long st_ino;
+
+	unsigned int	st_mode;
+	unsigned int	st_nlink;
+
+	unsigned int	st_uid;
+	unsigned int	st_gid;
+
+	__stdev64	(st_rdev);
+
+	unsigned char	__pad3[8];
+
+	long long	st_size;
+	unsigned int	st_blksize;
+
+	unsigned char	__pad4[8];
+	unsigned int	st_blocks;
+
+	struct timespec st_atim;
+	struct timespec st_mtim;
+	struct timespec st_ctim;
+
+	unsigned int	__unused4;
+	unsigned int	__unused5;
+};
+
+#endif
diff --git a/usr/include/arch/sparc/machine/asm.h b/usr/include/arch/sparc/machine/asm.h
new file mode 100644
index 0000000..04fe9b1
--- /dev/null
+++ b/usr/include/arch/sparc/machine/asm.h
@@ -0,0 +1,191 @@
+/*	$NetBSD: asm.h,v 1.14 2002/07/20 08:37:30 mrg Exp $ */
+
+/*
+ * Copyright (c) 1994 Allen Briggs
+ * All rights reserved.
+ *
+ * Gleaned from locore.s and sun3 asm.h which had the following copyrights:
+ * locore.s:
+ * Copyright (c) 1988 University of Utah.
+ * Copyright (c) 1982, 1990 The Regents of the University of California.
+ * sun3/include/asm.h:
+ * Copyright (c) 1993 Adam Glass
+ * Copyright (c) 1990 The Regents of the University of California.
+ *
+ * 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.
+ */
+
+#ifndef _ASM_H_
+#define _ASM_H_
+
+/* Pull in CCFSZ, CC64FSZ, and BIAS from frame.h */
+#ifndef _LOCORE
+#define _LOCORE
+#endif
+#include <machine/frame.h>
+
+#ifdef __ELF__
+#define	_C_LABEL(name)		name
+#else
+#ifdef __STDC__
+#define _C_LABEL(name)		_ ## name
+#else
+#define _C_LABEL(name)		_/**/name
+#endif
+#endif
+#define	_ASM_LABEL(name)	name
+
+#ifdef PIC
+/*
+ * PIC_PROLOGUE() is akin to the compiler generated function prologue for
+ * PIC code. It leaves the address of the Global Offset Table in DEST,
+ * clobbering register TMP in the process.
+ *
+ * We can use two code sequences.  We can read the %pc or use the call
+ * instruction that saves the pc in %o7.  Call requires the branch unit and
+ * IEU1, and clobbers %o7 which needs to be restored.  This instruction
+ * sequence takes about 4 cycles due to instruction interdependence.  Reading
+ * the pc takes 4 cycles to dispatch and is always dispatched alone.  That
+ * sequence takes 7 cycles.
+ */
+#ifdef __arch64__
+#define PIC_PROLOGUE(dest,tmp) \
+	mov %o7, tmp; \
+	sethi %hi(_GLOBAL_OFFSET_TABLE_-4),dest; \
+	call 0f; \
+	 or dest,%lo(_GLOBAL_OFFSET_TABLE_+4),dest; \
+0: \
+	add dest,%o7,dest; \
+	mov tmp, %o7
+#else
+#define PIC_PROLOGUE(dest,tmp) \
+	mov %o7,tmp; 3: call 4f; nop; 4: \
+	sethi %hi(_C_LABEL(_GLOBAL_OFFSET_TABLE_)-(3b-.)),dest; \
+	or dest,%lo(_C_LABEL(_GLOBAL_OFFSET_TABLE_)-(3b-.)),dest; \
+	add dest,%o7,dest; mov tmp,%o7
+#endif
+
+/*
+ * PICCY_SET() does the equivalent of a `set var, %dest' instruction in
+ * a PIC-like way, but without involving the Global Offset Table. This
+ * only works for VARs defined in the same file *and* in the text segment.
+ */
+#ifdef __arch64__
+#define PICCY_SET(var,dest,tmp) \
+	3: rd %pc, tmp; add tmp,(var-3b),dest
+#else
+#define PICCY_SET(var,dest,tmp) \
+	mov %o7,tmp; 3: call 4f; nop; 4: \
+	add %o7,(var-3b),dest; mov tmp,%o7
+#endif
+#else
+#define PIC_PROLOGUE(dest,tmp)
+#define PICCY_OFFSET(var,dest,tmp)
+#endif
+
+#define FTYPE(x)		.type x,@function
+#define OTYPE(x)		.type x,@object
+
+#define	_ENTRY(name) \
+	.align 4; .globl name; .proc 1; FTYPE(name); name:
+
+#ifdef GPROF
+/* see _MCOUNT_ENTRY in profile.h */
+#ifdef __ELF__
+#ifdef __arch64__
+#define _PROF_PROLOGUE \
+	.data; .align 8; 1: .uaword 0; .uaword 0; \
+	.text; save %sp,-CC64FSZ,%sp; sethi %hi(1b),%o0; call _mcount; \
+	or %o0,%lo(1b),%o0; restore
+#else
+#define _PROF_PROLOGUE \
+	.data; .align 4; 1: .long 0; \
+	.text; save %sp,-96,%sp; sethi %hi(1b),%o0; call _mcount; \
+	or %o0,%lo(1b),%o0; restore
+#endif
+#else
+#ifdef __arch64__
+#define _PROF_PROLOGUE \
+	.data; .align 8; 1: .uaword 0; .uaword 0; \
+	.text; save %sp,-CC64FSZ,%sp; sethi %hi(1b),%o0; call mcount; \
+	or %o0,%lo(1b),%o0; restore
+#else
+#define	_PROF_PROLOGUE \
+	.data; .align 4; 1: .long 0; \
+	.text; save %sp,-96,%sp; sethi %hi(1b),%o0; call mcount; \
+	or %o0,%lo(1b),%o0; restore
+#endif
+#endif
+#else
+#define _PROF_PROLOGUE
+#endif
+
+#define ENTRY(name)		_ENTRY(_C_LABEL(name)); _PROF_PROLOGUE
+#define ENTRY_NOPROFILE(name)	_ENTRY(_C_LABEL(name))
+#define	ASENTRY(name)		_ENTRY(_ASM_LABEL(name)); _PROF_PROLOGUE
+#define	FUNC(name)		ASENTRY(name)
+#define RODATA(name)		.align 4; .text; .globl _C_LABEL(name); \
+				OTYPE(_C_LABEL(name)); _C_LABEL(name):
+
+#define ASMSTR			.asciz
+
+#define RCSID(name)		.asciz name
+
+#ifdef __ELF__
+#define	WEAK_ALIAS(alias,sym)						\
+	.weak alias;							\
+	alias = sym
+#endif
+
+/*
+ * WARN_REFERENCES: create a warning if the specified symbol is referenced.
+ */
+#ifdef __ELF__
+#ifdef __STDC__
+#define	WARN_REFERENCES(_sym,_msg)				\
+	.section .gnu.warning. ## _sym ; .ascii _msg ; .text
+#else
+#define	WARN_REFERENCES(_sym,_msg)				\
+	.section .gnu.warning./**/_sym ; .ascii _msg ; .text
+#endif				/* __STDC__ */
+#else
+#ifdef __STDC__
+#define	__STRING(x)			#x
+#define	WARN_REFERENCES(sym,msg)					\
+	.stabs msg ## ,30,0,0,0 ;					\
+	.stabs __STRING(_ ## sym) ## ,1,0,0,0
+#else
+#define	__STRING(x)			"x"
+#define	WARN_REFERENCES(sym,msg)					\
+	.stabs msg,30,0,0,0 ;						\
+	.stabs __STRING(_/**/sym),1,0,0,0
+#endif				/* __STDC__ */
+#endif				/* __ELF__ */
+
+#endif				/* _ASM_H_ */
diff --git a/usr/include/arch/sparc/machine/frame.h b/usr/include/arch/sparc/machine/frame.h
new file mode 100644
index 0000000..6fb9c45
--- /dev/null
+++ b/usr/include/arch/sparc/machine/frame.h
@@ -0,0 +1,146 @@
+/*	$NetBSD: frame.h,v 1.4 2001/12/04 00:05:05 darrenr 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.
+ *
+ * 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, Lawrence Berkeley Laboratory.
+ *
+ * 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.
+ *
+ *	@(#)frame.h	8.1 (Berkeley) 6/11/93
+ */
+
+#ifndef _MACHINE_FRAME_H
+#define _MACHINE_FRAME_H
+
+#ifdef __ASSEMBLY__
+# define _LOCORE
+#endif
+
+#ifndef _LOCORE
+# include <stdint.h>
+#endif
+
+/*
+ * Sparc stack frame format.
+ *
+ * Note that the contents of each stack frame may be held only in
+ * machine register windows.  In order to get an accurate picture
+ * of the frame, you must first force the kernel to write any such
+ * windows to the stack.
+ */
+#ifndef _LOCORE
+#ifndef SUN4U
+struct frame {
+	int32_t fr_local[8];	/* space to save locals (%l0..%l7) */
+	int32_t fr_arg[6];	/* space to save arguments (%i0..%i5) */
+	struct frame *fr_fp;	/* space to save frame pointer (%i6) */
+	int32_t fr_pc;		/* space to save return pc (%i7) */
+	/*
+	 * SunOS reserves another 8 words here; this is pointless
+	 * but we do it for compatibility.
+	 */
+	int32_t fr_xxx;		/* `structure return pointer' (unused) */
+	int32_t fr_argd[6];	/* `arg dump area' (lunacy) */
+	int32_t fr_argx[1];	/* arg extension (args 7..n; variable size) */
+};
+#else
+struct frame32 {
+	int32_t fr_local[8];	/* space to save locals (%l0..%l7) */
+	int32_t fr_arg[6];	/* space to save arguments (%i0..%i5) */
+	uint32_t fr_fp;	/* space to save frame pointer (%i6) */
+	uint32_t fr_pc;	/* space to save return pc (%i7) */
+	/*
+	 * SunOS reserves another 8 words here; this is pointless
+	 * but we do it for compatibility.
+	 */
+	int32_t fr_xxx;		/* `structure return pointer' (unused) */
+	int32_t fr_argd[6];	/* `arg dump area' (lunacy) */
+	int32_t fr_argx[1];	/* arg extension (args 7..n; variable size) */
+};
+#endif
+#endif
+
+/*
+ * CCFSZ (C Compiler Frame SiZe) is the size of a stack frame required if
+ * a function is to call C code.  It should be just 64, but Sun defined
+ * their frame with space to hold arguments 0 through 5 (plus some junk),
+ * and varargs routines (such as kprintf) demand this, and gcc uses this
+ * area at times anyway.
+ */
+#define CCFSZ		96
+
+/*
+ * Sparc v9 stack frame format.
+ *
+ * Note that the contents of each stack frame may be held only in
+ * machine register windows.  In order to get an accurate picture
+ * of the frame, you must first force the kernel to write any such
+ * windows to the stack.
+ *
+ * V9 frames have an odd bias, so you can tall a v9 frame from
+ * a v8 frame by testing the stack pointer's lsb.
+ */
+#if !defined(_LOCORE) && !defined(_LIBC)
+struct frame64 {
+	int64_t fr_local[8];	/* space to save locals (%l0..%l7) */
+	int64_t fr_arg[6];	/* space to save arguments (%i0..%i5) */
+	uint64_t fr_fp;		/* space to save frame pointer (%i6) */
+	uint64_t fr_pc;		/* space to save return pc (%i7) */
+	/*
+	 * SVR4 reserves a bunch of extra stuff.
+	 */
+	int64_t fr_argd[6];	/* `register save area' (lunacy) */
+	int64_t fr_argx[0];	/* arg extension (args 7..n; variable size) */
+};
+
+#define v9next_frame(f)		((struct frame64*)(f->fr_fp+BIAS))
+#endif
+
+/*
+ * CC64FSZ (C Compiler 64-bit Frame SiZe) is the size of a stack frame used
+ * by the compiler in 64-bit mode.  It is (16)*8; space for 8 ins, 8 outs.
+ */
+#define CC64FSZ		176
+
+/*
+ * v9 stacks all have a bias of 2047 added to the %sp and %fp, so you can easily
+ * detect it by testing the register for an odd value.  Why 2K-1 I don't know.
+ */
+#define BIAS	(2048-1)
+
+#endif /* _MACHINE_FRAME_H */
diff --git a/usr/include/arch/sparc/machine/trap.h b/usr/include/arch/sparc/machine/trap.h
new file mode 100644
index 0000000..5c378c5
--- /dev/null
+++ b/usr/include/arch/sparc/machine/trap.h
@@ -0,0 +1,140 @@
+/*	$NetBSD: trap.h,v 1.11 1999/01/20 00:15:08 pk 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.
+ *
+ * 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, Lawrence Berkeley Laboratory.
+ *
+ * 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.
+ *
+ *	@(#)trap.h	8.1 (Berkeley) 6/11/93
+ */
+/*
+ * Sun4m support by Aaron Brown, Harvard University.
+ * Changes Copyright (c) 1995 The President and Fellows of Harvard College.
+ * All rights reserved.
+ */
+
+#ifndef	_MACHINE_TRAP_H
+#define	_MACHINE_TRAP_H
+
+/*	trap		vec	  (pri) description	*/
+#define	T_RESET		0x00	/* (1) not actually vectored; jumps to 0 */
+#define	T_TEXTFAULT	0x01	/* (2) address fault during instr fetch */
+#define	T_ILLINST	0x02	/* (3) illegal instruction */
+#define	T_PRIVINST	0x03	/* (4) privileged instruction */
+#define	T_FPDISABLED	0x04	/* (5) fp instr while fp disabled */
+#define	T_WINOF		0x05	/* (6) register window overflow */
+#define	T_WINUF		0x06	/* (7) register window underflow */
+#define	T_ALIGN		0x07	/* (8) address not properly aligned */
+#define	T_FPE		0x08	/* (9) floating point exception */
+#define	T_DATAFAULT	0x09	/* (10) address fault during data fetch */
+#define	T_TAGOF		0x0a	/* (11) tag overflow */
+/*			0x0b	   unused */
+/*			0x0c	   unused */
+/*			0x0d	   unused */
+/*			0x0e	   unused */
+/*			0x0f	   unused */
+/*			0x10	   unused */
+#define	T_L1INT		0x11	/* (27) level 1 interrupt */
+#define	T_L2INT		0x12	/* (26) level 2 interrupt */
+#define	T_L3INT		0x13	/* (25) level 3 interrupt */
+#define	T_L4INT		0x14	/* (24) level 4 interrupt */
+#define	T_L5INT		0x15	/* (23) level 5 interrupt */
+#define	T_L6INT		0x16	/* (22) level 6 interrupt */
+#define	T_L7INT		0x17	/* (21) level 7 interrupt */
+#define	T_L8INT		0x18	/* (20) level 8 interrupt */
+#define	T_L9INT		0x19	/* (19) level 9 interrupt */
+#define	T_L10INT	0x1a	/* (18) level 10 interrupt */
+#define	T_L11INT	0x1b	/* (17) level 11 interrupt */
+#define	T_L12INT	0x1c	/* (16) level 12 interrupt */
+#define	T_L13INT	0x1d	/* (15) level 13 interrupt */
+#define	T_L14INT	0x1e	/* (14) level 14 interrupt */
+#define	T_L15INT	0x1f	/* (13) level 15 interrupt */
+/*			0x20	   unused */
+/*	through		0x23	   unused */
+#define	T_CPDISABLED	0x24	/* (5) coprocessor instr while disabled */
+#define	T_UNIMPLFLUSH	0x25	/* Unimplemented FLUSH */
+/*	through		0x27	   unused */
+#define	T_CPEXCEPTION	0x28	/* (9) coprocessor exception */
+/*			0x29	   unused */
+#define T_IDIV0		0x2a	/* divide by zero (from hw [su]div instr) */
+#define T_STOREBUFFAULT	0x2b	/* SuperSPARC: Store buffer copy-back fault */
+/*			0x2c	   unused */
+/*	through		0x7f	   unused */
+
+/* beginning of `user' vectors (from trap instructions) - all priority 12 */
+#define	T_SUN_SYSCALL	0x80	/* system call */
+#define	T_BREAKPOINT	0x81	/* breakpoint `instruction' */
+#define	T_DIV0		0x82	/* division routine was handed 0 */
+#define	T_FLUSHWIN	0x83	/* flush windows */
+#define	T_CLEANWIN	0x84	/* provide clean windows */
+#define	T_RANGECHECK	0x85	/* ? */
+#define	T_FIXALIGN	0x86	/* fix up unaligned accesses */
+#define	T_INTOF		0x87	/* integer overflow ? */
+#define	T_SVR4_SYSCALL	0x88	/* SVR4 system call */
+#define	T_BSD_SYSCALL	0x89	/* BSD system call */
+#define	T_KGDB_EXEC	0x8a	/* for kernel gdb */
+
+/* 0x8b..0xff are currently unallocated, except the following */
+#define T_SVR4_GETCC		0xa0
+#define T_SVR4_SETCC		0xa1
+#define T_SVR4_GETPSR		0xa2
+#define T_SVR4_SETPSR		0xa3
+#define T_SVR4_GETHRTIME	0xa4
+#define T_SVR4_GETHRVTIME	0xa5
+#define T_SVR4_GETHRESTIME	0xa7
+
+#ifdef _KERNEL			/* pseudo traps for locore.s */
+#define	T_RWRET		-1	/* need first user window for trap return */
+#define	T_AST		-2	/* no-op, just needed reschedule or profile */
+#endif
+
+/* flags to system call (flags in %g1 along with syscall number) */
+#define	SYSCALL_G2RFLAG	0x400	/* on success, return to %g2 rather than npc */
+#define	SYSCALL_G7RFLAG	0x800	/* use %g7 as above (deprecated) */
+
+/*
+ * `software trap' macros to keep people happy (sparc v8 manual says not
+ * to set the upper bits).
+ */
+#define	ST_BREAKPOINT	(T_BREAKPOINT & 0x7f)
+#define	ST_DIV0		(T_DIV0 & 0x7f)
+#define	ST_FLUSHWIN	(T_FLUSHWIN & 0x7f)
+#define	ST_SYSCALL	(T_SUN_SYSCALL & 0x7f)
+
+#endif				/* _MACHINE_TRAP_H_ */
diff --git a/usr/include/arch/sparc64/klibc/archconfig.h b/usr/include/arch/sparc64/klibc/archconfig.h
new file mode 100644
index 0000000..bb0c003
--- /dev/null
+++ b/usr/include/arch/sparc64/klibc/archconfig.h
@@ -0,0 +1,15 @@
+/*
+ * include/arch/sparc64/klibc/archconfig.h
+ *
+ * See include/klibc/sysconfig.h for the options that can be set in
+ * this file.
+ *
+ */
+
+#ifndef _KLIBC_ARCHCONFIG_H
+#define _KLIBC_ARCHCONFIG_H
+
+#define _KLIBC_USE_RT_SIG 1	/* Use rt_* signals */
+#define _KLIBC_NEEDS_SA_RESTORER 1 /* Need a restorer function */
+
+#endif				/* _KLIBC_ARCHCONFIG_H */
diff --git a/usr/include/arch/sparc64/klibc/archsetjmp.h b/usr/include/arch/sparc64/klibc/archsetjmp.h
new file mode 100644
index 0000000..9e825bd
--- /dev/null
+++ b/usr/include/arch/sparc64/klibc/archsetjmp.h
@@ -0,0 +1,16 @@
+/*
+ * arch/sparc64/include/klibc/archsetjmp.h
+ */
+
+#ifndef _KLIBC_ARCHSETJMP_H
+#define _KLIBC_ARCHSETJMP_H
+
+struct __jmp_buf {
+	unsigned long __sp;
+	unsigned long __fp;
+	unsigned long __pc;
+};
+
+typedef struct __jmp_buf jmp_buf[1];
+
+#endif				/* _SETJMP_H */
diff --git a/usr/include/arch/sparc64/klibc/archsignal.h b/usr/include/arch/sparc64/klibc/archsignal.h
new file mode 100644
index 0000000..bb0a5ce
--- /dev/null
+++ b/usr/include/arch/sparc64/klibc/archsignal.h
@@ -0,0 +1,17 @@
+/*
+ * arch/sparc64/include/klibc/archsignal.h
+ *
+ * Architecture-specific signal definitions
+ *
+ */
+
+#ifndef _KLIBC_ARCHSIGNAL_H
+#define _KLIBC_ARCHSIGNAL_H
+
+#define __WANT_POSIX1B_SIGNALS__
+#include <asm/signal.h>
+
+/* Not actually used by the kernel... */
+#define SA_RESTORER	0x80000000
+
+#endif
diff --git a/usr/include/arch/sparc64/klibc/archstat.h b/usr/include/arch/sparc64/klibc/archstat.h
new file mode 100644
index 0000000..56fb2a4
--- /dev/null
+++ b/usr/include/arch/sparc64/klibc/archstat.h
@@ -0,0 +1,30 @@
+#ifndef _KLIBC_ARCHSTAT_H
+#define _KLIBC_ARCHSTAT_H
+
+#include <klibc/stathelp.h>
+
+#define _STATBUF_ST_NSEC
+
+struct stat {
+	__stdev64	(st_dev);
+	unsigned long	st_ino;
+	unsigned long	st_nlink;
+
+	unsigned int	st_mode;
+	unsigned int	st_uid;
+	unsigned int	st_gid;
+	unsigned int	__pad0;
+
+	__stdev64 (st_rdev);
+	long		st_size;
+	long		st_blksize;
+	long		st_blocks;
+
+	struct timespec st_atim;
+	struct timespec st_mtim;
+	struct timespec st_ctim;
+
+	unsigned long __unused[3];
+};
+
+#endif
diff --git a/usr/include/arch/x86_64/klibc/archconfig.h b/usr/include/arch/x86_64/klibc/archconfig.h
new file mode 100644
index 0000000..b8a2a6d
--- /dev/null
+++ b/usr/include/arch/x86_64/klibc/archconfig.h
@@ -0,0 +1,15 @@
+/*
+ * include/arch/x86_64/klibc/archconfig.h
+ *
+ * See include/klibc/sysconfig.h for the options that can be set in
+ * this file.
+ *
+ */
+
+#ifndef _KLIBC_ARCHCONFIG_H
+#define _KLIBC_ARCHCONFIG_H
+
+/* x86-64 doesn't provide a default sigreturn. */
+#define _KLIBC_NEEDS_SA_RESTORER 1
+
+#endif				/* _KLIBC_ARCHCONFIG_H */
diff --git a/usr/include/arch/x86_64/klibc/archsetjmp.h b/usr/include/arch/x86_64/klibc/archsetjmp.h
new file mode 100644
index 0000000..454fc60
--- /dev/null
+++ b/usr/include/arch/x86_64/klibc/archsetjmp.h
@@ -0,0 +1,21 @@
+/*
+ * arch/x86_64/include/klibc/archsetjmp.h
+ */
+
+#ifndef _KLIBC_ARCHSETJMP_H
+#define _KLIBC_ARCHSETJMP_H
+
+struct __jmp_buf {
+	unsigned long __rbx;
+	unsigned long __rsp;
+	unsigned long __rbp;
+	unsigned long __r12;
+	unsigned long __r13;
+	unsigned long __r14;
+	unsigned long __r15;
+	unsigned long __rip;
+};
+
+typedef struct __jmp_buf jmp_buf[1];
+
+#endif				/* _SETJMP_H */
diff --git a/usr/include/arch/x86_64/klibc/archsignal.h b/usr/include/arch/x86_64/klibc/archsignal.h
new file mode 100644
index 0000000..6c8ec77
--- /dev/null
+++ b/usr/include/arch/x86_64/klibc/archsignal.h
@@ -0,0 +1,18 @@
+/*
+ * arch/x86_64/include/klibc/archsignal.h
+ *
+ * Architecture-specific signal definitions
+ *
+ */
+
+#ifndef _KLIBC_ARCHSIGNAL_H
+#define _KLIBC_ARCHSIGNAL_H
+
+#include <asm/signal.h>
+/* The x86-64 headers defines NSIG 32, but it's actually 64 */
+#undef  _NSIG
+#undef  NSIG
+#define _NSIG 64
+#define NSIG  _NSIG
+
+#endif
diff --git a/usr/include/arch/x86_64/klibc/archstat.h b/usr/include/arch/x86_64/klibc/archstat.h
new file mode 100644
index 0000000..de168ac
--- /dev/null
+++ b/usr/include/arch/x86_64/klibc/archstat.h
@@ -0,0 +1,28 @@
+#ifndef _KLIBC_ARCHSTAT_H
+#define _KLIBC_ARCHSTAT_H
+
+#include <klibc/stathelp.h>
+
+#define _STATBUF_ST_NSEC
+
+struct stat {
+	__stdev64	(st_dev);
+	unsigned long	st_ino;
+	unsigned long	st_nlink;
+
+	unsigned int	st_mode;
+	unsigned int	st_uid;
+	unsigned int	st_gid;
+	unsigned int	__pad0;
+	__stdev64	(st_rdev);
+	long		st_size;
+	long		st_blksize;
+	long		st_blocks;	/* Number 512-byte blocks allocated. */
+
+	struct timespec st_atim;
+	struct timespec st_mtim;
+	struct timespec st_ctim;
+  	long		__unused[3];
+};
+
+#endif
diff --git a/usr/include/arch/x86_64/sys/io.h b/usr/include/arch/x86_64/sys/io.h
new file mode 100644
index 0000000..2a0ca48
--- /dev/null
+++ b/usr/include/arch/x86_64/sys/io.h
@@ -0,0 +1,127 @@
+/* ----------------------------------------------------------------------- *
+ *
+ *   Copyright 2004 H. Peter Anvin - All Rights Reserved
+ *
+ *   Permission is hereby granted, free of charge, to any person
+ *   obtaining a copy of this software and associated documentation
+ *   files (the "Software"), to deal in the Software without
+ *   restriction, including without limitation the rights to use,
+ *   copy, modify, merge, publish, distribute, sublicense, and/or
+ *   sell copies of the Software, and to permit persons to whom
+ *   the Software is furnished to do so, subject to the following
+ *   conditions:
+ *
+ *   The above copyright notice and this permission notice shall
+ *   be included in all copies or substantial portions of the Software.
+ *
+ *   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ *   EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ *   OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ *   NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ *   HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ *   WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ *   FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ *   OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * ----------------------------------------------------------------------- */
+
+/*
+ * sys/io.h for the i386 architecture
+ *
+ * Basic I/O macros
+ */
+
+#ifndef _SYS_IO_H
+#define _SYS_IO_H 1
+
+/* I/O-related system calls */
+
+int iopl(int);
+int ioperm(unsigned long, unsigned long, int);
+
+/* Basic I/O macros */
+
+static __inline__ void outb(unsigned char __v, unsigned short __p)
+{
+	asm volatile ("outb %0,%1" : : "a" (__v), "dN"(__p));
+}
+
+static __inline__ void outw(unsigned short __v, unsigned short __p)
+{
+	asm volatile ("outw %0,%1" : : "a" (__v), "dN"(__p));
+}
+
+static __inline__ void outl(unsigned int __v, unsigned short __p)
+{
+	asm volatile ("outl %0,%1" : : "a" (__v), "dN"(__p));
+}
+
+static __inline__ unsigned char inb(unsigned short __p)
+{
+	unsigned char __v;
+	asm volatile ("inb %1,%0" : "=a" (__v) : "dN"(__p));
+	return v;
+}
+
+static __inline__ unsigned short inw(unsigned short __p)
+{
+	unsigned short __v;
+	asm volatile ("inw %1,%0" : "=a" (__v) : "dN"(__p));
+	return v;
+}
+
+static __inline__ unsigned int inl(unsigned short __p)
+{
+	unsigned int __v;
+	asm volatile ("inl %1,%0" : "=a" (__v) : "dN"(__p));
+	return v;
+}
+
+/* String I/O macros */
+
+static __inline__ void
+outsb(unsigned short __p, const void *__d, unsigned long __n)
+{
+	asm volatile ("cld; rep; outsb"
+		      : "+S" (__d), "+c"(__n)
+		      : "d"(__p));
+}
+
+static __inline__ void
+outsw(unsigned short __p, const void *__d, unsigned long __n)
+{
+	asm volatile ("cld; rep; outsw"
+		      : "+S" (__d), "+c"(__n)
+		      : "d"(__p));
+}
+
+static __inline__ void
+outsl(unsigned short __p, const void *__d, unsigned long __n)
+{
+	asm volatile ("cld; rep; outsl"
+		      : "+S" (__d), "+c"(__n)
+		      : "d"(__p));
+}
+
+static __inline__ void insb(unsigned short __p, void *__d, unsigned long __n)
+{
+	asm volatile ("cld; rep; insb"
+		      : "+D" (__d), "+c"(__n)
+		      : "d"(__p));
+}
+
+static __inline__ void insw(unsigned short __p, void *__d, unsigned long __n)
+{
+	asm volatile ("cld; rep; insw"
+		      : "+D" (__d), "+c"(__n)
+		      : "d"(__p));
+}
+
+static __inline__ void insl(unsigned short __p, void *__d, unsigned long __n)
+{
+	asm volatile ("cld; rep; insl"
+		      : "+D" (__d), "+c"(__n)
+		      : "d"(__p));
+}
+
+#endif				/* _SYS_IO_H */
diff --git a/usr/include/arpa/inet.h b/usr/include/arpa/inet.h
new file mode 100644
index 0000000..8532f67
--- /dev/null
+++ b/usr/include/arpa/inet.h
@@ -0,0 +1,22 @@
+/*
+ * arpa/inet.h
+ */
+
+#ifndef _ARPA_INET_H
+#define _ARPA_INET_H
+
+#include <klibc/extern.h>
+#include <stdint.h>
+#include <sys/types.h>
+#include <netinet/in.h>
+#include <netinet/in6.h>
+
+__extern uint32_t inet_addr(const char *);
+__extern int inet_aton(const char *, struct in_addr *);
+__extern char *inet_ntoa(struct in_addr);
+__extern int inet_pton(int, const char *, void *);
+__extern const char *inet_ntop(int, const void *, char *, size_t);
+__extern unsigned int inet_nsap_addr(const char *, unsigned char *, int);
+__extern char *inet_nsap_ntoa(int, const unsigned char *, char *);
+
+#endif				/* _ARPA_INET_H */
diff --git a/usr/include/assert.h b/usr/include/assert.h
new file mode 100644
index 0000000..d89e082
--- /dev/null
+++ b/usr/include/assert.h
@@ -0,0 +1,22 @@
+/*
+ * assert.h
+ */
+
+#ifndef _ASSERT_H
+#define _ASSERT_H
+
+#include <klibc/compiler.h>
+
+#ifdef NDEBUG
+
+#define assert(x) ((void)(x))
+
+#else
+
+extern __noreturn __assert_fail(const char *, const char *, unsigned int);
+
+#define assert(x) ((x) ? (void)0 : __assert_fail(#x, __FILE__, __LINE__))
+
+#endif
+
+#endif				/* _ASSERT_H */
diff --git a/usr/include/bits32/bitsize.h b/usr/include/bits32/bitsize.h
new file mode 100644
index 0000000..06cc885
--- /dev/null
+++ b/usr/include/bits32/bitsize.h
@@ -0,0 +1,3 @@
+#ifndef _BITSIZE
+#define _BITSIZE 32
+#endif
diff --git a/usr/include/bits32/bitsize/limits.h b/usr/include/bits32/bitsize/limits.h
new file mode 100644
index 0000000..8eb97d6
--- /dev/null
+++ b/usr/include/bits32/bitsize/limits.h
@@ -0,0 +1,14 @@
+/*
+ * bits32/limits.h
+ */
+
+#ifndef _BITSIZE_LIMITS_H
+#define _BITSIZE_LIMITS_H
+
+#define LONG_BIT	32
+
+#define LONG_MIN	(-2147483647L-1)
+#define LONG_MAX	2147483647L
+#define ULONG_MAX	4294967295UL
+
+#endif				/* _BITSIZE_LIMITS_H */
diff --git a/usr/include/bits32/bitsize/stddef.h b/usr/include/bits32/bitsize/stddef.h
new file mode 100644
index 0000000..43d733c
--- /dev/null
+++ b/usr/include/bits32/bitsize/stddef.h
@@ -0,0 +1,18 @@
+/*
+ * bits32/stddef.h
+ */
+
+#ifndef _BITSIZE_STDDEF_H
+#define _BITSIZE_STDDEF_H
+
+#define _SIZE_T
+#if defined(__s390__) || defined(__cris__)
+typedef unsigned long size_t;
+#else
+typedef unsigned int size_t;
+#endif
+
+#define _PTRDIFF_T
+typedef signed int ptrdiff_t;
+
+#endif				/* _BITSIZE_STDDEF_H */
diff --git a/usr/include/bits32/bitsize/stdint.h b/usr/include/bits32/bitsize/stdint.h
new file mode 100644
index 0000000..8e444b6
--- /dev/null
+++ b/usr/include/bits32/bitsize/stdint.h
@@ -0,0 +1,34 @@
+/*
+ * bits32/stdint.h
+ */
+
+#ifndef _BITSIZE_STDINT_H
+#define _BITSIZE_STDINT_H
+
+typedef signed char		int8_t;
+typedef short int		int16_t;
+typedef int			int32_t;
+typedef long long int		int64_t;
+
+typedef unsigned char		uint8_t;
+typedef unsigned short int	uint16_t;
+typedef unsigned int		uint32_t;
+typedef unsigned long long int	uint64_t;
+
+typedef int			int_fast16_t;
+typedef int			int_fast32_t;
+
+typedef unsigned int		uint_fast16_t;
+typedef unsigned int		uint_fast32_t;
+
+typedef int			intptr_t;
+typedef unsigned int		uintptr_t;
+
+#define __INT64_C(c)   c ## LL
+#define __UINT64_C(c)  c ## ULL
+
+#define __PRI64_RANK   "ll"
+#define __PRIFAST_RANK ""
+#define __PRIPTR_RANK  ""
+
+#endif				/* _BITSIZE_STDINT_H */
diff --git a/usr/include/bits32/bitsize/stdintconst.h b/usr/include/bits32/bitsize/stdintconst.h
new file mode 100644
index 0000000..7db63bd
--- /dev/null
+++ b/usr/include/bits32/bitsize/stdintconst.h
@@ -0,0 +1,18 @@
+/*
+ * bits32/stdintconst.h
+ */
+
+#ifndef _BITSIZE_STDINTCONST_H
+#define _BITSIZE_STDINTCONST_H
+
+#define INT_FAST16_C(c)	 INT32_C(c)
+#define INT_FAST32_C(c)  INT32_C(c)
+
+#define UINT_FAST16_C(c) UINT32_C(c)
+#define UINT_FAST32_C(c) UINT32_C(c)
+
+#define INTPTR_C(c)	 INT32_C(c)
+#define UINTPTR_C(c)	 UINT32_C(c)
+#define PTRDIFF_C(c)     INT32_C(c)
+
+#endif				/* _BITSIZE_STDINTCONST_H */
diff --git a/usr/include/bits32/bitsize/stdintlimits.h b/usr/include/bits32/bitsize/stdintlimits.h
new file mode 100644
index 0000000..d85094d
--- /dev/null
+++ b/usr/include/bits32/bitsize/stdintlimits.h
@@ -0,0 +1,22 @@
+/*
+ * bits32/stdintlimits.h
+ */
+
+#ifndef _BITSIZE_STDINTLIMITS_H
+#define _BITSIZE_STDINTLIMITS_H
+
+#define INT_FAST16_MIN	INT32_MIN
+#define INT_FAST32_MIN	INT32_MIN
+#define INT_FAST16_MAX	INT32_MAX
+#define INT_FAST32_MAX	INT32_MAX
+#define UINT_FAST16_MAX UINT32_MAX
+#define UINT_FAST32_MAX UINT32_MAX
+
+#define INTPTR_MIN	INT32_MIN
+#define INTPTR_MAX	INT32_MAX
+#define UINTPTR_MAX	UINT32_MAX
+
+#define PTRDIFF_MIN	INT32_MIN
+#define PTRDIFF_MAX	INT32_MAX
+
+#endif				/* _BITSIZE_STDINTLIMITS_H */
diff --git a/usr/include/bits64/bitsize.h b/usr/include/bits64/bitsize.h
new file mode 100644
index 0000000..54696fd
--- /dev/null
+++ b/usr/include/bits64/bitsize.h
@@ -0,0 +1,3 @@
+#ifndef _BITSIZE
+#define _BITSIZE 64
+#endif
diff --git a/usr/include/bits64/bitsize/limits.h b/usr/include/bits64/bitsize/limits.h
new file mode 100644
index 0000000..f5bbf83
--- /dev/null
+++ b/usr/include/bits64/bitsize/limits.h
@@ -0,0 +1,14 @@
+/*
+ * bits64/limits.h
+ */
+
+#ifndef _BITSIZE_LIMITS_H
+#define _BITSIZE_LIMITS_H
+
+#define LONG_BIT	64
+
+#define LONG_MIN	(-9223372036854775807L-1)
+#define LONG_MAX	9223372036854775807L
+#define ULONG_MAX	18446744073709551615UL
+
+#endif				/* _BITSIZE_LIMITS_H */
diff --git a/usr/include/bits64/bitsize/stddef.h b/usr/include/bits64/bitsize/stddef.h
new file mode 100644
index 0000000..1e942a1
--- /dev/null
+++ b/usr/include/bits64/bitsize/stddef.h
@@ -0,0 +1,13 @@
+/*
+ * bits64/stddef.h
+ */
+
+#ifndef _BITSIZE_STDDEF_H
+#define _BITSIZE_STDDEF_H
+
+#define _SIZE_T
+typedef unsigned long size_t;
+#define _PTRDIFF_T
+typedef signed long ptrdiff_t;
+
+#endif				/* _BITSIZE_STDDEF_H */
diff --git a/usr/include/bits64/bitsize/stdint.h b/usr/include/bits64/bitsize/stdint.h
new file mode 100644
index 0000000..988e639
--- /dev/null
+++ b/usr/include/bits64/bitsize/stdint.h
@@ -0,0 +1,34 @@
+/*
+ * bits64/stdint.h
+ */
+
+#ifndef _BITSIZE_STDINT_H
+#define _BITSIZE_STDINT_H
+
+typedef signed char		int8_t;
+typedef short int		int16_t;
+typedef int			int32_t;
+typedef long int		int64_t;
+
+typedef unsigned char		uint8_t;
+typedef unsigned short int	uint16_t;
+typedef unsigned int		uint32_t;
+typedef unsigned long int	uint64_t;
+
+typedef long int		int_fast16_t;
+typedef long int		int_fast32_t;
+
+typedef unsigned long int	uint_fast16_t;
+typedef unsigned long int	uint_fast32_t;
+
+typedef long int		intptr_t;
+typedef unsigned long int	uintptr_t;
+
+#define __INT64_C(c)  c ## L
+#define __UINT64_C(c) c ## UL
+
+#define __PRI64_RANK	"l"
+#define __PRIFAST_RANK  "l"
+#define __PRIPTR_RANK	"l"
+
+#endif				/* _BITSIZE_STDINT_H */
diff --git a/usr/include/bits64/bitsize/stdintconst.h b/usr/include/bits64/bitsize/stdintconst.h
new file mode 100644
index 0000000..24e8eb6
--- /dev/null
+++ b/usr/include/bits64/bitsize/stdintconst.h
@@ -0,0 +1,18 @@
+/*
+ * bits64/stdintconst.h
+ */
+
+#ifndef _BITSIZE_STDINTCONST_H
+#define _BITSIZE_STDINTCONST_H
+
+#define INT_FAST16_C(c)	 INT64_C(c)
+#define INT_FAST32_C(c)  INT64_C(c)
+
+#define UINT_FAST16_C(c) UINT64_C(c)
+#define UINT_FAST32_C(c) UINT64_C(c)
+
+#define INTPTR_C(c)	 INT64_C(c)
+#define UINTPTR_C(c)	 UINT64_C(c)
+#define PTRDIFF_C(c)     INT64_C(c)
+
+#endif				/* _BITSIZE_STDINTCONST_H */
diff --git a/usr/include/bits64/bitsize/stdintlimits.h b/usr/include/bits64/bitsize/stdintlimits.h
new file mode 100644
index 0000000..805d5b8
--- /dev/null
+++ b/usr/include/bits64/bitsize/stdintlimits.h
@@ -0,0 +1,22 @@
+/*
+ * bits64/stdintlimits.h
+ */
+
+#ifndef _BITSIZE_STDINTLIMITS_H
+#define _BITSIZE_STDINTLIMITS_H
+
+#define INT_FAST16_MIN	INT64_MIN
+#define INT_FAST32_MIN	INT64_MIN
+#define INT_FAST16_MAX	INT64_MAX
+#define INT_FAST32_MAX	INT64_MAX
+#define UINT_FAST16_MAX UINT64_MAX
+#define UINT_FAST32_MAX UINT64_MAX
+
+#define INTPTR_MIN	INT64_MIN
+#define INTPTR_MAX	INT64_MAX
+#define UINTPTR_MAX	UINT64_MAX
+
+#define PTRDIFF_MIN	INT64_MIN
+#define PTRDIFF_MAX	INT64_MAX
+
+#endif				/* _BITSIZE_STDINTLIMITS_H */
diff --git a/usr/include/byteswap.h b/usr/include/byteswap.h
new file mode 100644
index 0000000..6f41a28
--- /dev/null
+++ b/usr/include/byteswap.h
@@ -0,0 +1,15 @@
+/*
+ * byteswap.h
+ */
+
+#ifndef _BYTESWAP_H
+#define _BYTESWAP_H
+
+#include <klibc/compiler.h>
+#include <asm/byteorder.h>
+
+#define bswap_16(x) __swab16(x)
+#define bswap_32(x) __swab32(x)
+#define bswap_64(x) __swab64(x)
+
+#endif				/* _BYTESWAP_H */
diff --git a/usr/include/ctype.h b/usr/include/ctype.h
new file mode 100644
index 0000000..670aec9
--- /dev/null
+++ b/usr/include/ctype.h
@@ -0,0 +1,140 @@
+/*
+ * ctype.h
+ *
+ * This assumes ISO 8859-1, being a reasonable superset of ASCII.
+ */
+
+#ifndef _CTYPE_H
+#define _CTYPE_H
+
+#include <klibc/extern.h>
+
+/*
+ * This relies on the following definitions:
+ *
+ * cntrl = !print
+ * alpha = upper|lower
+ * graph = punct|alpha|digit
+ * blank = '\t' || ' ' (per POSIX requirement)
+ */
+enum {
+	__ctype_upper = (1 << 0),
+	__ctype_lower = (1 << 1),
+	__ctype_digit = (1 << 2),
+	__ctype_xdigit = (1 << 3),
+	__ctype_space = (1 << 4),
+	__ctype_print = (1 << 5),
+	__ctype_punct = (1 << 6),
+	__ctype_cntrl = (1 << 7),
+};
+
+extern const unsigned char __ctypes[];
+
+static inline int __ctype_isalnum(int __c)
+{
+	return __ctypes[__c + 1] &
+	    (__ctype_upper | __ctype_lower | __ctype_digit);
+}
+
+static inline int __ctype_isalpha(int __c)
+{
+	return __ctypes[__c + 1] & (__ctype_upper | __ctype_lower);
+}
+
+static inline int __ctype_isascii(int __c)
+{
+	return !(__c & ~0x7f);
+}
+
+static inline int __ctype_isblank(int __c)
+{
+	return (__c == '\t') || (__c == ' ');
+}
+
+static inline int __ctype_iscntrl(int __c)
+{
+	return __ctypes[__c + 1] & __ctype_cntrl;
+}
+
+static inline int __ctype_isdigit(int __c)
+{
+	return ((unsigned)__c - '0') <= 9;
+}
+
+static inline int __ctype_isgraph(int __c)
+{
+	return __ctypes[__c + 1] &
+	    (__ctype_upper | __ctype_lower | __ctype_digit | __ctype_punct);
+}
+
+static inline int __ctype_islower(int __c)
+{
+	return __ctypes[__c + 1] & __ctype_lower;
+}
+
+static inline int __ctype_isprint(int __c)
+{
+	return __ctypes[__c + 1] & __ctype_print;
+}
+
+static inline int __ctype_ispunct(int __c)
+{
+	return __ctypes[__c + 1] & __ctype_punct;
+}
+
+static inline int __ctype_isspace(int __c)
+{
+	return __ctypes[__c + 1] & __ctype_space;
+}
+
+static inline int __ctype_isupper(int __c)
+{
+	return __ctypes[__c + 1] & __ctype_upper;
+}
+
+static inline int __ctype_isxdigit(int __c)
+{
+	return __ctypes[__c + 1] & __ctype_xdigit;
+}
+
+/* Note: this is decimal, not hex, to avoid accidental promotion to unsigned */
+#define _toupper(__c) ((__c) & ~32)
+#define _tolower(__c) ((__c) | 32)
+
+static inline int __ctype_toupper(int __c)
+{
+	return __ctype_islower(__c) ? _toupper(__c) : __c;
+}
+
+static inline int __ctype_tolower(int __c)
+{
+	return __ctype_isupper(__c) ? _tolower(__c) : __c;
+}
+
+#ifdef __CTYPE_NO_INLINE
+# define __CTYPEFUNC(X) \
+  __extern int X(int);
+#else
+#define __CTYPEFUNC(X) \
+  __extern inline int X(int __c)		\
+  {						\
+    return __ctype_##X(__c); 			\
+  }
+#endif
+
+__CTYPEFUNC(isalnum)
+    __CTYPEFUNC(isalpha)
+    __CTYPEFUNC(isascii)
+    __CTYPEFUNC(isblank)
+    __CTYPEFUNC(iscntrl)
+    __CTYPEFUNC(isdigit)
+    __CTYPEFUNC(isgraph)
+    __CTYPEFUNC(islower)
+    __CTYPEFUNC(isprint)
+    __CTYPEFUNC(ispunct)
+    __CTYPEFUNC(isspace)
+    __CTYPEFUNC(isupper)
+    __CTYPEFUNC(isxdigit)
+    __CTYPEFUNC(toupper)
+    __CTYPEFUNC(tolower)
+#endif				/* _CTYPE_H */
diff --git a/usr/include/dirent.h b/usr/include/dirent.h
new file mode 100644
index 0000000..e324474
--- /dev/null
+++ b/usr/include/dirent.h
@@ -0,0 +1,33 @@
+/*
+ * dirent.h
+ */
+
+#ifndef _DIRENT_H
+#define _DIRENT_H
+
+#include <klibc/extern.h>
+#include <sys/dirent.h>
+
+struct _IO_dir {
+	int __fd;
+
+#ifdef __KLIBC_DIRENT_INTERNALS
+	/* These fields for internal use only */
+
+	size_t bytes_left;
+	struct dirent *next;
+	/* Declaring this as an array of struct enforces correct alignment */
+	struct dirent buffer[15];	/* 15 times max dirent size =~ 4K */
+#endif
+};
+typedef struct _IO_dir DIR;
+
+__extern DIR *opendir(const char *);
+__extern struct dirent *readdir(DIR *);
+__extern int closedir(DIR *);
+static __inline__ int dirfd(DIR * __d)
+{
+	return __d->__fd;
+}
+
+#endif				/* _DIRENT_H */
diff --git a/usr/include/elf.h b/usr/include/elf.h
new file mode 100644
index 0000000..c543a81
--- /dev/null
+++ b/usr/include/elf.h
@@ -0,0 +1,11 @@
+/*
+ * elf.h
+ */
+
+#ifndef _ELF_H
+#define _ELF_H
+
+#include <sys/elf32.h>
+#include <sys/elf64.h>
+
+#endif				/* _ELF_H */
diff --git a/usr/include/endian.h b/usr/include/endian.h
new file mode 100644
index 0000000..a6cd6d9
--- /dev/null
+++ b/usr/include/endian.h
@@ -0,0 +1,15 @@
+/*
+ * endian.h
+ */
+
+#ifndef _ENDIAN_H
+#define _ENDIAN_H
+
+#include <klibc/endian.h>
+
+#define LITTLE_ENDIAN	__LITTLE_ENDIAN
+#define BIG_ENDIAN	__BIG_ENDIAN
+#define PDP_ENDIAN	__PDP_ENDIAN
+#define BYTE_ORDER	__BYTE_ORDER
+
+#endif				/* _ENDIAN_H */
diff --git a/usr/include/errno.h b/usr/include/errno.h
new file mode 100644
index 0000000..d8e20bd
--- /dev/null
+++ b/usr/include/errno.h
@@ -0,0 +1,13 @@
+/*
+ * errno.h
+ */
+
+#ifndef _ERRNO_H
+#define _ERRNO_H
+
+#include <klibc/extern.h>
+#include <asm/errno.h>
+
+__extern int errno;
+
+#endif /* _ERRNO_H */
diff --git a/usr/include/fcntl.h b/usr/include/fcntl.h
new file mode 100644
index 0000000..0908e21
--- /dev/null
+++ b/usr/include/fcntl.h
@@ -0,0 +1,46 @@
+/*
+ * fcntl.h
+ */
+
+#ifndef _FCNTL_H
+#define _FCNTL_H
+
+#include <klibc/extern.h>
+#include <klibc/compiler.h>
+#include <sys/types.h>
+#if defined(__mips__) && !defined(__mips64__)
+# include <klibc/archfcntl.h>
+#endif
+#include <linux/fcntl.h>
+
+/* This is ugly, but "struct flock" has actually been defined with
+   a long off_t, so it's really "struct flock64".  It just happens
+   to work.  Gag.  Barf.
+
+   This happens to work on all 32-bit architectures except MIPS. */
+
+#ifdef F_GETLK64
+# undef F_GETLK
+# define F_GETLK F_GETLK64
+#endif
+
+#ifdef F_SETLK64
+# undef F_SETLK
+# define F_SETLK F_SETLK64
+#endif
+
+#ifdef F_SETLKW64
+# undef F_SETLKW
+# define F_SETLKW F_SETLKW64
+#endif
+
+/* This is defined here as well as in <unistd.h> */
+#ifndef _KLIBC_IN_OPEN_C
+__extern int open(const char *, int, ...);
+__extern int openat(int, const char *, int, ...);
+#endif
+
+__extern int creat(const char *, mode_t);
+__extern int fcntl(int, int, ...);
+
+#endif				/* _FCNTL_H */
diff --git a/usr/include/fnmatch.h b/usr/include/fnmatch.h
new file mode 100644
index 0000000..0d88140
--- /dev/null
+++ b/usr/include/fnmatch.h
@@ -0,0 +1,15 @@
+#ifndef _FNMATCH_H
+#define _FNMATCH_H
+
+#include <klibc/extern.h>
+
+#define FNM_NOMATCH		1
+
+#define FNM_PATHNAME		1
+#define FNM_FILE_NAME		FNM_PATHNAME
+#define FNM_NOESCAPE		2
+#define FNM_PERIOD		4
+
+__extern int fnmatch(const char *, const char *, int);
+
+#endif /* _FNMATCH_H */
diff --git a/usr/include/getopt.h b/usr/include/getopt.h
new file mode 100644
index 0000000..71c41cd
--- /dev/null
+++ b/usr/include/getopt.h
@@ -0,0 +1,22 @@
+#ifndef _GETOPT_H
+#define _GETOPT_H
+
+#include <klibc/extern.h>
+
+struct option {
+	const char *name;
+	int has_arg;
+	int *flag;
+	int val;
+};
+
+enum {
+	no_argument	  = 0,
+	required_argument = 1,
+	optional_argument = 2,
+};
+
+__extern int getopt_long(int, char *const *, const char *,
+			 const struct option *, int *);
+
+#endif /* _GETOPT_H */
diff --git a/usr/include/grp.h b/usr/include/grp.h
new file mode 100644
index 0000000..88bf79e
--- /dev/null
+++ b/usr/include/grp.h
@@ -0,0 +1,20 @@
+/*
+ * grp.h
+ */
+
+#ifndef _GRP_H
+#define _GRP_H
+
+#include <klibc/extern.h>
+#include <sys/types.h>
+
+struct group {
+	char *gr_name;
+	char *gr_passwd;
+	gid_t gr_gid;
+	char **gr_mem;
+};
+
+__extern int setgroups(size_t, const gid_t *);
+
+#endif				/* _GRP_H */
diff --git a/usr/include/inttypes.h b/usr/include/inttypes.h
new file mode 100644
index 0000000..29311fe
--- /dev/null
+++ b/usr/include/inttypes.h
@@ -0,0 +1,226 @@
+/*
+ * inttypes.h
+ */
+
+#ifndef _INTTYPES_H
+#define _INTTYPES_H
+
+#include <klibc/extern.h>
+#include <stdint.h>
+#include <stddef.h>
+
+static __inline__ intmax_t imaxabs(intmax_t __n)
+{
+	return (__n < (intmax_t) 0) ? -__n : __n;
+}
+
+__extern intmax_t strtoimax(const char *, char **, int);
+__extern uintmax_t strtoumax(const char *, char **, int);
+
+/* extensions */
+__extern intmax_t strntoimax(const char *, char **, int, size_t);
+__extern uintmax_t strntoumax(const char *, char **, int, size_t);
+
+#if !defined(__cplusplus) || defined(__STDC_FORMAT_MACROS)
+
+#define PRId8	"d"
+#define PRId16	"d"
+#define PRId32	"d"
+#define PRId64	__PRI64_RANK "d"
+
+#define PRIdLEAST8	"d"
+#define PRIdLEAST16	"d"
+#define PRIdLEAST32	"d"
+#define PRIdLEAST64	__PRI64_RANK "d"
+
+#define PRIdFAST8	"d"
+#define PRIdFAST16	__PRIFAST_RANK "d"
+#define PRIdFAST32	__PRIFAST_RANK "d"
+#define PRIdFAST64	__PRI64_RANK "d"
+
+#define PRIdMAX	 __PRI64_RANK "d"
+#define PRIdPTR  __PRIPTR_RANK "d"
+
+#define PRIi8	"i"
+#define PRIi16	"i"
+#define PRIi32	"i"
+#define PRIi64	__PRI64_RANK "i"
+
+#define PRIiLEAST8	"i"
+#define PRIiLEAST16	"i"
+#define PRIiLEAST32	"i"
+#define PRIiLEAST64	__PRI64_RANK "i"
+
+#define PRIiFAST8	"i"
+#define PRIiFAST16	__PRIFAST_RANK "i"
+#define PRIiFAST32	__PRIFAST_RANK "i"
+#define PRIiFAST64	__PRI64_RANK "i"
+
+#define PRIiMAX	 __PRI64_RANK "i"
+#define PRIiPTR  __PRIPTR_RANK "i"
+
+#define PRIo8	"o"
+#define PRIo16	"o"
+#define PRIo32	"o"
+#define PRIo64	__PRI64_RANK "o"
+
+#define PRIoLEAST8	"o"
+#define PRIoLEAST16	"o"
+#define PRIoLEAST32	"o"
+#define PRIoLEAST64	__PRI64_RANK "o"
+
+#define PRIoFAST8	"o"
+#define PRIoFAST16	__PRIFAST_RANK "o"
+#define PRIoFAST32	__PRIFAST_RANK "o"
+#define PRIoFAST64	__PRI64_RANK "o"
+
+#define PRIoMAX	 __PRI64_RANK "o"
+#define PRIoPTR  __PRIPTR_RANK "o"
+
+#define PRIu8	"u"
+#define PRIu16	"u"
+#define PRIu32	"u"
+#define PRIu64	__PRI64_RANK "u"
+
+#define PRIuLEAST8	"u"
+#define PRIuLEAST16	"u"
+#define PRIuLEAST32	"u"
+#define PRIuLEAST64	__PRI64_RANK "u"
+
+#define PRIuFAST8	"u"
+#define PRIuFAST16	__PRIFAST_RANK "u"
+#define PRIuFAST32	__PRIFAST_RANK "u"
+#define PRIuFAST64	__PRI64_RANK "u"
+
+#define PRIuMAX	 __PRI64_RANK "u"
+#define PRIuPTR  __PRIPTR_RANK "u"
+
+#define PRIx8	"x"
+#define PRIx16	"x"
+#define PRIx32	"x"
+#define PRIx64	__PRI64_RANK "x"
+
+#define PRIxLEAST8	"x"
+#define PRIxLEAST16	"x"
+#define PRIxLEAST32	"x"
+#define PRIxLEAST64	__PRI64_RANK "x"
+
+#define PRIxFAST8	"x"
+#define PRIxFAST16	__PRIFAST_RANK "x"
+#define PRIxFAST32	__PRIFAST_RANK "x"
+#define PRIxFAST64	__PRI64_RANK "x"
+
+#define PRIxMAX	 __PRI64_RANK "x"
+#define PRIxPTR  __PRIPTR_RANK "x"
+
+#define PRIX8	"X"
+#define PRIX16	"X"
+#define PRIX32	"X"
+#define PRIX64	__PRI64_RANK "X"
+
+#define PRIXLEAST8	"X"
+#define PRIXLEAST16	"X"
+#define PRIXLEAST32	"X"
+#define PRIXLEAST64	__PRI64_RANK "X"
+
+#define PRIXFAST8	"X"
+#define PRIXFAST16	__PRIFAST_RANK "X"
+#define PRIXFAST32	__PRIFAST_RANK "X"
+#define PRIXFAST64	__PRI64_RANK "X"
+
+#define PRIXMAX	 __PRI64_RANK "X"
+#define PRIXPTR  __PRIPTR_RANK "X"
+
+#define SCNd8	"hhd"
+#define SCNd16	"hd"
+#define SCNd32	"d"
+#define SCNd64	__PRI64_RANK "d"
+
+#define SCNdLEAST8	"hhd"
+#define SCNdLEAST16	"hd"
+#define SCNdLEAST32	"d"
+#define SCNdLEAST64	__PRI64_RANK "d"
+
+#define SCNdFAST8	"hhd"
+#define SCNdFAST16	__PRIFAST_RANK "d"
+#define SCNdFAST32	__PRIFAST_RANK "d"
+#define SCNdFAST64	__PRI64_RANK "d"
+
+#define SCNdMAX	 __PRI64_RANK "d"
+#define SCNdPTR  __PRIPTR_RANK "d"
+
+#define SCNi8	"hhi"
+#define SCNi16	"hi"
+#define SCNi32	"i"
+#define SCNi64	__PRI64_RANK "i"
+
+#define SCNiLEAST8	"hhi"
+#define SCNiLEAST16	"hi"
+#define SCNiLEAST32	"i"
+#define SCNiLEAST64	__PRI64_RANK "i"
+
+#define SCNiFAST8	"hhi"
+#define SCNiFAST16	__PRIFAST_RANK "i"
+#define SCNiFAST32	__PRIFAST_RANK "i"
+#define SCNiFAST64	__PRI64_RANK "i"
+
+#define SCNiMAX	 __PRI64_RANK "i"
+#define SCNiPTR  __PRIPTR_RANK "i"
+
+#define SCNo8	"hho"
+#define SCNo16	"ho"
+#define SCNo32	"o"
+#define SCNo64	__PRI64_RANK "o"
+
+#define SCNoLEAST8	"hho"
+#define SCNoLEAST16	"ho"
+#define SCNoLEAST32	"o"
+#define SCNoLEAST64	__PRI64_RANK "o"
+
+#define SCNoFAST8	"hho"
+#define SCNoFAST16	__PRIFAST_RANK "o"
+#define SCNoFAST32	__PRIFAST_RANK "o"
+#define SCNoFAST64	__PRI64_RANK "o"
+
+#define SCNoMAX	 __PRI64_RANK "o"
+#define SCNoPTR  __PRIPTR_RANK "o"
+
+#define SCNu8	"hhu"
+#define SCNu16	"hu"
+#define SCNu32	"u"
+#define SCNu64	__PRI64_RANK "u"
+
+#define SCNuLEAST8	"hhu"
+#define SCNuLEAST16	"hu"
+#define SCNuLEAST32	"u"
+#define SCNuLEAST64	__PRI64_RANK "u"
+
+#define SCNuFAST8	"hhu"
+#define SCNuFAST16	__PRIFAST_RANK "u"
+#define SCNuFAST32	__PRIFAST_RANK "u"
+#define SCNuFAST64	__PRI64_RANK "u"
+
+#define SCNuMAX	 __PRI64_RANK "u"
+#define SCNuPTR  __PRIPTR_RANK "u"
+
+#define SCNx8	"hhx"
+#define SCNx16	"hx"
+#define SCNx32	"x"
+#define SCNx64	__PRI64_RANK "x"
+
+#define SCNxLEAST8	"hhx"
+#define SCNxLEAST16	"hx"
+#define SCNxLEAST32	"x"
+#define SCNxLEAST64	__PRI64_RANK "x"
+
+#define SCNxFAST8	"hhx"
+#define SCNxFAST16	__PRIFAST_RANK "x"
+#define SCNxFAST32	__PRIFAST_RANK "x"
+#define SCNxFAST64	__PRI64_RANK "x"
+
+#define SCNxMAX	 __PRI64_RANK "x"
+#define SCNxPTR  __PRIPTR_RANK "x"
+
+#endif
+
+#endif				/* _INTTYPES_H */
diff --git a/usr/include/klibc/compiler.h b/usr/include/klibc/compiler.h
new file mode 100644
index 0000000..d566234
--- /dev/null
+++ b/usr/include/klibc/compiler.h
@@ -0,0 +1,130 @@
+/*
+ * klibc/compiler.h
+ *
+ * Various compiler features
+ */
+
+#ifndef _KLIBC_COMPILER_H
+#define _KLIBC_COMPILER_H
+
+/* Specific calling conventions */
+/* __cdecl is used when we want varadic and non-varadic functions to have
+   the same binary calling convention. */
+#ifdef __i386__
+# ifdef __GNUC__
+#  define __cdecl __attribute__((cdecl,regparm(0)))
+# else
+  /* Most other C compilers have __cdecl as a keyword */
+# endif
+#else
+# define __cdecl		/* Meaningless on non-i386 */
+#endif
+
+/* How to declare a function that *must* be inlined */
+#ifdef __GNUC__
+# if __GNUC__ >= 3
+#  define __must_inline static __inline__ __attribute__((always_inline))
+# else
+#  define __must_inline extern __inline__
+# endif
+#else
+# define __must_inline inline	/* Just hope this works... */
+#endif
+
+/* How to declare a function that does not return */
+#ifdef __GNUC__
+# define __noreturn void __attribute__((noreturn))
+#else
+# define __noreturn void
+#endif
+
+/* "const" function:
+
+     Many functions do not examine any values except their arguments,
+     and have no effects except the return value.  Basically this is
+     just slightly more strict class than the `pure' attribute above,
+     since function is not allowed to read global memory.
+
+     Note that a function that has pointer arguments and examines the
+     data pointed to must _not_ be declared `const'.  Likewise, a
+     function that calls a non-`const' function usually must not be
+     `const'.  It does not make sense for a `const' function to return
+     `void'.
+*/
+#ifdef __GNUC__
+# define __constfunc __attribute__((const))
+#else
+# define __constfunc
+#endif
+#undef __attribute_const__
+#define __attribute_const__ __constfunc
+
+/* "pure" function:
+
+     Many functions have no effects except the return value and their
+     return value depends only on the parameters and/or global
+     variables.  Such a function can be subject to common subexpression
+     elimination and loop optimization just as an arithmetic operator
+     would be.  These functions should be declared with the attribute
+     `pure'.
+*/
+#ifdef __GNUC__
+# define __purefunc __attribute__((pure))
+#else
+# define __purefunc
+#endif
+#undef __attribute_pure__
+#define __attribute_pure__ __purefunc
+
+/* Format attribute */
+#ifdef __GNUC__
+# define __formatfunc(t,f,a) __attribute__((format(t,f,a)))
+#else
+# define __formatfunc(t,f,a)
+#endif
+
+/* malloc() function (returns unaliased pointer) */
+#if defined(__GNUC__) && (__GNUC__ >= 3)
+# define __mallocfunc __attribute__((malloc))
+#else
+# define __mallocfunc
+#endif
+
+/* likely/unlikely */
+#if defined(__GNUC__) && (__GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 95))
+# define __likely(x)   __builtin_expect((x), 1)
+# define __unlikely(x) __builtin_expect((x), 0)
+#else
+# define __likely(x)   (x)
+# define __unlikely(x) (x)
+#endif
+
+/* Possibly unused function */
+#ifdef __GNUC__
+# define __unusedfunc	__attribute__((unused))
+#else
+# define __unusedfunc
+#endif
+
+/* It's all user space... */
+#define __user
+
+/* The bitwise attribute: disallow arithmetric operations */
+#ifdef __CHECKER__		/* sparse only */
+# define __bitwise	__attribute__((bitwise))
+#else
+# define __bitwise
+#endif
+
+/* Shut up unused warnings */
+#ifdef __GNUC__
+# define __attribute_used__ __attribute__((used))
+#else
+# define __attribute_used__
+#endif
+
+/* Compiler pragma to make an alias symbol */
+#define __ALIAS(__t, __f, __p, __a) \
+  __t __f __p __attribute__((weak, alias(#__a)));
+
+#endif
diff --git a/usr/include/klibc/diverr.h b/usr/include/klibc/diverr.h
new file mode 100644
index 0000000..e70887e
--- /dev/null
+++ b/usr/include/klibc/diverr.h
@@ -0,0 +1,15 @@
+/*
+ * klibc/diverr.h
+ */
+
+#ifndef _KLIBC_DIVERR_H
+#define _KLIBC_DIVERR_H
+
+#include <signal.h>
+
+static __inline__ void __divide_error(void)
+{
+	raise(SIGFPE);
+}
+
+#endif				/* _KLIBC_DIVERR_H */
diff --git a/usr/include/klibc/endian.h b/usr/include/klibc/endian.h
new file mode 100644
index 0000000..99563de
--- /dev/null
+++ b/usr/include/klibc/endian.h
@@ -0,0 +1,39 @@
+/*
+ * klibc/endian.h
+ *
+ * Like <endian.h>, but export only double-underscore symbols
+ */
+
+#ifndef _KLIBC_ENDIAN_H
+#define _KLIBC_ENDIAN_H
+
+#include <klibc/compiler.h>
+#include <asm/byteorder.h>
+
+/* Linux' asm/byteorder.h defines either __LITTLE_ENDIAN or
+   __BIG_ENDIAN, but the glibc/BSD-ish macros expect both to be
+   defined with __BYTE_ORDER defining which is actually used... */
+
+#if defined(__LITTLE_ENDIAN)
+# undef  __LITTLE_ENDIAN
+# define __LITTLE_ENDIAN 1234
+# define __BIG_ENDIAN    4321
+# define __PDP_ENDIAN    3412
+# define __BYTE_ORDER    __LITTLE_ENDIAN
+#elif defined(__BIG_ENDIAN)
+# undef  __BIG_ENDIAN
+# define __LITTLE_ENDIAN 1234
+# define __BIG_ENDIAN    4321
+# define __PDP_ENDIAN    3412
+# define __BYTE_ORDER    __BIG_ENDIAN
+#elif defined(__PDP_ENDIAN)
+# undef  __PDP_ENDIAN
+# define __LITTLE_ENDIAN 1234
+# define __BIG_ENDIAN    4321
+# define __PDP_ENDIAN    3412
+# define __BYTE_ORDER    __PDP_ENDIAN
+#else
+# error "Unknown byte order!"
+#endif
+
+#endif				/* _KLIBC_ENDIAN_H */
diff --git a/usr/include/klibc/extern.h b/usr/include/klibc/extern.h
new file mode 100644
index 0000000..7d7c7b8
--- /dev/null
+++ b/usr/include/klibc/extern.h
@@ -0,0 +1,16 @@
+/*
+ * klibc/extern.h
+ */
+
+#ifndef _KLIBC_EXTERN_H
+#define _KLIBC_EXTERN_H
+
+#ifdef __cplusplus
+#define __extern extern "C"
+#else
+#define __extern extern
+#endif
+
+#define __alias(x) __attribute__((weak, alias(x)))
+
+#endif				/* _KLIBC_EXTERN_H */
diff --git a/usr/include/klibc/stathelp.h b/usr/include/klibc/stathelp.h
new file mode 100644
index 0000000..9520dad
--- /dev/null
+++ b/usr/include/klibc/stathelp.h
@@ -0,0 +1,24 @@
+/*
+ * stathelp.h
+ *
+ * Helper macros for <klibc/archstat.h>
+ */
+
+#ifndef _KLIBC_STATHELP_H
+#define _KLIBC_STATHELP_H
+
+#include <klibc/endian.h>
+
+/*
+ * Most architectures have a 64-bit field for st_dev and st_rdev,
+ * but dev_t is 32 bits (uint32_t == unsigned int), so make a
+ * macro we can use across all architectures.
+ */
+
+#if __BYTE_ORDER == __BIG_ENDIAN
+# define __stdev64(x)	unsigned int __##x, x;
+#else
+# define __stdev64(x)	unsigned int x, __##x;
+#endif
+
+#endif				/* _KLIBC_STATHELP_H */
diff --git a/usr/include/klibc/sysconfig.h b/usr/include/klibc/sysconfig.h
new file mode 100644
index 0000000..9c132d9
--- /dev/null
+++ b/usr/include/klibc/sysconfig.h
@@ -0,0 +1,187 @@
+/*
+ * klibc/sysconfig.h
+ *
+ * Allows for definitions of some things which may be system-dependent
+ * NOTE: this file must not result in any output from the preprocessor.
+ */
+
+#ifndef _KLIBC_SYSCONFIG_H
+#define _KLIBC_SYSCONFIG_H
+
+#include <klibc/archconfig.h>
+#include <asm/unistd.h>
+
+/*
+ * These are the variables that can be defined in <klibc/archconfig.h>.
+ * For boolean options, #define to 0 to disable, #define to 1 to enable.
+ *
+ * If undefined, they will be given defaults here.
+ */
+
+
+/*
+ * _KLIBC_NO_MMU:
+ *
+ *	Indicates this architecture doesn't have an MMU, and therefore
+ *	does not have the sys_fork and sys_brk system calls.
+ */
+/* Default to having an MMU if we can find the fork system call */
+#ifndef _KLIBC_NO_MMU
+# if defined(__NR_fork)
+#  define _KLIBC_NO_MMU 0
+# else
+#  define _KLIBC_NO_MMU 1
+# endif
+#endif
+
+
+/*
+ * _KLIBC_REAL_VFORK:
+ *
+ *	Indicates that this architecture has a real vfork() system call.
+ *	This is the default if sys_vfork exists; if there is an
+ *	architecture-dependent implementation of vfork(), define this
+ *	symbol.
+ */
+#ifndef _KLIBC_REAL_VFORK
+# if defined(__NR_vfork)
+#  define _KLIBC_REAL_VFORK 1
+# else
+#  define _KLIBC_REAL_VFORK 0
+# endif
+#endif
+
+
+/*
+ * _KLIBC_USE_MMAP2:
+ *
+ *	Indicates that this architecture should use sys_mmap2 instead
+ *	of sys_mmap.  This is the default on 32-bit architectures, assuming
+ *	sys_mmap2 exists.
+ */
+#ifndef _KLIBC_USE_MMAP2
+# if (_BITSIZE == 32 && defined(__NR_mmap2)) || \
+     (_BITSIZE == 64 && !defined(__NR_mmap))
+#  define _KLIBC_USE_MMAP2 1
+# else
+#  define _KLIBC_USE_MMAP2 0
+# endif
+#endif
+
+
+/*
+ * _KLIBC_MMAP2_SHIFT:
+ *
+ *	Indicate the shift of the offset parameter in sys_mmap2.
+ *	On most architectures, this is always 12, but on some
+ *	architectures it can be a different number, or the current
+ *	page size.  If this is dependent on the page size, define
+ *	this to an expression which includes __getpageshift().
+ */
+#ifndef _KLIBC_MMAP2_SHIFT
+# define _KLIBC_MMAP2_SHIFT 12
+#endif
+
+
+/*
+ * _KLIBC_MALLOC_USES_SBRK:
+ *
+ *	Indicates that malloc() should use sbrk() to obtain raw memory
+ *	from the system, rather than mmap().
+ */
+/* Default to get memory using mmap() */
+#ifndef _KLIBC_MALLOC_USES_SBRK
+# define _KLIBC_MALLOC_USES_SBRK 0
+#endif
+
+
+/*
+ * _KLIBC_MALLOC_CHUNK_SIZE:
+ *	This is the minimum chunk size we will ask the kernel for using
+ *	malloc(); this should be a multiple of the page size and must
+ *	be a power of 2.
+ */
+#ifndef _KLIBC_MALLOC_CHUNK_SIZE
+# define _KLIBC_MALLOC_CHUNK_SIZE	65536
+#endif
+
+
+/*
+ * _KLIBC_SBRK_ALIGNMENT:
+ *
+ *	This is the minimum alignment for the memory returned by
+ *	sbrk().  It must be a power of 2.  If _KLIBC_MALLOC_USES_SBRK
+ *	is set it should be no smaller than the size of struct
+ *	arena_header in malloc.h (== 4 pointers.)
+ */
+#ifndef _KLIBC_SBRK_ALIGNMENT
+# define _KLIBC_SBRK_ALIGNMENT		32
+#endif
+
+
+/*
+ * _KLIBC_USE_RT_SIG:
+ *
+ *      Indicates that this architecture should use the rt_sig*()
+ *      family of system calls, even if the older system calls are
+ *      provided.  This requires that <asm/signal.h> is correct for
+ *      using with the rt_sig*() system calls.  This is the default if
+ *      the older system calls are undefined in <asm/unistd.h>.
+ *
+ */
+#ifndef _KLIBC_USE_RT_SIG
+# ifdef __NR_sigaction
+#  define _KLIBC_USE_RT_SIG 0
+# else
+#  define _KLIBC_USE_RT_SIG 1
+# endif
+#endif
+
+
+/*
+ * _KLIBC_NEEDS_SA_RESTORER:
+ *
+ *	Some architectures, like x86-64 and some i386 Fedora kernels,
+ *	do not provide a default sigreturn, and therefore must have
+ *	SA_RESTORER set.
+ */
+#ifndef _KLIBC_NEEDS_SA_RESTORER
+# define _KLIBC_NEEDS_SA_RESTORER 0
+#endif
+
+
+/*
+ * _KLIBC_STATFS_F_TYPE_64:
+ *
+ *	This indicates that the f_type, f_bsize, f_namelen,
+ *	f_frsize, and f_spare fields of struct statfs are
+ *	64 bits long.  This is normally the case for 64-bit
+ *	platforms, and so is the default for those.  See
+ *	usr/include/sys/vfs.h for the exact details.
+ */
+#ifndef _KLIBC_STATFS_F_TYPE_64
+# define _KLIBC_STATFS_F_TYPE_64 (_BITSIZE == 64)
+#endif
+
+
+/*
+ * _KLIBC_STATFS_F_TYPE_32B:
+ *
+ * 	mips has it's own definition of statfs, which is
+ * 	different from any other 32 bit arch.
+ */	
+#ifndef _KLIBC_STATFS_F_TYPE_32B
+# define _KLIBC_STATFS_F_TYPE_32B 0
+#endif
+
+
+/*
+ * _KLIBC_HAS_ARCHSOCKET_H
+ *
+ *       This architecture has <klibc/archsocket.h>
+ */
+#ifndef _KLIBC_HAS_ARCHSOCKET_H
+# define _KLIBC_HAS_ARCHSOCKET_H 0
+#endif
+
+#endif /* _KLIBC_SYSCONFIG_H */
diff --git a/usr/include/limits.h b/usr/include/limits.h
new file mode 100644
index 0000000..942f005
--- /dev/null
+++ b/usr/include/limits.h
@@ -0,0 +1,40 @@
+/*
+ * limits.h
+ */
+
+#ifndef _LIMITS_H
+#define _LIMITS_H
+
+#define CHAR_BIT	8
+#define SHRT_BIT	16
+#define INT_BIT		32
+#define LONGLONG_BIT	64
+
+#define SCHAR_MIN	(-128)
+#define SCHAR_MAX	127
+#define UCHAR_MAX	255
+
+#ifdef __CHAR_UNSIGNED__
+# define CHAR_MIN 0
+# define CHAR_MAX UCHAR_MAX
+#else
+# define CHAR_MIN SCHAR_MIN
+# define CHAR_MAX SCHAR_MAX
+#endif
+
+#define SHRT_MIN	(-32768)
+#define SHRT_MAX	32767
+#define USHRT_MAX	65535
+
+#define INT_MIN		(-2147483647-1)
+#define INT_MAX		2147483647
+#define UINT_MAX	4294967295U
+
+#define LONGLONG_MIN	(-9223372036854775807LL-1)
+#define LONGLONG_MAX	9223372036854775807LL
+#define ULONGLONG_MAX	18446744073709551615ULL
+
+#include <bitsize/limits.h>
+#include <linux/limits.h>
+
+#endif				/* _LIMITS_H */
diff --git a/usr/include/malloc.h b/usr/include/malloc.h
new file mode 100644
index 0000000..2773167
--- /dev/null
+++ b/usr/include/malloc.h
@@ -0,0 +1,21 @@
+/*
+ * malloc.h
+ *
+ * Apparently people haven't caught on to use <stdlib.h>, which is the
+ * standard place for this crap since the 1980's...
+ */
+
+#ifndef _MALLOC_H
+#define _MALLOC_H
+
+#include <klibc/extern.h>
+#include <klibc/compiler.h>
+#include <stddef.h>
+
+__extern void free(void *);
+
+__extern __mallocfunc void *malloc(size_t);
+__extern __mallocfunc void *calloc(size_t, size_t);
+__extern __mallocfunc void *realloc(void *, size_t);
+
+#endif				/* _MALLOC_H */
diff --git a/usr/include/net/if.h b/usr/include/net/if.h
new file mode 100644
index 0000000..f6aa0c0
--- /dev/null
+++ b/usr/include/net/if.h
@@ -0,0 +1,7 @@
+#ifndef _NET_IF_H
+#define _NET_IF_H
+
+#include <sys/types.h>
+#include <linux/if.h>
+
+#endif /* _NET_IF_H */
diff --git a/usr/include/net/if_arp.h b/usr/include/net/if_arp.h
new file mode 100644
index 0000000..a25f1b4
--- /dev/null
+++ b/usr/include/net/if_arp.h
@@ -0,0 +1 @@
+#include <linux/if_arp.h>
diff --git a/usr/include/net/if_packet.h b/usr/include/net/if_packet.h
new file mode 100644
index 0000000..b5e8e0e
--- /dev/null
+++ b/usr/include/net/if_packet.h
@@ -0,0 +1 @@
+#include <linux/if_packet.h>
diff --git a/usr/include/net/route.h b/usr/include/net/route.h
new file mode 100644
index 0000000..a60df24
--- /dev/null
+++ b/usr/include/net/route.h
@@ -0,0 +1 @@
+#include <linux/route.h>
diff --git a/usr/include/netinet/if_ether.h b/usr/include/netinet/if_ether.h
new file mode 100644
index 0000000..060ef220
--- /dev/null
+++ b/usr/include/netinet/if_ether.h
@@ -0,0 +1 @@
+#include <linux/if_ether.h>
diff --git a/usr/include/netinet/in.h b/usr/include/netinet/in.h
new file mode 100644
index 0000000..2952bb2
--- /dev/null
+++ b/usr/include/netinet/in.h
@@ -0,0 +1,37 @@
+/*
+ * netinet/in.h
+ */
+
+#ifndef _NETINET_IN_H
+#define _NETINET_IN_H
+
+#include <klibc/extern.h>
+#include <stdint.h>
+#include <endian.h>		/* Must be included *before* <linux/in.h> */
+#include <sys/socket.h>		/* Must be included *before* <linux/in.h> */
+#include <linux/in.h>
+
+#ifndef htons
+# define htons(x)	__cpu_to_be16(x)
+#endif
+#ifndef ntohs
+# define ntohs(x)	__be16_to_cpu(x)
+#endif
+#ifndef htonl
+# define htonl(x)	__cpu_to_be32(x)
+#endif
+#ifndef ntohl
+# define ntohl(x)	__be32_to_cpu(x)
+#endif
+#ifndef htonq
+# define htonq(x)	__cpu_to_be64(x)
+#endif
+#ifndef ntohq
+# define ntohq(x)	__be64_to_cpu(x)
+#endif
+
+#define IPPORT_RESERVED	1024
+
+__extern int bindresvport(int sd, struct sockaddr_in *sin);
+
+#endif				/* _NETINET_IN_H */
diff --git a/usr/include/netinet/in6.h b/usr/include/netinet/in6.h
new file mode 100644
index 0000000..7e6da92
--- /dev/null
+++ b/usr/include/netinet/in6.h
@@ -0,0 +1,10 @@
+/*
+ * netinet/in6.h
+ */
+
+#ifndef _NETINET_IN6_H
+#define _NETINET_IN6_H
+
+#include <linux/in6.h>
+
+#endif				/* _NETINET_IN6_H */
diff --git a/usr/include/netinet/ip.h b/usr/include/netinet/ip.h
new file mode 100644
index 0000000..4684bfd
--- /dev/null
+++ b/usr/include/netinet/ip.h
@@ -0,0 +1,13 @@
+/*
+ * netinet/ip.h
+ */
+
+#ifndef _NETINET_IP_H
+#define _NETINET_IP_H
+
+#include <endian.h>
+#include <linux/ip.h>
+
+#define IP_DF		0x4000	/* Flag: "Don't Fragment" */
+
+#endif				/* _NETINET_IP_H */
diff --git a/usr/include/netinet/tcp.h b/usr/include/netinet/tcp.h
new file mode 100644
index 0000000..7fc4729
--- /dev/null
+++ b/usr/include/netinet/tcp.h
@@ -0,0 +1,11 @@
+/*
+ * netinet/tcp.h
+ */
+
+#ifndef _NETINET_TCP_H
+#define _NETINET_TCP_H
+
+#include <endian.h>		/* Include *before* linux/tcp.h */
+#include <linux/tcp.h>
+
+#endif				/* _NETINET_TCP_H */
diff --git a/usr/include/netinet/udp.h b/usr/include/netinet/udp.h
new file mode 100644
index 0000000..036f588
--- /dev/null
+++ b/usr/include/netinet/udp.h
@@ -0,0 +1,19 @@
+/*
+ * netinet/udp.h
+ */
+
+#ifndef _NETINET_UDP_H
+#define _NETINET_UDP_H
+
+/*
+ * We would include linux/udp.h, but it brings in too much other stuff
+ */
+
+struct udphdr {
+	__u16 source;
+	__u16 dest;
+	__u16 len;
+	__u16 check;
+};
+
+#endif				/* _NETINET_UDP_H */
diff --git a/usr/include/netpacket/packet.h b/usr/include/netpacket/packet.h
new file mode 100644
index 0000000..b5e8e0e
--- /dev/null
+++ b/usr/include/netpacket/packet.h
@@ -0,0 +1 @@
+#include <linux/if_packet.h>
diff --git a/usr/include/paths.h b/usr/include/paths.h
new file mode 100644
index 0000000..29ef301
--- /dev/null
+++ b/usr/include/paths.h
@@ -0,0 +1,74 @@
+/*
+ * Copyright (c) 1989, 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.
+ *
+ *	@(#)paths.h	8.1 (Berkeley) 6/2/93
+ */
+
+#ifndef _PATHS_H_
+#define	_PATHS_H_
+
+/* Default search path. */
+#define	_PATH_DEFPATH	"/usr/bin:/bin"
+/* All standard utilities path. */
+#define	_PATH_STDPATH \
+	"/usr/bin:/bin:/usr/sbin:/sbin"
+
+#define	_PATH_BSHELL	"/bin/sh"
+#define	_PATH_CONSOLE	"/dev/console"
+#define	_PATH_CSHELL	"/bin/csh"
+#define	_PATH_DEVDB	"/var/run/dev.db"
+#define	_PATH_DEVNULL	"/dev/null"
+#define	_PATH_DRUM	"/dev/drum"
+#define	_PATH_KLOG	"/proc/kmsg"
+#define	_PATH_KMEM	"/dev/kmem"
+#define	_PATH_LASTLOG	"/var/log/lastlog"
+#define	_PATH_MAILDIR	"/var/mail"
+#define	_PATH_MAN	"/usr/share/man"
+#define	_PATH_MEM	"/dev/mem"
+#define	_PATH_MNTTAB	"/etc/fstab"
+#define	_PATH_MOUNTED	"/etc/mtab"
+#define	_PATH_NOLOGIN	"/etc/nologin"
+#define	_PATH_PRESERVE	"/var/lib"
+#define	_PATH_RWHODIR	"/var/spool/rwho"
+#define	_PATH_SENDMAIL	"/usr/sbin/sendmail"
+#define	_PATH_SHADOW	"/etc/shadow"
+#define	_PATH_SHELLS	"/etc/shells"
+#define	_PATH_TTY	"/dev/tty"
+#define	_PATH_UNIX	"/boot/vmlinux"
+#define _PATH_UTMP	"/var/run/utmp"
+#define	_PATH_VI	"/bin/vi"
+#define _PATH_WTMP	"/var/log/wtmp"
+
+/* Provide trailing slash, since mostly used for building pathnames. */
+#define	_PATH_DEV	"/dev/"
+#define	_PATH_TMP	"/tmp/"
+#define	_PATH_VARDB	"/var/db/"
+#define	_PATH_VARRUN	"/var/run/"
+#define	_PATH_VARTMP	"/var/tmp/"
+
+#endif				/* !_PATHS_H_ */
diff --git a/usr/include/poll.h b/usr/include/poll.h
new file mode 100644
index 0000000..06fb41a
--- /dev/null
+++ b/usr/include/poll.h
@@ -0,0 +1 @@
+#include <sys/poll.h>
diff --git a/usr/include/pwd.h b/usr/include/pwd.h
new file mode 100644
index 0000000..aeddbfb
--- /dev/null
+++ b/usr/include/pwd.h
@@ -0,0 +1,19 @@
+#ifndef _PWD_H
+#define _PWD_H
+
+#include <klibc/extern.h>
+#include <sys/types.h>
+
+struct passwd {
+	char *pw_name;
+	char *pw_passwd;
+	uid_t pw_uid;
+	gid_t pw_gid;
+	char *pw_gecos;
+	char *pw_dir;
+	char *pw_shell;
+};
+
+__extern struct passwd *getpwnam(const char *name);
+
+#endif	/* _PWD_H */
diff --git a/usr/include/sched.h b/usr/include/sched.h
new file mode 100644
index 0000000..fb4da8d
--- /dev/null
+++ b/usr/include/sched.h
@@ -0,0 +1,36 @@
+/*
+ * sched.h
+ */
+
+#ifndef _SCHED_H
+#define _SCHED_H
+
+#include <klibc/extern.h>
+
+/* linux/sched.h is unusable; put the declarations we need here... */
+
+#define SCHED_NORMAL            0
+#define SCHED_FIFO              1
+#define SCHED_RR                2
+
+struct sched_param {
+	int sched_priority;
+};
+
+__extern int sched_setscheduler(pid_t, int, const struct sched_param *);
+__extern int sched_yield(void);
+
+/* Raw interfaces to clone(2); only actually usable for non-VM-cloning */
+#ifdef __ia64__
+__extern pid_t __clone2(int, void *, void *);
+static __inline__ pid_t __clone(int _f, void *_sp)
+{
+	/* If this is used with _sp != 0 it will have the effect of the sp
+	   and rsp growing away from a single point in opposite directions. */
+	return __clone2(_f, _sp, _sp);
+}
+#else
+__extern pid_t __clone(int, void *);
+#endif
+
+#endif				/* _SCHED_H */
diff --git a/usr/include/setjmp.h b/usr/include/setjmp.h
new file mode 100644
index 0000000..abebccd
--- /dev/null
+++ b/usr/include/setjmp.h
@@ -0,0 +1,43 @@
+/*
+ * setjmp.h
+ */
+
+#ifndef _SETJMP_H
+#define _SETJMP_H
+
+#include <klibc/extern.h>
+#include <klibc/compiler.h>
+#include <stddef.h>
+#include <signal.h>
+
+#include <klibc/archsetjmp.h>
+
+__extern int setjmp(jmp_buf);
+__extern __noreturn longjmp(jmp_buf, int);
+
+/*
+  Whose bright idea was it to add unrelated functionality to just about
+  the only function in the standard C library (setjmp) which cannot be
+  wrapped by an ordinary function wrapper?  Anyway, the damage is done,
+  and therefore, this wrapper *must* be inline.  However, gcc will
+  complain if this is an inline function for unknown reason, and
+  therefore sigsetjmp() needs to be a macro.
+*/
+
+struct __sigjmp_buf {
+	jmp_buf __jmpbuf;
+	sigset_t __sigs;
+};
+
+typedef struct __sigjmp_buf sigjmp_buf[1];
+
+#define sigsetjmp(__env, __save) \
+({ \
+  struct __sigjmp_buf *__e = (__env); \
+  sigprocmask(0, NULL, &__e->__sigs); \
+  setjmp(__e->__jmpbuf); \
+})
+
+__extern __noreturn siglongjmp(sigjmp_buf, int);
+
+#endif				/* _SETJMP_H */
diff --git a/usr/include/signal.h b/usr/include/signal.h
new file mode 100644
index 0000000..bb6b470
--- /dev/null
+++ b/usr/include/signal.h
@@ -0,0 +1,100 @@
+/*
+ * signal.h
+ */
+
+#ifndef _SIGNAL_H
+#define _SIGNAL_H
+
+#include <klibc/compiler.h>
+#include <klibc/extern.h>
+#include <string.h>		/* For memset() */
+#include <limits.h>		/* For LONG_BIT */
+#include <sys/types.h>
+
+#include <klibc/archsignal.h>	/* Includes <asm/signal.h> if appropriate */
+
+/* glibc seems to use sig_atomic_t as "int" pretty much on all architectures.
+   Do the same, but allow the architecture to override. */
+#ifndef _KLIBC_HAS_ARCH_SIG_ATOMIC_T
+typedef int sig_atomic_t;
+#endif
+
+/* Some architectures don't define these */
+#ifndef SA_RESETHAND
+# define SA_RESETHAND SA_ONESHOT
+#endif
+#ifndef SA_NODEFER
+# define SA_NODEFER SA_NOMASK
+#endif
+/* Some architectures define NSIG and not _NSIG or vice versa */
+#ifndef NSIG
+# define NSIG _NSIG
+#endif
+#ifndef _NSIG
+# define _NSIG NSIG
+#endif
+
+/* If we don't have any real-time signals available to userspace,
+   hide them all */
+#if SIGRTMAX <= SIGRTMIN
+# undef SIGRTMIN
+# undef SIGRTMAX
+#endif
+
+/* The kernel header files are inconsistent whether or not
+   SIGRTMAX is inclusive or exclusive.  POSIX seems to state that
+   it's inclusive, however. */
+#if SIGRTMAX >= _NSIG
+# undef  SIGRTMAX
+# define SIGRTMAX (_NSIG-1)
+#endif
+
+__extern const char *const sys_siglist[_NSIG];
+__extern const char *const sys_sigabbrev[_NSIG];
+
+/* This assumes sigset_t is either an unsigned long or an array of such,
+   and that _NSIG_BPW in the kernel is always LONG_BIT */
+
+static __inline__ int sigemptyset(sigset_t * __set)
+{
+	memset(__set, 0, sizeof *__set);
+	return 0;
+}
+static __inline__ int sigfillset(sigset_t * __set)
+{
+	memset(__set, ~0, sizeof *__set);
+	return 0;
+}
+static __inline__ int sigaddset(sigset_t * __set, int __signum)
+{
+	unsigned long *__lset = (unsigned long *)__set;
+	__signum--;		/* Signal 0 is not in the set */
+	__lset[__signum / LONG_BIT] |= 1UL << (__signum % LONG_BIT);
+	return 0;
+}
+static __inline__ int sigdelset(sigset_t * __set, int __signum)
+{
+	unsigned long *__lset = (unsigned long *)__set;
+	__signum--;		/* Signal 0 is not in the set */
+	__lset[__signum / LONG_BIT] &= ~(1UL << (__signum % LONG_BIT));
+	return 0;
+}
+static __inline__ int sigismember(sigset_t * __set, int __signum)
+{
+	unsigned long *__lset = (unsigned long *)__set;
+	__signum--;		/* Signal 0 is not in the set */
+	return (int)((__lset[__signum / LONG_BIT] >> (__signum % LONG_BIT)) &
+		     1);
+}
+
+__extern __sighandler_t __signal(int, __sighandler_t, int);
+__extern __sighandler_t sysv_signal(int, __sighandler_t);
+__extern __sighandler_t bsd_signal(int, __sighandler_t);
+__extern int sigaction(int, const struct sigaction *, struct sigaction *);
+__extern int sigprocmask(int, const sigset_t *, sigset_t *);
+__extern int sigpending(sigset_t *);
+__extern int sigsuspend(const sigset_t *);
+__extern int raise(int);
+__extern int kill(pid_t, int);
+
+#endif				/* _SIGNAL_H */
diff --git a/usr/include/stdarg.h b/usr/include/stdarg.h
new file mode 100644
index 0000000..cc324b8
--- /dev/null
+++ b/usr/include/stdarg.h
@@ -0,0 +1,14 @@
+/*
+ * stdarg.h
+ *
+ * This is just a wrapper for the gcc one, but defines va_copy()
+ * even if gcc doesn't.
+ */
+
+/* Note: the _STDARG_H macro belongs to the gcc header... */
+#include_next <stdarg.h>
+
+/* Older gcc considers this an extension, so it's double underbar only */
+#ifndef va_copy
+#define va_copy(d,s) __va_copy(d,s)
+#endif
diff --git a/usr/include/stddef.h b/usr/include/stddef.h
new file mode 100644
index 0000000..f1529a4
--- /dev/null
+++ b/usr/include/stddef.h
@@ -0,0 +1,24 @@
+/*
+ * stddef.h
+ */
+
+#ifndef _STDDEF_H
+#define _STDDEF_H
+
+#ifndef __KLIBC__
+# error "__KLIBC__ not defined, compiler invocation error!"
+#endif
+
+#include <bitsize/stddef.h>
+
+#undef NULL
+#ifdef __cplusplus
+# define NULL 0
+#else
+# define NULL ((void *)0)
+#endif
+
+#undef offsetof
+#define offsetof(t,m) ((size_t)&((t *)0)->m)
+
+#endif				/* _STDDEF_H */
diff --git a/usr/include/stdint.h b/usr/include/stdint.h
new file mode 100644
index 0000000..f64f027
--- /dev/null
+++ b/usr/include/stdint.h
@@ -0,0 +1,116 @@
+/*
+ * stdint.h
+ */
+
+#ifndef _STDINT_H
+#define _STDINT_H
+
+#include <bitsize/stdint.h>
+
+typedef int8_t		int_least8_t;
+typedef int16_t		int_least16_t;
+typedef int32_t		int_least32_t;
+typedef int64_t		int_least64_t;
+
+typedef uint8_t		uint_least8_t;
+typedef uint16_t	uint_least16_t;
+typedef uint32_t	uint_least32_t;
+typedef uint64_t	uint_least64_t;
+
+typedef int8_t		int_fast8_t;
+typedef int64_t		int_fast64_t;
+
+typedef uint8_t		uint_fast8_t;
+typedef uint64_t	uint_fast64_t;
+
+typedef int64_t		intmax_t;
+typedef uint64_t	uintmax_t;
+
+#if !defined(__cplusplus) || defined(__STDC_LIMIT_MACROS)
+
+#define INT8_MIN	(-128)
+#define INT16_MIN	(-32768)
+#define INT32_MIN	(-2147483647-1)
+#define INT64_MIN	(__INT64_C(-9223372036854775807)-1)
+
+#define INT8_MAX	(127)
+#define INT16_MAX	(32767)
+#define INT32_MAX	(2147483647)
+#define INT64_MAX	(__INT64_C(9223372036854775807))
+
+#define UINT8_MAX	(255U)
+#define UINT16_MAX	(65535U)
+#define UINT32_MAX	(4294967295U)
+#define UINT64_MAX	(__UINT64_C(18446744073709551615))
+
+#define INT_LEAST8_MIN	INT8_MIN
+#define INT_LEAST16_MIN	INT16_MIN
+#define INT_LEAST32_MIN	INT32_MIN
+#define INT_LEAST64_MIN	INT64_MIN
+
+#define INT_LEAST8_MAX	INT8_MAX
+#define INT_LEAST16_MAX	INT16_MAX
+#define INT_LEAST32_MAX	INT32_MAX
+#define INT_LEAST64_MAX	INT64_MAX
+
+#define UINT_LEAST8_MAX	 UINT8_MAX
+#define UINT_LEAST16_MAX UINT16_MAX
+#define UINT_LEAST32_MAX UINT32_MAX
+#define UINT_LEAST64_MAX UINT64_MAX
+
+#define INT_FAST8_MIN	INT8_MIN
+#define INT_FAST64_MIN	INT64_MIN
+
+#define INT_FAST8_MAX	INT8_MAX
+#define INT_FAST64_MAX	INT64_MAX
+
+#define UINT_FAST8_MAX	UINT8_MAX
+#define UINT_FAST64_MAX UINT64_MAX
+
+#define INTMAX_MIN	INT64_MIN
+#define INTMAX_MAX	INT64_MAX
+#define UINTMAX_MAX	UINT64_MAX
+
+#include <bitsize/stdintlimits.h>
+
+#endif
+
+#if !defined(__cplusplus) || defined(__STDC_CONSTANT_MACROS)
+
+#define INT8_C(c)	c
+#define INT16_C(c)	c
+#define INT32_C(c)	c
+#define INT64_C(c)	__INT64_C(c)
+
+#define UINT8_C(c)	c ## U
+#define UINT16_C(c)	c ## U
+#define UINT32_C(c)	c ## U
+#define UINT64_C(c)	__UINT64_C(c)
+
+#define INT_LEAST8_C(c)	 INT8_C(c)
+#define INT_LEAST16_C(c) INT16_C(c)
+#define INT_LEAST32_C(c) INT32_C(c)
+#define INT_LEAST64_C(c) INT64_C(c)
+
+#define UINT_LEAST8_C(c)  UINT8_C(c)
+#define UINT_LEAST16_C(c) UINT16_C(c)
+#define UINT_LEAST32_C(c) UINT32_C(c)
+#define UINT_LEAST64_C(c) UINT64_C(c)
+
+#define INT_FAST8_C(c)	INT8_C(c)
+#define INT_FAST64_C(c) INT64_C(c)
+
+#define UINT_FAST8_C(c)  UINT8_C(c)
+#define UINT_FAST64_C(c) UINT64_C(c)
+
+#define INTMAX_C(c)	INT64_C(c)
+#define UINTMAX_C(c)	UINT64_C(c)
+
+#include <bitsize/stdintconst.h>
+
+#endif
+
+/* Keep the kernel from trying to define these types... */
+#define __BIT_TYPES_DEFINED__
+
+#endif				/* _STDINT_H */
diff --git a/usr/include/stdio.h b/usr/include/stdio.h
new file mode 100644
index 0000000..1462f5b
--- /dev/null
+++ b/usr/include/stdio.h
@@ -0,0 +1,128 @@
+/*
+ * stdio.h
+ */
+
+#ifndef _STDIO_H
+#define _STDIO_H
+
+#include <klibc/extern.h>
+#include <stdarg.h>
+#include <stddef.h>
+#include <unistd.h>
+
+/* This structure doesn't really exist, but it gives us something
+   to define FILE * with */
+struct _IO_file;
+typedef struct _IO_file FILE;
+
+#ifndef EOF
+# define EOF (-1)
+#endif
+
+#ifndef BUFSIZ
+# define BUFSIZ 4096
+#endif
+
+#define SEEK_SET 0
+#define SEEK_CUR 1
+#define SEEK_END 2
+
+/*
+ * Convert between a FILE * and a file descriptor.  We don't actually
+ * have any in-memory data, so we just abuse the pointer itself to
+ * hold the data.  Note, however, that for file descriptors, -1 is
+ * error and 0 is a valid value; for FILE *, NULL (0) is error and
+ * non-NULL are valid.
+ */
+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 - 1;
+}
+
+/* This is a macro so it can be used as initializer */
+#define __create_file(__fd) ((FILE *)(size_t)((__fd) + 1))
+
+#define stdin  __create_file(0)
+#define stdout __create_file(1)
+#define stderr __create_file(2)
+
+__extern FILE *fopen(const char *, const char *);
+
+static __inline__ FILE *fdopen(int __fd, const char *__m)
+{
+	(void)__m;
+	return __create_file(__fd);
+}
+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 *);
+__extern int fputc(int, FILE *);
+#define putc(c,f)  fputc((c),(f))
+#define putchar(c) fputc((c),stdout)
+
+__extern int fgetc(FILE *);
+__extern char *fgets(char *, int, FILE *);
+#define getc(f) fgetc(f)
+#define getchar() fgetc(stdin)
+
+__extern size_t _fread(void *, size_t, FILE *);
+__extern size_t _fwrite(const void *, size_t, FILE *);
+
+#ifndef __NO_FREAD_FWRITE_INLINES
+extern __inline__ size_t fread(void *__p, size_t __s, size_t __n, FILE * __f)
+{
+	return _fread(__p, __s * __n, __f) / __s;
+}
+
+extern __inline__ size_t
+fwrite(const void *__p, size_t __s, size_t __n, FILE * __f)
+{
+	return _fwrite(__p, __s * __n, __f) / __s;
+}
+#endif
+
+__extern int printf(const char *, ...);
+__extern int vprintf(const char *, va_list);
+__extern int fprintf(FILE *, const char *, ...);
+__extern int vfprintf(FILE *, const char *, va_list);
+__extern int sprintf(char *, const char *, ...);
+__extern int vsprintf(char *, const char *, va_list);
+__extern int snprintf(char *, size_t n, const char *, ...);
+__extern int vsnprintf(char *, size_t n, const char *, va_list);
+__extern int asprintf(char **, const char *, ...);
+__extern int vasprintf(char **, const char *, va_list);
+
+/* No buffering, so no flushing needed */
+extern __inline__ int fflush(FILE * __f)
+{
+	(void)__f;
+	return 0;
+}
+
+__extern int sscanf(const char *, const char *, ...);
+__extern int vsscanf(const char *, const char *, va_list);
+
+__extern void perror(const char *);
+
+__extern int rename(const char *, const char *);
+__extern int renameat(int, const char *, int, const char *);
+
+__extern int remove(const char *);
+
+#endif				/* _STDIO_H */
diff --git a/usr/include/stdlib.h b/usr/include/stdlib.h
new file mode 100644
index 0000000..24cc226
--- /dev/null
+++ b/usr/include/stdlib.h
@@ -0,0 +1,94 @@
+/*
+ * stdlib.h
+ */
+
+#ifndef _STDLIB_H
+#define _STDLIB_H
+
+#include <klibc/extern.h>
+#include <klibc/compiler.h>
+#include <stddef.h>
+
+#include <malloc.h>
+
+#define EXIT_FAILURE 1
+#define EXIT_SUCCESS 0
+
+__extern __noreturn abort(void);
+static __inline__ int abs(int __n)
+{
+	return (__n < 0) ? -__n : __n;
+}
+__extern int system(const char *string);
+__extern int atexit(void (*)(void));
+__extern int on_exit(void (*)(int, void *), void *);
+__extern int atoi(const char *);
+__extern long atol(const char *);
+__extern long long atoll(const char *);
+__extern __noreturn exit(int);
+__extern __noreturn _exit(int);
+#define _Exit _exit
+static __inline__ long labs(long __n)
+{
+	return (__n < 0L) ? -__n : __n;
+}
+
+static __inline__ long long llabs(long long __n)
+{
+	return (__n < 0LL) ? -__n : __n;
+}
+
+__extern long strtol(const char *, char **, int);
+__extern long long strtoll(const char *, char **, int);
+__extern unsigned long strtoul(const char *, char **, int);
+__extern unsigned long long strtoull(const char *, char **, int);
+
+__extern char *getenv(const char *);
+__extern int putenv(const char *);
+__extern int setenv(const char *, const char *, int);
+__extern int unsetenv(const char *);
+__extern int clearenv(void);
+
+typedef int (*__comparefunc_t) (const void *, const void *);
+__extern void *bsearch(const void *, const void *, size_t, size_t,
+		       __comparefunc_t);
+__extern void qsort(void *, size_t, size_t, __comparefunc_t);
+
+__extern long jrand48(unsigned short *);
+__extern long mrand48(void);
+__extern long nrand48(unsigned short *);
+__extern long lrand48(void);
+__extern unsigned short *seed48(const unsigned short *);
+__extern void srand48(long);
+
+#define RAND_MAX 0x7fffffff
+static __inline__ int rand(void)
+{
+	return (int)lrand48();
+}
+static __inline__ void srand(unsigned int __s)
+{
+	srand48(__s);
+}
+static __inline__ long random(void)
+{
+	return lrand48();
+}
+static __inline__ void srandom(unsigned int __s)
+{
+	srand48(__s);
+}
+
+/* Basic PTY functions.  These only work if devpts is mounted! */
+
+__extern int unlockpt(int);
+__extern char *ptsname(int);
+__extern int getpt(void);
+
+static __inline__ int grantpt(int __fd)
+{
+	(void)__fd;
+	return 0;		/* devpts does this all for us! */
+}
+
+#endif				/* _STDLIB_H */
diff --git a/usr/include/string.h b/usr/include/string.h
new file mode 100644
index 0000000..1a6072c
--- /dev/null
+++ b/usr/include/string.h
@@ -0,0 +1,47 @@
+/*
+ * string.h
+ */
+
+#ifndef _STRING_H
+#define _STRING_H
+
+#include <klibc/extern.h>
+#include <stddef.h>
+
+__extern void *memccpy(void *, const void *, int, size_t);
+__extern void *memchr(const void *, int, size_t);
+__extern void *memrchr(const void *, int, size_t);
+__extern int memcmp(const void *, const void *, size_t);
+__extern void *memcpy(void *, const void *, size_t);
+__extern void *memmove(void *, const void *, size_t);
+__extern void *memset(void *, int, size_t);
+__extern void *memmem(const void *, size_t, const void *, size_t);
+__extern void memswap(void *, void *, size_t);
+__extern int strcasecmp(const char *, const char *);
+__extern int strncasecmp(const char *, const char *, size_t);
+__extern char *strcat(char *, const char *);
+__extern char *strchr(const char *, int);
+__extern char *index(const char *, int);
+__extern char *strrchr(const char *, int);
+__extern char *rindex(const char *, int);
+__extern int strcmp(const char *, const char *);
+__extern char *strcpy(char *, const char *);
+__extern size_t strcspn(const char *, const char *);
+__extern char *strdup(const char *);
+__extern char *strndup(const char *, size_t);
+__extern char *strerror(int);
+__extern char *strsignal(int);
+__extern size_t strlen(const char *);
+__extern size_t strnlen(const char *, size_t);
+__extern char *strncat(char *, const char *, size_t);
+__extern size_t strlcat(char *, const char *, size_t);
+__extern int strncmp(const char *, const char *, size_t);
+__extern char *strncpy(char *, const char *, size_t);
+__extern size_t strlcpy(char *, const char *, size_t);
+__extern char *strpbrk(const char *, const char *);
+__extern char *strsep(char **, const char *);
+__extern size_t strspn(const char *, const char *);
+__extern char *strstr(const char *, const char *);
+__extern char *strtok(char *, const char *);
+
+#endif				/* _STRING_H */
diff --git a/usr/include/sys/dirent.h b/usr/include/sys/dirent.h
new file mode 100644
index 0000000..18b7a33
--- /dev/null
+++ b/usr/include/sys/dirent.h
@@ -0,0 +1,32 @@
+/*
+ * sys/dirent.h
+ */
+
+#ifndef _SYS_DIRENT_H
+#define _SYS_DIRENT_H
+
+#include <stdint.h>
+
+/* The kernel calls this struct dirent64 */
+struct dirent {
+	uint64_t	d_ino;
+	int64_t		d_off;
+	unsigned short	d_reclen;
+	unsigned char	d_type;
+	char		d_name[256];
+};
+
+/* File types to use for d_type */
+#define DT_UNKNOWN	 0
+#define DT_FIFO		 1
+#define DT_CHR		 2
+#define DT_DIR		 4
+#define DT_BLK		 6
+#define DT_REG		 8
+#define DT_LNK		10
+#define DT_SOCK		12
+#define DT_WHT		14
+
+__extern int getdents(unsigned int, struct dirent *, unsigned int);
+
+#endif				/* _SYS_DIRENT_H */
diff --git a/usr/include/sys/elf32.h b/usr/include/sys/elf32.h
new file mode 100644
index 0000000..e4df8ce
--- /dev/null
+++ b/usr/include/sys/elf32.h
@@ -0,0 +1,113 @@
+/*
+ * sys/elf32.h
+ */
+
+#ifndef _SYS_ELF32_H
+#define _SYS_ELF32_H
+
+#include <sys/elfcommon.h>
+
+/* ELF standard typedefs (yet more proof that <stdint.h> was way overdue) */
+typedef uint16_t Elf32_Half;
+typedef int16_t Elf32_SHalf;
+typedef uint32_t Elf32_Word;
+typedef int32_t Elf32_Sword;
+typedef uint64_t Elf32_Xword;
+typedef int64_t Elf32_Sxword;
+
+typedef uint32_t Elf32_Off;
+typedef uint32_t Elf32_Addr;
+typedef uint16_t Elf32_Section;
+
+/* Dynamic header */
+
+typedef struct elf32_dyn {
+	Elf32_Sword d_tag;
+	union {
+		Elf32_Sword d_val;
+		Elf32_Addr d_ptr;
+	} d_un;
+} Elf32_Dyn;
+
+/* Relocations */
+
+#define ELF32_R_SYM(x)	((x) >> 8)
+#define ELF32_R_TYPE(x)	((x) & 0xff)
+
+typedef struct elf32_rel {
+	Elf32_Addr r_offset;
+	Elf32_Word r_info;
+} Elf32_Rel;
+
+typedef struct elf32_rela {
+	Elf32_Addr r_offset;
+	Elf32_Word r_info;
+	Elf32_Sword r_addend;
+} Elf32_Rela;
+
+/* Symbol */
+
+typedef struct elf32_sym {
+	Elf32_Word st_name;
+	Elf32_Addr st_value;
+	Elf32_Word st_size;
+	unsigned char st_info;
+	unsigned char st_other;
+	Elf32_Half st_shndx;
+} Elf32_Sym;
+
+/* Main file header */
+
+typedef struct elf32_hdr {
+	unsigned char e_ident[EI_NIDENT];
+	Elf32_Half e_type;
+	Elf32_Half e_machine;
+	Elf32_Word e_version;
+	Elf32_Addr e_entry;
+	Elf32_Off e_phoff;
+	Elf32_Off e_shoff;
+	Elf32_Word e_flags;
+	Elf32_Half e_ehsize;
+	Elf32_Half e_phentsize;
+	Elf32_Half e_phnum;
+	Elf32_Half e_shentsize;
+	Elf32_Half e_shnum;
+	Elf32_Half e_shstrndx;
+} Elf32_Ehdr;
+
+/* Program header */
+
+typedef struct elf32_phdr {
+	Elf32_Word p_type;
+	Elf32_Off p_offset;
+	Elf32_Addr p_vaddr;
+	Elf32_Addr p_paddr;
+	Elf32_Word p_filesz;
+	Elf32_Word p_memsz;
+	Elf32_Word p_flags;
+	Elf32_Word p_align;
+} Elf32_Phdr;
+
+/* Section header */
+
+typedef struct elf32_shdr {
+	Elf32_Word sh_name;
+	Elf32_Word sh_type;
+	Elf32_Word sh_flags;
+	Elf32_Addr sh_addr;
+	Elf32_Off sh_offset;
+	Elf32_Word sh_size;
+	Elf32_Word sh_link;
+	Elf32_Word sh_info;
+	Elf32_Word sh_addralign;
+	Elf32_Word sh_entsize;
+} Elf32_Shdr;
+
+/* Note header */
+typedef struct elf32_note {
+	Elf32_Word n_namesz;	/* Name size */
+	Elf32_Word n_descsz;	/* Content size */
+	Elf32_Word n_type;	/* Content type */
+} Elf32_Nhdr;
+
+#endif				/* _SYS_ELF32_H */
diff --git a/usr/include/sys/elf64.h b/usr/include/sys/elf64.h
new file mode 100644
index 0000000..0b486ac
--- /dev/null
+++ b/usr/include/sys/elf64.h
@@ -0,0 +1,113 @@
+/*
+ * sys/elf64.h
+ */
+
+#ifndef _SYS_ELF64_H
+#define _SYS_ELF64_H
+
+#include <sys/elfcommon.h>
+
+/* ELF standard typedefs (yet more proof that <stdint.h> was way overdue) */
+typedef uint16_t Elf64_Half;
+typedef int16_t Elf64_SHalf;
+typedef uint32_t Elf64_Word;
+typedef int32_t Elf64_Sword;
+typedef uint64_t Elf64_Xword;
+typedef int64_t Elf64_Sxword;
+
+typedef uint64_t Elf64_Off;
+typedef uint64_t Elf64_Addr;
+typedef uint16_t Elf64_Section;
+
+/* Dynamic header */
+
+typedef struct elf64_dyn {
+	Elf64_Sxword d_tag;
+	union {
+		Elf64_Xword d_val;
+		Elf64_Addr d_ptr;
+	} d_un;
+} Elf64_Dyn;
+
+/* Relocations */
+
+#define ELF64_R_SYM(x)	((x) >> 32)
+#define ELF64_R_TYPE(x)	((x) & 0xffffffff)
+
+typedef struct elf64_rel {
+	Elf64_Addr r_offset;
+	Elf64_Xword r_info;
+} Elf64_Rel;
+
+typedef struct elf64_rela {
+	Elf64_Addr r_offset;
+	Elf64_Xword r_info;
+	Elf64_Sxword r_addend;
+} Elf64_Rela;
+
+/* Symbol */
+
+typedef struct elf64_sym {
+	Elf64_Word st_name;
+	unsigned char st_info;
+	unsigned char st_other;
+	Elf64_Half st_shndx;
+	Elf64_Addr st_value;
+	Elf64_Xword st_size;
+} Elf64_Sym;
+
+/* Main file header */
+
+typedef struct elf64_hdr {
+	unsigned char e_ident[EI_NIDENT];
+	Elf64_Half e_type;
+	Elf64_Half e_machine;
+	Elf64_Word e_version;
+	Elf64_Addr e_entry;
+	Elf64_Off e_phoff;
+	Elf64_Off e_shoff;
+	Elf64_Word e_flags;
+	Elf64_Half e_ehsize;
+	Elf64_Half e_phentsize;
+	Elf64_Half e_phnum;
+	Elf64_Half e_shentsize;
+	Elf64_Half e_shnum;
+	Elf64_Half e_shstrndx;
+} Elf64_Ehdr;
+
+/* Program header */
+
+typedef struct elf64_phdr {
+	Elf64_Word p_type;
+	Elf64_Word p_flags;
+	Elf64_Off p_offset;
+	Elf64_Addr p_vaddr;
+	Elf64_Addr p_paddr;
+	Elf64_Xword p_filesz;
+	Elf64_Xword p_memsz;
+	Elf64_Xword p_align;
+} Elf64_Phdr;
+
+/* Section header */
+
+typedef struct elf64_shdr {
+	Elf64_Word sh_name;
+	Elf64_Word sh_type;
+	Elf64_Xword sh_flags;
+	Elf64_Addr sh_addr;
+	Elf64_Off sh_offset;
+	Elf64_Xword sh_size;
+	Elf64_Word sh_link;
+	Elf64_Word sh_info;
+	Elf64_Xword sh_addralign;
+	Elf64_Xword sh_entsize;
+} Elf64_Shdr;
+
+/* Note header */
+typedef struct elf64_note {
+	Elf64_Word n_namesz;	/* Name size */
+	Elf64_Word n_descsz;	/* Content size */
+	Elf64_Word n_type;	/* Content type */
+} Elf64_Nhdr;
+
+#endif				/* _SYS_ELF64_H */
diff --git a/usr/include/sys/elfcommon.h b/usr/include/sys/elfcommon.h
new file mode 100644
index 0000000..0d81db5
--- /dev/null
+++ b/usr/include/sys/elfcommon.h
@@ -0,0 +1,187 @@
+/*
+ * sys/elfcommon.h
+ */
+
+#ifndef _SYS_ELFCOMMON_H
+#define _SYS_ELFCOMMON_H
+
+#include <stdint.h>
+
+/* Segment types */
+#define PT_NULL    	0
+#define PT_LOAD    	1
+#define PT_DYNAMIC 	2
+#define PT_INTERP  	3
+#define PT_NOTE    	4
+#define PT_SHLIB   	5
+#define PT_PHDR    	6
+#define PT_LOOS    	0x60000000
+#define PT_HIOS    	0x6fffffff
+#define PT_LOPROC  	0x70000000
+#define PT_HIPROC  	0x7fffffff
+#define PT_GNU_EH_FRAME	0x6474e550	/* Extension, eh? */
+
+/* ELF file types */
+#define ET_NONE   	0
+#define ET_REL    	1
+#define ET_EXEC   	2
+#define ET_DYN    	3
+#define ET_CORE   	4
+#define ET_LOPROC 	0xff00
+#define ET_HIPROC 	0xffff
+
+/* ELF machine types */
+#define EM_NONE  	0
+#define EM_M32   	1
+#define EM_SPARC 	2
+#define EM_386   	3
+#define EM_68K   	4
+#define EM_88K   	5
+#define EM_486   	6	/* Not used in Linux at least */
+#define EM_860   	7
+#define EM_MIPS         8	/* R3k, bigendian(?) */
+#define EM_MIPS_RS4_BE 	10	/* R4k BE */
+#define EM_PARISC      	15
+#define EM_SPARC32PLUS 	18
+#define EM_PPC         	20
+#define EM_PPC64       	21
+#define EM_S390         22
+#define EM_SH          	42
+#define EM_SPARCV9	43	/* v9 = SPARC64 */
+#define EM_H8_300H      47
+#define EM_H8S          48
+#define EM_IA_64        50	/* Itanic */
+#define EM_X86_64       62
+#define EM_CRIS         76
+#define EM_V850         87
+#define EM_ALPHA        0x9026	/* Interrim Alpha that stuck around */
+#define EM_CYGNUS_V850  0x9080	/* Old v850 ID used by Cygnus */
+#define EM_S390_OLD     0xA390	/* Obsolete interrim value for S/390 */
+
+/* Dynamic type values */
+#define DT_NULL		0
+#define DT_NEEDED	1
+#define DT_PLTRELSZ	2
+#define DT_PLTGOT	3
+#define DT_HASH		4
+#define DT_STRTAB	5
+#define DT_SYMTAB	6
+#define DT_RELA		7
+#define DT_RELASZ	8
+#define DT_RELAENT	9
+#define DT_STRSZ	10
+#define DT_SYMENT	11
+#define DT_INIT		12
+#define DT_FINI		13
+#define DT_SONAME	14
+#define DT_RPATH	15
+#define DT_SYMBOLIC	16
+#define DT_REL		17
+#define DT_RELSZ	18
+#define DT_RELENT	19
+#define DT_PLTREL	20
+#define DT_DEBUG	21
+#define DT_TEXTREL	22
+#define DT_JMPREL	23
+#define DT_LOPROC	0x70000000
+#define DT_HIPROC	0x7fffffff
+
+/* Auxilliary table entries */
+#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_PLATFORM	15	/* string identifying CPU for optimizations */
+#define AT_HWCAP  	16	/* arch dependent hints at CPU capabilities */
+#define AT_CLKTCK 	17	/* frequency at which times() increments */
+/* 18..22 = ? */
+#define AT_SECURE 	23	/* secure mode boolean */
+
+/* Program header permission flags */
+#define PF_X            0x1
+#define PF_W            0x2
+#define PF_R            0x4
+
+/* Section header types */
+#define SHT_NULL        0
+#define SHT_PROGBITS    1
+#define SHT_SYMTAB      2
+#define SHT_STRTAB      3
+#define SHT_RELA        4
+#define SHT_HASH        5
+#define SHT_DYNAMIC     6
+#define SHT_NOTE        7
+#define SHT_NOBITS      8
+#define SHT_REL         9
+#define SHT_SHLIB       10
+#define SHT_DYNSYM      11
+#define SHT_NUM         12
+#define SHT_LOPROC      0x70000000
+#define SHT_HIPROC      0x7fffffff
+#define SHT_LOUSER      0x80000000
+#define SHT_HIUSER      0xffffffff
+
+/* Section header flags */
+#define SHF_WRITE       0x1
+#define SHF_ALLOC       0x2
+#define SHF_EXECINSTR   0x4
+#define SHF_MASKPROC    0xf0000000
+
+/* Special section numbers */
+#define SHN_UNDEF       0
+#define SHN_LORESERVE   0xff00
+#define SHN_LOPROC      0xff00
+#define SHN_HIPROC      0xff1f
+#define SHN_ABS         0xfff1
+#define SHN_COMMON      0xfff2
+#define SHN_HIRESERVE   0xffff
+
+/* Lenght of magic at the start of a file */
+#define EI_NIDENT	16
+
+/* Magic number constants... */
+#define EI_MAG0         0	/* e_ident[] indexes */
+#define EI_MAG1         1
+#define EI_MAG2         2
+#define EI_MAG3         3
+#define EI_CLASS        4
+#define EI_DATA         5
+#define EI_VERSION      6
+#define EI_OSABI        7
+#define EI_PAD          8
+
+#define ELFMAG0         0x7f	/* EI_MAG */
+#define ELFMAG1         'E'
+#define ELFMAG2         'L'
+#define ELFMAG3         'F'
+#define ELFMAG          "\177ELF"
+#define SELFMAG         4
+
+#define ELFCLASSNONE    0	/* EI_CLASS */
+#define ELFCLASS32      1
+#define ELFCLASS64      2
+#define ELFCLASSNUM     3
+
+#define ELFDATANONE     0	/* e_ident[EI_DATA] */
+#define ELFDATA2LSB     1
+#define ELFDATA2MSB     2
+
+#define EV_NONE         0	/* e_version, EI_VERSION */
+#define EV_CURRENT      1
+#define EV_NUM          2
+
+#define ELFOSABI_NONE   0
+#define ELFOSABI_LINUX  3
+
+#endif				/* _SYS_ELFCOMMON_H */
diff --git a/usr/include/sys/fsuid.h b/usr/include/sys/fsuid.h
new file mode 100644
index 0000000..d64e28b
--- /dev/null
+++ b/usr/include/sys/fsuid.h
@@ -0,0 +1,14 @@
+/*
+ * sys/fsuid.h
+ */
+
+#ifndef _SYS_FSUID_H
+#define _SYS_FSUID_H
+
+#include <klibc/extern.h>
+#include <sys/types.h>
+
+__extern int setfsuid(uid_t);
+__extern int setfsgid(gid_t);
+
+#endif				/* _SYS_FSUID_H */
diff --git a/usr/include/sys/inotify.h b/usr/include/sys/inotify.h
new file mode 100644
index 0000000..e08cb05
--- /dev/null
+++ b/usr/include/sys/inotify.h
@@ -0,0 +1,16 @@
+/*
+ * sys/inotify.h
+ */
+
+#ifndef _SYS_INOTIFY_H
+#define _SYS_INOTIFY_H
+
+#include <sys/types.h>
+#include <linux/inotify.h>
+#include <klibc/extern.h>
+
+__extern int inotify_init(void);
+__extern int inotify_add_watch(int, const char *, __u32);
+__extern int inotify_rm_watch(int, __u32);
+
+#endif				/* _SYS_INOTIFY_H */
diff --git a/usr/include/sys/ioctl.h b/usr/include/sys/ioctl.h
new file mode 100644
index 0000000..559f111
--- /dev/null
+++ b/usr/include/sys/ioctl.h
@@ -0,0 +1,14 @@
+/*
+ * sys/ioctl.h
+ */
+
+#ifndef _SYS_IOCTL_H
+#define _SYS_IOCTL_H
+
+#include <klibc/extern.h>
+#include <linux/ioctl.h>
+#include <asm/ioctls.h>
+
+__extern int ioctl(int, int, void *);
+
+#endif				/* _SYS_IOCTL_H */
diff --git a/usr/include/sys/klog.h b/usr/include/sys/klog.h
new file mode 100644
index 0000000..02c7217
--- /dev/null
+++ b/usr/include/sys/klog.h
@@ -0,0 +1,24 @@
+/*
+ * sys/klog.h
+ */
+
+#ifndef _SYS_KLOG_H
+#define _SYS_KLOG_H
+
+#include <klibc/extern.h>
+
+#define KLOG_CLOSE	0
+#define KLOG_OPEN	1
+#define KLOG_READ	2
+#define KLOG_READ_ALL	3
+#define KLOG_READ_CLEAR	4
+#define KLOG_CLEAR	5
+#define KLOG_DISABLE	6
+#define KLOG_ENABLE	7
+#define KLOG_SETLEVEL	8
+#define KLOG_UNREADSIZE	9
+#define KLOG_WRITE	10
+
+__extern int klogctl(int, char *, int);
+
+#endif				/* _SYS_KLOG_H */
diff --git a/usr/include/sys/md.h b/usr/include/sys/md.h
new file mode 100644
index 0000000..184e4aa
--- /dev/null
+++ b/usr/include/sys/md.h
@@ -0,0 +1,32 @@
+/* ----------------------------------------------------------------------- *
+ *
+ *   Copyright 2006 H. Peter Anvin - All Rights Reserved
+ *
+ *   This program is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation, Inc., 53 Temple Place Ste 330,
+ *   Boston MA 02111-1307, USA; either version 2 of the License, or
+ *   (at your option) any later version; incorporated herein by reference.
+ *
+ * ----------------------------------------------------------------------- */
+
+/*
+ * sys/md.h
+ *
+ * Defines for the Linux md functionality.  Some of this stuff is
+ * userspace-visible but lives in md_k.h, which is user-space unsafe.
+ * Sigh.
+ */
+
+#ifndef _SYS_MD_H
+#define _SYS_MD_H
+
+#define LEVEL_MULTIPATH         (-4)
+#define LEVEL_LINEAR            (-1)
+#define LEVEL_FAULTY            (-5)
+#define MAX_MD_DEVS  256	/* Max number of md dev */
+
+#include <linux/raid/md_u.h>
+#include <linux/raid/md_p.h>
+
+#endif				/* _SYS_MD_H */
diff --git a/usr/include/sys/mman.h b/usr/include/sys/mman.h
new file mode 100644
index 0000000..56f0b65
--- /dev/null
+++ b/usr/include/sys/mman.h
@@ -0,0 +1,26 @@
+/*
+ * sys/mman.h
+ */
+
+#ifndef _SYS_MMAN_H
+#define _SYS_MMAN_H
+
+#include <klibc/extern.h>
+#include <sys/types.h>
+#include <asm/mman.h>
+
+#define MAP_FAILED ((void *)-1)
+
+__extern void *mmap(void *, size_t, int, int, int, off_t);
+__extern int munmap(void *, size_t);
+__extern void *mremap(void *, size_t, size_t, unsigned long);
+__extern int shm_open(const char *, int, mode_t);
+__extern int shm_unlink(const char *);
+__extern int msync(const void *, size_t, int);
+__extern int mprotect(const void *, size_t, int);
+__extern int mlockall(int);
+__extern int munlockall(void);
+__extern int mlock(const void *, size_t);
+__extern int munlock(const void *, size_t);
+
+#endif				/* _SYS_MMAN_H */
diff --git a/usr/include/sys/mount.h b/usr/include/sys/mount.h
new file mode 100644
index 0000000..9d6b0ee
--- /dev/null
+++ b/usr/include/sys/mount.h
@@ -0,0 +1,71 @@
+/*
+ * sys/mount.h
+ */
+
+#ifndef _SYS_MOUNT_H
+#define _SYS_MOUNT_H
+
+#include <klibc/extern.h>
+#include <sys/ioctl.h>
+
+/*
+ * These are the fs-independent mount-flags: up to 32 flags are supported
+ */
+#define MS_RDONLY       0x0001	/* Mount read-only */
+#define MS_NOSUID       0x0002	/* Ignore suid and sgid bits */
+#define MS_NODEV        0x0004	/* Disallow access to device special files */
+#define MS_NOEXEC       0x0008	/* Disallow program execution */
+#define MS_SYNCHRONOUS  0x0010	/* Writes are synced at once */
+#define MS_REMOUNT      0x0020	/* Alter flags of a mounted FS */
+#define MS_MANDLOCK     0x0040	/* Allow mandatory locks on an FS */
+#define MS_DIRSYNC      0x0080	/* Directory modifications are synchronous */
+#define MS_NOATIME      0x0400	/* Do not update access times. */
+#define MS_NODIRATIME   0x0800	/* Do not update directory access times */
+#define MS_BIND         0x1000
+#define MS_MOVE         0x2000
+#define MS_REC          0x4000
+#define MS_VERBOSE      0x8000
+#define MS_POSIXACL     (1<<16)	/* VFS does not apply the umask */
+#define MS_ONE_SECOND   (1<<17)	/* fs has 1 sec a/m/ctime resolution */
+#define MS_ACTIVE       (1<<30)
+#define MS_NOUSER       (1<<31)
+
+/*
+ * Superblock flags that can be altered by MS_REMOUNT
+ */
+#define MS_RMT_MASK     (MS_RDONLY|MS_SYNCHRONOUS|MS_MANDLOCK|MS_NOATIME|MS_NODIRATIME)
+
+/*
+ * Old magic mount flag and mask
+ */
+#define MS_MGC_VAL 0xC0ED0000
+#define MS_MGC_MSK 0xffff0000
+
+/*
+ * umount2() flags
+ */
+#define MNT_FORCE	1	/* Forcibly unmount */
+#define MNT_DETACH	2	/* Detach from tree only */
+#define MNT_EXPIRE	4	/* Mark for expiry */
+
+/*
+ * Block device ioctls
+ */
+#define BLKROSET   _IO(0x12, 93)	/* Set device read-only (0 = read-write).  */
+#define BLKROGET   _IO(0x12, 94)	/* Get read-only status (0 = read_write).  */
+#define BLKRRPART  _IO(0x12, 95)	/* Re-read partition table.  */
+#define BLKGETSIZE _IO(0x12, 96)	/* Return device size.  */
+#define BLKFLSBUF  _IO(0x12, 97)	/* Flush buffer cache.  */
+#define BLKRASET   _IO(0x12, 98)	/* Set read ahead for block device.  */
+#define BLKRAGET   _IO(0x12, 99)	/* Get current read ahead setting.  */
+
+/*
+ * Prototypes
+ */
+__extern int mount(const char *, const char *,
+		   const char *, unsigned long, const void *);
+__extern int umount(const char *);
+__extern int umount2(const char *, int);
+__extern int pivot_root(const char *, const char *);
+
+#endif				/* _SYS_MOUNT_H */
diff --git a/usr/include/sys/param.h b/usr/include/sys/param.h
new file mode 100644
index 0000000..fb3b2e4
--- /dev/null
+++ b/usr/include/sys/param.h
@@ -0,0 +1,11 @@
+/*
+ * sys/param.h
+ */
+
+#ifndef _SYS_PARAM_H
+#define _SYS_PARAM_H
+
+#include <limits.h>
+#include <linux/param.h>
+
+#endif				/* _SYS_PARAM_H */
diff --git a/usr/include/sys/poll.h b/usr/include/sys/poll.h
new file mode 100644
index 0000000..f0c60c2
--- /dev/null
+++ b/usr/include/sys/poll.h
@@ -0,0 +1,20 @@
+/*
+ * poll.h
+ */
+
+#ifndef _POLL_H
+#define _POLL_H
+
+#include <klibc/extern.h>
+#include <sys/time.h>
+#include <signal.h>
+#include <linux/poll.h>
+
+/* POSIX specifies "int" for the timeout, Linux seems to use long... */
+
+typedef unsigned int nfds_t;
+__extern int poll(struct pollfd *, nfds_t, long);
+__extern int ppoll(struct pollfd *, nfds_t, struct timespec *,
+		   const sigset_t *);
+
+#endif				/* _POLL_H */
diff --git a/usr/include/sys/prctl.h b/usr/include/sys/prctl.h
new file mode 100644
index 0000000..c12c191
--- /dev/null
+++ b/usr/include/sys/prctl.h
@@ -0,0 +1,10 @@
+#ifndef _SYS_PRCTL_H
+#define _SYS_PRCTL_H
+
+#include <klibc/extern.h>
+#include <linux/prctl.h>
+
+/* glibc has this as a varadic function, so join the club... */
+__extern int prctl(int, ...);
+
+#endif /* _SYS_PRCTL_H */
diff --git a/usr/include/sys/reboot.h b/usr/include/sys/reboot.h
new file mode 100644
index 0000000..3337d27
--- /dev/null
+++ b/usr/include/sys/reboot.h
@@ -0,0 +1,25 @@
+/*
+ * sys/reboot.h
+ */
+
+#ifndef _SYS_REBOOT_H
+#define _SYS_REBOOT_H
+
+#include <klibc/extern.h>
+#include <linux/reboot.h>
+
+/* glibc names these constants differently; allow both versions */
+
+#define RB_AUTOBOOT	LINUX_REBOOT_CMD_RESTART
+#define RB_HALT_SYSTEM	LINUX_REBOOT_CMD_HALT
+#define RB_ENABLE_CAD	LINUX_REBOOT_CMD_CAD_ON
+#define RB_DISABLE_CAD	LINUX_REBOOT_CMD_CAD_OFF
+#define RB_POWER_OFF	LINUX_REBOOT_CMD_POWER_OFF
+
+/* glibc-ish one-argument version */
+__extern int reboot(int);
+
+/* Native four-argument system call */
+__extern int __reboot(int, int, int, void *);
+
+#endif				/* _SYS_REBOOT_H */
diff --git a/usr/include/sys/resource.h b/usr/include/sys/resource.h
new file mode 100644
index 0000000..41cefb4
--- /dev/null
+++ b/usr/include/sys/resource.h
@@ -0,0 +1,15 @@
+/*
+ * sys/resource.h
+ */
+
+#ifndef _SYS_RESOURCE_H
+#define _SYS_RESOURCE_H
+
+#include <klibc/extern.h>
+#include <sys/types.h>		/* MUST be included before linux/resource.h */
+#include <linux/resource.h>
+
+__extern int getpriority(int, int);
+__extern int setpriority(int, int, int);
+
+#endif				/* _SYS_RESOURCE_H */
diff --git a/usr/include/sys/select.h b/usr/include/sys/select.h
new file mode 100644
index 0000000..cc4e00e
--- /dev/null
+++ b/usr/include/sys/select.h
@@ -0,0 +1,17 @@
+/*
+ * sys/select.h
+ */
+
+#ifndef _SYS_SELECT_H
+#define _SYS_SELECT_H
+
+#include <klibc/extern.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <signal.h>
+
+__extern int select(int, fd_set *, fd_set *, fd_set *, struct timeval *);
+__extern int pselect(int, fd_set *, fd_set *, fd_set *,
+		     const struct timespec *, const sigset_t *);
+
+#endif				/* _SYS_SELECT_H */
diff --git a/usr/include/sys/sendfile.h b/usr/include/sys/sendfile.h
new file mode 100644
index 0000000..a745f10
--- /dev/null
+++ b/usr/include/sys/sendfile.h
@@ -0,0 +1,14 @@
+/*
+ * sys/sendfile.h
+ */
+
+#ifndef _SYS_SENDFILE_H
+#define _SYS_SENDFILE_H
+
+#include <klibc/extern.h>
+#include <stddef.h>
+#include <sys/types.h>
+
+__extern ssize_t sendfile(int, int, off_t *, size_t, off_t);
+
+#endif /* _SYS_SENDFILE_H */
diff --git a/usr/include/sys/socket.h b/usr/include/sys/socket.h
new file mode 100644
index 0000000..7d47087
--- /dev/null
+++ b/usr/include/sys/socket.h
@@ -0,0 +1,52 @@
+/*
+ * sys/socket.h
+ */
+
+#ifndef _SYS_SOCKET_H
+#define _SYS_SOCKET_H
+
+#include <klibc/extern.h>
+#include <klibc/compiler.h>
+#include <klibc/sysconfig.h>
+#include <linux/socket.h>
+#if _KLIBC_HAS_ARCHSOCKET_H
+#include <klibc/archsocket.h>
+#endif
+
+/* Great job, guys!  These are *architecture-specific* ABI constants,
+   that are hidden under #ifdef __KERNEL__... what a brilliant idea!
+   These are the "common" definitions; if not appropriate, override
+   them in <klibc/archsocket.h>. */
+   
+#ifndef SOCK_STREAM
+# define SOCK_STREAM    1
+# define SOCK_DGRAM     2
+# define SOCK_RAW       3
+# define SOCK_RDM       4
+# define SOCK_SEQPACKET 5
+# define SOCK_PACKET    10
+#endif
+
+typedef int socklen_t;
+
+__extern int socket(int, int, int);
+__extern int bind(int, struct sockaddr *, int);
+__extern int connect(int, struct sockaddr *, socklen_t);
+__extern int listen(int, int);
+__extern int accept(int, struct sockaddr *, socklen_t *);
+__extern int getsockname(int, struct sockaddr *, socklen_t *);
+__extern int getpeername(int, struct sockaddr *, socklen_t *);
+__extern int socketpair(int, int, int, int *);
+__extern int send(int, const void *, size_t, unsigned int);
+__extern int sendto(int, const void *, size_t, int, const struct sockaddr *,
+			socklen_t);
+__extern int recv(int, void *, size_t, unsigned int);
+__extern int recvfrom(int, void *, size_t, unsigned int, struct sockaddr *,
+			  socklen_t *);
+__extern int shutdown(int, int);
+__extern int setsockopt(int, int, int, const void *, socklen_t);
+__extern int getsockopt(int, int, int, void *, socklen_t *);
+__extern int sendmsg(int, const struct msghdr *, unsigned int);
+__extern int recvmsg(int, struct msghdr *, unsigned int);
+
+#endif				/* _SYS_SOCKET_H */
diff --git a/usr/include/sys/socketcalls.h b/usr/include/sys/socketcalls.h
new file mode 100644
index 0000000..1c4367d
--- /dev/null
+++ b/usr/include/sys/socketcalls.h
@@ -0,0 +1,28 @@
+/*
+ * sys/socketcalls.h
+ */
+
+#ifndef _SYS_SOCKETCALLS_H
+#define _SYS_SOCKETCALLS_H
+
+/* socketcalls by number, since <linux/net.h> isn't usable for assembly */
+
+#define SYS_SOCKET      1	/* sys_socket(2)                */
+#define SYS_BIND        2	/* sys_bind(2)                  */
+#define SYS_CONNECT     3	/* sys_connect(2)               */
+#define SYS_LISTEN      4	/* sys_listen(2)                */
+#define SYS_ACCEPT      5	/* sys_accept(2)                */
+#define SYS_GETSOCKNAME 6	/* sys_getsockname(2)           */
+#define SYS_GETPEERNAME 7	/* sys_getpeername(2)           */
+#define SYS_SOCKETPAIR  8	/* sys_socketpair(2)            */
+#define SYS_SEND        9	/* sys_send(2)                  */
+#define SYS_RECV        10	/* sys_recv(2)                  */
+#define SYS_SENDTO      11	/* sys_sendto(2)                */
+#define SYS_RECVFROM    12	/* sys_recvfrom(2)              */
+#define SYS_SHUTDOWN    13	/* sys_shutdown(2)              */
+#define SYS_SETSOCKOPT  14	/* sys_setsockopt(2)            */
+#define SYS_GETSOCKOPT  15	/* sys_getsockopt(2)            */
+#define SYS_SENDMSG     16	/* sys_sendmsg(2)               */
+#define SYS_RECVMSG     17	/* sys_recvmsg(2)               */
+
+#endif				/* _SYS_SOCKETCALLS_H */
diff --git a/usr/include/sys/splice.h b/usr/include/sys/splice.h
new file mode 100644
index 0000000..1fa26d91
--- /dev/null
+++ b/usr/include/sys/splice.h
@@ -0,0 +1,19 @@
+/*
+ * sys/splice.h
+ */
+
+#ifndef _SYS_SPLICE_H
+#define _SYS_SPLICE_H
+
+/* move pages instead of copying */
+#define SPLICE_F_MOVE		1
+/* don't block on the pipe splicing (but we may still block on the fd
+   we splice from/to, of course */
+#define SPLICE_F_NONBLOCK	2
+/* expect more data */
+#define SPLICE_F_MORE		4
+
+__extern int splice(int, off_t *, int, off_t *, size_t, unsigned int);
+__extern int tee(int, int, size_t, unsigned int);
+
+#endif				/* _SYS_SPLICE_H */
diff --git a/usr/include/sys/stat.h b/usr/include/sys/stat.h
new file mode 100644
index 0000000..33182fc
--- /dev/null
+++ b/usr/include/sys/stat.h
@@ -0,0 +1,78 @@
+/*
+ * sys/stat.h
+ */
+
+#ifndef _SYS_STAT_H
+#define _SYS_STAT_H
+
+#include <klibc/extern.h>
+#include <sys/types.h>
+#include <sys/time.h>		/* For struct timespec */
+#include <klibc/archstat.h>
+
+/* 2.6.21 kernels have once again hidden a bunch of stuff... */
+#ifndef S_IFMT
+
+#define S_IFMT  00170000
+#define S_IFSOCK 0140000
+#define S_IFLNK	 0120000
+#define S_IFREG  0100000
+#define S_IFBLK  0060000
+#define S_IFDIR  0040000
+#define S_IFCHR  0020000
+#define S_IFIFO  0010000
+#define S_ISUID  0004000
+#define S_ISGID  0002000
+#define S_ISVTX  0001000
+
+#define S_ISLNK(m)	(((m) & S_IFMT) == S_IFLNK)
+#define S_ISREG(m)	(((m) & S_IFMT) == S_IFREG)
+#define S_ISDIR(m)	(((m) & S_IFMT) == S_IFDIR)
+#define S_ISCHR(m)	(((m) & S_IFMT) == S_IFCHR)
+#define S_ISBLK(m)	(((m) & S_IFMT) == S_IFBLK)
+#define S_ISFIFO(m)	(((m) & S_IFMT) == S_IFIFO)
+#define S_ISSOCK(m)	(((m) & S_IFMT) == S_IFSOCK)
+
+#define S_IRWXU 00700
+#define S_IRUSR 00400
+#define S_IWUSR 00200
+#define S_IXUSR 00100
+
+#define S_IRWXG 00070
+#define S_IRGRP 00040
+#define S_IWGRP 00020
+#define S_IXGRP 00010
+
+#define S_IRWXO 00007
+#define S_IROTH 00004
+#define S_IWOTH 00002
+#define S_IXOTH 00001
+
+#define S_IRWXUGO	(S_IRWXU|S_IRWXG|S_IRWXO)
+#define S_IALLUGO	(S_ISUID|S_ISGID|S_ISVTX|S_IRWXUGO)
+#define S_IRUGO		(S_IRUSR|S_IRGRP|S_IROTH)
+#define S_IWUGO		(S_IWUSR|S_IWGRP|S_IWOTH)
+#define S_IXUGO		(S_IXUSR|S_IXGRP|S_IXOTH)
+
+#endif
+
+#ifdef _STATBUF_ST_NSEC
+  /* struct stat has struct timespec instead of time_t */
+# define st_atime  st_atim.tv_sec
+# define st_mtime  st_mtim.tv_sec
+# define st_ctime  st_ctim.tv_sec
+#endif
+
+__extern int stat(const char *, struct stat *);
+__extern int fstat(int, struct stat *);
+__extern int fstatat(int, const char *, struct stat *, int);
+__extern int lstat(const char *, struct stat *);
+__extern mode_t umask(mode_t);
+__extern int mknod(const char *, mode_t, dev_t);
+__extern int mknodat(int, const char *, const char *, mode_t, dev_t);
+static __inline__ int mkfifo(const char *__p, mode_t __m)
+{
+	return mknod(__p, (__m & ~S_IFMT) | S_IFIFO, (dev_t) 0);
+}
+
+#endif				/* _SYS_STAT_H */
diff --git a/usr/include/sys/statfs.h b/usr/include/sys/statfs.h
new file mode 100644
index 0000000..53b3b5e
--- /dev/null
+++ b/usr/include/sys/statfs.h
@@ -0,0 +1 @@
+#include <sys/vfs.h>
diff --git a/usr/include/sys/syscall.h b/usr/include/sys/syscall.h
new file mode 100644
index 0000000..8fe0142
--- /dev/null
+++ b/usr/include/sys/syscall.h
@@ -0,0 +1,13 @@
+/*
+ * sys/syscall.h
+ *
+ * Generic system call interface macros
+ */
+#ifndef _SYS_SYSCALL_H
+#define _SYS_SYSCALL_H
+
+#include <errno.h>
+#include <sys/types.h>
+#include <asm/unistd.h>
+
+#endif				/* _SYS_SYSCALL_H */
diff --git a/usr/include/sys/sysinfo.h b/usr/include/sys/sysinfo.h
new file mode 100644
index 0000000..dba68dc
--- /dev/null
+++ b/usr/include/sys/sysinfo.h
@@ -0,0 +1,12 @@
+/*
+ * sys/sysinfo.h
+ */
+
+#ifndef _SYS_SYSINFO_H
+#define _SYS_SYSINFO_H
+
+#include <linux/kernel.h>
+
+extern int sysinfo(struct sysinfo *info);
+
+#endif				/* _SYS_SYSINFO_H */
diff --git a/usr/include/sys/sysmacros.h b/usr/include/sys/sysmacros.h
new file mode 100644
index 0000000..c344339
--- /dev/null
+++ b/usr/include/sys/sysmacros.h
@@ -0,0 +1,34 @@
+/*
+ * sys/sysmacros.h
+ *
+ * Constructs to create and pick apart dev_t.  The double-underscore
+ * versions are macros so they can be used as constants.
+ */
+
+#ifndef _SYS_SYSMACROS_H
+#define _SYS_SYSMACROS_H
+
+#ifndef _SYS_TYPES_H
+# include <sys/types.h>
+#endif
+
+#define __major(__d) (((__d) >> 8) & 0xfff)
+static __inline__ int major(dev_t __d)
+{
+	return __major(__d);
+}
+
+#define __minor(__d) (((__d) & 0xff)|(((__d) >> 12) & 0xfff00))
+static __inline__ int minor(dev_t __d)
+{
+	return __minor(__d);
+}
+
+#define __makedev(__ma, __mi) \
+	((((__ma) & 0xfff) << 8)|((__mi) & 0xff)|(((__mi) & 0xfff00) << 12))
+static __inline__ dev_t makedev(int __ma, int __mi)
+{
+	return __makedev(__ma, __mi);
+}
+
+#endif				/* _SYS_SYSMACROS_H */
diff --git a/usr/include/sys/time.h b/usr/include/sys/time.h
new file mode 100644
index 0000000..7a2f8b9
--- /dev/null
+++ b/usr/include/sys/time.h
@@ -0,0 +1,54 @@
+/*
+ * sys/time.h
+ */
+
+#ifndef _SYS_TIME_H
+#define _SYS_TIME_H
+
+#include <klibc/extern.h>
+#include <stddef.h>
+#include <sys/types.h>
+#include <linux/time.h>
+
+/* The 2.6.20 Linux headers always #define FD_ZERO __FD_ZERO, etc, in
+   <linux/time.h> but not all architectures define the
+   double-underscore ones, except __NFDBITS, __FD_SETSIZE and
+   __FDSET_LONGS which are defined in <linux/posix_types.h>.
+
+   Unfortunately, some architectures define the double-underscore ones
+   as inlines, so we can't use a simple #ifdef test.  Thus, the only
+   safe option remaining is to #undef the top-level macros. */
+
+#undef FD_ZERO
+#undef FD_SET
+#undef FD_CLR
+#undef FD_ISSET
+
+__extern void *memset(void *, int, size_t);
+static inline void FD_ZERO(fd_set *__fdsetp)
+{
+	memset(__fdsetp, 0, sizeof(fd_set));
+}
+static inline void FD_SET(int __fd, fd_set *__fdsetp)
+{
+	__fdsetp->fds_bits[__fd/BITS_PER_LONG] |=
+		(1UL << (__fd % BITS_PER_LONG));
+}
+static inline void FD_CLR(int __fd, fd_set *__fdsetp)
+{
+	__fdsetp->fds_bits[__fd/BITS_PER_LONG] &=
+		~(1UL << (__fd % BITS_PER_LONG));
+}
+static inline int FD_ISSET(int __fd, fd_set *__fdsetp)
+{
+	return (__fdsetp->fds_bits[__fd/BITS_PER_LONG] >>
+		(__fd % BITS_PER_LONG)) & 1;
+}
+
+__extern int gettimeofday(struct timeval *, struct timezone *);
+__extern int settimeofday(const struct timeval *, const struct timezone *);
+__extern int getitimer(int, struct itimerval *);
+__extern int setitimer(int, const struct itimerval *, struct itimerval *);
+__extern int utimes(const char *, const struct timeval *);
+
+#endif				/* _SYS_TIME_H */
diff --git a/usr/include/sys/times.h b/usr/include/sys/times.h
new file mode 100644
index 0000000..16be69a
--- /dev/null
+++ b/usr/include/sys/times.h
@@ -0,0 +1,14 @@
+/*
+ * sys/times.h
+ */
+
+#ifndef _SYS_TIMES_H
+#define _SYS_TIMES_H
+
+#include <klibc/extern.h>
+#include <sys/types.h>
+#include <linux/times.h>
+
+__extern clock_t times(struct tms *);
+
+#endif				/* _SYS_TIMES_H */
diff --git a/usr/include/sys/types.h b/usr/include/sys/types.h
new file mode 100644
index 0000000..6780ed1
--- /dev/null
+++ b/usr/include/sys/types.h
@@ -0,0 +1,115 @@
+/*
+ * sys/types.h
+ */
+
+#ifndef _SYS_TYPES_H
+#define _SYS_TYPES_H
+
+#include <klibc/compiler.h>
+#include <stddef.h>
+#include <stdint.h>
+
+#define _SSIZE_T
+typedef ptrdiff_t ssize_t;
+
+#include <linux/posix_types.h>
+#include <asm/types.h>
+
+/* Keeps linux/types.h from getting included elsewhere */
+#define _LINUX_TYPES_H
+
+typedef __kernel_fd_set fd_set;
+typedef uint32_t dev_t;
+typedef __kernel_ino_t ino_t;
+typedef __kernel_mode_t mode_t;
+typedef __kernel_nlink_t nlink_t;
+typedef __kernel_loff_t off_t;
+typedef __kernel_loff_t loff_t;
+typedef __kernel_pid_t pid_t;
+typedef __kernel_daddr_t daddr_t;
+typedef __kernel_key_t key_t;
+typedef __kernel_suseconds_t suseconds_t;
+/* typedef __kernel_timer_t	timer_t; */
+typedef int timer_t;
+
+typedef __kernel_uid32_t uid_t;
+typedef __kernel_gid32_t gid_t;
+
+typedef __kernel_fsid_t fsid_t;
+
+/*
+ * The following typedefs are also protected by individual ifdefs for
+ * historical reasons:
+ */
+#ifndef _SIZE_T
+#define _SIZE_T
+typedef __kernel_size_t size_t;
+#endif
+
+#ifndef _SSIZE_T
+#define _SSIZE_T
+typedef __kernel_ssize_t ssize_t;
+#endif
+
+#ifndef _PTRDIFF_T
+#define _PTRDIFF_T
+typedef __kernel_ptrdiff_t ptrdiff_t;
+#endif
+
+#ifndef _TIME_T
+#define _TIME_T
+typedef __kernel_time_t time_t;
+#endif
+
+#ifndef _CLOCK_T
+#define _CLOCK_T
+typedef __kernel_clock_t clock_t;
+#endif
+
+#ifndef _CADDR_T
+#define _CADDR_T
+typedef __kernel_caddr_t caddr_t;
+#endif
+
+/* BSD */
+typedef unsigned char u_char;
+typedef unsigned short u_short;
+typedef unsigned int u_int;
+typedef unsigned long u_long;
+
+/* SysV */
+typedef unsigned char unchar;
+typedef unsigned short ushort;
+typedef unsigned int uint;
+typedef unsigned long ulong;
+
+/* More BSD */
+typedef uint8_t u_int8_t;
+typedef uint16_t u_int16_t;
+typedef uint32_t u_int32_t;
+typedef uint64_t u_int64_t;
+
+typedef uint16_t __bitwise __le16;
+typedef uint16_t __bitwise __be16;
+typedef uint32_t __bitwise __le32;
+typedef uint32_t __bitwise __be32;
+typedef uint64_t __bitwise __le64;
+typedef uint64_t __bitwise __be64;
+
+typedef uint16_t __sum16;
+typedef uint32_t __sum32;
+typedef uint64_t __sum64;
+
+/*
+ * Some headers seem to require this...
+ */
+#ifndef BITS_PER_LONG
+# define BITS_PER_LONG _BITSIZE
+#endif
+
+/*
+ * Some apps want this in <sys/types.h>
+ */
+#include <sys/sysmacros.h>
+
+#endif
diff --git a/usr/include/sys/uio.h b/usr/include/sys/uio.h
new file mode 100644
index 0000000..ee341fb
--- /dev/null
+++ b/usr/include/sys/uio.h
@@ -0,0 +1,15 @@
+/*
+ * sys/uio.h
+ */
+
+#ifndef _SYS_UIO_H
+#define _SYS_UIO_H
+
+#include <klibc/extern.h>
+#include <sys/types.h>
+#include <linux/uio.h>
+
+__extern int readv(int, const struct iovec *, int);
+__extern int writev(int, const struct iovec *, int);
+
+#endif				/* _SYS_UIO_H */
diff --git a/usr/include/sys/un.h b/usr/include/sys/un.h
new file mode 100644
index 0000000..252d87b
--- /dev/null
+++ b/usr/include/sys/un.h
@@ -0,0 +1,10 @@
+/*
+ * <sys/un.h>
+ */
+
+#ifndef _SYS_UN_H
+#define _SYS_UN_H
+
+#include <linux/un.h>
+
+#endif				/* _SYS_UN_H */
diff --git a/usr/include/sys/utime.h b/usr/include/sys/utime.h
new file mode 100644
index 0000000..56288a8
--- /dev/null
+++ b/usr/include/sys/utime.h
@@ -0,0 +1,10 @@
+/*
+ * sys/utime.h
+ */
+
+#ifndef _SYS_UTIME_H
+#define _SYS_UTIME_H
+
+#include <linux/utime.h>
+
+#endif				/* _SYS_UTIME_H */
diff --git a/usr/include/sys/utsname.h b/usr/include/sys/utsname.h
new file mode 100644
index 0000000..fd55c0b
--- /dev/null
+++ b/usr/include/sys/utsname.h
@@ -0,0 +1,23 @@
+/*
+ * sys/utsname.h
+ */
+
+#ifndef _SYS_UTSNAME_H
+#define _SYS_UTSNAME_H
+
+#include <klibc/extern.h>
+
+#define SYS_NMLN 65
+
+struct utsname {
+	char sysname[SYS_NMLN];
+	char nodename[SYS_NMLN];
+	char release[SYS_NMLN];
+	char version[SYS_NMLN];
+	char machine[SYS_NMLN];
+	char domainname[SYS_NMLN];
+};
+
+__extern int uname(struct utsname *);
+
+#endif				/* _SYS_UTSNAME_H */
diff --git a/usr/include/sys/vfs.h b/usr/include/sys/vfs.h
new file mode 100644
index 0000000..6fb1eab
--- /dev/null
+++ b/usr/include/sys/vfs.h
@@ -0,0 +1,132 @@
+/*
+ * sys/vfs.h
+ */
+
+#ifndef _SYS_VFS_H
+#define _SYS_VFS_H
+
+#include <stdint.h>
+#include <klibc/extern.h>
+#include <sys/types.h>
+#include <bitsize.h>
+#include <klibc/sysconfig.h>
+
+/* struct statfs64 -- there seems to be two standards -
+   one for 32 and one for 64 bits, and they're incompatible.
+   Worse, some 64-bit platforms seem to use the 32-bit layout.
+   Of course, there is no includable header that does this well. */
+
+#if _KLIBC_STATFS_F_TYPE_64
+
+struct statfs {
+	uint64_t f_type;
+	uint64_t f_bsize;
+	uint64_t f_blocks;
+	uint64_t f_bfree;
+	uint64_t f_bavail;
+	uint64_t f_files;
+	uint64_t f_ffree;
+	__kernel_fsid_t f_fsid;
+	uint64_t f_namelen;
+	uint64_t f_frsize;
+	uint64_t f_spare[5];
+};
+
+#elif _KLIBC_STATFS_F_TYPE_32B
+
+struct statfs {
+	uint32_t f_type;
+	uint32_t f_bsize;
+	uint32_t f_frsize;
+	uint32_t __pad;
+	uint64_t f_blocks;
+	uint64_t f_bfree;
+	uint64_t f_files;
+	uint64_t f_ffree;
+	uint64_t f_bavail;
+	__kernel_fsid_t f_fsid;
+	uint32_t f_namelen;
+	uint32_t f_spare[6];
+};
+
+#else /* not _KLIBC_STATFS_F_TYPE_64 */
+
+struct statfs {
+	uint32_t f_type;
+	uint32_t f_bsize;
+	uint64_t f_blocks;
+	uint64_t f_bfree;
+	uint64_t f_bavail;
+	uint64_t f_files;
+	uint64_t f_ffree;
+	__kernel_fsid_t f_fsid;
+	uint32_t f_namelen;
+	uint32_t f_frsize;
+	uint32_t f_spare[5];
+};
+
+#endif /* _KLIBC_STATFS_F_TYPE_64 */
+
+__extern int statfs(const char *, struct statfs *);
+__extern int fstatfs(int, struct statfs *);
+
+/* Various filesystem types */
+#define ADFS_SUPER_MAGIC	0xadf5
+#define AFFS_SUPER_MAGIC	0xadff
+#define AFS_FS_MAGIC		0x6B414653	/* 'kAFS' */
+#define AUTOFS_SUPER_MAGIC	0x0187
+#define BFS_MAGIC		0x1BADFACE
+#define CAPIFS_SUPER_MAGIC	0x434e
+#define CIFS_MAGIC_NUMBER	0xFF534D42
+#define CODA_SUPER_MAGIC	0x73757245
+#define CRAMFS_MAGIC		0x28cd3d45
+#define DEVFS_SUPER_MAGIC	0x1373
+#define DEVPTS_SUPER_MAGIC	0x1cd1
+#define EFS_SUPER_MAGIC		0x414A53
+#define EVENTPOLLFS_MAGIC	0x03111965
+#define EXT2_SUPER_MAGIC	0xEF53
+#define EXT3_SUPER_MAGIC	0xEF53
+#define GADGETFS_MAGIC		0xaee71ee7
+#define HFSPLUS_SUPER_MAGIC	0x482b
+#define HFS_MFS_SUPER_MAGIC	0xD2D7	/* MFS MDB (super block) */
+#define HFS_SUPER_MAGIC		0x4244	/* "BD": HFS MDB (super block) */
+#define HPFS_SUPER_MAGIC 0xf995e849
+#define HUGETLBFS_MAGIC		0x958458f6
+#define HWGFS_MAGIC		0x12061983
+#define IBMASMFS_MAGIC		0x66726f67
+#define ISOFS_SUPER_MAGIC	0x9660
+#define JFFS2_SUPER_MAGIC	0x72b6
+#define JFFS_MAGIC_BITMASK	0x34383931	/* "1984" */
+#define JFFS_MAGIC_SB_BITMASK	0x07c0	/* 1984 */
+#define JFS_SUPER_MAGIC		0x3153464a	/* "JFS1" */
+#define MINIX2_SUPER_MAGIC	0x2468	/* minix V2 fs */
+#define MINIX2_SUPER_MAGIC2	0x2478	/* minix V2 fs, 30 char names */
+#define MINIX_SUPER_MAGIC	0x137F	/* original minix fs */
+#define MINIX_SUPER_MAGIC2	0x138F	/* minix fs, 30 char names */
+#define MSDOS_SUPER_MAGIC	0x4d44	/* MD */
+#define NCP_SUPER_MAGIC		0x564c
+#define NFS_SUPER_MAGIC		0x6969
+#define NFS_SUPER_MAGIC		0x6969
+#define OPENPROM_SUPER_MAGIC	0x9fa1
+#define OPROFILEFS_MAGIC	0x6f70726f
+#define PFMFS_MAGIC		0xa0b4d889
+#define PIPEFS_MAGIC		0x50495045
+#define PROC_SUPER_MAGIC	0x9fa0
+#define QNX4_SUPER_MAGIC	0x002f	/* qnx4 fs detection */
+#define RAMFS_MAGIC		0x858458f6
+#define REISERFS_SUPER_MAGIC	0x52654973
+#define ROMFS_MAGIC		0x7275
+#define SMB_SUPER_MAGIC		0x517B
+#define SOCKFS_MAGIC		0x534F434B
+#define SYSFS_MAGIC		0x62656572
+#define TMPFS_MAGIC		0x01021994
+#define UDF_SUPER_MAGIC		0x15013346
+#define UFS_MAGIC		0x00011954
+#define UFS_MAGIC_4GB		0x05231994	/* fs > 4 GB && fs_featurebits */
+#define UFS_MAGIC_FEA		0x00195612	/* fs_featurebits supported */
+#define UFS_MAGIC_LFN		0x00095014	/* fs supports filenames > 14 chars */
+#define UFS_MAGIC_SEC		0x00612195	/* B1 security fs */
+#define USBDEVICE_SUPER_MAGIC	0x9fa2
+#define VXFS_SUPER_MAGIC	0xa501FCF5
+
+#endif				/* _SYS_VFS_H */
diff --git a/usr/include/sys/wait.h b/usr/include/sys/wait.h
new file mode 100644
index 0000000..0f5efaf
--- /dev/null
+++ b/usr/include/sys/wait.h
@@ -0,0 +1,28 @@
+/*
+ * sys/wait.h
+ */
+
+#ifndef _SYS_WAIT_H
+#define _SYS_WAIT_H
+
+#include <klibc/extern.h>
+#include <sys/types.h>
+#include <sys/resource.h>
+
+#include <linux/wait.h>
+
+#define WEXITSTATUS(s)	(((s) & 0xff00) >> 8)
+#define WTERMSIG(s)	((s) & 0x7f)
+#define WIFEXITED(s)	(WTERMSIG(s) == 0)
+#define WIFSTOPPED(s)	(WTERMSIG(s) == 0x7f)
+/* Ugly hack to avoid multiple evaluation of "s" */
+#define WIFSIGNALED(s)	(WTERMSIG((s)+1) >= 2)
+#define WCOREDUMP(s)	((s) & 0x80)
+#define WSTOPSIG(s)	WEXITSTATUS(s)
+
+__extern pid_t wait(int *);
+__extern pid_t waitpid(pid_t, int *, int);
+__extern pid_t wait3(int *, int, struct rusage *);
+__extern pid_t wait4(pid_t, int *, int, struct rusage *);
+
+#endif				/* _SYS_WAIT_H */
diff --git a/usr/include/sysexits.h b/usr/include/sysexits.h
new file mode 100644
index 0000000..ef454b9
--- /dev/null
+++ b/usr/include/sysexits.h
@@ -0,0 +1,26 @@
+#ifndef	_SYSEXITS_H
+#define	_SYSEXITS_H
+
+#define EX_OK		0	/* successful termination */
+
+#define EX__BASE	64	/* base value for error messages */
+
+#define EX_USAGE	64	/* command line usage error */
+#define EX_DATAERR	65	/* data format error */
+#define EX_NOINPUT	66	/* cannot open input */
+#define EX_NOUSER	67	/* addressee unknown */
+#define EX_NOHOST	68	/* host name unknown */
+#define EX_UNAVAILABLE	69	/* service unavailable */
+#define EX_SOFTWARE	70	/* internal software error */
+#define EX_OSERR	71	/* system error (e.g., can't fork) */
+#define EX_OSFILE	72	/* critical OS file missing */
+#define EX_CANTCREAT	73	/* can't create (user) output file */
+#define EX_IOERR	74	/* input/output error */
+#define EX_TEMPFAIL	75	/* temp failure; user is invited to retry */
+#define EX_PROTOCOL	76	/* remote error in protocol */
+#define EX_NOPERM	77	/* permission denied */
+#define EX_CONFIG	78	/* configuration error */
+
+#define EX__MAX	78	/* maximum listed value */
+
+#endif /* _SYSEXITS_H */
diff --git a/usr/include/syslog.h b/usr/include/syslog.h
new file mode 100644
index 0000000..71a17e0
--- /dev/null
+++ b/usr/include/syslog.h
@@ -0,0 +1,62 @@
+/*
+ * syslog.h
+ */
+
+#ifndef _SYSLOG_H
+#define _SYSLOG_H
+
+#include <stdio.h>
+#include <klibc/extern.h>
+
+/* Alert levels */
+#define LOG_EMERG	0
+#define LOG_ALERT	1
+#define LOG_CRIT	2
+#define LOG_ERR		3
+#define LOG_WARNING	4
+#define LOG_NOTICE	5
+#define LOG_INFO	6
+#define LOG_DEBUG	7
+
+#define LOG_PRIMASK	7
+#define LOG_PRI(x)	((x) & LOG_PRIMASK)
+
+/* Facilities; not actually used */
+#define LOG_KERN	0000
+#define LOG_USER	0010
+#define LOG_MAIL	0020
+#define LOG_DAEMON	0030
+#define LOG_AUTH	0040
+#define LOG_SYSLOG	0050
+#define LOG_LPR		0060
+#define LOG_NEWS	0070
+#define LOG_UUCP	0100
+#define LOG_CRON	0110
+#define LOG_AUTHPRIV	0120
+#define LOG_FTP		0130
+#define LOG_LOCAL0	0200
+#define LOG_LOCAL1	0210
+#define LOG_LOCAL2	0220
+#define LOG_LOCAL3	0230
+#define LOG_LOCAL4	0240
+#define LOG_LOCAL5	0250
+#define LOG_LOCAL6	0260
+#define LOG_LOCAL7	0270
+
+#define LOG_FACMASK	01770
+#define LOG_FAC(x)	(((x) >> 3) & (LOG_FACMASK >> 3))
+
+/* openlog() flags; only LOG_PID and LOG_PERROR supported */
+#define        LOG_PID         0x01	/* include pid with message */
+#define        LOG_CONS        0x02	/* write to console on logger error */
+#define        LOG_ODELAY      0x04	/* delay connection until syslog() */
+#define        LOG_NDELAY      0x08	/* open connection immediately */
+#define        LOG_NOWAIT      0x10	/* wait for child processes (unused on linux) */
+#define        LOG_PERROR      0x20	/* additional logging to stderr */
+
+__extern void openlog(const char *, int, int);
+__extern void syslog(int, const char *, ...);
+__extern void vsyslog(int, const char *, va_list);
+__extern void closelog(void);
+
+#endif				/* _SYSLOG_H */
diff --git a/usr/include/termios.h b/usr/include/termios.h
new file mode 100644
index 0000000..59d9859
--- /dev/null
+++ b/usr/include/termios.h
@@ -0,0 +1,91 @@
+/*
+ * termios.h
+ */
+
+#ifndef _TERMIOS_H
+#define _TERMIOS_H
+
+#include <klibc/extern.h>
+#include <stdint.h>
+#include <sys/ioctl.h>
+#include <sys/types.h>
+#include <linux/termios.h>
+
+/* Redefine these so the magic constants == the ioctl number to use. */
+#undef TCSANOW
+#undef TCSADRAIN
+#undef TCSAFLUSH
+#define TCSANOW	   TCSETS
+#define TCSADRAIN  TCSETSW
+#define TCSAFLUSH  TCSETSF
+
+static __inline__ int tcgetattr(int __fd, struct termios *__s)
+{
+	return ioctl(__fd, TCGETS, __s);
+}
+
+static __inline__ int tcsetattr(int __fd, int __opt, const struct termios *__s)
+{
+	return ioctl(__fd, __opt, (void *)__s);
+}
+
+static __inline__ int tcflow(int __fd, int __action)
+{
+	return ioctl(__fd, TCXONC, (void *)(intptr_t) __action);
+}
+
+static __inline__ int tcflush(int __fd, int __queue)
+{
+	return ioctl(__fd, TCFLSH, (void *)(intptr_t) __queue);
+}
+
+static __inline__ int tcdrain(int __fd)
+{
+	return ioctl(__fd, TCSBRK, (void *)1L);
+}
+
+static __inline__ pid_t tcgetpgrp(int __fd)
+{
+	pid_t __p;
+	return ioctl(__fd, TIOCGPGRP, &__p) ? (pid_t) - 1 : __p;
+}
+
+static __inline__ pid_t tcgetsid(int __fd)
+{
+	pid_t __p;
+	return ioctl(__fd, TIOCGSID, &__p) ? (pid_t) - 1 : __p;
+}
+
+static __inline__ int tcsendbreak(int __fd, int __duration)
+{
+	return ioctl(__fd, TCSBRKP, (void *)(uintptr_t) __duration);
+}
+
+static __inline__ int tcsetpgrp(int __fd, pid_t __p)
+{
+	return ioctl(__fd, TIOCSPGRP, &__p);
+}
+
+static __inline__ speed_t cfgetospeed(const struct termios *__s)
+{
+	return (speed_t) (__s->c_cflag & CBAUD);
+}
+
+static __inline__ speed_t cfgetispeed(const struct termios *__s)
+{
+	return (speed_t) (__s->c_cflag & CBAUD);
+}
+
+static __inline__ int cfsetospeed(struct termios *__s, speed_t __v)
+{
+	__s->c_cflag = (__s->c_cflag & ~CBAUD) | (__v & CBAUD);
+	return 0;
+}
+
+static __inline__ int cfsetispeed(struct termios *__s, speed_t __v)
+{
+	__s->c_cflag = (__s->c_cflag & ~CBAUD) | (__v & CBAUD);
+	return 0;
+}
+
+#endif				/* _TERMIOS_H */
diff --git a/usr/include/time.h b/usr/include/time.h
new file mode 100644
index 0000000..72b2993
--- /dev/null
+++ b/usr/include/time.h
@@ -0,0 +1,18 @@
+/*
+ * time.h
+ */
+
+#ifndef _TIME_H
+#define _TIME_H
+
+#include <klibc/extern.h>
+#include <sys/time.h>
+
+__extern time_t time(time_t *);
+__extern int nanosleep(const struct timespec *, struct timespec *);
+
+/* klibc-specific but useful since we don't have floating point */
+__extern char *strtotimeval(const char *str, struct timeval *tv);
+__extern char *strtotimespec(const char *str, struct timespec *tv);
+
+#endif				/* _TIME_H */
diff --git a/usr/include/unistd.h b/usr/include/unistd.h
new file mode 100644
index 0000000..d0fbd86
--- /dev/null
+++ b/usr/include/unistd.h
@@ -0,0 +1,161 @@
+/*
+ * unistd.h
+ */
+
+#ifndef _UNISTD_H
+#define _UNISTD_H
+
+#include <klibc/extern.h>
+#include <klibc/compiler.h>
+#include <stddef.h>
+#include <sys/types.h>
+#include <sys/select.h>
+
+__extern char **environ;
+__extern __noreturn _exit(int);
+
+__extern pid_t fork(void);
+__extern pid_t vfork(void);
+__extern pid_t getpid(void);
+__extern pid_t getpgid(pid_t);
+__extern int setpgid(pid_t, pid_t);
+__extern pid_t getppid(void);
+__extern pid_t getpgrp(void);
+__extern int setpgrp(void);
+__extern pid_t setsid(void);
+__extern pid_t getsid(pid_t);
+__extern int execv(const char *, char *const *);
+__extern int execvp(const char *, char *const *);
+__extern int execve(const char *, char *const *, char *const *);
+__extern int execvpe(const char *, char *const *, char *const *);
+__extern int execl(const char *, const char *, ...);
+__extern int execlp(const char *, const char *, ...);
+__extern int execle(const char *, const char *, ...);
+__extern int execlpe(const char *, const char *, ...);
+
+__extern int setuid(uid_t);
+__extern uid_t getuid(void);
+__extern int seteuid(uid_t);
+__extern uid_t geteuid(void);
+__extern int setgid(gid_t);
+__extern gid_t getgid(void);
+__extern int setegid(gid_t);
+__extern gid_t getegid(void);
+__extern int getgroups(int, gid_t *);
+__extern int setgroups(size_t, const gid_t *);
+__extern int setreuid(uid_t, uid_t);
+__extern int setregid(gid_t, gid_t);
+__extern int setresuid(uid_t, uid_t, uid_t);
+__extern int setresgid(gid_t, gid_t, gid_t);
+__extern int getfsuid(uid_t);
+__extern int setfsuid(uid_t);
+
+/* Macros for access() */
+#define R_OK	4		/* Read */
+#define W_OK	2		/* Write */
+#define X_OK	1		/* Execute */
+#define F_OK	0		/* Existence */
+
+__extern int access(const char *, int);
+__extern int faccessat(int, const char *, int);
+__extern int link(const char *, const char *);
+__extern int linkat(int, const char *, int, const char *);
+__extern int unlink(const char *);
+__extern int unlinkat(int, const char *);
+__extern int chdir(const char *);
+__extern int fchdir(int);
+__extern int chmod(const char *, mode_t);
+__extern int fchmod(int, mode_t);
+__extern int fchmodat(int, const char *, mode_t);
+__extern int mkdir(const char *, mode_t);
+__extern int mkdirat(int, const char *, const char *, mode_t);
+__extern int rmdir(const char *);
+__extern int pipe(int *);
+__extern int chroot(const char *);
+__extern int symlink(const char *, const char *);
+__extern int symlinkat(int, const char *, const char *);
+__extern int readlink(const char *, char *, size_t);
+__extern int readlinkat(int, const char *, char *, size_t);
+__extern int chown(const char *, uid_t, gid_t);
+__extern int fchown(int, uid_t, gid_t);
+__extern int lchown(const char *, uid_t, gid_t);
+__extern char *getcwd(char *, size_t);
+
+/* Also in <fcntl.h> */
+#ifndef _KLIBC_IN_OPEN_C
+__extern int open(const char *, int, ...);
+__extern int openat(int, const char *, int, ...);
+#endif
+__extern int creat(const char *, mode_t);
+__extern int open_cloexec(const char *, int, mode_t);
+__extern int close(int);
+__extern off_t lseek(int, off_t, int);
+/* off_t is 64 bits now even on 32-bit platforms; see llseek.c */
+static __inline__ off_t llseek(int __f, off_t __o, int __w)
+{
+	return lseek(__f, __o, __w);
+}
+
+__extern ssize_t read(int, void *, size_t);
+__extern ssize_t write(int, const void *, size_t);
+__extern ssize_t pread(int, void *, size_t, off_t);
+__extern ssize_t pwrite(int, const void *, size_t, off_t);
+
+__extern int dup(int);
+__extern int dup2(int, int);
+__extern int fcntl(int, int, ...);
+__extern int ioctl(int, int, void *);
+__extern int flock(int, int);
+__extern int ftruncate(int, off_t);
+
+/*
+ * Macros for sync_file_range()
+ */
+#define SYNC_FILE_RANGE_WAIT_BEFORE     1
+#define SYNC_FILE_RANGE_WRITE           2
+#define SYNC_FILE_RANGE_WAIT_AFTER      4
+
+__extern int sync(void);
+__extern int fsync(int);
+__extern int fdatasync(int);
+__extern int sync_file_range(int, off_t, off_t, unsigned int);
+
+__extern int pause(void);
+__extern unsigned int alarm(unsigned int);
+__extern unsigned int sleep(unsigned int);
+__extern void usleep(unsigned long);
+
+__extern int gethostname(char *, size_t);
+__extern int sethostname(const char *, size_t);
+__extern int getdomainname(char *, size_t);
+__extern int setdomainname(const char *, size_t);
+
+__extern void *__brk(void *);
+__extern int brk(void *);
+__extern void *sbrk(ptrdiff_t);
+
+__extern int getopt(int, char *const *, const char *);
+__extern char *optarg;
+__extern int optind, opterr, optopt;
+
+__extern int isatty(int);
+
+static __inline__ int getpagesize(void)
+{
+	extern unsigned int __page_size;
+	return __page_size;
+}
+static __inline__ int __getpageshift(void)
+{
+	extern unsigned int __page_shift;
+	return __page_shift;
+}
+
+__extern int daemon(int, int);
+
+/* Standard file descriptor numbers. */
+#define STDIN_FILENO	0
+#define STDOUT_FILENO	1
+#define STDERR_FILENO	2
+
+#endif				/* _UNISTD_H */
diff --git a/usr/include/utime.h b/usr/include/utime.h
new file mode 100644
index 0000000..fa00604
--- /dev/null
+++ b/usr/include/utime.h
@@ -0,0 +1,14 @@
+/*
+ * utime.h
+ */
+
+#ifndef _UTIME_H
+#define _UTIME_H
+
+#include <klibc/extern.h>
+#include <sys/types.h>
+#include <linux/utime.h>
+
+__extern int utime(const char *, const struct utimbuf *);
+
+#endif				/* _UTIME_H */
diff --git a/usr/include/zconf.h b/usr/include/zconf.h
new file mode 100644
index 0000000..afe324f
--- /dev/null
+++ b/usr/include/zconf.h
@@ -0,0 +1,332 @@
+/* zconf.h -- configuration of the zlib compression library
+ * Copyright (C) 1995-2005 Jean-loup Gailly.
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* @(#) $Id: zconf.h,v 1.1 2005/02/27 23:15:39 hpa Exp $ */
+
+#ifndef ZCONF_H
+#define ZCONF_H
+
+/*
+ * If you *really* need a unique prefix for all types and library functions,
+ * compile with -DZ_PREFIX. The "standard" zlib should be compiled without it.
+ */
+#ifdef Z_PREFIX
+#  define deflateInit_          z_deflateInit_
+#  define deflate               z_deflate
+#  define deflateEnd            z_deflateEnd
+#  define inflateInit_          z_inflateInit_
+#  define inflate               z_inflate
+#  define inflateEnd            z_inflateEnd
+#  define deflateInit2_         z_deflateInit2_
+#  define deflateSetDictionary  z_deflateSetDictionary
+#  define deflateCopy           z_deflateCopy
+#  define deflateReset          z_deflateReset
+#  define deflateParams         z_deflateParams
+#  define deflateBound          z_deflateBound
+#  define deflatePrime          z_deflatePrime
+#  define inflateInit2_         z_inflateInit2_
+#  define inflateSetDictionary  z_inflateSetDictionary
+#  define inflateSync           z_inflateSync
+#  define inflateSyncPoint      z_inflateSyncPoint
+#  define inflateCopy           z_inflateCopy
+#  define inflateReset          z_inflateReset
+#  define inflateBack           z_inflateBack
+#  define inflateBackEnd        z_inflateBackEnd
+#  define compress              z_compress
+#  define compress2             z_compress2
+#  define compressBound         z_compressBound
+#  define uncompress            z_uncompress
+#  define adler32               z_adler32
+#  define crc32                 z_crc32
+#  define get_crc_table         z_get_crc_table
+#  define zError                z_zError
+
+#  define alloc_func            z_alloc_func
+#  define free_func             z_free_func
+#  define in_func               z_in_func
+#  define out_func              z_out_func
+#  define Byte                  z_Byte
+#  define uInt                  z_uInt
+#  define uLong                 z_uLong
+#  define Bytef                 z_Bytef
+#  define charf                 z_charf
+#  define intf                  z_intf
+#  define uIntf                 z_uIntf
+#  define uLongf                z_uLongf
+#  define voidpf                z_voidpf
+#  define voidp                 z_voidp
+#endif
+
+#if defined(__MSDOS__) && !defined(MSDOS)
+#  define MSDOS
+#endif
+#if (defined(OS_2) || defined(__OS2__)) && !defined(OS2)
+#  define OS2
+#endif
+#if defined(_WINDOWS) && !defined(WINDOWS)
+#  define WINDOWS
+#endif
+#if defined(_WIN32) || defined(_WIN32_WCE) || defined(__WIN32__)
+#  ifndef WIN32
+#    define WIN32
+#  endif
+#endif
+#if (defined(MSDOS) || defined(OS2) || defined(WINDOWS)) && !defined(WIN32)
+#  if !defined(__GNUC__) && !defined(__FLAT__) && !defined(__386__)
+#    ifndef SYS16BIT
+#      define SYS16BIT
+#    endif
+#  endif
+#endif
+
+/*
+ * Compile with -DMAXSEG_64K if the alloc function cannot allocate more
+ * than 64k bytes at a time (needed on systems with 16-bit int).
+ */
+#ifdef SYS16BIT
+#  define MAXSEG_64K
+#endif
+#ifdef MSDOS
+#  define UNALIGNED_OK
+#endif
+
+#ifdef __STDC_VERSION__
+#  ifndef STDC
+#    define STDC
+#  endif
+#  if __STDC_VERSION__ >= 199901L
+#    ifndef STDC99
+#      define STDC99
+#    endif
+#  endif
+#endif
+#if !defined(STDC) && (defined(__STDC__) || defined(__cplusplus))
+#  define STDC
+#endif
+#if !defined(STDC) && (defined(__GNUC__) || defined(__BORLANDC__))
+#  define STDC
+#endif
+#if !defined(STDC) && (defined(MSDOS) || defined(WINDOWS) || defined(WIN32))
+#  define STDC
+#endif
+#if !defined(STDC) && (defined(OS2) || defined(__HOS_AIX__))
+#  define STDC
+#endif
+
+#if defined(__OS400__) && !defined(STDC)    /* iSeries (formerly AS/400). */
+#  define STDC
+#endif
+
+#ifndef STDC
+#  ifndef const /* cannot use !defined(STDC) && !defined(const) on Mac */
+#    define const       /* note: need a more gentle solution here */
+#  endif
+#endif
+
+/* Some Mac compilers merge all .h files incorrectly: */
+#if defined(__MWERKS__)||defined(applec)||defined(THINK_C)||defined(__SC__)
+#  define NO_DUMMY_DECL
+#endif
+
+/* Maximum value for memLevel in deflateInit2 */
+#ifndef MAX_MEM_LEVEL
+#  ifdef MAXSEG_64K
+#    define MAX_MEM_LEVEL 8
+#  else
+#    define MAX_MEM_LEVEL 9
+#  endif
+#endif
+
+/* Maximum value for windowBits in deflateInit2 and inflateInit2.
+ * WARNING: reducing MAX_WBITS makes minigzip unable to extract .gz files
+ * created by gzip. (Files created by minigzip can still be extracted by
+ * gzip.)
+ */
+#ifndef MAX_WBITS
+#  define MAX_WBITS   15 /* 32K LZ77 window */
+#endif
+
+/* The memory requirements for deflate are (in bytes):
+            (1 << (windowBits+2)) +  (1 << (memLevel+9))
+ that is: 128K for windowBits=15  +  128K for memLevel = 8  (default values)
+ plus a few kilobytes for small objects. For example, if you want to reduce
+ the default memory requirements from 256K to 128K, compile with
+     make CFLAGS="-O -DMAX_WBITS=14 -DMAX_MEM_LEVEL=7"
+ Of course this will generally degrade compression (there's no free lunch).
+
+   The memory requirements for inflate are (in bytes) 1 << windowBits
+ that is, 32K for windowBits=15 (default value) plus a few kilobytes
+ for small objects.
+*/
+
+                        /* Type declarations */
+
+#ifndef OF /* function prototypes */
+#  ifdef STDC
+#    define OF(args)  args
+#  else
+#    define OF(args)  ()
+#  endif
+#endif
+
+/* The following definitions for FAR are needed only for MSDOS mixed
+ * model programming (small or medium model with some far allocations).
+ * This was tested only with MSC; for other MSDOS compilers you may have
+ * to define NO_MEMCPY in zutil.h.  If you don't need the mixed model,
+ * just define FAR to be empty.
+ */
+#ifdef SYS16BIT
+#  if defined(M_I86SM) || defined(M_I86MM)
+     /* MSC small or medium model */
+#    define SMALL_MEDIUM
+#    ifdef _MSC_VER
+#      define FAR _far
+#    else
+#      define FAR far
+#    endif
+#  endif
+#  if (defined(__SMALL__) || defined(__MEDIUM__))
+     /* Turbo C small or medium model */
+#    define SMALL_MEDIUM
+#    ifdef __BORLANDC__
+#      define FAR _far
+#    else
+#      define FAR far
+#    endif
+#  endif
+#endif
+
+#if defined(WINDOWS) || defined(WIN32)
+   /* If building or using zlib as a DLL, define ZLIB_DLL.
+    * This is not mandatory, but it offers a little performance increase.
+    */
+#  ifdef ZLIB_DLL
+#    if defined(WIN32) && (!defined(__BORLANDC__) || (__BORLANDC__ >= 0x500))
+#      ifdef ZLIB_INTERNAL
+#        define ZEXTERN extern __declspec(dllexport)
+#      else
+#        define ZEXTERN extern __declspec(dllimport)
+#      endif
+#    endif
+#  endif  /* ZLIB_DLL */
+   /* If building or using zlib with the WINAPI/WINAPIV calling convention,
+    * define ZLIB_WINAPI.
+    * Caution: the standard ZLIB1.DLL is NOT compiled using ZLIB_WINAPI.
+    */
+#  ifdef ZLIB_WINAPI
+#    ifdef FAR
+#      undef FAR
+#    endif
+#    include <windows.h>
+     /* No need for _export, use ZLIB.DEF instead. */
+     /* For complete Windows compatibility, use WINAPI, not __stdcall. */
+#    define ZEXPORT WINAPI
+#    ifdef WIN32
+#      define ZEXPORTVA WINAPIV
+#    else
+#      define ZEXPORTVA FAR CDECL
+#    endif
+#  endif
+#endif
+
+#if defined (__BEOS__)
+#  ifdef ZLIB_DLL
+#    ifdef ZLIB_INTERNAL
+#      define ZEXPORT   __declspec(dllexport)
+#      define ZEXPORTVA __declspec(dllexport)
+#    else
+#      define ZEXPORT   __declspec(dllimport)
+#      define ZEXPORTVA __declspec(dllimport)
+#    endif
+#  endif
+#endif
+
+#ifndef ZEXTERN
+#  define ZEXTERN extern
+#endif
+#ifndef ZEXPORT
+#  define ZEXPORT
+#endif
+#ifndef ZEXPORTVA
+#  define ZEXPORTVA
+#endif
+
+#ifndef FAR
+#  define FAR
+#endif
+
+#if !defined(__MACTYPES__)
+typedef unsigned char  Byte;  /* 8 bits */
+#endif
+typedef unsigned int   uInt;  /* 16 bits or more */
+typedef unsigned long  uLong; /* 32 bits or more */
+
+#ifdef SMALL_MEDIUM
+   /* Borland C/C++ and some old MSC versions ignore FAR inside typedef */
+#  define Bytef Byte FAR
+#else
+   typedef Byte  FAR Bytef;
+#endif
+typedef char  FAR charf;
+typedef int   FAR intf;
+typedef uInt  FAR uIntf;
+typedef uLong FAR uLongf;
+
+#ifdef STDC
+   typedef void const *voidpc;
+   typedef void FAR   *voidpf;
+   typedef void       *voidp;
+#else
+   typedef Byte const *voidpc;
+   typedef Byte FAR   *voidpf;
+   typedef Byte       *voidp;
+#endif
+
+#if 0           /* HAVE_UNISTD_H -- this line is updated by ./configure */
+#  include <sys/types.h> /* for off_t */
+#  include <unistd.h>    /* for SEEK_* and off_t */
+#  ifdef VMS
+#    include <unixio.h>   /* for off_t */
+#  endif
+#  define z_off_t off_t
+#endif
+#ifndef SEEK_SET
+#  define SEEK_SET        0       /* Seek from beginning of file.  */
+#  define SEEK_CUR        1       /* Seek from current position.  */
+#  define SEEK_END        2       /* Set file pointer to EOF plus "offset" */
+#endif
+#ifndef z_off_t
+#  define z_off_t long
+#endif
+
+#if defined(__OS400__)
+#  define NO_vsnprintf
+#endif
+
+#if defined(__MVS__)
+#  define NO_vsnprintf
+#  ifdef FAR
+#    undef FAR
+#  endif
+#endif
+
+/* MVS linker does not support external names larger than 8 bytes */
+#if defined(__MVS__)
+#   pragma map(deflateInit_,"DEIN")
+#   pragma map(deflateInit2_,"DEIN2")
+#   pragma map(deflateEnd,"DEEND")
+#   pragma map(deflateBound,"DEBND")
+#   pragma map(inflateInit_,"ININ")
+#   pragma map(inflateInit2_,"ININ2")
+#   pragma map(inflateEnd,"INEND")
+#   pragma map(inflateSync,"INSY")
+#   pragma map(inflateSetDictionary,"INSEDI")
+#   pragma map(compressBound,"CMBND")
+#   pragma map(inflate_table,"INTABL")
+#   pragma map(inflate_fast,"INFA")
+#   pragma map(inflate_copyright,"INCOPY")
+#endif
+
+#endif /* ZCONF_H */
diff --git a/usr/include/zlib.h b/usr/include/zlib.h
new file mode 100644
index 0000000..0228179
--- /dev/null
+++ b/usr/include/zlib.h
@@ -0,0 +1,1357 @@
+/* zlib.h -- interface of the 'zlib' general purpose compression library
+  version 1.2.3, July 18th, 2005
+
+  Copyright (C) 1995-2005 Jean-loup Gailly and Mark Adler
+
+  This software is provided 'as-is', without any express or implied
+  warranty.  In no event will the authors be held liable for any damages
+  arising from the use of this software.
+
+  Permission is granted to anyone to use this software for any purpose,
+  including commercial applications, and to alter it and redistribute it
+  freely, subject to the following restrictions:
+
+  1. The origin of this software must not be misrepresented; you must not
+     claim that you wrote the original software. If you use this software
+     in a product, an acknowledgment in the product documentation would be
+     appreciated but is not required.
+  2. Altered source versions must be plainly marked as such, and must not be
+     misrepresented as being the original software.
+  3. This notice may not be removed or altered from any source distribution.
+
+  Jean-loup Gailly        Mark Adler
+  jloup@gzip.org          madler@alumni.caltech.edu
+
+
+  The data format used by the zlib library is described by RFCs (Request for
+  Comments) 1950 to 1952 in the files http://www.ietf.org/rfc/rfc1950.txt
+  (zlib format), rfc1951.txt (deflate format) and rfc1952.txt (gzip format).
+*/
+
+#ifndef ZLIB_H
+#define ZLIB_H
+
+#include "zconf.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define ZLIB_VERSION "1.2.3"
+#define ZLIB_VERNUM 0x1230
+
+/*
+     The 'zlib' compression library provides in-memory compression and
+  decompression functions, including integrity checks of the uncompressed
+  data.  This version of the library supports only one compression method
+  (deflation) but other algorithms will be added later and will have the same
+  stream interface.
+
+     Compression can be done in a single step if the buffers are large
+  enough (for example if an input file is mmap'ed), or can be done by
+  repeated calls of the compression function.  In the latter case, the
+  application must provide more input and/or consume the output
+  (providing more output space) before each call.
+
+     The compressed data format used by default by the in-memory functions is
+  the zlib format, which is a zlib wrapper documented in RFC 1950, wrapped
+  around a deflate stream, which is itself documented in RFC 1951.
+
+     The library also supports reading and writing files in gzip (.gz) format
+  with an interface similar to that of stdio using the functions that start
+  with "gz".  The gzip format is different from the zlib format.  gzip is a
+  gzip wrapper, documented in RFC 1952, wrapped around a deflate stream.
+
+     This library can optionally read and write gzip streams in memory as well.
+
+     The zlib format was designed to be compact and fast for use in memory
+  and on communications channels.  The gzip format was designed for single-
+  file compression on file systems, has a larger header than zlib to maintain
+  directory information, and uses a different, slower check method than zlib.
+
+     The library does not install any signal handler. The decoder checks
+  the consistency of the compressed data, so the library should never
+  crash even in case of corrupted input.
+*/
+
+typedef voidpf (*alloc_func) OF((voidpf opaque, uInt items, uInt size));
+typedef void   (*free_func)  OF((voidpf opaque, voidpf address));
+
+struct internal_state;
+
+typedef struct z_stream_s {
+    Bytef    *next_in;  /* next input byte */
+    uInt     avail_in;  /* number of bytes available at next_in */
+    uLong    total_in;  /* total nb of input bytes read so far */
+
+    Bytef    *next_out; /* next output byte should be put there */
+    uInt     avail_out; /* remaining free space at next_out */
+    uLong    total_out; /* total nb of bytes output so far */
+
+    char     *msg;      /* last error message, NULL if no error */
+    struct internal_state FAR *state; /* not visible by applications */
+
+    alloc_func zalloc;  /* used to allocate the internal state */
+    free_func  zfree;   /* used to free the internal state */
+    voidpf     opaque;  /* private data object passed to zalloc and zfree */
+
+    int     data_type;  /* best guess about the data type: binary or text */
+    uLong   adler;      /* adler32 value of the uncompressed data */
+    uLong   reserved;   /* reserved for future use */
+} z_stream;
+
+typedef z_stream FAR *z_streamp;
+
+/*
+     gzip header information passed to and from zlib routines.  See RFC 1952
+  for more details on the meanings of these fields.
+*/
+typedef struct gz_header_s {
+    int     text;       /* true if compressed data believed to be text */
+    uLong   time;       /* modification time */
+    int     xflags;     /* extra flags (not used when writing a gzip file) */
+    int     os;         /* operating system */
+    Bytef   *extra;     /* pointer to extra field or Z_NULL if none */
+    uInt    extra_len;  /* extra field length (valid if extra != Z_NULL) */
+    uInt    extra_max;  /* space at extra (only when reading header) */
+    Bytef   *name;      /* pointer to zero-terminated file name or Z_NULL */
+    uInt    name_max;   /* space at name (only when reading header) */
+    Bytef   *comment;   /* pointer to zero-terminated comment or Z_NULL */
+    uInt    comm_max;   /* space at comment (only when reading header) */
+    int     hcrc;       /* true if there was or will be a header crc */
+    int     done;       /* true when done reading gzip header (not used
+                           when writing a gzip file) */
+} gz_header;
+
+typedef gz_header FAR *gz_headerp;
+
+/*
+   The application must update next_in and avail_in when avail_in has
+   dropped to zero. It must update next_out and avail_out when avail_out
+   has dropped to zero. The application must initialize zalloc, zfree and
+   opaque before calling the init function. All other fields are set by the
+   compression library and must not be updated by the application.
+
+   The opaque value provided by the application will be passed as the first
+   parameter for calls of zalloc and zfree. This can be useful for custom
+   memory management. The compression library attaches no meaning to the
+   opaque value.
+
+   zalloc must return Z_NULL if there is not enough memory for the object.
+   If zlib is used in a multi-threaded application, zalloc and zfree must be
+   thread safe.
+
+   On 16-bit systems, the functions zalloc and zfree must be able to allocate
+   exactly 65536 bytes, but will not be required to allocate more than this
+   if the symbol MAXSEG_64K is defined (see zconf.h). WARNING: On MSDOS,
+   pointers returned by zalloc for objects of exactly 65536 bytes *must*
+   have their offset normalized to zero. The default allocation function
+   provided by this library ensures this (see zutil.c). To reduce memory
+   requirements and avoid any allocation of 64K objects, at the expense of
+   compression ratio, compile the library with -DMAX_WBITS=14 (see zconf.h).
+
+   The fields total_in and total_out can be used for statistics or
+   progress reports. After compression, total_in holds the total size of
+   the uncompressed data and may be saved for use in the decompressor
+   (particularly if the decompressor wants to decompress everything in
+   a single step).
+*/
+
+                        /* constants */
+
+#define Z_NO_FLUSH      0
+#define Z_PARTIAL_FLUSH 1 /* will be removed, use Z_SYNC_FLUSH instead */
+#define Z_SYNC_FLUSH    2
+#define Z_FULL_FLUSH    3
+#define Z_FINISH        4
+#define Z_BLOCK         5
+/* Allowed flush values; see deflate() and inflate() below for details */
+
+#define Z_OK            0
+#define Z_STREAM_END    1
+#define Z_NEED_DICT     2
+#define Z_ERRNO        (-1)
+#define Z_STREAM_ERROR (-2)
+#define Z_DATA_ERROR   (-3)
+#define Z_MEM_ERROR    (-4)
+#define Z_BUF_ERROR    (-5)
+#define Z_VERSION_ERROR (-6)
+/* Return codes for the compression/decompression functions. Negative
+ * values are errors, positive values are used for special but normal events.
+ */
+
+#define Z_NO_COMPRESSION         0
+#define Z_BEST_SPEED             1
+#define Z_BEST_COMPRESSION       9
+#define Z_DEFAULT_COMPRESSION  (-1)
+/* compression levels */
+
+#define Z_FILTERED            1
+#define Z_HUFFMAN_ONLY        2
+#define Z_RLE                 3
+#define Z_FIXED               4
+#define Z_DEFAULT_STRATEGY    0
+/* compression strategy; see deflateInit2() below for details */
+
+#define Z_BINARY   0
+#define Z_TEXT     1
+#define Z_ASCII    Z_TEXT   /* for compatibility with 1.2.2 and earlier */
+#define Z_UNKNOWN  2
+/* Possible values of the data_type field (though see inflate()) */
+
+#define Z_DEFLATED   8
+/* The deflate compression method (the only one supported in this version) */
+
+#define Z_NULL  0  /* for initializing zalloc, zfree, opaque */
+
+#define zlib_version zlibVersion()
+/* for compatibility with versions < 1.0.2 */
+
+                        /* basic functions */
+
+ZEXTERN const char * ZEXPORT zlibVersion OF((void));
+/* The application can compare zlibVersion and ZLIB_VERSION for consistency.
+   If the first character differs, the library code actually used is
+   not compatible with the zlib.h header file used by the application.
+   This check is automatically made by deflateInit and inflateInit.
+ */
+
+/*
+ZEXTERN int ZEXPORT deflateInit OF((z_streamp strm, int level));
+
+     Initializes the internal stream state for compression. The fields
+   zalloc, zfree and opaque must be initialized before by the caller.
+   If zalloc and zfree are set to Z_NULL, deflateInit updates them to
+   use default allocation functions.
+
+     The compression level must be Z_DEFAULT_COMPRESSION, or between 0 and 9:
+   1 gives best speed, 9 gives best compression, 0 gives no compression at
+   all (the input data is simply copied a block at a time).
+   Z_DEFAULT_COMPRESSION requests a default compromise between speed and
+   compression (currently equivalent to level 6).
+
+     deflateInit returns Z_OK if success, Z_MEM_ERROR if there was not
+   enough memory, Z_STREAM_ERROR if level is not a valid compression level,
+   Z_VERSION_ERROR if the zlib library version (zlib_version) is incompatible
+   with the version assumed by the caller (ZLIB_VERSION).
+   msg is set to null if there is no error message.  deflateInit does not
+   perform any compression: this will be done by deflate().
+*/
+
+
+ZEXTERN int ZEXPORT deflate OF((z_streamp strm, int flush));
+/*
+    deflate compresses as much data as possible, and stops when the input
+  buffer becomes empty or the output buffer becomes full. It may introduce some
+  output latency (reading input without producing any output) except when
+  forced to flush.
+
+    The detailed semantics are as follows. deflate performs one or both of the
+  following actions:
+
+  - Compress more input starting at next_in and update next_in and avail_in
+    accordingly. If not all input can be processed (because there is not
+    enough room in the output buffer), next_in and avail_in are updated and
+    processing will resume at this point for the next call of deflate().
+
+  - Provide more output starting at next_out and update next_out and avail_out
+    accordingly. This action is forced if the parameter flush is non zero.
+    Forcing flush frequently degrades the compression ratio, so this parameter
+    should be set only when necessary (in interactive applications).
+    Some output may be provided even if flush is not set.
+
+  Before the call of deflate(), the application should ensure that at least
+  one of the actions is possible, by providing more input and/or consuming
+  more output, and updating avail_in or avail_out accordingly; avail_out
+  should never be zero before the call. The application can consume the
+  compressed output when it wants, for example when the output buffer is full
+  (avail_out == 0), or after each call of deflate(). If deflate returns Z_OK
+  and with zero avail_out, it must be called again after making room in the
+  output buffer because there might be more output pending.
+
+    Normally the parameter flush is set to Z_NO_FLUSH, which allows deflate to
+  decide how much data to accumualte before producing output, in order to
+  maximize compression.
+
+    If the parameter flush is set to Z_SYNC_FLUSH, all pending output is
+  flushed to the output buffer and the output is aligned on a byte boundary, so
+  that the decompressor can get all input data available so far. (In particular
+  avail_in is zero after the call if enough output space has been provided
+  before the call.)  Flushing may degrade compression for some compression
+  algorithms and so it should be used only when necessary.
+
+    If flush is set to Z_FULL_FLUSH, all output is flushed as with
+  Z_SYNC_FLUSH, and the compression state is reset so that decompression can
+  restart from this point if previous compressed data has been damaged or if
+  random access is desired. Using Z_FULL_FLUSH too often can seriously degrade
+  compression.
+
+    If deflate returns with avail_out == 0, this function must be called again
+  with the same value of the flush parameter and more output space (updated
+  avail_out), until the flush is complete (deflate returns with non-zero
+  avail_out). In the case of a Z_FULL_FLUSH or Z_SYNC_FLUSH, make sure that
+  avail_out is greater than six to avoid repeated flush markers due to
+  avail_out == 0 on return.
+
+    If the parameter flush is set to Z_FINISH, pending input is processed,
+  pending output is flushed and deflate returns with Z_STREAM_END if there
+  was enough output space; if deflate returns with Z_OK, this function must be
+  called again with Z_FINISH and more output space (updated avail_out) but no
+  more input data, until it returns with Z_STREAM_END or an error. After
+  deflate has returned Z_STREAM_END, the only possible operations on the
+  stream are deflateReset or deflateEnd.
+
+    Z_FINISH can be used immediately after deflateInit if all the compression
+  is to be done in a single step. In this case, avail_out must be at least
+  the value returned by deflateBound (see below). If deflate does not return
+  Z_STREAM_END, then it must be called again as described above.
+
+    deflate() sets strm->adler to the adler32 checksum of all input read
+  so far (that is, total_in bytes).
+
+    deflate() may update strm->data_type if it can make a good guess about
+  the input data type (Z_BINARY or Z_TEXT). In doubt, the data is considered
+  binary. This field is only for information purposes and does not affect
+  the compression algorithm in any manner.
+
+    deflate() returns Z_OK if some progress has been made (more input
+  processed or more output produced), Z_STREAM_END if all input has been
+  consumed and all output has been produced (only when flush is set to
+  Z_FINISH), Z_STREAM_ERROR if the stream state was inconsistent (for example
+  if next_in or next_out was NULL), Z_BUF_ERROR if no progress is possible
+  (for example avail_in or avail_out was zero). Note that Z_BUF_ERROR is not
+  fatal, and deflate() can be called again with more input and more output
+  space to continue compressing.
+*/
+
+
+ZEXTERN int ZEXPORT deflateEnd OF((z_streamp strm));
+/*
+     All dynamically allocated data structures for this stream are freed.
+   This function discards any unprocessed input and does not flush any
+   pending output.
+
+     deflateEnd returns Z_OK if success, Z_STREAM_ERROR if the
+   stream state was inconsistent, Z_DATA_ERROR if the stream was freed
+   prematurely (some input or output was discarded). In the error case,
+   msg may be set but then points to a static string (which must not be
+   deallocated).
+*/
+
+
+/*
+ZEXTERN int ZEXPORT inflateInit OF((z_streamp strm));
+
+     Initializes the internal stream state for decompression. The fields
+   next_in, avail_in, zalloc, zfree and opaque must be initialized before by
+   the caller. If next_in is not Z_NULL and avail_in is large enough (the exact
+   value depends on the compression method), inflateInit determines the
+   compression method from the zlib header and allocates all data structures
+   accordingly; otherwise the allocation will be deferred to the first call of
+   inflate.  If zalloc and zfree are set to Z_NULL, inflateInit updates them to
+   use default allocation functions.
+
+     inflateInit returns Z_OK if success, Z_MEM_ERROR if there was not enough
+   memory, Z_VERSION_ERROR if the zlib library version is incompatible with the
+   version assumed by the caller.  msg is set to null if there is no error
+   message. inflateInit does not perform any decompression apart from reading
+   the zlib header if present: this will be done by inflate().  (So next_in and
+   avail_in may be modified, but next_out and avail_out are unchanged.)
+*/
+
+
+ZEXTERN int ZEXPORT inflate OF((z_streamp strm, int flush));
+/*
+    inflate decompresses as much data as possible, and stops when the input
+  buffer becomes empty or the output buffer becomes full. It may introduce
+  some output latency (reading input without producing any output) except when
+  forced to flush.
+
+  The detailed semantics are as follows. inflate performs one or both of the
+  following actions:
+
+  - Decompress more input starting at next_in and update next_in and avail_in
+    accordingly. If not all input can be processed (because there is not
+    enough room in the output buffer), next_in is updated and processing
+    will resume at this point for the next call of inflate().
+
+  - Provide more output starting at next_out and update next_out and avail_out
+    accordingly.  inflate() provides as much output as possible, until there
+    is no more input data or no more space in the output buffer (see below
+    about the flush parameter).
+
+  Before the call of inflate(), the application should ensure that at least
+  one of the actions is possible, by providing more input and/or consuming
+  more output, and updating the next_* and avail_* values accordingly.
+  The application can consume the uncompressed output when it wants, for
+  example when the output buffer is full (avail_out == 0), or after each
+  call of inflate(). If inflate returns Z_OK and with zero avail_out, it
+  must be called again after making room in the output buffer because there
+  might be more output pending.
+
+    The flush parameter of inflate() can be Z_NO_FLUSH, Z_SYNC_FLUSH,
+  Z_FINISH, or Z_BLOCK. Z_SYNC_FLUSH requests that inflate() flush as much
+  output as possible to the output buffer. Z_BLOCK requests that inflate() stop
+  if and when it gets to the next deflate block boundary. When decoding the
+  zlib or gzip format, this will cause inflate() to return immediately after
+  the header and before the first block. When doing a raw inflate, inflate()
+  will go ahead and process the first block, and will return when it gets to
+  the end of that block, or when it runs out of data.
+
+    The Z_BLOCK option assists in appending to or combining deflate streams.
+  Also to assist in this, on return inflate() will set strm->data_type to the
+  number of unused bits in the last byte taken from strm->next_in, plus 64
+  if inflate() is currently decoding the last block in the deflate stream,
+  plus 128 if inflate() returned immediately after decoding an end-of-block
+  code or decoding the complete header up to just before the first byte of the
+  deflate stream. The end-of-block will not be indicated until all of the
+  uncompressed data from that block has been written to strm->next_out.  The
+  number of unused bits may in general be greater than seven, except when
+  bit 7 of data_type is set, in which case the number of unused bits will be
+  less than eight.
+
+    inflate() should normally be called until it returns Z_STREAM_END or an
+  error. However if all decompression is to be performed in a single step
+  (a single call of inflate), the parameter flush should be set to
+  Z_FINISH. In this case all pending input is processed and all pending
+  output is flushed; avail_out must be large enough to hold all the
+  uncompressed data. (The size of the uncompressed data may have been saved
+  by the compressor for this purpose.) The next operation on this stream must
+  be inflateEnd to deallocate the decompression state. The use of Z_FINISH
+  is never required, but can be used to inform inflate that a faster approach
+  may be used for the single inflate() call.
+
+     In this implementation, inflate() always flushes as much output as
+  possible to the output buffer, and always uses the faster approach on the
+  first call. So the only effect of the flush parameter in this implementation
+  is on the return value of inflate(), as noted below, or when it returns early
+  because Z_BLOCK is used.
+
+     If a preset dictionary is needed after this call (see inflateSetDictionary
+  below), inflate sets strm->adler to the adler32 checksum of the dictionary
+  chosen by the compressor and returns Z_NEED_DICT; otherwise it sets
+  strm->adler to the adler32 checksum of all output produced so far (that is,
+  total_out bytes) and returns Z_OK, Z_STREAM_END or an error code as described
+  below. At the end of the stream, inflate() checks that its computed adler32
+  checksum is equal to that saved by the compressor and returns Z_STREAM_END
+  only if the checksum is correct.
+
+    inflate() will decompress and check either zlib-wrapped or gzip-wrapped
+  deflate data.  The header type is detected automatically.  Any information
+  contained in the gzip header is not retained, so applications that need that
+  information should instead use raw inflate, see inflateInit2() below, or
+  inflateBack() and perform their own processing of the gzip header and
+  trailer.
+
+    inflate() returns Z_OK if some progress has been made (more input processed
+  or more output produced), Z_STREAM_END if the end of the compressed data has
+  been reached and all uncompressed output has been produced, Z_NEED_DICT if a
+  preset dictionary is needed at this point, Z_DATA_ERROR if the input data was
+  corrupted (input stream not conforming to the zlib format or incorrect check
+  value), Z_STREAM_ERROR if the stream structure was inconsistent (for example
+  if next_in or next_out was NULL), Z_MEM_ERROR if there was not enough memory,
+  Z_BUF_ERROR if no progress is possible or if there was not enough room in the
+  output buffer when Z_FINISH is used. Note that Z_BUF_ERROR is not fatal, and
+  inflate() can be called again with more input and more output space to
+  continue decompressing. If Z_DATA_ERROR is returned, the application may then
+  call inflateSync() to look for a good compression block if a partial recovery
+  of the data is desired.
+*/
+
+
+ZEXTERN int ZEXPORT inflateEnd OF((z_streamp strm));
+/*
+     All dynamically allocated data structures for this stream are freed.
+   This function discards any unprocessed input and does not flush any
+   pending output.
+
+     inflateEnd returns Z_OK if success, Z_STREAM_ERROR if the stream state
+   was inconsistent. In the error case, msg may be set but then points to a
+   static string (which must not be deallocated).
+*/
+
+                        /* Advanced functions */
+
+/*
+    The following functions are needed only in some special applications.
+*/
+
+/*
+ZEXTERN int ZEXPORT deflateInit2 OF((z_streamp strm,
+                                     int  level,
+                                     int  method,
+                                     int  windowBits,
+                                     int  memLevel,
+                                     int  strategy));
+
+     This is another version of deflateInit with more compression options. The
+   fields next_in, zalloc, zfree and opaque must be initialized before by
+   the caller.
+
+     The method parameter is the compression method. It must be Z_DEFLATED in
+   this version of the library.
+
+     The windowBits parameter is the base two logarithm of the window size
+   (the size of the history buffer). It should be in the range 8..15 for this
+   version of the library. Larger values of this parameter result in better
+   compression at the expense of memory usage. The default value is 15 if
+   deflateInit is used instead.
+
+     windowBits can also be -8..-15 for raw deflate. In this case, -windowBits
+   determines the window size. deflate() will then generate raw deflate data
+   with no zlib header or trailer, and will not compute an adler32 check value.
+
+     windowBits can also be greater than 15 for optional gzip encoding. Add
+   16 to windowBits to write a simple gzip header and trailer around the
+   compressed data instead of a zlib wrapper. The gzip header will have no
+   file name, no extra data, no comment, no modification time (set to zero),
+   no header crc, and the operating system will be set to 255 (unknown).  If a
+   gzip stream is being written, strm->adler is a crc32 instead of an adler32.
+
+     The memLevel parameter specifies how much memory should be allocated
+   for the internal compression state. memLevel=1 uses minimum memory but
+   is slow and reduces compression ratio; memLevel=9 uses maximum memory
+   for optimal speed. The default value is 8. See zconf.h for total memory
+   usage as a function of windowBits and memLevel.
+
+     The strategy parameter is used to tune the compression algorithm. Use the
+   value Z_DEFAULT_STRATEGY for normal data, Z_FILTERED for data produced by a
+   filter (or predictor), Z_HUFFMAN_ONLY to force Huffman encoding only (no
+   string match), or Z_RLE to limit match distances to one (run-length
+   encoding). Filtered data consists mostly of small values with a somewhat
+   random distribution. In this case, the compression algorithm is tuned to
+   compress them better. The effect of Z_FILTERED is to force more Huffman
+   coding and less string matching; it is somewhat intermediate between
+   Z_DEFAULT and Z_HUFFMAN_ONLY. Z_RLE is designed to be almost as fast as
+   Z_HUFFMAN_ONLY, but give better compression for PNG image data. The strategy
+   parameter only affects the compression ratio but not the correctness of the
+   compressed output even if it is not set appropriately.  Z_FIXED prevents the
+   use of dynamic Huffman codes, allowing for a simpler decoder for special
+   applications.
+
+      deflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was not enough
+   memory, Z_STREAM_ERROR if a parameter is invalid (such as an invalid
+   method). msg is set to null if there is no error message.  deflateInit2 does
+   not perform any compression: this will be done by deflate().
+*/
+
+ZEXTERN int ZEXPORT deflateSetDictionary OF((z_streamp strm,
+                                             const Bytef *dictionary,
+                                             uInt  dictLength));
+/*
+     Initializes the compression dictionary from the given byte sequence
+   without producing any compressed output. This function must be called
+   immediately after deflateInit, deflateInit2 or deflateReset, before any
+   call of deflate. The compressor and decompressor must use exactly the same
+   dictionary (see inflateSetDictionary).
+
+     The dictionary should consist of strings (byte sequences) that are likely
+   to be encountered later in the data to be compressed, with the most commonly
+   used strings preferably put towards the end of the dictionary. Using a
+   dictionary is most useful when the data to be compressed is short and can be
+   predicted with good accuracy; the data can then be compressed better than
+   with the default empty dictionary.
+
+     Depending on the size of the compression data structures selected by
+   deflateInit or deflateInit2, a part of the dictionary may in effect be
+   discarded, for example if the dictionary is larger than the window size in
+   deflate or deflate2. Thus the strings most likely to be useful should be
+   put at the end of the dictionary, not at the front. In addition, the
+   current implementation of deflate will use at most the window size minus
+   262 bytes of the provided dictionary.
+
+     Upon return of this function, strm->adler is set to the adler32 value
+   of the dictionary; the decompressor may later use this value to determine
+   which dictionary has been used by the compressor. (The adler32 value
+   applies to the whole dictionary even if only a subset of the dictionary is
+   actually used by the compressor.) If a raw deflate was requested, then the
+   adler32 value is not computed and strm->adler is not set.
+
+     deflateSetDictionary returns Z_OK if success, or Z_STREAM_ERROR if a
+   parameter is invalid (such as NULL dictionary) or the stream state is
+   inconsistent (for example if deflate has already been called for this stream
+   or if the compression method is bsort). deflateSetDictionary does not
+   perform any compression: this will be done by deflate().
+*/
+
+ZEXTERN int ZEXPORT deflateCopy OF((z_streamp dest,
+                                    z_streamp source));
+/*
+     Sets the destination stream as a complete copy of the source stream.
+
+     This function can be useful when several compression strategies will be
+   tried, for example when there are several ways of pre-processing the input
+   data with a filter. The streams that will be discarded should then be freed
+   by calling deflateEnd.  Note that deflateCopy duplicates the internal
+   compression state which can be quite large, so this strategy is slow and
+   can consume lots of memory.
+
+     deflateCopy returns Z_OK if success, Z_MEM_ERROR if there was not
+   enough memory, Z_STREAM_ERROR if the source stream state was inconsistent
+   (such as zalloc being NULL). msg is left unchanged in both source and
+   destination.
+*/
+
+ZEXTERN int ZEXPORT deflateReset OF((z_streamp strm));
+/*
+     This function is equivalent to deflateEnd followed by deflateInit,
+   but does not free and reallocate all the internal compression state.
+   The stream will keep the same compression level and any other attributes
+   that may have been set by deflateInit2.
+
+      deflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source
+   stream state was inconsistent (such as zalloc or state being NULL).
+*/
+
+ZEXTERN int ZEXPORT deflateParams OF((z_streamp strm,
+                                      int level,
+                                      int strategy));
+/*
+     Dynamically update the compression level and compression strategy.  The
+   interpretation of level and strategy is as in deflateInit2.  This can be
+   used to switch between compression and straight copy of the input data, or
+   to switch to a different kind of input data requiring a different
+   strategy. If the compression level is changed, the input available so far
+   is compressed with the old level (and may be flushed); the new level will
+   take effect only at the next call of deflate().
+
+     Before the call of deflateParams, the stream state must be set as for
+   a call of deflate(), since the currently available input may have to
+   be compressed and flushed. In particular, strm->avail_out must be non-zero.
+
+     deflateParams returns Z_OK if success, Z_STREAM_ERROR if the source
+   stream state was inconsistent or if a parameter was invalid, Z_BUF_ERROR
+   if strm->avail_out was zero.
+*/
+
+ZEXTERN int ZEXPORT deflateTune OF((z_streamp strm,
+                                    int good_length,
+                                    int max_lazy,
+                                    int nice_length,
+                                    int max_chain));
+/*
+     Fine tune deflate's internal compression parameters.  This should only be
+   used by someone who understands the algorithm used by zlib's deflate for
+   searching for the best matching string, and even then only by the most
+   fanatic optimizer trying to squeeze out the last compressed bit for their
+   specific input data.  Read the deflate.c source code for the meaning of the
+   max_lazy, good_length, nice_length, and max_chain parameters.
+
+     deflateTune() can be called after deflateInit() or deflateInit2(), and
+   returns Z_OK on success, or Z_STREAM_ERROR for an invalid deflate stream.
+ */
+
+ZEXTERN uLong ZEXPORT deflateBound OF((z_streamp strm,
+                                       uLong sourceLen));
+/*
+     deflateBound() returns an upper bound on the compressed size after
+   deflation of sourceLen bytes.  It must be called after deflateInit()
+   or deflateInit2().  This would be used to allocate an output buffer
+   for deflation in a single pass, and so would be called before deflate().
+*/
+
+ZEXTERN int ZEXPORT deflatePrime OF((z_streamp strm,
+                                     int bits,
+                                     int value));
+/*
+     deflatePrime() inserts bits in the deflate output stream.  The intent
+  is that this function is used to start off the deflate output with the
+  bits leftover from a previous deflate stream when appending to it.  As such,
+  this function can only be used for raw deflate, and must be used before the
+  first deflate() call after a deflateInit2() or deflateReset().  bits must be
+  less than or equal to 16, and that many of the least significant bits of
+  value will be inserted in the output.
+
+      deflatePrime returns Z_OK if success, or Z_STREAM_ERROR if the source
+   stream state was inconsistent.
+*/
+
+ZEXTERN int ZEXPORT deflateSetHeader OF((z_streamp strm,
+                                         gz_headerp head));
+/*
+      deflateSetHeader() provides gzip header information for when a gzip
+   stream is requested by deflateInit2().  deflateSetHeader() may be called
+   after deflateInit2() or deflateReset() and before the first call of
+   deflate().  The text, time, os, extra field, name, and comment information
+   in the provided gz_header structure are written to the gzip header (xflag is
+   ignored -- the extra flags are set according to the compression level).  The
+   caller must assure that, if not Z_NULL, name and comment are terminated with
+   a zero byte, and that if extra is not Z_NULL, that extra_len bytes are
+   available there.  If hcrc is true, a gzip header crc is included.  Note that
+   the current versions of the command-line version of gzip (up through version
+   1.3.x) do not support header crc's, and will report that it is a "multi-part
+   gzip file" and give up.
+
+      If deflateSetHeader is not used, the default gzip header has text false,
+   the time set to zero, and os set to 255, with no extra, name, or comment
+   fields.  The gzip header is returned to the default state by deflateReset().
+
+      deflateSetHeader returns Z_OK if success, or Z_STREAM_ERROR if the source
+   stream state was inconsistent.
+*/
+
+/*
+ZEXTERN int ZEXPORT inflateInit2 OF((z_streamp strm,
+                                     int  windowBits));
+
+     This is another version of inflateInit with an extra parameter. The
+   fields next_in, avail_in, zalloc, zfree and opaque must be initialized
+   before by the caller.
+
+     The windowBits parameter is the base two logarithm of the maximum window
+   size (the size of the history buffer).  It should be in the range 8..15 for
+   this version of the library. The default value is 15 if inflateInit is used
+   instead. windowBits must be greater than or equal to the windowBits value
+   provided to deflateInit2() while compressing, or it must be equal to 15 if
+   deflateInit2() was not used. If a compressed stream with a larger window
+   size is given as input, inflate() will return with the error code
+   Z_DATA_ERROR instead of trying to allocate a larger window.
+
+     windowBits can also be -8..-15 for raw inflate. In this case, -windowBits
+   determines the window size. inflate() will then process raw deflate data,
+   not looking for a zlib or gzip header, not generating a check value, and not
+   looking for any check values for comparison at the end of the stream. This
+   is for use with other formats that use the deflate compressed data format
+   such as zip.  Those formats provide their own check values. If a custom
+   format is developed using the raw deflate format for compressed data, it is
+   recommended that a check value such as an adler32 or a crc32 be applied to
+   the uncompressed data as is done in the zlib, gzip, and zip formats.  For
+   most applications, the zlib format should be used as is. Note that comments
+   above on the use in deflateInit2() applies to the magnitude of windowBits.
+
+     windowBits can also be greater than 15 for optional gzip decoding. Add
+   32 to windowBits to enable zlib and gzip decoding with automatic header
+   detection, or add 16 to decode only the gzip format (the zlib format will
+   return a Z_DATA_ERROR).  If a gzip stream is being decoded, strm->adler is
+   a crc32 instead of an adler32.
+
+     inflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was not enough
+   memory, Z_STREAM_ERROR if a parameter is invalid (such as a null strm). msg
+   is set to null if there is no error message.  inflateInit2 does not perform
+   any decompression apart from reading the zlib header if present: this will
+   be done by inflate(). (So next_in and avail_in may be modified, but next_out
+   and avail_out are unchanged.)
+*/
+
+ZEXTERN int ZEXPORT inflateSetDictionary OF((z_streamp strm,
+                                             const Bytef *dictionary,
+                                             uInt  dictLength));
+/*
+     Initializes the decompression dictionary from the given uncompressed byte
+   sequence. This function must be called immediately after a call of inflate,
+   if that call returned Z_NEED_DICT. The dictionary chosen by the compressor
+   can be determined from the adler32 value returned by that call of inflate.
+   The compressor and decompressor must use exactly the same dictionary (see
+   deflateSetDictionary).  For raw inflate, this function can be called
+   immediately after inflateInit2() or inflateReset() and before any call of
+   inflate() to set the dictionary.  The application must insure that the
+   dictionary that was used for compression is provided.
+
+     inflateSetDictionary returns Z_OK if success, Z_STREAM_ERROR if a
+   parameter is invalid (such as NULL dictionary) or the stream state is
+   inconsistent, Z_DATA_ERROR if the given dictionary doesn't match the
+   expected one (incorrect adler32 value). inflateSetDictionary does not
+   perform any decompression: this will be done by subsequent calls of
+   inflate().
+*/
+
+ZEXTERN int ZEXPORT inflateSync OF((z_streamp strm));
+/*
+    Skips invalid compressed data until a full flush point (see above the
+  description of deflate with Z_FULL_FLUSH) can be found, or until all
+  available input is skipped. No output is provided.
+
+    inflateSync returns Z_OK if a full flush point has been found, Z_BUF_ERROR
+  if no more input was provided, Z_DATA_ERROR if no flush point has been found,
+  or Z_STREAM_ERROR if the stream structure was inconsistent. In the success
+  case, the application may save the current current value of total_in which
+  indicates where valid compressed data was found. In the error case, the
+  application may repeatedly call inflateSync, providing more input each time,
+  until success or end of the input data.
+*/
+
+ZEXTERN int ZEXPORT inflateCopy OF((z_streamp dest,
+                                    z_streamp source));
+/*
+     Sets the destination stream as a complete copy of the source stream.
+
+     This function can be useful when randomly accessing a large stream.  The
+   first pass through the stream can periodically record the inflate state,
+   allowing restarting inflate at those points when randomly accessing the
+   stream.
+
+     inflateCopy returns Z_OK if success, Z_MEM_ERROR if there was not
+   enough memory, Z_STREAM_ERROR if the source stream state was inconsistent
+   (such as zalloc being NULL). msg is left unchanged in both source and
+   destination.
+*/
+
+ZEXTERN int ZEXPORT inflateReset OF((z_streamp strm));
+/*
+     This function is equivalent to inflateEnd followed by inflateInit,
+   but does not free and reallocate all the internal decompression state.
+   The stream will keep attributes that may have been set by inflateInit2.
+
+      inflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source
+   stream state was inconsistent (such as zalloc or state being NULL).
+*/
+
+ZEXTERN int ZEXPORT inflatePrime OF((z_streamp strm,
+                                     int bits,
+                                     int value));
+/*
+     This function inserts bits in the inflate input stream.  The intent is
+  that this function is used to start inflating at a bit position in the
+  middle of a byte.  The provided bits will be used before any bytes are used
+  from next_in.  This function should only be used with raw inflate, and
+  should be used before the first inflate() call after inflateInit2() or
+  inflateReset().  bits must be less than or equal to 16, and that many of the
+  least significant bits of value will be inserted in the input.
+
+      inflatePrime returns Z_OK if success, or Z_STREAM_ERROR if the source
+   stream state was inconsistent.
+*/
+
+ZEXTERN int ZEXPORT inflateGetHeader OF((z_streamp strm,
+                                         gz_headerp head));
+/*
+      inflateGetHeader() requests that gzip header information be stored in the
+   provided gz_header structure.  inflateGetHeader() may be called after
+   inflateInit2() or inflateReset(), and before the first call of inflate().
+   As inflate() processes the gzip stream, head->done is zero until the header
+   is completed, at which time head->done is set to one.  If a zlib stream is
+   being decoded, then head->done is set to -1 to indicate that there will be
+   no gzip header information forthcoming.  Note that Z_BLOCK can be used to
+   force inflate() to return immediately after header processing is complete
+   and before any actual data is decompressed.
+
+      The text, time, xflags, and os fields are filled in with the gzip header
+   contents.  hcrc is set to true if there is a header CRC.  (The header CRC
+   was valid if done is set to one.)  If extra is not Z_NULL, then extra_max
+   contains the maximum number of bytes to write to extra.  Once done is true,
+   extra_len contains the actual extra field length, and extra contains the
+   extra field, or that field truncated if extra_max is less than extra_len.
+   If name is not Z_NULL, then up to name_max characters are written there,
+   terminated with a zero unless the length is greater than name_max.  If
+   comment is not Z_NULL, then up to comm_max characters are written there,
+   terminated with a zero unless the length is greater than comm_max.  When
+   any of extra, name, or comment are not Z_NULL and the respective field is
+   not present in the header, then that field is set to Z_NULL to signal its
+   absence.  This allows the use of deflateSetHeader() with the returned
+   structure to duplicate the header.  However if those fields are set to
+   allocated memory, then the application will need to save those pointers
+   elsewhere so that they can be eventually freed.
+
+      If inflateGetHeader is not used, then the header information is simply
+   discarded.  The header is always checked for validity, including the header
+   CRC if present.  inflateReset() will reset the process to discard the header
+   information.  The application would need to call inflateGetHeader() again to
+   retrieve the header from the next gzip stream.
+
+      inflateGetHeader returns Z_OK if success, or Z_STREAM_ERROR if the source
+   stream state was inconsistent.
+*/
+
+/*
+ZEXTERN int ZEXPORT inflateBackInit OF((z_streamp strm, int windowBits,
+                                        unsigned char FAR *window));
+
+     Initialize the internal stream state for decompression using inflateBack()
+   calls.  The fields zalloc, zfree and opaque in strm must be initialized
+   before the call.  If zalloc and zfree are Z_NULL, then the default library-
+   derived memory allocation routines are used.  windowBits is the base two
+   logarithm of the window size, in the range 8..15.  window is a caller
+   supplied buffer of that size.  Except for special applications where it is
+   assured that deflate was used with small window sizes, windowBits must be 15
+   and a 32K byte window must be supplied to be able to decompress general
+   deflate streams.
+
+     See inflateBack() for the usage of these routines.
+
+     inflateBackInit will return Z_OK on success, Z_STREAM_ERROR if any of
+   the paramaters are invalid, Z_MEM_ERROR if the internal state could not
+   be allocated, or Z_VERSION_ERROR if the version of the library does not
+   match the version of the header file.
+*/
+
+typedef unsigned (*in_func) OF((void FAR *, unsigned char FAR * FAR *));
+typedef int (*out_func) OF((void FAR *, unsigned char FAR *, unsigned));
+
+ZEXTERN int ZEXPORT inflateBack OF((z_streamp strm,
+                                    in_func in, void FAR *in_desc,
+                                    out_func out, void FAR *out_desc));
+/*
+     inflateBack() does a raw inflate with a single call using a call-back
+   interface for input and output.  This is more efficient than inflate() for
+   file i/o applications in that it avoids copying between the output and the
+   sliding window by simply making the window itself the output buffer.  This
+   function trusts the application to not change the output buffer passed by
+   the output function, at least until inflateBack() returns.
+
+     inflateBackInit() must be called first to allocate the internal state
+   and to initialize the state with the user-provided window buffer.
+   inflateBack() may then be used multiple times to inflate a complete, raw
+   deflate stream with each call.  inflateBackEnd() is then called to free
+   the allocated state.
+
+     A raw deflate stream is one with no zlib or gzip header or trailer.
+   This routine would normally be used in a utility that reads zip or gzip
+   files and writes out uncompressed files.  The utility would decode the
+   header and process the trailer on its own, hence this routine expects
+   only the raw deflate stream to decompress.  This is different from the
+   normal behavior of inflate(), which expects either a zlib or gzip header and
+   trailer around the deflate stream.
+
+     inflateBack() uses two subroutines supplied by the caller that are then
+   called by inflateBack() for input and output.  inflateBack() calls those
+   routines until it reads a complete deflate stream and writes out all of the
+   uncompressed data, or until it encounters an error.  The function's
+   parameters and return types are defined above in the in_func and out_func
+   typedefs.  inflateBack() will call in(in_desc, &buf) which should return the
+   number of bytes of provided input, and a pointer to that input in buf.  If
+   there is no input available, in() must return zero--buf is ignored in that
+   case--and inflateBack() will return a buffer error.  inflateBack() will call
+   out(out_desc, buf, len) to write the uncompressed data buf[0..len-1].  out()
+   should return zero on success, or non-zero on failure.  If out() returns
+   non-zero, inflateBack() will return with an error.  Neither in() nor out()
+   are permitted to change the contents of the window provided to
+   inflateBackInit(), which is also the buffer that out() uses to write from.
+   The length written by out() will be at most the window size.  Any non-zero
+   amount of input may be provided by in().
+
+     For convenience, inflateBack() can be provided input on the first call by
+   setting strm->next_in and strm->avail_in.  If that input is exhausted, then
+   in() will be called.  Therefore strm->next_in must be initialized before
+   calling inflateBack().  If strm->next_in is Z_NULL, then in() will be called
+   immediately for input.  If strm->next_in is not Z_NULL, then strm->avail_in
+   must also be initialized, and then if strm->avail_in is not zero, input will
+   initially be taken from strm->next_in[0 .. strm->avail_in - 1].
+
+     The in_desc and out_desc parameters of inflateBack() is passed as the
+   first parameter of in() and out() respectively when they are called.  These
+   descriptors can be optionally used to pass any information that the caller-
+   supplied in() and out() functions need to do their job.
+
+     On return, inflateBack() will set strm->next_in and strm->avail_in to
+   pass back any unused input that was provided by the last in() call.  The
+   return values of inflateBack() can be Z_STREAM_END on success, Z_BUF_ERROR
+   if in() or out() returned an error, Z_DATA_ERROR if there was a format
+   error in the deflate stream (in which case strm->msg is set to indicate the
+   nature of the error), or Z_STREAM_ERROR if the stream was not properly
+   initialized.  In the case of Z_BUF_ERROR, an input or output error can be
+   distinguished using strm->next_in which will be Z_NULL only if in() returned
+   an error.  If strm->next is not Z_NULL, then the Z_BUF_ERROR was due to
+   out() returning non-zero.  (in() will always be called before out(), so
+   strm->next_in is assured to be defined if out() returns non-zero.)  Note
+   that inflateBack() cannot return Z_OK.
+*/
+
+ZEXTERN int ZEXPORT inflateBackEnd OF((z_streamp strm));
+/*
+     All memory allocated by inflateBackInit() is freed.
+
+     inflateBackEnd() returns Z_OK on success, or Z_STREAM_ERROR if the stream
+   state was inconsistent.
+*/
+
+ZEXTERN uLong ZEXPORT zlibCompileFlags OF((void));
+/* Return flags indicating compile-time options.
+
+    Type sizes, two bits each, 00 = 16 bits, 01 = 32, 10 = 64, 11 = other:
+     1.0: size of uInt
+     3.2: size of uLong
+     5.4: size of voidpf (pointer)
+     7.6: size of z_off_t
+
+    Compiler, assembler, and debug options:
+     8: DEBUG
+     9: ASMV or ASMINF -- use ASM code
+     10: ZLIB_WINAPI -- exported functions use the WINAPI calling convention
+     11: 0 (reserved)
+
+    One-time table building (smaller code, but not thread-safe if true):
+     12: BUILDFIXED -- build static block decoding tables when needed
+     13: DYNAMIC_CRC_TABLE -- build CRC calculation tables when needed
+     14,15: 0 (reserved)
+
+    Library content (indicates missing functionality):
+     16: NO_GZCOMPRESS -- gz* functions cannot compress (to avoid linking
+                          deflate code when not needed)
+     17: NO_GZIP -- deflate can't write gzip streams, and inflate can't detect
+                    and decode gzip streams (to avoid linking crc code)
+     18-19: 0 (reserved)
+
+    Operation variations (changes in library functionality):
+     20: PKZIP_BUG_WORKAROUND -- slightly more permissive inflate
+     21: FASTEST -- deflate algorithm with only one, lowest compression level
+     22,23: 0 (reserved)
+
+    The sprintf variant used by gzprintf (zero is best):
+     24: 0 = vs*, 1 = s* -- 1 means limited to 20 arguments after the format
+     25: 0 = *nprintf, 1 = *printf -- 1 means gzprintf() not secure!
+     26: 0 = returns value, 1 = void -- 1 means inferred string length returned
+
+    Remainder:
+     27-31: 0 (reserved)
+ */
+
+
+                        /* utility functions */
+
+/*
+     The following utility functions are implemented on top of the
+   basic stream-oriented functions. To simplify the interface, some
+   default options are assumed (compression level and memory usage,
+   standard memory allocation functions). The source code of these
+   utility functions can easily be modified if you need special options.
+*/
+
+ZEXTERN int ZEXPORT compress OF((Bytef *dest,   uLongf *destLen,
+                                 const Bytef *source, uLong sourceLen));
+/*
+     Compresses the source buffer into the destination buffer.  sourceLen is
+   the byte length of the source buffer. Upon entry, destLen is the total
+   size of the destination buffer, which must be at least the value returned
+   by compressBound(sourceLen). Upon exit, destLen is the actual size of the
+   compressed buffer.
+     This function can be used to compress a whole file at once if the
+   input file is mmap'ed.
+     compress returns Z_OK if success, Z_MEM_ERROR if there was not
+   enough memory, Z_BUF_ERROR if there was not enough room in the output
+   buffer.
+*/
+
+ZEXTERN int ZEXPORT compress2 OF((Bytef *dest,   uLongf *destLen,
+                                  const Bytef *source, uLong sourceLen,
+                                  int level));
+/*
+     Compresses the source buffer into the destination buffer. The level
+   parameter has the same meaning as in deflateInit.  sourceLen is the byte
+   length of the source buffer. Upon entry, destLen is the total size of the
+   destination buffer, which must be at least the value returned by
+   compressBound(sourceLen). Upon exit, destLen is the actual size of the
+   compressed buffer.
+
+     compress2 returns Z_OK if success, Z_MEM_ERROR if there was not enough
+   memory, Z_BUF_ERROR if there was not enough room in the output buffer,
+   Z_STREAM_ERROR if the level parameter is invalid.
+*/
+
+ZEXTERN uLong ZEXPORT compressBound OF((uLong sourceLen));
+/*
+     compressBound() returns an upper bound on the compressed size after
+   compress() or compress2() on sourceLen bytes.  It would be used before
+   a compress() or compress2() call to allocate the destination buffer.
+*/
+
+ZEXTERN int ZEXPORT uncompress OF((Bytef *dest,   uLongf *destLen,
+                                   const Bytef *source, uLong sourceLen));
+/*
+     Decompresses the source buffer into the destination buffer.  sourceLen is
+   the byte length of the source buffer. Upon entry, destLen is the total
+   size of the destination buffer, which must be large enough to hold the
+   entire uncompressed data. (The size of the uncompressed data must have
+   been saved previously by the compressor and transmitted to the decompressor
+   by some mechanism outside the scope of this compression library.)
+   Upon exit, destLen is the actual size of the compressed buffer.
+     This function can be used to decompress a whole file at once if the
+   input file is mmap'ed.
+
+     uncompress returns Z_OK if success, Z_MEM_ERROR if there was not
+   enough memory, Z_BUF_ERROR if there was not enough room in the output
+   buffer, or Z_DATA_ERROR if the input data was corrupted or incomplete.
+*/
+
+
+typedef voidp gzFile;
+
+ZEXTERN gzFile ZEXPORT gzopen  OF((const char *path, const char *mode));
+/*
+     Opens a gzip (.gz) file for reading or writing. The mode parameter
+   is as in fopen ("rb" or "wb") but can also include a compression level
+   ("wb9") or a strategy: 'f' for filtered data as in "wb6f", 'h' for
+   Huffman only compression as in "wb1h", or 'R' for run-length encoding
+   as in "wb1R". (See the description of deflateInit2 for more information
+   about the strategy parameter.)
+
+     gzopen can be used to read a file which is not in gzip format; in this
+   case gzread will directly read from the file without decompression.
+
+     gzopen returns NULL if the file could not be opened or if there was
+   insufficient memory to allocate the (de)compression state; errno
+   can be checked to distinguish the two cases (if errno is zero, the
+   zlib error is Z_MEM_ERROR).  */
+
+ZEXTERN gzFile ZEXPORT gzdopen  OF((int fd, const char *mode));
+/*
+     gzdopen() associates a gzFile with the file descriptor fd.  File
+   descriptors are obtained from calls like open, dup, creat, pipe or
+   fileno (in the file has been previously opened with fopen).
+   The mode parameter is as in gzopen.
+     The next call of gzclose on the returned gzFile will also close the
+   file descriptor fd, just like fclose(fdopen(fd), mode) closes the file
+   descriptor fd. If you want to keep fd open, use gzdopen(dup(fd), mode).
+     gzdopen returns NULL if there was insufficient memory to allocate
+   the (de)compression state.
+*/
+
+ZEXTERN int ZEXPORT gzsetparams OF((gzFile file, int level, int strategy));
+/*
+     Dynamically update the compression level or strategy. See the description
+   of deflateInit2 for the meaning of these parameters.
+     gzsetparams returns Z_OK if success, or Z_STREAM_ERROR if the file was not
+   opened for writing.
+*/
+
+ZEXTERN int ZEXPORT    gzread  OF((gzFile file, voidp buf, unsigned len));
+/*
+     Reads the given number of uncompressed bytes from the compressed file.
+   If the input file was not in gzip format, gzread copies the given number
+   of bytes into the buffer.
+     gzread returns the number of uncompressed bytes actually read (0 for
+   end of file, -1 for error). */
+
+ZEXTERN int ZEXPORT    gzwrite OF((gzFile file,
+                                   voidpc buf, unsigned len));
+/*
+     Writes the given number of uncompressed bytes into the compressed file.
+   gzwrite returns the number of uncompressed bytes actually written
+   (0 in case of error).
+*/
+
+ZEXTERN int ZEXPORTVA   gzprintf OF((gzFile file, const char *format, ...));
+/*
+     Converts, formats, and writes the args to the compressed file under
+   control of the format string, as in fprintf. gzprintf returns the number of
+   uncompressed bytes actually written (0 in case of error).  The number of
+   uncompressed bytes written is limited to 4095. The caller should assure that
+   this limit is not exceeded. If it is exceeded, then gzprintf() will return
+   return an error (0) with nothing written. In this case, there may also be a
+   buffer overflow with unpredictable consequences, which is possible only if
+   zlib was compiled with the insecure functions sprintf() or vsprintf()
+   because the secure snprintf() or vsnprintf() functions were not available.
+*/
+
+ZEXTERN int ZEXPORT gzputs OF((gzFile file, const char *s));
+/*
+      Writes the given null-terminated string to the compressed file, excluding
+   the terminating null character.
+      gzputs returns the number of characters written, or -1 in case of error.
+*/
+
+ZEXTERN char * ZEXPORT gzgets OF((gzFile file, char *buf, int len));
+/*
+      Reads bytes from the compressed file until len-1 characters are read, or
+   a newline character is read and transferred to buf, or an end-of-file
+   condition is encountered.  The string is then terminated with a null
+   character.
+      gzgets returns buf, or Z_NULL in case of error.
+*/
+
+ZEXTERN int ZEXPORT    gzputc OF((gzFile file, int c));
+/*
+      Writes c, converted to an unsigned char, into the compressed file.
+   gzputc returns the value that was written, or -1 in case of error.
+*/
+
+ZEXTERN int ZEXPORT    gzgetc OF((gzFile file));
+/*
+      Reads one byte from the compressed file. gzgetc returns this byte
+   or -1 in case of end of file or error.
+*/
+
+ZEXTERN int ZEXPORT    gzungetc OF((int c, gzFile file));
+/*
+      Push one character back onto the stream to be read again later.
+   Only one character of push-back is allowed.  gzungetc() returns the
+   character pushed, or -1 on failure.  gzungetc() will fail if a
+   character has been pushed but not read yet, or if c is -1. The pushed
+   character will be discarded if the stream is repositioned with gzseek()
+   or gzrewind().
+*/
+
+ZEXTERN int ZEXPORT    gzflush OF((gzFile file, int flush));
+/*
+     Flushes all pending output into the compressed file. The parameter
+   flush is as in the deflate() function. The return value is the zlib
+   error number (see function gzerror below). gzflush returns Z_OK if
+   the flush parameter is Z_FINISH and all output could be flushed.
+     gzflush should be called only when strictly necessary because it can
+   degrade compression.
+*/
+
+ZEXTERN z_off_t ZEXPORT    gzseek OF((gzFile file,
+                                      z_off_t offset, int whence));
+/*
+      Sets the starting position for the next gzread or gzwrite on the
+   given compressed file. The offset represents a number of bytes in the
+   uncompressed data stream. The whence parameter is defined as in lseek(2);
+   the value SEEK_END is not supported.
+     If the file is opened for reading, this function is emulated but can be
+   extremely slow. If the file is opened for writing, only forward seeks are
+   supported; gzseek then compresses a sequence of zeroes up to the new
+   starting position.
+
+      gzseek returns the resulting offset location as measured in bytes from
+   the beginning of the uncompressed stream, or -1 in case of error, in
+   particular if the file is opened for writing and the new starting position
+   would be before the current position.
+*/
+
+ZEXTERN int ZEXPORT    gzrewind OF((gzFile file));
+/*
+     Rewinds the given file. This function is supported only for reading.
+
+   gzrewind(file) is equivalent to (int)gzseek(file, 0L, SEEK_SET)
+*/
+
+ZEXTERN z_off_t ZEXPORT    gztell OF((gzFile file));
+/*
+     Returns the starting position for the next gzread or gzwrite on the
+   given compressed file. This position represents a number of bytes in the
+   uncompressed data stream.
+
+   gztell(file) is equivalent to gzseek(file, 0L, SEEK_CUR)
+*/
+
+ZEXTERN int ZEXPORT gzeof OF((gzFile file));
+/*
+     Returns 1 when EOF has previously been detected reading the given
+   input stream, otherwise zero.
+*/
+
+ZEXTERN int ZEXPORT gzdirect OF((gzFile file));
+/*
+     Returns 1 if file is being read directly without decompression, otherwise
+   zero.
+*/
+
+ZEXTERN int ZEXPORT    gzclose OF((gzFile file));
+/*
+     Flushes all pending output if necessary, closes the compressed file
+   and deallocates all the (de)compression state. The return value is the zlib
+   error number (see function gzerror below).
+*/
+
+ZEXTERN const char * ZEXPORT gzerror OF((gzFile file, int *errnum));
+/*
+     Returns the error message for the last error which occurred on the
+   given compressed file. errnum is set to zlib error number. If an
+   error occurred in the file system and not in the compression library,
+   errnum is set to Z_ERRNO and the application may consult errno
+   to get the exact error code.
+*/
+
+ZEXTERN void ZEXPORT gzclearerr OF((gzFile file));
+/*
+     Clears the error and end-of-file flags for file. This is analogous to the
+   clearerr() function in stdio. This is useful for continuing to read a gzip
+   file that is being written concurrently.
+*/
+
+                        /* checksum functions */
+
+/*
+     These functions are not related to compression but are exported
+   anyway because they might be useful in applications using the
+   compression library.
+*/
+
+ZEXTERN uLong ZEXPORT adler32 OF((uLong adler, const Bytef *buf, uInt len));
+/*
+     Update a running Adler-32 checksum with the bytes buf[0..len-1] and
+   return the updated checksum. If buf is NULL, this function returns
+   the required initial value for the checksum.
+   An Adler-32 checksum is almost as reliable as a CRC32 but can be computed
+   much faster. Usage example:
+
+     uLong adler = adler32(0L, Z_NULL, 0);
+
+     while (read_buffer(buffer, length) != EOF) {
+       adler = adler32(adler, buffer, length);
+     }
+     if (adler != original_adler) error();
+*/
+
+ZEXTERN uLong ZEXPORT adler32_combine OF((uLong adler1, uLong adler2,
+                                          z_off_t len2));
+/*
+     Combine two Adler-32 checksums into one.  For two sequences of bytes, seq1
+   and seq2 with lengths len1 and len2, Adler-32 checksums were calculated for
+   each, adler1 and adler2.  adler32_combine() returns the Adler-32 checksum of
+   seq1 and seq2 concatenated, requiring only adler1, adler2, and len2.
+*/
+
+ZEXTERN uLong ZEXPORT crc32   OF((uLong crc, const Bytef *buf, uInt len));
+/*
+     Update a running CRC-32 with the bytes buf[0..len-1] and return the
+   updated CRC-32. If buf is NULL, this function returns the required initial
+   value for the for the crc. Pre- and post-conditioning (one's complement) is
+   performed within this function so it shouldn't be done by the application.
+   Usage example:
+
+     uLong crc = crc32(0L, Z_NULL, 0);
+
+     while (read_buffer(buffer, length) != EOF) {
+       crc = crc32(crc, buffer, length);
+     }
+     if (crc != original_crc) error();
+*/
+
+ZEXTERN uLong ZEXPORT crc32_combine OF((uLong crc1, uLong crc2, z_off_t len2));
+
+/*
+     Combine two CRC-32 check values into one.  For two sequences of bytes,
+   seq1 and seq2 with lengths len1 and len2, CRC-32 check values were
+   calculated for each, crc1 and crc2.  crc32_combine() returns the CRC-32
+   check value of seq1 and seq2 concatenated, requiring only crc1, crc2, and
+   len2.
+*/
+
+
+                        /* various hacks, don't look :) */
+
+/* deflateInit and inflateInit are macros to allow checking the zlib version
+ * and the compiler's view of z_stream:
+ */
+ZEXTERN int ZEXPORT deflateInit_ OF((z_streamp strm, int level,
+                                     const char *version, int stream_size));
+ZEXTERN int ZEXPORT inflateInit_ OF((z_streamp strm,
+                                     const char *version, int stream_size));
+ZEXTERN int ZEXPORT deflateInit2_ OF((z_streamp strm, int  level, int  method,
+                                      int windowBits, int memLevel,
+                                      int strategy, const char *version,
+                                      int stream_size));
+ZEXTERN int ZEXPORT inflateInit2_ OF((z_streamp strm, int  windowBits,
+                                      const char *version, int stream_size));
+ZEXTERN int ZEXPORT inflateBackInit_ OF((z_streamp strm, int windowBits,
+                                         unsigned char FAR *window,
+                                         const char *version,
+                                         int stream_size));
+#define deflateInit(strm, level) \
+        deflateInit_((strm), (level),       ZLIB_VERSION, sizeof(z_stream))
+#define inflateInit(strm) \
+        inflateInit_((strm),                ZLIB_VERSION, sizeof(z_stream))
+#define deflateInit2(strm, level, method, windowBits, memLevel, strategy) \
+        deflateInit2_((strm),(level),(method),(windowBits),(memLevel),\
+                      (strategy),           ZLIB_VERSION, sizeof(z_stream))
+#define inflateInit2(strm, windowBits) \
+        inflateInit2_((strm), (windowBits), ZLIB_VERSION, sizeof(z_stream))
+#define inflateBackInit(strm, windowBits, window) \
+        inflateBackInit_((strm), (windowBits), (window), \
+        ZLIB_VERSION, sizeof(z_stream))
+
+
+#if !defined(ZUTIL_H) && !defined(NO_DUMMY_DECL)
+    struct internal_state {int dummy;}; /* hack for buggy compilers */
+#endif
+
+ZEXTERN const char   * ZEXPORT zError           OF((int));
+ZEXTERN int            ZEXPORT inflateSyncPoint OF((z_streamp z));
+ZEXTERN const uLongf * ZEXPORT get_crc_table    OF((void));
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* ZLIB_H */
diff --git a/usr/initramfs.default b/usr/initramfs.default
new file mode 100644
index 0000000..d23437a
--- /dev/null
+++ b/usr/initramfs.default
@@ -0,0 +1,9 @@
+#####################
+# This is a very simple, default initramfs
+# See gen_init_cpio for syntax
+
+dir dev 0755 0 0
+nod dev/console 0600 0 0 c 5 1
+dir root 0700 0 0
+file kinit usr/kinit/kinit 0755 0 0
+slink init kinit 0755 0 0
diff --git a/usr/kinit/Kbuild b/usr/kinit/Kbuild
new file mode 100644
index 0000000..ff1d449
--- /dev/null
+++ b/usr/kinit/Kbuild
@@ -0,0 +1,37 @@
+#
+# Kbuild file for kinit
+#
+
+# library part of kinit. Is used by programs in sub-directories (resume et al)
+lib-y   := name_to_dev.o devname.o getarg.o
+# use lib for kinit
+kinit-y  := lib.a
+
+kinit-y  += kinit.o do_mounts.o ramdisk_load.o initrd.o
+kinit-y  += getintfile.o readfile.o xpio.o
+kinit-y  += do_mounts_md.o do_mounts_mtd.o nfsroot.o
+
+kinit-y  += ipconfig/
+kinit-y  += nfsmount/
+kinit-y  += run-init/
+kinit-y  += fstype/
+kinit-y  += resume/
+
+static-y := kinit
+shared-y := kinit.shared
+kinit.shared-y := $(kinit-y)
+
+# Additional include paths files
+KLIBCCFLAGS += -I$(srctree)/$(src)/fstype \
+	       -I$(srctree)/$(src)/ipconfig \
+  	       -I$(srctree)/$(src)/nfsmount \
+  	       -I$(srctree)/$(src)/resume \
+ 	       -I$(srctree)/$(src)/run-init
+
+# Cleaning
+targets += kinit kinit.g kinit.shared kinit.shared.g
+subdir- := fstype ipconfig nfsmount resume run-init
+
+
+# install binary
+install-y := kinit kinit.shared
diff --git a/usr/kinit/README b/usr/kinit/README
new file mode 100644
index 0000000..fa7f645
--- /dev/null
+++ b/usr/kinit/README
@@ -0,0 +1,9 @@
+kinit - tiny init program
+-------------------------
+
+This program is intended for use as /sbin/init in an initramfs
+environment.  It currently replaces the kernel's ipconfig and nfsroot
+code.
+
+--
+Bryan O'Sullivan (2003/05/05)
diff --git a/usr/kinit/devname.c b/usr/kinit/devname.c
new file mode 100644
index 0000000..aeb2135
--- /dev/null
+++ b/usr/kinit/devname.c
@@ -0,0 +1,112 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <dirent.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/sysmacros.h>
+
+/*
+ * Print the name of a block device.
+ */
+#define BUF_SIZE	512
+
+static int scansysdir(char *namebuf, char *sysdir, dev_t dev)
+{
+	char *dirtailptr = strchr(sysdir, '\0');
+	DIR *dir;
+	int done = 0;
+	struct dirent *de;
+	char *systail;
+	FILE *sysdev;
+	unsigned long ma, mi;
+	char *ep;
+	ssize_t rd;
+
+	if (!(dir = opendir(sysdir)))
+		return 0;
+
+	*dirtailptr++ = '/';
+
+	while (!done && (de = readdir(dir))) {
+		/* Assume if we see a dot-name in sysfs it's special */
+		if (de->d_name[0] == '.')
+			continue;
+
+		if (de->d_type != DT_UNKNOWN && de->d_type != DT_DIR)
+			continue;
+
+		if (strlen(de->d_name) >=
+		    (BUF_SIZE - 64) - (dirtailptr - sysdir))
+			continue;	/* Badness... */
+
+		strcpy(dirtailptr, de->d_name);
+		systail = strchr(sysdir, '\0');
+
+		strcpy(systail, "/dev");
+		if (!(sysdev = fopen(sysdir, "r")))
+			continue;
+
+		/* Abusing the namebuf as temporary storage here. */
+		rd = fread(namebuf, 1, BUF_SIZE, sysdev);
+		namebuf[rd] = '\0';	/* Just in case... */
+
+		fclose(sysdev);
+
+		ma = strtoul(namebuf, &ep, 10);
+		if (ma != major(dev) || *ep != ':')
+			continue;
+
+		mi = strtoul(ep + 1, &ep, 10);
+		if (*ep != '\n')
+			continue;
+
+		if (mi == minor(dev)) {
+			/* Found it! */
+			strcpy(namebuf, de->d_name);
+			done = 1;
+		} else {
+			/* we have a major number match, scan for partitions */
+			*systail = '\0';
+			done = scansysdir(namebuf, sysdir, dev);
+		}
+	}
+
+	closedir(dir);
+	return done;
+}
+
+const char *bdevname(dev_t dev)
+{
+	static char buf[BUF_SIZE];
+	char sysdir[BUF_SIZE];
+	char *p;
+
+	strcpy(sysdir, "/sys/block");
+
+	if (!scansysdir(buf, sysdir, dev))
+		strcpy(buf, "dev");	/* prints e.g. dev(3,5) */
+
+	p = strchr(buf, '\0');
+	snprintf(p, sizeof buf - (p - buf), "(%d,%d)", major(dev), minor(dev));
+
+	return buf;
+}
+
+#ifdef TEST_DEVNAME		/* Standalone test */
+
+int main(int argc, char *argv[])
+{
+	dev_t dev;
+	int i;
+
+	for (i = 1; i < argc; i++) {
+		dev = strtoul(argv[i], NULL, 0);
+
+		printf("0x%08x = %s\n", (unsigned int)dev, bdevname(dev));
+	}
+
+	return 0;
+}
+
+#endif				/* TEST */
diff --git a/usr/kinit/do_mounts.c b/usr/kinit/do_mounts.c
new file mode 100644
index 0000000..9daa006
--- /dev/null
+++ b/usr/kinit/do_mounts.c
@@ -0,0 +1,221 @@
+#include <ctype.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <sys/mount.h>
+#include <sys/stat.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <alloca.h>
+#include <inttypes.h>
+
+#include "do_mounts.h"
+#include "kinit.h"
+#include "fstype.h"
+#include "zlib.h"
+
+/* Create the device node "name" */
+int create_dev(const char *name, dev_t dev)
+{
+	unlink(name);
+	return mknod(name, S_IFBLK | 0600, dev);
+}
+
+/* mount a filesystem, possibly trying a set of different types */
+const char *mount_block(const char *source, const char *target,
+			const char *type, unsigned long flags,
+			const void *data)
+{
+	char *fslist, *p, *ep;
+	const char *rp;
+	ssize_t fsbytes;
+	int fd;
+
+	if (type) {
+		DEBUG(("kinit: trying to mount %s on %s with type %s\n",
+		       source, target, type));
+		int rv = mount(source, target, type, flags, data);
+		/* Mount readonly if necessary */
+		if (rv == -1 && errno == EACCES && !(flags & MS_RDONLY))
+			rv = mount(source, target, type, flags | MS_RDONLY,
+				   data);
+		return rv ? NULL : type;
+	}
+
+	/* If no type given, try to identify the type first; this
+	   also takes care of specific ordering requirements, like
+	   ext3 before ext2... */
+	fd = open(source, O_RDONLY);
+	if (fd >= 0) {
+		int err = identify_fs(fd, &type, NULL, 0);
+		close(fd);
+
+		if (!err && type) {
+			DEBUG(("kinit: %s appears to be a %s filesystem\n",
+			       source, type));
+			type = mount_block(source, target, type, flags, data);
+			if (type)
+				return type;
+		}
+	}
+
+	DEBUG(("kinit: failed to identify filesystem %s, trying all\n",
+	       source));
+
+	fsbytes = readfile("/proc/filesystems", &fslist);
+
+	errno = EINVAL;
+	if (fsbytes < 0)
+		return NULL;
+
+	p = fslist;
+	ep = fslist + fsbytes;
+
+	rp = NULL;
+
+	while (p < ep) {
+		type = p;
+		p = strchr(p, '\n');
+		if (!p)
+			break;
+		*p++ = '\0';
+		if (*type != '\t')	/* We can't mount a block device as a "nodev" fs */
+			continue;
+
+		type++;
+		rp = mount_block(source, target, type, flags, data);
+		if (rp)
+			break;
+		if (errno != EINVAL)
+			break;
+	}
+
+	free(fslist);
+	return rp;
+}
+
+/* mount the root filesystem from a block device */
+static int
+mount_block_root(int argc, char *argv[], dev_t root_dev,
+		 const char *type, unsigned long flags)
+{
+	const char *data, *rp;
+
+	data = get_arg(argc, argv, "rootflags=");
+	create_dev("/dev/root", root_dev);
+
+	errno = 0;
+
+	if (type) {
+		if ((rp = mount_block("/dev/root", "/root", type, flags, data)))
+			goto ok;
+		if (errno != EINVAL)
+			goto bad;
+	}
+
+	if (!errno
+	    && (rp = mount_block("/dev/root", "/root", NULL, flags, data)))
+		goto ok;
+
+      bad:
+	if (errno != EINVAL) {
+		/*
+		 * Allow the user to distinguish between failed open
+		 * and bad superblock on root device.
+		 */
+		fprintf(stderr, "%s: Cannot open root device %s\n",
+			progname, bdevname(root_dev));
+		return -errno;
+	} else {
+		fprintf(stderr, "%s: Unable to mount root fs on device %s\n",
+			progname, bdevname(root_dev));
+		return -ESRCH;
+	}
+
+      ok:
+	printf("%s: Mounted root (%s filesystem)%s.\n",
+	       progname, rp, (flags & MS_RDONLY) ? " readonly" : "");
+	return 0;
+}
+
+int
+mount_root(int argc, char *argv[], dev_t root_dev, const char *root_dev_name)
+{
+	unsigned long flags = MS_RDONLY | MS_VERBOSE;
+	int ret;
+	const char *type = get_arg(argc, argv, "rootfstype=");
+
+	if (get_flag(argc, argv, "rw") > get_flag(argc, argv, "ro")) {
+		DEBUG(("kinit: mounting root rw\n"));
+		flags &= ~MS_RDONLY;
+	}
+
+	if (type) {
+		if (!strcmp(type, "nfs"))
+			root_dev = Root_NFS;
+		else if (!strcmp(type, "jffs2") && !major(root_dev))
+			root_dev = Root_MTD;
+	}
+
+	switch (root_dev) {
+	case Root_NFS:
+		ret = mount_nfs_root(argc, argv, flags);
+		break;
+	case Root_MTD:
+		ret = mount_mtd_root(argc, argv, root_dev_name, type, flags);
+		break;
+	default:
+		ret = mount_block_root(argc, argv, root_dev, type, flags);
+		break;
+	}
+
+	if (!ret)
+		chdir("/root");
+
+	return ret;
+}
+
+int do_mounts(int argc, char *argv[])
+{
+	const char *root_dev_name = get_arg(argc, argv, "root=");
+	const char *root_delay = get_arg(argc, argv, "rootdelay=");
+	const char *load_ramdisk = get_arg(argc, argv, "load_ramdisk=");
+	dev_t root_dev = 0;
+
+	DEBUG(("kinit: do_mounts\n"));
+
+	if (root_delay) {
+		int delay = atoi(root_delay);
+		fprintf(stderr, "Waiting %d s before mounting root device...\n",
+			delay);
+		sleep(delay);
+	}
+
+	md_run(argc, argv);
+
+	if (root_dev_name) {
+		root_dev = name_to_dev_t(root_dev_name);
+	} else if (get_arg(argc, argv, "nfsroot=") ||
+		   get_arg(argc, argv, "nfsaddrs=")) {
+		root_dev = Root_NFS;
+	} else {
+		long rootdev;
+		getintfile("/proc/sys/kernel/real-root-dev", &rootdev);
+		root_dev = (dev_t) rootdev;
+	}
+
+	DEBUG(("kinit: root_dev = %s\n", bdevname(root_dev)));
+
+	if (initrd_load(argc, argv, root_dev)) {
+		DEBUG(("initrd loaded\n"));
+		return 0;
+	}
+
+	if (load_ramdisk && atoi(load_ramdisk)) {
+		if (ramdisk_load(argc, argv, root_dev))
+			root_dev = Root_RAM0;
+	}
+
+	return mount_root(argc, argv, root_dev, root_dev_name);
+}
diff --git a/usr/kinit/do_mounts.h b/usr/kinit/do_mounts.h
new file mode 100644
index 0000000..2024e86
--- /dev/null
+++ b/usr/kinit/do_mounts.h
@@ -0,0 +1,48 @@
+/*
+ * do_mounts.h
+ */
+
+#ifndef DO_MOUNTS_H
+#define DO_MOUNTS_H
+
+#include <sys/types.h>
+#include <sys/sysmacros.h>
+#include <sys/stat.h>
+
+#define	Root_RAM0	__makedev(1,0)
+
+/* These device numbers are only used internally */
+#define Root_NFS	__makedev(0,255)
+#define Root_MTD	__makedev(0,254)
+
+int create_dev(const char *name, dev_t dev);
+
+dev_t name_to_dev_t(const char *name);
+
+const char *mount_block(const char *source, const char *target,
+			const char *type, unsigned long flags,
+			const void *data);
+
+int mount_root(int argc, char *argv[], dev_t root_dev,
+	       const char *root_dev_name);
+
+int mount_mtd_root(int argc, char *argv[], const char *root_dev_name,
+		   const char *type, unsigned long flags);
+
+int do_mounts(int argc, char *argv[]);
+
+int initrd_load(int argc, char *argv[], dev_t root_dev);
+
+static inline dev_t bstat(const char *name)
+{
+	struct stat st;
+
+	if (stat(name, &st) || !S_ISBLK(st.st_mode))
+		return 0;
+	return st.st_rdev;
+}
+
+int load_ramdisk_compressed(const char *devpath, FILE * wfd,
+			    off_t ramdisk_start);
+
+#endif				/* DO_MOUNTS_H */
diff --git a/usr/kinit/do_mounts_md.c b/usr/kinit/do_mounts_md.c
new file mode 100644
index 0000000..696ffbd
--- /dev/null
+++ b/usr/kinit/do_mounts_md.c
@@ -0,0 +1,396 @@
+/*
+ * Handle autoconfiguration of md devices.  This is ugly, partially since
+ * it still relies on a sizable kernel component.
+ *
+ * This file is derived from the Linux kernel.
+ */
+
+#include <ctype.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <sys/mount.h>
+#include <sys/stat.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <alloca.h>
+#include <inttypes.h>
+#include <sys/sysmacros.h>
+#include <sys/md.h>
+#include <linux/major.h>
+
+#include "do_mounts.h"
+
+#define  LEVEL_NONE              (-1000000)
+
+/*
+ * When md (and any require personalities) are compiled into the kernel
+ * (not a module), arrays can be assembles are boot time using with AUTODETECT
+ * where specially marked partitions are registered with md_autodetect_dev(),
+ * and with MD_BOOT where devices to be collected are given on the boot line
+ * with md=.....
+ * The code for that is here.
+ */
+
+static int raid_noautodetect, raid_autopart;
+
+static struct {
+	int minor;
+	int partitioned;
+	int level;
+	int chunk;
+	char *device_names;
+} md_setup_args[MAX_MD_DEVS];
+
+static int md_setup_ents;
+
+/**
+ *	get_option - Parse integer from an option string
+ *	@str: option string
+ *	@pint: (output) integer value parsed from @str
+ *
+ *	Read an int from an option string; if available accept a subsequent
+ *	comma as well.
+ *
+ *	Return values:
+ *	0 : no int in string
+ *	1 : int found, no subsequent comma
+ *	2 : int found including a subsequent comma
+ */
+
+static int get_option(char **str, int *pint)
+{
+	char *cur = *str;
+
+	if (!cur || !(*cur))
+		return 0;
+	*pint = strtol(cur, str, 0);
+	if (cur == *str)
+		return 0;
+	if (**str == ',') {
+		(*str)++;
+		return 2;
+	}
+
+	return 1;
+}
+
+/*
+ * Find the partitioned md device major number... of course this *HAD*
+ * to be done dynamically instead of using a registered number.
+ * Sigh.  Double sigh.
+ */
+static int mdp_major(void)
+{
+	static int found = 0;
+	FILE *f;
+	char line[512], *p;
+	int is_blk, major_no;
+
+	if (found)
+		return found;
+
+	f = fopen("/proc/devices", "r");
+	is_blk = 0;
+	while (fgets(line, sizeof line, f)) {
+		if (!strcmp(line, "Block devices:\n"))
+			is_blk = 1;
+		if (is_blk) {
+			major_no = strtol(line, &p, 10);
+			while (*p && isspace(*p))
+				p++;
+
+			if (major_no == 0)	/* Not a number */
+				is_blk = 0;
+			else if (major_no > 0 && !strcmp(p, "mdp")) {
+				found = major_no;
+				break;
+			}
+		}
+	}
+	fclose(f);
+
+	if (!found) {
+		fprintf(stderr,
+			"Error: mdp devices detected but no mdp device found!\n");
+		exit(1);
+	}
+
+	return found;
+}
+
+/*
+ * Parse the command-line parameters given our kernel, but do not
+ * actually try to invoke the MD device now; that is handled by
+ * md_setup_drive after the low-level disk drivers have initialised.
+ *
+ * 27/11/1999: Fixed to work correctly with the 2.3 kernel (which
+ *             assigns the task of parsing integer arguments to the
+ *             invoked program now).  Added ability to initialise all
+ *             the MD devices (by specifying multiple "md=" lines)
+ *             instead of just one.  -- KTK
+ * 18May2000: Added support for persistent-superblock arrays:
+ *             md=n,0,factor,fault,device-list   uses RAID0 for device n
+ *             md=n,-1,factor,fault,device-list  uses LINEAR for device n
+ *             md=n,device-list      reads a RAID superblock from the devices
+ *             elements in device-list are read by name_to_kdev_t so can be
+ *             a hex number or something like /dev/hda1 /dev/sdb
+ * 2001-06-03: Dave Cinege <dcinege@psychosis.com>
+ *		Shifted name_to_kdev_t() and related operations to md_set_drive()
+ *		for later execution. Rewrote section to make devfs compatible.
+ */
+static int md_setup(char *str)
+{
+	int minor, level, factor, fault, partitioned = 0;
+	char *pername = "";
+	char *str1;
+	int ent;
+
+	if (*str == 'd') {
+		partitioned = 1;
+		str++;
+	}
+	if (get_option(&str, &minor) != 2) {	/* MD Number */
+		fprintf(stderr, "md: Too few arguments supplied to md=.\n");
+		return 0;
+	}
+	str1 = str;
+	if (minor >= MAX_MD_DEVS) {
+		fprintf(stderr, "md: md=%d, Minor device number too high.\n",
+			minor);
+		return 0;
+	}
+	for (ent = 0; ent < md_setup_ents; ent++)
+		if (md_setup_args[ent].minor == minor &&
+		    md_setup_args[ent].partitioned == partitioned) {
+			fprintf(stderr,
+				"md: md=%s%d, Specified more than once. "
+				"Replacing previous definition.\n",
+				partitioned ? "d" : "", minor);
+			break;
+		}
+	if (ent >= MAX_MD_DEVS) {
+		fprintf(stderr, "md: md=%s%d - too many md initialisations\n",
+			partitioned ? "d" : "", minor);
+		return 0;
+	}
+	if (ent >= md_setup_ents)
+		md_setup_ents++;
+	switch (get_option(&str, &level)) {	/* RAID level */
+	case 2:		/* could be 0 or -1.. */
+		if (level == 0 || level == LEVEL_LINEAR) {
+			if (get_option(&str, &factor) != 2 ||	/* Chunk Size */
+			    get_option(&str, &fault) != 2) {
+				fprintf(stderr,
+					"md: Too few arguments supplied to md=.\n");
+				return 0;
+			}
+			md_setup_args[ent].level = level;
+			md_setup_args[ent].chunk = 1 << (factor + 12);
+			if (level == LEVEL_LINEAR)
+				pername = "linear";
+			else
+				pername = "raid0";
+			break;
+		}
+		/* FALL THROUGH */
+	case 1:		/* the first device is numeric */
+		str = str1;
+		/* FALL THROUGH */
+	case 0:
+		md_setup_args[ent].level = LEVEL_NONE;
+		pername = "super-block";
+	}
+
+	fprintf(stderr, "md: Will configure md%s%d (%s) from %s, below.\n",
+		partitioned?"_d":"", minor, pername, str);
+	md_setup_args[ent].device_names = str;
+	md_setup_args[ent].partitioned = partitioned;
+	md_setup_args[ent].minor = minor;
+
+	return 1;
+}
+
+#define MdpMinorShift 6
+
+static void md_setup_drive(void)
+{
+	int dev_minor, i, ent, partitioned;
+	dev_t dev;
+	dev_t devices[MD_SB_DISKS + 1];
+
+	for (ent = 0; ent < md_setup_ents; ent++) {
+		int fd;
+		int err = 0;
+		char *devname;
+		mdu_disk_info_t dinfo;
+		char name[16];
+
+		dev_minor = md_setup_args[ent].minor;
+		partitioned = md_setup_args[ent].partitioned;
+		devname = md_setup_args[ent].device_names;
+
+		snprintf(name, sizeof name,
+			 "/dev/md%s%d", partitioned ? "_d" : "", dev_minor);
+
+		if (partitioned)
+			dev = makedev(mdp_major(), dev_minor << MdpMinorShift);
+		else
+			dev = makedev(MD_MAJOR, dev_minor);
+		create_dev(name, dev);
+		for (i = 0; i < MD_SB_DISKS && devname != 0; i++) {
+			char *p;
+
+			p = strchr(devname, ',');
+			if (p)
+				*p++ = 0;
+
+			dev = name_to_dev_t(devname);
+			if (!dev) {
+				fprintf(stderr, "md: Unknown device name: %s\n",
+					devname);
+				break;
+			}
+
+			devices[i] = dev;
+
+			devname = p;
+		}
+		devices[i] = 0;
+
+		if (!i)
+			continue;
+
+		fprintf(stderr, "md: Loading md%s%d: %s\n",
+			partitioned ? "_d" : "", dev_minor,
+			md_setup_args[ent].device_names);
+
+		fd = open(name, 0, 0);
+		if (fd < 0) {
+			fprintf(stderr, "md: open failed - cannot start "
+				"array %s\n", name);
+			continue;
+		}
+		if (ioctl(fd, SET_ARRAY_INFO, 0) == -EBUSY) {
+			fprintf(stderr,
+				"md: Ignoring md=%d, already autodetected. (Use raid=noautodetect)\n",
+				dev_minor);
+			close(fd);
+			continue;
+		}
+
+		if (md_setup_args[ent].level != LEVEL_NONE) {
+			/* non-persistent */
+			mdu_array_info_t ainfo;
+			ainfo.level = md_setup_args[ent].level;
+			ainfo.size = 0;
+			ainfo.nr_disks = 0;
+			ainfo.raid_disks = 0;
+			while (devices[ainfo.raid_disks])
+				ainfo.raid_disks++;
+			ainfo.md_minor = dev_minor;
+			ainfo.not_persistent = 1;
+
+			ainfo.state = (1 << MD_SB_CLEAN);
+			ainfo.layout = 0;
+			ainfo.chunk_size = md_setup_args[ent].chunk;
+			err = ioctl(fd, SET_ARRAY_INFO, &ainfo);
+			for (i = 0; !err && i <= MD_SB_DISKS; i++) {
+				dev = devices[i];
+				if (!dev)
+					break;
+				dinfo.number = i;
+				dinfo.raid_disk = i;
+				dinfo.state =
+				    (1 << MD_DISK_ACTIVE) | (1 << MD_DISK_SYNC);
+				dinfo.major = major(dev);
+				dinfo.minor = minor(dev);
+				err = ioctl(fd, ADD_NEW_DISK, &dinfo);
+			}
+		} else {
+			/* persistent */
+			for (i = 0; i <= MD_SB_DISKS; i++) {
+				dev = devices[i];
+				if (!dev)
+					break;
+				dinfo.major = major(dev);
+				dinfo.minor = minor(dev);
+				ioctl(fd, ADD_NEW_DISK, &dinfo);
+			}
+		}
+		if (!err)
+			err = ioctl(fd, RUN_ARRAY, 0);
+		if (err)
+			fprintf(stderr, "md: starting md%d failed\n",
+				dev_minor);
+		else {
+			/* reread the partition table.
+			 * I (neilb) and not sure why this is needed, but I cannot
+			 * boot a kernel with devfs compiled in from partitioned md
+			 * array without it
+			 */
+			close(fd);
+			fd = open(name, 0, 0);
+			ioctl(fd, BLKRRPART, 0);
+		}
+		close(fd);
+	}
+}
+
+static int raid_setup(char *str)
+{
+	int len, pos;
+
+	len = strlen(str) + 1;
+	pos = 0;
+
+	while (pos < len) {
+		char *comma = strchr(str + pos, ',');
+		int wlen;
+		if (comma)
+			wlen = (comma - str) - pos;
+		else
+			wlen = (len - 1) - pos;
+
+		if (!strncmp(str, "noautodetect", wlen))
+			raid_noautodetect = 1;
+		if (strncmp(str, "partitionable", wlen) == 0)
+			raid_autopart = 1;
+		if (strncmp(str, "part", wlen) == 0)
+			raid_autopart = 1;
+		pos += wlen + 1;
+	}
+	return 1;
+}
+
+static void md_run_setup(void)
+{
+	create_dev("/dev/md0", makedev(MD_MAJOR, 0));
+	if (raid_noautodetect)
+		fprintf(stderr,
+			"md: Skipping autodetection of RAID arrays. (raid=noautodetect)\n");
+	else {
+		int fd = open("/dev/md0", 0, 0);
+		if (fd >= 0) {
+			ioctl(fd, RAID_AUTORUN,
+			      (void *)(intptr_t) raid_autopart);
+			close(fd);
+		}
+	}
+	md_setup_drive();
+}
+
+void md_run(int argc, char *argv[])
+{
+	char **pp, *p;
+
+	for (pp = argv; (p = *pp); pp++) {
+		if (!strncmp(p, "raid=", 5))
+			raid_setup(p + 5);
+		else if (!strncmp(p, "md=", 3))
+			md_setup(p + 3);
+	}
+
+	md_run_setup();
+}
diff --git a/usr/kinit/do_mounts_mtd.c b/usr/kinit/do_mounts_mtd.c
new file mode 100644
index 0000000..7630920
--- /dev/null
+++ b/usr/kinit/do_mounts_mtd.c
@@ -0,0 +1,42 @@
+/*
+ * Mount an MTD device as a character device.
+ */
+
+#include <errno.h>
+#include <fcntl.h>
+#include <sys/mount.h>
+#include <sys/stat.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <inttypes.h>
+
+#include "kinit.h"
+#include "do_mounts.h"
+
+int mount_mtd_root(int argc, char *argv[], const char *root_dev_name,
+		   const char *type, unsigned long flags)
+{
+	const char *data = get_arg(argc, argv, "rootflags=");
+
+	if (!type)
+		type = "jffs2";
+
+	DEBUG(("Trying to mount MTD %s as root (%s filesystem)\n",
+	       root_dev_name, type));
+
+	if (mount(root_dev_name, "/root", type, flags, data)) {
+		int err = errno;
+		fprintf(stderr,
+			"%s: Unable to mount MTD %s (%s filesystem) "
+			"as root: %s\n",
+			progname, root_dev_name, type, strerror(err));
+		return -err;
+	} else {
+		fprintf(stderr, "%s: Mounted root (%s filesystem)%s.\n",
+			progname, type, (flags & MS_RDONLY) ? " readonly" : "");
+		return 0;
+	}
+
+}
diff --git a/usr/kinit/fstype/Kbuild b/usr/kinit/fstype/Kbuild
new file mode 100644
index 0000000..9b20db1
--- /dev/null
+++ b/usr/kinit/fstype/Kbuild
@@ -0,0 +1,25 @@
+#
+# Kbuild file for fstype
+#
+
+static-y := static/fstype
+shared-y := shared/fstype
+
+# common .o files
+objs := main.o fstype.o
+
+# TODO - do we want a stripped version
+# TODO - do we want the static.g + shared.g directories?
+
+# Create built-in.o with all object files (used by kinit)
+lib-y := $(objs)
+
+# .o files used to built executables
+static/fstype-y := $(objs)
+shared/fstype-y := $(objs)
+
+# Cleaning
+clean-dirs := static shared
+
+# install binary
+install-y := $(shared-y)
diff --git a/usr/kinit/fstype/cramfs_fs.h b/usr/kinit/fstype/cramfs_fs.h
new file mode 100644
index 0000000..6f5ad4f
--- /dev/null
+++ b/usr/kinit/fstype/cramfs_fs.h
@@ -0,0 +1,85 @@
+#ifndef __CRAMFS_H
+#define __CRAMFS_H
+
+#define CRAMFS_MAGIC		0x28cd3d45	/* some random number */
+#define CRAMFS_SIGNATURE	"Compressed ROMFS"
+
+/*
+ * Width of various bitfields in struct cramfs_inode.
+ * Primarily used to generate warnings in mkcramfs.
+ */
+#define CRAMFS_MODE_WIDTH 16
+#define CRAMFS_UID_WIDTH 16
+#define CRAMFS_SIZE_WIDTH 24
+#define CRAMFS_GID_WIDTH 8
+#define CRAMFS_NAMELEN_WIDTH 6
+#define CRAMFS_OFFSET_WIDTH 26
+
+/*
+ * Since inode.namelen is a unsigned 6-bit number, the maximum cramfs
+ * path length is 63 << 2 = 252.
+ */
+#define CRAMFS_MAXPATHLEN (((1 << CRAMFS_NAMELEN_WIDTH) - 1) << 2)
+
+/*
+ * Reasonably terse representation of the inode data.
+ */
+struct cramfs_inode {
+	__u32 mode:CRAMFS_MODE_WIDTH, uid:CRAMFS_UID_WIDTH;
+	/* SIZE for device files is i_rdev */
+	__u32 size:CRAMFS_SIZE_WIDTH, gid:CRAMFS_GID_WIDTH;
+	/* NAMELEN is the length of the file name, divided by 4 and
+	   rounded up.  (cramfs doesn't support hard links.) */
+	/* OFFSET: For symlinks and non-empty regular files, this
+	   contains the offset (divided by 4) of the file data in
+	   compressed form (starting with an array of block pointers;
+	   see README).  For non-empty directories it is the offset
+	   (divided by 4) of the inode of the first file in that
+	   directory.  For anything else, offset is zero. */
+	__u32 namelen:CRAMFS_NAMELEN_WIDTH, offset:CRAMFS_OFFSET_WIDTH;
+};
+
+struct cramfs_info {
+	__u32 crc;
+	__u32 edition;
+	__u32 blocks;
+	__u32 files;
+};
+
+/*
+ * Superblock information at the beginning of the FS.
+ */
+struct cramfs_super {
+	__u32 magic;		/* 0x28cd3d45 - random number */
+	__u32 size;		/* length in bytes */
+	__u32 flags;		/* feature flags */
+	__u32 future;		/* reserved for future use */
+	__u8 signature[16];	/* "Compressed ROMFS" */
+	struct cramfs_info fsid;	/* unique filesystem info */
+	__u8 name[16];		/* user-defined name */
+	struct cramfs_inode root;	/* root inode data */
+};
+
+/*
+ * Feature flags
+ *
+ * 0x00000000 - 0x000000ff: features that work for all past kernels
+ * 0x00000100 - 0xffffffff: features that don't work for past kernels
+ */
+#define CRAMFS_FLAG_FSID_VERSION_2	0x00000001	/* fsid version #2 */
+#define CRAMFS_FLAG_SORTED_DIRS		0x00000002	/* sorted dirs */
+#define CRAMFS_FLAG_HOLES		0x00000100	/* support for holes */
+#define CRAMFS_FLAG_WRONG_SIGNATURE	0x00000200	/* reserved */
+#define CRAMFS_FLAG_SHIFTED_ROOT_OFFSET	0x00000400	/* shifted root fs */
+
+/*
+ * Valid values in super.flags.  Currently we refuse to mount
+ * if (flags & ~CRAMFS_SUPPORTED_FLAGS).  Maybe that should be
+ * changed to test super.future instead.
+ */
+#define CRAMFS_SUPPORTED_FLAGS	( 0x000000ff \
+				| CRAMFS_FLAG_HOLES \
+				| CRAMFS_FLAG_WRONG_SIGNATURE \
+				| CRAMFS_FLAG_SHIFTED_ROOT_OFFSET )
+
+#endif
diff --git a/usr/kinit/fstype/ext2_fs.h b/usr/kinit/fstype/ext2_fs.h
new file mode 100644
index 0000000..293c5d6
--- /dev/null
+++ b/usr/kinit/fstype/ext2_fs.h
@@ -0,0 +1,79 @@
+/*
+ * The second extended file system magic number
+ */
+#define EXT2_SUPER_MAGIC	0xEF53
+
+/*
+ * Structure of the super block
+ */
+struct ext2_super_block {
+	__le32 s_inodes_count;	/* Inodes count */
+	__le32 s_blocks_count;	/* Blocks count */
+	__le32 s_r_blocks_count;	/* Reserved blocks count */
+	__le32 s_free_blocks_count;	/* Free blocks count */
+	__le32 s_free_inodes_count;	/* Free inodes count */
+	__le32 s_first_data_block;	/* First Data Block */
+	__le32 s_log_block_size;	/* Block size */
+	__le32 s_log_frag_size;	/* Fragment size */
+	__le32 s_blocks_per_group;	/* # Blocks per group */
+	__le32 s_frags_per_group;	/* # Fragments per group */
+	__le32 s_inodes_per_group;	/* # Inodes per group */
+	__le32 s_mtime;		/* Mount time */
+	__le32 s_wtime;		/* Write time */
+	__le16 s_mnt_count;	/* Mount count */
+	__le16 s_max_mnt_count;	/* Maximal mount count */
+	__le16 s_magic;		/* Magic signature */
+	__le16 s_state;		/* File system state */
+	__le16 s_errors;	/* Behaviour when detecting errors */
+	__le16 s_minor_rev_level;	/* minor revision level */
+	__le32 s_lastcheck;	/* time of last check */
+	__le32 s_checkinterval;	/* max. time between checks */
+	__le32 s_creator_os;	/* OS */
+	__le32 s_rev_level;	/* Revision level */
+	__le16 s_def_resuid;	/* Default uid for reserved blocks */
+	__le16 s_def_resgid;	/* Default gid for reserved blocks */
+	/*
+	 * These fields are for EXT2_DYNAMIC_REV superblocks only.
+	 *
+	 * Note: the difference between the compatible feature set and
+	 * the incompatible feature set is that if there is a bit set
+	 * in the incompatible feature set that the kernel doesn't
+	 * know about, it should refuse to mount the filesystem.
+	 *
+	 * e2fsck's requirements are more strict; if it doesn't know
+	 * about a feature in either the compatible or incompatible
+	 * feature set, it must abort and not try to meddle with
+	 * things it doesn't understand...
+	 */
+	__le32 s_first_ino;	/* First non-reserved inode */
+	__le16 s_inode_size;	/* size of inode structure */
+	__le16 s_block_group_nr;	/* block group # of this superblock */
+	__le32 s_feature_compat;	/* compatible feature set */
+	__le32 s_feature_incompat;	/* incompatible feature set */
+	__le32 s_feature_ro_compat;	/* readonly-compatible feature set */
+	__u8 s_uuid[16];	/* 128-bit uuid for volume */
+	char s_volume_name[16];	/* volume name */
+	char s_last_mounted[64];	/* directory where last mounted */
+	__le32 s_algorithm_usage_bitmap;	/* For compression */
+	/*
+	 * Performance hints.  Directory preallocation should only
+	 * happen if the EXT2_COMPAT_PREALLOC flag is on.
+	 */
+	__u8 s_prealloc_blocks;	/* Nr of blocks to try to preallocate */
+	__u8 s_prealloc_dir_blocks;	/* Nr to preallocate for dirs */
+	__u16 s_padding1;
+	/*
+	 * Journaling support valid if EXT3_FEATURE_COMPAT_HAS_JOURNAL set.
+	 */
+	__u8 s_journal_uuid[16];	/* uuid of journal superblock */
+	__u32 s_journal_inum;	/* inode number of journal file */
+	__u32 s_journal_dev;	/* device number of journal file */
+	__u32 s_last_orphan;	/* start of list of inodes to delete */
+	__u32 s_hash_seed[4];	/* HTREE hash seed */
+	__u8 s_def_hash_version;	/* Default hash version to use */
+	__u8 s_reserved_char_pad;
+	__u16 s_reserved_word_pad;
+	__le32 s_default_mount_opts;
+	__le32 s_first_meta_bg;	/* First metablock block group */
+	__u32 s_reserved[190];	/* Padding to the end of the block */
+};
diff --git a/usr/kinit/fstype/ext3_fs.h b/usr/kinit/fstype/ext3_fs.h
new file mode 100644
index 0000000..cec1bdd
--- /dev/null
+++ b/usr/kinit/fstype/ext3_fs.h
@@ -0,0 +1,92 @@
+/*
+ * The second extended file system magic number
+ */
+#define EXT3_SUPER_MAGIC        0xEF53
+
+#define EXT3_FEATURE_COMPAT_HAS_JOURNAL         0x0004
+
+/*
+ * Structure of the super block
+ */
+struct ext3_super_block {
+					/*00*/ __u32 s_inodes_count;
+					/* Inodes count */
+	__u32 s_blocks_count;	/* Blocks count */
+	__u32 s_r_blocks_count;	/* Reserved blocks count */
+	__u32 s_free_blocks_count;	/* Free blocks count */
+						/*10*/ __u32 s_free_inodes_count;
+						/* Free inodes count */
+	__u32 s_first_data_block;	/* First Data Block */
+	__u32 s_log_block_size;	/* Block size */
+	__s32 s_log_frag_size;	/* Fragment size */
+						/*20*/ __u32 s_blocks_per_group;
+						/* # Blocks per group */
+	__u32 s_frags_per_group;	/* # Fragments per group */
+	__u32 s_inodes_per_group;	/* # Inodes per group */
+	__u32 s_mtime;		/* Mount time */
+				/*30*/ __u32 s_wtime;
+				/* Write time */
+	__u16 s_mnt_count;	/* Mount count */
+	__s16 s_max_mnt_count;	/* Maximal mount count */
+	__u16 s_magic;		/* Magic signature */
+	__u16 s_state;		/* File system state */
+	__u16 s_errors;		/* Behaviour when detecting errors */
+	__u16 s_minor_rev_level;	/* minor revision level */
+					/*40*/ __u32 s_lastcheck;
+					/* time of last check */
+	__u32 s_checkinterval;	/* max. time between checks */
+	__u32 s_creator_os;	/* OS */
+	__u32 s_rev_level;	/* Revision level */
+					/*50*/ __u16 s_def_resuid;
+					/* Default uid for reserved blocks */
+	__u16 s_def_resgid;	/* Default gid for reserved blocks */
+	/*
+	 * These fields are for EXT3_DYNAMIC_REV superblocks only.
+	 *
+	 * Note: the difference between the compatible feature set and
+	 * the incompatible feature set is that if there is a bit set
+	 * in the incompatible feature set that the kernel doesn't
+	 * know about, it should refuse to mount the filesystem.
+	 *
+	 * e2fsck's requirements are more strict; if it doesn't know
+	 * about a feature in either the compatible or incompatible
+	 * feature set, it must abort and not try to meddle with
+	 * things it doesn't understand...
+	 */
+	__u32 s_first_ino;	/* First non-reserved inode */
+	__u16 s_inode_size;	/* size of inode structure */
+	__u16 s_block_group_nr;	/* block group # of this superblock */
+	__u32 s_feature_compat;	/* compatible feature set */
+						/*60*/ __u32 s_feature_incompat;
+						/* incompatible feature set */
+	__u32 s_feature_ro_compat;	/* readonly-compatible feature set */
+				/*68*/ __u8 s_uuid[16];
+				/* 128-bit uuid for volume */
+					/*78*/ char s_volume_name[16];
+					/* volume name */
+					/*88*/ char s_last_mounted[64];
+					/* directory where last mounted */
+						/*C8*/ __u32 s_algorithm_usage_bitmap;
+						/* For compression */
+	/*
+	 * Performance hints.  Directory preallocation should only
+	 * happen if the EXT3_FEATURE_COMPAT_DIR_PREALLOC flag is on.
+	 */
+	__u8 s_prealloc_blocks;	/* Nr of blocks to try to preallocate */
+	__u8 s_prealloc_dir_blocks;	/* Nr to preallocate for dirs */
+	__u16 s_padding1;
+	/*
+	 * Journaling support valid if EXT3_FEATURE_COMPAT_HAS_JOURNAL set.
+	 */
+					/*D0*/ __u8 s_journal_uuid[16];
+					/* uuid of journal superblock */
+					/*E0*/ __u32 s_journal_inum;
+					/* inode number of journal file */
+	__u32 s_journal_dev;	/* device number of journal file */
+	__u32 s_last_orphan;	/* start of list of inodes to delete */
+	__u32 s_hash_seed[4];	/* HTREE hash seed */
+	__u8 s_def_hash_version;	/* Default hash version to use */
+	__u8 s_reserved_char_pad;
+	__u16 s_reserved_word_pad;
+	__u32 s_reserved[192];	/* Padding to the end of the block */
+};
diff --git a/usr/kinit/fstype/fstype.c b/usr/kinit/fstype/fstype.c
new file mode 100644
index 0000000..4bbe7d6
--- /dev/null
+++ b/usr/kinit/fstype/fstype.c
@@ -0,0 +1,330 @@
+/*
+ * by rmk
+ *
+ * Detect filesystem type (on stdin) and output strings for two
+ * environment variables:
+ *  FSTYPE - filesystem type
+ *  FSSIZE - filesystem size (if known)
+ *
+ * We currently detect the filesystems listed below in the struct
+ * "imagetype images" (in the order they are listed).
+ *
+ * MINIX, ext3 and Reiserfs bits are currently untested.
+ */
+
+#include <sys/types.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <endian.h>
+#include <netinet/in.h>
+#include <sys/vfs.h>
+
+#define cpu_to_be32(x) __cpu_to_be32(x)	/* Needed by romfs_fs.h */
+
+#include "romfs_fs.h"
+#include "cramfs_fs.h"
+#include "minix_fs.h"
+#include "ext2_fs.h"
+#include "ext3_fs.h"
+#include "xfs_sb.h"
+#include "luks_fs.h"
+#include "lvm2_sb.h"
+#include "iso9660_sb.h"
+
+/*
+ * Slightly cleaned up version of jfs_superblock to
+ * avoid pulling in other kernel header files.
+ */
+#include "jfs_superblock.h"
+
+/*
+ * reiserfs_fs.h is too sick to include directly.
+ * Use a cleaned up version.
+ */
+#include "reiserfs_fs.h"
+
+#include "fstype.h"
+
+#define ARRAY_SIZE(x)	(sizeof(x) / sizeof(x[0]))
+
+#define BLOCK_SIZE 1024
+
+/* Swap needs the definition of block size */
+#include "swap_fs.h"
+
+static int gzip_image(const void *buf, unsigned long long *bytes)
+{
+	const unsigned char *p = buf;
+
+	if (p[0] == 037 && (p[1] == 0213 || p[1] == 0236)) {
+		/* The length of a gzip stream can only be determined
+		   by processing the whole stream */
+		*bytes = 0ULL;
+		return 1;
+	}
+	return 0;
+}
+
+static int cramfs_image(const void *buf, unsigned long long *bytes)
+{
+	const struct cramfs_super *sb = (const struct cramfs_super *)buf;
+
+	if (sb->magic == CRAMFS_MAGIC) {
+		if (sb->flags & CRAMFS_FLAG_FSID_VERSION_2)
+			*bytes = (unsigned long long)sb->fsid.blocks << 10;
+		else
+			*bytes = 0;
+		return 1;
+	}
+	return 0;
+}
+
+static int romfs_image(const void *buf, unsigned long long *bytes)
+{
+	const struct romfs_super_block *sb =
+	    (const struct romfs_super_block *)buf;
+
+	if (sb->word0 == ROMSB_WORD0 && sb->word1 == ROMSB_WORD1) {
+		*bytes = __be32_to_cpu(sb->size);
+		return 1;
+	}
+	return 0;
+}
+
+static int minix_image(const void *buf, unsigned long long *bytes)
+{
+	const struct minix_super_block *sb =
+	    (const struct minix_super_block *)buf;
+
+	if (sb->s_magic == MINIX_SUPER_MAGIC ||
+	    sb->s_magic == MINIX_SUPER_MAGIC2) {
+		*bytes = (unsigned long long)sb->s_nzones
+		    << (sb->s_log_zone_size + 10);
+		return 1;
+	}
+	return 0;
+}
+
+static int ext3_image(const void *buf, unsigned long long *bytes)
+{
+	const struct ext3_super_block *sb =
+	    (const struct ext3_super_block *)buf;
+
+	if (sb->s_magic == __cpu_to_le16(EXT2_SUPER_MAGIC) &&
+	    sb->
+	    s_feature_compat & __cpu_to_le32(EXT3_FEATURE_COMPAT_HAS_JOURNAL)) {
+		*bytes = (unsigned long long)__le32_to_cpu(sb->s_blocks_count)
+		    << (10 + __le32_to_cpu(sb->s_log_block_size));
+		return 1;
+	}
+	return 0;
+}
+
+static int ext2_image(const void *buf, unsigned long long *bytes)
+{
+	const struct ext2_super_block *sb =
+	    (const struct ext2_super_block *)buf;
+
+	if (sb->s_magic == __cpu_to_le16(EXT2_SUPER_MAGIC)) {
+		*bytes = (unsigned long long)__le32_to_cpu(sb->s_blocks_count)
+		    << (10 + __le32_to_cpu(sb->s_log_block_size));
+		return 1;
+	}
+	return 0;
+}
+
+static int reiserfs_image(const void *buf, unsigned long long *bytes)
+{
+	const struct reiserfs_super_block *sb =
+	    (const struct reiserfs_super_block *)buf;
+
+	if (memcmp(REISERFS_MAGIC(sb), REISERFS_SUPER_MAGIC_STRING,
+		   sizeof(REISERFS_SUPER_MAGIC_STRING) - 1) == 0 ||
+	    memcmp(REISERFS_MAGIC(sb), REISER2FS_SUPER_MAGIC_STRING,
+		   sizeof(REISER2FS_SUPER_MAGIC_STRING) - 1) == 0 ||
+	    memcmp(REISERFS_MAGIC(sb), REISER2FS_JR_SUPER_MAGIC_STRING,
+		   sizeof(REISER2FS_JR_SUPER_MAGIC_STRING) - 1) == 0) {
+		*bytes = (unsigned long long)REISERFS_BLOCK_COUNT(sb) *
+		    REISERFS_BLOCKSIZE(sb);
+		return 1;
+	}
+	return 0;
+}
+
+static int xfs_image(const void *buf, unsigned long long *bytes)
+{
+	const struct xfs_sb *sb = (const struct xfs_sb *)buf;
+
+	if (__be32_to_cpu(sb->sb_magicnum) == XFS_SB_MAGIC) {
+		*bytes = __be64_to_cpu(sb->sb_dblocks) *
+		    __be32_to_cpu(sb->sb_blocksize);
+		return 1;
+	}
+	return 0;
+}
+
+static int jfs_image(const void *buf, unsigned long long *bytes)
+{
+	const struct jfs_superblock *sb = (const struct jfs_superblock *)buf;
+
+	if (!memcmp(sb->s_magic, JFS_MAGIC, 4)) {
+		*bytes = __le32_to_cpu(sb->s_size);
+		return 1;
+	}
+	return 0;
+}
+
+static int luks_image(const void *buf, unsigned long long *blocks)
+{
+	const struct luks_partition_header *lph =
+	    (const struct luks_partition_header *)buf;
+
+	if (!memcmp(lph->magic, LUKS_MAGIC, LUKS_MAGIC_L)) {
+		/* FSSIZE is dictated by the underlying fs, not by LUKS */
+		*blocks = 0;
+		return 1;
+	}
+	return 0;
+}
+
+static int swap_image(const void *buf, unsigned long long *blocks)
+{
+	const struct swap_super_block *ssb =
+	    (const struct swap_super_block *)buf;
+
+	if (!memcmp(ssb->magic, SWAP_MAGIC_1, SWAP_MAGIC_L) ||
+	    !memcmp(ssb->magic, SWAP_MAGIC_2, SWAP_MAGIC_L)) {
+		*blocks = 0;
+		return 1;
+	}
+	return 0;
+}
+
+static int suspend_image(const void *buf, unsigned long long *blocks)
+{
+	const struct swap_super_block *ssb =
+	    (const struct swap_super_block *)buf;
+
+	if (!memcmp(ssb->magic, SUSP_MAGIC_1, SUSP_MAGIC_L) ||
+	    !memcmp(ssb->magic, SUSP_MAGIC_2, SUSP_MAGIC_L) ||
+	    !memcmp(ssb->magic, SUSP_MAGIC_U, SUSP_MAGIC_L)) {
+		*blocks = 0;
+		return 1;
+	}
+	return 0;
+}
+
+static int lvm2_image(const void *buf, unsigned long long *blocks)
+{
+	const struct lvm2_super_block *lsb;
+	int i;
+
+	/* We must check every 512 byte sector */
+	for (i = 0; i < BLOCK_SIZE; i += 0x200) {
+		lsb = (const struct lvm2_super_block *)(buf + i);
+
+		if (!memcmp(lsb->magic, LVM2_MAGIC, LVM2_MAGIC_L) &&
+		    !memcmp(lsb->type, LVM2_TYPE, LVM2_TYPE_L)) {
+			/* This is just one of possibly many PV's */
+			*blocks = 0;
+			return 1;
+		}
+	}
+
+	return 0;
+}
+
+static int iso_image(const void *buf, unsigned long long *blocks)
+{
+	const struct iso_volume_descriptor *isovd =
+	    (const struct iso_volume_descriptor *)buf;
+	const struct iso_hs_volume_descriptor *isohsvd =
+	    (const struct iso_hs_volume_descriptor *)buf;
+
+	if (!memcmp(isovd->id, ISO_MAGIC, ISO_MAGIC_L) ||
+	    !memcmp(isohsvd->id, ISO_HS_MAGIC, ISO_HS_MAGIC_L)) {
+		*blocks = 0;
+		return 1;
+	}
+	return 0;
+}
+
+struct imagetype {
+	off_t block;
+	const char name[12];
+	int (*identify) (const void *, unsigned long long *);
+};
+
+/*
+ * Note:
+ *
+ * Minix test needs to come after ext3/ext2, since it's possible for
+ * ext3/ext2 to look like minix by pure random chance.
+ *
+ * LVM comes after all other filesystems since it's possible
+ * that an old lvm signature is left on the disk if pvremove
+ * is not used before creating the new fs.
+ *
+ * The same goes for LUKS as for LVM.
+ */
+static struct imagetype images[] = {
+	{0, "gzip", gzip_image},
+	{0, "cramfs", cramfs_image},
+	{0, "romfs", romfs_image},
+	{0, "xfs", xfs_image},
+	{1, "ext3", ext3_image},
+	{1, "ext2", ext2_image},
+	{1, "minix", minix_image},
+	{8, "reiserfs", reiserfs_image},
+	{64, "reiserfs", reiserfs_image},
+	{32, "jfs", jfs_image},
+	{32, "iso9660", iso_image},
+	{0, "luks", luks_image},
+	{0, "lvm2", lvm2_image},
+	{1, "lvm2", lvm2_image},
+	{-1, "swap", swap_image},
+	{-1, "suspend", suspend_image},
+	{0, "", NULL}
+};
+
+int identify_fs(int fd, const char **fstype,
+		unsigned long long *bytes, off_t offset)
+{
+	uint64_t buf[BLOCK_SIZE >> 3];	/* 64-bit worst case alignment */
+	off_t cur_block = (off_t) - 1;
+	struct imagetype *ip;
+	int ret;
+	unsigned long long dummy;
+
+	if (!bytes)
+		bytes = &dummy;
+
+	*fstype = NULL;
+	*bytes = 0;
+
+	for (ip = images; ip->identify; ip++) {
+		/* Hack for swap, which apparently is dependent on page size */
+		if (ip->block == -1)
+			ip->block = SWAP_OFFSET();
+
+		if (cur_block != ip->block) {
+			/*
+			 * Read block.
+			 */
+			cur_block = ip->block;
+			ret = pread(fd, buf, BLOCK_SIZE,
+				    offset + cur_block * BLOCK_SIZE);
+			if (ret != BLOCK_SIZE)
+				return -1;	/* error */
+		}
+
+		if (ip->identify(buf, bytes)) {
+			*fstype = ip->name;
+			return 0;
+		}
+	}
+
+	return 1;		/* Unknown filesystem */
+}
diff --git a/usr/kinit/fstype/fstype.h b/usr/kinit/fstype/fstype.h
new file mode 100644
index 0000000..92b19df
--- /dev/null
+++ b/usr/kinit/fstype/fstype.h
@@ -0,0 +1,23 @@
+/*
+ * by rmk
+ *
+ * Detect filesystem type (on stdin) and output strings for two
+ * environment variables:
+ *  FSTYPE - filesystem type
+ *  FSSIZE - filesystem size (if known)
+ *
+ * We currently detect (in order):
+ *  gzip, cramfs, romfs, xfs, minix, ext3, ext2, reiserfs, jfs
+ *
+ * MINIX, ext3 and Reiserfs bits are currently untested.
+ */
+
+#ifndef FSTYPE_H
+#define FSTYPE_H
+
+#include <unistd.h>
+
+int identify_fs(int fd, const char **fstype,
+		unsigned long long *bytes, off_t offset);
+
+#endif
diff --git a/usr/kinit/fstype/iso9660_sb.h b/usr/kinit/fstype/iso9660_sb.h
new file mode 100644
index 0000000..efe0733
--- /dev/null
+++ b/usr/kinit/fstype/iso9660_sb.h
@@ -0,0 +1,24 @@
+#ifndef __ISO9660_SB_H
+#define __ISO9660_SB_H
+
+#define ISO_MAGIC_L	5
+#define ISO_MAGIC	"CD001"
+#define ISO_HS_MAGIC_L	5
+#define ISO_HS_MAGIC	"CDROM"
+
+/* ISO9660 Volume Descriptor */
+struct iso_volume_descriptor {
+	__u8 type;
+	char id[ISO_MAGIC_L];
+	__u8 version;
+};
+
+/* High Sierra Volume Descriptor */
+struct iso_hs_volume_descriptor {
+	char foo[8];
+	__u8 type;
+	char id[ISO_HS_MAGIC_L];
+	__u8 version;
+};
+
+#endif
diff --git a/usr/kinit/fstype/jfs_superblock.h b/usr/kinit/fstype/jfs_superblock.h
new file mode 100644
index 0000000..63132a0
--- /dev/null
+++ b/usr/kinit/fstype/jfs_superblock.h
@@ -0,0 +1,114 @@
+/*
+ *   Copyright (C) International Business Machines Corp., 2000-2003
+ *
+ *   This program is free software;  you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation; either version 2 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This program 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 General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program;  if not, write to the Free Software
+ *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+#ifndef	_H_JFS_SUPERBLOCK
+#define _H_JFS_SUPERBLOCK
+
+struct timestruc_t {
+	__le32 tv_sec;
+	__le32 tv_nsec;
+};
+
+/*
+ * make the magic number something a human could read
+ */
+#define JFS_MAGIC 	"JFS1"	/* Magic word */
+
+#define JFS_VERSION	2	/* Version number: Version 2 */
+
+#define LV_NAME_SIZE	11	/* MUST BE 11 for OS/2 boot sector */
+
+/*
+ *	aggregate superblock
+ *
+ * The name superblock is too close to super_block, so the name has been
+ * changed to jfs_superblock.  The utilities are still using the old name.
+ */
+struct jfs_superblock {
+	char s_magic[4];	/* 4: magic number */
+	__le32 s_version;	/* 4: version number */
+
+	__le64 s_size;		/* 8: aggregate size in hardware/LVM blocks;
+				 * VFS: number of blocks
+				 */
+	__le32 s_bsize;		/* 4: aggregate block size in bytes;
+				 * VFS: fragment size
+				 */
+	__le16 s_l2bsize;	/* 2: log2 of s_bsize */
+	__le16 s_l2bfactor;	/* 2: log2(s_bsize/hardware block size) */
+	__le32 s_pbsize;	/* 4: hardware/LVM block size in bytes */
+	__le16 s_l2pbsize;	/* 2: log2 of s_pbsize */
+	__le16 pad;		/* 2: padding necessary for alignment */
+
+	__le32 s_agsize;	/* 4: allocation group size in aggr. blocks */
+
+	__le32 s_flag;		/* 4: aggregate attributes:
+				 *    see jfs_filsys.h
+				 */
+	__le32 s_state;		/* 4: mount/unmount/recovery state:
+				 *    see jfs_filsys.h
+				 */
+	__le32 s_compress;	/* 4: > 0 if data compression */
+
+	__le64 s_ait2;		/* 8: first extent of secondary
+				 *    aggregate inode table
+				 */
+
+	__le64 s_aim2;		/* 8: first extent of secondary
+				 *    aggregate inode map
+				 */
+	__le32 s_logdev;	/* 4: device address of log */
+	__le32 s_logserial;	/* 4: log serial number at aggregate mount */
+	__le64 s_logpxd;	/* 8: inline log extent */
+
+	__le64 s_fsckpxd;	/* 8: inline fsck work space extent */
+
+	struct timestruc_t s_time;	/* 8: time last updated */
+
+	__le32 s_fsckloglen;	/* 4: Number of filesystem blocks reserved for
+				 *    the fsck service log.
+				 *    N.B. These blocks are divided among the
+				 *         versions kept.  This is not a per
+				 *         version size.
+				 *    N.B. These blocks are included in the
+				 *         length field of s_fsckpxd.
+				 */
+	char s_fscklog;		/* 1: which fsck service log is most recent
+				 *    0 => no service log data yet
+				 *    1 => the first one
+				 *    2 => the 2nd one
+				 */
+	char s_fpack[11];	/* 11: file system volume name
+				 *     N.B. This must be 11 bytes to
+				 *          conform with the OS/2 BootSector
+				 *          requirements
+				 *          Only used when s_version is 1
+				 */
+
+	/* extendfs() parameter under s_state & FM_EXTENDFS */
+	__le64 s_xsize;		/* 8: extendfs s_size */
+	__le64 s_xfsckpxd;	/* 8: extendfs fsckpxd */
+	__le64 s_xlogpxd;	/* 8: extendfs logpxd */
+	/* - 128 byte boundary - */
+
+	char s_uuid[16];	/* 16: 128-bit uuid for volume */
+	char s_label[16];	/* 16: volume label */
+	char s_loguuid[16];	/* 16: 128-bit uuid for log device */
+
+};
+
+#endif /*_H_JFS_SUPERBLOCK */
diff --git a/usr/kinit/fstype/luks_fs.h b/usr/kinit/fstype/luks_fs.h
new file mode 100644
index 0000000..fd8de315
--- /dev/null
+++ b/usr/kinit/fstype/luks_fs.h
@@ -0,0 +1,44 @@
+#ifndef __LINUX_LUKS_FS_H
+#define __LINUX_LUKS_FS_H
+
+/* The basic structures of the luks partition header */
+#define LUKS_MAGIC_L		6
+#define LUKS_CIPHERNAME_L	32
+#define LUKS_CIPHERMODE_L	32
+#define LUKS_HASHSPEC_L		32
+#define LUKS_UUID_STRING_L	40
+
+#define LUKS_MAGIC		"LUKS\xBA\xBE"
+#define LUKS_DIGESTSIZE		20
+#define LUKS_SALTSIZE		32
+#define LUKS_NUMKEYS		8
+#define LUKS_MKD_ITER		10
+#define LUKS_KEY_DISABLED	0x0000DEAD
+#define LUKS_KEY_ENABLED	0x00AC71F3
+#define LUKS_STRIPES		4000
+
+/* On-disk "super block" */
+struct luks_partition_header {
+	char	magic[LUKS_MAGIC_L];
+	__be16	version;
+	char	cipherName[LUKS_CIPHERNAME_L];
+	char	cipherMode[LUKS_CIPHERMODE_L];
+	char	hashSpec[LUKS_HASHSPEC_L];
+	__be32	payloadOffset;
+	__be32	keyBytes;
+	char	mkDigest[LUKS_DIGESTSIZE];
+	char	mkDigestSalt[LUKS_SALTSIZE];
+	__be32	mkDigestIterations;
+	char	uuid[LUKS_UUID_STRING_L];
+
+	struct {
+		__be32	active;
+		/* Parameters for PBKDF2 processing */
+		__be32	passwordIterations;
+		char	passwordSalt[LUKS_SALTSIZE];
+		__be32	keyMaterialOffset;
+		__be32	stripes;
+	} keyblock[LUKS_NUMKEYS];
+};
+
+#endif
diff --git a/usr/kinit/fstype/lvm2_sb.h b/usr/kinit/fstype/lvm2_sb.h
new file mode 100644
index 0000000..75dfc10
--- /dev/null
+++ b/usr/kinit/fstype/lvm2_sb.h
@@ -0,0 +1,18 @@
+#ifndef __LVM2_SB_H
+#define __LVM2_SB_H
+
+/* LVM2 super block definitions */
+#define LVM2_MAGIC_L		8
+#define LVM2_MAGIC		"LABELONE"
+#define LVM2_TYPE_L		8
+#define LVM2_TYPE		"LVM2 001"
+
+struct lvm2_super_block {
+	char magic[LVM2_MAGIC_L];
+	__be64 sector;
+	__be32 crc;
+	__be32 offset;
+	char type[LVM2_TYPE_L];
+};
+
+#endif
diff --git a/usr/kinit/fstype/main.c b/usr/kinit/fstype/main.c
new file mode 100644
index 0000000..0ceb593
--- /dev/null
+++ b/usr/kinit/fstype/main.c
@@ -0,0 +1,58 @@
+/*
+ * by rmk
+ *
+ * Detect filesystem type (on stdin) and output strings for two
+ * environment variables:
+ *  FSTYPE - filesystem type
+ *  FSSIZE - filesystem size (if known)
+ *
+ * We currently detect (in order):
+ *  gzip, cramfs, romfs, xfs, minix, ext3, ext2, reiserfs, jfs
+ *
+ * MINIX, ext3 and Reiserfs bits are currently untested.
+ */
+
+#include <stdio.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+#include <stdlib.h>
+#include "fstype.h"
+
+char *progname;
+
+int main(int argc, char *argv[])
+{
+	int fd = 0;
+	int rv;
+	const char *fstype;
+	const char *file = "stdin";
+	unsigned long long bytes;
+
+	progname = argv[0];
+
+	if (argc > 2) {
+		fprintf(stderr, "Usage: %s [file]\n", progname);
+		return 1;
+	}
+
+	if (argc > 1 && !(argv[1][0] == '-' && argv[1][1] == '\0')) {
+		fd = open(file = argv[1], O_RDONLY);
+		if (fd < 0) {
+			perror(argv[1]);
+			return 2;
+		}
+	}
+
+	rv = identify_fs(fd, &fstype, &bytes, 0);
+	if (rv == -1) {
+		perror(file);
+		return 2;
+	}
+
+	fstype = fstype ? fstype : "unknown";
+
+	fprintf(stdout, "FSTYPE=%s\nFSSIZE=%llu\n", fstype, bytes);
+	return rv;
+}
diff --git a/usr/kinit/fstype/minix_fs.h b/usr/kinit/fstype/minix_fs.h
new file mode 100644
index 0000000..e2899f0
--- /dev/null
+++ b/usr/kinit/fstype/minix_fs.h
@@ -0,0 +1,85 @@
+#ifndef _LINUX_MINIX_FS_H
+#define _LINUX_MINIX_FS_H
+
+/*
+ * The minix filesystem constants/structures
+ */
+
+/*
+ * Thanks to Kees J Bot for sending me the definitions of the new
+ * minix filesystem (aka V2) with bigger inodes and 32-bit block
+ * pointers.
+ */
+
+#define MINIX_ROOT_INO 1
+
+/* Not the same as the bogus LINK_MAX in <linux/limits.h>. Oh well. */
+#define MINIX_LINK_MAX	250
+#define MINIX2_LINK_MAX	65530
+
+#define MINIX_I_MAP_SLOTS	8
+#define MINIX_Z_MAP_SLOTS	64
+#define MINIX_SUPER_MAGIC	0x137F	/* original minix fs */
+#define MINIX_SUPER_MAGIC2	0x138F	/* minix fs, 30 char names */
+#define MINIX2_SUPER_MAGIC	0x2468	/* minix V2 fs */
+#define MINIX2_SUPER_MAGIC2	0x2478	/* minix V2 fs, 30 char names */
+#define MINIX_VALID_FS		0x0001	/* Clean fs. */
+#define MINIX_ERROR_FS		0x0002	/* fs has errors. */
+
+#define MINIX_INODES_PER_BLOCK ((BLOCK_SIZE)/(sizeof (struct minix_inode)))
+#define MINIX2_INODES_PER_BLOCK ((BLOCK_SIZE)/(sizeof (struct minix2_inode)))
+
+/*
+ * This is the original minix inode layout on disk.
+ * Note the 8-bit gid and atime and ctime.
+ */
+struct minix_inode {
+	__u16 i_mode;
+	__u16 i_uid;
+	__u32 i_size;
+	__u32 i_time;
+	__u8  i_gid;
+	__u8  i_nlinks;
+	__u16 i_zone[9];
+};
+
+/*
+ * The new minix inode has all the time entries, as well as
+ * long block numbers and a third indirect block (7+1+1+1
+ * instead of 7+1+1). Also, some previously 8-bit values are
+ * now 16-bit. The inode is now 64 bytes instead of 32.
+ */
+struct minix2_inode {
+	__u16 i_mode;
+	__u16 i_nlinks;
+	__u16 i_uid;
+	__u16 i_gid;
+	__u32 i_size;
+	__u32 i_atime;
+	__u32 i_mtime;
+	__u32 i_ctime;
+	__u32 i_zone[10];
+};
+
+/*
+ * minix super-block data on disk
+ */
+struct minix_super_block {
+	__u16 s_ninodes;
+	__u16 s_nzones;
+	__u16 s_imap_blocks;
+	__u16 s_zmap_blocks;
+	__u16 s_firstdatazone;
+	__u16 s_log_zone_size;
+	__u32 s_max_size;
+	__u16 s_magic;
+	__u16 s_state;
+	__u32 s_zones;
+};
+
+struct minix_dir_entry {
+	__u16 inode;
+	char  name[0];
+};
+
+#endif
diff --git a/usr/kinit/fstype/reiserfs_fs.h b/usr/kinit/fstype/reiserfs_fs.h
new file mode 100644
index 0000000..dd47995
--- /dev/null
+++ b/usr/kinit/fstype/reiserfs_fs.h
@@ -0,0 +1,69 @@
+struct journal_params {
+	__u32 jp_journal_1st_block;	/* where does journal start from on its
+					 * device */
+	__u32 jp_journal_dev;	/* journal device st_rdev */
+	__u32 jp_journal_size;	/* size of the journal */
+	__u32 jp_journal_trans_max;	/* max number of blocks in a transaction. */
+	__u32 jp_journal_magic;	/* random value made on fs creation (this
+				 * was sb_journal_block_count) */
+	__u32 jp_journal_max_batch;	/* max number of blocks to batch into a
+					 * trans */
+	__u32 jp_journal_max_commit_age;	/* in seconds, how old can an async
+						 * commit be */
+	__u32 jp_journal_max_trans_age;	/* in seconds, how old can a transaction
+					 * be */
+};
+
+/* this is the super from 3.5.X, where X >= 10 */
+struct reiserfs_super_block_v1 {
+	__u32 s_block_count;	/* blocks count         */
+	__u32 s_free_blocks;	/* free blocks count    */
+	__u32 s_root_block;	/* root block number    */
+	struct journal_params s_journal;
+	__u16 s_blocksize;	/* block size */
+	__u16 s_oid_maxsize;	/* max size of object id array, see
+				 * get_objectid() commentary  */
+	__u16 s_oid_cursize;	/* current size of object id array */
+	__u16 s_umount_state;	/* this is set to 1 when filesystem was
+				 * umounted, to 2 - when not */
+	char s_magic[10];	/* reiserfs magic string indicates that
+				 * file system is reiserfs:
+				 * "ReIsErFs" or "ReIsEr2Fs" or "ReIsEr3Fs" */
+	__u16 s_fs_state;	/* it is set to used by fsck to mark which
+				 * phase of rebuilding is done */
+	__u32 s_hash_function_code;	/* indicate, what hash function is being use
+					 * to sort names in a directory*/
+	__u16 s_tree_height;	/* height of disk tree */
+	__u16 s_bmap_nr;	/* amount of bitmap blocks needed to address
+				 * each block of file system */
+	__u16 s_version;	/* this field is only reliable on filesystem
+				 * with non-standard journal */
+	__u16 s_reserved_for_journal;	/* size in blocks of journal area on main
+					 * device, we need to keep after
+					 * making fs with non-standard journal */
+} __attribute__ ((__packed__));
+
+/* this is the on disk super block */
+struct reiserfs_super_block {
+	struct reiserfs_super_block_v1 s_v1;
+	__u32 s_inode_generation;
+	__u32 s_flags;		/* Right now used only by inode-attributes, if enabled */
+	unsigned char s_uuid[16];	/* filesystem unique identifier */
+	unsigned char s_label[16];	/* filesystem volume label */
+	char s_unused[88];	/* zero filled by mkreiserfs and
+				 * reiserfs_convert_objectid_map_v1()
+				 * so any additions must be updated
+				 * there as well. */
+} __attribute__ ((__packed__));
+
+#define REISERFS_SUPER_MAGIC_STRING "ReIsErFs"
+#define REISER2FS_SUPER_MAGIC_STRING "ReIsEr2Fs"
+#define REISER2FS_JR_SUPER_MAGIC_STRING "ReIsEr3Fs"
+
+#define SB_V1_DISK_SUPER_BLOCK(s) (&((s)->s_v1))
+#define REISERFS_BLOCKSIZE(s) \
+        __le32_to_cpu((SB_V1_DISK_SUPER_BLOCK(s)->s_blocksize))
+#define REISERFS_BLOCK_COUNT(s) \
+        __le32_to_cpu((SB_V1_DISK_SUPER_BLOCK(s)->s_block_count))
+#define REISERFS_MAGIC(s) \
+        (SB_V1_DISK_SUPER_BLOCK(s)->s_magic)
diff --git a/usr/kinit/fstype/romfs_fs.h b/usr/kinit/fstype/romfs_fs.h
new file mode 100644
index 0000000..c490fbc
--- /dev/null
+++ b/usr/kinit/fstype/romfs_fs.h
@@ -0,0 +1,56 @@
+#ifndef __LINUX_ROMFS_FS_H
+#define __LINUX_ROMFS_FS_H
+
+/* The basic structures of the romfs filesystem */
+
+#define ROMBSIZE BLOCK_SIZE
+#define ROMBSBITS BLOCK_SIZE_BITS
+#define ROMBMASK (ROMBSIZE-1)
+#define ROMFS_MAGIC 0x7275
+
+#define ROMFS_MAXFN 128
+
+#define __mkw(h,l) (((h)&0x00ff)<< 8|((l)&0x00ff))
+#define __mkl(h,l) (((h)&0xffff)<<16|((l)&0xffff))
+#define __mk4(a,b,c,d) cpu_to_be32(__mkl(__mkw(a,b),__mkw(c,d)))
+#define ROMSB_WORD0 __mk4('-','r','o','m')
+#define ROMSB_WORD1 __mk4('1','f','s','-')
+
+/* On-disk "super block" */
+
+struct romfs_super_block {
+	__be32 word0;
+	__be32 word1;
+	__be32 size;
+	__be32 checksum;
+	char name[0];		/* volume name */
+};
+
+/* On disk inode */
+
+struct romfs_inode {
+	__be32 next;		/* low 4 bits see ROMFH_ */
+	__be32 spec;
+	__be32 size;
+	__be32 checksum;
+	char name[0];
+};
+
+#define ROMFH_TYPE 7
+#define ROMFH_HRD 0
+#define ROMFH_DIR 1
+#define ROMFH_REG 2
+#define ROMFH_SYM 3
+#define ROMFH_BLK 4
+#define ROMFH_CHR 5
+#define ROMFH_SCK 6
+#define ROMFH_FIF 7
+#define ROMFH_EXEC 8
+
+/* Alignment */
+
+#define ROMFH_SIZE 16
+#define ROMFH_PAD (ROMFH_SIZE-1)
+#define ROMFH_MASK (~ROMFH_PAD)
+
+#endif
diff --git a/usr/kinit/fstype/swap_fs.h b/usr/kinit/fstype/swap_fs.h
new file mode 100644
index 0000000..7b7fddb
--- /dev/null
+++ b/usr/kinit/fstype/swap_fs.h
@@ -0,0 +1,25 @@
+#ifndef __LINUX_SWAP_FS_H
+#define __LINUX_SWAP_FS_H
+
+/* The basic structures of the swap super block */
+#define SWAP_MAGIC_L		10
+#define SWAP_RESERVED_L		(1024 - SWAP_MAGIC_L)
+#define SWAP_MAGIC_1		"SWAP-SPACE"
+#define SWAP_MAGIC_2		"SWAPSPACE2"
+
+/* Suspend signatures, located at same addr as swap magic */
+#define SUSP_MAGIC_L		9
+#define SUSP_MAGIC_1		"S1SUSPEND"
+#define SUSP_MAGIC_2		"S2SUSPEND"
+#define SUSP_MAGIC_U		"ULSUSPEND"
+
+/* The superblock is the last block in the first page */
+#define SWAP_OFFSET()		((getpagesize() - 1024) >> 10)
+
+/* On-disk "super block" */
+struct swap_super_block {
+	char reserved[SWAP_RESERVED_L];
+	char magic[SWAP_MAGIC_L];
+};
+
+#endif
diff --git a/usr/kinit/fstype/xfs_sb.h b/usr/kinit/fstype/xfs_sb.h
new file mode 100644
index 0000000..ac10ee9
--- /dev/null
+++ b/usr/kinit/fstype/xfs_sb.h
@@ -0,0 +1,16 @@
+/*
+ * Super block
+ * Fits into a sector-sized buffer at address 0 of each allocation group.
+ * Only the first of these is ever updated except during growfs.
+ */
+
+struct xfs_buf;
+struct xfs_mount;
+
+#define	XFS_SB_MAGIC		0x58465342	/* 'XFSB' */
+
+typedef struct xfs_sb {
+	__u32 sb_magicnum;	/* magic number == XFS_SB_MAGIC */
+	__u32 sb_blocksize;	/* logical block size, bytes */
+	__u64 sb_dblocks;	/* number of data blocks */
+} xfs_sb_t;
diff --git a/usr/kinit/getarg.c b/usr/kinit/getarg.c
new file mode 100644
index 0000000..fcce247
--- /dev/null
+++ b/usr/kinit/getarg.c
@@ -0,0 +1,57 @@
+#include <string.h>
+#include "kinit.h"
+
+/*
+ * Routines that hunt for a specific argument.  Please note that
+ * they actually search the array backwards.  That is because on the
+ * kernel command lines, it's legal to override an earlier argument
+ * with a later argument.
+ */
+
+/*
+ * Was this boolean argument passed?  If so return the index in the
+ * argv array for it.  For conflicting boolean options, use the
+ * one with the higher index.  The only case when the return value
+ * can be equal, is when they're both zero; so equality can be used
+ * as the default option choice.
+ *
+ * In other words, if two options "a" and "b" are opposites, and "a"
+ * is the default, this can be coded as:
+ *
+ * if (get_flag(argc,argv,"a") >= get_flag(argc,argv,"b"))
+ * 	do_a_stuff();
+ * else
+ *	do_b_stuff();
+ */
+int get_flag(int argc, char *argv[], const char *name)
+{
+	int i;
+
+	for (i = argc-1; i > 0; i--) {
+		if (!strcmp(argv[i], name))
+			return i;
+	}
+	return 0;
+}
+
+/*
+ * Was this textual parameter (foo=option) passed?
+ *
+ * This returns the latest instance of such an option in the argv array.
+ */
+char *get_arg(int argc, char *argv[], const char *name)
+{
+	int len = strlen(name);
+	char *ret = NULL;
+	int i;
+
+	for (i = argc-1; i > 0; i--) {
+		if (argv[i] && strncmp(argv[i], name, len) == 0 &&
+		    (argv[i][len] != '\0')) {
+			ret = argv[i] + len;
+			break;
+		}
+	}
+
+	return ret;
+}
diff --git a/usr/kinit/getintfile.c b/usr/kinit/getintfile.c
new file mode 100644
index 0000000..8cb94bb
--- /dev/null
+++ b/usr/kinit/getintfile.c
@@ -0,0 +1,28 @@
+/*
+ * Open a file and read it, assuming it contains a single long value.
+ * Return 0 if we read a valid value, otherwise -1.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+int getintfile(const char *path, long *val)
+{
+	char buffer[64];
+	char *ep;
+	FILE *f;
+
+	f = fopen(path, "r");
+	if (!f)
+		return -1;
+
+	ep = buffer + fread(buffer, 1, sizeof buffer - 1, f);
+	fclose(f);
+	*ep = '\0';
+
+	*val = strtol(buffer, &ep, 0);
+	if (*ep && *ep != '\n')
+		return -1;
+	else
+		return 0;
+}
diff --git a/usr/kinit/initrd.c b/usr/kinit/initrd.c
new file mode 100644
index 0000000..dc3af1a
--- /dev/null
+++ b/usr/kinit/initrd.c
@@ -0,0 +1,197 @@
+/*
+ * Handle initrd, thus putting the backwards into backwards compatible
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <sys/stat.h>
+#include <sys/mount.h>
+#include <sys/ioctl.h>
+#include <sys/wait.h>
+#include "do_mounts.h"
+#include "kinit.h"
+#include "xpio.h"
+
+#define BUF_SIZE	65536	/* Should be a power of 2 */
+
+/*
+ * Copy the initrd to /dev/ram0, copy from the end to the beginning
+ * to avoid taking 2x the memory.
+ */
+static int rd_copy_uncompressed(int ffd, int dfd)
+{
+	char buffer[BUF_SIZE];
+	off_t bytes;
+	struct stat st;
+
+	DEBUG(("kinit: uncompressed initrd\n"));
+
+	if (ffd < 0 || fstat(ffd, &st) || !S_ISREG(st.st_mode) ||
+	    (bytes = st.st_size) == 0)
+		return -1;
+
+	while (bytes) {
+		ssize_t blocksize = ((bytes - 1) & (BUF_SIZE - 1)) + 1;
+		off_t offset = bytes - blocksize;
+
+		DEBUG(("kinit: copying %zd bytes at offset %llu\n",
+		       blocksize, offset));
+
+		if (xpread(ffd, buffer, blocksize, offset) != blocksize ||
+		    xpwrite(dfd, buffer, blocksize, offset) != blocksize)
+			return -1;
+
+		ftruncate(ffd, offset);	/* Free up memory */
+		bytes = offset;
+	}
+	return 0;
+}
+
+static int rd_copy_image(const char *path)
+{
+	int ffd = open(path, O_RDONLY);
+	int rv = -1;
+	unsigned char gzip_magic[2];
+
+	if (ffd < 0)
+		goto barf;
+
+	if (xpread(ffd, gzip_magic, 2, 0) == 2 &&
+	    gzip_magic[0] == 037 && gzip_magic[1] == 0213) {
+		FILE *wfd = fopen("/dev/ram0", "w");
+		if (!wfd)
+			goto barf;
+		rv = load_ramdisk_compressed(path, wfd, 0);
+		fclose(wfd);
+	} else {
+		int dfd = open("/dev/ram0", O_WRONLY);
+		if (dfd < 0)
+			goto barf;
+		rv = rd_copy_uncompressed(ffd, dfd);
+		close(dfd);
+	}
+
+barf:
+	if (ffd >= 0)
+		close(ffd);
+	return rv;
+}
+
+/*
+ * Run /linuxrc, for emulation of old-style initrd
+ */
+static int run_linuxrc(int argc, char *argv[], dev_t root_dev)
+{
+	int root_fd, old_fd;
+	pid_t pid;
+	long realroot = Root_RAM0;
+	const char *ramdisk_name = "/dev/ram0";
+	FILE *fp;
+
+	DEBUG(("kinit: mounting initrd\n"));
+	mkdir("/root", 0700);
+	if (!mount_block(ramdisk_name, "/root", NULL, MS_VERBOSE, NULL))
+		return -errno;
+
+	/* Write the current "real root device" out to procfs */
+	DEBUG(("kinit: real_root_dev = %#x\n", root_dev));
+	fp = fopen("/proc/sys/kernel/real-root-dev", "w");
+	fprintf(fp, "%u", root_dev);
+	fclose(fp);
+
+	mkdir("/old", 0700);
+	root_fd = open_cloexec("/", O_RDONLY | O_DIRECTORY, 0);
+	old_fd = open_cloexec("/old", O_RDONLY | O_DIRECTORY, 0);
+
+	if (root_fd < 0 || old_fd < 0)
+		return -errno;
+
+	if (chdir("/root") ||
+	    mount(".", "/", NULL, MS_MOVE, NULL) || chroot("."))
+		return -errno;
+
+	pid = vfork();
+	if (pid == 0) {
+		setsid();
+		/* Looks like linuxrc doesn't get the init environment
+		   or parameters.  Weird, but so is the whole linuxrc bit. */
+		execl("/linuxrc", "linuxrc", NULL);
+		_exit(255);
+	} else if (pid > 0) {
+		DEBUG(("kinit: Waiting for linuxrc to complete...\n"));
+		while (waitpid(pid, NULL, 0) != pid) ;
+		DEBUG(("kinit: linuxrc done\n"));
+	} else {
+		return -errno;
+	}
+
+	if (fchdir(old_fd) ||
+	    mount("/", ".", NULL, MS_MOVE, NULL) ||
+	    fchdir(root_fd) || chroot("."))
+		return -errno;
+
+	close(root_fd);
+	close(old_fd);
+
+	getintfile("/proc/sys/kernel/real-root-dev", &realroot);
+
+	/* If realroot is Root_RAM0, then the initrd did any necessary work */
+	if (realroot == Root_RAM0) {
+		if (mount("/old", "/root", NULL, MS_MOVE, NULL))
+			return -errno;
+	} else {
+		mount_root(argc, argv, (dev_t) realroot, NULL);
+
+		/* If /root/initrd exists, move the initrd there, otherwise discard */
+		if (!mount("/old", "/root/initrd", NULL, MS_MOVE, NULL)) {
+			/* We're good */
+		} else {
+			int olddev = open(ramdisk_name, O_RDWR);
+			umount2("/old", MNT_DETACH);
+			if (olddev < 0 ||
+			    ioctl(olddev, BLKFLSBUF, (long)0) ||
+			    close(olddev)) {
+				fprintf(stderr,
+					"%s: Cannot flush initrd contents\n",
+					progname);
+			}
+		}
+	}
+
+	rmdir("/old");
+	return 0;
+}
+
+int initrd_load(int argc, char *argv[], dev_t root_dev)
+{
+	if (access("/initrd.image", R_OK))
+		return 0;	/* No initrd */
+
+	DEBUG(("kinit: initrd found\n"));
+
+	create_dev("/dev/ram0", Root_RAM0);
+
+	if (rd_copy_image("/initrd.image") || unlink("/initrd.image")) {
+		fprintf(stderr, "%s: initrd installation failed (too big?)\n",
+			progname);
+		return 0;	/* Failed to copy initrd */
+	}
+
+	DEBUG(("kinit: initrd copied\n"));
+
+	if (root_dev != Root_RAM0) {
+		int err;
+		DEBUG(("kinit: running linuxrc\n"));
+		err = run_linuxrc(argc, argv, root_dev);
+		if (err)
+			fprintf(stderr, "%s: running linuxrc: %s\n", progname,
+				strerror(-err));
+		return 1;	/* initrd is root, or run_linuxrc took care of it */
+	} else {
+		DEBUG(("kinit: permament (or pivoting) initrd, not running linuxrc\n"));
+		return 0;	/* Mounting initrd as ordinary root */
+	}
+}
diff --git a/usr/kinit/ipconfig/Kbuild b/usr/kinit/ipconfig/Kbuild
new file mode 100644
index 0000000..7f8d181
--- /dev/null
+++ b/usr/kinit/ipconfig/Kbuild
@@ -0,0 +1,31 @@
+#
+# Kbuild file for ipconfig
+#
+
+static-y := static/ipconfig
+shared-y := shared/ipconfig
+
+# common .o files
+objs := main.o netdev.o packet.o
+# dhcp
+objs += dhcp_proto.o
+# bootp
+objs += bootp_proto.o
+
+
+# TODO - do we want a stripped version
+# TODO - do we want the static.g + shared.g directories?
+
+
+# Create built-in.o with all object files (used by kinit)
+lib-y := $(objs)
+
+# .o files used to built executables
+static/ipconfig-y := $(objs)
+shared/ipconfig-y := $(objs)
+
+# Cleaning
+clean-dirs := static shared
+
+# install binary
+install-y := $(shared-y)
diff --git a/usr/kinit/ipconfig/README b/usr/kinit/ipconfig/README
new file mode 100644
index 0000000..5c8227a
--- /dev/null
+++ b/usr/kinit/ipconfig/README
@@ -0,0 +1,106 @@
+BOOTP/DHCP client for klibc
+---------------------------
+
+Usage:
+
+ipconfig [-c proto] [-d interface] [-i identifier]
+	 [-n] [-p port] [-t timeout] [interface ...]
+
+-c proto	Use PROTO as the configuration protocol for all
+		interfaces, unless overridden by specific interfaces.
+-d interface	Either the name of an interface, or a long spec.
+-i identifier	DHCP vendor class identifier.  The default is
+		"Linux ipconfig".
+-n		Do nothing - just print the configuration that would
+		be performed.
+-p port		Send bootp/dhcp broadcasts from PORT, to PORT - 1.
+-t timeout	Give up on all unconfigured interfaces after TIMEOUT secs.
+
+You can configure multiple interfaces by passing multiple interface
+specs on the command line, or by using the special interface name
+"all".  If you're autoconfiguring any interfaces, ipconfig will wait
+until either all such interfaces have been configured, or the timeout
+passes.
+
+PROTO can be one of the following, which selects the autoconfiguration
+protocol to use:
+
+not specified	use all protocols (the default)
+dhcp		use bootp and dhcp
+bootp		use bootp only
+rarp		use rarp (not currently supported)
+none		no autoconfiguration - either static config, or none at all
+
+An interface spec can be either short form, which is just the name of
+an interface (eth0 or whatever), or long form.  The long form consists
+of up to seven elements, separated by colons:
+
+<client-ip>:<server-ip>:<gw-ip>:<netmask>:<hostname>:<device>:<autoconf>
+
+  <client-ip>	IP address of the client. If empty, the address will
+                either be determined by RARP/BOOTP/DHCP. What protocol
+                is used de- pends on the <autoconf> parameter. If this
+                parameter is not empty, autoconf will be used.
+
+  <server-ip>   IP address of the NFS server. If RARP is used to
+                determine the client address and this parameter is NOT
+                empty only replies from the specified server are
+                accepted. To use different RARP and NFS server,
+                specify your RARP server here (or leave it blank), and
+                specify your NFS server in the `nfsroot' parameter
+                (see above). If this entry is blank the address of the
+                server is used which answered the RARP/BOOTP/DHCP
+                request.
+
+  <gw-ip>       IP address of a gateway if the server is on a different
+                subnet. If this entry is empty no gateway is used and the
+                server is assumed to be on the local network, unless a
+                value has been received by BOOTP/DHCP.
+
+  <netmask>     Netmask for local network interface. If this is empty,
+                the netmask is derived from the client IP address assuming
+                classful addressing, unless overridden in BOOTP/DHCP reply.
+
+  <hostname>    Name of the client. If empty, the client IP address is
+                used in ASCII notation, or the value received by
+                BOOTP/DHCP.
+
+  <device>      Name of network device to use. If this is empty, all
+                devices are used for RARP/BOOTP/DHCP requests, and the
+                first one we receive a reply on is configured. If you
+                have only one device, you can safely leave this blank.
+
+  <autoconf>	Method to use for autoconfiguration. If this is either
+                'rarp', 'bootp', or 'dhcp' the specified protocol is
+                used.  If the value is 'both', 'all' or empty, all
+                protocols are used.  'off', 'static' or 'none' means
+                no autoconfiguration.
+
+IP addresses and netmasks must be either absent (defaulting to zero)
+or presented in dotted-quad notation.
+
+An interface spec can be prefixed with either "ip=", "nfsaddrs=", both
+of which are ignored.  These (along with the ugliness of the long
+form) are present for compatibility with the in-kernel ipconfig code
+from 2.4 and earlier kernels.
+
+Here are a few examples of valid ipconfig command lines.
+
+Enable the loopback interface:
+    ipconfig 127.0.0.1:::::lo:none
+
+Try to configure eth0 using bootp for up to 30 seconds:
+    ipconfig -t 30 -c bootp eth0
+
+Configure eth0 and eth1 using dhcp or bootp, and eth2 statically:
+    ipconfig -c any eth0 eth1 192.168.1.1:::::eth2:none
+
+--
+
+From Russell's original README, and still true:
+
+The code in main.c is yucky imho.  Needs cleaning.
+
+--
+Russell King (2002/10/22)
+Bryan O'Sullivan (2003/04/29)
diff --git a/usr/kinit/ipconfig/bootp_packet.h b/usr/kinit/ipconfig/bootp_packet.h
new file mode 100644
index 0000000..3525ec3
--- /dev/null
+++ b/usr/kinit/ipconfig/bootp_packet.h
@@ -0,0 +1,31 @@
+#ifndef BOOTP_PACKET_H
+#define BOOTP_PACKET_H
+
+#include <sys/uio.h>
+
+struct netdev;
+
+/* packet ops */
+#define BOOTP_REQUEST	1
+#define BOOTP_REPLY	2
+
+/* your basic bootp packet */
+struct bootp_hdr {
+	uint8_t	 op;
+	uint8_t	 htype;
+	uint8_t	 hlen;
+	uint8_t	 hops;
+	uint32_t xid;
+	uint16_t secs;
+	uint16_t flags;
+	uint32_t ciaddr;
+	uint32_t yiaddr;
+	uint32_t siaddr;
+	uint32_t giaddr;
+	uint8_t	 chaddr[16];
+	char	 server_name[64];
+	char	 boot_file[128];
+	/* 312 bytes of extensions */
+};
+
+#endif
diff --git a/usr/kinit/ipconfig/bootp_proto.c b/usr/kinit/ipconfig/bootp_proto.c
new file mode 100644
index 0000000..9157984
--- /dev/null
+++ b/usr/kinit/ipconfig/bootp_proto.c
@@ -0,0 +1,212 @@
+/*
+ * BOOTP packet protocol handling.
+ */
+#include <sys/types.h>
+#include <sys/uio.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <unistd.h>
+#include <netinet/in.h>
+
+#include "ipconfig.h"
+#include "netdev.h"
+#include "bootp_packet.h"
+#include "bootp_proto.h"
+#include "packet.h"
+
+static uint8_t bootp_options[312] = {
+	[  0] = 99, 130, 83, 99,/* RFC1048 magic cookie */
+	[  4] = 1, 4,		/*   4-  9 subnet mask */
+	[ 10] = 3, 4,		/*  10- 15 default gateway */
+	[ 16] = 5, 8,		/*  16- 25 nameserver */
+	[ 26] = 12, 32,		/*  26- 59 host name */
+	[ 60] = 40, 32,		/*  60- 95 nis domain name */
+	[ 96] = 17, 40,		/*  96-137 boot path */
+	[138] = 57, 2, 1, 150,	/* 138-141 extension buffer */
+	[142] = 255,		/* end of list */
+};
+
+/*
+ * Send a plain bootp request packet with options
+ */
+int bootp_send_request(struct netdev *dev)
+{
+	struct bootp_hdr bootp;
+	struct iovec iov[] = {
+		/* [0] = ip + udp headers */
+		[1] = {&bootp, sizeof(bootp)},
+		[2] = {bootp_options, 312}
+	};
+
+	memset(&bootp, 0, sizeof(struct bootp_hdr));
+
+	bootp.op	= BOOTP_REQUEST, bootp.htype = dev->hwtype;
+	bootp.hlen	= dev->hwlen;
+	bootp.xid	= dev->bootp.xid;
+	bootp.ciaddr	= dev->ip_addr;
+	bootp.secs	= htons(time(NULL) - dev->open_time);
+	memcpy(bootp.chaddr, dev->hwaddr, 16);
+
+	DEBUG(("-> bootp xid 0x%08x secs 0x%08x ",
+	       bootp.xid, ntohs(bootp.secs)));
+
+	return packet_send(dev, iov, 2);
+}
+
+/*
+ * Parse a bootp reply packet
+ */
+int bootp_parse(struct netdev *dev, struct bootp_hdr *hdr,
+		uint8_t *exts, int extlen)
+{
+	dev->bootp.gateway	= hdr->giaddr;
+	dev->ip_addr		= hdr->yiaddr;
+	dev->ip_server		= hdr->siaddr;
+	dev->ip_netmask		= INADDR_ANY;
+	dev->ip_broadcast	= INADDR_ANY;
+	dev->ip_gateway		= hdr->giaddr;
+	dev->ip_nameserver[0]	= INADDR_ANY;
+	dev->ip_nameserver[1]	= INADDR_ANY;
+	dev->hostname[0]	= '\0';
+	dev->nisdomainname[0]	= '\0';
+	dev->bootpath[0]	= '\0';
+	memcpy(&dev->filename, &hdr->boot_file, FNLEN);
+
+	if (extlen >= 4 && exts[0] == 99 && exts[1] == 130 &&
+	    exts[2] == 83 && exts[3] == 99) {
+		uint8_t *ext;
+
+		for (ext = exts + 4; ext - exts < extlen;) {
+			int len;
+			uint8_t opt = *ext++;
+
+			if (opt == 0)
+				continue;
+			else if (opt == 255)
+				break;
+
+			len = *ext++;
+
+			switch (opt) {
+			case 1:	/* subnet mask */
+				if (len == 4)
+					memcpy(&dev->ip_netmask, ext, 4);
+				break;
+			case 3:	/* default gateway */
+				if (len >= 4)
+					memcpy(&dev->ip_gateway, ext, 4);
+				break;
+			case 6:	/* DNS server */
+				if (len >= 4)
+					memcpy(&dev->ip_nameserver, ext,
+					       len >= 8 ? 8 : 4);
+				break;
+			case 12:	/* host name */
+				if (len > sizeof(dev->hostname) - 1)
+					len = sizeof(dev->hostname) - 1;
+				memcpy(&dev->hostname, ext, len);
+				dev->hostname[len] = '\0';
+				break;
+			case 15:	/* domain name */
+				if (len > sizeof(dev->dnsdomainname) - 1)
+					len = sizeof(dev->dnsdomainname) - 1;
+				memcpy(&dev->dnsdomainname, ext, len);
+				dev->dnsdomainname[len] = '\0';
+				break;
+			case 17:	/* root path */
+				if (len > sizeof(dev->bootpath) - 1)
+					len = sizeof(dev->bootpath) - 1;
+				memcpy(&dev->bootpath, ext, len);
+				dev->bootpath[len] = '\0';
+				break;
+			case 26:	/* interface MTU */
+				if (len == 2)
+					dev->mtu = (ext[0] << 8) + ext[1];
+				break;
+			case 28:	/* broadcast addr */
+				if (len == 4)
+					memcpy(&dev->ip_broadcast, ext, 4);
+				break;
+			case 40:	/* NIS domain name */
+				if (len > sizeof(dev->nisdomainname) - 1)
+					len = sizeof(dev->nisdomainname) - 1;
+				memcpy(&dev->nisdomainname, ext, len);
+				dev->nisdomainname[len] = '\0';
+				break;
+			case 54: 	/* server identifier */
+				if (len == 4 && !dev->ip_server)
+					memcpy(&dev->ip_server, ext, 4);
+				break;
+			}
+
+			ext += len;
+		}
+	}
+
+	/*
+	 * Got packet.
+	 */
+	return 1;
+}
+
+/*
+ * Receive a bootp reply and parse packet
+ */
+int bootp_recv_reply(struct netdev *dev)
+{
+	struct bootp_hdr bootp;
+	uint8_t bootp_options[312];
+	struct iovec iov[] = {
+		/* [0] = ip + udp headers */
+		[1] = {&bootp, sizeof(struct bootp_hdr)},
+		[2] = {bootp_options, 312}
+	};
+	int ret;
+
+	ret = packet_recv(iov, 3);
+	if (ret <= 0)
+		return ret;
+
+	if (ret < sizeof(struct bootp_hdr) ||
+	    bootp.op != BOOTP_REPLY ||	/* RFC951 7.5 */
+	    bootp.xid != dev->bootp.xid ||
+	    memcmp(bootp.chaddr, dev->hwaddr, 16))
+		return 0;
+
+	ret -= sizeof(struct bootp_hdr);
+
+	return bootp_parse(dev, &bootp, bootp_options, ret);
+}
+
+/*
+ * Initialise interface for bootp.
+ */
+int bootp_init_if(struct netdev *dev)
+{
+	short flags;
+
+	/*
+	 * Get the device flags
+	 */
+	if (netdev_getflags(dev, &flags))
+		return -1;
+
+	/*
+	 * We can't do DHCP nor BOOTP if this device
+	 * doesn't support broadcast.
+	 */
+	if (dev->mtu < 364 || (flags & IFF_BROADCAST) == 0) {
+		dev->caps &= ~(CAP_BOOTP | CAP_DHCP);
+		return 0;
+	}
+
+	/*
+	 * Get a random XID
+	 */
+	dev->bootp.xid = (uint32_t) lrand48();
+	dev->open_time = time(NULL);
+
+	return 0;
+}
diff --git a/usr/kinit/ipconfig/bootp_proto.h b/usr/kinit/ipconfig/bootp_proto.h
new file mode 100644
index 0000000..60873ce
--- /dev/null
+++ b/usr/kinit/ipconfig/bootp_proto.h
@@ -0,0 +1,10 @@
+#ifndef IPCONFIG_BOOTP_PROTO_H
+#define IPCONFIG_BOOTP_PROTO_H
+
+int bootp_send_request(struct netdev *dev);
+int bootp_recv_reply(struct netdev *dev);
+int bootp_parse(struct netdev *dev, struct bootp_hdr *hdr, uint8_t * exts,
+		int extlen);
+int bootp_init_if(struct netdev *dev);
+
+#endif /* IPCONFIG_BOOTP_PROTO_H */
diff --git a/usr/kinit/ipconfig/dhcp_proto.c b/usr/kinit/ipconfig/dhcp_proto.c
new file mode 100644
index 0000000..a1090f3
--- /dev/null
+++ b/usr/kinit/ipconfig/dhcp_proto.c
@@ -0,0 +1,219 @@
+/*
+ * DHCP RFC 2131 and 2132
+ */
+#include <sys/types.h>
+#include <sys/uio.h>
+#include <netinet/in.h>
+#include <stdio.h>
+#include <string.h>
+#include <time.h>
+
+#include "ipconfig.h"
+#include "netdev.h"
+#include "bootp_packet.h"
+#include "bootp_proto.h"
+#include "dhcp_proto.h"
+#include "packet.h"
+
+static uint8_t dhcp_params[] = {
+	1,			/* subnet mask */
+	3,			/* default gateway */
+	6,			/* DNS server */
+	12,			/* host name */
+	15,			/* domain name */
+	17,			/* root path */
+	26,			/* interface mtu */
+	28,			/* broadcast addr */
+	40,			/* NIS domain name (why?) */
+};
+
+static uint8_t dhcp_discover_hdr[] = {
+	99, 130, 83, 99,		/* bootp cookie */
+	53, 1, DHCPDISCOVER,		/* dhcp message type */
+	55, sizeof(dhcp_params),	/* parameter list */
+};
+
+static uint8_t dhcp_request_hdr[] = {
+	99, 130, 83, 99,		/* boot cookie */
+	53, 1, DHCPREQUEST,		/* dhcp message type */
+#define SERVER_IP_OFF 9
+	54, 4, 0, 0, 0, 0,		/* server IP */
+#define REQ_IP_OFF 15
+	50, 4, 0, 0, 0, 0,		/* requested IP address */
+	55, sizeof(dhcp_params),	/* parameter list */
+};
+
+static uint8_t dhcp_end[] = {
+	255,
+};
+
+/* Both iovecs below have to have the same structure, since dhcp_send()
+   pokes at the internals */
+#define DHCP_IOV_LEN 6
+
+static struct iovec dhcp_discover_iov[] = {
+	/* [0] = ip + udp header */
+	/* [1] = bootp header */
+	[2] = {dhcp_discover_hdr, sizeof(dhcp_discover_hdr)},
+	[3] = {dhcp_params, sizeof(dhcp_params)},
+	/* [4] = DHCP vendor class */
+	[5] = {dhcp_end, sizeof(dhcp_end)}
+};
+
+static struct iovec dhcp_request_iov[] = {
+	/* [0] = ip + udp header */
+	/* [1] = bootp header */
+	[2] = {dhcp_request_hdr, sizeof(dhcp_request_hdr)},
+	[3] = {dhcp_params, sizeof(dhcp_params)},
+	/* [4] = DHCP vendor class */
+	[5] = {dhcp_end, sizeof(dhcp_end)}
+};
+
+/*
+ * Parse a DHCP response packet
+ */
+static int
+dhcp_parse(struct netdev *dev, struct bootp_hdr *hdr, uint8_t * exts, int extlen)
+{
+	uint8_t type = 0;
+	uint32_t serverid = INADDR_NONE;
+	int ret = 0;
+
+	if (extlen >= 4 && exts[0] == 99 && exts[1] == 130 &&
+	    exts[2] == 83 && exts[3] == 99) {
+		uint8_t *ext;
+
+		for (ext = exts + 4; ext - exts < extlen;) {
+			uint8_t len, *opt = ext++;
+			if (*opt == 0)
+				continue;
+
+			len = *ext++;
+
+			ext += len;
+
+			if (*opt == 53)
+				type = opt[2];
+			if (*opt == 54)
+				memcpy(&serverid, opt + 2, 4);
+		}
+	}
+
+	switch (type) {
+	case DHCPOFFER:
+		ret = bootp_parse(dev, hdr, exts, extlen);
+		if (ret == 1 && serverid != INADDR_NONE)
+			dev->serverid = serverid;
+		DEBUG(("\n   dhcp offer\n"));
+		break;
+
+	case DHCPACK:
+		ret = bootp_parse(dev, hdr, exts, extlen);
+		DEBUG(("\n   dhcp ack\n"));
+		break;
+
+	case DHCPNAK:
+		ret = 2;
+		DEBUG(("\n   dhcp nak\n"));
+		break;
+	}
+	return ret;
+}
+
+/*
+ * Receive and parse a DHCP packet
+ */
+static int dhcp_recv(struct netdev *dev)
+{
+	struct bootp_hdr bootp;
+	uint8_t dhcp_options[1500];
+	struct iovec iov[] = {
+		/* [0] = ip + udp header */
+		[1] = {&bootp, sizeof(struct bootp_hdr)},
+		[2] = {dhcp_options, sizeof(dhcp_options)}
+	};
+	int ret;
+
+	ret = packet_recv(iov, 3);
+	if (ret <= 0)
+		return ret;
+
+	DEBUG(("\n   dhcp xid %08x ", dev->bootp.xid));
+
+	if (ret < sizeof(struct bootp_hdr) || bootp.op != BOOTP_REPLY ||	/* RFC951 7.5 */
+	    bootp.xid != dev->bootp.xid ||
+	    memcmp(bootp.chaddr, dev->hwaddr, 16))
+		return 0;
+
+	ret -= sizeof(struct bootp_hdr);
+
+	return dhcp_parse(dev, &bootp, dhcp_options, ret);
+}
+
+static int dhcp_send(struct netdev *dev, struct iovec *vec)
+{
+	struct bootp_hdr bootp;
+
+	memset(&bootp, 0, sizeof(struct bootp_hdr));
+
+	bootp.op	= BOOTP_REQUEST;
+	bootp.htype	= dev->hwtype;
+	bootp.hlen	= dev->hwlen;
+	bootp.xid	= dev->bootp.xid;
+	bootp.ciaddr	= dev->ip_addr;
+	bootp.giaddr	= dev->bootp.gateway;
+	bootp.secs	= htons(time(NULL) - dev->open_time);
+	memcpy(bootp.chaddr, dev->hwaddr, 16);
+
+	vec[1].iov_base	= &bootp;
+	vec[1].iov_len	= sizeof(struct bootp_hdr);
+
+	vec[4].iov_base = vendor_class_identifier;
+	vec[4].iov_len  = vendor_class_identifier_len;
+
+	DEBUG(("xid %08x secs %d ", bootp.xid, ntohs(bootp.secs)));
+
+	return packet_send(dev, vec, DHCP_IOV_LEN);
+}
+
+/*
+ * Send a DHCP discover packet
+ */
+int dhcp_send_discover(struct netdev *dev)
+{
+	dev->ip_addr = INADDR_ANY;
+	dev->ip_gateway = INADDR_ANY;
+
+	DEBUG(("-> dhcp discover "));
+
+	return dhcp_send(dev, dhcp_discover_iov);
+}
+
+/*
+ * Receive a DHCP offer packet
+ */
+int dhcp_recv_offer(struct netdev *dev)
+{
+	return dhcp_recv(dev);
+}
+
+/*
+ * Send a DHCP request packet
+ */
+int dhcp_send_request(struct netdev *dev)
+{
+	memcpy(&dhcp_request_hdr[SERVER_IP_OFF], &dev->serverid, 4);
+	memcpy(&dhcp_request_hdr[REQ_IP_OFF], &dev->ip_addr, 4);
+
+	DEBUG(("-> dhcp request "));
+
+	return dhcp_send(dev, dhcp_request_iov);
+}
+
+/*
+ * Receive a DHCP ack packet
+ */
+int dhcp_recv_ack(struct netdev *dev)
+{
+	return dhcp_recv(dev);
+}
diff --git a/usr/kinit/ipconfig/dhcp_proto.h b/usr/kinit/ipconfig/dhcp_proto.h
new file mode 100644
index 0000000..0fba92f
--- /dev/null
+++ b/usr/kinit/ipconfig/dhcp_proto.h
@@ -0,0 +1,19 @@
+#ifndef IPCONFIG_DHCP_PROTO_H
+#define IPCONFIG_DHCP_PROTO_H
+
+/* DHCP message types */
+#define DHCPDISCOVER    1
+#define DHCPOFFER       2
+#define DHCPREQUEST     3
+#define DHCPDECLINE     4
+#define DHCPACK         5
+#define DHCPNAK         6
+#define DHCPRELEASE     7
+#define DHCPINFORM      8
+
+int dhcp_send_discover(struct netdev *dev);
+int dhcp_recv_offer(struct netdev *dev);
+int dhcp_send_request(struct netdev *dev);
+int dhcp_recv_ack(struct netdev *dev);
+
+#endif /* IPCONFIG_DHCP_PROTO_H */
diff --git a/usr/kinit/ipconfig/ipconfig.h b/usr/kinit/ipconfig/ipconfig.h
new file mode 100644
index 0000000..8b50474
--- /dev/null
+++ b/usr/kinit/ipconfig/ipconfig.h
@@ -0,0 +1,34 @@
+#ifndef IPCONFIG_IPCONFIG_H
+#define IPCONFIG_IPCONFIG_H
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#define LOCAL_PORT	68
+#define REMOTE_PORT	(LOCAL_PORT - 1)
+
+extern uint16_t cfg_local_port;
+extern uint16_t cfg_remote_port;
+
+extern char vendor_class_identifier[];
+extern int vendor_class_identifier_len;
+
+int ipconfig_main(int argc, char *argv[]);
+uint32_t ipconfig_server_address(void *next);
+
+/*
+ * Note for gcc 3.2.2:
+ *
+ * If you're turning on debugging, make sure you get rid of -Os from
+ * the gcc command line, or else ipconfig will fail to link.
+ */
+#define IPC_DEBUG
+
+#undef DEBUG
+#ifdef IPC_DEBUG
+#define DEBUG(x) printf x
+#else
+#define DEBUG(x) do { } while(0)
+#endif
+
+#endif /* IPCONFIG_IPCONFIG_H */
diff --git a/usr/kinit/ipconfig/main.c b/usr/kinit/ipconfig/main.c
new file mode 100644
index 0000000..50141e5
--- /dev/null
+++ b/usr/kinit/ipconfig/main.c
@@ -0,0 +1,786 @@
+#include <errno.h>
+#include <poll.h>
+#include <limits.h>
+#include <setjmp.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <time.h>
+#include <arpa/inet.h>
+#include <sys/types.h>
+#include <sys/time.h>
+#include <dirent.h>
+#include <fcntl.h>
+#include <unistd.h>		/* for getopts */
+
+#include <net/if_arp.h>
+
+#include "ipconfig.h"
+#include "netdev.h"
+#include "bootp_packet.h"
+#include "bootp_proto.h"
+#include "dhcp_proto.h"
+#include "packet.h"
+
+static const char sysfs_class_net[] = "/sys/class/net";
+static const char *progname;
+static jmp_buf abort_buf;
+static char do_not_config;
+static unsigned int default_caps = CAP_DHCP | CAP_BOOTP | CAP_RARP;
+static int loop_timeout = -1;
+static int configured;
+static int bringup_first = 0;
+
+/* DHCP vendor class identifier */
+char vendor_class_identifier[260];
+int vendor_class_identifier_len;
+
+struct state {
+	int state;
+	int restart_state;
+	time_t expire;
+	int retry_period;
+
+	struct netdev *dev;
+	struct state *next;
+};
+
+static inline const char *my_inet_ntoa(uint32_t addr)
+{
+	struct in_addr a;
+
+	a.s_addr = addr;
+
+	return inet_ntoa(a);
+}
+
+static void print_device_config(struct netdev *dev)
+{
+	printf("IP-Config: %s complete (from %s):\n", dev->name,
+	       my_inet_ntoa(dev->serverid ? dev->serverid : dev->ip_server));
+	printf(" address: %-16s ", my_inet_ntoa(dev->ip_addr));
+	printf("broadcast: %-16s ", my_inet_ntoa(dev->ip_broadcast));
+	printf("netmask: %-16s\n", my_inet_ntoa(dev->ip_netmask));
+	printf(" gateway: %-16s ", my_inet_ntoa(dev->ip_gateway));
+	printf("dns0     : %-16s ", my_inet_ntoa(dev->ip_nameserver[0]));
+	printf("dns1   : %-16s\n", my_inet_ntoa(dev->ip_nameserver[1]));
+	if (dev->hostname[0])
+		printf(" host   : %-64s\n", dev->hostname);
+	if (dev->dnsdomainname[0])
+		printf(" domain : %-64s\n", dev->dnsdomainname);
+	if (dev->nisdomainname[0])
+		printf(" nisdomain: %-64s\n", dev->nisdomainname);
+	printf(" rootserver: %s ", my_inet_ntoa(dev->ip_server));
+	printf("rootpath: %s\n", dev->bootpath);
+	printf(" filename  : %s\n", dev->filename);
+}
+
+static void configure_device(struct netdev *dev)
+{
+	if (do_not_config)
+		return;
+
+	if (netdev_setmtu(dev))
+		printf("IP-Config: failed to set MTU on %s to %u\n",
+		       dev->name, dev->mtu);
+
+	if (netdev_setaddress(dev))
+		printf("IP-Config: failed to set addresses on %s\n", dev->name);
+	if (netdev_setdefaultroute(dev))
+		printf("IP-Config: failed to set default route on %s\n",
+		       dev->name);
+	if (dev->hostname[0] &&
+			sethostname(dev->hostname, strlen(dev->hostname)))
+		printf("IP-Config: failed to set hostname '%s' from %s\n",
+			dev->hostname, dev->name);
+}
+
+static void dump_device_config(struct netdev *dev)
+{
+	char fn[40];
+	FILE *f;
+
+	snprintf(fn, sizeof(fn), "/tmp/net-%s.conf", dev->name);
+	f = fopen(fn, "w");
+	if (f) {
+		fprintf(f, "DEVICE=%s\n", dev->name);
+		fprintf(f, "IPV4ADDR=%s\n", my_inet_ntoa(dev->ip_addr));
+		fprintf(f, "IPV4BROADCAST=%s\n",
+			my_inet_ntoa(dev->ip_broadcast));
+		fprintf(f, "IPV4NETMASK=%s\n", my_inet_ntoa(dev->ip_netmask));
+		fprintf(f, "IPV4GATEWAY=%s\n", my_inet_ntoa(dev->ip_gateway));
+		fprintf(f, "IPV4DNS0=%s\n",
+			my_inet_ntoa(dev->ip_nameserver[0]));
+		fprintf(f, "IPV4DNS1=%s\n",
+			my_inet_ntoa(dev->ip_nameserver[1]));
+		fprintf(f, "HOSTNAME=%s\n", dev->hostname);
+		fprintf(f, "DNSDOMAIN=%s\n", dev->dnsdomainname);
+		fprintf(f, "NISDOMAIN=%s\n", dev->nisdomainname);
+		fprintf(f, "ROOTSERVER=%s\n", my_inet_ntoa(dev->ip_server));
+		fprintf(f, "ROOTPATH=%s\n", dev->bootpath);
+		fprintf(f, "filename=\"%s\"\n", dev->filename);
+		fclose(f);
+	}
+}
+
+static uint32_t inet_class_netmask(uint32_t ip)
+{
+	ip = ntohl(ip);
+	if (IN_CLASSA(ip))
+		return htonl(IN_CLASSA_NET);
+	if (IN_CLASSB(ip))
+		return htonl(IN_CLASSB_NET);
+	if (IN_CLASSC(ip))
+		return htonl(IN_CLASSC_NET);
+	return INADDR_ANY;
+}
+
+static void postprocess_device(struct netdev *dev)
+{
+	if (dev->ip_netmask == INADDR_ANY) {
+		dev->ip_netmask = inet_class_netmask(dev->ip_addr);
+		printf("IP-Config: %s guessed netmask %s\n",
+		       dev->name, my_inet_ntoa(dev->ip_netmask));
+	}
+	if (dev->ip_broadcast == INADDR_ANY) {
+		dev->ip_broadcast =
+		    (dev->ip_addr & dev->ip_netmask) | ~dev->ip_netmask;
+		printf("IP-Config: %s guessed broadcast address %s\n",
+		       dev->name, my_inet_ntoa(dev->ip_broadcast));
+	}
+	if (dev->ip_nameserver[0] == INADDR_ANY) {
+		dev->ip_nameserver[0] = dev->ip_server;
+		printf("IP-Config: %s guessed nameserver address %s\n",
+		       dev->name, my_inet_ntoa(dev->ip_nameserver[0]));
+	}
+}
+
+static void complete_device(struct netdev *dev)
+{
+	postprocess_device(dev);
+	configure_device(dev);
+	dump_device_config(dev);
+	print_device_config(dev);
+
+	++configured;
+
+	dev->next = ifaces;
+	ifaces = dev;
+}
+
+static int process_receive_event(struct state *s, time_t now)
+{
+	int handled = 1;
+
+	switch (s->state) {
+	case DEVST_BOOTP:
+		s->restart_state = DEVST_BOOTP;
+		switch (bootp_recv_reply(s->dev)) {
+		case -1:
+			s->state = DEVST_ERROR;
+			break;
+		case 1:
+			s->state = DEVST_COMPLETE;
+			DEBUG(("\n   bootp reply\n"));
+			break;
+		}
+		break;
+
+	case DEVST_DHCPDISC:
+		s->restart_state = DEVST_DHCPDISC;
+		switch (dhcp_recv_offer(s->dev)) {
+		case -1:
+			s->state = DEVST_ERROR;
+			break;
+		case 1:	/* Offer received */
+			s->state = DEVST_DHCPREQ;
+			dhcp_send_request(s->dev);
+			break;
+		}
+		break;
+
+	case DEVST_DHCPREQ:
+		s->restart_state = DEVST_DHCPDISC;
+		switch (dhcp_recv_ack(s->dev)) {
+		case -1:	/* error */
+			s->state = DEVST_ERROR;
+			break;
+		case 1:	/* ACK received */
+			s->state = DEVST_COMPLETE;
+			break;
+		case 2:	/* NAK received */
+			s->state = DEVST_DHCPDISC;
+			break;
+		}
+		break;
+	}
+
+	switch (s->state) {
+	case DEVST_COMPLETE:
+		complete_device(s->dev);
+		break;
+
+	case DEVST_ERROR:
+		/* error occurred, try again in 10 seconds */
+		s->expire = now + 10;
+	default:
+		DEBUG(("\n"));
+		handled = 0;
+		break;
+	}
+
+	return handled;
+}
+
+static void process_timeout_event(struct state *s, time_t now)
+{
+	int ret = 0;
+
+	/*
+	 * Is the link up?  If not, try again in 1 second.
+	 */
+	if (!netdev_running(s->dev)) {
+		s->expire = now + 1;
+		s->state = s->restart_state;
+		return;
+	}
+
+	/*
+	 * If we had an error, restore a sane state to
+	 * restart from.
+	 */
+	if (s->state == DEVST_ERROR)
+		s->state = s->restart_state;
+
+	/*
+	 * Now send a packet depending on our state.
+	 */
+	switch (s->state) {
+	case DEVST_BOOTP:
+		ret = bootp_send_request(s->dev);
+		s->restart_state = DEVST_BOOTP;
+		break;
+
+	case DEVST_DHCPDISC:
+		ret = dhcp_send_discover(s->dev);
+		s->restart_state = DEVST_DHCPDISC;
+		break;
+
+	case DEVST_DHCPREQ:
+		ret = dhcp_send_request(s->dev);
+		s->restart_state = DEVST_DHCPDISC;
+		break;
+	}
+
+	if (ret == -1) {
+		s->state = DEVST_ERROR;
+		s->expire = now + 10;
+	} else {
+		s->expire = now + s->retry_period;
+
+		s->retry_period *= 2;
+		if (s->retry_period > 60)
+			s->retry_period = 60;
+	}
+}
+
+static struct state *slist;
+struct netdev *ifaces;
+
+static int do_pkt_recv(int pkt_fd, time_t now)
+{
+	int ifindex, ret;
+	struct state *s;
+
+	ret = packet_peek(&ifindex);
+	if (ret < 0)
+		goto bail;
+
+	for (s = slist; s; s = s->next) {
+		if (s->dev->ifindex == ifindex) {
+			ret |= process_receive_event(s, now);
+			break;
+		}
+	}
+
+      bail:
+	return ret;
+}
+
+static int loop(void)
+{
+#define NR_FDS	1
+	struct pollfd fds[NR_FDS];
+	struct state *s;
+	int pkt_fd;
+	int nr = 0;
+	struct timeval now, prev;
+	time_t start;
+
+	pkt_fd = packet_open();
+	if (pkt_fd == -1) {
+		perror("packet_open");
+		return -1;
+	}
+
+	fds[0].fd = pkt_fd;
+	fds[0].events = POLLRDNORM;
+
+	gettimeofday(&now, NULL);
+	start = now.tv_sec;
+	while (1) {
+		int timeout = 60;
+		int pending = 0;
+		int done = 0;
+		int timeout_ms;
+		int x;
+
+		for (s = slist; s; s = s->next) {
+			DEBUG(("%s: state = %d\n", s->dev->name, s->state));
+
+			if (s->state == DEVST_COMPLETE) {
+				done++;
+				continue;
+			}
+
+			pending++;
+
+			if (s->expire - now.tv_sec <= 0) {
+				DEBUG(("timeout\n"));
+				process_timeout_event(s, now.tv_sec);
+			}
+
+			if (timeout > s->expire - now.tv_sec)
+				timeout = s->expire - now.tv_sec;
+		}
+
+		if (pending == 0 || (bringup_first && done))
+			break;
+
+		timeout_ms = timeout * 1000;
+
+		for (x = 0; x < 2; x++) {
+			int delta_ms;
+
+			if (timeout_ms <= 0)
+				timeout_ms = 100;
+
+			nr = poll(fds, NR_FDS, timeout_ms);
+			prev = now;
+			gettimeofday(&now, NULL);
+
+			if ((fds[0].revents & POLLRDNORM)) {
+				nr = do_pkt_recv(pkt_fd, now.tv_sec);
+				if (nr == 1)
+					break;
+				else if (nr == 0)
+					packet_discard();
+			}
+
+			if (loop_timeout >= 0 &&
+			    now.tv_sec - start >= loop_timeout) {
+				printf("IP-Config: no response after %d "
+				       "secs - giving up\n", loop_timeout);
+				goto bail;
+			}
+
+			delta_ms = (now.tv_sec - prev.tv_sec) * 1000;
+			delta_ms += (now.tv_usec - prev.tv_usec) / 1000;
+
+			DEBUG(("Delta: %d ms\n", delta_ms));
+
+			timeout_ms -= delta_ms;
+		}
+	}
+      bail:
+	packet_close();
+
+	return 0;
+}
+
+static int add_one_dev(struct netdev *dev)
+{
+	struct state *state;
+
+	state = malloc(sizeof(struct state));
+	if (!state)
+		return -1;
+
+	state->dev = dev;
+	state->expire = time(NULL);
+	state->retry_period = 1;
+
+	/*
+	 * Select the state that we start from.
+	 */
+	if (dev->caps & CAP_DHCP && dev->ip_addr == INADDR_ANY) {
+		state->restart_state = state->state = DEVST_DHCPDISC;
+	} else if (dev->caps & CAP_DHCP) {
+		state->restart_state = state->state = DEVST_DHCPREQ;
+	} else if (dev->caps & CAP_BOOTP) {
+		state->restart_state = state->state = DEVST_BOOTP;
+	}
+
+	state->next = slist;
+	slist = state;
+
+	return 0;
+}
+
+static void parse_addr(uint32_t * addr, const char *ip)
+{
+	struct in_addr in;
+	if (inet_aton(ip, &in) == 0) {
+		fprintf(stderr, "%s: can't parse IP address '%s'\n",
+			progname, ip);
+		longjmp(abort_buf, 1);
+	}
+	*addr = in.s_addr;
+}
+
+static unsigned int parse_proto(const char *ip)
+{
+	unsigned int caps = 0;
+
+	if (*ip == '\0' || strcmp(ip, "on") == 0 || strcmp(ip, "any") == 0)
+		caps = CAP_BOOTP | CAP_DHCP | CAP_RARP;
+	else if (strcmp(ip, "both") == 0)
+		caps = CAP_BOOTP | CAP_RARP;
+	else if (strcmp(ip, "dhcp") == 0)
+		caps = CAP_BOOTP | CAP_DHCP;
+	else if (strcmp(ip, "bootp") == 0)
+		caps = CAP_BOOTP;
+	else if (strcmp(ip, "rarp") == 0)
+		caps = CAP_RARP;
+	else if (strcmp(ip, "none") == 0 || strcmp(ip, "static") == 0
+		 || strcmp(ip, "off") == 0)
+		goto bail;
+	else {
+		fprintf(stderr, "%s: invalid protocol '%s'\n", progname, ip);
+		longjmp(abort_buf, 1);
+	}
+      bail:
+	return caps;
+}
+
+static int add_all_devices(struct netdev *template);
+
+static int parse_device(struct netdev *dev, const char *ip)
+{
+	char *cp;
+	int i, opt;
+	int is_ip = 0;
+
+	DEBUG(("IP-Config: parse_device: \"%s\"\n", ip));
+
+	if (strncmp(ip, "ip=", 3) == 0) {
+		ip += 3;
+		is_ip = 1;
+	} else if (strncmp(ip, "nfsaddrs=", 9) == 0) {
+		ip += 9;
+		is_ip = 1;	/* Not sure about this...? */
+	}
+
+	if (!strchr(ip, ':')) {
+		/* Only one option, e.g. "ip=dhcp", or it's an interface name */
+		if (is_ip) {
+			dev->caps = parse_proto(ip);
+			bringup_first = 1;
+		} else {
+			dev->name = ip;
+		}
+	} else {
+		for (i = opt = 0; ip && *ip; ip = cp, opt++) {
+			if ((cp = strchr(ip, ':'))) {
+				*cp++ = '\0';
+			}
+			if (opt > 6) {
+				fprintf(stderr, "%s: too many options for %s\n",
+					progname, dev->name);
+				longjmp(abort_buf, 1);
+			}
+
+			if (*ip == '\0')
+				continue;
+			DEBUG(("IP-Config: opt #%d: '%s'\n", opt, ip));
+			switch (opt) {
+			case 0:
+				parse_addr(&dev->ip_addr, ip);
+				dev->caps = 0;
+				break;
+			case 1:
+				parse_addr(&dev->ip_server, ip);
+				break;
+			case 2:
+				parse_addr(&dev->ip_gateway, ip);
+				break;
+			case 3:
+				parse_addr(&dev->ip_netmask, ip);
+				break;
+			case 4:
+				strncpy(dev->hostname, ip, SYS_NMLN - 1);
+				dev->hostname[SYS_NMLN - 1] = '\0';
+				break;
+			case 5:
+				dev->name = ip;
+				break;
+			case 6:
+				dev->caps = parse_proto(ip);
+				break;
+			}
+		}
+	}
+
+	if (dev->name == NULL ||
+	    dev->name[0] == '\0' || strcmp(dev->name, "all") == 0) {
+		add_all_devices(dev);
+		return 0;
+	}
+	return 1;
+}
+
+static void bringup_device(struct netdev *dev)
+{
+	if (netdev_up(dev) == 0) {
+		if (dev->caps) {
+			add_one_dev(dev);
+		} else {
+			complete_device(dev);
+		}
+	}
+}
+
+static void bringup_one_dev(struct netdev *template, struct netdev *dev)
+{
+	if (template->ip_addr != INADDR_NONE)
+		dev->ip_addr = template->ip_addr;
+	if (template->ip_server != INADDR_NONE)
+		dev->ip_server = template->ip_server;
+	if (template->ip_gateway != INADDR_NONE)
+		dev->ip_gateway = template->ip_gateway;
+	if (template->ip_netmask != INADDR_NONE)
+		dev->ip_netmask = template->ip_netmask;
+	if (template->ip_nameserver[0] != INADDR_NONE)
+		dev->ip_nameserver[0] = template->ip_nameserver[0];
+	if (template->ip_nameserver[1] != INADDR_NONE)
+		dev->ip_nameserver[1] = template->ip_nameserver[1];
+	if (template->hostname[0] != '\0')
+		strcpy(dev->hostname, template->hostname);
+	dev->caps &= template->caps;
+
+	bringup_device(dev);
+}
+
+static struct netdev *add_device(const char *info)
+{
+	struct netdev *dev;
+	int i;
+
+	dev = malloc(sizeof(struct netdev));
+	if (dev == NULL) {
+		fprintf(stderr, "%s: out of memory\n", progname);
+		longjmp(abort_buf, 1);
+	}
+
+	memset(dev, 0, sizeof(struct netdev));
+	dev->caps = default_caps;
+
+	if (parse_device(dev, info) == 0)
+		goto bail;
+
+	if (netdev_init_if(dev) == -1)
+		goto bail;
+
+	if (bootp_init_if(dev) == -1)
+		goto bail;
+
+	printf("IP-Config: %s hardware address", dev->name);
+	for (i = 0; i < dev->hwlen; i++)
+		printf("%c%02x", i == 0 ? ' ' : ':', dev->hwaddr[i]);
+	printf(" mtu %d%s%s\n", dev->mtu,
+	       dev->caps & CAP_DHCP ? " DHCP" :
+	       dev->caps & CAP_BOOTP ? " BOOTP" : "",
+	       dev->caps & CAP_RARP ? " RARP" : "");
+	return dev;
+      bail:
+	free(dev);
+	return NULL;
+}
+
+static int add_all_devices(struct netdev *template)
+{
+	DIR *d;
+	struct dirent *de;
+	struct netdev *dev;
+	char t[PATH_MAX], p[255];
+	int i, fd;
+	unsigned long flags;
+
+	d = opendir(sysfs_class_net);
+	if (!d)
+		return 0;
+
+	while ((de = readdir(d)) != NULL) {
+		/* This excludes devices beginning with dots or "dummy", as well as . or .. */
+		if (de->d_name[0] == '.' || !strcmp(de->d_name, ".."))
+			continue;
+		i = snprintf(t, PATH_MAX - 1, "%s/%s/flags", sysfs_class_net,
+			     de->d_name);
+		if (i < 0 || i >= PATH_MAX - 1)
+			continue;
+		t[i] = '\0';
+		fd = open(t, O_RDONLY);
+		if (fd < 0) {
+			perror(t);
+			continue;
+		}
+		i = read(fd, &p, sizeof(p) - 1);
+		close(fd);
+		if (i < 0) {
+			perror(t);
+			continue;
+		}
+		p[i] = '\0';
+		flags = strtoul(p, NULL, 0);
+		/* Heuristic for if this is a reasonable boot interface.
+		   This is the same
+		   logic the in-kernel ipconfig uses... */
+		if (!(flags & IFF_LOOPBACK) &&
+		    (flags & (IFF_BROADCAST | IFF_POINTOPOINT))) {
+			DEBUG(("Trying to bring up %s\n", de->d_name));
+
+			if (!(dev = add_device(de->d_name)))
+				continue;
+			bringup_one_dev(template, dev);
+		}
+	}
+	closedir(d);
+	return 1;
+}
+
+static int check_autoconfig(void)
+{
+	int ndev = 0, nauto = 0;
+	struct state *s;
+
+	for (s = slist; s; s = s->next) {
+		ndev++;
+		if (s->dev->caps)
+			nauto++;
+	}
+
+	if (ndev == 0) {
+		if (configured == 0) {
+			fprintf(stderr, "%s: no devices to configure\n",
+				progname);
+			longjmp(abort_buf, 1);
+		}
+	}
+
+	return nauto;
+}
+
+static void set_vendor_identifier(const char *id)
+{
+	int len = strlen(id);
+	if (len >= 255) {
+		fprintf(stderr,
+			"%s: invalid vendor class identifier: "
+			"%s\n", progname, id);
+		longjmp(abort_buf, 1);
+	}
+	memcpy(vendor_class_identifier+2, id, len);
+	vendor_class_identifier[0] = 60;
+	vendor_class_identifier[1] = len;
+	vendor_class_identifier_len = len+2;
+}
+
+int main(int argc, char *argv[])
+    __attribute__ ((weak, alias("ipconfig_main")));
+
+int ipconfig_main(int argc, char *argv[])
+{
+	struct netdev *dev;
+	int c, port;
+	int err;
+
+	/* If progname is set we're invoked from another program */
+	if (!progname) {
+		struct timeval now;
+		progname = argv[0];
+		gettimeofday(&now, NULL);
+		srand48(now.tv_usec ^ (now.tv_sec << 24));
+	}
+
+	if ((err = setjmp(abort_buf)))
+		return err;
+
+	/* Default vendor identifier */
+	set_vendor_identifier("Linux ipconfig");
+
+	do {
+		c = getopt(argc, argv, "c:d:i:onp:t:");
+		if (c == EOF)
+			break;
+
+		switch (c) {
+		case 'c':
+			default_caps = parse_proto(optarg);
+			break;
+		case 'p':
+			port = atoi(optarg);
+			if (port <= 0 || port > USHRT_MAX) {
+				fprintf(stderr,
+					"%s: invalid port number %d\n",
+					progname, port);
+				longjmp(abort_buf, 1);
+			}
+			cfg_local_port = port;
+			cfg_remote_port = cfg_local_port - 1;
+			break;
+		case 't':
+			loop_timeout = atoi(optarg);
+			if (loop_timeout < 0) {
+				fprintf(stderr,
+					"%s: invalid timeout %d\n",
+					progname, loop_timeout);
+				longjmp(abort_buf, 1);
+			}
+			break;
+		case 'i':
+			set_vendor_identifier(optarg);
+			break;
+		case 'o':
+			bringup_first = 1;
+			break;
+		case 'n':
+			do_not_config = 1;
+			break;
+		case 'd':
+			dev = add_device(optarg);
+			if (dev)
+				bringup_device(dev);
+			break;
+		case '?':
+			fprintf(stderr, "%s: invalid option -%c\n",
+				progname, optopt);
+			longjmp(abort_buf, 1);
+		}
+	} while (1);
+
+	for (c = optind; c < argc; c++) {
+		dev = add_device(argv[c]);
+		if (dev)
+			bringup_device(dev);
+	}
+
+	if (check_autoconfig()) {
+		if (cfg_local_port != LOCAL_PORT) {
+			printf("IP-Config: binding source port to %d, "
+			       "dest to %d\n", cfg_local_port, cfg_remote_port);
+		}
+		loop();
+	}
+
+	return 0;
+}
diff --git a/usr/kinit/ipconfig/netdev.c b/usr/kinit/ipconfig/netdev.c
new file mode 100644
index 0000000..35a920c
--- /dev/null
+++ b/usr/kinit/ipconfig/netdev.c
@@ -0,0 +1,249 @@
+/*
+ * ioctl-based device configuration
+ */
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/ioctl.h>
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <net/if.h>
+#include <net/if_arp.h>
+#include <netinet/in.h>
+#include <linux/route.h>
+
+#include "netdev.h"
+
+static int cfd = -1;
+
+static void copy_name(struct netdev *dev, struct ifreq *ifr)
+{
+	strncpy(ifr->ifr_name, dev->name, sizeof(ifr->ifr_name));
+	ifr->ifr_name[sizeof(ifr->ifr_name) - 1] = '\0';
+}
+
+int netdev_getflags(struct netdev *dev, short *flags)
+{
+	struct ifreq ifr;
+
+	copy_name(dev, &ifr);
+
+	if (ioctl(cfd, SIOCGIFFLAGS, &ifr) == -1) {
+		perror("SIOCGIFFLAGS");
+		return -1;
+	}
+
+	*flags = ifr.ifr_flags;
+	return 0;
+}
+
+static int netdev_sif_addr(struct ifreq *ifr, int cmd, uint32_t addr)
+{
+	struct sockaddr_in *sin = (struct sockaddr_in *)&ifr->ifr_addr;
+
+	sin->sin_family = AF_INET;
+	sin->sin_addr.s_addr = addr;
+
+	return ioctl(cfd, cmd, ifr);
+}
+
+int netdev_setaddress(struct netdev *dev)
+{
+	struct ifreq ifr;
+
+	copy_name(dev, &ifr);
+
+	if (dev->ip_addr != INADDR_ANY &&
+	    netdev_sif_addr(&ifr, SIOCSIFADDR, dev->ip_addr) == -1) {
+		perror("SIOCSIFADDR");
+		return -1;
+	}
+
+	if (dev->ip_broadcast != INADDR_ANY &&
+	    netdev_sif_addr(&ifr, SIOCSIFBRDADDR, dev->ip_broadcast) == -1) {
+		perror("SIOCSIFBRDADDR");
+		return -1;
+	}
+
+	if (dev->ip_netmask != INADDR_ANY &&
+	    netdev_sif_addr(&ifr, SIOCSIFNETMASK, dev->ip_netmask) == -1) {
+		perror("SIOCSIFNETMASK");
+		return -1;
+	}
+
+	return 0;
+}
+
+int netdev_setdefaultroute(struct netdev *dev)
+{
+	struct rtentry r;
+
+	if (dev->ip_gateway == INADDR_ANY)
+		return 0;
+
+	memset(&r, 0, sizeof(r));
+
+	((struct sockaddr_in *)&r.rt_dst)->sin_family = AF_INET;
+	((struct sockaddr_in *)&r.rt_dst)->sin_addr.s_addr = INADDR_ANY;
+	((struct sockaddr_in *)&r.rt_gateway)->sin_family = AF_INET;
+	((struct sockaddr_in *)&r.rt_gateway)->sin_addr.s_addr =
+	    dev->ip_gateway;
+	((struct sockaddr_in *)&r.rt_genmask)->sin_family = AF_INET;
+	((struct sockaddr_in *)&r.rt_genmask)->sin_addr.s_addr = INADDR_ANY;
+	r.rt_flags = RTF_UP | RTF_GATEWAY;
+
+	if (ioctl(cfd, SIOCADDRT, &r) == -1 && errno != EEXIST) {
+		perror("SIOCADDRT");
+		return -1;
+	}
+	return 0;
+}
+
+int netdev_setmtu(struct netdev *dev)
+{
+	struct ifreq ifr;
+
+	copy_name(dev, &ifr);
+	ifr.ifr_mtu = dev->mtu;
+
+	return ioctl(cfd, SIOCSIFMTU, &ifr);
+}
+
+static int netdev_gif_addr(struct ifreq *ifr, int cmd, uint32_t * ptr)
+{
+	struct sockaddr_in *sin = (struct sockaddr_in *)&ifr->ifr_addr;
+
+	if (ioctl(cfd, cmd, ifr) == -1)
+		return -1;
+
+	*ptr = sin->sin_addr.s_addr;
+
+	return 0;
+}
+
+int netdev_up(struct netdev *dev)
+{
+	struct ifreq ifr;
+
+	copy_name(dev, &ifr);
+
+	if (ioctl(cfd, SIOCGIFFLAGS, &ifr) == -1) {
+		perror("SIOCGIFFLAGS");
+		return -1;
+	}
+
+	ifr.ifr_flags |= IFF_UP;
+
+	if (ioctl(cfd, SIOCSIFFLAGS, &ifr) == -1) {
+		perror("SIOCSIFFLAGS");
+		return -1;
+	}
+	return 0;
+}
+
+int netdev_down(struct netdev *dev)
+{
+	struct ifreq ifr;
+
+	copy_name(dev, &ifr);
+
+	if (ioctl(cfd, SIOCGIFFLAGS, &ifr) == -1) {
+		perror("SIOCGIFFLAGS");
+		return -1;
+	}
+
+	ifr.ifr_flags &= ~IFF_UP;
+
+	if (ioctl(cfd, SIOCSIFFLAGS, &ifr) == -1) {
+		perror("SIOCSIFFLAGS");
+		return -1;
+	}
+	return 0;
+}
+
+int netdev_init_if(struct netdev *dev)
+{
+	struct ifreq ifr;
+
+	if (cfd == -1)
+		cfd = socket(AF_INET, SOCK_DGRAM, 0);
+	if (cfd == -1) {
+		fprintf(stderr, "ipconfig: %s: socket(AF_INET): %s\n",
+			dev->name, strerror(errno));
+		return -1;
+	}
+
+	copy_name(dev, &ifr);
+
+	if (ioctl(cfd, SIOCGIFINDEX, &ifr) == -1) {
+		fprintf(stderr, "ipconfig: %s: SIOCGIFINDEX: %s\n",
+			dev->name, strerror(errno));
+		return -1;
+	}
+
+	dev->ifindex = ifr.ifr_ifindex;
+
+	if (ioctl(cfd, SIOCGIFMTU, &ifr) == -1) {
+		fprintf(stderr, "ipconfig: %s: SIOCGIFMTU: %s\n",
+			dev->name, strerror(errno));
+		return -1;
+	}
+
+	dev->mtu = ifr.ifr_mtu;
+
+	if (ioctl(cfd, SIOCGIFHWADDR, &ifr) == -1) {
+		fprintf(stderr, "ipconfig: %s: SIOCGIFHWADDR: %s\n",
+			dev->name, strerror(errno));
+		return -1;
+	}
+
+	dev->hwtype = ifr.ifr_hwaddr.sa_family;
+	dev->hwlen  = 0;
+
+	switch (dev->hwtype) {
+	case ARPHRD_ETHER:
+		dev->hwlen = 6;
+		break;
+	case ARPHRD_EUI64:
+		dev->hwlen = 8;
+		break;
+	case ARPHRD_LOOPBACK:
+		dev->hwlen = 0;
+		break;
+	default:
+		return -1;
+	}
+
+	memcpy(dev->hwaddr, ifr.ifr_hwaddr.sa_data, dev->hwlen);
+	memset(dev->hwbrd, 0xff, dev->hwlen);
+
+	/*
+	 * Try to get the current interface information.
+	 */
+	if (dev->ip_addr == INADDR_NONE &&
+	    netdev_gif_addr(&ifr, SIOCGIFADDR, &dev->ip_addr) == -1) {
+		fprintf(stderr, "ipconfig: %s: SIOCGIFADDR: %s\n",
+			dev->name, strerror(errno));
+		dev->ip_addr = 0;
+		dev->ip_broadcast = 0;
+		dev->ip_netmask = 0;
+		return 0;
+	}
+
+	if (dev->ip_broadcast == INADDR_NONE &&
+	    netdev_gif_addr(&ifr, SIOCGIFBRDADDR, &dev->ip_broadcast) == -1) {
+		fprintf(stderr, "ipconfig: %s: SIOCGIFBRDADDR: %s\n",
+			dev->name, strerror(errno));
+		dev->ip_broadcast = 0;
+	}
+
+	if (dev->ip_netmask == INADDR_NONE &&
+	    netdev_gif_addr(&ifr, SIOCGIFNETMASK, &dev->ip_netmask) == -1) {
+		fprintf(stderr, "ipconfig: %s: SIOCGIFNETMASK: %s\n",
+			dev->name, strerror(errno));
+		dev->ip_netmask = 0;
+	}
+
+	return 0;
+}
diff --git a/usr/kinit/ipconfig/netdev.h b/usr/kinit/ipconfig/netdev.h
new file mode 100644
index 0000000..fb6640a
--- /dev/null
+++ b/usr/kinit/ipconfig/netdev.h
@@ -0,0 +1,81 @@
+#ifndef IPCONFIG_NETDEV_H
+#define IPCONFIG_NETDEV_H
+
+#include <sys/utsname.h>
+#include <net/if.h>
+
+#define BPLEN		40
+#define FNLEN		128			/* from DHCP  RFC 2131 */
+
+struct netdev {
+	const char *name;	/* Device name          */
+	unsigned int ifindex;	/* interface index      */
+	unsigned int hwtype;	/* ARPHRD_xxx           */
+	unsigned int hwlen;	/* HW address length    */
+	uint8_t hwaddr[16];	/* HW address           */
+	uint8_t hwbrd[16];	/* Broadcast HW address */
+	unsigned int mtu;	/* Device mtu           */
+	unsigned int caps;	/* Capabilities         */
+	time_t open_time;
+
+	struct {		/* BOOTP/DHCP info      */
+		int fd;
+		uint32_t xid;
+		uint32_t gateway; /* BOOTP/DHCP gateway   */
+	} bootp;
+
+	struct {		/* RARP information     */
+		int fd;
+	} rarp;
+
+	uint32_t ip_addr;	/* my address           */
+	uint32_t ip_broadcast;	/* broadcast address    */
+	uint32_t ip_server;	/* server address       */
+	uint32_t ip_netmask;	/* my subnet mask       */
+	uint32_t ip_gateway;	/* my gateway           */
+	uint32_t ip_nameserver[2];	/* two nameservers      */
+	uint32_t serverid;		/* dhcp serverid        */
+	char hostname[SYS_NMLN];	/* hostname             */
+	char dnsdomainname[SYS_NMLN];	/* dns domain name      */
+	char nisdomainname[SYS_NMLN];	/* nis domain name      */
+	char bootpath[BPLEN];	/* boot path            */
+	char filename[FNLEN];   /* filename             */
+	struct netdev *next;	/* next configured i/f  */
+};
+
+extern struct netdev *ifaces;
+
+/*
+ * Device capabilities
+ */
+#define CAP_BOOTP	(1<<0)
+#define CAP_DHCP	(1<<1)
+#define CAP_RARP	(1<<2)
+
+/*
+ * Device states
+ */
+#define DEVST_UP	0
+#define DEVST_BOOTP	1
+#define DEVST_DHCPDISC	2
+#define DEVST_DHCPREQ	3
+#define DEVST_COMPLETE	4
+#define DEVST_ERROR	5
+
+int netdev_getflags(struct netdev *dev, short *flags);
+int netdev_setaddress(struct netdev *dev);
+int netdev_setdefaultroute(struct netdev *dev);
+int netdev_up(struct netdev *dev);
+int netdev_down(struct netdev *dev);
+int netdev_init_if(struct netdev *dev);
+int netdev_setmtu(struct netdev *dev);
+
+static inline int netdev_running(struct netdev *dev)
+{
+	short flags;
+	int ret = netdev_getflags(dev, &flags);
+
+	return ret ? 0 : !!(flags & IFF_RUNNING);
+}
+
+#endif /* IPCONFIG_NETDEV_H */
diff --git a/usr/kinit/ipconfig/packet.c b/usr/kinit/ipconfig/packet.c
new file mode 100644
index 0000000..a75431d
--- /dev/null
+++ b/usr/kinit/ipconfig/packet.c
@@ -0,0 +1,284 @@
+/*
+ * Packet socket handling glue.
+ */
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <net/if_packet.h>
+#include <netinet/if_ether.h>
+#include <netinet/in.h>
+#include <netpacket/packet.h>
+#include <asm/byteorder.h>
+#include <arpa/inet.h>
+#include <netinet/ip.h>
+#include <netinet/udp.h>
+
+#include "ipconfig.h"
+#include "netdev.h"
+#include "packet.h"
+
+static int pkt_fd = -1;
+
+uint16_t cfg_local_port = LOCAL_PORT;
+uint16_t cfg_remote_port = REMOTE_PORT;
+
+int packet_open(void)
+{
+	int fd, one = 1;
+
+	if (pkt_fd != -1)
+		return pkt_fd;
+
+	/*
+	 * Get a PACKET socket for IP traffic.
+	 */
+	fd = socket(AF_PACKET, SOCK_DGRAM, htons(ETH_P_IP));
+	if (fd == -1) {
+		perror("socket");
+		return -1;
+	}
+
+	/*
+	 * We want to broadcast
+	 */
+	if (setsockopt(fd, SOL_SOCKET, SO_BROADCAST, &one, sizeof(one)) == -1) {
+		perror("SO_BROADCAST");
+		close(fd);
+		fd = -1;
+	}
+
+	pkt_fd = fd;
+
+	return fd;
+}
+
+void packet_close(void)
+{
+	close(pkt_fd);
+	pkt_fd = -1;
+}
+
+static unsigned int ip_checksum(uint16_t *hdr, int len)
+{
+	unsigned int chksum = 0;
+
+	while (len) {
+		chksum += *hdr++;
+		chksum += *hdr++;
+		len--;
+	}
+	chksum = (chksum & 0xffff) + (chksum >> 16);
+	chksum = (chksum & 0xffff) + (chksum >> 16);
+	return (~chksum) & 0xffff;
+}
+
+struct header {
+	struct iphdr ip;
+	struct udphdr udp;
+} __attribute__ ((packed));
+
+static struct header ipudp_hdrs = {
+	.ip = {
+	       .ihl		= 5,
+	       .version		= IPVERSION,
+	       .frag_off	= __constant_htons(IP_DF),
+	       .ttl		= 64,
+	       .protocol	= IPPROTO_UDP,
+	       .saddr		= INADDR_ANY,
+	       .daddr		= INADDR_BROADCAST,
+	       },
+	.udp = {
+		.source		= __constant_htons(LOCAL_PORT),
+		.dest		= __constant_htons(REMOTE_PORT),
+		.len		= 0,
+		.check		= 0,
+		},
+};
+
+#ifdef IPC_DEBUG		/* Only used by DEBUG(()) */
+static char *ntoa(uint32_t addr)
+{
+	struct in_addr in = { addr };
+	return inet_ntoa(in);
+}
+#endif
+
+/*
+ * Send a packet.  The options are listed in iov[1...iov_len].
+ * iov[0] is reserved for the bootp packet header.
+ */
+int packet_send(struct netdev *dev, struct iovec *iov, int iov_len)
+{
+	struct sockaddr_ll sll;
+	struct msghdr msg = {
+		.msg_name	= &sll,
+		.msg_namelen	= sizeof(sll),
+		.msg_iov	= iov,
+		.msg_iovlen	= iov_len,
+		.msg_control	= NULL,
+		.msg_controllen	= 0,
+		.msg_flags	= 0
+	};
+	int i, len = 0;
+
+	if (cfg_local_port != LOCAL_PORT) {
+		ipudp_hdrs.udp.source = htons(cfg_local_port);
+		ipudp_hdrs.udp.dest = htons(cfg_remote_port);
+	}
+
+	DEBUG(("\n   udp src %d dst %d", ntohs(ipudp_hdrs.udp.source),
+	       ntohs(ipudp_hdrs.udp.dest)));
+
+	DEBUG(("\n   ip src %s ", ntoa(ipudp_hdrs.ip.saddr)));
+	DEBUG(("dst %s ", ntoa(ipudp_hdrs.ip.daddr)));
+
+	/*
+	 * Glue in the ip+udp header iovec
+	 */
+	iov[0].iov_base = &ipudp_hdrs;
+	iov[0].iov_len = sizeof(struct header);
+
+	for (i = 0; i < iov_len; i++)
+		len += iov[i].iov_len;
+
+	sll.sll_family	 = AF_PACKET;
+	sll.sll_protocol = htons(ETH_P_IP);
+	sll.sll_ifindex	 = dev->ifindex;
+	sll.sll_hatype	 = dev->hwtype;
+	sll.sll_pkttype	 = PACKET_BROADCAST;
+	sll.sll_halen	 = dev->hwlen;
+	memcpy(sll.sll_addr, dev->hwbrd, dev->hwlen);
+
+	ipudp_hdrs.ip.tot_len = htons(len);
+	ipudp_hdrs.ip.check   = 0;
+	ipudp_hdrs.ip.check   = ip_checksum((uint16_t *) & ipudp_hdrs.ip,
+					    ipudp_hdrs.ip.ihl);
+
+	ipudp_hdrs.udp.len    = htons(len - sizeof(struct iphdr));
+
+	DEBUG(("\n   bytes %d\n", len));
+
+	return sendmsg(pkt_fd, &msg, 0);
+}
+
+int packet_peek(int *ifindex)
+{
+	struct sockaddr_ll sll;
+	struct iphdr iph;
+	int ret, sllen = sizeof(struct sockaddr_ll);
+
+	/*
+	 * Peek at the IP header.
+	 */
+	ret = recvfrom(pkt_fd, &iph, sizeof(struct iphdr),
+		       MSG_PEEK, (struct sockaddr *)&sll, &sllen);
+	if (ret == -1)
+		return -1;
+
+	if (sll.sll_family != AF_PACKET)
+		goto discard_pkt;
+
+	if (iph.ihl < 5 || iph.version != IPVERSION)
+		goto discard_pkt;
+
+	*ifindex = sll.sll_ifindex;
+
+	return 0;
+
+discard_pkt:
+	packet_discard();
+	return 0;
+}
+
+void packet_discard(void)
+{
+	struct iphdr iph;
+	struct sockaddr_ll sll;
+	socklen_t sllen = sizeof(sll);
+
+	recvfrom(pkt_fd, &iph, sizeof(iph), 0, (struct sockaddr *)&sll, &sllen);
+}
+
+/*
+ * Receive a bootp packet.  The options are listed in iov[1...iov_len].
+ * iov[0] must point to the bootp packet header.
+ */
+int packet_recv(struct iovec *iov, int iov_len)
+{
+	struct iphdr *ip, iph;
+	struct udphdr *udp;
+	struct msghdr msg = {
+		.msg_name	= NULL,
+		.msg_namelen	= 0,
+		.msg_iov	= iov,
+		.msg_iovlen	= iov_len,
+		.msg_control	= NULL,
+		.msg_controllen = 0,
+		.msg_flags	= 0
+	};
+	int ret, iphl;
+
+	ret = recvfrom(pkt_fd, &iph, sizeof(struct iphdr),
+		       MSG_PEEK, NULL, NULL);
+	if (ret == -1)
+		return -1;
+
+	if (iph.ihl < 5 || iph.version != IPVERSION)
+		goto discard_pkt;
+
+	iphl = iph.ihl * 4;
+
+	ip = malloc(iphl + sizeof(struct udphdr));
+	if (!ip)
+		goto discard_pkt;
+
+	udp = (struct udphdr *)((char *)ip + iphl);
+
+	iov[0].iov_base = ip;
+	iov[0].iov_len = iphl + sizeof(struct udphdr);
+
+	ret = recvmsg(pkt_fd, &msg, 0);
+	if (ret == -1)
+		goto free_pkt;
+
+	DEBUG(("<- bytes %d ", ret));
+
+	if (ip_checksum((uint16_t *) ip, ip->ihl) != 0)
+		goto free_pkt;
+
+	DEBUG(("\n   ip src %s ", ntoa(ip->saddr)));
+	DEBUG(("dst %s ", ntoa(ip->daddr)));
+
+	if (ntohs(ip->tot_len) > ret || ip->protocol != IPPROTO_UDP)
+		goto free_pkt;
+
+	ret -= 4 * ip->ihl;
+
+	DEBUG(("\n   udp src %d dst %d ", ntohs(udp->source),
+	       ntohs(udp->dest)));
+
+	if (udp->source != htons(cfg_remote_port) ||
+	    udp->dest != htons(cfg_local_port))
+		goto free_pkt;
+
+	if (ntohs(udp->len) > ret)
+		goto free_pkt;
+
+	ret -= sizeof(struct udphdr);
+
+	free(ip);
+
+	return ret;
+
+free_pkt:
+	free(ip);
+	return 0;
+
+discard_pkt:
+	DEBUG(("discarded\n"));
+	packet_discard();
+	return 0;
+}
diff --git a/usr/kinit/ipconfig/packet.h b/usr/kinit/ipconfig/packet.h
new file mode 100644
index 0000000..6e545b5
--- /dev/null
+++ b/usr/kinit/ipconfig/packet.h
@@ -0,0 +1,11 @@
+#ifndef IPCONFIG_PACKET_H
+#define IPCONFIG_PACKET_H
+
+int packet_open(void);
+void packet_close(void);
+int packet_send(struct netdev *dev, struct iovec *iov, int iov_len);
+int packet_peek(int *ifindex);
+void packet_discard(void);
+int packet_recv(struct iovec *iov, int iov_len);
+
+#endif /* IPCONFIG_PACKET_H */
diff --git a/usr/kinit/kinit.c b/usr/kinit/kinit.c
new file mode 100644
index 0000000..7c33718
--- /dev/null
+++ b/usr/kinit/kinit.c
@@ -0,0 +1,333 @@
+#include <sys/mount.h>
+#include <sys/stat.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <alloca.h>
+#include <limits.h>
+#include <ctype.h>
+#include <termios.h>
+
+#include "kinit.h"
+#include "ipconfig.h"
+#include "run-init.h"
+#include "resume.h"
+
+const char *progname = "kinit";
+int mnt_procfs;
+int mnt_sysfs;
+
+#ifdef INI_DEBUG
+void dump_args(int argc, char *argv[])
+{
+	int i;
+
+	printf("  argc == %d\n", argc);
+
+	for (i = 0; i < argc; i++) {
+		printf("  argv[%d]: \"%s\"\n", i, argv[i]);
+	}
+
+	if (argv[argc] != NULL) {
+		printf("  argv[%d]: \"%s\" (SHOULD BE NULL)\n",
+		       argc, argv[argc]);
+	}
+}
+#endif
+
+
+static int do_ipconfig(int argc, char *argv[])
+{
+	int i, a = 0;
+	char **args = alloca((argc + 3) * sizeof(char *));
+
+	if (!args)
+		return -1;
+
+	args[a++] = (char *)"IP-Config";
+	args[a++] = (char *)"-i";
+	args[a++] = (char *)"Linux kinit";
+
+	DEBUG(("Running ipconfig\n"));
+
+	for (i = 1; i < argc; i++) {
+		if (strncmp(argv[i], "ip=", 3) == 0 ||
+		    strncmp(argv[i], "nfsaddrs=", 9) == 0) {
+			args[a++] = argv[i];
+		}
+	}
+
+	if (a > 1) {
+		args[a] = NULL;
+		dump_args(a, args);
+		return ipconfig_main(a, args);
+	}
+
+	return 0;
+}
+
+static int split_cmdline(int cmdcmax, char *cmdv[], char *argv0,
+			 char *cmdlines[], char *args[])
+{
+	int was_space;
+	char c, *p;
+	int vmax = cmdcmax;
+	int v = 1;
+	int space;
+
+	if (cmdv)
+		cmdv[0] = argv0;
+
+	/* First, add the parsable command lines */
+
+	while (*cmdlines) {
+		p = *cmdlines++;
+		was_space = 1;
+		while (v < vmax) {
+			c = *p;
+			space = isspace(c);
+			if ((space || !c) && !was_space) {
+				if (cmdv)
+					*p = '\0';
+				v++;
+			} else if (was_space) {
+				if (cmdv)
+					cmdv[v] = p;
+			}
+
+			if (!c)
+				break;
+
+			was_space = space;
+			p++;
+		}
+	}
+
+	/* Second, add the explicit command line arguments */
+
+	while (*args && v < vmax) {
+		if (cmdv)
+			cmdv[v] = *args;
+		v++;
+		args++;
+	}
+
+	if (cmdv)
+		cmdv[v] = NULL;
+
+	return v;
+}
+
+static int mount_sys_fs(const char *check, const char *fsname,
+			const char *fstype)
+{
+	struct stat st;
+
+	if (stat(check, &st) == 0) {
+		return 0;
+	}
+
+	mkdir(fsname, 0555);
+
+	if (mount("none", fsname, fstype, 0, NULL) == -1) {
+		fprintf(stderr, "%s: could not mount %s as %s\n",
+			progname, fsname, fstype);
+		return -1;
+	}
+
+	return 1;
+}
+
+static void check_path(const char *path)
+{
+	struct stat st;
+
+	if (stat(path, &st) == -1) {
+		if (errno != ENOENT) {
+			perror("stat");
+			exit(1);
+		}
+		if (mkdir(path, 0755) == -1) {
+			perror("mkdir");
+			exit(1);
+		}
+	} else if (!S_ISDIR(st.st_mode)) {
+		fprintf(stderr, "%s: '%s' not a directory\n", progname, path);
+		exit(1);
+	}
+}
+
+static const char *find_init(const char *root, const char *user)
+{
+	const char *init_paths[] = {
+		"/sbin/init", "/bin/init", "/etc/init", "/bin/sh", NULL
+	};
+	const char **p;
+	const char *path;
+
+	if (chdir(root)) {
+		perror("chdir");
+		exit(1);
+	}
+
+	if (user)
+		DEBUG(("Checking for init: %s\n", user));
+
+	if (user && user[0] == '/' && !access(user+1, X_OK)) {
+		path = user;
+	} else {
+		for (p = init_paths; *p; p++) {
+			DEBUG(("Checking for init: %s\n", *p));
+			if (!access(*p+1, X_OK))
+				break;
+		}
+		path = *p;
+	}
+	chdir("/");
+	return path;
+}
+
+/* This is the argc and argv we pass to init */
+const char *init_path;
+int init_argc;
+char **init_argv;
+
+extern ssize_t readfile(const char *, char **);
+
+int main(int argc, char *argv[])
+{
+	char **cmdv, **args;
+	char *cmdlines[3];
+	int i;
+	const char *errmsg;
+	int ret = 0;
+	int cmdc;
+	int fd;
+	struct timeval now;
+
+	gettimeofday(&now, NULL);
+	srand48(now.tv_usec ^ (now.tv_sec << 24));
+
+	/* Default parameters for anything init-like we execute */
+	init_argc = argc;
+	init_argv = alloca((argc+1)*sizeof(char *));
+	memcpy(init_argv, argv, (argc+1)*sizeof(char *));
+
+	if ((fd = open("/dev/console", O_RDWR)) != -1) {
+		dup2(fd, STDIN_FILENO);
+		dup2(fd, STDOUT_FILENO);
+		dup2(fd, STDERR_FILENO);
+
+		if (fd > STDERR_FILENO) {
+			close(fd);
+		}
+	}
+
+	mnt_procfs = mount_sys_fs("/proc/cmdline", "/proc", "proc") >= 0;
+	if (!mnt_procfs) {
+		ret = 1;
+		goto bail;
+	}
+
+	mnt_sysfs = mount_sys_fs("/sys/bus", "/sys", "sysfs") >= 0;
+	if (!mnt_sysfs) {
+		ret = 1;
+		goto bail;
+	}
+
+	/* Construct the effective kernel command line.  The
+	   effective kernel command line consists of /arch.cmd, if
+	   it exists, /proc/cmdline, plus any arguments after an --
+	   argument on the proper command line, in that order. */
+
+	ret = readfile("/arch.cmd", &cmdlines[0]);
+	if (ret < 0)
+		cmdlines[0] = "";
+
+	ret = readfile("/proc/cmdline", &cmdlines[1]);
+	if (ret < 0) {
+		fprintf(stderr, "%s: cannot read /proc/cmdline\n", progname);
+		ret = 1;
+		goto bail;
+	}
+
+	cmdlines[2] = NULL;
+
+	/* Find an -- argument, and if so append to the command line */
+	for (i = 1; i < argc; i++) {
+		if (!strcmp(argv[i], "--")) {
+			i++;
+			break;
+		}
+	}
+	args = &argv[i];	/* Points either to first argument past -- or
+				   to the final NULL */
+
+	/* Count the number of arguments */
+	cmdc = split_cmdline(INT_MAX, NULL, argv[0], cmdlines, args);
+
+	/* Actually generate the cmdline array */
+	cmdv = (char **)alloca((cmdc+1)*sizeof(char *));
+	if (split_cmdline(cmdc, cmdv, argv[0], cmdlines, args) != cmdc) {
+		ret = 1;
+		goto bail;
+	}
+
+	/* Debugging... */
+	dump_args(cmdc, cmdv);
+
+	/* Resume from suspend-to-disk, if appropriate */
+	/* If successful, does not return */
+	do_resume(cmdc, cmdv);
+
+	/* Initialize networking, if applicable */
+	do_ipconfig(cmdc, cmdv);
+
+	check_path("/root");
+	do_mounts(cmdc, cmdv);
+
+	if (mnt_procfs) {
+		umount2("/proc", 0);
+		mnt_procfs = 0;
+	}
+
+	if (mnt_sysfs) {
+		umount2("/sys", 0);
+		mnt_sysfs = 0;
+	}
+
+	init_path = find_init("/root", get_arg(cmdc, cmdv, "init="));
+	if (!init_path) {
+		fprintf(stderr, "%s: init not found!\n", progname);
+		ret = 2;
+		goto bail;
+	}
+
+	init_argv[0] = strrchr(init_path, '/') + 1;
+
+	errmsg = run_init("/root", "/dev/console", init_path, init_argv);
+
+	/* If run_init returned, something went bad */
+	fprintf(stderr, "%s: %s: %s\n", progname, errmsg, strerror(errno));
+	ret = 2;
+	goto bail;
+
+bail:
+	if (mnt_procfs)
+		umount2("/proc", 0);
+
+	if (mnt_sysfs)
+		umount2("/sys", 0);
+
+	/*
+	 * If we get here, something bad probably happened, and the kernel
+	 * will most likely panic.  Drain console output so the user can
+	 * figure out what happened.
+	 */
+	tcdrain(2);
+	tcdrain(1);
+
+	return ret;
+}
diff --git a/usr/kinit/kinit.h b/usr/kinit/kinit.h
new file mode 100644
index 0000000..895f920
--- /dev/null
+++ b/usr/kinit/kinit.h
@@ -0,0 +1,70 @@
+/*
+ * kinit/kinit.h
+ */
+
+#ifndef KINIT_H
+#define KINIT_H
+
+#include <stddef.h>
+#include <stdio.h>
+#include <sys/types.h>
+
+int do_mounts(int argc, char *argv[]);
+int mount_nfs_root(int argc, char *argv[], int flags);
+int ramdisk_load(int argc, char *argv[], dev_t root_dev);
+void md_run(int argc, char *argv[]);
+const char *bdevname(dev_t dev);
+
+extern int mnt_procfs;
+extern int mnt_sysfs;
+
+extern int init_argc;
+extern char **init_argv;
+extern const char *progname;
+
+char *get_arg(int argc, char *argv[], const char *name);
+int get_flag(int argc, char *argv[], const char *name);
+
+int getintfile(const char *path, long *val);
+
+ssize_t readfile(const char *path, char **pptr);
+ssize_t freadfile(FILE *f, char **pptr);
+
+/*
+ * min()/max() macros that also do
+ * strict type-checking.. See the
+ * "unnecessary" pointer comparison.
+ * From the Linux kernel.
+ */
+#define min(x,y) ({ \
+        typeof(x) _x = (x);     \
+        typeof(y) _y = (y);     \
+        (void) (&_x == &_y);            \
+        _x < _y ? _x : _y; })
+
+#define max(x,y) ({ \
+        typeof(x) _x = (x);     \
+        typeof(y) _y = (y);     \
+        (void) (&_x == &_y);            \
+        _x > _y ? _x : _y; })
+
+#define INI_DEBUG
+
+#undef DEBUG
+#ifdef INI_DEBUG
+#define DEBUG(x) printf x
+#else
+#define DEBUG(x) do { } while (0)
+#endif
+
+#ifdef INI_DEBUG
+void dump_args(int argc, char *argv[]);
+#else
+static inline void dump_args(int argc, char *argv[])
+{
+	(void)argc;
+	(void)argv;
+}
+#endif
+
+#endif				/* KINIT_H */
diff --git a/usr/kinit/name_to_dev.c b/usr/kinit/name_to_dev.c
new file mode 100644
index 0000000..593bc12
--- /dev/null
+++ b/usr/kinit/name_to_dev.c
@@ -0,0 +1,202 @@
+#include <ctype.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <alloca.h>
+#include <inttypes.h>
+
+#include "do_mounts.h"
+#include "kinit.h"
+
+#define BUF_SZ		65536
+
+/* Find dev_t for e.g. "hda,NULL" or "hdb,2" */
+static dev_t try_name(char *name, int part)
+{
+	char path[BUF_SZ];
+	char buf[BUF_SZ];
+	int range;
+	unsigned int major, minor;
+	dev_t res;
+	char *s;
+	int len;
+	int fd;
+
+	/* read device number from /sys/block/.../dev */
+	snprintf(path, sizeof(path), "/sys/block/%s/dev", name);
+	fd = open(path, 0, 0);
+	if (fd < 0)
+		goto fail;
+	len = read(fd, buf, BUF_SZ);
+	close(fd);
+
+	if (len <= 0 || len == BUF_SZ || buf[len - 1] != '\n')
+		goto fail;
+	buf[len - 1] = '\0';
+	major = strtoul(buf, &s, 10);
+	if (*s != ':')
+		goto fail;
+	minor = strtoul(s + 1, &s, 10);
+	if (*s)
+		goto fail;
+	res = makedev(major, minor);
+
+	/* if it's there and we are not looking for a partition - that's it */
+	if (!part)
+		return res;
+
+	/* otherwise read range from .../range */
+	snprintf(path, sizeof(path), "/sys/block/%s/range", name);
+	fd = open(path, 0, 0);
+	if (fd < 0)
+		goto fail;
+	len = read(fd, buf, 32);
+	close(fd);
+	if (len <= 0 || len == 32 || buf[len - 1] != '\n')
+		goto fail;
+	buf[len - 1] = '\0';
+	range = strtoul(buf, &s, 10);
+	if (*s)
+		goto fail;
+
+	/* if partition is within range - we got it */
+	if (part < range) {
+		DEBUG(("kinit: try_name %s,%d = %s\n", name, part,
+		       bdevname(res + part)));
+		return res + part;
+	}
+
+      fail:
+	return (dev_t) 0;
+}
+
+/*
+ *	Convert a name into device number.  We accept the following variants:
+ *
+ *	1) device number in hexadecimal	represents itself
+ *	2) device number in major:minor decimal represents itself
+ *	3) /dev/nfs represents Root_NFS
+ *	4) /dev/<disk_name> represents the device number of disk
+ *	5) /dev/<disk_name><decimal> represents the device number
+ *         of partition - device number of disk plus the partition number
+ *	6) /dev/<disk_name>p<decimal> - same as the above, that form is
+ *	   used when disk name of partitioned disk ends on a digit.
+ *	7) an actual block device node in the initramfs filesystem
+ *
+ *	If name doesn't have fall into the categories above, we return 0.
+ *	Driverfs is used to check if something is a disk name - it has
+ *	all known disks under bus/block/devices.  If the disk name
+ *	contains slashes, name of driverfs node has them replaced with
+ *	dots.  try_name() does the actual checks, assuming that driverfs
+ *	is mounted on rootfs /sys.
+ */
+
+static inline dev_t name_to_dev_t_real(const char *name)
+{
+	char *p;
+	dev_t res = 0;
+	char *s;
+	int part;
+	struct stat st;
+	int len;
+	const char *devname;
+	char *cptr, *e1, *e2;
+	int major, minor;
+
+
+	if (name[0] == '/') {
+		devname = name;
+	} else {
+		char *dname = alloca(strlen(name) + 6);
+		sprintf(dname, "/dev/%s", name);
+		devname = dname;
+	}
+
+	if (!stat(devname, &st) && S_ISBLK(st.st_mode))
+		return st.st_rdev;
+
+	if (strncmp(name, "/dev/", 5)) {
+		if ((cptr = strchr(devname+5, ':')) &&
+		    cptr[1] != '\0') {
+			/* Colon-separated decimal device number */
+			*cptr = '\0';
+			major = strtoul(devname+5, &e1, 10);
+			minor = strtoul(cptr+1, &e2, 10);
+			if (!*e1 && !*e2)
+				return makedev(major, minor);
+			*cptr = ':';
+		} else {
+			/* Hexadecimal device number */
+			res = (dev_t) strtoul(name, &p, 16);
+			if (!*p)
+				return res;
+		}
+	} else {
+		name += 5;
+	}
+
+	if (!strcmp(name, "nfs"))
+		return Root_NFS;
+
+	if (!strcmp(name, "ram")) /* /dev/ram - historic alias for /dev/ram0 */
+		return Root_RAM0;
+
+	if (!strncmp(name, "mtd", 3))
+		return Root_MTD;
+
+	len = strlen(name);
+	s = alloca(len + 1);
+	memcpy(s, name, len + 1);
+
+	for (p = s; *p; p++)
+		if (*p == '/')
+			*p = '!';
+	res = try_name(s, 0);
+	if (res)
+		return res;
+
+	while (p > s && isdigit(p[-1]))
+		p--;
+	if (p == s || !*p || *p == '0')
+		goto fail;
+	part = strtoul(p, NULL, 10);
+	*p = '\0';
+	res = try_name(s, part);
+	if (res)
+		return res;
+
+	if (p < s + 2 || !isdigit(p[-2]) || p[-1] != 'p')
+		goto fail;
+	p[-1] = '\0';
+	res = try_name(s, part);
+	return res;
+
+fail:
+	return (dev_t) 0;
+}
+
+dev_t name_to_dev_t(const char *name)
+{
+	dev_t dev = name_to_dev_t_real(name);
+
+	DEBUG(("kinit: name_to_dev_t(%s) = %s\n", name, bdevname(dev)));
+	return dev;
+}
+
+#ifdef TEST_NAMETODEV		/* Standalone test */
+
+int main(int argc, char *argv[])
+{
+	int i;
+
+	for (i = 1; i < argc; i++)
+		name_to_dev_t(argv[i]);
+
+	return 0;
+}
+
+#endif
diff --git a/usr/kinit/nfsmount/Kbuild b/usr/kinit/nfsmount/Kbuild
new file mode 100644
index 0000000..461e6f3
--- /dev/null
+++ b/usr/kinit/nfsmount/Kbuild
@@ -0,0 +1,27 @@
+#
+# kbuild file for nfsmount
+#
+
+static-y := static/nfsmount
+#FIXME - build is broken static-y := dummypmap
+shared-y := shared/nfsmount
+
+objs := main.o mount.o portmap.o dummypmap.o sunrpc.o
+
+# Create built-in.o with all .o files (used by kinit)
+lib-y := $(objs)
+
+# .o files used for executables
+static/nfsmount-y := $(objs)
+shared/nfsmount-y := $(objs)
+
+# dummypmap uses a single .o file (rename src file?)
+dummypmap-y := dummypmap_test.o
+
+# TODO - do we want a stripped version
+# TODO - do we want the static.g + shared.g directories?
+
+clean-dirs := static shared
+
+# Install binary
+install-y := $(shared-y)
diff --git a/usr/kinit/nfsmount/README.locking b/usr/kinit/nfsmount/README.locking
new file mode 100644
index 0000000..bf2e8e7
--- /dev/null
+++ b/usr/kinit/nfsmount/README.locking
@@ -0,0 +1,26 @@
+I have implemented portmap spoofing in klibc nfsmount (released as
+klibc-0.144) This is basically a vestigial portmap daemon which gets
+launched before the mount() call and then just records any
+transactions it gets to a file and sends back an affirmative reply.
+
+There are two ways to use it (this belongs in a README file, but it's
+too late at night right now):
+
+a) Set a fixed portnumber in /proc/sys/nfs/nlm_tcpport and
+/proc/sys/nfs/nlm_udpport before calling nfsmount; once the portmapper
+starts feed that fixed portnumber to pmap_set(8).  In this case the
+pmap_file can be /dev/null.
+
+b) Allow the kernel to bind to any port and use the file produced by
+nfsroot to feed to pmap_set (it should be directly compatible); this
+means the file needs to be transferred to a place where the "real
+root" can find it before run-init.
+
+In either case, it is imperative that the real portmapper is launched
+before any program actually tries to create locks!
+
+To use it:
+
+	# We need the loopback device to be up before we do this!
+	ipconfig 127.0.0.1:::::lo:none
+	nfsroot -p pmap_file -o lock server:/pathname /realpath
diff --git a/usr/kinit/nfsmount/dummypmap.c b/usr/kinit/nfsmount/dummypmap.c
new file mode 100644
index 0000000..5ee2406
--- /dev/null
+++ b/usr/kinit/nfsmount/dummypmap.c
@@ -0,0 +1,186 @@
+/*
+ * Enough portmapper functionality that mount doesn't hang trying
+ * to start lockd.  Enables nfsroot with locking functionality.
+ *
+ * Note: the kernel will only speak to the local portmapper
+ * using RPC over UDP.
+ */
+
+#include <sys/types.h>
+#include <netinet/in.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <unistd.h>
+#include <string.h>
+#include <sys/socket.h>
+
+#include "sunrpc.h"
+
+extern const char *progname;
+
+struct portmap_call {
+	struct rpc_call rpc;
+	uint32_t program;
+	uint32_t version;
+	uint32_t proto;
+	uint32_t port;
+};
+
+struct portmap_reply {
+	struct rpc_reply rpc;
+	uint32_t port;
+};
+
+static int bind_portmap(void)
+{
+	int sock = socket(PF_INET, SOCK_DGRAM, 0);
+	struct sockaddr_in sin;
+
+	if (sock < 0)
+		return -1;
+
+	memset(&sin, 0, sizeof sin);
+	sin.sin_family = AF_INET;
+	sin.sin_addr.s_addr = htonl(0x7f000001);	/* 127.0.0.1 */
+	sin.sin_port = htons(RPC_PMAP_PORT);
+	if (bind(sock, (struct sockaddr *)&sin, sizeof sin) < 0) {
+		int err = errno;
+		close(sock);
+		errno = err;
+		return -1;
+	}
+
+	return sock;
+}
+
+static const char *protoname(uint32_t proto)
+{
+	switch (ntohl(proto)) {
+	case IPPROTO_TCP:
+		return "tcp";
+	case IPPROTO_UDP:
+		return "udp";
+	default:
+		return NULL;
+	}
+}
+
+static int dummy_portmap(int sock, FILE *portmap_file)
+{
+	struct sockaddr_in sin;
+	int pktlen, addrlen;
+	union {
+		struct portmap_call c;
+		unsigned char b[65536];	/* Max UDP packet size */
+	} pkt;
+	struct portmap_reply rply;
+
+	for (;;) {
+		addrlen = sizeof sin;
+		pktlen = recvfrom(sock, &pkt.c.rpc.hdr.udp, sizeof pkt, 0,
+				  (struct sockaddr *)&sin, &addrlen);
+
+		if (pktlen < 0) {
+			if (errno == EINTR)
+				continue;
+
+			return -1;
+		}
+
+		/* +4 to skip the TCP fragment header */
+		if (pktlen + 4 < sizeof(struct portmap_call))
+			continue;	/* Bad packet */
+
+		if (pkt.c.rpc.hdr.udp.msg_type != htonl(RPC_CALL))
+			continue;	/* Bad packet */
+
+		memset(&rply, 0, sizeof rply);
+
+		rply.rpc.hdr.udp.xid = pkt.c.rpc.hdr.udp.xid;
+		rply.rpc.hdr.udp.msg_type = htonl(RPC_REPLY);
+
+		if (pkt.c.rpc.rpc_vers != htonl(2)) {
+			rply.rpc.reply_state = htonl(REPLY_DENIED);
+			/* state <- RPC_MISMATCH == 0 */
+		} else if (pkt.c.rpc.program != htonl(PORTMAP_PROGRAM)) {
+			rply.rpc.reply_state = htonl(PROG_UNAVAIL);
+		} else if (pkt.c.rpc.prog_vers != htonl(2)) {
+			rply.rpc.reply_state = htonl(PROG_MISMATCH);
+		} else if (pkt.c.rpc.cred_len != 0 || pkt.c.rpc.vrf_len != 0) {
+			/* Can't deal with credentials data; the kernel
+			   won't send them */
+			rply.rpc.reply_state = htonl(SYSTEM_ERR);
+		} else {
+			switch (ntohl(pkt.c.rpc.proc)) {
+			case PMAP_PROC_NULL:
+				break;
+			case PMAP_PROC_SET:
+				if (pkt.c.proto == htonl(IPPROTO_TCP) ||
+				    pkt.c.proto == htonl(IPPROTO_UDP)) {
+					if (portmap_file)
+						fprintf(portmap_file,
+							"%u %u %s %u\n",
+							ntohl(pkt.c.program),
+							ntohl(pkt.c.version),
+							protoname(pkt.c.proto),
+							ntohl(pkt.c.port));
+					rply.port = htonl(1);	/* TRUE = success */
+				}
+				break;
+			case PMAP_PROC_UNSET:
+				rply.port = htonl(1);	/* TRUE = success */
+				break;
+			case PMAP_PROC_GETPORT:
+				break;
+			case PMAP_PROC_DUMP:
+				break;
+			default:
+				rply.rpc.reply_state = htonl(PROC_UNAVAIL);
+				break;
+			}
+		}
+
+		sendto(sock, &rply.rpc.hdr.udp, sizeof rply - 4, 0,
+		       (struct sockaddr *)&sin, addrlen);
+	}
+}
+
+pid_t start_dummy_portmap(const char *file)
+{
+	FILE *portmap_filep;
+	int sock;
+	pid_t spoof_portmap;
+
+	portmap_filep = fopen(file, "w");
+	if (!portmap_filep) {
+		fprintf(stderr, "%s: cannot write portmap file: %s\n",
+			progname, file);
+		return -1;
+	}
+
+	sock = bind_portmap();
+	if (sock == -1) {
+		if (errno == EINVAL || errno == EADDRINUSE)
+			return 0;	/* Assume not needed */
+		else {
+			fprintf(stderr, "%s: portmap spoofing failed\n",
+				progname);
+			return -1;
+		}
+	}
+
+	spoof_portmap = fork();
+	if (spoof_portmap == -1) {
+		fprintf(stderr, "%s: cannot fork\n", progname);
+		return -1;
+	} else if (spoof_portmap == 0) {
+		/* Child process */
+		dummy_portmap(sock, portmap_filep);
+		_exit(255);	/* Error */
+	} else {
+		/* Parent process */
+		close(sock);
+		return spoof_portmap;
+	}
+}
diff --git a/usr/kinit/nfsmount/dummypmap.h b/usr/kinit/nfsmount/dummypmap.h
new file mode 100644
index 0000000..37650bf
--- /dev/null
+++ b/usr/kinit/nfsmount/dummypmap.h
@@ -0,0 +1,11 @@
+/*
+ * Functions for the portmap spoofer
+ */
+
+#ifndef NFSMOUNT_DUMMYPORTMAP_H
+#define NFSMOUNT_DUMMYPORTMAP_H
+
+#include <unistd.h>
+pid_t start_dummy_portmap(const char *file);
+
+#endif /* NFSMOUNT_DUMMYPORTMAP_H */
diff --git a/usr/kinit/nfsmount/dummypmap_test.c b/usr/kinit/nfsmount/dummypmap_test.c
new file mode 100644
index 0000000..d81a141
--- /dev/null
+++ b/usr/kinit/nfsmount/dummypmap_test.c
@@ -0,0 +1,2 @@
+#define TEST
+#include "dummypmap.c"
diff --git a/usr/kinit/nfsmount/main.c b/usr/kinit/nfsmount/main.c
new file mode 100644
index 0000000..2e2eec7
--- /dev/null
+++ b/usr/kinit/nfsmount/main.c
@@ -0,0 +1,259 @@
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <arpa/inet.h>
+#include <limits.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <signal.h>
+#include <setjmp.h>
+#include <sys/wait.h>
+#include <unistd.h>
+#include <klibc/sysconfig.h>	/* For _KLIBC_NO_MMU */
+
+#include <linux/nfs_mount.h>
+
+#include "nfsmount.h"
+#include "sunrpc.h"
+#include "dummypmap.h"
+
+const char *progname;
+static jmp_buf abort_buf;
+
+static struct nfs_mount_data mount_data = {
+	.version	= NFS_MOUNT_VERSION,
+	.flags		= NFS_MOUNT_NONLM | NFS_MOUNT_VER3 | NFS_MOUNT_TCP,
+	.rsize		= 0,	/* Server's choice */
+	.wsize		= 0,	/* Server's choice */
+	.timeo		= 7,
+	.retrans	= 3,
+	.acregmin	= 3,
+	.acregmax	= 60,
+	.acdirmin	= 30,
+	.acdirmax	= 60,
+	.namlen		= NAME_MAX,
+};
+
+int nfs_port;
+
+static struct int_opts {
+	char *name;
+	int *val;
+} int_opts[] = {
+	{"port",	&nfs_port},
+	{"rsize",	&mount_data.rsize},
+	{"wsize",	&mount_data.wsize},
+	{"timeo",	&mount_data.timeo},
+	{"retrans",	&mount_data.retrans},
+	{"acregmin",	&mount_data.acregmin},
+	{"acregmax",	&mount_data.acregmax},
+	{"acdirmin",	&mount_data.acdirmin},
+	{"acdirmax",	&mount_data.acdirmax},
+	{NULL, NULL}
+};
+
+static struct bool_opts {
+	char *name;
+	int and_mask;
+	int or_mask;
+} bool_opts[] = {
+	{"soft", ~NFS_MOUNT_SOFT, NFS_MOUNT_SOFT},
+	{"hard", ~NFS_MOUNT_SOFT, 0},
+	{"intr", ~NFS_MOUNT_INTR, NFS_MOUNT_INTR},
+	{"nointr", ~NFS_MOUNT_INTR, 0},
+	{"posix", ~NFS_MOUNT_POSIX, NFS_MOUNT_POSIX},
+	{"noposix", ~NFS_MOUNT_POSIX, 0},
+	{"cto", ~NFS_MOUNT_NOCTO, 0},
+	{"nocto", ~NFS_MOUNT_NOCTO, NFS_MOUNT_NOCTO},
+	{"ac", ~NFS_MOUNT_NOAC, 0},
+	{"noac", ~NFS_MOUNT_NOAC, NFS_MOUNT_NOAC},
+	{"lock", ~NFS_MOUNT_NONLM, 0},
+	{"nolock", ~NFS_MOUNT_NONLM, NFS_MOUNT_NONLM},
+	{"v2", ~NFS_MOUNT_VER3, 0},
+	{"v3", ~NFS_MOUNT_VER3, NFS_MOUNT_VER3},
+	{"udp", ~NFS_MOUNT_TCP, 0},
+	{"tcp", ~NFS_MOUNT_TCP, NFS_MOUNT_TCP},
+	{"broken_suid", ~NFS_MOUNT_BROKEN_SUID, NFS_MOUNT_BROKEN_SUID},
+	{"ro", ~NFS_MOUNT_KLIBC_RONLY, NFS_MOUNT_KLIBC_RONLY},
+	{"rw", ~NFS_MOUNT_KLIBC_RONLY, 0},
+	{NULL, 0, 0}
+};
+
+static int parse_int(const char *val, const char *ctx)
+{
+	char *end;
+	int ret;
+
+	ret = (int)strtoul(val, &end, 0);
+	if (*val == '\0' || *end != '\0') {
+		fprintf(stderr, "%s: invalid value for %s\n", val, ctx);
+		longjmp(abort_buf, 1);
+	}
+	return ret;
+}
+
+static void parse_opts(char *opts)
+{
+	char *cp, *val;
+
+	while ((cp = strsep(&opts, ",")) != NULL) {
+		if (*cp == '\0')
+			continue;
+		if ((val = strchr(cp, '=')) != NULL) {
+			struct int_opts *opts = int_opts;
+			*val++ = '\0';
+			while (opts->name && strcmp(opts->name, cp) != 0)
+				opts++;
+			if (opts->name)
+				*(opts->val) = parse_int(val, opts->name);
+			else {
+				fprintf(stderr, "%s: bad option '%s'\n",
+					progname, cp);
+				longjmp(abort_buf, 1);
+			}
+		} else {
+			struct bool_opts *opts = bool_opts;
+			while (opts->name && strcmp(opts->name, cp) != 0)
+				opts++;
+			if (opts->name) {
+				mount_data.flags &= opts->and_mask;
+				mount_data.flags |= opts->or_mask;
+			} else {
+				fprintf(stderr, "%s: bad option '%s'\n",
+					progname, cp);
+				longjmp(abort_buf, 1);
+			}
+		}
+	}
+}
+
+static uint32_t parse_addr(const char *ip)
+{
+	struct in_addr in;
+	if (inet_aton(ip, &in) == 0) {
+		fprintf(stderr, "%s: can't parse IP address '%s'\n",
+			progname, ip);
+		longjmp(abort_buf, 1);
+	}
+	return in.s_addr;
+}
+
+static void check_path(const char *path)
+{
+	struct stat st;
+
+	if (stat(path, &st) == -1) {
+		perror("stat");
+		longjmp(abort_buf, 1);
+	} else if (!S_ISDIR(st.st_mode)) {
+		fprintf(stderr, "%s: '%s' not a directory\n", progname, path);
+		longjmp(abort_buf, 1);
+	}
+}
+
+int main(int argc, char *argv[])
+    __attribute__ ((weak, alias("nfsmount_main")));
+
+int nfsmount_main(int argc, char *argv[])
+{
+	uint32_t server;
+	char *rem_name;
+	char *rem_path;
+	char *hostname;
+	char *path;
+	int c;
+	const char *portmap_file;
+	pid_t spoof_portmap;
+	int err;
+
+	if ((err = setjmp(abort_buf)))
+		return err;
+
+	/* Set these here to avoid longjmp warning */
+	portmap_file = NULL;
+	spoof_portmap = 0;
+	server = 0;
+
+	/* If progname is set we're invoked from another program */
+	if (!progname) {
+		struct timeval now;
+		progname = argv[0];
+		gettimeofday(&now, NULL);
+		srand48(now.tv_usec ^ (now.tv_sec << 24));
+	}
+
+	while ((c = getopt(argc, argv, "o:p:")) != EOF) {
+		switch (c) {
+		case 'o':
+			parse_opts(optarg);
+			break;
+		case 'p':
+			portmap_file = optarg;
+			break;
+		case '?':
+			fprintf(stderr, "%s: invalid option -%c\n",
+				progname, optopt);
+			return 1;
+		}
+	}
+
+	if (optind == argc) {
+		fprintf(stderr, "%s: need a path\n", progname);
+		return 1;
+	}
+
+	hostname = rem_path = argv[optind];
+
+	if ((rem_name = strdup(rem_path)) == NULL) {
+		perror("strdup");
+		return 1;
+	}
+
+	if ((rem_path = strchr(rem_path, ':')) == NULL) {
+		fprintf(stderr, "%s: need a server\n", progname);
+		return 1;
+	}
+
+	*rem_path++ = '\0';
+
+	if (*rem_path != '/') {
+		fprintf(stderr, "%s: need a path\n", progname);
+		return 1;
+	}
+
+	server = parse_addr(hostname);
+
+	if (optind <= argc - 2)
+		path = argv[optind + 1];
+	else
+		path = "/nfs_root";
+
+	check_path(path);
+
+#if! _KLIBC_NO_MMU
+	/* Note: uClinux can't fork(), so the spoof portmapper is not
+	   available on uClinux. */
+	if (portmap_file)
+		spoof_portmap = start_dummy_portmap(portmap_file);
+
+	if (spoof_portmap == -1)
+		return 1;
+#endif
+
+	if (nfs_mount(rem_name, hostname, server, rem_path, path,
+		      &mount_data) != 0)
+		return 1;
+
+	/* If we set up the spoofer, tear it down now */
+	if (spoof_portmap) {
+		kill(SIGTERM, spoof_portmap);
+		while (waitpid(spoof_portmap, NULL, 0) == -1 &&
+		       errno == EINTR)
+		  ;
+	}
+
+	free(rem_name);
+
+	return 0;
+}
diff --git a/usr/kinit/nfsmount/mount.c b/usr/kinit/nfsmount/mount.c
new file mode 100644
index 0000000..066f6cd
--- /dev/null
+++ b/usr/kinit/nfsmount/mount.c
@@ -0,0 +1,357 @@
+#include <sys/mount.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <arpa/inet.h>
+#include <netinet/in.h>
+#include <linux/nfs.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+
+#include "nfsmount.h"
+#include "sunrpc.h"
+
+static uint32_t mount_port;
+
+struct mount_call {
+	struct rpc_call rpc;
+	uint32_t path_len;
+	char path[0];
+};
+
+/*
+ * The following structure is the NFS v3 on-the-wire file handle,
+ * as defined in rfc1813.
+ * This differs from the structure used by the kernel,
+ * defined in <linux/nfh3.h>: rfc has a long in network order,
+ * kernel has a short in native order.
+ * Both kernel and rfc use the name nfs_fh; kernel name is
+ * visible to user apps in some versions of libc.
+ * Use different name to avoid clashes.
+ */
+#define NFS_MAXFHSIZE_WIRE 64
+struct nfs_fh_wire {
+	uint32_t size;
+	char data[NFS_MAXFHSIZE_WIRE];
+} __attribute__ ((packed));
+
+struct mount_reply {
+	struct rpc_reply reply;
+	uint32_t status;
+	struct nfs_fh_wire fh;
+} __attribute__ ((packed));
+
+#define MNT_REPLY_MINSIZE (sizeof(struct rpc_reply) + sizeof(uint32_t))
+
+static int get_ports(uint32_t server, const struct nfs_mount_data *data)
+{
+	uint32_t nfs_ver, mount_ver;
+	uint32_t proto;
+
+	if (data->flags & NFS_MOUNT_VER3) {
+		nfs_ver = NFS3_VERSION;
+		mount_ver = NFS_MNT3_VERSION;
+	} else {
+		nfs_ver = NFS2_VERSION;
+		mount_ver = NFS_MNT_VERSION;
+	}
+
+	proto = (data->flags & NFS_MOUNT_TCP) ? IPPROTO_TCP : IPPROTO_UDP;
+
+	if (nfs_port == 0) {
+		nfs_port = portmap(server, NFS_PROGRAM, nfs_ver, proto);
+		if (nfs_port == 0) {
+			if (proto == IPPROTO_TCP) {
+				struct in_addr addr = { server };
+				fprintf(stderr, "NFS over TCP not "
+					"available from %s\n", inet_ntoa(addr));
+				return -1;
+			}
+			nfs_port = NFS_PORT;
+		}
+	}
+
+	if (mount_port == 0) {
+		mount_port = portmap(server, NFS_MNT_PROGRAM, mount_ver, proto);
+		if (mount_port == 0)
+			mount_port = MOUNT_PORT;
+	}
+	return 0;
+}
+
+static inline int pad_len(int len)
+{
+	return (len + 3) & ~3;
+}
+
+static inline void dump_params(uint32_t server,
+			       const char *path,
+			       const struct nfs_mount_data *data)
+{
+	(void)server;
+	(void)path;
+	(void)data;
+
+#ifdef NFS_DEBUG
+	struct in_addr addr = { server };
+
+	printf("NFS params:\n");
+	printf("  server = %s, path = \"%s\", ", inet_ntoa(addr), path);
+	printf("version = %d, proto = %s\n",
+	       data->flags & NFS_MOUNT_VER3 ? 3 : 2,
+	       (data->flags & NFS_MOUNT_TCP) ? "tcp" : "udp");
+	printf("  mount_port = %d, nfs_port = %d, flags = %08x\n",
+	       mount_port, nfs_port, data->flags);
+	printf("  rsize = %d, wsize = %d, timeo = %d, retrans = %d\n",
+	       data->rsize, data->wsize, data->timeo, data->retrans);
+	printf("  acreg (min, max) = (%d, %d), acdir (min, max) = (%d, %d)\n",
+	       data->acregmin, data->acregmax, data->acdirmin, data->acdirmax);
+	printf("  soft = %d, intr = %d, posix = %d, nocto = %d, noac = %d\n",
+	       (data->flags & NFS_MOUNT_SOFT) != 0,
+	       (data->flags & NFS_MOUNT_INTR) != 0,
+	       (data->flags & NFS_MOUNT_POSIX) != 0,
+	       (data->flags & NFS_MOUNT_NOCTO) != 0,
+	       (data->flags & NFS_MOUNT_NOAC) != 0);
+#endif
+}
+
+static inline void dump_fh(const char *data, int len)
+{
+	(void)data;
+	(void)len;
+
+#ifdef NFS_DEBUG
+	int i = 0;
+	int max = len - (len % 8);
+
+	printf("Root file handle: %d bytes\n", NFS2_FHSIZE);
+
+	while (i < max) {
+		int j;
+
+		printf("  %4d:  ", i);
+		for (j = 0; j < 4; j++) {
+			printf("%02x %02x %02x %02x  ",
+			       data[i] & 0xff, data[i + 1] & 0xff,
+			       data[i + 2] & 0xff, data[i + 3] & 0xff);
+		}
+		i += j;
+		printf("\n");
+	}
+#endif
+}
+
+static struct mount_reply mnt_reply;
+
+static int mount_call(uint32_t proc, uint32_t version,
+		      const char *path, struct client *clnt)
+{
+	struct mount_call *mnt_call = NULL;
+	size_t path_len, call_len;
+	struct rpc rpc;
+	int ret = 0;
+
+	path_len = strlen(path);
+	call_len = sizeof(*mnt_call) + pad_len(path_len);
+
+	if ((mnt_call = malloc(call_len)) == NULL) {
+		perror("malloc");
+		goto bail;
+	}
+
+	memset(mnt_call, 0, sizeof(*mnt_call));
+
+	mnt_call->rpc.program = htonl(NFS_MNT_PROGRAM);
+	mnt_call->rpc.prog_vers = htonl(version);
+	mnt_call->rpc.proc = htonl(proc);
+	mnt_call->path_len = htonl(path_len);
+	memcpy(mnt_call->path, path, path_len);
+
+	rpc.call = (struct rpc_call *)mnt_call;
+	rpc.call_len = call_len;
+	rpc.reply = (struct rpc_reply *)&mnt_reply;
+	rpc.reply_len = sizeof(mnt_reply);
+
+	if (rpc_call(clnt, &rpc) < 0)
+		goto bail;
+
+	if (proc != MNTPROC_MNT) {
+		goto done;
+	}
+
+	if (rpc.reply_len < MNT_REPLY_MINSIZE) {
+		fprintf(stderr, "incomplete reply: %zu < %zu\n",
+			rpc.reply_len, MNT_REPLY_MINSIZE);
+		goto bail;
+	}
+
+	if (mnt_reply.status != 0) {
+		fprintf(stderr, "mount call failed: %d\n",
+			ntohl(mnt_reply.status));
+		goto bail;
+	}
+
+	goto done;
+
+bail:
+	ret = -1;
+
+done:
+	if (mnt_call) {
+		free(mnt_call);
+	}
+
+	return ret;
+}
+
+static int mount_v2(const char *path,
+		    struct nfs_mount_data *data, struct client *clnt)
+{
+	int ret = mount_call(MNTPROC_MNT, NFS_MNT_VERSION, path, clnt);
+
+	if (ret == 0) {
+		dump_fh((const char *)&mnt_reply.fh, NFS2_FHSIZE);
+
+		data->root.size = NFS_FHSIZE;
+		memcpy(data->root.data, &mnt_reply.fh, NFS_FHSIZE);
+		memcpy(data->old_root.data, &mnt_reply.fh, NFS_FHSIZE);
+	}
+
+	return ret;
+}
+
+static inline int umount_v2(const char *path, struct client *clnt)
+{
+	return mount_call(MNTPROC_UMNT, NFS_MNT_VERSION, path, clnt);
+}
+
+static int mount_v3(const char *path,
+		    struct nfs_mount_data *data, struct client *clnt)
+{
+	int ret = mount_call(MNTPROC_MNT, NFS_MNT3_VERSION, path, clnt);
+
+	if (ret == 0) {
+		size_t fhsize = ntohl(mnt_reply.fh.size);
+
+		dump_fh((const char *)&mnt_reply.fh.data, fhsize);
+
+		memset(data->old_root.data, 0, NFS_FHSIZE);
+		memset(&data->root, 0, sizeof(data->root));
+		data->root.size = fhsize;
+		memcpy(&data->root.data, mnt_reply.fh.data, fhsize);
+		data->flags |= NFS_MOUNT_VER3;
+	}
+
+	return ret;
+}
+
+static inline int umount_v3(const char *path, struct client *clnt)
+{
+	return mount_call(MNTPROC_UMNT, NFS_MNT3_VERSION, path, clnt);
+}
+
+int nfs_mount(const char *pathname, const char *hostname,
+	      uint32_t server, const char *rem_path, const char *path,
+	      struct nfs_mount_data *data)
+{
+	struct client *clnt = NULL;
+	struct sockaddr_in addr;
+	char mounted = 0;
+	int sock = -1;
+	int ret = 0;
+	int mountflags;
+
+	if (get_ports(server, data) != 0) {
+		goto bail;
+	}
+
+	dump_params(server, rem_path, data);
+
+	if (data->flags & NFS_MOUNT_TCP) {
+		clnt = tcp_client(server, mount_port, CLI_RESVPORT);
+	} else {
+		clnt = udp_client(server, mount_port, CLI_RESVPORT);
+	}
+
+	if (clnt == NULL) {
+		goto bail;
+	}
+
+	if (data->flags & NFS_MOUNT_VER3) {
+		ret = mount_v3(rem_path, data, clnt);
+	} else {
+		ret = mount_v2(rem_path, data, clnt);
+	}
+
+	if (ret == -1) {
+		goto bail;
+	}
+	mounted = 1;
+
+	if (data->flags & NFS_MOUNT_TCP) {
+		sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
+	} else {
+		sock = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
+	}
+
+	if (sock == -1) {
+		perror("socket");
+		goto bail;
+	}
+
+	if (bindresvport(sock, 0) == -1) {
+		perror("bindresvport");
+		goto bail;
+	}
+
+	addr.sin_family = AF_INET;
+	addr.sin_addr.s_addr = server;
+	addr.sin_port = htons(nfs_port);
+	memcpy(&data->addr, &addr, sizeof(data->addr));
+
+	strncpy(data->hostname, hostname, sizeof(data->hostname));
+
+	data->fd = sock;
+
+	mountflags = (data->flags & NFS_MOUNT_KLIBC_RONLY) ? MS_RDONLY : 0;
+	data->flags = data->flags & NFS_MOUNT_FLAGMASK;
+	ret = mount(pathname, path, "nfs", mountflags, data);
+
+	if (ret == -1) {
+		if (errno == ENODEV) {
+			fprintf(stderr, "mount: the kernel lacks NFS v%d "
+				"support\n",
+				(data->flags & NFS_MOUNT_VER3) ? 3 : 2);
+		} else {
+			perror("mount");
+		}
+		goto bail;
+	}
+
+	DEBUG(("Mounted %s on %s\n", pathname, path));
+
+	goto done;
+
+      bail:
+	if (mounted) {
+		if (data->flags & NFS_MOUNT_VER3) {
+			umount_v3(path, clnt);
+		} else {
+			umount_v2(path, clnt);
+		}
+	}
+
+	ret = -1;
+
+      done:
+	if (clnt) {
+		client_free(clnt);
+	}
+
+	if (sock != -1) {
+		close(sock);
+	}
+
+	return ret;
+}
diff --git a/usr/kinit/nfsmount/nfsmount.h b/usr/kinit/nfsmount/nfsmount.h
new file mode 100644
index 0000000..0117c10
--- /dev/null
+++ b/usr/kinit/nfsmount/nfsmount.h
@@ -0,0 +1,35 @@
+#ifndef NFSMOUNT_NFSMOUNT_H
+#define NFSMOUNT_NFSMOUNT_H
+
+#include <linux/nfs_mount.h>
+
+extern int nfs_port;
+
+extern int nfsmount_main(int argc, char *argv[]);
+int nfs_mount(const char *rem_name, const char *hostname,
+	      uint32_t server, const char *rem_path,
+	      const char *path, struct nfs_mount_data *data);
+
+enum nfs_proto {
+	v2 = 2,
+	v3,
+};
+
+/* masked with NFS_MOUNT_FLAGMASK before mount() call */
+#define NFS_MOUNT_KLIBC_RONLY	0x00010000U
+/*
+ * Note for gcc 3.2.2:
+ *
+ * If you're turning on debugging, make sure you get rid of -Os from
+ * the gcc command line, or else ipconfig will fail to link.
+ */
+#define NFS_DEBUG
+
+#undef DEBUG
+#ifdef NFS_DEBUG
+#define DEBUG(x) printf x
+#else
+#define DEBUG(x) do { } while(0)
+#endif
+
+#endif /* NFSMOUNT_NFSMOUNT_H */
diff --git a/usr/kinit/nfsmount/portmap.c b/usr/kinit/nfsmount/portmap.c
new file mode 100644
index 0000000..2f111d9
--- /dev/null
+++ b/usr/kinit/nfsmount/portmap.c
@@ -0,0 +1,73 @@
+#include <sys/types.h>
+#include <netinet/in.h>
+#include <asm/byteorder.h>	/* __constant_hton* */
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "nfsmount.h"
+#include "sunrpc.h"
+
+struct portmap_call {
+	struct rpc_call rpc;
+	uint32_t program;
+	uint32_t version;
+	uint32_t proto;
+	uint32_t port;
+};
+
+struct portmap_reply {
+	struct rpc_reply rpc;
+	uint32_t port;
+};
+
+static struct portmap_call call = {
+	.rpc = {
+		.program	= __constant_htonl(RPC_PMAP_PROGRAM),
+		.prog_vers	= __constant_htonl(RPC_PMAP_VERSION),
+		.proc		= __constant_htonl(PMAP_PROC_GETPORT),
+	}
+};
+
+uint32_t portmap(uint32_t server, uint32_t program, uint32_t version, uint32_t proto)
+{
+	struct portmap_reply reply;
+	struct client *clnt;
+	struct rpc rpc;
+	uint32_t port = 0;
+
+	if ((clnt = tcp_client(server, RPC_PMAP_PORT, 0)) == NULL) {
+		if ((clnt = udp_client(server, RPC_PMAP_PORT, 0)) == NULL) {
+			goto bail;
+		}
+	}
+
+	call.program = htonl(program);
+	call.version = htonl(version);
+	call.proto = htonl(proto);
+
+	rpc.call = (struct rpc_call *)&call;
+	rpc.call_len = sizeof(call);
+	rpc.reply = (struct rpc_reply *)&reply;
+	rpc.reply_len = sizeof(reply);
+
+	if (rpc_call(clnt, &rpc) < 0)
+		goto bail;
+
+	if (rpc.reply_len < sizeof(reply)) {
+		fprintf(stderr, "incomplete reply: %zu < %zu\n",
+			rpc.reply_len, sizeof(reply));
+		goto bail;
+	}
+
+	port = ntohl(reply.port);
+
+bail:
+	DEBUG(("Port for %d/%d[%s]: %d\n", program, version,
+	       proto == IPPROTO_TCP ? "tcp" : "udp", port));
+
+	if (clnt) {
+		client_free(clnt);
+	}
+
+	return port;
+}
diff --git a/usr/kinit/nfsmount/sunrpc.c b/usr/kinit/nfsmount/sunrpc.c
new file mode 100644
index 0000000..915d412
--- /dev/null
+++ b/usr/kinit/nfsmount/sunrpc.c
@@ -0,0 +1,253 @@
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <errno.h>
+#include <poll.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include "nfsmount.h"
+#include "sunrpc.h"
+
+/*
+ * The magic offset is needed here because RPC over TCP includes a
+ * field that RPC over UDP doesn't.  Luvverly.
+ */
+static int rpc_do_reply(struct client *clnt, struct rpc *rpc, size_t off)
+{
+	int ret;
+
+	if ((ret = read(clnt->sock,
+			((char *)rpc->reply) + off,
+			rpc->reply_len - off)) == -1) {
+		perror("read");
+		goto bail;
+	} else if (ret < sizeof(struct rpc_reply) - off) {
+		fprintf(stderr, "short read: %d < %zu\n", ret,
+			sizeof(struct rpc_reply) - off);
+		goto bail;
+	}
+	rpc->reply_len = ret + off;
+
+	if ((!off && !(ntohl(rpc->reply->hdr.frag_hdr) & LAST_FRAG)) ||
+	    rpc->reply->hdr.udp.xid != rpc->call->hdr.udp.xid ||
+	    rpc->reply->hdr.udp.msg_type != htonl(RPC_REPLY)) {
+		fprintf(stderr, "bad reply\n");
+		goto bail;
+	}
+
+	if (ntohl(rpc->reply->state) != REPLY_OK) {
+		fprintf(stderr, "rpc failed: %d\n", ntohl(rpc->reply->state));
+		goto bail;
+	}
+
+	ret = 0;
+	goto done;
+
+bail:
+	ret = -1;
+done:
+	return ret;
+}
+
+static void rpc_header(struct client *clnt, struct rpc *rpc)
+{
+	(void)clnt;
+
+	rpc->call->hdr.frag_hdr = htonl(LAST_FRAG | rpc->call_len);
+	rpc->call->hdr.udp.xid = lrand48();
+	rpc->call->hdr.udp.msg_type = htonl(RPC_CALL);
+	rpc->call->rpc_vers = htonl(2);
+}
+
+static int rpc_call_tcp(struct client *clnt, struct rpc *rpc)
+{
+	int ret;
+
+	rpc_header(clnt, rpc);
+
+	if ((ret = write(clnt->sock, rpc->call, rpc->call_len)) == -1) {
+		perror("write");
+		goto bail;
+	} else if (ret < rpc->call_len) {
+		fprintf(stderr, "short write: %d < %zu\n", ret, rpc->call_len);
+		goto bail;
+	}
+
+	ret = rpc_do_reply(clnt, rpc, 0);
+	goto done;
+
+      bail:
+	ret = -1;
+
+      done:
+	return ret;
+}
+
+static int rpc_call_udp(struct client *clnt, struct rpc *rpc)
+{
+#define NR_FDS 1
+#define TIMEOUT_MS 3000
+#define MAX_TRIES 100
+#define UDP_HDR_OFF (sizeof(struct rpc_header) - sizeof(struct rpc_udp_header))
+	struct pollfd fds[NR_FDS];
+	int ret = -1;
+	int i;
+
+	rpc_header(clnt, rpc);
+
+	fds[0].fd = clnt->sock;
+	fds[0].events = POLLRDNORM;
+
+	rpc->call_len -= UDP_HDR_OFF;
+
+	for (i = 0; i < MAX_TRIES; i++) {
+		int timeout_ms = TIMEOUT_MS + (lrand48() % (TIMEOUT_MS / 2));
+		if ((ret = write(clnt->sock,
+				 ((char *)rpc->call) + UDP_HDR_OFF,
+				 rpc->call_len)) == -1) {
+			perror("write");
+			goto bail;
+		} else if (ret < rpc->call_len) {
+			fprintf(stderr, "short write: %d < %zu\n", ret,
+				rpc->call_len);
+			goto bail;
+		}
+		for (; i < MAX_TRIES; i++) {
+			if ((ret = poll(fds, NR_FDS, timeout_ms)) == -1) {
+				perror("poll");
+				goto bail;
+			}
+			if (ret == 0) {
+				DEBUG(("Timeout #%d\n", i + 1));
+				break;
+			}
+			if ((ret = rpc_do_reply(clnt, rpc, UDP_HDR_OFF)) == 0) {
+				goto done;
+			} else {
+				DEBUG(("Failed on try #%d - retrying\n",
+				       i + 1));
+			}
+		}
+	}
+
+      bail:
+	ret = -1;
+
+      done:
+	return ret;
+}
+
+struct client *tcp_client(uint32_t server, uint16_t port, uint32_t flags)
+{
+	struct client *clnt = malloc(sizeof(*clnt));
+	struct sockaddr_in addr;
+	int sock;
+
+	if (clnt == NULL) {
+		perror("malloc");
+		goto bail;
+	}
+
+	memset(clnt, 0, sizeof(clnt));
+
+	if ((sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) == -1) {
+		perror("socket");
+		goto bail;
+	}
+
+	if ((flags & CLI_RESVPORT) && bindresvport(sock, 0) == -1) {
+		perror("bindresvport");
+		goto bail;
+	}
+
+	clnt->sock = sock;
+	clnt->call_stub = rpc_call_tcp;
+
+	addr.sin_family = AF_INET;
+	addr.sin_port = htons(port);
+	addr.sin_addr.s_addr = server;
+
+	if (connect(sock, (struct sockaddr *)&addr, sizeof(addr)) == -1) {
+		perror("connect");
+		goto bail;
+	}
+
+	goto done;
+      bail:
+	if (clnt) {
+		free(clnt);
+		clnt = NULL;
+	}
+      done:
+	return clnt;
+}
+
+struct client *udp_client(uint32_t server, uint16_t port, uint32_t flags)
+{
+	struct client *clnt = malloc(sizeof(*clnt));
+	struct sockaddr_in addr;
+	int sock;
+
+	if (clnt == NULL) {
+		perror("malloc");
+		goto bail;
+	}
+
+	memset(clnt, 0, sizeof(clnt));
+
+	if ((sock = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP)) == -1) {
+		perror("socket");
+		goto bail;
+	}
+
+	if ((flags & CLI_RESVPORT) && bindresvport(sock, 0) == -1) {
+		perror("bindresvport");
+		goto bail;
+	} else {
+		struct sockaddr_in me;
+
+		me.sin_family = AF_INET;
+		me.sin_port = 0;
+		me.sin_addr.s_addr = INADDR_ANY;
+
+		if (0 && bind(sock, (struct sockaddr *)&me, sizeof(me)) == -1) {
+			perror("bind");
+			goto bail;
+		}
+	}
+
+	clnt->sock = sock;
+	clnt->call_stub = rpc_call_udp;
+
+	addr.sin_family = AF_INET;
+	addr.sin_port = htons(port);
+	addr.sin_addr.s_addr = server;
+
+	if (connect(sock, (struct sockaddr *)&addr, sizeof(addr)) == -1) {
+		perror("connect");
+		goto bail;
+	}
+
+	goto done;
+      bail:
+	if (clnt) {
+		free(clnt);
+		clnt = NULL;
+	}
+      done:
+	return clnt;
+}
+
+void client_free(struct client *c)
+{
+	if (c->sock != -1)
+		close(c->sock);
+	free(c);
+}
+
+int rpc_call(struct client *client, struct rpc *rpc)
+{
+	return client->call_stub(client, rpc);
+}
diff --git a/usr/kinit/nfsmount/sunrpc.h b/usr/kinit/nfsmount/sunrpc.h
new file mode 100644
index 0000000..d6d6c18
--- /dev/null
+++ b/usr/kinit/nfsmount/sunrpc.h
@@ -0,0 +1,99 @@
+/*
+ * open-coded SunRPC structures
+ */
+#ifndef NFSMOUNT_SUNRPC_H
+#define NFSMOUNT_SUNRPC_H
+
+#include <sys/types.h>
+#include <inttypes.h>
+
+#define SUNRPC_PORT	111
+#define MOUNT_PORT	627
+
+#define RPC_CALL	0
+#define RPC_REPLY	1
+
+#define PORTMAP_PROGRAM	100000
+#define NLM_PROGRAM	100021
+
+#define RPC_PMAP_PROGRAM	100000
+#define RPC_PMAP_VERSION	2
+#define RPC_PMAP_PORT		111
+
+#define PMAP_PROC_NULL		0
+#define PMAP_PROC_SET		1
+#define PMAP_PROC_UNSET		2
+#define PMAP_PROC_GETPORT	3
+#define PMAP_PROC_DUMP		4
+
+#define LAST_FRAG	0x80000000
+
+#define REPLY_OK	0
+#define REPLY_DENIED    1
+
+#define SUCCESS		0
+#define PROG_UNAVAIL	1
+#define PROG_MISMATCH	2
+#define PROC_UNAVAIL	3
+#define GARBAGE_ARGS	4
+#define SYSTEM_ERR	5
+
+struct rpc_udp_header {
+	uint32_t xid;
+	uint32_t msg_type;
+};
+
+struct rpc_header {
+	uint32_t frag_hdr;
+	struct rpc_udp_header udp;
+};
+
+struct rpc_call {
+	struct rpc_header hdr;
+	uint32_t rpc_vers;
+
+	uint32_t program;
+	uint32_t prog_vers;
+	uint32_t proc;
+	uint32_t cred_flavor;
+
+	uint32_t cred_len;
+	uint32_t vrf_flavor;
+	uint32_t vrf_len;
+};
+
+struct rpc_reply {
+	struct rpc_header hdr;
+	uint32_t reply_state;
+	uint32_t vrf_flavor;
+	uint32_t vrf_len;
+	uint32_t state;
+};
+
+struct rpc {
+	struct rpc_call *call;
+	size_t call_len;
+	struct rpc_reply *reply;
+	size_t reply_len;
+};
+
+struct client;
+
+typedef int (*call_stub) (struct client *, struct rpc *);
+
+struct client {
+	int sock;
+	call_stub call_stub;
+};
+
+#define CLI_RESVPORT	00000001
+
+struct client *tcp_client(uint32_t server, uint16_t port, uint32_t flags);
+struct client *udp_client(uint32_t server, uint16_t port, uint32_t flags);
+void client_free(struct client *client);
+
+int rpc_call(struct client *client, struct rpc *rpc);
+
+uint32_t portmap(uint32_t server, uint32_t program, uint32_t version, uint32_t proto);
+
+#endif /* NFSMOUNT_SUNRPC_H */
diff --git a/usr/kinit/nfsroot.c b/usr/kinit/nfsroot.c
new file mode 100644
index 0000000..9930fd5
--- /dev/null
+++ b/usr/kinit/nfsroot.c
@@ -0,0 +1,113 @@
+#include <arpa/inet.h>
+#include <sys/mount.h>
+#include <sys/stat.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+
+#include "ipconfig.h"
+#include "kinit.h"
+#include "netdev.h"
+#include "nfsmount.h"
+
+static char *sub_client(__u32 client, char *path, size_t len)
+{
+	struct in_addr addr = { client };
+	char buf[len];
+
+	if (strstr(path, "%s") != NULL) {
+		if (client == INADDR_NONE) {
+			fprintf(stderr, "Root-NFS: no client address\n");
+			exit(1);
+		}
+
+		snprintf(buf, len, path, inet_ntoa(addr));
+		strcpy(path, buf);
+	}
+
+	return path;
+}
+
+#define NFS_ARGC 6
+#define MOUNT_POINT "/root"
+
+int mount_nfs_root(int argc, char *argv[], int flags)
+{
+	(void)flags;		/* FIXME - don't ignore this */
+
+	struct in_addr addr = { INADDR_NONE };
+	__u32 client = INADDR_NONE;
+	const int len = 1024;
+	struct netdev *dev;
+	char *mtpt = MOUNT_POINT;
+	char *path = NULL;
+	char *dev_bootpath = NULL;
+	char root[len];
+	char *x, *opts;
+	int ret = 0;
+	int a = 1;
+	char *nfs_argv[NFS_ARGC + 1] = { "NFS-Mount" };
+
+	for (dev = ifaces; dev; dev = dev->next) {
+		if (dev->ip_server != INADDR_NONE &&
+		    dev->ip_server != INADDR_ANY) {
+			addr.s_addr = dev->ip_server;
+			client = dev->ip_addr;
+			dev_bootpath = dev->bootpath;
+			break;
+		}
+		if (dev->ip_addr != INADDR_NONE && dev->ip_addr != INADDR_ANY) {
+			client = dev->ip_addr;
+		}
+	}
+
+	/*
+	 * if the "nfsroot" option is set then it overrides
+	 * bootpath supplied by the boot server.
+	 */
+	if ((path = get_arg(argc, argv, "nfsroot=")) == NULL) {
+		if ((path = dev_bootpath) == NULL || path[0] == '\0')
+			/* no path - set a default */
+			path = (char *)"/tftpboot/%s";
+	} else if (dev_bootpath && dev_bootpath[0] != '\0')
+		fprintf(stderr,
+			"nfsroot=%s overrides boot server bootpath %s\n",
+			path, dev_bootpath);
+
+	if ((opts = strchr(path, ',')) != NULL) {
+		*opts++ = '\0';
+		nfs_argv[a++] = (char *)"-o";
+		nfs_argv[a++] = opts;
+	}
+
+	if ((x = strchr(path, ':')) == NULL) {
+		if (addr.s_addr == INADDR_NONE) {
+			fprintf(stderr, "Root-NFS: no server defined\n");
+			exit(1);
+		}
+
+		snprintf(root, len, "%s:%s", inet_ntoa(addr), path);
+	} else {
+		strcpy(root, path);
+	}
+
+	nfs_argv[a++] = sub_client(client, root, len);
+
+	DEBUG(("NFS-Root: mounting %s on %s with options \"%s\"\n",
+	       nfs_argv[a-1], mtpt, opts ? opts : ""));
+
+	nfs_argv[a++] = mtpt;
+	nfs_argv[a] = NULL;
+	assert(a <= NFS_ARGC);
+
+	dump_args(a, nfs_argv);
+
+	if ((ret = nfsmount_main(a, nfs_argv)) != 0) {
+		ret = -1;
+		goto done;
+	}
+
+      done:
+	return ret;
+}
diff --git a/usr/kinit/ramdisk_load.c b/usr/kinit/ramdisk_load.c
new file mode 100644
index 0000000..9d2e0b9
--- /dev/null
+++ b/usr/kinit/ramdisk_load.c
@@ -0,0 +1,271 @@
+#include <ctype.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <inttypes.h>
+#include <sys/stat.h>
+#include <linux/fs.h>
+#include <linux/cdrom.h>
+#include <linux/fd.h>
+
+#include "kinit.h"
+#include "do_mounts.h"
+#include "fstype.h"
+#include "zlib.h"
+
+#define BUF_SZ		65536
+
+static void wait_for_key(void)
+{
+	/* Wait until the user presses Enter */
+	while (getchar() != '\n')
+		;
+}
+
+static int change_disk(const char *devpath, int rfd, int disk)
+{
+	/* Try to eject and/or quiesce the device */
+	sync();
+	if (ioctl(rfd, FDEJECT, 0)) {
+		if (errno == ENOTTY) {
+			/* Not a floppy */
+			ioctl(rfd, CDROMEJECT, 0);
+		} else {
+			/* Non-ejectable floppy */
+			ioctl(rfd, FDRESET, FD_RESET_IF_NEEDED);
+		}
+	}
+	close(rfd);
+
+	fprintf(stderr,
+		"\nPlease insert disk %d for ramdisk and press Enter...", disk);
+	wait_for_key();
+
+	return open(devpath, O_RDONLY);
+}
+
+/* Also used in initrd.c */
+int load_ramdisk_compressed(const char *devpath, FILE * wfd,
+			    off_t ramdisk_start)
+{
+	int rfd = -1;
+	unsigned long long ramdisk_size, ramdisk_left;
+	int disk = 1;
+	ssize_t bytes;
+	int rv;
+	unsigned char in_buf[BUF_SZ], out_buf[BUF_SZ];
+	z_stream zs;
+
+	zs.zalloc = Z_NULL;	/* Use malloc() */
+	zs.zfree = Z_NULL;	/* Use free() */
+	zs.next_in = Z_NULL;	/* No data read yet */
+	zs.avail_in = 0;
+	zs.next_out = out_buf;
+	zs.avail_out = BUF_SZ;
+
+	if (inflateInit2(&zs, 32 + 15) != Z_OK)
+		goto err1;
+
+	rfd = open(devpath, O_RDONLY);
+	if (rfd < 0)
+		goto err2;
+
+	/* Set to the size of the medium, or "infinite" */
+	if (ioctl(rfd, BLKGETSIZE64, &ramdisk_size))
+		ramdisk_size = ~0ULL;
+
+	do {
+		/* Purge the output preferentially over reading new
+		   input, so we don't end up overrunning the input by
+		   accident and demanding a new disk which doesn't
+		   exist... */
+		if (zs.avail_out == 0) {
+			_fwrite(out_buf, BUF_SZ, wfd);
+			zs.next_out = out_buf;
+			zs.avail_out = BUF_SZ;
+		} else if (zs.avail_in == 0) {
+			if (ramdisk_start >= ramdisk_size) {
+				rfd = change_disk(devpath, rfd, ++disk);
+				if (rfd < 0)
+					goto err2;
+
+				if (ioctl(rfd, BLKGETSIZE64, &ramdisk_size))
+					ramdisk_size = ~0ULL;
+				ramdisk_start = 0;
+				DEBUG(("New size = %llu\n", ramdisk_size));
+			}
+			do {
+				ramdisk_left = ramdisk_size - ramdisk_start;
+				bytes = min(ramdisk_left,
+					    (unsigned long long)BUF_SZ);
+				bytes = pread(rfd, in_buf, bytes,
+					      ramdisk_start);
+			} while (bytes == -1 && errno == EINTR);
+			if (bytes <= 0)
+				goto err2;
+			ramdisk_start += bytes;
+			zs.next_in = in_buf;
+			zs.avail_in = bytes;
+
+			/* Print dots if we're reading from a real block device */
+			if (ramdisk_size != ~0ULL)
+				putc('.', stderr);
+		}
+		rv = inflate(&zs, Z_SYNC_FLUSH);
+	} while (rv == Z_OK || rv == Z_BUF_ERROR);
+
+	DEBUG(("kinit: inflate returned %d\n", rv));
+
+	if (rv != Z_STREAM_END)
+		goto err2;
+
+	/* Write the last */
+	_fwrite(out_buf, BUF_SZ - zs.avail_out, wfd);
+	DEBUG(("kinit: writing %d bytes\n", BUF_SZ - zs.avail_out));
+
+	inflateEnd(&zs);
+	return 0;
+
+err2:
+	inflateEnd(&zs);
+err1:
+	return -1;
+}
+
+static int
+load_ramdisk_raw(const char *devpath, FILE * wfd, off_t ramdisk_start,
+		 unsigned long long fssize)
+{
+	unsigned long long ramdisk_size, ramdisk_left;
+	int disk = 1;
+	ssize_t bytes;
+	unsigned char buf[BUF_SZ];
+	int rfd;
+
+	rfd = open(devpath, O_RDONLY);
+	if (rfd < 0)
+		return -1;
+
+	/* Set to the size of the medium, or "infinite" */
+	if (ioctl(rfd, BLKGETSIZE64, &ramdisk_size))
+		ramdisk_size = ~0ULL;
+
+	DEBUG(("start: %llu  size: %llu  fssize: %llu\n",
+	       ramdisk_start, ramdisk_size, fssize));
+
+	while (fssize) {
+
+		if (ramdisk_start >= ramdisk_size) {
+			rfd = change_disk(devpath, rfd, ++disk);
+			if (rfd < 0)
+				return -1;
+
+			if (ioctl(rfd, BLKGETSIZE64, &ramdisk_size))
+				ramdisk_size = ~0ULL;
+			ramdisk_start = 0;
+		}
+
+		do {
+			ramdisk_left =
+			    min(ramdisk_size - ramdisk_start, fssize);
+			bytes = min(ramdisk_left, (unsigned long long)BUF_SZ);
+			bytes = pread(rfd, buf, bytes, ramdisk_start);
+		} while (bytes == -1 && errno == EINTR);
+		if (bytes <= 0)
+			break;
+		_fwrite(buf, bytes, wfd);
+
+		ramdisk_start += bytes;
+		fssize -= bytes;
+
+		/* Print dots if we're reading from a real block device */
+		if (ramdisk_size != ~0ULL)
+			putc('.', stderr);
+	}
+
+	return !!fssize;
+}
+
+int ramdisk_load(int argc, char *argv[], dev_t root_dev)
+{
+	const char *arg_prompt_ramdisk = get_arg(argc, argv, "prompt_ramdisk=");
+	const char *arg_ramdisk_blocksize =
+	    get_arg(argc, argv, "ramdisk_blocksize=");
+	const char *arg_ramdisk_start = get_arg(argc, argv, "ramdisk_start=");
+	const char *arg_ramdisk_device = get_arg(argc, argv, "ramdisk_device=");
+
+	int prompt_ramdisk = arg_prompt_ramdisk ? atoi(arg_prompt_ramdisk) : 0;
+	int ramdisk_blocksize =
+	    arg_ramdisk_blocksize ? atoi(arg_ramdisk_blocksize) : 512;
+	off_t ramdisk_start =
+	    arg_ramdisk_start
+	    ? strtoumax(arg_ramdisk_start, NULL, 10) * ramdisk_blocksize : 0;
+	const char *ramdisk_device =
+	    arg_ramdisk_device ? arg_ramdisk_device : "/dev/fd0";
+
+	dev_t ramdisk_dev;
+	int rfd;
+	FILE *wfd;
+	const char *fstype;
+	unsigned long long fssize;
+	int is_gzip = 0;
+	int err;
+
+	if (prompt_ramdisk) {
+		fprintf(stderr,
+			"Please insert disk for ramdisk and press Enter...");
+		wait_for_key();
+	}
+
+	ramdisk_dev = name_to_dev_t(ramdisk_device);
+	if (!ramdisk_dev) {
+		fprintf(stderr,
+			"Failure loading ramdisk: unknown device: %s\n",
+			ramdisk_device);
+		return 0;
+	}
+
+	create_dev("/dev/rddev", ramdisk_dev);
+	create_dev("/dev/ram0", Root_RAM0);
+	rfd = open("/dev/rddev", O_RDONLY);
+	wfd = fopen("/dev/ram0", "w");
+
+	if (rfd < 0 || !wfd) {
+		perror("Could not open ramdisk device");
+		return 0;
+	}
+
+	/* Check filesystem type */
+	if (identify_fs(rfd, &fstype, &fssize, ramdisk_start) ||
+	    (fssize == 0 && !(is_gzip = !strcmp(fstype, "gzip")))) {
+		fprintf(stderr,
+			"Failure loading ramdisk: unknown filesystem type\n");
+		return 0;
+	}
+
+	DEBUG(("kinit: ramdisk is %s, size %llu\n", fstype, fssize));
+
+	fprintf(stderr, "Loading ramdisk (%s) ...", is_gzip ? "gzip" : "raw");
+
+	close(rfd);
+
+	if (is_gzip)
+		err = load_ramdisk_compressed("/dev/rddev", wfd, ramdisk_start);
+	else
+		err = load_ramdisk_raw("/dev/rddev", wfd,
+				       ramdisk_start, fssize);
+
+	fclose(wfd);
+
+	putc('\n', stderr);
+
+	if (err) {
+		perror("Failure loading ramdisk");
+		return 0;
+	}
+
+	return 1;
+}
diff --git a/usr/kinit/readfile.c b/usr/kinit/readfile.c
new file mode 100644
index 0000000..28f854f
--- /dev/null
+++ b/usr/kinit/readfile.c
@@ -0,0 +1,84 @@
+/*
+ * Read the entire contents of a file into malloc'd storage.  This
+ * is mostly useful for things like /proc files where we can't just
+ * fstat() to get the length and then mmap().
+ *
+ * Returns the number of bytes read, or -1 on error.
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <errno.h>
+#include <sys/stat.h>
+
+ssize_t freadfile(FILE *f, char **pp)
+{
+	size_t bs;		/* Decent starting point... */
+	size_t bf;		/* Bytes free */
+	size_t bu = 0;		/* Bytes used */
+	char *buffer, *nb;
+	size_t rv;
+	int old_errno = errno;
+
+	bs = BUFSIZ;		/* A guess as good as any */
+	bf = bs;
+	buffer = malloc(bs);
+
+	if (!buffer)
+		return -1;
+
+	for (;;) {
+		errno = 0;
+
+		while (bf && (rv = _fread(buffer + bu, bf, f))) {
+			bu += rv;
+			bf -= rv;
+		}
+
+		if (errno && errno != EINTR && errno != EAGAIN) {
+			/* error */
+			free(buffer);
+			return -1;
+		}
+
+		if (bf) {
+			/* Hit EOF, no error */
+
+			/* Try to free superfluous memory */
+			if ((nb = realloc(buffer, bu + 1)))
+				buffer = nb;
+
+			/* Null-terminate result for good measure */
+			buffer[bu] = '\0';
+
+			*pp = buffer;
+			errno = old_errno;
+			return bu;
+		}
+
+		/* Double the size of the buffer */
+		bf += bs;
+		bs += bs;
+		if (!(nb = realloc(buffer, bs))) {
+			/* out of memory error */
+			free(buffer);
+			return -1;
+		}
+		buffer = nb;
+	}
+}
+
+ssize_t readfile(const char *filename, char **pp)
+{
+	FILE *f = fopen(filename, "r");
+	ssize_t rv;
+
+	if (!f)
+		return -1;
+
+	rv = freadfile(f, pp);
+
+	fclose(f);
+
+	return rv;
+}
diff --git a/usr/kinit/resume/Kbuild b/usr/kinit/resume/Kbuild
new file mode 100644
index 0000000..034195d
--- /dev/null
+++ b/usr/kinit/resume/Kbuild
@@ -0,0 +1,30 @@
+#
+# Kbuild file for resume
+#
+
+static-y := static/resume
+shared-y := shared/resume
+
+# common .o files
+objs := resume.o resumelib.o
+
+# TODO - do we want a stripped version
+# TODO - do we want the static.g + shared.g directories?
+
+# Create lib.a with all object files (used by kinit)
+lib-y := $(objs)
+
+# Additional include paths files
+KLIBCCFLAGS += -I$(srctree)/$(src)/..
+
+# .o files used to built executables
+static/resume-y   := $(objs)
+static/resume-lib := ../lib.a
+shared/resume-y   := $(objs)
+shared/resume-lib := ../lib.a
+
+# Cleaning
+clean-dirs := static shared
+
+# install binary
+install-y := $(shared-y)
diff --git a/usr/kinit/resume/resume.c b/usr/kinit/resume/resume.c
new file mode 100644
index 0000000..80099f9
--- /dev/null
+++ b/usr/kinit/resume/resume.c
@@ -0,0 +1,25 @@
+/*
+ * Handle resume from suspend-to-disk
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "resume.h"
+
+char *progname;
+
+static __noreturn usage(void)
+{
+	fprintf(stderr, "Usage: %s /dev/<resumedevice> [offset]\n", progname);
+	exit(1);
+}
+
+int main(int argc, char *argv[], char *envp[])
+{
+	progname = argv[0];
+	if (argc < 2 || argc > 3)
+		usage();
+
+	return resume(argv[1], (argc > 2) ? strtoull(argv[2], NULL, 0) : 0ULL);
+}
diff --git a/usr/kinit/resume/resume.h b/usr/kinit/resume/resume.h
new file mode 100644
index 0000000..5fb929f
--- /dev/null
+++ b/usr/kinit/resume/resume.h
@@ -0,0 +1,7 @@
+#ifndef RESUME_H
+#define RESUME_H
+
+int do_resume(int argc, char *argv[]);
+int resume(const char *resume_file, unsigned long long resume_offset);
+
+#endif /* RESUME_H */
diff --git a/usr/kinit/resume/resumelib.c b/usr/kinit/resume/resumelib.c
new file mode 100644
index 0000000..12ef984
--- /dev/null
+++ b/usr/kinit/resume/resumelib.c
@@ -0,0 +1,87 @@
+/*
+ * Handle resume from suspend-to-disk
+ */
+
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <limits.h>
+#include <sys/stat.h>
+#include <sys/sysmacros.h>
+
+#include "kinit.h"
+#include "do_mounts.h"
+#include "resume.h"
+
+#ifndef CONFIG_PM_STD_PARTITION
+# define CONFIG_PM_STD_PARTITION ""
+#endif
+
+int do_resume(int argc, char *argv[])
+{
+	const char *resume_file = CONFIG_PM_STD_PARTITION;
+	const char *resume_arg;
+	unsigned long long resume_offset;
+
+	resume_arg = get_arg(argc, argv, "resume=");
+	resume_file = resume_arg ? resume_arg : resume_file;
+	/* No resume device specified */
+	if (!resume_file[0])
+		return 0;
+
+	resume_arg = get_arg(argc, argv, "resume_offset=");
+	resume_offset = resume_arg ? strtoull(resume_arg, NULL, 0) : 0ULL;
+
+	/* Fix: we either should consider reverting the device back to
+	   ordinary swap, or (better) put that code into swapon */
+	/* Noresume requested */
+	if (get_flag(argc, argv, "noresume"))
+		return 0;
+	return resume(resume_file, resume_offset);
+}
+
+int resume(const char *resume_file, unsigned long long resume_offset)
+{
+	dev_t resume_device;
+	int powerfd = -1;
+	char device_string[64];
+	int len;
+
+	resume_device = name_to_dev_t(resume_file);
+
+	if (major(resume_device) == 0) {
+		fprintf(stderr, "Invalid resume device: %s\n", resume_file);
+		goto failure;
+	}
+
+	if ((powerfd = open("/sys/power/resume", O_WRONLY)) < 0)
+		goto fail_r;
+
+	len = snprintf(device_string, sizeof device_string,
+		       "%u:%u:%llu",
+		       major(resume_device), minor(resume_device),
+		       resume_offset);
+
+	/* This should never happen */
+	if (len >= sizeof device_string)
+		goto fail_r;
+
+	DEBUG(("kinit: trying to resume from %s\n", resume_file));
+
+	if (write(powerfd, device_string, len) != len)
+		goto fail_r;
+
+	/* Okay, what are we still doing alive... */
+failure:
+	if (powerfd >= 0)
+		close(powerfd);
+	fprintf(stderr, "kinit: No resume image, doing normal boot...\n");
+	return -1;
+
+fail_r:
+	fprintf(stderr, "Cannot write /sys/power/resume "
+			"(no software suspend kernel support?)\n");
+	goto failure;
+}
diff --git a/usr/kinit/run-init/Kbuild b/usr/kinit/run-init/Kbuild
new file mode 100644
index 0000000..61a9d0b
--- /dev/null
+++ b/usr/kinit/run-init/Kbuild
@@ -0,0 +1,25 @@
+#
+# Kbuild file for run-init
+#
+
+static-y := static/run-init
+shared-y := shared/run-init
+
+# common .o files
+objs := run-init.o runinitlib.o
+
+# TODO - do we want a stripped version
+# TODO - do we want the static.g + shared.g directories?
+
+# Create built-in.o with all object files (used by kinit)
+lib-y := $(objs)
+
+# .o files used to built executables
+static/run-init-y := $(objs)
+shared/run-init-y := $(objs)
+
+# Cleaning
+clean-dirs := static shared
+
+# install binary
+install-y := $(shared-y)
diff --git a/usr/kinit/run-init/run-init.c b/usr/kinit/run-init/run-init.c
new file mode 100644
index 0000000..0f150dd
--- /dev/null
+++ b/usr/kinit/run-init/run-init.c
@@ -0,0 +1,93 @@
+/* ----------------------------------------------------------------------- *
+ *
+ *   Copyright 2004-2006 H. Peter Anvin - All Rights Reserved
+ *
+ *   Permission is hereby granted, free of charge, to any person
+ *   obtaining a copy of this software and associated documentation
+ *   files (the "Software"), to deal in the Software without
+ *   restriction, including without limitation the rights to use,
+ *   copy, modify, merge, publish, distribute, sublicense, and/or
+ *   sell copies of the Software, and to permit persons to whom
+ *   the Software is furnished to do so, subject to the following
+ *   conditions:
+ *
+ *   The above copyright notice and this permission notice shall
+ *   be included in all copies or substantial portions of the Software.
+ *
+ *   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ *   EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ *   OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ *   NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ *   HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ *   WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ *   FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ *   OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * ----------------------------------------------------------------------- */
+
+/*
+ * Usage: exec run-init [-c /dev/console] /real-root /sbin/init "$@"
+ *
+ * This program should be called as the last thing in a shell script
+ * acting as /init in an initramfs; it does the following:
+ *
+ * - Delete all files in the initramfs;
+ * - Remounts /real-root onto the root filesystem;
+ * - Chroots;
+ * - Opens /dev/console;
+ * - Spawns the specified init program (with arguments.)
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+#include "run-init.h"
+
+static const char *program;
+
+static void __attribute__ ((noreturn)) usage(void)
+{
+	fprintf(stderr,
+		"Usage: exec %s [-c consoledev] /real-root /sbin/init [args]\n",
+		program);
+	exit(1);
+}
+
+int main(int argc, char *argv[])
+{
+	/* Command-line options and defaults */
+	const char *console = "/dev/console";
+	const char *realroot;
+	const char *init;
+	const char *error;
+	char **initargs;
+
+	/* Variables... */
+	int o;
+
+	/* Parse the command line */
+	program = argv[0];
+
+	while ((o = getopt(argc, argv, "c:")) != -1) {
+		if (o == 'c') {
+			console = optarg;
+		} else {
+			usage();
+		}
+	}
+
+	if (argc - optind < 2)
+		usage();
+
+	realroot = argv[optind];
+	init = argv[optind + 1];
+	initargs = argv + optind + 1;
+
+	error = run_init(realroot, console, init, initargs);
+
+	/* If run_init returns, something went wrong */
+	fprintf(stderr, "%s: %s: %s\n", program, error, strerror(errno));
+	return 1;
+}
diff --git a/usr/kinit/run-init/run-init.h b/usr/kinit/run-init/run-init.h
new file mode 100644
index 0000000..a95328e
--- /dev/null
+++ b/usr/kinit/run-init/run-init.h
@@ -0,0 +1,34 @@
+/* ----------------------------------------------------------------------- *
+ *
+ *   Copyright 2004-2006 H. Peter Anvin - All Rights Reserved
+ *
+ *   Permission is hereby granted, free of charge, to any person
+ *   obtaining a copy of this software and associated documentation
+ *   files (the "Software"), to deal in the Software without
+ *   restriction, including without limitation the rights to use,
+ *   copy, modify, merge, publish, distribute, sublicense, and/or
+ *   sell copies of the Software, and to permit persons to whom
+ *   the Software is furnished to do so, subject to the following
+ *   conditions:
+ *
+ *   The above copyright notice and this permission notice shall
+ *   be included in all copies or substantial portions of the Software.
+ *
+ *   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ *   EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ *   OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ *   NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ *   HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ *   WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ *   FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ *   OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * ----------------------------------------------------------------------- */
+
+#ifndef RUN_INIT_H
+#define RUN_INIT_H
+
+const char *run_init(const char *realroot, const char *console,
+		     const char *init, char **initargs);
+
+#endif
diff --git a/usr/kinit/run-init/runinitlib.c b/usr/kinit/run-init/runinitlib.c
new file mode 100644
index 0000000..423637e
--- /dev/null
+++ b/usr/kinit/run-init/runinitlib.c
@@ -0,0 +1,214 @@
+/* ----------------------------------------------------------------------- *
+ *
+ *   Copyright 2004-2006 H. Peter Anvin - All Rights Reserved
+ *
+ *   Permission is hereby granted, free of charge, to any person
+ *   obtaining a copy of this software and associated documentation
+ *   files (the "Software"), to deal in the Software without
+ *   restriction, including without limitation the rights to use,
+ *   copy, modify, merge, publish, distribute, sublicense, and/or
+ *   sell copies of the Software, and to permit persons to whom
+ *   the Software is furnished to do so, subject to the following
+ *   conditions:
+ *
+ *   The above copyright notice and this permission notice shall
+ *   be included in all copies or substantial portions of the Software.
+ *
+ *   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ *   EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ *   OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ *   NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ *   HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ *   WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ *   FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ *   OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * ----------------------------------------------------------------------- */
+
+/*
+ * run_init(consoledev, realroot, init, initargs)
+ *
+ * This function should be called as the last thing in kinit,
+ * from initramfs, it does the following:
+ *
+ * - Delete all files in the initramfs;
+ * - Remounts /real-root onto the root filesystem;
+ * - Chroots;
+ * - Opens /dev/console;
+ * - Spawns the specified init program (with arguments.)
+ *
+ * On failure, returns a human-readable error message.
+ */
+
+#include <alloca.h>
+#include <assert.h>
+#include <dirent.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <sys/mount.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/vfs.h>
+#include "run-init.h"
+
+/* Make it possible to compile on glibc by including constants that the
+   always-behind shipped glibc headers may not include.  Classic example
+   on why the lack of ABI headers screw us up. */
+#ifndef TMPFS_MAGIC
+# define TMPFS_MAGIC	0x01021994
+#endif
+#ifndef RAMFS_MAGIC
+# define RAMFS_MAGIC	0x858458f6
+#endif
+#ifndef MS_MOVE
+# define MS_MOVE	8192
+#endif
+
+static int nuke(const char *what);
+
+static int nuke_dirent(int len, const char *dir, const char *name, dev_t me)
+{
+	int bytes = len + strlen(name) + 2;
+	char path[bytes];
+	int xlen;
+	struct stat st;
+
+	xlen = snprintf(path, bytes, "%s/%s", dir, name);
+	assert(xlen < bytes);
+
+	if (lstat(path, &st))
+		return ENOENT;	/* Return 0 since already gone? */
+
+	if (st.st_dev != me)
+		return 0;	/* DO NOT recurse down mount points!!!!! */
+
+	return nuke(path);
+}
+
+/* Wipe the contents of a directory, but not the directory itself */
+static int nuke_dir(const char *what)
+{
+	int len = strlen(what);
+	DIR *dir;
+	struct dirent *d;
+	int err = 0;
+	struct stat st;
+
+	if (lstat(what, &st))
+		return errno;
+
+	if (!S_ISDIR(st.st_mode))
+		return ENOTDIR;
+
+	if (!(dir = opendir(what))) {
+		/* EACCES means we can't read it.  Might be empty and removable;
+		   if not, the rmdir() in nuke() will trigger an error. */
+		return (errno == EACCES) ? 0 : errno;
+	}
+
+	while ((d = readdir(dir))) {
+		/* Skip . and .. */
+		if (d->d_name[0] == '.' &&
+		    (d->d_name[1] == '\0' ||
+		     (d->d_name[1] == '.' && d->d_name[2] == '\0')))
+			continue;
+
+		err = nuke_dirent(len, what, d->d_name, st.st_dev);
+		if (err) {
+			closedir(dir);
+			return err;
+		}
+	}
+
+	closedir(dir);
+
+	return 0;
+}
+
+static int nuke(const char *what)
+{
+	int rv;
+	int err = 0;
+
+	rv = unlink(what);
+	if (rv < 0) {
+		if (errno == EISDIR) {
+			/* It's a directory. */
+			err = nuke_dir(what);
+			if (!err)
+				err = rmdir(what) ? errno : err;
+		} else {
+			err = errno;
+		}
+	}
+
+	if (err) {
+		errno = err;
+		return err;
+	} else {
+		return 0;
+	}
+}
+
+const char *run_init(const char *realroot, const char *console,
+		     const char *init, char **initargs)
+{
+	struct stat rst, cst, ist;
+	struct statfs sfs;
+	int confd;
+
+	/* First, change to the new root directory */
+	if (chdir(realroot))
+		return "chdir to new root";
+
+	/* This is a potentially highly destructive program.  Take some
+	   extra precautions. */
+
+	/* Make sure the current directory is not on the same filesystem
+	   as the root directory */
+	if (stat("/", &rst) || stat(".", &cst))
+		return "stat";
+
+	if (rst.st_dev == cst.st_dev)
+		return "current directory on the same filesystem as the root";
+
+	/* The initramfs should have /init */
+	if (stat("/init", &ist) || !S_ISREG(ist.st_mode))
+		return "can't find /init on initramfs";
+
+	/* Make sure we're on a ramfs */
+	if (statfs("/", &sfs))
+		return "statfs /";
+	if (sfs.f_type != RAMFS_MAGIC && sfs.f_type != TMPFS_MAGIC)
+		return "rootfs not a ramfs or tmpfs";
+
+	/* Okay, I think we should be safe... */
+
+	/* Delete rootfs contents */
+	if (nuke_dir("/"))
+		return "nuking initramfs contents";
+
+	/* Overmount the root */
+	if (mount(".", "/", NULL, MS_MOVE, NULL))
+		return "overmounting root";
+
+	/* chroot, chdir */
+	if (chroot(".") || chdir("/"))
+		return "chroot";
+
+	/* Open /dev/console */
+	if ((confd = open(console, O_RDWR)) < 0)
+		return "opening console";
+	dup2(confd, 0);
+	dup2(confd, 1);
+	dup2(confd, 2);
+	close(confd);
+
+	/* Spawn init */
+	execv(init, initargs);
+	return init;		/* Failed to spawn init */
+}
diff --git a/usr/kinit/xpio.c b/usr/kinit/xpio.c
new file mode 100644
index 0000000..9373f7c
--- /dev/null
+++ b/usr/kinit/xpio.c
@@ -0,0 +1,49 @@
+/*
+ * Looping versions of pread() and pwrite()
+ */
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <errno.h>
+
+ssize_t xpread(int fd, void *buf, size_t count, off_t offset)
+{
+	ssize_t ctr = 0;
+	ssize_t rv = 0;
+	char *bp = buf;
+
+	while (count) {
+		rv = pread(fd, bp, count, offset);
+
+		if (rv == 0 || (rv == -1 && errno != EINTR))
+			break;
+
+		bp	+= rv;
+		count	-= rv;
+		offset	+= rv;
+		ctr	+= rv;
+	}
+
+	return ctr ? ctr : rv;
+}
+
+ssize_t xpwrite(int fd, void *buf, size_t count, off_t offset)
+{
+	ssize_t ctr = 0;
+	ssize_t rv = 0;
+	char *bp = buf;
+
+	while (count) {
+		rv = pwrite(fd, bp, count, offset);
+
+		if (rv == 0 || (rv == -1 && errno != EINTR))
+			break;
+
+		bp	+= rv;
+		count	-= rv;
+		offset	+= rv;
+		ctr	+= rv;
+	}
+
+	return ctr ? ctr : rv;
+}
diff --git a/usr/kinit/xpio.h b/usr/kinit/xpio.h
new file mode 100644
index 0000000..0596a32
--- /dev/null
+++ b/usr/kinit/xpio.h
@@ -0,0 +1,11 @@
+/*
+ * kinit/xpio.h
+ */
+
+#ifndef KINIT_XPIO_H
+#define KINIT_XPIO_H
+
+ssize_t xpread(int fd, void *buf, size_t count, off_t offset);
+ssize_t xpwrite(int fd, void *buf, size_t count, off_t offset);
+
+#endif				/* KINIT_XPIO_H */
diff --git a/usr/klibc/CAVEATS b/usr/klibc/CAVEATS
new file mode 100644
index 0000000..02b9b9e
--- /dev/null
+++ b/usr/klibc/CAVEATS
@@ -0,0 +1,60 @@
+	  -------------------------------------------------
+	  Please note the following caveats to using klibc:
+	  -------------------------------------------------
+
+optimization:
+-------------
+
+Compiling with -O0 is not supported.  It may or may not work; please
+use -O1 if you want to do maximize debuggability.
+
+Compiling with -O0 is more likely to work on gcc 3.
+
+
+setjmp()/longjmp():
+-------------------
+
+setjmp() and longjmp() *do not* save signal state.  sigsetjmp() and
+siglongjmp() *do* save the signal mask -- regardless of the value of
+the extra argument.
+
+The standards actually state that if you pass longjmp() a final value
+of zero the library should change that to a 1!  Presumably the reason
+is so people who write broken code can get away with writing
+longjmp(buf); or something equally bad.  If you pass longjmp() a final
+value of 0 you get what you deserve -- setjmp() will happily return 0.
+
+
+stdio:
+------
+
+Only a small subset of the stdio functions are implemented.  Those
+that are implemented do not buffer, although they *do* trap EINTR or
+short read/writes and iterate.
+
+_fread() and _fwrite(), which take only one size argument (like
+read/write), but do handle EINTR/short return are also available.
+
+
+namespaces:
+-----------
+
+klibc frequently includes headers in other headers in a way that
+exposes more symbols than POSIX says they should.  "Live with it."
+
+
+theading:
+---------
+
+klibc is not thread-safe.  Consequently, clone() or any of the
+pthreads functions are not included.
+
+
+bsd_signal vs sysv_signal:
+--------------------------
+
+There is no signal() call, because you never know if you want
+Linux/SysV semantics (SA_RESETHAND) or GNU/BSD semantics (SA_RESTART).
+The best, in *any* circumstances, is to never use signal() and instead
+use sigaction(), but in order to simplify porting you can use either
+sysv_signal() or bsd_signal(), depending on what you actually want.
diff --git a/usr/klibc/Kbuild b/usr/klibc/Kbuild
new file mode 100644
index 0000000..ad72116
--- /dev/null
+++ b/usr/klibc/Kbuild
@@ -0,0 +1,179 @@
+#
+# Kbuild file for klibc
+#
+
+# Tell that we are building klibc
+export klibc-build := y
+
+klib-y := vsnprintf.o snprintf.o vsprintf.o sprintf.o \
+	  asprintf.o vasprintf.o \
+	  vsscanf.o sscanf.o ctypes.o \
+	  strntoumax.o strntoimax.o \
+	  atoi.o atol.o atoll.o \
+	  strtol.o strtoll.o strtoul.o strtoull.o \
+	  strtoimax.o strtoumax.o \
+	  globals.o exit.o atexit.o onexit.o \
+	  execl.o execle.o execv.o execvpe.o execvp.o execlp.o execlpe.o \
+	  fork.o vfork.o wait.o wait3.o waitpid.o system.o \
+	  setpgrp.o getpgrp.o daemon.o \
+	  printf.o vprintf.o fprintf.o vfprintf.o perror.o \
+	  statfs.o fstatfs.o umount.o \
+	  creat.o open.o openat.o open_cloexec.o \
+	  fopen.o fread.o fread2.o fgetc.o fgets.o \
+	  fwrite.o fwrite2.o fputc.o fputs.o puts.o putchar.o \
+	  sleep.o usleep.o strtotimespec.o strtotimeval.o \
+	  raise.o abort.o assert.o alarm.o pause.o \
+	  __signal.o sysv_signal.o bsd_signal.o siglist.o sigabbrev.o \
+	  siglongjmp.o \
+	  sigaction.o sigpending.o sigprocmask.o sigsuspend.o \
+	  pselect.o ppoll.o \
+	  brk.o sbrk.o malloc.o realloc.o calloc.o \
+	  mmap.o shm_open.o shm_unlink.o \
+	  memcpy.o memcmp.o memset.o memccpy.o memmem.o memswap.o \
+	  memmove.o memchr.o memrchr.o \
+	  strcasecmp.o strncasecmp.o strndup.o strerror.o strsignal.o \
+	  strcat.o strchr.o strcmp.o strcpy.o strdup.o strlen.o strnlen.o \
+	  strncat.o strlcpy.o strlcat.o \
+	  strstr.o strncmp.o strncpy.o strrchr.o \
+	  strxspn.o strspn.o strcspn.o strpbrk.o strsep.o strtok.o \
+	  fnmatch.o \
+	  gethostname.o getdomainname.o getcwd.o \
+	  seteuid.o setegid.o \
+	  getenv.o setenv.o putenv.o __put_env.o unsetenv.o \
+	  clearenv.o nullenv.o \
+	  getopt.o getopt_long.o readdir.o remove.o \
+	  syslog.o closelog.o pty.o getpt.o isatty.o reboot.o \
+	  time.o utime.o llseek.o nice.o getpriority.o \
+	  qsort.o bsearch.o \
+	  lrand48.o jrand48.o mrand48.o nrand48.o srand48.o seed48.o \
+	  inet/inet_ntoa.o inet/inet_aton.o inet/inet_addr.o \
+	  inet/inet_ntop.o inet/inet_pton.o inet/bindresvport.o \
+	  send.o recv.o \
+	  ctype/isalnum.o ctype/isalpha.o ctype/isascii.o \
+	  ctype/isblank.o ctype/iscntrl.o ctype/isdigit.o \
+	  ctype/isgraph.o ctype/islower.o ctype/isprint.o \
+	  ctype/ispunct.o ctype/isspace.o ctype/isupper.o \
+	  ctype/isxdigit.o ctype/tolower.o ctype/toupper.o \
+	  userdb/getgrgid.o userdb/getgrnam.o userdb/getpwnam.o \
+	  userdb/getpwuid.o userdb/root_group.o userdb/root_user.o
+
+klib-$(CONFIG_KLIBC_ERRLIST) += errlist.o
+
+ifeq ($(CONFIG_KLIBC_ERRLIST),y)
+KLIBCCFLAGS_strerror.o += -DWITH_ERRLIST
+endif
+
+klib-$(CONFIG_KLIBC_ZLIB) += zlib/
+# arch specific .o files
+klib-y += arch/$(KLIBCARCHDIR)/
+
+#####
+# Shared definitions
+LIBC     := libc.a
+SOLIB    := libc.so
+SOHASH   := klibc.so
+CRT0     := arch/$(KLIBCARCHDIR)/crt0.o
+INTERP_O := interp.o
+
+always   := $(LIBC) $(SOLIB) $(SOHASH) $(INTERP_O)
+LIBC     := $(call objectify,$(LIBC))
+SOLIB    := $(call objectify,$(SOLIB))
+SOHASH   := $(call objectify,$(SOHASH))
+CRT0     := $(call objectify,$(CRT0))
+INTERP_O := $(call objectify,$(INTERP_O))
+
+SOLIBHASH = $(shell cat $(SOLIB).hash)
+
+# Generate syscall stubs
+klib-y += syscalls/
+# Generate socket calls stubs
+klib-y += socketcalls/
+
+#####
+# Readable errormessages extracted from src..
+targets += errlist.c
+quiet_cmd_errlist = GEN     $@
+      cmd_errlist = $(PERL) $< $(KLIBCCPPFLAGS) -errlist > $@ || rm -f $@
+
+$(obj)/errlist.c: $(srctree)/$(src)/makeerrlist.pl
+	$(call cmd,errlist)
+
+
+# all .o files for all dirs
+klib-o-files = $(shell cat $(obj)/klib.list \
+		$(addsuffix /klib.list, $(klib-dirs)))
+######
+# Build static library: libc.a
+targets += libc.a __static_init.o
+quiet_cmd_libc = KLIBCAR $@
+      cmd_libc = rm -f $@;						\
+                 $(KLIBCAR) cq $@					\
+		 $(call objectify,__static_init.o) $(klib-o-files);	\
+                 $(KLIBCRANLIB) $@
+
+$(LIBC): $(call objectify,__static_init.o) $(obj)/klib.list FORCE
+	$(call if_changed,libc)
+
+######
+# Build shared library
+targets += libc.so __shared_init.o
+
+quiet_cmd_libcso = KLIBCLD $@
+      cmd_libcso = $(KLIBCLD) $(KLIBCLDFLAGS) $(KLIBCSHAREDFLAGS) -o $@ \
+			--start-group					\
+				$(CRT0)					\
+				$(call objectify,__shared_init.o)	\
+				$(klib-o-files)				\
+				$(KLIBCLIBGCC)				\
+			--end-group
+
+$(SOLIB): $(call objectify,__shared_init.o) $(obj)/klib.list FORCE
+	$(call if_changed,libcso)
+
+
+#####
+# Build sha1 hash values
+targets     += klibc.so libc.so.hash
+hostprogs-y := sha1hash
+clean-files += klibc-???????????????????????????.so
+
+quiet_cmd_solibhash = HASH    $@
+      cmd_solibhash = $(KLIBCNM) $< | egrep '^[0-9a-fA-F]+ [ADRTW] ' | \
+                                        sort | $(obj)/sha1hash > $@
+$(SOLIB).hash: $(SOLIB) $(obj)/sha1hash FORCE
+	$(call if_changed,solibhash)
+
+quiet_cmd_sohash = GEN     $@
+      cmd_sohash = cat $< > $@;                                           \
+                     $(KLIBCSTRIP) $(KLIBCSTRIPFLAGS) $@;                 \
+		     chmod a+x $@;					  \
+                     rm -f $(obj)/klibc-???????????????????????????.so;   \
+                     ln -f $@ $(obj)/klibc-$(SOLIBHASH).so
+$(SOHASH): $(SOLIB) $(SOLIB).hash
+	$(call cmd,sohash)
+
+
+#####
+# build interp.o
+targets += interp.o
+
+quiet_cmd_interp = BUILD   $@
+      cmd_interp = $(KLIBCCC) $(klibccflags) -D__ASSEMBLY__     \
+                             -DLIBDIR=\"$(SHLIBDIR)\"         \
+			     -DSOHASH=\"$(SOLIBHASH)\" \
+			     -c -o $@ $<
+
+$(INTERP_O): $(obj)/interp.S $(SOLIB).hash
+	$(call if_changed,interp)
+
+#####
+# Install klibc
+install-rule:
+	@echo "  INSTALL klibc to $(INSTALLROOT)$(INSTALLDIR)/$(KLIBCCROSS)lib"
+	$(Q)$(foreach f, $(LIBC) $(SOLIB) $(CRT0) $(INTERP_O), \
+	  $(shell $(install-data) $(f) \
+	          $(INSTALLROOT)$(INSTALLDIR)/$(KLIBCCROSS)lib))
+	$(Q)$(install-lib) $(obj)/klibc-$(SOLIBHASH).so \
+	                      $(INSTALLROOT)$(INSTALLDIR)/$(KLIBCCROSS)lib
+	$(Q)$(install-lib) $(obj)/klibc-$(SOLIBHASH).so \
+	                      $(INSTALLROOT)$(SHLIBDIR)
diff --git a/usr/klibc/LICENSE b/usr/klibc/LICENSE
new file mode 100644
index 0000000..aa6d7a7
--- /dev/null
+++ b/usr/klibc/LICENSE
@@ -0,0 +1,73 @@
+This license applies to all files in directory and its subdirectories,
+unless otherwise noted in individual files.
+
+
+Some files are derived from files derived from the include/ directory
+of the Linux kernel, and are licensed under the terms of the GNU
+General Public License, version 2, as released by the Free Software
+Foundation, Inc.; incorporated herein by reference.
+
+				-----
+
+Some files are derived from files copyrighted by the Regents of The
+University of California, and are available under the following
+license:
+
+Note: The advertising clause in the license appearing on BSD Unix
+files was officially rescinded by the Director of the Office of
+Technology Licensing of the University of California on July 22
+1999. He states that clause 3 is "hereby deleted in its entirety."
+
+ * Copyright (c)
+ *	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.
+ * 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.
+
+				-----
+
+For all remaining files, the following license applies:
+
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * Any copyright notice(s) and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+ * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+ * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
diff --git a/usr/klibc/README b/usr/klibc/README
new file mode 100644
index 0000000..5dc2ce2
--- /dev/null
+++ b/usr/klibc/README
@@ -0,0 +1,80 @@
+This is klibc, what is intended to be a minimalistic libc subset for
+use with initramfs.  It is deliberately written for small size,
+minimal entaglement, and portability, not speed.  It is definitely a
+work in progress, and a lot of things are still missing.
+
+
+The build procedure is not very polished yet, but it should work like
+this:
+
+a) In the source root directory (the directory above the one in which
+   this file is found) create a symlink called "linux" pointing to a
+   reasonably recent Linux kernel tree (2.4 or 2.6 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.  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" (2.4) or "make prepare" (2.6).
+
+b) If you're cross-compiling, you need to set KLIBCARCH to the
+   appropriate architecture, and set CROSS_COMPILE to your toolchain
+   prefix.
+
+   IMPORTANT: if you're on a 64-bit machine with a 32-bit userland
+   (ia64, mips64, ppc64 sparc64, s390x or x86_64), and you want to
+   build the 32-bit version: you need to set KLIBCARCH to the 32-bit
+   architecture as well as set up the linux/include/asm symlink to
+   point to the 32-bit architecture.  Building the 32-bit architecture
+   usually (but not always) produces smaller binaries, and is likely
+   to be better tested.
+
+   If you are on ARM, and want to build a thumb version of the library
+   (this is supported), change OPTFLAGS in arch/arm/MCONFIG to build
+   thumb code.
+
+   The following is the last known status of various architectures:
+
+   alpha:	 Working
+   arm-thumb:	 Untested
+   arm:		 Working
+   arm26:	 Not yet ported
+   cris:	 Working
+   h8300:	 Not yet ported
+   i386:	 Working
+   ia64:	 Working
+   m32r:	 Untested
+   m68k:	 Untested
+   m68knommu:	 Not yet ported
+   mips:	 Working
+   mips64:	 Not yet ported
+   parisc:	 Working
+   parisc64:	 Not yet ported
+   ppc:		 Working
+   ppc64:	 Working
+   s390:	 Working static, shared untested
+   s390x:	 Working
+   sh:		 Untested
+   sh64:	 Not yet ported
+   sparc:	 Working
+   sparc64:	 Untested
+   v850:	 Not yet ported
+   x86-64:	 Working
+   xtensa:	 Not yet ported
+
+   Shared library support requires recent binutils on many
+   architectures.
+
+   Note that even the "working" ones likely have bugs.  Please report
+   them if you run into them.
+
+c) Type "make" and pray...
+
+d) Try the test programs in the tests/ directory.  They should run...
+
+Contact the klibc mailing list:
+
+	http://www.zytor.com/mailman/listinfo/klibc
+
+... for more info.
+
+	-hpa
diff --git a/usr/klibc/SOCKETCALLS.def b/usr/klibc/SOCKETCALLS.def
new file mode 100644
index 0000000..70d478f
--- /dev/null
+++ b/usr/klibc/SOCKETCALLS.def
@@ -0,0 +1,21 @@
+/* -*- c -*-
+ *
+ * These are calls that are invoked via the socketcall mechanism
+ * Note that on most architectures this is simply #included into
+ * SYSCALLS.def.
+ */
+<?> int socket(int, int, int);
+<?> int bind(int, struct sockaddr *, int);
+<?> int connect(int, struct sockaddr *, socklen_t);
+<?> int listen(int, int);
+<?> int accept(int, struct sockaddr *, socklen_t *);
+<?> int getsockname(int, struct sockaddr *, socklen_t *);
+<?> int getpeername(int, struct sockaddr *, socklen_t *);
+<?> int socketpair(int, int, int, int *);
+<?> int sendto(int, const void *, size_t, int, const struct sockaddr *, socklen_t);
+<?> int recvfrom(int, void *, size_t, unsigned int, struct sockaddr *, socklen_t *);
+<?> int shutdown(int, int);
+<?> int setsockopt(int, int, int, const void *, socklen_t);
+<?> int getsockopt(int, int, int, void *, socklen_t *);
+<?> int sendmsg(int, const struct msghdr *, unsigned int);
+<?> int recvmsg(int, struct msghdr *, unsigned int);
diff --git a/usr/klibc/SYSCALLS.def b/usr/klibc/SYSCALLS.def
new file mode 100644
index 0000000..c12d525
--- /dev/null
+++ b/usr/klibc/SYSCALLS.def
@@ -0,0 +1,262 @@
+/* -*- c -*-
+ *
+ * This is a list of system calls we invoke "directly".  These
+ * are generated into syscall stubs in their own files, so the
+ * linker can do its job properly.
+ *
+ * The full description of a line is:
+ * [<[?][!]arch,...>] type [sysname,...][@systype][::funcname](args);
+ *
+ * ? means only instantiate this system call if present in asm/unistd.h
+ */
+
+#include <asm/unistd.h>
+#include <klibc/sysconfig.h>
+#include <bitsize.h>
+
+/*
+ * Process-related syscalls
+ */
+void _exit,exit::_exit(int);
+<?!ia64> pid_t clone::__clone(unsigned long, void *);
+<?ia64> pid_t clone::__clone2(unsigned long, void *, void *);
+# if ! _KLIBC_NO_MMU
+<!sparc,sparc64,ia64> pid_t fork();
+<sparc,sparc64> pid_t fork@forkish();
+#endif
+#if _KLIBC_REAL_VFORK
+/*
+ * A lot of architectures need architecture-specific vfork
+ * stubs, due to the no-stack requirement.  These are the
+ * architectures which do not.
+ */
+<alpha,m32r,ppc,ppc64,sh,s390,s390x> pid_t vfork();
+<sparc,sparc64> pid_t vfork@forkish();
+#endif
+<!alpha> pid_t getpid();
+<alpha> pid_t getxpid@dual0::getpid();
+int setpgid(pid_t, pid_t);
+pid_t getpgid(pid_t);
+<!alpha> pid_t getppid();
+<alpha> pid_t getxpid@dual1::getppid();
+pid_t setsid();
+pid_t getsid(pid_t);
+pid_t wait4(pid_t, int *, int, struct rusage *);
+int execve(const char *, char * const *, char * const *);
+<?> int nice(int);
+<alpha,ia64> int getpriority(int, int);
+<!alpha,ia64> int getpriority::__getpriority(int, int);
+int setpriority(int, int, int);
+int sched_setscheduler(pid_t, int, const struct sched_param *);
+int sched_yield();
+<i386> int prctl@varadic(int, unsigned long, unsigned long, unsigned long, unsigned long);
+<!i386> int prctl(int, unsigned long, unsigned long, unsigned long, unsigned long);
+
+/*
+ * User and group IDs
+ */
+int setuid32,setuid::setuid(uid_t);
+int setgid32,setgid::setgid(gid_t);
+<!alpha> uid_t getuid32,getuid::getuid();
+<alpha>  uid_t getxuid@dual0::getuid();
+<!alpha> gid_t getgid32,getgid::getgid();
+<alpha> gid_t getxgid@dual0::getgid();
+<!alpha> uid_t geteuid32,geteuid::geteuid();
+<alpha> uid_t getxuid@dual1::geteuid();
+<!alpha> gid_t getegid32,getegid::getegid();
+<alpha> gid_t getxgid@dual1::getegid();
+int getgroups32,getgroups::getgroups(int, gid_t *);
+int setgroups32,setgroups::setgroups(size_t, const gid_t *);
+int setreuid32,setreuid::setreuid(uid_t, uid_t);
+int setregid32,setregid::setregid(gid_t, gid_t);
+int setfsuid32,setfsuid::setfsuid(uid_t);
+int setfsgid32,setfsgid::setfsgid(gid_t);
+int setresuid32,setresuid::setresuid(int, uid_t, uid_t, uid_t);
+
+/*
+ * Filesystem-related system calls
+ */
+int mount(const char *, const char *, const char *, unsigned long, const void *);
+<!alpha,ia64> int umount2(const char *, int);
+<alpha,ia64> int umount::umount2(const char *, int);
+<?> int pivot_root(const char *, const char *);
+int sync();
+#ifdef __NR_statfs64
+int statfs64::__statfs64(const char *, size_t, struct statfs *);
+#else
+int statfs(const char *, struct statfs *);
+#endif
+#ifdef __NR_fstatfs64
+int fstatfs64::__fstatfs64(int, size_t, struct statfs *);
+#else
+int fstatfs(int, struct statfs *);
+#endif
+int swapon(const char *, int);
+int swapoff(const char *);
+
+/*
+ * Inode-related system calls
+ */
+int access(const char *, int);
+<?> int faccessat(int, const char *, int);
+int link(const char *, const char *);
+<?> int linkat(int, const char *, int, const char *);
+int unlink(const char *);
+<?> int unlinkat(int, const char *);
+int chdir(const char *);
+int fchdir(int);
+int rename(const char *, const char *);
+<?> int renameat(int, const char *, int, const char *);
+int mknod(const char *, mode_t, dev_t);
+<?> int mknodat(int, const char *, const char *, mode_t, dev_t);
+int chmod(const char *, mode_t);
+int fchmod(int, mode_t);
+<?> int fchmodat(int, const char *, mode_t);
+int mkdir(const char *, mode_t);
+<?> int mkdirat(int, const char *, const char *, mode_t);
+int rmdir(const char *);
+<!alpha,ia64,mips,mips64,sparc,sparc64> int pipe(int *);
+mode_t umask(mode_t);
+int chroot(const char *);
+int symlink(const char *, const char *);
+<?> int symlinkat(const char *, int, const char *);
+int readlink(const char *, char *, size_t);
+<?> int readlinkat(int, const char *, char *, int);
+<!ppc64> int stat64,stat::stat(const char *, struct stat *);
+<!ppc64> int lstat64,lstat::lstat(const char *, struct stat *);
+<!ppc64> int fstat64,fstat::fstat(int, struct stat *);
+<ppc64> int stat::stat(const char *, struct stat *);
+<ppc64> int lstat::lstat(const char *, struct stat *);
+<ppc64> int fstat::fstat(int, struct stat *);
+/* XXX: Is this right?! */
+<?> int fstatat64,newstatat,fstatat::fstatat(int, const char *, struct stat *, int);
+int getdents64,getdents::getdents(unsigned int, struct dirent *, unsigned int);
+int chown32,chown::chown(const char *, uid_t, gid_t);
+int fchown32,fchown::fchown(int, uid_t, gid_t);
+<?> int fchownat(int, const char *, uid_t, gid_t, int);
+int lchown32,lchown::lchown(const char *, uid_t, gid_t);
+int getcwd::__getcwd(char *, size_t);
+<?> int utime(const char *, const struct utimbuf *);
+<?> int utimes(const char *, const struct timeval *);
+<?> int futimesat(int, const char *, const struct timeval *);
+<?> int inotify_init();
+<?> int inotify_add_watch(int, const char *, __u32);
+<?> int inotify_rm_watch(int, __u32);
+
+/*
+ * I/O operations
+ */
+<!i386,64> int open::__open(const char *, int, mode_t);
+<?!i386,64> int openat::__openat(int, const char *, int, mode_t);
+<64> int open(const char *, int, mode_t);
+ssize_t read(int, void *, size_t);
+ssize_t write(int, const void *, size_t);
+int close(int);
+<64> off_t lseek(int, off_t, int);
+<32> int _llseek::__llseek(int, unsigned long, unsigned long, off_t *, int);
+int dup(int);
+int dup2(int, int);
+<i386> int fcntl64@varadic::fcntl(int, int, unsigned long);
+<ppc64> int fcntl(int, int, unsigned long);
+<!i386,ppc64> int fcntl64,fcntl::fcntl(int, int, unsigned long);
+int ioctl(int, int, void *);
+int flock(int, int);
+int _newselect,select::select(int, fd_set *, fd_set *, fd_set *, struct timeval *);
+#if defined(__NR_pselect) && !_KLIBC_USE_RT_SIG
+int pselect(int, fd_set *, fd_set *, fd_set *, const struct timespec *, const sigset_t *);
+#elif defined(__NR_pselect7)
+int pselect7::__pselect7(int, fd_set *, fd_set *, fd_set *, struct timespec *, const sigset_t *, size_t);
+#elif defined(__NR_pselect6)
+int pselect6::__pselect6(int, fd_set *, fd_set *, fd_set *, struct timespec *, const struct __pselect6 *);
+#endif
+int poll(struct pollfd *, nfds_t, long);
+<?> int ppoll::__ppoll(struct pollfd *, nfds_t, struct timespec *, const sigset_t *, size_t);
+int fsync(int);
+int fdatasync,fsync::fdatasync(int);
+int readv(int, const struct iovec *, int);
+int writev(int, const struct iovec *, int);
+int ftruncate64,ftruncate::ftruncate(int, off_t);
+ssize_t pread64,pread::pread(int, void *, size_t, off_t);
+ssize_t pwrite64,pwrite::pwrite(int, void *, size_t, off_t);
+int sync_file_range,fdatasync,fsync::sync_file_range(int, off_t, off_t, unsigned int);
+<?> int splice(int, off_t *, int, off_t *, size_t, unsigned int);
+<?> int tee(int, int, size_t, unsigned int);
+ssize_t sendfile64,sendfile::sendfile(int, int, off_t *, size_t, off_t);
+
+/*
+ * Signal operations
+ *
+ * We really should get rid of the non-rt_* of these, but that takes
+ * sanitizing <signal.h> for all architectures, sigh.  See <klibc/config.h>.
+ */
+#if _KLIBC_USE_RT_SIG
+<!sparc,sparc64> int rt_sigaction::__rt_sigaction(int, const struct sigaction *, struct sigaction *, size_t);
+<sparc,sparc64> int rt_sigaction::__rt_sigaction(int, const struct sigaction *, struct sigaction *, void *, size_t);
+int rt_sigsuspend::__rt_sigsuspend(const sigset_t *, size_t);
+int rt_sigpending::__rt_sigpending(sigset_t *, size_t);
+int rt_sigprocmask::__rt_sigprocmask(int, const sigset_t *, sigset_t *, size_t);
+<sparc64> void rt_sigreturn::__sigreturn();
+#else
+int sigaction::__sigaction(int, const struct sigaction *, struct sigaction *);
+int sigsuspend(const sigset_t *);
+int sigpending(sigset_t *);
+int sigprocmask(int, const sigset_t *, sigset_t *);
+#endif
+int kill(pid_t, int);
+<?> unsigned int alarm(unsigned int);
+int getitimer(int, struct itimerval *);
+int setitimer(int, const struct itimerval *, struct itimerval *);
+
+/*
+ * Time-related system calls
+ */
+<?> time_t time(time_t *);
+clock_t times(struct tms *);
+int gettimeofday(struct timeval *, struct timezone *);
+int settimeofday(const struct timeval *, const struct timezone *);
+int nanosleep(const struct timespec *, struct timespec *);
+<?> int pause();
+
+/*
+ * Memory
+ */
+<?> void * brk::__brk(void *);
+int munmap(void *, size_t);
+void * mremap(void *, size_t, size_t, unsigned long);
+int msync(const void *, size_t, int);
+int mprotect(const void *, size_t, int);
+# if _KLIBC_USE_MMAP2
+<!s390> void * mmap2::__mmap2(void *, size_t, int, int, int, long);
+# else
+<!s390x> void * mmap(void *, size_t, int, int, int, long);
+int mlockall(int);
+int munlockall();
+int mlock(const void *, size_t);
+int munlock(const void *, size_t);
+#endif
+
+/*
+ * System stuff
+ */
+int uname(struct utsname *);
+int setdomainname(const char *, size_t);
+int sethostname(const char *, size_t);
+long init_module(void *, unsigned long, const char *);
+long delete_module(const char *, unsigned int);
+int reboot::__reboot(int, int, int, void *);
+int syslog::klogctl(int, char *, int);
+int sysinfo(struct sysinfo *);
+
+/*
+ * Low-level I/O (generally architecture-specific);
+ */
+<i386,x86_64> int iopl(int);
+<i386,x86_64> int ioperm(unsigned long, unsigned long, int);
+<i386> int vm86(struct vm86_struct *);
+
+/*
+ * Most architectures have the socket interfaces using regular
+ * system calls.
+ */
+<?!i386> long socketcall::__socketcall(int, const unsigned long *);
+#include "SOCKETCALLS.def"
diff --git a/usr/klibc/__put_env.c b/usr/klibc/__put_env.c
new file mode 100644
index 0000000..30d415c
--- /dev/null
+++ b/usr/klibc/__put_env.c
@@ -0,0 +1,74 @@
+/*
+ * __put_env.c - common code for putenv() and setenv()
+ */
+
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include "env.h"
+
+static size_t __environ_size;
+static char **__environ_alloc;
+
+/* str should be a duplicated version of the input string;
+   len is the length of the key including the = sign */
+
+int __put_env(char *str, size_t len, int overwrite)
+{
+	static char *const null_environ = { NULL };
+	char **p, *q;
+	char **newenv;
+	size_t n;
+
+	if (!environ)
+		environ = (char **)null_environ;
+
+	n = 1;			/* Include space for final NULL */
+	for (p = environ; (q = *p); p++) {
+		n++;
+		if (!strncmp(q, str, len)) {
+			if (!overwrite)
+				free(str);
+			else
+				*p = str;	/* Possible memory leak... */
+			return 0;
+		}
+	}
+
+	if (__environ_alloc && environ != __environ_alloc) {
+		free(__environ_alloc);
+		__environ_alloc = NULL;
+	}
+
+	/* Need to extend the environment */
+	if (n < __environ_size) {
+		p[1] = NULL;
+		*p = str;
+		return 0;
+	} else {
+		if (__environ_alloc) {
+			newenv =
+			    realloc(__environ_alloc,
+				    (__environ_size << 1) * sizeof(char *));
+			if (!newenv)
+				return -1;
+
+			__environ_size <<= 1;
+		} else {
+			/* Make a reasonable guess how much more space
+			   we need */
+			size_t newsize = n + 32;
+			newenv = malloc(newsize * sizeof(char *));
+			if (!newenv)
+				return -1;
+
+			memcpy(newenv, environ, n * sizeof(char *));
+			__environ_size = newsize;
+		}
+		newenv[n-1] = str;	/* Old NULL position */
+		newenv[n]   = NULL;
+		environ	= newenv;
+	}
+	return 0;
+}
diff --git a/usr/klibc/__shared_init.c b/usr/klibc/__shared_init.c
new file mode 100644
index 0000000..592a3db
--- /dev/null
+++ b/usr/klibc/__shared_init.c
@@ -0,0 +1,2 @@
+#define SHARED 1
+#include "libc_init.c"
diff --git a/usr/klibc/__signal.c b/usr/klibc/__signal.c
new file mode 100644
index 0000000..d174b8e
--- /dev/null
+++ b/usr/klibc/__signal.c
@@ -0,0 +1,20 @@
+/*
+ * __signal.c
+ */
+
+#include <signal.h>
+
+__sighandler_t __signal(int signum, __sighandler_t handler, int flags)
+{
+	struct sigaction sa;
+
+	sa.sa_handler = handler;
+	sa.sa_flags = flags;
+	sigemptyset(&sa.sa_mask);
+
+	if (sigaction(signum, &sa, &sa)) {
+		return (__sighandler_t) SIG_ERR;
+	} else {
+		return (__sighandler_t) sa.sa_handler;
+	}
+}
diff --git a/usr/klibc/__static_init.c b/usr/klibc/__static_init.c
new file mode 100644
index 0000000..0b59eed
--- /dev/null
+++ b/usr/klibc/__static_init.c
@@ -0,0 +1,2 @@
+#define SHARED 0
+#include "libc_init.c"
diff --git a/usr/klibc/abort.c b/usr/klibc/abort.c
new file mode 100644
index 0000000..4629a17
--- /dev/null
+++ b/usr/klibc/abort.c
@@ -0,0 +1,18 @@
+/*
+ * abort.c
+ */
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <signal.h>
+
+void abort(void)
+{
+	sigset_t set;
+
+	sigemptyset(&set);
+	sigaddset(&set, SIGABRT);
+	sigprocmask(SIG_UNBLOCK, &set, NULL);
+	raise(SIGABRT);
+	_exit(255);		/* raise() should have killed us */
+}
diff --git a/usr/klibc/alarm.c b/usr/klibc/alarm.c
new file mode 100644
index 0000000..8bd74c5
--- /dev/null
+++ b/usr/klibc/alarm.c
@@ -0,0 +1,25 @@
+/*
+ * alarm.c
+ */
+
+#include <sys/time.h>
+#include <sys/syscall.h>
+
+#ifndef __NR_alarm
+
+/* Emulate alarm() via setitimer() */
+
+unsigned int alarm(unsigned int seconds)
+{
+	struct itimerval iv;
+
+	iv.it_interval.tv_sec = iv.it_interval.tv_usec = 0;
+	iv.it_value.tv_sec = seconds;
+	iv.it_value.tv_usec = 0;
+
+	setitimer(ITIMER_REAL, &iv, &iv);
+
+	return iv.it_value.tv_sec + (iv.it_value.tv_usec ? 1 : 0);
+}
+
+#endif
diff --git a/usr/klibc/arch/README b/usr/klibc/arch/README
new file mode 100644
index 0000000..662b9d3
--- /dev/null
+++ b/usr/klibc/arch/README
@@ -0,0 +1,81 @@
+To port klibc to a new architecture, you need:
+
+a) A directory structure
+
+Each archtecture has a klibc/arch/ directory, which should include an
+MCONFIG and a Makefile.inc file, and an include/arch/ directory, which
+includes some architecture-specific header files, including
+klibc/archconfig.h.
+
+
+b) Architecture-specific configuration
+   (include/arch/*/klibc/sysconfig.h)
+
+This file can set configuration variables from
+include/klibc/sysconfig.h.
+
+
+c) Startup code
+   (klibc/arch/*/crt0.S)
+
+The crt0.S assembly routine typically corresponds to the following
+pseudo-C code.  In addition, each architecture needs any support
+routines that gcc-generated code expects to find in the system library
+-- Alpha, for example, needs divide subroutines.
+
+The "getenvtest" test program is a very good test for proper crt0.S
+functionality.
+
+
+extern __noreturn __libc_init(void *, void *);
+
+__noreturn _start(void)
+{
+  void *elf_data   = get_elf_data_address(); /* Usually the stack address */
+  void *atexit_ptr = get_atexit_ptr();       /* Usually in a register */
+
+  /* Some architectures need this for debugging to work */
+  setup_null_stack_frame_if_necessary();
+
+  __libc_init(elf_data, atexit_ptr);
+}
+
+
+d) A setenv implementation
+   (klibc/arch/*/setjmp.S, include/arch/*klibc/archsetjmp.h)
+
+On most (but not all!) architectures, this entails creating a setjmp
+buffer big enough to hold all callee-saved registers, plus the stack
+pointer and the return address.  In setjmp.S you have:
+
+* A "setjmp" function that writes out the callee-saved registers, the
+  stack pointer and the return address to the buffer pointed to by the
+  first argument, and then returns zero normally.
+
+  On some architectures you need to take some kind of action to make
+  sure the contents of the stack is actually manifest in memory and
+  not cached in the CPU.  In some cases (e.g. on SPARC) this will
+  automatically spill the registers onto the stack; then they don't
+  need to be spilled into the jmp_buf.
+
+* A "longjmp" function that read back these same registers from the
+  jmp_buf pointed to by the first argument, and returns the second
+  argument *to the address specified in the jmp_buf*.
+
+  On some architectures you need to take some kind of action to flush
+  any cached stack data or return stack.
+
+
+e) Any support functions needed by gcc, *unless* they are in libgcc
+  *and* libgcc is usable for klibc on your particular platform.  If
+  libgcc isn't usable for klibc (on MIPS, for example, libgcc is
+  compiled in a way that is not compatible with klibc) there are
+  reasonably good clones of most of the libgcc functions in the libgcc
+  directory.  To use them, add them to ARCHOBJS in
+  klibc/arch/*/Makefile.inc.
+
+
+f) A link location for the shared klibc.  This should be specified in
+  SHAREDFLAGS in klibc/arch/*/MCONFIG.
+
+  This is not applicable to no-MMU architectures.
diff --git a/usr/klibc/arch/alpha/Kbuild b/usr/klibc/arch/alpha/Kbuild
new file mode 100644
index 0000000..f5c30f3
--- /dev/null
+++ b/usr/klibc/arch/alpha/Kbuild
@@ -0,0 +1,52 @@
+# -*- makefile -*-
+#
+# arch/alpha/Makefile.inc
+#
+# Special rules for this architecture.  Note that this is actually
+# included from the main Makefile, and that pathnames should be
+# accordingly.
+#
+
+always  := crt0.o
+targets := crt0.o
+klib-y := pipe.o setjmp.o syscall.o sysdual.o
+
+# Special CFLAGS for the divide code
+DIVCFLAGS = $(KLIBCREQFLAGS) $(KLIBCARCHREQFLAGS) \
+	-O3 -fomit-frame-pointer -fcall-saved-1 -fcall-saved-2 \
+	-fcall-saved-3 -fcall-saved-4 -fcall-saved-5 -fcall-saved-6 \
+	-fcall-saved-7 -fcall-saved-8 -ffixed-15 -fcall-saved-16 \
+	-fcall-saved-17 -fcall-saved-18 -fcall-saved-19 -fcall-saved-20 \
+	-fcall-saved-21 -fcall-saved-22 -ffixed-23 -fcall-saved-24 \
+	-ffixed-25 -ffixed-27
+
+div-objs := __divqu.o __remqu.o __divq.o __remq.o
+div-objs += __divlu.o __remlu.o __divl.o __reml.o
+klib-y += $(div-objs)
+
+quiet_cmd_regswap = REGSWAP $@
+      cmd_regswap = sed -e 's/\$$0\b/$$27/g'  -e 's/\$$24\b/$$99/g' \
+                        -e 's/\$$16\b/$$24/g' -e 's/\$$17\b/$$25/g' \
+                        -e 's/\$$26\b/$$23/g' -e 's/\$$99\b/$$16/g' < $< > $@
+
+# Use static pattern rule to avoid using a temporary file
+$(addprefix $(obj)/,$(div-objs:.o=.S)): $(obj)/%.S: $(obj)/%.ss
+	$(call if_changed,regswap)
+
+quiet_cmd_genss = DIV-CC  $@
+      cmd_genss = $(CC) $(DIVCFLAGS) $(FILE_CFLAGS) \
+                        -DNAME=$(basename $(notdir $@)) -S -o $@ $<
+
+$(obj)/%.ss: $(obj)/divide.c
+	$(call if_changed,genss)
+
+$(obj)/__divqu.ss: FILE_CFLAGS := -DSIGNED=0 -DREM=0 -DBITS=64
+$(obj)/__remqu.ss: FILE_CFLAGS := -DSIGNED=0 -DREM=1 -DBITS=64
+$(obj)/__divq.ss:  FILE_CFLAGS := -DSIGNED=1 -DREM=0 -DBITS=64
+$(obj)/__remq.ss:  FILE_CFLAGS := -DSIGNED=1 -DREM=1 -DBITS=64
+$(obj)/__divlu.ss: FILE_CFLAGS := -DSIGNED=0 -DREM=0 -DBITS=32
+$(obj)/__remlu.ss: FILE_CFLAGS := -DSIGNED=0 -DREM=1 -DBITS=32
+$(obj)/__divl.ss:  FILE_CFLAGS := -DSIGNED=1 -DREM=0 -DBITS=32
+$(obj)/__reml.ss:  FILE_CFLAGS := -DSIGNED=1 -DREM=1 -DBITS=32
+
+targets     += $(div-objs:.o=.S) $(div-objs:.o=.ss)
diff --git a/usr/klibc/arch/alpha/MCONFIG b/usr/klibc/arch/alpha/MCONFIG
new file mode 100644
index 0000000..e7dc61a
--- /dev/null
+++ b/usr/klibc/arch/alpha/MCONFIG
@@ -0,0 +1,16 @@
+# -*- makefile -*-
+#
+# arch/alpha/MCONFIG
+#
+# Build configuration for this architecture
+#
+
+KLIBCOPTFLAGS += -Os
+KLIBCBITSIZE  = 64
+
+# Extra linkflags when building the shared version of the library
+# This address needs to be reachable using normal inter-module
+# calls, and work on the memory models for this architecture
+# 7 GB - normal binaries start at 4.5 GB, and the stack is below
+# the binary.
+KLIBCSHAREDFLAGS	= -Ttext 0x1c0000200
diff --git a/usr/klibc/arch/alpha/README-gcc b/usr/klibc/arch/alpha/README-gcc
new file mode 100644
index 0000000..1d0052f
--- /dev/null
+++ b/usr/klibc/arch/alpha/README-gcc
@@ -0,0 +1,22 @@
+   The current Alpha chips don't provide hardware for integer
+   division.  The C compiler expects the functions
+
+        __divqu: 64-bit unsigned long divide
+        __remqu: 64-bit unsigned long remainder
+        __divq/__remq:   signed 64-bit
+        __divlu/__remlu: unsigned 32-bit
+        __divl/__reml:   signed 32-bit
+
+   These are not normal C functions: instead of the normal calling
+   sequence, these expect their arguments in registers t10 and t11, and
+   return the result in t12 (aka pv).  Register AT may be clobbered
+   (assembly temporary), anything else must be saved.
+
+   Furthermore, the return address is in t9 instead of ra.
+
+   Normal function	Divide functions
+   ---------------	----------------
+   v0 ($0)		t12/pv ($27)
+   a0 ($16)		t10 ($24)
+   a1 ($17)		t11 ($25)
+   ra ($26)		t9 ($23)
diff --git a/usr/klibc/arch/alpha/crt0.S b/usr/klibc/arch/alpha/crt0.S
new file mode 100644
index 0000000..5e2babb
--- /dev/null
+++ b/usr/klibc/arch/alpha/crt0.S
@@ -0,0 +1,22 @@
+#
+# arch/alpha/crt0.S
+#
+
+	.text
+	.type	_start,@function
+	.ent	_start, 0
+	.globl	_start
+_start:
+	.frame  $30, 0, $26, 0
+	mov	$31, $15
+	br	$29, 1f
+1:	ldgp	$29, 0($29)
+	.prologue 0
+
+	lda	$16, 0($30)		# ELF data structure
+	lda	$17, 0($0)		# atexit pointer
+
+	jsr	$26, __libc_init
+
+	.size	_start,.-_start
+	.end	_start
diff --git a/usr/klibc/arch/alpha/divide.c b/usr/klibc/arch/alpha/divide.c
new file mode 100644
index 0000000..c44254f
--- /dev/null
+++ b/usr/klibc/arch/alpha/divide.c
@@ -0,0 +1,59 @@
+#include <stdint.h>
+#include <asm/gentrap.h>
+#include <asm/pal.h>
+
+#if BITS == 64
+typedef uint64_t uint;
+typedef int64_t sint;
+#else
+typedef uint32_t uint;
+typedef int32_t sint;
+#endif
+
+#ifdef SIGNED
+typedef sint xint;
+#else
+typedef uint xint;
+#endif
+
+xint NAME(uint num, uint den)
+{
+	uint quot = 0, qbit = 1;
+	int minus = 0;
+	xint v;
+
+	if (den == 0) {
+		/* This is really $16, but $16 and $24 are exchanged by a script */
+		register unsigned long cause asm("$24") = GEN_INTDIV;
+		asm volatile ("call_pal %0"::"i" (PAL_gentrap), "r"(cause));
+		return 0;	/* If trap returns... */
+	}
+#if SIGNED
+	if ((sint) (num ^ den) < 0)
+		minus = 1;
+	if ((sint) num < 0)
+		num = -num;
+	if ((sint) den < 0)
+		den = -den;
+#endif
+
+	/* Left-justify denominator and count shift */
+	while ((sint) den >= 0) {
+		den <<= 1;
+		qbit <<= 1;
+	}
+
+	while (qbit) {
+		if (den <= num) {
+			num -= den;
+			quot += qbit;
+		}
+		den >>= 1;
+		qbit >>= 1;
+	}
+
+	v = (xint) (REM ? num : quot);
+	if (minus)
+		v = -v;
+	return v;
+}
diff --git a/usr/klibc/arch/alpha/pipe.S b/usr/klibc/arch/alpha/pipe.S
new file mode 100644
index 0000000..ee72413
--- /dev/null
+++ b/usr/klibc/arch/alpha/pipe.S
@@ -0,0 +1,38 @@
+#
+# arch/alpha/pipe.S
+#
+
+#
+# pipe() on alpha returns both file descriptors in registers --
+# $0 (v0) and $20 (a4) respectively.  This is unlike any other system call,
+# as far as I can tell.
+#
+
+#include <asm/unistd.h>
+#include <machine/asm.h>
+
+	.text
+	.align	3
+	.type	pipe, @function
+	.ent	pipe, 0
+	.globl	pipe
+pipe:
+	.frame	sp,0,ra,0
+	lda	v0, __NR_pipe
+	callsys
+	beq	a3, 1f
+	br	pv, 2f			# pv <- pc
+2:
+	ldgp	gp, 0(pv)
+	lda	a1, errno
+	lda	v0, -1(zero)
+	stl	a3, 0(a1)
+	ret	zero,(ra),1
+1:
+	stl	v0, 0(a0)
+	lda	v0, 0
+	stl	a4, 4(a0)
+	ret	zero,(ra),1
+
+	.size	pipe,.-pipe
+	.end	pipe
diff --git a/usr/klibc/arch/alpha/setjmp.S b/usr/klibc/arch/alpha/setjmp.S
new file mode 100644
index 0000000..ed604bd
--- /dev/null
+++ b/usr/klibc/arch/alpha/setjmp.S
@@ -0,0 +1,75 @@
+#
+# setjmp.S
+#
+
+#
+# The jmp_buf looks like:
+#
+#	s0..5
+#	fp
+#	ra
+#	gp
+#	sp
+#
+
+#include <machine/asm.h>
+
+	.text
+	.align	3
+	.type	setjmp,@function
+	.ent	setjmp, 0
+	.globl	setjmp
+setjmp:
+	lda	v0,   0(zero)
+	stq	s0,   0(a0)
+	stq	s1,   8(a0)
+	stq	s2,  16(a0)
+	stq	s3,  24(a0)
+	stq	s4,  32(a0)
+	stq	s5,  40(a0)
+	stq	fp,  48(a0)
+	stq	ra,  56(a0)
+	stq	gp,  64(a0)
+	stq	sp,  72(a0)
+	stt	$f2,  80(a0)
+	stt	$f3,  88(a0)
+	stt	$f4,  96(a0)
+	stt	$f5, 104(a0)
+	stt	$f6, 112(a0)
+	stt	$f7, 120(a0)
+	stt	$f8, 128(a0)
+	stt	$f9, 136(a0)
+	ret	zero,(ra),1
+
+	.size setjmp,.-setjmp
+	.end setjmp
+
+	.type	longjmp,@function
+	.ent	longjmp, 0
+	.globl	longjmp
+longjmp:
+	mov	a1, v0
+	ldq	s0,   0(a0)
+	ldq	s1,   8(a0)
+	ldq	s2,  16(a0)
+	ldq	s3,  24(a0)
+	ldq	s4,  32(a0)
+	ldq	s5,  40(a0)
+	ldq	fp,  48(a0)
+	ldq	ra,  56(a0)
+	ldq	gp,  64(a0)
+	ldq	sp,  72(a0)
+	ldt	$f2,  80(a0)
+	ldt	$f3,  88(a0)
+	ldt	$f4,  96(a0)
+	ldt	$f5, 104(a0)
+	ldt	$f6, 112(a0)
+	ldt	$f7, 120(a0)
+	ldt	$f8, 128(a0)
+	ldt	$f9, 136(a0)
+	/* We're bound to get a mispredict here, but at least give us
+	   a chance to get the return stack back in sync... */
+	ret	zero,(ra),1
+
+	.size longjmp,.-longjmp
+	.end longjmp
diff --git a/usr/klibc/arch/alpha/syscall.S b/usr/klibc/arch/alpha/syscall.S
new file mode 100644
index 0000000..ae69ef2
--- /dev/null
+++ b/usr/klibc/arch/alpha/syscall.S
@@ -0,0 +1,26 @@
+#
+# arch/alpha/syscall.S
+#
+
+#include <machine/asm.h>
+
+	.text
+	.align	3
+	.type	__syscall_common,@function
+	.ent	__syscall_common, 0
+	.globl	__syscall_common
+__syscall_common:
+	.frame	sp,0,ra,0
+	callsys
+	beq	a3, 1f
+	br	pv, 2f			# pv <- pc
+2:
+	ldgp	gp, 0(pv)
+	lda	a1, errno
+	stl	v0, 0(a1)
+	lda	v0, -1(zero)
+1:
+	ret	zero,(ra),1
+
+	.size	__syscall_common,.-__syscall_common
+	.end	__syscall_common
diff --git a/usr/klibc/arch/alpha/sysdual.S b/usr/klibc/arch/alpha/sysdual.S
new file mode 100644
index 0000000..1719e37
--- /dev/null
+++ b/usr/klibc/arch/alpha/sysdual.S
@@ -0,0 +1,33 @@
+#
+# arch/alpha/sysdual.S
+#
+
+#
+# Some system calls have an alternate return value in r20 (a4).
+# This system call stub is for system calls where that is
+# the "real" return value.
+#
+
+#include <machine/asm.h>
+
+	.text
+	.align	3
+	.type	__syscall_dual1,@function
+	.ent	__syscall_dual1, 0
+	.globl	__syscall_dual1
+__syscall_dual1:
+	.frame	sp,0,ra,0
+	callsys
+	mov	v0, a4
+	beq	a3, 1f
+	br	pv, 2f			# pv <- pc
+2:
+	ldgp	gp, 0(pv)
+	lda	a1, errno
+	lda	v0, -1(zero)
+	stl	a3, 0(a1)
+1:
+	ret	zero,(ra),1
+
+	.size	__syscall_dual1,.-__syscall_dual1
+	.end	__syscall_dual1
diff --git a/usr/klibc/arch/alpha/sysstub.ph b/usr/klibc/arch/alpha/sysstub.ph
new file mode 100644
index 0000000..08b97e8
--- /dev/null
+++ b/usr/klibc/arch/alpha/sysstub.ph
@@ -0,0 +1,37 @@
+# -*- perl -*-
+#
+# arch/alpha/sysstub.ph
+#
+# Script to generate system call stubs
+#
+
+# On Alpha, most system calls follow the standard convention, with the
+# system call number in r0 (v0), return an error value in r19 (a3) as
+# well as the return value in r0 (v0).
+#
+# A few system calls are dual-return with the second return value in
+# r20 (a4).
+
+sub make_sysstub($$$$$@) {
+    my($outputdir, $fname, $type, $sname, $stype, @args) = @_;
+
+    $stype = $stype || 'common';
+    $stype = 'common' if ( $stype eq 'dual0' );
+
+    open(OUT, '>', "${outputdir}/${fname}.S");
+    print OUT "#include <asm/unistd.h>\n";
+    print OUT "#include <machine/asm.h>\n";
+    print OUT "\n";
+    print OUT "\t.text\n";
+    print OUT "\t.type ${fname},\@function\n";
+    print OUT "\t.ent\t${fname}, 0\n"; # What is this?
+    print OUT "\t.globl ${fname}\n";
+    print OUT "${fname}:\n";
+    print OUT "\tlda\tv0, __NR_${sname}(zero)\n";
+    print OUT "\tbr __syscall_${stype}\n";
+    print OUT "\t.size\t${fname},.-${fname}\n";
+    print OUT "\t.end\t${fname}\n";
+    close(OUT);
+}
+
+1;
diff --git a/usr/klibc/arch/arm/Kbuild b/usr/klibc/arch/arm/Kbuild
new file mode 100644
index 0000000..4946b6b
--- /dev/null
+++ b/usr/klibc/arch/arm/Kbuild
@@ -0,0 +1,13 @@
+#
+# klibc files for arm
+#
+
+klib-y := setjmp.o syscall.o vfork.o aeabi_nonsense.o
+
+klib-y += ../../libgcc/__udivmodsi4.o ../../libgcc/__divdi3.o
+klib-y += ../../libgcc/__moddi3.o     ../../libgcc/__udivdi3.o
+klib-y += ../../libgcc/__umoddi3.o    ../../libgcc/__udivmoddi4.o
+klib-y += ../../libgcc/__clzsi2.o
+
+always  := crt0.o
+targets := crt0.o
diff --git a/usr/klibc/arch/arm/MCONFIG b/usr/klibc/arch/arm/MCONFIG
new file mode 100644
index 0000000..418ba01
--- /dev/null
+++ b/usr/klibc/arch/arm/MCONFIG
@@ -0,0 +1,35 @@
+# -*- makefile -*-
+#
+# arch/arm/MCONFIG
+#
+# Special rules for this architecture.  Note that this is actually
+# included from the main Makefile, and that pathnames should be
+# accordingly.
+#
+
+CPU_ARCH := armv4
+CPU_TUNE := strongarm
+
+KLIBCOPTFLAGS += -Os -march=$(CPU_ARCH) -mtune=$(CPU_TUNE)
+KLIBCBITSIZE  = 32
+KLIBCREQFLAGS += -fno-exceptions
+KLIBCSTRIPFLAGS += -R .ARM.exidx
+
+ifeq ($(CONFIG_KLIBC_THUMB),y)
+CPU_ARCH := $(CPU_ARCH)t
+KLIBCREQFLAGS += -mthumb
+KLIBCLDFLAGS  += --thumb-entry _start
+KLIBCEMAIN     = --thumb-entry _start
+KLIBCREQFLAGS += -mabi=aapcs-linux
+KLIBCSHAREDFLAGS = -Ttext 0x380200
+else
+# Extra linkflags when building the shared version of the library
+# This address needs to be reachable using normal inter-module
+# calls, and work on the memory models for this architecture
+KLIBCSHAREDFLAGS = -Ttext 0x01800200
+ifeq ($(CONFIG_AEABI),y)
+KLIBCREQFLAGS += -mabi=aapcs-linux -mno-thumb-interwork
+else
+KLIBCREQFLAGS += -mabi=apcs-gnu -mno-thumb-interwork
+endif
+endif
diff --git a/usr/klibc/arch/arm/__muldi3.c b/usr/klibc/arch/arm/__muldi3.c
new file mode 100644
index 0000000..3fdeb2b
--- /dev/null
+++ b/usr/klibc/arch/arm/__muldi3.c
@@ -0,0 +1,15 @@
+#include <stdint.h>
+
+uint64_t __muldi3(uint64_t a, uint64_t b)
+{
+	uint32_t al = (uint32_t)a;
+	uint32_t ah = (uint32_t)(a >> 32);
+	uint32_t bl = (uint32_t)b;
+	uint32_t bh = (uint32_t)(b >> 32);
+	uint64_t v;
+
+	v = (uint64_t)al * bl;
+	v += (uint64_t)(al*bh+ah*bl) << 32;
+
+	return v;
+}
diff --git a/usr/klibc/arch/arm/aeabi_nonsense.S b/usr/klibc/arch/arm/aeabi_nonsense.S
new file mode 100644
index 0000000..c69eb11
--- /dev/null
+++ b/usr/klibc/arch/arm/aeabi_nonsense.S
@@ -0,0 +1,9 @@
+	.text
+	.globl	__aeabi_unwind_cpp_pr0
+__aeabi_unwind_cpp_pr0:
+	.globl	__aeabi_unwind_cpp_pr1
+__aeabi_unwind_cpp_pr1:
+	.globl	__aeabi_unwind_cpp_pr2
+__aeabi_unwind_cpp_pr2:
+	.globl	__aeabi_unwind_cpp_pr3
+__aeabi_unwind_cpp_pr3:
diff --git a/usr/klibc/arch/arm/crt0.S b/usr/klibc/arch/arm/crt0.S
new file mode 100644
index 0000000..1e81f8e
--- /dev/null
+++ b/usr/klibc/arch/arm/crt0.S
@@ -0,0 +1,23 @@
+#
+# arch/arm/crt0.S
+#
+# void _start(void)
+# {
+#    __libc_init(elf_structure, atexit_ptr);
+# }
+#
+
+	.text
+	.balign 4
+	.type _start,#function
+	.globl _start
+
+#ifdef __thumb__
+	.thumb_func
+#endif
+
+_start:	mov	r0, sp
+	mov	r1, #0
+	bl	__libc_init
+
+	.size _start,.-_start
diff --git a/usr/klibc/arch/arm/setjmp.S b/usr/klibc/arch/arm/setjmp.S
new file mode 100644
index 0000000..2232458
--- /dev/null
+++ b/usr/klibc/arch/arm/setjmp.S
@@ -0,0 +1,102 @@
+#
+# arch/arm/setjmp.S
+#
+# setjmp/longjmp for the ARM architecture
+#
+
+#ifndef	__thumb__
+
+#
+# "Pure ARM" version
+#
+# The jmp_buf is assumed to contain the following, in order:
+#		r4
+#		r5
+#		r6
+#		r7
+#		r8
+#		r9
+#		r10
+#		fp
+#		sp
+#		lr
+#
+
+	.text
+	.balign 4
+	.globl setjmp
+	.type setjmp, #function
+setjmp:
+	stmia	r0, {r4, r5, r6, r7, r8, r9, r10, fp, sp, lr}
+	mov	r0, #0
+	mov	pc, lr
+	.size setjmp,.-setjmp
+
+	.text
+	.balign 4
+	.globl longjmp
+	.type longjmp, #function
+longjmp:
+	ldmia	r0, {r4, r5, r6, r7, r8, r9, r10, fp, sp, lr}
+	mov	r0, r1
+	mov	pc, lr
+	.size longjmp,.-longjmp
+
+#else /* __thumb__ */
+
+#
+# Thumb version
+#
+# The jmp_buf is assumed to contain the following, in order:
+#		lr
+#		r4
+#		r5
+#		r6
+#		r7
+#		r8
+#		r9
+#		r10
+#		fp
+#		sp
+#
+
+	.text
+	.balign 4
+	.globl setjmp
+	.type setjmp, #function
+	.thumb_func
+setjmp:
+	mov	r3, lr
+	stmia	r0!, {r3, r4, r5, r6, r7}
+	mov	r3, r8
+	mov	r4, r9
+	mov	r5, r10
+	mov	r6, fp
+	mov	r7, sp
+	stmia	r0!, {r3, r4, r5, r6, r7}
+	mov	r0, #0
+	mov	pc, lr
+	.size setjmp,.-setjmp
+
+	.text
+	.balign 4
+	.globl longjmp
+	.type longjmp, #function
+	.thumb_func
+longjmp:
+	mov	r2, r0
+	add	r0, #5*4
+	ldmia	r0!, {r3, r4, r5, r6, r7}
+	mov	r8, r3
+	mov	r9, r4
+	mov	r10, r5
+	mov	fp, r6
+	mov	sp, r7
+	ldmia	r2!, {r3, r4, r5, r6, r7}
+	mov	r0, r1
+	bne	1f
+	mov	r0, #1
+1:	mov	pc, r3
+	.size longjmp,.-longjmp
+
+#endif /* __thumb__ */
diff --git a/usr/klibc/arch/arm/syscall.S b/usr/klibc/arch/arm/syscall.S
new file mode 100644
index 0000000..e5b04e2
--- /dev/null
+++ b/usr/klibc/arch/arm/syscall.S
@@ -0,0 +1,65 @@
+/*
+ * arch/arm/syscall.S
+ *
+ * System call common handling
+ */
+
+	.type	__syscall_common,#function
+	.globl	__syscall_common
+#ifndef __thumb__
+	/* ARM version - this is executed after the swi, unless
+	   we are compiled in EABI mode */
+
+	.balign	4
+__syscall_common:
+#ifdef __ARM_EABI__
+	ldr	r4, [sp,#16]
+	ldr	r5, [sp,#20]
+	ldr	r7, [lr]
+	swi	0
+#endif
+        cmn     r0, #4096
+        rsbcs	r2, r0, #0
+        ldrcs	r3, 1f
+        mvncs	r0, #0
+        strcs	r2, [r3]
+#ifdef __ARM_EABI__
+	ldmfd	sp!,{r4,r5,r7,pc}
+#else
+	ldmfd	sp!,{r4,r5,pc}
+#endif
+
+	.balign 4
+1:
+	.word	errno
+
+#else
+	/* Thumb version - must still load r4 and r5 and run swi */
+
+	.thumb_func
+	.balign	2
+__syscall_common:
+	mov	r7, lr
+	ldr	r4, [sp,#16]
+	sub	r7, #1		/* Remove the Thumb bit */
+	ldr	r5, [sp,#20]
+	ldrh	r7, [r7]
+	swi	0
+	ldr	r1, 2f
+	cmp	r0, r1
+	bcc	1f
+	ldr	r1, 3f
+	neg	r2, r0
+	mov	r0, #1
+	str	r2, [r1]
+	neg	r0, r0
+1:
+	pop	{r4,r5,r7,pc}
+
+	.balign	4
+2:
+	.word	-4095
+3:
+	.word	errno
+
+#endif
diff --git a/usr/klibc/arch/arm/sysstub.ph b/usr/klibc/arch/arm/sysstub.ph
new file mode 100644
index 0000000..d51ace1
--- /dev/null
+++ b/usr/klibc/arch/arm/sysstub.ph
@@ -0,0 +1,58 @@
+# -*- perl -*-
+#
+# arch/arm/sysstub.ph
+#
+# Script to generate system call stubs
+#
+
+
+sub make_sysstub($$$$$@) {
+    my($outputdir, $fname, $type, $sname, $stype, @args) = @_;
+
+    open(OUT, '>', "${outputdir}/${fname}.S");
+    print  OUT "#include <asm/unistd.h>\n";
+    print  OUT "#include <klibc/asmmacros.h>\n";
+
+    print  OUT "	.text\n";
+    print  OUT "	.type	${fname}, #function\n";
+    print  OUT "	.globl	${fname}\n";
+
+    print  OUT "#ifndef __thumb__\n";
+
+    print  OUT "#ifndef __ARM_EABI__\n";
+
+    # ARM version first
+    print  OUT "	.balign	4\n";
+    print  OUT "${fname}:\n";
+    print  OUT "	stmfd	sp!,{r4,r5,lr}\n";
+    print  OUT "	ldr	r4,[sp,#12]\n";
+    print  OUT "	ldr	r5,[sp,#16]\n";
+    print  OUT "	swi	# __NR_${sname}\n";
+    print  OUT "	b	__syscall_common\n";
+
+    print  OUT "#else /* __ARM_EABI__ */\n";
+
+    # ARM EABI version
+    print  out "	.balign	4\n";
+    print  OUT "${fname}:\n";
+    print  OUT "	stmfd	sp!,{r4,r5,r7,lr}\n";
+    print  OUT "	bl	__syscall_common\n";
+    print  OUT "	.word	__NR_${sname}\n";
+
+    print  OUT "#endif /* __ARM_EABI__ */\n";
+    print  OUT "#else /* __thumb__ */\n";
+
+    # Thumb version
+    print  OUT "	.balign	8\n";
+    print  OUT "	.thumb_func\n";
+    print  OUT "${fname}:\n";
+    print  OUT "	push	{r4,r5,r7,lr}\n";
+    print  OUT "	bl	__syscall_common\n";
+    print  OUT "	.short	__NR_${sname}\n";
+
+    print  OUT "#endif /* __thumb__*/\n";
+
+    print  OUT "	.size	__syscall${i},.-__syscall${i}\n";
+}
+
+1;
diff --git a/usr/klibc/arch/arm/vfork.S b/usr/klibc/arch/arm/vfork.S
new file mode 100644
index 0000000..3b2d9f75
--- /dev/null
+++ b/usr/klibc/arch/arm/vfork.S
@@ -0,0 +1,60 @@
+/*
+ * arch/arm/vfork.S
+ *
+ * vfork - nasty system call which must not use the stack.
+ */
+
+#include <asm/unistd.h>
+
+	.type	vfork,#function
+	.globl	vfork
+#ifndef __thumb__
+
+	.balign	4
+vfork:
+#ifdef	__ARM_EABI__
+	mov	r3, r7
+	mov	r7, # __NR_vfork
+	swi	0
+	mov	r7, r3
+#else
+	swi	# __NR_vfork
+#endif
+        cmn     r0, #4096
+        rsbcs	r2, r0, #0
+        ldrcs	r3, 1f
+        mvncs	r0, #0
+        strcs	r2, [r3]
+	mov	pc, lr
+
+	.balign 4
+1:
+	.word	errno
+
+#else
+
+	.thumb_func
+	.balign	2
+vfork:
+	mov	r3, r7
+	mov	r7, # __NR_vfork
+	swi	0
+	mov	r7, r3
+	ldr	r1, 2f
+	cmp	r0, r1
+	bcc	1f
+	ldr	r1, 3f
+	neg	r2, r0
+	mov	r0, #1
+	str	r2, [r1]
+	neg	r0, r0
+1:
+	mov	pc, lr
+
+	.balign	4
+2:
+	.word	-4095
+3:
+	.word	errno
+
+#endif
diff --git a/usr/klibc/arch/cris/Kbuild b/usr/klibc/arch/cris/Kbuild
new file mode 100644
index 0000000..13ceeec
--- /dev/null
+++ b/usr/klibc/arch/cris/Kbuild
@@ -0,0 +1,28 @@
+#
+# klibc files fora cris
+#
+
+always  := crt0.o
+targets := crt0.o
+
+klib-y += __negdi2.o setjmp.o syscall.o vfork.o
+
+klib-y += ../../libgcc/__divdi3.o     ../../libgcc/__moddi3.o
+klib-y += ../../libgcc/__udivdi3.o    ../../libgcc/__umoddi3.o
+klib-y += ../../libgcc/__udivmoddi4.o
+
+# Divide support
+klib-y := __Umod.o __Udiv.o __Mod.o __Div.o
+
+quiet_cmd_cc-div = DIV-CC  $@
+      cmd_cc-div = $(KLIBCC) $(klibccflags) -c -o $@ $<
+
+
+$(obj)/__Umod.o: $(src)/divide.c
+KLIBCCFLAGS___Umod.o := -DSIGNED=0 -DREM=1 -DBITS=32 -DNAME=__Umod
+$(obj)/__Udiv.o: $(src)/divide.c
+KLIBCCFLAGS___Udiv.o := -DSIGNED=0 -DREM=0 -DBITS=32 -DNAME=__Udiv
+$(obj)/__Mod.o: $(src)/divide.c
+KLIBCCFLAGS___Mod.o  := -DSIGNED=1 -DREM=1 -DBITS=32 -DNAME=__Mod
+$(obj)/__Div.o: $(src)/divide.c
+KLIBCCFLAGS___Div.o  := -DSIGNED=1 -DREM=0 -DBITS=32 -DNAME=__Div
diff --git a/usr/klibc/arch/cris/MCONFIG b/usr/klibc/arch/cris/MCONFIG
new file mode 100644
index 0000000..20bfe73
--- /dev/null
+++ b/usr/klibc/arch/cris/MCONFIG
@@ -0,0 +1,26 @@
+# -*- makefile -*-
+#
+# arch/cris/MCONFIG
+#
+# Special rules for this architecture.  Note that this is actually
+# included from the main Makefile, and that pathnames should be
+# accordingly.
+#
+
+KLIBCOPTFLAGS += -Os -fomit-frame-pointer
+KLIBCBITSIZE  = 32
+
+# Extra linkflags when building the shared version of the library
+# This address needs to be reachable using normal inter-module
+# calls, and work on the memory models for this architecture
+# 224 MB - normal binaries start at 0
+# (lib?)gcc on cris seems to insist on producing .init and .fini sections
+KLIBCSHAREDFLAGS     = --section-start .init=0x0e000100
+
+# The CRIS compiler needs an -iprefix to find libgcc includes when
+# nostdinc is used. It also needs -mlinux to compile linux applications.
+INCLUDE_PREFIX  = $(shell $(CC) -print-libgcc-file-name | sed -e s/libgcc.a//)
+KLIBCARCHREQFLAGS = -iprefix $(INCLUDE_PREFIX) -mlinux
+
+# Special flags needed for linking
+KLIBCLDFLAGS 	+= -mcrislinux
diff --git a/usr/klibc/arch/cris/__negdi2.S b/usr/klibc/arch/cris/__negdi2.S
new file mode 100644
index 0000000..3cca9ed
--- /dev/null
+++ b/usr/klibc/arch/cris/__negdi2.S
@@ -0,0 +1,25 @@
+/*
+ * arch/cris/__negdi2.c
+ */
+
+/*
+ * In 2's complement arithmetric, -x == (~x + 1), so
+ * -{h,l} = (~{h,l} + {0,1)
+ * -{h,l} = {~h,~l} + {0,1}
+ * -{h,l} = {~h + cy, ~l + 1}
+ * ... where cy = (l == 0)
+ * -{h,l} = {~h + cy, -l}
+ */
+
+	.text
+	.balign 4
+	.type	__negdi2,@function
+	.globl	__negdi2
+__negdi2:
+	neg.d	$r10,$r10
+	seq	$r12
+	not	$r11
+	ret
+	  add.d	$r12,$r11
+
+	.size __negdi2, .-__negdi2
diff --git a/usr/klibc/arch/cris/crt0.S b/usr/klibc/arch/cris/crt0.S
new file mode 100644
index 0000000..22cb9b4
--- /dev/null
+++ b/usr/klibc/arch/cris/crt0.S
@@ -0,0 +1,27 @@
+#
+# arch/cris/crt0.S
+#
+# Does arch-specific initialization and invokes __libc_init
+# with the appropriate arguments.
+#
+# See __static_init.c or __shared_init.c for the expected
+# arguments.
+#
+
+	.text
+	.balign 4
+	.type	_start,@function
+	.globl	_start
+_start:
+	/* Save the address of the ELF argument array */
+	move.d	$sp,$r10	/* Address of ELF arguments */
+
+	/* atexit() function (assume null) */
+	moveq	0,$r11
+
+	/* Set up a dummy stack frame to keep gcc from getting confused */
+	push	$r11
+	push	$r11
+	jump	__libc_init
+
+	.size _start, .-_start
diff --git a/usr/klibc/arch/cris/divide.c b/usr/klibc/arch/cris/divide.c
new file mode 100644
index 0000000..1d4ab23
--- /dev/null
+++ b/usr/klibc/arch/cris/divide.c
@@ -0,0 +1,99 @@
+#include <stdint.h>
+#include <signal.h>
+
+#if BITS == 64
+typedef uint64_t unum;
+typedef int64_t snum;
+#else
+typedef uint32_t unum;
+typedef int32_t snum;
+#endif
+
+#ifdef SIGNED
+typedef snum xnum;
+#else
+typedef unum xnum;
+#endif
+
+#ifdef __cris__
+static inline unum __attribute__ ((const))dstep(unum rs, unum rd)
+{
+	asm("dstep %1,%0": "+r"(rd):"r"(rs));
+	return rd;
+}
+
+static inline unum __attribute__ ((const))lz(unum rs)
+{
+	unum rd;
+	asm("lz %1,%0": "=r"(rd):"r"(rs));
+	return rd;
+}
+
+#else
+/* For testing */
+static inline unum __attribute__ ((const))dstep(unum rs, unum rd)
+{
+	rd <<= 1;
+	if (rd >= rs)
+		rd -= rs;
+
+	return rd;
+}
+
+static inline unum __attribute__ ((const))lz(unum rs)
+{
+	unum rd = 0;
+	while (rs >= 0x7fffffff) {
+		rd++;
+		rs <<= 1;
+	}
+	return rd;
+}
+
+#endif
+
+xnum NAME(unum num, unum den)
+{
+	unum quot = 0, qbit = 1;
+	int minus = 0;
+	xnum v;
+
+	if (den == 0) {
+		raise(SIGFPE);
+		return 0;	/* If signal ignored... */
+	}
+
+	if (den == 1)
+		return (xnum) (REM ? 0 : num);
+
+#if SIGNED
+	if ((snum) (num ^ den) < 0)
+		minus = 1;
+	if ((snum) num < 0)
+		num = -num;
+	if ((snum) den < 0)
+		den = -den;
+#endif
+
+	den--;
+
+	/* Left-justify denominator and count shift */
+	while ((snum) den >= 0) {
+		den <<= 1;
+		qbit <<= 1;
+	}
+
+	while (qbit) {
+		if (den <= num) {
+			num -= den;
+			quot += qbit;
+		}
+		den >>= 1;
+		qbit >>= 1;
+	}
+
+	v = (xnum) (REM ? num : quot);
+	if (minus)
+		v = -v;
+	return v;
+}
diff --git a/usr/klibc/arch/cris/setjmp.S b/usr/klibc/arch/cris/setjmp.S
new file mode 100644
index 0000000..2041b82
--- /dev/null
+++ b/usr/klibc/arch/cris/setjmp.S
@@ -0,0 +1,37 @@
+#
+# arch/cris/setjmp.S
+#
+# setjmp/longjmp for the cris architecture
+#
+
+#
+# The jmp_buf is assumed to contain the following, in order:
+#	$r8..$r0	(in that order)
+#	$sp	($r14)
+#	return address
+#
+
+	.text
+	.balign 4
+	.globl	setjmp
+	.type	setjmp, @function
+setjmp:
+	movem	$r8,[$r10+]		/* Save $r8..$r0 at $r10... */
+	move.d	$sp,[$r10+]
+	move	$srp,[$r10]
+	ret
+	  moveq	0,$r10
+
+	.size setjmp,.-setjmp
+
+	.text
+	.balign 4
+	.globl	longjmp
+	.type	longjmp, @function
+longjmp:
+	movem	[$r10+],$r8		/* Load $r8..$r0 from $r10... */
+	move.d	[$r10+],$sp
+	jump	[$r10]
+	move.d $r11,$r10
+
+	.size longjmp,.-longjmp
diff --git a/usr/klibc/arch/cris/syscall.S b/usr/klibc/arch/cris/syscall.S
new file mode 100644
index 0000000..d71495a
--- /dev/null
+++ b/usr/klibc/arch/cris/syscall.S
@@ -0,0 +1,30 @@
+/*
+ * arch/cris/syscall.S
+ *
+ * On cris, r9 contains the syscall number (set by generated stub);
+ * r10..r13 contain arguments 0-3 per the standard calling convention,
+ * and arguments 4-5 are passed in $mof and $srp; however, we have
+ * to save $srp around the system call.
+ */
+
+	.section ".text","ax"
+	.balign	4
+	.globl	__syscall_common
+	.type	__syscall_common,@function
+__syscall_common:
+	push	$srp
+	move	[$sp+4],$mof
+	move	[$sp+8],$srp
+	break	13
+
+	cmps.w	-4096,$r10
+	blo	1f
+	neg.d	$r10,$r11
+	move.d	$r11,[errno]
+	moveq	-1,$r10
+1:
+	pop	$srp
+	ret
+	nop
+
+	.size	__syscall_common,.-__syscall_common
diff --git a/usr/klibc/arch/cris/sysstub.ph b/usr/klibc/arch/cris/sysstub.ph
new file mode 100644
index 0000000..182ad73
--- /dev/null
+++ b/usr/klibc/arch/cris/sysstub.ph
@@ -0,0 +1,29 @@
+# -*- perl -*-
+#
+# arch/cris/sysstub.ph
+#
+# Script to generate system call stubs
+#
+
+sub make_sysstub($$$$$@) {
+    my($outputdir, $fname, $type, $sname, $stype, @args) = @_;
+
+    open(OUT, '>', "${outputdir}/${fname}.S");
+    print OUT "#include <asm/unistd.h>\n";
+    print OUT "\n";
+    print OUT "\t.text\n";
+    print OUT "\t.type\t${fname},\@function\n";
+    print OUT "\t.globl\t${fname}\n";
+    print OUT "\t.balign\t4\n";
+    print OUT "${fname}:\n";
+    print OUT "#if __NR_${sname} <= 31\n";
+    print OUT "\t  moveq\t__NR_${sname}, \$r9\n";
+    print OUT "#else\n";
+    print OUT "\t  move.d\t__NR_${sname}, \$r9\n";
+    print OUT "#endif\n";
+    print OUT "\tjump\t__syscall_common\n";
+    print OUT "\t.size ${fname},.-${fname}\n";
+    close(OUT);
+}
+
+1;
diff --git a/usr/klibc/arch/cris/vfork.S b/usr/klibc/arch/cris/vfork.S
new file mode 100644
index 0000000..ccdb36c
--- /dev/null
+++ b/usr/klibc/arch/cris/vfork.S
@@ -0,0 +1,29 @@
+/*
+ * arch/cris/vfork.S
+ *
+ * On cris, r9 contains the syscall number (set by generated stub);
+ * r10..r13 contain arguments 0-3 per the standard calling convention.
+ * The return address is in $srp; so we just need to avoid the stack
+ * usage of the normal syscall stubs.
+ */
+
+#include <asm/unistd.h>
+
+	.section ".text","ax"
+	.balign	4
+	.globl	vfork
+	.type	vfork,@function
+vfork:
+	move.d	__NR_vfork, $r9
+	break	13
+
+	cmps.w	-4096,$r10
+	blo	1f
+	neg.d	$r10,$r11
+	move.d	$r11,[errno]
+	moveq	-1,$r10
+1:
+	ret
+	nop
+
+	.size	vfork,.-vfork
diff --git a/usr/klibc/arch/i386/Kbuild b/usr/klibc/arch/i386/Kbuild
new file mode 100644
index 0000000..edc7b3c
--- /dev/null
+++ b/usr/klibc/arch/i386/Kbuild
@@ -0,0 +1,17 @@
+#
+# klibc .o files for i386
+#
+
+klib-y := socketcall.o setjmp.o syscall.o varsyscall.o
+klib-y += open.o openat.o vfork.o
+klib-y += libgcc/__ashldi3.o libgcc/__ashrdi3.o libgcc/__lshrdi3.o
+klib-y += libgcc/__muldi3.o  libgcc/__negdi2.o
+
+klib-y += ../../libgcc/__divdi3.o
+klib-y += ../../libgcc/__moddi3.o
+klib-y += ../../libgcc/__udivdi3.o
+klib-y += ../../libgcc/__umoddi3.o
+klib-y += ../../libgcc/__udivmoddi4.o
+
+always  := crt0.o
+targets := crt0.o
diff --git a/usr/klibc/arch/i386/MCONFIG b/usr/klibc/arch/i386/MCONFIG
new file mode 100644
index 0000000..ef112a4
--- /dev/null
+++ b/usr/klibc/arch/i386/MCONFIG
@@ -0,0 +1,33 @@
+# -*- makefile -*-
+#
+# arch/i386/MCONFIG
+#
+# Special rules for this architecture.  Note that this is actually
+# included from the main Makefile, and that pathnames should be
+# accordingly.
+#
+
+# Enable this to compile with register parameters; only safe for
+# gcc >= 3
+
+ifeq ($(CONFIG_REGPARM),y)
+REGPARM_OPT := -mregparm=3 -D_REGPARM=3
+endif
+
+gcc_align_option  := $(call cc-option, \
+		-falign-functions=0 -falign-jumps=0 -falign-loops=0, \
+		-malign-functions=0 -malign-jumps=0 -malign-loops=0)
+gcc_m32_option  := $(call cc-option, -m32, )
+
+KLIBCOPTFLAGS     += -march=i386 -Os -g -fomit-frame-pointer $(gcc_align_option)
+KLIBCLDFLAGS      = -m elf_i386
+KLIBCREQFLAGS	  += $(REGPARM_OPT)
+KLIBCARCHREQFLAGS += $(gcc_m32_option)
+
+KLIBCBITSIZE  = 32
+
+# Extra linkflags when building the shared version of the library
+# This address needs to be reachable using normal inter-module
+# calls, and work on the memory models for this architecture
+# 96 MB - normal binaries start at 128 MB
+KLIBCSHAREDFLAGS	= -Ttext 0x06000200
diff --git a/usr/klibc/arch/i386/crt0.S b/usr/klibc/arch/i386/crt0.S
new file mode 100644
index 0000000..8c6635e
--- /dev/null
+++ b/usr/klibc/arch/i386/crt0.S
@@ -0,0 +1,31 @@
+#
+# arch/i386/crt0.S
+#
+# Does arch-specific initialization and invokes __libc_init
+# with the appropriate arguments.
+#
+# See __static_init.c or __shared_init.c for the expected
+# arguments.
+#
+
+	.text
+	.align 4
+	.type _start,@function
+	.globl _start
+_start:
+	# Save the address of the ELF argument array
+	movl %esp,%eax		# Address of ELF arguments
+	# Set up a faux stack frame for the benefit of gdb
+	xorl %ebp,%ebp
+	push %ebp		# Keep gdb from getting confused
+	push %ebp		# Keep gdb from getting confused
+	# Push the arguments and called __libc_init()
+#ifndef _REGPARM
+	push %edx		# atexit() function
+	push %eax		# ELF array
+#endif
+	call __libc_init
+	# If __libc_init returns, problem...
+	hlt
+
+	.size _start, .-_start
diff --git a/usr/klibc/arch/i386/libgcc/__ashldi3.S b/usr/klibc/arch/i386/libgcc/__ashldi3.S
new file mode 100644
index 0000000..7344142
--- /dev/null
+++ b/usr/klibc/arch/i386/libgcc/__ashldi3.S
@@ -0,0 +1,29 @@
+/*
+ * arch/i386/libgcc/__ashldi3.S
+ *
+ * 64-bit shl
+ */
+	.text
+	.align 4
+	.globl __ashldi3
+	.type __ashldi3,@function
+__ashldi3:
+#ifndef _REGPARM
+	movl  4(%esp),%eax
+	movl  8(%esp),%edx
+	movb  12(%esp),%cl
+#endif
+	cmpb  $32,%cl
+	jae   1f
+
+	shldl %cl,%eax,%edx
+	shl   %cl,%eax
+	ret
+
+1:
+	xorl  %edx,%edx
+	shl   %cl,%eax
+	xchgl %edx,%eax
+	ret
+
+	.size __ashldi3,.-__ashldi3
diff --git a/usr/klibc/arch/i386/libgcc/__ashrdi3.S b/usr/klibc/arch/i386/libgcc/__ashrdi3.S
new file mode 100644
index 0000000..7666eb2
--- /dev/null
+++ b/usr/klibc/arch/i386/libgcc/__ashrdi3.S
@@ -0,0 +1,29 @@
+/*
+ * arch/i386/libgcc/__ashrdi3.S
+ *
+ * 64-bit sar
+ */
+	.text
+	.align 4
+	.globl __ashrdi3
+	.type __ashrdi3,@function
+__ashrdi3:
+#ifndef _REGPARM
+	movl  4(%esp),%eax
+	movl  8(%esp),%edx
+	movb  12(%esp),%cl
+#endif
+	cmpb  $32,%cl
+	jae   1f
+
+	shrdl %cl,%edx,%eax
+	sarl  %cl,%edx
+	ret
+
+1:
+	sarl  %cl,%edx
+	movl  %edx,%eax
+	cdq
+	ret
+
+	.size __ashrdi3,.-__ashrdi3
diff --git a/usr/klibc/arch/i386/libgcc/__lshrdi3.S b/usr/klibc/arch/i386/libgcc/__lshrdi3.S
new file mode 100644
index 0000000..6a63c52
--- /dev/null
+++ b/usr/klibc/arch/i386/libgcc/__lshrdi3.S
@@ -0,0 +1,29 @@
+/*
+ * arch/i386/libgcc/__lshrdi3.S
+ *
+ * 64-bit shr
+ */
+	.text
+	.align 4
+	.globl __lshrdi3
+	.type __lshrdi3,@function
+__lshrdi3:
+#ifndef _REGPARM
+	movl  4(%esp),%eax
+	movl  8(%esp),%edx
+	movb  12(%esp),%cl
+#endif
+	cmpb  $32,%cl
+	jae   1f
+
+	shrdl %cl,%edx,%eax
+	shrl  %cl,%edx
+	ret
+
+1:
+	shrl  %cl,%edx
+	xorl  %eax,%eax
+	xchgl %edx,%eax
+	ret
+
+	.size __lshrdi3,.-__lshrdi3
diff --git a/usr/klibc/arch/i386/libgcc/__muldi3.S b/usr/klibc/arch/i386/libgcc/__muldi3.S
new file mode 100644
index 0000000..472c7cc
--- /dev/null
+++ b/usr/klibc/arch/i386/libgcc/__muldi3.S
@@ -0,0 +1,34 @@
+/*
+ * arch/i386/libgcc/__muldi3.S
+ *
+ * 64*64 = 64 bit unsigned multiplication
+ */
+
+	.text
+	.align 4
+	.globl __muldi3
+	.type __muldi3,@function
+__muldi3:
+	push  %esi
+#ifndef _REGPARM
+	movl  8(%esp),%eax
+	movl  %eax,%esi
+	movl  16(%esp),%ecx
+	mull  %ecx
+	imull 12(%esp),%ecx
+	imull 20(%esp),%esi
+	addl  %ecx,%edx
+	addl  %esi,%edx
+#else
+	movl  %eax,%esi
+	push  %edx
+	mull  %ecx
+	imull 8(%esp),%esi
+	addl  %esi,%edx
+	pop   %esi
+	imull %esi,%ecx
+	addl  %ecx,%edx
+#endif
+	pop   %esi
+	ret
+	.size __muldi3,.-__muldi3
diff --git a/usr/klibc/arch/i386/libgcc/__negdi2.S b/usr/klibc/arch/i386/libgcc/__negdi2.S
new file mode 100644
index 0000000..147ad94
--- /dev/null
+++ b/usr/klibc/arch/i386/libgcc/__negdi2.S
@@ -0,0 +1,21 @@
+/*
+ * arch/i386/libgcc/__negdi2.S
+ *
+ * 64-bit negation
+ */
+
+	.text
+	.align 4
+	.globl __negdi2
+	.type __negdi2,@function
+__negdi2:
+#ifndef _REGPARM
+	movl 4(%esp),%eax
+	movl 8(%esp),%edx
+#endif
+	negl %edx
+	negl %eax
+	sbbl $0,%edx
+	ret
+
+	.size __negdi2,.-__negdi2
diff --git a/usr/klibc/arch/i386/open.S b/usr/klibc/arch/i386/open.S
new file mode 100644
index 0000000..7cd136c
--- /dev/null
+++ b/usr/klibc/arch/i386/open.S
@@ -0,0 +1,29 @@
+/*
+ * arch/i386/open.S
+ *
+ * Handle the open() system call - oddball due to the varadic
+ * prototype, which forces the use of the cdecl calling convention,
+ * and the need for O_LARGEFILE.
+ */
+
+#include <asm/unistd.h>
+
+/* <asm/fcntl.h>, despite the name, isn't assembly-safe */
+#define O_LARGEFILE     0100000
+
+	.globl	open
+	.type	open,@function
+
+open:
+#ifdef _REGPARM
+	movl	4(%esp),%eax
+	movl	8(%esp),%edx
+	movl	12(%esp),%ecx
+	orl	$O_LARGEFILE,%edx
+#else
+	orl	$O_LARGEFILE,8(%esp)
+#endif
+	pushl	$__NR_open
+	jmp	__syscall_common
+
+	.size	open,.-open
diff --git a/usr/klibc/arch/i386/openat.S b/usr/klibc/arch/i386/openat.S
new file mode 100644
index 0000000..2dfdfe2
--- /dev/null
+++ b/usr/klibc/arch/i386/openat.S
@@ -0,0 +1,26 @@
+/*
+ * arch/i386/openat.S
+ *
+ * Handle the openat() system call - oddball due to the varadic
+ * prototype, which forces the use of the cdecl calling convention,
+ * and the need for O_LARGEFILE.
+ */
+
+#include <asm/unistd.h>
+
+/* <asm/fcntl.h>, despite the name, isn't assembly-safe */
+#define O_LARGEFILE     0100000
+
+#ifdef __NR_openat		/* Don't build if kernel headers too old */
+
+	.globl	openat
+	.type	openat,@function
+
+openat:
+	orl	$O_LARGEFILE,12(%esp)
+	pushl	$__NR_openat
+	jmp	__syscall_varadic
+
+	.size	openat,.-openat
+
+#endif
diff --git a/usr/klibc/arch/i386/setjmp.S b/usr/klibc/arch/i386/setjmp.S
new file mode 100644
index 0000000..b766792
--- /dev/null
+++ b/usr/klibc/arch/i386/setjmp.S
@@ -0,0 +1,58 @@
+#
+# arch/i386/setjmp.S
+#
+# setjmp/longjmp for the i386 architecture
+#
+
+#
+# The jmp_buf is assumed to contain the following, in order:
+#	%ebx
+#	%esp
+#	%ebp
+#	%esi
+#	%edi
+#	<return address>
+#
+
+	.text
+	.align 4
+	.globl setjmp
+	.type setjmp, @function
+setjmp:
+#ifdef _REGPARM
+	movl %eax,%edx
+#else
+	movl 4(%esp),%edx
+#endif
+	popl %ecx			# Return address, and adjust the stack
+	xorl %eax,%eax			# Return value
+	movl %ebx,(%edx)
+	movl %esp,4(%edx)		# Post-return %esp!
+	pushl %ecx			# Make the call/return stack happy
+	movl %ebp,8(%edx)
+	movl %esi,12(%edx)
+	movl %edi,16(%edx)
+	movl %ecx,20(%edx)		# Return address
+	ret
+
+	.size setjmp,.-setjmp
+
+	.text
+	.align 4
+	.globl longjmp
+	.type longjmp, @function
+longjmp:
+#ifdef _REGPARM
+	xchgl %eax,%edx
+#else
+	movl 4(%esp),%edx		# jmp_ptr address
+	movl 8(%esp),%eax		# Return value
+#endif
+	movl (%edx),%ebx
+	movl 4(%edx),%esp
+	movl 8(%edx),%ebp
+	movl 12(%edx),%esi
+	movl 16(%edx),%edi
+	jmp *20(%edx)
+
+	.size longjmp,.-longjmp
diff --git a/usr/klibc/arch/i386/socketcall.S b/usr/klibc/arch/i386/socketcall.S
new file mode 100644
index 0000000..a40cc02
--- /dev/null
+++ b/usr/klibc/arch/i386/socketcall.S
@@ -0,0 +1,55 @@
+#
+# socketcall.S
+#
+# Socketcalls use the following convention:
+# %eax = __NR_socketcall
+# %ebx = socketcall number
+# %ecx = pointer to arguments (up to 6)
+#
+
+#include <asm/unistd.h>
+
+#ifdef __i386__
+
+	.text
+	.align 4
+	.globl __socketcall_common
+	.type __socketcall_common, @function
+
+__socketcall_common:
+	xchgl	%ebx,(%esp)	# The stub passes the socketcall # on stack
+
+#ifdef	_REGPARM
+	pushl	16(%esp)	# Arg 6
+	pushl	16(%esp)	# Arg 5
+	pushl	16(%esp)	# Arg 4
+	pushl	%ecx
+	pushl	%edx
+	pushl	%eax
+	movl	%esp,%ecx
+#else
+	leal	8(%esp),%ecx	# Arguments already contiguous on-stack
+#endif
+
+	movl	$__NR_socketcall,%eax
+	int	$0x80
+
+#ifdef	_REGPARM
+	addl	$6*4, %esp
+#endif
+
+	cmpl	$-4095,%eax	# Error return?
+
+	popl	%ebx
+
+	jb	1f
+
+	negl	%eax
+	movl	%eax,errno
+	orl	$-1,%eax	# Return -1
+1:
+	ret
+
+	.size __socketcall_common,.-__socketcall_common
+
+#endif
diff --git a/usr/klibc/arch/i386/syscall.S b/usr/klibc/arch/i386/syscall.S
new file mode 100644
index 0000000..d28717b
--- /dev/null
+++ b/usr/klibc/arch/i386/syscall.S
@@ -0,0 +1,69 @@
+/*
+ * arch/i386/syscall.S
+ *
+ * Common tail-handling code for system calls.
+ *
+ * The arguments are on the stack; the system call number in %eax.
+ */
+
+#define ARG(n)	(4*n+20)(%esp)
+
+	.text
+	.align	4
+	.globl	__syscall_common
+	.type	__syscall_common,@function
+__syscall_common:
+#ifdef _REGPARM
+	xchgl	%ebx,(%esp)
+#else
+	popl	%eax
+	pushl	%ebx
+#endif
+	pushl	%esi
+	pushl	%edi
+	pushl	%ebp
+
+#ifdef _REGPARM
+	xchgl	%eax,%ebx
+	xchgl	%ecx,%edx
+	movl	ARG(0),%esi
+	movl	ARG(1),%edi
+	movl	ARG(2),%ebp
+#else
+	movl	ARG(0),%ebx		# Syscall arguments
+	movl	ARG(1),%ecx
+	movl	ARG(2),%edx
+	movl	ARG(3),%esi
+	movl	ARG(4),%edi
+	movl	ARG(5),%ebp
+#endif
+	.globl __syscall_common_tail
+__syscall_common_tail:
+	int	$0x80
+
+	cmpl	$-4095,%eax
+
+	popl	%ebp
+	popl	%edi
+	popl	%esi
+	popl	%ebx
+
+	jb	1f
+
+	# Error return, must set errno
+	negl	%eax
+	movl	%eax,errno
+	orl	$-1,%eax		# Return -1
+
+1:
+	ret
+
+	.size	__syscall_common,.-__syscall_common
+
+#ifndef _REGPARM
+
+	.globl	__syscall_varadic
+	.type	__syscall_varadic,@function
+__syscall_varadic = __syscall_common
+
+#endif
diff --git a/usr/klibc/arch/i386/sysstub.ph b/usr/klibc/arch/i386/sysstub.ph
new file mode 100644
index 0000000..e73a3ff
--- /dev/null
+++ b/usr/klibc/arch/i386/sysstub.ph
@@ -0,0 +1,26 @@
+# -*- perl -*-
+#
+# arch/i386/sysstub.ph
+#
+# Script to generate system call stubs
+#
+
+sub make_sysstub($$$$$@) {
+    my($outputdir, $fname, $type, $sname, $stype, @args) = @_;
+
+    open(OUT, '>', "${outputdir}/${fname}.S");
+    print OUT "#include <asm/unistd.h>\n";
+    print OUT "\n";
+    print OUT "\t.type ${fname},\@function\n";
+    print OUT "\t.globl ${fname}\n";
+    print OUT "${fname}:\n";
+
+    $stype = 'common' if ( $stype eq '' );
+
+    print OUT "\tpushl \$__NR_${sname}\n";
+    print OUT "\tjmp __syscall_$stype\n";
+    print OUT "\t.size ${fname},.-${fname}\n";
+    close(OUT);
+}
+
+1;
diff --git a/usr/klibc/arch/i386/varsyscall.S b/usr/klibc/arch/i386/varsyscall.S
new file mode 100644
index 0000000..24329ea
--- /dev/null
+++ b/usr/klibc/arch/i386/varsyscall.S
@@ -0,0 +1,36 @@
+/*
+ * arch/i386/varsyscall.S
+ *
+ * Common tail-handling code for varadic system calls (which always
+ * use the cdecl convention.)
+ *
+ * The arguments are on the stack; the system call number in %eax.
+ */
+
+#ifdef	_REGPARM
+
+#define ARG(n)	(4*n+20)(%esp)
+
+	.text
+	.align	4
+	.globl	__syscall_varadic
+	.type	__syscall_varadic,@function
+__syscall_varadic:
+	popl	%eax
+	pushl	%ebx
+	pushl	%esi
+	pushl	%edi
+	pushl	%ebp
+
+	movl	ARG(0),%ebx		# Syscall arguments
+	movl	ARG(1),%ecx
+	movl	ARG(2),%edx
+	movl	ARG(3),%esi
+	movl	ARG(4),%edi
+	movl	ARG(5),%ebp
+
+	jmp	__syscall_common_tail
+
+	.size	__syscall_varadic,.-__syscall_varadic
+
+#endif
diff --git a/usr/klibc/arch/i386/vfork.S b/usr/klibc/arch/i386/vfork.S
new file mode 100644
index 0000000..c98ba3a
--- /dev/null
+++ b/usr/klibc/arch/i386/vfork.S
@@ -0,0 +1,26 @@
+#
+# usr/klibc/arch/i386/vfork.S
+#
+# vfork is nasty - there must be nothing at all on the stack above
+# the stack frame of the enclosing function.
+#
+
+#include <asm/unistd.h>
+
+        .text
+        .align  4
+	.globl	vfork
+	.type	vfork, @function
+vfork:
+	popl	%edx			/* Return address */
+	movl	$__NR_vfork, %eax
+	int	$0x80
+	pushl	%edx
+	cmpl	$-4095, %eax
+	jae	1f
+	ret
+1:
+	negl	%eax
+	movl	%eax, errno
+	orl	$-1, %eax
+	ret
diff --git a/usr/klibc/arch/ia64/Kbuild b/usr/klibc/arch/ia64/Kbuild
new file mode 100644
index 0000000..49070ff
--- /dev/null
+++ b/usr/klibc/arch/ia64/Kbuild
@@ -0,0 +1,13 @@
+#
+# klibc files for ia64
+#
+
+klib-y := vfork.o setjmp.o pipe.o syscall.o
+
+klib-y += ../../libgcc/__divdi3.o     ../../libgcc/__divsi3.o
+klib-y += ../../libgcc/__udivdi3.o    ../../libgcc/__udivsi3.o
+klib-y += ../../libgcc/__umodsi3.o    ../../libgcc/__umoddi3.o
+klib-y += ../../libgcc/__udivmodsi4.o ../../libgcc/__udivmoddi4.o
+
+always  := crt0.o
+targets := crt0.o
diff --git a/usr/klibc/arch/ia64/MCONFIG b/usr/klibc/arch/ia64/MCONFIG
new file mode 100644
index 0000000..ad868ef
--- /dev/null
+++ b/usr/klibc/arch/ia64/MCONFIG
@@ -0,0 +1,11 @@
+# -*- makefile -*-
+#
+# arch/ia64/MCONFIG
+#
+# Special rules for this architecture.  Note that this is actually
+# included from the main Makefile, and that pathnames should be
+# accordingly.
+#
+
+KLIBCOPTFLAGS += -Os
+KLIBCBITSIZE  = 64
diff --git a/usr/klibc/arch/ia64/crt0.S b/usr/klibc/arch/ia64/crt0.S
new file mode 100644
index 0000000..722276e
--- /dev/null
+++ b/usr/klibc/arch/ia64/crt0.S
@@ -0,0 +1,27 @@
+
+#include <asm/fpu.h>
+
+	.align 32
+	.global _start
+
+	.proc _start
+	.type _start,@function
+_start:
+	.prologue
+	.save rp, r0
+
+	alloc r2 = ar.pfs,0,0,2,0
+	movl r3 = FPSR_DEFAULT
+	;;
+	adds out0= 16,sp    /* argc pointer */
+	movl gp = @gprel(0f)
+0:	mov r9 = ip
+	;;
+	sub gp = r9, gp     /* back-compute gp value */
+
+	.body
+	br.call.sptk.few rp = __libc_init
+	;;
+	break 0             /* break miserably if we ever return */
+
+	.endp _start
diff --git a/usr/klibc/arch/ia64/pipe.c b/usr/klibc/arch/ia64/pipe.c
new file mode 100644
index 0000000..fa3a272
--- /dev/null
+++ b/usr/klibc/arch/ia64/pipe.c
@@ -0,0 +1,41 @@
+/*
+ * pipe.c
+ */
+
+#include <sys/syscall.h>
+#include <klibc/archsys.h>
+
+#define ASM_CLOBBERS ,"out2", "out3", "out4", "out5", "out6", "out7",    \
+   /* Non-stacked integer registers, minus r8, r9, r10, r15.  */	\
+  "r2", "r3", "r11", "r12", "r13", "r14", "r16", "r17", "r18",	        \
+  "r19", "r20", "r21", "r22", "r23", "r24", "r25", "r26", "r27",	\
+  "r28", "r29", "r30", "r31",						\
+  /* Predicate registers.  */						\
+  "p6", "p7", "p8", "p9", "p10", "p11", "p12", "p13", "p14", "p15",	\
+  /* Non-rotating fp registers.  */					\
+  "f6", "f7", "f8", "f9", "f10", "f11", "f12", "f13", "f14", "f15",	\
+  /* Branch registers.  */						\
+  "b6", "b7"
+
+int pipe(int *filedes)
+{
+	register long _r8 asm("r8");
+	register long _r9 asm("r9");
+	register long _r10 asm("r10");
+	register long _r15 asm("r15") = __NR_pipe;
+	register long _out0 asm("out0") = (long)filedes;
+	long _retval;
+	__asm __volatile(__IA64_BREAK:"=r"(_r8), "=r"(_r10), "=r"(_r15),
+			 "=r"(_out0), "=r"(_r9)
+			 :"2"(_r15), "3"(_out0)
+			 :"memory" ASM_CLOBBERS);
+	if (_r10 == -1) {
+		errno = _r8;
+		_retval = -1;
+	} else {
+		filedes[0] = _r8;
+		filedes[1] = _r9;
+		_retval = 0;
+	}
+	return _retval;
+}
diff --git a/usr/klibc/arch/ia64/setjmp.S b/usr/klibc/arch/ia64/setjmp.S
new file mode 100644
index 0000000..ab1cea2
--- /dev/null
+++ b/usr/klibc/arch/ia64/setjmp.S
@@ -0,0 +1,343 @@
+/*
+ * IA-64 specific setjmp/longjmp routines
+ *
+ * Inspired by setjmp.s from the FreeBSD kernel.
+ */
+
+#define	J_UNAT		0
+#define	J_NATS		0x8
+#define	J_PFS		0x10
+#define	J_BSP		0x18
+#define	J_RNAT		0x20
+#define	J_PREDS		0x28
+#define	J_LC		0x30
+#define	J_R4		0x38
+#define	J_R5		0x40
+#define	J_R6		0x48
+#define	J_R7		0x50
+#define	J_SP		0x58
+#define	J_F2		0x60
+#define	J_F3		0x70
+#define	J_F4		0x80
+#define	J_F5		0x90
+#define	J_F16		0xa0
+#define	J_F17		0xb0
+#define	J_F18		0xc0
+#define	J_F19		0xd0
+#define	J_F20		0xe0
+#define	J_F21		0xf0
+#define	J_F22		0x100
+#define	J_F23		0x110
+#define	J_F24		0x120
+#define	J_F25		0x130
+#define	J_F26		0x140
+#define	J_F27		0x150
+#define	J_F28		0x160
+#define	J_F29		0x170
+#define	J_F30		0x180
+#define	J_F31		0x190
+#define	J_FPSR		0x1a0
+#define	J_B0		0x1a8
+#define	J_B1		0x1b0
+#define	J_B2		0x1b8
+#define	J_B3		0x1c0
+#define	J_B4		0x1c8
+#define	J_B5		0x1d0
+#define	J_SIGMASK	0x1d8
+#define	J_SIGSET	0x1e0
+#define	J_GP		0x1f0
+
+// int setjmp(struct jmp_buffer *)
+//
+//  Setup a non-local goto.
+//
+// Description:
+//
+//  SetJump stores the current register set in the area pointed to
+//  by "save".  It returns zero.  Subsequent calls to "LongJump" will
+//  restore the registers and return non-zero to the same location.
+//
+// On entry, r32 contains the pointer to the jmp_buffer
+//
+	.align 32
+	.global setjmp
+	.proc setjmp
+setjmp:
+    //
+    //  Make sure buffer is aligned at 16byte boundary
+    //
+    add     r10 = -0x10,r0  ;;  // mask the lower 4 bits
+    and     r32 = r32, r10;;
+    add     r32 = 0x10, r32;;   // move to next 16 byte boundary
+
+    add     r10 = J_PREDS, r32  // skip Unats & pfs save area
+    add     r11 = J_BSP, r32
+    //
+    //  save immediate context
+    //
+    mov     r2 = ar.bsp         // save backing store pointer
+    mov     r3 = pr             // save predicates
+    flushrs
+    ;;
+    //
+    // save user Unat register
+    //
+    mov     r16 = ar.lc         // save loop count register
+    mov     r14 = ar.unat       // save user Unat register
+
+    st8     [r10] = r3, J_LC-J_PREDS
+    st8     [r11] = r2, J_R4-J_BSP
+    ;;
+    st8     [r10] = r16, J_R5-J_LC
+    st8     [r32] = r14, J_NATS // Note: Unat at the
+                                // beginning of the save area
+    mov     r15 = ar.pfs
+    ;;
+    //
+    //  save preserved general registers & NaT's
+    //
+    st8.spill   [r11] = r4, J_R6-J_R4
+    ;;
+    st8.spill   [r10] = r5, J_R7-J_R5
+    ;;
+    st8.spill   [r11] = r6, J_SP-J_R6
+    ;;
+    st8.spill   [r10] = r7, J_F3-J_R7
+    ;;
+    st8.spill   [r11] = sp, J_F2-J_SP
+    ;;
+    //
+    // save spilled Unat and pfs registers
+    //
+    mov     r2 = ar.unat        // save Unat register after spill
+    ;;
+    st8     [r32] = r2, J_PFS-J_NATS    // save unat for spilled regs
+    ;;
+    st8     [r32] = r15         // save pfs
+    //
+    //  save floating registers
+    //
+    stf.spill   [r11] = f2, J_F4-J_F2
+    stf.spill   [r10] = f3, J_F5-J_F3
+    ;;
+    stf.spill   [r11] = f4, J_F16-J_F4
+    stf.spill   [r10] = f5, J_F17-J_F5
+    ;;
+    stf.spill   [r11] = f16, J_F18-J_F16
+    stf.spill   [r10] = f17, J_F19-J_F17
+    ;;
+    stf.spill   [r11] = f18, J_F20-J_F18
+    stf.spill   [r10] = f19, J_F21-J_F19
+    ;;
+    stf.spill   [r11] = f20, J_F22-J_F20
+    stf.spill   [r10] = f21, J_F23-J_F21
+    ;;
+    stf.spill   [r11] = f22, J_F24-J_F22
+    stf.spill   [r10] = f23, J_F25-J_F23
+    ;;
+    stf.spill   [r11] = f24, J_F26-J_F24
+    stf.spill   [r10] = f25, J_F27-J_F25
+    ;;
+    stf.spill   [r11] = f26, J_F28-J_F26
+    stf.spill   [r10] = f27, J_F29-J_F27
+    ;;
+    stf.spill   [r11] = f28, J_F30-J_F28
+    stf.spill   [r10] = f29, J_F31-J_F29
+    ;;
+    stf.spill   [r11] = f30, J_FPSR-J_F30
+    stf.spill   [r10] = f31, J_B0-J_F31     // size of f31 + fpsr
+    //
+    // save FPSR register & branch registers
+    //
+    mov     r2 = ar.fpsr    // save fpsr register
+    mov     r3 = b0
+    ;;
+    st8     [r11] = r2, J_B1-J_FPSR
+    st8     [r10] = r3, J_B2-J_B0
+    mov     r2 = b1
+    mov     r3 = b2
+    ;;
+    st8     [r11] = r2, J_B3-J_B1
+    st8     [r10] = r3, J_B4-J_B2
+    mov     r2 = b3
+    mov     r3 = b4
+    ;;
+    st8     [r11] = r2, J_B5-J_B3
+    st8     [r10] = r3
+    mov     r2 = b5
+    ;;
+    st8     [r11] = r2
+    ;;
+    //
+    // return
+    //
+    mov     r8 = r0         // return 0 from setjmp
+    mov     ar.unat = r14   // restore unat
+    br.ret.sptk b0
+    .endp setjmp
+
+//
+// void longjmp(struct jmp_buffer *, int val)
+//
+//  Perform a non-local goto.
+//
+// Description:
+//
+//  LongJump initializes the register set to the values saved by a
+//  previous 'SetJump' and jumps to the return location saved by that
+//  'SetJump'.  This has the effect of unwinding the stack and returning
+//  for a second time to the 'SetJump'.
+//
+
+	.align 32
+	.global longjmp
+	.proc longjmp
+longjmp:
+    //
+    //  Make sure buffer is aligned at 16byte boundary
+    //
+    add     r10 = -0x10,r0  ;;  // mask the lower 4 bits
+    and     r32 = r32, r10;;
+    add     r32 = 0x10, r32;;   // move to next 16 byte boundary
+
+    //
+    // caching the return value as we do invala in the end
+    //
+    mov     r8 = r33            // return value
+
+    //
+    //  get immediate context
+    //
+    mov     r14 = ar.rsc        // get user RSC conf
+    add     r10 = J_PFS, r32    // get address of pfs
+    add     r11 = J_NATS, r32
+    ;;
+    ld8     r15 = [r10], J_BSP-J_PFS    // get pfs
+    ld8     r2 = [r11], J_LC-J_NATS     // get unat for spilled regs
+    ;;
+    mov     ar.unat = r2
+    ;;
+    ld8     r16 = [r10], J_PREDS-J_BSP  // get backing store pointer
+    mov     ar.rsc = r0         // put RSE in enforced lazy
+    mov     ar.pfs = r15
+    ;;
+
+    //
+    // while returning from longjmp the BSPSTORE and BSP needs to be
+    // same and discard all the registers allocated after we did
+    // setjmp. Also, we need to generate the RNAT register since we
+    // did not flushed the RSE on setjmp.
+    //
+    mov     r17 = ar.bspstore   // get current BSPSTORE
+    ;;
+    cmp.ltu p6,p7 = r17, r16    // is it less than BSP of
+(p6)    br.spnt.few .flush_rse
+    mov     r19 = ar.rnat       // get current RNAT
+    ;;
+    loadrs                      // invalidate dirty regs
+    br.sptk.many    .restore_rnat       // restore RNAT
+
+.flush_rse:
+    flushrs
+    ;;
+    mov     r19 = ar.rnat       // get current RNAT
+    mov     r17 = r16           // current BSPSTORE
+    ;;
+.restore_rnat:
+    //
+    // check if RNAT is saved between saved BSP and curr BSPSTORE
+    //
+    mov     r18 = 0x3f
+    ;;
+    dep     r18 = r18,r16,3,6   // get RNAT address
+    ;;
+    cmp.ltu p8,p9 = r18, r17    // RNAT saved on RSE
+    ;;
+(p8)    ld8     r19 = [r18]     // get RNAT from RSE
+    ;;
+    mov     ar.bspstore = r16   // set new BSPSTORE
+    ;;
+    mov     ar.rnat = r19       // restore RNAT
+    mov     ar.rsc = r14        // restore RSC conf
+
+
+    ld8     r3 = [r11], J_R4-J_LC       // get lc register
+    ld8     r2 = [r10], J_R5-J_PREDS    // get predicates
+    ;;
+    mov     pr = r2, -1
+    mov     ar.lc = r3
+    //
+    //  restore preserved general registers & NaT's
+    //
+    ld8.fill    r4 = [r11], J_R6-J_R4
+    ;;
+    ld8.fill    r5 = [r10], J_R7-J_R5
+    ld8.fill    r6 = [r11], J_SP-J_R6
+    ;;
+    ld8.fill    r7 = [r10], J_F2-J_R7
+    ld8.fill    sp = [r11], J_F3-J_SP
+    ;;
+    //
+    //  restore floating registers
+    //
+    ldf.fill    f2 = [r10], J_F4-J_F2
+    ldf.fill    f3 = [r11], J_F5-J_F3
+    ;;
+    ldf.fill    f4 = [r10], J_F16-J_F4
+    ldf.fill    f5 = [r11], J_F17-J_F5
+    ;;
+    ldf.fill    f16 = [r10], J_F18-J_F16
+    ldf.fill    f17 = [r11], J_F19-J_F17
+    ;;
+    ldf.fill    f18 = [r10], J_F20-J_F18
+    ldf.fill    f19 = [r11], J_F21-J_F19
+    ;;
+    ldf.fill    f20 = [r10], J_F22-J_F20
+    ldf.fill    f21 = [r11], J_F23-J_F21
+    ;;
+    ldf.fill    f22 = [r10], J_F24-J_F22
+    ldf.fill    f23 = [r11], J_F25-J_F23
+    ;;
+    ldf.fill    f24 = [r10], J_F26-J_F24
+    ldf.fill    f25 = [r11], J_F27-J_F25
+    ;;
+    ldf.fill    f26 = [r10], J_F28-J_F26
+    ldf.fill    f27 = [r11], J_F29-J_F27
+    ;;
+    ldf.fill    f28 = [r10], J_F30-J_F28
+    ldf.fill    f29 = [r11], J_F31-J_F29
+    ;;
+    ldf.fill    f30 = [r10], J_FPSR-J_F30
+    ldf.fill    f31 = [r11], J_B0-J_F31 ;;
+
+    //
+    // restore branch registers and fpsr
+    //
+    ld8     r16 = [r10], J_B1-J_FPSR    // get fpsr
+    ld8     r17 = [r11], J_B2-J_B0      // get return pointer
+    ;;
+    mov     ar.fpsr = r16
+    mov     b0 = r17
+    ld8     r2 = [r10], J_B3-J_B1
+    ld8     r3 = [r11], J_B4-J_B2
+    ;;
+    mov     b1 = r2
+    mov     b2 = r3
+    ld8     r2 = [r10], J_B5-J_B3
+    ld8     r3 = [r11]
+    ;;
+    mov     b3 = r2
+    mov     b4 = r3
+    ld8     r2 = [r10]
+    ld8     r21 = [r32]         // get user unat
+    ;;
+    mov     b5 = r2
+    mov     ar.unat = r21
+
+    //
+    // invalidate ALAT
+    //
+    invala ;;
+
+    br.ret.sptk b0
+    .endp longjmp
diff --git a/usr/klibc/arch/ia64/syscall.S b/usr/klibc/arch/ia64/syscall.S
new file mode 100644
index 0000000..9929618
--- /dev/null
+++ b/usr/klibc/arch/ia64/syscall.S
@@ -0,0 +1,20 @@
+#
+# arch/ia64/syscall.S
+#
+
+#include <asm/unistd.h>
+
+	.text
+	.align	32
+	.proc	__syscall_error
+	.globl	__syscall_error
+__syscall_error:
+	addl	r2 = @ltoffx(errno),gp
+	;;
+	ld8.mov	r3 = [r2],errno
+	;;
+	st4	[r3] = r8
+	mov	r8 = -1
+	br.ret.sptk.many b0
+	.size	__syscall_error, .-__syscall_error
+	.endp	__syscall_error
diff --git a/usr/klibc/arch/ia64/sysstub.ph b/usr/klibc/arch/ia64/sysstub.ph
new file mode 100644
index 0000000..8e686c6
--- /dev/null
+++ b/usr/klibc/arch/ia64/sysstub.ph
@@ -0,0 +1,29 @@
+# -*- perl -*-
+#
+# arch/ia64/sysstub.ph
+#
+# Script to generate system call stubs
+#
+
+sub make_sysstub($$$$$@) {
+    my($outputdir, $fname, $type, $sname, $stype, @args) = @_;
+
+    open(OUT, '>', "${outputdir}/${fname}.S");
+    print OUT "#include <asm/unistd.h>\n";
+    print OUT "\n";
+    print OUT "\t.text\n";
+    print OUT "\t.align 32\n";
+    print OUT "\t.proc ${fname}\n";
+    print OUT "\t.globl ${fname}\n";
+    print OUT "${fname}:\n";
+    print OUT "\tmov\tr15 = __NR_${sname}\n";
+    print OUT "\tbreak __BREAK_SYSCALL\n";
+    print OUT "\tcmp.eq p6,p0 = -1,r10\n";
+    print OUT "(p6)\tbr.few __syscall_error\n";
+    print OUT "\tbr.ret.sptk.many b0\n";
+    print OUT "\t.size\t${fname},.-${fname}\n";
+    print OUT "\t.endp\t${fname}\n";
+    close(OUT);
+}
+
+1;
diff --git a/usr/klibc/arch/ia64/vfork.S b/usr/klibc/arch/ia64/vfork.S
new file mode 100644
index 0000000..1a84902
--- /dev/null
+++ b/usr/klibc/arch/ia64/vfork.S
@@ -0,0 +1,42 @@
+/*
+ * ia64 specific vfork syscall
+ *
+ * Written By:	 Martin Hicks <mort@wildopensource.com>
+ *
+ */
+
+/* This syscall is a special case of the clone syscall */
+#include <asm/unistd.h>
+#include <asm/signal.h>
+#include <klibc/archsys.h>
+
+/* These are redefined here because linux/sched.h isn't safe for
+ * inclusion in asm.
+ */
+#define CLONE_VM    0x00000100 /* set if VM shared between processes */
+#define CLONE_VFORK 0x00004000 /* set if parent wants the child to wake it up on exit */
+
+/* pid_t vfork(void) */
+/* Implemented as clone(CLONE_VFORK | CLONE_VM | SIGCHLD, 0) */
+
+	.align 32
+	.proc vfork
+	.global vfork
+vfork:
+	alloc r2=ar.pfs,0,0,2,0
+	mov	r15=__NR_clone
+	mov	out0=CLONE_VM|CLONE_VFORK|SIGCHLD
+	mov     out1=0
+	;;
+	break 0x100000      // Do the syscall
+	;;
+	addl	r15=0,r1
+	cmp.eq  p7,p6 = -1,r10
+	;;
+	ld8	r14=[r15]
+	;;
+(p7)	st4	[r14]=r8
+	;;
+(p7)	mov	r8=-1
+	br.ret.sptk.many b0
+	.endp vfork
diff --git a/usr/klibc/arch/m32r/Kbuild b/usr/klibc/arch/m32r/Kbuild
new file mode 100644
index 0000000..ceb2ba0
--- /dev/null
+++ b/usr/klibc/arch/m32r/Kbuild
@@ -0,0 +1,13 @@
+#
+# klibc files for m32r
+#
+
+
+klib-y := setjmp.o syscall.o
+
+klib-y += ../../libgcc/__divdi3.o     ../../libgcc/__moddi3.o
+klib-y += ../../libgcc/__udivdi3.o    ../../libgcc/__umoddi3.o
+klib-y += ../../libgcc/__udivmoddi4.o
+
+always  := crt0.o
+targets := crt0.o
diff --git a/usr/klibc/arch/m32r/MCONFIG b/usr/klibc/arch/m32r/MCONFIG
new file mode 100644
index 0000000..7ca2785
--- /dev/null
+++ b/usr/klibc/arch/m32r/MCONFIG
@@ -0,0 +1,18 @@
+# -*- makefile -*-
+#
+# arch/m32r/MCONFIG
+#
+# Special rules for this architecture.  Note that this is actually
+# included from the main Makefile, and that pathnames should be
+# accordingly.
+#
+
+KLIBCOPTFLAGS += -Os
+KLIBCBITSIZE  = 32
+
+# Extra linkflags when building the shared version of the library
+# This address needs to be reachable using normal inter-module
+# calls, and work on the memory models for this architecture
+# 224 MB - normal binaries start at 0 (?)
+# (lib?)gcc on cris seems to insist on producing .init and .fini sections
+KLIBCSHAREDFLAGS     = --section-start .init=0x0e000100
diff --git a/usr/klibc/arch/m32r/crt0.S b/usr/klibc/arch/m32r/crt0.S
new file mode 100644
index 0000000..568e5d8
--- /dev/null
+++ b/usr/klibc/arch/m32r/crt0.S
@@ -0,0 +1,24 @@
+#
+# arch/m32r/crt0.S
+#
+# Does arch-specific initialization and invokes __libc_init
+# with the appropriate arguments.
+#
+# See __static_init.c or __shared_init.c for the expected
+# arguments.
+#
+
+	.text
+	.balign 4
+	.type	_start,@function
+	.globl	_start
+_start:
+	/* Save the address of the ELF argument array */
+	mv	r0, sp
+
+	/* atexit() function (assume null) */
+	xor	r1, r1
+
+	bl	__libc_init
+
+	.size _start, .-_start
diff --git a/usr/klibc/arch/m32r/setjmp.S b/usr/klibc/arch/m32r/setjmp.S
new file mode 100644
index 0000000..02a25e7
--- /dev/null
+++ b/usr/klibc/arch/m32r/setjmp.S
@@ -0,0 +1,47 @@
+#
+# arch/m32r/setjmp.S
+#
+# setjmp/longjmp for the M32R architecture
+#
+
+#
+# The jmp_buf is assumed to contain the following, in order:
+#	r8-r15
+#
+#	Note that r14 is the return address register and
+#	r15 is the stack pointer.
+#
+
+	.text
+	.balign 4
+	.globl	setjmp
+	.type	setjmp, @function
+setjmp:
+	st	r8, @r0
+	st	r9, @+r0
+	st	r10, @+r0
+	st	r11, @+r0
+	st	r12, @+r0
+	st	r13, @+r0
+	st	r14, @+r0
+	st	r15, @+r0
+	xor	r0, r0
+	jmp	r14
+	.size	setjmp,.-setjmp
+
+	.text
+	.balign 4
+	.globl	longjmp
+	.type	longjmp, @function
+longjmp:
+	ld	r8, @r0+
+	ld	r9, @r0+
+	ld	r10, @r0+
+	ld	r11, @r0+
+	ld	r12, @r0+
+	ld	r13, @r0+
+	ld	r14, @r0+
+	ld	r15, @r0
+	mv	r0, r1
+	jmp	r14
+	.size longjmp,.-longjmp
diff --git a/usr/klibc/arch/m32r/syscall.S b/usr/klibc/arch/m32r/syscall.S
new file mode 100644
index 0000000..a20a336
--- /dev/null
+++ b/usr/klibc/arch/m32r/syscall.S
@@ -0,0 +1,29 @@
+/*
+ * arch/m32r/syscall.S
+ *
+ *     r7 contains the syscall number (set by stub);
+ * r0..r3 contains arguments 0-3 per standard calling convention;
+ * r4..r5 contains arguments 4-5, but we have to get those from
+ *        the stack.
+ */
+
+	.section ".text","ax"
+	.balign	4
+	.globl	__syscall_common
+	.type	__syscall_common,@function
+__syscall_common:
+	ld	r4,@sp
+	ld	r5,@(4,sp)
+	trap	#2
+	cmpi	r0, #-4096
+	bnc	1f
+	jmp	r14
+1:
+	seth	r2,#high(errno)
+	or3	r2,r2,#low(errno)
+	neg	r1,r0
+	st	r1,@r7
+	ldi	r0,#-1
+	jmp	r14
+
+	.size	__syscall_common,.-__syscall_common
diff --git a/usr/klibc/arch/m32r/sysstub.ph b/usr/klibc/arch/m32r/sysstub.ph
new file mode 100644
index 0000000..98dfb9d
--- /dev/null
+++ b/usr/klibc/arch/m32r/sysstub.ph
@@ -0,0 +1,25 @@
+# -*- perl -*-
+#
+# arch/m32r/sysstub.ph
+#
+# Script to generate system call stubs
+#
+
+sub make_sysstub($$$$$@) {
+    my($outputdir, $fname, $type, $sname, $stype, @args) = @_;
+
+    open(OUT, '>', "${outputdir}/${fname}.S");
+    print OUT "#include <asm/unistd.h>\n";
+    print OUT "\n";
+    print OUT "\t.text\n";
+    print OUT "\t.type\t${fname},\@function\n";
+    print OUT "\t.globl\t${fname}\n";
+    print OUT "\t.balign\t4\n";
+    print OUT "${fname}:\n";
+    print OUT "\tldi\tr7,#__NR_${sname}\n";
+    print OUT "\tbra\t__syscall_common\n";
+    print OUT "\t.size ${fname},.-${fname}\n";
+    close(OUT);
+}
+
+1;
diff --git a/usr/klibc/arch/m68k/Kbuild b/usr/klibc/arch/m68k/Kbuild
new file mode 100644
index 0000000..8d6137c
--- /dev/null
+++ b/usr/klibc/arch/m68k/Kbuild
@@ -0,0 +1,8 @@
+#
+# klibc files for m68k
+#
+
+klib-y := setjmp.o syscall.o vfork.o
+
+always  := crt0.o
+targets := crt0.o
diff --git a/usr/klibc/arch/m68k/MCONFIG b/usr/klibc/arch/m68k/MCONFIG
new file mode 100644
index 0000000..7d4615d
--- /dev/null
+++ b/usr/klibc/arch/m68k/MCONFIG
@@ -0,0 +1,19 @@
+# -*- makefile -*-
+#
+# arch/m68k/MCONFIG
+#
+# Special rules for this architecture.  Note that this is actually
+# included from the main Makefile, and that pathnames should be
+# accordingly.
+#
+
+KLIBCOPTFLAGS += -Os -fomit-frame-pointer
+KLIBCBITSIZE  = 32
+
+# Extra linkflags when building the shared version of the library
+# This address needs to be reachable using normal inter-module
+# calls, and work on the memory models for this architecture
+# 2816 MB - normal binaries start at 2048 MB if I read the link
+# script right.  Not sure if there is a fundamental reason
+# to not duck below the halfway point...
+KLIBCSHAREDFLAGS        = -Ttext 0xb0000000
diff --git a/usr/klibc/arch/m68k/crt0.S b/usr/klibc/arch/m68k/crt0.S
new file mode 100644
index 0000000..fbf6f13
--- /dev/null
+++ b/usr/klibc/arch/m68k/crt0.S
@@ -0,0 +1,27 @@
+#
+# arch/m68k/crt0.S
+#
+# Does arch-specific initialization and invokes __libc_init
+# with the appropriate arguments.
+#
+# See __static_init.c or __shared_init.c for the expected
+# arguments.
+#
+
+	.text
+	.align 4
+	.type _start,@function
+	.globl _start
+_start:
+	# Zero out the frame pointer to be nice to the debugger
+	movea.l	#0,%a6
+	# Save the address of the ELF argument array
+	move.l	%a7, %d0
+	# Push a zero on the stack in lieu of atexit pointer
+	clr.l	-(%sp)
+	# Push ELF argument pointer on the stack
+	move.l	%d0, -(%a7)
+
+	jbsr	__libc_init
+
+	.size _start, .-_start
diff --git a/usr/klibc/arch/m68k/setjmp.S b/usr/klibc/arch/m68k/setjmp.S
new file mode 100644
index 0000000..1b3591e
--- /dev/null
+++ b/usr/klibc/arch/m68k/setjmp.S
@@ -0,0 +1,43 @@
+#
+# arch/m68k/setjmp.S
+#
+# setjmp/longjmp for the m68k architecture
+#
+
+#
+# The jmp_buf is assumed to contain the following, in order:
+#	%d2..%d7
+#	%a2..%a7
+#	return address
+#
+
+	.text
+	.align 2
+	.globl setjmp
+	.type setjmp, @function
+setjmp:
+	move.l	(%sp)+, %d0		| Return address
+	movea.l	(%sp), %a0		| Buffer address
+	| Postincrement mode is not permitted here...
+	movem.l	%d2-%d7/%a2-%a7, (%a0)
+	move.l	%d0, 48(%a0)		| Return address
+	move.l	%d0, -(%sp)		| Restore return address
+	clr.l	%d0			| Return value
+	movea.l	%d0, %a0		| Redundant return...
+	rts
+
+	.size setjmp,.-setjmp
+
+	.text
+	.align 2
+	.globl longjmp
+	.type longjmp, @function
+longjmp:
+	move.l	4(%sp), %a0		| Buffer address
+	move.l	8(%sp), %d0		| Return value
+	movem.l	(%a0)+, %d2-%d7/%a2-%a7
+	movea.l	(%a0), %a1
+	movea.l	%d0, %a0		| Redundant return...
+	jmp.l	(%a1)
+
+	.size longjmp,.-longjmp
diff --git a/usr/klibc/arch/m68k/syscall.S b/usr/klibc/arch/m68k/syscall.S
new file mode 100644
index 0000000..966c92d
--- /dev/null
+++ b/usr/klibc/arch/m68k/syscall.S
@@ -0,0 +1,27 @@
+/*
+ * arch/m68k/syscall.S
+ *
+ * Common tail-handling code for system calls.
+ *
+ * The arguments are on the stack; the system call number in %d0.
+ */
+
+	.text
+	.align	2
+	.globl	__syscall_common
+	.type	__syscall_common, @function
+__syscall_common:
+	movem.l %d2-%d6, -(%sp)	/* 5 registers saved */
+	movem.l	24(%sp), %d1-%d6
+	trap	#0
+	cmpi.l	#-4095, %d0
+	blt.l	1f
+	neg.l	%d0
+	move.l	%d0, (errno)
+	moveq	#-1, %d0
+1:
+	movea.l	%d0, %a0	/* Redundant return */
+	movem.l (%sp)+, %d2-%d6 /* Restore registers */
+	rts
+
+	.size	__syscall_common,.-__syscall_common
diff --git a/usr/klibc/arch/m68k/sysstub.ph b/usr/klibc/arch/m68k/sysstub.ph
new file mode 100644
index 0000000..78c239d
--- /dev/null
+++ b/usr/klibc/arch/m68k/sysstub.ph
@@ -0,0 +1,26 @@
+# -*- perl -*-
+#
+# arch/m68k/sysstub.ph
+#
+# Script to generate system call stubs
+#
+
+sub make_sysstub($$$$$@) {
+    my($outputdir, $fname, $type, $sname, $stype, @args) = @_;
+
+    open(OUT, '>', "${outputdir}/${fname}.S");
+    print OUT "#include <asm/unistd.h>\n";
+    print OUT "\n";
+    print OUT "\t.type ${fname},\@function\n";
+    print OUT "\t.globl ${fname}\n";
+    print OUT "${fname}:\n";
+
+    $stype = 'common' if ( $stype eq '' );
+
+    print OUT "\tmove.l\t# __NR_${sname}, %d0\n";
+    print OUT "\tbr\t__syscall_$stype\n";
+    print OUT "\t.size ${fname},.-${fname}\n";
+    close(OUT);
+}
+
+1;
diff --git a/usr/klibc/arch/m68k/vfork.S b/usr/klibc/arch/m68k/vfork.S
new file mode 100644
index 0000000..a3a7e44
--- /dev/null
+++ b/usr/klibc/arch/m68k/vfork.S
@@ -0,0 +1,28 @@
+#
+# usr/klibc/arch/m68k/vfork.S
+#
+# vfork is nasty - there must be nothing at all on the stack above
+# the stack frame of the enclosing function.
+#
+
+#include <asm/unistd.h>
+
+	.text
+	.align	2
+	.globl	vfork
+	.type	vfork, @function
+vfork:
+	move.l	(%sp)+, %d1		/* Return address */
+	move.l	# __NR_vfork, %d0
+	trap	#0
+	move.l	%d1, -(%sp)
+	cmpi.l	#-4095, %d0
+	blt.l	1f
+	neg.l	%d0
+	move.l	%d0, (errno)
+	moveq	#-1, %d0
+1:
+	movea.l	%d0, %a0
+	rts
+
+	.size	vfork, .-vfork
diff --git a/usr/klibc/arch/mips/Kbuild b/usr/klibc/arch/mips/Kbuild
new file mode 100644
index 0000000..972e450
--- /dev/null
+++ b/usr/klibc/arch/mips/Kbuild
@@ -0,0 +1,14 @@
+#
+# klibc files for mips
+#
+
+klib-y := pipe.o vfork.o setjmp.o syscall.o
+
+klib-y += ../../libgcc/__clzsi2.o     ../../libgcc/__ashldi3.o
+klib-y += ../../libgcc/__ashrdi3.o    ../../libgcc/__lshrdi3.o
+klib-y += ../../libgcc/__divdi3.o     ../../libgcc/__moddi3.o
+klib-y += ../../libgcc/__udivdi3.o    ../../libgcc/__umoddi3.o
+klib-y += ../../libgcc/__udivmoddi4.o
+
+always  := crt0.o
+targets := crt0.o
diff --git a/usr/klibc/arch/mips/MCONFIG b/usr/klibc/arch/mips/MCONFIG
new file mode 100644
index 0000000..c6331a1
--- /dev/null
+++ b/usr/klibc/arch/mips/MCONFIG
@@ -0,0 +1,15 @@
+# -*- makefile -*-
+#
+# arch/mips/MCONFIG
+#
+# Special rules for this architecture.  Note that this is actually
+# included from the main Makefile, and that pathnames should be
+# accordingly.
+#
+
+KLIBCARCHREQFLAGS = -fno-pic -mno-abicalls -G 0
+KLIBCOPTFLAGS     += -Os
+KLIBCBITSIZE      = 32
+
+# Extra linkflags when building the shared version of the library
+KLIBCSHAREDFLAGS	= -T $(src)/arch/$(KLIBCARCH)/klibc.ld
diff --git a/usr/klibc/arch/mips/crt0.S b/usr/klibc/arch/mips/crt0.S
new file mode 100644
index 0000000..142d9f2
--- /dev/null
+++ b/usr/klibc/arch/mips/crt0.S
@@ -0,0 +1,25 @@
+#
+# arch/mips/crt0.S
+#
+# Does arch-specific initialization and invokes __libc_init
+# with the appropriate arguments.
+#
+# See __static_init.c or __shared_init.c for the expected
+# arguments.
+#
+
+#include <machine/asm.h>
+
+NESTED(__start, 32, sp)
+	subu	sp, 32
+	sw	zero, 16(sp)
+
+	lui	gp, %hi(_gp)		# Initialize gp
+	addiu	gp, gp, _gp
+
+	addiu	a0, sp, 32		# Pointer to ELF entry structure
+	move	a1, v0			# Kernel-provided atexit() pointer
+
+	jal	__libc_init
+
+	END(__start)
diff --git a/usr/klibc/arch/mips/klibc.ld b/usr/klibc/arch/mips/klibc.ld
new file mode 100644
index 0000000..5a2a7a6
--- /dev/null
+++ b/usr/klibc/arch/mips/klibc.ld
@@ -0,0 +1,214 @@
+/* Linker script for klibc.so, needed because of the the damned
+   GNU ld script headers problem */
+
+ENTRY(__start)
+SECTIONS
+{
+  /* Read-only sections, merged into text segment: */
+  /* This address needs to be reachable using normal inter-module
+      calls, and work on the memory models for this architecture */
+  /* 2 MB -- the normal starting point for text is 4 MB */
+  . = 0x00200400;
+  .interp         : { *(.interp) }
+  .reginfo        : { *(.reginfo) }
+  .dynamic        : { *(.dynamic) }
+  .hash           : { *(.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.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.sdata .rel.sdata.* .rel.gnu.linkonce.s.*)
+      *(.rel.sbss .rel.sbss.* .rel.gnu.linkonce.sb.*)
+      *(.rel.sdata2 .rel.sdata2.* .rel.gnu.linkonce.s2.*)
+      *(.rel.sbss2 .rel.sbss2.* .rel.gnu.linkonce.sb2.*)
+      *(.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.sdata .rela.sdata.* .rela.gnu.linkonce.s.*)
+      *(.rela.sbss .rela.sbss.* .rela.gnu.linkonce.sb.*)
+      *(.rela.sdata2 .rela.sdata2.* .rela.gnu.linkonce.s2.*)
+      *(.rela.sbss2 .rela.sbss2.* .rela.gnu.linkonce.sb2.*)
+      *(.rela.bss .rela.bss.* .rela.gnu.linkonce.b.*)
+    }
+  .rel.plt        : { *(.rel.plt) }
+  .rela.plt       : { *(.rela.plt) }
+  .init           :
+  {
+    KEEP (*(.init))
+  } =0
+  .plt            : { *(.plt) }
+  .text           :
+  {
+    _ftext = . ;
+    *(.text .stub .text.* .gnu.linkonce.t.*)
+    /* .gnu.warning sections are handled specially by elf32.em.  */
+    *(.gnu.warning)
+    *(.mips16.fn.*) *(.mips16.call.*)
+  } =0
+  .fini           :
+  {
+    KEEP (*(.fini))
+  } =0
+  PROVIDE (__etext = .);
+  PROVIDE (_etext = .);
+  PROVIDE (etext = .);
+  .rodata         : { *(.rodata .rodata.* .gnu.linkonce.r.*) }
+  .rodata1        : { *(.rodata1) }
+  .sdata2         : { *(.sdata2 .sdata2.* .gnu.linkonce.s2.*) }
+  .sbss2          : { *(.sbss2 .sbss2.* .gnu.linkonce.sb2.*) }
+  .eh_frame_hdr : { *(.eh_frame_hdr) }
+  /* 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(8192);
+  /* Ensure the __preinit_array_start label is properly aligned.  We
+     could instead move the label definition inside the section, but
+     the linker would then create the section even if it turns out to
+     be empty, which isn't pretty.  */
+  . = ALIGN(32 / 8);
+  PROVIDE (__preinit_array_start = .);
+  .preinit_array     : { *(.preinit_array) }
+  PROVIDE (__preinit_array_end = .);
+  PROVIDE (__init_array_start = .);
+  .init_array     : { *(.init_array) }
+  PROVIDE (__init_array_end = .);
+  PROVIDE (__fini_array_start = .);
+  .fini_array     : { *(.fini_array) }
+  PROVIDE (__fini_array_end = .);
+  .data           :
+  {
+    _fdata = . ;
+    *(.data .data.* .gnu.linkonce.d.*)
+    SORT(CONSTRUCTORS)
+  }
+  .data1          : { *(.data1) }
+  .tdata	  : { *(.tdata .tdata.* .gnu.linkonce.td.*) }
+  .tbss		  : { *(.tbss .tbss.* .gnu.linkonce.tb.*) *(.tcommon) }
+  .eh_frame       : { KEEP (*(.eh_frame)) }
+  .gcc_except_table   : { *(.gcc_except_table) }
+  .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))
+    /* We don't want to include the .ctor section from
+       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 ) .ctors))
+    KEEP (*(SORT(.ctors.*)))
+    KEEP (*(.ctors))
+  }
+  .dtors          :
+  {
+    KEEP (*crtbegin*.o(.dtors))
+    KEEP (*(EXCLUDE_FILE (*crtend*.o ) .dtors))
+    KEEP (*(SORT(.dtors.*)))
+    KEEP (*(.dtors))
+  }
+  .jcr            : { KEEP (*(.jcr)) }
+  _gp = ALIGN(16) + 0x7ff0;
+  .got            : { *(.got.plt) *(.got) }
+  /* We want the small data sections together, so single-instruction offsets
+     can access them all, and initialized data all before uninitialized, so
+     we can shorten the on-disk segment size.  */
+  .sdata          :
+  {
+    *(.sdata .sdata.* .gnu.linkonce.s.*)
+  }
+  .lit8           : { *(.lit8) }
+  .lit4           : { *(.lit4) }
+  _edata = .;
+  PROVIDE (edata = .);
+  __bss_start = .;
+  _fbss = .;
+  .sbss           :
+  {
+    PROVIDE (__sbss_start = .);
+    PROVIDE (___sbss_start = .);
+    *(.dynsbss)
+    *(.sbss .sbss.* .gnu.linkonce.sb.*)
+    *(.scommon)
+    PROVIDE (__sbss_end = .);
+    PROVIDE (___sbss_end = .);
+  }
+  .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.  */
+   . = ALIGN(32 / 8);
+  }
+  . = ALIGN(32 / 8);
+  _end = .;
+  PROVIDE (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) }
+  .gptab.sdata : { *(.gptab.data) *(.gptab.sdata) }
+  .gptab.sbss : { *(.gptab.bss) *(.gptab.sbss) }
+  /DISCARD/ : { *(.note.GNU-stack) }
+}
diff --git a/usr/klibc/arch/mips/pipe.S b/usr/klibc/arch/mips/pipe.S
new file mode 100644
index 0000000..02b9405
--- /dev/null
+++ b/usr/klibc/arch/mips/pipe.S
@@ -0,0 +1,16 @@
+#include <asm/asm.h>
+#include <asm/regdef.h>
+#include <asm/unistd.h>
+
+LEAF(pipe)
+	li	v0, __NR_pipe
+	syscall
+	bnez	a3, 1f
+	sw	v0,  (a0)
+	sw	v1, 4(a0)
+	li	v0, 0
+	b	2f
+1:	sw	v0, errno
+	li	v0, -1
+2:	jr	ra
+	END(pipe)
diff --git a/usr/klibc/arch/mips/setjmp.S b/usr/klibc/arch/mips/setjmp.S
new file mode 100644
index 0000000..68eed19
--- /dev/null
+++ b/usr/klibc/arch/mips/setjmp.S
@@ -0,0 +1,80 @@
+#
+# arch/mips/setjmp.S
+#
+# setjmp/longjmp for the MIPS architecture
+#
+# The jmp_buf is assumed to contain the following, in order:
+#	s0..s7
+#	gp
+#	sp
+#	s8
+#	ra
+#	f20..f31
+#	fcr31
+#
+
+#include <machine/asm.h>
+
+LEAF(setjmp)
+	sw	s0,  0(a0)
+	sw	s1,  4(a0)
+	sw	s2,  8(a0)
+	sw	s3, 12(a0)
+	sw	s4, 16(a0)
+	sw	s5, 20(a0)
+	sw	s6, 24(a0)
+	sw	s7, 28(a0)
+	sw	gp, 32(a0)
+	sw	sp, 36(a0)
+	sw	s8, 40(a0)
+	sw	ra, 44(a0)
+	cfc1	t0,$31
+	swc1	$f20,48(a0)
+	swc1	$f21,52(a0)
+	swc1	$f22,56(a0)
+	swc1	$f23,60(a0)
+	swc1	$f24,64(a0)
+	swc1	$f25,68(a0)
+	swc1	$f26,72(a0)
+	swc1	$f27,76(a0)
+	swc1	$f28,80(a0)
+	swc1	$f29,84(a0)
+	swc1	$f30,88(a0)
+	swc1	$f31,92(a0)
+	sw	t0,96(a0)
+	move	v0,zero
+	jr	ra
+
+	END(setjmp)
+
+LEAF(longjmp)
+	lw	s0,  0(a0)
+	lw	s1,  4(a0)
+	lw	s2,  8(a0)
+	lw	s3, 12(a0)
+	lw	s4, 16(a0)
+	lw	s5, 20(a0)
+	lw	s6, 24(a0)
+	lw	s7, 28(a0)
+	lw	gp, 32(a0)
+	lw	sp, 36(a0)
+	lw	s8, 40(a0)
+	lw	ra, 44(a0)
+	lw	t0, 96(a0)
+	lwc1	$f20,48(a0)
+	lwc1	$f21,52(a0)
+	lwc1	$f22,56(a0)
+	lwc1	$f23,60(a0)
+	lwc1	$f24,64(a0)
+	lwc1	$f25,68(a0)
+	lwc1	$f26,72(a0)
+	lwc1	$f27,76(a0)
+	lwc1	$f28,80(a0)
+	lwc1	$f29,84(a0)
+	lwc1	$f30,88(a0)
+	lwc1	$f31,92(a0)
+	ctc1	t0,$31
+	move	v0,a1
+	jr	ra
+
+	END(longjmp)
diff --git a/usr/klibc/arch/mips/syscall.S b/usr/klibc/arch/mips/syscall.S
new file mode 100644
index 0000000..9f308df
--- /dev/null
+++ b/usr/klibc/arch/mips/syscall.S
@@ -0,0 +1,16 @@
+#include <asm/asm.h>
+#include <asm/regdef.h>
+#include <asm/unistd.h>
+
+	.set noreorder
+
+LEAF(__syscall_common)
+	syscall
+        beqz    a3, 1f
+	# sw is actually two instructions; the first one goes
+	# in the branch delay slot
+	# XXX: Break this up manually; as it is now it generates warnings.
+        sw      v0, errno
+        li      v0, -1
+1:      jr      ra
+	END(__syscall_common)
diff --git a/usr/klibc/arch/mips/sysstub.ph b/usr/klibc/arch/mips/sysstub.ph
new file mode 100644
index 0000000..a71d5d0
--- /dev/null
+++ b/usr/klibc/arch/mips/sysstub.ph
@@ -0,0 +1,30 @@
+# -*- perl -*-
+#
+# arch/mips/sysstub.ph
+#
+# Script to generate system call stubs
+#
+
+# On MIPS, most system calls follow the standard convention, with the
+# system call number in r0 (v0), return an error value in r19 (a3) as
+# well as the return value in r0 (v0).
+
+sub make_sysstub($$$$$@) {
+    my($outputdir, $fname, $type, $sname, $stype, @args) = @_;
+
+    $stype = $stype || 'common';
+    open(OUT, '>', "${outputdir}/${fname}.S");
+    print OUT "#include <asm/asm.h>\n";
+    print OUT "#include <asm/regdef.h>\n";
+    print OUT "#include <asm/unistd.h>\n";
+    print OUT "\n";
+    print OUT "\t.set noreorder\n";
+    print OUT "\n";
+    print OUT "LEAF(${fname})\n";
+    print OUT "\tj\t__syscall_${stype}\n";
+    print OUT "\t  li\tv0, __NR_${sname}\n";
+    print OUT "\tEND(${fname})\n";
+    close(OUT);
+}
+
+1;
diff --git a/usr/klibc/arch/mips/vfork.S b/usr/klibc/arch/mips/vfork.S
new file mode 100644
index 0000000..f9f035b
--- /dev/null
+++ b/usr/klibc/arch/mips/vfork.S
@@ -0,0 +1,16 @@
+#include <asm/asm.h>
+#include <asm/regdef.h>
+#include <asm/unistd.h>
+
+#define CLONE_VM	0x00000100
+#define CLONE_VFORK	0x00004000
+#define SIGCHLD		18
+
+	.set noreorder
+
+LEAF(vfork)
+	li	a0, CLONE_VFORK | CLONE_VM | SIGCHLD
+	li	a1, 0
+	j	__syscall_common
+	  li	v0, __NR_clone
+	END(vfork)
diff --git a/usr/klibc/arch/mips64/Kbuild b/usr/klibc/arch/mips64/Kbuild
new file mode 100644
index 0000000..970c0f8
--- /dev/null
+++ b/usr/klibc/arch/mips64/Kbuild
@@ -0,0 +1,3 @@
+#
+# klibc files for mips64
+#
diff --git a/usr/klibc/arch/mips64/MCONFIG b/usr/klibc/arch/mips64/MCONFIG
new file mode 100644
index 0000000..5c50b8d
--- /dev/null
+++ b/usr/klibc/arch/mips64/MCONFIG
@@ -0,0 +1,11 @@
+# -*- makefile -*-
+#
+# arch/mips64/MCONFIG
+#
+# Special rules for this architecture.  Note that this is actually
+# included from the main Makefile, and that pathnames should be
+# accordingly.
+#
+
+KLIBCOPTFLAGS += -Os
+KLIBCBITSIZE  = 64
diff --git a/usr/klibc/arch/parisc/Kbuild b/usr/klibc/arch/parisc/Kbuild
new file mode 100644
index 0000000..57ca5c2
--- /dev/null
+++ b/usr/klibc/arch/parisc/Kbuild
@@ -0,0 +1,8 @@
+#
+# klibc files for parisc
+#
+
+klib-y := setjmp.o syscall.o vfork.o
+
+always  := crt0.o
+targets := crt0.o
diff --git a/usr/klibc/arch/parisc/MCONFIG b/usr/klibc/arch/parisc/MCONFIG
new file mode 100644
index 0000000..628e987
--- /dev/null
+++ b/usr/klibc/arch/parisc/MCONFIG
@@ -0,0 +1,12 @@
+# -*- makefile -*-
+#
+# arch/parisc/MCONFIG
+#
+# Special rules for this architecture.  Note that this is actually
+# included from the main Makefile, and that pathnames should be
+# accordingly.
+#
+
+KLIBCOPTFLAGS += -Os -fomit-frame-pointer
+KLIBCBITSIZE  = 32
+KLIBCSHAREDFLAGS	= -Ttext 0x40001000
diff --git a/usr/klibc/arch/parisc/crt0.S b/usr/klibc/arch/parisc/crt0.S
new file mode 100644
index 0000000..0922446
--- /dev/null
+++ b/usr/klibc/arch/parisc/crt0.S
@@ -0,0 +1,37 @@
+	.align 4
+
+	.import $global$, data
+	.import __libc_init, code
+
+	.global _start
+	.export _start, ENTRY
+	.type _start,@function
+
+	.proc
+	.callinfo
+
+_start:
+/* extend the stack by 64-bytes */
+	ldo	64(%sp), %sp
+
+/* %r25 = argc
+ * %r24 = argv
+ * envp = argv + (argc + 1)
+ * elfdata = (argv - 4)
+ */
+	ldo	-4(%r24), %r26
+
+/* load global data */
+	ldil	L%$global$, %dp
+	ldo	R%$global$(%dp), %dp
+
+/* parisc abi puts the atexit pointer in %r23, see ELF_PLAT_INIT() */
+	copy	%r23, %r25
+
+/* branch to __libc_init */
+	bl	__libc_init,%r2
+	nop
+/* break miserably if we ever return */
+	iitlbp	%r0,(%sr0,%r0) /* illegal instruction */
+	nop
+	.procend
diff --git a/usr/klibc/arch/parisc/setjmp.S b/usr/klibc/arch/parisc/setjmp.S
new file mode 100644
index 0000000..c8d766c
--- /dev/null
+++ b/usr/klibc/arch/parisc/setjmp.S
@@ -0,0 +1,88 @@
+/*
+ * parisc specific setjmp/longjmp routines
+ *
+ */
+
+        .text
+        .align 4
+        .global setjmp
+        .export setjmp, code
+        .proc
+        .callinfo
+setjmp:
+        stw     %r3,0(%r26)
+        stw     %r4,8(%r26)
+        stw     %r5,12(%r26)
+        stw     %r6,16(%r26)
+        stw     %r7,20(%r26)
+        stw     %r8,24(%r26)
+        stw     %r9,28(%r26)
+        stw     %r10,32(%r26)
+        stw     %r11,36(%r26)
+        stw     %r12,40(%r26)
+        stw     %r13,44(%r26)
+        stw     %r14,48(%r26)
+        stw     %r15,52(%r26)
+        stw     %r16,56(%r26)
+        stw     %r17,60(%r26)
+        stw     %r18,64(%r26)
+        stw     %r19,68(%r26)
+        stw     %r27,72(%r26)
+        stw     %r30,76(%r26)
+        stw     %rp,80(%r26)
+        ldo     88(%r26),%r19
+        fstd,ma %fr12,8(%r19)
+        fstd,ma %fr13,8(%r19)
+        fstd,ma %fr14,8(%r19)
+        fstd,ma %fr15,8(%r19)
+        fstd,ma %fr16,8(%r19)
+        fstd,ma %fr17,8(%r19)
+        fstd,ma %fr18,8(%r19)
+        fstd,ma %fr19,8(%r19)
+        fstd,ma %fr20,8(%r19)
+        fstd     %fr21,0(%r19)
+        bv       %r0(%rp)
+        copy     %r0,%r28
+	.procend
+
+	.text
+	.align 4
+	.global longjmp
+	.export longjmp, code
+	.proc
+	.callinfo
+longjmp:
+        ldw     0(%r26),%r3
+        ldw     8(%r26),%r4
+        ldw     12(%r26),%r5
+        ldw     16(%r26),%r6
+        ldw     20(%r26),%r7
+        ldw     24(%r26),%r8
+        ldw     28(%r26),%r9
+        ldw     32(%r26),%r10
+        ldw     36(%r26),%r11
+        ldw     40(%r26),%r12
+        ldw     44(%r26),%r13
+        ldw     48(%r26),%r14
+        ldw     52(%r26),%r15
+        ldw     56(%r26),%r16
+        ldw     60(%r26),%r17
+        ldw     64(%r26),%r18
+        ldw     68(%r26),%r19
+        ldw     72(%r26),%r27
+        ldw     76(%r26),%r30
+        ldw     80(%r26),%rp
+        ldo     88(%r26),%r20
+        fldd,ma 8(%r20),%fr12
+        fldd,ma 8(%r20),%fr13
+        fldd,ma 8(%r20),%fr14
+        fldd,ma 8(%r20),%fr15
+        fldd,ma 8(%r20),%fr16
+        fldd,ma 8(%r20),%fr17
+        fldd,ma 8(%r20),%fr18
+        fldd,ma 8(%r20),%fr19
+        fldd,ma 8(%r20),%fr20
+        fldd    0(%r20),%fr21
+        bv      %r0(%rp)
+        copy    %r25,%r28
+        .procend
diff --git a/usr/klibc/arch/parisc/syscall.S b/usr/klibc/arch/parisc/syscall.S
new file mode 100644
index 0000000..0ff2a65
--- /dev/null
+++ b/usr/klibc/arch/parisc/syscall.S
@@ -0,0 +1,36 @@
+/*
+ * arch/parisc/syscall.S
+ *
+ * %r20 contains the system call number, %r2 contains whence we came
+ *
+ */
+
+	.text
+	.align 64				; cache-width aligned
+	.globl	__syscall_common
+	.type	__syscall_common,@function
+__syscall_common:
+	ldo 		0x40(%sp),%sp
+	stw 		%rp,-0x54(%sp)		; save return pointer
+
+	ldw 		-0x74(%sp),%r22		; %arg4
+	ldw 		-0x78(%sp),%r21		; %arg5
+
+	ble		0x100(%sr2, %r0)	; jump to gateway page
+	nop					; can we move a load here?
+
+	ldi		-0x1000,%r19		; %r19 = -4096
+	sub		%r0,%ret0,%r22		; %r22 = -%ret0
+	cmpb,>>=,n	%r19,%ret0,1f		; if %ret0 >= -4096UL
+	ldi		-1,%ret0		; nullified on taken forward
+
+	/* store %r22 to errno... */
+	ldil		L%errno,%r1
+	ldo		R%errno(%r1),%r1
+	stw		%r22,0(%r1)
+1:
+	ldw 		-0x54(%sp),%rp		; restore return pointer
+	bv		%r0(%rp)		; jump back
+	ldo 		-0x40(%sp),%sp
+
+	.size __syscall_common,.-__syscall_common
diff --git a/usr/klibc/arch/parisc/sysstub.ph b/usr/klibc/arch/parisc/sysstub.ph
new file mode 100644
index 0000000..e2196ac
--- /dev/null
+++ b/usr/klibc/arch/parisc/sysstub.ph
@@ -0,0 +1,28 @@
+# -*- perl -*-
+#
+# arch/parisc/sysstub.ph
+#
+# Script to generate system call stubs
+#
+
+sub make_sysstub($$$$$@) {
+    my($outputdir, $fname, $type, $sname, $stype, @args) = @_;
+
+    open(OUT, '>', "${outputdir}/${fname}.S");
+    print OUT "#include <asm/unistd.h>\n";
+    print OUT "\n";
+    print OUT "\t.text\n";
+    print OUT "\t.align 4\n";
+    print OUT "\t.import __syscall_common, code\n";
+    print OUT "\t.global ${fname}\n";
+    print OUT "\t.export ${fname}, code\n";
+    print OUT "\t.proc\n";
+    print OUT "\.callinfo\n";
+    print OUT "${fname}:\n";
+    print OUT "\tb\t__syscall_common\n";
+    print OUT "\t  ldo\t__NR_${sname}(%r0),%r20\n";
+    print OUT "\t.procend\n";
+    close(OUT);
+}
+
+1;
diff --git a/usr/klibc/arch/parisc/vfork.S b/usr/klibc/arch/parisc/vfork.S
new file mode 100644
index 0000000..97ebc8f
--- /dev/null
+++ b/usr/klibc/arch/parisc/vfork.S
@@ -0,0 +1,31 @@
+/*
+ * arch/parisc/vfork.S, "vfork() me harder. ugh." -- kyle
+ *
+ * %r20 contains the system call number, %rp contains whence we came,
+ * %rp is saved and restored across the syscall, thankfully.
+ *
+ */
+
+	.text
+	.align 64				; cache-width aligned
+	.globl	vfork
+	.type	vfork,@function
+vfork:
+	/* pid_t vfork(void) */
+	ble		0x100(%sr2, %r0)	; jump to gateway page
+	nop
+
+	ldi		-0x1000,%r19		; %r19 = -4096
+	sub		%r0,%ret0,%r22		; %r22 = -%ret0
+	cmpb,>>=,n	%r19,%ret0,1f		; if %ret0 >= -4096UL
+	ldi		-1,%ret0		; nullified on taken forward
+
+	/* store %r22 to errno... */
+	ldil		L%errno,%r1
+	ldo		R%errno(%r1),%r1
+	stw		%r22,0(%r1)
+1:
+	bv		%r0(%rp)		; jump back
+	nop
+
+	.size vfork,.-vfork
diff --git a/usr/klibc/arch/ppc/Kbuild b/usr/klibc/arch/ppc/Kbuild
new file mode 100644
index 0000000..699380f
--- /dev/null
+++ b/usr/klibc/arch/ppc/Kbuild
@@ -0,0 +1,12 @@
+#
+# klibc files for ppc
+#
+
+klib-y := setjmp.o syscall.o
+
+klib-y += ../../libgcc/__divdi3.o     ../../libgcc/__moddi3.o
+klib-y += ../../libgcc/__udivdi3.o    ../../libgcc/__umoddi3.o
+klib-y += ../../libgcc/__udivmoddi4.o
+
+always  := crt0.o
+targets := crt0.o
diff --git a/usr/klibc/arch/ppc/MCONFIG b/usr/klibc/arch/ppc/MCONFIG
new file mode 100644
index 0000000..e973389
--- /dev/null
+++ b/usr/klibc/arch/ppc/MCONFIG
@@ -0,0 +1,29 @@
+# -*- makefile -*-
+#
+# arch/ppc/MCONFIG
+#
+# Special rules for this architecture.  Note that this is actually
+# included from the main Makefile, and that pathnames should be
+# accordingly.
+#
+
+gcc_m32_option  := $(call cc-option, -m32, )
+
+KLIBCOPTFLAGS	   += -Os
+KLIBCLDFLAGS       = -m elf32ppclinux
+KLIBCARCHREQFLAGS += $(gcc_m32_option)
+
+KLIBCBITSIZE       = 32
+
+# Extra linkflags when building the shared version of the library
+# This address needs to be reachable using normal inter-module
+# calls, and work on the memory models for this architecture
+# 256-16 MB - normal binaries start at 256 MB, and jumps are limited
+# to +/- 16 MB
+KLIBCSHAREDFLAGS     = -Ttext 0x0f800200
+
+# The kernel so far has both asm-ppc* and asm-powerpc.
+KLIBCARCHINCFLAGS = -I$(KLIBCKERNELOBJ)arch/$(KLIBCARCH)/include
+
+# The asm include files live in asm-powerpc
+KLIBCASMARCH	= powerpc
diff --git a/usr/klibc/arch/ppc/crt0.S b/usr/klibc/arch/ppc/crt0.S
new file mode 100644
index 0000000..85b6dca
--- /dev/null
+++ b/usr/klibc/arch/ppc/crt0.S
@@ -0,0 +1,23 @@
+#
+# arch/ppc/crt0.S
+#
+
+	.text
+	.align 4
+	.type _start,@function
+	.globl _start
+_start:
+	stwu	1,-16(1)
+	addi	3,1,16
+	/*
+	 * the SVR4abippc.pdf specifies r7 as a pointer to
+	 * a termination function point
+	 * However, Section 8.4.1 of the LSB API docs say that
+	 * The value to be placed into register r7, the termination
+	 * function pointer, is not passed to the process.
+	 * So we stub it out, instead.
+	 */
+	li	4,0
+	bl	__libc_init
+
+	.size _start,.-_start
diff --git a/usr/klibc/arch/ppc/setjmp.S b/usr/klibc/arch/ppc/setjmp.S
new file mode 100644
index 0000000..e02b7da
--- /dev/null
+++ b/usr/klibc/arch/ppc/setjmp.S
@@ -0,0 +1,34 @@
+#
+# arch/ppc/setjmp.S
+#
+# Basic setjmp/longjmp implementation
+# This file was derived from the equivalent file in NetBSD
+#
+
+	.text
+	.align 4
+	.type setjmp,@function
+	.globl setjmp
+setjmp:
+        mflr    %r11                    /* save return address */
+        mfcr    %r12                    /* save condition register */
+        mr      %r10,%r1                /* save stack pointer */
+        mr      %r9,%r2                 /* save GPR2 (not needed) */
+        stmw    %r9,0(%r3)              /* save r9..r31 */
+        li      %r3,0                   /* indicate success */
+        blr                             /* return */
+
+	.size setjmp,.-setjmp
+
+	.type longjmp,@function
+	.globl longjmp
+longjmp:
+        lmw     %r9,0(%r3)              /* save r9..r31 */
+        mtlr    %r11                    /* restore LR */
+        mtcr    %r12                    /* restore CR */
+        mr      %r2,%r9                 /* restore GPR2 (not needed) */
+        mr      %r1,%r10                /* restore stack */
+        mr      %r3,%r4                 /* get return value */
+        blr                             /* return */
+
+	.size longjmp,.-longjmp
diff --git a/usr/klibc/arch/ppc/syscall.S b/usr/klibc/arch/ppc/syscall.S
new file mode 100644
index 0000000..0a7c37c
--- /dev/null
+++ b/usr/klibc/arch/ppc/syscall.S
@@ -0,0 +1,16 @@
+/*
+ * arch/ppc/syscall.S
+ *
+ * Common error-handling path for system calls.
+ */
+
+	.text
+	.align	2
+	.globl	__syscall_error
+	.type	__syscall_error,@function
+__syscall_error:
+	lis	9,errno@ha
+	stw	3,errno@l(9)
+	li	3,-1
+	blr
+	.size	__syscall_error,.-__syscall_error
diff --git a/usr/klibc/arch/ppc/sysstub.ph b/usr/klibc/arch/ppc/sysstub.ph
new file mode 100644
index 0000000..3b3916c
--- /dev/null
+++ b/usr/klibc/arch/ppc/sysstub.ph
@@ -0,0 +1,25 @@
+# -*- perl -*-
+#
+# arch/ppc/sysstub.ph
+#
+# Script to generate system call stubs
+#
+
+sub make_sysstub($$$$$@) {
+    my($outputdir, $fname, $type, $sname, $stype, @args) = @_;
+
+    open(OUT, '>', "${outputdir}/${fname}.S");
+    print OUT "#include <asm/unistd.h>\n";
+    print OUT "\n";
+    print OUT "\t.type ${fname},\@function\n";
+    print OUT "\t.globl ${fname}\n";
+    print OUT "${fname}:\n";
+    print OUT "\tli 0,__NR_${sname}\n";
+    print OUT "\tsc\n";
+    print OUT "\tbnslr\n";
+    print OUT "\tb __syscall_error\n";
+    print OUT "\t.size ${fname},.-${fname}\n";
+    close(OUT);
+}
+
+1;
diff --git a/usr/klibc/arch/ppc64/Kbuild b/usr/klibc/arch/ppc64/Kbuild
new file mode 100644
index 0000000..a39e91f
--- /dev/null
+++ b/usr/klibc/arch/ppc64/Kbuild
@@ -0,0 +1,8 @@
+#
+# klibc files for ppc64
+#
+
+klib-y := setjmp.o syscall.o
+
+always  := crt0.o
+targets := crt0.o
diff --git a/usr/klibc/arch/ppc64/MCONFIG b/usr/klibc/arch/ppc64/MCONFIG
new file mode 100644
index 0000000..eb2d07a
--- /dev/null
+++ b/usr/klibc/arch/ppc64/MCONFIG
@@ -0,0 +1,26 @@
+# -*- makefile -*-
+#
+# arch/ppc64/MCONFIG
+#
+# Special rules for this architecture.  Note that this is actually
+# included from the main Makefile, and that pathnames should be
+# accordingly.
+#
+
+KLIBCARCHREQFLAGS = -m64 -mcall-aixdesc
+KLIBCOPTFLAGS     += -Os
+KLIBCBITSIZE      = 64
+KLIBCLDFLAGS      = -m elf64ppc
+
+# Extra linkflags when building the shared version of the library
+# This address needs to be reachable using normal inter-module
+# calls, and work on the memory models for this architecture
+# 256-16 MB - normal binaries start at 256 MB, and jumps are limited
+# to +/- 16 MB
+KLIBCSHAREDFLAGS     = -Ttext 0x0f000200
+
+# The kernel so far has both asm-ppc* and asm-powerpc.
+KLIBCARCHINCFLAGS = -I$(KLIBCKERNELOBJ)arch/$(KLIBCARCH)/include
+
+# The asm include files live in asm-powerpc
+KLIBCASMARCH	= powerpc
diff --git a/usr/klibc/arch/ppc64/crt0.S b/usr/klibc/arch/ppc64/crt0.S
new file mode 100644
index 0000000..a7776a1
--- /dev/null
+++ b/usr/klibc/arch/ppc64/crt0.S
@@ -0,0 +1,32 @@
+#
+# arch/ppc64/crt0.S
+#
+# void _start(void)
+# {
+#    /* Divine up argc, argv, and envp */
+#    environ = envp;
+#    exit(main(argc, argv, envp));
+# }
+#
+
+	.section ".toc","aw"
+.LC0:	.tc	environ[TC],environ
+
+	.section ".opd","aw"
+	.align 3
+	.globl _start
+_start:
+	.quad	._start
+	.quad	.TOC.@tocbase, 0
+
+	.text
+	.globl	._start
+	.type	._start,@function
+._start:
+	stdu    %r1,-32(%r1)
+	addi    %r3,%r1,32
+	li	%r4,0		/* fini (unused) */
+	b 	.__libc_init
+	nop
+
+	.size _start,.-_start
diff --git a/usr/klibc/arch/ppc64/setjmp.S b/usr/klibc/arch/ppc64/setjmp.S
new file mode 100644
index 0000000..30db419
--- /dev/null
+++ b/usr/klibc/arch/ppc64/setjmp.S
@@ -0,0 +1,85 @@
+#
+# arch/ppc64/setjmp.S
+#
+# Basic setjmp/longjmp implementation
+#
+
+	.text
+	.align 4
+
+	.section ".opd","aw"
+setjmp:
+	.quad	.setjmp,.TOC.@tocbase,0
+	.previous
+	.size	setjmp,24
+	.type	.setjmp,@function
+	.globl	setjmp
+	.globl	.setjmp
+.setjmp:
+	mflr	%r11			/* save return address */
+	mfcr	%r12			/* save condition register */
+	std	%r2,0(%r3)		/* save TOC pointer (not needed) */
+	stdu	%r1,8(%r3)		/* save stack pointer */
+	stdu	%r11,8(%r3)
+	stdu	%r12,8(%r3)
+	stdu	%r13,8(%r3)		/* save caller saved regs */
+	stdu	%r14,8(%r3)
+	stdu	%r15,8(%r3)
+	stdu	%r16,8(%r3)
+	stdu	%r17,8(%r3)
+	stdu	%r18,8(%r3)
+	stdu	%r19,8(%r3)
+	stdu	%r20,8(%r3)
+	stdu	%r21,8(%r3)
+	stdu	%r22,8(%r3)
+	stdu	%r23,8(%r3)
+	stdu	%r24,8(%r3)
+	stdu	%r25,8(%r3)
+	stdu	%r26,8(%r3)
+	stdu	%r27,8(%r3)
+	stdu	%r28,8(%r3)
+	stdu	%r29,8(%r3)
+	stdu	%r30,8(%r3)
+	std	%r31,8(%r3)
+	li	%r3,0			/* indicate success */
+	blr				/* return */
+
+	.size .setjmp,.-.setjmp
+	.section ".opd","aw"
+longjmp:
+	.quad	.longjmp,.TOC.@tocbase,0
+	.previous
+	.size	longjmp,24
+	.type	.longjmp,@function
+	.globl	longjmp
+	.globl	.longjmp
+.longjmp:
+	ld	%r2,0(%r3)		/* restore TOC pointer (not needed) */
+	ldu	%r1,8(%r3)		/* restore stack */
+	ldu	%r11,8(%r3)
+	ldu	%r12,8(%r3)
+	ldu	%r13,8(%r3)		/* restore caller saved regs */
+	ldu	%r14,8(%r3)
+	ldu	%r15,8(%r3)
+	ldu	%r16,8(%r3)
+	ldu	%r17,8(%r3)
+	ldu	%r18,8(%r3)
+	ldu	%r19,8(%r3)
+	ldu	%r20,8(%r3)
+	ldu	%r21,8(%r3)
+	ldu	%r22,8(%r3)
+	ldu	%r23,8(%r3)
+	ldu	%r24,8(%r3)
+	ldu	%r25,8(%r3)
+	ldu	%r26,8(%r3)
+	ldu	%r27,8(%r3)
+	ldu	%r28,8(%r3)
+	ldu	%r29,8(%r3)
+	ldu	%r30,8(%r3)
+	ld	%r31,8(%r3)
+	mtlr	%r11			/* restore LR */
+	mtcr	%r12			/* restore CR */
+	mr	%r3,%r4			/* get return value */
+	blr				/* return */
+
+	.size .longjmp,.-.longjmp
diff --git a/usr/klibc/arch/ppc64/syscall.c b/usr/klibc/arch/ppc64/syscall.c
new file mode 100644
index 0000000..a5895fe
--- /dev/null
+++ b/usr/klibc/arch/ppc64/syscall.c
@@ -0,0 +1,14 @@
+/*
+ * arch/ppc64/syscall.c
+ *
+ * Common error-handling path for system calls.
+ * The return value from __syscall_error becomes the
+ * return value from the system call.
+ */
+#include <errno.h>
+
+long int __syscall_error(long int err)
+{
+	errno = err;
+	return -1;
+}
diff --git a/usr/klibc/arch/ppc64/sysstub.ph b/usr/klibc/arch/ppc64/sysstub.ph
new file mode 100644
index 0000000..9ee9370
--- /dev/null
+++ b/usr/klibc/arch/ppc64/sysstub.ph
@@ -0,0 +1,31 @@
+# -*- perl -*-
+#
+# arch/ppc64/sysstub.ph
+#
+# Script to generate system call stubs
+#
+
+sub make_sysstub($$$$$@) {
+    my($outputdir, $fname, $type, $sname, $stype, @args) = @_;
+
+    open(OUT, '>', "${outputdir}/${fname}.S");
+    print OUT "#include <asm/unistd.h>\n";
+    print OUT "\n";
+    print OUT "\t.globl ${fname}\n";
+    print OUT "\t.section \".opd\",\"aw\"\n";
+    print OUT "\t.align 3\n";
+    print OUT "${fname}:\n";
+    print OUT "\t.quad .${fname},.TOC.\@tocbase,0\n";
+    print OUT "\t.text\n";
+    print OUT "\t.type .${fname},\@function\n";
+    print OUT "\t.globl .${fname}\n";
+    print OUT ".${fname}:\n";
+    print OUT "\tli 0,__NR_${sname}\n";
+    print OUT "\tsc\n";
+    print OUT "\tbnslr\n";
+    print OUT "\tb .__syscall_error\n";
+    print OUT "\t.size .${fname},.-.${fname}\n";
+    close(OUT);
+}
+
+1;
diff --git a/usr/klibc/arch/s390/Kbuild b/usr/klibc/arch/s390/Kbuild
new file mode 100644
index 0000000..6a8e97a
--- /dev/null
+++ b/usr/klibc/arch/s390/Kbuild
@@ -0,0 +1,22 @@
+#
+# klibc files for s390
+#
+
+always  := crt0.o
+targets := crt0.o
+
+ifneq ("$(KLIBCARCH)", "s390x")
+
+klib-y := setjmp.o mmap.o syscall.o
+
+klib-y += ../../libgcc/__clzsi2.o   ../../libgcc/__ashldi3.o
+klib-y += ../../libgcc/__ashrdi3.o  ../../libgcc/__lshrdi3.o
+klib-y += ../../libgcc/__divdi3.o   ../../libgcc/__moddi3.o
+klib-y += ../../libgcc/__udivdi3.o  ../../libgcc/__umoddi3.o
+klib-y += ../../libgcc/__udivmoddi4.o
+
+else
+
+klib-y := setjmp.o mmap.o syscall.o
+
+endif
diff --git a/usr/klibc/arch/s390/MCONFIG b/usr/klibc/arch/s390/MCONFIG
new file mode 100644
index 0000000..82d9a74
--- /dev/null
+++ b/usr/klibc/arch/s390/MCONFIG
@@ -0,0 +1,23 @@
+# -*- makefile -*-
+#
+# arch/s390/MCONFIG
+#
+# Special rules for this architecture. Note that this is actually
+# included from the main Makefile, and that pathnames should be
+# accordingly.
+#
+
+KLIBCOPTFLAGS += -Os
+
+ifneq ("$(KLIBCARCH)", "s390x")
+	KLIBCBITSIZE	= 32
+	KLIBCCFLAGS	+= -m31
+	KLIBCLDFLAGS	+= -m elf_s390
+else
+	KLIBCBITSIZE	= 64
+	KLIBCCFLAGS	+= -m64
+	KLIBCLDFLAGS	+= -m elf64_s390
+endif
+
+KLIBCASMARCH		= s390
+KLIBCSHAREDFLAGS	= -Ttext 0x40000200
diff --git a/usr/klibc/arch/s390/crt0.S b/usr/klibc/arch/s390/crt0.S
new file mode 100644
index 0000000..fd9237e
--- /dev/null
+++ b/usr/klibc/arch/s390/crt0.S
@@ -0,0 +1,35 @@
+#
+# arch/s390/crt0.S
+#
+# Does arch-specific initialization and invokes __libc_init
+# with the appropriate arguments.
+#
+# See __static_init.c or __shared_init.c for the expected
+# arguments.
+#
+	.text
+	.align 4
+	.type _start,@function
+	.globl _start
+
+#ifndef __s390x__
+
+_start:
+	lr	%r2,%r15
+	lhi	%r3,0
+	ahi	%r15,-96
+	bras	%r1,.L0
+.L0:
+	l	%r1,.L1-.L0(%r1)
+	br	%r1
+.L1:
+	.long	__libc_init
+#else
+
+_start:
+	lgr	%r2,%r15
+	lghi	%r3,0
+	aghi	%r15,-160
+	jg	__libc_init
+#endif
+	.size _start,.-_start
diff --git a/usr/klibc/arch/s390/mmap.c b/usr/klibc/arch/s390/mmap.c
new file mode 100644
index 0000000..3331239
--- /dev/null
+++ b/usr/klibc/arch/s390/mmap.c
@@ -0,0 +1,74 @@
+#include <errno.h>
+#include <sys/types.h>
+#include <linux/unistd.h>
+
+struct mmap_arg_struct {
+	unsigned long addr;
+	unsigned long len;
+	unsigned long prot;
+	unsigned long flags;
+	unsigned long fd;
+	unsigned long offset;
+};
+
+#ifndef __s390x__
+
+void *__mmap2(void *addr, size_t len, int prot, int flags, int fd, long offset)
+{
+	struct mmap_arg_struct args = {
+		.addr	= (unsigned long)addr,
+		.len	= (unsigned long)len,
+		.prot	= (unsigned long)prot,
+		.flags	= (unsigned long)flags,
+		.fd	= (unsigned long)fd,
+		.offset = (unsigned long)offset,
+	};
+
+	register struct mmap_arg_struct *__arg1 asm("2") = &args;
+	register long __svcres asm("2");
+	unsigned long __res;
+
+	__asm__ __volatile__("    svc %b1\n"
+			     : "=d"(__svcres)
+			     : "i"(__NR_mmap2), "0"(__arg1)
+			     : "1", "cc", "memory");
+	__res = __svcres;
+	if (__res >= (unsigned long)-4095) {
+		errno = -__res;
+		__res = -1;
+	}
+	return (void *)__res;
+}
+
+#else /* __s390x__ */
+
+void *mmap(void *addr, size_t len, int prot, int flags, int fd, off_t offset)
+{
+	struct mmap_arg_struct args = {
+		.addr	= (unsigned long)addr,
+		.len	= (unsigned long)len,
+		.prot	= (unsigned long)prot,
+		.flags	= (unsigned long)flags,
+		.fd	= (unsigned long)fd,
+		.offset = (unsigned long)offset,
+	};
+
+	register struct mmap_arg_struct *__arg1 asm("2") = &args;
+	register long __svcres asm("2");
+	unsigned long __res;
+
+	__asm__ __volatile__ (
+		"    svc %b1\n"
+		: "=d" (__svcres)
+		: "i" (__NR_mmap),
+		  "0" (__arg1)
+		: "1", "cc", "memory");
+	__res = __svcres;
+	if (__res >= (unsigned long)-4095) {
+		errno = -__res;
+		__res = -1;
+	}
+	return (void *)__res;
+}
+
+#endif /* __s390x__ */
diff --git a/usr/klibc/arch/s390/setjmp.S b/usr/klibc/arch/s390/setjmp.S
new file mode 100644
index 0000000..c36a051
--- /dev/null
+++ b/usr/klibc/arch/s390/setjmp.S
@@ -0,0 +1,66 @@
+#
+# arch/s390/setjmp.S
+#
+# setjmp/longjmp for the s390 architecture
+#
+
+	.text
+	.align 4
+	.globl setjmp
+	.type setjmp, @function
+
+#ifndef __s390x__
+
+setjmp:
+	stm	%r6,%r15,0(%r2)		# save all general registers
+	std	%f4,40(%r2)		# save fp registers f4 and f6
+	std	%f6,48(%r2)
+	lhi	%r2,0			# return 0
+	br	%r14
+
+	.size setjmp,.-setjmp
+
+	.text
+	.align 4
+	.globl longjmp
+	.type longjmp, @function
+longjmp:
+	lr	%r1,%r2			# jmp_buf
+	lr	%r2,%r3			# return value
+	ld	%f6,48(%r1)		# restore all saved registers
+	ld	%f4,40(%r1)
+	lm	%r6,%r15,0(%r1)
+	br	%r14			# return to restored address
+
+	.size longjmp,.-longjmp
+
+#else
+
+setjmp:
+	stmg	%r6,%r15,0(%r2)		# save all general registers
+	std	%f1,80(%r2)		# save fp registers f4 and f6
+	std	%f3,88(%r2)
+	std	%f5,96(%r2)
+	std	%f7,104(%r2)
+	lghi	%r2,0			# return 0
+	br	%r14
+
+	.size setjmp,.-setjmp
+
+	.text
+	.align 4
+	.globl longjmp
+	.type longjmp, @function
+longjmp:
+	lgr	%r1,%r2			# jmp_buf
+	lgr	%r2,%r3			# return value
+	ld	%f7,104(%r1)		# restore all saved registers
+	ld	%f5,96(%r1)
+	ld	%f3,88(%r1)
+	ld	%f1,80(%r1)
+	lmg	%r6,%r15,0(%r1)
+	br	%r14			# return to restored address
+
+	.size longjmp,.-longjmp
+
+#endif
diff --git a/usr/klibc/arch/s390/syscall.c b/usr/klibc/arch/s390/syscall.c
new file mode 100644
index 0000000..e1d201d
--- /dev/null
+++ b/usr/klibc/arch/s390/syscall.c
@@ -0,0 +1,16 @@
+/*
+ * arch/s390/syscall.c
+ *
+ * Common error-handling path for system calls.
+ * The return value from __syscall_common becomes the
+ * return value from the system call.
+ */
+#include <errno.h>
+
+unsigned long __syscall_common(unsigned long err)
+{
+	if (err < -4095UL)
+		return err;
+	errno = -err;
+	return -1;
+}
diff --git a/usr/klibc/arch/s390/sysstub.ph b/usr/klibc/arch/s390/sysstub.ph
new file mode 100644
index 0000000..1ca7b6b
--- /dev/null
+++ b/usr/klibc/arch/s390/sysstub.ph
@@ -0,0 +1,63 @@
+# -*- perl -*-
+#
+# arch/s390/sysstub.ph
+#
+# Script to generate system call stubs
+#
+
+sub make_sysstub($$$$$@) {
+    my($outputdir, $fname, $type, $sname, $stype, @args) = @_;
+    my($t);
+    my($r, $llregs) = (0, ($typesize{'void *'} == 8) ? 1 : 2);
+
+    foreach $t (@args) {
+	    $r += ($typesize{$t} == 8) ? $llregs : 1;
+    }
+
+    open(OUT, '>', "${outputdir}/${fname}.S");
+    print OUT <<EOF;
+#include <asm/unistd.h>
+
+	.type ${fname},\@function
+	.globl ${fname}
+${fname}:
+.if ${r} > 6
+.print "System call with more than six parameters not supported yet."
+.err
+.endif
+.if ${r} == 6
+#ifndef __s390x__
+	st	%r7,56(%r15)
+	l	%r7,96(%r15)
+#else
+	stg	%r7,80(%r15)
+	lg	%r7,160(%r15)
+#endif
+.endif
+.if __NR_${sname} < 256
+	svc	__NR_${sname}
+.else
+	la	%r1,__NR_${sname}
+	svc	0
+.endif
+.if ${r} == 6
+#ifndef __s390x__
+	l	%r7,56(%r15)
+#else
+	lg	%r7,160(%r15)
+#endif
+.endif
+#ifndef __s390x__
+	bras	%r3,1f
+	.long	__syscall_common
+1:	l	%r3,0(%r3)
+	br	%r3
+#else
+	brasl	%r3,__syscall_common
+#endif
+	.size	${fname},.-${fname}
+EOF
+    close(OUT);
+}
+
+1;
diff --git a/usr/klibc/arch/sh/Kbuild b/usr/klibc/arch/sh/Kbuild
new file mode 100644
index 0000000..ab7ad5a
--- /dev/null
+++ b/usr/klibc/arch/sh/Kbuild
@@ -0,0 +1,8 @@
+#
+# klibc files for sh
+#
+
+klib-y := setjmp.o syscall.o
+
+always  := crt0.o
+targets := crt0.o
diff --git a/usr/klibc/arch/sh/MCONFIG b/usr/klibc/arch/sh/MCONFIG
new file mode 100644
index 0000000..ba90850
--- /dev/null
+++ b/usr/klibc/arch/sh/MCONFIG
@@ -0,0 +1,18 @@
+# -*- makefile -*-
+#
+# arch/sh/MCONFIG
+#
+# Special rules for this architecture.  Note that this is actually
+# included from the main Makefile, and that pathnames should be
+# accordingly.
+#
+
+ARCHREGFLAGS = -m4 -mno-implicit-fp
+KLIBCOPTFLAGS     += -Os -fomit-frame-pointer
+KLIBCBITSIZE      = 32
+
+# Extra linkflags when building the shared version of the library
+# This address needs to be reachable using normal inter-module
+# calls, and work on the memory models for this architecture
+# 2 MB -- the normal starting point for text is 4 MB.
+KLIBCSHAREDFLAGS	= -Ttext 0x00200200
diff --git a/usr/klibc/arch/sh/crt0.S b/usr/klibc/arch/sh/crt0.S
new file mode 100644
index 0000000..7f0a649
--- /dev/null
+++ b/usr/klibc/arch/sh/crt0.S
@@ -0,0 +1,27 @@
+#
+# arch/sh/crt0.S
+#
+# Does arch-specific initialization and invokes __libc_init
+# with the appropriate arguments.
+#
+# See __static_init.c or __shared_init.c for the expected
+# arguments.
+#
+
+	.text
+	.align 2
+	.type _start,#function
+	.globl _start
+
+_start:
+	mov	r15, r4
+	mov	#0, r5
+	mov.l	1f, r0
+
+	jsr	@r0
+	 nop
+
+	.align 2
+1:	.long	__libc_init
+
+	.size _start,.-_start
diff --git a/usr/klibc/arch/sh/setjmp.S b/usr/klibc/arch/sh/setjmp.S
new file mode 100644
index 0000000..2552358
--- /dev/null
+++ b/usr/klibc/arch/sh/setjmp.S
@@ -0,0 +1,64 @@
+#
+# arch/sh/setjmp.S
+#
+# setjmp/longjmp for the SuperH architecture
+#
+
+#
+# The jmp_buf is assumed to contain the following, in order:
+#
+#		r8
+#		r9
+#		r10
+#		r11
+#		r12
+#		r13
+#		r14
+#		r15
+#		pr
+#
+
+	.text
+	.align 2
+
+	.globl setjmp
+	.type setjmp, #function
+
+setjmp:
+	add	#(9*4), r4
+	sts.l	pr, @-r4
+	mov.l	r15, @-r4
+	mov.l	r14, @-r4
+	mov.l	r13, @-r4
+	mov.l	r12, @-r4
+	mov.l	r11, @-r4
+	mov.l	r10, @-r4
+	mov.l	r9, @-r4
+	mov.l	r8, @-r4
+	rts
+	 mov	#0, r0
+
+	.size setjmp,.-setjmp
+
+	.align 2
+	.globl longjmp
+	.type setjmp, #function
+
+longjmp:
+	mov.l	@r4+, r8
+	mov.l	@r4+, r9
+	mov.l	@r4+, r10
+	mov.l	@r4+, r11
+	mov.l	@r4+, r12
+	mov.l	@r4+, r13
+	mov.l	@r4+, r14
+	mov.l	@r4+, r15
+	lds.l	@r4+, pr
+	mov	r5, r0
+	tst	r0, r0
+	bf	1f
+	mov	#1, r0	! in case val==0
+1:	rts
+	 nop
+
+	.size longjmp,.-longjmp
diff --git a/usr/klibc/arch/sh/syscall.S b/usr/klibc/arch/sh/syscall.S
new file mode 100644
index 0000000..f5f85cc
--- /dev/null
+++ b/usr/klibc/arch/sh/syscall.S
@@ -0,0 +1,35 @@
+/*
+ * arch/sh/syscall.S
+ *
+ * On sh, r3 contains the syscall number (set by generated stub);
+ * r4..r7 contain arguments 0-3 per the standard calling convention,
+ * and arguments 4-5 are passed in r0 and r1.
+ *
+ * The return value is in r3 rather than standard r0.
+ */
+
+	.section ".text.syscall","ax"
+	.align	2
+	.globl	__syscall_common
+	.type	__syscall_common,@function
+__syscall_common:
+	mov.l	@(0,sp),r0
+	mov.l	@(4,sp),r1
+	trapa	#0x15
+	mov.l	1f,r0
+	cmp/hs	r0,r3
+	bt/s	3f
+	  neg	r3,r4
+	mov.l	2f,r5
+	mov.l	r4,@r5
+	rts
+	  mov	#-1,r0
+3:
+	rts
+	  mov	r3,r0
+
+	.align 2
+1:	.long	-4096		/* Errno limit */
+2:	.long	errno
+
+	.size	__syscall_common,.-__syscall_common
diff --git a/usr/klibc/arch/sh/sysstub.ph b/usr/klibc/arch/sh/sysstub.ph
new file mode 100644
index 0000000..0ff46dd
--- /dev/null
+++ b/usr/klibc/arch/sh/sysstub.ph
@@ -0,0 +1,38 @@
+# -*- perl -*-
+#
+# arch/sh/sysstub.ph
+#
+# Script to generate system call stubs
+#
+
+sub make_sysstub($$$$$@) {
+    my($outputdir, $fname, $type, $sname, $stype, @args) = @_;
+
+    open(OUT, '>', "${outputdir}/${fname}.S");
+    print OUT "#include <asm/unistd.h>\n";
+    print OUT "\n";
+    print OUT "\t.section\t\".text.syscall\",\"ax\"\n";
+    print OUT "\t.type\t${fname},\#function\n";
+    print OUT "\t.globl\t${fname}\n";
+    print OUT "\t.align\t2\n";
+    print OUT "\t.import __syscall_common\n";
+    print OUT "${fname}:\n";
+    print OUT "\t  mov.l\t1f, r3\n";
+    print OUT "\t  jmp\t\@r3\n";
+    print OUT "#if __NR_${sname} >= 128\n";
+    print OUT "\t  mov.l\t2f, r3\n";
+    print OUT "#else\n";
+    print OUT "\t  mov\t# __NR_${sname}, r3\n";
+    print OUT "#endif\n";
+    print OUT "\t.size ${fname},.-${fname}\n";
+    print OUT "\n";
+    print OUT "\t.align\t2\n";
+    print OUT "\t.import\t__syscall_common\n";
+    print OUT "1:\t.long\t__syscall_common\n";
+    print OUT "#if __NR_${sname} >= 128\n";
+    print OUT "2:\t.long\t__NR_${sname}\n";
+    print OUT "#endif\n";
+    close(OUT);
+}
+
+1;
diff --git a/usr/klibc/arch/sparc/Kbuild b/usr/klibc/arch/sparc/Kbuild
new file mode 100644
index 0000000..d013f5d
--- /dev/null
+++ b/usr/klibc/arch/sparc/Kbuild
@@ -0,0 +1,34 @@
+#
+# klibc files for sparc
+#
+
+always  := crt0.o
+targets := crt0.o
+
+m4-targets := sdiv.o srem.o udiv.o urem.o
+
+klib-y := $(m4-targets) smul.o umul.o __muldi3.o
+klib-y += setjmp.o pipe.o syscall.o sysfork.o
+
+klib-y += ../../libgcc/__ashldi3.o ../../libgcc/__ashrdi3.o
+klib-y += ../../libgcc/__lshrdi3.o ../../libgcc/__divdi3.o
+klib-y += ../../libgcc/__moddi3.o  ../../libgcc/__udivdi3.o
+klib-y += ../../libgcc/__umoddi3.o ../../libgcc/__udivmoddi4.o
+klib-y += ../../libgcc/__clzsi2.o
+
+
+$(obj)/sdiv.S: m4 := define(NAME,\`.div')define(OP,\`div')define(S,\`true')
+$(obj)/srem.S: m4 := define(NAME,\`.rem')define(OP,\`rem')define(S,\`true')
+$(obj)/udiv.S: m4 := define(NAME,\`.udiv')define(OP,\`div')define(S,\`false')
+$(obj)/urem.S: m4 := define(NAME,\`.urem')define(OP,\`rem')define(S,\`false')
+
+targets += $(m4-targets) $(m4-targets:.o=.S)
+
+quiet_cmd_m4 = M4      $@
+      cmd_m4 = (echo "$(m4)"; cat $^) | m4 > $@
+
+# build .o from .S
+$(addprefix $(obj)/,$(m4-targets)): $(obj)/%.o : $(obj)/%.S
+# build .S from .m4
+$(addprefix $(obj)/,$(m4-targets:.o=.S)): $(src)/divrem.m4
+	$(call if_changed,m4)
diff --git a/usr/klibc/arch/sparc/MCONFIG b/usr/klibc/arch/sparc/MCONFIG
new file mode 100644
index 0000000..235ce60
--- /dev/null
+++ b/usr/klibc/arch/sparc/MCONFIG
@@ -0,0 +1,19 @@
+# -*- makefile -*-
+#
+# arch/sparc/MCONFIG
+#
+# Special rules for this architecture.  Note that this is actually
+# included from the main Makefile, and that pathnames should be
+# accordingly.
+#
+
+KLIBCOPTFLAGS		 += -Os -m32 -mptr32
+KLIBCBITSIZE		 = 32
+KLIBCARCHREQFLAGS	+= -D__sparc32__
+
+# Extra linkflags when building the shared version of the library
+# This address needs to be reachable using normal inter-module
+# calls, and work on the memory models for this architecture
+# Normal binaries start at 64K; the linker wants 64K alignment,
+# and call instructions have a 30-bit signed offset, << 2.
+KLIBCSHAREDFLAGS	 = -Ttext 0x40000100
diff --git a/usr/klibc/arch/sparc/__muldi3.S b/usr/klibc/arch/sparc/__muldi3.S
new file mode 100644
index 0000000..e53848a
--- /dev/null
+++ b/usr/klibc/arch/sparc/__muldi3.S
@@ -0,0 +1,27 @@
+	.global .umul
+	.section	".text"
+	.align 4
+	.global __muldi3
+	.type	__muldi3, #function
+	.proc	017
+__muldi3:
+	save	%sp, -104, %sp
+	mov	%i1, %o0
+	call	.umul, 0
+	 mov	%i3, %o1
+	mov	%o0, %l2
+	mov	%o1, %l3
+	mov	%i1, %o0
+	call	.umul, 0
+	 mov	%i2, %o1
+	mov	%i0, %o1
+	mov	%o0, %l0
+	call	.umul, 0
+	 mov	%i3, %o0
+	mov	0, %l1
+	add	%l0, %o0, %l0
+	addcc	%l3, %l1, %i1
+	addx	%l2, %l0, %i0
+	jmp	%i7+8
+	 restore
+	.size	__muldi3, .-__muldi3
diff --git a/usr/klibc/arch/sparc/crt0.S b/usr/klibc/arch/sparc/crt0.S
new file mode 100644
index 0000000..63db188
--- /dev/null
+++ b/usr/klibc/arch/sparc/crt0.S
@@ -0,0 +1,2 @@
+#define TARGET_PTR_SIZE	32
+#include "crt0i.S"
diff --git a/usr/klibc/arch/sparc/crt0i.S b/usr/klibc/arch/sparc/crt0i.S
new file mode 100644
index 0000000..0220b01
--- /dev/null
+++ b/usr/klibc/arch/sparc/crt0i.S
@@ -0,0 +1,100 @@
+! This file derived from the equivalent in newlib
+!
+! C run time start off
+
+! This file supports:
+!
+! - both 32bit pointer and 64bit pointer environments (at compile time)
+! - an imposed stack bias (of 2047) (at run time)
+! - medium/low and medium/anywhere code models (at run time)
+
+! Initial stack setup:
+!
+!    bottom of stack (higher memory address)
+! 	...
+!	text of environment strings
+!	text of argument strings
+!	envp[envc] = 0 (4/8 bytes)
+!	...
+!	env[0] (4/8 bytes)
+!	argv[argc] = 0 (4/8 bytes)
+!	...
+!	argv[0] (4/8 bytes)
+!	argc (4/8 bytes)
+!	register save area (64 bits by 16 registers = 128 bytes)
+!	top of stack (%sp)
+
+! Stack Bias:
+!
+! It is the responsibility of the o/s to set this up.
+! We handle both a 0 and 2047 value for the stack bias.
+
+! Medium/Anywhere code model support:
+!
+! In this model %g4 points to the start of the data segment.
+! The text segment can go anywhere, but %g4 points to the *data* segment.
+! It is up to the compiler/linker to get this right.
+!
+! Since this model is statically linked the start of the data segment
+! is known at link time.  Eg:
+!
+!	sethi	%hh(data_start), %g1
+!	sethi	%lm(data_start), %g4
+!	or	%g1, %hm(data_start), %g1
+!	or	%g4, %lo(data_start), %g4
+!	sllx	%g1, 32, %g1
+!	or	%g4, %g1, %g4
+!
+! FIXME: For now we just assume 0.
+
+! FIXME: if %g1 contains a non-zero value, atexit() should be invoked
+! with this value.
+
+
+	.text
+	.align 4
+	.globl _start
+	.type _start, @function
+_start:
+	clr	%fp
+
+! We use %g4 even if the code model is Medium/Low (simplifies the code).
+
+	clr	%g4			! Medium/Anywhere base reg
+
+! If there is a stack bias in effect, account for it in %g5.  Then always
+! add %g5 to stack references below.  This way the code can be used with
+! or without an imposed bias.
+
+	andcc	%sp, 1, %g5
+	bz,a .LNoBias
+	 nop
+	mov	2047, %g5
+.LNoBias:
+	add	%sp, %g5, %g5
+
+! On entry, the kernel leaves room for one register frame, but
+! the C API wants more free space.  Thus, we need to drop the stack
+! pointer additionally.
+
+#if TARGET_PTR_SIZE == 32
+	sub	%sp, 32, %sp		! make room for incoming arguments
+#else /* TARGET_PTR_SIZE == 64 */
+	sub	%sp, 64, %sp		! make room for incoming arguments
+#endif
+
+! Set up pointers to the ELF data structure (argc, argv, ...)
+! Pass as the first argument to __libc_init
+#if TARGET_PTR_SIZE == 32
+	add	%g5, 0x40, %o0
+#else /* TARGET_PTR_SIZE == 64 */
+	add	%g5, 0x80, %o0
+#endif
+
+	call	__libc_init
+	 mov	%g1, %o1	! This is the "atexit" pointer;
+				! pass as the second argument to __libc_init
+
+! If __libc_init returns, something is hosed.  Try an illegal insn.
+! If that does not work, the o/s is hosed more than we are.
+	.long 0
diff --git a/usr/klibc/arch/sparc/divrem.m4 b/usr/klibc/arch/sparc/divrem.m4
new file mode 100644
index 0000000..aa4171d
--- /dev/null
+++ b/usr/klibc/arch/sparc/divrem.m4
@@ -0,0 +1,276 @@
+/*
+ * 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.
+ *
+ * from: Header: divrem.m4,v 1.4 92/06/25 13:23:57 torek Exp
+ * $NetBSD: divrem.m4,v 1.4 1997/10/09 10:07:54 lukem Exp $
+ */
+
+/*
+ * Division and remainder, from Appendix E of the Sparc Version 8
+ * Architecture Manual, with fixes from Gordon Irlam.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+	.asciz "@(#)divrem.m4	8.1 (Berkeley) 6/4/93"
+#endif /* LIBC_SCCS and not lint */
+
+/*
+ * Input: dividend and divisor in %o0 and %o1 respectively.
+ *
+ * m4 parameters:
+ *  NAME	name of function to generate
+ *  OP		OP=div => %o0 / %o1; OP=rem => %o0 % %o1
+ *  S		S=true => signed; S=false => unsigned
+ *
+ * Algorithm parameters:
+ *  N		how many bits per iteration we try to get (4)
+ *  WORDSIZE	total number of bits (32)
+ *
+ * Derived constants:
+ *  TWOSUPN	2^N, for label generation (m4 exponentiation currently broken)
+ *  TOPBITS	number of bits in the top `decade' of a number
+ *
+ * Important variables:
+ *  Q		the partial quotient under development (initially 0)
+ *  R		the remainder so far, initially the dividend
+ *  ITER	number of main division loop iterations required;
+ *		equal to ceil(log2(quotient) / N).  Note that this
+ *		is the log base (2^N) of the quotient.
+ *  V		the current comparand, initially divisor*2^(ITER*N-1)
+ *
+ * Cost:
+ *  Current estimate for non-large dividend is
+ *	ceil(log2(quotient) / N) * (10 + 7N/2) + C
+ *  A large dividend is one greater than 2^(31-TOPBITS) and takes a
+ *  different path, as the upper bits of the quotient must be developed
+ *  one bit at a time.
+ */
+
+define(N, `4')
+define(TWOSUPN, `16')
+define(WORDSIZE, `32')
+define(TOPBITS, eval(WORDSIZE - N*((WORDSIZE-1)/N)))
+
+define(dividend, `%o0')
+define(divisor, `%o1')
+define(Q, `%o2')
+define(R, `%o3')
+define(ITER, `%o4')
+define(V, `%o5')
+
+/* m4 reminder: ifelse(a,b,c,d) => if a is b, then c, else d */
+define(T, `%g1')
+define(SC, `%g7')
+ifelse(S, `true', `define(SIGN, `%g6')')
+
+/*
+ * This is the recursive definition for developing quotient digits.
+ *
+ * Parameters:
+ *  $1	the current depth, 1 <= $1 <= N
+ *  $2	the current accumulation of quotient bits
+ *  N	max depth
+ *
+ * We add a new bit to $2 and either recurse or insert the bits in
+ * the quotient.  R, Q, and V are inputs and outputs as defined above;
+ * the condition codes are expected to reflect the input R, and are
+ * modified to reflect the output R.
+ */
+define(DEVELOP_QUOTIENT_BITS,
+`	! depth $1, accumulated bits $2
+	bl	L.$1.eval(TWOSUPN+$2)
+	srl	V,1,V
+	! remainder is positive
+	subcc	R,V,R
+	ifelse($1, N,
+	`	b	9f
+		add	Q, ($2*2+1), Q
+	', `	DEVELOP_QUOTIENT_BITS(incr($1), `eval(2*$2+1)')')
+L.$1.eval(TWOSUPN+$2):
+	! remainder is negative
+	addcc	R,V,R
+	ifelse($1, N,
+	`	b	9f
+		add	Q, ($2*2-1), Q
+	', `	DEVELOP_QUOTIENT_BITS(incr($1), `eval(2*$2-1)')')
+	ifelse($1, 1, `9:')')
+
+#include <machine/asm.h>
+#include <machine/trap.h>
+
+FUNC(NAME)
+ifelse(S, `true',
+`	! compute sign of result; if neither is negative, no problem
+	orcc	divisor, dividend, %g0	! either negative?
+	bge	2f			! no, go do the divide
+	ifelse(OP, `div',
+		`xor	divisor, dividend, SIGN',
+		`mov	dividend, SIGN')	! compute sign in any case
+	tst	divisor
+	bge	1f
+	tst	dividend
+	! divisor is definitely negative; dividend might also be negative
+	bge	2f			! if dividend not negative...
+	neg	divisor			! in any case, make divisor nonneg
+1:	! dividend is negative, divisor is nonnegative
+	neg	dividend		! make dividend nonnegative
+2:
+')
+	! Ready to divide.  Compute size of quotient; scale comparand.
+	orcc	divisor, %g0, V
+	bnz	1f
+	mov	dividend, R
+
+		! Divide by zero trap.  If it returns, return 0 (about as
+		! wrong as possible, but that is what SunOS does...).
+		t	ST_DIV0
+		retl
+		clr	%o0
+
+1:
+	cmp	R, V			! if divisor exceeds dividend, done
+	blu	Lgot_result		! (and algorithm fails otherwise)
+	clr	Q
+	sethi	%hi(1 << (WORDSIZE - TOPBITS - 1)), T
+	cmp	R, T
+	blu	Lnot_really_big
+	clr	ITER
+
+	! `Here the dividend is >= 2^(31-N) or so.  We must be careful here,
+	! as our usual N-at-a-shot divide step will cause overflow and havoc.
+	! The number of bits in the result here is N*ITER+SC, where SC <= N.
+	! Compute ITER in an unorthodox manner: know we need to shift V into
+	! the top decade: so do not even bother to compare to R.'
+	1:
+		cmp	V, T
+		bgeu	3f
+		mov	1, SC
+		sll	V, N, V
+		b	1b
+		inc	ITER
+
+	! Now compute SC.
+	2:	addcc	V, V, V
+		bcc	Lnot_too_big
+		inc	SC
+
+		! We get here if the divisor overflowed while shifting.
+		! This means that R has the high-order bit set.
+		! Restore V and subtract from R.
+		sll	T, TOPBITS, T	! high order bit
+		srl	V, 1, V		! rest of V
+		add	V, T, V
+		b	Ldo_single_div
+		dec	SC
+
+	Lnot_too_big:
+	3:	cmp	V, R
+		blu	2b
+		nop
+		be	Ldo_single_div
+		nop
+	/* NB: these are commented out in the V8-Sparc manual as well */
+	/* (I do not understand this) */
+	! V > R: went too far: back up 1 step
+	!	srl	V, 1, V
+	!	dec	SC
+	! do single-bit divide steps
+	!
+	! We have to be careful here.  We know that R >= V, so we can do the
+	! first divide step without thinking.  BUT, the others are conditional,
+	! and are only done if R >= 0.  Because both R and V may have the high-
+	! order bit set in the first step, just falling into the regular
+	! division loop will mess up the first time around.
+	! So we unroll slightly...
+	Ldo_single_div:
+		deccc	SC
+		bl	Lend_regular_divide
+		nop
+		sub	R, V, R
+		mov	1, Q
+		b	Lend_single_divloop
+		nop
+	Lsingle_divloop:
+		sll	Q, 1, Q
+		bl	1f
+		srl	V, 1, V
+		! R >= 0
+		sub	R, V, R
+		b	2f
+		inc	Q
+	1:	! R < 0
+		add	R, V, R
+		dec	Q
+	2:
+	Lend_single_divloop:
+		deccc	SC
+		bge	Lsingle_divloop
+		tst	R
+		b,a	Lend_regular_divide
+
+Lnot_really_big:
+1:
+	sll	V, N, V
+	cmp	V, R
+	bleu	1b
+	inccc	ITER
+	be	Lgot_result
+	dec	ITER
+
+	tst	R	! set up for initial iteration
+Ldivloop:
+	sll	Q, N, Q
+	DEVELOP_QUOTIENT_BITS(1, 0)
+Lend_regular_divide:
+	deccc	ITER
+	bge	Ldivloop
+	tst	R
+	bl,a	Lgot_result
+	! non-restoring fixup here (one instruction only!)
+ifelse(OP, `div',
+`	dec	Q
+', `	add	R, divisor, R
+')
+
+Lgot_result:
+ifelse(S, `true',
+`	! check to see if answer should be < 0
+	tst	SIGN
+	bl,a	1f
+	ifelse(OP, `div', `neg Q', `neg R')
+1:')
+	retl
+	ifelse(OP, `div', `mov Q, %o0', `mov R, %o0')
diff --git a/usr/klibc/arch/sparc/pipe.S b/usr/klibc/arch/sparc/pipe.S
new file mode 100644
index 0000000..a8abf3c
--- /dev/null
+++ b/usr/klibc/arch/sparc/pipe.S
@@ -0,0 +1,30 @@
+/*
+ * arch/sparc/pipe.S
+ *
+ * The pipe system call are special on sparc[64]:
+ * they return the two file descriptors in %o0 and %o1.
+ */
+
+#include <asm/unistd.h>
+
+	.globl	pipe
+	.type	pipe,#function
+       	.align	4
+pipe:
+	mov	__NR_pipe, %g1
+	or	%o0, 0, %g4
+	t	0x10
+	bcc	1f
+	  nop
+	sethi	%hi(errno), %g4
+	or	%g4, %lo(errno), %g4
+	st	%o0,[%g4]
+	retl
+	  mov	-1, %o0
+1:
+	st	%o0,[%g4]
+	st	%o1,[%g4+4]
+	retl
+	  mov	0, %o0
+
+	.size pipe,.-pipe
diff --git a/usr/klibc/arch/sparc/setjmp.S b/usr/klibc/arch/sparc/setjmp.S
new file mode 100644
index 0000000..038ea78
--- /dev/null
+++ b/usr/klibc/arch/sparc/setjmp.S
@@ -0,0 +1,38 @@
+!
+! setjmp.S
+!
+! Basic setjmp/longjmp
+!
+! This code was based on the equivalent code in NetBSD
+!
+
+#include <machine/asm.h>
+#include <machine/trap.h>
+
+!
+! The jmp_buf contains the following entries:
+!   sp
+!   fp
+!   pc
+!
+ENTRY(setjmp)
+	st	%sp,[%o0+0]	! Callers stack pointer
+	st	%o7,[%o0+4]	! Return pc
+	st	%fp,[%o0+8]	! Frame pointer
+	retl			! Return
+	 clr	%o0		!  ...0
+
+ENTRY(longjmp)
+	sub	%sp, 64, %sp	! set up a local stack frame
+0:
+	t	ST_FLUSHWIN	! flush register windows out to memory
+	!
+	! We restore the saved stack pointer to %fp, then issue
+	! a restore instruction which will reload the register
+	! window from the stack.
+	!
+        ld      [%o0+4], %o7    /* restore return pc */
+        ld      [%o0+0], %fp    /* and stack pointer */
+
+        retl                    ! success, return %g6
+         restore        %o1, 0, %o0
diff --git a/usr/klibc/arch/sparc/smul.S b/usr/klibc/arch/sparc/smul.S
new file mode 100644
index 0000000..544ff6e
--- /dev/null
+++ b/usr/klibc/arch/sparc/smul.S
@@ -0,0 +1,160 @@
+/*	$NetBSD: mul.S,v 1.3 1997/07/16 14:37:42 christos 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.
+ *
+ * from: Header: mul.s,v 1.5 92/06/25 13:24:03 torek Exp
+ */
+
+#include <machine/asm.h>
+#if defined(LIBC_SCCS) && !defined(lint)
+#if 0
+	.asciz "@(#)mul.s	8.1 (Berkeley) 6/4/93"
+#else
+	RCSID("$NetBSD: mul.S,v 1.3 1997/07/16 14:37:42 christos Exp $")
+#endif
+#endif /* LIBC_SCCS and not lint */
+
+/*
+ * Signed multiply, from Appendix E of the Sparc Version 8
+ * Architecture Manual.
+ *
+ * Returns %o0 * %o1 in %o1%o0 (i.e., %o1 holds the upper 32 bits of
+ * the 64-bit product).
+ *
+ * This code optimizes short (less than 13-bit) multiplies.
+ */
+
+FUNC(.mul)
+	mov	%o0, %y		! multiplier -> Y
+	andncc	%o0, 0xfff, %g0	! test bits 12..31
+	be	Lmul_shortway	! if zero, can do it the short way
+	andcc	%g0, %g0, %o4	! zero the partial product and clear N and V
+
+	/*
+	 * Long multiply.  32 steps, followed by a final shift step.
+	 */
+	mulscc	%o4, %o1, %o4	! 1
+	mulscc	%o4, %o1, %o4	! 2
+	mulscc	%o4, %o1, %o4	! 3
+	mulscc	%o4, %o1, %o4	! 4
+	mulscc	%o4, %o1, %o4	! 5
+	mulscc	%o4, %o1, %o4	! 6
+	mulscc	%o4, %o1, %o4	! 7
+	mulscc	%o4, %o1, %o4	! 8
+	mulscc	%o4, %o1, %o4	! 9
+	mulscc	%o4, %o1, %o4	! 10
+	mulscc	%o4, %o1, %o4	! 11
+	mulscc	%o4, %o1, %o4	! 12
+	mulscc	%o4, %o1, %o4	! 13
+	mulscc	%o4, %o1, %o4	! 14
+	mulscc	%o4, %o1, %o4	! 15
+	mulscc	%o4, %o1, %o4	! 16
+	mulscc	%o4, %o1, %o4	! 17
+	mulscc	%o4, %o1, %o4	! 18
+	mulscc	%o4, %o1, %o4	! 19
+	mulscc	%o4, %o1, %o4	! 20
+	mulscc	%o4, %o1, %o4	! 21
+	mulscc	%o4, %o1, %o4	! 22
+	mulscc	%o4, %o1, %o4	! 23
+	mulscc	%o4, %o1, %o4	! 24
+	mulscc	%o4, %o1, %o4	! 25
+	mulscc	%o4, %o1, %o4	! 26
+	mulscc	%o4, %o1, %o4	! 27
+	mulscc	%o4, %o1, %o4	! 28
+	mulscc	%o4, %o1, %o4	! 29
+	mulscc	%o4, %o1, %o4	! 30
+	mulscc	%o4, %o1, %o4	! 31
+	mulscc	%o4, %o1, %o4	! 32
+	mulscc	%o4, %g0, %o4	! final shift
+
+	! If %o0 was negative, the result is
+	!	(%o0 * %o1) + (%o1 << 32))
+	! We fix that here.
+
+	tst	%o0
+	bge	1f
+	rd	%y, %o0
+
+	! %o0 was indeed negative; fix upper 32 bits of result by subtracting
+	! %o1 (i.e., return %o4 - %o1 in %o1).
+	retl
+	sub	%o4, %o1, %o1
+
+1:
+	retl
+	mov	%o4, %o1
+
+Lmul_shortway:
+	/*
+	 * Short multiply.  12 steps, followed by a final shift step.
+	 * The resulting bits are off by 12 and (32-12) = 20 bit positions,
+	 * but there is no problem with %o0 being negative (unlike above).
+	 */
+	mulscc	%o4, %o1, %o4	! 1
+	mulscc	%o4, %o1, %o4	! 2
+	mulscc	%o4, %o1, %o4	! 3
+	mulscc	%o4, %o1, %o4	! 4
+	mulscc	%o4, %o1, %o4	! 5
+	mulscc	%o4, %o1, %o4	! 6
+	mulscc	%o4, %o1, %o4	! 7
+	mulscc	%o4, %o1, %o4	! 8
+	mulscc	%o4, %o1, %o4	! 9
+	mulscc	%o4, %o1, %o4	! 10
+	mulscc	%o4, %o1, %o4	! 11
+	mulscc	%o4, %o1, %o4	! 12
+	mulscc	%o4, %g0, %o4	! final shift
+
+	/*
+	 *  %o4 has 20 of the bits that should be in the low part of the
+	 * result; %y has the bottom 12 (as %y's top 12).  That is:
+	 *
+	 *	  %o4		    %y
+	 * +----------------+----------------+
+	 * | -12- |   -20-  | -12- |   -20-  |
+	 * +------(---------+------)---------+
+	 *  --hi-- ----low-part----
+	 *
+	 * The upper 12 bits of %o4 should be sign-extended to form the
+	 * high part of the product (i.e., highpart = %o4 >> 20).
+	 */
+
+	rd	%y, %o5
+	sll	%o4, 12, %o0	! shift middle bits left 12
+	srl	%o5, 20, %o5	! shift low bits right 20, zero fill at left
+	or	%o5, %o0, %o0	! construct low part of result
+	retl
+	sra	%o4, 20, %o1	! ... and extract high part of result
diff --git a/usr/klibc/arch/sparc/syscall.S b/usr/klibc/arch/sparc/syscall.S
new file mode 100644
index 0000000..c0273f7
--- /dev/null
+++ b/usr/klibc/arch/sparc/syscall.S
@@ -0,0 +1,19 @@
+/*
+ * arch/sparc/syscall.S
+ *
+ * Common system-call stub; %g1 already set to syscall number
+ */
+
+	.globl	__syscall_common
+	.type	__syscall_common,#function
+       	.align	4
+__syscall_common:
+	t	0x10
+	bcc	1f
+	  sethi	%hi(errno), %g4
+	or	%g4, %lo(errno), %g4
+	st	%o0,[%g4]
+	mov	-1, %o0
+1:
+       	retl
+	  nop
diff --git a/usr/klibc/arch/sparc/sysfork.S b/usr/klibc/arch/sparc/sysfork.S
new file mode 100644
index 0000000..a66c76e
--- /dev/null
+++ b/usr/klibc/arch/sparc/sysfork.S
@@ -0,0 +1,25 @@
+/*
+ * arch/sparc/sysfork.S
+ *
+ * The fork and vfork system calls are special on sparc[64]:
+ * they return the "other process" pid in %o0 and the
+ * "is child" flag in %o1
+ *
+ * Common system-call stub; %g1 already set to syscall number
+ */
+
+	.globl	__syscall_forkish
+	.type	__syscall_forkish,#function
+       	.align	4
+__syscall_forkish:
+	t	0x10
+	sub	%o1, 1, %o1
+	bcc,a	1f
+	  and	%o0, %o1, %o0
+	sethi	%hi(errno), %g4
+	or	%g4, %lo(errno), %g4
+	st	%o0,[%g4]
+	mov	-1, %o0
+1:
+       	retl
+	  nop
diff --git a/usr/klibc/arch/sparc/sysstub.ph b/usr/klibc/arch/sparc/sysstub.ph
new file mode 100644
index 0000000..d8cedb5
--- /dev/null
+++ b/usr/klibc/arch/sparc/sysstub.ph
@@ -0,0 +1,25 @@
+# -*- perl -*-
+#
+# arch/sparc32/sysstub.ph
+#
+# Script to generate system call stubs
+#
+
+sub make_sysstub($$$$$@) {
+    my($outputdir, $fname, $type, $sname, $stype, @args) = @_;
+
+    $stype = $stype || 'common';
+
+    open(OUT, '>', "${outputdir}/${fname}.S");
+    print OUT "#include <asm/unistd.h>\n";
+    print OUT "\n";
+    print OUT "\t.type ${fname},\@function\n";
+    print OUT "\t.globl ${fname}\n";
+    print OUT "${fname}:\n";
+    print OUT "\tb __syscall_${stype}\n";
+    print OUT "\t  mov\t__NR_${sname}, %g1\n";
+    print OUT "\t.size ${fname},.-${fname}\n";
+    close(OUT);
+}
+
+1;
diff --git a/usr/klibc/arch/sparc/umul.S b/usr/klibc/arch/sparc/umul.S
new file mode 100644
index 0000000..6a7193d
--- /dev/null
+++ b/usr/klibc/arch/sparc/umul.S
@@ -0,0 +1,193 @@
+/*	$NetBSD: umul.S,v 1.3 1997/07/16 14:37:44 christos 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.
+ *
+ * from: Header: umul.s,v 1.4 92/06/25 13:24:05 torek Exp
+ */
+
+#include <machine/asm.h>
+#if defined(LIBC_SCCS) && !defined(lint)
+#if 0
+	.asciz "@(#)umul.s	8.1 (Berkeley) 6/4/93"
+#else
+	RCSID("$NetBSD: umul.S,v 1.3 1997/07/16 14:37:44 christos Exp $")
+#endif
+#endif /* LIBC_SCCS and not lint */
+
+/*
+ * Unsigned multiply.  Returns %o0 * %o1 in %o1%o0 (i.e., %o1 holds the
+ * upper 32 bits of the 64-bit product).
+ *
+ * This code optimizes short (less than 13-bit) multiplies.  Short
+ * multiplies require 25 instruction cycles, and long ones require
+ * 45 instruction cycles.
+ *
+ * On return, overflow has occurred (%o1 is not zero) if and only if
+ * the Z condition code is clear, allowing, e.g., the following:
+ *
+ *	call	.umul
+ *	nop
+ *	bnz	overflow	(or tnz)
+ */
+
+FUNC(.umul)
+	or	%o0, %o1, %o4
+	mov	%o0, %y		! multiplier -> Y
+	andncc	%o4, 0xfff, %g0	! test bits 12..31 of *both* args
+	be	Lmul_shortway	! if zero, can do it the short way
+	andcc	%g0, %g0, %o4	! zero the partial product and clear N and V
+
+	/*
+	 * Long multiply.  32 steps, followed by a final shift step.
+	 */
+	mulscc	%o4, %o1, %o4	! 1
+	mulscc	%o4, %o1, %o4	! 2
+	mulscc	%o4, %o1, %o4	! 3
+	mulscc	%o4, %o1, %o4	! 4
+	mulscc	%o4, %o1, %o4	! 5
+	mulscc	%o4, %o1, %o4	! 6
+	mulscc	%o4, %o1, %o4	! 7
+	mulscc	%o4, %o1, %o4	! 8
+	mulscc	%o4, %o1, %o4	! 9
+	mulscc	%o4, %o1, %o4	! 10
+	mulscc	%o4, %o1, %o4	! 11
+	mulscc	%o4, %o1, %o4	! 12
+	mulscc	%o4, %o1, %o4	! 13
+	mulscc	%o4, %o1, %o4	! 14
+	mulscc	%o4, %o1, %o4	! 15
+	mulscc	%o4, %o1, %o4	! 16
+	mulscc	%o4, %o1, %o4	! 17
+	mulscc	%o4, %o1, %o4	! 18
+	mulscc	%o4, %o1, %o4	! 19
+	mulscc	%o4, %o1, %o4	! 20
+	mulscc	%o4, %o1, %o4	! 21
+	mulscc	%o4, %o1, %o4	! 22
+	mulscc	%o4, %o1, %o4	! 23
+	mulscc	%o4, %o1, %o4	! 24
+	mulscc	%o4, %o1, %o4	! 25
+	mulscc	%o4, %o1, %o4	! 26
+	mulscc	%o4, %o1, %o4	! 27
+	mulscc	%o4, %o1, %o4	! 28
+	mulscc	%o4, %o1, %o4	! 29
+	mulscc	%o4, %o1, %o4	! 30
+	mulscc	%o4, %o1, %o4	! 31
+	mulscc	%o4, %o1, %o4	! 32
+	mulscc	%o4, %g0, %o4	! final shift
+
+
+	/*
+	 * Normally, with the shift-and-add approach, if both numbers are
+	 * positive you get the correct result.  WIth 32-bit two's-complement
+	 * numbers, -x is represented as
+	 *
+	 *		  x		    32
+	 *	( 2  -  ------ ) mod 2  *  2
+	 *		   32
+	 *		  2
+	 *
+	 * (the `mod 2' subtracts 1 from 1.bbbb).  To avoid lots of 2^32s,
+	 * we can treat this as if the radix point were just to the left
+	 * of the sign bit (multiply by 2^32), and get
+	 *
+	 *	-x  =  (2 - x) mod 2
+	 *
+	 * Then, ignoring the `mod 2's for convenience:
+	 *
+	 *   x *  y	= xy
+	 *  -x *  y	= 2y - xy
+	 *   x * -y	= 2x - xy
+	 *  -x * -y	= 4 - 2x - 2y + xy
+	 *
+	 * For signed multiplies, we subtract (x << 32) from the partial
+	 * product to fix this problem for negative multipliers (see mul.s).
+	 * Because of the way the shift into the partial product is calculated
+	 * (N xor V), this term is automatically removed for the multiplicand,
+	 * so we don't have to adjust.
+	 *
+	 * But for unsigned multiplies, the high order bit wasn't a sign bit,
+	 * and the correction is wrong.  So for unsigned multiplies where the
+	 * high order bit is one, we end up with xy - (y << 32).  To fix it
+	 * we add y << 32.
+	 */
+	tst	%o1
+	bl,a	1f		! if %o1 < 0 (high order bit = 1),
+	add	%o4, %o0, %o4	! %o4 += %o0 (add y to upper half)
+1:	rd	%y, %o0		! get lower half of product
+	retl
+	addcc	%o4, %g0, %o1	! put upper half in place and set Z for %o1==0
+
+Lmul_shortway:
+	/*
+	 * Short multiply.  12 steps, followed by a final shift step.
+	 * The resulting bits are off by 12 and (32-12) = 20 bit positions,
+	 * but there is no problem with %o0 being negative (unlike above),
+	 * and overflow is impossible (the answer is at most 24 bits long).
+	 */
+	mulscc	%o4, %o1, %o4	! 1
+	mulscc	%o4, %o1, %o4	! 2
+	mulscc	%o4, %o1, %o4	! 3
+	mulscc	%o4, %o1, %o4	! 4
+	mulscc	%o4, %o1, %o4	! 5
+	mulscc	%o4, %o1, %o4	! 6
+	mulscc	%o4, %o1, %o4	! 7
+	mulscc	%o4, %o1, %o4	! 8
+	mulscc	%o4, %o1, %o4	! 9
+	mulscc	%o4, %o1, %o4	! 10
+	mulscc	%o4, %o1, %o4	! 11
+	mulscc	%o4, %o1, %o4	! 12
+	mulscc	%o4, %g0, %o4	! final shift
+
+	/*
+	 * %o4 has 20 of the bits that should be in the result; %y has
+	 * the bottom 12 (as %y's top 12).  That is:
+	 *
+	 *	  %o4		    %y
+	 * +----------------+----------------+
+	 * | -12- |   -20-  | -12- |   -20-  |
+	 * +------(---------+------)---------+
+	 *	   -----result-----
+	 *
+	 * The 12 bits of %o4 left of the `result' area are all zero;
+	 * in fact, all top 20 bits of %o4 are zero.
+	 */
+
+	rd	%y, %o5
+	sll	%o4, 12, %o0	! shift middle bits left 12
+	srl	%o5, 20, %o5	! shift low bits right 20
+	or	%o5, %o0, %o0
+	retl
+	addcc	%g0, %g0, %o1	! %o1 = zero, and set Z
diff --git a/usr/klibc/arch/sparc64/Kbuild b/usr/klibc/arch/sparc64/Kbuild
new file mode 100644
index 0000000..2854f69
--- /dev/null
+++ b/usr/klibc/arch/sparc64/Kbuild
@@ -0,0 +1,8 @@
+#
+# klibc files for sparc64
+#
+
+klib-y := pipe.o setjmp.o syscall.o sysfork.o
+
+always  := crt0.o
+targets := crt0.o
diff --git a/usr/klibc/arch/sparc64/MCONFIG b/usr/klibc/arch/sparc64/MCONFIG
new file mode 100644
index 0000000..bd6f004
--- /dev/null
+++ b/usr/klibc/arch/sparc64/MCONFIG
@@ -0,0 +1,21 @@
+# -*- makefile -*-
+#
+# arch/sparc64/MCONFIG
+#
+# Special rules for this architecture.  Note that this is actually
+# included from the main Makefile, and that pathnames should be
+# accordingly.
+#
+
+KLIBCARCHREQFLAGS = -m64 -mptr64 -D__sparc64__
+KLIBCOPTFLAGS     += -Os
+KLIBCBITSIZE      = 64
+
+KLIBCLDFLAGS      = -m elf64_sparc
+
+# Extra linkflags when building the shared version of the library
+# This address needs to be reachable using normal inter-module
+# calls, and work on the memory models for this architecture
+# Normal binaries start at 1 MB; the linker wants 1 MB alignment,
+# and call instructions have a 30-bit signed offset, << 2.
+KLIBCSHAREDFLAGS	= -Ttext 0x80000200
diff --git a/usr/klibc/arch/sparc64/crt0.S b/usr/klibc/arch/sparc64/crt0.S
new file mode 100644
index 0000000..5faee7c
--- /dev/null
+++ b/usr/klibc/arch/sparc64/crt0.S
@@ -0,0 +1,2 @@
+#define TARGET_PTR_SIZE 64
+#include "../sparc/crt0i.S"
diff --git a/usr/klibc/arch/sparc64/pipe.S b/usr/klibc/arch/sparc64/pipe.S
new file mode 100644
index 0000000..c63b20f
--- /dev/null
+++ b/usr/klibc/arch/sparc64/pipe.S
@@ -0,0 +1,30 @@
+/*
+ * arch/sparc64/pipe.S
+ *
+ * The pipe system call are special on sparc[64]:
+ * they return the two file descriptors in %o0 and %o1.
+ */
+
+#include <asm/unistd.h>
+
+	.globl	pipe
+	.type	pipe,#function
+       	.align	4
+pipe:
+	mov	__NR_pipe, %g1
+	or	%o0, 0, %g4
+	t	0x6d
+	bcc	%xcc, 1f
+	  nop
+	sethi	%hi(errno), %g4
+	or	%g4, %lo(errno), %g4
+	st	%o0,[%g4]
+	retl
+	  mov	-1, %o0
+1:
+	st	%o0,[%g4]
+	st	%o1,[%g4+4]
+	retl
+	  mov	0, %o0
+
+	.size pipe,.-pipe
diff --git a/usr/klibc/arch/sparc64/setjmp.S b/usr/klibc/arch/sparc64/setjmp.S
new file mode 100644
index 0000000..75a6a68
--- /dev/null
+++ b/usr/klibc/arch/sparc64/setjmp.S
@@ -0,0 +1,55 @@
+!
+! setjmp.S
+!
+! Basic setjmp/longjmp
+!
+! This code was based on the equivalent code in NetBSD
+!
+
+!
+! The jmp_buf contains the following entries:
+!   sp
+!   fp
+!   pc
+!
+	.text
+	.align	4
+	.global	setjmp
+	.type	setjmp, @function
+setjmp:
+	stx	%sp,[%o0+0]	! Callers stack pointer
+	stx	%o7,[%o0+8]	! Return pc
+	stx	%fp,[%o0+16]	! Frame pointer
+	retl			! Return
+	 clr	%o0		!  ...0
+
+	.size	setjmp,.-setjmp
+
+
+       	.globl	longjmp
+	.type	longjmp, @function
+longjmp:
+	mov	%o1, %g4	! save return value
+	mov	%o0, %g1	! save target
+	ldx	[%g1+16],%g5	! get callers frame
+1:
+	cmp	%fp, %g5	! compare against desired frame
+	bl,a	1b		! if below...
+	 restore		! pop frame and loop
+	be,a	2f		! if there...
+       	 ldx	[%g1+0],%o2	! fetch return %sp
+
+.Lbotch:
+	unimp	0		! ... error ...
+
+2:
+       	cmp	%o2, %sp	! %sp must not decrease
+	bl	.Lbotch
+	 nop
+	mov	%o2, %sp	! it is OK, put it in place
+
+	ldx	[%g1+8],%o3	! fetch %pc
+	jmp	%o3 + 8		! if sucess...
+	 mov	%g4,%o0		!   return %g4
+
+	.size	longjmp,.-longjmp
diff --git a/usr/klibc/arch/sparc64/syscall.S b/usr/klibc/arch/sparc64/syscall.S
new file mode 100644
index 0000000..7ab9d95
--- /dev/null
+++ b/usr/klibc/arch/sparc64/syscall.S
@@ -0,0 +1,18 @@
+/*
+ * arch/sparc64/syscall.S
+ *
+ * Common system-call stub; %g1 already set to syscall number
+ */
+
+	.globl	__syscall_common
+	.type	__syscall_common,#function
+       	.align	4
+__syscall_common:
+	t	0x6d
+	bcc	%xcc, 1f
+	  sethi	%hi(errno), %g4
+	or	%g4, %lo(errno), %g4
+	st	%o0,[%g4]
+1:
+       	retl
+	  movcs	%xcc, -1, %o0
diff --git a/usr/klibc/arch/sparc64/sysfork.S b/usr/klibc/arch/sparc64/sysfork.S
new file mode 100644
index 0000000..2eed659
--- /dev/null
+++ b/usr/klibc/arch/sparc64/sysfork.S
@@ -0,0 +1,26 @@
+/*
+ * arch/sparc64/sysfork.S
+ *
+ * The fork and vfork system calls are special on sparc[64]:
+ * they return the "other process" pid in %o0 and the
+ * "is child" flag in %o1
+ *
+ * Common system-call stub; %g1 already set to syscall number
+ */
+
+	.globl	__syscall_forkish
+	.type	__syscall_forkish,#function
+       	.align	4
+__syscall_forkish:
+	t	0x6d
+	sub	%o1, 1, %o1
+	bcc,a	%xcc, 1f
+	  and	%o0, %o1, %o0
+	sethi	%hi(errno), %g4
+	or	%g4, %lo(errno), %g4
+	st	%o0, [%g4]
+	retl
+	  mov	-1, %o0
+1:
+       	retl
+	  nop
diff --git a/usr/klibc/arch/sparc64/sysstub.ph b/usr/klibc/arch/sparc64/sysstub.ph
new file mode 100644
index 0000000..deeb88c
--- /dev/null
+++ b/usr/klibc/arch/sparc64/sysstub.ph
@@ -0,0 +1,25 @@
+# -*- perl -*-
+#
+# arch/sparc64/sysstub.ph
+#
+# Script to generate system call stubs
+#
+
+sub make_sysstub($$$$$@) {
+    my($outputdir, $fname, $type, $sname, $stype, @args) = @_;
+
+    $stype = $stype || 'common';
+
+    open(OUT, '>', "${outputdir}/${fname}.S");
+    print OUT "#include <asm/unistd.h>\n";
+    print OUT "\n";
+    print OUT "\t.type ${fname},\@function\n";
+    print OUT "\t.globl ${fname}\n";
+    print OUT "${fname}:\n";
+    print OUT "\tb __syscall_${stype}\n";
+    print OUT "\t  mov\t__NR_${sname}, %g1\n";
+    print OUT "\t.size ${fname},.-${fname}\n";
+    close(OUT);
+}
+
+1;
diff --git a/usr/klibc/arch/x86_64/Kbuild b/usr/klibc/arch/x86_64/Kbuild
new file mode 100644
index 0000000..3f69c5b
--- /dev/null
+++ b/usr/klibc/arch/x86_64/Kbuild
@@ -0,0 +1,8 @@
+# -*- makefile -*-
+#
+# klibc files for x86_64
+
+always  := crt0.o
+targets := crt0.o
+
+klib-y := setjmp.o syscall.o sigreturn.o vfork.o
diff --git a/usr/klibc/arch/x86_64/MCONFIG b/usr/klibc/arch/x86_64/MCONFIG
new file mode 100644
index 0000000..b40c627
--- /dev/null
+++ b/usr/klibc/arch/x86_64/MCONFIG
@@ -0,0 +1,39 @@
+# -*- makefile -*-
+#
+# arch/x86-64/MCONFIG
+#
+# Special rules for this architecture.  Note that this is actually
+# included from the main Makefile, and that pathnames should be
+# accordingly.
+#
+# Blatantly copied and modified from i386 version by Mats Petersson, AMD.
+#
+
+#
+# NOTE: -fno-asynchronous-unwind-tables produce significantly smaller
+# binaries (20% smaller), but makes the code completely useless for
+# debugging using gdb.
+#
+KLIBCARCHREQFLAGS = -m64
+ifeq ($(DEBUG),y)
+KLIBCOPTFLAGS     += -g -Os -fomit-frame-pointer \
+		-falign-functions=1 -falign-jumps=1 -falign-loops=1
+else
+KLIBCOPTFLAGS     += -Os -fno-asynchronous-unwind-tables -fomit-frame-pointer \
+		-falign-functions=1 -falign-jumps=1 -falign-loops=1
+endif
+KLIBCBITSIZE      = 64
+KLIBCLDFLAGS      = -m elf_x86_64
+
+# Extra linkflags when building the shared version of the library
+# This address needs to be reachable using normal inter-module
+# calls, and work on the memory models for this architecture
+# 2 MB - normal binaries start at 4 MB
+#
+# Recent binutils use max-page-size=0x200000 by default, which pushes
+# klibc.so data over the 4 MB mark, overlapping the executable.
+# Revert to the old max-page-size=0x100000 value.
+KLIBCSHAREDFLAGS     = -Ttext 0x00200200 -z max-page-size=0x100000
+
+# Additional asm- directories needed during installation
+ASMARCH = asm-i386
diff --git a/usr/klibc/arch/x86_64/crt0.S b/usr/klibc/arch/x86_64/crt0.S
new file mode 100644
index 0000000..6a5f335
--- /dev/null
+++ b/usr/klibc/arch/x86_64/crt0.S
@@ -0,0 +1,22 @@
+#
+# arch/x86_64/crt0.S
+#
+# Does arch-specific initialization and invokes __libc_init
+# with the appropriate arguments.
+#
+# See __static_init.c or __shared_init.c for the expected
+# arguments.
+#
+
+	.text
+	.align 4
+	.type _start,@function
+	.globl _start
+_start:
+	movq %rsp,%rdi			# Offset of the ELF data structure
+	movq %rdx,%rsi			# The atexit() pointer (if any)
+	call __libc_init
+	# We should never get here...
+	hlt
+
+	.size _start,.-_start
diff --git a/usr/klibc/arch/x86_64/setjmp.S b/usr/klibc/arch/x86_64/setjmp.S
new file mode 100644
index 0000000..45f547b
--- /dev/null
+++ b/usr/klibc/arch/x86_64/setjmp.S
@@ -0,0 +1,54 @@
+#
+# arch/x86_64/setjmp.S
+#
+# setjmp/longjmp for the x86-64 architecture
+#
+
+#
+# The jmp_buf is assumed to contain the following, in order:
+#	%rbx
+#	%rsp (post-return)
+#	%rbp
+#	%r12
+#	%r13
+#	%r14
+#	%r15
+#	<return address>
+#
+
+	.text
+	.align 4
+	.globl setjmp
+	.type setjmp, @function
+setjmp:
+	pop  %rsi			# Return address, and adjust the stack
+	xorl %eax,%eax			# Return value
+	movq %rbx,(%rdi)
+	movq %rsp,8(%rdi)		# Post-return %rsp!
+	push %rsi			# Make the call/return stack happy
+	movq %rbp,16(%rdi)
+	movq %r12,24(%rdi)
+	movq %r13,32(%rdi)
+	movq %r14,40(%rdi)
+	movq %r15,48(%rdi)
+	movq %rsi,56(%rdi)		# Return address
+	ret
+
+	.size setjmp,.-setjmp
+
+	.text
+	.align 4
+	.globl longjmp
+	.type longjmp, @function
+longjmp:
+	movl %esi,%eax			# Return value (int)
+	movq (%rdi),%rbx
+	movq 8(%rdi),%rsp
+	movq 16(%rdi),%rbp
+	movq 24(%rdi),%r12
+	movq 32(%rdi),%r13
+	movq 40(%rdi),%r14
+	movq 48(%rdi),%r15
+	jmp *56(%rdi)
+
+	.size longjmp,.-longjmp
diff --git a/usr/klibc/arch/x86_64/sigreturn.S b/usr/klibc/arch/x86_64/sigreturn.S
new file mode 100644
index 0000000..46a5a0b
--- /dev/null
+++ b/usr/klibc/arch/x86_64/sigreturn.S
@@ -0,0 +1,15 @@
+/*
+ * arch/x86_64/sigreturn.S
+ */
+
+#include <asm/unistd.h>
+
+	.text
+	.align	4
+	.globl	__sigreturn
+	.type	__sigreturn,@function
+__sigreturn:
+	movl	$__NR_rt_sigreturn,%eax
+	syscall
+
+	.size	__sigreturn,.-__sigreturn
diff --git a/usr/klibc/arch/x86_64/syscall.S b/usr/klibc/arch/x86_64/syscall.S
new file mode 100644
index 0000000..1797797
--- /dev/null
+++ b/usr/klibc/arch/x86_64/syscall.S
@@ -0,0 +1,28 @@
+/*
+ * arch/x86-64/syscall.S
+ *
+ * Common tail-handling code for system calls.
+ *
+ * The arguments are in the standard argument registers; the system
+ * call number in %eax.
+ */
+	.text
+	.align	4
+	.globl	__syscall_common
+	.type	__syscall_common,@function
+__syscall_common:
+	movq	%rcx,%r10		# The kernel uses %r10 istf %rcx
+	syscall
+
+	cmpq	$-4095,%rax
+	jnb	1f
+	ret
+
+	# Error return, must set errno
+1:
+	negl	%eax
+	movl	%eax,errno(%rip)	# errno is type int, so 32 bits
+	orq	$-1,%rax		# orq $-1 smaller than movq $-1
+	ret
+
+	.size	__syscall_common,.-__syscall_common
diff --git a/usr/klibc/arch/x86_64/sysstub.ph b/usr/klibc/arch/x86_64/sysstub.ph
new file mode 100644
index 0000000..e2d797b
--- /dev/null
+++ b/usr/klibc/arch/x86_64/sysstub.ph
@@ -0,0 +1,23 @@
+# -*- perl -*-
+#
+# arch/x86_64/sysstub.ph
+#
+# Script to generate system call stubs
+#
+
+sub make_sysstub($$$$$@) {
+    my($outputdir, $fname, $type, $sname, $stype, @args) = @_;
+
+    open(OUT, '>', "${outputdir}/${fname}.S");
+    print OUT "#include <asm/unistd.h>\n";
+    print OUT "\n";
+    print OUT "\t.type ${fname},\@function\n";
+    print OUT "\t.globl ${fname}\n";
+    print OUT "${fname}:\n";
+    print OUT "\tmovl \$__NR_${sname},%eax\n"; # Zero-extends to 64 bits
+    print OUT "\tjmp __syscall_common\n";
+    print OUT "\t.size ${fname},.-${fname}\n";
+    close(OUT);
+}
+
+1;
diff --git a/usr/klibc/arch/x86_64/vfork.S b/usr/klibc/arch/x86_64/vfork.S
new file mode 100644
index 0000000..e1c8090
--- /dev/null
+++ b/usr/klibc/arch/x86_64/vfork.S
@@ -0,0 +1,26 @@
+#
+# usr/klibc/arch/x86_64/vfork.S
+#
+# vfork is nasty - there must be nothing at all on the stack above
+# the stack frame of the enclosing function.
+#
+
+#include <asm/unistd.h>
+
+	.text
+	.align	4
+	.globl	vfork
+	.type	vfork, @function
+vfork:
+	pop	%rdx			/* Return address */
+	movl	$__NR_vfork, %eax
+	syscall
+	push	%rdx
+	cmpq	$-4095, %rax
+	jae	1f
+	ret
+1:
+	negl	%eax
+	movl	%eax, errno(%rip)
+	orq	$-1, %rax
+	ret
diff --git a/usr/klibc/asprintf.c b/usr/klibc/asprintf.c
new file mode 100644
index 0000000..a3f5f00
--- /dev/null
+++ b/usr/klibc/asprintf.c
@@ -0,0 +1,30 @@
+/*
+ * asprintf.c
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+
+int asprintf(char **bufp, const char *format, ...)
+{
+	va_list ap, ap1;
+	int rv;
+	int bytes;
+	char *p;
+
+	va_start(ap, format);
+	va_copy(ap1, ap);
+
+	bytes = vsnprintf(NULL, 0, format, ap1) + 1;
+	va_end(ap1);
+
+	*bufp = p = malloc(bytes);
+	if (!p)
+		return -1;
+
+	rv = vsnprintf(p, bytes, format, ap);
+	va_end(ap);
+
+	return rv;
+}
diff --git a/usr/klibc/assert.c b/usr/klibc/assert.c
new file mode 100644
index 0000000..cca4129
--- /dev/null
+++ b/usr/klibc/assert.c
@@ -0,0 +1,14 @@
+/*
+ * assert.c
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <assert.h>
+#include <klibc/compiler.h>
+
+__noreturn __assert_fail(const char *expr, const char *file, unsigned int line)
+{
+	printf("Assertion %s failed, file %s, line %u\n", expr, file, line);
+	abort();
+}
diff --git a/usr/klibc/atexit.c b/usr/klibc/atexit.c
new file mode 100644
index 0000000..af1b461
--- /dev/null
+++ b/usr/klibc/atexit.c
@@ -0,0 +1,10 @@
+/*
+ * atexit.c
+ */
+
+#include <stdlib.h>
+
+int atexit(void (*fctn) (void))
+{
+	return on_exit((void (*)(int, void *))fctn, NULL);
+}
diff --git a/usr/klibc/atexit.h b/usr/klibc/atexit.h
new file mode 100644
index 0000000..5018689
--- /dev/null
+++ b/usr/klibc/atexit.h
@@ -0,0 +1,18 @@
+/*
+ * atexit.h
+ *
+ * atexit()/on_exit() internal definitions
+ */
+
+#ifndef ATEXIT_H
+#define ATEXIT_H
+
+struct atexit {
+	void (*fctn) (int, void *);
+	void *arg;		/* on_exit() parameter */
+	struct atexit *next;
+};
+
+extern struct atexit *__atexit_list;
+
+#endif				/* ATEXIT_H */
diff --git a/usr/klibc/atoi.c b/usr/klibc/atoi.c
new file mode 100644
index 0000000..a6ec0bf
--- /dev/null
+++ b/usr/klibc/atoi.c
@@ -0,0 +1,3 @@
+#define TYPE int
+#define NAME atoi
+#include "atox.c"
diff --git a/usr/klibc/atol.c b/usr/klibc/atol.c
new file mode 100644
index 0000000..e65484e
--- /dev/null
+++ b/usr/klibc/atol.c
@@ -0,0 +1,3 @@
+#define TYPE long
+#define NAME atol
+#include "atox.c"
diff --git a/usr/klibc/atoll.c b/usr/klibc/atoll.c
new file mode 100644
index 0000000..25df79e
--- /dev/null
+++ b/usr/klibc/atoll.c
@@ -0,0 +1,3 @@
+#define TYPE long long
+#define NAME atoll
+#include "atox.c"
diff --git a/usr/klibc/atox.c b/usr/klibc/atox.c
new file mode 100644
index 0000000..c013bb4
--- /dev/null
+++ b/usr/klibc/atox.c
@@ -0,0 +1,14 @@
+/*
+ * atox.c
+ *
+ * atoi(), atol(), atoll()
+ */
+
+#include <inttypes.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+TYPE NAME(const char *nptr)
+{
+	return (TYPE) strntoumax(nptr, (char **)NULL, 10, ~(size_t) 0);
+}
diff --git a/usr/klibc/brk.c b/usr/klibc/brk.c
new file mode 100644
index 0000000..df0bb7b
--- /dev/null
+++ b/usr/klibc/brk.c
@@ -0,0 +1,29 @@
+/* brk.c - Change data segment size */
+
+/* Written 2000 by Werner Almesberger */
+
+#include <stddef.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include "malloc.h"
+
+#if !_KLIBC_NO_MMU		/* uClinux doesn't have brk() */
+
+char *__current_brk;
+
+/*
+ * The Linux brk() isn't what most people expect, so we call the
+ * system call __brk() and provide a wrapper.
+ */
+int brk(void *end_data_segment)
+{
+	char *new_brk;
+
+	new_brk = __brk(end_data_segment);
+	if (new_brk != end_data_segment)
+		return -1;
+	__current_brk = new_brk;
+	return 0;
+}
+
+#endif
diff --git a/usr/klibc/bsd_signal.c b/usr/klibc/bsd_signal.c
new file mode 100644
index 0000000..4e6238c
--- /dev/null
+++ b/usr/klibc/bsd_signal.c
@@ -0,0 +1,11 @@
+/*
+ * bsd_signal.c
+ */
+
+#include <signal.h>
+
+__sighandler_t bsd_signal(int signum, __sighandler_t handler)
+{
+	/* BSD signal() semantics */
+	return __signal(signum, handler, SA_RESTART);
+}
diff --git a/usr/klibc/bsearch.c b/usr/klibc/bsearch.c
new file mode 100644
index 0000000..1c8b07f
--- /dev/null
+++ b/usr/klibc/bsearch.c
@@ -0,0 +1,26 @@
+/*
+ * bsearch.c
+ */
+
+#include <stdlib.h>
+
+void *bsearch(const void *key, const void *base, size_t nmemb,
+	      size_t size, int (*cmp) (const void *, const void *))
+{
+	while (nmemb) {
+		size_t mididx = nmemb / 2;
+		const void *midobj = base + mididx * size;
+		int diff = cmp(key, midobj);
+
+		if (diff == 0)
+			return (void *)midobj;
+
+		if (diff > 0) {
+			base = midobj + size;
+			nmemb -= mididx + 1;
+		} else
+			nmemb = mididx;
+	}
+
+	return NULL;
+}
diff --git a/usr/klibc/calloc.c b/usr/klibc/calloc.c
new file mode 100644
index 0000000..3db7664
--- /dev/null
+++ b/usr/klibc/calloc.c
@@ -0,0 +1,20 @@
+/*
+ * calloc.c
+ */
+
+#include <stdlib.h>
+#include <string.h>
+
+/* FIXME: This should look for multiplication overflow */
+
+void *calloc(size_t nmemb, size_t size)
+{
+	void *ptr;
+
+	size *= nmemb;
+	ptr = malloc(size);
+	if (ptr)
+		memset(ptr, 0, size);
+
+	return ptr;
+}
diff --git a/usr/klibc/clearenv.c b/usr/klibc/clearenv.c
new file mode 100644
index 0000000..7c2435e
--- /dev/null
+++ b/usr/klibc/clearenv.c
@@ -0,0 +1,17 @@
+/*
+ * clearenv.c
+ *
+ * Empty the environment
+ */
+
+#include <stdlib.h>
+#include <unistd.h>
+#include "env.h"
+
+/* Note: if environ has been malloc'd, it will be freed on the next
+   setenv() or putenv() */
+int clearenv(void)
+{
+	environ = (char **)__null_environ;
+	return 0;
+}
diff --git a/usr/klibc/closelog.c b/usr/klibc/closelog.c
new file mode 100644
index 0000000..0437710
--- /dev/null
+++ b/usr/klibc/closelog.c
@@ -0,0 +1,18 @@
+/*
+ * closelog.c
+ */
+
+#include <syslog.h>
+#include <unistd.h>
+
+extern int __syslog_fd;
+
+void closelog(void)
+{
+	int logfd = __syslog_fd;
+
+	if (logfd != -1) {
+		close(logfd);
+		__syslog_fd = -1;
+	}
+}
diff --git a/usr/klibc/creat.c b/usr/klibc/creat.c
new file mode 100644
index 0000000..b503bca
--- /dev/null
+++ b/usr/klibc/creat.c
@@ -0,0 +1,12 @@
+/*
+ * creat.c
+ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+int creat(const char *pathname, mode_t mode)
+{
+	return open(pathname, O_CREAT | O_WRONLY | O_TRUNC, mode);
+}
diff --git a/usr/klibc/ctype/ctypefunc.h b/usr/klibc/ctype/ctypefunc.h
new file mode 100644
index 0000000..f9e247d
--- /dev/null
+++ b/usr/klibc/ctype/ctypefunc.h
@@ -0,0 +1,13 @@
+/*
+ * ctype/ctype.h
+ *
+ * Common header for out-of-line ctype functions
+ */
+
+#define __CTYPE_NO_INLINE
+#include <ctype.h>
+
+#define CTYPEFUNC(X)				\
+  int X(int c) {				\
+    return __ctype_##X(c);			\
+  }
diff --git a/usr/klibc/ctype/isalnum.c b/usr/klibc/ctype/isalnum.c
new file mode 100644
index 0000000..57af18b
--- /dev/null
+++ b/usr/klibc/ctype/isalnum.c
@@ -0,0 +1,2 @@
+#include "ctypefunc.h"
+CTYPEFUNC(isalnum)
diff --git a/usr/klibc/ctype/isalpha.c b/usr/klibc/ctype/isalpha.c
new file mode 100644
index 0000000..8f2effe
--- /dev/null
+++ b/usr/klibc/ctype/isalpha.c
@@ -0,0 +1,2 @@
+#include "ctypefunc.h"
+CTYPEFUNC(isalpha)
diff --git a/usr/klibc/ctype/isascii.c b/usr/klibc/ctype/isascii.c
new file mode 100644
index 0000000..6a974d5
--- /dev/null
+++ b/usr/klibc/ctype/isascii.c
@@ -0,0 +1,2 @@
+#include "ctypefunc.h"
+CTYPEFUNC(isascii)
diff --git a/usr/klibc/ctype/isblank.c b/usr/klibc/ctype/isblank.c
new file mode 100644
index 0000000..7728550
--- /dev/null
+++ b/usr/klibc/ctype/isblank.c
@@ -0,0 +1,2 @@
+#include "ctypefunc.h"
+CTYPEFUNC(isblank)
diff --git a/usr/klibc/ctype/iscntrl.c b/usr/klibc/ctype/iscntrl.c
new file mode 100644
index 0000000..81db804
--- /dev/null
+++ b/usr/klibc/ctype/iscntrl.c
@@ -0,0 +1,2 @@
+#include "ctypefunc.h"
+CTYPEFUNC(iscntrl)
diff --git a/usr/klibc/ctype/isdigit.c b/usr/klibc/ctype/isdigit.c
new file mode 100644
index 0000000..41a39d9
--- /dev/null
+++ b/usr/klibc/ctype/isdigit.c
@@ -0,0 +1,2 @@
+#include "ctypefunc.h"
+CTYPEFUNC(isdigit)
diff --git a/usr/klibc/ctype/isgraph.c b/usr/klibc/ctype/isgraph.c
new file mode 100644
index 0000000..e5b83d1
--- /dev/null
+++ b/usr/klibc/ctype/isgraph.c
@@ -0,0 +1,2 @@
+#include "ctypefunc.h"
+CTYPEFUNC(isgraph)
diff --git a/usr/klibc/ctype/islower.c b/usr/klibc/ctype/islower.c
new file mode 100644
index 0000000..9e179ae
--- /dev/null
+++ b/usr/klibc/ctype/islower.c
@@ -0,0 +1,2 @@
+#include "ctypefunc.h"
+CTYPEFUNC(islower)
diff --git a/usr/klibc/ctype/isprint.c b/usr/klibc/ctype/isprint.c
new file mode 100644
index 0000000..9c6a351
--- /dev/null
+++ b/usr/klibc/ctype/isprint.c
@@ -0,0 +1,2 @@
+#include "ctypefunc.h"
+CTYPEFUNC(isprint)
diff --git a/usr/klibc/ctype/ispunct.c b/usr/klibc/ctype/ispunct.c
new file mode 100644
index 0000000..36b5258
--- /dev/null
+++ b/usr/klibc/ctype/ispunct.c
@@ -0,0 +1,2 @@
+#include "ctypefunc.h"
+CTYPEFUNC(ispunct)
diff --git a/usr/klibc/ctype/isspace.c b/usr/klibc/ctype/isspace.c
new file mode 100644
index 0000000..aed06c8
--- /dev/null
+++ b/usr/klibc/ctype/isspace.c
@@ -0,0 +1,2 @@
+#include "ctypefunc.h"
+CTYPEFUNC(isspace)
diff --git a/usr/klibc/ctype/isupper.c b/usr/klibc/ctype/isupper.c
new file mode 100644
index 0000000..70a139b
--- /dev/null
+++ b/usr/klibc/ctype/isupper.c
@@ -0,0 +1,2 @@
+#include "ctypefunc.h"
+CTYPEFUNC(isupper)
diff --git a/usr/klibc/ctype/isxdigit.c b/usr/klibc/ctype/isxdigit.c
new file mode 100644
index 0000000..ab89c1f
--- /dev/null
+++ b/usr/klibc/ctype/isxdigit.c
@@ -0,0 +1,2 @@
+#include "ctypefunc.h"
+CTYPEFUNC(isxdigit)
diff --git a/usr/klibc/ctype/tolower.c b/usr/klibc/ctype/tolower.c
new file mode 100644
index 0000000..24ca72b
--- /dev/null
+++ b/usr/klibc/ctype/tolower.c
@@ -0,0 +1,2 @@
+#include "ctypefunc.h"
+CTYPEFUNC(tolower)
diff --git a/usr/klibc/ctype/toupper.c b/usr/klibc/ctype/toupper.c
new file mode 100644
index 0000000..15763f7
--- /dev/null
+++ b/usr/klibc/ctype/toupper.c
@@ -0,0 +1,2 @@
+#include "ctypefunc.h"
+CTYPEFUNC(toupper)
diff --git a/usr/klibc/ctypes.c b/usr/klibc/ctypes.c
new file mode 100644
index 0000000..deb566a
--- /dev/null
+++ b/usr/klibc/ctypes.c
@@ -0,0 +1,284 @@
+/*
+ * ctypes.c
+ *
+ * This is the array that defines <ctype.h> classes.
+ * This assumes ISO 8859-1.
+ */
+
+#include <ctype.h>
+
+const unsigned char __ctypes[257] = {
+	0,			/* EOF */
+
+	__ctype_cntrl,		/* control character */
+	__ctype_cntrl,		/* control character */
+	__ctype_cntrl,		/* control character */
+	__ctype_cntrl,		/* control character */
+	__ctype_cntrl,		/* control character */
+	__ctype_cntrl,		/* control character */
+	__ctype_cntrl,		/* control character */
+	__ctype_cntrl,		/* control character */
+	__ctype_cntrl | __ctype_space,	/* BS */
+	__ctype_cntrl | __ctype_space,	/* TAB */
+	__ctype_cntrl | __ctype_space,	/* LF */
+	__ctype_cntrl | __ctype_space,	/* VT */
+	__ctype_cntrl | __ctype_space,	/* FF */
+	__ctype_cntrl | __ctype_space,	/* CR */
+	__ctype_cntrl,		/* control character */
+
+	__ctype_cntrl,		/* control character */
+	__ctype_cntrl,		/* control character */
+	__ctype_cntrl,		/* control character */
+	__ctype_cntrl,		/* control character */
+	__ctype_cntrl,		/* control character */
+	__ctype_cntrl,		/* control character */
+	__ctype_cntrl,		/* control character */
+	__ctype_cntrl,		/* control character */
+	__ctype_cntrl,		/* control character */
+	__ctype_cntrl,		/* control character */
+	__ctype_cntrl,		/* control character */
+	__ctype_cntrl,		/* control character */
+	__ctype_cntrl,		/* control character */
+	__ctype_cntrl,		/* control character */
+	__ctype_cntrl,		/* control character */
+	__ctype_cntrl,		/* control character */
+	__ctype_cntrl,		/* control character */
+
+	__ctype_print | __ctype_space,	/* space */
+	__ctype_print | __ctype_punct,	/* punctuation */
+	__ctype_print | __ctype_punct,	/* punctuation */
+	__ctype_print | __ctype_punct,	/* punctuation */
+	__ctype_print | __ctype_punct,	/* punctuation */
+	__ctype_print | __ctype_punct,	/* punctuation */
+	__ctype_print | __ctype_punct,	/* punctuation */
+	__ctype_print | __ctype_punct,	/* punctuation */
+	__ctype_print | __ctype_punct,	/* punctuation */
+	__ctype_print | __ctype_punct,	/* punctuation */
+	__ctype_print | __ctype_punct,	/* punctuation */
+	__ctype_print | __ctype_punct,	/* punctuation */
+	__ctype_print | __ctype_punct,	/* punctuation */
+	__ctype_print | __ctype_punct,	/* punctuation */
+	__ctype_print | __ctype_punct,	/* punctuation */
+	__ctype_print | __ctype_punct,	/* punctuation */
+
+	__ctype_print | __ctype_digit | __ctype_xdigit,	/* digit */
+	__ctype_print | __ctype_digit | __ctype_xdigit,	/* digit */
+	__ctype_print | __ctype_digit | __ctype_xdigit,	/* digit */
+	__ctype_print | __ctype_digit | __ctype_xdigit,	/* digit */
+	__ctype_print | __ctype_digit | __ctype_xdigit,	/* digit */
+	__ctype_print | __ctype_digit | __ctype_xdigit,	/* digit */
+	__ctype_print | __ctype_digit | __ctype_xdigit,	/* digit */
+	__ctype_print | __ctype_digit | __ctype_xdigit,	/* digit */
+	__ctype_print | __ctype_digit | __ctype_xdigit,	/* digit */
+	__ctype_print | __ctype_digit | __ctype_xdigit,	/* digit */
+	__ctype_print | __ctype_punct,	/* punctuation */
+	__ctype_print | __ctype_punct,	/* punctuation */
+	__ctype_print | __ctype_punct,	/* punctuation */
+	__ctype_print | __ctype_punct,	/* punctuation */
+	__ctype_print | __ctype_punct,	/* punctuation */
+	__ctype_print | __ctype_punct,	/* punctuation */
+
+	__ctype_print | __ctype_punct,	/* punctuation */
+	__ctype_print | __ctype_upper | __ctype_xdigit,	/* A-F */
+	__ctype_print | __ctype_upper | __ctype_xdigit,	/* A-F */
+	__ctype_print | __ctype_upper | __ctype_xdigit,	/* A-F */
+	__ctype_print | __ctype_upper | __ctype_xdigit,	/* A-F */
+	__ctype_print | __ctype_upper | __ctype_xdigit,	/* A-F */
+	__ctype_print | __ctype_upper | __ctype_xdigit,	/* A-F */
+	__ctype_print | __ctype_upper,	/* G-Z */
+	__ctype_print | __ctype_upper,	/* G-Z */
+	__ctype_print | __ctype_upper,	/* G-Z */
+	__ctype_print | __ctype_upper,	/* G-Z */
+	__ctype_print | __ctype_upper,	/* G-Z */
+	__ctype_print | __ctype_upper,	/* G-Z */
+	__ctype_print | __ctype_upper,	/* G-Z */
+	__ctype_print | __ctype_upper,	/* G-Z */
+	__ctype_print | __ctype_upper,	/* G-Z */
+
+	__ctype_print | __ctype_upper,	/* G-Z */
+	__ctype_print | __ctype_upper,	/* G-Z */
+	__ctype_print | __ctype_upper,	/* G-Z */
+	__ctype_print | __ctype_upper,	/* G-Z */
+	__ctype_print | __ctype_upper,	/* G-Z */
+	__ctype_print | __ctype_upper,	/* G-Z */
+	__ctype_print | __ctype_upper,	/* G-Z */
+	__ctype_print | __ctype_upper,	/* G-Z */
+	__ctype_print | __ctype_upper,	/* G-Z */
+	__ctype_print | __ctype_upper,	/* G-Z */
+	__ctype_print | __ctype_upper,	/* G-Z */
+	__ctype_print | __ctype_punct,	/* punctuation */
+	__ctype_print | __ctype_punct,	/* punctuation */
+	__ctype_print | __ctype_punct,	/* punctuation */
+	__ctype_print | __ctype_punct,	/* punctuation */
+	__ctype_print | __ctype_punct,	/* punctuation */
+
+	__ctype_print | __ctype_punct,	/* punctuation */
+	__ctype_print | __ctype_lower | __ctype_xdigit,	/* a-f */
+	__ctype_print | __ctype_lower | __ctype_xdigit,	/* a-f */
+	__ctype_print | __ctype_lower | __ctype_xdigit,	/* a-f */
+	__ctype_print | __ctype_lower | __ctype_xdigit,	/* a-f */
+	__ctype_print | __ctype_lower | __ctype_xdigit,	/* a-f */
+	__ctype_print | __ctype_lower | __ctype_xdigit,	/* a-f */
+	__ctype_print | __ctype_lower,	/* g-z */
+	__ctype_print | __ctype_lower,	/* g-z */
+	__ctype_print | __ctype_lower,	/* g-z */
+	__ctype_print | __ctype_lower,	/* g-z */
+	__ctype_print | __ctype_lower,	/* g-z */
+	__ctype_print | __ctype_lower,	/* g-z */
+	__ctype_print | __ctype_lower,	/* g-z */
+	__ctype_print | __ctype_lower,	/* g-z */
+	__ctype_print | __ctype_lower,	/* g-z */
+
+	__ctype_print | __ctype_lower,	/* g-z */
+	__ctype_print | __ctype_lower,	/* g-z */
+	__ctype_print | __ctype_lower,	/* g-z */
+	__ctype_print | __ctype_lower,	/* g-z */
+	__ctype_print | __ctype_lower,	/* g-z */
+	__ctype_print | __ctype_lower,	/* g-z */
+	__ctype_print | __ctype_lower,	/* g-z */
+	__ctype_print | __ctype_lower,	/* g-z */
+	__ctype_print | __ctype_lower,	/* g-z */
+	__ctype_print | __ctype_lower,	/* g-z */
+	__ctype_print | __ctype_lower,	/* g-z */
+	__ctype_print | __ctype_punct,	/* punctuation */
+	__ctype_print | __ctype_punct,	/* punctuation */
+	__ctype_print | __ctype_punct,	/* punctuation */
+	__ctype_print | __ctype_punct,	/* punctuation */
+	__ctype_cntrl,		/* control character */
+
+	__ctype_cntrl,		/* control character */
+	__ctype_cntrl,		/* control character */
+	__ctype_cntrl,		/* control character */
+	__ctype_cntrl,		/* control character */
+	__ctype_cntrl,		/* control character */
+	__ctype_cntrl,		/* control character */
+	__ctype_cntrl,		/* control character */
+	__ctype_cntrl,		/* control character */
+	__ctype_cntrl,		/* control character */
+	__ctype_cntrl,		/* control character */
+	__ctype_cntrl,		/* control character */
+	__ctype_cntrl,		/* control character */
+	__ctype_cntrl,		/* control character */
+	__ctype_cntrl,		/* control character */
+	__ctype_cntrl,		/* control character */
+	__ctype_cntrl,		/* control character */
+
+	__ctype_cntrl,		/* control character */
+	__ctype_cntrl,		/* control character */
+	__ctype_cntrl,		/* control character */
+	__ctype_cntrl,		/* control character */
+	__ctype_cntrl,		/* control character */
+	__ctype_cntrl,		/* control character */
+	__ctype_cntrl,		/* control character */
+	__ctype_cntrl,		/* control character */
+	__ctype_cntrl,		/* control character */
+	__ctype_cntrl,		/* control character */
+	__ctype_cntrl,		/* control character */
+	__ctype_cntrl,		/* control character */
+	__ctype_cntrl,		/* control character */
+	__ctype_cntrl,		/* control character */
+	__ctype_cntrl,		/* control character */
+	__ctype_cntrl,		/* control character */
+
+	__ctype_print | __ctype_space,	/* NBSP */
+	__ctype_print | __ctype_punct,	/* punctuation */
+	__ctype_print | __ctype_punct,	/* punctuation */
+	__ctype_print | __ctype_punct,	/* punctuation */
+	__ctype_print | __ctype_punct,	/* punctuation */
+	__ctype_print | __ctype_punct,	/* punctuation */
+	__ctype_print | __ctype_punct,	/* punctuation */
+	__ctype_print | __ctype_punct,	/* punctuation */
+	__ctype_print | __ctype_punct,	/* punctuation */
+	__ctype_print | __ctype_punct,	/* punctuation */
+	__ctype_print | __ctype_punct,	/* punctuation */
+	__ctype_print | __ctype_punct,	/* punctuation */
+	__ctype_print | __ctype_punct,	/* punctuation */
+	__ctype_print | __ctype_punct,	/* punctuation */
+	__ctype_print | __ctype_punct,	/* punctuation */
+	__ctype_print | __ctype_punct,	/* punctuation */
+
+	__ctype_print | __ctype_punct,	/* punctuation */
+	__ctype_print | __ctype_punct,	/* punctuation */
+	__ctype_print | __ctype_punct,	/* punctuation */
+	__ctype_print | __ctype_punct,	/* punctuation */
+	__ctype_print | __ctype_punct,	/* punctuation */
+	__ctype_print | __ctype_punct,	/* punctuation */
+	__ctype_print | __ctype_punct,	/* punctuation */
+	__ctype_print | __ctype_punct,	/* punctuation */
+	__ctype_print | __ctype_punct,	/* punctuation */
+	__ctype_print | __ctype_punct,	/* punctuation */
+	__ctype_print | __ctype_punct,	/* punctuation */
+	__ctype_print | __ctype_punct,	/* punctuation */
+	__ctype_print | __ctype_punct,	/* punctuation */
+	__ctype_print | __ctype_punct,	/* punctuation */
+	__ctype_print | __ctype_punct,	/* punctuation */
+	__ctype_print | __ctype_punct,	/* punctuation */
+
+	__ctype_print | __ctype_upper,	/* upper accented */
+	__ctype_print | __ctype_upper,	/* upper accented */
+	__ctype_print | __ctype_upper,	/* upper accented */
+	__ctype_print | __ctype_upper,	/* upper accented */
+	__ctype_print | __ctype_upper,	/* upper accented */
+	__ctype_print | __ctype_upper,	/* upper accented */
+	__ctype_print | __ctype_upper,	/* upper accented */
+	__ctype_print | __ctype_upper,	/* upper accented */
+	__ctype_print | __ctype_upper,	/* upper accented */
+	__ctype_print | __ctype_upper,	/* upper accented */
+	__ctype_print | __ctype_upper,	/* upper accented */
+	__ctype_print | __ctype_upper,	/* upper accented */
+	__ctype_print | __ctype_upper,	/* upper accented */
+	__ctype_print | __ctype_upper,	/* upper accented */
+	__ctype_print | __ctype_upper,	/* upper accented */
+	__ctype_print | __ctype_upper,	/* upper accented */
+
+	__ctype_print | __ctype_upper,	/* upper accented */
+	__ctype_print | __ctype_upper,	/* upper accented */
+	__ctype_print | __ctype_upper,	/* upper accented */
+	__ctype_print | __ctype_upper,	/* upper accented */
+	__ctype_print | __ctype_upper,	/* upper accented */
+	__ctype_print | __ctype_upper,	/* upper accented */
+	__ctype_print | __ctype_upper,	/* upper accented */
+	__ctype_print | __ctype_punct,	/* punctuation */
+	__ctype_print | __ctype_upper,	/* upper accented */
+	__ctype_print | __ctype_upper,	/* upper accented */
+	__ctype_print | __ctype_upper,	/* upper accented */
+	__ctype_print | __ctype_upper,	/* upper accented */
+	__ctype_print | __ctype_upper,	/* upper accented */
+	__ctype_print | __ctype_upper,	/* upper accented */
+	__ctype_print | __ctype_upper,	/* upper accented */
+	__ctype_print | __ctype_lower,	/* lower accented */
+
+	__ctype_print | __ctype_lower,	/* lower accented */
+	__ctype_print | __ctype_lower,	/* lower accented */
+	__ctype_print | __ctype_lower,	/* lower accented */
+	__ctype_print | __ctype_lower,	/* lower accented */
+	__ctype_print | __ctype_lower,	/* lower accented */
+	__ctype_print | __ctype_lower,	/* lower accented */
+	__ctype_print | __ctype_lower,	/* lower accented */
+	__ctype_print | __ctype_lower,	/* lower accented */
+	__ctype_print | __ctype_lower,	/* lower accented */
+	__ctype_print | __ctype_lower,	/* lower accented */
+	__ctype_print | __ctype_lower,	/* lower accented */
+	__ctype_print | __ctype_lower,	/* lower accented */
+	__ctype_print | __ctype_lower,	/* lower accented */
+	__ctype_print | __ctype_lower,	/* lower accented */
+	__ctype_print | __ctype_lower,	/* lower accented */
+	__ctype_print | __ctype_lower,	/* lower accented */
+
+	__ctype_print | __ctype_lower,	/* lower accented */
+	__ctype_print | __ctype_lower,	/* lower accented */
+	__ctype_print | __ctype_lower,	/* lower accented */
+	__ctype_print | __ctype_lower,	/* lower accented */
+	__ctype_print | __ctype_lower,	/* lower accented */
+	__ctype_print | __ctype_lower,	/* lower accented */
+	__ctype_print | __ctype_lower,	/* lower accented */
+	__ctype_print | __ctype_punct,	/* punctuation */
+	__ctype_print | __ctype_lower,	/* lower accented */
+	__ctype_print | __ctype_lower,	/* lower accented */
+	__ctype_print | __ctype_lower,	/* lower accented */
+	__ctype_print | __ctype_lower,	/* lower accented */
+	__ctype_print | __ctype_lower,	/* lower accented */
+	__ctype_print | __ctype_lower,	/* lower accented */
+	__ctype_print | __ctype_lower,	/* lower accented */
+	__ctype_print | __ctype_lower,	/* lower accented */
+};
diff --git a/usr/klibc/daemon.c b/usr/klibc/daemon.c
new file mode 100644
index 0000000..61b88dd
--- /dev/null
+++ b/usr/klibc/daemon.c
@@ -0,0 +1,35 @@
+/*
+ * daemon.c - "daemonize" a process
+ */
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+
+int daemon(int nochdir, int noclose)
+{
+	int nullfd;
+	pid_t f;
+
+	if (!nochdir) {
+		if (chdir("/"))
+			return -1;
+	}
+
+	if (!noclose) {
+		if ((nullfd = open("/dev/null", O_RDWR)) < 0 ||
+		    dup2(nullfd, 0) < 0 ||
+		    dup2(nullfd, 1) < 0 ||
+		    dup2(nullfd, 2) < 0)
+			return -1;
+		close(nullfd);
+	}
+
+	f = fork();
+	if (f < 0)
+		return -1;
+	else if (f > 0)
+		_exit(0);
+
+	return setsid();
+}
diff --git a/usr/klibc/env.h b/usr/klibc/env.h
new file mode 100644
index 0000000..ae70be8
--- /dev/null
+++ b/usr/klibc/env.h
@@ -0,0 +1,10 @@
+#ifndef ENV_H
+#define ENV_H
+
+/* str should be a duplicated version of the input string;
+   len is the length of the key including the = sign */
+int __put_env(char *str, size_t len, int overwrite);
+
+extern char *const __null_environ[];
+
+#endif
diff --git a/usr/klibc/exec_l.c b/usr/klibc/exec_l.c
new file mode 100644
index 0000000..76b70df
--- /dev/null
+++ b/usr/klibc/exec_l.c
@@ -0,0 +1,59 @@
+/*
+ * exec_l.c
+ *
+ * Common implementation of execl() execle() execlp()
+ */
+
+#include <stdarg.h>
+#include <alloca.h>
+#include <unistd.h>
+
+int NAME(const char *path, const char *arg0, ...)
+{
+	va_list ap, cap;
+	int argc = 1, rv;
+	const char **argv, **argp;
+	const char *arg;
+	char *const *envp;
+
+	va_start(ap, arg0);
+	va_copy(cap, ap);
+
+	/* Count the number of arguments */
+	do {
+		arg = va_arg(cap, const char *);
+		argc++;
+	} while (arg);
+
+	va_end(cap);
+
+	/* Allocate memory for the pointer array */
+	argp = argv = alloca(argc * sizeof(const char *));
+	if (!argv) {
+		va_end(ap);
+		return -1;
+	}
+
+	/* Copy the list into an array */
+	*argp++ = arg0;
+	do {
+		*argp++ = arg = va_arg(ap, const char *);
+	} while (arg);
+
+#if EXEC_E
+	/* execle() takes one more argument for the environment pointer */
+	envp = va_arg(ap, char *const *);
+#else
+	envp = environ;
+#endif
+
+#if EXEC_P
+	rv = execvpe(path, (char * const *)argv, envp);
+#else
+	rv = execve(path, (char * const *)argv, envp);
+#endif
+
+	va_end(ap);
+
+	return rv;
+}
diff --git a/usr/klibc/execl.c b/usr/klibc/execl.c
new file mode 100644
index 0000000..4581113
--- /dev/null
+++ b/usr/klibc/execl.c
@@ -0,0 +1,8 @@
+/*
+ * execl.c
+ */
+
+#define NAME execl
+#define EXEC_P 0
+#define EXEC_E 0
+#include "exec_l.c"
diff --git a/usr/klibc/execle.c b/usr/klibc/execle.c
new file mode 100644
index 0000000..b073988
--- /dev/null
+++ b/usr/klibc/execle.c
@@ -0,0 +1,8 @@
+/*
+ * execle.c
+ */
+
+#define NAME execle
+#define EXEC_P 0
+#define EXEC_E 1
+#include "exec_l.c"
diff --git a/usr/klibc/execlp.c b/usr/klibc/execlp.c
new file mode 100644
index 0000000..65c9aa4
--- /dev/null
+++ b/usr/klibc/execlp.c
@@ -0,0 +1,8 @@
+/*
+ * execlp.c
+ */
+
+#define NAME execlp
+#define EXEC_P 1
+#define EXEC_E 0
+#include "exec_l.c"
diff --git a/usr/klibc/execlpe.c b/usr/klibc/execlpe.c
new file mode 100644
index 0000000..fef972f
--- /dev/null
+++ b/usr/klibc/execlpe.c
@@ -0,0 +1,8 @@
+/*
+ * execlpe.c
+ */
+
+#define NAME execlpe
+#define EXEC_P 1
+#define EXEC_E 1
+#include "exec_l.c"
diff --git a/usr/klibc/execv.c b/usr/klibc/execv.c
new file mode 100644
index 0000000..29e5737
--- /dev/null
+++ b/usr/klibc/execv.c
@@ -0,0 +1,11 @@
+/*
+ * execv.c
+ */
+
+#include <stdarg.h>
+#include <unistd.h>
+
+int execv(const char *path, char *const *argv)
+{
+	return execve(path, argv, environ);
+}
diff --git a/usr/klibc/execvp.c b/usr/klibc/execvp.c
new file mode 100644
index 0000000..5a9f31d
--- /dev/null
+++ b/usr/klibc/execvp.c
@@ -0,0 +1,11 @@
+/*
+ * execvp.c
+ */
+
+#include <stdarg.h>
+#include <unistd.h>
+
+int execvp(const char *path, char *const *argv)
+{
+	return execvpe(path, argv, environ);
+}
diff --git a/usr/klibc/execvpe.c b/usr/klibc/execvpe.c
new file mode 100644
index 0000000..0b844f2
--- /dev/null
+++ b/usr/klibc/execvpe.c
@@ -0,0 +1,75 @@
+/*
+ * execvpe.c
+ *
+ * execvpe() function (from which we build execlp, execlpe, execvp).
+ *
+ * This version of execvpe() will *not* spawn /bin/sh if the command
+ * return ENOEXEC.  That's what #! is for, folks!
+ *
+ * Since execlpe() and execvpe() aren't in POSIX, nor in glibc,
+ * I have followed QNX precedent in the implementation of the PATH:
+ * the PATH that is used is the one in the current environment, not
+ * in the new environment.  Otherwise it would be impossible to pass
+ * a different PATH to the new process than the one one would want to
+ * use to search.
+ */
+
+#include <errno.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <limits.h>
+
+#define DEFAULT_PATH 	"/bin:/usr/bin:."
+
+int execvpe(const char *file, char *const *argv, char *const *envp)
+{
+	char path[PATH_MAX];
+	const char *searchpath, *esp;
+	size_t prefixlen, filelen, totallen;
+
+	if (strchr(file, '/'))	/* Specific path */
+		return execve(file, argv, envp);
+
+	filelen = strlen(file);
+
+	searchpath = getenv("PATH");
+	if (!searchpath)
+		searchpath = DEFAULT_PATH;
+
+	errno = ENOENT;		/* Default errno, if execve() doesn't
+				   change it */
+
+	do {
+		esp = strchr(searchpath, ':');
+		if (esp)
+			prefixlen = esp - searchpath;
+		else
+			prefixlen = strlen(searchpath);
+
+		if (prefixlen == 0 || searchpath[prefixlen - 1] == '/') {
+			totallen = prefixlen + filelen;
+			if (totallen >= PATH_MAX)
+				continue;
+			memcpy(path, searchpath, prefixlen);
+			memcpy(path + prefixlen, file, filelen);
+		} else {
+			totallen = prefixlen + filelen + 1;
+			if (totallen >= PATH_MAX)
+				continue;
+			memcpy(path, searchpath, prefixlen);
+			path[prefixlen] = '/';
+			memcpy(path + prefixlen + 1, file, filelen);
+		}
+		path[totallen] = '\0';
+
+		execve(path, argv, envp);
+		if (errno == E2BIG  || errno == ENOEXEC ||
+		    errno == ENOMEM || errno == ETXTBSY)
+			break;	/* Report this as an error, no more search */
+
+		searchpath = esp + 1;
+	} while (esp);
+
+	return -1;
+}
diff --git a/usr/klibc/exit.c b/usr/klibc/exit.c
new file mode 100644
index 0000000..92f11c5
--- /dev/null
+++ b/usr/klibc/exit.c
@@ -0,0 +1,30 @@
+/*
+ * exit.c
+ *
+ * exit(), including the handling of the atexit chain.
+ */
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/syscall.h>
+#include "atexit.h"
+
+/* Link chain for atexit/on_exit */
+struct atexit *__atexit_list;
+
+__noreturn exit(int rv)
+{
+	struct atexit *ap;
+
+	for (ap = __atexit_list; ap; ap = ap->next) {
+		/* This assumes extra args are harmless.  They should
+		   be in all normal C ABIs, but if an architecture has
+		   some particularly bizarre ABI this might be worth
+		   watching out for. */
+		ap->fctn(rv, ap->arg);
+	}
+
+	/* Handle any library destructors if we ever start using them... */
+
+	_exit(rv);
+}
diff --git a/usr/klibc/fgetc.c b/usr/klibc/fgetc.c
new file mode 100644
index 0000000..9092eae
--- /dev/null
+++ b/usr/klibc/fgetc.c
@@ -0,0 +1,19 @@
+/*
+ * fgetc.c
+ *
+ * Extremely slow fgetc implementation, using _fread().  If people
+ * actually need character-oriented input to be fast, we may actually
+ * have to implement buffering.  Sigh.
+ */
+
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <errno.h>
+
+int fgetc(FILE *f)
+{
+	unsigned char ch;
+
+	return (_fread(&ch, 1, f) == 1) ? (int)ch : EOF;
+}
diff --git a/usr/klibc/fgets.c b/usr/klibc/fgets.c
new file mode 100644
index 0000000..4e9cf68
--- /dev/null
+++ b/usr/klibc/fgets.c
@@ -0,0 +1,31 @@
+/*
+ * fgets.c
+ *
+ * This will be very slow due to the implementation of getc(),
+ * but we don't have anywhere to put characters we don't need from
+ * the input.
+ */
+
+#include <stdio.h>
+
+char *fgets(char *s, int n, FILE *f)
+{
+	int ch;
+	char *p = s;
+
+	while (n > 1) {
+		ch = getc(f);
+		if (ch == EOF) {
+			*p = '\0';
+			return NULL;
+		}
+		*p++ = ch;
+		n--;
+		if (ch == '\n')
+			break;
+	}
+	if (n)
+		*p = '\0';
+
+	return s;
+}
diff --git a/usr/klibc/fnmatch.c b/usr/klibc/fnmatch.c
new file mode 100644
index 0000000..5d0a25f
--- /dev/null
+++ b/usr/klibc/fnmatch.c
@@ -0,0 +1,72 @@
+/*
+ * fnmatch.c
+ *
+ * Original implementation by Kay Sievers, modified by H. Peter Anvin.
+ */
+
+#include <fnmatch.h>
+
+int fnmatch(const char *p, const char *s, int flags)
+{
+	if (flags & FNM_PATHNAME && *s == '/')
+		return (*p != '/') || fnmatch(p+1, s+1, flags);
+	if (flags & FNM_PERIOD && *s == '.')
+		return (*p != '.') || fnmatch(p+1, s+1, flags);
+
+	flags &= ~FNM_PERIOD;	/* Only applies at beginning */
+
+	if (!(flags & FNM_NOESCAPE) && *p == '\\') {
+		p++;
+		return (*p != *s) || fnmatch(p+1, s+1, flags);
+	}
+
+	if (*s == '\0') {
+		while (*p == '*')
+			p++;
+		return (*p != '\0');
+	}
+
+	switch (*p) {
+	case '[':
+		{
+			int not = 0;
+			p++;
+			if (*p == '!') {
+				not = 1;
+				p++;
+			}
+			while ((*p != '\0') && (*p != ']')) {
+				int match = 0;
+				if (p[1] == '-') {
+					if ((*s >= *p) && (*s <= p[2]))
+						match = 1;
+					p += 3;
+				} else {
+					match = (*p == *s);
+					p++;
+				}
+				if (match ^ not) {
+					while ((*p != '\0') && (*p != ']'))
+						p++;
+					if (*p == ']')
+						return fnmatch(p+1, s+1, flags);
+				}
+			}
+		}
+		break;
+	case '*':
+		if (fnmatch(p, s+1, flags))
+			return fnmatch(p+1, s, flags);
+		return 0;
+	case '\0':
+		if (*s == '\0') {
+			return 0;
+		}
+		break;
+	default:
+		if ((*p == *s) || (*p == '?'))
+			return fnmatch(p+1, s+1, flags);
+		break;
+	}
+	return 1;
+}
diff --git a/usr/klibc/fopen.c b/usr/klibc/fopen.c
new file mode 100644
index 0000000..6fa80d7
--- /dev/null
+++ b/usr/klibc/fopen.c
@@ -0,0 +1,39 @@
+/*
+ * 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;
+
+	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;
+		}
+	}
+
+	if (plus) {
+		flags = (flags & ~(O_RDONLY | O_WRONLY)) | O_RDWR;
+	}
+
+	/* Note: __create_file(-1) == NULL, so this is safe */
+	return __create_file(open(file, flags, 0666));
+}
diff --git a/usr/klibc/fork.c b/usr/klibc/fork.c
new file mode 100644
index 0000000..b07486e
--- /dev/null
+++ b/usr/klibc/fork.c
@@ -0,0 +1,21 @@
+/*
+ * fork.c
+ *
+ * This is normally just a syscall stub, but at least one system
+ * doesn't have sys_fork, only sys_clone...
+ */
+
+#include <sys/syscall.h>
+#include <signal.h>
+#include <unistd.h>
+#include <sched.h>
+#include <klibc/sysconfig.h>
+
+#if !_KLIBC_NO_MMU && !defined(__NR_fork)
+
+pid_t fork(void)
+{
+	return __clone(SIGCHLD, 0);
+}
+
+#endif				/* __NR_fork */
diff --git a/usr/klibc/fprintf.c b/usr/klibc/fprintf.c
new file mode 100644
index 0000000..8403923
--- /dev/null
+++ b/usr/klibc/fprintf.c
@@ -0,0 +1,19 @@
+/*
+ * fprintf.c
+ */
+
+#include <stdio.h>
+#include <stdarg.h>
+
+#define BUFFER_SIZE	16384
+
+int fprintf(FILE * file, const char *format, ...)
+{
+	va_list ap;
+	int rv;
+
+	va_start(ap, format);
+	rv = vfprintf(file, format, ap);
+	va_end(ap);
+	return rv;
+}
diff --git a/usr/klibc/fputc.c b/usr/klibc/fputc.c
new file mode 100644
index 0000000..386d86c
--- /dev/null
+++ b/usr/klibc/fputc.c
@@ -0,0 +1,14 @@
+/*
+ * fputc.c
+ *
+ * gcc "printf decompilation" expects this to exist...
+ */
+
+#include <stdio.h>
+
+int fputc(int c, FILE *f)
+{
+	unsigned char ch = c;
+
+	return _fwrite(&ch, 1, f) == 1 ? ch : EOF;
+}
diff --git a/usr/klibc/fputs.c b/usr/klibc/fputs.c
new file mode 100644
index 0000000..fb240d6
--- /dev/null
+++ b/usr/klibc/fputs.c
@@ -0,0 +1,15 @@
+/*
+ * fputs.c
+ *
+ * This isn't quite fputs() in the stdio sense, since we don't
+ * have stdio, but it takes a file descriptor argument instead
+ * of the FILE *.
+ */
+
+#include <stdio.h>
+#include <string.h>
+
+int fputs(const char *s, FILE *file)
+{
+	return _fwrite(s, strlen(s), file);
+}
diff --git a/usr/klibc/fread.c b/usr/klibc/fread.c
new file mode 100644
index 0000000..b9433aa
--- /dev/null
+++ b/usr/klibc/fread.c
@@ -0,0 +1,33 @@
+/*
+ * fread.c
+ */
+
+#include <errno.h>
+#include <unistd.h>
+#include <stdio.h>
+
+size_t _fread(void *buf, size_t count, FILE *f)
+{
+	size_t bytes = 0;
+	ssize_t rv;
+	char *p = buf;
+
+	while (count) {
+		rv = read(fileno(f), p, count);
+		if (rv == -1) {
+			if (errno == EINTR) {
+				errno = 0;
+				continue;
+			} else
+				break;
+		} else if (rv == 0) {
+			break;
+		}
+
+		p += rv;
+		bytes += rv;
+		count -= rv;
+	}
+
+	return bytes;
+}
diff --git a/usr/klibc/fread2.c b/usr/klibc/fread2.c
new file mode 100644
index 0000000..c9c6ed8
--- /dev/null
+++ b/usr/klibc/fread2.c
@@ -0,0 +1,13 @@
+/*
+ * fread2.c
+ *
+ * The actual fread() function as a non-inline
+ */
+
+#define __NO_FREAD_FWRITE_INLINES
+#include <stdio.h>
+
+size_t fread(void *ptr, size_t size, size_t nmemb, FILE * f)
+{
+	return _fread(ptr, size * nmemb, f) / size;
+}
diff --git a/usr/klibc/fstatfs.c b/usr/klibc/fstatfs.c
new file mode 100644
index 0000000..614f2ec
--- /dev/null
+++ b/usr/klibc/fstatfs.c
@@ -0,0 +1,19 @@
+/*
+ * fstatfs.c
+ *
+ * On architectures which do fstatfs64, wrap the system call
+ */
+
+#include <sys/syscall.h>
+#include <sys/vfs.h>
+
+#ifdef __NR_fstatfs64
+
+extern int __fstatfs64(int, size_t, struct statfs *);
+
+int fstatfs(int fd, struct statfs *buf)
+{
+	return __fstatfs64(fd, sizeof *buf, buf);
+}
+
+#endif
diff --git a/usr/klibc/fwrite.c b/usr/klibc/fwrite.c
new file mode 100644
index 0000000..cba8de8
--- /dev/null
+++ b/usr/klibc/fwrite.c
@@ -0,0 +1,33 @@
+/*
+ * fwrite.c
+ */
+
+#include <errno.h>
+#include <unistd.h>
+#include <stdio.h>
+
+size_t _fwrite(const void *buf, size_t count, FILE *f)
+{
+	size_t bytes = 0;
+	ssize_t rv;
+	const char *p = buf;
+
+	while (count) {
+		rv = write(fileno(f), p, count);
+		if (rv == -1) {
+			if (errno == EINTR) {
+				errno = 0;
+				continue;
+			} else
+				break;
+		} else if (rv == 0) {
+			break;
+		}
+
+		p += rv;
+		bytes += rv;
+		count -= rv;
+	}
+
+	return bytes;
+}
diff --git a/usr/klibc/fwrite2.c b/usr/klibc/fwrite2.c
new file mode 100644
index 0000000..b5ab0a4
--- /dev/null
+++ b/usr/klibc/fwrite2.c
@@ -0,0 +1,13 @@
+/*
+ * fwrite2.c
+ *
+ * The actual fwrite() function as a non-inline
+ */
+
+#define __NO_FREAD_FWRITE_INLINES
+#include <stdio.h>
+
+size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE * f)
+{
+	return _fwrite(ptr, size * nmemb, f) / size;
+}
diff --git a/usr/klibc/getcwd.c b/usr/klibc/getcwd.c
new file mode 100644
index 0000000..22ec812
--- /dev/null
+++ b/usr/klibc/getcwd.c
@@ -0,0 +1,15 @@
+/*
+ * getcwd.c
+ *
+ * The system call behaves differently than the library function.
+ */
+
+#include <unistd.h>
+#include <sys/syscall.h>
+
+extern int __getcwd(char *buf, size_t size);
+
+char *getcwd(char *buf, size_t size)
+{
+	return (__getcwd(buf, size) < 0) ? NULL : buf;
+}
diff --git a/usr/klibc/getdomainname.c b/usr/klibc/getdomainname.c
new file mode 100644
index 0000000..61722ca
--- /dev/null
+++ b/usr/klibc/getdomainname.c
@@ -0,0 +1,25 @@
+/*
+ * getdomainname.c
+ */
+
+#include <errno.h>
+#include <unistd.h>
+#include <string.h>
+#include <sys/utsname.h>
+
+int getdomainname(char *name, size_t len)
+{
+	struct utsname un;
+
+	if (!uname(&un))
+		return -1;
+
+	if (len < strlen(un.domainname) + 1) {
+		errno = EINVAL;
+		return -1;
+	}
+
+	strcpy(name, un.domainname);
+
+	return 0;
+}
diff --git a/usr/klibc/getenv.c b/usr/klibc/getenv.c
new file mode 100644
index 0000000..3a4ae5e
--- /dev/null
+++ b/usr/klibc/getenv.c
@@ -0,0 +1,24 @@
+/*
+ * getenv.c
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+char *getenv(const char *name)
+{
+	char **p, *q;
+	int len = strlen(name);
+
+	if (!environ)
+		return NULL;
+
+	for (p = environ; (q = *p); p++) {
+		if (!strncmp(name, q, len) && q[len] == '=') {
+			return q + (len + 1);
+		}
+	}
+
+	return NULL;
+}
diff --git a/usr/klibc/gethostname.c b/usr/klibc/gethostname.c
new file mode 100644
index 0000000..5326b5f
--- /dev/null
+++ b/usr/klibc/gethostname.c
@@ -0,0 +1,25 @@
+/*
+ * gethostname.c
+ */
+
+#include <errno.h>
+#include <unistd.h>
+#include <string.h>
+#include <sys/utsname.h>
+
+int gethostname(char *name, size_t len)
+{
+	struct utsname un;
+
+	if (!uname(&un))
+		return -1;
+
+	if (len < strlen(un.nodename) + 1) {
+		errno = EINVAL;
+		return -1;
+	}
+
+	strcpy(name, un.nodename);
+
+	return 0;
+}
diff --git a/usr/klibc/getopt.c b/usr/klibc/getopt.c
new file mode 100644
index 0000000..806735d
--- /dev/null
+++ b/usr/klibc/getopt.c
@@ -0,0 +1,97 @@
+/*
+ * getopt.c
+ *
+ * Simple POSIX getopt(), no GNU extensions...
+ */
+
+#include <stdint.h>
+#include <unistd.h>
+#include <string.h>
+
+char *optarg;
+int optind, opterr, optopt;
+static struct getopt_private_state {
+	const char *optptr;
+	const char *last_optstring;
+	char *const *last_argv;
+} pvt;
+
+int getopt(int argc, char *const *argv, const char *optstring)
+{
+	const char *carg;
+	const char *osptr;
+	int opt;
+
+	/* getopt() relies on a number of different global state
+	   variables, which can make this really confusing if there is
+	   more than one use of getopt() in the same program.  This
+	   attempts to detect that situation by detecting if the
+	   "optstring" or "argv" argument have changed since last time
+	   we were called; if so, reinitialize the query state. */
+
+	if (optstring != pvt.last_optstring || argv != pvt.last_argv ||
+	    optind < 1 || optind > argc) {
+		/* optind doesn't match the current query */
+		pvt.last_optstring = optstring;
+		pvt.last_argv = argv;
+		optind = 1;
+		pvt.optptr = NULL;
+	}
+
+	carg = argv[optind];
+
+	/* First, eliminate all non-option cases */
+
+	if (!carg || carg[0] != '-' || !carg[1]) {
+		return -1;
+	}
+
+	if (carg[1] == '-' && !carg[2]) {
+		optind++;
+		return -1;
+	}
+
+	if ((uintptr_t) (pvt.optptr - carg) > (uintptr_t) strlen(carg)) {
+		/* Someone frobbed optind, change to new opt. */
+		pvt.optptr = carg + 1;
+	}
+
+	opt = *pvt.optptr++;
+
+	if (opt != ':' && (osptr = strchr(optstring, opt))) {
+		if (osptr[1] == ':') {
+			if (*pvt.optptr) {
+				/* Argument-taking option with attached
+				   argument */
+				optarg = (char *)pvt.optptr;
+				optind++;
+			} else {
+				/* Argument-taking option with non-attached
+				   argument */
+				if (argv[optind + 1]) {
+					optarg = (char *)argv[optind+1];
+					optind += 2;
+				} else {
+					/* Missing argument */
+					optind++;
+					return (optstring[0] == ':')
+						? ':' : '?';
+				}
+			}
+			return opt;
+		} else {
+			/* Non-argument-taking option */
+			/* pvt.optptr will remember the exact position to
+			   resume at */
+			if (!*pvt.optptr)
+				optind++;
+			return opt;
+		}
+	} else {
+		/* Unknown option */
+		optopt = opt;
+		if (!*pvt.optptr)
+			optind++;
+		return '?';
+	}
+}
diff --git a/usr/klibc/getopt_long.c b/usr/klibc/getopt_long.c
new file mode 100644
index 0000000..e3d064b
--- /dev/null
+++ b/usr/klibc/getopt_long.c
@@ -0,0 +1,152 @@
+/*
+ * getopt.c
+ *
+ * getopt_long(), or at least a common subset thereof:
+ *
+ * - Option reordering is not supported
+ * - -W foo is not supported
+ * - First optstring character "-" not supported.
+ */
+
+#include <stdint.h>
+#include <unistd.h>
+#include <string.h>
+#include <getopt.h>
+
+char *optarg;
+int optind, opterr, optopt;
+static struct getopt_private_state {
+	const char *optptr;
+	const char *last_optstring;
+	char *const *last_argv;
+} pvt;
+
+static inline const char *option_matches(const char *arg_str,
+					 const char *opt_name)
+{
+	while (*arg_str != '\0' && *arg_str != '=') {
+		if (*arg_str++ != *opt_name++)
+			return NULL;
+	}
+
+	if (*opt_name)
+		return NULL;
+
+	return arg_str;
+}
+
+int getopt_long(int argc, char *const *argv, const char *optstring,
+		const struct option *longopts, int *longindex)
+{
+	const char *carg;
+	const char *osptr;
+	int opt;
+
+	/* getopt() relies on a number of different global state
+	   variables, which can make this really confusing if there is
+	   more than one use of getopt() in the same program.  This
+	   attempts to detect that situation by detecting if the
+	   "optstring" or "argv" argument have changed since last time
+	   we were called; if so, reinitialize the query state. */
+
+	if (optstring != pvt.last_optstring || argv != pvt.last_argv ||
+	    optind < 1 || optind > argc) {
+		/* optind doesn't match the current query */
+		pvt.last_optstring = optstring;
+		pvt.last_argv = argv;
+		optind = 1;
+		pvt.optptr = NULL;
+	}
+
+	carg = argv[optind];
+
+	/* First, eliminate all non-option cases */
+
+	if (!carg || carg[0] != '-' || !carg[1])
+		return -1;
+
+	if (carg[1] == '-') {
+		const struct option *lo;
+		const char *opt_end = NULL;
+
+		optind++;
+
+		/* Either it's a long option, or it's -- */
+		if (!carg[2]) {
+			/* It's -- */
+			return -1;
+		}
+
+		for (lo = longopts; lo->name; lo++) {
+			if ((opt_end = option_matches(carg+2, lo->name)))
+			    break;
+		}
+		if (!opt_end)
+			return '?';
+
+		if (longindex)
+			*longindex = lo-longopts;
+
+		if (*opt_end == '=') {
+			if (lo->has_arg)
+				optarg = (char *)opt_end+1;
+			else
+				return '?';
+		} else if (lo->has_arg == 1) {
+			if (!(optarg = argv[optind]))
+				return '?';
+			optind++;
+		}
+
+		if (lo->flag) {
+			*lo->flag = lo->val;
+			return 0;
+		} else {
+			return lo->val;
+		}
+	}
+
+	if ((uintptr_t) (pvt.optptr - carg) > (uintptr_t) strlen(carg)) {
+		/* Someone frobbed optind, change to new opt. */
+		pvt.optptr = carg + 1;
+	}
+
+	opt = *pvt.optptr++;
+
+	if (opt != ':' && (osptr = strchr(optstring, opt))) {
+		if (osptr[1] == ':') {
+			if (*pvt.optptr) {
+				/* Argument-taking option with attached
+				   argument */
+				optarg = (char *)pvt.optptr;
+				optind++;
+			} else {
+				/* Argument-taking option with non-attached
+				   argument */
+				if (argv[optind + 1]) {
+					optarg = (char *)argv[optind+1];
+					optind += 2;
+				} else {
+					/* Missing argument */
+					optind++;
+					return (optstring[0] == ':')
+						? ':' : '?';
+				}
+			}
+			return opt;
+		} else {
+			/* Non-argument-taking option */
+			/* pvt.optptr will remember the exact position to
+			   resume at */
+			if (!*pvt.optptr)
+				optind++;
+			return opt;
+		}
+	} else {
+		/* Unknown option */
+		optopt = opt;
+		if (!*pvt.optptr)
+			optind++;
+		return '?';
+	}
+}
diff --git a/usr/klibc/getpgrp.c b/usr/klibc/getpgrp.c
new file mode 100644
index 0000000..b20b17a
--- /dev/null
+++ b/usr/klibc/getpgrp.c
@@ -0,0 +1,10 @@
+/*
+ * getpgrp.c
+ */
+
+#include <unistd.h>
+
+pid_t getpgrp(void)
+{
+	return getpgid(0);
+}
diff --git a/usr/klibc/getpriority.c b/usr/klibc/getpriority.c
new file mode 100644
index 0000000..01d6e06
--- /dev/null
+++ b/usr/klibc/getpriority.c
@@ -0,0 +1,23 @@
+/*
+ * getpriority.c
+ *
+ * Needs to do some post-syscall mangling to distinguish error returns...
+ * but only on some platforms.  Sigh.
+ */
+
+#include <unistd.h>
+#include <sys/time.h>
+#include <sys/resource.h>
+#include <sys/syscall.h>
+
+#if !defined(__alpha__) && !defined(__ia64__)
+
+extern int __getpriority(int, int);
+
+int getpriority(int which, int who)
+{
+	int rv = __getpriority(which, who);
+	return (rv < 0) ? rv : 20-rv;
+}
+
+#endif
diff --git a/usr/klibc/getpt.c b/usr/klibc/getpt.c
new file mode 100644
index 0000000..76ca371
--- /dev/null
+++ b/usr/klibc/getpt.c
@@ -0,0 +1,17 @@
+/*
+ * getpt.c
+ *
+ * GNU extension to the standard Unix98 pty suite
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <termios.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+
+int getpt(void)
+{
+	return open("/dev/ptmx", O_RDWR | O_NOCTTY);
+}
diff --git a/usr/klibc/globals.c b/usr/klibc/globals.c
new file mode 100644
index 0000000..72ae91f
--- /dev/null
+++ b/usr/klibc/globals.c
@@ -0,0 +1,10 @@
+/*
+ * globals.c
+ *
+ * These have to be defined somewhere...
+ */
+#include <errno.h>
+#include <unistd.h>
+
+int errno;
+char **environ;
diff --git a/usr/klibc/inet/bindresvport.c b/usr/klibc/inet/bindresvport.c
new file mode 100644
index 0000000..e22c1c2
--- /dev/null
+++ b/usr/klibc/inet/bindresvport.c
@@ -0,0 +1,46 @@
+/*
+ * inet/bindresvport.c
+ */
+
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <string.h>
+#include <unistd.h>
+
+#define START_PORT	768
+#define END_PORT	IPPORT_RESERVED
+#define NUM_PORTS	(END_PORT - START_PORT)
+
+int bindresvport(int sd, struct sockaddr_in *sin)
+{
+	struct sockaddr_in me;
+	static short port;
+	int ret = 0;
+	int i;
+
+	if (sin == NULL) {
+		memset(&me, 0, sizeof(me));
+		sin = &me;
+		sin->sin_family = AF_INET;
+	} else if (sin->sin_family != AF_INET) {
+		errno = EPFNOSUPPORT;
+		return -1;
+	}
+
+	if (port == 0)
+		port = START_PORT + (getpid() % NUM_PORTS);
+
+	for (i = 0; i < NUM_PORTS; i++, port++) {
+		if (port == END_PORT)
+			port = START_PORT;
+		sin->sin_port = htons(port);
+
+		ret = bind(sd, (struct sockaddr *)sin, sizeof(*sin));
+		if (ret != -1)
+			break;
+	}
+
+	return ret;
+}
diff --git a/usr/klibc/inet/inet_addr.c b/usr/klibc/inet/inet_addr.c
new file mode 100644
index 0000000..2ef4535
--- /dev/null
+++ b/usr/klibc/inet/inet_addr.c
@@ -0,0 +1,14 @@
+/*
+ * inet/inet_addr.c
+ */
+
+#include <arpa/inet.h>
+#include <stdio.h>
+
+uint32_t inet_addr(const char *str)
+{
+	struct in_addr a;
+	int rv = inet_aton(str, &a);
+
+	return rv ? INADDR_NONE : a.s_addr;
+}
diff --git a/usr/klibc/inet/inet_aton.c b/usr/klibc/inet/inet_aton.c
new file mode 100644
index 0000000..beceeea
--- /dev/null
+++ b/usr/klibc/inet/inet_aton.c
@@ -0,0 +1,22 @@
+/*
+ * inet/inet_aton.c
+ */
+
+#include <arpa/inet.h>
+#include <stdio.h>
+
+int inet_aton(const char *str, struct in_addr *addr)
+{
+	union {
+		uint8_t	 b[4];
+		uint32_t l;
+	} a;
+
+	if (sscanf(str, "%hhu.%hhu.%hhu.%hhu",
+		   &a.b[0], &a.b[1], &a.b[2], &a.b[3]) == 4) {
+		addr->s_addr = a.l;	/* Always in network byte order */
+		return 1;
+	} else {
+		return 0;
+	}
+}
diff --git a/usr/klibc/inet/inet_ntoa.c b/usr/klibc/inet/inet_ntoa.c
new file mode 100644
index 0000000..6dbf057
--- /dev/null
+++ b/usr/klibc/inet/inet_ntoa.c
@@ -0,0 +1,16 @@
+/*
+ * inet/inet_ntoa.c
+ */
+
+#include <stdint.h>
+#include <arpa/inet.h>
+#include <stdio.h>
+
+char *inet_ntoa(struct in_addr addr)
+{
+	static char name[16];
+	const uint8_t *cp = (const uint8_t *) &addr.s_addr;
+
+	sprintf(name, "%u.%u.%u.%u", cp[0], cp[1], cp[2], cp[3]);
+	return name;
+}
diff --git a/usr/klibc/inet/inet_ntop.c b/usr/klibc/inet/inet_ntop.c
new file mode 100644
index 0000000..106fb45
--- /dev/null
+++ b/usr/klibc/inet/inet_ntop.c
@@ -0,0 +1,54 @@
+/*
+ * inet/inet_ntop.c
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <sys/socket.h>
+#include <arpa/inet.h>
+#include <netinet/in6.h>
+
+const char *inet_ntop(int af, const void *cp, char *buf, size_t len)
+{
+	size_t xlen;
+
+	switch (af) {
+	case AF_INET:
+		{
+			const uint8_t *bp = (const uint8_t *)
+				&((const struct in_addr *)cp)->s_addr;
+
+			xlen = snprintf(buf, len, "%u.%u.%u.%u",
+					bp[0], bp[1], bp[2], bp[3]);
+		}
+		break;
+
+	case AF_INET6:
+		{
+			const struct in6_addr *s = (const struct in6_addr *)cp;
+
+			xlen = snprintf(buf, len, "%x:%x:%x:%x:%x:%x:%x:%x",
+					ntohs(s->s6_addr16[0]),
+					ntohs(s->s6_addr16[1]),
+					ntohs(s->s6_addr16[2]),
+					ntohs(s->s6_addr16[3]),
+					ntohs(s->s6_addr16[4]),
+					ntohs(s->s6_addr16[5]),
+					ntohs(s->s6_addr16[6]),
+					ntohs(s->s6_addr16[7]));
+		}
+		break;
+
+	default:
+		errno = EAFNOSUPPORT;
+		return NULL;
+	}
+
+	if (xlen > len) {
+		errno = ENOSPC;
+		return NULL;
+	}
+
+	return buf;
+}
diff --git a/usr/klibc/inet/inet_pton.c b/usr/klibc/inet/inet_pton.c
new file mode 100644
index 0000000..19fe16e
--- /dev/null
+++ b/usr/klibc/inet/inet_pton.c
@@ -0,0 +1,78 @@
+/*
+ * inet/inet_pton.c
+ */
+
+#include <stdio.h>
+#include <stdint.h>
+#include <errno.h>
+#include <ctype.h>
+#include <string.h>
+#include <arpa/inet.h>
+#include <netinet/in6.h>
+
+static inline int hexval(int ch)
+{
+	if (ch >= '0' && ch <= '9') {
+		return ch - '0';
+	} else if (ch >= 'A' && ch <= 'F') {
+		return ch - 'A' + 10;
+	} else if (ch >= 'a' && ch <= 'f') {
+		return ch - 'a' + 10;
+	} else {
+		return -1;
+	}
+}
+
+int inet_pton(int af, const char *src, void *dst)
+{
+	switch (af) {
+	case AF_INET:
+		return inet_aton(src, (struct in_addr *)dst);
+
+	case AF_INET6:
+		{
+			struct in6_addr *d = (struct in6_addr *)dst;
+			int colons = 0, dcolons = 0;
+			int i;
+			const char *p;
+
+			/* A double colon will increment colons by 2,
+			   dcolons by 1 */
+			for (p = dst; *p; p++) {
+				if (p[0] == ':') {
+					colons++;
+					if (p[1] == ':')
+						dcolons++;
+				} else if (!isxdigit(*p))
+					return 0;	/* Invalid address */
+			}
+
+			if (colons > 7 || dcolons > 1
+			    || (!dcolons && colons != 7))
+				return 0;	/* Invalid address */
+
+			memset(d, 0, sizeof(struct in6_addr));
+
+			i = 0;
+			for (p = dst; *p; p++) {
+				if (*p == ':') {
+					if (p[1] == ':') {
+						i += (8 - colons);
+					} else {
+						i++;
+					}
+				} else {
+					d->s6_addr16[i] =
+					    htons((ntohs(d->s6_addr16[i]) << 4)
+						  + hexval(*p));
+				}
+			}
+
+			return 1;
+		}
+
+	default:
+		errno = EAFNOSUPPORT;
+		return -1;
+	}
+}
diff --git a/usr/klibc/interp.S b/usr/klibc/interp.S
new file mode 100644
index 0000000..4b15cfb
--- /dev/null
+++ b/usr/klibc/interp.S
@@ -0,0 +1,13 @@
+#
+# This is a hack to generate the .intrp section, which then
+# ld turns into an PT_INTERP header.
+#
+# NOTE: The .interp section needs to be "a", or it doesnt work...
+#
+
+        .section ".interp","a"
+        .ascii LIBDIR
+	.ascii "/klibc-"
+        .ascii SOHASH
+        .ascii ".so"
+        .byte 0
diff --git a/usr/klibc/isatty.c b/usr/klibc/isatty.c
new file mode 100644
index 0000000..b4a84b7
--- /dev/null
+++ b/usr/klibc/isatty.c
@@ -0,0 +1,20 @@
+/*
+ * isatty.c
+ */
+
+#include <unistd.h>
+#include <termios.h>
+#include <errno.h>
+
+int isatty(int fd)
+{
+	int old_errno = errno;
+	int istty;
+	pid_t dummy;
+
+	/* All ttys support TIOCGPGRP */
+	istty = !ioctl(fd, TIOCGPGRP, &dummy);
+	errno = old_errno;
+
+	return istty;
+}
diff --git a/usr/klibc/jrand48.c b/usr/klibc/jrand48.c
new file mode 100644
index 0000000..8e2b3ac
--- /dev/null
+++ b/usr/klibc/jrand48.c
@@ -0,0 +1,24 @@
+/*
+ * jrand48.c
+ */
+
+#include <stdlib.h>
+#include <stdint.h>
+
+long jrand48(unsigned short xsubi[3])
+{
+	uint64_t x;
+
+	/* The xsubi[] array is littleendian by spec */
+	x = (uint64_t) (uint16_t) xsubi[0] +
+	    ((uint64_t) (uint16_t) xsubi[1] << 16) +
+	    ((uint64_t) (uint16_t) xsubi[2] << 32);
+
+	x = (0x5deece66dULL * x) + 0xb;
+
+	xsubi[0] = (unsigned short)(uint16_t) x;
+	xsubi[1] = (unsigned short)(uint16_t) (x >> 16);
+	xsubi[2] = (unsigned short)(uint16_t) (x >> 32);
+
+	return (long)(int32_t) (x >> 16);
+}
diff --git a/usr/klibc/libc_init.c b/usr/klibc/libc_init.c
new file mode 100644
index 0000000..55460ce
--- /dev/null
+++ b/usr/klibc/libc_init.c
@@ -0,0 +1,107 @@
+/*
+ * libc_init.c
+ *
+ * This function takes the raw data block set up by the ELF loader
+ * in the kernel and parses it.  It is invoked by crt0.S which makes
+ * any necessary adjustments and passes calls this function using
+ * the standard C calling convention.
+ *
+ * The arguments are:
+ *  uintptr_t *elfdata	 -- The ELF loader data block; usually from the stack.
+ *                          Basically a pointer to argc.
+ *  void (*onexit)(void) -- Function to install into onexit
+ */
+
+/*
+ * Several Linux ABIs don't pass the onexit pointer, and the ones that
+ * do never use it.  Therefore, unless USE_ONEXIT is defined, we just
+ * ignore the onexit pointer.
+ */
+/* #define USE_ONEXIT */
+
+#include <stddef.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <klibc/compiler.h>
+#include <elf.h>
+#include "atexit.h"
+
+/* This file is included from __static_init.c or __shared_init.c */
+#ifndef SHARED
+# error "SHARED should be defined to 0 or 1"
+#endif
+
+char **environ;
+unsigned int __page_size, __page_shift;
+
+struct auxentry {
+	uintptr_t type;
+	uintptr_t v;
+};
+
+__noreturn __libc_init(uintptr_t * elfdata, void (*onexit) (void))
+{
+	int argc;
+	char **argv, **envp, **envend;
+	struct auxentry *auxentry;
+#if SHARED
+	typedef int (*main_t) (int, char **, char **);
+	main_t MAIN = NULL;
+#else
+	extern int main(int, char **, char **);
+#define MAIN main
+#endif
+	unsigned int page_size = 0, page_shift = 0;
+
+#ifdef USE_ONEXIT
+	if (onexit) {
+		static struct atexit at_exit;
+
+		at_exit.fctn = (void (*)(int, void *))onexit;
+		/* at_exit.next = NULL already */
+		__atexit_list = &at_exit;
+	}
+#else
+	(void)onexit;		/* Ignore this... */
+#endif
+
+	argc = (int)*elfdata++;
+	argv = (char **)elfdata;
+	envp = argv + (argc + 1);
+
+	/* The auxillary entry vector is after all the environment vars */
+	for (envend = envp; *envend; envend++) ;
+	auxentry = (struct auxentry *)(envend + 1);
+
+	while (auxentry->type) {
+		switch (auxentry->type) {
+#if SHARED
+		case AT_ENTRY:
+			MAIN = (main_t) (auxentry->v);
+			break;
+#endif
+		case AT_PAGESZ:
+			page_size = (unsigned int)(auxentry->v);
+			break;
+		}
+		auxentry++;
+	}
+
+	__page_size = page_size;
+
+#if __GNUC__ >= 4
+	/* unsigned int is 32 bits on all our architectures */
+	page_shift = __builtin_clz(page_size) ^ 31;
+#elif defined(__i386__) || defined(__x86_64__)
+      asm("bsrl %1,%0": "=r"(page_shift):"r"(page_size));
+#else
+	while (page_size > 1) {
+		page_shift++;
+		page_size >>= 1;
+	}
+#endif
+	__page_shift = page_shift;
+
+	environ = envp;
+	exit(MAIN(argc, argv, envp));
+}
diff --git a/usr/klibc/libgcc/__ashldi3.c b/usr/klibc/libgcc/__ashldi3.c
new file mode 100644
index 0000000..95937f0
--- /dev/null
+++ b/usr/klibc/libgcc/__ashldi3.c
@@ -0,0 +1,23 @@
+/*
+ * libgcc/__ashldi3.c
+ */
+
+#include <stdint.h>
+#include <stddef.h>
+
+uint64_t __ashldi3(uint64_t v, int cnt)
+{
+	int c = cnt & 31;
+	uint32_t vl = (uint32_t) v;
+	uint32_t vh = (uint32_t) (v >> 32);
+
+	if (cnt & 32) {
+		vh = (vl << c);
+		vl = 0;
+	} else {
+		vh = (vh << c) + (vl >> (32 - c));
+		vl = (vl << c);
+	}
+
+	return ((uint64_t) vh << 32) + vl;
+}
diff --git a/usr/klibc/libgcc/__ashrdi3.c b/usr/klibc/libgcc/__ashrdi3.c
new file mode 100644
index 0000000..14e6d18
--- /dev/null
+++ b/usr/klibc/libgcc/__ashrdi3.c
@@ -0,0 +1,23 @@
+/*
+ * libgcc/__ashrdi3.c
+ */
+
+#include <stdint.h>
+#include <stddef.h>
+
+uint64_t __ashrdi3(uint64_t v, int cnt)
+{
+	int c = cnt & 31;
+	uint32_t vl = (uint32_t) v;
+	uint32_t vh = (uint32_t) (v >> 32);
+
+	if (cnt & 32) {
+		vl = ((int32_t) vh >> c);
+		vh = (int32_t) vh >> 31;
+	} else {
+		vl = (vl >> c) + (vh << (32 - c));
+		vh = ((int32_t) vh >> c);
+	}
+
+	return ((uint64_t) vh << 32) + vl;
+}
diff --git a/usr/klibc/libgcc/__clzsi2.c b/usr/klibc/libgcc/__clzsi2.c
new file mode 100644
index 0000000..ebb11f0
--- /dev/null
+++ b/usr/klibc/libgcc/__clzsi2.c
@@ -0,0 +1,36 @@
+/*
+ * libgcc/__clzsi2.c
+ *
+ * Returns the leading number of 0 bits in the argument
+ */
+
+#include <stdint.h>
+#include <stddef.h>
+
+uint32_t __clzsi2(uint32_t v)
+{
+	int p = 31;
+
+	if (v & 0xffff0000) {
+		p -= 16;
+		v >>= 16;
+	}
+	if (v & 0xff00) {
+		p -= 8;
+		v >>= 8;
+	}
+	if (v & 0xf0) {
+		p -= 4;
+		v >>= 4;
+	}
+	if (v & 0xc) {
+		p -= 2;
+		v >>= 2;
+	}
+	if (v & 0x2) {
+		p -= 1;
+		v >>= 1;
+	}
+
+	return p;
+}
diff --git a/usr/klibc/libgcc/__divdi3.c b/usr/klibc/libgcc/__divdi3.c
new file mode 100644
index 0000000..973fe63
--- /dev/null
+++ b/usr/klibc/libgcc/__divdi3.c
@@ -0,0 +1,29 @@
+/*
+ * arch/i386/libgcc/__divdi3.c
+ */
+
+#include <stdint.h>
+#include <stddef.h>
+
+extern uint64_t __udivmoddi4(uint64_t num, uint64_t den, uint64_t * rem);
+
+int64_t __divdi3(int64_t num, int64_t den)
+{
+	int minus = 0;
+	int64_t v;
+
+	if (num < 0) {
+		num = -num;
+		minus = 1;
+	}
+	if (den < 0) {
+		den = -den;
+		minus ^= 1;
+	}
+
+	v = __udivmoddi4(num, den, NULL);
+	if (minus)
+		v = -v;
+
+	return v;
+}
diff --git a/usr/klibc/libgcc/__divsi3.c b/usr/klibc/libgcc/__divsi3.c
new file mode 100644
index 0000000..35420f5
--- /dev/null
+++ b/usr/klibc/libgcc/__divsi3.c
@@ -0,0 +1,29 @@
+/*
+ * libgcc/__divsi3.c
+ */
+
+#include <stdint.h>
+#include <stddef.h>
+
+extern uint32_t __udivmodsi4(uint32_t num, uint32_t den, uint32_t * rem);
+
+int32_t __divsi3(int32_t num, int32_t den)
+{
+	int minus = 0;
+	int32_t v;
+
+	if (num < 0) {
+		num = -num;
+		minus = 1;
+	}
+	if (den < 0) {
+		den = -den;
+		minus ^= 1;
+	}
+
+	v = __udivmodsi4(num, den, NULL);
+	if (minus)
+		v = -v;
+
+	return v;
+}
diff --git a/usr/klibc/libgcc/__lshrdi3.c b/usr/klibc/libgcc/__lshrdi3.c
new file mode 100644
index 0000000..765e1f2
--- /dev/null
+++ b/usr/klibc/libgcc/__lshrdi3.c
@@ -0,0 +1,23 @@
+/*
+ * libgcc/__lshrdi3.c
+ */
+
+#include <stdint.h>
+#include <stddef.h>
+
+uint64_t __lshrdi3(uint64_t v, int cnt)
+{
+	int c = cnt & 31;
+	uint32_t vl = (uint32_t) v;
+	uint32_t vh = (uint32_t) (v >> 32);
+
+	if (cnt & 32) {
+		vl = (vh >> c);
+		vh = 0;
+	} else {
+		vl = (vl >> c) + (vh << (32 - c));
+		vh = (vh >> c);
+	}
+
+	return ((uint64_t) vh << 32) + vl;
+}
diff --git a/usr/klibc/libgcc/__moddi3.c b/usr/klibc/libgcc/__moddi3.c
new file mode 100644
index 0000000..0e7ed98
--- /dev/null
+++ b/usr/klibc/libgcc/__moddi3.c
@@ -0,0 +1,29 @@
+/*
+ * arch/i386/libgcc/__moddi3.c
+ */
+
+#include <stdint.h>
+#include <stddef.h>
+
+extern uint64_t __udivmoddi4(uint64_t num, uint64_t den, uint64_t * rem);
+
+int64_t __moddi3(int64_t num, int64_t den)
+{
+	int minus = 0;
+	int64_t v;
+
+	if (num < 0) {
+		num = -num;
+		minus = 1;
+	}
+	if (den < 0) {
+		den = -den;
+		minus ^= 1;
+	}
+
+	(void)__udivmoddi4(num, den, (uint64_t *) & v);
+	if (minus)
+		v = -v;
+
+	return v;
+}
diff --git a/usr/klibc/libgcc/__modsi3.c b/usr/klibc/libgcc/__modsi3.c
new file mode 100644
index 0000000..33a21ba
--- /dev/null
+++ b/usr/klibc/libgcc/__modsi3.c
@@ -0,0 +1,29 @@
+/*
+ * libgcc/__modsi3.c
+ */
+
+#include <stdint.h>
+#include <stddef.h>
+
+extern uint32_t __udivmodsi4(uint32_t num, uint32_t den, uint32_t * rem);
+
+int32_t __modsi3(int32_t num, int32_t den)
+{
+	int minus = 0;
+	int32_t v;
+
+	if (num < 0) {
+		num = -num;
+		minus = 1;
+	}
+	if (den < 0) {
+		den = -den;
+		minus ^= 1;
+	}
+
+	(void)__udivmodsi4(num, den, (uint32_t *) & v);
+	if (minus)
+		v = -v;
+
+	return v;
+}
diff --git a/usr/klibc/libgcc/__udivdi3.c b/usr/klibc/libgcc/__udivdi3.c
new file mode 100644
index 0000000..5eea461
--- /dev/null
+++ b/usr/klibc/libgcc/__udivdi3.c
@@ -0,0 +1,13 @@
+/*
+ * arch/i386/libgcc/__divdi3.c
+ */
+
+#include <stdint.h>
+#include <stddef.h>
+
+extern uint64_t __udivmoddi4(uint64_t num, uint64_t den, uint64_t * rem);
+
+uint64_t __udivdi3(uint64_t num, uint64_t den)
+{
+	return __udivmoddi4(num, den, NULL);
+}
diff --git a/usr/klibc/libgcc/__udivmoddi4.c b/usr/klibc/libgcc/__udivmoddi4.c
new file mode 100644
index 0000000..aa86112
--- /dev/null
+++ b/usr/klibc/libgcc/__udivmoddi4.c
@@ -0,0 +1,32 @@
+#include <klibc/diverr.h>
+#include <stdint.h>
+
+uint64_t __udivmoddi4(uint64_t num, uint64_t den, uint64_t * rem_p)
+{
+	uint64_t quot = 0, qbit = 1;
+
+	if (den == 0) {
+		__divide_error();
+		return 0;	/* If trap returns... */
+	}
+
+	/* Left-justify denominator and count shift */
+	while ((int64_t) den >= 0) {
+		den <<= 1;
+		qbit <<= 1;
+	}
+
+	while (qbit) {
+		if (den <= num) {
+			num -= den;
+			quot += qbit;
+		}
+		den >>= 1;
+		qbit >>= 1;
+	}
+
+	if (rem_p)
+		*rem_p = num;
+
+	return quot;
+}
diff --git a/usr/klibc/libgcc/__udivmodsi4.c b/usr/klibc/libgcc/__udivmodsi4.c
new file mode 100644
index 0000000..54980f0
--- /dev/null
+++ b/usr/klibc/libgcc/__udivmodsi4.c
@@ -0,0 +1,32 @@
+#include <klibc/diverr.h>
+#include <stdint.h>
+
+uint32_t __udivmodsi4(uint32_t num, uint32_t den, uint32_t * rem_p)
+{
+	uint32_t quot = 0, qbit = 1;
+
+	if (den == 0) {
+		__divide_error();
+		return 0;	/* If trap returns... */
+	}
+
+	/* Left-justify denominator and count shift */
+	while ((int32_t) den >= 0) {
+		den <<= 1;
+		qbit <<= 1;
+	}
+
+	while (qbit) {
+		if (den <= num) {
+			num -= den;
+			quot += qbit;
+		}
+		den >>= 1;
+		qbit >>= 1;
+	}
+
+	if (rem_p)
+		*rem_p = num;
+
+	return quot;
+}
diff --git a/usr/klibc/libgcc/__udivsi3.c b/usr/klibc/libgcc/__udivsi3.c
new file mode 100644
index 0000000..5635f3f
--- /dev/null
+++ b/usr/klibc/libgcc/__udivsi3.c
@@ -0,0 +1,13 @@
+/*
+ * libgcc/__divsi3.c
+ */
+
+#include <stdint.h>
+#include <stddef.h>
+
+extern uint32_t __udivmodsi4(uint32_t num, uint32_t den, uint32_t * rem);
+
+uint32_t __udivsi3(uint32_t num, uint32_t den)
+{
+	return __udivmodsi4(num, den, NULL);
+}
diff --git a/usr/klibc/libgcc/__umoddi3.c b/usr/klibc/libgcc/__umoddi3.c
new file mode 100644
index 0000000..1fc754a
--- /dev/null
+++ b/usr/klibc/libgcc/__umoddi3.c
@@ -0,0 +1,16 @@
+/*
+ * arch/i386/libgcc/__umoddi3.c
+ */
+
+#include <stdint.h>
+#include <stddef.h>
+
+extern uint64_t __udivmoddi4(uint64_t num, uint64_t den, uint64_t * rem);
+
+uint64_t __umoddi3(uint64_t num, uint64_t den)
+{
+	uint64_t v;
+
+	(void)__udivmoddi4(num, den, &v);
+	return v;
+}
diff --git a/usr/klibc/libgcc/__umodsi3.c b/usr/klibc/libgcc/__umodsi3.c
new file mode 100644
index 0000000..85e6e3c
--- /dev/null
+++ b/usr/klibc/libgcc/__umodsi3.c
@@ -0,0 +1,16 @@
+/*
+ * libgcc/__umodsi3.c
+ */
+
+#include <stdint.h>
+#include <stddef.h>
+
+extern uint32_t __udivmodsi4(uint32_t num, uint32_t den, uint32_t * rem);
+
+uint32_t __umodsi3(uint32_t num, uint32_t den)
+{
+	uint32_t v;
+
+	(void)__udivmodsi4(num, den, &v);
+	return v;
+}
diff --git a/usr/klibc/llseek.c b/usr/klibc/llseek.c
new file mode 100644
index 0000000..93d813b
--- /dev/null
+++ b/usr/klibc/llseek.c
@@ -0,0 +1,30 @@
+/*
+ * llseek.c
+ *
+ * On 32-bit platforms, we need to use the _llseek() system call
+ * rather than lseek(), to be able to handle large disks.  _llseek()
+ * isn't just a normal syscall which takes a 64-bit argument; it needs
+ * to return a 64-bit value and so takes an extra pointer.
+ */
+
+#include <unistd.h>
+#include <sys/syscall.h>
+#include <bitsize.h>
+
+#if _BITSIZE == 32
+
+extern int __llseek(int fd, unsigned long hi, unsigned long lo, off_t * res,
+		    int whence);
+
+off_t lseek(int fd, off_t offset, int whence)
+{
+	off_t result;
+	int rv;
+
+	rv = __llseek(fd, (unsigned long)(offset >> 32), (unsigned long)offset,
+		      &result, whence);
+
+	return rv ? (off_t) - 1 : result;
+}
+
+#endif
diff --git a/usr/klibc/lrand48.c b/usr/klibc/lrand48.c
new file mode 100644
index 0000000..7dfcf92
--- /dev/null
+++ b/usr/klibc/lrand48.c
@@ -0,0 +1,13 @@
+/*
+ * lrand48.c
+ */
+
+#include <stdlib.h>
+#include <stdint.h>
+
+unsigned short __rand48_seed[3];	/* Common with mrand48.c, srand48.c */
+
+long lrand48(void)
+{
+	return (uint32_t) jrand48(__rand48_seed) >> 1;
+}
diff --git a/usr/klibc/makeerrlist.pl b/usr/klibc/makeerrlist.pl
new file mode 100644
index 0000000..43c747c
--- /dev/null
+++ b/usr/klibc/makeerrlist.pl
@@ -0,0 +1,98 @@
+#!/usr/bin/perl
+#
+# This creates sys_errlist from <asm/errno.h> through somewhat
+# heuristic matching.  It presumes the relevant entries are of the form
+# #define Exxxx <integer> /* comment */
+#
+
+use FileHandle;
+
+%errors  = ();
+%errmsg  = ();
+$maxerr  = -1;
+@includelist = ();		# Include directories
+
+sub parse_file($) {
+    my($file) = @_;
+    my($fh) = new FileHandle;
+    my($line, $error, $msg);
+    my($kernelonly) = 0;
+    my($root);
+
+    print STDERR "opening $file\n" unless ( $quiet );
+
+    $ok = 0;
+    foreach $root ( @includelist ) {
+	if ( $fh->open($root.'//'.$file, '<') ) {
+	    $ok = 1;
+	    last;
+	}
+    }
+
+    if ( ! $ok ) {
+	die "$0: Cannot find file $file\n";
+    }
+
+    while ( defined($line = <$fh>) ) {
+	if ( $kernelonly ) {
+	    if ( $line =~ /^\#\s*endif/ ) {
+		$kernelonly--;
+	    } elsif ( $line =~ /^\#\sif/ ) {
+		$kernelonly++;
+	    }
+	} else {
+	    if ( $line =~ /^\#\s*define\s+([A-Z0-9_]+)\s+([0-9]+)\s*\/\*\s*(.*\S)\s*\*\// ) {
+		$error = $1;
+		$errno = $2+0;
+		$msg   = $3;
+		print STDERR "$error ($errno) => \"$msg\"\n" unless ( $quiet );
+		$errors{$errno} = $error;
+		$errmsg{$errno} = $msg;
+		$maxerr = $errno if ( $errno > $maxerr );
+	    } elsif ( $line =~ /^\#\s*include\s+[\<\"](.*)[\>\"]/ ) {
+		parse_file($1);
+	    } elsif ( $line =~ /^\#\s*ifdef\s+__KERNEL__/ ) {
+		$kernelonly++;
+	    }
+	}
+    }
+    close($fh);
+    print STDERR "closing $file\n" unless ( $quiet );
+}
+
+$v = $ENV{'KBUILD_VERBOSE'};
+$quiet = defined($v) ? !$v : 0;
+
+foreach $arg ( @ARGV ) {
+    if ( $arg eq '-q' ) {
+	$quiet = 1;
+    } elsif ( $arg =~ /^-(errlist|errnos|maxerr)$/ ) {
+	$type = $arg;
+    } elsif ( $arg =~ '^\-I' ) {
+	push(@includelist, "$'");
+    } else {
+	# Ignore
+    }
+}
+
+parse_file('linux/errno.h');
+
+if ( $type eq '-errlist' ) {
+    print  "#include <errno.h>\n";
+    printf "const int sys_nerr = %d;\n", $maxerr+1;
+    printf "const char * const sys_errlist[%d] = {\n", $maxerr+1;
+    foreach $e ( sort(keys(%errors)) ) {
+	printf "  [%s] = \"%s\",\n", $errors{$e}, $errmsg{$e};
+    }
+    print "};\n";
+} elsif ( $type eq '-errnos' ) {
+    print  "#include <errno.h>\n";
+    printf "const int sys_nerr = %d;\n", $maxerr+1;
+    printf "const char * const sys_errlist[%d] = {\n", $maxerr+1;
+    foreach $e ( sort(keys(%errors)) ) {
+	printf "  [%s] = \"%s\",\n", $errors{$e}, $errors{$e};
+    }
+    print "};\n";
+} elsif ( $type eq '-maxerr' ) {
+    print $maxerr, "\n";
+}
diff --git a/usr/klibc/malloc.c b/usr/klibc/malloc.c
new file mode 100644
index 0000000..fbbbbbc
--- /dev/null
+++ b/usr/klibc/malloc.c
@@ -0,0 +1,283 @@
+/*
+ * malloc.c
+ *
+ * Very simple linked-list based malloc()/free().
+ */
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/mman.h>
+#include "malloc.h"
+
+/* Both the arena list and the free memory list are double linked
+   list with head node.  This the head node. Note that the arena list
+   is sorted in order of address. */
+static struct free_arena_header __malloc_head = {
+	{
+		ARENA_TYPE_HEAD,
+		0,
+		&__malloc_head,
+		&__malloc_head,
+	},
+	&__malloc_head,
+	&__malloc_head
+};
+
+static inline void mark_block_dead(struct free_arena_header *ah)
+{
+#ifdef DEBUG_MALLOC
+	ah->a.type = ARENA_TYPE_DEAD;
+#endif
+}
+
+static inline void remove_from_main_chain(struct free_arena_header *ah)
+{
+	struct free_arena_header *ap, *an;
+
+	mark_block_dead(ah);
+
+	ap = ah->a.prev;
+	an = ah->a.next;
+	ap->a.next = an;
+	an->a.prev = ap;
+}
+
+static inline void remove_from_free_chain(struct free_arena_header *ah)
+{
+	struct free_arena_header *ap, *an;
+
+	ap = ah->prev_free;
+	an = ah->next_free;
+	ap->next_free = an;
+	an->prev_free = ap;
+}
+
+static inline void remove_from_chains(struct free_arena_header *ah)
+{
+	remove_from_free_chain(ah);
+	remove_from_main_chain(ah);
+}
+
+static void *__malloc_from_block(struct free_arena_header *fp, size_t size)
+{
+	size_t fsize;
+	struct free_arena_header *nfp, *na, *fpn, *fpp;
+
+	fsize = fp->a.size;
+
+	/* We need the 2* to account for the larger requirements of a
+	   free block */
+	if (fsize >= size + 2 * sizeof(struct arena_header)) {
+		/* Bigger block than required -- split block */
+		nfp = (struct free_arena_header *)((char *)fp + size);
+		na = fp->a.next;
+
+		nfp->a.type = ARENA_TYPE_FREE;
+		nfp->a.size = fsize - size;
+		fp->a.type = ARENA_TYPE_USED;
+		fp->a.size = size;
+
+		/* Insert into all-block chain */
+		nfp->a.prev = fp;
+		nfp->a.next = na;
+		na->a.prev = nfp;
+		fp->a.next = nfp;
+
+		/* Replace current block on free chain */
+		nfp->next_free = fpn = fp->next_free;
+		nfp->prev_free = fpp = fp->prev_free;
+		fpn->prev_free = nfp;
+		fpp->next_free = nfp;
+	} else {
+		fp->a.type = ARENA_TYPE_USED; /* Allocate the whole block */
+		remove_from_free_chain(fp);
+	}
+
+	return (void *)(&fp->a + 1);
+}
+
+static struct free_arena_header *__free_block(struct free_arena_header *ah)
+{
+	struct free_arena_header *pah, *nah;
+
+	pah = ah->a.prev;
+	nah = ah->a.next;
+	if (pah->a.type == ARENA_TYPE_FREE &&
+	    (char *)pah + pah->a.size == (char *)ah) {
+		/* Coalesce into the previous block */
+		pah->a.size += ah->a.size;
+		pah->a.next = nah;
+		nah->a.prev = pah;
+		mark_block_dead(ah);
+
+		ah = pah;
+		pah = ah->a.prev;
+	} else {
+		/* Need to add this block to the free chain */
+		ah->a.type = ARENA_TYPE_FREE;
+
+		ah->next_free = __malloc_head.next_free;
+		ah->prev_free = &__malloc_head;
+		__malloc_head.next_free = ah;
+		ah->next_free->prev_free = ah;
+	}
+
+	/* In either of the previous cases, we might be able to merge
+	   with the subsequent block... */
+	if (nah->a.type == ARENA_TYPE_FREE &&
+	    (char *)ah + ah->a.size == (char *)nah) {
+		ah->a.size += nah->a.size;
+
+		/* Remove the old block from the chains */
+		remove_from_chains(nah);
+	}
+
+	/* Return the block that contains the called block */
+	return ah;
+}
+
+void *malloc(size_t size)
+{
+	struct free_arena_header *fp;
+	struct free_arena_header *pah;
+	size_t fsize;
+
+	if (size == 0)
+		return NULL;
+
+	/* Add the obligatory arena header, and round up */
+	size = (size + 2 * sizeof(struct arena_header) - 1) & ARENA_SIZE_MASK;
+
+	for (fp = __malloc_head.next_free; fp->a.type != ARENA_TYPE_HEAD;
+	     fp = fp->next_free) {
+		if (fp->a.size >= size) {
+			/* Found fit -- allocate out of this block */
+			return __malloc_from_block(fp, size);
+		}
+	}
+
+	/* Nothing found... need to request a block from the kernel */
+	fsize = (size + MALLOC_CHUNK_MASK) & ~MALLOC_CHUNK_MASK;
+
+#if _KLIBC_MALLOC_USES_SBRK
+	fp = (struct free_arena_header *)sbrk(fsize);
+#else
+	fp = (struct free_arena_header *)
+	    mmap(NULL, fsize, PROT_READ | PROT_WRITE,
+		 MAP_PRIVATE | MAP_ANONYMOUS, 0, 0);
+#endif
+
+	if (fp == (struct free_arena_header *)MAP_FAILED) {
+		return NULL;	/* Failed to get a block */
+	}
+
+	/* Insert the block into the management chains.  We need to set
+	   up the size and the main block list pointer, the rest of
+	   the work is logically identical to free(). */
+	fp->a.type = ARENA_TYPE_FREE;
+	fp->a.size = fsize;
+
+	/* We need to insert this into the main block list in the proper
+	   place -- this list is required to be sorted.  Since we most likely
+	   get memory assignments in ascending order, search backwards for
+	   the proper place. */
+	for (pah = __malloc_head.a.prev; pah->a.type != ARENA_TYPE_HEAD;
+	     pah = pah->a.prev) {
+		if (pah < fp)
+			break;
+	}
+
+	/* Now pah points to the node that should be the predecessor of
+	   the new node */
+	fp->a.next = pah->a.next;
+	fp->a.prev = pah;
+	pah->a.next = fp;
+	fp->a.next->a.prev = fp;
+
+	/* Insert into the free chain and coalesce with adjacent blocks */
+	fp = __free_block(fp);
+
+	/* Now we can allocate from this block */
+	return __malloc_from_block(fp, size);
+}
+
+void free(void *ptr)
+{
+	struct free_arena_header *ah;
+
+	if (!ptr)
+		return;
+
+	ah = (struct free_arena_header *)
+	    ((struct arena_header *)ptr - 1);
+
+#ifdef DEBUG_MALLOC
+	assert(ah->a.type == ARENA_TYPE_USED);
+#endif
+
+	/* Merge into adjacent free blocks */
+	ah = __free_block(ah);
+
+	/* See if it makes sense to return memory to the system */
+#if _KLIBC_MALLOC_USES_SBRK
+	if (ah->a.size >= _KLIBC_MALLOC_CHUNK_SIZE &&
+	    (char *)ah + ah->a.size == __current_brk) {
+		remove_from_chains(ah);
+		brk(ah);
+	}
+#else
+	{
+		size_t page_size = getpagesize();
+		size_t page_mask = page_size - 1;
+		size_t head_portion = -(size_t)ah & page_mask;
+		size_t tail_portion = ((size_t)ah + ah->a.size) & page_mask;
+		size_t adj_size;
+
+		/* Careful here... an individual chunk of memory must have
+		   a minimum size if it exists at all, so if either the
+		   head or the tail is below the minimum, then extend
+		   that chunk by a page. */
+
+		if (head_portion &&
+		    head_portion < 2*sizeof(struct arena_header))
+			head_portion += page_size;
+
+		if (tail_portion &&
+		    tail_portion < 2*sizeof(struct arena_header))
+			tail_portion += page_size;
+
+		adj_size = ah->a.size - head_portion - tail_portion;
+
+		/* Worth it?  This is written the way it is to guard
+		   against overflows... */
+		if (ah->a.size >= head_portion+tail_portion+
+		    _KLIBC_MALLOC_CHUNK_SIZE) {
+			struct free_arena_header *tah, *tan, *tap;
+
+			if (tail_portion) {
+				/* Make a new header, and insert into chains
+				   immediately after the current block */
+				tah = (struct free_arena_header *)
+					((char *)ah + head_portion + adj_size);
+				tah->a.type = ARENA_TYPE_FREE;
+				tah->a.size = tail_portion;
+				tah->a.next = tan = ah->a.next;
+				tan->a.prev = tah;
+				tah->a.prev = ah;
+				ah->a.next = tah;
+				tah->prev_free = tap = ah->prev_free;
+				tap->next_free = tah;
+				tah->next_free = ah;
+				ah->prev_free = tah;
+			}
+
+			if (head_portion)
+				ah->a.size = head_portion;
+			else
+				remove_from_chains(ah);
+
+			munmap((char *)ah + head_portion, adj_size);
+		}
+	}
+#endif
+}
diff --git a/usr/klibc/malloc.h b/usr/klibc/malloc.h
new file mode 100644
index 0000000..f3ec0a8
--- /dev/null
+++ b/usr/klibc/malloc.h
@@ -0,0 +1,50 @@
+/*
+ * malloc.h
+ *
+ * Internals for the memory allocator
+ */
+
+#include <stdint.h>
+#include <stddef.h>
+#include <klibc/sysconfig.h>
+
+/*
+ * This structure should be a power of two.  This becomes the
+ * alignment unit.
+ */
+struct free_arena_header;
+
+struct arena_header {
+	size_t type;
+	size_t size;		/* Also gives the location of the next entry */
+	struct free_arena_header *next, *prev;
+};
+
+#ifdef DEBUG_MALLOC
+#define ARENA_TYPE_USED 0x64e69c70
+#define ARENA_TYPE_FREE 0x012d610a
+#define ARENA_TYPE_HEAD 0x971676b5
+#define ARENA_TYPE_DEAD 0xeeeeeeee
+#else
+#define ARENA_TYPE_USED 0
+#define ARENA_TYPE_FREE 1
+#define ARENA_TYPE_HEAD 2
+#endif
+
+#define MALLOC_CHUNK_MASK (_KLIBC_MALLOC_CHUNK_SIZE-1)
+
+#define ARENA_SIZE_MASK (~(sizeof(struct arena_header)-1))
+
+/*
+ * This structure should be no more than twice the size of the
+ * previous structure.
+ */
+struct free_arena_header {
+	struct arena_header a;
+	struct free_arena_header *next_free, *prev_free;
+};
+
+/*
+ * Internal variable used by brk/sbrk
+ */
+extern char *__current_brk;
diff --git a/usr/klibc/memccpy.c b/usr/klibc/memccpy.c
new file mode 100644
index 0000000..83d02c9
--- /dev/null
+++ b/usr/klibc/memccpy.c
@@ -0,0 +1,23 @@
+/*
+ * memccpy.c
+ *
+ * memccpy()
+ */
+
+#include <stddef.h>
+#include <string.h>
+
+void *memccpy(void *dst, const void *src, int c, size_t n)
+{
+	char *q = dst;
+	const char *p = src;
+	char ch;
+
+	while (n--) {
+		*q++ = ch = *p++;
+		if (ch == (char)c)
+			return q;
+	}
+
+	return NULL;		/* No instance of "c" found */
+}
diff --git a/usr/klibc/memchr.c b/usr/klibc/memchr.c
new file mode 100644
index 0000000..f1947fb
--- /dev/null
+++ b/usr/klibc/memchr.c
@@ -0,0 +1,19 @@
+/*
+ * memchr.c
+ */
+
+#include <stddef.h>
+#include <string.h>
+
+void *memchr(const void *s, int c, size_t n)
+{
+	const unsigned char *sp = s;
+
+	while (n--) {
+		if (*sp == (unsigned char)c)
+			return (void *)sp;
+		sp++;
+	}
+
+	return NULL;
+}
diff --git a/usr/klibc/memcmp.c b/usr/klibc/memcmp.c
new file mode 100644
index 0000000..3ce9941
--- /dev/null
+++ b/usr/klibc/memcmp.c
@@ -0,0 +1,19 @@
+/*
+ * memcmp.c
+ */
+
+#include <string.h>
+
+int memcmp(const void *s1, const void *s2, size_t n)
+{
+	const unsigned char *c1 = s1, *c2 = s2;
+	int d = 0;
+
+	while (n--) {
+		d = (int)*c1++ - (int)*c2++;
+		if (d)
+			break;
+	}
+
+	return d;
+}
diff --git a/usr/klibc/memcpy.c b/usr/klibc/memcpy.c
new file mode 100644
index 0000000..5ce206d
--- /dev/null
+++ b/usr/klibc/memcpy.c
@@ -0,0 +1,29 @@
+/*
+ * memcpy.c
+ */
+
+#include <string.h>
+#include <stdint.h>
+
+void *memcpy(void *dst, const void *src, size_t n)
+{
+	const char *p = src;
+	char *q = dst;
+#if defined(__i386__)
+	size_t nl = n >> 2;
+	asm volatile ("cld ; rep ; movsl ; movl %3,%0 ; rep ; movsb":"+c" (nl),
+		      "+S"(p), "+D"(q)
+		      :"r"(n & 3));
+#elif defined(__x86_64__)
+	size_t nq = n >> 3;
+	asm volatile ("cld ; rep ; movsq ; movl %3,%%ecx ; rep ; movsb":"+c"
+		      (nq), "+S"(p), "+D"(q)
+		      :"r"((uint32_t) (n & 7)));
+#else
+	while (n--) {
+		*q++ = *p++;
+	}
+#endif
+
+	return dst;
+}
diff --git a/usr/klibc/memmem.c b/usr/klibc/memmem.c
new file mode 100644
index 0000000..8b5faa0
--- /dev/null
+++ b/usr/klibc/memmem.c
@@ -0,0 +1,52 @@
+/*
+ * memmem.c
+ *
+ * Find a byte string inside a longer byte string
+ *
+ * This uses the "Not So Naive" algorithm, a very simple but
+ * usually effective algorithm, see:
+ *
+ * http://www-igm.univ-mlv.fr/~lecroq/string/
+ */
+
+#include <string.h>
+
+void *memmem(const void *haystack, size_t n, const void *needle, size_t m)
+{
+	const unsigned char *y = (const unsigned char *)haystack;
+	const unsigned char *x = (const unsigned char *)needle;
+
+	size_t j, k, l;
+
+	if (m > n || !m || !n)
+		return NULL;
+
+	if (1 != m) {
+		if (x[0] == x[1]) {
+			k = 2;
+			l = 1;
+		} else {
+			k = 1;
+			l = 2;
+		}
+
+		j = 0;
+		while (j <= n - m) {
+			if (x[1] != y[j + 1]) {
+				j += k;
+			} else {
+				if (!memcmp(x + 2, y + j + 2, m - 2)
+				    && x[0] == y[j])
+					return (void *)&y[j];
+				j += l;
+			}
+		}
+	} else
+		do {
+			if (*y == *x)
+				return (void *)y;
+			y++;
+		} while (--n);
+
+	return NULL;
+}
diff --git a/usr/klibc/memmove.c b/usr/klibc/memmove.c
new file mode 100644
index 0000000..659c778
--- /dev/null
+++ b/usr/klibc/memmove.c
@@ -0,0 +1,36 @@
+/*
+ * memmove.c
+ */
+
+#include <string.h>
+
+void *memmove(void *dst, const void *src, size_t n)
+{
+	const char *p = src;
+	char *q = dst;
+#if defined(__i386__) || defined(__x86_64__)
+	if (q < p) {
+		asm volatile("cld ; rep ; movsb"
+			     : "+c" (n), "+S"(p), "+D"(q));
+	} else {
+		p += (n - 1);
+		q += (n - 1);
+		asm volatile("std ; rep ; movsb"
+			     : "+c" (n), "+S"(p), "+D"(q));
+	}
+#else
+	if (q < p) {
+		while (n--) {
+			*q++ = *p++;
+		}
+	} else {
+		p += n;
+		q += n;
+		while (n--) {
+			*--q = *--p;
+		}
+	}
+#endif
+
+	return dst;
+}
diff --git a/usr/klibc/memrchr.c b/usr/klibc/memrchr.c
new file mode 100644
index 0000000..ff6d711
--- /dev/null
+++ b/usr/klibc/memrchr.c
@@ -0,0 +1,19 @@
+/*
+ * memrchr.c
+ */
+
+#include <stddef.h>
+#include <string.h>
+
+void *memrchr(const void *s, int c, size_t n)
+{
+	const unsigned char *sp = (const unsigned char *)s + n - 1;
+
+	while (n--) {
+		if (*sp == (unsigned char)c)
+			return (void *)sp;
+		sp--;
+	}
+
+	return NULL;
+}
diff --git a/usr/klibc/memset.c b/usr/klibc/memset.c
new file mode 100644
index 0000000..aa00b5b
--- /dev/null
+++ b/usr/klibc/memset.c
@@ -0,0 +1,30 @@
+/*
+ * memset.c
+ */
+
+#include <string.h>
+#include <stdint.h>
+
+void *memset(void *dst, int c, size_t n)
+{
+	char *q = dst;
+
+#if defined(__i386__)
+	size_t nl = n >> 2;
+	asm volatile ("cld ; rep ; stosl ; movl %3,%0 ; rep ; stosb"
+		      : "+c" (nl), "+D" (q)
+		      : "a" ((unsigned char)c * 0x01010101U), "r" (n & 3));
+#elif defined(__x86_64__)
+	size_t nq = n >> 3;
+	asm volatile ("cld ; rep ; stosq ; movl %3,%%ecx ; rep ; stosb"
+		      :"+c" (nq), "+D" (q)
+		      : "a" ((unsigned char)c * 0x0101010101010101U),
+			"r" ((uint32_t) n & 7));
+#else
+	while (n--) {
+		*q++ = c;
+	}
+#endif
+
+	return dst;
+}
diff --git a/usr/klibc/memswap.c b/usr/klibc/memswap.c
new file mode 100644
index 0000000..b32315c
--- /dev/null
+++ b/usr/klibc/memswap.c
@@ -0,0 +1,24 @@
+/*
+ * memswap()
+ *
+ * Swaps the contents of two nonoverlapping memory areas.
+ * This really could be done faster...
+ */
+
+#include <string.h>
+
+void memswap(void *m1, void *m2, size_t n)
+{
+	char *p = m1;
+	char *q = m2;
+	char tmp;
+
+	while (n--) {
+		tmp = *p;
+		*p = *q;
+		*q = tmp;
+
+		p++;
+		q++;
+	}
+}
diff --git a/usr/klibc/mmap.c b/usr/klibc/mmap.c
new file mode 100644
index 0000000..9b1dcd9
--- /dev/null
+++ b/usr/klibc/mmap.c
@@ -0,0 +1,40 @@
+/*
+ * mmap.c
+ */
+
+#include <stdint.h>
+#include <errno.h>
+#include <sys/syscall.h>
+#include <sys/mman.h>
+#include <unistd.h>
+#include <bitsize.h>
+#include <klibc/sysconfig.h>
+
+/*
+ * Set in SYSCALLS whether or not we should use an unadorned mmap() system
+ * call (typical on 64-bit architectures).
+ */
+#if !_KLIBC_NO_MMU && _KLIBC_USE_MMAP2
+
+/* This architecture uses mmap2(). The Linux mmap2() system call takes
+   a page offset as the offset argument.  We need to make sure we have
+   the proper conversion in place. */
+
+extern void *__mmap2(void *, size_t, int, int, int, size_t);
+
+void *mmap(void *start, size_t length, int prot, int flags, int fd,
+	   off_t offset)
+{
+	const int mmap2_shift = _KLIBC_MMAP2_SHIFT;
+	const off_t mmap2_mask = ((off_t) 1 << mmap2_shift) - 1;
+
+	if (offset & mmap2_mask) {
+		errno = EINVAL;
+		return MAP_FAILED;
+	}
+
+	return __mmap2(start, length, prot, flags, fd,
+		       (size_t) offset >> mmap2_shift);
+}
+
+#endif
diff --git a/usr/klibc/mrand48.c b/usr/klibc/mrand48.c
new file mode 100644
index 0000000..e3b73cc
--- /dev/null
+++ b/usr/klibc/mrand48.c
@@ -0,0 +1,13 @@
+/*
+ * mrand48.c
+ */
+
+#include <stdlib.h>
+#include <stdint.h>
+
+unsigned short __rand48_seed[3];	/* Common with lrand48.c, srand48.c */
+
+long mrand48(void)
+{
+	return jrand48(__rand48_seed);
+}
diff --git a/usr/klibc/nice.c b/usr/klibc/nice.c
new file mode 100644
index 0000000..e6e99ac
--- /dev/null
+++ b/usr/klibc/nice.c
@@ -0,0 +1,19 @@
+/*
+ * nice.c
+ */
+
+#include <unistd.h>
+#include <sched.h>
+#include <sys/resource.h>
+#include <sys/syscall.h>
+
+#ifndef __NR_nice
+
+int nice(int inc)
+{
+	pid_t me = getpid();
+	return setpriority(me, PRIO_PROCESS,
+			   getpriority(me, PRIO_PROCESS) + inc);
+}
+
+#endif
diff --git a/usr/klibc/nrand48.c b/usr/klibc/nrand48.c
new file mode 100644
index 0000000..cb3532b
--- /dev/null
+++ b/usr/klibc/nrand48.c
@@ -0,0 +1,11 @@
+/*
+ * nrand48.c
+ */
+
+#include <stdlib.h>
+#include <stdint.h>
+
+long nrand48(unsigned short xsubi[3])
+{
+	return (long)((uint32_t) jrand48(xsubi) >> 1);
+}
diff --git a/usr/klibc/nullenv.c b/usr/klibc/nullenv.c
new file mode 100644
index 0000000..ba7e71c
--- /dev/null
+++ b/usr/klibc/nullenv.c
@@ -0,0 +1,8 @@
+/*
+ * nullenv.c
+ */
+
+#include <stddef.h>
+#include "env.h"
+
+char * const __null_environ[] = { NULL };
diff --git a/usr/klibc/onexit.c b/usr/klibc/onexit.c
new file mode 100644
index 0000000..15a96b5
--- /dev/null
+++ b/usr/klibc/onexit.c
@@ -0,0 +1,23 @@
+/*
+ * onexit.c
+ */
+
+#include <stdlib.h>
+#include <unistd.h>
+#include "atexit.h"
+
+int on_exit(void (*fctn) (int, void *), void *arg)
+{
+	struct atexit *as = malloc(sizeof(struct atexit));
+
+	if (!as)
+		return -1;
+
+	as->fctn = fctn;
+	as->arg = arg;
+
+	as->next = __atexit_list;
+	__atexit_list = as;
+
+	return 0;
+}
diff --git a/usr/klibc/open.c b/usr/klibc/open.c
new file mode 100644
index 0000000..9b0897a
--- /dev/null
+++ b/usr/klibc/open.c
@@ -0,0 +1,22 @@
+/*
+ * open.c
+ *
+ * On 32-bit platforms we need to pass O_LARGEFILE to the open()
+ * system call, to indicate that we're 64-bit safe.
+ */
+
+#define _KLIBC_IN_OPEN_C
+#include <unistd.h>
+#include <fcntl.h>
+#include <bitsize.h>
+
+#if _BITSIZE == 32 && !defined(__i386__)
+
+extern int __open(const char *, int, mode_t);
+
+int open(const char *pathname, int flags, mode_t mode)
+{
+	return __open(pathname, flags | O_LARGEFILE, mode);
+}
+
+#endif
diff --git a/usr/klibc/open_cloexec.c b/usr/klibc/open_cloexec.c
new file mode 100644
index 0000000..e30b09d
--- /dev/null
+++ b/usr/klibc/open_cloexec.c
@@ -0,0 +1,18 @@
+/*
+ * open_cloexec.c
+ *
+ * A quick hack to do an open() and set the cloexec flag
+ */
+
+#include <unistd.h>
+#include <fcntl.h>
+
+int open_cloexec(const char *path, int flags, mode_t mode)
+{
+	int fd = open(path, flags, mode);
+
+	if (fd >= 0)
+		fcntl(fd, F_SETFD, FD_CLOEXEC);
+
+	return fd;
+}
diff --git a/usr/klibc/openat.c b/usr/klibc/openat.c
new file mode 100644
index 0000000..83c87cd
--- /dev/null
+++ b/usr/klibc/openat.c
@@ -0,0 +1,22 @@
+/*
+ * openat.c
+ *
+ * On 32-bit platforms we need to pass O_LARGEFILE to the openat()
+ * system call, to indicate that we're 64-bit safe.
+ */
+
+#define _KLIBC_IN_OPEN_C
+#include <unistd.h>
+#include <fcntl.h>
+#include <bitsize.h>
+
+#if _BITSIZE == 32 && !defined(__i386__) && defined(__NR_openat)
+
+extern int __openat(int, const char *, int, mode_t);
+
+int openat(int dirfd, const char *pathname, int flags, mode_t mode)
+{
+	return __openat(dirfd, pathname, flags | O_LARGEFILE, mode);
+}
+
+#endif
diff --git a/usr/klibc/pause.c b/usr/klibc/pause.c
new file mode 100644
index 0000000..cec97a8
--- /dev/null
+++ b/usr/klibc/pause.c
@@ -0,0 +1,17 @@
+/*
+ * pause.c
+ */
+
+#include <stddef.h>
+#include <unistd.h>
+#include <sys/time.h>
+#include <sys/syscall.h>
+
+#ifndef __NR_pause
+
+int pause(void)
+{
+	return select(0, NULL, NULL, NULL, NULL);
+}
+
+#endif
diff --git a/usr/klibc/perror.c b/usr/klibc/perror.c
new file mode 100644
index 0000000..3177057
--- /dev/null
+++ b/usr/klibc/perror.c
@@ -0,0 +1,13 @@
+/*
+ * perror.c
+ */
+
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+
+void perror(const char *s)
+{
+	int e = errno;
+	fprintf(stderr, "%s: %s\n", s, strerror(e));
+}
diff --git a/usr/klibc/ppoll.c b/usr/klibc/ppoll.c
new file mode 100644
index 0000000..5e20a89
--- /dev/null
+++ b/usr/klibc/ppoll.c
@@ -0,0 +1,19 @@
+/*
+ * ppoll.c
+ */
+
+#include <sys/poll.h>
+#include <sys/syscall.h>
+
+#ifdef __NR_ppoll
+
+__extern int __ppoll(struct pollfd *, nfds_t, struct timespec *,
+		     const sigset_t *, size_t);
+
+int ppoll(struct pollfd *ufds, nfds_t nfds, struct timespec *timeout,
+	  const sigset_t * sigmask)
+{
+	return __ppoll(ufds, nfds, timeout, sigmask, sizeof *sigmask);
+}
+
+#endif
diff --git a/usr/klibc/printf.c b/usr/klibc/printf.c
new file mode 100644
index 0000000..02bdba0
--- /dev/null
+++ b/usr/klibc/printf.c
@@ -0,0 +1,19 @@
+/*
+ * printf.c
+ */
+
+#include <stdio.h>
+#include <stdarg.h>
+
+#define BUFFER_SIZE	16384
+
+int printf(const char *format, ...)
+{
+	va_list ap;
+	int rv;
+
+	va_start(ap, format);
+	rv = vfprintf(stdout, format, ap);
+	va_end(ap);
+	return rv;
+}
diff --git a/usr/klibc/pselect.c b/usr/klibc/pselect.c
new file mode 100644
index 0000000..1bb6852
--- /dev/null
+++ b/usr/klibc/pselect.c
@@ -0,0 +1,42 @@
+/*
+ * pselect.c
+ */
+
+#include <sys/select.h>
+#include <sys/syscall.h>
+
+#if defined(__NR_pselect) && !_KLIBC_USE_RT_SIG
+
+/* Don't need to do anything here; use syscall stub directly */
+
+#elif defined(__NR_pselect7)
+
+__extern int __pselect7(int, fd_set *, fd_set *, fd_set *,
+			const struct timespec *, const sigset_t *, size_t);
+
+int pselect(int n, fd_set * readfds, fd_set * writefds, fd_set * exceptfds,
+	    const struct timespec *timeout, const sigset_t * sigmask)
+{
+	return __pselect7(n, readfds, writefds, exceptfds,
+			  timeout, sigmask, sizeof *sigmask);
+}
+
+#elif defined(__NR_pselect6)
+
+struct __pselect6 {
+	const sigset_t *sigmask;
+	size_t sigsize;
+};
+
+__extern int __pselect6(int, fd_set *, fd_set *, fd_set *,
+			const struct timespec *, const struct __pselect6 *);
+
+int pselect(int n, fd_set * readfds, fd_set * writefds, fd_set * exceptfds,
+	    const struct timespec *timeout, const sigset_t * sigmask)
+{
+	struct __pselect6 extended_sigmask = { sigmask, sizeof *sigmask };
+	return __pselect6(n, readfds, writefds, exceptfds,
+			  timeout, &extended_sigmask);
+}
+
+#endif
diff --git a/usr/klibc/pty.c b/usr/klibc/pty.c
new file mode 100644
index 0000000..7fcb2ba
--- /dev/null
+++ b/usr/klibc/pty.c
@@ -0,0 +1,31 @@
+/*
+ * pty.c
+ *
+ * Basic Unix98 PTY functionality; assumes devpts mounted on /dev/pts
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <termios.h>
+#include <sys/ioctl.h>
+
+char *ptsname(int fd)
+{
+	static char buffer[32];	/* Big enough to hold even a 64-bit pts no */
+	unsigned int ptyno;
+
+	if (ioctl(fd, TIOCGPTN, &ptyno))
+		return NULL;
+
+	snprintf(buffer, sizeof buffer, "/dev/pts/%u", ptyno);
+
+	return buffer;
+}
+
+int unlockpt(int fd)
+{
+	int unlock = 0;
+
+	return ioctl(fd, TIOCSPTLCK, &unlock);
+}
diff --git a/usr/klibc/putchar.c b/usr/klibc/putchar.c
new file mode 100644
index 0000000..e2224ca
--- /dev/null
+++ b/usr/klibc/putchar.c
@@ -0,0 +1,15 @@
+/*
+ * putchar.c
+ *
+ * - gcc wants this
+ */
+
+#include <stdio.h>
+
+#undef putchar			/* Defined as a macro */
+int putchar(int);
+
+int putchar(int c)
+{
+	return fputc(c, stdout);
+}
diff --git a/usr/klibc/putenv.c b/usr/klibc/putenv.c
new file mode 100644
index 0000000..5059ecb
--- /dev/null
+++ b/usr/klibc/putenv.c
@@ -0,0 +1,37 @@
+/*
+ * putenv.c
+ */
+
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include "env.h"
+
+int putenv(const char *str)
+{
+	char *s;
+	const char *e, *z;
+
+	if (!str) {
+		errno = EINVAL;
+		return -1;
+	}
+
+	e = NULL;
+	for (z = str; *z; z++) {
+		if (*z == '=')
+			e = z;
+	}
+
+	if (!e) {
+		errno = EINVAL;
+		return -1;
+	}
+
+	s = strdup(str);
+	if (!s)
+		return -1;
+
+	return __put_env(s, e - str, 1);
+}
diff --git a/usr/klibc/puts.c b/usr/klibc/puts.c
new file mode 100644
index 0000000..27e16e2
--- /dev/null
+++ b/usr/klibc/puts.c
@@ -0,0 +1,13 @@
+/*
+ * puts.c
+ */
+
+#include <stdio.h>
+
+int puts(const char *s)
+{
+	if (fputs(s, stdout) < 0)
+		return -1;
+
+	return _fwrite("\n", 1, stdout);
+}
diff --git a/usr/klibc/qsort.c b/usr/klibc/qsort.c
new file mode 100644
index 0000000..73484a2
--- /dev/null
+++ b/usr/klibc/qsort.c
@@ -0,0 +1,45 @@
+/*
+ * qsort.c
+ *
+ * This is actually combsort.  It's an O(n log n) algorithm with
+ * simplicity/small code size being its main virtue.
+ */
+
+#include <stddef.h>
+#include <string.h>
+
+static inline size_t newgap(size_t gap)
+{
+	gap = (gap * 10) / 13;
+	if (gap == 9 || gap == 10)
+		gap = 11;
+
+	if (gap < 1)
+		gap = 1;
+	return gap;
+}
+
+void qsort(void *base, size_t nmemb, size_t size,
+	   int (*compar) (const void *, const void *))
+{
+	size_t gap = nmemb;
+	size_t i, j;
+	char *p1, *p2;
+	int swapped;
+
+	if (!nmemb)
+		return;
+
+	do {
+		gap = newgap(gap);
+		swapped = 0;
+
+		for (i = 0, p1 = base; i < nmemb - gap; i++, p1 += size) {
+			j = i + gap;
+			if (compar(p1, p2 = (char *)base + j * size) > 0) {
+				memswap(p1, p2, size);
+				swapped = 1;
+			}
+		}
+	} while (gap > 1 || swapped);
+}
diff --git a/usr/klibc/raise.c b/usr/klibc/raise.c
new file mode 100644
index 0000000..3b9d23d
--- /dev/null
+++ b/usr/klibc/raise.c
@@ -0,0 +1,11 @@
+/*
+ * raise.c
+ */
+
+#include <unistd.h>
+#include <signal.h>
+
+int raise(int signal)
+{
+	return kill(getpid(), signal);
+}
diff --git a/usr/klibc/readdir.c b/usr/klibc/readdir.c
new file mode 100644
index 0000000..453fc08
--- /dev/null
+++ b/usr/klibc/readdir.c
@@ -0,0 +1,57 @@
+/*
+ * readdir.c: opendir/readdir/closedir
+ */
+
+#include <unistd.h>
+#include <fcntl.h>
+#include <stdlib.h>
+
+#define __KLIBC_DIRENT_INTERNALS
+#include <dirent.h>
+
+DIR *opendir(const char *name)
+{
+	DIR *dp = malloc(sizeof(DIR));
+
+	if (!dp)
+		return NULL;
+
+	dp->__fd = open(name, O_DIRECTORY | O_RDONLY);
+
+	if (dp->__fd < 0) {
+		free(dp);
+		return NULL;
+	}
+
+	dp->bytes_left = 0;
+
+	return dp;
+}
+
+struct dirent *readdir(DIR *dir)
+{
+	struct dirent *dent;
+	int rv;
+
+	if (!dir->bytes_left) {
+		rv = getdents(dir->__fd, dir->buffer, sizeof(dir->buffer));
+		if (rv <= 0)
+			return NULL;
+		dir->bytes_left = rv;
+		dir->next = dir->buffer;
+	}
+
+	dent = dir->next;
+	dir->next = (struct dirent *)((char *)dir->next + dent->d_reclen);
+	dir->bytes_left -= dent->d_reclen;
+
+	return dent;
+}
+
+int closedir(DIR *dir)
+{
+	int rv;
+	rv = close(dir->__fd);
+	free(dir);
+	return rv;
+}
diff --git a/usr/klibc/realloc.c b/usr/klibc/realloc.c
new file mode 100644
index 0000000..14a2f2f
--- /dev/null
+++ b/usr/klibc/realloc.c
@@ -0,0 +1,48 @@
+/*
+ * realloc.c
+ */
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "malloc.h"
+
+/* FIXME: This is cheesy, it should be fixed later */
+
+void *realloc(void *ptr, size_t size)
+{
+	struct free_arena_header *ah;
+	void *newptr;
+	size_t oldsize;
+
+	if (!ptr)
+		return malloc(size);
+
+	if (size == 0) {
+		free(ptr);
+		return NULL;
+	}
+
+	/* Add the obligatory arena header, and round up */
+	size = (size + 2 * sizeof(struct arena_header) - 1) & ARENA_SIZE_MASK;
+
+	ah = (struct free_arena_header *)
+	    ((struct arena_header *)ptr - 1);
+
+	if (ah->a.size >= size && size >= (ah->a.size >> 2)) {
+		/* This field is a good size already. */
+		return ptr;
+	} else {
+		/* Make me a new block.  This is kind of bogus; we should
+		   be checking the following block to see if we can do an
+		   in-place adjustment... fix that later. */
+
+		oldsize = ah->a.size - sizeof(struct arena_header);
+
+		newptr = malloc(size);
+		memcpy(newptr, ptr, (size < oldsize) ? size : oldsize);
+		free(ptr);
+
+		return newptr;
+	}
+}
diff --git a/usr/klibc/reboot.c b/usr/klibc/reboot.c
new file mode 100644
index 0000000..5795dc3
--- /dev/null
+++ b/usr/klibc/reboot.c
@@ -0,0 +1,15 @@
+/*
+ * reboot.c
+ */
+
+#include <unistd.h>
+#include <sys/reboot.h>
+#include <sys/syscall.h>
+
+/* This provides the one-argument glibc-ish version of reboot.
+   The full four-argument system call is available as __reboot(). */
+
+int reboot(int flag)
+{
+	return __reboot(LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2, flag, NULL);
+}
diff --git a/usr/klibc/recv.c b/usr/klibc/recv.c
new file mode 100644
index 0000000..0baa00a
--- /dev/null
+++ b/usr/klibc/recv.c
@@ -0,0 +1,11 @@
+/*
+ * recv.c
+ */
+
+#include <stddef.h>
+#include <sys/socket.h>
+
+int recv(int s, void *buf, size_t len, unsigned int flags)
+{
+	return recvfrom(s, buf, len, flags, NULL, 0);
+}
diff --git a/usr/klibc/remove.c b/usr/klibc/remove.c
new file mode 100644
index 0000000..9088204
--- /dev/null
+++ b/usr/klibc/remove.c
@@ -0,0 +1,18 @@
+/*
+ * remove.c
+ */
+
+#include <stdio.h>
+#include <unistd.h>
+#include <errno.h>
+
+int remove(const char *pathname)
+{
+	int rv;
+
+	rv = unlink(pathname);
+	if (rv == -1 && errno == EISDIR)
+		return rmdir(pathname);
+
+	return rv;
+}
diff --git a/usr/klibc/sbrk.c b/usr/klibc/sbrk.c
new file mode 100644
index 0000000..4896ce0
--- /dev/null
+++ b/usr/klibc/sbrk.c
@@ -0,0 +1,45 @@
+/* sbrk.c - Change data segment size */
+
+/* Written 2000 by Werner Almesberger */
+/* Modified 2003-2004 for klibc by H. Peter Anvin */
+
+#include <stddef.h>
+#include <unistd.h>
+#include <inttypes.h>
+#include <errno.h>
+#include "malloc.h"
+
+#if !_KLIBC_NO_MMU		/* uClinux doesn't have brk() */
+
+char *__current_brk;		/* Common with brk.c */
+
+/* p is an address,  a is alignment; must be a power of 2 */
+static inline void *align_up(void *p, uintptr_t a)
+{
+	return (void *)(((uintptr_t) p + a - 1) & ~(a - 1));
+}
+
+void *sbrk(ptrdiff_t increment)
+{
+	char *start, *end, *new_brk;
+
+	if (!__current_brk)
+		__current_brk = __brk(NULL);
+
+	start = align_up(__current_brk, _KLIBC_SBRK_ALIGNMENT);
+	end = start + increment;
+
+	new_brk = __brk(end);
+
+	if (new_brk == (void *)-1)
+		return (void *)-1;
+	else if (new_brk < end) {
+		errno = ENOMEM;
+		return (void *)-1;
+	}
+
+	__current_brk = new_brk;
+	return start;
+}
+
+#endif				/* !_KLIBC_NO_MMU */
diff --git a/usr/klibc/seed48.c b/usr/klibc/seed48.c
new file mode 100644
index 0000000..ccdf183
--- /dev/null
+++ b/usr/klibc/seed48.c
@@ -0,0 +1,18 @@
+/*
+ * seed48.c
+ */
+
+#include <stdlib.h>
+#include <stdint.h>
+#include <string.h>
+
+unsigned short __rand48_seed[3];
+
+unsigned short *seed48(const unsigned short xsubi[3])
+{
+	static unsigned short oldseed[3];
+	memcpy(oldseed, __rand48_seed, sizeof __rand48_seed);
+	memcpy(__rand48_seed, xsubi, sizeof __rand48_seed);
+
+	return oldseed;
+}
diff --git a/usr/klibc/send.c b/usr/klibc/send.c
new file mode 100644
index 0000000..a867dd1
--- /dev/null
+++ b/usr/klibc/send.c
@@ -0,0 +1,11 @@
+/*
+ * send.c
+ */
+
+#include <stddef.h>
+#include <sys/socket.h>
+
+int send(int s, const void *buf, size_t len, unsigned int flags)
+{
+	return sendto(s, buf, len, flags, NULL, 0);
+}
diff --git a/usr/klibc/setegid.c b/usr/klibc/setegid.c
new file mode 100644
index 0000000..6af966f
--- /dev/null
+++ b/usr/klibc/setegid.c
@@ -0,0 +1,10 @@
+/*
+ * setegid.c
+ */
+
+#include <unistd.h>
+
+int setegid(gid_t egid)
+{
+	return setregid(-1, egid);
+}
diff --git a/usr/klibc/setenv.c b/usr/klibc/setenv.c
new file mode 100644
index 0000000..45a7aad
--- /dev/null
+++ b/usr/klibc/setenv.c
@@ -0,0 +1,42 @@
+/*
+ * setenv.c
+ */
+
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include "env.h"
+
+int setenv(const char *name, const char *val, int overwrite)
+{
+	const char *z;
+	char *s;
+	size_t l1, l2;
+
+	if (!name || !name[0]) {
+		errno = EINVAL;
+		return -1;
+	}
+
+	l1 = 0;
+	for (z = name; *z; z++) {
+		l1++;
+		if (*z == '=') {
+			errno = EINVAL;
+			return -1;
+		}
+	}
+
+	l2 = strlen(val);
+
+	s = malloc(l1 + l2 + 2);
+	if (!s)
+		return -1;
+
+	memcpy(s, name, l1);
+	s[l1] = '=';
+	memcpy(s + l1 + 1, val, l2 + 1);
+
+	return __put_env(s, l1 + 1, overwrite);
+}
diff --git a/usr/klibc/seteuid.c b/usr/klibc/seteuid.c
new file mode 100644
index 0000000..18dddb1
--- /dev/null
+++ b/usr/klibc/seteuid.c
@@ -0,0 +1,10 @@
+/*
+ * seteuid.c
+ */
+
+#include <unistd.h>
+
+int seteuid(uid_t euid)
+{
+	return setreuid(-1, euid);
+}
diff --git a/usr/klibc/setpgrp.c b/usr/klibc/setpgrp.c
new file mode 100644
index 0000000..75bbcc7
--- /dev/null
+++ b/usr/klibc/setpgrp.c
@@ -0,0 +1,10 @@
+/*
+ * setpgrp.c
+ */
+
+#include <unistd.h>
+
+int setpgrp(void)
+{
+	return setpgid(0, 0);
+}
diff --git a/usr/klibc/sha1hash.c b/usr/klibc/sha1hash.c
new file mode 100644
index 0000000..c29eebf
--- /dev/null
+++ b/usr/klibc/sha1hash.c
@@ -0,0 +1,317 @@
+/*
+SHA-1 in C
+By Steve Reid <sreid@sea-to-sky.net>
+100% Public Domain
+
+-----------------
+Modified 7/98
+By James H. Brown <jbrown@burgoyne.com>
+Still 100% Public Domain
+
+Corrected a problem which generated improper hash values on 16 bit machines
+Routine SHA1Update changed from
+	void SHA1Update(SHA1_CTX* context, unsigned char* data, unsigned int
+len)
+to
+	void SHA1Update(SHA1_CTX* context, unsigned char* data, unsigned
+long len)
+
+The 'len' parameter was declared an int which works fine on 32 bit machines.
+However, on 16 bit machines an int is too small for the shifts being done
+against
+it.  This caused the hash function to generate incorrect values if len was
+greater than 8191 (8K - 1) due to the 'len << 3' on line 3 of SHA1Update().
+
+Since the file IO in main() reads 16K at a time, any file 8K or larger would
+be guaranteed to generate the wrong hash (e.g. Test Vector #3, a million
+"a"s).
+
+I also changed the declaration of variables i & j in SHA1Update to
+unsigned long from unsigned int for the same reason.
+
+These changes should make no difference to any 32 bit implementations since
+an
+int and a long are the same size in those environments.
+
+--
+I also corrected a few compiler warnings generated by Borland C.
+1. Added #include <process.h> for exit() prototype
+2. Removed unused variable 'j' in SHA1Final
+3. Changed exit(0) to return(0) at end of main.
+
+ALL changes I made can be located by searching for comments containing 'JHB'
+-----------------
+Modified 8/98
+By Steve Reid <sreid@sea-to-sky.net>
+Still 100% public domain
+
+1- Removed #include <process.h> and used return() instead of exit()
+2- Fixed overwriting of finalcount in SHA1Final() (discovered by Chris Hall)
+3- Changed email address from steve@edmweb.com to sreid@sea-to-sky.net
+
+-----------------
+Modified 4/01
+By Saul Kravitz <Saul.Kravitz@celera.com>
+Still 100% PD
+Modified to run on Compaq Alpha hardware.
+
+-----------------
+Modified 2/03
+By H. Peter Anvin <hpa@zytor.com>
+Still 100% PD
+Modified to run on any hardware with <inttypes.h> and <netinet/in.h>
+Changed the driver program
+
+*/
+
+/*
+Test Vectors (from FIPS PUB 180-1)
+"abc"
+  A9993E36 4706816A BA3E2571 7850C26C 9CD0D89D
+"abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"
+  84983E44 1C3BD26E BAAE4AA1 F95129E5 E54670F1
+A million repetitions of "a"
+  34AA973C D4C4DAA4 F61EEB2B DBAD2731 6534016F
+*/
+
+/* #define SHA1HANDSOFF  */
+
+#include <stdio.h>
+#include <string.h>
+#include <inttypes.h>
+#include <netinet/in.h>		/* For htonl/ntohl/htons/ntohs */
+
+/* #include <process.h> */	/* prototype for exit() - JHB */
+/* Using return() instead of exit() - SWR */
+
+typedef struct {
+    uint32_t state[5];
+    uint32_t count[2];
+    unsigned char buffer[64];
+} SHA1_CTX;
+
+void SHA1Transform(uint32_t state[5], unsigned char buffer[64]);
+void SHA1Init(SHA1_CTX* context);
+void SHA1Update(SHA1_CTX* context, unsigned char* data, uint32_t len);	/*
+JHB */
+void SHA1Final(unsigned char digest[20], SHA1_CTX* context);
+
+#define rol(value, bits) (((value) << (bits)) | ((value) >> (32 - (bits))))
+
+/* blk0() and blk() perform the initial expand. */
+/* I got the idea of expanding during the round function from SSLeay */
+#define blk0(i) (block->l[i] = ntohl(block->l[i]))
+#define blk(i) (block->l[i&15] = rol(block->l[(i+13)&15]^block->l[(i+8)&15] \
+    ^block->l[(i+2)&15]^block->l[i&15],1))
+
+/* (R0+R1), R2, R3, R4 are the different operations used in SHA1 */
+#define R0(v,w,x,y,z,i) z+=((w&(x^y))^y)+blk0(i)+0x5A827999+rol(v,5);w=rol(w,30);
+#define R1(v,w,x,y,z,i) z+=((w&(x^y))^y)+blk(i)+0x5A827999+rol(v,5);w=rol(w,30);
+#define R2(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0x6ED9EBA1+rol(v,5);w=rol(w,30);
+#define R3(v,w,x,y,z,i) z+=(((w|x)&y)|(w&x))+blk(i)+0x8F1BBCDC+rol(v,5);w=rol(w,30);
+#define R4(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0xCA62C1D6+rol(v,5);w=rol(w,30);
+
+
+#ifdef VERBOSE  /* SAK */
+void SHAPrintContext(SHA1_CTX *context, char *msg){
+  printf("%s (%d,%d) %x %x %x %x %x\n",
+	 msg,
+	 context->count[0], context->count[1],
+	 context->state[0],
+	 context->state[1],
+	 context->state[2],
+	 context->state[3],
+	 context->state[4]);
+}
+#endif
+
+/* Hash a single 512-bit block. This is the core of the algorithm. */
+
+void SHA1Transform(uint32_t state[5], unsigned char buffer[64])
+{
+uint32_t a, b, c, d, e;
+typedef union {
+    unsigned char c[64];
+    uint32_t l[16];
+} CHAR64LONG16;
+CHAR64LONG16* block;
+#ifdef SHA1HANDSOFF
+static unsigned char workspace[64];
+    block = (CHAR64LONG16*)workspace;
+    memcpy(block, buffer, 64);
+#else
+    block = (CHAR64LONG16*)buffer;
+#endif
+    /* Copy context->state[] to working vars */
+    a = state[0];
+    b = state[1];
+    c = state[2];
+    d = state[3];
+    e = state[4];
+    /* 4 rounds of 20 operations each. Loop unrolled. */
+    R0(a,b,c,d,e, 0); R0(e,a,b,c,d, 1); R0(d,e,a,b,c, 2); R0(c,d,e,a,b, 3);
+    R0(b,c,d,e,a, 4); R0(a,b,c,d,e, 5); R0(e,a,b,c,d, 6); R0(d,e,a,b,c, 7);
+    R0(c,d,e,a,b, 8); R0(b,c,d,e,a, 9); R0(a,b,c,d,e,10); R0(e,a,b,c,d,11);
+    R0(d,e,a,b,c,12); R0(c,d,e,a,b,13); R0(b,c,d,e,a,14); R0(a,b,c,d,e,15);
+    R1(e,a,b,c,d,16); R1(d,e,a,b,c,17); R1(c,d,e,a,b,18); R1(b,c,d,e,a,19);
+    R2(a,b,c,d,e,20); R2(e,a,b,c,d,21); R2(d,e,a,b,c,22); R2(c,d,e,a,b,23);
+    R2(b,c,d,e,a,24); R2(a,b,c,d,e,25); R2(e,a,b,c,d,26); R2(d,e,a,b,c,27);
+    R2(c,d,e,a,b,28); R2(b,c,d,e,a,29); R2(a,b,c,d,e,30); R2(e,a,b,c,d,31);
+    R2(d,e,a,b,c,32); R2(c,d,e,a,b,33); R2(b,c,d,e,a,34); R2(a,b,c,d,e,35);
+    R2(e,a,b,c,d,36); R2(d,e,a,b,c,37); R2(c,d,e,a,b,38); R2(b,c,d,e,a,39);
+    R3(a,b,c,d,e,40); R3(e,a,b,c,d,41); R3(d,e,a,b,c,42); R3(c,d,e,a,b,43);
+    R3(b,c,d,e,a,44); R3(a,b,c,d,e,45); R3(e,a,b,c,d,46); R3(d,e,a,b,c,47);
+    R3(c,d,e,a,b,48); R3(b,c,d,e,a,49); R3(a,b,c,d,e,50); R3(e,a,b,c,d,51);
+    R3(d,e,a,b,c,52); R3(c,d,e,a,b,53); R3(b,c,d,e,a,54); R3(a,b,c,d,e,55);
+    R3(e,a,b,c,d,56); R3(d,e,a,b,c,57); R3(c,d,e,a,b,58); R3(b,c,d,e,a,59);
+    R4(a,b,c,d,e,60); R4(e,a,b,c,d,61); R4(d,e,a,b,c,62); R4(c,d,e,a,b,63);
+    R4(b,c,d,e,a,64); R4(a,b,c,d,e,65); R4(e,a,b,c,d,66); R4(d,e,a,b,c,67);
+    R4(c,d,e,a,b,68); R4(b,c,d,e,a,69); R4(a,b,c,d,e,70); R4(e,a,b,c,d,71);
+    R4(d,e,a,b,c,72); R4(c,d,e,a,b,73); R4(b,c,d,e,a,74); R4(a,b,c,d,e,75);
+    R4(e,a,b,c,d,76); R4(d,e,a,b,c,77); R4(c,d,e,a,b,78); R4(b,c,d,e,a,79);
+    /* Add the working vars back into context.state[] */
+    state[0] += a;
+    state[1] += b;
+    state[2] += c;
+    state[3] += d;
+    state[4] += e;
+    /* Wipe variables */
+    a = b = c = d = e = 0;
+}
+
+
+/* SHA1Init - Initialize new context */
+
+void SHA1Init(SHA1_CTX* context)
+{
+    /* SHA1 initialization constants */
+    context->state[0] = 0x67452301;
+    context->state[1] = 0xEFCDAB89;
+    context->state[2] = 0x98BADCFE;
+    context->state[3] = 0x10325476;
+    context->state[4] = 0xC3D2E1F0;
+    context->count[0] = context->count[1] = 0;
+}
+
+
+/* Run your data through this. */
+
+void SHA1Update(SHA1_CTX* context, unsigned char* data, uint32_t len)	/*
+JHB */
+{
+uint32_t i, j;	/* JHB */
+
+#ifdef VERBOSE
+    SHAPrintContext(context, "before");
+#endif
+    j = (context->count[0] >> 3) & 63;
+    if ((context->count[0] += len << 3) < (len << 3)) context->count[1]++;
+    context->count[1] += (len >> 29);
+    if ((j + len) > 63) {
+        memcpy(&context->buffer[j], data, (i = 64-j));
+        SHA1Transform(context->state, context->buffer);
+        for ( ; i + 63 < len; i += 64) {
+            SHA1Transform(context->state, &data[i]);
+        }
+        j = 0;
+    }
+    else i = 0;
+    memcpy(&context->buffer[j], &data[i], len - i);
+#ifdef VERBOSE
+    SHAPrintContext(context, "after ");
+#endif
+}
+
+
+/* Add padding and return the message digest. */
+
+void SHA1Final(unsigned char digest[20], SHA1_CTX* context)
+{
+uint32_t i;	/* JHB */
+unsigned char finalcount[8];
+
+    for (i = 0; i < 8; i++) {
+        finalcount[i] = (unsigned char)((context->count[(i >= 4 ? 0 : 1)]
+         >> ((3-(i & 3)) * 8) ) & 255);  /* Endian independent */
+    }
+    SHA1Update(context, (unsigned char *)"\200", 1);
+    while ((context->count[0] & 504) != 448) {
+        SHA1Update(context, (unsigned char *)"\0", 1);
+    }
+    SHA1Update(context, finalcount, 8);  /* Should cause a SHA1Transform()
+*/
+    for (i = 0; i < 20; i++) {
+        digest[i] = (unsigned char)
+         ((context->state[i>>2] >> ((3-(i & 3)) * 8) ) & 255);
+    }
+    /* Wipe variables */
+    i = 0;	/* JHB */
+    memset(context->buffer, 0, 64);
+    memset(context->state, 0, 20);
+    memset(context->count, 0, 8);
+    memset(finalcount, 0, 8);	/* SWR */
+#ifdef SHA1HANDSOFF  /* make SHA1Transform overwrite it's own static vars */
+    SHA1Transform(context->state, context->buffer);
+#endif
+}
+
+/*************************************************************/
+
+/* This is not quite the MIME base64 algorithm: it uses _ instead of /,
+   and instead of padding the output with = characters we just make the
+   output shorter. */
+char *mybase64(uint8_t digest[20])
+{
+  static const char charz[] =
+    "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_";
+  uint8_t input[21];
+  static char output[28];
+  int i, j;
+  uint8_t *p;
+  char *q;
+  uint32_t bv;
+
+  memcpy(input, digest, 20);
+  input[20] = 0;		/* Pad to multiple of 3 bytes */
+
+  p = input;  q = output;
+  for ( i = 0 ; i < 7 ; i++ ) {
+    bv = (p[0] << 16) | (p[1] << 8) | p[2];
+    p += 3;
+    for ( j = 0 ; j < 4 ; j++ ) {
+      *q++ = charz[(bv >> 18) & 0x3f];
+      bv <<= 6;
+    }
+  }
+  *--q = '\0';			/* The last character is not significant */
+  return output;
+}
+
+int main(int argc, char** argv)
+{
+  int i;
+  SHA1_CTX context;
+  uint8_t digest[20], buffer[16384];
+  FILE* file;
+
+  if (argc < 2) {
+    file = stdin;
+  }
+  else {
+    if (!(file = fopen(argv[1], "rb"))) {
+      fputs("Unable to open file.", stderr);
+      return(-1);
+    }
+  }
+  SHA1Init(&context);
+  while (!feof(file)) {  /* note: what if ferror(file) */
+    i = fread(buffer, 1, 16384, file);
+    SHA1Update(&context, buffer, i);
+  }
+  SHA1Final(digest, &context);
+  fclose(file);
+
+  puts(mybase64(digest));
+
+  return 0;
+}
diff --git a/usr/klibc/shm_open.c b/usr/klibc/shm_open.c
new file mode 100644
index 0000000..8fe93aa
--- /dev/null
+++ b/usr/klibc/shm_open.c
@@ -0,0 +1,23 @@
+/*
+ * shm_open.c
+ *
+ * POSIX shared memory support
+ */
+
+#include <stdlib.h>
+#include <alloca.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/mman.h>
+
+
+int shm_open(const char *path, int oflag, mode_t mode)
+{
+	int len = strlen(path);
+	char *pathbuf = alloca(len+10);
+
+	memcpy(pathbuf, "/dev/shm/", 9);
+	memcpy(pathbuf+9, path, len+1);
+
+	return open_cloexec(path, oflag, mode);
+}
diff --git a/usr/klibc/shm_unlink.c b/usr/klibc/shm_unlink.c
new file mode 100644
index 0000000..94a98a0
--- /dev/null
+++ b/usr/klibc/shm_unlink.c
@@ -0,0 +1,23 @@
+/*
+ * shm_unlink.c
+ *
+ * POSIX shared memory support
+ */
+
+#include <stdlib.h>
+#include <alloca.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/mman.h>
+
+
+int shm_unlink(const char *path)
+{
+	int len = strlen(path);
+	char *pathbuf = alloca(len+10);
+
+	memcpy(pathbuf, "/dev/shm/", 9);
+	memcpy(pathbuf+9, path, len+1);
+
+	return unlink(path);
+}
diff --git a/usr/klibc/sigabbrev.c b/usr/klibc/sigabbrev.c
new file mode 100644
index 0000000..21a799c
--- /dev/null
+++ b/usr/klibc/sigabbrev.c
@@ -0,0 +1,121 @@
+/*
+ * sigabbrev.h
+ *
+ * Construct the abbreviated signal list
+ */
+
+#include <signal.h>
+#include <unistd.h>
+
+const char *const sys_sigabbrev[NSIG] = {
+#ifdef SIGABRT
+	[SIGABRT] = "ABRT",
+#endif
+#ifdef SIGALRM
+	[SIGALRM] = "ALRM",
+#endif
+#ifdef SIGBUS
+	[SIGBUS] = "BUS",
+#endif
+#ifdef SIGCHLD
+	[SIGCHLD] = "CHLD",
+#endif
+#if defined(SIGCLD) && (SIGCHLD != SIGCLD)
+	[SIGCLD] = "CLD",
+#endif
+#ifdef SIGEMT
+	[SIGEMT] = "EMT",
+#endif
+#ifdef SIGFPE
+	[SIGFPE] = "FPE",
+#endif
+#ifdef SIGHUP
+	[SIGHUP] = "HUP",
+#endif
+#ifdef SIGILL
+	[SIGILL] = "ILL",
+#endif
+	/* SIGINFO == SIGPWR */
+#ifdef SIGINT
+	[SIGINT] = "INT",
+#endif
+#ifdef SIGIO
+	[SIGIO] = "IO",
+#endif
+#if defined(SIGIOT) && (SIGIOT != SIGABRT)
+	[SIGIOT] = "IOT",
+#endif
+#ifdef SIGKILL
+	[SIGKILL] = "KILL",
+#endif
+#if defined(SIGLOST) && (SIGLOST != SIGIO) && (SIGLOST != SIGPWR)
+	[SIGLOST] = "LOST",
+#endif
+#ifdef SIGPIPE
+	[SIGPIPE] = "PIPE",
+#endif
+#if defined(SIGPOLL) && (SIGPOLL != SIGIO)
+	[SIGPOLL] = "POLL",
+#endif
+#ifdef SIGPROF
+	[SIGPROF] = "PROF",
+#endif
+#ifdef SIGPWR
+	[SIGPWR] = "PWR",
+#endif
+#ifdef SIGQUIT
+	[SIGQUIT] = "QUIT",
+#endif
+	/* SIGRESERVE == SIGUNUSED */
+#ifdef SIGSEGV
+	[SIGSEGV] = "SEGV",
+#endif
+#ifdef SIGSTKFLT
+	[SIGSTKFLT] = "STKFLT",
+#endif
+#ifdef SIGSTOP
+	[SIGSTOP] = "STOP",
+#endif
+#ifdef SIGSYS
+	[SIGSYS] = "SYS",
+#endif
+#ifdef SIGTERM
+	[SIGTERM] = "TERM",
+#endif
+#ifdef SIGTSTP
+	[SIGTSTP] = "TSTP",
+#endif
+#ifdef SIGTTIN
+	[SIGTTIN] = "TTIN",
+#endif
+#ifdef SIGTTOU
+	[SIGTTOU] = "TTOU",
+#endif
+#ifdef SIGURG
+	[SIGURG] = "URG",
+#endif
+#ifdef SIGUSR1
+	[SIGUSR1] = "USR1",
+#endif
+#ifdef SIGUSR2
+	[SIGUSR2] = "USR2",
+#endif
+#ifdef SIGVTALRM
+	[SIGVTALRM] = "VTALRM",
+#endif
+#ifdef SIGWINCH
+	[SIGWINCH] = "WINCH",
+#endif
+#ifdef SIGXCPU
+	[SIGXCPU] = "XCPU",
+#endif
+#ifdef SIGXFSZ
+	[SIGXFSZ] = "XFSZ",
+#endif
+#ifdef SIGTRAP
+	[SIGTRAP] = "TRAP",
+#endif
+#ifdef SIGCONT
+	[SIGCONT] = "CONT",
+#endif
+};
diff --git a/usr/klibc/sigaction.c b/usr/klibc/sigaction.c
new file mode 100644
index 0000000..658c3ad
--- /dev/null
+++ b/usr/klibc/sigaction.c
@@ -0,0 +1,60 @@
+/*
+ * sigaction.c
+ */
+
+#include <signal.h>
+#include <sys/syscall.h>
+#include <klibc/sysconfig.h>
+
+__extern void __sigreturn(void);
+__extern int __sigaction(int, const struct sigaction *, struct sigaction *);
+#ifdef __sparc__
+__extern int __rt_sigaction(int, const struct sigaction *, struct sigaction *,
+			    void (*)(void), size_t);
+#else
+__extern int __rt_sigaction(int, const struct sigaction *, struct sigaction *,
+			    size_t);
+#endif
+
+int sigaction(int sig, const struct sigaction *act, struct sigaction *oact)
+{
+	int rv;
+
+#if _KLIBC_NEEDS_SA_RESTORER
+	struct sigaction sa;
+
+	if (act && !(act->sa_flags & SA_RESTORER)) {
+		sa = *act;
+		act = &sa;
+
+		/* The kernel can't be trusted to have a valid default
+		   restorer */
+		sa.sa_flags |= SA_RESTORER;
+		sa.sa_restorer = &__sigreturn;
+	}
+#endif
+
+#if _KLIBC_USE_RT_SIG
+# ifdef __sparc__
+	{
+		void (*restorer)(void);
+		restorer = (act && act->sa_flags & SA_RESTORER)
+			? (void (*)(void))((uintptr_t)act->sa_restorer - 8)
+			: NULL;
+		rv = __rt_sigaction(sig, act, oact, restorer, sizeof(sigset_t));
+	}
+# else
+	rv = __rt_sigaction(sig, act, oact, sizeof(sigset_t));
+# endif
+#else
+	rv = __sigaction(sig, act, oact);
+#endif
+
+#if _KLIBC_NEEDS_SA_RESTORER
+	if (oact && (oact->sa_restorer == &__sigreturn)) {
+		oact->sa_flags &= ~SA_RESTORER;
+	}
+#endif
+
+	return rv;
+}
diff --git a/usr/klibc/siglist.c b/usr/klibc/siglist.c
new file mode 100644
index 0000000..d690049
--- /dev/null
+++ b/usr/klibc/siglist.c
@@ -0,0 +1,121 @@
+/*
+ * siglist.h
+ *
+ * Construct the signal list
+ */
+
+#include <signal.h>
+#include <unistd.h>
+
+const char *const sys_siglist[NSIG] = {
+#ifdef SIGABRT
+	[SIGABRT] = "Aborted",
+#endif
+#ifdef SIGALRM
+	[SIGALRM] = "Alarm clock",
+#endif
+#ifdef SIGBUS
+	[SIGBUS] = "Bus error",
+#endif
+#ifdef SIGCHLD
+	[SIGCHLD] = "Child exited",
+#endif
+#if defined(SIGCLD) && (SIGCHLD != SIGCLD)
+	[SIGCLD] = "Child exited",
+#endif
+#ifdef SIGEMT
+	[SIGEMT] = "Emulation trap",
+#endif
+#ifdef SIGFPE
+	[SIGFPE] = "Floating point exception",
+#endif
+#ifdef SIGHUP
+	[SIGHUP] = "Hangup",
+#endif
+#ifdef SIGILL
+	[SIGILL] = "Illegal instruction",
+#endif
+	/* SIGINFO == SIGPWR */
+#ifdef SIGINT
+	[SIGINT] = "Interrupt",
+#endif
+#ifdef SIGIO
+	[SIGIO] = "I/O possible",
+#endif
+#if defined(SIGIOT) && (SIGIOT != SIGABRT)
+	[SIGIOT] = "I/O trap",
+#endif
+#ifdef SIGKILL
+	[SIGKILL] = "Killed",
+#endif
+#if defined(SIGLOST) && (SIGLOST != SIGIO) && (SIGLOST != SIGPWR)
+	[SIGLOST] = "Lock lost",
+#endif
+#ifdef SIGPIPE
+	[SIGPIPE] = "Broken pipe",
+#endif
+#if defined(SIGPOLL) && (SIGPOLL != SIGIO)
+	[SIGPOLL] = "Pollable event",
+#endif
+#ifdef SIGPROF
+	[SIGPROF] = "Profiling timer expired",
+#endif
+#ifdef SIGPWR
+	[SIGPWR] = "Power failure",
+#endif
+#ifdef SIGQUIT
+	[SIGQUIT] = "Quit",
+#endif
+	/* SIGRESERVE == SIGUNUSED */
+#ifdef SIGSEGV
+	[SIGSEGV] = "Segment violation",
+#endif
+#ifdef SIGSTKFLT
+	[SIGSTKFLT] = "Stack fault",
+#endif
+#ifdef SIGSTOP
+	[SIGSTOP] = "Stopped (signal)",
+#endif
+#ifdef SIGSYS
+	[SIGSYS] = "Bad system call",
+#endif
+#ifdef SIGTERM
+	[SIGTERM] = "Terminated",
+#endif
+#ifdef SIGTSTP
+	[SIGTSTP] = "Stopped",
+#endif
+#ifdef SIGTTIN
+	[SIGTTIN] = "Stopped (tty input)",
+#endif
+#ifdef SIGTTOU
+	[SIGTTOU] = "Stopped (tty output)",
+#endif
+#ifdef SIGURG
+	[SIGURG] = "Urgent I/O condition",
+#endif
+#ifdef SIGUSR1
+	[SIGUSR1] = "User signal 1",
+#endif
+#ifdef SIGUSR2
+	[SIGUSR2] = "User signal 2",
+#endif
+#ifdef SIGVTALRM
+	[SIGVTALRM] = "Virtual timer expired",
+#endif
+#ifdef SIGWINCH
+	[SIGWINCH] = "Window size changed",
+#endif
+#ifdef SIGXCPU
+	[SIGXCPU] = "CPU time limit exceeded",
+#endif
+#ifdef SIGXFSZ
+	[SIGXFSZ] = "File size limit exceeded",
+#endif
+#ifdef SIGTRAP
+	[SIGTRAP] = "Trace/breakpoint trap",
+#endif
+#ifdef SIGCONT
+	[SIGCONT] = "Continue",
+#endif
+};
diff --git a/usr/klibc/siglongjmp.c b/usr/klibc/siglongjmp.c
new file mode 100644
index 0000000..31042cb
--- /dev/null
+++ b/usr/klibc/siglongjmp.c
@@ -0,0 +1,15 @@
+/*
+ * siglongjmp.c
+ *
+ * sigsetjmp() is a macro, by necessity (it's either that or write
+ * it in assembly), but siglongjmp() is a normal function.
+ */
+
+#include <setjmp.h>
+#include <signal.h>
+
+__noreturn siglongjmp(sigjmp_buf buf, int retval)
+{
+	sigprocmask(SIG_SETMASK, &buf->__sigs, NULL);
+	longjmp(buf->__jmpbuf, retval);
+}
diff --git a/usr/klibc/sigpending.c b/usr/klibc/sigpending.c
new file mode 100644
index 0000000..26fd3e9
--- /dev/null
+++ b/usr/klibc/sigpending.c
@@ -0,0 +1,18 @@
+/*
+ * sigpending.c
+ */
+
+#include <signal.h>
+#include <sys/syscall.h>
+#include <klibc/sysconfig.h>
+
+#if _KLIBC_USE_RT_SIG
+
+__extern int __rt_sigpending(sigset_t *, size_t);
+
+int sigpending(sigset_t * set)
+{
+	return __rt_sigpending(set, sizeof(sigset_t));
+}
+
+#endif
diff --git a/usr/klibc/sigprocmask.c b/usr/klibc/sigprocmask.c
new file mode 100644
index 0000000..ea12c13
--- /dev/null
+++ b/usr/klibc/sigprocmask.c
@@ -0,0 +1,18 @@
+/*
+ * sigprocmask.c
+ */
+
+#include <signal.h>
+#include <sys/syscall.h>
+#include <klibc/sysconfig.h>
+
+#if _KLIBC_USE_RT_SIG
+
+__extern int __rt_sigprocmask(int, const sigset_t *, sigset_t *, size_t);
+
+int sigprocmask(int how, const sigset_t * set, sigset_t * oset)
+{
+	return __rt_sigprocmask(how, set, oset, sizeof(sigset_t));
+}
+
+#endif
diff --git a/usr/klibc/sigsuspend.c b/usr/klibc/sigsuspend.c
new file mode 100644
index 0000000..4d910d5
--- /dev/null
+++ b/usr/klibc/sigsuspend.c
@@ -0,0 +1,18 @@
+/*
+ * sigsuspend.c
+ */
+
+#include <signal.h>
+#include <sys/syscall.h>
+#include <klibc/sysconfig.h>
+
+#if _KLIBC_USE_RT_SIG
+
+__extern int __rt_sigsuspend(const sigset_t *, size_t);
+
+int sigsuspend(const sigset_t * mask)
+{
+	return __rt_sigsuspend(mask, sizeof *mask);
+}
+
+#endif
diff --git a/usr/klibc/sleep.c b/usr/klibc/sleep.c
new file mode 100644
index 0000000..750c51d
--- /dev/null
+++ b/usr/klibc/sleep.c
@@ -0,0 +1,20 @@
+/*
+ * sleep.c
+ */
+
+#include <errno.h>
+#include <time.h>
+
+unsigned int sleep(unsigned int seconds)
+{
+	struct timespec ts;
+
+	ts.tv_sec = seconds;
+	ts.tv_nsec = 0;
+	if (!nanosleep(&ts, &ts))
+		return 0;
+	else if (errno == EINTR)
+		return ts.tv_sec;
+	else
+		return -1;
+}
diff --git a/usr/klibc/snprintf.c b/usr/klibc/snprintf.c
new file mode 100644
index 0000000..713b3cd
--- /dev/null
+++ b/usr/klibc/snprintf.c
@@ -0,0 +1,16 @@
+/*
+ * snprintf.c
+ */
+
+#include <stdio.h>
+
+int snprintf(char *buffer, size_t n, const char *format, ...)
+{
+	va_list ap;
+	int rv;
+
+	va_start(ap, format);
+	rv = vsnprintf(buffer, n, format, ap);
+	va_end(ap);
+	return rv;
+}
diff --git a/usr/klibc/socketcalls.pl b/usr/klibc/socketcalls.pl
new file mode 100644
index 0000000..e6f75ab
--- /dev/null
+++ b/usr/klibc/socketcalls.pl
@@ -0,0 +1,88 @@
+#!/usr/bin/perl
+
+$v = $ENV{'KBUILD_VERBOSE'};
+$quiet = defined($v) ? !$v : 0;
+
+@args = ();
+for $arg ( @ARGV ) {
+    if ( $arg =~ /^-/ ) {
+	if ( $arg eq '-q' ) {
+	    $quiet = 1;
+	} else {
+	    die "$0: Unknown option: $arg\n";
+	}
+    } else {
+	push(@args, $arg);
+    }
+}
+($file, $arch, $outputdir) = @args;
+
+if (!open(FILE, "< $file")) {
+    die "$file: $!\n";
+}
+
+print "socketcall-objs := ";
+while ( defined($line = <FILE>) ) {
+    chomp $line;
+    $line =~ s/\s*(|\#.*|\/\/.*)$//;	# Strip comments and trailing blanks
+    next unless $line;
+
+    if ( $line =~ /^\s*\<\?\>\s*(.*)\s+([_a-zA-Z][_a-zA-Z0-9]+)\s*\((.*)\)\s*\;$/ ) {
+	$type = $1;
+	$name = $2;
+	$argv = $3;
+
+	@args = split(/\s*\,\s*/, $argv);
+	@cargs = ();
+
+	$i = 0;
+	for $arg ( @args ) {
+	    push(@cargs, "$arg a".$i++);
+	}
+	$nargs = $i;
+	print " \\\n\t${name}.o";
+
+	if ( $arch eq 'i386' ) {
+	    open(OUT, "> ${outputdir}/${name}.S")
+		or die "$0: Cannot open ${outputdir}/${name}.S\n";
+
+	    print OUT "#include <sys/socketcalls.h>\n";
+	    print OUT "\n";
+	    print OUT "\t.text\n";
+	    print OUT "\t.align	4\n";
+	    print OUT "\t.globl	${name}\n";
+	    print OUT "\t.type	${name},\@function\n";
+	    print OUT "${name}:\n";
+	    print OUT "\tpushl	\$SYS_\U${name}\n";
+	    print OUT "\tjmp	__socketcall_common\n";
+	    print OUT "\t.size ${name},.-${name}\n";
+	    close(OUT);
+	} else {
+	    open(OUT, "> ${outputdir}/${name}.c")
+		or die "$0: Cannot open ${outputdir}/${name}.c\n";
+
+	    print OUT "#include \"socketcommon.h\"\n";
+	    print OUT "\n";
+	    print OUT "#ifndef __NR_${name}\n\n";
+
+	    print OUT "extern long __socketcall(int, const unsigned long *);\n\n";
+
+	    print OUT "$type $name (", join(', ', @cargs), ")\n";
+	    print OUT "{\n";
+	    print OUT "    unsigned long args[$nargs];\n";
+	    for ( $i = 0 ; $i < $nargs ; $i++ ) {
+		print OUT "    args[$i] = (unsigned long)a$i;\n";
+	    }
+	    print OUT "    return ($type) __socketcall(SYS_\U${name}\E, args);\n";
+	    print OUT "}\n\n";
+
+	    print OUT "#endif\n";
+
+	    close(OUT);
+	}
+    } else {
+	die "$file:$.: Could not parse input\n";
+    }
+}
+
+print "\n";
diff --git a/usr/klibc/socketcalls/Kbuild b/usr/klibc/socketcalls/Kbuild
new file mode 100644
index 0000000..f0fc9a8
--- /dev/null
+++ b/usr/klibc/socketcalls/Kbuild
@@ -0,0 +1,50 @@
+#
+# Generate socket calls based on SOCKETCALLS.def
+#
+
+# Include automatically generated Makefile fragment.
+# It contains definition of socketcall-objs specifying name of all .o files
+ifeq ($(clean),)
+-include $(obj)/socketcalls.mk
+endif
+
+# Listing of all .o files
+always := klib.list
+
+#####
+# Generate socket calls stubs
+# Based on input from SOCKETCALLS.def generate socket call stubs
+targets     := klib.list
+targets     += socketcalls.mk
+targets	    += SOCKETCALLS.i
+targets     += $(socketcall-objs)
+clean-files += *.S *.c *.o *.list
+
+EXTRA_KLIBCCFLAGS := -I$(srctree)/$(src)
+
+quiet_cmd_makelist = LIST    $@
+      cmd_makelist = echo '$(filter-out FORCE,$^)' > $@
+
+# Create list of all files
+$(obj)/klib.list: $(call objectify,$(socketcall-objs)) FORCE
+	$(call if_changed,makelist)
+
+# Generate assembler file (.i)
+# We pass -ansi to keep cpp from define e.g. "i386" as well as "__i386__"
+quiet_cmd_socketcall.i = GEN     $@
+      cmd_socketcall.i = $(KLIBCCC) $(klibccflags) -D__ASSEMBLY__ \
+                                -ansi -x c -E -o $@ $<
+$(obj)/SOCKETCALLS.i: $(KLIBCSRC)/SOCKETCALLS.def FORCE
+	$(call if_changed_dep,socketcall.i)
+
+# Generate socketcall stubs
+quiet_cmd_socketcalls = GEN     $@
+      cmd_socketcalls = $(PERL) $(KLIBCSRC)/socketcalls.pl          \
+                                $(obj)/SOCKETCALLS.i	            \
+                                $(KLIBCARCH) $(obj) > $@ 	    \
+				|| ( rm -f $@ ; exit 1 )
+
+$(obj)/socketcalls.mk: $(KLIBCSRC)/socketcalls.pl                   \
+                       $(obj)/SOCKETCALLS.i                         \
+                       $(src)/socketcommon.h
+	$(call cmd,socketcalls)
diff --git a/usr/klibc/socketcalls/socketcommon.h b/usr/klibc/socketcalls/socketcommon.h
new file mode 100644
index 0000000..9c4b11f
--- /dev/null
+++ b/usr/klibc/socketcalls/socketcommon.h
@@ -0,0 +1,16 @@
+/*
+ * socketcommon.h
+ *
+ * Common header file for socketcall stubs
+ */
+
+#define __IN_SYS_COMMON
+#include <errno.h>
+#include <signal.h>
+#include <sys/types.h>
+#include <sys/syscall.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <sys/socket.h>
+#include <linux/net.h>
+#include <sys/socketcalls.h>
diff --git a/usr/klibc/sprintf.c b/usr/klibc/sprintf.c
new file mode 100644
index 0000000..c6d8758
--- /dev/null
+++ b/usr/klibc/sprintf.c
@@ -0,0 +1,18 @@
+/*
+ * sprintf.c
+ */
+
+#include <stdio.h>
+#include <unistd.h>
+
+int sprintf(char *buffer, const char *format, ...)
+{
+	va_list ap;
+	int rv;
+
+	va_start(ap, format);
+	rv = vsnprintf(buffer, ~(size_t) 0, format, ap);
+	va_end(ap);
+
+	return rv;
+}
diff --git a/usr/klibc/srand48.c b/usr/klibc/srand48.c
new file mode 100644
index 0000000..e1c9567
--- /dev/null
+++ b/usr/klibc/srand48.c
@@ -0,0 +1,15 @@
+/*
+ * srand48.c
+ */
+
+#include <stdlib.h>
+#include <stdint.h>
+
+unsigned short __rand48_seed[3];	/* Common with mrand48.c, lrand48.c */
+
+void srand48(long seedval)
+{
+	__rand48_seed[0] = 0x330e;
+	__rand48_seed[1] = (unsigned short)seedval;
+	__rand48_seed[2] = (unsigned short)((uint32_t) seedval >> 16);
+}
diff --git a/usr/klibc/sscanf.c b/usr/klibc/sscanf.c
new file mode 100644
index 0000000..f53b276
--- /dev/null
+++ b/usr/klibc/sscanf.c
@@ -0,0 +1,17 @@
+/*
+ * sscanf()
+ */
+
+#include <stdio.h>
+
+int sscanf(const char *str, const char *format, ...)
+{
+	va_list ap;
+	int rv;
+
+	va_start(ap, format);
+	rv = vsscanf(str, format, ap);
+	va_end(ap);
+
+	return rv;
+}
diff --git a/usr/klibc/statfs.c b/usr/klibc/statfs.c
new file mode 100644
index 0000000..b8b8700
--- /dev/null
+++ b/usr/klibc/statfs.c
@@ -0,0 +1,19 @@
+/*
+ * statfs.c
+ *
+ * On architectures which do statfs64, wrap the system call
+ */
+
+#include <sys/syscall.h>
+#include <sys/vfs.h>
+
+#ifdef __NR_statfs64
+
+extern int __statfs64(const char *, size_t, struct statfs *);
+
+int statfs(const char *path, struct statfs *buf)
+{
+	return __statfs64(path, sizeof *buf, buf);
+}
+
+#endif
diff --git a/usr/klibc/strcasecmp.c b/usr/klibc/strcasecmp.c
new file mode 100644
index 0000000..ee1f28b
--- /dev/null
+++ b/usr/klibc/strcasecmp.c
@@ -0,0 +1,24 @@
+/*
+ * strcasecmp.c
+ */
+
+#include <string.h>
+#include <ctype.h>
+
+int strcasecmp(const char *s1, const char *s2)
+{
+	const unsigned char *c1 = (const unsigned char *)s1;
+	const unsigned char *c2 = (const unsigned char *)s2;
+	unsigned char ch;
+	int d = 0;
+
+	while (1) {
+		/* toupper() expects an unsigned char (implicitly cast to int)
+		   as input, and returns an int, which is exactly what we want. */
+		d = toupper(ch = *c1++) - toupper(*c2++);
+		if (d || !ch)
+			break;
+	}
+
+	return d;
+}
diff --git a/usr/klibc/strcat.c b/usr/klibc/strcat.c
new file mode 100644
index 0000000..6c5b673
--- /dev/null
+++ b/usr/klibc/strcat.c
@@ -0,0 +1,11 @@
+/*
+ * strcat.c
+ */
+
+#include <string.h>
+
+char *strcat(char *dst, const char *src)
+{
+	strcpy(strchr(dst, '\0'), src);
+	return dst;
+}
diff --git a/usr/klibc/strchr.c b/usr/klibc/strchr.c
new file mode 100644
index 0000000..6040cc4
--- /dev/null
+++ b/usr/klibc/strchr.c
@@ -0,0 +1,19 @@
+/*
+ * strchr.c
+ */
+
+#include <string.h>
+#include <klibc/compiler.h>
+
+char *strchr(const char *s, int c)
+{
+	while (*s != (char)c) {
+		if (!*s)
+			return NULL;
+		s++;
+	}
+
+	return (char *)s;
+}
+
+__ALIAS(char *, index, (const char *, int), strchr)
diff --git a/usr/klibc/strcmp.c b/usr/klibc/strcmp.c
new file mode 100644
index 0000000..3ab9f5a
--- /dev/null
+++ b/usr/klibc/strcmp.c
@@ -0,0 +1,21 @@
+/*
+ * strcmp.c
+ */
+
+#include <string.h>
+
+int strcmp(const char *s1, const char *s2)
+{
+	const unsigned char *c1 = (const unsigned char *)s1;
+	const unsigned char *c2 = (const unsigned char *)s2;
+	unsigned char ch;
+	int d = 0;
+
+	while (1) {
+		d = (int)(ch = *c1++) - (int)*c2++;
+		if (d || !ch)
+			break;
+	}
+
+	return d;
+}
diff --git a/usr/klibc/strcpy.c b/usr/klibc/strcpy.c
new file mode 100644
index 0000000..aa656cf
--- /dev/null
+++ b/usr/klibc/strcpy.c
@@ -0,0 +1,20 @@
+/*
+ * strcpy.c
+ *
+ * strcpy()
+ */
+
+#include <string.h>
+
+char *strcpy(char *dst, const char *src)
+{
+	char *q = dst;
+	const char *p = src;
+	char ch;
+
+	do {
+		*q++ = ch = *p++;
+	} while (ch);
+
+	return dst;
+}
diff --git a/usr/klibc/strcspn.c b/usr/klibc/strcspn.c
new file mode 100644
index 0000000..bb3ac72
--- /dev/null
+++ b/usr/klibc/strcspn.c
@@ -0,0 +1,10 @@
+/*
+ * strcspn
+ */
+
+#include "strxspn.h"
+
+size_t strcspn(const char *s, const char *reject)
+{
+	return __strxspn(s, reject, 1);
+}
diff --git a/usr/klibc/strdup.c b/usr/klibc/strdup.c
new file mode 100644
index 0000000..905b51d
--- /dev/null
+++ b/usr/klibc/strdup.c
@@ -0,0 +1,17 @@
+/*
+ * strdup.c
+ */
+
+#include <string.h>
+#include <stdlib.h>
+
+char *strdup(const char *s)
+{
+	int l = strlen(s) + 1;
+	char *d = malloc(l);
+
+	if (d)
+		memcpy(d, s, l);
+
+	return d;
+}
diff --git a/usr/klibc/strerror.c b/usr/klibc/strerror.c
new file mode 100644
index 0000000..fed0e49
--- /dev/null
+++ b/usr/klibc/strerror.c
@@ -0,0 +1,33 @@
+/*
+ * strerror.c
+ */
+
+#include <string.h>
+
+char *strerror(int errnum)
+{
+	static char message[32] = "error ";	/* enough for error 2^63-1 */
+	char numbuf[32];
+	char *p;
+	unsigned int e = (unsigned int)errnum;
+
+#ifdef WITH_ERRLIST
+	extern const int sys_nerr;
+	extern const char *const sys_errlist[];
+
+	if (e < (unsigned int)sys_nerr && sys_errlist[e])
+		return (char *)sys_errlist[e];
+#endif
+
+	p = numbuf + sizeof numbuf;
+	*--p = '\0';
+
+	do {
+		*--p = (e % 10) + '0';
+		e /= 10;
+	} while (e);
+
+	memcpy(message + 6, p, (numbuf + sizeof numbuf) - p);
+
+	return message;
+}
diff --git a/usr/klibc/strlcat.c b/usr/klibc/strlcat.c
new file mode 100644
index 0000000..80c3375
--- /dev/null
+++ b/usr/klibc/strlcat.c
@@ -0,0 +1,31 @@
+/*
+ * strlcat.c
+ */
+
+#include <string.h>
+#include <klibc/compiler.h>
+
+size_t strlcat(char *dst, const char *src, size_t size)
+{
+	size_t bytes = 0;
+	char *q = dst;
+	const char *p = src;
+	char ch;
+
+	while (bytes < size && *q) {
+		q++;
+		bytes++;
+	}
+	if (bytes == size)
+		return (bytes + strlen(src));
+
+	while ((ch = *p++)) {
+		if (bytes + 1 < size)
+			*q++ = ch;
+
+		bytes++;
+	}
+
+	*q = '\0';
+	return bytes;
+}
diff --git a/usr/klibc/strlcpy.c b/usr/klibc/strlcpy.c
new file mode 100644
index 0000000..51c72d8
--- /dev/null
+++ b/usr/klibc/strlcpy.c
@@ -0,0 +1,27 @@
+/*
+ * strlcpy.c
+ */
+
+#include <string.h>
+#include <klibc/compiler.h>
+
+size_t strlcpy(char *dst, const char *src, size_t size)
+{
+	size_t bytes = 0;
+	char *q = dst;
+	const char *p = src;
+	char ch;
+
+	while ((ch = *p++)) {
+		if (bytes + 1 < size)
+			*q++ = ch;
+
+		bytes++;
+	}
+
+	/* If size == 0 there is no space for a final null... */
+	if (size)
+		*q = '\0';
+
+	return bytes;
+}
diff --git a/usr/klibc/strlen.c b/usr/klibc/strlen.c
new file mode 100644
index 0000000..86526a5
--- /dev/null
+++ b/usr/klibc/strlen.c
@@ -0,0 +1,13 @@
+/*
+ * strlen()
+ */
+
+#include <string.h>
+
+size_t strlen(const char *s)
+{
+	const char *ss = s;
+	while (*ss)
+		ss++;
+	return ss - s;
+}
diff --git a/usr/klibc/strncasecmp.c b/usr/klibc/strncasecmp.c
new file mode 100644
index 0000000..0551935
--- /dev/null
+++ b/usr/klibc/strncasecmp.c
@@ -0,0 +1,24 @@
+/*
+ * strncasecmp.c
+ */
+
+#include <string.h>
+#include <ctype.h>
+
+int strncasecmp(const char *s1, const char *s2, size_t n)
+{
+	const unsigned char *c1 = (const unsigned char *)s1;
+	const unsigned char *c2 = (const unsigned char *)s2;
+	unsigned char ch;
+	int d = 0;
+
+	while (n--) {
+		/* toupper() expects an unsigned char (implicitly cast to int)
+		   as input, and returns an int, which is exactly what we want. */
+		d = toupper(ch = *c1++) - toupper(*c2++);
+		if (d || !ch)
+			break;
+	}
+
+	return d;
+}
diff --git a/usr/klibc/strncat.c b/usr/klibc/strncat.c
new file mode 100644
index 0000000..beb026c
--- /dev/null
+++ b/usr/klibc/strncat.c
@@ -0,0 +1,22 @@
+/*
+ * strncat.c
+ */
+
+#include <string.h>
+#include <klibc/compiler.h>
+
+char *strncat(char *dst, const char *src, size_t n)
+{
+	char *q = strchr(dst, '\0');
+	const char *p = src;
+	char ch;
+
+	while (n--) {
+		*q++ = ch = *p++;
+		if (!ch)
+			return dst;
+	}
+	*q = '\0';
+
+	return dst;
+}
diff --git a/usr/klibc/strncmp.c b/usr/klibc/strncmp.c
new file mode 100644
index 0000000..5235545
--- /dev/null
+++ b/usr/klibc/strncmp.c
@@ -0,0 +1,21 @@
+/*
+ * strncmp.c
+ */
+
+#include <string.h>
+
+int strncmp(const char *s1, const char *s2, size_t n)
+{
+	const unsigned char *c1 = (const unsigned char *)s1;
+	const unsigned char *c2 = (const unsigned char *)s2;
+	unsigned char ch;
+	int d = 0;
+
+	while (n--) {
+		d = (int)(ch = *c1++) - (int)*c2++;
+		if (d || !ch)
+			break;
+	}
+
+	return d;
+}
diff --git a/usr/klibc/strncpy.c b/usr/klibc/strncpy.c
new file mode 100644
index 0000000..fffc118
--- /dev/null
+++ b/usr/klibc/strncpy.c
@@ -0,0 +1,24 @@
+/*
+ * strncpy.c
+ */
+
+#include <string.h>
+
+char *strncpy(char *dst, const char *src, size_t n)
+{
+	char *q = dst;
+	const char *p = src;
+	char ch;
+
+	while (n) {
+		n--;
+		*q++ = ch = *p++;
+		if (!ch)
+			break;
+	}
+
+	/* The specs say strncpy() fills the entire buffer with NUL.  Sigh. */
+	memset(q, 0, n);
+
+	return dst;
+}
diff --git a/usr/klibc/strndup.c b/usr/klibc/strndup.c
new file mode 100644
index 0000000..8b5974a
--- /dev/null
+++ b/usr/klibc/strndup.c
@@ -0,0 +1,17 @@
+/*
+ * strndup.c
+ */
+
+#include <string.h>
+#include <stdlib.h>
+
+char *strndup(const char *s, size_t n)
+{
+	int l = n > strlen(s) ? strlen(s) + 1 : n + 1;
+	char *d = malloc(l);
+
+	if (d)
+		memcpy(d, s, l);
+	d[n] = '\0';
+	return d;
+}
diff --git a/usr/klibc/strnlen.c b/usr/klibc/strnlen.c
new file mode 100644
index 0000000..1678f4b
--- /dev/null
+++ b/usr/klibc/strnlen.c
@@ -0,0 +1,18 @@
+/*
+ * strnlen()
+ */
+
+#include <string.h>
+
+size_t strnlen(const char *s, size_t maxlen)
+{
+	const char *ss = s;
+
+	/* Important: the maxlen test must precede the reference through ss;
+	   since the byte beyond the maximum may segfault */
+	while ((maxlen > 0) && *ss) {
+		ss++;
+		maxlen--;
+	}
+	return ss - s;
+}
diff --git a/usr/klibc/strntoimax.c b/usr/klibc/strntoimax.c
new file mode 100644
index 0000000..179d9e5
--- /dev/null
+++ b/usr/klibc/strntoimax.c
@@ -0,0 +1,13 @@
+/*
+ * strntoimax.c
+ *
+ * strntoimax()
+ */
+
+#include <stddef.h>
+#include <inttypes.h>
+
+intmax_t strntoimax(const char *nptr, char **endptr, int base, size_t n)
+{
+	return (intmax_t) strntoumax(nptr, endptr, base, n);
+}
diff --git a/usr/klibc/strntoumax.c b/usr/klibc/strntoumax.c
new file mode 100644
index 0000000..3440967
--- /dev/null
+++ b/usr/klibc/strntoumax.c
@@ -0,0 +1,76 @@
+/*
+ * strntoumax.c
+ *
+ * The strntoumax() function and associated
+ */
+
+#include <stddef.h>
+#include <stdint.h>
+#include <ctype.h>
+
+static inline int digitval(int ch)
+{
+	if (ch >= '0' && ch <= '9') {
+		return ch - '0';
+	} else if (ch >= 'A' && ch <= 'Z') {
+		return ch - 'A' + 10;
+	} else if (ch >= 'a' && ch <= 'z') {
+		return ch - 'a' + 10;
+	} else {
+		return -1;
+	}
+}
+
+uintmax_t strntoumax(const char *nptr, char **endptr, int base, size_t n)
+{
+	int minus = 0;
+	uintmax_t v = 0;
+	int d;
+
+	while (n && isspace((unsigned char)*nptr)) {
+		nptr++;
+		n--;
+	}
+
+	/* Single optional + or - */
+	if (n) {
+		char c = *nptr;
+		if (c == '-' || c == '+') {
+			minus = (c == '-');
+			nptr++;
+			n--;
+		}
+	}
+
+	if (base == 0) {
+		if (n >= 2 && nptr[0] == '0' &&
+		    (nptr[1] == 'x' || nptr[1] == 'X')) {
+			n -= 2;
+			nptr += 2;
+			base = 16;
+		} else if (n >= 1 && nptr[0] == '0') {
+			n--;
+			nptr++;
+			base = 8;
+		} else {
+			base = 10;
+		}
+	} else if (base == 16) {
+		if (n >= 2 && nptr[0] == '0' &&
+		    (nptr[1] == 'x' || nptr[1] == 'X')) {
+			n -= 2;
+			nptr += 2;
+		}
+	}
+
+	while (n && (d = digitval(*nptr)) >= 0 && d < base) {
+		v = v * base + d;
+		n--;
+		nptr++;
+	}
+
+	if (endptr)
+		*endptr = (char *)nptr;
+
+	return minus ? -v : v;
+}
diff --git a/usr/klibc/strpbrk.c b/usr/klibc/strpbrk.c
new file mode 100644
index 0000000..ba53d02
--- /dev/null
+++ b/usr/klibc/strpbrk.c
@@ -0,0 +1,12 @@
+/*
+ * strpbrk
+ */
+
+#include "strxspn.h"
+
+char *strpbrk(const char *s, const char *accept)
+{
+	const char *ss = s + __strxspn(s, accept, 1);
+
+	return *ss ? (char *)ss : NULL;
+}
diff --git a/usr/klibc/strrchr.c b/usr/klibc/strrchr.c
new file mode 100644
index 0000000..e36d37e
--- /dev/null
+++ b/usr/klibc/strrchr.c
@@ -0,0 +1,21 @@
+/*
+ * strrchr.c
+ */
+
+#include <string.h>
+#include <klibc/compiler.h>
+
+char *strrchr(const char *s, int c)
+{
+	const char *found = NULL;
+
+	while (*s) {
+		if (*s == (char)c)
+			found = s;
+		s++;
+	}
+
+	return (char *)found;
+}
+
+__ALIAS(char *, rindex, (const char *, int), strrchr)
diff --git a/usr/klibc/strsep.c b/usr/klibc/strsep.c
new file mode 100644
index 0000000..44e76bd
--- /dev/null
+++ b/usr/klibc/strsep.c
@@ -0,0 +1,21 @@
+/*
+ * strsep.c
+ */
+
+#include <string.h>
+
+char *strsep(char **stringp, const char *delim)
+{
+	char *s = *stringp;
+	char *e;
+
+	if (!s)
+		return NULL;
+
+	e = strpbrk(s, delim);
+	if (e)
+		*e++ = '\0';
+
+	*stringp = e;
+	return s;
+}
diff --git a/usr/klibc/strsignal.c b/usr/klibc/strsignal.c
new file mode 100644
index 0000000..e345e9c
--- /dev/null
+++ b/usr/klibc/strsignal.c
@@ -0,0 +1,26 @@
+/*
+ * strsignal.c
+ */
+
+#include <string.h>
+#include <signal.h>
+#include <stdio.h>
+
+char *strsignal(int sig)
+{
+	static char buf[64];
+
+	if ((unsigned)sig < _NSIG && sys_siglist[sig])
+		return (char *)sys_siglist[sig];
+
+#ifdef SIGRTMIN
+	if (sig >= SIGRTMIN && sig <= SIGRTMAX) {
+		snprintf(buf, sizeof buf, "Real-time signal %d",
+			 sig - SIGRTMIN);
+		return buf;
+	}
+#endif
+
+	snprintf(buf, sizeof buf, "Signal %d", sig);
+	return buf;
+}
diff --git a/usr/klibc/strspn.c b/usr/klibc/strspn.c
new file mode 100644
index 0000000..1222ce4
--- /dev/null
+++ b/usr/klibc/strspn.c
@@ -0,0 +1,10 @@
+/*
+ * strspn
+ */
+
+#include "strxspn.h"
+
+size_t strspn(const char *s, const char *accept)
+{
+	return __strxspn(s, accept, 0);
+}
diff --git a/usr/klibc/strstr.c b/usr/klibc/strstr.c
new file mode 100644
index 0000000..8850858
--- /dev/null
+++ b/usr/klibc/strstr.c
@@ -0,0 +1,11 @@
+/*
+ * strstr.c
+ */
+
+#include <string.h>
+
+char *strstr(const char *haystack, const char *needle)
+{
+	return (char *)memmem(haystack, strlen(haystack), needle,
+			      strlen(needle));
+}
diff --git a/usr/klibc/strtoimax.c b/usr/klibc/strtoimax.c
new file mode 100644
index 0000000..0cdd088
--- /dev/null
+++ b/usr/klibc/strtoimax.c
@@ -0,0 +1,3 @@
+#define TYPE intmax_t
+#define NAME strtoimax
+#include "strtox.c"
diff --git a/usr/klibc/strtok.c b/usr/klibc/strtok.c
new file mode 100644
index 0000000..c2671af
--- /dev/null
+++ b/usr/klibc/strtok.c
@@ -0,0 +1,19 @@
+/*
+ * strtok.c
+ */
+
+#include <string.h>
+
+char *strtok(char *s, const char *delim)
+{
+	static char *holder;
+
+	if (s)
+		holder = s;
+
+	do {
+		s = strsep(&holder, delim);
+	} while (s && !*s);
+
+	return s;
+}
diff --git a/usr/klibc/strtol.c b/usr/klibc/strtol.c
new file mode 100644
index 0000000..9efc8b9
--- /dev/null
+++ b/usr/klibc/strtol.c
@@ -0,0 +1,3 @@
+#define TYPE signed long
+#define NAME strtol
+#include "strtox.c"
diff --git a/usr/klibc/strtoll.c b/usr/klibc/strtoll.c
new file mode 100644
index 0000000..a9428c7
--- /dev/null
+++ b/usr/klibc/strtoll.c
@@ -0,0 +1,3 @@
+#define TYPE signed long long
+#define NAME strtoll
+#include "strtox.c"
diff --git a/usr/klibc/strtotimespec.c b/usr/klibc/strtotimespec.c
new file mode 100644
index 0000000..b426bf8
--- /dev/null
+++ b/usr/klibc/strtotimespec.c
@@ -0,0 +1,5 @@
+#define NAME	 strtotimespec
+#define TIMEX	 struct timespec
+#define FSEC	 tv_nsec
+#define DECIMALS 9
+#include "strtotimex.c"
diff --git a/usr/klibc/strtotimeval.c b/usr/klibc/strtotimeval.c
new file mode 100644
index 0000000..280d4bc
--- /dev/null
+++ b/usr/klibc/strtotimeval.c
@@ -0,0 +1,5 @@
+#define NAME	 strtotimeval
+#define TIMEX	 struct timeval
+#define FSEC	 tv_usec
+#define DECIMALS 6
+#include "strtotimex.c"
diff --git a/usr/klibc/strtotimex.c b/usr/klibc/strtotimex.c
new file mode 100644
index 0000000..7f59a4f
--- /dev/null
+++ b/usr/klibc/strtotimex.c
@@ -0,0 +1,39 @@
+/*
+ * strtotimex.c
+ *
+ * Nonstandard function which takes a string and converts it to a
+ * struct timespec/timeval.  Returns a pointer to the first non-numeric
+ * character in the string.
+ *
+ */
+
+#include <ctype.h>
+#include <inttypes.h>
+#include <stdlib.h>
+#include <sys/time.h>
+
+char *NAME(const char *str, TIMEX * ts)
+{
+	int n;
+	char *s, *s0;
+	__typeof__(ts->FSEC) fs;	/* Fractional seconds */
+
+	ts->tv_sec = strntoumax(str, &s, 10, ~(size_t) 0);
+	fs = 0;
+
+	if (*s == '.') {
+		s0 = s + 1;
+
+		fs = strntoumax(s0, &s, 10, DECIMALS);
+		n = s - s0;
+
+		while (isdigit(*s))
+			s++;
+
+		for (; n < DECIMALS; n++)
+			fs *= 10;
+	}
+
+	ts->FSEC = fs;
+	return s;
+}
diff --git a/usr/klibc/strtoul.c b/usr/klibc/strtoul.c
new file mode 100644
index 0000000..3189aaa
--- /dev/null
+++ b/usr/klibc/strtoul.c
@@ -0,0 +1,3 @@
+#define TYPE unsigned long
+#define NAME strtoul
+#include "strtox.c"
diff --git a/usr/klibc/strtoull.c b/usr/klibc/strtoull.c
new file mode 100644
index 0000000..83c14e9
--- /dev/null
+++ b/usr/klibc/strtoull.c
@@ -0,0 +1,3 @@
+#define TYPE unsigned long long
+#define NAME strtoull
+#include "strtox.c"
diff --git a/usr/klibc/strtoumax.c b/usr/klibc/strtoumax.c
new file mode 100644
index 0000000..a379710
--- /dev/null
+++ b/usr/klibc/strtoumax.c
@@ -0,0 +1,3 @@
+#define TYPE uintmax_t
+#define NAME strtoumax
+#include "strtox.c"
diff --git a/usr/klibc/strtox.c b/usr/klibc/strtox.c
new file mode 100644
index 0000000..54bdefc
--- /dev/null
+++ b/usr/klibc/strtox.c
@@ -0,0 +1,13 @@
+/*
+ * strtox.c
+ *
+ * strto...() functions, by macro definition
+ */
+
+#include <stddef.h>
+#include <inttypes.h>
+
+TYPE NAME(const char *nptr, char **endptr, int base)
+{
+	return (TYPE) strntoumax(nptr, endptr, base, ~(size_t) 0);
+}
diff --git a/usr/klibc/strxspn.c b/usr/klibc/strxspn.c
new file mode 100644
index 0000000..99bdbff
--- /dev/null
+++ b/usr/klibc/strxspn.c
@@ -0,0 +1,29 @@
+/*
+ * strpbrk
+ */
+
+#include <string.h>
+#include <stddef.h>
+#include <inttypes.h>
+#include <limits.h>
+#include "strxspn.h"
+
+size_t __strxspn(const char *s, const char *map, int parity)
+{
+	char matchmap[UCHAR_MAX + 1];
+	size_t n = 0;
+
+	/* Create bitmap */
+	memset(matchmap, 0, sizeof matchmap);
+	while (*map)
+		matchmap[(unsigned char)*map++] = 1;
+
+	/* Make sure the null character never matches */
+	matchmap[0] = parity;
+
+	/* Calculate span length */
+	while (matchmap[(unsigned char)*s++] ^ parity)
+		n++;
+
+	return n;
+}
diff --git a/usr/klibc/strxspn.h b/usr/klibc/strxspn.h
new file mode 100644
index 0000000..ce56ff2
--- /dev/null
+++ b/usr/klibc/strxspn.h
@@ -0,0 +1,12 @@
+/*
+ * strxspn.h
+ */
+
+#ifndef STRXSPN_H
+#define STRXSPN_H
+
+#include <stddef.h>
+
+extern size_t __strxspn(const char *s, const char *map, int parity);
+
+#endif
diff --git a/usr/klibc/syscalls.pl b/usr/klibc/syscalls.pl
new file mode 100644
index 0000000..3ff0222
--- /dev/null
+++ b/usr/klibc/syscalls.pl
@@ -0,0 +1,286 @@
+#!/usr/bin/perl
+#
+# Script to parse the SYSCALLS file and generate appropriate
+# stubs.
+#
+# Pass 1: generate the C array of sizes
+# Pass 2: generate the syscall stubs and other output
+#
+
+#
+# Convert a string to a C array of characters,
+# e.g. foo -> 'f','o','o','\0',
+#
+sub chararray($) {
+    use bytes;
+
+    my($s) = @_;
+    my($i, $c);
+    my($a) = '';
+
+    for ($i = 0; $i < length($s); $i++) {
+	$c = substr($s, $i, 1);
+	if (ord($c) < 32 || ord($c) > 126) {
+	    $a .= sprintf("0x%02x,", ord($c));
+	} elsif ($c eq "\\" || $c eq "\'") {
+	    $a .= "\'\\$c\',";
+	} else {
+	    $a .= "\'$c\',";
+	}
+    }
+
+    return $a;
+}
+
+#
+# This extracts an ASCIIZ string for the type and the additional
+# information.  This is open-coded, because unpack("Z*") apparently
+# is broken in Perl 5.6.1.
+#
+sub get_one_type($) {
+    use bytes;
+
+    my($typestr) = @_;
+    my $i, $c;
+    my $l = length($typestr);
+
+    for ($i = 0; $i < $l-3; $i++) {
+	$c = substr($typestr, $i, 1);
+	if ($c eq "\0") {
+	    return (substr($typestr, 0, $i),
+		    unpack("CC", substr($typestr, $i+1, 2)),
+		    substr($typestr, $i+3));
+	}
+    }
+
+    return (undef, undef, undef, undef);
+}
+
+$v = $ENV{'KBUILD_VERBOSE'};
+$quiet = defined($v) && ($v == 0) ? 1 : undef;
+
+@args = ();
+undef $pass;
+for $arg ( @ARGV ) {
+    if ( $arg =~ /^-/ ) {
+	if ( $arg eq '-q' ) {
+	    $quiet = 1;
+	} elsif ( $arg eq '-v' ) {
+	    $quiet = 0;
+	} elsif ( $arg =~ /\-([0-9]+)$/ ) {
+	    $pass = $1+0;
+	} else {
+	    die "$0: Unknown option: $arg\n";
+	}
+    } else {
+	push(@args, $arg);
+    }
+}
+($file, $sysstub, $arch, $bits, $unistd, $outputdir,
+ $havesyscall, $typesize) = @args;
+
+if (!$pass) {
+    die "$0: Need to specify pass\n";
+}
+
+$quiet = ($pass != 2) unless defined($quiet);
+
+require "$sysstub";
+
+if (!open(UNISTD, "< $unistd\0")) {
+    die "$0: $unistd: $!\n";
+}
+
+while ( defined($line = <UNISTD>) ) {
+    chomp $line;
+
+    if ( $line =~ /^\#\s*define\s+__NR_([A-Za-z0-9_]+)\s+(.*\S)\s*$/ ) {
+	$syscalls{$1} = $2;
+	print STDERR "SYSCALL FOUND: $1\n" unless ( $quiet );
+    }
+}
+close(UNISTD);
+
+if ($pass == 2) {
+    use bytes;
+
+    if (!open(TYPESIZE, "< $typesize\0")) {
+	die "$0: $typesize: $!\n";
+    }
+
+    binmode TYPESIZE;
+
+    $len = -s TYPESIZE;
+    if (read(TYPESIZE, $typebin, $len) != $len) {
+	die "$0: $typesize: short read: $!\n";
+    }
+    close(TYPESIZE);
+
+    $ix = index($typebin, "\x7a\xc8\xdb\x4e\x97\xb4\x9c\x19");
+    if ($ix < 0) {
+	die "$0: $typesize: magic number not found\n";
+    }
+
+    # Remove magic number and bytes before it
+    $typebin = substr($typebin, $ix+8);
+
+    # Expand the types until a terminating null
+    %typesize = ();
+    while (1) {
+	my $n, $sz, $si;
+	($n, $sz, $si, $typebin) = get_one_type($typebin);
+	last if (length($n) == 0);
+	$typesize{$n} = $sz;
+	$typesign{$n} = $si;
+	print STDERR "TYPE $n: size $sz, sign $si\n" unless ($quiet);
+    }
+} else {
+    # List here any types which should be sized even if they never occur
+    # in any system calls at all.
+    %type_list = ('int' => 1, 'long' => 1, 'long long' => 1,
+		  'void *' => 1,
+		  'intptr_t' => 1, 'uintptr_t' => 1,
+		  'intmax_t' => 1, 'uintmax_t' => 1);
+}
+
+if ($pass == 2) {
+    if (!open(HAVESYS, "> $havesyscall\0")) {
+	die "$0: $havesyscall: $!\n";
+    }
+
+    print HAVESYS "#ifndef _KLIBC_HAVESYSCALL_H\n";
+    print HAVESYS "#define _KLIBC_HAVESYSCALL_H 1\n\n";
+}
+
+if (!open(FILE, "< $file\0")) {
+    die "$0: $file: $!\n";
+}
+
+
+if ($pass == 2) {
+    print "syscall-objs := ";
+}
+
+
+while ( defined($line = <FILE>) ) {
+    chomp $line;
+    $line =~ s/\s*(|\#.*|\/\/.*)$//; # Strip comments and trailing blanks
+    next unless $line;
+
+    if ( $line =~ /^\s*(\<[^\>]+\>\s+|)([A-Za-z0-9_\*\s]+)\s+([A-Za-z0-9_,]+)(|\@[A-Za-z0-9_]+)(|\:\:[A-Za-z0-9_]+)\s*\(([^\:\)]*)\)\s*\;$/ ) {
+	$archs  = $1;
+	$type   = $2;
+	$snames = $3;
+	$stype  = $4;
+	$fname  = $5;
+	$argv   = $6;
+
+	$doit  = 1;
+	$maybe = 0;
+	if ( $archs ne '' ) {
+	    die "$file:$.: Invalid architecture spec: <$archs>\n"
+		unless ( $archs =~ /^\<(|\?)(|\!)([^\>\!\?]*)\>/ );
+	    $maybe = $1 ne '';
+	    $not = $2 ne '';
+	    $list = $3;
+
+	    $doit = $not || ($list eq '');
+
+	    @list = split(/,/, $list);
+	    foreach  $a ( @list ) {
+		if ( $a eq $arch || $a eq $bits ) {
+		    $doit = !$not;
+		    last;
+		}
+	    }
+	}
+	next if ( ! $doit );
+
+	undef $sname;
+	foreach $sn ( split(/,/, $snames) ) {
+	    if ( defined $syscalls{$sn} ) {
+		$sname = $sn;
+		last;
+	    }
+	}
+	if ( !defined($sname) ) {
+	    next if ( $maybe );
+	    die "$file:$.: Undefined system call: $snames\n";
+	}
+
+	$type  =~ s/\s*$//;
+	$stype =~ s/^\@//;
+
+	if ( $fname eq '' ) {
+	    $fname = $sname;
+	} else {
+	    $fname =~ s/^\:\://;
+	}
+
+	$argv =~ s/^\s+//;
+	$argv =~ s/\s+$//;
+
+	if ($argv eq 'void') {
+	    @args = ();
+	} else {
+	    @args = split(/\s*\,\s*/, $argv);
+	}
+
+	if ($pass == 1) {
+	    # Pass 1: Add the types to the type list
+	    foreach $a (@args) {
+		$type_list{$a}++;
+	    }
+	} else {
+	    # Pass 2: make sure all types defined, and actually generate stubs
+
+	    foreach $a (@args) {
+		if (!defined($typesize{$a})) {
+		    die "$0: $typesize: type name missing: $a\n";
+		}
+	    }
+
+	    print HAVESYS "#define _KLIBC_HAVE_SYSCALL_${fname} ${sname}\n";
+	    print " \\\n\t${fname}.o";
+	    make_sysstub($outputdir, $fname, $type, $sname, $stype, @args);
+	}
+    } else {
+	die "$file:$.: Could not parse input: \"$line\"\n";
+    }
+}
+
+if ($pass == 1) {
+    # Pass 1: generate typesize.c
+    if (!open(TYPESIZE, "> $typesize")) {
+	die "$0: cannot create file: $typesize: $!\n";
+    }
+
+    print TYPESIZE "#include \"syscommon.h\"\n";
+
+    # This compares -2 < 1 in the appropriate type, which is true for
+    # signed types and false for unsigned types.  We use -2 and 1 since
+    # gcc complains about comparing unsigned types with zero, and might
+    # complain equally about -1 in the future.
+    #
+    # This test is valid (as in, doesn't cause the compiler to barf)
+    # for pointers as well as for integral types; if we ever add system
+    # calls which take any other kinds of types than that then this needs
+    # to be smarter.
+    print TYPESIZE "#define SIGNED(X) ((X)-2 < (X)1)\n";
+
+    print TYPESIZE "\n";
+    print TYPESIZE "const unsigned char type_sizes[] = {\n";
+    print TYPESIZE "\t0x7a,0xc8,0xdb,0x4e,0x97,0xb4,0x9c,0x19, /* magic */\n";
+    foreach $t (sort(keys(%type_list))) {
+	print TYPESIZE "\t", chararray($t), "0, sizeof($t), SIGNED($t),\n";
+    }
+    print TYPESIZE "\t0, 0,\n";	# End sentinel
+    print TYPESIZE "};\n";
+    close(TYPESIZE);
+} else {
+    # Pass 2: finalize output files
+    print "\n";
+
+    print HAVESYS "\n#endif\n";
+    close(HAVESYS);
+}
diff --git a/usr/klibc/syscalls/Kbuild b/usr/klibc/syscalls/Kbuild
new file mode 100644
index 0000000..8a5b94d
--- /dev/null
+++ b/usr/klibc/syscalls/Kbuild
@@ -0,0 +1,94 @@
+#
+# kbuild file for generating syscall stubs
+#
+
+# Include automatically generated Makefile fragment.
+# It contains definition of syscall-objs specifying name of all .o files
+ifeq ($(clean),)
+-include $(obj)/syscalls.mk
+endif
+
+# Listing of all .o files
+always := klib.list
+
+
+#####
+# Generate syscalls stubs
+# Based on list in SYSCALLS.def generate stubs for sys calls. Actual arch code
+# is defined in an arch specific perl file
+targets += syscalls.mk
+targets += klib.list
+targets += SYSCALLS.i syscalls.nrs
+targets += typesize.c typesize.o typesize.bin
+targets += $(syscall-objs)
+
+# Side effect of running syscalls.pl
+clean-files += $(objtree)/$(KLIBCINC)/klibc/havesyscall.h
+clean-files += $(KLIBCINC)/klibc/havesyscall.h
+# All the syscall stubs
+clean-files += *.o *.S *.c *.list *.bin
+
+EXTRA_KLIBCCFLAGS := -I$(srctree)/$(src)
+
+quiet_cmd_makelist = LIST    $@
+      cmd_makelist = echo '$(filter-out FORCE,$^)' > $@
+
+# Create list of all files
+$(obj)/klib.list: $(call objectify,$(syscall-objs)) FORCE
+	$(call if_changed,makelist)
+
+# Generate assembler file (.i)
+# We pass -ansi to keep cpp from define e.g. "i386" as well as "__i386__"
+quiet_cmd_syscall.i = GEN     $@
+      cmd_syscall.i = $(KLIBCCC) $(klibccflags) -D__ASSEMBLY__ \
+                                -ansi -x c -E -o $@ $<
+$(obj)/SYSCALLS.i: $(KLIBCSRC)/SYSCALLS.def FORCE
+	$(call if_changed_dep,syscall.i)
+
+# Get syscalls numbers
+quiet_cmd_syscall.nrs = GEN     $@
+      cmd_syscall.nrs = $(KLIBCCC) $(klibccflags) -Wp,-dM -x c -E -o $@ $<
+$(obj)/syscalls.nrs: $(KLIBCINC)/sys/syscall.h FORCE
+	$(call if_changed_dep,syscall.nrs)
+
+# Generate typesize.c
+quiet_cmd_syscalsz = GEN     $@
+      cmd_syscalsz = mkdir -p $(KLIBCINC)/klibc/;                           \
+                     $(PERL) $(KLIBCSRC)/syscalls.pl -1 $(obj)/SYSCALLS.i   \
+                             $(KLIBCSRC)/arch/$(KLIBCARCHDIR)/sysstub.ph    \
+                             $(KLIBCARCH) $(KLIBCBITSIZE) $(obj)/syscalls.nrs \
+                             $(obj)                                         \
+                             $(KLIBCINC)/klibc/havesyscall.h 		    \
+			     $(obj)/typesize.c > $@                      \
+                             || ( rm -f $@ ; exit 1 )
+
+$(obj)/typesize.c: $(KLIBCSRC)/syscalls.pl $(obj)/SYSCALLS.i \
+                      $(KLIBCSRC)/arch/$(KLIBCARCHDIR)/sysstub.ph \
+                      $(src)/syscommon.h $(obj)/syscalls.nrs FORCE
+	$(call if_changed,syscalsz)
+
+# Convert typesize.o to typesize.bin
+quiet_cmd_mkbin = OBJCOPY $@
+      cmd_mkbin = $(KLIBCOBJCOPY) -O binary $< $@
+
+$(obj)/typesize.bin: $(obj)/typesize.o FORCE
+	$(call if_changed,mkbin)
+
+# Generate $(KLIBINC)/klibc/havesyscall.h + makefile fragment
+# Using sysstub.pl in arch dir generate all .S files
+quiet_cmd_syscalls = GEN     $@
+      cmd_syscalls = mkdir -p $(KLIBCINC)/klibc/;                           \
+                     $(PERL) $(KLIBCSRC)/syscalls.pl -2 $(obj)/SYSCALLS.i   \
+                             $(KLIBCSRC)/arch/$(KLIBCARCHDIR)/sysstub.ph    \
+                             $(KLIBCARCH) $(KLIBCBITSIZE) $(obj)/syscalls.nrs \
+                             $(obj)                                         \
+                             $(KLIBCINC)/klibc/havesyscall.h 		    \
+			     $(obj)/typesize.bin > $@                    \
+                             || ( rm -f $@ ; exit 1 )
+
+$(obj)/syscalls.mk: $(KLIBCSRC)/syscalls.pl $(obj)/SYSCALLS.i \
+                    $(KLIBCSRC)/arch/$(KLIBCARCHDIR)/sysstub.ph \
+                    $(call objectify, $(syscall-objs:.o=.S)) \
+                    $(src)/syscommon.h $(obj)/syscalls.nrs \
+		    $(obj)/typesize.bin FORCE
+	$(call if_changed,syscalls)
diff --git a/usr/klibc/syscalls/syscommon.h b/usr/klibc/syscalls/syscommon.h
new file mode 100644
index 0000000..0acae12
--- /dev/null
+++ b/usr/klibc/syscalls/syscommon.h
@@ -0,0 +1,33 @@
+/*
+ * syscommon.h
+ *
+ * Common header file for system call stubs
+ */
+
+#define __IN_SYS_COMMON
+#include <errno.h>
+#include <signal.h>
+#include <sys/types.h>
+#include <sys/syscall.h>
+
+#include <poll.h>
+#include <sched.h>
+#include <sys/dirent.h>
+#include <sys/klog.h>
+#include <sys/mman.h>
+#include <sys/resource.h>
+#include <sys/select.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <sys/times.h>
+#include <sys/uio.h>
+#include <sys/utime.h>
+#include <sys/utsname.h>
+#include <sys/vfs.h>
+#include <sys/wait.h>
+#include <unistd.h>
+
+#ifdef __i386__
+# include <sys/vm86.h>
+#endif
diff --git a/usr/klibc/syslog.c b/usr/klibc/syslog.c
new file mode 100644
index 0000000..4052eaa
--- /dev/null
+++ b/usr/klibc/syslog.c
@@ -0,0 +1,89 @@
+/*
+ * syslog.c
+ *
+ * Issue syslog messages via the kernel printk queue.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdarg.h>
+#include <syslog.h>
+#include <unistd.h>
+#include <fcntl.h>
+
+/* Maximum size for a kernel message */
+#define BUFLEN 1024
+
+/* Logging node */
+#define LOGDEV "/dev/kmsg"
+
+/* Max length of ID string */
+#define MAXID 31		/* MAXID+5 must be < BUFLEN */
+
+int __syslog_fd = -1;
+static char id[MAXID + 1];
+static int syslog_flags = 0;
+
+void openlog(const char *ident, int option, int facility)
+{
+	int fd;
+
+	(void)option;
+	(void)facility;		/* Unused */
+
+	if (__syslog_fd == -1) {
+		__syslog_fd = fd = open(LOGDEV, O_WRONLY);
+		if (fd == -1)
+			return;
+		fcntl(fd, F_SETFD, (long)FD_CLOEXEC);
+	}
+
+	syslog_flags = option;
+
+	strncpy(id, ident ? ident : "", MAXID);
+}
+
+void vsyslog(int prio, const char *format, va_list ap)
+{
+	char buf[BUFLEN];
+	int len;
+	int fd;
+
+	if (__syslog_fd == -1)
+		openlog(NULL, 0, 0);
+
+	buf[0] = '<';
+	buf[1] = LOG_PRI(prio) + '0';
+	buf[2] = '>';
+	len = 3;
+
+	if (syslog_flags & LOG_PID)
+		len += sprintf(buf + 3, "%s[%u]: ", id, getpid());
+	else if (*id)
+		len += sprintf(buf + 3, "%s: ", id);
+
+	len += vsnprintf(buf + len, BUFLEN - len, format, ap);
+
+	if (len > BUFLEN - 1)
+		len = BUFLEN - 1;
+	if (buf[len - 1] != '\n')
+		buf[len++] = '\n';
+
+	fd = __syslog_fd;
+	if (fd == -1)
+		fd = 2;		/* Failed to open log, write to stderr */
+
+	write(fd, buf, len);
+
+	if (syslog_flags & LOG_PERROR)
+		_fwrite(buf + 3, len - 3, stderr);
+}
+
+void syslog(int prio, const char *format, ...)
+{
+	va_list ap;
+
+	va_start(ap, format);
+	vsyslog(prio, format, ap);
+	va_end(ap);
+}
diff --git a/usr/klibc/system.c b/usr/klibc/system.c
new file mode 100644
index 0000000..4478b21
--- /dev/null
+++ b/usr/klibc/system.c
@@ -0,0 +1,61 @@
+/*
+ * system.c
+ *
+ * The system() function.  If this turns out to actually be *used*,
+ * we may want to try to detect the very simple cases (no shell magic)
+ * and handle them internally, instead of requiring that /bin/sh be
+ * present.
+ */
+
+#include <errno.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <signal.h>
+#include <sys/wait.h>
+
+int system(const char *string)
+{
+	pid_t pid;
+	struct sigaction ignore, old_int, old_quit;
+	sigset_t masked, oldmask;
+	static const char *argv[] = { "/bin/sh", "-c", NULL, NULL };
+	int status;
+
+	/* Block SIGCHLD and ignore SIGINT and SIGQUIT */
+	/* Do this before the fork() to avoid races */
+
+	ignore.sa_handler = SIG_IGN;
+	sigemptyset(&ignore.sa_mask);
+	ignore.sa_flags = 0;
+	sigaction(SIGINT, &ignore, &old_int);
+	sigaction(SIGQUIT, &ignore, &old_quit);
+
+	sigemptyset(&masked);
+	sigaddset(&masked, SIGCHLD);
+	sigprocmask(SIG_BLOCK, &masked, &oldmask);
+
+	pid = fork();
+
+	if (pid < 0)
+		return -1;
+	else if (pid == 0) {
+		sigaction(SIGINT, &old_int, NULL);
+		sigaction(SIGQUIT, &old_quit, NULL);
+		sigprocmask(SIG_SETMASK, &oldmask, NULL);
+
+		argv[2] = string;
+
+		execve(argv[0], (char *const *)argv, (char *const *)environ);
+		_exit(127);
+	}
+
+	/* else... */
+
+	waitpid(pid, &status, 0);
+
+	sigaction(SIGINT, &old_int, NULL);
+	sigaction(SIGQUIT, &old_quit, NULL);
+	sigprocmask(SIG_SETMASK, &oldmask, NULL);
+
+	return status;
+}
diff --git a/usr/klibc/sysv_signal.c b/usr/klibc/sysv_signal.c
new file mode 100644
index 0000000..beee7d7
--- /dev/null
+++ b/usr/klibc/sysv_signal.c
@@ -0,0 +1,11 @@
+/*
+ * sysv_signal.c
+ */
+
+#include <signal.h>
+
+__sighandler_t sysv_signal(int signum, __sighandler_t handler)
+{
+	/* Linux/SysV signal() semantics */
+	return __signal(signum, handler, SA_RESETHAND);
+}
diff --git a/usr/klibc/tests/Kbuild b/usr/klibc/tests/Kbuild
new file mode 100644
index 0000000..07e8d64
--- /dev/null
+++ b/usr/klibc/tests/Kbuild
@@ -0,0 +1,50 @@
+#
+# Kbuild file for all test files
+#
+
+test-files := $(wildcard $(srctree)/$(src)/*.c)
+test-files := $(notdir $(test-files))
+
+# This particular file uses a bunch of formats gcc don't know of, in order
+# to test the full range of our vsnprintf() function.  This outputs a bunch
+# of useless warnings unless we tell it not to.
+KLIBCCFLAGS_testvsnp.o := -Wno-format
+
+static-y := $(test-files:.c=)
+shared-y := $(addsuffix .shared, $(static-y))
+
+environ.shared-y	:= environ.o
+fcntl.shared-y		:= fcntl.o
+fnmatch.shared-y	:= fnmatch.o
+getopttest.shared-y	:= getopttest.o
+getoptlong.shared-y	:= getoptlong.o
+getpagesize.shared-y	:= getpagesize.o
+hello.shared-y		:= hello.o
+idtest.shared-y		:= idtest.o
+malloctest.shared-y	:= malloctest.o
+malloctest2.shared-y	:= malloctest2.o
+memstrtest.shared-y	:= memstrtest.o
+microhello.shared-y	:= microhello.o
+minihello.shared-y	:= minihello.o
+mmaptest.shared-y	:= mmaptest.o
+nfs_no_rpc.shared-y	:= nfs_no_rpc.o
+opentest.shared-y	:= opentest.o
+pipetest.shared-y	:= pipetest.o
+rtsig.shared-y		:= rtsig.o
+select.shared-y		:= select.o
+setenvtest.shared-y	:= setenvtest.o
+setjmptest.shared-y	:= setjmptest.o
+sigint.shared-y		:= sigint.o
+stat.shared-y		:= stat.o
+statfs.shared-y		:= statfs.o
+strlcpycat.shared-y	:= strlcpycat.o
+strtoimax.shared-y	:= strtoimax.o
+strtotime.shared-y	:= strtotime.o
+testrand48.shared-y	:= testrand48.o
+testvsnp.shared-y	:= testvsnp.o
+vfork.shared-y		:= vfork.o
+
+# Cleaning
+clean-files := $(static-y) $(shared-y) \
+	$(addsuffix .g, $(static-y) $(shared-y)) \
+	$(test-files:.c=.o)
diff --git a/usr/klibc/tests/environ.c b/usr/klibc/tests/environ.c
new file mode 100644
index 0000000..b5b082d
--- /dev/null
+++ b/usr/klibc/tests/environ.c
@@ -0,0 +1,24 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+
+int main(int argc, char *argv[], char *envp[])
+{
+	int i;
+
+	/* Verify envp == environ */
+	printf("Verifying envp == environ... %s\n",
+	       (envp == environ) ? "ok" : "ERROR");
+
+	/* Test argc/argv */
+	printf("argc = %d, argv = %p\n", argc, argv);
+	for (i = 0; i < argc; i++) {
+		printf("argv[%2d] = %s\n", i, argv[i]);
+	}
+
+	/* Test environ */
+	for (i = 0; envp[i]; i++)
+		printf("%s\n", envp[i]);
+
+	return 0;
+}
diff --git a/usr/klibc/tests/fcntl.c b/usr/klibc/tests/fcntl.c
new file mode 100644
index 0000000..97aa3a7
--- /dev/null
+++ b/usr/klibc/tests/fcntl.c
@@ -0,0 +1,50 @@
+/*
+ * Simple test of fcntl
+ */
+
+#include <stdio.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+
+int main(int argc, char *argv[])
+{
+	int fd = open(argv[0], O_RDONLY);
+	struct flock l;
+	long flags;
+
+	(void)argc;
+
+	if (fd < 0) {
+		perror("open");
+		exit(1);
+	}
+
+	/* Get the flags on this FD */
+
+	if ((flags = fcntl(fd, F_GETFL)) == -1) {
+		perror("F_GETFL");
+		exit(1);
+	}
+
+	if (flags != (O_RDONLY | O_LARGEFILE))
+		fprintf(stderr, "flags = %#lx\n", flags);
+
+	/* Set a lock on this FD */
+	memset(&l, 0, sizeof l);
+	l.l_type = F_RDLCK;
+	l.l_whence = SEEK_SET;
+	l.l_start = 123;
+	l.l_len = 456;
+
+	if (fcntl(fd, F_SETLK, &l) == -1) {
+		perror("F_SETLK");
+		exit(1);
+	}
+
+	/* Eventually, fork and try to conflict with this lock... */
+
+	return 0;
+}
diff --git a/usr/klibc/tests/fnmatch.c b/usr/klibc/tests/fnmatch.c
new file mode 100644
index 0000000..4150857
--- /dev/null
+++ b/usr/klibc/tests/fnmatch.c
@@ -0,0 +1,15 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <fnmatch.h>
+
+int main(int argc, char *argv[])
+{
+	int flags = atoi(argv[3]);
+	int match = fnmatch(argv[1], argv[2], flags);
+
+	printf("\"%s\" matches \"%s\": %d\n", argv[1], argv[2], match);
+
+	return match;
+}
+
+	
diff --git a/usr/klibc/tests/getoptlong.c b/usr/klibc/tests/getoptlong.c
new file mode 100644
index 0000000..c1174abc
--- /dev/null
+++ b/usr/klibc/tests/getoptlong.c
@@ -0,0 +1,57 @@
+/*
+ * getoptlong.c
+ *
+ * Simple test for getopt_long, set the environment variable GETOPTTEST
+ * to give the argument string to getopt()
+ */
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <getopt.h>
+
+static int foo = 0;
+	
+static const struct option long_options[] = {
+	{ "first",   1, NULL, 'f' },
+	{ "second",  0, NULL, 's' },
+	{ "third",   2, NULL, '3' },
+	{ "fourth",  0, NULL,  4 },
+	{ "set-foo", 0, &foo,  1 },
+	{ NULL, 0, NULL, 0 }
+};
+
+int main(int argc, char *const *argv)
+{
+	const char *parser;
+	const char *showchar;
+	char one_char[] = "\'?\'";
+	char num_buf[16];
+	int c;
+	int longindex;
+
+	parser = getenv("GETOPTTEST");
+	if (!parser)
+		parser = "abzf:o:";
+
+	do {
+		c = getopt_long(argc, argv, parser, long_options, &longindex);
+
+		if (c == EOF) {
+			showchar = "EOF";
+		} else if (c >= 32 && c <= 126) {
+			one_char[1] = c;
+			showchar = one_char;
+		} else {
+			snprintf(num_buf, sizeof num_buf, "%d", c);
+			showchar = num_buf;
+		}
+
+		printf("c = %s, optind = %d (\"%s\"), optarg = \"%s\", "
+		       "optopt = \'%c\', foo = %d, longindex = %d\n",
+		       showchar, optind, argv[optind],
+		       optarg, optopt, foo, longindex);
+	} while (c != -1);
+
+	return 0;
+}
diff --git a/usr/klibc/tests/getopttest.c b/usr/klibc/tests/getopttest.c
new file mode 100644
index 0000000..58619d1
--- /dev/null
+++ b/usr/klibc/tests/getopttest.c
@@ -0,0 +1,32 @@
+/*
+ * getopttest.c
+ *
+ * Simple test for getopt, set the environment variable GETOPTTEST
+ * to give the argument string to getopt()
+ */
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <stdio.h>
+
+int main(int argc, char *const *argv)
+{
+	const char *parser;
+	char showchar[] = "\'?\'";
+	int c;
+
+	parser = getenv("GETOPTTEST");
+	if (!parser)
+		parser = "abzf:o:";
+
+	do {
+		c = getopt(argc, argv, parser);
+		showchar[1] = c;
+		printf
+		    ("c = %s, optind = %d (%s), optarg = \"%s\", optopt = \'%c\'\n",
+		     (c == EOF) ? "EOF" : showchar, optind, argv[optind],
+		     optarg, optopt);
+	} while (c != -1);
+
+	return 0;
+}
diff --git a/usr/klibc/tests/getpagesize.c b/usr/klibc/tests/getpagesize.c
new file mode 100644
index 0000000..1ae946a
--- /dev/null
+++ b/usr/klibc/tests/getpagesize.c
@@ -0,0 +1,10 @@
+#include <unistd.h>
+#include <stdio.h>
+
+int main(void)
+{
+	printf("getpagesize()    = %d\n"
+	       "__getpageshift() = %d\n", getpagesize(), __getpageshift());
+
+	return 0;
+}
diff --git a/usr/klibc/tests/hello.c b/usr/klibc/tests/hello.c
new file mode 100644
index 0000000..3f859bd
--- /dev/null
+++ b/usr/klibc/tests/hello.c
@@ -0,0 +1,7 @@
+#include <stdio.h>
+
+int main(void)
+{
+	printf("Hello, World!\n");
+	return 0;
+}
diff --git a/usr/klibc/tests/idtest.c b/usr/klibc/tests/idtest.c
new file mode 100644
index 0000000..c3c4447
--- /dev/null
+++ b/usr/klibc/tests/idtest.c
@@ -0,0 +1,14 @@
+#include <stdio.h>
+#include <unistd.h>
+
+int main(void)
+{
+	printf("pid   = %u\n", getpid());
+	printf("ppid  = %u\n", getppid());
+	printf("uid   = %u\n", getuid());
+	printf("euid  = %u\n", geteuid());
+	printf("gid   = %u\n", getgid());
+	printf("egid  = %u\n", getegid());
+	sleep(10);
+	return 0;
+}
diff --git a/usr/klibc/tests/malloctest.c b/usr/klibc/tests/malloctest.c
new file mode 100644
index 0000000..2ae184e
--- /dev/null
+++ b/usr/klibc/tests/malloctest.c
@@ -0,0 +1,4146 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#define NCYCLES 4096
+
+int sizes[NCYCLES] = {
+	11986,
+	277806,
+	2659,
+	46,
+	0,
+	775553,
+	1991,
+	21,
+	7638,
+	250197,
+	155828,
+	5777,
+	9,
+	315006,
+	900788,
+	0,
+	24893,
+	119996,
+	72299,
+	171266,
+	357,
+	560,
+	368,
+	22952,
+	54058,
+	12638,
+	39155,
+	2738,
+	217563,
+	26853,
+	47,
+	75,
+	1167,
+	16917,
+	1899,
+	2905,
+	9337,
+	62243,
+	14214,
+	270523,
+	4024,
+	21,
+	32,
+	14892,
+	625144,
+	13,
+	21700,
+	8804,
+	254147,
+	0,
+	6,
+	836004,
+	1718,
+	2289,
+	15554,
+	412857,
+	185097,
+	806709,
+	64,
+	18602,
+	17064,
+	1779,
+	78153,
+	170600,
+	199100,
+	546528,
+	0,
+	21,
+	20609,
+	16514,
+	548196,
+	311446,
+	53484,
+	0,
+	551,
+	22225,
+	24,
+	153989,
+	457309,
+	526833,
+	227979,
+	757167,
+	429560,
+	0,
+	835,
+	1702,
+	475275,
+	798416,
+	753,
+	0,
+	11126,
+	145779,
+	2006,
+	0,
+	8182,
+	0,
+	569432,
+	9671,
+	36,
+	5523,
+	407325,
+	0,
+	65,
+	9293,
+	0,
+	6793,
+	468701,
+	73,
+	0,
+	186236,
+	0,
+	328405,
+	125616,
+	508013,
+	380519,
+	599518,
+	83,
+	151973,
+	466906,
+	9029,
+	159725,
+	1316,
+	1,
+	911532,
+	1508,
+	19050,
+	972850,
+	126,
+	439377,
+	29,
+	37928,
+	149628,
+	54,
+	130248,
+	2,
+	143,
+	0,
+	716873,
+	3327,
+	5,
+	116131,
+	5124,
+	559621,
+	2886,
+	534,
+	186432,
+	441,
+	7348,
+	10331,
+	1,
+	260935,
+	7,
+	4370,
+	405415,
+	2,
+	84518,
+	1970,
+	1,
+	281910,
+	46,
+	274,
+	2273,
+	370565,
+	4190,
+	820641,
+	577970,
+	32809,
+	974893,
+	398067,
+	380698,
+	4,
+	25978,
+	153,
+	882668,
+	312365,
+	9523,
+	156421,
+	0,
+	268143,
+	6,
+	2,
+	42987,
+	212,
+	12303,
+	6723,
+	1179,
+	0,
+	120924,
+	3877,
+	330421,
+	310445,
+	39264,
+	8,
+	85380,
+	464716,
+	0,
+	33657,
+	6285,
+	0,
+	4491,
+	229,
+	50,
+	373197,
+	6029,
+	19,
+	86884,
+	243745,
+	335656,
+	90945,
+	38973,
+	572950,
+	164129,
+	0,
+	3,
+	17,
+	13579,
+	4448,
+	47,
+	3,
+	132966,
+	726249,
+	498503,
+	256,
+	0,
+	25841,
+	0,
+	7,
+	945380,
+	11872,
+	69,
+	3799,
+	77223,
+	1914,
+	73,
+	810968,
+	10223,
+	257918,
+	184252,
+	350,
+	8101,
+	725,
+	9,
+	2,
+	2089,
+	175,
+	247,
+	185964,
+	36517,
+	3723,
+	313465,
+	209,
+	1300,
+	128071,
+	7425,
+	2436,
+	62,
+	13753,
+	9514,
+	41,
+	409141,
+	46643,
+	20866,
+	15664,
+	388548,
+	84692,
+	9549,
+	610,
+	7213,
+	14,
+	14930,
+	244719,
+	4748,
+	41682,
+	401098,
+	102506,
+	176535,
+	0,
+	5133,
+	548,
+	5234,
+	56,
+	11101,
+	87638,
+	336579,
+	291705,
+	640250,
+	768165,
+	370,
+	2809,
+	3,
+	0,
+	445122,
+	47190,
+	24885,
+	143556,
+	84,
+	504726,
+	610020,
+	40355,
+	902230,
+	4360,
+	1747,
+	3496,
+	489501,
+	19,
+	801601,
+	62189,
+	48,
+	2645,
+	320601,
+	27304,
+	17740,
+	344,
+	10,
+	991,
+	925503,
+	0,
+	315,
+	251,
+	3611,
+	1756,
+	683,
+	165,
+	380132,
+	181101,
+	453041,
+	892056,
+	67191,
+	252592,
+	32407,
+	56242,
+	8,
+	297173,
+	542903,
+	830334,
+	585236,
+	422555,
+	44769,
+	0,
+	68,
+	4143,
+	38754,
+	73539,
+	44579,
+	94001,
+	428537,
+	38554,
+	106612,
+	0,
+	182987,
+	831731,
+	3605,
+	752851,
+	52,
+	72,
+	120872,
+	963754,
+	31,
+	764,
+	240592,
+	99101,
+	328538,
+	440325,
+	12211,
+	151282,
+	353436,
+	2991,
+	40710,
+	5212,
+	5106,
+	139122,
+	148915,
+	498505,
+	1366,
+	516,
+	29190,
+	17,
+	224208,
+	40,
+	89,
+	19190,
+	8,
+	25377,
+	10029,
+	720,
+	97963,
+	0,
+	614,
+	244567,
+	2113,
+	903675,
+	8388,
+	6,
+	390705,
+	325006,
+	284272,
+	108086,
+	17,
+	2628,
+	952530,
+	20474,
+	898276,
+	138661,
+	3883,
+	903,
+	569993,
+	376918,
+	5849,
+	103404,
+	794499,
+	35388,
+	5,
+	0,
+	961626,
+	27415,
+	1927,
+	92036,
+	46241,
+	35978,
+	7426,
+	399884,
+	29490,
+	252655,
+	675971,
+	3509,
+	54170,
+	170790,
+	831341,
+	134579,
+	0,
+	790422,
+	35,
+	930830,
+	97394,
+	20265,
+	670,
+	38497,
+	1759,
+	71209,
+	93,
+	736,
+	11,
+	886,
+	1961,
+	7,
+	210607,
+	62226,
+	186736,
+	1518,
+	5,
+	5,
+	13,
+	66989,
+	442321,
+	0,
+	607939,
+	11253,
+	210875,
+	495530,
+	2,
+	221136,
+	377663,
+	372,
+	200658,
+	18591,
+	129783,
+	803411,
+	867506,
+	757446,
+	48836,
+	34,
+	200,
+	114983,
+	7287,
+	22849,
+	226669,
+	13,
+	0,
+	20164,
+	7828,
+	39,
+	49448,
+	26740,
+	185566,
+	9927,
+	36192,
+	91068,
+	338368,
+	926,
+	27746,
+	534794,
+	936132,
+	2922,
+	5,
+	183162,
+	256846,
+	242551,
+	134318,
+	212959,
+	167162,
+	470,
+	477045,
+	532116,
+	483794,
+	733,
+	5335,
+	83074,
+	4686,
+	9567,
+	1,
+	195100,
+	40354,
+	87338,
+	369,
+	800,
+	0,
+	194504,
+	469051,
+	363532,
+	850574,
+	5085,
+	167027,
+	794511,
+	124320,
+	303231,
+	132195,
+	13225,
+	46333,
+	4313,
+	89,
+	799,
+	51482,
+	0,
+	26,
+	12659,
+	1045,
+	23621,
+	0,
+	74926,
+	490979,
+	6,
+	3188,
+	9448,
+	174730,
+	38982,
+	102317,
+	189621,
+	853,
+	29227,
+	43374,
+	423,
+	420951,
+	686,
+	128,
+	31291,
+	0,
+	402819,
+	663143,
+	55903,
+	142,
+	2,
+	331584,
+	197164,
+	7,
+	671983,
+	53,
+	5020,
+	9782,
+	123,
+	743407,
+	1276,
+	1115,
+	1169,
+	122752,
+	824690,
+	292030,
+	2094,
+	144626,
+	0,
+	297278,
+	440,
+	742,
+	95879,
+	17682,
+	10654,
+	31,
+	22183,
+	746,
+	0,
+	0,
+	11185,
+	28,
+	394987,
+	36,
+	474,
+	243749,
+	1431,
+	56702,
+	76,
+	15619,
+	33071,
+	12181,
+	158647,
+	261786,
+	1,
+	119783,
+	48816,
+	6278,
+	4121,
+	61122,
+	69,
+	48790,
+	345335,
+	275917,
+	964393,
+	424,
+	586433,
+	20519,
+	18156,
+	756400,
+	27736,
+	458706,
+	1,
+	3286,
+	929624,
+	1883,
+	2,
+	1086,
+	439501,
+	552,
+	157132,
+	5565,
+	105061,
+	8199,
+	23,
+	178797,
+	0,
+	130644,
+	1,
+	6952,
+	754,
+	500,
+	647683,
+	0,
+	959079,
+	622561,
+	1131,
+	559783,
+	6862,
+	175420,
+	408671,
+	463461,
+	55908,
+	606496,
+	169,
+	49060,
+	247,
+	953,
+	333030,
+	0,
+	23399,
+	29193,
+	9303,
+	15,
+	515402,
+	34961,
+	365856,
+	633043,
+	173,
+	556089,
+	1809,
+	12215,
+	14,
+	316,
+	20642,
+	9,
+	15,
+	190391,
+	951463,
+	25059,
+	13654,
+	385040,
+	4272,
+	929033,
+	208813,
+	35166,
+	42849,
+	662648,
+	254811,
+	4230,
+	812459,
+	681,
+	390168,
+	5381,
+	4662,
+	173257,
+	478863,
+	103,
+	89332,
+	0,
+	0,
+	589484,
+	19369,
+	94,
+	9,
+	639917,
+	1110,
+	393,
+	101040,
+	911,
+	152899,
+	0,
+	2,
+	0,
+	0,
+	335691,
+	43694,
+	62273,
+	200121,
+	2250,
+	621004,
+	149918,
+	41063,
+	218229,
+	0,
+	497924,
+	16832,
+	587071,
+	0,
+	0,
+	729918,
+	2,
+	808513,
+	9417,
+	718,
+	0,
+	2769,
+	28704,
+	1335,
+	734726,
+	219157,
+	786230,
+	981004,
+	350788,
+	884529,
+	0,
+	87872,
+	34647,
+	85469,
+	4524,
+	339838,
+	38228,
+	0,
+	4151,
+	1145,
+	0,
+	351,
+	167956,
+	810075,
+	689,
+	251212,
+	583068,
+	2929,
+	189456,
+	2089,
+	48749,
+	278952,
+	77134,
+	0,
+	0,
+	45595,
+	281829,
+	969602,
+	43999,
+	69824,
+	856982,
+	61732,
+	336,
+	25488,
+	213,
+	46683,
+	1909,
+	174097,
+	57930,
+	91466,
+	828418,
+	95740,
+	378828,
+	128065,
+	68068,
+	0,
+	13312,
+	26006,
+	6760,
+	51,
+	276081,
+	640068,
+	634985,
+	7131,
+	784882,
+	790126,
+	628585,
+	205824,
+	764965,
+	17793,
+	3159,
+	649924,
+	0,
+	37383,
+	9919,
+	353,
+	0,
+	149003,
+	620629,
+	95928,
+	2560,
+	504343,
+	1000,
+	32,
+	43836,
+	407031,
+	207,
+	800894,
+	3222,
+	51028,
+	7,
+	6,
+	22010,
+	0,
+	21174,
+	12893,
+	824932,
+	7305,
+	70,
+	624258,
+	372139,
+	21504,
+	387996,
+	418931,
+	914268,
+	576,
+	0,
+	0,
+	618224,
+	787516,
+	133014,
+	422,
+	383124,
+	656318,
+	4420,
+	6082,
+	244813,
+	38585,
+	3200,
+	1,
+	2,
+	11882,
+	113,
+	45581,
+	13121,
+	95475,
+	807219,
+	8195,
+	995116,
+	13,
+	2146,
+	369925,
+	60103,
+	25,
+	125165,
+	51300,
+	4894,
+	173261,
+	74186,
+	1044,
+	122992,
+	1243,
+	21703,
+	26294,
+	197,
+	333825,
+	426872,
+	719580,
+	3598,
+	106,
+	0,
+	9932,
+	61509,
+	146,
+	721428,
+	964781,
+	319850,
+	573802,
+	7458,
+	317889,
+	0,
+	133086,
+	87836,
+	60496,
+	304249,
+	1565,
+	27,
+	42,
+	899324,
+	189637,
+	8648,
+	104570,
+	901598,
+	447765,
+	24,
+	108,
+	120127,
+	828626,
+	8,
+	899514,
+	28,
+	13,
+	7576,
+	163390,
+	1625,
+	3023,
+	155175,
+	2,
+	391,
+	1,
+	493073,
+	398,
+	210771,
+	26266,
+	287999,
+	38255,
+	249666,
+	598202,
+	119601,
+	216933,
+	91205,
+	0,
+	7247,
+	77077,
+	565383,
+	29102,
+	253641,
+	48855,
+	19722,
+	463536,
+	40182,
+	65393,
+	829444,
+	598402,
+	1590,
+	798,
+	467,
+	834847,
+	3007,
+	13711,
+	0,
+	195,
+	101662,
+	255749,
+	129201,
+	11965,
+	1781,
+	13349,
+	3100,
+	718066,
+	99,
+	712450,
+	888215,
+	42503,
+	43171,
+	494946,
+	0,
+	2175,
+	12387,
+	25662,
+	78,
+	739030,
+	0,
+	19,
+	427526,
+	4275,
+	5583,
+	0,
+	2447,
+	132398,
+	26437,
+	3873,
+	440035,
+	21,
+	6,
+	35432,
+	41523,
+	7179,
+	712703,
+	428868,
+	2793,
+	6,
+	286277,
+	1882,
+	95116,
+	2959,
+	86,
+	115425,
+	81386,
+	59836,
+	37,
+	247598,
+	34732,
+	249,
+	500110,
+	5589,
+	40319,
+	575,
+	12145,
+	385829,
+	565600,
+	582150,
+	92,
+	223209,
+	0,
+	910,
+	1048,
+	47329,
+	90944,
+	235,
+	8739,
+	686685,
+	1753,
+	126,
+	434,
+	609477,
+	25021,
+	6610,
+	52675,
+	4,
+	717846,
+	150864,
+	418583,
+	17751,
+	513794,
+	181362,
+	329556,
+	10426,
+	717019,
+	457,
+	616,
+	388984,
+	17,
+	8338,
+	59531,
+	32,
+	99565,
+	376146,
+	134578,
+	966,
+	0,
+	0,
+	174,
+	2105,
+	555,
+	8990,
+	298,
+	169932,
+	247281,
+	240918,
+	298655,
+	158743,
+	15994,
+	95708,
+	51,
+	2985,
+	4294,
+	731934,
+	185640,
+	1483,
+	87,
+	742033,
+	9,
+	1345,
+	3680,
+	133530,
+	9355,
+	800111,
+	28508,
+	0,
+	369,
+	31681,
+	24,
+	8237,
+	313380,
+	4732,
+	275423,
+	951592,
+	0,
+	41381,
+	225515,
+	393004,
+	526,
+	187,
+	19515,
+	6006,
+	28923,
+	310151,
+	2390,
+	374,
+	0,
+	19142,
+	72,
+	114,
+	193305,
+	24035,
+	397067,
+	18,
+	14839,
+	3473,
+	164,
+	104622,
+	378958,
+	2218,
+	0,
+	89053,
+	105183,
+	312265,
+	82146,
+	147210,
+	3419,
+	5178,
+	34948,
+	46836,
+	41319,
+	842825,
+	595972,
+	0,
+	249625,
+	325,
+	608,
+	372328,
+	119634,
+	7504,
+	920214,
+	7302,
+	444532,
+	359213,
+	27265,
+	1755,
+	48,
+	126799,
+	651270,
+	818220,
+	799493,
+	724024,
+	64047,
+	73699,
+	206999,
+	209,
+	1581,
+	0,
+	42937,
+	301144,
+	73416,
+	0,
+	242058,
+	29660,
+	3,
+	34709,
+	162719,
+	2863,
+	3992,
+	5212,
+	151814,
+	3092,
+	198001,
+	44331,
+	36,
+	407,
+	364771,
+	1349,
+	502772,
+	214726,
+	607,
+	388583,
+	137660,
+	337124,
+	13279,
+	10549,
+	943075,
+	164068,
+	19157,
+	38443,
+	26351,
+	0,
+	67167,
+	735,
+	46486,
+	130305,
+	232330,
+	744,
+	882337,
+	2,
+	69275,
+	126354,
+	9370,
+	2845,
+	299,
+	38988,
+	37834,
+	0,
+	306433,
+	9139,
+	237132,
+	0,
+	500,
+	13462,
+	373684,
+	107453,
+	381924,
+	347915,
+	4329,
+	1668,
+	3960,
+	370661,
+	3614,
+	636048,
+	0,
+	487449,
+	64925,
+	333894,
+	11,
+	52192,
+	531200,
+	155554,
+	461,
+	1547,
+	994361,
+	11955,
+	321056,
+	37425,
+	14249,
+	69151,
+	621862,
+	174,
+	79607,
+	34,
+	77577,
+	13723,
+	267550,
+	13801,
+	698,
+	12,
+	171556,
+	57354,
+	676845,
+	0,
+	24965,
+	908955,
+	570483,
+	0,
+	296387,
+	983966,
+	85012,
+	130298,
+	151946,
+	384474,
+	731455,
+	150699,
+	772,
+	216131,
+	346,
+	130935,
+	3472,
+	18,
+	426045,
+	677262,
+	808,
+	17030,
+	5188,
+	0,
+	491153,
+	67299,
+	19,
+	60342,
+	69,
+	0,
+	76478,
+	95763,
+	0,
+	28778,
+	147869,
+	335927,
+	27846,
+	2163,
+	22750,
+	162,
+	23,
+	11391,
+	469099,
+	5852,
+	63,
+	0,
+	0,
+	22193,
+	165,
+	489007,
+	9249,
+	12477,
+	2841,
+	223532,
+	13877,
+	173,
+	3570,
+	45477,
+	233073,
+	23296,
+	64377,
+	4910,
+	8,
+	76246,
+	411147,
+	287411,
+	10450,
+	3667,
+	1,
+	500933,
+	31363,
+	257,
+	1705,
+	6036,
+	49934,
+	13738,
+	13485,
+	61608,
+	561978,
+	76493,
+	16377,
+	1817,
+	0,
+	235600,
+	0,
+	16347,
+	680478,
+	5115,
+	895607,
+	138270,
+	369912,
+	53110,
+	0,
+	647083,
+	85,
+	458681,
+	163227,
+	52767,
+	196,
+	267719,
+	14047,
+	147293,
+	814457,
+	174896,
+	0,
+	34138,
+	36,
+	21575,
+	3,
+	0,
+	0,
+	38391,
+	2597,
+	2,
+	1433,
+	3807,
+	36476,
+	287,
+	141530,
+	29389,
+	495655,
+	30014,
+	0,
+	550766,
+	11958,
+	348,
+	226760,
+	15,
+	251353,
+	675788,
+	518308,
+	215,
+	81987,
+	409862,
+	559596,
+	114283,
+	4925,
+	0,
+	17,
+	14221,
+	0,
+	162,
+	766370,
+	4898,
+	998,
+	493,
+	138418,
+	265159,
+	12152,
+	5229,
+	1204,
+	1814,
+	432530,
+	2889,
+	144,
+	1149,
+	35886,
+	636931,
+	6640,
+	1508,
+	414118,
+	858,
+	20039,
+	17398,
+	3,
+	5094,
+	6,
+	13996,
+	6754,
+	362,
+	451487,
+	11471,
+	7896,
+	330009,
+	244269,
+	99928,
+	0,
+	14311,
+	9949,
+	15251,
+	283923,
+	123754,
+	188360,
+	93902,
+	854384,
+	548001,
+	531788,
+	26298,
+	328479,
+	941,
+	246535,
+	106320,
+	28769,
+	440,
+	4,
+	61262,
+	55615,
+	170,
+	989327,
+	692534,
+	8063,
+	445842,
+	4434,
+	255349,
+	117781,
+	6,
+	9249,
+	136216,
+	38165,
+	307012,
+	12,
+	2341,
+	18062,
+	371882,
+	662154,
+	12623,
+	176847,
+	332220,
+	590935,
+	33682,
+	0,
+	121374,
+	67,
+	46841,
+	495890,
+	640,
+	19,
+	14737,
+	11032,
+	17,
+	5993,
+	302562,
+	827710,
+	165346,
+	49607,
+	87863,
+	308513,
+	735300,
+	1914,
+	2900,
+	207308,
+	9068,
+	83494,
+	179,
+	417,
+	41605,
+	74681,
+	652171,
+	4013,
+	29811,
+	13966,
+	8136,
+	78,
+	61182,
+	674187,
+	0,
+	331121,
+	0,
+	18559,
+	386,
+	77,
+	348439,
+	975358,
+	18,
+	33700,
+	47396,
+	204751,
+	2350,
+	26503,
+	0,
+	83653,
+	446,
+	10844,
+	485,
+	9241,
+	88347,
+	232419,
+	936900,
+	43250,
+	2,
+	26112,
+	811955,
+	20723,
+	102069,
+	42255,
+	8431,
+	119508,
+	4080,
+	13565,
+	12,
+	46110,
+	62096,
+	638777,
+	44025,
+	152985,
+	13362,
+	3,
+	12331,
+	193337,
+	56419,
+	14593,
+	3837,
+	282314,
+	403454,
+	48589,
+	135,
+	18350,
+	2160,
+	90,
+	918216,
+	7083,
+	105534,
+	742826,
+	399028,
+	1470,
+	23770,
+	480,
+	677884,
+	340472,
+	107406,
+	0,
+	5002,
+	445,
+	748948,
+	534012,
+	592464,
+	6539,
+	819632,
+	3138,
+	4,
+	39397,
+	229683,
+	12204,
+	2439,
+	65131,
+	817226,
+	22596,
+	0,
+	1046,
+	94638,
+	0,
+	95403,
+	1230,
+	790056,
+	19976,
+	43085,
+	14251,
+	139187,
+	20232,
+	693,
+	3058,
+	27654,
+	65690,
+	40948,
+	15001,
+	21089,
+	14425,
+	322459,
+	13571,
+	228154,
+	536814,
+	761221,
+	28030,
+	2322,
+	921,
+	1,
+	1137,
+	187815,
+	8,
+	34911,
+	4527,
+	15,
+	46,
+	78801,
+	0,
+	73605,
+	44,
+	28233,
+	1370,
+	73409,
+	198159,
+	66586,
+	3,
+	2576,
+	15,
+	35460,
+	263237,
+	44997,
+	2873,
+	240,
+	1781,
+	269,
+	46,
+	272778,
+	28404,
+	8232,
+	417073,
+	234591,
+	9,
+	720349,
+	1176,
+	16195,
+	0,
+	9705,
+	0,
+	14,
+	947048,
+	163,
+	76288,
+	1115,
+	267020,
+	3416,
+	414217,
+	441004,
+	95131,
+	765002,
+	6196,
+	9069,
+	27017,
+	137039,
+	65247,
+	266489,
+	484945,
+	187008,
+	45405,
+	5700,
+	9,
+	7751,
+	12,
+	294,
+	3093,
+	6350,
+	103303,
+	6045,
+	252345,
+	140207,
+	22390,
+	234867,
+	443326,
+	1,
+	0,
+	89972,
+	8637,
+	427150,
+	22146,
+	0,
+	310432,
+	390333,
+	10461,
+	1632,
+	31403,
+	908653,
+	0,
+	6543,
+	163479,
+	67608,
+	195543,
+	315889,
+	822964,
+	383536,
+	954954,
+	1619,
+	241,
+	96053,
+	104556,
+	767302,
+	2469,
+	12,
+	164330,
+	78,
+	141,
+	170519,
+	268214,
+	53338,
+	48342,
+	721,
+	58980,
+	4345,
+	1,
+	856265,
+	87289,
+	57219,
+	775679,
+	123992,
+	695804,
+	113025,
+	832,
+	117420,
+	16634,
+	352,
+	24729,
+	14973,
+	25622,
+	131290,
+	0,
+	22,
+	87740,
+	5917,
+	533,
+	2934,
+	34261,
+	9174,
+	0,
+	1656,
+	764587,
+	54652,
+	35597,
+	36389,
+	577889,
+	63957,
+	26808,
+	34556,
+	56,
+	15641,
+	137,
+	1,
+	3,
+	11724,
+	197397,
+	39027,
+	87902,
+	320,
+	791479,
+	7,
+	487864,
+	0,
+	433,
+	25733,
+	6956,
+	15407,
+	312557,
+	526302,
+	383019,
+	340215,
+	96,
+	276158,
+	6493,
+	135613,
+	2000,
+	1218,
+	930,
+	276808,
+	273249,
+	8896,
+	397,
+	735095,
+	20648,
+	2079,
+	5349,
+	205,
+	356313,
+	841954,
+	8255,
+	266874,
+	0,
+	965,
+	287993,
+	1549,
+	207833,
+	75,
+	178180,
+	39072,
+	0,
+	43254,
+	3847,
+	227,
+	2712,
+	161043,
+	463264,
+	74720,
+	795789,
+	12,
+	6812,
+	202804,
+	29379,
+	64241,
+	132121,
+	790622,
+	493588,
+	0,
+	48,
+	147352,
+	925197,
+	38149,
+	18380,
+	0,
+	270280,
+	633,
+	3373,
+	31294,
+	7830,
+	0,
+	0,
+	11371,
+	56143,
+	5393,
+	74724,
+	495109,
+	0,
+	18993,
+	21524,
+	0,
+	53889,
+	400509,
+	204563,
+	0,
+	11625,
+	9635,
+	0,
+	1678,
+	12096,
+	59,
+	817112,
+	10002,
+	128209,
+	11593,
+	17313,
+	15200,
+	106796,
+	261401,
+	707077,
+	0,
+	314030,
+	798591,
+	14175,
+	5668,
+	2766,
+	0,
+	566,
+	5543,
+	24112,
+	154482,
+	5642,
+	0,
+	38410,
+	3,
+	4,
+	700724,
+	25024,
+	5,
+	407,
+	564150,
+	672,
+	143,
+	2049,
+	574708,
+	65858,
+	213412,
+	3797,
+	511,
+	30907,
+	1212,
+	765,
+	2127,
+	481,
+	130048,
+	113816,
+	39861,
+	153169,
+	503378,
+	523944,
+	111,
+	55083,
+	698,
+	275,
+	3,
+	3195,
+	1657,
+	0,
+	317881,
+	6672,
+	543,
+	153011,
+	77240,
+	9338,
+	889850,
+	29518,
+	872485,
+	181927,
+	376086,
+	266,
+	409,
+	4,
+	14856,
+	31943,
+	2448,
+	8,
+	75,
+	383097,
+	294366,
+	0,
+	173084,
+	753160,
+	66457,
+	725783,
+	51,
+	127651,
+	1073,
+	12598,
+	140080,
+	0,
+	296375,
+	581720,
+	217346,
+	8272,
+	2051,
+	185390,
+	520645,
+	1260,
+	13873,
+	168040,
+	19690,
+	103347,
+	295011,
+	548404,
+	48,
+	4,
+	916417,
+	1948,
+	621365,
+	263245,
+	2792,
+	86803,
+	181193,
+	558081,
+	50907,
+	442770,
+	51448,
+	340276,
+	1346,
+	607,
+	459627,
+	0,
+	30,
+	73298,
+	15389,
+	12264,
+	2719,
+	2936,
+	143043,
+	209970,
+	0,
+	42,
+	6657,
+	317419,
+	0,
+	32622,
+	524000,
+	0,
+	310331,
+	303778,
+	268710,
+	9,
+	10410,
+	25343,
+	949506,
+	784353,
+	3861,
+	46823,
+	251292,
+	75008,
+	269798,
+	87731,
+	112813,
+	571679,
+	385,
+	3,
+	2811,
+	36025,
+	9243,
+	935128,
+	906,
+	10688,
+	25,
+	86757,
+	307,
+	55,
+	22,
+	2,
+	61,
+	620426,
+	484530,
+	633806,
+	0,
+	1342,
+	9293,
+	992181,
+	503,
+	195433,
+	46150,
+	893091,
+	3207,
+	2865,
+	72894,
+	830299,
+	355,
+	327479,
+	0,
+	35573,
+	3068,
+	15699,
+	31187,
+	55378,
+	416067,
+	91721,
+	159,
+	0,
+	255139,
+	2104,
+	19,
+	606757,
+	323,
+	902659,
+	365655,
+	400,
+	903,
+	408,
+	385,
+	21774,
+	701290,
+	234426,
+	17020,
+	950,
+	0,
+	0,
+	429,
+	1245,
+	405871,
+	1097,
+	280634,
+	74,
+	158233,
+	1583,
+	180333,
+	42114,
+	575973,
+	539327,
+	59252,
+	121928,
+	165,
+	148501,
+	55757,
+	7494,
+	127728,
+	7832,
+	68504,
+	619770,
+	70995,
+	312816,
+	7307,
+	38265,
+	46248,
+	363304,
+	269442,
+	77112,
+	448331,
+	910442,
+	474418,
+	152752,
+	752,
+	104912,
+	408492,
+	691709,
+	632381,
+	48519,
+	20524,
+	344294,
+	14670,
+	0,
+	21607,
+	81162,
+	181458,
+	0,
+	908322,
+	7261,
+	10888,
+	58054,
+	1788,
+	970933,
+	5925,
+	121553,
+	36152,
+	588267,
+	23615,
+	1850,
+	30728,
+	3599,
+	1319,
+	6027,
+	0,
+	32141,
+	984156,
+	436781,
+	15003,
+	621407,
+	9412,
+	562911,
+	189740,
+	377895,
+	656800,
+	197,
+	14413,
+	99382,
+	384,
+	11480,
+	0,
+	86118,
+	881961,
+	1905,
+	82061,
+	4140,
+	741153,
+	26,
+	687,
+	12251,
+	10945,
+	209267,
+	220602,
+	135881,
+	6,
+	237945,
+	158,
+	5,
+	76303,
+	81344,
+	986042,
+	956063,
+	30282,
+	186055,
+	357802,
+	12492,
+	577476,
+	838,
+	0,
+	11,
+	117602,
+	0,
+	187928,
+	96860,
+	4268,
+	3478,
+	818264,
+	1649,
+	17175,
+	272,
+	158951,
+	440987,
+	677594,
+	14935,
+	37953,
+	0,
+	198,
+	160404,
+	12,
+	287803,
+	2386,
+	10,
+	271663,
+	319152,
+	361322,
+	68370,
+	428,
+	182707,
+	387429,
+	1152,
+	360065,
+	25218,
+	2790,
+	42228,
+	13,
+	110942,
+	452491,
+	1,
+	665638,
+	2308,
+	1196,
+	87306,
+	66,
+	219,
+	0,
+	130736,
+	334,
+	605,
+	5979,
+	2681,
+	0,
+	123463,
+	11219,
+	283681,
+	19269,
+	553,
+	6217,
+	130965,
+	714409,
+	242,
+	674833,
+	237581,
+	133284,
+	683,
+	1758,
+	278193,
+	518726,
+	44,
+	420361,
+	325228,
+	14955,
+	10,
+	11994,
+	64157,
+	1937,
+	20214,
+	848,
+	27804,
+	151341,
+	79236,
+	316393,
+	158883,
+	1196,
+	334,
+	22797,
+	185955,
+	13857,
+	397357,
+	7948,
+	6038,
+	0,
+	2621,
+	16,
+	155267,
+	44809,
+	9171,
+	21328,
+	12212,
+	40200,
+	2600,
+	439,
+	804014,
+	10938,
+	96135,
+	43696,
+	158715,
+	4,
+	284558,
+	191,
+	270254,
+	7923,
+	880603,
+	21032,
+	107700,
+	172,
+	700823,
+	5613,
+	78816,
+	258290,
+	214398,
+	821856,
+	295325,
+	0,
+	1,
+	23559,
+	63895,
+	21249,
+	717490,
+	956952,
+	944819,
+	793,
+	356,
+	757716,
+	111773,
+	394826,
+	25665,
+	4358,
+	640216,
+	1152,
+	37175,
+	150192,
+	106071,
+	28992,
+	67,
+	1685,
+	134242,
+	2,
+	102045,
+	1457,
+	419589,
+	6789,
+	677,
+	94675,
+	11300,
+	2595,
+	8,
+	926535,
+	265194,
+	0,
+	886048,
+	246242,
+	1494,
+	191,
+	169985,
+	649765,
+	0,
+	201,
+	1069,
+	679163,
+	16627,
+	274639,
+	84438,
+	3,
+	1301,
+	247496,
+	5879,
+	710904,
+	403652,
+	958241,
+	361,
+	139732,
+	6042,
+	15985,
+	2378,
+	267031,
+	223767,
+	9656,
+	241717,
+	33863,
+	14314,
+	205697,
+	1274,
+	168000,
+	621777,
+	837913,
+	89654,
+	659829,
+	69,
+	503884,
+	432717,
+	70443,
+	110891,
+	19655,
+	132432,
+	620401,
+	428,
+	0,
+	425662,
+	0,
+	0,
+	0,
+	194489,
+	7601,
+	26870,
+	0,
+	63,
+	594,
+	12278,
+	582479,
+	213723,
+	424489,
+	96446,
+	990664,
+	46966,
+	44137,
+	829810,
+	104,
+	19707,
+	16,
+	0,
+	2499,
+	167075,
+	140972,
+	249283,
+	6620,
+	68368,
+	856414,
+	9255,
+	14315,
+	0,
+	11432,
+	24329,
+	216463,
+	299556,
+	818401,
+	246607,
+	697733,
+	229,
+	144,
+	389394,
+	664634,
+	0,
+	19393,
+	657903,
+	52912,
+	952177,
+	536931,
+	187271,
+	17687,
+	970155,
+	232571,
+	234016,
+	159980,
+	13510,
+	32952,
+	0,
+	0,
+	24132,
+	18806,
+	15624,
+	28364,
+	472126,
+	626978,
+	599,
+	112843,
+	502933,
+	915660,
+	63920,
+	0,
+	84,
+	10899,
+	904823,
+	126,
+	469132,
+	590052,
+	195831,
+	443113,
+	294149,
+	15944,
+	2271,
+	282974,
+	211,
+	0,
+	22934,
+	82283,
+	49973,
+	41707,
+	87530,
+	0,
+	910528,
+	0,
+	36029,
+	423337,
+	817512,
+	223671,
+	27800,
+	398847,
+	198528,
+	1,
+	560679,
+	518270,
+	23033,
+	501059,
+	0,
+	3909,
+	272062,
+	261581,
+	187,
+	52043,
+	334,
+	24354,
+	3947,
+	8549,
+	37863,
+	328851,
+	963771,
+	1,
+	3930,
+	82416,
+	6,
+	2943,
+	122101,
+	82577,
+	85,
+	89540,
+	5135,
+	109236,
+	18297,
+	1,
+	177371,
+	4541,
+	769577,
+	178,
+	417,
+	960566,
+	33803,
+	911651,
+	248160,
+	153725,
+	43981,
+	809174,
+	116,
+	486900,
+	4842,
+	148490,
+	131534,
+	4347,
+	239949,
+	984096,
+	749756,
+	429499,
+	2794,
+	78209,
+	18812,
+	21111,
+	490,
+	328042,
+	12,
+	132119,
+	505103,
+	353148,
+	0,
+	373656,
+	951244,
+	491,
+	355778,
+	30620,
+	317,
+	60175,
+	220,
+	214496,
+	41249,
+	5169,
+	78367,
+	506804,
+	0,
+	1368,
+	407,
+	295126,
+	1288,
+	86,
+	97614,
+	61640,
+	244723,
+	3,
+	0,
+	869827,
+	527246,
+	52,
+	107036,
+	240739,
+	780281,
+	113084,
+	62009,
+	740343,
+	483201,
+	8649,
+	16419,
+	1,
+	801574,
+	95524,
+	326126,
+	26912,
+	877040,
+	10262,
+	5895,
+	0,
+	132633,
+	59171,
+	306347,
+	702701,
+	196245,
+	12642,
+	32723,
+	24608,
+	30287,
+	45775,
+	18281,
+	7587,
+	144532,
+	5,
+	35,
+	99862,
+	215127,
+	170875,
+	61461,
+	77790,
+	5,
+	0,
+	129358,
+	0,
+	105084,
+	21399,
+	42233,
+	85397,
+	480654,
+	555988,
+	89575,
+	42346,
+	20004,
+	11102,
+	21321,
+	185,
+	379267,
+	849147,
+	121514,
+	3388,
+	33662,
+	12,
+	164898,
+	226,
+	274,
+	385003,
+	365052,
+	693376,
+	41245,
+	9010,
+	41594,
+	89835,
+	10490,
+	272,
+	128437,
+	0,
+	122648,
+	277,
+	116505,
+	38372,
+	4,
+	1376,
+	0,
+	46317,
+	139368,
+	36398,
+	193899,
+	30632,
+	26371,
+	7548,
+	367643,
+	954849,
+	25889,
+	36567,
+	176,
+	140631,
+	4690,
+	975031,
+	80965,
+	500471,
+	8442,
+	43,
+	27758,
+	301501,
+	3797,
+	80,
+	384440,
+	928477,
+	4960,
+	24566,
+	33245,
+	14638,
+	228354,
+	54347,
+	861285,
+	12841,
+	2,
+	157402,
+	646747,
+	53763,
+	1,
+	214732,
+	49471,
+	49757,
+	998,
+	201135,
+	566,
+	73512,
+	194240,
+	391773,
+	21510,
+	13,
+	829894,
+	783200,
+	565329,
+	2101,
+	12,
+	191043,
+	1621,
+	18443,
+	279,
+	294135,
+	526503,
+	729735,
+	4639,
+	444138,
+	5835,
+	12372,
+	46362,
+	1543,
+	870907,
+	83262,
+	0,
+	38331,
+	95,
+	1194,
+	909,
+	8053,
+	453066,
+	845561,
+	411,
+	3229,
+	1,
+	158,
+	1431,
+	835137,
+	21774,
+	7298,
+	148388,
+	224649,
+	379318,
+	520138,
+	39781,
+	172130,
+	362634,
+	487495,
+	51957,
+	158,
+	1770,
+	7,
+	18010,
+	1063,
+	171484,
+	19924,
+	279867,
+	469956,
+	189785,
+	0,
+	814,
+	60580,
+	944349,
+	18743,
+	553235,
+	0,
+	95475,
+	99,
+	0,
+	5,
+	42623,
+	178418,
+	398940,
+	5700,
+	69023,
+	5786,
+	0,
+	10531,
+	551,
+	86308,
+	63451,
+	32704,
+	176903,
+	0,
+	251689,
+	11589,
+	25711,
+	43437,
+	1431,
+	304,
+	52965,
+	34816,
+	268688,
+	47756,
+	825323,
+	122608,
+	81246,
+	69974,
+	360515,
+	99973,
+	143015,
+	5063,
+	4499,
+	34459,
+	171982,
+	677943,
+	489082,
+	257515,
+	3765,
+	5,
+	7416,
+	602206,
+	74122,
+	3,
+	686204,
+	5493,
+	28901,
+	11349,
+	549668,
+	257082,
+	82000,
+	17031,
+	1517,
+	7442,
+	937160,
+	722,
+	0,
+	72952,
+	377192,
+	438266,
+	555,
+	31436,
+	284,
+	56390,
+	0,
+	585856,
+	27635,
+	519344,
+	126131,
+	360273,
+	845073,
+	0,
+	191965,
+	55652,
+	23,
+	112773,
+	639025,
+	84749,
+	0,
+	330822,
+	7173,
+	126217,
+	871,
+	112112,
+	0,
+	664,
+	530474,
+	1,
+	379564,
+	172617,
+	647308,
+	0,
+	356,
+	17,
+	84345,
+	457,
+	0,
+	8,
+	6,
+	136602,
+	634424,
+	0,
+	177298,
+	100726,
+	91661,
+	383792,
+	1665,
+	43583,
+	15775,
+	4083,
+	4277,
+	345749,
+	969599,
+	65804,
+	19327,
+	0,
+	352514,
+	4225,
+	9,
+	103767,
+	0,
+	0,
+	148436,
+	850,
+	33,
+	2146,
+	20153,
+	50,
+	9063,
+	50329,
+	348379,
+	2569,
+	83697,
+	37073,
+	715486,
+	629,
+	4753,
+	442,
+	259203,
+	287223,
+	48625,
+	9,
+	70184,
+	45946,
+	144947,
+	0,
+	60285,
+	28640,
+	7626,
+	134159,
+	33,
+	12452,
+	150566,
+	348293,
+	124426,
+	353952,
+	11,
+	22,
+	776742,
+	29072,
+	132168,
+	254533,
+	319957,
+	1602,
+	1659,
+	209341,
+	32847,
+	92392,
+	753005,
+	1392,
+	10271,
+	28557,
+	6717,
+	941745,
+	0,
+	0,
+	0,
+	78645,
+	45320,
+	11193,
+	1448,
+	130626,
+	377907,
+	795535,
+	24285,
+	26094,
+	266691,
+	64449,
+	77400,
+	191410,
+	1,
+	1346,
+	25224,
+	489637,
+	47052,
+	248592,
+	76689,
+	0,
+	7722,
+	47285,
+	3152,
+	285577,
+	0,
+	149366,
+	264346,
+	1,
+	208602,
+	320459,
+	131771,
+	1421,
+	350,
+	723283,
+	714934,
+	0,
+	566439,
+	11656,
+	34189,
+	125484,
+	943273,
+	15,
+	7789,
+	0,
+	7427,
+	464278,
+	680924,
+	651102,
+	87794,
+	39640,
+	838644,
+	964500,
+	1,
+	1765,
+	272604,
+	10,
+	837347,
+	44845,
+	130,
+	163357,
+	4150,
+	403331,
+	839132,
+	44876,
+	272792,
+	592527,
+	57225,
+	128826,
+	2915,
+	2,
+	3570,
+	2410,
+	199,
+	171358,
+	5931,
+	53620,
+	55299,
+	1868,
+	24123,
+	165,
+	346513,
+	16527,
+	133,
+	517412,
+	195700,
+	730365,
+	896209,
+	152760,
+	24577,
+	65,
+	8218,
+	349642,
+	901345,
+	5127,
+	5102,
+	238318,
+	955,
+	631921,
+	12218,
+	55101,
+	930381,
+	219503,
+	469237,
+	132,
+	16701,
+	494,
+	199729,
+	0,
+	32139,
+	314,
+	172,
+	2947,
+	106997,
+	4871,
+	236,
+	6146,
+	1843,
+	128,
+	0,
+	254240,
+	2964,
+	14825,
+	60624,
+	2108,
+	286953,
+	654931,
+	0,
+	0,
+	396587,
+	19852,
+	70311,
+	363561,
+	282,
+	17966,
+	924254,
+	104173,
+	130816,
+	179096,
+	105466,
+	136,
+	618261,
+	358433,
+	25587,
+	49357,
+	102,
+	133746,
+	620776,
+	17084,
+	406881,
+	802675,
+	349,
+	69,
+	8761,
+	278482,
+	16336,
+	128,
+	160096,
+	25857,
+	280,
+	39639,
+	726299,
+	293905,
+	4621,
+	41,
+	649,
+	3655,
+	269286,
+	578026,
+	0,
+	11156,
+	1,
+	744858,
+	531,
+	48155,
+	28435,
+	7991,
+	447,
+	10201,
+	379341,
+	0,
+	5773,
+	0,
+	295,
+	228592,
+	331155,
+	104089,
+	628069,
+	29693,
+	22,
+	13,
+	0,
+	0,
+	554349,
+	6082,
+	238,
+	23,
+	151873,
+	805937,
+	0,
+	194076,
+	6450,
+	3,
+	128322,
+	69149,
+	95511,
+	86,
+	844368,
+	415964,
+	51985,
+	308686,
+	553403,
+	624943,
+	365800,
+	4,
+	120263,
+	91239,
+	195248,
+	58010,
+	19,
+	415112,
+	136806,
+	42,
+	571848,
+	55306,
+	29454,
+	3,
+	144926,
+	189,
+	0,
+	161943,
+	592155,
+	10930,
+	279297,
+	56932,
+	957430,
+	10244,
+	190296,
+	807209,
+	781,
+	1466,
+	235055,
+	33,
+	196,
+	58280,
+	436,
+	408649,
+	221,
+	711143,
+	10495,
+	2441,
+	275720,
+	2,
+	15391,
+	132107,
+	102610,
+	688549,
+	237142,
+	3041,
+	14,
+	308623,
+	0,
+	0,
+	287,
+	295147,
+	61443,
+	229,
+	207,
+	2051,
+	64,
+	13479,
+	55656,
+	570134,
+	50387,
+	225869,
+	20615,
+	258465,
+	64932,
+	112461,
+	164521,
+	907269,
+	758563,
+	22901,
+	0,
+	7944,
+	48,
+	154921,
+	2784,
+	548608,
+	0,
+	12524,
+	142556,
+	0,
+	13882,
+	507227,
+	316598,
+	987551,
+	0,
+	894687,
+	1964,
+	364,
+	10316,
+	440269,
+	9,
+	776723,
+	72288,
+	54604,
+	185101,
+	142,
+	362,
+	11679,
+	77,
+	79,
+	529321,
+	364,
+	42387,
+	0,
+	570879,
+	417503,
+	604871,
+	578806,
+	1102,
+	66584,
+	615440,
+	146744,
+	19441,
+	170478,
+	144069,
+	36170,
+	145376,
+	842283,
+	193612,
+	3,
+	359429,
+	368596,
+	0,
+	11064,
+	7726,
+	229410,
+	63569,
+	67402,
+	91,
+	203201,
+	213513,
+	0,
+	704479,
+	1325,
+	0,
+	385154,
+	13,
+	806763,
+	197132,
+	6183,
+	45760,
+	99377,
+	0,
+	972077,
+	4043,
+	195700,
+	34229,
+	0,
+	154027,
+	633,
+	6,
+	32142,
+	0,
+	29,
+	620842,
+	14099,
+	495465,
+	26937,
+	0,
+	0,
+	432,
+	227704,
+	0,
+	63,
+	0,
+	19,
+	863491,
+	20,
+	1,
+	160713,
+	24607,
+	85800,
+	3566,
+	37854,
+	81913,
+	121573,
+	816,
+	20,
+	133253,
+	692231,
+	4869,
+	255175,
+	15028,
+	9383,
+	542877,
+	4608,
+	369610,
+	243635,
+	385285,
+	391565,
+	286009,
+	0,
+	61685,
+	416318,
+	208,
+	67019,
+	788416,
+	88,
+	165056,
+	0,
+	439589,
+	160,
+	105528,
+	152,
+	160624,
+	865,
+	390229,
+	714086,
+	6007,
+	30229,
+	481306,
+	173266,
+	1135,
+	2266,
+	8,
+	59,
+	104722,
+	647885,
+	579471,
+	21309,
+	230834,
+	140278,
+	31858,
+	3288,
+	36011,
+	151387,
+	594217,
+	22439,
+	418638,
+	76859,
+	29363,
+	154809,
+	275533,
+	39,
+	472996,
+	22076,
+	7481,
+	155705,
+	10406,
+	214779,
+	223,
+	1312,
+	16391,
+	17203,
+	55605,
+	44579,
+	69332,
+	303,
+	19217,
+	26288,
+	126212,
+	316,
+	98,
+	114,
+	37382,
+	137591,
+	439749,
+	12972,
+	54,
+	154879,
+	0,
+	102680,
+	7639,
+	309119,
+	263550,
+	766,
+	1124,
+	56,
+	686608,
+	123767,
+	518054,
+	18,
+	672385,
+	3161,
+	53791,
+	26769,
+	451670,
+	61,
+	148245,
+	2713,
+	96725,
+	4794,
+	33247,
+	297946,
+	33380,
+	0,
+	20034,
+	5647,
+	17227,
+	76444,
+	0,
+	21011,
+	675,
+	13226,
+	1027,
+	990842,
+	124459,
+	34406,
+	53,
+	69540,
+	134,
+	0,
+	168521,
+	6,
+	4075,
+	1137,
+	63740,
+	220,
+	10434,
+	1171,
+	28950,
+	0,
+	79680,
+	993269,
+	355622,
+	15,
+	0,
+	1452,
+	21667,
+	22208,
+	494484,
+	33984,
+	691308,
+	10,
+	693686,
+	196,
+	9,
+	70676,
+	157660,
+	775,
+	165,
+	468432,
+	1083,
+	515154,
+	778344,
+	70241,
+	42,
+	40931,
+	277125,
+	43837,
+	301881,
+	1332,
+	56712,
+	9013,
+	1299,
+	7564,
+	31092,
+	1975,
+	113517,
+	833295,
+	245021,
+	36503,
+	23586,
+	149327,
+	89175,
+	10512,
+	484348,
+	187793,
+	954609,
+	53199,
+	792175,
+	126,
+	12369,
+	405,
+	0,
+	6614,
+	322857,
+	166,
+	571874,
+	60839,
+	180975,
+	146722,
+	411565,
+	1536,
+	1,
+	11,
+	116230,
+	60514,
+	9003,
+	2325,
+	43763,
+	63,
+	355553,
+	0,
+	389876,
+	14672,
+	11526,
+	160209,
+	65,
+	10283,
+	966,
+	10,
+	58333,
+	129920,
+	2850,
+	83346,
+	0,
+	14,
+	295819,
+	679550,
+	143928,
+	29489,
+	82324,
+	36558,
+	267118,
+	143313,
+	90107,
+	12789,
+	951,
+	0,
+	187619,
+	295317,
+	82,
+	41326,
+	309682,
+	907327,
+	809358,
+	324,
+	139157,
+	12,
+	78366,
+	671811,
+	354,
+	131,
+	70525,
+	35830,
+	281018,
+	91456,
+	92523,
+	54874,
+	48273,
+	2423,
+	0,
+	81,
+	361314,
+	374811,
+	394758,
+	15350,
+	795,
+	3,
+	16779,
+	796684,
+	477556,
+	73927,
+	26643,
+	119281,
+	62692,
+	17039,
+	454778,
+	952,
+	48973,
+	19529,
+	151,
+	239121,
+	93509,
+	254702,
+	1307,
+	10029,
+	7973,
+	546706,
+	806644,
+	680517,
+	223,
+	0,
+	2,
+	0,
+	402421,
+	619193,
+	15685,
+	2,
+	939715,
+	519198,
+	0,
+	444312,
+	23204,
+	35669,
+	32467,
+	0,
+	799725,
+	5883,
+	2217,
+	32292,
+	355557,
+	22179,
+	1066,
+	15704,
+	610,
+	37819,
+	403626,
+	83101,
+	10989,
+	311607,
+	43394,
+	72576,
+	335450,
+	85964,
+	73734,
+	105142,
+	38292,
+	0,
+	181516,
+	33959,
+	611797,
+	221838,
+	5931,
+	7666,
+	1044,
+	477173,
+	13591,
+	405,
+	521,
+	190653,
+	184191,
+	0,
+	215,
+	847195,
+	22782,
+	11912,
+	27345,
+	2572,
+	0,
+	566350,
+	7,
+	52302,
+	26641,
+	587826,
+	127,
+	2,
+	44449,
+	153198,
+	14,
+	926,
+	285,
+	0,
+	938196,
+	52255,
+	9153,
+	807,
+	12548,
+	358324,
+	18521,
+	104956,
+	42738,
+	116,
+	135772,
+	189554,
+	38,
+	54,
+	36,
+	89768,
+	17170,
+	75,
+	34502,
+	45489,
+	172796,
+	971810,
+	16153,
+	499280,
+	1,
+	879663,
+	53830,
+	186,
+	539,
+	242059,
+	268,
+	402,
+	2732,
+	68057,
+	18463,
+	198560,
+	10068,
+	591753,
+	6116,
+	699280,
+	1,
+	0,
+	114258,
+	277,
+	149,
+	283821,
+	352561,
+	88172,
+	684476,
+	3450,
+	87,
+	99936,
+	3155,
+	72983,
+	31619,
+	8832,
+	58666,
+	0,
+	59023,
+	306091,
+	352150,
+	255063,
+	992708,
+	23,
+	4896,
+	18165,
+	424401,
+	227613,
+	5175,
+	347,
+	139846,
+	11962,
+	714,
+	3501,
+	82367,
+	11110,
+	10,
+	12874,
+	0,
+	0,
+	222712,
+	169,
+	123281,
+	0,
+	268149,
+	101,
+	17446,
+	4262,
+	489,
+	0,
+	30,
+	0,
+	277235,
+	28,
+	71,
+	23,
+	61219,
+	953631,
+	477548,
+	662491,
+	273,
+	44787,
+	4130,
+	14483,
+	470571,
+	735977,
+	406648,
+	815898,
+	5985,
+	462696,
+	937510,
+	9,
+	0,
+	111727,
+	93,
+	331435,
+	336402,
+	78690,
+	49,
+	0,
+	87422,
+	1242,
+	0,
+	8783,
+	8540,
+	314,
+	33411,
+	805718,
+	247,
+	6870,
+	523743,
+	8323,
+	612593,
+	430,
+	354048,
+	264913,
+	83,
+	114063,
+	202825,
+	35202,
+	32823,
+	185554,
+	85760,
+	45159,
+	5971,
+	267733,
+	4545,
+	116,
+	6910,
+	24833,
+	218,
+	922362,
+	221735,
+	740,
+	7112,
+	31,
+	15739,
+	523589,
+	4,
+	95996,
+	936,
+	823951,
+	0,
+	88,
+	160,
+	375419,
+	663627,
+	3741,
+	22896,
+	114326,
+	415962,
+	880100,
+	6222,
+	18650,
+	35524,
+	195076,
+	506,
+	451640,
+	541336,
+	70903,
+	3946,
+	1,
+	61765,
+	1,
+	2696,
+	753129,
+	289,
+	225234,
+	378692,
+	1703,
+	6751,
+	1,
+	820,
+	7677,
+	589,
+	12412,
+	317,
+	69,
+	226031,
+	134523,
+	318253,
+	66677,
+	111025,
+	96,
+	0,
+	96,
+	523528,
+	1017,
+	0,
+	258740,
+	420947,
+	4600,
+	400684,
+	12174,
+	11770,
+	52,
+	5959,
+	82658,
+	531787,
+	202,
+	548430,
+	964,
+	1054,
+	34,
+	96897,
+	25445,
+	47609,
+	386052,
+	97004,
+	1935,
+	30074,
+	13458,
+	494105,
+	54,
+	65575,
+	594698,
+	2340,
+	20259,
+	84,
+	2774,
+	534,
+	972534,
+	115057,
+	0,
+	11379,
+	0,
+	271,
+	266305,
+	132595,
+	2,
+	773561,
+	52365,
+	3585,
+	351,
+	148206,
+	778964,
+	149379,
+	596,
+	284914,
+	2900,
+	35596,
+	1547,
+	212027,
+	8100,
+	12248,
+	3013,
+	1814,
+	183415,
+	273633,
+	15812,
+	0,
+	966680,
+	14830,
+	134309,
+	0,
+	416450,
+	206611,
+	816,
+	82258,
+	9873,
+	3155,
+	53485,
+	779805,
+	107690,
+	254475,
+	102504,
+	72495,
+	17301,
+	472130,
+	6895,
+	245420,
+	7299,
+	110508,
+	27776,
+	246134,
+	0,
+	330853,
+	0,
+	271767,
+	61886,
+	24123,
+	309681,
+	58325,
+	608865,
+	20666,
+	87349,
+	229228,
+	246,
+	457768,
+	5374,
+	69643,
+	148,
+	618375,
+	45236,
+	352565,
+	133904,
+	152,
+	10688,
+	18,
+	0,
+	276036,
+	493281,
+	11156,
+	12566,
+	5762,
+	113,
+	24179,
+	98,
+	327,
+	893,
+	209180,
+	140805,
+	0,
+	2341,
+	66309,
+	30305,
+	630559,
+	3682,
+	152767,
+	265822,
+	142868,
+	1535,
+	728603,
+	69081,
+	353151,
+	237995,
+	1075,
+	925071,
+	86,
+	6748,
+	0,
+	684186,
+	735,
+	13793,
+	4790,
+	73175,
+	69677,
+	367627,
+	238650,
+	303543,
+	1,
+	26059,
+	21392,
+	10,
+	288609,
+	0,
+	76345,
+	158496,
+	7000,
+	1865,
+	20385,
+	0,
+	54213,
+	9948,
+	102667,
+	6963,
+	71,
+	555744,
+	5626,
+	2512,
+	1124,
+	7171,
+	628,
+	29225,
+	321687,
+	61519,
+	4,
+	8352,
+	9156,
+};
+
+char *pointers[NCYCLES];
+
+int main(void)
+{
+	int r, i, j, sp, sq;
+	char *p, *q, *ep, *eq;
+	int ok;
+	int err = 0;
+
+	for (r = 0; r < 4; r++) {
+		for (i = 0; i < NCYCLES; i++) {
+			pointers[i] = p = malloc(sp = sizes[i]);
+			ep = p + sp;
+			ok = 1;
+			for (j = 0; j < i; j++) {
+				q = pointers[j];
+				sq = sizes[j];
+				eq = q + sq;
+
+				if ((p < q && ep > q) || (p >= q && p < eq)) {
+					ok = 0;
+					err = 1;
+					break;
+				}
+			}
+			printf("Allocated %6d bytes at %p, ok = %d\n", sp, p,
+			       ok);
+
+			if (p)
+				memset(p, 0xee, sp);	/* Poison this memory */
+		}
+
+		for (i = 0; i < NCYCLES; i++) {
+			free(pointers[i]);
+			printf("Freed %6d bytes at %p\n", sizes[i],
+			       pointers[i]);
+		}
+	}
+
+	return err;
+}
diff --git a/usr/klibc/tests/malloctest2.c b/usr/klibc/tests/malloctest2.c
new file mode 100644
index 0000000..1845073
--- /dev/null
+++ b/usr/klibc/tests/malloctest2.c
@@ -0,0 +1,62 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#define NCYCLES 32768
+#define NSLOTS  4096
+
+struct slot {
+	char *ptr;
+	size_t size;
+};
+
+struct slot s[NSLOTS];
+
+int main(void)
+{
+	size_t sp, sq;
+	char *p, *ep, *q, *eq;
+	int r, i, j;
+	int ok;
+	int err = 0;
+
+	for (r = 0; r < NCYCLES; r++) {
+		i = lrand48() % NSLOTS;
+
+		if (s[i].ptr) {
+			free(s[i].ptr);
+			printf("Freed     %8zu bytes at %p\n", s[i].size,
+			       s[i].ptr);
+			s[i].ptr = NULL;
+			s[i].size = 0;
+		} else {
+			sp = lrand48();	/* 32-bit random number */
+			sp >>= 12 + (lrand48() % 20);
+
+			s[i].size = sp;
+			s[i].ptr = p = malloc(sp);
+			ep = p + sp;
+			ok = 1;
+			for (j = 0; j < NSLOTS; j++) {
+				q = s[j].ptr;
+				if (i != j && q) {
+					sq = s[j].size;
+					eq = q + sq;
+
+					if ((p < q && ep > q)
+					    || (p >= q && p < eq)) {
+						ok = 0;
+						err = 1;
+						break;
+					}
+				}
+			}
+			printf("Allocated %8zu bytes at %p, ok = %d\n", sp, p,
+			       ok);
+
+			if (p)
+				memset(p, 0xee, sp);	/* Poison this memory */
+		}
+	}
+	return err;
+}
diff --git a/usr/klibc/tests/memstrtest.c b/usr/klibc/tests/memstrtest.c
new file mode 100644
index 0000000..8d473fb
--- /dev/null
+++ b/usr/klibc/tests/memstrtest.c
@@ -0,0 +1,28 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+int main(void)
+{
+	unsigned char t1[256], t2[256];
+	int i;
+	int r;
+
+	for (i = 0; i < (int)sizeof(t1); i++)
+		t1[i] = t2[i] = (unsigned char)i;
+
+	r = memcmp(t1, t2, sizeof(t1));
+	printf("memcmp r = %d\n", r);
+	r = memcmp(t1, t2, sizeof(t1) / 2);
+	printf("memcmp r = %d\n", r);
+	t1[255] = 0;
+	r = memcmp(t1, t2, sizeof(t1));
+	printf("memcmp r = %d\n", r);
+
+	for (i = 0; i < (int)sizeof(t1); i++)
+		t1[i] = 0xaa;
+	memset(t2, 0xaa, sizeof(t2));
+	r = memcmp(t1, t2, sizeof(t1));
+	printf("memcmp r = %d\n", r);
+	return 0;
+}
diff --git a/usr/klibc/tests/microhello.c b/usr/klibc/tests/microhello.c
new file mode 100644
index 0000000..c999d11
--- /dev/null
+++ b/usr/klibc/tests/microhello.c
@@ -0,0 +1,9 @@
+#include <stdio.h>
+#include <unistd.h>
+
+int main(void)
+{
+	static const char hello[] = "Hello, World!\n";
+	_fwrite(hello, sizeof hello - 1, stdout);
+	return 0;
+}
diff --git a/usr/klibc/tests/minihello.c b/usr/klibc/tests/minihello.c
new file mode 100644
index 0000000..ae9072e
--- /dev/null
+++ b/usr/klibc/tests/minihello.c
@@ -0,0 +1,7 @@
+#include <stdio.h>
+
+int main(void)
+{
+	fputs("Hello, World!\n", stdout);
+	return 0;
+}
diff --git a/usr/klibc/tests/mmaptest.c b/usr/klibc/tests/mmaptest.c
new file mode 100644
index 0000000..eac04e8
--- /dev/null
+++ b/usr/klibc/tests/mmaptest.c
@@ -0,0 +1,73 @@
+/*
+ * mmaptest.c
+ *
+ * Test some simple cases of mmap()
+ */
+
+#include <sys/mman.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <errno.h>
+#include <stdint.h>
+#include <fcntl.h>
+
+static void make_test_file(int fd)
+{
+	unsigned long v;
+	FILE *f = fdopen(fd, "wb");
+
+	for (v = 0; v < 262144; v += sizeof(v))
+		_fwrite(&v, sizeof(v), f);
+}
+
+int main(int argc, char *argv[])
+{
+	void *foo;
+	char *test_file = (argc > 1) ? argv[1] : "/tmp/mmaptest.tmp";
+	int rv, fd;
+
+	/* Important case, this is how we get memory for malloc() */
+	errno = 0;
+	foo = mmap(NULL, 65536, PROT_READ | PROT_WRITE,
+		   MAP_PRIVATE | MAP_ANONYMOUS, 0, 0);
+
+	printf("mmap() returned %p, errno = %d\n", foo, errno);
+	if (foo == MAP_FAILED)
+		return 1;
+
+	rv = munmap(foo, 65536);
+	printf("munmap() returned %d, errno = %d\n", rv, errno);
+	if (rv)
+		return 1;
+
+	/* Create test file */
+	fd = open(test_file, O_RDWR | O_CREAT | O_TRUNC, 0666);
+	if (fd < 0) {
+		perror(test_file);
+		return 1;
+	}
+
+	make_test_file(fd);
+
+	/* Map test file */
+	foo = mmap(NULL, 65536, PROT_READ, MAP_SHARED, fd, 131072);
+	printf("mmap() returned %p, errno = %d\n", foo, errno);
+	if (foo == MAP_FAILED)
+		return 1;
+
+	if (*(unsigned long *)foo != 131072) {
+		printf("mmap() with offset returned the wrong offset %ld!\n",
+		       *(unsigned long *)foo);
+		return 1;
+	}
+
+	if (munmap(foo, 65536)) {
+		printf("munmap() returned nonzero, errno = %d\n", errno);
+		return 1;
+	}
+
+	close(fd);
+	unlink(test_file);
+
+	return 0;
+}
diff --git a/usr/klibc/tests/opentest.c b/usr/klibc/tests/opentest.c
new file mode 100644
index 0000000..8be7b3d
--- /dev/null
+++ b/usr/klibc/tests/opentest.c
@@ -0,0 +1,15 @@
+#include <stdio.h>
+
+int main(void)
+{
+	char buffer[1024];
+	FILE *f;
+
+	f = fopen("/etc/passwd", "r");
+	fgets(buffer, 1024, f);
+	fclose(f);
+
+	printf("Line 1 = %s", buffer);
+
+	return 0;
+}
diff --git a/usr/klibc/tests/pipetest.c b/usr/klibc/tests/pipetest.c
new file mode 100644
index 0000000..0e49721
--- /dev/null
+++ b/usr/klibc/tests/pipetest.c
@@ -0,0 +1,39 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <string.h>
+#include <errno.h>
+
+int main(void)
+{
+	/* Size of message must be <= PIPE_BUF */
+	const char msg[] = "Hello, World!";
+	char buf[512];
+	int rv;
+	int pfd[2];
+
+	if (pipe(pfd)) {
+		perror("pipe");
+		return 1;
+	}
+
+	if (write(pfd[1], msg, sizeof msg) != sizeof msg) {
+		perror("write");
+		return 1;
+	}
+
+	while ((rv = read(pfd[0], buf, sizeof buf)) < sizeof msg) {
+		if (rv == -1 && errno == EINTR)
+			continue;
+		perror("read");
+		return 1;
+	}
+
+	if (memcmp(msg, buf, sizeof msg)) {
+		fprintf(stderr, "Message miscompare!\n");
+		return 1;
+	}
+
+	return 0;
+}
diff --git a/usr/klibc/tests/rtsig.c b/usr/klibc/tests/rtsig.c
new file mode 100644
index 0000000..a7f8eed
--- /dev/null
+++ b/usr/klibc/tests/rtsig.c
@@ -0,0 +1,12 @@
+#include <stdio.h>
+#include <signal.h>
+
+int main(void)
+{
+#ifdef SIGRTMIN
+	printf("sigrtmin = %d, sigrtmax = %d\n", SIGRTMIN, SIGRTMAX);
+#else
+	printf("No realtime signals\n");
+#endif
+	return 0;
+}
diff --git a/usr/klibc/tests/select.c b/usr/klibc/tests/select.c
new file mode 100644
index 0000000..db75c55
--- /dev/null
+++ b/usr/klibc/tests/select.c
@@ -0,0 +1,55 @@
+/*
+ * Simple test of select()
+ */
+
+#include <sys/select.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <unistd.h>
+
+int main(int argc, char *argv[])
+{
+	int fdn, fdz, pfd[2], rv;
+	fd_set readset;
+	struct timeval timeout;
+	int err = 0;
+
+	/* We can always read from /dev/zero; open a pipe that is never
+	   ready for a "never readable" file descriptor */
+	fdz = open("/dev/zero", O_RDONLY);
+	pipe(pfd);
+	fdn = pfd[0];
+
+	FD_ZERO(&readset);
+	FD_SET(fdn, &readset);
+
+	timeout.tv_sec = 0;
+	timeout.tv_usec = 100000;
+
+	rv = select(FD_SETSIZE, &readset, NULL, NULL, &timeout);
+
+	if (rv != 0) {
+		fprintf(stderr,
+			"select with timeout failed (rv = %d, errno = %s)\n",
+			rv, strerror(errno));
+		err++;
+	}
+
+	FD_ZERO(&readset);
+	FD_SET(fdn, &readset);
+	FD_SET(fdz, &readset);
+
+	rv = select(FD_SETSIZE, &readset, NULL, NULL, &timeout);
+	
+	if (rv != 1 || !FD_ISSET(fdz, &readset) ||
+	    FD_ISSET(fdn, &readset)) {
+		fprintf(stderr,
+			"select with /dev/zero failed (rv = %d, errno = %s)\n",
+			rv, strerror(errno));
+		err++;
+	}
+
+	return err;
+}
diff --git a/usr/klibc/tests/setenvtest.c b/usr/klibc/tests/setenvtest.c
new file mode 100644
index 0000000..1b07199
--- /dev/null
+++ b/usr/klibc/tests/setenvtest.c
@@ -0,0 +1,39 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+
+int main(int argc, char *argv[])
+{
+	(void)argc;
+	(void)argv;
+
+	/* Set SETENV */
+	setenv("SETENV", "setenv", 1);
+
+	/* Set PUTENV */
+	putenv("PUTENV=putenv");
+
+	/* Print the results... */
+	printf("SETENV = %s\n", getenv("SETENV"));
+	printf("PUTENV = %s\n", getenv("PUTENV"));
+
+	/* Override tests */
+	setenv("SETENV", "setenv_good", 1);
+	putenv("PUTENV=putenv_good");
+	printf("SETENV = %s\n", getenv("SETENV"));
+	printf("PUTENV = %s\n", getenv("PUTENV"));
+
+	/* Non-override test */
+	setenv("SETENV", "setenv_bad", 0);
+	setenv("NEWENV", "newenv_good", 0);
+	printf("SETENV = %s\n", getenv("SETENV"));
+	printf("NEWENV = %s\n", getenv("NEWENV"));
+
+	/* Undef test */
+	unsetenv("SETENV");
+	unsetenv("NEWENV");
+	printf("SETENV = %s\n", getenv("SETENV"));
+	printf("NEWENV = %s\n", getenv("NEWENV"));
+
+	return 0;
+}
diff --git a/usr/klibc/tests/setjmptest.c b/usr/klibc/tests/setjmptest.c
new file mode 100644
index 0000000..30c4e16
--- /dev/null
+++ b/usr/klibc/tests/setjmptest.c
@@ -0,0 +1,38 @@
+/*
+ * setjmptest.c
+ */
+
+#include <stdio.h>
+#include <setjmp.h>
+
+static jmp_buf buf;
+
+void do_stuff(int v)
+{
+	printf("calling longjmp with %d... ", v + 1);
+	longjmp(buf, v + 1);
+}
+
+void recurse(int ctr, int v)
+{
+	if (ctr--) {
+		recurse(ctr, v);
+	} else {
+		do_stuff(v);
+	}
+
+	printf("ERROR!\n");	/* We should never get here... */
+}
+
+int main(void)
+{
+	int v;
+
+	v = setjmp(buf);
+	printf("setjmp returned %d\n", v);
+
+	if (v < 256)
+		recurse(v, v);
+
+	return 0;
+}
diff --git a/usr/klibc/tests/sigint.c b/usr/klibc/tests/sigint.c
new file mode 100644
index 0000000..f11ae1f
--- /dev/null
+++ b/usr/klibc/tests/sigint.c
@@ -0,0 +1,64 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <signal.h>
+
+static sig_atomic_t counter = 0;
+
+static void sig_handler(int signum)
+{
+	static char msg[] = "Signal handler\n";
+
+	(void)signum;
+
+	write(1, msg, sizeof msg - 1);
+	counter++;
+}
+
+int main(int argc, char *argv[])
+{
+	struct sigaction act, oact;
+	pid_t f;
+	sigset_t set;
+
+	(void)argc;
+
+	memset(&act, 0x00, sizeof(struct sigaction));
+	act.sa_handler = sig_handler;
+	sigemptyset(&act.sa_mask);
+	act.sa_flags = SA_RESTART;
+
+	/* oact is there for the benefit of strace() */
+	sigaction(SIGINT, &act, &oact);
+	sigaction(SIGTERM, &act, &oact);
+
+	sigemptyset(&set);
+	sigaddset(&set, SIGINT);
+	sigprocmask(SIG_BLOCK, &set, NULL);
+
+	f = fork();
+
+	if (f < 0) {
+		perror(argv[0]);
+		exit(255);
+	} else if (f > 0) {
+		sleep(3);
+		if (counter) {
+			fprintf(stderr, "Signal received while masked!\n");
+			exit(1);
+		}
+		sigprocmask(SIG_UNBLOCK, &set, NULL);
+		sleep(3);
+		if (!counter) {
+			fprintf(stderr, "No signal received!\n");
+			exit(1);
+		} else {
+			printf("Signal received OK\n");
+			exit(0);
+		}
+	} else {
+		sleep(1);
+		kill(getppid(), SIGINT);
+		_exit(0);
+	}
+}
diff --git a/usr/klibc/tests/stat.c b/usr/klibc/tests/stat.c
new file mode 100644
index 0000000..90223cf
--- /dev/null
+++ b/usr/klibc/tests/stat.c
@@ -0,0 +1,63 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <sys/stat.h>
+#include <sys/sysmacros.h>
+#include <sys/types.h>
+
+static void do_stat(const char *path)
+{
+	struct stat st;
+
+	if (stat(path, &st)) {
+		perror(path);
+		exit(1);
+	}
+
+	printf("Path = %s\n"
+	       "   st_dev       = %#jx (%u,%u)\n"
+	       "   st_ino       = %ju\n"
+	       "   st_mode      = %#jo\n"
+	       "   st_nlink     = %ju\n"
+	       "   st_uid       = %ju\n"
+	       "   st_gid       = %ju\n"
+	       "   st_rdev      = %#jx (%u,%u)\n"
+	       "   st_size      = %ju\n"
+	       "   st_blksize   = %ju\n"
+	       "   st_blocks    = %ju\n",
+	       path,
+	       (uintmax_t) st.st_dev, major(st.st_dev), minor(st.st_dev),
+	       (uintmax_t) st.st_ino,
+	       (uintmax_t) st.st_mode,
+	       (uintmax_t) st.st_nlink,
+	       (uintmax_t) st.st_uid,
+	       (uintmax_t) st.st_gid,
+	       (uintmax_t) st.st_rdev, major(st.st_rdev), minor(st.st_rdev),
+	       (uintmax_t) st.st_size,
+	       (uintmax_t) st.st_blksize, (uintmax_t) st.st_blocks);
+
+#ifdef _STATBUF_ST_NSEC
+	printf("   st_atim      = %jd.%09u\n"
+	       "   st.mtim      = %jd.%09u\n"
+	       "   st.ctim      = %jd.%09u\n",
+	       (uintmax_t) st.st_atim.tv_sec, (unsigned int)st.st_atim.tv_nsec,
+	       (uintmax_t) st.st_mtim.tv_sec, (unsigned int)st.st_mtim.tv_nsec,
+	       (uintmax_t) st.st_ctim.tv_sec, (unsigned int)st.st_ctim.tv_nsec);
+#else
+	printf("   st_atime     = %jd\n"
+	       "   st.mtime     = %jd\n"
+	       "   st.ctime     = %jd\n",
+	       (uintmax_t) st.st_atime,
+	       (uintmax_t) st.st_mtime, (uintmax_t) st.st_ctime);
+#endif
+}
+
+int main(int argc, char *argv[])
+{
+	int i;
+
+	for (i = 1; i < argc; i++)
+		do_stat(argv[i]);
+
+	return 0;
+}
diff --git a/usr/klibc/tests/statfs.c b/usr/klibc/tests/statfs.c
new file mode 100644
index 0000000..0cf99f1
--- /dev/null
+++ b/usr/klibc/tests/statfs.c
@@ -0,0 +1,42 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <sys/vfs.h>
+
+static void do_statfs(const char *path)
+{
+	struct statfs sfs;
+
+	if (statfs(path, &sfs)) {
+		perror(path);
+		exit(1);
+	}
+
+	printf("Path = %s\n"
+	       "   f_type     = %#jx\n"
+	       "   f_bsize    = %jd\n"
+	       "   f_blocks   = %jd\n"
+	       "   f_bfree    = %jd\n"
+	       "   f_bavail   = %jd\n"
+	       "   f_files    = %jd\n"
+	       "   f_ffree    = %jd\n"
+	       "   f_namelen  = %jd\n",
+	       path,
+	       (uintmax_t) sfs.f_type,
+	       (intmax_t) sfs.f_bsize,
+	       (intmax_t) sfs.f_blocks,
+	       (intmax_t) sfs.f_bfree,
+	       (intmax_t) sfs.f_bavail,
+	       (intmax_t) sfs.f_files,
+	       (intmax_t) sfs.f_ffree, (intmax_t) sfs.f_namelen);
+}
+
+int main(int argc, char *argv[])
+{
+	int i;
+
+	for (i = 1; i < argc; i++)
+		do_statfs(argv[i]);
+
+	return 0;
+}
diff --git a/usr/klibc/tests/strlcpycat.c b/usr/klibc/tests/strlcpycat.c
new file mode 100644
index 0000000..14df0cd
--- /dev/null
+++ b/usr/klibc/tests/strlcpycat.c
@@ -0,0 +1,111 @@
+#include <stdio.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+
+int main(void)
+{
+	char temp[8];
+	size_t len;
+
+	printf("strlcpy:\n");
+	len = strlcpy(temp, "123", sizeof(temp));
+	printf("'%s'len:%zu strlen:%zu\n", temp, len, strlen(temp));
+	if (strcmp(temp, "123") != 0)
+		goto error;
+
+	len = strlcpy(temp, "", sizeof(temp));
+	printf("'%s'len:%zu strlen:%zu\n", temp, len, strlen(temp));
+	if (strcmp(temp, "") != 0)
+		goto error;
+
+	len = strlcpy(temp, "1234567890", sizeof(temp));
+	printf("'%s'len:%zu strlen:%zu\n", temp, len, strlen(temp));
+	if (strcmp(temp, "1234567") != 0)
+		goto error;
+
+	len = strlcpy(temp, "123", 1);
+	printf("'%s'len:%zu strlen:%zu\n", temp, len, strlen(temp));
+	if (strcmp(temp, "") != 0)
+		goto error;
+
+	len = strlcpy(temp, "1234567890", 1);
+	printf("'%s'len:%zu strlen:%zu\n", temp, len, strlen(temp));
+	if (strcmp(temp, "") != 0)
+		goto error;
+
+	len = strlcpy(temp, "123", 0);
+	printf("'%s'len:%zu strlen:%zu\n", temp, len, strlen(temp));
+	if (strcmp(temp, "") != 0)
+		goto error;
+
+	len = strlcpy(temp, "1234567890", 0);
+	printf("'%s'len:%zu strlen:%zu\n", temp, len, strlen(temp));
+	if (strcmp(temp, "") != 0)
+		goto error;
+
+	len = strlcpy(temp, "1234567", sizeof(temp));
+	printf("'%s'len:%zu strlen:%zu\n", temp, len, strlen(temp));
+	if (strcmp(temp, "1234567") != 0)
+		goto error;
+
+	len = strlcpy(temp, "12345678", sizeof(temp));
+	printf("'%s'len:%zu strlen:%zu\n", temp, len, strlen(temp));
+	if (strcmp(temp, "1234567") != 0)
+		goto error;
+
+	printf("\n");
+	printf("strlcat:\n");
+	strcpy(temp, "");
+	len = strlcat(temp, "123", sizeof(temp));
+	printf("'%s'len:%zu strlen:%zu\n", temp, len, strlen(temp));
+	if (strcmp(temp, "123") != 0)
+		goto error;
+
+	strcpy(temp, "ABC");
+	len = strlcat(temp, "", sizeof(temp));
+	printf("'%s'len:%zu strlen:%zu\n", temp, len, strlen(temp));
+	if (strcmp(temp, "ABC") != 0)
+		goto error;
+
+	strcpy(temp, "");
+	len = strlcat(temp, "", sizeof(temp));
+	printf("'%s'len:%zu strlen:%zu\n", temp, len, strlen(temp));
+	if (strcmp(temp, "") != 0)
+		goto error;
+
+	strcpy(temp, "ABC");
+	len = strlcat(temp, "123", sizeof(temp));
+	printf("'%s'len:%zu strlen:%zu\n", temp, len, strlen(temp));
+	if (strcmp(temp, "ABC123") != 0)
+		goto error;
+
+	strcpy(temp, "ABC");
+	len = strlcat(temp, "1234567890", sizeof(temp));
+	printf("'%s'len:%zu strlen:%zu\n", temp, len, strlen(temp));
+	if (strcmp(temp, "ABC1234") != 0)
+		goto error;
+
+	strcpy(temp, "ABC");
+	len = strlcat(temp, "123", 5);
+	printf("'%s'len:%zu strlen:%zu\n", temp, len, strlen(temp));
+	if (strcmp(temp, "ABC1") != 0)
+		goto error;
+
+	strcpy(temp, "ABC");
+	len = strlcat(temp, "123", 1);
+	printf("'%s'len:%zu strlen:%zu\n", temp, len, strlen(temp));
+	if (strcmp(temp, "ABC") != 0)
+		goto error;
+
+	strcpy(temp, "ABC");
+	len = strlcat(temp, "123", 0);
+	printf("'%s'len:%zu strlen:%zu\n", temp, len, strlen(temp));
+	if (strcmp(temp, "ABC") != 0)
+		goto error;
+
+	exit(0);
+error:
+	printf("unexpected result\n");
+	exit(1);
+}
diff --git a/usr/klibc/tests/strtoimax.c b/usr/klibc/tests/strtoimax.c
new file mode 100644
index 0000000..318f2d4
--- /dev/null
+++ b/usr/klibc/tests/strtoimax.c
@@ -0,0 +1,23 @@
+/*
+ * strtoimaxtest.c
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <inttypes.h>
+
+int main(int argc, char *argv[])
+{
+	int i;
+	char *ep;
+	intmax_t iv;
+
+	for (i = 1; i < argc; i++) {
+		iv = strtoimax(argv[i], &ep, 0);
+		printf("strtoimax(\"%s\") = %jd\n", argv[i], iv);
+		if (*ep)
+			printf("   ep = \"%s\"\n", ep);
+	}
+
+	return 0;
+}
diff --git a/usr/klibc/tests/strtotime.c b/usr/klibc/tests/strtotime.c
new file mode 100644
index 0000000..16d2e0f
--- /dev/null
+++ b/usr/klibc/tests/strtotime.c
@@ -0,0 +1,25 @@
+#include <stdio.h>
+#include <time.h>
+
+int main(int argc, char *argv[])
+{
+	struct timeval tv;
+	struct timespec ts;
+	int i;
+	const char *rv, *rs;
+
+	for (i = 1; i < argc; i++) {
+		rs = strtotimespec(argv[i], &ts);
+		rv = strtotimeval(argv[i], &tv);
+		printf("String:   \"%s\"\n"
+		       "Timespec: %ld.%09ld\n"
+		       "Residual: \"%s\"\n"
+		       "Timeval:  %ld.%06ld\n"
+		       "Residual: \"%s\"\n",
+		       argv[i],
+		       (long)ts.tv_sec, (long)ts.tv_nsec, rs,
+		       (long)tv.tv_sec, (long)tv.tv_usec, rv);
+	}
+
+	return 0;
+}
diff --git a/usr/klibc/tests/testrand48.c b/usr/klibc/tests/testrand48.c
new file mode 100644
index 0000000..26868c7
--- /dev/null
+++ b/usr/klibc/tests/testrand48.c
@@ -0,0 +1,19 @@
+#include <stdlib.h>
+#include <stdio.h>
+
+int main(void)
+{
+	unsigned short seed1[] = { 0x1234, 0x5678, 0x9abc };
+	unsigned short *oldseed;
+
+	oldseed = seed48(seed1);
+	printf("Initial seed: %#06x %#06x %#06x\n",
+	       oldseed[0], oldseed[1], oldseed[2]);
+
+	printf("lrand48() = %ld\n", lrand48());
+
+	seed48(seed1);
+	printf("mrand48() = %ld\n", mrand48());
+
+	return 1;
+}
diff --git a/usr/klibc/tests/testvsnp.c b/usr/klibc/tests/testvsnp.c
new file mode 100644
index 0000000..098b49a
--- /dev/null
+++ b/usr/klibc/tests/testvsnp.c
@@ -0,0 +1,119 @@
+#include <assert.h>
+#include <stdarg.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <string.h>
+#include <stdio.h>
+
+int main(void)
+{
+	int r, i;
+	char buffer[512];
+
+	r = snprintf(buffer, 512, "Hello, %d", 37);
+	printf("buffer = \"%s\" (%d), r = %d\n", buffer, strlen(buffer), r);
+
+	r = snprintf(buffer, 512, "Hello, %'d", 37373737);
+	printf("buffer = \"%s\" (%d), r = %d\n", buffer, strlen(buffer), r);
+
+	r = snprintf(buffer, 512, "Hello, %'x", 0xdeadbeef);
+	printf("buffer = \"%s\" (%d), r = %d\n", buffer, strlen(buffer), r);
+
+	r = snprintf(buffer, 512, "Hello, %'#X", 0xdeadbeef);
+	printf("buffer = \"%s\" (%d), r = %d\n", buffer, strlen(buffer), r);
+
+	r = snprintf(buffer, 512, "Hello, %'#llo", 0123456701234567ULL);
+	printf("buffer = \"%s\" (%d), r = %d\n", buffer, strlen(buffer), r);
+
+	/* Make sure overflow works correctly */
+	memset(buffer, '\xff', 512);
+	r = snprintf(buffer, 16, "Hello, %'#llo", 0123456701234567ULL);
+	printf("buffer = \"%s\" (%d), r = %d\n", buffer, strlen(buffer), r);
+	for (i = 16; i < 512; i++)
+		assert(buffer[i] == '\xff');
+
+	r = snprintf(buffer, 512, "Hello, %'#40.20llo", 0123456701234567ULL);
+	printf("buffer = \"%s\" (%d), r = %d\n", buffer, strlen(buffer), r);
+
+	r = snprintf(buffer, 512, "Hello, %'#-40.20llo", 0123456701234567ULL);
+	printf("buffer = \"%s\" (%d), r = %d\n", buffer, strlen(buffer), r);
+
+	r = snprintf(buffer, 512, "Hello, %'#*.*llo", 40, 20,
+		     0123456701234567ULL);
+	printf("buffer = \"%s\" (%d), r = %d\n", buffer, strlen(buffer), r);
+
+	r = snprintf(buffer, 512, "Hello, %'#*.*llo", -40, 20,
+		     0123456701234567ULL);
+	printf("buffer = \"%s\" (%d), r = %d\n", buffer, strlen(buffer), r);
+
+	r = snprintf(buffer, 512, "Hello, %'#*.*llo", -40, -20,
+		     0123456701234567ULL);
+	printf("buffer = \"%s\" (%d), r = %d\n", buffer, strlen(buffer), r);
+
+	r = snprintf(buffer, 512, "Hello, %'#*.*llx", -40, -20,
+		     0123456701234567ULL);
+	printf("buffer = \"%s\" (%d), r = %d\n", buffer, strlen(buffer), r);
+
+	r = snprintf(buffer, 512, "Hello, %p", &buffer);
+	printf("buffer = \"%s\" (%d), r = %d\n", buffer, strlen(buffer), r);
+
+	r = snprintf(buffer, 512, "Hello, %P", &buffer);
+	printf("buffer = \"%s\" (%d), r = %d\n", buffer, strlen(buffer), r);
+
+	r = snprintf(buffer, 512, "Hello, %20p", &buffer);
+	printf("buffer = \"%s\" (%d), r = %d\n", buffer, strlen(buffer), r);
+
+	r = snprintf(buffer, 512, "Hello, %-20p", &buffer);
+	printf("buffer = \"%s\" (%d), r = %d\n", buffer, strlen(buffer), r);
+
+	r = snprintf(buffer, 512, "Hello, %-20p", NULL);
+	printf("buffer = \"%s\" (%d), r = %d\n", buffer, strlen(buffer), r);
+
+	r = snprintf(buffer, 20, "Hello, %'-20p", NULL);
+	printf("buffer = \"%s\" (%d), r = %d\n", buffer, strlen(buffer), r);
+
+	r = snprintf(buffer, 15, "Hello, %'-20p", NULL);
+	printf("buffer = \"%s\" (%d), r = %d\n", buffer, strlen(buffer), r);
+
+	r = snprintf(buffer, 3, "Hello, %'-20p", NULL);
+	printf("buffer = \"%s\" (%d), r = %d\n", buffer, strlen(buffer), r);
+
+	/* This shouldn't change buffer in any way! */
+	r = snprintf(buffer, 0, "Hello, %'-20p", NULL);
+	printf("buffer = \"%s\" (%d), r = %d\n", buffer, strlen(buffer), r);
+
+	for (i = -30; i <= 30; i++) {
+		r = snprintf(buffer, 40, "Hello, %'*p", i, NULL);
+		printf("buffer = \"%s\" (%d), r = %d\n", buffer, strlen(buffer),
+		       r);
+	}
+
+	r = snprintf(buffer, 40, "Hello, %'-20s", "String");
+	printf("buffer = \"%s\" (%d), r = %d\n", buffer, strlen(buffer), r);
+
+	r = snprintf(buffer, 40, "Hello, %'20s", "String");
+	printf("buffer = \"%s\" (%d), r = %d\n", buffer, strlen(buffer), r);
+
+	r = snprintf(buffer, 40, "Hello, %'020s", "String");
+	printf("buffer = \"%s\" (%d), r = %d\n", buffer, strlen(buffer), r);
+
+	r = snprintf(buffer, 40, "Hello, %'-20s", NULL);
+	printf("buffer = \"%s\" (%d), r = %d\n", buffer, strlen(buffer), r);
+
+	r = snprintf(buffer, 40, "Hello, %'20s", NULL);
+	printf("buffer = \"%s\" (%d), r = %d\n", buffer, strlen(buffer), r);
+
+	r = snprintf(buffer, 40, "Hello, %'020s", NULL);
+	printf("buffer = \"%s\" (%d), r = %d\n", buffer, strlen(buffer), r);
+
+	r = snprintf(buffer, 40, "Hello, %'-20c", '*');
+	printf("buffer = \"%s\" (%d), r = %d\n", buffer, strlen(buffer), r);
+
+	r = snprintf(buffer, 40, "Hello, %'20c", '*');
+	printf("buffer = \"%s\" (%d), r = %d\n", buffer, strlen(buffer), r);
+
+	r = snprintf(buffer, 40, "Hello, %'020c", '*');
+	printf("buffer = \"%s\" (%d), r = %d\n", buffer, strlen(buffer), r);
+
+	return 0;
+}
diff --git a/usr/klibc/tests/vfork.c b/usr/klibc/tests/vfork.c
new file mode 100644
index 0000000..7adc036
--- /dev/null
+++ b/usr/klibc/tests/vfork.c
@@ -0,0 +1,45 @@
+/*
+ * usr/klibc/tests/vfork.c
+ *
+ * vfork is messy on most architectures.  Do our best to test it out.
+ */
+
+#include <errno.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+
+int main(int argc, char *argv[])
+{
+	pid_t f, rv;
+	int status;
+
+	f = vfork();
+
+	if (f == 0) {
+		printf("Child (%d)...\n", (int)getpid());
+		_exit(123);
+	} else if (f > 0) {
+		int err = 0;
+
+		printf("Parent (child = %d)\n", (int)f);
+
+		rv = waitpid(f, &status, 0);
+		if (rv != f) {
+			printf("waitpid returned %d, errno = %d\n",
+			       (int)rv, errno);
+			err++;
+		}
+		if (!WIFEXITED(status) || WEXITSTATUS(status) != 123) {
+			printf("Child process existed with wrong status %d\n",
+			       status);
+			err++;
+		}
+		return err;
+	} else {
+		printf("vfork returned %d, errno = %d\n",
+		       (int)f, errno);
+		return 127;
+	}
+}
diff --git a/usr/klibc/time.c b/usr/klibc/time.c
new file mode 100644
index 0000000..a0c366b
--- /dev/null
+++ b/usr/klibc/time.c
@@ -0,0 +1,23 @@
+/*
+ * time.c
+ */
+
+#include <time.h>
+#include <sys/time.h>
+#include <sys/syscall.h>
+
+#ifndef __NR_time
+
+time_t time(time_t * t)
+{
+	struct timeval tv;
+
+	gettimeofday(&tv, NULL);
+
+	if (t)
+		*t = (time_t) tv.tv_sec;
+
+	return (time_t) tv.tv_sec;
+}
+
+#endif
diff --git a/usr/klibc/umount.c b/usr/klibc/umount.c
new file mode 100644
index 0000000..d31a300
--- /dev/null
+++ b/usr/klibc/umount.c
@@ -0,0 +1,12 @@
+/*
+ * umount.c
+ *
+ * Single-argument form of umount
+ */
+
+#include <sys/mount.h>
+
+int umount(const char *dir)
+{
+	return umount2(dir, 0);
+}
diff --git a/usr/klibc/unsetenv.c b/usr/klibc/unsetenv.c
new file mode 100644
index 0000000..c5cc95a
--- /dev/null
+++ b/usr/klibc/unsetenv.c
@@ -0,0 +1,44 @@
+/*
+ * unsetenv.c
+ */
+
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include "env.h"
+
+int unsetenv(const char *name)
+{
+	size_t len;
+	char **p, *q;
+	const char *z;
+
+	if (!name || !name[0]) {
+		errno = EINVAL;
+		return -1;
+	}
+
+	len = 0;
+	for (z = name; *z; z++) {
+		len++;
+		if (*z == '=') {
+			errno = EINVAL;
+			return -1;
+		}
+	}
+
+	if (!environ)
+		return 0;
+
+	for (p = environ; (q = *p); p++) {
+		if (!strncmp(name, q, len) && q[len] == '=')
+			break;
+	}
+
+	for (; (q = *p); p++) {
+		p[0] = p[1];
+	}
+
+	return 0;
+}
diff --git a/usr/klibc/userdb/getgrgid.c b/usr/klibc/userdb/getgrgid.c
new file mode 100644
index 0000000..5e13a47
--- /dev/null
+++ b/usr/klibc/userdb/getgrgid.c
@@ -0,0 +1,16 @@
+/*
+ * getgrgid.c
+ *
+ * Dummy getgrgid() to support udev
+ */
+
+#include "userdb.h"
+
+struct group *getgrgid(gid_t gid)
+{
+	if (!gid)
+		return (struct group *)&__root_group;
+
+	errno = ENOENT;
+	return NULL;
+}
diff --git a/usr/klibc/userdb/getgrnam.c b/usr/klibc/userdb/getgrnam.c
new file mode 100644
index 0000000..8df7b8f
--- /dev/null
+++ b/usr/klibc/userdb/getgrnam.c
@@ -0,0 +1,16 @@
+/*
+ * getgrnam.c
+ *
+ * Dummy getgrnam() to support udev
+ */
+
+#include "userdb.h"
+
+struct group *getgrnam(const char *name)
+{
+	if (!strcmp(name, "root"))
+		return (struct group *)&__root_group;
+
+	errno = ENOENT;
+	return NULL;
+}
diff --git a/usr/klibc/userdb/getpwnam.c b/usr/klibc/userdb/getpwnam.c
new file mode 100644
index 0000000..ae1359c
--- /dev/null
+++ b/usr/klibc/userdb/getpwnam.c
@@ -0,0 +1,17 @@
+/*
+ * getpwnam.c
+ *
+ * Dummy getpwnam() to support udev
+ */
+
+#include "userdb.h"
+
+
+struct passwd *getpwnam(const char *name)
+{
+	if (!strcmp(name, "root"))
+		return (struct passwd *)&__root_user;
+
+	errno = ENOENT;
+	return NULL;
+}
diff --git a/usr/klibc/userdb/getpwuid.c b/usr/klibc/userdb/getpwuid.c
new file mode 100644
index 0000000..f924f29
--- /dev/null
+++ b/usr/klibc/userdb/getpwuid.c
@@ -0,0 +1,17 @@
+/*
+ * getpwuid.c
+ *
+ * Dummy getpwuid() to support udev
+ */
+
+#include "userdb.h"
+
+
+struct passwd *getpwuid(uid_t uid)
+{
+	if (!uid)
+		return (struct passwd *)&__root_user;
+
+	errno = ENOENT;
+	return NULL;
+}
diff --git a/usr/klibc/userdb/root_group.c b/usr/klibc/userdb/root_group.c
new file mode 100644
index 0000000..e936d54
--- /dev/null
+++ b/usr/klibc/userdb/root_group.c
@@ -0,0 +1,12 @@
+/*
+ * root_group.c
+ */
+
+#include "userdb.h"
+
+const struct group __root_group = {
+	.gr_name   = "root",
+	.gr_passwd = "",
+	.gr_gid    = 0,
+	.gr_mem    = NULL
+};
diff --git a/usr/klibc/userdb/root_user.c b/usr/klibc/userdb/root_user.c
new file mode 100644
index 0000000..ee2e99a
--- /dev/null
+++ b/usr/klibc/userdb/root_user.c
@@ -0,0 +1,17 @@
+/*
+ * root_user.c
+ *
+ */
+
+#include "userdb.h"
+#include <paths.h>
+
+const struct passwd __root_user = {
+	.pw_name    = "root",
+	.pw_passwd  = "",
+	.pw_uid     = 0,
+	.pw_gid     = 0,
+	.pw_gecos   = "root",
+	.pw_dir     = "/",
+	.pw_shell   = _PATH_BSHELL
+};
diff --git a/usr/klibc/userdb/userdb.h b/usr/klibc/userdb/userdb.h
new file mode 100644
index 0000000..dda093f
--- /dev/null
+++ b/usr/klibc/userdb/userdb.h
@@ -0,0 +1,19 @@
+/*
+ * userdb.h
+ *
+ * Common header file
+ */
+
+#ifndef USERDB_H
+#define USERDB_H
+
+#include <sys/types.h>
+#include <pwd.h>
+#include <grp.h>
+#include <string.h>
+#include <errno.h>
+
+extern const struct passwd __root_user;
+extern const struct group __root_group;
+
+#endif /* USERDB_H */
diff --git a/usr/klibc/usleep.c b/usr/klibc/usleep.c
new file mode 100644
index 0000000..93bfabe
--- /dev/null
+++ b/usr/klibc/usleep.c
@@ -0,0 +1,15 @@
+/*
+ * usleep.c
+ */
+
+#include <errno.h>
+#include <time.h>
+
+void usleep(unsigned long usec)
+{
+	struct timespec ts;
+
+	ts.tv_sec = usec / 1000000UL;
+	ts.tv_nsec = (usec % 1000000UL) * 1000;
+	while (nanosleep(&ts, &ts) == -1 && errno == EINTR) ;
+}
diff --git a/usr/klibc/utime.c b/usr/klibc/utime.c
new file mode 100644
index 0000000..cb8f50a
--- /dev/null
+++ b/usr/klibc/utime.c
@@ -0,0 +1,24 @@
+/*
+ * utime.c
+ */
+
+#include <utime.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/syscall.h>
+
+#ifndef __NR_utime
+
+int utime(const char *filename, const struct utimbuf *buf)
+{
+	struct timeval tvp[2];
+
+	tvp[0].tv_sec = buf->actime;
+	tvp[0].tv_usec = 0;
+	tvp[1].tv_sec = buf->modtime;
+	tvp[1].tv_usec = 0;
+
+	return utimes(filename, tvp);
+}
+
+#endif
diff --git a/usr/klibc/vasprintf.c b/usr/klibc/vasprintf.c
new file mode 100644
index 0000000..cdc302f
--- /dev/null
+++ b/usr/klibc/vasprintf.c
@@ -0,0 +1,25 @@
+/*
+ * vasprintf.c
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+
+int vasprintf(char **bufp, const char *format, va_list ap)
+{
+	va_list ap1;
+	int bytes;
+	char *p;
+
+	va_copy(ap1, ap);
+
+	bytes = vsnprintf(NULL, 0, format, ap1) + 1;
+	va_end(ap1);
+
+	*bufp = p = malloc(bytes);
+	if (!p)
+		return -1;
+
+	return vsnprintf(p, bytes, format, ap);
+}
diff --git a/usr/klibc/version b/usr/klibc/version
new file mode 100644
index 0000000..c239c60
--- /dev/null
+++ b/usr/klibc/version
@@ -0,0 +1 @@
+1.5
diff --git a/usr/klibc/vfork.c b/usr/klibc/vfork.c
new file mode 100644
index 0000000..f2b1a85
--- /dev/null
+++ b/usr/klibc/vfork.c
@@ -0,0 +1,16 @@
+/*
+ * vfork.c
+ *
+ * Emulate vfork() with fork() if necessary
+ */
+
+#include <unistd.h>
+#include <klibc/compiler.h>
+#include <klibc/sysconfig.h>
+
+#if !_KLIBC_NO_MMU && !_KLIBC_REAL_VFORK
+int vfork(void)
+{
+	return fork();
+}
+#endif
diff --git a/usr/klibc/vfprintf.c b/usr/klibc/vfprintf.c
new file mode 100644
index 0000000..6f5663b
--- /dev/null
+++ b/usr/klibc/vfprintf.c
@@ -0,0 +1,26 @@
+/*
+ * vfprintf.c
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdarg.h>
+#include <unistd.h>
+
+#define BUFFER_SIZE	32768
+
+int vfprintf(FILE * file, const char *format, va_list ap)
+{
+	int rv;
+	char buffer[BUFFER_SIZE];
+
+	rv = vsnprintf(buffer, BUFFER_SIZE, format, ap);
+
+	if (rv < 0)
+		return rv;
+
+	if (rv > BUFFER_SIZE - 1)
+		rv = BUFFER_SIZE - 1;
+
+	return _fwrite(buffer, rv, file);
+}
diff --git a/usr/klibc/vprintf.c b/usr/klibc/vprintf.c
new file mode 100644
index 0000000..d6bfeaf
--- /dev/null
+++ b/usr/klibc/vprintf.c
@@ -0,0 +1,11 @@
+/*
+ * vprintf.c
+ */
+
+#include <stdio.h>
+#include <stdarg.h>
+
+int vprintf(const char *format, va_list ap)
+{
+	return vfprintf(stdout, format, ap);
+}
diff --git a/usr/klibc/vsnprintf.c b/usr/klibc/vsnprintf.c
new file mode 100644
index 0000000..26be710
--- /dev/null
+++ b/usr/klibc/vsnprintf.c
@@ -0,0 +1,488 @@
+/*
+ * vsnprintf.c
+ *
+ * vsnprintf(), from which the rest of the printf()
+ * family is built
+ */
+
+#include <stdarg.h>
+#include <stddef.h>
+#include <inttypes.h>
+#include <string.h>
+#include <limits.h>
+#include <stdio.h>
+
+enum flags {
+	FL_ZERO		= 0x01,	/* Zero modifier */
+	FL_MINUS	= 0x02,	/* Minus modifier */
+	FL_PLUS		= 0x04,	/* Plus modifier */
+	FL_TICK		= 0x08,	/* ' modifier */
+	FL_SPACE	= 0x10,	/* Space modifier */
+	FL_HASH		= 0x20,	/* # modifier */
+	FL_SIGNED	= 0x40,	/* Number is signed */
+	FL_UPPER	= 0x80	/* Upper case digits */
+};
+
+/* These may have to be adjusted on certain implementations */
+enum ranks {
+	rank_char	= -2,
+	rank_short	= -1,
+	rank_int	=  0,
+	rank_long	=  1,
+	rank_longlong	=  2
+};
+
+#define MIN_RANK	rank_char
+#define MAX_RANK	rank_longlong
+
+#define INTMAX_RANK	rank_longlong
+#define SIZE_T_RANK	rank_long
+#define PTRDIFF_T_RANK	rank_long
+
+#define EMIT(x) ({ if (o<n){*q++ = (x);} o++; })
+
+static size_t
+format_int(char *q, size_t n, uintmax_t val, enum flags flags,
+	   int base, int width, int prec)
+{
+	char *qq;
+	size_t o = 0, oo;
+	static const char lcdigits[] = "0123456789abcdef";
+	static const char ucdigits[] = "0123456789ABCDEF";
+	const char *digits;
+	uintmax_t tmpval;
+	int minus = 0;
+	int ndigits = 0, nchars;
+	int tickskip, b4tick;
+
+	/* Select type of digits */
+	digits = (flags & FL_UPPER) ? ucdigits : lcdigits;
+
+	/* If signed, separate out the minus */
+	if (flags & FL_SIGNED && (intmax_t) val < 0) {
+		minus = 1;
+		val = (uintmax_t) (-(intmax_t) val);
+	}
+
+	/* Count the number of digits needed.  This returns zero for 0. */
+	tmpval = val;
+	while (tmpval) {
+		tmpval /= base;
+		ndigits++;
+	}
+
+	/* Adjust ndigits for size of output */
+
+	if (flags & FL_HASH && base == 8) {
+		if (prec < ndigits + 1)
+			prec = ndigits + 1;
+	}
+
+	if (ndigits < prec) {
+		ndigits = prec;	/* Mandatory number padding */
+	} else if (val == 0) {
+		ndigits = 1;	/* Zero still requires space */
+	}
+
+	/* For ', figure out what the skip should be */
+	if (flags & FL_TICK) {
+		tickskip = (base == 16) ? 4 : 3;
+	} else {
+		tickskip = ndigits;	/* No tick marks */
+	}
+
+	/* Tick marks aren't digits, but generated by the number converter */
+	ndigits += (ndigits - 1) / tickskip;
+
+	/* Now compute the number of nondigits */
+	nchars = ndigits;
+
+	if (minus || (flags & (FL_PLUS | FL_SPACE)))
+		nchars++;	/* Need space for sign */
+	if ((flags & FL_HASH) && base == 16) {
+		nchars += 2;	/* Add 0x for hex */
+	}
+
+	/* Emit early space padding */
+	if (!(flags & (FL_MINUS | FL_ZERO)) && width > nchars) {
+		while (width > nchars) {
+			EMIT(' ');
+			width--;
+		}
+	}
+
+	/* Emit nondigits */
+	if (minus)
+		EMIT('-');
+	else if (flags & FL_PLUS)
+		EMIT('+');
+	else if (flags & FL_SPACE)
+		EMIT(' ');
+
+	if ((flags & FL_HASH) && base == 16) {
+		EMIT('0');
+		EMIT((flags & FL_UPPER) ? 'X' : 'x');
+	}
+
+	/* Emit zero padding */
+	if ((flags & (FL_MINUS | FL_ZERO)) == FL_ZERO && width > ndigits) {
+		while (width > nchars) {
+			EMIT('0');
+			width--;
+		}
+	}
+
+	/* Generate the number.  This is done from right to left. */
+	q += ndigits;		/* Advance the pointer to end of number */
+	o += ndigits;
+	qq = q;
+	oo = o;			/* Temporary values */
+
+	b4tick = tickskip;
+	while (ndigits > 0) {
+		if (!b4tick--) {
+			qq--;
+			oo--;
+			ndigits--;
+			if (oo < n)
+				*qq = '_';
+			b4tick = tickskip - 1;
+		}
+		qq--;
+		oo--;
+		ndigits--;
+		if (oo < n)
+			*qq = digits[val % base];
+		val /= base;
+	}
+
+	/* Emit late space padding */
+	while ((flags & FL_MINUS) && width > nchars) {
+		EMIT(' ');
+		width--;
+	}
+
+	return o;
+}
+
+int vsnprintf(char *buffer, size_t n, const char *format, va_list ap)
+{
+	const char *p = format;
+	char ch;
+	char *q = buffer;
+	size_t o = 0;		/* Number of characters output */
+	uintmax_t val = 0;
+	int rank = rank_int;	/* Default rank */
+	int width = 0;
+	int prec = -1;
+	int base;
+	size_t sz;
+	enum flags flags = 0;
+	enum {
+		st_normal,	/* Ground state */
+		st_flags,	/* Special flags */
+		st_width,	/* Field width */
+		st_prec,	/* Field precision */
+		st_modifiers	/* Length or conversion modifiers */
+	} state = st_normal;
+	const char *sarg;	/* %s string argument */
+	char carg;		/* %c char argument */
+	int slen;		/* String length */
+
+	while ((ch = *p++)) {
+		switch (state) {
+		case st_normal:
+			if (ch == '%') {
+				state = st_flags;
+				flags = 0;
+				rank = rank_int;
+				width = 0;
+				prec = -1;
+			} else {
+				EMIT(ch);
+			}
+			break;
+
+		case st_flags:
+			switch (ch) {
+			case '-':
+				flags |= FL_MINUS;
+				break;
+			case '+':
+				flags |= FL_PLUS;
+				break;
+			case '\'':
+				flags |= FL_TICK;
+				break;
+			case ' ':
+				flags |= FL_SPACE;
+				break;
+			case '#':
+				flags |= FL_HASH;
+				break;
+			case '0':
+				flags |= FL_ZERO;
+				break;
+			default:
+				state = st_width;
+				p--;	/* Process this character again */
+				break;
+			}
+			break;
+
+		case st_width:
+			if (ch >= '0' && ch <= '9') {
+				width = width * 10 + (ch - '0');
+			} else if (ch == '*') {
+				width = va_arg(ap, int);
+				if (width < 0) {
+					width = -width;
+					flags |= FL_MINUS;
+				}
+			} else if (ch == '.') {
+				prec = 0;	/* Precision given */
+				state = st_prec;
+			} else {
+				state = st_modifiers;
+				p--;	/* Process this character again */
+			}
+			break;
+
+		case st_prec:
+			if (ch >= '0' && ch <= '9') {
+				prec = prec * 10 + (ch - '0');
+			} else if (ch == '*') {
+				prec = va_arg(ap, int);
+				if (prec < 0)
+					prec = -1;
+			} else {
+				state = st_modifiers;
+				p--;	/* Process this character again */
+			}
+			break;
+
+		case st_modifiers:
+			switch (ch) {
+				/* Length modifiers - nonterminal sequences */
+			case 'h':
+				rank--;	/* Shorter rank */
+				break;
+			case 'l':
+				rank++;	/* Longer rank */
+				break;
+			case 'j':
+				rank = INTMAX_RANK;
+				break;
+			case 'z':
+				rank = SIZE_T_RANK;
+				break;
+			case 't':
+				rank = PTRDIFF_T_RANK;
+				break;
+			case 'L':
+			case 'q':
+				rank += 2;
+				break;
+			default:
+				/* Output modifiers - terminal sequences */
+
+				/* Next state will be normal */
+				state = st_normal;
+
+				/* Canonicalize rank */
+				if (rank < MIN_RANK)
+					rank = MIN_RANK;
+				else if (rank > MAX_RANK)
+					rank = MAX_RANK;
+
+				switch (ch) {
+				case 'P':	/* Upper case pointer */
+					flags |= FL_UPPER;
+					/* fall through */
+				case 'p':	/* Pointer */
+					base = 16;
+					prec = (CHAR_BIT*sizeof(void *)+3)/4;
+					flags |= FL_HASH;
+					val = (uintmax_t)(uintptr_t)
+						va_arg(ap, void *);
+					goto is_integer;
+
+				case 'd':	/* Signed decimal output */
+				case 'i':
+					base = 10;
+					flags |= FL_SIGNED;
+					switch (rank) {
+					case rank_char:
+						/* Yes, all these casts are
+						   needed... */
+						val = (uintmax_t)(intmax_t)
+							(signed char)
+							va_arg(ap, signed int);
+						break;
+					case rank_short:
+						val = (uintmax_t)(intmax_t)
+							(signed short)
+							va_arg(ap, signed int);
+						break;
+					case rank_int:
+						val = (uintmax_t)(intmax_t)
+						    va_arg(ap, signed int);
+						break;
+					case rank_long:
+						val = (uintmax_t)(intmax_t)
+						    va_arg(ap, signed long);
+						break;
+					case rank_longlong:
+						val = (uintmax_t)(intmax_t)
+						    va_arg(ap,
+							   signed long long);
+						break;
+					}
+					goto is_integer;
+				case 'o':	/* Octal */
+					base = 8;
+					goto is_unsigned;
+				case 'u':	/* Unsigned decimal */
+					base = 10;
+					goto is_unsigned;
+				case 'X':	/* Upper case hexadecimal */
+					flags |= FL_UPPER;
+					/* fall through */
+				case 'x':	/* Hexadecimal */
+					base = 16;
+					goto is_unsigned;
+
+				is_unsigned:
+					switch (rank) {
+					case rank_char:
+						val = (uintmax_t)
+							(unsigned char)
+							va_arg(ap, unsigned
+							       int);
+						break;
+					case rank_short:
+						val = (uintmax_t)
+							(unsigned short)
+							va_arg(ap, unsigned
+							       int);
+						break;
+					case rank_int:
+						val = (uintmax_t)
+							va_arg(ap, unsigned
+							       int);
+						break;
+					case rank_long:
+						val = (uintmax_t)
+							va_arg(ap, unsigned
+							       long);
+						break;
+					case rank_longlong:
+						val = (uintmax_t)
+							va_arg(ap, unsigned
+							       long long);
+						break;
+					}
+					/* fall through */
+
+				is_integer:
+					sz = format_int(q, (o < n) ? n - o : 0,
+							val, flags, base,
+							width, prec);
+					q += sz;
+					o += sz;
+					break;
+
+				case 'c':	/* Character */
+					carg = (char)va_arg(ap, int);
+					sarg = &carg;
+					slen = 1;
+					goto is_string;
+				case 's':	/* String */
+					sarg = va_arg(ap, const char *);
+					sarg = sarg ? sarg : "(null)";
+					slen = strlen(sarg);
+					goto is_string;
+
+				is_string:
+					{
+						char sch;
+						int i;
+
+						if (prec != -1 && slen > prec)
+							slen = prec;
+
+						if (width > slen
+						    && !(flags & FL_MINUS)) {
+							char pad =
+							    (flags & FL_ZERO) ?
+							    '0' : ' ';
+							while (width > slen) {
+								EMIT(pad);
+								width--;
+							}
+						}
+						for (i = slen; i; i--) {
+							sch = *sarg++;
+							EMIT(sch);
+						}
+						if (width > slen
+						    && (flags & FL_MINUS)) {
+							while (width > slen) {
+								EMIT(' ');
+								width--;
+							}
+						}
+					}
+					break;
+
+				case 'n':
+					{
+						/* Output the number of
+						   characters written */
+
+						switch (rank) {
+						case rank_char:
+							*va_arg(ap,
+								signed char *)
+								= o;
+							break;
+						case rank_short:
+							*va_arg(ap,
+								signed short *)
+								= o;
+							break;
+						case rank_int:
+							*va_arg(ap,
+								signed int *)
+								= o;
+							break;
+						case rank_long:
+							*va_arg(ap,
+								signed long *)
+								= o;
+							break;
+						case rank_longlong:
+							*va_arg(ap,
+								signed long long *)
+								= o;
+							break;
+						}
+					}
+					break;
+
+				default:	/* Anything else, including % */
+					EMIT(ch);
+					break;
+				}
+			}
+		}
+	}
+
+	/* Null-terminate the string */
+	if (o < n)
+		*q = '\0';	/* No overflow */
+	else if (n > 0)
+		buffer[n - 1] = '\0';	/* Overflow - terminate at end of buffer */
+
+	return o;
+}
diff --git a/usr/klibc/vsprintf.c b/usr/klibc/vsprintf.c
new file mode 100644
index 0000000..51f5d87
--- /dev/null
+++ b/usr/klibc/vsprintf.c
@@ -0,0 +1,11 @@
+/*
+ * vsprintf.c
+ */
+
+#include <stdio.h>
+#include <unistd.h>
+
+int vsprintf(char *buffer, const char *format, va_list ap)
+{
+	return vsnprintf(buffer, ~(size_t) 0, format, ap);
+}
diff --git a/usr/klibc/vsscanf.c b/usr/klibc/vsscanf.c
new file mode 100644
index 0000000..51e50f7
--- /dev/null
+++ b/usr/klibc/vsscanf.c
@@ -0,0 +1,399 @@
+/*
+ * vsscanf.c
+ *
+ * vsscanf(), from which the rest of the scanf()
+ * family is built
+ */
+
+#include <ctype.h>
+#include <stdarg.h>
+#include <stddef.h>
+#include <inttypes.h>
+#include <string.h>
+#include <limits.h>
+#include <stdio.h>
+
+#ifndef LONG_BIT
+#define LONG_BIT (CHAR_BIT*sizeof(long))
+#endif
+
+enum flags {
+	FL_SPLAT = 0x01,	/* Drop the value, do not assign */
+	FL_INV   = 0x02,	/* Character-set with inverse */
+	FL_WIDTH = 0x04,	/* Field width specified */
+	FL_MINUS = 0x08,	/* Negative number */
+};
+
+enum ranks {
+	rank_char     = -2,
+	rank_short    = -1,
+	rank_int      = 0,
+	rank_long     = 1,
+	rank_longlong = 2,
+	rank_ptr      = INT_MAX	/* Special value used for pointers */
+};
+
+#define MIN_RANK	rank_char
+#define MAX_RANK	rank_longlong
+
+#define INTMAX_RANK	rank_longlong
+#define SIZE_T_RANK	rank_long
+#define PTRDIFF_T_RANK	rank_long
+
+enum bail {
+	bail_none = 0,		/* No error condition */
+	bail_eof,		/* Hit EOF */
+	bail_err		/* Conversion mismatch */
+};
+
+static inline const char *skipspace(const char *p)
+{
+	while (isspace((unsigned char)*p))
+		p++;
+	return p;
+}
+
+#undef set_bit
+static inline void set_bit(unsigned long *bitmap, unsigned int bit)
+{
+	bitmap[bit / LONG_BIT] |= 1UL << (bit % LONG_BIT);
+}
+
+#undef test_bit
+static inline int test_bit(unsigned long *bitmap, unsigned int bit)
+{
+	return (int)(bitmap[bit / LONG_BIT] >> (bit % LONG_BIT)) & 1;
+}
+
+int vsscanf(const char *buffer, const char *format, va_list ap)
+{
+	const char *p = format;
+	char ch;
+	unsigned char uc;
+	const char *q = buffer;
+	const char *qq;
+	uintmax_t val = 0;
+	int rank = rank_int;	/* Default rank */
+	unsigned int width = UINT_MAX;
+	int base;
+	enum flags flags = 0;
+	enum {
+		st_normal,	/* Ground state */
+		st_flags,	/* Special flags */
+		st_width,	/* Field width */
+		st_modifiers,	/* Length or conversion modifiers */
+		st_match_init,	/* Initial state of %[ sequence */
+		st_match,	/* Main state of %[ sequence */
+		st_match_range,	/* After - in a %[ sequence */
+	} state = st_normal;
+	char *sarg = NULL;	/* %s %c or %[ string argument */
+	enum bail bail = bail_none;
+	int sign;
+	int converted = 0;	/* Successful conversions */
+	unsigned long matchmap[((1 << CHAR_BIT) + (LONG_BIT - 1)) / LONG_BIT];
+	int matchinv = 0;	/* Is match map inverted? */
+	unsigned char range_start = 0;
+
+	while ((ch = *p++) && !bail) {
+		switch (state) {
+		case st_normal:
+			if (ch == '%') {
+				state = st_flags;
+				flags = 0;
+				rank = rank_int;
+				width = UINT_MAX;
+			} else if (isspace((unsigned char)ch)) {
+				q = skipspace(q);
+			} else {
+				if (*q == ch)
+					q++;
+				else
+					bail = bail_err; /* Match failure */
+			}
+			break;
+
+		case st_flags:
+			switch (ch) {
+			case '*':
+				flags |= FL_SPLAT;
+				break;
+			case '0'...'9':
+				width = (ch - '0');
+				state = st_width;
+				flags |= FL_WIDTH;
+				break;
+			default:
+				state = st_modifiers;
+				p--;	/* Process this character again */
+				break;
+			}
+			break;
+
+		case st_width:
+			if (ch >= '0' && ch <= '9') {
+				width = width * 10 + (ch - '0');
+			} else {
+				state = st_modifiers;
+				p--;	/* Process this character again */
+			}
+			break;
+
+		case st_modifiers:
+			switch (ch) {
+				/* Length modifiers - nonterminal sequences */
+			case 'h':
+				rank--;	/* Shorter rank */
+				break;
+			case 'l':
+				rank++;	/* Longer rank */
+				break;
+			case 'j':
+				rank = INTMAX_RANK;
+				break;
+			case 'z':
+				rank = SIZE_T_RANK;
+				break;
+			case 't':
+				rank = PTRDIFF_T_RANK;
+				break;
+			case 'L':
+			case 'q':
+				rank = rank_longlong;	/* long double/long long */
+				break;
+
+			default:
+				/* Output modifiers - terminal sequences */
+				/* Next state will be normal */
+				state = st_normal;
+
+				/* Canonicalize rank */
+				if (rank < MIN_RANK)
+					rank = MIN_RANK;
+				else if (rank > MAX_RANK)
+					rank = MAX_RANK;
+
+				switch (ch) {
+				case 'P':	/* Upper case pointer */
+				case 'p':	/* Pointer */
+					rank = rank_ptr;
+					base = 0;
+					sign = 0;
+					goto scan_int;
+
+				case 'i':	/* Base-independent integer */
+					base = 0;
+					sign = 1;
+					goto scan_int;
+
+				case 'd':	/* Decimal integer */
+					base = 10;
+					sign = 1;
+					goto scan_int;
+
+				case 'o':	/* Octal integer */
+					base = 8;
+					sign = 0;
+					goto scan_int;
+
+				case 'u':	/* Unsigned decimal integer */
+					base = 10;
+					sign = 0;
+					goto scan_int;
+
+				case 'x':	/* Hexadecimal integer */
+				case 'X':
+					base = 16;
+					sign = 0;
+					goto scan_int;
+
+				case 'n':	/* # of characters consumed */
+					val = (q - buffer);
+					goto set_integer;
+
+				      scan_int:
+					q = skipspace(q);
+					if (!*q) {
+						bail = bail_eof;
+						break;
+					}
+					val =
+					    strntoumax(q, (char **)&qq, base,
+						       width);
+					if (qq == q) {
+						bail = bail_err;
+						break;
+					}
+					q = qq;
+					if (!(flags & FL_SPLAT))
+						converted++;
+					/* fall through */
+
+				      set_integer:
+					if (!(flags & FL_SPLAT)) {
+						switch (rank) {
+						case rank_char:
+							*va_arg(ap,
+								unsigned char *)
+								= val;
+							break;
+						case rank_short:
+							*va_arg(ap,
+								unsigned short
+								*) = val;
+							break;
+						case rank_int:
+							*va_arg(ap,
+								unsigned int *)
+							    = val;
+							break;
+						case rank_long:
+							*va_arg(ap,
+								unsigned long *)
+								= val;
+							break;
+						case rank_longlong:
+							*va_arg(ap,
+								unsigned long
+								long *) = val;
+							break;
+						case rank_ptr:
+							*va_arg(ap, void **) =
+								(void *)
+								(uintptr_t)val;
+							break;
+						}
+					}
+					break;
+
+				case 'c':	/* Character */
+					/* Default width == 1 */
+					width = (flags & FL_WIDTH) ? width : 1;
+					if (flags & FL_SPLAT) {
+						while (width--) {
+							if (!*q) {
+								bail = bail_eof;
+								break;
+							}
+						}
+					} else {
+						sarg = va_arg(ap, char *);
+						while (width--) {
+							if (!*q) {
+								bail = bail_eof;
+								break;
+							}
+							*sarg++ = *q++;
+						}
+						if (!bail)
+							converted++;
+					}
+					break;
+
+				case 's':	/* String */
+					uc = 1;	/* Anything nonzero */
+					if (flags & FL_SPLAT) {
+						while (width-- && (uc = *q) &&
+						       !isspace(uc)) {
+							q++;
+						}
+					} else {
+						char *sp;
+						sp = sarg = va_arg(ap, char *);
+						while (width-- && (uc = *q) &&
+						       !isspace(uc)) {
+							*sp++ = uc;
+							q++;
+						}
+						if (sarg != sp) {
+							/* Terminate output */
+							*sp = '\0';
+							converted++;
+						}
+					}
+					if (!uc)
+						bail = bail_eof;
+					break;
+
+				case '[':	/* Character range */
+					sarg = (flags & FL_SPLAT) ? NULL
+						: va_arg(ap, char *);
+					state = st_match_init;
+					matchinv = 0;
+					memset(matchmap, 0, sizeof matchmap);
+					break;
+
+				case '%':	/* %% sequence */
+					if (*q == '%')
+						q++;
+					else
+						bail = bail_err;
+					break;
+
+				default:	/* Anything else */
+					/* Unknown sequence */
+					bail = bail_err;
+					break;
+				}
+			}
+			break;
+
+		case st_match_init:	/* Initial state for %[ match */
+			if (ch == '^' && !(flags & FL_INV)) {
+				matchinv = 1;
+			} else {
+				set_bit(matchmap, (unsigned char)ch);
+				state = st_match;
+			}
+			break;
+
+		case st_match:	/* Main state for %[ match */
+			if (ch == ']') {
+				goto match_run;
+			} else if (ch == '-') {
+				range_start = (unsigned char)ch;
+				state = st_match_range;
+			} else {
+				set_bit(matchmap, (unsigned char)ch);
+			}
+			break;
+
+		case st_match_range:	/* %[ match after - */
+			if (ch == ']') {
+				/* - was last character */
+				set_bit(matchmap, (unsigned char)'-');
+				goto match_run;
+			} else {
+				int i;
+				for (i = range_start; i < (unsigned char)ch;
+				     i++)
+					set_bit(matchmap, i);
+				state = st_match;
+			}
+			break;
+
+		      match_run:	/* Match expression finished */
+			qq = q;
+			uc = 1;	/* Anything nonzero */
+			while (width && (uc = *q)
+			       && test_bit(matchmap, uc)^matchinv) {
+				if (sarg)
+					*sarg++ = uc;
+				q++;
+			}
+			if (q != qq && sarg) {
+				*sarg = '\0';
+				converted++;
+			} else {
+				bail = bail_err;
+			}
+			if (!uc)
+				bail = bail_eof;
+			break;
+		}
+	}
+
+	if (bail == bail_eof && !converted)
+		converted = -1;	/* Return EOF (-1) */
+
+	return converted;
+}
diff --git a/usr/klibc/wait.c b/usr/klibc/wait.c
new file mode 100644
index 0000000..73bb1a2
--- /dev/null
+++ b/usr/klibc/wait.c
@@ -0,0 +1,12 @@
+/*
+ * wait.c
+ */
+
+#include <stdlib.h>
+#include <sys/wait.h>
+#include <sys/types.h>
+
+pid_t wait(int *status)
+{
+	return wait4((pid_t) - 1, status, 0, NULL);
+}
diff --git a/usr/klibc/wait3.c b/usr/klibc/wait3.c
new file mode 100644
index 0000000..1f35414
--- /dev/null
+++ b/usr/klibc/wait3.c
@@ -0,0 +1,12 @@
+/*
+ * wait3.c
+ */
+
+#include <sys/types.h>
+#include <sys/resource.h>
+#include <sys/wait.h>
+
+pid_t wait3(int *status, int options, struct rusage * rusage)
+{
+	return wait4((pid_t) - 1, status, options, rusage);
+}
diff --git a/usr/klibc/waitpid.c b/usr/klibc/waitpid.c
new file mode 100644
index 0000000..a157122
--- /dev/null
+++ b/usr/klibc/waitpid.c
@@ -0,0 +1,12 @@
+/*
+ * waitpid.c
+ */
+
+#include <sys/types.h>
+#include <sys/resource.h>
+#include <sys/wait.h>
+
+pid_t waitpid(pid_t pid, int *status, int options)
+{
+	return wait4(pid, status, options, NULL);
+}
diff --git a/usr/klibc/zlib/FAQ b/usr/klibc/zlib/FAQ
new file mode 100644
index 0000000..441d910
--- /dev/null
+++ b/usr/klibc/zlib/FAQ
@@ -0,0 +1,339 @@
+
+                Frequently Asked Questions about zlib
+
+
+If your question is not there, please check the zlib home page
+http://www.zlib.org which may have more recent information.
+The lastest zlib FAQ is at http://www.gzip.org/zlib/zlib_faq.html
+
+
+ 1. Is zlib Y2K-compliant?
+
+    Yes. zlib doesn't handle dates.
+
+ 2. Where can I get a Windows DLL version?
+
+    The zlib sources can be compiled without change to produce a DLL.
+    See the file win32/DLL_FAQ.txt in the zlib distribution.
+    Pointers to the precompiled DLL are found in the zlib web site at
+    http://www.zlib.org.
+
+ 3. Where can I get a Visual Basic interface to zlib?
+
+    See
+        * http://www.dogma.net/markn/articles/zlibtool/zlibtool.htm
+        * contrib/visual-basic.txt in the zlib distribution
+        * win32/DLL_FAQ.txt in the zlib distribution
+
+ 4. compress() returns Z_BUF_ERROR.
+
+    Make sure that before the call of compress, the length of the compressed
+    buffer is equal to the total size of the compressed buffer and not
+    zero. For Visual Basic, check that this parameter is passed by reference
+    ("as any"), not by value ("as long").
+
+ 5. deflate() or inflate() returns Z_BUF_ERROR.
+
+    Before making the call, make sure that avail_in and avail_out are not
+    zero. When setting the parameter flush equal to Z_FINISH, also make sure
+    that avail_out is big enough to allow processing all pending input.
+    Note that a Z_BUF_ERROR is not fatal--another call to deflate() or
+    inflate() can be made with more input or output space. A Z_BUF_ERROR
+    may in fact be unavoidable depending on how the functions are used, since
+    it is not possible to tell whether or not there is more output pending
+    when strm.avail_out returns with zero.
+
+ 6. Where's the zlib documentation (man pages, etc.)?
+
+    It's in zlib.h for the moment, and Francis S. Lin has converted it to a
+    web page zlib.html. Volunteers to transform this to Unix-style man pages,
+    please contact us (zlib@gzip.org). Examples of zlib usage are in the files
+    example.c and minigzip.c.
+
+ 7. Why don't you use GNU autoconf or libtool or ...?
+
+    Because we would like to keep zlib as a very small and simple
+    package. zlib is rather portable and doesn't need much configuration.
+
+ 8. I found a bug in zlib.
+
+    Most of the time, such problems are due to an incorrect usage of
+    zlib. Please try to reproduce the problem with a small program and send
+    the corresponding source to us at zlib@gzip.org . Do not send
+    multi-megabyte data files without prior agreement.
+
+ 9. Why do I get "undefined reference to gzputc"?
+
+    If "make test" produces something like
+
+       example.o(.text+0x154): undefined reference to `gzputc'
+
+    check that you don't have old files libz.* in /usr/lib, /usr/local/lib or
+    /usr/X11R6/lib. Remove any old versions, then do "make install".
+
+10. I need a Delphi interface to zlib.
+
+    See the contrib/delphi directory in the zlib distribution.
+
+11. Can zlib handle .zip archives?
+
+    Not by itself, no.  See the directory contrib/minizip in the zlib
+    distribution.
+
+12. Can zlib handle .Z files?
+
+    No, sorry. You have to spawn an uncompress or gunzip subprocess, or adapt
+    the code of uncompress on your own.
+
+13. How can I make a Unix shared library?
+
+    make clean
+    ./configure -s
+    make
+
+14. How do I install a shared zlib library on Unix?
+
+    After the above, then:
+
+    make install
+
+    However, many flavors of Unix come with a shared zlib already installed.
+    Before going to the trouble of compiling a shared version of zlib and
+    trying to install it, you may want to check if it's already there! If you
+    can #include <zlib.h>, it's there. The -lz option will probably link to it.
+
+15. I have a question about OttoPDF.
+
+    We are not the authors of OttoPDF. The real author is on the OttoPDF web
+    site: Joel Hainley, jhainley@myndkryme.com.
+
+16. Can zlib decode Flate data in an Adobe PDF file?
+
+    Yes. See http://www.fastio.com/ (ClibPDF), or http://www.pdflib.com/ .
+    To modify PDF forms, see http://sourceforge.net/projects/acroformtool/ .
+
+17. Why am I getting this "register_frame_info not found" error on Solaris?
+
+    After installing zlib 1.1.4 on Solaris 2.6, running applications using zlib
+    generates an error such as:
+
+        ld.so.1: rpm: fatal: relocation error: file /usr/local/lib/libz.so:
+        symbol __register_frame_info: referenced symbol not found
+
+    The symbol __register_frame_info is not part of zlib, it is generated by
+    the C compiler (cc or gcc). You must recompile applications using zlib
+    which have this problem. This problem is specific to Solaris. See
+    http://www.sunfreeware.com for Solaris versions of zlib and applications
+    using zlib.
+
+18. Why does gzip give an error on a file I make with compress/deflate?
+
+    The compress and deflate functions produce data in the zlib format, which
+    is different and incompatible with the gzip format. The gz* functions in
+    zlib on the other hand use the gzip format. Both the zlib and gzip
+    formats use the same compressed data format internally, but have different
+    headers and trailers around the compressed data.
+
+19. Ok, so why are there two different formats?
+
+    The gzip format was designed to retain the directory information about
+    a single file, such as the name and last modification date. The zlib
+    format on the other hand was designed for in-memory and communication
+    channel applications, and has a much more compact header and trailer and
+    uses a faster integrity check than gzip.
+
+20. Well that's nice, but how do I make a gzip file in memory?
+
+    You can request that deflate write the gzip format instead of the zlib
+    format using deflateInit2(). You can also request that inflate decode
+    the gzip format using inflateInit2(). Read zlib.h for more details.
+
+21. Is zlib thread-safe?
+
+    Yes. However any library routines that zlib uses and any application-
+    provided memory allocation routines must also be thread-safe. zlib's gz*
+    functions use stdio library routines, and most of zlib's functions use the
+    library memory allocation routines by default. zlib's Init functions allow
+    for the application to provide custom memory allocation routines.
+
+    Of course, you should only operate on any given zlib or gzip stream from a
+    single thread at a time.
+
+22. Can I use zlib in my commercial application?
+
+    Yes. Please read the license in zlib.h.
+
+23. Is zlib under the GNU license?
+
+    No. Please read the license in zlib.h.
+
+24. The license says that altered source versions must be "plainly marked". So
+    what exactly do I need to do to meet that requirement?
+
+    You need to change the ZLIB_VERSION and ZLIB_VERNUM #defines in zlib.h. In
+    particular, the final version number needs to be changed to "f", and an
+    identification string should be appended to ZLIB_VERSION. Version numbers
+    x.x.x.f are reserved for modifications to zlib by others than the zlib
+    maintainers. For example, if the version of the base zlib you are altering
+    is "1.2.3.4", then in zlib.h you should change ZLIB_VERNUM to 0x123f, and
+    ZLIB_VERSION to something like "1.2.3.f-zachary-mods-v3". You can also
+    update the version strings in deflate.c and inftrees.c.
+
+    For altered source distributions, you should also note the origin and
+    nature of the changes in zlib.h, as well as in ChangeLog and README, along
+    with the dates of the alterations. The origin should include at least your
+    name (or your company's name), and an email address to contact for help or
+    issues with the library.
+
+    Note that distributing a compiled zlib library along with zlib.h and
+    zconf.h is also a source distribution, and so you should change
+    ZLIB_VERSION and ZLIB_VERNUM and note the origin and nature of the changes
+    in zlib.h as you would for a full source distribution.
+
+25. Will zlib work on a big-endian or little-endian architecture, and can I
+    exchange compressed data between them?
+
+    Yes and yes.
+
+26. Will zlib work on a 64-bit machine?
+
+    It should. It has been tested on 64-bit machines, and has no dependence
+    on any data types being limited to 32-bits in length. If you have any
+    difficulties, please provide a complete problem report to zlib@gzip.org
+
+27. Will zlib decompress data from the PKWare Data Compression Library?
+
+    No. The PKWare DCL uses a completely different compressed data format
+    than does PKZIP and zlib. However, you can look in zlib's contrib/blast
+    directory for a possible solution to your problem.
+
+28. Can I access data randomly in a compressed stream?
+
+    No, not without some preparation. If when compressing you periodically
+    use Z_FULL_FLUSH, carefully write all the pending data at those points,
+    and keep an index of those locations, then you can start decompression
+    at those points. You have to be careful to not use Z_FULL_FLUSH too
+    often, since it can significantly degrade compression.
+
+29. Does zlib work on MVS, OS/390, CICS, etc.?
+
+    We don't know for sure. We have heard occasional reports of success on
+    these systems. If you do use it on one of these, please provide us with
+    a report, instructions, and patches that we can reference when we get
+    these questions. Thanks.
+
+30. Is there some simpler, easier to read version of inflate I can look at
+    to understand the deflate format?
+
+    First off, you should read RFC 1951. Second, yes. Look in zlib's
+    contrib/puff directory.
+
+31. Does zlib infringe on any patents?
+
+    As far as we know, no. In fact, that was originally the whole point behind
+    zlib. Look here for some more information:
+
+    http://www.gzip.org/#faq11
+
+32. Can zlib work with greater than 4 GB of data?
+
+    Yes. inflate() and deflate() will process any amount of data correctly.
+    Each call of inflate() or deflate() is limited to input and output chunks
+    of the maximum value that can be stored in the compiler's "unsigned int"
+    type, but there is no limit to the number of chunks. Note however that the
+    strm.total_in and strm_total_out counters may be limited to 4 GB. These
+    counters are provided as a convenience and are not used internally by
+    inflate() or deflate(). The application can easily set up its own counters
+    updated after each call of inflate() or deflate() to count beyond 4 GB.
+    compress() and uncompress() may be limited to 4 GB, since they operate in a
+    single call. gzseek() and gztell() may be limited to 4 GB depending on how
+    zlib is compiled. See the zlibCompileFlags() function in zlib.h.
+
+    The word "may" appears several times above since there is a 4 GB limit
+    only if the compiler's "long" type is 32 bits. If the compiler's "long"
+    type is 64 bits, then the limit is 16 exabytes.
+
+33. Does zlib have any security vulnerabilities?
+
+    The only one that we are aware of is potentially in gzprintf(). If zlib
+    is compiled to use sprintf() or vsprintf(), then there is no protection
+    against a buffer overflow of a 4K string space, other than the caller of
+    gzprintf() assuring that the output will not exceed 4K. On the other
+    hand, if zlib is compiled to use snprintf() or vsnprintf(), which should
+    normally be the case, then there is no vulnerability. The ./configure
+    script will display warnings if an insecure variation of sprintf() will
+    be used by gzprintf(). Also the zlibCompileFlags() function will return
+    information on what variant of sprintf() is used by gzprintf().
+
+    If you don't have snprintf() or vsnprintf() and would like one, you can
+    find a portable implementation here:
+
+        http://www.ijs.si/software/snprintf/
+
+    Note that you should be using the most recent version of zlib. Versions
+    1.1.3 and before were subject to a double-free vulnerability.
+
+34. Is there a Java version of zlib?
+
+    Probably what you want is to use zlib in Java. zlib is already included
+    as part of the Java SDK in the java.util.zip package. If you really want
+    a version of zlib written in the Java language, look on the zlib home
+    page for links: http://www.zlib.org/
+
+35. I get this or that compiler or source-code scanner warning when I crank it
+    up to maximally-pedantic. Can't you guys write proper code?
+
+    Many years ago, we gave up attempting to avoid warnings on every compiler
+    in the universe. It just got to be a waste of time, and some compilers
+    were downright silly. So now, we simply make sure that the code always
+    works.
+
+36. Valgrind (or some similar memory access checker) says that deflate is
+    performing a conditional jump that depends on an uninitialized value.
+    Isn't that a bug?
+
+    No.  That is intentional for performance reasons, and the output of
+    deflate is not affected.  This only started showing up recently since
+    zlib 1.2.x uses malloc() by default for allocations, whereas earlier
+    versions used calloc(), which zeros out the allocated memory.
+
+37. Will zlib read the (insert any ancient or arcane format here) compressed
+    data format?
+
+    Probably not. Look in the comp.compression FAQ for pointers to various
+    formats and associated software.
+
+38. How can I encrypt/decrypt zip files with zlib?
+
+    zlib doesn't support encryption. The original PKZIP encryption is very weak
+    and can be broken with freely available programs. To get strong encryption,
+    use GnuPG, http://www.gnupg.org/ , which already includes zlib compression.
+    For PKZIP compatible "encryption", look at http://www.info-zip.org/
+
+39. What's the difference between the "gzip" and "deflate" HTTP 1.1 encodings?
+
+    "gzip" is the gzip format, and "deflate" is the zlib format. They should
+    probably have called the second one "zlib" instead to avoid confusion
+    with the raw deflate compressed data format. While the HTTP 1.1 RFC 2616
+    correctly points to the zlib specification in RFC 1950 for the "deflate"
+    transfer encoding, there have been reports of servers and browsers that
+    incorrectly produce or expect raw deflate data per the deflate
+    specficiation in RFC 1951, most notably Microsoft. So even though the
+    "deflate" transfer encoding using the zlib format would be the more
+    efficient approach (and in fact exactly what the zlib format was designed
+    for), using the "gzip" transfer encoding is probably more reliable due to
+    an unfortunate choice of name on the part of the HTTP 1.1 authors.
+
+    Bottom line: use the gzip format for HTTP 1.1 encoding.
+
+40. Does zlib support the new "Deflate64" format introduced by PKWare?
+
+    No. PKWare has apparently decided to keep that format proprietary, since
+    they have not documented it as they have previous compression formats.
+    In any case, the compression improvements are so modest compared to other
+    more modern approaches, that it's not worth the effort to implement.
+
+41. Can you please sign these lengthy legal documents and fax them back to us
+    so that we can use your software in our product?
+
+    No. Go away. Shoo.
diff --git a/usr/klibc/zlib/INDEX b/usr/klibc/zlib/INDEX
new file mode 100644
index 0000000..0587e59
--- /dev/null
+++ b/usr/klibc/zlib/INDEX
@@ -0,0 +1,51 @@
+ChangeLog       history of changes
+FAQ             Frequently Asked Questions about zlib
+INDEX           this file
+Makefile        makefile for Unix (generated by configure)
+Makefile.in     makefile for Unix (template for configure)
+README          guess what
+algorithm.txt   description of the (de)compression algorithm
+configure       configure script for Unix
+zconf.in.h      template for zconf.h (used by configure)
+
+amiga/          makefiles for Amiga SAS C
+as400/          makefiles for IBM AS/400
+msdos/          makefiles for MSDOS
+old/            makefiles for various architectures and zlib documentation
+                files that have not yet been updated for zlib 1.2.x
+projects/       projects for various Integrated Development Environments
+qnx/            makefiles for QNX
+win32/          makefiles for Windows
+
+                zlib public header files (must be kept):
+zconf.h
+zlib.h
+
+                private source files used to build the zlib library:
+adler32.c
+compress.c
+crc32.c
+crc32.h
+deflate.c
+deflate.h
+gzio.c
+infback.c
+inffast.c
+inffast.h
+inffixed.h
+inflate.c
+inflate.h
+inftrees.c
+inftrees.h
+trees.c
+trees.h
+uncompr.c
+zutil.c
+zutil.h
+
+                source files for sample programs:
+example.c
+minigzip.c
+
+                unsupported contribution by third parties
+See contrib/README.contrib
diff --git a/usr/klibc/zlib/Kbuild b/usr/klibc/zlib/Kbuild
new file mode 100644
index 0000000..f2e1bf2
--- /dev/null
+++ b/usr/klibc/zlib/Kbuild
@@ -0,0 +1,8 @@
+# zlib
+
+klib-y := adler32.o compress.o crc32.o gzio.o
+klib-y += uncompr.o deflate.o trees.o zutil.o
+klib-y += inflate.o infback.o inftrees.o inffast.o
+
+# zlib specific flag
+EXTRA_KLIBCCFLAGS := -DDYNAMIC_CRC_TABLE
diff --git a/usr/klibc/zlib/README b/usr/klibc/zlib/README
new file mode 100644
index 0000000..758cc50
--- /dev/null
+++ b/usr/klibc/zlib/README
@@ -0,0 +1,125 @@
+ZLIB DATA COMPRESSION LIBRARY
+
+zlib 1.2.3 is a general purpose data compression library.  All the code is
+thread safe.  The data format used by the zlib library is described by RFCs
+(Request for Comments) 1950 to 1952 in the files
+http://www.ietf.org/rfc/rfc1950.txt (zlib format), rfc1951.txt (deflate format)
+and rfc1952.txt (gzip format). These documents are also available in other
+formats from ftp://ftp.uu.net/graphics/png/documents/zlib/zdoc-index.html
+
+All functions of the compression library are documented in the file zlib.h
+(volunteer to write man pages welcome, contact zlib@gzip.org). A usage example
+of the library is given in the file example.c which also tests that the library
+is working correctly. Another example is given in the file minigzip.c. The
+compression library itself is composed of all source files except example.c and
+minigzip.c.
+
+To compile all files and run the test program, follow the instructions given at
+the top of Makefile. In short "make test; make install" should work for most
+machines. For Unix: "./configure; make test; make install". For MSDOS, use one
+of the special makefiles such as Makefile.msc. For VMS, use make_vms.com.
+
+Questions about zlib should be sent to <zlib@gzip.org>, or to Gilles Vollant
+<info@winimage.com> for the Windows DLL version. The zlib home page is
+http://www.zlib.org or http://www.gzip.org/zlib/ Before reporting a problem,
+please check this site to verify that you have the latest version of zlib;
+otherwise get the latest version and check whether the problem still exists or
+not.
+
+PLEASE read the zlib FAQ http://www.gzip.org/zlib/zlib_faq.html before asking
+for help.
+
+Mark Nelson <markn@ieee.org> wrote an article about zlib for the Jan. 1997
+issue of  Dr. Dobb's Journal; a copy of the article is available in
+http://dogma.net/markn/articles/zlibtool/zlibtool.htm
+
+The changes made in version 1.2.3 are documented in the file ChangeLog.
+
+Unsupported third party contributions are provided in directory "contrib".
+
+A Java implementation of zlib is available in the Java Development Kit
+http://java.sun.com/j2se/1.4.2/docs/api/java/util/zip/package-summary.html
+See the zlib home page http://www.zlib.org for details.
+
+A Perl interface to zlib written by Paul Marquess <pmqs@cpan.org> is in the
+CPAN (Comprehensive Perl Archive Network) sites
+http://www.cpan.org/modules/by-module/Compress/
+
+A Python interface to zlib written by A.M. Kuchling <amk@amk.ca> is
+available in Python 1.5 and later versions, see
+http://www.python.org/doc/lib/module-zlib.html
+
+A zlib binding for TCL written by Andreas Kupries <a.kupries@westend.com> is
+availlable at http://www.oche.de/~akupries/soft/trf/trf_zip.html
+
+An experimental package to read and write files in .zip format, written on top
+of zlib by Gilles Vollant <info@winimage.com>, is available in the
+contrib/minizip directory of zlib.
+
+
+Notes for some targets:
+
+- For Windows DLL versions, please see win32/DLL_FAQ.txt
+
+- For 64-bit Irix, deflate.c must be compiled without any optimization. With
+  -O, one libpng test fails. The test works in 32 bit mode (with the -n32
+  compiler flag). The compiler bug has been reported to SGI.
+
+- zlib doesn't work with gcc 2.6.3 on a DEC 3000/300LX under OSF/1 2.1 it works
+  when compiled with cc.
+
+- On Digital Unix 4.0D (formely OSF/1) on AlphaServer, the cc option -std1 is
+  necessary to get gzprintf working correctly. This is done by configure.
+
+- zlib doesn't work on HP-UX 9.05 with some versions of /bin/cc. It works with
+  other compilers. Use "make test" to check your compiler.
+
+- gzdopen is not supported on RISCOS, BEOS and by some Mac compilers.
+
+- For PalmOs, see http://palmzlib.sourceforge.net/
+
+- When building a shared, i.e. dynamic library on Mac OS X, the library must be
+  installed before testing (do "make install" before "make test"), since the
+  library location is specified in the library.
+
+
+Acknowledgments:
+
+  The deflate format used by zlib was defined by Phil Katz. The deflate
+  and zlib specifications were written by L. Peter Deutsch. Thanks to all the
+  people who reported problems and suggested various improvements in zlib;
+  they are too numerous to cite here.
+
+Copyright notice:
+
+ (C) 1995-2004 Jean-loup Gailly and Mark Adler
+
+  This software is provided 'as-is', without any express or implied
+  warranty.  In no event will the authors be held liable for any damages
+  arising from the use of this software.
+
+  Permission is granted to anyone to use this software for any purpose,
+  including commercial applications, and to alter it and redistribute it
+  freely, subject to the following restrictions:
+
+  1. The origin of this software must not be misrepresented; you must not
+     claim that you wrote the original software. If you use this software
+     in a product, an acknowledgment in the product documentation would be
+     appreciated but is not required.
+  2. Altered source versions must be plainly marked as such, and must not be
+     misrepresented as being the original software.
+  3. This notice may not be removed or altered from any source distribution.
+
+  Jean-loup Gailly        Mark Adler
+  jloup@gzip.org          madler@alumni.caltech.edu
+
+If you use the zlib library in a product, we would appreciate *not*
+receiving lengthy legal documents to sign. The sources are provided
+for free but without warranty of any kind.  The library has been
+entirely written by Jean-loup Gailly and Mark Adler; it does not
+include third-party code.
+
+If you redistribute modified sources, we would appreciate that you include
+in the file ChangeLog history information documenting your changes. Please
+read the FAQ for more information on the distribution of modified source
+versions.
diff --git a/usr/klibc/zlib/adler32.c b/usr/klibc/zlib/adler32.c
new file mode 100644
index 0000000..22e1151
--- /dev/null
+++ b/usr/klibc/zlib/adler32.c
@@ -0,0 +1,149 @@
+/* adler32.c -- compute the Adler-32 checksum of a data stream
+ * Copyright (C) 1995-2004 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* @(#) $Id: adler32.c,v 1.1 2005/02/27 23:15:39 hpa Exp $ */
+
+#define ZLIB_INTERNAL
+#include "zlib.h"
+
+#define BASE 65521UL    /* largest prime smaller than 65536 */
+#define NMAX 5552
+/* NMAX is the largest n such that 255n(n+1)/2 + (n+1)(BASE-1) <= 2^32-1 */
+
+#define DO1(buf,i)  {adler += (buf)[i]; sum2 += adler;}
+#define DO2(buf,i)  DO1(buf,i); DO1(buf,i+1);
+#define DO4(buf,i)  DO2(buf,i); DO2(buf,i+2);
+#define DO8(buf,i)  DO4(buf,i); DO4(buf,i+4);
+#define DO16(buf)   DO8(buf,0); DO8(buf,8);
+
+/* use NO_DIVIDE if your processor does not do division in hardware */
+#ifdef NO_DIVIDE
+#  define MOD(a) \
+    do { \
+        if (a >= (BASE << 16)) a -= (BASE << 16); \
+        if (a >= (BASE << 15)) a -= (BASE << 15); \
+        if (a >= (BASE << 14)) a -= (BASE << 14); \
+        if (a >= (BASE << 13)) a -= (BASE << 13); \
+        if (a >= (BASE << 12)) a -= (BASE << 12); \
+        if (a >= (BASE << 11)) a -= (BASE << 11); \
+        if (a >= (BASE << 10)) a -= (BASE << 10); \
+        if (a >= (BASE << 9)) a -= (BASE << 9); \
+        if (a >= (BASE << 8)) a -= (BASE << 8); \
+        if (a >= (BASE << 7)) a -= (BASE << 7); \
+        if (a >= (BASE << 6)) a -= (BASE << 6); \
+        if (a >= (BASE << 5)) a -= (BASE << 5); \
+        if (a >= (BASE << 4)) a -= (BASE << 4); \
+        if (a >= (BASE << 3)) a -= (BASE << 3); \
+        if (a >= (BASE << 2)) a -= (BASE << 2); \
+        if (a >= (BASE << 1)) a -= (BASE << 1); \
+        if (a >= BASE) a -= BASE; \
+    } while (0)
+#  define MOD4(a) \
+    do { \
+        if (a >= (BASE << 4)) a -= (BASE << 4); \
+        if (a >= (BASE << 3)) a -= (BASE << 3); \
+        if (a >= (BASE << 2)) a -= (BASE << 2); \
+        if (a >= (BASE << 1)) a -= (BASE << 1); \
+        if (a >= BASE) a -= BASE; \
+    } while (0)
+#else
+#  define MOD(a) a %= BASE
+#  define MOD4(a) a %= BASE
+#endif
+
+/* ========================================================================= */
+uLong ZEXPORT adler32(adler, buf, len)
+    uLong adler;
+    const Bytef *buf;
+    uInt len;
+{
+    unsigned long sum2;
+    unsigned n;
+
+    /* split Adler-32 into component sums */
+    sum2 = (adler >> 16) & 0xffff;
+    adler &= 0xffff;
+
+    /* in case user likes doing a byte at a time, keep it fast */
+    if (len == 1) {
+        adler += buf[0];
+        if (adler >= BASE)
+            adler -= BASE;
+        sum2 += adler;
+        if (sum2 >= BASE)
+            sum2 -= BASE;
+        return adler | (sum2 << 16);
+    }
+
+    /* initial Adler-32 value (deferred check for len == 1 speed) */
+    if (buf == Z_NULL)
+        return 1L;
+
+    /* in case short lengths are provided, keep it somewhat fast */
+    if (len < 16) {
+        while (len--) {
+            adler += *buf++;
+            sum2 += adler;
+        }
+        if (adler >= BASE)
+            adler -= BASE;
+        MOD4(sum2);             /* only added so many BASE's */
+        return adler | (sum2 << 16);
+    }
+
+    /* do length NMAX blocks -- requires just one modulo operation */
+    while (len >= NMAX) {
+        len -= NMAX;
+        n = NMAX / 16;          /* NMAX is divisible by 16 */
+        do {
+            DO16(buf);          /* 16 sums unrolled */
+            buf += 16;
+        } while (--n);
+        MOD(adler);
+        MOD(sum2);
+    }
+
+    /* do remaining bytes (less than NMAX, still just one modulo) */
+    if (len) {                  /* avoid modulos if none remaining */
+        while (len >= 16) {
+            len -= 16;
+            DO16(buf);
+            buf += 16;
+        }
+        while (len--) {
+            adler += *buf++;
+            sum2 += adler;
+        }
+        MOD(adler);
+        MOD(sum2);
+    }
+
+    /* return recombined sums */
+    return adler | (sum2 << 16);
+}
+
+/* ========================================================================= */
+uLong ZEXPORT adler32_combine(adler1, adler2, len2)
+    uLong adler1;
+    uLong adler2;
+    z_off_t len2;
+{
+    unsigned long sum1;
+    unsigned long sum2;
+    unsigned rem;
+
+    /* the derivation of this formula is left as an exercise for the reader */
+    rem = (unsigned)(len2 % BASE);
+    sum1 = adler1 & 0xffff;
+    sum2 = rem * sum1;
+    MOD(sum2);
+    sum1 += (adler2 & 0xffff) + BASE - 1;
+    sum2 += ((adler1 >> 16) & 0xffff) + ((adler2 >> 16) & 0xffff) + BASE - rem;
+    if (sum1 > BASE) sum1 -= BASE;
+    if (sum1 > BASE) sum1 -= BASE;
+    if (sum2 > (BASE << 1)) sum2 -= (BASE << 1);
+    if (sum2 > BASE) sum2 -= BASE;
+    return sum1 | (sum2 << 16);
+}
diff --git a/usr/klibc/zlib/algorithm.txt b/usr/klibc/zlib/algorithm.txt
new file mode 100644
index 0000000..b022dde
--- /dev/null
+++ b/usr/klibc/zlib/algorithm.txt
@@ -0,0 +1,209 @@
+1. Compression algorithm (deflate)
+
+The deflation algorithm used by gzip (also zip and zlib) is a variation of
+LZ77 (Lempel-Ziv 1977, see reference below). It finds duplicated strings in
+the input data.  The second occurrence of a string is replaced by a
+pointer to the previous string, in the form of a pair (distance,
+length).  Distances are limited to 32K bytes, and lengths are limited
+to 258 bytes. When a string does not occur anywhere in the previous
+32K bytes, it is emitted as a sequence of literal bytes.  (In this
+description, `string' must be taken as an arbitrary sequence of bytes,
+and is not restricted to printable characters.)
+
+Literals or match lengths are compressed with one Huffman tree, and
+match distances are compressed with another tree. The trees are stored
+in a compact form at the start of each block. The blocks can have any
+size (except that the compressed data for one block must fit in
+available memory). A block is terminated when deflate() determines that
+it would be useful to start another block with fresh trees. (This is
+somewhat similar to the behavior of LZW-based _compress_.)
+
+Duplicated strings are found using a hash table. All input strings of
+length 3 are inserted in the hash table. A hash index is computed for
+the next 3 bytes. If the hash chain for this index is not empty, all
+strings in the chain are compared with the current input string, and
+the longest match is selected.
+
+The hash chains are searched starting with the most recent strings, to
+favor small distances and thus take advantage of the Huffman encoding.
+The hash chains are singly linked. There are no deletions from the
+hash chains, the algorithm simply discards matches that are too old.
+
+To avoid a worst-case situation, very long hash chains are arbitrarily
+truncated at a certain length, determined by a runtime option (level
+parameter of deflateInit). So deflate() does not always find the longest
+possible match but generally finds a match which is long enough.
+
+deflate() also defers the selection of matches with a lazy evaluation
+mechanism. After a match of length N has been found, deflate() searches for
+a longer match at the next input byte. If a longer match is found, the
+previous match is truncated to a length of one (thus producing a single
+literal byte) and the process of lazy evaluation begins again. Otherwise,
+the original match is kept, and the next match search is attempted only N
+steps later.
+
+The lazy match evaluation is also subject to a runtime parameter. If
+the current match is long enough, deflate() reduces the search for a longer
+match, thus speeding up the whole process. If compression ratio is more
+important than speed, deflate() attempts a complete second search even if
+the first match is already long enough.
+
+The lazy match evaluation is not performed for the fastest compression
+modes (level parameter 1 to 3). For these fast modes, new strings
+are inserted in the hash table only when no match was found, or
+when the match is not too long. This degrades the compression ratio
+but saves time since there are both fewer insertions and fewer searches.
+
+
+2. Decompression algorithm (inflate)
+
+2.1 Introduction
+
+The key question is how to represent a Huffman code (or any prefix code) so
+that you can decode fast.  The most important characteristic is that shorter
+codes are much more common than longer codes, so pay attention to decoding the
+short codes fast, and let the long codes take longer to decode.
+
+inflate() sets up a first level table that covers some number of bits of
+input less than the length of longest code.  It gets that many bits from the
+stream, and looks it up in the table.  The table will tell if the next
+code is that many bits or less and how many, and if it is, it will tell
+the value, else it will point to the next level table for which inflate()
+grabs more bits and tries to decode a longer code.
+
+How many bits to make the first lookup is a tradeoff between the time it
+takes to decode and the time it takes to build the table.  If building the
+table took no time (and if you had infinite memory), then there would only
+be a first level table to cover all the way to the longest code.  However,
+building the table ends up taking a lot longer for more bits since short
+codes are replicated many times in such a table.  What inflate() does is
+simply to make the number of bits in the first table a variable, and  then
+to set that variable for the maximum speed.
+
+For inflate, which has 286 possible codes for the literal/length tree, the size
+of the first table is nine bits.  Also the distance trees have 30 possible
+values, and the size of the first table is six bits.  Note that for each of
+those cases, the table ended up one bit longer than the ``average'' code
+length, i.e. the code length of an approximately flat code which would be a
+little more than eight bits for 286 symbols and a little less than five bits
+for 30 symbols.
+
+
+2.2 More details on the inflate table lookup
+
+Ok, you want to know what this cleverly obfuscated inflate tree actually
+looks like.  You are correct that it's not a Huffman tree.  It is simply a
+lookup table for the first, let's say, nine bits of a Huffman symbol.  The
+symbol could be as short as one bit or as long as 15 bits.  If a particular
+symbol is shorter than nine bits, then that symbol's translation is duplicated
+in all those entries that start with that symbol's bits.  For example, if the
+symbol is four bits, then it's duplicated 32 times in a nine-bit table.  If a
+symbol is nine bits long, it appears in the table once.
+
+If the symbol is longer than nine bits, then that entry in the table points
+to another similar table for the remaining bits.  Again, there are duplicated
+entries as needed.  The idea is that most of the time the symbol will be short
+and there will only be one table look up.  (That's whole idea behind data
+compression in the first place.)  For the less frequent long symbols, there
+will be two lookups.  If you had a compression method with really long
+symbols, you could have as many levels of lookups as is efficient.  For
+inflate, two is enough.
+
+So a table entry either points to another table (in which case nine bits in
+the above example are gobbled), or it contains the translation for the symbol
+and the number of bits to gobble.  Then you start again with the next
+ungobbled bit.
+
+You may wonder: why not just have one lookup table for how ever many bits the
+longest symbol is?  The reason is that if you do that, you end up spending
+more time filling in duplicate symbol entries than you do actually decoding.
+At least for deflate's output that generates new trees every several 10's of
+kbytes.  You can imagine that filling in a 2^15 entry table for a 15-bit code
+would take too long if you're only decoding several thousand symbols.  At the
+other extreme, you could make a new table for every bit in the code.  In fact,
+that's essentially a Huffman tree.  But then you spend two much time
+traversing the tree while decoding, even for short symbols.
+
+So the number of bits for the first lookup table is a trade of the time to
+fill out the table vs. the time spent looking at the second level and above of
+the table.
+
+Here is an example, scaled down:
+
+The code being decoded, with 10 symbols, from 1 to 6 bits long:
+
+A: 0
+B: 10
+C: 1100
+D: 11010
+E: 11011
+F: 11100
+G: 11101
+H: 11110
+I: 111110
+J: 111111
+
+Let's make the first table three bits long (eight entries):
+
+000: A,1
+001: A,1
+010: A,1
+011: A,1
+100: B,2
+101: B,2
+110: -> table X (gobble 3 bits)
+111: -> table Y (gobble 3 bits)
+
+Each entry is what the bits decode as and how many bits that is, i.e. how
+many bits to gobble.  Or the entry points to another table, with the number of
+bits to gobble implicit in the size of the table.
+
+Table X is two bits long since the longest code starting with 110 is five bits
+long:
+
+00: C,1
+01: C,1
+10: D,2
+11: E,2
+
+Table Y is three bits long since the longest code starting with 111 is six
+bits long:
+
+000: F,2
+001: F,2
+010: G,2
+011: G,2
+100: H,2
+101: H,2
+110: I,3
+111: J,3
+
+So what we have here are three tables with a total of 20 entries that had to
+be constructed.  That's compared to 64 entries for a single table.  Or
+compared to 16 entries for a Huffman tree (six two entry tables and one four
+entry table).  Assuming that the code ideally represents the probability of
+the symbols, it takes on the average 1.25 lookups per symbol.  That's compared
+to one lookup for the single table, or 1.66 lookups per symbol for the
+Huffman tree.
+
+There, I think that gives you a picture of what's going on.  For inflate, the
+meaning of a particular symbol is often more than just a letter.  It can be a
+byte (a "literal"), or it can be either a length or a distance which
+indicates a base value and a number of bits to fetch after the code that is
+added to the base value.  Or it might be the special end-of-block code.  The
+data structures created in inftrees.c try to encode all that information
+compactly in the tables.
+
+
+Jean-loup Gailly        Mark Adler
+jloup@gzip.org          madler@alumni.caltech.edu
+
+
+References:
+
+[LZ77] Ziv J., Lempel A., ``A Universal Algorithm for Sequential Data
+Compression,'' IEEE Transactions on Information Theory, Vol. 23, No. 3,
+pp. 337-343.
+
+``DEFLATE Compressed Data Format Specification'' available in
+http://www.ietf.org/rfc/rfc1951.txt
diff --git a/usr/klibc/zlib/compress.c b/usr/klibc/zlib/compress.c
new file mode 100644
index 0000000..4f48f55
--- /dev/null
+++ b/usr/klibc/zlib/compress.c
@@ -0,0 +1,79 @@
+/* compress.c -- compress a memory buffer
+ * Copyright (C) 1995-2003 Jean-loup Gailly.
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* @(#) $Id: compress.c,v 1.1 2005/02/27 23:15:39 hpa Exp $ */
+
+#define ZLIB_INTERNAL
+#include "zlib.h"
+
+/* ===========================================================================
+     Compresses the source buffer into the destination buffer. The level
+   parameter has the same meaning as in deflateInit.  sourceLen is the byte
+   length of the source buffer. Upon entry, destLen is the total size of the
+   destination buffer, which must be at least 0.1% larger than sourceLen plus
+   12 bytes. Upon exit, destLen is the actual size of the compressed buffer.
+
+     compress2 returns Z_OK if success, Z_MEM_ERROR if there was not enough
+   memory, Z_BUF_ERROR if there was not enough room in the output buffer,
+   Z_STREAM_ERROR if the level parameter is invalid.
+*/
+int ZEXPORT compress2 (dest, destLen, source, sourceLen, level)
+    Bytef *dest;
+    uLongf *destLen;
+    const Bytef *source;
+    uLong sourceLen;
+    int level;
+{
+    z_stream stream;
+    int err;
+
+    stream.next_in = (Bytef*)source;
+    stream.avail_in = (uInt)sourceLen;
+#ifdef MAXSEG_64K
+    /* Check for source > 64K on 16-bit machine: */
+    if ((uLong)stream.avail_in != sourceLen) return Z_BUF_ERROR;
+#endif
+    stream.next_out = dest;
+    stream.avail_out = (uInt)*destLen;
+    if ((uLong)stream.avail_out != *destLen) return Z_BUF_ERROR;
+
+    stream.zalloc = (alloc_func)0;
+    stream.zfree = (free_func)0;
+    stream.opaque = (voidpf)0;
+
+    err = deflateInit(&stream, level);
+    if (err != Z_OK) return err;
+
+    err = deflate(&stream, Z_FINISH);
+    if (err != Z_STREAM_END) {
+        deflateEnd(&stream);
+        return err == Z_OK ? Z_BUF_ERROR : err;
+    }
+    *destLen = stream.total_out;
+
+    err = deflateEnd(&stream);
+    return err;
+}
+
+/* ===========================================================================
+ */
+int ZEXPORT compress (dest, destLen, source, sourceLen)
+    Bytef *dest;
+    uLongf *destLen;
+    const Bytef *source;
+    uLong sourceLen;
+{
+    return compress2(dest, destLen, source, sourceLen, Z_DEFAULT_COMPRESSION);
+}
+
+/* ===========================================================================
+     If the default memLevel or windowBits for deflateInit() is changed, then
+   this function needs to be updated.
+ */
+uLong ZEXPORT compressBound (sourceLen)
+    uLong sourceLen;
+{
+    return sourceLen + (sourceLen >> 12) + (sourceLen >> 14) + 11;
+}
diff --git a/usr/klibc/zlib/crc32.c b/usr/klibc/zlib/crc32.c
new file mode 100644
index 0000000..f658a9e
--- /dev/null
+++ b/usr/klibc/zlib/crc32.c
@@ -0,0 +1,423 @@
+/* crc32.c -- compute the CRC-32 of a data stream
+ * Copyright (C) 1995-2005 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ *
+ * Thanks to Rodney Brown <rbrown64@csc.com.au> for his contribution of faster
+ * CRC methods: exclusive-oring 32 bits of data at a time, and pre-computing
+ * tables for updating the shift register in one step with three exclusive-ors
+ * instead of four steps with four exclusive-ors.  This results in about a
+ * factor of two increase in speed on a Power PC G4 (PPC7455) using gcc -O3.
+ */
+
+/* @(#) $Id$ */
+
+/*
+  Note on the use of DYNAMIC_CRC_TABLE: there is no mutex or semaphore
+  protection on the static variables used to control the first-use generation
+  of the crc tables.  Therefore, if you #define DYNAMIC_CRC_TABLE, you should
+  first call get_crc_table() to initialize the tables before allowing more than
+  one thread to use crc32().
+ */
+
+#ifdef MAKECRCH
+#  include <stdio.h>
+#  ifndef DYNAMIC_CRC_TABLE
+#    define DYNAMIC_CRC_TABLE
+#  endif /* !DYNAMIC_CRC_TABLE */
+#endif /* MAKECRCH */
+
+#include "zutil.h"      /* for STDC and FAR definitions */
+
+#define local static
+
+/* Find a four-byte integer type for crc32_little() and crc32_big(). */
+#ifndef NOBYFOUR
+#  ifdef STDC           /* need ANSI C limits.h to determine sizes */
+#    include <limits.h>
+#    define BYFOUR
+#    if (UINT_MAX == 0xffffffffUL)
+       typedef unsigned int u4;
+#    else
+#      if (ULONG_MAX == 0xffffffffUL)
+         typedef unsigned long u4;
+#      else
+#        if (USHRT_MAX == 0xffffffffUL)
+           typedef unsigned short u4;
+#        else
+#          undef BYFOUR     /* can't find a four-byte integer type! */
+#        endif
+#      endif
+#    endif
+#  endif /* STDC */
+#endif /* !NOBYFOUR */
+
+/* Definitions for doing the crc four data bytes at a time. */
+#ifdef BYFOUR
+#  define REV(w) (((w)>>24)+(((w)>>8)&0xff00)+ \
+                (((w)&0xff00)<<8)+(((w)&0xff)<<24))
+   local unsigned long crc32_little OF((unsigned long,
+                        const unsigned char FAR *, unsigned));
+   local unsigned long crc32_big OF((unsigned long,
+                        const unsigned char FAR *, unsigned));
+#  define TBLS 8
+#else
+#  define TBLS 1
+#endif /* BYFOUR */
+
+/* Local functions for crc concatenation */
+local unsigned long gf2_matrix_times OF((unsigned long *mat,
+                                         unsigned long vec));
+local void gf2_matrix_square OF((unsigned long *square, unsigned long *mat));
+
+#ifdef DYNAMIC_CRC_TABLE
+
+local volatile int crc_table_empty = 1;
+local unsigned long FAR crc_table[TBLS][256];
+local void make_crc_table OF((void));
+#ifdef MAKECRCH
+   local void write_table OF((FILE *, const unsigned long FAR *));
+#endif /* MAKECRCH */
+/*
+  Generate tables for a byte-wise 32-bit CRC calculation on the polynomial:
+  x^32+x^26+x^23+x^22+x^16+x^12+x^11+x^10+x^8+x^7+x^5+x^4+x^2+x+1.
+
+  Polynomials over GF(2) are represented in binary, one bit per coefficient,
+  with the lowest powers in the most significant bit.  Then adding polynomials
+  is just exclusive-or, and multiplying a polynomial by x is a right shift by
+  one.  If we call the above polynomial p, and represent a byte as the
+  polynomial q, also with the lowest power in the most significant bit (so the
+  byte 0xb1 is the polynomial x^7+x^3+x+1), then the CRC is (q*x^32) mod p,
+  where a mod b means the remainder after dividing a by b.
+
+  This calculation is done using the shift-register method of multiplying and
+  taking the remainder.  The register is initialized to zero, and for each
+  incoming bit, x^32 is added mod p to the register if the bit is a one (where
+  x^32 mod p is p+x^32 = x^26+...+1), and the register is multiplied mod p by
+  x (which is shifting right by one and adding x^32 mod p if the bit shifted
+  out is a one).  We start with the highest power (least significant bit) of
+  q and repeat for all eight bits of q.
+
+  The first table is simply the CRC of all possible eight bit values.  This is
+  all the information needed to generate CRCs on data a byte at a time for all
+  combinations of CRC register values and incoming bytes.  The remaining tables
+  allow for word-at-a-time CRC calculation for both big-endian and little-
+  endian machines, where a word is four bytes.
+*/
+local void make_crc_table()
+{
+    unsigned long c;
+    int n, k;
+    unsigned long poly;                 /* polynomial exclusive-or pattern */
+    /* terms of polynomial defining this crc (except x^32): */
+    static volatile int first = 1;      /* flag to limit concurrent making */
+    static const unsigned char p[] = {0,1,2,4,5,7,8,10,11,12,16,22,23,26};
+
+    /* See if another task is already doing this (not thread-safe, but better
+       than nothing -- significantly reduces duration of vulnerability in
+       case the advice about DYNAMIC_CRC_TABLE is ignored) */
+    if (first) {
+        first = 0;
+
+        /* make exclusive-or pattern from polynomial (0xedb88320UL) */
+        poly = 0UL;
+        for (n = 0; n < sizeof(p)/sizeof(unsigned char); n++)
+            poly |= 1UL << (31 - p[n]);
+
+        /* generate a crc for every 8-bit value */
+        for (n = 0; n < 256; n++) {
+            c = (unsigned long)n;
+            for (k = 0; k < 8; k++)
+                c = c & 1 ? poly ^ (c >> 1) : c >> 1;
+            crc_table[0][n] = c;
+        }
+
+#ifdef BYFOUR
+        /* generate crc for each value followed by one, two, and three zeros,
+           and then the byte reversal of those as well as the first table */
+        for (n = 0; n < 256; n++) {
+            c = crc_table[0][n];
+            crc_table[4][n] = REV(c);
+            for (k = 1; k < 4; k++) {
+                c = crc_table[0][c & 0xff] ^ (c >> 8);
+                crc_table[k][n] = c;
+                crc_table[k + 4][n] = REV(c);
+            }
+        }
+#endif /* BYFOUR */
+
+        crc_table_empty = 0;
+    }
+    else {      /* not first */
+        /* wait for the other guy to finish (not efficient, but rare) */
+        while (crc_table_empty)
+            ;
+    }
+
+#ifdef MAKECRCH
+    /* write out CRC tables to crc32.h */
+    {
+        FILE *out;
+
+        out = fopen("crc32.h", "w");
+        if (out == NULL) return;
+        fprintf(out, "/* crc32.h -- tables for rapid CRC calculation\n");
+        fprintf(out, " * Generated automatically by crc32.c\n */\n\n");
+        fprintf(out, "local const unsigned long FAR ");
+        fprintf(out, "crc_table[TBLS][256] =\n{\n  {\n");
+        write_table(out, crc_table[0]);
+#  ifdef BYFOUR
+        fprintf(out, "#ifdef BYFOUR\n");
+        for (k = 1; k < 8; k++) {
+            fprintf(out, "  },\n  {\n");
+            write_table(out, crc_table[k]);
+        }
+        fprintf(out, "#endif\n");
+#  endif /* BYFOUR */
+        fprintf(out, "  }\n};\n");
+        fclose(out);
+    }
+#endif /* MAKECRCH */
+}
+
+#ifdef MAKECRCH
+local void write_table(out, table)
+    FILE *out;
+    const unsigned long FAR *table;
+{
+    int n;
+
+    for (n = 0; n < 256; n++)
+        fprintf(out, "%s0x%08lxUL%s", n % 5 ? "" : "    ", table[n],
+                n == 255 ? "\n" : (n % 5 == 4 ? ",\n" : ", "));
+}
+#endif /* MAKECRCH */
+
+#else /* !DYNAMIC_CRC_TABLE */
+/* ========================================================================
+ * Tables of CRC-32s of all single-byte values, made by make_crc_table().
+ */
+#include "crc32.h"
+#endif /* DYNAMIC_CRC_TABLE */
+
+/* =========================================================================
+ * This function can be used by asm versions of crc32()
+ */
+const unsigned long FAR * ZEXPORT get_crc_table()
+{
+#ifdef DYNAMIC_CRC_TABLE
+    if (crc_table_empty)
+        make_crc_table();
+#endif /* DYNAMIC_CRC_TABLE */
+    return (const unsigned long FAR *)crc_table;
+}
+
+/* ========================================================================= */
+#define DO1 crc = crc_table[0][((int)crc ^ (*buf++)) & 0xff] ^ (crc >> 8)
+#define DO8 DO1; DO1; DO1; DO1; DO1; DO1; DO1; DO1
+
+/* ========================================================================= */
+unsigned long ZEXPORT crc32(crc, buf, len)
+    unsigned long crc;
+    const unsigned char FAR *buf;
+    unsigned len;
+{
+    if (buf == Z_NULL) return 0UL;
+
+#ifdef DYNAMIC_CRC_TABLE
+    if (crc_table_empty)
+        make_crc_table();
+#endif /* DYNAMIC_CRC_TABLE */
+
+#ifdef BYFOUR
+    if (sizeof(void *) == sizeof(ptrdiff_t)) {
+        u4 endian;
+
+        endian = 1;
+        if (*((unsigned char *)(&endian)))
+            return crc32_little(crc, buf, len);
+        else
+            return crc32_big(crc, buf, len);
+    }
+#endif /* BYFOUR */
+    crc = crc ^ 0xffffffffUL;
+    while (len >= 8) {
+        DO8;
+        len -= 8;
+    }
+    if (len) do {
+        DO1;
+    } while (--len);
+    return crc ^ 0xffffffffUL;
+}
+
+#ifdef BYFOUR
+
+/* ========================================================================= */
+#define DOLIT4 c ^= *buf4++; \
+        c = crc_table[3][c & 0xff] ^ crc_table[2][(c >> 8) & 0xff] ^ \
+            crc_table[1][(c >> 16) & 0xff] ^ crc_table[0][c >> 24]
+#define DOLIT32 DOLIT4; DOLIT4; DOLIT4; DOLIT4; DOLIT4; DOLIT4; DOLIT4; DOLIT4
+
+/* ========================================================================= */
+local unsigned long crc32_little(crc, buf, len)
+    unsigned long crc;
+    const unsigned char FAR *buf;
+    unsigned len;
+{
+    register u4 c;
+    register const u4 FAR *buf4;
+
+    c = (u4)crc;
+    c = ~c;
+    while (len && ((ptrdiff_t)buf & 3)) {
+        c = crc_table[0][(c ^ *buf++) & 0xff] ^ (c >> 8);
+        len--;
+    }
+
+    buf4 = (const u4 FAR *)(const void FAR *)buf;
+    while (len >= 32) {
+        DOLIT32;
+        len -= 32;
+    }
+    while (len >= 4) {
+        DOLIT4;
+        len -= 4;
+    }
+    buf = (const unsigned char FAR *)buf4;
+
+    if (len) do {
+        c = crc_table[0][(c ^ *buf++) & 0xff] ^ (c >> 8);
+    } while (--len);
+    c = ~c;
+    return (unsigned long)c;
+}
+
+/* ========================================================================= */
+#define DOBIG4 c ^= *++buf4; \
+        c = crc_table[4][c & 0xff] ^ crc_table[5][(c >> 8) & 0xff] ^ \
+            crc_table[6][(c >> 16) & 0xff] ^ crc_table[7][c >> 24]
+#define DOBIG32 DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4
+
+/* ========================================================================= */
+local unsigned long crc32_big(crc, buf, len)
+    unsigned long crc;
+    const unsigned char FAR *buf;
+    unsigned len;
+{
+    register u4 c;
+    register const u4 FAR *buf4;
+
+    c = REV((u4)crc);
+    c = ~c;
+    while (len && ((ptrdiff_t)buf & 3)) {
+        c = crc_table[4][(c >> 24) ^ *buf++] ^ (c << 8);
+        len--;
+    }
+
+    buf4 = (const u4 FAR *)(const void FAR *)buf;
+    buf4--;
+    while (len >= 32) {
+        DOBIG32;
+        len -= 32;
+    }
+    while (len >= 4) {
+        DOBIG4;
+        len -= 4;
+    }
+    buf4++;
+    buf = (const unsigned char FAR *)buf4;
+
+    if (len) do {
+        c = crc_table[4][(c >> 24) ^ *buf++] ^ (c << 8);
+    } while (--len);
+    c = ~c;
+    return (unsigned long)(REV(c));
+}
+
+#endif /* BYFOUR */
+
+#define GF2_DIM 32      /* dimension of GF(2) vectors (length of CRC) */
+
+/* ========================================================================= */
+local unsigned long gf2_matrix_times(mat, vec)
+    unsigned long *mat;
+    unsigned long vec;
+{
+    unsigned long sum;
+
+    sum = 0;
+    while (vec) {
+        if (vec & 1)
+            sum ^= *mat;
+        vec >>= 1;
+        mat++;
+    }
+    return sum;
+}
+
+/* ========================================================================= */
+local void gf2_matrix_square(square, mat)
+    unsigned long *square;
+    unsigned long *mat;
+{
+    int n;
+
+    for (n = 0; n < GF2_DIM; n++)
+        square[n] = gf2_matrix_times(mat, mat[n]);
+}
+
+/* ========================================================================= */
+uLong ZEXPORT crc32_combine(crc1, crc2, len2)
+    uLong crc1;
+    uLong crc2;
+    z_off_t len2;
+{
+    int n;
+    unsigned long row;
+    unsigned long even[GF2_DIM];    /* even-power-of-two zeros operator */
+    unsigned long odd[GF2_DIM];     /* odd-power-of-two zeros operator */
+
+    /* degenerate case */
+    if (len2 == 0)
+        return crc1;
+
+    /* put operator for one zero bit in odd */
+    odd[0] = 0xedb88320L;           /* CRC-32 polynomial */
+    row = 1;
+    for (n = 1; n < GF2_DIM; n++) {
+        odd[n] = row;
+        row <<= 1;
+    }
+
+    /* put operator for two zero bits in even */
+    gf2_matrix_square(even, odd);
+
+    /* put operator for four zero bits in odd */
+    gf2_matrix_square(odd, even);
+
+    /* apply len2 zeros to crc1 (first square will put the operator for one
+       zero byte, eight zero bits, in even) */
+    do {
+        /* apply zeros operator for this bit of len2 */
+        gf2_matrix_square(even, odd);
+        if (len2 & 1)
+            crc1 = gf2_matrix_times(even, crc1);
+        len2 >>= 1;
+
+        /* if no more bits set, then done */
+        if (len2 == 0)
+            break;
+
+        /* another iteration of the loop with odd and even swapped */
+        gf2_matrix_square(odd, even);
+        if (len2 & 1)
+            crc1 = gf2_matrix_times(odd, crc1);
+        len2 >>= 1;
+
+        /* if no more bits set, then done */
+    } while (len2 != 0);
+
+    /* return combined crc */
+    crc1 ^= crc2;
+    return crc1;
+}
diff --git a/usr/klibc/zlib/crc32.h b/usr/klibc/zlib/crc32.h
new file mode 100644
index 0000000..8053b61
--- /dev/null
+++ b/usr/klibc/zlib/crc32.h
@@ -0,0 +1,441 @@
+/* crc32.h -- tables for rapid CRC calculation
+ * Generated automatically by crc32.c
+ */
+
+local const unsigned long FAR crc_table[TBLS][256] =
+{
+  {
+    0x00000000UL, 0x77073096UL, 0xee0e612cUL, 0x990951baUL, 0x076dc419UL,
+    0x706af48fUL, 0xe963a535UL, 0x9e6495a3UL, 0x0edb8832UL, 0x79dcb8a4UL,
+    0xe0d5e91eUL, 0x97d2d988UL, 0x09b64c2bUL, 0x7eb17cbdUL, 0xe7b82d07UL,
+    0x90bf1d91UL, 0x1db71064UL, 0x6ab020f2UL, 0xf3b97148UL, 0x84be41deUL,
+    0x1adad47dUL, 0x6ddde4ebUL, 0xf4d4b551UL, 0x83d385c7UL, 0x136c9856UL,
+    0x646ba8c0UL, 0xfd62f97aUL, 0x8a65c9ecUL, 0x14015c4fUL, 0x63066cd9UL,
+    0xfa0f3d63UL, 0x8d080df5UL, 0x3b6e20c8UL, 0x4c69105eUL, 0xd56041e4UL,
+    0xa2677172UL, 0x3c03e4d1UL, 0x4b04d447UL, 0xd20d85fdUL, 0xa50ab56bUL,
+    0x35b5a8faUL, 0x42b2986cUL, 0xdbbbc9d6UL, 0xacbcf940UL, 0x32d86ce3UL,
+    0x45df5c75UL, 0xdcd60dcfUL, 0xabd13d59UL, 0x26d930acUL, 0x51de003aUL,
+    0xc8d75180UL, 0xbfd06116UL, 0x21b4f4b5UL, 0x56b3c423UL, 0xcfba9599UL,
+    0xb8bda50fUL, 0x2802b89eUL, 0x5f058808UL, 0xc60cd9b2UL, 0xb10be924UL,
+    0x2f6f7c87UL, 0x58684c11UL, 0xc1611dabUL, 0xb6662d3dUL, 0x76dc4190UL,
+    0x01db7106UL, 0x98d220bcUL, 0xefd5102aUL, 0x71b18589UL, 0x06b6b51fUL,
+    0x9fbfe4a5UL, 0xe8b8d433UL, 0x7807c9a2UL, 0x0f00f934UL, 0x9609a88eUL,
+    0xe10e9818UL, 0x7f6a0dbbUL, 0x086d3d2dUL, 0x91646c97UL, 0xe6635c01UL,
+    0x6b6b51f4UL, 0x1c6c6162UL, 0x856530d8UL, 0xf262004eUL, 0x6c0695edUL,
+    0x1b01a57bUL, 0x8208f4c1UL, 0xf50fc457UL, 0x65b0d9c6UL, 0x12b7e950UL,
+    0x8bbeb8eaUL, 0xfcb9887cUL, 0x62dd1ddfUL, 0x15da2d49UL, 0x8cd37cf3UL,
+    0xfbd44c65UL, 0x4db26158UL, 0x3ab551ceUL, 0xa3bc0074UL, 0xd4bb30e2UL,
+    0x4adfa541UL, 0x3dd895d7UL, 0xa4d1c46dUL, 0xd3d6f4fbUL, 0x4369e96aUL,
+    0x346ed9fcUL, 0xad678846UL, 0xda60b8d0UL, 0x44042d73UL, 0x33031de5UL,
+    0xaa0a4c5fUL, 0xdd0d7cc9UL, 0x5005713cUL, 0x270241aaUL, 0xbe0b1010UL,
+    0xc90c2086UL, 0x5768b525UL, 0x206f85b3UL, 0xb966d409UL, 0xce61e49fUL,
+    0x5edef90eUL, 0x29d9c998UL, 0xb0d09822UL, 0xc7d7a8b4UL, 0x59b33d17UL,
+    0x2eb40d81UL, 0xb7bd5c3bUL, 0xc0ba6cadUL, 0xedb88320UL, 0x9abfb3b6UL,
+    0x03b6e20cUL, 0x74b1d29aUL, 0xead54739UL, 0x9dd277afUL, 0x04db2615UL,
+    0x73dc1683UL, 0xe3630b12UL, 0x94643b84UL, 0x0d6d6a3eUL, 0x7a6a5aa8UL,
+    0xe40ecf0bUL, 0x9309ff9dUL, 0x0a00ae27UL, 0x7d079eb1UL, 0xf00f9344UL,
+    0x8708a3d2UL, 0x1e01f268UL, 0x6906c2feUL, 0xf762575dUL, 0x806567cbUL,
+    0x196c3671UL, 0x6e6b06e7UL, 0xfed41b76UL, 0x89d32be0UL, 0x10da7a5aUL,
+    0x67dd4accUL, 0xf9b9df6fUL, 0x8ebeeff9UL, 0x17b7be43UL, 0x60b08ed5UL,
+    0xd6d6a3e8UL, 0xa1d1937eUL, 0x38d8c2c4UL, 0x4fdff252UL, 0xd1bb67f1UL,
+    0xa6bc5767UL, 0x3fb506ddUL, 0x48b2364bUL, 0xd80d2bdaUL, 0xaf0a1b4cUL,
+    0x36034af6UL, 0x41047a60UL, 0xdf60efc3UL, 0xa867df55UL, 0x316e8eefUL,
+    0x4669be79UL, 0xcb61b38cUL, 0xbc66831aUL, 0x256fd2a0UL, 0x5268e236UL,
+    0xcc0c7795UL, 0xbb0b4703UL, 0x220216b9UL, 0x5505262fUL, 0xc5ba3bbeUL,
+    0xb2bd0b28UL, 0x2bb45a92UL, 0x5cb36a04UL, 0xc2d7ffa7UL, 0xb5d0cf31UL,
+    0x2cd99e8bUL, 0x5bdeae1dUL, 0x9b64c2b0UL, 0xec63f226UL, 0x756aa39cUL,
+    0x026d930aUL, 0x9c0906a9UL, 0xeb0e363fUL, 0x72076785UL, 0x05005713UL,
+    0x95bf4a82UL, 0xe2b87a14UL, 0x7bb12baeUL, 0x0cb61b38UL, 0x92d28e9bUL,
+    0xe5d5be0dUL, 0x7cdcefb7UL, 0x0bdbdf21UL, 0x86d3d2d4UL, 0xf1d4e242UL,
+    0x68ddb3f8UL, 0x1fda836eUL, 0x81be16cdUL, 0xf6b9265bUL, 0x6fb077e1UL,
+    0x18b74777UL, 0x88085ae6UL, 0xff0f6a70UL, 0x66063bcaUL, 0x11010b5cUL,
+    0x8f659effUL, 0xf862ae69UL, 0x616bffd3UL, 0x166ccf45UL, 0xa00ae278UL,
+    0xd70dd2eeUL, 0x4e048354UL, 0x3903b3c2UL, 0xa7672661UL, 0xd06016f7UL,
+    0x4969474dUL, 0x3e6e77dbUL, 0xaed16a4aUL, 0xd9d65adcUL, 0x40df0b66UL,
+    0x37d83bf0UL, 0xa9bcae53UL, 0xdebb9ec5UL, 0x47b2cf7fUL, 0x30b5ffe9UL,
+    0xbdbdf21cUL, 0xcabac28aUL, 0x53b39330UL, 0x24b4a3a6UL, 0xbad03605UL,
+    0xcdd70693UL, 0x54de5729UL, 0x23d967bfUL, 0xb3667a2eUL, 0xc4614ab8UL,
+    0x5d681b02UL, 0x2a6f2b94UL, 0xb40bbe37UL, 0xc30c8ea1UL, 0x5a05df1bUL,
+    0x2d02ef8dUL
+#ifdef BYFOUR
+  },
+  {
+    0x00000000UL, 0x191b3141UL, 0x32366282UL, 0x2b2d53c3UL, 0x646cc504UL,
+    0x7d77f445UL, 0x565aa786UL, 0x4f4196c7UL, 0xc8d98a08UL, 0xd1c2bb49UL,
+    0xfaefe88aUL, 0xe3f4d9cbUL, 0xacb54f0cUL, 0xb5ae7e4dUL, 0x9e832d8eUL,
+    0x87981ccfUL, 0x4ac21251UL, 0x53d92310UL, 0x78f470d3UL, 0x61ef4192UL,
+    0x2eaed755UL, 0x37b5e614UL, 0x1c98b5d7UL, 0x05838496UL, 0x821b9859UL,
+    0x9b00a918UL, 0xb02dfadbUL, 0xa936cb9aUL, 0xe6775d5dUL, 0xff6c6c1cUL,
+    0xd4413fdfUL, 0xcd5a0e9eUL, 0x958424a2UL, 0x8c9f15e3UL, 0xa7b24620UL,
+    0xbea97761UL, 0xf1e8e1a6UL, 0xe8f3d0e7UL, 0xc3de8324UL, 0xdac5b265UL,
+    0x5d5daeaaUL, 0x44469febUL, 0x6f6bcc28UL, 0x7670fd69UL, 0x39316baeUL,
+    0x202a5aefUL, 0x0b07092cUL, 0x121c386dUL, 0xdf4636f3UL, 0xc65d07b2UL,
+    0xed705471UL, 0xf46b6530UL, 0xbb2af3f7UL, 0xa231c2b6UL, 0x891c9175UL,
+    0x9007a034UL, 0x179fbcfbUL, 0x0e848dbaUL, 0x25a9de79UL, 0x3cb2ef38UL,
+    0x73f379ffUL, 0x6ae848beUL, 0x41c51b7dUL, 0x58de2a3cUL, 0xf0794f05UL,
+    0xe9627e44UL, 0xc24f2d87UL, 0xdb541cc6UL, 0x94158a01UL, 0x8d0ebb40UL,
+    0xa623e883UL, 0xbf38d9c2UL, 0x38a0c50dUL, 0x21bbf44cUL, 0x0a96a78fUL,
+    0x138d96ceUL, 0x5ccc0009UL, 0x45d73148UL, 0x6efa628bUL, 0x77e153caUL,
+    0xbabb5d54UL, 0xa3a06c15UL, 0x888d3fd6UL, 0x91960e97UL, 0xded79850UL,
+    0xc7cca911UL, 0xece1fad2UL, 0xf5facb93UL, 0x7262d75cUL, 0x6b79e61dUL,
+    0x4054b5deUL, 0x594f849fUL, 0x160e1258UL, 0x0f152319UL, 0x243870daUL,
+    0x3d23419bUL, 0x65fd6ba7UL, 0x7ce65ae6UL, 0x57cb0925UL, 0x4ed03864UL,
+    0x0191aea3UL, 0x188a9fe2UL, 0x33a7cc21UL, 0x2abcfd60UL, 0xad24e1afUL,
+    0xb43fd0eeUL, 0x9f12832dUL, 0x8609b26cUL, 0xc94824abUL, 0xd05315eaUL,
+    0xfb7e4629UL, 0xe2657768UL, 0x2f3f79f6UL, 0x362448b7UL, 0x1d091b74UL,
+    0x04122a35UL, 0x4b53bcf2UL, 0x52488db3UL, 0x7965de70UL, 0x607eef31UL,
+    0xe7e6f3feUL, 0xfefdc2bfUL, 0xd5d0917cUL, 0xcccba03dUL, 0x838a36faUL,
+    0x9a9107bbUL, 0xb1bc5478UL, 0xa8a76539UL, 0x3b83984bUL, 0x2298a90aUL,
+    0x09b5fac9UL, 0x10aecb88UL, 0x5fef5d4fUL, 0x46f46c0eUL, 0x6dd93fcdUL,
+    0x74c20e8cUL, 0xf35a1243UL, 0xea412302UL, 0xc16c70c1UL, 0xd8774180UL,
+    0x9736d747UL, 0x8e2de606UL, 0xa500b5c5UL, 0xbc1b8484UL, 0x71418a1aUL,
+    0x685abb5bUL, 0x4377e898UL, 0x5a6cd9d9UL, 0x152d4f1eUL, 0x0c367e5fUL,
+    0x271b2d9cUL, 0x3e001cddUL, 0xb9980012UL, 0xa0833153UL, 0x8bae6290UL,
+    0x92b553d1UL, 0xddf4c516UL, 0xc4eff457UL, 0xefc2a794UL, 0xf6d996d5UL,
+    0xae07bce9UL, 0xb71c8da8UL, 0x9c31de6bUL, 0x852aef2aUL, 0xca6b79edUL,
+    0xd37048acUL, 0xf85d1b6fUL, 0xe1462a2eUL, 0x66de36e1UL, 0x7fc507a0UL,
+    0x54e85463UL, 0x4df36522UL, 0x02b2f3e5UL, 0x1ba9c2a4UL, 0x30849167UL,
+    0x299fa026UL, 0xe4c5aeb8UL, 0xfdde9ff9UL, 0xd6f3cc3aUL, 0xcfe8fd7bUL,
+    0x80a96bbcUL, 0x99b25afdUL, 0xb29f093eUL, 0xab84387fUL, 0x2c1c24b0UL,
+    0x350715f1UL, 0x1e2a4632UL, 0x07317773UL, 0x4870e1b4UL, 0x516bd0f5UL,
+    0x7a468336UL, 0x635db277UL, 0xcbfad74eUL, 0xd2e1e60fUL, 0xf9ccb5ccUL,
+    0xe0d7848dUL, 0xaf96124aUL, 0xb68d230bUL, 0x9da070c8UL, 0x84bb4189UL,
+    0x03235d46UL, 0x1a386c07UL, 0x31153fc4UL, 0x280e0e85UL, 0x674f9842UL,
+    0x7e54a903UL, 0x5579fac0UL, 0x4c62cb81UL, 0x8138c51fUL, 0x9823f45eUL,
+    0xb30ea79dUL, 0xaa1596dcUL, 0xe554001bUL, 0xfc4f315aUL, 0xd7626299UL,
+    0xce7953d8UL, 0x49e14f17UL, 0x50fa7e56UL, 0x7bd72d95UL, 0x62cc1cd4UL,
+    0x2d8d8a13UL, 0x3496bb52UL, 0x1fbbe891UL, 0x06a0d9d0UL, 0x5e7ef3ecUL,
+    0x4765c2adUL, 0x6c48916eUL, 0x7553a02fUL, 0x3a1236e8UL, 0x230907a9UL,
+    0x0824546aUL, 0x113f652bUL, 0x96a779e4UL, 0x8fbc48a5UL, 0xa4911b66UL,
+    0xbd8a2a27UL, 0xf2cbbce0UL, 0xebd08da1UL, 0xc0fdde62UL, 0xd9e6ef23UL,
+    0x14bce1bdUL, 0x0da7d0fcUL, 0x268a833fUL, 0x3f91b27eUL, 0x70d024b9UL,
+    0x69cb15f8UL, 0x42e6463bUL, 0x5bfd777aUL, 0xdc656bb5UL, 0xc57e5af4UL,
+    0xee530937UL, 0xf7483876UL, 0xb809aeb1UL, 0xa1129ff0UL, 0x8a3fcc33UL,
+    0x9324fd72UL
+  },
+  {
+    0x00000000UL, 0x01c26a37UL, 0x0384d46eUL, 0x0246be59UL, 0x0709a8dcUL,
+    0x06cbc2ebUL, 0x048d7cb2UL, 0x054f1685UL, 0x0e1351b8UL, 0x0fd13b8fUL,
+    0x0d9785d6UL, 0x0c55efe1UL, 0x091af964UL, 0x08d89353UL, 0x0a9e2d0aUL,
+    0x0b5c473dUL, 0x1c26a370UL, 0x1de4c947UL, 0x1fa2771eUL, 0x1e601d29UL,
+    0x1b2f0bacUL, 0x1aed619bUL, 0x18abdfc2UL, 0x1969b5f5UL, 0x1235f2c8UL,
+    0x13f798ffUL, 0x11b126a6UL, 0x10734c91UL, 0x153c5a14UL, 0x14fe3023UL,
+    0x16b88e7aUL, 0x177ae44dUL, 0x384d46e0UL, 0x398f2cd7UL, 0x3bc9928eUL,
+    0x3a0bf8b9UL, 0x3f44ee3cUL, 0x3e86840bUL, 0x3cc03a52UL, 0x3d025065UL,
+    0x365e1758UL, 0x379c7d6fUL, 0x35dac336UL, 0x3418a901UL, 0x3157bf84UL,
+    0x3095d5b3UL, 0x32d36beaUL, 0x331101ddUL, 0x246be590UL, 0x25a98fa7UL,
+    0x27ef31feUL, 0x262d5bc9UL, 0x23624d4cUL, 0x22a0277bUL, 0x20e69922UL,
+    0x2124f315UL, 0x2a78b428UL, 0x2bbade1fUL, 0x29fc6046UL, 0x283e0a71UL,
+    0x2d711cf4UL, 0x2cb376c3UL, 0x2ef5c89aUL, 0x2f37a2adUL, 0x709a8dc0UL,
+    0x7158e7f7UL, 0x731e59aeUL, 0x72dc3399UL, 0x7793251cUL, 0x76514f2bUL,
+    0x7417f172UL, 0x75d59b45UL, 0x7e89dc78UL, 0x7f4bb64fUL, 0x7d0d0816UL,
+    0x7ccf6221UL, 0x798074a4UL, 0x78421e93UL, 0x7a04a0caUL, 0x7bc6cafdUL,
+    0x6cbc2eb0UL, 0x6d7e4487UL, 0x6f38fadeUL, 0x6efa90e9UL, 0x6bb5866cUL,
+    0x6a77ec5bUL, 0x68315202UL, 0x69f33835UL, 0x62af7f08UL, 0x636d153fUL,
+    0x612bab66UL, 0x60e9c151UL, 0x65a6d7d4UL, 0x6464bde3UL, 0x662203baUL,
+    0x67e0698dUL, 0x48d7cb20UL, 0x4915a117UL, 0x4b531f4eUL, 0x4a917579UL,
+    0x4fde63fcUL, 0x4e1c09cbUL, 0x4c5ab792UL, 0x4d98dda5UL, 0x46c49a98UL,
+    0x4706f0afUL, 0x45404ef6UL, 0x448224c1UL, 0x41cd3244UL, 0x400f5873UL,
+    0x4249e62aUL, 0x438b8c1dUL, 0x54f16850UL, 0x55330267UL, 0x5775bc3eUL,
+    0x56b7d609UL, 0x53f8c08cUL, 0x523aaabbUL, 0x507c14e2UL, 0x51be7ed5UL,
+    0x5ae239e8UL, 0x5b2053dfUL, 0x5966ed86UL, 0x58a487b1UL, 0x5deb9134UL,
+    0x5c29fb03UL, 0x5e6f455aUL, 0x5fad2f6dUL, 0xe1351b80UL, 0xe0f771b7UL,
+    0xe2b1cfeeUL, 0xe373a5d9UL, 0xe63cb35cUL, 0xe7fed96bUL, 0xe5b86732UL,
+    0xe47a0d05UL, 0xef264a38UL, 0xeee4200fUL, 0xeca29e56UL, 0xed60f461UL,
+    0xe82fe2e4UL, 0xe9ed88d3UL, 0xebab368aUL, 0xea695cbdUL, 0xfd13b8f0UL,
+    0xfcd1d2c7UL, 0xfe976c9eUL, 0xff5506a9UL, 0xfa1a102cUL, 0xfbd87a1bUL,
+    0xf99ec442UL, 0xf85cae75UL, 0xf300e948UL, 0xf2c2837fUL, 0xf0843d26UL,
+    0xf1465711UL, 0xf4094194UL, 0xf5cb2ba3UL, 0xf78d95faUL, 0xf64fffcdUL,
+    0xd9785d60UL, 0xd8ba3757UL, 0xdafc890eUL, 0xdb3ee339UL, 0xde71f5bcUL,
+    0xdfb39f8bUL, 0xddf521d2UL, 0xdc374be5UL, 0xd76b0cd8UL, 0xd6a966efUL,
+    0xd4efd8b6UL, 0xd52db281UL, 0xd062a404UL, 0xd1a0ce33UL, 0xd3e6706aUL,
+    0xd2241a5dUL, 0xc55efe10UL, 0xc49c9427UL, 0xc6da2a7eUL, 0xc7184049UL,
+    0xc25756ccUL, 0xc3953cfbUL, 0xc1d382a2UL, 0xc011e895UL, 0xcb4dafa8UL,
+    0xca8fc59fUL, 0xc8c97bc6UL, 0xc90b11f1UL, 0xcc440774UL, 0xcd866d43UL,
+    0xcfc0d31aUL, 0xce02b92dUL, 0x91af9640UL, 0x906dfc77UL, 0x922b422eUL,
+    0x93e92819UL, 0x96a63e9cUL, 0x976454abUL, 0x9522eaf2UL, 0x94e080c5UL,
+    0x9fbcc7f8UL, 0x9e7eadcfUL, 0x9c381396UL, 0x9dfa79a1UL, 0x98b56f24UL,
+    0x99770513UL, 0x9b31bb4aUL, 0x9af3d17dUL, 0x8d893530UL, 0x8c4b5f07UL,
+    0x8e0de15eUL, 0x8fcf8b69UL, 0x8a809decUL, 0x8b42f7dbUL, 0x89044982UL,
+    0x88c623b5UL, 0x839a6488UL, 0x82580ebfUL, 0x801eb0e6UL, 0x81dcdad1UL,
+    0x8493cc54UL, 0x8551a663UL, 0x8717183aUL, 0x86d5720dUL, 0xa9e2d0a0UL,
+    0xa820ba97UL, 0xaa6604ceUL, 0xaba46ef9UL, 0xaeeb787cUL, 0xaf29124bUL,
+    0xad6fac12UL, 0xacadc625UL, 0xa7f18118UL, 0xa633eb2fUL, 0xa4755576UL,
+    0xa5b73f41UL, 0xa0f829c4UL, 0xa13a43f3UL, 0xa37cfdaaUL, 0xa2be979dUL,
+    0xb5c473d0UL, 0xb40619e7UL, 0xb640a7beUL, 0xb782cd89UL, 0xb2cddb0cUL,
+    0xb30fb13bUL, 0xb1490f62UL, 0xb08b6555UL, 0xbbd72268UL, 0xba15485fUL,
+    0xb853f606UL, 0xb9919c31UL, 0xbcde8ab4UL, 0xbd1ce083UL, 0xbf5a5edaUL,
+    0xbe9834edUL
+  },
+  {
+    0x00000000UL, 0xb8bc6765UL, 0xaa09c88bUL, 0x12b5afeeUL, 0x8f629757UL,
+    0x37def032UL, 0x256b5fdcUL, 0x9dd738b9UL, 0xc5b428efUL, 0x7d084f8aUL,
+    0x6fbde064UL, 0xd7018701UL, 0x4ad6bfb8UL, 0xf26ad8ddUL, 0xe0df7733UL,
+    0x58631056UL, 0x5019579fUL, 0xe8a530faUL, 0xfa109f14UL, 0x42acf871UL,
+    0xdf7bc0c8UL, 0x67c7a7adUL, 0x75720843UL, 0xcdce6f26UL, 0x95ad7f70UL,
+    0x2d111815UL, 0x3fa4b7fbUL, 0x8718d09eUL, 0x1acfe827UL, 0xa2738f42UL,
+    0xb0c620acUL, 0x087a47c9UL, 0xa032af3eUL, 0x188ec85bUL, 0x0a3b67b5UL,
+    0xb28700d0UL, 0x2f503869UL, 0x97ec5f0cUL, 0x8559f0e2UL, 0x3de59787UL,
+    0x658687d1UL, 0xdd3ae0b4UL, 0xcf8f4f5aUL, 0x7733283fUL, 0xeae41086UL,
+    0x525877e3UL, 0x40edd80dUL, 0xf851bf68UL, 0xf02bf8a1UL, 0x48979fc4UL,
+    0x5a22302aUL, 0xe29e574fUL, 0x7f496ff6UL, 0xc7f50893UL, 0xd540a77dUL,
+    0x6dfcc018UL, 0x359fd04eUL, 0x8d23b72bUL, 0x9f9618c5UL, 0x272a7fa0UL,
+    0xbafd4719UL, 0x0241207cUL, 0x10f48f92UL, 0xa848e8f7UL, 0x9b14583dUL,
+    0x23a83f58UL, 0x311d90b6UL, 0x89a1f7d3UL, 0x1476cf6aUL, 0xaccaa80fUL,
+    0xbe7f07e1UL, 0x06c36084UL, 0x5ea070d2UL, 0xe61c17b7UL, 0xf4a9b859UL,
+    0x4c15df3cUL, 0xd1c2e785UL, 0x697e80e0UL, 0x7bcb2f0eUL, 0xc377486bUL,
+    0xcb0d0fa2UL, 0x73b168c7UL, 0x6104c729UL, 0xd9b8a04cUL, 0x446f98f5UL,
+    0xfcd3ff90UL, 0xee66507eUL, 0x56da371bUL, 0x0eb9274dUL, 0xb6054028UL,
+    0xa4b0efc6UL, 0x1c0c88a3UL, 0x81dbb01aUL, 0x3967d77fUL, 0x2bd27891UL,
+    0x936e1ff4UL, 0x3b26f703UL, 0x839a9066UL, 0x912f3f88UL, 0x299358edUL,
+    0xb4446054UL, 0x0cf80731UL, 0x1e4da8dfUL, 0xa6f1cfbaUL, 0xfe92dfecUL,
+    0x462eb889UL, 0x549b1767UL, 0xec277002UL, 0x71f048bbUL, 0xc94c2fdeUL,
+    0xdbf98030UL, 0x6345e755UL, 0x6b3fa09cUL, 0xd383c7f9UL, 0xc1366817UL,
+    0x798a0f72UL, 0xe45d37cbUL, 0x5ce150aeUL, 0x4e54ff40UL, 0xf6e89825UL,
+    0xae8b8873UL, 0x1637ef16UL, 0x048240f8UL, 0xbc3e279dUL, 0x21e91f24UL,
+    0x99557841UL, 0x8be0d7afUL, 0x335cb0caUL, 0xed59b63bUL, 0x55e5d15eUL,
+    0x47507eb0UL, 0xffec19d5UL, 0x623b216cUL, 0xda874609UL, 0xc832e9e7UL,
+    0x708e8e82UL, 0x28ed9ed4UL, 0x9051f9b1UL, 0x82e4565fUL, 0x3a58313aUL,
+    0xa78f0983UL, 0x1f336ee6UL, 0x0d86c108UL, 0xb53aa66dUL, 0xbd40e1a4UL,
+    0x05fc86c1UL, 0x1749292fUL, 0xaff54e4aUL, 0x322276f3UL, 0x8a9e1196UL,
+    0x982bbe78UL, 0x2097d91dUL, 0x78f4c94bUL, 0xc048ae2eUL, 0xd2fd01c0UL,
+    0x6a4166a5UL, 0xf7965e1cUL, 0x4f2a3979UL, 0x5d9f9697UL, 0xe523f1f2UL,
+    0x4d6b1905UL, 0xf5d77e60UL, 0xe762d18eUL, 0x5fdeb6ebUL, 0xc2098e52UL,
+    0x7ab5e937UL, 0x680046d9UL, 0xd0bc21bcUL, 0x88df31eaUL, 0x3063568fUL,
+    0x22d6f961UL, 0x9a6a9e04UL, 0x07bda6bdUL, 0xbf01c1d8UL, 0xadb46e36UL,
+    0x15080953UL, 0x1d724e9aUL, 0xa5ce29ffUL, 0xb77b8611UL, 0x0fc7e174UL,
+    0x9210d9cdUL, 0x2aacbea8UL, 0x38191146UL, 0x80a57623UL, 0xd8c66675UL,
+    0x607a0110UL, 0x72cfaefeUL, 0xca73c99bUL, 0x57a4f122UL, 0xef189647UL,
+    0xfdad39a9UL, 0x45115eccUL, 0x764dee06UL, 0xcef18963UL, 0xdc44268dUL,
+    0x64f841e8UL, 0xf92f7951UL, 0x41931e34UL, 0x5326b1daUL, 0xeb9ad6bfUL,
+    0xb3f9c6e9UL, 0x0b45a18cUL, 0x19f00e62UL, 0xa14c6907UL, 0x3c9b51beUL,
+    0x842736dbUL, 0x96929935UL, 0x2e2efe50UL, 0x2654b999UL, 0x9ee8defcUL,
+    0x8c5d7112UL, 0x34e11677UL, 0xa9362eceUL, 0x118a49abUL, 0x033fe645UL,
+    0xbb838120UL, 0xe3e09176UL, 0x5b5cf613UL, 0x49e959fdUL, 0xf1553e98UL,
+    0x6c820621UL, 0xd43e6144UL, 0xc68bceaaUL, 0x7e37a9cfUL, 0xd67f4138UL,
+    0x6ec3265dUL, 0x7c7689b3UL, 0xc4caeed6UL, 0x591dd66fUL, 0xe1a1b10aUL,
+    0xf3141ee4UL, 0x4ba87981UL, 0x13cb69d7UL, 0xab770eb2UL, 0xb9c2a15cUL,
+    0x017ec639UL, 0x9ca9fe80UL, 0x241599e5UL, 0x36a0360bUL, 0x8e1c516eUL,
+    0x866616a7UL, 0x3eda71c2UL, 0x2c6fde2cUL, 0x94d3b949UL, 0x090481f0UL,
+    0xb1b8e695UL, 0xa30d497bUL, 0x1bb12e1eUL, 0x43d23e48UL, 0xfb6e592dUL,
+    0xe9dbf6c3UL, 0x516791a6UL, 0xccb0a91fUL, 0x740cce7aUL, 0x66b96194UL,
+    0xde0506f1UL
+  },
+  {
+    0x00000000UL, 0x96300777UL, 0x2c610eeeUL, 0xba510999UL, 0x19c46d07UL,
+    0x8ff46a70UL, 0x35a563e9UL, 0xa395649eUL, 0x3288db0eUL, 0xa4b8dc79UL,
+    0x1ee9d5e0UL, 0x88d9d297UL, 0x2b4cb609UL, 0xbd7cb17eUL, 0x072db8e7UL,
+    0x911dbf90UL, 0x6410b71dUL, 0xf220b06aUL, 0x4871b9f3UL, 0xde41be84UL,
+    0x7dd4da1aUL, 0xebe4dd6dUL, 0x51b5d4f4UL, 0xc785d383UL, 0x56986c13UL,
+    0xc0a86b64UL, 0x7af962fdUL, 0xecc9658aUL, 0x4f5c0114UL, 0xd96c0663UL,
+    0x633d0ffaUL, 0xf50d088dUL, 0xc8206e3bUL, 0x5e10694cUL, 0xe44160d5UL,
+    0x727167a2UL, 0xd1e4033cUL, 0x47d4044bUL, 0xfd850dd2UL, 0x6bb50aa5UL,
+    0xfaa8b535UL, 0x6c98b242UL, 0xd6c9bbdbUL, 0x40f9bcacUL, 0xe36cd832UL,
+    0x755cdf45UL, 0xcf0dd6dcUL, 0x593dd1abUL, 0xac30d926UL, 0x3a00de51UL,
+    0x8051d7c8UL, 0x1661d0bfUL, 0xb5f4b421UL, 0x23c4b356UL, 0x9995bacfUL,
+    0x0fa5bdb8UL, 0x9eb80228UL, 0x0888055fUL, 0xb2d90cc6UL, 0x24e90bb1UL,
+    0x877c6f2fUL, 0x114c6858UL, 0xab1d61c1UL, 0x3d2d66b6UL, 0x9041dc76UL,
+    0x0671db01UL, 0xbc20d298UL, 0x2a10d5efUL, 0x8985b171UL, 0x1fb5b606UL,
+    0xa5e4bf9fUL, 0x33d4b8e8UL, 0xa2c90778UL, 0x34f9000fUL, 0x8ea80996UL,
+    0x18980ee1UL, 0xbb0d6a7fUL, 0x2d3d6d08UL, 0x976c6491UL, 0x015c63e6UL,
+    0xf4516b6bUL, 0x62616c1cUL, 0xd8306585UL, 0x4e0062f2UL, 0xed95066cUL,
+    0x7ba5011bUL, 0xc1f40882UL, 0x57c40ff5UL, 0xc6d9b065UL, 0x50e9b712UL,
+    0xeab8be8bUL, 0x7c88b9fcUL, 0xdf1ddd62UL, 0x492dda15UL, 0xf37cd38cUL,
+    0x654cd4fbUL, 0x5861b24dUL, 0xce51b53aUL, 0x7400bca3UL, 0xe230bbd4UL,
+    0x41a5df4aUL, 0xd795d83dUL, 0x6dc4d1a4UL, 0xfbf4d6d3UL, 0x6ae96943UL,
+    0xfcd96e34UL, 0x468867adUL, 0xd0b860daUL, 0x732d0444UL, 0xe51d0333UL,
+    0x5f4c0aaaUL, 0xc97c0dddUL, 0x3c710550UL, 0xaa410227UL, 0x10100bbeUL,
+    0x86200cc9UL, 0x25b56857UL, 0xb3856f20UL, 0x09d466b9UL, 0x9fe461ceUL,
+    0x0ef9de5eUL, 0x98c9d929UL, 0x2298d0b0UL, 0xb4a8d7c7UL, 0x173db359UL,
+    0x810db42eUL, 0x3b5cbdb7UL, 0xad6cbac0UL, 0x2083b8edUL, 0xb6b3bf9aUL,
+    0x0ce2b603UL, 0x9ad2b174UL, 0x3947d5eaUL, 0xaf77d29dUL, 0x1526db04UL,
+    0x8316dc73UL, 0x120b63e3UL, 0x843b6494UL, 0x3e6a6d0dUL, 0xa85a6a7aUL,
+    0x0bcf0ee4UL, 0x9dff0993UL, 0x27ae000aUL, 0xb19e077dUL, 0x44930ff0UL,
+    0xd2a30887UL, 0x68f2011eUL, 0xfec20669UL, 0x5d5762f7UL, 0xcb676580UL,
+    0x71366c19UL, 0xe7066b6eUL, 0x761bd4feUL, 0xe02bd389UL, 0x5a7ada10UL,
+    0xcc4add67UL, 0x6fdfb9f9UL, 0xf9efbe8eUL, 0x43beb717UL, 0xd58eb060UL,
+    0xe8a3d6d6UL, 0x7e93d1a1UL, 0xc4c2d838UL, 0x52f2df4fUL, 0xf167bbd1UL,
+    0x6757bca6UL, 0xdd06b53fUL, 0x4b36b248UL, 0xda2b0dd8UL, 0x4c1b0aafUL,
+    0xf64a0336UL, 0x607a0441UL, 0xc3ef60dfUL, 0x55df67a8UL, 0xef8e6e31UL,
+    0x79be6946UL, 0x8cb361cbUL, 0x1a8366bcUL, 0xa0d26f25UL, 0x36e26852UL,
+    0x95770cccUL, 0x03470bbbUL, 0xb9160222UL, 0x2f260555UL, 0xbe3bbac5UL,
+    0x280bbdb2UL, 0x925ab42bUL, 0x046ab35cUL, 0xa7ffd7c2UL, 0x31cfd0b5UL,
+    0x8b9ed92cUL, 0x1daede5bUL, 0xb0c2649bUL, 0x26f263ecUL, 0x9ca36a75UL,
+    0x0a936d02UL, 0xa906099cUL, 0x3f360eebUL, 0x85670772UL, 0x13570005UL,
+    0x824abf95UL, 0x147ab8e2UL, 0xae2bb17bUL, 0x381bb60cUL, 0x9b8ed292UL,
+    0x0dbed5e5UL, 0xb7efdc7cUL, 0x21dfdb0bUL, 0xd4d2d386UL, 0x42e2d4f1UL,
+    0xf8b3dd68UL, 0x6e83da1fUL, 0xcd16be81UL, 0x5b26b9f6UL, 0xe177b06fUL,
+    0x7747b718UL, 0xe65a0888UL, 0x706a0fffUL, 0xca3b0666UL, 0x5c0b0111UL,
+    0xff9e658fUL, 0x69ae62f8UL, 0xd3ff6b61UL, 0x45cf6c16UL, 0x78e20aa0UL,
+    0xeed20dd7UL, 0x5483044eUL, 0xc2b30339UL, 0x612667a7UL, 0xf71660d0UL,
+    0x4d476949UL, 0xdb776e3eUL, 0x4a6ad1aeUL, 0xdc5ad6d9UL, 0x660bdf40UL,
+    0xf03bd837UL, 0x53aebca9UL, 0xc59ebbdeUL, 0x7fcfb247UL, 0xe9ffb530UL,
+    0x1cf2bdbdUL, 0x8ac2bacaUL, 0x3093b353UL, 0xa6a3b424UL, 0x0536d0baUL,
+    0x9306d7cdUL, 0x2957de54UL, 0xbf67d923UL, 0x2e7a66b3UL, 0xb84a61c4UL,
+    0x021b685dUL, 0x942b6f2aUL, 0x37be0bb4UL, 0xa18e0cc3UL, 0x1bdf055aUL,
+    0x8def022dUL
+  },
+  {
+    0x00000000UL, 0x41311b19UL, 0x82623632UL, 0xc3532d2bUL, 0x04c56c64UL,
+    0x45f4777dUL, 0x86a75a56UL, 0xc796414fUL, 0x088ad9c8UL, 0x49bbc2d1UL,
+    0x8ae8effaUL, 0xcbd9f4e3UL, 0x0c4fb5acUL, 0x4d7eaeb5UL, 0x8e2d839eUL,
+    0xcf1c9887UL, 0x5112c24aUL, 0x1023d953UL, 0xd370f478UL, 0x9241ef61UL,
+    0x55d7ae2eUL, 0x14e6b537UL, 0xd7b5981cUL, 0x96848305UL, 0x59981b82UL,
+    0x18a9009bUL, 0xdbfa2db0UL, 0x9acb36a9UL, 0x5d5d77e6UL, 0x1c6c6cffUL,
+    0xdf3f41d4UL, 0x9e0e5acdUL, 0xa2248495UL, 0xe3159f8cUL, 0x2046b2a7UL,
+    0x6177a9beUL, 0xa6e1e8f1UL, 0xe7d0f3e8UL, 0x2483dec3UL, 0x65b2c5daUL,
+    0xaaae5d5dUL, 0xeb9f4644UL, 0x28cc6b6fUL, 0x69fd7076UL, 0xae6b3139UL,
+    0xef5a2a20UL, 0x2c09070bUL, 0x6d381c12UL, 0xf33646dfUL, 0xb2075dc6UL,
+    0x715470edUL, 0x30656bf4UL, 0xf7f32abbUL, 0xb6c231a2UL, 0x75911c89UL,
+    0x34a00790UL, 0xfbbc9f17UL, 0xba8d840eUL, 0x79dea925UL, 0x38efb23cUL,
+    0xff79f373UL, 0xbe48e86aUL, 0x7d1bc541UL, 0x3c2ade58UL, 0x054f79f0UL,
+    0x447e62e9UL, 0x872d4fc2UL, 0xc61c54dbUL, 0x018a1594UL, 0x40bb0e8dUL,
+    0x83e823a6UL, 0xc2d938bfUL, 0x0dc5a038UL, 0x4cf4bb21UL, 0x8fa7960aUL,
+    0xce968d13UL, 0x0900cc5cUL, 0x4831d745UL, 0x8b62fa6eUL, 0xca53e177UL,
+    0x545dbbbaUL, 0x156ca0a3UL, 0xd63f8d88UL, 0x970e9691UL, 0x5098d7deUL,
+    0x11a9ccc7UL, 0xd2fae1ecUL, 0x93cbfaf5UL, 0x5cd76272UL, 0x1de6796bUL,
+    0xdeb55440UL, 0x9f844f59UL, 0x58120e16UL, 0x1923150fUL, 0xda703824UL,
+    0x9b41233dUL, 0xa76bfd65UL, 0xe65ae67cUL, 0x2509cb57UL, 0x6438d04eUL,
+    0xa3ae9101UL, 0xe29f8a18UL, 0x21cca733UL, 0x60fdbc2aUL, 0xafe124adUL,
+    0xeed03fb4UL, 0x2d83129fUL, 0x6cb20986UL, 0xab2448c9UL, 0xea1553d0UL,
+    0x29467efbUL, 0x687765e2UL, 0xf6793f2fUL, 0xb7482436UL, 0x741b091dUL,
+    0x352a1204UL, 0xf2bc534bUL, 0xb38d4852UL, 0x70de6579UL, 0x31ef7e60UL,
+    0xfef3e6e7UL, 0xbfc2fdfeUL, 0x7c91d0d5UL, 0x3da0cbccUL, 0xfa368a83UL,
+    0xbb07919aUL, 0x7854bcb1UL, 0x3965a7a8UL, 0x4b98833bUL, 0x0aa99822UL,
+    0xc9fab509UL, 0x88cbae10UL, 0x4f5def5fUL, 0x0e6cf446UL, 0xcd3fd96dUL,
+    0x8c0ec274UL, 0x43125af3UL, 0x022341eaUL, 0xc1706cc1UL, 0x804177d8UL,
+    0x47d73697UL, 0x06e62d8eUL, 0xc5b500a5UL, 0x84841bbcUL, 0x1a8a4171UL,
+    0x5bbb5a68UL, 0x98e87743UL, 0xd9d96c5aUL, 0x1e4f2d15UL, 0x5f7e360cUL,
+    0x9c2d1b27UL, 0xdd1c003eUL, 0x120098b9UL, 0x533183a0UL, 0x9062ae8bUL,
+    0xd153b592UL, 0x16c5f4ddUL, 0x57f4efc4UL, 0x94a7c2efUL, 0xd596d9f6UL,
+    0xe9bc07aeUL, 0xa88d1cb7UL, 0x6bde319cUL, 0x2aef2a85UL, 0xed796bcaUL,
+    0xac4870d3UL, 0x6f1b5df8UL, 0x2e2a46e1UL, 0xe136de66UL, 0xa007c57fUL,
+    0x6354e854UL, 0x2265f34dUL, 0xe5f3b202UL, 0xa4c2a91bUL, 0x67918430UL,
+    0x26a09f29UL, 0xb8aec5e4UL, 0xf99fdefdUL, 0x3accf3d6UL, 0x7bfde8cfUL,
+    0xbc6ba980UL, 0xfd5ab299UL, 0x3e099fb2UL, 0x7f3884abUL, 0xb0241c2cUL,
+    0xf1150735UL, 0x32462a1eUL, 0x73773107UL, 0xb4e17048UL, 0xf5d06b51UL,
+    0x3683467aUL, 0x77b25d63UL, 0x4ed7facbUL, 0x0fe6e1d2UL, 0xccb5ccf9UL,
+    0x8d84d7e0UL, 0x4a1296afUL, 0x0b238db6UL, 0xc870a09dUL, 0x8941bb84UL,
+    0x465d2303UL, 0x076c381aUL, 0xc43f1531UL, 0x850e0e28UL, 0x42984f67UL,
+    0x03a9547eUL, 0xc0fa7955UL, 0x81cb624cUL, 0x1fc53881UL, 0x5ef42398UL,
+    0x9da70eb3UL, 0xdc9615aaUL, 0x1b0054e5UL, 0x5a314ffcUL, 0x996262d7UL,
+    0xd85379ceUL, 0x174fe149UL, 0x567efa50UL, 0x952dd77bUL, 0xd41ccc62UL,
+    0x138a8d2dUL, 0x52bb9634UL, 0x91e8bb1fUL, 0xd0d9a006UL, 0xecf37e5eUL,
+    0xadc26547UL, 0x6e91486cUL, 0x2fa05375UL, 0xe836123aUL, 0xa9070923UL,
+    0x6a542408UL, 0x2b653f11UL, 0xe479a796UL, 0xa548bc8fUL, 0x661b91a4UL,
+    0x272a8abdUL, 0xe0bccbf2UL, 0xa18dd0ebUL, 0x62defdc0UL, 0x23efe6d9UL,
+    0xbde1bc14UL, 0xfcd0a70dUL, 0x3f838a26UL, 0x7eb2913fUL, 0xb924d070UL,
+    0xf815cb69UL, 0x3b46e642UL, 0x7a77fd5bUL, 0xb56b65dcUL, 0xf45a7ec5UL,
+    0x370953eeUL, 0x763848f7UL, 0xb1ae09b8UL, 0xf09f12a1UL, 0x33cc3f8aUL,
+    0x72fd2493UL
+  },
+  {
+    0x00000000UL, 0x376ac201UL, 0x6ed48403UL, 0x59be4602UL, 0xdca80907UL,
+    0xebc2cb06UL, 0xb27c8d04UL, 0x85164f05UL, 0xb851130eUL, 0x8f3bd10fUL,
+    0xd685970dUL, 0xe1ef550cUL, 0x64f91a09UL, 0x5393d808UL, 0x0a2d9e0aUL,
+    0x3d475c0bUL, 0x70a3261cUL, 0x47c9e41dUL, 0x1e77a21fUL, 0x291d601eUL,
+    0xac0b2f1bUL, 0x9b61ed1aUL, 0xc2dfab18UL, 0xf5b56919UL, 0xc8f23512UL,
+    0xff98f713UL, 0xa626b111UL, 0x914c7310UL, 0x145a3c15UL, 0x2330fe14UL,
+    0x7a8eb816UL, 0x4de47a17UL, 0xe0464d38UL, 0xd72c8f39UL, 0x8e92c93bUL,
+    0xb9f80b3aUL, 0x3cee443fUL, 0x0b84863eUL, 0x523ac03cUL, 0x6550023dUL,
+    0x58175e36UL, 0x6f7d9c37UL, 0x36c3da35UL, 0x01a91834UL, 0x84bf5731UL,
+    0xb3d59530UL, 0xea6bd332UL, 0xdd011133UL, 0x90e56b24UL, 0xa78fa925UL,
+    0xfe31ef27UL, 0xc95b2d26UL, 0x4c4d6223UL, 0x7b27a022UL, 0x2299e620UL,
+    0x15f32421UL, 0x28b4782aUL, 0x1fdeba2bUL, 0x4660fc29UL, 0x710a3e28UL,
+    0xf41c712dUL, 0xc376b32cUL, 0x9ac8f52eUL, 0xada2372fUL, 0xc08d9a70UL,
+    0xf7e75871UL, 0xae591e73UL, 0x9933dc72UL, 0x1c259377UL, 0x2b4f5176UL,
+    0x72f11774UL, 0x459bd575UL, 0x78dc897eUL, 0x4fb64b7fUL, 0x16080d7dUL,
+    0x2162cf7cUL, 0xa4748079UL, 0x931e4278UL, 0xcaa0047aUL, 0xfdcac67bUL,
+    0xb02ebc6cUL, 0x87447e6dUL, 0xdefa386fUL, 0xe990fa6eUL, 0x6c86b56bUL,
+    0x5bec776aUL, 0x02523168UL, 0x3538f369UL, 0x087faf62UL, 0x3f156d63UL,
+    0x66ab2b61UL, 0x51c1e960UL, 0xd4d7a665UL, 0xe3bd6464UL, 0xba032266UL,
+    0x8d69e067UL, 0x20cbd748UL, 0x17a11549UL, 0x4e1f534bUL, 0x7975914aUL,
+    0xfc63de4fUL, 0xcb091c4eUL, 0x92b75a4cUL, 0xa5dd984dUL, 0x989ac446UL,
+    0xaff00647UL, 0xf64e4045UL, 0xc1248244UL, 0x4432cd41UL, 0x73580f40UL,
+    0x2ae64942UL, 0x1d8c8b43UL, 0x5068f154UL, 0x67023355UL, 0x3ebc7557UL,
+    0x09d6b756UL, 0x8cc0f853UL, 0xbbaa3a52UL, 0xe2147c50UL, 0xd57ebe51UL,
+    0xe839e25aUL, 0xdf53205bUL, 0x86ed6659UL, 0xb187a458UL, 0x3491eb5dUL,
+    0x03fb295cUL, 0x5a456f5eUL, 0x6d2fad5fUL, 0x801b35e1UL, 0xb771f7e0UL,
+    0xeecfb1e2UL, 0xd9a573e3UL, 0x5cb33ce6UL, 0x6bd9fee7UL, 0x3267b8e5UL,
+    0x050d7ae4UL, 0x384a26efUL, 0x0f20e4eeUL, 0x569ea2ecUL, 0x61f460edUL,
+    0xe4e22fe8UL, 0xd388ede9UL, 0x8a36abebUL, 0xbd5c69eaUL, 0xf0b813fdUL,
+    0xc7d2d1fcUL, 0x9e6c97feUL, 0xa90655ffUL, 0x2c101afaUL, 0x1b7ad8fbUL,
+    0x42c49ef9UL, 0x75ae5cf8UL, 0x48e900f3UL, 0x7f83c2f2UL, 0x263d84f0UL,
+    0x115746f1UL, 0x944109f4UL, 0xa32bcbf5UL, 0xfa958df7UL, 0xcdff4ff6UL,
+    0x605d78d9UL, 0x5737bad8UL, 0x0e89fcdaUL, 0x39e33edbUL, 0xbcf571deUL,
+    0x8b9fb3dfUL, 0xd221f5ddUL, 0xe54b37dcUL, 0xd80c6bd7UL, 0xef66a9d6UL,
+    0xb6d8efd4UL, 0x81b22dd5UL, 0x04a462d0UL, 0x33cea0d1UL, 0x6a70e6d3UL,
+    0x5d1a24d2UL, 0x10fe5ec5UL, 0x27949cc4UL, 0x7e2adac6UL, 0x494018c7UL,
+    0xcc5657c2UL, 0xfb3c95c3UL, 0xa282d3c1UL, 0x95e811c0UL, 0xa8af4dcbUL,
+    0x9fc58fcaUL, 0xc67bc9c8UL, 0xf1110bc9UL, 0x740744ccUL, 0x436d86cdUL,
+    0x1ad3c0cfUL, 0x2db902ceUL, 0x4096af91UL, 0x77fc6d90UL, 0x2e422b92UL,
+    0x1928e993UL, 0x9c3ea696UL, 0xab546497UL, 0xf2ea2295UL, 0xc580e094UL,
+    0xf8c7bc9fUL, 0xcfad7e9eUL, 0x9613389cUL, 0xa179fa9dUL, 0x246fb598UL,
+    0x13057799UL, 0x4abb319bUL, 0x7dd1f39aUL, 0x3035898dUL, 0x075f4b8cUL,
+    0x5ee10d8eUL, 0x698bcf8fUL, 0xec9d808aUL, 0xdbf7428bUL, 0x82490489UL,
+    0xb523c688UL, 0x88649a83UL, 0xbf0e5882UL, 0xe6b01e80UL, 0xd1dadc81UL,
+    0x54cc9384UL, 0x63a65185UL, 0x3a181787UL, 0x0d72d586UL, 0xa0d0e2a9UL,
+    0x97ba20a8UL, 0xce0466aaUL, 0xf96ea4abUL, 0x7c78ebaeUL, 0x4b1229afUL,
+    0x12ac6fadUL, 0x25c6adacUL, 0x1881f1a7UL, 0x2feb33a6UL, 0x765575a4UL,
+    0x413fb7a5UL, 0xc429f8a0UL, 0xf3433aa1UL, 0xaafd7ca3UL, 0x9d97bea2UL,
+    0xd073c4b5UL, 0xe71906b4UL, 0xbea740b6UL, 0x89cd82b7UL, 0x0cdbcdb2UL,
+    0x3bb10fb3UL, 0x620f49b1UL, 0x55658bb0UL, 0x6822d7bbUL, 0x5f4815baUL,
+    0x06f653b8UL, 0x319c91b9UL, 0xb48adebcUL, 0x83e01cbdUL, 0xda5e5abfUL,
+    0xed3498beUL
+  },
+  {
+    0x00000000UL, 0x6567bcb8UL, 0x8bc809aaUL, 0xeeafb512UL, 0x5797628fUL,
+    0x32f0de37UL, 0xdc5f6b25UL, 0xb938d79dUL, 0xef28b4c5UL, 0x8a4f087dUL,
+    0x64e0bd6fUL, 0x018701d7UL, 0xb8bfd64aUL, 0xddd86af2UL, 0x3377dfe0UL,
+    0x56106358UL, 0x9f571950UL, 0xfa30a5e8UL, 0x149f10faUL, 0x71f8ac42UL,
+    0xc8c07bdfUL, 0xada7c767UL, 0x43087275UL, 0x266fcecdUL, 0x707fad95UL,
+    0x1518112dUL, 0xfbb7a43fUL, 0x9ed01887UL, 0x27e8cf1aUL, 0x428f73a2UL,
+    0xac20c6b0UL, 0xc9477a08UL, 0x3eaf32a0UL, 0x5bc88e18UL, 0xb5673b0aUL,
+    0xd00087b2UL, 0x6938502fUL, 0x0c5fec97UL, 0xe2f05985UL, 0x8797e53dUL,
+    0xd1878665UL, 0xb4e03addUL, 0x5a4f8fcfUL, 0x3f283377UL, 0x8610e4eaUL,
+    0xe3775852UL, 0x0dd8ed40UL, 0x68bf51f8UL, 0xa1f82bf0UL, 0xc49f9748UL,
+    0x2a30225aUL, 0x4f579ee2UL, 0xf66f497fUL, 0x9308f5c7UL, 0x7da740d5UL,
+    0x18c0fc6dUL, 0x4ed09f35UL, 0x2bb7238dUL, 0xc518969fUL, 0xa07f2a27UL,
+    0x1947fdbaUL, 0x7c204102UL, 0x928ff410UL, 0xf7e848a8UL, 0x3d58149bUL,
+    0x583fa823UL, 0xb6901d31UL, 0xd3f7a189UL, 0x6acf7614UL, 0x0fa8caacUL,
+    0xe1077fbeUL, 0x8460c306UL, 0xd270a05eUL, 0xb7171ce6UL, 0x59b8a9f4UL,
+    0x3cdf154cUL, 0x85e7c2d1UL, 0xe0807e69UL, 0x0e2fcb7bUL, 0x6b4877c3UL,
+    0xa20f0dcbUL, 0xc768b173UL, 0x29c70461UL, 0x4ca0b8d9UL, 0xf5986f44UL,
+    0x90ffd3fcUL, 0x7e5066eeUL, 0x1b37da56UL, 0x4d27b90eUL, 0x284005b6UL,
+    0xc6efb0a4UL, 0xa3880c1cUL, 0x1ab0db81UL, 0x7fd76739UL, 0x9178d22bUL,
+    0xf41f6e93UL, 0x03f7263bUL, 0x66909a83UL, 0x883f2f91UL, 0xed589329UL,
+    0x546044b4UL, 0x3107f80cUL, 0xdfa84d1eUL, 0xbacff1a6UL, 0xecdf92feUL,
+    0x89b82e46UL, 0x67179b54UL, 0x027027ecUL, 0xbb48f071UL, 0xde2f4cc9UL,
+    0x3080f9dbUL, 0x55e74563UL, 0x9ca03f6bUL, 0xf9c783d3UL, 0x176836c1UL,
+    0x720f8a79UL, 0xcb375de4UL, 0xae50e15cUL, 0x40ff544eUL, 0x2598e8f6UL,
+    0x73888baeUL, 0x16ef3716UL, 0xf8408204UL, 0x9d273ebcUL, 0x241fe921UL,
+    0x41785599UL, 0xafd7e08bUL, 0xcab05c33UL, 0x3bb659edUL, 0x5ed1e555UL,
+    0xb07e5047UL, 0xd519ecffUL, 0x6c213b62UL, 0x094687daUL, 0xe7e932c8UL,
+    0x828e8e70UL, 0xd49eed28UL, 0xb1f95190UL, 0x5f56e482UL, 0x3a31583aUL,
+    0x83098fa7UL, 0xe66e331fUL, 0x08c1860dUL, 0x6da63ab5UL, 0xa4e140bdUL,
+    0xc186fc05UL, 0x2f294917UL, 0x4a4ef5afUL, 0xf3762232UL, 0x96119e8aUL,
+    0x78be2b98UL, 0x1dd99720UL, 0x4bc9f478UL, 0x2eae48c0UL, 0xc001fdd2UL,
+    0xa566416aUL, 0x1c5e96f7UL, 0x79392a4fUL, 0x97969f5dUL, 0xf2f123e5UL,
+    0x05196b4dUL, 0x607ed7f5UL, 0x8ed162e7UL, 0xebb6de5fUL, 0x528e09c2UL,
+    0x37e9b57aUL, 0xd9460068UL, 0xbc21bcd0UL, 0xea31df88UL, 0x8f566330UL,
+    0x61f9d622UL, 0x049e6a9aUL, 0xbda6bd07UL, 0xd8c101bfUL, 0x366eb4adUL,
+    0x53090815UL, 0x9a4e721dUL, 0xff29cea5UL, 0x11867bb7UL, 0x74e1c70fUL,
+    0xcdd91092UL, 0xa8beac2aUL, 0x46111938UL, 0x2376a580UL, 0x7566c6d8UL,
+    0x10017a60UL, 0xfeaecf72UL, 0x9bc973caUL, 0x22f1a457UL, 0x479618efUL,
+    0xa939adfdUL, 0xcc5e1145UL, 0x06ee4d76UL, 0x6389f1ceUL, 0x8d2644dcUL,
+    0xe841f864UL, 0x51792ff9UL, 0x341e9341UL, 0xdab12653UL, 0xbfd69aebUL,
+    0xe9c6f9b3UL, 0x8ca1450bUL, 0x620ef019UL, 0x07694ca1UL, 0xbe519b3cUL,
+    0xdb362784UL, 0x35999296UL, 0x50fe2e2eUL, 0x99b95426UL, 0xfcdee89eUL,
+    0x12715d8cUL, 0x7716e134UL, 0xce2e36a9UL, 0xab498a11UL, 0x45e63f03UL,
+    0x208183bbUL, 0x7691e0e3UL, 0x13f65c5bUL, 0xfd59e949UL, 0x983e55f1UL,
+    0x2106826cUL, 0x44613ed4UL, 0xaace8bc6UL, 0xcfa9377eUL, 0x38417fd6UL,
+    0x5d26c36eUL, 0xb389767cUL, 0xd6eecac4UL, 0x6fd61d59UL, 0x0ab1a1e1UL,
+    0xe41e14f3UL, 0x8179a84bUL, 0xd769cb13UL, 0xb20e77abUL, 0x5ca1c2b9UL,
+    0x39c67e01UL, 0x80fea99cUL, 0xe5991524UL, 0x0b36a036UL, 0x6e511c8eUL,
+    0xa7166686UL, 0xc271da3eUL, 0x2cde6f2cUL, 0x49b9d394UL, 0xf0810409UL,
+    0x95e6b8b1UL, 0x7b490da3UL, 0x1e2eb11bUL, 0x483ed243UL, 0x2d596efbUL,
+    0xc3f6dbe9UL, 0xa6916751UL, 0x1fa9b0ccUL, 0x7ace0c74UL, 0x9461b966UL,
+    0xf10605deUL
+#endif
+  }
+};
diff --git a/usr/klibc/zlib/deflate.c b/usr/klibc/zlib/deflate.c
new file mode 100644
index 0000000..7a9b03d
--- /dev/null
+++ b/usr/klibc/zlib/deflate.c
@@ -0,0 +1,1736 @@
+/* deflate.c -- compress data using the deflation algorithm
+ * Copyright (C) 1995-2005 Jean-loup Gailly.
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/*
+ *  ALGORITHM
+ *
+ *      The "deflation" process depends on being able to identify portions
+ *      of the input text which are identical to earlier input (within a
+ *      sliding window trailing behind the input currently being processed).
+ *
+ *      The most straightforward technique turns out to be the fastest for
+ *      most input files: try all possible matches and select the longest.
+ *      The key feature of this algorithm is that insertions into the string
+ *      dictionary are very simple and thus fast, and deletions are avoided
+ *      completely. Insertions are performed at each input character, whereas
+ *      string matches are performed only when the previous match ends. So it
+ *      is preferable to spend more time in matches to allow very fast string
+ *      insertions and avoid deletions. The matching algorithm for small
+ *      strings is inspired from that of Rabin & Karp. A brute force approach
+ *      is used to find longer strings when a small match has been found.
+ *      A similar algorithm is used in comic (by Jan-Mark Wams) and freeze
+ *      (by Leonid Broukhis).
+ *         A previous version of this file used a more sophisticated algorithm
+ *      (by Fiala and Greene) which is guaranteed to run in linear amortized
+ *      time, but has a larger average cost, uses more memory and is patented.
+ *      However the F&G algorithm may be faster for some highly redundant
+ *      files if the parameter max_chain_length (described below) is too large.
+ *
+ *  ACKNOWLEDGEMENTS
+ *
+ *      The idea of lazy evaluation of matches is due to Jan-Mark Wams, and
+ *      I found it in 'freeze' written by Leonid Broukhis.
+ *      Thanks to many people for bug reports and testing.
+ *
+ *  REFERENCES
+ *
+ *      Deutsch, L.P.,"DEFLATE Compressed Data Format Specification".
+ *      Available in http://www.ietf.org/rfc/rfc1951.txt
+ *
+ *      A description of the Rabin and Karp algorithm is given in the book
+ *         "Algorithms" by R. Sedgewick, Addison-Wesley, p252.
+ *
+ *      Fiala,E.R., and Greene,D.H.
+ *         Data Compression with Finite Windows, Comm.ACM, 32,4 (1989) 490-595
+ *
+ */
+
+/* @(#) $Id: deflate.c,v 1.1 2005/02/27 23:15:39 hpa Exp $ */
+
+#include "deflate.h"
+
+const char deflate_copyright[] =
+   " deflate 1.2.3 Copyright 1995-2005 Jean-loup Gailly ";
+/*
+  If you use the zlib library in a product, an acknowledgment is welcome
+  in the documentation of your product. If for some reason you cannot
+  include such an acknowledgment, I would appreciate that you keep this
+  copyright string in the executable of your product.
+ */
+
+/* ===========================================================================
+ *  Function prototypes.
+ */
+typedef enum {
+    need_more,      /* block not completed, need more input or more output */
+    block_done,     /* block flush performed */
+    finish_started, /* finish started, need only more output at next deflate */
+    finish_done     /* finish done, accept no more input or output */
+} block_state;
+
+typedef block_state (*compress_func) OF((deflate_state *s, int flush));
+/* Compression function. Returns the block state after the call. */
+
+local void fill_window    OF((deflate_state *s));
+local block_state deflate_stored OF((deflate_state *s, int flush));
+local block_state deflate_fast   OF((deflate_state *s, int flush));
+#ifndef FASTEST
+local block_state deflate_slow   OF((deflate_state *s, int flush));
+#endif
+local void lm_init        OF((deflate_state *s));
+local void putShortMSB    OF((deflate_state *s, uInt b));
+local void flush_pending  OF((z_streamp strm));
+local int read_buf        OF((z_streamp strm, Bytef *buf, unsigned size));
+#ifndef FASTEST
+#ifdef ASMV
+      void match_init OF((void)); /* asm code initialization */
+      uInt longest_match  OF((deflate_state *s, IPos cur_match));
+#else
+local uInt longest_match  OF((deflate_state *s, IPos cur_match));
+#endif
+#endif
+local uInt longest_match_fast OF((deflate_state *s, IPos cur_match));
+
+#ifdef DEBUG
+local  void check_match OF((deflate_state *s, IPos start, IPos match,
+                            int length));
+#endif
+
+/* ===========================================================================
+ * Local data
+ */
+
+#define NIL 0
+/* Tail of hash chains */
+
+#ifndef TOO_FAR
+#  define TOO_FAR 4096
+#endif
+/* Matches of length 3 are discarded if their distance exceeds TOO_FAR */
+
+#define MIN_LOOKAHEAD (MAX_MATCH+MIN_MATCH+1)
+/* Minimum amount of lookahead, except at the end of the input file.
+ * See deflate.c for comments about the MIN_MATCH+1.
+ */
+
+/* Values for max_lazy_match, good_match and max_chain_length, depending on
+ * the desired pack level (0..9). The values given below have been tuned to
+ * exclude worst case performance for pathological files. Better values may be
+ * found for specific files.
+ */
+typedef struct config_s {
+   ush good_length; /* reduce lazy search above this match length */
+   ush max_lazy;    /* do not perform lazy search above this match length */
+   ush nice_length; /* quit search above this match length */
+   ush max_chain;
+   compress_func func;
+} config;
+
+#ifdef FASTEST
+local const config configuration_table[2] = {
+/*      good lazy nice chain */
+/* 0 */ {0,    0,  0,    0, deflate_stored},  /* store only */
+/* 1 */ {4,    4,  8,    4, deflate_fast}}; /* max speed, no lazy matches */
+#else
+local const config configuration_table[10] = {
+/*      good lazy nice chain */
+/* 0 */ {0,    0,  0,    0, deflate_stored},  /* store only */
+/* 1 */ {4,    4,  8,    4, deflate_fast}, /* max speed, no lazy matches */
+/* 2 */ {4,    5, 16,    8, deflate_fast},
+/* 3 */ {4,    6, 32,   32, deflate_fast},
+
+/* 4 */ {4,    4, 16,   16, deflate_slow},  /* lazy matches */
+/* 5 */ {8,   16, 32,   32, deflate_slow},
+/* 6 */ {8,   16, 128, 128, deflate_slow},
+/* 7 */ {8,   32, 128, 256, deflate_slow},
+/* 8 */ {32, 128, 258, 1024, deflate_slow},
+/* 9 */ {32, 258, 258, 4096, deflate_slow}}; /* max compression */
+#endif
+
+/* Note: the deflate() code requires max_lazy >= MIN_MATCH and max_chain >= 4
+ * For deflate_fast() (levels <= 3) good is ignored and lazy has a different
+ * meaning.
+ */
+
+#define EQUAL 0
+/* result of memcmp for equal strings */
+
+#ifndef NO_DUMMY_DECL
+struct static_tree_desc_s {int dummy;}; /* for buggy compilers */
+#endif
+
+/* ===========================================================================
+ * Update a hash value with the given input byte
+ * IN  assertion: all calls to to UPDATE_HASH are made with consecutive
+ *    input characters, so that a running hash key can be computed from the
+ *    previous key instead of complete recalculation each time.
+ */
+#define UPDATE_HASH(s,h,c) (h = (((h)<<s->hash_shift) ^ (c)) & s->hash_mask)
+
+
+/* ===========================================================================
+ * Insert string str in the dictionary and set match_head to the previous head
+ * of the hash chain (the most recent string with same hash key). Return
+ * the previous length of the hash chain.
+ * If this file is compiled with -DFASTEST, the compression level is forced
+ * to 1, and no hash chains are maintained.
+ * IN  assertion: all calls to to INSERT_STRING are made with consecutive
+ *    input characters and the first MIN_MATCH bytes of str are valid
+ *    (except for the last MIN_MATCH-1 bytes of the input file).
+ */
+#ifdef FASTEST
+#define INSERT_STRING(s, str, match_head) \
+   (UPDATE_HASH(s, s->ins_h, s->window[(str) + (MIN_MATCH-1)]), \
+    match_head = s->head[s->ins_h], \
+    s->head[s->ins_h] = (Pos)(str))
+#else
+#define INSERT_STRING(s, str, match_head) \
+   (UPDATE_HASH(s, s->ins_h, s->window[(str) + (MIN_MATCH-1)]), \
+    match_head = s->prev[(str) & s->w_mask] = s->head[s->ins_h], \
+    s->head[s->ins_h] = (Pos)(str))
+#endif
+
+/* ===========================================================================
+ * Initialize the hash table (avoiding 64K overflow for 16 bit systems).
+ * prev[] will be initialized on the fly.
+ */
+#define CLEAR_HASH(s) \
+    s->head[s->hash_size-1] = NIL; \
+    zmemzero((Bytef *)s->head, (unsigned)(s->hash_size-1)*sizeof(*s->head));
+
+/* ========================================================================= */
+int ZEXPORT deflateInit_(strm, level, version, stream_size)
+    z_streamp strm;
+    int level;
+    const char *version;
+    int stream_size;
+{
+    return deflateInit2_(strm, level, Z_DEFLATED, MAX_WBITS, DEF_MEM_LEVEL,
+                         Z_DEFAULT_STRATEGY, version, stream_size);
+    /* To do: ignore strm->next_in if we use it as window */
+}
+
+/* ========================================================================= */
+int ZEXPORT deflateInit2_(strm, level, method, windowBits, memLevel, strategy,
+                  version, stream_size)
+    z_streamp strm;
+    int  level;
+    int  method;
+    int  windowBits;
+    int  memLevel;
+    int  strategy;
+    const char *version;
+    int stream_size;
+{
+    deflate_state *s;
+    int wrap = 1;
+    static const char my_version[] = ZLIB_VERSION;
+
+    ushf *overlay;
+    /* We overlay pending_buf and d_buf+l_buf. This works since the average
+     * output size for (length,distance) codes is <= 24 bits.
+     */
+
+    if (version == Z_NULL || version[0] != my_version[0] ||
+        stream_size != sizeof(z_stream)) {
+        return Z_VERSION_ERROR;
+    }
+    if (strm == Z_NULL) return Z_STREAM_ERROR;
+
+    strm->msg = Z_NULL;
+    if (strm->zalloc == (alloc_func)0) {
+        strm->zalloc = zcalloc;
+        strm->opaque = (voidpf)0;
+    }
+    if (strm->zfree == (free_func)0) strm->zfree = zcfree;
+
+#ifdef FASTEST
+    if (level != 0) level = 1;
+#else
+    if (level == Z_DEFAULT_COMPRESSION) level = 6;
+#endif
+
+    if (windowBits < 0) { /* suppress zlib wrapper */
+        wrap = 0;
+        windowBits = -windowBits;
+    }
+#ifdef GZIP
+    else if (windowBits > 15) {
+        wrap = 2;       /* write gzip wrapper instead */
+        windowBits -= 16;
+    }
+#endif
+    if (memLevel < 1 || memLevel > MAX_MEM_LEVEL || method != Z_DEFLATED ||
+        windowBits < 8 || windowBits > 15 || level < 0 || level > 9 ||
+        strategy < 0 || strategy > Z_FIXED) {
+        return Z_STREAM_ERROR;
+    }
+    if (windowBits == 8) windowBits = 9;  /* until 256-byte window bug fixed */
+    s = (deflate_state *) ZALLOC(strm, 1, sizeof(deflate_state));
+    if (s == Z_NULL) return Z_MEM_ERROR;
+    strm->state = (struct internal_state FAR *)s;
+    s->strm = strm;
+
+    s->wrap = wrap;
+    s->gzhead = Z_NULL;
+    s->w_bits = windowBits;
+    s->w_size = 1 << s->w_bits;
+    s->w_mask = s->w_size - 1;
+
+    s->hash_bits = memLevel + 7;
+    s->hash_size = 1 << s->hash_bits;
+    s->hash_mask = s->hash_size - 1;
+    s->hash_shift =  ((s->hash_bits+MIN_MATCH-1)/MIN_MATCH);
+
+    s->window = (Bytef *) ZALLOC(strm, s->w_size, 2*sizeof(Byte));
+    s->prev   = (Posf *)  ZALLOC(strm, s->w_size, sizeof(Pos));
+    s->head   = (Posf *)  ZALLOC(strm, s->hash_size, sizeof(Pos));
+
+    s->lit_bufsize = 1 << (memLevel + 6); /* 16K elements by default */
+
+    overlay = (ushf *) ZALLOC(strm, s->lit_bufsize, sizeof(ush)+2);
+    s->pending_buf = (uchf *) overlay;
+    s->pending_buf_size = (ulg)s->lit_bufsize * (sizeof(ush)+2L);
+
+    if (s->window == Z_NULL || s->prev == Z_NULL || s->head == Z_NULL ||
+        s->pending_buf == Z_NULL) {
+        s->status = FINISH_STATE;
+        strm->msg = (char*)ERR_MSG(Z_MEM_ERROR);
+        deflateEnd (strm);
+        return Z_MEM_ERROR;
+    }
+    s->d_buf = overlay + s->lit_bufsize/sizeof(ush);
+    s->l_buf = s->pending_buf + (1+sizeof(ush))*s->lit_bufsize;
+
+    s->level = level;
+    s->strategy = strategy;
+    s->method = (Byte)method;
+
+    return deflateReset(strm);
+}
+
+/* ========================================================================= */
+int ZEXPORT deflateSetDictionary (strm, dictionary, dictLength)
+    z_streamp strm;
+    const Bytef *dictionary;
+    uInt  dictLength;
+{
+    deflate_state *s;
+    uInt length = dictLength;
+    uInt n;
+    IPos hash_head = 0;
+
+    if (strm == Z_NULL || strm->state == Z_NULL || dictionary == Z_NULL ||
+        strm->state->wrap == 2 ||
+        (strm->state->wrap == 1 && strm->state->status != INIT_STATE))
+        return Z_STREAM_ERROR;
+
+    s = strm->state;
+    if (s->wrap)
+        strm->adler = adler32(strm->adler, dictionary, dictLength);
+
+    if (length < MIN_MATCH) return Z_OK;
+    if (length > MAX_DIST(s)) {
+        length = MAX_DIST(s);
+        dictionary += dictLength - length; /* use the tail of the dictionary */
+    }
+    zmemcpy(s->window, dictionary, length);
+    s->strstart = length;
+    s->block_start = (long)length;
+
+    /* Insert all strings in the hash table (except for the last two bytes).
+     * s->lookahead stays null, so s->ins_h will be recomputed at the next
+     * call of fill_window.
+     */
+    s->ins_h = s->window[0];
+    UPDATE_HASH(s, s->ins_h, s->window[1]);
+    for (n = 0; n <= length - MIN_MATCH; n++) {
+        INSERT_STRING(s, n, hash_head);
+    }
+    if (hash_head) hash_head = 0;  /* to make compiler happy */
+    return Z_OK;
+}
+
+/* ========================================================================= */
+int ZEXPORT deflateReset (strm)
+    z_streamp strm;
+{
+    deflate_state *s;
+
+    if (strm == Z_NULL || strm->state == Z_NULL ||
+        strm->zalloc == (alloc_func)0 || strm->zfree == (free_func)0) {
+        return Z_STREAM_ERROR;
+    }
+
+    strm->total_in = strm->total_out = 0;
+    strm->msg = Z_NULL; /* use zfree if we ever allocate msg dynamically */
+    strm->data_type = Z_UNKNOWN;
+
+    s = (deflate_state *)strm->state;
+    s->pending = 0;
+    s->pending_out = s->pending_buf;
+
+    if (s->wrap < 0) {
+        s->wrap = -s->wrap; /* was made negative by deflate(..., Z_FINISH); */
+    }
+    s->status = s->wrap ? INIT_STATE : BUSY_STATE;
+    strm->adler =
+#ifdef GZIP
+        s->wrap == 2 ? crc32(0L, Z_NULL, 0) :
+#endif
+        adler32(0L, Z_NULL, 0);
+    s->last_flush = Z_NO_FLUSH;
+
+    _tr_init(s);
+    lm_init(s);
+
+    return Z_OK;
+}
+
+/* ========================================================================= */
+int ZEXPORT deflateSetHeader (strm, head)
+    z_streamp strm;
+    gz_headerp head;
+{
+    if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR;
+    if (strm->state->wrap != 2) return Z_STREAM_ERROR;
+    strm->state->gzhead = head;
+    return Z_OK;
+}
+
+/* ========================================================================= */
+int ZEXPORT deflatePrime (strm, bits, value)
+    z_streamp strm;
+    int bits;
+    int value;
+{
+    if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR;
+    strm->state->bi_valid = bits;
+    strm->state->bi_buf = (ush)(value & ((1 << bits) - 1));
+    return Z_OK;
+}
+
+/* ========================================================================= */
+int ZEXPORT deflateParams(strm, level, strategy)
+    z_streamp strm;
+    int level;
+    int strategy;
+{
+    deflate_state *s;
+    compress_func func;
+    int err = Z_OK;
+
+    if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR;
+    s = strm->state;
+
+#ifdef FASTEST
+    if (level != 0) level = 1;
+#else
+    if (level == Z_DEFAULT_COMPRESSION) level = 6;
+#endif
+    if (level < 0 || level > 9 || strategy < 0 || strategy > Z_FIXED) {
+        return Z_STREAM_ERROR;
+    }
+    func = configuration_table[s->level].func;
+
+    if (func != configuration_table[level].func && strm->total_in != 0) {
+        /* Flush the last buffer: */
+        err = deflate(strm, Z_PARTIAL_FLUSH);
+    }
+    if (s->level != level) {
+        s->level = level;
+        s->max_lazy_match   = configuration_table[level].max_lazy;
+        s->good_match       = configuration_table[level].good_length;
+        s->nice_match       = configuration_table[level].nice_length;
+        s->max_chain_length = configuration_table[level].max_chain;
+    }
+    s->strategy = strategy;
+    return err;
+}
+
+/* ========================================================================= */
+int ZEXPORT deflateTune(strm, good_length, max_lazy, nice_length, max_chain)
+    z_streamp strm;
+    int good_length;
+    int max_lazy;
+    int nice_length;
+    int max_chain;
+{
+    deflate_state *s;
+
+    if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR;
+    s = strm->state;
+    s->good_match = good_length;
+    s->max_lazy_match = max_lazy;
+    s->nice_match = nice_length;
+    s->max_chain_length = max_chain;
+    return Z_OK;
+}
+
+/* =========================================================================
+ * For the default windowBits of 15 and memLevel of 8, this function returns
+ * a close to exact, as well as small, upper bound on the compressed size.
+ * They are coded as constants here for a reason--if the #define's are
+ * changed, then this function needs to be changed as well.  The return
+ * value for 15 and 8 only works for those exact settings.
+ *
+ * For any setting other than those defaults for windowBits and memLevel,
+ * the value returned is a conservative worst case for the maximum expansion
+ * resulting from using fixed blocks instead of stored blocks, which deflate
+ * can emit on compressed data for some combinations of the parameters.
+ *
+ * This function could be more sophisticated to provide closer upper bounds
+ * for every combination of windowBits and memLevel, as well as wrap.
+ * But even the conservative upper bound of about 14% expansion does not
+ * seem onerous for output buffer allocation.
+ */
+uLong ZEXPORT deflateBound(strm, sourceLen)
+    z_streamp strm;
+    uLong sourceLen;
+{
+    deflate_state *s;
+    uLong destLen;
+
+    /* conservative upper bound */
+    destLen = sourceLen +
+              ((sourceLen + 7) >> 3) + ((sourceLen + 63) >> 6) + 11;
+
+    /* if can't get parameters, return conservative bound */
+    if (strm == Z_NULL || strm->state == Z_NULL)
+        return destLen;
+
+    /* if not default parameters, return conservative bound */
+    s = strm->state;
+    if (s->w_bits != 15 || s->hash_bits != 8 + 7)
+        return destLen;
+
+    /* default settings: return tight bound for that case */
+    return compressBound(sourceLen);
+}
+
+/* =========================================================================
+ * Put a short in the pending buffer. The 16-bit value is put in MSB order.
+ * IN assertion: the stream state is correct and there is enough room in
+ * pending_buf.
+ */
+local void putShortMSB (s, b)
+    deflate_state *s;
+    uInt b;
+{
+    put_byte(s, (Byte)(b >> 8));
+    put_byte(s, (Byte)(b & 0xff));
+}
+
+/* =========================================================================
+ * Flush as much pending output as possible. All deflate() output goes
+ * through this function so some applications may wish to modify it
+ * to avoid allocating a large strm->next_out buffer and copying into it.
+ * (See also read_buf()).
+ */
+local void flush_pending(strm)
+    z_streamp strm;
+{
+    unsigned len = strm->state->pending;
+
+    if (len > strm->avail_out) len = strm->avail_out;
+    if (len == 0) return;
+
+    zmemcpy(strm->next_out, strm->state->pending_out, len);
+    strm->next_out  += len;
+    strm->state->pending_out  += len;
+    strm->total_out += len;
+    strm->avail_out  -= len;
+    strm->state->pending -= len;
+    if (strm->state->pending == 0) {
+        strm->state->pending_out = strm->state->pending_buf;
+    }
+}
+
+/* ========================================================================= */
+int ZEXPORT deflate (strm, flush)
+    z_streamp strm;
+    int flush;
+{
+    int old_flush; /* value of flush param for previous deflate call */
+    deflate_state *s;
+
+    if (strm == Z_NULL || strm->state == Z_NULL ||
+        flush > Z_FINISH || flush < 0) {
+        return Z_STREAM_ERROR;
+    }
+    s = strm->state;
+
+    if (strm->next_out == Z_NULL ||
+        (strm->next_in == Z_NULL && strm->avail_in != 0) ||
+        (s->status == FINISH_STATE && flush != Z_FINISH)) {
+        ERR_RETURN(strm, Z_STREAM_ERROR);
+    }
+    if (strm->avail_out == 0) ERR_RETURN(strm, Z_BUF_ERROR);
+
+    s->strm = strm; /* just in case */
+    old_flush = s->last_flush;
+    s->last_flush = flush;
+
+    /* Write the header */
+    if (s->status == INIT_STATE) {
+#ifdef GZIP
+        if (s->wrap == 2) {
+            strm->adler = crc32(0L, Z_NULL, 0);
+            put_byte(s, 31);
+            put_byte(s, 139);
+            put_byte(s, 8);
+            if (s->gzhead == NULL) {
+                put_byte(s, 0);
+                put_byte(s, 0);
+                put_byte(s, 0);
+                put_byte(s, 0);
+                put_byte(s, 0);
+                put_byte(s, s->level == 9 ? 2 :
+                            (s->strategy >= Z_HUFFMAN_ONLY || s->level < 2 ?
+                             4 : 0));
+                put_byte(s, OS_CODE);
+                s->status = BUSY_STATE;
+            }
+            else {
+                put_byte(s, (s->gzhead->text ? 1 : 0) +
+                            (s->gzhead->hcrc ? 2 : 0) +
+                            (s->gzhead->extra == Z_NULL ? 0 : 4) +
+                            (s->gzhead->name == Z_NULL ? 0 : 8) +
+                            (s->gzhead->comment == Z_NULL ? 0 : 16)
+                        );
+                put_byte(s, (Byte)(s->gzhead->time & 0xff));
+                put_byte(s, (Byte)((s->gzhead->time >> 8) & 0xff));
+                put_byte(s, (Byte)((s->gzhead->time >> 16) & 0xff));
+                put_byte(s, (Byte)((s->gzhead->time >> 24) & 0xff));
+                put_byte(s, s->level == 9 ? 2 :
+                            (s->strategy >= Z_HUFFMAN_ONLY || s->level < 2 ?
+                             4 : 0));
+                put_byte(s, s->gzhead->os & 0xff);
+                if (s->gzhead->extra != NULL) {
+                    put_byte(s, s->gzhead->extra_len & 0xff);
+                    put_byte(s, (s->gzhead->extra_len >> 8) & 0xff);
+                }
+                if (s->gzhead->hcrc)
+                    strm->adler = crc32(strm->adler, s->pending_buf,
+                                        s->pending);
+                s->gzindex = 0;
+                s->status = EXTRA_STATE;
+            }
+        }
+        else
+#endif
+        {
+            uInt header = (Z_DEFLATED + ((s->w_bits-8)<<4)) << 8;
+            uInt level_flags;
+
+            if (s->strategy >= Z_HUFFMAN_ONLY || s->level < 2)
+                level_flags = 0;
+            else if (s->level < 6)
+                level_flags = 1;
+            else if (s->level == 6)
+                level_flags = 2;
+            else
+                level_flags = 3;
+            header |= (level_flags << 6);
+            if (s->strstart != 0) header |= PRESET_DICT;
+            header += 31 - (header % 31);
+
+            s->status = BUSY_STATE;
+            putShortMSB(s, header);
+
+            /* Save the adler32 of the preset dictionary: */
+            if (s->strstart != 0) {
+                putShortMSB(s, (uInt)(strm->adler >> 16));
+                putShortMSB(s, (uInt)(strm->adler & 0xffff));
+            }
+            strm->adler = adler32(0L, Z_NULL, 0);
+        }
+    }
+#ifdef GZIP
+    if (s->status == EXTRA_STATE) {
+        if (s->gzhead->extra != NULL) {
+            uInt beg = s->pending;  /* start of bytes to update crc */
+
+            while (s->gzindex < (s->gzhead->extra_len & 0xffff)) {
+                if (s->pending == s->pending_buf_size) {
+                    if (s->gzhead->hcrc && s->pending > beg)
+                        strm->adler = crc32(strm->adler, s->pending_buf + beg,
+                                            s->pending - beg);
+                    flush_pending(strm);
+                    beg = s->pending;
+                    if (s->pending == s->pending_buf_size)
+                        break;
+                }
+                put_byte(s, s->gzhead->extra[s->gzindex]);
+                s->gzindex++;
+            }
+            if (s->gzhead->hcrc && s->pending > beg)
+                strm->adler = crc32(strm->adler, s->pending_buf + beg,
+                                    s->pending - beg);
+            if (s->gzindex == s->gzhead->extra_len) {
+                s->gzindex = 0;
+                s->status = NAME_STATE;
+            }
+        }
+        else
+            s->status = NAME_STATE;
+    }
+    if (s->status == NAME_STATE) {
+        if (s->gzhead->name != NULL) {
+            uInt beg = s->pending;  /* start of bytes to update crc */
+            int val;
+
+            do {
+                if (s->pending == s->pending_buf_size) {
+                    if (s->gzhead->hcrc && s->pending > beg)
+                        strm->adler = crc32(strm->adler, s->pending_buf + beg,
+                                            s->pending - beg);
+                    flush_pending(strm);
+                    beg = s->pending;
+                    if (s->pending == s->pending_buf_size) {
+                        val = 1;
+                        break;
+                    }
+                }
+                val = s->gzhead->name[s->gzindex++];
+                put_byte(s, val);
+            } while (val != 0);
+            if (s->gzhead->hcrc && s->pending > beg)
+                strm->adler = crc32(strm->adler, s->pending_buf + beg,
+                                    s->pending - beg);
+            if (val == 0) {
+                s->gzindex = 0;
+                s->status = COMMENT_STATE;
+            }
+        }
+        else
+            s->status = COMMENT_STATE;
+    }
+    if (s->status == COMMENT_STATE) {
+        if (s->gzhead->comment != NULL) {
+            uInt beg = s->pending;  /* start of bytes to update crc */
+            int val;
+
+            do {
+                if (s->pending == s->pending_buf_size) {
+                    if (s->gzhead->hcrc && s->pending > beg)
+                        strm->adler = crc32(strm->adler, s->pending_buf + beg,
+                                            s->pending - beg);
+                    flush_pending(strm);
+                    beg = s->pending;
+                    if (s->pending == s->pending_buf_size) {
+                        val = 1;
+                        break;
+                    }
+                }
+                val = s->gzhead->comment[s->gzindex++];
+                put_byte(s, val);
+            } while (val != 0);
+            if (s->gzhead->hcrc && s->pending > beg)
+                strm->adler = crc32(strm->adler, s->pending_buf + beg,
+                                    s->pending - beg);
+            if (val == 0)
+                s->status = HCRC_STATE;
+        }
+        else
+            s->status = HCRC_STATE;
+    }
+    if (s->status == HCRC_STATE) {
+        if (s->gzhead->hcrc) {
+            if (s->pending + 2 > s->pending_buf_size)
+                flush_pending(strm);
+            if (s->pending + 2 <= s->pending_buf_size) {
+                put_byte(s, (Byte)(strm->adler & 0xff));
+                put_byte(s, (Byte)((strm->adler >> 8) & 0xff));
+                strm->adler = crc32(0L, Z_NULL, 0);
+                s->status = BUSY_STATE;
+            }
+        }
+        else
+            s->status = BUSY_STATE;
+    }
+#endif
+
+    /* Flush as much pending output as possible */
+    if (s->pending != 0) {
+        flush_pending(strm);
+        if (strm->avail_out == 0) {
+            /* Since avail_out is 0, deflate will be called again with
+             * more output space, but possibly with both pending and
+             * avail_in equal to zero. There won't be anything to do,
+             * but this is not an error situation so make sure we
+             * return OK instead of BUF_ERROR at next call of deflate:
+             */
+            s->last_flush = -1;
+            return Z_OK;
+        }
+
+    /* Make sure there is something to do and avoid duplicate consecutive
+     * flushes. For repeated and useless calls with Z_FINISH, we keep
+     * returning Z_STREAM_END instead of Z_BUF_ERROR.
+     */
+    } else if (strm->avail_in == 0 && flush <= old_flush &&
+               flush != Z_FINISH) {
+        ERR_RETURN(strm, Z_BUF_ERROR);
+    }
+
+    /* User must not provide more input after the first FINISH: */
+    if (s->status == FINISH_STATE && strm->avail_in != 0) {
+        ERR_RETURN(strm, Z_BUF_ERROR);
+    }
+
+    /* Start a new block or continue the current one.
+     */
+    if (strm->avail_in != 0 || s->lookahead != 0 ||
+        (flush != Z_NO_FLUSH && s->status != FINISH_STATE)) {
+        block_state bstate;
+
+        bstate = (*(configuration_table[s->level].func))(s, flush);
+
+        if (bstate == finish_started || bstate == finish_done) {
+            s->status = FINISH_STATE;
+        }
+        if (bstate == need_more || bstate == finish_started) {
+            if (strm->avail_out == 0) {
+                s->last_flush = -1; /* avoid BUF_ERROR next call, see above */
+            }
+            return Z_OK;
+            /* If flush != Z_NO_FLUSH && avail_out == 0, the next call
+             * of deflate should use the same flush parameter to make sure
+             * that the flush is complete. So we don't have to output an
+             * empty block here, this will be done at next call. This also
+             * ensures that for a very small output buffer, we emit at most
+             * one empty block.
+             */
+        }
+        if (bstate == block_done) {
+            if (flush == Z_PARTIAL_FLUSH) {
+                _tr_align(s);
+            } else { /* FULL_FLUSH or SYNC_FLUSH */
+                _tr_stored_block(s, (char*)0, 0L, 0);
+                /* For a full flush, this empty block will be recognized
+                 * as a special marker by inflate_sync().
+                 */
+                if (flush == Z_FULL_FLUSH) {
+                    CLEAR_HASH(s);             /* forget history */
+                }
+            }
+            flush_pending(strm);
+            if (strm->avail_out == 0) {
+              s->last_flush = -1; /* avoid BUF_ERROR at next call, see above */
+              return Z_OK;
+            }
+        }
+    }
+    Assert(strm->avail_out > 0, "bug2");
+
+    if (flush != Z_FINISH) return Z_OK;
+    if (s->wrap <= 0) return Z_STREAM_END;
+
+    /* Write the trailer */
+#ifdef GZIP
+    if (s->wrap == 2) {
+        put_byte(s, (Byte)(strm->adler & 0xff));
+        put_byte(s, (Byte)((strm->adler >> 8) & 0xff));
+        put_byte(s, (Byte)((strm->adler >> 16) & 0xff));
+        put_byte(s, (Byte)((strm->adler >> 24) & 0xff));
+        put_byte(s, (Byte)(strm->total_in & 0xff));
+        put_byte(s, (Byte)((strm->total_in >> 8) & 0xff));
+        put_byte(s, (Byte)((strm->total_in >> 16) & 0xff));
+        put_byte(s, (Byte)((strm->total_in >> 24) & 0xff));
+    }
+    else
+#endif
+    {
+        putShortMSB(s, (uInt)(strm->adler >> 16));
+        putShortMSB(s, (uInt)(strm->adler & 0xffff));
+    }
+    flush_pending(strm);
+    /* If avail_out is zero, the application will call deflate again
+     * to flush the rest.
+     */
+    if (s->wrap > 0) s->wrap = -s->wrap; /* write the trailer only once! */
+    return s->pending != 0 ? Z_OK : Z_STREAM_END;
+}
+
+/* ========================================================================= */
+int ZEXPORT deflateEnd (strm)
+    z_streamp strm;
+{
+    int status;
+
+    if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR;
+
+    status = strm->state->status;
+    if (status != INIT_STATE &&
+        status != EXTRA_STATE &&
+        status != NAME_STATE &&
+        status != COMMENT_STATE &&
+        status != HCRC_STATE &&
+        status != BUSY_STATE &&
+        status != FINISH_STATE) {
+      return Z_STREAM_ERROR;
+    }
+
+    /* Deallocate in reverse order of allocations: */
+    TRY_FREE(strm, strm->state->pending_buf);
+    TRY_FREE(strm, strm->state->head);
+    TRY_FREE(strm, strm->state->prev);
+    TRY_FREE(strm, strm->state->window);
+
+    ZFREE(strm, strm->state);
+    strm->state = Z_NULL;
+
+    return status == BUSY_STATE ? Z_DATA_ERROR : Z_OK;
+}
+
+/* =========================================================================
+ * Copy the source state to the destination state.
+ * To simplify the source, this is not supported for 16-bit MSDOS (which
+ * doesn't have enough memory anyway to duplicate compression states).
+ */
+int ZEXPORT deflateCopy (dest, source)
+    z_streamp dest;
+    z_streamp source;
+{
+#ifdef MAXSEG_64K
+    return Z_STREAM_ERROR;
+#else
+    deflate_state *ds;
+    deflate_state *ss;
+    ushf *overlay;
+
+
+    if (source == Z_NULL || dest == Z_NULL || source->state == Z_NULL) {
+        return Z_STREAM_ERROR;
+    }
+
+    ss = source->state;
+
+    zmemcpy(dest, source, sizeof(z_stream));
+
+    ds = (deflate_state *) ZALLOC(dest, 1, sizeof(deflate_state));
+    if (ds == Z_NULL) return Z_MEM_ERROR;
+    dest->state = (struct internal_state FAR *) ds;
+    zmemcpy(ds, ss, sizeof(deflate_state));
+    ds->strm = dest;
+
+    ds->window = (Bytef *) ZALLOC(dest, ds->w_size, 2*sizeof(Byte));
+    ds->prev   = (Posf *)  ZALLOC(dest, ds->w_size, sizeof(Pos));
+    ds->head   = (Posf *)  ZALLOC(dest, ds->hash_size, sizeof(Pos));
+    overlay = (ushf *) ZALLOC(dest, ds->lit_bufsize, sizeof(ush)+2);
+    ds->pending_buf = (uchf *) overlay;
+
+    if (ds->window == Z_NULL || ds->prev == Z_NULL || ds->head == Z_NULL ||
+        ds->pending_buf == Z_NULL) {
+        deflateEnd (dest);
+        return Z_MEM_ERROR;
+    }
+    /* following zmemcpy do not work for 16-bit MSDOS */
+    zmemcpy(ds->window, ss->window, ds->w_size * 2 * sizeof(Byte));
+    zmemcpy(ds->prev, ss->prev, ds->w_size * sizeof(Pos));
+    zmemcpy(ds->head, ss->head, ds->hash_size * sizeof(Pos));
+    zmemcpy(ds->pending_buf, ss->pending_buf, (uInt)ds->pending_buf_size);
+
+    ds->pending_out = ds->pending_buf + (ss->pending_out - ss->pending_buf);
+    ds->d_buf = overlay + ds->lit_bufsize/sizeof(ush);
+    ds->l_buf = ds->pending_buf + (1+sizeof(ush))*ds->lit_bufsize;
+
+    ds->l_desc.dyn_tree = ds->dyn_ltree;
+    ds->d_desc.dyn_tree = ds->dyn_dtree;
+    ds->bl_desc.dyn_tree = ds->bl_tree;
+
+    return Z_OK;
+#endif /* MAXSEG_64K */
+}
+
+/* ===========================================================================
+ * Read a new buffer from the current input stream, update the adler32
+ * and total number of bytes read.  All deflate() input goes through
+ * this function so some applications may wish to modify it to avoid
+ * allocating a large strm->next_in buffer and copying from it.
+ * (See also flush_pending()).
+ */
+local int read_buf(strm, buf, size)
+    z_streamp strm;
+    Bytef *buf;
+    unsigned size;
+{
+    unsigned len = strm->avail_in;
+
+    if (len > size) len = size;
+    if (len == 0) return 0;
+
+    strm->avail_in  -= len;
+
+    if (strm->state->wrap == 1) {
+        strm->adler = adler32(strm->adler, strm->next_in, len);
+    }
+#ifdef GZIP
+    else if (strm->state->wrap == 2) {
+        strm->adler = crc32(strm->adler, strm->next_in, len);
+    }
+#endif
+    zmemcpy(buf, strm->next_in, len);
+    strm->next_in  += len;
+    strm->total_in += len;
+
+    return (int)len;
+}
+
+/* ===========================================================================
+ * Initialize the "longest match" routines for a new zlib stream
+ */
+local void lm_init (s)
+    deflate_state *s;
+{
+    s->window_size = (ulg)2L*s->w_size;
+
+    CLEAR_HASH(s);
+
+    /* Set the default configuration parameters:
+     */
+    s->max_lazy_match   = configuration_table[s->level].max_lazy;
+    s->good_match       = configuration_table[s->level].good_length;
+    s->nice_match       = configuration_table[s->level].nice_length;
+    s->max_chain_length = configuration_table[s->level].max_chain;
+
+    s->strstart = 0;
+    s->block_start = 0L;
+    s->lookahead = 0;
+    s->match_length = s->prev_length = MIN_MATCH-1;
+    s->match_available = 0;
+    s->ins_h = 0;
+#ifndef FASTEST
+#ifdef ASMV
+    match_init(); /* initialize the asm code */
+#endif
+#endif
+}
+
+#ifndef FASTEST
+/* ===========================================================================
+ * Set match_start to the longest match starting at the given string and
+ * return its length. Matches shorter or equal to prev_length are discarded,
+ * in which case the result is equal to prev_length and match_start is
+ * garbage.
+ * IN assertions: cur_match is the head of the hash chain for the current
+ *   string (strstart) and its distance is <= MAX_DIST, and prev_length >= 1
+ * OUT assertion: the match length is not greater than s->lookahead.
+ */
+#ifndef ASMV
+/* For 80x86 and 680x0, an optimized version will be provided in match.asm or
+ * match.S. The code will be functionally equivalent.
+ */
+local uInt longest_match(s, cur_match)
+    deflate_state *s;
+    IPos cur_match;                             /* current match */
+{
+    unsigned chain_length = s->max_chain_length;/* max hash chain length */
+    register Bytef *scan = s->window + s->strstart; /* current string */
+    register Bytef *match;                       /* matched string */
+    register int len;                           /* length of current match */
+    int best_len = s->prev_length;              /* best match length so far */
+    int nice_match = s->nice_match;             /* stop if match long enough */
+    IPos limit = s->strstart > (IPos)MAX_DIST(s) ?
+        s->strstart - (IPos)MAX_DIST(s) : NIL;
+    /* Stop when cur_match becomes <= limit. To simplify the code,
+     * we prevent matches with the string of window index 0.
+     */
+    Posf *prev = s->prev;
+    uInt wmask = s->w_mask;
+
+#ifdef UNALIGNED_OK
+    /* Compare two bytes at a time. Note: this is not always beneficial.
+     * Try with and without -DUNALIGNED_OK to check.
+     */
+    register Bytef *strend = s->window + s->strstart + MAX_MATCH - 1;
+    register ush scan_start = *(ushf*)scan;
+    register ush scan_end   = *(ushf*)(scan+best_len-1);
+#else
+    register Bytef *strend = s->window + s->strstart + MAX_MATCH;
+    register Byte scan_end1  = scan[best_len-1];
+    register Byte scan_end   = scan[best_len];
+#endif
+
+    /* The code is optimized for HASH_BITS >= 8 and MAX_MATCH-2 multiple of 16.
+     * It is easy to get rid of this optimization if necessary.
+     */
+    Assert(s->hash_bits >= 8 && MAX_MATCH == 258, "Code too clever");
+
+    /* Do not waste too much time if we already have a good match: */
+    if (s->prev_length >= s->good_match) {
+        chain_length >>= 2;
+    }
+    /* Do not look for matches beyond the end of the input. This is necessary
+     * to make deflate deterministic.
+     */
+    if ((uInt)nice_match > s->lookahead) nice_match = s->lookahead;
+
+    Assert((ulg)s->strstart <= s->window_size-MIN_LOOKAHEAD, "need lookahead");
+
+    do {
+        Assert(cur_match < s->strstart, "no future");
+        match = s->window + cur_match;
+
+        /* Skip to next match if the match length cannot increase
+         * or if the match length is less than 2.  Note that the checks below
+         * for insufficient lookahead only occur occasionally for performance
+         * reasons.  Therefore uninitialized memory will be accessed, and
+         * conditional jumps will be made that depend on those values.
+         * However the length of the match is limited to the lookahead, so
+         * the output of deflate is not affected by the uninitialized values.
+         */
+#if (defined(UNALIGNED_OK) && MAX_MATCH == 258)
+        /* This code assumes sizeof(unsigned short) == 2. Do not use
+         * UNALIGNED_OK if your compiler uses a different size.
+         */
+        if (*(ushf*)(match+best_len-1) != scan_end ||
+            *(ushf*)match != scan_start) continue;
+
+        /* It is not necessary to compare scan[2] and match[2] since they are
+         * always equal when the other bytes match, given that the hash keys
+         * are equal and that HASH_BITS >= 8. Compare 2 bytes at a time at
+         * strstart+3, +5, ... up to strstart+257. We check for insufficient
+         * lookahead only every 4th comparison; the 128th check will be made
+         * at strstart+257. If MAX_MATCH-2 is not a multiple of 8, it is
+         * necessary to put more guard bytes at the end of the window, or
+         * to check more often for insufficient lookahead.
+         */
+        Assert(scan[2] == match[2], "scan[2]?");
+        scan++, match++;
+        do {
+        } while (*(ushf*)(scan+=2) == *(ushf*)(match+=2) &&
+                 *(ushf*)(scan+=2) == *(ushf*)(match+=2) &&
+                 *(ushf*)(scan+=2) == *(ushf*)(match+=2) &&
+                 *(ushf*)(scan+=2) == *(ushf*)(match+=2) &&
+                 scan < strend);
+        /* The funny "do {}" generates better code on most compilers */
+
+        /* Here, scan <= window+strstart+257 */
+        Assert(scan <= s->window+(unsigned)(s->window_size-1), "wild scan");
+        if (*scan == *match) scan++;
+
+        len = (MAX_MATCH - 1) - (int)(strend-scan);
+        scan = strend - (MAX_MATCH-1);
+
+#else /* UNALIGNED_OK */
+
+        if (match[best_len]   != scan_end  ||
+            match[best_len-1] != scan_end1 ||
+            *match            != *scan     ||
+            *++match          != scan[1])      continue;
+
+        /* The check at best_len-1 can be removed because it will be made
+         * again later. (This heuristic is not always a win.)
+         * It is not necessary to compare scan[2] and match[2] since they
+         * are always equal when the other bytes match, given that
+         * the hash keys are equal and that HASH_BITS >= 8.
+         */
+        scan += 2, match++;
+        Assert(*scan == *match, "match[2]?");
+
+        /* We check for insufficient lookahead only every 8th comparison;
+         * the 256th check will be made at strstart+258.
+         */
+        do {
+        } while (*++scan == *++match && *++scan == *++match &&
+                 *++scan == *++match && *++scan == *++match &&
+                 *++scan == *++match && *++scan == *++match &&
+                 *++scan == *++match && *++scan == *++match &&
+                 scan < strend);
+
+        Assert(scan <= s->window+(unsigned)(s->window_size-1), "wild scan");
+
+        len = MAX_MATCH - (int)(strend - scan);
+        scan = strend - MAX_MATCH;
+
+#endif /* UNALIGNED_OK */
+
+        if (len > best_len) {
+            s->match_start = cur_match;
+            best_len = len;
+            if (len >= nice_match) break;
+#ifdef UNALIGNED_OK
+            scan_end = *(ushf*)(scan+best_len-1);
+#else
+            scan_end1  = scan[best_len-1];
+            scan_end   = scan[best_len];
+#endif
+        }
+    } while ((cur_match = prev[cur_match & wmask]) > limit
+             && --chain_length != 0);
+
+    if ((uInt)best_len <= s->lookahead) return (uInt)best_len;
+    return s->lookahead;
+}
+#endif /* ASMV */
+#endif /* FASTEST */
+
+/* ---------------------------------------------------------------------------
+ * Optimized version for level == 1 or strategy == Z_RLE only
+ */
+local uInt longest_match_fast(s, cur_match)
+    deflate_state *s;
+    IPos cur_match;                             /* current match */
+{
+    register Bytef *scan = s->window + s->strstart; /* current string */
+    register Bytef *match;                       /* matched string */
+    register int len;                           /* length of current match */
+    register Bytef *strend = s->window + s->strstart + MAX_MATCH;
+
+    /* The code is optimized for HASH_BITS >= 8 and MAX_MATCH-2 multiple of 16.
+     * It is easy to get rid of this optimization if necessary.
+     */
+    Assert(s->hash_bits >= 8 && MAX_MATCH == 258, "Code too clever");
+
+    Assert((ulg)s->strstart <= s->window_size-MIN_LOOKAHEAD, "need lookahead");
+
+    Assert(cur_match < s->strstart, "no future");
+
+    match = s->window + cur_match;
+
+    /* Return failure if the match length is less than 2:
+     */
+    if (match[0] != scan[0] || match[1] != scan[1]) return MIN_MATCH-1;
+
+    /* The check at best_len-1 can be removed because it will be made
+     * again later. (This heuristic is not always a win.)
+     * It is not necessary to compare scan[2] and match[2] since they
+     * are always equal when the other bytes match, given that
+     * the hash keys are equal and that HASH_BITS >= 8.
+     */
+    scan += 2, match += 2;
+    Assert(*scan == *match, "match[2]?");
+
+    /* We check for insufficient lookahead only every 8th comparison;
+     * the 256th check will be made at strstart+258.
+     */
+    do {
+    } while (*++scan == *++match && *++scan == *++match &&
+             *++scan == *++match && *++scan == *++match &&
+             *++scan == *++match && *++scan == *++match &&
+             *++scan == *++match && *++scan == *++match &&
+             scan < strend);
+
+    Assert(scan <= s->window+(unsigned)(s->window_size-1), "wild scan");
+
+    len = MAX_MATCH - (int)(strend - scan);
+
+    if (len < MIN_MATCH) return MIN_MATCH - 1;
+
+    s->match_start = cur_match;
+    return (uInt)len <= s->lookahead ? (uInt)len : s->lookahead;
+}
+
+#ifdef DEBUG
+/* ===========================================================================
+ * Check that the match at match_start is indeed a match.
+ */
+local void check_match(s, start, match, length)
+    deflate_state *s;
+    IPos start, match;
+    int length;
+{
+    /* check that the match is indeed a match */
+    if (zmemcmp(s->window + match,
+                s->window + start, length) != EQUAL) {
+        fprintf(stderr, " start %u, match %u, length %d\n",
+                start, match, length);
+        do {
+            fprintf(stderr, "%c%c", s->window[match++], s->window[start++]);
+        } while (--length != 0);
+        z_error("invalid match");
+    }
+    if (z_verbose > 1) {
+        fprintf(stderr,"\\[%d,%d]", start-match, length);
+        do { putc(s->window[start++], stderr); } while (--length != 0);
+    }
+}
+#else
+#  define check_match(s, start, match, length)
+#endif /* DEBUG */
+
+/* ===========================================================================
+ * Fill the window when the lookahead becomes insufficient.
+ * Updates strstart and lookahead.
+ *
+ * IN assertion: lookahead < MIN_LOOKAHEAD
+ * OUT assertions: strstart <= window_size-MIN_LOOKAHEAD
+ *    At least one byte has been read, or avail_in == 0; reads are
+ *    performed for at least two bytes (required for the zip translate_eol
+ *    option -- not supported here).
+ */
+local void fill_window(s)
+    deflate_state *s;
+{
+    register unsigned n, m;
+    register Posf *p;
+    unsigned more;    /* Amount of free space at the end of the window. */
+    uInt wsize = s->w_size;
+
+    do {
+        more = (unsigned)(s->window_size -(ulg)s->lookahead -(ulg)s->strstart);
+
+        /* Deal with !@#$% 64K limit: */
+        if (sizeof(int) <= 2) {
+            if (more == 0 && s->strstart == 0 && s->lookahead == 0) {
+                more = wsize;
+
+            } else if (more == (unsigned)(-1)) {
+                /* Very unlikely, but possible on 16 bit machine if
+                 * strstart == 0 && lookahead == 1 (input done a byte at time)
+                 */
+                more--;
+            }
+        }
+
+        /* If the window is almost full and there is insufficient lookahead,
+         * move the upper half to the lower one to make room in the upper half.
+         */
+        if (s->strstart >= wsize+MAX_DIST(s)) {
+
+            zmemcpy(s->window, s->window+wsize, (unsigned)wsize);
+            s->match_start -= wsize;
+            s->strstart    -= wsize; /* we now have strstart >= MAX_DIST */
+            s->block_start -= (long) wsize;
+
+            /* Slide the hash table (could be avoided with 32 bit values
+               at the expense of memory usage). We slide even when level == 0
+               to keep the hash table consistent if we switch back to level > 0
+               later. (Using level 0 permanently is not an optimal usage of
+               zlib, so we don't care about this pathological case.)
+             */
+            /* %%% avoid this when Z_RLE */
+            n = s->hash_size;
+            p = &s->head[n];
+            do {
+                m = *--p;
+                *p = (Pos)(m >= wsize ? m-wsize : NIL);
+            } while (--n);
+
+            n = wsize;
+#ifndef FASTEST
+            p = &s->prev[n];
+            do {
+                m = *--p;
+                *p = (Pos)(m >= wsize ? m-wsize : NIL);
+                /* If n is not on any hash chain, prev[n] is garbage but
+                 * its value will never be used.
+                 */
+            } while (--n);
+#endif
+            more += wsize;
+        }
+        if (s->strm->avail_in == 0) return;
+
+        /* If there was no sliding:
+         *    strstart <= WSIZE+MAX_DIST-1 && lookahead <= MIN_LOOKAHEAD - 1 &&
+         *    more == window_size - lookahead - strstart
+         * => more >= window_size - (MIN_LOOKAHEAD-1 + WSIZE + MAX_DIST-1)
+         * => more >= window_size - 2*WSIZE + 2
+         * In the BIG_MEM or MMAP case (not yet supported),
+         *   window_size == input_size + MIN_LOOKAHEAD  &&
+         *   strstart + s->lookahead <= input_size => more >= MIN_LOOKAHEAD.
+         * Otherwise, window_size == 2*WSIZE so more >= 2.
+         * If there was sliding, more >= WSIZE. So in all cases, more >= 2.
+         */
+        Assert(more >= 2, "more < 2");
+
+        n = read_buf(s->strm, s->window + s->strstart + s->lookahead, more);
+        s->lookahead += n;
+
+        /* Initialize the hash value now that we have some input: */
+        if (s->lookahead >= MIN_MATCH) {
+            s->ins_h = s->window[s->strstart];
+            UPDATE_HASH(s, s->ins_h, s->window[s->strstart+1]);
+#if MIN_MATCH != 3
+            Call UPDATE_HASH() MIN_MATCH-3 more times
+#endif
+        }
+        /* If the whole input has less than MIN_MATCH bytes, ins_h is garbage,
+         * but this is not important since only literal bytes will be emitted.
+         */
+
+    } while (s->lookahead < MIN_LOOKAHEAD && s->strm->avail_in != 0);
+}
+
+/* ===========================================================================
+ * Flush the current block, with given end-of-file flag.
+ * IN assertion: strstart is set to the end of the current match.
+ */
+#define FLUSH_BLOCK_ONLY(s, eof) { \
+   _tr_flush_block(s, (s->block_start >= 0L ? \
+                   (charf *)&s->window[(unsigned)s->block_start] : \
+                   (charf *)Z_NULL), \
+                (ulg)((long)s->strstart - s->block_start), \
+                (eof)); \
+   s->block_start = s->strstart; \
+   flush_pending(s->strm); \
+   Tracev((stderr,"[FLUSH]")); \
+}
+
+/* Same but force premature exit if necessary. */
+#define FLUSH_BLOCK(s, eof) { \
+   FLUSH_BLOCK_ONLY(s, eof); \
+   if (s->strm->avail_out == 0) return (eof) ? finish_started : need_more; \
+}
+
+/* ===========================================================================
+ * Copy without compression as much as possible from the input stream, return
+ * the current block state.
+ * This function does not insert new strings in the dictionary since
+ * uncompressible data is probably not useful. This function is used
+ * only for the level=0 compression option.
+ * NOTE: this function should be optimized to avoid extra copying from
+ * window to pending_buf.
+ */
+local block_state deflate_stored(s, flush)
+    deflate_state *s;
+    int flush;
+{
+    /* Stored blocks are limited to 0xffff bytes, pending_buf is limited
+     * to pending_buf_size, and each stored block has a 5 byte header:
+     */
+    ulg max_block_size = 0xffff;
+    ulg max_start;
+
+    if (max_block_size > s->pending_buf_size - 5) {
+        max_block_size = s->pending_buf_size - 5;
+    }
+
+    /* Copy as much as possible from input to output: */
+    for (;;) {
+        /* Fill the window as much as possible: */
+        if (s->lookahead <= 1) {
+
+            Assert(s->strstart < s->w_size+MAX_DIST(s) ||
+                   s->block_start >= (long)s->w_size, "slide too late");
+
+            fill_window(s);
+            if (s->lookahead == 0 && flush == Z_NO_FLUSH) return need_more;
+
+            if (s->lookahead == 0) break; /* flush the current block */
+        }
+        Assert(s->block_start >= 0L, "block gone");
+
+        s->strstart += s->lookahead;
+        s->lookahead = 0;
+
+        /* Emit a stored block if pending_buf will be full: */
+        max_start = s->block_start + max_block_size;
+        if (s->strstart == 0 || (ulg)s->strstart >= max_start) {
+            /* strstart == 0 is possible when wraparound on 16-bit machine */
+            s->lookahead = (uInt)(s->strstart - max_start);
+            s->strstart = (uInt)max_start;
+            FLUSH_BLOCK(s, 0);
+        }
+        /* Flush if we may have to slide, otherwise block_start may become
+         * negative and the data will be gone:
+         */
+        if (s->strstart - (uInt)s->block_start >= MAX_DIST(s)) {
+            FLUSH_BLOCK(s, 0);
+        }
+    }
+    FLUSH_BLOCK(s, flush == Z_FINISH);
+    return flush == Z_FINISH ? finish_done : block_done;
+}
+
+/* ===========================================================================
+ * Compress as much as possible from the input stream, return the current
+ * block state.
+ * This function does not perform lazy evaluation of matches and inserts
+ * new strings in the dictionary only for unmatched strings or for short
+ * matches. It is used only for the fast compression options.
+ */
+local block_state deflate_fast(s, flush)
+    deflate_state *s;
+    int flush;
+{
+    IPos hash_head = NIL; /* head of the hash chain */
+    int bflush;           /* set if current block must be flushed */
+
+    for (;;) {
+        /* Make sure that we always have enough lookahead, except
+         * at the end of the input file. We need MAX_MATCH bytes
+         * for the next match, plus MIN_MATCH bytes to insert the
+         * string following the next match.
+         */
+        if (s->lookahead < MIN_LOOKAHEAD) {
+            fill_window(s);
+            if (s->lookahead < MIN_LOOKAHEAD && flush == Z_NO_FLUSH) {
+                return need_more;
+            }
+            if (s->lookahead == 0) break; /* flush the current block */
+        }
+
+        /* Insert the string window[strstart .. strstart+2] in the
+         * dictionary, and set hash_head to the head of the hash chain:
+         */
+        if (s->lookahead >= MIN_MATCH) {
+            INSERT_STRING(s, s->strstart, hash_head);
+        }
+
+        /* Find the longest match, discarding those <= prev_length.
+         * At this point we have always match_length < MIN_MATCH
+         */
+        if (hash_head != NIL && s->strstart - hash_head <= MAX_DIST(s)) {
+            /* To simplify the code, we prevent matches with the string
+             * of window index 0 (in particular we have to avoid a match
+             * of the string with itself at the start of the input file).
+             */
+#ifdef FASTEST
+            if ((s->strategy != Z_HUFFMAN_ONLY && s->strategy != Z_RLE) ||
+                (s->strategy == Z_RLE && s->strstart - hash_head == 1)) {
+                s->match_length = longest_match_fast (s, hash_head);
+            }
+#else
+            if (s->strategy != Z_HUFFMAN_ONLY && s->strategy != Z_RLE) {
+                s->match_length = longest_match (s, hash_head);
+            } else if (s->strategy == Z_RLE && s->strstart - hash_head == 1) {
+                s->match_length = longest_match_fast (s, hash_head);
+            }
+#endif
+            /* longest_match() or longest_match_fast() sets match_start */
+        }
+        if (s->match_length >= MIN_MATCH) {
+            check_match(s, s->strstart, s->match_start, s->match_length);
+
+            _tr_tally_dist(s, s->strstart - s->match_start,
+                           s->match_length - MIN_MATCH, bflush);
+
+            s->lookahead -= s->match_length;
+
+            /* Insert new strings in the hash table only if the match length
+             * is not too large. This saves time but degrades compression.
+             */
+#ifndef FASTEST
+            if (s->match_length <= s->max_insert_length &&
+                s->lookahead >= MIN_MATCH) {
+                s->match_length--; /* string at strstart already in table */
+                do {
+                    s->strstart++;
+                    INSERT_STRING(s, s->strstart, hash_head);
+                    /* strstart never exceeds WSIZE-MAX_MATCH, so there are
+                     * always MIN_MATCH bytes ahead.
+                     */
+                } while (--s->match_length != 0);
+                s->strstart++;
+            } else
+#endif
+            {
+                s->strstart += s->match_length;
+                s->match_length = 0;
+                s->ins_h = s->window[s->strstart];
+                UPDATE_HASH(s, s->ins_h, s->window[s->strstart+1]);
+#if MIN_MATCH != 3
+                Call UPDATE_HASH() MIN_MATCH-3 more times
+#endif
+                /* If lookahead < MIN_MATCH, ins_h is garbage, but it does not
+                 * matter since it will be recomputed at next deflate call.
+                 */
+            }
+        } else {
+            /* No match, output a literal byte */
+            Tracevv((stderr,"%c", s->window[s->strstart]));
+            _tr_tally_lit (s, s->window[s->strstart], bflush);
+            s->lookahead--;
+            s->strstart++;
+        }
+        if (bflush) FLUSH_BLOCK(s, 0);
+    }
+    FLUSH_BLOCK(s, flush == Z_FINISH);
+    return flush == Z_FINISH ? finish_done : block_done;
+}
+
+#ifndef FASTEST
+/* ===========================================================================
+ * Same as above, but achieves better compression. We use a lazy
+ * evaluation for matches: a match is finally adopted only if there is
+ * no better match at the next window position.
+ */
+local block_state deflate_slow(s, flush)
+    deflate_state *s;
+    int flush;
+{
+    IPos hash_head = NIL;    /* head of hash chain */
+    int bflush;              /* set if current block must be flushed */
+
+    /* Process the input block. */
+    for (;;) {
+        /* Make sure that we always have enough lookahead, except
+         * at the end of the input file. We need MAX_MATCH bytes
+         * for the next match, plus MIN_MATCH bytes to insert the
+         * string following the next match.
+         */
+        if (s->lookahead < MIN_LOOKAHEAD) {
+            fill_window(s);
+            if (s->lookahead < MIN_LOOKAHEAD && flush == Z_NO_FLUSH) {
+                return need_more;
+            }
+            if (s->lookahead == 0) break; /* flush the current block */
+        }
+
+        /* Insert the string window[strstart .. strstart+2] in the
+         * dictionary, and set hash_head to the head of the hash chain:
+         */
+        if (s->lookahead >= MIN_MATCH) {
+            INSERT_STRING(s, s->strstart, hash_head);
+        }
+
+        /* Find the longest match, discarding those <= prev_length.
+         */
+        s->prev_length = s->match_length, s->prev_match = s->match_start;
+        s->match_length = MIN_MATCH-1;
+
+        if (hash_head != NIL && s->prev_length < s->max_lazy_match &&
+            s->strstart - hash_head <= MAX_DIST(s)) {
+            /* To simplify the code, we prevent matches with the string
+             * of window index 0 (in particular we have to avoid a match
+             * of the string with itself at the start of the input file).
+             */
+            if (s->strategy != Z_HUFFMAN_ONLY && s->strategy != Z_RLE) {
+                s->match_length = longest_match (s, hash_head);
+            } else if (s->strategy == Z_RLE && s->strstart - hash_head == 1) {
+                s->match_length = longest_match_fast (s, hash_head);
+            }
+            /* longest_match() or longest_match_fast() sets match_start */
+
+            if (s->match_length <= 5 && (s->strategy == Z_FILTERED
+#if TOO_FAR <= 32767
+                || (s->match_length == MIN_MATCH &&
+                    s->strstart - s->match_start > TOO_FAR)
+#endif
+                )) {
+
+                /* If prev_match is also MIN_MATCH, match_start is garbage
+                 * but we will ignore the current match anyway.
+                 */
+                s->match_length = MIN_MATCH-1;
+            }
+        }
+        /* If there was a match at the previous step and the current
+         * match is not better, output the previous match:
+         */
+        if (s->prev_length >= MIN_MATCH && s->match_length <= s->prev_length) {
+            uInt max_insert = s->strstart + s->lookahead - MIN_MATCH;
+            /* Do not insert strings in hash table beyond this. */
+
+            check_match(s, s->strstart-1, s->prev_match, s->prev_length);
+
+            _tr_tally_dist(s, s->strstart -1 - s->prev_match,
+                           s->prev_length - MIN_MATCH, bflush);
+
+            /* Insert in hash table all strings up to the end of the match.
+             * strstart-1 and strstart are already inserted. If there is not
+             * enough lookahead, the last two strings are not inserted in
+             * the hash table.
+             */
+            s->lookahead -= s->prev_length-1;
+            s->prev_length -= 2;
+            do {
+                if (++s->strstart <= max_insert) {
+                    INSERT_STRING(s, s->strstart, hash_head);
+                }
+            } while (--s->prev_length != 0);
+            s->match_available = 0;
+            s->match_length = MIN_MATCH-1;
+            s->strstart++;
+
+            if (bflush) FLUSH_BLOCK(s, 0);
+
+        } else if (s->match_available) {
+            /* If there was no match at the previous position, output a
+             * single literal. If there was a match but the current match
+             * is longer, truncate the previous match to a single literal.
+             */
+            Tracevv((stderr,"%c", s->window[s->strstart-1]));
+            _tr_tally_lit(s, s->window[s->strstart-1], bflush);
+            if (bflush) {
+                FLUSH_BLOCK_ONLY(s, 0);
+            }
+            s->strstart++;
+            s->lookahead--;
+            if (s->strm->avail_out == 0) return need_more;
+        } else {
+            /* There is no previous match to compare with, wait for
+             * the next step to decide.
+             */
+            s->match_available = 1;
+            s->strstart++;
+            s->lookahead--;
+        }
+    }
+    Assert (flush != Z_NO_FLUSH, "no flush?");
+    if (s->match_available) {
+        Tracevv((stderr,"%c", s->window[s->strstart-1]));
+        _tr_tally_lit(s, s->window[s->strstart-1], bflush);
+        s->match_available = 0;
+    }
+    FLUSH_BLOCK(s, flush == Z_FINISH);
+    return flush == Z_FINISH ? finish_done : block_done;
+}
+#endif /* FASTEST */
+
+#if 0
+/* ===========================================================================
+ * For Z_RLE, simply look for runs of bytes, generate matches only of distance
+ * one.  Do not maintain a hash table.  (It will be regenerated if this run of
+ * deflate switches away from Z_RLE.)
+ */
+local block_state deflate_rle(s, flush)
+    deflate_state *s;
+    int flush;
+{
+    int bflush;         /* set if current block must be flushed */
+    uInt run;           /* length of run */
+    uInt max;           /* maximum length of run */
+    uInt prev;          /* byte at distance one to match */
+    Bytef *scan;        /* scan for end of run */
+
+    for (;;) {
+        /* Make sure that we always have enough lookahead, except
+         * at the end of the input file. We need MAX_MATCH bytes
+         * for the longest encodable run.
+         */
+        if (s->lookahead < MAX_MATCH) {
+            fill_window(s);
+            if (s->lookahead < MAX_MATCH && flush == Z_NO_FLUSH) {
+                return need_more;
+            }
+            if (s->lookahead == 0) break; /* flush the current block */
+        }
+
+        /* See how many times the previous byte repeats */
+        run = 0;
+        if (s->strstart > 0) {      /* if there is a previous byte, that is */
+            max = s->lookahead < MAX_MATCH ? s->lookahead : MAX_MATCH;
+            scan = s->window + s->strstart - 1;
+            prev = *scan++;
+            do {
+                if (*scan++ != prev)
+                    break;
+            } while (++run < max);
+        }
+
+        /* Emit match if have run of MIN_MATCH or longer, else emit literal */
+        if (run >= MIN_MATCH) {
+            check_match(s, s->strstart, s->strstart - 1, run);
+            _tr_tally_dist(s, 1, run - MIN_MATCH, bflush);
+            s->lookahead -= run;
+            s->strstart += run;
+        } else {
+            /* No match, output a literal byte */
+            Tracevv((stderr,"%c", s->window[s->strstart]));
+            _tr_tally_lit (s, s->window[s->strstart], bflush);
+            s->lookahead--;
+            s->strstart++;
+        }
+        if (bflush) FLUSH_BLOCK(s, 0);
+    }
+    FLUSH_BLOCK(s, flush == Z_FINISH);
+    return flush == Z_FINISH ? finish_done : block_done;
+}
+#endif
diff --git a/usr/klibc/zlib/deflate.h b/usr/klibc/zlib/deflate.h
new file mode 100644
index 0000000..0a37d70
--- /dev/null
+++ b/usr/klibc/zlib/deflate.h
@@ -0,0 +1,331 @@
+/* deflate.h -- internal compression state
+ * Copyright (C) 1995-2004 Jean-loup Gailly
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* WARNING: this file should *not* be used by applications. It is
+   part of the implementation of the compression library and is
+   subject to change. Applications should only use zlib.h.
+ */
+
+/* @(#) $Id: deflate.h,v 1.1 2005/02/27 23:15:39 hpa Exp $ */
+
+#ifndef DEFLATE_H
+#define DEFLATE_H
+
+#include "zutil.h"
+
+/* define NO_GZIP when compiling if you want to disable gzip header and
+   trailer creation by deflate().  NO_GZIP would be used to avoid linking in
+   the crc code when it is not needed.  For shared libraries, gzip encoding
+   should be left enabled. */
+#ifndef NO_GZIP
+#  define GZIP
+#endif
+
+/* ===========================================================================
+ * Internal compression state.
+ */
+
+#define LENGTH_CODES 29
+/* number of length codes, not counting the special END_BLOCK code */
+
+#define LITERALS  256
+/* number of literal bytes 0..255 */
+
+#define L_CODES (LITERALS+1+LENGTH_CODES)
+/* number of Literal or Length codes, including the END_BLOCK code */
+
+#define D_CODES   30
+/* number of distance codes */
+
+#define BL_CODES  19
+/* number of codes used to transfer the bit lengths */
+
+#define HEAP_SIZE (2*L_CODES+1)
+/* maximum heap size */
+
+#define MAX_BITS 15
+/* All codes must not exceed MAX_BITS bits */
+
+#define INIT_STATE    42
+#define EXTRA_STATE   69
+#define NAME_STATE    73
+#define COMMENT_STATE 91
+#define HCRC_STATE   103
+#define BUSY_STATE   113
+#define FINISH_STATE 666
+/* Stream status */
+
+
+/* Data structure describing a single value and its code string. */
+typedef struct ct_data_s {
+    union {
+        ush  freq;       /* frequency count */
+        ush  code;       /* bit string */
+    } fc;
+    union {
+        ush  dad;        /* father node in Huffman tree */
+        ush  len;        /* length of bit string */
+    } dl;
+} FAR ct_data;
+
+#define Freq fc.freq
+#define Code fc.code
+#define Dad  dl.dad
+#define Len  dl.len
+
+typedef struct static_tree_desc_s  static_tree_desc;
+
+typedef struct tree_desc_s {
+    ct_data *dyn_tree;           /* the dynamic tree */
+    int     max_code;            /* largest code with non zero frequency */
+    static_tree_desc *stat_desc; /* the corresponding static tree */
+} FAR tree_desc;
+
+typedef ush Pos;
+typedef Pos FAR Posf;
+typedef unsigned IPos;
+
+/* A Pos is an index in the character window. We use short instead of int to
+ * save space in the various tables. IPos is used only for parameter passing.
+ */
+
+typedef struct internal_state {
+    z_streamp strm;      /* pointer back to this zlib stream */
+    int   status;        /* as the name implies */
+    Bytef *pending_buf;  /* output still pending */
+    ulg   pending_buf_size; /* size of pending_buf */
+    Bytef *pending_out;  /* next pending byte to output to the stream */
+    uInt   pending;      /* nb of bytes in the pending buffer */
+    int   wrap;          /* bit 0 true for zlib, bit 1 true for gzip */
+    gz_headerp  gzhead;  /* gzip header information to write */
+    uInt   gzindex;      /* where in extra, name, or comment */
+    Byte  method;        /* STORED (for zip only) or DEFLATED */
+    int   last_flush;    /* value of flush param for previous deflate call */
+
+                /* used by deflate.c: */
+
+    uInt  w_size;        /* LZ77 window size (32K by default) */
+    uInt  w_bits;        /* log2(w_size)  (8..16) */
+    uInt  w_mask;        /* w_size - 1 */
+
+    Bytef *window;
+    /* Sliding window. Input bytes are read into the second half of the window,
+     * and move to the first half later to keep a dictionary of at least wSize
+     * bytes. With this organization, matches are limited to a distance of
+     * wSize-MAX_MATCH bytes, but this ensures that IO is always
+     * performed with a length multiple of the block size. Also, it limits
+     * the window size to 64K, which is quite useful on MSDOS.
+     * To do: use the user input buffer as sliding window.
+     */
+
+    ulg window_size;
+    /* Actual size of window: 2*wSize, except when the user input buffer
+     * is directly used as sliding window.
+     */
+
+    Posf *prev;
+    /* Link to older string with same hash index. To limit the size of this
+     * array to 64K, this link is maintained only for the last 32K strings.
+     * An index in this array is thus a window index modulo 32K.
+     */
+
+    Posf *head; /* Heads of the hash chains or NIL. */
+
+    uInt  ins_h;          /* hash index of string to be inserted */
+    uInt  hash_size;      /* number of elements in hash table */
+    uInt  hash_bits;      /* log2(hash_size) */
+    uInt  hash_mask;      /* hash_size-1 */
+
+    uInt  hash_shift;
+    /* Number of bits by which ins_h must be shifted at each input
+     * step. It must be such that after MIN_MATCH steps, the oldest
+     * byte no longer takes part in the hash key, that is:
+     *   hash_shift * MIN_MATCH >= hash_bits
+     */
+
+    long block_start;
+    /* Window position at the beginning of the current output block. Gets
+     * negative when the window is moved backwards.
+     */
+
+    uInt match_length;           /* length of best match */
+    IPos prev_match;             /* previous match */
+    int match_available;         /* set if previous match exists */
+    uInt strstart;               /* start of string to insert */
+    uInt match_start;            /* start of matching string */
+    uInt lookahead;              /* number of valid bytes ahead in window */
+
+    uInt prev_length;
+    /* Length of the best match at previous step. Matches not greater than this
+     * are discarded. This is used in the lazy match evaluation.
+     */
+
+    uInt max_chain_length;
+    /* To speed up deflation, hash chains are never searched beyond this
+     * length.  A higher limit improves compression ratio but degrades the
+     * speed.
+     */
+
+    uInt max_lazy_match;
+    /* Attempt to find a better match only when the current match is strictly
+     * smaller than this value. This mechanism is used only for compression
+     * levels >= 4.
+     */
+#   define max_insert_length  max_lazy_match
+    /* Insert new strings in the hash table only if the match length is not
+     * greater than this length. This saves time but degrades compression.
+     * max_insert_length is used only for compression levels <= 3.
+     */
+
+    int level;    /* compression level (1..9) */
+    int strategy; /* favor or force Huffman coding*/
+
+    uInt good_match;
+    /* Use a faster search when the previous match is longer than this */
+
+    int nice_match; /* Stop searching when current match exceeds this */
+
+                /* used by trees.c: */
+    /* Didn't use ct_data typedef below to supress compiler warning */
+    struct ct_data_s dyn_ltree[HEAP_SIZE];   /* literal and length tree */
+    struct ct_data_s dyn_dtree[2*D_CODES+1]; /* distance tree */
+    struct ct_data_s bl_tree[2*BL_CODES+1];  /* Huffman tree for bit lengths */
+
+    struct tree_desc_s l_desc;               /* desc. for literal tree */
+    struct tree_desc_s d_desc;               /* desc. for distance tree */
+    struct tree_desc_s bl_desc;              /* desc. for bit length tree */
+
+    ush bl_count[MAX_BITS+1];
+    /* number of codes at each bit length for an optimal tree */
+
+    int heap[2*L_CODES+1];      /* heap used to build the Huffman trees */
+    int heap_len;               /* number of elements in the heap */
+    int heap_max;               /* element of largest frequency */
+    /* The sons of heap[n] are heap[2*n] and heap[2*n+1]. heap[0] is not used.
+     * The same heap array is used to build all trees.
+     */
+
+    uch depth[2*L_CODES+1];
+    /* Depth of each subtree used as tie breaker for trees of equal frequency
+     */
+
+    uchf *l_buf;          /* buffer for literals or lengths */
+
+    uInt  lit_bufsize;
+    /* Size of match buffer for literals/lengths.  There are 4 reasons for
+     * limiting lit_bufsize to 64K:
+     *   - frequencies can be kept in 16 bit counters
+     *   - if compression is not successful for the first block, all input
+     *     data is still in the window so we can still emit a stored block even
+     *     when input comes from standard input.  (This can also be done for
+     *     all blocks if lit_bufsize is not greater than 32K.)
+     *   - if compression is not successful for a file smaller than 64K, we can
+     *     even emit a stored file instead of a stored block (saving 5 bytes).
+     *     This is applicable only for zip (not gzip or zlib).
+     *   - creating new Huffman trees less frequently may not provide fast
+     *     adaptation to changes in the input data statistics. (Take for
+     *     example a binary file with poorly compressible code followed by
+     *     a highly compressible string table.) Smaller buffer sizes give
+     *     fast adaptation but have of course the overhead of transmitting
+     *     trees more frequently.
+     *   - I can't count above 4
+     */
+
+    uInt last_lit;      /* running index in l_buf */
+
+    ushf *d_buf;
+    /* Buffer for distances. To simplify the code, d_buf and l_buf have
+     * the same number of elements. To use different lengths, an extra flag
+     * array would be necessary.
+     */
+
+    ulg opt_len;        /* bit length of current block with optimal trees */
+    ulg static_len;     /* bit length of current block with static trees */
+    uInt matches;       /* number of string matches in current block */
+    int last_eob_len;   /* bit length of EOB code for last block */
+
+#ifdef DEBUG
+    ulg compressed_len; /* total bit length of compressed file mod 2^32 */
+    ulg bits_sent;      /* bit length of compressed data sent mod 2^32 */
+#endif
+
+    ush bi_buf;
+    /* Output buffer. bits are inserted starting at the bottom (least
+     * significant bits).
+     */
+    int bi_valid;
+    /* Number of valid bits in bi_buf.  All bits above the last valid bit
+     * are always zero.
+     */
+
+} FAR deflate_state;
+
+/* Output a byte on the stream.
+ * IN assertion: there is enough room in pending_buf.
+ */
+#define put_byte(s, c) {s->pending_buf[s->pending++] = (c);}
+
+
+#define MIN_LOOKAHEAD (MAX_MATCH+MIN_MATCH+1)
+/* Minimum amount of lookahead, except at the end of the input file.
+ * See deflate.c for comments about the MIN_MATCH+1.
+ */
+
+#define MAX_DIST(s)  ((s)->w_size-MIN_LOOKAHEAD)
+/* In order to simplify the code, particularly on 16 bit machines, match
+ * distances are limited to MAX_DIST instead of WSIZE.
+ */
+
+        /* in trees.c */
+void _tr_init         OF((deflate_state *s));
+int  _tr_tally        OF((deflate_state *s, unsigned dist, unsigned lc));
+void _tr_flush_block  OF((deflate_state *s, charf *buf, ulg stored_len,
+                          int eof));
+void _tr_align        OF((deflate_state *s));
+void _tr_stored_block OF((deflate_state *s, charf *buf, ulg stored_len,
+                          int eof));
+
+#define d_code(dist) \
+   ((dist) < 256 ? _dist_code[dist] : _dist_code[256+((dist)>>7)])
+/* Mapping from a distance to a distance code. dist is the distance - 1 and
+ * must not have side effects. _dist_code[256] and _dist_code[257] are never
+ * used.
+ */
+
+#ifndef DEBUG
+/* Inline versions of _tr_tally for speed: */
+
+#if defined(GEN_TREES_H) || !defined(STDC)
+  extern uch _length_code[];
+  extern uch _dist_code[];
+#else
+  extern const uch _length_code[];
+  extern const uch _dist_code[];
+#endif
+
+# define _tr_tally_lit(s, c, flush) \
+  { uch cc = (c); \
+    s->d_buf[s->last_lit] = 0; \
+    s->l_buf[s->last_lit++] = cc; \
+    s->dyn_ltree[cc].Freq++; \
+    flush = (s->last_lit == s->lit_bufsize-1); \
+   }
+# define _tr_tally_dist(s, distance, length, flush) \
+  { uch len = (length); \
+    ush dist = (distance); \
+    s->d_buf[s->last_lit] = dist; \
+    s->l_buf[s->last_lit++] = len; \
+    dist--; \
+    s->dyn_ltree[_length_code[len]+LITERALS+1].Freq++; \
+    s->dyn_dtree[d_code(dist)].Freq++; \
+    flush = (s->last_lit == s->lit_bufsize-1); \
+  }
+#else
+# define _tr_tally_lit(s, c, flush) flush = _tr_tally(s, 0, c)
+# define _tr_tally_dist(s, distance, length, flush) \
+              flush = _tr_tally(s, distance, length)
+#endif
+
+#endif /* DEFLATE_H */
diff --git a/usr/klibc/zlib/gzio.c b/usr/klibc/zlib/gzio.c
new file mode 100644
index 0000000..0116ea3
--- /dev/null
+++ b/usr/klibc/zlib/gzio.c
@@ -0,0 +1,1029 @@
+/* gzio.c -- IO on .gz files
+ * Copyright (C) 1995-2005 Jean-loup Gailly.
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ *
+ * Compile this file with -DNO_GZCOMPRESS to avoid the compression code.
+ */
+
+/* @(#) $Id: gzio.c,v 1.1 2005/02/27 23:15:39 hpa Exp $ */
+
+#include <stdio.h>
+
+#include "zutil.h"
+
+#ifdef NO_DEFLATE       /* for compatibility with old definition */
+#  define NO_GZCOMPRESS
+#endif
+
+#ifndef NO_DUMMY_DECL
+struct internal_state {int dummy;}; /* for buggy compilers */
+#endif
+
+#ifndef Z_BUFSIZE
+#  ifdef MAXSEG_64K
+#    define Z_BUFSIZE 4096 /* minimize memory usage for 16-bit DOS */
+#  else
+#    define Z_BUFSIZE 16384
+#  endif
+#endif
+#ifndef Z_PRINTF_BUFSIZE
+#  define Z_PRINTF_BUFSIZE 4096
+#endif
+
+#ifdef __MVS__
+#  pragma map (fdopen , "\174\174FDOPEN")
+   FILE *fdopen(int, const char *);
+#endif
+
+#ifndef STDC
+extern voidp  malloc OF((uInt size));
+extern void   free   OF((voidpf ptr));
+#endif
+
+#define ALLOC(size) malloc(size)
+#define TRYFREE(p) {if (p) free(p);}
+
+static int const gz_magic[2] = {0x1f, 0x8b}; /* gzip magic header */
+
+/* gzip flag byte */
+#define ASCII_FLAG   0x01 /* bit 0 set: file probably ascii text */
+#define HEAD_CRC     0x02 /* bit 1 set: header CRC present */
+#define EXTRA_FIELD  0x04 /* bit 2 set: extra field present */
+#define ORIG_NAME    0x08 /* bit 3 set: original file name present */
+#define COMMENT      0x10 /* bit 4 set: file comment present */
+#define RESERVED     0xE0 /* bits 5..7: reserved */
+
+typedef struct gz_stream {
+    z_stream stream;
+    int      z_err;   /* error code for last stream operation */
+    int      z_eof;   /* set if end of input file */
+    FILE     *file;   /* .gz file */
+    Byte     *inbuf;  /* input buffer */
+    Byte     *outbuf; /* output buffer */
+    uLong    crc;     /* crc32 of uncompressed data */
+    char     *msg;    /* error message */
+    char     *path;   /* path name for debugging only */
+    int      transparent; /* 1 if input file is not a .gz file */
+    char     mode;    /* 'w' or 'r' */
+    z_off_t  start;   /* start of compressed data in file (header skipped) */
+    z_off_t  in;      /* bytes into deflate or inflate */
+    z_off_t  out;     /* bytes out of deflate or inflate */
+    int      back;    /* one character push-back */
+    int      last;    /* true if push-back is last character */
+} gz_stream;
+
+
+local gzFile gz_open      OF((const char *path, const char *mode, int  fd));
+local int do_flush        OF((gzFile file, int flush));
+local int    get_byte     OF((gz_stream *s));
+local void   check_header OF((gz_stream *s));
+local int    destroy      OF((gz_stream *s));
+local void   putLong      OF((FILE *file, uLong x));
+local uLong  getLong      OF((gz_stream *s));
+
+/* ===========================================================================
+     Opens a gzip (.gz) file for reading or writing. The mode parameter
+   is as in fopen ("rb" or "wb"). The file is given either by file descriptor
+   or path name (if fd == -1).
+     gz_open returns NULL if the file could not be opened or if there was
+   insufficient memory to allocate the (de)compression state; errno
+   can be checked to distinguish the two cases (if errno is zero, the
+   zlib error is Z_MEM_ERROR).
+*/
+local gzFile gz_open (path, mode, fd)
+    const char *path;
+    const char *mode;
+    int  fd;
+{
+    int err;
+    int level = Z_DEFAULT_COMPRESSION; /* compression level */
+    int strategy = Z_DEFAULT_STRATEGY; /* compression strategy */
+    char *p = (char*)mode;
+    gz_stream *s;
+    char fmode[80]; /* copy of mode, without the compression level */
+    char *m = fmode;
+
+    if (!path || !mode) return Z_NULL;
+
+    s = (gz_stream *)ALLOC(sizeof(gz_stream));
+    if (!s) return Z_NULL;
+
+    s->stream.zalloc = (alloc_func)0;
+    s->stream.zfree = (free_func)0;
+    s->stream.opaque = (voidpf)0;
+    s->stream.next_in = s->inbuf = Z_NULL;
+    s->stream.next_out = s->outbuf = Z_NULL;
+    s->stream.avail_in = s->stream.avail_out = 0;
+    s->file = NULL;
+    s->z_err = Z_OK;
+    s->z_eof = 0;
+    s->in = 0;
+    s->out = 0;
+    s->back = EOF;
+    s->crc = crc32(0L, Z_NULL, 0);
+    s->msg = NULL;
+    s->transparent = 0;
+
+    s->path = (char*)ALLOC(strlen(path)+1);
+    if (s->path == NULL) {
+        return destroy(s), (gzFile)Z_NULL;
+    }
+    strcpy(s->path, path); /* do this early for debugging */
+
+    s->mode = '\0';
+    do {
+        if (*p == 'r') s->mode = 'r';
+        if (*p == 'w' || *p == 'a') s->mode = 'w';
+        if (*p >= '0' && *p <= '9') {
+            level = *p - '0';
+        } else if (*p == 'f') {
+          strategy = Z_FILTERED;
+        } else if (*p == 'h') {
+          strategy = Z_HUFFMAN_ONLY;
+        } else if (*p == 'R') {
+          strategy = Z_RLE;
+        } else {
+            *m++ = *p; /* copy the mode */
+        }
+    } while (*p++ && m != fmode + sizeof(fmode));
+    if (s->mode == '\0') return destroy(s), (gzFile)Z_NULL;
+
+    if (s->mode == 'w') {
+#ifdef NO_GZCOMPRESS
+        err = Z_STREAM_ERROR;
+#else
+        err = deflateInit2(&(s->stream), level,
+                           Z_DEFLATED, -MAX_WBITS, DEF_MEM_LEVEL, strategy);
+        /* windowBits is passed < 0 to suppress zlib header */
+
+        s->stream.next_out = s->outbuf = (Byte*)ALLOC(Z_BUFSIZE);
+#endif
+        if (err != Z_OK || s->outbuf == Z_NULL) {
+            return destroy(s), (gzFile)Z_NULL;
+        }
+    } else {
+        s->stream.next_in  = s->inbuf = (Byte*)ALLOC(Z_BUFSIZE);
+
+        err = inflateInit2(&(s->stream), -MAX_WBITS);
+        /* windowBits is passed < 0 to tell that there is no zlib header.
+         * Note that in this case inflate *requires* an extra "dummy" byte
+         * after the compressed stream in order to complete decompression and
+         * return Z_STREAM_END. Here the gzip CRC32 ensures that 4 bytes are
+         * present after the compressed stream.
+         */
+        if (err != Z_OK || s->inbuf == Z_NULL) {
+            return destroy(s), (gzFile)Z_NULL;
+        }
+    }
+    s->stream.avail_out = Z_BUFSIZE;
+
+    errno = 0;
+    s->file = fd < 0 ? F_OPEN(path, fmode) : (FILE*)fdopen(fd, fmode);
+
+    if (s->file == NULL) {
+        return destroy(s), (gzFile)Z_NULL;
+    }
+    if (s->mode == 'w') {
+        /* Write a very simple .gz header:
+         */
+        fprintf(s->file, "%c%c%c%c%c%c%c%c%c%c", gz_magic[0], gz_magic[1],
+             Z_DEFLATED, 0 /*flags*/, 0,0,0,0 /*time*/, 0 /*xflags*/, OS_CODE);
+        s->start = 10L;
+        /* We use 10L instead of ftell(s->file) to because ftell causes an
+         * fflush on some systems. This version of the library doesn't use
+         * start anyway in write mode, so this initialization is not
+         * necessary.
+         */
+    } else {
+        check_header(s); /* skip the .gz header */
+        s->start = ftell(s->file) - s->stream.avail_in;
+    }
+
+    return (gzFile)s;
+}
+
+/* ===========================================================================
+     Opens a gzip (.gz) file for reading or writing.
+*/
+gzFile ZEXPORT gzopen (path, mode)
+    const char *path;
+    const char *mode;
+{
+    return gz_open (path, mode, -1);
+}
+
+/* ===========================================================================
+     Associate a gzFile with the file descriptor fd. fd is not dup'ed here
+   to mimic the behavio(u)r of fdopen.
+*/
+gzFile ZEXPORT gzdopen (fd, mode)
+    int fd;
+    const char *mode;
+{
+    char name[46];      /* allow for up to 128-bit integers */
+
+    if (fd < 0) return (gzFile)Z_NULL;
+    sprintf(name, "<fd:%d>", fd); /* for debugging */
+
+    return gz_open (name, mode, fd);
+}
+
+/* ===========================================================================
+ * Update the compression level and strategy
+ */
+int ZEXPORT gzsetparams (file, level, strategy)
+    gzFile file;
+    int level;
+    int strategy;
+{
+    gz_stream *s = (gz_stream*)file;
+
+    if (s == NULL || s->mode != 'w') return Z_STREAM_ERROR;
+
+    /* Make room to allow flushing */
+    if (s->stream.avail_out == 0) {
+
+        s->stream.next_out = s->outbuf;
+        if (fwrite(s->outbuf, 1, Z_BUFSIZE, s->file) != Z_BUFSIZE) {
+            s->z_err = Z_ERRNO;
+        }
+        s->stream.avail_out = Z_BUFSIZE;
+    }
+
+    return deflateParams (&(s->stream), level, strategy);
+}
+
+/* ===========================================================================
+     Read a byte from a gz_stream; update next_in and avail_in. Return EOF
+   for end of file.
+   IN assertion: the stream s has been sucessfully opened for reading.
+*/
+local int get_byte(s)
+    gz_stream *s;
+{
+    if (s->z_eof) return EOF;
+    if (s->stream.avail_in == 0) {
+        errno = 0;
+        s->stream.avail_in = (uInt)fread(s->inbuf, 1, Z_BUFSIZE, s->file);
+        if (s->stream.avail_in == 0) {
+            s->z_eof = 1;
+	    /* klibc hack */
+            if (errno) s->z_err = Z_ERRNO;
+            return EOF;
+        }
+        s->stream.next_in = s->inbuf;
+    }
+    s->stream.avail_in--;
+    return *(s->stream.next_in)++;
+}
+
+/* ===========================================================================
+      Check the gzip header of a gz_stream opened for reading. Set the stream
+    mode to transparent if the gzip magic header is not present; set s->err
+    to Z_DATA_ERROR if the magic header is present but the rest of the header
+    is incorrect.
+    IN assertion: the stream s has already been created sucessfully;
+       s->stream.avail_in is zero for the first time, but may be non-zero
+       for concatenated .gz files.
+*/
+local void check_header(s)
+    gz_stream *s;
+{
+    int method; /* method byte */
+    int flags;  /* flags byte */
+    uInt len;
+    int c;
+
+    /* Assure two bytes in the buffer so we can peek ahead -- handle case
+       where first byte of header is at the end of the buffer after the last
+       gzip segment */
+    len = s->stream.avail_in;
+    if (len < 2) {
+        if (len) s->inbuf[0] = s->stream.next_in[0];
+        errno = 0;
+        len = (uInt)fread(s->inbuf + len, 1, Z_BUFSIZE >> len, s->file);
+	/* klibc hack */
+        if (len == 0 && errno) s->z_err = Z_ERRNO;
+        s->stream.avail_in += len;
+        s->stream.next_in = s->inbuf;
+        if (s->stream.avail_in < 2) {
+            s->transparent = s->stream.avail_in;
+            return;
+        }
+    }
+
+    /* Peek ahead to check the gzip magic header */
+    if (s->stream.next_in[0] != gz_magic[0] ||
+        s->stream.next_in[1] != gz_magic[1]) {
+        s->transparent = 1;
+        return;
+    }
+    s->stream.avail_in -= 2;
+    s->stream.next_in += 2;
+
+    /* Check the rest of the gzip header */
+    method = get_byte(s);
+    flags = get_byte(s);
+    if (method != Z_DEFLATED || (flags & RESERVED) != 0) {
+        s->z_err = Z_DATA_ERROR;
+        return;
+    }
+
+    /* Discard time, xflags and OS code: */
+    for (len = 0; len < 6; len++) (void)get_byte(s);
+
+    if ((flags & EXTRA_FIELD) != 0) { /* skip the extra field */
+        len  =  (uInt)get_byte(s);
+        len += ((uInt)get_byte(s))<<8;
+        /* len is garbage if EOF but the loop below will quit anyway */
+        while (len-- != 0 && get_byte(s) != EOF) ;
+    }
+    if ((flags & ORIG_NAME) != 0) { /* skip the original file name */
+        while ((c = get_byte(s)) != 0 && c != EOF) ;
+    }
+    if ((flags & COMMENT) != 0) {   /* skip the .gz file comment */
+        while ((c = get_byte(s)) != 0 && c != EOF) ;
+    }
+    if ((flags & HEAD_CRC) != 0) {  /* skip the header crc */
+        for (len = 0; len < 2; len++) (void)get_byte(s);
+    }
+    s->z_err = s->z_eof ? Z_DATA_ERROR : Z_OK;
+}
+
+ /* ===========================================================================
+ * Cleanup then free the given gz_stream. Return a zlib error code.
+   Try freeing in the reverse order of allocations.
+ */
+local int destroy (s)
+    gz_stream *s;
+{
+    int err = Z_OK;
+
+    if (!s) return Z_STREAM_ERROR;
+
+    TRYFREE(s->msg);
+
+    if (s->stream.state != NULL) {
+        if (s->mode == 'w') {
+#ifdef NO_GZCOMPRESS
+            err = Z_STREAM_ERROR;
+#else
+            err = deflateEnd(&(s->stream));
+#endif
+        } else if (s->mode == 'r') {
+            err = inflateEnd(&(s->stream));
+        }
+    }
+    if (s->file != NULL && fclose(s->file)) {
+#ifdef ESPIPE
+        if (errno != ESPIPE) /* fclose is broken for pipes in HP/UX */
+#endif
+            err = Z_ERRNO;
+    }
+    if (s->z_err < 0) err = s->z_err;
+
+    TRYFREE(s->inbuf);
+    TRYFREE(s->outbuf);
+    TRYFREE(s->path);
+    TRYFREE(s);
+    return err;
+}
+
+/* ===========================================================================
+     Reads the given number of uncompressed bytes from the compressed file.
+   gzread returns the number of bytes actually read (0 for end of file).
+*/
+int ZEXPORT gzread (file, buf, len)
+    gzFile file;
+    voidp buf;
+    unsigned len;
+{
+    gz_stream *s = (gz_stream*)file;
+    Bytef *start = (Bytef*)buf; /* starting point for crc computation */
+    Byte  *next_out; /* == stream.next_out but not forced far (for MSDOS) */
+
+    if (s == NULL || s->mode != 'r') return Z_STREAM_ERROR;
+
+    if (s->z_err == Z_DATA_ERROR || s->z_err == Z_ERRNO) return -1;
+    if (s->z_err == Z_STREAM_END) return 0;  /* EOF */
+
+    next_out = (Byte*)buf;
+    s->stream.next_out = (Bytef*)buf;
+    s->stream.avail_out = len;
+
+    if (s->stream.avail_out && s->back != EOF) {
+        *next_out++ = s->back;
+        s->stream.next_out++;
+        s->stream.avail_out--;
+        s->back = EOF;
+        s->out++;
+        start++;
+        if (s->last) {
+            s->z_err = Z_STREAM_END;
+            return 1;
+        }
+    }
+
+    while (s->stream.avail_out != 0) {
+
+        if (s->transparent) {
+            /* Copy first the lookahead bytes: */
+            uInt n = s->stream.avail_in;
+            if (n > s->stream.avail_out) n = s->stream.avail_out;
+            if (n > 0) {
+                zmemcpy(s->stream.next_out, s->stream.next_in, n);
+                next_out += n;
+                s->stream.next_out = next_out;
+                s->stream.next_in   += n;
+                s->stream.avail_out -= n;
+                s->stream.avail_in  -= n;
+            }
+            if (s->stream.avail_out > 0) {
+                s->stream.avail_out -=
+                    (uInt)fread(next_out, 1, s->stream.avail_out, s->file);
+            }
+            len -= s->stream.avail_out;
+            s->in  += len;
+            s->out += len;
+            if (len == 0) s->z_eof = 1;
+            return (int)len;
+        }
+        if (s->stream.avail_in == 0 && !s->z_eof) {
+
+            errno = 0;
+            s->stream.avail_in = (uInt)fread(s->inbuf, 1, Z_BUFSIZE, s->file);
+            if (s->stream.avail_in == 0) {
+                s->z_eof = 1;
+                if (errno) {
+                    s->z_err = Z_ERRNO;
+                    break;
+                }
+            }
+            s->stream.next_in = s->inbuf;
+        }
+        s->in += s->stream.avail_in;
+        s->out += s->stream.avail_out;
+        s->z_err = inflate(&(s->stream), Z_NO_FLUSH);
+        s->in -= s->stream.avail_in;
+        s->out -= s->stream.avail_out;
+
+        if (s->z_err == Z_STREAM_END) {
+            /* Check CRC and original size */
+            s->crc = crc32(s->crc, start, (uInt)(s->stream.next_out - start));
+            start = s->stream.next_out;
+
+            if (getLong(s) != s->crc) {
+                s->z_err = Z_DATA_ERROR;
+            } else {
+                (void)getLong(s);
+                /* The uncompressed length returned by above getlong() may be
+                 * different from s->out in case of concatenated .gz files.
+                 * Check for such files:
+                 */
+                check_header(s);
+                if (s->z_err == Z_OK) {
+                    inflateReset(&(s->stream));
+                    s->crc = crc32(0L, Z_NULL, 0);
+                }
+            }
+        }
+        if (s->z_err != Z_OK || s->z_eof) break;
+    }
+    s->crc = crc32(s->crc, start, (uInt)(s->stream.next_out - start));
+
+    if (len == s->stream.avail_out &&
+        (s->z_err == Z_DATA_ERROR || s->z_err == Z_ERRNO))
+        return -1;
+    return (int)(len - s->stream.avail_out);
+}
+
+
+/* ===========================================================================
+      Reads one byte from the compressed file. gzgetc returns this byte
+   or -1 in case of end of file or error.
+*/
+int ZEXPORT gzgetc(file)
+    gzFile file;
+{
+    unsigned char c;
+
+    return gzread(file, &c, 1) == 1 ? c : -1;
+}
+
+
+/* ===========================================================================
+      Push one byte back onto the stream.
+*/
+int ZEXPORT gzungetc(c, file)
+    int c;
+    gzFile file;
+{
+    gz_stream *s = (gz_stream*)file;
+
+    if (s == NULL || s->mode != 'r' || c == EOF || s->back != EOF) return EOF;
+    s->back = c;
+    s->out--;
+    s->last = (s->z_err == Z_STREAM_END);
+    if (s->last) s->z_err = Z_OK;
+    s->z_eof = 0;
+    return c;
+}
+
+
+/* ===========================================================================
+      Reads bytes from the compressed file until len-1 characters are
+   read, or a newline character is read and transferred to buf, or an
+   end-of-file condition is encountered.  The string is then terminated
+   with a null character.
+      gzgets returns buf, or Z_NULL in case of error.
+
+      The current implementation is not optimized at all.
+*/
+char * ZEXPORT gzgets(file, buf, len)
+    gzFile file;
+    char *buf;
+    int len;
+{
+    char *b = buf;
+    if (buf == Z_NULL || len <= 0) return Z_NULL;
+
+    while (--len > 0 && gzread(file, buf, 1) == 1 && *buf++ != '\n') ;
+    *buf = '\0';
+    return b == buf && len > 0 ? Z_NULL : b;
+}
+
+
+#ifndef NO_GZCOMPRESS
+/* ===========================================================================
+     Writes the given number of uncompressed bytes into the compressed file.
+   gzwrite returns the number of bytes actually written (0 in case of error).
+*/
+int ZEXPORT gzwrite (file, buf, len)
+    gzFile file;
+    voidpc buf;
+    unsigned len;
+{
+    gz_stream *s = (gz_stream*)file;
+
+    if (s == NULL || s->mode != 'w') return Z_STREAM_ERROR;
+
+    s->stream.next_in = (Bytef*)buf;
+    s->stream.avail_in = len;
+
+    while (s->stream.avail_in != 0) {
+
+        if (s->stream.avail_out == 0) {
+
+            s->stream.next_out = s->outbuf;
+            if (fwrite(s->outbuf, 1, Z_BUFSIZE, s->file) != Z_BUFSIZE) {
+                s->z_err = Z_ERRNO;
+                break;
+            }
+            s->stream.avail_out = Z_BUFSIZE;
+        }
+        s->in += s->stream.avail_in;
+        s->out += s->stream.avail_out;
+        s->z_err = deflate(&(s->stream), Z_NO_FLUSH);
+        s->in -= s->stream.avail_in;
+        s->out -= s->stream.avail_out;
+        if (s->z_err != Z_OK) break;
+    }
+    s->crc = crc32(s->crc, (const Bytef *)buf, len);
+
+    return (int)(len - s->stream.avail_in);
+}
+
+
+/* ===========================================================================
+     Converts, formats, and writes the args to the compressed file under
+   control of the format string, as in fprintf. gzprintf returns the number of
+   uncompressed bytes actually written (0 in case of error).
+*/
+#ifdef STDC
+#include <stdarg.h>
+
+int ZEXPORTVA gzprintf (gzFile file, const char *format, /* args */ ...)
+{
+    char buf[Z_PRINTF_BUFSIZE];
+    va_list va;
+    int len;
+
+    buf[sizeof(buf) - 1] = 0;
+    va_start(va, format);
+#ifdef NO_vsnprintf
+#  ifdef HAS_vsprintf_void
+    (void)vsprintf(buf, format, va);
+    va_end(va);
+    for (len = 0; len < sizeof(buf); len++)
+        if (buf[len] == 0) break;
+#  else
+    len = vsprintf(buf, format, va);
+    va_end(va);
+#  endif
+#else
+#  ifdef HAS_vsnprintf_void
+    (void)vsnprintf(buf, sizeof(buf), format, va);
+    va_end(va);
+    len = strlen(buf);
+#  else
+    len = vsnprintf(buf, sizeof(buf), format, va);
+    va_end(va);
+#  endif
+#endif
+    if (len <= 0 || len >= (int)sizeof(buf) || buf[sizeof(buf) - 1] != 0)
+        return 0;
+    return gzwrite(file, buf, (unsigned)len);
+}
+#else /* not ANSI C */
+
+int ZEXPORTVA gzprintf (file, format, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10,
+                       a11, a12, a13, a14, a15, a16, a17, a18, a19, a20)
+    gzFile file;
+    const char *format;
+    int a1, a2, a3, a4, a5, a6, a7, a8, a9, a10,
+        a11, a12, a13, a14, a15, a16, a17, a18, a19, a20;
+{
+    char buf[Z_PRINTF_BUFSIZE];
+    int len;
+
+    buf[sizeof(buf) - 1] = 0;
+#ifdef NO_snprintf
+#  ifdef HAS_sprintf_void
+    sprintf(buf, format, a1, a2, a3, a4, a5, a6, a7, a8,
+            a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20);
+    for (len = 0; len < sizeof(buf); len++)
+        if (buf[len] == 0) break;
+#  else
+    len = sprintf(buf, format, a1, a2, a3, a4, a5, a6, a7, a8,
+                a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20);
+#  endif
+#else
+#  ifdef HAS_snprintf_void
+    snprintf(buf, sizeof(buf), format, a1, a2, a3, a4, a5, a6, a7, a8,
+             a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20);
+    len = strlen(buf);
+#  else
+    len = snprintf(buf, sizeof(buf), format, a1, a2, a3, a4, a5, a6, a7, a8,
+                 a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20);
+#  endif
+#endif
+    if (len <= 0 || len >= sizeof(buf) || buf[sizeof(buf) - 1] != 0)
+        return 0;
+    return gzwrite(file, buf, len);
+}
+#endif
+
+/* ===========================================================================
+      Writes c, converted to an unsigned char, into the compressed file.
+   gzputc returns the value that was written, or -1 in case of error.
+*/
+int ZEXPORT gzputc(file, c)
+    gzFile file;
+    int c;
+{
+    unsigned char cc = (unsigned char) c; /* required for big endian systems */
+
+    return gzwrite(file, &cc, 1) == 1 ? (int)cc : -1;
+}
+
+
+/* ===========================================================================
+      Writes the given null-terminated string to the compressed file, excluding
+   the terminating null character.
+      gzputs returns the number of characters written, or -1 in case of error.
+*/
+int ZEXPORT gzputs(file, s)
+    gzFile file;
+    const char *s;
+{
+    return gzwrite(file, (char*)s, (unsigned)strlen(s));
+}
+
+
+/* ===========================================================================
+     Flushes all pending output into the compressed file. The parameter
+   flush is as in the deflate() function.
+*/
+local int do_flush (file, flush)
+    gzFile file;
+    int flush;
+{
+    uInt len;
+    int done = 0;
+    gz_stream *s = (gz_stream*)file;
+
+    if (s == NULL || s->mode != 'w') return Z_STREAM_ERROR;
+
+    s->stream.avail_in = 0; /* should be zero already anyway */
+
+    for (;;) {
+        len = Z_BUFSIZE - s->stream.avail_out;
+
+        if (len != 0) {
+            if ((uInt)fwrite(s->outbuf, 1, len, s->file) != len) {
+                s->z_err = Z_ERRNO;
+                return Z_ERRNO;
+            }
+            s->stream.next_out = s->outbuf;
+            s->stream.avail_out = Z_BUFSIZE;
+        }
+        if (done) break;
+        s->out += s->stream.avail_out;
+        s->z_err = deflate(&(s->stream), flush);
+        s->out -= s->stream.avail_out;
+
+        /* Ignore the second of two consecutive flushes: */
+        if (len == 0 && s->z_err == Z_BUF_ERROR) s->z_err = Z_OK;
+
+        /* deflate has finished flushing only when it hasn't used up
+         * all the available space in the output buffer:
+         */
+        done = (s->stream.avail_out != 0 || s->z_err == Z_STREAM_END);
+
+        if (s->z_err != Z_OK && s->z_err != Z_STREAM_END) break;
+    }
+    return  s->z_err == Z_STREAM_END ? Z_OK : s->z_err;
+}
+
+int ZEXPORT gzflush (file, flush)
+     gzFile file;
+     int flush;
+{
+    gz_stream *s = (gz_stream*)file;
+    int err = do_flush (file, flush);
+
+    if (err) return err;
+    fflush(s->file);
+    return  s->z_err == Z_STREAM_END ? Z_OK : s->z_err;
+}
+#endif /* NO_GZCOMPRESS */
+
+/* ===========================================================================
+      Sets the starting position for the next gzread or gzwrite on the given
+   compressed file. The offset represents a number of bytes in the
+      gzseek returns the resulting offset location as measured in bytes from
+   the beginning of the uncompressed stream, or -1 in case of error.
+      SEEK_END is not implemented, returns error.
+      In this version of the library, gzseek can be extremely slow.
+*/
+z_off_t ZEXPORT gzseek (file, offset, whence)
+    gzFile file;
+    z_off_t offset;
+    int whence;
+{
+    gz_stream *s = (gz_stream*)file;
+
+    if (s == NULL || whence == SEEK_END ||
+        s->z_err == Z_ERRNO || s->z_err == Z_DATA_ERROR) {
+        return -1L;
+    }
+
+    if (s->mode == 'w') {
+#ifdef NO_GZCOMPRESS
+        return -1L;
+#else
+        if (whence == SEEK_SET) {
+            offset -= s->in;
+        }
+        if (offset < 0) return -1L;
+
+        /* At this point, offset is the number of zero bytes to write. */
+        if (s->inbuf == Z_NULL) {
+            s->inbuf = (Byte*)ALLOC(Z_BUFSIZE); /* for seeking */
+            if (s->inbuf == Z_NULL) return -1L;
+            zmemzero(s->inbuf, Z_BUFSIZE);
+        }
+        while (offset > 0)  {
+            uInt size = Z_BUFSIZE;
+            if (offset < Z_BUFSIZE) size = (uInt)offset;
+
+            size = gzwrite(file, s->inbuf, size);
+            if (size == 0) return -1L;
+
+            offset -= size;
+        }
+        return s->in;
+#endif
+    }
+    /* Rest of function is for reading only */
+
+    /* compute absolute position */
+    if (whence == SEEK_CUR) {
+        offset += s->out;
+    }
+    if (offset < 0) return -1L;
+
+    if (s->transparent) {
+        /* map to fseek */
+        s->back = EOF;
+        s->stream.avail_in = 0;
+        s->stream.next_in = s->inbuf;
+        if (fseek(s->file, offset, SEEK_SET) < 0) return -1L;
+
+        s->in = s->out = offset;
+        return offset;
+    }
+
+    /* For a negative seek, rewind and use positive seek */
+    if (offset >= s->out) {
+        offset -= s->out;
+    } else if (gzrewind(file) < 0) {
+        return -1L;
+    }
+    /* offset is now the number of bytes to skip. */
+
+    if (offset != 0 && s->outbuf == Z_NULL) {
+        s->outbuf = (Byte*)ALLOC(Z_BUFSIZE);
+        if (s->outbuf == Z_NULL) return -1L;
+    }
+    if (offset && s->back != EOF) {
+        s->back = EOF;
+        s->out++;
+        offset--;
+        if (s->last) s->z_err = Z_STREAM_END;
+    }
+    while (offset > 0)  {
+        int size = Z_BUFSIZE;
+        if (offset < Z_BUFSIZE) size = (int)offset;
+
+        size = gzread(file, s->outbuf, (uInt)size);
+        if (size <= 0) return -1L;
+        offset -= size;
+    }
+    return s->out;
+}
+
+/* ===========================================================================
+     Rewinds input file.
+*/
+int ZEXPORT gzrewind (file)
+    gzFile file;
+{
+    gz_stream *s = (gz_stream*)file;
+
+    if (s == NULL || s->mode != 'r') return -1;
+
+    s->z_err = Z_OK;
+    s->z_eof = 0;
+    s->back = EOF;
+    s->stream.avail_in = 0;
+    s->stream.next_in = s->inbuf;
+    s->crc = crc32(0L, Z_NULL, 0);
+    if (!s->transparent) (void)inflateReset(&s->stream);
+    s->in = 0;
+    s->out = 0;
+    return fseek(s->file, s->start, SEEK_SET);
+}
+
+/* ===========================================================================
+     Returns the starting position for the next gzread or gzwrite on the
+   given compressed file. This position represents a number of bytes in the
+   uncompressed data stream.
+*/
+z_off_t ZEXPORT gztell (file)
+    gzFile file;
+{
+    return gzseek(file, 0L, SEEK_CUR);
+}
+
+/* ===========================================================================
+     Returns 1 when EOF has previously been detected reading the given
+   input stream, otherwise zero.
+*/
+int ZEXPORT gzeof (file)
+    gzFile file;
+{
+    gz_stream *s = (gz_stream*)file;
+
+    /* With concatenated compressed files that can have embedded
+     * crc trailers, z_eof is no longer the only/best indicator of EOF
+     * on a gz_stream. Handle end-of-stream error explicitly here.
+     */
+    if (s == NULL || s->mode != 'r') return 0;
+    if (s->z_eof) return 1;
+    return s->z_err == Z_STREAM_END;
+}
+
+/* ===========================================================================
+     Returns 1 if reading and doing so transparently, otherwise zero.
+*/
+int ZEXPORT gzdirect (file)
+    gzFile file;
+{
+    gz_stream *s = (gz_stream*)file;
+
+    if (s == NULL || s->mode != 'r') return 0;
+    return s->transparent;
+}
+
+/* ===========================================================================
+   Outputs a long in LSB order to the given file
+*/
+local void putLong (file, x)
+    FILE *file;
+    uLong x;
+{
+    int n;
+    for (n = 0; n < 4; n++) {
+        fputc((int)(x & 0xff), file);
+        x >>= 8;
+    }
+}
+
+/* ===========================================================================
+   Reads a long in LSB order from the given gz_stream. Sets z_err in case
+   of error.
+*/
+local uLong getLong (s)
+    gz_stream *s;
+{
+    uLong x = (uLong)get_byte(s);
+    int c;
+
+    x += ((uLong)get_byte(s))<<8;
+    x += ((uLong)get_byte(s))<<16;
+    c = get_byte(s);
+    if (c == EOF) s->z_err = Z_DATA_ERROR;
+    x += ((uLong)c)<<24;
+    return x;
+}
+
+/* ===========================================================================
+     Flushes all pending output if necessary, closes the compressed file
+   and deallocates all the (de)compression state.
+*/
+int ZEXPORT gzclose (file)
+    gzFile file;
+{
+    gz_stream *s = (gz_stream*)file;
+
+    if (s == NULL) return Z_STREAM_ERROR;
+
+    if (s->mode == 'w') {
+#ifdef NO_GZCOMPRESS
+        return Z_STREAM_ERROR;
+#else
+        if (do_flush (file, Z_FINISH) != Z_OK)
+            return destroy((gz_stream*)file);
+
+        putLong (s->file, s->crc);
+        putLong (s->file, (uLong)(s->in & 0xffffffff));
+#endif
+    }
+    return destroy((gz_stream*)file);
+}
+
+#ifdef STDC
+#  define zstrerror(errnum) strerror(errnum)
+#else
+#  define zstrerror(errnum) ""
+#endif
+
+/* ===========================================================================
+     Returns the error message for the last error which occurred on the
+   given compressed file. errnum is set to zlib error number. If an
+   error occurred in the file system and not in the compression library,
+   errnum is set to Z_ERRNO and the application may consult errno
+   to get the exact error code.
+*/
+const char * ZEXPORT gzerror (file, errnum)
+    gzFile file;
+    int *errnum;
+{
+    char *m;
+    gz_stream *s = (gz_stream*)file;
+
+    if (s == NULL) {
+        *errnum = Z_STREAM_ERROR;
+        return (const char*)ERR_MSG(Z_STREAM_ERROR);
+    }
+    *errnum = s->z_err;
+    if (*errnum == Z_OK) return (const char*)"";
+
+    m = (char*)(*errnum == Z_ERRNO ? zstrerror(errno) : s->stream.msg);
+
+    if (m == NULL || *m == '\0') m = (char*)ERR_MSG(s->z_err);
+
+    TRYFREE(s->msg);
+    s->msg = (char*)ALLOC(strlen(s->path) + strlen(m) + 3);
+    if (s->msg == Z_NULL) return (const char*)ERR_MSG(Z_MEM_ERROR);
+    strcpy(s->msg, s->path);
+    strcat(s->msg, ": ");
+    strcat(s->msg, m);
+    return (const char*)s->msg;
+}
+
+/* ===========================================================================
+     Clear the error and end-of-file flags, and do the same for the real file.
+*/
+void ZEXPORT gzclearerr (file)
+    gzFile file;
+{
+    gz_stream *s = (gz_stream*)file;
+
+    if (s == NULL) return;
+    if (s->z_err != Z_STREAM_END) s->z_err = Z_OK;
+    s->z_eof = 0;
+    /* klibc hack */
+    /* clearerr(s->file); */
+}
diff --git a/usr/klibc/zlib/infback.c b/usr/klibc/zlib/infback.c
new file mode 100644
index 0000000..455dbc9
--- /dev/null
+++ b/usr/klibc/zlib/infback.c
@@ -0,0 +1,623 @@
+/* infback.c -- inflate using a call-back interface
+ * Copyright (C) 1995-2005 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/*
+   This code is largely copied from inflate.c.  Normally either infback.o or
+   inflate.o would be linked into an application--not both.  The interface
+   with inffast.c is retained so that optimized assembler-coded versions of
+   inflate_fast() can be used with either inflate.c or infback.c.
+ */
+
+#include "zutil.h"
+#include "inftrees.h"
+#include "inflate.h"
+#include "inffast.h"
+
+/* function prototypes */
+local void fixedtables OF((struct inflate_state FAR *state));
+
+/*
+   strm provides memory allocation functions in zalloc and zfree, or
+   Z_NULL to use the library memory allocation functions.
+
+   windowBits is in the range 8..15, and window is a user-supplied
+   window and output buffer that is 2**windowBits bytes.
+ */
+int ZEXPORT inflateBackInit_(strm, windowBits, window, version, stream_size)
+z_streamp strm;
+int windowBits;
+unsigned char FAR *window;
+const char *version;
+int stream_size;
+{
+    struct inflate_state FAR *state;
+
+    if (version == Z_NULL || version[0] != ZLIB_VERSION[0] ||
+        stream_size != (int)(sizeof(z_stream)))
+        return Z_VERSION_ERROR;
+    if (strm == Z_NULL || window == Z_NULL ||
+        windowBits < 8 || windowBits > 15)
+        return Z_STREAM_ERROR;
+    strm->msg = Z_NULL;                 /* in case we return an error */
+    if (strm->zalloc == (alloc_func)0) {
+        strm->zalloc = zcalloc;
+        strm->opaque = (voidpf)0;
+    }
+    if (strm->zfree == (free_func)0) strm->zfree = zcfree;
+    state = (struct inflate_state FAR *)ZALLOC(strm, 1,
+                                               sizeof(struct inflate_state));
+    if (state == Z_NULL) return Z_MEM_ERROR;
+    Tracev((stderr, "inflate: allocated\n"));
+    strm->state = (struct internal_state FAR *)state;
+    state->dmax = 32768U;
+    state->wbits = windowBits;
+    state->wsize = 1U << windowBits;
+    state->window = window;
+    state->write = 0;
+    state->whave = 0;
+    return Z_OK;
+}
+
+/*
+   Return state with length and distance decoding tables and index sizes set to
+   fixed code decoding.  Normally this returns fixed tables from inffixed.h.
+   If BUILDFIXED is defined, then instead this routine builds the tables the
+   first time it's called, and returns those tables the first time and
+   thereafter.  This reduces the size of the code by about 2K bytes, in
+   exchange for a little execution time.  However, BUILDFIXED should not be
+   used for threaded applications, since the rewriting of the tables and virgin
+   may not be thread-safe.
+ */
+local void fixedtables(state)
+struct inflate_state FAR *state;
+{
+#ifdef BUILDFIXED
+    static int virgin = 1;
+    static code *lenfix, *distfix;
+    static code fixed[544];
+
+    /* build fixed huffman tables if first call (may not be thread safe) */
+    if (virgin) {
+        unsigned sym, bits;
+        static code *next;
+
+        /* literal/length table */
+        sym = 0;
+        while (sym < 144) state->lens[sym++] = 8;
+        while (sym < 256) state->lens[sym++] = 9;
+        while (sym < 280) state->lens[sym++] = 7;
+        while (sym < 288) state->lens[sym++] = 8;
+        next = fixed;
+        lenfix = next;
+        bits = 9;
+        inflate_table(LENS, state->lens, 288, &(next), &(bits), state->work);
+
+        /* distance table */
+        sym = 0;
+        while (sym < 32) state->lens[sym++] = 5;
+        distfix = next;
+        bits = 5;
+        inflate_table(DISTS, state->lens, 32, &(next), &(bits), state->work);
+
+        /* do this just once */
+        virgin = 0;
+    }
+#else /* !BUILDFIXED */
+#   include "inffixed.h"
+#endif /* BUILDFIXED */
+    state->lencode = lenfix;
+    state->lenbits = 9;
+    state->distcode = distfix;
+    state->distbits = 5;
+}
+
+/* Macros for inflateBack(): */
+
+/* Load returned state from inflate_fast() */
+#define LOAD() \
+    do { \
+        put = strm->next_out; \
+        left = strm->avail_out; \
+        next = strm->next_in; \
+        have = strm->avail_in; \
+        hold = state->hold; \
+        bits = state->bits; \
+    } while (0)
+
+/* Set state from registers for inflate_fast() */
+#define RESTORE() \
+    do { \
+        strm->next_out = put; \
+        strm->avail_out = left; \
+        strm->next_in = next; \
+        strm->avail_in = have; \
+        state->hold = hold; \
+        state->bits = bits; \
+    } while (0)
+
+/* Clear the input bit accumulator */
+#define INITBITS() \
+    do { \
+        hold = 0; \
+        bits = 0; \
+    } while (0)
+
+/* Assure that some input is available.  If input is requested, but denied,
+   then return a Z_BUF_ERROR from inflateBack(). */
+#define PULL() \
+    do { \
+        if (have == 0) { \
+            have = in(in_desc, &next); \
+            if (have == 0) { \
+                next = Z_NULL; \
+                ret = Z_BUF_ERROR; \
+                goto inf_leave; \
+            } \
+        } \
+    } while (0)
+
+/* Get a byte of input into the bit accumulator, or return from inflateBack()
+   with an error if there is no input available. */
+#define PULLBYTE() \
+    do { \
+        PULL(); \
+        have--; \
+        hold += (unsigned long)(*next++) << bits; \
+        bits += 8; \
+    } while (0)
+
+/* Assure that there are at least n bits in the bit accumulator.  If there is
+   not enough available input to do that, then return from inflateBack() with
+   an error. */
+#define NEEDBITS(n) \
+    do { \
+        while (bits < (unsigned)(n)) \
+            PULLBYTE(); \
+    } while (0)
+
+/* Return the low n bits of the bit accumulator (n < 16) */
+#define BITS(n) \
+    ((unsigned)hold & ((1U << (n)) - 1))
+
+/* Remove n bits from the bit accumulator */
+#define DROPBITS(n) \
+    do { \
+        hold >>= (n); \
+        bits -= (unsigned)(n); \
+    } while (0)
+
+/* Remove zero to seven bits as needed to go to a byte boundary */
+#define BYTEBITS() \
+    do { \
+        hold >>= bits & 7; \
+        bits -= bits & 7; \
+    } while (0)
+
+/* Assure that some output space is available, by writing out the window
+   if it's full.  If the write fails, return from inflateBack() with a
+   Z_BUF_ERROR. */
+#define ROOM() \
+    do { \
+        if (left == 0) { \
+            put = state->window; \
+            left = state->wsize; \
+            state->whave = left; \
+            if (out(out_desc, put, left)) { \
+                ret = Z_BUF_ERROR; \
+                goto inf_leave; \
+            } \
+        } \
+    } while (0)
+
+/*
+   strm provides the memory allocation functions and window buffer on input,
+   and provides information on the unused input on return.  For Z_DATA_ERROR
+   returns, strm will also provide an error message.
+
+   in() and out() are the call-back input and output functions.  When
+   inflateBack() needs more input, it calls in().  When inflateBack() has
+   filled the window with output, or when it completes with data in the
+   window, it calls out() to write out the data.  The application must not
+   change the provided input until in() is called again or inflateBack()
+   returns.  The application must not change the window/output buffer until
+   inflateBack() returns.
+
+   in() and out() are called with a descriptor parameter provided in the
+   inflateBack() call.  This parameter can be a structure that provides the
+   information required to do the read or write, as well as accumulated
+   information on the input and output such as totals and check values.
+
+   in() should return zero on failure.  out() should return non-zero on
+   failure.  If either in() or out() fails, than inflateBack() returns a
+   Z_BUF_ERROR.  strm->next_in can be checked for Z_NULL to see whether it
+   was in() or out() that caused in the error.  Otherwise,  inflateBack()
+   returns Z_STREAM_END on success, Z_DATA_ERROR for an deflate format
+   error, or Z_MEM_ERROR if it could not allocate memory for the state.
+   inflateBack() can also return Z_STREAM_ERROR if the input parameters
+   are not correct, i.e. strm is Z_NULL or the state was not initialized.
+ */
+int ZEXPORT inflateBack(strm, in, in_desc, out, out_desc)
+z_streamp strm;
+in_func in;
+void FAR *in_desc;
+out_func out;
+void FAR *out_desc;
+{
+    struct inflate_state FAR *state;
+    unsigned char FAR *next;    /* next input */
+    unsigned char FAR *put;     /* next output */
+    unsigned have, left;        /* available input and output */
+    unsigned long hold;         /* bit buffer */
+    unsigned bits;              /* bits in bit buffer */
+    unsigned copy;              /* number of stored or match bytes to copy */
+    unsigned char FAR *from;    /* where to copy match bytes from */
+    code this;                  /* current decoding table entry */
+    code last;                  /* parent table entry */
+    unsigned len;               /* length to copy for repeats, bits to drop */
+    int ret;                    /* return code */
+    static const unsigned short order[19] = /* permutation of code lengths */
+        {16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15};
+
+    /* Check that the strm exists and that the state was initialized */
+    if (strm == Z_NULL || strm->state == Z_NULL)
+        return Z_STREAM_ERROR;
+    state = (struct inflate_state FAR *)strm->state;
+
+    /* Reset the state */
+    strm->msg = Z_NULL;
+    state->mode = TYPE;
+    state->last = 0;
+    state->whave = 0;
+    next = strm->next_in;
+    have = next != Z_NULL ? strm->avail_in : 0;
+    hold = 0;
+    bits = 0;
+    put = state->window;
+    left = state->wsize;
+
+    /* Inflate until end of block marked as last */
+    for (;;)
+        switch (state->mode) {
+        case TYPE:
+            /* determine and dispatch block type */
+            if (state->last) {
+                BYTEBITS();
+                state->mode = DONE;
+                break;
+            }
+            NEEDBITS(3);
+            state->last = BITS(1);
+            DROPBITS(1);
+            switch (BITS(2)) {
+            case 0:                             /* stored block */
+                Tracev((stderr, "inflate:     stored block%s\n",
+                        state->last ? " (last)" : ""));
+                state->mode = STORED;
+                break;
+            case 1:                             /* fixed block */
+                fixedtables(state);
+                Tracev((stderr, "inflate:     fixed codes block%s\n",
+                        state->last ? " (last)" : ""));
+                state->mode = LEN;              /* decode codes */
+                break;
+            case 2:                             /* dynamic block */
+                Tracev((stderr, "inflate:     dynamic codes block%s\n",
+                        state->last ? " (last)" : ""));
+                state->mode = TABLE;
+                break;
+            case 3:
+                strm->msg = (char *)"invalid block type";
+                state->mode = BAD;
+            }
+            DROPBITS(2);
+            break;
+
+        case STORED:
+            /* get and verify stored block length */
+            BYTEBITS();                         /* go to byte boundary */
+            NEEDBITS(32);
+            if ((hold & 0xffff) != ((hold >> 16) ^ 0xffff)) {
+                strm->msg = (char *)"invalid stored block lengths";
+                state->mode = BAD;
+                break;
+            }
+            state->length = (unsigned)hold & 0xffff;
+            Tracev((stderr, "inflate:       stored length %u\n",
+                    state->length));
+            INITBITS();
+
+            /* copy stored block from input to output */
+            while (state->length != 0) {
+                copy = state->length;
+                PULL();
+                ROOM();
+                if (copy > have) copy = have;
+                if (copy > left) copy = left;
+                zmemcpy(put, next, copy);
+                have -= copy;
+                next += copy;
+                left -= copy;
+                put += copy;
+                state->length -= copy;
+            }
+            Tracev((stderr, "inflate:       stored end\n"));
+            state->mode = TYPE;
+            break;
+
+        case TABLE:
+            /* get dynamic table entries descriptor */
+            NEEDBITS(14);
+            state->nlen = BITS(5) + 257;
+            DROPBITS(5);
+            state->ndist = BITS(5) + 1;
+            DROPBITS(5);
+            state->ncode = BITS(4) + 4;
+            DROPBITS(4);
+#ifndef PKZIP_BUG_WORKAROUND
+            if (state->nlen > 286 || state->ndist > 30) {
+                strm->msg = (char *)"too many length or distance symbols";
+                state->mode = BAD;
+                break;
+            }
+#endif
+            Tracev((stderr, "inflate:       table sizes ok\n"));
+
+            /* get code length code lengths (not a typo) */
+            state->have = 0;
+            while (state->have < state->ncode) {
+                NEEDBITS(3);
+                state->lens[order[state->have++]] = (unsigned short)BITS(3);
+                DROPBITS(3);
+            }
+            while (state->have < 19)
+                state->lens[order[state->have++]] = 0;
+            state->next = state->codes;
+            state->lencode = (code const FAR *)(state->next);
+            state->lenbits = 7;
+            ret = inflate_table(CODES, state->lens, 19, &(state->next),
+                                &(state->lenbits), state->work);
+            if (ret) {
+                strm->msg = (char *)"invalid code lengths set";
+                state->mode = BAD;
+                break;
+            }
+            Tracev((stderr, "inflate:       code lengths ok\n"));
+
+            /* get length and distance code code lengths */
+            state->have = 0;
+            while (state->have < state->nlen + state->ndist) {
+                for (;;) {
+                    this = state->lencode[BITS(state->lenbits)];
+                    if ((unsigned)(this.bits) <= bits) break;
+                    PULLBYTE();
+                }
+                if (this.val < 16) {
+                    NEEDBITS(this.bits);
+                    DROPBITS(this.bits);
+                    state->lens[state->have++] = this.val;
+                }
+                else {
+                    if (this.val == 16) {
+                        NEEDBITS(this.bits + 2);
+                        DROPBITS(this.bits);
+                        if (state->have == 0) {
+                            strm->msg = (char *)"invalid bit length repeat";
+                            state->mode = BAD;
+                            break;
+                        }
+                        len = (unsigned)(state->lens[state->have - 1]);
+                        copy = 3 + BITS(2);
+                        DROPBITS(2);
+                    }
+                    else if (this.val == 17) {
+                        NEEDBITS(this.bits + 3);
+                        DROPBITS(this.bits);
+                        len = 0;
+                        copy = 3 + BITS(3);
+                        DROPBITS(3);
+                    }
+                    else {
+                        NEEDBITS(this.bits + 7);
+                        DROPBITS(this.bits);
+                        len = 0;
+                        copy = 11 + BITS(7);
+                        DROPBITS(7);
+                    }
+                    if (state->have + copy > state->nlen + state->ndist) {
+                        strm->msg = (char *)"invalid bit length repeat";
+                        state->mode = BAD;
+                        break;
+                    }
+                    while (copy--)
+                        state->lens[state->have++] = (unsigned short)len;
+                }
+            }
+
+            /* handle error breaks in while */
+            if (state->mode == BAD) break;
+
+            /* build code tables */
+            state->next = state->codes;
+            state->lencode = (code const FAR *)(state->next);
+            state->lenbits = 9;
+            ret = inflate_table(LENS, state->lens, state->nlen, &(state->next),
+                                &(state->lenbits), state->work);
+            if (ret) {
+                strm->msg = (char *)"invalid literal/lengths set";
+                state->mode = BAD;
+                break;
+            }
+            state->distcode = (code const FAR *)(state->next);
+            state->distbits = 6;
+            ret = inflate_table(DISTS, state->lens + state->nlen, state->ndist,
+                            &(state->next), &(state->distbits), state->work);
+            if (ret) {
+                strm->msg = (char *)"invalid distances set";
+                state->mode = BAD;
+                break;
+            }
+            Tracev((stderr, "inflate:       codes ok\n"));
+            state->mode = LEN;
+
+        case LEN:
+            /* use inflate_fast() if we have enough input and output */
+            if (have >= 6 && left >= 258) {
+                RESTORE();
+                if (state->whave < state->wsize)
+                    state->whave = state->wsize - left;
+                inflate_fast(strm, state->wsize);
+                LOAD();
+                break;
+            }
+
+            /* get a literal, length, or end-of-block code */
+            for (;;) {
+                this = state->lencode[BITS(state->lenbits)];
+                if ((unsigned)(this.bits) <= bits) break;
+                PULLBYTE();
+            }
+            if (this.op && (this.op & 0xf0) == 0) {
+                last = this;
+                for (;;) {
+                    this = state->lencode[last.val +
+                            (BITS(last.bits + last.op) >> last.bits)];
+                    if ((unsigned)(last.bits + this.bits) <= bits) break;
+                    PULLBYTE();
+                }
+                DROPBITS(last.bits);
+            }
+            DROPBITS(this.bits);
+            state->length = (unsigned)this.val;
+
+            /* process literal */
+            if (this.op == 0) {
+                Tracevv((stderr, this.val >= 0x20 && this.val < 0x7f ?
+                        "inflate:         literal '%c'\n" :
+                        "inflate:         literal 0x%02x\n", this.val));
+                ROOM();
+                *put++ = (unsigned char)(state->length);
+                left--;
+                state->mode = LEN;
+                break;
+            }
+
+            /* process end of block */
+            if (this.op & 32) {
+                Tracevv((stderr, "inflate:         end of block\n"));
+                state->mode = TYPE;
+                break;
+            }
+
+            /* invalid code */
+            if (this.op & 64) {
+                strm->msg = (char *)"invalid literal/length code";
+                state->mode = BAD;
+                break;
+            }
+
+            /* length code -- get extra bits, if any */
+            state->extra = (unsigned)(this.op) & 15;
+            if (state->extra != 0) {
+                NEEDBITS(state->extra);
+                state->length += BITS(state->extra);
+                DROPBITS(state->extra);
+            }
+            Tracevv((stderr, "inflate:         length %u\n", state->length));
+
+            /* get distance code */
+            for (;;) {
+                this = state->distcode[BITS(state->distbits)];
+                if ((unsigned)(this.bits) <= bits) break;
+                PULLBYTE();
+            }
+            if ((this.op & 0xf0) == 0) {
+                last = this;
+                for (;;) {
+                    this = state->distcode[last.val +
+                            (BITS(last.bits + last.op) >> last.bits)];
+                    if ((unsigned)(last.bits + this.bits) <= bits) break;
+                    PULLBYTE();
+                }
+                DROPBITS(last.bits);
+            }
+            DROPBITS(this.bits);
+            if (this.op & 64) {
+                strm->msg = (char *)"invalid distance code";
+                state->mode = BAD;
+                break;
+            }
+            state->offset = (unsigned)this.val;
+
+            /* get distance extra bits, if any */
+            state->extra = (unsigned)(this.op) & 15;
+            if (state->extra != 0) {
+                NEEDBITS(state->extra);
+                state->offset += BITS(state->extra);
+                DROPBITS(state->extra);
+            }
+            if (state->offset > state->wsize - (state->whave < state->wsize ?
+                                                left : 0)) {
+                strm->msg = (char *)"invalid distance too far back";
+                state->mode = BAD;
+                break;
+            }
+            Tracevv((stderr, "inflate:         distance %u\n", state->offset));
+
+            /* copy match from window to output */
+            do {
+                ROOM();
+                copy = state->wsize - state->offset;
+                if (copy < left) {
+                    from = put + copy;
+                    copy = left - copy;
+                }
+                else {
+                    from = put - state->offset;
+                    copy = left;
+                }
+                if (copy > state->length) copy = state->length;
+                state->length -= copy;
+                left -= copy;
+                do {
+                    *put++ = *from++;
+                } while (--copy);
+            } while (state->length != 0);
+            break;
+
+        case DONE:
+            /* inflate stream terminated properly -- write leftover output */
+            ret = Z_STREAM_END;
+            if (left < state->wsize) {
+                if (out(out_desc, state->window, state->wsize - left))
+                    ret = Z_BUF_ERROR;
+            }
+            goto inf_leave;
+
+        case BAD:
+            ret = Z_DATA_ERROR;
+            goto inf_leave;
+
+        default:                /* can't happen, but makes compilers happy */
+            ret = Z_STREAM_ERROR;
+            goto inf_leave;
+        }
+
+    /* Return unused input */
+  inf_leave:
+    strm->next_in = next;
+    strm->avail_in = have;
+    return ret;
+}
+
+int ZEXPORT inflateBackEnd(strm)
+z_streamp strm;
+{
+    if (strm == Z_NULL || strm->state == Z_NULL || strm->zfree == (free_func)0)
+        return Z_STREAM_ERROR;
+    ZFREE(strm, strm->state);
+    strm->state = Z_NULL;
+    Tracev((stderr, "inflate: end\n"));
+    return Z_OK;
+}
diff --git a/usr/klibc/zlib/inffast.c b/usr/klibc/zlib/inffast.c
new file mode 100644
index 0000000..bbee92e
--- /dev/null
+++ b/usr/klibc/zlib/inffast.c
@@ -0,0 +1,318 @@
+/* inffast.c -- fast decoding
+ * Copyright (C) 1995-2004 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+#include "zutil.h"
+#include "inftrees.h"
+#include "inflate.h"
+#include "inffast.h"
+
+#ifndef ASMINF
+
+/* Allow machine dependent optimization for post-increment or pre-increment.
+   Based on testing to date,
+   Pre-increment preferred for:
+   - PowerPC G3 (Adler)
+   - MIPS R5000 (Randers-Pehrson)
+   Post-increment preferred for:
+   - none
+   No measurable difference:
+   - Pentium III (Anderson)
+   - M68060 (Nikl)
+ */
+#ifdef POSTINC
+#  define OFF 0
+#  define PUP(a) *(a)++
+#else
+#  define OFF 1
+#  define PUP(a) *++(a)
+#endif
+
+/*
+   Decode literal, length, and distance codes and write out the resulting
+   literal and match bytes until either not enough input or output is
+   available, an end-of-block is encountered, or a data error is encountered.
+   When large enough input and output buffers are supplied to inflate(), for
+   example, a 16K input buffer and a 64K output buffer, more than 95% of the
+   inflate execution time is spent in this routine.
+
+   Entry assumptions:
+
+        state->mode == LEN
+        strm->avail_in >= 6
+        strm->avail_out >= 258
+        start >= strm->avail_out
+        state->bits < 8
+
+   On return, state->mode is one of:
+
+        LEN -- ran out of enough output space or enough available input
+        TYPE -- reached end of block code, inflate() to interpret next block
+        BAD -- error in block data
+
+   Notes:
+
+    - The maximum input bits used by a length/distance pair is 15 bits for the
+      length code, 5 bits for the length extra, 15 bits for the distance code,
+      and 13 bits for the distance extra.  This totals 48 bits, or six bytes.
+      Therefore if strm->avail_in >= 6, then there is enough input to avoid
+      checking for available input while decoding.
+
+    - The maximum bytes that a single length/distance pair can output is 258
+      bytes, which is the maximum length that can be coded.  inflate_fast()
+      requires strm->avail_out >= 258 for each loop to avoid checking for
+      output space.
+ */
+void inflate_fast(strm, start)
+z_streamp strm;
+unsigned start;         /* inflate()'s starting value for strm->avail_out */
+{
+    struct inflate_state FAR *state;
+    unsigned char FAR *in;      /* local strm->next_in */
+    unsigned char FAR *last;    /* while in < last, enough input available */
+    unsigned char FAR *out;     /* local strm->next_out */
+    unsigned char FAR *beg;     /* inflate()'s initial strm->next_out */
+    unsigned char FAR *end;     /* while out < end, enough space available */
+#ifdef INFLATE_STRICT
+    unsigned dmax;              /* maximum distance from zlib header */
+#endif
+    unsigned wsize;             /* window size or zero if not using window */
+    unsigned whave;             /* valid bytes in the window */
+    unsigned write;             /* window write index */
+    unsigned char FAR *window;  /* allocated sliding window, if wsize != 0 */
+    unsigned long hold;         /* local strm->hold */
+    unsigned bits;              /* local strm->bits */
+    code const FAR *lcode;      /* local strm->lencode */
+    code const FAR *dcode;      /* local strm->distcode */
+    unsigned lmask;             /* mask for first level of length codes */
+    unsigned dmask;             /* mask for first level of distance codes */
+    code this;                  /* retrieved table entry */
+    unsigned op;                /* code bits, operation, extra bits, or */
+                                /*  window position, window bytes to copy */
+    unsigned len;               /* match length, unused bytes */
+    unsigned dist;              /* match distance */
+    unsigned char FAR *from;    /* where to copy match from */
+
+    /* copy state to local variables */
+    state = (struct inflate_state FAR *)strm->state;
+    in = strm->next_in - OFF;
+    last = in + (strm->avail_in - 5);
+    out = strm->next_out - OFF;
+    beg = out - (start - strm->avail_out);
+    end = out + (strm->avail_out - 257);
+#ifdef INFLATE_STRICT
+    dmax = state->dmax;
+#endif
+    wsize = state->wsize;
+    whave = state->whave;
+    write = state->write;
+    window = state->window;
+    hold = state->hold;
+    bits = state->bits;
+    lcode = state->lencode;
+    dcode = state->distcode;
+    lmask = (1U << state->lenbits) - 1;
+    dmask = (1U << state->distbits) - 1;
+
+    /* decode literals and length/distances until end-of-block or not enough
+       input data or output space */
+    do {
+        if (bits < 15) {
+            hold += (unsigned long)(PUP(in)) << bits;
+            bits += 8;
+            hold += (unsigned long)(PUP(in)) << bits;
+            bits += 8;
+        }
+        this = lcode[hold & lmask];
+      dolen:
+        op = (unsigned)(this.bits);
+        hold >>= op;
+        bits -= op;
+        op = (unsigned)(this.op);
+        if (op == 0) {                          /* literal */
+            Tracevv((stderr, this.val >= 0x20 && this.val < 0x7f ?
+                    "inflate:         literal '%c'\n" :
+                    "inflate:         literal 0x%02x\n", this.val));
+            PUP(out) = (unsigned char)(this.val);
+        }
+        else if (op & 16) {                     /* length base */
+            len = (unsigned)(this.val);
+            op &= 15;                           /* number of extra bits */
+            if (op) {
+                if (bits < op) {
+                    hold += (unsigned long)(PUP(in)) << bits;
+                    bits += 8;
+                }
+                len += (unsigned)hold & ((1U << op) - 1);
+                hold >>= op;
+                bits -= op;
+            }
+            Tracevv((stderr, "inflate:         length %u\n", len));
+            if (bits < 15) {
+                hold += (unsigned long)(PUP(in)) << bits;
+                bits += 8;
+                hold += (unsigned long)(PUP(in)) << bits;
+                bits += 8;
+            }
+            this = dcode[hold & dmask];
+          dodist:
+            op = (unsigned)(this.bits);
+            hold >>= op;
+            bits -= op;
+            op = (unsigned)(this.op);
+            if (op & 16) {                      /* distance base */
+                dist = (unsigned)(this.val);
+                op &= 15;                       /* number of extra bits */
+                if (bits < op) {
+                    hold += (unsigned long)(PUP(in)) << bits;
+                    bits += 8;
+                    if (bits < op) {
+                        hold += (unsigned long)(PUP(in)) << bits;
+                        bits += 8;
+                    }
+                }
+                dist += (unsigned)hold & ((1U << op) - 1);
+#ifdef INFLATE_STRICT
+                if (dist > dmax) {
+                    strm->msg = (char *)"invalid distance too far back";
+                    state->mode = BAD;
+                    break;
+                }
+#endif
+                hold >>= op;
+                bits -= op;
+                Tracevv((stderr, "inflate:         distance %u\n", dist));
+                op = (unsigned)(out - beg);     /* max distance in output */
+                if (dist > op) {                /* see if copy from window */
+                    op = dist - op;             /* distance back in window */
+                    if (op > whave) {
+                        strm->msg = (char *)"invalid distance too far back";
+                        state->mode = BAD;
+                        break;
+                    }
+                    from = window - OFF;
+                    if (write == 0) {           /* very common case */
+                        from += wsize - op;
+                        if (op < len) {         /* some from window */
+                            len -= op;
+                            do {
+                                PUP(out) = PUP(from);
+                            } while (--op);
+                            from = out - dist;  /* rest from output */
+                        }
+                    }
+                    else if (write < op) {      /* wrap around window */
+                        from += wsize + write - op;
+                        op -= write;
+                        if (op < len) {         /* some from end of window */
+                            len -= op;
+                            do {
+                                PUP(out) = PUP(from);
+                            } while (--op);
+                            from = window - OFF;
+                            if (write < len) {  /* some from start of window */
+                                op = write;
+                                len -= op;
+                                do {
+                                    PUP(out) = PUP(from);
+                                } while (--op);
+                                from = out - dist;      /* rest from output */
+                            }
+                        }
+                    }
+                    else {                      /* contiguous in window */
+                        from += write - op;
+                        if (op < len) {         /* some from window */
+                            len -= op;
+                            do {
+                                PUP(out) = PUP(from);
+                            } while (--op);
+                            from = out - dist;  /* rest from output */
+                        }
+                    }
+                    while (len > 2) {
+                        PUP(out) = PUP(from);
+                        PUP(out) = PUP(from);
+                        PUP(out) = PUP(from);
+                        len -= 3;
+                    }
+                    if (len) {
+                        PUP(out) = PUP(from);
+                        if (len > 1)
+                            PUP(out) = PUP(from);
+                    }
+                }
+                else {
+                    from = out - dist;          /* copy direct from output */
+                    do {                        /* minimum length is three */
+                        PUP(out) = PUP(from);
+                        PUP(out) = PUP(from);
+                        PUP(out) = PUP(from);
+                        len -= 3;
+                    } while (len > 2);
+                    if (len) {
+                        PUP(out) = PUP(from);
+                        if (len > 1)
+                            PUP(out) = PUP(from);
+                    }
+                }
+            }
+            else if ((op & 64) == 0) {          /* 2nd level distance code */
+                this = dcode[this.val + (hold & ((1U << op) - 1))];
+                goto dodist;
+            }
+            else {
+                strm->msg = (char *)"invalid distance code";
+                state->mode = BAD;
+                break;
+            }
+        }
+        else if ((op & 64) == 0) {              /* 2nd level length code */
+            this = lcode[this.val + (hold & ((1U << op) - 1))];
+            goto dolen;
+        }
+        else if (op & 32) {                     /* end-of-block */
+            Tracevv((stderr, "inflate:         end of block\n"));
+            state->mode = TYPE;
+            break;
+        }
+        else {
+            strm->msg = (char *)"invalid literal/length code";
+            state->mode = BAD;
+            break;
+        }
+    } while (in < last && out < end);
+
+    /* return unused bytes (on entry, bits < 8, so in won't go too far back) */
+    len = bits >> 3;
+    in -= len;
+    bits -= len << 3;
+    hold &= (1U << bits) - 1;
+
+    /* update state and return */
+    strm->next_in = in + OFF;
+    strm->next_out = out + OFF;
+    strm->avail_in = (unsigned)(in < last ? 5 + (last - in) : 5 - (in - last));
+    strm->avail_out = (unsigned)(out < end ?
+                                 257 + (end - out) : 257 - (out - end));
+    state->hold = hold;
+    state->bits = bits;
+    return;
+}
+
+/*
+   inflate_fast() speedups that turned out slower (on a PowerPC G3 750CXe):
+   - Using bit fields for code structure
+   - Different op definition to avoid & for extra bits (do & for table bits)
+   - Three separate decoding do-loops for direct, window, and write == 0
+   - Special case for distance > 1 copies to do overlapped load and store copy
+   - Explicit branch predictions (based on measured branch probabilities)
+   - Deferring match copy and interspersed it with decoding subsequent codes
+   - Swapping literal/length else
+   - Swapping window/direct else
+   - Larger unrolled copy loops (three is about right)
+   - Moving len -= 3 statement into middle of loop
+ */
+
+#endif /* !ASMINF */
diff --git a/usr/klibc/zlib/inffast.h b/usr/klibc/zlib/inffast.h
new file mode 100644
index 0000000..1e88d2d
--- /dev/null
+++ b/usr/klibc/zlib/inffast.h
@@ -0,0 +1,11 @@
+/* inffast.h -- header to use inffast.c
+ * Copyright (C) 1995-2003 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* WARNING: this file should *not* be used by applications. It is
+   part of the implementation of the compression library and is
+   subject to change. Applications should only use zlib.h.
+ */
+
+void inflate_fast OF((z_streamp strm, unsigned start));
diff --git a/usr/klibc/zlib/inffixed.h b/usr/klibc/zlib/inffixed.h
new file mode 100644
index 0000000..75ed4b5
--- /dev/null
+++ b/usr/klibc/zlib/inffixed.h
@@ -0,0 +1,94 @@
+    /* inffixed.h -- table for decoding fixed codes
+     * Generated automatically by makefixed().
+     */
+
+    /* WARNING: this file should *not* be used by applications. It
+       is part of the implementation of the compression library and
+       is subject to change. Applications should only use zlib.h.
+     */
+
+    static const code lenfix[512] = {
+        {96,7,0},{0,8,80},{0,8,16},{20,8,115},{18,7,31},{0,8,112},{0,8,48},
+        {0,9,192},{16,7,10},{0,8,96},{0,8,32},{0,9,160},{0,8,0},{0,8,128},
+        {0,8,64},{0,9,224},{16,7,6},{0,8,88},{0,8,24},{0,9,144},{19,7,59},
+        {0,8,120},{0,8,56},{0,9,208},{17,7,17},{0,8,104},{0,8,40},{0,9,176},
+        {0,8,8},{0,8,136},{0,8,72},{0,9,240},{16,7,4},{0,8,84},{0,8,20},
+        {21,8,227},{19,7,43},{0,8,116},{0,8,52},{0,9,200},{17,7,13},{0,8,100},
+        {0,8,36},{0,9,168},{0,8,4},{0,8,132},{0,8,68},{0,9,232},{16,7,8},
+        {0,8,92},{0,8,28},{0,9,152},{20,7,83},{0,8,124},{0,8,60},{0,9,216},
+        {18,7,23},{0,8,108},{0,8,44},{0,9,184},{0,8,12},{0,8,140},{0,8,76},
+        {0,9,248},{16,7,3},{0,8,82},{0,8,18},{21,8,163},{19,7,35},{0,8,114},
+        {0,8,50},{0,9,196},{17,7,11},{0,8,98},{0,8,34},{0,9,164},{0,8,2},
+        {0,8,130},{0,8,66},{0,9,228},{16,7,7},{0,8,90},{0,8,26},{0,9,148},
+        {20,7,67},{0,8,122},{0,8,58},{0,9,212},{18,7,19},{0,8,106},{0,8,42},
+        {0,9,180},{0,8,10},{0,8,138},{0,8,74},{0,9,244},{16,7,5},{0,8,86},
+        {0,8,22},{64,8,0},{19,7,51},{0,8,118},{0,8,54},{0,9,204},{17,7,15},
+        {0,8,102},{0,8,38},{0,9,172},{0,8,6},{0,8,134},{0,8,70},{0,9,236},
+        {16,7,9},{0,8,94},{0,8,30},{0,9,156},{20,7,99},{0,8,126},{0,8,62},
+        {0,9,220},{18,7,27},{0,8,110},{0,8,46},{0,9,188},{0,8,14},{0,8,142},
+        {0,8,78},{0,9,252},{96,7,0},{0,8,81},{0,8,17},{21,8,131},{18,7,31},
+        {0,8,113},{0,8,49},{0,9,194},{16,7,10},{0,8,97},{0,8,33},{0,9,162},
+        {0,8,1},{0,8,129},{0,8,65},{0,9,226},{16,7,6},{0,8,89},{0,8,25},
+        {0,9,146},{19,7,59},{0,8,121},{0,8,57},{0,9,210},{17,7,17},{0,8,105},
+        {0,8,41},{0,9,178},{0,8,9},{0,8,137},{0,8,73},{0,9,242},{16,7,4},
+        {0,8,85},{0,8,21},{16,8,258},{19,7,43},{0,8,117},{0,8,53},{0,9,202},
+        {17,7,13},{0,8,101},{0,8,37},{0,9,170},{0,8,5},{0,8,133},{0,8,69},
+        {0,9,234},{16,7,8},{0,8,93},{0,8,29},{0,9,154},{20,7,83},{0,8,125},
+        {0,8,61},{0,9,218},{18,7,23},{0,8,109},{0,8,45},{0,9,186},{0,8,13},
+        {0,8,141},{0,8,77},{0,9,250},{16,7,3},{0,8,83},{0,8,19},{21,8,195},
+        {19,7,35},{0,8,115},{0,8,51},{0,9,198},{17,7,11},{0,8,99},{0,8,35},
+        {0,9,166},{0,8,3},{0,8,131},{0,8,67},{0,9,230},{16,7,7},{0,8,91},
+        {0,8,27},{0,9,150},{20,7,67},{0,8,123},{0,8,59},{0,9,214},{18,7,19},
+        {0,8,107},{0,8,43},{0,9,182},{0,8,11},{0,8,139},{0,8,75},{0,9,246},
+        {16,7,5},{0,8,87},{0,8,23},{64,8,0},{19,7,51},{0,8,119},{0,8,55},
+        {0,9,206},{17,7,15},{0,8,103},{0,8,39},{0,9,174},{0,8,7},{0,8,135},
+        {0,8,71},{0,9,238},{16,7,9},{0,8,95},{0,8,31},{0,9,158},{20,7,99},
+        {0,8,127},{0,8,63},{0,9,222},{18,7,27},{0,8,111},{0,8,47},{0,9,190},
+        {0,8,15},{0,8,143},{0,8,79},{0,9,254},{96,7,0},{0,8,80},{0,8,16},
+        {20,8,115},{18,7,31},{0,8,112},{0,8,48},{0,9,193},{16,7,10},{0,8,96},
+        {0,8,32},{0,9,161},{0,8,0},{0,8,128},{0,8,64},{0,9,225},{16,7,6},
+        {0,8,88},{0,8,24},{0,9,145},{19,7,59},{0,8,120},{0,8,56},{0,9,209},
+        {17,7,17},{0,8,104},{0,8,40},{0,9,177},{0,8,8},{0,8,136},{0,8,72},
+        {0,9,241},{16,7,4},{0,8,84},{0,8,20},{21,8,227},{19,7,43},{0,8,116},
+        {0,8,52},{0,9,201},{17,7,13},{0,8,100},{0,8,36},{0,9,169},{0,8,4},
+        {0,8,132},{0,8,68},{0,9,233},{16,7,8},{0,8,92},{0,8,28},{0,9,153},
+        {20,7,83},{0,8,124},{0,8,60},{0,9,217},{18,7,23},{0,8,108},{0,8,44},
+        {0,9,185},{0,8,12},{0,8,140},{0,8,76},{0,9,249},{16,7,3},{0,8,82},
+        {0,8,18},{21,8,163},{19,7,35},{0,8,114},{0,8,50},{0,9,197},{17,7,11},
+        {0,8,98},{0,8,34},{0,9,165},{0,8,2},{0,8,130},{0,8,66},{0,9,229},
+        {16,7,7},{0,8,90},{0,8,26},{0,9,149},{20,7,67},{0,8,122},{0,8,58},
+        {0,9,213},{18,7,19},{0,8,106},{0,8,42},{0,9,181},{0,8,10},{0,8,138},
+        {0,8,74},{0,9,245},{16,7,5},{0,8,86},{0,8,22},{64,8,0},{19,7,51},
+        {0,8,118},{0,8,54},{0,9,205},{17,7,15},{0,8,102},{0,8,38},{0,9,173},
+        {0,8,6},{0,8,134},{0,8,70},{0,9,237},{16,7,9},{0,8,94},{0,8,30},
+        {0,9,157},{20,7,99},{0,8,126},{0,8,62},{0,9,221},{18,7,27},{0,8,110},
+        {0,8,46},{0,9,189},{0,8,14},{0,8,142},{0,8,78},{0,9,253},{96,7,0},
+        {0,8,81},{0,8,17},{21,8,131},{18,7,31},{0,8,113},{0,8,49},{0,9,195},
+        {16,7,10},{0,8,97},{0,8,33},{0,9,163},{0,8,1},{0,8,129},{0,8,65},
+        {0,9,227},{16,7,6},{0,8,89},{0,8,25},{0,9,147},{19,7,59},{0,8,121},
+        {0,8,57},{0,9,211},{17,7,17},{0,8,105},{0,8,41},{0,9,179},{0,8,9},
+        {0,8,137},{0,8,73},{0,9,243},{16,7,4},{0,8,85},{0,8,21},{16,8,258},
+        {19,7,43},{0,8,117},{0,8,53},{0,9,203},{17,7,13},{0,8,101},{0,8,37},
+        {0,9,171},{0,8,5},{0,8,133},{0,8,69},{0,9,235},{16,7,8},{0,8,93},
+        {0,8,29},{0,9,155},{20,7,83},{0,8,125},{0,8,61},{0,9,219},{18,7,23},
+        {0,8,109},{0,8,45},{0,9,187},{0,8,13},{0,8,141},{0,8,77},{0,9,251},
+        {16,7,3},{0,8,83},{0,8,19},{21,8,195},{19,7,35},{0,8,115},{0,8,51},
+        {0,9,199},{17,7,11},{0,8,99},{0,8,35},{0,9,167},{0,8,3},{0,8,131},
+        {0,8,67},{0,9,231},{16,7,7},{0,8,91},{0,8,27},{0,9,151},{20,7,67},
+        {0,8,123},{0,8,59},{0,9,215},{18,7,19},{0,8,107},{0,8,43},{0,9,183},
+        {0,8,11},{0,8,139},{0,8,75},{0,9,247},{16,7,5},{0,8,87},{0,8,23},
+        {64,8,0},{19,7,51},{0,8,119},{0,8,55},{0,9,207},{17,7,15},{0,8,103},
+        {0,8,39},{0,9,175},{0,8,7},{0,8,135},{0,8,71},{0,9,239},{16,7,9},
+        {0,8,95},{0,8,31},{0,9,159},{20,7,99},{0,8,127},{0,8,63},{0,9,223},
+        {18,7,27},{0,8,111},{0,8,47},{0,9,191},{0,8,15},{0,8,143},{0,8,79},
+        {0,9,255}
+    };
+
+    static const code distfix[32] = {
+        {16,5,1},{23,5,257},{19,5,17},{27,5,4097},{17,5,5},{25,5,1025},
+        {21,5,65},{29,5,16385},{16,5,3},{24,5,513},{20,5,33},{28,5,8193},
+        {18,5,9},{26,5,2049},{22,5,129},{64,5,0},{16,5,2},{23,5,385},
+        {19,5,25},{27,5,6145},{17,5,7},{25,5,1537},{21,5,97},{29,5,24577},
+        {16,5,4},{24,5,769},{20,5,49},{28,5,12289},{18,5,13},{26,5,3073},
+        {22,5,193},{64,5,0}
+    };
diff --git a/usr/klibc/zlib/inflate.c b/usr/klibc/zlib/inflate.c
new file mode 100644
index 0000000..792fdee
--- /dev/null
+++ b/usr/klibc/zlib/inflate.c
@@ -0,0 +1,1368 @@
+/* inflate.c -- zlib decompression
+ * Copyright (C) 1995-2005 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/*
+ * Change history:
+ *
+ * 1.2.beta0    24 Nov 2002
+ * - First version -- complete rewrite of inflate to simplify code, avoid
+ *   creation of window when not needed, minimize use of window when it is
+ *   needed, make inffast.c even faster, implement gzip decoding, and to
+ *   improve code readability and style over the previous zlib inflate code
+ *
+ * 1.2.beta1    25 Nov 2002
+ * - Use pointers for available input and output checking in inffast.c
+ * - Remove input and output counters in inffast.c
+ * - Change inffast.c entry and loop from avail_in >= 7 to >= 6
+ * - Remove unnecessary second byte pull from length extra in inffast.c
+ * - Unroll direct copy to three copies per loop in inffast.c
+ *
+ * 1.2.beta2    4 Dec 2002
+ * - Change external routine names to reduce potential conflicts
+ * - Correct filename to inffixed.h for fixed tables in inflate.c
+ * - Make hbuf[] unsigned char to match parameter type in inflate.c
+ * - Change strm->next_out[-state->offset] to *(strm->next_out - state->offset)
+ *   to avoid negation problem on Alphas (64 bit) in inflate.c
+ *
+ * 1.2.beta3    22 Dec 2002
+ * - Add comments on state->bits assertion in inffast.c
+ * - Add comments on op field in inftrees.h
+ * - Fix bug in reuse of allocated window after inflateReset()
+ * - Remove bit fields--back to byte structure for speed
+ * - Remove distance extra == 0 check in inflate_fast()--only helps for lengths
+ * - Change post-increments to pre-increments in inflate_fast(), PPC biased?
+ * - Add compile time option, POSTINC, to use post-increments instead (Intel?)
+ * - Make MATCH copy in inflate() much faster for when inflate_fast() not used
+ * - Use local copies of stream next and avail values, as well as local bit
+ *   buffer and bit count in inflate()--for speed when inflate_fast() not used
+ *
+ * 1.2.beta4    1 Jan 2003
+ * - Split ptr - 257 statements in inflate_table() to avoid compiler warnings
+ * - Move a comment on output buffer sizes from inffast.c to inflate.c
+ * - Add comments in inffast.c to introduce the inflate_fast() routine
+ * - Rearrange window copies in inflate_fast() for speed and simplification
+ * - Unroll last copy for window match in inflate_fast()
+ * - Use local copies of window variables in inflate_fast() for speed
+ * - Pull out common write == 0 case for speed in inflate_fast()
+ * - Make op and len in inflate_fast() unsigned for consistency
+ * - Add FAR to lcode and dcode declarations in inflate_fast()
+ * - Simplified bad distance check in inflate_fast()
+ * - Added inflateBackInit(), inflateBack(), and inflateBackEnd() in new
+ *   source file infback.c to provide a call-back interface to inflate for
+ *   programs like gzip and unzip -- uses window as output buffer to avoid
+ *   window copying
+ *
+ * 1.2.beta5    1 Jan 2003
+ * - Improved inflateBack() interface to allow the caller to provide initial
+ *   input in strm.
+ * - Fixed stored blocks bug in inflateBack()
+ *
+ * 1.2.beta6    4 Jan 2003
+ * - Added comments in inffast.c on effectiveness of POSTINC
+ * - Typecasting all around to reduce compiler warnings
+ * - Changed loops from while (1) or do {} while (1) to for (;;), again to
+ *   make compilers happy
+ * - Changed type of window in inflateBackInit() to unsigned char *
+ *
+ * 1.2.beta7    27 Jan 2003
+ * - Changed many types to unsigned or unsigned short to avoid warnings
+ * - Added inflateCopy() function
+ *
+ * 1.2.0        9 Mar 2003
+ * - Changed inflateBack() interface to provide separate opaque descriptors
+ *   for the in() and out() functions
+ * - Changed inflateBack() argument and in_func typedef to swap the length
+ *   and buffer address return values for the input function
+ * - Check next_in and next_out for Z_NULL on entry to inflate()
+ *
+ * The history for versions after 1.2.0 are in ChangeLog in zlib distribution.
+ */
+
+#include "zutil.h"
+#include "inftrees.h"
+#include "inflate.h"
+#include "inffast.h"
+
+#ifdef MAKEFIXED
+#  ifndef BUILDFIXED
+#    define BUILDFIXED
+#  endif
+#endif
+
+/* function prototypes */
+local void fixedtables OF((struct inflate_state FAR *state));
+local int updatewindow OF((z_streamp strm, unsigned out));
+#ifdef BUILDFIXED
+   void makefixed OF((void));
+#endif
+local unsigned syncsearch OF((unsigned FAR *have, unsigned char FAR *buf,
+                              unsigned len));
+
+int ZEXPORT inflateReset(strm)
+z_streamp strm;
+{
+    struct inflate_state FAR *state;
+
+    if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR;
+    state = (struct inflate_state FAR *)strm->state;
+    strm->total_in = strm->total_out = state->total = 0;
+    strm->msg = Z_NULL;
+    strm->adler = 1;        /* to support ill-conceived Java test suite */
+    state->mode = HEAD;
+    state->last = 0;
+    state->havedict = 0;
+    state->dmax = 32768U;
+    state->head = Z_NULL;
+    state->wsize = 0;
+    state->whave = 0;
+    state->write = 0;
+    state->hold = 0;
+    state->bits = 0;
+    state->lencode = state->distcode = state->next = state->codes;
+    Tracev((stderr, "inflate: reset\n"));
+    return Z_OK;
+}
+
+int ZEXPORT inflatePrime(strm, bits, value)
+z_streamp strm;
+int bits;
+int value;
+{
+    struct inflate_state FAR *state;
+
+    if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR;
+    state = (struct inflate_state FAR *)strm->state;
+    if (bits > 16 || state->bits + bits > 32) return Z_STREAM_ERROR;
+    value &= (1L << bits) - 1;
+    state->hold += value << state->bits;
+    state->bits += bits;
+    return Z_OK;
+}
+
+int ZEXPORT inflateInit2_(strm, windowBits, version, stream_size)
+z_streamp strm;
+int windowBits;
+const char *version;
+int stream_size;
+{
+    struct inflate_state FAR *state;
+
+    if (version == Z_NULL || version[0] != ZLIB_VERSION[0] ||
+        stream_size != (int)(sizeof(z_stream)))
+        return Z_VERSION_ERROR;
+    if (strm == Z_NULL) return Z_STREAM_ERROR;
+    strm->msg = Z_NULL;                 /* in case we return an error */
+    if (strm->zalloc == (alloc_func)0) {
+        strm->zalloc = zcalloc;
+        strm->opaque = (voidpf)0;
+    }
+    if (strm->zfree == (free_func)0) strm->zfree = zcfree;
+    state = (struct inflate_state FAR *)
+            ZALLOC(strm, 1, sizeof(struct inflate_state));
+    if (state == Z_NULL) return Z_MEM_ERROR;
+    Tracev((stderr, "inflate: allocated\n"));
+    strm->state = (struct internal_state FAR *)state;
+    if (windowBits < 0) {
+        state->wrap = 0;
+        windowBits = -windowBits;
+    }
+    else {
+        state->wrap = (windowBits >> 4) + 1;
+#ifdef GUNZIP
+        if (windowBits < 48) windowBits &= 15;
+#endif
+    }
+    if (windowBits < 8 || windowBits > 15) {
+        ZFREE(strm, state);
+        strm->state = Z_NULL;
+        return Z_STREAM_ERROR;
+    }
+    state->wbits = (unsigned)windowBits;
+    state->window = Z_NULL;
+    return inflateReset(strm);
+}
+
+int ZEXPORT inflateInit_(strm, version, stream_size)
+z_streamp strm;
+const char *version;
+int stream_size;
+{
+    return inflateInit2_(strm, DEF_WBITS, version, stream_size);
+}
+
+/*
+   Return state with length and distance decoding tables and index sizes set to
+   fixed code decoding.  Normally this returns fixed tables from inffixed.h.
+   If BUILDFIXED is defined, then instead this routine builds the tables the
+   first time it's called, and returns those tables the first time and
+   thereafter.  This reduces the size of the code by about 2K bytes, in
+   exchange for a little execution time.  However, BUILDFIXED should not be
+   used for threaded applications, since the rewriting of the tables and virgin
+   may not be thread-safe.
+ */
+local void fixedtables(state)
+struct inflate_state FAR *state;
+{
+#ifdef BUILDFIXED
+    static int virgin = 1;
+    static code *lenfix, *distfix;
+    static code fixed[544];
+
+    /* build fixed huffman tables if first call (may not be thread safe) */
+    if (virgin) {
+        unsigned sym, bits;
+        static code *next;
+
+        /* literal/length table */
+        sym = 0;
+        while (sym < 144) state->lens[sym++] = 8;
+        while (sym < 256) state->lens[sym++] = 9;
+        while (sym < 280) state->lens[sym++] = 7;
+        while (sym < 288) state->lens[sym++] = 8;
+        next = fixed;
+        lenfix = next;
+        bits = 9;
+        inflate_table(LENS, state->lens, 288, &(next), &(bits), state->work);
+
+        /* distance table */
+        sym = 0;
+        while (sym < 32) state->lens[sym++] = 5;
+        distfix = next;
+        bits = 5;
+        inflate_table(DISTS, state->lens, 32, &(next), &(bits), state->work);
+
+        /* do this just once */
+        virgin = 0;
+    }
+#else /* !BUILDFIXED */
+#   include "inffixed.h"
+#endif /* BUILDFIXED */
+    state->lencode = lenfix;
+    state->lenbits = 9;
+    state->distcode = distfix;
+    state->distbits = 5;
+}
+
+#ifdef MAKEFIXED
+#include <stdio.h>
+
+/*
+   Write out the inffixed.h that is #include'd above.  Defining MAKEFIXED also
+   defines BUILDFIXED, so the tables are built on the fly.  makefixed() writes
+   those tables to stdout, which would be piped to inffixed.h.  A small program
+   can simply call makefixed to do this:
+
+    void makefixed(void);
+
+    int main(void)
+    {
+        makefixed();
+        return 0;
+    }
+
+   Then that can be linked with zlib built with MAKEFIXED defined and run:
+
+    a.out > inffixed.h
+ */
+void makefixed()
+{
+    unsigned low, size;
+    struct inflate_state state;
+
+    fixedtables(&state);
+    puts("    /* inffixed.h -- table for decoding fixed codes");
+    puts("     * Generated automatically by makefixed().");
+    puts("     */");
+    puts("");
+    puts("    /* WARNING: this file should *not* be used by applications.");
+    puts("       It is part of the implementation of this library and is");
+    puts("       subject to change. Applications should only use zlib.h.");
+    puts("     */");
+    puts("");
+    size = 1U << 9;
+    printf("    static const code lenfix[%u] = {", size);
+    low = 0;
+    for (;;) {
+        if ((low % 7) == 0) printf("\n        ");
+        printf("{%u,%u,%d}", state.lencode[low].op, state.lencode[low].bits,
+               state.lencode[low].val);
+        if (++low == size) break;
+        putchar(',');
+    }
+    puts("\n    };");
+    size = 1U << 5;
+    printf("\n    static const code distfix[%u] = {", size);
+    low = 0;
+    for (;;) {
+        if ((low % 6) == 0) printf("\n        ");
+        printf("{%u,%u,%d}", state.distcode[low].op, state.distcode[low].bits,
+               state.distcode[low].val);
+        if (++low == size) break;
+        putchar(',');
+    }
+    puts("\n    };");
+}
+#endif /* MAKEFIXED */
+
+/*
+   Update the window with the last wsize (normally 32K) bytes written before
+   returning.  If window does not exist yet, create it.  This is only called
+   when a window is already in use, or when output has been written during this
+   inflate call, but the end of the deflate stream has not been reached yet.
+   It is also called to create a window for dictionary data when a dictionary
+   is loaded.
+
+   Providing output buffers larger than 32K to inflate() should provide a speed
+   advantage, since only the last 32K of output is copied to the sliding window
+   upon return from inflate(), and since all distances after the first 32K of
+   output will fall in the output data, making match copies simpler and faster.
+   The advantage may be dependent on the size of the processor's data caches.
+ */
+local int updatewindow(strm, out)
+z_streamp strm;
+unsigned out;
+{
+    struct inflate_state FAR *state;
+    unsigned copy, dist;
+
+    state = (struct inflate_state FAR *)strm->state;
+
+    /* if it hasn't been done already, allocate space for the window */
+    if (state->window == Z_NULL) {
+        state->window = (unsigned char FAR *)
+                        ZALLOC(strm, 1U << state->wbits,
+                               sizeof(unsigned char));
+        if (state->window == Z_NULL) return 1;
+    }
+
+    /* if window not in use yet, initialize */
+    if (state->wsize == 0) {
+        state->wsize = 1U << state->wbits;
+        state->write = 0;
+        state->whave = 0;
+    }
+
+    /* copy state->wsize or less output bytes into the circular window */
+    copy = out - strm->avail_out;
+    if (copy >= state->wsize) {
+        zmemcpy(state->window, strm->next_out - state->wsize, state->wsize);
+        state->write = 0;
+        state->whave = state->wsize;
+    }
+    else {
+        dist = state->wsize - state->write;
+        if (dist > copy) dist = copy;
+        zmemcpy(state->window + state->write, strm->next_out - copy, dist);
+        copy -= dist;
+        if (copy) {
+            zmemcpy(state->window, strm->next_out - copy, copy);
+            state->write = copy;
+            state->whave = state->wsize;
+        }
+        else {
+            state->write += dist;
+            if (state->write == state->wsize) state->write = 0;
+            if (state->whave < state->wsize) state->whave += dist;
+        }
+    }
+    return 0;
+}
+
+/* Macros for inflate(): */
+
+/* check function to use adler32() for zlib or crc32() for gzip */
+#ifdef GUNZIP
+#  define UPDATE(check, buf, len) \
+    (state->flags ? crc32(check, buf, len) : adler32(check, buf, len))
+#else
+#  define UPDATE(check, buf, len) adler32(check, buf, len)
+#endif
+
+/* check macros for header crc */
+#ifdef GUNZIP
+#  define CRC2(check, word) \
+    do { \
+        hbuf[0] = (unsigned char)(word); \
+        hbuf[1] = (unsigned char)((word) >> 8); \
+        check = crc32(check, hbuf, 2); \
+    } while (0)
+
+#  define CRC4(check, word) \
+    do { \
+        hbuf[0] = (unsigned char)(word); \
+        hbuf[1] = (unsigned char)((word) >> 8); \
+        hbuf[2] = (unsigned char)((word) >> 16); \
+        hbuf[3] = (unsigned char)((word) >> 24); \
+        check = crc32(check, hbuf, 4); \
+    } while (0)
+#endif
+
+/* Load registers with state in inflate() for speed */
+#define LOAD() \
+    do { \
+        put = strm->next_out; \
+        left = strm->avail_out; \
+        next = strm->next_in; \
+        have = strm->avail_in; \
+        hold = state->hold; \
+        bits = state->bits; \
+    } while (0)
+
+/* Restore state from registers in inflate() */
+#define RESTORE() \
+    do { \
+        strm->next_out = put; \
+        strm->avail_out = left; \
+        strm->next_in = next; \
+        strm->avail_in = have; \
+        state->hold = hold; \
+        state->bits = bits; \
+    } while (0)
+
+/* Clear the input bit accumulator */
+#define INITBITS() \
+    do { \
+        hold = 0; \
+        bits = 0; \
+    } while (0)
+
+/* Get a byte of input into the bit accumulator, or return from inflate()
+   if there is no input available. */
+#define PULLBYTE() \
+    do { \
+        if (have == 0) goto inf_leave; \
+        have--; \
+        hold += (unsigned long)(*next++) << bits; \
+        bits += 8; \
+    } while (0)
+
+/* Assure that there are at least n bits in the bit accumulator.  If there is
+   not enough available input to do that, then return from inflate(). */
+#define NEEDBITS(n) \
+    do { \
+        while (bits < (unsigned)(n)) \
+            PULLBYTE(); \
+    } while (0)
+
+/* Return the low n bits of the bit accumulator (n < 16) */
+#define BITS(n) \
+    ((unsigned)hold & ((1U << (n)) - 1))
+
+/* Remove n bits from the bit accumulator */
+#define DROPBITS(n) \
+    do { \
+        hold >>= (n); \
+        bits -= (unsigned)(n); \
+    } while (0)
+
+/* Remove zero to seven bits as needed to go to a byte boundary */
+#define BYTEBITS() \
+    do { \
+        hold >>= bits & 7; \
+        bits -= bits & 7; \
+    } while (0)
+
+/* Reverse the bytes in a 32-bit value */
+#define REVERSE(q) \
+    ((((q) >> 24) & 0xff) + (((q) >> 8) & 0xff00) + \
+     (((q) & 0xff00) << 8) + (((q) & 0xff) << 24))
+
+/*
+   inflate() uses a state machine to process as much input data and generate as
+   much output data as possible before returning.  The state machine is
+   structured roughly as follows:
+
+    for (;;) switch (state) {
+    ...
+    case STATEn:
+        if (not enough input data or output space to make progress)
+            return;
+        ... make progress ...
+        state = STATEm;
+        break;
+    ...
+    }
+
+   so when inflate() is called again, the same case is attempted again, and
+   if the appropriate resources are provided, the machine proceeds to the
+   next state.  The NEEDBITS() macro is usually the way the state evaluates
+   whether it can proceed or should return.  NEEDBITS() does the return if
+   the requested bits are not available.  The typical use of the BITS macros
+   is:
+
+        NEEDBITS(n);
+        ... do something with BITS(n) ...
+        DROPBITS(n);
+
+   where NEEDBITS(n) either returns from inflate() if there isn't enough
+   input left to load n bits into the accumulator, or it continues.  BITS(n)
+   gives the low n bits in the accumulator.  When done, DROPBITS(n) drops
+   the low n bits off the accumulator.  INITBITS() clears the accumulator
+   and sets the number of available bits to zero.  BYTEBITS() discards just
+   enough bits to put the accumulator on a byte boundary.  After BYTEBITS()
+   and a NEEDBITS(8), then BITS(8) would return the next byte in the stream.
+
+   NEEDBITS(n) uses PULLBYTE() to get an available byte of input, or to return
+   if there is no input available.  The decoding of variable length codes uses
+   PULLBYTE() directly in order to pull just enough bytes to decode the next
+   code, and no more.
+
+   Some states loop until they get enough input, making sure that enough
+   state information is maintained to continue the loop where it left off
+   if NEEDBITS() returns in the loop.  For example, want, need, and keep
+   would all have to actually be part of the saved state in case NEEDBITS()
+   returns:
+
+    case STATEw:
+        while (want < need) {
+            NEEDBITS(n);
+            keep[want++] = BITS(n);
+            DROPBITS(n);
+        }
+        state = STATEx;
+    case STATEx:
+
+   As shown above, if the next state is also the next case, then the break
+   is omitted.
+
+   A state may also return if there is not enough output space available to
+   complete that state.  Those states are copying stored data, writing a
+   literal byte, and copying a matching string.
+
+   When returning, a "goto inf_leave" is used to update the total counters,
+   update the check value, and determine whether any progress has been made
+   during that inflate() call in order to return the proper return code.
+   Progress is defined as a change in either strm->avail_in or strm->avail_out.
+   When there is a window, goto inf_leave will update the window with the last
+   output written.  If a goto inf_leave occurs in the middle of decompression
+   and there is no window currently, goto inf_leave will create one and copy
+   output to the window for the next call of inflate().
+
+   In this implementation, the flush parameter of inflate() only affects the
+   return code (per zlib.h).  inflate() always writes as much as possible to
+   strm->next_out, given the space available and the provided input--the effect
+   documented in zlib.h of Z_SYNC_FLUSH.  Furthermore, inflate() always defers
+   the allocation of and copying into a sliding window until necessary, which
+   provides the effect documented in zlib.h for Z_FINISH when the entire input
+   stream available.  So the only thing the flush parameter actually does is:
+   when flush is set to Z_FINISH, inflate() cannot return Z_OK.  Instead it
+   will return Z_BUF_ERROR if it has not reached the end of the stream.
+ */
+
+int ZEXPORT inflate(strm, flush)
+z_streamp strm;
+int flush;
+{
+    struct inflate_state FAR *state;
+    unsigned char FAR *next;    /* next input */
+    unsigned char FAR *put;     /* next output */
+    unsigned have, left;        /* available input and output */
+    unsigned long hold;         /* bit buffer */
+    unsigned bits;              /* bits in bit buffer */
+    unsigned in, out;           /* save starting available input and output */
+    unsigned copy;              /* number of stored or match bytes to copy */
+    unsigned char FAR *from;    /* where to copy match bytes from */
+    code this;                  /* current decoding table entry */
+    code last;                  /* parent table entry */
+    unsigned len;               /* length to copy for repeats, bits to drop */
+    int ret;                    /* return code */
+#ifdef GUNZIP
+    unsigned char hbuf[4];      /* buffer for gzip header crc calculation */
+#endif
+    static const unsigned short order[19] = /* permutation of code lengths */
+        {16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15};
+
+    if (strm == Z_NULL || strm->state == Z_NULL || strm->next_out == Z_NULL ||
+        (strm->next_in == Z_NULL && strm->avail_in != 0))
+        return Z_STREAM_ERROR;
+
+    state = (struct inflate_state FAR *)strm->state;
+    if (state->mode == TYPE) state->mode = TYPEDO;      /* skip check */
+    LOAD();
+    in = have;
+    out = left;
+    ret = Z_OK;
+    for (;;)
+        switch (state->mode) {
+        case HEAD:
+            if (state->wrap == 0) {
+                state->mode = TYPEDO;
+                break;
+            }
+            NEEDBITS(16);
+#ifdef GUNZIP
+            if ((state->wrap & 2) && hold == 0x8b1f) {  /* gzip header */
+                state->check = crc32(0L, Z_NULL, 0);
+                CRC2(state->check, hold);
+                INITBITS();
+                state->mode = FLAGS;
+                break;
+            }
+            state->flags = 0;           /* expect zlib header */
+            if (state->head != Z_NULL)
+                state->head->done = -1;
+            if (!(state->wrap & 1) ||   /* check if zlib header allowed */
+#else
+            if (
+#endif
+                ((BITS(8) << 8) + (hold >> 8)) % 31) {
+                strm->msg = (char *)"incorrect header check";
+                state->mode = BAD;
+                break;
+            }
+            if (BITS(4) != Z_DEFLATED) {
+                strm->msg = (char *)"unknown compression method";
+                state->mode = BAD;
+                break;
+            }
+            DROPBITS(4);
+            len = BITS(4) + 8;
+            if (len > state->wbits) {
+                strm->msg = (char *)"invalid window size";
+                state->mode = BAD;
+                break;
+            }
+            state->dmax = 1U << len;
+            Tracev((stderr, "inflate:   zlib header ok\n"));
+            strm->adler = state->check = adler32(0L, Z_NULL, 0);
+            state->mode = hold & 0x200 ? DICTID : TYPE;
+            INITBITS();
+            break;
+#ifdef GUNZIP
+        case FLAGS:
+            NEEDBITS(16);
+            state->flags = (int)(hold);
+            if ((state->flags & 0xff) != Z_DEFLATED) {
+                strm->msg = (char *)"unknown compression method";
+                state->mode = BAD;
+                break;
+            }
+            if (state->flags & 0xe000) {
+                strm->msg = (char *)"unknown header flags set";
+                state->mode = BAD;
+                break;
+            }
+            if (state->head != Z_NULL)
+                state->head->text = (int)((hold >> 8) & 1);
+            if (state->flags & 0x0200) CRC2(state->check, hold);
+            INITBITS();
+            state->mode = TIME;
+        case TIME:
+            NEEDBITS(32);
+            if (state->head != Z_NULL)
+                state->head->time = hold;
+            if (state->flags & 0x0200) CRC4(state->check, hold);
+            INITBITS();
+            state->mode = OS;
+        case OS:
+            NEEDBITS(16);
+            if (state->head != Z_NULL) {
+                state->head->xflags = (int)(hold & 0xff);
+                state->head->os = (int)(hold >> 8);
+            }
+            if (state->flags & 0x0200) CRC2(state->check, hold);
+            INITBITS();
+            state->mode = EXLEN;
+        case EXLEN:
+            if (state->flags & 0x0400) {
+                NEEDBITS(16);
+                state->length = (unsigned)(hold);
+                if (state->head != Z_NULL)
+                    state->head->extra_len = (unsigned)hold;
+                if (state->flags & 0x0200) CRC2(state->check, hold);
+                INITBITS();
+            }
+            else if (state->head != Z_NULL)
+                state->head->extra = Z_NULL;
+            state->mode = EXTRA;
+        case EXTRA:
+            if (state->flags & 0x0400) {
+                copy = state->length;
+                if (copy > have) copy = have;
+                if (copy) {
+                    if (state->head != Z_NULL &&
+                        state->head->extra != Z_NULL) {
+                        len = state->head->extra_len - state->length;
+                        zmemcpy(state->head->extra + len, next,
+                                len + copy > state->head->extra_max ?
+                                state->head->extra_max - len : copy);
+                    }
+                    if (state->flags & 0x0200)
+                        state->check = crc32(state->check, next, copy);
+                    have -= copy;
+                    next += copy;
+                    state->length -= copy;
+                }
+                if (state->length) goto inf_leave;
+            }
+            state->length = 0;
+            state->mode = NAME;
+        case NAME:
+            if (state->flags & 0x0800) {
+                if (have == 0) goto inf_leave;
+                copy = 0;
+                do {
+                    len = (unsigned)(next[copy++]);
+                    if (state->head != Z_NULL &&
+                            state->head->name != Z_NULL &&
+                            state->length < state->head->name_max)
+                        state->head->name[state->length++] = len;
+                } while (len && copy < have);
+                if (state->flags & 0x0200)
+                    state->check = crc32(state->check, next, copy);
+                have -= copy;
+                next += copy;
+                if (len) goto inf_leave;
+            }
+            else if (state->head != Z_NULL)
+                state->head->name = Z_NULL;
+            state->length = 0;
+            state->mode = COMMENT;
+        case COMMENT:
+            if (state->flags & 0x1000) {
+                if (have == 0) goto inf_leave;
+                copy = 0;
+                do {
+                    len = (unsigned)(next[copy++]);
+                    if (state->head != Z_NULL &&
+                            state->head->comment != Z_NULL &&
+                            state->length < state->head->comm_max)
+                        state->head->comment[state->length++] = len;
+                } while (len && copy < have);
+                if (state->flags & 0x0200)
+                    state->check = crc32(state->check, next, copy);
+                have -= copy;
+                next += copy;
+                if (len) goto inf_leave;
+            }
+            else if (state->head != Z_NULL)
+                state->head->comment = Z_NULL;
+            state->mode = HCRC;
+        case HCRC:
+            if (state->flags & 0x0200) {
+                NEEDBITS(16);
+                if (hold != (state->check & 0xffff)) {
+                    strm->msg = (char *)"header crc mismatch";
+                    state->mode = BAD;
+                    break;
+                }
+                INITBITS();
+            }
+            if (state->head != Z_NULL) {
+                state->head->hcrc = (int)((state->flags >> 9) & 1);
+                state->head->done = 1;
+            }
+            strm->adler = state->check = crc32(0L, Z_NULL, 0);
+            state->mode = TYPE;
+            break;
+#endif
+        case DICTID:
+            NEEDBITS(32);
+            strm->adler = state->check = REVERSE(hold);
+            INITBITS();
+            state->mode = DICT;
+        case DICT:
+            if (state->havedict == 0) {
+                RESTORE();
+                return Z_NEED_DICT;
+            }
+            strm->adler = state->check = adler32(0L, Z_NULL, 0);
+            state->mode = TYPE;
+        case TYPE:
+            if (flush == Z_BLOCK) goto inf_leave;
+        case TYPEDO:
+            if (state->last) {
+                BYTEBITS();
+                state->mode = CHECK;
+                break;
+            }
+            NEEDBITS(3);
+            state->last = BITS(1);
+            DROPBITS(1);
+            switch (BITS(2)) {
+            case 0:                             /* stored block */
+                Tracev((stderr, "inflate:     stored block%s\n",
+                        state->last ? " (last)" : ""));
+                state->mode = STORED;
+                break;
+            case 1:                             /* fixed block */
+                fixedtables(state);
+                Tracev((stderr, "inflate:     fixed codes block%s\n",
+                        state->last ? " (last)" : ""));
+                state->mode = LEN;              /* decode codes */
+                break;
+            case 2:                             /* dynamic block */
+                Tracev((stderr, "inflate:     dynamic codes block%s\n",
+                        state->last ? " (last)" : ""));
+                state->mode = TABLE;
+                break;
+            case 3:
+                strm->msg = (char *)"invalid block type";
+                state->mode = BAD;
+            }
+            DROPBITS(2);
+            break;
+        case STORED:
+            BYTEBITS();                         /* go to byte boundary */
+            NEEDBITS(32);
+            if ((hold & 0xffff) != ((hold >> 16) ^ 0xffff)) {
+                strm->msg = (char *)"invalid stored block lengths";
+                state->mode = BAD;
+                break;
+            }
+            state->length = (unsigned)hold & 0xffff;
+            Tracev((stderr, "inflate:       stored length %u\n",
+                    state->length));
+            INITBITS();
+            state->mode = COPY;
+        case COPY:
+            copy = state->length;
+            if (copy) {
+                if (copy > have) copy = have;
+                if (copy > left) copy = left;
+                if (copy == 0) goto inf_leave;
+                zmemcpy(put, next, copy);
+                have -= copy;
+                next += copy;
+                left -= copy;
+                put += copy;
+                state->length -= copy;
+                break;
+            }
+            Tracev((stderr, "inflate:       stored end\n"));
+            state->mode = TYPE;
+            break;
+        case TABLE:
+            NEEDBITS(14);
+            state->nlen = BITS(5) + 257;
+            DROPBITS(5);
+            state->ndist = BITS(5) + 1;
+            DROPBITS(5);
+            state->ncode = BITS(4) + 4;
+            DROPBITS(4);
+#ifndef PKZIP_BUG_WORKAROUND
+            if (state->nlen > 286 || state->ndist > 30) {
+                strm->msg = (char *)"too many length or distance symbols";
+                state->mode = BAD;
+                break;
+            }
+#endif
+            Tracev((stderr, "inflate:       table sizes ok\n"));
+            state->have = 0;
+            state->mode = LENLENS;
+        case LENLENS:
+            while (state->have < state->ncode) {
+                NEEDBITS(3);
+                state->lens[order[state->have++]] = (unsigned short)BITS(3);
+                DROPBITS(3);
+            }
+            while (state->have < 19)
+                state->lens[order[state->have++]] = 0;
+            state->next = state->codes;
+            state->lencode = (code const FAR *)(state->next);
+            state->lenbits = 7;
+            ret = inflate_table(CODES, state->lens, 19, &(state->next),
+                                &(state->lenbits), state->work);
+            if (ret) {
+                strm->msg = (char *)"invalid code lengths set";
+                state->mode = BAD;
+                break;
+            }
+            Tracev((stderr, "inflate:       code lengths ok\n"));
+            state->have = 0;
+            state->mode = CODELENS;
+        case CODELENS:
+            while (state->have < state->nlen + state->ndist) {
+                for (;;) {
+                    this = state->lencode[BITS(state->lenbits)];
+                    if ((unsigned)(this.bits) <= bits) break;
+                    PULLBYTE();
+                }
+                if (this.val < 16) {
+                    NEEDBITS(this.bits);
+                    DROPBITS(this.bits);
+                    state->lens[state->have++] = this.val;
+                }
+                else {
+                    if (this.val == 16) {
+                        NEEDBITS(this.bits + 2);
+                        DROPBITS(this.bits);
+                        if (state->have == 0) {
+                            strm->msg = (char *)"invalid bit length repeat";
+                            state->mode = BAD;
+                            break;
+                        }
+                        len = state->lens[state->have - 1];
+                        copy = 3 + BITS(2);
+                        DROPBITS(2);
+                    }
+                    else if (this.val == 17) {
+                        NEEDBITS(this.bits + 3);
+                        DROPBITS(this.bits);
+                        len = 0;
+                        copy = 3 + BITS(3);
+                        DROPBITS(3);
+                    }
+                    else {
+                        NEEDBITS(this.bits + 7);
+                        DROPBITS(this.bits);
+                        len = 0;
+                        copy = 11 + BITS(7);
+                        DROPBITS(7);
+                    }
+                    if (state->have + copy > state->nlen + state->ndist) {
+                        strm->msg = (char *)"invalid bit length repeat";
+                        state->mode = BAD;
+                        break;
+                    }
+                    while (copy--)
+                        state->lens[state->have++] = (unsigned short)len;
+                }
+            }
+
+            /* handle error breaks in while */
+            if (state->mode == BAD) break;
+
+            /* build code tables */
+            state->next = state->codes;
+            state->lencode = (code const FAR *)(state->next);
+            state->lenbits = 9;
+            ret = inflate_table(LENS, state->lens, state->nlen, &(state->next),
+                                &(state->lenbits), state->work);
+            if (ret) {
+                strm->msg = (char *)"invalid literal/lengths set";
+                state->mode = BAD;
+                break;
+            }
+            state->distcode = (code const FAR *)(state->next);
+            state->distbits = 6;
+            ret = inflate_table(DISTS, state->lens + state->nlen, state->ndist,
+                            &(state->next), &(state->distbits), state->work);
+            if (ret) {
+                strm->msg = (char *)"invalid distances set";
+                state->mode = BAD;
+                break;
+            }
+            Tracev((stderr, "inflate:       codes ok\n"));
+            state->mode = LEN;
+        case LEN:
+            if (have >= 6 && left >= 258) {
+                RESTORE();
+                inflate_fast(strm, out);
+                LOAD();
+                break;
+            }
+            for (;;) {
+                this = state->lencode[BITS(state->lenbits)];
+                if ((unsigned)(this.bits) <= bits) break;
+                PULLBYTE();
+            }
+            if (this.op && (this.op & 0xf0) == 0) {
+                last = this;
+                for (;;) {
+                    this = state->lencode[last.val +
+                            (BITS(last.bits + last.op) >> last.bits)];
+                    if ((unsigned)(last.bits + this.bits) <= bits) break;
+                    PULLBYTE();
+                }
+                DROPBITS(last.bits);
+            }
+            DROPBITS(this.bits);
+            state->length = (unsigned)this.val;
+            if ((int)(this.op) == 0) {
+                Tracevv((stderr, this.val >= 0x20 && this.val < 0x7f ?
+                        "inflate:         literal '%c'\n" :
+                        "inflate:         literal 0x%02x\n", this.val));
+                state->mode = LIT;
+                break;
+            }
+            if (this.op & 32) {
+                Tracevv((stderr, "inflate:         end of block\n"));
+                state->mode = TYPE;
+                break;
+            }
+            if (this.op & 64) {
+                strm->msg = (char *)"invalid literal/length code";
+                state->mode = BAD;
+                break;
+            }
+            state->extra = (unsigned)(this.op) & 15;
+            state->mode = LENEXT;
+        case LENEXT:
+            if (state->extra) {
+                NEEDBITS(state->extra);
+                state->length += BITS(state->extra);
+                DROPBITS(state->extra);
+            }
+            Tracevv((stderr, "inflate:         length %u\n", state->length));
+            state->mode = DIST;
+        case DIST:
+            for (;;) {
+                this = state->distcode[BITS(state->distbits)];
+                if ((unsigned)(this.bits) <= bits) break;
+                PULLBYTE();
+            }
+            if ((this.op & 0xf0) == 0) {
+                last = this;
+                for (;;) {
+                    this = state->distcode[last.val +
+                            (BITS(last.bits + last.op) >> last.bits)];
+                    if ((unsigned)(last.bits + this.bits) <= bits) break;
+                    PULLBYTE();
+                }
+                DROPBITS(last.bits);
+            }
+            DROPBITS(this.bits);
+            if (this.op & 64) {
+                strm->msg = (char *)"invalid distance code";
+                state->mode = BAD;
+                break;
+            }
+            state->offset = (unsigned)this.val;
+            state->extra = (unsigned)(this.op) & 15;
+            state->mode = DISTEXT;
+        case DISTEXT:
+            if (state->extra) {
+                NEEDBITS(state->extra);
+                state->offset += BITS(state->extra);
+                DROPBITS(state->extra);
+            }
+#ifdef INFLATE_STRICT
+            if (state->offset > state->dmax) {
+                strm->msg = (char *)"invalid distance too far back";
+                state->mode = BAD;
+                break;
+            }
+#endif
+            if (state->offset > state->whave + out - left) {
+                strm->msg = (char *)"invalid distance too far back";
+                state->mode = BAD;
+                break;
+            }
+            Tracevv((stderr, "inflate:         distance %u\n", state->offset));
+            state->mode = MATCH;
+        case MATCH:
+            if (left == 0) goto inf_leave;
+            copy = out - left;
+            if (state->offset > copy) {         /* copy from window */
+                copy = state->offset - copy;
+                if (copy > state->write) {
+                    copy -= state->write;
+                    from = state->window + (state->wsize - copy);
+                }
+                else
+                    from = state->window + (state->write - copy);
+                if (copy > state->length) copy = state->length;
+            }
+            else {                              /* copy from output */
+                from = put - state->offset;
+                copy = state->length;
+            }
+            if (copy > left) copy = left;
+            left -= copy;
+            state->length -= copy;
+            do {
+                *put++ = *from++;
+            } while (--copy);
+            if (state->length == 0) state->mode = LEN;
+            break;
+        case LIT:
+            if (left == 0) goto inf_leave;
+            *put++ = (unsigned char)(state->length);
+            left--;
+            state->mode = LEN;
+            break;
+        case CHECK:
+            if (state->wrap) {
+                NEEDBITS(32);
+                out -= left;
+                strm->total_out += out;
+                state->total += out;
+                if (out)
+                    strm->adler = state->check =
+                        UPDATE(state->check, put - out, out);
+                out = left;
+                if ((
+#ifdef GUNZIP
+                     state->flags ? hold :
+#endif
+                     REVERSE(hold)) != state->check) {
+                    strm->msg = (char *)"incorrect data check";
+                    state->mode = BAD;
+                    break;
+                }
+                INITBITS();
+                Tracev((stderr, "inflate:   check matches trailer\n"));
+            }
+#ifdef GUNZIP
+            state->mode = LENGTH;
+        case LENGTH:
+            if (state->wrap && state->flags) {
+                NEEDBITS(32);
+                if (hold != (state->total & 0xffffffffUL)) {
+                    strm->msg = (char *)"incorrect length check";
+                    state->mode = BAD;
+                    break;
+                }
+                INITBITS();
+                Tracev((stderr, "inflate:   length matches trailer\n"));
+            }
+#endif
+            state->mode = DONE;
+        case DONE:
+            ret = Z_STREAM_END;
+            goto inf_leave;
+        case BAD:
+            ret = Z_DATA_ERROR;
+            goto inf_leave;
+        case MEM:
+            return Z_MEM_ERROR;
+        case SYNC:
+        default:
+            return Z_STREAM_ERROR;
+        }
+
+    /*
+       Return from inflate(), updating the total counts and the check value.
+       If there was no progress during the inflate() call, return a buffer
+       error.  Call updatewindow() to create and/or update the window state.
+       Note: a memory error from inflate() is non-recoverable.
+     */
+  inf_leave:
+    RESTORE();
+    if (state->wsize || (state->mode < CHECK && out != strm->avail_out))
+        if (updatewindow(strm, out)) {
+            state->mode = MEM;
+            return Z_MEM_ERROR;
+        }
+    in -= strm->avail_in;
+    out -= strm->avail_out;
+    strm->total_in += in;
+    strm->total_out += out;
+    state->total += out;
+    if (state->wrap && out)
+        strm->adler = state->check =
+            UPDATE(state->check, strm->next_out - out, out);
+    strm->data_type = state->bits + (state->last ? 64 : 0) +
+                      (state->mode == TYPE ? 128 : 0);
+    if (((in == 0 && out == 0) || flush == Z_FINISH) && ret == Z_OK)
+        ret = Z_BUF_ERROR;
+    return ret;
+}
+
+int ZEXPORT inflateEnd(strm)
+z_streamp strm;
+{
+    struct inflate_state FAR *state;
+    if (strm == Z_NULL || strm->state == Z_NULL || strm->zfree == (free_func)0)
+        return Z_STREAM_ERROR;
+    state = (struct inflate_state FAR *)strm->state;
+    if (state->window != Z_NULL) ZFREE(strm, state->window);
+    ZFREE(strm, strm->state);
+    strm->state = Z_NULL;
+    Tracev((stderr, "inflate: end\n"));
+    return Z_OK;
+}
+
+int ZEXPORT inflateSetDictionary(strm, dictionary, dictLength)
+z_streamp strm;
+const Bytef *dictionary;
+uInt dictLength;
+{
+    struct inflate_state FAR *state;
+    unsigned long id;
+
+    /* check state */
+    if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR;
+    state = (struct inflate_state FAR *)strm->state;
+    if (state->wrap != 0 && state->mode != DICT)
+        return Z_STREAM_ERROR;
+
+    /* check for correct dictionary id */
+    if (state->mode == DICT) {
+        id = adler32(0L, Z_NULL, 0);
+        id = adler32(id, dictionary, dictLength);
+        if (id != state->check)
+            return Z_DATA_ERROR;
+    }
+
+    /* copy dictionary to window */
+    if (updatewindow(strm, strm->avail_out)) {
+        state->mode = MEM;
+        return Z_MEM_ERROR;
+    }
+    if (dictLength > state->wsize) {
+        zmemcpy(state->window, dictionary + dictLength - state->wsize,
+                state->wsize);
+        state->whave = state->wsize;
+    }
+    else {
+        zmemcpy(state->window + state->wsize - dictLength, dictionary,
+                dictLength);
+        state->whave = dictLength;
+    }
+    state->havedict = 1;
+    Tracev((stderr, "inflate:   dictionary set\n"));
+    return Z_OK;
+}
+
+int ZEXPORT inflateGetHeader(strm, head)
+z_streamp strm;
+gz_headerp head;
+{
+    struct inflate_state FAR *state;
+
+    /* check state */
+    if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR;
+    state = (struct inflate_state FAR *)strm->state;
+    if ((state->wrap & 2) == 0) return Z_STREAM_ERROR;
+
+    /* save header structure */
+    state->head = head;
+    head->done = 0;
+    return Z_OK;
+}
+
+/*
+   Search buf[0..len-1] for the pattern: 0, 0, 0xff, 0xff.  Return when found
+   or when out of input.  When called, *have is the number of pattern bytes
+   found in order so far, in 0..3.  On return *have is updated to the new
+   state.  If on return *have equals four, then the pattern was found and the
+   return value is how many bytes were read including the last byte of the
+   pattern.  If *have is less than four, then the pattern has not been found
+   yet and the return value is len.  In the latter case, syncsearch() can be
+   called again with more data and the *have state.  *have is initialized to
+   zero for the first call.
+ */
+local unsigned syncsearch(have, buf, len)
+unsigned FAR *have;
+unsigned char FAR *buf;
+unsigned len;
+{
+    unsigned got;
+    unsigned next;
+
+    got = *have;
+    next = 0;
+    while (next < len && got < 4) {
+        if ((int)(buf[next]) == (got < 2 ? 0 : 0xff))
+            got++;
+        else if (buf[next])
+            got = 0;
+        else
+            got = 4 - got;
+        next++;
+    }
+    *have = got;
+    return next;
+}
+
+int ZEXPORT inflateSync(strm)
+z_streamp strm;
+{
+    unsigned len;               /* number of bytes to look at or looked at */
+    unsigned long in, out;      /* temporary to save total_in and total_out */
+    unsigned char buf[4];       /* to restore bit buffer to byte string */
+    struct inflate_state FAR *state;
+
+    /* check parameters */
+    if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR;
+    state = (struct inflate_state FAR *)strm->state;
+    if (strm->avail_in == 0 && state->bits < 8) return Z_BUF_ERROR;
+
+    /* if first time, start search in bit buffer */
+    if (state->mode != SYNC) {
+        state->mode = SYNC;
+        state->hold <<= state->bits & 7;
+        state->bits -= state->bits & 7;
+        len = 0;
+        while (state->bits >= 8) {
+            buf[len++] = (unsigned char)(state->hold);
+            state->hold >>= 8;
+            state->bits -= 8;
+        }
+        state->have = 0;
+        syncsearch(&(state->have), buf, len);
+    }
+
+    /* search available input */
+    len = syncsearch(&(state->have), strm->next_in, strm->avail_in);
+    strm->avail_in -= len;
+    strm->next_in += len;
+    strm->total_in += len;
+
+    /* return no joy or set up to restart inflate() on a new block */
+    if (state->have != 4) return Z_DATA_ERROR;
+    in = strm->total_in;  out = strm->total_out;
+    inflateReset(strm);
+    strm->total_in = in;  strm->total_out = out;
+    state->mode = TYPE;
+    return Z_OK;
+}
+
+/*
+   Returns true if inflate is currently at the end of a block generated by
+   Z_SYNC_FLUSH or Z_FULL_FLUSH. This function is used by one PPP
+   implementation to provide an additional safety check. PPP uses
+   Z_SYNC_FLUSH but removes the length bytes of the resulting empty stored
+   block. When decompressing, PPP checks that at the end of input packet,
+   inflate is waiting for these length bytes.
+ */
+int ZEXPORT inflateSyncPoint(strm)
+z_streamp strm;
+{
+    struct inflate_state FAR *state;
+
+    if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR;
+    state = (struct inflate_state FAR *)strm->state;
+    return state->mode == STORED && state->bits == 0;
+}
+
+int ZEXPORT inflateCopy(dest, source)
+z_streamp dest;
+z_streamp source;
+{
+    struct inflate_state FAR *state;
+    struct inflate_state FAR *copy;
+    unsigned char FAR *window;
+    unsigned wsize;
+
+    /* check input */
+    if (dest == Z_NULL || source == Z_NULL || source->state == Z_NULL ||
+        source->zalloc == (alloc_func)0 || source->zfree == (free_func)0)
+        return Z_STREAM_ERROR;
+    state = (struct inflate_state FAR *)source->state;
+
+    /* allocate space */
+    copy = (struct inflate_state FAR *)
+           ZALLOC(source, 1, sizeof(struct inflate_state));
+    if (copy == Z_NULL) return Z_MEM_ERROR;
+    window = Z_NULL;
+    if (state->window != Z_NULL) {
+        window = (unsigned char FAR *)
+                 ZALLOC(source, 1U << state->wbits, sizeof(unsigned char));
+        if (window == Z_NULL) {
+            ZFREE(source, copy);
+            return Z_MEM_ERROR;
+        }
+    }
+
+    /* copy state */
+    zmemcpy(dest, source, sizeof(z_stream));
+    zmemcpy(copy, state, sizeof(struct inflate_state));
+    if (state->lencode >= state->codes &&
+        state->lencode <= state->codes + ENOUGH - 1) {
+        copy->lencode = copy->codes + (state->lencode - state->codes);
+        copy->distcode = copy->codes + (state->distcode - state->codes);
+    }
+    copy->next = copy->codes + (state->next - state->codes);
+    if (window != Z_NULL) {
+        wsize = 1U << state->wbits;
+        zmemcpy(window, state->window, wsize);
+    }
+    copy->window = window;
+    dest->state = (struct internal_state FAR *)copy;
+    return Z_OK;
+}
diff --git a/usr/klibc/zlib/inflate.h b/usr/klibc/zlib/inflate.h
new file mode 100644
index 0000000..07bd3e7
--- /dev/null
+++ b/usr/klibc/zlib/inflate.h
@@ -0,0 +1,115 @@
+/* inflate.h -- internal inflate state definition
+ * Copyright (C) 1995-2004 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* WARNING: this file should *not* be used by applications. It is
+   part of the implementation of the compression library and is
+   subject to change. Applications should only use zlib.h.
+ */
+
+/* define NO_GZIP when compiling if you want to disable gzip header and
+   trailer decoding by inflate().  NO_GZIP would be used to avoid linking in
+   the crc code when it is not needed.  For shared libraries, gzip decoding
+   should be left enabled. */
+#ifndef NO_GZIP
+#  define GUNZIP
+#endif
+
+/* Possible inflate modes between inflate() calls */
+typedef enum {
+    HEAD,       /* i: waiting for magic header */
+    FLAGS,      /* i: waiting for method and flags (gzip) */
+    TIME,       /* i: waiting for modification time (gzip) */
+    OS,         /* i: waiting for extra flags and operating system (gzip) */
+    EXLEN,      /* i: waiting for extra length (gzip) */
+    EXTRA,      /* i: waiting for extra bytes (gzip) */
+    NAME,       /* i: waiting for end of file name (gzip) */
+    COMMENT,    /* i: waiting for end of comment (gzip) */
+    HCRC,       /* i: waiting for header crc (gzip) */
+    DICTID,     /* i: waiting for dictionary check value */
+    DICT,       /* waiting for inflateSetDictionary() call */
+        TYPE,       /* i: waiting for type bits, including last-flag bit */
+        TYPEDO,     /* i: same, but skip check to exit inflate on new block */
+        STORED,     /* i: waiting for stored size (length and complement) */
+        COPY,       /* i/o: waiting for input or output to copy stored block */
+        TABLE,      /* i: waiting for dynamic block table lengths */
+        LENLENS,    /* i: waiting for code length code lengths */
+        CODELENS,   /* i: waiting for length/lit and distance code lengths */
+            LEN,        /* i: waiting for length/lit code */
+            LENEXT,     /* i: waiting for length extra bits */
+            DIST,       /* i: waiting for distance code */
+            DISTEXT,    /* i: waiting for distance extra bits */
+            MATCH,      /* o: waiting for output space to copy string */
+            LIT,        /* o: waiting for output space to write literal */
+    CHECK,      /* i: waiting for 32-bit check value */
+    LENGTH,     /* i: waiting for 32-bit length (gzip) */
+    DONE,       /* finished check, done -- remain here until reset */
+    BAD,        /* got a data error -- remain here until reset */
+    MEM,        /* got an inflate() memory error -- remain here until reset */
+    SYNC        /* looking for synchronization bytes to restart inflate() */
+} inflate_mode;
+
+/*
+    State transitions between above modes -
+
+    (most modes can go to the BAD or MEM mode -- not shown for clarity)
+
+    Process header:
+        HEAD -> (gzip) or (zlib)
+        (gzip) -> FLAGS -> TIME -> OS -> EXLEN -> EXTRA -> NAME
+        NAME -> COMMENT -> HCRC -> TYPE
+        (zlib) -> DICTID or TYPE
+        DICTID -> DICT -> TYPE
+    Read deflate blocks:
+            TYPE -> STORED or TABLE or LEN or CHECK
+            STORED -> COPY -> TYPE
+            TABLE -> LENLENS -> CODELENS -> LEN
+    Read deflate codes:
+                LEN -> LENEXT or LIT or TYPE
+                LENEXT -> DIST -> DISTEXT -> MATCH -> LEN
+                LIT -> LEN
+    Process trailer:
+        CHECK -> LENGTH -> DONE
+ */
+
+/* state maintained between inflate() calls.  Approximately 7K bytes. */
+struct inflate_state {
+    inflate_mode mode;          /* current inflate mode */
+    int last;                   /* true if processing last block */
+    int wrap;                   /* bit 0 true for zlib, bit 1 true for gzip */
+    int havedict;               /* true if dictionary provided */
+    int flags;                  /* gzip header method and flags (0 if zlib) */
+    unsigned dmax;              /* zlib header max distance (INFLATE_STRICT) */
+    unsigned long check;        /* protected copy of check value */
+    unsigned long total;        /* protected copy of output count */
+    gz_headerp head;            /* where to save gzip header information */
+        /* sliding window */
+    unsigned wbits;             /* log base 2 of requested window size */
+    unsigned wsize;             /* window size or zero if not using window */
+    unsigned whave;             /* valid bytes in the window */
+    unsigned write;             /* window write index */
+    unsigned char FAR *window;  /* allocated sliding window, if needed */
+        /* bit accumulator */
+    unsigned long hold;         /* input bit accumulator */
+    unsigned bits;              /* number of bits in "in" */
+        /* for string and stored block copying */
+    unsigned length;            /* literal or length of data to copy */
+    unsigned offset;            /* distance back to copy string from */
+        /* for table and code decoding */
+    unsigned extra;             /* extra bits needed */
+        /* fixed and dynamic code tables */
+    code const FAR *lencode;    /* starting table for length/literal codes */
+    code const FAR *distcode;   /* starting table for distance codes */
+    unsigned lenbits;           /* index bits for lencode */
+    unsigned distbits;          /* index bits for distcode */
+        /* dynamic table building */
+    unsigned ncode;             /* number of code length code lengths */
+    unsigned nlen;              /* number of length code lengths */
+    unsigned ndist;             /* number of distance code lengths */
+    unsigned have;              /* number of code lengths in lens[] */
+    code FAR *next;             /* next available space in codes[] */
+    unsigned short lens[320];   /* temporary storage for code lengths */
+    unsigned short work[288];   /* work area for code table building */
+    code codes[ENOUGH];         /* space for code tables */
+};
diff --git a/usr/klibc/zlib/inftrees.c b/usr/klibc/zlib/inftrees.c
new file mode 100644
index 0000000..8a9c13f
--- /dev/null
+++ b/usr/klibc/zlib/inftrees.c
@@ -0,0 +1,329 @@
+/* inftrees.c -- generate Huffman trees for efficient decoding
+ * Copyright (C) 1995-2005 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+#include "zutil.h"
+#include "inftrees.h"
+
+#define MAXBITS 15
+
+const char inflate_copyright[] =
+   " inflate 1.2.3 Copyright 1995-2005 Mark Adler ";
+/*
+  If you use the zlib library in a product, an acknowledgment is welcome
+  in the documentation of your product. If for some reason you cannot
+  include such an acknowledgment, I would appreciate that you keep this
+  copyright string in the executable of your product.
+ */
+
+/*
+   Build a set of tables to decode the provided canonical Huffman code.
+   The code lengths are lens[0..codes-1].  The result starts at *table,
+   whose indices are 0..2^bits-1.  work is a writable array of at least
+   lens shorts, which is used as a work area.  type is the type of code
+   to be generated, CODES, LENS, or DISTS.  On return, zero is success,
+   -1 is an invalid code, and +1 means that ENOUGH isn't enough.  table
+   on return points to the next available entry's address.  bits is the
+   requested root table index bits, and on return it is the actual root
+   table index bits.  It will differ if the request is greater than the
+   longest code or if it is less than the shortest code.
+ */
+int inflate_table(type, lens, codes, table, bits, work)
+codetype type;
+unsigned short FAR *lens;
+unsigned codes;
+code FAR * FAR *table;
+unsigned FAR *bits;
+unsigned short FAR *work;
+{
+    unsigned len;               /* a code's length in bits */
+    unsigned sym;               /* index of code symbols */
+    unsigned min, max;          /* minimum and maximum code lengths */
+    unsigned root;              /* number of index bits for root table */
+    unsigned curr;              /* number of index bits for current table */
+    unsigned drop;              /* code bits to drop for sub-table */
+    int left;                   /* number of prefix codes available */
+    unsigned used;              /* code entries in table used */
+    unsigned huff;              /* Huffman code */
+    unsigned incr;              /* for incrementing code, index */
+    unsigned fill;              /* index for replicating entries */
+    unsigned low;               /* low bits for current root entry */
+    unsigned mask;              /* mask for low root bits */
+    code this;                  /* table entry for duplication */
+    code FAR *next;             /* next available space in table */
+    const unsigned short FAR *base;     /* base value table to use */
+    const unsigned short FAR *extra;    /* extra bits table to use */
+    int end;                    /* use base and extra for symbol > end */
+    unsigned short count[MAXBITS+1];    /* number of codes of each length */
+    unsigned short offs[MAXBITS+1];     /* offsets in table for each length */
+    static const unsigned short lbase[31] = { /* Length codes 257..285 base */
+        3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31,
+        35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0};
+    static const unsigned short lext[31] = { /* Length codes 257..285 extra */
+        16, 16, 16, 16, 16, 16, 16, 16, 17, 17, 17, 17, 18, 18, 18, 18,
+        19, 19, 19, 19, 20, 20, 20, 20, 21, 21, 21, 21, 16, 201, 196};
+    static const unsigned short dbase[32] = { /* Distance codes 0..29 base */
+        1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193,
+        257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145,
+        8193, 12289, 16385, 24577, 0, 0};
+    static const unsigned short dext[32] = { /* Distance codes 0..29 extra */
+        16, 16, 16, 16, 17, 17, 18, 18, 19, 19, 20, 20, 21, 21, 22, 22,
+        23, 23, 24, 24, 25, 25, 26, 26, 27, 27,
+        28, 28, 29, 29, 64, 64};
+
+    /*
+       Process a set of code lengths to create a canonical Huffman code.  The
+       code lengths are lens[0..codes-1].  Each length corresponds to the
+       symbols 0..codes-1.  The Huffman code is generated by first sorting the
+       symbols by length from short to long, and retaining the symbol order
+       for codes with equal lengths.  Then the code starts with all zero bits
+       for the first code of the shortest length, and the codes are integer
+       increments for the same length, and zeros are appended as the length
+       increases.  For the deflate format, these bits are stored backwards
+       from their more natural integer increment ordering, and so when the
+       decoding tables are built in the large loop below, the integer codes
+       are incremented backwards.
+
+       This routine assumes, but does not check, that all of the entries in
+       lens[] are in the range 0..MAXBITS.  The caller must assure this.
+       1..MAXBITS is interpreted as that code length.  zero means that that
+       symbol does not occur in this code.
+
+       The codes are sorted by computing a count of codes for each length,
+       creating from that a table of starting indices for each length in the
+       sorted table, and then entering the symbols in order in the sorted
+       table.  The sorted table is work[], with that space being provided by
+       the caller.
+
+       The length counts are used for other purposes as well, i.e. finding
+       the minimum and maximum length codes, determining if there are any
+       codes at all, checking for a valid set of lengths, and looking ahead
+       at length counts to determine sub-table sizes when building the
+       decoding tables.
+     */
+
+    /* accumulate lengths for codes (assumes lens[] all in 0..MAXBITS) */
+    for (len = 0; len <= MAXBITS; len++)
+        count[len] = 0;
+    for (sym = 0; sym < codes; sym++)
+        count[lens[sym]]++;
+
+    /* bound code lengths, force root to be within code lengths */
+    root = *bits;
+    for (max = MAXBITS; max >= 1; max--)
+        if (count[max] != 0) break;
+    if (root > max) root = max;
+    if (max == 0) {                     /* no symbols to code at all */
+        this.op = (unsigned char)64;    /* invalid code marker */
+        this.bits = (unsigned char)1;
+        this.val = (unsigned short)0;
+        *(*table)++ = this;             /* make a table to force an error */
+        *(*table)++ = this;
+        *bits = 1;
+        return 0;     /* no symbols, but wait for decoding to report error */
+    }
+    for (min = 1; min <= MAXBITS; min++)
+        if (count[min] != 0) break;
+    if (root < min) root = min;
+
+    /* check for an over-subscribed or incomplete set of lengths */
+    left = 1;
+    for (len = 1; len <= MAXBITS; len++) {
+        left <<= 1;
+        left -= count[len];
+        if (left < 0) return -1;        /* over-subscribed */
+    }
+    if (left > 0 && (type == CODES || max != 1))
+        return -1;                      /* incomplete set */
+
+    /* generate offsets into symbol table for each length for sorting */
+    offs[1] = 0;
+    for (len = 1; len < MAXBITS; len++)
+        offs[len + 1] = offs[len] + count[len];
+
+    /* sort symbols by length, by symbol order within each length */
+    for (sym = 0; sym < codes; sym++)
+        if (lens[sym] != 0) work[offs[lens[sym]]++] = (unsigned short)sym;
+
+    /*
+       Create and fill in decoding tables.  In this loop, the table being
+       filled is at next and has curr index bits.  The code being used is huff
+       with length len.  That code is converted to an index by dropping drop
+       bits off of the bottom.  For codes where len is less than drop + curr,
+       those top drop + curr - len bits are incremented through all values to
+       fill the table with replicated entries.
+
+       root is the number of index bits for the root table.  When len exceeds
+       root, sub-tables are created pointed to by the root entry with an index
+       of the low root bits of huff.  This is saved in low to check for when a
+       new sub-table should be started.  drop is zero when the root table is
+       being filled, and drop is root when sub-tables are being filled.
+
+       When a new sub-table is needed, it is necessary to look ahead in the
+       code lengths to determine what size sub-table is needed.  The length
+       counts are used for this, and so count[] is decremented as codes are
+       entered in the tables.
+
+       used keeps track of how many table entries have been allocated from the
+       provided *table space.  It is checked when a LENS table is being made
+       against the space in *table, ENOUGH, minus the maximum space needed by
+       the worst case distance code, MAXD.  This should never happen, but the
+       sufficiency of ENOUGH has not been proven exhaustively, hence the check.
+       This assumes that when type == LENS, bits == 9.
+
+       sym increments through all symbols, and the loop terminates when
+       all codes of length max, i.e. all codes, have been processed.  This
+       routine permits incomplete codes, so another loop after this one fills
+       in the rest of the decoding tables with invalid code markers.
+     */
+
+    /* set up for code type */
+    switch (type) {
+    case CODES:
+        base = extra = work;    /* dummy value--not used */
+        end = 19;
+        break;
+    case LENS:
+        base = lbase;
+        base -= 257;
+        extra = lext;
+        extra -= 257;
+        end = 256;
+        break;
+    default:            /* DISTS */
+        base = dbase;
+        extra = dext;
+        end = -1;
+    }
+
+    /* initialize state for loop */
+    huff = 0;                   /* starting code */
+    sym = 0;                    /* starting code symbol */
+    len = min;                  /* starting code length */
+    next = *table;              /* current table to fill in */
+    curr = root;                /* current table index bits */
+    drop = 0;                   /* current bits to drop from code for index */
+    low = (unsigned)(-1);       /* trigger new sub-table when len > root */
+    used = 1U << root;          /* use root table entries */
+    mask = used - 1;            /* mask for comparing low */
+
+    /* check available table space */
+    if (type == LENS && used >= ENOUGH - MAXD)
+        return 1;
+
+    /* process all codes and make table entries */
+    for (;;) {
+        /* create table entry */
+        this.bits = (unsigned char)(len - drop);
+        if ((int)(work[sym]) < end) {
+            this.op = (unsigned char)0;
+            this.val = work[sym];
+        }
+        else if ((int)(work[sym]) > end) {
+            this.op = (unsigned char)(extra[work[sym]]);
+            this.val = base[work[sym]];
+        }
+        else {
+            this.op = (unsigned char)(32 + 64);         /* end of block */
+            this.val = 0;
+        }
+
+        /* replicate for those indices with low len bits equal to huff */
+        incr = 1U << (len - drop);
+        fill = 1U << curr;
+        min = fill;                 /* save offset to next table */
+        do {
+            fill -= incr;
+            next[(huff >> drop) + fill] = this;
+        } while (fill != 0);
+
+        /* backwards increment the len-bit code huff */
+        incr = 1U << (len - 1);
+        while (huff & incr)
+            incr >>= 1;
+        if (incr != 0) {
+            huff &= incr - 1;
+            huff += incr;
+        }
+        else
+            huff = 0;
+
+        /* go to next symbol, update count, len */
+        sym++;
+        if (--(count[len]) == 0) {
+            if (len == max) break;
+            len = lens[work[sym]];
+        }
+
+        /* create new sub-table if needed */
+        if (len > root && (huff & mask) != low) {
+            /* if first time, transition to sub-tables */
+            if (drop == 0)
+                drop = root;
+
+            /* increment past last table */
+            next += min;            /* here min is 1 << curr */
+
+            /* determine length of next table */
+            curr = len - drop;
+            left = (int)(1 << curr);
+            while (curr + drop < max) {
+                left -= count[curr + drop];
+                if (left <= 0) break;
+                curr++;
+                left <<= 1;
+            }
+
+            /* check for enough space */
+            used += 1U << curr;
+            if (type == LENS && used >= ENOUGH - MAXD)
+                return 1;
+
+            /* point entry in root table to sub-table */
+            low = huff & mask;
+            (*table)[low].op = (unsigned char)curr;
+            (*table)[low].bits = (unsigned char)root;
+            (*table)[low].val = (unsigned short)(next - *table);
+        }
+    }
+
+    /*
+       Fill in rest of table for incomplete codes.  This loop is similar to the
+       loop above in incrementing huff for table indices.  It is assumed that
+       len is equal to curr + drop, so there is no loop needed to increment
+       through high index bits.  When the current sub-table is filled, the loop
+       drops back to the root table to fill in any remaining entries there.
+     */
+    this.op = (unsigned char)64;                /* invalid code marker */
+    this.bits = (unsigned char)(len - drop);
+    this.val = (unsigned short)0;
+    while (huff != 0) {
+        /* when done with sub-table, drop back to root table */
+        if (drop != 0 && (huff & mask) != low) {
+            drop = 0;
+            len = root;
+            next = *table;
+            this.bits = (unsigned char)len;
+        }
+
+        /* put invalid code marker in table */
+        next[huff >> drop] = this;
+
+        /* backwards increment the len-bit code huff */
+        incr = 1U << (len - 1);
+        while (huff & incr)
+            incr >>= 1;
+        if (incr != 0) {
+            huff &= incr - 1;
+            huff += incr;
+        }
+        else
+            huff = 0;
+    }
+
+    /* set return parameters */
+    *table += used;
+    *bits = root;
+    return 0;
+}
diff --git a/usr/klibc/zlib/inftrees.h b/usr/klibc/zlib/inftrees.h
new file mode 100644
index 0000000..b1104c8
--- /dev/null
+++ b/usr/klibc/zlib/inftrees.h
@@ -0,0 +1,55 @@
+/* inftrees.h -- header to use inftrees.c
+ * Copyright (C) 1995-2005 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* WARNING: this file should *not* be used by applications. It is
+   part of the implementation of the compression library and is
+   subject to change. Applications should only use zlib.h.
+ */
+
+/* Structure for decoding tables.  Each entry provides either the
+   information needed to do the operation requested by the code that
+   indexed that table entry, or it provides a pointer to another
+   table that indexes more bits of the code.  op indicates whether
+   the entry is a pointer to another table, a literal, a length or
+   distance, an end-of-block, or an invalid code.  For a table
+   pointer, the low four bits of op is the number of index bits of
+   that table.  For a length or distance, the low four bits of op
+   is the number of extra bits to get after the code.  bits is
+   the number of bits in this code or part of the code to drop off
+   of the bit buffer.  val is the actual byte to output in the case
+   of a literal, the base length or distance, or the offset from
+   the current table to the next table.  Each entry is four bytes. */
+typedef struct {
+    unsigned char op;           /* operation, extra bits, table bits */
+    unsigned char bits;         /* bits in this part of the code */
+    unsigned short val;         /* offset in table or code value */
+} code;
+
+/* op values as set by inflate_table():
+    00000000 - literal
+    0000tttt - table link, tttt != 0 is the number of table index bits
+    0001eeee - length or distance, eeee is the number of extra bits
+    01100000 - end of block
+    01000000 - invalid code
+ */
+
+/* Maximum size of dynamic tree.  The maximum found in a long but non-
+   exhaustive search was 1444 code structures (852 for length/literals
+   and 592 for distances, the latter actually the result of an
+   exhaustive search).  The true maximum is not known, but the value
+   below is more than safe. */
+#define ENOUGH 2048
+#define MAXD 592
+
+/* Type of code to build for inftable() */
+typedef enum {
+    CODES,
+    LENS,
+    DISTS
+} codetype;
+
+extern int inflate_table OF((codetype type, unsigned short FAR *lens,
+                             unsigned codes, code FAR * FAR *table,
+                             unsigned FAR *bits, unsigned short FAR *work));
diff --git a/usr/klibc/zlib/trees.c b/usr/klibc/zlib/trees.c
new file mode 100644
index 0000000..82578a1
--- /dev/null
+++ b/usr/klibc/zlib/trees.c
@@ -0,0 +1,1219 @@
+/* trees.c -- output deflated data using Huffman coding
+ * Copyright (C) 1995-2005 Jean-loup Gailly
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/*
+ *  ALGORITHM
+ *
+ *      The "deflation" process uses several Huffman trees. The more
+ *      common source values are represented by shorter bit sequences.
+ *
+ *      Each code tree is stored in a compressed form which is itself
+ * a Huffman encoding of the lengths of all the code strings (in
+ * ascending order by source values).  The actual code strings are
+ * reconstructed from the lengths in the inflate process, as described
+ * in the deflate specification.
+ *
+ *  REFERENCES
+ *
+ *      Deutsch, L.P.,"'Deflate' Compressed Data Format Specification".
+ *      Available in ftp.uu.net:/pub/archiving/zip/doc/deflate-1.1.doc
+ *
+ *      Storer, James A.
+ *          Data Compression:  Methods and Theory, pp. 49-50.
+ *          Computer Science Press, 1988.  ISBN 0-7167-8156-5.
+ *
+ *      Sedgewick, R.
+ *          Algorithms, p290.
+ *          Addison-Wesley, 1983. ISBN 0-201-06672-6.
+ */
+
+/* @(#) $Id: trees.c,v 1.1 2005/02/27 23:15:39 hpa Exp $ */
+
+/* #define GEN_TREES_H */
+
+#include "deflate.h"
+
+#ifdef DEBUG
+#  include <ctype.h>
+#endif
+
+/* ===========================================================================
+ * Constants
+ */
+
+#define MAX_BL_BITS 7
+/* Bit length codes must not exceed MAX_BL_BITS bits */
+
+#define END_BLOCK 256
+/* end of block literal code */
+
+#define REP_3_6      16
+/* repeat previous bit length 3-6 times (2 bits of repeat count) */
+
+#define REPZ_3_10    17
+/* repeat a zero length 3-10 times  (3 bits of repeat count) */
+
+#define REPZ_11_138  18
+/* repeat a zero length 11-138 times  (7 bits of repeat count) */
+
+local const int extra_lbits[LENGTH_CODES] /* extra bits for each length code */
+   = {0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0};
+
+local const int extra_dbits[D_CODES] /* extra bits for each distance code */
+   = {0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13};
+
+local const int extra_blbits[BL_CODES]/* extra bits for each bit length code */
+   = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,7};
+
+local const uch bl_order[BL_CODES]
+   = {16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15};
+/* The lengths of the bit length codes are sent in order of decreasing
+ * probability, to avoid transmitting the lengths for unused bit length codes.
+ */
+
+#define Buf_size (8 * 2*sizeof(char))
+/* Number of bits used within bi_buf. (bi_buf might be implemented on
+ * more than 16 bits on some systems.)
+ */
+
+/* ===========================================================================
+ * Local data. These are initialized only once.
+ */
+
+#define DIST_CODE_LEN  512 /* see definition of array dist_code below */
+
+#if defined(GEN_TREES_H) || !defined(STDC)
+/* non ANSI compilers may not accept trees.h */
+
+local ct_data static_ltree[L_CODES+2];
+/* The static literal tree. Since the bit lengths are imposed, there is no
+ * need for the L_CODES extra codes used during heap construction. However
+ * The codes 286 and 287 are needed to build a canonical tree (see _tr_init
+ * below).
+ */
+
+local ct_data static_dtree[D_CODES];
+/* The static distance tree. (Actually a trivial tree since all codes use
+ * 5 bits.)
+ */
+
+uch _dist_code[DIST_CODE_LEN];
+/* Distance codes. The first 256 values correspond to the distances
+ * 3 .. 258, the last 256 values correspond to the top 8 bits of
+ * the 15 bit distances.
+ */
+
+uch _length_code[MAX_MATCH-MIN_MATCH+1];
+/* length code for each normalized match length (0 == MIN_MATCH) */
+
+local int base_length[LENGTH_CODES];
+/* First normalized length for each code (0 = MIN_MATCH) */
+
+local int base_dist[D_CODES];
+/* First normalized distance for each code (0 = distance of 1) */
+
+#else
+#  include "trees.h"
+#endif /* GEN_TREES_H */
+
+struct static_tree_desc_s {
+    const ct_data *static_tree;  /* static tree or NULL */
+    const intf *extra_bits;      /* extra bits for each code or NULL */
+    int     extra_base;          /* base index for extra_bits */
+    int     elems;               /* max number of elements in the tree */
+    int     max_length;          /* max bit length for the codes */
+};
+
+local static_tree_desc  static_l_desc =
+{static_ltree, extra_lbits, LITERALS+1, L_CODES, MAX_BITS};
+
+local static_tree_desc  static_d_desc =
+{static_dtree, extra_dbits, 0,          D_CODES, MAX_BITS};
+
+local static_tree_desc  static_bl_desc =
+{(const ct_data *)0, extra_blbits, 0,   BL_CODES, MAX_BL_BITS};
+
+/* ===========================================================================
+ * Local (static) routines in this file.
+ */
+
+local void tr_static_init OF((void));
+local void init_block     OF((deflate_state *s));
+local void pqdownheap     OF((deflate_state *s, ct_data *tree, int k));
+local void gen_bitlen     OF((deflate_state *s, tree_desc *desc));
+local void gen_codes      OF((ct_data *tree, int max_code, ushf *bl_count));
+local void build_tree     OF((deflate_state *s, tree_desc *desc));
+local void scan_tree      OF((deflate_state *s, ct_data *tree, int max_code));
+local void send_tree      OF((deflate_state *s, ct_data *tree, int max_code));
+local int  build_bl_tree  OF((deflate_state *s));
+local void send_all_trees OF((deflate_state *s, int lcodes, int dcodes,
+                              int blcodes));
+local void compress_block OF((deflate_state *s, ct_data *ltree,
+                              ct_data *dtree));
+local void set_data_type  OF((deflate_state *s));
+local unsigned bi_reverse OF((unsigned value, int length));
+local void bi_windup      OF((deflate_state *s));
+local void bi_flush       OF((deflate_state *s));
+local void copy_block     OF((deflate_state *s, charf *buf, unsigned len,
+                              int header));
+
+#ifdef GEN_TREES_H
+local void gen_trees_header OF((void));
+#endif
+
+#ifndef DEBUG
+#  define send_code(s, c, tree) send_bits(s, tree[c].Code, tree[c].Len)
+   /* Send a code of the given tree. c and tree must not have side effects */
+
+#else /* DEBUG */
+#  define send_code(s, c, tree) \
+     { if (z_verbose>2) fprintf(stderr,"\ncd %3d ",(c)); \
+       send_bits(s, tree[c].Code, tree[c].Len); }
+#endif
+
+/* ===========================================================================
+ * Output a short LSB first on the stream.
+ * IN assertion: there is enough room in pendingBuf.
+ */
+#define put_short(s, w) { \
+    put_byte(s, (uch)((w) & 0xff)); \
+    put_byte(s, (uch)((ush)(w) >> 8)); \
+}
+
+/* ===========================================================================
+ * Send a value on a given number of bits.
+ * IN assertion: length <= 16 and value fits in length bits.
+ */
+#ifdef DEBUG
+local void send_bits      OF((deflate_state *s, int value, int length));
+
+local void send_bits(s, value, length)
+    deflate_state *s;
+    int value;  /* value to send */
+    int length; /* number of bits */
+{
+    Tracevv((stderr," l %2d v %4x ", length, value));
+    Assert(length > 0 && length <= 15, "invalid length");
+    s->bits_sent += (ulg)length;
+
+    /* If not enough room in bi_buf, use (valid) bits from bi_buf and
+     * (16 - bi_valid) bits from value, leaving (width - (16-bi_valid))
+     * unused bits in value.
+     */
+    if (s->bi_valid > (int)Buf_size - length) {
+        s->bi_buf |= (value << s->bi_valid);
+        put_short(s, s->bi_buf);
+        s->bi_buf = (ush)value >> (Buf_size - s->bi_valid);
+        s->bi_valid += length - Buf_size;
+    } else {
+        s->bi_buf |= value << s->bi_valid;
+        s->bi_valid += length;
+    }
+}
+#else /* !DEBUG */
+
+#define send_bits(s, value, length) \
+{ int len = length;\
+  if (s->bi_valid > (int)Buf_size - len) {\
+    int val = value;\
+    s->bi_buf |= (val << s->bi_valid);\
+    put_short(s, s->bi_buf);\
+    s->bi_buf = (ush)val >> (Buf_size - s->bi_valid);\
+    s->bi_valid += len - Buf_size;\
+  } else {\
+    s->bi_buf |= (value) << s->bi_valid;\
+    s->bi_valid += len;\
+  }\
+}
+#endif /* DEBUG */
+
+
+/* the arguments must not have side effects */
+
+/* ===========================================================================
+ * Initialize the various 'constant' tables.
+ */
+local void tr_static_init()
+{
+#if defined(GEN_TREES_H) || !defined(STDC)
+    static int static_init_done = 0;
+    int n;        /* iterates over tree elements */
+    int bits;     /* bit counter */
+    int length;   /* length value */
+    int code;     /* code value */
+    int dist;     /* distance index */
+    ush bl_count[MAX_BITS+1];
+    /* number of codes at each bit length for an optimal tree */
+
+    if (static_init_done) return;
+
+    /* For some embedded targets, global variables are not initialized: */
+    static_l_desc.static_tree = static_ltree;
+    static_l_desc.extra_bits = extra_lbits;
+    static_d_desc.static_tree = static_dtree;
+    static_d_desc.extra_bits = extra_dbits;
+    static_bl_desc.extra_bits = extra_blbits;
+
+    /* Initialize the mapping length (0..255) -> length code (0..28) */
+    length = 0;
+    for (code = 0; code < LENGTH_CODES-1; code++) {
+        base_length[code] = length;
+        for (n = 0; n < (1<<extra_lbits[code]); n++) {
+            _length_code[length++] = (uch)code;
+        }
+    }
+    Assert (length == 256, "tr_static_init: length != 256");
+    /* Note that the length 255 (match length 258) can be represented
+     * in two different ways: code 284 + 5 bits or code 285, so we
+     * overwrite length_code[255] to use the best encoding:
+     */
+    _length_code[length-1] = (uch)code;
+
+    /* Initialize the mapping dist (0..32K) -> dist code (0..29) */
+    dist = 0;
+    for (code = 0 ; code < 16; code++) {
+        base_dist[code] = dist;
+        for (n = 0; n < (1<<extra_dbits[code]); n++) {
+            _dist_code[dist++] = (uch)code;
+        }
+    }
+    Assert (dist == 256, "tr_static_init: dist != 256");
+    dist >>= 7; /* from now on, all distances are divided by 128 */
+    for ( ; code < D_CODES; code++) {
+        base_dist[code] = dist << 7;
+        for (n = 0; n < (1<<(extra_dbits[code]-7)); n++) {
+            _dist_code[256 + dist++] = (uch)code;
+        }
+    }
+    Assert (dist == 256, "tr_static_init: 256+dist != 512");
+
+    /* Construct the codes of the static literal tree */
+    for (bits = 0; bits <= MAX_BITS; bits++) bl_count[bits] = 0;
+    n = 0;
+    while (n <= 143) static_ltree[n++].Len = 8, bl_count[8]++;
+    while (n <= 255) static_ltree[n++].Len = 9, bl_count[9]++;
+    while (n <= 279) static_ltree[n++].Len = 7, bl_count[7]++;
+    while (n <= 287) static_ltree[n++].Len = 8, bl_count[8]++;
+    /* Codes 286 and 287 do not exist, but we must include them in the
+     * tree construction to get a canonical Huffman tree (longest code
+     * all ones)
+     */
+    gen_codes((ct_data *)static_ltree, L_CODES+1, bl_count);
+
+    /* The static distance tree is trivial: */
+    for (n = 0; n < D_CODES; n++) {
+        static_dtree[n].Len = 5;
+        static_dtree[n].Code = bi_reverse((unsigned)n, 5);
+    }
+    static_init_done = 1;
+
+#  ifdef GEN_TREES_H
+    gen_trees_header();
+#  endif
+#endif /* defined(GEN_TREES_H) || !defined(STDC) */
+}
+
+/* ===========================================================================
+ * Genererate the file trees.h describing the static trees.
+ */
+#ifdef GEN_TREES_H
+#  ifndef DEBUG
+#    include <stdio.h>
+#  endif
+
+#  define SEPARATOR(i, last, width) \
+      ((i) == (last)? "\n};\n\n" :    \
+       ((i) % (width) == (width)-1 ? ",\n" : ", "))
+
+void gen_trees_header()
+{
+    FILE *header = fopen("trees.h", "w");
+    int i;
+
+    Assert (header != NULL, "Can't open trees.h");
+    fprintf(header,
+            "/* header created automatically with -DGEN_TREES_H */\n\n");
+
+    fprintf(header, "local const ct_data static_ltree[L_CODES+2] = {\n");
+    for (i = 0; i < L_CODES+2; i++) {
+        fprintf(header, "{{%3u},{%3u}}%s", static_ltree[i].Code,
+                static_ltree[i].Len, SEPARATOR(i, L_CODES+1, 5));
+    }
+
+    fprintf(header, "local const ct_data static_dtree[D_CODES] = {\n");
+    for (i = 0; i < D_CODES; i++) {
+        fprintf(header, "{{%2u},{%2u}}%s", static_dtree[i].Code,
+                static_dtree[i].Len, SEPARATOR(i, D_CODES-1, 5));
+    }
+
+    fprintf(header, "const uch _dist_code[DIST_CODE_LEN] = {\n");
+    for (i = 0; i < DIST_CODE_LEN; i++) {
+        fprintf(header, "%2u%s", _dist_code[i],
+                SEPARATOR(i, DIST_CODE_LEN-1, 20));
+    }
+
+    fprintf(header, "const uch _length_code[MAX_MATCH-MIN_MATCH+1]= {\n");
+    for (i = 0; i < MAX_MATCH-MIN_MATCH+1; i++) {
+        fprintf(header, "%2u%s", _length_code[i],
+                SEPARATOR(i, MAX_MATCH-MIN_MATCH, 20));
+    }
+
+    fprintf(header, "local const int base_length[LENGTH_CODES] = {\n");
+    for (i = 0; i < LENGTH_CODES; i++) {
+        fprintf(header, "%1u%s", base_length[i],
+                SEPARATOR(i, LENGTH_CODES-1, 20));
+    }
+
+    fprintf(header, "local const int base_dist[D_CODES] = {\n");
+    for (i = 0; i < D_CODES; i++) {
+        fprintf(header, "%5u%s", base_dist[i],
+                SEPARATOR(i, D_CODES-1, 10));
+    }
+
+    fclose(header);
+}
+#endif /* GEN_TREES_H */
+
+/* ===========================================================================
+ * Initialize the tree data structures for a new zlib stream.
+ */
+void _tr_init(s)
+    deflate_state *s;
+{
+    tr_static_init();
+
+    s->l_desc.dyn_tree = s->dyn_ltree;
+    s->l_desc.stat_desc = &static_l_desc;
+
+    s->d_desc.dyn_tree = s->dyn_dtree;
+    s->d_desc.stat_desc = &static_d_desc;
+
+    s->bl_desc.dyn_tree = s->bl_tree;
+    s->bl_desc.stat_desc = &static_bl_desc;
+
+    s->bi_buf = 0;
+    s->bi_valid = 0;
+    s->last_eob_len = 8; /* enough lookahead for inflate */
+#ifdef DEBUG
+    s->compressed_len = 0L;
+    s->bits_sent = 0L;
+#endif
+
+    /* Initialize the first block of the first file: */
+    init_block(s);
+}
+
+/* ===========================================================================
+ * Initialize a new block.
+ */
+local void init_block(s)
+    deflate_state *s;
+{
+    int n; /* iterates over tree elements */
+
+    /* Initialize the trees. */
+    for (n = 0; n < L_CODES;  n++) s->dyn_ltree[n].Freq = 0;
+    for (n = 0; n < D_CODES;  n++) s->dyn_dtree[n].Freq = 0;
+    for (n = 0; n < BL_CODES; n++) s->bl_tree[n].Freq = 0;
+
+    s->dyn_ltree[END_BLOCK].Freq = 1;
+    s->opt_len = s->static_len = 0L;
+    s->last_lit = s->matches = 0;
+}
+
+#define SMALLEST 1
+/* Index within the heap array of least frequent node in the Huffman tree */
+
+
+/* ===========================================================================
+ * Remove the smallest element from the heap and recreate the heap with
+ * one less element. Updates heap and heap_len.
+ */
+#define pqremove(s, tree, top) \
+{\
+    top = s->heap[SMALLEST]; \
+    s->heap[SMALLEST] = s->heap[s->heap_len--]; \
+    pqdownheap(s, tree, SMALLEST); \
+}
+
+/* ===========================================================================
+ * Compares to subtrees, using the tree depth as tie breaker when
+ * the subtrees have equal frequency. This minimizes the worst case length.
+ */
+#define smaller(tree, n, m, depth) \
+   (tree[n].Freq < tree[m].Freq || \
+   (tree[n].Freq == tree[m].Freq && depth[n] <= depth[m]))
+
+/* ===========================================================================
+ * Restore the heap property by moving down the tree starting at node k,
+ * exchanging a node with the smallest of its two sons if necessary, stopping
+ * when the heap property is re-established (each father smaller than its
+ * two sons).
+ */
+local void pqdownheap(s, tree, k)
+    deflate_state *s;
+    ct_data *tree;  /* the tree to restore */
+    int k;               /* node to move down */
+{
+    int v = s->heap[k];
+    int j = k << 1;  /* left son of k */
+    while (j <= s->heap_len) {
+        /* Set j to the smallest of the two sons: */
+        if (j < s->heap_len &&
+            smaller(tree, s->heap[j+1], s->heap[j], s->depth)) {
+            j++;
+        }
+        /* Exit if v is smaller than both sons */
+        if (smaller(tree, v, s->heap[j], s->depth)) break;
+
+        /* Exchange v with the smallest son */
+        s->heap[k] = s->heap[j];  k = j;
+
+        /* And continue down the tree, setting j to the left son of k */
+        j <<= 1;
+    }
+    s->heap[k] = v;
+}
+
+/* ===========================================================================
+ * Compute the optimal bit lengths for a tree and update the total bit length
+ * for the current block.
+ * IN assertion: the fields freq and dad are set, heap[heap_max] and
+ *    above are the tree nodes sorted by increasing frequency.
+ * OUT assertions: the field len is set to the optimal bit length, the
+ *     array bl_count contains the frequencies for each bit length.
+ *     The length opt_len is updated; static_len is also updated if stree is
+ *     not null.
+ */
+local void gen_bitlen(s, desc)
+    deflate_state *s;
+    tree_desc *desc;    /* the tree descriptor */
+{
+    ct_data *tree        = desc->dyn_tree;
+    int max_code         = desc->max_code;
+    const ct_data *stree = desc->stat_desc->static_tree;
+    const intf *extra    = desc->stat_desc->extra_bits;
+    int base             = desc->stat_desc->extra_base;
+    int max_length       = desc->stat_desc->max_length;
+    int h;              /* heap index */
+    int n, m;           /* iterate over the tree elements */
+    int bits;           /* bit length */
+    int xbits;          /* extra bits */
+    ush f;              /* frequency */
+    int overflow = 0;   /* number of elements with bit length too large */
+
+    for (bits = 0; bits <= MAX_BITS; bits++) s->bl_count[bits] = 0;
+
+    /* In a first pass, compute the optimal bit lengths (which may
+     * overflow in the case of the bit length tree).
+     */
+    tree[s->heap[s->heap_max]].Len = 0; /* root of the heap */
+
+    for (h = s->heap_max+1; h < HEAP_SIZE; h++) {
+        n = s->heap[h];
+        bits = tree[tree[n].Dad].Len + 1;
+        if (bits > max_length) bits = max_length, overflow++;
+        tree[n].Len = (ush)bits;
+        /* We overwrite tree[n].Dad which is no longer needed */
+
+        if (n > max_code) continue; /* not a leaf node */
+
+        s->bl_count[bits]++;
+        xbits = 0;
+        if (n >= base) xbits = extra[n-base];
+        f = tree[n].Freq;
+        s->opt_len += (ulg)f * (bits + xbits);
+        if (stree) s->static_len += (ulg)f * (stree[n].Len + xbits);
+    }
+    if (overflow == 0) return;
+
+    Trace((stderr,"\nbit length overflow\n"));
+    /* This happens for example on obj2 and pic of the Calgary corpus */
+
+    /* Find the first bit length which could increase: */
+    do {
+        bits = max_length-1;
+        while (s->bl_count[bits] == 0) bits--;
+        s->bl_count[bits]--;      /* move one leaf down the tree */
+        s->bl_count[bits+1] += 2; /* move one overflow item as its brother */
+        s->bl_count[max_length]--;
+        /* The brother of the overflow item also moves one step up,
+         * but this does not affect bl_count[max_length]
+         */
+        overflow -= 2;
+    } while (overflow > 0);
+
+    /* Now recompute all bit lengths, scanning in increasing frequency.
+     * h is still equal to HEAP_SIZE. (It is simpler to reconstruct all
+     * lengths instead of fixing only the wrong ones. This idea is taken
+     * from 'ar' written by Haruhiko Okumura.)
+     */
+    for (bits = max_length; bits != 0; bits--) {
+        n = s->bl_count[bits];
+        while (n != 0) {
+            m = s->heap[--h];
+            if (m > max_code) continue;
+            if ((unsigned) tree[m].Len != (unsigned) bits) {
+                Trace((stderr,"code %d bits %d->%d\n", m, tree[m].Len, bits));
+                s->opt_len += ((long)bits - (long)tree[m].Len)
+                              *(long)tree[m].Freq;
+                tree[m].Len = (ush)bits;
+            }
+            n--;
+        }
+    }
+}
+
+/* ===========================================================================
+ * Generate the codes for a given tree and bit counts (which need not be
+ * optimal).
+ * IN assertion: the array bl_count contains the bit length statistics for
+ * the given tree and the field len is set for all tree elements.
+ * OUT assertion: the field code is set for all tree elements of non
+ *     zero code length.
+ */
+local void gen_codes (tree, max_code, bl_count)
+    ct_data *tree;             /* the tree to decorate */
+    int max_code;              /* largest code with non zero frequency */
+    ushf *bl_count;            /* number of codes at each bit length */
+{
+    ush next_code[MAX_BITS+1]; /* next code value for each bit length */
+    ush code = 0;              /* running code value */
+    int bits;                  /* bit index */
+    int n;                     /* code index */
+
+    /* The distribution counts are first used to generate the code values
+     * without bit reversal.
+     */
+    for (bits = 1; bits <= MAX_BITS; bits++) {
+        next_code[bits] = code = (code + bl_count[bits-1]) << 1;
+    }
+    /* Check that the bit counts in bl_count are consistent. The last code
+     * must be all ones.
+     */
+    Assert (code + bl_count[MAX_BITS]-1 == (1<<MAX_BITS)-1,
+            "inconsistent bit counts");
+    Tracev((stderr,"\ngen_codes: max_code %d ", max_code));
+
+    for (n = 0;  n <= max_code; n++) {
+        int len = tree[n].Len;
+        if (len == 0) continue;
+        /* Now reverse the bits */
+        tree[n].Code = bi_reverse(next_code[len]++, len);
+
+        Tracecv(tree != static_ltree, (stderr,"\nn %3d %c l %2d c %4x (%x) ",
+             n, (isgraph(n) ? n : ' '), len, tree[n].Code, next_code[len]-1));
+    }
+}
+
+/* ===========================================================================
+ * Construct one Huffman tree and assigns the code bit strings and lengths.
+ * Update the total bit length for the current block.
+ * IN assertion: the field freq is set for all tree elements.
+ * OUT assertions: the fields len and code are set to the optimal bit length
+ *     and corresponding code. The length opt_len is updated; static_len is
+ *     also updated if stree is not null. The field max_code is set.
+ */
+local void build_tree(s, desc)
+    deflate_state *s;
+    tree_desc *desc; /* the tree descriptor */
+{
+    ct_data *tree         = desc->dyn_tree;
+    const ct_data *stree  = desc->stat_desc->static_tree;
+    int elems             = desc->stat_desc->elems;
+    int n, m;          /* iterate over heap elements */
+    int max_code = -1; /* largest code with non zero frequency */
+    int node;          /* new node being created */
+
+    /* Construct the initial heap, with least frequent element in
+     * heap[SMALLEST]. The sons of heap[n] are heap[2*n] and heap[2*n+1].
+     * heap[0] is not used.
+     */
+    s->heap_len = 0, s->heap_max = HEAP_SIZE;
+
+    for (n = 0; n < elems; n++) {
+        if (tree[n].Freq != 0) {
+            s->heap[++(s->heap_len)] = max_code = n;
+            s->depth[n] = 0;
+        } else {
+            tree[n].Len = 0;
+        }
+    }
+
+    /* The pkzip format requires that at least one distance code exists,
+     * and that at least one bit should be sent even if there is only one
+     * possible code. So to avoid special checks later on we force at least
+     * two codes of non zero frequency.
+     */
+    while (s->heap_len < 2) {
+        node = s->heap[++(s->heap_len)] = (max_code < 2 ? ++max_code : 0);
+        tree[node].Freq = 1;
+        s->depth[node] = 0;
+        s->opt_len--; if (stree) s->static_len -= stree[node].Len;
+        /* node is 0 or 1 so it does not have extra bits */
+    }
+    desc->max_code = max_code;
+
+    /* The elements heap[heap_len/2+1 .. heap_len] are leaves of the tree,
+     * establish sub-heaps of increasing lengths:
+     */
+    for (n = s->heap_len/2; n >= 1; n--) pqdownheap(s, tree, n);
+
+    /* Construct the Huffman tree by repeatedly combining the least two
+     * frequent nodes.
+     */
+    node = elems;              /* next internal node of the tree */
+    do {
+        pqremove(s, tree, n);  /* n = node of least frequency */
+        m = s->heap[SMALLEST]; /* m = node of next least frequency */
+
+        s->heap[--(s->heap_max)] = n; /* keep the nodes sorted by frequency */
+        s->heap[--(s->heap_max)] = m;
+
+        /* Create a new node father of n and m */
+        tree[node].Freq = tree[n].Freq + tree[m].Freq;
+        s->depth[node] = (uch)((s->depth[n] >= s->depth[m] ?
+                                s->depth[n] : s->depth[m]) + 1);
+        tree[n].Dad = tree[m].Dad = (ush)node;
+#ifdef DUMP_BL_TREE
+        if (tree == s->bl_tree) {
+            fprintf(stderr,"\nnode %d(%d), sons %d(%d) %d(%d)",
+                    node, tree[node].Freq, n, tree[n].Freq, m, tree[m].Freq);
+        }
+#endif
+        /* and insert the new node in the heap */
+        s->heap[SMALLEST] = node++;
+        pqdownheap(s, tree, SMALLEST);
+
+    } while (s->heap_len >= 2);
+
+    s->heap[--(s->heap_max)] = s->heap[SMALLEST];
+
+    /* At this point, the fields freq and dad are set. We can now
+     * generate the bit lengths.
+     */
+    gen_bitlen(s, (tree_desc *)desc);
+
+    /* The field len is now set, we can generate the bit codes */
+    gen_codes ((ct_data *)tree, max_code, s->bl_count);
+}
+
+/* ===========================================================================
+ * Scan a literal or distance tree to determine the frequencies of the codes
+ * in the bit length tree.
+ */
+local void scan_tree (s, tree, max_code)
+    deflate_state *s;
+    ct_data *tree;   /* the tree to be scanned */
+    int max_code;    /* and its largest code of non zero frequency */
+{
+    int n;                     /* iterates over all tree elements */
+    int prevlen = -1;          /* last emitted length */
+    int curlen;                /* length of current code */
+    int nextlen = tree[0].Len; /* length of next code */
+    int count = 0;             /* repeat count of the current code */
+    int max_count = 7;         /* max repeat count */
+    int min_count = 4;         /* min repeat count */
+
+    if (nextlen == 0) max_count = 138, min_count = 3;
+    tree[max_code+1].Len = (ush)0xffff; /* guard */
+
+    for (n = 0; n <= max_code; n++) {
+        curlen = nextlen; nextlen = tree[n+1].Len;
+        if (++count < max_count && curlen == nextlen) {
+            continue;
+        } else if (count < min_count) {
+            s->bl_tree[curlen].Freq += count;
+        } else if (curlen != 0) {
+            if (curlen != prevlen) s->bl_tree[curlen].Freq++;
+            s->bl_tree[REP_3_6].Freq++;
+        } else if (count <= 10) {
+            s->bl_tree[REPZ_3_10].Freq++;
+        } else {
+            s->bl_tree[REPZ_11_138].Freq++;
+        }
+        count = 0; prevlen = curlen;
+        if (nextlen == 0) {
+            max_count = 138, min_count = 3;
+        } else if (curlen == nextlen) {
+            max_count = 6, min_count = 3;
+        } else {
+            max_count = 7, min_count = 4;
+        }
+    }
+}
+
+/* ===========================================================================
+ * Send a literal or distance tree in compressed form, using the codes in
+ * bl_tree.
+ */
+local void send_tree (s, tree, max_code)
+    deflate_state *s;
+    ct_data *tree; /* the tree to be scanned */
+    int max_code;       /* and its largest code of non zero frequency */
+{
+    int n;                     /* iterates over all tree elements */
+    int prevlen = -1;          /* last emitted length */
+    int curlen;                /* length of current code */
+    int nextlen = tree[0].Len; /* length of next code */
+    int count = 0;             /* repeat count of the current code */
+    int max_count = 7;         /* max repeat count */
+    int min_count = 4;         /* min repeat count */
+
+    /* tree[max_code+1].Len = -1; */  /* guard already set */
+    if (nextlen == 0) max_count = 138, min_count = 3;
+
+    for (n = 0; n <= max_code; n++) {
+        curlen = nextlen; nextlen = tree[n+1].Len;
+        if (++count < max_count && curlen == nextlen) {
+            continue;
+        } else if (count < min_count) {
+            do { send_code(s, curlen, s->bl_tree); } while (--count != 0);
+
+        } else if (curlen != 0) {
+            if (curlen != prevlen) {
+                send_code(s, curlen, s->bl_tree); count--;
+            }
+            Assert(count >= 3 && count <= 6, " 3_6?");
+            send_code(s, REP_3_6, s->bl_tree); send_bits(s, count-3, 2);
+
+        } else if (count <= 10) {
+            send_code(s, REPZ_3_10, s->bl_tree); send_bits(s, count-3, 3);
+
+        } else {
+            send_code(s, REPZ_11_138, s->bl_tree); send_bits(s, count-11, 7);
+        }
+        count = 0; prevlen = curlen;
+        if (nextlen == 0) {
+            max_count = 138, min_count = 3;
+        } else if (curlen == nextlen) {
+            max_count = 6, min_count = 3;
+        } else {
+            max_count = 7, min_count = 4;
+        }
+    }
+}
+
+/* ===========================================================================
+ * Construct the Huffman tree for the bit lengths and return the index in
+ * bl_order of the last bit length code to send.
+ */
+local int build_bl_tree(s)
+    deflate_state *s;
+{
+    int max_blindex;  /* index of last bit length code of non zero freq */
+
+    /* Determine the bit length frequencies for literal and distance trees */
+    scan_tree(s, (ct_data *)s->dyn_ltree, s->l_desc.max_code);
+    scan_tree(s, (ct_data *)s->dyn_dtree, s->d_desc.max_code);
+
+    /* Build the bit length tree: */
+    build_tree(s, (tree_desc *)(&(s->bl_desc)));
+    /* opt_len now includes the length of the tree representations, except
+     * the lengths of the bit lengths codes and the 5+5+4 bits for the counts.
+     */
+
+    /* Determine the number of bit length codes to send. The pkzip format
+     * requires that at least 4 bit length codes be sent. (appnote.txt says
+     * 3 but the actual value used is 4.)
+     */
+    for (max_blindex = BL_CODES-1; max_blindex >= 3; max_blindex--) {
+        if (s->bl_tree[bl_order[max_blindex]].Len != 0) break;
+    }
+    /* Update opt_len to include the bit length tree and counts */
+    s->opt_len += 3*(max_blindex+1) + 5+5+4;
+    Tracev((stderr, "\ndyn trees: dyn %ld, stat %ld",
+            s->opt_len, s->static_len));
+
+    return max_blindex;
+}
+
+/* ===========================================================================
+ * Send the header for a block using dynamic Huffman trees: the counts, the
+ * lengths of the bit length codes, the literal tree and the distance tree.
+ * IN assertion: lcodes >= 257, dcodes >= 1, blcodes >= 4.
+ */
+local void send_all_trees(s, lcodes, dcodes, blcodes)
+    deflate_state *s;
+    int lcodes, dcodes, blcodes; /* number of codes for each tree */
+{
+    int rank;                    /* index in bl_order */
+
+    Assert (lcodes >= 257 && dcodes >= 1 && blcodes >= 4, "not enough codes");
+    Assert (lcodes <= L_CODES && dcodes <= D_CODES && blcodes <= BL_CODES,
+            "too many codes");
+    Tracev((stderr, "\nbl counts: "));
+    send_bits(s, lcodes-257, 5); /* not +255 as stated in appnote.txt */
+    send_bits(s, dcodes-1,   5);
+    send_bits(s, blcodes-4,  4); /* not -3 as stated in appnote.txt */
+    for (rank = 0; rank < blcodes; rank++) {
+        Tracev((stderr, "\nbl code %2d ", bl_order[rank]));
+        send_bits(s, s->bl_tree[bl_order[rank]].Len, 3);
+    }
+    Tracev((stderr, "\nbl tree: sent %ld", s->bits_sent));
+
+    send_tree(s, (ct_data *)s->dyn_ltree, lcodes-1); /* literal tree */
+    Tracev((stderr, "\nlit tree: sent %ld", s->bits_sent));
+
+    send_tree(s, (ct_data *)s->dyn_dtree, dcodes-1); /* distance tree */
+    Tracev((stderr, "\ndist tree: sent %ld", s->bits_sent));
+}
+
+/* ===========================================================================
+ * Send a stored block
+ */
+void _tr_stored_block(s, buf, stored_len, eof)
+    deflate_state *s;
+    charf *buf;       /* input block */
+    ulg stored_len;   /* length of input block */
+    int eof;          /* true if this is the last block for a file */
+{
+    send_bits(s, (STORED_BLOCK<<1)+eof, 3);  /* send block type */
+#ifdef DEBUG
+    s->compressed_len = (s->compressed_len + 3 + 7) & (ulg)~7L;
+    s->compressed_len += (stored_len + 4) << 3;
+#endif
+    copy_block(s, buf, (unsigned)stored_len, 1); /* with header */
+}
+
+/* ===========================================================================
+ * Send one empty static block to give enough lookahead for inflate.
+ * This takes 10 bits, of which 7 may remain in the bit buffer.
+ * The current inflate code requires 9 bits of lookahead. If the
+ * last two codes for the previous block (real code plus EOB) were coded
+ * on 5 bits or less, inflate may have only 5+3 bits of lookahead to decode
+ * the last real code. In this case we send two empty static blocks instead
+ * of one. (There are no problems if the previous block is stored or fixed.)
+ * To simplify the code, we assume the worst case of last real code encoded
+ * on one bit only.
+ */
+void _tr_align(s)
+    deflate_state *s;
+{
+    send_bits(s, STATIC_TREES<<1, 3);
+    send_code(s, END_BLOCK, static_ltree);
+#ifdef DEBUG
+    s->compressed_len += 10L; /* 3 for block type, 7 for EOB */
+#endif
+    bi_flush(s);
+    /* Of the 10 bits for the empty block, we have already sent
+     * (10 - bi_valid) bits. The lookahead for the last real code (before
+     * the EOB of the previous block) was thus at least one plus the length
+     * of the EOB plus what we have just sent of the empty static block.
+     */
+    if (1 + s->last_eob_len + 10 - s->bi_valid < 9) {
+        send_bits(s, STATIC_TREES<<1, 3);
+        send_code(s, END_BLOCK, static_ltree);
+#ifdef DEBUG
+        s->compressed_len += 10L;
+#endif
+        bi_flush(s);
+    }
+    s->last_eob_len = 7;
+}
+
+/* ===========================================================================
+ * Determine the best encoding for the current block: dynamic trees, static
+ * trees or store, and output the encoded block to the zip file.
+ */
+void _tr_flush_block(s, buf, stored_len, eof)
+    deflate_state *s;
+    charf *buf;       /* input block, or NULL if too old */
+    ulg stored_len;   /* length of input block */
+    int eof;          /* true if this is the last block for a file */
+{
+    ulg opt_lenb, static_lenb; /* opt_len and static_len in bytes */
+    int max_blindex = 0;  /* index of last bit length code of non zero freq */
+
+    /* Build the Huffman trees unless a stored block is forced */
+    if (s->level > 0) {
+
+        /* Check if the file is binary or text */
+        if (stored_len > 0 && s->strm->data_type == Z_UNKNOWN)
+            set_data_type(s);
+
+        /* Construct the literal and distance trees */
+        build_tree(s, (tree_desc *)(&(s->l_desc)));
+        Tracev((stderr, "\nlit data: dyn %ld, stat %ld", s->opt_len,
+                s->static_len));
+
+        build_tree(s, (tree_desc *)(&(s->d_desc)));
+        Tracev((stderr, "\ndist data: dyn %ld, stat %ld", s->opt_len,
+                s->static_len));
+        /* At this point, opt_len and static_len are the total bit lengths of
+         * the compressed block data, excluding the tree representations.
+         */
+
+        /* Build the bit length tree for the above two trees, and get the index
+         * in bl_order of the last bit length code to send.
+         */
+        max_blindex = build_bl_tree(s);
+
+        /* Determine the best encoding. Compute the block lengths in bytes. */
+        opt_lenb = (s->opt_len+3+7)>>3;
+        static_lenb = (s->static_len+3+7)>>3;
+
+        Tracev((stderr, "\nopt %lu(%lu) stat %lu(%lu) stored %lu lit %u ",
+                opt_lenb, s->opt_len, static_lenb, s->static_len, stored_len,
+                s->last_lit));
+
+        if (static_lenb <= opt_lenb) opt_lenb = static_lenb;
+
+    } else {
+        Assert(buf != (char*)0, "lost buf");
+        opt_lenb = static_lenb = stored_len + 5; /* force a stored block */
+    }
+
+#ifdef FORCE_STORED
+    if (buf != (char*)0) { /* force stored block */
+#else
+    if (stored_len+4 <= opt_lenb && buf != (char*)0) {
+                       /* 4: two words for the lengths */
+#endif
+        /* The test buf != NULL is only necessary if LIT_BUFSIZE > WSIZE.
+         * Otherwise we can't have processed more than WSIZE input bytes since
+         * the last block flush, because compression would have been
+         * successful. If LIT_BUFSIZE <= WSIZE, it is never too late to
+         * transform a block into a stored block.
+         */
+        _tr_stored_block(s, buf, stored_len, eof);
+
+#ifdef FORCE_STATIC
+    } else if (static_lenb >= 0) { /* force static trees */
+#else
+    } else if (s->strategy == Z_FIXED || static_lenb == opt_lenb) {
+#endif
+        send_bits(s, (STATIC_TREES<<1)+eof, 3);
+        compress_block(s, (ct_data *)static_ltree, (ct_data *)static_dtree);
+#ifdef DEBUG
+        s->compressed_len += 3 + s->static_len;
+#endif
+    } else {
+        send_bits(s, (DYN_TREES<<1)+eof, 3);
+        send_all_trees(s, s->l_desc.max_code+1, s->d_desc.max_code+1,
+                       max_blindex+1);
+        compress_block(s, (ct_data *)s->dyn_ltree, (ct_data *)s->dyn_dtree);
+#ifdef DEBUG
+        s->compressed_len += 3 + s->opt_len;
+#endif
+    }
+    Assert (s->compressed_len == s->bits_sent, "bad compressed size");
+    /* The above check is made mod 2^32, for files larger than 512 MB
+     * and uLong implemented on 32 bits.
+     */
+    init_block(s);
+
+    if (eof) {
+        bi_windup(s);
+#ifdef DEBUG
+        s->compressed_len += 7;  /* align on byte boundary */
+#endif
+    }
+    Tracev((stderr,"\ncomprlen %lu(%lu) ", s->compressed_len>>3,
+           s->compressed_len-7*eof));
+}
+
+/* ===========================================================================
+ * Save the match info and tally the frequency counts. Return true if
+ * the current block must be flushed.
+ */
+int _tr_tally (s, dist, lc)
+    deflate_state *s;
+    unsigned dist;  /* distance of matched string */
+    unsigned lc;    /* match length-MIN_MATCH or unmatched char (if dist==0) */
+{
+    s->d_buf[s->last_lit] = (ush)dist;
+    s->l_buf[s->last_lit++] = (uch)lc;
+    if (dist == 0) {
+        /* lc is the unmatched char */
+        s->dyn_ltree[lc].Freq++;
+    } else {
+        s->matches++;
+        /* Here, lc is the match length - MIN_MATCH */
+        dist--;             /* dist = match distance - 1 */
+        Assert((ush)dist < (ush)MAX_DIST(s) &&
+               (ush)lc <= (ush)(MAX_MATCH-MIN_MATCH) &&
+               (ush)d_code(dist) < (ush)D_CODES,  "_tr_tally: bad match");
+
+        s->dyn_ltree[_length_code[lc]+LITERALS+1].Freq++;
+        s->dyn_dtree[d_code(dist)].Freq++;
+    }
+
+#ifdef TRUNCATE_BLOCK
+    /* Try to guess if it is profitable to stop the current block here */
+    if ((s->last_lit & 0x1fff) == 0 && s->level > 2) {
+        /* Compute an upper bound for the compressed length */
+        ulg out_length = (ulg)s->last_lit*8L;
+        ulg in_length = (ulg)((long)s->strstart - s->block_start);
+        int dcode;
+        for (dcode = 0; dcode < D_CODES; dcode++) {
+            out_length += (ulg)s->dyn_dtree[dcode].Freq *
+                (5L+extra_dbits[dcode]);
+        }
+        out_length >>= 3;
+        Tracev((stderr,"\nlast_lit %u, in %ld, out ~%ld(%ld%%) ",
+               s->last_lit, in_length, out_length,
+               100L - out_length*100L/in_length));
+        if (s->matches < s->last_lit/2 && out_length < in_length/2) return 1;
+    }
+#endif
+    return (s->last_lit == s->lit_bufsize-1);
+    /* We avoid equality with lit_bufsize because of wraparound at 64K
+     * on 16 bit machines and because stored blocks are restricted to
+     * 64K-1 bytes.
+     */
+}
+
+/* ===========================================================================
+ * Send the block data compressed using the given Huffman trees
+ */
+local void compress_block(s, ltree, dtree)
+    deflate_state *s;
+    ct_data *ltree; /* literal tree */
+    ct_data *dtree; /* distance tree */
+{
+    unsigned dist;      /* distance of matched string */
+    int lc;             /* match length or unmatched char (if dist == 0) */
+    unsigned lx = 0;    /* running index in l_buf */
+    unsigned code;      /* the code to send */
+    int extra;          /* number of extra bits to send */
+
+    if (s->last_lit != 0) do {
+        dist = s->d_buf[lx];
+        lc = s->l_buf[lx++];
+        if (dist == 0) {
+            send_code(s, lc, ltree); /* send a literal byte */
+            Tracecv(isgraph(lc), (stderr," '%c' ", lc));
+        } else {
+            /* Here, lc is the match length - MIN_MATCH */
+            code = _length_code[lc];
+            send_code(s, code+LITERALS+1, ltree); /* send the length code */
+            extra = extra_lbits[code];
+            if (extra != 0) {
+                lc -= base_length[code];
+                send_bits(s, lc, extra);       /* send the extra length bits */
+            }
+            dist--; /* dist is now the match distance - 1 */
+            code = d_code(dist);
+            Assert (code < D_CODES, "bad d_code");
+
+            send_code(s, code, dtree);       /* send the distance code */
+            extra = extra_dbits[code];
+            if (extra != 0) {
+                dist -= base_dist[code];
+                send_bits(s, dist, extra);   /* send the extra distance bits */
+            }
+        } /* literal or match pair ? */
+
+        /* Check that the overlay between pending_buf and d_buf+l_buf is ok: */
+        Assert((uInt)(s->pending) < s->lit_bufsize + 2*lx,
+               "pendingBuf overflow");
+
+    } while (lx < s->last_lit);
+
+    send_code(s, END_BLOCK, ltree);
+    s->last_eob_len = ltree[END_BLOCK].Len;
+}
+
+/* ===========================================================================
+ * Set the data type to BINARY or TEXT, using a crude approximation:
+ * set it to Z_TEXT if all symbols are either printable characters (33 to 255)
+ * or white spaces (9 to 13, or 32); or set it to Z_BINARY otherwise.
+ * IN assertion: the fields Freq of dyn_ltree are set.
+ */
+local void set_data_type(s)
+    deflate_state *s;
+{
+    int n;
+
+    for (n = 0; n < 9; n++)
+        if (s->dyn_ltree[n].Freq != 0)
+            break;
+    if (n == 9)
+        for (n = 14; n < 32; n++)
+            if (s->dyn_ltree[n].Freq != 0)
+                break;
+    s->strm->data_type = (n == 32) ? Z_TEXT : Z_BINARY;
+}
+
+/* ===========================================================================
+ * Reverse the first len bits of a code, using straightforward code (a faster
+ * method would use a table)
+ * IN assertion: 1 <= len <= 15
+ */
+local unsigned bi_reverse(code, len)
+    unsigned code; /* the value to invert */
+    int len;       /* its bit length */
+{
+    register unsigned res = 0;
+    do {
+        res |= code & 1;
+        code >>= 1, res <<= 1;
+    } while (--len > 0);
+    return res >> 1;
+}
+
+/* ===========================================================================
+ * Flush the bit buffer, keeping at most 7 bits in it.
+ */
+local void bi_flush(s)
+    deflate_state *s;
+{
+    if (s->bi_valid == 16) {
+        put_short(s, s->bi_buf);
+        s->bi_buf = 0;
+        s->bi_valid = 0;
+    } else if (s->bi_valid >= 8) {
+        put_byte(s, (Byte)s->bi_buf);
+        s->bi_buf >>= 8;
+        s->bi_valid -= 8;
+    }
+}
+
+/* ===========================================================================
+ * Flush the bit buffer and align the output on a byte boundary
+ */
+local void bi_windup(s)
+    deflate_state *s;
+{
+    if (s->bi_valid > 8) {
+        put_short(s, s->bi_buf);
+    } else if (s->bi_valid > 0) {
+        put_byte(s, (Byte)s->bi_buf);
+    }
+    s->bi_buf = 0;
+    s->bi_valid = 0;
+#ifdef DEBUG
+    s->bits_sent = (s->bits_sent+7) & ~7;
+#endif
+}
+
+/* ===========================================================================
+ * Copy a stored block, storing first the length and its
+ * one's complement if requested.
+ */
+local void copy_block(s, buf, len, header)
+    deflate_state *s;
+    charf    *buf;    /* the input data */
+    unsigned len;     /* its length */
+    int      header;  /* true if block header must be written */
+{
+    bi_windup(s);        /* align on byte boundary */
+    s->last_eob_len = 8; /* enough lookahead for inflate */
+
+    if (header) {
+        put_short(s, (ush)len);
+        put_short(s, (ush)~len);
+#ifdef DEBUG
+        s->bits_sent += 2*16;
+#endif
+    }
+#ifdef DEBUG
+    s->bits_sent += (ulg)len<<3;
+#endif
+    while (len--) {
+        put_byte(s, *buf++);
+    }
+}
diff --git a/usr/klibc/zlib/trees.h b/usr/klibc/zlib/trees.h
new file mode 100644
index 0000000..aadfa16
--- /dev/null
+++ b/usr/klibc/zlib/trees.h
@@ -0,0 +1,127 @@
+/* header created automatically with -DGEN_TREES_H */
+
+local const ct_data static_ltree[L_CODES+2] = {
+{{ 12},{  8}}, {{140},{  8}}, {{ 76},{  8}}, {{204},{  8}}, {{ 44},{  8}},
+{{172},{  8}}, {{108},{  8}}, {{236},{  8}}, {{ 28},{  8}}, {{156},{  8}},
+{{ 92},{  8}}, {{220},{  8}}, {{ 60},{  8}}, {{188},{  8}}, {{124},{  8}},
+{{252},{  8}}, {{  2},{  8}}, {{130},{  8}}, {{ 66},{  8}}, {{194},{  8}},
+{{ 34},{  8}}, {{162},{  8}}, {{ 98},{  8}}, {{226},{  8}}, {{ 18},{  8}},
+{{146},{  8}}, {{ 82},{  8}}, {{210},{  8}}, {{ 50},{  8}}, {{178},{  8}},
+{{114},{  8}}, {{242},{  8}}, {{ 10},{  8}}, {{138},{  8}}, {{ 74},{  8}},
+{{202},{  8}}, {{ 42},{  8}}, {{170},{  8}}, {{106},{  8}}, {{234},{  8}},
+{{ 26},{  8}}, {{154},{  8}}, {{ 90},{  8}}, {{218},{  8}}, {{ 58},{  8}},
+{{186},{  8}}, {{122},{  8}}, {{250},{  8}}, {{  6},{  8}}, {{134},{  8}},
+{{ 70},{  8}}, {{198},{  8}}, {{ 38},{  8}}, {{166},{  8}}, {{102},{  8}},
+{{230},{  8}}, {{ 22},{  8}}, {{150},{  8}}, {{ 86},{  8}}, {{214},{  8}},
+{{ 54},{  8}}, {{182},{  8}}, {{118},{  8}}, {{246},{  8}}, {{ 14},{  8}},
+{{142},{  8}}, {{ 78},{  8}}, {{206},{  8}}, {{ 46},{  8}}, {{174},{  8}},
+{{110},{  8}}, {{238},{  8}}, {{ 30},{  8}}, {{158},{  8}}, {{ 94},{  8}},
+{{222},{  8}}, {{ 62},{  8}}, {{190},{  8}}, {{126},{  8}}, {{254},{  8}},
+{{  1},{  8}}, {{129},{  8}}, {{ 65},{  8}}, {{193},{  8}}, {{ 33},{  8}},
+{{161},{  8}}, {{ 97},{  8}}, {{225},{  8}}, {{ 17},{  8}}, {{145},{  8}},
+{{ 81},{  8}}, {{209},{  8}}, {{ 49},{  8}}, {{177},{  8}}, {{113},{  8}},
+{{241},{  8}}, {{  9},{  8}}, {{137},{  8}}, {{ 73},{  8}}, {{201},{  8}},
+{{ 41},{  8}}, {{169},{  8}}, {{105},{  8}}, {{233},{  8}}, {{ 25},{  8}},
+{{153},{  8}}, {{ 89},{  8}}, {{217},{  8}}, {{ 57},{  8}}, {{185},{  8}},
+{{121},{  8}}, {{249},{  8}}, {{  5},{  8}}, {{133},{  8}}, {{ 69},{  8}},
+{{197},{  8}}, {{ 37},{  8}}, {{165},{  8}}, {{101},{  8}}, {{229},{  8}},
+{{ 21},{  8}}, {{149},{  8}}, {{ 85},{  8}}, {{213},{  8}}, {{ 53},{  8}},
+{{181},{  8}}, {{117},{  8}}, {{245},{  8}}, {{ 13},{  8}}, {{141},{  8}},
+{{ 77},{  8}}, {{205},{  8}}, {{ 45},{  8}}, {{173},{  8}}, {{109},{  8}},
+{{237},{  8}}, {{ 29},{  8}}, {{157},{  8}}, {{ 93},{  8}}, {{221},{  8}},
+{{ 61},{  8}}, {{189},{  8}}, {{125},{  8}}, {{253},{  8}}, {{ 19},{  9}},
+{{275},{  9}}, {{147},{  9}}, {{403},{  9}}, {{ 83},{  9}}, {{339},{  9}},
+{{211},{  9}}, {{467},{  9}}, {{ 51},{  9}}, {{307},{  9}}, {{179},{  9}},
+{{435},{  9}}, {{115},{  9}}, {{371},{  9}}, {{243},{  9}}, {{499},{  9}},
+{{ 11},{  9}}, {{267},{  9}}, {{139},{  9}}, {{395},{  9}}, {{ 75},{  9}},
+{{331},{  9}}, {{203},{  9}}, {{459},{  9}}, {{ 43},{  9}}, {{299},{  9}},
+{{171},{  9}}, {{427},{  9}}, {{107},{  9}}, {{363},{  9}}, {{235},{  9}},
+{{491},{  9}}, {{ 27},{  9}}, {{283},{  9}}, {{155},{  9}}, {{411},{  9}},
+{{ 91},{  9}}, {{347},{  9}}, {{219},{  9}}, {{475},{  9}}, {{ 59},{  9}},
+{{315},{  9}}, {{187},{  9}}, {{443},{  9}}, {{123},{  9}}, {{379},{  9}},
+{{251},{  9}}, {{507},{  9}}, {{  7},{  9}}, {{263},{  9}}, {{135},{  9}},
+{{391},{  9}}, {{ 71},{  9}}, {{327},{  9}}, {{199},{  9}}, {{455},{  9}},
+{{ 39},{  9}}, {{295},{  9}}, {{167},{  9}}, {{423},{  9}}, {{103},{  9}},
+{{359},{  9}}, {{231},{  9}}, {{487},{  9}}, {{ 23},{  9}}, {{279},{  9}},
+{{151},{  9}}, {{407},{  9}}, {{ 87},{  9}}, {{343},{  9}}, {{215},{  9}},
+{{471},{  9}}, {{ 55},{  9}}, {{311},{  9}}, {{183},{  9}}, {{439},{  9}},
+{{119},{  9}}, {{375},{  9}}, {{247},{  9}}, {{503},{  9}}, {{ 15},{  9}},
+{{271},{  9}}, {{143},{  9}}, {{399},{  9}}, {{ 79},{  9}}, {{335},{  9}},
+{{207},{  9}}, {{463},{  9}}, {{ 47},{  9}}, {{303},{  9}}, {{175},{  9}},
+{{431},{  9}}, {{111},{  9}}, {{367},{  9}}, {{239},{  9}}, {{495},{  9}},
+{{ 31},{  9}}, {{287},{  9}}, {{159},{  9}}, {{415},{  9}}, {{ 95},{  9}},
+{{351},{  9}}, {{223},{  9}}, {{479},{  9}}, {{ 63},{  9}}, {{319},{  9}},
+{{191},{  9}}, {{447},{  9}}, {{127},{  9}}, {{383},{  9}}, {{255},{  9}},
+{{511},{  9}}, {{  0},{  7}}, {{ 64},{  7}}, {{ 32},{  7}}, {{ 96},{  7}},
+{{ 16},{  7}}, {{ 80},{  7}}, {{ 48},{  7}}, {{112},{  7}}, {{  8},{  7}},
+{{ 72},{  7}}, {{ 40},{  7}}, {{104},{  7}}, {{ 24},{  7}}, {{ 88},{  7}},
+{{ 56},{  7}}, {{120},{  7}}, {{  4},{  7}}, {{ 68},{  7}}, {{ 36},{  7}},
+{{100},{  7}}, {{ 20},{  7}}, {{ 84},{  7}}, {{ 52},{  7}}, {{116},{  7}},
+{{  3},{  8}}, {{131},{  8}}, {{ 67},{  8}}, {{195},{  8}}, {{ 35},{  8}},
+{{163},{  8}}, {{ 99},{  8}}, {{227},{  8}}
+};
+
+local const ct_data static_dtree[D_CODES] = {
+{{ 0},{ 5}}, {{16},{ 5}}, {{ 8},{ 5}}, {{24},{ 5}}, {{ 4},{ 5}},
+{{20},{ 5}}, {{12},{ 5}}, {{28},{ 5}}, {{ 2},{ 5}}, {{18},{ 5}},
+{{10},{ 5}}, {{26},{ 5}}, {{ 6},{ 5}}, {{22},{ 5}}, {{14},{ 5}},
+{{30},{ 5}}, {{ 1},{ 5}}, {{17},{ 5}}, {{ 9},{ 5}}, {{25},{ 5}},
+{{ 5},{ 5}}, {{21},{ 5}}, {{13},{ 5}}, {{29},{ 5}}, {{ 3},{ 5}},
+{{19},{ 5}}, {{11},{ 5}}, {{27},{ 5}}, {{ 7},{ 5}}, {{23},{ 5}}
+};
+
+const uch _dist_code[DIST_CODE_LEN] = {
+ 0,  1,  2,  3,  4,  4,  5,  5,  6,  6,  6,  6,  7,  7,  7,  7,  8,  8,  8,  8,
+ 8,  8,  8,  8,  9,  9,  9,  9,  9,  9,  9,  9, 10, 10, 10, 10, 10, 10, 10, 10,
+10, 10, 10, 10, 10, 10, 10, 10, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
+11, 11, 11, 11, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
+12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 13, 13, 13, 13,
+13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
+13, 13, 13, 13, 13, 13, 13, 13, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
+14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
+14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
+14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 15, 15, 15, 15, 15, 15, 15, 15,
+15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
+15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
+15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,  0,  0, 16, 17,
+18, 18, 19, 19, 20, 20, 20, 20, 21, 21, 21, 21, 22, 22, 22, 22, 22, 22, 22, 22,
+23, 23, 23, 23, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+24, 24, 24, 24, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
+26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 27, 27, 27, 27, 27, 27, 27, 27,
+27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27,
+27, 27, 27, 27, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28,
+28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28,
+28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28,
+28, 28, 28, 28, 28, 28, 28, 28, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29,
+29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29,
+29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29,
+29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29
+};
+
+const uch _length_code[MAX_MATCH-MIN_MATCH+1]= {
+ 0,  1,  2,  3,  4,  5,  6,  7,  8,  8,  9,  9, 10, 10, 11, 11, 12, 12, 12, 12,
+13, 13, 13, 13, 14, 14, 14, 14, 15, 15, 15, 15, 16, 16, 16, 16, 16, 16, 16, 16,
+17, 17, 17, 17, 17, 17, 17, 17, 18, 18, 18, 18, 18, 18, 18, 18, 19, 19, 19, 19,
+19, 19, 19, 19, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 22, 22, 22, 22,
+22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 23, 23, 23, 23, 23, 23, 23, 23,
+23, 23, 23, 23, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 26, 26, 26, 26, 26, 26, 26, 26,
+26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
+26, 26, 26, 26, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27,
+27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 28
+};
+
+local const int base_length[LENGTH_CODES] = {
+0, 1, 2, 3, 4, 5, 6, 7, 8, 10, 12, 14, 16, 20, 24, 28, 32, 40, 48, 56,
+64, 80, 96, 112, 128, 160, 192, 224, 0
+};
+
+local const int base_dist[D_CODES] = {
+    0,     1,     2,     3,     4,     6,     8,    12,    16,    24,
+   32,    48,    64,    96,   128,   192,   256,   384,   512,   768,
+ 1024,  1536,  2048,  3072,  4096,  6144,  8192, 12288, 16384, 24576
+};
diff --git a/usr/klibc/zlib/uncompr.c b/usr/klibc/zlib/uncompr.c
new file mode 100644
index 0000000..debee438
--- /dev/null
+++ b/usr/klibc/zlib/uncompr.c
@@ -0,0 +1,61 @@
+/* uncompr.c -- decompress a memory buffer
+ * Copyright (C) 1995-2003 Jean-loup Gailly.
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* @(#) $Id: uncompr.c,v 1.1 2005/02/27 23:15:39 hpa Exp $ */
+
+#define ZLIB_INTERNAL
+#include "zlib.h"
+
+/* ===========================================================================
+     Decompresses the source buffer into the destination buffer.  sourceLen is
+   the byte length of the source buffer. Upon entry, destLen is the total
+   size of the destination buffer, which must be large enough to hold the
+   entire uncompressed data. (The size of the uncompressed data must have
+   been saved previously by the compressor and transmitted to the decompressor
+   by some mechanism outside the scope of this compression library.)
+   Upon exit, destLen is the actual size of the compressed buffer.
+     This function can be used to decompress a whole file at once if the
+   input file is mmap'ed.
+
+     uncompress returns Z_OK if success, Z_MEM_ERROR if there was not
+   enough memory, Z_BUF_ERROR if there was not enough room in the output
+   buffer, or Z_DATA_ERROR if the input data was corrupted.
+*/
+int ZEXPORT uncompress (dest, destLen, source, sourceLen)
+    Bytef *dest;
+    uLongf *destLen;
+    const Bytef *source;
+    uLong sourceLen;
+{
+    z_stream stream;
+    int err;
+
+    stream.next_in = (Bytef*)source;
+    stream.avail_in = (uInt)sourceLen;
+    /* Check for source > 64K on 16-bit machine: */
+    if ((uLong)stream.avail_in != sourceLen) return Z_BUF_ERROR;
+
+    stream.next_out = dest;
+    stream.avail_out = (uInt)*destLen;
+    if ((uLong)stream.avail_out != *destLen) return Z_BUF_ERROR;
+
+    stream.zalloc = (alloc_func)0;
+    stream.zfree = (free_func)0;
+
+    err = inflateInit(&stream);
+    if (err != Z_OK) return err;
+
+    err = inflate(&stream, Z_FINISH);
+    if (err != Z_STREAM_END) {
+        inflateEnd(&stream);
+        if (err == Z_NEED_DICT || (err == Z_BUF_ERROR && stream.avail_in == 0))
+            return Z_DATA_ERROR;
+        return err;
+    }
+    *destLen = stream.total_out;
+
+    err = inflateEnd(&stream);
+    return err;
+}
diff --git a/usr/klibc/zlib/zconf.in.h b/usr/klibc/zlib/zconf.in.h
new file mode 100644
index 0000000..c7575eb
--- /dev/null
+++ b/usr/klibc/zlib/zconf.in.h
@@ -0,0 +1,332 @@
+/* zconf.h -- configuration of the zlib compression library
+ * Copyright (C) 1995-2005 Jean-loup Gailly.
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* @(#) $Id: zconf.in.h,v 1.1 2005/02/27 23:15:39 hpa Exp $ */
+
+#ifndef ZCONF_H
+#define ZCONF_H
+
+/*
+ * If you *really* need a unique prefix for all types and library functions,
+ * compile with -DZ_PREFIX. The "standard" zlib should be compiled without it.
+ */
+#ifdef Z_PREFIX
+#  define deflateInit_          z_deflateInit_
+#  define deflate               z_deflate
+#  define deflateEnd            z_deflateEnd
+#  define inflateInit_          z_inflateInit_
+#  define inflate               z_inflate
+#  define inflateEnd            z_inflateEnd
+#  define deflateInit2_         z_deflateInit2_
+#  define deflateSetDictionary  z_deflateSetDictionary
+#  define deflateCopy           z_deflateCopy
+#  define deflateReset          z_deflateReset
+#  define deflateParams         z_deflateParams
+#  define deflateBound          z_deflateBound
+#  define deflatePrime          z_deflatePrime
+#  define inflateInit2_         z_inflateInit2_
+#  define inflateSetDictionary  z_inflateSetDictionary
+#  define inflateSync           z_inflateSync
+#  define inflateSyncPoint      z_inflateSyncPoint
+#  define inflateCopy           z_inflateCopy
+#  define inflateReset          z_inflateReset
+#  define inflateBack           z_inflateBack
+#  define inflateBackEnd        z_inflateBackEnd
+#  define compress              z_compress
+#  define compress2             z_compress2
+#  define compressBound         z_compressBound
+#  define uncompress            z_uncompress
+#  define adler32               z_adler32
+#  define crc32                 z_crc32
+#  define get_crc_table         z_get_crc_table
+#  define zError                z_zError
+
+#  define alloc_func            z_alloc_func
+#  define free_func             z_free_func
+#  define in_func               z_in_func
+#  define out_func              z_out_func
+#  define Byte                  z_Byte
+#  define uInt                  z_uInt
+#  define uLong                 z_uLong
+#  define Bytef                 z_Bytef
+#  define charf                 z_charf
+#  define intf                  z_intf
+#  define uIntf                 z_uIntf
+#  define uLongf                z_uLongf
+#  define voidpf                z_voidpf
+#  define voidp                 z_voidp
+#endif
+
+#if defined(__MSDOS__) && !defined(MSDOS)
+#  define MSDOS
+#endif
+#if (defined(OS_2) || defined(__OS2__)) && !defined(OS2)
+#  define OS2
+#endif
+#if defined(_WINDOWS) && !defined(WINDOWS)
+#  define WINDOWS
+#endif
+#if defined(_WIN32) || defined(_WIN32_WCE) || defined(__WIN32__)
+#  ifndef WIN32
+#    define WIN32
+#  endif
+#endif
+#if (defined(MSDOS) || defined(OS2) || defined(WINDOWS)) && !defined(WIN32)
+#  if !defined(__GNUC__) && !defined(__FLAT__) && !defined(__386__)
+#    ifndef SYS16BIT
+#      define SYS16BIT
+#    endif
+#  endif
+#endif
+
+/*
+ * Compile with -DMAXSEG_64K if the alloc function cannot allocate more
+ * than 64k bytes at a time (needed on systems with 16-bit int).
+ */
+#ifdef SYS16BIT
+#  define MAXSEG_64K
+#endif
+#ifdef MSDOS
+#  define UNALIGNED_OK
+#endif
+
+#ifdef __STDC_VERSION__
+#  ifndef STDC
+#    define STDC
+#  endif
+#  if __STDC_VERSION__ >= 199901L
+#    ifndef STDC99
+#      define STDC99
+#    endif
+#  endif
+#endif
+#if !defined(STDC) && (defined(__STDC__) || defined(__cplusplus))
+#  define STDC
+#endif
+#if !defined(STDC) && (defined(__GNUC__) || defined(__BORLANDC__))
+#  define STDC
+#endif
+#if !defined(STDC) && (defined(MSDOS) || defined(WINDOWS) || defined(WIN32))
+#  define STDC
+#endif
+#if !defined(STDC) && (defined(OS2) || defined(__HOS_AIX__))
+#  define STDC
+#endif
+
+#if defined(__OS400__) && !defined(STDC)    /* iSeries (formerly AS/400). */
+#  define STDC
+#endif
+
+#ifndef STDC
+#  ifndef const /* cannot use !defined(STDC) && !defined(const) on Mac */
+#    define const       /* note: need a more gentle solution here */
+#  endif
+#endif
+
+/* Some Mac compilers merge all .h files incorrectly: */
+#if defined(__MWERKS__)||defined(applec)||defined(THINK_C)||defined(__SC__)
+#  define NO_DUMMY_DECL
+#endif
+
+/* Maximum value for memLevel in deflateInit2 */
+#ifndef MAX_MEM_LEVEL
+#  ifdef MAXSEG_64K
+#    define MAX_MEM_LEVEL 8
+#  else
+#    define MAX_MEM_LEVEL 9
+#  endif
+#endif
+
+/* Maximum value for windowBits in deflateInit2 and inflateInit2.
+ * WARNING: reducing MAX_WBITS makes minigzip unable to extract .gz files
+ * created by gzip. (Files created by minigzip can still be extracted by
+ * gzip.)
+ */
+#ifndef MAX_WBITS
+#  define MAX_WBITS   15 /* 32K LZ77 window */
+#endif
+
+/* The memory requirements for deflate are (in bytes):
+            (1 << (windowBits+2)) +  (1 << (memLevel+9))
+ that is: 128K for windowBits=15  +  128K for memLevel = 8  (default values)
+ plus a few kilobytes for small objects. For example, if you want to reduce
+ the default memory requirements from 256K to 128K, compile with
+     make CFLAGS="-O -DMAX_WBITS=14 -DMAX_MEM_LEVEL=7"
+ Of course this will generally degrade compression (there's no free lunch).
+
+   The memory requirements for inflate are (in bytes) 1 << windowBits
+ that is, 32K for windowBits=15 (default value) plus a few kilobytes
+ for small objects.
+*/
+
+                        /* Type declarations */
+
+#ifndef OF /* function prototypes */
+#  ifdef STDC
+#    define OF(args)  args
+#  else
+#    define OF(args)  ()
+#  endif
+#endif
+
+/* The following definitions for FAR are needed only for MSDOS mixed
+ * model programming (small or medium model with some far allocations).
+ * This was tested only with MSC; for other MSDOS compilers you may have
+ * to define NO_MEMCPY in zutil.h.  If you don't need the mixed model,
+ * just define FAR to be empty.
+ */
+#ifdef SYS16BIT
+#  if defined(M_I86SM) || defined(M_I86MM)
+     /* MSC small or medium model */
+#    define SMALL_MEDIUM
+#    ifdef _MSC_VER
+#      define FAR _far
+#    else
+#      define FAR far
+#    endif
+#  endif
+#  if (defined(__SMALL__) || defined(__MEDIUM__))
+     /* Turbo C small or medium model */
+#    define SMALL_MEDIUM
+#    ifdef __BORLANDC__
+#      define FAR _far
+#    else
+#      define FAR far
+#    endif
+#  endif
+#endif
+
+#if defined(WINDOWS) || defined(WIN32)
+   /* If building or using zlib as a DLL, define ZLIB_DLL.
+    * This is not mandatory, but it offers a little performance increase.
+    */
+#  ifdef ZLIB_DLL
+#    if defined(WIN32) && (!defined(__BORLANDC__) || (__BORLANDC__ >= 0x500))
+#      ifdef ZLIB_INTERNAL
+#        define ZEXTERN extern __declspec(dllexport)
+#      else
+#        define ZEXTERN extern __declspec(dllimport)
+#      endif
+#    endif
+#  endif  /* ZLIB_DLL */
+   /* If building or using zlib with the WINAPI/WINAPIV calling convention,
+    * define ZLIB_WINAPI.
+    * Caution: the standard ZLIB1.DLL is NOT compiled using ZLIB_WINAPI.
+    */
+#  ifdef ZLIB_WINAPI
+#    ifdef FAR
+#      undef FAR
+#    endif
+#    include <windows.h>
+     /* No need for _export, use ZLIB.DEF instead. */
+     /* For complete Windows compatibility, use WINAPI, not __stdcall. */
+#    define ZEXPORT WINAPI
+#    ifdef WIN32
+#      define ZEXPORTVA WINAPIV
+#    else
+#      define ZEXPORTVA FAR CDECL
+#    endif
+#  endif
+#endif
+
+#if defined (__BEOS__)
+#  ifdef ZLIB_DLL
+#    ifdef ZLIB_INTERNAL
+#      define ZEXPORT   __declspec(dllexport)
+#      define ZEXPORTVA __declspec(dllexport)
+#    else
+#      define ZEXPORT   __declspec(dllimport)
+#      define ZEXPORTVA __declspec(dllimport)
+#    endif
+#  endif
+#endif
+
+#ifndef ZEXTERN
+#  define ZEXTERN extern
+#endif
+#ifndef ZEXPORT
+#  define ZEXPORT
+#endif
+#ifndef ZEXPORTVA
+#  define ZEXPORTVA
+#endif
+
+#ifndef FAR
+#  define FAR
+#endif
+
+#if !defined(__MACTYPES__)
+typedef unsigned char  Byte;  /* 8 bits */
+#endif
+typedef unsigned int   uInt;  /* 16 bits or more */
+typedef unsigned long  uLong; /* 32 bits or more */
+
+#ifdef SMALL_MEDIUM
+   /* Borland C/C++ and some old MSC versions ignore FAR inside typedef */
+#  define Bytef Byte FAR
+#else
+   typedef Byte  FAR Bytef;
+#endif
+typedef char  FAR charf;
+typedef int   FAR intf;
+typedef uInt  FAR uIntf;
+typedef uLong FAR uLongf;
+
+#ifdef STDC
+   typedef void const *voidpc;
+   typedef void FAR   *voidpf;
+   typedef void       *voidp;
+#else
+   typedef Byte const *voidpc;
+   typedef Byte FAR   *voidpf;
+   typedef Byte       *voidp;
+#endif
+
+#if 0           /* HAVE_UNISTD_H -- this line is updated by ./configure */
+#  include <sys/types.h> /* for off_t */
+#  include <unistd.h>    /* for SEEK_* and off_t */
+#  ifdef VMS
+#    include <unixio.h>   /* for off_t */
+#  endif
+#  define z_off_t off_t
+#endif
+#ifndef SEEK_SET
+#  define SEEK_SET        0       /* Seek from beginning of file.  */
+#  define SEEK_CUR        1       /* Seek from current position.  */
+#  define SEEK_END        2       /* Set file pointer to EOF plus "offset" */
+#endif
+#ifndef z_off_t
+#  define z_off_t long
+#endif
+
+#if defined(__OS400__)
+#  define NO_vsnprintf
+#endif
+
+#if defined(__MVS__)
+#  define NO_vsnprintf
+#  ifdef FAR
+#    undef FAR
+#  endif
+#endif
+
+/* MVS linker does not support external names larger than 8 bytes */
+#if defined(__MVS__)
+#   pragma map(deflateInit_,"DEIN")
+#   pragma map(deflateInit2_,"DEIN2")
+#   pragma map(deflateEnd,"DEEND")
+#   pragma map(deflateBound,"DEBND")
+#   pragma map(inflateInit_,"ININ")
+#   pragma map(inflateInit2_,"ININ2")
+#   pragma map(inflateEnd,"INEND")
+#   pragma map(inflateSync,"INSY")
+#   pragma map(inflateSetDictionary,"INSEDI")
+#   pragma map(compressBound,"CMBND")
+#   pragma map(inflate_table,"INTABL")
+#   pragma map(inflate_fast,"INFA")
+#   pragma map(inflate_copyright,"INCOPY")
+#endif
+
+#endif /* ZCONF_H */
diff --git a/usr/klibc/zlib/zlib.3 b/usr/klibc/zlib/zlib.3
new file mode 100644
index 0000000..90b8162
--- /dev/null
+++ b/usr/klibc/zlib/zlib.3
@@ -0,0 +1,159 @@
+.TH ZLIB 3 "18 July 2005"
+.SH NAME
+zlib \- compression/decompression library
+.SH SYNOPSIS
+[see
+.I zlib.h
+for full description]
+.SH DESCRIPTION
+The
+.I zlib
+library is a general purpose data compression library.
+The code is thread safe.
+It provides in-memory compression and decompression functions,
+including integrity checks of the uncompressed data.
+This version of the library supports only one compression method (deflation)
+but other algorithms will be added later
+and will have the same stream interface.
+.LP
+Compression can be done in a single step if the buffers are large enough
+(for example if an input file is mmap'ed),
+or can be done by repeated calls of the compression function.
+In the latter case,
+the application must provide more input and/or consume the output
+(providing more output space) before each call.
+.LP
+The library also supports reading and writing files in
+.IR gzip (1)
+(.gz) format
+with an interface similar to that of stdio.
+.LP
+The library does not install any signal handler.
+The decoder checks the consistency of the compressed data,
+so the library should never crash even in case of corrupted input.
+.LP
+All functions of the compression library are documented in the file
+.IR zlib.h .
+The distribution source includes examples of use of the library
+in the files
+.I example.c
+and
+.IR minigzip.c .
+.LP
+Changes to this version are documented in the file
+.I ChangeLog
+that accompanies the source,
+and are concerned primarily with bug fixes and portability enhancements.
+.LP
+A Java implementation of
+.I zlib
+is available in the Java Development Kit 1.1:
+.IP
+http://www.javasoft.com/products/JDK/1.1/docs/api/Package-java.util.zip.html
+.LP
+A Perl interface to
+.IR zlib ,
+written by Paul Marquess (pmqs@cpan.org),
+is available at CPAN (Comprehensive Perl Archive Network) sites,
+including:
+.IP
+http://www.cpan.org/modules/by-module/Compress/
+.LP
+A Python interface to
+.IR zlib ,
+written by A.M. Kuchling (amk@magnet.com),
+is available in Python 1.5 and later versions:
+.IP
+http://www.python.org/doc/lib/module-zlib.html
+.LP
+A
+.I zlib
+binding for
+.IR tcl (1),
+written by Andreas Kupries (a.kupries@westend.com),
+is availlable at:
+.IP
+http://www.westend.com/~kupries/doc/trf/man/man.html
+.LP
+An experimental package to read and write files in .zip format,
+written on top of
+.I zlib
+by Gilles Vollant (info@winimage.com),
+is available at:
+.IP
+http://www.winimage.com/zLibDll/unzip.html
+and also in the
+.I contrib/minizip
+directory of the main
+.I zlib
+web site.
+.SH "SEE ALSO"
+The
+.I zlib
+web site can be found at either of these locations:
+.IP
+http://www.zlib.org
+.br
+http://www.gzip.org/zlib/
+.LP
+The data format used by the zlib library is described by RFC
+(Request for Comments) 1950 to 1952 in the files:
+.IP
+http://www.ietf.org/rfc/rfc1950.txt (concerning zlib format)
+.br
+http://www.ietf.org/rfc/rfc1951.txt (concerning deflate format)
+.br
+http://www.ietf.org/rfc/rfc1952.txt (concerning gzip format)
+.LP
+These documents are also available in other formats from:
+.IP
+ftp://ftp.uu.net/graphics/png/documents/zlib/zdoc-index.html
+.LP
+Mark Nelson (markn@ieee.org) wrote an article about
+.I zlib
+for the Jan. 1997 issue of  Dr. Dobb's Journal;
+a copy of the article is available at:
+.IP
+http://dogma.net/markn/articles/zlibtool/zlibtool.htm
+.SH "REPORTING PROBLEMS"
+Before reporting a problem,
+please check the
+.I zlib
+web site to verify that you have the latest version of
+.IR zlib ;
+otherwise,
+obtain the latest version and see if the problem still exists.
+Please read the
+.I zlib
+FAQ at:
+.IP
+http://www.gzip.org/zlib/zlib_faq.html
+.LP
+before asking for help.
+Send questions and/or comments to zlib@gzip.org,
+or (for the Windows DLL version) to Gilles Vollant (info@winimage.com).
+.SH AUTHORS
+Version 1.2.3
+Copyright (C) 1995-2005 Jean-loup Gailly (jloup@gzip.org)
+and Mark Adler (madler@alumni.caltech.edu).
+.LP
+This software is provided "as-is,"
+without any express or implied warranty.
+In no event will the authors be held liable for any damages
+arising from the use of this software.
+See the distribution directory with respect to requirements
+governing redistribution.
+The deflate format used by
+.I zlib
+was defined by Phil Katz.
+The deflate and
+.I zlib
+specifications were written by L. Peter Deutsch.
+Thanks to all the people who reported problems and suggested various
+improvements in
+.IR zlib ;
+who are too numerous to cite here.
+.LP
+UNIX manual page by R. P. C. Rodgers,
+U.S. National Library of Medicine (rodgers@nlm.nih.gov).
+.\" end of man page
diff --git a/usr/klibc/zlib/zutil.c b/usr/klibc/zlib/zutil.c
new file mode 100644
index 0000000..f9ce953
--- /dev/null
+++ b/usr/klibc/zlib/zutil.c
@@ -0,0 +1,318 @@
+/* zutil.c -- target dependent utility functions for the compression library
+ * Copyright (C) 1995-2005 Jean-loup Gailly.
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* @(#) $Id: zutil.c,v 1.1 2005/02/27 23:15:39 hpa Exp $ */
+
+#include "zutil.h"
+
+#ifndef NO_DUMMY_DECL
+struct internal_state      {int dummy;}; /* for buggy compilers */
+#endif
+
+const char * const z_errmsg[10] = {
+"need dictionary",     /* Z_NEED_DICT       2  */
+"stream end",          /* Z_STREAM_END      1  */
+"",                    /* Z_OK              0  */
+"file error",          /* Z_ERRNO         (-1) */
+"stream error",        /* Z_STREAM_ERROR  (-2) */
+"data error",          /* Z_DATA_ERROR    (-3) */
+"insufficient memory", /* Z_MEM_ERROR     (-4) */
+"buffer error",        /* Z_BUF_ERROR     (-5) */
+"incompatible version",/* Z_VERSION_ERROR (-6) */
+""};
+
+
+const char * ZEXPORT zlibVersion()
+{
+    return ZLIB_VERSION;
+}
+
+uLong ZEXPORT zlibCompileFlags()
+{
+    uLong flags;
+
+    flags = 0;
+    switch (sizeof(uInt)) {
+    case 2:     break;
+    case 4:     flags += 1;     break;
+    case 8:     flags += 2;     break;
+    default:    flags += 3;
+    }
+    switch (sizeof(uLong)) {
+    case 2:     break;
+    case 4:     flags += 1 << 2;        break;
+    case 8:     flags += 2 << 2;        break;
+    default:    flags += 3 << 2;
+    }
+    switch (sizeof(voidpf)) {
+    case 2:     break;
+    case 4:     flags += 1 << 4;        break;
+    case 8:     flags += 2 << 4;        break;
+    default:    flags += 3 << 4;
+    }
+    switch (sizeof(z_off_t)) {
+    case 2:     break;
+    case 4:     flags += 1 << 6;        break;
+    case 8:     flags += 2 << 6;        break;
+    default:    flags += 3 << 6;
+    }
+#ifdef DEBUG
+    flags += 1 << 8;
+#endif
+#if defined(ASMV) || defined(ASMINF)
+    flags += 1 << 9;
+#endif
+#ifdef ZLIB_WINAPI
+    flags += 1 << 10;
+#endif
+#ifdef BUILDFIXED
+    flags += 1 << 12;
+#endif
+#ifdef DYNAMIC_CRC_TABLE
+    flags += 1 << 13;
+#endif
+#ifdef NO_GZCOMPRESS
+    flags += 1L << 16;
+#endif
+#ifdef NO_GZIP
+    flags += 1L << 17;
+#endif
+#ifdef PKZIP_BUG_WORKAROUND
+    flags += 1L << 20;
+#endif
+#ifdef FASTEST
+    flags += 1L << 21;
+#endif
+#ifdef STDC
+#  ifdef NO_vsnprintf
+        flags += 1L << 25;
+#    ifdef HAS_vsprintf_void
+        flags += 1L << 26;
+#    endif
+#  else
+#    ifdef HAS_vsnprintf_void
+        flags += 1L << 26;
+#    endif
+#  endif
+#else
+        flags += 1L << 24;
+#  ifdef NO_snprintf
+        flags += 1L << 25;
+#    ifdef HAS_sprintf_void
+        flags += 1L << 26;
+#    endif
+#  else
+#    ifdef HAS_snprintf_void
+        flags += 1L << 26;
+#    endif
+#  endif
+#endif
+    return flags;
+}
+
+#ifdef DEBUG
+
+#  ifndef verbose
+#    define verbose 0
+#  endif
+int z_verbose = verbose;
+
+void z_error (m)
+    char *m;
+{
+    fprintf(stderr, "%s\n", m);
+    exit(1);
+}
+#endif
+
+/* exported to allow conversion of error code to string for compress() and
+ * uncompress()
+ */
+const char * ZEXPORT zError(err)
+    int err;
+{
+    return ERR_MSG(err);
+}
+
+#if defined(_WIN32_WCE)
+    /* The Microsoft C Run-Time Library for Windows CE doesn't have
+     * errno.  We define it as a global variable to simplify porting.
+     * Its value is always 0 and should not be used.
+     */
+    int errno = 0;
+#endif
+
+#ifndef HAVE_MEMCPY
+
+void zmemcpy(dest, source, len)
+    Bytef* dest;
+    const Bytef* source;
+    uInt  len;
+{
+    if (len == 0) return;
+    do {
+        *dest++ = *source++; /* ??? to be unrolled */
+    } while (--len != 0);
+}
+
+int zmemcmp(s1, s2, len)
+    const Bytef* s1;
+    const Bytef* s2;
+    uInt  len;
+{
+    uInt j;
+
+    for (j = 0; j < len; j++) {
+        if (s1[j] != s2[j]) return 2*(s1[j] > s2[j])-1;
+    }
+    return 0;
+}
+
+void zmemzero(dest, len)
+    Bytef* dest;
+    uInt  len;
+{
+    if (len == 0) return;
+    do {
+        *dest++ = 0;  /* ??? to be unrolled */
+    } while (--len != 0);
+}
+#endif
+
+
+#ifdef SYS16BIT
+
+#ifdef __TURBOC__
+/* Turbo C in 16-bit mode */
+
+#  define MY_ZCALLOC
+
+/* Turbo C malloc() does not allow dynamic allocation of 64K bytes
+ * and farmalloc(64K) returns a pointer with an offset of 8, so we
+ * must fix the pointer. Warning: the pointer must be put back to its
+ * original form in order to free it, use zcfree().
+ */
+
+#define MAX_PTR 10
+/* 10*64K = 640K */
+
+local int next_ptr = 0;
+
+typedef struct ptr_table_s {
+    voidpf org_ptr;
+    voidpf new_ptr;
+} ptr_table;
+
+local ptr_table table[MAX_PTR];
+/* This table is used to remember the original form of pointers
+ * to large buffers (64K). Such pointers are normalized with a zero offset.
+ * Since MSDOS is not a preemptive multitasking OS, this table is not
+ * protected from concurrent access. This hack doesn't work anyway on
+ * a protected system like OS/2. Use Microsoft C instead.
+ */
+
+voidpf zcalloc (voidpf opaque, unsigned items, unsigned size)
+{
+    voidpf buf = opaque; /* just to make some compilers happy */
+    ulg bsize = (ulg)items*size;
+
+    /* If we allocate less than 65520 bytes, we assume that farmalloc
+     * will return a usable pointer which doesn't have to be normalized.
+     */
+    if (bsize < 65520L) {
+        buf = farmalloc(bsize);
+        if (*(ush*)&buf != 0) return buf;
+    } else {
+        buf = farmalloc(bsize + 16L);
+    }
+    if (buf == NULL || next_ptr >= MAX_PTR) return NULL;
+    table[next_ptr].org_ptr = buf;
+
+    /* Normalize the pointer to seg:0 */
+    *((ush*)&buf+1) += ((ush)((uch*)buf-0) + 15) >> 4;
+    *(ush*)&buf = 0;
+    table[next_ptr++].new_ptr = buf;
+    return buf;
+}
+
+void  zcfree (voidpf opaque, voidpf ptr)
+{
+    int n;
+    if (*(ush*)&ptr != 0) { /* object < 64K */
+        farfree(ptr);
+        return;
+    }
+    /* Find the original pointer */
+    for (n = 0; n < next_ptr; n++) {
+        if (ptr != table[n].new_ptr) continue;
+
+        farfree(table[n].org_ptr);
+        while (++n < next_ptr) {
+            table[n-1] = table[n];
+        }
+        next_ptr--;
+        return;
+    }
+    ptr = opaque; /* just to make some compilers happy */
+    Assert(0, "zcfree: ptr not found");
+}
+
+#endif /* __TURBOC__ */
+
+
+#ifdef M_I86
+/* Microsoft C in 16-bit mode */
+
+#  define MY_ZCALLOC
+
+#if (!defined(_MSC_VER) || (_MSC_VER <= 600))
+#  define _halloc  halloc
+#  define _hfree   hfree
+#endif
+
+voidpf zcalloc (voidpf opaque, unsigned items, unsigned size)
+{
+    if (opaque) opaque = 0; /* to make compiler happy */
+    return _halloc((long)items, size);
+}
+
+void  zcfree (voidpf opaque, voidpf ptr)
+{
+    if (opaque) opaque = 0; /* to make compiler happy */
+    _hfree(ptr);
+}
+
+#endif /* M_I86 */
+
+#endif /* SYS16BIT */
+
+
+#ifndef MY_ZCALLOC /* Any system without a special alloc function */
+
+#ifndef STDC
+extern voidp  malloc OF((uInt size));
+extern voidp  calloc OF((uInt items, uInt size));
+extern void   free   OF((voidpf ptr));
+#endif
+
+voidpf zcalloc (opaque, items, size)
+    voidpf opaque;
+    unsigned items;
+    unsigned size;
+{
+    if (opaque) items += size - size; /* make compiler happy */
+    return sizeof(uInt) > 2 ? (voidpf)malloc(items * size) :
+                              (voidpf)calloc(items, size);
+}
+
+void  zcfree (opaque, ptr)
+    voidpf opaque;
+    voidpf ptr;
+{
+    free(ptr);
+    if (opaque) return; /* make compiler happy */
+}
+
+#endif /* MY_ZCALLOC */
diff --git a/usr/klibc/zlib/zutil.h b/usr/klibc/zlib/zutil.h
new file mode 100644
index 0000000..42f52b1
--- /dev/null
+++ b/usr/klibc/zlib/zutil.h
@@ -0,0 +1,269 @@
+/* zutil.h -- internal interface and configuration of the compression library
+ * Copyright (C) 1995-2005 Jean-loup Gailly.
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* WARNING: this file should *not* be used by applications. It is
+   part of the implementation of the compression library and is
+   subject to change. Applications should only use zlib.h.
+ */
+
+/* @(#) $Id: zutil.h,v 1.1 2005/02/27 23:15:39 hpa Exp $ */
+
+#ifndef ZUTIL_H
+#define ZUTIL_H
+
+#define ZLIB_INTERNAL
+#include "zlib.h"
+
+#ifdef STDC
+#  ifndef _WIN32_WCE
+#    include <stddef.h>
+#  endif
+#  include <string.h>
+#  include <stdlib.h>
+#endif
+#ifdef NO_ERRNO_H
+#   ifdef _WIN32_WCE
+      /* The Microsoft C Run-Time Library for Windows CE doesn't have
+       * errno.  We define it as a global variable to simplify porting.
+       * Its value is always 0 and should not be used.  We rename it to
+       * avoid conflict with other libraries that use the same workaround.
+       */
+#     define errno z_errno
+#   endif
+    extern int errno;
+#else
+#  ifndef _WIN32_WCE
+#    include <errno.h>
+#  endif
+#endif
+
+#ifndef local
+#  define local static
+#endif
+/* compile with -Dlocal if your debugger can't find static symbols */
+
+typedef unsigned char  uch;
+typedef uch FAR uchf;
+typedef unsigned short ush;
+typedef ush FAR ushf;
+typedef unsigned long  ulg;
+
+extern const char * const z_errmsg[10]; /* indexed by 2-zlib_error */
+/* (size given to avoid silly warnings with Visual C++) */
+
+#define ERR_MSG(err) z_errmsg[Z_NEED_DICT-(err)]
+
+#define ERR_RETURN(strm,err) \
+  return (strm->msg = (char*)ERR_MSG(err), (err))
+/* To be used only when the state is known to be valid */
+
+        /* common constants */
+
+#ifndef DEF_WBITS
+#  define DEF_WBITS MAX_WBITS
+#endif
+/* default windowBits for decompression. MAX_WBITS is for compression only */
+
+#if MAX_MEM_LEVEL >= 8
+#  define DEF_MEM_LEVEL 8
+#else
+#  define DEF_MEM_LEVEL  MAX_MEM_LEVEL
+#endif
+/* default memLevel */
+
+#define STORED_BLOCK 0
+#define STATIC_TREES 1
+#define DYN_TREES    2
+/* The three kinds of block type */
+
+#define MIN_MATCH  3
+#define MAX_MATCH  258
+/* The minimum and maximum match lengths */
+
+#define PRESET_DICT 0x20 /* preset dictionary flag in zlib header */
+
+        /* target dependencies */
+
+#if defined(MSDOS) || (defined(WINDOWS) && !defined(WIN32))
+#  define OS_CODE  0x00
+#  if defined(__TURBOC__) || defined(__BORLANDC__)
+#    if(__STDC__ == 1) && (defined(__LARGE__) || defined(__COMPACT__))
+       /* Allow compilation with ANSI keywords only enabled */
+       void _Cdecl farfree( void *block );
+       void *_Cdecl farmalloc( unsigned long nbytes );
+#    else
+#      include <alloc.h>
+#    endif
+#  else /* MSC or DJGPP */
+#    include <malloc.h>
+#  endif
+#endif
+
+#ifdef AMIGA
+#  define OS_CODE  0x01
+#endif
+
+#if defined(VAXC) || defined(VMS)
+#  define OS_CODE  0x02
+#  define F_OPEN(name, mode) \
+     fopen((name), (mode), "mbc=60", "ctx=stm", "rfm=fix", "mrs=512")
+#endif
+
+#if defined(ATARI) || defined(atarist)
+#  define OS_CODE  0x05
+#endif
+
+#ifdef OS2
+#  define OS_CODE  0x06
+#  ifdef M_I86
+     #include <malloc.h>
+#  endif
+#endif
+
+#if defined(MACOS) || defined(TARGET_OS_MAC)
+#  define OS_CODE  0x07
+#  if defined(__MWERKS__) && __dest_os != __be_os && __dest_os != __win32_os
+#    include <unix.h> /* for fdopen */
+#  else
+#    ifndef fdopen
+#      define fdopen(fd,mode) NULL /* No fdopen() */
+#    endif
+#  endif
+#endif
+
+#ifdef TOPS20
+#  define OS_CODE  0x0a
+#endif
+
+#ifdef WIN32
+#  ifndef __CYGWIN__  /* Cygwin is Unix, not Win32 */
+#    define OS_CODE  0x0b
+#  endif
+#endif
+
+#ifdef __50SERIES /* Prime/PRIMOS */
+#  define OS_CODE  0x0f
+#endif
+
+#if defined(_BEOS_) || defined(RISCOS)
+#  define fdopen(fd,mode) NULL /* No fdopen() */
+#endif
+
+#if (defined(_MSC_VER) && (_MSC_VER > 600))
+#  if defined(_WIN32_WCE)
+#    define fdopen(fd,mode) NULL /* No fdopen() */
+#    ifndef _PTRDIFF_T_DEFINED
+       typedef int ptrdiff_t;
+#      define _PTRDIFF_T_DEFINED
+#    endif
+#  else
+#    define fdopen(fd,type)  _fdopen(fd,type)
+#  endif
+#endif
+
+        /* common defaults */
+
+#ifndef OS_CODE
+#  define OS_CODE  0x03  /* assume Unix */
+#endif
+
+#ifndef F_OPEN
+#  define F_OPEN(name, mode) fopen((name), (mode))
+#endif
+
+         /* functions */
+
+#if defined(STDC99) || (defined(__TURBOC__) && __TURBOC__ >= 0x550)
+#  ifndef HAVE_VSNPRINTF
+#    define HAVE_VSNPRINTF
+#  endif
+#endif
+#if defined(__CYGWIN__)
+#  ifndef HAVE_VSNPRINTF
+#    define HAVE_VSNPRINTF
+#  endif
+#endif
+#ifndef HAVE_VSNPRINTF
+#  ifdef MSDOS
+     /* vsnprintf may exist on some MS-DOS compilers (DJGPP?),
+        but for now we just assume it doesn't. */
+#    define NO_vsnprintf
+#  endif
+#  ifdef __TURBOC__
+#    define NO_vsnprintf
+#  endif
+#  ifdef WIN32
+     /* In Win32, vsnprintf is available as the "non-ANSI" _vsnprintf. */
+#    if !defined(vsnprintf) && !defined(NO_vsnprintf)
+#      define vsnprintf _vsnprintf
+#    endif
+#  endif
+#  ifdef __SASC
+#    define NO_vsnprintf
+#  endif
+#endif
+#ifdef VMS
+#  define NO_vsnprintf
+#endif
+
+#if defined(pyr)
+#  define NO_MEMCPY
+#endif
+#if defined(SMALL_MEDIUM) && !defined(_MSC_VER) && !defined(__SC__)
+ /* Use our own functions for small and medium model with MSC <= 5.0.
+  * You may have to use the same strategy for Borland C (untested).
+  * The __SC__ check is for Symantec.
+  */
+#  define NO_MEMCPY
+#endif
+#if defined(STDC) && !defined(HAVE_MEMCPY) && !defined(NO_MEMCPY)
+#  define HAVE_MEMCPY
+#endif
+#ifdef HAVE_MEMCPY
+#  ifdef SMALL_MEDIUM /* MSDOS small or medium model */
+#    define zmemcpy _fmemcpy
+#    define zmemcmp _fmemcmp
+#    define zmemzero(dest, len) _fmemset(dest, 0, len)
+#  else
+#    define zmemcpy memcpy
+#    define zmemcmp memcmp
+#    define zmemzero(dest, len) memset(dest, 0, len)
+#  endif
+#else
+   extern void zmemcpy  OF((Bytef* dest, const Bytef* source, uInt len));
+   extern int  zmemcmp  OF((const Bytef* s1, const Bytef* s2, uInt len));
+   extern void zmemzero OF((Bytef* dest, uInt len));
+#endif
+
+/* Diagnostic functions */
+#ifdef DEBUG
+#  include <stdio.h>
+   extern int z_verbose;
+   extern void z_error    OF((char *m));
+#  define Assert(cond,msg) {if(!(cond)) z_error(msg);}
+#  define Trace(x) {if (z_verbose>=0) fprintf x ;}
+#  define Tracev(x) {if (z_verbose>0) fprintf x ;}
+#  define Tracevv(x) {if (z_verbose>1) fprintf x ;}
+#  define Tracec(c,x) {if (z_verbose>0 && (c)) fprintf x ;}
+#  define Tracecv(c,x) {if (z_verbose>1 && (c)) fprintf x ;}
+#else
+#  define Assert(cond,msg)
+#  define Trace(x)
+#  define Tracev(x)
+#  define Tracevv(x)
+#  define Tracec(c,x)
+#  define Tracecv(c,x)
+#endif
+
+
+voidpf zcalloc OF((voidpf opaque, unsigned items, unsigned size));
+void   zcfree  OF((voidpf opaque, voidpf ptr));
+
+#define ZALLOC(strm, items, size) \
+           (*((strm)->zalloc))((strm)->opaque, (items), (size))
+#define ZFREE(strm, addr)  (*((strm)->zfree))((strm)->opaque, (voidpf)(addr))
+#define TRY_FREE(s, p) {if (p) ZFREE(s, p);}
+
+#endif /* ZUTIL_H */
diff --git a/usr/utils/Kbuild b/usr/utils/Kbuild
new file mode 100644
index 0000000..8264b59
--- /dev/null
+++ b/usr/utils/Kbuild
@@ -0,0 +1,68 @@
+#
+# Kbuild file for klib utils
+#
+
+progs := chroot dd mkdir mkfifo mknod mount pivot_root umount
+progs += true false sleep ln nuke minips cat
+progs += insmod uname halt kill readlink cpio
+
+static-y := $(addprefix static/, $(progs))
+shared-y := $(addprefix shared/, $(progs))
+
+# The binary is placed in a subdir, so we need to tell kbuild this
+static/chroot-y     := chroot.o
+shared/chroot-y     := chroot.o
+static/dd-y         := dd.o
+shared/dd-y         := dd.o
+static/mkdir-y      := mkdir.o file_mode.o
+shared/mkdir-y      := mkdir.o file_mode.o
+static/mkfifo-y     := mkfifo.o file_mode.o
+shared/mkfifo-y     := mkfifo.o file_mode.o
+static/mknod-y      := mknod.o file_mode.o
+shared/mknod-y      := mknod.o file_mode.o
+static/mount-y      := mount_main.o mount_opts.o
+shared/mount-y      := mount_main.o mount_opts.o
+static/pivot_root-y := pivot_root.o
+shared/pivot_root-y := pivot_root.o
+static/umount-y     := umount.o
+shared/umount-y     := umount.o
+static/true-y       := true.o
+shared/true-y       := true.o
+static/false-y      := false.o
+shared/false-y      := false.o
+static/sleep-y      := sleep.o
+shared/sleep-y      := sleep.o
+static/ln-y         := ln.o
+shared/ln-y         := ln.o
+static/nuke-y       := nuke.o
+shared/nuke-y       := nuke.o
+static/minips-y     := minips.o
+shared/minips-y     := minips.o
+static/cat-y        := cat.o
+shared/cat-y        := cat.o
+static/insmod-y     := insmod.o
+shared/insmod-y     := insmod.o
+static/uname-y      := uname.o
+shared/uname-y      := uname.o
+static/halt-y       := halt.o
+shared/halt-y       := halt.o
+static/kill-y       := kill.o
+shared/kill-y       := kill.o
+static/readlink-y   := readlink.o
+shared/readlink-y   := readlink.o
+static/cpio-y	    := cpio.o
+shared/cpio-y       := cpio.o
+
+# Additionally linked targets
+always := static/reboot static/poweroff shared/reboot shared/poweroff
+
+$(obj)/static/reboot $(obj)/static/poweroff: $(obj)/static/halt
+	$(call cmd,ln)
+$(obj)/shared/reboot $(obj)/shared/poweroff: $(obj)/shared/halt
+	$(call cmd,ln)
+
+# Clean deletes the static and shared dir
+clean-dirs := static shared
+
+# install only install the shared binaries
+install-y := $(shared-y) shared/reboot shared/poweroff
diff --git a/usr/utils/cat.c b/usr/utils/cat.c
new file mode 100644
index 0000000..1108d2e
--- /dev/null
+++ b/usr/utils/cat.c
@@ -0,0 +1,329 @@
+/* $NetBSD: cat.c,v 1.43 2004/01/04 03:31:28 jschauma Exp $	*/
+
+/*
+ * Copyright (c) 1989, 1993
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Kevin Fall.
+ *
+ * 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. 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.
+ */
+
+#ifndef __COPYRIGHT
+#define __COPYRIGHT(arg)
+#endif
+#ifndef __RCSID
+#define __RCSID(arg)
+#endif
+
+#if HAVE_NBTOOL_CONFIG_H
+#include "nbtool_config.h"
+#endif
+
+#ifndef __KLIBC__
+#include <sys/cdefs.h>
+#endif
+#if !defined(lint)
+__COPYRIGHT("@(#) Copyright (c) 1989, 1993\n\
+	The Regents of the University of California.  All rights reserved.\n");
+#if 0
+static char sccsid[] = "@(#)cat.c	8.2 (Berkeley) 4/27/95";
+#else
+__RCSID("$NetBSD: cat.c,v 1.43 2004/01/04 03:31:28 jschauma Exp $");
+#endif
+#endif				/* not lint */
+
+#include <sys/param.h>
+#include <sys/stat.h>
+
+#include <ctype.h>
+#ifndef __KLIBC__
+#include <err.h>
+#endif
+#include <errno.h>
+#include <fcntl.h>
+#ifndef __KLIBC__
+#include <locale.h>
+#endif
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+int bflag, eflag, fflag, lflag, nflag, sflag, tflag, vflag;
+int rval;
+const char *filename;
+
+int main(int, char *[]);
+void cook_args(char *argv[]);
+void cook_buf(FILE *);
+void raw_args(char *argv[]);
+void raw_cat(int);
+
+int main(int argc, char *argv[])
+{
+	int ch;
+	struct flock stdout_lock;
+
+#ifndef __KLIBC__
+	setprogname(argv[0]);
+	(void)setlocale(LC_ALL, "");
+#endif
+
+	while ((ch = getopt(argc, argv, "beflnstuv")) != -1)
+		switch (ch) {
+		case 'b':
+			bflag = nflag = 1;	/* -b implies -n */
+			break;
+		case 'e':
+			eflag = vflag = 1;	/* -e implies -v */
+			break;
+		case 'f':
+			fflag = 1;
+			break;
+		case 'l':
+			lflag = 1;
+			break;
+		case 'n':
+			nflag = 1;
+			break;
+		case 's':
+			sflag = 1;
+			break;
+		case 't':
+			tflag = vflag = 1;	/* -t implies -v */
+			break;
+		case 'u':
+#ifndef __KLIBC__
+			setbuf(stdout, NULL);
+#endif
+			break;
+		case 'v':
+			vflag = 1;
+			break;
+		default:
+		case '?':
+			(void)fprintf(stderr,
+				      "usage: cat [-beflnstuv] [-] [file ...]\n");
+			exit(1);
+			/* NOTREACHED */
+		}
+	argv += optind;
+
+	if (lflag) {
+		stdout_lock.l_len = 0;
+		stdout_lock.l_start = 0;
+		stdout_lock.l_type = F_WRLCK;
+		stdout_lock.l_whence = SEEK_SET;
+		if (fcntl(STDOUT_FILENO, F_SETLKW, &stdout_lock) == -1) {
+			perror("fcntl");
+			exit(1);
+		}
+	}
+
+	if (bflag || eflag || nflag || sflag || tflag || vflag)
+		cook_args(argv);
+	else
+		raw_args(argv);
+	if (fclose(stdout)) {
+		perror("fclose");
+		exit(1);
+	}
+	exit(rval);
+	/* NOTREACHED */
+}
+
+void cook_args(char **argv)
+{
+	FILE *fp;
+
+	fp = stdin;
+	filename = "stdin";
+	do {
+		if (*argv) {
+			if (!strcmp(*argv, "-"))
+				fp = stdin;
+			else if ((fp = fopen(*argv,
+					     fflag ? "rf" : "r")) == NULL) {
+				perror("fopen");
+				rval = 1;
+				++argv;
+				continue;
+			}
+			filename = *argv++;
+		}
+		cook_buf(fp);
+		if (fp != stdin)
+			(void)fclose(fp);
+	} while (*argv);
+}
+
+void cook_buf(FILE * fp)
+{
+	int ch, gobble, line, prev;
+	int stdout_err = 0;
+
+	line = gobble = 0;
+	for (prev = '\n'; (ch = getc(fp)) != EOF; prev = ch) {
+		if (prev == '\n') {
+			if (ch == '\n') {
+				if (sflag) {
+					if (!gobble && putchar(ch) == EOF)
+						break;
+					gobble = 1;
+					continue;
+				}
+				if (nflag) {
+					if (!bflag) {
+						if (fprintf(stdout,
+							    "%6d\t",
+							    ++line) < 0) {
+							stdout_err++;
+							break;
+						}
+					} else if (eflag) {
+						if (fprintf(stdout,
+							    "%6s\t", "") < 0) {
+							stdout_err++;
+							break;
+						}
+					}
+				}
+			} else if (nflag) {
+				if (fprintf(stdout, "%6d\t", ++line) < 0) {
+					stdout_err++;
+					break;
+				}
+			}
+		}
+		gobble = 0;
+		if (ch == '\n') {
+			if (eflag)
+				if (putchar('$') == EOF)
+					break;
+		} else if (ch == '\t') {
+			if (tflag) {
+				if (putchar('^') == EOF || putchar('I') == EOF)
+					break;
+				continue;
+			}
+		} else if (vflag) {
+			if (!isascii(ch)) {
+				if (putchar('M') == EOF || putchar('-') == EOF)
+					break;
+				ch = (ch) & 0x7f;
+			}
+			if (iscntrl(ch)) {
+				if (putchar('^') == EOF ||
+				    putchar(ch == '\177' ? '?' :
+					    ch | 0100) == EOF)
+					break;
+				continue;
+			}
+		}
+		if (putchar(ch) == EOF)
+			break;
+	}
+	if (stdout_err) {
+		perror(filename);
+		rval = 1;
+	}
+}
+
+void raw_args(char **argv)
+{
+	int fd;
+
+	fd = fileno(stdin);
+	filename = "stdin";
+	do {
+		if (*argv) {
+			if (!strcmp(*argv, "-"))
+				fd = fileno(stdin);
+			else if (fflag) {
+				struct stat st;
+				fd = open(*argv, O_RDONLY | O_NONBLOCK, 0);
+				if (fd < 0)
+					goto skip;
+
+				if (fstat(fd, &st) == -1) {
+					close(fd);
+					goto skip;
+				}
+				if (!S_ISREG(st.st_mode)) {
+					close(fd);
+					errno = EINVAL;
+					goto skipnomsg;
+				}
+			} else if ((fd = open(*argv, O_RDONLY, 0)) < 0) {
+			      skip:
+				perror(*argv);
+			      skipnomsg:
+				rval = 1;
+				++argv;
+				continue;
+			}
+			filename = *argv++;
+		}
+		raw_cat(fd);
+		if (fd != fileno(stdin))
+			(void)close(fd);
+	} while (*argv);
+}
+
+void raw_cat(int rfd)
+{
+	static char *buf;
+	static char fb_buf[BUFSIZ];
+	static size_t bsize;
+
+	struct stat sbuf;
+	ssize_t nr, nw, off;
+	int wfd;
+
+	wfd = fileno(stdout);
+	if (buf == NULL) {
+		if (fstat(wfd, &sbuf) == 0) {
+			bsize = sbuf.st_blksize > BUFSIZ ?
+			    sbuf.st_blksize : BUFSIZ;
+			buf = malloc(bsize);
+		}
+		if (buf == NULL) {
+			buf = fb_buf;
+			bsize = BUFSIZ;
+		}
+	}
+	while ((nr = read(rfd, buf, bsize)) > 0)
+		for (off = 0; nr; nr -= nw, off += nw)
+			if ((nw = write(wfd, buf + off, (size_t) nr)) < 0) {
+				perror("write");
+				exit(1);
+			}
+	if (nr < 0) {
+		fprintf(stderr, "%s: invalid length\n", filename);
+		rval = 1;
+	}
+}
diff --git a/usr/utils/chroot.c b/usr/utils/chroot.c
new file mode 100644
index 0000000..e3e6791
--- /dev/null
+++ b/usr/utils/chroot.c
@@ -0,0 +1,25 @@
+/*
+ * by rmk
+ */
+#include <unistd.h>
+#include <stdio.h>
+
+int main(int argc, char *argv[], char *envp[])
+{
+	if (argc < 3) {
+		fprintf(stderr, "Usage: %s newroot command...\n", argv[0]);
+		return 1;
+	}
+
+	if (chroot(argv[1]) == -1) {
+		perror("chroot");
+		return 1;
+	}
+
+	if (execve(argv[2], argv + 2, envp) == -1) {
+		perror("execve");
+		return 1;
+	}
+
+	return 0;
+}
diff --git a/usr/utils/cpio.c b/usr/utils/cpio.c
new file mode 100644
index 0000000..a41f40a
--- /dev/null
+++ b/usr/utils/cpio.c
@@ -0,0 +1,1102 @@
+/* copyin.c - extract or list a cpio archive
+   Copyright (C) 1990,1991,1992,2001,2002,2003,2004 Free Software Foundation, Inc.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2, or (at your option)
+   any later version.
+
+   This program 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 General Public License for more details.
+
+   You should have received a copy of the GNU General Public License along
+   with this program; if not, write to the Free Software Foundation, Inc.,
+   59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
+
+#include <errno.h>
+#include <fcntl.h>
+#include <malloc.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <time.h>
+#include <unistd.h>
+#include <utime.h>
+#ifndef	FNM_PATHNAME
+#include <fnmatch.h>
+#endif
+
+#ifndef	O_BINARY
+# define O_BINARY 0
+#endif
+
+# ifndef DIRECTORY_SEPARATOR
+#  define DIRECTORY_SEPARATOR '/'
+# endif
+
+# ifndef ISSLASH
+#  define ISSLASH(C) ((C) == DIRECTORY_SEPARATOR)
+# endif
+
+# ifndef FILE_SYSTEM_PREFIX_LEN
+#  define FILE_SYSTEM_PREFIX_LEN(Filename) 0
+# endif
+
+#ifndef SYMLINK_USES_UMASK
+# define UMASKED_SYMLINK(name1,name2,mode)    symlink(name1,name2)
+#else
+# define UMASKED_SYMLINK(name1,name2,mode)    umasked_symlink(name1,name2,mode)
+#endif				/* SYMLINK_USES_UMASK */
+
+/* Return 1 if an array of N objects, each of size S, cannot exist due
+   to size arithmetic overflow.  S must be positive and N must be
+   nonnegative.  This is a macro, not an inline function, so that it
+   works correctly even when SIZE_MAX < N.
+
+   By gnulib convention, SIZE_MAX represents overflow in size
+   calculations, so the conservative dividend to use here is
+   SIZE_MAX - 1, since SIZE_MAX might represent an overflowed value.
+   However, malloc (SIZE_MAX) fails on all known hosts where
+   sizeof (ptrdiff_t) <= sizeof (size_t), so do not bother to test for
+   exactly-SIZE_MAX allocations on such hosts; this avoids a test and
+   branch when S is known to be 1.  */
+# define xalloc_oversized(n, s) \
+    ((size_t) (sizeof (ptrdiff_t) <= sizeof (size_t) ? -1 : -2) / (s) < (n))
+
+#define DISK_IO_BLOCK_SIZE	(512)
+
+char *progname = NULL;
+
+/* If true, print a . for each file processed. (-V) */
+char dot_flag = false;
+
+/* Input and output buffers.  */
+char *input_buffer, *output_buffer;
+
+/* The size of the input buffer.  */
+long input_buffer_size;
+
+/* Current locations in `input_buffer' and `output_buffer'.  */
+char *in_buff, *out_buff;
+
+/* Current number of bytes stored at `input_buff' and `output_buff'.  */
+long input_size, output_size;
+
+/* Block size value, initially 512.  -B sets to 5120.  */
+int io_block_size = 512;
+
+struct new_cpio_header {
+	unsigned short c_magic;
+	unsigned long c_ino;
+	unsigned long c_mode;
+	unsigned long c_uid;
+	unsigned long c_gid;
+	unsigned long c_nlink;
+	unsigned long c_mtime;
+	unsigned long c_filesize;
+	long c_dev_maj;
+	long c_dev_min;
+	long c_rdev_maj;
+	long c_rdev_min;
+	unsigned long c_namesize;
+	unsigned long c_chksum;
+	char *c_name;
+	char *c_tar_linkname;
+};
+
+/* Total number of bytes read and written for all files.  
+   Now that many tape drives hold more than 4Gb we need more than 32
+   bits to hold input_bytes and output_bytes.  But it's not worth
+   the trouble of adding special multi-precision arithmetic if the 
+   compiler doesn't support 64 bit ints since input_bytes and
+   output_bytes are only used to print the number of blocks copied.  */
+#ifdef __GNUC__
+long long input_bytes, output_bytes;
+#else
+long input_bytes, output_bytes;
+#endif
+
+/* Allocate N bytes of memory dynamically, with error checking.  */
+
+void *xmalloc(size_t n)
+{
+	void *p;
+	if (xalloc_oversized(n, 1) || (!(p = malloc(n)) && n != 0)) {
+		fprintf(stderr, "%s: memory exhausted\n", progname);
+		exit(1);
+	}
+	return p;
+/*   return xnmalloc_inline (n, 1); */
+}
+
+/* Change the size of an allocated block of memory P to N bytes,
+   with error checking.  */
+
+void *xrealloc(void *p, size_t n)
+{
+	if (xalloc_oversized(n, 1) || (!(p = realloc(p, n)) && n != 0)) {
+		fprintf(stderr, "%s: memory exhausted\n", progname);
+		exit(1);
+	}
+	return p;
+/*   return xnrealloc_inline (p, n, 1); */
+}
+
+/* Clone STRING.  */
+
+char *xstrdup(char const *string)
+{
+	size_t s = strlen(string) + 1;
+	return memcpy(xmalloc(s), string, s);
+/*   return xmemdup_inline (string, strlen (string) + 1); */
+}
+
+/* Copy NUM_BYTES of buffer `in_buff' into IN_BUF.
+   `in_buff' may be partly full.
+   When `in_buff' is exhausted, refill it from file descriptor IN_DES.  */
+
+static void tape_fill_input_buffer(int in_des, int num_bytes)
+{
+	in_buff = input_buffer;
+	num_bytes = (num_bytes < io_block_size) ? num_bytes : io_block_size;
+	input_size = read(in_des, input_buffer, num_bytes);
+	if (input_size < 0) {
+		fprintf(stderr, "%s: read error: %s\n", progname,
+			strerror(errno));
+		exit(1);
+	}
+	if (input_size == 0) {
+		fprintf(stderr, "%s: premature end of file\n", progname);
+		exit(1);
+	}
+	input_bytes += input_size;
+}
+
+/* Write `output_size' bytes of `output_buffer' to file
+   descriptor OUT_DES and reset `output_size' and `out_buff'.
+   If `swapping_halfwords' or `swapping_bytes' is set,
+   do the appropriate swapping first.  Our callers have
+   to make sure to only set these flags if `output_size' 
+   is appropriate (a multiple of 4 for `swapping_halfwords',
+   2 for `swapping_bytes').  The fact that DISK_IO_BLOCK_SIZE
+   must always be a multiple of 4 helps us (and our callers)
+   insure this.  */
+
+void disk_empty_output_buffer(int out_des)
+{
+	int bytes_written;
+
+	bytes_written = write(out_des, output_buffer, output_size);
+
+	if (bytes_written != output_size) {
+		fprintf(stderr, "%s: write error: %s\n",
+			progname, strerror(errno));
+		exit(1);
+	}
+	output_bytes += output_size;
+	out_buff = output_buffer;
+	output_size = 0;
+}
+
+/* Copy NUM_BYTES of buffer IN_BUF to `out_buff', which may be partly full.
+   When `out_buff' fills up, flush it to file descriptor OUT_DES.  */
+
+void disk_buffered_write(char *in_buf, int out_des, long num_bytes)
+{
+	register long bytes_left = num_bytes;	/* Bytes needing to be copied.  */
+	register long space_left;	/* Room left in output buffer.  */
+
+	while (bytes_left > 0) {
+		space_left = DISK_IO_BLOCK_SIZE - output_size;
+		if (space_left == 0)
+			disk_empty_output_buffer(out_des);
+		else {
+			if (bytes_left < space_left)
+				space_left = bytes_left;
+			memmove(out_buff, in_buf, (unsigned)space_left);
+			out_buff += space_left;
+			output_size += space_left;
+			in_buf += space_left;
+			bytes_left -= space_left;
+		}
+	}
+}
+
+/* Copy a file using the input and output buffers, which may start out
+   partly full.  After the copy, the files are not closed nor the last
+   block flushed to output, and the input buffer may still be partly
+   full.  If `crc_i_flag' is set, add each byte to `crc'.
+   IN_DES is the file descriptor for input;
+   OUT_DES is the file descriptor for output;
+   NUM_BYTES is the number of bytes to copy.  */
+
+void copy_files_tape_to_disk(int in_des, int out_des, long num_bytes)
+{
+	long size;
+
+	while (num_bytes > 0) {
+		if (input_size == 0)
+			tape_fill_input_buffer(in_des, io_block_size);
+		size = (input_size < num_bytes) ? input_size : num_bytes;
+		disk_buffered_write(in_buff, out_des, size);
+		num_bytes -= size;
+		input_size -= size;
+		in_buff += size;
+	}
+}
+
+/* if IN_BUF is NULL, Skip the next NUM_BYTES bytes of file descriptor IN_DES. */
+void tape_buffered_read(char *in_buf, int in_des, long num_bytes)
+{
+	register long bytes_left = num_bytes;	/* Bytes needing to be copied.  */
+	register long space_left;	/* Bytes to copy from input buffer.  */
+
+	while (bytes_left > 0) {
+		if (input_size == 0)
+			tape_fill_input_buffer(in_des, io_block_size);
+		if (bytes_left < input_size)
+			space_left = bytes_left;
+		else
+			space_left = input_size;
+		if (in_buf != NULL) {
+			memmove(in_buf, in_buff, (unsigned)space_left);
+			in_buf += space_left;
+		}
+		in_buff += space_left;
+		input_size -= space_left;
+		bytes_left -= space_left;
+	}
+}
+
+/* Skip the next NUM_BYTES bytes of file descriptor IN_DES.  */
+#define tape_toss_input(in_des,num_bytes) \
+(tape_buffered_read(NULL,(in_des),(num_bytes)))
+
+struct deferment {
+	struct deferment *next;
+	struct new_cpio_header header;
+};
+
+struct deferment *create_deferment(struct new_cpio_header *file_hdr)
+{
+	struct deferment *d;
+	d = (struct deferment *)xmalloc(sizeof(struct deferment));
+	d->header = *file_hdr;
+	d->header.c_name = (char *)xmalloc(strlen(file_hdr->c_name) + 1);
+	strcpy(d->header.c_name, file_hdr->c_name);
+	return d;
+}
+
+void free_deferment(struct deferment *d)
+{
+	free(d->header.c_name);
+	free(d);
+}
+
+int link_to_name(char *link_name, char *link_target)
+{
+	int res = link(link_target, link_name);
+	return res;
+}
+
+struct inode_val {
+	unsigned long inode;
+	unsigned long major_num;
+	unsigned long minor_num;
+	char *file_name;
+};
+
+/* Inode hash table.  Allocated by first call to add_inode.  */
+static struct inode_val **hash_table = NULL;
+
+/* Size of current hash table.  Initial size is 47.  (47 = 2*22 + 3) */
+static int hash_size = 22;
+
+/* Number of elements in current hash table.  */
+static int hash_num;
+
+/* Do the hash insert.  Used in normal inserts and resizing the hash
+   table.  It is guaranteed that there is room to insert the item.
+   NEW_VALUE is the pointer to the previously allocated inode, file
+   name association record.  */
+
+static void hash_insert(struct inode_val *new_value)
+{
+	int start;		/* Home position for the value.  */
+	int temp;		/* Used for rehashing.  */
+
+	/* Hash function is node number modulo the table size.  */
+	start = new_value->inode % hash_size;
+
+	/* Do the initial look into the table.  */
+	if (hash_table[start] == NULL) {
+		hash_table[start] = new_value;
+		return;
+	}
+
+	/* If we get to here, the home position is full with a different inode
+	   record.  Do a linear search for the first NULL pointer and insert
+	   the new item there.  */
+	temp = (start + 1) % hash_size;
+	while (hash_table[temp] != NULL)
+		temp = (temp + 1) % hash_size;
+
+	/* Insert at the NULL.  */
+	hash_table[temp] = new_value;
+}
+
+/* Associate FILE_NAME with the inode NODE_NUM.  (Insert into hash table.)  */
+
+void
+add_inode(unsigned long node_num, char *file_name, unsigned long major_num,
+	  unsigned long minor_num)
+{
+	struct inode_val *temp;
+
+	/* Create new inode record.  */
+	temp = (struct inode_val *)xmalloc(sizeof(struct inode_val));
+	temp->inode = node_num;
+	temp->major_num = major_num;
+	temp->minor_num = minor_num;
+	temp->file_name = xstrdup(file_name);
+
+	/* Do we have to increase the size of (or initially allocate)
+	   the hash table?  */
+	if (hash_num == hash_size || hash_table == NULL) {
+		struct inode_val **old_table;	/* Pointer to old table.  */
+		int i;		/* Index for re-insert loop.  */
+
+		/* Save old table.  */
+		old_table = hash_table;
+		if (old_table == NULL)
+			hash_num = 0;
+
+		/* Calculate new size of table and allocate it.
+		   Sequence of table sizes is 47, 97, 197, 397, 797, 1597, 3197, 6397 ...
+		   where 3197 and most of the sizes after 6397 are not prime.  The other
+		   numbers listed are prime.  */
+		hash_size = 2 * hash_size + 3;
+		hash_table = (struct inode_val **)
+		    xmalloc(hash_size * sizeof(struct inode_val *));
+		memset(hash_table, 0, hash_size * sizeof(struct inode_val *));
+
+		/* Insert the values from the old table into the new table.  */
+		for (i = 0; i < hash_num; i++)
+			hash_insert(old_table[i]);
+
+		if (old_table != NULL)
+			free(old_table);
+	}
+
+	/* Insert the new record and increment the count of elements in the
+	   hash table.  */
+	hash_insert(temp);
+	hash_num++;
+}
+
+char *find_inode_file(unsigned long node_num, unsigned long major_num,
+		      unsigned long minor_num)
+{
+	int start;		/* Initial hash location.  */
+	int temp;		/* Rehash search variable.  */
+
+	if (hash_table != NULL) {
+		/* Hash function is node number modulo the table size.  */
+		start = node_num % hash_size;
+
+		/* Initial look into the table.  */
+		if (hash_table[start] == NULL)
+			return NULL;
+		if (hash_table[start]->inode == node_num
+		    && hash_table[start]->major_num == major_num
+		    && hash_table[start]->minor_num == minor_num)
+			return hash_table[start]->file_name;
+
+		/* The home position is full with a different inode record.
+		   Do a linear search terminated by a NULL pointer.  */
+		for (temp = (start + 1) % hash_size;
+		     hash_table[temp] != NULL && temp != start;
+		     temp = (temp + 1) % hash_size) {
+			if (hash_table[temp]->inode == node_num
+			    && hash_table[start]->major_num == major_num
+			    && hash_table[start]->minor_num == minor_num)
+				return hash_table[temp]->file_name;
+		}
+	}
+	return NULL;
+}
+
+/* Try and create a hard link from FILE_NAME to another file 
+   with the given major/minor device number and inode.  If no other
+   file with the same major/minor/inode numbers is known, add this file
+   to the list of known files and associated major/minor/inode numbers
+   and return -1.  If another file with the same major/minor/inode
+   numbers is found, try and create another link to it using
+   link_to_name, and return 0 for success and -1 for failure.  */
+
+int
+link_to_maj_min_ino(char *file_name, int st_dev_maj, int st_dev_min, int st_ino)
+{
+	int link_res;
+	char *link_name;
+	link_res = -1;
+	/* Is the file a link to a previously copied file?  */
+	link_name = find_inode_file(st_ino, st_dev_maj, st_dev_min);
+	if (link_name == NULL)
+		add_inode(st_ino, file_name, st_dev_maj, st_dev_min);
+	else
+		link_res = link_to_name(file_name, link_name);
+	return link_res;
+}
+
+static void copyin_regular_file(struct new_cpio_header *file_hdr,
+				int in_file_des);
+
+void warn_junk_bytes(long bytes_skipped)
+{
+	fprintf(stderr, "%s: warning: skipped %ld byte(s) of junk\n",
+		progname, bytes_skipped);
+}
+
+/* Skip the padding on IN_FILE_DES after a header or file,
+   up to the next header.
+   The number of bytes skipped is based on OFFSET -- the current offset
+   from the last start of a header (or file) -- and the current
+   header type.  */
+
+static void tape_skip_padding(int in_file_des, int offset)
+{
+	int pad;
+	pad = (4 - (offset % 4)) % 4;
+
+	if (pad != 0)
+		tape_toss_input(in_file_des, pad);
+}
+
+static int
+try_existing_file(struct new_cpio_header *file_hdr, int in_file_des,
+		  int *existing_dir)
+{
+	struct stat file_stat;
+
+	*existing_dir = false;
+	if (lstat(file_hdr->c_name, &file_stat) == 0) {
+		if (S_ISDIR(file_stat.st_mode)
+		    && ((file_hdr->c_mode & S_IFMT) == S_IFDIR)) {
+			/* If there is already a directory there that
+			   we are trying to create, don't complain about
+			   it.  */
+			*existing_dir = true;
+			return 0;
+		} else if (S_ISDIR(file_stat.st_mode)
+			   ? rmdir(file_hdr->c_name)
+			   : unlink(file_hdr->c_name)) {
+			fprintf(stderr, "%s: cannot remove current %s: %s\n",
+				progname, file_hdr->c_name, strerror(errno));
+			tape_toss_input(in_file_des, file_hdr->c_filesize);
+			tape_skip_padding(in_file_des, file_hdr->c_filesize);
+			return -1;	/* Go to the next file.  */
+		}
+	}
+	return 0;
+}
+
+/* The newc and crc formats store multiply linked copies of the same file 
+   in the archive only once.  The actual data is attached to the last link 
+   in the archive, and the other links all have a filesize of 0.  When a 
+   file in the archive has multiple links and a filesize of 0, its data is 
+   probably "attatched" to another file in the archive, so we can't create
+   it right away.  We have to "defer" creating it until we have created
+   the file that has the data "attatched" to it.  We keep a list of the
+   "defered" links on deferments.  */
+
+struct deferment *deferments = NULL;
+
+/* Add a file header to the deferments list.  For now they all just
+   go on one list, although we could optimize this if necessary.  */
+
+static void defer_copyin(struct new_cpio_header *file_hdr)
+{
+	struct deferment *d;
+	d = create_deferment(file_hdr);
+	d->next = deferments;
+	deferments = d;
+	return;
+}
+
+/* We just created a file that (probably) has some other links to it
+   which have been defered.  Go through all of the links on the deferments
+   list and create any which are links to this file.  */
+
+static void create_defered_links(struct new_cpio_header *file_hdr)
+{
+	struct deferment *d;
+	struct deferment *d_prev;
+	int ino;
+	int maj;
+	int min;
+	int link_res;
+	ino = file_hdr->c_ino;
+	maj = file_hdr->c_dev_maj;
+	min = file_hdr->c_dev_min;
+	d = deferments;
+	d_prev = NULL;
+	while (d != NULL) {
+		if ((d->header.c_ino == ino) && (d->header.c_dev_maj == maj)
+		    && (d->header.c_dev_min == min)) {
+			struct deferment *d_free;
+			link_res =
+			    link_to_name(d->header.c_name, file_hdr->c_name);
+			if (link_res < 0) {
+				fprintf(stderr,
+					"%s: cannot link %s to %s: %s\n",
+					progname, d->header.c_name,
+					file_hdr->c_name, strerror(errno));
+			}
+			if (d_prev != NULL)
+				d_prev->next = d->next;
+			else
+				deferments = d->next;
+			d_free = d;
+			d = d->next;
+			free_deferment(d_free);
+		} else {
+			d_prev = d;
+			d = d->next;
+		}
+	}
+}
+
+/* If we had a multiply linked file that really was empty then we would
+   have defered all of its links, since we never found any with data
+   "attached", and they will still be on the deferment list even when
+   we are done reading the whole archive.  Write out all of these
+   empty links that are still on the deferments list.  */
+
+static void create_final_defers()
+{
+	struct deferment *d;
+	int link_res;
+	int out_file_des;
+	struct utimbuf times;	/* For setting file times.  */
+	/* Initialize this in case it has members we don't know to set.  */
+	memset(&times, 0, sizeof(struct utimbuf));
+
+	for (d = deferments; d != NULL; d = d->next) {
+		/* Debian hack: A line, which could cause an endless loop, was
+		   removed (97/1/2).  It was reported by Ronald F. Guilmette to
+		   the upstream maintainers. -BEM */
+		/* Debian hack:  This was reported by Horst Knobloch. This bug has
+		   been reported to "bug-gnu-utils@prep.ai.mit.edu". (99/1/6) -BEM
+		 */
+		link_res = link_to_maj_min_ino(d->header.c_name,
+					       d->header.c_dev_maj,
+					       d->header.c_dev_min,
+					       d->header.c_ino);
+		if (link_res == 0) {
+			continue;
+		}
+		out_file_des = open(d->header.c_name,
+				    O_CREAT | O_WRONLY | O_BINARY, 0600);
+		if (out_file_des < 0) {
+			fprintf(stderr, "%s: open %s: %s\n",
+				progname, d->header.c_name, strerror(errno));
+			continue;
+		}
+
+		/* File is now copied; set attributes.  */
+		if ((fchown(out_file_des, d->header.c_uid, d->header.c_gid) < 0)
+		    && errno != EPERM)
+			fprintf(stderr, "%s: fchown %s: %s\n",
+				progname, d->header.c_name, strerror(errno));
+		/* chown may have turned off some permissions we wanted. */
+		if (fchmod(out_file_des, (int)d->header.c_mode) < 0)
+			fprintf(stderr, "%s: fchmod %s: %s\n",
+				progname, d->header.c_name, strerror(errno));
+
+		if (close(out_file_des) < 0)
+			fprintf(stderr, "%s: close %s: %s\n",
+				progname, d->header.c_name, strerror(errno));
+
+	}
+}
+
+static void
+copyin_regular_file(struct new_cpio_header *file_hdr, int in_file_des)
+{
+	int out_file_des;	/* Output file descriptor.  */
+
+	/* Can the current file be linked to a previously copied file? */
+	if (file_hdr->c_nlink > 1) {
+		int link_res;
+		if (file_hdr->c_filesize == 0) {
+			/* The newc and crc formats store multiply linked copies
+			   of the same file in the archive only once.  The
+			   actual data is attached to the last link in the
+			   archive, and the other links all have a filesize
+			   of 0.  Since this file has multiple links and a
+			   filesize of 0, its data is probably attatched to
+			   another file in the archive.  Save the link, and
+			   process it later when we get the actual data.  We
+			   can't just create it with length 0 and add the
+			   data later, in case the file is readonly.  We still
+			   lose if its parent directory is readonly (and we aren't
+			   running as root), but there's nothing we can do about
+			   that.  */
+			defer_copyin(file_hdr);
+			tape_toss_input(in_file_des, file_hdr->c_filesize);
+			tape_skip_padding(in_file_des, file_hdr->c_filesize);
+			return;
+		}
+		/* If the file has data (filesize != 0), then presumably
+		   any other links have already been defer_copyin'ed(),
+		   but GNU cpio version 2.0-2.2 didn't do that, so we
+		   still have to check for links here (and also in case
+		   the archive was created and later appeneded to). */
+		/* Debian hack: (97/1/2) This was reported by Ronald
+		   F. Guilmette to the upstream maintainers. -BEM */
+		link_res = link_to_maj_min_ino(file_hdr->c_name,
+					       file_hdr->c_dev_maj,
+					       file_hdr->c_dev_min,
+					       file_hdr->c_ino);
+		if (link_res == 0) {
+			tape_toss_input(in_file_des, file_hdr->c_filesize);
+			tape_skip_padding(in_file_des, file_hdr->c_filesize);
+			return;
+		}
+	}
+
+	/* If not linked, copy the contents of the file.  */
+	out_file_des = open(file_hdr->c_name,
+			    O_CREAT | O_WRONLY | O_BINARY, 0600);
+
+	if (out_file_des < 0) {
+		fprintf(stderr, "%s: open %s: %s\n",
+			progname, file_hdr->c_name, strerror(errno));
+		tape_toss_input(in_file_des, file_hdr->c_filesize);
+		tape_skip_padding(in_file_des, file_hdr->c_filesize);
+		return;
+	}
+
+	copy_files_tape_to_disk(in_file_des, out_file_des,
+				file_hdr->c_filesize);
+	disk_empty_output_buffer(out_file_des);
+
+	if (close(out_file_des) < 0)
+		fprintf(stderr, "%s: close %s: %s\n",
+			progname, file_hdr->c_name, strerror(errno));
+
+	/* File is now copied; set attributes.  */
+	if ((chown(file_hdr->c_name, file_hdr->c_uid, file_hdr->c_gid) < 0)
+	    && errno != EPERM)
+		fprintf(stderr, "%s: chown %s: %s\n",
+			progname, file_hdr->c_name, strerror(errno));
+
+	/* chown may have turned off some permissions we wanted. */
+	if (chmod(file_hdr->c_name, (int)file_hdr->c_mode) < 0)
+		fprintf(stderr, "%s: chmod %s: %s\n",
+			progname, file_hdr->c_name, strerror(errno));
+
+	tape_skip_padding(in_file_des, file_hdr->c_filesize);
+	if (file_hdr->c_nlink > 1) {
+		/* (see comment above for how the newc and crc formats 
+		   store multiple links).  Now that we have the data 
+		   for this file, create any other links to it which
+		   we defered.  */
+		create_defered_links(file_hdr);
+	}
+}
+
+/* In general, we can't use the builtin `basename' function if available,
+   since it has different meanings in different environments.
+   In some environments the builtin `basename' modifies its argument.
+
+   Return the address of the last file name component of NAME.  If
+   NAME has no file name components because it is all slashes, return
+   NAME if it is empty, the address of its last slash otherwise.  */
+
+char *base_name(char const *name)
+{
+	char const *base = name + FILE_SYSTEM_PREFIX_LEN(name);
+	char const *p;
+
+	for (p = base; *p; p++) {
+		if (ISSLASH(*p)) {
+			/* Treat multiple adjacent slashes like a single slash.  */
+			do
+				p++;
+			while (ISSLASH(*p));
+
+			/* If the file name ends in slash, use the trailing slash as
+			   the basename if no non-slashes have been found.  */
+			if (!*p) {
+				if (ISSLASH(*base))
+					base = p - 1;
+				break;
+			}
+
+			/* *P is a non-slash preceded by a slash.  */
+			base = p;
+		}
+	}
+
+	return (char *)base;
+}
+
+/* Return the length of of the basename NAME.  Typically NAME is the
+   value returned by base_name.  Act like strlen (NAME), except omit
+   redundant trailing slashes.  */
+
+size_t base_len(char const *name)
+{
+	size_t len;
+
+	for (len = strlen(name); 1 < len && ISSLASH(name[len - 1]); len--)
+		continue;
+
+	return len;
+}
+
+/* Remove trailing slashes from PATH.
+   Return true if a trailing slash was removed.
+   This is useful when using filename completion from a shell that
+   adds a "/" after directory names (such as tcsh and bash), because
+   the Unix rename and rmdir system calls return an "Invalid argument" error
+   when given a path that ends in "/" (except for the root directory).  */
+
+bool strip_trailing_slashes(char *path)
+{
+	char *base = base_name(path);
+	char *base_lim = base + base_len(base);
+	bool had_slash = (*base_lim != '\0');
+	*base_lim = '\0';
+	return had_slash;
+}
+
+static void copyin_directory(struct new_cpio_header *file_hdr, int existing_dir)
+{
+	int res;		/* Result of various function calls.  */
+
+	/* Strip any trailing `/'s off the filename; tar puts
+	   them on.  We might as well do it here in case anybody
+	   else does too, since they cause strange things to happen.  */
+	strip_trailing_slashes(file_hdr->c_name);
+
+	/* Ignore the current directory.  It must already exist,
+	   and we don't want to change its permission, ownership
+	   or time.  */
+	if (file_hdr->c_name[0] == '.' && file_hdr->c_name[1] == '\0') {
+		return;
+	}
+
+	if (!existing_dir)
+	{
+		res = mkdir(file_hdr->c_name, file_hdr->c_mode);
+	} else
+		res = 0;
+	if (res < 0) {
+		/* In some odd cases where the file_hdr->c_name includes `.',
+		   the directory may have actually been created by
+		   create_all_directories(), so the mkdir will fail
+		   because the directory exists.  If that's the case,
+		   don't complain about it.  */
+		struct stat file_stat;
+		if ((errno != EEXIST) ||
+		    (lstat(file_hdr->c_name, &file_stat) != 0) ||
+		    !(S_ISDIR(file_stat.st_mode))) {
+			fprintf(stderr, "%s: lstat %s: %s\n",
+				progname, file_hdr->c_name, strerror(errno));
+			return;
+		}
+	}
+	if ((chown(file_hdr->c_name, file_hdr->c_uid, file_hdr->c_gid) < 0)
+	    && errno != EPERM)
+		fprintf(stderr, "%s: chown %s: %s\n",
+			progname, file_hdr->c_name, strerror(errno));
+	/* chown may have turned off some permissions we wanted. */
+	if (chmod(file_hdr->c_name, (int)file_hdr->c_mode) < 0)
+		fprintf(stderr, "%s: chmod %s: %s\n",
+			progname, file_hdr->c_name, strerror(errno));
+}
+
+static void copyin_device(struct new_cpio_header *file_hdr)
+{
+	int res;		/* Result of various function calls.  */
+
+	if (file_hdr->c_nlink > 1) {
+		int link_res;
+		/* Debian hack:  This was reported by Horst
+		   Knobloch. This bug has been reported to
+		   "bug-gnu-utils@prep.ai.mit.edu". (99/1/6) -BEM */
+		link_res = link_to_maj_min_ino(file_hdr->c_name,
+					       file_hdr->c_dev_maj,
+					       file_hdr->c_dev_min,
+					       file_hdr->c_ino);
+		if (link_res == 0) {
+			return;
+		}
+	}
+
+	res = mknod(file_hdr->c_name, file_hdr->c_mode,
+		    makedev(file_hdr->c_rdev_maj, file_hdr->c_rdev_min));
+	if (res < 0) {
+		fprintf(stderr, "%s: mknod %s: %s\n", progname,
+			file_hdr->c_name, strerror(errno));
+		return;
+	}
+	if ((chown(file_hdr->c_name, file_hdr->c_uid, file_hdr->c_gid) < 0)
+	    && errno != EPERM)
+		fprintf(stderr, "%s: chown %s: %s\n", progname,
+			file_hdr->c_name, strerror(errno));
+	/* chown may have turned off some permissions we wanted. */
+	if (chmod(file_hdr->c_name, file_hdr->c_mode) < 0)
+		fprintf(stderr, "%s: chmod %s: %s\n", progname,
+			file_hdr->c_name, strerror(errno));
+}
+
+static void copyin_link(struct new_cpio_header *file_hdr, int in_file_des)
+{
+	char *link_name = NULL;	/* Name of hard and symbolic links.  */
+	int res;		/* Result of various function calls.  */
+
+	link_name = (char *)xmalloc((unsigned int)file_hdr->c_filesize + 1);
+	link_name[file_hdr->c_filesize] = '\0';
+	tape_buffered_read(link_name, in_file_des, file_hdr->c_filesize);
+	tape_skip_padding(in_file_des, file_hdr->c_filesize);
+
+	res = UMASKED_SYMLINK(link_name, file_hdr->c_name, file_hdr->c_mode);
+	if (res < 0) {
+		fprintf(stderr, "%s: UMASKED_SYMLINK %s: %s\n",
+			progname, file_hdr->c_name, strerror(errno));
+		free(link_name);
+		return;
+	}
+	if ((lchown(file_hdr->c_name, file_hdr->c_uid, file_hdr->c_gid) < 0)
+	    && errno != EPERM) {
+		fprintf(stderr, "%s: lchown %s: %s\n",
+			progname, file_hdr->c_name, strerror(errno));
+	}
+	free(link_name);
+}
+
+static void copyin_file(struct new_cpio_header *file_hdr, int in_file_des)
+{
+	int existing_dir;
+
+	if (try_existing_file(file_hdr, in_file_des, &existing_dir) < 0)
+		return;
+
+	/* Do the real copy or link.  */
+	switch (file_hdr->c_mode & S_IFMT) {
+	case S_IFREG:
+		copyin_regular_file(file_hdr, in_file_des);
+		break;
+
+	case S_IFDIR:
+		copyin_directory(file_hdr, existing_dir);
+		break;
+
+	case S_IFCHR:
+	case S_IFBLK:
+#ifdef S_IFSOCK
+	case S_IFSOCK:
+#endif
+#ifdef S_IFIFO
+	case S_IFIFO:
+#endif
+		copyin_device(file_hdr);
+		break;
+
+#ifdef S_IFLNK
+	case S_IFLNK:
+		copyin_link(file_hdr, in_file_des);
+		break;
+#endif
+
+	default:
+		fprintf(stderr, "%s: %s: unknown file type\n",
+			progname, file_hdr->c_name);
+		tape_toss_input(in_file_des, file_hdr->c_filesize);
+		tape_skip_padding(in_file_des, file_hdr->c_filesize);
+	}
+}
+
+/* Fill in FILE_HDR by reading a new-format ASCII format cpio header from
+   file descriptor IN_DES, except for the magic number, which is
+   already filled in.  */
+
+void read_in_new_ascii(struct new_cpio_header *file_hdr, int in_des)
+{
+	char ascii_header[112];
+
+	tape_buffered_read(ascii_header, in_des, 104L);
+	ascii_header[104] = '\0';
+	sscanf(ascii_header,
+	       "%8lx%8lx%8lx%8lx%8lx%8lx%8lx%8lx%8lx%8lx%8lx%8lx%8lx",
+	       &file_hdr->c_ino, &file_hdr->c_mode, &file_hdr->c_uid,
+	       &file_hdr->c_gid, &file_hdr->c_nlink, &file_hdr->c_mtime,
+	       &file_hdr->c_filesize, &file_hdr->c_dev_maj,
+	       &file_hdr->c_dev_min, &file_hdr->c_rdev_maj,
+	       &file_hdr->c_rdev_min, &file_hdr->c_namesize,
+	       &file_hdr->c_chksum);
+	/* Read file name from input.  */
+	if (file_hdr->c_name != NULL)
+		free(file_hdr->c_name);
+	file_hdr->c_name = (char *)xmalloc(file_hdr->c_namesize);
+	tape_buffered_read(file_hdr->c_name, in_des,
+			   (long)file_hdr->c_namesize);
+
+	/* In SVR4 ASCII format, the amount of space allocated for the header
+	   is rounded up to the next long-word, so we might need to drop
+	   1-3 bytes.  */
+	tape_skip_padding(in_des, file_hdr->c_namesize + 110);
+}
+
+/* Return 16-bit integer I with the bytes swapped.  */
+#define swab_short(i) ((((i) << 8) & 0xff00) | (((i) >> 8) & 0x00ff))
+
+/* Read the header, including the name of the file, from file
+   descriptor IN_DES into FILE_HDR.  */
+
+void read_in_header(struct new_cpio_header *file_hdr, int in_des)
+{
+	long bytes_skipped = 0;	/* Bytes of junk found before magic number.  */
+
+	/* Search for a valid magic number.  */
+
+	file_hdr->c_tar_linkname = NULL;
+
+	tape_buffered_read((char *)file_hdr, in_des, 6L);
+	while (1) {
+		if (!strncmp((char *)file_hdr, "070702", 6)
+		    || !strncmp((char *)file_hdr, "070701", 6))
+		{
+			if (bytes_skipped > 0)
+				warn_junk_bytes(bytes_skipped);
+
+			read_in_new_ascii(file_hdr, in_des);
+			break;
+		}
+		bytes_skipped++;
+		memmove((char *)file_hdr, (char *)file_hdr + 1, 5);
+		tape_buffered_read((char *)file_hdr + 5, in_des, 1L);
+	}
+}
+
+/* Read the collection from standard input and create files
+   in the file system.  */
+
+void process_copy_in()
+{
+	char done = false;	/* True if trailer reached.  */
+	struct new_cpio_header file_hdr;	/* Output header information.  */
+	int in_file_des;	/* Input file descriptor.  */
+
+	/* Initialize the copy in.  */
+	file_hdr.c_name = NULL;
+
+	/* only from stdin */
+	in_file_des = 0;
+
+	/* While there is more input in the collection, process the input.  */
+	while (!done) {
+		/* Start processing the next file by reading the header.  */
+		read_in_header(&file_hdr, in_file_des);
+
+		/* Is this the header for the TRAILER file?  */
+		if (strcmp("TRAILER!!!", file_hdr.c_name) == 0) {
+			done = true;
+			break;
+		}
+
+		/* Copy the input file into the directory structure.  */
+
+		copyin_file(&file_hdr, in_file_des);
+
+		if (dot_flag)
+			fputc('.', stderr);
+	}
+
+	if (dot_flag)
+		fputc('\n', stderr);
+
+	create_final_defers();
+
+}
+
+/* Initialize the input and output buffers to their proper size and
+   initialize all variables associated with the input and output
+   buffers.  */
+
+void initialize_buffers()
+{
+	int in_buf_size, out_buf_size;
+
+	/* Make sure the input buffer can always hold 2 blocks and that it
+	   is big enough to hold 1 tar record (512 bytes) even if it
+	   is not aligned on a block boundary.  The extra buffer space
+	   is needed by process_copyin and peek_in_buf to automatically
+	   figure out what kind of archive it is reading.  */
+	if (io_block_size >= 512)
+		in_buf_size = 2 * io_block_size;
+	else
+		in_buf_size = 1024;
+	out_buf_size = DISK_IO_BLOCK_SIZE;
+
+	input_buffer = (char *)xmalloc(in_buf_size);
+	in_buff = input_buffer;
+	input_buffer_size = in_buf_size;
+	input_size = 0;
+	input_bytes = 0;
+
+	output_buffer = (char *)xmalloc(out_buf_size);
+	out_buff = output_buffer;
+	output_size = 0;
+	output_bytes = 0;
+
+}
+
+int main(int argc, char *argv[])
+{
+	int c;
+	int extract_flag = false;
+
+	progname = argv[0];
+
+	do {
+		c = getopt(argc, argv, "iV");
+		if (c == EOF)
+			break;
+		switch (c) {
+		case 'V':
+			dot_flag = true;
+			break;
+
+		case 'i':
+			extract_flag = true;
+			break;
+		case '?':
+			fprintf(stderr,
+				"%s: not implemented or invalid option -%c\n",
+				progname, optopt);
+			exit(1);
+
+		}
+	} while (1);
+
+	if (extract_flag) {
+		initialize_buffers();
+
+		process_copy_in();
+	} else {
+		fprintf(stderr, "Usage: %s [-V] -i [< archive]\n", progname);
+		exit(1);
+	}
+
+	return 0;
+}
diff --git a/usr/utils/dd.c b/usr/utils/dd.c
new file mode 100644
index 0000000..562e2cf
--- /dev/null
+++ b/usr/utils/dd.c
@@ -0,0 +1,533 @@
+#include <ctype.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <setjmp.h>
+#include <signal.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#define ARRAY_SIZE(x)	(sizeof(x) / sizeof(x[0]))
+
+static char *progname;
+
+struct option {
+	const char *opt;
+	char *str;
+	char *arg;
+};
+
+struct conv {
+	const char str[8];
+	unsigned int set;
+	unsigned int exclude;
+};
+
+#define CONV_BLOCK	(1<<0)
+#define CONV_UNBLOCK	(1<<1)
+
+#define CONV_LCASE	(1<<2)
+#define CONV_UCASE	(1<<3)
+
+#define CONV_SWAB	(1<<4)
+#define CONV_NOERROR	(1<<5)
+#define CONV_NOTRUNC	(1<<6)
+#define CONV_SYNC	(1<<7)
+
+static struct option options[] = {
+	{"bs", NULL, NULL},
+#define OPT_BS		(&options[0])
+	{"cbs", NULL, NULL},
+#define OPT_CBS		(&options[1])
+	{"conv", NULL, NULL},
+#define OPT_CONV	(&options[2])
+	{"count", NULL, NULL},
+#define OPT_COUNT	(&options[3])
+	{"ibs", NULL, NULL},
+#define OPT_IBS		(&options[4])
+	{"if", NULL, NULL},
+#define OPT_IF		(&options[5])
+	{"obs", NULL, NULL},
+#define OPT_OBS		(&options[6])
+	{"of", NULL, NULL},
+#define OPT_OF		(&options[7])
+	{"seek", NULL, NULL},
+#define OPT_SEEK	(&options[8])
+	{"skip", NULL, NULL}
+#define OPT_SKIP	(&options[9])
+};
+
+static const struct conv conv_opts[] = {
+	{"block", CONV_BLOCK, CONV_UNBLOCK},
+	{"unblock", CONV_UNBLOCK, CONV_BLOCK},
+	{"lcase", CONV_LCASE, CONV_UCASE},
+	{"ucase", CONV_UCASE, CONV_LCASE},
+	{"swab", CONV_SWAB, 0},
+	{"noerror", CONV_NOERROR, 0},
+	{"notrunc", CONV_NOTRUNC, 0},
+	{"sync", CONV_SYNC, 0},
+};
+
+static size_t cbs;
+static unsigned int conv;
+static unsigned int count;
+static size_t ibs = 512;
+static size_t obs = 512;
+static unsigned int seek;
+static unsigned int skip;
+static char *in_buf;
+static char *out_buf;
+
+static size_t parse_bs(struct option *opt)
+{
+	unsigned long val, realval = 1;
+	char *str = opt->str;
+	int err = 0;
+
+	do {
+		char *s = str;
+		val = strtoul(str, &str, 10);
+		if (s == str || (val == ULONG_MAX && errno == ERANGE)) {
+			err = 1;
+			break;
+		}
+
+		/*
+		 * This option may be followed by
+		 * 'b', 'k' or 'x'
+		 */
+		if (*str == 'b') {
+			val *= 512;
+			str++;
+		} else if (*str == 'k') {
+			val *= 1024;
+			str++;
+		}
+		realval *= val;
+		if (*str != 'x')
+			break;
+		str++;
+	} while (1);
+
+	if (*str != '\0')
+		err = 1;
+
+	if (err) {
+		fprintf(stderr, "%s: bad operand `%s'\n", progname, opt->arg);
+		exit(1);
+	}
+
+	return (size_t) realval;
+}
+
+static unsigned int parse_num(struct option *opt)
+{
+	unsigned long val;
+	char *str = opt->str;
+
+	val = strtoul(str, &str, 10);
+	if (str == opt->str || (val == ULONG_MAX && errno == ERANGE) ||
+	    val > UINT_MAX) {
+		fprintf(stderr, "%s: bad operand `%s'\n", progname, opt->arg);
+		exit(1);
+	}
+
+	return (unsigned int)val;
+}
+
+static int parse_options(int argc, char *argv[])
+{
+	unsigned int i;
+	char *p, *s;
+	int arg;
+
+	/*
+	 * We cheat here; we don't parse the operand values
+	 * themselves here.  We merely split the operands
+	 * up.  This means that bs=foo bs=1 won't produce
+	 * an error.
+	 */
+	for (arg = 1; arg < argc; arg++) {
+		unsigned int len;
+
+		s = strchr(argv[arg], '=');
+		if (!s)
+			s = argv[arg];	/* don't recognise this arg */
+
+		len = s - argv[arg];
+		for (i = 0; i < ARRAY_SIZE(options); i++) {
+			if (strncmp(options[i].opt, argv[arg], len) != 0)
+				continue;
+
+			options[i].str = s + 1;
+			options[i].arg = argv[arg];
+			break;
+		}
+
+		if (i == ARRAY_SIZE(options)) {
+			fprintf(stderr, "%s: bad operand `%s'\n",
+				progname, argv[arg]);
+			return 1;
+		}
+	}
+
+	/*
+	 * Translate numeric operands.
+	 */
+	if (OPT_IBS->str)
+		ibs = parse_bs(OPT_IBS);
+	if (OPT_OBS->str)
+		obs = parse_bs(OPT_OBS);
+	if (OPT_CBS->str)
+		cbs = parse_bs(OPT_CBS);
+	if (OPT_COUNT->str)
+		count = parse_num(OPT_COUNT);
+	if (OPT_SEEK->str)
+		seek = parse_num(OPT_SEEK);
+	if (OPT_SKIP->str)
+		skip = parse_num(OPT_SKIP);
+
+	/*
+	 * If bs= is specified, it overrides ibs= and obs=
+	 */
+	if (OPT_BS->str)
+		ibs = obs = parse_bs(OPT_BS);
+
+	/*
+	 * And finally conv=
+	 */
+	if (OPT_CONV->str) {
+		p = OPT_CONV->str;
+
+		while ((s = strsep(&p, ",")) != NULL) {
+			for (i = 0; i < ARRAY_SIZE(conv_opts); i++) {
+				if (strcmp(s, conv_opts[i].str) != 0)
+					continue;
+				conv &= ~conv_opts[i].exclude;
+				conv |= conv_opts[i].set;
+				break;
+			}
+
+			if (i == ARRAY_SIZE(conv_opts)) {
+				fprintf(stderr, "%s: bad conversion `%s'\n",
+					progname, s);
+				return 1;
+			}
+		}
+	}
+
+	if (conv & (CONV_BLOCK | CONV_UNBLOCK) && cbs == 0) {
+		fprintf(stderr, "%s: block/unblock conversion with zero cbs\n",
+			progname);
+		return 1;
+	}
+
+	return 0;
+}
+
+static int safe_read(int fd, void *buf, size_t size)
+{
+	int ret, count = 0;
+	char *p = buf;
+
+	while (size) {
+		ret = read(fd, p, size);
+
+		/*
+		 * If we got EINTR, go again.
+		 */
+		if (ret == -1 && errno == EINTR)
+			continue;
+
+		/*
+		 * If we encountered an error condition
+		 * or read 0 bytes (EOF) return what we
+		 * have.
+		 */
+		if (ret == -1 || ret == 0)
+			return count ? count : ret;
+
+		/*
+		 * We read some bytes.
+		 */
+		count += ret;
+		size -= ret;
+		p += ret;
+	}
+
+	return count;
+}
+
+static int skip_blocks(int fd, void *buf, unsigned int blks, size_t size)
+{
+	unsigned int blk;
+	int ret = 0;
+
+	/*
+	 * Try to seek.
+	 */
+	for (blk = 0; blk < blks; blk++) {
+		ret = lseek(fd, size, SEEK_CUR);
+		if (ret == -1)
+			break;
+	}
+
+	/*
+	 * If we failed to seek, read instead.
+	 * FIXME: we don't handle short reads here, or
+	 * EINTR correctly.
+	 */
+	if (blk == 0 && ret == -1 && errno == ESPIPE) {
+		for (blk = 0; blk < blks; blk++) {
+			ret = safe_read(fd, buf, size);
+			if (ret != (int)size)
+				break;
+		}
+	}
+
+	if (ret == -1) {
+		perror("seek/skip");
+		return 1;
+	}
+	return 0;
+}
+
+struct stats {
+	unsigned int in_full;
+	unsigned int in_partial;
+	unsigned int out_full;
+	unsigned int out_partial;
+	unsigned int truncated;
+};
+
+static int do_dd(int rd, int wr, struct stats *stats)
+{
+	unsigned int i;
+	int ret;
+	int fill_val = 0;
+	size_t out_size = 0;
+	size_t in_size;
+	char *buf;
+
+	if (conv & (CONV_BLOCK | CONV_UNBLOCK))
+		fill_val = ' ';
+
+	while (!OPT_COUNT->str || count-- != 0) {
+		buf = in_buf;
+
+		/*
+		 * 1. read ibs-sized buffer
+		 */
+		in_size = ret = read(rd, in_buf, ibs);
+		if (ret == -1 || (ret == 0 && (conv & CONV_NOERROR) == 0))
+			break;
+
+		if (in_size == ibs) {
+			stats->in_full++;
+		} else {
+			stats->in_partial++;
+
+			/*
+			 * 2. zero (or append spaces)
+			 */
+			if (conv & CONV_SYNC) {
+				memset(in_buf + in_size, fill_val,
+				       ibs - in_size);
+				in_size = ibs;
+			}
+		}
+
+		/*
+		 * 4. swab conversion.  With an odd number of bytes,
+		 * last byte does not get swapped.
+		 */
+		if (conv & CONV_SWAB) {
+			char c;
+
+			for (i = 1; i < in_size; i += 2) {
+				c = in_buf[i - 1];
+				in_buf[i - 1] = in_buf[i];
+				in_buf[i] = c;
+			}
+		}
+
+		/*
+		 * 5. remaining conversions.
+		 */
+		if (conv & CONV_LCASE)
+			for (i = 0; i < in_size; i++)
+				in_buf[i] = tolower(in_buf[i]);
+
+		if (conv & CONV_UCASE)
+			for (i = 0; i < in_size; i++)
+				in_buf[i] = toupper(in_buf[i]);
+
+		/* block/unblock ? */
+
+		/*
+		 * 6. Aggregate into obs sized buffers.
+		 * If the in_size is obs-sized and we have no
+		 * data waiting, just write "buf" to the output.
+		 */
+		if (out_size == 0 && in_size == obs) {
+			write(wr, buf, obs);
+			stats->out_full++;
+		} else {
+			/*
+			 * We had data waiting, or we didn't have an
+			 * obs-sized input block.  We need to append
+			 * the input data to the output buffer.
+			 */
+			unsigned int space;
+			char *in_ptr = in_buf;
+
+			do {
+				space = obs - out_size;
+				if (space > in_size)
+					space = in_size;
+
+				memcpy(out_buf + out_size, in_ptr, space);
+				out_size += space;
+				in_size -= space;
+				in_ptr += space;
+
+				if (out_size == obs) {
+					write(wr, out_buf, obs);
+					stats->out_full++;
+					out_size = 0;
+				}
+			} while (out_size == 0 && in_size);
+
+			if (in_size) {
+				memcpy(out_buf, in_ptr, in_size);
+				out_size = in_size;
+			}
+		}
+	}
+
+	if (out_size) {
+		write(wr, out_buf, out_size);
+		stats->out_partial++;
+	}
+
+	return 0;
+}
+
+static sigjmp_buf jmp;
+
+static void sigint_handler(int sig)
+{
+	siglongjmp(jmp, -sig);
+}
+
+static int dd(int rd_fd, int wr_fd, struct stats *stats)
+{
+	int ret;
+
+	ret = sigsetjmp(jmp, 1);
+	if (ret == 0) {
+		sysv_signal(SIGINT, sigint_handler);
+		ret = do_dd(rd_fd, wr_fd, stats);
+	}
+
+	sysv_signal(SIGINT, SIG_DFL);
+	return ret;
+}
+
+int main(int argc, char *argv[])
+{
+	struct stats stats;
+	int ret;
+	int rd_fd = 0, wr_fd = 1;
+
+	progname = argv[0];
+
+	ret = parse_options(argc, argv);
+	if (ret)
+		return ret;
+
+	if (conv & (CONV_BLOCK | CONV_UNBLOCK)) {
+		fprintf(stderr, "%s: block/unblock not implemented\n",
+			progname);
+		return 1;
+	}
+
+	in_buf = malloc(ibs);
+	if (!in_buf) {
+		perror("malloc ibs");
+		return 1;
+	}
+
+	out_buf = malloc(obs);
+	if (!out_buf) {
+		perror("malloc obs");
+		return 1;
+	}
+
+	/*
+	 * Open the input file, if specified.
+	 */
+	if (OPT_IF->str) {
+		rd_fd = open(OPT_IF->str, O_RDONLY);
+		if (rd_fd == -1) {
+			perror("open input file");
+			return 1;
+		}
+	}
+
+	/*
+	 * Open the output file, if specified.
+	 */
+	if (OPT_OF->str) {
+		int flags = O_WRONLY|O_CREAT;
+		flags |= (conv & CONV_NOTRUNC) ? 0 : O_TRUNC;
+		wr_fd = open(OPT_OF->str, flags, 0666);
+		if (wr_fd == -1) {
+			perror("open output file");
+			return 1;
+		}
+	}
+
+	/*
+	 * Skip obs-sized blocks of output file.
+	 */
+	if (OPT_SEEK->str && skip_blocks(wr_fd, out_buf, seek, obs))
+		return 1;
+
+	/*
+	 * Skip ibs-sized blocks of input file.
+	 */
+	if (OPT_SKIP->str && skip_blocks(rd_fd, in_buf, skip, ibs))
+		return 1;
+
+	memset(&stats, 0, sizeof(stats));
+
+	/*
+	 * Do the real work
+	 */
+	ret = dd(rd_fd, wr_fd, &stats);
+
+	if (close(rd_fd) == -1)
+		perror(OPT_IF->str ? OPT_IF->str : "stdin");
+	if (close(wr_fd) == -1)
+		perror(OPT_OF->str ? OPT_OF->str : "stdout");
+
+	fprintf(stderr, "%u+%u records in\n", stats.in_full, stats.in_partial);
+	fprintf(stderr, "%u+%u records out\n",
+		stats.out_full, stats.out_partial);
+	if (stats.truncated)
+		fprintf(stderr, "%u truncated record%s\n",
+			stats.truncated, stats.truncated == 1 ? "" : "s");
+
+	/*
+	 * ret will be -SIGINT if we got a SIGINT.  Raise
+	 * the signal again to cause us to terminate with
+	 * SIGINT status.
+	 */
+	if (ret == -SIGINT)
+		raise(SIGINT);
+
+	return ret;
+}
diff --git a/usr/utils/false.c b/usr/utils/false.c
new file mode 100644
index 0000000..2c3243a
--- /dev/null
+++ b/usr/utils/false.c
@@ -0,0 +1,4 @@
+int main(void)
+{
+	return 1;
+}
diff --git a/usr/utils/file_mode.c b/usr/utils/file_mode.c
new file mode 100644
index 0000000..48f7f43
--- /dev/null
+++ b/usr/utils/file_mode.c
@@ -0,0 +1,143 @@
+#include <sys/stat.h>
+#include <ctype.h>
+#include <errno.h>
+#include <limits.h>
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "file_mode.h"
+
+extern char *progname;
+
+mode_t parse_file_mode(char *arg, mode_t mode, mode_t sumask)
+{
+	char *clause;
+
+	if (isdigit(*arg) && *arg < '8') {
+		unsigned long num;
+
+		num = strtoul(arg, NULL, 8);
+		if ((num == ULONG_MAX && errno == ERANGE) || num > 07777) {
+			fprintf(stderr, "%s: invalid mode `%s'\n", progname,
+				arg);
+			exit(255);
+		}
+		return (mode_t) num;
+	}
+
+	while ((clause = strsep(&arg, ",")) != NULL) {
+		mode_t who = 0;
+		int action;
+		char *p = clause;
+
+		/*
+		 * Parse the who list.  Optional.
+		 */
+		while (1) {
+			switch (*p++) {
+			case 'u':
+				who |= S_IRWXU | S_ISUID;
+				continue;
+			case 'g':
+				who |= S_IRWXG | S_ISGID;
+				continue;
+			case 'o':
+				who |= S_IRWXO | S_ISVTX;
+				continue;
+			case 'a':
+				who =
+				    S_IRWXU | S_IRWXG | S_IRWXO | S_ISUID |
+				    S_ISGID | S_ISVTX;
+				continue;
+			}
+			/* undo the increment above */
+			p--;
+			break;
+		}
+
+		if (who == 0)
+			who = (~sumask) | S_ISVTX;
+
+		/*
+		 * Parse an action list.  Must be at least one action.
+		 */
+		while (*p) {
+			mode_t perm = 0;
+
+			/*
+			 * Parse the action
+			 */
+			action = *p;
+			if (action == '+' || action == '-' || action == '=')
+				p++;
+
+			/*
+			 * Parse perm
+			 */
+			while (*p) {
+				switch (*p++) {
+				case 'r':
+					perm |= S_IRUSR | S_IRGRP | S_IROTH;
+					continue;
+				case 'w':
+					perm |= S_IWUSR | S_IWGRP | S_IWOTH;
+					continue;
+				case 'x':
+					perm |= S_IXUSR | S_IXGRP | S_IXOTH;
+					continue;
+				case 'X':
+					perm |= S_ISVTX;
+					continue;
+				case 's':
+					perm |= S_ISUID | S_ISGID;
+					continue;
+				case 'u':
+					perm = mode & S_IRWXU;
+					perm |= perm >> 3 | perm >> 6;
+					if (mode & S_ISUID)
+						perm |= S_ISGID;
+					continue;
+				case 'g':
+					perm = mode & S_IRWXG;
+					perm |= perm << 3 | perm >> 3;
+					if (mode & S_ISGID)
+						perm |= S_ISUID;
+					continue;
+				case 'o':
+					perm = mode & S_IRWXO;
+					perm |= perm << 6 | perm << 3;
+					continue;
+				}
+				/* undo the increment above */
+				p--;
+				break;
+			}
+
+			perm &= who;
+
+			switch (action) {
+			case '+':
+				mode |= perm;
+				continue;
+
+			case '-':
+				mode &= ~perm;
+				continue;
+
+			case '=':
+				mode &= ~who;
+				mode |= perm;
+				continue;
+			}
+
+			if (!action)
+				break;
+			fprintf(stderr, "%s: invalid mode `%s'\n", progname,
+				clause);
+			exit(255);
+		}
+	}
+
+	return mode;
+}
diff --git a/usr/utils/file_mode.h b/usr/utils/file_mode.h
new file mode 100644
index 0000000..364f603
--- /dev/null
+++ b/usr/utils/file_mode.h
@@ -0,0 +1,6 @@
+#ifndef UTILS_FILE_MODE_H
+#define UTILS_FILE_MODE_H
+
+mode_t parse_file_mode(char *arg, mode_t mode, mode_t sumask);
+
+#endif /* UTILS_FILE_MODE_H */
diff --git a/usr/utils/halt.c b/usr/utils/halt.c
new file mode 100644
index 0000000..a6656b5
--- /dev/null
+++ b/usr/utils/halt.c
@@ -0,0 +1,55 @@
+#include <stdlib.h>
+#include <unistd.h>
+#include <signal.h>
+#include <sys/reboot.h>
+#include <klibc/compiler.h>
+
+static __noreturn usage(void)
+{
+       static char mesg[] = "Usage: {halt|reboot|poweroff} [-n]\n";
+       write(2, mesg, sizeof(mesg) - 1);
+       exit(1);
+}
+
+int main(int argc, char *argv[])
+{
+       int cmd = 0; /* initalize to shut gcc up */
+       int do_sync = 1;
+       char *ptr, *ptr2;
+
+       /* Which action (program name)? */
+       ptr2 = ptr = argv[0];
+       while (*ptr2)
+               if (*ptr2++ == '/')
+                       ptr = ptr2;
+       if (*ptr == 'r')
+               cmd = LINUX_REBOOT_CMD_RESTART;
+       else if (*ptr == 'h')
+               cmd = LINUX_REBOOT_CMD_HALT;
+       else if (*ptr == 'p')
+               cmd = LINUX_REBOOT_CMD_POWER_OFF;
+       else
+               usage();
+
+       /* Walk options */
+       while (*++argv && **argv == '-')
+               switch (*++*argv) {
+                       case 'f': break; /* -f assumed */
+                       case 'n': do_sync = 0; break;
+                       default:
+                               usage();
+               }
+       if (*argv)
+               usage(); /* any args == error */
+
+       if (do_sync)
+               sync();
+       reboot(LINUX_REBOOT_CMD_CAD_OFF); /* Enable CTRL+ALT+DEL */
+       if (!reboot(cmd)) {
+               /* Success. Currently, CMD_HALT returns, so stop the world */
+               /* kill(-1, SIGSTOP); */
+               kill(getpid(), SIGSTOP);
+       }
+       write(2, "failed.\n", 8);
+       return 1;
+}
diff --git a/usr/utils/insmod.c b/usr/utils/insmod.c
new file mode 100644
index 0000000..47b5880
--- /dev/null
+++ b/usr/utils/insmod.c
@@ -0,0 +1,140 @@
+/* insmod.c: insert a module into the kernel.
+    Copyright (C) 2001  Rusty Russell.
+    Copyright (C) 2002  Rusty Russell, IBM Corporation.
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program 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 General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+*/
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/mman.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <errno.h>
+
+#define streq(a,b) (strcmp((a),(b)) == 0)
+
+/* This really needs to be in a header file... */
+extern long init_module(void *, unsigned long, const char *);
+
+static void print_usage(const char *progname)
+{
+	fprintf(stderr, "Usage: %s filename [args]\n", progname);
+	exit(1);
+}
+
+/* We use error numbers in a loose translation... */
+static const char *moderror(int err)
+{
+	switch (err) {
+	case ENOEXEC:
+		return "Invalid module format";
+	case ENOENT:
+		return "Unknown symbol in module";
+	case ESRCH:
+		return "Module has wrong symbol version";
+	case EINVAL:
+		return "Invalid parameters";
+	default:
+		return strerror(err);
+	}
+}
+
+static void *grab_file(const char *filename, unsigned long *size)
+{
+	unsigned int max = 16384;
+	int ret, fd;
+	void *buffer = malloc(max);
+
+	if (streq(filename, "-"))
+		fd = dup(STDIN_FILENO);
+	else
+		fd = open(filename, O_RDONLY, 0);
+
+	if (fd < 0)
+		return NULL;
+
+	*size = 0;
+	while ((ret = read(fd, buffer + *size, max - *size)) > 0) {
+		*size += ret;
+		if (*size == max)
+			buffer = realloc(buffer, max *= 2);
+	}
+	if (ret < 0) {
+		free(buffer);
+		buffer = NULL;
+	}
+	close(fd);
+	return buffer;
+}
+
+int main(int argc, char *argv[])
+{
+	int i;
+	long int ret;
+	unsigned long len;
+	void *file;
+	char *filename, *options = strdup("");
+	char *progname = argv[0];
+
+	if (argv[1] && (streq(argv[1], "--version") || streq(argv[1], "-V"))) {
+		puts("klibc insmod");
+		exit(0);
+	}
+
+	/* Ignore old options, for backwards compat. */
+	while (argv[1] && (streq(argv[1], "-p")
+			   || streq(argv[1], "-s")
+			   || streq(argv[1], "-f"))) {
+		argv++;
+		argc--;
+	}
+
+	filename = argv[1];
+	if (!filename)
+		print_usage(progname);
+
+	/* Rest is options */
+	for (i = 2; i < argc; i++) {
+		options = realloc(options,
+				  strlen(options) + 2 + strlen(argv[i]) + 2);
+		/* Spaces handled by "" pairs, but no way of escaping
+		   quotes */
+		if (strchr(argv[i], ' '))
+			strcat(options, "\"");
+		strcat(options, argv[i]);
+		if (strchr(argv[i], ' '))
+			strcat(options, "\"");
+		strcat(options, " ");
+	}
+
+	file = grab_file(filename, &len);
+	if (!file) {
+		fprintf(stderr, "insmod: can't read '%s': %s\n",
+			filename, strerror(errno));
+		exit(1);
+	}
+
+	ret = init_module(file, len, options);
+	if (ret != 0) {
+		fprintf(stderr, "insmod: error inserting '%s': %li %s\n",
+			filename, ret, moderror(errno));
+		exit(1);
+	}
+	exit(0);
+}
diff --git a/usr/utils/kill.c b/usr/utils/kill.c
new file mode 100644
index 0000000..8e68faa
--- /dev/null
+++ b/usr/utils/kill.c
@@ -0,0 +1,33 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <signal.h>
+#include <string.h>
+
+char *progname;
+
+static __noreturn usage(void)
+{
+	fprintf(stderr, "Usage: %s pid\n", progname);
+	exit(1);
+}
+int main(int argc, char *argv[], char *envp[])
+{
+	long pid;
+	char *endp;
+
+	progname = argv[0];
+	if (argc != 2)
+		usage();
+
+	pid = strtol(argv[1], &endp, 10);
+	if (*endp != '\0') {
+		perror("pid");
+		usage();
+	}
+
+	if (kill(pid, SIGTERM) == -1) {
+		perror("kill");
+		exit(-1);
+	}
+	exit(0);
+}
diff --git a/usr/utils/ln.c b/usr/utils/ln.c
new file mode 100644
index 0000000..e826eb8
--- /dev/null
+++ b/usr/utils/ln.c
@@ -0,0 +1,77 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+#include <linux/limits.h>
+
+int main(int argc, char *argv[])
+{
+	int c, s, f;
+	char *p;
+	struct stat sb;
+
+	s = f = 0;
+	do {
+		c = getopt(argc, argv, "sf");
+		if (c == EOF)
+			break;
+
+		switch (c) {
+
+		case 's':
+			s = 1;
+			break;
+		case 'f':
+			f = 1;
+			break;
+		case '?':
+			fprintf(stderr, "%s: invalid option -%c\n",
+				argv[0], optopt);
+			return 1;
+		}
+
+	} while (1);
+
+	if (optind == argc) {
+		fprintf(stderr, "Usage: %s [-s] [-f] target link\n", argv[0]);
+		return 1;
+	}
+
+	memset(&sb, 0, sizeof(struct stat));
+	if (stat(argv[argc - 1], &sb) < 0 && argc - optind > 2) {
+		if (!(S_ISDIR(sb.st_mode))) {
+			fprintf(stderr,
+				"multiple targets and %s is not a directory\n",
+				argv[argc - 1]);
+			return 1;
+		}
+	}
+
+	for (c = optind; c < argc - 1; c++) {
+		char target[PATH_MAX];
+
+		p = strrchr(argv[c], '/');
+		p++;
+
+		if (S_ISDIR(sb.st_mode))
+			snprintf(target, PATH_MAX, "%s/%s", argv[argc - 1], p);
+		else
+			snprintf(target, PATH_MAX, "%s", argv[argc - 1]);
+
+		if (f)
+			unlink(target);
+
+		if (s) {
+			if (symlink(argv[c], target) == -1)
+				perror(target);
+		} else {
+			if (link(argv[c], target) == -1)
+				perror(target);
+		}
+	}
+
+	return 0;
+}
diff --git a/usr/utils/minips.c b/usr/utils/minips.c
new file mode 100644
index 0000000..fabf8b6
--- /dev/null
+++ b/usr/utils/minips.c
@@ -0,0 +1,510 @@
+/*
+ * Copyright 1998 by Albert Cahalan; all rights reserved.
+ * This file may be used subject to the terms and conditions of the
+ * GNU Library General Public License Version 2, or any later version
+ * at your option, as published by the Free Software Foundation.
+ * This program 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 Library General Public License for more details.
+ */
+
+/* This is a minimal /bin/ps, designed to be smaller than the old ps
+ * while still supporting some of the more important features of the
+ * new ps. (for total size, note that this ps does not need libproc)
+ * It is suitable for Linux-on-a-floppy systems only.
+ *
+ * Maintainers: do not compile or install for normal systems.
+ * Anyone needing this will want to tweak their compiler anyway.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/ioctl.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <dirent.h>
+#include <unistd.h>
+
+#include <asm/param.h>		/* HZ */
+
+static int P_euid;
+static int P_pid;
+static char P_cmd[16];
+static char P_state;
+static int P_ppid, P_pgrp, P_session, P_tty, P_tpgid;
+static unsigned long P_flags, P_min_flt, P_cmin_flt, P_maj_flt, P_cmaj_flt,
+    P_utime, P_stime;
+static long P_cutime, P_cstime, P_priority, P_nice, P_timeout, P_it_real_value;
+static unsigned long P_start_time, P_vsize;
+static long P_rss;
+static unsigned long P_rss_rlim, P_start_code, P_end_code, P_start_stack,
+    P_kstk_esp, P_kstk_eip;
+static unsigned P_signal, P_blocked, P_sigignore, P_sigcatch;
+static unsigned long P_wchan, P_nswap, P_cnswap;
+
+#if 0
+static int screen_cols = 80;
+static int w_count;
+#endif
+
+static int want_one_pid;
+static const char *want_one_command;
+static int select_notty;
+static int select_all;
+
+static int ps_format;
+static int old_h_option;
+
+/* we only pretend to support this */
+static int show_args;		/* implicit with -f and all BSD options */
+static int bsd_c_option;	/* this option overrides the above */
+
+static int ps_argc;		/* global argc */
+static char **ps_argv;		/* global argv */
+static int thisarg;		/* index into ps_argv */
+static char *flagptr;		/* current location in ps_argv[thisarg] */
+
+#ifndef HZ
+#warning HZ not defined, assuming it is 100
+#define HZ 100
+#endif
+
+int page_shift;			/* Page size as shift count */
+
+static void usage(void)
+{
+	fprintf(stderr,
+		"-C   select by command name (minimal ps only accepts one)\n"
+		"-p   select by process ID (minimal ps only accepts one)\n"
+		"-e   all processes (same as ax)\n"
+		"a    all processes w/ tty, including other users\n"
+		"x    processes w/o controlling ttys\n"
+		"-f   full format\n"
+		"-j,j job control format\n"
+		"v    virtual memory format\n"
+		"-l,l long format\n"
+		"u    user-oriented format\n"
+		"-o   user-defined format (limited support, only \"ps -o pid=\")\n"
+		"h    no header\n"
+/*
+    "-A   all processes (same as ax)\n"
+    "c    true command name\n"
+    "-w,w wide output\n"
+*/
+	    );
+	exit(1);
+}
+
+/*
+ * Return the next argument, or call the usage function.
+ * This handles both:   -oFOO   -o FOO
+ */
+static const char *get_opt_arg(void)
+{
+	const char *ret;
+	ret = flagptr + 1;	/* assume argument is part of ps_argv[thisarg] */
+	if (*ret)
+		return ret;
+	if (++thisarg >= ps_argc)
+		usage();	/* there is nothing left */
+	/* argument is the new ps_argv[thisarg] */
+	ret = ps_argv[thisarg];
+	if (!ret || !*ret)
+		usage();
+	return ret;
+}
+
+/* return the PID, or 0 if nothing good */
+static void parse_pid(const char *str)
+{
+	char *endp;
+	int num;
+	if (!str)
+		goto bad;
+	num = strtol(str, &endp, 0);
+	if (*endp != '\0')
+		goto bad;
+	if (num < 1)
+		goto bad;
+	if (want_one_pid)
+		goto bad;
+	want_one_pid = num;
+	return;
+      bad:
+	usage();
+}
+
+/***************** parse SysV options, including Unix98  *****************/
+static void parse_sysv_option(void)
+{
+	do {
+		switch (*flagptr) {
+    /**** selection ****/
+		case 'C':	/* end */
+			if (want_one_command)
+				usage();
+			want_one_command = get_opt_arg();
+			return;	/* can't have any more options */
+		case 'p':	/* end */
+			parse_pid(get_opt_arg());
+			return;	/* can't have any more options */
+		case 'A':
+		case 'e':
+			select_all++;
+			select_notty++;
+		case 'w':	/* here for now, since the real one is not used */
+			break;
+    /**** output format ****/
+		case 'f':
+			show_args = 1;
+			/* FALL THROUGH */
+		case 'j':
+		case 'l':
+			if (ps_format)
+				usage();
+			ps_format = *flagptr;
+			break;
+		case 'o':	/* end */
+			/* We only support a limited form: "ps -o pid="  (yes, just "pid=") */
+			if (strcmp(get_opt_arg(), "pid="))
+				usage();
+			if (ps_format)
+				usage();
+			ps_format = 'o';
+			old_h_option++;
+			return;	/* can't have any more options */
+    /**** other stuff ****/
+#if 0
+		case 'w':
+			w_count++;
+			break;
+#endif
+		default:
+			usage();
+		}		/* switch */
+	} while (*++flagptr);
+}
+
+/************************* parse BSD options **********************/
+static void parse_bsd_option(void)
+{
+	do {
+		switch (*flagptr) {
+    /**** selection ****/
+		case 'a':
+			select_all++;
+			break;
+		case 'x':
+			select_notty++;
+			break;
+		case 'p':	/* end */
+			parse_pid(get_opt_arg());
+			return;	/* can't have any more options */
+    /**** output format ****/
+		case 'j':
+		case 'l':
+		case 'u':
+		case 'v':
+			if (ps_format)
+				usage();
+			ps_format = 0x80 | *flagptr;	/* use 0x80 to tell BSD from SysV */
+			break;
+    /**** other stuff ****/
+		case 'c':
+			bsd_c_option++;
+#if 0
+			break;
+#endif
+		case 'w':
+#if 0
+			w_count++;
+#endif
+			break;
+		case 'h':
+			old_h_option++;
+			break;
+		default:
+			usage();
+		}		/* switch */
+	} while (*++flagptr);
+}
+
+#if 0
+/* not used yet */
+static void choose_dimensions(void)
+{
+	struct winsize ws;
+	char *columns;
+	/* screen_cols is 80 by default */
+	if (ioctl(1, TIOCGWINSZ, &ws) != -1 && ws.ws_col > 30)
+		screen_cols = ws.ws_col;
+	columns = getenv("COLUMNS");
+	if (columns && *columns) {
+		long t;
+		char *endptr;
+		t = strtol(columns, &endptr, 0);
+		if (!*endptr && (t > 30) && (t < (long)999999999))
+			screen_cols = (int)t;
+	}
+	if (w_count && (screen_cols < 132))
+		screen_cols = 132;
+	if (w_count > 1)
+		screen_cols = 999999999;
+}
+#endif
+
+static void arg_parse(int argc, char *argv[])
+{
+	int sel = 0;		/* to verify option sanity */
+	ps_argc = argc;
+	ps_argv = argv;
+	thisarg = 0;
+  /**** iterate over the args ****/
+	while (++thisarg < ps_argc) {
+		flagptr = ps_argv[thisarg];
+		switch (*flagptr) {
+		case '0'...'9':
+			show_args = 1;
+			parse_pid(flagptr);
+			break;
+		case '-':
+			flagptr++;
+			parse_sysv_option();
+			break;
+		default:
+			show_args = 1;
+			parse_bsd_option();
+			break;
+		}
+	}
+  /**** sanity check and clean-up ****/
+	if (want_one_pid)
+		sel++;
+	if (want_one_command)
+		sel++;
+	if (select_notty || select_all)
+		sel++;
+	if (sel > 1 || select_notty > 1 || select_all > 1 || bsd_c_option > 1
+	    || old_h_option > 1)
+		usage();
+	if (bsd_c_option)
+		show_args = 0;
+}
+
+/* return 1 if it works, or 0 for failure */
+static int stat2proc(int pid)
+{
+	char buf[800];		/* about 40 fields, 64-bit decimal is about 20 chars */
+	int num;
+	int fd;
+	char *tmp;
+	struct stat sb;		/* stat() used to get EUID */
+	snprintf(buf, 32, "/proc/%d/stat", pid);
+	if ((fd = open(buf, O_RDONLY, 0)) == -1)
+		return 0;
+	num = read(fd, buf, sizeof buf - 1);
+	fstat(fd, &sb);
+	P_euid = sb.st_uid;
+	close(fd);
+	if (num < 80)
+		return 0;
+	buf[num] = '\0';
+	tmp = strrchr(buf, ')');	/* split into "PID (cmd" and "<rest>" */
+	*tmp = '\0';		/* replace trailing ')' with NUL */
+	/* parse these two strings separately, skipping the leading "(". */
+	memset(P_cmd, 0, sizeof P_cmd);	/* clear */
+	sscanf(buf, "%d (%15c", &P_pid, P_cmd);	/* comm[16] in kernel */
+	num = sscanf(tmp + 2,	/* skip space after ')' too */
+		     "%c " "%d %d %d %d %d " "%lu %lu %lu %lu %lu %lu %lu " "%ld %ld %ld %ld %ld %ld " "%lu %lu " "%ld " "%lu %lu %lu %lu %lu %lu " "%u %u %u %u "	/* no use for RT signals */
+		     "%lu %lu %lu",
+		     &P_state,
+		     &P_ppid, &P_pgrp, &P_session, &P_tty, &P_tpgid,
+		     &P_flags, &P_min_flt, &P_cmin_flt, &P_maj_flt, &P_cmaj_flt,
+		     &P_utime, &P_stime, &P_cutime, &P_cstime, &P_priority,
+		     &P_nice, &P_timeout, &P_it_real_value, &P_start_time,
+		     &P_vsize, &P_rss, &P_rss_rlim, &P_start_code, &P_end_code,
+		     &P_start_stack, &P_kstk_esp, &P_kstk_eip, &P_signal,
+		     &P_blocked, &P_sigignore, &P_sigcatch, &P_wchan, &P_nswap,
+		     &P_cnswap);
+/*    fprintf(stderr, "stat2proc converted %d fields.\n",num); */
+	P_vsize /= 1024;
+	P_rss <<= page_shift - 10;
+	if (num < 30)
+		return 0;
+	if (P_pid != pid)
+		return 0;
+	return 1;
+}
+
+static const char *do_time(unsigned long t)
+{
+	int hh, mm, ss;
+	static char buf[32];
+	int cnt = 0;
+	t /= HZ;
+	ss = t % 60;
+	t /= 60;
+	mm = t % 60;
+	t /= 60;
+	hh = t % 24;
+	t /= 24;
+	if (t)
+		cnt = snprintf(buf, sizeof buf, "%d-", (int)t);
+	snprintf(cnt + buf, sizeof(buf) - cnt, "%02d:%02d:%02d", hh, mm, ss);
+	return buf;
+}
+
+static void print_proc(void)
+{
+	char tty[16];
+	snprintf(tty, sizeof tty, "%3d,%-3d", (P_tty >> 8) & 0xff,
+		 P_tty & 0xff);
+	switch (ps_format) {
+	case 0:
+		printf("%5d %s %s", P_pid, tty, do_time(P_utime + P_stime));
+		break;
+	case 'o':
+		printf("%d\n", P_pid);
+		return;		/* don't want the command */
+	case 'l':
+		printf("%03x %c %5d %5d %5d  - %3d %3d - "
+		       "%5ld %06x %s %s",
+		       (unsigned)P_flags & 0x777, P_state, P_euid, P_pid,
+		       P_ppid, (int)P_priority, (int)P_nice,
+		       P_vsize >> (page_shift - 10),
+		       (unsigned)(P_wchan & 0xffffff), tty,
+		       do_time(P_utime + P_stime)
+		    );
+		break;
+	case 'f':
+		printf("%5d %5d %5d  -   -   %s %s",
+		       P_euid, P_pid, P_ppid, tty, do_time(P_utime + P_stime)
+		    );
+		break;
+	case 'j':
+		printf("%5d %5d %5d %s %s",
+		       P_pid, P_pgrp, P_session, tty, do_time(P_utime + P_stime)
+		    );
+		break;
+	case 'u' | 0x80:
+		printf("%5d %5d    -    - %5ld %5ld %s %c   -   %s",
+		       P_euid, P_pid, P_vsize, P_rss, tty, P_state,
+		       do_time(P_utime + P_stime)
+		    );
+		break;
+	case 'v' | 0x80:
+		printf("%5d %s %c %s %6d   -   - %5d    -",
+		       P_pid, tty, P_state, do_time(P_utime + P_stime),
+		       (int)P_maj_flt, (int)P_rss);
+		break;
+	case 'j' | 0x80:
+		printf("%5d %5d %5d %5d %s %5d %c %5d %s",
+		       P_ppid, P_pid, P_pgrp, P_session, tty, P_tpgid, P_state,
+		       P_euid, do_time(P_utime + P_stime)
+		    );
+		break;
+	case 'l' | 0x80:
+		printf("%03x %5d %5d %5d %3d %3d "
+		       "%5ld %4ld %06x %c %s %s",
+		       (unsigned)P_flags & 0x777, P_euid, P_pid, P_ppid,
+		       (int)P_priority, (int)P_nice, P_vsize, P_rss,
+		       (unsigned)(P_wchan & 0xffffff), P_state, tty,
+		       do_time(P_utime + P_stime)
+		    );
+		break;
+	default:
+		break;
+	}
+	if (show_args)
+		printf(" [%s]\n", P_cmd);
+	else
+		printf(" %s\n", P_cmd);
+}
+
+int main(int argc, char *argv[])
+{
+	arg_parse(argc, argv);
+
+	page_shift = __getpageshift();
+
+#if 0
+	choose_dimensions();
+#endif
+	if (!old_h_option) {
+		const char *head;
+		switch (ps_format) {
+		default:	/* can't happen */
+		case 0:
+			head = "  PID TTY         TIME CMD";
+			break;
+		case 'l':
+			head =
+			    "  F S   UID   PID  PPID  C PRI  NI ADDR SZ WCHAN    TTY       TIME CMD";
+			break;
+		case 'f':
+			head =
+			    "  UID   PID  PPID  C STIME   TTY       TIME CMD";
+			break;
+		case 'j':
+			head = "  PID  PGID   SID TTY         TIME CMD";
+			break;
+		case 'u' | 0x80:
+			head =
+			    "  UID   PID %CPU %MEM   VSZ   RSS   TTY   S START     TIME COMMAND";
+			break;
+		case 'v' | 0x80:
+			head =
+			    "  PID   TTY   S     TIME  MAJFL TRS DRS   RSS %MEM COMMAND";
+			break;
+		case 'j' | 0x80:
+			head =
+			    " PPID   PID  PGID   SID   TTY   TPGID S   UID     TIME COMMAND";
+			break;
+		case 'l' | 0x80:
+			head =
+			    "  F   UID   PID  PPID PRI  NI   VSZ  RSS WCHAN  S   TTY       TIME COMMAND";
+			break;
+		}
+		printf("%s\n", head);
+	}
+	if (want_one_pid) {
+		if (stat2proc(want_one_pid))
+			print_proc();
+		else
+			exit(1);
+	} else {
+		struct dirent *ent;	/* dirent handle */
+		DIR *dir;
+		int ouruid;
+		int found_a_proc;
+		found_a_proc = 0;
+		ouruid = getuid();
+		dir = opendir("/proc");
+		if (!dir)
+			exit(1);
+		while ((ent = readdir(dir))) {
+			if (*ent->d_name < '0' || *ent->d_name > '9')
+				continue;
+			if (!stat2proc(atoi(ent->d_name)))
+				continue;
+			if (want_one_command) {
+				if (strcmp(want_one_command, P_cmd))
+					continue;
+			} else {
+				if (!select_notty && P_tty == -1)
+					continue;
+				if (!select_all && P_euid != ouruid)
+					continue;
+			}
+			found_a_proc++;
+			print_proc();
+		}
+		closedir(dir);
+		exit(!found_a_proc);
+	}
+	return 0;
+}
diff --git a/usr/utils/mkdir.c b/usr/utils/mkdir.c
new file mode 100644
index 0000000..af241ef
--- /dev/null
+++ b/usr/utils/mkdir.c
@@ -0,0 +1,154 @@
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "file_mode.h"
+
+static mode_t leaf_mode, subdir_mode;
+static int p_flag;
+
+char *progname;
+
+static __noreturn usage(void)
+{
+	fprintf(stderr, "Usage: %s [-p] [-m mode] dir...\n", progname);
+	exit(1);
+}
+
+static int make_one_dir(char *dir, mode_t mode)
+{
+	struct stat stbuf;
+
+	if (mkdir(dir, mode) == -1) {
+		int err = errno;
+
+		/*
+		 * Ignore the error if it all of the following
+		 * are satisfied:
+		 *  - error was EEXIST
+		 *  - -p was specified
+		 *  - stat indicates that its a directory
+		 */
+		if (p_flag && errno == EEXIST &&
+		    stat(dir, &stbuf) == 0 && S_ISDIR(stbuf.st_mode))
+			return 1;
+		errno = err;
+		fprintf(stderr, "%s: ", progname);
+		perror(dir);
+		return -1;
+	}
+	return 0;
+}
+
+static int make_dir(char *dir)
+{
+	int ret;
+
+	if (p_flag) {
+		char *s, *p;
+
+		/*
+		 * Recurse each directory, trying to make it
+		 * as we go.  Should we check to see if it
+		 * exists, and if so if it's a directory
+		 * before calling mkdir?
+		 */
+		s = dir;
+		while ((p = strchr(s, '/')) != NULL) {
+			/*
+			 * Ignore the leading /
+			 */
+			if (p != dir) {
+				*p = '\0';
+
+				/*
+				 * Make the intermediary directory.  POSIX
+				 * says that these directories are created
+				 * with umask,u+wx
+				 */
+				if (make_one_dir(dir, subdir_mode) == -1)
+					return -1;
+
+				*p = '/';
+			}
+			s = p + 1;
+		}
+	}
+
+	/*
+	 * Make the final target.  Only complain if the
+	 * target already exists if -p was not specified.
+	 * This is created with the asked for mode & ~umask
+	 */
+	ret = make_one_dir(dir, leaf_mode);
+	if (ret == -1)
+		return -1;
+
+	/*
+	 * We might not set all the permission bits.  Do that
+	 * here (but only if we did create it.)
+	 */
+	if (ret == 0 && chmod(dir, leaf_mode) == -1) {
+		int err_save = errno;
+
+		/*
+		 * We failed, remove the directory we created
+		 */
+		rmdir(dir);
+		errno = err_save;
+		fprintf(stderr, "%s: ", progname);
+		perror(dir);
+		return -1;
+	}
+	return 0;
+}
+
+int main(int argc, char *argv[])
+{
+	int c, ret = 0;
+	mode_t saved_umask;
+
+	progname = argv[0];
+
+	saved_umask = umask(0);
+	leaf_mode = (S_IRWXU | S_IRWXG | S_IRWXO) & ~saved_umask;
+	subdir_mode = (saved_umask ^ (S_IRWXU | S_IRWXG | S_IRWXO))
+	    | S_IWUSR | S_IXUSR;
+
+	do {
+		c = getopt(argc, argv, "pm:");
+		if (c == EOF)
+			break;
+		switch (c) {
+		case 'm':
+			leaf_mode =
+			    parse_file_mode(optarg, leaf_mode, saved_umask);
+			break;
+		case 'p':
+			p_flag = 1;
+			break;
+
+		case '?':
+			fprintf(stderr, "%s: invalid option -%c\n",
+				progname, optopt);
+			usage();
+		}
+	} while (1);
+
+	if (optind == argc)
+		usage();
+
+	while (optind < argc) {
+		if (make_dir(argv[optind]))
+			ret = 255;	/* seems to be what gnu mkdir does */
+		optind++;
+	}
+
+	return ret;
+}
diff --git a/usr/utils/mkfifo.c b/usr/utils/mkfifo.c
new file mode 100644
index 0000000..f2ac35f
--- /dev/null
+++ b/usr/utils/mkfifo.c
@@ -0,0 +1,71 @@
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "file_mode.h"
+
+static mode_t leaf_mode;
+
+char *progname;
+
+static int make_fifo(char *dir)
+{
+	if (mkfifo(dir, leaf_mode)) {
+		/*
+		 * We failed, remove the directory we created.
+		 */
+		fprintf(stderr, "%s: ", progname);
+		perror(dir);
+		return -1;
+	}
+	return 0;
+}
+
+int main(int argc, char *argv[])
+{
+	int c, ret = 0;
+	mode_t saved_umask;
+
+	progname = argv[0];
+
+	saved_umask = umask(0);
+	leaf_mode =
+	    (S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH) &
+	    ~saved_umask;
+
+	do {
+		c = getopt(argc, argv, "m:");
+		if (c == EOF)
+			break;
+		switch (c) {
+		case 'm':
+			leaf_mode =
+			    parse_file_mode(optarg, leaf_mode, saved_umask);
+			break;
+
+		case '?':
+			fprintf(stderr, "%s: invalid option -%c\n",
+				progname, optopt);
+			exit(1);
+		}
+	} while (1);
+
+	if (optind == argc) {
+		fprintf(stderr, "Usage: %s [-m mode] file...\n", progname);
+		exit(1);
+	}
+
+	while (optind < argc) {
+		if (make_fifo(argv[optind]))
+			ret = 255;	/* seems to be what gnu mkdir does */
+		optind++;
+	}
+
+	return ret;
+}
diff --git a/usr/utils/mknod.c b/usr/utils/mknod.c
new file mode 100644
index 0000000..3145450
--- /dev/null
+++ b/usr/utils/mknod.c
@@ -0,0 +1,70 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/stat.h>
+
+char *progname;
+
+static __noreturn usage(void)
+{
+	fprintf(stderr, "Usage: %s name {b|c|p} major minor\n", progname);
+	exit(1);
+}
+
+int main(int argc, char *argv[])
+{
+	char *name, *type, typec, *endp;
+	unsigned int major, minor;
+	mode_t mode;
+	dev_t dev;
+
+	progname = *argv++;
+
+	name = *argv++;
+	if (!name)
+		usage();
+
+	type = *argv++;
+	if (!type || !type[0] || type[1])
+		usage();
+	typec = type[0];
+
+	mode = 0;
+	switch (type[0]) {
+	case 'c':
+		mode = S_IFCHR;
+		break;
+	case 'b':
+		mode = S_IFBLK;
+		break;
+	case 'p':
+		mode = S_IFIFO;
+		break;
+	default:
+		usage();
+	}
+
+	if (mode == S_IFIFO) {
+		dev = 0;
+	} else {
+		if (!argv[0] || !argv[1])
+			usage();
+
+		major = strtol(*argv++, &endp, 0);
+		if (*endp != '\0')
+			usage();
+		minor = strtol(*argv++, &endp, 0);
+		if (*endp != '\0')
+			usage();
+		dev = makedev(major, minor);
+	}
+
+	if (*argv)
+		usage();
+
+	if (mknod(name, mode|0666, dev) == -1) {
+		perror("mknod");
+		exit(1);
+	}
+
+	exit(0);
+}
diff --git a/usr/utils/mount_main.c b/usr/utils/mount_main.c
new file mode 100644
index 0000000..e8e22cd
--- /dev/null
+++ b/usr/utils/mount_main.c
@@ -0,0 +1,105 @@
+/*
+ * by rmk
+ */
+#include <sys/mount.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "mount_opts.h"
+
+char *progname;
+
+static struct extra_opts extra;
+static unsigned long rwflag;
+
+static int
+do_mount(char *dev, char *dir, char *type, unsigned long rwflag, void *data)
+{
+	char *s;
+	int error = 0;
+
+	while ((s = strsep(&type, ",")) != NULL) {
+	      retry:
+		if (mount(dev, dir, s, rwflag, data) == -1) {
+			error = errno;
+			/*
+			 * If the filesystem is not found, or the
+			 * superblock is invalid, try the next.
+			 */
+			if (error == ENODEV || error == EINVAL)
+				continue;
+
+			/*
+			 * If we get EACCESS, and we're trying to
+			 * mount readwrite and this isn't a remount,
+			 * try read only.
+			 */
+			if (error == EACCES &&
+			    (rwflag & (MS_REMOUNT | MS_RDONLY)) == 0) {
+				rwflag |= MS_RDONLY;
+				goto retry;
+			}
+			break;
+		}
+	}
+
+	if (error) {
+		errno = error;
+		perror("mount");
+		return 255;
+	}
+
+	return 0;
+}
+
+int main(int argc, char *argv[])
+{
+	char *type = NULL;
+	int c;
+
+	progname = argv[0];
+	rwflag = MS_VERBOSE;
+
+	do {
+		c = getopt(argc, argv, "o:rt:w");
+		if (c == EOF)
+			break;
+		switch (c) {
+		case 'o':
+			rwflag = parse_mount_options(optarg, rwflag, &extra);
+			break;
+		case 'r':
+			rwflag |= MS_RDONLY;
+			break;
+		case 't':
+			type = optarg;
+			break;
+		case 'w':
+			rwflag &= ~MS_RDONLY;
+			break;
+		case '?':
+			fprintf(stderr, "%s: invalid option -%c\n",
+				progname, optopt);
+			exit(1);
+		}
+	} while (1);
+
+	/*
+	 * If remount, bind or move was specified, then we don't
+	 * have a "type" as such.  Use the dummy "none" type.
+	 */
+	if (rwflag & MS_TYPE)
+		type = "none";
+
+	if (optind + 2 != argc || type == NULL) {
+		fprintf(stderr, "Usage: %s [-r] [-w] [-o options] [-t type] "
+			"device directory\n", progname);
+		exit(1);
+	}
+
+	return do_mount(argv[optind], argv[optind + 1], type, rwflag,
+			extra.str);
+}
diff --git a/usr/utils/mount_opts.c b/usr/utils/mount_opts.c
new file mode 100644
index 0000000..98f58cf
--- /dev/null
+++ b/usr/utils/mount_opts.c
@@ -0,0 +1,94 @@
+/*
+ * by rmk
+ *
+ * Decode mount options.
+ */
+#include <sys/mount.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "mount_opts.h"
+
+#define ARRAY_SIZE(x)	(sizeof(x) / sizeof(x[0]))
+
+static const struct mount_opts options[] = {
+	/* name         mask            set             noset           */
+	{"async", MS_SYNCHRONOUS, 0, MS_SYNCHRONOUS},
+	{"atime", MS_NOATIME, 0, MS_NOATIME},
+	{"bind", MS_TYPE, MS_BIND, 0,},
+	{"dev", MS_NODEV, 0, MS_NODEV},
+	{"diratime", MS_NODIRATIME, 0, MS_NODIRATIME},
+	{"dirsync", MS_DIRSYNC, MS_DIRSYNC, 0},
+	{"exec", MS_NOEXEC, 0, MS_NOEXEC},
+	{"move", MS_TYPE, MS_MOVE, 0},
+	{"recurse", MS_REC, MS_REC, 0},
+	{"remount", MS_TYPE, MS_REMOUNT, 0},
+	{"ro", MS_RDONLY, MS_RDONLY, 0},
+	{"rw", MS_RDONLY, 0, MS_RDONLY},
+	{"suid", MS_NOSUID, 0, MS_NOSUID},
+	{"sync", MS_SYNCHRONOUS, MS_SYNCHRONOUS, 0},
+	{"verbose", MS_VERBOSE, MS_VERBOSE, 0},
+};
+
+static void add_extra_option(struct extra_opts *extra, char *s)
+{
+	int len = strlen(s);
+	int newlen = extra->used_size + len;
+
+	if (extra->str)
+		len++;		/* +1 for ',' */
+
+	if (newlen >= extra->alloc_size) {
+		char *new;
+
+		new = realloc(extra->str, newlen + 1);	/* +1 for NUL */
+		if (!new)
+			return;
+
+		extra->str = new;
+		extra->end = extra->str + extra->used_size;
+		extra->alloc_size = newlen;
+	}
+
+	if (extra->used_size) {
+		*extra->end = ',';
+		extra->end++;
+	}
+	strcpy(extra->end, s);
+	extra->used_size += len;
+
+}
+
+unsigned long
+parse_mount_options(char *arg, unsigned long rwflag, struct extra_opts *extra)
+{
+	char *s;
+
+	while ((s = strsep(&arg, ",")) != NULL) {
+		char *opt = s;
+		unsigned int i;
+		int res, no = s[0] == 'n' && s[1] == 'o';
+
+		if (no)
+			s += 2;
+
+		for (i = 0, res = 1; i < ARRAY_SIZE(options); i++) {
+			res = strcmp(s, options[i].str);
+
+			if (res == 0) {
+				rwflag &= ~options[i].rwmask;
+				if (no)
+					rwflag |= options[i].rwnoset;
+				else
+					rwflag |= options[i].rwset;
+			}
+			if (res <= 0)
+				break;
+		}
+
+		if (res != 0 && s[0])
+			add_extra_option(extra, opt);
+	}
+
+	return rwflag;
+}
diff --git a/usr/utils/mount_opts.h b/usr/utils/mount_opts.h
new file mode 100644
index 0000000..cf47cae
--- /dev/null
+++ b/usr/utils/mount_opts.h
@@ -0,0 +1,26 @@
+#ifndef UTILS_MOUNT_OPTS_H
+#define UTILS_MOUNT_OPTS_H
+
+struct mount_opts {
+	const char str[8];
+	unsigned long rwmask;
+	unsigned long rwset;
+	unsigned long rwnoset;
+};
+
+struct extra_opts {
+	char *str;
+	char *end;
+	int used_size;
+	int alloc_size;
+};
+
+/*
+ * These options define the function of "mount(2)".
+ */
+#define MS_TYPE	(MS_REMOUNT|MS_BIND|MS_MOVE)
+
+unsigned long
+parse_mount_options(char *arg, unsigned long rwflag, struct extra_opts *extra);
+
+#endif /* UTILS_MOUNT_OPTS_H */
diff --git a/usr/utils/nuke.c b/usr/utils/nuke.c
new file mode 100644
index 0000000..829bd05
--- /dev/null
+++ b/usr/utils/nuke.c
@@ -0,0 +1,121 @@
+/* ----------------------------------------------------------------------- *
+ *
+ *   Copyright 2004-2006 H. Peter Anvin - All Rights Reserved
+ *
+ *   Permission is hereby granted, free of charge, to any person
+ *   obtaining a copy of this software and associated documentation
+ *   files (the "Software"), to deal in the Software without
+ *   restriction, including without limitation the rights to use,
+ *   copy, modify, merge, publish, distribute, sublicense, and/or
+ *   sell copies of the Software, and to permit persons to whom
+ *   the Software is furnished to do so, subject to the following
+ *   conditions:
+ *
+ *   The above copyright notice and this permission notice shall
+ *   be included in all copies or substantial portions of the Software.
+ *
+ *   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ *   EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ *   OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ *   NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ *   HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ *   WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ *   FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ *   OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * ----------------------------------------------------------------------- */
+
+/*
+ * Simple program which does the same thing as rm -rf, except it takes
+ * no options and can therefore not get confused by filenames starting
+ * with -.  Similarly, an empty list of inputs is assumed to mean don't
+ * do anything.
+ */
+
+#include <alloca.h>
+#include <assert.h>
+#include <dirent.h>
+#include <errno.h>
+#include <string.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+static const char *program;
+
+static int nuke(const char *what);
+
+static int nuke_dirent(int len, const char *dir, const char *name)
+{
+	int bytes = len + strlen(name) + 2;
+	char path[bytes];
+	int xlen;
+
+	xlen = snprintf(path, bytes, "%s/%s", dir, name);
+	assert(xlen < bytes);
+
+	return nuke(path);
+}
+
+/* Wipe the contents of a directory, but not the directory itself */
+static int nuke_dir(const char *what)
+{
+	int len = strlen(what);
+	DIR *dir;
+	struct dirent *d;
+	int err = 0;
+
+	if (!(dir = opendir(what))) {
+		/* EACCES means we can't read it.  Might be empty and removable;
+		   if not, the rmdir() in nuke() will trigger an error. */
+		return (errno == EACCES) ? 0 : errno;
+	}
+
+	while ((d = readdir(dir))) {
+		/* Skip . and .. */
+		if (d->d_name[0] == '.' &&
+		    (d->d_name[1] == '\0' ||
+		     (d->d_name[1] == '.' && d->d_name[2] == '\0')))
+			continue;
+
+		err = nuke_dirent(len, what, d->d_name);
+		if (err) {
+			closedir(dir);
+			return err;
+		}
+	}
+
+	closedir(dir);
+
+	return 0;
+}
+
+static int nuke(const char *what)
+{
+	int rv;
+	int err = 0;
+
+	rv = unlink(what);
+	if (rv < 0) {
+		if (errno == EISDIR) {
+			/* It's a directory. */
+			err = nuke_dir(what);
+			if (!err)
+				rmdir(what);
+		}
+	}
+
+	return 0;
+}
+
+int main(int argc, char *argv[])
+{
+	int i;
+
+	program = argv[0];
+
+	for (i = 1; i < argc; i++)
+		nuke(argv[i]);
+
+	return 0;
+}
diff --git a/usr/utils/pivot_root.c b/usr/utils/pivot_root.c
new file mode 100644
index 0000000..41b2ea0
--- /dev/null
+++ b/usr/utils/pivot_root.c
@@ -0,0 +1,19 @@
+/* Change the root file system */
+
+/* Written 2000 by Werner Almesberger */
+
+#include <stdio.h>
+#include <sys/mount.h>
+
+int main(int argc, const char **argv)
+{
+	if (argc != 3) {
+		fprintf(stderr, "Usage: %s new_root put_old\n", argv[0]);
+		return 1;
+	}
+	if (pivot_root(argv[1], argv[2]) < 0) {
+		perror("pivot_root");
+		return 1;
+	}
+	return 0;
+}
diff --git a/usr/utils/readlink.c b/usr/utils/readlink.c
new file mode 100644
index 0000000..00c2a1e
--- /dev/null
+++ b/usr/utils/readlink.c
@@ -0,0 +1,38 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/stat.h>
+
+char *progname;
+
+static __noreturn usage(void)
+{
+	fprintf(stderr, "Usage: %s link\n", progname);
+	exit(1);
+}
+
+int main(int argc, char *argv[])
+{
+	char *name, *link = NULL;
+	size_t max_siz = 128;
+
+	progname = *argv++;
+
+	name = *argv++;
+	if (!name)
+		usage();
+
+	link = malloc(max_siz);
+	if (!link) {
+		perror("malloc");
+		exit(1);
+	}
+
+	if (readlink(name, link, max_siz) == -1) {
+		perror("readlink");
+		exit(1);
+	}
+	printf("%s\n", link);
+
+	exit(0);
+}
diff --git a/usr/utils/sleep.c b/usr/utils/sleep.c
new file mode 100644
index 0000000..5df6aee
--- /dev/null
+++ b/usr/utils/sleep.c
@@ -0,0 +1,25 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <time.h>
+#include <errno.h>
+
+int main(int argc, char *argv[])
+{
+	struct timespec ts;
+	char *p;
+
+	if (argc != 2)
+		goto err;
+
+	p = strtotimespec(argv[1], &ts);
+	if (*p)
+		goto err;
+
+	while (nanosleep(&ts, &ts) == -1 && errno == EINTR) ;
+
+	return 0;
+
+      err:
+	fprintf(stderr, "Usage: %s seconds[.fraction]\n", argv[0]);
+	return 1;
+}
diff --git a/usr/utils/true.c b/usr/utils/true.c
new file mode 100644
index 0000000..31dbf45
--- /dev/null
+++ b/usr/utils/true.c
@@ -0,0 +1,4 @@
+int main(void)
+{
+	return 0;
+}
diff --git a/usr/utils/umount.c b/usr/utils/umount.c
new file mode 100644
index 0000000..85497a7
--- /dev/null
+++ b/usr/utils/umount.c
@@ -0,0 +1,48 @@
+/*
+ * by rmk
+ */
+#include <sys/mount.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+char *progname;
+
+int main(int argc, char *argv[])
+{
+	int c, flag = 0;
+
+	progname = argv[0];
+
+	do {
+		c = getopt(argc, argv, "fl");
+		if (c == EOF)
+			break;
+		switch (c) {
+		case 'f':
+			flag |= MNT_FORCE;
+			break;
+		case 'l':
+			flag |= MNT_DETACH;
+			break;
+		case '?':
+			fprintf(stderr, "%s: invalid option -%c\n",
+				progname, optopt);
+			exit(1);
+		}
+	} while (1);
+
+	if (optind + 1 != argc) {
+		fprintf(stderr, "Usage: %s [-f] [-l] mntpoint\n", progname);
+		return 1;
+	}
+
+	if (umount2(argv[optind], flag) == -1) {
+		perror("umount2");
+		return 255;
+	}
+
+	return 0;
+}
diff --git a/usr/utils/uname.c b/usr/utils/uname.c
new file mode 100644
index 0000000..88aedb9
--- /dev/null
+++ b/usr/utils/uname.c
@@ -0,0 +1,154 @@
+/*
+ * by tlh
+ *
+ * The uname program for system information: kernel name, kernel
+ * release, kernel release, machine, processor, platform, os and
+ * hostname.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <string.h>
+#include <sys/utsname.h>
+
+enum uname_fields {
+	UN_SYSNAME,
+	UN_NODENAME,
+	UN_RELEASE,
+	UN_VERSION,
+	UN_MACHINE,
+#if NOT_IMPLEMENTED_PROCESSOR
+	UN_PROCESSOR,
+#endif
+	UN_HARDWARE,
+#if NOT_IMPLEMENTED_OS
+	UN_OS,
+#endif
+	UN_NR_FIELDS
+};
+
+void usage(FILE * stream, const char *progname)
+{
+	fprintf(stream,
+		"Usage: %s [OPTION] . . .\n"
+		"Print system information,  No options defaults to -s.\n"
+		"\n"
+		"  -a   print all the information in the same order as follows below\n"
+		"  -s   kernel name\n"
+		"  -n   network node name (hostname)\n"
+		"  -r   kernel release\n"
+		"  -v   kernel version\n" "  -m   machine hardware name\n"
+#if NOT_IMPLEMENTED_PROCESSOR
+		"  -p   processor type\n"
+#endif
+		"  -i   hardware platform\n"
+#if NOT_IMPLEMENTED_OS
+		"  -o   operating system\n"
+#endif
+		"\n" "  -h   help/usage\n" "\n", progname);
+}
+
+char *make_hardware(const char *machine)
+{
+	char *hardware;
+
+	if (!(hardware = strdup(machine))) {
+		fprintf(stderr, "strdup() failed: %s\n", strerror(errno));
+		goto end;
+	}
+	if (strlen(hardware) == 4
+	    && hardware[0] == 'i' && hardware[2] == '8' && hardware[3] == '6') {
+		hardware[1] = '3';
+	}
+      end:
+	return hardware;
+}
+
+int main(int argc, char *argv[])
+{
+	int ec = 1;
+	int opt;
+	int i;
+	int nr_pr;
+	struct utsname buf;
+	char *uname_fields[UN_NR_FIELDS] = { NULL };
+
+	if (-1 == uname(&buf)) {
+		fprintf(stderr, "uname() failure: %s\n", strerror(errno));
+		goto end;
+	}
+
+	if (1 == argc)
+		/* no options given - default to -s */
+		uname_fields[UN_SYSNAME] = buf.sysname;
+
+	while ((opt = getopt(argc, argv, "asnrvmpioh")) != -1) {
+		switch (opt) {
+		case 'a':
+			uname_fields[UN_SYSNAME] = buf.sysname;
+			uname_fields[UN_NODENAME] = buf.nodename;
+			uname_fields[UN_RELEASE] = buf.release;
+			uname_fields[UN_VERSION] = buf.version;
+			uname_fields[UN_MACHINE] = buf.machine;
+			uname_fields[UN_HARDWARE] = make_hardware(buf.machine);
+			if (!uname_fields[UN_HARDWARE])
+				goto end;
+			break;
+		case 's':
+			uname_fields[UN_SYSNAME] = buf.sysname;
+			break;
+		case 'n':
+			uname_fields[UN_NODENAME] = buf.nodename;
+			break;
+		case 'r':
+			uname_fields[UN_RELEASE] = buf.release;
+			break;
+		case 'v':
+			uname_fields[UN_VERSION] = buf.version;
+			break;
+		case 'm':
+			uname_fields[UN_MACHINE] = buf.machine;
+			break;
+#if NOT_IMPLEMENTED_PROCESSOR
+		case 'p':
+			break;
+#endif
+		case 'i':
+			uname_fields[UN_HARDWARE] = make_hardware(buf.machine);
+			if (!uname_fields[UN_HARDWARE])
+				goto end;
+			break;
+#if NOT_IMPLEMENTED_OS
+		case 'o':
+			break;
+#endif
+		case 'h':
+			usage(stdout, argv[0]);
+			ec = 0;
+			goto end;
+			break;
+		default:
+			usage(stderr, argv[0]);
+			goto end;
+			break;
+		}
+	}
+
+	for (nr_pr = 0, i = UN_SYSNAME; i < UN_NR_FIELDS; i++) {
+		if (!uname_fields[i])
+			continue;
+		if (nr_pr)
+			fputc(' ', stdout);
+		fputs(uname_fields[i], stdout);
+		nr_pr++;
+	}
+	fputc('\n', stdout);
+
+	ec = 0;
+
+      end:
+	if (uname_fields[UN_HARDWARE])
+		free(uname_fields[UN_HARDWARE]);
+	return ec;
+}