A few minor updates. ;-)

Seriously though, read the Changelog for busybox 0.42,
which this is about to become...
 -Erik
diff --git a/Changelog b/Changelog
index 6581b5c..7ecc4fb 100644
--- a/Changelog
+++ b/Changelog
@@ -1,4 +1,41 @@
 0.42
+
+        * Fairly massive restructuring of umount.c to deal with remounting 
+	  busy devices read-only. Adds a -r option to control that; it is 
+	  optionally compiled in with BB_FEATURE_REMOUNT
+        * Added a bunch of functions to mtab.c to interact with the
+          {get,set,end}mntent interface; as it turns out, those functions do
+	  not appear to be re-entrant, and that causes a lot of problems with
+	  the way umount was originally written.
+        * Makes init send TERM and KILL (instead of HUP and KILL) on reboot
+	  to be more consistent with sysvinit
+        * Changes to init.c to use the new -r option to umount. Also increased
+	  the sleep time between the time the TERM and KILL signals are sent
+
+        - Randolph Chung
+
+
+	* cp.c, mv.c: removed, replaced by cp_mv.c which has been
+	    extensively rewritten from the original cp.c.
+	* Also added a warning message to the `mv' usage string saying that
+	    this is not GNU mv, and it will break hard links. cp also breaks
+	    hard links.
+	* ln.c: implemented `-n' switch, no-deref symlinks.
+	* include<sys/param.h>: and use PATH_MAX everywhere.
+	* busybox: File name buffer overrun guards to prevent future crashes.
+	    - Always check exit status.
+	    - Purge all use of `creat()', replace with `open()'.
+	* utility.c 
+	    - recursiveAction was overriding the value of 
+		followLinks thus ignoring it.
+	    - isDirectory now takes a followLinks boolean, updated all callers
+	    - copyFile had the followLinks logic reversed.
+	* messages.c: New file. Put common error message strings all in
+	    one place in an attempt to shrink the binary a little.
+
+	-Karl M. Hegbloom
+
+
 	* Made tar creation support in busybox tar optional.
 	* You no longer _have_ to put a "-" in front of tar options.
 	* Tar could inadvertently change permissions and ownership on
@@ -16,11 +53,11 @@
 	    for the kernel init chroot patch by Werner Almesberger, which 
 	    allows init to chroot to a new device, and umount the old one.
 	* Fixed bug that wouldn't let one chown a symlink -- it would
-	  always dereference before.  -beppu
+	    always dereference before.  -beppu
 	* Fixed a bug where init could have reference already freed memory.
 	    Found and fixed by Taketoshi Sano <kgh12351@nifty.ne.jp>
 	* Several contributions from Friedrich Vedder <fwv@myrtle.lahn.de>
-	* added (and documented) "-n" option for head - 
+	* Added (and documented) "-n" option for head - 
 	* Cleanup for a number of usage messages -- also 
 	    contributed Friedrich Vedder <fwv@myrtle.lahn.de>
 	* Cosmetic fix to busybox.c (Don't print a comma at the
@@ -42,6 +79,11 @@
 	    Randolph Chung <tausq@debian.org>.
 	* cp could, when copying symlinks, change permissions of the
 	    files pointed to by the symlinks.
+	* Several fixes from Pavel Roskin <pavel_roskin@geocities.com>:
+	    - `chown' with 1 argument displayed the error incorrectly
+	    - `fdflush', `length' and `printf' crashed when run without arguments
+	    - `fdflush' tried to flush itself using *argv
+	    - added "skip" and "seek" to dd.
 
 
 	-Erik Andersen
diff --git a/Makefile b/Makefile
index 554dd00..490d393 100644
--- a/Makefile
+++ b/Makefile
@@ -15,71 +15,74 @@
 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 #
 
+PROG      := busybox
+VERSION   := 0.42
+BUILDTIME := $(shell TZ=GMT date "+%Y%m%d-%H%M")
 
-PROG=busybox
-VERSION=0.42
-BUILDTIME=$(shell date "+%Y%m%d-%H%M")
+# Set the following to `true' to make a debuggable build.
+# Leave this set to `false' for production use.
+# eg: `make DODEBUG=true'
+DODEBUG = false
 
-# Comment out the following to make a debuggable build
-# Leave this off for production use.
-DODEBUG=false
 # If you want a static binary, turn this on.  I can't think
 # of many situations where anybody would ever want it static, 
 # but...
-DOSTATIC=false
+DOSTATIC = false
 
-#This will choke on a non-debian system
-ARCH=`uname -m | sed -e 's/i.86/i386/' | sed -e 's/sparc.*/sparc/'`
+# This will choke on a non-debian system
+ARCH =`uname -m | sed -e 's/i.86/i386/' | sed -e 's/sparc.*/sparc/'`
 
-GCCMAJVERSION=$(shell $(CC) --version | sed -n "s/^\([^\.]*\).*/\1/p" )
-GCCMINVERSION=$(shell $(CC) --version | sed -n "s/^[^\.]*\.\([^\.]*\)[\.].*/\1/p" )
+CC = gcc
 
-GCCSUPPORTSOPTSIZE=$(shell \
-if ( test $(GCCMAJVERSION) -eq 2 ) ; then \
-    if ( test $(GCCMINVERSION) -ge 66 ) ; then \
-	echo "true"; \
-    else \
-	echo "false"; \
-    fi; \
-else \
-    if ( test $(GCCMAJVERSION) -gt 2 ) ; then \
-	echo "true"; \
-    else \
-	echo "false"; \
-    fi; \
+GCCMAJVERSION = $(shell $(CC) --version | sed -n "s/^[^0-9]*\([0-9]\)\.\([0-9].*\)[\.].*/\1/p")
+GCCMINVERSION = $(shell $(CC) --version | sed -n "s/^[^0-9]*\([0-9]\)\.\([0-9].*\)[\.].*/\2/p")
+
+
+GCCSUPPORTSOPTSIZE = $(shell			\
+if ( test $(GCCMAJVERSION) -eq 2 ) ; then	\
+    if ( test $(GCCMINVERSION) -ge 66 ) ; then	\
+	echo "true";				\
+    else					\
+	echo "false";				\
+    fi;						\
+else						\
+    if ( test $(GCCMAJVERSION) -gt 2 ) ; then	\
+	echo "true";				\
+    else					\
+	echo "false";				\
+    fi;						\
 fi; )
 
 
 ifeq ($(GCCSUPPORTSOPTSIZE), true)
-    OPTIMIZATION=-Os
+    OPTIMIZATION = -Os
 else
-    OPTIMIZATION=-O2
+    OPTIMIZATION = -O2
 endif
 
 # -D_GNU_SOURCE is needed because environ is used in init.c
 ifeq ($(DODEBUG),true)
-    CFLAGS+=-Wall -g -D_GNU_SOURCE -DDEBUG_INIT
-    STRIP=
-    LDFLAGS=
+    CFLAGS += -Wall -g -D_GNU_SOURCE -DDEBUG_INIT
+    STRIP   =
+    LDFLAGS =
 else
-    CFLAGS+=-Wall $(OPTIMIZATION) -fomit-frame-pointer -fno-builtin -D_GNU_SOURCE
-    LDFLAGS= -s
-    STRIP= strip --remove-section=.note --remove-section=.comment $(PROG)
+    CFLAGS  += -Wall $(OPTIMIZATION) -fomit-frame-pointer -fno-builtin -D_GNU_SOURCE
+    LDFLAGS  = -s
+    STRIP    = strip --remove-section=.note --remove-section=.comment $(PROG)
     #Only staticly link when _not_ debugging 
     ifeq ($(DOSTATIC),true)
-	LDFLAGS+= --static
+	LDFLAGS += --static
     endif
-    
 endif
 
 ifndef $(PREFIX)
-    PREFIX=`pwd`/_install
+    PREFIX = `pwd`/_install
 endif
 
-LIBRARIES=
-OBJECTS=$(shell ./busybox.sh)
-CFLAGS+= -DBB_VER='"$(VERSION)"'
-CFLAGS+= -DBB_BT='"$(BUILDTIME)"'
+LIBRARIES =
+OBJECTS   = $(shell ./busybox.sh) messages.o utility.o
+CFLAGS    += -DBB_VER='"$(VERSION)"'
+CFLAGS    += -DBB_BT='"$(BUILDTIME)"'
 ifdef BB_INIT_SCRIPT
     CFLAGS += -DINIT_SCRIPT=${BB_INIT_SCRIPT}
 endif
@@ -90,7 +93,7 @@
 	$(CC) $(LDFLAGS) -o $(PROG) $(OBJECTS) $(LIBRARIES)
 	$(STRIP)
 
-busybox.links:
+busybox.links: busybox.def.h
 	- ./busybox.mkll | sort >$@
 
 clean:
@@ -100,7 +103,7 @@
 distclean: clean
 	- rm -f $(PROG)
 
-$(OBJECTS):  busybox.def.h internal.h Makefile
+$(OBJECTS): %.o: %.c busybox.def.h internal.h Makefile messages.c 
 
 install: busybox busybox.links
 	./install.sh $(PREFIX)
@@ -108,6 +111,18 @@
 dist: release
 
 release: distclean
-	(cd .. ; rm -rf busybox-$(VERSION) ; cp -a busybox busybox-$(VERSION); rm -rf busybox-$(VERSION)/CVS busybox-$(VERSION)/scripts/CVS busybox-$(VERSION)/docs/CVS busybox-$(VERSION)/.cvsignore ; tar -cvzf busybox-$(VERSION).tar.gz busybox-$(VERSION)) 
-
-
+	cd ..;					\
+	rm -rf busybox-$(VERSION);		\
+	cp -a busybox busybox-$(VERSION);	\
+						\
+	find busybox-$(VERSION)/ -type d	\
+				 -name CVS	\
+				 -print		\
+		| xargs rm -rf;			\
+						\
+	find busybox-$(VERSION)/ -type f	\
+				 -name .cvsignore \
+				 -print		\
+		| xargs rm -f;			\
+						\
+	tar -cvzf busybox-$(VERSION).tar.gz busybox-$(VERSION)/;
diff --git a/TODO b/TODO
index b951767..51a0d14 100644
--- a/TODO
+++ b/TODO
@@ -26,3 +26,44 @@
 * tr
 * expr (maybe?)  (ash builtin?)
 
+
+
+
+Some known bugs, todo items, etc...
+
+-----------------------
+
+
+[andersen@slag busybox]$ ./busybox du /bin
+6213    /bin
+[andersen@slag busybox]$ du /bin
+2971    /bin
+[andersen@slag busybox]$ du --block-size=512 /bin
+5943    /bin
+
+-----------------------
+
+-rw-r--r-- 1000/1000      4398 2000-01-06 21:55 uniq.c
+-rw-r--r-- 1000/1000      1568 1999-10-20 18:08 update.c
+-rw-r----- 0/1000         1168 2000-01-29 21:03 update.o
+-rw-r--r-- 1000/1000     22820 2000-01-05 11:36 utility.c
+-rw-r----- 0/1000         7372 2000-01-29 21:03 utility.o
+tar: Skipping to next file header
+tar: Skipping to next file header
+tar: Archive - EOF not on block boundary
+tar: Error is not recoverable: exiting now
+
+
+#1 You are storing by id instead of name like normal tar. Did you realize this?
+(or am I missing some compile option? )ctar did not do this, and I don't think
+it's a good idea for LRP.
+
+#2
+ctar did not produce the EOF error like your tar does. I believe you need to
+pad the end of the archive with at least 2 tarsized (512byte) blocks. (I
+think???)
+
+#3
+There is no exclude file(s) option to tar. LRP's packaging system can not
+function without this. Will you have the time to add this soon?
+
diff --git a/applets/busybox.c b/applets/busybox.c
index 7f14473..e2c2e03 100644
--- a/applets/busybox.c
+++ b/applets/busybox.c
@@ -50,8 +50,9 @@
 #ifdef BB_CHVT			//usr/bin
     {"chvt", chvt_main},
 #endif
-#ifdef BB_CP			//bin
-    {"cp", cp_main},
+#ifdef BB_CP_MV			//bin
+    {"cp", cp_mv_main},
+    {"mv", cp_mv_main},
 #endif
 #ifdef BB_DATE			//bin
     {"date", date_main},
@@ -170,10 +171,7 @@
 #ifdef BB_MT			//bin
     {"mt", mt_main},
 #endif
-#ifdef BB_MV			//bin
-    {"mv", mv_main},
-#endif
-#ifdef BB_NSLOOKUP		//bin
+#ifdef BB_NSLOOKUP		//usr/bin
     {"nslookup", nslookup_main},
 #endif
 #ifdef BB_PING                  //bin
diff --git a/applets/busybox.mkll b/applets/busybox.mkll
index be6d937..c4420f5 100755
--- a/applets/busybox.mkll
+++ b/applets/busybox.mkll
@@ -1,5 +1,5 @@
 #!/bin/sh
-#Make busybox links list file
+# Make busybox links list file.
 
 DF="busybox.def.h"
 MF="busybox.c"
diff --git a/archival/gunzip.c b/archival/gunzip.c
index fddcc76..db7fa1d 100644
--- a/archival/gunzip.c
+++ b/archival/gunzip.c
@@ -3,6 +3,9 @@
    */
 
 #include "internal.h"
+#define bb_need_name_too_long
+#define BB_DECLARE_EXTERN
+#include "messages.c"
 
 static const char gunzip_usage[] =
     "gunzip [OPTION]... FILE\n\n"
@@ -64,6 +67,7 @@
 #include <signal.h>
 #include <sys/stat.h>
 #include <errno.h>
+#include <sys/param.h>		/* for PATH_MAX */
 
 /* #include "tailor.h" */
 
@@ -627,8 +631,12 @@
 #endif
 #define RW_USER (S_IRUSR | S_IWUSR)  /* creation mode for open() */
 
-#ifndef MAX_PATH_LEN
-#  define MAX_PATH_LEN   1024 /* max pathname length */
+#ifndef MAX_PATH_LEN /* max pathname length */
+#  ifdef PATH_MAX
+#    define MAX_PATH_LEN   PATH_MAX
+#  else
+#    define MAX_PATH_LEN   1024
+#  endif
 #endif
 
 #ifndef SEEK_END
@@ -696,8 +704,8 @@
     int delInputFile=0;
     struct stat statBuf;
     char* delFileName; 
-    char ifname[MAX_PATH_LEN]; /* input file name */
-    char ofname[MAX_PATH_LEN]; /* output file name */
+    char ifname[MAX_PATH_LEN + 1]; /* input file name */
+    char ofname[MAX_PATH_LEN + 1]; /* output file name */
 
     if (argc==1)
 	usage(gunzip_usage);
@@ -764,7 +772,11 @@
 	/* Open up the input file */
 	if (*argv=='\0')
 	    usage(gunzip_usage);
-	strncpy(ifname, *argv, MAX_PATH_LEN);
+	if (strlen(*argv) > MAX_PATH_LEN) {
+	    fprintf(stderr, name_too_long, "gunzip");
+	    do_exit(WARNING);
+	}
+	strcpy(ifname, *argv);
 
 	/* Open input fille */
 	inFileNum=open( ifname, O_RDONLY);
@@ -799,7 +811,11 @@
 	char* pos;
 
 	/* And get to work */
-	strncpy(ofname, ifname, MAX_PATH_LEN-4);
+	if (strlen(ifname) > MAX_PATH_LEN - 4) {
+	    fprintf(stderr, name_too_long, "gunzip");
+	    do_exit(WARNING);
+	}
+	strcpy(ofname, ifname);
 	pos=strstr(ofname, ".gz");
 	if (pos != NULL) {
 	    *pos='\0';
diff --git a/archival/tar.c b/archival/tar.c
index 0fa09ff..6496231 100644
--- a/archival/tar.c
+++ b/archival/tar.c
@@ -40,6 +40,7 @@
 #include <utime.h>
 #include <sys/types.h>
 #include <sys/sysmacros.h>
+#include <sys/param.h>		/* for PATH_MAX */
 
 
 #ifdef BB_FEATURE_TAR_CREATE
@@ -1041,7 +1042,7 @@
     DIR *dir;
     struct dirent *entry;
     int needSlash;
-    char fullName[NAME_MAX];
+    char fullName[PATH_MAX + 1];
 
     /* 
      * Construct the directory name as used in the tar file by appending
diff --git a/busybox.c b/busybox.c
index 7f14473..e2c2e03 100644
--- a/busybox.c
+++ b/busybox.c
@@ -50,8 +50,9 @@
 #ifdef BB_CHVT			//usr/bin
     {"chvt", chvt_main},
 #endif
-#ifdef BB_CP			//bin
-    {"cp", cp_main},
+#ifdef BB_CP_MV			//bin
+    {"cp", cp_mv_main},
+    {"mv", cp_mv_main},
 #endif
 #ifdef BB_DATE			//bin
     {"date", date_main},
@@ -170,10 +171,7 @@
 #ifdef BB_MT			//bin
     {"mt", mt_main},
 #endif
-#ifdef BB_MV			//bin
-    {"mv", mv_main},
-#endif
-#ifdef BB_NSLOOKUP		//bin
+#ifdef BB_NSLOOKUP		//usr/bin
     {"nslookup", nslookup_main},
 #endif
 #ifdef BB_PING                  //bin
diff --git a/busybox.def.h b/busybox.def.h
index fa19220..306c877 100644
--- a/busybox.def.h
+++ b/busybox.def.h
@@ -95,11 +95,6 @@
 //
 //
 //
-// Don't turn BB_UTILITY off.  It contains support code 
-// that compiles to 0 if everything else if turned off.
-#define BB_UTILITY
-//
-//
 //
 // This is where feature definitions go.  Generally speaking,
 // turning this stuff off makes things a bit smaller (and less 
@@ -132,7 +127,7 @@
 #define BB_FEATURE_USE_INITTAB
 //
 //Enable init being called as /linuxrc
-#define BB_FEATURE_LINUXRC
+//#define BB_FEATURE_LINUXRC
 //
 //
 //Simple tail implementation (2k vs 6k for the full one).  Still
@@ -142,11 +137,20 @@
 // Enable support for loop devices in mount
 #define BB_FEATURE_MOUNT_LOOP
 //
+// Enable support for a real /etc/mtab file instead of /proc/mounts
+#ifdef BB_MOUNT
+//#define BB_MTAB
+#endif
+//
+//
+// Enable support for remounting filesystems
+#define BB_FEATURE_REMOUNT
+//
 // Enable support for creation of tar files.
 //#define BB_FEATURE_TAR_CREATE
 //
 // Allow init to permenently chroot, and umount the old root fs
-// just like an initrd does.  Requires a kernel patch by Werner Almesberger.
+// 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
diff --git a/busybox.mkll b/busybox.mkll
index be6d937..c4420f5 100755
--- a/busybox.mkll
+++ b/busybox.mkll
@@ -1,5 +1,5 @@
 #!/bin/sh
-#Make busybox links list file
+# Make busybox links list file.
 
 DF="busybox.def.h"
 MF="busybox.c"
diff --git a/chmod_chown_chgrp.c b/chmod_chown_chgrp.c
index 773f4b0..b4c5da9 100644
--- a/chmod_chown_chgrp.c
+++ b/chmod_chown_chgrp.c
@@ -21,10 +21,14 @@
  *
  */
 
+#include "internal.h"
+#define BB_DECLARE_EXTERN
+#define bb_need_invalid_option
+#include "messages.c"
+
 #include <stdio.h>
 #include <grp.h>
 #include <pwd.h>
-#include "internal.h"
 
 
 static uid_t uid = -1;
@@ -69,7 +73,7 @@
 	case CHMOD_APP:
 	    /* Parse the specified modes */
 	    if ( parse_mode(theMode, &(statbuf->st_mode)) == FALSE ) {
-		fprintf(stderr, "%s: Unknown mode: %s\n", invocationName, theMode);
+		fprintf(stderr, "%s: unknown mode: %s\n", invocationName, theMode);
 		exit( FALSE);
 	    }
 	    if (chmod(fileName, statbuf->st_mode) == 0)
@@ -84,6 +88,7 @@
 {
     int recursiveFlag=FALSE;
     char *groupName;
+    char *p;
     const char *appUsage;
 
     whichApp = (strcmp(*argv, "chown")==0)? CHOWN_APP : (strcmp(*argv, "chmod")==0)? CHMOD_APP : CHGRP_APP; 
@@ -103,7 +108,7 @@
 		recursiveFlag = TRUE;
 		break;
 	    default:
-		fprintf(stderr, "Unknown option: %c\n", **argv);
+		fprintf(stderr, invalid_option, invocationName, **argv);
 		usage( appUsage);
 	}
 	argc--;
@@ -117,14 +122,18 @@
 	/* Find the selected group */
 	if ( whichApp==CHGRP_APP ) {
 	    groupName = *argv;
-	    gid = my_getgrnam(groupName);
+	    gid = strtoul(groupName, &p, 10); /* maybe it's already numeric */
+	    if (groupName == p)
+	        gid = my_getgrnam(groupName);
 	    if (gid == -1)
 		goto bad_group;
 	} else {
 	    groupName = strchr(*argv, '.');
 	    if (groupName) {
 		*groupName++ = '\0';
-		gid = my_getgrnam(groupName);
+	        gid = strtoul(groupName, &p, 10);
+	        if (groupName == p)
+		    gid = my_getgrnam(groupName);
 		if (gid == -1)
 		    goto bad_group;
 	    } else
@@ -134,9 +143,11 @@
 
 	/* Find the selected user (if appropriate)  */
 	if (whichApp==CHOWN_APP) {
-	    uid = my_getpwnam(*argv);
+	    uid = strtoul(*argv, &p, 10); /* if numeric ...*/
+	    if (*argv == p)
+	        uid = my_getpwnam(*argv);
 	    if (uid == -1) {
-		fprintf(stderr, "%s: Unknown user name: %s\n", invocationName, *argv);
+		fprintf(stderr, "%s: unknown user name: %s\n", invocationName, *argv);
 		exit( FALSE);
 	    }
 	}
@@ -144,7 +155,7 @@
     
     /* Ok, ready to do the deed now */
     if (argc <= 1) {
-	fprintf(stderr, "%s: too few arguments", invocationName);
+	fprintf(stderr, "%s: too few arguments\n", invocationName);
 	exit( FALSE);
     }
     while (argc-- > 1) {
@@ -154,7 +165,7 @@
     exit(TRUE);
 
 bad_group:
-    fprintf(stderr, "%s: Unknown group name: %s\n", invocationName, groupName);
+    fprintf(stderr, "%s: unknown group name: %s\n", invocationName, groupName);
     exit( FALSE);
 }
 
diff --git a/coreutils/cp.c b/coreutils/cp.c
deleted file mode 100644
index e96012d..0000000
--- a/coreutils/cp.c
+++ /dev/null
@@ -1,127 +0,0 @@
-/*
- * Mini cp implementation for busybox
- *
- *
- * Copyright (C) 1999 by Lineo, inc.
- * Written by Erik Andersen <andersen@lineo.com>, <andersee@debian.org>
- *
- * 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 <time.h>
-#include <utime.h>
-#include <dirent.h>
-
-static const char cp_usage[] = "cp [OPTION]... SOURCE DEST\n"
-    "   or: cp [OPTION]... SOURCE... DIRECTORY\n\n"
-    "Copy SOURCE to DEST, or multiple SOURCE(s) to DIRECTORY.\n"
-    "\n"
-    "\t-a\tsame as -dpR\n"
-    "\t-d\tpreserve links\n"
-    "\t-p\tpreserve file attributes if possible\n"
-    "\t-R\tcopy directories recursively\n";
-
-
-static int recursiveFlag = FALSE;
-static int followLinks = FALSE;
-static int preserveFlag = FALSE;
-static const char *srcName;
-static const char *destName;
-static int destDirFlag = FALSE;
-static int srcDirFlag = FALSE;
-
-static int fileAction(const char *fileName, struct stat* statbuf)
-{
-    char newdestName[NAME_MAX];
-    char* newsrcName = NULL;
-
-    strcpy(newdestName, destName);
-    if ( srcDirFlag == TRUE ) {
-	if (recursiveFlag!=TRUE ) {
-	    fprintf(stderr, "cp: %s: omitting directory\n", srcName);
-	    return( TRUE);
-	}
-	strcat(newdestName, strstr(fileName, srcName) + strlen(srcName));
-    } 
-    
-    if (destDirFlag==TRUE && srcDirFlag == FALSE) {
-	if (newdestName[strlen(newdestName)-1] != '/' ) {
-	    strcat(newdestName, "/");
-	}
-	newsrcName = strrchr(srcName, '/');
-	if (newsrcName && *newsrcName != '\0')
-	    strcat(newdestName, newsrcName);
-	else
-	    strcat(newdestName, srcName);
-    }
-    
-    return (copyFile(fileName, newdestName, preserveFlag, followLinks));
-}
-
-extern int cp_main(int argc, char **argv)
-{
-    if (argc < 3) {
-	usage (cp_usage);
-    }
-    argc--;
-    argv++;
-
-    /* Parse any options */
-    while (**argv == '-') {
-	while (*++(*argv))
-	    switch (**argv) {
-	    case 'a':
-		followLinks = TRUE;
-		preserveFlag = TRUE;
-		recursiveFlag = TRUE;
-		break;
-	    case 'd':
-		followLinks = TRUE;
-		break;
-	    case 'p':
-		preserveFlag = TRUE;
-		break;
-	    case 'R':
-		recursiveFlag = TRUE;
-		break;
-	    default:
-		usage (cp_usage);
-	    }
-	argc--;
-	argv++;
-    }
-
-
-    destName = argv[argc - 1];
-    destDirFlag = isDirectory(destName);
-
-    if ((argc > 3) && destDirFlag==FALSE) {
-	fprintf(stderr, "%s: not a directory\n", destName);
-	exit (FALSE);
-    }
-
-    while (argc-- > 1) {
-	srcName = *(argv++);
-	srcDirFlag = isDirectory(srcName);
-	if (recursiveAction(srcName, recursiveFlag, followLinks, FALSE,
-			       fileAction, fileAction) == FALSE) {
-	    exit( FALSE);
-	}
-    }
-    exit( TRUE);
-}
diff --git a/coreutils/date.c b/coreutils/date.c
index 77e7c39..a352892 100644
--- a/coreutils/date.c
+++ b/coreutils/date.c
@@ -20,6 +20,10 @@
 */
 
 #include "internal.h"
+#define BB_DECLARE_EXTERN
+#define bb_need_invalid_date
+#define bb_need_memory_exhausted
+#include "messages.c"
 #include <stdlib.h>
 #include <errno.h>
 #include <sys/time.h>
@@ -59,7 +63,7 @@
 	     &(tm_time->tm_year));
 
   if(nr < 4 || nr > 5) {
-    fprintf(stderr, "date: invalid date `%s'\n", t_string);
+    fprintf(stderr, invalid_date, "date", t_string);
     exit( FALSE);
   }
 
@@ -152,7 +156,7 @@
 
   }
 
-  fprintf(stderr, "date: invalid date `%s'\n", t_string);
+  fprintf(stderr, invalid_date, "date", t_string);
 
   exit( FALSE);
 
@@ -190,7 +194,7 @@
 	    case 'u':
 		utc = 1;
 		if (putenv ("TZ=UTC0") != 0) {
-		    fprintf(stderr,"date: memory exhausted\n");
+		    fprintf(stderr, memory_exhausted, "date");
 		    exit( FALSE);
 		}
 		/* Look ma, no break.  Don't fix it either. */
@@ -204,10 +208,10 @@
 	    }
 	} else {
 	    if ( (date_fmt == NULL) && (strcmp(*argv, "+")==0) )
-		date_fmt = *argv;
+		date_fmt=*argv;
 	    else if (date_str == NULL) {
 		set_time = 1;
-		date_str = *argv;
+		date_str=*argv;
 	    } else { 
 		usage ( date_usage);
 	    }
@@ -241,7 +245,7 @@
     /* Correct any day of week and day of year etc fields */
     tm = mktime(&tm_time);
     if (tm < 0 ) {
-      fprintf(stderr, "date: invalid date `%s'\n", date_str);
+      fprintf(stderr, invalid_date, "date", date_str);
       exit( FALSE);
     }
 
@@ -284,4 +288,3 @@
   exit( TRUE);
 
 }
