コード例 #1
0
ファイル: enquiry.c プロジェクト: Felllini/sprezzos-world
/**
 * Print a single package which:
 *  (a) is the target of one or more relevant predependencies.
 *  (b) has itself no unsatisfied pre-dependencies.
 *
 * If such a package is present output is the Packages file entry,
 * which can be massaged as appropriate.
 *
 * Exit status:
 *  0 = a package printed, OK
 *  1 = no suitable package available
 *  2 = error
 */
int
predeppackage(const char *const *argv)
{
  static struct varbuf vb;

  struct pkgiterator *it;
  struct pkginfo *pkg = NULL, *startpkg, *trypkg;
  struct dependency *dep;
  struct deppossi *possi, *provider;

  if (*argv)
    badusage(_("--%s takes no arguments"), cipaction->olong);

  modstatdb_open(msdbrw_readonly | msdbrw_available_readonly);
  /* We use clientdata->istobe to detect loops. */
  clear_istobes();

  dep = NULL;
  it = pkg_db_iter_new();
  while (!dep && (pkg = pkg_db_iter_next_pkg(it))) {
    /* Ignore packages user doesn't want. */
    if (pkg->want != want_install)
      continue;
    /* Ignore packages not available. */
    if (!pkg->files)
      continue;
    pkg->clientdata->istobe= itb_preinstall;
    for (dep= pkg->available.depends; dep; dep= dep->next) {
      if (dep->type != dep_predepends) continue;
      if (depisok(dep, &vb, NULL, NULL, true))
        continue;
      /* This will leave dep non-NULL, and so exit the loop. */
      break;
    }
    pkg->clientdata->istobe= itb_normal;
    /* If dep is NULL we go and get the next package. */
  }
  pkg_db_iter_free(it);

  if (!dep)
    return 1; /* Not found. */
  assert(pkg);
  startpkg= pkg;
  pkg->clientdata->istobe= itb_preinstall;

  /* OK, we have found an unsatisfied predependency.
   * Now go and find the first thing we need to install, as a first step
   * towards satisfying it. */
  do {
    /* We search for a package which would satisfy dep, and put it in pkg. */
    for (possi = dep->list, pkg = NULL;
         !pkg && possi;
         possi=possi->next) {
      struct deppossi_pkg_iterator *possi_iter;

      possi_iter = deppossi_pkg_iter_new(possi, wpb_available);
      while (!pkg && (trypkg = deppossi_pkg_iter_next(possi_iter))) {
        if (trypkg->files && trypkg->clientdata->istobe == itb_normal &&
            versionsatisfied(&trypkg->available, possi)) {
          pkg = trypkg;
          break;
        }
        if (possi->verrel != dpkg_relation_none)
          continue;
        for (provider = possi->ed->depended.available;
             !pkg && provider;
             provider = provider->next) {
          if (provider->up->type != dep_provides)
            continue;
          trypkg = provider->up->up;
          if (!trypkg->files)
            continue;
          if (trypkg->clientdata->istobe == itb_normal) {
            pkg = trypkg;
            break;
          }
        }
      }
      deppossi_pkg_iter_free(possi_iter);
    }
    if (!pkg) {
      varbuf_reset(&vb);
      describedepcon(&vb,dep);
      varbuf_end_str(&vb);
      notice(_("cannot see how to satisfy pre-dependency:\n %s"), vb.buf);
      ohshit(_("cannot satisfy pre-dependencies for %.250s (wanted due to %.250s)"),
             pkgbin_name(dep->up, &dep->up->available, pnaw_nonambig),
             pkgbin_name(startpkg, &startpkg->available, pnaw_nonambig));
    }
    pkg->clientdata->istobe= itb_preinstall;
    for (dep= pkg->available.depends; dep; dep= dep->next) {
      if (dep->type != dep_predepends) continue;
      if (depisok(dep, &vb, NULL, NULL, true))
        continue;
      /* This will leave dep non-NULL, and so exit the loop. */
      break;
    }
  } while (dep);

  /* OK, we've found it - pkg has no unsatisfied pre-dependencies! */
  writerecord(stdout, _("<standard output>"), pkg, &pkg->available);

  m_output(stdout, _("<standard output>"));

  return 0;
}
コード例 #2
0
ファイル: depcon.c プロジェクト: Felllini/sprezzos-world
/*
 * *whynot must already have been initialized; it need not be
 * empty though - it will be reset before use.
 *
 * If depisok returns false for ‘not OK’ it will contain a description,
 * newline-terminated BUT NOT NUL-TERMINATED, of the reason.
 *
 * If depisok returns true it will contain garbage.
 * allowunconfigd should be non-zero during the ‘Pre-Depends’ checking
 * before a package is unpacked, when it is sufficient for the package
 * to be unpacked provided that both the unpacked and previously-configured
 * versions are acceptable.
 *
 * On false return (‘not OK’), *canfixbyremove refers to a package which
 * if removed (dep_conflicts) or deconfigured (dep_breaks) will fix
 * the problem. Caller may pass NULL for canfixbyremove and need not
 * initialize *canfixbyremove.
 *
 * On false return (‘not OK’), *canfixbytrigaw refers to a package which
 * can fix the problem if all the packages listed in Triggers-Awaited have
 * their triggers processed. Caller may pass NULL for canfixbytrigaw and
 * need not initialize *canfixbytrigaw.
 */
