[BusyBox] PATCH: cp /dev/null some_file

Anthony Shipman als at labyrinth.net.au
Thu May 27 08:21:55 UTC 2004


Below is a bug fix for the common idiom
	cp /dev/null some_file
to create an empty file.

--- orig/busybox/busybox-1.00-pre10/coreutils/mv.c
+++ mod/busybox/busybox-1.00-pre10/coreutils/mv.c
@@ -121,7 +121,7 @@
 					}
 				}
 				if ((copy_file(*argv, dest,
-					FILEUTILS_RECUR | FILEUTILS_PRESERVE_STATUS) >= 0) &&
+					FILEUTILS_RECUR | FILEUTILS_PRESERVE_STATUS | FILEUTILS_MOVE) >= 0) &&
 					(remove_file(*argv, FILEUTILS_RECUR | FILEUTILS_FORCE) >= 0)) {
 					goto RET_0;
 				}
--- orig/busybox/busybox-1.00-pre10/include/libbb.h
+++ mod/busybox/busybox-1.00-pre10/include/libbb.h
@@ -318,7 +318,8 @@
 	FILEUTILS_DEREFERENCE = 2,
 	FILEUTILS_RECUR = 4,
 	FILEUTILS_FORCE = 8,
-	FILEUTILS_INTERACTIVE = 16
+	FILEUTILS_INTERACTIVE = 16,
+	FILEUTILS_MOVE = 0x40000000
 };
 
 extern const char *bb_applet_name;
--- orig/busybox/busybox-1.00-pre10/libbb/copy_file.c
+++ mod/busybox/busybox-1.00-pre10/libbb/copy_file.c
@@ -32,12 +32,17 @@
 
 #include "busybox.h"
 
+static int  must_read(const struct stat* src_stat, int flags);
+
+
+
 int copy_file(const char *source, const char *dest, int flags)
 {
 	struct stat source_stat;
 	struct stat dest_stat;
 	int dest_exists = 0;
 	int status = 0;
+	int force_read = 0;
 
 	if ((!(flags & FILEUTILS_DEREFERENCE) &&
 			lstat(source, &source_stat) < 0) ||
@@ -61,6 +66,9 @@
 		dest_exists = 1;
 	}
 
+	/*  Test for special treatment for some device files. */
+	force_read = must_read(&source_stat, flags);
+
 	if (S_ISDIR(source_stat.st_mode)) {
 		DIR *dp;
 		struct dirent *d;
@@ -122,7 +130,7 @@
 			bb_perror_msg("unable to change permissions of `%s'", dest);
 			status = -1;
 		}
-	} else if (S_ISREG(source_stat.st_mode)) {
+	} else if (S_ISREG(source_stat.st_mode) || force_read) {
 		int src_fd;
 		int dst_fd;
 #ifdef CONFIG_FEATURE_PRESERVE_HARDLINKS
@@ -209,9 +217,11 @@
 		}
 	if (S_ISBLK(source_stat.st_mode) || S_ISCHR(source_stat.st_mode) ||
 	    S_ISSOCK(source_stat.st_mode)) {
-		if (mknod(dest, source_stat.st_mode, source_stat.st_rdev) < 0) {
-			bb_perror_msg("unable to create `%s'", dest);
-			return -1;
+		if (!force_read) {
+			if (mknod(dest, source_stat.st_mode, source_stat.st_rdev) < 0) {
+				bb_perror_msg("unable to create `%s'", dest);
+				return -1;
+			}
 		}
 	} else if (S_ISFIFO(source_stat.st_mode)) {
 		if (mkfifo(dest, source_stat.st_mode) < 0) {
@@ -264,3 +274,52 @@
 
 	return status;
 }
+
+
+
+static int
+must_read(const struct stat* src_stat, int flags)
+{
+    /*	Test if the file is a /dev file that should be read rather
+		then recreated. For example we want
+			cp /dev/null xyz
+		to create an empty file not try to make a device node called
+		'xyz'.
+		
+		On the other hand an attempt at
+			mv /dev/null xyz
+		should attempt to create a device node if the mv command 
+		decides to copy after a rename fails (even if this is a
+		dumb thing to do). FILEUTILS_MOVE indicates this case.
+
+		At the moment only /dev/null is treated specially. Note
+		that we want to recognise the file in the case of a command
+		like
+			cd /dev; cp null xyz
+		Also we want to recognise copies of the file in e.g. chroot
+		environments. So we have to compare device numbers.
+
+		If we are recursively copying the /dev directory then
+		we should be attempting to make a device node in the
+		destination. But there is no reliable way to detect
+		this case.
+
+		This returns true if the file should be treated as data 
+		rather than a device node.
+    */
+	struct stat		null;
+
+	if (flags & FILEUTILS_MOVE)
+		return 0;
+
+	if (S_ISCHR(src_stat->st_mode)) {
+		/*	It's a char device node. Compare it with /dev/null.
+		*/
+		if (stat("/dev/null", &null) >= 0) {
+			if (S_ISCHR(null.st_mode) && src_stat->st_rdev == null.st_rdev)
+				return 1;
+		}
+	}
+
+	return 0;
+}


-- 
Anthony Shipman                    Elektrichore - The muse of 
als at labyrinth.net.au                          high technology.




More information about the busybox mailing list