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