1/* $NetBSD: perform.c,v 1.4 2021/04/10 19:49:59 nia 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: perform.c,v 1.4 2021/04/10 19:49:59 nia Exp $"); 11 12/*- 13 * Copyright (c) 2008 Joerg Sonnenberger <joerg@NetBSD.org>. 14 * All rights reserved. 15 * 16 * Redistribution and use in source and binary forms, with or without 17 * modification, are permitted provided that the following conditions 18 * are met: 19 * 20 * 1. Redistributions of source code must retain the above copyright 21 * notice, this list of conditions and the following disclaimer. 22 * 2. Redistributions in binary form must reproduce the above copyright 23 * notice, this list of conditions and the following disclaimer in 24 * the documentation and/or other materials provided with the 25 * distribution. 26 * 27 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 28 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 29 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 30 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 31 * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 32 * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, 33 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 34 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 35 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 36 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 37 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 38 * SUCH DAMAGE. 39 */ 40 41/* 42 * FreeBSD install - a package for the installation and maintainance 43 * of non-core utilities. 44 * 45 * Redistribution and use in source and binary forms, with or without 46 * modification, are permitted provided that the following conditions 47 * are met: 48 * 1. Redistributions of source code must retain the above copyright 49 * notice, this list of conditions and the following disclaimer. 50 * 2. Redistributions in binary form must reproduce the above copyright 51 * notice, this list of conditions and the following disclaimer in the 52 * documentation and/or other materials provided with the distribution. 53 * 54 * Jordan K. Hubbard 55 * 23 Aug 1993 56 * 57 * This is the main body of the info module. 58 * 59 */ 60 61#include "lib.h" 62#include "info.h" 63 64#if HAVE_SYS_TYPES_H 65#include <sys/types.h> 66#endif 67#if HAVE_SYS_STAT_H 68#include <sys/stat.h> 69#endif 70#if HAVE_SYS_QUEUE_H 71#include <sys/queue.h> 72#endif 73#if HAVE_SYS_WAIT_H 74#include <sys/wait.h> 75#endif 76 77#ifndef BOOTSTRAP 78#include <archive.h> 79#include <archive_entry.h> 80#endif 81#if HAVE_ERR_H 82#include <err.h> 83#endif 84#include <ctype.h> 85#include <dirent.h> 86#include <errno.h> 87#include <fcntl.h> 88#include <limits.h> 89#include <stddef.h> 90#include <signal.h> 91 92#define LOAD_CONTENTS (1 << 0) 93#define LOAD_COMMENT (1 << 1) 94#define LOAD_DESC (1 << 2) 95#define LOAD_INSTALL (1 << 3) 96#define LOAD_DEINSTALL (1 << 4) 97#define LOAD_DISPLAY (1 << 5) 98#define LOAD_MTREE (1 << 6) 99#define LOAD_BUILD_VERSION (1 << 7) 100#define LOAD_BUILD_INFO (1 << 8) 101#define LOAD_SIZE_PKG (1 << 9) 102#define LOAD_SIZE_ALL (1 << 10) 103#define LOAD_PRESERVE (1 << 11) 104#define LOAD_REQUIRED_BY (1 << 12) 105#define LOAD_INSTALLED_INFO (1 << 13) 106 107static const struct pkg_meta_desc { 108 size_t entry_offset; 109 const char *entry_filename; 110 int entry_mask; 111 int required_file; 112} pkg_meta_descriptors[] = { 113 { offsetof(struct pkg_meta, meta_contents), CONTENTS_FNAME, 114 LOAD_CONTENTS, 1}, 115 { offsetof(struct pkg_meta, meta_comment), COMMENT_FNAME, 116 LOAD_COMMENT, 1 }, 117 { offsetof(struct pkg_meta, meta_desc), DESC_FNAME, 118 LOAD_DESC, 1 }, 119 { offsetof(struct pkg_meta, meta_install), INSTALL_FNAME, 120 LOAD_INSTALL, 0 }, 121 { offsetof(struct pkg_meta, meta_deinstall), DEINSTALL_FNAME, 122 LOAD_DEINSTALL, 0 }, 123 { offsetof(struct pkg_meta, meta_display), DISPLAY_FNAME, 124 LOAD_DISPLAY, 0 }, 125 { offsetof(struct pkg_meta, meta_mtree), MTREE_FNAME, 126 LOAD_MTREE, 0 }, 127 { offsetof(struct pkg_meta, meta_build_version), BUILD_VERSION_FNAME, 128 LOAD_BUILD_VERSION, 0 }, 129 { offsetof(struct pkg_meta, meta_build_info), BUILD_INFO_FNAME, 130 LOAD_BUILD_INFO, 0 }, 131 { offsetof(struct pkg_meta, meta_size_pkg), SIZE_PKG_FNAME, 132 LOAD_SIZE_PKG, 0 }, 133 { offsetof(struct pkg_meta, meta_size_all), SIZE_ALL_FNAME, 134 LOAD_SIZE_ALL, 0 }, 135 { offsetof(struct pkg_meta, meta_preserve), PRESERVE_FNAME, 136 LOAD_PRESERVE, 0 }, 137 { offsetof(struct pkg_meta, meta_required_by), REQUIRED_BY_FNAME, 138 LOAD_REQUIRED_BY, 0 }, 139 { offsetof(struct pkg_meta, meta_installed_info), INSTALLED_INFO_FNAME, 140 LOAD_INSTALLED_INFO, 0 }, 141 { 0, NULL, 0, 0 }, 142}; 143 144static int desired_meta_data; 145 146static void 147free_pkg_meta(struct pkg_meta *meta) 148{ 149 const struct pkg_meta_desc *descr; 150 151 for (descr = pkg_meta_descriptors; descr->entry_filename; ++descr) 152 free(*(char **)((char *)meta + descr->entry_offset)); 153 154 free(meta); 155} 156 157#ifndef BOOTSTRAP 158static struct pkg_meta * 159read_meta_data_from_archive(struct archive *archive, 160 struct archive_entry *entry) 161{ 162 struct pkg_meta *meta; 163 const char *fname; 164 const struct pkg_meta_desc *descr, *last_descr; 165 char **target; 166 int64_t size; 167 int r, found_required; 168 169 found_required = 0; 170 171 meta = xcalloc(1, sizeof(*meta)); 172 173 last_descr = 0; 174 if (entry != NULL) { 175 r = ARCHIVE_OK; 176 goto has_entry; 177 } 178 179 while ((r = archive_read_next_header(archive, &entry)) == ARCHIVE_OK) { 180has_entry: 181 fname = archive_entry_pathname(entry); 182 183 for (descr = pkg_meta_descriptors; descr->entry_filename; 184 ++descr) { 185 if (strcmp(descr->entry_filename, fname) == 0) 186 break; 187 } 188 if (descr->entry_filename == NULL) 189 break; 190 191 if (descr->required_file) 192 ++found_required; 193 194 target = (char **)((char *)meta + descr->entry_offset); 195 if (*target) 196 errx(2, "duplicate entry, package corrupt"); 197 if (descr < last_descr) 198 warnx("misordered package, continuing"); 199 else 200 last_descr = descr; 201 202 if ((descr->entry_mask & desired_meta_data) == 0) { 203 if (archive_read_data_skip(archive)) 204 errx(2, "cannot read package meta data"); 205 continue; 206 } 207 208 size = archive_entry_size(entry); 209 if (size > SSIZE_MAX - 1) 210 errx(2, "package meta data too large to process"); 211 *target = xmalloc(size + 1); 212 if (archive_read_data(archive, *target, size) != size) 213 errx(2, "cannot read package meta data"); 214 (*target)[size] = '\0'; 215 } 216 217 for (descr = pkg_meta_descriptors; descr->entry_filename; ++descr) { 218 if (descr->required_file) 219 --found_required; 220 } 221 222 meta->is_installed = 0; 223 if (found_required != 0 || (r != ARCHIVE_OK && r != ARCHIVE_EOF)) { 224 free_pkg_meta(meta); 225 meta = NULL; 226 } 227 228 return meta; 229} 230#endif 231 232static struct pkg_meta * 233read_meta_data_from_pkgdb(const char *pkg) 234{ 235 struct pkg_meta *meta; 236 const struct pkg_meta_desc *descr; 237 char **target; 238 char *fname; 239 int fd; 240 struct stat st; 241 242 meta = xcalloc(1, sizeof(*meta)); 243 244 for (descr = pkg_meta_descriptors; descr->entry_filename; ++descr) { 245 if ((descr->entry_mask & desired_meta_data) == 0) 246 continue; 247 248 fname = pkgdb_pkg_file(pkg, descr->entry_filename); 249 fd = open(fname, O_RDONLY, 0); 250 free(fname); 251 if (fd == -1) { 252 if (errno == ENOENT && descr->required_file == 0) 253 continue; 254 err(2, "cannot read meta data file %s of package %s", 255 descr->entry_filename, pkg); 256 } 257 target = (char **)((char *)meta + descr->entry_offset); 258 259 if (fstat(fd, &st) == -1) 260 err(2, "cannot stat meta data"); 261 if ((st.st_mode & S_IFMT) != S_IFREG) 262 errx(1, "meta data is not regular file"); 263 if (st.st_size > SSIZE_MAX - 1) 264 err(2, "meta data file too large to process"); 265 *target = xmalloc(st.st_size + 1); 266 if (read(fd, *target, st.st_size) != st.st_size) 267 err(2, "cannot read meta data"); 268 (*target)[st.st_size] = '\0'; 269 close(fd); 270 } 271 272 meta->is_installed = 1; 273 274 return meta; 275} 276 277static void 278build_full_reqby(lpkg_head_t *reqby, struct pkg_meta *meta, int limit) 279{ 280 char *iter, *eol, *next; 281 lpkg_t *lpp; 282 struct pkg_meta *meta_dep; 283 284 if (limit == 65536) 285 errx(1, "Cycle in the dependency tree, bailing out"); 286 287 if (meta->is_installed == 0 || meta->meta_required_by == NULL) 288 return; 289 290 for (iter = meta->meta_required_by; *iter != '\0'; iter = next) { 291 eol = iter + strcspn(iter, "\n"); 292 if (*eol == '\n') 293 next = eol + 1; 294 else 295 next = eol; 296 if (iter == eol) 297 continue; 298 TAILQ_FOREACH(lpp, reqby, lp_link) { 299 if (strlen(lpp->lp_name) + iter != eol) 300 continue; 301 if (memcmp(lpp->lp_name, iter, eol - iter) == 0) 302 break; 303 } 304 if (lpp != NULL) 305 continue; 306 *eol = '\0'; 307 lpp = alloc_lpkg(iter); 308 if (next != eol) 309 *eol = '\n'; 310 311 meta_dep = read_meta_data_from_pkgdb(lpp->lp_name); 312 if (meta_dep == NULL) 313 continue; 314 build_full_reqby(reqby, meta_dep, limit + 1); 315 free_pkg_meta(meta_dep); 316 317 TAILQ_INSERT_HEAD(reqby, lpp, lp_link); 318 } 319} 320 321static lfile_head_t files; 322 323static int 324pkg_do(const char *pkg) 325{ 326 struct pkg_meta *meta; 327 int code = 0; 328 const char *binpkgfile = NULL; 329 char *pkgdir; 330 331 if (IS_URL(pkg) || (fexists(pkg) && isfile(pkg))) { 332#ifdef BOOTSTRAP 333 errx(2, "Binary packages not supported during bootstrap"); 334#else 335 struct archive *archive; 336 struct archive_entry *entry; 337 char *archive_name, *pkgname; 338 339 archive = open_archive(pkg, &archive_name); 340 if (archive == NULL) { 341 warnx("can't find package `%s', skipped", pkg); 342 return -1; 343 } 344 pkgname = NULL; 345 entry = NULL; 346 pkg_verify_signature(archive_name, &archive, &entry, &pkgname); 347 if (archive == NULL) 348 return -1; 349 free(pkgname); 350 351 meta = read_meta_data_from_archive(archive, entry); 352 archive_read_free(archive); 353 if (!IS_URL(pkg)) 354 binpkgfile = pkg; 355#endif 356 } else { 357 /* 358 * It's not an uninstalled package, try and find it among the 359 * installed 360 */ 361 pkgdir = pkgdb_pkg_dir(pkg); 362 if (!fexists(pkgdir) || !(isdir(pkgdir) || islinktodir(pkgdir))) { 363 switch (add_installed_pkgs_by_basename(pkg, &pkgs)) { 364 case 1: 365 return 0; 366 case 0: 367 /* No match */ 368 warnx("can't find package `%s'", pkg); 369 return 1; 370 case -1: 371 errx(EXIT_FAILURE, "Error during search in pkgdb for %s", pkg); 372 } 373 } 374 free(pkgdir); 375 meta = read_meta_data_from_pkgdb(pkg); 376 } 377 378 if (meta == NULL) { 379 warnx("invalid package `%s' skipped", pkg); 380 return 1; 381 } 382 383 /* 384 * Index is special info type that has to override all others to make 385 * any sense. 386 */ 387 if (Flags & SHOW_INDEX) { 388 char tmp[MaxPathSize]; 389 390 (void) snprintf(tmp, sizeof(tmp), "%-19s ", pkg); 391 show_index(meta->meta_comment, tmp); 392 } else if (Flags & SHOW_BI_VAR) { 393 if (strcspn(BuildInfoVariable, "ABCDEFGHIJKLMNOPQRSTUVWXYZ") 394 == strlen(BuildInfoVariable)) { 395 if (meta->meta_installed_info) 396 show_var(meta->meta_installed_info, BuildInfoVariable); 397 } else { 398 if (meta->meta_build_info) 399 show_var(meta->meta_build_info, BuildInfoVariable); 400 else 401 warnx("Build information missing"); 402 } 403 } else { 404 package_t plist; 405 406 /* Read the contents list */ 407 parse_plist(&plist, meta->meta_contents); 408 409 /* Start showing the package contents */ 410 if (!Quiet && !(Flags & SHOW_SUMMARY)) { 411 printf("%sInformation for %s:\n\n", InfoPrefix, pkg); 412 if (meta->meta_preserve) { 413 printf("*** PACKAGE MAY NOT BE DELETED ***\n"); 414 } 415 } 416 if (Flags & SHOW_SUMMARY) { 417 show_summary(meta, &plist, binpkgfile); 418 } 419 if (Flags & SHOW_COMMENT) { 420 show_file(meta->meta_comment, "Comment:\n", TRUE); 421 } 422 if (Flags & SHOW_DEPENDS) { 423 show_depends("Requires:\n", &plist); 424 } 425 if (Flags & SHOW_BLD_DEPENDS) { 426 show_bld_depends("Built using:\n", &plist); 427 } 428 if ((Flags & SHOW_REQBY) && meta->meta_required_by) { 429 show_file(meta->meta_required_by, "Required by:\n", TRUE); 430 } 431 if ((Flags & SHOW_FULL_REQBY) && meta->is_installed) { 432 lpkg_head_t reqby; 433 TAILQ_INIT(&reqby); 434 build_full_reqby(&reqby, meta, 0); 435 show_list(&reqby, "Full required by list:\n"); 436 } 437 if (Flags & SHOW_DESC) { 438 show_file(meta->meta_desc, "Description:\n", TRUE); 439 } 440 if ((Flags & SHOW_DISPLAY) && meta->meta_display) { 441 show_file(meta->meta_display, "Install notice:\n", 442 TRUE); 443 } 444 if (Flags & SHOW_PLIST) { 445 show_plist("Packing list:\n", &plist, PLIST_SHOW_ALL); 446 } 447 if ((Flags & SHOW_INSTALL) && meta->meta_install) { 448 show_file(meta->meta_install, "Install script:\n", 449 TRUE); 450 } 451 if ((Flags & SHOW_DEINSTALL) && meta->meta_deinstall) { 452 show_file(meta->meta_deinstall, "De-Install script:\n", 453 TRUE); 454 } 455 if ((Flags & SHOW_MTREE) && meta->meta_mtree) { 456 show_file(meta->meta_mtree, "mtree file:\n", TRUE); 457 } 458 if (Flags & SHOW_PREFIX) { 459 show_plist("Prefix(s):\n", &plist, PLIST_CWD); 460 } 461 if (Flags & SHOW_FILES) { 462 show_files("Files:\n", &plist); 463 } 464 if ((Flags & SHOW_BUILD_VERSION) && meta->meta_build_version) { 465 show_file(meta->meta_build_version, "Build version:\n", 466 TRUE); 467 } 468 if (Flags & SHOW_BUILD_INFO) { 469 if (meta->meta_build_info) { 470 show_file(meta->meta_build_info, "Build information:\n", 471 TRUE); 472 } 473 if (meta->meta_installed_info) { 474 show_file(meta->meta_installed_info, "Installed information:\n", 475 TRUE); 476 } 477 } 478 if ((Flags & SHOW_PKG_SIZE) && meta->meta_size_pkg) { 479 show_file(meta->meta_size_pkg, "Size of this package in bytes: ", 480 TRUE); 481 } 482 if ((Flags & SHOW_ALL_SIZE) && meta->meta_size_all) { 483 show_file(meta->meta_size_all, "Size in bytes including required pkgs: ", 484 TRUE); 485 } 486 if (!Quiet && !(Flags & SHOW_SUMMARY)) { 487 if (meta->meta_preserve) { 488 printf("*** PACKAGE MAY NOT BE DELETED ***\n\n"); 489 } 490 puts(InfoPrefix); 491 } 492 free_plist(&plist); 493 } 494 free_pkg_meta(meta); 495 return code; 496} 497 498struct print_matching_arg { 499 const char *pattern; 500 int got_match; 501}; 502 503static int 504print_matching_pkg(const char *pkgname, void *cookie) 505{ 506 struct print_matching_arg *arg= cookie; 507 508 if (pkg_match(arg->pattern, pkgname)) { 509 if (!Quiet) 510 puts(pkgname); 511 arg->got_match = 1; 512 } 513 514 return 0; 515} 516 517/* 518 * Returns 0 if at least one package matching pkgname. 519 * Returns 1 otherwise. 520 * 521 * If -q was not specified, print all matching packages to stdout. 522 */ 523int 524CheckForPkg(const char *pkgname) 525{ 526 struct print_matching_arg arg; 527 528 arg.pattern = pkgname; 529 arg.got_match = 0; 530 531 if (iterate_pkg_db(print_matching_pkg, &arg) == -1) { 532 warnx("cannot iterate pkgdb"); 533 return 1; 534 } 535 536 if (arg.got_match == 0 && !ispkgpattern(pkgname)) { 537 char *pattern; 538 539 pattern = xasprintf("%s-[0-9]*", pkgname); 540 541 arg.pattern = pattern; 542 arg.got_match = 0; 543 544 if (iterate_pkg_db(print_matching_pkg, &arg) == -1) { 545 free(pattern); 546 warnx("cannot iterate pkgdb"); 547 return 1; 548 } 549 free(pattern); 550 } 551 552 if (arg.got_match) 553 return 0; 554 else 555 return 1; 556} 557 558/* 559 * Returns 0 if at least one package matching pkgname. 560 * Returns 1 otherwise. 561 * 562 * If -q was not specified, print best match to stdout. 563 */ 564int 565CheckForBestPkg(const char *pkgname) 566{ 567 char *pattern, *best_match; 568 569 best_match = find_best_matching_installed_pkg(pkgname, 1); 570 if (best_match == NULL) { 571 if (ispkgpattern(pkgname)) 572 return 1; 573 574 pattern = xasprintf("%s-[0-9]*", pkgname); 575 best_match = find_best_matching_installed_pkg(pattern, 1); 576 free(pattern); 577 } 578 579 if (best_match == NULL) 580 return 1; 581 if (!Quiet) 582 puts(best_match); 583 free(best_match); 584 return 0; 585} 586 587static int 588perform_single_pkg(const char *pkg, void *cookie) 589{ 590 int *err_cnt = cookie; 591 592 if (Which == WHICH_ALL || !is_automatic_installed(pkg)) 593 *err_cnt += pkg_do(pkg); 594 595 return 0; 596} 597 598int 599pkg_perform(lpkg_head_t *pkghead) 600{ 601 int err_cnt = 0; 602 603 TAILQ_INIT(&files); 604 605 desired_meta_data = 0; 606 if ((Flags & (SHOW_INDEX | SHOW_BI_VAR)) == 0) 607 desired_meta_data |= LOAD_PRESERVE; 608 if ((Flags & (SHOW_INDEX | SHOW_BI_VAR)) == 0) 609 desired_meta_data |= LOAD_CONTENTS; 610 if (Flags & (SHOW_COMMENT | SHOW_INDEX | SHOW_SUMMARY)) 611 desired_meta_data |= LOAD_COMMENT; 612 if (Flags & (SHOW_BI_VAR | SHOW_BUILD_INFO | SHOW_SUMMARY)) 613 desired_meta_data |= LOAD_BUILD_INFO | LOAD_INSTALLED_INFO; 614 if (Flags & (SHOW_SUMMARY | SHOW_PKG_SIZE)) 615 desired_meta_data |= LOAD_SIZE_PKG; 616 if (Flags & SHOW_ALL_SIZE) 617 desired_meta_data |= LOAD_SIZE_ALL; 618 if (Flags & (SHOW_SUMMARY | SHOW_DESC)) 619 desired_meta_data |= LOAD_DESC; 620 if (Flags & (SHOW_REQBY | SHOW_FULL_REQBY)) 621 desired_meta_data |= LOAD_REQUIRED_BY; 622 if (Flags & SHOW_DISPLAY) 623 desired_meta_data |= LOAD_DISPLAY; 624 if (Flags & SHOW_INSTALL) 625 desired_meta_data |= LOAD_INSTALL; 626 if (Flags & SHOW_DEINSTALL) 627 desired_meta_data |= LOAD_DEINSTALL; 628 if (Flags & SHOW_MTREE) 629 desired_meta_data |= LOAD_MTREE; 630 if (Flags & SHOW_BUILD_VERSION) 631 desired_meta_data |= LOAD_BUILD_VERSION; 632 633 if (Which != WHICH_LIST) { 634 if (File2Pkg) { 635 /* Show all files with the package they belong to */ 636 if (pkgdb_dump() == -1) 637 err_cnt = 1; 638 } else { 639 if (iterate_pkg_db(perform_single_pkg, &err_cnt) == -1) 640 err_cnt = 1; 641 } 642 } else { 643 /* Show info on individual pkg(s) */ 644 lpkg_t *lpp; 645 646 while ((lpp = TAILQ_FIRST(pkghead)) != NULL) { 647 TAILQ_REMOVE(pkghead, lpp, lp_link); 648 err_cnt += pkg_do(lpp->lp_name); 649 free_lpkg(lpp); 650 } 651 } 652 return err_cnt; 653} 654