A few updates (including the cp fix the Craig has been looking for)
 -Erik
diff --git a/AUTHORS b/AUTHORS
index 7986afc..526205b 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -37,4 +37,5 @@
 Enrique Zanardi <ezanardi@ull.es>
     tarcat (since removed), loadkmap, various fixes, Debian maintenance
 
-
+Karl M. Hegbloom <karlheg@debian.org>
+    cp_mv.c, the test suite, various fixes to utility.c, &c.
diff --git a/Changelog b/Changelog
index 3c90ab9..0398ce9 100644
--- a/Changelog
+++ b/Changelog
@@ -18,6 +18,20 @@
 	    free).  Use of /proc (or not) is policy that should be set up in 
 	    /etc/fstab (or in hardcoded scripts), not in init.
 	* Fixed rebooting when init runs as an initrd.
+	* Fixes and updates from Karl M. Hegbloom  <karlheg@debian.org>
+	    - update.c rewritten to look more like update-2.11
+	    - moveed the inode hash out of du.c and into utility.c to make 
+		it a common resource that can be used by other apps.
+	    - cp_mv.c now checks inodes to see if a source and dest are
+		the same, and prints an error (instead of endlessly looping).
+	    - mv now attempts to do a rename, and will fall back to doing
+		a copy only if the rename fails.
+	* Several fixes from Pavel Roskin <pavel_roskin@geocities.com>:
+	    - Fixes to sort.  Removed "-g", fixed and added "-r"
+	    - Fixes to the makefile for handling "strip"
+	* An initial telnet implementation was added by 
+	    Randolph Chung <tausq@debian.org>.
+
 
 	-Erik Andersen
 
diff --git a/TODO b/TODO
index e05558b..daa21cf 100644
--- a/TODO
+++ b/TODO
@@ -53,12 +53,6 @@
 -----------------------
 
 
-
-Some known bugs, todo items, etc...
-
------------------------
-
-
 -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
@@ -116,3 +110,21 @@
 syslog box, right?  I can see that this would be useful.
 I'll add this to the TODO list,
 
+
+-----------------------
+
+
+ In utility.c:copyFile: It uses followLinks for both source and
+ destination files... is that right for `mv'?  Will need to revisit
+ the GNU, freeBSD, and MINIX versions for this... Should read the
+ Unix98 and POSIX specs also.
+
+-----------------------
+
+ I think that the add_inode &c in utility.c needs to also stow the
+ st_dev field, and that du.c should NOT call `reset_inode_list'
+ because there can be hard links from inside one argv/ to inside
+ another argv/.  du.c probably ought to have an -x switch like GNU du
+ does also...
+
+
diff --git a/applets/busybox.c b/applets/busybox.c
index 13f8db9..a80a567 100644
--- a/applets/busybox.c
+++ b/applets/busybox.c
@@ -300,15 +300,17 @@
 
 int main(int argc, char **argv)
 {
-	char *s = argv[0];
-	char *name = argv[0];
-	const struct Applet *a = applets;
+	char				*s		= argv[0];
+	char				*name	= argv[0];
+	const struct Applet	*a		= applets;
 
 	while (*s != '\0') {
 		if (*s++ == '/')
 			name = s;
 	}
 
+	*argv = name;
+
 	while (a->name != 0) {
 		if (strcmp(name, a->name) == 0) {
 			int status;
@@ -341,7 +343,7 @@
 		fprintf(stderr, "Usage: busybox [function] [arguments]...\n");
 		fprintf(stderr, "   or: [function] [arguments]...\n\n");
 		fprintf(stderr,
-				"\tMost people will create a symlink to busybox for each\n"
+				"\tMost people will create a link to busybox for each\n"
 				"\tfunction name, and busybox will act like whatever you invoke it as.\n");
 		fprintf(stderr, "\nCurrently defined functions:\n");
 
@@ -362,3 +364,11 @@
 		return (main(argc, argv));
 	}
 }
+
+/*
+Local Variables:
+c-file-style: "linux"
+c-basic-offset: 4
+tab-width: 4
+End:
+*/
diff --git a/busybox.c b/busybox.c
index 13f8db9..a80a567 100644
--- a/busybox.c
+++ b/busybox.c
@@ -300,15 +300,17 @@
 
 int main(int argc, char **argv)
 {
-	char *s = argv[0];
-	char *name = argv[0];
-	const struct Applet *a = applets;
+	char				*s		= argv[0];
+	char				*name	= argv[0];
+	const struct Applet	*a		= applets;
 
 	while (*s != '\0') {
 		if (*s++ == '/')
 			name = s;
 	}
 
+	*argv = name;
+
 	while (a->name != 0) {
 		if (strcmp(name, a->name) == 0) {
 			int status;
@@ -341,7 +343,7 @@
 		fprintf(stderr, "Usage: busybox [function] [arguments]...\n");
 		fprintf(stderr, "   or: [function] [arguments]...\n\n");
 		fprintf(stderr,
-				"\tMost people will create a symlink to busybox for each\n"
+				"\tMost people will create a link to busybox for each\n"
 				"\tfunction name, and busybox will act like whatever you invoke it as.\n");
 		fprintf(stderr, "\nCurrently defined functions:\n");
 
@@ -362,3 +364,11 @@
 		return (main(argc, argv));
 	}
 }
+
+/*
+Local Variables:
+c-file-style: "linux"
+c-basic-offset: 4
+tab-width: 4
+End:
+*/
diff --git a/busybox.def.h b/busybox.def.h
index 8ed5a9c..d42be44 100644
--- a/busybox.def.h
+++ b/busybox.def.h
@@ -150,6 +150,9 @@
 // Enable support for creation of tar files.
 //#define BB_FEATURE_TAR_CREATE
 //
+//// Enable reverse sort
+//#define BB_FEATURE_SORT_REVERSE
+//
 // Allow init to permenently chroot, and umount the old root fs
 // just like an initrd does.  Requires a kernel patch by Werner Almesberger. 
 // ftp://icaftp.epfl.ch/pub/people/almesber/misc/umount-root-*.tar.gz
diff --git a/cat.c b/cat.c
index 86f85fe..58a1b0f 100644
--- a/cat.c
+++ b/cat.c
@@ -59,3 +59,11 @@
 	}
 	exit(TRUE);
 }
+
+/*
+Local Variables:
+c-file-style: "linux"
+c-basic-offset: 4
+tab-width: 4
+End:
+*/
diff --git a/chmod_chown_chgrp.c b/chmod_chown_chgrp.c
index f037e95..4e5e9b0 100644
--- a/chmod_chown_chgrp.c
+++ b/chmod_chown_chgrp.c
@@ -181,3 +181,11 @@
   bad_group:
 	fatalError( "%s: unknown group name: %s\n", invocationName, groupName);
 }
+
+/*
+Local Variables:
+c-file-style: "linux"
+c-basic-offset: 4
+tab-width: 4
+End:
+*/
diff --git a/chroot.c b/chroot.c
index 6a01be6..3622c26 100644
--- a/chroot.c
+++ b/chroot.c
@@ -65,3 +65,12 @@
 			*argv, strerror(errno));
 	exit(FALSE);
 }
