[PATCH 1/7] whereis: rewrite most of the command

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



The earlier code gave little or no change to fix bugs and improve the
command.  This rewrite attempts to make further patching easier.

Signed-off-by: Sami Kerola <kerolasa@xxxxxx>
---
 misc-utils/whereis.c | 468 +++++++++++++++++++++++++--------------------------
 1 file changed, 229 insertions(+), 239 deletions(-)

diff --git a/misc-utils/whereis.c b/misc-utils/whereis.c
index 4194ad5..eeec976 100644
--- a/misc-utils/whereis.c
+++ b/misc-utils/whereis.c
@@ -49,13 +49,35 @@
 #include <stdlib.h>
 #include <string.h>
 #include <ctype.h>
+#include <assert.h>
 
 #include "xalloc.h"
 #include "nls.h"
 #include "c.h"
 #include "closestream.h"
 
-static char *bindirs[] = {
+#define BIN_BIT (1 << 1)
+#define MAN_BIT (1 << 2)
+#define SRC_BIT (1 << 3)
+
+static char uflag = 0;
+
+enum {
+	BIN_DIR = 0,
+	MAN_DIR,
+	SRC_DIR,
+	ALL_DIRS
+};
+
+struct is_here {
+	int type;
+	dev_t st_dev;
+	ino_t st_ino;
+	char *path;
+	struct is_here *next;
+};
+
+static const char *bindirs[] = {
 	"/bin",
 	"/usr/bin",
 	"/sbin",
@@ -110,7 +132,7 @@ static char *bindirs[] = {
 	0
 };
 
-static char *mandirs[] = {
+static const char *mandirs[] = {
 	"/usr/man/*",
 	"/usr/share/man/*",
 	"/usr/X386/man/*",
@@ -120,7 +142,7 @@ static char *mandirs[] = {
 	0
 };
 
-static char *srcdirs[] = {
+static const char *srcdirs[] = {
 	"/usr/src/*",
 	"/usr/src/lib/libc/*",
 	"/usr/src/lib/libc/net/*",
@@ -130,11 +152,7 @@ static char *srcdirs[] = {
 	0
 };
 
-static char sflag = 1, bflag = 1, mflag = 1, uflag;
-static char **Sflag, **Bflag, **Mflag, **pathdir, **pathdir_p;
-static int Scnt, Bcnt, Mcnt, count, print;
-
-static void __attribute__ ((__noreturn__)) usage(FILE * out)
+static void __attribute__((__noreturn__)) usage(FILE *out)
 {
 	fputs(_("\nUsage:\n"), out);
 	fprintf(out,
@@ -156,8 +174,7 @@ static void __attribute__ ((__noreturn__)) usage(FILE * out)
 	exit(out == stderr ? EXIT_FAILURE : EXIT_SUCCESS);
 }
 
-static int
-itsit(char *cp, char *dp)
+static int itsit(char *cp, char *dp)
 {
 	int i = strlen(dp);
 
@@ -185,86 +202,90 @@ itsit(char *cp, char *dp)
 	return 0;
 }
 
-static void
-findin(char *dir, char *cp)
+static void findin(char *dir, char *cp, int *nr_found, char **wait)
 {
 	DIR *dirp;
 	struct dirent *dp;
-	char *d, *dd;
-	size_t l;
-	char dirbuf[1024];
-	struct stat statbuf;
 
-	dd = strchr(dir, '*');
-	if (!dd) {
-		dirp = opendir(dir);
-		if (dirp == NULL)
-			return;
-		while ((dp = readdir(dirp)) != NULL) {
-			if (itsit(cp, dp->d_name)) {
-				count++;
-				if (print)
-					printf(" %s/%s", dir, dp->d_name);
-			}
-		}
-		closedir(dirp);
+	dirp = opendir(dir);
+	if (dirp == NULL)
 		return;
-	}
-
-	l = strlen(dir);
-	if (l < sizeof(dirbuf)) {
-		/* refuse excessively long names */
-		strcpy(dirbuf, dir);
-		d = strchr(dirbuf, '*');
-		if (d)
-			*d = 0;
-		dirp = opendir(dirbuf);
-		if (dirp == NULL)
-			return;
-		while ((dp = readdir(dirp)) != NULL) {
-			if (!strcmp(dp->d_name, ".") ||
-			    !strcmp(dp->d_name, ".."))
-				continue;
-			if (strlen(dp->d_name) + l > sizeof(dirbuf))
-				continue;
-			sprintf(d, "%s", dp->d_name);
-			if (stat(dirbuf, &statbuf))
-				continue;
-			if (!S_ISDIR(statbuf.st_mode))
-				continue;
-			strcat(d, dd + 1);
-			findin(dirbuf, cp);
+	while ((dp = readdir(dirp)) != NULL)
+		if (itsit(cp, dp->d_name)) {
+			if (*(nr_found) == 0)
+				xasprintf(wait, "%s/%s", dir, dp->d_name);
+			else if (*(nr_found) == 1 && *wait != NULL)
+				printf("%s: %s %s/%s", cp, *wait, dir,
+				       dp->d_name);
+			else if (*(nr_found) == 1)
+				printf("%s: %s/%s", cp, dir, dp->d_name);
+			else
+				printf(" %s/%s", dir, dp->d_name);
+			(*nr_found)++;
 		}
-		closedir(dirp);
-	}
+	closedir(dirp);
 	return;
-
 }
 
-static int inpath(const char *str)
+static void add_dir(struct is_here *dirlist, int type, const char *dir)
 {
-	size_t i;
+	struct stat statbuf;
+	struct is_here *prev = NULL;
 
-	for (i = 0; i < ARRAY_SIZE(bindirs) - 1 ; i++)
-		if (!strcmp(bindirs[i], str))
-			return 1;
+	if (access(dir, R_OK) != 0)
+		return;
+	if (stat(dir, &statbuf))
+		return;
+	if (!S_ISDIR(statbuf.st_mode))
+		return;
+	while (dirlist) {
+		if (dirlist->st_ino == statbuf.st_ino &&
+		    dirlist->st_dev == statbuf.st_dev && dirlist->type == type)
+			return;
+		prev = dirlist;
+		dirlist = dirlist->next;
+	}
+	assert(prev);
+	dirlist = xcalloc(1, sizeof(struct is_here));
+	dirlist->st_ino = statbuf.st_ino;
+	dirlist->st_dev = statbuf.st_dev;
+	dirlist->type = type;
+	dirlist->path = xstrdup(dir);
+	prev->next = dirlist;
+	return;
+}
 
-	for (i = 0; i < ARRAY_SIZE(mandirs) - 1; i++)
-		if (!strcmp(mandirs[i], str))
-			return 1;
+static void add_subdirs(struct is_here *dirlist, int type,
+			const char *dir)
+{
+#define DIRBUF 1024
+	char dirbuf[DIRBUF], *d;
+	DIR *dirp;
+	struct dirent *dp;
 
-	for (i = 0; i < ARRAY_SIZE(srcdirs) - 1; i++)
-		if (!strcmp(srcdirs[i], str))
-			return 1;
+	strncpy(dirbuf, dir, DIRBUF);
+	d = strchr(dirbuf, '*');
+	*d = 0;
 
-	return 0;
+	dirp = opendir(dirbuf);
+	if (dirp == NULL)
+		return;
+	while ((dp = readdir(dirp)) != NULL) {
+		if (!strcmp(dp->d_name, ".") || !strcmp(dp->d_name, ".."))
+			continue;
+		sprintf(d, "%s", dp->d_name);
+		/* a dir definition can have a star in middle of path */
+		strcat(dirbuf, strchr(dir, '*') + 1);
+		add_dir(dirlist, type, dirbuf);
+	}
+	closedir(dirp);
+	return;
 }
 
-static void fillpath(void)
+static void environ_list(const char *env, struct is_here *dirlist,
+			 int type)
 {
-	char *key=NULL, *tok=NULL, *pathcp, *path = getenv("PATH");
-	int i = 0;
-
+	char *key = NULL, *tok = NULL, *pathcp, *path = getenv(env);
 
 	if (!path)
 		return;
@@ -272,150 +293,105 @@ static void fillpath(void)
 
 	for (tok = strtok_r(pathcp, ":", &key); tok;
 	     tok = strtok_r(NULL, ":", &key)) {
-
-		/* make sure we don't repeat the search path */
-		if (inpath(tok))
-			continue;
-
-		pathdir = xrealloc(pathdir, (i + 1) * sizeof(char *));
-		pathdir[i++] = xstrdup(tok);
+		add_dir(dirlist, type, tok);
 	}
-
-	pathdir = xrealloc(pathdir, (i + 1) * sizeof(char *));
-	pathdir[i] = NULL;
-
-	pathdir_p = pathdir;
 	free(pathcp);
+	return;
 }
 
-static void freepath(void)
-{
-	free(pathdir);
-}
-
-static void
-findv(char **dirv, int dirc, char *cp)
-{
-
-	while (dirc > 0)
-		findin(*dirv++, cp), dirc--;
-}
-
-static void
-looksrc(char *cp)
-{
-	if (Sflag == NULL)
-		findv(srcdirs, ARRAY_SIZE(srcdirs)-1, cp);
-	else
-		findv(Sflag, Scnt, cp);
-}
-
-static void
-lookbin(char *cp)
-{
-	if (Bflag == NULL) {
-		findv(bindirs, ARRAY_SIZE(bindirs)-1, cp);
-		while (*pathdir_p)
-			findin(*pathdir_p++, cp);		/* look $PATH */
-	 } else
-		findv(Bflag, Bcnt, cp);
-}
-
-static void
-lookman(char *cp)
+static void construct_list(struct is_here *dirlist, int type,
+			   const char **list)
 {
-	if (Mflag == NULL)
-		findv(mandirs, ARRAY_SIZE(mandirs)-1, cp);
-	else
-		findv(Mflag, Mcnt, cp);
+	size_t i;
+	char *star;
+	for (i = 0; list[i]; i++) {
+		star = strchr(list[i], '*');
+		if (!star)
+			add_dir(dirlist, type, list[i]);
+		else
+			add_subdirs(dirlist, type, list[i]);
+	}
+	return;
 }
 
-static void
-getlist(int *argcp, char ***argvp, char ***flagp, int *cntp)
+static void getlist(int *argcp, char ***argvp, struct is_here *dirlist,
+		   int type)
 {
 	(*argvp)++;
-	*flagp = *argvp;
-	*cntp = 0;
-	for ((*argcp)--; *argcp > 0 && (*argvp)[0][0] != '-'; (*argcp)--)
-		(*cntp)++, (*argvp)++;
-	(*argcp)++;
-	(*argvp)--;
+	for ((*argcp)--; 0 < *argcp && (*argvp)[0][0] != '-'; (*argcp)--) {
+		add_dir(dirlist, type, **argvp);
+		(*argvp)++;
+	}
+	return;
 }
 
-static void
-zerof(void)
+static int check_type(int type, int flags)
 {
-	if (sflag && bflag && mflag)
-		sflag = bflag = mflag = 0;
+	if (type == BIN_DIR && !(flags & BIN_BIT))
+		return 1;
+	if (type == MAN_DIR && !(flags & MAN_BIT))
+		return 1;
+	if (type == SRC_DIR && !(flags & SRC_BIT))
+		return 1;
+	return 0;
 }
 
-static int
-print_again(char *cp)
+static struct is_here *free_dirs(struct is_here *dirlist, int type)
 {
-	if (print)
-		printf("%s:", cp);
-	if (sflag) {
-		looksrc(cp);
-		if (uflag && print == 0 && count != 1) {
-			print = 1;
-			return 1;
+	struct is_here *first, *prev, *next;
+	if (type == ALL_DIRS) {
+		while (dirlist) {
+			next = dirlist->next;
+			free(dirlist->path);
+			free(dirlist);
+			dirlist = next;
 		}
+		return NULL;
 	}
-	count = 0;
-	if (bflag) {
-		lookbin(cp);
-		if (uflag && print == 0 && count != 1) {
-			print = 1;
-			return 1;
-		}
-	}
-	count = 0;
-	if (mflag) {
-		lookman(cp);
-		if (uflag && print == 0 && count != 1) {
-			print = 1;
-			return 1;
+	first = NULL;
+	prev = NULL;
+	while (dirlist) {
+		if (dirlist->type == type) {
+			next = dirlist->next;
+			free(dirlist->path);
+			free(dirlist);
+			dirlist = next;
+			if (prev)
+				prev->next = dirlist;
+			continue;
 		}
+		if (!first)
+			first = dirlist;
+		prev = dirlist;
+		dirlist = dirlist->next;
 	}
-	return 0;
+	return first;
 }
 
-static void
-lookup(char *cp)
+static void lookup(char *argv, struct is_here *dirlist, int flags)
 {
-	register char *dp;
-
-	for (dp = cp; *dp; dp++)
-		continue;
-	for (; dp > cp; dp--) {
-		if (*dp == '.') {
-			*dp = 0;
-			break;
-		}
+	int nr_found;
+	char *wait = NULL;
+
+	nr_found = uflag == 1 ? 0 : 1;
+
+	for (; dirlist; dirlist = dirlist->next) {
+		if (check_type(dirlist->type, flags))
+			continue;
+		if (dirlist->path != NULL)
+			findin(dirlist->path, argv, &nr_found, &wait);
 	}
-	for (dp = cp; *dp; dp++)
-		if (*dp == '/')
-			cp = dp + 1;
-	if (uflag) {
-		print = 0;
-		count = 0;
-	} else
-		print = 1;
-
-	while (print_again(cp))
-		/* all in print_again() */ ;
-
-	if (print)
-		printf("\n");
+	free(wait);
+	if (1 < nr_found)
+		putchar('\n');
+	return;
 }
 
-/*
- * whereis name
- * look for source, documentation and binaries
- */
-int
-main(int argc, char **argv)
+int main(int argc, char **argv)
 {
+	struct is_here *dirlist;
+	char flags = CHAR_MAX;
+
 	setlocale(LC_ALL, "");
 	bindtextdomain(PACKAGE, LOCALEDIR);
 	textdomain(PACKAGE);
@@ -425,60 +401,74 @@ main(int argc, char **argv)
 	if (argc == 0)
 		usage(stderr);
 
+	dirlist = xcalloc(1, sizeof(struct is_here));
+	construct_list(dirlist, BIN_DIR, bindirs);
+	environ_list("PATH", dirlist, BIN_DIR);
+	construct_list(dirlist, MAN_DIR, mandirs);
+	construct_list(dirlist, SRC_DIR, srcdirs);
+
 	do
 		if (argv[0][0] == '-') {
 			register char *cp = argv[0] + 1;
-			while (*cp) switch (*cp++) {
-
-			case 'f':
-				break;
-
-			case 'S':
-				getlist(&argc, &argv, &Sflag, &Scnt);
-				break;
-
-			case 'B':
-				getlist(&argc, &argv, &Bflag, &Bcnt);
-				break;
-
-			case 'M':
-				getlist(&argc, &argv, &Mflag, &Mcnt);
-				break;
-
-			case 's':
-				zerof();
-				sflag++;
-				continue;
-
-			case 'u':
-				uflag++;
-				continue;
-
-			case 'b':
-				zerof();
-				bflag++;
-				continue;
-
-			case 'm':
-				zerof();
-				mflag++;
-				continue;
-			case 'V':
-				printf(UTIL_LINUX_VERSION);
-				return EXIT_SUCCESS;
-			case 'h':
-				usage(stdout);
-			default:
-				usage(stderr);
-			}
+			while (*cp)
+				switch (*cp++) {
+
+				case 'f':
+					break;
+
+				case 'u':
+					uflag = 1;
+					continue;
+
+				case 'B':
+					dirlist = free_dirs(dirlist, BIN_DIR);
+					getlist(&argc, &argv, dirlist, BIN_DIR);
+					break;
+
+				case 'M':
+					dirlist = free_dirs(dirlist, MAN_DIR);
+					getlist(&argc, &argv, dirlist, MAN_DIR);
+					break;
+
+				case 'S':
+					dirlist = free_dirs(dirlist, SRC_DIR);
+					getlist(&argc, &argv, dirlist, SRC_DIR);
+					break;
+
+				case 'b':
+					if (flags == CHAR_MAX)
+						flags = BIN_BIT;
+					else
+						flags |= BIN_BIT;
+					continue;
+
+				case 'm':
+					if (flags == CHAR_MAX)
+						flags = MAN_BIT;
+					else
+						flags |= MAN_BIT;
+					continue;
+
+				case 's':
+					if (flags == CHAR_MAX)
+						flags = SRC_BIT;
+					else
+						flags |= SRC_BIT;
+					continue;
+
+				case 'V':
+					printf(UTIL_LINUX_VERSION);
+					return EXIT_SUCCESS;
+				case 'h':
+					usage(stdout);
+				default:
+					usage(stderr);
+				}
 			argv++;
 		} else {
-			if (Bcnt == 0 && pathdir == NULL)
-				fillpath();
-			lookup(*argv++);
+			lookup(*argv++, dirlist, flags);
 		}
 	while (--argc > 0);
-
-	freepath();
+	free_dirs(dirlist, ALL_DIRS);
 	return EXIT_SUCCESS;
 }
-- 
1.8.2

--
To unsubscribe from this list: send the line "unsubscribe util-linux" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[Index of Archives]     [Netdev]     [Ethernet Bridging]     [Linux Wireless]     [Kernel Newbies]     [Security]     [Linux for Hams]     [Netfilter]     [Bugtraq]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux RAID]     [Linux Admin]     [Samba]

  Powered by Linux