bool
depisok(struct dependency *dep, struct varbuf *whynot,
        struct pkginfo **canfixbyremove, struct pkginfo **canfixbytrigaw,
        bool allowunconfigd)
{
  struct deppossi *possi;
  struct deppossi *provider;
  struct pkginfo *pkg_pos;
  int nconflicts;

  /* Use this buffer so that when internationalisation comes along we
   * don't have to rewrite the code completely, only redo the sprintf strings
   * (assuming we have the fancy argument-number-specifiers).
   * Allow 250x3 for package names, versions, &c, + 250 for ourselves. */
  char linebuf[1024];

  assert(dep->type == dep_depends || dep->type == dep_predepends ||
	 dep->type == dep_breaks || dep->type == dep_conflicts ||
	 dep->type == dep_recommends || dep->type == dep_suggests ||
	 dep->type == dep_enhances);

  if (canfixbyremove)
    *canfixbyremove = NULL;
  if (canfixbytrigaw)
    *canfixbytrigaw = NULL;

  /* The dependency is always OK if we're trying to remove the depend*ing*
   * package. */
  switch (dep->up->clientdata->istobe) {
  case itb_remove: case itb_deconfigure:
    return true;
  case itb_normal:
    /* Only installed packages can be make dependency problems. */
    switch (dep->up->status) {
    case stat_installed:
    case stat_triggerspending:
    case stat_triggersawaited:
      break;
    case stat_notinstalled: case stat_configfiles: case stat_halfinstalled:
    case stat_halfconfigured: case stat_unpacked:
      return true;
    default:
      internerr("unknown status depending '%d'", dep->up->status);
    }
    break;
  case itb_installnew: case itb_preinstall:
    break;
  default:
    internerr("unknown istobe depending '%d'", dep->up->clientdata->istobe);
  }

  /* Describe the dependency, in case we have to moan about it. */
  varbuf_reset(whynot);
  varbuf_add_char(whynot, ' ');
  describedepcon(whynot, dep);
  varbuf_add_char(whynot, '\n');

  /* TODO: Check dep_enhances as well. */
  if (dep->type == dep_depends || dep->type == dep_predepends ||
      dep->type == dep_recommends || dep->type == dep_suggests ) {
    /* Go through the alternatives. As soon as we find one that
     * we like, we return ‘true’ straight away. Otherwise, when we get to
     * the end we'll have accumulated all the reasons in whynot and
     * can return ‘false’. */

    for (possi= dep->list; possi; possi= possi->next) {
      struct deppossi_pkg_iterator *possi_iter;

      possi_iter = deppossi_pkg_iter_new(possi, wpb_by_istobe);
      while ((pkg_pos = deppossi_pkg_iter_next(possi_iter))) {
        switch (pkg_pos->clientdata->istobe) {
        case itb_remove:
          sprintf(linebuf, _("  %.250s is to be removed.\n"),
                  pkg_name(pkg_pos, pnaw_nonambig));
          break;
        case itb_deconfigure:
          sprintf(linebuf, _("  %.250s is to be deconfigured.\n"),
                  pkg_name(pkg_pos, pnaw_nonambig));
          break;
        case itb_installnew:
          if (versionsatisfied(&pkg_pos->available, possi)) {
            deppossi_pkg_iter_free(possi_iter);
            return true;
          }
          sprintf(linebuf, _("  %.250s is to be installed, but is version "
                             "%.250s.\n"),
                  pkgbin_name(pkg_pos, &pkg_pos->available, pnaw_nonambig),
                  versiondescribe(&pkg_pos->available.version, vdew_nonambig));
          break;
        case itb_normal:
        case itb_preinstall:
          switch (pkg_pos->status) {
          case stat_installed:
          case stat_triggerspending:
            if (versionsatisfied(&pkg_pos->installed, possi)) {
              deppossi_pkg_iter_free(possi_iter);
              return true;
            }
            sprintf(linebuf, _("  %.250s is installed, but is version "
                               "%.250s.\n"),
                    pkg_name(pkg_pos, pnaw_nonambig),
                    versiondescribe(&pkg_pos->installed.version, vdew_nonambig));
            break;
          case stat_notinstalled:
            /* Don't say anything about this yet - it might be a virtual package.
             * Later on, if nothing has put anything in linebuf, we know that it
             * isn't and issue a diagnostic then. */
            *linebuf = '\0';
            break;
          case stat_triggersawaited:
              if (canfixbytrigaw && versionsatisfied(&pkg_pos->installed, possi))
                *canfixbytrigaw = pkg_pos;
              /* Fall through to have a chance to return OK due to
               * allowunconfigd and to fill the explanation */
          case stat_unpacked:
          case stat_halfconfigured:
            if (allowunconfigd) {
              if (!dpkg_version_is_informative(&pkg_pos->configversion)) {
                sprintf(linebuf, _("  %.250s is unpacked, but has never been "
                                   "configured.\n"),
                        pkg_name(pkg_pos, pnaw_nonambig));
                break;
              } else if (!versionsatisfied(&pkg_pos->installed, possi)) {
                sprintf(linebuf, _("  %.250s is unpacked, but is version "
                                   "%.250s.\n"),
                        pkg_name(pkg_pos, pnaw_nonambig),
                        versiondescribe(&pkg_pos->installed.version,
                                        vdew_nonambig));
                break;
              } else if (!dpkg_version_relate(&pkg_pos->configversion,
                                              possi->verrel,
                                              &possi->version)) {
                sprintf(linebuf, _("  %.250s latest configured version is "
                                   "%.250s.\n"),
                        pkg_name(pkg_pos, pnaw_nonambig),
                        versiondescribe(&pkg_pos->configversion, vdew_nonambig));
                break;
              } else {
                deppossi_pkg_iter_free(possi_iter);
                return true;
              }
            }
            /* Fall through. */
          default:
            sprintf(linebuf, _("  %.250s is %s.\n"),
                    pkg_name(pkg_pos, pnaw_nonambig),
                    gettext(statusstrings[pkg_pos->status]));
            break;
          }
          break;
        default:
          internerr("unknown istobe depended '%d'", pkg_pos->clientdata->istobe);
        }
        varbuf_add_str(whynot, linebuf);
      }
      deppossi_pkg_iter_free(possi_iter);

      /* If there was no version specified we try looking for Providers. */
      if (possi->verrel == dpkg_relation_none) {
        /* See if the package we're about to install Provides it. */
        for (provider = possi->ed->depended.available;
             provider;
             provider = provider->rev_next) {
          if (provider->up->type != dep_provides) continue;
          if (provider->up->up->clientdata->istobe == itb_installnew)
            return true;
        }

        /* Now look at the packages already on the system. */
        for (provider = possi->ed->depended.installed;
             provider;
             provider = provider->rev_next) {
          if (provider->up->type != dep_provides) continue;

          switch (provider->up->up->clientdata->istobe) {
          case itb_installnew:
            /* Don't pay any attention to the Provides field of the
             * currently-installed version of the package we're trying
             * to install. We dealt with that by using the available
             * information above. */
            continue;
          case itb_remove:
            sprintf(linebuf, _("  %.250s provides %.250s but is to be removed.\n"),
                    pkg_name(provider->up->up, pnaw_nonambig),
                    possi->ed->name);
            break;
          case itb_deconfigure:
            sprintf(linebuf, _("  %.250s provides %.250s but is to be deconfigured.\n"),
                    pkg_name(provider->up->up, pnaw_nonambig),
                    possi->ed->name);
            break;
          case itb_normal: case itb_preinstall:
            if (provider->up->up->status == stat_installed ||
                provider->up->up->status == stat_triggerspending)
              return true;
            if (provider->up->up->status == stat_triggersawaited)
              *canfixbytrigaw = provider->up->up;
            sprintf(linebuf, _("  %.250s provides %.250s but is %s.\n"),
                    pkg_name(provider->up->up, pnaw_nonambig),
                    possi->ed->name,
                    gettext(statusstrings[provider->up->up->status]));
            break;
          default:
            internerr("unknown istobe provider '%d'",
                      provider->up->up->clientdata->istobe);
          }
          varbuf_add_str(whynot, linebuf);
        }

        if (!*linebuf) {
          /* If the package wasn't installed at all, and we haven't said
           * yet why this isn't satisfied, we should say so now. */
          sprintf(linebuf, _("  %.250s is not installed.\n"), possi->ed->name);
          varbuf_add_str(whynot, linebuf);
        }
      }
    }

    return false;
  } else {
    /* It's conflicts or breaks. There's only one main alternative,
     * but we also have to consider Providers. We return ‘false’ as soon
     * as we find something that matches the conflict, and only describe
     * it then. If we get to the end without finding anything we return
     * ‘true’. */

    possi= dep->list;
    nconflicts= 0;

    if (possi->ed != possi->up->up->set) {
      struct deppossi_pkg_iterator *possi_iter;

      /* If the package conflicts with or breaks itself it must mean
       * other packages which provide the same virtual name. We
       * therefore don't look at the real package and go on to the
       * virtual ones. */

      possi_iter = deppossi_pkg_iter_new(possi, wpb_by_istobe);
      while ((pkg_pos = deppossi_pkg_iter_next(possi_iter))) {
        switch (pkg_pos->clientdata->istobe) {
        case itb_remove:
          break;
        case itb_installnew:
          if (!versionsatisfied(&pkg_pos->available, possi))
            break;
          sprintf(linebuf, _("  %.250s (version %.250s) is to be installed.\n"),
                  pkgbin_name(pkg_pos, &pkg_pos->available, pnaw_nonambig),
                  versiondescribe(&pkg_pos->available.version, vdew_nonambig));
          varbuf_add_str(whynot, linebuf);
          if (!canfixbyremove) {
            deppossi_pkg_iter_free(possi_iter);
            return false;
          }
          nconflicts++;
          *canfixbyremove = pkg_pos;
          break;
        case itb_deconfigure:
          if (dep->type == dep_breaks)
            break; /* Already deconfiguring this. */
          /* Fall through. */
        case itb_normal:
        case itb_preinstall:
          switch (pkg_pos->status) {
          case stat_notinstalled:
          case stat_configfiles:
            break;
          case stat_halfinstalled:
          case stat_unpacked:
          case stat_halfconfigured:
            if (dep->type == dep_breaks)
              break; /* No problem. */
          case stat_installed:
          case stat_triggerspending:
          case stat_triggersawaited:
            if (!versionsatisfied(&pkg_pos->installed, possi))
              break;
            sprintf(linebuf, _("  %.250s (version %.250s) is present and %s.\n"),
                    pkg_name(pkg_pos, pnaw_nonambig),
                    versiondescribe(&pkg_pos->installed.version, vdew_nonambig),
                    gettext(statusstrings[pkg_pos->status]));
            varbuf_add_str(whynot, linebuf);
            if (!canfixbyremove) {
              deppossi_pkg_iter_free(possi_iter);
              return false;
            }
            nconflicts++;
            *canfixbyremove = pkg_pos;
          }
          break;
        default:
          internerr("unknown istobe conflict '%d'", pkg_pos->clientdata->istobe);
        }
      }
      deppossi_pkg_iter_free(possi_iter);
    }

    /* If there was no version specified we try looking for Providers. */
    if (possi->verrel == dpkg_relation_none) {
      /* See if the package we're about to install Provides it. */
      for (provider = possi->ed->depended.available;
           provider;
           provider = provider->rev_next) {
        if (provider->up->type != dep_provides) continue;
        if (provider->up->up->clientdata->istobe != itb_installnew) continue;
        if (provider->up->up->set == dep->up->set)
          continue; /* Conflicts and provides the same. */
        sprintf(linebuf, _("  %.250s provides %.250s and is to be installed.\n"),
                pkgbin_name(provider->up->up, &provider->up->up->available,
                            pnaw_nonambig), possi->ed->name);
        varbuf_add_str(whynot, linebuf);
        /* We can't remove the one we're about to install: */
        if (canfixbyremove)
          *canfixbyremove = NULL;
        return false;
      }

      /* Now look at the packages already on the system. */
      for (provider = possi->ed->depended.installed;
           provider;
           provider = provider->rev_next) {
        if (provider->up->type != dep_provides) continue;

        if (provider->up->up->set == dep->up->set)
          continue; /* Conflicts and provides the same. */

        switch (provider->up->up->clientdata->istobe) {
        case itb_installnew:
          /* Don't pay any attention to the Provides field of the
           * currently-installed version of the package we're trying
           * to install. We dealt with that package by using the
           * available information above. */
          continue;
        case itb_remove:
          continue;
        case itb_deconfigure:
          if (dep->type == dep_breaks)
            continue; /* Already deconfiguring. */
        case itb_normal: case itb_preinstall:
          switch (provider->up->up->status) {
          case stat_notinstalled: case stat_configfiles:
            continue;
          case stat_halfinstalled: case stat_unpacked:
          case stat_halfconfigured:
            if (dep->type == dep_breaks)
              break; /* No problem. */
          case stat_installed:
          case stat_triggerspending:
          case stat_triggersawaited:
            sprintf(linebuf,
                    _("  %.250s provides %.250s and is present and %s.\n"),
                    pkg_name(provider->up->up, pnaw_nonambig), possi->ed->name,
                    gettext(statusstrings[provider->up->up->status]));
            varbuf_add_str(whynot, linebuf);
            if (!canfixbyremove)
              return false;
            nconflicts++;
            *canfixbyremove= provider->up->up;
            break;
          }
          break;
        default:
          internerr("unknown istobe conflict provider '%d'",
                    provider->up->up->clientdata->istobe);
        }
      }
    }

    if (!nconflicts)
      return true;
    if (nconflicts > 1)
      *canfixbyremove = NULL;
    return false;

  } /* if (dependency) {...} else {...} */
}
コード例 #3
0
ファイル: packages.c プロジェクト: nisc-code/dpkg
/*
 * Checks [Pre]-Depends only.
 */