+
+
+/*
+Local Variables:
+c-file-style: "linux"
+c-basic-offset: 4
+tab-width: 4
+End:
+*/
diff --git a/chvt.c b/chvt.c
index a32bd3e..635022a 100644
--- a/chvt.c
+++ b/chvt.c
@@ -34,3 +34,12 @@
 	}
 	exit(TRUE);
 }
+
+
+/*
+Local Variables:
+c-file-style: "linux"
+c-basic-offset: 4
+tab-width: 4
+End:
+*/
diff --git a/console-tools/chvt.c b/console-tools/chvt.c
index a32bd3e..635022a 100644
--- a/console-tools/chvt.c
+++ b/console-tools/chvt.c
@@ -34,3 +34,12 @@
 	}
 	exit(TRUE);
 }
+
+
+/*
+Local Variables:
+c-file-style: "linux"
+c-basic-offset: 4
+tab-width: 4
+End:
+*/
diff --git a/coreutils/cat.c b/coreutils/cat.c
index 86f85fe..58a1b0f 100644
--- a/coreutils/cat.c
+++ b/coreutils/cat.c
@@ -59,3 +59,11 @@
 	}
 	exit(TRUE);
 }
+
+/*
+Local Variables:
+c-file-style: "linux"
+c-basic-offset: 4
+tab-width: 4
+End:
+*/
diff --git a/coreutils/chroot.c b/coreutils/chroot.c
index 6a01be6..3622c26 100644
--- a/coreutils/chroot.c
+++ b/coreutils/chroot.c
@@ -65,3 +65,12 @@
 			*argv, strerror(errno));
 	exit(FALSE);
 }
+
+
+/*
+Local Variables:
+c-file-style: "linux"
+c-basic-offset: 4
+tab-width: 4
+End:
+*/
diff --git a/coreutils/df.c b/coreutils/df.c
index 43d5d26..bc843f7 100644
--- a/coreutils/df.c
+++ b/coreutils/df.c
@@ -108,3 +108,11 @@
 
 	exit(TRUE);
 }
+
+/*
+Local Variables:
+c-file-style: "linux"
+c-basic-offset: 4
+tab-width: 4
+End:
+*/
diff --git a/coreutils/du.c b/coreutils/du.c
index 4dc7ea1..b6ebaca 100644
--- a/coreutils/du.c
+++ b/coreutils/du.c
@@ -36,16 +36,6 @@
 
 typedef void (Display) (long, char *);
 
-typedef struct inode_type {
-	struct inode_type *next;
-	ino_t ino;
-} INODETYPE;
-
-#define HASH_SIZE	311		/* Should be prime */
-#define hash_inode(i)	((i) % HASH_SIZE)
-
-static INODETYPE *inode_hash_list[HASH_SIZE];
-
 static const char du_usage[] =
 	"du [OPTION]... [FILE]...\n\n"
 	"Summarize disk space used for each FILE and/or directory.\n"
@@ -71,52 +61,6 @@
 	}
 }
 
-/* Return 1 if inode is in inode hash list, else return 0 */
-static int is_in_list(const ino_t ino)
-{
-	INODETYPE *inode;
-
-	inode = inode_hash_list[hash_inode(ino)];
-	while (inode != NULL) {
-		if (inode->ino == ino)
-			return 1;
-		inode = inode->next;
-	}
-
-	return 0;
-}
-
-/* Add inode to inode hash list */
-static void add_inode(const ino_t ino)
-{
-	int i;
-	INODETYPE *inode;
-    
-	i = hash_inode(ino);
-	inode = malloc(sizeof(INODETYPE));
-	if (inode == NULL)
-		fatalError("du: Not enough memory.");
-
-	inode->ino = ino;
-	inode->next = inode_hash_list[i];
-	inode_hash_list[i] = inode;
-}
-
-/* Clear inode hash list */
-static void reset_inode_list(void)
-{
-	int i;
-	INODETYPE *inode;
-
-	for (i = 0; i < HASH_SIZE; i++) {
-		while (inode_hash_list[i] != NULL) {
-			inode = inode_hash_list[i]->next;
-			free(inode_hash_list[i]);
-			inode_hash_list[i] = inode;
-		}
-	}
-}
-
 /* tiny recursive du */
 static long du(char *filename)
 {
@@ -175,13 +119,13 @@
 	}
 	else if (statbuf.st_nlink > 1 && !count_hardlinks) {
 		/* Add files with hard links only once */
-		if (is_in_list(statbuf.st_ino)) {
+		if (is_in_ino_dev_hashtable(&statbuf, NULL)) {
 			sum = 0L;
 			if (du_depth == 1)
 				print(sum, filename);
 		}
 		else {
-			add_inode(statbuf.st_ino);
+			add_to_ino_dev_hashtable(&statbuf, NULL);
 		}
 	}
 	du_depth--;
@@ -231,11 +175,18 @@
 			if (sum && isDirectory(argv[i], FALSE, NULL)) {
 				print_normal(sum, argv[i]);
 			}
-			reset_inode_list();
+			reset_ino_dev_hashtable();
 		}
 	}
 
 	exit(0);
 }
 
-/* $Id: du.c,v 1.15 2000/02/21 17:27:17 erik Exp $ */
+/* $Id: du.c,v 1.16 2000/03/04 21:19:32 erik Exp $ */
+/*
+Local Variables:
+c-file-style: "linux"
+c-basic-offset: 4
+tab-width: 4
+End:
+*/
diff --git a/coreutils/ln.c b/coreutils/ln.c
index 0715bfa..c54026c 100644
--- a/coreutils/ln.c
+++ b/coreutils/ln.c
@@ -128,3 +128,11 @@
 	}
 	exit TRUE;
 }
+
+/*
+Local Variables:
+c-file-style: "linux"
+c-basic-offset: 4
+tab-width: 4
+End:
+*/
diff --git a/coreutils/sort.c b/coreutils/sort.c
index 609c5e0..e6894f6 100644
--- a/coreutils/sort.c
+++ b/coreutils/sort.c
@@ -29,7 +29,18 @@
 #include <stdio.h>
 #include <errno.h>
 
-static const char sort_usage[] = "sort [OPTION]... [FILE]...\n\n";
+static const char sort_usage[] = "sort [-n]"
+#ifdef BB_FEATURE_SORT_REVERSE
+" [-r]"
+#endif
+" [FILE]...\n\n";
+
+#ifdef BB_FEATURE_SORT_REVERSE
+#define APPLY_REVERSE(x) (reverse ? -(x) : (x))
+static int reverse = 0;
+#else
+#define APPLY_REVERSE(x) (x)
+#endif
 
 /* typedefs _______________________________________________________________ */
 
@@ -120,7 +131,7 @@
 	y = *doh;
 
 	// fprintf(stdout, "> %p: %s< %p: %s", x, x->data, y, y->data);
-	return strcmp(x->data, y->data);
+	return APPLY_REVERSE(strcmp(x->data, y->data));
 }
 
 /* numeric order */
@@ -138,7 +149,7 @@
 	xint = strtoul(x->data, NULL, 10);
 	yint = strtoul(y->data, NULL, 10);
 
-	return (xint - yint);
+	return APPLY_REVERSE(xint - yint);
 }
 
 
