Wrote killall.

Adjusted mount, ps, utility.c, etc to handle my nifty new kernel
patches the allow busybox to run perfectly without /proc.
 -Erik
diff --git a/Changelog b/Changelog
index f0c5e2f..fd560a8 100644
--- a/Changelog
+++ b/Changelog
@@ -1,5 +1,5 @@
 0.43
-	* Wrote basename, and uptime.
+	* Wrote basename, killall, and uptime.
 	* Added freeramdisk, which will free up all memory associated
 	    with a ram disk.  Contributed by Emanuele Caratti <wiz@iol.it>
 	    and then adjusted a bit by me.
@@ -35,8 +35,8 @@
 	    - Fixes to the makefile for handling "strip"
 	* An initial telnet implementation was added by 
 	    Randolph Chung <tausq@debian.org>.
-	* Fixed a bug where "sed 's/foo/bar/g'" would go into an 
-	    infinite loop.
+	* Fixed a bug where "sed 's/foo/bar/g'" (i.e. a script w/o a "-e")
+	    would go into an infinite loop.
 
 
 	-Erik Andersen
diff --git a/applets/busybox.c b/applets/busybox.c
index 36cf0a0..cea191c 100644
--- a/applets/busybox.c
+++ b/applets/busybox.c
@@ -139,6 +139,9 @@
 #ifdef BB_KILL					//bin
 	{"kill", kill_main},
 #endif
+#ifdef BB_KILLALL				//usr/bin
+	{"killall", kill_main},
+#endif
 #ifdef BB_LENGTH				//usr/bin
 	{"length", length_main},
 #endif
diff --git a/busybox.c b/busybox.c
index 36cf0a0..cea191c 100644
--- a/busybox.c
+++ b/busybox.c
@@ -139,6 +139,9 @@
 #ifdef BB_KILL					//bin
 	{"kill", kill_main},
 #endif
+#ifdef BB_KILLALL				//usr/bin
+	{"killall", kill_main},
+#endif
 #ifdef BB_LENGTH				//usr/bin
 	{"length", length_main},
 #endif
diff --git a/busybox.def.h b/busybox.def.h
index 306133b..da34055 100644
--- a/busybox.def.h
+++ b/busybox.def.h
@@ -39,6 +39,7 @@
 // Don't turn BB_INSMOD on.  It doesn't work.
 //#define BB_INSMOD
 #define BB_KILL
+#define BB_KILLALL
 #define BB_KLOGD
 //#define BB_LENGTH
 #define BB_LN
@@ -106,8 +107,17 @@
 // pretty/useful).
 //
 //
+// Turn this on to use Erik's very cool devps, devmtab, 
+// etc. kernel drivers, thereby eliminating the need for 
+// the /proc filesystem and thereby saving lots and lots 
+// memory for more important things.
+// You can't use this and USE_PROCFS at the same time...
+//#define BB_FEATURE_USE_DEVPS_N_DEVMTAB
+//
+//
 // enable features that use the /proc filesystem (apps that 
 // break without this will tell you on compile)...
+// You can't use this and DEVPS_N_DEVMTAB at the same time...
 #define BB_FEATURE_USE_PROCFS
 //
 // Use termios to manipulate the screen ('more' is prettier with this on)
@@ -161,6 +171,6 @@
 // just like an initrd does.  Requires a kernel patch by Werner Almesberger. 
 // ftp://icaftp.epfl.ch/pub/people/almesber/misc/umount-root-*.tar.gz
 #ifdef BB_MOUNT
-#define BB_FEATURE_INIT_CHROOT
+//#define BB_FEATURE_INIT_CHROOT
 #endif
 //
diff --git a/chmod_chown_chgrp.c b/chmod_chown_chgrp.c
index 4e5e9b0..e197ee3 100644
--- a/chmod_chown_chgrp.c
+++ b/chmod_chown_chgrp.c
@@ -98,13 +98,11 @@
 	char *p;
 	const char *appUsage;
 
-	whichApp =
-		(strcmp(*argv, "chown") == 0)? 
+	whichApp = (strcmp(*argv, "chown") == 0)? 
 			CHOWN_APP : (strcmp(*argv, "chmod") == 0)? 
 				CHMOD_APP : CHGRP_APP;
 
-	appUsage =
-		(whichApp == CHOWN_APP)? 
+	appUsage = (whichApp == CHOWN_APP)? 
 			chown_usage : (whichApp == CHMOD_APP) ? chmod_usage : chgrp_usage;
 
 	if (argc < 2)
diff --git a/halt.c b/halt.c
index d61c387..f2c9828 100644
--- a/halt.c
+++ b/halt.c
@@ -27,5 +27,5 @@
 extern int halt_main(int argc, char **argv)
 {
 	/* don't assume init's pid == 1 */
-	exit(kill(findInitPid(), SIGUSR1));
+	exit(kill(findPidByName("init"), SIGUSR1));
 }
diff --git a/init/halt.c b/init/halt.c
index d61c387..f2c9828 100644
--- a/init/halt.c
+++ b/init/halt.c
@@ -27,5 +27,5 @@
 extern int halt_main(int argc, char **argv)
 {
 	/* don't assume init's pid == 1 */
-	exit(kill(findInitPid(), SIGUSR1));
+	exit(kill(findPidByName("init"), SIGUSR1));
 }
diff --git a/init/poweroff.c b/init/poweroff.c
index 7f9abf1..14dc2f5 100644
--- a/init/poweroff.c
+++ b/init/poweroff.c
@@ -27,5 +27,5 @@
 extern int poweroff_main(int argc, char **argv)
 {
 	/* don't assume init's pid == 1 */
-	exit(kill(findInitPid(), SIGUSR2));
+	exit(kill(findPidByName("init"), SIGUSR2));
 }
