You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

967 lines
25 KiB

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <errno.h>
#include "dpkg.h"
#include "memory.h"
// enlarge this if britney has issues parsing packages
// (e.g. very slow installability checks)
#define SIZEOFHASHMAP 16
/* #define DIAGNOSE 1 */
#define insert_packagenamelist(x,y) insert_l_packagenamelist(x,y,__LINE__)
static void free_dependency(dependency *dep);
static void free_collected_package(dpkg_collected_package *pkg);
static collpackagelist **get_matching_low(collpackagelist **addto,
dpkg_packages *pkgs, dependency *dep, int line);
static collpackagelist *get_matching(dpkg_packages *pkgs, deplist *depopts, int line);
static deplist *read_deplist(char **buf, char sep, char end);
static dependency *read_dependency(char **buf, char *end);
static void add_virtualpackage(virtualpkgtbl *vpkgs, char *package,
char *version, char *multiarch,
dpkg_collected_package *cpkg);
static void remove_virtualpackage(virtualpkgtbl *vpkgs, char *pkgname,
dpkg_collected_package *cpkg);
static char *read_packagename(char **buf, char *end);
static char *read_until_char(char **buf, char *end);
static int checkinstallable(dpkg_packages *pkgs, collpackagelist *instoneof);
// implemented in dpkg-lib.c
int cmpversions(char *left, int op, char *right);
#define block_malloc(s) block_malloc2(s, __LINE__)
static int dependency_counts[] = { 1, 1, 0, 0 };
#define SMB_SIZE (1<<22)
struct stringmemblock {
struct stringmemblock *next;
size_t last;
char mem[SMB_SIZE];
};
static struct stringmemblock *stringmemory = NULL;
static int stringmemorycount = 0;
static const unsigned long stringmemblocksizekib = (unsigned long) sizeof(struct stringmemblock) / 1024;
static char *my_strdup(char *foo) {
struct stringmemblock *which;
size_t len;
if (!foo) return NULL;
len = strlen(foo) + 1;
if (len > SMB_SIZE) return strdup(foo);
for (which = stringmemory; which; which = which->next) {
if (SMB_SIZE - which->last > len + 1) {
break;
}
}
if (!which) {
which = malloc(sizeof(struct stringmemblock));
if (!which) return NULL;
MDEBUG1_ONLY(fprintf(stderr,
"ALLOC: string memblock %d (%lu KiB, %lu KiB total)\n",
stringmemorycount, stringmemblocksizekib,
(stringmemorycount+1) * stringmemblocksizekib));
memset(which->mem, 0, SMB_SIZE);
which->last = 0;
which->next = stringmemory;
stringmemory = which;
stringmemorycount++;
}
strcpy(&which->mem[which->last], foo);
foo = &which->mem[which->last];
which->last += len;
return foo;
}
/* DIE **/
static void die(char *orig_msg) {
char *msg = my_strdup(orig_msg);
if (*msg && msg[strlen(msg)-1] == ':') {
msg[strlen(msg)-1] = '\0';
perror(msg);
} else {
printf("%s\n", msg);
}
abort();
}
/*************************************************************************
* Basic Package Operations
*/
static dpkg_collected_package *new_collected_package(dpkg_package *pkg) {
dpkg_collected_package *result;
result = block_malloc(sizeof(dpkg_collected_package));
if (result == NULL) die("new_collected_package alloc:");
result->pkg = pkg;
result->installed = 0;
result->conflicted = 0;
result->installable = UNKNOWN;
result->mayaffect = NULL;
return result;
}
static void free_collected_package(dpkg_collected_package *cpkg) {
if (cpkg == NULL) return;
cpkg->pkg = NULL;
free_packagenamelist(cpkg->mayaffect);
cpkg->mayaffect = NULL;
block_free(cpkg, sizeof(dpkg_collected_package));
}
LIST_IMPL(deplist, dependency*, free_dependency, block_malloc, block_free);
LIST_IMPL(deplistlist, deplist*, free_deplist, block_malloc, block_free);
LIST_IMPLX(packagenamelist, char*, KEEP(char*));
LIST_IMPL(ownedpackagenamelist, char*, KEEP(char*), block_malloc, block_free);
/* ownedpackagenamelist stores the packagename in the string store */
static int packagecmp(dpkg_package *l, dpkg_package *r) {
if (l->priority < r->priority) return -1;
if (l->priority > r->priority) return +1;
return strcmp(l->package, r->package);
}
/* container for existing pkgs */
LIST_IMPL(packagelist, dpkg_package *, KEEP(dpkg_package *), block_malloc, block_free);
LIST_IMPLX(collpackagelist, dpkg_collected_package *,
KEEP(dpkg_collected_package *))
#define insert_collpackagelist(x,y) insert_l_collpackagelist(x,y,__LINE__)
/*************************************************************************
* Operations on distributions (collections of packages)
*/
dpkg_packages *new_packages(char *arch) {
dpkg_packages *result;
result = block_malloc(sizeof(dpkg_packages));
if (result == NULL) die("new_packages alloc:");
result->arch = my_strdup(arch);
result->packages = new_packagetbl();
result->virtualpkgs = new_virtualpkgtbl();
return result;
}
void add_package(dpkg_packages *pkgs, dpkg_package *pkg)
{
ownedpackagenamelist *v;
dpkg_collected_package *cpkg;
if (lookup_packagetbl(pkgs->packages, pkg->package) != NULL)
return;
cpkg = new_collected_package(pkg);
add_packagetbl(pkgs->packages, cpkg->pkg->package, cpkg);
add_virtualpackage(pkgs->virtualpkgs, cpkg->pkg->package,
cpkg->pkg->version, cpkg->pkg->multiarch, cpkg);
for (v = cpkg->pkg->provides; v != NULL; v = v->next) {
add_virtualpackage(pkgs->virtualpkgs, v->value, NULL, NULL, cpkg);
}
}
void remove_package(dpkg_packages *pkgs, dpkg_collected_package *cpkg) {
ownedpackagenamelist *v;
packagenamelist *aff;
dpkg_collected_package *p;
for (aff = cpkg->mayaffect; aff != NULL; aff = aff->next) {
p = lookup_packagetbl(pkgs->packages, aff->value);
if (p == NULL) continue;
p->installable = UNKNOWN;
}
p = remove_packagetbl(pkgs->packages, cpkg->pkg->package);
if (p != cpkg) return;
remove_virtualpackage(pkgs->virtualpkgs, cpkg->pkg->package, cpkg);
for (v = cpkg->pkg->provides; v != NULL; v = v->next) {
remove_virtualpackage(pkgs->virtualpkgs, v->value, cpkg);
}
free_collected_package(cpkg);
}
void free_packages(dpkg_packages *pkgs) {
if (pkgs == NULL) return;
/* block_free(pkgs->arch); */
free_packagetbl(pkgs->packages);
free_virtualpkgtbl(pkgs->virtualpkgs);
block_free(pkgs, sizeof(dpkg_packages));
}
HASH_IMPL(packagetbl, char *, dpkg_collected_package *, SIZEOFHASHMAP, strhash, strcmp,
KEEP(char*),free_collected_package);
HASH_IMPL(virtualpkgtbl, char *, virtualpkg *, SIZEOFHASHMAP, strhash, strcmp,
KEEP(char*), free_virtualpkg);
/* dpkg_provision refers to memory allocated elsewhere */
LIST_IMPL(virtualpkg, dpkg_provision, KEEP(dpkg_provision), block_malloc, block_free);
static void remove_virtualpackage(virtualpkgtbl *vpkgs, char *pkgname,
dpkg_collected_package *cpkg)
{
virtualpkg *list;
virtualpkg **where;
list = lookup_virtualpkgtbl(vpkgs, pkgname);
assert(list != NULL);
where = &list;
while((*where)->value.pkg != cpkg) {
where = &(*where)->next;
assert(*where != NULL);
}
delete_virtualpkg(where);
if (list == NULL) {
remove_virtualpkgtbl(vpkgs, pkgname);
} else {
replace_virtualpkgtbl(vpkgs, pkgname, list);
}
}
static void add_virtualpackage(virtualpkgtbl *vpkgs, char *package,
char *version, char *multiarch,
dpkg_collected_package *cpkg)
{
dpkg_provision value;
virtualpkg *list, **addto;
int shouldreplace;
value.pkg = cpkg;
value.version = version;
value.multiarch = multiarch;
list = lookup_virtualpkgtbl(vpkgs, package);
shouldreplace = (list != NULL);
addto = &list;
while (*addto != NULL
&& packagecmp(cpkg->pkg, (*addto)->value.pkg->pkg) >= 0)
{
addto = &(*addto)->next;
}
insert_virtualpkg(addto, value);
if (shouldreplace) {
replace_virtualpkgtbl(vpkgs, package, list);
/* old list is included in new list, so we don't need to free */
} else {
add_virtualpkgtbl(vpkgs, package, list);
}
}
/*************************************************************************
* Parsing Helper Functions
*/
ownedpackagenamelist *read_packagenames(char *buf) {
ownedpackagenamelist *result = NULL;
ownedpackagenamelist **addto = &result;
DEBUG_ONLY( char *strend = buf + strlen(buf); )
char *sub;
while ((sub = my_strdup(read_packagename(&buf, ",")))) {
insert_ownedpackagenamelist(addto, sub);
addto = &(*addto)->next;
while(isspace(*buf)) buf++;
if (*buf == ',') {
buf++;
continue;
}
if (*buf == '\0') {
break;
}
die("read_packagenames no/bad seperator");
}
DEBUG_ONLY( assert(buf <= strend); )
return result;
}
static char *read_until_char(char **buf, char *end) {
static char *result = NULL;
char *start;
DEBUG_ONLY( char *strend = *buf + strlen(*buf); )
int n;
while(isspace(**buf)) (*buf)++;
start = *buf;
while (**buf && !isspace(**buf) && strchr(end, **buf) == NULL) {
(*buf)++;
}
n = *buf - start;
if (n == 0) return NULL;
result = realloc(result, n + 1);
if (result == NULL) die("read_until_char alloc:");
strncpy(result, start, n);
result[n] = '\0';
while(isspace(**buf)) (*buf)++;
DEBUG_ONLY( assert(*buf <= strend); )
return result;
}
static char *read_packagename(char **buf, char *end) {
return read_until_char(buf, end);
}
deplist *read_dep_and(char *buf) {
return read_deplist(&buf, ',', '\0');
}
static deplist *read_deplist(char **buf, char sep, char end) {
deplist *result = NULL;
deplist **addto = &result;
char separs[3] = { sep, end, '\0' };
DEBUG_ONLY( char *strend = *buf + strlen(*buf); )
dependency *sub;
while ((sub = read_dependency(buf, separs))) {
insert_deplist(addto, sub);
addto = &(*addto)->next;
while(isspace(**buf)) (*buf)++;
if (**buf == sep) {
(*buf)++;
continue;
}
if (**buf == '\0' || **buf == end) {
break;
}
die("read_deplist no/bad seperator");
}
DEBUG_ONLY( assert(*buf <= strend); )
return result;
}
deplistlist *read_dep_andor(char *buf) {
deplistlist *result = NULL;
deplistlist **addto = &result;
deplist *sub;
DEBUG_ONLY( char *strend = buf + strlen(buf); )
while ((sub = read_deplist(&buf, '|', ','))) {
insert_deplistlist(addto, sub);
addto = &(*addto)->next;
if (*buf == ',') buf++;
}
DEBUG_ONLY( assert(buf <= strend); )
return result;
}
static dependency *read_dependency(char **buf, char *end) {
dependency *dep;
char *name;
char newend[11];
DEBUG_ONLY( char *strend = *buf + strlen(*buf); )
assert(strlen(end) <= 8);
newend[0] = '('; newend[1] = ':'; strcpy(newend + 2, end);
name = my_strdup(read_until_char(buf, newend));
if (name == NULL) return NULL;
dep = block_malloc(sizeof(dependency));
if (dep == NULL) die("read_dependency alloc 1:");
dep->package = name;
if (**buf == ':') {
(*buf)++;
dep->archqual = my_strdup(read_until_char(buf, newend));
if (dep->archqual == NULL) return NULL;
} else
dep->archqual = NULL;
while(isspace(**buf)) (*buf)++;
if (**buf != '(') {
dep->op = dr_NOOP;
dep->version = NULL;
} else {
(*buf)++;
while(isspace(**buf)) (*buf)++;
/* << , <= , = , >= , >> */
if (**buf == '<') {
(*buf)++;
if (**buf == '<') {
dep->op = dr_LT;
(*buf)++;
} else if (**buf == '=') {
dep->op = dr_LTEQ;
(*buf)++;
} else {
/* The forms `<' and `>' were used to mean earlier/later or
* equal, rather than strictly earlier/later, so they should
* not appear in new packages (though `dpkg' still supports
* them).
*/
dep->op = dr_LTEQ;
}
} else if (**buf == '>') {
(*buf)++;
if (**buf == '>') {
dep->op = dr_GT;
(*buf)++;
} else if (**buf == '=') {
dep->op = dr_GTEQ;
(*buf)++;
} else {
dep->op = dr_GTEQ;
}
} else if (**buf == '=') {
dep->op = dr_EQ;
(*buf)++;
if (**buf == '>') {
dep->op = dr_GTEQ;
(*buf)++;
} else if (**buf == '<') {
dep->op = dr_LTEQ;
(*buf)++;
}
} else {
/* treat it as an implicit = :( */
dep->op = dr_EQ;
/* would prefer to: die("read_dependency unknown version op"); */
}
while (isspace(**buf)) (*buf)++;
newend[0] = ')'; strcpy(newend + 1, end);
dep->version = my_strdup(read_until_char(buf, newend));
while (isspace(**buf)) (*buf)++;
if (dep->version == NULL) die("read_dependency: no version");
if (**buf != ')') die("read_dependency: unterminated version");
(*buf)++;
}
DEBUG_ONLY( assert(*buf <= strend); )
return dep;
}
static void free_dependency(dependency *dep) {
if (dep == NULL) return;
/* block_free(dep->package); */
/* if (dep->version) block_free(dep->version); */
block_free(dep, sizeof(dependency));
}
/*************************************************************************
* Installability Checking
*/
static collpackagelist **get_matching_low(collpackagelist **addto,
dpkg_packages *pkgs, dependency *dep, int line)
{
virtualpkg *vpkg;
for (vpkg = lookup_virtualpkgtbl(pkgs->virtualpkgs, dep->package);
vpkg != NULL;
vpkg = vpkg->next)
{
int add;
add = 0;
if (dep->op == dr_NOOP) {
add = 1;
} else if (vpkg->value.version != NULL) {
if (cmpversions(vpkg->value.version, dep->op, dep->version)) {
add = 1;
}
}
if (dep->archqual != NULL) {
if (strcmp(dep->archqual, "any") == 0) {
if (vpkg->value.multiarch == NULL || strcmp(vpkg->value.multiarch, "allowed") != 0)
add = 0;
} else
add = 0;
}
if (add) {
insert_l_collpackagelist(addto, vpkg->value.pkg, line);
addto = &(*addto)->next;
}
}
return addto;
}
static collpackagelist *get_matching(dpkg_packages *pkgs, deplist *depopts, int line) {
collpackagelist *list = NULL;
collpackagelist **addto = &list;
for(; depopts != NULL; depopts = depopts->next) {
addto = get_matching_low(addto, pkgs, depopts->value, line);
}
return list;
}
typedef struct instonelist instonelist;
struct instonelist {
collpackagelist *curX;
collpackagelist *instoneX;
int expandedX;
struct instonelist *nextX, *prevX, *cutoffX;
};
#define I1CUR(i1) ((i1)->curX)
#define I1INSTONE(i1) ((i1)->instoneX)
#define I1CUTOFF(i1) ((i1)->cutoffX)
#define I1NEXT(i1) ((i1)->nextX) /* can be modified ! */
#define I1PREV(i1) ((i1)->prevX)
#define I1EXPANDED(i1) ((i1)->expandedX)
static instonelist *insert_instonelist(instonelist *where, collpackagelist *instone);
static void trim_instonelist_after(instonelist *first);
static void free_instonelist(instonelist *l);
static instonelist *insert_instonelist(instonelist *old, collpackagelist *instone)
{
instonelist *n = block_malloc(sizeof(instonelist));
if (n == NULL)
die("insert_instonelist alloc:");
n->curX = NULL;
n->instoneX = instone;
n->cutoffX = NULL;
n->nextX = (old ? old->nextX : NULL);
n->prevX = old;
n->expandedX = 0;
if (old) old->nextX = n;
if (n->nextX) n->nextX->prevX = n;
return n;
}
static void trim_instonelist_after(instonelist *first) {
if (!first->nextX) return;
first->nextX->prevX = NULL;
free_instonelist(first->nextX);
first->nextX = NULL;
}
static void free_instonelist(instonelist *l) {
instonelist *p, *k;
if (!l) return;
for (p = l; p->nextX; p = p->nextX);
do {
k = p;
p = k->prevX;
free_collpackagelist(k->instoneX);
block_free(k, sizeof(instonelist));
} while (k != l);
}
static int caninstall(dpkg_packages *pkgs, dpkg_collected_package *cpkg) {
collpackagelist *conflicts;
collpackagelist *conf;
int okay;
if (cpkg->installed > 0) return 1;
if (cpkg->conflicted > 0) return 0;
conflicts = get_matching(pkgs, cpkg->pkg->conflicts, __LINE__);
okay = 1;
for (conf = conflicts; conf != NULL; conf = conf->next) {
if (conf->value->installed > 0) {
okay = 0;
break;
}
}
free_collpackagelist(conflicts);
return okay;
}
static void install(dpkg_packages *pkgs, dpkg_collected_package *cpkg) {
if (cpkg->installed == 0) {
collpackagelist *conflicts = get_matching(pkgs, cpkg->pkg->conflicts, __LINE__);
collpackagelist *conf;
for (conf = conflicts; conf != NULL; conf = conf->next) {
if (conf->value == cpkg) continue;
assert(conf->value->installed == 0);
conf->value->conflicted++;
}
free_collpackagelist(conflicts);
}
assert(cpkg->conflicted == 0);
cpkg->installed++;
}
static void uninstall(dpkg_packages *pkgs, dpkg_collected_package *cpkg) {
assert(cpkg->installed > 0);
assert(cpkg->conflicted == 0);
cpkg->installed--;
if (cpkg->installed == 0) {
collpackagelist *conflicts = get_matching(pkgs, cpkg->pkg->conflicts, __LINE__);
collpackagelist *conf;
for (conf = conflicts; conf != NULL; conf = conf->next) {
if (conf->value == cpkg) continue;
assert(conf->value->installed == 0);
assert(conf->value->conflicted > 0);
conf->value->conflicted--;
}
free_collpackagelist(conflicts);
}
}
int checkinstallable2(dpkg_packages *pkgs, char *pkgname) {
dpkg_collected_package *cpkg = lookup_packagetbl(pkgs->packages, pkgname);
collpackagelist *cpl = NULL;
if (cpkg == NULL) return 0;
insert_collpackagelist(&cpl, cpkg);
/* cpl gets freed in checkinstallable :-/ */
return checkinstallable(pkgs, cpl);
}
static void debug_checkinstallable(FILE *out, instonelist *list,
instonelist *last, instonelist *pointer)
{
instonelist *l;
fprintf(out, "Status:");
/* codes: | = multiple options here
* @ = no options can satisfy this dep
* + = dependencies that can be expanded have been
* * = nothing selected yet
* > = where pointer points
* ^ = the cut point for where we are
*/
for (l = list; ; l = I1NEXT(l)) {
fprintf(out, " ");
if (l == pointer) fprintf(out, ">");
if (l == I1CUTOFF(pointer)) fprintf(out, "^");
if (I1INSTONE(l) == NULL) {
fprintf(out, "@");
} else {
if (I1INSTONE(l)->next != NULL) {
fprintf(out, "|");
}
if (I1EXPANDED(l)) {
fprintf(out, "+");
}
if (I1CUR(l) == NULL) {
fprintf(out, "*%s", I1INSTONE(l)->value->pkg->package);
} else {
fprintf(out, "%s", I1CUR(l)->value->pkg->package);
}
}
if (l == last) break;
}
fprintf(out, " ###\n");
fflush(out);
}
static int checkinstallable(dpkg_packages *pkgs, collpackagelist *instoneof) {
/* We use pkg->installed, pkg->conflicted to note how many
* times we've used this pkg to satisfy a dependency or installed
* a package that conflicts with it.
* Thus: pkg->installed == 0, or pkg->conflicted == 0
*
* We assume these are okay initially, aren't being played with
* concurrently elsewhere, and make sure they're still okay when
* we return.
*/
instonelist *list;
instonelist *last;
instonelist *pointer;
unsigned long counter = 10000000;
{
collpackagelist *cpkg;
for (cpkg = instoneof; cpkg; cpkg = cpkg->next) {
if (cpkg->value->installable == YES) {
free_collpackagelist(instoneof);
return 1;
}
}
}
list = insert_instonelist(NULL, instoneof);
last = list;
pointer = list;
while(--counter > 0 && pointer) {
deplistlist *dep;
dpkg_collected_package *instpkg; /* convenient alias */
int i;
#ifndef NDEBUG
{
instonelist *p;
for (p = list; p != pointer; p = I1NEXT(p)) {
assert(p != NULL);
assert(I1CUR(p) != NULL);
assert(I1CUR(p)->value != NULL);
assert(I1CUR(p)->value->installed > 0);
assert(I1CUR(p)->value->conflicted == 0);
}
if (I1NEXT(pointer) == NULL) {
assert(pointer == last);
} else {
for (p = I1NEXT(pointer); p; p = I1NEXT(p)) {
if (I1NEXT(p) == NULL) {
assert(p == last);
}
assert(I1CUR(p) == NULL);
}
}
}
#endif
#ifdef DIAGNOSE
debug_checkinstallable(stdout, list, last, pointer);
#endif
if (I1CUR(pointer) == NULL) {
I1CUR(pointer) = I1INSTONE(pointer);
/* try to choose an already installed package if there is one */
while (I1CUR(pointer) != NULL) {
if (I1CUR(pointer)->value->installed != 0) {
break;
}
I1CUR(pointer) = I1CUR(pointer)->next;
}
if (I1CUR(pointer) == NULL) {
I1CUR(pointer) = I1INSTONE(pointer);
}
assert(I1CUR(pointer) || !I1INSTONE(pointer));
I1CUTOFF(pointer) = last;
} else {
uninstall(pkgs, I1CUR(pointer)->value);
trim_instonelist_after(I1CUTOFF(pointer));
last = I1CUTOFF(pointer);
if (I1CUR(pointer)->value->installed > 0) {
/* this dependency isn't the issue -- even doing
* nothing to satisfy it (ie, using an already
* installed package) doesn't do any good. So give up.
*/
I1CUR(pointer) = NULL;
} else {
I1CUR(pointer) = I1CUR(pointer)->next;
}
}
while(I1CUR(pointer) && !caninstall(pkgs, I1CUR(pointer)->value)) {
I1CUR(pointer) = I1CUR(pointer)->next;
}
if (I1CUR(pointer) == NULL) {
if (I1PREV(pointer) == NULL) break;
pointer = I1PREV(pointer);
continue;
}
instpkg = I1CUR(pointer)->value;
install(pkgs, instpkg);
assert(instpkg->installed > 0);
if (instpkg->installed == 1) {
/* if it's been installed exactly once, then this must've been
* the first time it was touched, so we need to look at the
* dependencies. If it's the second or later, then we don't care
* about them.
*/
/* if any of the deps can't be satisfied, don't move on */
int bother = 1;
int expanded = I1EXPANDED(pointer);
for (i = 0; i < 4; i++) {
if (!dependency_counts[i]) continue;
for (dep = instpkg->pkg->depends[i];
dep != NULL; dep = dep->next)
{
collpackagelist *thisdep = get_matching(pkgs, dep->value, __LINE__);
if (thisdep == NULL) {
bother = 0;
} else if (thisdep != NULL && thisdep->next == NULL) {
collpackagelist *x;
/* if there's only one way of fulfilling this dep,
* do it "ASAP"
*/
/* optimisation: if thisdep == foo, but the parent
* was foo|bar, then we already know "foo" is not going
* to work in this combination, and we can skip it.
*
* This deals with cases like X deps: Y|bar, bar deps: Y
* where bar is a virtual package; cf xlibs
*/
for (x = I1INSTONE(pointer); x != I1CUR(pointer); x = x->next) {
if (x->value == thisdep->value) {
bother = 0;
break;
}
}
if (I1INSTONE(pointer)->next == NULL) {
/* the parent of this entry essentially depends
* on this too, so we'll get it out of the way
* ASAP, to reduce the degree of exponentiation
* in bad cases.
*
* _However_ we only want to do this _once_ for
* any particular node.
*/
if (expanded) {
/* thisdep isn't used! */
free_collpackagelist(thisdep);
} else {
insert_instonelist(pointer, thisdep);
I1EXPANDED(pointer) = 1;
}
} else {
insert_instonelist(I1CUTOFF(pointer), thisdep);
}
if (I1NEXT(last)) last = I1NEXT(last);
assert(!I1NEXT(last));
} else {
/* otherwise it's a multi possibility dep, so do it
* at the end
*/
last = insert_instonelist(last, thisdep);
}
}
}
if (!bother) {
/* stay where we are, and try the next possibility */
continue;
}
}
pointer = I1NEXT(pointer);
}
if (counter == 0) {
unsigned int package_count = 0;
fprintf(stderr, "AIEEE: counter overflow:");
assert(pointer != NULL);
if (I1CUR(pointer) == NULL || I1CUR(pointer)->value == NULL) {
/* we're not guaranteed that pointer will make sense here */
pointer = I1PREV(pointer);
}
for (; pointer != NULL; pointer = I1PREV(pointer)) {
if (I1CUR(pointer) == NULL) {
/* should only happen at pointer, so not here */
fprintf(stderr, " >> eep, no packages at pointer <<");
continue;
}
if (I1CUR(pointer)->value == NULL) {
/* should never happen */
fprintf(stderr, " >> eep, no package selected <<");
continue;
}
/* the full list is no as interesting as the "guilty" package,
* display the number of involved packages instead */
#if 0
fprintf(stderr, " %s%s",
(I1INSTONE(pointer)->next == NULL ? "" : "|"),
I1CUR(pointer)->value->pkg->package);
#endif
package_count++;
uninstall(pkgs, I1CUR(pointer)->value);
}
fprintf(stderr, " %u involved packages.\n", package_count);
free_instonelist(list);
/* let the caller know we hit a bad failure */
return -1;
}
if (pointer == NULL) {
dpkg_collected_package *cpkg = I1CUR(list)->value;
assert(cpkg->installable != YES);
cpkg->installable = YES;
for (pointer = last; pointer != NULL; pointer = I1PREV(pointer)) {
if (I1CUR(pointer)->value->installed == 1) {
packagenamelist **p = &I1CUR(pointer)->value->mayaffect;
#if 0
while ( *p && (*p)->value < cpkg->pkg->package ) {
p = &(*p)->next;
}
if (*p == NULL || (*p)->value > cpkg->pkg->package)
#endif
{
insert_packagenamelist(p, cpkg->pkg->package);
}
}
uninstall(pkgs, I1CUR(pointer)->value);
}
free_instonelist(list);
return 1;
} else {
assert(I1CUR(list) == NULL);
free_instonelist(list);
return 0;
}
}