Bug Summary

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