@@ -254,20 +265,19 @@
 		if (argv[i][0] == '-') {
 			opt = argv[i][1];
 			switch (opt) {
-			case 'g':
-				/* what's the diff between -g && -n? */
-				compare = compare_numeric;
-				break;
 			case 'h':
 				usage(sort_usage);
 				break;
 			case 'n':
-				/* what's the diff between -g && -n? */
+				/* numeric comparison */
 				compare = compare_numeric;
 				break;
+#ifdef BB_FEATURE_SORT_REVERSE
 			case 'r':
 				/* reverse */
+				reverse = 1;
 				break;
+#endif
 			default:
 				fprintf(stderr, "sort: invalid option -- %c\n", opt);
 				usage(sort_usage);
@@ -310,4 +320,4 @@
 	exit(0);
 }
 
-/* $Id: sort.c,v 1.11 2000/02/08 19:58:47 erik Exp $ */
+/* $Id: sort.c,v 1.12 2000/03/04 21:19:32 erik Exp $ */
diff --git a/cp_mv.c b/cp_mv.c
index 4c55e62..8dbc4e8 100644
--- a/cp_mv.c
+++ b/cp_mv.c
@@ -37,11 +37,15 @@
 #include <utime.h>
 #include <dirent.h>
 #include <sys/param.h>
+#include <setjmp.h>				/* Ok to use this since `ash' does, therefore it's in the libc subset already. */
+#include <string.h>
+#include <unistd.h>
+#include <errno.h>
 
 #define is_cp 0
 #define is_mv 1
+static int         dz_i;		/* index into cp_mv_usage */
 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"
@@ -55,92 +59,131 @@
 	"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"
 };
 
+static int recursiveFlag;
+static int followLinks;
+static int preserveFlag;
+
+static const char *baseSrcName;
+static int		   srcDirFlag;
+static struct stat srcStatBuf;
+
+static char		   baseDestName[PATH_MAX + 1];
+static size_t	   baseDestLen;
+static int		   destDirFlag;
+static struct stat destStatBuf;
+
+static jmp_buf      catch;
+static volatile int mv_Action_first_time;
+
+static void name_too_long__exit (void) __attribute__((noreturn));
+
+static
+void name_too_long__exit (void)
+{
+	fprintf(stderr, name_too_long, dz);
+	exit FALSE;
+}
+
+static 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)
+				name_too_long__exit();
+			strcat(_buf, "/");
+		}
+	}
+	if (*_buflen + strlen(srcBasename) > PATH_MAX)
+		name_too_long__exit();
+	strcat(_buf, srcBasename);
+	return;
+	
+}
+
+static int
+cp_mv_Action(const char *fileName, struct stat *statbuf)
+{
+	char		destName[PATH_MAX + 1];
+	size_t		destLen;
+	const char *srcBasename;
+	char	   *name;
+
+	strcpy(destName, baseDestName);
+	destLen = strlen(destName);
+
+	if (srcDirFlag == TRUE) {
+		if (recursiveFlag == FALSE) {
+			fprintf(stderr, omitting_directory, dz, baseSrcName);
+			return TRUE;
+		}
+		srcBasename = (strstr(fileName, baseSrcName)
+					   + strlen(baseSrcName));
+
+		if (destLen + strlen(srcBasename) > PATH_MAX) {
+			fprintf(stderr, name_too_long, dz);
+			return FALSE;
+		}
+		strcat(destName, srcBasename);
+	}
+	else if (destDirFlag == TRUE) {
+		fill_baseDest_buf(&destName[0], &destLen);
+	}
+	else {
+		srcBasename = baseSrcName;
+	}
+	if (mv_Action_first_time && (dz_i == is_mv)) {
+		mv_Action_first_time = errno = 0;
+		if (rename(fileName, destName) < 0 && errno != EXDEV) {
+			fprintf(stderr, "%s: rename(%s, %s): %s\n",
+					dz, fileName, destName, strerror(errno));
+			goto do_copyFile;	/* Try anyway... */
+		}
+		else if (errno == EXDEV)
+			goto do_copyFile;
+		else
+			longjmp(catch, 1);	/* succeeded with rename() */
+	}
+ do_copyFile:
+	if (preserveFlag == TRUE && statbuf->st_nlink > 1) {
+		if (is_in_ino_dev_hashtable(statbuf, &name)) {
+			if (link(name, destName) < 0) {
+				fprintf(stderr, "%s: link(%s, %s): %s\n",
+						dz, name, destName, strerror(errno));
+				return FALSE;
+			}
+			return TRUE;
+		}
+		else {
+			add_to_ino_dev_hashtable(statbuf, destName);
+		}
+	}
+	return copyFile(fileName, destName, preserveFlag, followLinks);
+}
+
+static int
+rm_Action(const char *fileName, struct stat *statbuf)
+{
+	int status = TRUE;
+
+	if (S_ISDIR(statbuf->st_mode)) {
+		if (rmdir(fileName) < 0) {
+			fprintf(stderr, "%s: rmdir(%s): %s\n", dz, fileName, strerror(errno));
+			status = FALSE;
+		}
+	} else if (unlink(fileName) < 0) {
+		fprintf(stderr, "%s: unlink(%s): %s\n", dz, fileName, strerror(errno));
+		status = FALSE;
+	}
+	return status;
+}
+
 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;
-	struct stat srcStatBuf;
-
-	char baseDestName[PATH_MAX + 1];
-	size_t baseDestLen;
-	int destDirFlag;
-	struct stat destStatBuf;
-
-	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) {
-		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");
-				return FALSE;
-			}
-			strcat(destName, srcBasename);
-		} else if (destDirFlag == TRUE) {
-			fill_baseDest_buf(&destName[0], &destLen);
-		} else {
-			srcBasename = baseSrcName;
-		}
-		return copyFile(fileName, destName, preserveFlag, followLinks);
-	}
-
-	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++;
+	dz = *argv;					/* already basename'd by busybox.c:main */
 	if (*dz == 'c' && *(dz + 1) == 'p')
 		dz_i = is_cp;
 	else
