1 /* $NetBSD: main.c,v 1.1.1.15 2010/04/23 20:54:07 joerg Exp $ */
2
3 #if HAVE_CONFIG_H
4 #include "config.h"
5 #endif
6 #include <nbcompat.h>
7 #if HAVE_SYS_CDEFS_H
8 #include <sys/cdefs.h>
9 #endif
10 __RCSID("$NetBSD: main.c,v 1.1.1.15 2010/04/23 20:54:07 joerg Exp $");
11
12 /*-
13 * Copyright (c) 1999-2009 The NetBSD Foundation, Inc.
14 * All rights reserved.
15 *
16 * This code is derived from software contributed to The NetBSD Foundation
17 * by Hubert Feyrer <hubert@feyrer.de> and
18 * by Joerg Sonnenberger <joerg@NetBSD.org>.
19 *
20 * Redistribution and use in source and binary forms, with or without
21 * modification, are permitted provided that the following conditions
22 * are met:
23 * 1. Redistributions of source code must retain the above copyright
24 * notice, this list of conditions and the following disclaimer.
25 * 2. Redistributions in binary form must reproduce the above copyright
26 * notice, this list of conditions and the following disclaimer in the
27 * documentation and/or other materials provided with the distribution.
28 *
29 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
30 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
31 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
32 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
33 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
34 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
35 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
36 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
37 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
38 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
39 * POSSIBILITY OF SUCH DAMAGE.
40 */
41
42 #if HAVE_SYS_TYPES_H
43 #include <sys/types.h>
44 #endif
45 #if HAVE_SYS_STAT_H
46 #include <sys/stat.h>
47 #endif
48 #if HAVE_DIRENT_H
49 #include <dirent.h>
50 #endif
51 #if HAVE_ERR_H
52 #include <err.h>
53 #endif
54 #if HAVE_ERRNO_H
55 #include <errno.h>
56 #endif
57 #if HAVE_FCNTL_H
58 #include <fcntl.h>
59 #endif
60 #ifndef NETBSD
61 #include <nbcompat/md5.h>
62 #else
63 #include <md5.h>
64 #endif
65 #if HAVE_LIMITS_H
66 #include <limits.h>
67 #endif
68 #if HAVE_STDIO_H
69 #include <stdio.h>
70 #endif
71 #if HAVE_STRING_H
72 #include <string.h>
73 #endif
74
75 #ifndef BOOTSTRAP
76 #include <archive.h>
77 #include <fetch.h>
78 #endif
79
80 #include "admin.h"
81 #include "lib.h"
82
83 #define DEFAULT_SFX ".t[bg]z" /* default suffix for ls{all,best} */
84
85 struct pkgdb_count {
86 size_t files;
87 size_t directories;
88 size_t packages;
89 };
90
91 static const char Options[] = "C:K:SVbd:qs:v";
92
93 int quiet, verbose;
94
95 static void set_unset_variable(char **, Boolean);
96
97 /* print usage message and exit */
98 void
usage(void)99 usage(void)
100 {
101 (void) fprintf(stderr, "usage: %s [-bqSVv] [-C config] [-d lsdir] [-K pkg_dbdir] [-s sfx] command [args ...]\n"
102 "Where 'commands' and 'args' are:\n"
103 " rebuild - rebuild pkgdb from +CONTENTS files\n"
104 " rebuild-tree - rebuild +REQUIRED_BY files from forward deps\n"
105 " check [pkg ...] - check md5 checksum of installed files\n"
106 " add pkg ... - add pkg files to database\n"
107 " delete pkg ... - delete file entries for pkg in database\n"
108 " set variable=value pkg ... - set installation variable for package\n"
109 " unset variable pkg ... - unset installation variable for package\n"
110 " lsall /path/to/pkgpattern - list all pkgs matching the pattern\n"
111 " lsbest /path/to/pkgpattern - list pkgs matching the pattern best\n"
112 " dump - dump database\n"
113 " pmatch pattern pkg - returns true if pkg matches pattern, otherwise false\n"
114 " fetch-pkg-vulnerabilities [-s] - fetch new vulnerability file\n"
115 " check-pkg-vulnerabilities [-s] <file> - check syntax and checksums of the vulnerability file\n"
116 " audit [-es] [-t type] ... - check installed packages for vulnerabilities\n"
117 " audit-pkg [-es] [-t type] ... - check listed packages for vulnerabilities\n"
118 " audit-batch [-es] [-t type] ... - check packages in listed files for vulnerabilities\n"
119 " audit-history [-t type] ... - print all advisories for package names\n"
120 " check-license <condition> - check if condition is acceptable\n"
121 " check-single-license <license> - check if license is acceptable\n"
122 " config-var name - print current value of the configuration variable\n"
123 " check-signature ... - verify the signature of packages\n"
124 " x509-sign-package pkg spkg key cert - create X509 signature\n"
125 " gpg-sign-package pkg spkg - create GPG signature\n",
126 getprogname());
127 exit(EXIT_FAILURE);
128 }
129
130 /*
131 * add1pkg(<pkg>)
132 * adds the files listed in the +CONTENTS of <pkg> into the
133 * pkgdb.byfile.db database file in the current package dbdir. It
134 * returns the number of files added to the database file.
135 */
136 static int
add_pkg(const char * pkgdir,void * vp)137 add_pkg(const char *pkgdir, void *vp)
138 {
139 FILE *f;
140 plist_t *p;
141 package_t Plist;
142 char *contents;
143 char *PkgName, *dirp;
144 char file[MaxPathSize];
145 struct pkgdb_count *count;
146
147 if (!pkgdb_open(ReadWrite))
148 err(EXIT_FAILURE, "cannot open pkgdb");
149
150 count = vp;
151 ++count->packages;
152
153 contents = pkgdb_pkg_file(pkgdir, CONTENTS_FNAME);
154 if ((f = fopen(contents, "r")) == NULL)
155 errx(EXIT_FAILURE, "%s: can't open `%s'", pkgdir, CONTENTS_FNAME);
156 free(contents);
157
158 read_plist(&Plist, f);
159 if ((p = find_plist(&Plist, PLIST_NAME)) == NULL) {
160 errx(EXIT_FAILURE, "Package `%s' has no @name, aborting.", pkgdir);
161 }
162
163 PkgName = p->name;
164 dirp = NULL;
165 for (p = Plist.head; p; p = p->next) {
166 switch(p->type) {
167 case PLIST_FILE:
168 if (dirp == NULL) {
169 errx(EXIT_FAILURE, "@cwd not yet found, please send-pr!");
170 }
171 (void) snprintf(file, sizeof(file), "%s/%s", dirp, p->name);
172 if (!(isfile(file) || islinktodir(file))) {
173 if (isbrokenlink(file)) {
174 warnx("%s: Symlink `%s' exists and is in %s but target does not exist!",
175 PkgName, file, CONTENTS_FNAME);
176 } else {
177 warnx("%s: File `%s' is in %s but not on filesystem!",
178 PkgName, file, CONTENTS_FNAME);
179 }
180 } else {
181 pkgdb_store(file, PkgName);
182 ++count->files;
183 }
184 break;
185 case PLIST_PKGDIR:
186 add_pkgdir(PkgName, dirp, p->name);
187 ++count->directories;
188 break;
189 case PLIST_CWD:
190 if (strcmp(p->name, ".") != 0)
191 dirp = p->name;
192 else
193 dirp = pkgdb_pkg_dir(pkgdir);
194 break;
195 case PLIST_IGNORE:
196 p = p->next;
197 break;
198 case PLIST_SHOW_ALL:
199 case PLIST_SRC:
200 case PLIST_CMD:
201 case PLIST_CHMOD:
202 case PLIST_CHOWN:
203 case PLIST_CHGRP:
204 case PLIST_COMMENT:
205 case PLIST_NAME:
206 case PLIST_UNEXEC:
207 case PLIST_DISPLAY:
208 case PLIST_PKGDEP:
209 case PLIST_DIR_RM:
210 case PLIST_OPTION:
211 case PLIST_PKGCFL:
212 case PLIST_BLDDEP:
213 break;
214 }
215 }
216 free_plist(&Plist);
217 fclose(f);
218 pkgdb_close();
219
220 return 0;
221 }
222
223 static void
delete1pkg(const char * pkgdir)224 delete1pkg(const char *pkgdir)
225 {
226 if (!pkgdb_open(ReadWrite))
227 err(EXIT_FAILURE, "cannot open pkgdb");
228 (void) pkgdb_remove_pkg(pkgdir);
229 pkgdb_close();
230 }
231
232 static void
rebuild(void)233 rebuild(void)
234 {
235 char *cachename;
236 struct pkgdb_count count;
237
238 count.files = 0;
239 count.directories = 0;
240 count.packages = 0;
241
242 cachename = pkgdb_get_database();
243 if (unlink(cachename) != 0 && errno != ENOENT)
244 err(EXIT_FAILURE, "unlink %s", cachename);
245
246 setbuf(stdout, NULL);
247
248 iterate_pkg_db(add_pkg, &count);
249
250 printf("\n");
251 printf("Stored %" PRIzu " file%s and %zu explicit director%s"
252 " from %"PRIzu " package%s in %s.\n",
253 count.files, count.files == 1 ? "" : "s",
254 count.directories, count.directories == 1 ? "y" : "ies",
255 count.packages, count.packages == 1 ? "" : "s",
256 cachename);
257 }
258
259 static int
lspattern(const char * pkg,void * vp)260 lspattern(const char *pkg, void *vp)
261 {
262 const char *dir = vp;
263 printf("%s/%s\n", dir, pkg);
264 return 0;
265 }
266
267 static int
lsbasepattern(const char * pkg,void * vp)268 lsbasepattern(const char *pkg, void *vp)
269 {
270 puts(pkg);
271 return 0;
272 }
273
274 static int
remove_required_by(const char * pkgname,void * cookie)275 remove_required_by(const char *pkgname, void *cookie)
276 {
277 char *path;
278
279 path = pkgdb_pkg_file(pkgname, REQUIRED_BY_FNAME);
280
281 if (unlink(path) == -1 && errno != ENOENT)
282 err(EXIT_FAILURE, "Cannot remove %s", path);
283
284 free(path);
285
286 return 0;
287 }
288
289 static void
add_required_by(const char * pattern,const char * required_by)290 add_required_by(const char *pattern, const char *required_by)
291 {
292 char *best_installed, *path;
293 int fd;
294 size_t len;
295
296 best_installed = find_best_matching_installed_pkg(pattern);
297 if (best_installed == NULL) {
298 warnx("Dependency %s of %s unresolved", pattern, required_by);
299 return;
300 }
301
302 path = pkgdb_pkg_file(best_installed, REQUIRED_BY_FNAME);
303 free(best_installed);
304
305 if ((fd = open(path, O_WRONLY | O_APPEND | O_CREAT, 0644)) == -1)
306 errx(EXIT_FAILURE, "Cannot write to %s", path);
307 free(path);
308
309 len = strlen(required_by);
310 if (write(fd, required_by, len) != (ssize_t)len ||
311 write(fd, "\n", 1) != 1 ||
312 close(fd) == -1)
313 errx(EXIT_FAILURE, "Cannot write to %s", path);
314 }
315
316
317 static int
add_depends_of(const char * pkgname,void * cookie)318 add_depends_of(const char *pkgname, void *cookie)
319 {
320 FILE *fp;
321 plist_t *p;
322 package_t plist;
323 char *path;
324
325 path = pkgdb_pkg_file(pkgname, CONTENTS_FNAME);
326 if ((fp = fopen(path, "r")) == NULL)
327 errx(EXIT_FAILURE, "Cannot read %s of package %s",
328 CONTENTS_FNAME, pkgname);
329 free(path);
330 read_plist(&plist, fp);
331 fclose(fp);
332
333 for (p = plist.head; p; p = p->next) {
334 if (p->type == PLIST_PKGDEP)
335 add_required_by(p->name, pkgname);
336 }
337
338 free_plist(&plist);
339
340 return 0;
341 }
342
343 static void
rebuild_tree(void)344 rebuild_tree(void)
345 {
346 if (iterate_pkg_db(remove_required_by, NULL) == -1)
347 errx(EXIT_FAILURE, "cannot iterate pkgdb");
348 if (iterate_pkg_db(add_depends_of, NULL) == -1)
349 errx(EXIT_FAILURE, "cannot iterate pkgdb");
350 }
351
352 int
main(int argc,char * argv[])353 main(int argc, char *argv[])
354 {
355 Boolean use_default_sfx = TRUE;
356 Boolean show_basename_only = FALSE;
357 char lsdir[MaxPathSize];
358 char sfx[MaxPathSize];
359 char *lsdirp = NULL;
360 int ch;
361
362 setprogname(argv[0]);
363
364 if (argc < 2)
365 usage();
366
367 while ((ch = getopt(argc, argv, Options)) != -1)
368 switch (ch) {
369 case 'C':
370 config_file = optarg;
371 break;
372
373 case 'K':
374 pkgdb_set_dir(optarg, 3);
375 break;
376
377 case 'S':
378 sfx[0] = 0x0;
379 use_default_sfx = FALSE;
380 break;
381
382 case 'V':
383 show_version();
384 /* NOTREACHED */
385
386 case 'b':
387 show_basename_only = TRUE;
388 break;
389
390 case 'd':
391 (void) strlcpy(lsdir, optarg, sizeof(lsdir));
392 lsdirp = lsdir;
393 break;
394
395 case 'q':
396 quiet = 1;
397 break;
398
399 case 's':
400 (void) strlcpy(sfx, optarg, sizeof(sfx));
401 use_default_sfx = FALSE;
402 break;
403
404 case 'v':
405 ++verbose;
406 break;
407
408 default:
409 usage();
410 /* NOTREACHED */
411 }
412
413 argc -= optind;
414 argv += optind;
415
416 if (argc <= 0) {
417 usage();
418 }
419
420 /*
421 * config-var is reading the config file implicitly,
422 * so skip it here.
423 */
424 if (strcasecmp(argv[0], "config-var") != 0)
425 pkg_install_config();
426
427 if (use_default_sfx)
428 (void) strlcpy(sfx, DEFAULT_SFX, sizeof(sfx));
429
430 if (strcasecmp(argv[0], "pmatch") == 0) {
431
432 char *pattern, *pkg;
433
434 argv++; /* "pmatch" */
435
436 if (argv[0] == NULL || argv[1] == NULL) {
437 usage();
438 }
439
440 pattern = argv[0];
441 pkg = argv[1];
442
443 if (pkg_match(pattern, pkg)){
444 return 0;
445 } else {
446 return 1;
447 }
448
449 } else if (strcasecmp(argv[0], "rebuild") == 0) {
450
451 rebuild();
452 printf("Done.\n");
453
454
455 } else if (strcasecmp(argv[0], "rebuild-tree") == 0) {
456
457 rebuild_tree();
458 printf("Done.\n");
459
460 } else if (strcasecmp(argv[0], "check") == 0) {
461 argv++; /* "check" */
462
463 check(argv);
464
465 if (!quiet) {
466 printf("Done.\n");
467 }
468
469 } else if (strcasecmp(argv[0], "lsall") == 0) {
470 argv++; /* "lsall" */
471
472 while (*argv != NULL) {
473 /* args specified */
474 int rc;
475 const char *basep, *dir;
476
477 dir = lsdirp ? lsdirp : dirname_of(*argv);
478 basep = basename_of(*argv);
479
480 if (show_basename_only)
481 rc = match_local_files(dir, use_default_sfx, 1, basep, lsbasepattern, NULL);
482 else
483 rc = match_local_files(dir, use_default_sfx, 1, basep, lspattern, __UNCONST(dir));
484 if (rc == -1)
485 errx(EXIT_FAILURE, "Error from match_local_files(\"%s\", \"%s\", ...)",
486 dir, basep);
487
488 argv++;
489 }
490
491 } else if (strcasecmp(argv[0], "lsbest") == 0) {
492 argv++; /* "lsbest" */
493
494 while (*argv != NULL) {
495 /* args specified */
496 const char *basep, *dir;
497 char *p;
498
499 dir = lsdirp ? lsdirp : dirname_of(*argv);
500 basep = basename_of(*argv);
501
502 p = find_best_matching_file(dir, basep, use_default_sfx, 1);
503
504 if (p) {
505 if (show_basename_only)
506 printf("%s\n", p);
507 else
508 printf("%s/%s\n", dir, p);
509 free(p);
510 }
511
512 argv++;
513 }
514 } else if (strcasecmp(argv[0], "list") == 0 ||
515 strcasecmp(argv[0], "dump") == 0) {
516
517 pkgdb_dump();
518
519 } else if (strcasecmp(argv[0], "add") == 0) {
520 struct pkgdb_count count;
521
522 count.files = 0;
523 count.directories = 0;
524 count.packages = 0;
525
526 for (++argv; *argv != NULL; ++argv)
527 add_pkg(*argv, &count);
528 } else if (strcasecmp(argv[0], "delete") == 0) {
529 argv++; /* "delete" */
530 while (*argv != NULL) {
531 delete1pkg(*argv);
532 argv++;
533 }
534 } else if (strcasecmp(argv[0], "set") == 0) {
535 argv++; /* "set" */
536 set_unset_variable(argv, FALSE);
537 } else if (strcasecmp(argv[0], "unset") == 0) {
538 argv++; /* "unset" */
539 set_unset_variable(argv, TRUE);
540 } else if (strcasecmp(argv[0], "config-var") == 0) {
541 argv++;
542 if (argv == NULL || argv[1] != NULL)
543 errx(EXIT_FAILURE, "config-var takes exactly one argument");
544 pkg_install_show_variable(argv[0]);
545 } else if (strcasecmp(argv[0], "check-license") == 0) {
546 if (argv[1] == NULL)
547 errx(EXIT_FAILURE, "check-license takes exactly one argument");
548
549 load_license_lists();
550
551 switch (acceptable_pkg_license(argv[1])) {
552 case 0:
553 puts("no");
554 return 0;
555 case 1:
556 puts("yes");
557 return 0;
558 case -1:
559 errx(EXIT_FAILURE, "invalid license condition");
560 }
561 } else if (strcasecmp(argv[0], "check-single-license") == 0) {
562 if (argv[1] == NULL)
563 errx(EXIT_FAILURE, "check-license takes exactly one argument");
564 load_license_lists();
565
566 switch (acceptable_license(argv[1])) {
567 case 0:
568 puts("no");
569 return 0;
570 case 1:
571 puts("yes");
572 return 0;
573 case -1:
574 errx(EXIT_FAILURE, "invalid license");
575 }
576 }
577 #ifndef BOOTSTRAP
578 else if (strcasecmp(argv[0], "findbest") == 0) {
579 struct url *url;
580 char *output;
581 int rc;
582
583 process_pkg_path();
584
585 rc = 0;
586 for (++argv; *argv != NULL; ++argv) {
587 url = find_best_package(NULL, *argv, 1);
588 if (url == NULL) {
589 rc = 1;
590 continue;
591 }
592 output = fetchStringifyURL(url);
593 puts(output);
594 fetchFreeURL(url);
595 free(output);
596 }
597
598 return rc;
599 } else if (strcasecmp(argv[0], "fetch-pkg-vulnerabilities") == 0) {
600 fetch_pkg_vulnerabilities(--argc, ++argv);
601 } else if (strcasecmp(argv[0], "check-pkg-vulnerabilities") == 0) {
602 check_pkg_vulnerabilities(--argc, ++argv);
603 } else if (strcasecmp(argv[0], "audit") == 0) {
604 audit_pkgdb(--argc, ++argv);
605 } else if (strcasecmp(argv[0], "audit-pkg") == 0) {
606 audit_pkg(--argc, ++argv);
607 } else if (strcasecmp(argv[0], "audit-batch") == 0) {
608 audit_batch(--argc, ++argv);
609 } else if (strcasecmp(argv[0], "audit-history") == 0) {
610 audit_history(--argc, ++argv);
611 } else if (strcasecmp(argv[0], "check-signature") == 0) {
612 struct archive *pkg;
613 int rc;
614
615 rc = 0;
616 for (--argc, ++argv; argc > 0; --argc, ++argv) {
617 char *archive_name;
618
619 pkg = open_archive(*argv, &archive_name);
620 if (pkg == NULL) {
621 warnx("%s could not be opened", *argv);
622 continue;
623 }
624 if (pkg_full_signature_check(archive_name, &pkg))
625 rc = 1;
626 free(archive_name);
627 if (!pkg)
628 archive_read_finish(pkg);
629 }
630 return rc;
631 } else if (strcasecmp(argv[0], "x509-sign-package") == 0) {
632 #ifdef HAVE_SSL
633 --argc;
634 ++argv;
635 if (argc != 4)
636 errx(EXIT_FAILURE, "x509-sign-package takes exactly four arguments");
637 pkg_sign_x509(argv[0], argv[1], argv[2], argv[3]);
638 #else
639 errx(EXIT_FAILURE, "OpenSSL support is not included");
640 #endif
641 } else if (strcasecmp(argv[0], "gpg-sign-package") == 0) {
642 --argc;
643 ++argv;
644 if (argc != 2)
645 errx(EXIT_FAILURE, "gpg-sign-package takes exactly two arguments");
646 pkg_sign_gpg(argv[0], argv[1]);
647 }
648 #endif
649 else {
650 usage();
651 }
652
653 return 0;
654 }
655
656 struct set_installed_info_arg {
657 char *variable;
658 char *value;
659 int got_match;
660 };
661
662 static int
set_installed_info_var(const char * name,void * cookie)663 set_installed_info_var(const char *name, void *cookie)
664 {
665 struct set_installed_info_arg *arg = cookie;
666 char *filename;
667 int retval;
668
669 filename = pkgdb_pkg_file(name, INSTALLED_INFO_FNAME);
670
671 retval = var_set(filename, arg->variable, arg->value);
672
673 free(filename);
674 arg->got_match = 1;
675
676 return retval;
677 }
678
679 static void
set_unset_variable(char ** argv,Boolean unset)680 set_unset_variable(char **argv, Boolean unset)
681 {
682 struct set_installed_info_arg arg;
683 char *eq;
684 char *variable;
685 int ret = 0;
686
687 if (argv[0] == NULL || argv[1] == NULL)
688 usage();
689
690 variable = NULL;
691
692 if (unset) {
693 arg.variable = argv[0];
694 arg.value = NULL;
695 } else {
696 eq = NULL;
697 if ((eq=strchr(argv[0], '=')) == NULL)
698 usage();
699
700 variable = xmalloc(eq-argv[0]+1);
701 strlcpy(variable, argv[0], eq-argv[0]+1);
702
703 arg.variable = variable;
704 arg.value = eq+1;
705
706 if (strcmp(variable, AUTOMATIC_VARNAME) == 0 &&
707 strcasecmp(arg.value, "yes") != 0 &&
708 strcasecmp(arg.value, "no") != 0) {
709 errx(EXIT_FAILURE,
710 "unknown value `%s' for " AUTOMATIC_VARNAME,
711 arg.value);
712 }
713 }
714 if (strpbrk(arg.variable, "ABCDEFGHIJKLMNOPQRSTUVWXYZ") != NULL) {
715 free(variable);
716 errx(EXIT_FAILURE,
717 "variable name must not contain uppercase letters");
718 }
719
720 argv++;
721 while (*argv != NULL) {
722 arg.got_match = 0;
723 if (match_installed_pkgs(*argv, set_installed_info_var, &arg) == -1)
724 errx(EXIT_FAILURE, "Cannot process pkdbdb");
725 if (arg.got_match == 0) {
726 char *pattern;
727
728 if (ispkgpattern(*argv)) {
729 warnx("no matching pkg for `%s'", *argv);
730 ret++;
731 } else {
732 pattern = xasprintf("%s-[0-9]*", *argv);
733
734 if (match_installed_pkgs(pattern, set_installed_info_var, &arg) == -1)
735 errx(EXIT_FAILURE, "Cannot process pkdbdb");
736
737 if (arg.got_match == 0) {
738 warnx("cannot find package %s", *argv);
739 ++ret;
740 }
741 free(pattern);
742 }
743 }
744
745 argv++;
746 }
747
748 if (ret > 0)
749 exit(EXIT_FAILURE);
750
751 free(variable);
752
753 return;
754 }
755