Exemple #1
0
static void
enqueue_specified(const char *const *argv)
{
  const char *thisarg;

  while ((thisarg = *argv++) != NULL) {
    struct dpkg_error err;
    struct pkginfo *pkg;

    pkg = pkg_spec_parse_pkg(thisarg, &err);
    if (pkg == NULL)
      badusage(_("--%s needs a valid package name but '%.250s' is not: %s"),
               cipaction->olong, thisarg, err.str);

    if (pkg->status == stat_notinstalled) {
      size_t l = strlen(pkg->set->name);
      const char *extension = pkg->set->name + l - sizeof(DEBEXT) + 1;

      if (l >= sizeof(DEBEXT) && strcmp(extension, DEBEXT) == 0)
        badusage(_("you must specify packages by their own names,"
                   " not by quoting the names of the files they come in"));
    }
    enqueue_package(pkg);
  }
}
Exemple #2
0
static void
enqueue_pending(void)
{
  struct pkg_hash_iter *iter;
  struct pkginfo *pkg;

  iter = pkg_hash_iter_new();
  while ((pkg = pkg_hash_iter_next_pkg(iter)) != NULL) {
    switch (cipaction->arg_int) {
    case act_configure:
      if (!(pkg->status == PKG_STAT_UNPACKED ||
            pkg->status == PKG_STAT_HALFCONFIGURED ||
            pkg->trigpend_head))
        continue;
      if (pkg->want != PKG_WANT_INSTALL)
        continue;
      break;
    case act_triggers:
      if (!pkg->trigpend_head)
        continue;
      if (pkg->want != PKG_WANT_INSTALL)
        continue;
      break;
    case act_remove:
    case act_purge:
      if (pkg->want != PKG_WANT_PURGE) {
        if (pkg->want != PKG_WANT_DEINSTALL)
          continue;
        if (pkg->status == PKG_STAT_CONFIGFILES)
          continue;
      }
      if (pkg->status == PKG_STAT_NOTINSTALLED)
        continue;
      break;
    default:
      internerr("unknown action '%d'", cipaction->arg_int);
    }
    enqueue_package(pkg);
  }
  pkg_hash_iter_free(iter);
}
Exemple #3
0
static void
enqueue_pending(void)
{
  struct pkgiterator *it;
  struct pkginfo *pkg;

  it = pkg_db_iter_new();
  while ((pkg = pkg_db_iter_next_pkg(it)) != NULL) {
    switch (cipaction->arg_int) {
    case act_configure:
      if (!(pkg->status == stat_unpacked ||
            pkg->status == stat_halfconfigured ||
            pkg->trigpend_head))
        continue;
      if (pkg->want != want_install)
        continue;
      break;
    case act_triggers:
      if (!pkg->trigpend_head)
        continue;
      if (pkg->want != want_install)
        continue;
      break;
    case act_remove:
    case act_purge:
      if (pkg->want != want_purge) {
        if (pkg->want != want_deinstall)
          continue;
        if (pkg->status == stat_configfiles)
          continue;
      }
      if (pkg->status == stat_notinstalled)
        continue;
      break;
    default:
      internerr("unknown action '%d'", cipaction->arg_int);
    }
    enqueue_package(pkg);
  }
  pkg_db_iter_free(it);
}
Exemple #4
0
/*
 * Does cycle checking. Doesn't mind if pkg has no triggers pending - in
 * that case does nothing but fix up any stale awaiters.
 */
