]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - usr.sbin/pkg_install/lib/match.c
This commit was generated by cvs2svn to compensate for changes in r90792,
[FreeBSD/FreeBSD.git] / usr.sbin / pkg_install / lib / match.c
1 #ifndef lint
2 static const char rcsid[] =
3   "$FreeBSD$";
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  */
36 struct store {
37     int currlen;
38     int used;
39     char **store;
40 };
41
42 static int rex_match(const char *, const char *);
43 static int storeappend(struct store *, const char *);
44 static 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  */
57 char **
58 matchinstalled(match_t MatchType, char **patterns, int *retval)
59 {
60     int i, errcode, len;
61     char *matched;
62     const char *paths[2] = {LOG_DIR, NULL};
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     if (!isdir(paths[0])) {
89         if (retval != NULL)
90             *retval = 1;
91         return NULL;
92         /* Not reached */
93     }
94
95     /* Count number of patterns */
96     if (patterns != NULL) {
97         for (len = 0; patterns[len]; len++) {}
98         lmatched = alloca(sizeof(*lmatched) * len);
99         if (lmatched == NULL) {
100             warnx("%s(): alloca() failed", __FUNCTION__);
101             if (retval != NULL)
102                 *retval = 1;
103             return NULL;
104         } 
105     } else
106         len = 0;
107     
108     for (i = 0; i < len; i++)
109         lmatched[i] = FALSE;
110
111     ftsp = fts_open((char * const *)(uintptr_t)paths, FTS_LOGICAL | FTS_NOCHDIR | FTS_NOSTAT, fname_cmp);
112     if (ftsp != NULL) {
113         while ((f = fts_read(ftsp)) != NULL) {
114             if (f->fts_info == FTS_D && f->fts_level == 1) {
115                 fts_set(ftsp, f, FTS_SKIP);
116                 matched = NULL;
117                 errcode = 0;
118                 if (MatchType == MATCH_ALL)
119                     matched = f->fts_name;
120                 else 
121                     for (i = 0; patterns[i]; i++) {
122                         switch (MatchType) {
123                         case MATCH_REGEX:
124                             errcode = rex_match(patterns[i], f->fts_name);
125                             if (errcode == 1) {
126                                 matched = f->fts_name;
127                                 errcode = 0;
128                             }
129                             break;
130                         case MATCH_GLOB:
131                             if (fnmatch(patterns[i], f->fts_name, 0) == 0) {
132                                 matched = f->fts_name;
133                                 lmatched[i] = TRUE;
134                             }
135                             break;
136                         default:
137                             break;
138                         }
139                         if (matched != NULL || errcode != 0)
140                             break;
141                     }
142                 if (errcode == 0 && matched != NULL)
143                     errcode = storeappend(store, matched);
144                 if (errcode != 0) {
145                     if (retval != NULL)
146                         *retval = 1;
147                     return NULL;
148                     /* Not reached */
149                 }
150             }
151         }
152         fts_close(ftsp);
153     }
154
155     if (MatchType == MATCH_GLOB) {
156         for (i = 0; i < len; i++)
157             if (lmatched[i] == FALSE)
158                 storeappend(store, patterns[i]);
159     }
160
161     if (store->used == 0)
162         return NULL;
163     else
164         return store->store;
165 }
166
167 /*
168  * Returns 1 if specified pkgname matches RE pattern.
169  * Otherwise returns 0 if doesn't match or -1 if RE
170  * engine reported an error (usually invalid syntax).
171  */
172 static int
173 rex_match(const char *pattern, const char *pkgname)
174 {
175     char errbuf[128];
176     int errcode;
177     int retval;
178     regex_t rex;
179
180     retval = 0;
181
182     errcode = regcomp(&rex, pattern, REG_BASIC | REG_NOSUB);
183     if (errcode == 0)
184         errcode = regexec(&rex, pkgname, 0, NULL, 0);
185
186     if (errcode == 0) {
187         retval = 1;
188     } else if (errcode != REG_NOMATCH) {
189         regerror(errcode, &rex, errbuf, sizeof(errbuf));
190         warnx("%s: %s", pattern, errbuf);
191         retval = -1;
192     }
193
194     regfree(&rex);
195
196     return retval;
197 }
198
199 static int
200 storeappend(struct store *store, const char *item)
201 {
202     if (store->used + 2 > store->currlen) {
203         store->currlen += 16;
204         store->store = reallocf(store->store,
205                                 store->currlen * sizeof(*(store->store)));
206         if (store->store == NULL) {
207             store->currlen = 0;
208             warnx("%s(): reallocf() failed", __FUNCTION__);
209             return 1;
210         }
211     }
212
213     asprintf(&(store->store[store->used]), "%s", item);
214     if (store->store[store->used] == NULL) {
215         warnx("%s(): malloc() failed", __FUNCTION__);
216         return 1;
217     }
218     store->used++;
219     store->store[store->used] = NULL;
220
221     return 0;
222 }
223
224 static int
225 fname_cmp(const FTSENT **a, const FTSENT **b)
226 {
227     return strcmp((*a)->fts_name, (*b)->fts_name);
228 }