-
diff --git a/coreutils/dd.c b/coreutils/dd.c
index bc01eed..3e1024a 100644
--- a/coreutils/dd.c
+++ b/coreutils/dd.c
@@ -40,15 +40,16 @@
 #endif
 
 static const char dd_usage[] =
-"dd [if=name] [of=name] [bs=n] [count=n]\n\n"
+"dd [if=name] [of=name] [bs=n] [count=n] [skip=n] [seek=n]\n\n"
 "Copy a file, converting and formatting according to options\n\n"
 "\tif=FILE\tread from FILE instead of stdin\n"
-"\tof=FILE\twrite to FILE instead of stout\n"
-"\tbs=n\tread and write N BYTES at a time\n"
+"\tof=FILE\twrite to FILE instead of stdout\n"
+"\tbs=n\tread and write n bytes at a time\n"
 "\tcount=n\tcopy only n input blocks\n"
-//"\tskip=n\tskip n input blocks\n"
+"\tskip=n\tskip n input blocks\n"
+"\tseek=n\tskip n output blocks\n"
 "\n"
-"BYTES may be suffixed by w (x2), k (x1024), b (x512), or m (x1024^2).\n";
+"Numbers may be suffixed by w (x2), k (x1024), b (x512), or M (x1024^2)\n";
 
 
 
@@ -61,8 +62,9 @@
     int outFd;
     int inCc = 0;
     int outCc;
-    size_t blockSize = 512;
-    //uintmax_t skipBlocks = 0;
+    long blockSize = 512;
+    uintmax_t skipBlocks = 0;
+    uintmax_t seekBlocks = 0;
     uintmax_t count = (uintmax_t)-1;
     uintmax_t intotal;
     uintmax_t outTotal;
@@ -91,16 +93,22 @@
 		goto usage;
 	    }
 	}
-#if 0
 	else if (strncmp(*argv, "skip", 4) == 0) {
-	    skipBlocks = atoi( *argv); 
+	    skipBlocks = getNum ((strchr(*argv, '='))+1);
 	    if (skipBlocks <= 0) {
-		fprintf (stderr, "Bad skip value %d\n", skipBlocks);
+		fprintf (stderr, "Bad skip value %s\n", *argv);
 		goto usage;
 	    }
 
 	}
-#endif
+	else if (strncmp(*argv, "seek", 4) == 0) {
+	    seekBlocks = getNum ((strchr(*argv, '='))+1);
+	    if (seekBlocks <= 0) {
+		fprintf (stderr, "Bad seek value %s\n", *argv);
+		goto usage;
+	    }
+
+	}
 	else {
 	    goto usage;
 	}
@@ -131,7 +139,7 @@
     if (outFile == NULL)
 	outFd = fileno(stdout);
     else
-	outFd = creat (outFile, 0666);
+	outFd = open(outFile, O_WRONLY | O_CREAT | O_TRUNC, 0666);
 
     if (outFd < 0) {
 	perror (outFile);
@@ -140,10 +148,11 @@
 	exit( FALSE);
     }
 
-    //lseek(inFd, skipBlocks*blockSize, SEEK_SET);
+    lseek(inFd, skipBlocks*blockSize, SEEK_SET);
+    lseek(outFd, seekBlocks*blockSize, SEEK_SET);
     //
     //TODO: Convert to using fullRead & fullWrite
