1/* $NetBSD: main.c,v 1.6 2020/12/02 13:53:50 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.6 2020/12/02 13:53:50 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 hashed list of +REQUIRED_BY entries. 99 */ 100struct reqd_by_entry { 101 char *pkgname; 102 SLIST_ENTRY(reqd_by_entry) entries; 103}; 104SLIST_HEAD(reqd_by_entry_head, reqd_by_entry); 105 106/* 107 * A hashed list of packages that contain +REQUIRED_BY entries. 108 */ 109struct pkg_reqd_by { 110 char *pkgname; 111 struct reqd_by_entry_head required_by[PKG_HASH_SIZE]; 112 SLIST_ENTRY(pkg_reqd_by) entries; 113}; 114SLIST_HEAD(pkg_reqd_by_head, pkg_reqd_by); 115 116static const char Options[] = "C:K:SVbd:qs:v"; 117 118int quiet, verbose; 119 120static void set_unset_variable(char **, Boolean); 121static void digest_input(char **); 122 123/* print usage message and exit */ 124void 125usage(void) 126{ 127 (void) fprintf(stderr, "usage: %s [-bqSVv] [-C config] [-d lsdir] [-K pkg_dbdir] [-s sfx] command [args ...]\n" 128 "Where 'commands' and 'args' are:\n" 129 " rebuild - rebuild pkgdb from +CONTENTS files\n" 130 " rebuild-tree - rebuild +REQUIRED_BY files from forward deps\n" 131 " check [pkg ...] - check md5 checksum of installed files\n" 132 " add pkg ... - add pkg files to database\n" 133 " set variable=value pkg ... - set installation variable for package\n" 134 " unset variable pkg ... - unset installation variable for package\n" 135 " lsall /path/to/pkgpattern - list all pkgs matching the pattern\n" 136 " lsbest /path/to/pkgpattern - list pkgs matching the pattern best\n" 137 " dump - dump database\n" 138 " pmatch pattern pkg - returns true if pkg matches pattern, otherwise false\n" 139 " fetch-pkg-vulnerabilities [-s] - fetch new vulnerability file\n" 140 " check-pkg-vulnerabilities [-s] <file> - check syntax and checksums of the vulnerability file\n" 141 " audit [-eis] [-t type] ... - check installed packages for vulnerabilities\n" 142 " audit-pkg [-eis] [-t type] ... - check listed packages for vulnerabilities\n" 143 " audit-batch [-eis] [-t type] ... - check packages in listed files for vulnerabilities\n" 144 " audit-history [-t type] ... - print all advisories for package names\n" 145 " check-license <condition> - check if condition is acceptable\n" 146 " check-single-license <license> - check if license is acceptable\n" 147 " config-var name - print current value of the configuration variable\n" 148 " check-signature ... - verify the signature of packages\n" 149 " x509-sign-package pkg spkg key cert - create X509 signature\n" 150 " gpg-sign-package pkg spkg - create GPG signature\n", 151 getprogname()); 152 exit(EXIT_FAILURE); 153} 154 155/* 156 * add1pkg(<pkg>) 157 * adds the files listed in the +CONTENTS of <pkg> into the 158 * pkgdb.byfile.db database file in the current package dbdir. It 159 * returns the number of files added to the database file. 160 */ 161static int 162add_pkg(const char *pkgdir, void *vp) 163{ 164 FILE *f; 165 plist_t *p; 166 package_t Plist; 167 char *contents; 168 char *PkgName, *dirp; 169 char file[MaxPathSize]; 170 struct pkgdb_count *count; 171 172 if (!pkgdb_open(ReadWrite)) 173 err(EXIT_FAILURE, "cannot open pkgdb"); 174 175 count = vp; 176 ++count->packages; 177 178 contents = pkgdb_pkg_file(pkgdir, CONTENTS_FNAME); 179 if ((f = fopen(contents, "r")) == NULL) 180 errx(EXIT_FAILURE, "%s: can't open `%s'", pkgdir, CONTENTS_FNAME); 181 free(contents); 182 183 read_plist(&Plist, f); 184 if ((p = find_plist(&Plist, PLIST_NAME)) == NULL) { 185 errx(EXIT_FAILURE, "Package `%s' has no @name, aborting.", pkgdir); 186 } 187 188 PkgName = p->name; 189 dirp = NULL; 190 for (p = Plist.head; p; p = p->next) { 191 switch(p->type) { 192 case PLIST_FILE: 193 if (dirp == NULL) { 194 errx(EXIT_FAILURE, "@cwd not yet found, please send-pr!"); 195 } 196 (void) snprintf(file, sizeof(file), "%s/%s", dirp, p->name); 197 if (!(isfile(file) || islinktodir(file))) { 198 if (isbrokenlink(file)) { 199 warnx("%s: Symlink `%s' exists and is in %s but target does not exist!", 200 PkgName, file, CONTENTS_FNAME); 201 } else { 202 warnx("%s: File `%s' is in %s but not on filesystem!", 203 PkgName, file, CONTENTS_FNAME); 204 } 205 } else { 206 pkgdb_store(file, PkgName); 207 ++count->files; 208 } 209 break; 210 case PLIST_PKGDIR: 211 add_pkgdir(PkgName, dirp, p->name); 212 ++count->directories; 213 break; 214 case PLIST_CWD: 215 if (strcmp(p->name, ".") != 0) 216 dirp = p->name; 217 else 218 dirp = pkgdb_pkg_dir(pkgdir); 219 break; 220 case PLIST_IGNORE: 221 p = p->next; 222 break; 223 case PLIST_SHOW_ALL: 224 case PLIST_SRC: 225 case PLIST_CMD: 226 case PLIST_CHMOD: 227 case PLIST_CHOWN: 228 case PLIST_CHGRP: 229 case PLIST_COMMENT: 230 case PLIST_NAME: 231 case PLIST_UNEXEC: 232 case PLIST_DISPLAY: 233 case PLIST_PKGDEP: 234 case PLIST_DIR_RM: 235 case PLIST_OPTION: 236 case PLIST_PKGCFL: 237 case PLIST_BLDDEP: 238 break; 239 } 240 } 241 free_plist(&Plist); 242 fclose(f); 243 pkgdb_close(); 244 245 return 0; 246} 247 248static void 249rebuild(void) 250{ 251 char *cachename; 252 struct pkgdb_count count; 253 254 count.files = 0; 255 count.directories = 0; 256 count.packages = 0; 257 258 cachename = pkgdb_get_database(); 259 if (unlink(cachename) != 0 && errno != ENOENT) 260 err(EXIT_FAILURE, "unlink %s", cachename); 261 262 setbuf(stdout, NULL); 263 264 iterate_pkg_db(add_pkg, &count); 265 266 printf("\n"); 267 printf("Stored %" PRIzu " file%s and %" PRIzu " explicit director%s" 268 " from %"PRIzu " package%s in %s.\n", 269 count.files, count.files == 1 ? "" : "s", 270 count.directories, count.directories == 1 ? "y" : "ies", 271 count.packages, count.packages == 1 ? "" : "s", 272 cachename); 273} 274 275static int 276lspattern(const char *pkg, void *vp) 277{ 278 const char *dir = vp; 279 printf("%s/%s\n", dir, pkg); 280 return 0; 281} 282 283static int 284lsbasepattern(const char *pkg, void *vp) 285{ 286 puts(pkg); 287 return 0; 288} 289 290static int 291remove_required_by(const char *pkgname, void *cookie) 292{ 293 char *path; 294 295 path = pkgdb_pkg_file(pkgname, REQUIRED_BY_FNAME); 296 297 if (unlink(path) == -1 && errno != ENOENT) 298 err(EXIT_FAILURE, "Cannot remove %s", path); 299 300 free(path); 301 302 return 0; 303} 304 305static void 306add_required_by(const char *pattern, const char *pkgname, struct pkg_reqd_by_head *hash) 307{ 308 struct pkg_reqd_by_head *phead; 309 struct pkg_reqd_by *pkg; 310 struct reqd_by_entry_head *ehead; 311 struct reqd_by_entry *entry; 312 char *best_installed; 313 int i; 314 315 best_installed = find_best_matching_installed_pkg(pattern, 1); 316 if (best_installed == NULL) { 317 warnx("Dependency %s of %s unresolved", pattern, pkgname); 318 return; 319 } 320 321 /* 322 * Find correct reqd_by head based on hash of best_installed, which is 323 * the package in question that we are adding +REQUIRED_BY entries for. 324 */ 325 phead = &hash[PKG_HASH_ENTRY(best_installed)]; 326 327 /* 328 * Look for an existing entry in this hash list. 329 */ 330 SLIST_FOREACH(pkg, phead, entries) { 331 if (strcmp(pkg->pkgname, best_installed) == 0) { 332 333 /* 334 * Found an entry, now see if it already has a 335 * +REQUIRED_BY entry recorded for this pkgname, 336 * and if not then add it. 337 */ 338 ehead = &pkg->required_by[PKG_HASH_ENTRY(pkgname)]; 339 SLIST_FOREACH(entry, ehead, entries) { 340 if (strcmp(entry->pkgname, pkgname) == 0) 341 break; 342 } 343 344 if (entry == NULL) { 345 entry = xmalloc(sizeof(*entry)); 346 entry->pkgname = xstrdup(pkgname); 347 SLIST_INSERT_HEAD(ehead, entry, entries); 348 } 349 350 break; 351 } 352 } 353 354 /* 355 * Create new package containing its first +REQUIRED_BY entry. 356 */ 357 if (pkg == NULL) { 358 pkg = xmalloc(sizeof(*pkg)); 359 pkg->pkgname = xstrdup(best_installed); 360 for (i = 0; i < PKG_HASH_SIZE; i++) 361 SLIST_INIT(&pkg->required_by[i]); 362 363 ehead = &pkg->required_by[PKG_HASH_ENTRY(pkgname)]; 364 entry = xmalloc(sizeof(*entry)); 365 entry->pkgname = xstrdup(pkgname); 366 SLIST_INSERT_HEAD(ehead, entry, entries); 367 368 SLIST_INSERT_HEAD(phead, pkg, entries); 369 } 370 371 free(best_installed); 372} 373 374static int 375add_depends_of(const char *pkgname, void *cookie) 376{ 377 FILE *fp; 378 struct pkg_reqd_by_head *h = cookie; 379 plist_t *p; 380 package_t plist; 381 char *path; 382 383 path = pkgdb_pkg_file(pkgname, CONTENTS_FNAME); 384 if ((fp = fopen(path, "r")) == NULL) 385 errx(EXIT_FAILURE, "Cannot read %s of package %s", 386 CONTENTS_FNAME, pkgname); 387 free(path); 388 read_plist(&plist, fp); 389 fclose(fp); 390 391 for (p = plist.head; p; p = p->next) { 392 if (p->type == PLIST_PKGDEP) 393 add_required_by(p->name, pkgname, h); 394 } 395 396 free_plist(&plist); 397 398 return 0; 399} 400 401static void 402rebuild_tree(void) 403{ 404 FILE *fp; 405 struct pkg_reqd_by_head pkgs[PKG_HASH_SIZE]; 406 struct pkg_reqd_by *p; 407 struct reqd_by_entry *e; 408 int fd, i, j; 409 char *path; 410 411 for (i = 0; i < PKG_HASH_SIZE; i++) 412 SLIST_INIT(&pkgs[i]); 413 414 /* 415 * First, calculate all of the +REQUIRED_BY entries and store in our 416 * pkgs hashed list. 417 */ 418 if (iterate_pkg_db(add_depends_of, &pkgs) == -1) 419 errx(EXIT_FAILURE, "cannot iterate pkgdb"); 420 421 /* 422 * Now we can remove all existing +REQUIRED_BY files. 423 */ 424 if (iterate_pkg_db(remove_required_by, NULL) == -1) 425 errx(EXIT_FAILURE, "cannot iterate pkgdb"); 426 427 /* 428 * Finally, write out all the new +REQUIRED_BY files. 429 */ 430 for (i = 0; i < PKG_HASH_SIZE; i++) { 431 SLIST_FOREACH(p, &pkgs[i], entries) { 432 path = pkgdb_pkg_file(p->pkgname, REQUIRED_BY_FNAME); 433 434 if ((fd = open(path, O_WRONLY | O_APPEND | O_CREAT, 435 0644)) == -1) 436 errx(EXIT_FAILURE, "cannot write to %s", path); 437 438 if ((fp = fdopen(fd, "a")) == NULL) 439 errx(EXIT_FAILURE, "cannot open %s", path); 440 441 for (j = 0; j < PKG_HASH_SIZE; j++) { 442 SLIST_FOREACH(e, &p->required_by[j], entries) 443 fprintf(fp, "%s\n", e->pkgname); 444 } 445 if (fclose(fp) == EOF) { 446 remove(path); 447 errx(EXIT_FAILURE, "cannot close %s", path); 448 } 449 } 450 } 451} 452 453int 454main(int argc, char *argv[]) 455{ 456 Boolean use_default_sfx = TRUE; 457 Boolean show_basename_only = FALSE; 458 char lsdir[MaxPathSize]; 459 char sfx[MaxPathSize]; 460 char *lsdirp = NULL; 461 int ch; 462 463 setprogname(argv[0]); 464 465 if (argc < 2) 466 usage(); 467 468 while ((ch = getopt(argc, argv, Options)) != -1) 469 switch (ch) { 470 case 'C': 471 config_file = optarg; 472 break; 473 474 case 'K': 475 pkgdb_set_dir(optarg, 3); 476 break; 477 478 case 'S': 479 sfx[0] = 0x0; 480 use_default_sfx = FALSE; 481 break; 482 483 case 'V': 484 show_version(); 485 /* NOTREACHED */ 486 487 case 'b': 488 show_basename_only = TRUE; 489 break; 490 491 case 'd': 492 (void) strlcpy(lsdir, optarg, sizeof(lsdir)); 493 lsdirp = lsdir; 494 break; 495 496 case 'q': 497 quiet = 1; 498 break; 499 500 case 's': 501 (void) strlcpy(sfx, optarg, sizeof(sfx)); 502 use_default_sfx = FALSE; 503 break; 504 505 case 'v': 506 ++verbose; 507 break; 508 509 default: 510 usage(); 511 /* NOTREACHED */ 512 } 513 514 argc -= optind; 515 argv += optind; 516 517 if (argc <= 0) { 518 usage(); 519 } 520 521 /* 522 * config-var is reading the config file implicitly, 523 * so skip it here. 524 */ 525 if (strcasecmp(argv[0], "config-var") != 0) 526 pkg_install_config(); 527 528 if (use_default_sfx) 529 (void) strlcpy(sfx, DEFAULT_SFX, sizeof(sfx)); 530 531 if (strcasecmp(argv[0], "pmatch") == 0) { 532 533 char *pattern, *pkg; 534 535 argv++; /* "pmatch" */ 536 537 if (argv[0] == NULL || argv[1] == NULL) { 538 usage(); 539 } 540 541 pattern = argv[0]; 542 pkg = argv[1]; 543 544 if (pkg_match(pattern, pkg)){ 545 return 0; 546 } else { 547 return 1; 548 } 549 550 } else if (strcasecmp(argv[0], "rebuild") == 0) { 551 552 rebuild(); 553 printf("Done.\n"); 554 555 556 } else if (strcasecmp(argv[0], "rebuild-tree") == 0) { 557 558 rebuild_tree(); 559 printf("Done.\n"); 560 561 } else if (strcasecmp(argv[0], "check") == 0) { 562 argv++; /* "check" */ 563 564 check(argv); 565 566 if (!quiet) { 567 printf("Done.\n"); 568 } 569 570 } else if (strcasecmp(argv[0], "lsall") == 0) { 571 argv++; /* "lsall" */ 572 573 while (*argv != NULL) { 574 /* args specified */ 575 int rc; 576 const char *basep, *dir; 577 578 dir = lsdirp ? lsdirp : dirname_of(*argv); 579 basep = basename_of(*argv); 580 581 if (show_basename_only) 582 rc = match_local_files(dir, use_default_sfx, 1, basep, lsbasepattern, NULL); 583 else 584 rc = match_local_files(dir, use_default_sfx, 1, basep, lspattern, __UNCONST(dir)); 585 if (rc == -1) 586 errx(EXIT_FAILURE, "Error from match_local_files(\"%s\", \"%s\", ...)", 587 dir, basep); 588 589 argv++; 590 } 591 592 } else if (strcasecmp(argv[0], "lsbest") == 0) { 593 argv++; /* "lsbest" */ 594 595 while (*argv != NULL) { 596 /* args specified */ 597 const char *basep, *dir; 598 char *p; 599 600 dir = lsdirp ? lsdirp : dirname_of(*argv); 601 basep = basename_of(*argv); 602 603 p = find_best_matching_file(dir, basep, use_default_sfx, 1); 604 605 if (p) { 606 if (show_basename_only) 607 printf("%s\n", p); 608 else 609 printf("%s/%s\n", dir, p); 610 free(p); 611 } 612 613 argv++; 614 } 615 } else if (strcasecmp(argv[0], "list") == 0 || 616 strcasecmp(argv[0], "dump") == 0) { 617 618 pkgdb_dump(); 619 620 } else if (strcasecmp(argv[0], "add") == 0) { 621 struct pkgdb_count count; 622 623 count.files = 0; 624 count.directories = 0; 625 count.packages = 0; 626 627 for (++argv; *argv != NULL; ++argv) 628 add_pkg(*argv, &count); 629 } else if (strcasecmp(argv[0], "set") == 0) { 630 argv++; /* "set" */ 631 set_unset_variable(argv, FALSE); 632 } else if (strcasecmp(argv[0], "unset") == 0) { 633 argv++; /* "unset" */ 634 set_unset_variable(argv, TRUE); 635 } else if (strcasecmp(argv[0], "digest") == 0) { 636 argv++; /* "digest" */ 637 digest_input(argv); 638 } else if (strcasecmp(argv[0], "config-var") == 0) { 639 argv++; 640 if (argv == NULL || argv[1] != NULL) 641 errx(EXIT_FAILURE, "config-var takes exactly one argument"); 642 pkg_install_show_variable(argv[0]); 643 } else if (strcasecmp(argv[0], "check-license") == 0) { 644 if (argv[1] == NULL) 645 errx(EXIT_FAILURE, "check-license takes exactly one argument"); 646 647 load_license_lists(); 648 649 switch (acceptable_pkg_license(argv[1])) { 650 case 0: 651 puts("no"); 652 return 0; 653 case 1: 654 puts("yes"); 655 return 0; 656 case -1: 657 errx(EXIT_FAILURE, "invalid license condition"); 658 } 659 } else if (strcasecmp(argv[0], "check-single-license") == 0) { 660 if (argv[1] == NULL) 661 errx(EXIT_FAILURE, "check-license takes exactly one argument"); 662 load_license_lists(); 663 664 switch (acceptable_license(argv[1])) { 665 case 0: 666 puts("no"); 667 return 0; 668 case 1: 669 puts("yes"); 670 return 0; 671 case -1: 672 errx(EXIT_FAILURE, "invalid license"); 673 } 674 } 675#ifndef BOOTSTRAP 676 else if (strcasecmp(argv[0], "findbest") == 0) { 677 struct url *url; 678 char *output; 679 int rc; 680 681 process_pkg_path(); 682 683 rc = 0; 684 for (++argv; *argv != NULL; ++argv) { 685 url = find_best_package(NULL, *argv, 1); 686 if (url == NULL) { 687 rc = 1; 688 continue; 689 } 690 output = fetchStringifyURL(url); 691 puts(output); 692 fetchFreeURL(url); 693 free(output); 694 } 695 696 return rc; 697 } else if (strcasecmp(argv[0], "fetch-pkg-vulnerabilities") == 0) { 698 fetch_pkg_vulnerabilities(--argc, ++argv); 699 } else if (strcasecmp(argv[0], "check-pkg-vulnerabilities") == 0) { 700 check_pkg_vulnerabilities(--argc, ++argv); 701 } else if (strcasecmp(argv[0], "audit") == 0) { 702 audit_pkgdb(--argc, ++argv); 703 } else if (strcasecmp(argv[0], "audit-pkg") == 0) { 704 audit_pkg(--argc, ++argv); 705 } else if (strcasecmp(argv[0], "audit-batch") == 0) { 706 audit_batch(--argc, ++argv); 707 } else if (strcasecmp(argv[0], "audit-history") == 0) { 708 audit_history(--argc, ++argv); 709 } else if (strcasecmp(argv[0], "check-signature") == 0) { 710 struct archive *pkg; 711 int rc; 712 713 rc = 0; 714 for (--argc, ++argv; argc > 0; --argc, ++argv) { 715 char *archive_name; 716 717 pkg = open_archive(*argv, &archive_name); 718 if (pkg == NULL) { 719 warnx("%s could not be opened", *argv); 720 continue; 721 } 722 if (pkg_full_signature_check(archive_name, &pkg)) 723 rc = 1; 724 free(archive_name); 725 if (pkg != NULL) 726 archive_read_free(pkg); 727 } 728 return rc; 729 } else if (strcasecmp(argv[0], "x509-sign-package") == 0) { 730#ifdef HAVE_SSL 731 --argc; 732 ++argv; 733 if (argc != 4) 734 errx(EXIT_FAILURE, "x509-sign-package takes exactly four arguments"); 735 pkg_sign_x509(argv[0], argv[1], argv[2], argv[3]); 736#else 737 errx(EXIT_FAILURE, "OpenSSL support is not included"); 738#endif 739 } else if (strcasecmp(argv[0], "gpg-sign-package") == 0) { 740 --argc; 741 ++argv; 742 if (argc != 2) 743 errx(EXIT_FAILURE, "gpg-sign-package takes exactly two arguments"); 744 pkg_sign_gpg(argv[0], argv[1]); 745 } 746#endif 747 else { 748 usage(); 749 } 750 751 return 0; 752} 753 754struct set_installed_info_arg { 755 char *variable; 756 char *value; 757 int got_match; 758}; 759 760static int 761set_installed_info_var(const char *name, void *cookie) 762{ 763 struct set_installed_info_arg *arg = cookie; 764 char *filename; 765 int retval; 766 767 filename = pkgdb_pkg_file(name, INSTALLED_INFO_FNAME); 768 769 retval = var_set(filename, arg->variable, arg->value); 770 771 free(filename); 772 arg->got_match = 1; 773 774 return retval; 775} 776 777static void 778set_unset_variable(char **argv, Boolean unset) 779{ 780 struct set_installed_info_arg arg; 781 char *eq; 782 char *variable; 783 int ret = 0; 784 785 if (argv[0] == NULL || argv[1] == NULL) 786 usage(); 787 788 variable = NULL; 789 790 if (unset) { 791 arg.variable = argv[0]; 792 arg.value = NULL; 793 } else { 794 eq = NULL; 795 if ((eq=strchr(argv[0], '=')) == NULL) 796 usage(); 797 798 variable = xmalloc(eq-argv[0]+1); 799 strlcpy(variable, argv[0], eq-argv[0]+1); 800 801 arg.variable = variable; 802 arg.value = eq+1; 803 804 if (strcmp(variable, AUTOMATIC_VARNAME) == 0 && 805 strcasecmp(arg.value, "yes") != 0 && 806 strcasecmp(arg.value, "no") != 0) { 807 errx(EXIT_FAILURE, 808 "unknown value `%s' for " AUTOMATIC_VARNAME, 809 arg.value); 810 } 811 } 812 if (strpbrk(arg.variable, "ABCDEFGHIJKLMNOPQRSTUVWXYZ") != NULL) { 813 free(variable); 814 errx(EXIT_FAILURE, 815 "variable name must not contain uppercase letters"); 816 } 817 818 argv++; 819 while (*argv != NULL) { 820 arg.got_match = 0; 821 if (match_installed_pkgs(*argv, set_installed_info_var, &arg) == -1) 822 errx(EXIT_FAILURE, "Cannot process pkdbdb"); 823 if (arg.got_match == 0) { 824 char *pattern; 825 826 if (ispkgpattern(*argv)) { 827 warnx("no matching pkg for `%s'", *argv); 828 ret++; 829 } else { 830 pattern = xasprintf("%s-[0-9]*", *argv); 831 832 if (match_installed_pkgs(pattern, set_installed_info_var, &arg) == -1) 833 errx(EXIT_FAILURE, "Cannot process pkdbdb"); 834 835 if (arg.got_match == 0) { 836 warnx("cannot find package %s", *argv); 837 ++ret; 838 } 839 free(pattern); 840 } 841 } 842 843 argv++; 844 } 845 846 if (ret > 0) 847 exit(EXIT_FAILURE); 848 849 free(variable); 850 851 return; 852} 853 854static void 855digest_input(char **argv) 856{ 857 char digest[SHA256_DIGEST_STRING_LENGTH]; 858 int failures = 0; 859 860 while (*argv != NULL) { 861 if (SHA256_File(*argv, digest)) { 862 puts(digest); 863 } else { 864 warn("cannot process %s", *argv); 865 ++failures; 866 } 867 argv++; 868 } 869 if (failures) 870 exit(EXIT_FAILURE); 871} 872