pkg_jobs_universe.c
1 /* Copyright (c) 2014, Vsevolod Stakhov 2 * All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions are met: 6 * * Redistributions of source code must retain the above copyright 7 * notice, this list of conditions and the following disclaimer. 8 * * Redistributions in binary form must reproduce the above copyright 9 * notice, this list of conditions and the following disclaimer in the 10 * documentation and/or other materials provided with the distribution. 11 * 12 * THIS SOFTWARE IS PROVIDED ''AS IS'' AND ANY 13 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 14 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 15 * DISCLAIMED. IN NO EVENT SHALL AUTHOR BE LIABLE FOR ANY 16 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 17 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 18 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 19 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 20 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 21 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 22 */ 23 24 #ifdef HAVE_CONFIG_H 25 #include "pkg_config.h" 26 #endif 27 28 #define dbg(x, ...) pkg_dbg(PKG_DBG_UNIVERSE, x, __VA_ARGS__) 29 30 #include <sys/param.h> 31 #include <sys/types.h> 32 33 #include <assert.h> 34 #include <errno.h> 35 #if __has_include(<libutil.h>) 36 #include <libutil.h> 37 #endif 38 #include <stdbool.h> 39 #include <stdlib.h> 40 #include <string.h> 41 #include <ctype.h> 42 43 #include "pkg.h" 44 #include "private/event.h" 45 #include "private/pkg.h" 46 #include "private/pkgdb.h" 47 #include "private/pkg_jobs.h" 48 49 #define IS_DELETE(j) ((j)->type == PKG_JOBS_DEINSTALL || (j)->type == PKG_JOBS_AUTOREMOVE) 50 51 struct pkg * 52 pkg_jobs_universe_get_local(struct pkg_jobs_universe *universe, 53 const char *uid, unsigned flag) 54 { 55 struct pkg *pkg = NULL; 56 struct pkgdb_it *it; 57 struct pkg_job_universe_item *unit, *cur, *found; 58 59 if (flag == 0) { 60 flag = PKG_LOAD_BASIC|PKG_LOAD_DEPS|PKG_LOAD_RDEPS|PKG_LOAD_OPTIONS| 61 PKG_LOAD_REQUIRES|PKG_LOAD_PROVIDES| 62 PKG_LOAD_SHLIBS_REQUIRED|PKG_LOAD_SHLIBS_PROVIDED|PKG_LOAD_ANNOTATIONS| 63 PKG_LOAD_CONFLICTS; 64 } 65 66 unit = pkghash_get_value(universe->items, uid); 67 if (unit != NULL) { 68 /* Search local in a universe chain */ 69 cur = unit; 70 found = NULL; 71 do { 72 if (cur->pkg->type == PKG_INSTALLED || cur->pkg->type == PKG_GROUP_INSTALLED) { 73 found = cur; 74 break; 75 } 76 cur = cur->prev; 77 } while (cur != unit); 78 79 if (found && found->pkg->type == PKG_INSTALLED) { 80 pkgdb_ensure_loaded(universe->j->db, found->pkg, flag); 81 return (found->pkg); 82 } 83 } 84 85 /* XX TODO query local groups */ 86 if ((it = pkgdb_query(universe->j->db, uid, MATCH_INTERNAL)) == NULL) 87 return (NULL); 88 89 if (pkgdb_it_next(it, &pkg, flag) != EPKG_OK) 90 pkg = NULL; 91 92 pkgdb_it_free(it); 93 94 return (pkg); 95 } 96 97 static pkgs_t * 98 pkg_jobs_universe_get_remote(struct pkg_jobs_universe *universe, 99 const char *uid, unsigned flag) 100 { 101 struct pkg *pkg = NULL; 102 pkgs_t *result = NULL; 103 struct pkgdb_it *it; 104 struct pkg_job_universe_item *unit, *cur, *found; 105 106 if (flag == 0) { 107 flag = PKG_LOAD_BASIC|PKG_LOAD_DEPS|PKG_LOAD_OPTIONS| 108 PKG_LOAD_PROVIDES|PKG_LOAD_REQUIRES| 109 PKG_LOAD_SHLIBS_REQUIRED|PKG_LOAD_SHLIBS_PROVIDED| 110 PKG_LOAD_ANNOTATIONS|PKG_LOAD_CONFLICTS; 111 } 112 113 unit = pkghash_get_value(universe->items, uid); 114 if (unit != NULL && unit->pkg->type != PKG_INSTALLED) { 115 /* Search local in a universe chain */ 116 cur = unit; 117 found = NULL; 118 do { 119 if (cur->pkg->type != PKG_INSTALLED) { 120 found = cur; 121 break; 122 } 123 cur = cur->prev; 124 } while (cur != unit); 125 126 if (found) { 127 /* Assume processed */ 128 return (NULL); 129 } 130 } 131 132 if ((it = pkgdb_repo_query2(universe->j->db, uid, MATCH_INTERNAL, 133 universe->j->reponames)) == NULL) 134 return (NULL); 135 136 while (pkgdb_it_next(it, &pkg, flag) == EPKG_OK) { 137 if (result == NULL) 138 result = xcalloc(1, sizeof(pkgs_t)); 139 append_pkg_if_newer(result, pkg); 140 pkg = NULL; 141 } 142 143 pkgdb_it_free(it); 144 145 return (result); 146 } 147 148 /** 149 * Check whether a package is in the universe already or add it 150 * @return item or NULL 151 */ 152 int 153 pkg_jobs_universe_add_pkg(struct pkg_jobs_universe *universe, struct pkg *pkg, 154 struct pkg_job_universe_item **found) 155 { 156 struct pkg_job_universe_item *item, *seen, *tmp = NULL; 157 158 pkg_validate(pkg, universe->j->db); 159 160 if (pkg->digest == NULL) { 161 dbg(3, "no digest found for package %s (%s-%s)", 162 pkg->uid, pkg->name, pkg->version); 163 if (pkg_checksum_calculate(pkg, universe->j->db, false, true, false) != EPKG_OK) { 164 if (found != NULL) 165 *found = NULL; 166 return (EPKG_FATAL); 167 } 168 } 169 170 seen = pkghash_get_value(universe->seen, pkg->digest); 171 if (seen) { 172 bool same_package = false; 173 174 DL_FOREACH(seen, tmp) { 175 if (tmp->pkg == pkg || (tmp->pkg->type == pkg->type && 176 STREQ(tmp->pkg->digest, pkg->digest))) { 177 if (tmp->pkg->reponame != NULL) { 178 if (STREQ(tmp->pkg->reponame, pkg->reponame)) { 179 same_package = true; 180 break; 181 } 182 } else { 183 same_package = true; 184 break; 185 } 186 } 187 } 188 189 if (same_package) { 190 if (found != NULL) { 191 *found = seen; 192 } 193 194 return (EPKG_END); 195 } 196 } 197 198 if (pkg_is_locked(pkg)) { 199 return (EPKG_LOCKED); 200 } 201 202 dbg(2, "add new %s pkg: %s, (%s-%s:%s)", 203 (pkg->type == PKG_INSTALLED ? "local" : "remote"), pkg->uid, 204 pkg->name, pkg->version, pkg->digest); 205 206 item = xcalloc(1, sizeof (struct pkg_job_universe_item)); 207 item->pkg = pkg; 208 209 tmp = pkghash_get_value(universe->items, pkg->uid); 210 if (tmp == NULL) { 211 pkghash_safe_add(universe->items, pkg->uid, item, NULL); 212 item->inhash = true; 213 } 214 215 DL_APPEND(tmp, item); 216 217 if (seen == NULL) 218 pkghash_safe_add(universe->seen, item->pkg->digest, item, NULL); 219 220 universe->nitems++; 221 222 if (found != NULL) 223 *found = item; 224 225 return (EPKG_OK); 226 } 227 228 #define DEPS_FLAG_REVERSE 0x1 << 1 229 #define DEPS_FLAG_MIRROR 0x1 << 2 230 #define DEPS_FLAG_FORCE_LOCAL 0x1 << 3 231 #define DEPS_FLAG_FORCE_MISSING 0x1 << 4 232 #define DEPS_FLAG_FORCE_UPGRADE 0x1 << 5 233 234 static int 235 pkg_jobs_universe_process_deps(struct pkg_jobs_universe *universe, 236 struct pkg *pkg, unsigned flags) 237 { 238 struct pkg_dep *d = NULL; 239 int (*deps_func)(const struct pkg *pkg, struct pkg_dep **d); 240 int rc; 241 struct pkg_job_universe_item *unit; 242 struct pkg *npkg, *rpkg, *lpkg; 243 pkgs_t *rpkgs = NULL; 244 bool found = false; 245 246 rpkg = NULL; 247 248 if (flags & DEPS_FLAG_REVERSE) { 249 dbg(4, "Processing rdeps for %s (%s)", pkg->uid, pkg->type == PKG_INSTALLED ? "installed" : "remote"); 250 if (pkg->type != PKG_INSTALLED) { 251 lpkg = pkg_jobs_universe_get_local(universe, pkg->uid, 0); 252 if (lpkg != NULL && lpkg != pkg) 253 return (pkg_jobs_universe_process_deps(universe, lpkg, flags)); 254 } 255 deps_func = pkg_rdeps; 256 } 257 else { 258 dbg(4, "Processing deps for %s", pkg->uid); 259 deps_func = pkg_deps; 260 } 261 262 while (deps_func(pkg, &d) == EPKG_OK) { 263 dbg(4, "Processing *deps for %s: %s", pkg->uid, d->uid); 264 if (pkghash_get(universe->items, d->uid) != NULL) 265 continue; 266 267 rpkgs = NULL; 268 npkg = NULL; 269 if (!(flags & DEPS_FLAG_MIRROR)) { 270 npkg = pkg_jobs_universe_get_local(universe, d->uid, 0); 271 } 272 273 if (!(flags & DEPS_FLAG_FORCE_LOCAL)) { 274 275 /* Check for remote dependencies */ 276 rpkgs = pkg_jobs_universe_get_remote(universe, d->uid, 0); 277 } 278 279 if (npkg == NULL && rpkgs == NULL) { 280 pkg_emit_error("%s has a missing dependency: %s", 281 pkg->name, d->name); 282 283 if (flags & DEPS_FLAG_FORCE_MISSING) { 284 continue; 285 } 286 287 return (EPKG_FATAL); 288 } 289 290 if (npkg != NULL) { 291 if (pkg_jobs_universe_process_item(universe, npkg, &unit) != EPKG_OK) { 292 continue; 293 } 294 } 295 296 if (rpkgs == NULL) 297 continue; 298 /* 299 * When processing deps, we should first try to select a dependency 300 * from the same repo. 301 * Otherwise, we would have ping-pong of dependencies instead of 302 * the situation when this behaviour is handled by 303 * CONSERVATIVE_UPGRADES. 304 * 305 * Important notes here: 306 * 1. We are looking for packages that are dependencies of a package 307 * `pkg` 308 * 2. Now if `pkg` belongs to repo `r` and `rpkg` belongs to repo 309 * `r` then we just select it. 310 * 3. If `rpkg` is not found in `r` we just scan all packages 311 */ 312 313 /* 314 * XXX: this is the proper place to expand flexible dependencies 315 */ 316 317 found = false; 318 /* Iteration one */ 319 vec_rforeach(*rpkgs, i) { 320 rpkg = rpkgs->d[i]; 321 322 if (pkg->reponame && rpkg->reponame && 323 STREQ(pkg->reponame, rpkg->reponame)) { 324 found = true; 325 break; 326 } 327 } 328 329 /* Fallback if a dependency is not found in the same repo */ 330 if (!found) { 331 vec_rforeach(*rpkgs, i) { 332 rpkg = rpkgs->d[i]; 333 334 if (npkg != NULL) { 335 /* Set reason for upgrades */ 336 if (!pkg_jobs_need_upgrade(&universe->j->system_shlibs, rpkg, npkg)) 337 continue; 338 /* Save automatic flag */ 339 rpkg->automatic = npkg->automatic; 340 } 341 342 rc = pkg_jobs_universe_process_item(universe, rpkg, NULL); 343 344 /* Special case if we cannot find any package */ 345 if (npkg == NULL && rc != EPKG_OK) { 346 vec_free(rpkgs); 347 free(rpkgs); 348 return (rc); 349 } 350 } 351 } 352 else { 353 assert (rpkg != NULL); 354 355 if (npkg != NULL) { 356 /* Set reason for upgrades */ 357 if (!pkg_jobs_need_upgrade(&universe->j->system_shlibs, rpkg, npkg)) 358 continue; 359 /* Save automatic flag */ 360 rpkg->automatic = npkg->automatic; 361 } 362 363 rc = pkg_jobs_universe_process_item(universe, rpkg, NULL); 364 if (npkg == NULL && rc != EPKG_OK) { 365 vec_free(rpkgs); 366 free(rpkgs); 367 return (rc); 368 } 369 } 370 371 vec_free(rpkgs); 372 free(rpkgs); 373 } 374 375 return (EPKG_OK); 376 } 377 378 static int 379 pkg_jobs_universe_handle_provide(struct pkg_jobs_universe *universe, 380 struct pkgdb_it *it, const char *name, bool is_shlib) 381 { 382 struct pkg_job_universe_item *unit; 383 struct pkg_job_provide *pr, *prhead; 384 struct pkg *npkg, *rpkg; 385 int rc; 386 unsigned flags = PKG_LOAD_BASIC|PKG_LOAD_OPTIONS|PKG_LOAD_DEPS| 387 PKG_LOAD_REQUIRES|PKG_LOAD_PROVIDES| 388 PKG_LOAD_SHLIBS_REQUIRED|PKG_LOAD_SHLIBS_PROVIDED| 389 PKG_LOAD_ANNOTATIONS|PKG_LOAD_CONFLICTS; 390 391 rpkg = NULL; 392 393 prhead = pkghash_get_value(universe->provides, name); 394 while (pkgdb_it_next(it, &rpkg, flags) == EPKG_OK) { 395 dbg(4, "handle_provide: processing package %s for %s %s", 396 rpkg->uid, is_shlib ? "shlib" : "provide", name); 397 398 /* Check for local packages */ 399 if ((unit = pkghash_get_value(universe->items, rpkg->uid)) != NULL) { 400 dbg(4, "handle_provide: package %s already in universe", rpkg->uid); 401 /* 402 * Skip adding the remote package if a local version 403 * with the same digest already exists in the universe: 404 * there is nothing to upgrade. 405 */ 406 if (unit->pkg->type == PKG_INSTALLED && 407 unit->pkg->digest != NULL && 408 rpkg->digest != NULL && 409 STREQ(unit->pkg->digest, rpkg->digest)) { 410 dbg(4, "handle_provide: %s remote identical to local, skipping", rpkg->uid); 411 pkg_free(rpkg); 412 rpkg = NULL; 413 goto provide; 414 } 415 if (pkg_jobs_universe_process_item(universe, rpkg, 416 &unit) != EPKG_OK) { 417 continue; 418 } 419 420 rpkg = NULL; 421 } 422 else { 423 /* Maybe local package has just been not added */ 424 npkg = pkg_jobs_universe_get_local(universe, rpkg->uid, 0); 425 if (npkg != NULL) { 426 dbg(4, "handle_provide: found local package %s", npkg->uid); 427 if (pkg_jobs_universe_process_item(universe, npkg, 428 &unit) != EPKG_OK) { 429 return (EPKG_FATAL); 430 } 431 /* 432 * Skip adding the remote package if the local 433 * version has the same digest. 434 */ 435 if (npkg->digest != NULL && 436 rpkg->digest != NULL && 437 STREQ(npkg->digest, rpkg->digest)) { 438 dbg(4, "handle_provide: %s remote identical to local, skipping", rpkg->uid); 439 pkg_free(rpkg); 440 rpkg = NULL; 441 goto provide; 442 } 443 if (pkg_jobs_universe_process_item(universe, rpkg, 444 &unit) != EPKG_OK) { 445 continue; 446 } 447 if (unit != NULL) 448 rpkg = NULL; 449 } 450 } 451 452 /* Skip seen packages */ 453 if (unit == NULL) { 454 if (rpkg->digest == NULL) { 455 dbg(3, "no digest found for package %s", rpkg->uid); 456 if (pkg_checksum_calculate(rpkg, 457 universe->j->db, false, true, false) != EPKG_OK) { 458 return (EPKG_FATAL); 459 } 460 } 461 rc = pkg_jobs_universe_process_item(universe, rpkg, 462 &unit); 463 464 if (rc != EPKG_OK) { 465 return (rc); 466 } 467 468 /* Reset package to avoid freeing */ 469 rpkg = NULL; 470 } 471 472 provide: 473 pr = xcalloc (1, sizeof (*pr)); 474 pr->un = unit; 475 pr->provide = name; 476 pr->is_shlib = is_shlib; 477 478 if (prhead == NULL) { 479 DL_APPEND(prhead, pr); 480 pkghash_safe_add(universe->provides, pr->provide, 481 prhead, NULL); 482 dbg(4, "add new provide %s-%s(%s) for require %s", 483 pr->un->pkg->name, pr->un->pkg->version, 484 pr->un->pkg->type == PKG_INSTALLED ? "l" : "r", 485 pr->provide); 486 } else { 487 DL_APPEND(prhead, pr); 488 dbg(4, "append provide %s-%s(%s) for require %s", 489 pr->un->pkg->name, pr->un->pkg->version, 490 pr->un->pkg->type == PKG_INSTALLED ? "l" : "r", 491 pr->provide); 492 } 493 } 494 495 return (EPKG_OK); 496 } 497 498 static int 499 pkg_jobs_universe_process_shlibs(struct pkg_jobs_universe *universe, 500 struct pkg *pkg) 501 { 502 struct pkgdb_it *it; 503 int rc; 504 505 dbg(4, "process_shlibs: processing %zu shlibs for %s", 506 vec_len(&pkg->shlibs_required), pkg->uid); 507 508 vec_foreach(pkg->shlibs_required, i) { 509 const char *s = pkg->shlibs_required.d[i]; 510 if (charv_search(&universe->j->system_shlibs, s) != NULL) { 511 dbg(4, "process_shlibs: %s is a system shlib, skipping", s); 512 continue; 513 } 514 if (pkghash_get(universe->provides, s) != NULL) { 515 dbg(4, "process_shlibs: %s already in provides hash, skipping", s); 516 continue; 517 } 518 519 dbg(4, "process_shlibs: looking for providers of %s for %s", s, pkg->uid); 520 521 /* Check for local provides */ 522 it = pkgdb_query_shlib_provide(universe->j->db, s); 523 if (it != NULL) { 524 rc = pkg_jobs_universe_handle_provide(universe, it, s, 525 true); 526 pkgdb_it_free(it); 527 528 if (rc != EPKG_OK) { 529 dbg(1, "cannot find local packages that provide library %s " 530 "required for %s", 531 s, pkg->name); 532 } 533 } 534 /* Not found, search in the repos */ 535 it = pkgdb_repo_shlib_provide(universe->j->db, 536 s, universe->j->reponames); 537 538 if (it != NULL) { 539 rc = pkg_jobs_universe_handle_provide(universe, it, s, 540 true); 541 pkgdb_it_free(it); 542 543 if (rc != EPKG_OK) { 544 dbg(1, "cannot find remote packages that provide library %s " 545 "required for %s", 546 s, pkg->name); 547 } 548 } 549 } 550 551 return (EPKG_OK); 552 } 553 554 static int 555 pkg_jobs_universe_process_provides_requires(struct pkg_jobs_universe *universe, 556 struct pkg *pkg) 557 { 558 struct pkgdb_it *it; 559 int rc; 560 561 dbg(4, "process_requires: processing %zu requires for %s", 562 vec_len(&pkg->requires), pkg->uid); 563 564 vec_foreach(pkg->requires, i) { 565 const char *r = pkg->requires.d[i]; 566 if (pkghash_get(universe->provides, r) != NULL) { 567 dbg(4, "process_requires: %s already in provides hash, skipping", r); 568 continue; 569 } 570 571 dbg(4, "process_requires: looking for providers of %s for %s", r, pkg->uid); 572 573 /* Check for local provides */ 574 it = pkgdb_query_provide(universe->j->db, r); 575 if (it != NULL) { 576 rc = pkg_jobs_universe_handle_provide(universe, it, r, 577 false); 578 pkgdb_it_free(it); 579 580 if (rc != EPKG_OK) { 581 dbg(1, "cannot find local packages that provide %s " 582 "required for %s", 583 r, pkg->name); 584 } 585 } 586 587 /* Not found, search in the repos */ 588 it = pkgdb_repo_provide(universe->j->db, 589 r, universe->j->reponames); 590 591 if (it != NULL) { 592 rc = pkg_jobs_universe_handle_provide(universe, it, r, 593 false); 594 pkgdb_it_free(it); 595 596 if (rc != EPKG_OK) { 597 dbg(1, "cannot find remote packages that provide %s " 598 "required for %s", 599 r, pkg->name); 600 return (rc); 601 } 602 } 603 } 604 605 return (EPKG_OK); 606 } 607 608 int 609 pkg_jobs_universe_process_item(struct pkg_jobs_universe *universe, struct pkg *pkg, 610 struct pkg_job_universe_item **result) 611 { 612 unsigned flags = 0, job_flags; 613 int rc = EPKG_OK; 614 pkg_jobs_t type = universe->j->type; 615 struct pkg_job_universe_item *found; 616 617 dbg(4, "Processing item %s", pkg->uid); 618 619 job_flags = universe->j->flags; 620 621 /* 622 * Add pkg itself. If package is already seen then we check the `processed` 623 * flag that means that we have already tried to check our universe 624 */ 625 rc = pkg_jobs_universe_add_pkg(universe, pkg, &found); 626 if (rc == EPKG_CONFLICT) 627 return (rc); 628 629 if (result) 630 *result = found; 631 632 if (rc == EPKG_END) { 633 dbg(4, "Package %s already seen, processed=%d", pkg->uid, found->processed); 634 if (found->processed) 635 return (EPKG_OK); 636 } 637 else if (rc != EPKG_OK) { 638 return (rc); 639 } 640 641 found->processed = true; 642 643 /* Convert jobs flags to dependency logical flags */ 644 if (job_flags & PKG_FLAG_FORCE_MISSING) 645 flags |= DEPS_FLAG_FORCE_MISSING; 646 647 switch(type) { 648 case PKG_JOBS_FETCH: 649 if (job_flags & PKG_FLAG_RECURSIVE) { 650 flags |= DEPS_FLAG_MIRROR; 651 /* For fetch jobs we worry about depends only */ 652 rc = pkg_jobs_universe_process_deps(universe, pkg, flags); 653 } 654 break; 655 case PKG_JOBS_INSTALL: 656 case PKG_JOBS_UPGRADE: 657 /* Handle depends */ 658 rc = pkg_jobs_universe_process_deps(universe, pkg, flags); 659 if (rc != EPKG_OK) 660 return (rc); 661 /* 662 * Handle reverse depends. Limit recursive expansion to 663 * prevent the universe from growing exponentially 664 * (target → dep → rdep → dep → rdep …). 665 * 666 * Process rdeps when: 667 * - We are not inside rdeps processing yet (depth == 0), OR 668 * - This is a remote package (an upgrade is being considered 669 * and its rdeps may need updating too). 670 */ 671 if (universe->rdeps_depth == 0 || 672 pkg->type != PKG_INSTALLED) { 673 universe->rdeps_depth++; 674 rc = pkg_jobs_universe_process_deps(universe, pkg, 675 flags|DEPS_FLAG_REVERSE); 676 universe->rdeps_depth--; 677 if (rc != EPKG_OK) 678 return (rc); 679 } 680 /* Provides/requires */ 681 rc = pkg_jobs_universe_process_shlibs(universe, pkg); 682 if (rc != EPKG_OK) 683 return (rc); 684 rc = pkg_jobs_universe_process_provides_requires(universe, pkg); 685 if (rc != EPKG_OK) 686 return (rc); 687 break; 688 case PKG_JOBS_AUTOREMOVE: 689 rc = pkg_jobs_universe_process_deps(universe, pkg, flags); 690 if (rc != EPKG_OK) 691 return (rc); 692 rc = pkg_jobs_universe_process_shlibs(universe, pkg); 693 if (rc != EPKG_OK) 694 return (rc); 695 rc = pkg_jobs_universe_process_provides_requires(universe, pkg); 696 if (rc != EPKG_OK) 697 return (rc); 698 break; 699 /* XXX */ 700 break; 701 case PKG_JOBS_DEINSTALL: 702 /* For delete jobs we worry only about local reverse deps */ 703 flags |= DEPS_FLAG_REVERSE|DEPS_FLAG_FORCE_LOCAL; 704 if (job_flags & PKG_FLAG_RECURSIVE) { 705 rc = pkg_jobs_universe_process_deps(universe, pkg, flags); 706 if (rc != EPKG_OK) 707 return (rc); 708 rc = pkg_jobs_universe_process_shlibs(universe, pkg); 709 if (rc != EPKG_OK) 710 return (rc); 711 rc = pkg_jobs_universe_process_provides_requires(universe, pkg); 712 if (rc != EPKG_OK) 713 return (rc); 714 break; 715 } 716 break; 717 } 718 719 return (rc); 720 } 721 722 int 723 pkg_jobs_universe_process(struct pkg_jobs_universe *universe, 724 struct pkg *pkg) 725 { 726 return (pkg_jobs_universe_process_item(universe, pkg, NULL)); 727 } 728 729 static void 730 pkg_jobs_universe_provide_free(struct pkg_job_provide *pr) 731 { 732 struct pkg_job_provide *cur, *tmp; 733 734 DL_FOREACH_SAFE(pr, cur, tmp) { 735 free (cur); 736 } 737 } 738 739 void 740 pkg_jobs_universe_free(struct pkg_jobs_universe *universe) 741 { 742 struct pkg_job_universe_item *cur, *curtmp; 743 pkghash_it it; 744 745 it = pkghash_iterator(universe->items); 746 while (pkghash_next(&it)) { 747 LL_FOREACH_SAFE(it.value, cur, curtmp) { 748 pkg_free(cur->pkg); 749 free(cur); 750 } 751 } 752 pkghash_destroy(universe->items); 753 universe->items = NULL; 754 pkghash_destroy(universe->seen); 755 universe->seen = NULL; 756 it = pkghash_iterator(universe->provides); 757 while (pkghash_next(&it)) 758 pkg_jobs_universe_provide_free(it.value); 759 pkghash_destroy(universe->provides); 760 free(universe); 761 } 762 763 struct pkg_jobs_universe * 764 pkg_jobs_universe_new(struct pkg_jobs *j) 765 { 766 struct pkg_jobs_universe *universe; 767 768 universe = xcalloc(1, sizeof(struct pkg_jobs_universe)); 769 universe->j = j; 770 771 return (universe); 772 } 773 774 struct pkg_job_universe_item * 775 pkg_jobs_universe_find(struct pkg_jobs_universe *universe, const char *uid) 776 { 777 return (pkghash_get_value(universe->items, uid)); 778 } 779 780 static struct pkg_job_universe_item * 781 pkg_jobs_universe_select_max_ver(struct pkg_job_universe_item *chain) 782 { 783 struct pkg_job_universe_item *cur, *res = NULL; 784 bool found = false; 785 int r; 786 787 LL_FOREACH(chain, cur) { 788 if (cur->pkg->type == PKG_INSTALLED) 789 continue; 790 791 if (res != NULL) { 792 r = pkg_version_change_between(cur->pkg, res->pkg); 793 if (r == PKG_UPGRADE) { 794 res = cur; 795 found = true; 796 } 797 else if (r != PKG_REINSTALL) { 798 /* 799 * Actually the selected package is newer than some other 800 * packages in the chain 801 */ 802 found = true; 803 } 804 } 805 else { 806 res = cur; 807 } 808 } 809 810 return (found ? res : NULL); 811 } 812 813 static struct pkg_job_universe_item * 814 pkg_jobs_universe_select_max_prio(struct pkg_job_universe_item *chain) 815 { 816 struct pkg_repo *repo; 817 unsigned int max_pri = 0; 818 struct pkg_job_universe_item *cur, *res = NULL; 819 820 LL_FOREACH(chain, cur) { 821 if (cur->pkg->type == PKG_INSTALLED) 822 continue; 823 824 if (cur->pkg->reponame) { 825 repo = pkg_repo_find(cur->pkg->reponame); 826 if (repo && repo->priority > max_pri) { 827 res = cur; 828 max_pri = repo->priority; 829 } 830 } 831 } 832 833 return (res); 834 } 835 836 static struct pkg_job_universe_item * 837 pkg_jobs_universe_select_same_repo(struct pkg_job_universe_item *chain, 838 struct pkg_job_universe_item *local, const char *assumed_reponame) 839 { 840 struct pkg_repo *local_repo = NULL, *repo; 841 struct pkg_job_universe_item *cur, *res = NULL; 842 843 if (!local) { 844 845 if (assumed_reponame) { 846 local_repo = pkg_repo_find(assumed_reponame); 847 } 848 } 849 else { 850 if (local->pkg->reponame) { 851 local_repo = pkg_repo_find(local->pkg->reponame); 852 } 853 else { 854 const char *lrepo = pkg_kv_get(&local->pkg->annotations, "repository"); 855 if (lrepo) { 856 local_repo = pkg_repo_find(lrepo); 857 } 858 } 859 } 860 861 if (local_repo == NULL) { 862 return (NULL); 863 } 864 else { 865 LL_FOREACH(chain, cur) { 866 if (cur->pkg->type == PKG_INSTALLED) 867 continue; 868 869 if (cur->pkg->reponame) { 870 repo = pkg_repo_find(cur->pkg->reponame); 871 if (repo == local_repo) { 872 res = cur; 873 break; 874 } 875 } 876 } 877 } 878 879 return (res); 880 } 881 882 struct pkg_job_universe_item * 883 pkg_jobs_universe_select_candidate(struct pkg_job_universe_item *chain, 884 struct pkg_job_universe_item *local, bool conservative, 885 const char *reponame, bool pinning) 886 { 887 struct pkg_job_universe_item *res = NULL; 888 889 if (local == NULL) { 890 /* New package selection */ 891 if (conservative) { 892 /* Check same repo */ 893 if (reponame && pinning) { 894 res = pkg_jobs_universe_select_same_repo(chain, NULL, reponame); 895 } 896 897 if (res == NULL) { 898 /* Priority -> version */ 899 res = pkg_jobs_universe_select_max_prio(chain); 900 if (res == NULL) { 901 res = pkg_jobs_universe_select_max_ver(chain); 902 } 903 } 904 } 905 else { 906 if (reponame && pinning) { 907 res = pkg_jobs_universe_select_same_repo(chain, NULL, reponame); 908 } 909 910 if (res == NULL) { 911 /* Version -> priority */ 912 res = pkg_jobs_universe_select_max_ver(chain); 913 if (res == NULL) { 914 res = pkg_jobs_universe_select_max_prio(chain); 915 } 916 } 917 } 918 } 919 else { 920 if (conservative) { 921 /* same -> prio -> version */ 922 if (pinning) 923 res = pkg_jobs_universe_select_same_repo(chain, local, reponame); 924 if (res == NULL) { 925 res = pkg_jobs_universe_select_max_prio(chain); 926 } 927 if (res == NULL) { 928 res = pkg_jobs_universe_select_max_ver(chain); 929 } 930 } 931 else { 932 /* same -> version -> prio */ 933 if (pinning) 934 res = pkg_jobs_universe_select_same_repo(chain, local, reponame); 935 if (res == NULL) { 936 res = pkg_jobs_universe_select_max_ver(chain); 937 } 938 if (res == NULL) { 939 res = pkg_jobs_universe_select_max_prio(chain); 940 } 941 } 942 } 943 944 /* 945 * When all heuristics fail and a local package exists, prefer 946 * the remote candidate whose digest matches the installed one. 947 * This avoids proposing a spurious reinstall from another repo 948 * when the same version is available in multiple repositories. 949 */ 950 if (res == NULL && local != NULL) { 951 struct pkg_job_universe_item *cur; 952 LL_FOREACH(chain, cur) { 953 if (cur->pkg->type != PKG_INSTALLED && 954 STREQ(local->pkg->digest, cur->pkg->digest)) { 955 res = cur; 956 break; 957 } 958 } 959 } 960 961 /* Fallback to any */ 962 return (res != NULL ? res : chain); 963 } 964 965 void 966 pkg_jobs_universe_process_upgrade_chains(struct pkg_jobs *j) 967 { 968 struct pkg_job_universe_item *unit, *cur, *local; 969 struct pkg_job_request *req; 970 struct pkg_job_request_item *rit, *rtmp; 971 pkghash_it it; 972 973 it = pkghash_iterator(j->universe->items); 974 while (pkghash_next(&it)) { 975 unsigned vercnt = 0; 976 unit = (struct pkg_job_universe_item *)it.value; 977 978 req = pkghash_get_value(j->request_add, unit->pkg->uid); 979 if (req == NULL) { 980 /* Not obviously requested */ 981 continue; 982 } 983 984 local = NULL; 985 LL_FOREACH(unit, cur) { 986 if (cur->pkg->type == PKG_INSTALLED) 987 local = cur; 988 vercnt ++; 989 } 990 991 if (local != NULL && local->pkg->locked) { 992 dbg(1, "removing %s from the request as it is locked", 993 local->pkg->uid); 994 pkghash_del(j->request_add, req->item->pkg->uid); 995 pkg_jobs_request_free(req); 996 continue; 997 } 998 999 if (vercnt <= 1) 1000 continue; 1001 1002 /* 1003 * Here we have more than one upgrade candidate, 1004 * if local == NULL, then we have two remote repos, 1005 * if local != NULL, then we have unspecified upgrade path 1006 */ 1007 1008 if ((local == NULL && vercnt > 1) || (vercnt > 2)) { 1009 /* Select the most recent or one of packages */ 1010 struct pkg_job_universe_item *selected; 1011 1012 selected = pkg_jobs_universe_select_candidate(unit, local, 1013 j->conservative, NULL, j->pinning); 1014 /* 1015 * Now remove all requests but selected from the requested 1016 * candidates 1017 */ 1018 assert(selected != NULL); 1019 pkghash_del(j->request_add, req->item->pkg->uid); 1020 1021 /* 1022 * We also check if the selected package has different digest, 1023 * and if it has the same digest we proceed only if we have a 1024 * forced job 1025 */ 1026 if (local != NULL && STREQ(local->pkg->digest, selected->pkg->digest) && 1027 (j->flags & PKG_FLAG_FORCE) == 0) { 1028 dbg(1, "removing %s from the request as it is the " 1029 "same as local", selected->pkg->uid); 1030 continue; 1031 } 1032 1033 LL_FOREACH(unit, cur) { 1034 if (cur == selected) 1035 continue; 1036 1037 DL_FOREACH_SAFE(req->item, rit, rtmp) { 1038 if (rit->unit == cur) { 1039 DL_DELETE(req->item, rit); 1040 free(rit); 1041 } 1042 } 1043 } 1044 if (req->item == NULL) { 1045 rit = xcalloc(1, sizeof(*rit)); 1046 rit->pkg = selected->pkg; 1047 rit->unit = selected; 1048 DL_APPEND(req->item, rit); 1049 } 1050 pkghash_safe_add(j->request_add, selected->pkg->uid, req, NULL); 1051 } 1052 } 1053 } 1054 1055 struct pkg_job_universe_item* 1056 pkg_jobs_universe_get_upgrade_candidates(struct pkg_jobs_universe *universe, 1057 const char *uid, struct pkg *lp, bool force, const char *version) 1058 { 1059 struct pkg *pkg = NULL, *selected = lp; 1060 struct pkgdb_it *it; 1061 struct pkg_job_universe_item *unit, *ucur; 1062 int flag = PKG_LOAD_BASIC|PKG_LOAD_DEPS|PKG_LOAD_OPTIONS| 1063 PKG_LOAD_REQUIRES|PKG_LOAD_PROVIDES| 1064 PKG_LOAD_SHLIBS_REQUIRED|PKG_LOAD_SHLIBS_PROVIDED| 1065 PKG_LOAD_ANNOTATIONS|PKG_LOAD_CONFLICTS; 1066 pkgs_t candidates = vec_init(); 1067 1068 unit = pkghash_get_value(universe->items, uid); 1069 if (unit != NULL) { 1070 /* 1071 * If a unit has been found, we have already found the potential 1072 * upgrade chain for it 1073 */ 1074 if (force) { 1075 /* 1076 * We also need to ensure that a chain contains remote packages 1077 * in case of forced upgrade 1078 */ 1079 DL_FOREACH(unit, ucur) { 1080 if (ucur->pkg->type != PKG_INSTALLED) { 1081 return (unit); 1082 } 1083 } 1084 } 1085 else { 1086 return (unit); 1087 } 1088 } 1089 1090 if ((it = pkgdb_repo_query2(universe->j->db, uid, MATCH_INTERNAL, 1091 universe->j->reponames)) == NULL) 1092 return (NULL); 1093 1094 while (pkgdb_it_next(it, &pkg, flag) == EPKG_OK) { 1095 1096 if (version != NULL && strcmp(pkg->version, version) != 0) 1097 continue; 1098 1099 if (force) { 1100 /* Just add everything */ 1101 selected = pkg; 1102 } 1103 else { 1104 if (selected == lp && 1105 (lp == NULL || pkg_jobs_need_upgrade(&universe->j->system_shlibs, pkg, lp))) 1106 selected = pkg; 1107 else if (pkg_version_change_between(pkg, selected) == PKG_UPGRADE) 1108 selected = pkg; 1109 } 1110 vec_push(&candidates, pkg); 1111 pkg = NULL; 1112 } 1113 1114 pkgdb_it_free(it); 1115 1116 if (lp != NULL) { 1117 /* Add local package to the universe as well */ 1118 pkg_jobs_universe_add_pkg(universe, lp, NULL); 1119 } 1120 if (selected != lp) { 1121 /* We need to add the whole chain of upgrade candidates */ 1122 vec_rforeach(candidates, i) { 1123 pkg_jobs_universe_add_pkg(universe, candidates.d[i], 1124 NULL); 1125 } 1126 } 1127 else { 1128 vec_free_and_free(&candidates, pkg_free); 1129 return (NULL); 1130 } 1131 1132 unit = pkghash_get_value(universe->items, uid); 1133 vec_free(&candidates); 1134 1135 return (unit); 1136 }