enum dep_check
dependencies_ok(struct pkginfo *pkg, struct pkginfo *removing,
                struct varbuf *aemsgs)
{
  /* Valid values: 2 = ok, 1 = defer, 0 = halt. */
  enum dep_check ok;
  /* Valid values: 0 = none, 1 = defer, 2 = withwarning, 3 = ok. */
  enum found_status found, thisf;
  int interestingwarnings;
  bool matched, anycannotfixbytrig;
  struct varbuf oemsgs = VARBUF_INIT;
  struct dependency *dep;
  struct deppossi *possi, *provider;
  struct pkginfo *possfixbytrig, *canfixbytrig;

  interestingwarnings= 0;
  ok = dep_check_ok;
  debug(dbg_depcon,"checking dependencies of %s (- %s)",
        pkg_name(pkg, pnaw_always),
        removing ? pkg_name(removing, pnaw_always) : "<none>");

  anycannotfixbytrig = false;
  canfixbytrig = NULL;
  for (dep= pkg->installed.depends; dep; dep= dep->next) {
    if (dep->type != dep_depends && dep->type != dep_predepends) continue;
    debug(dbg_depcondetail,"  checking group ...");
    matched = false;
    varbuf_reset(&oemsgs);
    found = found_none;
    possfixbytrig = NULL;
    for (possi = dep->list; found != found_ok && possi; possi = possi->next) {
      struct deppossi_pkg_iterator *possi_iter;
      struct pkginfo *pkg_pos;

      debug(dbg_depcondetail,"    checking possibility  -> %s",possi->ed->name);
      if (possi->cyclebreak) {
        debug(dbg_depcondetail,"      break cycle so ok and found");
        found = found_ok;
        break;
      }

      thisf = found_none;
      possi_iter = deppossi_pkg_iter_new(possi, wpb_installed);
      while ((pkg_pos = deppossi_pkg_iter_next(possi_iter))) {
        thisf = deppossi_ok_found(pkg_pos, pkg, removing, NULL,
                                  &possfixbytrig, &matched, possi,
                                  &interestingwarnings, &oemsgs);
        if (thisf > found)
          found = thisf;
        if (found == found_ok)
          break;
      }
      deppossi_pkg_iter_free(possi_iter);

      if (found != found_ok && possi->verrel == dpkg_relation_none) {
        for (provider = possi->ed->depended.installed;
             found != found_ok && provider;
             provider = provider->rev_next) {
          if (provider->up->type != dep_provides)
            continue;
          debug(dbg_depcondetail, "     checking provider %s",
                pkg_name(provider->up->up, pnaw_always));
          if (!deparchsatisfied(&provider->up->up->installed, provider->arch,
                                possi)) {
            debug(dbg_depcondetail, "       provider does not satisfy arch");
            continue;
          }
          thisf = deppossi_ok_found(provider->up->up, pkg, removing,
                                    possi->ed,
                                    &possfixbytrig, &matched, NULL,
                                    &interestingwarnings, &oemsgs);
          if (thisf > found)
            found = thisf;
        }
      }
      debug(dbg_depcondetail,"    found %d",found);
      if (thisf > found) found= thisf;
    }
    if (fc_depends) {
      thisf = (dependtry >= 4) ? found_forced : found_defer;
      if (thisf > found) {
        found = thisf;
        debug(dbg_depcondetail, "  rescued by force-depends, found %d", found);
      }
    }
    debug(dbg_depcondetail, "  found %d matched %d possfixbytrig %s",
          found, matched,
          possfixbytrig ? pkg_name(possfixbytrig, pnaw_always) : "-");
    if (removing && !matched) continue;
    switch (found) {
    case found_none:
      anycannotfixbytrig = true;
      ok = dep_check_halt;
    case found_forced:
      varbuf_add_str(aemsgs, " ");
      varbuf_add_pkgbin_name(aemsgs, pkg, &pkg->installed, pnaw_nonambig);
      varbuf_add_str(aemsgs, _(" depends on "));
      varbufdependency(aemsgs, dep);
      if (interestingwarnings) {
        /* Don't print the line about the package to be removed if
         * that's the only line. */
        varbuf_end_str(&oemsgs);
        varbuf_add_str(aemsgs, _("; however:\n"));
        varbuf_add_str(aemsgs, oemsgs.buf);
      } else {
        varbuf_add_str(aemsgs, ".\n");
      }
      break;
    case found_defer:
      if (possfixbytrig)
        canfixbytrig = possfixbytrig;
      else
        anycannotfixbytrig = true;
      if (ok > dep_check_defer)
        ok = dep_check_defer;
      break;
    case found_ok:
      break;
    default:
      internerr("unknown value for found '%d'", found);
    }
  }
  if (ok == dep_check_halt &&
      (pkg->clientdata && pkg->clientdata->istobe == itb_remove))
    ok = dep_check_defer;
  if (!anycannotfixbytrig && canfixbytrig)
    progress_bytrigproc = canfixbytrig;

