File: | lib/depends.c |
Warning: | line 453, column 6 Value stored to 'p' is never read |
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 | |
22 | const char * const RPMVERSION = VERSION"4.13.90"; |
23 | |
24 | const char * const rpmNAME = PACKAGE"rpm"; |
25 | |
26 | const char * const rpmEVR = VERSION"4.13.90"; |
27 | |
28 | const 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 | |
67 | enum 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 | */ |
78 | static 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 | */ |
111 | static 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 */ |
146 | rpmdbMatchIterator 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 | */ |
166 | static 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). */ |
172 | static 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). */ |
205 | static 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 | */ |
264 | static 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 | */ |
283 | static 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 | */ |
319 | static 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 | |
371 | exit: |
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 | |
394 | rpmal 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 | |
412 | static 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 | |
483 | exit: |
484 | return ec; |
485 | } |
486 | |
487 | int 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 | |
496 | int 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 | |
505 | int 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 */ |
513 | static 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 | */ |
602 | static 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 | |
610 | retry: |
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 | |
700 | unsatisfied: |
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 | |
710 | exit: |
711 | return rc; |
712 | } |
713 | |
714 | /* Check a dependency set for problems */ |
715 | static 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 */ |
736 | static 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 | |
769 | static 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 | |
779 | static 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 | |
820 | static 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 | |
837 | static 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 | |
848 | static 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 | |
879 | int 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 | |
1034 | exit: |
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 | } |