diff --git a/init/reboot.c b/init/reboot.c
index f782fa1..fc01ea0 100644
--- a/init/reboot.c
+++ b/init/reboot.c
@@ -27,7 +27,7 @@
 extern int reboot_main(int argc, char **argv)
 {
 	/* don't assume init's pid == 1 */
-	exit(kill(findInitPid(), SIGINT));
+	exit(kill(findPidByName("init"), SIGINT));
 }
 
 /*
diff --git a/internal.h b/internal.h
index fcb24dc..2e2556d 100644
--- a/internal.h
+++ b/internal.h
@@ -203,7 +203,7 @@
 extern char *mtab_getinfo(const char *match, const char which);
 extern int check_wildcard_match(const char* text, const char* pattern);
 extern long getNum (const char *cp);
-extern pid_t findInitPid();
+extern pid_t findPidByName( char* pidName);
 extern void *xmalloc (size_t size);
 #if defined BB_INIT || defined BB_SYSLOGD
 extern int device_open(char *device, int mode);
diff --git a/kill.c b/kill.c
index 5166212..8a99e0f 100644
--- a/kill.c
+++ b/kill.c
@@ -24,6 +24,7 @@
 #include "internal.h"
 #include <stdio.h>
 #include <stdlib.h>
+#include <errno.h>
 #include <unistd.h>
 #include <signal.h>
 #include <ctype.h>
@@ -35,6 +36,14 @@
 	"Send a signal (default is SIGTERM) to the specified process(es).\n\n"
 	"Options:\n" "\t-l\tList all signal names and numbers.\n\n";
 
+static const char *killall_usage =
+	"killall [-signal] process-name [process-name ...]\n\n"
+	"Send a signal (default is SIGTERM) to the specified process(es).\n\n"
+	"Options:\n" "\t-l\tList all signal names and numbers.\n\n";
+
+
+#define KILL	0
+#define KILLALL	1
 
 struct signal_name {
 	const char *name;
@@ -120,13 +129,19 @@
 
 extern int kill_main(int argc, char **argv)
 {
-	int sig = SIGTERM;
+	int whichApp, sig = SIGTERM;
+	const char *appUsage;
+
+	/* Figure out what we are trying to do here */
+	whichApp = (strcmp(*argv, "killall") == 0)? 
+		KILLALL : KILL; 
+	appUsage = (whichApp == KILLALL)?  killall_usage : kill_usage;
 
 	argc--;
 	argv++;
 	/* Parse any options */
 	if (argc < 1)