void
trigproc(struct pkginfo *pkg, enum trigproc_type type)
{
	static struct varbuf namesarg;

	struct varbuf depwhynot = VARBUF_INIT;
	struct trigpend *tp;
	struct pkginfo *gaveup;

	debug(dbg_triggers, "trigproc %s", pkg_name(pkg, pnaw_always));

	if (pkg->clientdata->trigprocdeferred)
		pkg->clientdata->trigprocdeferred->pkg = NULL;
	pkg->clientdata->trigprocdeferred = NULL;

	if (pkg->trigpend_head) {
		enum dep_check ok;

		assert(pkg->status == PKG_STAT_TRIGGERSPENDING ||
		       pkg->status == PKG_STAT_TRIGGERSAWAITED);

		if (dependtry > 1) {
			gaveup = check_trigger_cycle(pkg);
			if (gaveup == pkg)
				return;

			if (findbreakcycle(pkg))
				sincenothing = 0;
		}

		ok = dependencies_ok(pkg, NULL, &depwhynot);
		if (ok == DEP_CHECK_DEFER) {
			varbuf_destroy(&depwhynot);
			enqueue_package(pkg);
			return;
		} else if (ok == DEP_CHECK_HALT) {
			/* We cannot process this package on this dpkg run,
			 * and we can get here repeatedly if this package is
			 * required to make progress for other packages. So
			 * reset the trigger cycles tracking to avoid bogus
			 * cycle detections. */
			trigproc_reset_cycle();

			/* When doing opportunistic trigger processig, nothing
			 * requires us to be able to make progress; skip the
			 * package and silently ignore the error due to
			 * unsatisfiable dependencies. */
			if (type == TRIGPROC_TRY) {
				varbuf_destroy(&depwhynot);
				return;
			}

			sincenothing = 0;
			varbuf_end_str(&depwhynot);
			notice(_("dependency problems prevent processing "
			         "triggers for %s:\n%s"),
			       pkg_name(pkg, pnaw_nonambig), depwhynot.buf);
			varbuf_destroy(&depwhynot);
			ohshit(_("dependency problems - leaving triggers unprocessed"));
		} else if (depwhynot.used) {
			varbuf_end_str(&depwhynot);
			notice(_("%s: dependency problems, but processing "
			         "triggers anyway as you requested:\n%s"),
			       pkg_name(pkg, pnaw_nonambig), depwhynot.buf);
			varbuf_destroy(&depwhynot);
		}

		if (dependtry <= 1) {
			gaveup = check_trigger_cycle(pkg);
			if (gaveup == pkg)
				return;
		}

		printf(_("Processing triggers for %s (%s) ...\n"),
		       pkg_name(pkg, pnaw_nonambig),
		       versiondescribe(&pkg->installed.version, vdew_nonambig));
		log_action("trigproc", pkg, &pkg->installed);

		varbuf_reset(&namesarg);
		for (tp = pkg->trigpend_head; tp; tp = tp->next) {
			varbuf_add_char(&namesarg, ' ');
			varbuf_add_str(&namesarg, tp->name);
		}
		varbuf_end_str(&namesarg);

		/* Setting the status to half-configured
		 * causes modstatdb_note to clear pending triggers. */
		pkg_set_status(pkg, PKG_STAT_HALFCONFIGURED);
		modstatdb_note(pkg);

		if (!f_noact) {
			sincenothing = 0;
			maintscript_postinst(pkg, "triggered",
			                     namesarg.buf + 1, NULL);
		}

		post_postinst_tasks(pkg, PKG_STAT_INSTALLED);
	} else {
		/* In other branch is done by modstatdb_note(), from inside
		 * post_postinst_tasks(). */
		trig_clear_awaiters(pkg);
	}
}
Exemple #5
0
void
enqueue_package_mark_seen(struct pkginfo *pkg)
{
  enqueue_package(pkg);
  pkg->clientdata->cmdline_seen++;
}
Exemple #6
0
/*
 * Return values:
 *   0: cannot be satisfied.
 *   1: defer: may be satisfied later, when other packages are better or
 *      at higher dependtry due to --force
 *      will set *fixbytrig to package whose trigger processing would help
 *      if applicable (and leave it alone otherwise).
 *   2: not satisfied but forcing
 *      (*interestingwarnings >= 0 on exit? caller is to print oemsgs).
 *   3: satisfied now.
 */
