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