Branch data Line data Source code
1 : : /*-
2 : : * Copyright (c) 2011-2022 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 <err.h>
37 : : #include <errno.h>
38 : : #include <getopt.h>
39 : : #include <pkg.h>
40 : : #include <stdio.h>
41 : : #include <stdlib.h>
42 : : #include <string.h>
43 : : #include <unistd.h>
44 : : #include <ctype.h>
45 : : #include <regex.h>
46 : : #include <tllist.h>
47 : :
48 : : #include "pkgcli.h"
49 : :
50 : : struct installed_ports {
51 : : char *origin;
52 : : };
53 : :
54 : : struct regex_cache {
55 : : char *pattern;
56 : : regex_t reg;
57 : : };
58 : :
59 : :
60 : : static void
61 : 8 : installed_ports_free(struct installed_ports *p)
62 : : {
63 [ + - ]: 8 : if (!p)
64 : 0 : return;
65 : 8 : free(p->origin);
66 : 8 : free(p);
67 : 8 : }
68 : :
69 : : static void
70 : 7 : regex_cache_free(struct regex_cache *p)
71 : : {
72 [ + - ]: 7 : if (!p)
73 : 0 : return;
74 : 7 : regfree(&p->reg);
75 : 7 : free(p->pattern);
76 : 7 : free(p);
77 : 7 : }
78 : :
79 : : void
80 : 0 : usage_updating(void)
81 : : {
82 : 0 : fprintf(stderr, "Usage: pkg updating [-i] [-d YYYYMMDD] [-f file] [portname ...]\n");
83 : 0 : fprintf(stderr, "For more information see 'pkg help updating'.\n");
84 : :
85 : 0 : }
86 : :
87 : : static char *
88 : 7 : convert_re(const char *src)
89 : : {
90 : : const char *p;
91 : : char *q;
92 : 7 : bool brace_flag = false;
93 : 7 : size_t len = strlen(src);
94 : 7 : char *buf = malloc(len*2+1);
95 [ + - ]: 7 : if (buf == NULL)
96 : 0 : return NULL;
97 : :
98 [ + + ]: 130 : for (p=src, q=buf; p < src+len; p++) {
99 [ + + + + : 123 : switch (*p) {
+ + + ]
100 : : case '*':
101 : 2 : *q++ = '.';
102 : 2 : *q++ = '*';
103 : 2 : break;
104 : : case '?':
105 : 2 : *q++ = '.';
106 : 2 : break;
107 : : case '.':
108 : 1 : *q++ = '\\';
109 : 1 : *q++ = '.';
110 : 1 : break;
111 : : case '{':
112 : 2 : *q++='(';
113 : 2 : brace_flag=true;
114 : 2 : break;
115 : : case ',':
116 [ + - ]: 4 : if (brace_flag)
117 : 4 : *q++='|';
118 : : else
119 : 0 : *q++=*p;
120 : 4 : break;
121 : : case '}':
122 : 2 : *q++=')';
123 : 2 : brace_flag=false;
124 : 2 : break;
125 : : default:
126 : 110 : *q++ = *p;
127 : 110 : }
128 : 123 : }
129 : 7 : *q ='\0';
130 : 7 : return buf;
131 : 7 : }
132 : :
133 : : int
134 : 9 : matcher(const char *affects, const char *origin, bool ignorecase)
135 : : {
136 : : int i, n, count, found, ret, rc;
137 : : bool was_spc;
138 : : size_t len;
139 : : char *re, *buf, *p, **words;
140 : : struct regex_cache *ent;
141 : 9 : tll(struct regex_cache *) cache = tll_init();
142 : :
143 : 9 : len = strlen(affects);
144 : 9 : buf = strdup(affects);
145 [ + - ]: 9 : if (buf == NULL)
146 : 0 : return 0;
147 : :
148 [ + + ]: 313 : for (count = 0, was_spc = true, p = buf; p < buf + len ; p++) {
149 [ + + ]: 304 : if (isspace(*p)) {
150 [ + + ]: 47 : if (!was_spc)
151 : 29 : was_spc = true;
152 : 47 : *p = '\0';
153 : 47 : } else {
154 [ + + ]: 257 : if (was_spc) {
155 : 29 : count++;
156 : 29 : was_spc = false;
157 : 29 : }
158 : : }
159 : 304 : }
160 : :
161 : 9 : words = malloc(sizeof(char*)*count);
162 [ + - ]: 9 : if (words == NULL) {
163 : 0 : free(buf);
164 : 0 : return 0;
165 : : }
166 : :
167 [ + + ]: 313 : for (i = 0, was_spc = true, p = buf; p < buf + len ; p++) {
168 [ + + ]: 304 : if (*p == '\0') {
169 [ + + ]: 47 : if (!was_spc)
170 : 29 : was_spc = true;
171 : 47 : } else {
172 [ + + ]: 257 : if (was_spc) {
173 : 29 : words[i++] = p;
174 : 29 : was_spc = false;
175 : 29 : }
176 : : }
177 : 304 : }
178 : :
179 [ + + ]: 29 : for(ret = 0, i = 0; i < count; i++) {
180 : 28 : n = strlen(words[i]);
181 [ + + ]: 28 : if (words[i][n-1] == ',') {
182 : 1 : words[i][n-1] = '\0';
183 : 1 : }
184 [ + + # # ]: 28 : if (strpbrk(words[i],"^$*|?") == NULL &&
185 [ + + + - ]: 24 : (strchr(words[i],'[') == NULL || strchr(words[i],']') == NULL) &&
186 [ + + - + ]: 23 : (strchr(words[i],'{') == NULL || strchr(words[i],'}') == NULL) &&
187 [ - + ]: 21 : (strchr(words[i],'(') == NULL || strchr(words[i],')') == NULL)) {
188 [ - + ]: 21 : if (ignorecase) {
189 [ # # ]: 0 : if (strcasecmp(words[i], origin) == 0) {
190 : 0 : ret = 1;
191 : 0 : break;
192 : : }
193 : 0 : } else {
194 [ + + ]: 21 : if (strcmp(words[i], origin) == 0) {
195 : 2 : ret = 1;
196 : 2 : break;
197 : : }
198 : : }
199 : 19 : continue;
200 : : }
201 : :
202 : 7 : found = 0;
203 [ - + + - : 7 : tll_foreach(cache, it) {
# # ]
204 [ # # ]: 0 : if (ignorecase)
205 : 0 : rc = strcasecmp(words[i], it->item->pattern);
206 : : else
207 : 0 : rc = strcmp(words[i], it->item->pattern);
208 [ # # ]: 0 : if (rc == 0) {
209 : 0 : found++;
210 [ # # ]: 0 : if (regexec(&it->item->reg, origin, 0, NULL, 0) == 0) {
211 : 0 : ret = 1;
212 : 0 : break;
213 : : }
214 : 0 : }
215 : 0 : }
216 [ - + ]: 7 : if (found == 0) {
217 [ - + ]: 7 : if ((ent = malloc(sizeof(struct regex_cache))) == NULL) {
218 : 0 : ret = 0;
219 : 0 : goto out;
220 : : }
221 [ - + ]: 7 : if ((ent->pattern = strdup(words[i])) == NULL) {
222 : 0 : regex_cache_free(ent);
223 : 0 : ret = 0;
224 : 0 : goto out;
225 : : }
226 : 7 : re = convert_re(words[i]);
227 [ - + ]: 7 : if (re == NULL) {
228 : 0 : regex_cache_free(ent);
229 : 0 : ret = 0;
230 : 0 : goto out;
231 : : }
232 : 7 : regcomp(&ent->reg, re, (ignorecase) ? REG_ICASE|REG_EXTENDED : REG_EXTENDED);
233 : 7 : free(re);
234 [ - + + - : 7 : tll_push_front(cache, ent);
# # - + -
+ ]
235 [ + + ]: 7 : if (regexec(&ent->reg, origin, 0, NULL, 0) == 0) {
236 : 6 : ret = 1;
237 : 6 : break;
238 : : }
239 : 1 : }
240 : 10 : }
241 : :
242 : : out:
243 [ + + + + : 16 : tll_foreach(cache, it)
- + ]
244 [ + - - + : 7 : tll_remove_and_free(cache, it, regex_cache_free);
- + ]
245 : 9 : free(words);
246 : 9 : free(buf);
247 : 9 : return (ret);
248 : 9 : }
249 : :
250 : : int
251 : 9 : exec_updating(int argc, char **argv)
252 : : {
253 : 9 : char *date = NULL;
254 : 9 : char *dateline = NULL;
255 : 9 : char *updatingfile = NULL;
256 : 9 : bool caseinsensitive = false;
257 : : struct installed_ports *port;
258 : 9 : tll(struct installed_ports *) origins = tll_init();
259 : : int ch;
260 : 9 : char *line = NULL;
261 : 9 : size_t linecap = 0;
262 : : char *tmp;
263 : 9 : int head = 0;
264 : 9 : int found = 0;
265 : 9 : struct pkgdb *db = NULL;
266 : 9 : struct pkg *pkg = NULL;
267 : 9 : struct pkgdb_it *it = NULL;
268 : : FILE *fd;
269 : 9 : int retcode = EXIT_SUCCESS;
270 : : #ifdef HAVE_CAPSICUM
271 : : cap_rights_t rights;
272 : : #endif
273 : :
274 : 9 : struct option longopts[] = {
275 : : { "date", required_argument, NULL, 'd' },
276 : : { "file", required_argument, NULL, 'f' },
277 : : { "case-insensitive", no_argument, NULL, 'i' },
278 : : { NULL, 0, NULL, 0 },
279 : : };
280 : :
281 [ + + ]: 18 : while ((ch = getopt_long(argc, argv, "+d:f:i", longopts, NULL)) != -1) {
282 [ - + - - ]: 9 : switch (ch) {
283 : : case 'd':
284 : 0 : date = optarg;
285 : 0 : break;
286 : : case 'f':
287 : 9 : updatingfile = optarg;
288 : 9 : break;
289 : : case 'i':
290 : 0 : caseinsensitive = true;
291 : 0 : break;
292 : : default:
293 : 0 : usage_updating();
294 : 0 : return (EXIT_FAILURE);
295 : : }
296 : : }
297 : 9 : argc -= optind;
298 : 9 : argv += optind;
299 : :
300 : : /* checking date format */
301 [ + - ]: 9 : if (date != NULL)
302 [ # # ]: 0 : if (strlen(date) != 8 || strspn(date, "0123456789") != 8)
303 : 0 : err(EXIT_FAILURE, "Invalid date format");
304 : :
305 [ - + ]: 9 : if (pkgdb_open(&db, PKGDB_DEFAULT) != EPKG_OK)
306 : 0 : return (EXIT_FAILURE);
307 : :
308 [ - + ]: 9 : if (pkgdb_obtain_lock(db, PKGDB_LOCK_READONLY) != EPKG_OK) {
309 : 0 : pkgdb_close(db);
310 : 0 : warnx("Cannot get a read lock on a database, it is locked by another process");
311 : 0 : return (EXIT_FAILURE);
312 : : }
313 : :
314 [ + - ]: 9 : if (updatingfile == NULL) {
315 : 0 : const char *portsdir = pkg_object_string(pkg_config_get("PORTSDIR"));
316 [ # # ]: 0 : if (portsdir == NULL) {
317 : 0 : retcode = EXIT_FAILURE;
318 : 0 : goto cleanup;
319 : : }
320 : 0 : asprintf(&updatingfile, "%s/UPDATING", portsdir);
321 : 0 : }
322 : :
323 : 9 : fd = fopen(updatingfile, "r");
324 [ + - ]: 9 : if (fd == NULL) {
325 : 0 : warnx("Unable to open: %s", updatingfile);
326 : 0 : goto cleanup;
327 : : }
328 : :
329 : : #ifdef HAVE_CAPSICUM
330 : : cap_rights_init(&rights, CAP_READ);
331 : : if (cap_rights_limit(fileno(fd), &rights) < 0 && errno != ENOSYS ) {
332 : : warn("cap_rights_limit() failed");
333 : : fclose(fd);
334 : : return (EXIT_FAILURE);
335 : : }
336 : :
337 : : #ifndef PKG_COVERAGE
338 : : if (cap_enter() < 0 && errno != ENOSYS) {
339 : : warn("cap_enter() failed");
340 : : fclose(fd);
341 : : return (EXIT_FAILURE);
342 : : }
343 : : #endif
344 : : #endif
345 : :
346 [ - + ]: 9 : if (argc == 0) {
347 [ + - ]: 9 : if ((it = pkgdb_query(db, NULL, MATCH_ALL)) == NULL) {
348 : 0 : retcode = EXIT_FAILURE;
349 : 0 : fclose(fd);
350 : 0 : goto cleanup;
351 : : }
352 : :
353 [ + + ]: 17 : while (pkgdb_it_next(it, &pkg, PKG_LOAD_BASIC) == EPKG_OK) {
354 : 8 : port = malloc(sizeof(struct installed_ports));
355 : 8 : pkg_asprintf(&port->origin, "%o", pkg);
356 [ - + + - : 8 : tll_push_front(origins, port);
# # - + -
+ ]
357 : : }
358 : 9 : } else {
359 [ # # ]: 0 : while (*argv) {
360 : 0 : port = malloc(sizeof(struct installed_ports));
361 : 0 : port->origin = strdup(*argv);
362 [ # # # # : 0 : tll_push_front(origins, port);
# # # # #
# ]
363 : 0 : argv++;
364 : : }
365 : : }
366 : :
367 [ + + ]: 65 : while (getline(&line, &linecap, fd) > 0) {
368 [ + + ]: 56 : if (strspn(line, "0123456789:") == 9) {
369 : 11 : free(dateline);
370 : 11 : dateline = strdup(line);
371 : 11 : found = 0;
372 : 11 : head = 1;
373 [ - + ]: 56 : } else if (head == 0) {
374 : 0 : continue;
375 : : }
376 : :
377 : 56 : tmp = NULL;
378 [ + + ]: 56 : if (found == 0) {
379 [ + + ]: 25 : if (strstr(line, "AFFECTS") != NULL) {
380 [ + + + + : 12 : tll_foreach(origins, it) {
- + ]
381 [ + + ]: 9 : if (matcher(line, it->item->origin, caseinsensitive) != 0) {
382 : 8 : tmp = "";
383 : 8 : break;
384 : : }
385 : 1 : }
386 [ + + ]: 11 : if (tmp == NULL)
387 : 3 : tmp = strcasestr(line, "all users\n");
388 [ + + ]: 11 : if (tmp == NULL)
389 : 2 : tmp = strcasestr(line, "all ports users\n");
390 [ + + ]: 11 : if (tmp != NULL) {
391 [ - + # # ]: 10 : if ((date != NULL) && strncmp(dateline, date, 8) < 0) {
392 : 0 : continue;
393 : : }
394 : 10 : printf("%s%s",dateline, line);
395 : 10 : found = 1;
396 : 10 : }
397 : 11 : }
398 : 25 : } else {
399 : 31 : printf("%s",line);
400 : : }
401 : : }
402 : 9 : fclose(fd);
403 : :
404 : : cleanup:
405 [ + + + + : 17 : tll_foreach(origins, it)
- + ]
406 [ + - - + : 8 : tll_remove_and_free(origins, it, installed_ports_free);
- + ]
407 : 9 : pkgdb_it_free(it);
408 : 9 : pkgdb_release_lock(db, PKGDB_LOCK_READONLY);
409 : 9 : pkgdb_close(db);
410 : 9 : pkg_free(pkg);
411 : 9 : free(line);
412 : 9 : free(dateline);
413 : :
414 : 9 : return (retcode);
415 : 9 : }
|