~ubuntu-branches/debian/jessie/debfoster/jessie

« back to all changes in this revision

Viewing changes to src/status.c

  • Committer: Bazaar Package Importer
  • Author(s): Ivo Timmermans
  • Date: 2002-01-17 23:08:39 UTC
  • Revision ID: james.westby@ubuntu.com-20020117230839-s22xl5hew1z4s3r5
Tags: upstream-2.5
ImportĀ upstreamĀ versionĀ 2.5

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
#include <stdio.h>
 
2
#include <ctype.h>
 
3
#include <string.h>
 
4
#include <stdlib.h>
 
5
#include <unistd.h>
 
6
 
 
7
#include <fcntl.h>
 
8
#include <sys/stat.h>
 
9
#include <sys/mman.h>
 
10
 
 
11
#include "error.h"
 
12
#include "conffile.h"
 
13
#include "AVLTree.h"
 
14
#include "symbol.h"
 
15
#include "config.h"
 
16
#include "intl.h"
 
17
#include "status.h"
 
18
 
 
19
#define READBUF 4096
 
20
 
 
21
struct pinfo {
 
22
        char *name;
 
23
        char *section;
 
24
        char *predepends, *depends, *recommends, *suggests, *provides, *tasks;
 
25
        unsigned short installed:1;
 
26
        unsigned short keep:1;
 
27
        unsigned short nokeep:1;
 
28
};
 
29
 
 
30
/* Life is all about priorities */
 
31
static const char *debian_priorities[] = {
 
32
        "required",
 
33
        "important",
 
34
        "standard",
 
35
        "optional",
 
36
        "extra",
 
37
        "ANY",
 
38
        NULL
 
39
};
 
40
 
 
41
static AVLTree *priorities = NULL, *keepsections = NULL, *nokeepsections = NULL, *guessdepends = NULL;
 
42
AVLTree *packages;
 
43
 
 
44
int chomp(char *s) {
 
45
        int r;
 
46
        r = strlen(s)-1;
 
47
        if(r>=0 && s[r] == '\n') {
 
48
                s[r--] = '\0';
 
49
                if(r>=0 && s[r] == '\r')
 
50
                        s[r--] = '\0';
 
51
        }
 
52
        return r+2;
 
53
}
 
54
 
 
55
char *chop(char *s) {
 
56
        int r;
 
57
        r = chomp(s)-2;
 
58
        while(r>=0 && strchr(" \t\n\r", s[r]))
 
59
                s[r--] = '\0';
 
60
        while(*s && strchr(" \t\n\r", *s))
 
61
                s++;
 
62
        return s;
 
63
}
 
64
 
 
65
int pkgcmp(struct package *a, struct package *b) {
 
66
        return symcmp(a->name, b->name);
 
67
}
 
68
 
 
69
struct package *pkg_find(symbol_t s) {
 
70
        struct package p;
 
71
        AVLNode *n;
 
72
        p.name = s;
 
73
        n = AVLSearch(packages, &p);
 
74
        return n ? (struct package *)n->item : NULL;
 
75
}
 
76
 
 
77
void free_package(struct package *pkg) {
 
78
        AVLFreeNodes(&pkg->depends);
 
79
        AVLFreeNodes(&pkg->dependents);
 
80
        AVLFreeNodes(&pkg->provides);
 
81
        AVLFreeNodes(&pkg->providers);
 
82
        free(pkg);
 
83
}
 
84
 
 
85
struct package *new_package(symbol_t s) {
 
86
        struct package *pkg;
 
87
 
 
88
        pkg = xmalloc(sizeof(struct package));
 
89
        pkg->name = s;
 
90
        pkg->provider_count = 0;
 
91
        pkg->orphan_depends = 0;
 
92
        pkg->installed = 0;
 
93
        pkg->keep = 0;
 
94
        pkg->nokeep = 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);
 
99
        return pkg;
 
100
}
 
101
 
 
102
struct package *get_package(symbol_t s)
 
103
{
 
104
        struct package *pkg = pkg_find(s);
 
105
        if(!pkg) {
 
106
                pkg = new_package(s);
 
107
                if (!AVLInsert(packages, pkg))
 
108
                        perror_exit(ERROR_SYSTEM, "AVLInsert()");
 
109
        }
 
110
        return pkg;
 
111
}
 
112
 
 
113
static void process_dep(AVLTree *t, char *s) {
 
114
        struct package *pkg, *ppkg;
 
115
        char *dep = s, *str = s;
 
116
        symbol_t name;
 
117
        int alternative_depend = 0;
 
118
 
 
119
        while(s && *s) {
 
120
                switch(*str) {
 
121
                        case ' ':
 
122
                        case '\t':
 
123
                                str++;
 
124
                                break;
 
125
                        case '(':
 
126
                                while (*str && *str++ != ')');
 
127
                                break;
 
128
                        case ',':
 
129
                                str++;
 
130
                        case '\0':
 
131
                                *dep++ = '\0';
 
132
                                if (*s) {
 
133
                                        name = symbol(s);
 
134
                                        AVLInsert(t, name);
 
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);
 
140
                                                }
 
141
                                        }
 
142
                                        alternative_depend = 0;
 
143
                                        s = dep = str;
 
144
                                }
 
