- rescusitate --rebuild.
[platform/upstream/rpm.git] / lib / problems.c
1 /**
2  * \file lib/problems.c
3  */
4
5 #include "system.h"
6
7 #include <rpmlib.h>
8
9 #include "rpmts.h"
10
11 #include "misc.h"
12 #include "debug.h"
13
14 /*@access fnpyKey@*/
15 /*@access rpmProblem@*/
16 /*@access rpmProblemSet@*/
17
18 /*@unchecked@*/
19 static int _ps_debug = 0;
20
21 rpmProblemSet XrpmpsUnlink(rpmProblemSet ps, const char * msg,
22                 const char * fn, unsigned ln)
23 {
24 /*@-modfilesystem@*/
25 if (_ps_debug)
26 fprintf(stderr, "--> ps %p -- %d %s at %s:%u\n", ps, ps->nrefs, msg, fn, ln);
27 /*@=modfilesystem@*/
28     ps->nrefs--;
29     return NULL;
30 }
31
32 rpmProblemSet XrpmpsLink(rpmProblemSet ps, const char * msg,
33                 const char * fn, unsigned ln)
34 {
35     ps->nrefs++;
36 /*@-modfilesystem@*/
37 if (_ps_debug)
38 fprintf(stderr, "--> ps %p ++ %d %s at %s:%u\n", ps, ps->nrefs, msg, fn, ln);
39 /*@=modfilesystem@*/
40     /*@-refcounttrans@*/ return ps; /*@=refcounttrans@*/
41 }
42
43 rpmProblemSet rpmProblemSetCreate(void)
44 {
45     rpmProblemSet ps;
46
47     ps = xcalloc(1, sizeof(*ps));
48     ps->numProblems = ps->numProblemsAlloced = 0;
49     ps->probs = NULL;
50     ps->nrefs = 0;
51
52     return rpmpsLink(ps, "create");
53 }
54
55 /* XXX FIXME: merge into problems */
56 rpmProblem rpmdepFreeConflicts(rpmProblem probs, int numProblems)
57 {
58     int i;
59
60     if (probs != NULL)
61     for (i = 0; i < numProblems; i++) {
62         rpmProblem p = probs + i;
63         p->pkgNEVR = _free(p->pkgNEVR);
64         p->altNEVR = _free(p->altNEVR);
65         p->str1 = _free(p->str1);
66     }
67     probs = _free(probs);
68     return NULL;
69 }
70
71 rpmProblemSet rpmProblemSetFree(rpmProblemSet ps)
72 {
73     if (ps == NULL) return NULL;
74     if (ps->nrefs > 1)
75         return rpmpsUnlink(ps, "dereference");
76         
77     if (ps->probs) {
78         int i;
79         for (i = 0; i < ps->numProblems; i++) {
80             rpmProblem p = ps->probs + i;
81             p->pkgNEVR = _free(p->pkgNEVR);
82             p->altNEVR = _free(p->altNEVR);
83             p->str1 = _free(p->str1);
84         }
85     }
86     (void) rpmpsUnlink(ps, "destroy");
87     /*@-refcounttrans -usereleased@*/
88     ps = _free(ps);
89     /*@=refcounttrans =usereleased@*/
90     return NULL;
91 }
92
93 void rpmProblemSetAppend(rpmProblemSet ps, rpmProblemType type,
94                 const char * pkgNEVR, fnpyKey key,
95                 const char * dn, const char * bn,
96                 const char * altNEVR, unsigned long ulong1)
97 {
98     rpmProblem p;
99     char *t;
100
101     if (ps == NULL) return;
102
103     if (ps->numProblems == ps->numProblemsAlloced) {
104         if (ps->numProblemsAlloced)
105             ps->numProblemsAlloced *= 2;
106         else
107             ps->numProblemsAlloced = 2;
108         ps->probs = xrealloc(ps->probs,
109                         ps->numProblemsAlloced * sizeof(*ps->probs));
110     }
111
112     p = ps->probs + ps->numProblems;
113     ps->numProblems++;
114     memset(p, 0, sizeof(*p));
115
116     p->type = type;
117     p->key = key;
118     p->ulong1 = ulong1;
119     p->ignoreProblem = 0;
120
121     p->pkgNEVR = (pkgNEVR ? xstrdup(pkgNEVR) : NULL);
122     p->altNEVR = (altNEVR ? xstrdup(altNEVR) : NULL);
123
124     p->str1 = NULL;
125     if (dn != NULL || bn != NULL) {
126         t = xcalloc(1,  (dn != NULL ? strlen(dn) : 0) +
127                         (bn != NULL ? strlen(bn) : 0) + 1);
128         p->str1 = t;
129         if (dn != NULL) t = stpcpy(t, dn);
130         if (bn != NULL) t = stpcpy(t, bn);
131     }
132 }
133
134 #define XSTRCMP(a, b) ((!(a) && !(b)) || ((a) && (b) && !strcmp((a), (b))))
135
136 int rpmProblemSetTrim(rpmProblemSet ps, rpmProblemSet filter)
137 {
138     rpmProblem t;
139     rpmProblem f;
140     int gotProblems = 0;
141
142     if (ps == NULL || ps->numProblems == 0)
143         return 0;
144
145     if (filter == NULL)
146         return (ps->numProblems == 0 ? 0 : 1);
147
148     t = ps->probs;
149     f = filter->probs;
150
151     /*@-branchstate@*/
152     while ((f - filter->probs) < filter->numProblems) {
153         if (!f->ignoreProblem) {
154             f++;
155             continue;
156         }
157         while ((t - ps->probs) < ps->numProblems) {
158             /*@-nullpass@*/     /* LCL: looks good to me <shrug> */
159             if (f->type == t->type && t->key == f->key &&
160                      XSTRCMP(f->str1, t->str1))
161                 /*@innerbreak@*/ break;
162             /*@=nullpass@*/
163             t++;
164             gotProblems = 1;
165         }
166
167         /* XXX This can't happen, but let's be sane in case it does. */
168         if ((t - ps->probs) == ps->numProblems)
169             break;
170
171         t->ignoreProblem = f->ignoreProblem;
172         t++, f++;
173     }
174     /*@=branchstate@*/
175
176     if ((t - ps->probs) < ps->numProblems)
177         gotProblems = 1;
178
179     return gotProblems;
180 }
181
182 /* XXX FIXME: merge into problems */
183 /* XXX used in verify.c rpmlibprov.c */
184 void printDepFlags(FILE * fp, const char * version, int flags)
185 {
186     if (flags)
187         fprintf(fp, " ");
188
189     if (flags & RPMSENSE_LESS) 
190         fprintf(fp, "<");
191     if (flags & RPMSENSE_GREATER)
192         fprintf(fp, ">");
193     if (flags & RPMSENSE_EQUAL)
194         fprintf(fp, "=");
195
196     if (flags)
197         fprintf(fp, " %s", version);
198 }
199
200 #if !defined(HAVE_VSNPRINTF)
201 /*@-shadow -bufferoverflowhigh @*/
202 static inline int vsnprintf(/*@out@*/ char * buf, /*@unused@*/ int nb,
203         const char * fmt, va_list ap)
204 {
205     return vsprintf(buf, fmt, ap);
206 }
207 /*@=shadow =bufferoverflowhigh @*/
208 #endif
209 #if !defined(HAVE_SNPRINTF)
210 static inline int snprintf(/*@out@*/ char * buf, int nb, const char * fmt, ...)
211 {
212     va_list ap;
213     int rc;
214     va_start(ap, fmt);
215     rc = vsnprintf(buf, nb, fmt, ap);
216     va_end(ap);
217     return rc;
218 }
219 #endif
220
221 const char * rpmProblemString(const rpmProblem prob)
222 {
223 /*@observer@*/
224     const char * pkgNEVR = (prob->pkgNEVR ? prob->pkgNEVR : "?pkgNEVR?");
225 /*@observer@*/
226     const char * altNEVR = (prob->altNEVR ? prob->altNEVR : "?altNEVR?");
227 /*@observer@*/
228     const char * str1 = (prob->str1 ? prob->str1 : N_("different"));
229     int nb =    strlen(pkgNEVR) + strlen(str1) + strlen(altNEVR) + 100;
230     char * buf = xmalloc(nb+1);
231     int rc;
232
233     switch (prob->type) {
234     case RPMPROB_BADARCH:
235         rc = snprintf(buf, nb,
236                 _("package %s is intended for a %s architecture"),
237                 pkgNEVR, str1);
238         break;
239     case RPMPROB_BADOS:
240         rc = snprintf(buf, nb,
241                 _("package %s is intended for a %s operating system"),
242                 pkgNEVR, str1);
243         break;
244     case RPMPROB_PKG_INSTALLED:
245         rc = snprintf(buf, nb,
246                 _("package %s is already installed"),
247                 pkgNEVR);
248         break;
249     case RPMPROB_BADRELOCATE:
250         rc = snprintf(buf, nb,
251                 _("path %s in package %s is not relocateable"),
252                 str1, pkgNEVR);
253         break;
254     case RPMPROB_NEW_FILE_CONFLICT:
255         rc = snprintf(buf, nb,
256                 _("file %s conflicts between attempted installs of %s and %s"),
257                 str1, pkgNEVR, altNEVR);
258         break;
259     case RPMPROB_FILE_CONFLICT:
260         rc = snprintf(buf, nb,
261             _("file %s from install of %s conflicts with file from package %s"),
262                 str1, pkgNEVR, altNEVR);
263         break;
264     case RPMPROB_OLDPACKAGE:
265         rc = snprintf(buf, nb,
266                 _("package %s (which is newer than %s) is already installed"),
267                 altNEVR, pkgNEVR);
268         break;
269     case RPMPROB_DISKSPACE:
270         rc = snprintf(buf, nb,
271             _("installing package %s needs %ld%cb on the %s filesystem"),
272                 pkgNEVR,
273                 prob->ulong1 > (1024*1024)
274                     ? (prob->ulong1 + 1024 * 1024 - 1) / (1024 * 1024)
275                     : (prob->ulong1 + 1023) / 1024,
276                 prob->ulong1 > (1024*1024) ? 'M' : 'K',
277                 str1);
278         break;
279     case RPMPROB_DISKNODES:
280         rc = snprintf(buf, nb,
281             _("installing package %s needs %ld inodes on the %s filesystem"),
282                 pkgNEVR, (long)prob->ulong1, str1);
283         break;
284     case RPMPROB_BADPRETRANS:
285         rc = snprintf(buf, nb,
286                 _("package %s pre-transaction syscall(s): %s failed: %s"),
287                 pkgNEVR, str1, strerror(prob->ulong1));
288         break;
289     case RPMPROB_REQUIRES:
290         rc = snprintf(buf, nb, _("package %s has unsatisfied Requires: %s\n"),
291                 pkgNEVR, altNEVR+2);
292         break;
293     case RPMPROB_CONFLICT:
294         rc = snprintf(buf, nb, _("package %s has unsatisfied Conflicts: %s\n"),
295                 pkgNEVR, altNEVR+2);
296         break;
297     default:
298         rc = snprintf(buf, nb,
299                 _("unknown error %d encountered while manipulating package %s"),
300                 prob->type, pkgNEVR);
301         break;
302     }
303
304     buf[nb] = '\0';
305     return buf;
306 }
307
308 void rpmProblemPrint(FILE *fp, rpmProblem prob)
309 {
310     const char * msg = rpmProblemString(prob);
311     fprintf(fp, "%s\n", msg);
312     msg = _free(msg);
313 }
314
315 void rpmProblemSetPrint(FILE *fp, rpmProblemSet ps)
316 {
317     int i;
318
319     if (ps == NULL)
320         return;
321
322     if (fp == NULL)
323         fp = stderr;
324
325     for (i = 0; i < ps->numProblems; i++) {
326         rpmProblem myprob = ps->probs + i;
327         if (!myprob->ignoreProblem)
328             rpmProblemPrint(fp, myprob);
329     }
330 }
331
332 static int sameProblem(const rpmProblem ap, const rpmProblem bp)
333         /*@*/
334 {
335     if (ap->type != bp->type)
336         return 1;
337     if (ap->pkgNEVR)
338         if (bp->pkgNEVR && strcmp(ap->pkgNEVR, bp->pkgNEVR))
339             return 1;
340     if (ap->altNEVR)
341         if (bp->altNEVR && strcmp(ap->altNEVR, bp->altNEVR))
342             return 1;
343     if (ap->str1)
344         if (bp->str1 && strcmp(ap->str1, bp->str1))
345             return 1;
346
347     if (ap->ulong1 != bp->ulong1)
348         return 1;
349
350     return 0;
351 }
352
353 /* XXX FIXME: merge into rpmProblemSetPrint */
354 void printDepProblems(FILE * fp, rpmProblem probs, int numProblems)
355 {
356     const char * pkgNEVR, * altNEVR;
357     rpmProblem p;
358     int i;
359
360     if (probs != NULL)
361     for (i = 0; i < numProblems; i++) {
362         int j;
363
364         p = probs + i;
365
366         /* Filter already displayed problems. */
367         for (j = 0; j < i; j++) {
368             if (!sameProblem(p, probs + j))
369                 /*@innerbreak@*/ break;
370         }
371         if (j < i)
372             continue;
373
374         pkgNEVR = (p->pkgNEVR ? p->pkgNEVR : "?pkgNEVR?");
375         altNEVR = (p->altNEVR ? p->altNEVR : "? ?altNEVR?");
376
377         fprintf(fp, "\t%s %s %s\n", altNEVR+2,
378                 ((altNEVR[0] == 'C' && altNEVR[1] == ' ')
379                         ?  _("conflicts with") : _("is needed by")),
380                 pkgNEVR);
381     }
382 }