main.c revision 1.7
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 91struct 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 */ 101struct pkgbase_entry { 102 char *pkgbase; 103 char *pkgname; 104 SLIST_ENTRY(pkgbase_entry) entries; 105}; 106SLIST_HEAD(pkgbase_entry_head, pkgbase_entry); 107 108/* 109 * A hashed list of +REQUIRED_BY entries. 110 */ 111struct reqd_by_entry { 112 char *pkgname; 113 SLIST_ENTRY(reqd_by_entry) entries; 114}; 115SLIST_HEAD(reqd_by_entry_head, reqd_by_entry); 116 117/* 118 * A hashed list of packages that contain +REQUIRED_BY entries. 119 */ 120struct 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}; 125SLIST_HEAD(pkg_reqd_by_head, pkg_reqd_by); 126 127static const char Options[] = "C:K:SVbd:qs:v"; 128 129int quiet, verbose; 130 131static void set_unset_variable(char **, Boolean); 132static void digest_input(char **); 133 134/* print usage message and exit */ 135void 136usage(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 */ 172static int 173add_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 259static void 260rebuild(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 286static int 287lspattern(const char *pkg, void *vp) 288{ 289 const char *dir = vp; 290 printf("%s/%s\n", dir, pkg); 291 return 0; 292} 293 294static int 295lsbasepattern(const char *pkg, void *vp) 296{ 297 puts(pkg); 298 return 0; 299} 300 301static int 302remove_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 316static void 317add_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 385static int 386add_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 */ 416static int 417check_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 445static void 446check_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 455static void 456rebuild_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 507int 508main(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 814struct set_installed_info_arg { 815 char *variable; 816 char *value; 817 int got_match; 818}; 819 820static int 821set_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 837static void 838set_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 914static void 915digest_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