static enum found_status
deppossi_ok_found(struct pkginfo *possdependee, struct pkginfo *requiredby,
                  struct pkginfo *removing, struct deppossi *provider,
                  struct pkginfo **fixbytrig,
                  bool *matched, struct deppossi *checkversion,
                  int *interestingwarnings, struct varbuf *oemsgs)
{
  enum found_status thisf;

  if (ignore_depends(possdependee)) {
    debug(dbg_depcondetail,"      ignoring depended package so ok and found");
    return FOUND_OK;
  }
  thisf = FOUND_NONE;
  if (possdependee == removing) {
    if (provider) {
      varbuf_printf(oemsgs,
                    _("  Package %s which provides %s is to be removed.\n"),
                    pkg_name(possdependee, pnaw_nonambig),
                    provider->ed->name);
    } else {
      varbuf_printf(oemsgs, _("  Package %s is to be removed.\n"),
                    pkg_name(possdependee, pnaw_nonambig));
    }

    *matched = true;
    debug(dbg_depcondetail,"      removing possdependee, returning %d",thisf);
    return thisf;
  }
  switch (possdependee->status) {
  case PKG_STAT_UNPACKED:
  case PKG_STAT_HALFCONFIGURED:
  case PKG_STAT_TRIGGERSAWAITED:
  case PKG_STAT_TRIGGERSPENDING:
  case PKG_STAT_INSTALLED:
    if (checkversion) {
      if (provider) {
        debug(dbg_depcondetail, "      checking package %s provided by pkg %s",
              checkversion->ed->name, pkg_name(possdependee, pnaw_always));
        if (!pkg_virtual_deppossi_satisfied(checkversion, provider)) {
          varbuf_printf(oemsgs,
                        _("  Version of %s on system, provided by %s, is %s.\n"),
                        checkversion->ed->name,
                        pkg_name(possdependee, pnaw_always),
                        versiondescribe(&provider->version, vdew_nonambig));
          if (in_force(FORCE_DEPENDS_VERSION))
            thisf = found_forced_on(DEPEND_TRY_FORCE_DEPENDS_VERSION);
          debug(dbg_depcondetail, "      bad version");
          goto unsuitable;
        }
      } else {
        debug(dbg_depcondetail, "      checking non-provided pkg %s",
              pkg_name(possdependee, pnaw_always));
        if (!versionsatisfied(&possdependee->installed, checkversion)) {
          varbuf_printf(oemsgs, _("  Version of %s on system is %s.\n"),
                        pkg_name(possdependee, pnaw_nonambig),
                        versiondescribe(&possdependee->installed.version,
                                        vdew_nonambig));
          if (in_force(FORCE_DEPENDS_VERSION))
            thisf = found_forced_on(DEPEND_TRY_FORCE_DEPENDS_VERSION);
          debug(dbg_depcondetail, "      bad version");
          goto unsuitable;
        }
      }
    }
    if (possdependee->status == PKG_STAT_INSTALLED ||
        possdependee->status == PKG_STAT_TRIGGERSPENDING) {
      debug(dbg_depcondetail,"      is installed, ok and found");
      return FOUND_OK;
    }
    if (possdependee->status == PKG_STAT_TRIGGERSAWAITED) {
      if (possdependee->trigaw.head == NULL)
        internerr("package %s in state %s, has no awaited triggers",
                  pkg_name(possdependee, pnaw_always),
                  pkg_status_name(possdependee));

      if (removing ||
          !(f_triggers ||
            (possdependee->clientdata &&
             possdependee->clientdata->istobe == PKG_ISTOBE_INSTALLNEW))) {
        if (provider) {
          varbuf_printf(oemsgs,
                        _("  Package %s which provides %s awaits trigger processing.\n"),
                        pkg_name(possdependee, pnaw_nonambig),
                        provider->ed->name);
        } else {
          varbuf_printf(oemsgs,
                        _("  Package %s awaits trigger processing.\n"),
                        pkg_name(possdependee, pnaw_nonambig));
        }
        debug(dbg_depcondetail, "      triggers-awaited, no fixbytrig");
        goto unsuitable;
      }
      /* We don't check the status of trigaw.head->pend here, just in case
       * we get into the pathological situation where Triggers-Awaited but
       * the named package doesn't actually have any pending triggers. In
       * that case we queue the non-pending package for trigger processing
       * anyway, and that trigger processing will be a noop except for
       * sorting out all of the packages which name it in Triggers-Awaited.
       *
       * (This situation can only arise if modstatdb_note success in
       * clearing the triggers-pending status of the pending package
       * but then fails to go on to update the awaiters.) */
      *fixbytrig = possdependee->trigaw.head->pend;
      debug(dbg_depcondetail,
            "      triggers-awaited, fixbytrig '%s', defer",
            pkg_name(*fixbytrig, pnaw_always));
      return FOUND_DEFER;
    }
    if (possdependee->clientdata &&
        possdependee->clientdata->istobe == PKG_ISTOBE_INSTALLNEW) {
      debug(dbg_depcondetail,"      unpacked/halfconfigured, defer");
      return FOUND_DEFER;
    } else if (!removing && in_force(FORCE_CONFIGURE_ANY) &&
               !skip_due_to_hold(possdependee) &&
               !(possdependee->status == PKG_STAT_HALFCONFIGURED)) {
      notice(_("also configuring '%s' (required by '%s')"),
             pkg_name(possdependee, pnaw_nonambig),
             pkg_name(requiredby, pnaw_nonambig));
      enqueue_package(possdependee);
      sincenothing = 0;
      return FOUND_DEFER;
    } else {
      if (provider) {
        varbuf_printf(oemsgs,
                      _("  Package %s which provides %s is not configured yet.\n"),
                      pkg_name(possdependee, pnaw_nonambig),
                      provider->ed->name);
      } else {
        varbuf_printf(oemsgs, _("  Package %s is not configured yet.\n"),
                      pkg_name(possdependee, pnaw_nonambig));
      }

      debug(dbg_depcondetail, "      not configured/able");
      goto unsuitable;
    }

  default:
    if (provider) {
      varbuf_printf(oemsgs,
                    _("  Package %s which provides %s is not installed.\n"),
                    pkg_name(possdependee, pnaw_nonambig),
                    provider->ed->name);
    } else {
      varbuf_printf(oemsgs, _("  Package %s is not installed.\n"),
                    pkg_name(possdependee, pnaw_nonambig));
    }

    debug(dbg_depcondetail, "      not installed");
    goto unsuitable;
  }

unsuitable:
  debug(dbg_depcondetail, "        returning %d", thisf);
  (*interestingwarnings)++;

  return thisf;
}
Exemple #7
0
void process_queue(void) {
  struct pkg_list *rundown;
  struct pkginfo *volatile pkg;
  volatile enum action action_todo;
  jmp_buf ejbuf;
  enum pkg_istobe istobe = PKG_ISTOBE_NORMAL;

  if (abort_processing)
    return;

  clear_istobes();

  switch (cipaction->arg_int) {
  case act_triggers:
  case act_configure:
  case act_install:
    istobe = PKG_ISTOBE_INSTALLNEW;
    break;
  case act_remove:
  case act_purge:
    istobe = PKG_ISTOBE_REMOVE;
    break;
  default:
    internerr("unknown action '%d'", cipaction->arg_int);
  }
  for (rundown = queue.head; rundown; rundown = rundown->next) {
    ensure_package_clientdata(rundown->pkg);

    /* We have processed this package more than once. There are no duplicates
     * as we make sure of that when enqueuing them. */
    if (rundown->pkg->clientdata->cmdline_seen > 1) {
      switch (cipaction->arg_int) {
      case act_triggers:
      case act_configure: case act_remove: case act_purge:
        printf(_("Package %s listed more than once, only processing once.\n"),
               pkg_name(rundown->pkg, pnaw_nonambig));
        break;
      case act_install:
        printf(_("More than one copy of package %s has been unpacked\n"
               " in this run !  Only configuring it once.\n"),
               pkg_name(rundown->pkg, pnaw_nonambig));
        break;
      default:
        internerr("unknown action '%d'", cipaction->arg_int);
      }
    }
    rundown->pkg->clientdata->istobe = istobe;
  }

  while (!pkg_queue_is_empty(&queue)) {
    pkg = pkg_queue_pop(&queue);
    if (!pkg)
      continue; /* Duplicate, which we removed earlier. */

    ensure_package_clientdata(pkg);
    pkg->clientdata->enqueued = false;

    action_todo = cipaction->arg_int;

    if (sincenothing++ > queue.length * 3 + 2) {
      /* Make sure that even if we have exceeded the queue since not having
       * made any progress, we are not getting stuck trying to progress by
       * trigger processing, w/o jumping into the next dependtry. */
      dependtry++;
      sincenothing = 0;
      if (dependtry >= DEPEND_TRY_LAST)
        internerr("exceeded dependtry %d (sincenothing=%d; queue.length=%d)",
                  dependtry, sincenothing, queue.length);
    } else if (sincenothing > queue.length * 2 + 2) {
      if (dependtry >= DEPEND_TRY_TRIGGERS &&
          progress_bytrigproc && progress_bytrigproc->trigpend_head) {
        enqueue_package(pkg);
        pkg = progress_bytrigproc;
        progress_bytrigproc = NULL;
        action_todo = act_configure;
      } else {
        dependtry++;
        sincenothing = 0;
        if (dependtry >= DEPEND_TRY_LAST)
          internerr("exceeded dependtry %d (sincenothing=%d, queue.length=%d)",
                    dependtry, sincenothing, queue.length);
      }
    }

    debug(dbg_general, "process queue pkg %s queue.len %d progress %d, try %d",
          pkg_name(pkg, pnaw_always), queue.length, sincenothing, dependtry);

    if (pkg->status > PKG_STAT_INSTALLED)
      internerr("package %s status %d is out-of-bounds",
                pkg_name(pkg, pnaw_always), pkg->status);

    if (setjmp(ejbuf)) {
      /* Give up on it from the point of view of other packages, i.e. reset
       * istobe. */
      pkg->clientdata->istobe = PKG_ISTOBE_NORMAL;

      pop_error_context(ehflag_bombout);
      if (abort_processing)
        return;
      continue;
    }
    push_error_context_jump(&ejbuf, print_error_perpackage,
                            pkg_name(pkg, pnaw_nonambig));

    switch (action_todo) {
    case act_triggers:
      if (!pkg->trigpend_head)
        ohshit(_("package %.250s is not ready for trigger processing\n"
                 " (current status '%.250s' with no pending triggers)"),
               pkg_name(pkg, pnaw_nonambig), pkg_status_name(pkg));
      /* Fall through. */
    case act_install:
      /* Don't try to configure pkgs that we've just disappeared. */
      if (pkg->status == PKG_STAT_NOTINSTALLED)
        break;
      /* Fall through. */
    case act_configure:
      /* Do whatever is most needed. */
      if (pkg->trigpend_head)
        trigproc(pkg, TRIGPROC_TRY_QUEUED);
      else
        deferred_configure(pkg);
      break;
    case act_remove: case act_purge:
      deferred_remove(pkg);
      break;
    default:
      internerr("unknown action '%d'", cipaction->arg_int);
    }
    m_output(stdout, _("<standard output>"));
    m_output(stderr, _("<standard error>"));

    pop_error_context(ehflag_normaltidy);
  }

  if (queue.length)
    internerr("finished package processing with non-empty queue length %d",
              queue.length);
}
Exemple #8
0
/*
 * Also has conflictor in argv[1] and infavour in argv[2].
 * conflictor may be NULL if deconfigure was due to Breaks.
 */
