LCOV - code coverage report
Current view: top level - libpkg - pkg_solve.c (source / functions) Hit Total Coverage
Test: rapport Lines: 509 754 67.5 %
Date: 2021-12-10 16:22:55 Functions: 21 26 80.8 %
Branches: 279 457 61.1 %

           Branch data     Line data    Source code
       1                 :            : /*-
       2                 :            :  * Copyright (c) 2013-2017 Vsevolod Stakhov <vsevolod@FreeBSD.org>
       3                 :            :  * All rights reserved.
       4                 :            :  *
       5                 :            :  * Redistribution and use in source and binary forms, with or without
       6                 :            :  * modification, are permitted provided that the following conditions
       7                 :            :  * are met:
       8                 :            :  * 1. Redistributions of source code must retain the above copyright
       9                 :            :  *    notice, this list of conditions and the following disclaimer
      10                 :            :  *    in this position and unchanged.
      11                 :            :  * 2. Redistributions in binary form must reproduce the above copyright
      12                 :            :  *    notice, this list of conditions and the following disclaimer in the
      13                 :            :  *    documentation and/or other materials provided with the distribution.
      14                 :            :  *
      15                 :            :  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
      16                 :            :  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
      17                 :            :  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
      18                 :            :  * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
      19                 :            :  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
      20                 :            :  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
      21                 :            :  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
      22                 :            :  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
      23                 :            :  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
      24                 :            :  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
      25                 :            :  */
      26                 :            : 
      27                 :            : #include <sys/param.h>
      28                 :            : #include <sys/mount.h>
      29                 :            : 
      30                 :            : #include <assert.h>
      31                 :            : #include <errno.h>
      32                 :            : #include <stdbool.h>
      33                 :            : #include <stdlib.h>
      34                 :            : #include <stdio.h>
      35                 :            : #include <string.h>
      36                 :            : #include <ctype.h>
      37                 :            : #include <math.h>
      38                 :            : #include <kvec.h>
      39                 :            : 
      40                 :            : #include "pkg.h"
      41                 :            : #include "private/event.h"
      42                 :            : #include "private/pkg.h"
      43                 :            : #include "private/pkgdb.h"
      44                 :            : #include "private/pkg_jobs.h"
      45                 :            : #include "picosat.h"
      46                 :            : 
      47                 :            : struct pkg_solve_item;
      48                 :            : 
      49                 :            : enum pkg_solve_rule_type {
      50                 :            :         PKG_RULE_DEPEND = 0,
      51                 :            :         PKG_RULE_UPGRADE_CONFLICT,
      52                 :            :         PKG_RULE_EXPLICIT_CONFLICT,
      53                 :            :         PKG_RULE_REQUEST_CONFLICT,
      54                 :            :         PKG_RULE_REQUEST,
      55                 :            :         PKG_RULE_REQUIRE,
      56                 :            :         PKG_RULE_MAX
      57                 :            : };
      58                 :            : 
      59                 :            : static const char *rule_reasons[] = {
      60                 :            :         [PKG_RULE_DEPEND] = "dependency",
      61                 :            :         [PKG_RULE_UPGRADE_CONFLICT] = "upgrade",
      62                 :            :         [PKG_RULE_REQUEST_CONFLICT] = "candidates",
      63                 :            :         [PKG_RULE_EXPLICIT_CONFLICT] = "conflict",
      64                 :            :         [PKG_RULE_REQUEST] = "request",
      65                 :            :         [PKG_RULE_REQUIRE] = "require",
      66                 :            :         [PKG_RULE_MAX] = NULL
      67                 :            : };
      68                 :            : 
      69                 :            : enum pkg_solve_variable_flags {
      70                 :            :         PKG_VAR_INSTALL = (1 << 0),
      71                 :            :         PKG_VAR_TOP = (1 << 1),
      72                 :            :         PKG_VAR_FAILED = (1 << 2),
      73                 :            :         PKG_VAR_ASSUMED = (1 << 3),
      74                 :            :         PKG_VAR_ASSUMED_TRUE = (1 << 4)
      75                 :            : };
      76                 :            : struct pkg_solve_variable {
      77                 :            :         struct pkg_job_universe_item *unit;
      78                 :            :         unsigned int flags;
      79                 :            :         int order;
      80                 :            :         const char *digest;
      81                 :            :         const char *uid;
      82                 :            :         const char *assumed_reponame;
      83                 :            :         struct pkg_solve_variable *next, *prev;
      84                 :            : };
      85                 :            : 
      86                 :            : struct pkg_solve_item {
      87                 :            :         int nitems;
      88                 :            :         int nresolved;
      89                 :            :         struct pkg_solve_variable *var;
      90                 :            :         int inverse;
      91                 :            :         struct pkg_solve_item *prev,*next;
      92                 :            : };
      93                 :            : 
      94                 :            : struct pkg_solve_rule {
      95                 :            :         enum pkg_solve_rule_type reason;
      96                 :            :         struct pkg_solve_item *items;
      97                 :            : };
      98                 :            : 
      99                 :            : struct pkg_solve_problem {
     100                 :            :         struct pkg_jobs *j;
     101                 :            :         kvec_t(struct pkg_solve_rule *) rules;
     102                 :            :         pkghash *variables_by_uid;
     103                 :            :         struct pkg_solve_variable *variables;
     104                 :            :         PicoSAT *sat;
     105                 :            :         size_t nvars;
     106                 :            : };
     107                 :            : 
     108                 :            : struct pkg_solve_impl_graph {
     109                 :            :         struct pkg_solve_variable *var;
     110                 :            :         struct pkg_solve_impl_graph *prev, *next;
     111                 :            : };
     112                 :            : 
     113                 :            : /*
     114                 :            :  * Use XOR here to implement the following logic:
     115                 :            :  * atom is true if it is installed and not inverted or
     116                 :            :  * if it is not installed but inverted
     117                 :            :  */
     118                 :            : #define PKG_SOLVE_CHECK_ITEM(item)                              \
     119                 :            :         ((item)->var->to_install ^ (item)->inverse)
     120                 :            : 
     121                 :            : /*
     122                 :            :  * Utilities to convert jobs to SAT rule
     123                 :            :  */
     124                 :            : 
     125                 :            : static void
     126                 :       3134 : pkg_solve_item_new(struct pkg_solve_rule *rule, struct pkg_solve_variable *var,
     127                 :            :     int inverse)
     128                 :            : {
     129                 :            :         struct pkg_solve_item *it;
     130                 :            : 
     131                 :       3134 :         it = xcalloc(1, sizeof(struct pkg_solve_item));
     132                 :       3134 :         it->var = var;
     133                 :       3134 :         it->inverse = inverse;
     134         [ +  + ]:       3134 :         it->nitems = rule->items ? rule->items->nitems + 1 : 1;
     135         [ +  + ]:       3134 :         DL_APPEND(rule->items, it);
     136                 :       3134 : }
     137                 :            : 
     138                 :            : static struct pkg_solve_rule *
     139                 :       1834 : pkg_solve_rule_new(enum pkg_solve_rule_type reason)
     140                 :            : {
     141                 :            :         struct pkg_solve_rule *result;
     142                 :            : 
     143                 :       1834 :         result = xcalloc(1, sizeof(struct pkg_solve_rule));
     144                 :       1834 :         result->reason = reason;
     145                 :            : 
     146                 :       1834 :         return (result);
     147                 :            : }
     148                 :            : 
     149                 :            : static void
     150                 :       1291 : pkg_solve_variable_set(struct pkg_solve_variable *var,
     151                 :            :         struct pkg_job_universe_item *item)
     152                 :            : {
     153                 :       1291 :         var->unit = item;
     154                 :            :         /* XXX: Is it safe to save a ptr here ? */
     155                 :       1291 :         var->digest = item->pkg->digest;
     156                 :       1291 :         var->uid = item->pkg->uid;
     157                 :       1291 :         var->prev = var;
     158                 :       1291 : }
     159                 :            : 
     160                 :            : static void
     161                 :       1834 : pkg_solve_rule_free(struct pkg_solve_rule *rule)
     162                 :            : {
     163                 :            :         struct pkg_solve_item *it, *tmp;
     164                 :            : 
     165   [ +  +  +  + ]:       4968 :         LL_FOREACH_SAFE(rule->items, it, tmp) {
     166                 :       3134 :                 free(it);
     167                 :       3134 :         }
     168                 :       1834 :         free(rule);
     169                 :       1834 : }
     170                 :            : 
     171                 :            : 
     172                 :            : void
     173                 :        640 : pkg_solve_problem_free(struct pkg_solve_problem *problem)
     174                 :            : {
     175         [ +  + ]:       1646 :         while (kv_size(problem->rules)) {
     176                 :       1006 :                 pkg_solve_rule_free(kv_pop(problem->rules));
     177                 :            :         }
     178                 :            : 
     179                 :        640 :         pkghash_destroy(problem->variables_by_uid);
     180                 :            : 
     181                 :        640 :         picosat_reset(problem->sat);
     182                 :        640 :         free(problem->variables);
     183                 :        640 :         free(problem);
     184                 :        640 : }
     185                 :            : 
     186                 :            : 
     187                 :            : static void
     188                 :          0 : pkg_print_rule_buf(struct pkg_solve_rule *rule, xstring *sb)
     189                 :            : {
     190                 :          0 :         struct pkg_solve_item *it = rule->items, *key_elt = NULL;
     191                 :            : 
     192                 :          0 :         fprintf(sb->fp, "%s rule: ", rule_reasons[rule->reason]);
     193   [ #  #  #  #  :          0 :         switch(rule->reason) {
                   #  # ]
     194                 :            :         case PKG_RULE_DEPEND:
     195         [ #  # ]:          0 :                 LL_FOREACH(rule->items, it) {
     196         [ #  # ]:          0 :                         if (it->inverse == -1) {
     197                 :          0 :                                 key_elt = it;
     198                 :          0 :                                 break;
     199                 :            :                         }
     200                 :          0 :                 }
     201         [ #  # ]:          0 :                 if (key_elt) {
     202                 :          0 :                         fprintf(sb->fp, "package %s%s depends on: ", key_elt->var->uid,
     203                 :          0 :                                 (key_elt->var->unit->pkg->type == PKG_INSTALLED) ? "(l)" : "(r)");
     204                 :          0 :                 }
     205         [ #  # ]:          0 :                 LL_FOREACH(rule->items, it) {
     206         [ #  # ]:          0 :                         if (it != key_elt) {
     207                 :          0 :                                 fprintf(sb->fp, "%s%s", it->var->uid,
     208                 :          0 :                                         (it->var->unit->pkg->type == PKG_INSTALLED) ? "(l)" : "(r)");
     209                 :          0 :                         }
     210                 :          0 :                 }
     211                 :          0 :                 break;
     212                 :            :         case PKG_RULE_UPGRADE_CONFLICT:
     213                 :          0 :                 fprintf(sb->fp, "upgrade local %s-%s to remote %s-%s",
     214                 :          0 :                         it->var->uid, it->var->unit->pkg->version,
     215                 :          0 :                         it->next->var->uid, it->next->var->unit->pkg->version);
     216                 :          0 :                 break;
     217                 :            :         case PKG_RULE_EXPLICIT_CONFLICT:
     218                 :          0 :                 fprintf(sb->fp, "The following packages conflict with each other: ");
     219         [ #  # ]:          0 :                 LL_FOREACH(rule->items, it) {
     220                 :          0 :                         fprintf(sb->fp, "%s-%s%s%s", it->var->unit->pkg->uid, it->var->unit->pkg->version,
     221                 :          0 :                                 (it->var->unit->pkg->type == PKG_INSTALLED) ? "(l)" : "(r)",
     222                 :          0 :                                 it->next ? ", " : "");
     223                 :          0 :                 }
     224                 :          0 :                 break;
     225                 :            :         case PKG_RULE_REQUIRE:
     226         [ #  # ]:          0 :                 LL_FOREACH(rule->items, it) {
     227         [ #  # ]:          0 :                         if (it->inverse == -1) {
     228                 :          0 :                                 key_elt = it;
     229                 :          0 :                                 break;
     230                 :            :                         }
     231                 :          0 :                 }
     232         [ #  # ]:          0 :                 if (key_elt) {
     233                 :          0 :                         fprintf(sb->fp, "package %s%s depends on a requirement provided by: ",
     234                 :          0 :                                 key_elt->var->uid,
     235                 :          0 :                                 (key_elt->var->unit->pkg->type == PKG_INSTALLED) ? "(l)" : "(r)");
     236                 :          0 :                 }
     237         [ #  # ]:          0 :                 LL_FOREACH(rule->items, it) {
     238         [ #  # ]:          0 :                         if (it != key_elt) {
     239                 :          0 :                                 fprintf(sb->fp, "%s%s", it->var->uid,
     240                 :          0 :                                         (it->var->unit->pkg->type == PKG_INSTALLED) ? "(l)" : "(r)");
     241                 :          0 :                         }
     242                 :          0 :                 }
     243                 :          0 :                 break;
     244                 :            :         case PKG_RULE_REQUEST_CONFLICT:
     245                 :          0 :                 fprintf(sb->fp, "The following packages in request are candidates for installation: ");
     246         [ #  # ]:          0 :                 LL_FOREACH(rule->items, it) {
     247                 :          0 :                         fprintf(sb->fp, "%s-%s%s", it->var->uid, it->var->unit->pkg->version,
     248                 :          0 :                                         it->next ? ", " : "");
     249                 :          0 :                 }
     250                 :          0 :                 break;
     251                 :            :         default:
     252                 :          0 :                 break;
     253                 :            :         }
     254                 :          0 : }
     255                 :            : 
     256                 :            : static void
     257                 :       1006 : pkg_debug_print_rule(struct pkg_solve_rule *rule)
     258                 :            : {
     259                 :            :         xstring *sb;
     260                 :            : 
     261         [ +  - ]:       1006 :         if (ctx.debug_level < 3)
     262                 :       1006 :                 return;
     263                 :            : 
     264                 :          0 :         sb = xstring_new();
     265                 :            : 
     266                 :          0 :         pkg_print_rule_buf(rule, sb);
     267                 :            : 
     268                 :          0 :         fflush(sb->fp);
     269                 :          0 :         pkg_debug(2, "%s", sb->buf);
     270                 :          0 :         xstring_free(sb);
     271                 :       1006 : }
     272                 :            : 
     273                 :            : static int
     274                 :         56 : pkg_solve_handle_provide (struct pkg_solve_problem *problem,
     275                 :            :                 struct pkg_job_provide *pr, struct pkg_solve_rule *rule,
     276                 :            :                 struct pkg *orig, const char *reponame, int *cnt)
     277                 :            : {
     278                 :            :         struct pkg_solve_variable *var, *curvar;
     279                 :            :         struct pkg_job_universe_item *un;
     280                 :            :         struct pkg *pkg;
     281                 :            :         bool libfound, providefound;
     282                 :            : 
     283                 :            :         /* Find the first package in the universe list */
     284                 :         56 :         un = pr->un;
     285         [ +  + ]:         76 :         while (un->prev->next != NULL) {
     286                 :         20 :                 un = un->prev;
     287                 :            :         }
     288                 :            : 
     289                 :            :         /* Find the corresponding variables chain */
     290                 :            : 
     291                 :         56 :         var = pkghash_get_value(problem->variables_by_uid, un->pkg->uid);
     292         [ +  + ]:        140 :         LL_FOREACH(var, curvar) {
     293                 :            :                 /*
     294                 :            :                  * For each provide we need to check whether this package
     295                 :            :                  * actually provides this require
     296                 :            :                  */
     297                 :         84 :                 libfound = providefound = false;
     298                 :         84 :                 pkg = curvar->unit->pkg;
     299                 :            : 
     300         [ +  + ]:         84 :                 if (pr->is_shlib) {
     301                 :         16 :                         libfound = (pkghash_get(pkg->shlibs_provided, pr->provide) != NULL);
     302                 :            :                         /* Skip incompatible ABI as well */
     303   [ +  -  +  - ]:         16 :                         if (libfound && strcmp(pkg->arch, orig->arch) != 0) {
     304                 :          0 :                                 pkg_debug(2, "solver: require %s: package %s-%s(%c) provides wrong ABI %s, "
     305                 :          0 :                                         "wanted %s", pr->provide, pkg->name, pkg->version,
     306                 :          0 :                                         pkg->type == PKG_INSTALLED ? 'l' : 'r', orig->arch, pkg->arch);
     307                 :          0 :                                 continue;
     308                 :            :                         }
     309                 :         16 :                 }
     310                 :            :                 else {
     311                 :         68 :                         providefound = (pkghash_get(pkg->provides, pr->provide) != NULL);
     312                 :            :                 }
     313                 :            : 
     314   [ +  +  +  + ]:         84 :                 if (!providefound && !libfound) {
     315                 :         56 :                         pkg_debug(4, "solver: %s provide is not satisfied by %s-%s(%c)", pr->provide,
     316                 :         28 :                                         pkg->name, pkg->version, pkg->type == PKG_INSTALLED ?
     317                 :            :                                                         'l' : 'r');
     318                 :         28 :                         continue;
     319                 :            :                 }
     320                 :            : 
     321         [ -  + ]:         56 :                 if (curvar->assumed_reponame == NULL) {
     322                 :         56 :                         curvar->assumed_reponame = reponame;
     323                 :         56 :                 }
     324                 :            : 
     325                 :        112 :                 pkg_debug(4, "solver: %s provide is satisfied by %s-%s(%c)", pr->provide,
     326                 :         56 :                                 pkg->name, pkg->version, pkg->type == PKG_INSTALLED ?
     327                 :            :                                 'l' : 'r');
     328                 :            : 
     329                 :         56 :                 pkg_solve_item_new(rule, curvar, 1);
     330                 :         56 :                 (*cnt)++;
     331                 :         56 :         }
     332                 :            : 
     333                 :         56 :         return (EPKG_OK);
     334                 :            : }
     335                 :            : 
     336                 :            : static int
     337                 :        503 : pkg_solve_add_depend_rule(struct pkg_solve_problem *problem,
     338                 :            :                 struct pkg_solve_variable *var,
     339                 :            :                 struct pkg_dep *dep,
     340                 :            :                 const char *reponame)
     341                 :            : {
     342                 :            :         const char *uid;
     343                 :            :         struct pkg_solve_variable *depvar, *curvar;
     344                 :        503 :         struct pkg_solve_rule *rule = NULL;
     345                 :        503 :         int cnt = 0;
     346                 :            :         struct pkg_dep *cur;
     347                 :            : 
     348                 :            :         /* Dependency rule: (!A | B1 | B2 | B3...) */
     349                 :        503 :         rule = pkg_solve_rule_new(PKG_RULE_DEPEND);
     350                 :            :         /* !A */
     351                 :        503 :         pkg_solve_item_new(rule, var, -1);
     352                 :            : 
     353         [ +  + ]:       1006 :         LL_FOREACH2(dep, cur, alt_next) {
     354                 :        503 :                 uid = cur->uid;
     355                 :        503 :                 depvar = NULL;
     356                 :        503 :                 depvar = pkghash_get_value(problem->variables_by_uid, uid);
     357         [ +  + ]:        503 :                 if (depvar == NULL) {
     358                 :         59 :                         pkg_debug(2, "cannot find variable dependency %s", uid);
     359                 :         59 :                         continue;
     360                 :            :                 }
     361                 :            : 
     362                 :            :                 /* B1 | B2 | ... */
     363                 :        444 :                 cnt = 1;
     364         [ +  + ]:       1068 :                 LL_FOREACH(depvar, curvar) {
     365                 :            :                         /* Propagate reponame */
     366         [ -  + ]:        624 :                         if (curvar->assumed_reponame == NULL) {
     367                 :        624 :                                 curvar->assumed_reponame = reponame;
     368                 :        624 :                         }
     369                 :            : 
     370                 :        624 :                         pkg_solve_item_new(rule, curvar, 1);
     371                 :        624 :                         cnt++;
     372                 :        624 :                 }
     373                 :        444 :         }
     374                 :            : 
     375         [ +  + ]:        503 :         if (cnt == 0) {
     376                 :         59 :                 pkg_debug(2, "cannot find any suitable dependency for %s", var->uid);
     377                 :         59 :                 pkg_solve_rule_free(rule);
     378                 :            : 
     379                 :         59 :                 return (EPKG_FATAL);
     380                 :            :         }
     381                 :            : 
     382   [ +  +  +  + ]:        444 :         kv_prepend(typeof(rule), problem->rules, rule);
     383                 :            : 
     384                 :        444 :         return (EPKG_OK);
     385                 :        503 : }
     386                 :            : 
     387                 :            : static int
     388                 :        108 : pkg_solve_add_conflict_rule(struct pkg_solve_problem *problem,
     389                 :            :                 struct pkg *pkg,
     390                 :            :                 struct pkg_solve_variable *var,
     391                 :            :                 struct pkg_conflict *conflict)
     392                 :            : {
     393                 :            :         const char *uid;
     394                 :            :         struct pkg_solve_variable *confvar, *curvar;
     395                 :        108 :         struct pkg_solve_rule *rule = NULL;
     396                 :            :         struct pkg *other;
     397                 :            : 
     398                 :        108 :         uid = conflict->uid;
     399                 :        108 :         confvar = pkghash_get_value(problem->variables_by_uid, uid);
     400         [ -  + ]:        108 :         if (confvar == NULL) {
     401                 :          0 :                 pkg_debug(2, "cannot find conflict %s", uid);
     402                 :          0 :                 return (EPKG_END);
     403                 :            :         }
     404                 :            : 
     405                 :            :         /* Add conflict rule from each of the alternative */
     406         [ +  + ]:        268 :         LL_FOREACH(confvar, curvar) {
     407                 :        160 :                 other = curvar->unit->pkg;
     408         [ +  + ]:        160 :                 if (conflict->type == PKG_CONFLICT_REMOTE_LOCAL) {
     409                 :            :                         /* Skip unappropriate packages */
     410         [ +  + ]:        140 :                         if (pkg->type == PKG_INSTALLED) {
     411         [ +  + ]:         68 :                                 if (other->type == PKG_INSTALLED)
     412                 :         16 :                                         continue;
     413                 :         52 :                         }
     414                 :            :                         else {
     415         [ +  + ]:         72 :                                 if (other->type != PKG_INSTALLED)
     416                 :         24 :                                         continue;
     417                 :            :                         }
     418                 :        100 :                 }
     419         [ -  + ]:         20 :                 else if (conflict->type == PKG_CONFLICT_REMOTE_REMOTE) {
     420         [ -  + ]:         20 :                         if (pkg->type == PKG_INSTALLED)
     421                 :          0 :                                 continue;
     422                 :            : 
     423         [ +  + ]:         20 :                         if (other->type == PKG_INSTALLED)
     424                 :          4 :                                 continue;
     425                 :         16 :                 }
     426                 :            :                 /*
     427                 :            :                  * Also if a conflict is digest specific then we skip
     428                 :            :                  * variables with mismatched digests
     429                 :            :                  */
     430         [ -  + ]:        116 :                 if (conflict->digest) {
     431         [ +  + ]:        116 :                         if (strcmp (conflict->digest, other->digest) != 0)
     432                 :          8 :                                 continue;
     433                 :        108 :                 }
     434                 :            : 
     435                 :            :                 /* Conflict rule: (!A | !Bx) */
     436                 :        108 :                 rule = pkg_solve_rule_new(PKG_RULE_EXPLICIT_CONFLICT);
     437                 :            :                 /* !A */
     438                 :        108 :                 pkg_solve_item_new(rule, var, -1);
     439                 :            :                 /* !Bx */
     440                 :        108 :                 pkg_solve_item_new(rule, curvar, -1);
     441                 :            : 
     442   [ +  +  +  + ]:        108 :                 kv_prepend(typeof(rule), problem->rules, rule);
     443                 :        108 :         }
     444                 :            : 
     445                 :        108 :         return (EPKG_OK);
     446                 :        108 : }
     447                 :            : 
     448                 :            : static int
     449                 :         80 : pkg_solve_add_require_rule(struct pkg_solve_problem *problem,
     450                 :            :                 struct pkg_solve_variable *var,
     451                 :            :                 const char *requirement,
     452                 :            :                 const char *reponame)
     453                 :            : {
     454                 :            :         struct pkg_solve_rule *rule;
     455                 :         80 :         struct pkg_solve_item *it = NULL;
     456                 :            :         struct pkg_job_provide *pr, *prhead;
     457                 :            :         struct pkg *pkg;
     458                 :            :         int cnt;
     459                 :            : 
     460                 :         80 :         pkg = var->unit->pkg;
     461                 :            : 
     462                 :         80 :         prhead = pkghash_get_value(problem->j->universe->provides, requirement);
     463         [ +  + ]:         80 :         if (prhead != NULL) {
     464                 :         56 :                 pkg_debug(4, "solver: Add require rule: %s-%s(%c) wants %s",
     465                 :         56 :                         pkg->name, pkg->version, pkg->type == PKG_INSTALLED ? 'l' : 'r',
     466                 :         56 :                         requirement);
     467                 :            :                 /* Require rule !A | P1 | P2 | P3 ... */
     468                 :         56 :                 rule = pkg_solve_rule_new(PKG_RULE_REQUIRE);
     469                 :            :                 /* !A */
     470                 :         56 :                 pkg_solve_item_new(rule, var, -1);
     471                 :            :                 /* B1 | B2 | ... */
     472                 :         56 :                 cnt = 1;
     473         [ +  + ]:        112 :                 LL_FOREACH(prhead, pr) {
     474   [ +  -  +  - ]:        112 :                         if (pkg_solve_handle_provide(problem, pr, rule, pkg, reponame, &cnt)
     475                 :         56 :                                         != EPKG_OK) {
     476                 :          0 :                                 free(it);
     477                 :          0 :                                 free(rule);
     478                 :          0 :                                 return (EPKG_FATAL);
     479                 :            :                         }
     480                 :         56 :                 }
     481                 :            : 
     482         [ +  - ]:         56 :                 if (cnt > 1) {
     483   [ +  +  +  + ]:         56 :                         kv_prepend(typeof(rule), problem->rules, rule);
     484                 :         56 :                 }
     485                 :            :                 else {
     486                 :            :                         /* Missing dependencies... */
     487                 :          0 :                         free(it);
     488                 :          0 :                         free(rule);
     489                 :            :                 }
     490                 :         56 :         }
     491                 :            :         else {
     492                 :            :                 /*
     493                 :            :                  * XXX:
     494                 :            :                  * This is terribly broken now so ignore till provides/requires
     495                 :            :                  * are really fixed.
     496                 :            :                  */
     497                 :         24 :                 pkg_debug(1, "solver: for package: %s cannot find provide for requirement: %s",
     498                 :         24 :                     pkg->name, requirement);
     499                 :            :         }
     500                 :            : 
     501                 :         80 :         return (EPKG_OK);
     502                 :         80 : }
     503                 :            : 
     504                 :            : static struct pkg_solve_variable *
     505                 :       1652 : pkg_solve_find_var_in_chain(struct pkg_solve_variable *var,
     506                 :            :         struct pkg_job_universe_item *item)
     507                 :            : {
     508                 :            :         struct pkg_solve_variable *cur;
     509                 :            : 
     510         [ +  - ]:       1652 :         assert(var != NULL);
     511         [ +  - ]:       1953 :         LL_FOREACH(var, cur) {
     512         [ +  + ]:       1953 :                 if (cur->unit == item) {
     513                 :       1652 :                         return (cur);
     514                 :            :                 }
     515                 :        301 :         }
     516                 :            : 
     517                 :          0 :         return (NULL);
     518                 :       1652 : }
     519                 :            : 
     520                 :            : static int
     521                 :        769 : pkg_solve_add_request_rule(struct pkg_solve_problem *problem,
     522                 :            :         struct pkg_solve_variable *var, struct pkg_job_request *req, int inverse)
     523                 :            : {
     524                 :        769 :         struct pkg_solve_rule *rule = NULL;
     525                 :            :         struct pkg_job_request_item *item, *confitem;
     526                 :            :         struct pkg_solve_variable *confvar, *curvar;
     527                 :            :         int cnt;
     528                 :            : 
     529                 :        769 :         pkg_debug(4, "solver: add variable from %s request with uid %s-%s",
     530                 :        769 :                 inverse < 0 ? "delete" : "install", var->uid, var->digest);
     531                 :            : 
     532                 :            :         /*
     533                 :            :          * Get the suggested item
     534                 :            :          */
     535                 :        769 :         var = pkghash_get_value(problem->variables_by_uid, req->item->pkg->uid);
     536                 :        769 :         var = pkg_solve_find_var_in_chain(var, req->item->unit);
     537         [ +  - ]:        769 :         assert(var != NULL);
     538                 :            :         /* Assume the most significant variable */
     539                 :        769 :         picosat_assume(problem->sat, var->order * inverse);
     540                 :            : 
     541                 :            :         /*
     542                 :            :          * Add clause for any of candidates:
     543                 :            :          * A1 | A2 | ... | An
     544                 :            :          */
     545                 :        769 :         rule = pkg_solve_rule_new(PKG_RULE_REQUEST);
     546                 :            : 
     547                 :        769 :         cnt = 0;
     548                 :            : 
     549         [ +  + ]:       1652 :         LL_FOREACH(req->item, item) {
     550                 :        883 :                 curvar = pkg_solve_find_var_in_chain(var, item->unit);
     551         [ +  - ]:        883 :                 assert(curvar != NULL);
     552                 :        883 :                 pkg_solve_item_new(rule, curvar, inverse);
     553                 :            :                 /* All request variables are top level */
     554                 :        883 :                 curvar->flags |= PKG_VAR_TOP;
     555                 :            : 
     556         [ +  + ]:        883 :                 if (inverse > 0) {
     557                 :        734 :                         curvar->flags |= PKG_VAR_INSTALL;
     558                 :        734 :                 }
     559                 :            : 
     560                 :        883 :                 cnt++;
     561                 :        883 :         }
     562                 :            : 
     563   [ +  +  +  - ]:        769 :         if (cnt > 1 && var->unit->inhash != 0) {
     564   [ #  #  #  # ]:          0 :                 kv_prepend(typeof(rule), problem->rules, rule);
     565                 :            :                 /* Also need to add pairs of conflicts */
     566         [ #  # ]:          0 :                 LL_FOREACH(req->item, item) {
     567                 :          0 :                         curvar = pkg_solve_find_var_in_chain(var, item->unit);
     568         [ #  # ]:          0 :                         assert(curvar != NULL);
     569         [ #  # ]:          0 :                         if (item->next == NULL)
     570                 :          0 :                                 continue;
     571         [ #  # ]:          0 :                         LL_FOREACH(item->next, confitem) {
     572                 :          0 :                                 confvar = pkg_solve_find_var_in_chain(var, confitem->unit);
     573         [ #  # ]:          0 :                                 assert(confvar != NULL && confvar != curvar && confvar != var);
     574                 :            :                                 /* Conflict rule: (!A | !Bx) */
     575                 :          0 :                                 rule = pkg_solve_rule_new(PKG_RULE_REQUEST_CONFLICT);
     576                 :            :                                 /* !A */
     577                 :          0 :                                 pkg_solve_item_new(rule, curvar, -1);
     578                 :            :                                 /* !Bx */
     579                 :          0 :                                 pkg_solve_item_new(rule, confvar, -1);
     580                 :            : 
     581   [ #  #  #  # ]:          0 :                                 kv_prepend(typeof(rule), problem->rules, rule);
     582                 :          0 :                         }
     583                 :          0 :                 }
     584                 :          0 :         }
     585                 :            :         else {
     586                 :            :                 /* No need to add unary rules as we added the assumption already */
     587                 :        769 :                 pkg_solve_rule_free(rule);
     588                 :            :         }
     589                 :            : 
     590                 :        769 :         var->flags |= PKG_VAR_TOP;
     591         [ +  + ]:        769 :         if (inverse > 0) {
     592                 :        620 :                 var->flags |= PKG_VAR_INSTALL;
     593                 :        620 :         }
     594                 :            : 
     595                 :        769 :         return (EPKG_OK);
     596                 :            : }
     597                 :            : 
     598                 :            : static int
     599                 :        276 : pkg_solve_add_chain_rule(struct pkg_solve_problem *problem,
     600                 :            :         struct pkg_solve_variable *var)
     601                 :            : {
     602                 :            :         struct pkg_solve_variable *curvar, *confvar;
     603                 :            :         struct pkg_solve_rule *rule;
     604                 :            : 
     605                 :            :         /* Rewind to first */
     606         [ -  + ]:        276 :         while (var->prev->next != NULL) {
     607                 :          0 :                 var = var->prev;
     608                 :            :         }
     609                 :            : 
     610         [ -  + ]:        613 :         LL_FOREACH(var, curvar) {
     611                 :            :                 /* Conflict rule: (!Ax | !Ay) */
     612         [ +  + ]:        613 :                 if (curvar->next == NULL) {
     613                 :        276 :                         break;
     614                 :            :                 }
     615                 :            : 
     616         [ +  + ]:        735 :                 LL_FOREACH(curvar->next, confvar) {
     617                 :        398 :                         rule = pkg_solve_rule_new(PKG_RULE_UPGRADE_CONFLICT);
     618                 :            :                         /* !Ax */
     619                 :        398 :                         pkg_solve_item_new(rule, curvar, -1);
     620                 :            :                         /* !Ay */
     621                 :        398 :                         pkg_solve_item_new(rule, confvar, -1);
     622                 :            : 
     623   [ +  +  +  + ]:        398 :                         kv_prepend(typeof(rule), problem->rules, rule);
     624                 :        398 :                 }
     625                 :        337 :         }
     626                 :            : 
     627                 :        276 :         return (EPKG_OK);
     628                 :            : }
     629                 :            : 
     630                 :            : static int
     631                 :        954 : pkg_solve_process_universe_variable(struct pkg_solve_problem *problem,
     632                 :            :                 struct pkg_solve_variable *var)
     633                 :            : {
     634                 :            :         struct pkg_dep *dep;
     635                 :            :         struct pkg_conflict *conflict;
     636                 :            :         struct pkg *pkg;
     637                 :            :         struct pkg_solve_variable *cur_var;
     638                 :        954 :         struct pkg_jobs *j = problem->j;
     639                 :        954 :         struct pkg_job_request *jreq = NULL;
     640                 :            :         pkghash_it it;
     641                 :        954 :         bool chain_added = false;
     642                 :            : 
     643         [ +  + ]:       2245 :         LL_FOREACH(var, cur_var) {
     644                 :       1291 :                 pkg = cur_var->unit->pkg;
     645                 :            : 
     646                 :            :                 /* Request */
     647         [ +  + ]:       1291 :                 if (!(cur_var->flags & PKG_VAR_TOP)) {
     648                 :       1047 :                         jreq = pkghash_get_value(j->request_add, cur_var->uid);
     649         [ +  + ]:       1047 :                         if (jreq != NULL)
     650                 :        620 :                                 pkg_solve_add_request_rule(problem, cur_var, jreq, 1);
     651                 :       1047 :                         jreq = pkghash_get_value(j->request_delete, cur_var->uid);
     652         [ +  + ]:       1047 :                         if (jreq != NULL)
     653                 :        149 :                                 pkg_solve_add_request_rule(problem, cur_var, jreq, -1);
     654                 :       1047 :                 }
     655                 :            : 
     656         [ +  + ]:       1291 :                 if (jreq) {
     657                 :        149 :                         cur_var->assumed_reponame = pkg->reponame;
     658                 :        149 :                 }
     659                 :            : 
     660                 :            :                 /* Depends */
     661         [ +  + ]:       1794 :                 LL_FOREACH(pkg->depends, dep) {
     662   [ +  +  +  +  :       1509 :                         if (pkg_solve_add_depend_rule(problem, cur_var, dep,
                   +  + ]
     663                 :       1006 :                                         cur_var->assumed_reponame) != EPKG_OK) {
     664                 :         59 :                                 continue;
     665                 :            :                         }
     666                 :        444 :                 }
     667                 :            : 
     668                 :            :                 /* Conflicts */
     669         [ +  + ]:       1399 :                 LL_FOREACH(pkg->conflicts, conflict) {
     670         [ -  + ]:        108 :                         if (pkg_solve_add_conflict_rule(problem, pkg, cur_var, conflict) !=
     671                 :            :                                                         EPKG_OK)
     672                 :          0 :                                 continue;
     673                 :        108 :                 }
     674                 :            : 
     675                 :            :                 /* Shlibs */
     676                 :       1291 :                 it = pkghash_iterator(pkg->shlibs_required);
     677         [ +  + ]:       1323 :                 while (pkghash_next(&it)) {
     678   [ -  +  -  +  :         96 :                         if (pkg_solve_add_require_rule(problem, cur_var,
                   -  + ]
     679                 :         64 :                             it.key, cur_var->assumed_reponame) != EPKG_OK) {
     680                 :          0 :                                 continue;
     681                 :            :                         }
     682                 :            :                 }
     683                 :       1291 :                 it = pkghash_iterator(pkg->requires);
     684         [ +  + ]:       1339 :                 while (pkghash_next(&it)) {
     685   [ -  +  -  +  :        144 :                         if (pkg_solve_add_require_rule(problem, cur_var,
                   -  + ]
     686                 :         96 :                             it.key, cur_var->assumed_reponame) != EPKG_OK) {
     687                 :          0 :                                 continue;
     688                 :            :                         }
     689                 :            :                 }
     690                 :            : 
     691                 :            : 
     692                 :            :                 /*
     693                 :            :                  * If this var chain contains mutually conflicting vars
     694                 :            :                  * we need to register conflicts with all following
     695                 :            :                  * vars
     696                 :            :                  */
     697   [ +  +  +  +  :       1291 :                 if (!chain_added && (cur_var->next != NULL || cur_var->prev != var)) {
                   -  + ]
     698         [ -  + ]:        276 :                         if (pkg_solve_add_chain_rule(problem, cur_var) != EPKG_OK)
     699                 :          0 :                                 continue;
     700                 :            : 
     701                 :        276 :                         chain_added = true;
     702                 :        276 :                 }
     703                 :       1291 :         }
     704                 :            : 
     705                 :        954 :         return (EPKG_OK);
     706                 :            : }
     707                 :            : 
     708                 :            : static int
     709                 :        954 : pkg_solve_add_variable(struct pkg_job_universe_item *un,
     710                 :            :                 struct pkg_solve_problem *problem, size_t *n)
     711                 :            : {
     712                 :            :         struct pkg_job_universe_item *ucur;
     713                 :        954 :         struct pkg_solve_variable *var = NULL, *tvar = NULL;
     714                 :            : 
     715         [ +  + ]:       2245 :         LL_FOREACH(un, ucur) {
     716         [ +  - ]:       1291 :                 assert(*n < problem->nvars);
     717                 :            : 
     718                 :            :                 /* Add new variable */
     719                 :       1291 :                 var = &problem->variables[*n];
     720                 :       1291 :                 pkg_solve_variable_set(var, ucur);
     721                 :            : 
     722         [ +  + ]:       1291 :                 if (tvar == NULL) {
     723                 :        954 :                         pkg_debug(4, "solver: add variable from universe with uid %s", var->uid);
     724   [ +  +  -  + ]:       1278 :                         pkghash_safe_add(problem->variables_by_uid, var->uid, var, NULL);
     725                 :        954 :                         tvar = var;
     726                 :        954 :                 }
     727                 :            :                 else {
     728                 :            :                         /* Insert a variable to a chain */
     729         [ +  - ]:        337 :                         DL_APPEND(tvar, var);
     730                 :            :                 }
     731                 :       1291 :                 (*n) ++;
     732                 :       1291 :                 var->order = *n;
     733                 :       1291 :         }
     734                 :            : 
     735                 :        954 :         return (EPKG_OK);
     736                 :            : }
     737                 :            : 
     738                 :            : struct pkg_solve_problem *
     739                 :        640 : pkg_solve_jobs_to_sat(struct pkg_jobs *j)
     740                 :            : {
     741                 :            :         struct pkg_solve_problem *problem;
     742                 :            :         struct pkg_job_universe_item *un;
     743                 :        640 :         size_t i = 0;
     744                 :            :         pkghash_it it;
     745                 :            : 
     746                 :        640 :         problem = xcalloc(1, sizeof(struct pkg_solve_problem));
     747                 :            : 
     748                 :        640 :         problem->j = j;
     749                 :        640 :         problem->nvars = j->universe->nitems;
     750                 :        640 :         problem->variables = xcalloc(problem->nvars, sizeof(struct pkg_solve_variable));
     751                 :        640 :         problem->sat = picosat_init();
     752                 :        640 :         kv_init(problem->rules);
     753                 :            : 
     754         [ +  - ]:        640 :         if (problem->sat == NULL) {
     755                 :          0 :                 pkg_emit_errno("picosat_init", "pkg_solve_sat_problem");
     756                 :          0 :                 return (NULL);
     757                 :            :         }
     758                 :            : 
     759                 :        640 :         picosat_adjust(problem->sat, problem->nvars);
     760                 :            : 
     761                 :            :         /* Parse universe */
     762                 :        640 :         it = pkghash_iterator(j->universe->items);
     763         [ +  + ]:       1594 :         while (pkghash_next(&it)) {
     764                 :        954 :                 un = (struct pkg_job_universe_item *)it.value;
     765                 :            :                 /* Add corresponding variables */
     766         [ +  - ]:        954 :                 if (pkg_solve_add_variable(un, problem, &i) == EPKG_FATAL)
     767                 :          0 :                         goto err;
     768                 :            :         }
     769                 :            : 
     770                 :            :         /* Add rules for all conflict chains */
     771                 :        640 :         it = pkghash_iterator(j->universe->items);
     772         [ +  + ]:       1594 :         while (pkghash_next(&it)) {
     773                 :            :                 struct pkg_solve_variable *var;
     774                 :            : 
     775                 :        954 :                 un = (struct pkg_job_universe_item *)it.value;
     776                 :        954 :                 var = pkghash_get_value(problem->variables_by_uid, un->pkg->uid);
     777         [ +  - ]:        954 :                 if (var == NULL) {
     778                 :          0 :                         pkg_emit_error("internal solver error: variable %s is not found",
     779                 :          0 :                             un->pkg->uid);
     780                 :          0 :                         goto err;
     781                 :            :                 }
     782         [ +  - ]:        954 :                 if (pkg_solve_process_universe_variable(problem, var) != EPKG_OK)
     783                 :          0 :                         goto err;
     784                 :            :         }
     785                 :            : 
     786         [ +  + ]:        640 :         if (kv_size(problem->rules) == 0)
     787                 :        424 :                 pkg_debug(1, "problem has no requests");
     788                 :            : 
     789                 :        640 :         return (problem);
     790                 :            : 
     791                 :            : err:
     792                 :          0 :         return (NULL);
     793                 :        640 : }
     794                 :            : 
     795                 :            : static int
     796                 :        672 : pkg_solve_picosat_iter(struct pkg_solve_problem *problem, int iter __unused)
     797                 :            : {
     798                 :            :         int res, i;
     799                 :            :         struct pkg_solve_variable *var, *cur;
     800                 :        672 :         bool is_installed = false;
     801                 :            : 
     802                 :        672 :         picosat_reset_phases(problem->sat);
     803                 :        672 :         picosat_reset_scores(problem->sat);
     804                 :            :         /* Set initial guess */
     805         [ +  + ]:       2151 :         for (i = 0; i < problem->nvars; i ++) {
     806                 :       1479 :                 var = &problem->variables[i];
     807                 :       1479 :                 is_installed = false;
     808                 :            : 
     809         [ +  + ]:       2436 :                 LL_FOREACH(var, cur) {
     810         [ +  + ]:       1560 :                         if (cur->unit->pkg->type == PKG_INSTALLED) {
     811                 :        603 :                                 is_installed = true;
     812                 :        603 :                                 break;
     813                 :            :                         }
     814                 :        957 :                 }
     815                 :            : 
     816         [ +  + ]:       1479 :                 if (var->flags & PKG_VAR_TOP)
     817                 :        756 :                         continue;
     818                 :            : 
     819         [ +  + ]:        723 :                 if (!(var->flags & (PKG_VAR_FAILED|PKG_VAR_ASSUMED))) {
     820         [ +  + ]:        459 :                         if (is_installed) {
     821                 :        334 :                                 picosat_set_default_phase_lit(problem->sat, i + 1, 1);
     822                 :        334 :                                 picosat_set_more_important_lit(problem->sat, i + 1);
     823                 :        334 :                         }
     824   [ +  +  +  + ]:        125 :                         else if  (!var->next && var->prev == var) {
     825                 :            :                                 /* Prefer not to install if have no local version */
     826                 :         28 :                                 picosat_set_default_phase_lit(problem->sat, i + 1, -1);
     827                 :         28 :                                 picosat_set_less_important_lit(problem->sat, i + 1);
     828                 :         28 :                         }
     829                 :        459 :                 }
     830         [ +  + ]:        264 :                 else if (var->flags & PKG_VAR_FAILED) {
     831         [ +  + ]:         36 :                         if (var->unit->pkg->type == PKG_INSTALLED) {
     832                 :         32 :                                 picosat_set_default_phase_lit(problem->sat, i + 1, -1);
     833                 :         32 :                                 picosat_set_less_important_lit(problem->sat, i + 1);
     834                 :         32 :                         }
     835                 :            :                         else {
     836                 :          4 :                                 picosat_set_default_phase_lit(problem->sat, i + 1, 1);
     837                 :          4 :                                 picosat_set_more_important_lit(problem->sat, i + 1);
     838                 :            :                         }
     839                 :            : 
     840                 :         36 :                         var->flags &= ~PKG_VAR_FAILED;
     841                 :         36 :                 }
     842                 :        723 :         }
     843                 :            : 
     844                 :        672 :         res = picosat_sat(problem->sat, -1);
     845                 :            : 
     846                 :        672 :         return (res);
     847                 :            : }
     848                 :            : 
     849                 :            : static void
     850                 :       1006 : pkg_solve_set_initial_assumption(struct pkg_solve_problem *problem,
     851                 :            :                 struct pkg_solve_rule *rule)
     852                 :            : {
     853                 :            :         struct pkg_job_universe_item *selected, *cur, *local, *first;
     854                 :            :         struct pkg_solve_item *item;
     855                 :            :         struct pkg_solve_variable *var, *cvar;
     856                 :       1006 :         bool conservative = false, prefer_local = false;
     857                 :       1006 :         const char *assumed_reponame = NULL;
     858                 :            : 
     859         [ +  + ]:       1006 :         if (problem->j->type == PKG_JOBS_INSTALL) {
     860                 :            :                 /* Avoid upgrades on INSTALL job */
     861                 :        229 :                 conservative = true;
     862                 :        229 :                 prefer_local = true;
     863                 :        229 :         }
     864                 :            :         else {
     865                 :        777 :                 conservative = pkg_object_bool(pkg_config_get("CONSERVATIVE_UPGRADE"));
     866                 :            :         }
     867                 :            : 
     868      [ +  +  + ]:       1006 :         switch (rule->reason) {
     869                 :            :         case PKG_RULE_DEPEND:
     870                 :            :                 /*
     871                 :            :                  * The first item is dependent item, the next items are
     872                 :            :                  * dependencies. We assume that all deps belong to a single
     873                 :            :                  * upgrade chain.
     874                 :            :                  */
     875         [ +  - ]:        444 :                 assert (rule->items != NULL);
     876                 :        444 :                 item = rule->items;
     877                 :        444 :                 var = item->var;
     878                 :        444 :                 assumed_reponame = var->assumed_reponame;
     879                 :            : 
     880                 :            :                 /* Check what we are depending on */
     881         [ +  + ]:        444 :                 if (!(var->flags & (PKG_VAR_TOP|PKG_VAR_ASSUMED_TRUE))) {
     882                 :            :                         /*
     883                 :            :                          * We are interested merely in dependencies of top variables
     884                 :            :                          * or of previously assumed dependencies
     885                 :            :                          */
     886                 :        188 :                         pkg_debug(4, "solver: not interested in dependencies for %s-%s",
     887                 :        188 :                                         var->unit->pkg->name, var->unit->pkg->version);
     888                 :        188 :                         return;
     889                 :            :                 }
     890                 :            :                 else {
     891                 :        256 :                         pkg_debug(4, "solver: examine dependencies for %s-%s",
     892                 :        256 :                                         var->unit->pkg->name, var->unit->pkg->version);
     893                 :            :                 }
     894                 :            : 
     895                 :            : 
     896                 :        256 :                 item = rule->items->next;
     897         [ -  + ]:        256 :                 assert (item != NULL);
     898                 :        256 :                 var = item->var;
     899                 :        256 :                 first = var->unit;
     900                 :            : 
     901                 :            :                 /* Rewind chains */
     902         [ -  + ]:        256 :                 while (first->prev->next != NULL) {
     903                 :          0 :                         first = first->prev;
     904                 :            :                 }
     905         [ -  + ]:        256 :                 while (var->prev->next != NULL) {
     906                 :          0 :                         var = var->prev;
     907                 :            :                 }
     908                 :            : 
     909         [ +  + ]:        480 :                 LL_FOREACH(var, cvar) {
     910         [ +  + ]:        300 :                         if (cvar->flags & PKG_VAR_ASSUMED) {
     911                 :            :                                 /* Do not reassume packages */
     912                 :         76 :                                 return;
     913                 :            :                         }
     914                 :        224 :                 }
     915                 :            :                 /* Forward chain to find local package */
     916                 :        180 :                 local = NULL;
     917                 :            : 
     918         [ +  + ]:        292 :                 DL_FOREACH (first, cur) {
     919         [ +  + ]:        180 :                         if (cur->pkg->type == PKG_INSTALLED) {
     920                 :         68 :                                 local = cur;
     921                 :         68 :                                 break;
     922                 :            :                         }
     923                 :        112 :                 }
     924                 :            : 
     925   [ +  +  +  + ]:        180 :                 if (prefer_local && local != NULL) {
     926                 :          4 :                         selected = local;
     927                 :          4 :                 }
     928                 :            :                 else {
     929                 :        352 :                         selected = pkg_jobs_universe_select_candidate(first, local,
     930                 :        176 :                             conservative, assumed_reponame, true);
     931                 :            : 
     932   [ +  +  -  +  :        176 :                         if (local && (strcmp(selected->pkg->digest, local->pkg->digest) == 0 ||
                   #  # ]
     933                 :          0 :                             !pkg_jobs_need_upgrade(selected->pkg, local->pkg))) {
     934                 :         64 :                                 selected = local;
     935                 :         64 :                         }
     936                 :            :                 }
     937                 :            : 
     938                 :            :                 /* Now we can find the according var */
     939         [ -  + ]:        180 :                 if (selected != NULL) {
     940                 :            : 
     941         [ +  + ]:        404 :                         LL_FOREACH(var, cvar) {
     942         [ +  + ]:        224 :                                 if (cvar->unit == selected) {
     943                 :        180 :                                         picosat_set_default_phase_lit(problem->sat, cvar->order, 1);
     944                 :        180 :                                         pkg_debug(4, "solver: assumed %s-%s(%s) to be installed",
     945                 :        180 :                                                         selected->pkg->name, selected->pkg->version,
     946                 :        180 :                                                         selected->pkg->type == PKG_INSTALLED ? "l" : "r");
     947                 :        180 :                                         cvar->flags |= PKG_VAR_ASSUMED_TRUE;
     948                 :        180 :                                 }
     949                 :            :                                 else {
     950                 :         44 :                                         pkg_debug(4, "solver: assumed %s-%s(%s) to be NOT installed",
     951                 :         44 :                                                         cvar->unit->pkg->name, cvar->unit->pkg->version,
     952                 :         44 :                                                         cvar->unit->pkg->type == PKG_INSTALLED ? "l" : "r");
     953                 :         44 :                                         picosat_set_default_phase_lit(problem->sat, cvar->order, -1);
     954                 :            :                                 }
     955                 :            : 
     956                 :        224 :                                 cvar->flags |= PKG_VAR_ASSUMED;
     957                 :        224 :                         }
     958                 :            : 
     959                 :        180 :                 }
     960                 :        180 :                 break;
     961                 :            :         case PKG_RULE_REQUIRE:
     962                 :            :                 /* XXX: deal with require rules somehow */
     963                 :         56 :                 break;
     964                 :            :         default:
     965                 :            :                 /* No nothing */
     966                 :        506 :                 return;
     967                 :            :         }
     968                 :       1006 : }
     969                 :            : 
     970                 :            : int
     971                 :        640 : pkg_solve_sat_problem(struct pkg_solve_problem *problem)
     972                 :            : {
     973                 :            :         struct pkg_solve_rule *rule;
     974                 :            :         struct pkg_solve_item *item;
     975                 :        640 :         int res, iter = 0;
     976                 :            :         size_t i;
     977                 :        640 :         bool need_reiterate = false;
     978                 :        640 :         const int *failed = NULL;
     979                 :        640 :         int attempt = 0;
     980                 :            :         struct pkg_solve_variable *var;
     981                 :            : 
     982         [ +  + ]:       1646 :         for (i = 0; i < kv_size(problem->rules); i++) {
     983                 :       1006 :                 rule = kv_A(problem->rules, i);
     984                 :            : 
     985         [ +  + ]:       3198 :                 LL_FOREACH(rule->items, item) {
     986                 :       2192 :                         picosat_add(problem->sat, item->var->order * item->inverse);
     987                 :       2192 :                 }
     988                 :            : 
     989                 :       1006 :                 picosat_add(problem->sat, 0);
     990                 :       1006 :                 pkg_debug_print_rule(rule);
     991                 :       1006 :         }
     992                 :            : 
     993         [ +  + ]:       1646 :         for (i = 0; i < kv_size(problem->rules); i++) {
     994                 :       1006 :                 rule = kv_A(problem->rules, i);
     995                 :       1006 :                 pkg_solve_set_initial_assumption(problem, rule);
     996                 :       1646 :         }
     997                 :            : 
     998                 :            : reiterate:
     999                 :            : 
    1000                 :        672 :         res = pkg_solve_picosat_iter(problem, iter);
    1001                 :            : 
    1002         [ +  + ]:        672 :         if (res != PICOSAT_SATISFIABLE) {
    1003                 :            :                 /*
    1004                 :            :                  * in case we cannot satisfy the problem it appears by
    1005                 :            :                  * experience that the culprit seems to always be the latest of
    1006                 :            :                  * listed in the failed assumptions.
    1007                 :            :                  * So try to remove them for the given problem.
    1008                 :            :                  * To avoid endless loop allow a maximum of 10 iterations no
    1009                 :            :                  * more
    1010                 :            :                  */
    1011                 :          8 :                 failed = picosat_failed_assumptions(problem->sat);
    1012                 :          8 :                 attempt++;
    1013                 :            : 
    1014                 :            :                 /* get the last failure */
    1015         [ +  + ]:         24 :                 while (*failed) {
    1016                 :         16 :                         failed++;
    1017                 :            :                 }
    1018                 :          8 :                 failed--;
    1019                 :            : 
    1020         [ -  + ]:          8 :                 if (attempt >= 10) {
    1021                 :          0 :                         pkg_emit_error("Cannot solve problem using SAT solver");
    1022                 :          0 :                         xstring *sb = xstring_new();
    1023                 :            : 
    1024         [ #  # ]:          0 :                         while (*failed) {
    1025                 :          0 :                                 var = &problem->variables[abs(*failed) - 1];
    1026         [ #  # ]:          0 :                                 for (i = 0; i < kv_size(problem->rules); i++) {
    1027                 :          0 :                                         rule = kv_A(problem->rules, i);
    1028                 :            : 
    1029         [ #  # ]:          0 :                                         if (rule->reason != PKG_RULE_DEPEND) {
    1030         [ #  # ]:          0 :                                                 LL_FOREACH(rule->items, item) {
    1031         [ #  # ]:          0 :                                                         if (item->var == var) {
    1032                 :          0 :                                                                 pkg_print_rule_buf(rule, sb);
    1033                 :          0 :                                                                 fputc('\n', sb->fp);
    1034                 :          0 :                                                                 break;
    1035                 :            :                                                         }
    1036                 :          0 :                                                 }
    1037                 :          0 :                                         }
    1038                 :          0 :                                 }
    1039                 :            : 
    1040                 :          0 :                                 fprintf(sb->fp, "cannot %s package %s, remove it from request? ",
    1041                 :          0 :                                                 var->flags & PKG_VAR_INSTALL ? "install" : "remove", var->uid);
    1042                 :            : 
    1043                 :          0 :                                 fflush(sb->fp);
    1044         [ #  # ]:          0 :                                 if (pkg_emit_query_yesno(true, sb->buf)) {
    1045                 :          0 :                                         var->flags |= PKG_VAR_FAILED;
    1046                 :          0 :                                 }
    1047                 :            : 
    1048                 :          0 :                                 failed++;
    1049                 :          0 :                                 need_reiterate = true;
    1050                 :            :                         }
    1051                 :          0 :                         xstring_free(sb);
    1052                 :          0 :                 } else {
    1053                 :          8 :                         pkg_emit_notice("Cannot solve problem using SAT solver, trying another plan");
    1054                 :          8 :                         var = &problem->variables[abs(*failed) - 1];
    1055                 :            : 
    1056                 :          8 :                         var->flags |= PKG_VAR_FAILED;
    1057                 :            : 
    1058                 :          8 :                         need_reiterate = true;
    1059                 :            :                 }
    1060                 :            : 
    1061                 :            : #if 0
    1062                 :            :                 failed = picosat_next_maximal_satisfiable_subset_of_assumptions(problem->sat);
    1063                 :            : 
    1064                 :            :                 while (*failed) {
    1065                 :            :                         struct pkg_solve_variable *var = &problem->variables[*failed - 1];
    1066                 :            : 
    1067                 :            :                         pkg_emit_notice("var: %s", var->uid);
    1068                 :            : 
    1069                 :            :                         failed ++;
    1070                 :            :                 }
    1071                 :            : 
    1072                 :            :                 return (EPKG_AGAIN);
    1073                 :            : #endif
    1074                 :          8 :         }
    1075                 :            :         else {
    1076                 :            : 
    1077                 :            :                 /* Assign vars */
    1078         [ +  + ]:       2099 :                 for (i = 0; i < problem->nvars; i ++) {
    1079                 :       1435 :                         int val = picosat_deref(problem->sat, i + 1);
    1080                 :       1435 :                         struct pkg_solve_variable *var = &problem->variables[i];
    1081                 :            : 
    1082         [ +  + ]:       1435 :                         if (val > 0)
    1083                 :        829 :                                 var->flags |= PKG_VAR_INSTALL;
    1084                 :            :                         else
    1085                 :        606 :                                 var->flags &= ~PKG_VAR_INSTALL;
    1086                 :            : 
    1087                 :       1435 :                         pkg_debug(2, "decided %s %s-%s to %s",
    1088                 :       1435 :                                         var->unit->pkg->type == PKG_INSTALLED ? "local" : "remote",
    1089                 :       1435 :                                                         var->uid, var->digest,
    1090                 :       1435 :                                                         var->flags & PKG_VAR_INSTALL ? "install" : "delete");
    1091                 :       1435 :                 }
    1092                 :            : 
    1093                 :            :                 /* Check for reiterations */
    1094   [ +  +  +  + ]:       1000 :                 if ((problem->j->type == PKG_JOBS_INSTALL ||
    1095                 :        664 :                                 problem->j->type == PKG_JOBS_UPGRADE) && iter == 0) {
    1096         [ +  + ]:       1585 :                         for (i = 0; i < problem->nvars; i ++) {
    1097                 :       1098 :                                 bool failed_var = false;
    1098                 :       1098 :                                 struct pkg_solve_variable *var = &problem->variables[i], *cur;
    1099                 :            : 
    1100         [ +  + ]:       1098 :                                 if (!(var->flags & PKG_VAR_INSTALL)) {
    1101         [ +  + ]:        714 :                                         LL_FOREACH(var, cur) {
    1102         [ +  + ]:        597 :                                                 if (cur->flags & PKG_VAR_INSTALL) {
    1103                 :        236 :                                                         failed_var = false;
    1104                 :        236 :                                                         break;
    1105                 :            :                                                 }
    1106         [ +  + ]:        361 :                                                 else if (cur->unit->pkg->type == PKG_INSTALLED) {
    1107                 :        264 :                                                         failed_var = true;
    1108                 :        264 :                                                 }
    1109                 :        361 :                                         }
    1110                 :        353 :                                 }
    1111                 :            : 
    1112                 :            :                                 /*
    1113                 :            :                                  * If we want to delete local packages on installation, do one more SAT
    1114                 :            :                                  * iteration to ensure that we have no other choices
    1115                 :            :                                  */
    1116         [ +  + ]:       1098 :                                 if (failed_var) {
    1117                 :         32 :                                         pkg_debug (1, "trying to delete local package %s-%s on install/upgrade,"
    1118                 :            :                                                         " reiterate on SAT",
    1119                 :         32 :                                                         var->unit->pkg->name, var->unit->pkg->version);
    1120                 :         32 :                                         need_reiterate = true;
    1121                 :            : 
    1122         [ +  + ]:         68 :                                         LL_FOREACH(var, cur) {
    1123                 :         36 :                                                 cur->flags |= PKG_VAR_FAILED;
    1124                 :         36 :                                         }
    1125                 :         32 :                                 }
    1126                 :       1098 :                         }
    1127                 :        487 :                 }
    1128                 :            :         }
    1129                 :            : 
    1130         [ +  + ]:        672 :         if (need_reiterate) {
    1131                 :         32 :                 iter ++;
    1132                 :            : 
    1133                 :            :                 /* Restore top-level assumptions */
    1134         [ +  + ]:        220 :                 for (i = 0; i < problem->nvars; i ++) {
    1135                 :        188 :                         struct pkg_solve_variable *var = &problem->variables[i];
    1136                 :            : 
    1137         [ +  + ]:        188 :                         if (var->flags & PKG_VAR_TOP) {
    1138         [ +  + ]:         60 :                                 if (var->flags & PKG_VAR_FAILED) {
    1139                 :          8 :                                         var->flags ^= PKG_VAR_INSTALL | PKG_VAR_FAILED;
    1140                 :          8 :                                 }
    1141                 :            : 
    1142                 :        120 :                                 picosat_assume(problem->sat, var->order *
    1143                 :         60 :                                                 (var->flags & PKG_VAR_INSTALL ? 1 : -1));
    1144                 :         60 :                         }
    1145                 :        188 :                 }
    1146                 :            : 
    1147                 :         32 :                 need_reiterate = false;
    1148                 :            : 
    1149                 :         32 :                 goto reiterate;
    1150                 :            :         }
    1151                 :            : 
    1152                 :        640 :         return (EPKG_OK);
    1153                 :            : }
    1154                 :            : 
    1155                 :            : void
    1156                 :          0 : pkg_solve_dot_export(struct pkg_solve_problem *problem, FILE *file)
    1157                 :            : {
    1158                 :            :         struct pkg_solve_rule *rule;
    1159                 :            :         size_t i;
    1160                 :            : 
    1161                 :          0 :         fprintf(file, "digraph {\n");
    1162                 :            : 
    1163         [ #  # ]:          0 :         for (i = 0; i < problem->nvars; i ++) {
    1164                 :          0 :                 struct pkg_solve_variable *var = &problem->variables[i];
    1165                 :            : 
    1166                 :          0 :                 fprintf(file, "\tp%d [shape=%s label=\"%s-%s\"]\n", var->order,
    1167                 :          0 :                                 var->unit->pkg->type == PKG_INSTALLED ? "ellipse" : "octagon",
    1168                 :          0 :                                 var->uid, var->unit->pkg->version);
    1169                 :          0 :         }
    1170                 :            : 
    1171                 :            :         /* Print all variables as nodes */
    1172                 :            : 
    1173         [ #  # ]:          0 :         for (i = 0; i < kv_size(problem->rules); i++) {
    1174                 :          0 :                 rule = kv_A(problem->rules, i);
    1175                 :          0 :                 struct pkg_solve_item *it = rule->items, *key_elt = NULL;
    1176                 :            : 
    1177   [ #  #  #  # ]:          0 :                 switch(rule->reason) {
    1178                 :            :                 case PKG_RULE_DEPEND:
    1179         [ #  # ]:          0 :                         LL_FOREACH(rule->items, it) {
    1180         [ #  # ]:          0 :                                 if (it->inverse == -1) {
    1181                 :          0 :                                         key_elt = it;
    1182                 :          0 :                                         break;
    1183                 :            :                                 }
    1184                 :          0 :                         }
    1185         [ #  # ]:          0 :                         assert (key_elt != NULL);
    1186                 :            : 
    1187         [ #  # ]:          0 :                         LL_FOREACH(rule->items, it) {
    1188         [ #  # ]:          0 :                                 if (it != key_elt) {
    1189                 :          0 :                                         fprintf(file, "\tp%d -> p%d;\n", key_elt->var->order,
    1190                 :          0 :                                                         it->var->order);
    1191                 :          0 :                                 }
    1192                 :          0 :                         }
    1193                 :          0 :                         break;
    1194                 :            :                 case PKG_RULE_UPGRADE_CONFLICT:
    1195                 :            :                 case PKG_RULE_EXPLICIT_CONFLICT:
    1196                 :            :                 case PKG_RULE_REQUEST_CONFLICT:
    1197                 :          0 :                         fprintf(file, "\tp%d -> p%d [arrowhead=none,color=red];\n",
    1198                 :          0 :                                         it->var->order, it->next->var->order);
    1199                 :          0 :                         break;
    1200                 :            :                 case PKG_RULE_REQUIRE:
    1201         [ #  # ]:          0 :                         LL_FOREACH(rule->items, it) {
    1202         [ #  # ]:          0 :                                 if (it->inverse == -1) {
    1203                 :          0 :                                         key_elt = it;
    1204                 :          0 :                                         break;
    1205                 :            :                                 }
    1206                 :          0 :                         }
    1207         [ #  # ]:          0 :                         assert (key_elt != NULL);
    1208                 :            : 
    1209         [ #  # ]:          0 :                         LL_FOREACH(rule->items, it) {
    1210         [ #  # ]:          0 :                                 if (it != key_elt) {
    1211                 :          0 :                                         fprintf(file, "\tp%d -> p%d[arrowhead=diamond];\n", key_elt->var->order,
    1212                 :          0 :                                                         it->var->order);
    1213                 :          0 :                                 }
    1214                 :          0 :                         }
    1215                 :          0 :                         break;
    1216                 :            :                 default:
    1217                 :          0 :                         break;
    1218                 :            :                 }
    1219                 :          0 :         }
    1220                 :            : 
    1221                 :          0 :         fprintf(file, "}\n");
    1222                 :          0 : }
    1223                 :            : 
    1224                 :            : int
    1225                 :          0 : pkg_solve_dimacs_export(struct pkg_solve_problem *problem, FILE *f)
    1226                 :            : {
    1227                 :            :         struct pkg_solve_rule *rule;
    1228                 :            :         struct pkg_solve_item *it;
    1229                 :            : 
    1230                 :          0 :         fprintf(f, "p cnf %d %zu\n", (int)problem->nvars, kv_size(problem->rules));
    1231                 :            : 
    1232         [ #  # ]:          0 :         for (unsigned int i = 0; i < kv_size(problem->rules); i++) {
    1233                 :          0 :                 rule = kv_A(problem->rules, i);
    1234         [ #  # ]:          0 :                 LL_FOREACH(rule->items, it) {
    1235                 :          0 :                         size_t order = it->var - problem->variables;
    1236         [ #  # ]:          0 :                         if (order < problem->nvars)
    1237                 :          0 :                                 fprintf(f, "%ld ", (long)((order + 1) * it->inverse));
    1238                 :          0 :                 }
    1239                 :          0 :                 fprintf(f, "0\n");
    1240                 :          0 :         }
    1241                 :          0 :         return (EPKG_OK);
    1242                 :            : }
    1243                 :            : 
    1244                 :            : static void
    1245                 :        954 : pkg_solve_insert_res_job (struct pkg_solve_variable *var,
    1246                 :            :                 struct pkg_solve_problem *problem)
    1247                 :            : {
    1248                 :            :         struct pkg_solved *res;
    1249                 :        954 :         struct pkg_solve_variable *cur_var, *del_var = NULL, *add_var = NULL;
    1250                 :        954 :         int seen_add = 0, seen_del = 0;
    1251                 :        954 :         struct pkg_jobs *j = problem->j;
    1252                 :            : 
    1253         [ +  + ]:       2245 :         LL_FOREACH(var, cur_var) {
    1254   [ +  +  +  + ]:       1291 :                 if ((cur_var->flags & PKG_VAR_INSTALL) &&
    1255                 :        765 :                                 cur_var->unit->pkg->type != PKG_INSTALLED) {
    1256                 :        691 :                         add_var = cur_var;
    1257                 :        691 :                         seen_add ++;
    1258                 :        691 :                 }
    1259         [ +  + ]:        600 :                 else if (!(cur_var->flags & PKG_VAR_INSTALL)
    1260         [ +  + ]:        600 :                                 && cur_var->unit->pkg->type == PKG_INSTALLED) {
    1261                 :        433 :                         del_var = cur_var;
    1262                 :        433 :                         seen_del ++;
    1263                 :        433 :                 }
    1264                 :       1291 :         }
    1265                 :            : 
    1266         [ -  + ]:        954 :         if (seen_add > 1) {
    1267                 :          0 :                 pkg_emit_error("internal solver error: more than two packages to install(%d) "
    1268                 :          0 :                                 "from the same uid: %s", seen_add, var->uid);
    1269                 :          0 :                 return;
    1270                 :            :         }
    1271   [ +  +  +  + ]:        954 :         else if (seen_add != 0 || seen_del != 0) {
    1272         [ +  + ]:        880 :                 if (seen_add > 0) {
    1273                 :        691 :                         res = xcalloc(1, sizeof(struct pkg_solved));
    1274                 :            :                         /* Pure install */
    1275         [ +  + ]:        691 :                         if (seen_del == 0) {
    1276                 :        447 :                                 res->items[0] = add_var->unit;
    1277                 :        447 :                                 res->type = (j->type == PKG_JOBS_FETCH) ?
    1278                 :            :                                                                 PKG_SOLVED_FETCH : PKG_SOLVED_INSTALL;
    1279         [ +  + ]:        447 :                                 DL_APPEND(j->jobs, res);
    1280                 :        447 :                                 pkg_debug(3, "pkg_solve: schedule installation of %s %s",
    1281                 :        447 :                                         add_var->uid, add_var->digest);
    1282                 :        447 :                         }
    1283                 :            :                         else {
    1284                 :            :                                 /* Upgrade */
    1285                 :        244 :                                 res->items[0] = add_var->unit;
    1286                 :        244 :                                 res->items[1] = del_var->unit;
    1287                 :        244 :                                 res->type = PKG_SOLVED_UPGRADE;
    1288         [ +  + ]:        244 :                                 DL_APPEND(j->jobs, res);
    1289                 :        244 :                                 pkg_debug(3, "pkg_solve: schedule upgrade of %s from %s to %s",
    1290                 :        244 :                                         del_var->uid, del_var->digest, add_var->digest);
    1291                 :            :                         }
    1292                 :        691 :                         j->count ++;
    1293                 :        691 :                 }
    1294                 :            : 
    1295                 :            :                 /*
    1296                 :            :                  * For delete requests there could be multiple delete requests per UID,
    1297                 :            :                  * so we need to re-process vars and add all delete jobs required.
    1298                 :            :                  */
    1299         [ +  + ]:       2089 :                 LL_FOREACH(var, cur_var) {
    1300   [ +  +  +  + ]:       1209 :                         if (!(cur_var->flags & PKG_VAR_INSTALL) &&
    1301                 :        518 :                                         cur_var->unit->pkg->type == PKG_INSTALLED) {
    1302                 :            :                                 /* Skip already added items */
    1303   [ +  +  -  + ]:        433 :                                 if (seen_add > 0 && cur_var == del_var)
    1304                 :        244 :                                         continue;
    1305                 :            : 
    1306                 :        189 :                                 res = xcalloc(1, sizeof(struct pkg_solved));
    1307                 :        189 :                                 res->items[0] = cur_var->unit;
    1308                 :        189 :                                 res->type = PKG_SOLVED_DELETE;
    1309         [ +  + ]:        189 :                                 DL_APPEND(j->jobs, res);
    1310                 :        189 :                                 pkg_debug(3, "pkg_solve: schedule deletion of %s %s",
    1311                 :        189 :                                         cur_var->uid, cur_var->digest);
    1312                 :        189 :                                 j->count ++;
    1313                 :        189 :                         }
    1314                 :        965 :                 }
    1315                 :        880 :         }
    1316                 :            :         else {
    1317                 :         74 :                 pkg_debug(2, "solver: ignoring package %s(%s) as its state has not been changed",
    1318                 :         74 :                                 var->uid, var->digest);
    1319                 :            :         }
    1320                 :        954 : }
    1321                 :            : 
    1322                 :            : int
    1323                 :        640 : pkg_solve_sat_to_jobs(struct pkg_solve_problem *problem)
    1324                 :            : {
    1325                 :            :         struct pkg_solve_variable *var;
    1326                 :        640 :         pkghash_it it = pkghash_iterator(problem->variables_by_uid);
    1327                 :            : 
    1328         [ +  + ]:       1594 :         while (pkghash_next(&it)) {
    1329                 :        954 :                 var = (struct pkg_solve_variable *)it.value;
    1330                 :        954 :                 pkg_debug(4, "solver: check variable with uid %s", var->uid);
    1331                 :        954 :                 pkg_solve_insert_res_job(var, problem);
    1332                 :            :         }
    1333                 :            : 
    1334                 :        640 :         return (EPKG_OK);
    1335                 :            : }
    1336                 :            : 
    1337                 :            : static bool
    1338                 :          0 : pkg_solve_parse_sat_output_store(struct pkg_solve_problem *problem, const char *var_str)
    1339                 :            : {
    1340                 :            :         struct pkg_solve_variable *var;
    1341                 :            :         ssize_t order;
    1342                 :            : 
    1343                 :          0 :         order = strtol(var_str, NULL, 10);
    1344         [ #  # ]:          0 :         if (order == 0)
    1345                 :          0 :                 return (true);
    1346         [ #  # ]:          0 :         if (order < 0) {
    1347                 :            :                 /* negative value means false */
    1348                 :          0 :                 order = - order - 1;
    1349         [ #  # ]:          0 :                 if ((size_t)order < problem->nvars) {
    1350                 :          0 :                         var = problem->variables + order;
    1351                 :          0 :                         var->flags &= ~PKG_VAR_INSTALL;
    1352                 :          0 :                 }
    1353                 :          0 :         } else {
    1354                 :            :                 /* positive value means true */
    1355                 :          0 :                 order = order - 1;
    1356         [ #  # ]:          0 :                 if ((size_t)order < problem->nvars) {
    1357                 :          0 :                         var = problem->variables + order;
    1358                 :          0 :                         var->flags |= PKG_VAR_INSTALL;
    1359                 :          0 :                 }
    1360                 :            :         }
    1361                 :          0 :         return (false);
    1362                 :          0 : }
    1363                 :            : 
    1364                 :            : int
    1365                 :          0 : pkg_solve_parse_sat_output(FILE *f, struct pkg_solve_problem *problem)
    1366                 :            : {
    1367                 :          0 :         int ret = EPKG_OK;
    1368                 :          0 :         char *line = NULL, *var_str, *begin;
    1369                 :          0 :         size_t linecap = 0;
    1370                 :          0 :         bool got_sat = false, done = false;
    1371                 :            : 
    1372         [ #  # ]:          0 :         while (getline(&line, &linecap, f) > 0) {
    1373         [ #  # ]:          0 :                 if (strncmp(line, "SAT", 3) == 0) {
    1374                 :          0 :                         got_sat = true;
    1375                 :          0 :                 }
    1376         [ #  # ]:          0 :                 else if (got_sat) {
    1377                 :          0 :                         begin = line;
    1378                 :          0 :                         do {
    1379                 :          0 :                                 var_str = strsep(&begin, " \t");
    1380                 :            :                                 /* Skip unexpected lines */
    1381   [ #  #  #  #  :          0 :                                 if (var_str == NULL || (!isdigit(*var_str) && *var_str != '-'))
                   #  # ]
    1382                 :          0 :                                         continue;
    1383         [ #  # ]:          0 :                                 if (pkg_solve_parse_sat_output_store(problem, var_str))
    1384                 :          0 :                                         done = true;
    1385         [ #  # ]:          0 :                         } while (begin != NULL);
    1386                 :          0 :                 }
    1387         [ #  # ]:          0 :                 else if (strncmp(line, "v ", 2) == 0) {
    1388                 :          0 :                         begin = line + 2;
    1389                 :          0 :                         do {
    1390                 :          0 :                                 var_str = strsep(&begin, " \t");
    1391                 :            :                                 /* Skip unexpected lines */
    1392   [ #  #  #  #  :          0 :                                 if (var_str == NULL || (!isdigit(*var_str) && *var_str != '-'))
                   #  # ]
    1393                 :          0 :                                         continue;
    1394         [ #  # ]:          0 :                                 if (pkg_solve_parse_sat_output_store(problem, var_str))
    1395                 :          0 :                                         done = true;
    1396         [ #  # ]:          0 :                         } while (begin != NULL);
    1397                 :          0 :                 }
    1398                 :            :                 else {
    1399                 :            :                         /* Slightly ignore anything from solver */
    1400                 :          0 :                         continue;
    1401                 :            :                 }
    1402                 :            :         }
    1403                 :            : 
    1404         [ #  # ]:          0 :         if (done)
    1405                 :          0 :                 ret = pkg_solve_sat_to_jobs(problem);
    1406                 :            :         else {
    1407                 :          0 :                 pkg_emit_error("cannot parse sat solver output");
    1408                 :          0 :                 ret = EPKG_FATAL;
    1409                 :            :         }
    1410                 :            : 
    1411                 :          0 :         free(line);
    1412                 :            : 
    1413                 :          0 :         return (ret);
    1414                 :            : }

Generated by: LCOV version 1.15