Radish alpha
H
rad:z3QDZAW2FAfuLvihrhiyDC9fAD8G9
HardenedBSD Package Manager
Radicle
Git
added ability to search for filenames in $PATH
Elvira Khabirova committed 12 years ago
commit e5d211074285e874663a387505e08fdf6a39b115
parent 4bce6de
2 files changed +79 -4
modified docs/pkg-which.8
@@ -41,6 +41,8 @@ Shows the origin of the package instead of name-version
Treat
.Ao file Ac
as a glob pattern.
+
.It Fl p
+
Search for the filename in PATH.
.El
.Sh ENVIRONMENT
The following environment variables affect the execution of
modified src/which.c
@@ -27,6 +27,7 @@
 */

#include <sys/param.h>
+
#include <sys/stat.h>

#include <stdio.h>
#include <pkg.h>
@@ -40,10 +41,13 @@
void
usage_which(void)
{
-
	fprintf(stderr, "Usage: pkg which [-qgo] <file>\n\n");
+
	fprintf(stderr, "Usage: pkg which [-qgop] <file>\n\n");
	fprintf(stderr, "For more information see 'pkg help which'.\n");
}

+
static int is_there(char *);
+
int get_match(char **, char *, char *);
+

int
exec_which(int argc, char **argv)
{
@@ -51,12 +55,15 @@ exec_which(int argc, char **argv)
	struct pkgdb_it *it = NULL;
	struct pkg *pkg = NULL;
	char pathabs[MAXPATHLEN];
+
	char *p, *path;
	int ret = EPKG_OK, retcode = EX_SOFTWARE;
	int ch;
+
	int res;
	bool orig = false;
	bool glob = false;
+
	bool search = false;

-
	while ((ch = getopt(argc, argv, "qgo")) != -1) {
+
	while ((ch = getopt(argc, argv, "qgop")) != -1) {
		switch (ch) {
		case 'q':
			quiet = true;
@@ -67,6 +74,9 @@ exec_which(int argc, char **argv)
		case 'o':
			orig = true;
			break;
+
		case 'p':
+
			search = true;
+
			break;
		default:
			usage_which();
			return (EX_USAGE);
@@ -81,11 +91,34 @@ exec_which(int argc, char **argv)
		return (EX_USAGE);
	}

-
	if (!glob)
+
	if (!glob && !search)
		absolutepath(argv[0], pathabs, sizeof(pathabs));
-
	else {
+
	else if (!search) {
		if (strlcpy(pathabs, argv[0], sizeof(pathabs)) >= sizeof(pathabs))
			return (EX_USAGE);
+
	} else {
+

+
		if ((p = getenv("PATH")) == NULL)
+
			return (EX_USAGE);
+
		path = malloc(strlen(p)+1);
+
		if (path == NULL)
+
			return (EX_OSERR);
+

+
		memcpy(path, p, strlen(p)+1);
+

+
		if (strlen(argv[0]) >= FILENAME_MAX)
+
			return (EX_USAGE);
+

+
		p = NULL;
+
		res = get_match(&p, path, argv[0]);
+
		if (res == (EX_USAGE)) {
+
			printf("%s was not found in PATH\n", argv[0]);
+
			return (EX_USAGE);
+
		} else if (res == (EX_OSERR)) {
+
			return (EX_OSERR);
+
		}
+

+
		strncpy(pathabs, p, strlen(p)+1);
	}

	if (pkgdb_open(&db, PKGDB_DEFAULT) != EPKG_OK) {
@@ -127,3 +160,43 @@ cleanup:

	return (retcode);
}
+

+

+
static int
+
is_there(char *candidate)
+
{
+
	struct stat fin;
+

+
	/* XXX work around access(2) false positives for superuser */
+
	if (access(candidate, X_OK) == 0 &&
+
	    stat(candidate, &fin) == 0 &&
+
	    S_ISREG(fin.st_mode) &&
+
	    (getuid() != 0 ||
+
	    (fin.st_mode & (S_IXUSR | S_IXGRP | S_IXOTH)) != 0)) {
+
		return (1);
+
	}
+
	return (0);
+
}
+

+
int
+
get_match(char **pathabs, char *path, char *filename)
+
{
+
	char candidate[PATH_MAX];
+
	const char *d;
+

+
	while ((d = strsep(&path, ":")) != NULL) {
+
		if (*d == '\0')
+
			d = ".";
+
		if (snprintf(candidate, sizeof(candidate), "%s/%s", d,
+
		    filename) >= (int)sizeof(candidate))
+
			continue;
+
		if (is_there(candidate)) {
+
			*pathabs = malloc(strlen(candidate)+1);
+
			if (*pathabs == NULL)
+
				return (EX_OSERR);
+
			strncpy(*pathabs, candidate, strlen(candidate)+1);
+
			return (EX_OK);
+
		}
+
	}
+
	return (EX_USAGE);
+
}