#include <sys/cdefs.h>
#ifndef lint
__COPYRIGHT("@(#) Copyright (c) 1989, 1993\
The Regents of the University of California. All rights reserved.");
#endif
#ifndef lint
#if 0
static char sccsid[] = "@(#)locate.c 8.1 (Berkeley) 6/6/93";
#endif
__RCSID("$NetBSD: locate.c,v 1.19 2018/05/14 05:17:10 lukem Exp $");
#endif
#include <sys/param.h>
#include <fnmatch.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <err.h>
#include <errno.h>
#include <sys/queue.h>
#include <sys/stat.h>
#include "locate.h"
#include "pathnames.h"
struct locate_db {
LIST_ENTRY(locate_db) db_link;
FILE *db_fp;
const char *db_path;
};
LIST_HEAD(db_list, locate_db) db_list;
#ifndef NEW
# define NEW(type) (type *) malloc(sizeof (type))
#endif
static void add_db(const char *);
static int fastfind(FILE *, char *);
static char *patprep(const char *);
static void
add_db(const char *path)
{
FILE *fp;
struct locate_db *dbp;
struct stat st;
if (path == NULL || *path == '\0')
return;
if ((fp = fopen(path, "r")) == NULL)
err(1, "Can't open database `%s'", path);
if (fstat(fileno(fp), &st) == -1)
err(1, "Can't stat database `%s'", path);
if (S_ISDIR(st.st_mode)) {
errno = EISDIR;
err(1, "Can't use database `%s'", path);
}
dbp = NEW(struct locate_db);
dbp->db_fp = fp;
dbp->db_path = path;
LIST_INSERT_HEAD(&db_list, dbp, db_link);
}
int
main(int argc, char *argv[])
{
struct locate_db *dbp;
const char *locate_path = getenv("LOCATE_PATH");
char *cp;
int c;
int rc;
int found = 0;
LIST_INIT(&db_list);
while ((c = getopt(argc, argv, "d:")) != EOF) {
switch (c) {
case 'd':
locate_path = optarg;
break;
}
}
if (argc <= optind) {
(void)fprintf(stderr, "Usage: %s [-d dbpath] pattern ...\n",
getprogname());
exit(1);
}
if (!locate_path)
locate_path = _PATH_FCODES;
char *lp = strdup(locate_path);
while ((cp = strrchr(lp, ':'))) {
*cp++ = '\0';
add_db(cp);
}
add_db(lp);
free(lp);
if (LIST_EMPTY(&db_list))
exit(1);
for (; optind < argc; ++optind) {
LIST_FOREACH(dbp, &db_list, db_link) {
rc = fastfind(dbp->db_fp, argv[optind]);
if (rc > 0) {
found = 1;
} else if (rc < 0) {
errx(2, "Invalid data in database file `%s'",
dbp->db_path);
}
}
}
exit(found == 0);
}
static int
fastfind(FILE *fp, char *pathpart)
{
char *p, *s;
int c;
int count, found, globflag, printed;
char *cutoff, *patend, *q;
char bigram1[NBG], bigram2[NBG], path[MAXPATHLEN];
rewind(fp);
for (c = 0, p = bigram1, s = bigram2; c < NBG; c++)
p[c] = getc(fp), s[c] = getc(fp);
p = pathpart;
globflag = strchr(p, '*') || strchr(p, '?') || strchr(p, '[');
patend = patprep(p);
found = printed = 0;
for (c = getc(fp), count = 0; c != EOF;) {
count += ((c == SWITCH) ? getw(fp) : c) - OFFSET;
for (p = path + count; (c = getc(fp)) > SWITCH;) {
if (p < path || p >= path + sizeof(path) - 1)
return -1;
if (c < PARITY)
*p++ = c;
else {
c &= PARITY - 1;
if (c < 0 || c >= (int)sizeof(bigram1))
return -1;
*p++ = bigram1[c], *p++ = bigram2[c];
}
}
*p-- = '\0';
if (p < path || count < 0)
return -1;
cutoff = (found ? path : path + count);
for (found = 0, s = p; s >= cutoff; s--)
if (*s == *patend) {
for (p = patend - 1, q = s - 1; *p != '\0';
p--, q--)
if (*q != *p)
break;
if (*p == '\0') {
found = 1;
if (!globflag ||
!fnmatch(pathpart, path, 0)) {
(void)printf("%s\n", path);
++printed;
}
break;
}
}
}
return printed;
}
static char globfree[100];
static char *
patprep(const char *name)
{
const char *endmark, *p;
char *subp = globfree;
*subp++ = '\0';
p = name + strlen(name) - 1;
for (; p >= name; p--)
if (strchr("*?", *p) == 0)
break;
if (p < name)
p = name;
if (*p == ']')
for (p--; p >= name; p--)
if (*p == '[') {
p--;
break;
}
if (p < name)
p = name;
if ((p == name) && strchr("?*[]", *p) != 0)
*subp++ = '/';
else {
for (endmark = p; p >= name; p--)
if (strchr("]*?", *p) != 0)
break;
for (++p;
(p <= endmark) && subp < (globfree + sizeof(globfree));)
*subp++ = *p++;
}
*subp = '\0';
return --subp;
}