  varbuf_destroy(&oemsgs);
  debug(dbg_depcon,"ok %d msgs >>%.*s<<", ok, (int)aemsgs->used, aemsgs->buf);
  return ok;
}
コード例 #4
0
ファイル: depcon.c プロジェクト: Felllini/sprezzos-world
/**
 * Cycle breaking works recursively down the package dependency tree.
 *
 * ‘sofar’ is the list of packages we've descended down already - if we
 * encounter any of its packages again in a dependency we have found a cycle.
 */
static bool
findbreakcyclerecursive(struct pkginfo *pkg, struct cyclesofarlink *sofar)
{
  struct cyclesofarlink thislink, *sol;
  struct dependency *dep;
  struct deppossi *possi, *providelink;
  struct pkginfo *provider, *pkg_pos;

  if (pkg->clientdata->color == black)
    return false;
  pkg->clientdata->color = gray;

  if (debug_has_flag(dbg_depcondetail)) {
    struct varbuf str_pkgs = VARBUF_INIT;

    for (sol = sofar; sol; sol = sol->prev) {
      varbuf_add_str(&str_pkgs, " <- ");
      varbuf_add_pkgbin_name(&str_pkgs, sol->pkg, &sol->pkg->installed, pnaw_nonambig);
    }
    varbuf_end_str(&str_pkgs);
    debug(dbg_depcondetail, "findbreakcyclerecursive %s %s",
          pkg_name(pkg, pnaw_always), str_pkgs.buf);
    varbuf_destroy(&str_pkgs);
  }
  thislink.pkg= pkg;
  thislink.prev = sofar;
  thislink.possi = NULL;
  for (dep= pkg->installed.depends; dep; dep= dep->next) {
    if (dep->type != dep_depends && dep->type != dep_predepends) continue;
    for (possi= dep->list; possi; possi= possi->next) {
      struct deppossi_pkg_iterator *possi_iter;

      /* Don't find the same cycles again. */
      if (possi->cyclebreak) continue;
      thislink.possi= possi;

      possi_iter = deppossi_pkg_iter_new(possi, wpb_installed);
      while ((pkg_pos = deppossi_pkg_iter_next(possi_iter)))
        if (foundcyclebroken(&thislink, sofar, pkg_pos, possi)) {
          deppossi_pkg_iter_free(possi_iter);
          return true;
        }
      deppossi_pkg_iter_free(possi_iter);

      /* Right, now we try all the providers ... */
      for (providelink = possi->ed->depended.installed;
           providelink;
           providelink = providelink->rev_next) {
        if (providelink->up->type != dep_provides) continue;
        provider= providelink->up->up;
        if (provider->clientdata->istobe == itb_normal) continue;
        /* We don't break things at ‘provides’ links, so ‘possi’ is
         * still the one we use. */
        if (foundcyclebroken(&thislink, sofar, provider, possi))
          return true;
      }
    }
  }
  /* Nope, we didn't find a cycle to break. */
  pkg->clientdata->color = black;
  return false;
}