-    // from utilitity.c
+    // from utility.c
     //  -Erik
     while (outTotal < count * blockSize) {
 	inCc = read (inFd, buf, blockSize);
diff --git a/coreutils/du.c b/coreutils/du.c
index 79b5536..e2cf3f7 100644
--- a/coreutils/du.c
+++ b/coreutils/du.c
@@ -22,17 +22,18 @@
  */
 
 #include "internal.h"
+#define BB_DECLARE_EXTERN
+#define bb_need_name_too_long
+#include "messages.c"
+
 #include <sys/types.h>
 #include <fcntl.h>
 #include <dirent.h>
 #include <stdio.h>
 #include <errno.h>
-#if 0
-#include <unistd.h>
-#include <sys/stat.h>
-#endif
+#include <sys/param.h>		/* for PATH_MAX */
 
-typedef void (Display)(size_t, char *);
+typedef void (Display)(long, char *);
 
 static const char du_usage[] =
 "du [OPTION]... [FILE]...\n\n"
@@ -44,13 +45,13 @@
 static Display	*print;
 
 static void
-print_normal(size_t size, char *filename)
+print_normal(long size, char *filename)
 {
-    fprintf(stdout, "%-7d %s\n", (size >> 1), filename);
+    fprintf(stdout, "%-7ld %s\n", size, filename);
 }
 
 static void
-print_summary(size_t size, char *filename)
+print_summary(long size, char *filename)
 {
     if (du_depth == 1) { 
 	print_normal(size, filename); 
@@ -59,11 +60,11 @@
 
 
 /* tiny recursive du */
-static size_t
+static long
 du(char *filename)
 {
     struct stat statbuf;
-    size_t	sum;
+    long	sum;
 
     if ((lstat(filename, &statbuf)) != 0) { 
 	fprintf(stdout, "du: %s: %s\n", filename, strerror(errno));
@@ -80,14 +81,19 @@
 	dir = opendir(filename);
 	if (!dir) { return 0; }
 	while ((entry = readdir(dir))) {
-	    char newfile[512];
+	    char newfile[PATH_MAX + 1];
 	    char *name = entry->d_name;
 
 	    if (  (strcmp(name, "..") == 0)
 	       || (strcmp(name, ".")  == 0)) 
 	    { continue; }
 
+	    if (strlen(filename) + strlen(name) + 1 > PATH_MAX) {
+	      fprintf(stderr, name_too_long, "du");
+	      return 0;
+	    }
 	    sprintf(newfile, "%s/%s", filename, name);
+
 	    sum += du(newfile);
 	}
 	closedir(dir);
@@ -130,14 +136,14 @@
     if (i >= argc) {
 	du(".");
     } else {
-	int sum;
+	long sum;
 	for ( ; i < argc; i++) {
 	    sum = du(argv[i]);
-	    if ((sum) && (isDirectory(argv[i]))) { print_normal(sum, argv[i]); }
+	    if ((sum) && (isDirectory(argv[i], FALSE))) { print_normal(sum, argv[i]); }
 	}
     }
 
     exit(0);
 }
 
-/* $Id: du.c,v 1.9 2000/01/23 18:19:02 erik Exp $ */
+/* $Id: du.c,v 1.10 2000/02/07 05:29:42 erik Exp $ */
diff --git a/coreutils/head.c b/coreutils/head.c
index bc7f354..b80d065 100644
--- a/coreutils/head.c
+++ b/coreutils/head.c
@@ -105,4 +105,4 @@
     exit(0);
 }
 
-/* $Id: head.c,v 1.6 2000/01/25 18:13:53 erik Exp $ */
+/* $Id: head.c,v 1.7 2000/02/07 05:29:42 erik Exp $ */
diff --git a/coreutils/length.c b/coreutils/length.c
index 46242b5..2c83cdf 100644
--- a/coreutils/length.c
+++ b/coreutils/length.c
@@ -6,7 +6,7 @@
 extern int
 length_main(int argc, char * * argv)
 {
-    if ( **(argv+1) == '-' ) {
+    if ( argc != 2 || **(argv+1) == '-' ) {
 	usage("length string\n");
     }
     printf("%d\n", strlen(argv[1]));
diff --git a/coreutils/ln.c b/coreutils/ln.c
index 60fe394..f20b340 100644
--- a/coreutils/ln.c
+++ b/coreutils/ln.c
@@ -22,26 +22,32 @@
  */
 
 #include "internal.h"
+#define BB_DECLARE_EXTERN
+#define bb_need_name_too_long
+#define bb_need_not_a_directory
+#include "messages.c"
+
 #include <stdio.h>
 #include <dirent.h>
 #include <errno.h>
+#include <sys/param.h>		/* for PATH_MAX */
 
-
-static const char ln_usage[] = "ln [OPTION] TARGET... LINK_NAME|DIRECTORY\n\n"
-"Create a link named LINK_NAME or DIRECTORY to the specified TARGET\n\n"
-"Options:\n"
-"\t-s\tmake symbolic links instead of hard links\n"
-"\t-f\tremove existing destination files\n";
-
+static const char ln_usage[] =
+    "ln [OPTION] TARGET... LINK_NAME|DIRECTORY\n\n"
+    "Create a link named LINK_NAME or DIRECTORY to the specified TARGET\n\n"
+    "Options:\n"
+    "\t-s\tmake symbolic links instead of hard links\n"
+    "\t-f\tremove existing destination files\n"
+    "\t-n\tno dereference symlinks - treat like normal file\n";
 
 static int symlinkFlag = FALSE;
 static int removeoldFlag = FALSE;
-
+static int followLinks = TRUE;
 
 extern int ln_main(int argc, char **argv)
 {
-    int status;
-    static char* linkName;
+    char *linkName;
+    int linkIntoDirFlag;
 
     if (argc < 3) {
 	usage (ln_usage);
@@ -59,6 +65,9 @@
 	    case 'f':
 		removeoldFlag = TRUE;
 		break;
+	    case 'n':
+		followLinks = FALSE;
+		break;
 	    default:
 		usage (ln_usage);
 	    }
@@ -66,30 +75,54 @@
 	argv++;
     }
 
-
     linkName = argv[argc - 1];
 
-    if ((argc > 3) && !(isDirectory(linkName))) {
-	fprintf(stderr, "%s: not a directory\n", linkName);
-	exit (FALSE);
+    if (strlen(linkName) > PATH_MAX) {
+	fprintf(stderr, name_too_long, "ln");
+	exit FALSE;
+    }
+
+    linkIntoDirFlag = isDirectory(linkName, TRUE);
+
+    if ((argc > 3) && !linkIntoDirFlag) {
+	fprintf(stderr, not_a_directory, "ln", linkName);
+	exit FALSE;
     }
 
     while (argc-- >= 2) {
-	if (removeoldFlag==TRUE ) {
+	char srcName[PATH_MAX + 1];
+	int nChars, status;
+
+	if (strlen(*argv) > PATH_MAX) {
+	    fprintf(stderr, name_too_long, "ln");
+	    exit FALSE;
+	}
+
+	if (followLinks == FALSE) {
+	    strcpy(srcName, *argv);
+	} else {
+	    /* Warning!  This can silently truncate if > PATH_MAX, but
+	    I don't think that there can be one > PATH_MAX anyway. */
+	    nChars = readlink(*argv, srcName, PATH_MAX);
+	    srcName[nChars] = '\0';
+	}
+
+	if (removeoldFlag == TRUE) {
 	    status = ( unlink(linkName) && errno != ENOENT );
-	    if ( status != 0 ) {
+	    if (status != 0) {
 		perror(linkName);
-		exit( FALSE);
+		exit FALSE;
 	    }
 	}
-	if ( symlinkFlag==TRUE)
-		status = symlink(*argv, linkName);
+
+	if (symlinkFlag == TRUE)
+	    status = symlink(*argv, linkName);
 	else
-		status = link(*argv, linkName);
-	if ( status != 0 ) {
+	    status = link(*argv, linkName);
+	if (status != 0) {
 	    perror(linkName);
-	    exit( FALSE);
+	    exit FALSE;
 	}
     }
-    exit( TRUE);
+    exit TRUE;
 }
diff --git a/coreutils/ls.c b/coreutils/ls.c
index 78193e7..450ea18 100644
--- a/coreutils/ls.c
+++ b/coreutils/ls.c
@@ -178,7 +178,7 @@
 
 static void list_single(const char *name, struct stat *info, const char *fullname)
 {
-	char scratch[PATH_MAX];
+	char scratch[PATH_MAX + 1];
 	short len = strlen(name);
 #ifdef BB_FEATURE_LS_FILETYPES
 	char append = append_char(info->st_mode);
diff --git a/coreutils/mkdir.c b/coreutils/mkdir.c
index 017ef9b..8e3f51b 100644
--- a/coreutils/mkdir.c
+++ b/coreutils/mkdir.c
@@ -22,9 +22,13 @@
  */
 
 #include "internal.h"
+#define bb_need_name_too_long
+#define BB_DECLARE_EXTERN
+#include "messages.c"
+
 #include <stdio.h>
 #include <errno.h>
-#include <sys/param.h>
+#include <sys/param.h>		/* for PATH_MAX */
 
 static const char mkdir_usage[] =
 "mkdir [OPTION] DIRECTORY...\n\n"
@@ -40,27 +44,27 @@
 
 extern int mkdir_main(int argc, char **argv)
 {
-    int i=FALSE;
+    int i = FALSE;
     argc--;
     argv++;
 
     /* Parse any options */
     while (argc > 0 && **argv == '-') {
-	while (i==FALSE && *++(*argv)) {
+	while (i == FALSE && *++(*argv)) {
 	    switch (**argv) {
 	    case 'm':
 		if (--argc == 0)
 		    usage( mkdir_usage);
 		/* Find the specified modes */
 		mode = 0;
-		if ( parse_mode(*(++argv), &mode) == FALSE ) {
+		if (parse_mode(*(++argv), &mode) == FALSE ) {
 		    fprintf(stderr, "Unknown mode: %s\n", *argv);
-		    exit( FALSE);
+		    exit FALSE;
 		}
 		/* Set the umask for this process so it doesn't 
 		 * screw up whatever the user just entered. */
 		umask(0);
-		i=TRUE;
+		i = TRUE;
 		break;
 	    case 'p':
 		parentFlag = TRUE;
@@ -73,7 +77,6 @@
 	argv++;
     }
 
-
     if (argc < 1) {
 	usage( mkdir_usage);
     }
@@ -81,13 +84,16 @@
     while (argc > 0) {
 	int status;
 	struct stat statBuf;
-	char buf[NAME_MAX];
-
+	char buf[PATH_MAX + 1];
+	if (strlen(*argv) > PATH_MAX - 1) {
+	    fprintf(stderr, name_too_long, "mkdir");
+	    exit FALSE;
+	}
 	strcpy (buf, *argv);
-	status=stat(buf, &statBuf);
-	if (parentFlag == FALSE && status != -1 && status != ENOENT ) {
+	status = stat(buf, &statBuf);
+	if (parentFlag == FALSE && status != -1 && errno != ENOENT) {
 	    fprintf(stderr, "%s: File exists\n", buf);
-	    exit( FALSE);
+	    exit FALSE;
 	}
 	if (parentFlag == TRUE) {
 	    strcat( buf, "/");
@@ -96,13 +102,13 @@
 	else { 
 	    if (mkdir (buf, mode) != 0 && parentFlag == FALSE) {
 		perror(buf);
-		exit( FALSE);
+		exit FALSE;
 	    }
 	}
 	argc--;
 	argv++;
     }
-    exit( TRUE);
+    exit TRUE;
 }
 
 
diff --git a/coreutils/mv.c b/coreutils/mv.c
deleted file mode 100644
index 467a360..0000000
--- a/coreutils/mv.c
+++ /dev/null
@@ -1,112 +0,0 @@
-/*
- * Mini mv implementation for busybox
- *
- *
- * Copyright (C) 1999 by Lineo, inc.
- * Written by Erik Andersen <andersen@lineo.com>, <andersee@debian.org>
- *
- * 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 <time.h>
-#include <utime.h>
-#include <dirent.h>
-
-static const char mv_usage[] = "mv SOURCE DEST\n"
-"   or: mv SOURCE... DIRECTORY\n\n"
-"Rename SOURCE to DEST, or move SOURCE(s) to DIRECTORY.\n";
-
-
-static const char *srcName;
-static const char *destName;
-static int destDirFlag = FALSE;
-static int srcDirFlag = FALSE;
-
-static int fileAction(const char *fileName, struct stat* statbuf)
-{
-    char newdestName[NAME_MAX];
-    char* newsrcName = NULL;
-
-    strcpy(newdestName, destName);
-    if ( srcDirFlag == TRUE ) {
-	strcat(newdestName, strstr(fileName, srcName) + strlen(srcName));
-    } 
-    
-    if (destDirFlag==TRUE && srcDirFlag == FALSE) {
-	if (newdestName[strlen(newdestName)-1] != '/' ) {
-	    strcat(newdestName, "/");
-	}
-	newsrcName = strrchr(srcName, '/');
-	if (newsrcName && *newsrcName != '\0')
-	    strcat(newdestName, newsrcName);
-	else
-	    strcat(newdestName, srcName);
-    }
-    
-    return (copyFile(fileName, newdestName, TRUE, TRUE));
-}
-
-static int rmfileAction(const char *fileName, struct stat* statbuf)
-{
-    if (unlink( fileName) < 0 ) {
-	perror( fileName);
-	return ( FALSE);
-    }
-    return ( TRUE);
-}
-
-static int rmdirAction(const char *fileName, struct stat* statbuf)
-{
-    if (rmdir( fileName) < 0 ) {
-	perror( fileName);
-	return ( FALSE);
-    }
-    return ( TRUE);
-}
-
-
-extern int mv_main(int argc, char **argv)
-{
-    if (argc < 3) {
-	usage (mv_usage);
-    }
-    argc--;
-    argv++;
-
-    destName = argv[argc - 1];
-    destDirFlag = isDirectory(destName);
-
-    if ((argc > 3) && destDirFlag==FALSE) {
-	fprintf(stderr, "%s: not a directory\n", destName);
-	exit (FALSE);
-    }
-
-    while (argc-- > 1) {
-	srcName = *(argv++);
-	srcDirFlag = isDirectory(srcName);
-	if (recursiveAction(srcName, TRUE, TRUE, FALSE,
-			       fileAction, fileAction) == FALSE) {
-	    exit( FALSE);
-	}
-	if (recursiveAction(srcName, TRUE, TRUE, TRUE,
-			       rmfileAction, rmdirAction) == FALSE) {
-	    exit( FALSE);
-	}
-    }
-    exit( TRUE);
-}
diff --git a/coreutils/printf.c b/coreutils/printf.c
index 5be3a67..5fd5ea3 100644
--- a/coreutils/printf.c
+++ b/coreutils/printf.c
@@ -143,7 +143,7 @@
   int args_used;
 
   exit_status = 0;
-  if ( **(argv+1) == '-' ) {
+  if ( argc <= 1 || **(argv+1) == '-' ) {
     usage (printf_usage);
   }
 
diff --git a/coreutils/pwd.c b/coreutils/pwd.c
index c5ce6ff..bacabd7 100644
--- a/coreutils/pwd.c
+++ b/coreutils/pwd.c
@@ -23,11 +23,12 @@
 #include "internal.h"
 #include <stdio.h>
 #include <dirent.h>
+#include <sys/param.h>
 
 extern int
 pwd_main(int argc, char * * argv)
 {
-	char		buf[NAME_MAX];
+	char		buf[PATH_MAX + 1];
 
 	if ( getcwd(buf, sizeof(buf)) == NULL ) {
 		perror("get working directory");
diff --git a/coreutils/sort.c b/coreutils/sort.c
index 4df5627..d529ce7 100644
--- a/coreutils/sort.c
+++ b/coreutils/sort.c
@@ -309,4 +309,4 @@
     exit(0);
 }
 
-/* $Id: sort.c,v 1.9 2000/01/23 18:19:02 erik Exp $ */
+/* $Id: sort.c,v 1.10 2000/02/07 05:29:42 erik Exp $ */
diff --git a/coreutils/tail.c b/coreutils/tail.c
index 5198892..0ab8f11 100644
--- a/coreutils/tail.c
+++ b/coreutils/tail.c
@@ -33,7 +33,7 @@
     and generally busyboxed, Erik Andersen <andersen@lineo.com>
 
    Removed superfluous options and associated code ("-c", "-n", "-q").
-   Removed "tail -f" suport for multiple files.
+   Removed "tail -f" support for multiple files.
    Both changes by Friedrich Vedder <fwv@myrtle.lahn.de>.
 
  */
diff --git a/coreutils/tee.c b/coreutils/tee.c
index 8d1ca6e..4c5c691 100644
--- a/coreutils/tee.c
+++ b/coreutils/tee.c
@@ -123,4 +123,4 @@
     exit(0);
 }
 
-/* $Id: tee.c,v 1.4 1999/12/10 08:25:07 andersen Exp $ */
+/* $Id: tee.c,v 1.5 2000/02/07 05:29:42 erik Exp $ */
diff --git a/coreutils/uniq.c b/coreutils/uniq.c
index a7bff54..965d290 100644
--- a/coreutils/uniq.c
+++ b/coreutils/uniq.c
@@ -193,4 +193,4 @@
     exit(0);
 }
 
-/* $Id: uniq.c,v 1.5 2000/01/23 18:19:02 erik Exp $ */
+/* $Id: uniq.c,v 1.6 2000/02/07 05:29:42 erik Exp $ */
diff --git a/cp.c b/cp.c
deleted file mode 100644
index e96012d..0000000
--- a/cp.c
+++ /dev/null
@@ -1,127 +0,0 @@
-/*
- * Mini cp implementation for busybox
- *
- *
- * Copyright (C) 1999 by Lineo, inc.
- * Written by Erik Andersen <andersen@lineo.com>, <andersee@debian.org>
- *
- * 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 <time.h>
-#include <utime.h>
-#include <dirent.h>
-
-static const char cp_usage[] = "cp [OPTION]... SOURCE DEST\n"
-    "   or: cp [OPTION]... SOURCE... DIRECTORY\n\n"
-    "Copy SOURCE to DEST, or multiple SOURCE(s) to DIRECTORY.\n"
-    "\n"
-    "\t-a\tsame as -dpR\n"
-    "\t-d\tpreserve links\n"
-    "\t-p\tpreserve file attributes if possible\n"
-    "\t-R\tcopy directories recursively\n";
-
-
-static int recursiveFlag = FALSE;
-static int followLinks = FALSE;
-static int preserveFlag = FALSE;
-static const char *srcName;
-static const char *destName;
-static int destDirFlag = FALSE;
-static int srcDirFlag = FALSE;
-
-static int fileAction(const char *fileName, struct stat* statbuf)
-{
-    char newdestName[NAME_MAX];
-    char* newsrcName = NULL;
-
-    strcpy(newdestName, destName);
-    if ( srcDirFlag == TRUE ) {
-	if (recursiveFlag!=TRUE ) {
-	    fprintf(stderr, "cp: %s: omitting directory\n", srcName);
-	    return( TRUE);
-	}
-	strcat(newdestName, strstr(fileName, srcName) + strlen(srcName));
-    } 
-    
-    if (destDirFlag==TRUE && srcDirFlag == FALSE) {
-	if (newdestName[strlen(newdestName)-1] != '/' ) {
-	    strcat(newdestName, "/");
-	}
-	newsrcName = strrchr(srcName, '/');
-	if (newsrcName && *newsrcName != '\0')
-	    strcat(newdestName, newsrcName);
-	else
-	    strcat(newdestName, srcName);
-    }
-    
-    return (copyFile(fileName, newdestName, preserveFlag, followLinks));
-}
-
-extern int cp_main(int argc, char **argv)
-{
-    if (argc < 3) {
-	usage (cp_usage);
-    }
-    argc--;
-    argv++;
-
-    /* Parse any options */
-    while (**argv == '-') {
-	while (*++(*argv))
-	    switch (**argv) {
-	    case 'a':
-		followLinks = TRUE;
-		preserveFlag = TRUE;
-		recursiveFlag = TRUE;
-		break;
-	    case 'd':
-		followLinks = TRUE;
-		break;
-	    case 'p':
-		preserveFlag = TRUE;
-		break;
-	    case 'R':
-		recursiveFlag = TRUE;
-		break;
-	    default:
-		usage (cp_usage);
-	    }
-	argc--;
-	argv++;
-    }
-
-
-    destName = argv[argc - 1];
-    destDirFlag = isDirectory(destName);
-
-    if ((argc > 3) && destDirFlag==FALSE) {
-	fprintf(stderr, "%s: not a directory\n", destName);
-	exit (FALSE);
-    }
-
-    while (argc-- > 1) {
-	srcName = *(argv++);
-	srcDirFlag = isDirectory(srcName);
-	if (recursiveAction(srcName, recursiveFlag, followLinks, FALSE,
-			       fileAction, fileAction) == FALSE) {
-	    exit( FALSE);
-	}
-    }
-    exit( TRUE);
-}
diff --git a/cp_mv.c b/cp_mv.c
new file mode 100644
index 0000000..2ba8662
--- /dev/null
+++ b/cp_mv.c
@@ -0,0 +1,258 @@
+/*
+ * Mini `cp' and `mv' implementation for BusyBox.
+ *
+ *
+ * Copyright (C) 1999 by Lineo, inc.
+ * Written by Erik Andersen <andersen@lineo.com>, <andersee@debian.org>
+ *
+ * Copyright (C) 2000 by BitterSweet Enterprises, LLC. (GPL)
+ * Extensively modified and rewritten by  Karl M. Hegbloom <karlheg@debian.org>
+ *
+ * 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"
+#define BB_DECLARE_EXTERN
+#define bb_need_name_too_long
+#define bb_need_omitting_directory
+#define bb_need_not_a_directory
+#include "messages.c"
+
+#include <stdio.h>
+#include <time.h>
+#include <utime.h>
+#include <dirent.h>
+#include <sys/param.h>
+
+#define is_cp 0
+#define is_mv 1
+static const char *dz;		/* dollar zero, .bss */
+static int dz_i;		/* index,       .bss */
+static const char *cp_mv_usage[] =     /* .rodata */
+{
+     "cp [OPTION]... SOURCE DEST\n"
+     "   or: cp [OPTION]... SOURCE... DIRECTORY\n\n"
+     "Copy SOURCE to DEST, or multiple SOURCE(s) to DIRECTORY.\n"
+     "\n"
+     "\t-a\tsame as -dpR\n"
+     "\t-d\tpreserve links\n"
+     "\t-p\tpreserve file attributes if possible\n"
+     "\t-R\tcopy directories recursively\n"
+     ,
+     "mv SOURCE DEST\n"
+     "   or: mv SOURCE... DIRECTORY\n\n"
+     "Rename SOURCE to DEST, or move SOURCE(s) to DIRECTORY.\n"
+     "Warning!!  This is not GNU `mv'.  It does not preserve hard links.\n"
+};
+
+extern int cp_mv_main(int argc, char **argv)
+{
+    __label__ name_too_long__exit;
+    __label__ exit_false;
+
+    int         recursiveFlag;
+    int         followLinks;
+    int         preserveFlag;
+
+    const char *baseSrcName;
+    int         srcDirFlag;
+
+    char        baseDestName[PATH_MAX + 1];
+    size_t      baseDestLen;
+    int         destDirFlag;
+
+    void fill_baseDest_buf(char *_buf, size_t *_buflen)
+	{
+	    const char *srcBasename;
+	    if ((srcBasename = strrchr(baseSrcName, '/')) == NULL)
+	    {
+		srcBasename = baseSrcName;
+		if (_buf[*_buflen - 1] != '/')
+		{
+		    if (++(*_buflen) > PATH_MAX)
+			goto name_too_long__exit;
+		    strcat(_buf, "/");
+		}
+	    }
+	    if (*_buflen + strlen(srcBasename) > PATH_MAX)
+		goto name_too_long__exit;
+	    strcat(_buf, srcBasename);
+	    return;
+	}
+
+    int fileAction(const char *fileName, struct stat *statbuf)
+	{
+	    __label__   return_false;
+	    char        destName[PATH_MAX + 1];
+	    size_t      destLen;
+	    const char *srcBasename;
+	    
+	    strcpy(destName, baseDestName);
+	    destLen = strlen(destName);
+	    
+	    if (srcDirFlag == TRUE)
+	    {
+		if (recursiveFlag == FALSE)
+		{
+		    fprintf(stderr, omitting_directory, "cp", baseSrcName);
+		    return TRUE;
+		}
+		srcBasename = (strstr(fileName, baseSrcName)
+			       + strlen(baseSrcName));
+		if (destLen + strlen(srcBasename) > PATH_MAX)
+		{
+		    fprintf(stderr, name_too_long, "cp");
+		    goto return_false;
+		}
+		strcat(destName, srcBasename);
+	    }
+	    else if (destDirFlag == TRUE)
+	    {
+		fill_baseDest_buf(&destName[0], &destLen);
+	    }
+	    else
+	    {
+		srcBasename = baseSrcName;
+	    }
+	    return copyFile(fileName, destName, preserveFlag, followLinks);
+	    
+	return_false:
+	    return FALSE;
+	}
+
+    int rmfileAction(const char *fileName, struct stat* statbuf)
+	 {
+	      if (unlink(fileName) < 0 ) {
+		   perror(fileName);
+		   return FALSE;
+	      }
+	      return TRUE;
+	 }
+
+    int rmdirAction(const char *fileName, struct stat* statbuf)
+	 {
+	      if (rmdir(fileName) < 0 ) {
+		   perror(fileName);
+		   return FALSE;
+	      }
+	      return TRUE;
+	 }
+
+    if ((dz = strrchr(*argv, '/')) == NULL) dz = *argv; else dz++;
+    if (*dz == 'c' && *(dz + 1) == 'p') dz_i = is_cp; else dz_i = is_mv;
+    if (argc < 3) usage(cp_mv_usage[dz_i]);
+    argc--;
+    argv++;
+
+    if (dz_i == is_cp)
+    {
+	recursiveFlag = preserveFlag = FALSE;
+	followLinks = TRUE;
+	while (**argv == '-')
+	{
+	    while (*++(*argv))
+	    {
+		switch (**argv)
+		{
+		case 'a':
+		    followLinks   = FALSE;
+		    preserveFlag  = TRUE;
+		    recursiveFlag = TRUE;
+		    break;
+		case 'd':
+		    followLinks   = FALSE;
+		    break;
+		case 'p':
+		    preserveFlag  = TRUE;
+		    break;
+		case 'R':
+		    recursiveFlag = TRUE;
+		    break;
+		default:
+		    usage(cp_mv_usage[is_cp]);
+		}
+	    }
+	    argc--;
+	    argv++;
+	}
+    }
+    else /* (dz_i == is_mv) */
+    {
+	recursiveFlag = preserveFlag = TRUE;
+	followLinks = FALSE;
+    }
+
+    if (strlen(argv[argc - 1]) > PATH_MAX)
+    {
+	fprintf(stderr, name_too_long, "cp");
+	goto exit_false;
+    }
+    strcpy(baseDestName, argv[argc - 1]);
+    baseDestLen = strlen(baseDestName);
+    if (baseDestLen == 0) goto exit_false;
+
+    destDirFlag = isDirectory(baseDestName, TRUE);
+    if ((argc > 3) && destDirFlag == FALSE)
+    {
+	fprintf(stderr, not_a_directory, "cp", baseDestName);
+	goto exit_false;
+    }
+
+    while (argc-- > 1)
+    {
+	size_t srcLen;
+	int    flags_memo;
+
+	baseSrcName = *(argv++);
+
+	if ((srcLen = strlen(baseSrcName)) > PATH_MAX)
+	    goto name_too_long__exit;
+
+	if (srcLen == 0) continue;
+
+	srcDirFlag = isDirectory(baseSrcName, followLinks);
+
+	if ((flags_memo = (recursiveFlag == TRUE &&
+			   srcDirFlag == TRUE && destDirFlag == TRUE)))
+	{
+	    fill_baseDest_buf(&baseDestName[0], &baseDestLen);
+	}
+	if (recursiveAction(baseSrcName,
+			    recursiveFlag, followLinks, FALSE,
+			    fileAction, fileAction)
+	    == FALSE) goto exit_false;
+
+	if (dz_i == is_mv &&
+	    recursiveAction(baseSrcName,
+			    recursiveFlag, followLinks, TRUE,
+			    rmfileAction, rmdirAction)
+	    == FALSE) goto exit_false;
+
+	if (flags_memo) *(baseDestName + baseDestLen) = '\0';
+    }
+
+    exit TRUE;
+
+ name_too_long__exit:
+    fprintf(stderr, name_too_long, "cp");
+ exit_false:
+    exit FALSE;
+}
+
+// Local Variables:
+// c-file-style: "k&r"
+// c-basic-offset: 4
+// End:
diff --git a/date.c b/date.c
index 77e7c39..a352892 100644
--- a/date.c
+++ b/date.c
@@ -20,6 +20,10 @@
 */
 
 #include "internal.h"
+#define BB_DECLARE_EXTERN
+#define bb_need_invalid_date
+#define bb_need_memory_exhausted
+#include "messages.c"
 #include <stdlib.h>
 #include <errno.h>
 #include <sys/time.h>
@@ -59,7 +63,7 @@
 	     &(tm_time->tm_year));
 
   if(nr < 4 || nr > 5) {
-    fprintf(stderr, "date: invalid date `%s'\n", t_string);
+    fprintf(stderr, invalid_date, "date", t_string);
     exit( FALSE);
   }
 
@@ -152,7 +156,7 @@
 
   }
 
-  fprintf(stderr, "date: invalid date `%s'\n", t_string);
+  fprintf(stderr, invalid_date, "date", t_string);
 
   exit( FALSE);
 
@@ -190,7 +194,7 @@
 	    case 'u':
 		utc = 1;
 		if (putenv ("TZ=UTC0") != 0) {
-		    fprintf(stderr,"date: memory exhausted\n");
+		    fprintf(stderr, memory_exhausted, "date");
 		    exit( FALSE);
 		}
 		/* Look ma, no break.  Don't fix it either. */
@@ -204,10 +208,10 @@
 	    }
 	} else {
 	    if ( (date_fmt == NULL) && (strcmp(*argv, "+")==0) )
-		date_fmt = *argv;
+		date_fmt=*argv;
 	    else if (date_str == NULL) {
 		set_time = 1;
-		date_str = *argv;
+		date_str=*argv;
 	    } else { 
 		usage ( date_usage);
 	    }
@@ -241,7 +245,7 @@
     /* Correct any day of week and day of year etc fields */
     tm = mktime(&tm_time);
     if (tm < 0 ) {
-      fprintf(stderr, "date: invalid date `%s'\n", date_str);
+      fprintf(stderr, invalid_date, "date", date_str);
       exit( FALSE);
     }
 
@@ -284,4 +288,3 @@
   exit( TRUE);
 
 }
-
diff --git a/dd.c b/dd.c
index bc01eed..3e1024a 100644
--- a/dd.c
+++ b/dd.c
@@ -40,15 +40,16 @@
 #endif
 
 static const char dd_usage[] =
-"dd [if=name] [of=name] [bs=n] [count=n]\n\n"
+"dd [if=name] [of=name] [bs=n] [count=n] [skip=n] [seek=n]\n\n"
 "Copy a file, converting and formatting according to options\n\n"
 "\tif=FILE\tread from FILE instead of stdin\n"
-"\tof=FILE\twrite to FILE instead of stout\n"
-"\tbs=n\tread and write N BYTES at a time\n"
+"\tof=FILE\twrite to FILE instead of stdout\n"
+"\tbs=n\tread and write n bytes at a time\n"
 "\tcount=n\tcopy only n input blocks\n"
-//"\tskip=n\tskip n input blocks\n"
+"\tskip=n\tskip n input blocks\n"
+"\tseek=n\tskip n output blocks\n"
 "\n"
-"BYTES may be suffixed by w (x2), k (x1024), b (x512), or m (x1024^2).\n";
+"Numbers may be suffixed by w (x2), k (x1024), b (x512), or M (x1024^2)\n";
 
 
 
@@ -61,8 +62,9 @@
     int outFd;
     int inCc = 0;
     int outCc;
-    size_t blockSize = 512;
-    //uintmax_t skipBlocks = 0;
+    long blockSize = 512;
+    uintmax_t skipBlocks = 0;
+    uintmax_t seekBlocks = 0;
     uintmax_t count = (uintmax_t)-1;
     uintmax_t intotal;
     uintmax_t outTotal;
@@ -91,16 +93,22 @@
 		goto usage;
 	    }
 	}
-#if 0
 	else if (strncmp(*argv, "skip", 4) == 0) {
-	    skipBlocks = atoi( *argv); 
+	    skipBlocks = getNum ((strchr(*argv, '='))+1);
 	    if (skipBlocks <= 0) {
-		fprintf (stderr, "Bad skip value %d\n", skipBlocks);
+		fprintf (stderr, "Bad skip value %s\n", *argv);
 		goto usage;
 	    }
 
 	}
-#endif
+	else if (strncmp(*argv, "seek", 4) == 0) {
+	    seekBlocks = getNum ((strchr(*argv, '='))+1);
+	    if (seekBlocks <= 0) {
+		fprintf (stderr, "Bad seek value %s\n", *argv);
+		goto usage;
+	    }
+
+	}
 	else {
 	    goto usage;
 	}
@@ -131,7 +139,7 @@
     if (outFile == NULL)
 	outFd = fileno(stdout);
     else
-	outFd = creat (outFile, 0666);
+	outFd = open(outFile, O_WRONLY | O_CREAT | O_TRUNC, 0666);
 
     if (outFd < 0) {
 	perror (outFile);
@@ -140,10 +148,11 @@
 	exit( FALSE);
     }
 
-    //lseek(inFd, skipBlocks*blockSize, SEEK_SET);
+    lseek(inFd, skipBlocks*blockSize, SEEK_SET);
+    lseek(outFd, seekBlocks*blockSize, SEEK_SET);
     //
     //TODO: Convert to using fullRead & fullWrite
-    // from utilitity.c
+    // from utility.c
     //  -Erik
     while (outTotal < count * blockSize) {
 	inCc = read (inFd, buf, blockSize);
diff --git a/du.c b/du.c
index 79b5536..e2cf3f7 100644
--- a/du.c
+++ b/du.c
@@ -22,17 +22,18 @@
  */
 
 #include "internal.h"
+#define BB_DECLARE_EXTERN
+#define bb_need_name_too_long
+#include "messages.c"
+
 #include <sys/types.h>
 #include <fcntl.h>
 #include <dirent.h>
 #include <stdio.h>
 #include <errno.h>
-#if 0
-#include <unistd.h>
-#include <sys/stat.h>
-#endif
+#include <sys/param.h>		/* for PATH_MAX */
 
-typedef void (Display)(size_t, char *);
+typedef void (Display)(long, char *);
 
 static const char du_usage[] =
 "du [OPTION]... [FILE]...\n\n"
@@ -44,13 +45,13 @@
 static Display	*print;
 
 static void
-print_normal(size_t size, char *filename)
+print_normal(long size, char *filename)
 {
-    fprintf(stdout, "%-7d %s\n", (size >> 1), filename);
+    fprintf(stdout, "%-7ld %s\n", size, filename);
 }
 
 static void
-print_summary(size_t size, char *filename)
+print_summary(long size, char *filename)
 {
     if (du_depth == 1) { 
 	print_normal(size, filename); 
@@ -59,11 +60,11 @@
 
 
 /* tiny recursive du */
-static size_t
+static long
 du(char *filename)
 {
     struct stat statbuf;
-    size_t	sum;
+    long	sum;
 
     if ((lstat(filename, &statbuf)) != 0) { 
 	fprintf(stdout, "du: %s: %s\n", filename, strerror(errno));
@@ -80,14 +81,19 @@
 	dir = opendir(filename);
 	if (!dir) { return 0; }
 	while ((entry = readdir(dir))) {
-	    char newfile[512];
+	    char newfile[PATH_MAX + 1];
 	    char *name = entry->d_name;
 
 	    if (  (strcmp(name, "..") == 0)
 	       || (strcmp(name, ".")  == 0)) 
 	    { continue; }
 
+	    if (strlen(filename) + strlen(name) + 1 > PATH_MAX) {
+	      fprintf(stderr, name_too_long, "du");
+	      return 0;
+	    }
 	    sprintf(newfile, "%s/%s", filename, name);
+
 	    sum += du(newfile);
 	}
 	closedir(dir);
@@ -130,14 +136,14 @@
     if (i >= argc) {
 	du(".");
     } else {
-	int sum;
+	long sum;
 	for ( ; i < argc; i++) {
 	    sum = du(argv[i]);
-	    if ((sum) && (isDirectory(argv[i]))) { print_normal(sum, argv[i]); }
+	    if ((sum) && (isDirectory(argv[i], FALSE))) { print_normal(sum, argv[i]); }
 	}
     }
 
     exit(0);
 }
 
-/* $Id: du.c,v 1.9 2000/01/23 18:19:02 erik Exp $ */
+/* $Id: du.c,v 1.10 2000/02/07 05:29:42 erik Exp $ */
diff --git a/fdflush.c b/fdflush.c
index 51b0c2b..a244e8d 100644
--- a/fdflush.c
+++ b/fdflush.c
@@ -31,7 +31,7 @@
 {
     int	value;
     int	fd;
-    if ( **(argv+1) == '-' ) {
+    if ( argc <= 1 || **(argv++) == '-' ) {
 	usage( "fdflush device\n");
     }
 
diff --git a/find.c b/find.c
index 47ce21e..50872b7 100644
--- a/find.c
+++ b/find.c
@@ -90,7 +90,7 @@
 		if (strcmp(*argv, "name")==0) {
 		    if (argc-- > 1) {
 			pattern = *(++argv);
-			stopit=TRUE;
+			stopit = TRUE;
 		    } else {
 			usage (find_usage);
 		    }
diff --git a/findutils/find.c b/findutils/find.c
index 47ce21e..50872b7 100644
--- a/findutils/find.c
+++ b/findutils/find.c
@@ -90,7 +90,7 @@
 		if (strcmp(*argv, "name")==0) {
 		    if (argc-- > 1) {
 			pattern = *(++argv);
-			stopit=TRUE;
+			stopit = TRUE;
 		    } else {
 			usage (find_usage);
 		    }
diff --git a/fsck_minix.c b/fsck_minix.c
index d31de20..09111c5 100644
--- a/fsck_minix.c
+++ b/fsck_minix.c
@@ -96,6 +96,7 @@
 #include <termios.h>
 #include <mntent.h>
 #include <sys/stat.h>
+#include <sys/param.h>		/* for PATH_MAX */
 
 #include <linux/fs.h>
 #include <linux/minix_fs.h>
@@ -143,7 +144,7 @@
 /* File-name data */
 #define MAX_DEPTH 50
 static int name_depth = 0;
-static char name_list[MAX_DEPTH][NAME_MAX+1];
+static char name_list[MAX_DEPTH][PATH_MAX + 1];
 
 static char * inode_buffer = NULL;
 #define Inode (((struct minix_inode *) inode_buffer)-1)
diff --git a/gunzip.c b/gunzip.c
index fddcc76..db7fa1d 100644
--- a/gunzip.c
+++ b/gunzip.c
@@ -3,6 +3,9 @@
    */
 
 #include "internal.h"
+#define bb_need_name_too_long
+#define BB_DECLARE_EXTERN
+#include "messages.c"
 
 static const char gunzip_usage[] =
     "gunzip [OPTION]... FILE\n\n"
@@ -64,6 +67,7 @@
 #include <signal.h>
 #include <sys/stat.h>
 #include <errno.h>
+#include <sys/param.h>		/* for PATH_MAX */
 
 /* #include "tailor.h" */
 
@@ -627,8 +631,12 @@
 #endif
 #define RW_USER (S_IRUSR | S_IWUSR)  /* creation mode for open() */
 
-#ifndef MAX_PATH_LEN
-#  define MAX_PATH_LEN   1024 /* max pathname length */
+#ifndef MAX_PATH_LEN /* max pathname length */
+#  ifdef PATH_MAX
+#    define MAX_PATH_LEN   PATH_MAX
+#  else
+#    define MAX_PATH_LEN   1024
+#  endif
 #endif
 
 #ifndef SEEK_END
@@ -696,8 +704,8 @@
     int delInputFile=0;
     struct stat statBuf;
     char* delFileName; 
-    char ifname[MAX_PATH_LEN]; /* input file name */
-    char ofname[MAX_PATH_LEN]; /* output file name */
+    char ifname[MAX_PATH_LEN + 1]; /* input file name */
+    char ofname[MAX_PATH_LEN + 1]; /* output file name */
 
     if (argc==1)
 	usage(gunzip_usage);
@@ -764,7 +772,11 @@
 	/* Open up the input file */
 	if (*argv=='\0')
 	    usage(gunzip_usage);
-	strncpy(ifname, *argv, MAX_PATH_LEN);
+	if (strlen(*argv) > MAX_PATH_LEN) {
+	    fprintf(stderr, name_too_long, "gunzip");
+	    do_exit(WARNING);
+	}
+	strcpy(ifname, *argv);
 
 	/* Open input fille */
 	inFileNum=open( ifname, O_RDONLY);
@@ -799,7 +811,11 @@
 	char* pos;
 
 	/* And get to work */
-	strncpy(ofname, ifname, MAX_PATH_LEN-4);
+	if (strlen(ifname) > MAX_PATH_LEN - 4) {
+	    fprintf(stderr, name_too_long, "gunzip");
+	    do_exit(WARNING);
+	}
+	strcpy(ofname, ifname);
 	pos=strstr(ofname, ".gz");
 	if (pos != NULL) {
 	    *pos='\0';
diff --git a/head.c b/head.c
index bc7f354..b80d065 100644
--- a/head.c
+++ b/head.c
@@ -105,4 +105,4 @@
     exit(0);
 }
 
-/* $Id: head.c,v 1.6 2000/01/25 18:13:53 erik Exp $ */
+/* $Id: head.c,v 1.7 2000/02/07 05:29:42 erik Exp $ */
diff --git a/hostname.c b/hostname.c
index 20e1741..68a5609 100644
--- a/hostname.c
+++ b/hostname.c
@@ -1,5 +1,5 @@
 /*
- * $Id: hostname.c,v 1.5 1999/12/09 06:11:36 andersen Exp $
+ * $Id: hostname.c,v 1.6 2000/02/07 05:29:42 erik Exp $
  * Mini hostname implementation for busybox
  *
  * Copyright (C) 1999 by Randolph Chung <tausq@debian.org>
diff --git a/init.c b/init.c
index d88b64b..2b1d213 100644
--- a/init.c
+++ b/init.c
@@ -40,6 +40,7 @@
 #include <sys/reboot.h>
 #include <sys/kdaemon.h>
 #include <sys/sysmacros.h>
+#include <asm/types.h>
 #include <linux/serial.h>	/* for serial_struct */
 #include <sys/vt.h>		/* for vt_stat */
 #include <sys/ioctl.h>
@@ -123,7 +124,7 @@
 
     /* Retry up to 5 times */
     for (f = 0; f < 5; f++)
-	if ((fd = open(device, m)) >= 0)
+	if ((fd = open(device, m, 0600)) >= 0)
 	    break;
     if (fd < 0)
 	return fd;
@@ -470,19 +471,19 @@
     sync();
 
     /* Send signals to every process _except_ pid 1 */
-    message(CONSOLE, "Sending SIGHUP to all processes.\r\n");
-    kill(-1, SIGHUP);
-    sleep(2);
+    message(CONSOLE, "Sending SIGTERM to all processes.\r\n");
+    kill(-1, SIGTERM);
+    sleep(5);
     sync();
 
     message(CONSOLE, "Sending SIGKILL to all processes.\r\n");
     kill(-1, SIGKILL);
-    sleep(1);
+    sleep(5);
 
     message(CONSOLE, "Disabling swap.\r\n");
-    waitfor( "swapoff -a", console, FALSE);
+	waitfor( "swapoff -a", console, FALSE);
     message(CONSOLE, "Unmounting filesystems.\r\n");
-    waitfor("umount -a", console, FALSE);
+	waitfor("umount -a -r", console, FALSE);
     sync();
     if (kernelVersion > 0 && kernelVersion <= 2 * 65536 + 2 * 256 + 11) {
 	/* bdflush, kupdate not needed for kernels >2.2.11 */
@@ -500,7 +501,7 @@
     sync();
 
     /* allow time for last message to reach serial console */
-    sleep(2);
+    sleep(5);
 
 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0)
     if (sig == SIGUSR2)
diff --git a/init/init.c b/init/init.c
index d88b64b..2b1d213 100644
--- a/init/init.c
+++ b/init/init.c
@@ -40,6 +40,7 @@
 #include <sys/reboot.h>
 #include <sys/kdaemon.h>
 #include <sys/sysmacros.h>
+#include <asm/types.h>
 #include <linux/serial.h>	/* for serial_struct */
 #include <sys/vt.h>		/* for vt_stat */
 #include <sys/ioctl.h>
@@ -123,7 +124,7 @@
 
     /* Retry up to 5 times */
     for (f = 0; f < 5; f++)
-	if ((fd = open(device, m)) >= 0)
+	if ((fd = open(device, m, 0600)) >= 0)
 	    break;
     if (fd < 0)
 	return fd;
@@ -470,19 +471,19 @@
     sync();
 
     /* Send signals to every process _except_ pid 1 */
-    message(CONSOLE, "Sending SIGHUP to all processes.\r\n");
-    kill(-1, SIGHUP);
-    sleep(2);
+    message(CONSOLE, "Sending SIGTERM to all processes.\r\n");
+    kill(-1, SIGTERM);
+    sleep(5);
     sync();
 
     message(CONSOLE, "Sending SIGKILL to all processes.\r\n");
     kill(-1, SIGKILL);
-    sleep(1);
+    sleep(5);
 
     message(CONSOLE, "Disabling swap.\r\n");
-    waitfor( "swapoff -a", console, FALSE);
+	waitfor( "swapoff -a", console, FALSE);
     message(CONSOLE, "Unmounting filesystems.\r\n");
-    waitfor("umount -a", console, FALSE);
+	waitfor("umount -a -r", console, FALSE);
     sync();
     if (kernelVersion > 0 && kernelVersion <= 2 * 65536 + 2 * 256 + 11) {
 	/* bdflush, kupdate not needed for kernels >2.2.11 */
@@ -500,7 +501,7 @@
     sync();
 
     /* allow time for last message to reach serial console */
-    sleep(2);
+    sleep(5);
 
 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0)
     if (sig == SIGUSR2)
diff --git a/insmod.c b/insmod.c
index 9cb635f..31cb112 100644
--- a/insmod.c
+++ b/insmod.c
@@ -67,8 +67,8 @@
 #endif
 
 
-static char m_filename[PATH_MAX] = "\0";
-static char m_fullName[PATH_MAX] ="\0";
+static char m_filename[PATH_MAX + 1] = "\0";
+static char m_fullName[PATH_MAX + 1] = "\0";
 static const char insmod_usage[] =
     "insmod [OPTION]... MODULE [symbol=value]...\n\n"
     "Loads the specified kernel modules into the kernel.\n\n"
@@ -101,7 +101,7 @@
 {
     int len;
     char *tmp;
-    char m_name[PATH_MAX] ="\0";
+    char m_name[PATH_MAX + 1] ="\0";
     FILE *fp;
 
     if (argc<=1) {
diff --git a/internal.h b/internal.h
index 1686054..79e6a03 100644
--- a/internal.h
+++ b/internal.h
@@ -1,3 +1,4 @@
+
 /*
  * Busybox main internal header file
  *
@@ -20,8 +21,8 @@
  * Permission has been granted to redistribute this code under the GPL.
  *
  */
-#ifndef	_INTERNAL_H_
-#define	_INTERNAL_H_
+#ifndef	_BB_INTERNAL_H_
+#define	_BB_INTERNAL_H_    1
 
 #include "busybox.def.h"
 
@@ -37,7 +38,10 @@
 #define FALSE   ((int) 1)
 #define TRUE    ((int) 0)
 
-#define PATH_LEN        1024
+/* for mtab.c */
+#define MTAB_GETMOUNTPT '1'
+#define MTAB_GETDEVICE  '2'
+
 #define BUF_SIZE        8192
 #define EXPAND_ALLOC    1024
 
@@ -55,7 +59,7 @@
 extern int busybox_main(int argc, char** argv);
 extern int block_device_main(int argc, char** argv);
 extern int cat_main(int argc, char** argv);
-extern int cp_main(int argc, char** argv);
+extern int cp_mv_main(int argc, char** argv);
 extern int chmod_chown_chgrp_main(int argc, char** argv);
 extern int chroot_main(int argc, char** argv);
 extern int chvt_main(int argc, char** argv);
@@ -105,8 +109,7 @@
 extern int more_main(int argc, char** argv);
 extern int mount_main(int argc, char** argv);
 extern int mt_main(int argc, char** argv);
-extern int mv_main(int argc, char** argv);
-extern int nslookup_main(int argc, char** argv);
+extern int nslookup_main(int argc, char **argv);
 extern int ping_main(int argc, char **argv);
 extern int poweroff_main(int argc, char **argv);
 extern int printf_main(int argc, char** argv);
@@ -142,7 +145,7 @@
 
 const char *modeString(int mode);
 const char *timeString(time_t timeVal);
-int isDirectory(const char *name);
+int isDirectory(const char *name, const int followLinks);
 int isDevice(const char *name);
 int copyFile(const char *srcName, const char *destName, int setModes,
 	        int followLinks);
@@ -172,6 +175,11 @@
 extern void write_mtab(char* blockDevice, char* directory, 
 	char* filesystemType, long flags, char* string_flags);
 extern void erase_mtab(const char * name);
+extern void mtab_read(void);
+extern void mtab_free(void);
+extern char *mtab_first(void **iter);
+extern char *mtab_next(void **iter);
+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();
@@ -226,5 +234,4 @@
 #endif
 
 
-#endif /* _INTERNAL_H_ */
-
+#endif /* _BB_INTERNAL_H_ */
diff --git a/length.c b/length.c
index 46242b5..2c83cdf 100644
--- a/length.c
+++ b/length.c
@@ -6,7 +6,7 @@
 extern int
 length_main(int argc, char * * argv)
 {
-    if ( **(argv+1) == '-' ) {
+    if ( argc != 2 || **(argv+1) == '-' ) {
 	usage("length string\n");
     }
     printf("%d\n", strlen(argv[1]));
diff --git a/ln.c b/ln.c
index 60fe394..f20b340 100644
--- a/ln.c
+++ b/ln.c
@@ -22,26 +22,32 @@
  */
 
 #include "internal.h"
+#define BB_DECLARE_EXTERN
+#define bb_need_name_too_long
+#define bb_need_not_a_directory
+#include "messages.c"
+
 #include <stdio.h>
 #include <dirent.h>
 #include <errno.h>
+#include <sys/param.h>		/* for PATH_MAX */
 
-
-static const char ln_usage[] = "ln [OPTION] TARGET... LINK_NAME|DIRECTORY\n\n"
-"Create a link named LINK_NAME or DIRECTORY to the specified TARGET\n\n"
-"Options:\n"
-"\t-s\tmake symbolic links instead of hard links\n"
-"\t-f\tremove existing destination files\n";
-
+static const char ln_usage[] =
+    "ln [OPTION] TARGET... LINK_NAME|DIRECTORY\n\n"
+    "Create a link named LINK_NAME or DIRECTORY to the specified TARGET\n\n"
+    "Options:\n"
+    "\t-s\tmake symbolic links instead of hard links\n"
+    "\t-f\tremove existing destination files\n"
+    "\t-n\tno dereference symlinks - treat like normal file\n";
 
 static int symlinkFlag = FALSE;
 static int removeoldFlag = FALSE;
-
+static int followLinks = TRUE;
 
 extern int ln_main(int argc, char **argv)
 {
-    int status;
-    static char* linkName;
+    char *linkName;
+    int linkIntoDirFlag;
 
     if (argc < 3) {
 	usage (ln_usage);
@@ -59,6 +65,9 @@
 	    case 'f':
 		removeoldFlag = TRUE;
 		break;
+	    case 'n':
+		followLinks = FALSE;
+		break;
 	    default:
 		usage (ln_usage);
 	    }
@@ -66,30 +75,54 @@
 	argv++;
     }
 
-
     linkName = argv[argc - 1];
 
-    if ((argc > 3) && !(isDirectory(linkName))) {
-	fprintf(stderr, "%s: not a directory\n", linkName);
-	exit (FALSE);
+    if (strlen(linkName) > PATH_MAX) {
+	fprintf(stderr, name_too_long, "ln");
+	exit FALSE;
+    }
+
+    linkIntoDirFlag = isDirectory(linkName, TRUE);
+
+    if ((argc > 3) && !linkIntoDirFlag) {
+	fprintf(stderr, not_a_directory, "ln", linkName);
+	exit FALSE;
     }
 
     while (argc-- >= 2) {
-	if (removeoldFlag==TRUE ) {
+	char srcName[PATH_MAX + 1];
+	int nChars, status;
+
+	if (strlen(*argv) > PATH_MAX) {
+	    fprintf(stderr, name_too_long, "ln");
+	    exit FALSE;
+	}
+
+	if (followLinks == FALSE) {
+	    strcpy(srcName, *argv);
+	} else {
+	    /* Warning!  This can silently truncate if > PATH_MAX, but
+	    I don't think that there can be one > PATH_MAX anyway. */
+	    nChars = readlink(*argv, srcName, PATH_MAX);
+	    srcName[nChars] = '\0';
+	}
+
+	if (removeoldFlag == TRUE) {
 	    status = ( unlink(linkName) && errno != ENOENT );
-	    if ( status != 0 ) {
+	    if (status != 0) {
 		perror(linkName);
-		exit( FALSE);
+		exit FALSE;
 	    }
 	}
-	if ( symlinkFlag==TRUE)
-		status = symlink(*argv, linkName);
+
+	if (symlinkFlag == TRUE)
+	    status = symlink(*argv, linkName);
 	else
-		status = link(*argv, linkName);
-	if ( status != 0 ) {
+	    status = link(*argv, linkName);
+	if (status != 0) {
 	    perror(linkName);
-	    exit( FALSE);
+	    exit FALSE;
 	}
     }
-    exit( TRUE);
+    exit TRUE;
 }
diff --git a/ls.c b/ls.c
index 78193e7..450ea18 100644
--- a/ls.c
+++ b/ls.c
@@ -178,7 +178,7 @@
 
 static void list_single(const char *name, struct stat *info, const char *fullname)
 {
-	char scratch[PATH_MAX];
+	char scratch[PATH_MAX + 1];
 	short len = strlen(name);
 #ifdef BB_FEATURE_LS_FILETYPES
 	char append = append_char(info->st_mode);
diff --git a/messages.c b/messages.c
new file mode 100644
index 0000000..bfbf317
--- /dev/null
+++ b/messages.c
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2000 by BitterSweet Enterprises, LLC.
+ * Written by Karl M. Hegbloom <karlheg@debian.org>
+ *
+ * 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
+ *
+ */
+
+/*
+ *  Let's put all of these messages in one place, and link this in as
+ *  a separate object module, so that there are not going to be
+ *  multiple non-unique but very similar strings in the binary.
+ *  Perhaps this will make it simpler to internationalize also, and
+ *  may make the binary slightly smaller.
+ */
+#ifndef _BB_MESSAGES_C
+#define _BB_MESSAGES_C
+
+#define _BB_DEF_MESSAGE_PROTO(symbol)			 extern const char *symbol;
+#define _BB_DEF_MESSAGE_INITIALIZE(symbol, string_const) const char *symbol = string_const;
+
+#ifdef BB_DECLARE_EXTERN
+#  define BB_DEF_MESSAGE(symbol, string_const) _BB_DEF_MESSAGE_PROTO(symbol)
+#else
+#  define BB_DEF_MESSAGE(symbol, string_const) _BB_DEF_MESSAGE_INITIALIZE(symbol, string_const)
+#endif
+
+#if defined bb_need_name_too_long || ! defined BB_DECLARE_EXTERN
+BB_DEF_MESSAGE(name_too_long, "%s: file name too long\n")
+#endif
+
+#if defined bb_need_omitting_directory || ! defined BB_DECLARE_EXTERN
+BB_DEF_MESSAGE(omitting_directory, "%s: %s: omitting directory\n")
+#endif
+
+#if defined bb_need_not_a_directory || ! defined BB_DECLARE_EXTERN
+BB_DEF_MESSAGE(not_a_directory, "%s: %s: not a directory\n")
+#endif
+
+#if defined bb_need_memory_exhausted || ! defined BB_DECLARE_EXTERN
+BB_DEF_MESSAGE(memory_exhausted, "%s: memory exhausted\n")
+#endif
+
+#if defined bb_need_invalid_date || ! defined BB_DECLARE_EXTERN
+BB_DEF_MESSAGE(invalid_date, "%s: invalid date `%s'\n")
+#endif
+
+#if defined bb_need_invalid_option || ! defined BB_DECLARE_EXTERN
+BB_DEF_MESSAGE(invalid_option, "%s: invalid option -- %c\n")
+#endif
+
+#endif /* _BB_MESSAGES_C */
diff --git a/mkdir.c b/mkdir.c
index 017ef9b..8e3f51b 100644
--- a/mkdir.c
+++ b/mkdir.c
@@ -22,9 +22,13 @@
  */
 
 #include "internal.h"
+#define bb_need_name_too_long
+#define BB_DECLARE_EXTERN
+#include "messages.c"
+
 #include <stdio.h>
 #include <errno.h>
-#include <sys/param.h>
+#include <sys/param.h>		/* for PATH_MAX */
 
 static const char mkdir_usage[] =
 "mkdir [OPTION] DIRECTORY...\n\n"
@@ -40,27 +44,27 @@
 
 extern int mkdir_main(int argc, char **argv)
 {
-    int i=FALSE;
+    int i = FALSE;
     argc--;
     argv++;
 
     /* Parse any options */
     while (argc > 0 && **argv == '-') {
-	while (i==FALSE && *++(*argv)) {
+	while (i == FALSE && *++(*argv)) {
 	    switch (**argv) {
 	    case 'm':
 		if (--argc == 0)
 		    usage( mkdir_usage);
 		/* Find the specified modes */
 		mode = 0;
-		if ( parse_mode(*(++argv), &mode) == FALSE ) {
+		if (parse_mode(*(++argv), &mode) == FALSE ) {
 		    fprintf(stderr, "Unknown mode: %s\n", *argv);
-		    exit( FALSE);
+		    exit FALSE;
 		}
 		/* Set the umask for this process so it doesn't 
 		 * screw up whatever the user just entered. */
 		umask(0);
-		i=TRUE;
+		i = TRUE;
 		break;
 	    case 'p':
 		parentFlag = TRUE;
@@ -73,7 +77,6 @@
 	argv++;
     }
 
-
     if (argc < 1) {
 	usage( mkdir_usage);
     }
@@ -81,13 +84,16 @@
     while (argc > 0) {
 	int status;
 	struct stat statBuf;
-	char buf[NAME_MAX];
-
+	char buf[PATH_MAX + 1];
+	if (strlen(*argv) > PATH_MAX - 1) {
+	    fprintf(stderr, name_too_long, "mkdir");
+	    exit FALSE;
+	}
 	strcpy (buf, *argv);
-	status=stat(buf, &statBuf);
-	if (parentFlag == FALSE && status != -1 && status != ENOENT ) {
+	status = stat(buf, &statBuf);
+	if (parentFlag == FALSE && status != -1 && errno != ENOENT) {
 	    fprintf(stderr, "%s: File exists\n", buf);
-	    exit( FALSE);
+	    exit FALSE;
 	}
 	if (parentFlag == TRUE) {
 	    strcat( buf, "/");
@@ -96,13 +102,13 @@
 	else { 
 	    if (mkdir (buf, mode) != 0 && parentFlag == FALSE) {
 		perror(buf);
-		exit( FALSE);
+		exit FALSE;
 	    }
 	}
 	argc--;
 	argv++;
     }
-    exit( TRUE);
+    exit TRUE;
 }
 
 
diff --git a/modutils/insmod.c b/modutils/insmod.c
index 9cb635f..31cb112 100644
--- a/modutils/insmod.c
+++ b/modutils/insmod.c
@@ -67,8 +67,8 @@
 #endif
 
 
-static char m_filename[PATH_MAX] = "\0";
-static char m_fullName[PATH_MAX] ="\0";
+static char m_filename[PATH_MAX + 1] = "\0";
+static char m_fullName[PATH_MAX + 1] = "\0";
 static const char insmod_usage[] =
     "insmod [OPTION]... MODULE [symbol=value]...\n\n"
     "Loads the specified kernel modules into the kernel.\n\n"
@@ -101,7 +101,7 @@
 {
     int len;
     char *tmp;
-    char m_name[PATH_MAX] ="\0";
+    char m_name[PATH_MAX + 1] ="\0";
     FILE *fp;
 
     if (argc<=1) {
diff --git a/mtab.c b/mtab.c
index 98e42a3..41d8818 100644
--- a/mtab.c
+++ b/mtab.c
@@ -5,21 +5,13 @@
 #include <string.h>
 #include <stdio.h>
 #include <mntent.h>
+#include <fstab.h>
 #include <sys/mount.h>
 
 extern const char mtab_file[]; /* Defined in utility.c */
 
-static char *
-stralloc(const char * string)
-{
-	int	length = strlen(string) + 1;
-	char *	n = malloc(length);
-	memcpy(n, string, length);
-	return n;
-}
 
-extern void
-erase_mtab(const char * name)
+void erase_mtab(const char * name)
 {
 	struct mntent	entries[20];
 	int	count = 0;
@@ -39,10 +31,10 @@
 	}
 
 	while ( (m = getmntent(mountTable)) != 0 ) {
-		entries[count].mnt_fsname = stralloc(m->mnt_fsname);
-		entries[count].mnt_dir = stralloc(m->mnt_dir);
-		entries[count].mnt_type = stralloc(m->mnt_type);
-		entries[count].mnt_opts = stralloc(m->mnt_opts);
+		entries[count].mnt_fsname = strdup(m->mnt_fsname);
+		entries[count].mnt_dir = strdup(m->mnt_dir);
+		entries[count].mnt_type = strdup(m->mnt_type);
+		entries[count].mnt_opts = strdup(m->mnt_opts);
 		entries[count].mnt_freq = m->mnt_freq;
 		entries[count].mnt_passno = m->mnt_passno;
 		count++;
@@ -65,8 +57,7 @@
 		perror(mtab_file);
 }
 
-extern void 
-write_mtab(char* blockDevice, char* directory, 
+void write_mtab(char* blockDevice, char* directory, 
 	char* filesystemType, long flags, char* string_flags)
 {
 	FILE *mountTable = setmntent(mtab_file, "a+");
@@ -110,4 +101,3 @@
     }
 }
 
-
diff --git a/mv.c b/mv.c
deleted file mode 100644
index 467a360..0000000
--- a/mv.c
+++ /dev/null
@@ -1,112 +0,0 @@
-/*
- * Mini mv implementation for busybox
- *
- *
- * Copyright (C) 1999 by Lineo, inc.
- * Written by Erik Andersen <andersen@lineo.com>, <andersee@debian.org>
- *
- * 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 <time.h>
-#include <utime.h>
-#include <dirent.h>
-
-static const char mv_usage[] = "mv SOURCE DEST\n"
-"   or: mv SOURCE... DIRECTORY\n\n"
-"Rename SOURCE to DEST, or move SOURCE(s) to DIRECTORY.\n";
-
-
-static const char *srcName;
-static const char *destName;
-static int destDirFlag = FALSE;
-static int srcDirFlag = FALSE;
-
-static int fileAction(const char *fileName, struct stat* statbuf)
-{
-    char newdestName[NAME_MAX];
-    char* newsrcName = NULL;
-
-    strcpy(newdestName, destName);
-    if ( srcDirFlag == TRUE ) {
-	strcat(newdestName, strstr(fileName, srcName) + strlen(srcName));
-    } 
-    
-    if (destDirFlag==TRUE && srcDirFlag == FALSE) {
-	if (newdestName[strlen(newdestName)-1] != '/' ) {
-	    strcat(newdestName, "/");
-	}
-	newsrcName = strrchr(srcName, '/');
-	if (newsrcName && *newsrcName != '\0')
-	    strcat(newdestName, newsrcName);
-	else
-	    strcat(newdestName, srcName);
-    }
-    
-    return (copyFile(fileName, newdestName, TRUE, TRUE));
-}
-
-static int rmfileAction(const char *fileName, struct stat* statbuf)
-{
-    if (unlink( fileName) < 0 ) {
-	perror( fileName);
-	return ( FALSE);
-    }
-    return ( TRUE);
-}
-
-static int rmdirAction(const char *fileName, struct stat* statbuf)
-{
-    if (rmdir( fileName) < 0 ) {
-	perror( fileName);
-	return ( FALSE);
-    }
-    return ( TRUE);
-}
-
-
-extern int mv_main(int argc, char **argv)
-{
-    if (argc < 3) {
-	usage (mv_usage);
-    }
-    argc--;
-    argv++;
-
-    destName = argv[argc - 1];
-    destDirFlag = isDirectory(destName);
-
-    if ((argc > 3) && destDirFlag==FALSE) {
-	fprintf(stderr, "%s: not a directory\n", destName);
-	exit (FALSE);
-    }
-
-    while (argc-- > 1) {
-	srcName = *(argv++);
-	srcDirFlag = isDirectory(srcName);
-	if (recursiveAction(srcName, TRUE, TRUE, FALSE,
-			       fileAction, fileAction) == FALSE) {
-	    exit( FALSE);
-	}
-	if (recursiveAction(srcName, TRUE, TRUE, TRUE,
-			       rmfileAction, rmdirAction) == FALSE) {
-	    exit( FALSE);
-	}
-    }
-    exit( TRUE);
-}
diff --git a/networking/hostname.c b/networking/hostname.c
index 20e1741..68a5609 100644
--- a/networking/hostname.c
+++ b/networking/hostname.c
@@ -1,5 +1,5 @@
 /*
- * $Id: hostname.c,v 1.5 1999/12/09 06:11:36 andersen Exp $
+ * $Id: hostname.c,v 1.6 2000/02/07 05:29:42 erik Exp $
  * Mini hostname implementation for busybox
  *
  * Copyright (C) 1999 by Randolph Chung <tausq@debian.org>
diff --git a/networking/nslookup.c b/networking/nslookup.c
index 82d3b36..969d0b1 100644
--- a/networking/nslookup.c
+++ b/networking/nslookup.c
@@ -185,4 +185,4 @@
     return 0;
 }
 
-/* $Id: nslookup.c,v 1.2 2000/01/30 09:47:16 beppu Exp $ */
+/* $Id: nslookup.c,v 1.3 2000/02/07 05:29:42 erik Exp $ */
diff --git a/networking/ping.c b/networking/ping.c
index 5b68019..3ffbdc5 100644
--- a/networking/ping.c
+++ b/networking/ping.c
@@ -1,5 +1,5 @@
 /*
- * $Id: ping.c,v 1.9 2000/01/29 06:29:32 erik Exp $
+ * $Id: ping.c,v 1.10 2000/02/07 05:29:42 erik Exp $
  * Mini ping implementation for busybox
  *
  * Copyright (C) 1999 by Randolph Chung <tausq@debian.org>
@@ -175,7 +175,8 @@
 static const char* ping_usage = "ping [OPTION]... host\n\n"
 "Send ICMP ECHO_REQUEST packets to network hosts.\n\n"
 "Options:\n"
-"\t-q\t\tQuiet mode, only displays output at start and when finished.\n"
+"\t-q\t\tQuiet mode, only displays output at start"
+"\t\t\tand when finished.\n"
 "\t-c COUNT\tSend only COUNT pings.\n";
 
 static char *hostname = NULL;
diff --git a/nslookup.c b/nslookup.c
index 82d3b36..969d0b1 100644
--- a/nslookup.c
+++ b/nslookup.c
@@ -185,4 +185,4 @@
     return 0;
 }
 
-/* $Id: nslookup.c,v 1.2 2000/01/30 09:47:16 beppu Exp $ */
+/* $Id: nslookup.c,v 1.3 2000/02/07 05:29:42 erik Exp $ */
diff --git a/ping.c b/ping.c
index 5b68019..3ffbdc5 100644
--- a/ping.c
+++ b/ping.c
@@ -1,5 +1,5 @@
 /*
- * $Id: ping.c,v 1.9 2000/01/29 06:29:32 erik Exp $
+ * $Id: ping.c,v 1.10 2000/02/07 05:29:42 erik Exp $
  * Mini ping implementation for busybox
  *
  * Copyright (C) 1999 by Randolph Chung <tausq@debian.org>
@@ -175,7 +175,8 @@
 static const char* ping_usage = "ping [OPTION]... host\n\n"
 "Send ICMP ECHO_REQUEST packets to network hosts.\n\n"
 "Options:\n"
-"\t-q\t\tQuiet mode, only displays output at start and when finished.\n"
+"\t-q\t\tQuiet mode, only displays output at start"
+"\t\t\tand when finished.\n"
 "\t-c COUNT\tSend only COUNT pings.\n";
 
 static char *hostname = NULL;
diff --git a/printf.c b/printf.c
index 5be3a67..5fd5ea3 100644
--- a/printf.c
+++ b/printf.c
@@ -143,7 +143,7 @@
   int args_used;
 
   exit_status = 0;
-  if ( **(argv+1) == '-' ) {
+  if ( argc <= 1 || **(argv+1) == '-' ) {
     usage (printf_usage);
   }
 
diff --git a/pwd.c b/pwd.c
index c5ce6ff..bacabd7 100644
--- a/pwd.c
+++ b/pwd.c
@@ -23,11 +23,12 @@
 #include "internal.h"
 #include <stdio.h>
 #include <dirent.h>
+#include <sys/param.h>
 
 extern int
 pwd_main(int argc, char * * argv)
 {
-	char		buf[NAME_MAX];
+	char		buf[PATH_MAX + 1];
 
 	if ( getcwd(buf, sizeof(buf)) == NULL ) {
 		perror("get working directory");
diff --git a/sort.c b/sort.c
index 4df5627..d529ce7 100644
--- a/sort.c
+++ b/sort.c
@@ -309,4 +309,4 @@
     exit(0);
 }
 
-/* $Id: sort.c,v 1.9 2000/01/23 18:19:02 erik Exp $ */
+/* $Id: sort.c,v 1.10 2000/02/07 05:29:42 erik Exp $ */
diff --git a/swaponoff.c b/swaponoff.c
index 8eaf979..3c02bdd 100644
--- a/swaponoff.c
+++ b/swaponoff.c
@@ -65,7 +65,6 @@
 do_em_all()
 {
 	struct mntent *m;
-	char swapName[NAME_MAX];
 	FILE *f = setmntent ("/etc/fstab", "r");
 
 	if (f == NULL) {
@@ -73,8 +72,8 @@
 	    exit( FALSE); 
 	}
 	while ((m = getmntent (f)) != NULL) {
-	    if (!strstr (m->mnt_type, "swap")) {
-		    swap_enable_disable( swapName);
+	    if (!strstr (m->mnt_type, MNTTYPE_SWAP)) {
+		    swap_enable_disable( m->mnt_fsname);
 	    }
 	}
 	endmntent (f);
diff --git a/sysklogd/syslogd.c b/sysklogd/syslogd.c
index 0be9ded..29ede13 100644
--- a/sysklogd/syslogd.c
+++ b/sysklogd/syslogd.c
@@ -77,7 +77,7 @@
 
     /* Retry up to 5 times */
     for (f = 0; f < 5; f++)
-	if ((fd = open(device, m)) >= 0)
+	if ((fd = open(device, m, 0600)) >= 0)
 	    break;
     if (fd < 0)
 	return fd;
@@ -177,9 +177,6 @@
     char *q, *p = buf;
     int readSize;
 
-    /* Remove any preexisting socket/file */
-    unlink(_PATH_LOG);
-
     /* Set up sig handlers */
     signal(SIGINT,  quit_signal);
     signal(SIGTERM, quit_signal);
@@ -188,8 +185,9 @@
     signal(SIGALRM, domark);
     alarm(MarkInterval);
 
+    /* Remove any preexisting socket/file */
+    unlink(_PATH_LOG);
 
-    unlink( _PATH_LOG);
     memset(&sunx, 0, sizeof(sunx));
     sunx.sun_family = AF_UNIX;	/* Unix domain socket */
     strncpy(sunx.sun_path, _PATH_LOG, sizeof(sunx.sun_path));
@@ -200,12 +198,17 @@
 
     addrLength = sizeof(sunx.sun_family) + strlen(sunx.sun_path);
     if ( (bind(fd, (struct sockaddr *) &sunx, addrLength)) ||
-	    (fchmod(fd, 0666) < 0) || (listen(fd, 5)) ) 
+	    (listen(fd, 5)) ) 
     {
 	perror("Could not connect to socket " _PATH_LOG);
 	exit( FALSE);
     }
     
+    umask(0);
+    if (chmod(_PATH_LOG, 0666) < 0) {
+        perror("Could not set permission on " _PATH_LOG);
+        exit (FALSE);
+    }
     
     logMessage(LOG_SYSLOG|LOG_INFO, "syslogd started: "
 	    "BusyBox v" BB_VER " (" BB_BT ")");
diff --git a/syslogd.c b/syslogd.c
index 0be9ded..29ede13 100644
--- a/syslogd.c
+++ b/syslogd.c
@@ -77,7 +77,7 @@
 
     /* Retry up to 5 times */
     for (f = 0; f < 5; f++)
-	if ((fd = open(device, m)) >= 0)
+	if ((fd = open(device, m, 0600)) >= 0)
 	    break;
     if (fd < 0)
 	return fd;
@@ -177,9 +177,6 @@
     char *q, *p = buf;
     int readSize;
 
-    /* Remove any preexisting socket/file */
-    unlink(_PATH_LOG);
-
     /* Set up sig handlers */
     signal(SIGINT,  quit_signal);
     signal(SIGTERM, quit_signal);
@@ -188,8 +185,9 @@
     signal(SIGALRM, domark);
     alarm(MarkInterval);
 
+    /* Remove any preexisting socket/file */
+    unlink(_PATH_LOG);
 
-    unlink( _PATH_LOG);
     memset(&sunx, 0, sizeof(sunx));
     sunx.sun_family = AF_UNIX;	/* Unix domain socket */
     strncpy(sunx.sun_path, _PATH_LOG, sizeof(sunx.sun_path));
@@ -200,12 +198,17 @@
 
     addrLength = sizeof(sunx.sun_family) + strlen(sunx.sun_path);
     if ( (bind(fd, (struct sockaddr *) &sunx, addrLength)) ||
-	    (fchmod(fd, 0666) < 0) || (listen(fd, 5)) ) 
+	    (listen(fd, 5)) ) 
     {
 	perror("Could not connect to socket " _PATH_LOG);
 	exit( FALSE);
     }
     
+    umask(0);
+    if (chmod(_PATH_LOG, 0666) < 0) {
+        perror("Could not set permission on " _PATH_LOG);
+        exit (FALSE);
+    }
     
     logMessage(LOG_SYSLOG|LOG_INFO, "syslogd started: "
 	    "BusyBox v" BB_VER " (" BB_BT ")");
diff --git a/tail.c b/tail.c
index 5198892..0ab8f11 100644
--- a/tail.c
+++ b/tail.c
@@ -33,7 +33,7 @@
     and generally busyboxed, Erik Andersen <andersen@lineo.com>
 
    Removed superfluous options and associated code ("-c", "-n", "-q").
-   Removed "tail -f" suport for multiple files.
+   Removed "tail -f" support for multiple files.
    Both changes by Friedrich Vedder <fwv@myrtle.lahn.de>.
 
  */
diff --git a/tar.c b/tar.c
index 0fa09ff..6496231 100644
--- a/tar.c
+++ b/tar.c
@@ -40,6 +40,7 @@
 #include <utime.h>
 #include <sys/types.h>
 #include <sys/sysmacros.h>
+#include <sys/param.h>		/* for PATH_MAX */
 
 
 #ifdef BB_FEATURE_TAR_CREATE
@@ -1041,7 +1042,7 @@
     DIR *dir;
     struct dirent *entry;
     int needSlash;
-    char fullName[NAME_MAX];
+    char fullName[PATH_MAX + 1];
 
     /* 
      * Construct the directory name as used in the tar file by appending
diff --git a/tee.c b/tee.c
index 8d1ca6e..4c5c691 100644
--- a/tee.c
+++ b/tee.c
@@ -123,4 +123,4 @@
     exit(0);
 }
 
-/* $Id: tee.c,v 1.4 1999/12/10 08:25:07 andersen Exp $ */
+/* $Id: tee.c,v 1.5 2000/02/07 05:29:42 erik Exp $ */
diff --git a/tests/Makefile b/tests/Makefile
new file mode 100644
index 0000000..0156344
--- /dev/null
+++ b/tests/Makefile
@@ -0,0 +1,28 @@
+all test_all: message_header cp_tests mv_tests ln_tests
+
+clean: cp_clean mv_clean ln_clean
+
+message_header:
+	@echo
+	@echo If tests faile due to differences in timestamps in commands that are not set
+	@echo to preserve timestamps, just run the tests again.
+	@echo
+
+include cp_tests.mk
+include mv_tests.mk
+include ln_tests.mk
+
+BBL := $(shell pushd .. >/dev/null &&		\
+	         ${MAKE} busybox.links >/dev/null && \
+	       popd >/dev/null &&		\
+	       cat ../busybox.links |		\
+	         sed -e 's,.*/\(.*\)$$,\1,')
+
+../busybox:
+	cd .. && ${MAKE} busybox
+
+$(BBL): ../busybox
+	rm -f $@
+	ln ../busybox $@
+
+.PHONY: all test_all message_header
diff --git a/tests/cp_tests.mk b/tests/cp_tests.mk
new file mode 100644
index 0000000..e14262a
--- /dev/null
+++ b/tests/cp_tests.mk
@@ -0,0 +1,270 @@
+# This is a -*- makefile -*-
+
+# GNU `cp'
+GCP = /bin/cp
+# BusyBox `cp'
+BCP = $(shell pwd)/cp
+
+.PHONY: cp_clean
+cp_clean:
+	rm -rf cp_tests cp_*.{gnu,bb} cp
+
+.PHONY: cp_tests
+cp_tests: cp_clean cp
+	@echo;
+	@echo "No output from diff means busybox cp is functioning properly.";
+
+	@echo;
+	${BCP} || true;
+
+	@echo;
+	mkdir cp_tests;
+
+	@echo;
+	cd cp_tests;				\
+	 echo A file > afile;			\
+	 ls -l afile > ../cp_afile_afilecopy.gnu; \
+	 ${GCP} afile afilecopy;		\
+	 ls -l afile afilecopy >> ../cp_afile_afilecopy.gnu;
+
+	@echo;
+	rm -f cp_tests/afile*;
+
+	@echo;
+	cd cp_tests;				\
+	 echo A file > afile;			\
+	 ls -l afile > ../cp_afile_afilecopy.bb; \
+	 ${BCP} afile afilecopy;		\
+	 ls -l afile afilecopy >> ../cp_afile_afilecopy.bb;
+
+	@echo;
+	diff -u cp_afile_afilecopy.gnu cp_afile_afilecopy.bb;
+
+	@echo;
+	rm -f cp_tests/afile*;
+
+	@echo; echo;
+	cd cp_tests;				\
+	 mkdir there there1;			\
+	 cd there;				\
+	  ln -s ../afile .;
+
+	@echo;
+	cd cp_tests;				\
+	 echo A file > afile;			\
+	 ls -l afile > ../cp_symlink.gnu;	\
+	 ${GCP} there/afile there1/;		\
+	 ls -l afile there/afile there1/afile >> ../cp_symlink.gnu;
+
+	@echo;
+	rm -f cp_tests/afile cp_tests/there1/afile;
+
+	@echo;
+	cd cp_tests;				\
+	 echo A file > afile;			\
+	 ls -l afile > ../cp_symlink.bb;	\
+	 ${BCP} there/afile there1/;		\
+	 ls -l afile there/afile there1/afile >> ../cp_symlink.bb;
+
+	@echo;
+	diff -u cp_symlink.gnu cp_symlink.bb;
+
+	@echo;
+	rm -f cp_tests/afile cp_tests/there1/afile;
+
+	@echo; echo;
+	cd cp_tests;				\
+	 echo A file > afile;			\
+	 ls -l afile > ../cp_a_symlink.gnu;	\
+	 ${GCP} -a there/afile there1/;		\
+	 ls -l afile there/afile there1/afile >> ../cp_a_symlink.gnu;
+
+	@echo;
+	rm -f cp_tests/afile cp_tests/there1/afile;
+
+	@echo;
+	cd cp_tests;				\
+	 echo A file > afile;			\
+	 ls -l afile > ../cp_a_symlink.bb;	\
+	 ${BCP} -a there/afile there1/;		\
+	 ls -l afile there/afile there1/afile >> ../cp_a_symlink.bb;
+
+	@echo;
+	diff -u cp_a_symlink.gnu cp_a_symlink.bb;
+
+	@echo;
+	rm -f cp_tests/afile
+	rm -rf cp_tests/there{,1};
+
+	@echo; echo;
+	cd cp_tests;				\
+	 echo A file > there/afile;		\
+	 mkdir there/adir;			\
+	 touch there/adir/afileinadir;		\
+	 ln -s $(shell pwd) there/alink;
+
+	@echo;
+	cd cp_tests;				\
+	 ${GCP} -a there/ there1/;		\
+	 ls -lR there/ there1/ > ../cp_a_dir_dir.gnu;
+
+	@echo;
+	rm -rf cp_tests/there1;
+
+	@echo;
+	cd cp_tests;				\
+	 ${BCP} -a there/ there1/;		\
+	 ls -lR there/ there1/ > ../cp_a_dir_dir.bb;
+
+	@echo;
+	diff -u cp_a_dir_dir.gnu cp_a_dir_dir.bb;
+
+	@echo;
+	rm -rf cp_tests/there1/;
+
+	@echo; echo;
+	cd cp_tests;				\
+	 echo A file number one > afile1;	\
+	 echo A file number two, blah. > afile2; \
+	 ln -s afile1 symlink1;			\
+	 mkdir there1;				\
+	 ${GCP} afile1 afile2 symlink1 there1/;	\
+	 ls -lR > ../cp_files_dir.gnu;
+
+	@echo;
+	rm -rf cp_tests/{afile{1,2},symlink1,there1};
+
+	@echo;
+	cd cp_tests;				\
+	 echo A file number one > afile1;	\
+	 echo A file number two, blah. > afile2; \
+	 ln -s afile1 symlink1;			\
+	 mkdir there1;				\
+	 ${BCP} afile1 afile2 symlink1 there1/;	\
+	 ls -lR > ../cp_files_dir.bb;
+
+	@echo;
+	diff -u cp_files_dir.gnu cp_files_dir.bb;
+
+	@echo;
+	rm -rf cp_tests/{afile{1,2},symlink1,there1};
+
+	@echo; echo;
+	cd cp_tests;				\
+	 echo A file number one > afile1;	\
+	 echo A file number two, blah. > afile2; \
+	 ln -s afile1 symlink1;			\
+	 mkdir there1;				\
+	 ${GCP} -d afile1 afile2 symlink1 there1/; \
+	 ls -lR > ../cp_d_files_dir.gnu;
+
+	@echo;
+	rm -rf cp_tests/{afile{1,2},symlink1,there1};
+
+	@echo;
+	cd cp_tests;				\
+	 echo A file number one > afile1;	\
+	 echo A file number two, blah. > afile2; \
+	 ln -s afile1 symlink1;			\
+	 mkdir there1;				\
+	 ${BCP} -d afile1 afile2 symlink1 there1/; \
+	 ls -lR > ../cp_d_files_dir.bb;
+
+	@echo;
+	diff -u cp_d_files_dir.gnu cp_d_files_dir.bb;
+
+	@echo;
+	rm -rf cp_tests/{afile{1,2},symlink1,there1};
+
+	@echo; echo;
+	cd cp_tests;				\
+	 echo A file number one > afile1;	\
+	 echo A file number two, blah. > afile2; \
+	 touch --date='Sat Jan 29 21:24:08 PST 2000' afile1; \
+	 ln -s afile1 symlink1;			\
+	 mkdir there1;				\
+	 ${GCP} -p afile1 afile2 symlink1 there1/; \
+	 ls -lR > ../cp_p_files_dir.gnu;
+
+	@echo;
+	rm -rf cp_tests/{afile{1,2},symlink1,there1};
+
+	@echo;
+	cd cp_tests;				\
+	 echo A file number one > afile1;	\
+	 echo A file number two, blah. > afile2; \
+	 touch --date='Sat Jan 29 21:24:08 PST 2000' afile1; \
+	 ln -s afile1 symlink1;			\
+	 mkdir there1;				\
+	 ${BCP} -p afile1 afile2 symlink1 there1/; \
+	 ls -lR > ../cp_p_files_dir.bb;
+
+	@echo;
+	diff -u cp_p_files_dir.gnu cp_p_files_dir.bb;
+
+	@echo;
+	rm -rf cp_tests/{afile{1,2},symlink1,there1};
+
+	@echo; echo;
+	cd cp_tests;				\
+	 echo A file number one > afile1;	\
+	 echo A file number two, blah. > afile2; \
+	 touch --date='Sat Jan 29 21:24:08 PST 2000' afile1; \
+	 ln -s afile1 symlink1;			\
+	 mkdir there1;				\
+	 ${GCP} -p -d afile1 afile2 symlink1 there1/; \
+	 ls -lR > ../cp_pd_files_dir.gnu;
+
+	@echo;
+	rm -rf cp_tests/{afile{1,2},symlink1,there1};
+
+	@echo;
+	cd cp_tests;				\
+	 echo A file number one > afile1;	\
+	 echo A file number two, blah. > afile2; \
+	 touch --date='Sat Jan 29 21:24:08 PST 2000' afile1; \
+	 ln -s afile1 symlink1;			\
+	 mkdir there1;				\
+	 ${BCP} -p -d afile1 afile2 symlink1 there1/; \
+	 ls -lR > ../cp_pd_files_dir.bb;
+
+	@echo;
+	diff -u cp_pd_files_dir.gnu cp_pd_files_dir.bb;
+
+	@echo;
+	rm -rf cp_tests/{afile{1,2},symlink1,there1};
+
+	@echo; echo;
+	cd cp_tests;				\
+	 mkdir dir{a,b};			\
+	 echo A file > dira/afile;		\
+	 echo A file in dirb > dirb/afileindirb; \
+	 ln -s dira/afile dira/alinktoafile;	\
+	 mkdir dira/subdir1;			\
+	 echo Another file > dira/subdir1/anotherfile; \
+	 ls -lR . > ../cp_a_dira_dirb.gnu;	\
+	 ${GCP} -a dira dirb;			\
+	 ls -lR . >> ../cp_a_dira_dirb.gnu;
+
+	# false;
+	@echo;
+	rm -rf cp_tests/dir{a,b};
+
+	@echo;
+	cd cp_tests;				\
+	 mkdir dir{a,b};			\
+	 echo A file > dira/afile;		\
+	 echo A file in dirb > dirb/afileindirb; \
+	 ln -s dira/afile dira/alinktoafile;	\
+	 mkdir dira/subdir1;			\
+	 echo Another file > dira/subdir1/anotherfile; \
+	 ls -lR . > ../cp_a_dira_dirb.bb;	\
+	 ${BCP} -a dira dirb;			\
+	 ls -lR . >> ../cp_a_dira_dirb.bb;
+
+	@echo;
+	diff -u cp_a_dira_dirb.gnu cp_a_dira_dirb.bb;
+
+	# false;
+	@echo;
+	rm -rf cp_tests/dir{a,b};
diff --git a/tests/ln_tests.mk b/tests/ln_tests.mk
new file mode 100644
index 0000000..5925edd
--- /dev/null
+++ b/tests/ln_tests.mk
@@ -0,0 +1,66 @@
+
+# GNU `ln'
+GLN = /bin/ln
+# BusyBox `ln'
+BLN = $(shell pwd)/ln
+
+.PHONY: ln_clean
+ln_clean:
+	rm -rf ln_tests ln_*.{gnu,bb} ln
+
+.PHONY: ln_tests
+ln_tests: ln_clean ln
+	@echo;
+	@echo "No output from diff means busybox ln is functioning properly.";
+
+	@echo;
+	${BLN} || true;
+
+	@echo;
+	mkdir ln_tests;
+
+	@echo;
+	cd ln_tests;				\
+	 echo A file > afile;			\
+	 ls -l afile > ../ln_afile_newname.gnu;	\
+	 ${GLN} afile newname;			\
+	 ls -l afile newname >> ../ln_afile_newname.gnu;
+
+	@echo;
+	rm -f ln_tests/{afile,newname};
+
+	@echo;
+	cd ln_tests;				\
+	 echo A file > afile;			\
+	 ls -l afile > ../ln_afile_newname.bb;	\
+	 ${BLN} afile newname;			\
+	 ls -l afile newname >> ../ln_afile_newname.bb;
+
+	@echo;
+	diff -u ln_afile_newname.gnu ln_afile_newname.bb
+
+	@echo;
+	rm -f ln_tests/{afile,newname};
+
+	@echo;
+	cd ln_tests;				\
+	 echo A file > afile;			\
+	 ls -l afile > ../ln_s_afile_newname.gnu;	\
+	 ${GLN} -s afile newname;		\
+	 ls -l afile newname >> ../ln_s_afile_newname.gnu;
+
+	@echo;
+	rm -f ln_tests/{afile,newname};
+
+	@echo;
+	cd ln_tests;				\
+	 echo A file > afile;			\
+	 ls -l afile > ../ln_s_afile_newname.bb;	\
+	 ${BLN} -s afile newname;		\
+	 ls -l afile newname >> ../ln_s_afile_newname.bb;
+
+	@echo;
+	diff -u ln_s_afile_newname.gnu ln_s_afile_newname.bb
+
+	@echo;
+	rm -f ln_tests/{afile,newname};
diff --git a/tests/mv_tests.mk b/tests/mv_tests.mk
new file mode 100644
index 0000000..3a90125
--- /dev/null
+++ b/tests/mv_tests.mk
@@ -0,0 +1,137 @@
+
+# GNU `mv'
+GMV = /bin/mv
+# BusyBox `mv'
+BMV = $(shell pwd)/mv
+
+.PHONY: mv_clean
+mv_clean:
+	rm -rf mv_tests mv_*.{gnu,bb} mv
+
+.PHONY: mv_tests
+mv_tests: mv_clean mv
+	@echo;
+	@echo "No output from diff means busybox mv is functioning properly.";
+	@echo;
+	@echo "No such file or directory is good; it means the old file got removed.";
+	@echo;
+	${BMV} || true;
+
+	@echo;
+	mkdir mv_tests;
+
+	@echo;
+	cd mv_tests;				\
+	 echo A file > afile;			\
+	 ls -l afile > ../mv_afile_newname.gnu;	\
+	 ${GMV} afile newname;			\
+	 ls -l newname >> ../mv_afile_newname.gnu;
+	-ls -l mv_tests/afile;
+
+	@echo;
+	rm -f mv_tests/{afile,newname};
+
+	@echo;
+	cd mv_tests;				\
+	 echo A file > afile;			\
+	 ls -l afile > ../mv_afile_newname.bb;	\
+	 ${BMV} afile newname;			\
+	 ls -l newname >> ../mv_afile_newname.bb;
+	-ls -l mv_tests/afile;
+
+	@echo;
+	diff -u mv_afile_newname.gnu mv_afile_newname.bb;
+
+	@echo;
+	rm -f mv_tests/{afile,newname};
+
+	@echo; echo;
+	cd mv_tests;				\
+	 echo A file > afile;			\
+	 ln -s afile symlink;			\
+	 ls -l afile symlink > ../mv_symlink_newname.gnu; \
+	 ${GMV} symlink newname;		\
+	 ls -l afile newname >> ../mv_symlink_newname.gnu;
+	-ls -l mv_tests/symlink;
+
+	@echo;
+	rm -f mv_tests/{afile,newname};
+
+	@echo;
+	cd mv_tests;				\
+	 echo A file > afile;			\
+	 ln -s afile symlink;			\
+	 ls -l afile symlink > ../mv_symlink_newname.bb;\
+	 ${BMV} symlink newname;		\
+	 ls -l afile newname >> ../mv_symlink_newname.bb;
+	-ls -l mv_tests/symlink;
+
+	@echo;
+	diff -u mv_symlink_newname.gnu mv_symlink_newname.bb;
+
+	@echo;
+	rm -rf mv_tests/*;
+
+	@echo; echo;
+	cd mv_tests;				\
+	 echo A file > afile;			\
+	 ln -s afile symlink;			\
+	 mkdir newdir;				\
+	 ls -lR > ../mv_file_symlink_dir.gnu;	\
+	 ${GMV} symlink afile newdir;		\
+	 ls -lR >> ../mv_file_symlink_dir.gnu;
+	-ls -l mv_tests/{symlink,afile};
+
+	@echo;
+	rm -rf mv_tests/*
+
+	@echo; echo;
+	cd mv_tests;				\
+	 echo A file > afile;			\
+	 ln -s afile symlink;			\
+	 mkdir newdir;				\
+	 ls -lR > ../mv_file_symlink_dir.bb;	\
+	 ${BMV} symlink afile newdir;		\
+	 ls -lR >> ../mv_file_symlink_dir.bb;
+	-ls -l mv_tests/{symlink,afile};
+
+	@echo;
+	diff -u mv_file_symlink_dir.gnu mv_file_symlink_dir.bb;
+
+	@echo;
+	rm -rf mv_tests/*;
+
+	@echo; echo;
+	cd mv_tests;				\
+	 mkdir dir{a,b};			\
+	 echo A file > dira/afile;		\
+	 echo A file in dirb > dirb/afileindirb; \
+	 ln -s dira/afile dira/alinktoafile;	\
+	 mkdir dira/subdir1;			\
+	 echo Another file > dira/subdir1/anotherfile; \
+	 ls -lR . > ../mv_dira_dirb.gnu;	\
+	 ${GMV} dira dirb;			\
+	 ls -lR . >> ../mv_dira_dirb.gnu;
+
+	# false;
+	@echo;
+	rm -rf mv_tests/dir{a,b};
+
+	@echo;
+	cd mv_tests;				\
+	 mkdir dir{a,b};			\
+	 echo A file > dira/afile;		\
+	 echo A file in dirb > dirb/afileindirb; \
+	 ln -s dira/afile dira/alinktoafile;	\
+	 mkdir dira/subdir1;			\
+	 echo Another file > dira/subdir1/anotherfile; \
+	 ls -lR . > ../mv_dira_dirb.bb;		\
+	 ${BMV} dira dirb;			\
+	 ls -lR . >> ../mv_dira_dirb.bb;
+
+	@echo;
+	diff -u mv_dira_dirb.gnu mv_dira_dirb.bb;
+
+	# false;
+	@echo;
+	rm -rf mv_tests/dir{a,b};
diff --git a/umount.c b/umount.c
index 68b27e3..b65caf7 100644
--- a/umount.c
+++ b/umount.c
@@ -37,11 +37,24 @@
 #else
 "\n"
 #endif
+#ifdef BB_FEATURE_REMOUNT
+"\t-r:\tTry to remount devices as read-only if mount is busy\n"
+#endif
 ;
 
+struct _mtab_entry_t {
+  char *device;
+  char *mountpt;
+  struct _mtab_entry_t *next;
+};
+
+static struct _mtab_entry_t *mtab_cache = NULL;
+
+
 
 static int useMtab = TRUE;
 static int umountAll = FALSE;
+static int doRemount = FALSE;
 extern const char mtab_file[]; /* Defined in utility.c */
 
 #define MIN(x,y) (x > y ? x : y)
@@ -50,21 +63,10 @@
 do_umount(const char* name, int useMtab)
 {
     int status;
-    struct mntent *m;
-    FILE *mountTable;
-    const char *blockDevice = NULL;
+    char *blockDevice = mtab_getinfo(name, MTAB_GETDEVICE);
 
-    if ((mountTable = setmntent (mtab_file, "r"))) {
-	while ((m = getmntent (mountTable)) != 0) {
-	    if (strncmp(m->mnt_dir, name,
-			MIN(strlen(m->mnt_dir),strlen(name))) == 0)
-		blockDevice = m->mnt_fsname;
-	    else if (strcmp(m->mnt_fsname, name) == 0) {
-		blockDevice = name;
-		name = m->mnt_dir;
-	    }
-	}
-    }
+    if (blockDevice && strcmp(blockDevice, name) == 0)
+        name = mtab_getinfo(blockDevice, MTAB_GETMOUNTPT);
 
     status = umount(name);
 
@@ -73,57 +75,53 @@
 	/* this was a loop device, delete it */
 	del_loop(blockDevice);
 #endif
-#if defined BB_MTAB
+#if defined BB_FEATURE_REMOUNT
+    if ( status != 0 && doRemount == TRUE && errno == EBUSY ) {
+        status = mount(blockDevice, name, NULL, 
+                       MS_MGC_VAL | MS_REMOUNT | MS_RDONLY, NULL);
+	if (status == 0) {
+	    fprintf(stderr, "umount: %s busy - remounted read-only\n", 
+                    blockDevice);
+	    /* TODO: update mtab if BB_MTAB is defined */
+	} else {
+	    fprintf(stderr, "umount: Cannot remount %s read-only\n",
+                    blockDevice);
+	}
+    }
+#endif
     if ( status == 0 ) {
+#if defined BB_MTAB
 	if ( useMtab==TRUE )
 	    erase_mtab(name);
-	return 0;
-    }
-    else
 #endif
-	return(status);
+	return( TRUE);
+    }
+    return(FALSE);
 }
 
 static int
 umount_all(int useMtab)
 {
-	int status;
-	struct mntent *m;
-        FILE *mountTable;
+	int status = TRUE;
+	char *mountpt;
+	void *iter;
 
-        if ((mountTable = setmntent (mtab_file, "r"))) {
-            while ((m = getmntent (mountTable)) != 0) {
-                char *blockDevice = m->mnt_fsname;
-#if ! defined BB_MTAB
-		if (strcmp (blockDevice, "/dev/root") == 0) {
-		    struct fstab* fstabItem;
-		    fstabItem = getfsfile ("/");
-		    if (fstabItem != NULL) {
-			blockDevice = fstabItem->fs_spec;
-		    }
+	for (mountpt = mtab_first(&iter); mountpt; mountpt = mtab_next(&iter)) {
+            status=do_umount (mountpt, useMtab);
+            if (status != 0) {
+                /* Don't bother retrying the umount on busy devices */
+		if (errno == EBUSY) {
+                   perror(mountpt);
+		   continue;
 		}
-#endif
-		/* Don't umount /proc when doing umount -a */
-                if (strcmp (blockDevice, "proc") == 0)
-		    continue;
-
-		status=do_umount (m->mnt_dir, useMtab);
-		if (status!=0) {
-		    /* Don't bother retrying the umount on busy devices */
-		    if (errno==EBUSY) {
-			perror(m->mnt_dir); 
-			continue;
-		    }
-		    status=do_umount (blockDevice, useMtab);
-		    if (status!=0) {
-			printf ("Couldn't umount %s on %s (type %s): %s\n", 
-				blockDevice, m->mnt_dir, m->mnt_type, strerror(errno));
-		    }
+		status = do_umount (mountpt, useMtab);
+		if (status != 0) {
+                    printf ("Couldn't umount %s on %s: %s\n", 
+                        mountpt, mtab_getinfo(mountpt, MTAB_GETDEVICE), strerror(errno));
 		}
             }
-            endmntent (mountTable);
         }
-        return( TRUE);
+        return (status);
 }
 
 extern int
@@ -144,13 +142,18 @@
 		useMtab = FALSE;
 		break;
 #endif
+#ifdef BB_FEATURE_REMOUNT
+	    case 'r':
+		doRemount = TRUE;
+		break;
+#endif
 	    default:
 		usage( umount_usage);
 	}
     }
 
-
-    if(umountAll==TRUE) {
+    mtab_read();
+    if (umountAll==TRUE) {
 	exit(umount_all(useMtab));
     }
     if ( do_umount(*argv,useMtab) == 0 )
@@ -161,3 +164,87 @@
     }
 }
 
+
+
+/* These functions are here because the getmntent functions do not appear
+ * to be re-entrant, which leads to all sorts of problems when we try to
+ * use them recursively - randolph
+ */
+void mtab_read(void)
+{
+    struct _mtab_entry_t *entry = NULL;
+    struct mntent *e;
+    FILE *fp;
+  
+    if (mtab_cache != NULL) return;
+ 
+    if ((fp = setmntent(mtab_file, "r")) == NULL) {
+        fprintf(stderr, "Cannot open %s\n", mtab_file);
+	return;
+    }
+    while ((e = getmntent(fp))) {
+        entry = malloc(sizeof(struct _mtab_entry_t));
+	entry->device = strdup(e->mnt_fsname);
+	entry->mountpt = strdup(e->mnt_dir);
+	entry->next = mtab_cache;
+	mtab_cache = entry;
+    }
+    endmntent(fp);
+}
+
+char *mtab_getinfo(const char *match, const char which)
+{
+    struct _mtab_entry_t *cur = mtab_cache;
+    while (cur) {
+        if (strcmp(cur->mountpt, match) == 0 ||
+	    strcmp(cur->device, match) == 0) {
+	    if (which == MTAB_GETMOUNTPT) {
+	        return cur->mountpt;
+	    } else {
+#if !defined BB_MTAB
+                if (strcmp(cur->device, "/dev/root") == 0) {
+                    struct fstab* fstabItem;
+	            fstabItem = getfsfile ("/");
+	            if (fstabItem != NULL) return fstabItem->fs_spec;
+	        }
+#endif
+	        return cur->device;  
+	    }
+	}
+        cur = cur->next;
+    }
+    return NULL;
+}
+
+char *mtab_first(void **iter)
+{
+    struct _mtab_entry_t *mtab_iter;
+    if (!iter) return NULL;
+    mtab_iter = mtab_cache;
+    *iter = (void *)mtab_iter;
+    return mtab_next(iter);
+}
+
+char *mtab_next(void **iter)
+{
+    char *mp;
+    if (iter == NULL || *iter == NULL) return NULL;
+    mp = ((struct _mtab_entry_t *)(*iter))->mountpt;
+    *iter = (void *)((struct _mtab_entry_t *)(*iter))->next;
+    return mp;
+}
+
+void mtab_free(void)
+{
+    struct _mtab_entry_t *this, *next;
+
+    this = mtab_cache;
+    while (this) {
+      next = this->next;
+      if (this->device) free(this->device);
+      if (this->mountpt) free(this->mountpt);
+      free(this);
+      this = next;
+    }
+}
+
diff --git a/uniq.c b/uniq.c
index a7bff54..965d290 100644
--- a/uniq.c
+++ b/uniq.c
@@ -193,4 +193,4 @@
     exit(0);
 }
 
-/* $Id: uniq.c,v 1.5 2000/01/23 18:19:02 erik Exp $ */
+/* $Id: uniq.c,v 1.6 2000/02/07 05:29:42 erik Exp $ */
diff --git a/util-linux/fdflush.c b/util-linux/fdflush.c
index 51b0c2b..a244e8d 100644
--- a/util-linux/fdflush.c
+++ b/util-linux/fdflush.c
@@ -31,7 +31,7 @@
 {
     int	value;
     int	fd;
-    if ( **(argv+1) == '-' ) {
+    if ( argc <= 1 || **(argv++) == '-' ) {
 	usage( "fdflush device\n");
     }
 
diff --git a/util-linux/fsck_minix.c b/util-linux/fsck_minix.c
index d31de20..09111c5 100644
--- a/util-linux/fsck_minix.c
+++ b/util-linux/fsck_minix.c
@@ -96,6 +96,7 @@
 #include <termios.h>
 #include <mntent.h>
 #include <sys/stat.h>
+#include <sys/param.h>		/* for PATH_MAX */
 
 #include <linux/fs.h>
 #include <linux/minix_fs.h>
@@ -143,7 +144,7 @@
 /* File-name data */
 #define MAX_DEPTH 50
 static int name_depth = 0;
-static char name_list[MAX_DEPTH][NAME_MAX+1];
+static char name_list[MAX_DEPTH][PATH_MAX + 1];
 
 static char * inode_buffer = NULL;
 #define Inode (((struct minix_inode *) inode_buffer)-1)
diff --git a/util-linux/swaponoff.c b/util-linux/swaponoff.c
index 8eaf979..3c02bdd 100644
--- a/util-linux/swaponoff.c
+++ b/util-linux/swaponoff.c
@@ -65,7 +65,6 @@
 do_em_all()
 {
 	struct mntent *m;
-	char swapName[NAME_MAX];
 	FILE *f = setmntent ("/etc/fstab", "r");
 
 	if (f == NULL) {
@@ -73,8 +72,8 @@
 	    exit( FALSE); 
 	}
 	while ((m = getmntent (f)) != NULL) {
-	    if (!strstr (m->mnt_type, "swap")) {
-		    swap_enable_disable( swapName);
+	    if (!strstr (m->mnt_type, MNTTYPE_SWAP)) {
+		    swap_enable_disable( m->mnt_fsname);
 	    }
 	}
 	endmntent (f);
diff --git a/util-linux/umount.c b/util-linux/umount.c
index 68b27e3..b65caf7 100644
--- a/util-linux/umount.c
+++ b/util-linux/umount.c
@@ -37,11 +37,24 @@
 #else
 "\n"
 #endif
+#ifdef BB_FEATURE_REMOUNT
+"\t-r:\tTry to remount devices as read-only if mount is busy\n"
+#endif
 ;
 
+struct _mtab_entry_t {
+  char *device;
+  char *mountpt;
+  struct _mtab_entry_t *next;
+};
+
+static struct _mtab_entry_t *mtab_cache = NULL;
+
+
 
 static int useMtab = TRUE;
 static int umountAll = FALSE;
+static int doRemount = FALSE;
 extern const char mtab_file[]; /* Defined in utility.c */
 
 #define MIN(x,y) (x > y ? x : y)
@@ -50,21 +63,10 @@
 do_umount(const char* name, int useMtab)
 {
     int status;
-    struct mntent *m;
-    FILE *mountTable;
-    const char *blockDevice = NULL;
+    char *blockDevice = mtab_getinfo(name, MTAB_GETDEVICE);
 
-    if ((mountTable = setmntent (mtab_file, "r"))) {
-	while ((m = getmntent (mountTable)) != 0) {
-	    if (strncmp(m->mnt_dir, name,
-			MIN(strlen(m->mnt_dir),strlen(name))) == 0)
-		blockDevice = m->mnt_fsname;
-	    else if (strcmp(m->mnt_fsname, name) == 0) {
-		blockDevice = name;
-		name = m->mnt_dir;
-	    }
-	}
-    }
+    if (blockDevice && strcmp(blockDevice, name) == 0)
+        name = mtab_getinfo(blockDevice, MTAB_GETMOUNTPT);
 
     status = umount(name);
 
@@ -73,57 +75,53 @@
 	/* this was a loop device, delete it */
 	del_loop(blockDevice);
 #endif
-#if defined BB_MTAB
+#if defined BB_FEATURE_REMOUNT
+    if ( status != 0 && doRemount == TRUE && errno == EBUSY ) {
+        status = mount(blockDevice, name, NULL, 
+                       MS_MGC_VAL | MS_REMOUNT | MS_RDONLY, NULL);
+	if (status == 0) {
+	    fprintf(stderr, "umount: %s busy - remounted read-only\n", 
+                    blockDevice);
+	    /* TODO: update mtab if BB_MTAB is defined */
+	} else {
+	    fprintf(stderr, "umount: Cannot remount %s read-only\n",
+                    blockDevice);
+	}
+    }
+#endif
     if ( status == 0 ) {
+#if defined BB_MTAB
 	if ( useMtab==TRUE )
 	    erase_mtab(name);
-	return 0;
-    }
-    else
 #endif
-	return(status);
+	return( TRUE);
+    }
+    return(FALSE);
 }
 
 static int
 umount_all(int useMtab)
 {
-	int status;
-	struct mntent *m;
-        FILE *mountTable;
+	int status = TRUE;
+	char *mountpt;
+	void *iter;
 
-        if ((mountTable = setmntent (mtab_file, "r"))) {
-            while ((m = getmntent (mountTable)) != 0) {
-                char *blockDevice = m->mnt_fsname;
-#if ! defined BB_MTAB
-		if (strcmp (blockDevice, "/dev/root") == 0) {
-		    struct fstab* fstabItem;
-		    fstabItem = getfsfile ("/");
-		    if (fstabItem != NULL) {
-			blockDevice = fstabItem->fs_spec;
-		    }
+	for (mountpt = mtab_first(&iter); mountpt; mountpt = mtab_next(&iter)) {
+            status=do_umount (mountpt, useMtab);
+            if (status != 0) {
+                /* Don't bother retrying the umount on busy devices */
+		if (errno == EBUSY) {
+                   perror(mountpt);
+		   continue;
 		}
-#endif
-		/* Don't umount /proc when doing umount -a */
-                if (strcmp (blockDevice, "proc") == 0)
-		    continue;
-
-		status=do_umount (m->mnt_dir, useMtab);
-		if (status!=0) {
-		    /* Don't bother retrying the umount on busy devices */
-		    if (errno==EBUSY) {
-			perror(m->mnt_dir); 
-			continue;
-		    }
-		    status=do_umount (blockDevice, useMtab);
-		    if (status!=0) {
-			printf ("Couldn't umount %s on %s (type %s): %s\n", 
-				blockDevice, m->mnt_dir, m->mnt_type, strerror(errno));
-		    }
+		status = do_umount (mountpt, useMtab);
+		if (status != 0) {
+                    printf ("Couldn't umount %s on %s: %s\n", 
+                        mountpt, mtab_getinfo(mountpt, MTAB_GETDEVICE), strerror(errno));
 		}
             }
-            endmntent (mountTable);
         }
-        return( TRUE);
+        return (status);
 }
 
 extern int
@@ -144,13 +142,18 @@
 		useMtab = FALSE;
 		break;
 #endif
+#ifdef BB_FEATURE_REMOUNT
+	    case 'r':
+		doRemount = TRUE;
+		break;
+#endif
 	    default:
 		usage( umount_usage);
 	}
     }
 
-
-    if(umountAll==TRUE) {
+    mtab_read();
+    if (umountAll==TRUE) {
 	exit(umount_all(useMtab));
     }
     if ( do_umount(*argv,useMtab) == 0 )
@@ -161,3 +164,87 @@
     }
 }
 
+
+
+/* These functions are here because the getmntent functions do not appear
+ * to be re-entrant, which leads to all sorts of problems when we try to
+ * use them recursively - randolph
+ */
+void mtab_read(void)
+{
+    struct _mtab_entry_t *entry = NULL;
+    struct mntent *e;
+    FILE *fp;
+  
+    if (mtab_cache != NULL) return;
+ 
+    if ((fp = setmntent(mtab_file, "r")) == NULL) {
+        fprintf(stderr, "Cannot open %s\n", mtab_file);
+	return;
+    }
+    while ((e = getmntent(fp))) {
+        entry = malloc(sizeof(struct _mtab_entry_t));
+	entry->device = strdup(e->mnt_fsname);
+	entry->mountpt = strdup(e->mnt_dir);
+	entry->next = mtab_cache;
+	mtab_cache = entry;
+    }
+    endmntent(fp);
+}
+
+char *mtab_getinfo(const char *match, const char which)
+{
+    struct _mtab_entry_t *cur = mtab_cache;
+    while (cur) {
+        if (strcmp(cur->mountpt, match) == 0 ||
+	    strcmp(cur->device, match) == 0) {
+	    if (which == MTAB_GETMOUNTPT) {
+	        return cur->mountpt;
+	    } else {
+#if !defined BB_MTAB
+                if (strcmp(cur->device, "/dev/root") == 0) {
+                    struct fstab* fstabItem;
+	            fstabItem = getfsfile ("/");
+	            if (fstabItem != NULL) return fstabItem->fs_spec;
+	        }
+#endif
+	        return cur->device;  
+	    }
+	}
+        cur = cur->next;
+    }
+    return NULL;
+}
+
+char *mtab_first(void **iter)
+{
+    struct _mtab_entry_t *mtab_iter;
+    if (!iter) return NULL;
+    mtab_iter = mtab_cache;
+    *iter = (void *)mtab_iter;
+    return mtab_next(iter);
+}
+
+char *mtab_next(void **iter)
+{
+    char *mp;
+    if (iter == NULL || *iter == NULL) return NULL;
+    mp = ((struct _mtab_entry_t *)(*iter))->mountpt;
+    *iter = (void *)((struct _mtab_entry_t *)(*iter))->next;
+    return mp;
+}
+
+void mtab_free(void)
+{
+    struct _mtab_entry_t *this, *next;
+
+    this = mtab_cache;
+    while (this) {
+      next = this->next;
+      if (this->device) free(this->device);
+      if (this->mountpt) free(this->mountpt);
+      free(this);
+      this = next;
+    }
+}
+
diff --git a/utility.c b/utility.c
index 191701b..a27aaa2 100644
--- a/utility.c
+++ b/utility.c
@@ -25,6 +25,17 @@
  */
 
 #include "internal.h"
+#if defined (BB_CHMOD_CHOWN_CHGRP) \
+ || defined (BB_CP_MV)		   \
+ || defined (BB_FIND)		   \
+ || defined (BB_LS)		   \
+ || defined (BB_INSMOD)
+/* same conditions as recursiveAction */
+#define bb_need_name_too_long
+#endif
+#define BB_DECLARE_EXTERN
+#include "messages.c"
+
 #include <stdio.h>
 #include <string.h>
 #include <errno.h>
@@ -35,6 +46,7 @@
 #include <sys/stat.h>
 #include <unistd.h>
 #include <ctype.h>
+#include <sys/param.h>		/* for PATH_MAX */
 
 #if defined BB_FEATURE_MOUNT_LOOP
 #include <fcntl.h>
@@ -58,9 +70,10 @@
 
 extern void usage(const char *usage)
 {
-    fprintf(stderr, "BusyBox v%s (%s) multi-call binary -- GPL2\n\n", BB_VER, BB_BT);
+    fprintf(stderr, "BusyBox v%s (%s) multi-call binary -- GPL2\n\n",
+	    BB_VER, BB_BT);
     fprintf(stderr, "Usage: %s\n", usage);
-    exit(FALSE);
+    exit FALSE;
 }
 
 
@@ -78,9 +91,8 @@
 {
   FILE *file;
   int major=0, minor=0, patch=0;
-  char* filename="/proc/sys/kernel/osrelease";
 
-  file = fopen(filename,"r");
+  file = fopen("/proc/sys/kernel/osrelease", "r");
   if (file == NULL) {
     /* bummer, /proc must not be mounted... */
     return( 0);
@@ -89,28 +101,34 @@
   fclose(file);
   return major*65536 + minor*256 + patch;
 }
-
-#endif
+#endif /* BB_INIT || BB_PS */
 
 
 
-#if defined (BB_CP) || defined (BB_MV)
+#if defined (BB_CP_MV) || defined (BB_DU) || defined (BB_LN)
 /*
  * Return TRUE if a fileName is a directory.
  * Nonexistant files return FALSE.
  */
-int isDirectory(const char *name)
+int isDirectory(const char *fileName, const int followLinks)
 {
     struct stat statBuf;
+    int status;
 
-    if (stat(name, &statBuf) < 0)
-	return FALSE;
+    if (followLinks == TRUE)
+      status = stat(fileName, &statBuf);
+    else
+      status = lstat(fileName, &statBuf);
+
+    if (status < 0)
+      return FALSE;
     if (S_ISDIR(statBuf.st_mode))
-	return TRUE;
-    return(FALSE);
+      return TRUE;
+    return FALSE;
 }
+#endif
 
-
+#if defined (BB_CP_MV)
 /*
  * Copy one file to another, while possibly preserving its modes, times,
  * and modes.  Returns TRUE if successful, or FALSE on a failure with an
@@ -120,33 +138,33 @@
  */
 int
 copyFile( const char *srcName, const char *destName, 
-	 int setModes, int followLinks)
+	  int setModes, int followLinks)
 {
     int rfd;
     int wfd;
     int rcc;
-    int result;
+    int status;
     char buf[BUF_SIZE];
     struct stat srcStatBuf;
     struct stat dstStatBuf;
     struct utimbuf times;
 
-    /* Grab the source file's stats */
-    if (followLinks == FALSE)
-	result = stat(srcName, &srcStatBuf);
+    if (followLinks == TRUE)
+	status = stat(srcName, &srcStatBuf);
     else 
-	result = lstat(srcName, &srcStatBuf);
-    if (result < 0) {
+	status = lstat(srcName, &srcStatBuf);
+
+    if (status < 0) {
 	perror(srcName);
 	return FALSE;
     }
 
-    /* Grab the dest file's stats */
-    if (followLinks == FALSE)
-	result = stat(destName, &dstStatBuf);
-    else 
-	result = lstat(destName, &dstStatBuf);
-    if (result < 0) {
+    if (followLinks == TRUE)	
+	status = stat(destName, &dstStatBuf);
+    else
+	status = lstat(destName, &dstStatBuf);
+
+    if (status < 0) {
 	dstStatBuf.st_ino = -1;
 	dstStatBuf.st_dev = -1;
     }
@@ -160,45 +178,49 @@
     if (S_ISDIR(srcStatBuf.st_mode)) {
 	//fprintf(stderr, "copying directory %s to %s\n", srcName, destName);
 	/* Make sure the directory is writable */
-	result = mkdir(destName, 0777777 ^ umask(0));
-	if (result < 0 && errno != EEXIST) {
+	status = mkdir(destName, 0777777 ^ umask(0));
+	if (status < 0 && errno != EEXIST) {
 	    perror(destName);
-	    return (FALSE);
+	    return FALSE;
 	}
     } else if (S_ISLNK(srcStatBuf.st_mode)) {
-	char *link_val;
+	char link_val[PATH_MAX + 1];
 	int link_size;
 
 	//fprintf(stderr, "copying link %s to %s\n", srcName, destName);
-	link_val = (char *) alloca(PATH_MAX + 2);
-	link_size = readlink(srcName, link_val, PATH_MAX + 1);
+	/* Warning: This could possibly truncate silently, to PATH_MAX chars */
+	link_size = readlink(srcName, &link_val[0], PATH_MAX);
 	if (link_size < 0) {
 	    perror(srcName);
-	    return (FALSE);
+	    return FALSE;
 	}
 	link_val[link_size] = '\0';
-	link_size = symlink(link_val, destName);
-	if (link_size != 0) {
+	status = symlink(link_val, destName);
+	if (status < 0) {
 	    perror(destName);
-	    return (FALSE);
+	    return FALSE;
 	}
 #if (__GLIBC__ >= 2) && (__GLIBC_MINOR__ >= 1)
 	if (setModes == TRUE) {
-	    lchown(destName, srcStatBuf.st_uid, srcStatBuf.st_gid);
+	    if (lchown(destName, srcStatBuf.st_uid, srcStatBuf.st_gid) < 0) {
+	      perror(destName);
+	      return FALSE;
+	    }
 	}
 #endif
+	return TRUE;
     } else if (S_ISFIFO(srcStatBuf.st_mode)) {
 	//fprintf(stderr, "copying fifo %s to %s\n", srcName, destName);
-	if (mkfifo(destName, 0644)) {
+	if (mkfifo(destName, 0644) < 0) {
 	    perror(destName);
-	    return (FALSE);
+	    return FALSE;
 	}
     } else if (S_ISBLK(srcStatBuf.st_mode) || S_ISCHR(srcStatBuf.st_mode) 
-	    || S_ISSOCK (srcStatBuf.st_mode)) {
+		|| S_ISSOCK (srcStatBuf.st_mode)) {
 	//fprintf(stderr, "copying soc, blk, or chr %s to %s\n", srcName, destName);
-	if (mknod(destName, srcStatBuf.st_mode, srcStatBuf.st_rdev)) {
+	if (mknod(destName, srcStatBuf.st_mode, srcStatBuf.st_rdev) < 0) {
 	    perror(destName);
-	    return (FALSE);
+	    return FALSE;
 	}
     } else if (S_ISREG(srcStatBuf.st_mode)) {
 	//fprintf(stderr, "copying regular file %s to %s\n", srcName, destName);
@@ -208,7 +230,7 @@
 	    return FALSE;
 	}
 
-	wfd = creat(destName, srcStatBuf.st_mode);
+	wfd = open(destName, O_WRONLY | O_CREAT | O_TRUNC, srcStatBuf.st_mode);
 	if (wfd < 0) {
 	    perror(destName);
 	    close(rfd);
@@ -231,24 +253,32 @@
 
     if (setModes == TRUE) {
 	/* This is fine, since symlinks never get here */
-	chown(destName, srcStatBuf.st_uid, srcStatBuf.st_gid);
-	chmod(destName, srcStatBuf.st_mode);
+	if (chown(destName, srcStatBuf.st_uid, srcStatBuf.st_gid) < 0) {
+	  perror(destName);
+	  exit FALSE;
+	}
+	if (chmod(destName, srcStatBuf.st_mode) < 0) {
+	  perror(destName);
+	  exit FALSE;
+	}
 	times.actime = srcStatBuf.st_atime;
 	times.modtime = srcStatBuf.st_mtime;
-	utime(destName, &times);
+	if (utime(destName, &times) < 0) {
+	  perror(destName);
+	  exit FALSE;
+	}
     }
 
     return TRUE;
 
-
-  error_exit:
+ error_exit:
     perror(destName);
     close(rfd);
     close(wfd);
 
     return FALSE;
 }
-#endif
+#endif /* BB_CP_MV */
 
 
 
@@ -296,7 +326,7 @@
     }
     return buf;
 }
-#endif
+#endif /* BB_TAR || BB_LS */
 
 
 #if defined BB_TAR
@@ -324,9 +354,9 @@
 
     return buf;
 }
-#endif
+#endif /* BB_TAR */
 
-#if defined BB_TAR || defined BB_CP || defined BB_MV
+#if defined BB_TAR || defined BB_CP_MV
 /*
  * Write all of the supplied buffer out to a file.
  * This does multiple writes as necessary.
@@ -352,7 +382,7 @@
 
     return total;
 }
-#endif
+#endif /* BB_TAR || BB_CP_MV */
 
 
 #if defined BB_TAR || defined BB_TAIL
@@ -385,10 +415,14 @@
 
     return total;
 }
-#endif
+#endif /* BB_TAR || BB_TAIL */
 
 
-#if defined (BB_CHMOD_CHOWN_CHGRP) || defined (BB_CP) || defined (BB_FIND) || defined (BB_LS) || defined (BB_INSMOD)
+#if defined (BB_CHMOD_CHOWN_CHGRP) \
+ || defined (BB_CP_MV)		   \
+ || defined (BB_FIND)		   \
+ || defined (BB_LS)		   \
+ || defined (BB_INSMOD)
 /*
  * Walk down all the directories under the specified 
  * location, and do something (something specified
@@ -399,13 +433,15 @@
  * and so isn't sufficiently portable to take over since glibc2.1
  * is so stinking huge.
  */
-int
-recursiveAction(const char *fileName, int recurse, int followLinks, int depthFirst,
-		int (*fileAction) (const char *fileName, struct stat* statbuf),
-		int (*dirAction) (const char *fileName, struct stat* statbuf))
+int recursiveAction(const char *fileName,
+		    int recurse, int followLinks, int depthFirst,
+		    int (*fileAction) (const char *fileName,
+				       struct stat* statbuf),
+		    int (*dirAction) (const char *fileName,
+				      struct stat* statbuf))
 {
     int status;
-    struct stat statbuf, statbuf1;
+    struct stat statbuf;
     struct dirent *next;
 
     if (followLinks == TRUE)
@@ -414,16 +450,20 @@
 	status = lstat(fileName, &statbuf);
 
     if (status < 0) {
-	//fprintf(stderr, "status=%d followLinks=%d TRUE=%d\n", status, followLinks, TRUE);
+#ifdef BB_DEBUG_PRINT_SCAFFOLD
+      fprintf(stderr,
+	      "status=%d followLinks=%d TRUE=%d\n",
+	      status, followLinks, TRUE);
+#endif
 	perror(fileName);
-	return (FALSE);
+	return FALSE;
     }
 
-    if ( (followLinks == FALSE) && (S_ISLNK(statbuf.st_mode)) ) {
+    if ((followLinks == FALSE) && (S_ISLNK(statbuf.st_mode)) ) {
 	if (fileAction == NULL)
-	    return (TRUE);
+	    return TRUE;
 	else
-	    return (fileAction(fileName, &statbuf));
+	    return fileAction(fileName, &statbuf);
     }
 
     if (recurse == FALSE) {
@@ -431,67 +471,65 @@
 	    if (dirAction != NULL)
 		return (dirAction(fileName, &statbuf));
 	    else
-		return (TRUE);
-	} 
-    }
-    
-    status = lstat(fileName, &statbuf1);
-    if (status < 0) {
-	perror(fileName);
-	return (FALSE);
+		return TRUE;
+	}
     }
 
-    if (S_ISDIR(statbuf.st_mode) && S_ISDIR(statbuf1.st_mode)) {
+    if (S_ISDIR(statbuf.st_mode)) {
 	DIR *dir;
 	dir = opendir(fileName);
 	if (!dir) {
 	    perror(fileName);
-	    return (FALSE);
+	    return FALSE;
 	}
 	if (dirAction != NULL && depthFirst == FALSE) {
 	    status = dirAction(fileName, &statbuf);
 	    if (status == FALSE) {
 		perror(fileName);
-		return (FALSE);
+		return FALSE;
 	    }
 	}
 	while ((next = readdir(dir)) != NULL) {
-	    char nextFile[NAME_MAX];
+	    char nextFile[PATH_MAX + 1];
 	    if ((strcmp(next->d_name, "..") == 0)
-		|| (strcmp(next->d_name, ".") == 0)) {
+		 || (strcmp(next->d_name, ".") == 0)) {
 		continue;
 	    }
+	    if (strlen(fileName) + strlen(next->d_name) + 1 > PATH_MAX) {
+		fprintf(stderr, name_too_long, "ftw");
+		return FALSE;
+	    }
 	    sprintf(nextFile, "%s/%s", fileName, next->d_name);
 	    status =
 		recursiveAction(nextFile, TRUE, followLinks, depthFirst, 
-			fileAction, dirAction);
+				fileAction, dirAction);
 	    if (status < 0) {
 		closedir(dir);
-		return (FALSE);
+		return FALSE;
 	    }
 	}
 	status = closedir(dir);
 	if (status < 0) {
 	    perror(fileName);
-	    return (FALSE);
+	    return FALSE;
 	}
 	if (dirAction != NULL && depthFirst == TRUE) {
 	    status = dirAction(fileName, &statbuf);
 	    if (status == FALSE) {
 		perror(fileName);
-		return (FALSE);
+		return FALSE;
 	    }
 	}
     } else {
 	if (fileAction == NULL)
-	    return (TRUE);
+	    return TRUE;
 	else
-	    return (fileAction(fileName, &statbuf));
+	    return fileAction(fileName, &statbuf);
     }
-    return (TRUE);
+    return TRUE;
 }
 
-#endif
+#endif /* BB_CHMOD_CHOWN_CHGRP || BB_CP_MV || BB_FIND || BB_LS || BB_INSMOD */
 
 
 
@@ -506,25 +544,25 @@
 {
     char *cp;
     char *cpOld;
-    char buf[NAME_MAX];
+    char buf[PATH_MAX + 1];
     int retVal=0;
 
     strcpy( buf, name);
-    cp = strchr (buf, '/');
+    cp = strchr(buf, '/');
     while (cp) {
 	cpOld = cp;
-	cp = strchr (cp + 1, '/');
+	cp = strchr(cp + 1, '/');
 	*cpOld = '\0';
-	retVal = mkdir (buf, cp ? 0777 : mode);
+	retVal = mkdir(buf, cp ? 0777 : mode);
 	if (retVal != 0 && errno != EEXIST) {
-	    perror( buf);
-	    return( FALSE);
+	    perror(buf);
+	    return FALSE;
 	}
 	*cpOld = '/';
     }
-    return( TRUE);
+    return TRUE;
 }
-#endif
+#endif /* BB_TAR || BB_MKDIR */
 
 
 
@@ -624,7 +662,7 @@
 }
 
 
-#endif
+#endif /* BB_CHMOD_CHOWN_CHGRP || BB_MKDIR */
 
 
 
@@ -712,7 +750,7 @@
 }
 
 
-#endif
+#endif /* BB_CHMOD_CHOWN_CHGRP || BB_PS */
 
 
 
@@ -804,7 +842,7 @@
 }
 
 
-#endif
+#endif /* BB_CHVT || BB_DEALLOCVT */
 
 
 #if !defined BB_REGEXP && (defined BB_GREP || defined BB_SED)  
@@ -883,8 +921,7 @@
 	return FALSE;
 }
 
-
-#endif
+#endif /* ! BB_REGEXP && (BB_GREP || BB_SED) */
 
 
 #if defined BB_FIND
@@ -986,7 +1023,7 @@
 
     return TRUE;
 }
-#endif
+#endif /* BB_FIND */
 
 
 
@@ -1030,7 +1067,7 @@
     endmntent(mountTable);
     return mountEntry;
 }
-#endif
+#endif /* BB_DF || BB_MTAB */
 
 
 
@@ -1052,7 +1089,8 @@
 	value = value * 10 + *cp++ - '0';
 
     switch (*cp++) {
-    case 'm':
+    case 'M':
+    case 'm': /* `tail' uses it traditionally */
 	value *= 1048576;
 	break;
 
@@ -1080,7 +1118,7 @@
 
     return value;
 }
-#endif
+#endif /* BB_DD || BB_TAIL */
 
 
 #if defined BB_INIT || defined BB_HALT || defined BB_REBOOT 
@@ -1120,9 +1158,12 @@
     }
     return 0;
 }
-#endif
+#endif /* BB_INIT || BB_HALT || BB_REBOOT */
 
-#if defined BB_GUNZIP || defined BB_GZIP || defined BB_PRINTF || defined BB_TAIL
+#if defined BB_GUNZIP \
+ || defined BB_GZIP   \
+ || defined BB_PRINTF \
+ || defined BB_TAIL
 extern void *xmalloc (size_t size)
 {
     void *cp = malloc (size);
@@ -1138,7 +1179,7 @@
     fprintf(stderr, "\n%s\n", msg);
     exit(1);
 }
-#endif
+#endif /* BB_GUNZIP || BB_GZIP || BB_PRINTF || BB_TAIL */
 
 #if (__GLIBC__ < 2) && (defined BB_SYSLOGD || defined BB_INIT)
 extern int vdprintf(int d, const char *format, va_list ap)
@@ -1149,7 +1190,7 @@
     len = vsprintf(buf, format, ap);
     return write(d, buf, len);
 }
-#endif
+#endif /* BB_SYSLOGD */
 
 #if defined BB_FEATURE_MOUNT_LOOP
 extern int del_loop(const char *device)