match.c revision 80042
1#ifndef lint
2static const char rcsid[] =
3  "$FreeBSD: head/usr.sbin/pkg_install/lib/match.c 80042 2001-07-20 13:20:32Z sobomax $";
4#endif
5
6/*
7 * FreeBSD install - a package for the installation and maintainance
8 * of non-core utilities.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 *    notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 *    notice, this list of conditions and the following disclaimer in the
17 *    documentation and/or other materials provided with the distribution.
18 *
19 * Maxim Sobolev
20 * 24 February 2001
21 *
22 * Routines used to query installed packages.
23 *
24 */
25
26#include "lib.h"
27#include <err.h>
28#include <fnmatch.h>
29#include <fts.h>
30#include <regex.h>
31
32/*
33 * Simple structure representing argv-like
34 * NULL-terminated list.
35 */
36struct store {
37    int currlen;
38    int used;
39    char **store;
40};
41
42static int rex_match(char *, char *);
43static int storeappend(struct store *, const char *);
44static int fname_cmp(const FTSENT **, const FTSENT **);
45
46/*
47 * Function to query names of installed packages.
48 * MatchType	- one of MATCH_ALL, MATCH_REGEX, MATCH_GLOB;
49 * patterns	- NULL-terminated list of glob or regex patterns
50 *		  (could be NULL for MATCH_ALL);
51 * retval	- return value (could be NULL if you don't want/need
52 *		  return value).
53 * Returns NULL-terminated list with matching names.
54 * Names in list returned are dynamically allocated and should
55 * not be altered by the caller.
56 */
57char **
58matchinstalled(match_t MatchType, char **patterns, int *retval)
59{
60    int i, errcode, len;
61    char *tmp, *matched;
62    char *paths[2];
63    static struct store *store = NULL;
64    FTS *ftsp;
65    FTSENT *f;
66    Boolean *lmatched;
67
68    if (store == NULL) {
69	store = malloc(sizeof *store);
70	if (store == NULL) {
71	    warnx("%s(): malloc() failed", __FUNCTION__);
72	    if (retval != NULL)
73		*retval = 1;
74	    return NULL;
75	}
76	store->currlen = 0;
77	store->store = NULL;
78    } else
79	if (store->store != NULL)
80	    /* Free previously allocated memory */
81	    for (i = 0; store->store[i] != NULL; i++)
82		free(store->store[i]);
83    store->used = 0;
84
85    if (retval != NULL)
86	*retval = 0;
87
88    tmp = getenv(PKG_DBDIR);
89    if (!tmp)
90	tmp = DEF_LOG_DIR;
91    if (!isdir(tmp)) {
92	if (retval != NULL)
93	    *retval = 1;
94	return NULL;
95	/* Not reached */
96    }
97
98    /* Count number of patterns */
99    if (patterns != NULL) {
100	for (len = 0; patterns[len]; len++) {}
101	lmatched = alloca(sizeof(*lmatched) * len);
102	if (lmatched == NULL) {
103	    warnx("%s(): alloca() failed", __FUNCTION__);
104	    if (retval != NULL)
105		*retval = 1;
106	    return NULL;
107    	}
108    } else
109	len = 0;
110
111    for (i = 0; i < len; i++)
112	lmatched[i] = FALSE;
113
114    paths[0] = tmp;
115    paths[1] = NULL;
116    ftsp = fts_open(paths, FTS_LOGICAL | FTS_NOCHDIR | FTS_NOSTAT, fname_cmp);
117    if (ftsp != NULL) {
118	while ((f = fts_read(ftsp)) != NULL) {
119	    if (f->fts_info == FTS_D && f->fts_level == 1) {
120		fts_set(ftsp, f, FTS_SKIP);
121		matched = NULL;
122		errcode = 0;
123		if (MatchType == MATCH_ALL)
124		    matched = f->fts_name;
125		else
126		    for (i = 0; patterns[i]; i++) {
127			switch (MatchType) {
128			case MATCH_REGEX:
129			    errcode = rex_match(patterns[i], f->fts_name);
130			    if (errcode == 1) {
131				matched = f->fts_name;
132				errcode = 0;
133			    }
134			    break;
135			case MATCH_GLOB:
136			    if (fnmatch(patterns[i], f->fts_name, 0) == 0) {
137				matched = f->fts_name;
138				lmatched[i] = TRUE;
139			    }
140			    break;
141			default:
142			    break;
143			}
144			if (matched != NULL || errcode != 0)
145			    break;
146		    }
147		if (errcode == 0 && matched != NULL)
148		    errcode = storeappend(store, matched);
149		if (errcode != 0) {
150		    if (retval != NULL)
151			*retval = 1;
152		    return NULL;
153		    /* Not reached */
154		}
155	    }
156	}
157	fts_close(ftsp);
158    }
159
160    if (MatchType == MATCH_GLOB) {
161	for (i = 0; i < len; i++)
162	    if (lmatched[i] == FALSE)
163		storeappend(store, patterns[i]);
164    }
165
166    if (store->used == 0)
167	return NULL;
168    else
169	return store->store;
170}
171
172/*
173 * Returns 1 if specified pkgname matches RE pattern.
174 * Otherwise returns 0 if doesn't match or -1 if RE
175 * engine reported an error (usually invalid syntax).
176 */
177static int
178rex_match(char *pattern, char *pkgname)
179{
180    char errbuf[128];
181    int errcode;
182    int retval;
183    regex_t rex;
184
185    retval = 0;
186
187    errcode = regcomp(&rex, pattern, REG_BASIC | REG_NOSUB);
188    if (errcode == 0)
189	errcode = regexec(&rex, pkgname, 0, NULL, 0);
190
191    if (errcode == 0) {
192	retval = 1;
193    } else if (errcode != REG_NOMATCH) {
194	regerror(errcode, &rex, errbuf, sizeof(errbuf));
195	warnx("%s: %s", pattern, errbuf);
196	retval = -1;
197    }
198
199    regfree(&rex);
200
201    return retval;
202}
203
204static int
205storeappend(struct store *store, const char *item)
206{
207    if (store->used + 2 > store->currlen) {
208	store->currlen += 16;
209	store->store = reallocf(store->store,
210				store->currlen * sizeof(*(store->store)));
211	if (store->store == NULL) {
212	    store->currlen = 0;
213	    warnx("%s(): reallocf() failed", __FUNCTION__);
214	    return 1;
215	}
216    }
217
218    asprintf(&(store->store[store->used]), "%s", item);
219    if (store->store[store->used] == NULL) {
220	warnx("%s(): malloc() failed", __FUNCTION__);
221	return 1;
222    }
223    store->used++;
224    store->store[store->used] = NULL;
225
226    return 0;
227}
228
229static int
230fname_cmp(const FTSENT **a, const FTSENT **b)
231{
232    return strcmp((*a)->fts_name, (*b)->fts_name);
233}
234