changeset 3068:ecbf62d1a7f7

6479906 *rm* source can be worked on to improve code readability
author sn199410
date Mon, 06 Nov 2006 11:04:37 -0800
parents 4cca2cfcfad0
children 7e4a1e78c5bf
files usr/src/cmd/rm/rm.c
diffstat 1 files changed, 48 insertions(+), 85 deletions(-) [+]
line wrap: on
line diff
--- a/usr/src/cmd/rm/rm.c	Mon Nov 06 01:13:39 2006 -0800
+++ b/usr/src/cmd/rm/rm.c	Mon Nov 06 11:04:37 2006 -0800
@@ -64,8 +64,8 @@
 static	int	errcode;
 static	int interactive, recursive, silent; /* flags for command line options */
 
-static	void	rm(char *, int);
-static	void	undir(char *, int, dev_t, ino_t);
+static	int	rm(char *, int);
+static	int	undir(char *, int, dev_t, ino_t);
 static	int	yes(void);
 static	int	mypath(dev_t, ino_t);
 
@@ -76,7 +76,7 @@
 static int initdirfd;
 
 static void push_name(char *name, int first);
-static void pop_name(int first);
+static int pop_name(int first);
 static void force_chdir(char *);
 static void ch_dir(char *);
 static char *get_filename(char *name);
@@ -90,11 +90,6 @@
 	/* flag set when can't get dev/inode of a parent dir */
 static int	parent_err = 0;
 static avl_tree_t *tree;	/* tree to keep track of nodes visited */
-	/*
-	 * flag set when an attempt to move subdirectories during execution
-	 * of rm is discovered
-	 */
-static int	bad_chdir = 0;
 
 struct dir_id {
 	dev_t	dev;
@@ -179,16 +174,9 @@
 
 	while (argc-- > 0) {
 		tree = NULL;
-		rm(*argv, 1);
-		while (bad_chdir) {
-			/*
-			 * If bad_chdir is set, the argument directory is not
-			 * deleted since rm does not continue with the recursion
-			 * Call rm() again on the same argument to remove it.
-			 */
-			bad_chdir = 0;
-			rm(*argv, 1);
-		}
+		/* Retry if rm() fails due to bad chdir */
+		while (rm(*argv, 1) < 0)
+			;
 		argv++;
 		destroy_tree(tree);
 	}
@@ -198,7 +186,7 @@
 	/* NOTREACHED */
 }
 
-static void
+static int
 rm(char *path, int first)
 {
 	struct stat buffer;
@@ -214,7 +202,7 @@
 			perror(path);
 			++errcode;
 		}
-		return;
+		return (0);
 	}
 
 	/* prevent removal of / but allow removal of sym-links */
@@ -223,7 +211,7 @@
 		(void) fprintf(stderr,
 		    gettext("rm of %s is not allowed\n"), resolved_path);
 		errcode++;
-		return;
+		return (0);
 	}
 
 	/* prevent removal of . or .. (directly) */
@@ -235,7 +223,7 @@
 		(void) fprintf(stderr,
 			gettext("rm of %s is not allowed\n"), path);
 		errcode++;
-		return;
+		return (0);
 	}
 	/*
 	 * If it's a directory, remove its contents.
@@ -249,7 +237,7 @@
 			(void) fprintf(stderr,
 			    gettext("rm: %s is a directory\n"), path);
 			++errcode;
-			return;
+			return (0);
 		}
 
 		if (first_dir) {
@@ -258,16 +246,8 @@
 			first_dir = 0;
 		}
 
-		undir(path, first, buffer.st_dev, buffer.st_ino);
-		return;
+		return (undir(path, first, buffer.st_dev, buffer.st_ino));
 	}
-	/*
-	 * If 'bad_chdir' is set, rm is in an unintended directory and tries
-	 * to unlink a file whose name is contained in 'path'. Return to
-	 * the calling function without proceeding with the argument.
-	 */
-	if (bad_chdir)
-		return;
 
 	filepath = get_filename(path);
 
@@ -291,7 +271,7 @@
 			filepath, yeschr, nochr);
 		if (!yes()) {
 			free(filepath);
-			return;
+			return (0);
 		}
 	} else if (!silent) {
 		/*
@@ -318,7 +298,7 @@
 			 */
 			if (!yes()) {
 				free(filepath);
-				return;
+				return (0);
 			}
 		}
 	}
@@ -334,7 +314,7 @@
 	if (unlink(path) == FAIL) {
 		if (errno == ENOENT) {
 			free(filepath);
-			return;
+			return (0);
 		}
 #ifndef XPG4
 		if (!silent || interactive) {
@@ -349,9 +329,10 @@
 	}
 
 	free(filepath);
+	return (0);
 }
 
