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