24
char *predepends, *depends, *recommends, *suggests, *provides, *tasks;
25
unsigned short installed:1;
26
unsigned short keep:1;
27
unsigned short nokeep:1;
30
/* Life is all about priorities */
31
static const char *debian_priorities[] = {
41
static AVLTree *priorities = NULL, *keepsections = NULL, *nokeepsections = NULL, *guessdepends = NULL;
47
if(r>=0 && s[r] == '\n') {
49
if(r>=0 && s[r] == '\r')
58
while(r>=0 && strchr(" \t\n\r", s[r]))
60
while(*s && strchr(" \t\n\r", *s))
65
int pkgcmp(struct package *a, struct package *b) {
66
return symcmp(a->name, b->name);
69
struct package *pkg_find(symbol_t s) {
73
n = AVLSearch(packages, &p);
74
return n ? (struct package *)n->item : NULL;
77
void free_package(struct package *pkg) {
78
AVLFreeNodes(&pkg->depends);
79
AVLFreeNodes(&pkg->dependents);
80
AVLFreeNodes(&pkg->provides);
81
AVLFreeNodes(&pkg->providers);
85
struct package *new_package(symbol_t s) {
88
pkg = xmalloc(sizeof(struct package));
90
pkg->provider_count = 0;
91
pkg->orphan_depends = 0;
95
AVLInitTree(&pkg->depends, (AVLCompare)strcasecmp, NULL);
96
AVLInitTree(&pkg->dependents, (AVLCompare)strcasecmp, NULL);
97
AVLInitTree(&pkg->provides, (AVLCompare)strcasecmp, NULL);
98
AVLInitTree(&pkg->providers, (AVLCompare)strcasecmp, NULL);
102
struct package *get_package(symbol_t s)
104
struct package *pkg = pkg_find(s);
106
pkg = new_package(s);
107
if (!AVLInsert(packages, pkg))
108
perror_exit(ERROR_SYSTEM, "AVLInsert()");
113
static void process_dep(AVLTree *t, char *s) {
114
struct package *pkg, *ppkg;
115
char *dep = s, *str = s;
117
int alternative_depend = 0;
126
while (*str && *str++ != ')');
135
ppkg = get_package(name);
136
if(alternative_depend) {
137
while (s && (dep = strsep(&s, "|"))) {
138
pkg = get_package(symbol(dep));
139
AVLInsert(&pkg->provides, name);
142
alternative_depend = 0;
147
alternative_depend = 1;
155
static void process_package(struct pinfo *p) {
156
static struct pinfo null = {0};
159
if(p->name && p->installed) {
160
symbol_t name = symbol(p->name);
161
pkg = get_package(name);
164
pkg->nokeep = p->nokeep;
165
process_dep(&pkg->provides, p->provides);
166
process_dep(&pkg->depends, p->predepends);
167
process_dep(&pkg->depends, p->depends);
168
process_dep(&pkg->depends, p->recommends);
169
process_dep(&pkg->depends, p->suggests);
190
static void process_available(struct pinfo *p) {
191
static struct pinfo null = {0};
197
if(p->name && p->tasks) {
198
symbol_t name = symbol(p->name);
199
pkg = pkg_find(name);
200
if(pkg && pkg->installed) {
201
AVLInitTree(&tasks, (AVLCompare)strcasecmp, NULL);
202
process_dep(&tasks, p->tasks);
203
while((c = tasks.head) != NULL) {
204
task_name = xstrcat("task-", (char *)c->item);
205
pkg = get_package(symbol(task_name));
206
AVLInsert(&pkg->depends, name);
209
AVLDeleteNode(&tasks, c);
232
static void parse_status(char *s, struct pinfo *p) {
235
do word = strsep(&s, " \t");
236
while(word && !*word);
238
p->keep |= !strcasecmp(word, "hold");
240
do word = strsep(&s, " \t");
241
while(word && !*word);
242
/* usually word is "ok" now */
244
do word = strsep(&s, " \t");
245
while(word && !*word);
246
p->installed = !strcasecmp(word, "installed");
249
static int parse_line(char *s, struct pinfo *p) {
250
switch(tolower(*s)) {
252
if(!strncasecmp(s+1,"epends:",7))
253
p->depends = xstrdup(chop(s+8));
256
if(UseEssential && !strncasecmp(s+1,"ssential:",9))
257
p->keep |= !strcasecmp(chop(s+10), "yes");
260
switch(tolower(s[1])) {
262
switch(tolower(s[2])) {
264
if(UsePreDepends && !strncasecmp(s+3,"-depends:",9))
265
p->predepends = xstrdup(chop(s+12));
268
if(!strncasecmp(s+3,"ority:",6))
269
p->keep |= !!AVLSearch(priorities,chop(s+9));
272
if(!strncasecmp(s+3,"vides:",6))
273
p->provides = xstrdup(chop(s+9));
278
if(!strncasecmp(s+2,"ckage:",6))
279
p->name = xstrdup(chop(s+8));
284
if(UseRecommends && !strncasecmp(s+1,"ecommends:",10))
285
p->recommends = xstrdup(chop(s+11));
288
switch(tolower(s[1])) {
290
if(!strncasecmp(s+2,"ction:",6)) {
291
char *r = strrchr(s, '/');
292
r = chop(r ? r+1 : s+8);
293
p->keep |= !!AVLSearch(keepsections, r);
294
p->nokeep |= !!AVLSearch(nokeepsections, r);
298
if(UseSuggests && !strncasecmp(s+2,"ggests:",7))
299
p->suggests = xstrdup(chop(s+9));
302
if(!strncasecmp(s+2,"atus:",5))
303
parse_status(chop(s+7), p);
308
if(!strncasecmp(s+1,"ask:",4))
309
p->tasks = xstrdup(chop(s+5));
324
typedef void (*process_func)(struct pinfo *);
325
void readlines(const char *filename, process_func process_record) {
326
struct pinfo p = {0};
333
fd = open(filename, O_RDONLY);
335
perror_exit(ERROR_SYSTEM, DpkgStatus);
338
&& S_ISREG(st.st_mode)
339
&& (buf = mmap(NULL,st.st_size,PROT_READ|PROT_WRITE,MAP_PRIVATE,fd,0))) {
340
if(buf[st.st_size-1] != '\n')
341
error_exit(ERROR_SYSTEM,
342
"%s is truncated (no trailing newline)\n", DpkgStatus);
343
buf[st.st_size-1] = '\0';
344
for(s = buf; s; s = t) {
348
if(parse_line(s, &p))
351
if(munmap(buf, st.st_size))
357
perror_exit(ERROR_SYSTEM, DpkgStatus);
358
buf = alloca(READBUF);
360
perror_exit(ERROR_SYSTEM, "alloca()");
361
while(fgets(buf, READBUF, f))
362
if(parse_line(buf, &p))
369
AVLTree *initlist(AVLTree *tree, const char *str) {
370
const char *s, *d = ", \t";
373
AVLInitTree(tree, (AVLCompare)strcasecmp, (AVLFreeItem)free);
376
for(s = str; *s; s += n + strspn(s, d)) {
378
AVLInsert(tree, xstrndup(s, n));
385
symbol_t guessbase(symbol_t name) {
389
if((s = strrchr(name, '-')) && AVLSearch(guessdepends, symbol(s+1))) {
390
n = s - (char *)name;
391
if (!(s = alloca(n+1)))
392
error_exit(ERROR_SYSTEM, "alloca()");
401
void readstatus(void) {
402
static AVLTree trees[4];
405
AVLFreeNodes(packages);
407
AVLFreeNodes(priorities);
409
priorities = AVLInitTree(trees, (AVLCompare)strcasecmp, NULL);
411
keepsections = initlist(trees+1, KeepSections);
413
nokeepsections = initlist(trees+2, NokeepSections);
415
guessdepends = initlist(trees+3, GuessDepends);
417
for(pri = debian_priorities; *pri && strcasecmp(MaxPriority, *pri); pri++)
418
AVLInsert(priorities, (char *)*pri);
420
error_exit(ERROR_CONFIG, _("Unknown priority \"%s\"\n"), MaxPriority);
422
readlines(DpkgStatus, process_package); /* Read package status */
424
readlines(DpkgAvailable, process_available); /* Read additional info */