rpm  5.2.1
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 
44 /*@dependent@*/
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@*/
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. */
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@*/
185 /*@unchecked@*/
187 /*@unchecked@*/
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")
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 
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  */
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())
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())
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++;
739  }
740 
741  pkgKey = rpmalAdd(&ts->addedPackages, pkgKey, rpmteKey(p),
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@*/
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@*/
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))
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 *
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 
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,
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);
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))
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 
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";
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)
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 }