Sanitize python object -> tag number exception handling
[platform/upstream/rpm.git] / lib / rpmps.c
1 /**
2  * \file lib/rpmps.c
3  */
4
5 #include "system.h"
6
7 #include <inttypes.h>
8
9 #include <rpm/rpmstring.h>
10 #include <rpm/rpmps.h>
11
12 #include "debug.h"
13
14 /**
15  */
16 struct rpmProblem_s {
17     char * pkgNEVR;
18     char * altNEVR;
19     fnpyKey key;
20     rpmProblemType type;
21     int ignoreProblem;
22     char * str1;
23     uint64_t num1;
24     int nrefs;
25 };
26
27 /**
28  */
29 struct rpmps_s {
30     int numProblems;            /*!< Current probs array size. */
31     int numProblemsAlloced;     /*!< Allocated probs array size. */
32     rpmProblem *probs;          /*!< Array of pointers to specific problems. */
33     int nrefs;                  /*!< Reference count. */
34 };
35
36 struct rpmpsi_s {
37     int ix;
38     rpmps ps;
39 };
40
41
42 int _rpmps_debug = 0;
43
44 rpmps rpmpsUnlink(rpmps ps, const char * msg)
45 {
46     if (ps) {
47         ps->nrefs--;
48     }
49     return NULL;
50 }
51
52 rpmps rpmpsLink(rpmps ps, const char * msg)
53 {
54     if (ps) {
55         ps->nrefs++;
56     }
57     return ps;
58 }
59
60 int rpmpsNumProblems(rpmps ps)
61 {
62     int numProblems = 0;
63     if (ps && ps->probs)
64         numProblems = ps->numProblems;
65     return numProblems;
66 }
67
68 rpmpsi rpmpsInitIterator(rpmps ps)
69 {
70     rpmpsi psi = NULL;
71     if (ps != NULL) {
72         psi = xcalloc(1, sizeof(*psi));
73         psi->ps = rpmpsLink(ps, RPMDBG_M("rpmpsInitIterator"));
74         psi->ix = -1;
75     }
76     return psi;
77 }
78
79 rpmpsi rpmpsFreeIterator(rpmpsi psi)
80 {
81     if (psi != NULL) {
82         rpmpsUnlink(psi->ps, RPMDBG_M("rpmpsFreeIterator"));
83         free(psi);
84         psi = NULL;
85     }
86     return psi;
87 }
88
89 int rpmpsNextIterator(rpmpsi psi)
90 {
91     int i = -1;
92
93     if (psi != NULL && ++psi->ix >= 0) {
94         if (psi->ix < rpmpsNumProblems(psi->ps)) {
95             i = psi->ix;
96         } else {
97             psi->ix = -1;
98         }            
99     }
100     return i;
101 }
102
103 rpmProblem rpmpsGetProblem(rpmpsi psi)
104 {
105     rpmProblem *p = NULL;
106     if (psi != NULL && psi->ix >= 0 && psi->ix < rpmpsNumProblems(psi->ps)) {
107         p = psi->ps->probs + psi->ix;
108     } 
109     return p ? *p : NULL;
110 }
111
112 rpmps rpmpsCreate(void)
113 {
114     rpmps ps = xcalloc(1, sizeof(*ps));
115     return rpmpsLink(ps, RPMDBG_M("rpmpsCreate"));
116 }
117
118 rpmps rpmpsFree(rpmps ps)
119 {
120     if (ps == NULL) return NULL;
121     if (ps->nrefs > 1) {
122         return rpmpsUnlink(ps, RPMDBG_M("rpmpsFree"));
123     }
124         
125     if (ps->probs) {
126         rpmpsi psi = rpmpsInitIterator(ps);
127         while (rpmpsNextIterator(psi) >= 0) {
128             rpmProblemFree(rpmpsGetProblem(psi));       
129         }
130         rpmpsFreeIterator(psi);
131         ps->probs = _free(ps->probs);
132     }
133     ps = _free(ps);
134     return NULL;
135 }
136
137 void rpmpsAppendProblem(rpmps ps, rpmProblem prob)
138 {
139     rpmProblem *p = NULL;
140     if (ps == NULL) return;
141
142     if (ps->numProblems == ps->numProblemsAlloced) {
143         if (ps->numProblemsAlloced)
144             ps->numProblemsAlloced *= 2;
145         else
146             ps->numProblemsAlloced = 2;
147         ps->probs = xrealloc(ps->probs,
148                         ps->numProblemsAlloced * sizeof(ps->probs));
149     }
150
151     p = ps->probs + ps->numProblems;
152     ps->numProblems++;
153     *p = rpmProblemLink(prob);
154 }
155
156 void rpmpsAppend(rpmps ps, rpmProblemType type,
157                 const char * pkgNEVR, fnpyKey key,
158                 const char * dn, const char * bn,
159                 const char * altNEVR, uint64_t number)
160 {
161     rpmProblem p = NULL;
162     if (ps == NULL) return;
163
164     p = rpmProblemCreate(type, pkgNEVR, key, dn, bn, altNEVR, number);
165     rpmpsAppendProblem(ps, p);
166     rpmProblemFree(p);
167 }
168
169 #define XSTRCMP(a, b) ((!(a) && !(b)) || ((a) && (b) && rstreq((a), (b))))
170
171 /* XXX TODO: implement with iterators */
172 int rpmpsTrim(rpmps ps, rpmps filter)
173 {
174     rpmProblem *t;
175     rpmProblem *f;
176     int gotProblems = 0;
177
178     if (ps == NULL || ps->numProblems == 0)
179         return 0;
180
181     if (filter == NULL)
182         return (ps->numProblems == 0 ? 0 : 1);
183
184     t = ps->probs;
185     f = filter->probs;
186
187     while ((f - filter->probs) < filter->numProblems) {
188         if (!(*f)->ignoreProblem) {
189             f++;
190             continue;
191         }
192         while ((t - ps->probs) < ps->numProblems) {
193             if ((*f)->type == (*t)->type && (*t)->key == (*f)->key &&
194                      XSTRCMP((*f)->str1, (*t)->str1))
195                 break;
196             t++;
197             gotProblems = 1;
198         }
199
200         /* XXX This can't happen, but let's be sane in case it does. */
201         if ((t - ps->probs) == ps->numProblems)
202             break;
203
204         (*t)->ignoreProblem = (*f)->ignoreProblem;
205         t++, f++;
206     }
207
208     if ((t - ps->probs) < ps->numProblems)
209         gotProblems = 1;
210
211     return gotProblems;
212 }
213
214 rpmProblem rpmProblemCreate(rpmProblemType type,
215                             const char * pkgNEVR,
216                             fnpyKey key,
217                             const char * dn, const char * bn,
218                             const char * altNEVR,
219                             uint64_t number)
220 {
221     rpmProblem p = xcalloc(1, sizeof(*p));
222     char *t;
223
224     p->type = type;
225     p->key = key;
226     p->num1 = number;
227     p->ignoreProblem = 0;
228
229     p->pkgNEVR = (pkgNEVR ? xstrdup(pkgNEVR) : NULL);
230     p->altNEVR = (altNEVR ? xstrdup(altNEVR) : NULL);
231
232     p->str1 = NULL;
233     if (dn != NULL || bn != NULL) {
234         t = xcalloc(1,  (dn != NULL ? strlen(dn) : 0) +
235                         (bn != NULL ? strlen(bn) : 0) + 1);
236         p->str1 = t;
237         if (dn != NULL) t = stpcpy(t, dn);
238         if (bn != NULL) t = stpcpy(t, bn);
239     }
240     return rpmProblemLink(p);
241 }
242
243 rpmProblem rpmProblemFree(rpmProblem prob)
244 {
245     if (prob == NULL) return NULL;
246
247     if (prob->nrefs > 1) {
248         return rpmProblemUnlink(prob);
249     }
250     prob->pkgNEVR = _free(prob->pkgNEVR);
251     prob->altNEVR = _free(prob->altNEVR);
252     prob->str1 = _free(prob->str1);
253     free(prob);
254     return NULL;
255 }
256
257 rpmProblem rpmProblemLink(rpmProblem prob)
258 {
259     if (prob) {
260         prob->nrefs++;
261     }
262     return prob;
263 }
264
265 rpmProblem rpmProblemUnlink(rpmProblem prob)
266 {
267     if (prob) {
268         prob->nrefs--;
269     }
270     return NULL;
271 }
272
273 const char * rpmProblemGetPkgNEVR(const rpmProblem p)
274 {
275     return (p->pkgNEVR);
276 }
277
278 const char * rpmProblemGetAltNEVR(const rpmProblem p)
279 {
280     return (p->altNEVR);
281 }
282
283 fnpyKey rpmProblemGetKey(const rpmProblem p)
284 {
285     return (p->key);
286 }
287
288 rpmProblemType rpmProblemGetType(const rpmProblem p)
289 {
290     return (p->type);
291 }
292
293 const char * rpmProblemGetStr(const rpmProblem p)
294 {
295     return (p->str1);
296 }
297
298 rpm_loff_t rpmProblemGetDiskNeed(const rpmProblem p)
299 {
300     return (p->num1);
301 }
302
303 char * rpmProblemString(const rpmProblem prob)
304 {
305     const char * pkgNEVR = (prob->pkgNEVR ? prob->pkgNEVR : "?pkgNEVR?");
306     const char * altNEVR = (prob->altNEVR ? prob->altNEVR : "? ?altNEVR?");
307     const char * str1 = (prob->str1 ? prob->str1 : N_("different"));
308     char * buf = NULL;
309     int rc;
310
311     switch (prob->type) {
312     case RPMPROB_BADARCH:
313         rc = rasprintf(&buf, _("package %s is intended for a %s architecture"),
314                 pkgNEVR, str1);
315         break;
316     case RPMPROB_BADOS:
317         rc = rasprintf(&buf,
318                 _("package %s is intended for a %s operating system"),
319                 pkgNEVR, str1);
320         break;
321     case RPMPROB_PKG_INSTALLED:
322         rc = rasprintf(&buf, _("package %s is already installed"),
323                 pkgNEVR);
324         break;
325     case RPMPROB_BADRELOCATE:
326         rc = rasprintf(&buf, _("path %s in package %s is not relocatable"),
327                 str1, pkgNEVR);
328         break;
329     case RPMPROB_NEW_FILE_CONFLICT:
330         rc = rasprintf(&buf, 
331                 _("file %s conflicts between attempted installs of %s and %s"),
332                 str1, pkgNEVR, altNEVR);
333         break;
334     case RPMPROB_FILE_CONFLICT:
335         rc = rasprintf(&buf,
336             _("file %s from install of %s conflicts with file from package %s"),
337                 str1, pkgNEVR, altNEVR);
338         break;
339     case RPMPROB_OLDPACKAGE:
340         rc = rasprintf(&buf,
341                 _("package %s (which is newer than %s) is already installed"),
342                 altNEVR, pkgNEVR);
343         break;
344     case RPMPROB_DISKSPACE:
345         rc = rasprintf(&buf,
346             _("installing package %s needs %" PRIu64 "%cB on the %s filesystem"),
347                 pkgNEVR,
348                 prob->num1 > (1024*1024)
349                     ? (prob->num1 + 1024 * 1024 - 1) / (1024 * 1024)
350                     : (prob->num1 + 1023) / 1024,
351                 prob->num1 > (1024*1024) ? 'M' : 'K',
352                 str1);
353         break;
354     case RPMPROB_DISKNODES:
355         rc = rasprintf(&buf,
356             _("installing package %s needs %" PRIu64 " inodes on the %s filesystem"),
357                 pkgNEVR, prob->num1, str1);
358         break;
359     case RPMPROB_REQUIRES:
360         rc = rasprintf(&buf, _("%s is needed by %s%s"),
361                 altNEVR+2,
362                 (prob->num1 ? "" : _("(installed) ")), pkgNEVR);
363         break;
364     case RPMPROB_CONFLICT:
365         rc = rasprintf(&buf, _("%s conflicts with %s%s"),
366                 altNEVR+2,
367                 (prob->num1 ? "" : _("(installed) ")), pkgNEVR);
368         break;
369     default:
370         rc = rasprintf(&buf,
371                 _("unknown error %d encountered while manipulating package %s"),
372                 prob->type, pkgNEVR);
373         break;
374     }
375
376     return buf;
377 }
378
379 static int sameProblem(const rpmProblem ap, const rpmProblem bp)
380 {
381     if (ap->type != bp->type)
382         return 0;
383     if (ap->pkgNEVR)
384         if (bp->pkgNEVR && !rstreq(ap->pkgNEVR, bp->pkgNEVR))
385             return 0;
386     if (ap->altNEVR)
387         if (bp->altNEVR && !rstreq(ap->altNEVR, bp->altNEVR))
388             return 0;
389     if (ap->str1)
390         if (bp->str1 && !rstreq(ap->str1, bp->str1))
391             return 0;
392
393     if (ap->num1 != bp->num1)
394         return 0;
395
396     return 1;
397 }
398
399 void rpmpsPrint(FILE *fp, rpmps ps)
400 {
401     char * msg = NULL;
402     rpmpsi psi = NULL;
403     int i;
404
405     if (ps == NULL || ps->probs == NULL || ps->numProblems <= 0)
406         return;
407
408     if (fp == NULL)
409         fp = stderr;
410
411     psi = rpmpsInitIterator(ps);
412     while ((i = rpmpsNextIterator(psi)) >= 0) {
413         int j;
414         rpmProblem p = rpmpsGetProblem(psi);
415
416         if (p->ignoreProblem)
417             continue;
418
419         rpmpsi psif = rpmpsInitIterator(ps);
420         /* Filter already displayed problems. */
421         while ((j = rpmpsNextIterator(psif)) < i) {
422             if (sameProblem(p, rpmpsGetProblem(psif)))
423                 break;
424         }
425         rpmpsFreeIterator(psif);
426         if (j < i)
427             continue;
428
429         msg = rpmProblemString(p);
430         fprintf(fp, "\t%s\n", msg);
431         msg = _free(msg);
432
433     }
434     psi = rpmpsFreeIterator(psi);
435 }