xref: /freebsd/usr.bin/locate/locate/util.c (revision b3e7694832e81d7a904a10f525f8797b753bf0d3)
1 /*
2  * SPDX-License-Identifier: BSD-3-Clause
3  *
4  * Copyright (c) 1995-2022 Wolfram Schneider <wosch@FreeBSD.org>
5  * Copyright (c) 1989, 1993
6  *	The Regents of the University of California.  All rights reserved.
7  *
8  * This code is derived from software contributed to Berkeley by
9  * James A. Woods.
10  *
11  * Redistribution and use in source and binary forms, with or without
12  * modification, are permitted provided that the following conditions
13  * are met:
14  * 1. Redistributions of source code must retain the above copyright
15  *    notice, this list of conditions and the following disclaimer.
16  * 2. Redistributions in binary form must reproduce the above copyright
17  *    notice, this list of conditions and the following disclaimer in the
18  *    documentation and/or other materials provided with the distribution.
19  * 3. Neither the name of the University nor the names of its contributors
20  *    may be used to endorse or promote products derived from this software
21  *    without specific prior written permission.
22  *
23  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
24  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
27  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33  * SUCH DAMAGE.
34  */
35 
36 #include <sys/param.h>
37 #include <stdlib.h>
38 #include <string.h>
39 #include <err.h>
40 #include <arpa/inet.h>
41 #include <stdio.h>
42 #include <sys/stat.h>
43 
44 #include "locate.h"
45 #include "pathnames.h"
46 
47 char 	**colon(char **, char*, char*);
48 char 	*patprep(char *);
49 u_char 	*tolower_word(u_char *);
50 int 	getwm(caddr_t);
51 int 	getwf(FILE *);
52 int	check_bigram_char(int);
53 
54 /*
55  * Validate bigram chars. If the test failed the database is corrupt
56  * or the database is obviously not a locate database.
57  */
58 int
check_bigram_char(int ch)59 check_bigram_char(int ch)
60 {
61 	/* legal bigram: 0, ASCII_MIN ... ASCII_MAX */
62 	if (ch == 0 ||
63 	    (ch >= ASCII_MIN && ch <= ASCII_MAX))
64 		return (ch);
65 
66 	errx(1,
67 		"locate database header corrupt, bigram char outside 0, %d-%d: %d",
68 		ASCII_MIN, ASCII_MAX, ch);
69 	exit(1);
70 }
71 
72 /* split a colon separated string into a char vector
73  *
74  * "bla:foo" -> {"foo", "bla"}
75  * "bla:"    -> {"foo", dot}
76  * "bla"     -> {"bla"}
77  * ""	     -> do nothing
78  *
79  */
80 char **
colon(char ** dbv,char * path,char * dot)81 colon(char **dbv, char *path, char *dot)
82 {
83 	int vlen, slen;
84 	char *c, *ch, *p;
85 	char **pv;
86 
87 	if (dbv == NULL) {
88 		if ((dbv = malloc(sizeof(char *))) == NULL)
89 			err(1, "malloc");
90 		*dbv = NULL;
91 	}
92 
93 	/* empty string */
94 	if (*path == '\0') {
95 		warnx("empty database name, ignored");
96 		return (dbv);
97 	}
98 
99 	/* length of string vector */
100 	for(vlen = 0, pv = dbv; *pv != NULL; pv++, vlen++);
101 
102 	for (ch = c = path; ; ch++) {
103 		if (*ch == ':' ||
104 		    (!*ch && !(*(ch - 1) == ':' && ch == 1+ path))) {
105 			/* single colon -> dot */
106 			if (ch == c)
107 				p = dot;
108 			else {
109 				/* a string */
110 				slen = ch - c;
111 				if ((p = malloc(sizeof(char) * (slen + 1)))
112 				    == NULL)
113 					err(1, "malloc");
114 				bcopy(c, p, slen);
115 				*(p + slen) = '\0';
116 			}
117 			/* increase dbv with element p */
118 			if ((dbv = realloc(dbv, sizeof(char *) * (vlen + 2)))
119 			    == NULL)
120 				err(1, "realloc");
121 			*(dbv + vlen) = p;
122 			*(dbv + ++vlen) = NULL;
123 			c = ch + 1;
124 		}
125 		if (*ch == '\0')
126 			break;
127 	}
128 	return (dbv);
129 }
130 
131 /*
132  * extract last glob-free subpattern in name for fast pre-match; prepend
133  * '\0' for backwards match; return end of new pattern
134  */
135 static char globfree[100];
136 
137 char *
patprep(char * name)138 patprep(char *name)
139 {
140 	char *endmark, *p, *subp;
141 
142 	subp = globfree;
143 	*subp++ = '\0';   /* set first element to '\0' */
144 	p = name + strlen(name) - 1;
145 
146 	/* skip trailing metacharacters */
147 	for (; p >= name; p--)
148 		if (strchr(LOCATE_REG, *p) == NULL)
149 			break;
150 
151 	/*
152 	 * check if maybe we are in a character class
153 	 *
154 	 * 'foo.[ch]'
155 	 *        |----< p
156 	 */
157 	if (p >= name &&
158 	    (strchr(p, '[') != NULL || strchr(p, ']') != NULL)) {
159 		for (p = name; *p != '\0'; p++)
160 			if (*p == ']' || *p == '[')
161 				break;
162 		p--;
163 
164 		/*
165 		 * cannot find a non-meta character, give up
166 		 * '*\*[a-z]'
167 		 *    |-------< p
168 		 */
169 		if (p >= name && strchr(LOCATE_REG, *p) != NULL)
170 			p = name - 1;
171 	}
172 
173 	if (p < name)
174 		/* only meta chars: "???", force '/' search */
175 		*subp++ = '/';
176 
177 	else {
178 		for (endmark = p; p >= name; p--)
179 			if (strchr(LOCATE_REG, *p) != NULL)
180 				break;
181 		for (++p;
182 		    (p <= endmark) && subp < (globfree + sizeof(globfree));)
183 			*subp++ = *p++;
184 	}
185 	*subp = '\0';
186 	return (--subp);
187 }
188 
189 /* tolower word */
190 u_char *
tolower_word(u_char * word)191 tolower_word(u_char *word)
192 {
193 	u_char *p;
194 
195 	for(p = word; *p != '\0'; p++)
196 		*p = TOLOWER(*p);
197 
198 	return (word);
199 }
200 
201 
202 /*
203  * Read integer from mmap pointer.
204  * Essentially a simple ``return *(int *)p'' but avoids sigbus
205  * for integer alignment (SunOS 4.x, 5.x).
206  *
207  * Convert network byte order to host byte order if necessary.
208  * So we can read a locate database on FreeBSD/i386 (little endian)
209  * which was built on SunOS/sparc (big endian).
210  */
211 
212 int
getwm(caddr_t p)213 getwm(caddr_t p)
214 {
215 	union {
216 		char buf[INTSIZE];
217 		int i;
218 	} u;
219 	int i, hi;
220 
221 	/* the integer is stored by an offset of 14 (!!!) */
222         int i_max = LOCATE_PATH_MAX + OFFSET;
223         int i_min = -(LOCATE_PATH_MAX - OFFSET);
224 
225 	for (i = 0; i < (int)INTSIZE; i++)
226 		u.buf[i] = *p++;
227 
228 	i = u.i;
229 
230 	if (i >= i_max || i <= i_min) {
231 		hi = ntohl(i);
232 		if (hi >= i_max || hi <= i_min)
233 			errx(1, "integer out of range: %d < %d < %d",
234 			    i_min, abs(i) < abs(hi) ? i : hi, i_max);
235 		return (hi);
236 	}
237 	return (i);
238 }
239 
240 /*
241  * Read integer from stream.
242  *
243  * Convert network byte order to host byte order if necessary.
244  * So we can read on FreeBSD/i386 (little endian) a locate database
245  * which was built on SunOS/sparc (big endian).
246  */
247 
248 int
getwf(FILE * fp)249 getwf(FILE *fp)
250 {
251 	int word, hword;
252         int i_max = LOCATE_PATH_MAX + OFFSET;
253         int i_min = -(LOCATE_PATH_MAX - OFFSET);
254 
255 	word = getw(fp);
256 
257 	if (word >= i_max || word <= i_min) {
258 		hword = ntohl(word);
259 		if (hword >= i_max || hword <= i_min)
260 			errx(1, "integer out of range: %d < %d < %d",
261 			    i_min, abs(word) < abs(hword) ? word : hword, i_max);
262 		return (hword);
263 	}
264 	return (word);
265 }
266 
267 void
rebuild_message(char * db)268 rebuild_message(char *db)
269 {
270 	/* only for the default locate database */
271 	if (strcmp(_PATH_FCODES, db) == 0) {
272 		fprintf(stderr, "\nTo create a new database, please run the following command as root:\n\n");
273 		fprintf(stderr, "  /etc/periodic/weekly/310.locate\n\n");
274 	}
275 }
276 
277 int
check_size(char * db)278 check_size(char *db)
279 {
280         struct stat sb;
281         off_t len;
282 
283 	if (stat(db, &sb) == -1) {
284 		warnx("the locate database '%s' does not exist.", db);
285 		rebuild_message(db);
286 		return (0);
287 	}
288 	len = sb.st_size;
289 
290 	if (len < (2 * NBG)) {
291 		warnx("the locate database '%s' is smaller than %d bytes large.", db, (2 * NBG));
292 		rebuild_message(db);
293 		return (0);
294 	}
295 
296 	return (1);
297 }
298