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