Unmodified sources from Android AOSP /system/core/toolbox as
of June 9, 2011.
diff --git a/Android.mk b/Android.mk
new file mode 100644
index 0000000..ef3980a
--- /dev/null
+++ b/Android.mk
@@ -0,0 +1,95 @@
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+TOOLS := \
+	ls \
+	mount \
+	cat \
+	ps \
+	kill \
+	ln \
+	insmod \
+	rmmod \
+	lsmod \
+	ifconfig \
+	setconsole \
+	rm \
+	mkdir \
+	rmdir \
+	reboot \
+	getevent \
+	sendevent \
+	date \
+	wipe \
+	sync \
+	umount \
+	start \
+	stop \
+	notify \
+	cmp \
+	dmesg \
+	route \
+	hd \
+	dd \
+	df \
+	getprop \
+	setprop \
+	watchprops \
+	log \
+	sleep \
+	renice \
+	printenv \
+	smd \
+	chmod \
+	chown \
+	newfs_msdos \
+	netstat \
+	ioctl \
+	mv \
+	schedtop \
+	top \
+	iftop \
+	id \
+	uptime \
+	vmstat \
+	nandread \
+	ionice \
+	lsof
+
+LOCAL_SRC_FILES:= \
+	toolbox.c \
+	$(patsubst %,%.c,$(TOOLS))
+
+LOCAL_SHARED_LIBRARIES := libcutils libc
+
+LOCAL_MODULE:= toolbox
+
+# Including this will define $(intermediates).
+#
+include $(BUILD_EXECUTABLE)
+
+$(LOCAL_PATH)/toolbox.c: $(intermediates)/tools.h
+
+TOOLS_H := $(intermediates)/tools.h
+$(TOOLS_H): PRIVATE_TOOLS := $(TOOLS)
+$(TOOLS_H): PRIVATE_CUSTOM_TOOL = echo "/* file generated automatically */" > $@ ; for t in $(PRIVATE_TOOLS) ; do echo "TOOL($$t)" >> $@ ; done
+$(TOOLS_H): $(LOCAL_PATH)/Android.mk
+$(TOOLS_H):
+	$(transform-generated-source)
+
+# Make #!/system/bin/toolbox launchers for each tool.
+#
+SYMLINKS := $(addprefix $(TARGET_OUT)/bin/,$(TOOLS))
+$(SYMLINKS): TOOLBOX_BINARY := $(LOCAL_MODULE)
+$(SYMLINKS): $(LOCAL_INSTALLED_MODULE) $(LOCAL_PATH)/Android.mk
+	@echo "Symlink: $@ -> $(TOOLBOX_BINARY)"
+	@mkdir -p $(dir $@)
+	@rm -rf $@
+	$(hide) ln -sf $(TOOLBOX_BINARY) $@
+
+ALL_DEFAULT_INSTALLED_MODULES += $(SYMLINKS)
+
+# We need this so that the installed files could be picked up based on the
+# local module name
+ALL_MODULES.$(LOCAL_MODULE).INSTALLED := \
+    $(ALL_MODULES.$(LOCAL_MODULE).INSTALLED) $(SYMLINKS)
diff --git a/MODULE_LICENSE_BSD b/MODULE_LICENSE_BSD
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/MODULE_LICENSE_BSD
diff --git a/NOTICE b/NOTICE
new file mode 100644
index 0000000..895b49a
--- /dev/null
+++ b/NOTICE
@@ -0,0 +1,193 @@
+
+Copyright (c) 2010, The Android Open Source Project.
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+ * Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+ * 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.
+ * Neither the name of The Android Open Source Project 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 COPYRIGHT HOLDERS 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
+COPYRIGHT OWNER 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.
+
+
+Copyright (c) 2009, The Android Open Source Project.
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+ * Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+ * 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.
+ * Neither the name of The Android Open Source Project 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 COPYRIGHT HOLDERS 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
+COPYRIGHT OWNER 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.
+
+
+Copyright (c) 2008, The Android Open Source Project.
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+ * Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+ * 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.
+ * Neither the name of The Android Open Source Project 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 COPYRIGHT HOLDERS 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
+COPYRIGHT OWNER 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.
+
+
+Copyright (c) 1998 Robert Nordier
+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.
+This code is derived from software contributed to Berkeley by
+Keith Muller of the University of California, San Diego and Lance
+Visser of Convex Computer Corporation.
+This code is derived from software contributed to Berkeley by
+Mike Muuss.
+
+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.
+
+
+ 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.
+
+
+ Copyright (c) 1991, 1993, 1994
+	The Regents of the University of California.  All rights reserved.
+
+ This code is derived from software contributed to Berkeley by
+ Keith Muller of the University of California, San Diego and Lance
+ Visser of Convex Computer Corporation.
+
+ 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.
+
diff --git a/alarm.c b/alarm.c
new file mode 100644
index 0000000..9bd58aa
--- /dev/null
+++ b/alarm.c
@@ -0,0 +1,190 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <string.h>
+#include <errno.h>
+#include <time.h>
+#include <asm/ioctl.h>
+//#include <linux/rtc.h>
+#include <linux/android_alarm.h>
+
+int alarm_main(int argc, char *argv[])
+{
+	int c;
+    int res;
+	struct tm tm;
+	time_t t;
+	struct timespec ts;
+//	struct rtc_time rtc_time;
+	char strbuf[26];
+	int afd;
+	int nfd;
+//	struct timeval timeout = { 0, 0 };
+    int wait = 0;
+	fd_set rfds;
+	const char wake_lock_id[] = "alarm_test"; 
+	int waitalarmmask = 0;
+
+    int useutc = 0;
+	android_alarm_type_t alarmtype_low = ANDROID_ALARM_RTC_WAKEUP;
+	android_alarm_type_t alarmtype_high = ANDROID_ALARM_RTC_WAKEUP;
+	android_alarm_type_t alarmtype = 0;
+
+    do {
+        //c = getopt(argc, argv, "uw:");
+        c = getopt(argc, argv, "uwat:");
+        if (c == EOF)
+            break;
+        switch (c) {
+        case 'u':
+            useutc = 1;
+            break;
+		case 't':
+			alarmtype_low = alarmtype_high = strtol(optarg, NULL, 0);
+			break;
+		case 'a':
+			alarmtype_low = ANDROID_ALARM_RTC_WAKEUP;
+			alarmtype_high = ANDROID_ALARM_TYPE_COUNT - 1;
+			break;
+        case 'w':
+            //timeout.tv_sec = strtol(optarg, NULL, 0);
+            wait = 1;
+            break;
+        case '?':
+            fprintf(stderr, "%s: invalid option -%c\n",
+                argv[0], optopt);
+            exit(1);
+        }
+    } while (1);
+    if(optind + 2 < argc) {
+        fprintf(stderr,"%s [-uwa] [-t type] [seconds]\n", argv[0]);
+        return 1;
+    }
+
+    afd = open("/dev/alarm", O_RDWR);
+    if(afd < 0) {
+        fprintf(stderr, "Unable to open rtc: %s\n", strerror(errno));
+        return 1;
+    }
+
+    if(optind == argc) {
+		for(alarmtype = alarmtype_low; alarmtype <= alarmtype_high; alarmtype++) {
+			waitalarmmask |= 1U << alarmtype;
+		}
+#if 0
+        res = ioctl(fd, RTC_ALM_READ, &tm);
+        if(res < 0) {
+            fprintf(stderr, "Unable to read alarm: %s\n", strerror(errno));
+			return 1;
+        }
+#endif
+#if 0
+		t = timegm(&tm);
+        if(useutc)
+            gmtime_r(&t, &tm);
+        else
+            localtime_r(&t, &tm);
+#endif
+#if 0
+        asctime_r(&tm, strbuf);
+        printf("%s", strbuf);
+#endif
+    }
+    else if(optind + 1 == argc) {
+#if 0
+        res = ioctl(fd, RTC_RD_TIME, &tm);
+        if(res < 0) {
+            fprintf(stderr, "Unable to set alarm: %s\n", strerror(errno));
+			return 1;
+        }
+        asctime_r(&tm, strbuf);
+        printf("Now: %s", strbuf);
+        time(&tv.tv_sec);
+#endif
+#if 0
+		time(&ts.tv_sec);
+		ts.tv_nsec = 0;
+		
+        //strptime(argv[optind], NULL, &tm);
+        //tv.tv_sec = mktime(&tm);
+        //tv.tv_usec = 0;
+#endif
+		for(alarmtype = alarmtype_low; alarmtype <= alarmtype_high; alarmtype++) {
+			waitalarmmask |= 1U << alarmtype;
+		    res = ioctl(afd, ANDROID_ALARM_GET_TIME(alarmtype), &ts);
+		    if(res < 0) {
+		        fprintf(stderr, "Unable to get current time: %s\n", strerror(errno));
+				return 1;
+		    }
+		    ts.tv_sec += strtol(argv[optind], NULL, 0);
+		    //strtotimeval(argv[optind], &tv);
+			gmtime_r(&ts.tv_sec, &tm);
+		    printf("time %s -> %ld.%09ld\n", argv[optind], ts.tv_sec, ts.tv_nsec);
+		    asctime_r(&tm, strbuf);
+		    printf("Requested %s", strbuf);
+			
+		    res = ioctl(afd, ANDROID_ALARM_SET(alarmtype), &ts);
+		    if(res < 0) {
+		        fprintf(stderr, "Unable to set alarm: %s\n", strerror(errno));
+				return 1;
+		    }
+		}
+#if 0
+        res = ioctl(fd, RTC_ALM_SET, &tm);
+        if(res < 0) {
+            fprintf(stderr, "Unable to set alarm: %s\n", strerror(errno));
+			return 1;
+        }
+        res = ioctl(fd, RTC_AIE_ON);
+        if(res < 0) {
+            fprintf(stderr, "Unable to enable alarm: %s\n", strerror(errno));
+			return 1;
+        }
+#endif
+    }
+    else {
+        fprintf(stderr,"%s [-u] [date]\n", argv[0]);
+        return 1;
+    }
+
+	if(wait) {
+		while(waitalarmmask) {
+			printf("wait for alarm %x\n", waitalarmmask);
+			res = ioctl(afd, ANDROID_ALARM_WAIT);
+			if(res < 0) {
+				fprintf(stderr, "alarm wait failed\n");
+			}
+			printf("got alarm %x\n", res);
+			waitalarmmask &= ~res;
+			nfd = open("/sys/android_power/acquire_full_wake_lock", O_RDWR);
+			write(nfd, wake_lock_id, sizeof(wake_lock_id) - 1);
+			close(nfd);
+			//sleep(5);
+			nfd = open("/sys/android_power/release_wake_lock", O_RDWR);
+			write(nfd, wake_lock_id, sizeof(wake_lock_id) - 1);
+			close(nfd);
+		}
+		printf("done\n");
+	}
+#if 0	
+	FD_ZERO(&rfds);
+	FD_SET(fd, &rfds);
+	res = select(fd + 1, &rfds, NULL, NULL, &timeout);
+    if(res < 0) {
+        fprintf(stderr, "select failed: %s\n", strerror(errno));
+		return 1;
+    }
+	if(res > 0) {
+		int event;
+		read(fd, &event, sizeof(event));
+		fprintf(stderr, "got %x\n", event);
+	}
+	else {
+		fprintf(stderr, "timeout waiting for alarm\n");
+	}
+#endif
+
+    close(afd);
+
+    return 0;
+}
diff --git a/cat.c b/cat.c
new file mode 100644
index 0000000..6ac31f8
--- /dev/null
+++ b/cat.c
@@ -0,0 +1,291 @@
+/* $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.
+ */
+
+#include <sys/param.h>
+#include <sys/stat.h>
+
+#include <ctype.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#define CAT_BUFSIZ (4096)
+
+static int bflag, eflag, fflag, lflag, nflag, sflag, tflag, vflag;
+static int rval;
+static const char *filename;
+
+static 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;
+	}
+}
+
+static 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)
+			fclose(fp);
+	} while (*argv);
+}
+
+static void
+raw_cat(int rfd)
+{
+	static char *buf;
+	static char fb_buf[CAT_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 > CAT_BUFSIZ ?
+			    sbuf.st_blksize : CAT_BUFSIZ;
+			buf = malloc(bsize);
+		}
+		if (buf == NULL) {
+			buf = fb_buf;
+			bsize = CAT_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(EXIT_FAILURE);
+			}
+	if (nr < 0) {
+		fprintf(stderr,"%s: invalid length\n", filename);
+		rval = 1;
+	}
+}
+
+static 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))
+			close(fd);
+	} while (*argv);
+}
+
+int
+cat_main(int argc, char *argv[])
+{
+	int ch;
+	struct flock stdout_lock;
+
+	while ((ch = getopt(argc, argv, "beflnstv")) != -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 'v':
+			vflag = 1;
+			break;
+		default:
+		case '?':
+			fprintf(stderr,
+				"usage: cat [-beflnstv] [-] [file ...]\n");
+			exit(EXIT_FAILURE);
+		}
+	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(EXIT_FAILURE);
+		}
+	}
+
+	if (bflag || eflag || nflag || sflag || tflag || vflag)
+		cook_args(argv);
+	else
+		raw_args(argv);
+	if (fclose(stdout))
+	{
+		perror("fclose");
+		exit(EXIT_FAILURE);
+	}
+	exit(rval);
+}
diff --git a/chmod.c b/chmod.c
new file mode 100644
index 0000000..2a524e9
--- /dev/null
+++ b/chmod.c
@@ -0,0 +1,101 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <dirent.h>
+#include <errno.h>
+#include <sys/limits.h>
+#include <sys/stat.h>
+
+#include <unistd.h>
+#include <time.h>
+
+void recurse_chmod(char* path, int mode)
+{
+    struct dirent *dp;
+    DIR *dir = opendir(path);
+    if (dir == NULL) {
+        // not a directory, carry on
+        return;
+    }
+    char *subpath = malloc(sizeof(char)*PATH_MAX);
+    int pathlen = strlen(path);
+
+    while ((dp = readdir(dir)) != NULL) {
+        if (strcmp(dp->d_name, ".") == 0 ||
+            strcmp(dp->d_name, "..") == 0) continue;
+
+        if (strlen(dp->d_name) + pathlen + 2/*NUL and slash*/ > PATH_MAX) {
+            fprintf(stderr, "Invalid path specified: too long\n");
+            exit(1);
+        }
+
+        strcpy(subpath, path);
+        strcat(subpath, "/");
+        strcat(subpath, dp->d_name);
+
+        if (chmod(subpath, mode) < 0) {
+            fprintf(stderr, "Unable to chmod %s: %s\n", subpath, strerror(errno));
+            exit(1);
+        }
+
+        recurse_chmod(subpath, mode);
+    }
+    free(subpath);
+    closedir(dir);
+}
+
+static int usage()
+{
+    fprintf(stderr, "Usage: chmod [OPTION] <MODE> <FILE>\n");
+    fprintf(stderr, "  -R, --recursive         change files and directories recursively\n");
+    fprintf(stderr, "  --help                  display this help and exit\n");
+
+    return 10;
+}
+
+int chmod_main(int argc, char **argv)
+{
+    int i;
+
+    if (argc < 3 || strcmp(argv[1], "--help") == 0) {
+        return usage();
+    }
+
+    int recursive = (strcmp(argv[1], "-R") == 0 ||
+                     strcmp(argv[1], "--recursive") == 0) ? 1 : 0;
+
+    if (recursive && argc < 4) {
+        return usage();
+    }
+
+    if (recursive) {
+        argc--;
+        argv++;
+    }
+
+    int mode = 0;
+    const char* s = argv[1];
+    while (*s) {
+        if (*s >= '0' && *s <= '7') {
+            mode = (mode<<3) | (*s-'0');
+        }
+        else {
+            fprintf(stderr, "Bad mode\n");
+            return 10;
+        }
+        s++;
+    }
+
+    for (i = 2; i < argc; i++) {
+        if (chmod(argv[i], mode) < 0) {
+            fprintf(stderr, "Unable to chmod %s: %s\n", argv[i], strerror(errno));
+            return 10;
+        }
+        if (recursive) {
+            recurse_chmod(argv[i], mode);
+        }
+    }
+    return 0;
+}
+
diff --git a/chown.c b/chown.c
new file mode 100644
index 0000000..e9d108b
--- /dev/null
+++ b/chown.c
@@ -0,0 +1,71 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <dirent.h>
+#include <errno.h>
+#include <pwd.h>
+#include <grp.h>
+
+#include <unistd.h>
+#include <time.h>
+
+int chown_main(int argc, char **argv)
+{
+    int i;
+
+    if (argc < 3) {
+        fprintf(stderr, "Usage: chown <USER>[.GROUP] <FILE1> [FILE2] ...\n");
+        return 10;
+    }
+
+    // Copy argv[1] to 'user' so we can truncate it at the period
+    // if a group id specified.
+    char user[32];
+    char *group = NULL;
+    strncpy(user, argv[1], sizeof(user));
+    if ((group = strchr(user, '.')) != NULL) {
+        *group++ = '\0';
+    }
+
+    // Lookup uid (and gid if specified)
+    struct passwd *pw;
+    struct group *grp = NULL;
+    uid_t uid;
+    gid_t gid = -1; // passing -1 to chown preserves current group
+
+    pw = getpwnam(user);
+    if (pw != NULL) {
+        uid = pw->pw_uid;
+    } else {
+        char* endptr;
+        uid = (int) strtoul(user, &endptr, 0);
+        if (endptr == user) {  // no conversion
+          fprintf(stderr, "No such user '%s'\n", user);
+          return 10;
+        }
+    }
+
+    if (group != NULL) {
+        grp = getgrnam(group);
+        if (grp != NULL) {
+            gid = grp->gr_gid;
+        } else {
+            char* endptr;
+            gid = (int) strtoul(group, &endptr, 0);
+            if (endptr == group) {  // no conversion
+                fprintf(stderr, "No such group '%s'\n", group);
+                return 10;
+            }
+        }
+    }
+
+    for (i = 2; i < argc; i++) {
+        if (chown(argv[i], uid, gid) < 0) {
+            fprintf(stderr, "Unable to chmod %s: %s\n", argv[i], strerror(errno));
+            return 10;
+        }
+    }
+
+    return 0;
+}
diff --git a/cmp.c b/cmp.c
new file mode 100644
index 0000000..9bd2e19
--- /dev/null
+++ b/cmp.c
@@ -0,0 +1,90 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdint.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include <errno.h>
+
+int cmp_main(int argc, char *argv[])
+{
+    int c;
+    int fd1, fd2;
+	char buf1[4096], buf2[4096];
+    int res, res1, res2;
+	int rv = 0;
+	int i;
+	int filepos = 0;
+
+	int show_byte = 0;
+	int show_all = 0;
+	int limit = 0;
+
+    do {
+        c = getopt(argc, argv, "bln:");
+        if (c == EOF)
+            break;
+        switch (c) {
+        case 'b':
+            show_byte = 1;
+            break;
+        case 'l':
+            show_all = 1;
+            break;
+        case 'n':
+            limit = atoi(optarg);
+            break;
+        case '?':
+            fprintf(stderr, "%s: invalid option -%c\n",
+                argv[0], optopt);
+            exit(1);
+        }
+    } while (1);
+
+    if (optind + 2 != argc) {
+        fprintf(stderr, "Usage: %s [-b] [-l] [-n count] file1 file2\n", argv[0]);
+        exit(1);
+    }
+
+    fd1 = open(argv[optind], O_RDONLY);
+    if(fd1 < 0) {
+        fprintf(stderr, "could not open %s, %s\n", argv[optind], strerror(errno));
+        return 1;
+    }
+
+    fd2 = open(argv[optind+1], O_RDONLY);
+    if(fd2 < 0) {
+        fprintf(stderr, "could not open %s, %s\n", argv[optind+1], strerror(errno));
+        return 1;
+    }
+    
+    while(1) {
+        res1 = read(fd1, &buf1, sizeof(buf1));
+        res2 = read(fd2, &buf2, sizeof(buf2));
+		res = res1 < res2 ? res1 : res2;
+		if(res1 == 0 && res2 == 0) {
+			return rv;
+		}
+		for(i = 0; i < res; i++) {
+			if(buf1[i] != buf2[i]) {
+				printf("%s %s differ byte %d", argv[optind], argv[optind+1], filepos + i);
+				if(show_byte)
+					printf(" 0x%02x 0x%02x", buf1[i], buf2[i]);
+				printf("\n");
+				if(!show_all)
+					return 1;
+				rv = 1;
+			}
+			if(limit) {
+				limit--;
+				if(limit == 0)
+					return rv;
+			}
+		}
+		if(res1 != res2 || res < 0) {
+			printf("%s on %s\n", res < 0 ? "Read error" : "EOF", res1 < res2 ? argv[optind] : argv[optind+1]);
+			return 1;
+		}
+		filepos += res;
+    }
+}
diff --git a/date.c b/date.c
new file mode 100644
index 0000000..13b5210
--- /dev/null
+++ b/date.c
@@ -0,0 +1,132 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <string.h>
+#include <errno.h>
+#include <time.h>
+#include <linux/android_alarm.h>
+
+static void settime(char *s) {
+    struct tm tm;
+    int day = atoi(s);
+    int hour;
+    time_t t;
+    int fd;
+    struct timespec ts;
+
+    while (*s && *s != '.')
+        s++;
+
+    if (*s)
+        s++;
+
+    hour = atoi(s);
+
+    tm.tm_year = day / 10000 - 1900;
+    tm.tm_mon = (day % 10000) / 100 - 1;
+    tm.tm_mday = (day % 100);
+    tm.tm_hour = hour / 10000;
+    tm.tm_min = (hour % 10000) / 100;
+    tm.tm_sec = (hour % 100);
+    tm.tm_isdst = -1;
+
+    t = mktime(&tm);
+    
+    fd = open("/dev/alarm", O_RDWR);
+    ts.tv_sec = t;
+    ts.tv_nsec = 0;
+    ioctl(fd, ANDROID_ALARM_SET_RTC, &ts);
+}
+
+int date_main(int argc, char *argv[])
+{
+	int c;
+    int res;
+	struct tm tm;
+	time_t t;
+	struct timeval tv;
+    struct timespec ts;
+	char strbuf[260];
+    int fd;
+
+    int useutc = 0;
+
+    tzset();
+
+    do {
+        c = getopt(argc, argv, "us:");
+        if (c == EOF)
+            break;
+        switch (c) {
+        case 'u':
+            useutc = 1;
+            break;
+        case 's':
+            settime(optarg);
+            break;
+        case '?':
+            fprintf(stderr, "%s: invalid option -%c\n",
+                argv[0], optopt);
+            exit(1);
+        }
+    } while (1);
+    if(optind + 2 < argc) {
+        fprintf(stderr,"%s [-u] [date]\n", argv[0]);
+        return 1;
+    }
+
+    int hasfmt = argc == optind + 1 && argv[optind][0] == '+';
+    if(optind == argc || hasfmt) {
+        char buf[2000];
+        time(&t);
+        if (useutc) {
+            gmtime_r(&t, &tm);
+            strftime(strbuf, sizeof(strbuf),
+                     (hasfmt ? argv[optind] + 1 : "%a %b %e %H:%M:%S GMT %Y"),
+                     &tm);
+        } else {
+            localtime_r(&t, &tm);
+            strftime(strbuf, sizeof(strbuf),
+                     (hasfmt ? argv[optind] + 1 : "%a %b %e %H:%M:%S %Z %Y"),
+                     &tm);
+        }
+        printf("%s\n", strbuf);
+    }
+    else if(optind + 1 == argc) {
+#if 0
+        struct tm *tmptr;
+        tmptr = getdate(argv[optind]);
+        if(tmptr == NULL) {
+            fprintf(stderr,"getdate_r failed\n");
+            return 1;
+        }
+        tm = *tmptr;
+#if 0
+        if(getdate_r(argv[optind], &tm) < 0) {
+            fprintf(stderr,"getdate_r failed %s\n", strerror(errno));
+            return 1;
+        }
+#endif
+#endif
+        //strptime(argv[optind], NULL, &tm);
+        //tv.tv_sec = mktime(&tm);
+        //tv.tv_usec = 0;
+        strtotimeval(argv[optind], &tv);
+        printf("time %s -> %d.%d\n", argv[optind], tv.tv_sec, tv.tv_usec);
+        fd = open("/dev/alarm", O_RDWR);
+        ts.tv_sec = tv.tv_sec;
+        ts.tv_nsec = tv.tv_usec * 1000;
+        res = ioctl(fd, ANDROID_ALARM_SET_RTC, &ts);
+        //res = settimeofday(&tv, NULL);
+        if(res < 0) {
+            fprintf(stderr,"settimeofday failed %s\n", strerror(errno));
+            return 1;
+        }
+    }
+    else {
+        fprintf(stderr,"%s [-s 20070325.123456] [-u] [date]\n", argv[0]);
+        return 1;
+    }
+
+    return 0;
+}
diff --git a/dd.c b/dd.c
new file mode 100644
index 0000000..c6af3ea
--- /dev/null
+++ b/dd.c
@@ -0,0 +1,1358 @@
+/*	$NetBSD: dd.c,v 1.37 2004/01/17 21:00:16 dbj Exp $	*/
+
+/*-
+ * Copyright (c) 1991, 1993, 1994
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Keith Muller of the University of California, San Diego and Lance
+ * Visser of Convex Computer Corporation.
+ *
+ * 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/cdefs.h>
+#ifndef lint
+__COPYRIGHT("@(#) Copyright (c) 1991, 1993, 1994\n\
+	The Regents of the University of California.  All rights reserved.\n");
+#endif /* not lint */
+
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)dd.c	8.5 (Berkeley) 4/2/94";
+#else
+__RCSID("$NetBSD: dd.c,v 1.37 2004/01/17 21:00:16 dbj Exp $");
+#endif
+#endif /* not lint */
+
+#include <sys/param.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <sys/time.h>
+
+#include <ctype.h>
+#include <err.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "dd.h"
+
+#define NO_CONV
+
+//#include "extern.h"
+void block(void);
+void block_close(void);
+void dd_out(int);
+void def(void);
+void def_close(void);
+void jcl(char **);
+void pos_in(void);
+void pos_out(void);
+void summary(void);
+void summaryx(int);
+void terminate(int);
+void unblock(void);
+void unblock_close(void);
+ssize_t bwrite(int, const void *, size_t);
+
+extern IO		in, out;
+extern STAT		st;
+extern void		(*cfunc)(void);
+extern uint64_t		cpy_cnt;
+extern uint64_t		cbsz;
+extern u_int		ddflags;
+extern u_int		files_cnt;
+extern int		progress;
+extern const u_char	*ctab;
+extern const u_char	a2e_32V[], a2e_POSIX[];
+extern const u_char	e2a_32V[], e2a_POSIX[];
+extern const u_char	a2ibm_32V[], a2ibm_POSIX[];
+extern u_char		casetab[];
+
+
+#define MAX(a, b) ((a) > (b) ? (a) : (b))
+
+static void dd_close(void);
+static void dd_in(void);
+static void getfdtype(IO *);
+static int redup_clean_fd(int);
+static void setup(void);
+
+
+IO		in, out;		/* input/output state */
+STAT		st;			/* statistics */
+void		(*cfunc)(void);		/* conversion function */
+uint64_t	cpy_cnt;		/* # of blocks to copy */
+static off_t	pending = 0;		/* pending seek if sparse */
+u_int		ddflags;		/* conversion options */
+uint64_t	cbsz;			/* conversion block size */
+u_int		files_cnt = 1;		/* # of files to copy */
+int		progress = 0;		/* display sign of life */
+const u_char	*ctab;			/* conversion table */
+sigset_t	infoset;		/* a set blocking SIGINFO */
+
+int
+dd_main(int argc, char *argv[])
+{
+	int ch;
+
+	while ((ch = getopt(argc, argv, "")) != -1) {
+		switch (ch) {
+		default:
+			fprintf(stderr, "usage: dd [operand ...]\n");
+			exit(1);
+			/* NOTREACHED */
+		}
+	}
+	argc -= (optind - 1);
+	argv += (optind - 1);
+
+	jcl(argv);
+	setup();
+
+//	(void)signal(SIGINFO, summaryx);
+	(void)signal(SIGINT, terminate);
+	(void)sigemptyset(&infoset);
+//	(void)sigaddset(&infoset, SIGINFO);
+
+	(void)atexit(summary);
+
+	while (files_cnt--)
+		dd_in();
+
+	dd_close();
+	exit(0);
+	/* NOTREACHED */
+}
+
+static void
+setup(void)
+{
+
+	if (in.name == NULL) {
+		in.name = "stdin";
+		in.fd = STDIN_FILENO;
+	} else {
+		in.fd = open(in.name, O_RDONLY, 0);
+		if (in.fd < 0) {
+			fprintf(stderr, "%s: cannot open for read: %s\n",
+				in.name, strerror(errno));
+			exit(1);
+			/* NOTREACHED */
+		}
+
+		/* Ensure in.fd is outside the stdio descriptor range */
+		in.fd = redup_clean_fd(in.fd);
+	}
+
+	getfdtype(&in);
+
+	if (files_cnt > 1 && !(in.flags & ISTAPE)) {
+		fprintf(stderr,
+			"files is not supported for non-tape devices\n");
+		exit(1);
+		/* NOTREACHED */
+	}
+
+	if (out.name == NULL) {
+		/* No way to check for read access here. */
+		out.fd = STDOUT_FILENO;
+		out.name = "stdout";
+	} else {
+#define	OFLAGS \
+    (O_CREAT | (ddflags & (C_SEEK | C_NOTRUNC) ? 0 : O_TRUNC))
+		out.fd = open(out.name, O_RDWR | OFLAGS /*, DEFFILEMODE */);
+		/*
+		 * May not have read access, so try again with write only.
+		 * Without read we may have a problem if output also does
+		 * not support seeks.
+		 */
+		if (out.fd < 0) {
+			out.fd = open(out.name, O_WRONLY | OFLAGS /*, DEFFILEMODE */);
+			out.flags |= NOREAD;
+		}
+		if (out.fd < 0) {
+			fprintf(stderr, "%s: cannot open for write: %s\n",
+				out.name, strerror(errno));
+			exit(1);
+			/* NOTREACHED */
+		}
+
+		/* Ensure out.fd is outside the stdio descriptor range */
+		out.fd = redup_clean_fd(out.fd);
+	}
+
+	getfdtype(&out);
+
+	/*
+	 * Allocate space for the input and output buffers.  If not doing
+	 * record oriented I/O, only need a single buffer.
+	 */
+	if (!(ddflags & (C_BLOCK|C_UNBLOCK))) {
+		if ((in.db = malloc(out.dbsz + in.dbsz - 1)) == NULL) {
+			exit(1);
+			/* NOTREACHED */
+		}
+		out.db = in.db;
+	} else if ((in.db =
+	    malloc((u_int)(MAX(in.dbsz, cbsz) + cbsz))) == NULL ||
+	    (out.db = malloc((u_int)(out.dbsz + cbsz))) == NULL) {
+		exit(1);
+		/* NOTREACHED */
+	}
+	in.dbp = in.db;
+	out.dbp = out.db;
+
+	/* Position the input/output streams. */
+	if (in.offset)
+		pos_in();
+	if (out.offset)
+		pos_out();
+
+	/*
+	 * Truncate the output file; ignore errors because it fails on some
+	 * kinds of output files, tapes, for example.
+	 */
+	if ((ddflags & (C_OF | C_SEEK | C_NOTRUNC)) == (C_OF | C_SEEK))
+		(void)ftruncate(out.fd, (off_t)out.offset * out.dbsz);
+
+	/*
+	 * If converting case at the same time as another conversion, build a
+	 * table that does both at once.  If just converting case, use the
+	 * built-in tables.
+	 */
+	if (ddflags & (C_LCASE|C_UCASE)) {
+#ifdef	NO_CONV
+		/* Should not get here, but just in case... */
+		fprintf(stderr, "case conv and -DNO_CONV\n");
+		exit(1);
+		/* NOTREACHED */
+#else	/* NO_CONV */
+		u_int cnt;
+
+		if (ddflags & C_ASCII || ddflags & C_EBCDIC) {
+			if (ddflags & C_LCASE) {
+				for (cnt = 0; cnt < 0377; ++cnt)
+					casetab[cnt] = tolower(ctab[cnt]);
+			} else {
+				for (cnt = 0; cnt < 0377; ++cnt)
+					casetab[cnt] = toupper(ctab[cnt]);
+			}
+		} else {
+			if (ddflags & C_LCASE) {
+				for (cnt = 0; cnt < 0377; ++cnt)
+					casetab[cnt] = tolower(cnt);
+			} else {
+				for (cnt = 0; cnt < 0377; ++cnt)
+					casetab[cnt] = toupper(cnt);
+			}
+		}
+
+		ctab = casetab;
+#endif	/* NO_CONV */
+	}
+
+	(void)gettimeofday(&st.start, NULL);	/* Statistics timestamp. */
+}
+
+static void
+getfdtype(IO *io)
+{
+//	struct mtget mt;
+	struct stat sb;
+
+	if (fstat(io->fd, &sb)) {
+		fprintf(stderr, "%s: cannot fstat: %s\n",
+			io->name, strerror(errno));
+		exit(1);
+		/* NOTREACHED */
+	}
+	if (S_ISCHR(sb.st_mode))
+		io->flags |= /*ioctl(io->fd, MTIOCGET, &mt) ? ISCHR : ISTAPE; */ ISCHR;
+	else if (lseek(io->fd, (off_t)0, SEEK_CUR) == -1 && errno == ESPIPE)
+		io->flags |= ISPIPE;		/* XXX fixed in 4.4BSD */
+}
+
+/*
+ * Move the parameter file descriptor to a descriptor that is outside the
+ * stdio descriptor range, if necessary.  This is required to avoid
+ * accidentally outputting completion or error messages into the
+ * output file that were intended for the tty.
+ */
+static int
+redup_clean_fd(int fd)
+{
+	int newfd;
+
+	if (fd != STDIN_FILENO && fd != STDOUT_FILENO &&
+	    fd != STDERR_FILENO)
+		/* File descriptor is ok, return immediately. */
+		return fd;
+
+	/*
+	 * 3 is the first descriptor greater than STD*_FILENO.  Any
+	 * free descriptor valued 3 or above is acceptable...
+	 */
+	newfd = fcntl(fd, F_DUPFD, 3);
+	if (newfd < 0) {
+		fprintf(stderr, "dupfd IO: %s\n", strerror(errno));
+		exit(1);
+		/* NOTREACHED */
+	}
+
+	close(fd);
+
+	return newfd;
+}
+
+static void
+dd_in(void)
+{
+	int flags;
+	int64_t n;
+
+	for (flags = ddflags;;) {
+		if (cpy_cnt && (st.in_full + st.in_part) >= cpy_cnt)
+			return;
+
+		/*
+		 * Clear the buffer first if doing "sync" on input.
+		 * If doing block operations use spaces.  This will
+		 * affect not only the C_NOERROR case, but also the
+		 * last partial input block which should be padded
+		 * with zero and not garbage.
+		 */
+		if (flags & C_SYNC) {
+			if (flags & (C_BLOCK|C_UNBLOCK))
+				(void)memset(in.dbp, ' ', in.dbsz);
+			else
+				(void)memset(in.dbp, 0, in.dbsz);
+		}
+
+		n = read(in.fd, in.dbp, in.dbsz);
+		if (n == 0) {
+			in.dbrcnt = 0;
+			return;
+		}
+
+		/* Read error. */
+		if (n < 0) {
+
+			/*
+			 * If noerror not specified, die.  POSIX requires that
+			 * the warning message be followed by an I/O display.
+			 */
+			fprintf(stderr, "%s: read error: %s\n",
+				in.name, strerror(errno));
+			if (!(flags & C_NOERROR)) {
+				exit(1);
+				/* NOTREACHED */
+			}
+			summary();
+
+			/*
+			 * If it's not a tape drive or a pipe, seek past the
+			 * error.  If your OS doesn't do the right thing for
+			 * raw disks this section should be modified to re-read
+			 * in sector size chunks.
+			 */
+			if (!(in.flags & (ISPIPE|ISTAPE)) &&
+			    lseek(in.fd, (off_t)in.dbsz, SEEK_CUR))
+				fprintf(stderr, "%s: seek error: %s\n",
+					in.name, strerror(errno));
+
+			/* If sync not specified, omit block and continue. */
+			if (!(ddflags & C_SYNC))
+				continue;
+
+			/* Read errors count as full blocks. */
+			in.dbcnt += in.dbrcnt = in.dbsz;
+			++st.in_full;
+
+		/* Handle full input blocks. */
+		} else if (n == in.dbsz) {
+			in.dbcnt += in.dbrcnt = n;
+			++st.in_full;
+
+		/* Handle partial input blocks. */
+		} else {
+			/* If sync, use the entire block. */
+			if (ddflags & C_SYNC)
+				in.dbcnt += in.dbrcnt = in.dbsz;
+			else
+				in.dbcnt += in.dbrcnt = n;
+			++st.in_part;
+		}
+
+		/*
+		 * POSIX states that if bs is set and no other conversions
+		 * than noerror, notrunc or sync are specified, the block
+		 * is output without buffering as it is read.
+		 */
+		if (ddflags & C_BS) {
+			out.dbcnt = in.dbcnt;
+			dd_out(1);
+			in.dbcnt = 0;
+			continue;
+		}
+
+/*		if (ddflags & C_SWAB) {
+			if ((n = in.dbrcnt) & 1) {
+				++st.swab;
+				--n;
+			}
+			swab(in.dbp, in.dbp, n);
+		}
+*/
+		in.dbp += in.dbrcnt;
+		(*cfunc)();
+	}
+}
+
+/*
+ * Cleanup any remaining I/O and flush output.  If necesssary, output file
+ * is truncated.
+ */
+static void
+dd_close(void)
+{
+
+	if (cfunc == def)
+		def_close();
+	else if (cfunc == block)
+		block_close();
+	else if (cfunc == unblock)
+		unblock_close();
+	if (ddflags & C_OSYNC && out.dbcnt < out.dbsz) {
+		(void)memset(out.dbp, 0, out.dbsz - out.dbcnt);
+		out.dbcnt = out.dbsz;
+	}
+	/* If there are pending sparse blocks, make sure
+	 * to write out the final block un-sparse
+	 */
+	if ((out.dbcnt == 0) && pending) {
+		memset(out.db, 0, out.dbsz);
+		out.dbcnt = out.dbsz;
+		out.dbp = out.db + out.dbcnt;
+		pending -= out.dbsz;
+	}
+	if (out.dbcnt)
+		dd_out(1);
+
+	/*
+	 * Reporting nfs write error may be defered until next
+	 * write(2) or close(2) system call.  So, we need to do an
+	 * extra check.  If an output is stdout, the file structure
+	 * may be shared among with other processes and close(2) just
+	 * decreases the reference count.
+	 */
+	if (out.fd == STDOUT_FILENO && fsync(out.fd) == -1 && errno != EINVAL) {
+		fprintf(stderr, "fsync stdout: %s\n", strerror(errno));
+		exit(1);
+		/* NOTREACHED */
+	}
+	if (close(out.fd) == -1) {
+		fprintf(stderr, "close: %s\n", strerror(errno));
+		exit(1);
+		/* NOTREACHED */
+	}
+}
+
+void
+dd_out(int force)
+{
+	static int warned;
+	int64_t cnt, n, nw;
+	u_char *outp;
+
+	/*
+	 * Write one or more blocks out.  The common case is writing a full
+	 * output block in a single write; increment the full block stats.
+	 * Otherwise, we're into partial block writes.  If a partial write,
+	 * and it's a character device, just warn.  If a tape device, quit.
+	 *
+	 * The partial writes represent two cases.  1: Where the input block
+	 * was less than expected so the output block was less than expected.
+	 * 2: Where the input block was the right size but we were forced to
+	 * write the block in multiple chunks.  The original versions of dd(1)
+	 * never wrote a block in more than a single write, so the latter case
+	 * never happened.
+	 *
+	 * One special case is if we're forced to do the write -- in that case
+	 * we play games with the buffer size, and it's usually a partial write.
+	 */
+	outp = out.db;
+	for (n = force ? out.dbcnt : out.dbsz;; n = out.dbsz) {
+		for (cnt = n;; cnt -= nw) {
+
+			if (!force && ddflags & C_SPARSE) {
+				int sparse, i;
+				sparse = 1;	/* Is buffer sparse? */
+				for (i = 0; i < cnt; i++)
+					if (outp[i] != 0) {
+						sparse = 0;
+						break;
+					}
+				if (sparse) {
+					pending += cnt;
+					outp += cnt;
+					nw = 0;
+					break;
+				}
+			}
+			if (pending != 0) {
+				if (lseek(out.fd, pending, SEEK_CUR) ==
+				    -1) {
+					fprintf(stderr,
+						"%s: seek error creating "
+						"sparse file: %s\n",
+						out.name, strerror(errno));
+					exit(1);
+				}
+			}
+			nw = bwrite(out.fd, outp, cnt);
+			if (nw <= 0) {
+				if (nw == 0) {
+					fprintf(stderr, "%s: end of device\n",
+						out.name);
+					exit(1);
+					/* NOTREACHED */
+				}
+				if (errno != EINTR) {
+					fprintf(stderr, "%s: write error: %s\n",
+						out.name, strerror(errno));
+					/* NOTREACHED */
+					exit(1);
+				}
+				nw = 0;
+			}
+			if (pending) {
+				st.bytes += pending;
+				st.sparse += pending/out.dbsz;
+				st.out_full += pending/out.dbsz;
+				pending = 0;
+			}
+			outp += nw;
+			st.bytes += nw;
+			if (nw == n) {
+				if (n != out.dbsz)
+					++st.out_part;
+				else
+					++st.out_full;
+				break;
+			}
+			++st.out_part;
+			if (nw == cnt)
+				break;
+			if (out.flags & ISCHR && !warned) {
+				warned = 1;
+				fprintf(stderr, "%s: short write on character "
+					"device\n", out.name);
+			}
+			if (out.flags & ISTAPE) {
+				fprintf(stderr,
+					"%s: short write on tape device",
+					out.name);
+				exit(1);
+				/* NOTREACHED */
+			}
+		}
+		if ((out.dbcnt -= n) < out.dbsz)
+			break;
+	}
+
+	/* Reassemble the output block. */
+	if (out.dbcnt)
+		(void)memmove(out.db, out.dbp - out.dbcnt, out.dbcnt);
+	out.dbp = out.db + out.dbcnt;
+
+	if (progress)
+		(void)write(STDERR_FILENO, ".", 1);
+}
+
+/*
+ * A protected against SIGINFO write
+ */
+ssize_t
+bwrite(int fd, const void *buf, size_t len)
+{
+	sigset_t oset;
+	ssize_t rv;
+	int oerrno;
+
+	(void)sigprocmask(SIG_BLOCK, &infoset, &oset);
+	rv = write(fd, buf, len);
+	oerrno = errno;
+	(void)sigprocmask(SIG_SETMASK, &oset, NULL);
+	errno = oerrno;
+	return (rv);
+}
+
+/*
+ * Position input/output data streams before starting the copy.  Device type
+ * dependent.  Seekable devices use lseek, and the rest position by reading.
+ * Seeking past the end of file can cause null blocks to be written to the
+ * output.
+ */
+void
+pos_in(void)
+{
+	int bcnt, cnt, nr, warned;
+
+	/* If not a pipe or tape device, try to seek on it. */
+	if (!(in.flags & (ISPIPE|ISTAPE))) {
+		if (lseek(in.fd,
+		    (off_t)in.offset * (off_t)in.dbsz, SEEK_CUR) == -1) {
+			fprintf(stderr, "%s: seek error: %s",
+				in.name, strerror(errno));
+			exit(1);
+			/* NOTREACHED */
+		}
+		return;
+		/* NOTREACHED */
+	}
+
+	/*
+	 * Read the data.  If a pipe, read until satisfy the number of bytes
+	 * being skipped.  No differentiation for reading complete and partial
+	 * blocks for other devices.
+	 */
+	for (bcnt = in.dbsz, cnt = in.offset, warned = 0; cnt;) {
+		if ((nr = read(in.fd, in.db, bcnt)) > 0) {
+			if (in.flags & ISPIPE) {
+				if (!(bcnt -= nr)) {
+					bcnt = in.dbsz;
+					--cnt;
+				}
+			} else
+				--cnt;
+			continue;
+		}
+
+		if (nr == 0) {
+			if (files_cnt > 1) {
+				--files_cnt;
+				continue;
+			}
+			fprintf(stderr, "skip reached end of input\n");
+			exit(1);
+			/* NOTREACHED */
+		}
+
+		/*
+		 * Input error -- either EOF with no more files, or I/O error.
+		 * If noerror not set die.  POSIX requires that the warning
+		 * message be followed by an I/O display.
+		 */
+		if (ddflags & C_NOERROR) {
+			if (!warned) {
+
+				fprintf(stderr, "%s: error occurred\n",
+					in.name);
+				warned = 1;
+				summary();
+			}
+			continue;
+		}
+		fprintf(stderr, "%s: read error: %s", in.name, strerror(errno));
+		exit(1);
+		/* NOTREACHED */
+	}
+}
+
+void
+pos_out(void)
+{
+//	struct mtop t_op;
+	int cnt, n;
+
+	/*
+	 * If not a tape, try seeking on the file.  Seeking on a pipe is
+	 * going to fail, but don't protect the user -- they shouldn't
+	 * have specified the seek operand.
+	 */
+	if (!(out.flags & ISTAPE)) {
+		if (lseek(out.fd,
+		    (off_t)out.offset * (off_t)out.dbsz, SEEK_SET) == -1) {
+			fprintf(stderr, "%s: seek error: %s\n",
+				out.name, strerror(errno));
+			exit(1);
+			/* NOTREACHED */
+		}
+		return;
+	}
+
+	/* If no read access, try using mtio. */
+	if (out.flags & NOREAD) {
+/*		t_op.mt_op = MTFSR;
+		t_op.mt_count = out.offset;
+
+		if (ioctl(out.fd, MTIOCTOP, &t_op) < 0)*/
+			fprintf(stderr, "%s: cannot read", out.name);
+			exit(1);
+			/* NOTREACHED */
+		return;
+	}
+
+	/* Read it. */
+	for (cnt = 0; cnt < out.offset; ++cnt) {
+		if ((n = read(out.fd, out.db, out.dbsz)) > 0)
+			continue;
+
+		if (n < 0) {
+			fprintf(stderr, "%s: cannot position by reading: %s\n",
+				out.name, strerror(errno));
+			exit(1);
+			/* NOTREACHED */
+		}
+
+		/*
+		 * If reach EOF, fill with NUL characters; first, back up over
+		 * the EOF mark.  Note, cnt has not yet been incremented, so
+		 * the EOF read does not count as a seek'd block.
+		 */
+/*		t_op.mt_op = MTBSR;
+		t_op.mt_count = 1;
+		if (ioctl(out.fd, MTIOCTOP, &t_op) == -1) */ {
+			fprintf(stderr, "%s: cannot position\n", out.name);
+			exit(1);
+			/* NOTREACHED */
+		}
+
+		while (cnt++ < out.offset)
+			if ((n = bwrite(out.fd, out.db, out.dbsz)) != out.dbsz) {
+				fprintf(stderr, "%s: cannot position "
+					"by writing: %s\n",
+					out.name, strerror(errno));
+				exit(1);
+				/* NOTREACHED */
+			}
+		break;
+	}
+}
+
+/*
+ * def --
+ * Copy input to output.  Input is buffered until reaches obs, and then
+ * output until less than obs remains.  Only a single buffer is used.
+ * Worst case buffer calculation is (ibs + obs - 1).
+ */
+void
+def(void)
+{
+	uint64_t cnt;
+	u_char *inp;
+	const u_char *t;
+
+	if ((t = ctab) != NULL)
+		for (inp = in.dbp - (cnt = in.dbrcnt); cnt--; ++inp)
+			*inp = t[*inp];
+
+	/* Make the output buffer look right. */
+	out.dbp = in.dbp;
+	out.dbcnt = in.dbcnt;
+
+	if (in.dbcnt >= out.dbsz) {
+		/* If the output buffer is full, write it. */
+		dd_out(0);
+
+		/*
+		 * Ddout copies the leftover output to the beginning of
+		 * the buffer and resets the output buffer.  Reset the
+		 * input buffer to match it.
+	 	 */
+		in.dbp = out.dbp;
+		in.dbcnt = out.dbcnt;
+	}
+}
+
+void
+def_close(void)
+{
+
+	/* Just update the count, everything is already in the buffer. */
+	if (in.dbcnt)
+		out.dbcnt = in.dbcnt;
+}
+
+#ifdef	NO_CONV
+/* Build a smaller version (i.e. for a miniroot) */
+/* These can not be called, but just in case...  */
+static const char no_block[] = "unblock and -DNO_CONV?\n";
+void block(void)		{ fprintf(stderr, "%s", no_block + 2); exit(1); }
+void block_close(void)		{ fprintf(stderr, "%s", no_block + 2); exit(1); }
+void unblock(void)		{ fprintf(stderr, "%s", no_block); exit(1); }
+void unblock_close(void)	{ fprintf(stderr, "%s", no_block); exit(1); }
+#else	/* NO_CONV */
+
+/*
+ * Copy variable length newline terminated records with a max size cbsz
+ * bytes to output.  Records less than cbs are padded with spaces.
+ *
+ * max in buffer:  MAX(ibs, cbsz)
+ * max out buffer: obs + cbsz
+ */
+void
+block(void)
+{
+	static int intrunc;
+	int ch = 0;	/* pacify gcc */
+	uint64_t cnt, maxlen;
+	u_char *inp, *outp;
+	const u_char *t;
+
+	/*
+	 * Record truncation can cross block boundaries.  If currently in a
+	 * truncation state, keep tossing characters until reach a newline.
+	 * Start at the beginning of the buffer, as the input buffer is always
+	 * left empty.
+	 */
+	if (intrunc) {
+		for (inp = in.db, cnt = in.dbrcnt;
+		    cnt && *inp++ != '\n'; --cnt);
+		if (!cnt) {
+			in.dbcnt = 0;
+			in.dbp = in.db;
+			return;
+		}
+		intrunc = 0;
+		/* Adjust the input buffer numbers. */
+		in.dbcnt = cnt - 1;
+		in.dbp = inp + cnt - 1;
+	}
+
+	/*
+	 * Copy records (max cbsz size chunks) into the output buffer.  The
+	 * translation is done as we copy into the output buffer.
+	 */
+	for (inp = in.dbp - in.dbcnt, outp = out.dbp; in.dbcnt;) {
+		maxlen = MIN(cbsz, in.dbcnt);
+		if ((t = ctab) != NULL)
+			for (cnt = 0;
+			    cnt < maxlen && (ch = *inp++) != '\n'; ++cnt)
+				*outp++ = t[ch];
+		else
+			for (cnt = 0;
+			    cnt < maxlen && (ch = *inp++) != '\n'; ++cnt)
+				*outp++ = ch;
+		/*
+		 * Check for short record without a newline.  Reassemble the
+		 * input block.
+		 */
+		if (ch != '\n' && in.dbcnt < cbsz) {
+			(void)memmove(in.db, in.dbp - in.dbcnt, in.dbcnt);
+			break;
+		}
+
+		/* Adjust the input buffer numbers. */
+		in.dbcnt -= cnt;
+		if (ch == '\n')
+			--in.dbcnt;
+
+		/* Pad short records with spaces. */
+		if (cnt < cbsz)
+			(void)memset(outp, ctab ? ctab[' '] : ' ', cbsz - cnt);
+		else {
+			/*
+			 * If the next character wouldn't have ended the
+			 * block, it's a truncation.
+			 */
+			if (!in.dbcnt || *inp != '\n')
+				++st.trunc;
+
+			/* Toss characters to a newline. */
+			for (; in.dbcnt && *inp++ != '\n'; --in.dbcnt);
+			if (!in.dbcnt)
+				intrunc = 1;
+			else
+				--in.dbcnt;
+		}
+
+		/* Adjust output buffer numbers. */
+		out.dbp += cbsz;
+		if ((out.dbcnt += cbsz) >= out.dbsz)
+			dd_out(0);
+		outp = out.dbp;
+	}
+	in.dbp = in.db + in.dbcnt;
+}
+
+void
+block_close(void)
+{
+
+	/*
+	 * Copy any remaining data into the output buffer and pad to a record.
+	 * Don't worry about truncation or translation, the input buffer is
+	 * always empty when truncating, and no characters have been added for
+	 * translation.  The bottom line is that anything left in the input
+	 * buffer is a truncated record.  Anything left in the output buffer
+	 * just wasn't big enough.
+	 */
+	if (in.dbcnt) {
+		++st.trunc;
+		(void)memmove(out.dbp, in.dbp - in.dbcnt, in.dbcnt);
+		(void)memset(out.dbp + in.dbcnt,
+		    ctab ? ctab[' '] : ' ', cbsz - in.dbcnt);
+		out.dbcnt += cbsz;
+	}
+}
+
+/*
+ * Convert fixed length (cbsz) records to variable length.  Deletes any
+ * trailing blanks and appends a newline.
+ *
+ * max in buffer:  MAX(ibs, cbsz) + cbsz
+ * max out buffer: obs + cbsz
+ */
+void
+unblock(void)
+{
+	uint64_t cnt;
+	u_char *inp;
+	const u_char *t;
+
+	/* Translation and case conversion. */
+	if ((t = ctab) != NULL)
+		for (cnt = in.dbrcnt, inp = in.dbp - 1; cnt--; inp--)
+			*inp = t[*inp];
+	/*
+	 * Copy records (max cbsz size chunks) into the output buffer.  The
+	 * translation has to already be done or we might not recognize the
+	 * spaces.
+	 */
+	for (inp = in.db; in.dbcnt >= cbsz; inp += cbsz, in.dbcnt -= cbsz) {
+		for (t = inp + cbsz - 1; t >= inp && *t == ' '; --t);
+		if (t >= inp) {
+			cnt = t - inp + 1;
+			(void)memmove(out.dbp, inp, cnt);
+			out.dbp += cnt;
+			out.dbcnt += cnt;
+		}
+		++out.dbcnt;
+		*out.dbp++ = '\n';
+		if (out.dbcnt >= out.dbsz)
+			dd_out(0);
+	}
+	if (in.dbcnt)
+		(void)memmove(in.db, in.dbp - in.dbcnt, in.dbcnt);
+	in.dbp = in.db + in.dbcnt;
+}
+
+void
+unblock_close(void)
+{
+	uint64_t cnt;
+	u_char *t;
+
+	if (in.dbcnt) {
+		warnx("%s: short input record", in.name);
+		for (t = in.db + in.dbcnt - 1; t >= in.db && *t == ' '; --t);
+		if (t >= in.db) {
+			cnt = t - in.db + 1;
+			(void)memmove(out.dbp, in.db, cnt);
+			out.dbp += cnt;
+			out.dbcnt += cnt;
+		}
+		++out.dbcnt;
+		*out.dbp++ = '\n';
+	}
+}
+
+#endif	/* NO_CONV */
+
+#define	tv2mS(tv) ((tv).tv_sec * 1000LL + ((tv).tv_usec + 500) / 1000)
+
+void
+summary(void)
+{
+	char buf[100];
+	int64_t mS;
+	struct timeval tv;
+
+	if (progress)
+		(void)write(STDERR_FILENO, "\n", 1);
+
+	(void)gettimeofday(&tv, NULL);
+	mS = tv2mS(tv) - tv2mS(st.start);
+	if (mS == 0)
+		mS = 1;
+	/* Use snprintf(3) so that we don't reenter stdio(3). */
+	(void)snprintf(buf, sizeof(buf),
+	    "%llu+%llu records in\n%llu+%llu records out\n",
+	    (unsigned long long)st.in_full,  (unsigned long long)st.in_part,
+	    (unsigned long long)st.out_full, (unsigned long long)st.out_part);
+	(void)write(STDERR_FILENO, buf, strlen(buf));
+	if (st.swab) {
+		(void)snprintf(buf, sizeof(buf), "%llu odd length swab %s\n",
+		    (unsigned long long)st.swab,
+		    (st.swab == 1) ? "block" : "blocks");
+		(void)write(STDERR_FILENO, buf, strlen(buf));
+	}
+	if (st.trunc) {
+		(void)snprintf(buf, sizeof(buf), "%llu truncated %s\n",
+		    (unsigned long long)st.trunc,
+		    (st.trunc == 1) ? "block" : "blocks");
+		(void)write(STDERR_FILENO, buf, strlen(buf));
+	}
+	if (st.sparse) {
+		(void)snprintf(buf, sizeof(buf), "%llu sparse output %s\n",
+		    (unsigned long long)st.sparse,
+		    (st.sparse == 1) ? "block" : "blocks");
+		(void)write(STDERR_FILENO, buf, strlen(buf));
+	}
+	(void)snprintf(buf, sizeof(buf),
+	    "%llu bytes transferred in %lu.%03d secs (%llu bytes/sec)\n",
+	    (unsigned long long) st.bytes,
+	    (long) (mS / 1000),
+	    (int) (mS % 1000),
+	    (unsigned long long) (st.bytes * 1000LL / mS));
+	(void)write(STDERR_FILENO, buf, strlen(buf));
+}
+
+void
+terminate(int notused)
+{
+
+	exit(0);
+	/* NOTREACHED */
+}
+
+static int	c_arg(const void *, const void *);
+#ifndef	NO_CONV
+static int	c_conv(const void *, const void *);
+#endif
+static void	f_bs(char *);
+static void	f_cbs(char *);
+static void	f_conv(char *);
+static void	f_count(char *);
+static void	f_files(char *);
+static void	f_ibs(char *);
+static void	f_if(char *);
+static void	f_obs(char *);
+static void	f_of(char *);
+static void	f_seek(char *);
+static void	f_skip(char *);
+static void	f_progress(char *);
+
+static const struct arg {
+	const char *name;
+	void (*f)(char *);
+	u_int set, noset;
+} args[] = {
+     /* the array needs to be sorted by the first column so
+	bsearch() can be used to find commands quickly */
+	{ "bs",		f_bs,		C_BS,	 C_BS|C_IBS|C_OBS|C_OSYNC },
+	{ "cbs",	f_cbs,		C_CBS,	 C_CBS },
+	{ "conv",	f_conv,		0,	 0 },
+	{ "count",	f_count,	C_COUNT, C_COUNT },
+	{ "files",	f_files,	C_FILES, C_FILES },
+	{ "ibs",	f_ibs,		C_IBS,	 C_BS|C_IBS },
+	{ "if",		f_if,		C_IF,	 C_IF },
+	{ "obs",	f_obs,		C_OBS,	 C_BS|C_OBS },
+	{ "of",		f_of,		C_OF,	 C_OF },
+	{ "progress",	f_progress,	0,	 0 },
+	{ "seek",	f_seek,		C_SEEK,	 C_SEEK },
+	{ "skip",	f_skip,		C_SKIP,	 C_SKIP },
+};
+
+/*
+ * args -- parse JCL syntax of dd.
+ */
+void
+jcl(char **argv)
+{
+	struct arg *ap, tmp;
+	char *oper, *arg;
+
+	in.dbsz = out.dbsz = 512;
+
+	while ((oper = *++argv) != NULL) {
+		if ((arg = strchr(oper, '=')) == NULL) {
+			fprintf(stderr, "unknown operand %s\n", oper);
+			exit(1);
+			/* NOTREACHED */
+		}
+		*arg++ = '\0';
+		if (!*arg) {
+			fprintf(stderr, "no value specified for %s\n", oper);
+			exit(1);
+			/* NOTREACHED */
+		}
+		tmp.name = oper;
+		if (!(ap = (struct arg *)bsearch(&tmp, args,
+		    sizeof(args)/sizeof(struct arg), sizeof(struct arg),
+		    c_arg))) {
+			fprintf(stderr, "unknown operand %s\n", tmp.name);
+			exit(1);
+			/* NOTREACHED */
+		}
+		if (ddflags & ap->noset) {
+			fprintf(stderr,
+			    "%s: illegal argument combination or already set\n",
+			    tmp.name);
+			exit(1);
+			/* NOTREACHED */
+		}
+		ddflags |= ap->set;
+		ap->f(arg);
+	}
+
+	/* Final sanity checks. */
+
+	if (ddflags & C_BS) {
+		/*
+		 * Bs is turned off by any conversion -- we assume the user
+		 * just wanted to set both the input and output block sizes
+		 * and didn't want the bs semantics, so we don't warn.
+		 */
+		if (ddflags & (C_BLOCK | C_LCASE | C_SWAB | C_UCASE |
+		    C_UNBLOCK | C_OSYNC | C_ASCII | C_EBCDIC | C_SPARSE)) {
+			ddflags &= ~C_BS;
+			ddflags |= C_IBS|C_OBS;
+		}
+
+		/* Bs supersedes ibs and obs. */
+		if (ddflags & C_BS && ddflags & (C_IBS|C_OBS))
+			fprintf(stderr, "bs supersedes ibs and obs\n");
+	}
+
+	/*
+	 * Ascii/ebcdic and cbs implies block/unblock.
+	 * Block/unblock requires cbs and vice-versa.
+	 */
+	if (ddflags & (C_BLOCK|C_UNBLOCK)) {
+		if (!(ddflags & C_CBS)) {
+			fprintf(stderr, "record operations require cbs\n");
+			exit(1);
+			/* NOTREACHED */
+		}
+		cfunc = ddflags & C_BLOCK ? block : unblock;
+	} else if (ddflags & C_CBS) {
+		if (ddflags & (C_ASCII|C_EBCDIC)) {
+			if (ddflags & C_ASCII) {
+				ddflags |= C_UNBLOCK;
+				cfunc = unblock;
+			} else {
+				ddflags |= C_BLOCK;
+				cfunc = block;
+			}
+		} else {
+			fprintf(stderr,
+			    "cbs meaningless if not doing record operations\n");
+			exit(1);
+			/* NOTREACHED */
+		}
+	} else
+		cfunc = def;
+
+	/* Read, write and seek calls take off_t as arguments.
+	 *
+	 * The following check is not done because an off_t is a quad
+	 *  for current NetBSD implementations.
+	 *
+	 * if (in.offset > INT_MAX/in.dbsz || out.offset > INT_MAX/out.dbsz)
+	 *	errx(1, "seek offsets cannot be larger than %d", INT_MAX);
+	 */
+}
+
+static int
+c_arg(const void *a, const void *b)
+{
+
+	return (strcmp(((const struct arg *)a)->name,
+	    ((const struct arg *)b)->name));
+}
+
+static long long strsuftoll(const char* name, const char* arg, int def, unsigned int max)
+{
+	long long result;
+	
+	if (sscanf(arg, "%lld", &result) == 0)
+		result = def;
+	return result;
+}
+
+static void
+f_bs(char *arg)
+{
+
+	in.dbsz = out.dbsz = strsuftoll("block size", arg, 1, UINT_MAX);
+}
+
+static void
+f_cbs(char *arg)
+{
+
+	cbsz = strsuftoll("conversion record size", arg, 1, UINT_MAX);
+}
+
+static void
+f_count(char *arg)
+{
+
+	cpy_cnt = strsuftoll("block count", arg, 0, LLONG_MAX);
+	if (!cpy_cnt)
+		terminate(0);
+}
+
+static void
+f_files(char *arg)
+{
+
+	files_cnt = (u_int)strsuftoll("file count", arg, 0, UINT_MAX);
+	if (!files_cnt)
+		terminate(0);
+}
+
+static void
+f_ibs(char *arg)
+{
+
+	if (!(ddflags & C_BS))
+		in.dbsz = strsuftoll("input block size", arg, 1, UINT_MAX);
+}
+
+static void
+f_if(char *arg)
+{
+
+	in.name = arg;
+}
+
+static void
+f_obs(char *arg)
+{
+
+	if (!(ddflags & C_BS))
+		out.dbsz = strsuftoll("output block size", arg, 1, UINT_MAX);
+}
+
+static void
+f_of(char *arg)
+{
+
+	out.name = arg;
+}
+
+static void
+f_seek(char *arg)
+{
+
+	out.offset = strsuftoll("seek blocks", arg, 0, LLONG_MAX);
+}
+
+static void
+f_skip(char *arg)
+{
+
+	in.offset = strsuftoll("skip blocks", arg, 0, LLONG_MAX);
+}
+
+static void
+f_progress(char *arg)
+{
+
+	if (*arg != '0')
+		progress = 1;
+}
+
+#ifdef	NO_CONV
+/* Build a small version (i.e. for a ramdisk root) */
+static void
+f_conv(char *arg)
+{
+
+	fprintf(stderr, "conv option disabled\n");
+	exit(1);
+	/* NOTREACHED */
+}
+#else	/* NO_CONV */
+
+static const struct conv {
+	const char *name;
+	u_int set, noset;
+	const u_char *ctab;
+} clist[] = {
+	{ "ascii",	C_ASCII,	C_EBCDIC,	e2a_POSIX },
+	{ "block",	C_BLOCK,	C_UNBLOCK,	NULL },
+	{ "ebcdic",	C_EBCDIC,	C_ASCII,	a2e_POSIX },
+	{ "ibm",	C_EBCDIC,	C_ASCII,	a2ibm_POSIX },
+	{ "lcase",	C_LCASE,	C_UCASE,	NULL },
+	{ "noerror",	C_NOERROR,	0,		NULL },
+	{ "notrunc",	C_NOTRUNC,	0,		NULL },
+	{ "oldascii",	C_ASCII,	C_EBCDIC,	e2a_32V },
+	{ "oldebcdic",	C_EBCDIC,	C_ASCII,	a2e_32V },
+	{ "oldibm",	C_EBCDIC,	C_ASCII,	a2ibm_32V },
+	{ "osync",	C_OSYNC,	C_BS,		NULL },
+	{ "sparse",	C_SPARSE,	0,		NULL },
+	{ "swab",	C_SWAB,		0,		NULL },
+	{ "sync",	C_SYNC,		0,		NULL },
+	{ "ucase",	C_UCASE,	C_LCASE,	NULL },
+	{ "unblock",	C_UNBLOCK,	C_BLOCK,	NULL },
+	/* If you add items to this table, be sure to add the
+	 * conversions to the C_BS check in the jcl routine above.
+	 */
+};
+
+static void
+f_conv(char *arg)
+{
+	struct conv *cp, tmp;
+
+	while (arg != NULL) {
+		tmp.name = strsep(&arg, ",");
+		if (!(cp = (struct conv *)bsearch(&tmp, clist,
+		    sizeof(clist)/sizeof(struct conv), sizeof(struct conv),
+		    c_conv))) {
+			errx(EXIT_FAILURE, "unknown conversion %s", tmp.name);
+			/* NOTREACHED */
+		}
+		if (ddflags & cp->noset) {
+			errx(EXIT_FAILURE, "%s: illegal conversion combination", tmp.name);
+			/* NOTREACHED */
+		}
+		ddflags |= cp->set;
+		if (cp->ctab)
+			ctab = cp->ctab;
+	}
+}
+
+static int
+c_conv(const void *a, const void *b)
+{
+
+	return (strcmp(((const struct conv *)a)->name,
+	    ((const struct conv *)b)->name));
+}
+
+#endif	/* NO_CONV */
+
+
diff --git a/dd.h b/dd.h
new file mode 100644
index 0000000..794a464
--- /dev/null
+++ b/dd.h
@@ -0,0 +1,91 @@
+/*	$NetBSD: dd.h,v 1.12 2004/01/17 20:48:57 dbj Exp $	*/
+
+/*-
+ * Copyright (c) 1991, 1993, 1994
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Keith Muller of the University of California, San Diego and Lance
+ * Visser of Convex Computer Corporation.
+ *
+ * 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.
+ *
+ *	@(#)dd.h	8.3 (Berkeley) 4/2/94
+ */
+
+/* Input/output stream state. */
+typedef struct {
+	u_char		*db;		/* buffer address */
+	u_char		*dbp;		/* current buffer I/O address */
+	uint64_t	dbcnt;		/* current buffer byte count */
+	int64_t		dbrcnt;		/* last read byte count */
+	uint64_t	dbsz;		/* buffer size */
+
+#define	ISCHR		0x01		/* character device (warn on short) */
+#define	ISPIPE		0x02		/* pipe (not truncatable) */
+#define	ISTAPE		0x04		/* tape (not seekable) */
+#define	NOREAD		0x08		/* not readable */
+	u_int		flags;
+
+	const char  	*name;		/* name */
+	int		fd;		/* file descriptor */
+	uint64_t	offset;		/* # of blocks to skip */
+} IO;
+
+typedef struct {
+	uint64_t	in_full;	/* # of full input blocks */
+	uint64_t	in_part;	/* # of partial input blocks */
+	uint64_t	out_full;	/* # of full output blocks */
+	uint64_t	out_part;	/* # of partial output blocks */
+	uint64_t	trunc;		/* # of truncated records */
+	uint64_t	swab;		/* # of odd-length swab blocks */
+	uint64_t	sparse;		/* # of sparse output blocks */
+	uint64_t	bytes;		/* # of bytes written */
+	struct timeval	start;		/* start time of dd */
+} STAT;
+
+/* Flags (in ddflags). */
+#define	C_ASCII		0x00001
+#define	C_BLOCK		0x00002
+#define	C_BS		0x00004
+#define	C_CBS		0x00008
+#define	C_COUNT		0x00010
+#define	C_EBCDIC	0x00020
+#define	C_FILES		0x00040
+#define	C_IBS		0x00080
+#define	C_IF		0x00100
+#define	C_LCASE		0x00200
+#define	C_NOERROR	0x00400
+#define	C_NOTRUNC	0x00800
+#define	C_OBS		0x01000
+#define	C_OF		0x02000
+#define	C_SEEK		0x04000
+#define	C_SKIP		0x08000
+#define	C_SWAB		0x10000
+#define	C_SYNC		0x20000
+#define	C_UCASE		0x40000
+#define	C_UNBLOCK	0x80000
+#define	C_OSYNC		0x100000
+#define	C_SPARSE	0x200000
diff --git a/df.c b/df.c
new file mode 100644
index 0000000..63940a1
--- /dev/null
+++ b/df.c
@@ -0,0 +1,79 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <sys/statfs.h>
+
+static int ok = EXIT_SUCCESS;
+
+static void printsize(long long n)
+{
+    char unit = 'K';
+    n /= 1024;
+    if (n > 1024) {
+        n /= 1024;
+        unit = 'M';
+    }
+    if (n > 1024) {
+        n /= 1024;
+        unit = 'G';
+    }
+    printf("%4lld%c", n, unit);
+}
+
+static void df(char *s, int always) {
+    struct statfs st;
+
+    if (statfs(s, &st) < 0) {
+        fprintf(stderr, "%s: %s\n", s, strerror(errno));
+        ok = EXIT_FAILURE;
+    } else {
+        if (st.f_blocks == 0 && !always)
+            return;        
+        printf("%-20s  ", s);
+        printsize((long long)st.f_blocks * (long long)st.f_bsize);
+        printf("  ");
+        printsize((long long)(st.f_blocks - (long long)st.f_bfree) * st.f_bsize);
+        printf("  ");
+        printsize((long long)st.f_bfree * (long long)st.f_bsize);
+        printf("   %d\n", (int) st.f_bsize);
+    }
+}
+
+int df_main(int argc, char *argv[]) {
+    printf("Filesystem             Size   Used   Free   Blksize\n");
+    if (argc == 1) {
+        char s[2000];
+        FILE *f = fopen("/proc/mounts", "r");
+
+        while (fgets(s, 2000, f)) {
+            char *c, *e = s;
+
+            for (c = s; *c; c++) {
+                if (*c == ' ') {
+                    e = c + 1;
+                    break;
+                }
+            }
+
+            for (c = e; *c; c++) {
+                if (*c == ' ') {
+                    *c = '\0';
+                    break;
+                }
+            }
+
+            df(e, 0);
+        }
+
+        fclose(f);
+    } else {
+        int i;
+
+        for (i = 1; i < argc; i++) {
+            df(argv[i], 1);
+        }
+    }
+
+    exit(ok);
+}
diff --git a/dmesg.c b/dmesg.c
new file mode 100644
index 0000000..e57f607
--- /dev/null
+++ b/dmesg.c
@@ -0,0 +1,43 @@
+#include <stdlib.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <errno.h>
+#include <sys/klog.h>
+#include <string.h>
+
+#define KLOG_BUF_SHIFT	17	/* CONFIG_LOG_BUF_SHIFT from our kernel */
+#define KLOG_BUF_LEN	(1 << KLOG_BUF_SHIFT)
+
+int dmesg_main(int argc, char **argv)
+{
+    char buffer[KLOG_BUF_LEN + 1];
+    char *p = buffer;
+    ssize_t ret;
+    int n, op;
+
+    if((argc == 2) && (!strcmp(argv[1],"-c"))) {
+        op = KLOG_READ_CLEAR;
+    } else {
+        op = KLOG_READ_ALL;
+    }
+
+    n = klogctl(op, buffer, KLOG_BUF_LEN);
+    if (n < 0) {
+        perror("klogctl");
+        return EXIT_FAILURE;
+    }
+    buffer[n] = '\0';
+
+    while((ret = write(STDOUT_FILENO, p, n))) {
+        if (ret == -1) {
+	    if (errno == EINTR)
+                continue;
+	    perror("write");
+	    return EXIT_FAILURE;
+	}
+	p += ret;
+	n -= ret;
+    }
+
+    return 0;
+}
diff --git a/exists.c b/exists.c
new file mode 100644
index 0000000..e348668
--- /dev/null
+++ b/exists.c
@@ -0,0 +1,16 @@
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+int exists_main(int argc, char *argv[])
+{
+    struct stat s;
+
+    if(argc < 2) return 1;
+
+    if(stat(argv[1], &s)) {
+        return 1;
+    } else {
+        return 0;
+    }
+}
diff --git a/getevent.c b/getevent.c
new file mode 100644
index 0000000..256720d
--- /dev/null
+++ b/getevent.c
@@ -0,0 +1,470 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdint.h>
+#include <dirent.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include <sys/inotify.h>
+#include <sys/limits.h>
+#include <sys/poll.h>
+#include <linux/input.h> // this does not compile
+#include <errno.h>
+
+static struct pollfd *ufds;
+static char **device_names;
+static int nfds;
+
+enum {
+    PRINT_DEVICE_ERRORS     = 1U << 0,
+    PRINT_DEVICE            = 1U << 1,
+    PRINT_DEVICE_NAME       = 1U << 2,
+    PRINT_DEVICE_INFO       = 1U << 3,
+    PRINT_VERSION           = 1U << 4,
+    PRINT_POSSIBLE_EVENTS   = 1U << 5,
+};
+
+static int print_possible_events(int fd)
+{
+    uint8_t *bits = NULL;
+    ssize_t bits_size = 0;
+    const char* label;
+    int i, j, k;
+    int res, res2;
+    
+    printf("  events:\n");
+    for(i = 0; i <= EV_MAX; i++) {
+        int count = 0;
+        while(1) {
+            res = ioctl(fd, EVIOCGBIT(i, bits_size), bits);
+            if(res < bits_size)
+                break;
+            bits_size = res + 16;
+            bits = realloc(bits, bits_size * 2);
+            if(bits == NULL) {
+                fprintf(stderr, "failed to allocate buffer of size %d\n", bits_size);
+                return 1;
+            }
+        }
+        res2 = 0;
+        switch(i) {
+            case EV_SYN:
+                label = "SYN";
+                break;
+            case EV_KEY:
+                res2 = ioctl(fd, EVIOCGKEY(res), bits + bits_size);
+                label = "KEY";
+                break;
+            case EV_REL:
+                label = "REL";
+                break;
+            case EV_ABS:
+                label = "ABS";
+                break;
+            case EV_MSC:
+                label = "MSC";
+                break;
+            case EV_LED:
+                res2 = ioctl(fd, EVIOCGLED(res), bits + bits_size);
+                label = "LED";
+                break;
+            case EV_SND:
+                res2 = ioctl(fd, EVIOCGSND(res), bits + bits_size);
+                label = "SND";
+                break;
+            case EV_SW:
+                res2 = ioctl(fd, EVIOCGSW(bits_size), bits + bits_size);
+                label = "SW ";
+                break;
+            case EV_REP:
+                label = "REP";
+                break;
+            case EV_FF:
+                label = "FF ";
+                break;
+            case EV_PWR:
+                label = "PWR";
+                break;
+            default:
+                res2 = 0;
+                label = "???";
+        }
+        for(j = 0; j < res; j++) {
+            for(k = 0; k < 8; k++)
+                if(bits[j] & 1 << k) {
+                    char down;
+                    if(j < res2 && (bits[j + bits_size] & 1 << k))
+                        down = '*';
+                    else
+                        down = ' ';
+                    if(count == 0)
+                        printf("    %s (%04x):", label, i);
+                    else if((count & 0x7) == 0 || i == EV_ABS)
+                        printf("\n               ");
+                    printf(" %04x%c", j * 8 + k, down);
+                    if(i == EV_ABS) {
+                        struct input_absinfo abs;
+                        if(ioctl(fd, EVIOCGABS(j * 8 + k), &abs) == 0) {
+                            printf(" value %d, min %d, max %d, fuzz %d flat %d", abs.value, abs.minimum, abs.maximum, abs.fuzz, abs.flat);
+                        }
+                    }
+                    count++;
+                }
+        }
+        if(count)
+            printf("\n");
+    }
+    free(bits);
+    return 0;
+}
+
+static int open_device(const char *device, int print_flags)
+{
+    int version;
+    int fd;
+    struct pollfd *new_ufds;
+    char **new_device_names;
+    char name[80];
+    char location[80];
+    char idstr[80];
+    struct input_id id;
+
+    fd = open(device, O_RDWR);
+    if(fd < 0) {
+        if(print_flags & PRINT_DEVICE_ERRORS)
+            fprintf(stderr, "could not open %s, %s\n", device, strerror(errno));
+        return -1;
+    }
+    
+    if(ioctl(fd, EVIOCGVERSION, &version)) {
+        if(print_flags & PRINT_DEVICE_ERRORS)
+            fprintf(stderr, "could not get driver version for %s, %s\n", device, strerror(errno));
+        return -1;
+    }
+    if(ioctl(fd, EVIOCGID, &id)) {
+        if(print_flags & PRINT_DEVICE_ERRORS)
+            fprintf(stderr, "could not get driver id for %s, %s\n", device, strerror(errno));
+        return -1;
+    }
+    name[sizeof(name) - 1] = '\0';
+    location[sizeof(location) - 1] = '\0';
+    idstr[sizeof(idstr) - 1] = '\0';
+    if(ioctl(fd, EVIOCGNAME(sizeof(name) - 1), &name) < 1) {
+        //fprintf(stderr, "could not get device name for %s, %s\n", device, strerror(errno));
+        name[0] = '\0';
+    }
+    if(ioctl(fd, EVIOCGPHYS(sizeof(location) - 1), &location) < 1) {
+        //fprintf(stderr, "could not get location for %s, %s\n", device, strerror(errno));
+        location[0] = '\0';
+    }
+    if(ioctl(fd, EVIOCGUNIQ(sizeof(idstr) - 1), &idstr) < 1) {
+        //fprintf(stderr, "could not get idstring for %s, %s\n", device, strerror(errno));
+        idstr[0] = '\0';
+    }
+
+    new_ufds = realloc(ufds, sizeof(ufds[0]) * (nfds + 1));
+    if(new_ufds == NULL) {
+        fprintf(stderr, "out of memory\n");
+        return -1;
+    }
+    ufds = new_ufds;
+    new_device_names = realloc(device_names, sizeof(device_names[0]) * (nfds + 1));
+    if(new_device_names == NULL) {
+        fprintf(stderr, "out of memory\n");
+        return -1;
+    }
+    device_names = new_device_names;
+
+    if(print_flags & PRINT_DEVICE)
+        printf("add device %d: %s\n", nfds, device);
+    if(print_flags & PRINT_DEVICE_INFO)
+        printf("  bus:      %04x\n"
+               "  vendor    %04x\n"
+               "  product   %04x\n"
+               "  version   %04x\n",
+               id.bustype, id.vendor, id.product, id.version);
+    if(print_flags & PRINT_DEVICE_NAME)
+        printf("  name:     \"%s\"\n", name);
+    if(print_flags & PRINT_DEVICE_INFO)
+        printf("  location: \"%s\"\n"
+               "  id:       \"%s\"\n", location, idstr);
+    if(print_flags & PRINT_VERSION)
+        printf("  version:  %d.%d.%d\n",
+               version >> 16, (version >> 8) & 0xff, version & 0xff);
+
+    if(print_flags & PRINT_POSSIBLE_EVENTS) {
+        print_possible_events(fd);
+    }
+
+    ufds[nfds].fd = fd;
+    ufds[nfds].events = POLLIN;
+    device_names[nfds] = strdup(device);
+    nfds++;
+
+    return 0;
+}
+
+int close_device(const char *device, int print_flags)
+{
+    int i;
+    for(i = 1; i < nfds; i++) {
+        if(strcmp(device_names[i], device) == 0) {
+            int count = nfds - i - 1;
+            if(print_flags & PRINT_DEVICE)
+                printf("remove device %d: %s\n", i, device);
+            free(device_names[i]);
+            memmove(device_names + i, device_names + i + 1, sizeof(device_names[0]) * count);
+            memmove(ufds + i, ufds + i + 1, sizeof(ufds[0]) * count);
+            nfds--;
+            return 0;
+        }
+    }
+    if(print_flags & PRINT_DEVICE_ERRORS)
+        fprintf(stderr, "remote device: %s not found\n", device);
+    return -1;
+}
+
+static int read_notify(const char *dirname, int nfd, int print_flags)
+{
+    int res;
+    char devname[PATH_MAX];
+    char *filename;
+    char event_buf[512];
+    int event_size;
+    int event_pos = 0;
+    struct inotify_event *event;
+
+    res = read(nfd, event_buf, sizeof(event_buf));
+    if(res < (int)sizeof(*event)) {
+        if(errno == EINTR)
+            return 0;
+        fprintf(stderr, "could not get event, %s\n", strerror(errno));
+        return 1;
+    }
+    //printf("got %d bytes of event information\n", res);
+
+    strcpy(devname, dirname);
+    filename = devname + strlen(devname);
+    *filename++ = '/';
+
+    while(res >= (int)sizeof(*event)) {
+        event = (struct inotify_event *)(event_buf + event_pos);
+        //printf("%d: %08x \"%s\"\n", event->wd, event->mask, event->len ? event->name : "");
+        if(event->len) {
+            strcpy(filename, event->name);
+            if(event->mask & IN_CREATE) {
+                open_device(devname, print_flags);
+            }
+            else {
+                close_device(devname, print_flags);
+            }
+        }
+        event_size = sizeof(*event) + event->len;
+        res -= event_size;
+        event_pos += event_size;
+    }
+    return 0;
+}
+
+static int scan_dir(const char *dirname, int print_flags)
+{
+    char devname[PATH_MAX];
+    char *filename;
+    DIR *dir;
+    struct dirent *de;
+    dir = opendir(dirname);
+    if(dir == NULL)
+        return -1;
+    strcpy(devname, dirname);
+    filename = devname + strlen(devname);
+    *filename++ = '/';
+    while((de = readdir(dir))) {
+        if(de->d_name[0] == '.' &&
+           (de->d_name[1] == '\0' ||
+            (de->d_name[1] == '.' && de->d_name[2] == '\0')))
+            continue;
+        strcpy(filename, de->d_name);
+        open_device(devname, print_flags);
+    }
+    closedir(dir);
+    return 0;
+}
+
+static void usage(int argc, char *argv[])
+{
+    fprintf(stderr, "Usage: %s [-t] [-n] [-s switchmask] [-S] [-v [mask]] [-p] [-q] [-c count] [-r] [device]\n", argv[0]);
+    fprintf(stderr, "    -t: show time stamps\n");
+    fprintf(stderr, "    -n: don't print newlines\n");
+    fprintf(stderr, "    -s: print switch states for given bits\n");
+    fprintf(stderr, "    -S: print all switch states\n");
+    fprintf(stderr, "    -v: verbosity mask (errs=1, dev=2, name=4, info=8, vers=16, pos. events=32)\n");
+    fprintf(stderr, "    -p: show possible events (errs, dev, name, pos. events)\n");
+    fprintf(stderr, "    -q: quiet (clear verbosity mask)\n");
+    fprintf(stderr, "    -c: print given number of events then exit\n");
+    fprintf(stderr, "    -r: print rate events are received\n");
+}
+
+int getevent_main(int argc, char *argv[])
+{
+    int c;
+    int i;
+    int res;
+    int pollres;
+    int get_time = 0;
+    int print_device = 0;
+    char *newline = "\n";
+    uint16_t get_switch = 0;
+    struct input_event event;
+    int version;
+    int print_flags = PRINT_DEVICE_ERRORS | PRINT_DEVICE | PRINT_DEVICE_NAME;
+    int print_flags_set = 0;
+    int dont_block = -1;
+    int event_count = 0;
+    int sync_rate = 0;
+    int64_t last_sync_time = 0;
+    const char *device = NULL;
+    const char *device_path = "/dev/input";
+
+    opterr = 0;
+    do {
+        c = getopt(argc, argv, "tns:Sv::pqc:rh");
+        if (c == EOF)
+            break;
+        switch (c) {
+        case 't':
+            get_time = 1;
+            break;
+        case 'n':
+            newline = "";
+            break;
+        case 's':
+            get_switch = strtoul(optarg, NULL, 0);
+            if(dont_block == -1)
+                dont_block = 1;
+            break;
+        case 'S':
+            get_switch = ~0;
+            if(dont_block == -1)
+                dont_block = 1;
+            break;
+        case 'v':
+            if(optarg)
+                print_flags =  strtoul(optarg, NULL, 0);
+            else
+                print_flags |= PRINT_DEVICE | PRINT_DEVICE_NAME | PRINT_DEVICE_INFO | PRINT_VERSION;
+            print_flags_set = 1;
+            break;
+        case 'p':
+            print_flags = PRINT_DEVICE_ERRORS | PRINT_DEVICE | PRINT_DEVICE_NAME | PRINT_POSSIBLE_EVENTS;
+            print_flags_set = 1;
+            if(dont_block == -1)
+                dont_block = 1;
+            break;
+        case 'q':
+            print_flags = 0;
+            print_flags_set = 1;
+            break;
+        case 'c':
+            event_count = atoi(optarg);
+            dont_block = 0;
+            break;
+        case 'r':
+            sync_rate = 1;
+            break;
+        case '?':
+            fprintf(stderr, "%s: invalid option -%c\n",
+                argv[0], optopt);
+        case 'h':
+            usage(argc, argv);
+            exit(1);
+        }
+    } while (1);
+    if(dont_block == -1)
+        dont_block = 0;
+
+    if (optind + 1 == argc) {
+        device = argv[optind];
+        optind++;
+    }
+    if (optind != argc) {
+        usage(argc, argv);
+        exit(1);
+    }
+    nfds = 1;
+    ufds = calloc(1, sizeof(ufds[0]));
+    ufds[0].fd = inotify_init();
+    ufds[0].events = POLLIN;
+    if(device) {
+        if(!print_flags_set)
+            print_flags = PRINT_DEVICE_ERRORS;
+        res = open_device(device, print_flags);
+        if(res < 0) {
+            return 1;
+        }
+    }
+    else {
+        print_device = 1;
+		res = inotify_add_watch(ufds[0].fd, device_path, IN_DELETE | IN_CREATE);
+        if(res < 0) {
+            fprintf(stderr, "could not add watch for %s, %s\n", device_path, strerror(errno));
+            return 1;
+        }
+        res = scan_dir(device_path, print_flags);
+        if(res < 0) {
+            fprintf(stderr, "scan dir failed for %s\n", device_path);
+            return 1;
+        }
+    }
+
+    if(get_switch) {
+        for(i = 1; i < nfds; i++) {
+            uint16_t sw;
+            res = ioctl(ufds[i].fd, EVIOCGSW(1), &sw);
+            if(res < 0) {
+                fprintf(stderr, "could not get switch state, %s\n", strerror(errno));
+                return 1;
+            }
+            sw &= get_switch;
+            printf("%04x%s", sw, newline);
+        }
+    }
+
+    if(dont_block)
+        return 0;
+
+    while(1) {
+        pollres = poll(ufds, nfds, -1);
+        //printf("poll %d, returned %d\n", nfds, pollres);
+        if(ufds[0].revents & POLLIN) {
+            read_notify(device_path, ufds[0].fd, print_flags);
+        }
+        for(i = 1; i < nfds; i++) {
+            if(ufds[i].revents) {
+                if(ufds[i].revents & POLLIN) {
+                    res = read(ufds[i].fd, &event, sizeof(event));
+                    if(res < (int)sizeof(event)) {
+                        fprintf(stderr, "could not get event\n");
+                        return 1;
+                    }
+                    if(get_time) {
+                        printf("%ld-%ld: ", event.time.tv_sec, event.time.tv_usec);
+                    }
+                    if(print_device)
+                        printf("%s: ", device_names[i]);
+                    printf("%04x %04x %08x", event.type, event.code, event.value);
+                    if(sync_rate && event.type == 0 && event.code == 0) {
+                        int64_t now = event.time.tv_sec * 1000000LL + event.time.tv_usec;
+                        if(last_sync_time)
+                            printf(" rate %lld", 1000000LL / (now - last_sync_time));
+                        last_sync_time = now;
+                    }
+                    printf("%s", newline);
+                    if(event_count && --event_count == 0)
+                        return 0;
+                }
+            }
+        }
+    }
+
+    return 0;
+}
diff --git a/getprop.c b/getprop.c
new file mode 100644
index 0000000..fc80a4d
--- /dev/null
+++ b/getprop.c
@@ -0,0 +1,34 @@
+#include <stdio.h>
+
+#include <cutils/properties.h>
+
+#include <sys/system_properties.h>
+
+static void proplist(const char *key, const char *name, 
+                     void *user __attribute__((unused)))
+{
+    printf("[%s]: [%s]\n", key, name);
+}
+
+int __system_property_wait(prop_info *pi);
+
+int getprop_main(int argc, char *argv[])
+{
+    int n = 0;
+
+    if (argc == 1) {
+        (void)property_list(proplist, NULL);
+    } else {
+        char value[PROPERTY_VALUE_MAX];
+        char *default_value;
+        if(argc > 2) {
+            default_value = argv[2];
+        } else {
+            default_value = "";
+        }
+
+        property_get(argv[1], value, default_value);
+        printf("%s\n", value);
+    }
+    return 0;
+}
diff --git a/hd.c b/hd.c
new file mode 100644
index 0000000..1f7d179
--- /dev/null
+++ b/hd.c
@@ -0,0 +1,95 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdint.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include <errno.h>
+
+int hd_main(int argc, char *argv[])
+{
+    int c;
+    int fd;
+	unsigned char buf[4096];
+    int res;
+	int read_len;
+	int rv = 0;
+	int i;
+	int filepos = 0;
+	int sum;
+	int lsum;
+
+	int base = -1;
+	int count = 0;
+	int repeat = 0;
+
+    do {
+        c = getopt(argc, argv, "b:c:r:");
+        if (c == EOF)
+            break;
+        switch (c) {
+        case 'b':
+            base = strtol(optarg, NULL, 0);
+            break;
+        case 'c':
+            count = strtol(optarg, NULL, 0);
+            break;
+		case 'r':
+			repeat = strtol(optarg, NULL, 0);
+			break;
+        case '?':
+            fprintf(stderr, "%s: invalid option -%c\n",
+                argv[0], optopt);
+            exit(1);
+        }
+    } while (1);
+
+    if (optind + 1 != argc) {
+        fprintf(stderr, "Usage: %s [-b base] [-c count] [-r delay] file\n", argv[0]);
+        exit(1);
+    }
+
+    fd = open(argv[optind], O_RDONLY);
+    if(fd < 0) {
+        fprintf(stderr, "could not open %s, %s\n", argv[optind], strerror(errno));
+        return 1;
+    }
+
+	do {
+		if(base >= 0) {
+			lseek(fd, base, SEEK_SET);
+			filepos = base;
+		}
+		sum = 0;
+		lsum = 0;
+	    while(1) {
+			read_len = sizeof(buf);
+			if(count > 0 && base + count - filepos < read_len)
+				read_len = base + count - filepos;
+	        res = read(fd, &buf, read_len);
+			for(i = 0; i < res; i++) {
+				if((i & 15) == 0) {
+					printf("%08x: ", filepos + i);
+				}
+				lsum += buf[i];
+				sum += buf[i];
+				printf("%02x ", buf[i]);
+				if(((i & 15) == 15) || (i == res - 1)) {
+					printf("s %x\n", lsum);
+					lsum = 0;
+				}
+			}
+			if(res <= 0) {
+				printf("Read error on %s, offset %d len %d, %s\n", argv[optind], filepos, read_len, strerror(errno));
+				return 1;
+			}
+			filepos += res;
+			if(filepos == base + count)
+				break;
+	    }
+		printf("sum %x\n", sum);
+		if(repeat)
+			sleep(repeat);
+	} while(repeat);
+	return 0;
+}
diff --git a/id.c b/id.c
new file mode 100644
index 0000000..bb03cad
--- /dev/null
+++ b/id.c
@@ -0,0 +1,51 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <pwd.h>
+#include <grp.h>
+
+static void print_uid(uid_t uid)
+{
+    struct passwd *pw = getpwuid(uid);
+
+    if (pw) {
+        printf("%d(%s)", uid, pw->pw_name);
+    } else {
+        printf("%d",uid);
+    }
+}
+
+static void print_gid(gid_t gid)
+{
+    struct group *gr = getgrgid(gid);
+    if (gr) {
+        printf("%d(%s)", gid, gr->gr_name);
+    } else {
+        printf("%d",gid);
+    }
+}
+
+int id_main(int argc, char **argv)
+{
+    gid_t list[64];
+    int n, max;
+
+    max = getgroups(64, list);
+    if (max < 0) max = 0;
+
+    printf("uid=");
+    print_uid(getuid());
+    printf(" gid=");
+    print_gid(getgid());
+    if (max) {
+        printf(" groups=");
+        print_gid(list[0]);
+        for(n = 1; n < max; n++) {
+            printf(",");
+            print_gid(list[n]);
+        }
+    }
+    printf("\n");
+    return 0;
+}
diff --git a/ifconfig.c b/ifconfig.c
new file mode 100644
index 0000000..80c0e5c
--- /dev/null
+++ b/ifconfig.c
@@ -0,0 +1,163 @@
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include <errno.h>
+#include <string.h>
+#include <ctype.h>
+
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <linux/if.h>
+#include <linux/sockios.h>
+#include <arpa/inet.h>
+
+static void die(const char *s)
+{
+    fprintf(stderr,"error: %s (%s)\n", s, strerror(errno));
+    exit(-1);
+}
+
+static void setflags(int s, struct ifreq *ifr, int set, int clr)
+{
+    if(ioctl(s, SIOCGIFFLAGS, ifr) < 0) die("SIOCGIFFLAGS");
+    ifr->ifr_flags = (ifr->ifr_flags & (~clr)) | set;
+    if(ioctl(s, SIOCSIFFLAGS, ifr) < 0) die("SIOCSIFFLAGS");
+}
+
+static inline void init_sockaddr_in(struct sockaddr_in *sin, const char *addr)
+{
+    sin->sin_family = AF_INET;
+    sin->sin_port = 0;
+    sin->sin_addr.s_addr = inet_addr(addr);
+}
+
+static void setmtu(int s, struct ifreq *ifr, const char *mtu)
+{
+    int m = atoi(mtu);
+    ifr->ifr_mtu = m;
+    if(ioctl(s, SIOCSIFMTU, ifr) < 0) die("SIOCSIFMTU");
+}
+static void setdstaddr(int s, struct ifreq *ifr, const char *addr)
+{
+    init_sockaddr_in((struct sockaddr_in *) &ifr->ifr_dstaddr, addr);
+    if(ioctl(s, SIOCSIFDSTADDR, ifr) < 0) die("SIOCSIFDSTADDR");
+}
+
+static void setnetmask(int s, struct ifreq *ifr, const char *addr)
+{
+    init_sockaddr_in((struct sockaddr_in *) &ifr->ifr_netmask, addr);
+    if(ioctl(s, SIOCSIFNETMASK, ifr) < 0) die("SIOCSIFNETMASK");
+}
+
+static void setaddr(int s, struct ifreq *ifr, const char *addr)
+{
+    init_sockaddr_in((struct sockaddr_in *) &ifr->ifr_addr, addr);
+    if(ioctl(s, SIOCSIFADDR, ifr) < 0) die("SIOCSIFADDR");
+}
+
+int ifconfig_main(int argc, char *argv[])
+{
+    struct ifreq ifr;
+    int s;
+    unsigned int addr, mask, flags;
+    char astring[20];
+    char mstring[20];
+    char *updown, *brdcst, *loopbk, *ppp, *running, *multi;
+    
+    argc--;
+    argv++;
+
+    if(argc == 0) return 0;
+
+    memset(&ifr, 0, sizeof(struct ifreq));
+    strncpy(ifr.ifr_name, argv[0], IFNAMSIZ);
+    ifr.ifr_name[IFNAMSIZ-1] = 0;
+    argc--, argv++;
+
+    if((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
+        die("cannot open control socket\n");
+    }
+
+    if (argc == 0) {
+        if (ioctl(s, SIOCGIFADDR, &ifr) < 0) {
+            perror(ifr.ifr_name);
+            return -1;
+        } else
+            addr = ((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr.s_addr;
+
+        if (ioctl(s, SIOCGIFNETMASK, &ifr) < 0) {
+            perror(ifr.ifr_name);
+            return -1;
+        } else
+            mask = ((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr.s_addr;
+
+        if (ioctl(s, SIOCGIFFLAGS, &ifr) < 0) {
+            perror(ifr.ifr_name);
+            return -1;
+        } else
+            flags = ifr.ifr_flags;
+
+        sprintf(astring, "%d.%d.%d.%d",
+                addr & 0xff,
+                ((addr >> 8) & 0xff),
+                ((addr >> 16) & 0xff),
+                ((addr >> 24) & 0xff));
+        sprintf(mstring, "%d.%d.%d.%d",
+                mask & 0xff,
+                ((mask >> 8) & 0xff),
+                ((mask >> 16) & 0xff),
+                ((mask >> 24) & 0xff));
+        printf("%s: ip %s mask %s flags [", ifr.ifr_name,
+               astring,
+               mstring
+               );
+
+        updown =  (flags & IFF_UP)           ? "up" : "down";
+        brdcst =  (flags & IFF_BROADCAST)    ? " broadcast" : "";
+        loopbk =  (flags & IFF_LOOPBACK)     ? " loopback" : "";
+        ppp =     (flags & IFF_POINTOPOINT)  ? " point-to-point" : "";
+        running = (flags & IFF_RUNNING)      ? " running" : "";
+        multi =   (flags & IFF_MULTICAST)    ? " multicast" : "";
+        printf("%s%s%s%s%s%s]\n", updown, brdcst, loopbk, ppp, running, multi);
+        return 0;
+    }
+    
+    while(argc > 0) {
+        if (!strcmp(argv[0], "up")) {
+            setflags(s, &ifr, IFF_UP, 0);
+        } else if (!strcmp(argv[0], "mtu")) {
+            argc--, argv++;
+            if (!argc) {
+                errno = EINVAL;
+                die("expecting a value for parameter \"mtu\"");
+            }
+            setmtu(s, &ifr, argv[0]);
+        } else if (!strcmp(argv[0], "-pointopoint")) {
+            setflags(s, &ifr, IFF_POINTOPOINT, 1);
+        } else if (!strcmp(argv[0], "pointopoint")) {
+            argc--, argv++;
+            if (!argc) { 
+                errno = EINVAL;
+                die("expecting an IP address for parameter \"pointtopoint\"");
+            }
+            setdstaddr(s, &ifr, argv[0]);
+            setflags(s, &ifr, IFF_POINTOPOINT, 0);
+        } else if (!strcmp(argv[0], "down")) {
+            setflags(s, &ifr, 0, IFF_UP);
+        } else if (!strcmp(argv[0], "netmask")) {
+            argc--, argv++;
+            if (!argc) { 
+                errno = EINVAL;
+                die("expecting an IP address for parameter \"netmask\"");
+            }
+            setnetmask(s, &ifr, argv[0]);
+        } else if (isdigit(argv[0][0])) {
+            setaddr(s, &ifr, argv[0]);
+            setflags(s, &ifr, IFF_UP, 0);
+        }
+        argc--, argv++;
+    }
+    return 0;
+}
diff --git a/iftop.c b/iftop.c
new file mode 100644
index 0000000..800c0f0
--- /dev/null
+++ b/iftop.c
@@ -0,0 +1,278 @@
+/*
+ * Copyright (c) 2008, The Android Open Source Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * 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.
+ *  * Neither the name of Google, Inc. 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 COPYRIGHT HOLDERS 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
+ * COPYRIGHT OWNER 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 <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#include <net/if.h>
+
+#define PROC_NET_DEV    "/proc/net/dev"
+
+#define MAX_IF           8   /* max interfaces we can handle */
+
+#ifndef PAGE_SIZE
+# define PAGE_SIZE 4096
+#endif
+
+#define _STR(s) #s
+#define STR(s) _STR(s)
+
+struct if_stats {
+    char name[IFNAMSIZ];
+
+    unsigned int mtu;
+
+    unsigned int rx_bytes;
+    unsigned int rx_packets;
+    unsigned int rx_errors;
+    unsigned int rx_dropped;
+
+    unsigned int tx_bytes;
+    unsigned int tx_packets;
+    unsigned int tx_errors;
+    unsigned int tx_dropped;
+};
+
+static int get_mtu(const char *if_name)
+{
+    struct ifreq ifr;
+    int s, ret;
+
+    s = socket(AF_INET, SOCK_DGRAM, 0);
+    if (s < 0) {
+        perror("socket");
+        exit(EXIT_FAILURE);
+    }
+
+    memset(&ifr, 0, sizeof(struct ifreq));
+    ifr.ifr_addr.sa_family = AF_INET;
+    strcpy(ifr.ifr_name, if_name);
+
+    ret = ioctl(s, SIOCGIFMTU, &ifr);
+    if (ret < 0) {
+        perror("ioctl");
+        exit(EXIT_FAILURE);
+    }
+
+    ret = close(s);
+    if (ret < 0) {
+        perror("close");
+        exit(EXIT_FAILURE);
+    }
+
+    return ifr.ifr_mtu;
+}
+
+static int get_interfaces(struct if_stats *ifs)
+{
+    char buf[PAGE_SIZE];
+    char *p;
+    int ret, nr, fd;
+
+    fd = open(PROC_NET_DEV, O_RDONLY);
+    if (fd < 0) {
+        perror("open");
+        exit(EXIT_FAILURE);
+    }
+
+    ret = read(fd, buf, sizeof(buf) - 1);
+    if (ret < 0) {
+        perror("read");
+        exit(EXIT_FAILURE);
+    } else if (!ret) {
+        fprintf(stderr, "reading " PROC_NET_DEV " returned premature EOF\n");
+        exit(EXIT_FAILURE);
+    }
+    buf[ret] = '\0';
+
+    /* skip down to the third line */
+    p = strchr(buf, '\n');
+    if (!p) {
+        fprintf(stderr, "parsing " PROC_NET_DEV " failed unexpectedly\n");
+        exit(EXIT_FAILURE);
+    }
+    p = strchr(p + 1, '\n');
+    if (!p) {
+        fprintf(stderr, "parsing " PROC_NET_DEV " failed unexpectedly\n");
+        exit(EXIT_FAILURE);
+    }
+    p += 1;
+
+    /*
+     * Key:
+     * if: (Rx) bytes packets errs drop fifo frame compressed multicast \
+     *     (Tx) bytes packets errs drop fifo colls carrier compressed
+     */
+    for (nr = 0; nr < MAX_IF; nr++) {
+        char *c;
+
+        ret = sscanf(p, "%" STR(IFNAMSIZ) "s", ifs->name);
+        if (ret != 1) {
+            fprintf(stderr, "parsing " PROC_NET_DEV " failed unexpectedly\n");
+            exit(EXIT_FAILURE);
+        }
+
+        /*
+         * This works around a bug in the proc file where large interface names
+         * or Rx byte counts eat the delimiter, breaking sscanf.
+         */
+        c = strchr(ifs->name, ':');
+        if (c)
+            *c = '\0';
+
+        p = strchr(p, ':') + 1;
+
+        ret = sscanf(p, "%u %u %u %u %*u %*u %*u %*u %u %u %u %u %*u %*u "
+                     "%*u %*u\n", &ifs->rx_bytes, &ifs->rx_packets,
+                     &ifs->rx_errors, &ifs->rx_dropped, &ifs->tx_bytes,
+                     &ifs->tx_packets, &ifs->tx_errors, &ifs->tx_dropped);
+        if (ret != 8) {
+            fprintf(stderr, "parsing " PROC_NET_DEV " failed unexpectedly\n");
+            exit(EXIT_FAILURE);
+        }
+
+        ifs->mtu = get_mtu(ifs->name);
+
+        p = strchr(p, '\n') + 1;
+        if (*p == '\0') {
+            nr++;
+            break;
+        }
+
+        ifs++;
+    }
+
+    ret = close(fd);
+    if (ret) {
+        perror("close");
+        exit(EXIT_FAILURE);
+    }
+
+    return nr;
+}
+
+static void print_header(void)
+{
+    printf("               Rx                              Tx\n");
+    printf("%-8s %-5s %-10s %-8s %-5s %-5s %-10s %-8s %-5s %-5s\n",
+           "name", "MTU", "bytes", "packets", "errs", "drpd", "bytes",
+           "packets", "errs", "drpd");
+}
+
+static int print_interfaces(struct if_stats *old, struct if_stats *new, int nr)
+{
+    int i = 0;
+
+    while (nr--) {
+        if (old->rx_packets || old->tx_packets) {
+            printf("%-8s %-5u %-10u %-8u %-5u %-5u %-10u %-8u %-5u %-5u\n",
+                   new->name, new->mtu,
+                   new->rx_bytes - old->rx_bytes,
+                   new->rx_packets - old->rx_packets,
+                   new->rx_errors - old->rx_errors,
+                   new->rx_dropped - old->rx_dropped,
+                   new->tx_bytes - old->tx_bytes,
+                   new->tx_packets - old->tx_packets,
+                   new->tx_errors - old->tx_errors,
+                   new->tx_dropped - old->tx_dropped);
+            i++;
+        }
+        old++;
+        new++;
+    }
+
+    return i;
+}
+
+static void usage(const char *cmd)
+{
+    fprintf(stderr, "usage: %s [ -r repeats] [ -d delay ]\n", cmd);
+}
+
+int iftop_main(int argc, char *argv[])
+{
+    struct if_stats ifs[2][MAX_IF];
+    int count = 0, header_interval = 22, delay = 1, i;
+    unsigned int toggle = 0;
+
+    for (i = 1; i < argc; i++) {
+        if (!strcmp(argv[i], "-d")) {
+            if (i >= argc - 1) {
+                fprintf(stderr, "Option -d requires an argument.\n");
+                exit(EXIT_FAILURE);
+            }
+            delay = atoi(argv[i++]);
+            if (!delay)
+                delay = 1;
+            continue;
+        }
+        if (!strcmp(argv[i], "-r")) {
+            if (i >= argc - 1) {
+                fprintf(stderr, "Option -r requires an argument.\n");
+                exit(EXIT_FAILURE);
+            }
+            header_interval = atoi(argv[i++]);
+            if (header_interval < MAX_IF)
+                header_interval = MAX_IF;
+            continue;
+        }
+        if (!strcmp(argv[i], "-h")) {
+            usage(argv[0]);
+            exit(EXIT_SUCCESS);
+        }
+        usage(argv[0]);
+        exit(EXIT_FAILURE);
+    }
+
+    get_interfaces(ifs[!toggle]);
+    if (header_interval)
+        print_header();
+    while (1) {
+        int nr;
+
+        sleep(delay);
+        nr = get_interfaces(ifs[toggle]);
+        if (header_interval && count + nr > header_interval) {
+            print_header();
+            count = 0;
+        }
+        count += print_interfaces(ifs[!toggle], ifs[toggle], nr);
+        toggle = !toggle;
+    }
+
+    return 0;
+}
diff --git a/insmod.c b/insmod.c
new file mode 100644
index 0000000..756a64b
--- /dev/null
+++ b/insmod.c
@@ -0,0 +1,97 @@
+#include <stdio.h>
+#include <string.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <malloc.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+extern int init_module(void *, unsigned long, const char *);
+
+static void *read_file(const char *filename, ssize_t *_size)
+{
+	int ret, fd;
+	struct stat sb;
+	ssize_t size;
+	void *buffer = NULL;
+
+	/* open the file */
+	fd = open(filename, O_RDONLY);
+	if (fd < 0)
+		return NULL;
+
+	/* find out how big it is */
+	if (fstat(fd, &sb) < 0)
+		goto bail;
+	size = sb.st_size;
+
+	/* allocate memory for it to be read into */
+	buffer = malloc(size);
+	if (!buffer)
+		goto bail;
+
+	/* slurp it into our buffer */
+	ret = read(fd, buffer, size);
+	if (ret != size)
+		goto bail;
+
+	/* let the caller know how big it is */
+	*_size = size;
+
+bail:
+	close(fd);
+	return buffer;
+}
+
+#define min(x,y) ((x) < (y) ? (x) : (y))
+int insmod_main(int argc, char **argv)
+{
+	void *file;
+	ssize_t size = 0;
+	char opts[1024];
+	int ret;
+
+	/* make sure we've got an argument */
+	if (argc < 2) {
+		fprintf(stderr, "usage: insmod <module.o>\n");
+		return -1;
+	}
+
+	/* read the file into memory */
+	file = read_file(argv[1], &size);
+	if (!file) {
+		fprintf(stderr, "insmod: can't open '%s'\n", argv[1]);
+		return -1;
+	}
+
+	opts[0] = '\0';
+	if (argc > 2) {
+		int i, len;
+		char *end = opts + sizeof(opts) - 1;
+		char *ptr = opts;
+
+		for (i = 2; (i < argc) && (ptr < end); i++) {
+			len = min(strlen(argv[i]), end - ptr);
+			memcpy(ptr, argv[i], len);
+			ptr += len;
+			*ptr++ = ' ';
+		}
+		*(ptr - 1) = '\0';
+	}
+
+	/* pass it to the kernel */
+	ret = init_module(file, size, opts);
+	if (ret != 0) {
+		fprintf(stderr,
+                "insmod: init_module '%s' failed (%s)\n",
+                argv[1], strerror(errno));
+	}
+
+	/* free the file buffer */
+	free(file);
+
+	return ret;
+}
+
diff --git a/ioctl.c b/ioctl.c
new file mode 100644
index 0000000..e28f2a4
--- /dev/null
+++ b/ioctl.c
@@ -0,0 +1,125 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <string.h>
+#include <linux/kd.h>
+#include <linux/vt.h>
+#include <errno.h>
+#include <pthread.h>
+
+int ioctl_main(int argc, char *argv[])
+{
+    int c;
+    int fd;
+    int res;
+
+    int read_only = 0;
+    int length = -1;
+    int arg_size = 4;
+    int direct_arg = 0;
+    uint32_t ioctl_nr;
+    void *ioctl_args;
+    uint8_t *ioctl_argp;
+    uint8_t *ioctl_argp_save;
+    int rem;
+
+    do {
+        c = getopt(argc, argv, "rdl:a:h");
+        if (c == EOF)
+            break;
+        switch (c) {
+        case 'r':
+            read_only = 1;
+            break;
+        case 'd':
+            direct_arg = 1;
+            break;
+        case 'l':
+            length = strtol(optarg, NULL, 0);
+            break;
+        case 'a':
+            arg_size = strtol(optarg, NULL, 0);
+            break;
+        case 'h':
+            fprintf(stderr, "%s [-l <length>] [-a <argsize>] [-rdh] <device> <ioctlnr>\n"
+                    "  -l <lenght>   Length of io buffer\n"
+                    "  -a <argsize>  Size of each argument (1-8)\n"
+                    "  -r            Open device in read only mode\n"
+                    "  -d            Direct argument (no iobuffer)\n"
+                    "  -h            Print help\n", argv[0]);
+            return -1;
+        case '?':
+            fprintf(stderr, "%s: invalid option -%c\n",
+                argv[0], optopt);
+            exit(1);
+        }
+    } while (1);
+
+    if(optind + 2 > argc) {
+        fprintf(stderr, "%s: too few arguments\n", argv[0]);
+        exit(1);
+    }
+
+    fd = open(argv[optind], O_RDWR | O_SYNC);
+    if (fd < 0) {
+        fprintf(stderr, "cannot open %s\n", argv[optind]);
+        return 1;
+    }
+    optind++;
+    
+    ioctl_nr = strtol(argv[optind], NULL, 0);
+    optind++;
+
+    if(direct_arg) {
+        arg_size = 4;
+        length = 4;
+    }
+
+    if(length < 0) {
+        length = (argc - optind) * arg_size;
+    }
+    if(length) {
+        ioctl_args = calloc(1, length);
+
+        ioctl_argp_save = ioctl_argp = ioctl_args;
+        rem = length;
+        while(optind < argc) {
+            uint64_t tmp = strtoull(argv[optind], NULL, 0);
+            if(rem < arg_size) {
+                fprintf(stderr, "%s: too many arguments\n", argv[0]);
+                exit(1);
+            }
+            memcpy(ioctl_argp, &tmp, arg_size);
+            ioctl_argp += arg_size;
+            rem -= arg_size;
+            optind++;
+        }
+    }
+    printf("sending ioctl 0x%x", ioctl_nr);
+    rem = length;
+    while(rem--) {
+        printf(" 0x%02x", *ioctl_argp_save++);
+    }
+    printf("\n");
+
+    if(direct_arg)
+        res = ioctl(fd, ioctl_nr, *(uint32_t*)ioctl_args);
+    else if(length)
+        res = ioctl(fd, ioctl_nr, ioctl_args);
+    else
+        res = ioctl(fd, ioctl_nr, 0);
+    if (res < 0) {
+        fprintf(stderr, "ioctl 0x%x failed, %d\n", ioctl_nr, res);
+        return 1;
+    }
+    if(length) {
+        printf("return buf:");
+        ioctl_argp = ioctl_args;
+        rem = length;
+        while(rem--) {
+            printf(" %02x", *ioctl_argp++);
+        }
+        printf("\n");
+    }
+    return 0;
+}
diff --git a/ionice.c b/ionice.c
new file mode 100644
index 0000000..4a182f2
--- /dev/null
+++ b/ionice.c
@@ -0,0 +1,57 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <errno.h>
+
+#include <cutils/iosched_policy.h>
+
+static char *classes[] = {"none", "rt", "be", "idle", NULL};
+
+int ionice_main(int argc, char *argv[])
+{
+    IoSchedClass clazz = IoSchedClass_NONE;
+    int ioprio = 0;
+    int pid;
+
+    if(argc != 2 && argc != 4) {
+        fprintf(stderr, "usage: ionice <pid> [none|rt|be|idle] [prio]\n");
+        return 1;
+    }
+
+    if (!(pid = atoi(argv[1]))) {
+        fprintf(stderr, "Invalid pid specified\n");
+        return 1;
+    }
+
+    if (argc == 2) {
+        if (android_get_ioprio(pid, &clazz, &ioprio)) {
+            fprintf(stderr, "Failed to read priority (%s)\n", strerror(errno));
+            return 1;
+        }
+        fprintf(stdout, "Pid %d, class %s (%d), prio %d\n", pid, classes[clazz], clazz, ioprio);
+        return 0;
+    }
+
+    if (!strcmp(argv[2], "none")) {
+        clazz = IoSchedClass_NONE;
+    } else if (!strcmp(argv[2], "rt")) {
+        clazz = IoSchedClass_RT;
+    } else if (!strcmp(argv[2], "be")) {
+        clazz = IoSchedClass_BE;
+    } else if (!strcmp(argv[2], "idle")) {
+        clazz = IoSchedClass_IDLE;
+    } else {
+        fprintf(stderr, "Unsupported class '%s'\n", argv[2]);
+        return 1;
+    }
+
+    ioprio = atoi(argv[3]);
+
+    printf("Setting pid %d i/o class to %d, prio %d\n", pid, clazz, ioprio);
+    if (android_set_ioprio(pid, clazz, ioprio)) {
+        fprintf(stderr, "Failed to set priority (%s)\n", strerror(errno));
+        return 1;
+    }
+
+    return 0;
+}
diff --git a/kill.c b/kill.c
new file mode 100644
index 0000000..4d0e479
--- /dev/null
+++ b/kill.c
@@ -0,0 +1,35 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+
+#include <sys/types.h>
+#include <signal.h>
+
+int kill_main(int argc, char **argv)
+{
+    int sig = SIGTERM;
+    int result = 0;
+    
+    argc--;
+    argv++;
+
+    if(argc >= 2 && argv[0][0] == '-'){
+        sig = atoi(argv[0] + 1);
+        argc--;
+        argv++;
+    }
+
+    while(argc > 0){
+        int pid = atoi(argv[0]);
+        int err = kill(pid, sig);
+        if (err < 0) {
+            result = err;
+            fprintf(stderr, "could not kill pid %d: %s\n", pid, strerror(errno));
+        }
+            
+        argc--;
+        argv++;
+    }
+    
+    return result;
+}
diff --git a/ln.c b/ln.c
new file mode 100644
index 0000000..dcd5e3a
--- /dev/null
+++ b/ln.c
@@ -0,0 +1,34 @@
+#include <stdio.h>
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+
+static int usage()
+{
+    fprintf(stderr,"ln [-s] <target> <name>\n");
+    return -1;
+}
+
+int ln_main(int argc, char *argv[])
+{
+    int symbolic = 0;
+    int ret;
+    if(argc < 2) return usage();
+    
+    if(!strcmp(argv[1],"-s")) {
+        symbolic = 1;
+        argc--;
+        argv++;
+    }
+
+    if(argc < 3) return usage();
+
+    if(symbolic) {
+        ret = symlink(argv[1], argv[2]);
+    } else {
+        ret = link(argv[1], argv[2]);
+    }
+    if(ret < 0)
+        fprintf(stderr, "link failed %s\n", strerror(errno));
+    return ret;
+}
diff --git a/log.c b/log.c
new file mode 100644
index 0000000..f30e6a7
--- /dev/null
+++ b/log.c
@@ -0,0 +1,145 @@
+/*
+ * Copyright (c) 2008, The Android Open Source Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * 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.
+ *  * Neither the name of Google, Inc. 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 COPYRIGHT HOLDERS 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
+ * COPYRIGHT OWNER 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 <cutils/logd.h>
+#include <ctype.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <stdlib.h>
+#include <cutils/sockets.h>
+#include <unistd.h>
+
+/*
+ * Note: also accepts 0-9 priorities
+ * returns ANDROID_LOG_UNKNOWN if the character is unrecognized
+ */
+static android_LogPriority filterCharToPri (char c)
+{
+    android_LogPriority pri;
+
+    c = tolower(c);
+
+    if (c >= '0' && c <= '9') {
+        if (c >= ('0'+ANDROID_LOG_SILENT)) {
+            pri = ANDROID_LOG_VERBOSE;
+        } else {
+            pri = (android_LogPriority)(c - '0');
+        }
+    } else if (c == 'v') {
+        pri = ANDROID_LOG_VERBOSE;
+    } else if (c == 'd') {
+        pri = ANDROID_LOG_DEBUG;
+    } else if (c == 'i') {
+        pri = ANDROID_LOG_INFO;
+    } else if (c == 'w') {
+        pri = ANDROID_LOG_WARN;
+    } else if (c == 'e') {
+        pri = ANDROID_LOG_ERROR;
+    } else if (c == 'f') {
+        pri = ANDROID_LOG_FATAL;
+    } else if (c == 's') {
+        pri = ANDROID_LOG_SILENT;
+    } else if (c == '*') {
+        pri = ANDROID_LOG_DEFAULT;
+    } else {
+        pri = ANDROID_LOG_UNKNOWN;
+    }
+
+    return pri;
+}
+
+static int usage(const char *s)
+{
+    fprintf(stderr, "USAGE: %s [-p priorityChar] [-t tag] message\n", s);
+
+    fprintf(stderr, "\tpriorityChar should be one of:\n"
+                        "\t\tv,d,i,w,e\n");
+    exit(-1);
+}
+
+
+int log_main(int argc, char *argv[])
+{
+    android_LogPriority priority; 
+    const char *tag = "log";
+    char buffer[4096];
+    int i;
+
+    priority = ANDROID_LOG_INFO;
+
+    for (;;) {
+        int ret;
+
+        ret = getopt(argc, argv, "t:p:h");
+
+        if (ret < 0) {
+            break;
+        }
+
+        switch(ret) {
+            case 't':
+                tag = optarg;
+            break;
+            
+            case 'p':
+                priority = filterCharToPri(optarg[0]);
+                if (priority == ANDROID_LOG_UNKNOWN) {
+                    usage(argv[0]);                    
+                }
+            break;
+
+            case 'h':
+                usage(argv[0]);
+            break;
+        }
+    }
+
+    if (optind == argc) {
+        usage(argv[0]);
+    }
+
+    buffer[0] = '\0';
+    
+    for (i = optind ; i < argc ; i++) {
+        strncat(buffer, argv[i], sizeof(buffer)-1);
+        strncat(buffer, " ", sizeof(buffer)-1);
+    }
+
+    if(buffer[0] == 0) {
+        usage(argv[0]);
+    }
+
+    __android_log_print(priority, tag, "%s", buffer);
+
+    return 0;
+}
+
diff --git a/ls.c b/ls.c
new file mode 100644
index 0000000..962bf47
--- /dev/null
+++ b/ls.c
@@ -0,0 +1,508 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <dirent.h>
+#include <errno.h>
+
+#include <sys/stat.h>
+#include <unistd.h>
+#include <time.h>
+
+#include <pwd.h>
+#include <grp.h>
+
+#include <linux/kdev_t.h>
+#include <limits.h>
+
+// dynamic arrays
+typedef struct {
+    int count;
+    int capacity;
+    void** items;
+} dynarray_t;
+
+#define DYNARRAY_INITIALIZER  { 0, 0, NULL }
+
+static void dynarray_init( dynarray_t *a )
+{
+    a->count = a->capacity = 0;
+    a->items = NULL;
+}
+
+static void dynarray_reserve_more( dynarray_t *a, int count )
+{
+    int old_cap = a->capacity;
+    int new_cap = old_cap;
+    const int max_cap = INT_MAX/sizeof(void*);
+    void** new_items;
+    int new_count = a->count + count;
+
+    if (count <= 0)
+        return;
+
+    if (count > max_cap - a->count)
+        abort();
+
+    new_count = a->count + count;
+
+    while (new_cap < new_count) {
+        old_cap = new_cap;
+        new_cap += (new_cap >> 2) + 4;
+        if (new_cap < old_cap || new_cap > max_cap) {
+            new_cap = max_cap;
+        }
+    }
+    new_items = realloc(a->items, new_cap*sizeof(void*));
+    if (new_items == NULL)
+        abort();
+
+    a->items = new_items;
+    a->capacity = new_cap;
+}
+
+static void dynarray_append( dynarray_t *a, void* item )
+{
+    if (a->count >= a->capacity)
+        dynarray_reserve_more(a, 1);
+
+    a->items[a->count++] = item;
+}
+
+static void dynarray_done( dynarray_t *a )
+{
+    free(a->items);
+    a->items = NULL;
+    a->count = a->capacity = 0;
+}
+
+#define DYNARRAY_FOREACH_TYPE(_array,_item_type,_item,_stmnt) \
+    do { \
+        int _nn_##__LINE__ = 0; \
+        for (;_nn_##__LINE__ < (_array)->count; ++ _nn_##__LINE__) { \
+            _item_type _item = (_item_type)(_array)->items[_nn_##__LINE__]; \
+            _stmnt; \
+        } \
+    } while (0)
+
+#define DYNARRAY_FOREACH(_array,_item,_stmnt) \
+    DYNARRAY_FOREACH_TYPE(_array,void *,_item,_stmnt)
+
+// string arrays
+
+typedef dynarray_t  strlist_t;
+
+#define  STRLIST_INITIALIZER  DYNARRAY_INITIALIZER
+
+#define  STRLIST_FOREACH(_list,_string,_stmnt) \
+    DYNARRAY_FOREACH_TYPE(_list,char *,_string,_stmnt)
+
+static void strlist_init( strlist_t *list )
+{
+    dynarray_init(list);
+}
+
+static void strlist_append_b( strlist_t *list, const void* str, size_t  slen )
+{
+    char *copy = malloc(slen+1);
+    memcpy(copy, str, slen);
+    copy[slen] = '\0';
+    dynarray_append(list, copy);
+}
+
+static void strlist_append_dup( strlist_t *list, const char *str)
+{
+    strlist_append_b(list, str, strlen(str));
+}
+
+static void strlist_done( strlist_t *list )
+{
+    STRLIST_FOREACH(list, string, free(string));
+    dynarray_done(list);
+}
+
+static int strlist_compare_strings(const void* a, const void* b)
+{
+    const char *sa = *(const char **)a;
+    const char *sb = *(const char **)b;
+    return strcmp(sa, sb);
+}
+
+static void strlist_sort( strlist_t *list )
+{
+    if (list->count > 0) {
+        qsort(list->items, 
+              (size_t)list->count,
+              sizeof(void*),
+              strlist_compare_strings);
+    }
+}
+
+// bits for flags argument
+#define LIST_LONG           (1 << 0)
+#define LIST_ALL            (1 << 1)
+#define LIST_RECURSIVE      (1 << 2)
+#define LIST_DIRECTORIES    (1 << 3)
+#define LIST_SIZE           (1 << 4)
+
+// fwd
+static int listpath(const char *name, int flags);
+
+static char mode2kind(unsigned mode)
+{
+    switch(mode & S_IFMT){
+    case S_IFSOCK: return 's';
+    case S_IFLNK: return 'l';
+    case S_IFREG: return '-';
+    case S_IFDIR: return 'd';
+    case S_IFBLK: return 'b';
+    case S_IFCHR: return 'c';
+    case S_IFIFO: return 'p';
+    default: return '?';
+    }
+}
+
+static void mode2str(unsigned mode, char *out)
+{
+    *out++ = mode2kind(mode);
+    
+    *out++ = (mode & 0400) ? 'r' : '-';
+    *out++ = (mode & 0200) ? 'w' : '-';
+    if(mode & 04000) {
+        *out++ = (mode & 0100) ? 's' : 'S';
+    } else {
+        *out++ = (mode & 0100) ? 'x' : '-';
+    }
+    *out++ = (mode & 040) ? 'r' : '-';
+    *out++ = (mode & 020) ? 'w' : '-';
+    if(mode & 02000) {
+        *out++ = (mode & 010) ? 's' : 'S';
+    } else {
+        *out++ = (mode & 010) ? 'x' : '-';
+    }
+    *out++ = (mode & 04) ? 'r' : '-';
+    *out++ = (mode & 02) ? 'w' : '-';
+    if(mode & 01000) {
+        *out++ = (mode & 01) ? 't' : 'T';
+    } else {
+        *out++ = (mode & 01) ? 'x' : '-';
+    }
+    *out = 0;
+}
+
+static void user2str(unsigned uid, char *out)
+{
+    struct passwd *pw = getpwuid(uid);
+    if(pw) {
+        strcpy(out, pw->pw_name);
+    } else {
+        sprintf(out, "%d", uid);
+    }
+}
+
+static void group2str(unsigned gid, char *out)
+{
+    struct group *gr = getgrgid(gid);
+    if(gr) {
+        strcpy(out, gr->gr_name);
+    } else {
+        sprintf(out, "%d", gid);
+    }
+}
+
+static int show_total_size(const char *dirname, DIR *d, int flags)
+{
+    struct dirent *de;
+    char tmp[1024];
+    struct stat s;
+    int sum = 0;
+
+    /* run through the directory and sum up the file block sizes */
+    while ((de = readdir(d)) != 0) {
+        if (strcmp(de->d_name, ".") == 0 || strcmp(de->d_name, "..") == 0)
+            continue;
+        if (de->d_name[0] == '.' && (flags & LIST_ALL) == 0)
+            continue;
+
+        if (strcmp(dirname, "/") == 0)
+            snprintf(tmp, sizeof(tmp), "/%s", de->d_name);
+        else
+            snprintf(tmp, sizeof(tmp), "%s/%s", dirname, de->d_name);
+
+        if (lstat(tmp, &s) < 0) {
+            fprintf(stderr, "stat failed on %s: %s\n", tmp, strerror(errno));
+            rewinddir(d);
+            return -1;
+        }
+
+        sum += s.st_blocks / 2;
+    }
+
+    printf("total %d\n", sum);
+    rewinddir(d);
+    return 0;
+}
+
+static int listfile_size(const char *path, const char *filename, int flags)
+{
+    struct stat s;
+
+    if (lstat(path, &s) < 0) {
+        fprintf(stderr, "lstat '%s' failed: %s\n", path, strerror(errno));
+        return -1;
+    }
+
+    /* blocks are 512 bytes, we want output to be KB */
+    printf("%lld %s\n", s.st_blocks / 2, filename);
+    return 0;
+}
+
+static int listfile_long(const char *path, int flags)
+{
+    struct stat s;
+    char date[32];
+    char mode[16];
+    char user[16];
+    char group[16];
+    const char *name;
+
+    /* name is anything after the final '/', or the whole path if none*/
+    name = strrchr(path, '/');
+    if(name == 0) {
+        name = path;
+    } else {
+        name++;
+    }
+
+    if(lstat(path, &s) < 0) {
+        return -1;
+    }
+
+    mode2str(s.st_mode, mode);
+    user2str(s.st_uid, user);
+    group2str(s.st_gid, group);
+
+    strftime(date, 32, "%Y-%m-%d %H:%M", localtime((const time_t*)&s.st_mtime));
+    date[31] = 0;
+    
+// 12345678901234567890123456789012345678901234567890123456789012345678901234567890
+// MMMMMMMM UUUUUUUU GGGGGGGGG XXXXXXXX YYYY-MM-DD HH:MM NAME (->LINK)
+
+    switch(s.st_mode & S_IFMT) {
+    case S_IFBLK:
+    case S_IFCHR:
+        printf("%s %-8s %-8s %3d, %3d %s %s\n",
+               mode, user, group, 
+               (int) MAJOR(s.st_rdev), (int) MINOR(s.st_rdev),
+               date, name);
+        break;
+    case S_IFREG:
+        printf("%s %-8s %-8s %8lld %s %s\n",
+               mode, user, group, s.st_size, date, name);
+        break;
+    case S_IFLNK: {
+        char linkto[256];
+        int len;
+
+        len = readlink(path, linkto, 256);
+        if(len < 0) return -1;
+        
+        if(len > 255) {
+            linkto[252] = '.';
+            linkto[253] = '.';
+            linkto[254] = '.';
+            linkto[255] = 0;
+        } else {
+            linkto[len] = 0;
+        }
+        
+        printf("%s %-8s %-8s          %s %s -> %s\n",
+               mode, user, group, date, name, linkto);
+        break;
+    }
+    default:
+        printf("%s %-8s %-8s          %s %s\n",
+               mode, user, group, date, name);
+
+    }
+    return 0;
+}
+
+static int listfile(const char *dirname, const char *filename, int flags)
+{
+    if ((flags & (LIST_LONG | LIST_SIZE)) == 0) {
+        printf("%s\n", filename);
+        return 0;
+    }
+
+    char tmp[4096];
+    const char* pathname = filename;
+
+    if (dirname != NULL) {
+        snprintf(tmp, sizeof(tmp), "%s/%s", dirname, filename);
+        pathname = tmp;
+    } else {
+        pathname = filename;
+    }
+
+    if ((flags & LIST_LONG) != 0) {
+        return listfile_long(pathname, flags);
+    } else /*((flags & LIST_SIZE) != 0)*/ {
+        return listfile_size(pathname, filename, flags);
+    }
+}
+
+static int listdir(const char *name, int flags)
+{
+    char tmp[4096];
+    DIR *d;
+    struct dirent *de;
+    strlist_t  files = STRLIST_INITIALIZER;
+    
+    d = opendir(name);
+    if(d == 0) {
+        fprintf(stderr, "opendir failed, %s\n", strerror(errno));
+        return -1;
+    }
+
+    if ((flags & LIST_SIZE) != 0) {
+        show_total_size(name, d, flags);
+    }
+
+    while((de = readdir(d)) != 0){
+        if (!strcmp(de->d_name, ".") || !strcmp(de->d_name, "..")) continue;
+        if(de->d_name[0] == '.' && (flags & LIST_ALL) == 0) continue;
+
+        strlist_append_dup(&files, de->d_name);
+    }
+
+    strlist_sort(&files);
+    STRLIST_FOREACH(&files, filename, listfile(name, filename, flags));
+    strlist_done(&files);
+
+    if (flags & LIST_RECURSIVE) {
+        strlist_t subdirs = STRLIST_INITIALIZER;
+
+        rewinddir(d);
+
+        while ((de = readdir(d)) != 0) {
+            struct stat s;
+            int err;
+
+            if (!strcmp(de->d_name, ".") || !strcmp(de->d_name, ".."))
+                continue;
+            if (de->d_name[0] == '.' && (flags & LIST_ALL) == 0)
+                continue;
+
+            if (!strcmp(name, "/"))
+                snprintf(tmp, sizeof(tmp), "/%s", de->d_name);
+            else
+                snprintf(tmp, sizeof(tmp), "%s/%s", name, de->d_name);
+
+            /*
+             * If the name ends in a '/', use stat() so we treat it like a
+             * directory even if it's a symlink.
+             */
+            if (tmp[strlen(tmp)-1] == '/')
+                err = stat(tmp, &s);
+            else
+                err = lstat(tmp, &s);
+
+            if (err < 0) {
+                perror(tmp);
+                closedir(d);
+                return -1;
+            }
+
+            if (S_ISDIR(s.st_mode)) {
+                strlist_append_dup(&subdirs, tmp);
+            }
+        }
+        strlist_sort(&subdirs);
+        STRLIST_FOREACH(&subdirs, path, {
+            printf("\n%s:\n", path);
+            listdir(path, flags);
+        });
+        strlist_done(&subdirs);
+    }
+
+    closedir(d);
+    return 0;
+}
+
+static int listpath(const char *name, int flags)
+{
+    struct stat s;
+    int err;
+
+    /*
+     * If the name ends in a '/', use stat() so we treat it like a
+     * directory even if it's a symlink.
+     */
+    if (name[strlen(name)-1] == '/')
+        err = stat(name, &s);
+    else
+        err = lstat(name, &s);
+
+    if (err < 0) {
+        perror(name);
+        return -1;
+    }
+
+    if ((flags & LIST_DIRECTORIES) == 0 && S_ISDIR(s.st_mode)) {
+        if (flags & LIST_RECURSIVE)
+            printf("\n%s:\n", name);
+        return listdir(name, flags);
+    } else {
+        /* yeah this calls stat() again*/
+        return listfile(NULL, name, flags);
+    }
+}
+
+int ls_main(int argc, char **argv)
+{
+    int flags = 0;
+    int listed = 0;
+    
+    if(argc > 1) {
+        int i;
+        int err = 0;
+        strlist_t  files = STRLIST_INITIALIZER;
+
+        for (i = 1; i < argc; i++) {
+            if (argv[i][0] == '-') {
+                /* an option ? */
+                const char *arg = argv[i]+1;
+                while (arg[0]) {
+                    switch (arg[0]) {
+                    case 'l': flags |= LIST_LONG; break;
+                    case 's': flags |= LIST_SIZE; break;
+                    case 'R': flags |= LIST_RECURSIVE; break;
+                    case 'd': flags |= LIST_DIRECTORIES; break;
+                    case 'a': flags |= LIST_ALL; break;
+                    default:
+                        fprintf(stderr, "%s: Unknown option '-%c'. Aborting.\n", "ls", arg[0]);
+                        exit(1);
+                    }
+                    arg++;
+                }
+            } else {
+                /* not an option ? */
+                strlist_append_dup(&files, argv[i]);
+            }
+        }
+
+        if (files.count > 0) {
+            STRLIST_FOREACH(&files, path, {
+                if (listpath(path, flags) != 0) {
+                    err = EXIT_FAILURE;
+                }
+            });
+            strlist_done(&files);
+            return err;
+        }
+    }
+    
+    // list working directory if no files or directories were specified    
+    return listpath(".", flags);
+}
diff --git a/lsmod.c b/lsmod.c
new file mode 100644
index 0000000..8b55ee6
--- /dev/null
+++ b/lsmod.c
@@ -0,0 +1,10 @@
+#include <stdio.h>
+
+extern int cat_main(int argc, char **argv);
+
+int lsmod_main(int argc, char **argv)
+{
+	char *cat_argv[] = { "cat", "/proc/modules", NULL };
+	return cat_main(2, cat_argv);
+}
+
diff --git a/lsof.c b/lsof.c
new file mode 100644
index 0000000..99891db
--- /dev/null
+++ b/lsof.c
@@ -0,0 +1,223 @@
+/*
+ * Copyright (c) 2010, The Android Open Source Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * 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.
+ *  * Neither the name of Google, Inc. 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 COPYRIGHT HOLDERS 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
+ * COPYRIGHT OWNER 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 <dirent.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <libgen.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#define BUF_MAX 1024
+#define CMD_DISPLAY_MAX 10
+
+struct pid_info_t {
+    pid_t pid;
+
+    char cmdline[CMD_DISPLAY_MAX];
+
+    char path[PATH_MAX];
+    ssize_t parent_length;
+};
+
+void print_header()
+{
+    printf("%-9s %5s %10s %4s %9s %18s %9s %10s %s\n",
+            "COMMAND",
+            "PID",
+            "USER",
+            "FD",
+            "TYPE",
+            "DEVICE",
+            "SIZE/OFF",
+            "NODE",
+            "NAME");
+}
+
+void print_type(char *type, struct pid_info_t* info)
+{
+    static ssize_t link_dest_size;
+    static char link_dest[PATH_MAX];
+
+    strncat(info->path, type, sizeof(info->path));
+    if ((link_dest_size = readlink(info->path, link_dest, sizeof(link_dest)-1)) < 0) {
+        if (errno == ENOENT)
+            goto out;
+
+        snprintf(link_dest, sizeof(link_dest), "%s (readlink: %s)", info->path, strerror(errno));
+    } else {
+        link_dest[link_dest_size] = '\0';
+    }
+
+    // Things that are just the root filesystem are uninteresting (we already know)
+    if (!strcmp(link_dest, "/"))
+        goto out;
+
+    printf("%-9s %5d %10s %4s %9s %18s %9s %10s %s\n", info->cmdline, info->pid, "???", type,
+            "???", "???", "???", "???", link_dest);
+
+out:
+    info->path[info->parent_length] = '\0';
+}
+
+// Prints out all file that have been memory mapped
+void print_maps(struct pid_info_t* info)
+{
+    FILE *maps;
+    char buffer[PATH_MAX + 100];
+
+    size_t offset;
+    int major, minor;
+    char device[10];
+    long int inode;
+    char file[PATH_MAX];
+
+    strncat(info->path, "maps", sizeof(info->path));
+
+    maps = fopen(info->path, "r");
+    if (!maps)
+        goto out;
+
+    while (fscanf(maps, "%*x-%*x %*s %zx %5s %ld %s\n", &offset, device, &inode,
+            file) == 4) {
+        // We don't care about non-file maps
+        if (inode == 0 || !strcmp(device, "00:00"))
+            continue;
+
+        printf("%-9s %5d %10s %4s %9s %18s %9zd %10ld %s\n", info->cmdline, info->pid, "???", "mem",
+                "???", device, offset, inode, file);
+    }
+
+    fclose(maps);
+
+out:
+    info->path[info->parent_length] = '\0';
+}
+
+// Prints out all open file descriptors
+void print_fds(struct pid_info_t* info)
+{
+    static char* fd_path = "fd/";
+    strncat(info->path, fd_path, sizeof(info->path));
+
+    int previous_length = info->parent_length;
+    info->parent_length += strlen(fd_path);
+
+    DIR *dir = opendir(info->path);
+    if (dir == NULL) {
+        char msg[BUF_MAX];
+        snprintf(msg, sizeof(msg), "%s (opendir: %s)", info->path, strerror(errno));
+        printf("%-9s %5d %10s %4s %9s %18s %9s %10s %s\n", info->cmdline, info->pid, "???", "FDS",
+                "", "", "", "", msg);
+        goto out;
+    }
+
+    struct dirent* de;
+    while ((de = readdir(dir))) {
+        if (!strcmp(de->d_name, ".") || !strcmp(de->d_name, ".."))
+            continue;
+
+        print_type(de->d_name, info);
+    }
+    closedir(dir);
+
+out:
+    info->parent_length = previous_length;
+    info->path[info->parent_length] = '\0';
+}
+
+void lsof_dumpinfo(pid_t pid)
+{
+    int fd;
+    struct pid_info_t info;
+    info.pid = pid;
+
+    snprintf(info.path, sizeof(info.path), "/proc/%d/", pid);
+
+    info.parent_length = strlen(info.path);
+
+    // Read the command line information; each argument is terminated with NULL.
+    strncat(info.path, "cmdline", sizeof(info.path));
+    fd = open(info.path, O_RDONLY);
+    if (fd < 0) {
+        fprintf(stderr, "Couldn't read %s\n", info.path);
+        return;
+    }
+    char cmdline[PATH_MAX];
+    if (read(fd, cmdline, sizeof(cmdline)) < 0) {
+        fprintf(stderr, "Error reading cmdline: %s: %s\n", info.path, strerror(errno));
+        close(fd);
+        return;
+    }
+    close(fd);
+    info.path[info.parent_length] = '\0';
+
+    // We only want the basename of the cmdline
+    strncpy(info.cmdline, basename(cmdline), sizeof(info.cmdline));
+    info.cmdline[sizeof(info.cmdline)-1] = '\0';
+
+    // Read each of these symlinks
+    print_type("cwd", &info);
+    print_type("exe", &info);
+    print_type("root", &info);
+
+    print_fds(&info);
+    print_maps(&info);
+}
+
+int lsof_main(int argc, char *argv[])
+{
+    DIR *dir = opendir("/proc");
+    if (dir == NULL) {
+        fprintf(stderr, "Couldn't open /proc\n");
+        return -1;
+    }
+
+    print_header();
+
+    struct dirent* de;
+    while ((de = readdir(dir))) {
+        if (!strcmp(de->d_name, ".") || !strcmp(de->d_name, ".."))
+            continue;
+
+        // Only inspect directories that are PID numbers
+        char* endptr;
+        long int pid = strtol(de->d_name, &endptr, 10);
+        if (*endptr != '\0')
+            continue;
+
+        lsof_dumpinfo(pid);
+    }
+    closedir(dir);
+
+    return 0;
+}
diff --git a/mkdir.c b/mkdir.c
new file mode 100644
index 0000000..656970a
--- /dev/null
+++ b/mkdir.c
@@ -0,0 +1,78 @@
+#include <stdio.h>
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+#include <sys/limits.h>
+#include <sys/stat.h>
+
+static int usage()
+{
+    fprintf(stderr,"mkdir [OPTION] <target>\n");
+    fprintf(stderr,"    --help           display usage and exit\n");
+    fprintf(stderr,"    -p, --parents    create parent directories as needed\n");
+    return -1;
+}
+
+int mkdir_main(int argc, char *argv[])
+{
+    int symbolic = 0;
+    int ret;
+    if(argc < 2 || strcmp(argv[1], "--help") == 0) {
+        return usage();
+    }
+
+    int recursive = (strcmp(argv[1], "-p") == 0 ||
+                     strcmp(argv[1], "--parents") == 0) ? 1 : 0;
+
+    if(recursive && argc < 3) {
+        // -p specified without a path
+        return usage();
+    }
+
+    if(recursive) {
+        argc--;
+        argv++;
+    }
+
+    char currpath[PATH_MAX], *pathpiece;
+    struct stat st;
+
+    while(argc > 1) {
+        argc--;
+        argv++;
+        if(recursive) {
+            // reset path
+            strcpy(currpath, "");
+            // create the pieces of the path along the way
+            pathpiece = strtok(argv[0], "/");
+            if(argv[0][0] == '/') {
+                // prepend / if needed
+                strcat(currpath, "/");
+            }
+            while(pathpiece != NULL) {
+                if(strlen(currpath) + strlen(pathpiece) + 2/*NUL and slash*/ > PATH_MAX) {
+                    fprintf(stderr, "Invalid path specified: too long\n");
+                    return 1;
+                }
+                strcat(currpath, pathpiece);
+                strcat(currpath, "/");
+                if(stat(currpath, &st) != 0) {
+                    ret = mkdir(currpath, 0777);
+                    if(ret < 0) {
+                        fprintf(stderr, "mkdir failed for %s, %s\n", currpath, strerror(errno));
+                        return ret;
+                    }
+                }
+                pathpiece = strtok(NULL, "/");
+            }
+        } else {
+            ret = mkdir(argv[0], 0777);
+            if(ret < 0) {
+                fprintf(stderr, "mkdir failed for %s, %s\n", argv[0], strerror(errno));
+                return ret;
+            }
+        }
+    }
+    
+    return 0;
+}
diff --git a/mount.c b/mount.c
new file mode 100644
index 0000000..472c952
--- /dev/null
+++ b/mount.c
@@ -0,0 +1,276 @@
+/*
+ * mount.c, by rmk
+ */
+
+#include <sys/mount.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <linux/loop.h>
+
+#define ARRAY_SIZE(x)	(sizeof(x) / sizeof(x[0]))
+
+// FIXME - only one loop mount is supported at a time
+#define LOOP_DEVICE "/dev/block/loop0"
+
+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)
+
+
+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;
+
+}
+
+static unsigned long
+parse_mount_options(char *arg, unsigned long rwflag, struct extra_opts *extra, int* loop)
+{
+	char *s;
+    
+    *loop = 0;
+	while ((s = strsep(&arg, ",")) != NULL) {
+		char *opt = s;
+		unsigned int i;
+		int res, no = s[0] == 'n' && s[1] == 'o';
+
+		if (no)
+			s += 2;
+
+        if (strcmp(s, "loop") == 0) {
+            *loop = 1;
+            continue;
+        }
+		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;
+}
+
+static 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, int loop)
+{
+	char *s;
+	int error = 0;
+
+    if (loop) {
+        int file_fd, device_fd;
+        int flags;
+
+        flags = (rwflag & MS_RDONLY) ? O_RDONLY : O_RDWR;
+        
+        // FIXME - only one loop mount supported at a time
+        file_fd = open(dev, flags);
+        if (file_fd < -1) {
+            perror("open backing file failed");
+            return 1;
+        }
+        device_fd = open(LOOP_DEVICE, flags);
+        if (device_fd < -1) {
+            perror("open loop device failed");
+            close(file_fd);
+            return 1;
+        }
+        if (ioctl(device_fd, LOOP_SET_FD, file_fd) < 0) {
+            perror("ioctl LOOP_SET_FD failed");
+            close(file_fd);
+            close(device_fd);
+            return 1;
+        }
+
+        close(file_fd);
+        close(device_fd);
+        dev = LOOP_DEVICE;
+    }
+
+	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;
+}
+
+static int print_mounts()
+{
+    FILE* f;
+    int length;
+    char buffer[100];
+    
+    f = fopen("/proc/mounts", "r");
+    if (!f) {
+        fprintf(stdout, "could not open /proc/mounts\n");
+        return -1;
+    }
+
+    do {
+        length = fread(buffer, 1, 100, f);
+        if (length > 0)
+            fwrite(buffer, 1, length, stdout);
+    } while (length > 0);
+
+    fclose(f);
+    return 0;
+}
+
+int mount_main(int argc, char *argv[])
+{
+	char *type = NULL;
+	int c;
+	int loop = 0;
+
+	progname = argv[0];
+	rwflag = MS_VERBOSE;
+	
+	// mount with no arguments is equivalent to "cat /proc/mounts"
+	if (argc == 1) return print_mounts();
+
+	do {
+		c = getopt(argc, argv, "o:rt:w");
+		if (c == EOF)
+			break;
+		switch (c) {
+		case 'o':
+			rwflag = parse_mount_options(optarg, rwflag, &extra, &loop);
+			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, loop);
+}
diff --git a/mv.c b/mv.c
new file mode 100644
index 0000000..a5bc225
--- /dev/null
+++ b/mv.c
@@ -0,0 +1,59 @@
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <limits.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+
+int mv_main(int argc, char *argv[])
+{
+    const char* dest;
+    struct stat st;
+    int i;
+
+    if (argc < 3) {
+        fprintf(stderr,"USAGE: %s <source...> <destination>\n", argv[0]);
+        return -1;
+    }
+
+    /* check if destination exists */
+    dest = argv[argc - 1];
+    if (stat(dest, &st)) {
+        /* an error, unless the destination was missing */
+        if (errno != ENOENT) {
+            fprintf(stderr, "failed on %s - %s\n", dest, strerror(errno));
+            return -1;
+        }
+        st.st_mode = 0;
+    }
+
+    for (i = 1; i < argc - 1; i++) {
+        const char *source = argv[i];
+        char fullDest[PATH_MAX + 1 + PATH_MAX + 1];
+        /* assume we build "dest/source", and let rename() fail on pathsize */
+        if (strlen(dest) + 1 + strlen(source) + 1 > sizeof(fullDest)) {
+            fprintf(stderr, "path too long\n");
+            return -1;
+        }
+        strcpy(fullDest, dest);
+
+        /* if destination is a directory, concat the source file name */
+        if (S_ISDIR(st.st_mode)) {
+            const char *fileName = strrchr(source, '/');
+            if (fullDest[strlen(fullDest)-1] != '/') {
+                strcat(fullDest, "/");
+            }
+            strcat(fullDest, fileName ? fileName + 1 : source);
+        }
+
+        /* attempt to move it */
+        if (rename(source, fullDest)) {
+            fprintf(stderr, "failed on '%s' - %s\n", source, strerror(errno));
+            return -1;
+        }
+    }
+
+    return 0;
+}
+
diff --git a/nandread.c b/nandread.c
new file mode 100644
index 0000000..9644973
--- /dev/null
+++ b/nandread.c
@@ -0,0 +1,286 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <errno.h>
+#include <fcntl.h>
+
+#include <mtd/mtd-user.h>
+#include <sys/ioctl.h>
+
+static int test_empty(const char *buf, size_t size)
+{
+    while(size--) {
+        if (*buf++ != 0xff)
+            return 0;
+    }
+    return 1;
+}
+
+int nandread_main(int argc, char **argv)
+{
+    char *devname = NULL;
+    char *filename = NULL;
+    char *statusfilename = NULL;
+    char *statusext = ".stat";
+    int fd;
+    int outfd = -1;
+    FILE *statusfile = NULL;
+    int ret;
+    int verbose = 0;
+    void *buffer;
+    loff_t pos, opos, end, bpos;
+    loff_t start = 0, len = 0;
+    int c;
+    int i;
+    int empty_pages = 0;
+    int page_count = 0;
+    int bad_block;
+    int rawmode = 0;
+    uint32_t *oob_data;
+    uint8_t *oob_fixed;
+    size_t spare_size = 64;
+    struct mtd_info_user mtdinfo;
+    struct mtd_ecc_stats initial_ecc, last_ecc, ecc;
+    struct mtd_oob_buf oobbuf;
+    struct nand_ecclayout ecclayout;
+
+    do {
+        c = getopt(argc, argv, "d:f:s:S:L:Rhv");
+        if (c == EOF)
+            break;
+        switch (c) {
+        case 'd':
+            devname = optarg;
+            break;
+        case 'f':
+            filename = optarg;
+            break;
+        case 's':
+            spare_size = atoi(optarg);
+            break;
+        case 'S':
+            start = strtoll(optarg, NULL, 0);
+            break;
+        case 'L':
+            len = strtoll(optarg, NULL, 0);
+            break;
+        case 'R':
+            rawmode = 1;
+            break;
+        case 'v':
+            verbose++;
+            break;
+        case 'h':
+            fprintf(stderr, "%s [-d <dev>] [-f file] [-s sparesize] [-vh]\n"
+                    "  -d <dev>   Read from <dev>\n"
+                    "  -f <file>  Write to <file>\n"
+                    "  -s <size>  Number of spare bytes in file (default 64)\n"
+                    "  -R         Raw mode\n"
+                    "  -S <start> Start offset (default 0)\n"
+                    "  -L <len>   Length (default 0)\n"
+                    "  -v         Print info\n"
+                    "  -h         Print help\n", argv[0]);
+            return -1;
+        case '?':
+            fprintf(stderr, "%s: invalid option -%c\n",
+                argv[0], optopt);
+            exit(1);
+        }
+    } while (1);
+
+    if (optind < argc) {
+        fprintf(stderr, "%s: extra arguments\n", argv[0]);
+        return 1;
+    }
+    if (!devname) {
+        fprintf(stderr, "%s: specify device name\n", argv[0]);
+        return 1;
+    }
+
+    fd = open(devname, O_RDONLY);
+    if (fd < 0) {
+        fprintf(stderr, "cannot open %s, %s\n", devname, strerror(errno));
+        return 1;
+    }
+
+    if (filename) {
+        outfd = creat(filename, 0666);
+        if (outfd < 0) {
+            fprintf(stderr, "cannot open %s, %s\n", filename, strerror(errno));
+            return 1;
+        }
+        statusfilename = malloc(strlen(filename) + strlen(statusext) + 1);
+        strcpy(statusfilename, filename);
+        strcat(statusfilename, statusext);
+        statusfile = fopen(statusfilename, "w+");
+        if (!statusfile) {
+            fprintf(stderr, "cannot open %s, %s\n", statusfilename, strerror(errno));
+            return 1;
+        }
+    }
+
+    ret = ioctl(fd, MEMGETINFO, &mtdinfo);
+    if (ret) {
+        fprintf(stderr, "failed get mtd info for %s, %s\n",
+                devname, strerror(errno));
+        return 1;
+    }
+
+    if (verbose) {
+        printf("size: %u\n", mtdinfo.size);
+        printf("erase size: %u\n", mtdinfo.erasesize);
+        printf("write size: %u\n", mtdinfo.writesize);
+        printf("oob size: %u\n", mtdinfo.oobsize);
+    }
+
+    buffer = malloc(mtdinfo.writesize + mtdinfo.oobsize + spare_size);
+    if (!buffer) {
+        fprintf(stderr, "failed allocate readbuffer size %u\n",
+                mtdinfo.writesize + mtdinfo.oobsize);
+        return 1;
+    }
+
+    oobbuf.length = mtdinfo.oobsize;
+    oob_data = (uint32_t *)((uint8_t *)buffer + mtdinfo.writesize);
+    memset(oob_data, 0xff, mtdinfo.oobsize + spare_size);
+    oobbuf.ptr = (uint8_t *)oob_data + spare_size;
+
+    ret = ioctl(fd, ECCGETLAYOUT, &ecclayout);
+    if (ret) {
+        fprintf(stderr, "failed get ecc layout for %s, %s\n",
+                devname, strerror(errno));
+        return 1;
+    }
+    if (verbose) {
+        printf("ecc bytes: %u\n", ecclayout.eccbytes);
+        printf("oobavail: %u\n", ecclayout.oobavail);
+    }
+    if (ecclayout.oobavail > spare_size)
+        printf("oobavail, %d > image spare size, %d\n", ecclayout.oobavail, spare_size);
+
+    ret = ioctl(fd, ECCGETSTATS, &initial_ecc);
+    if (ret) {
+        fprintf(stderr, "failed get ecc stats for %s, %s\n",
+                devname, strerror(errno));
+        return 1;
+    }
+    last_ecc = initial_ecc;
+
+    if (verbose) {
+        printf("initial ecc corrected: %u\n", initial_ecc.corrected);
+        printf("initial ecc failed: %u\n", initial_ecc.failed);
+        printf("initial ecc badblocks: %u\n", initial_ecc.badblocks);
+        printf("initial ecc bbtblocks: %u\n", initial_ecc.bbtblocks);
+    }
+
+    if (rawmode) {
+        rawmode = mtdinfo.oobsize;
+        ret = ioctl(fd, MTDFILEMODE, MTD_MODE_RAW);
+        if (ret) {
+            fprintf(stderr, "failed set raw mode for %s, %s\n",
+                    devname, strerror(errno));
+            return 1;
+        }
+    }
+
+    end = len ? (start + len) : mtdinfo.size;
+    for (pos = start, opos = 0; pos < end; pos += mtdinfo.writesize) {
+        bad_block = 0;
+        if (verbose > 3)
+            printf("reading at %llx\n", pos);
+        lseek64(fd, pos, SEEK_SET);
+        ret = read(fd, buffer, mtdinfo.writesize + rawmode);
+        if (ret < (int)mtdinfo.writesize) {
+            fprintf(stderr, "short read at %llx, %d\n", pos, ret);
+            bad_block = 2;
+        }
+        if (!rawmode) {
+            oobbuf.start = pos;
+            ret = ioctl(fd, MEMREADOOB, &oobbuf);
+            if (ret) {
+                fprintf(stderr, "failed to read oob data at %llx, %d\n", pos, ret);
+                bad_block = 2;
+            }
+        }
+        ret = ioctl(fd, ECCGETSTATS, &ecc);
+        if (ret) {
+            fprintf(stderr, "failed get ecc stats for %s, %s\n",
+                    devname, strerror(errno));
+            return 1;
+        }
+        bpos = pos / mtdinfo.erasesize * mtdinfo.erasesize;
+        ret = ioctl(fd, MEMGETBADBLOCK, &bpos);
+        if (ret && errno != EOPNOTSUPP) {
+            printf("badblock at %llx\n", pos);
+            bad_block = 1;
+        }
+        if (ecc.corrected != last_ecc.corrected)
+            printf("ecc corrected, %u, at %llx\n", ecc.corrected - last_ecc.corrected, pos);
+        if (ecc.failed != last_ecc.failed)
+            printf("ecc failed, %u, at %llx\n", ecc.failed - last_ecc.failed, pos);
+        if (ecc.badblocks != last_ecc.badblocks)
+            printf("ecc badblocks, %u, at %llx\n", ecc.badblocks - last_ecc.badblocks, pos);
+        if (ecc.bbtblocks != last_ecc.bbtblocks)
+            printf("ecc bbtblocks, %u, at %llx\n", ecc.bbtblocks - last_ecc.bbtblocks, pos);
+
+        if (!rawmode) {
+            oob_fixed = (uint8_t *)oob_data;
+            for (i = 0; i < MTD_MAX_OOBFREE_ENTRIES; i++) {
+                int len = ecclayout.oobfree[i].length;
+                if (oob_fixed + len > oobbuf.ptr)
+                    len = oobbuf.ptr - oob_fixed;
+                if (len) {
+                    memcpy(oob_fixed, oobbuf.ptr + ecclayout.oobfree[i].offset, len);
+                    oob_fixed += len;
+                }
+            }
+        }
+
+        if (outfd >= 0) {
+            ret = write(outfd, buffer, mtdinfo.writesize + spare_size);
+            if (ret < (int)(mtdinfo.writesize + spare_size)) {
+                fprintf(stderr, "short write at %llx, %d\n", pos, ret);
+                close(outfd);
+                outfd = -1;
+            }
+            if (ecc.corrected != last_ecc.corrected)
+                fprintf(statusfile, "%08llx: ecc corrected\n", opos);
+            if (ecc.failed != last_ecc.failed)
+                fprintf(statusfile, "%08llx: ecc failed\n", opos);
+            if (bad_block == 1)
+                fprintf(statusfile, "%08llx: badblock\n", opos);
+            if (bad_block == 2)
+                fprintf(statusfile, "%08llx: read error\n", opos);
+            opos += mtdinfo.writesize + spare_size;
+        }
+
+        last_ecc = ecc;
+        page_count++;
+        if (test_empty(buffer, mtdinfo.writesize + mtdinfo.oobsize + spare_size))
+            empty_pages++;
+        else if (verbose > 2 || (verbose > 1 && !(pos & (mtdinfo.erasesize - 1))))
+            printf("page at %llx (%d oobbytes): %08x %08x %08x %08x "
+                   "%08x %08x %08x %08x\n", pos, oobbuf.start,
+                   oob_data[0], oob_data[1], oob_data[2], oob_data[3],
+                   oob_data[4], oob_data[5], oob_data[6], oob_data[7]);
+    }
+
+    if (outfd >= 0) {
+        fprintf(statusfile, "read %d pages, %d empty\n", page_count, empty_pages);
+        fprintf(statusfile, "total ecc corrected, %u\n", ecc.corrected - initial_ecc.corrected);
+        fprintf(statusfile, "total ecc failed, %u\n", ecc.failed - initial_ecc.failed);
+        fprintf(statusfile, "total ecc badblocks, %u\n", ecc.badblocks - initial_ecc.badblocks);
+        fprintf(statusfile, "total ecc bbtblocks, %u\n", ecc.bbtblocks - initial_ecc.bbtblocks);
+    }
+    if (verbose) {
+        printf("total ecc corrected, %u\n", ecc.corrected - initial_ecc.corrected);
+        printf("total ecc failed, %u\n", ecc.failed - initial_ecc.failed);
+        printf("total ecc badblocks, %u\n", ecc.badblocks - initial_ecc.badblocks);
+        printf("total ecc bbtblocks, %u\n", ecc.bbtblocks - initial_ecc.bbtblocks);
+    }
+    printf("read %d pages, %d empty\n", page_count, empty_pages);
+
+    return 0;
+}
+
diff --git a/netstat.c b/netstat.c
new file mode 100644
index 0000000..5768599
--- /dev/null
+++ b/netstat.c
@@ -0,0 +1,154 @@
+/*
+ * Copyright (c) 2008, The Android Open Source Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * 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.
+ *  * Neither the name of Google, Inc. 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 COPYRIGHT HOLDERS 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
+ * COPYRIGHT OWNER 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 <arpa/inet.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+
+typedef union iaddr iaddr;
+typedef union iaddr6 iaddr6;
+
+union iaddr {
+    unsigned u;
+    unsigned char b[4];
+};
+
+union iaddr6 {
+    struct {
+        unsigned a;
+        unsigned b;
+        unsigned c;
+        unsigned d;
+    } u;
+    unsigned char b[16];
+};
+
+static const char *state2str(unsigned state)
+{
+    switch(state){
+    case 0x1: return "ESTABLISHED";
+    case 0x2: return "SYN_SENT";
+    case 0x3: return "SYN_RECV";
+    case 0x4: return "FIN_WAIT1";
+    case 0x5: return "FIN_WAIT2";
+    case 0x6: return "TIME_WAIT";
+    case 0x7: return "CLOSE";
+    case 0x8: return "CLOSE_WAIT";
+    case 0x9: return "LAST_ACK";
+    case 0xA: return "LISTEN";
+    case 0xB: return "CLOSING";
+    default: return "UNKNOWN";
+    }
+}
+
+/* addr + : + port + \0 */
+#define ADDR_LEN INET6_ADDRSTRLEN + 1 + 5 + 1
+
+static void addr2str(int af, const void *addr, unsigned port, char *buf)
+{
+    if (inet_ntop(af, addr, buf, ADDR_LEN) == NULL) {
+        *buf = '\0';
+        return;
+    }
+    size_t len = strlen(buf);
+    if (port) {
+        snprintf(buf+len, ADDR_LEN-len, ":%d", port);
+    } else {
+        strncat(buf+len, ":*", ADDR_LEN-len-1);
+    }
+}
+
+static void ipv4(const char *filename, const char *label) {
+    FILE *fp = fopen(filename, "r");
+    if (fp == NULL) {
+        return;
+    }
+    char buf[BUFSIZ];
+    fgets(buf, BUFSIZ, fp);
+    while (fgets(buf, BUFSIZ, fp)){
+        char lip[ADDR_LEN];
+        char rip[ADDR_LEN];
+        iaddr laddr, raddr;
+        unsigned lport, rport, state, txq, rxq, num;
+        int n = sscanf(buf, " %d: %x:%x %x:%x %x %x:%x",
+                       &num, &laddr.u, &lport, &raddr.u, &rport,
+                       &state, &txq, &rxq);
+        if (n == 8) {
+            addr2str(AF_INET, &laddr, lport, lip);
+            addr2str(AF_INET, &raddr, rport, rip);
+
+            printf("%4s  %6d %6d %-22s %-22s %s\n",
+                   label, txq, rxq, lip, rip,
+                   state2str(state));
+        }
+    }
+    fclose(fp);
+}
+
+static void ipv6(const char *filename, const char *label) {
+    FILE *fp = fopen(filename, "r");
+    if (fp == NULL) {
+        return;
+    }
+    char buf[BUFSIZ];
+    fgets(buf, BUFSIZ, fp);
+    while (fgets(buf, BUFSIZ, fp)){
+        char lip[ADDR_LEN];
+        char rip[ADDR_LEN];
+        iaddr6 laddr6, raddr6;
+        unsigned lport, rport, state, txq, rxq, num;
+        int n = sscanf(buf, " %d: %8x%8x%8x%8x:%x %8x%8x%8x%8x:%x %x %x:%x",
+                       &num, &laddr6.u.a, &laddr6.u.b, &laddr6.u.c, &laddr6.u.d, &lport,
+                       &raddr6.u.a, &raddr6.u.b, &raddr6.u.c, &raddr6.u.d, &rport,
+                       &state, &txq, &rxq);
+        if (n == 14) {
+            addr2str(AF_INET6, &laddr6, lport, lip);
+            addr2str(AF_INET6, &raddr6, rport, rip);
+
+            printf("%4s  %6d %6d %-22s %-22s %s\n",
+                   label, txq, rxq, lip, rip,
+                   state2str(state));
+        }
+    }
+    fclose(fp);
+}
+
+int netstat_main(int argc, char *argv[])
+{
+    printf("Proto Recv-Q Send-Q Local Address          Foreign Address        State\n");
+    ipv4("/proc/net/tcp",  "tcp");
+    ipv4("/proc/net/udp",  "udp");
+    ipv6("/proc/net/tcp6", "tcp6");
+    ipv6("/proc/net/udp6", "udp6");
+    return 0;
+}
diff --git a/newfs_msdos.c b/newfs_msdos.c
new file mode 100644
index 0000000..ff9e844
--- /dev/null
+++ b/newfs_msdos.c
@@ -0,0 +1,1085 @@
+/*
+ * Copyright (c) 1998 Robert Nordier
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``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(S) 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 lint
+static const char rcsid[] =
+  "$FreeBSD: src/sbin/newfs_msdos/newfs_msdos.c,v 1.33 2009/04/11 14:56:29 ed Exp $";
+#endif /* not lint */
+
+#include <sys/param.h>
+
+#ifndef ANDROID
+  #include <sys/fdcio.h>
+  #include <sys/disk.h>
+  #include <sys/disklabel.h>
+  #include <sys/mount.h>
+#else
+  #include <stdarg.h>
+  #include <linux/fs.h>
+  #include <linux/hdreg.h>
+#endif
+
+#include <sys/stat.h>
+#include <sys/time.h>
+
+#include <ctype.h>
+#include <err.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <inttypes.h>
+#include <paths.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <unistd.h>
+
+#define MAXU16	  0xffff	/* maximum unsigned 16-bit quantity */
+#define BPN	  4		/* bits per nibble */
+#define NPB	  2		/* nibbles per byte */
+
+#define DOSMAGIC  0xaa55	/* DOS magic number */
+#define MINBPS	  512		/* minimum bytes per sector */
+#define MAXSPC	  128		/* maximum sectors per cluster */
+#define MAXNFT	  16		/* maximum number of FATs */
+#define DEFBLK	  4096		/* default block size */
+#define DEFBLK16  2048		/* default block size FAT16 */
+#define DEFRDE	  512		/* default root directory entries */
+#define RESFTE	  2		/* reserved FAT entries */
+#define MINCLS12  1		/* minimum FAT12 clusters */
+#define MINCLS16  0x1000	/* minimum FAT16 clusters */
+#define MINCLS32  2		/* minimum FAT32 clusters */
+#define MAXCLS12  0xfed 	/* maximum FAT12 clusters */
+#define MAXCLS16  0xfff5	/* maximum FAT16 clusters */
+#define MAXCLS32  0xffffff5	/* maximum FAT32 clusters */
+
+#define mincls(fat)  ((fat) == 12 ? MINCLS12 :	\
+		      (fat) == 16 ? MINCLS16 :	\
+				    MINCLS32)
+
+#define maxcls(fat)  ((fat) == 12 ? MAXCLS12 :	\
+		      (fat) == 16 ? MAXCLS16 :	\
+				    MAXCLS32)
+
+#define mk1(p, x)				\
+    (p) = (u_int8_t)(x)
+
+#define mk2(p, x)				\
+    (p)[0] = (u_int8_t)(x),			\
+    (p)[1] = (u_int8_t)((x) >> 010)
+
+#define mk4(p, x)				\
+    (p)[0] = (u_int8_t)(x),			\
+    (p)[1] = (u_int8_t)((x) >> 010),		\
+    (p)[2] = (u_int8_t)((x) >> 020),		\
+    (p)[3] = (u_int8_t)((x) >> 030)
+
+#define argto1(arg, lo, msg)  argtou(arg, lo, 0xff, msg)
+#define argto2(arg, lo, msg)  argtou(arg, lo, 0xffff, msg)
+#define argto4(arg, lo, msg)  argtou(arg, lo, 0xffffffff, msg)
+#define argtox(arg, lo, msg)  argtou(arg, lo, UINT_MAX, msg)
+
+struct bs {
+    u_int8_t jmp[3];		/* bootstrap entry point */
+    u_int8_t oem[8];		/* OEM name and version */
+};
+
+struct bsbpb {
+    u_int8_t bps[2];		/* bytes per sector */
+    u_int8_t spc;		/* sectors per cluster */
+    u_int8_t res[2];		/* reserved sectors */
+    u_int8_t nft;		/* number of FATs */
+    u_int8_t rde[2];		/* root directory entries */
+    u_int8_t sec[2];		/* total sectors */
+    u_int8_t mid;		/* media descriptor */
+    u_int8_t spf[2];		/* sectors per FAT */
+    u_int8_t spt[2];		/* sectors per track */
+    u_int8_t hds[2];		/* drive heads */
+    u_int8_t hid[4];		/* hidden sectors */
+    u_int8_t bsec[4];		/* big total sectors */
+};
+
+struct bsxbpb {
+    u_int8_t bspf[4];		/* big sectors per FAT */
+    u_int8_t xflg[2];		/* FAT control flags */
+    u_int8_t vers[2];		/* file system version */
+    u_int8_t rdcl[4];		/* root directory start cluster */
+    u_int8_t infs[2];		/* file system info sector */
+    u_int8_t bkbs[2];		/* backup boot sector */
+    u_int8_t rsvd[12];		/* reserved */
+};
+
+struct bsx {
+    u_int8_t drv;		/* drive number */
+    u_int8_t rsvd;		/* reserved */
+    u_int8_t sig;		/* extended boot signature */
+    u_int8_t volid[4];		/* volume ID number */
+    u_int8_t label[11]; 	/* volume label */
+    u_int8_t type[8];		/* file system type */
+};
+
+struct de {
+    u_int8_t namext[11];	/* name and extension */
+    u_int8_t attr;		/* attributes */
+    u_int8_t rsvd[10];		/* reserved */
+    u_int8_t time[2];		/* creation time */
+    u_int8_t date[2];		/* creation date */
+    u_int8_t clus[2];		/* starting cluster */
+    u_int8_t size[4];		/* size */
+};
+
+struct bpb {
+    u_int bps;			/* bytes per sector */
+    u_int spc;			/* sectors per cluster */
+    u_int res;			/* reserved sectors */
+    u_int nft;			/* number of FATs */
+    u_int rde;			/* root directory entries */
+    u_int sec;			/* total sectors */
+    u_int mid;			/* media descriptor */
+    u_int spf;			/* sectors per FAT */
+    u_int spt;			/* sectors per track */
+    u_int hds;			/* drive heads */
+    u_int hid;			/* hidden sectors */
+    u_int bsec; 		/* big total sectors */
+    u_int bspf; 		/* big sectors per FAT */
+    u_int rdcl; 		/* root directory start cluster */
+    u_int infs; 		/* file system info sector */
+    u_int bkbs; 		/* backup boot sector */
+};
+
+#define BPBGAP 0, 0, 0, 0, 0, 0
+
+static struct {
+    const char *name;
+    struct bpb bpb;
+} const stdfmt[] = {
+    {"160",  {512, 1, 1, 2,  64,  320, 0xfe, 1,  8, 1, BPBGAP}},
+    {"180",  {512, 1, 1, 2,  64,  360, 0xfc, 2,  9, 1, BPBGAP}},
+    {"320",  {512, 2, 1, 2, 112,  640, 0xff, 1,  8, 2, BPBGAP}},
+    {"360",  {512, 2, 1, 2, 112,  720, 0xfd, 2,  9, 2, BPBGAP}},
+    {"640",  {512, 2, 1, 2, 112, 1280, 0xfb, 2,  8, 2, BPBGAP}},    
+    {"720",  {512, 2, 1, 2, 112, 1440, 0xf9, 3,  9, 2, BPBGAP}},
+    {"1200", {512, 1, 1, 2, 224, 2400, 0xf9, 7, 15, 2, BPBGAP}},
+    {"1232", {1024,1, 1, 2, 192, 1232, 0xfe, 2,  8, 2, BPBGAP}},    
+    {"1440", {512, 1, 1, 2, 224, 2880, 0xf0, 9, 18, 2, BPBGAP}},
+    {"2880", {512, 2, 1, 2, 240, 5760, 0xf0, 9, 36, 2, BPBGAP}}
+};
+
+static const u_int8_t bootcode[] = {
+    0xfa,			/* cli		    */
+    0x31, 0xc0, 		/* xor	   ax,ax    */
+    0x8e, 0xd0, 		/* mov	   ss,ax    */
+    0xbc, 0x00, 0x7c,		/* mov	   sp,7c00h */
+    0xfb,			/* sti		    */
+    0x8e, 0xd8, 		/* mov	   ds,ax    */
+    0xe8, 0x00, 0x00,		/* call    $ + 3    */
+    0x5e,			/* pop	   si	    */
+    0x83, 0xc6, 0x19,		/* add	   si,+19h  */
+    0xbb, 0x07, 0x00,		/* mov	   bx,0007h */
+    0xfc,			/* cld		    */
+    0xac,			/* lodsb	    */
+    0x84, 0xc0, 		/* test    al,al    */
+    0x74, 0x06, 		/* jz	   $ + 8    */
+    0xb4, 0x0e, 		/* mov	   ah,0eh   */
+    0xcd, 0x10, 		/* int	   10h	    */
+    0xeb, 0xf5, 		/* jmp	   $ - 9    */
+    0x30, 0xe4, 		/* xor	   ah,ah    */
+    0xcd, 0x16, 		/* int	   16h	    */
+    0xcd, 0x19, 		/* int	   19h	    */
+    0x0d, 0x0a,
+    'N', 'o', 'n', '-', 's', 'y', 's', 't',
+    'e', 'm', ' ', 'd', 'i', 's', 'k',
+    0x0d, 0x0a,
+    'P', 'r', 'e', 's', 's', ' ', 'a', 'n',
+    'y', ' ', 'k', 'e', 'y', ' ', 't', 'o',
+    ' ', 'r', 'e', 'b', 'o', 'o', 't',
+    0x0d, 0x0a,
+    0
+};
+
+static void check_mounted(const char *, mode_t);
+static void getstdfmt(const char *, struct bpb *);
+static void getdiskinfo(int, const char *, const char *, int,
+			struct bpb *);
+static void print_bpb(struct bpb *);
+static u_int ckgeom(const char *, u_int, const char *);
+static u_int argtou(const char *, u_int, u_int, const char *);
+static off_t argtooff(const char *, const char *);
+static int oklabel(const char *);
+static void mklabel(u_int8_t *, const char *);
+static void setstr(u_int8_t *, const char *, size_t);
+static void usage(void);
+
+#ifdef ANDROID
+#define powerof2(x)     ((((x) - 1) & (x)) == 0)
+#define howmany(x, y)   (((x) + ((y) - 1)) / (y))
+#define MAX(x,y) ((x) > (y) ? (x) : (y))
+#define MIN(a, b) ((a) < (b) ? (a) : (b))
+
+#endif
+/*
+ * Construct a FAT12, FAT16, or FAT32 file system.
+ */
+int
+newfs_msdos_main(int argc, char *argv[])
+{
+    static const char opts[] = "@:NB:C:F:I:L:O:S:a:b:c:e:f:h:i:k:m:n:o:r:s:u:";
+    const char *opt_B = NULL, *opt_L = NULL, *opt_O = NULL, *opt_f = NULL;
+    u_int opt_F = 0, opt_I = 0, opt_S = 0, opt_a = 0, opt_b = 0, opt_c = 0;
+    u_int opt_e = 0, opt_h = 0, opt_i = 0, opt_k = 0, opt_m = 0, opt_n = 0;
+    u_int opt_o = 0, opt_r = 0, opt_s = 0, opt_u = 0;
+    int opt_N = 0;
+    int Iflag = 0, mflag = 0, oflag = 0;
+    char buf[MAXPATHLEN];
+    struct stat sb;
+    struct timeval tv;
+    struct bpb bpb;
+    struct tm *tm;
+    struct bs *bs;
+    struct bsbpb *bsbpb;
+    struct bsxbpb *bsxbpb;
+    struct bsx *bsx;
+    struct de *de;
+    u_int8_t *img;
+    const char *fname, *dtype, *bname;
+    ssize_t n;
+    time_t now;
+    u_int fat, bss, rds, cls, dir, lsn, x, x1, x2;
+    int ch, fd, fd1;
+    off_t opt_create = 0, opt_ofs = 0;
+
+    while ((ch = getopt(argc, argv, opts)) != -1)
+	switch (ch) {
+	case '@':
+	    opt_ofs = argtooff(optarg, "offset");
+	    break;
+	case 'N':
+	    opt_N = 1;
+	    break;
+	case 'B':
+	    opt_B = optarg;
+	    break;
+	case 'C':
+	    opt_create = argtooff(optarg, "create size");
+	    break;
+	case 'F':
+	    if (strcmp(optarg, "12") &&
+		strcmp(optarg, "16") &&
+		strcmp(optarg, "32"))
+		errx(1, "%s: bad FAT type", optarg);
+	    opt_F = atoi(optarg);
+	    break;
+	case 'I':
+	    opt_I = argto4(optarg, 0, "volume ID");
+	    Iflag = 1;
+	    break;
+	case 'L':
+	    if (!oklabel(optarg))
+		errx(1, "%s: bad volume label", optarg);
+	    opt_L = optarg;
+	    break;
+	case 'O':
+	    if (strlen(optarg) > 8)
+		errx(1, "%s: bad OEM string", optarg);
+	    opt_O = optarg;
+	    break;
+	case 'S':
+	    opt_S = argto2(optarg, 1, "bytes/sector");
+	    break;
+	case 'a':
+	    opt_a = argto4(optarg, 1, "sectors/FAT");
+	    break;
+	case 'b':
+	    opt_b = argtox(optarg, 1, "block size");
+	    opt_c = 0;
+	    break;
+	case 'c':
+	    opt_c = argto1(optarg, 1, "sectors/cluster");
+	    opt_b = 0;
+	    break;
+	case 'e':
+	    opt_e = argto2(optarg, 1, "directory entries");
+	    break;
+	case 'f':
+	    opt_f = optarg;
+	    break;
+	case 'h':
+	    opt_h = argto2(optarg, 1, "drive heads");
+	    break;
+	case 'i':
+	    opt_i = argto2(optarg, 1, "info sector");
+	    break;
+	case 'k':
+	    opt_k = argto2(optarg, 1, "backup sector");
+	    break;
+	case 'm':
+	    opt_m = argto1(optarg, 0, "media descriptor");
+	    mflag = 1;
+	    break;
+	case 'n':
+	    opt_n = argto1(optarg, 1, "number of FATs");
+	    break;
+	case 'o':
+	    opt_o = argto4(optarg, 0, "hidden sectors");
+	    oflag = 1;
+	    break;
+	case 'r':
+	    opt_r = argto2(optarg, 1, "reserved sectors");
+	    break;
+	case 's':
+	    opt_s = argto4(optarg, 1, "file system size");
+	    break;
+	case 'u':
+	    opt_u = argto2(optarg, 1, "sectors/track");
+	    break;
+	default:
+	    usage();
+	}
+    argc -= optind;
+    argv += optind;
+    if (argc < 1 || argc > 2)
+	usage();
+    fname = *argv++;
+    if (!opt_create && !strchr(fname, '/')) {
+	snprintf(buf, sizeof(buf), "%s%s", _PATH_DEV, fname);
+	if (!(fname = strdup(buf)))
+	    err(1, NULL);
+    }
+    dtype = *argv;
+    if (opt_create) {
+	if (opt_N)
+	    errx(1, "create (-C) is incompatible with -N");
+	fd = open(fname, O_RDWR | O_CREAT | O_TRUNC, 0644);
+	if (fd == -1)
+	    errx(1, "failed to create %s", fname);
+	if (ftruncate(fd, opt_create))
+	    errx(1, "failed to initialize %jd bytes", (intmax_t)opt_create);
+    } else if ((fd = open(fname, opt_N ? O_RDONLY : O_RDWR)) == -1)
+	err(1, "%s", fname);
+    if (fstat(fd, &sb))
+	err(1, "%s", fname);
+    if (opt_create) {
+	if (!S_ISREG(sb.st_mode))
+	    warnx("warning, %s is not a regular file", fname);
+    } else {
+	if (!S_ISCHR(sb.st_mode))
+	    warnx("warning, %s is not a character device", fname);
+    }
+    if (!opt_N)
+	check_mounted(fname, sb.st_mode);
+    if (opt_ofs && opt_ofs != lseek(fd, opt_ofs, SEEK_SET))
+	errx(1, "cannot seek to %jd", (intmax_t)opt_ofs);
+    memset(&bpb, 0, sizeof(bpb));
+    if (opt_f) {
+	getstdfmt(opt_f, &bpb);
+	bpb.bsec = bpb.sec;
+	bpb.sec = 0;
+	bpb.bspf = bpb.spf;
+	bpb.spf = 0;
+    }
+    if (opt_h)
+	bpb.hds = opt_h;
+    if (opt_u)
+	bpb.spt = opt_u;
+    if (opt_S)
+	bpb.bps = opt_S;
+    if (opt_s)
+	bpb.bsec = opt_s;
+    if (oflag)
+	bpb.hid = opt_o;
+    if (!(opt_f || (opt_h && opt_u && opt_S && opt_s && oflag))) {
+	off_t delta;
+	getdiskinfo(fd, fname, dtype, oflag, &bpb);
+        if (opt_s) {
+            bpb.bsec = opt_s;
+        }
+	bpb.bsec -= (opt_ofs / bpb.bps);
+	delta = bpb.bsec % bpb.spt;
+	if (delta != 0) {
+	    warnx("trim %d sectors from %d to adjust to a multiple of %d",
+		(int)delta, bpb.bsec, bpb.spt);
+	    bpb.bsec -= delta;
+	}
+	if (bpb.spc == 0) {	/* set defaults */
+	    if (bpb.bsec <= 6000)	/* about 3MB -> 512 bytes */
+		bpb.spc = 1;
+	    else if (bpb.bsec <= (1<<17)) /* 64M -> 4k */
+		bpb.spc = 8;
+	    else if (bpb.bsec <= (1<<19)) /* 256M -> 8k */
+		bpb.spc = 16;
+	    else if (bpb.bsec <= (1<<21)) /* 1G -> 16k */
+		bpb.spc = 32;
+	    else
+		bpb.spc = 64;		/* otherwise 32k */
+	}
+    }
+    if (!powerof2(bpb.bps))
+	errx(1, "bytes/sector (%u) is not a power of 2", bpb.bps);
+    if (bpb.bps < MINBPS)
+	errx(1, "bytes/sector (%u) is too small; minimum is %u",
+	     bpb.bps, MINBPS);
+    if (!(fat = opt_F)) {
+	if (opt_f)
+	    fat = 12;
+	else if (!opt_e && (opt_i || opt_k))
+	    fat = 32;
+    }
+    if ((fat == 32 && opt_e) || (fat != 32 && (opt_i || opt_k)))
+	errx(1, "-%c is not a legal FAT%s option",
+	     fat == 32 ? 'e' : opt_i ? 'i' : 'k',
+	     fat == 32 ? "32" : "12/16");
+    if (opt_f && fat == 32)
+	bpb.rde = 0;
+    if (opt_b) {
+	if (!powerof2(opt_b))
+	    errx(1, "block size (%u) is not a power of 2", opt_b);
+	if (opt_b < bpb.bps)
+	    errx(1, "block size (%u) is too small; minimum is %u",
+		 opt_b, bpb.bps);
+	if (opt_b > bpb.bps * MAXSPC)
+	    errx(1, "block size (%u) is too large; maximum is %u",
+		 opt_b, bpb.bps * MAXSPC);
+	bpb.spc = opt_b / bpb.bps;
+    }
+    if (opt_c) {
+	if (!powerof2(opt_c))
+	    errx(1, "sectors/cluster (%u) is not a power of 2", opt_c);
+	bpb.spc = opt_c;
+    }
+    if (opt_r)
+	bpb.res = opt_r;
+    if (opt_n) {
+	if (opt_n > MAXNFT)
+	    errx(1, "number of FATs (%u) is too large; maximum is %u",
+		 opt_n, MAXNFT);
+	bpb.nft = opt_n;
+    }
+    if (opt_e)
+	bpb.rde = opt_e;
+    if (mflag) {
+	if (opt_m < 0xf0)
+	    errx(1, "illegal media descriptor (%#x)", opt_m);
+	bpb.mid = opt_m;
+    }
+    if (opt_a)
+	bpb.bspf = opt_a;
+    if (opt_i)
+	bpb.infs = opt_i;
+    if (opt_k)
+	bpb.bkbs = opt_k;
+    bss = 1;
+    bname = NULL;
+    fd1 = -1;
+    if (opt_B) {
+	bname = opt_B;
+	if (!strchr(bname, '/')) {
+	    snprintf(buf, sizeof(buf), "/boot/%s", bname);
+	    if (!(bname = strdup(buf)))
+		err(1, NULL);
+	}
+	if ((fd1 = open(bname, O_RDONLY)) == -1 || fstat(fd1, &sb))
+	    err(1, "%s", bname);
+	if (!S_ISREG(sb.st_mode) || sb.st_size % bpb.bps ||
+	    sb.st_size < bpb.bps || sb.st_size > bpb.bps * MAXU16)
+	    errx(1, "%s: inappropriate file type or format", bname);
+	bss = sb.st_size / bpb.bps;
+    }
+    if (!bpb.nft)
+	bpb.nft = 2;
+    if (!fat) {
+	if (bpb.bsec < (bpb.res ? bpb.res : bss) +
+	    howmany((RESFTE + (bpb.spc ? MINCLS16 : MAXCLS12 + 1)) *
+		    ((bpb.spc ? 16 : 12) / BPN), bpb.bps * NPB) *
+	    bpb.nft +
+	    howmany(bpb.rde ? bpb.rde : DEFRDE,
+		    bpb.bps / sizeof(struct de)) +
+	    (bpb.spc ? MINCLS16 : MAXCLS12 + 1) *
+	    (bpb.spc ? bpb.spc : howmany(DEFBLK, bpb.bps)))
+	    fat = 12;
+	else if (bpb.rde || bpb.bsec <
+		 (bpb.res ? bpb.res : bss) +
+		 howmany((RESFTE + MAXCLS16) * 2, bpb.bps) * bpb.nft +
+		 howmany(DEFRDE, bpb.bps / sizeof(struct de)) +
+		 (MAXCLS16 + 1) *
+		 (bpb.spc ? bpb.spc : howmany(8192, bpb.bps)))
+	    fat = 16;
+	else
+	    fat = 32;
+    }
+    x = bss;
+    if (fat == 32) {
+	if (!bpb.infs) {
+	    if (x == MAXU16 || x == bpb.bkbs)
+		errx(1, "no room for info sector");
+	    bpb.infs = x;
+	}
+	if (bpb.infs != MAXU16 && x <= bpb.infs)
+	    x = bpb.infs + 1;
+	if (!bpb.bkbs) {
+	    if (x == MAXU16)
+		errx(1, "no room for backup sector");
+	    bpb.bkbs = x;
+	} else if (bpb.bkbs != MAXU16 && bpb.bkbs == bpb.infs)
+	    errx(1, "backup sector would overwrite info sector");
+	if (bpb.bkbs != MAXU16 && x <= bpb.bkbs)
+	    x = bpb.bkbs + 1;
+    }
+    if (!bpb.res)
+	bpb.res = fat == 32 ? MAX(x, MAX(16384 / bpb.bps, 4)) : x;
+    else if (bpb.res < x)
+	errx(1, "too few reserved sectors");
+    if (fat != 32 && !bpb.rde)
+	bpb.rde = DEFRDE;
+    rds = howmany(bpb.rde, bpb.bps / sizeof(struct de));
+    if (!bpb.spc)
+	for (bpb.spc = howmany(fat == 16 ? DEFBLK16 : DEFBLK, bpb.bps);
+	     bpb.spc < MAXSPC &&
+	     bpb.res +
+	     howmany((RESFTE + maxcls(fat)) * (fat / BPN),
+		     bpb.bps * NPB) * bpb.nft +
+	     rds +
+	     (u_int64_t)(maxcls(fat) + 1) * bpb.spc <= bpb.bsec;
+	     bpb.spc <<= 1);
+    if (fat != 32 && bpb.bspf > MAXU16)
+	errx(1, "too many sectors/FAT for FAT12/16");
+    x1 = bpb.res + rds;
+    x = bpb.bspf ? bpb.bspf : 1;
+    if (x1 + (u_int64_t)x * bpb.nft > bpb.bsec)
+	errx(1, "meta data exceeds file system size");
+    x1 += x * bpb.nft;
+    x = (u_int64_t)(bpb.bsec - x1) * bpb.bps * NPB /
+	(bpb.spc * bpb.bps * NPB + fat / BPN * bpb.nft);
+    x2 = howmany((RESFTE + MIN(x, maxcls(fat))) * (fat / BPN),
+		 bpb.bps * NPB);
+    if (!bpb.bspf) {
+	bpb.bspf = x2;
+	x1 += (bpb.bspf - 1) * bpb.nft;
+    }
+    cls = (bpb.bsec - x1) / bpb.spc;
+    x = (u_int64_t)bpb.bspf * bpb.bps * NPB / (fat / BPN) - RESFTE;
+    if (cls > x)
+	cls = x;
+    if (bpb.bspf < x2)
+	warnx("warning: sectors/FAT limits file system to %u clusters",
+	      cls);
+    if (cls < mincls(fat))
+	errx(1, "%u clusters too few clusters for FAT%u, need %u", cls, fat,
+	    mincls(fat));
+    if (cls > maxcls(fat)) {
+	cls = maxcls(fat);
+	bpb.bsec = x1 + (cls + 1) * bpb.spc - 1;
+	warnx("warning: FAT type limits file system to %u sectors",
+	      bpb.bsec);
+    }
+    printf("%s: %u sector%s in %u FAT%u cluster%s "
+	   "(%u bytes/cluster)\n", fname, cls * bpb.spc,
+	   cls * bpb.spc == 1 ? "" : "s", cls, fat,
+	   cls == 1 ? "" : "s", bpb.bps * bpb.spc);
+    if (!bpb.mid)
+	bpb.mid = !bpb.hid ? 0xf0 : 0xf8;
+    if (fat == 32)
+	bpb.rdcl = RESFTE;
+    if (bpb.hid + bpb.bsec <= MAXU16) {
+	bpb.sec = bpb.bsec;
+	bpb.bsec = 0;
+    }
+    if (fat != 32) {
+	bpb.spf = bpb.bspf;
+	bpb.bspf = 0;
+    }
+    print_bpb(&bpb);
+    if (!opt_N) {
+	gettimeofday(&tv, NULL);
+	now = tv.tv_sec;
+	tm = localtime(&now);
+	if (!(img = malloc(bpb.bps)))
+	    err(1, NULL);
+	dir = bpb.res + (bpb.spf ? bpb.spf : bpb.bspf) * bpb.nft;
+	for (lsn = 0; lsn < dir + (fat == 32 ? bpb.spc : rds); lsn++) {
+	    x = lsn;
+	    if (opt_B &&
+		fat == 32 && bpb.bkbs != MAXU16 &&
+		bss <= bpb.bkbs && x >= bpb.bkbs) {
+		x -= bpb.bkbs;
+		if (!x && lseek(fd1, opt_ofs, SEEK_SET))
+		    err(1, "%s", bname);
+	    }
+	    if (opt_B && x < bss) {
+		if ((n = read(fd1, img, bpb.bps)) == -1)
+		    err(1, "%s", bname);
+		if ((unsigned)n != bpb.bps)
+		    errx(1, "%s: can't read sector %u", bname, x);
+	    } else
+		memset(img, 0, bpb.bps);
+	    if (!lsn ||
+	      (fat == 32 && bpb.bkbs != MAXU16 && lsn == bpb.bkbs)) {
+		x1 = sizeof(struct bs);
+		bsbpb = (struct bsbpb *)(img + x1);
+		mk2(bsbpb->bps, bpb.bps);
+		mk1(bsbpb->spc, bpb.spc);
+		mk2(bsbpb->res, bpb.res);
+		mk1(bsbpb->nft, bpb.nft);
+		mk2(bsbpb->rde, bpb.rde);
+		mk2(bsbpb->sec, bpb.sec);
+		mk1(bsbpb->mid, bpb.mid);
+		mk2(bsbpb->spf, bpb.spf);
+		mk2(bsbpb->spt, bpb.spt);
+		mk2(bsbpb->hds, bpb.hds);
+		mk4(bsbpb->hid, bpb.hid);
+		mk4(bsbpb->bsec, bpb.bsec);
+		x1 += sizeof(struct bsbpb);
+		if (fat == 32) {
+		    bsxbpb = (struct bsxbpb *)(img + x1);
+		    mk4(bsxbpb->bspf, bpb.bspf);
+		    mk2(bsxbpb->xflg, 0);
+		    mk2(bsxbpb->vers, 0);
+		    mk4(bsxbpb->rdcl, bpb.rdcl);
+		    mk2(bsxbpb->infs, bpb.infs);
+		    mk2(bsxbpb->bkbs, bpb.bkbs);
+		    x1 += sizeof(struct bsxbpb);
+		}
+		bsx = (struct bsx *)(img + x1);
+		mk1(bsx->sig, 0x29);
+		if (Iflag)
+		    x = opt_I;
+		else
+		    x = (((u_int)(1 + tm->tm_mon) << 8 |
+			  (u_int)tm->tm_mday) +
+			 ((u_int)tm->tm_sec << 8 |
+			  (u_int)(tv.tv_usec / 10))) << 16 |
+			((u_int)(1900 + tm->tm_year) +
+			 ((u_int)tm->tm_hour << 8 |
+			  (u_int)tm->tm_min));
+		mk4(bsx->volid, x);
+		mklabel(bsx->label, opt_L ? opt_L : "NO NAME");
+		sprintf(buf, "FAT%u", fat);
+		setstr(bsx->type, buf, sizeof(bsx->type));
+		if (!opt_B) {
+		    x1 += sizeof(struct bsx);
+		    bs = (struct bs *)img;
+		    mk1(bs->jmp[0], 0xeb);
+		    mk1(bs->jmp[1], x1 - 2);
+		    mk1(bs->jmp[2], 0x90);
+		    setstr(bs->oem, opt_O ? opt_O : "BSD  4.4",
+			   sizeof(bs->oem));
+		    memcpy(img + x1, bootcode, sizeof(bootcode));
+		    mk2(img + MINBPS - 2, DOSMAGIC);
+		}
+	    } else if (fat == 32 && bpb.infs != MAXU16 &&
+		       (lsn == bpb.infs ||
+			(bpb.bkbs != MAXU16 &&
+			 lsn == bpb.bkbs + bpb.infs))) {
+		mk4(img, 0x41615252);
+		mk4(img + MINBPS - 28, 0x61417272);
+		mk4(img + MINBPS - 24, 0xffffffff);
+		mk4(img + MINBPS - 20, bpb.rdcl);
+		mk2(img + MINBPS - 2, DOSMAGIC);
+	    } else if (lsn >= bpb.res && lsn < dir &&
+		       !((lsn - bpb.res) %
+			 (bpb.spf ? bpb.spf : bpb.bspf))) {
+		mk1(img[0], bpb.mid);
+		for (x = 1; x < fat * (fat == 32 ? 3 : 2) / 8; x++)
+		    mk1(img[x], fat == 32 && x % 4 == 3 ? 0x0f : 0xff);
+	    } else if (lsn == dir && opt_L) {
+		de = (struct de *)img;
+		mklabel(de->namext, opt_L);
+		mk1(de->attr, 050);
+		x = (u_int)tm->tm_hour << 11 |
+		    (u_int)tm->tm_min << 5 |
+		    (u_int)tm->tm_sec >> 1;
+		mk2(de->time, x);
+		x = (u_int)(tm->tm_year - 80) << 9 |
+		    (u_int)(tm->tm_mon + 1) << 5 |
+		    (u_int)tm->tm_mday;
+		mk2(de->date, x);
+	    }
+	    if ((n = write(fd, img, bpb.bps)) == -1)
+		err(1, "%s", fname);
+	    if ((unsigned)n != bpb.bps) {
+		errx(1, "%s: can't write sector %u", fname, lsn);
+                exit(1);
+            }
+	}
+    }
+    return 0;
+}
+
+/*
+ * Exit with error if file system is mounted.
+ */
+static void
+check_mounted(const char *fname, mode_t mode)
+{
+    struct statfs *mp;
+    const char *s1, *s2;
+    size_t len;
+    int n, r;
+
+#ifdef ANDROID
+    warnx("Skipping mount checks");
+#else
+    if (!(n = getmntinfo(&mp, MNT_NOWAIT)))
+	err(1, "getmntinfo");
+    len = strlen(_PATH_DEV);
+    s1 = fname;
+    if (!strncmp(s1, _PATH_DEV, len))
+	s1 += len;
+    r = S_ISCHR(mode) && s1 != fname && *s1 == 'r';
+    for (; n--; mp++) {
+	s2 = mp->f_mntfromname;
+	if (!strncmp(s2, _PATH_DEV, len))
+	    s2 += len;
+	if ((r && s2 != mp->f_mntfromname && !strcmp(s1 + 1, s2)) ||
+	    !strcmp(s1, s2))
+	    errx(1, "%s is mounted on %s", fname, mp->f_mntonname);
+    }
+#endif
+}
+
+/*
+ * Get a standard format.
+ */
+static void
+getstdfmt(const char *fmt, struct bpb *bpb)
+{
+    u_int x, i;
+
+    x = sizeof(stdfmt) / sizeof(stdfmt[0]);
+    for (i = 0; i < x && strcmp(fmt, stdfmt[i].name); i++);
+    if (i == x)
+	errx(1, "%s: unknown standard format", fmt);
+    *bpb = stdfmt[i].bpb;
+}
+
+/*
+ * Get disk slice, partition, and geometry information.
+ */
+
+#ifdef ANDROID
+static void
+getdiskinfo(int fd, const char *fname, const char *dtype, __unused int oflag,
+	    struct bpb *bpb)
+{
+    struct hd_geometry geom;
+
+    if (ioctl(fd, BLKSSZGET, &bpb->bps)) {
+        fprintf(stderr, "Error getting bytes / sector (%s)\n", strerror(errno));
+        exit(1);
+    }
+
+    ckgeom(fname, bpb->bps, "bytes/sector");
+
+    if (ioctl(fd, BLKGETSIZE, &bpb->bsec)) {
+        fprintf(stderr, "Error getting blocksize (%s)\n", strerror(errno));
+        exit(1);
+    }
+
+    if (ioctl(fd, HDIO_GETGEO, &geom)) {
+        fprintf(stderr, "Error getting gemoetry (%s) - trying sane values\n", strerror(errno));
+        geom.heads = 64;
+        geom.sectors = 63;
+    }
+
+    if (!geom.heads) {
+        printf("Bogus heads from kernel - setting sane value\n");
+        geom.heads = 64;
+    }
+
+    if (!geom.sectors) {
+        printf("Bogus sectors from kernel - setting sane value\n");
+        geom.sectors = 63;
+    }
+
+    bpb->spt = geom.sectors;
+    ckgeom(fname, bpb->spt, "sectors/track");
+
+    bpb->hds = geom.heads;
+    ckgeom(fname, bpb->hds, "drive heads");
+}
+
+#else
+
+static void
+getdiskinfo(int fd, const char *fname, const char *dtype, __unused int oflag,
+	    struct bpb *bpb)
+{
+    struct disklabel *lp, dlp;
+    struct fd_type type;
+    off_t ms, hs = 0;
+
+    lp = NULL;
+
+    /* If the user specified a disk type, try to use that */
+    if (dtype != NULL) {
+	lp = getdiskbyname(dtype);
+    }
+
+    /* Maybe it's a floppy drive */
+    if (lp == NULL) {
+	if (ioctl(fd, DIOCGMEDIASIZE, &ms) == -1) {
+	    struct stat st;
+
+	    if (fstat(fd, &st))
+		err(1, "Cannot get disk size");
+	    /* create a fake geometry for a file image */
+	    ms = st.st_size;
+	    dlp.d_secsize = 512;
+	    dlp.d_nsectors = 63;
+	    dlp.d_ntracks = 255;
+	    dlp.d_secperunit = ms / dlp.d_secsize;
+	    lp = &dlp;
+	} else if (ioctl(fd, FD_GTYPE, &type) != -1) {
+	    dlp.d_secsize = 128 << type.secsize;
+	    dlp.d_nsectors = type.sectrac;
+	    dlp.d_ntracks = type.heads;
+	    dlp.d_secperunit = ms / dlp.d_secsize;
+	    lp = &dlp;
+	}
+    }
+
+    /* Maybe it's a fixed drive */
+    if (lp == NULL) {
+	if (ioctl(fd, DIOCGDINFO, &dlp) == -1) {
+	    if (bpb->bps == 0 && ioctl(fd, DIOCGSECTORSIZE, &dlp.d_secsize) == -1)
+		errx(1, "Cannot get sector size, %s", strerror(errno));
+
+	    /* XXX Should we use bpb->bps if it's set? */
+	    dlp.d_secperunit = ms / dlp.d_secsize;
+
+	    if (bpb->spt == 0 && ioctl(fd, DIOCGFWSECTORS, &dlp.d_nsectors) == -1) {
+		warnx("Cannot get number of sectors per track, %s", strerror(errno));
+		dlp.d_nsectors = 63;
+	    }
+	    if (bpb->hds == 0 && ioctl(fd, DIOCGFWHEADS, &dlp.d_ntracks) == -1) {
+		warnx("Cannot get number of heads, %s", strerror(errno));
+		if (dlp.d_secperunit <= 63*1*1024)
+		    dlp.d_ntracks = 1;
+		else if (dlp.d_secperunit <= 63*16*1024)
+		    dlp.d_ntracks = 16;
+		else
+		    dlp.d_ntracks = 255;
+	    }
+	}
+
+	hs = (ms / dlp.d_secsize) - dlp.d_secperunit;
+	lp = &dlp;
+    }
+
+    if (bpb->bps == 0)
+	bpb->bps = ckgeom(fname, lp->d_secsize, "bytes/sector");
+    if (bpb->spt == 0)
+	bpb->spt = ckgeom(fname, lp->d_nsectors, "sectors/track");
+    if (bpb->hds == 0)
+	bpb->hds = ckgeom(fname, lp->d_ntracks, "drive heads");
+    if (bpb->bsec == 0)
+	bpb->bsec = lp->d_secperunit;
+    if (bpb->hid == 0)
+	bpb->hid = hs;
+}
+#endif
+
+/*
+ * Print out BPB values.
+ */
+static void
+print_bpb(struct bpb *bpb)
+{
+    printf("bps=%u spc=%u res=%u nft=%u", bpb->bps, bpb->spc, bpb->res,
+	   bpb->nft);
+    if (bpb->rde)
+	printf(" rde=%u", bpb->rde);
+    if (bpb->sec)
+	printf(" sec=%u", bpb->sec);
+    printf(" mid=%#x", bpb->mid);
+    if (bpb->spf)
+	printf(" spf=%u", bpb->spf);
+    printf(" spt=%u hds=%u hid=%u", bpb->spt, bpb->hds, bpb->hid);
+    if (bpb->bsec)
+	printf(" bsec=%u", bpb->bsec);
+    if (!bpb->spf) {
+	printf(" bspf=%u rdcl=%u", bpb->bspf, bpb->rdcl);
+	printf(" infs=");
+	printf(bpb->infs == MAXU16 ? "%#x" : "%u", bpb->infs);
+	printf(" bkbs=");
+	printf(bpb->bkbs == MAXU16 ? "%#x" : "%u", bpb->bkbs);
+    }
+    printf("\n");
+}
+
+/*
+ * Check a disk geometry value.
+ */
+static u_int
+ckgeom(const char *fname, u_int val, const char *msg)
+{
+    if (!val)
+	errx(1, "%s: no default %s", fname, msg);
+    if (val > MAXU16)
+	errx(1, "%s: illegal %s %d", fname, msg, val);
+    return val;
+}
+
+/*
+ * Convert and check a numeric option argument.
+ */
+static u_int
+argtou(const char *arg, u_int lo, u_int hi, const char *msg)
+{
+    char *s;
+    u_long x;
+
+    errno = 0;
+    x = strtoul(arg, &s, 0);
+    if (errno || !*arg || *s || x < lo || x > hi)
+	errx(1, "%s: bad %s", arg, msg);
+    return x;
+}
+
+/*
+ * Same for off_t, with optional skmgpP suffix
+ */
+static off_t
+argtooff(const char *arg, const char *msg)
+{
+    char *s;
+    off_t x;
+
+    x = strtoll(arg, &s, 0);
+    /* allow at most one extra char */
+    if (errno || x < 0 || (s[0] && s[1]) )
+	errx(1, "%s: bad %s", arg, msg);
+    if (*s) {	/* the extra char is the multiplier */
+	switch (*s) {
+	default:
+	    errx(1, "%s: bad %s", arg, msg);
+	    /* notreached */
+	
+	case 's':	/* sector */
+	case 'S':
+	    x <<= 9;	/* times 512 */
+	    break;
+
+	case 'k':	/* kilobyte */
+	case 'K':
+	    x <<= 10;	/* times 1024 */
+	    break;
+
+	case 'm':	/* megabyte */
+	case 'M':
+	    x <<= 20;	/* times 1024*1024 */
+	    break;
+
+	case 'g':	/* gigabyte */
+	case 'G':
+	    x <<= 30;	/* times 1024*1024*1024 */
+	    break;
+
+	case 'p':	/* partition start */
+	case 'P':	/* partition start */
+	case 'l':	/* partition length */
+	case 'L':	/* partition length */
+	    errx(1, "%s: not supported yet %s", arg, msg);
+	    /* notreached */
+	}
+    }
+    return x;
+}
+
+/*
+ * Check a volume label.
+ */
+static int
+oklabel(const char *src)
+{
+    int c, i;
+
+    for (i = 0; i <= 11; i++) {
+	c = (u_char)*src++;
+	if (c < ' ' + !i || strchr("\"*+,./:;<=>?[\\]|", c))
+	    break;
+    }
+    return i && !c;
+}
+
+/*
+ * Make a volume label.
+ */
+static void
+mklabel(u_int8_t *dest, const char *src)
+{
+    int c, i;
+
+    for (i = 0; i < 11; i++) {
+	c = *src ? toupper(*src++) : ' ';
+	*dest++ = !i && c == '\xe5' ? 5 : c;
+    }
+}
+
+/*
+ * Copy string, padding with spaces.
+ */
+static void
+setstr(u_int8_t *dest, const char *src, size_t len)
+{
+    while (len--)
+	*dest++ = *src ? *src++ : ' ';
+}
+
+/*
+ * Print usage message.
+ */
+static void
+usage(void)
+{
+	fprintf(stderr,
+	    "usage: newfs_msdos [ -options ] special [disktype]\n"
+	    "where the options are:\n"
+	    "\t-@ create file system at specified offset\n"                         
+	    "\t-B get bootstrap from file\n"
+	    "\t-C create image file with specified size\n"
+	    "\t-F FAT type (12, 16, or 32)\n"
+	    "\t-I volume ID\n"
+	    "\t-L volume label\n"
+	    "\t-N don't create file system: just print out parameters\n"
+	    "\t-O OEM string\n"
+	    "\t-S bytes/sector\n"
+	    "\t-a sectors/FAT\n"
+	    "\t-b block size\n"
+	    "\t-c sectors/cluster\n"
+	    "\t-e root directory entries\n"
+	    "\t-f standard format\n"
+	    "\t-h drive heads\n"
+	    "\t-i file system info sector\n"
+	    "\t-k backup boot sector\n"
+	    "\t-m media descriptor\n"
+	    "\t-n number of FATs\n"
+	    "\t-o hidden sectors\n"
+	    "\t-r reserved sectors\n"
+	    "\t-s file system size (sectors)\n"
+	    "\t-u sectors/track\n");
+	exit(1);
+}
diff --git a/notify.c b/notify.c
new file mode 100644
index 0000000..b1761d2
--- /dev/null
+++ b/notify.c
@@ -0,0 +1,144 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdint.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include <sys/inotify.h>
+#include <errno.h>
+
+int notify_main(int argc, char *argv[])
+{
+    int c;
+    int nfd, ffd;
+    int res;
+	char event_buf[512];
+    struct inotify_event *event;
+	int event_mask = IN_ALL_EVENTS;
+    int event_count = 1;
+	int print_files = 0;
+	int verbose = 2;
+	int width = 80;
+	char **file_names;
+	int file_count;
+	int id_offset = 0;
+	int i;
+	char *buf;
+
+    do {
+        c = getopt(argc, argv, "m:c:pv:w:");
+        if (c == EOF)
+            break;
+        switch (c) {
+        case 'm':
+            event_mask = strtol(optarg, NULL, 0);
+            break;
+        case 'c':
+            event_count = atoi(optarg);
+            break;
+		case 'p':
+			print_files = 1;
+			break;
+        case 'v':
+            verbose = atoi(optarg);
+            break;
+        case 'w':
+            width = atoi(optarg);
+            break;
+        case '?':
+            fprintf(stderr, "%s: invalid option -%c\n",
+                argv[0], optopt);
+            exit(1);
+        }
+    } while (1);
+
+    if (argc <= optind) {
+        fprintf(stderr, "Usage: %s [-m eventmask] [-c count] [-p] [-v verbosity] path [path ...]\n", argv[0]);
+		return 1;
+    }
+
+    nfd = inotify_init();
+    if(nfd < 0) {
+        fprintf(stderr, "inotify_init failed, %s\n", strerror(errno));
+        return 1;
+    }
+	file_names = argv + optind;
+	file_count = argc - optind;
+	for(i = 0; i < file_count; i++) {
+		res = inotify_add_watch(nfd, file_names[i], event_mask);
+		if(res < 0) {
+	        fprintf(stderr, "inotify_add_watch failed for %s, %s\n", file_names[i], strerror(errno));
+			return 1;
+		}
+		if(i == 0)
+			id_offset = -res;
+		if(res + id_offset != i) {
+			fprintf(stderr, "%s got unexpected id %d instead of %d\n", file_names[i], res, i);
+			return 1;
+		}
+	}
+
+	buf = malloc(width + 2);
+    
+    while(1) {
+		int event_pos = 0;
+        res = read(nfd, event_buf, sizeof(event_buf));
+        if(res < (int)sizeof(*event)) {
+			if(errno == EINTR)
+				continue;
+            fprintf(stderr, "could not get event, %s\n", strerror(errno));
+            return 1;
+        }
+		//printf("got %d bytes of event information\n", res);
+		while(res >= (int)sizeof(*event)) {
+			int event_size;
+			event = (struct inotify_event *)(event_buf + event_pos);
+			if(verbose >= 2)
+		        printf("%s: %08x %08x \"%s\"\n", file_names[event->wd + id_offset], event->mask, event->cookie, event->len ? event->name : "");
+			else if(verbose >= 2)
+		        printf("%s: %08x \"%s\"\n", file_names[event->wd + id_offset], event->mask, event->len ? event->name : "");
+			else if(verbose >= 1)
+		        printf("%d: %08x \"%s\"\n", event->wd, event->mask, event->len ? event->name : "");
+			if(print_files && (event->mask & IN_MODIFY)) {
+				char filename[512];
+				ssize_t read_len;
+				char *display_name;
+				int buflen;
+				strcpy(filename, file_names[event->wd + id_offset]);
+				if(event->len) {
+					strcat(filename, "/");
+					strcat(filename, event->name);
+				}
+				ffd = open(filename, O_RDONLY);
+				display_name = (verbose >= 2 || event->len == 0) ? filename : event->name;
+				buflen = width - strlen(display_name);
+				read_len = read(ffd, buf, buflen);
+				if(read_len > 0) {
+					if(read_len < buflen && buf[read_len-1] != '\n') {
+						buf[read_len] = '\n';
+						read_len++;
+					}
+					if(read_len == buflen) {
+						buf[--read_len] = '\0';
+						buf[--read_len] = '\n';
+						buf[--read_len] = '.';
+						buf[--read_len] = '.';
+						buf[--read_len] = '.';
+					}
+					else {
+						buf[read_len] = '\0';
+					}
+					printf("%s: %s", display_name, buf);
+				}
+				close(ffd);
+			}
+	        if(event_count && --event_count == 0)
+	            return 0;
+			event_size = sizeof(*event) + event->len;
+			res -= event_size;
+			event_pos += event_size;
+		}
+    }
+
+    return 0;
+}
diff --git a/powerd.c b/powerd.c
new file mode 100644
index 0000000..1f29a8b
--- /dev/null
+++ b/powerd.c
@@ -0,0 +1,441 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <string.h>
+#include <errno.h>
+#include <time.h>
+#include <sys/select.h>
+#include <sys/inotify.h>
+
+#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
+
+//#include <linux/input.h> // this does not compile
+
+// from <linux/input.h>
+
+struct input_event {
+	struct timeval time;
+	__u16 type;
+	__u16 code;
+	__s32 value;
+};
+
+#define EVIOCGVERSION		_IOR('E', 0x01, int)			/* get driver version */
+#define EVIOCGID		_IOR('E', 0x02, struct input_id)	/* get device ID */
+#define EVIOCGKEYCODE		_IOR('E', 0x04, int[2])			/* get keycode */
+#define EVIOCSKEYCODE		_IOW('E', 0x04, int[2])			/* set keycode */
+
+#define EVIOCGNAME(len)		_IOC(_IOC_READ, 'E', 0x06, len)		/* get device name */
+#define EVIOCGPHYS(len)		_IOC(_IOC_READ, 'E', 0x07, len)		/* get physical location */
+#define EVIOCGUNIQ(len)		_IOC(_IOC_READ, 'E', 0x08, len)		/* get unique identifier */
+
+#define EVIOCGKEY(len)		_IOC(_IOC_READ, 'E', 0x18, len)		/* get global keystate */
+#define EVIOCGLED(len)		_IOC(_IOC_READ, 'E', 0x19, len)		/* get all LEDs */
+#define EVIOCGSND(len)		_IOC(_IOC_READ, 'E', 0x1a, len)		/* get all sounds status */
+#define EVIOCGSW(len)		_IOC(_IOC_READ, 'E', 0x1b, len)		/* get all switch states */
+
+#define EVIOCGBIT(ev,len)	_IOC(_IOC_READ, 'E', 0x20 + ev, len)	/* get event bits */
+#define EVIOCGABS(abs)		_IOR('E', 0x40 + abs, struct input_absinfo)		/* get abs value/limits */
+#define EVIOCSABS(abs)		_IOW('E', 0xc0 + abs, struct input_absinfo)		/* set abs value/limits */
+
+#define EVIOCSFF		_IOC(_IOC_WRITE, 'E', 0x80, sizeof(struct ff_effect))	/* send a force effect to a force feedback device */
+#define EVIOCRMFF		_IOW('E', 0x81, int)			/* Erase a force effect */
+#define EVIOCGEFFECTS		_IOR('E', 0x84, int)			/* Report number of effects playable at the same time */
+
+#define EVIOCGRAB		_IOW('E', 0x90, int)			/* Grab/Release device */
+
+/*
+ * Event types
+ */
+
+#define EV_SYN			0x00
+#define EV_KEY			0x01
+#define EV_REL			0x02
+#define EV_ABS			0x03
+#define EV_MSC			0x04
+#define EV_SW			0x05
+#define EV_LED			0x11
+#define EV_SND			0x12
+#define EV_REP			0x14
+#define EV_FF			0x15
+#define EV_PWR			0x16
+#define EV_FF_STATUS		0x17
+#define EV_MAX			0x1f
+
+#define KEY_POWER		116
+#define KEY_SLEEP		142
+#define SW_0		0x00
+
+// end <linux/input.h>
+
+struct notify_entry {
+    int id;
+    int (*handler)(struct notify_entry *entry, struct inotify_event *event);
+    const char *filename;
+};
+
+int charging_state_notify_handler(struct notify_entry *entry, struct inotify_event *event)
+{
+    static int state = -1;
+    int last_state;
+    char buf[40];
+    int read_len;
+    int fd;
+
+    last_state = state;
+    fd = open(entry->filename, O_RDONLY);
+    read_len = read(fd, buf, sizeof(buf));
+    if(read_len > 0) {
+        //printf("charging_state_notify_handler: \"%s\"\n", buf);
+        state = !(strncmp(buf, "Unknown", 7) == 0 
+                  || strncmp(buf, "Discharging", 11) == 0);
+    }
+    close(fd);
+    //printf("charging_state_notify_handler: %d -> %d\n", last_state, state);
+    return state > last_state;
+}
+
+struct notify_entry watched_files[] = {
+    {
+        .filename = "/sys/android_power/charging_state",
+        .handler = charging_state_notify_handler
+    }
+};
+
+int call_notify_handler(struct inotify_event *event)
+{
+    unsigned int start, i;
+    start = event->wd - watched_files[0].id;
+    if(start >= ARRAY_SIZE(watched_files))
+        start = 0;
+    //printf("%d: %08x \"%s\"\n", event->wd, event->mask, event->len ? event->name : "");
+    for(i = start; i < ARRAY_SIZE(watched_files); i++) {
+        if(event->wd == watched_files[i].id) {
+            if(watched_files[i].handler) {
+                return watched_files[i].handler(&watched_files[i], event);
+            }
+            return 1;
+        }
+    }
+    for(i = 0; i < start; i++) {
+        if(event->wd == watched_files[i].id) {
+            if(watched_files[i].handler) {
+                return watched_files[i].handler(&watched_files[i], event);
+            }
+            return 1;
+        }
+    }
+    return 0;
+}
+
+int handle_inotify_event(int nfd)
+{
+    int res;
+    int wake_up = 0;
+    struct inotify_event *event;
+    char event_buf[512];
+    int event_pos = 0;
+
+    res = read(nfd, event_buf, sizeof(event_buf));
+    if(res < (int)sizeof(*event)) {
+        if(errno == EINTR)
+            return 0;
+        fprintf(stderr, "could not get event, %s\n", strerror(errno));
+        return 0;
+    }
+    printf("got %d bytes of event information\n", res);
+    while(res >= (int)sizeof(*event)) {
+        int event_size;
+        event = (struct inotify_event *)(event_buf + event_pos);
+        wake_up |= call_notify_handler(event);
+        event_size = sizeof(*event) + event->len;
+        res -= event_size;
+        event_pos += event_size;
+    }
+    return wake_up;
+}
+
+int powerd_main(int argc, char *argv[])
+{
+    int c;
+    unsigned int i;
+    int res;
+    struct timeval tv;
+    int eventfd;
+    int notifyfd;
+    int powerfd;
+    int powerfd_is_sleep;
+    int user_activity_fd;
+    int acquire_partial_wake_lock_fd;
+    int acquire_full_wake_lock_fd;
+    int release_wake_lock_fd;
+    char *eventdev = "/dev/input/event0";
+    const char *android_sleepdev = "/sys/android_power/request_sleep";
+    const char *android_autooff_dev = "/sys/android_power/auto_off_timeout";
+    const char *android_user_activity_dev = "/sys/android_power/last_user_activity";
+    const char *android_acquire_partial_wake_lock_dev = "/sys/android_power/acquire_partial_wake_lock";
+    const char *android_acquire_full_wake_lock_dev = "/sys/android_power/acquire_full_wake_lock";
+    const char *android_release_wake_lock_dev = "/sys/android_power/release_wake_lock";
+    const char *powerdev = "/sys/power/state";
+    const char suspendstring[] = "standby";
+    const char wakelockstring[] = "powerd";
+    fd_set rfds;
+    struct input_event event;
+    struct input_event light_event;
+    struct input_event light_event2;
+    int gotkey = 1;
+    time_t idle_time = 5;
+    const char *idle_time_string = "5";
+    time_t lcd_light_time = 0;
+    time_t key_light_time = 0;
+    int verbose = 1;
+    int event_sleep = 0;
+    int got_power_key_down = 0;
+    struct timeval power_key_down_time = { 0, 0 };
+
+    light_event.type = EV_LED;
+    light_event.code = 4; // bright lcd backlight
+    light_event.value = 0; // light off -- sleep after timeout
+
+    light_event2.type = EV_LED;
+    light_event2.code = 8; // keyboard backlight
+    light_event2.value = 0; // light off -- sleep after timeout
+
+    do {
+        c = getopt(argc, argv, "e:ni:vql:k:");
+        if (c == EOF)
+            break;
+        switch (c) {
+        case 'e':
+            eventdev = optarg;
+            break;
+        case 'n':
+            gotkey = 0;
+            break;
+        case 'i':
+            idle_time = atoi(optarg);
+            idle_time_string = optarg;
+            break;
+        case 'v':
+            verbose = 2;
+            break;
+        case 'q':
+            verbose = 0;
+            break;
+        case 'l':
+            lcd_light_time = atoi(optarg);
+            break;
+        case 'k':
+            key_light_time = atoi(optarg);
+            break;
+        case '?':
+            fprintf(stderr, "%s: invalid option -%c\n",
+                argv[0], optopt);
+            exit(1);
+        }
+    } while (1);
+    if(optind  != argc) {
+        fprintf(stderr,"%s [-e eventdev]\n", argv[0]);
+        return 1;
+    }
+
+    eventfd = open(eventdev, O_RDWR | O_NONBLOCK);
+    if(eventfd < 0) {
+        fprintf(stderr, "could not open %s, %s\n", eventdev, strerror(errno));
+        return 1;
+    }
+    if(key_light_time >= lcd_light_time) {
+        lcd_light_time = key_light_time + 1;
+        fprintf(stderr,"lcd bright backlight time must be longer than keyboard backlight time.\n"
+            "Setting lcd bright backlight time to %ld seconds\n", lcd_light_time);
+    }
+
+    user_activity_fd = open(android_user_activity_dev, O_RDWR);
+    if(user_activity_fd >= 0) {
+        int auto_off_fd = open(android_autooff_dev, O_RDWR);
+        write(auto_off_fd, idle_time_string, strlen(idle_time_string));
+        close(auto_off_fd);
+    }
+
+    powerfd = open(android_sleepdev, O_RDWR);
+    if(powerfd >= 0) {
+        powerfd_is_sleep = 1;
+        if(verbose > 0)
+            printf("Using android sleep dev: %s\n", android_sleepdev);
+    }
+    else {
+        powerfd_is_sleep = 0;
+        powerfd = open(powerdev, O_RDWR);
+        if(powerfd >= 0) {
+            if(verbose > 0)
+                printf("Using linux power dev: %s\n", powerdev);
+        }
+    }
+    if(powerfd < 0) {
+        fprintf(stderr, "could not open %s, %s\n", powerdev, strerror(errno));
+        return 1;
+    }
+
+    notifyfd = inotify_init();
+    if(notifyfd < 0) {
+        fprintf(stderr, "inotify_init failed, %s\n", strerror(errno));
+        return 1;
+    }
+    fcntl(notifyfd, F_SETFL, O_NONBLOCK | fcntl(notifyfd, F_GETFL));
+    for(i = 0; i < ARRAY_SIZE(watched_files); i++) {
+        watched_files[i].id = inotify_add_watch(notifyfd, watched_files[i].filename, IN_MODIFY);
+        printf("Watching %s, id %d\n", watched_files[i].filename, watched_files[i].id);
+    }
+
+    acquire_partial_wake_lock_fd = open(android_acquire_partial_wake_lock_dev, O_RDWR);
+    acquire_full_wake_lock_fd = open(android_acquire_full_wake_lock_dev, O_RDWR);
+    release_wake_lock_fd = open(android_release_wake_lock_dev, O_RDWR);
+
+    if(user_activity_fd >= 0) {
+        idle_time = 60*60*24; // driver handles real timeout
+    }
+    if(gotkey) {
+        tv.tv_sec = idle_time;
+        tv.tv_usec = 0;
+    }
+    else {
+        tv.tv_sec = 0;
+        tv.tv_usec = 500000;
+    }
+    
+    while(1) {
+        FD_ZERO(&rfds);
+        //FD_SET(0, &rfds);
+        FD_SET(eventfd, &rfds);
+        FD_SET(notifyfd, &rfds);
+        res = select(((notifyfd > eventfd) ? notifyfd : eventfd) + 1, &rfds, NULL, NULL, &tv);
+        if(res < 0) {
+            fprintf(stderr, "select failed, %s\n", strerror(errno));
+            return 1;
+        }
+        if(res == 0) {
+            if(light_event2.value == 1)
+                goto light2_off;
+            if(light_event.value == 1)
+                goto light_off;
+            if(user_activity_fd < 0) {
+                if(gotkey && verbose > 0)
+                    printf("Idle - sleep\n");
+                if(!gotkey && verbose > 1)
+                    printf("Reenter sleep\n");
+                goto sleep;
+            }
+            else {
+                tv.tv_sec = 60*60*24;
+                tv.tv_usec = 0;
+            }
+        }
+        if(res > 0) {
+            //if(FD_ISSET(0, &rfds)) {
+            //  printf("goto data on stdin quit\n");
+            //  return 0;
+            //}
+            if(FD_ISSET(notifyfd, &rfds)) {
+                write(acquire_partial_wake_lock_fd, wakelockstring, sizeof(wakelockstring) - 1);
+                if(handle_inotify_event(notifyfd) > 0) {
+                    write(acquire_full_wake_lock_fd, wakelockstring, sizeof(wakelockstring) - 1);
+                }
+                write(release_wake_lock_fd, wakelockstring, sizeof(wakelockstring) - 1);
+            }
+            if(FD_ISSET(eventfd, &rfds)) {
+                write(acquire_partial_wake_lock_fd, wakelockstring, sizeof(wakelockstring) - 1);
+                res = read(eventfd, &event, sizeof(event));
+                if(res < (int)sizeof(event)) {
+                    fprintf(stderr, "could not get event\n");
+                    write(release_wake_lock_fd, wakelockstring, sizeof(wakelockstring) - 1);
+                    return 1;
+                }
+                if(event.type == EV_PWR && event.code == KEY_SLEEP) {
+                    event_sleep = event.value;
+                }
+                if(event.type == EV_KEY || (event.type == EV_SW && event.code == SW_0 && event.value == 1)) {
+                    gotkey = 1;
+                    if(user_activity_fd >= 0) {
+                        char buf[32];
+                        int len;
+                        len = sprintf(buf, "%ld%06lu000", event.time.tv_sec, event.time.tv_usec);
+                        write(user_activity_fd, buf, len);
+                    }
+                    if(lcd_light_time | key_light_time) {
+                        tv.tv_sec = key_light_time;
+                        light_event.value = 1;
+                        write(eventfd, &light_event, sizeof(light_event));
+                        light_event2.value = 1;
+                        write(eventfd, &light_event2, sizeof(light_event2));
+                    }
+                    else {
+                        tv.tv_sec = idle_time;
+                    }
+                    tv.tv_usec = 0;
+                    if(verbose > 1)
+                        printf("got %s %s %d%s\n", event.type == EV_KEY ? "key" : "switch", event.value ? "down" : "up", event.code, event_sleep ? " from sleep" : "");
+                    if(event.code == KEY_POWER) {
+                        if(event.value == 0) {
+                            int tmp_got_power_key_down = got_power_key_down;
+                            got_power_key_down = 0;
+                            if(tmp_got_power_key_down) {
+                                // power key released
+                                if(verbose > 0)
+                                    printf("Power key released - sleep\n");
+                                write(release_wake_lock_fd, wakelockstring, sizeof(wakelockstring) - 1);
+                                goto sleep;
+                            }
+                        }
+                        else if(event_sleep == 0) {
+                            got_power_key_down = 1;
+                            power_key_down_time = event.time;
+                        }
+                    }
+                }
+                if(event.type == EV_SW && event.code == SW_0 && event.value == 0) {
+                    if(verbose > 0)
+                        printf("Flip closed - sleep\n");
+                    power_key_down_time = event.time;
+                    write(release_wake_lock_fd, wakelockstring, sizeof(wakelockstring) - 1);
+                    goto sleep;
+                }
+                write(release_wake_lock_fd, wakelockstring, sizeof(wakelockstring) - 1);
+            }
+        }
+        if(0) {
+light_off:
+            light_event.value = 0;
+            write(eventfd, &light_event, sizeof(light_event));
+            tv.tv_sec = idle_time - lcd_light_time;
+        }
+        if(0) {
+light2_off:
+            light_event2.value = 0;
+            write(eventfd, &light_event2, sizeof(light_event2));
+            tv.tv_sec = lcd_light_time - key_light_time;
+        }
+        if(0) {
+sleep:
+            if(light_event.value == 1) {
+                light_event.value = 0;
+                write(eventfd, &light_event, sizeof(light_event));
+                light_event2.value = 0;
+                write(eventfd, &light_event2, sizeof(light_event2));
+                tv.tv_sec = idle_time - lcd_light_time;
+            }
+            if(powerfd_is_sleep) {
+                char buf[32];
+                int len;
+                len = sprintf(buf, "%ld%06lu000", power_key_down_time.tv_sec, power_key_down_time.tv_usec);
+                write(powerfd, buf, len);
+            }
+            else
+                write(powerfd, suspendstring, sizeof(suspendstring) - 1);
+            gotkey = 0;
+            tv.tv_sec = 0;
+            tv.tv_usec = 500000;
+        }
+    }
+
+    return 0;
+}
diff --git a/printenv.c b/printenv.c
new file mode 100644
index 0000000..d5ea531
--- /dev/null
+++ b/printenv.c
@@ -0,0 +1,29 @@
+#include <stdio.h>
+#include <stdlib.h>
+
+extern char** environ;
+
+int printenv_main (int argc, char **argv)
+{
+    char** e;
+    char* v;
+    int i;
+   
+    if (argc == 1) {
+        e = environ;
+        while (*e) {
+            printf("%s\n", *e);
+            e++;
+        }
+    } else {
+        for (i=1; i<argc; i++) {
+            v = getenv(argv[i]);
+            if (v) {
+                printf("%s\n", v);
+            }
+        }
+    }
+
+    return 0;
+}
+
diff --git a/ps.c b/ps.c
new file mode 100644
index 0000000..bc50cfa
--- /dev/null
+++ b/ps.c
@@ -0,0 +1,234 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <fcntl.h>
+
+#include <string.h>
+
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <dirent.h>
+
+#include <pwd.h>
+
+#include <cutils/sched_policy.h>
+
+
+static char *nexttoksep(char **strp, char *sep)
+{
+    char *p = strsep(strp,sep);
+    return (p == 0) ? "" : p;
+}
+static char *nexttok(char **strp)
+{
+    return nexttoksep(strp, " ");
+}
+
+#define SHOW_PRIO 1
+#define SHOW_TIME 2
+#define SHOW_POLICY 4
+
+static int display_flags = 0;
+
+static int ps_line(int pid, int tid, char *namefilter)
+{
+    char statline[1024];
+    char cmdline[1024];
+    char user[32];
+    struct stat stats;
+    int fd, r;
+    char *ptr, *name, *state;
+    int ppid, tty;
+    unsigned wchan, rss, vss, eip;
+    unsigned utime, stime;
+    int prio, nice, rtprio, sched;
+    struct passwd *pw;
+    
+    sprintf(statline, "/proc/%d", pid);
+    stat(statline, &stats);
+
+    if(tid) {
+        sprintf(statline, "/proc/%d/task/%d/stat", pid, tid);
+        cmdline[0] = 0;
+    } else {
+        sprintf(statline, "/proc/%d/stat", pid);
+        sprintf(cmdline, "/proc/%d/cmdline", pid);    
+        fd = open(cmdline, O_RDONLY);
+        if(fd == 0) {
+            r = 0;
+        } else {
+            r = read(fd, cmdline, 1023);
+            close(fd);
+            if(r < 0) r = 0;
+        }
+        cmdline[r] = 0;
+    }
+    
+    fd = open(statline, O_RDONLY);
+    if(fd == 0) return -1;
+    r = read(fd, statline, 1023);
+    close(fd);
+    if(r < 0) return -1;
+    statline[r] = 0;
+
+    ptr = statline;
+    nexttok(&ptr); // skip pid
+    ptr++;          // skip "("
+
+    name = ptr;
+    ptr = strrchr(ptr, ')'); // Skip to *last* occurence of ')',
+    *ptr++ = '\0';           // and null-terminate name.
+
+    ptr++;          // skip " "
+    state = nexttok(&ptr);
+    ppid = atoi(nexttok(&ptr));
+    nexttok(&ptr); // pgrp
+    nexttok(&ptr); // sid
+    tty = atoi(nexttok(&ptr));
+    
+    nexttok(&ptr); // tpgid
+    nexttok(&ptr); // flags
+    nexttok(&ptr); // minflt
+    nexttok(&ptr); // cminflt
+    nexttok(&ptr); // majflt
+    nexttok(&ptr); // cmajflt
+#if 1
+    utime = atoi(nexttok(&ptr));
+    stime = atoi(nexttok(&ptr));
+#else
+    nexttok(&ptr); // utime
+    nexttok(&ptr); // stime
+#endif
+    nexttok(&ptr); // cutime
+    nexttok(&ptr); // cstime
+    prio = atoi(nexttok(&ptr));
+    nice = atoi(nexttok(&ptr));
+    nexttok(&ptr); // threads
+    nexttok(&ptr); // itrealvalue
+    nexttok(&ptr); // starttime
+    vss = strtoul(nexttok(&ptr), 0, 10); // vsize
+    rss = strtoul(nexttok(&ptr), 0, 10); // rss
+    nexttok(&ptr); // rlim
+    nexttok(&ptr); // startcode
+    nexttok(&ptr); // endcode
+    nexttok(&ptr); // startstack
+    nexttok(&ptr); // kstkesp
+    eip = strtoul(nexttok(&ptr), 0, 10); // kstkeip
+    nexttok(&ptr); // signal
+    nexttok(&ptr); // blocked
+    nexttok(&ptr); // sigignore
+    nexttok(&ptr); // sigcatch
+    wchan = strtoul(nexttok(&ptr), 0, 10); // wchan
+    nexttok(&ptr); // nswap
+    nexttok(&ptr); // cnswap
+    nexttok(&ptr); // exit signal
+    nexttok(&ptr); // processor
+    rtprio = atoi(nexttok(&ptr)); // rt_priority
+    sched = atoi(nexttok(&ptr)); // scheduling policy
+    
+    tty = atoi(nexttok(&ptr));
+    
+    if(tid != 0) {
+        ppid = pid;
+        pid = tid;
+    }
+
+    pw = getpwuid(stats.st_uid);
+    if(pw == 0) {
+        sprintf(user,"%d",(int)stats.st_uid);
+    } else {
+        strcpy(user,pw->pw_name);
+    }
+    
+    if(!namefilter || !strncmp(name, namefilter, strlen(namefilter))) {
+        printf("%-9s %-5d %-5d %-6d %-5d", user, pid, ppid, vss / 1024, rss * 4);
+        if(display_flags&SHOW_PRIO)
+            printf(" %-5d %-5d %-5d %-5d", prio, nice, rtprio, sched);
+        if (display_flags & SHOW_POLICY) {
+            SchedPolicy p;
+            if (get_sched_policy(pid, &p) < 0)
+                printf(" un ");
+            else {
+                if (p == SP_BACKGROUND)
+                    printf(" bg ");
+                else if (p == SP_FOREGROUND)
+                    printf(" fg ");
+                else
+                    printf(" er ");
+            }
+        }
+        printf(" %08x %08x %s %s", wchan, eip, state, cmdline[0] ? cmdline : name);
+        if(display_flags&SHOW_TIME)
+            printf(" (u:%d, s:%d)", utime, stime);
+
+        printf("\n");
+    }
+    return 0;
+}
+
+
+void ps_threads(int pid, char *namefilter)
+{
+    char tmp[128];
+    DIR *d;
+    struct dirent *de;
+
+    sprintf(tmp,"/proc/%d/task",pid);
+    d = opendir(tmp);
+    if(d == 0) return;
+    
+    while((de = readdir(d)) != 0){
+        if(isdigit(de->d_name[0])){
+            int tid = atoi(de->d_name);
+            if(tid == pid) continue;
+            ps_line(pid, tid, namefilter);
+        }
+    }
+    closedir(d);    
+}
+
+int ps_main(int argc, char **argv)
+{
+    DIR *d;
+    struct dirent *de;
+    char *namefilter = 0;
+    int pidfilter = 0;
+    int threads = 0;
+    
+    d = opendir("/proc");
+    if(d == 0) return -1;
+
+    while(argc > 1){
+        if(!strcmp(argv[1],"-t")) {
+            threads = 1;
+        } else if(!strcmp(argv[1],"-x")) {
+            display_flags |= SHOW_TIME;
+        } else if(!strcmp(argv[1],"-P")) {
+            display_flags |= SHOW_POLICY;
+        } else if(!strcmp(argv[1],"-p")) {
+            display_flags |= SHOW_PRIO;
+        }  else if(isdigit(argv[1][0])){
+            pidfilter = atoi(argv[1]);
+        } else {
+            namefilter = argv[1];
+        }
+        argc--;
+        argv++;
+    }
+
+    printf("USER     PID   PPID  VSIZE  RSS   %s %s WCHAN    PC         NAME\n", 
+           (display_flags&SHOW_PRIO)?"PRIO  NICE  RTPRI SCHED ":"",
+           (display_flags&SHOW_POLICY)?"PCY " : "");
+    while((de = readdir(d)) != 0){
+        if(isdigit(de->d_name[0])){
+            int pid = atoi(de->d_name);
+            if(!pidfilter || (pidfilter == pid)) {
+                ps_line(pid, 0, namefilter);
+                if(threads) ps_threads(pid, namefilter);
+            }
+        }
+    }
+    closedir(d);
+    return 0;
+}
+
diff --git a/r.c b/r.c
new file mode 100644
index 0000000..5a82e20
--- /dev/null
+++ b/r.c
@@ -0,0 +1,74 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/mman.h>
+#include <fcntl.h>
+#include <string.h>
+
+static int usage()
+{
+    fprintf(stderr,"r [-b|-s] <address> [<value>]\n");
+    return -1;
+}
+
+int r_main(int argc, char *argv[])
+{
+    int width = 4, set = 0, fd;
+    unsigned addr, value;
+    void *page;
+    
+    if(argc < 2) return usage();
+
+    if(!strcmp(argv[1], "-b")) {
+        width = 1;
+        argc--;
+        argv++;
+    } else if(!strcmp(argv[1], "-s")) {
+        width = 2;
+        argc--;
+        argv++;
+    }
+
+    if(argc < 2) return usage();
+    addr = strtoul(argv[1], 0, 16);
+
+    if(argc > 2) {
+        set = 1;
+        value = strtoul(argv[2], 0, 16);
+    }
+
+    fd = open("/dev/mem", O_RDWR | O_SYNC);
+    if(fd < 0) {
+        fprintf(stderr,"cannot open /dev/mem\n");
+        return -1;
+    }
+    
+    page = mmap(0, 8192, PROT_READ | PROT_WRITE,
+                MAP_SHARED, fd, addr & (~4095));
+
+    if(page == MAP_FAILED){
+        fprintf(stderr,"cannot mmap region\n");
+        return -1;
+    }
+
+    switch(width){
+    case 4: {
+        unsigned *x = (unsigned*) (((unsigned) page) + (addr & 4095));
+        if(set) *x = value;
+        fprintf(stderr,"%08x: %08x\n", addr, *x);
+        break;
+    }
+    case 2: {
+        unsigned short *x = (unsigned short*) (((unsigned) page) + (addr & 4095));
+        if(set) *x = value;
+        fprintf(stderr,"%08x: %04x\n", addr, *x);
+        break;
+    }
+    case 1: {
+        unsigned char *x = (unsigned char*) (((unsigned) page) + (addr & 4095));
+        if(set) *x = value;
+        fprintf(stderr,"%08x: %02x\n", addr, *x);
+        break;
+    }
+    }    
+    return 0;
+}
diff --git a/readtty.c b/readtty.c
new file mode 100644
index 0000000..2b27548
--- /dev/null
+++ b/readtty.c
@@ -0,0 +1,183 @@
+#include <ctype.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/mman.h>
+#include <fcntl.h>
+#include <string.h>
+#include <termios.h>
+#include <unistd.h>
+
+struct {
+    char key;
+    char *chars;
+} map[] = {
+    { '1', "_ -1?!,.:;\"'<=>()_" },
+    { '2', "Cabc2ABC" },
+    { '3', "Fdef3DEF" },
+    { '4', "Ighi4GHI" },
+    { '5', "Ljkl5JKL" },
+    { '6', "Omno6MNO" },
+    { '7', "Spqrs7PQRS" },
+    { '8', "Vtuv8TUV" },
+    { '9', "Zwxyz9WXYZ" },
+    { '0', "*+&0@/#*" },
+};
+
+char next_char(char key, char current)
+{
+    int i;
+    char *next;
+    for(i = 0; i < sizeof(map) / sizeof(map[0]); i++) {
+        if(key == map[i].key) {
+            next = strchr(map[i].chars, current);
+            if(next && next[1])
+                return next[1];
+            return map[i].chars[1];
+        }
+    }
+    return key;
+}
+
+char prev_char(char key, char current)
+{
+    int i;
+    char *next;
+    for(i = 0; i < sizeof(map) / sizeof(map[0]); i++) {
+        if(key == map[i].key) {
+            next = strchr(map[i].chars+1, current);
+            if(next && next[-1])
+                return next[-1];
+            return map[i].chars[1];
+        }
+    }
+    return key;
+}
+
+int readtty_main(int argc, char *argv[])
+{
+    int c;
+    //int flags;
+    char buf[1];
+    int res;
+    struct termios ttyarg;
+    struct termios savedttyarg;
+    int nonblock = 0;
+    int timeout = 0;
+    int flush = 0;
+    int phone = 0;
+    char *accept = NULL;
+    char *rejectstring = NULL;
+    char last_char_in = 0;
+    char current_char = 0;
+    char *exit_string = NULL;
+    int exit_match = 0;
+
+    do {
+        c = getopt(argc, argv, "nt:fa:r:pe:");
+        if (c == EOF)
+            break;
+        switch (c) {
+        case 't':
+            timeout = atoi(optarg);
+            break;
+        case 'n':
+            nonblock = 1;
+            break;
+        case 'f':
+            flush = 1;
+            break;
+        case 'a':
+            accept = optarg;
+            break;
+        case 'r':
+            rejectstring = optarg;
+            break;
+        case 'p':
+            phone = 1;
+            break;
+        case 'e':
+            exit_string = optarg;
+            break;
+        case '?':
+            fprintf(stderr, "%s: invalid option -%c\n",
+                argv[0], optopt);
+            exit(1);
+        }
+    } while (1);
+
+    if(flush)
+        tcflush(STDIN_FILENO, TCIFLUSH);
+    ioctl(STDIN_FILENO, TCGETS , &savedttyarg) ;       /* set changed tty arguments */
+    ttyarg = savedttyarg;
+    ttyarg.c_cc[VMIN] = (timeout > 0 || nonblock) ? 0 : 1;                /* minimum of 0 chars */
+    ttyarg.c_cc[VTIME] = timeout;              /* wait max 15/10 sec */
+    ttyarg.c_iflag = BRKINT | ICRNL; 
+    ttyarg.c_lflag &= ~(ECHO | ICANON);
+    ioctl(STDIN_FILENO, TCSETS , &ttyarg);
+
+    while (1) {
+        res = read(STDIN_FILENO, buf, 1);
+        if(res <= 0) {
+            if(phone) {
+                if(current_char) {
+                    write(STDERR_FILENO, &current_char, 1);
+                    write(STDOUT_FILENO, &current_char, 1);
+                    if(exit_string && current_char == exit_string[exit_match]) {
+                        exit_match++;
+                        if(exit_string[exit_match] == '\0')
+                            break;
+                    }
+                    else
+                        exit_match = 0;
+                    current_char = 0;
+                }
+                continue;
+            }
+            break;
+        }
+        if(accept && strchr(accept, buf[0]) == NULL) {
+            if(rejectstring) {
+                write(STDOUT_FILENO, rejectstring, strlen(rejectstring));
+                break;
+            }
+            if(flush)
+                tcflush(STDIN_FILENO, TCIFLUSH);
+            continue;
+        }
+        if(phone) {
+            //if(!isprint(buf[0])) {
+            //  fprintf(stderr, "got unprintable character 0x%x\n", buf[0]);
+            //}
+            if(buf[0] == '\0') {
+                if(current_char) {
+                    current_char = prev_char(last_char_in, current_char);
+                    write(STDERR_FILENO, &current_char, 1);
+                    write(STDERR_FILENO, "\b", 1);
+                }
+                continue;
+            }
+            if(current_char && buf[0] != last_char_in) {
+                write(STDERR_FILENO, &current_char, 1);
+                write(STDOUT_FILENO, &current_char, 1);
+                if(exit_string && current_char == exit_string[exit_match]) {
+                    exit_match++;
+                    if(exit_string[exit_match] == '\0')
+                        break;
+                }
+                else
+                    exit_match = 0;
+                current_char = 0;
+            }
+            last_char_in = buf[0];
+            current_char = next_char(last_char_in, current_char);
+            write(STDERR_FILENO, &current_char, 1);
+            write(STDERR_FILENO, "\b", 1);
+            continue;
+        }
+        write(STDOUT_FILENO, buf, 1);
+        break;
+    }
+    ioctl(STDIN_FILENO, TCSETS , &savedttyarg) ;       /* set changed tty arguments */
+
+    return 0;
+}
diff --git a/reboot.c b/reboot.c
new file mode 100644
index 0000000..aebe185
--- /dev/null
+++ b/reboot.c
@@ -0,0 +1,56 @@
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/reboot.h>
+#include <unistd.h>
+
+int reboot_main(int argc, char *argv[])
+{
+    int ret;
+    int nosync = 0;
+    int poweroff = 0;
+
+    opterr = 0;
+    do {
+        int c;
+
+        c = getopt(argc, argv, "np");
+        
+        if (c == EOF) {
+            break;
+        }
+        
+        switch (c) {
+        case 'n':
+            nosync = 1;
+            break;
+        case 'p':
+            poweroff = 1;
+            break;
+        case '?':
+            fprintf(stderr, "usage: %s [-n] [-p] [rebootcommand]\n", argv[0]);
+            exit(EXIT_FAILURE);
+        }
+    } while (1);
+
+    if(argc > optind + 1) {
+        fprintf(stderr, "%s: too many arguments\n", argv[0]);
+        exit(EXIT_FAILURE);
+    }
+
+    if(!nosync)
+        sync();
+
+    if(poweroff)
+        ret = __reboot(LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2, LINUX_REBOOT_CMD_POWER_OFF, NULL);
+    else if(argc > optind)
+        ret = __reboot(LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2, LINUX_REBOOT_CMD_RESTART2, argv[optind]);
+    else
+        ret = reboot(RB_AUTOBOOT);
+    if(ret < 0) {
+        perror("reboot");
+        exit(EXIT_FAILURE);
+    }
+    fprintf(stderr, "reboot returned\n");
+    return 0;
+}
diff --git a/renice.c b/renice.c
new file mode 100644
index 0000000..978b329
--- /dev/null
+++ b/renice.c
@@ -0,0 +1,144 @@
+/*
+ * Copyright (c) 2008, The Android Open Source Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * 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.
+ *  * Neither the name of Google, Inc. 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 COPYRIGHT HOLDERS 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
+ * COPYRIGHT OWNER 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 <unistd.h>
+#include <stdlib.h>
+#include <sys/time.h>
+#include <sys/resource.h>
+#include <sched.h>
+
+static void
+usage(const char *s)
+{
+    fprintf(stderr, "USAGE: %s [[-r] priority pids ...] [-g pid]\n", s);
+    exit(EXIT_FAILURE);
+}
+
+void print_prio(pid_t pid)
+{
+    int sched;
+    struct sched_param sp;
+
+    printf("pid %d's priority: %d\n", pid, getpriority(PRIO_PROCESS, pid));
+
+    printf("scheduling class: ");
+    sched = sched_getscheduler(pid);
+    switch (sched) {
+    case SCHED_FIFO:
+        printf("FIFO\n");
+        break;
+    case SCHED_RR:
+        printf("RR\n");
+        break;
+    case SCHED_OTHER:
+        printf("Normal\n");
+        break;
+    case -1:
+        perror("sched_getscheduler");
+        break;
+    default:
+        printf("Unknown\n");
+    }
+
+    sched_getparam(pid, &sp);
+    printf("RT prio: %d (of %d to %d)\n", sp.sched_priority,
+           sched_get_priority_min(sched), sched_get_priority_max(sched));
+}
+
+int renice_main(int argc, char *argv[])
+{
+    int prio;
+    int realtime = 0;
+    char *cmd = argv[0];
+
+    // consume command name
+    argc--;
+    argv++;
+
+    if (argc < 1)
+        usage(cmd);
+
+    if(strcmp("-r", argv[0]) == 0) {
+        // do realtime priority adjustment
+        realtime = 1;
+        argc--;
+        argv++;
+    }
+
+	if(strcmp("-g", argv[0]) == 0) {
+        if (argc < 2)
+            usage(cmd);
+        print_prio(atoi(argv[1]));
+        return 0;
+    }
+
+    if (argc < 1)
+        usage(cmd);
+
+    prio = atoi(argv[0]);
+    argc--;
+    argv++;
+
+    if (argc < 1)
+        usage(cmd);
+
+    while(argc) {
+        pid_t pid;
+
+        pid = atoi(argv[0]);
+        argc--;
+        argv++;
+
+        if (realtime) {
+            struct sched_param sp = { .sched_priority = prio };
+            int ret;
+
+            ret = sched_setscheduler(pid, SCHED_RR, &sp);
+            if (ret) {
+                perror("sched_set_scheduler");
+                exit(EXIT_FAILURE);
+            }
+        } else {
+            int ret;
+
+            ret = setpriority(PRIO_PROCESS, pid, prio);
+            if (ret) {
+                perror("setpriority");
+                exit(EXIT_FAILURE);
+            }
+        }
+    }
+   
+    return 0;
+}
+
+
diff --git a/rm.c b/rm.c
new file mode 100644
index 0000000..bd66311
--- /dev/null
+++ b/rm.c
@@ -0,0 +1,92 @@
+#include <stdio.h>
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+#include <dirent.h>
+#include <limits.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+static int usage()
+{
+    fprintf(stderr,"rm [-rR] <target>\n");
+    return -1;
+}
+
+/* return -1 on failure, with errno set to the first error */
+static int unlink_recursive(const char* name)
+{
+    struct stat st;
+    DIR *dir;
+    struct dirent *de;
+    int fail = 0;
+
+    /* is it a file or directory? */
+    if (lstat(name, &st) < 0)
+        return -1;
+
+    /* a file, so unlink it */
+    if (!S_ISDIR(st.st_mode))
+        return unlink(name);
+
+    /* a directory, so open handle */
+    dir = opendir(name);
+    if (dir == NULL)
+        return -1;
+
+    /* recurse over components */
+    errno = 0;
+    while ((de = readdir(dir)) != NULL) {
+        char dn[PATH_MAX];
+        if (!strcmp(de->d_name, "..") || !strcmp(de->d_name, "."))
+            continue;
+        sprintf(dn, "%s/%s", name, de->d_name);
+        if (unlink_recursive(dn) < 0) {
+            fail = 1;
+            break;
+        }
+        errno = 0;
+    }
+    /* in case readdir or unlink_recursive failed */
+    if (fail || errno < 0) {
+        int save = errno;
+        closedir(dir);
+        errno = save;
+        return -1;
+    }
+
+    /* close directory handle */
+    if (closedir(dir) < 0)
+        return -1;
+
+    /* delete target directory */
+    return rmdir(name);
+}
+
+int rm_main(int argc, char *argv[])
+{
+    int ret;
+    int i = 1;
+    int recursive = 0;
+
+    if (argc < 2)
+        return usage();
+
+    /* check if recursive */
+    if (argc >=2 && (!strcmp(argv[1], "-r") || !strcmp(argv[1], "-R"))) {
+        recursive = 1;
+        i = 2;
+    }
+    
+    /* loop over the file/directory args */
+    for (; i < argc; i++) {
+        int ret = recursive ? unlink_recursive(argv[i]) : unlink(argv[i]);
+        if (ret < 0) {
+            fprintf(stderr, "rm failed for %s, %s\n", argv[i], strerror(errno));
+            return -1;
+        }
+    }
+
+    return 0;
+}
+
diff --git a/rmdir.c b/rmdir.c
new file mode 100644
index 0000000..06f3df2
--- /dev/null
+++ b/rmdir.c
@@ -0,0 +1,29 @@
+#include <stdio.h>
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+
+static int usage()
+{
+    fprintf(stderr,"rmdir <directory>\n");
+    return -1;
+}
+
+int rmdir_main(int argc, char *argv[])
+{
+    int symbolic = 0;
+    int ret;
+    if(argc < 2) return usage();
+
+    while(argc > 1) {
+        argc--;
+        argv++;
+        ret = rmdir(argv[0]);
+        if(ret < 0) {
+            fprintf(stderr, "rmdir failed for %s, %s\n", argv[0], strerror(errno));
+            return ret;
+        }
+    }
+    
+    return 0;
+}
diff --git a/rmmod.c b/rmmod.c
new file mode 100644
index 0000000..7e10c06
--- /dev/null
+++ b/rmmod.c
@@ -0,0 +1,42 @@
+#include <stdio.h>
+#include <string.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <malloc.h>
+#include <errno.h>
+#include <asm/unistd.h>
+
+extern int delete_module(const char *, unsigned int);
+
+int rmmod_main(int argc, char **argv)
+{
+	int ret;
+	char *modname, *dot;
+
+	/* make sure we've got an argument */
+	if (argc < 2) {
+		fprintf(stderr, "usage: rmmod <module>\n");
+		return -1;
+	}
+
+	/* if given /foo/bar/blah.ko, make a weak attempt
+	 * to convert to "blah", just for convenience
+	 */
+	modname = strrchr(argv[1], '/');
+	if (!modname)
+		modname = argv[1];
+	dot = strchr(argv[1], '.');
+	if (dot)
+		*dot = '\0';
+
+	/* pass it to the kernel */
+	ret = delete_module(modname, O_NONBLOCK | O_EXCL);
+	if (ret != 0) {
+		fprintf(stderr, "rmmod: delete_module '%s' failed (errno %d)\n",
+						modname, errno);
+		return -1;
+	}
+
+	return 0;
+}
+
diff --git a/rotatefb.c b/rotatefb.c
new file mode 100644
index 0000000..2ff4127
--- /dev/null
+++ b/rotatefb.c
@@ -0,0 +1,71 @@
+#include <ctype.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/mman.h>
+#include <fcntl.h>
+#include <string.h>
+#include <termios.h>
+#include <unistd.h>
+#include <errno.h>
+#include <linux/fb.h>
+
+
+int rotatefb_main(int argc, char *argv[])
+{
+    int c;
+    char *fbdev = "/dev/graphics/fb0";
+    int rotation = 0;
+    int fd;
+    int res;
+    struct fb_var_screeninfo fbinfo;
+
+    do {
+        c = getopt(argc, argv, "d:");
+        if (c == EOF)
+            break;
+        switch (c) {
+        case 'd':
+            fbdev = optarg;
+            break;
+        case '?':
+            fprintf(stderr, "%s: invalid option -%c\n",
+                argv[0], optopt);
+            exit(1);
+        }
+    } while (1);
+
+    if(optind + 1 != argc) {
+        fprintf(stderr, "%s: specify rotation\n", argv[0]);
+        exit(1);
+    }
+    rotation = atoi(argv[optind]);
+
+    fd = open(fbdev, O_RDWR);
+    if(fd < 0) {
+        fprintf(stderr, "cannot open %s\n", fbdev);
+        return 1;
+    }
+
+    res = ioctl(fd, FBIOGET_VSCREENINFO, &fbinfo);
+    if(res < 0) {
+        fprintf(stderr, "failed to get fbinfo: %s\n", strerror(errno));
+        return 1;
+    }
+    if((fbinfo.rotate ^ rotation) & 1) {
+        unsigned int xres = fbinfo.yres;
+        fbinfo.yres = fbinfo.xres;
+        fbinfo.xres = xres;
+        fbinfo.xres_virtual = fbinfo.xres;
+        fbinfo.yres_virtual = fbinfo.yres * 2;
+        if(fbinfo.yoffset == xres)
+            fbinfo.yoffset = fbinfo.yres;
+    }
+    fbinfo.rotate = rotation; 
+    res = ioctl(fd, FBIOPUT_VSCREENINFO, &fbinfo);
+    if(res < 0) {
+        fprintf(stderr, "failed to set fbinfo: %s\n", strerror(errno));
+        return 1;
+    }
+
+    return 0;
+}
diff --git a/route.c b/route.c
new file mode 100644
index 0000000..3e10014
--- /dev/null
+++ b/route.c
@@ -0,0 +1,113 @@
+/*
+ * Copyright (c) 2009, The Android Open Source Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * 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.
+ *  * Neither the name of Google, Inc. 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 COPYRIGHT HOLDERS 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
+ * COPYRIGHT OWNER 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 <string.h>
+#include <errno.h>
+#include <sys/ioctl.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <linux/route.h>
+
+static inline int set_address(const char *address, struct sockaddr *sa) {
+    return inet_aton(address, &((struct sockaddr_in *)sa)->sin_addr);
+}
+
+/* current support the following routing entries */
+/* route add default dev wlan0 */
+/* route add default gw 192.168.1.1 dev wlan0 */
+/* route add -net 192.168.1.2 netmask 255.255.255.0 gw 192.168.1.1 */
+
+int route_main(int argc, char *argv[])
+{
+    struct rtentry rt = {
+        .rt_dst     = {.sa_family = AF_INET},
+        .rt_genmask = {.sa_family = AF_INET},
+        .rt_gateway = {.sa_family = AF_INET},
+    };
+
+    errno = EINVAL;
+    if (argc > 2 && !strcmp(argv[1], "add")) {
+        if (!strcmp(argv[2], "default")) {
+            /* route add default dev wlan0 */
+            if (argc > 4 && !strcmp(argv[3], "dev")) {
+                rt.rt_flags = RTF_UP;
+                rt.rt_dev = argv[4];
+                errno = 0;
+                goto apply;
+            }
+
+            /* route add default gw 192.168.1.1 dev wlan0 */
+            if (argc > 6 && !strcmp(argv[3], "gw") && !strcmp(argv[5], "dev")) {
+                rt.rt_flags = RTF_UP | RTF_GATEWAY;
+                rt.rt_dev = argv[6];
+                if (set_address(argv[4], &rt.rt_gateway)) {
+                    errno = 0;
+                }
+                goto apply;
+            }
+        }
+
+        /* route add -net 192.168.1.2 netmask 255.255.255.0 gw 192.168.1.1 */
+        if (argc > 7 && !strcmp(argv[2], "-net") &&
+                !strcmp(argv[4], "netmask")) {
+            if (!strcmp(argv[6], "gw")) {
+                rt.rt_flags = RTF_UP | RTF_GATEWAY;
+                if (set_address(argv[3], &rt.rt_dst) &&
+                    set_address(argv[5], &rt.rt_genmask) &&
+                    set_address(argv[7], &rt.rt_gateway)) {
+                    errno = 0;
+                }
+                goto apply;
+            } else if (!strcmp(argv[6], "dev")) {
+                rt.rt_flags = RTF_UP;
+                rt.rt_dev = argv[7];
+                if (set_address(argv[3], &rt.rt_dst) &&
+                    set_address(argv[5], &rt.rt_genmask)) {
+                    errno = 0;
+                }
+                goto apply;
+            }
+        }
+    }
+
+apply:
+    if (!errno) {
+        int s = socket(AF_INET, SOCK_DGRAM, 0);
+        if (s != -1 && (ioctl(s, SIOCADDRT, &rt) != -1 || errno == EEXIST)) {
+            return 0;
+        }
+    }
+    puts(strerror(errno));
+    return errno;
+}
diff --git a/schedtop.c b/schedtop.c
new file mode 100644
index 0000000..c0e0141
--- /dev/null
+++ b/schedtop.c
@@ -0,0 +1,335 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <fcntl.h>
+
+#include <string.h>
+
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <dirent.h>
+#include <signal.h>
+
+#include <pwd.h>
+
+struct thread_info {
+    int pid;
+    int tid;
+    char name[64];
+    uint64_t exec_time;
+    uint64_t delay_time;
+    uint32_t run_count;
+};
+
+struct thread_table {
+    size_t allocated;
+    size_t active;
+    struct thread_info *data;
+};
+
+enum {
+    FLAG_BATCH = 1U << 0,
+    FLAG_HIDE_IDLE = 1U << 1,
+    FLAG_SHOW_THREADS = 1U << 2,
+    FLAG_USE_ALTERNATE_SCREEN = 1U << 3,
+};
+
+static int time_dp = 9;
+static int time_div = 1;
+#define NS_TO_S_D(ns) \
+    (uint32_t)((ns) / 1000000000), time_dp, ((uint32_t)((ns) % 1000000000) / time_div)
+
+struct thread_table processes;
+struct thread_table last_processes;
+struct thread_table threads;
+struct thread_table last_threads;
+
+static void grow_table(struct thread_table *table)
+{
+    size_t size = table->allocated;
+    struct thread_info *new_table;
+    if (size < 128)
+        size = 128;
+    else
+        size *= 2;
+    
+    new_table = realloc(table->data, size * sizeof(*table->data));
+    if (new_table == NULL) {
+        fprintf(stderr, "out of memory\n");
+        exit(1);
+    }
+    table->data = new_table;
+    table->allocated = size;
+}
+
+static struct thread_info *get_item(struct thread_table *table)
+{
+    if (table->active >= table->allocated)
+        grow_table(table);
+    return table->data + table->active;
+}
+
+static void commit_item(struct thread_table *table)
+{
+    table->active++;
+}
+
+static int read_line(char *line, size_t line_size)
+{
+    int fd;
+    int len;
+    fd = open(line, O_RDONLY);
+    if(fd == 0)
+        return -1;
+    len = read(fd, line, line_size - 1);
+    close(fd);
+    if (len <= 0)
+        return -1;
+    line[len] = '\0';
+    return 0;
+}
+
+static void add_thread(int pid, int tid, struct thread_info *proc_info)
+{
+    char line[1024];
+    char *name, *name_end;
+    size_t name_len;
+    struct thread_info *info;
+    if(tid == 0)
+        info = get_item(&processes);
+    else
+        info = get_item(&threads);
+    info->pid = pid;
+    info->tid = tid;
+
+    if(tid)
+        sprintf(line, "/proc/%d/task/%d/schedstat", pid, tid);
+    else
+        sprintf(line, "/proc/%d/schedstat", pid);
+    if (read_line(line, sizeof(line)))
+        return;
+    if(sscanf(line, "%llu %llu %u", &info->exec_time, &info->delay_time, &info->run_count) != 3)
+        return;
+    if (proc_info) {
+        proc_info->exec_time += info->exec_time;
+        proc_info->delay_time += info->delay_time;
+        proc_info->run_count += info->run_count;
+    }
+
+    name = NULL;
+    if (!tid) {
+        sprintf(line, "/proc/%d/cmdline", pid);
+        if (read_line(line, sizeof(line)) == 0 && line[0]) {
+            name = line;
+            name_len = strlen(name);
+        }
+    }
+    if (!name) {
+        if (tid)
+            sprintf(line, "/proc/%d/task/%d/stat", pid, tid);
+        else
+            sprintf(line, "/proc/%d/stat", pid);
+        if (read_line(line, sizeof(line)))
+            return;
+        name = strchr(line, '(');
+        if (name == NULL)
+            return;
+        name_end = strchr(name, ')');
+        if (name_end == NULL)
+            return;
+        name++;
+        name_len = name_end - name;
+    }
+    if (name_len >= sizeof(info->name))
+        name_len = sizeof(info->name) - 1;
+    memcpy(info->name, name, name_len);
+    info->name[name_len] = '\0';
+    if(tid == 0)
+        commit_item(&processes);
+    else
+        commit_item(&threads);
+}
+
+static void add_threads(int pid, struct thread_info *proc_info)
+{
+    char path[1024];
+    DIR *d;
+    struct dirent *de;
+    sprintf(path, "/proc/%d/task", pid);
+    d = opendir(path);
+    if(d == 0) return;
+    while((de = readdir(d)) != 0){
+        if(isdigit(de->d_name[0])){
+            int tid = atoi(de->d_name);
+            add_thread(pid, tid, proc_info);
+        }
+    }
+    closedir(d);
+}
+
+static void print_threads(int pid, uint32_t flags)
+{
+    size_t i, j;
+    for (i = 0; i < last_threads.active; i++) {
+        int epid = last_threads.data[i].pid;
+        int tid = last_threads.data[i].tid;
+        if (epid != pid)
+            continue;
+        for (j = 0; j < threads.active; j++)
+            if (tid == threads.data[j].tid)
+                break;
+        if (j == threads.active)
+            printf(" %5u died\n", tid);
+        else if (!(flags & FLAG_HIDE_IDLE) || threads.data[j].run_count - last_threads.data[i].run_count)
+            printf(" %5u %2u.%0*u %2u.%0*u %5u %5u.%0*u %5u.%0*u %7u  %s\n", tid,
+                NS_TO_S_D(threads.data[j].exec_time - last_threads.data[i].exec_time),
+                NS_TO_S_D(threads.data[j].delay_time - last_threads.data[i].delay_time),
+                threads.data[j].run_count - last_threads.data[i].run_count,
+                NS_TO_S_D(threads.data[j].exec_time), NS_TO_S_D(threads.data[j].delay_time),
+                threads.data[j].run_count, threads.data[j].name);
+    }
+}
+
+static void update_table(DIR *d, uint32_t flags)
+{
+    size_t i, j;
+    struct dirent *de;
+    
+    rewinddir(d);
+    while((de = readdir(d)) != 0){
+        if(isdigit(de->d_name[0])){
+            int pid = atoi(de->d_name);
+            struct thread_info *proc_info;
+            add_thread(pid, 0, NULL);
+            proc_info = &processes.data[processes.active - 1];
+            proc_info->exec_time = 0;
+            proc_info->delay_time = 0;
+            proc_info->run_count = 0;
+            add_threads(pid, proc_info);
+        }
+    }
+    if (!(flags & FLAG_BATCH))
+        printf("\e[H\e[0J");
+    printf("Processes: %d, Threads %d\n", processes.active, threads.active);
+    switch (time_dp) {
+    case 3:
+        printf("   TID --- SINCE LAST ---- ---------- TOTAL ----------\n");
+        printf("  PID  EXEC_T  DELAY SCHED EXEC_TIME DELAY_TIM   SCHED NAME\n");
+        break;
+    case 6:
+        printf("   TID ------ SINCE LAST -------    ------------ TOTAL -----------\n");
+        printf("  PID  EXEC_TIME DELAY_TIM SCHED    EXEC_TIME   DELAY_TIME   SCHED NAME\n");
+        break;
+    default:
+        printf("   TID    -------- SINCE LAST --------       ------------- TOTAL -------------\n");
+        printf("  PID     EXEC_TIME   DELAY_TIME SCHED       EXEC_TIME      DELAY_TIME   SCHED NAME\n");
+        break;
+    }
+    for (i = 0; i < last_processes.active; i++) {
+        int pid = last_processes.data[i].pid;
+        int tid = last_processes.data[i].tid;
+        for (j = 0; j < processes.active; j++)
+            if (pid == processes.data[j].pid)
+                break;
+        if (j == processes.active)
+            printf("%5u died\n", pid);
+        else if (!(flags & FLAG_HIDE_IDLE) || processes.data[j].run_count - last_processes.data[i].run_count) {
+            printf("%5u  %2u.%0*u %2u.%0*u %5u %5u.%0*u %5u.%0*u %7u %s\n", pid,
+                NS_TO_S_D(processes.data[j].exec_time - last_processes.data[i].exec_time),
+                NS_TO_S_D(processes.data[j].delay_time - last_processes.data[i].delay_time),
+                processes.data[j].run_count - last_processes.data[i].run_count,
+                NS_TO_S_D(processes.data[j].exec_time), NS_TO_S_D(processes.data[j].delay_time),
+                processes.data[j].run_count, processes.data[j].name);
+            if (flags & FLAG_SHOW_THREADS)
+                print_threads(pid, flags);
+        }
+    }
+
+    {
+        struct thread_table tmp;
+        tmp = last_processes;
+        last_processes = processes;
+        processes = tmp;
+        processes.active = 0;
+        tmp = last_threads;
+        last_threads = threads;
+        threads = tmp;
+        threads.active = 0;
+    }
+}
+
+void
+sig_abort(int signum)
+{
+    printf("\e[?47l");
+    exit(0);
+}
+
+
+int schedtop_main(int argc, char **argv)
+{
+    int c;
+    DIR *d;
+    struct dirent *de;
+    char *namefilter = 0;
+    int pidfilter = 0;
+    uint32_t flags = 0;    
+    int delay = 3000000;
+    float delay_f;
+
+    while(1) {
+        c = getopt(argc, argv, "d:ibtamun");
+        if (c == EOF)
+            break;
+        switch (c) {
+        case 'd':
+            delay_f = atof(optarg);
+            delay = delay_f * 1000000;
+            break;
+        case 'b':
+            flags |= FLAG_BATCH;
+            break;
+        case 'i':
+            flags |= FLAG_HIDE_IDLE;
+            break;
+        case 't':
+            flags |= FLAG_SHOW_THREADS;
+            break;
+        case 'a':
+            flags |= FLAG_USE_ALTERNATE_SCREEN;
+            break;
+        case 'm':
+            time_dp = 3;
+            time_div = 1000000;
+            break;
+        case 'u':
+            time_dp = 6;
+            time_div = 1000;
+            break;
+        case 'n':
+            time_dp = 9;
+            time_div = 1;
+            break;
+        }
+    }
+
+    d = opendir("/proc");
+    if(d == 0) return -1;
+
+    if (!(flags & FLAG_BATCH)) {
+        if(flags & FLAG_USE_ALTERNATE_SCREEN) {
+            signal(SIGINT, sig_abort);
+            signal(SIGPIPE, sig_abort);
+            signal(SIGTERM, sig_abort);
+            printf("\e7\e[?47h");
+        }
+        printf("\e[2J");
+    }
+    while (1) {
+        update_table(d, flags);
+        usleep(delay);
+    }
+    closedir(d);
+    return 0;
+}
+
diff --git a/sendevent.c b/sendevent.c
new file mode 100644
index 0000000..1608e6c
--- /dev/null
+++ b/sendevent.c
@@ -0,0 +1,80 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdint.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+//#include <linux/input.h> // this does not compile
+#include <errno.h>
+
+
+// from <linux/input.h>
+
+struct input_event {
+	struct timeval time;
+	__u16 type;
+	__u16 code;
+	__s32 value;
+};
+
+#define EVIOCGVERSION		_IOR('E', 0x01, int)			/* get driver version */
+#define EVIOCGID		_IOR('E', 0x02, struct input_id)	/* get device ID */
+#define EVIOCGKEYCODE		_IOR('E', 0x04, int[2])			/* get keycode */
+#define EVIOCSKEYCODE		_IOW('E', 0x04, int[2])			/* set keycode */
+
+#define EVIOCGNAME(len)		_IOC(_IOC_READ, 'E', 0x06, len)		/* get device name */
+#define EVIOCGPHYS(len)		_IOC(_IOC_READ, 'E', 0x07, len)		/* get physical location */
+#define EVIOCGUNIQ(len)		_IOC(_IOC_READ, 'E', 0x08, len)		/* get unique identifier */
+
+#define EVIOCGKEY(len)		_IOC(_IOC_READ, 'E', 0x18, len)		/* get global keystate */
+#define EVIOCGLED(len)		_IOC(_IOC_READ, 'E', 0x19, len)		/* get all LEDs */
+#define EVIOCGSND(len)		_IOC(_IOC_READ, 'E', 0x1a, len)		/* get all sounds status */
+#define EVIOCGSW(len)		_IOC(_IOC_READ, 'E', 0x1b, len)		/* get all switch states */
+
+#define EVIOCGBIT(ev,len)	_IOC(_IOC_READ, 'E', 0x20 + ev, len)	/* get event bits */
+#define EVIOCGABS(abs)		_IOR('E', 0x40 + abs, struct input_absinfo)		/* get abs value/limits */
+#define EVIOCSABS(abs)		_IOW('E', 0xc0 + abs, struct input_absinfo)		/* set abs value/limits */
+
+#define EVIOCSFF		_IOC(_IOC_WRITE, 'E', 0x80, sizeof(struct ff_effect))	/* send a force effect to a force feedback device */
+#define EVIOCRMFF		_IOW('E', 0x81, int)			/* Erase a force effect */
+#define EVIOCGEFFECTS		_IOR('E', 0x84, int)			/* Report number of effects playable at the same time */
+
+#define EVIOCGRAB		_IOW('E', 0x90, int)			/* Grab/Release device */
+
+// end <linux/input.h>
+
+
+
+int sendevent_main(int argc, char *argv[])
+{
+    int i;
+    int fd;
+    int ret;
+    int version;
+    struct input_event event;
+
+    if(argc != 5) {
+        fprintf(stderr, "use: %s device type code value\n", argv[0]);
+        return 1;
+    }
+
+    fd = open(argv[1], O_RDWR);
+    if(fd < 0) {
+        fprintf(stderr, "could not open %s, %s\n", argv[optind], strerror(errno));
+        return 1;
+    }
+    if (ioctl(fd, EVIOCGVERSION, &version)) {
+        fprintf(stderr, "could not get driver version for %s, %s\n", argv[optind], strerror(errno));
+        return 1;
+    }
+    memset(&event, 0, sizeof(event));
+    event.type = atoi(argv[2]);
+    event.code = atoi(argv[3]);
+    event.value = atoi(argv[4]);
+    ret = write(fd, &event, sizeof(event));
+    if(ret < sizeof(event)) {
+        fprintf(stderr, "write event failed, %s\n", strerror(errno));
+        return -1;
+    }
+    return 0;
+}
diff --git a/setconsole.c b/setconsole.c
new file mode 100644
index 0000000..b0ce13f
--- /dev/null
+++ b/setconsole.c
@@ -0,0 +1,164 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <string.h>
+#include <linux/kd.h>
+#include <linux/vt.h>
+#include <errno.h>
+#include <pthread.h>
+
+static int activate_thread_switch_vc;
+static void *activate_thread(void *arg)
+{
+    int res;
+    int fd = (int)arg;
+    while(activate_thread_switch_vc >= 0) {
+        do {
+            res = ioctl(fd, VT_ACTIVATE, (void*)activate_thread_switch_vc);
+        } while(res < 0 && errno == EINTR);
+        if (res < 0) {
+            fprintf(stderr, "ioctl( vcfd, VT_ACTIVATE, vtnum) failed, %d %d %s for %d\n", res, errno, strerror(errno), activate_thread_switch_vc);
+        }
+        if(activate_thread_switch_vc >= 0)
+            sleep(1);
+    }
+    return NULL;
+}
+
+
+int setconsole_main(int argc, char *argv[])
+{
+    int c;
+    int fd;
+    int res;
+
+    int mode = -1;
+    int new_vc = 0;
+    int close_vc = 0;
+    int switch_vc = -1;
+    int printvc = 0;
+    char *ttydev = "/dev/tty0";
+
+    do {
+        c = getopt(argc, argv, "d:gtncv:poh");
+        if (c == EOF)
+            break;
+        switch (c) {
+        case 'd':
+            ttydev = optarg;
+            break;
+        case 'g':
+            if(mode == KD_TEXT) {
+                fprintf(stderr, "%s: cannot specify both -g and -t\n", argv[0]);
+                exit(1);
+            }
+            mode = KD_GRAPHICS;
+            break;
+        case 't':
+            if(mode == KD_GRAPHICS) {
+                fprintf(stderr, "%s: cannot specify both -g and -t\n", argv[0]);
+                exit(1);
+            }
+            mode = KD_TEXT;
+            break;
+        case 'n':
+            new_vc = 1;
+            break;
+        case 'c':
+            close_vc = 1;
+            break;
+        case 'v':
+            switch_vc = atoi(optarg);
+            break;
+        case 'p':
+            printvc |= 1;
+            break;
+        case 'o':
+            printvc |= 2;
+            break;
+        case 'h':
+            fprintf(stderr, "%s [-d <dev>] [-v <vc>] [-gtncpoh]\n"
+                    "  -d <dev>   Use <dev> instead of /dev/tty0\n"
+                    "  -v <vc>    Switch to virtual console <vc>\n"
+                    "  -g         Switch to graphics mode\n"
+                    "  -t         Switch to text mode\n"
+                    "  -n         Create and switch to new virtual console\n"
+                    "  -c         Close unused virtual consoles\n"
+                    "  -p         Print new virtual console\n"
+                    "  -o         Print old virtual console\n"
+                    "  -h         Print help\n", argv[0]);
+            return -1;
+        case '?':
+            fprintf(stderr, "%s: invalid option -%c\n",
+                argv[0], optopt);
+            exit(1);
+        }
+    } while (1);
+    if(mode == -1 && new_vc == 0 && close_vc == 0 && switch_vc == -1 && printvc == 0) {
+        fprintf(stderr,"%s [-d <dev>] [-v <vc>] [-gtncpoh]\n", argv[0]);
+        return -1;
+    }
+
+    fd = open(ttydev, O_RDWR | O_SYNC);
+    if (fd < 0) {
+        fprintf(stderr, "cannot open %s\n", ttydev);
+        return -1;
+    }
+
+    if ((printvc && !new_vc) || (printvc & 2)) {
+        struct vt_stat vs;
+
+        res = ioctl(fd, VT_GETSTATE, &vs);
+        if (res < 0) {
+            fprintf(stderr, "ioctl(vcfd, VT_GETSTATE, &vs) failed, %d\n", res);
+        }
+        printf("%d\n", vs.v_active);
+    }
+
+    if (new_vc) {
+        int vtnum;
+        res = ioctl(fd, VT_OPENQRY, &vtnum);
+        if (res < 0 || vtnum == -1) {
+            fprintf(stderr, "ioctl(vcfd, VT_OPENQRY, &vtnum) failed, res %d, vtnum %d\n", res, vtnum);
+        }
+        switch_vc = vtnum;
+    }
+    if (switch_vc != -1) {
+        pthread_t thread;
+        pthread_attr_t attr;
+        activate_thread_switch_vc = switch_vc;
+        pthread_attr_init(&attr);
+        pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
+        pthread_create(&thread, &attr, activate_thread, (void*)fd);
+        
+        do {
+            res = ioctl(fd, VT_WAITACTIVE, (void*)switch_vc);
+        } while(res < 0 && errno == EINTR);
+        activate_thread_switch_vc = -1;
+        if (res < 0) {
+            fprintf(stderr, "ioctl( vcfd, VT_WAITACTIVE, vtnum) failed, %d %d %s for %d\n", res, errno, strerror(errno), switch_vc);
+        }
+        if(printvc & 1)
+            printf("%d\n", switch_vc);
+
+        close(fd);
+        fd = open(ttydev, O_RDWR | O_SYNC);
+        if (fd < 0) {
+            fprintf(stderr, "cannot open %s\n", ttydev);
+            return -1;
+        }
+    }
+    if (close_vc) {
+        res = ioctl(fd, VT_DISALLOCATE, 0);
+        if (res < 0) {
+            fprintf(stderr, "ioctl(vcfd, VT_DISALLOCATE, 0) failed, %d\n", res);
+        }
+    }
+    if (mode != -1) {
+        if (ioctl(fd, KDSETMODE, (void*)mode) < 0) {
+            fprintf(stderr, "KDSETMODE %d failed\n", mode);
+            return -1;
+        }
+    }
+    return 0;
+}
diff --git a/setkey.c b/setkey.c
new file mode 100644
index 0000000..1ff2774
--- /dev/null
+++ b/setkey.c
@@ -0,0 +1,89 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <string.h>
+#include <linux/kd.h>
+#include <linux/vt.h>
+#include <errno.h>
+
+static void setkey_usage(char *argv[])
+{
+    fprintf(stderr, "%s [-t <table>] [-k <index>] [-v value] [-r] [-h]\n"
+            "  -t <table> Select table\n"
+            "  -k <index> Select key\n"
+            "  -v <value> Set entry\n"
+            "  -r         Read current entry\n"
+            "  -h         Print help\n", argv[0]);
+}
+
+#define TTYDEV	"/dev/tty0"
+
+int setkey_main(int argc, char *argv[])
+{
+    int fd;
+    struct kbentry kbe;
+    int did_something = 0;
+
+    kbe.kb_table = 0;
+    kbe.kb_index = -1;
+    kbe.kb_value = 0;
+
+    fd = open(TTYDEV, O_RDWR | O_SYNC);
+    if (fd < 0) {
+        fprintf(stderr, "open %s: %s\n", TTYDEV, strerror(errno));
+        return 1;
+    }
+
+    do {
+        int c, ret;
+
+        c = getopt(argc, argv, "t:k:v:hr");
+        if (c == EOF)
+            break;
+
+        switch (c) {
+        case 't':
+            kbe.kb_table = strtol(optarg, NULL, 0);
+            break;
+        case 'k':
+            kbe.kb_index = strtol(optarg, NULL, 0);
+            break;
+        case 'v':
+            kbe.kb_value = strtol(optarg, NULL, 0);
+            ret = ioctl(fd, KDSKBENT, &kbe);
+            if (ret < 0) {
+                fprintf(stderr, "KDSKBENT %d %d %d failed: %s\n",
+                        kbe.kb_table, kbe.kb_index, kbe.kb_value,
+                        strerror(errno));
+                return 1;
+            }
+            did_something = 1;
+            break;
+        case 'r':
+            ret = ioctl(fd, KDGKBENT, &kbe);
+            if (ret < 0) {
+                fprintf(stderr, "KDGKBENT %d %d  failed: %s\n",
+                        kbe.kb_table, kbe.kb_index, strerror(errno));
+                return 1;
+            }
+            printf("0x%x 0x%x 0x%x\n",
+                   kbe.kb_table, kbe.kb_index, kbe.kb_value);
+            did_something = 1;
+            break;
+        case 'h':
+            setkey_usage(argv);
+            return 1;
+        case '?':
+            fprintf(stderr, "%s: invalid option -%c\n",
+                argv[0], optopt);
+            return 1;
+        }
+    } while (1);
+
+    if(optind != argc || !did_something) {
+        setkey_usage(argv);
+        return 1;
+    }
+
+    return 0;
+}
diff --git a/setprop.c b/setprop.c
new file mode 100644
index 0000000..63ad2b4
--- /dev/null
+++ b/setprop.c
@@ -0,0 +1,18 @@
+#include <stdio.h>
+
+#include <cutils/properties.h>
+
+int setprop_main(int argc, char *argv[])
+{
+    if(argc != 3) {
+        fprintf(stderr,"usage: setprop <key> <value>\n");
+        return 1;
+    }
+
+    if(property_set(argv[1], argv[2])){
+        fprintf(stderr,"could not set property\n");
+        return 1;
+    }
+
+    return 0;
+}
diff --git a/sleep.c b/sleep.c
new file mode 100644
index 0000000..c09ae03
--- /dev/null
+++ b/sleep.c
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) 2008, The Android Open Source Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * 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.
+ *  * Neither the name of Google, Inc. 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 COPYRIGHT HOLDERS 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
+ * COPYRIGHT OWNER 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 <unistd.h>
+#include <stdlib.h>
+
+static void
+usage(const char *s)
+{
+    fprintf(stderr, "USAGE: %s SECONDS\n", s);
+    exit(-1);
+}
+
+int sleep_main(int argc, char *argv[])
+{
+    unsigned long seconds;
+    char *endptr;
+
+    if (argc != 2) {
+        usage(argv[0]);
+    }
+
+    seconds = strtoul(argv[1], &endptr, 10);
+
+    if (endptr == argv[1]) {
+        usage(argv[0]);
+    }
+
+
+    sleep((unsigned int)seconds);
+   
+    return 0;
+}
+
+
diff --git a/smd.c b/smd.c
new file mode 100644
index 0000000..91e495c
--- /dev/null
+++ b/smd.c
@@ -0,0 +1,41 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <fcntl.h>
+#include <errno.h>
+
+int smd_main(int argc, char **argv)
+{
+    int fd, len, r, port = 0;
+    char devname[32];
+    argc--;
+    argv++;
+
+    if((argc > 0) && (argv[0][0] == '-')) {
+        port = atoi(argv[0] + 1);
+        argc--;
+        argv++;
+    }
+
+    sprintf(devname,"/dev/smd%d",port);
+    fd = open(devname, O_WRONLY);
+    if(fd < 0) {
+        fprintf(stderr,"failed to open smd0 - %s\n",
+            strerror(errno));
+        return -1;
+    }
+    while(argc > 0) {
+        len = strlen(argv[0]);
+        r = write(fd, argv[0], len);
+        if(r != len) {
+            fprintf(stderr,"failed to write smd0 (%d) %s\n",
+                r, strerror(errno));
+            return -1;
+        }
+        argc--;
+        argv++;
+        write(fd, argc ? " " : "\r", 1);
+    }
+    close(fd);
+    return 0;       
+}
diff --git a/start.c b/start.c
new file mode 100644
index 0000000..3bd9fbb
--- /dev/null
+++ b/start.c
@@ -0,0 +1,20 @@
+
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <cutils/properties.h>
+
+int start_main(int argc, char *argv[])
+{
+    char buf[1024];
+    if(argc > 1) {
+        property_set("ctl.start", argv[1]);
+    } else {
+        /* default to "start zygote" "start runtime" */
+        property_set("ctl.start", "zygote");
+        property_set("ctl.start", "runtime");
+    }
+    
+    return 0;
+}
diff --git a/stop.c b/stop.c
new file mode 100644
index 0000000..05baffd
--- /dev/null
+++ b/stop.c
@@ -0,0 +1,20 @@
+#include <stdio.h>
+#include <string.h>
+
+#include <cutils/properties.h>
+
+int stop_main(int argc, char *argv[])
+{
+    char buf[1024];
+
+    if(argc > 1) {
+        property_set("ctl.stop", argv[1]);
+    } else{
+        /* default to "stop runtime" "stop zygote" */
+        property_set("ctl.stop", "runtime");
+        property_set("ctl.stop", "zygote");
+    }
+
+    return 0;
+}
+
diff --git a/sync.c b/sync.c
new file mode 100644
index 0000000..8284276
--- /dev/null
+++ b/sync.c
@@ -0,0 +1,7 @@
+#include <unistd.h>
+
+int sync_main(int argc, char **argv)
+{
+	sync();
+	return 0;
+}
diff --git a/syren.c b/syren.c
new file mode 100644
index 0000000..06e329e
--- /dev/null
+++ b/syren.c
@@ -0,0 +1,154 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <malloc.h>
+
+/* ioctl crap */
+#define SYREN_RD		101
+#define SYREN_WR		102
+#define SYREN_OLD_RD	108
+#define SYREN_OLD_WR	109
+
+struct syren_io_args {
+	unsigned long	page;
+	unsigned long	addr;
+	unsigned long	value;
+};
+
+typedef struct {
+	u_char			page;
+	u_char			addr;
+	const char		*name;
+} syren_reg;
+
+static syren_reg registers[] = {
+	{ 0, 0x04, "TOGBR1" },
+	{ 0, 0x05, "TOGBR2" },
+	{ 0, 0x06, "VBDCTRL" },
+	{ 1, 0x07, "VBUCTRL" },
+	{ 1, 0x08, "VBCTRL" },
+	{ 1, 0x09, "PWDNRG" },
+	{ 1, 0x0a, "VBPOP" },
+	{ 1, 0x0b, "VBCTRL2" },
+	{ 1, 0x0f, "VAUDCTRL" },
+	{ 1, 0x10, "VAUSCTRL" },
+	{ 1, 0x11, "VAUOCTRL" },
+	{ 1, 0x12, "VAUDPLL" },
+	{ 1, 0x17, "VRPCSIMR" },
+	{ 0, 0, 0 }
+};
+
+static syren_reg *find_reg(const char *name)
+{
+	int i;
+
+	for (i = 0; registers[i].name != 0; i++) {
+		if (!strcasecmp(registers[i].name, name))
+			return &registers[i];
+	}
+
+	return NULL;
+}
+
+static int usage(void)
+{
+	fprintf(stderr, "usage: syren [r/w] [REGNAME | page:addr] (value)\n");
+	return 1;
+}
+
+int
+syren_main(int argc, char **argv)
+{
+	int cmd = -1;
+	syren_reg *r;
+	struct syren_io_args sio;
+	char name[32];
+	int fd;
+
+	if (argc < 3) {
+		return usage();
+	}
+
+	switch(argv[1][0]) {
+	case 'r':
+		cmd = SYREN_RD;
+		break;
+	case 'w':
+		cmd = SYREN_WR;
+		break;
+	case 'R':
+		cmd = SYREN_OLD_RD;
+		break;
+	case 'W':
+		cmd = SYREN_OLD_WR;
+		break;
+	default:
+		return usage();
+	}
+
+	if (cmd == SYREN_WR || cmd == SYREN_OLD_WR) {
+		if (argc < 4)
+			return usage();
+		sio.value = strtoul(argv[3], 0, 0);
+	}
+
+	fd = open("/dev/eac", O_RDONLY);
+	if (fd < 0) {
+		fprintf(stderr, "can't open /dev/eac\n");
+		return 1;
+	}
+
+	if (strcasecmp(argv[2], "all") == 0) {
+		int i;
+		if (cmd != SYREN_RD && cmd != SYREN_OLD_RD) {
+			fprintf(stderr, "can only read all registers\n");
+			return 1;
+		}
+
+		for (i = 0; registers[i].name; i++) {
+			sio.page = registers[i].page;
+			sio.addr = registers[i].addr;
+			if (ioctl(fd, cmd, &sio) < 0) {
+				fprintf(stderr, "%s: error\n", registers[i].name);
+			} else {
+				fprintf(stderr, "%s: %04x\n", registers[i].name, sio.value);
+			}
+		}
+
+		close(fd);
+		return 0;
+	}
+
+	r = find_reg(argv[2]);
+	if (r == NULL) {
+		strcpy(name, argv[2]);
+		char *addr_str = strchr(argv[2], ':');
+		if (addr_str == NULL)
+			return usage();
+		*addr_str++ = 0;
+		sio.page = strtoul(argv[2], 0, 0);
+		sio.addr = strtoul(addr_str, 0, 0);
+	} else {
+		strcpy(name, r->name);
+		sio.page = r->page;
+		sio.addr = r->addr;
+	}
+
+	if (ioctl(fd, cmd, &sio) < 0) {
+		fprintf(stderr, "ioctl(%d) failed\n", cmd);
+		return 1;
+	}
+
+	if (cmd == SYREN_RD || cmd == SYREN_OLD_RD) {
+		printf("%s: %04x\n", name, sio.value);
+	} else {
+		printf("wrote %04x to %s\n", sio.value, name);
+	}
+
+	close(fd);
+
+	return 0;
+}
+
diff --git a/toolbox.c b/toolbox.c
new file mode 100644
index 0000000..0eac390
--- /dev/null
+++ b/toolbox.c
@@ -0,0 +1,57 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+int main(int, char **);
+
+static int toolbox_main(int argc, char **argv)
+{
+    // "toolbox foo ..." is equivalent to "foo ..."
+    if (argc > 1) {
+        return main(argc - 1, argv + 1);
+    } else {
+        printf("Toolbox!\n");
+        return 0;
+    }
+}
+
+#define TOOL(name) int name##_main(int, char**);
+#include "tools.h"
+#undef TOOL
+
+static struct 
+{
+    const char *name;
+    int (*func)(int, char**);
+} tools[] = {
+    { "toolbox", toolbox_main },
+#define TOOL(name) { #name, name##_main },
+#include "tools.h"
+#undef TOOL
+    { 0, 0 },
+};
+
+int main(int argc, char **argv)
+{
+    int i;
+    char *name = argv[0];
+
+    if((argc > 1) && (argv[1][0] == '@')) {
+        name = argv[1] + 1;
+        argc--;
+        argv++;
+    } else {
+        char *cmd = strrchr(argv[0], '/');
+        if (cmd)
+            name = cmd + 1;
+    }
+
+    for(i = 0; tools[i].name; i++){
+        if(!strcmp(tools[i].name, name)){
+            return tools[i].func(argc, argv);
+        }
+    }
+
+    printf("%s: no such tool\n", argv[0]);
+    return -1;
+}
diff --git a/top.c b/top.c
new file mode 100644
index 0000000..daade6d
--- /dev/null
+++ b/top.c
@@ -0,0 +1,572 @@
+/*
+ * Copyright (c) 2008, The Android Open Source Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * 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.
+ *  * Neither the name of Google, Inc. 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 COPYRIGHT HOLDERS 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
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <ctype.h>
+#include <dirent.h>
+#include <grp.h>
+#include <pwd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <cutils/sched_policy.h>
+
+struct cpu_info {
+    long unsigned utime, ntime, stime, itime;
+    long unsigned iowtime, irqtime, sirqtime;
+};
+
+#define PROC_NAME_LEN 64
+#define THREAD_NAME_LEN 32
+
+struct proc_info {
+    struct proc_info *next;
+    pid_t pid;
+    pid_t tid;
+    uid_t uid;
+    gid_t gid;
+    char name[PROC_NAME_LEN];
+    char tname[THREAD_NAME_LEN];
+    char state;
+    long unsigned utime;
+    long unsigned stime;
+    long unsigned delta_utime;
+    long unsigned delta_stime;
+    long unsigned delta_time;
+    long vss;
+    long rss;
+    int num_threads;
+    char policy[32];
+};
+
+struct proc_list {
+    struct proc_info **array;
+    int size;
+};
+
+#define die(...) { fprintf(stderr, __VA_ARGS__); exit(EXIT_FAILURE); }
+
+#define INIT_PROCS 50
+#define THREAD_MULT 8
+static struct proc_info **old_procs, **new_procs;
+static int num_old_procs, num_new_procs;
+static struct proc_info *free_procs;
+static int num_used_procs, num_free_procs;
+
+static int max_procs, delay, iterations, threads;
+
+static struct cpu_info old_cpu, new_cpu;
+
+static struct proc_info *alloc_proc(void);
+static void free_proc(struct proc_info *proc);
+static void read_procs(void);
+static int read_stat(char *filename, struct proc_info *proc);
+static void read_policy(int pid, struct proc_info *proc);
+static void add_proc(int proc_num, struct proc_info *proc);
+static int read_cmdline(char *filename, struct proc_info *proc);
+static int read_status(char *filename, struct proc_info *proc);
+static void print_procs(void);
+static struct proc_info *find_old_proc(pid_t pid, pid_t tid);
+static void free_old_procs(void);
+static int (*proc_cmp)(const void *a, const void *b);
+static int proc_cpu_cmp(const void *a, const void *b);
+static int proc_vss_cmp(const void *a, const void *b);
+static int proc_rss_cmp(const void *a, const void *b);
+static int proc_thr_cmp(const void *a, const void *b);
+static int numcmp(long long a, long long b);
+static void usage(char *cmd);
+
+int top_main(int argc, char *argv[]) {
+    int i;
+
+    num_used_procs = num_free_procs = 0;
+
+    max_procs = 0;
+    delay = 3;
+    iterations = -1;
+    proc_cmp = &proc_cpu_cmp;
+    for (i = 1; i < argc; i++) {
+        if (!strcmp(argv[i], "-m")) {
+            if (i + 1 >= argc) {
+                fprintf(stderr, "Option -m expects an argument.\n");
+                usage(argv[0]);
+                exit(EXIT_FAILURE);
+            }
+            max_procs = atoi(argv[++i]);
+            continue;
+        }
+        if (!strcmp(argv[i], "-n")) {
+            if (i + 1 >= argc) {
+                fprintf(stderr, "Option -n expects an argument.\n");
+                usage(argv[0]);
+                exit(EXIT_FAILURE);
+            }
+            iterations = atoi(argv[++i]);
+            continue;
+        }
+        if (!strcmp(argv[i], "-d")) {
+            if (i + 1 >= argc) {
+                fprintf(stderr, "Option -d expects an argument.\n");
+                usage(argv[0]);
+                exit(EXIT_FAILURE);
+            }
+            delay = atoi(argv[++i]);
+            continue;
+        }
+        if (!strcmp(argv[i], "-s")) {
+            if (i + 1 >= argc) {
+                fprintf(stderr, "Option -s expects an argument.\n");
+                usage(argv[0]);
+                exit(EXIT_FAILURE);
+            }
+            ++i;
+            if (!strcmp(argv[i], "cpu")) { proc_cmp = &proc_cpu_cmp; continue; }
+            if (!strcmp(argv[i], "vss")) { proc_cmp = &proc_vss_cmp; continue; }
+            if (!strcmp(argv[i], "rss")) { proc_cmp = &proc_rss_cmp; continue; }
+            if (!strcmp(argv[i], "thr")) { proc_cmp = &proc_thr_cmp; continue; }
+            fprintf(stderr, "Invalid argument \"%s\" for option -s.\n", argv[i]);
+            exit(EXIT_FAILURE);
+        }
+        if (!strcmp(argv[i], "-t")) { threads = 1; continue; }
+        if (!strcmp(argv[i], "-h")) {
+            usage(argv[0]);
+            exit(EXIT_SUCCESS);
+        }
+        fprintf(stderr, "Invalid argument \"%s\".\n", argv[i]);
+        usage(argv[0]);
+        exit(EXIT_FAILURE);
+    }
+
+    if (threads && proc_cmp == &proc_thr_cmp) {
+        fprintf(stderr, "Sorting by threads per thread makes no sense!\n");
+        exit(EXIT_FAILURE);
+    }
+
+    free_procs = NULL;
+
+    num_new_procs = num_old_procs = 0;
+    new_procs = old_procs = NULL;
+
+    read_procs();
+    while ((iterations == -1) || (iterations-- > 0)) {
+        old_procs = new_procs;
+        num_old_procs = num_new_procs;
+        memcpy(&old_cpu, &new_cpu, sizeof(old_cpu));
+        sleep(delay);
+        read_procs();
+        print_procs();
+        free_old_procs();
+    }
+
+    return 0;
+}
+
+static struct proc_info *alloc_proc(void) {
+    struct proc_info *proc;
+
+    if (free_procs) {
+        proc = free_procs;
+        free_procs = free_procs->next;
+        num_free_procs--;
+    } else {
+        proc = malloc(sizeof(*proc));
+        if (!proc) die("Could not allocate struct process_info.\n");
+    }
+
+    num_used_procs++;
+
+    return proc;
+}
+
+static void free_proc(struct proc_info *proc) {
+    proc->next = free_procs;
+    free_procs = proc;
+
+    num_used_procs--;
+    num_free_procs++;
+}
+
+#define MAX_LINE 256
+
+static void read_procs(void) {
+    DIR *proc_dir, *task_dir;
+    struct dirent *pid_dir, *tid_dir;
+    char filename[64];
+    FILE *file;
+    int proc_num;
+    struct proc_info *proc;
+    pid_t pid, tid;
+
+    int i;
+
+    proc_dir = opendir("/proc");
+    if (!proc_dir) die("Could not open /proc.\n");
+
+    new_procs = calloc(INIT_PROCS * (threads ? THREAD_MULT : 1), sizeof(struct proc_info *));
+    num_new_procs = INIT_PROCS * (threads ? THREAD_MULT : 1);
+
+    file = fopen("/proc/stat", "r");
+    if (!file) die("Could not open /proc/stat.\n");
+    fscanf(file, "cpu  %lu %lu %lu %lu %lu %lu %lu", &new_cpu.utime, &new_cpu.ntime, &new_cpu.stime,
+            &new_cpu.itime, &new_cpu.iowtime, &new_cpu.irqtime, &new_cpu.sirqtime);
+    fclose(file);
+
+    proc_num = 0;
+    while ((pid_dir = readdir(proc_dir))) {
+        if (!isdigit(pid_dir->d_name[0]))
+            continue;
+
+        pid = atoi(pid_dir->d_name);
+        
+        struct proc_info cur_proc;
+        
+        if (!threads) {
+            proc = alloc_proc();
+
+            proc->pid = proc->tid = pid;
+
+            sprintf(filename, "/proc/%d/stat", pid);
+            read_stat(filename, proc);
+
+            sprintf(filename, "/proc/%d/cmdline", pid);
+            read_cmdline(filename, proc);
+
+            sprintf(filename, "/proc/%d/status", pid);
+            read_status(filename, proc);
+
+            read_policy(pid, proc);
+
+            proc->num_threads = 0;
+        } else {
+            sprintf(filename, "/proc/%d/cmdline", pid);
+            read_cmdline(filename, &cur_proc);
+
+            sprintf(filename, "/proc/%d/status", pid);
+            read_status(filename, &cur_proc);
+            
+            proc = NULL;
+        }
+
+        sprintf(filename, "/proc/%d/task", pid);
+        task_dir = opendir(filename);
+        if (!task_dir) continue;
+
+        while ((tid_dir = readdir(task_dir))) {
+            if (!isdigit(tid_dir->d_name[0]))
+                continue;
+
+            if (threads) {
+                tid = atoi(tid_dir->d_name);
+
+                proc = alloc_proc();
+
+                proc->pid = pid; proc->tid = tid;
+
+                sprintf(filename, "/proc/%d/task/%d/stat", pid, tid);
+                read_stat(filename, proc);
+
+                read_policy(tid, proc);
+
+                strcpy(proc->name, cur_proc.name);
+                proc->uid = cur_proc.uid;
+                proc->gid = cur_proc.gid;
+
+                add_proc(proc_num++, proc);
+            } else {
+                proc->num_threads++;
+            }
+        }
+
+        closedir(task_dir);
+        
+        if (!threads)
+            add_proc(proc_num++, proc);
+    }
+
+    for (i = proc_num; i < num_new_procs; i++)
+        new_procs[i] = NULL;
+
+    closedir(proc_dir);
+}
+
+static int read_stat(char *filename, struct proc_info *proc) {
+    FILE *file;
+    char buf[MAX_LINE], *open_paren, *close_paren;
+    int res, idx;
+
+    file = fopen(filename, "r");
+    if (!file) return 1;
+    fgets(buf, MAX_LINE, file);
+    fclose(file);
+
+    /* Split at first '(' and last ')' to get process name. */
+    open_paren = strchr(buf, '(');
+    close_paren = strrchr(buf, ')');
+    if (!open_paren || !close_paren) return 1;
+
+    *open_paren = *close_paren = '\0';
+    strncpy(proc->tname, open_paren + 1, THREAD_NAME_LEN);
+    proc->tname[THREAD_NAME_LEN-1] = 0;
+    
+    /* Scan rest of string. */
+    sscanf(close_paren + 1, " %c %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d "
+                 "%lu %lu %*d %*d %*d %*d %*d %*d %*d %lu %ld",
+                 &proc->state, &proc->utime, &proc->stime, &proc->vss, &proc->rss);
+
+    return 0;
+}
+
+static void add_proc(int proc_num, struct proc_info *proc) {
+    int i;
+
+    if (proc_num >= num_new_procs) {
+        new_procs = realloc(new_procs, 2 * num_new_procs * sizeof(struct proc_info *));
+        if (!new_procs) die("Could not expand procs array.\n");
+        for (i = num_new_procs; i < 2 * num_new_procs; i++)
+            new_procs[i] = NULL;
+        num_new_procs = 2 * num_new_procs;
+    }
+    new_procs[proc_num] = proc;
+}
+
+static int read_cmdline(char *filename, struct proc_info *proc) {
+    FILE *file;
+    char line[MAX_LINE];
+
+    line[0] = '\0';
+    file = fopen(filename, "r");
+    if (!file) return 1;
+    fgets(line, MAX_LINE, file);
+    fclose(file);
+    if (strlen(line) > 0) {
+        strncpy(proc->name, line, PROC_NAME_LEN);
+        proc->name[PROC_NAME_LEN-1] = 0;
+    } else
+        proc->name[0] = 0;
+    return 0;
+}
+
+static void read_policy(int pid, struct proc_info *proc) {
+    SchedPolicy p;
+    if (get_sched_policy(pid, &p) < 0)
+        strcpy(proc->policy, "unk");
+    else {
+        if (p == SP_BACKGROUND)
+            strcpy(proc->policy, "bg");
+        else if (p == SP_FOREGROUND)
+            strcpy(proc->policy, "fg");
+        else
+            strcpy(proc->policy, "er");
+    }
+}
+
+static int read_status(char *filename, struct proc_info *proc) {
+    FILE *file;
+    char line[MAX_LINE];
+    unsigned int uid, gid;
+
+    file = fopen(filename, "r");
+    if (!file) return 1;
+    while (fgets(line, MAX_LINE, file)) {
+        sscanf(line, "Uid: %u", &uid);
+        sscanf(line, "Gid: %u", &gid);
+    }
+    fclose(file);
+    proc->uid = uid; proc->gid = gid;
+    return 0;
+}
+
+static void print_procs(void) {
+    int i;
+    struct proc_info *old_proc, *proc;
+    long unsigned total_delta_time;
+    struct passwd *user;
+    struct group *group;
+    char *user_str, user_buf[20];
+    char *group_str, group_buf[20];
+
+    for (i = 0; i < num_new_procs; i++) {
+        if (new_procs[i]) {
+            old_proc = find_old_proc(new_procs[i]->pid, new_procs[i]->tid);
+            if (old_proc) {
+                new_procs[i]->delta_utime = new_procs[i]->utime - old_proc->utime;
+                new_procs[i]->delta_stime = new_procs[i]->stime - old_proc->stime;
+            } else {
+                new_procs[i]->delta_utime = 0;
+                new_procs[i]->delta_stime = 0;
+            }
+            new_procs[i]->delta_time = new_procs[i]->delta_utime + new_procs[i]->delta_stime;
+        }
+    }
+
+    total_delta_time = (new_cpu.utime + new_cpu.ntime + new_cpu.stime + new_cpu.itime
+                        + new_cpu.iowtime + new_cpu.irqtime + new_cpu.sirqtime)
+                     - (old_cpu.utime + old_cpu.ntime + old_cpu.stime + old_cpu.itime
+                        + old_cpu.iowtime + old_cpu.irqtime + old_cpu.sirqtime);
+
+    qsort(new_procs, num_new_procs, sizeof(struct proc_info *), proc_cmp);
+
+    printf("\n\n\n");
+    printf("User %ld%%, System %ld%%, IOW %ld%%, IRQ %ld%%\n",
+            ((new_cpu.utime + new_cpu.ntime) - (old_cpu.utime + old_cpu.ntime)) * 100  / total_delta_time,
+            ((new_cpu.stime ) - (old_cpu.stime)) * 100 / total_delta_time,
+            ((new_cpu.iowtime) - (old_cpu.iowtime)) * 100 / total_delta_time,
+            ((new_cpu.irqtime + new_cpu.sirqtime)
+                    - (old_cpu.irqtime + old_cpu.sirqtime)) * 100 / total_delta_time);
+    printf("User %ld + Nice %ld + Sys %ld + Idle %ld + IOW %ld + IRQ %ld + SIRQ %ld = %ld\n",
+            new_cpu.utime - old_cpu.utime,
+            new_cpu.ntime - old_cpu.ntime,
+            new_cpu.stime - old_cpu.stime,
+            new_cpu.itime - old_cpu.itime,
+            new_cpu.iowtime - old_cpu.iowtime,
+            new_cpu.irqtime - old_cpu.irqtime,
+            new_cpu.sirqtime - old_cpu.sirqtime,
+            total_delta_time);
+    printf("\n");
+    if (!threads) 
+        printf("%5s %4s %1s %5s %7s %7s %3s %-8s %s\n", "PID", "CPU%", "S", "#THR", "VSS", "RSS", "PCY", "UID", "Name");
+    else
+        printf("%5s %5s %4s %1s %7s %7s %3s %-8s %-15s %s\n", "PID", "TID", "CPU%", "S", "VSS", "RSS", "PCY", "UID", "Thread", "Proc");
+
+    for (i = 0; i < num_new_procs; i++) {
+        proc = new_procs[i];
+
+        if (!proc || (max_procs && (i >= max_procs)))
+            break;
+        user  = getpwuid(proc->uid);
+        group = getgrgid(proc->gid);
+        if (user && user->pw_name) {
+            user_str = user->pw_name;
+        } else {
+            snprintf(user_buf, 20, "%d", proc->uid);
+            user_str = user_buf;
+        }
+        if (group && group->gr_name) {
+            group_str = group->gr_name;
+        } else {
+            snprintf(group_buf, 20, "%d", proc->gid);
+            group_str = group_buf;
+        }
+        if (!threads) 
+            printf("%5d %3ld%% %c %5d %6ldK %6ldK %3s %-8.8s %s\n", proc->pid, proc->delta_time * 100 / total_delta_time, proc->state, proc->num_threads,
+                proc->vss / 1024, proc->rss * getpagesize() / 1024, proc->policy, user_str, proc->name[0] != 0 ? proc->name : proc->tname);
+        else
+            printf("%5d %5d %3ld%% %c %6ldK %6ldK %3s %-8.8s %-15s %s\n", proc->pid, proc->tid, proc->delta_time * 100 / total_delta_time, proc->state,
+                proc->vss / 1024, proc->rss * getpagesize() / 1024, proc->policy, user_str, proc->tname, proc->name);
+    }
+}
+
+static struct proc_info *find_old_proc(pid_t pid, pid_t tid) {
+    int i;
+
+    for (i = 0; i < num_old_procs; i++)
+        if (old_procs[i] && (old_procs[i]->pid == pid) && (old_procs[i]->tid == tid))
+            return old_procs[i];
+
+    return NULL;
+}
+
+static void free_old_procs(void) {
+    int i;
+
+    for (i = 0; i < num_old_procs; i++)
+        if (old_procs[i])
+            free_proc(old_procs[i]);
+
+    free(old_procs);
+}
+
+static int proc_cpu_cmp(const void *a, const void *b) {
+    struct proc_info *pa, *pb;
+
+    pa = *((struct proc_info **)a); pb = *((struct proc_info **)b);
+
+    if (!pa && !pb) return 0;
+    if (!pa) return 1;
+    if (!pb) return -1;
+
+    return -numcmp(pa->delta_time, pb->delta_time);
+}
+
+static int proc_vss_cmp(const void *a, const void *b) {
+    struct proc_info *pa, *pb;
+
+    pa = *((struct proc_info **)a); pb = *((struct proc_info **)b);
+
+    if (!pa && !pb) return 0;
+    if (!pa) return 1;
+    if (!pb) return -1;
+
+    return -numcmp(pa->vss, pb->vss);
+}
+
+static int proc_rss_cmp(const void *a, const void *b) {
+    struct proc_info *pa, *pb;
+
+    pa = *((struct proc_info **)a); pb = *((struct proc_info **)b);
+
+    if (!pa && !pb) return 0;
+    if (!pa) return 1;
+    if (!pb) return -1;
+
+    return -numcmp(pa->rss, pb->rss);
+}
+
+static int proc_thr_cmp(const void *a, const void *b) {
+    struct proc_info *pa, *pb;
+
+    pa = *((struct proc_info **)a); pb = *((struct proc_info **)b);
+
+    if (!pa && !pb) return 0;
+    if (!pa) return 1;
+    if (!pb) return -1;
+
+    return -numcmp(pa->num_threads, pb->num_threads);
+}
+
+static int numcmp(long long a, long long b) {
+    if (a < b) return -1;
+    if (a > b) return 1;
+    return 0;
+}
+
+static void usage(char *cmd) {
+    fprintf(stderr, "Usage: %s [ -m max_procs ] [ -n iterations ] [ -d delay ] [ -s sort_column ] [ -t ] [ -h ]\n"
+                    "    -m num  Maximum number of processes to display.\n"
+                    "    -n num  Updates to show before exiting.\n"
+                    "    -d num  Seconds to wait between updates.\n"
+                    "    -s col  Column to sort by (cpu,vss,rss,thr).\n"
+                    "    -t      Show threads instead of processes.\n"
+                    "    -h      Display this help screen.\n",
+        cmd);
+}
diff --git a/umount.c b/umount.c
new file mode 100644
index 0000000..92c6076
--- /dev/null
+++ b/umount.c
@@ -0,0 +1,74 @@
+
+#include <sys/mount.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <linux/loop.h>
+
+// FIXME - only one loop mount is supported at a time
+#define LOOP_DEVICE "/dev/block/loop0"
+
+static int is_loop_mount(const char* path)
+{
+    FILE* f;
+    int count;
+    char device[256];
+    char mount_path[256];
+    char rest[256];
+    int result = 0;
+    int path_length = strlen(path);
+    
+    f = fopen("/proc/mounts", "r");
+    if (!f) {
+        fprintf(stdout, "could not open /proc/mounts\n");
+        return -1;
+    }
+
+    do {
+        count = fscanf(f, "%255s %255s %255s\n", device, mount_path, rest);
+        if (count == 3) {
+            if (strcmp(LOOP_DEVICE, device) == 0 && strcmp(path, mount_path) == 0) {
+                result = 1;
+                break;
+            }
+        }
+    } while (count == 3);
+
+    fclose(f);
+    return result;
+}
+
+int umount_main(int argc, char *argv[])
+{
+    int loop, loop_fd;
+    
+    if(argc != 2) {
+        fprintf(stderr,"umount <path>\n");
+        return 1;
+    }
+
+    loop = is_loop_mount(argv[1]);
+    if(umount(argv[1])){
+        fprintf(stderr,"failed.\n");
+        return 1;
+    }
+
+    if (loop) {
+        // free the loop device
+        loop_fd = open(LOOP_DEVICE, O_RDONLY);
+        if (loop_fd < -1) {
+            perror("open loop device failed");
+            return 1;
+        }
+        if (ioctl(loop_fd, LOOP_CLR_FD, 0) < 0) {
+            perror("ioctl LOOP_CLR_FD failed");
+            return 1;
+        }
+
+        close(loop_fd);
+    }
+
+    return 0;
+}
diff --git a/uptime.c b/uptime.c
new file mode 100644
index 0000000..3d8061c
--- /dev/null
+++ b/uptime.c
@@ -0,0 +1,103 @@
+/*
+ * Copyright (c) 2010, The Android Open Source Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * 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.
+ *  * Neither the name of Google, Inc. 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 COPYRIGHT HOLDERS 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
+ * COPYRIGHT OWNER 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/time.h>
+#include <linux/ioctl.h>
+#include <linux/rtc.h>
+#include <linux/android_alarm.h>
+#include <fcntl.h>
+#include <stdio.h>
+
+
+static void format_time(int time, char* buffer) {
+    int seconds, minutes, hours, days;
+
+    seconds = time % 60;
+    time /= 60;
+    minutes = time % 60;
+    time /= 60;
+    hours = time % 24;
+    days = time / 24;
+
+    if (days > 0)
+        sprintf(buffer, "%d days, %02d:%02d:%02d", days, hours, minutes, seconds);
+    else
+        sprintf(buffer, "%02d:%02d:%02d", hours, minutes, seconds);
+}
+
+int64_t elapsedRealtime()
+{
+    struct timespec ts;
+    int fd, result;
+
+    fd = open("/dev/alarm", O_RDONLY);
+    if (fd < 0)
+        return fd;
+
+   result = ioctl(fd, ANDROID_ALARM_GET_TIME(ANDROID_ALARM_ELAPSED_REALTIME), &ts);
+   close(fd);
+
+    if (result == 0)
+        return ts.tv_sec;
+    return -1;
+}
+
+int uptime_main(int argc, char *argv[])
+{
+    float up_time, idle_time;
+    char up_string[100], idle_string[100], sleep_string[100];
+    int elapsed;
+
+    FILE* file = fopen("/proc/uptime", "r");
+    if (!file) {
+        fprintf(stderr, "Could not open /proc/uptime\n");
+        return -1;
+    }
+    if (fscanf(file, "%f %f", &up_time, &idle_time) != 2) {
+        fprintf(stderr, "Could not parse /proc/uptime\n");
+        fclose(file);
+        return -1;
+    }
+    fclose(file);
+
+    elapsed = elapsedRealtime();
+    if (elapsed < 0) {
+        fprintf(stderr, "elapsedRealtime failed\n");
+        return -1;
+    }
+
+    format_time(elapsed, up_string);
+    format_time((int)idle_time, idle_string);
+    format_time((int)(elapsed - up_time), sleep_string);
+    printf("up time: %s, idle time: %s, sleep time: %s\n", up_string, idle_string, sleep_string);
+
+    return 0;
+}
diff --git a/vmstat.c b/vmstat.c
new file mode 100644
index 0000000..600f136
--- /dev/null
+++ b/vmstat.c
@@ -0,0 +1,247 @@
+/*
+ * Copyright (c) 2008, The Android Open Source Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * 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.
+ *  * Neither the name of Google, Inc. 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 COPYRIGHT HOLDERS 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
+ * COPYRIGHT OWNER 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 <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/param.h>
+#include <unistd.h>
+
+struct state {
+    long procs_r;
+    long procs_b;
+
+    long mem_free;
+    long mem_mapped;
+    long mem_anon;
+    long mem_slab;
+
+    long sys_in;
+    long sys_cs;
+    long sys_flt;
+
+    long cpu_us;
+    long cpu_ni;
+    long cpu_sy;
+    long cpu_id;
+    long cpu_wa;
+    long cpu_ir;
+    long cpu_si;
+};
+
+#define MAX_LINE 256
+
+char line[MAX_LINE];
+
+static void read_state(struct state *s);
+static int read_meminfo(struct state *s);
+static int read_stat(struct state *s);
+static int read_vmstat(struct state *s);
+static void print_header(void);
+static void print_line(struct state *old, struct state *new);
+static void usage(char *cmd);
+
+int vmstat_main(int argc, char *argv[]) {
+    struct state s[2];
+    int iterations, delay, header_interval;
+    int toggle, count;
+    int i;
+
+    iterations = 0;
+    delay = 1;
+    header_interval = 20;
+
+    for (i = 1; i < argc; i++) {
+        if (!strcmp(argv[i], "-n")) { 
+            if (i >= argc - 1) {
+                fprintf(stderr, "Option -n requires an argument.\n");
+                exit(EXIT_FAILURE);
+            }
+            iterations = atoi(argv[++i]);
+            continue;
+        }
+        if (!strcmp(argv[i], "-d")) {
+            if (i >= argc - 1) {
+                fprintf(stderr, "Option -d requires an argument.\n");
+                exit(EXIT_FAILURE);
+            }
+            delay = atoi(argv[++i]);
+            continue;
+        }
+        if (!strcmp(argv[i], "-r")) {
+            if (i >= argc - 1) {
+                fprintf(stderr, "Option -r requires an argument.\n");
+                exit(EXIT_FAILURE);
+            }
+            header_interval = atoi(argv[++i]);
+            continue;
+        }
+        if (!strcmp(argv[i], "-h")) {
+            usage(argv[0]);
+            exit(EXIT_SUCCESS);
+        }
+        fprintf(stderr, "Invalid argument \"%s\".\n", argv[i]);
+        usage(argv[0]);
+	exit(EXIT_FAILURE);
+    }
+
+    toggle = 0;
+    count = 0;
+
+    if (!header_interval)
+        print_header();
+    read_state(&s[1 - toggle]);
+    while ((iterations == 0) || (iterations-- > 0)) {
+        sleep(delay);
+        read_state(&s[toggle]);
+        if (header_interval) {
+            if (count == 0)
+                print_header();
+            count = (count + 1) % header_interval;
+        }
+        print_line(&s[1 - toggle], &s[toggle]);
+        toggle = 1 - toggle;
+    }
+
+    return 0;
+}
+
+static void read_state(struct state *s) {
+    int error;
+
+    error = read_meminfo(s);
+    if (error) {
+        fprintf(stderr, "vmstat: could not read /proc/meminfo: %s\n", strerror(error));
+        exit(EXIT_FAILURE);
+    }
+
+    error = read_stat(s);
+    if (error) {
+        fprintf(stderr, "vmstat: could not read /proc/stat: %s\n", strerror(error));
+        exit(EXIT_FAILURE);
+    }
+
+    error = read_vmstat(s);
+    if (error) {
+        fprintf(stderr, "vmstat: could not read /proc/vmstat: %s\n", strerror(error));
+        exit(EXIT_FAILURE);
+    }
+}
+
+static int read_meminfo(struct state *s) {
+    FILE *f;
+
+    f = fopen("/proc/meminfo", "r");
+    if (!f) return errno;
+
+    while (fgets(line, MAX_LINE, f)) {
+        sscanf(line, "MemFree: %ld kB", &s->mem_free);
+        sscanf(line, "AnonPages: %ld kB", &s->mem_anon);
+        sscanf(line, "Mapped: %ld kB", &s->mem_mapped);
+        sscanf(line, "Slab: %ld kB", &s->mem_slab);
+    }
+
+    fclose(f);
+
+    return 0;
+}
+
+static int read_stat(struct state *s) {
+    FILE *f;
+
+    f = fopen("/proc/stat", "r");
+    if (!f) return errno;
+
+    while (fgets(line, MAX_LINE, f)) {
+        if (!strncmp(line, "cpu ", 4)) {
+            sscanf(line, "cpu  %ld %ld %ld %ld %ld %ld %ld",
+                &s->cpu_us, &s->cpu_ni, &s->cpu_sy, &s->cpu_id, &s->cpu_wa,
+                &s->cpu_ir, &s->cpu_si);
+        }
+        sscanf(line, "intr %ld", &s->sys_in);
+        sscanf(line, "ctxt %ld", &s->sys_cs);
+        sscanf(line, "procs_running %ld", &s->procs_r);
+        sscanf(line, "procs_blocked %ld", &s->procs_b);
+    }
+
+    fclose(f);
+
+    return 0;
+}
+
+static int read_vmstat(struct state *s) {
+    FILE *f;
+
+    f = fopen("/proc/vmstat", "r");
+    if (!f) return errno;
+
+    while (fgets(line, MAX_LINE, f)) {
+        sscanf(line, "pgmajfault %ld", &s->sys_flt);
+    }
+
+    fclose(f);
+
+    return 0;
+}
+
+static void print_header(void) {
+    printf("%-5s  %-27s  %-14s  %-17s\n", "procs", "memory", "system", "cpu");
+    printf("%2s %2s  %6s %6s %6s %6s  %4s %4s %4s  %2s %2s %2s %2s %2s %2s\n", "r", "b", "free", "mapped", "anon", "slab", "in", "cs", "flt", "us", "ni", "sy", "id", "wa", "ir");
+}
+
+/* Jiffies to percent conversion */
+#define JP(jif) ((jif) * 100 / (HZ))
+#define NORM(var) ((var) = (((var) > 99) ? (99) : (var)))
+
+static void print_line(struct state *old, struct state *new) {
+    int us, ni, sy, id, wa, ir;
+    us = JP(new->cpu_us - old->cpu_us); NORM(us);
+    ni = JP(new->cpu_ni - old->cpu_ni); NORM(ni);
+    sy = JP(new->cpu_sy - old->cpu_sy); NORM(sy);
+    id = JP(new->cpu_id - old->cpu_id); NORM(id);
+    wa = JP(new->cpu_wa - old->cpu_wa); NORM(wa);
+    ir = JP(new->cpu_ir - old->cpu_ir); NORM(ir);
+    printf("%2ld %2ld  %6ld %6ld %6ld %6ld  %4ld %4ld %4ld  %2d %2d %2d %2d %2d %2d\n",
+        new->procs_r ? (new->procs_r - 1) : 0, new->procs_b,
+        new->mem_free, new->mem_mapped, new->mem_anon, new->mem_slab,
+        new->sys_in - old->sys_in, new->sys_cs - old->sys_cs, new->sys_flt - old->sys_flt,
+        us, ni, sy, id, wa, ir);
+}
+
+static void usage(char *cmd) {
+    fprintf(stderr, "Usage: %s [ -h ] [ -n iterations ] [ -d delay ] [ -r header_repeat ]\n"
+                    "    -n iterations     How many rows of data to print.\n"
+                    "    -d delay          How long to sleep between rows.\n"
+                    "    -r header_repeat  How many rows to print before repeating\n"
+                    "                      the header.  Zero means never repeat.\n"
+                    "    -h                Displays this help screen.\n",
+        cmd);
+}
diff --git a/watchprops.c b/watchprops.c
new file mode 100644
index 0000000..d311992
--- /dev/null
+++ b/watchprops.c
@@ -0,0 +1,76 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <time.h>
+
+#include <cutils/properties.h>
+
+#include <sys/atomics.h>
+
+#define _REALLY_INCLUDE_SYS__SYSTEM_PROPERTIES_H_
+#include <sys/_system_properties.h>
+
+
+extern prop_area *__system_property_area__;
+
+typedef struct pwatch pwatch;
+
+struct pwatch
+{
+    const prop_info *pi;
+    unsigned serial;
+};
+
+static pwatch watchlist[1024];
+
+static void announce(const prop_info *pi)
+{
+    char name[PROP_NAME_MAX];
+    char value[PROP_VALUE_MAX];
+    char *x;
+    
+    __system_property_read(pi, name, value);
+
+    for(x = value; *x; x++) {
+        if((*x < 32) || (*x > 127)) *x = '.';
+    }
+
+    fprintf(stderr,"%10d %s = '%s'\n", (int) time(0), name, value);
+}
+
+int watchprops_main(int argc, char *argv[])
+{
+    prop_area *pa = __system_property_area__;
+    unsigned serial = pa->serial;
+    unsigned count = pa->count;
+    unsigned n;
+    
+    if(count >= 1024) exit(1);
+
+    for(n = 0; n < count; n++) {
+        watchlist[n].pi = __system_property_find_nth(n);
+        watchlist[n].serial = watchlist[n].pi->serial;
+    }
+
+    for(;;) {
+        do {
+            __futex_wait(&pa->serial, serial, 0);
+        } while(pa->serial == serial);
+
+        while(count < pa->count){
+            watchlist[count].pi = __system_property_find_nth(count);
+            watchlist[count].serial = watchlist[n].pi->serial;
+            announce(watchlist[count].pi);
+            count++;
+            if(count == 1024) exit(1);
+        }
+
+        for(n = 0; n < count; n++){
+            unsigned tmp = watchlist[n].pi->serial;
+            if(watchlist[n].serial != tmp) {
+                announce(watchlist[n].pi);
+                watchlist[n].serial = tmp;
+            }
+        }
+    }
+    return 0;
+}
diff --git a/wipe.c b/wipe.c
new file mode 100644
index 0000000..7e263fd
--- /dev/null
+++ b/wipe.c
@@ -0,0 +1,176 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <dirent.h>
+#include <string.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/reboot.h>
+#include <sys/stat.h>
+
+#ifndef PATH_MAX
+#define PATH_MAX 4096
+#endif
+
+
+/* Directories created by init defined in system/rootdir/init.rc */
+static char *INIT_DIRS[] = {
+    "/system/etc/ppp",
+    "/data/misc",
+    "/data/local",
+    "/data/local/tmp",
+    "/data/data",
+    "/data/app_private",
+    "/data/app",
+    NULL
+};
+
+static void wipe (const char *path);
+
+static int usage()
+{
+    fprintf(stderr, "wipe <system|data|all>\n\n"
+                    "system means '/system'\n"
+                    "data means '/data'\n");
+
+    return -1;
+}
+
+int wipe_main (int argc, char *argv[])
+{
+    char *whatToWipe;
+
+    if (argc != 2) return usage();
+
+    whatToWipe = argv[1];
+
+    if (0 == strcmp (whatToWipe, "system")) {
+        fprintf(stdout, "Wiping /system\n");
+        wipe ("/system");
+        fprintf(stdout, "Done wiping /android\n");
+    } else if (0 == strcmp (whatToWipe, "data")) {
+        fprintf(stdout, "Wiping /data\n");
+        wipe ("/data");
+        fprintf(stdout, "Done wiping /data\n");
+    } else if (0 == strcmp (whatToWipe, "all")) {
+        fprintf(stdout, "Wiping /system and /data\n");
+        wipe ("/system");
+        wipe ("/data");
+        fprintf(stdout, "Done wiping /system and /data\n");
+    } else if (0 == strcmp(whatToWipe, "nuke")) {
+		int ret;
+		fprintf(stdout, "Nuking the device...\n");
+		wipe ("/system");
+        wipe ("/data");
+		fprintf(stdout, "Device nuked! Rebooting...\n");
+		ret = reboot(RB_AUTOBOOT);
+	    if (ret < 0) {
+	        fprintf(stderr, "Reboot failed, %s\n", strerror(errno));
+	        return 1;
+	    }
+	} else {
+        return usage();
+    }
+
+    return 0;
+}
+
+static char nameBuffer[PATH_MAX];
+static struct stat statBuffer;
+
+static void wipe (const char *path) 
+{
+    DIR *dir;
+    struct dirent *de;
+    int ret;
+
+    dir = opendir(path);
+
+    if (dir == NULL) {
+        fprintf (stderr, "Error opendir'ing %s '%s'\n",
+                    path, strerror(errno));
+        return;
+    }
+
+    char *filenameOffset;
+
+    strcpy(nameBuffer, path);
+    strcat(nameBuffer, "/");
+
+    filenameOffset = nameBuffer + strlen(nameBuffer);
+
+    for (;;) {
+        de = readdir(dir);
+
+        if (de == NULL) {
+            break;
+        }
+
+        if (0 == strcmp(de->d_name, ".")
+                || 0 == strcmp(de->d_name, "..")
+                || 0 == strcmp(de->d_name, "lost+found")
+        ) {
+            continue;
+        }
+
+        strcpy(filenameOffset, de->d_name);
+
+        ret = lstat (nameBuffer, &statBuffer);
+
+        if (ret != 0) {
+            fprintf(stderr, "stat() error on '%s' '%s'\n", 
+                    nameBuffer, strerror(errno));
+        }
+
+        if(S_ISDIR(statBuffer.st_mode)) {
+            int i;
+            char *newpath;
+
+#if 0
+            closedir(dir);
+#endif
+
+            newpath = strdup(nameBuffer);
+            wipe(newpath);
+
+            /* Leave directories created by init, they have special permissions. */
+            for (i = 0; INIT_DIRS[i]; i++) {
+                if (strcmp(INIT_DIRS[i], newpath) == 0) {
+                    break;
+                }
+            }
+            if (INIT_DIRS[i] == NULL) {
+                ret = rmdir(newpath);
+                if (ret != 0) {
+                    fprintf(stderr, "rmdir() error on '%s' '%s'\n", 
+                        newpath, strerror(errno));
+                }
+            }
+
+            free(newpath);
+
+#if 0
+            dir = opendir(path);
+            if (dir == NULL) {
+                fprintf (stderr, "Error opendir'ing %s '%s'\n",
+                            path, strerror(errno));
+                return;
+            }
+#endif
+
+            strcpy(nameBuffer, path);
+            strcat(nameBuffer, "/");
+
+        } else {
+            ret = unlink(nameBuffer);
+
+            if (ret != 0) {
+                fprintf(stderr, "unlink() error on '%s' '%s'\n", 
+                    nameBuffer, strerror(errno));
+            }
+        }
+    }
+
+    closedir(dir);
+
+}