git: edadc3f90515 - main - whereis(1): Respect PORTSDIR variable
Date: Sat, 29 Aug 2026 15:18:59 UTC
The branch main has been updated by fernape:
URL: https://cgit.FreeBSD.org/src/commit/?id=edadc3f9051595a9c2e693d8ab666a50b9e7a21a
commit edadc3f9051595a9c2e693d8ab666a50b9e7a21a
Author: Fernando Apesteguía <fernape@FreeBSD.org>
AuthorDate: 2026-08-23 15:46:18 +0000
Commit: Fernando Apesteguía <fernape@FreeBSD.org>
CommitDate: 2026-08-29 15:15:43 +0000
whereis(1): Respect PORTSDIR variable
PORTSDIR is a very common variable that points to the location of a ports
directory. Make whereis(1) respect this variable too.
Reviewed by: arrowd@, christos@
Approved by: christos@
Differential Revision: https://reviews.freebsd.org/D56845
---
usr.bin/whereis/whereis.1 | 4 ++
usr.bin/whereis/whereis.c | 118 +++++++++++++++++++++++++---------------------
2 files changed, 69 insertions(+), 53 deletions(-)
diff --git a/usr.bin/whereis/whereis.1 b/usr.bin/whereis/whereis.1
index 90922ce61db5..1b6adaeaf077 100644
--- a/usr.bin/whereis/whereis.1
+++ b/usr.bin/whereis/whereis.1
@@ -72,6 +72,10 @@ including all the subdirectories of
.Pa /usr/src
and
.Pa /usr/ports .
+If the environment variable
+.Ev PORTSDIR
+is defined and points to a directory then all its subdirectories
+are included in the search of program sources.
.Pp
The following options are available:
.Bl -tag -width indent
diff --git a/usr.bin/whereis/whereis.c b/usr.bin/whereis/whereis.c
index 8de56b9cf654..afc099276dfe 100644
--- a/usr.bin/whereis/whereis.c
+++ b/usr.bin/whereis/whereis.c
@@ -312,64 +312,76 @@ defaults(void)
abort();
nele = 0;
decolonify(b, &sourcedirs, &nele);
-
- if (stat(PATH_PORTS, &sb) == -1) {
- if (errno == ENOENT)
- /* no /usr/ports, we are done */
- return;
- err(EX_OSERR, "stat(" PATH_PORTS ")");
+ ccharp path_ports;
+ if ((cp = getenv("PORTSDIR")) != NULL) {
+ b = strdup(cp);
+ if (b == NULL)
+ abort();
}
- if ((sb.st_mode & S_IFMT) != S_IFDIR)
- /* /usr/ports is not a directory, ignore */
- return;
- if (access(PATH_PORTS, R_OK | X_OK) != 0)
- return;
- if ((dir = opendir(PATH_PORTS)) == NULL)
- err(EX_OSERR, "opendir" PATH_PORTS ")");
- while ((dirp = readdir(dir)) != NULL) {
- /*
- * Not everything below PATH_PORTS is of
- * interest. First, all dot files and
- * directories (e. g. .snap) can be ignored.
- * Also, all subdirectories starting with a
- * capital letter are not going to be
- * examined, as they are used for internal
- * purposes (Mk, Tools, ...). This also
- * matches a possible CVS subdirectory.
- * Finally, the distfiles subdirectory is also
- * special, and should not be considered to
- * avoid false matches.
- */
- if (dirp->d_name[0] == '.' ||
- /*
- * isupper() not used on purpose: the
- * check is supposed to default to the C
- * locale instead of the current user's
- * locale.
- */
- (dirp->d_name[0] >= 'A' && dirp->d_name[0] <= 'Z') ||
- strcmp(dirp->d_name, "distfiles") == 0)
+ ccharp ports_locations[2] = {PATH_PORTS, cp};
+ int i;
+ for (i = 0; i < 2; i++) {
+ path_ports = ports_locations[i];
+ if (!path_ports)
continue;
- if ((b = malloc(sizeof PATH_PORTS + 1 + dirp->d_namlen))
- == NULL)
- abort();
- strcpy(b, PATH_PORTS);
- strcat(b, "/");
- strcat(b, dirp->d_name);
- if (stat(b, &sb) == -1 ||
- (sb.st_mode & S_IFMT) != S_IFDIR ||
- access(b, R_OK | X_OK) != 0) {
- free(b);
+ if (stat(path_ports, &sb) == -1) {
+ if (errno == ENOENT)
+ /* no /usr/ports, we are done */
+ continue;
+ err(EX_OSERR, "stat(%s)", path_ports);
+ }
+ if ((sb.st_mode & S_IFMT) != S_IFDIR)
+ /* This is not a directory, ignore */
+ continue;
+ if (access(path_ports, R_OK | X_OK) != 0)
continue;
+ if ((dir = opendir(path_ports)) == NULL)
+ err(EX_OSERR, "opendir %s)", path_ports);
+ while ((dirp = readdir(dir)) != NULL) {
+ /*
+ * Not everything below path_ports is of
+ * interest. First, all dot files and
+ * directories (e. g. .snap) can be ignored.
+ * Also, all subdirectories starting with a
+ * capital letter are not going to be
+ * examined, as they are used for internal
+ * purposes (Mk, Tools, ...). This also
+ * matches a possible CVS subdirectory.
+ * Finally, the distfiles subdirectory is also
+ * special, and should not be considered to
+ * avoid false matches.
+ */
+ if (dirp->d_name[0] == '.' ||
+ /*
+ * isupper() not used on purpose: the
+ * check is supposed to default to the C
+ * locale instead of the current user's
+ * locale.
+ */
+ (dirp->d_name[0] >= 'A' && dirp->d_name[0] <= 'Z') ||
+ strcmp(dirp->d_name, "distfiles") == 0)
+ continue;
+ if ((b = malloc(strlen(path_ports) + 1 + dirp->d_namlen))
+ == NULL)
+ abort();
+ strcpy(b, path_ports);
+ strcat(b, "/");
+ strcat(b, dirp->d_name);
+ if (stat(b, &sb) == -1 ||
+ (sb.st_mode & S_IFMT) != S_IFDIR ||
+ access(b, R_OK | X_OK) != 0) {
+ free(b);
+ continue;
+ }
+ sourcedirs = realloc(sourcedirs,
+ (nele + 2) * sizeof(char *));
+ if (sourcedirs == NULL)
+ abort();
+ sourcedirs[nele++] = b;
+ sourcedirs[nele] = NULL;
}
- sourcedirs = realloc(sourcedirs,
- (nele + 2) * sizeof(char *));
- if (sourcedirs == NULL)
- abort();
- sourcedirs[nele++] = b;
- sourcedirs[nele] = NULL;
+ closedir(dir);
}
- closedir(dir);
}
}