Bug Summary

File:lib/depends.c
Warning:line 455, column 6
Value stored to 'p' is never read

Annotated Source Code

1/** \ingroup rpmts
2 * \file lib/depends.c
3 */
4
5#include "system.h"
6
7#include <rpm/rpmlib.h> /* rpmVersionCompare, rpmlib provides */
8#include <rpm/rpmtag.h>
9#include <rpm/rpmlog.h>
10#include <rpm/rpmdb.h>
11#include <rpm/rpmds.h>
12#include <rpm/rpmfi.h>
13
14#include "lib/rpmts_internal.h"
15#include "lib/rpmte_internal.h"
16#include "lib/rpmds_internal.h"
17#include "lib/rpmfi_internal.h" /* rpmfiles stuff for now */
18#include "lib/misc.h"
19
20#include "lib/backend/dbiset.h"
21
22#include "debug.h"
23
24const char * const RPMVERSION = VERSION"4.14.90";
25
26const char * const rpmNAME = PACKAGE"rpm";
27
28const char * const rpmEVR = VERSION"4.14.90";
29
30const int rpmFLAGS = RPMSENSE_EQUAL;
31
32#undef HASHTYPE
33#undef HTKEYTYPE
34#undef HTDATATYPE
35
36#define HASHTYPE depCache
37#define HTKEYTYPE const char *
38#define HTDATATYPE int
39#include "lib/rpmhash.H"
40#include "lib/rpmhash.C"
41#undef HASHTYPE
42#undef HTKEYTYPE
43#undef HTDATATYPE
44
45#define HASHTYPE packageHash
46#define HTKEYTYPE unsigned int
47#define HTDATATYPE struct rpmte_s *
48#include "rpmhash.C"
49#undef HASHTYPE
50#undef HTKEYTYPE
51#undef HTDATATYPE
52
53#define HASHTYPE filedepHash
54#define HTKEYTYPE const char *
55#define HTDATATYPE const char *
56#include "rpmhash.H"
57#include "rpmhash.C"
58#undef HASHTYPE
59#undef HTKEYTYPE
60#undef HTDATATYPE
61
62#define HASHTYPE depexistsHash
63#define HTKEYTYPE const char *
64#include "lib/rpmhash.H"
65#include "lib/rpmhash.C"
66#undef HASHTYPE
67#undef HTKEYTYPE
68
69enum addOp_e {
70 RPMTE_INSTALL = 0,
71 RPMTE_UPGRADE = 1,
72 RPMTE_REINSTALL = 2,
73};
74
75/**
76 * Check for supported payload format in header.
77 * @param h header to check
78 * @return RPMRC_OK if supported, RPMRC_FAIL otherwise
79 */
80static rpmRC headerCheckPayloadFormat(Header h) {
81 rpmRC rc = RPMRC_OK;
82 const char *payloadfmt = headerGetString(h, RPMTAG_PAYLOADFORMAT);
83 /*
84 * XXX Ugh, rpm 3.x packages don't have payload format tag. Instead
85 * of blindly allowing, should check somehow (HDRID existence or... ?)
86 */
87 if (!payloadfmt) return rc;
88
89 if (!rstreq(payloadfmt, "cpio")) {
90 char *nevra = headerGetAsString(h, RPMTAG_NEVRA);
91 if (payloadfmt && rstreq(payloadfmt, "drpm")) {
92 rpmlog(RPMLOG_ERR,
93 _("%s is a Delta RPM and cannot be directly installed\n")dcgettext ("rpm", "%s is a Delta RPM and cannot be directly installed\n"
, 5)
,
94 nevra);
95 } else {
96 rpmlog(RPMLOG_ERR,
97 _("Unsupported payload (%s) in package %s\n")dcgettext ("rpm", "Unsupported payload (%s) in package %s\n",
5)
,
98 payloadfmt ? payloadfmt : "none", nevra);
99 }
100 free(nevra);
101 rc = RPMRC_FAIL;
102 }
103 return rc;
104}
105
106/**
107 * Add removed package instance to ordered transaction set.
108 * @param ts transaction set
109 * @param h header
110 * @param depends installed package of pair (or RPMAL_NOMATCH on erase)
111 * @return 0 on success
112 */
113static int removePackage(rpmts ts, Header h, rpmte depends)
114{
115 tsMembers tsmem = rpmtsMembers(ts);
116 rpmte p, *pp;
117 unsigned int dboffset = headerGetInstance(h);
118
119 /* Can't remove what's not installed */
120 if (dboffset == 0) return 1;
121
122 /* Filter out duplicate erasures. */
123 if (packageHashGetEntry(tsmem->removedPackages, dboffset, &pp, NULL((void*)0), NULL((void*)0))) {
124 rpmteSetDependsOn(pp[0], depends);
125 return 0;
126 }
127
128 p = rpmteNew(ts, h, TR_REMOVED, NULL((void*)0), NULL((void*)0));
129 if (p == NULL((void*)0))
130 return 1;
131
132 packageHashAddEntry(tsmem->removedPackages, dboffset, p);
133
134 if (tsmem->orderCount >= tsmem->orderAlloced) {
135 tsmem->orderAlloced += (tsmem->orderCount - tsmem->orderAlloced) + tsmem->delta;
136 tsmem->order = xrealloc(tsmem->order, sizeof(*tsmem->order) * tsmem->orderAlloced)rrealloc((tsmem->order), (sizeof(*tsmem->order) * tsmem
->orderAlloced))
;
137 }
138
139 rpmteSetDependsOn(p, depends);
140
141 tsmem->order[tsmem->orderCount] = p;
142 tsmem->orderCount++;
143
144 return 0;
145}
146
147/* Return rpmdb iterator with removals optionally pruned out */
148rpmdbMatchIterator rpmtsPrunedIterator(rpmts ts, rpmDbiTagVal tag,
149 const char * key, int prune)
150{
151 rpmdbMatchIterator mi = rpmtsInitIterator(ts, tag, key, 0);
152 if (prune) {
153 tsMembers tsmem = rpmtsMembers(ts);
154 rpmdbPruneIterator(mi, tsmem->removedPackages);
155 }
156 return mi;
157}
158
159/**
160 * Decides whether to skip a package upgrade/obsoletion on TE color.
161 *
162 * @param tscolor color of this transaction
163 * @param color color of this transaction element
164 * @param ocolor header color of the upgraded/obsoleted package
165 *
166 * @return non-zero if the package should be skipped
167 */
168static int skipColor(rpm_color_t tscolor, rpm_color_t color, rpm_color_t ocolor)
169{
170 return tscolor && color && ocolor && !(color & ocolor);
171}
172
173/* Add erase elements for older packages of same color (if any). */
174static int addSelfErasures(rpmts ts, rpm_color_t tscolor, int op,
175 rpmte p, rpm_color_t hcolor, Header h)
176{
177 Header oh;
178 rpmdbMatchIterator mi = rpmtsInitIterator(ts, RPMDBI_NAME, rpmteN(p), 0);
179 int rc = 0;
180 int cmp;
181
182 while ((oh = rpmdbNextIterator(mi)) != NULL((void*)0)) {
183 /* Ignore colored packages not in our rainbow. */
184 if (skipColor(tscolor, hcolor, headerGetNumber(oh, RPMTAG_HEADERCOLOR)))
185 continue;
186
187 cmp = rpmVersionCompare(h, oh);
188
189 /* On upgrade, skip packages that contain identical NEVR. */
190 if ((op == RPMTE_UPGRADE) && (cmp == 0))
191 continue;
192
193 /* On reinstall, skip packages with differing NEVR. */
194 if ((op == RPMTE_REINSTALL) && (cmp != 0))
195 continue;
196
197 if (removePackage(ts, oh, p)) {
198 rc = 1;
199 break;
200 }
201 }
202 rpmdbFreeIterator(mi);
203 return rc;
204}
205
206/* Add erase elements for obsoleted packages of same color (if any). */
207static int addObsoleteErasures(rpmts ts, rpm_color_t tscolor, rpmte p)
208{
209 rpmstrPool tspool = rpmtsPool(ts);
210 rpmds obsoletes = rpmdsInit(rpmteDS(p, RPMTAG_OBSOLETENAME));
211 Header oh;
212 int rc = 0;
213
214 while (rpmdsNext(obsoletes) >= 0 && rc == 0) {
215 const char * Name;
216 rpmdbMatchIterator mi = NULL((void*)0);
217
218 if ((Name = rpmdsN(obsoletes)) == NULL((void*)0))
219 continue; /* XXX can't happen */
220
221 mi = rpmtsPrunedIterator(ts, RPMDBI_NAME, Name, 1);
222
223 while ((oh = rpmdbNextIterator(mi)) != NULL((void*)0)) {
224 const char *oarch = headerGetString(oh, RPMTAG_ARCH);
225 int match;
226
227 /* avoid self-obsoleting packages */
228 if (rstreq(rpmteN(p), Name) && rstreq(rpmteA(p), oarch)) {
229 char * ohNEVRA = headerGetAsString(oh, RPMTAG_NEVRA);
230 rpmlog(RPMLOG_DEBUG, " Not obsoleting: %s\n", ohNEVRA);
231 free(ohNEVRA);
232 continue;
233 }
234
235 /*
236 * Rpm prior to 3.0.3 does not have versioned obsoletes.
237 * If no obsoletes version info is available, match all names.
238 */
239 match = (rpmdsEVR(obsoletes) == NULL((void*)0));
240 if (!match)
241 match = rpmdsMatches(tspool, oh, -1, obsoletes, 1,
242 _rpmds_nopromote);
243
244 if (match) {
245 char * ohNEVRA = headerGetAsString(oh, RPMTAG_NEVRA);
246 rpmlog(RPMLOG_DEBUG, " Obsoletes: %s\t\terases %s\n",
247 rpmdsDNEVR(obsoletes)+2, ohNEVRA);
248 free(ohNEVRA);
249
250 if (removePackage(ts, oh, p)) {
251 rc = 1;
252 break;
253 }
254 }
255 }
256 rpmdbFreeIterator(mi);
257 }
258 return rc;
259}
260
261/*
262 * Lookup obsoletions in the added set. In theory there could
263 * be more than one obsoleting package, but we only care whether this
264 * has been obsoleted by *something* or not.
265 */
266static rpmte checkObsoleted(rpmal addedPackages, rpmds thisds)
267{
268 rpmte p = NULL((void*)0);
269 rpmte *matches = NULL((void*)0);
270
271 matches = rpmalAllObsoletes(addedPackages, thisds);
272 if (matches) {
273 p = matches[0];
274 free(matches);
275 }
276 return p;
277}
278
279/*
280 * Filtered rpmal lookup: on colored transactions there can be more
281 * than one identical NEVR but different arch, this must be allowed.
282 * Only a single element needs to be considred as there can only ever
283 * be one previous element to be replaced.
284 */
285static rpmte checkAdded(rpmal addedPackages, rpm_color_t tscolor,
286 rpmte te, rpmds ds)
287{
288 rpmte p = NULL((void*)0);
289 rpmte *matches = NULL((void*)0);
290
291 matches = rpmalAllSatisfiesDepend(addedPackages, ds);
292 if (matches) {
293 const char * arch = rpmteA(te);
294 const char * os = rpmteO(te);
295
296 for (rpmte *m = matches; m && *m; m++) {
297 if (tscolor) {
298 const char * parch = rpmteA(*m);
299 const char * pos = rpmteO(*m);
300
301 if (arch == NULL((void*)0) || parch == NULL((void*)0) || os == NULL((void*)0) || pos == NULL((void*)0))
302 continue;
303 if (!rstreq(arch, parch) || !rstreq(os, pos))
304 continue;
305 }
306 p = *m;
307 break;
308 }
309 free(matches);
310 }
311 return p;
312}
313
314/*
315 * Check for previously added versions and obsoletions.
316 * Return index where to place this element, or -1 to skip.
317 * XXX OBSOLETENAME is a bit of a hack, but gives us what
318 * we want from rpmal: we're only interested in added package
319 * names here, not their provides.
320 */
321static int findPos(rpmts ts, rpm_color_t tscolor, rpmte te, int upgrade)
322{
323 tsMembers tsmem = rpmtsMembers(ts);
324 int oc = tsmem->orderCount;
325 int skip = 0;
326 const char * name = rpmteN(te);
327 const char * evr = rpmteEVR(te);
328 rpmte p;
329 rpmstrPool tspool = rpmtsPool(ts);
330 rpmds oldChk = rpmdsSinglePool(tspool, RPMTAG_OBSOLETENAME,
331 name, evr, (RPMSENSE_LESS));
332 rpmds newChk = rpmdsSinglePool(tspool, RPMTAG_OBSOLETENAME,
333 name, evr, (RPMSENSE_GREATER));
334 rpmds sameChk = rpmdsSinglePool(tspool, RPMTAG_OBSOLETENAME,
335 name, evr, (RPMSENSE_EQUAL));
336 rpmds obsChk = rpmteDS(te, RPMTAG_OBSOLETENAME);
337
338 /* If obsoleting package has already been added, skip this. */
339 if ((p = checkObsoleted(tsmem->addedPackages, rpmteDS(te, RPMTAG_NAME)))) {
340 skip = 1;
341 goto exit;
342 }
343
344 /* If obsoleted package has already been added, replace with this. */
345 rpmdsInit(obsChk);
346 while (rpmdsNext(obsChk) >= 0) {
347 /* XXX Obsoletes are not colored */
348 if ((p = checkAdded(tsmem->addedPackages, 0, te, obsChk))) {
349 goto exit;
350 }
351 }
352
353 /* If same NEVR has already been added, skip this. */
354 if ((p = checkAdded(tsmem->addedPackages, tscolor, te, sameChk))) {
355 skip = 1;
356 goto exit;
357 }
358
359 /* On upgrades... */
360 if (upgrade) {
361 /* ...if newer NEVR has already been added, skip this. */
362 if ((p = checkAdded(tsmem->addedPackages, tscolor, te, newChk))) {
363 skip = 1;
364 goto exit;
365 }
366
367 /* ...if older NEVR has already been added, replace with this. */
368 if ((p = checkAdded(tsmem->addedPackages, tscolor, te, oldChk))) {
369 goto exit;
370 }
371 }
372
373exit:
374 /* If we found a previous element we've something to say */
375 if (p != NULL((void*)0) && rpmIsVerbose()(rpmlogSetMask(0) >= (1 << ((unsigned)(RPMLOG_INFO))
))
) {
376 const char *msg = skip ?
377 _("package %s was already added, skipping %s\n")dcgettext ("rpm", "package %s was already added, skipping %s\n"
, 5)
:
378 _("package %s was already added, replacing with %s\n")dcgettext ("rpm", "package %s was already added, replacing with %s\n"
, 5)
;
379 rpmlog(RPMLOG_WARNING, msg, rpmteNEVRA(p), rpmteNEVRA(te));
380 }
381
382 /* If replacing a previous element, find out where it is. Pooh. */
383 if (!skip && p != NULL((void*)0)) {
384 for (oc = 0; oc < tsmem->orderCount; oc++) {
385 if (p == tsmem->order[oc])
386 break;
387 }
388 }
389
390 rpmdsFree(oldChk);
391 rpmdsFree(newChk);
392 rpmdsFree(sameChk);
393 return (skip) ? -1 : oc;
394}
395
396rpmal rpmtsCreateAl(rpmts ts, rpmElementTypes types)
397{
398 rpmal al = NULL((void*)0);
399 if (ts) {
400 rpmte p;
401 rpmtsi pi;
402 rpmstrPool tspool = rpmtsPool(ts);
403
404 al = rpmalCreate(tspool, (rpmtsNElements(ts) / 4) + 1, rpmtsFlags(ts),
405 rpmtsColor(ts), rpmtsPrefColor(ts));
406 pi = rpmtsiInit(ts);
407 while ((p = rpmtsiNext(pi, types)))
408 rpmalAdd(al, p);
409 rpmtsiFree(pi);
410 }
411 return al;
412}
413
414static int addPackage(rpmts ts, Header h,
415 fnpyKey key, int op, rpmRelocation * relocs)
416{
417 tsMembers tsmem = rpmtsMembers(ts);
418 rpm_color_t tscolor = rpmtsColor(ts);
419 rpmte p = NULL((void*)0);
420 int isSource = headerIsSource(h);
421 int ec = 0;
422 int oc = tsmem->orderCount;
423
424 /* Check for supported payload format if it's a package */
425 if (key && headerCheckPayloadFormat(h) != RPMRC_OK) {
426 ec = 1;
427 goto exit;
428 }
429
430 /* Source packages are never "upgraded" */
431 if (isSource)
432 op = RPMTE_INSTALL;
433
434 /* Do lazy (readonly?) open of rpm database for upgrades. */
435 if (op != RPMTE_INSTALL && rpmtsGetRdb(ts) == NULL((void*)0) && rpmtsGetDBMode(ts) != -1) {
436 if ((ec = rpmtsOpenDB(ts, rpmtsGetDBMode(ts))) != 0)
437 goto exit;
438 }
439
440 p = rpmteNew(ts, h, TR_ADDED, key, relocs);
441 if (p == NULL((void*)0)) {
442 ec = 1;
443 goto exit;
444 }
445
446 /* Check binary packages for redundancies in the set */
447 if (!isSource) {
448 oc = findPos(ts, tscolor, p, (op == RPMTE_UPGRADE));
449 /* If we're replacing a previously added element, free the old one */
450 if (oc >= 0 && oc < tsmem->orderCount) {
451 rpmalDel(tsmem->addedPackages, tsmem->order[oc]);
452 tsmem->order[oc] = rpmteFree(tsmem->order[oc]);
453 /* If newer NEVR was already added, we're done */
454 } else if (oc < 0) {
455 p = rpmteFree(p);
Value stored to 'p' is never read
456 goto exit;
457 }
458 }
459
460 if (oc >= tsmem->orderAlloced) {
461 tsmem->orderAlloced += (oc - tsmem->orderAlloced) + tsmem->delta;
462 tsmem->order = xrealloc(tsmem->order,rrealloc((tsmem->order), (tsmem->orderAlloced * sizeof(
*tsmem->order)))
463 tsmem->orderAlloced * sizeof(*tsmem->order))rrealloc((tsmem->order), (tsmem->orderAlloced * sizeof(
*tsmem->order)))
;
464 }
465
466
467 tsmem->order[oc] = p;
468 if (oc == tsmem->orderCount) {
469 tsmem->orderCount++;
470 }
471
472 if (tsmem->addedPackages == NULL((void*)0)) {
473 tsmem->addedPackages = rpmalCreate(rpmtsPool(ts), 5, rpmtsFlags(ts),
474 tscolor, rpmtsPrefColor(ts));
475 }
476 rpmalAdd(tsmem->addedPackages, p);
477
478 /* Add erasure elements for old versions and obsoletions on upgrades */
479 /* XXX TODO: If either of these fails, we'd need to undo all additions */
480 if (op != RPMTE_INSTALL)
481 addSelfErasures(ts, tscolor, op, p, rpmteColor(p), h);
482 if (op == RPMTE_UPGRADE)
483 addObsoleteErasures(ts, tscolor, p);
484
485exit:
486 return ec;
487}
488
489int rpmtsAddInstallElement(rpmts ts, Header h,
490 fnpyKey key, int upgrade, rpmRelocation * relocs)
491{
492 int op = (upgrade == 0) ? RPMTE_INSTALL : RPMTE_UPGRADE;
493 if (rpmtsSetupTransactionPlugins(ts) == RPMRC_FAIL)
494 return 1;
495 return addPackage(ts, h, key, op, relocs);
496}
497
498int rpmtsAddReinstallElement(rpmts ts, Header h, fnpyKey key)
499{
500 if (rpmtsSetupTransactionPlugins(ts) == RPMRC_FAIL)
501 return 1;
502 /* TODO: pull relocations from installed package */
503 /* TODO: should reinstall of non-installed package fail? */
504 return addPackage(ts, h, key, RPMTE_REINSTALL, NULL((void*)0));
505}
506
507int rpmtsAddEraseElement(rpmts ts, Header h, int dboffset)
508{
509 if (rpmtsSetupTransactionPlugins(ts) == RPMRC_FAIL)
510 return 1;
511 return removePackage(ts, h, NULL((void*)0));
512}
513
514/* Cached rpmdb provide lookup, returns 0 if satisfied, 1 otherwise */
515static int rpmdbProvides(rpmts ts, depCache dcache, rpmds dep, dbiIndexSet *matches)
516{
517 const char * Name = rpmdsN(dep);
518 const char * DNEVR = rpmdsDNEVR(dep);
519 rpmTagVal deptag = rpmdsTagN(dep);
520 int *cachedrc = NULL((void*)0);
521 rpmdbMatchIterator mi = NULL((void*)0);
522 Header h = NULL((void*)0);
523 int rc = 0;
524 /* pretrans deps are provided by current packages, don't prune erasures */
525 int prune = (rpmdsFlags(dep) & RPMSENSE_PRETRANS) ? 0 : 1;
526 unsigned int keyhash = 0;
527
528 /* See if we already looked this up */
529 if (prune && !matches) {
530 keyhash = depCacheKeyHash(dcache, DNEVR);
531 if (depCacheGetHEntry(dcache, DNEVR, keyhash, &cachedrc, NULL((void*)0), NULL((void*)0))) {
532 rc = *cachedrc;
533 rpmdsNotify(dep, "(cached)", rc);
534 return rc;
535 }
536 }
537
538 if (matches)
539 *matches = dbiIndexSetNew(0);
540 /*
541 * See if a filename dependency is a real file in some package,
542 * taking file state into account: replaced, wrong colored and
543 * not installed files can not satisfy a dependency.
544 */
545 if (deptag != RPMTAG_OBSOLETENAME && Name[0] == '/') {
546 mi = rpmtsPrunedIterator(ts, RPMDBI_INSTFILENAMES, Name, prune);
547 while ((h = rpmdbNextIterator(mi)) != NULL((void*)0)) {
548 /* Ignore self-conflicts */
549 if (deptag == RPMTAG_CONFLICTNAME) {
550 unsigned int instance = headerGetInstance(h);
551 if (instance && instance == rpmdsInstance(dep))
552 continue;
553 }
554 if (matches) {
555 dbiIndexSetAppendOne(*matches, headerGetInstance(h), 0, 0);
556 continue;
557 }
558 rpmdsNotify(dep, "(db files)", rc);
559 break;
560 }
561 rpmdbFreeIterator(mi);
562 }
563
564 /* Otherwise look in provides no matter what the dependency looks like */
565 if (h == NULL((void*)0)) {
566 rpmstrPool tspool = rpmtsPool(ts);
567 /* Obsoletes use just name alone, everything else uses provides */
568 rpmTagVal dbtag = RPMDBI_PROVIDENAME;
569 int selfevr = 0;
570 if (deptag == RPMTAG_OBSOLETENAME) {
571 dbtag = RPMDBI_NAME;
572 selfevr = 1;
573 }
574
575 mi = rpmtsPrunedIterator(ts, dbtag, Name, prune);
576 while ((h = rpmdbNextIterator(mi)) != NULL((void*)0)) {
577 /* Provide-indexes can't be used with nevr-only matching */
578 int prix = (selfevr) ? -1 : rpmdbGetIteratorFileNum(mi);
579 int match = rpmdsMatches(tspool, h, prix, dep, selfevr,
580 _rpmds_nopromote);
581 /* Ignore self-obsoletes and self-conflicts */
582 if (match && (deptag == RPMTAG_OBSOLETENAME || deptag == RPMTAG_CONFLICTNAME)) {
583 unsigned int instance = headerGetInstance(h);
584 if (instance && instance == rpmdsInstance(dep))
585 match = 0;
586 }
587 if (match) {
588 if (matches) {
589 dbiIndexSetAppendOne(*matches, headerGetInstance(h), 0, 0);
590 continue;
591 }
592 rpmdsNotify(dep, "(db provides)", rc);
593 break;
594 }
595 }
596 rpmdbFreeIterator(mi);
597 }
598 rc = (h != NULL((void*)0)) ? 0 : 1;
599
600 if (matches) {
601 dbiIndexSetUniq(*matches, 0);
602 rc = dbiIndexSetCount(*matches) ? 0 : 1;
603 }
604
605 /* Cache the relatively expensive rpmdb lookup results */
606 /* Caching the oddball non-pruned case would mess up other results */
607 if (prune && !matches)
608 depCacheAddHEntry(dcache, xstrdup(DNEVR)rstrdup((DNEVR)), keyhash, rc);
609 return rc;
610}
611
612static dbiIndexSet unsatisfiedDependSet(rpmts ts, rpmds dep)
613{
614 dbiIndexSet set1 = NULL((void*)0), set2 = NULL((void*)0);
615 tsMembers tsmem = rpmtsMembers(ts);
616 rpmsenseFlags dsflags = rpmdsFlags(dep);
617
618 if (dsflags & RPMSENSE_RPMLIB)
619 goto exit;
620
621 if (rpmdsIsRich(dep)) {
622 rpmds ds1, ds2;
623 rpmrichOp op;
624 char *emsg = 0;
625
626 if (rpmdsParseRichDep(dep, &ds1, &ds2, &op, &emsg) != RPMRC_OK) {
627 rpmdsNotify(dep, emsg ? emsg : "(parse error)", 1);
628 _free(emsg)rfree((emsg));
629 goto exit;
630 }
631 /* only a subset of ops is supported in set mode */
632 if (op != RPMRICHOP_WITH && op != RPMRICHOP_WITHOUT
633 && op != RPMRICHOP_OR && op != RPMRICHOP_SINGLE) {
634 rpmdsNotify(dep, "(unsupported op in set mode)", 1);
635 goto exit_rich;
636 }
637
638 set1 = unsatisfiedDependSet(ts, ds1);
639 if (op == RPMRICHOP_SINGLE)
640 goto exit_rich;
641 if (op != RPMRICHOP_OR && dbiIndexSetCount(set1) == 0)
642 goto exit_rich;
643 set2 = unsatisfiedDependSet(ts, ds2);
644 if (op == RPMRICHOP_WITH) {
645 dbiIndexSetFilterSet(set1, set2, 0);
646 } else if (op == RPMRICHOP_WITHOUT) {
647 dbiIndexSetPruneSet(set1, set2, 0);
648 } else if (op == RPMRICHOP_OR) {
649 dbiIndexSetAppendSet(set1, set2, 0);
650 }
651exit_rich:
652 ds1 = rpmdsFree(ds1);
653 ds2 = rpmdsFree(ds2);
654 goto exit;
655 }
656
657 /* match database entries */
658 rpmdbProvides(ts, NULL((void*)0), dep, &set1);
659
660 /* Pretrans dependencies can't be satisfied by added packages. */
661 if (!(dsflags & RPMSENSE_PRETRANS)) {
662 rpmte *matches = rpmalAllSatisfiesDepend(tsmem->addedPackages, dep);
663 if (matches) {
664 for (rpmte *p = matches; *p; p++)
665 dbiIndexSetAppendOne(set1, rpmalLookupTE(tsmem->addedPackages, *p), 1, 0);
666 }
667 _free(matches)rfree((matches));
668 }
669
670exit:
671 set2 = dbiIndexSetFree(set2);
672 return set1 ? set1 : dbiIndexSetNew(0);
673}
674
675/**
676 * Check dep for an unsatisfied dependency.
677 * @param ts transaction set
678 * @param dcache dependency cache
679 * @param dep dependency
680 * @return 0 if satisfied, 1 if not satisfied
681 */
682static int unsatisfiedDepend(rpmts ts, depCache dcache, rpmds dep)
683{
684 tsMembers tsmem = rpmtsMembers(ts);
685 int rc;
686 int retrying = 0;
687 int adding = (rpmdsInstance(dep) == 0);
688 rpmsenseFlags dsflags = rpmdsFlags(dep);
689
690retry:
691 rc = 0; /* assume dependency is satisfied */
692
693 /*
694 * New features in rpm packaging implicitly add versioned dependencies
695 * on rpmlib provides. The dependencies look like "rpmlib(YaddaYadda)".
696 * Check those dependencies now.
697 */
698 if (dsflags & RPMSENSE_RPMLIB) {
699 if (tsmem->rpmlib == NULL((void*)0))
700 rpmdsRpmlibPool(rpmtsPool(ts), &(tsmem->rpmlib), NULL((void*)0));
701
702 if (tsmem->rpmlib != NULL((void*)0) && rpmdsSearch(tsmem->rpmlib, dep) >= 0) {
703 rpmdsNotify(dep, "(rpmlib provides)", rc);
704 goto exit;
705 }
706 goto unsatisfied;
707 }
708
709 /* Dont look at pre-requisites of already installed packages */
710 if (!adding && isInstallPreReq(dsflags)((dsflags) & ((RPMSENSE_SCRIPT_PRE|RPMSENSE_SCRIPT_POST|RPMSENSE_RPMLIB
|RPMSENSE_KEYRING|RPMSENSE_PRETRANS|RPMSENSE_POSTTRANS) &
~RPMSENSE_PREREQ))
&& !isErasePreReq(dsflags)((dsflags) & ((RPMSENSE_SCRIPT_PREUN|RPMSENSE_SCRIPT_POSTUN
) & ~RPMSENSE_PREREQ))
)
711 goto exit;
712
713 /* Handle rich dependencies */
714 if (rpmdsIsRich(dep)) {
715 rpmds ds1, ds2;
716 rpmrichOp op;
717 char *emsg = 0;
718 if (rpmdsParseRichDep(dep, &ds1, &ds2, &op, &emsg) != RPMRC_OK) {
719 rc = rpmdsTagN(dep) == RPMTAG_CONFLICTNAME ? 0 : 1;
720 if (rpmdsInstance(dep) != 0)
721 rc = !rc; /* ignore errors for installed packages */
722 rpmdsNotify(dep, emsg ? emsg : "(parse error)", rc);
723 _free(emsg)rfree((emsg));
724 goto exit;
725 }
726 if (op == RPMRICHOP_WITH || op == RPMRICHOP_WITHOUT) {
727 /* switch to set mode processing */
728 dbiIndexSet set = unsatisfiedDependSet(ts, dep);
729 rc = dbiIndexSetCount(set) ? 0 : 1;
730 dbiIndexSetFree(set);
731 ds1 = rpmdsFree(ds1);
732 ds2 = rpmdsFree(ds2);
733 rpmdsNotify(dep, "(rich)", rc);
734 goto exit;
735 }
736 if (op == RPMRICHOP_IF) {
737 if (rpmdsIsRich(ds2)) {
738 /* check if this is a IF...ELSE combination */
739 rpmds ds21 = NULL((void*)0), ds22 = NULL((void*)0);
740 rpmrichOp op2;
741 if (rpmdsParseRichDep(ds2, &ds21, &ds22, &op2, NULL((void*)0)) == RPMRC_OK && op2 == RPMRICHOP_ELSE) {
742 rc = unsatisfiedDepend(ts, dcache, ds21);
743 if (rc) {
744 rpmdsFree(ds1);
745 ds1 = ds22;
746 ds22 = NULL((void*)0);
747 }
748 rc = 1;
749 }
750 rpmdsFree(ds21);
751 rpmdsFree(ds22);
752 }
753 if (!rc)
754 rc = !unsatisfiedDepend(ts, dcache, ds2);
755 }
756 if (op != RPMRICHOP_IF || rc)
757 rc = unsatisfiedDepend(ts, dcache, ds1);
758 if ((rc && op == RPMRICHOP_OR) || (!rc && op == RPMRICHOP_AND))
759 rc = unsatisfiedDepend(ts, dcache, ds2);
760 ds1 = rpmdsFree(ds1);
761 ds2 = rpmdsFree(ds2);
762 rpmdsNotify(dep, "(rich)", rc);
763 goto exit;
764 }
765
766 /* Pretrans dependencies can't be satisfied by added packages. */
767 if (!(dsflags & RPMSENSE_PRETRANS)) {
768 rpmte *matches = rpmalAllSatisfiesDepend(tsmem->addedPackages, dep);
769 int match = matches && *matches;
770 _free(matches)rfree((matches));
771 if (match)
772 goto exit;
773 }
774
775 /* See if the rpmdb provides it */
776 if (rpmdbProvides(ts, dcache, dep, NULL((void*)0)) == 0)
777 goto exit;
778
779 /* Search for an unsatisfied dependency. */
780 if (adding && !retrying && !(dsflags & RPMSENSE_PRETRANS)) {
781 int xx = rpmtsSolve(ts, dep);
782 if (xx == 0)
783 goto exit;
784 if (xx == -1) {
785 retrying = 1;
786 goto retry;
787 }
788 }
789
790unsatisfied:
791 if (dsflags & RPMSENSE_MISSINGOK) {
792 /* note the result, but missingok deps are never unsatisfied */
793 rpmdsNotify(dep, "(missingok)", 1);
794 } else {
795 /* dependency is unsatisfied */
796 rc = 1;
797 rpmdsNotify(dep, NULL((void*)0), rc);
798 }
799
800exit:
801 return rc;
802}
803
804/* Check a dependency set for problems */
805static void checkDS(rpmts ts, depCache dcache, rpmte te,
806 const char * pkgNEVRA, rpmds ds,
807 rpm_color_t tscolor)
808{
809 rpm_color_t dscolor;
810 /* require-problems are unsatisfied, others appear "satisfied" */
811 int is_problem = (rpmdsTagN(ds) == RPMTAG_REQUIRENAME);
812
813 ds = rpmdsInit(ds);
814 while (rpmdsNext(ds) >= 0) {
815 /* Ignore colored dependencies not in our rainbow. */
816 dscolor = rpmdsColor(ds);
817 if (tscolor && dscolor && !(tscolor & dscolor))
818 continue;
819
820 if (unsatisfiedDepend(ts, dcache, ds) == is_problem)
821 rpmteAddDepProblem(te, pkgNEVRA, ds, NULL((void*)0));
822 }
823}
824
825/* Check a given dependency against installed packages */
826static void checkInstDeps(rpmts ts, depCache dcache, rpmte te,
827 rpmTag depTag, const char *dep)
828{
829 Header h;
830 rpmdbMatchIterator mi = rpmtsPrunedIterator(ts, depTag, dep, 1);
831 rpmstrPool pool = rpmtsPool(ts);
832 /* require-problems are unsatisfied, others appear "satisfied" */
833 int is_problem = (depTag == RPMTAG_REQUIRENAME);
834
835 while ((h = rpmdbNextIterator(mi)) != NULL((void*)0)) {
836 char * pkgNEVRA;
837 rpmds ds;
838
839 /* Ignore self-obsoletes and self-conflicts */
840 if (depTag == RPMTAG_OBSOLETENAME || depTag == RPMTAG_CONFLICTNAME) {
841 unsigned int instance = headerGetInstance(h);
842 if (instance && instance == rpmteDBInstance(te))
843 continue;
844 }
845
846 pkgNEVRA = headerGetAsString(h, RPMTAG_NEVRA);
847 ds = rpmdsNewPool(pool, h, depTag, 0);
848 rpmdsSetIx(ds, rpmdbGetIteratorFileNum(mi));
849
850 if (unsatisfiedDepend(ts, dcache, ds) == is_problem)
851 rpmteAddDepProblem(te, pkgNEVRA, ds, NULL((void*)0));
852
853 rpmdsFree(ds);
854 free(pkgNEVRA);
855 }
856 rpmdbFreeIterator(mi);
857}
858
859static void checkNotInstDeps(rpmts ts, depCache dcache, rpmte te,
860 rpmTag depTag, const char *dep)
861{
862 char *ndep = rmalloc(strlen(dep) + 2);
863 ndep[0] = '!';
864 strcpy(ndep + 1, dep);
865 checkInstDeps(ts, dcache, te, depTag, ndep);
866 free(ndep);
867}
868
869static void checkInstFileDeps(rpmts ts, depCache dcache, rpmte te,
870 rpmTag depTag, rpmfi fi, int is_not,
871 filedepHash cache, fingerPrintCache *fpcp)
872{
873 fingerPrintCache fpc = *fpcp;
874 fingerPrint * fp = NULL((void*)0);
875 const char *basename = rpmfiBN(fi);
876 const char *dirname;
877 const char **dirnames = 0;
878 int ndirnames = 0;
879 int i;
880
881 filedepHashGetEntry(cache, basename, &dirnames, &ndirnames, NULL((void*)0));
882 if (!ndirnames)
883 return;
884 if (!fpc)
885 *fpcp = fpc = fpCacheCreate(1001, NULL((void*)0));
886 dirname = rpmfiDN(fi);
887 fpLookup(fpc, dirname, basename, &fp);
888 for (i = 0; i < ndirnames; i++) {
889 char *fpdep = 0;
890 const char *dep;
891 if (!strcmp(dirnames[i], dirname)) {
892 dep = rpmfiFN(fi);
893 } else if (fpLookupEquals(fpc, fp, dirnames[i], basename)) {
894 fpdep = rmalloc(strlen(dirnames[i]) + strlen(basename) + 1);
895 strcpy(fpdep, dirnames[i]);
896 strcat(fpdep, basename);
897 dep = fpdep;
898 } else {
899 continue;
900 }
901 if (!is_not)
902 checkInstDeps(ts, dcache, te, depTag, dep);
903 else
904 checkNotInstDeps(ts, dcache, te, depTag, dep);
905 _free(fpdep)rfree((fpdep));
906 }
907 _free(fp)rfree((fp));
908}
909
910static void addFileDepToHash(filedepHash hash, char *key, size_t keylen)
911{
912 int i;
913 char *basename, *dirname;
914 if (!keylen || key[0] != '/')
915 return;
916 for (i = keylen - 1; key[i] != '/'; i--)
917 ;
918 dirname = rmalloc(i + 2);
919 memcpy(dirname, key, i + 1);
920 dirname[i + 1] = 0;
921 basename = rmalloc(keylen - i);
922 memcpy(basename, key + i + 1, keylen - i - 1);
923 basename[keylen - i - 1] = 0;
924 filedepHashAddEntry(hash, basename, dirname);
925}
926
927static void addDepToHash(depexistsHash hash, char *key, size_t keylen)
928{
929 char *keystr;
930 if (!keylen)
931 return;
932 keystr = rmalloc(keylen + 1);
933 strncpy(keystr, key, keylen);
934 keystr[keylen] = 0;
935 depexistsHashAddEntry(hash, keystr);
936}
937
938static void addIndexToDepHashes(rpmts ts, rpmDbiTag tag,
939 depexistsHash dephash, filedepHash filehash,
940 depexistsHash depnothash, filedepHash filenothash)
941{
942 char *key;
943 size_t keylen;
944 rpmdbIndexIterator ii = rpmdbIndexIteratorInit(rpmtsGetRdb(ts), tag);
945
946 if (!ii)
947 return;
948 while ((rpmdbIndexIteratorNext(ii, (const void**)&key, &keylen)) == 0) {
949 if (!key || !keylen)
950 continue;
951 if (*key == '!' && keylen > 1) {
952 key++;
953 keylen--;
954 if (*key == '/' && filenothash)
955 addFileDepToHash(filenothash, key, keylen);
956 if (depnothash)
957 addDepToHash(depnothash, key, keylen);
958 } else {
959 if (*key == '/' && filehash)
960 addFileDepToHash(filehash, key, keylen);
961 if (dephash)
962 addDepToHash(dephash, key, keylen);
963 }
964 }
965 rpmdbIndexIteratorFree(ii);
966}
967
968
969int rpmtsCheck(rpmts ts)
970{
971 rpm_color_t tscolor = rpmtsColor(ts);
972 rpmtsi pi = NULL((void*)0); rpmte p;
973 int closeatexit = 0;
974 int rc = 0;
975 depCache dcache = NULL((void*)0);
976 filedepHash confilehash = NULL((void*)0); /* file conflicts of installed packages */
977 filedepHash connotfilehash = NULL((void*)0); /* file conflicts of installed packages */
978 depexistsHash connothash = NULL((void*)0);
979 filedepHash reqfilehash = NULL((void*)0); /* file requires of installed packages */
980 filedepHash reqnotfilehash = NULL((void*)0); /* file requires of installed packages */
981 depexistsHash reqnothash = NULL((void*)0);
982 fingerPrintCache fpc = NULL((void*)0);
983 rpmdb rdb = NULL((void*)0);
984
985 (void) rpmswEnter(rpmtsOp(ts, RPMTS_OP_CHECK), 0);
986
987 /* Do lazy, readonly, open of rpm database. */
988 rdb = rpmtsGetRdb(ts);
989 if (rdb == NULL((void*)0) && rpmtsGetDBMode(ts) != -1) {
990 if ((rc = rpmtsOpenDB(ts, rpmtsGetDBMode(ts))) != 0)
991 goto exit;
992 rdb = rpmtsGetRdb(ts);
993 closeatexit = 1;
994 }
995
996 if (rdb)
997 rpmdbCtrl(rdb, RPMDB_CTRL_LOCK_RO);
998
999 /* XXX FIXME: figure some kind of heuristic for the cache size */
1000 dcache = depCacheCreate(5001, rstrhash, strcmp,
1001 (depCacheFreeKey)rfree, NULL((void*)0));
1002
1003 /* build hashes of all confilict sdependencies */
1004 confilehash = filedepHashCreate(257, rstrhash, strcmp,
1005 (filedepHashFreeKey)rfree,
1006 (filedepHashFreeData)rfree);
1007 connothash = depexistsHashCreate(257, rstrhash, strcmp,
1008 (filedepHashFreeKey)rfree);
1009 connotfilehash = filedepHashCreate(257, rstrhash, strcmp,
1010 (filedepHashFreeKey)rfree,
1011 (filedepHashFreeData)rfree);
1012 addIndexToDepHashes(ts, RPMTAG_CONFLICTNAME, NULL((void*)0), confilehash, connothash, connotfilehash);
1013 if (!filedepHashNumKeys(confilehash))
1014 confilehash = filedepHashFree(confilehash);
1015 if (!depexistsHashNumKeys(connothash))
1016 connothash= depexistsHashFree(connothash);
1017 if (!filedepHashNumKeys(connotfilehash))
1018 connotfilehash = filedepHashFree(connotfilehash);
1019
1020 /* build hashes of all requires dependencies */
1021 reqfilehash = filedepHashCreate(8191, rstrhash, strcmp,
1022 (filedepHashFreeKey)rfree,
1023 (filedepHashFreeData)rfree);
1024 reqnothash = depexistsHashCreate(257, rstrhash, strcmp,
1025 (filedepHashFreeKey)rfree);
1026 reqnotfilehash = filedepHashCreate(257, rstrhash, strcmp,
1027 (filedepHashFreeKey)rfree,
1028 (filedepHashFreeData)rfree);
1029 addIndexToDepHashes(ts, RPMTAG_REQUIRENAME, NULL((void*)0), reqfilehash, reqnothash, reqnotfilehash);
1030 if (!filedepHashNumKeys(reqfilehash))
1031 reqfilehash = filedepHashFree(reqfilehash);
1032 if (!depexistsHashNumKeys(reqnothash))
1033 reqnothash= depexistsHashFree(reqnothash);
1034 if (!filedepHashNumKeys(reqnotfilehash))
1035 reqnotfilehash = filedepHashFree(reqnotfilehash);
1036
1037 /*
1038 * Look at all of the added packages and make sure their dependencies
1039 * are satisfied.
1040 */
1041 pi = rpmtsiInit(ts);
1042 while ((p = rpmtsiNext(pi, TR_ADDED)) != NULL((void*)0)) {
1043 rpmds provides = rpmdsInit(rpmteDS(p, RPMTAG_PROVIDENAME));
1044
1045 rpmlog(RPMLOG_DEBUG, "========== +++ %s %s/%s 0x%x\n",
1046 rpmteNEVR(p), rpmteA(p), rpmteO(p), rpmteColor(p));
1047
1048 checkDS(ts, dcache, p, rpmteNEVRA(p), rpmteDS(p, RPMTAG_REQUIRENAME),
1049 tscolor);
1050 checkDS(ts, dcache, p, rpmteNEVRA(p), rpmteDS(p, RPMTAG_CONFLICTNAME),
1051 tscolor);
1052 checkDS(ts, dcache, p, rpmteNEVRA(p), rpmteDS(p, RPMTAG_OBSOLETENAME),
1053 tscolor);
1054
1055 /* Check provides against conflicts in installed packages. */
1056 while (rpmdsNext(provides) >= 0) {
1057 const char *dep = rpmdsN(provides);
1058 checkInstDeps(ts, dcache, p, RPMTAG_CONFLICTNAME, dep);
1059 if (reqnothash && depexistsHashHasEntry(reqnothash, dep))
1060 checkNotInstDeps(ts, dcache, p, RPMTAG_REQUIRENAME, dep);
1061 }
1062
1063 /* Skip obsoletion checks for source packages (ie build) */
1064 if (rpmteIsSource(p))
1065 continue;
1066
1067 /* Check package name (not provides!) against installed obsoletes */
1068 checkInstDeps(ts, dcache, p, RPMTAG_OBSOLETENAME, rpmteN(p));
1069
1070 /* Check filenames against installed conflicts */
1071 if (confilehash || reqnotfilehash) {
1072 rpmfiles files = rpmteFiles(p);
1073 rpmfi fi = rpmfilesIter(files, RPMFI_ITER_FWD);
1074 while (rpmfiNext(fi) >= 0) {
1075 if (confilehash)
1076 checkInstFileDeps(ts, dcache, p, RPMTAG_CONFLICTNAME, fi, 0, confilehash, &fpc);
1077 if (reqnotfilehash)
1078 checkInstFileDeps(ts, dcache, p, RPMTAG_REQUIRENAME, fi, 1, reqnotfilehash, &fpc);
1079 }
1080 rpmfiFree(fi);
1081 rpmfilesFree(files);
1082 }
1083 }
1084 rpmtsiFree(pi);
1085
1086 /*
1087 * Look at the removed packages and make sure they aren't critical.
1088 */
1089 pi = rpmtsiInit(ts);
1090 while ((p = rpmtsiNext(pi, TR_REMOVED)) != NULL((void*)0)) {
1091 rpmds provides = rpmdsInit(rpmteDS(p, RPMTAG_PROVIDENAME));
1092
1093 rpmlog(RPMLOG_DEBUG, "========== --- %s %s/%s 0x%x\n",
1094 rpmteNEVR(p), rpmteA(p), rpmteO(p), rpmteColor(p));
1095
1096 /* Check provides and filenames against installed dependencies. */
1097 while (rpmdsNext(provides) >= 0) {
1098 const char *dep = rpmdsN(provides);
1099 checkInstDeps(ts, dcache, p, RPMTAG_REQUIRENAME, dep);
1100 if (connothash && depexistsHashHasEntry(connothash, dep))
1101 checkNotInstDeps(ts, dcache, p, RPMTAG_CONFLICTNAME, dep);
1102 }
1103
1104 if (reqfilehash || connotfilehash) {
1105 rpmfiles files = rpmteFiles(p);
1106 rpmfi fi = rpmfilesIter(files, RPMFI_ITER_FWD);;
1107 while (rpmfiNext(fi) >= 0) {
1108 if (RPMFILE_IS_INSTALLED(rpmfiFState(fi))((rpmfiFState(fi)) == RPMFILE_STATE_NORMAL || (rpmfiFState(fi
)) == RPMFILE_STATE_NETSHARED)
) {
1109 if (reqfilehash)
1110 checkInstFileDeps(ts, dcache, p, RPMTAG_REQUIRENAME, fi, 0, reqfilehash, &fpc);
1111 if (connotfilehash)
1112 checkInstFileDeps(ts, dcache, p, RPMTAG_CONFLICTNAME, fi, 1, connotfilehash, &fpc);
1113 }
1114 }
1115 rpmfiFree(fi);
1116 rpmfilesFree(files);
1117 }
1118 }
1119 rpmtsiFree(pi);
1120
1121 if (rdb)
1122 rpmdbCtrl(rdb, RPMDB_CTRL_UNLOCK_RO);
1123
1124exit:
1125 depCacheFree(dcache);
1126 filedepHashFree(confilehash);
1127 filedepHashFree(connotfilehash);
1128 depexistsHashFree(connothash);
1129 filedepHashFree(reqfilehash);
1130 filedepHashFree(reqnotfilehash);
1131 depexistsHashFree(reqnothash);
1132 fpCacheFree(fpc);
1133
1134 (void) rpmswExit(rpmtsOp(ts, RPMTS_OP_CHECK), 0);
1135
1136 if (closeatexit)
1137 (void) rpmtsCloseDB(ts);
1138 return rc;
1139}