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