145
                                break;
 
146
                        case '|':
 
147
                                alternative_depend = 1;
 
148
                        default:
 
149
                                *dep++ = *str++;
 
150
                                break;
 
151
                }
 
152
        }
 
153
}
 
154
 
 
155
static void process_package(struct pinfo *p) {
 
156
        static struct pinfo null = {0};
 
157
        struct package *pkg;
 
158
 
 
159
        if(p->name && p->installed) {
 
160
                symbol_t name = symbol(p->name);
 
161
                pkg = get_package(name);
 
162
                pkg->installed  = 1;
 
163
                pkg->keep       = p->keep;
 
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);
 
170
        }
 
171
        if(p->name)
 
172
                free(p->name);
 
173
        if(p->section)
 
174
                free(p->section);
 
175
        if(p->provides)
 
176
                free(p->provides);
 
177
        if(p->predepends)
 
178
                free(p->predepends);
 
179
        if(p->depends)
 
180
                free(p->depends);
 
181
        if(p->recommends)
 
182
                free(p->recommends);
 
183
        if(p->suggests)
 
184
                free(p->suggests);
 
185
        if(p->tasks)
 
186
                free(p->tasks);
 
187
        *p = null;
 
188
}
 
189
 
 
190
static void process_available(struct pinfo *p) {
 
191
        static struct pinfo null = {0};
 
192
        struct package *pkg;
 
193
        char *task_name;
 
194
        AVLTree tasks;
 
195
        AVLNode *c;
 
196
 
 
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);
 
207
                                pkg->task = 1;
 
208
                                free(task_name);
 
209
                                AVLDeleteNode(&tasks, c);
 
210
                        }
 
211
                }
 
212
        }
 
213
        if(p->name)
 
214
                free(p->name);
 
215
        if(p->section)
 
216
                free(p->section);
 
217
        if(p->provides)
 
218
                free(p->provides);
 
219
        if(p->predepends)
 
220
                free(p->predepends);
 
221
        if(p->depends)
 
222
                free(p->depends);
 
223
        if(p->recommends)
 
224
                free(p->recommends);
 
225
        if(p->suggests)
 
226
                free(p->suggests);
 
227
        if(p->tasks)
 
228
                free(p->tasks);
 
229
        *p = null;
 
230
}
 
231
 
 
232
static void parse_status(char *s, struct pinfo *p) {
 
233
        char *word;
 
234
 
 
235
        do word = strsep(&s, " \t");
 
236
        while(word && !*word);
 
237
        if(UseHold)
 
238
                p->keep |= !strcasecmp(word, "hold");
 
239
 
 
240
        do word = strsep(&s, " \t");
 
241
        while(word && !*word);
 
242
        /* usually word is "ok" now */
 
243
 
 
244
        do word = strsep(&s, " \t");
 
245
        while(word && !*word);
 
246
        p->installed = !strcasecmp(word, "installed");
 
247
}
 
248
 
 
249
static int parse_line(char *s, struct pinfo *p) {
 
250
        switch(tolower(*s)) {
 
251
                case 'd':
 
252
                        if(!strncasecmp(s+1,"epends:",7))
 
253
                                p->depends = xstrdup(chop(s+8));
 
254
                break;
 
255
                case 'e':
 
256
                        if(UseEssential && !strncasecmp(s+1,"ssential:",9))
 
257
                                p->keep |= !strcasecmp(chop(s+10), "yes");
 
258
                break;
 
259
                case 'p':
 
260
                        switch(tolower(s[1])) {
 
261
                                case 'r':
 
262
                                        switch(tolower(s[2])) {
 
263
                                                case 'e':
 
264
                                                        if(UsePreDepends && !strncasecmp(s+3,"-depends:",9))
 
265
                                                                p->predepends = xstrdup(chop(s+12));
 
266
                                                break;
 
267
                                                case 'i':
 
268
                                                        if(!strncasecmp(s+3,"ority:",6))
 
269
                                                                p->keep |= !!AVLSearch(priorities,chop(s+9));
 
270
                                                break;
 
271
                                                case 'o':
 
272
                                                        if(!strncasecmp(s+3,"vides:",6))
 
273
                                                                p->provides = xstrdup(chop(s+9));
 
274
                                                break;
 
275
                                        }
 
276
                                break;
 
277
                                case 'a':
 
278
                                        if(!strncasecmp(s+2,"ckage:",6))
 
279
                                                p->name = xstrdup(chop(s+8));
 
280
                                break;
 
281
                        }
 
282
                break;
 
283
                case 'r':
 
284
                        if(UseRecommends && !strncasecmp(s+1,"ecommends:",10))
 
285
                                p->recommends = xstrdup(chop(s+11));
 
286
                break;
 
287
                case 's':
 
288
                        switch(tolower(s[1])) {
 
289
                                case 'e':
 
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);
 
295
                                        }
 
296
                                break;
 
297
                                case 'u':
 
298
                                        if(UseSuggests && !strncasecmp(s+2,"ggests:",7))
 
299
                                                p->suggests = xstrdup(chop(s+9));
 
300
                                break;
 
301
                                case 't':
 
302
                                        if(!strncasecmp(s+2,"atus:",5))
 
303
                                                parse_status(chop(s+7), p);
 
304
                                break;
 
305
                        }
 
