rpm 5.2.1

- Main Page
- Related Pages
- Modules
- Data Structures
- Files

- File List
- Globals

depends.c
Go to the documentation of this file.
1
5 #include "system.h"
6
7 #include <rpmio.h>
8 #include <rpmiotypes.h> /* XXX fnpyKey */
9 #include <rpmcb.h>
10 #include <rpmmacro.h> /* XXX rpmExpand("%{_dependency_whiteout}" */
11 #include <envvar.h>
12 #include <ugid.h> /* XXX user()/group() probes */
13
14 #include <rpmtag.h>
15 #define _RPMDB_INTERNAL /* XXX response cache needs dbiOpen et al. */
16 #include <rpmdb.h>
17
18 #define _RPMTE_INTERNAL
19 #include <rpmte.h>
20 #define _RPMTS_INTERNAL
21 #include <rpmcli.h> /* XXX rpmcliPackagesTotal */
22
23 #define _RPMEVR_INTERNAL
24 #include <rpmds.h>
25 #include <rpmfi.h>
26
27 #include "debug.h"
28
29 /*@access tsortInfo @*/
30 /*@access rpmte @*/ /* XXX for install <-> erase associate. */
31 /*@access rpmts @*/
32 /*@access rpmDiskSpaceInfo @*/
33
34 /*@access alKey @*/ /* XXX for reordering and RPMAL_NOMATCH assign */
35
38 typedef /*@abstract@*/ struct orderListIndex_s * orderListIndex;
39 /*@access orderListIndex@*/
40
43 struct orderListIndex_s {
44 /*@dependent@*/
45 alKey pkgKey;
46 int orIndex;
47 };
48
49 #if defined(CACHE_DEPENDENCY_RESULT)
50 /*@unchecked@*/
51 int _cacheDependsRC = CACHE_DEPENDENCY_RESULT;
52 #endif
53
54 /*@observer@*/ /*@unchecked@*/
55 const char *rpmNAME = PACKAGE;
56
57 /*@observer@*/ /*@unchecked@*/
58 const char *rpmEVR = VERSION;
59
60 /*@unchecked@*/
61 int rpmFLAGS = RPMSENSE_EQUAL;
62
69 static int intcmp(const void * a, const void * b)
70 /*@requires maxRead(a) == 0 /\ maxRead(b) == 0 @*/
71 {
72 const int * aptr = a;
73 const int * bptr = b;
74 int rc = (*aptr - *bptr);
75 return rc;
76 }
77
87 static int removePackage(rpmts ts, Header h, int dboffset,
88 /*@null@*/ int * indexp,
89 /*@exposed@*/ /*@dependent@*/ /*@null@*/ alKey depends)
90 /*@globals rpmGlobalMacroContext, h_errno, fileSystem, internalState @*/
91 /*@modifies ts, h, *indexp, rpmGlobalMacroContext, fileSystem, internalState @*/
92 {
93 rpmte p;
94
95 /* Filter out duplicate erasures. */
96 if (ts->numRemovedPackages > 0 && ts->removedPackages != NULL) {
97 int * needle = NULL;
98 needle = bsearch(&dboffset, ts->removedPackages, ts->numRemovedPackages,
99 sizeof(*ts->removedPackages), intcmp);
100 if (needle != NULL) {
101 /* XXX lastx should be per-call, not per-ts. */
102 if (indexp != NULL)
103 *indexp = needle - ts->removedPackages;
104 return 0;
105 }
106 }
107
108 if (ts->numRemovedPackages == ts->allocedRemovedPackages) {
109 ts->allocedRemovedPackages += ts->delta;
110 ts->removedPackages = xrealloc(ts->removedPackages,
111 sizeof(ts->removedPackages) * ts->allocedRemovedPackages);
112 }
113
114 if (ts->removedPackages != NULL) { /* XXX can't happen. */
115 ts->removedPackages[ts->numRemovedPackages] = dboffset;
116 ts->numRemovedPackages++;
117 if (ts->numRemovedPackages > 1)
118 qsort(ts->removedPackages, ts->numRemovedPackages,
119 sizeof(*ts->removedPackages), intcmp);
120 }
121
122 if (ts->orderCount >= ts->orderAlloced) {
123 ts->orderAlloced += (ts->orderCount - ts->orderAlloced) + ts->delta;
124 /*@-type +voidabstract @*/
125 ts->order = xrealloc(ts->order, sizeof(*ts->order) * ts->orderAlloced);
126 /*@=type =voidabstract @*/
127 }
128
129 p = rpmteNew(ts, h, TR_REMOVED, NULL, NULL, dboffset, depends);
130 ts->order[ts->orderCount] = p;
131 if (indexp != NULL)
132 *indexp = ts->orderCount;
133 ts->orderCount++;
134
135 /*@-nullstate@*/ /* XXX FIX: ts->order[] can be NULL. */
136 return 0;
137 /*@=nullstate@*/
138 }
139
146 static int rpmHeadersIdentical(Header first, Header second)
147 /*@globals internalState @*/
148 /*@modifies internalState @*/
149 {
150 HE_t he = memset(alloca(sizeof(*he)), 0, sizeof(*he));
151 const char * one, * two;
152 int rc = 0;
153 int xx;
154
155 he->tag = RPMTAG_HDRID;
156 xx = headerGet(first, he, 0);
157 one = he->p.str;
158 he->tag = RPMTAG_HDRID;
159 xx = headerGet(second, he, 0);
160 two = he->p.str;
161
162 if (one && two)
163 rc = ((strcmp(one, two) == 0) ? 1 : 0);
164 else if (one && !two)
165 rc = 0;
166 else if (!one && two)
167 rc = 0;
168 else {
169 /* XXX Headers w/o digests case devolves to NEVR comparison. */
170 rpmds A = rpmdsThis(first, RPMTAG_REQUIRENAME, RPMSENSE_EQUAL);
171 rpmds B = rpmdsThis(second, RPMTAG_REQUIRENAME, RPMSENSE_EQUAL);
172 rc = rpmdsCompare(A, B);
173 (void)rpmdsFree(A);
174 A = NULL;
175 (void)rpmdsFree(B);
176 B = NULL;
177 }
178 one = _free(one);
179 two = _free(two);
180 return rc;
181 }
182
183 /*@unchecked@*/
184 static rpmTag _upgrade_tag;
185 /*@unchecked@*/
186 static rpmTag _debuginfo_tag;
187 /*@unchecked@*/
188 static rpmTag _obsolete_tag;
189
198 static int rpmtsAddUpgrades(rpmts ts, rpmte p, rpmuint32_t hcolor, Header h)
199 /*@globals rpmGlobalMacroContext, h_errno, fileSystem, internalState @*/
200 /*@modifies ts, p, rpmGlobalMacroContext, fileSystem, internalState @*/
201 {
202 HE_t he = memset(alloca(sizeof(*he)), 0, sizeof(*he));
203 rpmuint32_t tscolor = rpmtsColor(ts);
204 alKey pkgKey = rpmteAddedKey(p);
205 rpmuint32_t ohcolor;
206 rpmmi mi;
207 Header oh;
208 int xx;
209
210 if (_upgrade_tag == 0) {
211 const char * t = rpmExpand("%{?_upgrade_tag}", NULL);
212 /*@-mods@*/
213 _upgrade_tag = (!strcmp(t, "name") ? RPMTAG_NAME : RPMTAG_PROVIDENAME);
214 /*@=mods@*/
215 t = _free(t);
216 }
217
218 mi = rpmtsInitIterator(ts, _upgrade_tag, rpmteN(p), 0);
219 while((oh = rpmmiNext(mi)) != NULL) {
220 int lastx;
221 rpmte q;
222
223 /* Ignore colored packages not in our rainbow. */
224 ohcolor = hGetColor(oh);
225 if (tscolor && hcolor && ohcolor && !(hcolor & ohcolor))
226 continue;
227
228 /* Snarf the original install tid & time from older package(s). */
229 he->tag = RPMTAG_ORIGINTID;
230 xx = headerGet(oh, he, 0);
231 if (xx && he->p.ui32p != NULL) {
232 if (p->originTid[0] == 0 || p->originTid[0] > he->p.ui32p[0]
233 || (he->c > 1 && p->originTid[0] == he->p.ui32p[0] && p->originTid[1] > he->p.ui32p[1]))
234 {
235 p->originTid[0] = he->p.ui32p[0];
236 p->originTid[1] = (he->c > 1 ? he->p.ui32p[1] : 0);
237 }
238 he->p.ptr = _free(he->p.ptr);
239 }
240 he->tag = RPMTAG_ORIGINTIME;
241 xx = headerGet(oh, he, 0);
242 if (xx && he->p.ui32p != NULL) {
243 if (p->originTime[0] == 0 || p->originTime[0] > he->p.ui32p[0]
244 || (he->c > 1 && p->originTime[0] == he->p.ui32p[0] && p->originTime[1] > he->p.ui32p[1]))
245 {
246 p->originTime[0] = he->p.ui32p[0];
247 p->originTime[1] = (he->c > 1 ? he->p.ui32p[1] : 0);
248 }
249 he->p.ptr = _free(he->p.ptr);
250 }
251
252 #if defined(RPM_VENDOR_WINDRIVER)
253 /*
254 * If we're capable of installing multiple colors
255 * but at least one of the packages are white (0), we
256 * further verify the arch is the same (or compatible) to trigger an upgrade
257 * we do have a special case to allow upgrades of noarch w/ a arch package
258 */
259 if (tscolor && (!hcolor || !ohcolor)) {
260 const char * arch;
261 const char * oharch;
262 he->tag = RPMTAG_ARCH;
263 xx = headerGet(h, he, 0);
264 arch = (xx && he->p.str != NULL ? he->p.str : NULL);
265 he->tag = RPMTAG_ARCH;
266 xx = headerGet(oh, he, 0);
267 oharch = (xx && he->p.str != NULL ? he->p.str : NULL);
268 if (arch != NULL && oharch != NULL) {
269 if (strcmp("noarch", arch) || strcmp("noarch", oharch)) {
270 if (!_isCompatibleArch(arch, oharch)) {
271 arch = _free(arch);
272 oharch = _free(oharch);
273 continue;
274 }
275 }
276 }
277 arch = _free(arch);
278 oharch = _free(oharch);
279 }
280 #endif
281
282 /* Skip identical packages. */
283 if (rpmHeadersIdentical(h, oh))
284 continue;
285
286 /* Create an erasure element. */
287 lastx = -1;
288 xx = removePackage(ts, oh, rpmmiInstance(mi), &lastx, pkgKey);
289 assert(lastx >= 0 && lastx < ts->orderCount);
290 q = ts->order[lastx];
291
292 /* Chain through upgrade flink. */
293 xx = rpmteChain(p, q, oh, "Upgrades");
294
295 /*@-nullptrarith@*/
296 rpmlog(RPMLOG_DEBUG, D_(" upgrade erases %s\n"), rpmteNEVRA(q));
297 /*@=nullptrarith@*/
298
299 }
300 mi = rpmmiFree(mi);
301
302 return 0;
303 }
304
311 static inline int chkSuffix(const char * fn, const char * suffix)
312 /*@*/
313 {
314 size_t flen = strlen(fn);
315 size_t slen = strlen(suffix);
316 return (flen > slen && !strcmp(fn + flen - slen, suffix));
317 }
318
327 static int rpmtsEraseDebuginfo(rpmts ts, rpmte p, Header h,
328 /*@exposed@*/ /*@dependent@*/ /*@null@*/ alKey pkgKey)
329 /*@globals rpmGlobalMacroContext, h_errno, fileSystem, internalState @*/
330 /*@modifies ts, p, rpmGlobalMacroContext, fileSystem, internalState @*/
331 {
332 HE_t he = memset(alloca(sizeof(*he)), 0, sizeof(*he));
333 const void *keyval = NULL;
334 size_t keylen = 0;
335 size_t nrefs = 0;
336 rpmuint32_t debuginfoInstance = 0;
337 Header debuginfoHeader = NULL;
338 rpmmi mi;
339 Header oh;
340 int xx;
341
342 /* XXX SOURCEPKGID is not populated reliably, do not use (yet). */
343 if (_debuginfo_tag == 0) {
344 const char * t = rpmExpand("%{?_debuginfo_tag}", NULL);
345 /*@-mods@*/
346 _debuginfo_tag = (*t != '\0' && !strcmp(t, "pkgid")
347 ? RPMTAG_SOURCEPKGID : RPMTAG_SOURCERPM);
348 /*@=mods@*/
349 t = _free(t);
350 }
351
352 /* Grab the retrieval key. */
353 switch (_debuginfo_tag) {
354 default: return 0; /*@notreached@*/ break;
355 case RPMTAG_SOURCERPM: keyval = rpmteSourcerpm(p); break;
356 }
357
358 /* Count remaining members in build set, excluding -debuginfo (if any). */
359 mi = rpmtsInitIterator(ts, _debuginfo_tag, keyval, keylen);
360 xx = rpmmiPrune(mi, ts->removedPackages, ts->numRemovedPackages, 1);
361 while((oh = rpmmiNext(mi)) != NULL) {
362 /* Skip identical packages. */
363 if (rpmHeadersIdentical(h, oh))
364 continue;
365
366 he->tag = RPMTAG_NAME;
367 xx = headerGet(oh, he, 0);
368 if (!xx || he->p.str == NULL)
369 continue;
370 /* Save the -debuginfo member. */
371 if (chkSuffix(he->p.str, "-debuginfo")) {
372 debuginfoInstance = rpmmiInstance(mi);
373 debuginfoHeader = headerLink(oh);
374 } else
375 nrefs++;
376 he->p.str = _free(he->p.str);
377 }
378 mi = rpmmiFree(mi);
379
380 /* Remove -debuginfo package when last build member is erased. */
381 if (nrefs == 0 && debuginfoInstance > 0 && debuginfoHeader != NULL) {
382 int lastx = -1;
383 rpmte q;
384
385 /* Create an erasure element. */
386 lastx = -1;
387 xx = removePackage(ts, debuginfoHeader, debuginfoInstance,
388 &lastx, pkgKey);
389 assert(lastx >= 0 && lastx < ts->orderCount);
390 q = ts->order[lastx];
391
392 /* Chain through upgrade flink. */
393 /* XXX avoid assertion failure when erasing. */
394 if (pkgKey != RPMAL_NOMATCH)
395 xx = rpmteChain(p, q, oh, "Upgrades");
396
397 /*@-nullptrarith@*/
398 rpmlog(RPMLOG_DEBUG, D_(" lastref erases %s\n"), rpmteNEVRA(q));
399 /*@=nullptrarith@*/
400
401 }
402 (void)headerFree(debuginfoHeader);
403 debuginfoHeader = NULL;
404
405 return (int)nrefs;
406 }
407
415 static int rpmtsAddObsoletes(rpmts ts, rpmte p, rpmuint32_t hcolor)
416 /*@globals rpmGlobalMacroContext, h_errno, fileSystem, internalState @*/
417 /*@modifies ts, p, rpmGlobalMacroContext, fileSystem, internalState @*/
418 {
419 rpmuint32_t tscolor = rpmtsColor(ts);
420 alKey pkgKey = rpmteAddedKey(p);
421 rpmuint32_t ohcolor;
422 rpmds obsoletes;
423 rpmuint32_t dscolor;
424 rpmmi mi;
425 Header oh;
426 int xx;
427
428 if (_obsolete_tag == 0) {
429 const char *t = rpmExpand("%{?_obsolete_tag}", NULL);
430 /*@-mods@*/
431 _obsolete_tag = (!strcmp(t, "name") ? RPMTAG_NAME : RPMTAG_PROVIDENAME);
432 /*@=mods@*/
433 t = _free(t);
434 }
435
436 obsoletes = rpmdsLink(rpmteDS(p, RPMTAG_OBSOLETENAME), "Obsoletes");
437 obsoletes = rpmdsInit(obsoletes);
438 if (obsoletes != NULL)
439 while (rpmdsNext(obsoletes) >= 0) {
440 const char * Name;
441
442 if ((Name = rpmdsN(obsoletes)) == NULL)
443 continue; /* XXX can't happen */
444
445 /* Ignore colored obsoletes not in our rainbow. */
446 #if 0
447 /* XXX obsoletes are never colored, so this is for future devel. */
448 dscolor = rpmdsColor(obsoletes);
449 #else
450 dscolor = hcolor;
451 #endif
452 if (tscolor && dscolor && !(tscolor & dscolor))
453 continue;
454
455 /* XXX avoid self-obsoleting packages. */
456 if (!strcmp(rpmteN(p), Name))
457 continue;
458
459 /* Obsolete containing package if given a file, otherwise provide. */
460 if (Name[0] == '/')
461 mi = rpmtsInitIterator(ts, RPMTAG_BASENAMES, Name, 0);
462 else
463 mi = rpmtsInitIterator(ts, _obsolete_tag, Name, 0);
464
465 xx = rpmmiPrune(mi,
466 ts->removedPackages, ts->numRemovedPackages, 1);
467
468 while((oh = rpmmiNext(mi)) != NULL) {
469 int lastx;
470 rpmte q;
471
472 /* Ignore colored packages not in our rainbow. */
473 ohcolor = hGetColor(oh);
474
475 /* XXX provides *are* colored, effectively limiting Obsoletes:
476 to matching only colored Provides: based on pkg coloring. */
477 if (tscolor && hcolor && ohcolor && !(hcolor & ohcolor))
478 /*@innercontinue@*/ continue;
479
480 /*
481 * Rpm prior to 3.0.3 does not have versioned obsoletes.
482 * If no obsoletes version info is available, match all names.
483 */
484 if (!(rpmdsEVR(obsoletes) == NULL
485 || rpmdsAnyMatchesDep(oh, obsoletes, _rpmds_nopromote)))
486 /*@innercontinue@*/ continue;
487
488 /* Create an erasure element. */
489 lastx = -1;
490 xx = removePackage(ts, oh, rpmmiInstance(mi), &lastx, pkgKey);
491 assert(lastx >= 0 && lastx < ts->orderCount);
492 q = ts->order[lastx];
493
494 /* Chain through obsoletes flink. */
495 xx = rpmteChain(p, q, oh, "Obsoletes");
496
497 /*@-nullptrarith@*/
498 rpmlog(RPMLOG_DEBUG, D_(" Obsoletes: %s\t\terases %s\n"),
499 rpmdsDNEVR(obsoletes)+2, rpmteNEVRA(q));
500 /*@=nullptrarith@*/
501 }
502 mi = rpmmiFree(mi);
503 }
504 (void)rpmdsFree(obsoletes);
505 obsoletes = NULL;
506
507 return 0;
508 }
509
510 #if defined(RPM_VENDOR_WINDRIVER)
511 /* Is "compat" compatible w/ arch? */
512 int _isCompatibleArch(const char * arch, const char * compat)
513 {
514 const char * compatArch = rpmExpand(compat, " %{?_", compat, "_compat_arch}", NULL);
515 const char * p, * pe, * t;
516 int match = 0;
517
518 /* Hack to ensure iX86 being automatically compatible */
519 if (arch[0] == 'i' && arch[2] == '8' && arch[3] == '6') {
520 if ((arch[0] == compat[0]) &&
521 (arch[2] == compat[2]) &&
522 (arch[3] == compat[3]))
523 match = 1;
524
525 if (!strcmp(compat, "x86_32"))
526 match = 1;
527 }
528
529 for ( p = pe = compatArch ; *pe && match == 0 ; ) {
530 while (*p && xisspace(*p)) p++;
531 pe = p ; while (*pe && !xisspace(*pe)) pe++;
532 if (p == pe)
533 break;
534 t = strndup(p, (pe - p));
535 p = pe; /* Advance to next chunk */
536 rpmlog(RPMLOG_DEBUG, D_(" Comparing compat archs %s ? %s\n"), arch, t);
537 if (!strcmp(arch, t))
538 match = 1;
539 t = _free(t);
540 }
541 compatArch = _free(compatArch);
542 return match;
543 }
544 #endif
545
546 int rpmtsAddInstallElement(rpmts ts, Header h,
547 fnpyKey key, int upgrade, rpmRelocation relocs)
548 {
549 HE_t he = memset(alloca(sizeof(*he)), 0, sizeof(*he));
550 rpmdepFlags depFlags = rpmtsDFlags(ts);
551 rpmuint32_t tscolor = rpmtsColor(ts);
552 rpmuint32_t hcolor;
553 int isSource;
554 int duplicate = 0;
555 rpmtsi pi = NULL; rpmte p;
556 const char * arch = NULL;
557 const char * os = NULL;
558 rpmds oldChk, newChk;
559 alKey pkgKey; /* addedPackages key */
560 int xx;
561 int ec = 0;
562 int rc;
563 int oc;
564
565 hcolor = hGetColor(h);
566 pkgKey = RPMAL_NOMATCH;
567
568 /*
569 * Always add source headers.
570 */
571 isSource =
572 (headerIsEntry(h, RPMTAG_SOURCERPM) == 0 &&
573 headerIsEntry(h, RPMTAG_ARCH) != 0);
574 if (isSource) {
575 oc = ts->orderCount;
576 goto addheader;
577 }
578
579 /*
580 * Check platform affinity of binary packages.
581 */
582 he->tag = RPMTAG_ARCH;
583 xx = headerGet(h, he, 0);
584 arch = he->p.str;
585 he->tag = RPMTAG_OS;
586 xx = headerGet(h, he, 0);
587 os = he->p.str;
588 if (nplatpat > 1) {
589 const char * platform = NULL;
590
591 he->tag = RPMTAG_PLATFORM;
592 xx = headerGet(h, he, 0);
593 platform = he->p.str;
594 if (!xx || platform == NULL)
595 platform = rpmExpand(arch, "-unknown-", os, NULL);
596
597 rc = rpmPlatformScore(platform, platpat, nplatpat);
598 if (rc <= 0) {
599 rpmps ps = rpmtsProblems(ts);
600 he->tag = RPMTAG_NVRA;
601 xx = headerGet(h, he, 0);
602 assert(he->p.str != NULL);
603
604 rpmpsAppend(ps, RPMPROB_BADPLATFORM, he->p.str, key,
605 platform, NULL, NULL, 0);
606
607 /* XXX problem string should be printed by caller instead. */
608 if (rpmIsVerbose()) {
609 const char * msg = rpmProblemString(rpmpsGetProblem(ps, -1));
610 rpmlog(RPMLOG_WARNING, "%s\n", msg);
611 msg = _free(msg);
612 }
613
614 ps = rpmpsFree(ps);
615 he->p.ptr = _free(he->p.ptr);
616 ec = 1;
617 }
618 platform = _free(platform);
619 if (ec)
620 goto exit;
621 }
622
623 /*
624 * Always install compatible binary packages.
625 */
626 if (!upgrade) {
627 oc = ts->orderCount;
628 goto addheader;
629 }
630
631 /*
632 * Check that upgrade package is uniquely newer, replace older if necessary.
633 */
634 oldChk = rpmdsThis(h, RPMTAG_REQUIRENAME, (RPMSENSE_LESS));
635 newChk = rpmdsThis(h, RPMTAG_REQUIRENAME, (RPMSENSE_EQUAL|RPMSENSE_GREATER));
636 /* XXX can't use rpmtsiNext() filter or oc will have wrong value. */
637 for (pi = rpmtsiInit(ts), oc = 0; (p = rpmtsiNext(pi, 0)) != NULL; oc++) {
638 rpmds this;
639
640 /* XXX Only added packages need be checked for dupes here. */
641 if (rpmteType(p) == TR_REMOVED)
642 continue;
643
644 /* XXX Never check source header NEVRAO. */
645 if (rpmteIsSource(p))
646 continue;
647
648 if (tscolor) {
649 const char * parch;
650 const char * pos;
651
652 if (arch == NULL || (parch = rpmteA(p)) == NULL)
653 continue;
654 #if defined(RPM_VENDOR_WINDRIVER)
655 /* XXX hackery for alias matching. */
656 if (!_isCompatibleArch(arch, parch))
657 continue;
658 #else
659 /* XXX hackery for i[3456]86 alias matching. */
660 if (arch[0] == 'i' && arch[2] == '8' && arch[3] == '6') {
661 if (arch[0] != parch[0]) continue;
662 if (arch[2] != parch[2]) continue;
663 if (arch[3] != parch[3]) continue;
664 }
665 #endif
666 else if (strcmp(arch, parch))
667 continue;
668 if (os == NULL || (pos = rpmteO(p)) == NULL)
669 continue;
670
671 if (strcmp(os, pos))
672 continue;
673 }
674
675 /* OK, binary rpm's with same arch and os. Check NEVR. */
676 if ((this = rpmteDS(p, RPMTAG_NAME)) == NULL)
677 continue; /* XXX can't happen */
678
679 /* If newer NEVRAO already added, then skip adding older. */
680 rc = rpmdsCompare(newChk, this);
681 if (rc != 0) {
682 const char * pkgNEVR = rpmdsDNEVR(this);
683 const char * addNEVR = rpmdsDNEVR(oldChk);
684 if (rpmIsVerbose())
685 rpmlog(RPMLOG_WARNING,
686 _("package %s was already added, skipping %s\n"),
687 (pkgNEVR ? pkgNEVR + 2 : "?pkgNEVR?"),
688 (addNEVR ? addNEVR + 2 : "?addNEVR?"));
689 ec = 1;
690 break;
691 }
692
693 /* If older NEVRAO already added, then replace old with new. */
694 rc = rpmdsCompare(oldChk, this);
695 if (rc != 0) {
696 const char * pkgNEVR = rpmdsDNEVR(this);
697 const char * addNEVR = rpmdsDNEVR(newChk);
698 if (rpmIsVerbose())
699 rpmlog(RPMLOG_WARNING,
700 _("package %s was already added, replacing with %s\n"),
701 (pkgNEVR ? pkgNEVR + 2 : "?pkgNEVR?"),
702 (addNEVR ? addNEVR + 2 : "?addNEVR?"));
703 duplicate = 1;
704 pkgKey = rpmteAddedKey(p);
705 break;
706 }
707 }
708 pi = rpmtsiFree(pi);
709 (void)rpmdsFree(oldChk);
710 oldChk = NULL;
711 (void)rpmdsFree(newChk);
712 newChk = NULL;
713
714 /* If newer (or same) NEVRAO was already added, exit now. */
715 if (ec)
716 goto exit;
717
718 addheader:
719 if (oc >= ts->orderAlloced) {
720 ts->orderAlloced += (oc - ts->orderAlloced) + ts->delta;
721 /*@-type +voidabstract @*/
722 ts->order = xrealloc(ts->order, ts->orderAlloced * sizeof(*ts->order));
723 /*@=type =voidabstract @*/
724 }
725
726 p = rpmteNew(ts, h, TR_ADDED, key, relocs, -1, pkgKey);
727 assert(p != NULL);
728
729 if (duplicate && oc < ts->orderCount) {
730 /*@-type -unqualifiedtrans@*/
731 ts->order[oc] = rpmteFree(ts->order[oc]);
732 /*@=type =unqualifiedtrans@*/
733 }
734
735 ts->order[oc] = p;
736 if (!duplicate) {
737 ts->orderCount++;
738 rpmcliPackagesTotal++;
739 }
740
741 pkgKey = rpmalAdd(&ts->addedPackages, pkgKey, rpmteKey(p),
742 rpmteDS(p, RPMTAG_PROVIDENAME),
743 rpmteFI(p, RPMTAG_BASENAMES), tscolor);
744 if (pkgKey == RPMAL_NOMATCH) {
745 ts->order[oc] = rpmteFree(ts->order[oc]);
746 ts->teInstall = NULL;
747 ec = 1;
748 goto exit;
749 }
750 (void) rpmteSetAddedKey(p, pkgKey);
751
752 if (!duplicate) {
753 ts->numAddedPackages++;
754 }
755
756 ts->teInstall = ts->order[oc];
757
758 /* XXX rpmgi hack: Save header in transaction element if requested. */
759 if (upgrade & 0x2)
760 (void) rpmteSetHeader(p, h);
761
762 /* If not upgrading, then we're done. */
763 if (!(upgrade & 0x1))
764 goto exit;
765
766 /* If source rpm, then we're done. */
767 if (isSource)
768 goto exit;
769
770 /* Do lazy (readonly?) open of rpm database. */
771 if (rpmtsGetRdb(ts) == NULL && rpmtsDBMode(ts) != -1) {
772 if ((ec = rpmtsOpenDB(ts, rpmtsDBMode(ts)) != 0))
773 goto exit;
774 }
775
776 /* Add upgrades to the transaction (if not disabled). */
777 if (!(depFlags & RPMDEPS_FLAG_NOUPGRADE)) {
778 /*
779 * Don't upgrade -debuginfo until build set is empty.
780 *
781 * XXX Almost, but not quite, correct since the test depends on
782 * added package arrival order.
783 * I.e. -debuginfo additions must always follow all
784 * other additions so that erasures of other members in the
785 * same build set are seen if/when included in the same transaction.
786 */
787 xx = rpmtsEraseDebuginfo(ts, p, h, pkgKey);
788 if (!chkSuffix(rpmteN(p), "-debuginfo") || xx == 0)
789 xx = rpmtsAddUpgrades(ts, p, hcolor, h);
790 }
791
792 /* Add Obsoletes: to the transaction (if not disabled). */
793 if (!(depFlags & RPMDEPS_FLAG_NOOBSOLETES)) {
794 xx = rpmtsAddObsoletes(ts, p, hcolor);
795 }
796
797 ec = 0;
798
799 exit:
800 arch = _free(arch);
801 os = _free(os);
802 pi = rpmtsiFree(pi);
803 return ec;
804 }
805
806 int rpmtsAddEraseElement(rpmts ts, Header h, int dboffset)
807 {
808 int oc = -1;
809 int rc = removePackage(ts, h, dboffset, &oc, RPMAL_NOMATCH);
810 if (rc == 0 && oc >= 0 && oc < ts->orderCount) {
811 (void) rpmtsEraseDebuginfo(ts, ts->order[oc], h, RPMAL_NOMATCH);
812 ts->teErase = ts->order[oc];
813 } else
814 ts->teErase = NULL;
815 return rc;
816 }
817
818 /*@only@*/ /*@null@*/ /*@unchecked@*/
819 static char *sysinfo_path = NULL;
820
821 /*@refcounted@*/ /*@null@*/ /*@unchecked@*/
822 static rpmds rpmlibP = NULL;
823 /*@refcounted@*/ /*@null@*/ /*@unchecked@*/
824 rpmds cpuinfoP = NULL;
825 /*@refcounted@*/ /*@null@*/ /*@unchecked@*/
826 static rpmds getconfP = NULL;
827 /*@refcounted@*/ /*@null@*/ /*@unchecked@*/
828 static rpmds unameP = NULL;
829
830 void rpmnsClean(void)
831 /*@globals sysinfo_path, _sysinfo_path, rpmlibP, cpuinfoP, getconfP, unameP @*/
832 /*@modifies sysinfo_path, _sysinfo_path, rpmlibP, cpuinfoP, getconfP, unameP @*/
833 {
834 (void)rpmdsFree(rpmlibP);
835 rpmlibP = NULL;
836 (void)rpmdsFree(cpuinfoP);
837 cpuinfoP = NULL;
838 (void)rpmdsFree(getconfP);
839 getconfP = NULL;
840 (void)rpmdsFree(unameP);
841 unameP = NULL;
842 /*@-observertrans@*/
843 _sysinfo_path = _free(_sysinfo_path);
844 /*@=observertrans@*/
845 sysinfo_path = _free(sysinfo_path);
846 }
847
855 static int unsatisfiedDepend(rpmts ts, rpmds dep, int adding)
856 /*@globals rpmGlobalMacroContext, h_errno,
857 sysinfo_path, fileSystem, internalState @*/
858 /*@modifies ts, dep, rpmGlobalMacroContext,
859 sysinfo_path, fileSystem, internalState @*/
860 {
861 DBT * key = alloca(sizeof(*key));
862 DBT * data = alloca(sizeof(*data));
863 rpmmi mi;
864 nsType NSType;
865 const char * Name;
866 rpmuint32_t Flags;
867 Header h;
868 #if defined(CACHE_DEPENDENCY_RESULT)
869 int _cacheThisRC = 1;
870 #endif
871 int rc;
872 int xx;
873 int retries = 20;
874
875 if ((Name = rpmdsN(dep)) == NULL)
876 return 0; /* XXX can't happen */
877 Flags = rpmdsFlags(dep);
878 NSType = rpmdsNSType(dep);
879
880 #if defined(CACHE_DEPENDENCY_RESULT)
881 /*
882 * Check if dbiOpen/dbiPut failed (e.g. permissions), we can't cache.
883 */
884 if (_cacheDependsRC) {
885 dbiIndex dbi;
886 dbi = dbiOpen(rpmtsGetRdb(ts), RPMDBI_DEPENDS, 0);
887 if (dbi == NULL)
888 _cacheDependsRC = 0;
889 else {
890 const char * DNEVR;
891
892 rc = -1;
893 if ((DNEVR = rpmdsDNEVR(dep)) != NULL) {
894 DBC * dbcursor = NULL;
895 void * datap = NULL;
896 size_t datalen = 0;
897 size_t DNEVRlen = strlen(DNEVR);
898
899 xx = dbiCopen(dbi, dbiTxnid(dbi), &dbcursor, 0);
900
901 memset(key, 0, sizeof(*key));
902 /*@i@*/ key->data = (void *) DNEVR;
903 key->size = DNEVRlen;
904 memset(data, 0, sizeof(*data));
905 data->data = datap;
906 data->size = datalen;
907 /*@-nullstate@*/ /* FIX: data->data may be NULL */
908 xx = dbiGet(dbi, dbcursor, key, data, DB_SET);
909 /*@=nullstate@*/
910 DNEVR = key->data;
911 DNEVRlen = key->size;
912 datap = data->data;
913 datalen = data->size;
914
915 if (xx == 0 && datap && datalen == 4)
916 memcpy(&rc, datap, datalen);
917 xx = dbiCclose(dbi, dbcursor, 0);
918 }
919
920 if (rc >= 0) {
921 rpmdsNotify(dep, _("(cached)"), rc);
922 return rpmdsNegateRC(dep, rc);
923 }
924 }
925 }
926 #endif
927
928 retry:
929 rc = 0; /* assume dependency is satisfied */
930
931 /* Expand macro probe dependencies. */
932 if (NSType == RPMNS_TYPE_FUNCTION) {
933 xx = rpmExpandNumeric(Name);
934 rc = (xx ? 0 : 1);
935 if (Flags & RPMSENSE_MISSINGOK)
936 goto unsatisfied;
937 rpmdsNotify(dep, _("(function probe)"), rc);
938 goto exit;
939 }
940
941 /* Evaluate user/group lookup probes. */
942 if (NSType == RPMNS_TYPE_USER) {
943 const char *s;
944 uid_t uid = 0;
945 s = Name; while (*s && xisdigit(*s)) s++;
946
947 if (*s)
948 xx = unameToUid(Name, &uid);
949 else {
950 uid = strtol(Name, NULL, 10);
951 xx = (uidToUname(uid) ? 0 : -1);
952 }
953 rc = (xx >= 0 ? 0 : 1);
954 if (Flags & RPMSENSE_MISSINGOK)
955 goto unsatisfied;
956 rpmdsNotify(dep, _("(user lookup)"), rc);
957 goto exit;
958 }
959 if (NSType == RPMNS_TYPE_GROUP) {
960 const char *s;
961 gid_t gid = 0;
962 s = Name; while (*s && xisdigit(*s)) s++;
963
964 if (*s)
965 xx = gnameToGid(Name, &gid);
966 else {
967 gid = strtol(Name, NULL, 10);
968 xx = (gidToGname(gid) ? 0 : -1);
969 }
970 rc = (xx >= 0 ? 0 : 1);
971 if (Flags & RPMSENSE_MISSINGOK)
972 goto unsatisfied;
973 rpmdsNotify(dep, _("(group lookup)"), rc);
974 goto exit;
975 }
976
977 /* Evaluate access(2) probe dependencies. */
978 if (NSType == RPMNS_TYPE_ACCESS) {
979 rc = rpmioAccess(Name, NULL, X_OK);
980 if (Flags & RPMSENSE_MISSINGOK)
981 goto unsatisfied;
982 rpmdsNotify(dep, _("(access probe)"), rc);
983 goto exit;
984 }
985
986 /* Evaluate mtab lookup and diskspace probe dependencies. */
987 if (NSType == RPMNS_TYPE_MOUNTED) {
988 const char ** fs = NULL;
989 int nfs = 0;
990 int i = 0;
991
992 xx = rpmtsInitDSI(ts);
993 fs = ts->filesystems;
994 nfs = ts->filesystemCount;
995
996 if (fs != NULL)
997 for (i = 0; i < nfs; i++) {
998 if (!strcmp(fs[i], Name))
999 break;
1000 }
1001 rc = (i < nfs ? 0 : 1);
1002 if (Flags & RPMSENSE_MISSINGOK)
1003 goto unsatisfied;
1004 rpmdsNotify(dep, _("(mtab probe)"), rc);
1005 goto exit;
1006 }
1007
1008 if (NSType == RPMNS_TYPE_DISKSPACE) {
1009 size_t nb = strlen(Name);
1010 rpmDiskSpaceInfo dsi = NULL;
1011 const char ** fs = NULL;
1012 size_t fslen = 0, longest = 0;
1013 int nfs = 0;
1014 int i = 0;
1015
1016 xx = rpmtsInitDSI(ts);
1017 fs = ts->filesystems;
1018 nfs = ts->filesystemCount;
1019
1020 if (fs != NULL)
1021 for (i = 0; i < nfs; i++) {
1022 fslen = strlen(fs[i]);
1023 if (fslen > nb)
1024 continue;
1025 if (strncmp(fs[i], Name, fslen))
1026 continue;
1027 if (fslen > 1 && Name[fslen] != '/' && Name[fslen] != '\0')
1028 continue;
1029 if (fslen < longest)
1030 continue;
1031 longest = fslen;
1032 dsi = ts->dsi + i;
1033 }
1034 if (dsi == NULL)
1035 rc = 1; /* no mounted paths !?! */
1036 else {
1037 char * end = NULL;
1038 /*@-unrecog@*/
1039 rpmuint64_t needed = strtoll(rpmdsEVR(dep), &end, 0);
1040 /*@=unrecog@*/
1041
1042 if (end && *end) {
1043 if (strchr("Gg", end[0]) && strchr("Bb", end[1]) && !end[2])
1044 needed *= 1024 * 1024 * 1024;
1045 if (strchr("Mm", end[0]) && strchr("Bb", end[1]) && !end[2])
1046 needed *= 1024 * 1024;
1047 if (strchr("Kk", end[0]) && strchr("Bb", end[1]) && !end[2])
1048 needed *= 1024;
1049 } else
1050 needed *= 1024 * 1024; /* XXX assume Mb if no units given */
1051
1052 needed = BLOCK_ROUND(needed, dsi->f_bsize);
1053 xx = (dsi->f_bavail - needed);
1054 if ((Flags & RPMSENSE_LESS) && xx < 0) rc = 0;
1055 else if ((Flags & RPMSENSE_GREATER) && xx > 0) rc = 0;
1056 else if ((Flags & RPMSENSE_EQUAL) && xx == 0) rc = 0;
1057 else rc = 1;
1058 }
1059 if (Flags & RPMSENSE_MISSINGOK)
1060 goto unsatisfied;
1061 rpmdsNotify(dep, _("(diskspace probe)"), rc);
1062 goto exit;
1063 }
1064
1065 if (NSType == RPMNS_TYPE_DIGEST) {
1066 const char * EVR = rpmdsEVR(dep);
1067 const char *filename;
1068 pgpHashAlgo digestHashAlgo;
1069 FD_t fd;
1070 char *cp;
1071 int algo;
1072
1073 filename = Name;
1074 digestHashAlgo = PGPHASHALGO_MD5;
1075 if ((cp = strchr(filename, ':')) != NULL) {
1076 if ((algo = pgpHashAlgoStringToNumber(filename, cp-filename)) != PGPHASHALGO_ERROR) {
1077 digestHashAlgo = algo;
1078 filename = cp + 1;
1079 }
1080 }
1081 rc = 1; /* XXX assume failure */
1082 fd = Fopen(filename, "r.fdio");
1083 if (fd && !Ferror(fd)) {
1084 DIGEST_CTX ctx = rpmDigestInit(digestHashAlgo, RPMDIGEST_NONE);
1085 const char * digest = NULL;
1086 size_t digestlen = 0;
1087 int asAscii = 1;
1088 size_t nbuf = 8 * BUFSIZ;
1089 char * buf = alloca(nbuf);
1090 size_t nb;
1091
1092 while ((nb = Fread(buf, sizeof(buf[0]), nbuf, fd)) > 0)
1093 xx = rpmDigestUpdate(ctx, buf, nb);
1094 xx = Fclose(fd); fd = NULL;
1095 xx = rpmDigestFinal(ctx, &digest, &digestlen, asAscii);
1096
1097 xx = (EVR && *EVR && digest && *digest) ? strcasecmp(EVR, digest) : -1;
1098 /* XXX only equality makes sense for digest compares */
1099 if ((Flags & RPMSENSE_EQUAL) && xx == 0) rc = 0;
1100 }
1101 if (Flags & RPMSENSE_MISSINGOK)
1102 goto unsatisfied;
1103 rpmdsNotify(dep, _("(digest probe)"), rc);
1104 goto exit;
1105 }
1106
1107 if (NSType == RPMNS_TYPE_SIGNATURE) {
1108 const char * EVR = rpmdsEVR(dep);
1109 ARGV_t avN = NULL;
1110 ARGV_t avEVR = NULL;
1111 rpmRC res;
1112
1113 /* Split /fn:/sig */
1114 xx = argvSplit(&avN, Name, ":");
1115
1116 /* Split /pub:id */
1117 xx = (EVR && *EVR) ? argvSplit(&avEVR, EVR, ":") : argvAdd(&avEVR, "");
1118
1119 res = rpmnsProbeSignature(ts, avN[0], avN[1], avEVR[0], avEVR[1], 0);
1120 rc = (res == RPMRC_OK ? 0 : 1);
1121
1122 avN = argvFree(avN);
1123 avEVR = argvFree(avEVR);
1124
1125 if (Flags & RPMSENSE_MISSINGOK)
1126 goto unsatisfied;
1127 rpmdsNotify(dep, _("(signature probe)"), rc);
1128 goto exit;
1129 }
1130
1131 if (NSType == RPMNS_TYPE_VERIFY) {
1132 QVA_t qva = memset(alloca(sizeof(*qva)), 0, sizeof(*qva));
1133
1134 qva->qva_mode = 'v';
1135 qva->qva_flags = (int)(VERIFY_ALL & ~(VERIFY_DEPS|VERIFY_SCRIPT));
1136 rc = 0; /* assume success */
1137 if (rpmtsGetRdb(ts) != NULL) {
1138 if (!strcmp(Name, "*")) /* -Va probe */
1139 mi = rpmtsInitIterator(ts, RPMDBI_PACKAGES, NULL, 0);
1140 else if (Name[0] == '/') /* -Vf probe */
1141 mi = rpmtsInitIterator(ts, RPMTAG_BASENAMES, Name, 0);
1142 else /* -V probe */
1143 mi = rpmtsInitIterator(ts, RPMTAG_PROVIDENAME, Name, 0);
1144 while ((h = rpmmiNext(mi)) != NULL) {
1145 if (!(Name[0] == '/' || !strcmp(Name, "*")))
1146 if (!rpmdsAnyMatchesDep(h, dep, _rpmds_nopromote))
1147 continue;
1148 xx = (showVerifyPackage(qva, ts, h) ? 1 : 0);
1149 if (xx)
1150 rc = 1;
1151 }
1152 mi = rpmmiFree(mi);
1153 }
1154
1155 if (Flags & RPMSENSE_MISSINGOK)
1156 goto unsatisfied;
1157 rpmdsNotify(dep, _("(verify probe)"), rc);
1158 goto exit;
1159 }
1160
1161 if (NSType == RPMNS_TYPE_GNUPG) {
1162 const char * EVR = rpmdsEVR(dep);
1163 if (!(EVR && *EVR)) {
1164 static const char gnupg_pre[] = "%(%{__gpg} --batch --no-tty --quiet --verify ";
1165 static const char gnupg_post[] = " 2>/dev/null; echo $?)";
1166 const char * t = rpmExpand(gnupg_pre, Name, gnupg_post, NULL);
1167 rc = (t && t[0] == '0') ? 0 : 1;
1168 t = _free(t);
1169 }
1170 else {
1171 static const char gnupg_pre[] = "%(%{__gpg} --batch --no-tty --quiet --verify ";
1172 static const char gnupg_post[] = " 2>&1 | grep '^Primary key fingerprint:' | sed -e 's;^.*: *;;' -e 's; *;;g')";
1173 const char * t = rpmExpand(gnupg_pre, Name, gnupg_post, NULL);
1174 rc = ((Flags & RPMSENSE_EQUAL) && strcasecmp(EVR, t) == 0) ? 0 : 1;
1175 t = _free(t);
1176 }
1177 if (Flags & RPMSENSE_MISSINGOK)
1178 goto unsatisfied;
1179 rpmdsNotify(dep, _("(gnupg probe)"), rc);
1180 goto exit;
1181 }
1182
1183 if (NSType == RPMNS_TYPE_MACRO) {
1184 static const char macro_pre[] = "%{?";
1185 static const char macro_post[] = ":0}";
1186 const char * a = rpmExpand(macro_pre, Name, macro_post, NULL);
1187
1188 rc = (a && a[0] == '0') ? 0 : 1;
1189 a = _free(a);
1190 if (Flags & RPMSENSE_MISSINGOK)
1191 goto unsatisfied;
1192 rpmdsNotify(dep, _("(macro probe)"), rc);
1193 goto exit;
1194 }
1195
1196 if (NSType == RPMNS_TYPE_ENVVAR) {
1197 const char * a = envGet(Name);
1198 const char * b = rpmdsEVR(dep);
1199
1200 /* Existence test if EVR is missing/empty. */
1201 if (!(b && *b))
1202 rc = (!(a && *a));
1203 else {
1204 int sense = (a && *a) ? strcmp(a, b) : -1;
1205
1206 if ((Flags & RPMSENSE_SENSEMASK) == RPMSENSE_NOTEQUAL)
1207 rc = (sense == 0);
1208 else if (sense < 0 && (Flags & RPMSENSE_LESS))
1209 rc = 0;
1210 else if (sense > 0 && (Flags & RPMSENSE_GREATER))
1211 rc = 0;
1212 else if (sense == 0 && (Flags & RPMSENSE_EQUAL))
1213 rc = 0;
1214 else
1215 rc = (sense != 0);
1216 }
1217
1218 if (Flags & RPMSENSE_MISSINGOK)
1219 goto unsatisfied;
1220 rpmdsNotify(dep, _("(envvar probe)"), rc);
1221 goto exit;
1222 }
1223
1224 if (NSType == RPMNS_TYPE_RUNNING) {
1225 char *t = NULL;
1226 pid_t pid = strtol(Name, &t, 10);
1227
1228 if (t == NULL || *t != '\0') {
1229 const char * fn = rpmGetPath("%{_varrun}/", Name, ".pid", NULL);
1230 FD_t fd = NULL;
1231
1232 if (fn && *fn != '%' && (fd = Fopen(fn, "r.fdio")) && !Ferror(fd)) {
1233 char buf[32];
1234 size_t nb = Fread(buf, sizeof(buf[0]), sizeof(buf), fd);
1235
1236 if (nb > 0)
1237 pid = strtol(buf, &t, 10);
1238 } else
1239 pid = 0;
1240 if (fd != NULL)
1241 (void) Fclose(fd);
1242 fn = _free(fn);
1243 }
1244 rc = (pid > 0 ? (kill(pid, 0) < 0 && errno == ESRCH) : 1);
1245 if (Flags & RPMSENSE_MISSINGOK)
1246 goto unsatisfied;
1247 rpmdsNotify(dep, _("(running probe)"), rc);
1248 goto exit;
1249 }
1250
1251 if (NSType == RPMNS_TYPE_SANITY) {
1252 /* XXX only the installer does not have the database open here. */
1253 rc = 1; /* assume failure */
1254 if (rpmtsGetRdb(ts) != NULL) {
1255 mi = rpmtsInitIterator(ts, RPMTAG_PROVIDENAME, Name, 0);
1256 while ((h = rpmmiNext(mi)) != NULL) {
1257 if (!rpmdsAnyMatchesDep(h, dep, _rpmds_nopromote))
1258 continue;
1259 rc = (headerIsEntry(h, RPMTAG_SANITYCHECK) == 0);
1260 if (rc == 0) {
1261 /* XXX FIXME: actually run the sanitycheck script. */
1262 break;
1263 }
1264 }
1265 mi = rpmmiFree(mi);
1266 }
1267 if (Flags & RPMSENSE_MISSINGOK)
1268 goto unsatisfied;
1269 rpmdsNotify(dep, _("(sanity probe)"), rc);
1270 goto exit;
1271 }
1272
1273 if (NSType == RPMNS_TYPE_VCHECK) {
1274 rc = 1; /* assume failure */
1275 if (rpmtsGetRdb(ts) != NULL) {
1276 mi = rpmtsInitIterator(ts, RPMTAG_PROVIDENAME, Name, 0);
1277 while ((h = rpmmiNext(mi)) != NULL) {
1278 if (!rpmdsAnyMatchesDep(h, dep, _rpmds_nopromote))
1279 continue;
1280 rc = (headerIsEntry(h, RPMTAG_TRACK) == 0);
1281 if (rc == 0) {
1282 /* XXX FIXME: actually run the vcheck script. */
1283 break;
1284 }
1285 }
1286 mi = rpmmiFree(mi);
1287 }
1288 if (Flags & RPMSENSE_MISSINGOK)
1289 goto unsatisfied;
1290 rpmdsNotify(dep, _("(vcheck probe)"), rc);
1291 goto exit;
1292 }
1293
1294 /* Search system configured provides. */
1295 if (sysinfo_path == NULL) {
1296 sysinfo_path = rpmExpand("%{?_rpmds_sysinfo_path}", NULL);
1297 if (!(sysinfo_path != NULL && *sysinfo_path == '/')) {
1298 sysinfo_path = _free(sysinfo_path);
1299 sysinfo_path = xstrdup(SYSCONFIGDIR "/sysinfo");
1300 }
1301 }
1302
1303 if (!rpmioAccess(sysinfo_path, NULL, R_OK)) {
1304 #ifdef NOTYET /* XXX just sysinfo Provides: for now. */
1305 rpmTag tagN = (Name[0] == '/' ? RPMTAG_DIRNAMES : RPMTAG_PROVIDENAME);
1306 #else
1307 rpmTag tagN = RPMTAG_PROVIDENAME;
1308 #endif
1309 rpmds P = rpmdsFromPRCO(rpmtsPRCO(ts), tagN);
1310 if (rpmdsSearch(P, dep) >= 0) {
1311 rpmdsNotify(dep, _("(sysinfo provides)"), rc);
1312 goto exit;
1313 }
1314 }
1315
1316 /*
1317 * New features in rpm packaging implicitly add versioned dependencies
1318 * on rpmlib provides. The dependencies look like "rpmlib(YaddaYadda)".
1319 * Check those dependencies now.
1320 */
1321 if (NSType == RPMNS_TYPE_RPMLIB) {
1322 static int oneshot = -1;
1323
1324 if (oneshot)
1325 oneshot = rpmdsRpmlib(&rpmlibP, NULL);
1326 if (rpmlibP == NULL)
1327 goto unsatisfied;
1328
1329 if (rpmdsSearch(rpmlibP, dep) >= 0) {
1330 rpmdsNotify(dep, _("(rpmlib provides)"), rc);
1331 goto exit;
1332 }
1333 goto unsatisfied;
1334 }
1335
1336 if (NSType == RPMNS_TYPE_CPUINFO) {
1337 static int oneshot = -1;
1338
1339 if (oneshot && cpuinfoP == NULL)
1340 oneshot = rpmdsCpuinfo(&cpuinfoP, NULL);
1341 if (cpuinfoP == NULL)
1342 goto unsatisfied;
1343
1344 if (rpmdsSearch(cpuinfoP, dep) >= 0) {
1345 rpmdsNotify(dep, _("(cpuinfo provides)"), rc);
1346 goto exit;
1347 }
1348 goto unsatisfied;
1349 }
1350
1351 if (NSType == RPMNS_TYPE_GETCONF) {
1352 static int oneshot = -1;
1353
1354 if (oneshot)
1355 oneshot = rpmdsGetconf(&getconfP, NULL);
1356 if (getconfP == NULL)
1357 goto unsatisfied;
1358
1359 if (rpmdsSearch(getconfP, dep) >= 0) {
1360 rpmdsNotify(dep, _("(getconf provides)"), rc);
1361 goto exit;
1362 }
1363 goto unsatisfied;
1364 }
1365
1366 if (NSType == RPMNS_TYPE_UNAME) {
1367 static int oneshot = -1;
1368
1369 if (oneshot)
1370 oneshot = rpmdsUname(&unameP, NULL);
1371 if (unameP == NULL)
1372 goto unsatisfied;
1373
1374 if (rpmdsSearch(unameP, dep) >= 0) {
1375 rpmdsNotify(dep, _("(uname provides)"), rc);
1376 goto exit;
1377 }
1378 goto unsatisfied;
1379 }
1380
1381 if (NSType == RPMNS_TYPE_SONAME) {
1382 rpmds sonameP = NULL;
1383 rpmPRCO PRCO = rpmdsNewPRCO(NULL);
1384 char * fn = strcpy(alloca(strlen(Name)+1), Name);
1385 int flags = 0; /* XXX RPMELF_FLAG_SKIPREQUIRES? */
1386 rpmds ds;
1387
1388 /* XXX Only absolute paths for now. */
1389 if (*fn != '/')
1390 goto unsatisfied;
1391 fn[strlen(fn)-1] = '\0';
1392
1393 /* Extract ELF Provides: from /path/to/DSO. */
1394 xx = rpmdsELF(fn, flags, rpmdsMergePRCO, PRCO);
1395 sonameP = rpmdsFromPRCO(PRCO, RPMTAG_PROVIDENAME);
1396 if (!(xx == 0 && sonameP != NULL))
1397 goto unsatisfied;
1398
1399 /* Search using the original {EVR,"",Flags} from the dep set. */
1400 ds = rpmdsSingle(rpmdsTagN(dep), rpmdsEVR(dep), "", Flags);
1401 xx = rpmdsSearch(sonameP, ds);
1402 (void)rpmdsFree(ds);
1403 ds = NULL;
1404 PRCO = rpmdsFreePRCO(PRCO);
1405
1406 /* Was the dependency satisfied? */
1407 if (xx >= 0) {
1408 rpmdsNotify(dep, _("(soname provides)"), rc);
1409 goto exit;
1410 }
1411 goto unsatisfied;
1412 }
1413
1414 /* Search added packages for the dependency. */
1415 if (rpmalSatisfiesDepend(ts->addedPackages, dep, NULL) != NULL) {
1416 #if defined(CACHE_DEPENDENCY_RESULT)
1417 /*
1418 * XXX Ick, context sensitive answers from dependency cache.
1419 * XXX Always resolve added dependencies within context to disambiguate.
1420 */
1421 if (_rpmds_nopromote)
1422 _cacheThisRC = 0;
1423 #endif
1424 goto exit;
1425 }
1426
1427 /* XXX only the installer does not have the database open here. */
1428 if (rpmtsGetRdb(ts) != NULL) {
1429 if (Name[0] == '/') {
1430 /* depFlags better be 0! */
1431
1432 mi = rpmtsInitIterator(ts, RPMTAG_BASENAMES, Name, 0);
1433 (void) rpmmiPrune(mi,
1434 ts->removedPackages, ts->numRemovedPackages, 1);
1435 while ((h = rpmmiNext(mi)) != NULL) {
1436 rpmdsNotify(dep, _("(db files)"), rc);
1437 mi = rpmmiFree(mi);
1438 goto exit;
1439 }
1440 mi = rpmmiFree(mi);
1441 }
1442
1443 mi = rpmtsInitIterator(ts, RPMTAG_PROVIDENAME, Name, 0);
1444 (void) rpmmiPrune(mi,
1445 ts->removedPackages, ts->numRemovedPackages, 1);
1446 while ((h = rpmmiNext(mi)) != NULL) {
1447 if (rpmdsAnyMatchesDep(h, dep, _rpmds_nopromote)) {
1448 rpmdsNotify(dep, _("(db provides)"), rc);
1449 mi = rpmmiFree(mi);
1450 goto exit;
1451 }
1452 }
1453 mi = rpmmiFree(mi);
1454 }
1455
1456 /*
1457 * Search for an unsatisfied dependency.
1458 */
1459 if (adding == 1 && retries > 0 && !(rpmtsDFlags(ts) & RPMDEPS_FLAG_NOSUGGEST)) {
1460 if (ts->solve != NULL) {
1461 xx = (*ts->solve) (ts, dep, ts->solveData);
1462 if (xx == 0)
1463 goto exit;
1464 if (xx == -1) {
1465 retries--;
1466 rpmalMakeIndex(ts->addedPackages);
1467 goto retry;
1468 }
1469 }
1470 }
1471
1472 unsatisfied:
1473 if (Flags & RPMSENSE_MISSINGOK) {
1474 rc = 0; /* dependency is unsatisfied, but just a hint. */
1475 #if defined(CACHE_DEPENDENCY_RESULT)
1476 _cacheThisRC = 0;
1477 #endif
1478 rpmdsNotify(dep, _("(hint skipped)"), rc);
1479 } else {
1480 rc = 1; /* dependency is unsatisfied */
1481 rpmdsNotify(dep, NULL, rc);
1482 }
1483
1484 exit:
1485 /*
1486 * If dbiOpen/dbiPut fails (e.g. permissions), we can't cache.
1487 */
1488 #if defined(CACHE_DEPENDENCY_RESULT)
1489 if (_cacheDependsRC && _cacheThisRC) {
1490 dbiIndex dbi;
1491 dbi = dbiOpen(rpmtsGetRdb(ts), RPMDBI_DEPENDS, 0);
1492 if (dbi == NULL) {
1493 _cacheDependsRC = 0;
1494 } else {
1495 const char * DNEVR;
1496 xx = 0;
1497 if ((DNEVR = rpmdsDNEVR(dep)) != NULL) {
1498 DBC * dbcursor = NULL;
1499 size_t DNEVRlen = strlen(DNEVR);
1500
1501 xx = dbiCopen(dbi, dbiTxnid(dbi), &dbcursor, DB_WRITECURSOR);
1502
1503 memset(key, 0, sizeof(*key));
1504 /*@i@*/ key->data = (void *) DNEVR;
1505 key->size = DNEVRlen;
1506 memset(data, 0, sizeof(*data));
1507 data->data = &rc;
1508 data->size = sizeof(rc);
1509
1510 /*@-compmempass@*/
1511 xx = dbiPut(dbi, dbcursor, key, data, 0);
1512 /*@=compmempass@*/
1513 xx = dbiCclose(dbi, dbcursor, DB_WRITECURSOR);
1514 }
1515 if (xx)
1516 _cacheDependsRC = 0;
1517 }
1518 }
1519 #endif
1520
1521 return rpmdsNegateRC(dep, rc);
1522 }
1523
1537 static int checkPackageDeps(rpmts ts, const char * pkgNEVRA,
1538 /*@null@*/ rpmds requires,
1539 /*@null@*/ rpmds conflicts,
1540 /*@null@*/ rpmds dirnames,
1541 /*@null@*/ rpmds linktos,
1542 /*@null@*/ const char * depName,
1543 rpmuint32_t tscolor, int adding)
1544 /*@globals rpmGlobalMacroContext, h_errno,
1545 fileSystem, internalState @*/
1546 /*@modifies ts, requires, conflicts, dirnames, linktos,
1547 rpmGlobalMacroContext, fileSystem, internalState */
1548 {
1549 rpmps ps = rpmtsProblems(ts);
1550 rpmuint32_t dscolor;
1551 const char * Name;
1552 int terminate = 2; /* XXX terminate if rc >= terminate */
1553 int rc;
1554 int ourrc = 0;
1555 #if defined(RPM_VENDOR_MANDRIVA) || defined(RPM_VENDOR_ARK) /* optional-dirname-and-symlink-deps */
1556 int dirname_deps;
1557 int symlink_deps;
1558 #endif
1559
1560 requires = rpmdsInit(requires);
1561 if (requires != NULL)
1562 while (ourrc < terminate && rpmdsNext(requires) >= 0) {
1563
1564 if ((Name = rpmdsN(requires)) == NULL)
1565 continue; /* XXX can't happen */
1566
1567 /* Filter out requires that came along for the ride. */
1568 if (depName != NULL && strcmp(depName, Name))
1569 continue;
1570
1571 /* Ignore colored requires not in our rainbow. */
1572 dscolor = rpmdsColor(requires);
1573 if (tscolor && dscolor && !(tscolor & dscolor))
1574 continue;
1575
1576 rc = unsatisfiedDepend(ts, requires, adding);
1577
1578 switch (rc) {
1579 case 0: /* requirements are satisfied. */
1580 /*@switchbreak@*/ break;
1581 case 1: /* requirements are not satisfied. */
1582 { fnpyKey * suggestedKeys = NULL;
1583
1584 if (ts->availablePackages != NULL) {
1585 suggestedKeys = rpmalAllSatisfiesDepend(ts->availablePackages,
1586 requires, NULL);
1587 }
1588
1589 rpmdsProblem(ps, pkgNEVRA, requires, suggestedKeys, adding);
1590
1591 }
1592 ourrc = 1;
1593 /*@switchbreak@*/ break;
1594 case 2: /* something went wrong! */
1595 default:
1596 ourrc = 2;
1597 /*@switchbreak@*/ break;
1598 }
1599 }
1600
1601 conflicts = rpmdsInit(conflicts);
1602 if (conflicts != NULL)
1603 while (ourrc < terminate && rpmdsNext(conflicts) >= 0) {
1604
1605 if ((Name = rpmdsN(conflicts)) == NULL)
1606 continue; /* XXX can't happen */
1607
1608 /* Filter out conflicts that came along for the ride. */
1609 if (depName != NULL && strcmp(depName, Name))
1610 continue;
1611
1612 /* Ignore colored conflicts not in our rainbow. */
1613 dscolor = rpmdsColor(conflicts);
1614 if (tscolor && dscolor && !(tscolor & dscolor))
1615 continue;
1616
1617 rc = unsatisfiedDepend(ts, conflicts, adding);
1618
1619 /* 1 == unsatisfied, 0 == satsisfied */
1620 switch (rc) {
1621 case 0: /* conflicts exist. */
1622 rpmdsProblem(ps, pkgNEVRA, conflicts, NULL, adding);
1623 ourrc = 1;
1624 /*@switchbreak@*/ break;
1625 case 1: /* conflicts don't exist. */
1626 /*@switchbreak@*/ break;
1627 case 2: /* something went wrong! */
1628 default:
1629 ourrc = 2;
1630 /*@switchbreak@*/ break;
1631 }
1632 }
1633
1634 #if defined(RPM_VENDOR_MANDRIVA) || defined(RPM_VENDOR_ARK) /* optional-dirname-and-symlink-deps */
1635 dirname_deps = rpmExpandNumeric("%{?_check_dirname_deps}%{?!_check_dirname_deps:1}");
1636 if (dirname_deps) {
1637 #endif
1638 dirnames = rpmdsInit(dirnames);
1639 if (dirnames != NULL)
1640 while (ourrc < terminate && rpmdsNext(dirnames) >= 0) {
1641
1642 if ((Name = rpmdsN(dirnames)) == NULL)
1643 continue; /* XXX can't happen */
1644
1645 /* Filter out dirnames that came along for the ride. */
1646 if (depName != NULL && strcmp(depName, Name))
1647 continue;
1648
1649 /* Ignore colored dirnames not in our rainbow. */
1650 dscolor = rpmdsColor(dirnames);
1651 if (tscolor && dscolor && !(tscolor & dscolor))
1652 continue;
1653
1654 rc = unsatisfiedDepend(ts, dirnames, adding);
1655
1656 switch (rc) {
1657 case 0: /* requirements are satisfied. */
1658 /*@switchbreak@*/ break;
1659 case 1: /* requirements are not satisfied. */
1660 { fnpyKey * suggestedKeys = NULL;
1661
1662 if (ts->availablePackages != NULL) {
1663 suggestedKeys = rpmalAllSatisfiesDepend(ts->availablePackages,
1664 dirnames, NULL);
1665 }
1666
1667 rpmdsProblem(ps, pkgNEVRA, dirnames, suggestedKeys, adding);
1668
1669 }
1670 ourrc = 1;
1671 /*@switchbreak@*/ break;
1672 case 2: /* something went wrong! */
1673 default:
1674 ourrc = 2;
1675 /*@switchbreak@*/ break;
1676 }
1677 }
1678 #if defined(RPM_VENDOR_MANDRIVA) || defined(RPM_VENDOR_ARK) /* optional-dirname-and-symlink-deps */
1679 }
1680
1681 symlink_deps = rpmExpandNumeric("%{?_check_symlink_deps}%{?!_check_symlink_deps:1}");
1682 if (symlink_deps) {
1683 #endif
1684 linktos = rpmdsInit(linktos);
1685 if (linktos != NULL)
1686 while (ourrc < terminate && rpmdsNext(linktos) >= 0) {
1687
1688 if ((Name = rpmdsN(linktos)) == NULL)
1689 continue; /* XXX can't happen */
1690 if (*Name == '\0') /* XXX most linktos are empty */
1691 continue;
1692
1693 /* Filter out linktos that came along for the ride. */
1694 if (depName != NULL && strcmp(depName, Name))
1695 continue;
1696
1697 /* Ignore colored linktos not in our rainbow. */
1698 dscolor = rpmdsColor(linktos);
1699 if (tscolor && dscolor && !(tscolor & dscolor))
1700 continue;
1701
1702 rc = unsatisfiedDepend(ts, linktos, adding);
1703
1704 switch (rc) {
1705 case 0: /* requirements are satisfied. */
1706 /*@switchbreak@*/ break;
1707 case 1: /* requirements are not satisfied. */
1708 { fnpyKey * suggestedKeys = NULL;
1709
1710 if (ts->availablePackages != NULL) {
1711 suggestedKeys = rpmalAllSatisfiesDepend(ts->availablePackages,
1712 linktos, NULL);
1713 }
1714
1715 rpmdsProblem(ps, pkgNEVRA, linktos, suggestedKeys, adding);
1716
1717 }
1718 ourrc = 1;
1719 /*@switchbreak@*/ break;
1720 case 2: /* something went wrong! */
1721 default:
1722 ourrc = 2;
1723 /*@switchbreak@*/ break;
1724 }
1725 }
1726 #if defined(RPM_VENDOR_MANDRIVA) || defined(RPM_VENDOR_ARK) /* optional-dirname-and-symlink-deps */
1727 }
1728 #endif
1729
1730 ps = rpmpsFree(ps);
1731 return ourrc;
1732 }
1733
1744 static int checkPackageSet(rpmts ts, const char * depName,
1745 /*@only@*/ /*@null@*/ rpmmi mi, int adding)
1746 /*@globals rpmGlobalMacroContext, h_errno, fileSystem, internalState @*/
1747 /*@modifies ts, mi, rpmGlobalMacroContext, fileSystem, internalState @*/
1748 {
1749 HE_t he = memset(alloca(sizeof(*he)), 0, sizeof(*he));
1750 rpmdepFlags depFlags = rpmtsDFlags(ts);
1751 rpmuint32_t tscolor = rpmtsColor(ts);
1752 int scareMem = 0;
1753 Header h;
1754 int terminate = 2; /* XXX terminate if rc >= terminate */
1755 int ourrc = 0;
1756
1757 (void) rpmmiPrune(mi,
1758 ts->removedPackages, ts->numRemovedPackages, 1);
1759 while (ourrc < terminate && (h = rpmmiNext(mi)) != NULL) {
1760 rpmds requires = NULL;
1761 rpmds conflicts = NULL;
1762 rpmds dirnames = NULL;
1763 rpmds linktos = NULL;
1764 int rc;
1765
1766 he->tag = RPMTAG_NVRA;
1767 rc = (headerGet(h, he, 0) ? 0 : 2);
1768 if (rc > ourrc)
1769 ourrc = rc;
1770 if (ourrc >= terminate) {
1771 he->p.str = _free(he->p.str);
1772 break;
1773 }
1774
1775 if (!(depFlags & RPMDEPS_FLAG_NOREQUIRES))
1776 requires = rpmdsNew(h, RPMTAG_REQUIRENAME, scareMem);
1777 if (!(depFlags & RPMDEPS_FLAG_NOCONFLICTS))
1778 conflicts = rpmdsNew(h, RPMTAG_CONFLICTNAME, scareMem);
1779 if (!(depFlags & RPMDEPS_FLAG_NOPARENTDIRS))
1780 dirnames = rpmdsNew(h, RPMTAG_DIRNAMES, scareMem);
1781 if (!(depFlags & RPMDEPS_FLAG_NOLINKTOS))
1782 linktos = rpmdsNew(h, RPMTAG_FILELINKTOS, scareMem);
1783
1784 (void) rpmdsSetNoPromote(requires, _rpmds_nopromote);
1785 (void) rpmdsSetNoPromote(conflicts, _rpmds_nopromote);
1786 (void) rpmdsSetNoPromote(dirnames, _rpmds_nopromote);
1787 (void) rpmdsSetNoPromote(linktos, _rpmds_nopromote);
1788
1789 rc = checkPackageDeps(ts, he->p.str,
1790 requires, conflicts, dirnames, linktos,
1791 depName, tscolor, adding);
1792
1793 (void)rpmdsFree(linktos);
1794 linktos = NULL;
1795 (void)rpmdsFree(dirnames);
1796 dirnames = NULL;
1797 (void)rpmdsFree(conflicts);
1798 conflicts = NULL;
1799 (void)rpmdsFree(requires);
1800 requires = NULL;
1801 he->p.str = _free(he->p.str);
1802
1803 if (rc > ourrc)
1804 ourrc = rc;
1805 }
1806 mi = rpmmiFree(mi);
1807
1808 return ourrc;
1809 }
1810
1817 static int checkDependentPackages(rpmts ts, const char * depName)
1818 /*@globals rpmGlobalMacroContext, h_errno, fileSystem, internalState @*/
1819 /*@modifies ts, rpmGlobalMacroContext, fileSystem, internalState @*/
1820 {
1821 int rc = 0;
1822
1823 /* XXX rpmdb can be closed here, avoid error msg. */
1824 if (rpmtsGetRdb(ts) != NULL) {
1825 rpmmi mi;
1826 mi = rpmtsInitIterator(ts, RPMTAG_REQUIRENAME, depName, 0);
1827 rc = checkPackageSet(ts, depName, mi, 0);
1828 }
1829 return rc;
1830 }
1831
1838 static int checkDependentConflicts(rpmts ts, const char * depName)
1839 /*@globals rpmGlobalMacroContext, h_errno, fileSystem, internalState @*/
1840 /*@modifies ts, rpmGlobalMacroContext, fileSystem, internalState @*/
1841 {
1842 int rc = 0;
1843
1844 /* XXX rpmdb can be closed here, avoid error msg. */
1845 if (rpmtsGetRdb(ts) != NULL) {
1846 rpmmi mi;
1847 mi = rpmtsInitIterator(ts, RPMTAG_CONFLICTNAME, depName, 0);
1848 rc = checkPackageSet(ts, depName, mi, 1);
1849 }
1850
1851 return rc;
1852 }
1853
1854 struct badDeps_s {
1855 /*@observer@*/ /*@owned@*/ /*@null@*/
1856 const char * pname;
1857 /*@observer@*/ /*@dependent@*/ /*@null@*/
1858 const char * qname;
1859 };
1860
1861 #ifdef REFERENCE
1862 static struct badDeps_s {
1863 /*@observer@*/ /*@null@*/ const char * pname;
1864 /*@observer@*/ /*@null@*/ const char * qname;
1865 } badDeps[] = {
1866 { NULL, NULL }
1867 };
1868 #else
1869 /*@unchecked@*/
1870 static int badDepsInitialized = 0;
1871
1872 /*@unchecked@*/ /*@only@*/ /*@null@*/
1873 static struct badDeps_s * badDeps = NULL;
1874 #endif
1875
1878 /*@-modobserver -observertrans @*/
1879 static void freeBadDeps(void)
1880 /*@globals badDeps, badDepsInitialized @*/
1881 /*@modifies badDeps, badDepsInitialized @*/
1882 {
1883 if (badDeps) {
1884 struct badDeps_s * bdp;
1885 for (bdp = badDeps; bdp->pname != NULL && bdp->qname != NULL; bdp++)
1886 bdp->pname = _free(bdp->pname);
1887 badDeps = _free(badDeps);
1888 }
1889 badDepsInitialized = 0;
1890 }
1891 /*@=modobserver =observertrans @*/
1892
1901 static int ignoreDep(const rpmts ts, const rpmte p, const rpmte q)
1902 /*@globals badDeps, badDepsInitialized,
1903 rpmGlobalMacroContext, h_errno, internalState @*/
1904 /*@modifies badDeps, badDepsInitialized,
1905 rpmGlobalMacroContext, internalState @*/
1906 {
1907 struct badDeps_s * bdp;
1908
1909 if (!badDepsInitialized) {
1910 char * s = rpmExpand("%{?_dependency_whiteout}", NULL);
1911 const char ** av = NULL;
1912 int anaconda = rpmtsDFlags(ts) & RPMDEPS_FLAG_ANACONDA;
1913 int msglvl = (anaconda || (rpmtsDFlags(ts) & RPMDEPS_FLAG_DEPLOOPS))
1914 ? RPMLOG_WARNING : RPMLOG_DEBUG;
1915 int ac = 0;
1916 int i;
1917
1918 if (s != NULL && *s != '\0'
1919 && !(i = poptParseArgvString(s, &ac, (const char ***)&av))
1920 && ac > 0 && av != NULL)
1921 {
1922 bdp = badDeps = xcalloc(ac+1, sizeof(*badDeps));
1923 for (i = 0; i < ac; i++, bdp++) {
1924 char * pname, * qname;
1925
1926 if (av[i] == NULL)
1927 break;
1928 pname = xstrdup(av[i]);
1929 if ((qname = strchr(pname, '>')) != NULL)
1930 *qname++ = '\0';
1931 bdp->pname = pname;
1932 /*@-usereleased@*/
1933 bdp->qname = qname;
1934 /*@=usereleased@*/
1935 rpmlog(msglvl,
1936 _("ignore package name relation(s) [%d]\t%s -> %s\n"),
1937 i, bdp->pname, (bdp->qname ? bdp->qname : "???"));
1938 }
1939 bdp->pname = NULL;
1940 bdp->qname = NULL;
1941 }
1942 av = _free(av);
1943 s = _free(s);
1944 badDepsInitialized++;
1945 }
1946
1947 /*@-compdef@*/
1948 if (badDeps != NULL)
1949 for (bdp = badDeps; bdp->pname != NULL && bdp->qname != NULL; bdp++) {
1950 if (!strcmp(rpmteN(p), bdp->pname) && !strcmp(rpmteN(q), bdp->qname))
1951 return 1;
1952 }
1953 return 0;
1954 /*@=compdef@*/
1955 }
1956
1962 static void markLoop(/*@special@*/ tsortInfo tsi, rpmte q)
1963 /*@globals internalState @*/
1964 /*@uses tsi @*/
1965 /*@modifies internalState @*/
1966 {
1967 rpmte p;
1968
1969 while (tsi != NULL && (p = tsi->tsi_suc) != NULL) {
1970 tsi = tsi->tsi_next;
1971 if (rpmteTSI(p)->tsi_chain != NULL)
1972 continue;
1973 /*@-assignexpose -temptrans@*/
1974 rpmteTSI(p)->tsi_chain = q;
1975 /*@=assignexpose =temptrans@*/
1976 if (rpmteTSI(p)->tsi_next != NULL)
1977 markLoop(rpmteTSI(p)->tsi_next, p);
1978 }
1979 }
1980
1981 /*
1982 * Return display string a dependency, adding contextual flags marker.
1983 * @param f dependency flags
1984 * @return display string
1985 */
1986 static inline /*@observer@*/ const char * identifyDepend(rpmuint32_t f)
1987 /*@*/
1988 {
1989 f = _notpre(f);
1990 if (f & RPMSENSE_SCRIPT_PRE)
1991 return "Requires(pre):";
1992 if (f & RPMSENSE_SCRIPT_POST)
1993 return "Requires(post):";
1994 if (f & RPMSENSE_SCRIPT_PREUN)
1995 return "Requires(preun):";
1996 if (f & RPMSENSE_SCRIPT_POSTUN)
1997 return "Requires(postun):";
1998 if (f & RPMSENSE_SCRIPT_VERIFY)
1999 return "Requires(verify):";
2000 if (f & RPMSENSE_MISSINGOK)
2001 return "Requires(hint):";
2002 if (f & RPMSENSE_FIND_REQUIRES)
2003 return "Requires(auto):";
2004 return "Requires:";
2005 }
2006
2019 /*@-mustmod@*/ /* FIX: hack modifies, but -type disables */
2020 static /*@owned@*/ /*@null@*/ const char *
2021 zapRelation(rpmte q, rpmte p,
2022 int zap, /*@in@*/ /*@out@*/ int * nzaps, int msglvl)
2023 /*@globals rpmGlobalMacroContext, h_errno, internalState @*/
2024 /*@modifies q, p, *nzaps, rpmGlobalMacroContext, internalState @*/
2025 {
2026 rpmds requires;
2027 tsortInfo tsi_prev;
2028 tsortInfo tsi;
2029 const char *dp = NULL;
2030
2031 for (tsi_prev = rpmteTSI(q), tsi = rpmteTSI(q)->tsi_next;
2032 tsi != NULL;
2033 /* XXX Note: the loop traverses "not found", break on "found". */
2034 /*@-nullderef@*/
2035 tsi_prev = tsi, tsi = tsi->tsi_next)
2036 /*@=nullderef@*/
2037 {
2038 rpmuint32_t Flags;
2039
2040 /*@-abstractcompare@*/
2041 if (tsi->tsi_suc != p)
2042 continue;
2043 /*@=abstractcompare@*/
2044
2045 requires = rpmteDS((rpmteType(p) == TR_REMOVED ? q : p), tsi->tsi_tagn);
2046 if (requires == NULL) continue; /* XXX can't happen */
2047
2048 (void) rpmdsSetIx(requires, tsi->tsi_reqx);
2049
2050 Flags = rpmdsFlags(requires);
2051
2052 dp = rpmdsNewDNEVR( identifyDepend(Flags), requires);
2053
2054 /*
2055 * Attempt to unravel a dependency loop by eliminating Requires's.
2056 */
2057 if (zap) {
2058 rpmlog(msglvl,
2059 _("removing %s \"%s\" from tsort relations.\n"),
2060 (rpmteNEVRA(p) ? rpmteNEVRA(p) : "???"), dp);
2061 rpmteTSI(p)->tsi_count--;
2062 if (tsi_prev) tsi_prev->tsi_next = tsi->tsi_next;
2063 tsi->tsi_next = NULL;
2064 tsi->tsi_suc = NULL;
2065 tsi = _free(tsi);
2066 if (nzaps)
2067 (*nzaps)++;
2068 if (zap)
2069 zap--;
2070 }
2071 /* XXX Note: the loop traverses "not found", get out now! */
2072 break;
2073 }
2074 return dp;
2075 }
2076 /*@=mustmod@*/
2077
2086 /*@-mustmod@*/
2087 static inline int addRelation(rpmts ts,
2088 /*@dependent@*/ rpmte p,
2089 unsigned char * selected,
2090 rpmds requires)
2091 /*@globals rpmGlobalMacroContext, h_errno, fileSystem, internalState @*/
2092 /*@modifies ts, p, *selected, rpmGlobalMacroContext,
2093 fileSystem, internalState @*/
2094 {
2095 rpmtsi qi; rpmte q;
2096 tsortInfo tsi;
2097 nsType NSType = rpmdsNSType(requires);
2098 fnpyKey key;
2099 int teType = rpmteType(p);
2100 alKey pkgKey;
2101 int i = 0;
2102 rpmal al = (teType == TR_ADDED ? ts->addedPackages : ts->erasedPackages);
2103
2104 /* Avoid certain NS dependencies. */
2105 switch (NSType) {
2106 case RPMNS_TYPE_RPMLIB:
2107 case RPMNS_TYPE_CONFIG:
2108 case RPMNS_TYPE_CPUINFO:
2109 case RPMNS_TYPE_GETCONF:
2110 case RPMNS_TYPE_UNAME:
2111 case RPMNS_TYPE_SONAME:
2112 case RPMNS_TYPE_ACCESS:
2113 case RPMNS_TYPE_USER:
2114 case RPMNS_TYPE_GROUP:
2115 case RPMNS_TYPE_MOUNTED:
2116 case RPMNS_TYPE_DISKSPACE:
2117 case RPMNS_TYPE_DIGEST:
2118 case RPMNS_TYPE_GNUPG:
2119 case RPMNS_TYPE_MACRO:
2120 case RPMNS_TYPE_ENVVAR:
2121 case RPMNS_TYPE_RUNNING:
2122 case RPMNS_TYPE_SANITY:
2123 case RPMNS_TYPE_VCHECK:
2124 case RPMNS_TYPE_SIGNATURE:
2125 return 0;
2126 /*@notreached@*/ break;
2127 default:
2128 break;
2129 }
2130
2131 pkgKey = RPMAL_NOMATCH;
2132 key = rpmalSatisfiesDepend(al, requires, &pkgKey);
2133
2134 /* Ordering depends only on added/erased package relations. */
2135 if (pkgKey == RPMAL_NOMATCH)
2136 return 0;
2137
2138 /* XXX Set q to the added/removed package that was found. */
2139 /* XXX pretend erasedPackages are just appended to addedPackages. */
2140 if (teType == TR_REMOVED)
2141 pkgKey = (alKey)(((long)pkgKey) + ts->numAddedPackages);
2142
2143 for (qi = rpmtsiInit(ts), i = 0; (q = rpmtsiNext(qi, 0)) != NULL; i++) {
2144 if (pkgKey == rpmteAddedKey(q))
2145 break;
2146 }
2147 qi = rpmtsiFree(qi);
2148 if (q == NULL || i >= ts->orderCount)
2149 return 0;
2150
2151 /* Avoid certain dependency relations. */
2152 if (ignoreDep(ts, p, q))
2153 return 0;
2154
2155 /* Avoid redundant relations. */
2156 if (selected[i] != 0)
2157 return 0;
2158 selected[i] = 1;
2159
2160 /* Erasures are reversed installs. */
2161 if (teType == TR_REMOVED) {
2162 rpmte r = p;
2163 p = q;
2164 q = r;
2165 }
2166
2167 /* T3. Record next "q <- p" relation (i.e. "p" requires "q"). */
2168 rpmteTSI(p)->tsi_count++; /* bump p predecessor count */
2169
2170 if (rpmteDepth(p) <= rpmteDepth(q)) /* Save max. depth in dependency tree */
2171 (void) rpmteSetDepth(p, (rpmteDepth(q) + 1));
2172 if (rpmteDepth(p) > ts->maxDepth)
2173 ts->maxDepth = rpmteDepth(p);
2174
2175 tsi = xcalloc(1, sizeof(*tsi));
2176 tsi->tsi_suc = p;
2177
2178 tsi->tsi_tagn = rpmdsTagN(requires);
2179 tsi->tsi_reqx = rpmdsIx(requires);
2180
2181 tsi->tsi_next = rpmteTSI(q)->tsi_next;
2182 rpmteTSI(q)->tsi_next = tsi;
2183 rpmteTSI(q)->tsi_qcnt++; /* bump q successor count */
2184
2185 return 0;
2186 }
2187 /*@=mustmod@*/
2188
2195 static int orderListIndexCmp(const void * one, const void * two) /*@*/
2196 {
2197 /*@-castexpose@*/
2198 long a = (long) ((const orderListIndex)one)->pkgKey;
2199 long b = (long) ((const orderListIndex)two)->pkgKey;
2200 /*@=castexpose@*/
2201 return (a - b);
2202 }
2203
2211 /*@-mustmod@*/
2212 static void addQ(/*@dependent@*/ rpmte p,
2213 /*@in@*/ /*@out@*/ rpmte * qp,
2214 /*@in@*/ /*@out@*/ rpmte * rp,
2215 rpmuint32_t prefcolor)
2216 /*@modifies p, *qp, *rp @*/
2217 {
2218 rpmte q, qprev;
2219
2220 /* Mark the package as queued. */
2221 rpmteTSI(p)->tsi_queued = 1;
2222
2223 if ((*rp) == NULL) { /* 1st element */
2224 /*@-dependenttrans@*/ /* FIX: double indirection */
2225 (*rp) = (*qp) = p;
2226 /*@=dependenttrans@*/
2227 return;
2228 }
2229
2230 /* Find location in queue using metric tsi_qcnt. */
2231 for (qprev = NULL, q = (*qp);
2232 q != NULL;
2233 qprev = q, q = rpmteTSI(q)->tsi_suc)
2234 {
2235 /* XXX Insure preferred color first. */
2236 if (rpmteColor(p) != prefcolor && rpmteColor(p) != rpmteColor(q))
2237 continue;
2238
2239 /* XXX Insure removed after added. */
2240 if (rpmteType(p) == TR_REMOVED && rpmteType(p) != rpmteType(q))
2241 continue;
2242 if (rpmteTSI(q)->tsi_qcnt <= rpmteTSI(p)->tsi_qcnt)
2243 break;
2244 }
2245
2246 if (qprev == NULL) { /* insert at beginning of list */
2247 rpmteTSI(p)->tsi_suc = q;
2248 /*@-dependenttrans@*/
2249 (*qp) = p; /* new head */
2250 /*@=dependenttrans@*/
2251 } else if (q == NULL) { /* insert at end of list */
2252 rpmteTSI(qprev)->tsi_suc = p;
2253 /*@-dependenttrans@*/
2254 (*rp) = p; /* new tail */
2255 /*@=dependenttrans@*/
2256 } else { /* insert between qprev and q */
2257 rpmteTSI(p)->tsi_suc = q;
2258 rpmteTSI(qprev)->tsi_suc = p;
2259 }
2260 }
2261 /*@=mustmod@*/
2262
2263 /*@unchecked@*/
2264 #ifdef NOTYET
2265 static rpmuint32_t _autobits = _notpre(_ALL_REQUIRES_MASK);
2266 #else
2267 static rpmuint32_t _autobits = 0xffffffff;
2268 #endif
2269 #define isAuto(_x) ((_x) & _autobits)
2270
2271 /*@unchecked@*/
2272 static int slashDepth = 100; /* #slashes pemitted in parentdir deps. */
2273
2274 static int countSlashes(const char * dn)
2275 /*@*/
2276 {
2277 int nslashes = 0;
2278 int c;
2279
2280 while ((c = (int)*dn++) != 0) {
2281 switch (c) {
2282 default: continue; /*@notreached@*/ /*@switchbreak@*/break;
2283 case '/': nslashes++; /*@switchbreak@*/break;
2284 }
2285 }
2286
2287 return nslashes;
2288 }
2289
2290 int rpmtsOrder(rpmts ts)
2291 {
2292 rpmds requires;
2293 rpmuint32_t Flags;
2294 int anaconda = rpmtsDFlags(ts) & RPMDEPS_FLAG_ANACONDA;
2295 rpmuint32_t prefcolor = rpmtsPrefColor(ts);
2296 rpmtsi pi; rpmte p;
2297 rpmtsi qi; rpmte q;
2298 rpmtsi ri; rpmte r;
2299 tsortInfo tsi;
2300 tsortInfo tsi_next;
2301 alKey * ordering;
2302 int orderingCount = 0;
2303 unsigned char * selected = alloca(sizeof(*selected) * (ts->orderCount + 1));
2304 int loopcheck;
2305 rpmte * newOrder;
2306 int newOrderCount = 0;
2307 orderListIndex orderList;
2308 int numOrderList;
2309 int npeer = 128; /* XXX more than deep enough for now. */
2310 int * peer = memset(alloca(npeer*sizeof(*peer)), 0, (npeer*sizeof(*peer)));
2311 int nrescans = 10;
2312 int _printed = 0;
2313 char deptypechar;
2314 size_t tsbytes;
2315 int oType = 0;
2316 int treex;
2317 int depth;
2318 int breadth;
2319 int qlen;
2320 int i, j;
2321
2322 #ifdef DYING
2323 rpmalMakeIndex(ts->addedPackages);
2324 #endif
2325
2326 /* Create erased package index. */
2327 pi = rpmtsiInit(ts);
2328 while ((p = rpmtsiNext(pi, TR_REMOVED)) != NULL) {
2329 alKey pkgKey;
2330 fnpyKey key;
2331 rpmuint32_t tscolor = rpmtsColor(ts);
2332 pkgKey = RPMAL_NOMATCH;
2333 /*@-abstract@*/
2334 key = (fnpyKey) p;
2335 /*@=abstract@*/
2336 pkgKey = rpmalAdd(&ts->erasedPackages, pkgKey, key,
2337 rpmteDS(p, RPMTAG_PROVIDENAME),
2338 rpmteFI(p, RPMTAG_BASENAMES), tscolor);
2339 /* XXX pretend erasedPackages are just appended to addedPackages. */
2340 pkgKey = (alKey)(((long)pkgKey) + ts->numAddedPackages);
2341 (void) rpmteSetAddedKey(p, pkgKey);
2342 }
2343 pi = rpmtsiFree(pi);
2344 rpmalMakeIndex(ts->erasedPackages);
2345
2346 (void) rpmswEnter(rpmtsOp(ts, RPMTS_OP_ORDER), 0);
2347
2348 /* T1. Initialize. */
2349 if (oType == 0)
2350 numOrderList = ts->orderCount;
2351 else {
2352 numOrderList = 0;
2353 if (oType & TR_ADDED)
2354 numOrderList += ts->numAddedPackages;
2355 if (oType & TR_REMOVED)
2356 numOrderList += ts->numRemovedPackages;
2357 }
2358 ordering = alloca(sizeof(*ordering) * (numOrderList + 1));
2359 loopcheck = numOrderList;
2360 tsbytes = 0;
2361
2362 pi = rpmtsiInit(ts);
2363 while ((p = rpmtsiNext(pi, oType)) != NULL)
2364 rpmteNewTSI(p);
2365 pi = rpmtsiFree(pi);
2366
2367 /* Record all relations. */
2368 rpmlog(RPMLOG_DEBUG, D_("========== recording tsort relations\n"));
2369 pi = rpmtsiInit(ts);
2370 while ((p = rpmtsiNext(pi, oType)) != NULL) {
2371
2372 memset(selected, 0, sizeof(*selected) * ts->orderCount);
2373
2374 if ((requires = rpmteDS(p, RPMTAG_REQUIRENAME)) != NULL) {
2375
2376 /* Avoid narcisstic relations. */
2377 selected[rpmtsiOc(pi)] = 1;
2378
2379 /* T2. Next "q <- p" relation. */
2380
2381 /* First, do pre-requisites. */
2382 requires = rpmdsInit(requires);
2383 if (requires != NULL)
2384 while (rpmdsNext(requires) >= 0) {
2385
2386 Flags = rpmdsFlags(requires);
2387 if (!isAuto(Flags))
2388 /*@innercontinue@*/ continue;
2389
2390 switch (rpmteType(p)) {
2391 case TR_REMOVED:
2392 /* Skip if not %preun/%postun requires. */
2393 if (!isErasePreReq(Flags))
2394 /*@innercontinue@*/ continue;
2395 /*@switchbreak@*/ break;
2396 case TR_ADDED:
2397 /* Skip if not %pre/%post requires. */
2398 if (!isInstallPreReq(Flags))
2399 /*@innercontinue@*/ continue;
2400 /*@switchbreak@*/ break;
2401 }
2402
2403 /* T3. Record next "q <- p" relation (i.e. "p" requires "q"). */
2404 (void) addRelation(ts, p, selected, requires);
2405
2406 }
2407
2408 /* Then do co-requisites. */
2409 requires = rpmdsInit(requires);
2410 if (requires != NULL)
2411 while (rpmdsNext(requires) >= 0) {
2412
2413 Flags = rpmdsFlags(requires);
2414 if (!isAuto(Flags))
2415 /*@innercontinue@*/ continue;
2416
2417 switch (rpmteType(p)) {
2418 case TR_REMOVED:
2419 /* Skip if %preun/%postun requires. */
2420 if (isErasePreReq(Flags))
2421 /*@innercontinue@*/ continue;
2422 /*@switchbreak@*/ break;
2423 case TR_ADDED:
2424 /* Skip if %pre/%post requires. */
2425 if (isInstallPreReq(Flags))
2426 /*@innercontinue@*/ continue;
2427 /*@switchbreak@*/ break;
2428 }
2429
2430 /* T3. Record next "q <- p" relation (i.e. "p" requires "q"). */
2431 (void) addRelation(ts, p, selected, requires);
2432
2433 }
2434 }
2435
2436 /* Ensure that erasures follow installs during upgrades. */
2437 if (rpmteType(p) == TR_REMOVED && p->flink.Pkgid && p->flink.Pkgid[0]) {
2438
2439 qi = rpmtsiInit(ts);
2440 while ((q = rpmtsiNext(qi, TR_ADDED)) != NULL) {
2441 if (strcmp(q->pkgid, p->flink.Pkgid[0]))
2442 /*@innercontinue@*/ continue;
2443 requires = rpmdsFromPRCO(q->PRCO, RPMTAG_NAME);
2444 if (requires != NULL) {
2445 /* XXX disable erased arrow reversal. */
2446 p->type = TR_ADDED;
2447 (void) addRelation(ts, p, selected, requires);
2448 p->type = TR_REMOVED;
2449 }
2450 }
2451 qi = rpmtsiFree(qi);
2452 }
2453
2454 {
2455
2456 /* Order by requiring parent directories pre-requsites. */
2457 requires = rpmdsInit(rpmteDS(p, RPMTAG_DIRNAMES));
2458 if (requires != NULL)
2459 while (rpmdsNext(requires) >= 0) {
2460
2461 /* XXX Attempt to avoid loops by filtering out deep paths. */
2462 if (countSlashes(rpmdsN(requires)) > slashDepth)
2463 /*@innercontinue@*/ continue;
2464
2465 /* T3. Record next "q <- p" relation (i.e. "p" requires "q"). */
2466 (void) addRelation(ts, p, selected, requires);
2467
2468 }
2469
2470 /* Order by requiring no dangling symlinks. */
2471 requires = rpmdsInit(rpmteDS(p, RPMTAG_FILELINKTOS));
2472 if (requires != NULL)
2473 while (rpmdsNext(requires) >= 0) {
2474
2475 /* T3. Record next "q <- p" relation (i.e. "p" requires "q"). */
2476 (void) addRelation(ts, p, selected, requires);
2477
2478 }
2479 }
2480
2481 }
2482 pi = rpmtsiFree(pi);
2483
2484 /* Save predecessor count and mark tree roots. */
2485 treex = 0;
2486 pi = rpmtsiInit(ts);
2487 while ((p = rpmtsiNext(pi, oType)) != NULL) {
2488 int npreds;
2489
2490 npreds = rpmteTSI(p)->tsi_count;
2491
2492 (void) rpmteSetNpreds(p, npreds);
2493 (void) rpmteSetDepth(p, 0);
2494
2495 if (npreds == 0) {
2496 treex++;
2497 (void) rpmteSetTree(p, treex);
2498 (void) rpmteSetBreadth(p, treex);
2499 } else
2500 (void) rpmteSetTree(p, -1);
2501 #ifdef UNNECESSARY
2502 (void) rpmteSetParent(p, NULL);
2503 #endif
2504
2505 }
2506 pi = rpmtsiFree(pi);
2507 ts->ntrees = treex;
2508
2509 /* T4. Scan for zeroes. */
2510 rpmlog(RPMLOG_DEBUG, D_("========== tsorting packages (order, #predecessors, #succesors, tree, Ldepth, Rbreadth)\n"));
2511
2512 rescan:
2513 if (pi != NULL) pi = rpmtsiFree(pi);
2514 q = r = NULL;
2515 qlen = 0;
2516 pi = rpmtsiInit(ts);
2517 while ((p = rpmtsiNext(pi, oType)) != NULL) {
2518
2519 /* Prefer packages in chainsaw or anaconda presentation order. */
2520 if (anaconda)
2521 rpmteTSI(p)->tsi_qcnt = (ts->orderCount - rpmtsiOc(pi));
2522
2523 if (rpmteTSI(p)->tsi_count != 0)
2524 continue;
2525 rpmteTSI(p)->tsi_suc = NULL;
2526 addQ(p, &q, &r, prefcolor);
2527 qlen++;
2528 }
2529 pi = rpmtsiFree(pi);
2530
2531 /* T5. Output front of queue (T7. Remove from queue.) */
2532 for (; q != NULL; q = rpmteTSI(q)->tsi_suc) {
2533
2534 /* Mark the package as unqueued. */
2535 rpmteTSI(q)->tsi_queued = 0;
2536
2537 if (oType != 0)
2538 switch (rpmteType(q)) {
2539 case TR_ADDED:
2540 if (!(oType & TR_ADDED))
2541 continue;
2542 /*@switchbreak@*/ break;
2543 case TR_REMOVED:
2544 if (!(oType & TR_REMOVED))
2545 continue;
2546 /*@switchbreak@*/ break;
2547 default:
2548 continue;
2549 /*@notreached@*/ /*@switchbreak@*/ break;
2550 }
2551 deptypechar = (rpmteType(q) == TR_REMOVED ? '-' : '+');
2552
2553 treex = rpmteTree(q);
2554 depth = rpmteDepth(q);
2555 breadth = ((depth < npeer) ? peer[depth]++ : 0);
2556 (void) rpmteSetBreadth(q, breadth);
2557
2558 rpmlog(RPMLOG_DEBUG, "%5d%5d%5d%5d%5d%5d %*s%c%s\n",
2559 orderingCount, rpmteNpreds(q),
2560 rpmteTSI(q)->tsi_qcnt,
2561 treex, depth, breadth,
2562 (2 * depth), "",
2563 deptypechar,
2564 (rpmteNEVRA(q) ? rpmteNEVRA(q) : "???"));
2565
2566 (void) rpmteSetDegree(q, 0);
2567 tsbytes += rpmtePkgFileSize(q);
2568
2569 ordering[orderingCount] = rpmteAddedKey(q);
2570 orderingCount++;
2571 qlen--;
2572 loopcheck--;
2573
2574 /* T6. Erase relations. */
2575 tsi_next = rpmteTSI(q)->tsi_next;
2576 rpmteTSI(q)->tsi_next = NULL;
2577 while ((tsi = tsi_next) != NULL) {
2578 tsi_next = tsi->tsi_next;
2579 tsi->tsi_next = NULL;
2580 p = tsi->tsi_suc;
2581 if (p && (--rpmteTSI(p)->tsi_count) <= 0) {
2582
2583 (void) rpmteSetTree(p, treex);
2584 (void) rpmteSetDepth(p, depth+1);
2585 (void) rpmteSetParent(p, q);
2586 (void) rpmteSetDegree(q, rpmteDegree(q)+1);
2587
2588 /* XXX TODO: add control bit. */
2589 rpmteTSI(p)->tsi_suc = NULL;
2590 /*@-nullstate@*/ /* XXX FIX: rpmteTSI(q)->tsi_suc can be NULL. */
2591 addQ(p, &rpmteTSI(q)->tsi_suc, &r, prefcolor);
2592 /*@=nullstate@*/
2593 qlen++;
2594 }
2595 tsi = _free(tsi);
2596 }
2597 if (!_printed && loopcheck == qlen && rpmteTSI(q)->tsi_suc != NULL) {
2598 _printed++;
2599 (void) rpmtsUnorderedSuccessors(ts, orderingCount);
2600 rpmlog(RPMLOG_DEBUG,
2601 D_("========== successors only (%d bytes)\n"), (int)tsbytes);
2602
2603 /* Relink the queue in presentation order. */
2604 tsi = rpmteTSI(q);
2605 pi = rpmtsiInit(ts);
2606 while ((p = rpmtsiNext(pi, oType)) != NULL) {
2607 /* Is this element in the queue? */
2608 if (rpmteTSI(p)->tsi_queued == 0)
2609 /*@innercontinue@*/ continue;
2610 tsi->tsi_suc = p;
2611 tsi = rpmteTSI(p);
2612 }
2613 pi = rpmtsiFree(pi);
2614 tsi->tsi_suc = NULL;
2615 }
2616 }
2617
2618 /* T8. End of process. Check for loops. */
2619 if (loopcheck != 0) {
2620 int nzaps;
2621
2622 /* T9. Initialize predecessor chain. */
2623 nzaps = 0;
2624 qi = rpmtsiInit(ts);
2625 while ((q = rpmtsiNext(qi, oType)) != NULL) {
2626 rpmteTSI(q)->tsi_chain = NULL;
2627 rpmteTSI(q)->tsi_queued = 0;
2628 /* Mark packages already sorted. */
2629 if (rpmteTSI(q)->tsi_count == 0)
2630 rpmteTSI(q)->tsi_count = -1;
2631 }
2632 qi = rpmtsiFree(qi);
2633
2634 /* T10. Mark all packages with their predecessors. */
2635 qi = rpmtsiInit(ts);
2636 while ((q = rpmtsiNext(qi, oType)) != NULL) {
2637 if ((tsi = rpmteTSI(q)->tsi_next) == NULL)
2638 continue;
2639 rpmteTSI(q)->tsi_next = NULL;
2640 markLoop(tsi, q);
2641 rpmteTSI(q)->tsi_next = tsi;
2642 }
2643 qi = rpmtsiFree(qi);
2644
2645 /* T11. Print all dependency loops. */
2646 ri = rpmtsiInit(ts);
2647 while ((r = rpmtsiNext(ri, oType)) != NULL)
2648 {
2649 int printed;
2650
2651 printed = 0;
2652
2653 /* T12. Mark predecessor chain, looking for start of loop. */
2654 for (q = rpmteTSI(r)->tsi_chain; q != NULL;
2655 q = rpmteTSI(q)->tsi_chain)
2656 {
2657 if (rpmteTSI(q)->tsi_queued)
2658 /*@innerbreak@*/ break;
2659 rpmteTSI(q)->tsi_queued = 1;
2660 }
2661
2662 /* T13. Print predecessor chain from start of loop. */
2663 while ((p = q) != NULL && (q = rpmteTSI(p)->tsi_chain) != NULL) {
2664 #if 0
2665 const char * nevra;
2666 #endif
2667 const char * dp;
2668 rpmlogLvl msglvl = (anaconda || (rpmtsDFlags(ts) & RPMDEPS_FLAG_DEPLOOPS))
2669 ? RPMLOG_WARNING : RPMLOG_ERR;
2670 #if defined(RPM_VENDOR_MANDRIVA) /* loop-detection-optional-loglevel */
2671 // Report loops as debug-level message by default (7 = RPMLOG_DEBUG), overridable
2672 msglvl = rpmExpandNumeric("%{?_loop_detection_loglevel}%{?!_loop_detection_loglevel:7}");
2673 #endif
2674
2675 /* Unchain predecessor loop. */
2676 rpmteTSI(p)->tsi_chain = NULL;
2677
2678 if (!printed) {
2679 rpmlog(msglvl, _("LOOP:\n"));
2680 printed = 1;
2681 }
2682
2683 /* Find (and destroy if co-requisite) "q <- p" relation. */
2684 dp = zapRelation(q, p, 1, &nzaps, msglvl);
2685
2686 #if 0
2687 /* Print next member of loop. */
2688 nevra = rpmteNEVRA(p);
2689 rpmlog(msglvl, " %-40s %s\n", (nevra ? nevra : "???"),
2690 (dp ? dp : "not found!?!"));
2691 #endif
2692
2693 dp = _free(dp);
2694 }
2695
2696 /* Walk (and erase) linear part of predecessor chain as well. */
2697 for (p = r, q = rpmteTSI(r)->tsi_chain; q != NULL;
2698 p = q, q = rpmteTSI(q)->tsi_chain)
2699 {
2700 /* Unchain linear part of predecessor loop. */
2701 rpmteTSI(p)->tsi_chain = NULL;
2702 rpmteTSI(p)->tsi_queued = 0;
2703 }
2704 }
2705 ri = rpmtsiFree(ri);
2706
2707 /* If a relation was eliminated, then continue sorting. */
2708 /* XXX TODO: add control bit. */
2709 if (nzaps && nrescans-- > 0) {
2710 rpmlog(RPMLOG_DEBUG, D_("========== continuing tsort ...\n"));
2711 goto rescan;
2712 }
2713
2714 /* Return no. of packages that could not be ordered. */
2715 rpmlog(RPMLOG_ERR, _("rpmtsOrder failed, %d elements remain\n"),
2716 loopcheck);
2717
2718 #ifdef NOTYET
2719 /* Do autorollback goal since we could not sort this transaction properly. */
2720 (void) rpmtsRollback(ts, RPMPROB_FILTER_NONE, 0, NULL);
2721 #endif
2722
2723 return loopcheck;
2724 }
2725
2726 /* Clean up tsort remnants (if any). */
2727 pi = rpmtsiInit(ts);
2728 while ((p = rpmtsiNext(pi, 0)) != NULL)
2729 rpmteFreeTSI(p);
2730 pi = rpmtsiFree(pi);
2731
2732 /*
2733 * The order ends up as installed packages followed by removed packages.
2734 */
2735 orderList = xcalloc(numOrderList, sizeof(*orderList));
2736 j = 0;
2737 pi = rpmtsiInit(ts);
2738 while ((p = rpmtsiNext(pi, oType)) != NULL) {
2739 /* Prepare added/erased package ordering permutation. */
2740 orderList[j].pkgKey = rpmteAddedKey(p);
2741 orderList[j].orIndex = rpmtsiOc(pi);
2742 j++;
2743 }
2744 pi = rpmtsiFree(pi);
2745
2746 qsort(orderList, numOrderList, sizeof(*orderList), orderListIndexCmp);
2747
2748 /*@-type@*/
2749 newOrder = xcalloc(ts->orderCount, sizeof(*newOrder));
2750 /*@=type@*/
2751 for (i = 0, newOrderCount = 0; i < orderingCount; i++)
2752 {
2753 struct orderListIndex_s key;
2754 orderListIndex needle;
2755
2756 key.pkgKey = ordering[i];
2757 needle = bsearch(&key, orderList, numOrderList,
2758 sizeof(key), orderListIndexCmp);
2759 if (needle == NULL) /* XXX can't happen */
2760 continue;
2761
2762 j = needle->orIndex;
2763 if ((q = ts->order[j]) == NULL || needle->pkgKey == RPMAL_NOMATCH)
2764 continue;
2765
2766 newOrder[newOrderCount++] = q;
2767 ts->order[j] = NULL;
2768 }
2769
2770 assert(newOrderCount == ts->orderCount);
2771
2772 /*@+voidabstract@*/
2773 ts->order = _free(ts->order);
2774 /*@=voidabstract@*/
2775 ts->order = newOrder;
2776 ts->orderAlloced = ts->orderCount;
2777 orderList = _free(orderList);
2778
2779 #ifdef DYING /* XXX now done at the CLI level just before rpmtsRun(). */
2780 rpmtsClean(ts);
2781 #endif
2782 freeBadDeps();
2783
2784 (void) rpmswExit(rpmtsOp(ts, RPMTS_OP_ORDER), 0);
2785
2786 return 0;
2787 }
2788
2789 int rpmtsCheck(rpmts ts)
2790 {
2791 const char * depName = NULL;
2792 rpmdepFlags depFlags = rpmtsDFlags(ts);
2793 rpmuint32_t tscolor = rpmtsColor(ts);
2794 rpmmi mi = NULL;
2795 rpmtsi pi = NULL; rpmte p;
2796 int closeatexit = 0;
2797 int xx;
2798 int terminate = 2; /* XXX terminate if rc >= terminate */
2799 int rc = 0;
2800 int ourrc = 0;
2801
2802 (void) rpmswEnter(rpmtsOp(ts, RPMTS_OP_CHECK), 0);
2803
2804 /* Do lazy, readonly, open of rpm database. */
2805 if (rpmtsGetRdb(ts) == NULL && rpmtsDBMode(ts) != -1) {
2806 rc = (rpmtsOpenDB(ts, rpmtsDBMode(ts)) ? 2 : 0);
2807 closeatexit = (rc == 0);
2808 }
2809 if (rc && (ourrc = rc) >= terminate)
2810 goto exit;
2811
2812 ts->probs = rpmpsFree(ts->probs);
2813
2814 rpmalMakeIndex(ts->addedPackages);
2815
2816 /*
2817 * Look at all of the added packages and make sure their dependencies
2818 * are satisfied.
2819 */
2820 pi = rpmtsiInit(ts);
2821 while (ourrc < terminate && (p = rpmtsiNext(pi, TR_ADDED)) != NULL) {
2822 rpmds provides, requires, conflicts, dirnames, linktos;
2823 rpmfi fi;
2824
2825 /*@-nullpass@*/ /* FIX: rpmts{A,O} can return null. */
2826 rpmlog(RPMLOG_DEBUG, "========== +++ %s %s/%s 0x%x\n",
2827 rpmteNEVR(p), rpmteA(p), rpmteO(p), rpmteColor(p));
2828 /*@=nullpass@*/
2829 requires = (!(depFlags & RPMDEPS_FLAG_NOREQUIRES)
2830 ? rpmteDS(p, RPMTAG_REQUIRENAME) : NULL);
2831 conflicts = (!(depFlags & RPMDEPS_FLAG_NOCONFLICTS)
2832 ? rpmteDS(p, RPMTAG_CONFLICTNAME) : NULL);
2833 /* XXX srpm's don't have directory paths. */
2834 if (p->isSource) {
2835 dirnames = NULL;
2836 linktos = NULL;
2837 } else {
2838 dirnames = (!(depFlags & RPMDEPS_FLAG_NOPARENTDIRS)
2839 ? rpmteDS(p, RPMTAG_DIRNAMES) : NULL);
2840 linktos = (!(depFlags & RPMDEPS_FLAG_NOLINKTOS)
2841 ? rpmteDS(p, RPMTAG_FILELINKTOS) : NULL);
2842 }
2843
2844 rc = checkPackageDeps(ts, rpmteNEVRA(p),
2845 requires, conflicts, dirnames, linktos,
2846 NULL, tscolor, 1);
2847 if (rc && (ourrc = rc) >= terminate)
2848 break;
2849
2850 provides = rpmteDS(p, RPMTAG_PROVIDENAME);
2851 provides = rpmdsInit(provides);
2852 if (provides != NULL)
2853 while (ourrc < terminate && rpmdsNext(provides) >= 0) {
2854 depName = _free(depName);
2855 depName = xstrdup(rpmdsN(provides));
2856
2857 #ifdef NOTYET
2858 if (rpmdsNSType(provides) == RPMNS_TYPE_ENVVAR) {
2859 const char * EVR = rpmdsEVR(provides);
2860 if (rpmdsNegateRC(provides, 0))
2861 EVR = NULL;
2862 if (envPut(depName, EVR));
2863 rc = 2;
2864 } else
2865 #endif
2866
2867 /* Adding: check provides key against conflicts matches. */
2868 if (checkDependentConflicts(ts, depName))
2869 rc = 1;
2870 }
2871 if (rc && (ourrc = rc) >= terminate)
2872 break;
2873
2874 fi = rpmteFI(p, RPMTAG_BASENAMES);
2875 fi = rpmfiInit(fi, 0);
2876 while (ourrc < terminate && rpmfiNext(fi) >= 0) {
2877 depName = _free(depName);
2878 depName = xstrdup(rpmfiFN(fi));
2879 /* Adding: check filename against conflicts matches. */
2880 if (checkDependentConflicts(ts, depName))
2881 rc = 1;
2882 }
2883 if (rc && (ourrc = rc) >= terminate)
2884 break;
2885 }
2886 pi = rpmtsiFree(pi);
2887 if (rc && (ourrc = rc) >= terminate)
2888 goto exit;
2889
2890 /*
2891 * Look at the removed packages and make sure they aren't critical.
2892 */
2893 pi = rpmtsiInit(ts);
2894 while (ourrc < terminate && (p = rpmtsiNext(pi, TR_REMOVED)) != NULL) {
2895 rpmds provides;
2896 rpmfi fi;
2897
2898 /*@-nullpass@*/ /* FIX: rpmts{A,O} can return null. */
2899 rpmlog(RPMLOG_DEBUG, "========== --- %s %s/%s 0x%x\n",
2900 rpmteNEVR(p), rpmteA(p), rpmteO(p), rpmteColor(p));
2901 /*@=nullpass@*/
2902
2903 provides = rpmteDS(p, RPMTAG_PROVIDENAME);
2904 provides = rpmdsInit(provides);
2905 if (provides != NULL)
2906 while (ourrc < terminate && rpmdsNext(provides) >= 0) {
2907 depName = _free(depName);
2908 depName = xstrdup(rpmdsN(provides));
2909
2910 /* Erasing: check provides against requiredby matches. */
2911 if (checkDependentPackages(ts, depName))
2912 rc = 1;
2913 }
2914 if (rc && (ourrc = rc) >= terminate)
2915 break;
2916
2917 fi = rpmteFI(p, RPMTAG_BASENAMES);
2918 fi = rpmfiInit(fi, 0);
2919 while (ourrc < terminate && rpmfiNext(fi) >= 0) {
2920 depName = _free(depName);
2921 depName = xstrdup(rpmfiFN(fi));
2922 /* Erasing: check filename against requiredby matches. */
2923 if (checkDependentPackages(ts, depName))
2924 rc = 1;
2925 }
2926 if (rc && (ourrc = rc) >= terminate)
2927 break;
2928 }
2929 pi = rpmtsiFree(pi);
2930 if (rc && (ourrc = rc) >= terminate)
2931 goto exit;
2932
2933 /*
2934 * Make sure transaction dependencies are satisfied.
2935 */
2936 { const char * tsNEVRA = "transaction dependencies";
2937 rpmds R = rpmdsFromPRCO(rpmtsPRCO(ts), RPMTAG_REQUIRENAME);
2938 rpmds C = rpmdsFromPRCO(rpmtsPRCO(ts), RPMTAG_CONFLICTNAME);
2939 rpmds D = NULL;
2940 rpmds L = NULL;
2941 const char * dep = NULL;
2942 int adding = 2;
2943 tscolor = 0; /* XXX no coloring for transaction dependencies. */
2944 rc = checkPackageDeps(ts, tsNEVRA, R, C, D, L, dep, tscolor, adding);
2945 }
2946 if (rc && (ourrc = rc) >= terminate)
2947 goto exit;
2948
2949 exit:
2950 mi = rpmmiFree(mi);
2951 pi = rpmtsiFree(pi);
2952 depName = _free(depName);
2953
2954 (void) rpmswExit(rpmtsOp(ts, RPMTS_OP_CHECK), 0);
2955
2956 if (closeatexit)
2957 xx = rpmtsCloseDB(ts);
2958 #if defined(CACHE_DEPENDENCY_RESULT)
2959 else if (_cacheDependsRC)
2960 xx = rpmdbCloseDBI(rpmtsGetRdb(ts), RPMDBI_DEPENDS);
2961 #endif
2962
2963 #ifdef NOTYET
2964 /* On failed dependencies, perform the autorollback goal (if any). */
2965 { rpmps ps = rpmtsProblems(ts);
2966 if (rc || rpmpsNumProblems(ps) > 0)
2967 (void) rpmtsRollback(ts, RPMPROB_FILTER_NONE, 0, NULL);
2968 ps = rpmpsFree(ps);
2969 }
2970 #endif
2971
2972 return ourrc;
2973 }