Example #1
0
/*
 * Returns package we're to give up on.
 */
static struct pkginfo *
check_trigger_cycle(struct pkginfo *processing_now)
{
	struct trigcyclenode *tcn;
	struct trigcycleperpkg *tcpp, *tortoise_pkg;
	struct trigpend *tortoise_trig;
	struct pkgiterator *iter;
	struct pkginfo *pkg, *giveup;
	const char *sep;

	debug(dbg_triggers, "check_triggers_cycle pnow=%s",
	      pkg_name(processing_now, pnaw_always));

	tcn = nfmalloc(sizeof(*tcn));
	tcn->pkgs = NULL;
	tcn->then_processed = processing_now;

	iter = pkg_db_iter_new();
	while ((pkg = pkg_db_iter_next_pkg(iter))) {
		if (!pkg->trigpend_head)
			continue;
		tcpp = nfmalloc(sizeof(*tcpp));
		tcpp->pkg = pkg;
		tcpp->then_trigs = pkg->trigpend_head;
		tcpp->next = tcn->pkgs;
		tcn->pkgs = tcpp;
	}
	pkg_db_iter_free(iter);
	if (!hare) {
		debug(dbg_triggersdetail, "check_triggers_cycle pnow=%s first",
		      pkg_name(processing_now, pnaw_always));
		tcn->next = NULL;
		hare = tortoise = tcn;
		return NULL;
	}

	tcn->next = NULL;
	hare->next = tcn;
	hare = tcn;
	if (tortoise_advance)
		tortoise = tortoise->next;
	tortoise_advance = !tortoise_advance;

	/* Now we compare hare to tortoise.
	 * We want to find a trigger pending in tortoise which is not in hare
	 * if we find such a thing we have proved that hare isn't a superset
	 * of tortoise and so that we haven't found a loop (yet). */
	for (tortoise_pkg = tortoise->pkgs;
	     tortoise_pkg;
	     tortoise_pkg = tortoise_pkg->next) {
		if (tortoise_not_in_hare(processing_now, tortoise_pkg))
			return NULL;
	}
	/* Oh dear. hare is a superset of tortoise. We are making no
	 * progress. */
	notice(_("cycle found while processing triggers:\n"
	         " chain of packages whose triggers are or may be responsible:"));
	sep = "  ";
	for (tcn = tortoise; tcn; tcn = tcn->next) {
		fprintf(stderr, "%s%s", sep,
		        pkg_name(tcn->then_processed, pnaw_nonambig));
		sep = " -> ";
	}
	fprintf(stderr, _("\n" " packages' pending triggers which are"
	                  " or may be unresolvable:\n"));
	for (tortoise_pkg = tortoise->pkgs;
	     tortoise_pkg;
	     tortoise_pkg = tortoise_pkg->next) {
		fprintf(stderr, "  %s",
		        pkg_name(tortoise_pkg->pkg, pnaw_nonambig));
		sep = ": ";
		for (tortoise_trig = tortoise_pkg->then_trigs;
		     tortoise_trig;
		     tortoise_trig = tortoise_trig->next) {
			fprintf(stderr, "%s%s", sep, tortoise_trig->name);
		}
		fprintf(stderr, "\n");
	}

	/* We give up on the _earliest_ package involved. */
	giveup = tortoise->pkgs->pkg;
	debug(dbg_triggers, "check_triggers_cycle pnow=%s giveup=%s",
	      pkg_name(processing_now, pnaw_always),
	      pkg_name(giveup, pnaw_always));
	assert(giveup->status == PKG_STAT_TRIGGERSAWAITED ||
	       giveup->status == PKG_STAT_TRIGGERSPENDING);
	pkg_set_status(giveup, PKG_STAT_HALFCONFIGURED);
	modstatdb_note(giveup);
	print_error_perpackage(_("triggers looping, abandoned"),
	                       pkg_name(giveup, pnaw_nonambig));

	return giveup;
}
Example #2
0
/*
 * Returns package we're to give up on.
 */
