[BusyBox] "which" mostly rewritten

Pavel Roskin pavel_roskin at geocities.com
Mon Jun 5 22:50:29 UTC 2000


Hello!

The current "which" is so buggy that it was easier for me to reimplement
it. Some notes:

Instead of scanning whole directories with readdir() I decided to use
stat(). This also gives us the possibility to ignore non-executable files.

The official "which" doesn't ignore directories, why should we bother?

"which" without arguments doesn't crash anymore.

If PATH is not defined we shouldn't fallback to a default. It's a problem
that should be reported. BTW, the official "which" crashes when run as
"env - which foo" (LinuxPPC 1999 Q3).

In order to process many arguments we should make a copy path_list,
otherwise it cannot be reused.

The official "which" stops processing arguments if it cannot find a file.
The error message is printed on stdout. The exit code is 1. All this is
now emulated.

I'll apply the patch myself with notes in Changelog. Ok?

Pavel Roskin

===================
diff -u -r1.1 which.c
--- which.c	2000/06/02 13:42:13	1.1
+++ which.c	2000/06/05 19:31:05
@@ -23,15 +23,18 @@
 
 #include "internal.h"
 #include <stdio.h>
-#include <dirent.h>
+#include <sys/stat.h>
+#include <sys/param.h>
 
 
 extern int which_main(int argc, char **argv)
 {
-	char *path_list, *test, *tmp;
-	struct dirent *next;
+	char *path_list, *test, *tmp, *path_parsed;
+	char buf[PATH_MAX];
+	struct stat filestat;
+	int count = 0;
 
-	if (**(argv + 1) == '-') {
+	if (argc <= 1 || **(argv + 1) == '-') {
 		usage("which [COMMAND ...]\n"
 #ifndef BB_FEATURE_TRIVIAL_HELP
 				"\nLocates a COMMAND.\n"
@@ -42,23 +45,47 @@
 
 	path_list = getenv("PATH");
 	if (!path_list)
-		path_list = "/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin";
+		fatalError("which: PATH is not defined\n");
 
-	while(argc-- > 0 && *(argv++) != '\0' && strlen(*argv)) { 
-		for( test=path_list; (tmp=strchr(test, ':')) && (tmp+1)!=NULL; test=++tmp) {
-			DIR *dir;
-			*tmp='\0';
-			//printf("Checking directory '%s'\n", test);
-			dir = opendir(test);
-			if (!dir)
-				continue;
-			while ((next = readdir(dir)) != NULL) {
-				//printf("Checking file '%s'\n", next->d_name);
-				if ((strcmp(next->d_name, *argv) == 0)) {
-					printf("%s/%s\n", test, next->d_name);
-					exit(TRUE);
-				}
+	path_parsed = malloc (strlen(path_list) + 1);
+	strcpy (path_parsed, path_list);
+
+	/* Parse path_parsed */
+	count = 1;
+	test = path_parsed;
+	while (1) {
+		tmp = strchr(test, ':');
+		if (tmp == NULL)
+			break;
+		*tmp = 0;
+		test = tmp + 1;
+		count++;
+	}
+
+
+	while(argc-- > 0) { 
+		int i;
+		int found = FALSE;
+		test = path_parsed;
+		argv++;
+		for (i = 0; i < count; i++) {
+			strcpy (buf, test);
+			strcat (buf, "/");
+			strcat (buf, *argv);
+			if (stat (buf, &filestat) == 0
+			    && filestat.st_mode & S_IXUSR)
+			{
+				found = TRUE;
+				break;
 			}
+			test += (strlen(test) + 1);
+		}
+		if (found == TRUE)
+			printf ("%s\n", buf);
+		else
+		{
+			printf ("which: no %s in (%s)\n", *argv, path_list);
+			exit (FALSE);
 		}
 	}
 	exit(TRUE);
===================








More information about the busybox mailing list