@@ -199,53 +242,93 @@
 
 	while (argc-- > 1) {
 		size_t srcLen;
-		int flags_memo;
+		volatile int flags_memo;
+		int	   status;
 
 		baseSrcName = *(argv++);
 
 		if ((srcLen = strlen(baseSrcName)) > PATH_MAX)
-			goto name_too_long__exit;
+			name_too_long__exit();
 
-		if (srcLen == 0)
-			continue;
+		if (srcLen == 0) continue; /* "" */
 
 		srcDirFlag = isDirectory(baseSrcName, followLinks, &srcStatBuf);
 
 		if ((flags_memo = (recursiveFlag == TRUE &&
 						   srcDirFlag == TRUE && destDirFlag == TRUE))) {
-				if ((destStatBuf.st_ino == srcStatBuf.st_ino) &&
-					(destStatBuf.st_rdev == srcStatBuf.st_rdev)) {
-						fprintf(stderr,
-								"%s: Cannot %s `%s' into a subdirectory of itself, `%s/%s'\n",
-								dz, dz, baseSrcName, baseDestName, baseSrcName);
-						continue;
+
+			struct stat sb;
+			int			state = 0;
+			char		*pushd, *d, *p;
+
+			if ((pushd = getcwd(NULL, PATH_MAX + 1)) == NULL) {
+				fprintf(stderr, "%s: getcwd(): %s\n", dz, strerror(errno));
+				continue;
+			}
+			if (chdir(baseDestName) < 0) {
+				fprintf(stderr, "%s: chdir(%s): %s\n", dz, baseSrcName, strerror(errno));
+				continue;
+			}
+			if ((d = getcwd(NULL, PATH_MAX + 1)) == NULL) {
+				fprintf(stderr, "%s: getcwd(): %s\n", dz, strerror(errno));
+				continue;
+			}
+			while (!state && *d != '\0') {
+				if (stat(d, &sb) < 0) {	/* stat not lstat - always dereference targets */
+					fprintf(stderr, "%s: stat(%s) :%s\n", dz, d, strerror(errno));
+					state = -1;
+					continue;
 				}
+				if ((sb.st_ino == srcStatBuf.st_ino) &&
+					(sb.st_dev == srcStatBuf.st_dev)) {
+					fprintf(stderr,
+							"%s: Cannot %s `%s' "
+							"into a subdirectory of itself, `%s/%s'\n",
+							dz, dz, baseSrcName, baseDestName, baseSrcName);
+					state = -1;
+					continue;
+				}
+				if ((p = strrchr(d, '/')) != NULL) {
+					*p = '\0';
+				}
+			}
+			if (chdir(pushd) < 0) {
+				fprintf(stderr, "%s: chdir(%s): %s\n", dz, pushd, strerror(errno));
+				free(pushd);
+				free(d);
+				continue;
+			}
+			free(pushd);
+			free(d);
+			if (state < 0)
+				continue;
+			else
 				fill_baseDest_buf(baseDestName, &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;
-
+		status = setjmp(catch);
+		if (status == 0) {
+			mv_Action_first_time = 1;
+			if (recursiveAction(baseSrcName,
+								recursiveFlag, followLinks, FALSE,
+								cp_mv_Action, cp_mv_Action) == FALSE) goto exit_false;
+			if (dz_i == is_mv &&
+				recursiveAction(baseSrcName,
+								recursiveFlag, followLinks, TRUE,
+								rm_Action, rm_Action) == FALSE) goto exit_false;
+		}		
 		if (flags_memo)
 			*(baseDestName + baseDestLen) = '\0';
 	}
-
+// exit_true:
 	exit TRUE;
-
-  name_too_long__exit:
-	fprintf(stderr, name_too_long, "cp");
-  exit_false:
+ exit_false:
 	exit FALSE;
 }
 
-// Local Variables:
-// c-file-style: "linux"
-// tab-width: 4
-// End:
+/*
+Local Variables:
+c-file-style: "linux"
+c-basic-offset: 4
+tab-width: 4
+End:
+*/
diff --git a/df.c b/df.c
index 43d5d26..bc843f7 100644
--- a/df.c
+++ b/df.c
@@ -108,3 +108,11 @@
 
 	exit(TRUE);
 }
+
+/*
+Local Variables:
+c-file-style: "linux"
+c-basic-offset: 4
+tab-width: 4
+End:
+*/
diff --git a/du.c b/du.c
index 4dc7ea1..b6ebaca 100644
--- a/du.c
+++ b/du.c
@@ -36,16 +36,6 @@
 
 typedef void (Display) (long, char *);
 
-typedef struct inode_type {
-	struct inode_type *next;
-	ino_t ino;
-} INODETYPE;
-
-#define HASH_SIZE	311		/* Should be prime */
-#define hash_inode(i)	((i) % HASH_SIZE)
-
-static INODETYPE *inode_hash_list[HASH_SIZE];
-
 static const char du_usage[] =
 	"du [OPTION]... [FILE]...\n\n"
 	"Summarize disk space used for each FILE and/or directory.\n"
@@ -71,52 +61,6 @@
 	}
 }
 
-/* Return 1 if inode is in inode hash list, else return 0 */
-static int is_in_list(const ino_t ino)
-{
-	INODETYPE *inode;
-
-	inode = inode_hash_list[hash_inode(ino)];
-	while (inode != NULL) {
-		if (inode->ino == ino)
-			return 1;
-		inode = inode->next;
-	}
-
-	return 0;
-}
-
-/* Add inode to inode hash list */
-static void add_inode(const ino_t ino)
-{
-	int i;
-	INODETYPE *inode;
-    
-	i = hash_inode(ino);
-	inode = malloc(sizeof(INODETYPE));
-	if (inode == NULL)
-		fatalError("du: Not enough memory.");
-
-	inode->ino = ino;
-	inode->next = inode_hash_list[i];
-	inode_hash_list[i] = inode;
-}
-
-/* Clear inode hash list */
-static void reset_inode_list(void)
-{
-	int i;
-	INODETYPE *inode;
-
-	for (i = 0; i < HASH_SIZE; i++) {
-		while (inode_hash_list[i] != NULL) {
-			inode = inode_hash_list[i]->next;
-			free(inode_hash_list[i]);
-			inode_hash_list[i] = inode;
-		}
-	}
-}
-
 /* tiny recursive du */
 static long du(char *filename)
 {
@@ -175,13 +119,13 @@
 	}
 	else if (statbuf.st_nlink > 1 && !count_hardlinks) {
 		/* Add files with hard links only once */
-		if (is_in_list(statbuf.st_ino)) {
+		if (is_in_ino_dev_hashtable(&statbuf, NULL)) {
 			sum = 0L;
 			if (du_depth == 1)
 				print(sum, filename);
 		}
 		else {
-			add_inode(statbuf.st_ino);
+			add_to_ino_dev_hashtable(&statbuf, NULL);
 		}
 	}
 	du_depth--;
@@ -231,11 +175,18 @@
 			if (sum && isDirectory(argv[i], FALSE, NULL)) {
 				print_normal(sum, argv[i]);
 			}
-			reset_inode_list();
+			reset_ino_dev_hashtable();
 		}
 	}
 
 	exit(0);
 }
 
-/* $Id: du.c,v 1.15 2000/02/21 17:27:17 erik Exp $ */
+/* $Id: du.c,v 1.16 2000/03/04 21:19:32 erik Exp $ */
+/*
+Local Variables:
+c-file-style: "linux"
+c-basic-offset: 4
+tab-width: 4
+End:
+*/
diff --git a/init.c b/init.c
index 1837391..350ea62 100644
--- a/init.c
+++ b/init.c
@@ -242,6 +242,7 @@
 	int fd;
 	int tried_devcons = 0;
 	int tried_vtprimary = 0;
+	struct vt_stat vt;
 	struct serial_struct sr;
 	char *s;
 
@@ -264,8 +265,6 @@
 	}
 #endif
 	else {
-		struct vt_stat vt;
-
 		/* 2.2 kernels: identify the real console backend and try to use it */
 		if (ioctl(0, TIOCGSERIAL, &sr) == 0) {
 			/* this is a serial console */
@@ -951,3 +950,11 @@
 		sleep(1);
 	}
 }
+
+/*
+Local Variables:
+c-file-style: "linux"
+c-basic-offset: 4
+tab-width: 4
+End:
+*/
diff --git a/init/init.c b/init/init.c
index 1837391..350ea62 100644
--- a/init/init.c
+++ b/init/init.c
@@ -242,6 +242,7 @@
 	int fd;
 	int tried_devcons = 0;
 	int tried_vtprimary = 0;
+	struct vt_stat vt;
 	struct serial_struct sr;
 	char *s;
 