void ok_prermdeconfigure(int argc, void **argv) {
  struct pkginfo *deconf= (struct pkginfo*)argv[0];

  if (cipaction->arg_int == act_install)
    enqueue_package(deconf);
}
Exemple #9
0
/*
 * Return values:
 *   0: cannot be satisfied.
 *   1: defer: may be satisfied later, when other packages are better or
 *      at higher dependtry due to --force
 *      will set *fixbytrig to package whose trigger processing would help
 *      if applicable (and leave it alone otherwise).
 *   2: not satisfied but forcing
 *      (*interestingwarnings >= 0 on exit? caller is to print oemsgs).
 *   3: satisfied now.
 */
static enum found_status
deppossi_ok_found(struct pkginfo *possdependee, struct pkginfo *requiredby,
                  struct pkginfo *removing, struct pkgset *providing,
                  struct pkginfo **fixbytrig,
                  bool *matched, struct deppossi *checkversion,
                  int *interestingwarnings, struct varbuf *oemsgs)
{
  enum found_status thisf;

  if (ignore_depends(possdependee)) {
    debug(dbg_depcondetail,"      ignoring depended package so ok and found");
    return found_ok;
  }
  thisf = found_none;
  if (possdependee == removing) {
    if (providing) {
      varbuf_printf(oemsgs,
                    _("  Package %s which provides %s is to be removed.\n"),
                    pkg_name(possdependee, pnaw_nonambig), providing->name);
    } else {
      varbuf_printf(oemsgs, _("  Package %s is to be removed.\n"),
                    pkg_name(possdependee, pnaw_nonambig));
    }

    *matched = true;
    debug(dbg_depcondetail,"      removing possdependee, returning %d",thisf);
    return thisf;
  }
  switch (possdependee->status) {
  case stat_unpacked:
  case stat_halfconfigured:
  case stat_triggersawaited:
  case stat_triggerspending:
  case stat_installed:
    if (checkversion && !versionsatisfied(&possdependee->installed,checkversion)) {
      varbuf_printf(oemsgs, _("  Version of %s on system is %s.\n"),
                    pkg_name(possdependee, pnaw_nonambig),
                    versiondescribe(&possdependee->installed.version,
                                    vdew_nonambig));
      assert(checkversion->verrel != dpkg_relation_none);
      if (fc_dependsversion)
        thisf = (dependtry >= 3) ? found_forced : found_defer;
      debug(dbg_depcondetail,"      bad version, returning %d",thisf);
      (*interestingwarnings)++;
      return thisf;
    }
    if (possdependee->status == stat_installed ||
        possdependee->status == stat_triggerspending) {
      debug(dbg_depcondetail,"      is installed, ok and found");
      return found_ok;
    }
    if (possdependee->status == stat_triggersawaited) {
      assert(possdependee->trigaw.head);
      if (removing || !(f_triggers ||
                        possdependee->clientdata->istobe == itb_installnew)) {
        if (providing) {
          varbuf_printf(oemsgs,
                        _("  Package %s which provides %s awaits trigger processing.\n"),
                        pkg_name(possdependee, pnaw_nonambig), providing->name);
        } else {
          varbuf_printf(oemsgs,
                        _("  Package %s awaits trigger processing.\n"),
                        pkg_name(possdependee, pnaw_nonambig));
        }
        debug(dbg_depcondetail, "      triggers-awaited, no fixbytrig");
        goto unsuitable;
      }
      /* We don't check the status of trigaw.head->pend here, just in case
       * we get into the pathological situation where Triggers-Awaited but
       * the named package doesn't actually have any pending triggers. In
       * that case we queue the non-pending package for trigger processing
       * anyway, and that trigger processing will be a noop except for
       * sorting out all of the packages which name it in Triggers-Awaited.
       *
       * (This situation can only arise if modstatdb_note success in
       * clearing the triggers-pending status of the pending package
       * but then fails to go on to update the awaiters.) */
      *fixbytrig = possdependee->trigaw.head->pend;
      debug(dbg_depcondetail,
            "      triggers-awaited, fixbytrig '%s', defer",
            pkg_name(*fixbytrig, pnaw_always));
      return found_defer;
    }
    if (possdependee->clientdata &&
        possdependee->clientdata->istobe == itb_installnew) {
      debug(dbg_depcondetail,"      unpacked/halfconfigured, defer");
      return found_defer;
    } else if (!removing && fc_configureany &&
               !skip_due_to_hold(possdependee) &&
               !(possdependee->status == stat_halfconfigured)) {
      notice(_("also configuring '%s' (required by '%s')"),
             pkg_name(possdependee, pnaw_nonambig),
             pkg_name(requiredby, pnaw_nonambig));
      enqueue_package(possdependee);
      sincenothing = 0;
      return found_defer;
    } else {
      if (providing) {
        varbuf_printf(oemsgs,
                      _("  Package %s which provides %s is not configured yet.\n"),
                      pkg_name(possdependee, pnaw_nonambig), providing->name);
      } else {
        varbuf_printf(oemsgs, _("  Package %s is not configured yet.\n"),
                      pkg_name(possdependee, pnaw_nonambig));
      }

      debug(dbg_depcondetail, "      not configured/able");
      goto unsuitable;
    }

  default:
    if (providing) {
      varbuf_printf(oemsgs,
                    _("  Package %s which provides %s is not installed.\n"),
                    pkg_name(possdependee, pnaw_nonambig), providing->name);
    } else {
      varbuf_printf(oemsgs, _("  Package %s is not installed.\n"),
                    pkg_name(possdependee, pnaw_nonambig));
    }

    debug(dbg_depcondetail, "      not installed");
    goto unsuitable;
  }

unsuitable:
  debug(dbg_depcondetail, "        returning %d", thisf);
  (*interestingwarnings)++;

  return thisf;
}
Exemple #10
0
void process_queue(void) {
  struct pkg_list *rundown;
  struct pkginfo *volatile pkg;
  volatile enum action action_todo;
  jmp_buf ejbuf;
  enum istobes istobe= itb_normal;

  if (abort_processing)
    return;

  clear_istobes();

  switch (cipaction->arg_int) {
  case act_triggers:
  case act_configure: case act_install:  istobe= itb_installnew;  break;
  case act_remove: case act_purge:       istobe= itb_remove;      break;
  default:
    internerr("unknown action '%d'", cipaction->arg_int);
  }
  for (rundown = queue.head; rundown; rundown = rundown->next) {
    ensure_package_clientdata(rundown->pkg);
    if (rundown->pkg->clientdata->istobe == istobe) {
      /* Erase the queue entry - this is a second copy! */
      switch (cipaction->arg_int) {
      case act_triggers:
      case act_configure: case act_remove: case act_purge:
        printf(_("Package %s listed more than once, only processing once.\n"),
               pkg_name(rundown->pkg, pnaw_nonambig));
        break;
      case act_install:
        printf(_("More than one copy of package %s has been unpacked\n"
               " in this run !  Only configuring it once.\n"),
               pkg_name(rundown->pkg, pnaw_nonambig));
        break;
      default:
        internerr("unknown action '%d'", cipaction->arg_int);
      }
      rundown->pkg = NULL;
   } else {
      rundown->pkg->clientdata->istobe= istobe;
    }
  }

  while (!pkg_queue_is_empty(&queue)) {
    pkg = pkg_queue_pop(&queue);
    if (!pkg)
      continue; /* Duplicate, which we removed earlier. */

    action_todo = cipaction->arg_int;

    if (sincenothing++ > queue.length * 2 + 2) {
      if (progress_bytrigproc && progress_bytrigproc->trigpend_head) {
        enqueue_package(pkg);
        pkg = progress_bytrigproc;
        action_todo = act_configure;
      } else {
        dependtry++;
        sincenothing = 0;
        assert(dependtry <= 4);
      }
    }

    assert(pkg->status <= stat_installed);

    if (setjmp(ejbuf)) {
      /* Give up on it from the point of view of other packages, i.e. reset
       * istobe. */
      pkg->clientdata->istobe= itb_normal;

      pop_error_context(ehflag_bombout);
      if (abort_processing)
        return;
      continue;
    }
    push_error_context_jump(&ejbuf, print_error_perpackage,
                            pkg_name(pkg, pnaw_nonambig));

    switch (action_todo) {
    case act_triggers:
      if (!pkg->trigpend_head)
        ohshit(_("package %.250s is not ready for trigger processing\n"
                 " (current status `%.250s' with no pending triggers)"),
               pkg_name(pkg, pnaw_nonambig), statusinfos[pkg->status].name);
      /* Fall through. */
    case act_install:
      /* Don't try to configure pkgs that we've just disappeared. */
      if (pkg->status == stat_notinstalled)
        break;
      /* Fall through. */
    case act_configure:
      /* Do whatever is most needed. */
      if (pkg->trigpend_head)
        trigproc(pkg);
      else
        deferred_configure(pkg);
      break;
    case act_remove: case act_purge:
      deferred_remove(pkg);
      break;
    default:
      internerr("unknown action '%d'", cipaction->arg_int);
    }
    m_output(stdout, _("<standard output>"));
    m_output(stderr, _("<standard error>"));

    pop_error_context(ehflag_normaltidy);
  }
  assert(!queue.length);
}