-		usage(kill_usage);
+		usage(appUsage);
 
 	while (argc > 0 && **argv == '-') {
 		while (*++(*argv)) {
@@ -150,7 +165,7 @@
 				}
 				break;
 			case '-':
-				usage(kill_usage);
+				usage(appUsage);
 			default:
 				{
 					if (isdigit(**argv)) {
@@ -186,32 +201,34 @@
 
   do_it_now:
 
-	while (--argc >= 0) {
-		int pid;
-		struct stat statbuf;
-		char pidpath[20] = "/proc/";
+	if (whichApp == KILL) {
+		/* Looks like they want to do a kill. Do that */
+		while (--argc >= 0) {
+			int pid;
 
-		if (!isdigit(**argv)) {
-			fprintf(stderr, "bad PID: %s\n", *argv);
-			exit(FALSE);
+			if (!isdigit(**argv))
+				fatalError( "Bad PID: %s\n", strerror(errno));
+			pid = strtol(*argv, NULL, 0);
+			if (kill(pid, sig) != 0) 
+				fatalError( "Could not kill pid '%d': %s\n", pid, strerror(errno));
+			argv++;
 		}
-		pid = atoi(*argv);
-		snprintf(pidpath, 20, "/proc/%s/stat", *argv);
-		if (stat(pidpath, &statbuf) != 0) {
-			fprintf(stderr, "kill: (%d) - No such pid\n", pid);
-			exit(FALSE);
+	} else {
+		/* Looks like they want to do a killall.  Do that */
+		while (--argc >= 0) {
+			int pid;
+
+			while((pid = findPidByName( *argv))) {
+				if (kill(pid, sig) != 0) 
+					fatalError( "Could not kill pid '%d': %s\n", pid, strerror(errno));
+			}
+			argv++;
 		}
-		fprintf(stderr, "sig = %d\n", sig);
-		if (kill(pid, sig) != 0) {
-			perror(*argv);
-			exit(FALSE);
-		}
-		argv++;
 	}
+
 	exit(TRUE);
 
 
   end:
-	fprintf(stderr, "bad signal name: %s\n", *argv);
-	exit(TRUE);
+	fatalError( "bad signal name: %s\n", *argv);
 }
diff --git a/mount.c b/mount.c
index 37f789d..f46664b 100644
--- a/mount.c
+++ b/mount.c
@@ -46,6 +46,10 @@
 #include <sys/mount.h>
 #include <ctype.h>
 #include <fstab.h>
+#if defined BB_FEATURE_USE_DEVPS_N_DEVMTAB
+#include <linux/devmtab.h>
+#endif
+
 
 #if defined BB_FEATURE_MOUNT_LOOP
 #include <fcntl.h>
@@ -221,9 +225,8 @@
 {
 	int status = 0;
 
-	char buf[255];
-
 #if defined BB_FEATURE_USE_PROCFS
+	char buf[255];
 	if (strcmp(filesystemType, "auto") == 0) {
 		FILE *f = fopen("/proc/filesystems", "r");
 
@@ -252,6 +255,43 @@
 		fclose(f);
 	} else
 #endif
+#if defined BB_FEATURE_USE_DEVPS_N_DEVMTAB
+	if (strcmp(filesystemType, "auto") == 0) {
+		int fd, i, numfilesystems;
+		char device[] = "/dev/mtab";
+		struct k_fstype *fslist;
+
+		/* open device */ 
+		fd = open(device, O_RDONLY);
+		if (fd < 0)
+			fatalError("open failed for `%s': %s\n", device, strerror (errno));
+
+		/* How many filesystems?  We need to know to allocate enough space */
+		numfilesystems = ioctl (fd, DEVMTAB_COUNT_FILESYSTEMS);
+		if (numfilesystems<0)
+			fatalError("\nDEVMTAB_COUNT_FILESYSTEMS: %s\n", strerror (errno));
+		fslist = (struct k_fstype *) calloc ( numfilesystems, sizeof(struct k_fstype));
+
+		/* Grab the list of available filesystems */
+		status = ioctl (fd, DEVMTAB_GET_FILESYSTEMS, fslist);
+		if (status<0)
+			fatalError("\nDEVMTAB_GET_FILESYSTEMS: %s\n", strerror (errno));
+
+		/* Walk the list trying to mount filesystems 
+		 * that do not claim to be nodev filesystems */
+		for( i = 0 ; i < numfilesystems ; i++) {
+			if (fslist[i].mnt_nodev)
+				continue;
+			status = do_mount(blockDevice, directory, fslist[i].mnt_type,
+							  flags | MS_MGC_VAL, string_flags,
+							  useMtab, fakeIt, mtab_opts);
+			if (status == TRUE)
+				break;
+		}
+		free( fslist);
+		close(fd);
+	} else
+#endif
 	{
 		status = do_mount(blockDevice, directory, filesystemType,
 						  flags | MS_MGC_VAL, string_flags, useMtab,
@@ -285,6 +325,39 @@
 	/* Only compiled in if BB_MTAB is not defined */
 	whine_if_fstab_is_missing();
 
+#if defined BB_FEATURE_USE_DEVPS_N_DEVMTAB
+	if (argc == 1) {
+		int fd, i, numfilesystems;
+		char device[] = "/dev/mtab";
+		struct k_mntent *mntentlist;
+
+		/* open device */ 
+		fd = open(device, O_RDONLY);
+		if (fd < 0)
+			fatalError("open failed for `%s': %s\n", device, strerror (errno));
+
+		/* How many mounted filesystems?  We need to know to 
+		 * allocate enough space for later... */
+		numfilesystems = ioctl (fd, DEVMTAB_COUNT_MOUNTS);
+		if (numfilesystems<0)
+			fatalError( "\nDEVMTAB_COUNT_MOUNTS: %s\n", strerror (errno));
+		mntentlist = (struct k_mntent *) calloc ( numfilesystems, sizeof(struct k_mntent));
+		
+		/* Grab the list of mounted filesystems */
+		if (ioctl (fd, DEVMTAB_GET_MOUNTS, mntentlist)<0)
+			fatalError( "\nDEVMTAB_GET_MOUNTS: %s\n", strerror (errno));
+
+		for( i = 0 ; i < numfilesystems ; i++) {
+			fprintf( stdout, "%s %s %s %s %d %d\n", mntentlist[i].mnt_fsname,
+					mntentlist[i].mnt_dir, mntentlist[i].mnt_type, 
+					mntentlist[i].mnt_opts, mntentlist[i].mnt_freq, 
+					mntentlist[i].mnt_passno);
+		}
+		free( mntentlist);
+		close(fd);
+		exit(TRUE);
+	}
+#else
 	if (argc == 1) {
 		FILE *mountTable = setmntent(mtab_file, "r");
 
@@ -310,7 +383,7 @@
 		}
 		exit(TRUE);
 	}
-
+#endif
 
 	/* Parse options */
 	i = --argc;
@@ -372,10 +445,9 @@
 		struct mntent *m;
 		FILE *f = setmntent("/etc/fstab", "r");
 
-		if (f == NULL) {
-			perror("/etc/fstab");
-			exit(FALSE);
-		}
+		if (f == NULL)
+			fatalError( "\nCannot ream /etc/fstab: %s\n", strerror (errno));
+
 		while ((m = getmntent(f)) != NULL) {
 			// If the file system isn't noauto, 
 			// and isn't swap or nfs, then mount it
diff --git a/poweroff.c b/poweroff.c
index 7f9abf1..14dc2f5 100644
--- a/poweroff.c
+++ b/poweroff.c
@@ -27,5 +27,5 @@
 extern int poweroff_main(int argc, char **argv)
 {
 	/* don't assume init's pid == 1 */
-	exit(kill(findInitPid(), SIGUSR2));
+	exit(kill(findPidByName("init"), SIGUSR2));
 }
diff --git a/procps/kill.c b/procps/kill.c
index 5166212..8a99e0f 100644
--- a/procps/kill.c
+++ b/procps/kill.c
@@ -24,6 +24,7 @@
 #include "internal.h"
 #include <stdio.h>
 #include <stdlib.h>
+#include <errno.h>
 #include <unistd.h>
 #include <signal.h>
 #include <ctype.h>
@@ -35,6 +36,14 @@
 	"Send a signal (default is SIGTERM) to the specified process(es).\n\n"
 	"Options:\n" "\t-l\tList all signal names and numbers.\n\n";
 
+static const char *killall_usage =
+	"killall [-signal] process-name [process-name ...]\n\n"
+	"Send a signal (default is SIGTERM) to the specified process(es).\n\n"
+	"Options:\n" "\t-l\tList all signal names and numbers.\n\n";
+
+
+#define KILL	0
+#define KILLALL	1
 
 struct signal_name {
 	const char *name;
@@ -120,13 +129,19 @@
 
 extern int kill_main(int argc, char **argv)
 {
-	int sig = SIGTERM;
+	int whichApp, sig = SIGTERM;
+	const char *appUsage;
+
+	/* Figure out what we are trying to do here */
+	whichApp = (strcmp(*argv, "killall") == 0)? 
+		KILLALL : KILL; 
+	appUsage = (whichApp == KILLALL)?  killall_usage : kill_usage;
 
 	argc--;
 	argv++;
 	/* Parse any options */
 	if (argc < 1)
-		usage(kill_usage);
+		usage(appUsage);
 
 	while (argc > 0 && **argv == '-') {
 		while (*++(*argv)) {
@@ -150,7 +165,7 @@
 				}
 				break;
 			case '-':
-				usage(kill_usage);
+				usage(appUsage);
 			default:
 				{
 					if (isdigit(**argv)) {
@@ -186,32 +201,34 @@
 
   do_it_now:
 
-	while (--argc >= 0) {
-		int pid;
-		struct stat statbuf;
-		char pidpath[20] = "/proc/";
+	if (whichApp == KILL) {
+		/* Looks like they want to do a kill. Do that */
+		while (--argc >= 0) {
+			int pid;
 
-		if (!isdigit(**argv)) {
-			fprintf(stderr, "bad PID: %s\n", *argv);
-			exit(FALSE);
+			if (!isdigit(**argv))
+				fatalError( "Bad PID: %s\n", strerror(errno));
+			pid = strtol(*argv, NULL, 0);
+			if (kill(pid, sig) != 0) 
+				fatalError( "Could not kill pid '%d': %s\n", pid, strerror(errno));
+			argv++;
 		}
-		pid = atoi(*argv);
-		snprintf(pidpath, 20, "/proc/%s/stat", *argv);
-		if (stat(pidpath, &statbuf) != 0) {
-			fprintf(stderr, "kill: (%d) - No such pid\n", pid);
-			exit(FALSE);
+	} else {
+		/* Looks like they want to do a killall.  Do that */
+		while (--argc >= 0) {
+			int pid;
+
+			while((pid = findPidByName( *argv))) {
+				if (kill(pid, sig) != 0) 
+					fatalError( "Could not kill pid '%d': %s\n", pid, strerror(errno));
+			}
+			argv++;
 		}
-		fprintf(stderr, "sig = %d\n", sig);
-		if (kill(pid, sig) != 0) {
-			perror(*argv);
-			exit(FALSE);
-		}
-		argv++;
 	}
+
 	exit(TRUE);
 
 
   end:
-	fprintf(stderr, "bad signal name: %s\n", *argv);
-	exit(TRUE);
+	fatalError( "bad signal name: %s\n", *argv);
 }
diff --git a/procps/ps.c b/procps/ps.c
index 207cdaa..b0933ab 100644
--- a/procps/ps.c
+++ b/procps/ps.c
@@ -1,34 +1,47 @@
 /* vi: set sw=4 ts=4: */
 /*
- * Mini ps implementation for busybox
+ * Mini ps implementation(s) for busybox
+ *
+ * Copyright (C) 1999 by Lineo, inc.  Written by Erik Andersen
+ * <andersen@lineo.com>, <andersee@debian.org>
  *
  *
- * Copyright (C) 1999 by Lineo, inc.
- * Written by Erik Andersen <andersen@lineo.com>, <andersee@debian.org>
+ * This contains _two_ implementations of ps for Linux.  One uses the
+ * traditional /proc virtual filesystem, and the other use the devps kernel
+ * driver (written by Erik Andersen to avoid using /proc thereby saving 100k+).
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
  *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
  *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA 02111-1307 USA
  *
  */
 
 #include "internal.h"
+#include <stdio.h>
 #include <unistd.h>
 #include <dirent.h>
-#include <stdio.h>
+#include <errno.h>
 #include <fcntl.h>
 #include <ctype.h>
 
+#if ! defined BB_FEATURE_USE_DEVPS_N_DEVMTAB
+
+/* The following is the first ps implementation --
+ * the one using the /proc virtual filesystem.
+ */
+
 #if ! defined BB_FEATURE_USE_PROCFS
 #error Sorry, I depend on the /proc filesystem right now.
 #endif
@@ -105,16 +118,12 @@
 	char groupName[10] = "";
 	int i, c;
 
-	if (argc > 1 && **(argv + 1) == '-') {
-		usage
-			("ps\n\nReport process status\n\nThis version of ps accepts no options.\n");
-	}
+	if (argc > 1 && **(argv + 1) == '-')
+		usage ("ps\n\nReport process status\n\nThis version of ps accepts no options.\n");
 
 	dir = opendir("/proc");
-	if (!dir) {
-		perror("Can't open /proc");
-		exit(FALSE);
-	}
+	if (!dir)
+		fatalError("Can't open /proc");
 
 	fprintf(stdout, "%5s  %-8s %-3s %5s %s\n", "PID", "Uid", "Gid",
 			"State", "Command");
@@ -131,9 +140,9 @@
 
 		/* Make some adjustments as needed */
 		my_getpwuid(uidName, p.ruid);
-		my_getgrgid(groupName, p.rgid);
 		if (*uidName == '\0')
 			sprintf(uidName, "%d", p.ruid);
+		my_getgrgid(groupName, p.rgid);
 		if (*groupName == '\0')
 			sprintf(groupName, "%d", p.rgid);
 
@@ -141,10 +150,8 @@
 				p.state);
 		sprintf(path, "/proc/%s/cmdline", entry->d_name);
 		file = fopen(path, "r");
-		if (file == NULL) {
-			perror(path);
-			exit(FALSE);
-		}
+		if (file == NULL)
+			fatalError("Can't open %s: %s\n", path, strerror(errno));
 		i = 0;
 		while (((c = getc(file)) != EOF) && (i < 53)) {
 			i++;
@@ -159,3 +166,90 @@
 	closedir(dir);
 	exit(TRUE);
 }
+
+
+#else /* BB_FEATURE_USE_DEVPS_N_DEVMTAB */
+
+
+/* The following is the second ps implementation --
+ * this one uses the nifty new devps kernel device.
+ */
+
+#include <sys/ioctl.h>
+#include <linux/devps.h>
+
+
+extern int ps_main(int argc, char **argv)
+{
+	char device[] = "/dev/ps";
+	int i, fd;
+	pid_t num_pids;
+	pid_t* pid_array = NULL;
+	struct pid_info info;
+	char uidName[10] = "";
+	char groupName[10] = "";
+
+	if (argc > 1 && **(argv + 1) == '-') 
+		usage("ps-devps\n\nReport process status\n\nThis version of ps accepts no options.\n\n");
+
+	/* open device */ 
+	fd = open(device, O_RDONLY);
+	if (fd < 0) 
+		fatalError( "open failed for `%s': %s\n", device, strerror (errno));
+
+	/* Find out how many processes there are */
+	if (ioctl (fd, DEVPS_GET_NUM_PIDS, &num_pids)<0) 
+		fatalError( "\nDEVPS_GET_PID_LIST: %s\n", strerror (errno));
+	
+	/* Allocate some memory -- grab a few extras just in case 
+	 * some new processes start up while we wait. The kernel will
+	 * just ignore any extras if we give it too many, and will trunc.
+	 * the list if we give it too few.  */
+	pid_array = (pid_t*) calloc( num_pids+10, sizeof(pid_t));
+	pid_array[0] = num_pids+10;
+
+	/* Now grab the pid list */
+	if (ioctl (fd, DEVPS_GET_PID_LIST, pid_array)<0) 
+		fatalError("\nDEVPS_GET_PID_LIST: %s\n", strerror (errno));
+
+	/* Print up a ps listing */
+	fprintf(stdout, "%5s  %-8s %-3s %5s %s\n", "PID", "Uid", "Gid",
+			"State", "Command");
+
+	for (i=1; i<pid_array[0] ; i++) {
+		uidName[0] = '\0';
+		groupName[0] = '\0';
+	    info.pid = pid_array[i];
+
+	    if (ioctl (fd, DEVPS_GET_PID_INFO, &info)<0)
+			fatalError("\nDEVPS_GET_PID_INFO: %s\n", strerror (errno));
+	    
+		/* Make some adjustments as needed */
+		my_getpwuid(uidName, info.euid);
+		if (*uidName == '\0')
+			sprintf(uidName, "%ld", info.euid);
+		my_getgrgid(groupName, info.egid);
+		if (*groupName == '\0')
+			sprintf(groupName, "%ld", info.egid);
+
+		fprintf(stdout, "%5d %-8s %-8s %c ", info.pid, uidName, groupName, info.state);
+
+		if (strlen(info.command_line) > 1)
+			fprintf(stdout, "%s\n", info.command_line);
+		else
+			fprintf(stdout, "[%s]\n", info.name);
+
+	}
+
+	/* Free memory */
+	free( pid_array);
+
+	/* close device */
+	if (close (fd) != 0) 
+		fatalError("close failed for `%s': %s\n", device, strerror (errno));
+ 
+	exit (0);
+}
+
+#endif /* BB_FEATURE_USE_DEVPS_N_DEVMTAB */
+
diff --git a/ps.c b/ps.c
index 207cdaa..b0933ab 100644
--- a/ps.c
+++ b/ps.c
@@ -1,34 +1,47 @@
 /* vi: set sw=4 ts=4: */
 /*
- * Mini ps implementation for busybox
+ * Mini ps implementation(s) for busybox
+ *
+ * Copyright (C) 1999 by Lineo, inc.  Written by Erik Andersen
+ * <andersen@lineo.com>, <andersee@debian.org>
  *
  *
- * Copyright (C) 1999 by Lineo, inc.
- * Written by Erik Andersen <andersen@lineo.com>, <andersee@debian.org>
+ * This contains _two_ implementations of ps for Linux.  One uses the
+ * traditional /proc virtual filesystem, and the other use the devps kernel
+ * driver (written by Erik Andersen to avoid using /proc thereby saving 100k+).
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
  *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
  *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA 02111-1307 USA
  *
  */
 
 #include "internal.h"
+#include <stdio.h>
 #include <unistd.h>
 #include <dirent.h>
-#include <stdio.h>
+#include <errno.h>
 #include <fcntl.h>
 #include <ctype.h>
 
+#if ! defined BB_FEATURE_USE_DEVPS_N_DEVMTAB
+
+/* The following is the first ps implementation --
+ * the one using the /proc virtual filesystem.
+ */
+
 #if ! defined BB_FEATURE_USE_PROCFS
 #error Sorry, I depend on the /proc filesystem right now.
 #endif
@@ -105,16 +118,12 @@
 	char groupName[10] = "";
 	int i, c;
 
-	if (argc > 1 && **(argv + 1) == '-') {
-		usage
-			("ps\n\nReport process status\n\nThis version of ps accepts no options.\n");
-	}
+	if (argc > 1 && **(argv + 1) == '-')
+		usage ("ps\n\nReport process status\n\nThis version of ps accepts no options.\n");
 
 	dir = opendir("/proc");
-	if (!dir) {
-		perror("Can't open /proc");
-		exit(FALSE);
-	}
+	if (!dir)
+		fatalError("Can't open /proc");
 
 	fprintf(stdout, "%5s  %-8s %-3s %5s %s\n", "PID", "Uid", "Gid",
 			"State", "Command");
@@ -131,9 +140,9 @@
 
 		/* Make some adjustments as needed */
 		my_getpwuid(uidName, p.ruid);
-		my_getgrgid(groupName, p.rgid);
 		if (*uidName == '\0')
 			sprintf(uidName, "%d", p.ruid);
+		my_getgrgid(groupName, p.rgid);
 		if (*groupName == '\0')
 			sprintf(groupName, "%d", p.rgid);
 
@@ -141,10 +150,8 @@
 				p.state);
 		sprintf(path, "/proc/%s/cmdline", entry->d_name);
 		file = fopen(path, "r");
-		if (file == NULL) {
-			perror(path);
-			exit(FALSE);
-		}
+		if (file == NULL)
+			fatalError("Can't open %s: %s\n", path, strerror(errno));
 		i = 0;
 		while (((c = getc(file)) != EOF) && (i < 53)) {
 			i++;
@@ -159,3 +166,90 @@
 	closedir(dir);
 	exit(TRUE);
 }
+
+
+#else /* BB_FEATURE_USE_DEVPS_N_DEVMTAB */
+
+
+/* The following is the second ps implementation --
+ * this one uses the nifty new devps kernel device.
+ */
+
+#include <sys/ioctl.h>
+#include <linux/devps.h>
+
+
+extern int ps_main(int argc, char **argv)
+{
+	char device[] = "/dev/ps";
+	int i, fd;
+	pid_t num_pids;
+	pid_t* pid_array = NULL;
+	struct pid_info info;
+	char uidName[10] = "";
+	char groupName[10] = "";
+
+	if (argc > 1 && **(argv + 1) == '-') 
+		usage("ps-devps\n\nReport process status\n\nThis version of ps accepts no options.\n\n");
+
+	/* open device */ 
+	fd = open(device, O_RDONLY);
+	if (fd < 0) 
+		fatalError( "open failed for `%s': %s\n", device, strerror (errno));
+
+	/* Find out how many processes there are */
+	if (ioctl (fd, DEVPS_GET_NUM_PIDS, &num_pids)<0) 
+		fatalError( "\nDEVPS_GET_PID_LIST: %s\n", strerror (errno));
+	
+	/* Allocate some memory -- grab a few extras just in case 
+	 * some new processes start up while we wait. The kernel will
+	 * just ignore any extras if we give it too many, and will trunc.
+	 * the list if we give it too few.  */
+	pid_array = (pid_t*) calloc( num_pids+10, sizeof(pid_t));
+	pid_array[0] = num_pids+10;
+
+	/* Now grab the pid list */
+	if (ioctl (fd, DEVPS_GET_PID_LIST, pid_array)<0) 
+		fatalError("\nDEVPS_GET_PID_LIST: %s\n", strerror (errno));
+
+	/* Print up a ps listing */
+	fprintf(stdout, "%5s  %-8s %-3s %5s %s\n", "PID", "Uid", "Gid",
+			"State", "Command");
+
+	for (i=1; i<pid_array[0] ; i++) {
+		uidName[0] = '\0';
+		groupName[0] = '\0';
+	    info.pid = pid_array[i];
+
+	    if (ioctl (fd, DEVPS_GET_PID_INFO, &info)<0)
+			fatalError("\nDEVPS_GET_PID_INFO: %s\n", strerror (errno));
+	    
+		/* Make some adjustments as needed */
+		my_getpwuid(uidName, info.euid);
+		if (*uidName == '\0')
+			sprintf(uidName, "%ld", info.euid);
+		my_getgrgid(groupName, info.egid);
+		if (*groupName == '\0')
+			sprintf(groupName, "%ld", info.egid);
+
+		fprintf(stdout, "%5d %-8s %-8s %c ", info.pid, uidName, groupName, info.state);
+
+		if (strlen(info.command_line) > 1)
+			fprintf(stdout, "%s\n", info.command_line);
+		else
+			fprintf(stdout, "[%s]\n", info.name);
+
+	}
+
+	/* Free memory */
+	free( pid_array);
+
+	/* close device */
+	if (close (fd) != 0) 
+		fatalError("close failed for `%s': %s\n", device, strerror (errno));
+ 
+	exit (0);
+}
+
+#endif /* BB_FEATURE_USE_DEVPS_N_DEVMTAB */
+
diff --git a/reboot.c b/reboot.c
index f782fa1..fc01ea0 100644
--- a/reboot.c
+++ b/reboot.c
@@ -27,7 +27,7 @@
 extern int reboot_main(int argc, char **argv)
 {
 	/* don't assume init's pid == 1 */
-	exit(kill(findInitPid(), SIGINT));
+	exit(kill(findPidByName("init"), SIGINT));
 }
 
 /*
diff --git a/util-linux/mount.c b/util-linux/mount.c
index 37f789d..f46664b 100644
--- a/util-linux/mount.c
+++ b/util-linux/mount.c
@@ -46,6 +46,10 @@
 #include <sys/mount.h>
 #include <ctype.h>
 #include <fstab.h>
+#if defined BB_FEATURE_USE_DEVPS_N_DEVMTAB
+#include <linux/devmtab.h>
+#endif
+
 
 #if defined BB_FEATURE_MOUNT_LOOP
 #include <fcntl.h>
@@ -221,9 +225,8 @@
 {
 	int status = 0;
 
-	char buf[255];
-
 #if defined BB_FEATURE_USE_PROCFS
+	char buf[255];
 	if (strcmp(filesystemType, "auto") == 0) {
 		FILE *f = fopen("/proc/filesystems", "r");
 
@@ -252,6 +255,43 @@
 		fclose(f);
 	} else
 #endif
+#if defined BB_FEATURE_USE_DEVPS_N_DEVMTAB
+	if (strcmp(filesystemType, "auto") == 0) {
+		int fd, i, numfilesystems;
+		char device[] = "/dev/mtab";
+		struct k_fstype *fslist;
+
+		/* open device */ 
+		fd = open(device, O_RDONLY);
+		if (fd < 0)
+			fatalError("open failed for `%s': %s\n", device, strerror (errno));
+
+		/* How many filesystems?  We need to know to allocate enough space */
+		numfilesystems = ioctl (fd, DEVMTAB_COUNT_FILESYSTEMS);
+		if (numfilesystems<0)
+			fatalError("\nDEVMTAB_COUNT_FILESYSTEMS: %s\n", strerror (errno));
+		fslist = (struct k_fstype *) calloc ( numfilesystems, sizeof(struct k_fstype));
+
+		/* Grab the list of available filesystems */
+		status = ioctl (fd, DEVMTAB_GET_FILESYSTEMS, fslist);
+		if (status<0)
+			fatalError("\nDEVMTAB_GET_FILESYSTEMS: %s\n", strerror (errno));
+
+		/* Walk the list trying to mount filesystems 
+		 * that do not claim to be nodev filesystems */
+		for( i = 0 ; i < numfilesystems ; i++) {
+			if (fslist[i].mnt_nodev)
+				continue;
+			status = do_mount(blockDevice, directory, fslist[i].mnt_type,
+							  flags | MS_MGC_VAL, string_flags,
+							  useMtab, fakeIt, mtab_opts);
+			if (status == TRUE)
+				break;
+		}
+		free( fslist);
+		close(fd);
+	} else
+#endif
 	{
 		status = do_mount(blockDevice, directory, filesystemType,
 						  flags | MS_MGC_VAL, string_flags, useMtab,
@@ -285,6 +325,39 @@
 	/* Only compiled in if BB_MTAB is not defined */
 	whine_if_fstab_is_missing();
 
+#if defined BB_FEATURE_USE_DEVPS_N_DEVMTAB
+	if (argc == 1) {
+		int fd, i, numfilesystems;
+		char device[] = "/dev/mtab";
+		struct k_mntent *mntentlist;
+
+		/* open device */ 
+		fd = open(device, O_RDONLY);
+		if (fd < 0)
+			fatalError("open failed for `%s': %s\n", device, strerror (errno));
+
+		/* How many mounted filesystems?  We need to know to 
+		 * allocate enough space for later... */
+		numfilesystems = ioctl (fd, DEVMTAB_COUNT_MOUNTS);
+		if (numfilesystems<0)
+			fatalError( "\nDEVMTAB_COUNT_MOUNTS: %s\n", strerror (errno));
+		mntentlist = (struct k_mntent *) calloc ( numfilesystems, sizeof(struct k_mntent));
+		
+		/* Grab the list of mounted filesystems */
+		if (ioctl (fd, DEVMTAB_GET_MOUNTS, mntentlist)<0)
+			fatalError( "\nDEVMTAB_GET_MOUNTS: %s\n", strerror (errno));
+
+		for( i = 0 ; i < numfilesystems ; i++) {
+			fprintf( stdout, "%s %s %s %s %d %d\n", mntentlist[i].mnt_fsname,
+					mntentlist[i].mnt_dir, mntentlist[i].mnt_type, 
+					mntentlist[i].mnt_opts, mntentlist[i].mnt_freq, 
+					mntentlist[i].mnt_passno);
+		}
+		free( mntentlist);
+		close(fd);
+		exit(TRUE);
+	}
+#else
 	if (argc == 1) {
 		FILE *mountTable = setmntent(mtab_file, "r");
 
@@ -310,7 +383,7 @@
 		}
 		exit(TRUE);
 	}
-
+#endif
 
 	/* Parse options */
 	i = --argc;
@@ -372,10 +445,9 @@
 		struct mntent *m;
 		FILE *f = setmntent("/etc/fstab", "r");
 
-		if (f == NULL) {
-			perror("/etc/fstab");
-			exit(FALSE);
-		}
+		if (f == NULL)
+			fatalError( "\nCannot ream /etc/fstab: %s\n", strerror (errno));
+
 		while ((m = getmntent(f)) != NULL) {
 			// If the file system isn't noauto, 
 			// and isn't swap or nfs, then mount it
diff --git a/utility.c b/utility.c
index 64c1a48..7de9974 100644
--- a/utility.c
+++ b/utility.c
@@ -56,6 +56,13 @@
 #include <linux/loop.h>
 #endif
 
+/* Busybox mount uses either /proc/filesystems or /dev/mtab to get the 
+ * list of available filesystems used for the -t auto option */ 
+#if defined BB_FEATURE_USE_PROCFS && defined BB_FEATURE_USE_DEVPS_N_DEVMTAB
+//#error Sorry, but busybox can't use both /proc and /dev/ps at the same time -- Pick one and try again.
+#error "Sorry, but busybox can't use both /proc and /dev/ps at the same time -- Pick one and try again."
+#endif
+
 
 #if defined BB_MOUNT || defined BB_UMOUNT || defined BB_DF
 #  if defined BB_FEATURE_USE_PROCFS
@@ -64,9 +71,13 @@
 #    if defined BB_MTAB
 const char mtab_file[] = "/etc/mtab";
 #    else
-#      error With (BB_MOUNT||BB_UMOUNT||BB_DF) defined, you must define either BB_MTAB or BB_FEATURE_USE_PROCFS
+#      if defined BB_FEATURE_USE_DEVPS_N_DEVMTAB
+const char mtab_file[] = "/dev/mtab";
+#    else
+#        error With (BB_MOUNT||BB_UMOUNT||BB_DF) defined, you must define either BB_MTAB or ( BB_FEATURE_USE_PROCFS | BB_FEATURE_USE_DEVPS_N_DEVMTAB)
 #    endif
 #  endif
+#  endif
 #endif
 
 
@@ -1238,29 +1249,96 @@
 
 #if defined BB_INIT || defined BB_HALT || defined BB_REBOOT
 
-#if ! defined BB_FEATURE_USE_PROCFS
-#error Sorry, I depend on the /proc filesystem right now.
+#ifdef BB_FEATURE_USE_DEVPS_N_DEVMTAB
+#include <linux/devps.h>
 #endif
-/* findInitPid()
+
+#if defined BB_FEATURE_USE_DEVPS_N_DEVMTAB
+/* findPidByName()
  *  
- *  This finds the pid of init (which is not always 1).
- *  Currently, it's implemented by rummaging through the proc filesystem.
+ *  This finds the pid of the specified process,
+ *  by using the /dev/ps device driver.
  *
  *  [return]
  *  0	    failure
- *  pid	    when init's pid is found.
+ *  pid	    when the pid is found.
  */
-extern pid_t findInitPid()
+extern pid_t findPidByName( char* pidName)
 {
-	pid_t init_pid;
+	int fd, i;
+	char device[] = "/dev/ps";
+	pid_t thePid = 0;
+	pid_t num_pids;
+	pid_t* pid_array = NULL;
+
+	/* open device */ 
+	fd = open(device, O_RDONLY);
+	if (fd < 0)
+		fatalError( "open failed for `%s': %s\n", device, strerror (errno));
+
+	/* Find out how many processes there are */
+	if (ioctl (fd, DEVPS_GET_NUM_PIDS, &num_pids)<0) 
+		fatalError( "\nDEVPS_GET_PID_LIST: %s\n", strerror (errno));
+	
+	/* Allocate some memory -- grab a few extras just in case 
+	 * some new processes start up while we wait. The kernel will
+	 * just ignore any extras if we give it too many, and will trunc.
+	 * the list if we give it too few.  */
+	pid_array = (pid_t*) calloc( num_pids+10, sizeof(pid_t));
+	pid_array[0] = num_pids+10;
+
+	/* Now grab the pid list */
+	if (ioctl (fd, DEVPS_GET_PID_LIST, pid_array)<0) 
+		fatalError( "\nDEVPS_GET_PID_LIST: %s\n", strerror (errno));
+
+	/* Now search for a match */
+	for (i=1; i<pid_array[0] ; i++) {
+		struct pid_info info;
+
+	    info.pid = pid_array[i];
+	    if (ioctl (fd, DEVPS_GET_PID_INFO, &info)<0)
+			fatalError( "\nDEVPS_GET_PID_INFO: %s\n", strerror (errno));
+
+		if ((strstr(info.command_line, pidName) != NULL)) {
+			thePid = info.pid;
+			break;
+		}
+	}
+
+	/* Free memory */
+	free( pid_array);
+
+	/* close device */
+	if (close (fd) != 0) 
+		fatalError( "close failed for `%s': %s\n",device, strerror (errno));
+
+	return thePid;
+}
+#else		/* BB_FEATURE_USE_DEVPS_N_DEVMTAB */
+#if ! defined BB_FEATURE_USE_PROCFS
+#error Sorry, I depend on the /proc filesystem right now.
+#endif
+/* findPidByName()
+ *  
+ *  This finds the pid of the specified process.
+ *  Currently, it's implemented by rummaging through 
+ *  the proc filesystem.
+ *
+ *  [return]
+ *  0	    failure
+ *  pid	    when the pid is found.
+ */
+extern pid_t findPidByName( char* pidName)
+{
+	pid_t thePid;
 	char filename[256];
 	char buffer[256];
 
 	/* no need to opendir ;) */
-	for (init_pid = 1; init_pid < 65536; init_pid++) {
+	for (thePid = 1; thePid < 65536; thePid++) {
 		FILE *status;
 
-		sprintf(filename, "/proc/%d/cmdline", init_pid);
+		sprintf(filename, "/proc/%d/cmdline", thePid);
 		status = fopen(filename, "r");
 		if (!status) {
 			continue;
@@ -1268,12 +1346,13 @@
 		fgets(buffer, 256, status);
 		fclose(status);
 
-		if ((strstr(buffer, "init") != NULL)) {
-			return init_pid;
+		if ((strstr(buffer, pidName) != NULL)) {
+			return thePid;
 		}
 	}
 	return 0;
 }
+#endif							/* BB_FEATURE_USE_DEVPS_N_DEVMTAB */
 #endif							/* BB_INIT || BB_HALT || BB_REBOOT */
 
 #if defined BB_GUNZIP \