@@ -264,8 +265,6 @@
 	}
 #endif
 	else {
-		struct vt_stat vt;
-
 		/* 2.2 kernels: identify the real console backend and try to use it */
 		if (ioctl(0, TIOCGSERIAL, &sr) == 0) {
 			/* this is a serial console */
@@ -951,3 +950,11 @@
 		sleep(1);
 	}
 }
+
+/*
+Local Variables:
+c-file-style: "linux"
+c-basic-offset: 4
+tab-width: 4
+End:
+*/
diff --git a/init/reboot.c b/init/reboot.c
index ef2a848..f782fa1 100644
--- a/init/reboot.c
+++ b/init/reboot.c
@@ -29,3 +29,11 @@
 	/* don't assume init's pid == 1 */
 	exit(kill(findInitPid(), SIGINT));
 }
+
+/*
+Local Variables:
+c-file-style: "linux"
+c-basic-offset: 4
+tab-width: 4
+End:
+*/
diff --git a/internal.h b/internal.h
index 4d035c9..4c7bd97 100644
--- a/internal.h
+++ b/internal.h
@@ -154,6 +154,17 @@
 const char *timeString(time_t timeVal);
 int isDirectory(const char *name, const int followLinks, struct stat *statBuf);
 int isDevice(const char *name);
+
+typedef struct ino_dev_hash_bucket_struct {
+  struct ino_dev_hash_bucket_struct *next;
+  ino_t ino;
+  dev_t dev;
+  char name[1];
+} ino_dev_hashtable_bucket_t;
+int is_in_ino_dev_hashtable(const struct stat *statbuf, char **name);
+void add_to_ino_dev_hashtable(const struct stat *statbuf, const char *name);
+void reset_ino_dev_hashtable(void);
+
 int copyFile(const char *srcName, const char *destName, int setModes,
 	        int followLinks);
 char *buildName(const char *dirName, const char *fileName);
diff --git a/ln.c b/ln.c
index 0715bfa..c54026c 100644
--- a/ln.c
+++ b/ln.c
@@ -128,3 +128,11 @@
 	}
 	exit TRUE;
 }
+
+/*
+Local Variables:
+c-file-style: "linux"
+c-basic-offset: 4
+tab-width: 4
+End:
+*/
diff --git a/miscutils/update.c b/miscutils/update.c
index fef188b..bb77c5f 100644
--- a/miscutils/update.c
+++ b/miscutils/update.c
@@ -1,9 +1,11 @@
 /* vi: set sw=4 ts=4: */
 /*
- * Mini update implementation for busybox
+ * Mini update implementation for busybox; much pasted from update-2.11
  *
  *
  * Copyright (C) 1995, 1996 by Bruce Perens <bruce@pixar.com>.
+ * Copyright (c) 1996, 1997, 1999 Torsten Poulin.
+ * Copyright (c) 2000 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
@@ -23,6 +25,8 @@
 
 #include "internal.h"
 #include <linux/unistd.h>
+#include <sys/param.h>
+#include <sys/syslog.h>
 
 #if defined(__GLIBC__)
 #include <sys/kdaemon.h>
@@ -30,37 +34,79 @@
 _syscall2(int, bdflush, int, func, int, data);
 #endif							/* __GLIBC__ */
 
+static char update_usage[] =
+	"update [options]\n"
+	"  -S\tforce use of sync(2) instead of flushing\n"
+	"  -s SECS\tcall sync this often (default 30)\n"
+	"  -f SECS\tflush some buffers this often (default 5)\n";
+
+static unsigned int sync_duration = 30;
+static unsigned int flush_duration = 5;
+static int use_sync = 0;
+
 extern int update_main(int argc, char **argv)
 {
-	/*
-	 * Update is actually two daemons, bdflush and update.
-	 */
 	int pid;
 
+	while (**argv == '-') {
+		while (*++(*argv)) {
+			switch (**argv) {
+			case 'S':
+				use_sync = 1;
+				break;
+			case 's':
+				if (--argc < 1) usage(update_usage);
+				sync_duration = atoi(*(++argv));
+				break;
+			case 'f':
+				if (--argc < 1) usage(update_usage);
+				flush_duration = atoi(*(++argv));
+				break;
+			}
+		}
+		argc--;
+		argv++;
+	}
+
 	pid = fork();
 	if (pid < 0)
-		return pid;
+		exit(FALSE);
 	else if (pid == 0) {
+		/* Become a proper daemon */
+		setsid();
+		chdir("/");
+		for (pid = 0; pid < OPEN_MAX; pid++) close(pid);
+
 		/*
 		 * This is no longer necessary since 1.3.5x, but it will harmlessly
 		 * exit if that is the case.
 		 */
-		strcpy(argv[0], "bdflush (update)");
-		argv[1] = 0;
-		argv[2] = 0;
-		bdflush(1, 0);
-		_exit(0);
-	}
-	pid = fork();
-	if (pid < 0)
-		return pid;
-	else if (pid == 0) {
-		argv[0] = "update";
+		argv[0] = "bdflush (update)";
+		argv[1] = NULL;
+		argv[2] = NULL;
 		for (;;) {
-			sync();
-			sleep(30);
+			if (use_sync) {
+				sleep(sync_duration);
+				sync();
+			} else {
+				sleep(flush_duration);
+				if (bdflush(1, 0) < 0) {
+					openlog("update", LOG_CONS, LOG_DAEMON);
+					syslog(LOG_INFO,
+						   "This kernel does not need update(8). Exiting.");
+					closelog();
+					exit(TRUE);
+				}
+			}
 		}
 	}
-
-	return 0;
+	return TRUE;
 }
+
+/*
+Local Variables:
+c-file-style: "linux"
+c-basic-offset: 4
+tab-width: 4
+End:
+*/
diff --git a/reboot.c b/reboot.c
index ef2a848..f782fa1 100644
--- a/reboot.c
+++ b/reboot.c
@@ -29,3 +29,11 @@
 	/* don't assume init's pid == 1 */
 	exit(kill(findInitPid(), SIGINT));
 }
+
+/*
+Local Variables:
+c-file-style: "linux"
+c-basic-offset: 4
+tab-width: 4
+End:
+*/
diff --git a/sort.c b/sort.c
index 609c5e0..e6894f6 100644
--- a/sort.c
+++ b/sort.c
@@ -29,7 +29,18 @@
 #include <stdio.h>
 #include <errno.h>
 
-static const char sort_usage[] = "sort [OPTION]... [FILE]...\n\n";
+static const char sort_usage[] = "sort [-n]"
+#ifdef BB_FEATURE_SORT_REVERSE
+" [-r]"
+#endif
+" [FILE]...\n\n";
+
+#ifdef BB_FEATURE_SORT_REVERSE
+#define APPLY_REVERSE(x) (reverse ? -(x) : (x))
+static int reverse = 0;
+#else
+#define APPLY_REVERSE(x) (x)
+#endif
 
 /* typedefs _______________________________________________________________ */
 
@@ -120,7 +131,7 @@
 	y = *doh;
 
 	// fprintf(stdout, "> %p: %s< %p: %s", x, x->data, y, y->data);
-	return strcmp(x->data, y->data);
+	return APPLY_REVERSE(strcmp(x->data, y->data));
 }
 
 /* numeric order */
