Branch data Line data Source code
1 : : /*-
2 : : * Copyright (c) 2011-2012 Baptiste Daroussin <bapt@FreeBSD.org>
3 : : * Copyright (c) 2014 Matthew Seaman <matthew@FreeBSD.org>
4 : : * All rights reserved.
5 : : *
6 : : * Redistribution and use in source and binary forms, with or without
7 : : * modification, are permitted provided that the following conditions
8 : : * are met:
9 : : * 1. Redistributions of source code must retain the above copyright
10 : : * notice, this list of conditions and the following disclaimer
11 : : * in this position and unchanged.
12 : : * 2. Redistributions in binary form must reproduce the above copyright
13 : : * notice, this list of conditions and the following disclaimer in the
14 : : * documentation and/or other materials provided with the distribution.
15 : : *
16 : : * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
17 : : * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18 : : * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19 : : * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
20 : : * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21 : : * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22 : : * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23 : : * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 : : * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25 : : * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 : : */
27 : :
28 : : #ifdef HAVE_CONFIG_H
29 : : #include "pkg_config.h"
30 : : #endif
31 : :
32 : : #ifdef HAVE_CAPSICUM
33 : : #include <sys/capsicum.h>
34 : : #endif
35 : :
36 : : #include <sys/queue.h>
37 : :
38 : : #include <err.h>
39 : : #include <errno.h>
40 : : #include <getopt.h>
41 : : #include <pkg.h>
42 : : #include <stdio.h>
43 : : #include <stdlib.h>
44 : : #include <string.h>
45 : : #include <unistd.h>
46 : : #include <ctype.h>
47 : : #include <regex.h>
48 : :
49 : : #include "pkgcli.h"
50 : :
51 : : struct installed_ports {
52 : : char *origin;
53 : : SLIST_ENTRY(installed_ports) next;
54 : : };
55 : :
56 : : struct regex_cache {
57 : : char *pattern;
58 : : regex_t reg;
59 : : SLIST_ENTRY(regex_cache) next;
60 : : };
61 : :
62 : : void
63 : 0 : usage_updating(void)
64 : : {
65 : 0 : fprintf(stderr, "Usage: pkg updating [-i] [-d YYYYMMDD] [-f file] [portname ...]\n");
66 : 0 : fprintf(stderr, "For more information see 'pkg help updating'.\n");
67 : :
68 : 0 : }
69 : :
70 : : static char *
71 : 28 : convert_re(const char *src)
72 : : {
73 : : const char *p;
74 : : char *q;
75 : 28 : bool brace_flag = false;
76 : 28 : size_t len = strlen(src);
77 : 28 : char *buf = malloc(len*2+1);
78 [ - + ]: 28 : if (buf == NULL)
79 : 0 : return NULL;
80 : :
81 [ + + ]: 704 : for (p=src, q=buf; p < src+len; p++) {
82 [ + + + + : 676 : switch (*p) {
+ + + ]
83 : : case '*':
84 : 8 : *q++ = '.';
85 : 8 : *q++ = '*';
86 : 8 : break;
87 : : case '?':
88 : 8 : *q++ = '.';
89 : 8 : break;
90 : : case '.':
91 : 4 : *q++ = '\\';
92 : 4 : *q++ = '.';
93 : 4 : break;
94 : : case '{':
95 : 8 : *q++='(';
96 : 8 : brace_flag=true;
97 : 8 : break;
98 : : case ',':
99 [ + - ]: 16 : if (brace_flag)
100 : 16 : *q++='|';
101 : : else
102 : 0 : *q++=*p;
103 : 16 : break;
104 : : case '}':
105 : 8 : *q++=')';
106 : 8 : brace_flag=false;
107 : 8 : break;
108 : : default:
109 : 624 : *q++ = *p;
110 : 624 : }
111 : 676 : }
112 : 28 : *q ='\0';
113 : 28 : return buf;
114 : 28 : }
115 : :
116 : : int
117 : 36 : matcher(const char *affects, const char *origin, bool ignorecase)
118 : : {
119 : : int i, n, count, found, ret, rc;
120 : : bool was_spc;
121 : : size_t len;
122 : : char *re, *buf, *p, **words;
123 : : struct regex_cache *ent;
124 : : static SLIST_HEAD(,regex_cache) cache = SLIST_HEAD_INITIALIZER(regex_cache);
125 : :
126 : 36 : len = strlen(affects);
127 : 36 : buf = strdup(affects);
128 [ + - ]: 36 : if (buf == NULL)
129 : 0 : return 0;
130 : :
131 [ + + ]: 1516 : for (count = 0, was_spc = true, p = buf; p < buf + len ; p++) {
132 [ + + ]: 1480 : if (isspace(*p)) {
133 [ + + ]: 188 : if (!was_spc)
134 : 116 : was_spc = true;
135 : 188 : *p = '\0';
136 : 188 : } else {
137 [ + + ]: 1292 : if (was_spc) {
138 : 116 : count++;
139 : 116 : was_spc = false;
140 : 116 : }
141 : : }
142 : 1480 : }
143 : :
144 : 36 : words = malloc(sizeof(char*)*count);
145 [ + - ]: 36 : if (words == NULL) {
146 : 0 : free(buf);
147 : 0 : return 0;
148 : : }
149 : :
150 [ + + ]: 1516 : for (i = 0, was_spc = true, p = buf; p < buf + len ; p++) {
151 [ + + ]: 1480 : if (*p == '\0') {
152 [ + + ]: 188 : if (!was_spc)
153 : 116 : was_spc = true;
154 : 188 : } else {
155 [ + + ]: 1292 : if (was_spc) {
156 : 116 : words[i++] = p;
157 : 116 : was_spc = false;
158 : 116 : }
159 : : }
160 : 1480 : }
161 : :
162 [ + + ]: 116 : for(ret = 0, i = 0; i < count; i++) {
163 : 112 : n = strlen(words[i]);
164 [ + + ]: 112 : if (words[i][n-1] == ',') {
165 : 4 : words[i][n-1] = '\0';
166 : 4 : }
167 [ + + ]: 112 : if (strpbrk(words[i],"^$*|?") == NULL &&
168 [ + + + - ]: 96 : (strchr(words[i],'[') == NULL || strchr(words[i],']') == NULL) &&
169 [ + + ]: 92 : (strchr(words[i],'{') == NULL || strchr(words[i],'}') == NULL) &&
170 [ - + ]: 84 : (strchr(words[i],'(') == NULL || strchr(words[i],')') == NULL)) {
171 [ - + ]: 84 : if (ignorecase) {
172 [ # # ]: 0 : if (strcasecmp(words[i], origin) == 0) {
173 : 0 : ret = 1;
174 : 0 : break;
175 : : }
176 : 0 : } else {
177 [ + + ]: 84 : if (strcmp(words[i], origin) == 0) {
178 : 8 : ret = 1;
179 : 8 : break;
180 : : }
181 : : }
182 : 76 : continue;
183 : : }
184 : :
185 : 28 : found = 0;
186 [ + + ]: 32 : SLIST_FOREACH(ent, &cache, next) {
187 [ - + ]: 4 : if (ignorecase)
188 : 0 : rc = strcasecmp(words[i], ent->pattern);
189 : : else
190 : 4 : rc = strcmp(words[i], ent->pattern);
191 [ + - ]: 4 : if (rc == 0) {
192 : 0 : found++;
193 [ # # ]: 0 : if (regexec(&ent->reg, origin, 0, NULL, 0) == 0) {
194 : 0 : ret = 1;
195 : 0 : break;
196 : : }
197 : 0 : }
198 : 4 : }
199 [ - + ]: 28 : if (found == 0) {
200 : 28 : ent = malloc(sizeof(struct regex_cache));
201 [ + - ]: 28 : if (ent == NULL)
202 : 0 : goto err;
203 [ + - ]: 28 : if ((ent->pattern = strdup(words[i])) == NULL) {
204 : 0 : free(ent);
205 : 0 : goto err;
206 : : }
207 : 28 : re = convert_re(words[i]);
208 [ + - ]: 28 : if (re == NULL) {
209 : 0 : free(ent->pattern);
210 : 0 : free(ent);
211 : 0 : goto err;
212 : : }
213 : 28 : regcomp(&ent->reg, re, (ignorecase) ? REG_ICASE|REG_EXTENDED : REG_EXTENDED);
214 : 28 : free(re);
215 : 28 : SLIST_INSERT_HEAD(&cache, ent, next);
216 [ + + ]: 28 : if (regexec(&ent->reg, origin, 0, NULL, 0) == 0) {
217 : 24 : ret = 1;
218 : 24 : break;
219 : : }
220 : 4 : }
221 : 4 : }
222 : :
223 : 36 : free(words);
224 : 36 : free(buf);
225 : 36 : return ret;
226 : : err:
227 : 0 : free(words);
228 : 0 : free(buf);
229 : 0 : return 0;
230 : 36 : }
231 : :
232 : : int
233 : 36 : exec_updating(int argc, char **argv)
234 : : {
235 : 36 : char *date = NULL;
236 : 36 : char *dateline = NULL;
237 : 36 : char *updatingfile = NULL;
238 : 36 : bool caseinsensitive = false;
239 : : struct installed_ports *port;
240 : : SLIST_HEAD(,installed_ports) origins;
241 : : int ch;
242 : 36 : char *line = NULL;
243 : 36 : size_t linecap = 0;
244 : : char *tmp;
245 : 36 : int head = 0;
246 : 36 : int found = 0;
247 : 36 : struct pkgdb *db = NULL;
248 : 36 : struct pkg *pkg = NULL;
249 : 36 : struct pkgdb_it *it = NULL;
250 : : FILE *fd;
251 : 36 : int retcode = EXIT_SUCCESS;
252 : : #ifdef HAVE_CAPSICUM
253 : : cap_rights_t rights;
254 : : #endif
255 : :
256 : 36 : struct option longopts[] = {
257 : : { "date", required_argument, NULL, 'd' },
258 : : { "file", required_argument, NULL, 'f' },
259 : : { "case-insensitive", no_argument, NULL, 'i' },
260 : : { NULL, 0, NULL, 0 },
261 : : };
262 : :
263 [ + + ]: 72 : while ((ch = getopt_long(argc, argv, "+d:f:i", longopts, NULL)) != -1) {
264 [ - + - - ]: 36 : switch (ch) {
265 : : case 'd':
266 : 0 : date = optarg;
267 : 0 : break;
268 : : case 'f':
269 : 36 : updatingfile = optarg;
270 : 36 : break;
271 : : case 'i':
272 : 0 : caseinsensitive = true;
273 : 0 : break;
274 : : default:
275 : 0 : usage_updating();
276 : 0 : return (EXIT_FAILURE);
277 : : }
278 : : }
279 : 36 : argc -= optind;
280 : 36 : argv += optind;
281 : :
282 : : /* checking date format */
283 [ + - ]: 36 : if (date != NULL)
284 [ # # ]: 0 : if (strlen(date) != 8 || strspn(date, "0123456789") != 8)
285 : 0 : err(EXIT_FAILURE, "Invalid date format");
286 : :
287 [ - + ]: 36 : if (pkgdb_open(&db, PKGDB_DEFAULT) != EPKG_OK)
288 : 0 : return (EXIT_FAILURE);
289 : :
290 [ - + ]: 36 : if (pkgdb_obtain_lock(db, PKGDB_LOCK_READONLY) != EPKG_OK) {
291 : 0 : pkgdb_close(db);
292 : 0 : warnx("Cannot get a read lock on a database, it is locked by another process");
293 : 0 : return (EXIT_FAILURE);
294 : : }
295 : :
296 [ + - ]: 36 : if (updatingfile == NULL) {
297 : 0 : const char *portsdir = pkg_object_string(pkg_config_get("PORTSDIR"));
298 [ # # ]: 0 : if (portsdir == NULL) {
299 : 0 : retcode = EXIT_FAILURE;
300 : 0 : goto cleanup;
301 : : }
302 : 0 : asprintf(&updatingfile, "%s/UPDATING", portsdir);
303 : 0 : }
304 : :
305 : 36 : fd = fopen(updatingfile, "r");
306 [ + - ]: 36 : if (fd == NULL) {
307 : 0 : warnx("Unable to open: %s", updatingfile);
308 : 0 : goto cleanup;
309 : : }
310 : :
311 : : #ifdef HAVE_CAPSICUM
312 : 36 : cap_rights_init(&rights, CAP_READ);
313 [ - + - + : 36 : if (cap_rights_limit(fileno(fd), &rights) < 0 && errno != ENOSYS ) {
# # ]
314 : 0 : warn("cap_rights_limit() failed");
315 : 0 : fclose(fd);
316 : 0 : return (EXIT_FAILURE);
317 : : }
318 : :
319 : : #ifndef PKG_COVERAGE
320 : : if (cap_enter() < 0 && errno != ENOSYS) {
321 : : warn("cap_enter() failed");
322 : : fclose(fd);
323 : : return (EXIT_FAILURE);
324 : : }
325 : : #endif
326 : : #endif
327 : :
328 : 36 : SLIST_INIT(&origins);
329 [ - + ]: 36 : if (argc == 0) {
330 [ + - ]: 36 : if ((it = pkgdb_query(db, NULL, MATCH_ALL)) == NULL) {
331 : 0 : retcode = EXIT_FAILURE;
332 : 0 : fclose(fd);
333 : 0 : goto cleanup;
334 : : }
335 : :
336 [ + + ]: 68 : while (pkgdb_it_next(it, &pkg, PKG_LOAD_BASIC) == EPKG_OK) {
337 : 32 : port = malloc(sizeof(struct installed_ports));
338 : 32 : pkg_asprintf(&port->origin, "%o", pkg);
339 : 32 : SLIST_INSERT_HEAD(&origins, port, next);
340 : : }
341 : 36 : } else {
342 [ # # ]: 0 : while (*argv) {
343 : 0 : port = malloc(sizeof(struct installed_ports));
344 : 0 : port->origin = strdup(*argv);
345 : 0 : SLIST_INSERT_HEAD(&origins, port, next);
346 : 0 : argv++;
347 : : }
348 : : }
349 : :
350 [ + + ]: 260 : while (getline(&line, &linecap, fd) > 0) {
351 [ + + ]: 224 : if (strspn(line, "0123456789:") == 9) {
352 : 44 : dateline = strdup(line);
353 : 44 : found = 0;
354 : 44 : head = 1;
355 [ + - ]: 224 : } else if (head == 0) {
356 : 0 : continue;
357 : : }
358 : :
359 : 224 : tmp = NULL;
360 [ + + ]: 224 : if (found == 0) {
361 [ + + ]: 100 : if (strstr(line, "AFFECTS") != NULL) {
362 [ + + ]: 48 : SLIST_FOREACH(port, &origins, next) {
363 [ + + ]: 36 : if (matcher(line, port->origin, caseinsensitive) != 0) {
364 : 32 : tmp = "";
365 : 32 : break;
366 : : }
367 : 4 : }
368 [ + + ]: 44 : if (tmp == NULL)
369 : 12 : tmp = strcasestr(line, "all users\n");
370 [ + + ]: 44 : if (tmp == NULL)
371 : 8 : tmp = strcasestr(line, "all ports users\n");
372 [ + + ]: 44 : if (tmp != NULL) {
373 [ - + # # ]: 40 : if ((date != NULL) && strncmp(dateline, date, 8) < 0) {
374 : 0 : continue;
375 : : }
376 : 40 : printf("%s%s",dateline, line);
377 : 40 : found = 1;
378 : 40 : }
379 : 44 : }
380 : 100 : } else {
381 : 124 : printf("%s",line);
382 : : }
383 : : }
384 : 36 : fclose(fd);
385 : :
386 : : cleanup:
387 : 36 : pkgdb_it_free(it);
388 : 36 : pkgdb_release_lock(db, PKGDB_LOCK_READONLY);
389 : 36 : pkgdb_close(db);
390 : 36 : pkg_free(pkg);
391 : 36 : free(dateline);
392 : :
393 : 36 : return (retcode);
394 : 36 : }
|