2 * FreeBSD install - a package for the installation and maintainance
3 * of non-core utilities.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
17 * Routines used to query installed packages.
19 * $FreeBSD: src/usr.sbin/pkg_install/lib/match.c,v 1.2.2.8 2002/08/20 06:35:08 obrien Exp $
20 * $DragonFly: src/usr.sbin/pkg_install/lib/Attic/match.c,v 1.2 2003/06/17 04:29:59 dillon Exp $
30 * Simple structure representing argv-like
31 * NULL-terminated list.
39 static int rex_match(const char *, const char *);
40 struct store *storecreate(struct store *);
41 static int storeappend(struct store *, const char *);
42 static int fname_cmp(const FTSENT **, const FTSENT **);
45 * Function to query names of installed packages.
46 * MatchType - one of MATCH_ALL, MATCH_REGEX, MATCH_GLOB;
47 * patterns - NULL-terminated list of glob or regex patterns
48 * (could be NULL for MATCH_ALL);
49 * retval - return value (could be NULL if you don't want/need
51 * Returns NULL-terminated list with matching names.
52 * Names in list returned are dynamically allocated and should
53 * not be altered by the caller.
56 matchinstalled(match_t MatchType, char **patterns, int *retval)
60 const char *paths[2] = {LOG_DIR, NULL};
61 static struct store *store = NULL;
66 store = storecreate(store);
76 if (!isdir(paths[0])) {
83 /* Count number of patterns */
84 if (patterns != NULL) {
85 for (len = 0; patterns[len]; len++) {}
86 lmatched = alloca(sizeof(*lmatched) * len);
87 if (lmatched == NULL) {
88 warnx("%s(): alloca() failed", __func__);
96 for (i = 0; i < len; i++)
99 ftsp = fts_open((char * const *)(uintptr_t)paths, FTS_LOGICAL | FTS_NOCHDIR | FTS_NOSTAT, fname_cmp);
101 while ((f = fts_read(ftsp)) != NULL) {
102 if (f->fts_info == FTS_D && f->fts_level == 1) {
103 fts_set(ftsp, f, FTS_SKIP);
106 if (MatchType == MATCH_ALL)
107 matched = f->fts_name;
109 for (i = 0; patterns[i]; i++) {
112 errcode = rex_match(patterns[i], f->fts_name);
114 matched = f->fts_name;
119 if (fnmatch(patterns[i], f->fts_name, 0) == 0) {
120 matched = f->fts_name;
127 if (matched != NULL || errcode != 0)
130 if (errcode == 0 && matched != NULL)
131 errcode = storeappend(store, matched);
143 if (MatchType == MATCH_GLOB) {
144 for (i = 0; i < len; i++)
145 if (lmatched[i] == FALSE)
146 storeappend(store, patterns[i]);
149 if (store->used == 0)
156 * Synopsis is similar to matchinstalled(), but use origin
157 * as a key for matching packages.
160 matchbyorigin(const char *origin, int *retval)
164 static struct store *store = NULL;
166 store = storecreate(store);
176 installed = matchinstalled(MATCH_ALL, NULL, retval);
177 if (installed == NULL)
180 for (i = 0; installed[i] != NULL; i++) {
182 char *cp, tmp[PATH_MAX];
185 snprintf(tmp, PATH_MAX, "%s/%s", LOG_DIR, installed[i]);
187 * SPECIAL CASE: ignore empty dirs, since we can can see them
188 * during port installation.
192 snprintf(tmp, PATH_MAX, "%s/%s", tmp, CONTENTS_FNAME);
193 fp = fopen(tmp, "r");
202 while (fgets(tmp, sizeof(tmp), fp)) {
203 int len = strlen(tmp);
205 while (len && isspace(tmp[len - 1]))
210 if (tmp[0] != CMD_CHAR)
212 cmd = plist_cmd(tmp + 1, &cp);
213 if (cmd == PLIST_ORIGIN) {
214 if (strcmp(origin, cp) == 0)
215 storeappend(store, installed[i]);
219 if (cmd != PLIST_ORIGIN)
220 warnx("package %s has no origin recorded", installed[i]);
224 if (store->used == 0)
231 * Return TRUE if the specified package is installed,
232 * or FALSE otherwise.
235 isinstalledpkg(const char *name)
237 char buf[FILENAME_MAX];
239 snprintf(buf, sizeof(buf), "%s/%s", LOG_DIR, name);
240 if (!isdir(buf) || access(buf, R_OK) == FAIL)
243 snprintf(buf, sizeof(buf), "%s/%s", buf, CONTENTS_FNAME);
244 if (!isfile(buf) || access(buf, R_OK) == FAIL)
251 * Returns 1 if specified pkgname matches RE pattern.
252 * Otherwise returns 0 if doesn't match or -1 if RE
253 * engine reported an error (usually invalid syntax).
256 rex_match(const char *pattern, const char *pkgname)
265 errcode = regcomp(&rex, pattern, REG_BASIC | REG_NOSUB);
267 errcode = regexec(&rex, pkgname, 0, NULL, 0);
271 } else if (errcode != REG_NOMATCH) {
272 regerror(errcode, &rex, errbuf, sizeof(errbuf));
273 warnx("%s: %s", pattern, errbuf);
283 * Create an empty store, optionally deallocating
284 * any previously allocated space if store != NULL.
287 storecreate(struct store *store)
292 store = malloc(sizeof *store);
294 warnx("%s(): malloc() failed", __func__);
299 } else if (store->store != NULL) {
300 /* Free previously allocated memory */
301 for (i = 0; store->store[i] != NULL; i++)
302 free(store->store[i]);
303 store->store[0] = NULL;
311 * Append specified element to the provided store.
314 storeappend(struct store *store, const char *item)
316 if (store->used + 2 > store->currlen) {
317 store->currlen += 16;
318 store->store = reallocf(store->store,
319 store->currlen * sizeof(*(store->store)));
320 if (store->store == NULL) {
322 warnx("%s(): reallocf() failed", __func__);
327 asprintf(&(store->store[store->used]), "%s", item);
328 if (store->store[store->used] == NULL) {
329 warnx("%s(): malloc() failed", __func__);
333 store->store[store->used] = NULL;
339 fname_cmp(const FTSENT **a, const FTSENT **b)
341 return strcmp((*a)->fts_name, (*b)->fts_name);