LCOV - code coverage report
Current view: top level - libpkg - pkg_jobs_universe.c (source / functions) Hit Total Coverage
Test: cov.info Lines: 350 523 66.9 %
Date: 2015-08-15 Functions: 23 25 92.0 %

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

Generated by: LCOV version 1.10