306
                break;
 
307
                case 't':
 
308
                        if(!strncasecmp(s+1,"ask:",4))
 
309
                                p->tasks = xstrdup(chop(s+5));
 
310
                break;
 
311
                case ' ':
 
312
                case '\t':
 
313
                case '\r':
 
314
                        if(!*chop(s))
 
315
                                return 1;
 
316
                        break;
 
317
                case '\0':
 
318
                case '\n':
 
319
                        return 1;
 
320
        }
 
321
        return 0;
 
322
}
 
323
 
 
324
typedef void (*process_func)(struct pinfo *);
 
325
void readlines(const char *filename, process_func process_record) {
 
326
        struct pinfo p = {0};
 
327
        FILE *f;
 
328
        int fd;
 
329
        char *buf;
 
330
        char *s, *t;
 
331
        struct stat st;
 
332
 
 
333
        fd = open(filename, O_RDONLY);
 
334
        if(fd<0)
 
335
                perror_exit(ERROR_SYSTEM, DpkgStatus);
 
336
 
 
337
        if(!fstat(fd, &st)
 
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) {
 
345
                        t = strchr(s, '\n');
 
346
                        if(t)
 
347
                                *t++ = '\0';
 
348
                        if(parse_line(s, &p))
 
349
                                process_record(&p);
 
350
                }
 
351
                if(munmap(buf, st.st_size))
 
352
                        perror("munmap()");
 
353
                close(fd);
 
354
        } else {
 
355
                f = fdopen(fd, "r");
 
356
                if(!f)
 
357
                        perror_exit(ERROR_SYSTEM, DpkgStatus);
 
358
                buf = alloca(READBUF);
 
359
                if(!buf)
 
360
                        perror_exit(ERROR_SYSTEM, "alloca()");
 
361
                while(fgets(buf, READBUF, f))
 
362
                        if(parse_line(buf, &p))
 
363
                                process_record(&p);
 
364
                fclose(f);
 
365
        }
 
366
        process_record(&p);
 
367
}
 
368
 
 
369
AVLTree *initlist(AVLTree *tree, const char *str) {
 
370
        const char *s, *d = ", \t";
 
371
        int n;
 
372
 
 
373
        AVLInitTree(tree, (AVLCompare)strcasecmp, (AVLFreeItem)free);
 
374
 
 
375
        if (str) {
 
376
                for(s = str; *s; s += n + strspn(s, d)) {
 
377
                        n = strcspn(s, d);
 
378
                        AVLInsert(tree, xstrndup(s, n));
 
379
                }
 
380
        }
 
381
 
 
382
        return tree;
 
383
}
 
384
 
 
385
symbol_t guessbase(symbol_t name) {
 
386
        char *s;
 
387
        int n;
 
388
 
 
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()");
 
393
                strncpy(s, name, n);
 
394
                s[n] = '\0';
 
395
                return symbol(s);
 
396
        }
 
397
 
 
398
        return NULL;
 
399
}
 
400
 
 
401
void readstatus(void) {
 
402
        static AVLTree trees[4];
 
403
        const char **pri;
 
404
 
 
405
        AVLFreeNodes(packages);
 
406
        if(priorities)
 
407
                AVLFreeNodes(priorities);
 
408
        else
 
409
                priorities = AVLInitTree(trees, (AVLCompare)strcasecmp, NULL);
 
410
        if(!keepsections)
 
411
                keepsections = initlist(trees+1, KeepSections);
 
412
        if(!nokeepsections)
 
413
                nokeepsections = initlist(trees+2, NokeepSections);
 
414
        if(!guessdepends)
 
415
                guessdepends = initlist(trees+3, GuessDepends); 
 
416
 
 
417
        for(pri = debian_priorities; *pri && strcasecmp(MaxPriority, *pri); pri++)
 
418
                AVLInsert(priorities, (char *)*pri);
 
419
        if(!*pri)
 
420
                error_exit(ERROR_CONFIG, _("Unknown priority \"%s\"\n"), MaxPriority);
 
421
 
 
422
        readlines(DpkgStatus, process_package);         /* Read package status */
 
423
        if(UseTasks)
 
424
                readlines(DpkgAvailable, process_available);    /* Read additional info */
 
425
}