pkg_delete.c revision 1.3
1/*- 2 * Copyright (c) 2009 Joerg Sonnenberger <joerg@NetBSD.org>. 3 * Copyright (c) 2003 Johnny Lam <jlam@NetBSD.org>. 4 * All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in 14 * the documentation and/or other materials provided with the 15 * distribution. 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 18 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 19 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 20 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 21 * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 22 * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, 23 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 24 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 25 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 26 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 27 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 28 * SUCH DAMAGE. 29 */ 30#if HAVE_CONFIG_H 31#include "config.h" 32#endif 33#include <nbcompat.h> 34#if HAVE_SYS_CDEFS_H 35#include <sys/cdefs.h> 36#endif 37__RCSID("$NetBSD: pkg_delete.c,v 1.3 2018/03/25 04:04:36 sevan Exp $"); 38 39#if HAVE_ERR_H 40#include <err.h> 41#endif 42#include <stdio.h> 43#include <stdlib.h> 44 45#include "lib.h" 46 47static const char *pkgdb; 48static const char *destdir; 49static const char *prefix; 50 51static int keep_preserve; 52static int no_deinstall; 53static int find_by_filename; 54static int unregister_only; 55static int pkgdb_update_only; 56static int delete_recursive; 57static int delete_new_leaves; 58static int delete_automatic_leaves; 59 60static void 61usage(void) 62{ 63 fprintf(stderr, "usage: pkg_delete [-ADFfkNnORrVv] [-K pkg_dbdir]" 64 " [-P destdir] [-p prefix] pkg-name ...\n"); 65 exit(1); 66} 67 68static int 69add_by_filename(lpkg_head_t *pkgs, const char *filename) 70{ 71 lpkg_t *lpp; 72 char *s; 73 74 if ((s = pkgdb_retrieve(filename)) == NULL) { 75 warnx("No matching package for file `%s' in pkgdb", filename); 76 return 1; 77 } 78 79 /* XXX Verify that pkgdb is consistent? Trust it for now... */ 80 81 lpp = alloc_lpkg(s); 82 TAILQ_INSERT_TAIL(pkgs, lpp, lp_link); 83 return 0; 84} 85 86static int 87add_by_pattern(lpkg_head_t *pkgs, const char *pattern) 88{ 89 switch (add_installed_pkgs_by_pattern(pattern, pkgs)) { 90 case 0: 91 warnx("No package matching `%s' found", pattern); 92 return 1; 93 case -1: 94 warnx("Error while iterating package database for `%s'", 95 pattern); 96 return 1; 97 default: 98 return 0; 99 } 100} 101 102/* 103 * The argument is either a fixed package name or an absolute path. 104 * The latter is recognized for legacy compatibility and must point 105 * into the package database. 106 */ 107static int 108add_by_pkgname(lpkg_head_t *pkgs, char *pkg) 109{ 110 char *s; 111 lpkg_t *lpp; 112 size_t l; 113 const char *orig_pkg = pkg; 114 115 if (pkg[0] == '/') { 116 l = strlen(pkgdb); 117 if (strncmp(pkg, pkgdb, l) || pkg[l] != '/') { 118 warnx("Absolute path is not relative to " 119 "package database, skipping: %s", pkg); 120 return 1; 121 } 122 pkg += l + 1; 123 } 124 l = strcspn(pkg, "/"); 125 if (pkg[l + strspn(pkg + l, "/")] != '\0') { 126 warnx("`%s' is not a package name, skipping", orig_pkg); 127 return 1; 128 } 129 pkg[l] = '\0'; 130 131 s = pkgdb_pkg_file(pkg, CONTENTS_FNAME); 132 if (fexists(s)) { 133 free(s); 134 lpp = alloc_lpkg(pkg); 135 TAILQ_INSERT_TAIL(pkgs, lpp, lp_link); 136 return 0; 137 } 138 free(s); 139 140 switch (add_installed_pkgs_by_basename(pkg, pkgs)) { 141 case 0: 142 warnx("No matching package for basename `%s' of `%s'", 143 pkg, orig_pkg); 144 return 1; 145 case -1: 146 warnx("Error expanding basename `%s' of `%s'", 147 pkg, orig_pkg); 148 return 1; 149 default: 150 return 0; 151 } 152} 153 154/* 155 * Evaluate +REQUIRED_BY. This function is used for four different 156 * tasks: 157 * 0: check if no depending packages remain 158 * 1: like 0, but prepend the depending packages to pkgs if they exist 159 * 2: print remaining packages to stderr 160 * 3: check all and at least one depending packages have been removed 161 */ 162static int 163process_required_by(const char *pkg, lpkg_head_t *pkgs, 164 lpkg_head_t *sorted_pkgs, int action) 165{ 166 char line[MaxPathSize], *eol, *fname; 167 FILE *fp; 168 lpkg_t *lpp; 169 int got_match, got_miss; 170 171 fname = pkgdb_pkg_file(pkg, REQUIRED_BY_FNAME); 172 if (!fexists(fname)) { 173 free(fname); 174 return 0; 175 } 176 177 if ((fp = fopen(fname, "r")) == NULL) { 178 warn("Failed to open `%s'", fname); 179 free(fname); 180 return -1; 181 } 182 free(fname); 183 184 got_match = 0; 185 got_miss = 0; 186 187 while (fgets(line, sizeof(line), fp)) { 188 if ((eol = strrchr(line, '\n')) != NULL) 189 *eol = '\0'; 190 TAILQ_FOREACH(lpp, sorted_pkgs, lp_link) { 191 if (strcmp(lpp->lp_name, line) == 0) 192 break; 193 } 194 if (lpp != NULL) { 195 got_match = 1; 196 continue; 197 } 198 got_miss = 1; 199 if (pkgs) { 200 TAILQ_FOREACH(lpp, pkgs, lp_link) { 201 if (strcmp(lpp->lp_name, line) == 0) 202 break; 203 } 204 if (lpp != NULL) 205 continue; 206 } 207 switch (action) { 208 case 0: 209 fclose(fp); 210 return 1; 211 case 1: 212 lpp = alloc_lpkg(line); 213 TAILQ_INSERT_HEAD(pkgs, lpp, lp_link); 214 break; 215 case 2: 216 fprintf(stderr, "\t%s\n", line); 217 break; 218 case 3: 219 fclose(fp); 220 return 0; 221 } 222 } 223 224 fclose(fp); 225 226 return (action == 3 ? got_match : got_miss); 227} 228 229/* 230 * Main function to order the patterns from the command line and 231 * add the subtrees for -r processing as needed. 232 * 233 * The first part ensures that all packages are listed at most once 234 * in pkgs. Afterwards the list is scanned for packages without depending 235 * packages. Each such package is moved to sorted_pkgs in order. 236 * If -r is given, all dependencies are inserted at the head of pkgs. 237 * The loop has to continue as long as progress is made. This can happen 238 * either because another package has been added to pkgs due to recursion 239 * (head of pkgs changed) or because a package has no more depending packages 240 * (tail of sorted_pkgs changed). 241 * 242 * If no progress is made, the remaining packages are moved to sorted_pkgs 243 * and an error is returned for the !Force case. 244 */ 245static int 246sort_and_recurse(lpkg_head_t *pkgs, lpkg_head_t *sorted_pkgs) 247{ 248 lpkg_t *lpp, *lpp2, *lpp_next, *lpp_old_tail, *lpp_old_head; 249 int rv; 250 251 TAILQ_FOREACH_SAFE(lpp, pkgs, lp_link, lpp_next) { 252 TAILQ_FOREACH(lpp2, pkgs, lp_link) { 253 if (lpp != lpp2 && 254 strcmp(lpp->lp_name, lpp2->lp_name) == 0) 255 break; 256 } 257 if (lpp2 == NULL) 258 continue; 259 TAILQ_REMOVE(pkgs, lpp, lp_link); 260 free_lpkg(lpp); 261 } 262 263 while (!TAILQ_EMPTY(pkgs)) { 264 lpp_old_tail = TAILQ_LAST(sorted_pkgs, _lpkg_head_t); 265 lpp_old_head = TAILQ_FIRST(pkgs); 266 267 TAILQ_FOREACH_SAFE(lpp, pkgs, lp_link, lpp_next) { 268 rv = process_required_by(lpp->lp_name, pkgs, 269 sorted_pkgs, delete_recursive ? 1 : 0); 270 if (rv) 271 continue; 272 TAILQ_REMOVE(pkgs, lpp, lp_link); 273 TAILQ_INSERT_TAIL(sorted_pkgs, lpp, lp_link); 274 } 275 276 if (lpp_old_tail == TAILQ_LAST(sorted_pkgs, _lpkg_head_t) && 277 lpp_old_head == TAILQ_FIRST(pkgs)) 278 break; 279 } 280 281 if (TAILQ_EMPTY(pkgs)) 282 return 0; 283 284 while (!TAILQ_EMPTY(pkgs)) { 285 lpp = TAILQ_FIRST(pkgs); 286 TAILQ_REMOVE(pkgs, lpp, lp_link); 287 fprintf(stderr, 288 "Package `%s' is still required by other packages:\n", 289 lpp->lp_name); 290 process_required_by(lpp->lp_name, NULL, sorted_pkgs, 2); 291 if (Force) { 292 TAILQ_INSERT_TAIL(sorted_pkgs, lpp, lp_link); 293 } else 294 free_lpkg(lpp); 295 } 296 297 return !Force; 298} 299 300struct find_leaves_data { 301 lpkg_head_t *pkgs; 302 int progress; 303}; 304 305/* 306 * Iterator for finding leaf packages. 307 * Packages that are marked as not for deletion are not considered as 308 * leaves. For all other packages it is checked if at least one package 309 * that depended on them is to be removed AND no depending package remains. 310 * If that is the case, the package is appended to the sorted list. 311 * As this package can't have depending packages left, the topological order 312 * remains consistent. 313 */ 314static int 315find_new_leaves_iter(const char *pkg, void *cookie) 316{ 317 char *fname; 318 struct find_leaves_data *data = cookie; 319 lpkg_t *lpp; 320 321 fname = pkgdb_pkg_file(pkg, PRESERVE_FNAME); 322 if (fexists(fname)) { 323 free(fname); 324 return 0; 325 } 326 free(fname); 327 328 if (delete_automatic_leaves && !delete_new_leaves && 329 !is_automatic_installed(pkg)) 330 return 0; 331 332 /* Check whether this package is already on the list first. */ 333 TAILQ_FOREACH(lpp, data->pkgs, lp_link) { 334 if (strcmp(lpp->lp_name, pkg) == 0) 335 return 0; 336 } 337 338 if (process_required_by(pkg, NULL, data->pkgs, 3) == 1) { 339 lpp = alloc_lpkg(pkg); 340 TAILQ_INSERT_TAIL(data->pkgs, lpp, lp_link); 341 data->progress = 1; 342 } 343 344 return 0; 345} 346 347/* 348 * Iterate over all installed packages and look for new leaf packages. 349 * As long as the loop adds one new leaf package, processing continues. 350 */ 351static void 352find_new_leaves(lpkg_head_t *pkgs) 353{ 354 struct find_leaves_data data; 355 356 data.pkgs = pkgs; 357 do { 358 data.progress = 0; 359 iterate_pkg_db(find_new_leaves_iter, &data); 360 } while (data.progress); 361} 362 363/* 364 * Check that no entry on the package list is marked as not for deletion. 365 */ 366static int 367find_preserve_pkgs(lpkg_head_t *pkgs) 368{ 369 lpkg_t *lpp, *lpp_next; 370 char *fname; 371 int found_preserve; 372 373 found_preserve = 0; 374 TAILQ_FOREACH_SAFE(lpp, pkgs, lp_link, lpp_next) { 375 fname = pkgdb_pkg_file(lpp->lp_name, PRESERVE_FNAME); 376 if (!fexists(fname)) { 377 free(fname); 378 continue; 379 } 380 free(fname); 381 if (keep_preserve) { 382 TAILQ_REMOVE(pkgs, lpp, lp_link); 383 free_lpkg(lpp); 384 continue; 385 } 386 if (!found_preserve) 387 warnx("The following packages are marked as not " 388 "for deletion:"); 389 found_preserve = 1; 390 fprintf(stderr, "\t%s\n", lpp->lp_name); 391 } 392 if (!found_preserve) 393 return 0; 394 if (Force == 0 || (!unregister_only && Force == 1)) 395 return 1; 396 fprintf(stderr, "...but will delete them anyway\n"); 397 return 0; 398} 399 400/* 401 * Run the +DEINSTALL script. Depending on whether this is 402 * pre- or post-deinstall phase, different arguments are passed down. 403 */ 404static int 405run_deinstall_script(const char *pkg, int do_postdeinstall) 406{ 407 const char *target, *text; 408 char *fname, *pkgdir; 409 int rv; 410 411 fname = pkgdb_pkg_file(pkg, DEINSTALL_FNAME); 412 if (!fexists(fname)) { 413 free(fname); 414 return 0; 415 } 416 417 if (do_postdeinstall) { 418 target = "POST-DEINSTALL"; 419 text = "post-deinstall"; 420 } else { 421 target = "DEINSTALL"; 422 text = "deinstall"; 423 } 424 425 if (Fake) { 426 printf("Would execute %s script with argument %s now\n", 427 text, target); 428 free(fname); 429 return 0; 430 } 431 432 pkgdir = pkgdb_pkg_dir(pkg); 433 if (chmod(fname, 0555)) 434 warn("chmod of `%s' failed", fname); 435 rv = fcexec(pkgdir, fname, pkg, target, NULL); 436 if (rv) 437 warnx("%s script returned error status", text); 438 free(pkgdir); 439 free(fname); 440 return rv; 441} 442 443/* 444 * Copy lines from fname to fname_tmp, filtering out lines equal to text. 445 * Afterwards rename fname_tmp to fname; 446 */ 447static int 448remove_line(const char *fname, const char *fname_tmp, const char *text) 449{ 450 FILE *fp, *fp_out; 451 char line[MaxPathSize], *eol; 452 int rv; 453 454 if ((fp = fopen(fname, "r")) == NULL) { 455 warn("Unable to open `%s'", fname); 456 return 1; 457 } 458 if ((fp_out = fopen(fname_tmp, "w")) == NULL) { 459 warn("Unable to open `%s'", fname_tmp); 460 fclose(fp); 461 return 1; 462 } 463 464 while (fgets(line, sizeof(line), fp) != NULL) { 465 if ((eol = strrchr(line, '\n')) != NULL) 466 *eol = '\0'; 467 if (strcmp(line, text) == 0) 468 continue; 469 fprintf(fp_out, "%s\n", line); 470 } 471 fclose(fp); 472 473 if (fclose(fp_out) == EOF) { 474 remove(fname_tmp); 475 warnx("Failure while closing `%s' temp file", fname_tmp); 476 return 1; 477 } 478 479 if (rename(fname_tmp, fname) == -1) { 480 warn("Unable to rename `%s' to `%s'", fname_tmp, fname); 481 rv = 1; 482 } else 483 rv = 0; 484 remove(fname_tmp); 485 486 return rv; 487} 488 489/* 490 * remove_depend is used as iterator function below. 491 * The passed-in package name should be removed from the 492 * +REQUIRED_BY list of the dependency. Such an entry 493 * can miss in a fully correct package database, if the pattern 494 * matches more than one package. 495 */ 496static int 497remove_depend(const char *cur_pkg, void *cookie) 498{ 499 const char *pkg = cookie; 500 char *fname, *fname2; 501 int rv; 502 503 fname = pkgdb_pkg_file(cur_pkg, REQUIRED_BY_FNAME); 504 if (isemptyfile(fname)) { 505 free(fname); 506 return 0; 507 } 508 fname2 = pkgdb_pkg_file(cur_pkg, REQUIRED_BY_FNAME_TMP); 509 510 rv = remove_line(fname, fname2, pkg); 511 512 free(fname2); 513 free(fname); 514 515 return rv; 516} 517 518static int 519remove_pkg(const char *pkg) 520{ 521 FILE *fp; 522 char *fname, *pkgdir; 523 package_t plist; 524 plist_t *p; 525 int rv, late_error; 526 527 if (pkgdb_update_only) 528 return pkgdb_remove_pkg(pkg) ? 0 : 1; 529 530 fname = pkgdb_pkg_file(pkg, CONTENTS_FNAME); 531 if (!fexists(fname)) { 532 warnx("package `%s' is not installed, `%s' missing", pkg, fname); 533 free(fname); 534 return 1; 535 } 536 free(fname); 537 538 fname = pkgdb_pkg_file(pkg, CONTENTS_FNAME); 539 if ((fp = fopen(fname, "r")) == NULL) { 540 warnx("Failed to open `%s'", fname); 541 free(fname); 542 return 1; 543 } 544 read_plist(&plist, fp); 545 fclose(fp); 546 547 /* 548 * If a prefix has been provided, remove the first @cwd and 549 * prepend that prefix. This allows removing packages without 550 * @cwd if really necessary. pkg_admin rebuild is likely needed 551 * afterwards though. 552 */ 553 if (prefix) { 554 delete_plist(&plist, FALSE, PLIST_CWD, NULL); 555 add_plist_top(&plist, PLIST_CWD, prefix); 556 } 557 if ((p = find_plist(&plist, PLIST_CWD)) == NULL) { 558 warnx("Package `%s' doesn't have a prefix", pkg); 559 return 1; 560 } 561 562 if (find_plist(&plist, PLIST_NAME) == NULL) { 563 /* Cheat a bit to allow removal of such bad packages. */ 564 warnx("Package `%s' doesn't have a name", pkg); 565 add_plist_top(&plist, PLIST_NAME, pkg); 566 } 567 568 setenv(PKG_REFCOUNT_DBDIR_VNAME, config_pkg_refcount_dbdir, 1); 569 fname = pkgdb_pkg_dir(pkg); 570 setenv(PKG_METADATA_DIR_VNAME, fname, 1); 571 free(fname); 572 setenv(PKG_PREFIX_VNAME, p->name, 1); 573 574 if (!no_deinstall && !unregister_only) { 575 if (run_deinstall_script(pkg, 0) && !Force) 576 return 1; 577 } 578 579 late_error = 0; 580 581 if (Fake) 582 printf("Attempting to delete package `%s'\n", pkg); 583 else if (delete_package(FALSE, &plist, unregister_only, 584 destdir) == FAIL) { 585 warnx("couldn't entirely delete package `%s'", pkg); 586 /* 587 * XXX It could be nice to error out here explicitly, 588 * XXX but this is problematic for missing or changed files. 589 * XXX At least the inability to remove files at all should 590 * XXX be handled though. 591 */ 592 } 593 594 /* 595 * Past the point of no return. Files are gone, all that is left 596 * is cleaning up registered dependencies and removing the meta data. 597 * Errors in the remaining part are counted, but don't stop the 598 * processing. 599 */ 600 601 for (p = plist.head; p; p = p->next) { 602 if (p->type != PLIST_PKGDEP) 603 continue; 604 if (Verbose) 605 printf("Attempting to remove dependency " 606 "on package `%s'\n", p->name); 607 if (Fake) 608 continue; 609 match_installed_pkgs(p->name, remove_depend, 610 __UNCONST(pkg)); 611 } 612 613 free_plist(&plist); 614 615 if (!no_deinstall && !unregister_only) 616 late_error |= run_deinstall_script(pkg, 1); 617 618 if (Fake) 619 return 0; 620 621 /* 622 * Kill the pkgdb subdirectory. The files have been removed, so 623 * this is way beyond the point of no return. 624 */ 625 pkgdir = pkgdb_pkg_dir(pkg); 626 (void) remove_files(pkgdir, "+*"); 627 rv = 1; 628 if (isemptydir(pkgdir)&& rmdir(pkgdir) == 0) 629 rv = 0; 630 else if (!Force) 631 warnx("Couldn't remove package directory in `%s'", pkgdir); 632 else if (recursive_remove(pkgdir, 1)) 633 warn("Couldn't remove package directory `%s'", pkgdir); 634 else 635 warnx("Package directory `%s' forcefully removed", pkgdir); 636 free(pkgdir); 637 638 return rv | late_error; 639} 640 641int 642main(int argc, char *argv[]) 643{ 644 lpkg_head_t pkgs, sorted_pkgs; 645 int ch, r, has_error; 646 unsigned long bad_count; 647 648 TAILQ_INIT(&pkgs); 649 TAILQ_INIT(&sorted_pkgs); 650 651 setprogname(argv[0]); 652 while ((ch = getopt(argc, argv, "ADFfK:kNnOP:p:RrVv")) != -1) { 653 switch (ch) { 654 case 'A': 655 delete_automatic_leaves = 1; 656 break; 657 case 'D': 658 no_deinstall = 1; 659 break; 660 case 'F': 661 find_by_filename = 1; 662 break; 663 case 'f': 664 ++Force; 665 break; 666 case 'K': 667 pkgdb_set_dir(optarg, 3); 668 break; 669 case 'k': 670 keep_preserve = 1; 671 break; 672 case 'N': 673 unregister_only = 1; 674 break; 675 case 'n': 676 Fake = 1; 677 break; 678 case 'O': 679 pkgdb_update_only = 1; 680 break; 681 case 'P': 682 destdir = optarg; 683 break; 684 case 'p': 685 prefix = optarg; 686 break; 687 case 'R': 688 delete_new_leaves = 1; 689 break; 690 case 'r': 691 delete_recursive = 1; 692 break; 693 case 'V': 694 show_version(); 695 /* NOTREACHED */ 696 case 'v': 697 ++Verbose; 698 break; 699 default: 700 usage(); 701 break; 702 } 703 } 704 705 pkg_install_config(); 706 707 pkgdb = xstrdup(pkgdb_get_dir()); 708 709 if (destdir != NULL) { 710 char *pkgdbdir; 711 712 pkgdbdir = xasprintf("%s/%s", destdir, pkgdb); 713 pkgdb_set_dir(pkgdbdir, 4); 714 free(pkgdbdir); 715 } 716 717 argc -= optind; 718 argv += optind; 719 720 if (argc == 0) { 721 if (find_by_filename) 722 warnx("Missing filename(s)"); 723 else 724 warnx("Missing package name(s)"); 725 usage(); 726 } 727 728 if (Fake) 729 r = pkgdb_open(ReadOnly); 730 else 731 r = pkgdb_open(ReadWrite); 732 733 if (!r) 734 errx(EXIT_FAILURE, "Opening pkgdb failed"); 735 736 /* First, process all command line options. */ 737 738 has_error = 0; 739 for (; argc != 0; --argc, ++argv) { 740 if (find_by_filename) 741 has_error |= add_by_filename(&pkgs, *argv); 742 else if (ispkgpattern(*argv)) 743 has_error |= add_by_pattern(&pkgs, *argv); 744 else 745 has_error |= add_by_pkgname(&pkgs, *argv); 746 } 747 748 if (has_error && !Force) { 749 pkgdb_close(); 750 return EXIT_FAILURE; 751 } 752 753 /* Second, reorder and recursive if necessary. */ 754 755 if (sort_and_recurse(&pkgs, &sorted_pkgs)) { 756 pkgdb_close(); 757 return EXIT_FAILURE; 758 } 759 760 /* Third, add leaves if necessary. */ 761 762 if (delete_new_leaves || delete_automatic_leaves) 763 find_new_leaves(&sorted_pkgs); 764 765 /* 766 * Now that all packages to remove are known, check 767 * if all are removable. After that, start the actual 768 * removal. 769 */ 770 771 if (find_preserve_pkgs(&sorted_pkgs)) { 772 pkgdb_close(); 773 return EXIT_FAILURE; 774 } 775 776 setenv(PKG_REFCOUNT_DBDIR_VNAME, pkgdb_refcount_dir(), 1); 777 778 bad_count = 0; 779 while (!TAILQ_EMPTY(&sorted_pkgs)) { 780 lpkg_t *lpp; 781 782 lpp = TAILQ_FIRST(&sorted_pkgs); 783 TAILQ_REMOVE(&sorted_pkgs, lpp, lp_link); 784 if (remove_pkg(lpp->lp_name)) { 785 ++bad_count; 786 if (!Force) 787 break; 788 } 789 free_lpkg(lpp); 790 } 791 792 pkgdb_close(); 793 794 if (Force && bad_count && Verbose) 795 warnx("Removal of %lu packages failed", bad_count); 796 797 return bad_count > 0 ? EXIT_FAILURE : EXIT_SUCCESS; 798} 799