Branch data Line data Source code
1 : : /*-
2 : : * Copyright (c) 2011-2012 Baptiste Daroussin <bapt@FreeBSD.org>
3 : : * Copyright (c) 2011-2012 Marin Atanasov Nikolov <dnaeon@gmail.com>
4 : : * Copyright (c) 2012 Bryan Drewery <bryan@shatow.net>
5 : : * Copyright (c) 2013-2014 Matthew Seaman <matthew@FreeBSD.org>
6 : : * All rights reserved.
7 : : *
8 : : * Redistribution and use in source and binary forms, with or without
9 : : * modification, are permitted provided that the following conditions
10 : : * are met:
11 : : * 1. Redistributions of source code must retain the above copyright
12 : : * notice, this list of conditions and the following disclaimer
13 : : * in this position and unchanged.
14 : : * 2. Redistributions in binary form must reproduce the above copyright
15 : : * notice, this list of conditions and the following disclaimer in the
16 : : * documentation and/or other materials provided with the distribution.
17 : : *
18 : : * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
19 : : * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20 : : * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21 : : * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
22 : : * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23 : : * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 : : * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 : : * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 : : * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27 : : * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 : : */
29 : :
30 : : #include <sys/types.h>
31 : :
32 : : #include <ctype.h>
33 : : #include <err.h>
34 : : #include <getopt.h>
35 : : #include <inttypes.h>
36 : : #include <stdio.h>
37 : : #include <stdlib.h>
38 : : #include <string.h>
39 : : #include <unistd.h>
40 : :
41 : : #include <pkg.h>
42 : : #include "pkgcli.h"
43 : :
44 : : static struct query_flags accepted_query_flags[] = {
45 : : { 'd', "nov", 1, PKG_LOAD_DEPS },
46 : : { 'r', "nov", 1, PKG_LOAD_RDEPS },
47 : : { 'C', "", 1, PKG_LOAD_CATEGORIES },
48 : : { 'F', "ps", 1, PKG_LOAD_FILES },
49 : : { 'O', "kvdD", 1, PKG_LOAD_OPTIONS },
50 : : { 'D', "", 1, PKG_LOAD_DIRS },
51 : : { 'L', "", 1, PKG_LOAD_LICENSES },
52 : : { 'U', "", 1, PKG_LOAD_USERS },
53 : : { 'G', "", 1, PKG_LOAD_GROUPS },
54 : : { 'B', "", 1, PKG_LOAD_SHLIBS_REQUIRED },
55 : : { 'b', "", 1, PKG_LOAD_SHLIBS_PROVIDED },
56 : : { 'A', "tv", 1, PKG_LOAD_ANNOTATIONS },
57 : : { '?', "drCFODLUGBbA", 1, PKG_LOAD_BASIC }, /* dbflags handled in analyse_query_string() */
58 : : { '#', "drCFODLUGBbA", 1, PKG_LOAD_BASIC }, /* dbflags handled in analyse_query_string() */
59 : : { 's', "hb", 0, PKG_LOAD_BASIC },
60 : : { 'Q', "", 0, PKG_LOAD_BASIC },
61 : : { 'n', "", 0, PKG_LOAD_BASIC },
62 : : { 'v', "", 0, PKG_LOAD_BASIC },
63 : : { 'o', "", 0, PKG_LOAD_BASIC },
64 : : { 'p', "", 0, PKG_LOAD_BASIC },
65 : : { 'm', "", 0, PKG_LOAD_BASIC },
66 : : { 'c', "", 0, PKG_LOAD_BASIC },
67 : : { 'e', "", 0, PKG_LOAD_BASIC },
68 : : { 'w', "", 0, PKG_LOAD_BASIC },
69 : : { 'l', "", 0, PKG_LOAD_BASIC },
70 : : { 'q', "", 0, PKG_LOAD_BASIC },
71 : : { 'a', "", 0, PKG_LOAD_BASIC },
72 : : { 'k', "", 0, PKG_LOAD_BASIC },
73 : : { 'M', "", 0, PKG_LOAD_BASIC },
74 : : { 't', "", 0, PKG_LOAD_BASIC },
75 : : { 'R', "", 0, PKG_LOAD_ANNOTATIONS },
76 : : { 'V', "", 0, PKG_LOAD_BASIC },
77 : : { 'X', "", 0, PKG_LOAD_BASIC | PKG_LOAD_SCRIPTS | PKG_LOAD_LUA_SCRIPTS },
78 : : };
79 : :
80 : : static void
81 : 44 : format_str(struct pkg *pkg, xstring *dest, const char *qstr, const void *data)
82 : : {
83 : 44 : bool automatic = false;
84 : 44 : bool locked = false;
85 : 44 : bool vital = false;
86 : :
87 : 44 : xstring_reset(dest);
88 : :
89 [ + + ]: 143 : while (qstr[0] != '\0') {
90 [ + + ]: 99 : if (qstr[0] == '%') {
91 : 68 : qstr++;
92 [ - - + + : 68 : switch (qstr[0]) {
- - - - +
- + - - -
- + + - -
- + + - +
- - - - -
- - - + +
- ]
93 : : case 'n':
94 : 18 : pkg_fprintf(dest->fp, "%n", pkg);
95 : 18 : break;
96 : : case 'v':
97 : 7 : pkg_fprintf(dest->fp, "%v", pkg);
98 : 7 : break;
99 : : case 'o':
100 : 0 : pkg_fprintf(dest->fp, "%o", pkg);
101 : 0 : break;
102 : : case 'R':
103 : 0 : pkg_fprintf(dest->fp, "%N", pkg);
104 : 0 : break;
105 : : case 'p':
106 : 0 : pkg_fprintf(dest->fp, "%p", pkg);
107 : 0 : break;
108 : : case 'm':
109 : 0 : pkg_fprintf(dest->fp, "%m", pkg);
110 : 0 : break;
111 : : case 'c':
112 : 2 : pkg_fprintf(dest->fp, "%c", pkg);
113 : 2 : break;
114 : : case 'w':
115 : 0 : pkg_fprintf(dest->fp, "%w", pkg);
116 : 0 : break;
117 : : case 'a':
118 : 5 : pkg_get(pkg, PKG_ATTR_AUTOMATIC, &automatic);
119 : 5 : fprintf(dest->fp, "%d", automatic);
120 : 5 : break;
121 : : case 'k':
122 : 0 : pkg_get(pkg, PKG_ATTR_LOCKED, &locked);
123 : 0 : fprintf(dest->fp, "%d", locked);
124 : 0 : break;
125 : : case 't':
126 : 0 : pkg_fprintf(dest->fp, "%t", pkg);
127 : 0 : break;
128 : : case 's':
129 : 0 : qstr++;
130 [ # # ]: 0 : if (qstr[0] == 'h')
131 : 0 : pkg_fprintf(dest->fp, "%#sB", pkg);
132 [ # # ]: 0 : else if (qstr[0] == 'b')
133 : 0 : pkg_fprintf(dest->fp, "%s", pkg);
134 : 0 : break;
135 : : case 'e':
136 : 0 : pkg_fprintf(dest->fp, "%e", pkg);
137 : 0 : break;
138 : : case '?':
139 : 2 : qstr++;
140 [ + - - - : 2 : switch (qstr[0]) {
- - + - -
- - - - ]
141 : : case 'd':
142 : 0 : pkg_fprintf(dest->fp, "%?d", pkg);
143 : 0 : break;
144 : : case 'r':
145 : 0 : pkg_fprintf(dest->fp, "%?r", pkg);
146 : 0 : break;
147 : : case 'C':
148 : 0 : pkg_fprintf(dest->fp, "%?C", pkg);
149 : 0 : break;
150 : : case 'F':
151 : 1 : pkg_fprintf(dest->fp, "%?F", pkg);
152 : 1 : break;
153 : : case 'O':
154 : 1 : pkg_fprintf(dest->fp, "%?O", pkg);
155 : 1 : break;
156 : : case 'D':
157 : 0 : pkg_fprintf(dest->fp, "%?D", pkg);
158 : 0 : break;
159 : : case 'L':
160 : 0 : pkg_fprintf(dest->fp, "%?L", pkg);
161 : 0 : break;
162 : : case 'U':
163 : 0 : pkg_fprintf(dest->fp, "%?U", pkg);
164 : 0 : break;
165 : : case 'G':
166 : 0 : pkg_fprintf(dest->fp, "%?G", pkg);
167 : 0 : break;
168 : : case 'B':
169 : 0 : pkg_fprintf(dest->fp, "%?B", pkg);
170 : 0 : break;
171 : : case 'b':
172 : 0 : pkg_fprintf(dest->fp, "%?b", pkg);
173 : 0 : break;
174 : : case 'A':
175 : 0 : pkg_fprintf(dest->fp, "%?A", pkg);
176 : 0 : break;
177 : : }
178 : 2 : break;
179 : : case '#':
180 : 2 : qstr++;
181 [ + - - - : 2 : switch (qstr[0]) {
- - + - -
- - - - ]
182 : : case 'd':
183 : 0 : pkg_fprintf(dest->fp, "%#d", pkg);
184 : 0 : break;
185 : : case 'r':
186 : 0 : pkg_fprintf(dest->fp, "%#r", pkg);
187 : 0 : break;
188 : : case 'C':
189 : 0 : pkg_fprintf(dest->fp, "%#C", pkg);
190 : 0 : break;
191 : : case 'F':
192 : 1 : pkg_fprintf(dest->fp, "%#F", pkg);
193 : 1 : break;
194 : : case 'O':
195 : 1 : pkg_fprintf(dest->fp, "%#O", pkg);
196 : 1 : break;
197 : : case 'D':
198 : 0 : pkg_fprintf(dest->fp, "%#D", pkg);
199 : 0 : break;
200 : : case 'L':
201 : 0 : pkg_fprintf(dest->fp, "%#L", pkg);
202 : 0 : break;
203 : : case 'U':
204 : 0 : pkg_fprintf(dest->fp, "%#U", pkg);
205 : 0 : break;
206 : : case 'G':
207 : 0 : pkg_fprintf(dest->fp, "%#G", pkg);
208 : 0 : break;
209 : : case 'B':
210 : 0 : pkg_fprintf(dest->fp, "%#B", pkg);
211 : 0 : break;
212 : : case 'b':
213 : 0 : pkg_fprintf(dest->fp, "%#b", pkg);
214 : 0 : break;
215 : : case 'A':
216 : 0 : pkg_fprintf(dest->fp, "%#A", pkg);
217 : 0 : break;
218 : : }
219 : 2 : break;
220 : : case 'Q':
221 : 0 : pkg_fprintf(dest->fp, "%Q", pkg);
222 : 0 : break;
223 : : case 'q':
224 : 0 : pkg_fprintf(dest->fp, "%q", pkg);
225 : 0 : break;
226 : : case 'l':
227 : 0 : pkg_fprintf(dest->fp, "%l", pkg);
228 : 0 : break;
229 : : case 'd':
230 : 6 : qstr++;
231 [ + + ]: 6 : if (qstr[0] == 'n')
232 : 2 : pkg_fprintf(dest->fp, "%dn", data);
233 [ + + ]: 4 : else if (qstr[0] == 'o')
234 : 2 : pkg_fprintf(dest->fp, "%do", data);
235 [ - + ]: 2 : else if (qstr[0] == 'v')
236 : 2 : pkg_fprintf(dest->fp, "%dv", data);
237 : 6 : break;
238 : : case 'r':
239 : 15 : qstr++;
240 [ + + ]: 15 : if (qstr[0] == 'n')
241 : 5 : pkg_fprintf(dest->fp, "%rn", data);
242 [ + + ]: 10 : else if (qstr[0] == 'o')
243 : 5 : pkg_fprintf(dest->fp, "%ro", data);
244 [ - + ]: 5 : else if (qstr[0] == 'v')
245 : 5 : pkg_fprintf(dest->fp, "%rv", data);
246 : 15 : break;
247 : : case 'C':
248 : 0 : pkg_fprintf(dest->fp, "%Cn", data);
249 : 0 : break;
250 : : case 'F':
251 : 5 : qstr++;
252 [ + - ]: 5 : if (qstr[0] == 'p')
253 : 5 : pkg_fprintf(dest->fp, "%Fn", data);
254 [ # # ]: 0 : else if (qstr[0] == 's')
255 : 0 : pkg_fprintf(dest->fp, "%Fs", data);
256 : 5 : break;
257 : : case 'O':
258 : 0 : qstr++;
259 [ # # ]: 0 : if (qstr[0] == 'k')
260 : 0 : pkg_fprintf(dest->fp, "%On", data);
261 [ # # ]: 0 : else if (qstr[0] == 'v')
262 : 0 : pkg_fprintf(dest->fp, "%Ov", data);
263 [ # # ]: 0 : else if (qstr[0] == 'd') /* default value */
264 : 0 : pkg_fprintf(dest->fp, "%Od", data);
265 [ # # ]: 0 : else if (qstr[0] == 'D') /* description */
266 : 0 : pkg_fprintf(dest->fp, "%OD", data);
267 : 0 : break;
268 : : case 'D':
269 : 0 : pkg_fprintf(dest->fp, "%Dn", data);
270 : 0 : break;
271 : : case 'L':
272 : 0 : pkg_fprintf(dest->fp, "%Ln", data);
273 : 0 : break;
274 : : case 'U':
275 : 0 : pkg_fprintf(dest->fp, "%Un", data);
276 : 0 : break;
277 : : case 'G':
278 : 0 : pkg_fprintf(dest->fp, "%Gn", data);
279 : 0 : break;
280 : : case 'B':
281 : 0 : pkg_fprintf(dest->fp, "%Bn", data);
282 : 0 : break;
283 : : case 'b':
284 : 0 : pkg_fprintf(dest->fp, "%bn", data);
285 : 0 : break;
286 : : case 'A':
287 : 0 : qstr++;
288 [ # # ]: 0 : if (qstr[0] == 't')
289 : 0 : pkg_fprintf(dest->fp, "%An", data);
290 [ # # ]: 0 : else if (qstr[0] == 'v')
291 : 0 : pkg_fprintf(dest->fp, "%Av", data);
292 : 0 : break;
293 : : case 'M':
294 [ # # ]: 0 : if (pkg_has_message(pkg))
295 : 0 : pkg_fprintf(dest->fp, "%M", pkg);
296 : 0 : break;
297 : : case 'V':
298 : 4 : pkg_get(pkg, PKG_ATTR_VITAL, &vital);
299 : 4 : fprintf(dest->fp, "%d", vital);
300 : 4 : break;
301 : : case 'X':
302 : 2 : pkg_fprintf(dest->fp, "%X", pkg);
303 : 2 : break;
304 : : case '%':
305 : 0 : fprintf(dest->fp, "%c", '%');
306 : 0 : break;
307 : : }
308 [ - + ]: 99 : } else if (qstr[0] == '\\') {
309 : 0 : qstr++;
310 [ # # # # : 0 : switch (qstr[0]) {
# # # # ]
311 : : case 'n':
312 : 0 : fprintf(dest->fp, "%c", '\n');
313 : 0 : break;
314 : : case 'a':
315 : 0 : fprintf(dest->fp, "%c", '\a');
316 : 0 : break;
317 : : case 'b':
318 : 0 : fprintf(dest->fp, "%c", '\b');
319 : 0 : break;
320 : : case 'f':
321 : 0 : fprintf(dest->fp, "%c", '\f');
322 : 0 : break;
323 : : case 'r':
324 : 0 : fprintf(dest->fp, "%c", '\r');
325 : 0 : break;
326 : : case '\\':
327 : 0 : fprintf(dest->fp, "%c", '\\');
328 : 0 : break;
329 : : case 't':
330 : 0 : fprintf(dest->fp, "%c", '\t');
331 : 0 : break;
332 : : }
333 : 0 : } else {
334 : 31 : fprintf(dest->fp, "%c", qstr[0]);
335 : : }
336 : 99 : qstr++;
337 : : }
338 : 44 : fflush(dest->fp);
339 : 44 : }
340 : :
341 : : void
342 : 42 : print_query(struct pkg *pkg, char *qstr, char multiline)
343 : : {
344 : : xstring *output;
345 : 42 : struct pkg_dep *dep = NULL;
346 : 42 : struct pkg_option *option = NULL;
347 : 42 : struct pkg_file *file = NULL;
348 : 42 : struct pkg_dir *dir = NULL;
349 : 42 : const char *str = NULL;
350 : 42 : struct pkg_kv *kv = NULL;
351 : 42 : struct pkg_stringlist *sl = NULL;
352 : : struct pkg_stringlist_iterator *slit;
353 : 42 : struct pkg_kvlist *kl = NULL;
354 : : struct pkg_kvlist_iterator *kit;
355 : :
356 : 42 : output = xstring_new();
357 : :
358 [ - - + + : 42 : switch (multiline) {
+ - + - -
- - - - ]
359 : : case 'd':
360 [ + + ]: 4 : while (pkg_deps(pkg, &dep) == EPKG_OK) {
361 : 2 : format_str(pkg, output, qstr, dep);
362 : 2 : printf("%s\n", output->buf);
363 : : }
364 : 2 : break;
365 : : case 'r':
366 [ + + ]: 10 : while (pkg_rdeps(pkg, &dep) == EPKG_OK) {
367 : 5 : format_str(pkg, output, qstr, dep);
368 : 5 : printf("%s\n", output->buf);
369 : : }
370 : 5 : break;
371 : : case 'C':
372 : 0 : pkg_get(pkg, PKG_ATTR_CATEGORIES, &sl);
373 : 0 : slit = pkg_stringlist_iterator(sl);
374 [ # # ]: 0 : while ((str = pkg_stringlist_next(slit))) {
375 : 0 : format_str(pkg, output, qstr, str);
376 : 0 : printf("%s\n", output->buf);
377 : : }
378 : 0 : free(slit);
379 : 0 : free(sl);
380 : 0 : break;
381 : : case 'O':
382 [ # # ]: 0 : while (pkg_options(pkg, &option) == EPKG_OK) {
383 : 0 : format_str(pkg, output, qstr, option);
384 : 0 : printf("%s\n", output->buf);
385 : : }
386 : 0 : break;
387 : : case 'F':
388 [ + + ]: 8 : while (pkg_files(pkg, &file) == EPKG_OK) {
389 : 5 : format_str(pkg, output, qstr, file);
390 : 5 : printf("%s\n", output->buf);
391 : : }
392 : 3 : break;
393 : : case 'D':
394 [ # # ]: 0 : while (pkg_dirs(pkg, &dir) == EPKG_OK) {
395 : 0 : format_str(pkg, output, qstr, dir);
396 : 0 : printf("%s\n", output->buf);
397 : : }
398 : 0 : break;
399 : : case 'L':
400 : 0 : pkg_get(pkg, PKG_ATTR_LICENSES, &sl);
401 : 0 : slit = pkg_stringlist_iterator(sl);
402 [ # # ]: 0 : while ((str = pkg_stringlist_next(slit))) {
403 : 0 : format_str(pkg, output, qstr, str);
404 : 0 : printf("%s\n", output->buf);
405 : : }
406 : 0 : free(slit);
407 : 0 : free(sl);
408 : 0 : break;
409 : : case 'U':
410 : 0 : pkg_get(pkg, PKG_ATTR_USERS, &sl);
411 : 0 : slit = pkg_stringlist_iterator(sl);
412 [ # # ]: 0 : while ((str = pkg_stringlist_next(slit))) {
413 : 0 : format_str(pkg, output, qstr, str);
414 : 0 : printf("%s\n", output->buf);
415 : : }
416 : 0 : break;
417 : : case 'G':
418 : 0 : pkg_get(pkg, PKG_ATTR_GROUPS, &sl);
419 : 0 : slit = pkg_stringlist_iterator(sl);
420 [ # # ]: 0 : while ((str = pkg_stringlist_next(slit))) {
421 : 0 : format_str(pkg, output, qstr, str);
422 : 0 : printf("%s\n", output->buf);
423 : : }
424 : 0 : break;
425 : : case 'B':
426 : 0 : pkg_get(pkg, PKG_ATTR_SHLIBS_REQUIRED, &sl);
427 : 0 : slit = pkg_stringlist_iterator(sl);
428 [ # # ]: 0 : while ((str = pkg_stringlist_next(slit))) {
429 : 0 : format_str(pkg, output, qstr, str);
430 : 0 : printf("%s\n", output->buf);
431 : : }
432 : 0 : break;
433 : : case 'b':
434 : 0 : pkg_get(pkg, PKG_ATTR_SHLIBS_PROVIDED, &sl);
435 : 0 : slit = pkg_stringlist_iterator(sl);
436 [ # # ]: 0 : while ((str = pkg_stringlist_next(slit))) {
437 : 0 : format_str(pkg, output, qstr, str);
438 : 0 : printf("%s\n", output->buf);
439 : : }
440 : 0 : break;
441 : : case 'A':
442 : 0 : pkg_get(pkg, PKG_ATTR_ANNOTATIONS, &kl);
443 : 0 : kit = pkg_kvlist_iterator(kl);
444 [ # # ]: 0 : while ((kv = pkg_kvlist_next(kit))) {
445 : 0 : format_str(pkg, output, qstr, kv);
446 : 0 : printf("%s\n", output->buf);
447 : : }
448 : 0 : free(kit);
449 : 0 : free(kl);
450 : 0 : break;
451 : : default:
452 : 32 : format_str(pkg, output, qstr, dep);
453 : 32 : printf("%s\n", output->buf);
454 : 32 : break;
455 : : }
456 : 42 : xstring_free(output);
457 : 42 : }
458 : :
459 : : typedef enum {
460 : : NONE,
461 : : NEXT_IS_INT,
462 : : OPERATOR_INT,
463 : : INT,
464 : : NEXT_IS_STRING,
465 : : OPERATOR_STRING,
466 : : STRING,
467 : : QUOTEDSTRING,
468 : : SQUOTEDSTRING,
469 : : POST_EXPR,
470 : : } state_t;
471 : :
472 : : int
473 : 18 : format_sql_condition(const char *str, xstring *sqlcond, bool for_remote)
474 : : {
475 : 18 : state_t state = NONE;
476 : 18 : unsigned int bracket_level = 0;
477 : : const char *sqlop;
478 : 18 : bool collate_nocase = false;
479 : :
480 : 18 : fprintf(sqlcond->fp, " WHERE ");
481 [ + + ]: 126 : while (str[0] != '\0') {
482 [ + + ]: 108 : if (state == NONE) {
483 [ + + ]: 22 : if (str[0] == '%') {
484 : 20 : str++;
485 [ + - - - : 20 : switch (str[0]) {
- - - - -
+ - - - -
+ - - ]
486 : : case 'n':
487 : 5 : fprintf(sqlcond->fp, "p.name");
488 : 5 : state = OPERATOR_STRING;
489 : 5 : break;
490 : : case 'o':
491 : 0 : fprintf(sqlcond->fp, "origin");
492 : 0 : state = OPERATOR_STRING;
493 : 0 : break;
494 : : case 'p':
495 : 0 : fprintf(sqlcond->fp, "prefix");
496 : 0 : state = OPERATOR_STRING;
497 : 0 : break;
498 : : case 'm':
499 : 0 : fprintf(sqlcond->fp, "maintainer");
500 : 0 : state = OPERATOR_STRING;
501 : 0 : break;
502 : : case 'c':
503 : 0 : fprintf(sqlcond->fp, "comment");
504 : 0 : state = OPERATOR_STRING;
505 : 0 : break;
506 : : case 'w':
507 : 0 : fprintf(sqlcond->fp, "www");
508 : 0 : state = OPERATOR_STRING;
509 : 0 : break;
510 : : case 's':
511 : 0 : fprintf(sqlcond->fp, "flatsize");
512 : 0 : state = OPERATOR_INT;
513 : 0 : break;
514 : : case 'a':
515 [ + - ]: 1 : if (for_remote)
516 : 0 : goto bad_option;
517 : 1 : fprintf(sqlcond->fp, "automatic");
518 : 1 : state = OPERATOR_INT;
519 : 1 : break;
520 : : case 'q':
521 : 0 : fprintf(sqlcond->fp, "arch");
522 : 0 : state = OPERATOR_STRING;
523 : 0 : break;
524 : : case 'k':
525 [ # # ]: 0 : if (for_remote)
526 : 0 : goto bad_option;
527 : 0 : fprintf(sqlcond->fp, "locked");
528 : 0 : state = OPERATOR_INT;
529 : 0 : break;
530 : : case 'M':
531 [ # # ]: 0 : if (for_remote)
532 : 0 : goto bad_option;
533 : 0 : fprintf(sqlcond->fp, "message");
534 : 0 : state = OPERATOR_STRING;
535 : 0 : break;
536 : : case 't':
537 [ # # ]: 0 : if (for_remote)
538 : 0 : goto bad_option;
539 : 0 : fprintf(sqlcond->fp, "time");
540 : 0 : state = OPERATOR_INT;
541 : 0 : break;
542 : : case 'e':
543 : 0 : fprintf(sqlcond->fp, "desc");
544 : 0 : state = OPERATOR_STRING;
545 : 0 : break;
546 : : case 'V':
547 [ # # ]: 0 : if (for_remote)
548 : 0 : goto bad_option;
549 : 0 : fprintf(sqlcond->fp, "vital");
550 : 0 : state = OPERATOR_INT;
551 : 14 : break;
552 : : case '#': /* FALLTHROUGH */
553 : : case '?':
554 : 14 : sqlop = (str[0] == '#' ? "COUNT(*)" : "COUNT(*) > 0");
555 : 14 : str++;
556 [ + + - + : 14 : switch (str[0]) {
- - - - +
- - - - ]
557 : : case 'd':
558 : 3 : fprintf(sqlcond->fp, "(SELECT %s FROM deps AS d WHERE d.package_id=p.id)", sqlop);
559 : 3 : break;
560 : : case 'r':
561 : 7 : fprintf(sqlcond->fp, "(SELECT %s FROM deps AS d WHERE d.name=p.name)", sqlop);
562 : 7 : break;
563 : : case 'C':
564 : 0 : fprintf(sqlcond->fp, "(SELECT %s FROM pkg_categories AS d WHERE d.package_id=p.id)", sqlop);
565 : 0 : break;
566 : : case 'F':
567 [ # # ]: 0 : if (for_remote)
568 : 0 : goto bad_option;
569 : 0 : fprintf(sqlcond->fp, "(SELECT %s FROM files AS d WHERE d.package_id=p.id)", sqlop);
570 : 0 : break;
571 : : case 'O':
572 : 3 : fprintf(sqlcond->fp, "(SELECT %s FROM pkg_option AS d WHERE d.package_id=p.id)", sqlop);
573 : 3 : break;
574 : : case 'D':
575 [ - + ]: 1 : if (for_remote)
576 : 0 : goto bad_option;
577 : 1 : fprintf(sqlcond->fp, "(SELECT %s FROM pkg_directories AS d WHERE d.package_id=p.id)", sqlop);
578 : 1 : break;
579 : : case 'L':
580 : 0 : fprintf(sqlcond->fp, "(SELECT %s FROM pkg_licenses AS d WHERE d.package_id=p.id)", sqlop);
581 : 0 : break;
582 : : case 'U':
583 [ # # ]: 0 : if (for_remote)
584 : 0 : goto bad_option;
585 : 0 : fprintf(sqlcond->fp, "(SELECT %s FROM pkg_users AS d WHERE d.package_id=p.id)", sqlop);
586 : 0 : break;
587 : : case 'G':
588 [ # # ]: 0 : if (for_remote)
589 : 0 : goto bad_option;
590 : 0 : fprintf(sqlcond->fp, "(SELECT %s FROM pkg_groups AS d WHERE d.package_id=p.id)", sqlop);
591 : 0 : break;
592 : : case 'B':
593 : 0 : fprintf(sqlcond->fp, "(SELECT %s FROM pkg_shlibs_required AS d WHERE d.package_id=p.id)", sqlop);
594 : 0 : break;
595 : : case 'b':
596 : 0 : fprintf(sqlcond->fp, "(SELECT %s FROM pkg_shlibs_provided AS d WHERE d.package_id=p.id)", sqlop);
597 : 0 : break;
598 : : case 'A':
599 : 0 : fprintf(sqlcond->fp, "(SELECT %s FROM pkg_annotation AS d WHERE d.package_id=p.id)", sqlop);
600 : 0 : break;
601 : : default:
602 : 0 : goto bad_option;
603 : : }
604 : 14 : state = OPERATOR_INT;
605 : 14 : break;
606 : : default:
607 : : bad_option:
608 : 0 : fprintf(stderr, "malformed evaluation string\n");
609 : 0 : return (EPKG_FATAL);
610 : : }
611 : 20 : } else {
612 [ - + - - ]: 2 : switch (str[0]) {
613 : : case '(':
614 : 0 : bracket_level++;
615 : 0 : fprintf(sqlcond->fp, "%c", str[0]);
616 : 2 : break;
617 : : case ' ':
618 : : case '\t':
619 : 2 : break;
620 : : default:
621 : 0 : fprintf(stderr, "unexpected character: %c\n", str[0]);
622 : 0 : return (EPKG_FATAL);
623 : : }
624 : : }
625 [ + + ]: 108 : } else if (state == POST_EXPR) {
626 [ + - - - : 4 : switch (str[0]) {
- + ]
627 : : case ')':
628 [ # # ]: 0 : if (bracket_level == 0) {
629 : 0 : fprintf(stderr, "too many closing brackets.\n");
630 : 0 : return (EPKG_FATAL);
631 : : }
632 : 0 : bracket_level--;
633 : 0 : fprintf(sqlcond->fp, "%c", str[0]);
634 : 2 : break;
635 : : case ' ':
636 : : case '\t':
637 : 2 : break;
638 : : case '|':
639 [ # # ]: 0 : if (str[1] == '|') {
640 : 0 : str++;
641 : 0 : state = NONE;
642 : 0 : fprintf(sqlcond->fp, " OR ");
643 : 0 : break;
644 : : } else {
645 : 0 : fprintf(stderr, "unexpected character %c\n", str[1]);
646 : 0 : return (EPKG_FATAL);
647 : : }
648 : : case '&':
649 [ + - ]: 2 : if (str[1] == '&') {
650 : 2 : str++;
651 : 2 : state = NONE;
652 : 2 : fprintf(sqlcond->fp, " AND ");
653 : 2 : break;
654 : : } else {
655 : 0 : fprintf(stderr, "unexpected character %c\n", str[1]);
656 : 0 : return (EPKG_FATAL);
657 : : }
658 : : default:
659 : 0 : fprintf(stderr, "unexpected character %c\n", str[0]);
660 : 0 : return (EPKG_FATAL);
661 : : }
662 [ + + + + ]: 86 : } else if (state == OPERATOR_STRING || state == OPERATOR_INT) {
663 : : /* only operators or space are allowed here */
664 [ + + ]: 30 : if (isspace(str[0])) {
665 : : /* do nothing */
666 [ - + ]: 30 : } else if (str[0] == '~' ) {
667 [ # # ]: 0 : if (state != OPERATOR_STRING) {
668 : 0 : fprintf(stderr, "~ expected only for string testing\n");
669 : 0 : return (EPKG_FATAL);
670 : : }
671 : 0 : state = NEXT_IS_STRING;
672 : 0 : fprintf(sqlcond->fp, " GLOB ");
673 [ + + - + ]: 20 : } else if (str[0] == '>' || str[0] == '<') {
674 [ + - ]: 13 : if (state != OPERATOR_INT) {
675 : 0 : fprintf(stderr, "> expected only for integers\n");
676 : 0 : return (EPKG_FATAL);
677 : : }
678 : 13 : state = NEXT_IS_INT;
679 : 13 : fprintf(sqlcond->fp, "%c", str[0]);
680 [ + - ]: 13 : if (str[1] == '=') {
681 : 0 : str++;
682 : 0 : fprintf(sqlcond->fp, "%c", str[0]);
683 : 0 : }
684 [ + + ]: 20 : } else if (str[0] == '=') {
685 [ + + ]: 5 : if (state == OPERATOR_STRING) {
686 : 3 : state = NEXT_IS_STRING;
687 : 3 : } else {
688 : 2 : state = NEXT_IS_INT;
689 : : }
690 : 5 : fprintf(sqlcond->fp, "%c", str[0]);
691 [ + - ]: 5 : if (str[1] == '=') {
692 : 5 : str++;
693 [ # # # # ]: 5 : } else if (str[1] == '~' && state == NEXT_IS_STRING) {
694 : 0 : str++;
695 : 0 : collate_nocase = true;
696 : 0 : }
697 [ - + ]: 7 : } else if (str[0] == '!') {
698 [ + - ]: 2 : if (str[1] == '=') {
699 : 2 : fprintf(sqlcond->fp, "%c", str[0]);
700 : 2 : fprintf(sqlcond->fp, "%c", str[1]);
701 [ # # ]: 2 : } else if (str[1] == '~') {
702 : 0 : fprintf(sqlcond->fp, " NOT GLOB ");
703 : 0 : } else {
704 : 0 : fprintf(stderr, "expecting = or ~ after !\n");
705 : 0 : return (EPKG_FATAL);
706 : : }
707 : 2 : str++;
708 [ + - ]: 2 : if (state == OPERATOR_STRING) {
709 : 2 : state = NEXT_IS_STRING;
710 : 2 : } else {
711 : 0 : state = NEXT_IS_INT;
712 : : }
713 [ - + # # ]: 2 : if (str[0] == '~' && state == NEXT_IS_STRING) {
714 : 0 : str++;
715 : 0 : collate_nocase = true;
716 : 0 : }
717 : 2 : } else {
718 : 0 : fprintf(stderr, "an operator is expected, got %c\n", str[0]);
719 : 0 : return (EPKG_FATAL);
720 : : }
721 [ + + + + ]: 82 : } else if (state == NEXT_IS_STRING || state == NEXT_IS_INT) {
722 [ + + ]: 30 : if (isspace(str[0])) {
723 : : /* do nothing */
724 : 10 : } else {
725 [ + + ]: 20 : if (state == NEXT_IS_STRING) {
726 [ - + ]: 5 : if (str[0] == '"') {
727 : 0 : state = QUOTEDSTRING;
728 [ - + ]: 5 : } else if (str[0] == '\'') {
729 : 0 : state = SQUOTEDSTRING;
730 : 0 : } else {
731 : 5 : state = STRING;
732 : 5 : str--;
733 : : }
734 : 5 : fprintf(sqlcond->fp, "%c", '\'');
735 : 5 : } else {
736 [ + - ]: 15 : if (!isdigit(str[0])) {
737 : 0 : fprintf(stderr, "a number is expected, got: %c\n", str[0]);
738 : 0 : return (EPKG_FATAL);
739 : : }
740 : 15 : state = INT;
741 : 15 : fprintf(sqlcond->fp, "%c", str[0]);
742 : : }
743 : : }
744 [ + + ]: 52 : } else if (state == INT) {
745 [ - + ]: 2 : if (!isdigit(str[0])) {
746 : 2 : state = POST_EXPR;
747 : 2 : str--;
748 : 2 : } else {
749 : 0 : fprintf(sqlcond->fp, "%c", str[0]);
750 : : }
751 [ - + # # : 22 : } else if (state == STRING || state == QUOTEDSTRING || state == SQUOTEDSTRING) {
# # ]
752 [ + - + - : 20 : if ((state == STRING && isspace(str[0])) ||
# # ]
753 [ - + # # ]: 20 : (state == QUOTEDSTRING && str[0] == '"') ||
754 [ - + ]: 20 : (state == SQUOTEDSTRING && str[0] == '\'')) {
755 : 0 : fprintf(sqlcond->fp, "%c", '\'');
756 : 0 : state = POST_EXPR;
757 [ # # ]: 0 : if (collate_nocase) {
758 : 0 : fprintf(sqlcond->fp, " COLLATE NOCASE ");
759 : 0 : collate_nocase = false;
760 : 0 : }
761 : 0 : } else {
762 : 20 : fprintf(sqlcond->fp, "%c", str[0]);
763 [ - + ]: 20 : if (str[0] == '\'')
764 : 0 : fprintf(sqlcond->fp, "%c", str[0]);
765 [ - + # # ]: 20 : else if (str[0] == '%' && for_remote)
766 : 0 : fprintf(sqlcond->fp, "%c", str[0]);
767 : : }
768 : 20 : }
769 : 108 : str++;
770 : : }
771 [ + + ]: 18 : if (state == STRING) {
772 : 5 : fprintf(sqlcond->fp, "%c", '\'');
773 : 5 : state = POST_EXPR;
774 [ + - ]: 5 : if (collate_nocase) {
775 : 0 : fprintf(sqlcond->fp, " COLLATE NOCASE ");
776 : 0 : collate_nocase = false;
777 : 0 : }
778 : 5 : }
779 : :
780 [ + + + - ]: 18 : if (state != POST_EXPR && state != INT) {
781 : 0 : fprintf(stderr, "unexpected end of expression\n");
782 : 0 : return (EPKG_FATAL);
783 [ - + ]: 18 : } else if (bracket_level > 0) {
784 : 0 : fprintf(stderr, "unexpected end of expression (too many open brackets)\n");
785 : 0 : return (EPKG_FATAL);
786 : : }
787 : :
788 : 18 : return (EPKG_OK);
789 : 18 : }
790 : :
791 : : int
792 : 49 : analyse_query_string(char *qstr, struct query_flags *q_flags, const unsigned int q_flags_len, int *flags, char *multiline)
793 : : {
794 : : unsigned int i, j, k;
795 : 49 : unsigned int valid_flag = 0;
796 : 49 : unsigned int valid_opts = 0;
797 : : size_t len;
798 : :
799 : 49 : j = 0; /* shut up scanbuild */
800 : :
801 [ + - ]: 49 : if (strchr(qstr, '%') == NULL) {
802 : 0 : fprintf(stderr, "Invalid query: query should contain a format string\n");
803 : 0 : return (EPKG_FATAL);
804 : : }
805 : :
806 [ + + ]: 162 : while (qstr[0] != '\0') {
807 [ + + ]: 113 : if (qstr[0] == '%') {
808 : 77 : qstr++;
809 : 77 : valid_flag = 0;
810 : :
811 [ - + ]: 994 : for (i = 0; i < q_flags_len; i++) {
812 : : /* found the flag */
813 [ + + ]: 994 : if (qstr[0] == q_flags[i].flag) {
814 : 77 : valid_flag = 1;
815 : :
816 : : /* if the flag is followed by additional options */
817 [ + + ]: 77 : if (q_flags[i].options[0] != '\0') {
818 : 31 : qstr++;
819 : 31 : valid_opts = 0;
820 : :
821 : 31 : len = strlen(q_flags[i].options);
822 [ - + ]: 69 : for (j = 0; j < len; j++) {
823 [ + + ]: 69 : if (qstr[0] == q_flags[i].options[j]) {
824 : 31 : valid_opts = 1;
825 : 31 : break;
826 : : }
827 : 38 : }
828 : :
829 [ + - ]: 31 : if (valid_opts == 0) {
830 : 0 : fprintf(stderr, "Invalid query: '%%%c' should be followed by:", q_flags[i].flag);
831 : :
832 : 0 : len = strlen(q_flags[i].options);
833 [ # # ]: 0 : for (j = 0; j < len; j++)
834 : 0 : fprintf(stderr, " %c%c", q_flags[i].options[j],
835 : 0 : q_flags[i].options[j + 1] == '\0' ?
836 : : '\n' : ',');
837 : :
838 : 0 : return (EPKG_FATAL);
839 : : }
840 : 31 : }
841 : :
842 : : /* if this is a multiline flag */
843 [ + + ]: 77 : if (q_flags[i].multiline == 1) {
844 [ + + - + ]: 31 : if (*multiline != 0 && *multiline != q_flags[i].flag) {
845 : 0 : fprintf(stderr, "Invalid query: '%%%c' and '%%%c' cannot be queried at the same time\n",
846 : 0 : *multiline, q_flags[i].flag);
847 : 0 : return (EPKG_FATAL);
848 : : } else {
849 : 31 : *multiline = q_flags[i].flag;
850 : : }
851 : 31 : }
852 : :
853 : : /* handle the '?' flag cases */
854 [ + + + + ]: 77 : if (q_flags[i].flag == '?' || q_flags[i].flag == '#') {
855 [ - + ]: 18 : for (k = 0; k < q_flags_len; k++)
856 [ + + ]: 18 : if (q_flags[k].flag == q_flags[i].options[j]) {
857 : 4 : *flags |= q_flags[k].dbflags;
858 : 4 : break;
859 : : }
860 : 4 : } else {
861 : 73 : *flags |= q_flags[i].dbflags;
862 : : }
863 : :
864 : 77 : break; /* don't iterate over the rest of the flags */
865 : : }
866 : 917 : }
867 : :
868 [ + - ]: 77 : if (valid_flag == 0) {
869 : 0 : fprintf(stderr, "Unknown query format key: '%%%c'\n", qstr[0]);
870 : 0 : return (EPKG_FATAL);
871 : : }
872 : 77 : }
873 : :
874 : 113 : qstr++;
875 : : }
876 : :
877 : 49 : return (EPKG_OK);
878 : 49 : }
879 : :
880 : : void
881 : 0 : usage_query(void)
882 : : {
883 : 0 : fprintf(stderr, "Usage: pkg query <query-format> <pkg-name>\n");
884 : 0 : fprintf(stderr, " pkg query [-a] <query-format>\n");
885 : 0 : fprintf(stderr, " pkg query -F <pkg-name> <query-format>\n");
886 : 0 : fprintf(stderr, " pkg query -e <evaluation> <query-format>\n");
887 : 0 : fprintf(stderr, " pkg query [-Cgix] <query-format> <pattern> <...>\n\n");
888 : 0 : fprintf(stderr, "For more information see 'pkg help query.'\n");
889 : 0 : }
890 : :
891 : : int
892 : 37 : exec_query(int argc, char **argv)
893 : : {
894 : 37 : struct pkgdb *db = NULL;
895 : 37 : struct pkgdb_it *it = NULL;
896 : 37 : struct pkg *pkg = NULL;
897 : 37 : char *pkgname = NULL;
898 : 37 : int query_flags = PKG_LOAD_BASIC;
899 : 37 : match_t match = MATCH_EXACT;
900 : : int ch;
901 : : int ret;
902 : 37 : int retcode = EXIT_SUCCESS;
903 : : int i;
904 : 37 : char multiline = 0;
905 : 37 : int nprinted = 0;
906 : 37 : char *condition = NULL;
907 : 37 : const char *condition_sql = NULL;
908 : 37 : xstring *sqlcond = NULL;
909 : 37 : const unsigned int q_flags_len = NELEM(accepted_query_flags);
910 : :
911 : 37 : struct option longopts[] = {
912 : : { "all", no_argument, NULL, 'a' },
913 : : { "case-sensitive", no_argument, NULL, 'C' },
914 : : { "evaluate", required_argument, NULL, 'e' },
915 : : { "file", required_argument, NULL, 'F' },
916 : : { "glob", no_argument, NULL, 'g' },
917 : : { "case-insensitive", no_argument, NULL, 'i' },
918 : : { "regex", no_argument, NULL, 'x' },
919 : : { NULL, 0, NULL, 0 },
920 : : };
921 : :
922 [ + + ]: 60 : while ((ch = getopt_long(argc, argv, "+aCe:F:gix", longopts, NULL)) != -1) {
923 [ - + + + : 23 : switch (ch) {
- - + - ]
924 : : case 'a':
925 : 0 : match = MATCH_ALL;
926 : 0 : break;
927 : : case 'C':
928 : 0 : pkgdb_set_case_sensitivity(true);
929 : 0 : break;
930 : : case 'e':
931 : 13 : condition = optarg;
932 : 13 : break;
933 : : case 'F':
934 : 8 : pkgname = optarg;
935 : 8 : break;
936 : : case 'g':
937 : 1 : match = MATCH_GLOB;
938 : 1 : break;
939 : : case 'i':
940 : 0 : pkgdb_set_case_sensitivity(false);
941 : 0 : break;
942 : : case 'x':
943 : 1 : match = MATCH_REGEX;
944 : 1 : break;
945 : : default:
946 : 0 : usage_query();
947 : 0 : return (EXIT_FAILURE);
948 : : }
949 : : }
950 : :
951 : 37 : argc -= optind;
952 : 37 : argv += optind;
953 : :
954 [ + - + - ]: 37 : if ((match == MATCH_ALL || pkgname != NULL)
955 [ + + ]: 37 : && argc > 1) {
956 : 0 : usage_query();
957 : 0 : retcode = EXIT_FAILURE;
958 : 0 : goto cleanup;
959 : : }
960 : :
961 [ + - ]: 37 : if (argc == 0) {
962 : 0 : usage_query();
963 : 0 : retcode = EXIT_FAILURE;
964 : 0 : goto cleanup;
965 : : }
966 : :
967 : : /* Default to all packages if no pkg provided */
968 [ + + + + : 37 : if (argc == 1 && pkgname == NULL && match == MATCH_EXACT) {
- + ]
969 : 10 : match = MATCH_ALL;
970 [ + + # # ]: 37 : } else if (((argc == 1) ^ (match == MATCH_ALL)) && pkgname == NULL
971 [ - + ]: 8 : && condition == NULL) {
972 : 0 : usage_query();
973 : 0 : retcode = EXIT_FAILURE;
974 : 0 : goto cleanup;
975 : : }
976 : :
977 [ - + - + ]: 74 : if (analyse_query_string(argv[0], accepted_query_flags, q_flags_len,
978 : 37 : &query_flags, &multiline) != EPKG_OK) {
979 : 0 : retcode = EXIT_FAILURE;
980 : 0 : goto cleanup;
981 : : }
982 : :
983 [ + + ]: 37 : if (pkgname != NULL) {
984 : : /* Use a manifest or compact manifest if possible. */
985 : 8 : int open_flags = 0;
986 [ + + + + ]: 16 : if ((query_flags & ~(PKG_LOAD_DEPS|
987 : : PKG_LOAD_OPTIONS|
988 : : PKG_LOAD_CATEGORIES|
989 : : PKG_LOAD_LICENSES|
990 : : PKG_LOAD_USERS|
991 : : PKG_LOAD_GROUPS|
992 : : PKG_LOAD_SHLIBS_REQUIRED|
993 : : PKG_LOAD_SHLIBS_PROVIDED|
994 : : PKG_LOAD_ANNOTATIONS|
995 : : PKG_LOAD_CONFLICTS|
996 : : PKG_LOAD_PROVIDES|
997 : 8 : PKG_LOAD_REQUIRES)) == 0) {
998 : 3 : open_flags = PKG_OPEN_MANIFEST_COMPACT;
999 [ + + ]: 8 : } else if ((query_flags & PKG_LOAD_FILES) == 0) {
1000 : 2 : open_flags = PKG_OPEN_MANIFEST_ONLY;
1001 : 2 : }
1002 [ - + ]: 8 : if (pkg_open(&pkg, pkgname, open_flags) != EPKG_OK) {
1003 : 0 : retcode = EXIT_FAILURE;
1004 : 0 : goto cleanup;
1005 : : }
1006 : :
1007 : 8 : print_query(pkg, argv[0], multiline);
1008 : 8 : retcode = EXIT_SUCCESS;
1009 : 8 : goto cleanup;
1010 : : }
1011 : :
1012 [ + + ]: 29 : if (condition != NULL) {
1013 : 13 : sqlcond = xstring_new();
1014 [ - + ]: 13 : if (format_sql_condition(condition, sqlcond, false) != EPKG_OK) {
1015 : 0 : retcode = EXIT_FAILURE;
1016 : 0 : goto cleanup;
1017 : : }
1018 : 13 : }
1019 : :
1020 : 29 : ret = pkgdb_access(PKGDB_MODE_READ, PKGDB_DB_LOCAL);
1021 [ - + ]: 29 : if (ret == EPKG_ENOACCESS) {
1022 : 0 : warnx("Insufficient privileges to query the package database");
1023 : 0 : retcode = EXIT_FAILURE;
1024 : 0 : goto cleanup;
1025 [ - + ]: 29 : } else if (ret == EPKG_ENODB) {
1026 [ # # ]: 0 : if (!quiet)
1027 : 0 : warnx("No packages installed");
1028 : 0 : retcode = EXIT_SUCCESS;
1029 : 0 : goto cleanup;
1030 [ - + ]: 29 : } else if (ret != EPKG_OK) {
1031 : 0 : retcode = EXIT_FAILURE;
1032 : 0 : goto cleanup;
1033 : : }
1034 : :
1035 : 29 : ret = pkgdb_open(&db, PKGDB_DEFAULT);
1036 [ - + ]: 29 : if (ret != EPKG_OK) {
1037 : 0 : retcode = EXIT_FAILURE;
1038 : 0 : goto cleanup;
1039 : : }
1040 : :
1041 : 29 : pkg_drop_privileges();
1042 [ - + ]: 29 : if (pkgdb_obtain_lock(db, PKGDB_LOCK_READONLY) != EPKG_OK) {
1043 : 0 : warnx("Cannot get a read lock on a database, it is locked by another process");
1044 : 0 : retcode = EXIT_FAILURE;
1045 : 0 : goto cleanup;
1046 : : }
1047 : :
1048 [ + + ]: 29 : if (sqlcond) {
1049 : 13 : fflush(sqlcond->fp);
1050 : 13 : condition_sql = sqlcond->buf;
1051 : 13 : }
1052 : 29 : i = 1;
1053 : 33 : do {
1054 [ + + ]: 33 : pkgname = i < argc ? argv[i] : NULL;
1055 : :
1056 [ + - ]: 33 : if ((it = pkgdb_query_cond(db, condition_sql, pkgname, match)) == NULL) {
1057 [ # # # # ]: 0 : warnx("DEBUG: %s/%s\n", condition_sql ? condition_sql : "-", pkgname ? pkgname : "-");
1058 : 0 : retcode = EXIT_FAILURE;
1059 : 0 : break;
1060 : : }
1061 : :
1062 [ + + ]: 58 : while ((ret = pkgdb_it_next(it, &pkg, query_flags)) == EPKG_OK) {
1063 : 25 : nprinted++;
1064 : 25 : print_query(pkg, argv[0], multiline);
1065 : : }
1066 : :
1067 [ - + ]: 33 : if (ret != EPKG_END) {
1068 : 0 : retcode = EXIT_FAILURE;
1069 : 0 : break;
1070 : : }
1071 : :
1072 : 33 : pkgdb_it_free(it);
1073 : 33 : i++;
1074 [ + + ]: 33 : } while (i < argc);
1075 : :
1076 [ + + + + : 30 : if (nprinted == 0 && match != MATCH_ALL && retcode == EXIT_SUCCESS) {
+ - ]
1077 : : /* ensure to return a non-zero status when no package
1078 : : were found. */
1079 : 1 : retcode = EXIT_FAILURE;
1080 : 1 : }
1081 : :
1082 : : cleanup:
1083 : 37 : xstring_free(sqlcond);
1084 : :
1085 : 37 : pkg_free(pkg);
1086 : :
1087 : 37 : pkgdb_release_lock(db, PKGDB_LOCK_READONLY);
1088 : 37 : pkgdb_close(db);
1089 : :
1090 : 37 : return (retcode);
1091 : 37 : }
|