-static void
+static int
 undir(char *path, int first, dev_t dev, ino_t ino)
 {
 	char	*newpath;
@@ -360,6 +341,7 @@
 	int	ismypath;
 	int	ret;
 	int	chdir_failed = 0;
+	int	bad_chdir = 0;
 	size_t	len;
 
 	push_name(path, first);
@@ -384,10 +366,8 @@
 		/*
 		 * If the answer is no, skip the directory.
 		 */
-		if (!yes()) {
-			pop_name(first);
-			return;
-		}
+		if (!yes())
+			return (pop_name(first));
 	}
 
 #ifdef XPG4
@@ -407,10 +387,8 @@
 			/*
 			 * If the answer is no, skip the directory.
 			 */
-			if (!yes()) {
-				pop_name(first);
-				return;
-			}
+			if (!yes())
+				return (pop_name(first));
 		}
 	}
 #endif
@@ -430,8 +408,7 @@
 			perror("rm");
 		}
 		errcode++;
-		pop_name(first);
-		return;
+		return (pop_name(first));
 	}
 
 	/*
@@ -464,8 +441,7 @@
 			    fullpath, yeschr, nochr);
 			if (!yes()) {
 				++errcode;
-				pop_name(first);
-				return;
+				return (pop_name(first));
 			}
 		}
 
@@ -492,8 +468,7 @@
 		}
 
 		/* Continue to next file/directory rather than exit */
-		pop_name(first);
-		return;
+		return (pop_name(first));
 	}
 
 	/*
@@ -552,7 +527,8 @@
 		 */
 		if (name->dd_fd >= maxfiles) {
 			(void) closedir(name);
-			rm(newpath, 0);
+			if (rm(newpath, 0) < 0)
+				bad_chdir = -1;
 			if (!chdir_failed)
 				name = opendir(".");
 			else
@@ -565,28 +541,20 @@
 				cleanup();
 				exit(2);
 			}
-		} else
-			rm(newpath, 0);
+		} else if (rm(newpath, 0) < 0)
+			bad_chdir = -1;
 
 		free(newpath);
-
-		/*
-		 * If an attempt to move files/directories during the execution
-		 * of rm is detected DO NOT proceed with the argument directory.
-		 * rm, in such a case, may have chdir() into a directory outside
-		 * the hierarchy of argument directory.
-		 */
-		if (bad_chdir) {
-			pop_name(first);
-			(void) closedir(name);
-			return;
-		}
+		if (bad_chdir)
+			break;
 	}
 
 	/*
 	 * Close the directory we just finished reading.
 	 */
 	(void) closedir(name);
+	if (bad_chdir)
+		return (-1);
 
 	/*
 	 * The contents of the directory have been removed.  If the
@@ -616,19 +584,16 @@
 
 	switch (ismypath) {
 	case 3:
-		pop_name(first);
-		return;
+		return (pop_name(first));
 	case 2:
 		(void) fprintf(stderr,
 		    gettext("rm: Cannot remove any directory in the path "
 			"of the current working directory\n%s\n"), fullpath);
 		++errcode;
-		pop_name(first);
-		return;
+		return (pop_name(first));
 	case 1:
 		++errcode;
-		pop_name(first);
-		return;
+		return (pop_name(first));
 	case 0:
 		break;
 	}
@@ -639,10 +604,8 @@
 	if (interactive) {
 		(void) fprintf(stderr, gettext("rm: remove %s: (%s/%s)? "),
 			fullpath, yeschr, nochr);
-		if (!yes()) {
-			pop_name(first);
-			return;
-		}
+		if (!yes())
+			return (pop_name(first));
 	}
 	if (rmdir(path) == FAIL) {
 		(void) fprintf(stderr,
@@ -651,7 +614,7 @@
 		perror("");
 		++errcode;
 	}
-	pop_name(first);
+	return (pop_name(first));
 }
 
 
@@ -795,16 +758,17 @@
 	current_dir = newdir;
 }
 
-static void
+static int
 pop_name(int first)
 {
+	int	retval = 0;
 	char *slash;
 	struct	stat buffer;
 	struct	dir_id *remove_dir;
 
 	if (first) {
 		*fullpath = '\0';
-		return;
+		return (0);
 	}
 	slash = strrchr(fullpath, '/');
 	if (slash)
@@ -829,17 +793,16 @@
 	 */
 	if ((current_dir->inode != buffer.st_ino) || (current_dir->dev !=
 	    buffer.st_dev)) {
-		if (!bad_chdir) {
-			(void) fprintf(stderr, gettext("rm: WARNING: "
-			    "A subdirectory of %s was moved or linked to "
-			    "another directory during the execution of rm\n"),
-			    fullpath);
-		}
-		bad_chdir = 1;
+		(void) fprintf(stderr, gettext("rm: WARNING: "
+		    "A subdirectory of %s was moved or linked to "
+		    "another directory during the execution of rm\n"),
+		    fullpath);
+		retval = -1;
 	}
 	remove_dir = current_dir;
 	current_dir = current_dir->next;
 	free(remove_dir);
+	return (retval);
 }
 
 static void