match.c revision 73134
1#ifndef lint 2static const char rcsid[] = 3 "$FreeBSD: head/usr.sbin/pkg_install/lib/match.c 73134 2001-02-27 09:00:18Z 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 28#include <err.h> 29#include <fnmatch.h> 30#include <fts.h> 31#include <regex.h> 32 33/* 34 * Simple structure representing argv-like 35 * NULL-terminated list. 36 */ 37struct store { 38 int currlen; 39 int used; 40 char **store; 41}; 42 43static int rex_match(char *, char *); 44static void storeappend(struct store *, const char *); 45static int fname_cmp(const FTSENT **, const FTSENT **); 46 47/* 48 * Function to query names of installed packages. 49 * MatchType - one of MATCH_ALL, MATCH_REGEX, MATCH_GLOB; 50 * patterns - NULL-terminated list of glob or regex patterns 51 * (could be NULL for MATCH_ALL); 52 * retval - return value (could be NULL if you don't want/need 53 * return value). 54 * Returns NULL-terminated list with matching names. 55 * Names in list returned are dynamically allocated and should 56 * not be altered by the caller. 57 */ 58char ** 59matchinstalled(match_t MatchType, char **patterns, int *retval) 60{ 61 int i, matched, errcode; 62 char *tmp; 63 char *paths[2]; 64 static struct store *store = NULL; 65 FTS *ftsp; 66 FTSENT *f; 67 68 if (store == NULL) { 69 store = malloc(sizeof *store); 70 store->currlen = 0; 71 store->store = NULL; 72 } else { 73 if (store->store != NULL) { 74 /* Free previously allocated memory */ 75 for (i = 0; store->store[i] != NULL; i++) 76 free(store->store[i]); 77 } 78 } 79 store->used = 0; 80 81 if (retval != NULL) 82 *retval = 0; 83 84 tmp = getenv(PKG_DBDIR); 85 if (!tmp) 86 tmp = DEF_LOG_DIR; 87 if (!isdir(tmp)) { 88 if (retval != NULL) 89 *retval = 1; 90 return NULL; 91 /* Not reached */ 92 } 93 94 paths[0] = tmp; 95 paths[1] = NULL; 96 ftsp = fts_open(paths, FTS_LOGICAL | FTS_NOCHDIR | FTS_NOSTAT, fname_cmp); 97 if (ftsp != NULL) { 98 while ((f = fts_read(ftsp)) != NULL) { 99 if (f->fts_info == FTS_D && f->fts_level == 1) { 100 fts_set(ftsp, f, FTS_SKIP); 101 if (MatchType == MATCH_ALL) { 102 storeappend(store, f->fts_name); 103 continue; 104 } 105 for (i = 0; patterns[i]; i++) { 106 matched = 0; 107 switch (MatchType) { 108 case MATCH_REGEX: 109 errcode = rex_match(patterns[i], f->fts_name); 110 if (errcode == 1) { 111 storeappend(store, f->fts_name); 112 matched = 1; 113 } else if (errcode == -1) { 114 if (retval != NULL) 115 *retval = 1; 116 return NULL; 117 /* Not reached */ 118 } 119 break; 120 case MATCH_GLOB: 121 if (fnmatch(patterns[i], f->fts_name, 0) == 0) { 122 storeappend(store, f->fts_name); 123 matched = 1; 124 } 125 break; 126 default: 127 break; 128 } 129 if (matched == 1) 130 break; 131 } 132 } 133 } 134 fts_close(ftsp); 135 } 136 137 if (store->used == 0) 138 return NULL; 139 else 140 return store->store; 141} 142 143/* 144 * Returns 1 if specified pkgname matches RE pattern. 145 * Otherwise returns 0 if doesn't match or -1 if RE 146 * engine reported an error (usually invalid syntax). 147 */ 148static int 149rex_match(char *pattern, char *pkgname) 150{ 151 char errbuf[128]; 152 int errcode; 153 int retval; 154 regex_t rex; 155 156 retval = 0; 157 158 errcode = regcomp(&rex, pattern, REG_BASIC | REG_NOSUB); 159 if (errcode == 0) 160 errcode = regexec(&rex, pkgname, 0, NULL, 0); 161 162 if (errcode == 0) { 163 retval = 1; 164 } else if (errcode != REG_NOMATCH) { 165 regerror(errcode, &rex, errbuf, sizeof(errbuf)); 166 warnx("%s: %s", pattern, errbuf); 167 retval = -1; 168 } 169 170 regfree(&rex); 171 172 return retval; 173} 174 175static void 176storeappend(struct store *store, const char *item) 177{ 178 char **tmp; 179 180 if (store->used + 2 > store->currlen) { 181 tmp = store->store; 182 store->currlen += 16; 183 store->store = malloc(store->currlen * sizeof(*(store->store))); 184 memcpy(store->store, tmp, store->used * sizeof(*(store->store))); 185 free(tmp); 186 } 187 188 asprintf(&(store->store[store->used]), "%s", item); 189 store->used++; 190 store->store[store->used] = NULL; 191} 192 193static int 194fname_cmp(const FTSENT **a, const FTSENT **b) 195{ 196 return strcmp((*a)->fts_name, (*b)->fts_name); 197} 198