[klibc] Miscellaneous utilities for klibc

A collection of minor utilities for klibc.

Signed-off-by: H. Peter Anvin <hpa@zytor.com>
diff --git a/usr/Kbuild b/usr/Kbuild
index 4b2be06..4fea24c 100644
--- a/usr/Kbuild
+++ b/usr/Kbuild
@@ -6,7 +6,7 @@
 
 include-subdir := include
 klibc-subdir := klibc
-usr-subdirs  := kinit
+usr-subdirs  := kinit utils
 subdir-      := $(include-subdir) $(klibc-subdir) $(usr-subdirs)
 
 usr-subdirs  := $(addprefix _usr_,$(usr-subdirs))
diff --git a/usr/utils/Kbuild b/usr/utils/Kbuild
new file mode 100644
index 0000000..76ffff0
--- /dev/null
+++ b/usr/utils/Kbuild
@@ -0,0 +1,62 @@
+#
+# 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
+
+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
+
+# 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..a734301
--- /dev/null
+++ b/usr/utils/chroot.c
@@ -0,0 +1,25 @@
+/*
+ * chroot.c, 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/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..ee84cb9
--- /dev/null
+++ b/usr/utils/file_mode.h
@@ -0,0 +1 @@
+mode_t parse_file_mode(char *arg, mode_t mode, mode_t sumask);
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/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..97893c2
--- /dev/null
+++ b/usr/utils/minips.c
@@ -0,0 +1,508 @@
+/*
+ * 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");
+		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..1275472
--- /dev/null
+++ b/usr/utils/mkdir.c
@@ -0,0 +1,150 @@
+#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 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);
+			exit(1);
+		}
+	} while (1);
+
+	if (optind == argc) {
+		fprintf(stderr, "Usage: %s [-p] [-m mode] dir...\n", progname);
+		exit(1);
+	}
+
+	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..1facda7
--- /dev/null
+++ b/usr/utils/mknod.c
@@ -0,0 +1,58 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/stat.h>
+
+char *progname;
+
+static __noreturn usage(void)
+{
+	fprintf(stderr, "Usage: %s name {b|c} major minor\n", progname);
+	exit(1);
+}
+
+int main(int argc, char *argv[], char *envp[])
+{
+	char *name = NULL, *endp;
+	unsigned int major, minor;
+	mode_t mode;
+	dev_t dev;
+
+	progname = argv[0];
+	if (argc != 5)
+		usage();
+
+	name = argv[1];
+	if (!name) {
+		perror("device");
+		usage();
+	}
+
+	mode = 0666;
+	if (argv[2][0] == 'c')
+		mode |= S_IFCHR;
+	else if (argv[2][0] == 'b')
+		mode |= S_IFBLK;
+	else {
+		perror("block or char devices.");
+		usage();
+	}
+
+	major = strtol(argv[3], &endp, 0);
+	if (*endp != '\0') {
+		perror("major.");
+		usage();
+	}
+	minor = strtol(argv[4], &endp, 0);
+	if (*endp != '\0') {
+		perror("minor.");
+		usage();
+	}
+	dev = makedev(major, minor);
+
+	if (mknod(name, mode, 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..347ff0c
--- /dev/null
+++ b/usr/utils/mount_main.c
@@ -0,0 +1,105 @@
+/*
+ * mount.c, 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..f2a8047
--- /dev/null
+++ b/usr/utils/mount_opts.c
@@ -0,0 +1,94 @@
+/*
+ * mount_opts.c, 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..2353262
--- /dev/null
+++ b/usr/utils/mount_opts.h
@@ -0,0 +1,21 @@
+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);
diff --git a/usr/utils/nuke.c b/usr/utils/nuke.c
new file mode 100644
index 0000000..b0e4f8e
--- /dev/null
+++ b/usr/utils/nuke.c
@@ -0,0 +1,134 @@
+/* ----------------------------------------------------------------------- *
+ *
+ *   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.
+ *
+ * ----------------------------------------------------------------------- */
+
+/*
+ * nuke.c
+ *
+ * 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)
+				err = rmdir(what) ? errno : err;
+		} else {
+			err = errno;
+		}
+	}
+
+	if (err) {
+		fprintf(stderr, "%s: %s: %s\n", program, what, strerror(err));
+		return err;
+	} else {
+		return 0;
+	}
+}
+
+int main(int argc, char *argv[])
+{
+	int i;
+	int err = 0;
+
+	program = argv[0];
+
+	for (i = 1; i < argc; i++) {
+		err = nuke(argv[i]);
+		if (err)
+			break;
+	}
+
+	return !!err;
+}
diff --git a/usr/utils/pivot_root.c b/usr/utils/pivot_root.c
new file mode 100644
index 0000000..7a570ed
--- /dev/null
+++ b/usr/utils/pivot_root.c
@@ -0,0 +1,19 @@
+/* pivot_root.c - 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/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..5628916
--- /dev/null
+++ b/usr/utils/umount.c
@@ -0,0 +1,45 @@
+/*
+ * umount.c, 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, "f");
+		if (c == EOF)
+			break;
+		switch (c) {
+		case 'f':
+			flag |= MNT_FORCE;
+			break;
+		case '?':
+			fprintf(stderr, "%s: invalid option -%c\n",
+				progname, optopt);
+			exit(1);
+		}
+	} while (1);
+
+	if (optind + 1 != argc) {
+		fprintf(stderr, "Usage: %s [-f] 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..4b7bac8
--- /dev/null
+++ b/usr/utils/uname.c
@@ -0,0 +1,154 @@
+/*
+ * uname.c, 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;
+}