@@ -138,7 +149,7 @@
 	xint = strtoul(x->data, NULL, 10);
 	yint = strtoul(y->data, NULL, 10);
 
-	return (xint - yint);
+	return APPLY_REVERSE(xint - yint);
 }
 
 
@@ -254,20 +265,19 @@
 		if (argv[i][0] == '-') {
 			opt = argv[i][1];
 			switch (opt) {
-			case 'g':
-				/* what's the diff between -g && -n? */
-				compare = compare_numeric;
-				break;
 			case 'h':
 				usage(sort_usage);
 				break;
 			case 'n':
-				/* what's the diff between -g && -n? */
+				/* numeric comparison */
 				compare = compare_numeric;
 				break;
+#ifdef BB_FEATURE_SORT_REVERSE
 			case 'r':
 				/* reverse */
+				reverse = 1;
 				break;
+#endif
 			default:
 				fprintf(stderr, "sort: invalid option -- %c\n", opt);
 				usage(sort_usage);
@@ -310,4 +320,4 @@
 	exit(0);
 }
 
-/* $Id: sort.c,v 1.11 2000/02/08 19:58:47 erik Exp $ */
+/* $Id: sort.c,v 1.12 2000/03/04 21:19:32 erik Exp $ */
diff --git a/tests/Makefile b/tests/Makefile
index 0156344..c4fb0e9 100644
--- a/tests/Makefile
+++ b/tests/Makefile
@@ -1,16 +1,21 @@
-all test_all: message_header cp_tests mv_tests ln_tests
+# busybox/tests/Makefile - Run through all defined tests.
+# ------------------------
+# Copyright (C) 2000  Karl M. Hegbloom <karlheg@debian.org>  GPL
 
-clean: cp_clean mv_clean ln_clean
+all:: message_header
 
 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 BusyBox Test Suite.
 	@echo
 
-include cp_tests.mk
-include mv_tests.mk
-include ln_tests.mk
+clean::
+
+distclean: clean
+
+.PHONY: all clean distclean message_header
+
+include $(wildcard *_tests.mk)
 
 BBL := $(shell pushd .. >/dev/null &&		\
 	         ${MAKE} busybox.links >/dev/null && \
@@ -21,8 +26,6 @@
 ../busybox:
 	cd .. && ${MAKE} busybox
 
-$(BBL): ../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
index e14262a..e79f2b3 100644
--- a/tests/cp_tests.mk
+++ b/tests/cp_tests.mk
@@ -1,18 +1,23 @@
-# This is a -*- makefile -*-
+# cp_tests.mk - Set of test cases for busybox cp
+# -------------
+# Copyright (C) 2000 Karl M. Hegbloom <karlheg@debian.org> GPL
+#
 
 # GNU `cp'
 GCP = /bin/cp
 # BusyBox `cp'
 BCP = $(shell pwd)/cp
 
-.PHONY: cp_clean
-cp_clean:
-	rm -rf cp_tests cp_*.{gnu,bb} cp
+all:: cp_tests
+clean:: cp_clean
 
-.PHONY: cp_tests
+cp_clean:
+	- rm -rf cp_tests cp_*.{gnu,bb} cp
+
 cp_tests: cp_clean cp
 	@echo;
 	@echo "No output from diff means busybox cp is functioning properly.";
+	@echo "Some tests might show timestamp differences that are Ok.";
 
 	@echo;
 	${BCP} || true;
@@ -20,7 +25,8 @@
 	@echo;
 	mkdir cp_tests;
 
-	@echo;
+	# Copy a file to a copy of the file
+	@echo ------------------------------;
 	cd cp_tests;				\
 	 echo A file > afile;			\
 	 ls -l afile > ../cp_afile_afilecopy.gnu; \
@@ -28,7 +34,7 @@
 	 ls -l afile afilecopy >> ../cp_afile_afilecopy.gnu;
 
 	@echo;
-	rm -f cp_tests/afile*;
+	rm -rf cp_tests/*;
 
 	@echo;
 	cd cp_tests;				\
@@ -38,118 +44,135 @@
 	 ls -l afile afilecopy >> ../cp_afile_afilecopy.bb;
 
 	@echo;
-	diff -u cp_afile_afilecopy.gnu cp_afile_afilecopy.bb;
+	@echo Might show timestamp differences.
+	-diff -u cp_afile_afilecopy.gnu cp_afile_afilecopy.bb;
 
 	@echo;
-	rm -f cp_tests/afile*;
+	rm -rf cp_tests/*;
 
-	@echo; echo;
+	# Copy a file pointed to by a symlink
+	@echo; echo ------------------------------;
 	cd cp_tests;				\
-	 mkdir there there1;			\
-	 cd there;				\
-	  ln -s ../afile .;
+	 mkdir here there;			\
+	 echo A file > afile;			\
+	 cd here;				\
+	  ln -s ../afile .;			\
+
+	@echo;
+	cd cp_tests;				\
+	 ls -lR . > ../cp_symlink.gnu;		\
+	 ${GCP} here/afile there;		\
+	 ls -lR . >> ../cp_symlink.gnu;
+
+	@echo;
+	rm -rf cp_tests/there/*;
+
+	sleep 1;
+
+	@echo;
+	cd cp_tests;				\
+	 ls -lR . > ../cp_symlink.bb;		\
+	 ${BCP} here/afile there;		\
+	 ls -lR . >> ../cp_symlink.bb;
+
+	@echo;
+	@echo Will show timestamp difference.
+	-diff -u cp_symlink.gnu cp_symlink.bb;
+
+	@echo;
+	rm -rf cp_tests/*
+
+	# Copy a symlink, useing the -a switch.
+	@echo; echo ------------------------------;
+	cd cp_tests;				\
+	 echo A file > afile;			\
+	 mkdir here there;			\
+	 cd here;				\
+	  ln -s ../afile .
+
+	cd cp_test;				\
+	 ls -lR . > ../cp_a_symlink.gnu;	\
+	 ${GCP} -a here/afile there;		\
+	 ls -lR . >> ../cp_a_symlink.gnu;
+
+	@echo;
+	rm -f cp_tests/there/*;
+
+	sleep 1;
 
 	@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;
+	 ls -lR . > ../cp_a_symlink.bb;		\
+	 ${BCP} -a here/afile there;		\
+	 ls -lR . >> ../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};
+	rm -f cp_tests/*;
 
-	@echo; echo;
+	# Copy a directory into another directory with the -a switch
+	@echo; echo ------------------------------;
 	cd cp_tests;				\
-	 echo A file > there/afile;		\
-	 mkdir there/adir;			\
-	 touch there/adir/afileinadir;		\
-	 ln -s $(shell pwd) there/alink;
+	 mkdir here there;			\
+	 echo A file > here/afile;		\
+	 mkdir here/adir;			\
+	 touch here/adir/afileinadir;		\
+	 ln -s $$(pwd) here/alink;
 
 	@echo;
 	cd cp_tests;				\
-	 ${GCP} -a there/ there1/;		\
-	 ls -lR there/ there1/ > ../cp_a_dir_dir.gnu;
+	 ls -lR . > ../cp_a_dir_dir.gnu;	\
+	 ${GCP} -a here/ there/;		\
+	 ls -lR . >> ../cp_a_dir_dir.gnu;
 
 	@echo;
-	rm -rf cp_tests/there1;
+	rm -rf cp_tests/there/*;
+
+	sleep 1;
 
 	@echo;
 	cd cp_tests;				\
-	 ${BCP} -a there/ there1/;		\
-	 ls -lR there/ there1/ > ../cp_a_dir_dir.bb;
+	 ls -lR . > ../cp_a_dir_dir.bb;		\
+	 ${BCP} -a here/ there/;		\
+	 ls -lR . >> ../cp_a_dir_dir.bb;
 
 	@echo;
 	diff -u cp_a_dir_dir.gnu cp_a_dir_dir.bb;
 
 	@echo;
-	rm -rf cp_tests/there1/;
+	rm -rf cp_tests/*;
 
-	@echo; echo;
+	# Copy a set of files to a directory.
+	@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/;	\
+	 mkdir there;
+
+	cd cp_tests;				\
+	 ${GCP} afile1 afile2 symlink1 there/;	\
 	 ls -lR > ../cp_files_dir.gnu;
 
 	@echo;
-	rm -rf cp_tests/{afile{1,2},symlink1,there1};
+	rm -rf cp_tests/there/*;
 
 	@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/;	\
+	 ${BCP} afile1 afile2 symlink1 there/;	\
 	 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};
+	rm -rf cp_tests/*;
 
-	@echo; echo;
+	# Copy a set of files to a directory with the -d switch.
+	@echo; echo ------------------------------;
 	cd cp_tests;				\
 	 echo A file number one > afile1;	\
 	 echo A file number two, blah. > afile2; \
@@ -176,7 +199,8 @@
 	@echo;
 	rm -rf cp_tests/{afile{1,2},symlink1,there1};
 
-	@echo; echo;
+	# Copy a set of files to a directory with the -p switch.
+	@echo; echo ------------------------------;
 	cd cp_tests;				\
 	 echo A file number one > afile1;	\
 	 echo A file number two, blah. > afile2; \
@@ -205,7 +229,8 @@
 	@echo;
 	rm -rf cp_tests/{afile{1,2},symlink1,there1};
 
-	@echo; echo;
+	# Copy a set of files to a directory with -p and -d switches.
+	@echo; echo ------------------------------;
 	cd cp_tests;				\
 	 echo A file number one > afile1;	\
 	 echo A file number two, blah. > afile2; \
@@ -234,7 +259,8 @@
 	@echo;
 	rm -rf cp_tests/{afile{1,2},symlink1,there1};
 
-	@echo; echo;
+	# Copy a directory into another directory with the -a switch.
+	@echo; echo ------------------------------;
 	cd cp_tests;				\
 	 mkdir dir{a,b};			\
 	 echo A file > dira/afile;		\
@@ -246,7 +272,6 @@
 	 ${GCP} -a dira dirb;			\
 	 ls -lR . >> ../cp_a_dira_dirb.gnu;
 
-	# false;
 	@echo;
 	rm -rf cp_tests/dir{a,b};
 
@@ -265,6 +290,31 @@
 	@echo;
 	diff -u cp_a_dira_dirb.gnu cp_a_dira_dirb.bb;
 
-	# false;
 	@echo;
 	rm -rf cp_tests/dir{a,b};
+
+	# Copy a directory to another directory, without the -a switch.
+	@echo; echo ------------------------------;
+	@echo There should be an error message about cannot cp a dir to a subdir of itself.
+	cd cp_tests;				\
+	 touch a b c;				\
+	 mkdir adir;				\
+	 ls -lR . > ../cp_a_star_adir.gnu;	\
+	 ${GCP} -a * adir;			\
+	 ls -lR . >> ../cp_a_star_adir.gnu;
+
+	@echo
+	@echo There should be an error message about cannot cp a dir to a subdir of itself.
+	cd cp_tests;				\
+	 rm -rf adir;				\
+	 mkdir adir;				\
+	 ls -lR . > ../cp_a_star_adir.bb;	\
+	 ${BCP} -a * adir;			\
+	 ls -lR . >> ../cp_a_star_adir.bb;
+
+	@echo;
+	diff -u cp_a_star_adir.gnu cp_a_star_adir.bb;
+
+	@echo;
+	rm -rf cp_tests;
+	@echo; echo Done.
diff --git a/tests/ln_tests.mk b/tests/ln_tests.mk
index 5925edd..3110f81 100644
--- a/tests/ln_tests.mk
+++ b/tests/ln_tests.mk
@@ -1,14 +1,19 @@
+# ln_tests.mk - Set of tests for busybox ln
+# -------------
+# Copyright (C) 2000 Karl M. Hegbloom <karlheg@debian.org> GPL
+#
 
 # GNU `ln'
 GLN = /bin/ln
 # BusyBox `ln'
 BLN = $(shell pwd)/ln
 
-.PHONY: ln_clean
+all:: ln_tests
+clean:: 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.";
diff --git a/tests/mv_tests.mk b/tests/mv_tests.mk
index 3a90125..81b8ffd 100644
--- a/tests/mv_tests.mk
+++ b/tests/mv_tests.mk
@@ -1,14 +1,19 @@
+# mv_tests.mk - Set of tests cases for busybox mv
+# -------------
+# Copyright (C) 2000 Karl M. Hegbloom <karlheg@debian.org> GPL
+#
 
 # GNU `mv'
 GMV = /bin/mv
 # BusyBox `mv'
 BMV = $(shell pwd)/mv
 
-.PHONY: mv_clean
+all:: mv_tests
+clean:: 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.";
@@ -45,7 +50,7 @@
 	@echo;
 	rm -f mv_tests/{afile,newname};
 
-	@echo; echo;
+	@echo; echo ------------------------------;
 	cd mv_tests;				\
 	 echo A file > afile;			\
 	 ln -s afile symlink;			\
@@ -72,7 +77,7 @@
 	@echo;
 	rm -rf mv_tests/*;
 
-	@echo; echo;
+	@echo; echo ------------------------------;
 	cd mv_tests;				\
 	 echo A file > afile;			\
 	 ln -s afile symlink;			\
@@ -85,7 +90,7 @@
 	@echo;
 	rm -rf mv_tests/*
 
-	@echo; echo;
+	@echo; echo ------------------------------;
 	cd mv_tests;				\
 	 echo A file > afile;			\
 	 ln -s afile symlink;			\
@@ -101,7 +106,7 @@
 	@echo;
 	rm -rf mv_tests/*;
 
-	@echo; echo;
+	@echo; echo ------------------------------;
 	cd mv_tests;				\
 	 mkdir dir{a,b};			\
 	 echo A file > dira/afile;		\
@@ -135,3 +140,27 @@
 	# false;
 	@echo;
 	rm -rf mv_tests/dir{a,b};
+
+	@echo; echo ------------------------------;
+	@echo There should be an error message about cannot mv a dir to a subdir of itself.
+	cd mv_tests;				\
+	 touch a b c;				\
+	 mkdir adir;				\
+	 ls -lR . > ../mv_a_star_adir.gnu;	\
+	 ${GMV} * adir;				\
+	 ls -lR . >> ../mv_a_star_adir.gnu;
+
+	@echo
+	@echo There should be an error message about cannot mv a dir to a subdir of itself.
+	cd mv_tests;				\
+	 rm -rf adir;				\
+	 mkdir adir;				\
+	 ls -lR . > ../mv_a_star_adir.bb;	\
+	 ${BMV} * adir;			\
+	 ls -lR . >> ../mv_a_star_adir.bb;
+
+	@echo;
+	diff -u mv_a_star_adir.gnu mv_a_star_adir.bb;
+
+	@echo;
+	rm -rf mv_test/*;
diff --git a/update.c b/update.c
index fef188b..bb77c5f 100644
--- a/update.c
+++ b/update.c
@@ -1,9 +1,11 @@
 /* vi: set sw=4 ts=4: */
 /*
- * Mini update implementation for busybox
+ * Mini update implementation for busybox; much pasted from update-2.11
  *
  *
  * Copyright (C) 1995, 1996 by Bruce Perens <bruce@pixar.com>.
+ * Copyright (c) 1996, 1997, 1999 Torsten Poulin.
+ * Copyright (c) 2000 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
@@ -23,6 +25,8 @@
 
 #include "internal.h"
 #include <linux/unistd.h>
+#include <sys/param.h>
+#include <sys/syslog.h>
 
 #if defined(__GLIBC__)
 #include <sys/kdaemon.h>
@@ -30,37 +34,79 @@
 _syscall2(int, bdflush, int, func, int, data);
 #endif							/* __GLIBC__ */
 
+static char update_usage[] =
+	"update [options]\n"
+	"  -S\tforce use of sync(2) instead of flushing\n"
+	"  -s SECS\tcall sync this often (default 30)\n"
+	"  -f SECS\tflush some buffers this often (default 5)\n";
+
+static unsigned int sync_duration = 30;
+static unsigned int flush_duration = 5;
+static int use_sync = 0;
+
 extern int update_main(int argc, char **argv)
 {
-	/*
-	 * Update is actually two daemons, bdflush and update.
-	 */
 	int pid;
 
+	while (**argv == '-') {
+		while (*++(*argv)) {
+			switch (**argv) {
+			case 'S':
+				use_sync = 1;
+				break;
+			case 's':
+				if (--argc < 1) usage(update_usage);
+				sync_duration = atoi(*(++argv));
+				break;
+			case 'f':
+				if (--argc < 1) usage(update_usage);
+				flush_duration = atoi(*(++argv));
+				break;
+			}
+		}
+		argc--;
+		argv++;
+	}
+
 	pid = fork();
 	if (pid < 0)
-		return pid;
+		exit(FALSE);
 	else if (pid == 0) {
+		/* Become a proper daemon */
+		setsid();
+		chdir("/");
+		for (pid = 0; pid < OPEN_MAX; pid++) close(pid);
+
 		/*
 		 * This is no longer necessary since 1.3.5x, but it will harmlessly
 		 * exit if that is the case.
 		 */
-		strcpy(argv[0], "bdflush (update)");
-		argv[1] = 0;
-		argv[2] = 0;
-		bdflush(1, 0);
-		_exit(0);
-	}
-	pid = fork();
-	if (pid < 0)
-		return pid;
-	else if (pid == 0) {
-		argv[0] = "update";
+		argv[0] = "bdflush (update)";
+		argv[1] = NULL;
+		argv[2] = NULL;
 		for (;;) {
-			sync();
-			sleep(30);
+			if (use_sync) {
+				sleep(sync_duration);
+				sync();
+			} else {
+				sleep(flush_duration);
+				if (bdflush(1, 0) < 0) {
+					openlog("update", LOG_CONS, LOG_DAEMON);
+					syslog(LOG_INFO,
+						   "This kernel does not need update(8). Exiting.");
+					closelog();
+					exit(TRUE);
+				}
+			}
 		}
 	}
-
-	return 0;
+	return TRUE;
 }
+
+/*
+Local Variables:
+c-file-style: "linux"
+c-basic-offset: 4
+tab-width: 4
+End:
+*/
diff --git a/utility.c b/utility.c
index 0279cca..c8ce392 100644
--- a/utility.c
+++ b/utility.c
@@ -122,7 +122,76 @@
 }
 #endif							/* BB_INIT || BB_PS */
 
+#if defined (BB_CP_MV) || defined (BB_DU)
 
+#define HASH_SIZE	311		/* Should be prime */
+#define hash_inode(i)	((i) % HASH_SIZE)
+
+static ino_dev_hashtable_bucket_t *ino_dev_hashtable[HASH_SIZE];
+
+/*
+ * Return 1 if statbuf->st_ino && statbuf->st_dev are recorded in
+ * `ino_dev_hashtable', else return 0
+ *
+ * If NAME is a non-NULL pointer to a character pointer, and there is
+ * a match, then set *NAME to the value of the name slot in that
+ * bucket.
+ */
+int is_in_ino_dev_hashtable(const struct stat *statbuf, char **name)
+{
+	ino_dev_hashtable_bucket_t *bucket;
+
+	bucket = ino_dev_hashtable[hash_inode(statbuf->st_ino)];
+	while (bucket != NULL) {
+	  if ((bucket->ino == statbuf->st_ino) &&
+		  (bucket->dev == statbuf->st_dev))
+	  {
+		if (name) *name = bucket->name;
+		return 1;
+	  }
+	  bucket = bucket->next;
+	}
+	return 0;
+}
+
+/* Add statbuf to statbuf hash table */
+void add_to_ino_dev_hashtable(const struct stat *statbuf, const char *name)
+{
+	int i;
+	size_t s;
+	ino_dev_hashtable_bucket_t *bucket;
+    
+	i = hash_inode(statbuf->st_ino);
+	s = name ? strlen(name) : 0;
+	bucket = malloc(sizeof(ino_dev_hashtable_bucket_t) + s);
+	if (bucket == NULL)
+		fatalError("Not enough memory.");
+	bucket->ino = statbuf->st_ino;
+	bucket->dev = statbuf->st_dev;
+	if (name)
+		strcpy(bucket->name, name);
+	else
+		bucket->name[0] = '\0';
+	bucket->next = ino_dev_hashtable[i];
+	ino_dev_hashtable[i] = bucket;
+}
+
+/* Clear statbuf hash table */
+void reset_ino_dev_hashtable(void)
+{
+	int i;
+	ino_dev_hashtable_bucket_t *bucket;
+
+	for (i = 0; i < HASH_SIZE; i++) {
+		while (ino_dev_hashtable[i] != NULL) {
+			bucket = ino_dev_hashtable[i]->next;
+			free(ino_dev_hashtable[i]);
+			ino_dev_hashtable[i] = bucket;
+		}
+	}
+}
+
+#endif /* BB_CP_MV || BB_DU */
 
 #if defined (BB_CP_MV) || defined (BB_DU) || defined (BB_LN)
 /*
@@ -161,7 +230,7 @@
 /*
  * Copy one file to another, while possibly preserving its modes, times,
  * and modes.  Returns TRUE if successful, or FALSE on a failure with an
- * error message output.  (Failure is not indicted if the attributes cannot
+ * error message output.  (Failure is not indicated if the attributes cannot
  * be set.)
  *  -Erik Andersen
  */
@@ -1335,6 +1404,11 @@
 }
 #endif
 
-
-
 /* END CODE */
+/*
+Local Variables:
+c-file-style: "linux"
+c-basic-offset: 4
+tab-width: 4
+End:
+*/