static struct pkginfo *
check_trigger_cycle(struct pkginfo *processing_now)
{
	struct trigcyclenode *tcn;
	struct trigcycleperpkg *tcpp, *tortoise_pkg;
	struct trigpend *hare_trig, *tortoise_trig;
	struct pkgiterator *it;
	struct pkginfo *pkg, *giveup;
	const char *sep;

	debug(dbg_triggers, "check_triggers_cycle pnow=%s",
	      pkg_describe(processing_now, pdo_foreign));

	tcn = nfmalloc(sizeof(*tcn));
	tcn->pkgs = NULL;
	tcn->then_processed = processing_now;

	it = pkg_db_iter_new();
	while ((pkg = pkg_db_iter_next_pkg(it))) {
		if (!pkg->trigpend_head)
			continue;
		tcpp = nfmalloc(sizeof(*tcpp));
		tcpp->pkg = pkg;
		tcpp->then_trigs = pkg->trigpend_head;
		tcpp->next = tcn->pkgs;
		tcn->pkgs = tcpp;
	}
	pkg_db_iter_free(it);
	if (!hare) {
		debug(dbg_triggersdetail, "check_triggers_cycle pnow=%s first",
		      pkg_describe(processing_now, pdo_foreign));
		tcn->next = NULL;
		hare = tortoise = tcn;
		return NULL;
	}

	tcn->next = NULL;
	hare->next = tcn;
	hare = tcn;
	if (tortoise_advance)
		tortoise = tortoise->next;
	tortoise_advance = !tortoise_advance;

	/* Now we compare hare to tortoise.
	 * We want to find a trigger pending in tortoise which is not in hare
	 * if we find such a thing we have proved that hare isn't a superset
	 * of tortoise and so that we haven't found a loop (yet). */
	for (tortoise_pkg = tortoise->pkgs;
	     tortoise_pkg;
	     tortoise_pkg = tortoise_pkg->next) {
		const char *pnow_name, *tortoise_name;
		pnow_name = pkg_describe(processing_now, pdo_foreign);
		tortoise_name = pkg_describe(tortoise_pkg->pkg, pdo_foreign);
		debug(dbg_triggersdetail, "check_triggers_cycle pnow=%s tortoise=%s",
		      pnow_name, tortoise_name);
		for (tortoise_trig = tortoise_pkg->then_trigs;
		     tortoise_trig;
		     tortoise_trig = tortoise_trig->next) {
			debug(dbg_triggersdetail,
			      "check_triggers_cycle pnow=%s tortoise=%s"
			      " tortoisetrig=%s", pnow_name, tortoise_name,
			      tortoise_trig->name);
			/* hare is now so we can just look up in the actual
			 * data. */
			for (hare_trig = tortoise_pkg->pkg->trigpend_head;
			     hare_trig;
			     hare_trig = hare_trig->next) {
				debug(dbg_triggersstupid,
				      "check_triggers_cycle pnow=%s tortoise=%s"
				      " tortoisetrig=%s haretrig=%s",
				      pnow_name, tortoise_name,
				      tortoise_trig->name, hare_trig->name);
				if (!strcmp(hare_trig->name, tortoise_trig->name))
					goto found_in_hare;
			}
			/* Not found in hare, yay! */
			debug(dbg_triggersdetail,
			      "check_triggers_cycle pnow=%s tortoise=%s OK",
			      pnow_name, tortoise_name);
			return NULL;
			found_in_hare:;
		}
	}
	/* Oh dear. hare is a superset of tortoise. We are making no
	 * progress. */
	fprintf(stderr, _("%s: cycle found while processing triggers:\n chain of"
	        " packages whose triggers are or may be responsible:\n"),
	        dpkg_get_progname());
	sep = "  ";
	for (tcn = tortoise; tcn; tcn = tcn->next) {
		fprintf(stderr, "%s%s", sep,
		        pkg_describe(tcn->then_processed, pdo_foreign));
		sep = " -> ";
	}
	fprintf(stderr, _("\n" " packages' pending triggers which are"
	                  " or may be unresolvable:\n"));
	for (tortoise_pkg = tortoise->pkgs;
	     tortoise_pkg;
	     tortoise_pkg = tortoise_pkg->next) {
		fprintf(stderr, "  %s",
		        pkg_describe(tortoise_pkg->pkg, pdo_foreign));
		sep = ": ";
		for (tortoise_trig = tortoise_pkg->then_trigs;
		     tortoise_trig;
		     tortoise_trig = tortoise_trig->next) {
			fprintf(stderr, "%s%s", sep, tortoise_trig->name);
		}
		fprintf(stderr, "\n");
	}

	/* We give up on the _earliest_ package involved. */
	giveup = tortoise->pkgs->pkg;
	debug(dbg_triggers, "check_triggers_cycle pnow=%s giveup=%p",
	      pkg_describe(processing_now, pdo_foreign),
	      pkg_describe(giveup, pdo_foreign));
	assert(giveup->status == stat_triggersawaited ||
	       giveup->status == stat_triggerspending);
	giveup->status = stat_halfconfigured;
	modstatdb_note(giveup);
	print_error_perpackage(_("triggers looping, abandoned"),
	                       pkg_describe(giveup, pdo_foreign));

	return giveup;
}