00001
00005 #include "system.h"
00006
00007 #include <rpmio.h>
00008 #include <rpmiotypes.h>
00009 #include <rpmcb.h>
00010 #include <rpmmacro.h>
00011 #include <envvar.h>
00012 #include <ugid.h>
00013
00014 #include <rpmtag.h>
00015 #define _RPMDB_INTERNAL
00016 #include <rpmdb.h>
00017
00018 #define _RPMTE_INTERNAL
00019 #include <rpmte.h>
00020 #define _RPMTS_INTERNAL
00021 #include <rpmcli.h>
00022
00023 #define _RPMEVR_INTERNAL
00024 #include <rpmds.h>
00025 #include <rpmfi.h>
00026
00027 #include "debug.h"
00028
00029
00030
00031
00032
00033
00034
00035
00038 typedef struct orderListIndex_s * orderListIndex;
00039
00040
00043 struct orderListIndex_s {
00044
00045 alKey pkgKey;
00046 int orIndex;
00047 };
00048
00049 #if defined(CACHE_DEPENDENCY_RESULT)
00050
00051 int _cacheDependsRC = CACHE_DEPENDENCY_RESULT;
00052 #endif
00053
00054
00055 const char *rpmNAME = PACKAGE;
00056
00057
00058 const char *rpmEVR = VERSION;
00059
00060
00061 int rpmFLAGS = RPMSENSE_EQUAL;
00062
00069 static int intcmp(const void * a, const void * b)
00070
00071 {
00072 const int * aptr = a;
00073 const int * bptr = b;
00074 int rc = (*aptr - *bptr);
00075 return rc;
00076 }
00077
00087 static int removePackage(rpmts ts, Header h, int dboffset,
00088 int * indexp,
00089 alKey depends)
00090
00091
00092 {
00093 rpmte p;
00094
00095
00096 if (ts->numRemovedPackages > 0 && ts->removedPackages != NULL) {
00097 int * needle = NULL;
00098 needle = bsearch(&dboffset, ts->removedPackages, ts->numRemovedPackages,
00099 sizeof(*ts->removedPackages), intcmp);
00100 if (needle != NULL) {
00101
00102 if (indexp != NULL)
00103 *indexp = needle - ts->removedPackages;
00104 return 0;
00105 }
00106 }
00107
00108 if (ts->numRemovedPackages == ts->allocedRemovedPackages) {
00109 ts->allocedRemovedPackages += ts->delta;
00110 ts->removedPackages = xrealloc(ts->removedPackages,
00111 sizeof(ts->removedPackages) * ts->allocedRemovedPackages);
00112 }
00113
00114 if (ts->removedPackages != NULL) {
00115 ts->removedPackages[ts->numRemovedPackages] = dboffset;
00116 ts->numRemovedPackages++;
00117 if (ts->numRemovedPackages > 1)
00118 qsort(ts->removedPackages, ts->numRemovedPackages,
00119 sizeof(*ts->removedPackages), intcmp);
00120 }
00121
00122 if (ts->orderCount >= ts->orderAlloced) {
00123 ts->orderAlloced += (ts->orderCount - ts->orderAlloced) + ts->delta;
00124
00125 ts->order = xrealloc(ts->order, sizeof(*ts->order) * ts->orderAlloced);
00126
00127 }
00128
00129 p = rpmteNew(ts, h, TR_REMOVED, NULL, NULL, dboffset, depends);
00130 ts->order[ts->orderCount] = p;
00131 if (indexp != NULL)
00132 *indexp = ts->orderCount;
00133 ts->orderCount++;
00134
00135
00136 return 0;
00137
00138 }
00139
00146 static int rpmHeadersIdentical(Header first, Header second)
00147
00148
00149 {
00150 HE_t he = memset(alloca(sizeof(*he)), 0, sizeof(*he));
00151 const char * one, * two;
00152 int rc = 0;
00153 int xx;
00154
00155 he->tag = RPMTAG_HDRID;
00156 xx = headerGet(first, he, 0);
00157 one = he->p.str;
00158 he->tag = RPMTAG_HDRID;
00159 xx = headerGet(second, he, 0);
00160 two = he->p.str;
00161
00162 if (one && two)
00163 rc = ((strcmp(one, two) == 0) ? 1 : 0);
00164 else if (one && !two)
00165 rc = 0;
00166 else if (!one && two)
00167 rc = 0;
00168 else {
00169
00170 rpmds A = rpmdsThis(first, RPMTAG_REQUIRENAME, RPMSENSE_EQUAL);
00171 rpmds B = rpmdsThis(second, RPMTAG_REQUIRENAME, RPMSENSE_EQUAL);
00172 rc = rpmdsCompare(A, B);
00173 (void)rpmdsFree(A);
00174 A = NULL;
00175 (void)rpmdsFree(B);
00176 B = NULL;
00177 }
00178 one = _free(one);
00179 two = _free(two);
00180 return rc;
00181 }
00182
00183
00184 static rpmTag _upgrade_tag;
00185
00186 static rpmTag _debuginfo_tag;
00187
00188 static rpmTag _obsolete_tag;
00189
00198 static int rpmtsAddUpgrades(rpmts ts, rpmte p, rpmuint32_t hcolor, Header h)
00199
00200
00201 {
00202 HE_t he = memset(alloca(sizeof(*he)), 0, sizeof(*he));
00203 rpmuint32_t tscolor = rpmtsColor(ts);
00204 alKey pkgKey = rpmteAddedKey(p);
00205 rpmuint32_t ohcolor;
00206 rpmmi mi;
00207 Header oh;
00208 int xx;
00209
00210 if (_upgrade_tag == 0) {
00211 const char * t = rpmExpand("%{?_upgrade_tag}", NULL);
00212
00213 _upgrade_tag = (!strcmp(t, "name") ? RPMTAG_NAME : RPMTAG_PROVIDENAME);
00214
00215 t = _free(t);
00216 }
00217
00218 mi = rpmtsInitIterator(ts, _upgrade_tag, rpmteN(p), 0);
00219 while((oh = rpmmiNext(mi)) != NULL) {
00220 int lastx;
00221 rpmte q;
00222
00223
00224 ohcolor = hGetColor(oh);
00225 if (tscolor && hcolor && ohcolor && !(hcolor & ohcolor))
00226 continue;
00227
00228
00229 he->tag = RPMTAG_ORIGINTID;
00230 xx = headerGet(oh, he, 0);
00231 if (xx && he->p.ui32p != NULL) {
00232 if (p->originTid[0] == 0 || p->originTid[0] > he->p.ui32p[0]
00233 || (he->c > 1 && p->originTid[0] == he->p.ui32p[0] && p->originTid[1] > he->p.ui32p[1]))
00234 {
00235 p->originTid[0] = he->p.ui32p[0];
00236 p->originTid[1] = (he->c > 1 ? he->p.ui32p[1] : 0);
00237 }
00238 he->p.ptr = _free(he->p.ptr);
00239 }
00240 he->tag = RPMTAG_ORIGINTIME;
00241 xx = headerGet(oh, he, 0);
00242 if (xx && he->p.ui32p != NULL) {
00243 if (p->originTime[0] == 0 || p->originTime[0] > he->p.ui32p[0]
00244 || (he->c > 1 && p->originTime[0] == he->p.ui32p[0] && p->originTime[1] > he->p.ui32p[1]))
00245 {
00246 p->originTime[0] = he->p.ui32p[0];
00247 p->originTime[1] = (he->c > 1 ? he->p.ui32p[1] : 0);
00248 }
00249 he->p.ptr = _free(he->p.ptr);
00250 }
00251
00252 #if defined(RPM_VENDOR_WINDRIVER)
00253
00254
00255
00256
00257
00258
00259 if (tscolor && (!hcolor || !ohcolor)) {
00260 const char * arch;
00261 const char * oharch;
00262 he->tag = RPMTAG_ARCH;
00263 xx = headerGet(h, he, 0);
00264 arch = (xx && he->p.str != NULL ? he->p.str : NULL);
00265 he->tag = RPMTAG_ARCH;
00266 xx = headerGet(oh, he, 0);
00267 oharch = (xx && he->p.str != NULL ? he->p.str : NULL);
00268 if (arch != NULL && oharch != NULL) {
00269 if (strcmp("noarch", arch) || strcmp("noarch", oharch)) {
00270 if (!_isCompatibleArch(arch, oharch)) {
00271 arch = _free(arch);
00272 oharch = _free(oharch);
00273 continue;
00274 }
00275 }
00276 }
00277 arch = _free(arch);
00278 oharch = _free(oharch);
00279 }
00280 #endif
00281
00282
00283 if (rpmHeadersIdentical(h, oh))
00284 continue;
00285
00286
00287 lastx = -1;
00288 xx = removePackage(ts, oh, rpmmiInstance(mi), &lastx, pkgKey);
00289 assert(lastx >= 0 && lastx < ts->orderCount);
00290 q = ts->order[lastx];
00291
00292
00293 xx = rpmteChain(p, q, oh, "Upgrades");
00294
00295
00296 rpmlog(RPMLOG_DEBUG, D_(" upgrade erases %s\n"), rpmteNEVRA(q));
00297
00298
00299 }
00300 mi = rpmmiFree(mi);
00301
00302 return 0;
00303 }
00304
00311 static inline int chkSuffix(const char * fn, const char * suffix)
00312
00313 {
00314 size_t flen = strlen(fn);
00315 size_t slen = strlen(suffix);
00316 return (flen > slen && !strcmp(fn + flen - slen, suffix));
00317 }
00318
00327 static int rpmtsEraseDebuginfo(rpmts ts, rpmte p, Header h,
00328 alKey pkgKey)
00329
00330
00331 {
00332 HE_t he = memset(alloca(sizeof(*he)), 0, sizeof(*he));
00333 const void *keyval = NULL;
00334 size_t keylen = 0;
00335 size_t nrefs = 0;
00336 rpmuint32_t debuginfoInstance = 0;
00337 Header debuginfoHeader = NULL;
00338 rpmmi mi;
00339 Header oh;
00340 int xx;
00341
00342
00343 if (_debuginfo_tag == 0) {
00344 const char * t = rpmExpand("%{?_debuginfo_tag}", NULL);
00345
00346 _debuginfo_tag = (*t != '\0' && !strcmp(t, "pkgid")
00347 ? RPMTAG_SOURCEPKGID : RPMTAG_SOURCERPM);
00348
00349 t = _free(t);
00350 }
00351
00352
00353 switch (_debuginfo_tag) {
00354 default: return 0; break;
00355 case RPMTAG_SOURCERPM: keyval = rpmteSourcerpm(p); break;
00356 }
00357
00358
00359 mi = rpmtsInitIterator(ts, _debuginfo_tag, keyval, keylen);
00360 xx = rpmmiPrune(mi, ts->removedPackages, ts->numRemovedPackages, 1);
00361 while((oh = rpmmiNext(mi)) != NULL) {
00362
00363 if (rpmHeadersIdentical(h, oh))
00364 continue;
00365
00366 he->tag = RPMTAG_NAME;
00367 xx = headerGet(oh, he, 0);
00368 if (!xx || he->p.str == NULL)
00369 continue;
00370
00371 if (chkSuffix(he->p.str, "-debuginfo")) {
00372 debuginfoInstance = rpmmiInstance(mi);
00373 debuginfoHeader = headerLink(oh);
00374 } else
00375 nrefs++;
00376 he->p.str = _free(he->p.str);
00377 }
00378 mi = rpmmiFree(mi);
00379
00380
00381 if (nrefs == 0 && debuginfoInstance > 0 && debuginfoHeader != NULL) {
00382 int lastx = -1;
00383 rpmte q;
00384
00385
00386 lastx = -1;
00387 xx = removePackage(ts, debuginfoHeader, debuginfoInstance,
00388 &lastx, pkgKey);
00389 assert(lastx >= 0 && lastx < ts->orderCount);
00390 q = ts->order[lastx];
00391
00392
00393
00394 if (pkgKey != RPMAL_NOMATCH)
00395 xx = rpmteChain(p, q, oh, "Upgrades");
00396
00397
00398 rpmlog(RPMLOG_DEBUG, D_(" lastref erases %s\n"), rpmteNEVRA(q));
00399
00400
00401 }
00402 (void)headerFree(debuginfoHeader);
00403 debuginfoHeader = NULL;
00404
00405 return (int)nrefs;
00406 }
00407
00415 static int rpmtsAddObsoletes(rpmts ts, rpmte p, rpmuint32_t hcolor)
00416
00417
00418 {
00419 rpmuint32_t tscolor = rpmtsColor(ts);
00420 alKey pkgKey = rpmteAddedKey(p);
00421 rpmuint32_t ohcolor;
00422 rpmds obsoletes;
00423 rpmuint32_t dscolor;
00424 rpmmi mi;
00425 Header oh;
00426 int xx;
00427
00428 if (_obsolete_tag == 0) {
00429 const char *t = rpmExpand("%{?_obsolete_tag}", NULL);
00430
00431 _obsolete_tag = (!strcmp(t, "name") ? RPMTAG_NAME : RPMTAG_PROVIDENAME);
00432
00433 t = _free(t);
00434 }
00435
00436 obsoletes = rpmdsLink(rpmteDS(p, RPMTAG_OBSOLETENAME), "Obsoletes");
00437 obsoletes = rpmdsInit(obsoletes);
00438 if (obsoletes != NULL)
00439 while (rpmdsNext(obsoletes) >= 0) {
00440 const char * Name;
00441
00442 if ((Name = rpmdsN(obsoletes)) == NULL)
00443 continue;
00444
00445
00446 #if 0
00447
00448 dscolor = rpmdsColor(obsoletes);
00449 #else
00450 dscolor = hcolor;
00451 #endif
00452 if (tscolor && dscolor && !(tscolor & dscolor))
00453 continue;
00454
00455
00456 if (!strcmp(rpmteN(p), Name))
00457 continue;
00458
00459
00460 if (Name[0] == '/')
00461 mi = rpmtsInitIterator(ts, RPMTAG_BASENAMES, Name, 0);
00462 else
00463 mi = rpmtsInitIterator(ts, _obsolete_tag, Name, 0);
00464
00465 xx = rpmmiPrune(mi,
00466 ts->removedPackages, ts->numRemovedPackages, 1);
00467
00468 while((oh = rpmmiNext(mi)) != NULL) {
00469 int lastx;
00470 rpmte q;
00471
00472
00473 ohcolor = hGetColor(oh);
00474
00475
00476
00477 if (tscolor && hcolor && ohcolor && !(hcolor & ohcolor))
00478 continue;
00479
00480
00481
00482
00483
00484 if (!(rpmdsEVR(obsoletes) == NULL
00485 || rpmdsAnyMatchesDep(oh, obsoletes, _rpmds_nopromote)))
00486 continue;
00487
00488
00489 lastx = -1;
00490 xx = removePackage(ts, oh, rpmmiInstance(mi), &lastx, pkgKey);
00491 assert(lastx >= 0 && lastx < ts->orderCount);
00492 q = ts->order[lastx];
00493
00494
00495 xx = rpmteChain(p, q, oh, "Obsoletes");
00496
00497
00498 rpmlog(RPMLOG_DEBUG, D_(" Obsoletes: %s\t\terases %s\n"),
00499 rpmdsDNEVR(obsoletes)+2, rpmteNEVRA(q));
00500
00501 }
00502 mi = rpmmiFree(mi);
00503 }
00504 (void)rpmdsFree(obsoletes);
00505 obsoletes = NULL;
00506
00507 return 0;
00508 }
00509
00510 #if defined(RPM_VENDOR_WINDRIVER)
00511
00512 int _isCompatibleArch(const char * arch, const char * compat)
00513 {
00514 const char * compatArch = rpmExpand(compat, " %{?_", compat, "_compat_arch}", NULL);
00515 const char * p, * pe, * t;
00516 int match = 0;
00517
00518
00519 if (arch[0] == 'i' && arch[2] == '8' && arch[3] == '6') {
00520 if ((arch[0] == compat[0]) &&
00521 (arch[2] == compat[2]) &&
00522 (arch[3] == compat[3]))
00523 match = 1;
00524
00525 if (!strcmp(compat, "x86_32"))
00526 match = 1;
00527 }
00528
00529 for ( p = pe = compatArch ; *pe && match == 0 ; ) {
00530 while (*p && xisspace(*p)) p++;
00531 pe = p ; while (*pe && !xisspace(*pe)) pe++;
00532 if (p == pe)
00533 break;
00534 t = strndup(p, (pe - p));
00535 p = pe;
00536 rpmlog(RPMLOG_DEBUG, D_(" Comparing compat archs %s ? %s\n"), arch, t);
00537 if (!strcmp(arch, t))
00538 match = 1;
00539 t = _free(t);
00540 }
00541 compatArch = _free(compatArch);
00542 return match;
00543 }
00544 #endif
00545
00546 int rpmtsAddInstallElement(rpmts ts, Header h,
00547 fnpyKey key, int upgrade, rpmRelocation relocs)
00548 {
00549 HE_t he = memset(alloca(sizeof(*he)), 0, sizeof(*he));
00550 rpmdepFlags depFlags = rpmtsDFlags(ts);
00551 rpmuint32_t tscolor = rpmtsColor(ts);
00552 rpmuint32_t hcolor;
00553 int isSource;
00554 int duplicate = 0;
00555 rpmtsi pi = NULL; rpmte p;
00556 const char * arch = NULL;
00557 const char * os = NULL;
00558 rpmds oldChk, newChk;
00559 alKey pkgKey;
00560 int xx;
00561 int ec = 0;
00562 int rc;
00563 int oc;
00564
00565 hcolor = hGetColor(h);
00566 pkgKey = RPMAL_NOMATCH;
00567
00568
00569
00570
00571 isSource =
00572 (headerIsEntry(h, RPMTAG_SOURCERPM) == 0 &&
00573 headerIsEntry(h, RPMTAG_ARCH) != 0);
00574 if (isSource) {
00575 oc = ts->orderCount;
00576 goto addheader;
00577 }
00578
00579
00580
00581
00582 he->tag = RPMTAG_ARCH;
00583 xx = headerGet(h, he, 0);
00584 arch = he->p.str;
00585 he->tag = RPMTAG_OS;
00586 xx = headerGet(h, he, 0);
00587 os = he->p.str;
00588 if (nplatpat > 1) {
00589 const char * platform = NULL;
00590
00591 he->tag = RPMTAG_PLATFORM;
00592 xx = headerGet(h, he, 0);
00593 platform = he->p.str;
00594 if (!xx || platform == NULL)
00595 platform = rpmExpand(arch, "-unknown-", os, NULL);
00596
00597 rc = rpmPlatformScore(platform, platpat, nplatpat);
00598 if (rc <= 0) {
00599 rpmps ps = rpmtsProblems(ts);
00600 he->tag = RPMTAG_NVRA;
00601 xx = headerGet(h, he, 0);
00602 assert(he->p.str != NULL);
00603
00604 rpmpsAppend(ps, RPMPROB_BADPLATFORM, he->p.str, key,
00605 platform, NULL, NULL, 0);
00606
00607
00608 if (rpmIsVerbose()) {
00609 const char * msg = rpmProblemString(rpmpsGetProblem(ps, -1));
00610 rpmlog(RPMLOG_WARNING, "%s\n", msg);
00611 msg = _free(msg);
00612 }
00613
00614 ps = rpmpsFree(ps);
00615 he->p.ptr = _free(he->p.ptr);
00616 ec = 1;
00617 }
00618 platform = _free(platform);
00619 if (ec)
00620 goto exit;
00621 }
00622
00623
00624
00625
00626 if (!upgrade) {
00627 oc = ts->orderCount;
00628 goto addheader;
00629 }
00630
00631
00632
00633
00634 oldChk = rpmdsThis(h, RPMTAG_REQUIRENAME, (RPMSENSE_LESS));
00635 newChk = rpmdsThis(h, RPMTAG_REQUIRENAME, (RPMSENSE_EQUAL|RPMSENSE_GREATER));
00636
00637 for (pi = rpmtsiInit(ts), oc = 0; (p = rpmtsiNext(pi, 0)) != NULL; oc++) {
00638 rpmds this;
00639
00640
00641 if (rpmteType(p) == TR_REMOVED)
00642 continue;
00643
00644
00645 if (rpmteIsSource(p))
00646 continue;
00647
00648 if (tscolor) {
00649 const char * parch;
00650 const char * pos;
00651
00652 if (arch == NULL || (parch = rpmteA(p)) == NULL)
00653 continue;
00654 #if defined(RPM_VENDOR_WINDRIVER)
00655
00656 if (!_isCompatibleArch(arch, parch))
00657 continue;
00658 #else
00659
00660 if (arch[0] == 'i' && arch[2] == '8' && arch[3] == '6') {
00661 if (arch[0] != parch[0]) continue;
00662 if (arch[2] != parch[2]) continue;
00663 if (arch[3] != parch[3]) continue;
00664 }
00665 #endif
00666 else if (strcmp(arch, parch))
00667 continue;
00668 if (os == NULL || (pos = rpmteO(p)) == NULL)
00669 continue;
00670
00671 if (strcmp(os, pos))
00672 continue;
00673 }
00674
00675
00676 if ((this = rpmteDS(p, RPMTAG_NAME)) == NULL)
00677 continue;
00678
00679
00680 rc = rpmdsCompare(newChk, this);
00681 if (rc != 0) {
00682 const char * pkgNEVR = rpmdsDNEVR(this);
00683 const char * addNEVR = rpmdsDNEVR(oldChk);
00684 if (rpmIsVerbose())
00685 rpmlog(RPMLOG_WARNING,
00686 _("package %s was already added, skipping %s\n"),
00687 (pkgNEVR ? pkgNEVR + 2 : "?pkgNEVR?"),
00688 (addNEVR ? addNEVR + 2 : "?addNEVR?"));
00689 ec = 1;
00690 break;
00691 }
00692
00693
00694 rc = rpmdsCompare(oldChk, this);
00695 if (rc != 0) {
00696 const char * pkgNEVR = rpmdsDNEVR(this);
00697 const char * addNEVR = rpmdsDNEVR(newChk);
00698 if (rpmIsVerbose())
00699 rpmlog(RPMLOG_WARNING,
00700 _("package %s was already added, replacing with %s\n"),
00701 (pkgNEVR ? pkgNEVR + 2 : "?pkgNEVR?"),
00702 (addNEVR ? addNEVR + 2 : "?addNEVR?"));
00703 duplicate = 1;
00704 pkgKey = rpmteAddedKey(p);
00705 break;
00706 }
00707 }
00708 pi = rpmtsiFree(pi);
00709 (void)rpmdsFree(oldChk);
00710 oldChk = NULL;
00711 (void)rpmdsFree(newChk);
00712 newChk = NULL;
00713
00714
00715 if (ec)
00716 goto exit;
00717
00718 addheader:
00719 if (oc >= ts->orderAlloced) {
00720 ts->orderAlloced += (oc - ts->orderAlloced) + ts->delta;
00721
00722 ts->order = xrealloc(ts->order, ts->orderAlloced * sizeof(*ts->order));
00723
00724 }
00725
00726 p = rpmteNew(ts, h, TR_ADDED, key, relocs, -1, pkgKey);
00727 assert(p != NULL);
00728
00729 if (duplicate && oc < ts->orderCount) {
00730
00731 ts->order[oc] = rpmteFree(ts->order[oc]);
00732
00733 }
00734
00735 ts->order[oc] = p;
00736 if (!duplicate) {
00737 ts->orderCount++;
00738 rpmcliPackagesTotal++;
00739 }
00740
00741 pkgKey = rpmalAdd(&ts->addedPackages, pkgKey, rpmteKey(p),
00742 rpmteDS(p, RPMTAG_PROVIDENAME),
00743 rpmteFI(p, RPMTAG_BASENAMES), tscolor);
00744 if (pkgKey == RPMAL_NOMATCH) {
00745 ts->order[oc] = rpmteFree(ts->order[oc]);
00746 ts->teInstall = NULL;
00747 ec = 1;
00748 goto exit;
00749 }
00750 (void) rpmteSetAddedKey(p, pkgKey);
00751
00752 if (!duplicate) {
00753 ts->numAddedPackages++;
00754 }
00755
00756 ts->teInstall = ts->order[oc];
00757
00758
00759 if (upgrade & 0x2)
00760 (void) rpmteSetHeader(p, h);
00761
00762
00763 if (!(upgrade & 0x1))
00764 goto exit;
00765
00766
00767 if (isSource)
00768 goto exit;
00769
00770
00771 if (rpmtsGetRdb(ts) == NULL && rpmtsDBMode(ts) != -1) {
00772 if ((ec = rpmtsOpenDB(ts, rpmtsDBMode(ts)) != 0))
00773 goto exit;
00774 }
00775
00776
00777 if (!(depFlags & RPMDEPS_FLAG_NOUPGRADE)) {
00778
00779
00780
00781
00782
00783
00784
00785
00786
00787 xx = rpmtsEraseDebuginfo(ts, p, h, pkgKey);
00788 if (!chkSuffix(rpmteN(p), "-debuginfo") || xx == 0)
00789 xx = rpmtsAddUpgrades(ts, p, hcolor, h);
00790 }
00791
00792
00793 if (!(depFlags & RPMDEPS_FLAG_NOOBSOLETES)) {
00794 xx = rpmtsAddObsoletes(ts, p, hcolor);
00795 }
00796
00797 ec = 0;
00798
00799 exit:
00800 arch = _free(arch);
00801 os = _free(os);
00802 pi = rpmtsiFree(pi);
00803 return ec;
00804 }
00805
00806 int rpmtsAddEraseElement(rpmts ts, Header h, int dboffset)
00807 {
00808 int oc = -1;
00809 int rc = removePackage(ts, h, dboffset, &oc, RPMAL_NOMATCH);
00810 if (rc == 0 && oc >= 0 && oc < ts->orderCount) {
00811 (void) rpmtsEraseDebuginfo(ts, ts->order[oc], h, RPMAL_NOMATCH);
00812 ts->teErase = ts->order[oc];
00813 } else
00814 ts->teErase = NULL;
00815 return rc;
00816 }
00817
00818
00819 static char *sysinfo_path = NULL;
00820
00821
00822 static rpmds rpmlibP = NULL;
00823
00824 rpmds cpuinfoP = NULL;
00825
00826 static rpmds getconfP = NULL;
00827
00828 static rpmds unameP = NULL;
00829
00830 void rpmnsClean(void)
00831
00832
00833 {
00834 (void)rpmdsFree(rpmlibP);
00835 rpmlibP = NULL;
00836 (void)rpmdsFree(cpuinfoP);
00837 cpuinfoP = NULL;
00838 (void)rpmdsFree(getconfP);
00839 getconfP = NULL;
00840 (void)rpmdsFree(unameP);
00841 unameP = NULL;
00842
00843 _sysinfo_path = _free(_sysinfo_path);
00844
00845 sysinfo_path = _free(sysinfo_path);
00846 }
00847
00855 static int unsatisfiedDepend(rpmts ts, rpmds dep, int adding)
00856
00857
00858
00859
00860 {
00861 DBT * key = alloca(sizeof(*key));
00862 DBT * data = alloca(sizeof(*data));
00863 rpmmi mi;
00864 nsType NSType;
00865 const char * Name;
00866 rpmuint32_t Flags;
00867 Header h;
00868 #if defined(CACHE_DEPENDENCY_RESULT)
00869 int _cacheThisRC = 1;
00870 #endif
00871 int rc;
00872 int xx;
00873 int retries = 20;
00874
00875 if ((Name = rpmdsN(dep)) == NULL)
00876 return 0;
00877 Flags = rpmdsFlags(dep);
00878 NSType = rpmdsNSType(dep);
00879
00880 #if defined(CACHE_DEPENDENCY_RESULT)
00881
00882
00883
00884 if (_cacheDependsRC) {
00885 dbiIndex dbi;
00886 dbi = dbiOpen(rpmtsGetRdb(ts), RPMDBI_DEPENDS, 0);
00887 if (dbi == NULL)
00888 _cacheDependsRC = 0;
00889 else {
00890 const char * DNEVR;
00891
00892 rc = -1;
00893 if ((DNEVR = rpmdsDNEVR(dep)) != NULL) {
00894 DBC * dbcursor = NULL;
00895 void * datap = NULL;
00896 size_t datalen = 0;
00897 size_t DNEVRlen = strlen(DNEVR);
00898
00899 xx = dbiCopen(dbi, dbiTxnid(dbi), &dbcursor, 0);
00900
00901 memset(key, 0, sizeof(*key));
00902 key->data = (void *) DNEVR;
00903 key->size = DNEVRlen;
00904 memset(data, 0, sizeof(*data));
00905 data->data = datap;
00906 data->size = datalen;
00907
00908 xx = dbiGet(dbi, dbcursor, key, data, DB_SET);
00909
00910 DNEVR = key->data;
00911 DNEVRlen = key->size;
00912 datap = data->data;
00913 datalen = data->size;
00914
00915 if (xx == 0 && datap && datalen == 4)
00916 memcpy(&rc, datap, datalen);
00917 xx = dbiCclose(dbi, dbcursor, 0);
00918 }
00919
00920 if (rc >= 0) {
00921 rpmdsNotify(dep, _("(cached)"), rc);
00922 return rpmdsNegateRC(dep, rc);
00923 }
00924 }
00925 }
00926 #endif
00927
00928 retry:
00929 rc = 0;
00930
00931
00932 if (NSType == RPMNS_TYPE_FUNCTION) {
00933 xx = rpmExpandNumeric(Name);
00934 rc = (xx ? 0 : 1);
00935 if (Flags & RPMSENSE_MISSINGOK)
00936 goto unsatisfied;
00937 rpmdsNotify(dep, _("(function probe)"), rc);
00938 goto exit;
00939 }
00940
00941
00942 if (NSType == RPMNS_TYPE_USER) {
00943 const char *s;
00944 uid_t uid = 0;
00945 s = Name; while (*s && xisdigit(*s)) s++;
00946
00947 if (*s)
00948 xx = unameToUid(Name, &uid);
00949 else {
00950 uid = strtol(Name, NULL, 10);
00951 xx = (uidToUname(uid) ? 0 : -1);
00952 }
00953 rc = (xx >= 0 ? 0 : 1);
00954 if (Flags & RPMSENSE_MISSINGOK)
00955 goto unsatisfied;
00956 rpmdsNotify(dep, _("(user lookup)"), rc);
00957 goto exit;
00958 }
00959 if (NSType == RPMNS_TYPE_GROUP) {
00960 const char *s;
00961 gid_t gid = 0;
00962 s = Name; while (*s && xisdigit(*s)) s++;
00963
00964 if (*s)
00965 xx = gnameToGid(Name, &gid);
00966 else {
00967 gid = strtol(Name, NULL, 10);
00968 xx = (gidToGname(gid) ? 0 : -1);
00969 }
00970 rc = (xx >= 0 ? 0 : 1);
00971 if (Flags & RPMSENSE_MISSINGOK)
00972 goto unsatisfied;
00973 rpmdsNotify(dep, _("(group lookup)"), rc);
00974 goto exit;
00975 }
00976
00977
00978 if (NSType == RPMNS_TYPE_ACCESS) {
00979 rc = rpmioAccess(Name, NULL, X_OK);
00980 if (Flags & RPMSENSE_MISSINGOK)
00981 goto unsatisfied;
00982 rpmdsNotify(dep, _("(access probe)"), rc);
00983 goto exit;
00984 }
00985
00986
00987 if (NSType == RPMNS_TYPE_MOUNTED) {
00988 const char ** fs = NULL;
00989 int nfs = 0;
00990 int i = 0;
00991
00992 xx = rpmtsInitDSI(ts);
00993 fs = ts->filesystems;
00994 nfs = ts->filesystemCount;
00995
00996 if (fs != NULL)
00997 for (i = 0; i < nfs; i++) {
00998 if (!strcmp(fs[i], Name))
00999 break;
01000 }
01001 rc = (i < nfs ? 0 : 1);
01002 if (Flags & RPMSENSE_MISSINGOK)
01003 goto unsatisfied;
01004 rpmdsNotify(dep, _("(mtab probe)"), rc);
01005 goto exit;
01006 }
01007
01008 if (NSType == RPMNS_TYPE_DISKSPACE) {
01009 size_t nb = strlen(Name);
01010 rpmDiskSpaceInfo dsi = NULL;
01011 const char ** fs = NULL;
01012 size_t fslen = 0, longest = 0;
01013 int nfs = 0;
01014 int i = 0;
01015
01016 xx = rpmtsInitDSI(ts);
01017 fs = ts->filesystems;
01018 nfs = ts->filesystemCount;
01019
01020 if (fs != NULL)
01021 for (i = 0; i < nfs; i++) {
01022 fslen = strlen(fs[i]);
01023 if (fslen > nb)
01024 continue;
01025 if (strncmp(fs[i], Name, fslen))
01026 continue;
01027 if (fslen > 1 && Name[fslen] != '/' && Name[fslen] != '\0')
01028 continue;
01029 if (fslen < longest)
01030 continue;
01031 longest = fslen;
01032 dsi = ts->dsi + i;
01033 }
01034 if (dsi == NULL)
01035 rc = 1;
01036 else {
01037 char * end = NULL;
01038
01039 rpmuint64_t needed = strtoll(rpmdsEVR(dep), &end, 0);
01040
01041
01042 if (end && *end) {
01043 if (strchr("Gg", end[0]) && strchr("Bb", end[1]) && !end[2])
01044 needed *= 1024 * 1024 * 1024;
01045 if (strchr("Mm", end[0]) && strchr("Bb", end[1]) && !end[2])
01046 needed *= 1024 * 1024;
01047 if (strchr("Kk", end[0]) && strchr("Bb", end[1]) && !end[2])
01048 needed *= 1024;
01049 } else
01050 needed *= 1024 * 1024;
01051
01052 needed = BLOCK_ROUND(needed, dsi->f_bsize);
01053 xx = (dsi->f_bavail - needed);
01054 if ((Flags & RPMSENSE_LESS) && xx < 0) rc = 0;
01055 else if ((Flags & RPMSENSE_GREATER) && xx > 0) rc = 0;
01056 else if ((Flags & RPMSENSE_EQUAL) && xx == 0) rc = 0;
01057 else rc = 1;
01058 }
01059 if (Flags & RPMSENSE_MISSINGOK)
01060 goto unsatisfied;
01061 rpmdsNotify(dep, _("(diskspace probe)"), rc);
01062 goto exit;
01063 }
01064
01065 if (NSType == RPMNS_TYPE_DIGEST) {
01066 const char * EVR = rpmdsEVR(dep);
01067 const char *filename;
01068 pgpHashAlgo digestHashAlgo;
01069 FD_t fd;
01070 char *cp;
01071 int algo;
01072
01073 filename = Name;
01074 digestHashAlgo = PGPHASHALGO_MD5;
01075 if ((cp = strchr(filename, ':')) != NULL) {
01076 if ((algo = pgpHashAlgoStringToNumber(filename, cp-filename)) != PGPHASHALGO_ERROR) {
01077 digestHashAlgo = algo;
01078 filename = cp + 1;
01079 }
01080 }
01081 rc = 1;
01082 fd = Fopen(filename, "r.fdio");
01083 if (fd && !Ferror(fd)) {
01084 DIGEST_CTX ctx = rpmDigestInit(digestHashAlgo, RPMDIGEST_NONE);
01085 const char * digest = NULL;
01086 size_t digestlen = 0;
01087 int asAscii = 1;
01088 size_t nbuf = 8 * BUFSIZ;
01089 char * buf = alloca(nbuf);
01090 size_t nb;
01091
01092 while ((nb = Fread(buf, sizeof(buf[0]), nbuf, fd)) > 0)
01093 xx = rpmDigestUpdate(ctx, buf, nb);
01094 xx = Fclose(fd); fd = NULL;
01095 xx = rpmDigestFinal(ctx, &digest, &digestlen, asAscii);
01096
01097 xx = (EVR && *EVR && digest && *digest) ? strcasecmp(EVR, digest) : -1;
01098
01099 if ((Flags & RPMSENSE_EQUAL) && xx == 0) rc = 0;
01100 }
01101 if (Flags & RPMSENSE_MISSINGOK)
01102 goto unsatisfied;
01103 rpmdsNotify(dep, _("(digest probe)"), rc);
01104 goto exit;
01105 }
01106
01107 if (NSType == RPMNS_TYPE_SIGNATURE) {
01108 const char * EVR = rpmdsEVR(dep);
01109 ARGV_t avN = NULL;
01110 ARGV_t avEVR = NULL;
01111 rpmRC res;
01112
01113
01114 xx = argvSplit(&avN, Name, ":");
01115
01116
01117 xx = (EVR && *EVR) ? argvSplit(&avEVR, EVR, ":") : argvAdd(&avEVR, "");
01118
01119 res = rpmnsProbeSignature(ts, avN[0], avN[1], avEVR[0], avEVR[1], 0);
01120 rc = (res == RPMRC_OK ? 0 : 1);
01121
01122 avN = argvFree(avN);
01123 avEVR = argvFree(avEVR);
01124
01125 if (Flags & RPMSENSE_MISSINGOK)
01126 goto unsatisfied;
01127 rpmdsNotify(dep, _("(signature probe)"), rc);
01128 goto exit;
01129 }
01130
01131 if (NSType == RPMNS_TYPE_VERIFY) {
01132 QVA_t qva = memset(alloca(sizeof(*qva)), 0, sizeof(*qva));
01133
01134 qva->qva_mode = 'v';
01135 qva->qva_flags = (int)(VERIFY_ALL & ~(VERIFY_DEPS|VERIFY_SCRIPT));
01136 rc = 0;
01137 if (rpmtsGetRdb(ts) != NULL) {
01138 if (!strcmp(Name, "*"))
01139 mi = rpmtsInitIterator(ts, RPMDBI_PACKAGES, NULL, 0);
01140 else if (Name[0] == '/')
01141 mi = rpmtsInitIterator(ts, RPMTAG_BASENAMES, Name, 0);
01142 else
01143 mi = rpmtsInitIterator(ts, RPMTAG_PROVIDENAME, Name, 0);
01144 while ((h = rpmmiNext(mi)) != NULL) {
01145 if (!(Name[0] == '/' || !strcmp(Name, "*")))
01146 if (!rpmdsAnyMatchesDep(h, dep, _rpmds_nopromote))
01147 continue;
01148 xx = (showVerifyPackage(qva, ts, h) ? 1 : 0);
01149 if (xx)
01150 rc = 1;
01151 }
01152 mi = rpmmiFree(mi);
01153 }
01154
01155 if (Flags & RPMSENSE_MISSINGOK)
01156 goto unsatisfied;
01157 rpmdsNotify(dep, _("(verify probe)"), rc);
01158 goto exit;
01159 }
01160
01161 if (NSType == RPMNS_TYPE_GNUPG) {
01162 const char * EVR = rpmdsEVR(dep);
01163 if (!(EVR && *EVR)) {
01164 static const char gnupg_pre[] = "%(%{__gpg} --batch --no-tty --quiet --verify ";
01165 static const char gnupg_post[] = " 2>/dev/null; echo $?)";
01166 const char * t = rpmExpand(gnupg_pre, Name, gnupg_post, NULL);
01167 rc = (t && t[0] == '0') ? 0 : 1;
01168 t = _free(t);
01169 }
01170 else {
01171 static const char gnupg_pre[] = "%(%{__gpg} --batch --no-tty --quiet --verify ";
01172 static const char gnupg_post[] = " 2>&1 | grep '^Primary key fingerprint:' | sed -e 's;^.*: *;;' -e 's; *;;g')";
01173 const char * t = rpmExpand(gnupg_pre, Name, gnupg_post, NULL);
01174 rc = ((Flags & RPMSENSE_EQUAL) && strcasecmp(EVR, t) == 0) ? 0 : 1;
01175 t = _free(t);
01176 }
01177 if (Flags & RPMSENSE_MISSINGOK)
01178 goto unsatisfied;
01179 rpmdsNotify(dep, _("(gnupg probe)"), rc);
01180 goto exit;
01181 }
01182
01183 if (NSType == RPMNS_TYPE_MACRO) {
01184 static const char macro_pre[] = "%{?";
01185 static const char macro_post[] = ":0}";
01186 const char * a = rpmExpand(macro_pre, Name, macro_post, NULL);
01187
01188 rc = (a && a[0] == '0') ? 0 : 1;
01189 a = _free(a);
01190 if (Flags & RPMSENSE_MISSINGOK)
01191 goto unsatisfied;
01192 rpmdsNotify(dep, _("(macro probe)"), rc);
01193 goto exit;
01194 }
01195
01196 if (NSType == RPMNS_TYPE_ENVVAR) {
01197 const char * a = envGet(Name);
01198 const char * b = rpmdsEVR(dep);
01199
01200
01201 if (!(b && *b))
01202 rc = (!(a && *a));
01203 else {
01204 int sense = (a && *a) ? strcmp(a, b) : -1;
01205
01206 if ((Flags & RPMSENSE_SENSEMASK) == RPMSENSE_NOTEQUAL)
01207 rc = (sense == 0);
01208 else if (sense < 0 && (Flags & RPMSENSE_LESS))
01209 rc = 0;
01210 else if (sense > 0 && (Flags & RPMSENSE_GREATER))
01211 rc = 0;
01212 else if (sense == 0 && (Flags & RPMSENSE_EQUAL))
01213 rc = 0;
01214 else
01215 rc = (sense != 0);
01216 }
01217
01218 if (Flags & RPMSENSE_MISSINGOK)
01219 goto unsatisfied;
01220 rpmdsNotify(dep, _("(envvar probe)"), rc);
01221 goto exit;
01222 }
01223
01224 if (NSType == RPMNS_TYPE_RUNNING) {
01225 char *t = NULL;
01226 pid_t pid = strtol(Name, &t, 10);
01227
01228 if (t == NULL || *t != '\0') {
01229 const char * fn = rpmGetPath("%{_varrun}/", Name, ".pid", NULL);
01230 FD_t fd = NULL;
01231
01232 if (fn && *fn != '%' && (fd = Fopen(fn, "r.fdio")) && !Ferror(fd)) {
01233 char buf[32];
01234 size_t nb = Fread(buf, sizeof(buf[0]), sizeof(buf), fd);
01235
01236 if (nb > 0)
01237 pid = strtol(buf, &t, 10);
01238 } else
01239 pid = 0;
01240 if (fd != NULL)
01241 (void) Fclose(fd);
01242 fn = _free(fn);
01243 }
01244 rc = (pid > 0 ? (kill(pid, 0) < 0 && errno == ESRCH) : 1);
01245 if (Flags & RPMSENSE_MISSINGOK)
01246 goto unsatisfied;
01247 rpmdsNotify(dep, _("(running probe)"), rc);
01248 goto exit;
01249 }
01250
01251 if (NSType == RPMNS_TYPE_SANITY) {
01252
01253 rc = 1;
01254 if (rpmtsGetRdb(ts) != NULL) {
01255 mi = rpmtsInitIterator(ts, RPMTAG_PROVIDENAME, Name, 0);
01256 while ((h = rpmmiNext(mi)) != NULL) {
01257 if (!rpmdsAnyMatchesDep(h, dep, _rpmds_nopromote))
01258 continue;
01259 rc = (headerIsEntry(h, RPMTAG_SANITYCHECK) == 0);
01260 if (rc == 0) {
01261
01262 break;
01263 }
01264 }
01265 mi = rpmmiFree(mi);
01266 }
01267 if (Flags & RPMSENSE_MISSINGOK)
01268 goto unsatisfied;
01269 rpmdsNotify(dep, _("(sanity probe)"), rc);
01270 goto exit;
01271 }
01272
01273 if (NSType == RPMNS_TYPE_VCHECK) {
01274 rc = 1;
01275 if (rpmtsGetRdb(ts) != NULL) {
01276 mi = rpmtsInitIterator(ts, RPMTAG_PROVIDENAME, Name, 0);
01277 while ((h = rpmmiNext(mi)) != NULL) {
01278 if (!rpmdsAnyMatchesDep(h, dep, _rpmds_nopromote))
01279 continue;
01280 rc = (headerIsEntry(h, RPMTAG_TRACK) == 0);
01281 if (rc == 0) {
01282
01283 break;
01284 }
01285 }
01286 mi = rpmmiFree(mi);
01287 }
01288 if (Flags & RPMSENSE_MISSINGOK)
01289 goto unsatisfied;
01290 rpmdsNotify(dep, _("(vcheck probe)"), rc);
01291 goto exit;
01292 }
01293
01294
01295 if (sysinfo_path == NULL) {
01296 sysinfo_path = rpmExpand("%{?_rpmds_sysinfo_path}", NULL);
01297 if (!(sysinfo_path != NULL && *sysinfo_path == '/')) {
01298 sysinfo_path = _free(sysinfo_path);
01299 sysinfo_path = xstrdup(SYSCONFIGDIR "/sysinfo");
01300 }
01301 }
01302
01303 if (!rpmioAccess(sysinfo_path, NULL, R_OK)) {
01304 #ifdef NOTYET
01305 rpmTag tagN = (Name[0] == '/' ? RPMTAG_DIRNAMES : RPMTAG_PROVIDENAME);
01306 #else
01307 rpmTag tagN = RPMTAG_PROVIDENAME;
01308 #endif
01309 rpmds P = rpmdsFromPRCO(rpmtsPRCO(ts), tagN);
01310 if (rpmdsSearch(P, dep) >= 0) {
01311 rpmdsNotify(dep, _("(sysinfo provides)"), rc);
01312 goto exit;
01313 }
01314 }
01315
01316
01317
01318
01319
01320
01321 if (NSType == RPMNS_TYPE_RPMLIB) {
01322 static int oneshot = -1;
01323
01324 if (oneshot)
01325 oneshot = rpmdsRpmlib(&rpmlibP, NULL);
01326 if (rpmlibP == NULL)
01327 goto unsatisfied;
01328
01329 if (rpmdsSearch(rpmlibP, dep) >= 0) {
01330 rpmdsNotify(dep, _("(rpmlib provides)"), rc);
01331 goto exit;
01332 }
01333 goto unsatisfied;
01334 }
01335
01336 if (NSType == RPMNS_TYPE_CPUINFO) {
01337 static int oneshot = -1;
01338
01339 if (oneshot && cpuinfoP == NULL)
01340 oneshot = rpmdsCpuinfo(&cpuinfoP, NULL);
01341 if (cpuinfoP == NULL)
01342 goto unsatisfied;
01343
01344 if (rpmdsSearch(cpuinfoP, dep) >= 0) {
01345 rpmdsNotify(dep, _("(cpuinfo provides)"), rc);
01346 goto exit;
01347 }
01348 goto unsatisfied;
01349 }
01350
01351 if (NSType == RPMNS_TYPE_GETCONF) {
01352 static int oneshot = -1;
01353
01354 if (oneshot)
01355 oneshot = rpmdsGetconf(&getconfP, NULL);
01356 if (getconfP == NULL)
01357 goto unsatisfied;
01358
01359 if (rpmdsSearch(getconfP, dep) >= 0) {
01360 rpmdsNotify(dep, _("(getconf provides)"), rc);
01361 goto exit;
01362 }
01363 goto unsatisfied;
01364 }
01365
01366 if (NSType == RPMNS_TYPE_UNAME) {
01367 static int oneshot = -1;
01368
01369 if (oneshot)
01370 oneshot = rpmdsUname(&unameP, NULL);
01371 if (unameP == NULL)
01372 goto unsatisfied;
01373
01374 if (rpmdsSearch(unameP, dep) >= 0) {
01375 rpmdsNotify(dep, _("(uname provides)"), rc);
01376 goto exit;
01377 }
01378 goto unsatisfied;
01379 }
01380
01381 if (NSType == RPMNS_TYPE_SONAME) {
01382 rpmds sonameP = NULL;
01383 rpmPRCO PRCO = rpmdsNewPRCO(NULL);
01384 char * fn = strcpy(alloca(strlen(Name)+1), Name);
01385 int flags = 0;
01386 rpmds ds;
01387
01388
01389 if (*fn != '/')
01390 goto unsatisfied;
01391 fn[strlen(fn)-1] = '\0';
01392
01393
01394 xx = rpmdsELF(fn, flags, rpmdsMergePRCO, PRCO);
01395 sonameP = rpmdsFromPRCO(PRCO, RPMTAG_PROVIDENAME);
01396 if (!(xx == 0 && sonameP != NULL))
01397 goto unsatisfied;
01398
01399
01400 ds = rpmdsSingle(rpmdsTagN(dep), rpmdsEVR(dep), "", Flags);
01401 xx = rpmdsSearch(sonameP, ds);
01402 (void)rpmdsFree(ds);
01403 ds = NULL;
01404 PRCO = rpmdsFreePRCO(PRCO);
01405
01406
01407 if (xx >= 0) {
01408 rpmdsNotify(dep, _("(soname provides)"), rc);
01409 goto exit;
01410 }
01411 goto unsatisfied;
01412 }
01413
01414
01415 if (rpmalSatisfiesDepend(ts->addedPackages, dep, NULL) != NULL) {
01416 #if defined(CACHE_DEPENDENCY_RESULT)
01417
01418
01419
01420
01421 if (_rpmds_nopromote)
01422 _cacheThisRC = 0;
01423 #endif
01424 goto exit;
01425 }
01426
01427
01428 if (rpmtsGetRdb(ts) != NULL) {
01429 if (Name[0] == '/') {
01430
01431
01432 mi = rpmtsInitIterator(ts, RPMTAG_BASENAMES, Name, 0);
01433 (void) rpmmiPrune(mi,
01434 ts->removedPackages, ts->numRemovedPackages, 1);
01435 while ((h = rpmmiNext(mi)) != NULL) {
01436 rpmdsNotify(dep, _("(db files)"), rc);
01437 mi = rpmmiFree(mi);
01438 goto exit;
01439 }
01440 mi = rpmmiFree(mi);
01441 }
01442
01443 mi = rpmtsInitIterator(ts, RPMTAG_PROVIDENAME, Name, 0);
01444 (void) rpmmiPrune(mi,
01445 ts->removedPackages, ts->numRemovedPackages, 1);
01446 while ((h = rpmmiNext(mi)) != NULL) {
01447 if (rpmdsAnyMatchesDep(h, dep, _rpmds_nopromote)) {
01448 rpmdsNotify(dep, _("(db provides)"), rc);
01449 mi = rpmmiFree(mi);
01450 goto exit;
01451 }
01452 }
01453 mi = rpmmiFree(mi);
01454 }
01455
01456
01457
01458
01459 if (adding == 1 && retries > 0 && !(rpmtsDFlags(ts) & RPMDEPS_FLAG_NOSUGGEST)) {
01460 if (ts->solve != NULL) {
01461 xx = (*ts->solve) (ts, dep, ts->solveData);
01462 if (xx == 0)
01463 goto exit;
01464 if (xx == -1) {
01465 retries--;
01466 rpmalMakeIndex(ts->addedPackages);
01467 goto retry;
01468 }
01469 }
01470 }
01471
01472 unsatisfied:
01473 if (Flags & RPMSENSE_MISSINGOK) {
01474 rc = 0;
01475 #if defined(CACHE_DEPENDENCY_RESULT)
01476 _cacheThisRC = 0;
01477 #endif
01478 rpmdsNotify(dep, _("(hint skipped)"), rc);
01479 } else {
01480 rc = 1;
01481 rpmdsNotify(dep, NULL, rc);
01482 }
01483
01484 exit:
01485
01486
01487
01488 #if defined(CACHE_DEPENDENCY_RESULT)
01489 if (_cacheDependsRC && _cacheThisRC) {
01490 dbiIndex dbi;
01491 dbi = dbiOpen(rpmtsGetRdb(ts), RPMDBI_DEPENDS, 0);
01492 if (dbi == NULL) {
01493 _cacheDependsRC = 0;
01494 } else {
01495 const char * DNEVR;
01496 xx = 0;
01497 if ((DNEVR = rpmdsDNEVR(dep)) != NULL) {
01498 DBC * dbcursor = NULL;
01499 size_t DNEVRlen = strlen(DNEVR);
01500
01501 xx = dbiCopen(dbi, dbiTxnid(dbi), &dbcursor, DB_WRITECURSOR);
01502
01503 memset(key, 0, sizeof(*key));
01504 key->data = (void *) DNEVR;
01505 key->size = DNEVRlen;
01506 memset(data, 0, sizeof(*data));
01507 data->data = &rc;
01508 data->size = sizeof(rc);
01509
01510
01511 xx = dbiPut(dbi, dbcursor, key, data, 0);
01512
01513 xx = dbiCclose(dbi, dbcursor, DB_WRITECURSOR);
01514 }
01515 if (xx)
01516 _cacheDependsRC = 0;
01517 }
01518 }
01519 #endif
01520
01521 return rpmdsNegateRC(dep, rc);
01522 }
01523
01537 static int checkPackageDeps(rpmts ts, const char * pkgNEVRA,
01538 rpmds requires,
01539 rpmds conflicts,
01540 rpmds dirnames,
01541 rpmds linktos,
01542 const char * depName,
01543 rpmuint32_t tscolor, int adding)
01544
01545
01546
01547
01548 {
01549 rpmps ps = rpmtsProblems(ts);
01550 rpmuint32_t dscolor;
01551 const char * Name;
01552 int terminate = 2;
01553 int rc;
01554 int ourrc = 0;
01555 #if defined(RPM_VENDOR_MANDRIVA) || defined(RPM_VENDOR_ARK)
01556 int dirname_deps;
01557 int symlink_deps;
01558 #endif
01559
01560 requires = rpmdsInit(requires);
01561 if (requires != NULL)
01562 while (ourrc < terminate && rpmdsNext(requires) >= 0) {
01563
01564 if ((Name = rpmdsN(requires)) == NULL)
01565 continue;
01566
01567
01568 if (depName != NULL && strcmp(depName, Name))
01569 continue;
01570
01571
01572 dscolor = rpmdsColor(requires);
01573 if (tscolor && dscolor && !(tscolor & dscolor))
01574 continue;
01575
01576 rc = unsatisfiedDepend(ts, requires, adding);
01577
01578 switch (rc) {
01579 case 0:
01580 break;
01581 case 1:
01582 { fnpyKey * suggestedKeys = NULL;
01583
01584 if (ts->availablePackages != NULL) {
01585 suggestedKeys = rpmalAllSatisfiesDepend(ts->availablePackages,
01586 requires, NULL);
01587 }
01588
01589 rpmdsProblem(ps, pkgNEVRA, requires, suggestedKeys, adding);
01590
01591 }
01592 ourrc = 1;
01593 break;
01594 case 2:
01595 default:
01596 ourrc = 2;
01597 break;
01598 }
01599 }
01600
01601 conflicts = rpmdsInit(conflicts);
01602 if (conflicts != NULL)
01603 while (ourrc < terminate && rpmdsNext(conflicts) >= 0) {
01604
01605 if ((Name = rpmdsN(conflicts)) == NULL)
01606 continue;
01607
01608
01609 if (depName != NULL && strcmp(depName, Name))
01610 continue;
01611
01612
01613 dscolor = rpmdsColor(conflicts);
01614 if (tscolor && dscolor && !(tscolor & dscolor))
01615 continue;
01616
01617 rc = unsatisfiedDepend(ts, conflicts, adding);
01618
01619
01620 switch (rc) {
01621 case 0:
01622 rpmdsProblem(ps, pkgNEVRA, conflicts, NULL, adding);
01623 ourrc = 1;
01624 break;
01625 case 1:
01626 break;
01627 case 2:
01628 default:
01629 ourrc = 2;
01630 break;
01631 }
01632 }
01633
01634 #if defined(RPM_VENDOR_MANDRIVA) || defined(RPM_VENDOR_ARK)
01635 dirname_deps = rpmExpandNumeric("%{?_check_dirname_deps}%{?!_check_dirname_deps:1}");
01636 if (dirname_deps) {
01637 #endif
01638 dirnames = rpmdsInit(dirnames);
01639 if (dirnames != NULL)
01640 while (ourrc < terminate && rpmdsNext(dirnames) >= 0) {
01641
01642 if ((Name = rpmdsN(dirnames)) == NULL)
01643 continue;
01644
01645
01646 if (depName != NULL && strcmp(depName, Name))
01647 continue;
01648
01649
01650 dscolor = rpmdsColor(dirnames);
01651 if (tscolor && dscolor && !(tscolor & dscolor))
01652 continue;
01653
01654 rc = unsatisfiedDepend(ts, dirnames, adding);
01655
01656 switch (rc) {
01657 case 0:
01658 break;
01659 case 1:
01660 { fnpyKey * suggestedKeys = NULL;
01661
01662 if (ts->availablePackages != NULL) {
01663 suggestedKeys = rpmalAllSatisfiesDepend(ts->availablePackages,
01664 dirnames, NULL);
01665 }
01666
01667 rpmdsProblem(ps, pkgNEVRA, dirnames, suggestedKeys, adding);
01668
01669 }
01670 ourrc = 1;
01671 break;
01672 case 2:
01673 default:
01674 ourrc = 2;
01675 break;
01676 }
01677 }
01678 #if defined(RPM_VENDOR_MANDRIVA) || defined(RPM_VENDOR_ARK)
01679 }
01680
01681 symlink_deps = rpmExpandNumeric("%{?_check_symlink_deps}%{?!_check_symlink_deps:1}");
01682 if (symlink_deps) {
01683 #endif
01684 linktos = rpmdsInit(linktos);
01685 if (linktos != NULL)
01686 while (ourrc < terminate && rpmdsNext(linktos) >= 0) {
01687
01688 if ((Name = rpmdsN(linktos)) == NULL)
01689 continue;
01690 if (*Name == '\0')
01691 continue;
01692
01693
01694 if (depName != NULL && strcmp(depName, Name))
01695 continue;
01696
01697
01698 dscolor = rpmdsColor(linktos);
01699 if (tscolor && dscolor && !(tscolor & dscolor))
01700 continue;
01701
01702 rc = unsatisfiedDepend(ts, linktos, adding);
01703
01704 switch (rc) {
01705 case 0:
01706 break;
01707 case 1:
01708 { fnpyKey * suggestedKeys = NULL;
01709
01710 if (ts->availablePackages != NULL) {
01711 suggestedKeys = rpmalAllSatisfiesDepend(ts->availablePackages,
01712 linktos, NULL);
01713 }
01714
01715 rpmdsProblem(ps, pkgNEVRA, linktos, suggestedKeys, adding);
01716
01717 }
01718 ourrc = 1;
01719 break;
01720 case 2:
01721 default:
01722 ourrc = 2;
01723 break;
01724 }
01725 }
01726 #if defined(RPM_VENDOR_MANDRIVA) || defined(RPM_VENDOR_ARK)
01727 }
01728 #endif
01729
01730 ps = rpmpsFree(ps);
01731 return ourrc;
01732 }
01733
01744 static int checkPackageSet(rpmts ts, const char * depName,
01745 rpmmi mi, int adding)
01746
01747
01748 {
01749 HE_t he = memset(alloca(sizeof(*he)), 0, sizeof(*he));
01750 rpmdepFlags depFlags = rpmtsDFlags(ts);
01751 rpmuint32_t tscolor = rpmtsColor(ts);
01752 int scareMem = 0;
01753 Header h;
01754 int terminate = 2;
01755 int ourrc = 0;
01756
01757 (void) rpmmiPrune(mi,
01758 ts->removedPackages, ts->numRemovedPackages, 1);
01759 while (ourrc < terminate && (h = rpmmiNext(mi)) != NULL) {
01760 rpmds requires = NULL;
01761 rpmds conflicts = NULL;
01762 rpmds dirnames = NULL;
01763 rpmds linktos = NULL;
01764 int rc;
01765
01766 he->tag = RPMTAG_NVRA;
01767 rc = (headerGet(h, he, 0) ? 0 : 2);
01768 if (rc > ourrc)
01769 ourrc = rc;
01770 if (ourrc >= terminate) {
01771 he->p.str = _free(he->p.str);
01772 break;
01773 }
01774
01775 if (!(depFlags & RPMDEPS_FLAG_NOREQUIRES))
01776 requires = rpmdsNew(h, RPMTAG_REQUIRENAME, scareMem);
01777 if (!(depFlags & RPMDEPS_FLAG_NOCONFLICTS))
01778 conflicts = rpmdsNew(h, RPMTAG_CONFLICTNAME, scareMem);
01779 if (!(depFlags & RPMDEPS_FLAG_NOPARENTDIRS))
01780 dirnames = rpmdsNew(h, RPMTAG_DIRNAMES, scareMem);
01781 if (!(depFlags & RPMDEPS_FLAG_NOLINKTOS))
01782 linktos = rpmdsNew(h, RPMTAG_FILELINKTOS, scareMem);
01783
01784 (void) rpmdsSetNoPromote(requires, _rpmds_nopromote);
01785 (void) rpmdsSetNoPromote(conflicts, _rpmds_nopromote);
01786 (void) rpmdsSetNoPromote(dirnames, _rpmds_nopromote);
01787 (void) rpmdsSetNoPromote(linktos, _rpmds_nopromote);
01788
01789 rc = checkPackageDeps(ts, he->p.str,
01790 requires, conflicts, dirnames, linktos,
01791 depName, tscolor, adding);
01792
01793 (void)rpmdsFree(linktos);
01794 linktos = NULL;
01795 (void)rpmdsFree(dirnames);
01796 dirnames = NULL;
01797 (void)rpmdsFree(conflicts);
01798 conflicts = NULL;
01799 (void)rpmdsFree(requires);
01800 requires = NULL;
01801 he->p.str = _free(he->p.str);
01802
01803 if (rc > ourrc)
01804 ourrc = rc;
01805 }
01806 mi = rpmmiFree(mi);
01807
01808 return ourrc;
01809 }
01810
01817 static int checkDependentPackages(rpmts ts, const char * depName)
01818
01819
01820 {
01821 int rc = 0;
01822
01823
01824 if (rpmtsGetRdb(ts) != NULL) {
01825 rpmmi mi;
01826 mi = rpmtsInitIterator(ts, RPMTAG_REQUIRENAME, depName, 0);
01827 rc = checkPackageSet(ts, depName, mi, 0);
01828 }
01829 return rc;
01830 }
01831
01838 static int checkDependentConflicts(rpmts ts, const char * depName)
01839
01840
01841 {
01842 int rc = 0;
01843
01844
01845 if (rpmtsGetRdb(ts) != NULL) {
01846 rpmmi mi;
01847 mi = rpmtsInitIterator(ts, RPMTAG_CONFLICTNAME, depName, 0);
01848 rc = checkPackageSet(ts, depName, mi, 1);
01849 }
01850
01851 return rc;
01852 }
01853
01854 struct badDeps_s {
01855
01856 const char * pname;
01857
01858 const char * qname;
01859 };
01860
01861 #ifdef REFERENCE
01862 static struct badDeps_s {
01863 const char * pname;
01864 const char * qname;
01865 } badDeps[] = {
01866 { NULL, NULL }
01867 };
01868 #else
01869
01870 static int badDepsInitialized = 0;
01871
01872
01873 static struct badDeps_s * badDeps = NULL;
01874 #endif
01875
01878
01879 static void freeBadDeps(void)
01880
01881
01882 {
01883 if (badDeps) {
01884 struct badDeps_s * bdp;
01885 for (bdp = badDeps; bdp->pname != NULL && bdp->qname != NULL; bdp++)
01886 bdp->pname = _free(bdp->pname);
01887 badDeps = _free(badDeps);
01888 }
01889 badDepsInitialized = 0;
01890 }
01891
01892
01901 static int ignoreDep(const rpmts ts, const rpmte p, const rpmte q)
01902
01903
01904
01905
01906 {
01907 struct badDeps_s * bdp;
01908
01909 if (!badDepsInitialized) {
01910 char * s = rpmExpand("%{?_dependency_whiteout}", NULL);
01911 const char ** av = NULL;
01912 int anaconda = rpmtsDFlags(ts) & RPMDEPS_FLAG_ANACONDA;
01913 int msglvl = (anaconda || (rpmtsDFlags(ts) & RPMDEPS_FLAG_DEPLOOPS))
01914 ? RPMLOG_WARNING : RPMLOG_DEBUG;
01915 int ac = 0;
01916 int i;
01917
01918 if (s != NULL && *s != '\0'
01919 && !(i = poptParseArgvString(s, &ac, (const char ***)&av))
01920 && ac > 0 && av != NULL)
01921 {
01922 bdp = badDeps = xcalloc(ac+1, sizeof(*badDeps));
01923 for (i = 0; i < ac; i++, bdp++) {
01924 char * pname, * qname;
01925
01926 if (av[i] == NULL)
01927 break;
01928 pname = xstrdup(av[i]);
01929 if ((qname = strchr(pname, '>')) != NULL)
01930 *qname++ = '\0';
01931 bdp->pname = pname;
01932
01933 bdp->qname = qname;
01934
01935 rpmlog(msglvl,
01936 _("ignore package name relation(s) [%d]\t%s -> %s\n"),
01937 i, bdp->pname, (bdp->qname ? bdp->qname : "???"));
01938 }
01939 bdp->pname = NULL;
01940 bdp->qname = NULL;
01941 }
01942 av = _free(av);
01943 s = _free(s);
01944 badDepsInitialized++;
01945 }
01946
01947
01948 if (badDeps != NULL)
01949 for (bdp = badDeps; bdp->pname != NULL && bdp->qname != NULL; bdp++) {
01950 if (!strcmp(rpmteN(p), bdp->pname) && !strcmp(rpmteN(q), bdp->qname))
01951 return 1;
01952 }
01953 return 0;
01954
01955 }
01956
01962 static void markLoop( tsortInfo tsi, rpmte q)
01963
01964
01965
01966 {
01967 rpmte p;
01968
01969 while (tsi != NULL && (p = tsi->tsi_suc) != NULL) {
01970 tsi = tsi->tsi_next;
01971 if (rpmteTSI(p)->tsi_chain != NULL)
01972 continue;
01973
01974 rpmteTSI(p)->tsi_chain = q;
01975
01976 if (rpmteTSI(p)->tsi_next != NULL)
01977 markLoop(rpmteTSI(p)->tsi_next, p);
01978 }
01979 }
01980
01981
01982
01983
01984
01985
01986 static inline const char * identifyDepend(rpmuint32_t f)
01987
01988 {
01989 f = _notpre(f);
01990 if (f & RPMSENSE_SCRIPT_PRE)
01991 return "Requires(pre):";
01992 if (f & RPMSENSE_SCRIPT_POST)
01993 return "Requires(post):";
01994 if (f & RPMSENSE_SCRIPT_PREUN)
01995 return "Requires(preun):";
01996 if (f & RPMSENSE_SCRIPT_POSTUN)
01997 return "Requires(postun):";
01998 if (f & RPMSENSE_SCRIPT_VERIFY)
01999 return "Requires(verify):";
02000 if (f & RPMSENSE_MISSINGOK)
02001 return "Requires(hint):";
02002 if (f & RPMSENSE_FIND_REQUIRES)
02003 return "Requires(auto):";
02004 return "Requires:";
02005 }
02006
02019
02020 static const char *
02021 zapRelation(rpmte q, rpmte p,
02022 int zap, int * nzaps, int msglvl)
02023
02024
02025 {
02026 rpmds requires;
02027 tsortInfo tsi_prev;
02028 tsortInfo tsi;
02029 const char *dp = NULL;
02030
02031 for (tsi_prev = rpmteTSI(q), tsi = rpmteTSI(q)->tsi_next;
02032 tsi != NULL;
02033
02034
02035 tsi_prev = tsi, tsi = tsi->tsi_next)
02036
02037 {
02038 rpmuint32_t Flags;
02039
02040
02041 if (tsi->tsi_suc != p)
02042 continue;
02043
02044
02045 requires = rpmteDS((rpmteType(p) == TR_REMOVED ? q : p), tsi->tsi_tagn);
02046 if (requires == NULL) continue;
02047
02048 (void) rpmdsSetIx(requires, tsi->tsi_reqx);
02049
02050 Flags = rpmdsFlags(requires);
02051
02052 dp = rpmdsNewDNEVR( identifyDepend(Flags), requires);
02053
02054
02055
02056
02057 if (zap) {
02058 rpmlog(msglvl,
02059 _("removing %s \"%s\" from tsort relations.\n"),
02060 (rpmteNEVRA(p) ? rpmteNEVRA(p) : "???"), dp);
02061 rpmteTSI(p)->tsi_count--;
02062 if (tsi_prev) tsi_prev->tsi_next = tsi->tsi_next;
02063 tsi->tsi_next = NULL;
02064 tsi->tsi_suc = NULL;
02065 tsi = _free(tsi);
02066 if (nzaps)
02067 (*nzaps)++;
02068 if (zap)
02069 zap--;
02070 }
02071
02072 break;
02073 }
02074 return dp;
02075 }
02076
02077
02086
02087 static inline int addRelation(rpmts ts,
02088 rpmte p,
02089 unsigned char * selected,
02090 rpmds requires)
02091
02092
02093
02094 {
02095 rpmtsi qi; rpmte q;
02096 tsortInfo tsi;
02097 nsType NSType = rpmdsNSType(requires);
02098 fnpyKey key;
02099 int teType = rpmteType(p);
02100 alKey pkgKey;
02101 int i = 0;
02102 rpmal al = (teType == TR_ADDED ? ts->addedPackages : ts->erasedPackages);
02103
02104
02105 switch (NSType) {
02106 case RPMNS_TYPE_RPMLIB:
02107 case RPMNS_TYPE_CONFIG:
02108 case RPMNS_TYPE_CPUINFO:
02109 case RPMNS_TYPE_GETCONF:
02110 case RPMNS_TYPE_UNAME:
02111 case RPMNS_TYPE_SONAME:
02112 case RPMNS_TYPE_ACCESS:
02113 case RPMNS_TYPE_USER:
02114 case RPMNS_TYPE_GROUP:
02115 case RPMNS_TYPE_MOUNTED:
02116 case RPMNS_TYPE_DISKSPACE:
02117 case RPMNS_TYPE_DIGEST:
02118 case RPMNS_TYPE_GNUPG:
02119 case RPMNS_TYPE_MACRO:
02120 case RPMNS_TYPE_ENVVAR:
02121 case RPMNS_TYPE_RUNNING:
02122 case RPMNS_TYPE_SANITY:
02123 case RPMNS_TYPE_VCHECK:
02124 case RPMNS_TYPE_SIGNATURE:
02125 return 0;
02126 break;
02127 default:
02128 break;
02129 }
02130
02131 pkgKey = RPMAL_NOMATCH;
02132 key = rpmalSatisfiesDepend(al, requires, &pkgKey);
02133
02134
02135 if (pkgKey == RPMAL_NOMATCH)
02136 return 0;
02137
02138
02139
02140 if (teType == TR_REMOVED)
02141 pkgKey = (alKey)(((long)pkgKey) + ts->numAddedPackages);
02142
02143 for (qi = rpmtsiInit(ts), i = 0; (q = rpmtsiNext(qi, 0)) != NULL; i++) {
02144 if (pkgKey == rpmteAddedKey(q))
02145 break;
02146 }
02147 qi = rpmtsiFree(qi);
02148 if (q == NULL || i >= ts->orderCount)
02149 return 0;
02150
02151
02152 if (ignoreDep(ts, p, q))
02153 return 0;
02154
02155
02156 if (selected[i] != 0)
02157 return 0;
02158 selected[i] = 1;
02159
02160
02161 if (teType == TR_REMOVED) {
02162 rpmte r = p;
02163 p = q;
02164 q = r;
02165 }
02166
02167
02168 rpmteTSI(p)->tsi_count++;
02169
02170 if (rpmteDepth(p) <= rpmteDepth(q))
02171 (void) rpmteSetDepth(p, (rpmteDepth(q) + 1));
02172 if (rpmteDepth(p) > ts->maxDepth)
02173 ts->maxDepth = rpmteDepth(p);
02174
02175 tsi = xcalloc(1, sizeof(*tsi));
02176 tsi->tsi_suc = p;
02177
02178 tsi->tsi_tagn = rpmdsTagN(requires);
02179 tsi->tsi_reqx = rpmdsIx(requires);
02180
02181 tsi->tsi_next = rpmteTSI(q)->tsi_next;
02182 rpmteTSI(q)->tsi_next = tsi;
02183 rpmteTSI(q)->tsi_qcnt++;
02184
02185 return 0;
02186 }
02187
02188
02195 static int orderListIndexCmp(const void * one, const void * two)
02196 {
02197
02198 long a = (long) ((const orderListIndex)one)->pkgKey;
02199 long b = (long) ((const orderListIndex)two)->pkgKey;
02200
02201 return (a - b);
02202 }
02203
02211
02212 static void addQ( rpmte p,
02213 rpmte * qp,
02214 rpmte * rp,
02215 rpmuint32_t prefcolor)
02216
02217 {
02218 rpmte q, qprev;
02219
02220
02221 rpmteTSI(p)->tsi_queued = 1;
02222
02223 if ((*rp) == NULL) {
02224
02225 (*rp) = (*qp) = p;
02226
02227 return;
02228 }
02229
02230
02231 for (qprev = NULL, q = (*qp);
02232 q != NULL;
02233 qprev = q, q = rpmteTSI(q)->tsi_suc)
02234 {
02235
02236 if (rpmteColor(p) != prefcolor && rpmteColor(p) != rpmteColor(q))
02237 continue;
02238
02239
02240 if (rpmteType(p) == TR_REMOVED && rpmteType(p) != rpmteType(q))
02241 continue;
02242 if (rpmteTSI(q)->tsi_qcnt <= rpmteTSI(p)->tsi_qcnt)
02243 break;
02244 }
02245
02246 if (qprev == NULL) {
02247 rpmteTSI(p)->tsi_suc = q;
02248
02249 (*qp) = p;
02250
02251 } else if (q == NULL) {
02252 rpmteTSI(qprev)->tsi_suc = p;
02253
02254 (*rp) = p;
02255
02256 } else {
02257 rpmteTSI(p)->tsi_suc = q;
02258 rpmteTSI(qprev)->tsi_suc = p;
02259 }
02260 }
02261
02262
02263
02264 #ifdef NOTYET
02265 static rpmuint32_t _autobits = _notpre(_ALL_REQUIRES_MASK);
02266 #else
02267 static rpmuint32_t _autobits = 0xffffffff;
02268 #endif
02269 #define isAuto(_x) ((_x) & _autobits)
02270
02271
02272 static int slashDepth = 100;
02273
02274 static int countSlashes(const char * dn)
02275
02276 {
02277 int nslashes = 0;
02278 int c;
02279
02280 while ((c = (int)*dn++) != 0) {
02281 switch (c) {
02282 default: continue; break;
02283 case '/': nslashes++; break;
02284 }
02285 }
02286
02287 return nslashes;
02288 }
02289
02290 int rpmtsOrder(rpmts ts)
02291 {
02292 rpmds requires;
02293 rpmuint32_t Flags;
02294 int anaconda = rpmtsDFlags(ts) & RPMDEPS_FLAG_ANACONDA;
02295 rpmuint32_t prefcolor = rpmtsPrefColor(ts);
02296 rpmtsi pi; rpmte p;
02297 rpmtsi qi; rpmte q;
02298 rpmtsi ri; rpmte r;
02299 tsortInfo tsi;
02300 tsortInfo tsi_next;
02301 alKey * ordering;
02302 int orderingCount = 0;
02303 unsigned char * selected = alloca(sizeof(*selected) * (ts->orderCount + 1));
02304 int loopcheck;
02305 rpmte * newOrder;
02306 int newOrderCount = 0;
02307 orderListIndex orderList;
02308 int numOrderList;
02309 int npeer = 128;
02310 int * peer = memset(alloca(npeer*sizeof(*peer)), 0, (npeer*sizeof(*peer)));
02311 int nrescans = 10;
02312 int _printed = 0;
02313 char deptypechar;
02314 size_t tsbytes;
02315 int oType = 0;
02316 int treex;
02317 int depth;
02318 int breadth;
02319 int qlen;
02320 int i, j;
02321
02322 #ifdef DYING
02323 rpmalMakeIndex(ts->addedPackages);
02324 #endif
02325
02326
02327 pi = rpmtsiInit(ts);
02328 while ((p = rpmtsiNext(pi, TR_REMOVED)) != NULL) {
02329 alKey pkgKey;
02330 fnpyKey key;
02331 rpmuint32_t tscolor = rpmtsColor(ts);
02332 pkgKey = RPMAL_NOMATCH;
02333
02334 key = (fnpyKey) p;
02335
02336 pkgKey = rpmalAdd(&ts->erasedPackages, pkgKey, key,
02337 rpmteDS(p, RPMTAG_PROVIDENAME),
02338 rpmteFI(p, RPMTAG_BASENAMES), tscolor);
02339
02340 pkgKey = (alKey)(((long)pkgKey) + ts->numAddedPackages);
02341 (void) rpmteSetAddedKey(p, pkgKey);
02342 }
02343 pi = rpmtsiFree(pi);
02344 rpmalMakeIndex(ts->erasedPackages);
02345
02346 (void) rpmswEnter(rpmtsOp(ts, RPMTS_OP_ORDER), 0);
02347
02348
02349 if (oType == 0)
02350 numOrderList = ts->orderCount;
02351 else {
02352 numOrderList = 0;
02353 if (oType & TR_ADDED)
02354 numOrderList += ts->numAddedPackages;
02355 if (oType & TR_REMOVED)
02356 numOrderList += ts->numRemovedPackages;
02357 }
02358 ordering = alloca(sizeof(*ordering) * (numOrderList + 1));
02359 loopcheck = numOrderList;
02360 tsbytes = 0;
02361
02362 pi = rpmtsiInit(ts);
02363 while ((p = rpmtsiNext(pi, oType)) != NULL)
02364 rpmteNewTSI(p);
02365 pi = rpmtsiFree(pi);
02366
02367
02368 rpmlog(RPMLOG_DEBUG, D_("========== recording tsort relations\n"));
02369 pi = rpmtsiInit(ts);
02370 while ((p = rpmtsiNext(pi, oType)) != NULL) {
02371
02372 memset(selected, 0, sizeof(*selected) * ts->orderCount);
02373
02374 if ((requires = rpmteDS(p, RPMTAG_REQUIRENAME)) != NULL) {
02375
02376
02377 selected[rpmtsiOc(pi)] = 1;
02378
02379
02380
02381
02382 requires = rpmdsInit(requires);
02383 if (requires != NULL)
02384 while (rpmdsNext(requires) >= 0) {
02385
02386 Flags = rpmdsFlags(requires);
02387 if (!isAuto(Flags))
02388 continue;
02389
02390 switch (rpmteType(p)) {
02391 case TR_REMOVED:
02392
02393 if (!isErasePreReq(Flags))
02394 continue;
02395 break;
02396 case TR_ADDED:
02397
02398 if (!isInstallPreReq(Flags))
02399 continue;
02400 break;
02401 }
02402
02403
02404 (void) addRelation(ts, p, selected, requires);
02405
02406 }
02407
02408
02409 requires = rpmdsInit(requires);
02410 if (requires != NULL)
02411 while (rpmdsNext(requires) >= 0) {
02412
02413 Flags = rpmdsFlags(requires);
02414 if (!isAuto(Flags))
02415 continue;
02416
02417 switch (rpmteType(p)) {
02418 case TR_REMOVED:
02419
02420 if (isErasePreReq(Flags))
02421 continue;
02422 break;
02423 case TR_ADDED:
02424
02425 if (isInstallPreReq(Flags))
02426 continue;
02427 break;
02428 }
02429
02430
02431 (void) addRelation(ts, p, selected, requires);
02432
02433 }
02434 }
02435
02436
02437 if (rpmteType(p) == TR_REMOVED && p->flink.Pkgid && p->flink.Pkgid[0]) {
02438
02439 qi = rpmtsiInit(ts);
02440 while ((q = rpmtsiNext(qi, TR_ADDED)) != NULL) {
02441 if (strcmp(q->pkgid, p->flink.Pkgid[0]))
02442 continue;
02443 requires = rpmdsFromPRCO(q->PRCO, RPMTAG_NAME);
02444 if (requires != NULL) {
02445
02446 p->type = TR_ADDED;
02447 (void) addRelation(ts, p, selected, requires);
02448 p->type = TR_REMOVED;
02449 }
02450 }
02451 qi = rpmtsiFree(qi);
02452 }
02453
02454 {
02455
02456
02457 requires = rpmdsInit(rpmteDS(p, RPMTAG_DIRNAMES));
02458 if (requires != NULL)
02459 while (rpmdsNext(requires) >= 0) {
02460
02461
02462 if (countSlashes(rpmdsN(requires)) > slashDepth)
02463 continue;
02464
02465
02466 (void) addRelation(ts, p, selected, requires);
02467
02468 }
02469
02470
02471 requires = rpmdsInit(rpmteDS(p, RPMTAG_FILELINKTOS));
02472 if (requires != NULL)
02473 while (rpmdsNext(requires) >= 0) {
02474
02475
02476 (void) addRelation(ts, p, selected, requires);
02477
02478 }
02479 }
02480
02481 }
02482 pi = rpmtsiFree(pi);
02483
02484
02485 treex = 0;
02486 pi = rpmtsiInit(ts);
02487 while ((p = rpmtsiNext(pi, oType)) != NULL) {
02488 int npreds;
02489
02490 npreds = rpmteTSI(p)->tsi_count;
02491
02492 (void) rpmteSetNpreds(p, npreds);
02493 (void) rpmteSetDepth(p, 0);
02494
02495 if (npreds == 0) {
02496 treex++;
02497 (void) rpmteSetTree(p, treex);
02498 (void) rpmteSetBreadth(p, treex);
02499 } else
02500 (void) rpmteSetTree(p, -1);
02501 #ifdef UNNECESSARY
02502 (void) rpmteSetParent(p, NULL);
02503 #endif
02504
02505 }
02506 pi = rpmtsiFree(pi);
02507 ts->ntrees = treex;
02508
02509
02510 rpmlog(RPMLOG_DEBUG, D_("========== tsorting packages (order, #predecessors, #succesors, tree, Ldepth, Rbreadth)\n"));
02511
02512 rescan:
02513 if (pi != NULL) pi = rpmtsiFree(pi);
02514 q = r = NULL;
02515 qlen = 0;
02516 pi = rpmtsiInit(ts);
02517 while ((p = rpmtsiNext(pi, oType)) != NULL) {
02518
02519
02520 if (anaconda)
02521 rpmteTSI(p)->tsi_qcnt = (ts->orderCount - rpmtsiOc(pi));
02522
02523 if (rpmteTSI(p)->tsi_count != 0)
02524 continue;
02525 rpmteTSI(p)->tsi_suc = NULL;
02526 addQ(p, &q, &r, prefcolor);
02527 qlen++;
02528 }
02529 pi = rpmtsiFree(pi);
02530
02531
02532 for (; q != NULL; q = rpmteTSI(q)->tsi_suc) {
02533
02534
02535 rpmteTSI(q)->tsi_queued = 0;
02536
02537 if (oType != 0)
02538 switch (rpmteType(q)) {
02539 case TR_ADDED:
02540 if (!(oType & TR_ADDED))
02541 continue;
02542 break;
02543 case TR_REMOVED:
02544 if (!(oType & TR_REMOVED))
02545 continue;
02546 break;
02547 default:
02548 continue;
02549 break;
02550 }
02551 deptypechar = (rpmteType(q) == TR_REMOVED ? '-' : '+');
02552
02553 treex = rpmteTree(q);
02554 depth = rpmteDepth(q);
02555 breadth = ((depth < npeer) ? peer[depth]++ : 0);
02556 (void) rpmteSetBreadth(q, breadth);
02557
02558 rpmlog(RPMLOG_DEBUG, "%5d%5d%5d%5d%5d%5d %*s%c%s\n",
02559 orderingCount, rpmteNpreds(q),
02560 rpmteTSI(q)->tsi_qcnt,
02561 treex, depth, breadth,
02562 (2 * depth), "",
02563 deptypechar,
02564 (rpmteNEVRA(q) ? rpmteNEVRA(q) : "???"));
02565
02566 (void) rpmteSetDegree(q, 0);
02567 tsbytes += rpmtePkgFileSize(q);
02568
02569 ordering[orderingCount] = rpmteAddedKey(q);
02570 orderingCount++;
02571 qlen--;
02572 loopcheck--;
02573
02574
02575 tsi_next = rpmteTSI(q)->tsi_next;
02576 rpmteTSI(q)->tsi_next = NULL;
02577 while ((tsi = tsi_next) != NULL) {
02578 tsi_next = tsi->tsi_next;
02579 tsi->tsi_next = NULL;
02580 p = tsi->tsi_suc;
02581 if (p && (--rpmteTSI(p)->tsi_count) <= 0) {
02582
02583 (void) rpmteSetTree(p, treex);
02584 (void) rpmteSetDepth(p, depth+1);
02585 (void) rpmteSetParent(p, q);
02586 (void) rpmteSetDegree(q, rpmteDegree(q)+1);
02587
02588
02589 rpmteTSI(p)->tsi_suc = NULL;
02590
02591 addQ(p, &rpmteTSI(q)->tsi_suc, &r, prefcolor);
02592
02593 qlen++;
02594 }
02595 tsi = _free(tsi);
02596 }
02597 if (!_printed && loopcheck == qlen && rpmteTSI(q)->tsi_suc != NULL) {
02598 _printed++;
02599 (void) rpmtsUnorderedSuccessors(ts, orderingCount);
02600 rpmlog(RPMLOG_DEBUG,
02601 D_("========== successors only (%d bytes)\n"), (int)tsbytes);
02602
02603
02604 tsi = rpmteTSI(q);
02605 pi = rpmtsiInit(ts);
02606 while ((p = rpmtsiNext(pi, oType)) != NULL) {
02607
02608 if (rpmteTSI(p)->tsi_queued == 0)
02609 continue;
02610 tsi->tsi_suc = p;
02611 tsi = rpmteTSI(p);
02612 }
02613 pi = rpmtsiFree(pi);
02614 tsi->tsi_suc = NULL;
02615 }
02616 }
02617
02618
02619 if (loopcheck != 0) {
02620 int nzaps;
02621
02622
02623 nzaps = 0;
02624 qi = rpmtsiInit(ts);
02625 while ((q = rpmtsiNext(qi, oType)) != NULL) {
02626 rpmteTSI(q)->tsi_chain = NULL;
02627 rpmteTSI(q)->tsi_queued = 0;
02628
02629 if (rpmteTSI(q)->tsi_count == 0)
02630 rpmteTSI(q)->tsi_count = -1;
02631 }
02632 qi = rpmtsiFree(qi);
02633
02634
02635 qi = rpmtsiInit(ts);
02636 while ((q = rpmtsiNext(qi, oType)) != NULL) {
02637 if ((tsi = rpmteTSI(q)->tsi_next) == NULL)
02638 continue;
02639 rpmteTSI(q)->tsi_next = NULL;
02640 markLoop(tsi, q);
02641 rpmteTSI(q)->tsi_next = tsi;
02642 }
02643 qi = rpmtsiFree(qi);
02644
02645
02646 ri = rpmtsiInit(ts);
02647 while ((r = rpmtsiNext(ri, oType)) != NULL)
02648 {
02649 int printed;
02650
02651 printed = 0;
02652
02653
02654 for (q = rpmteTSI(r)->tsi_chain; q != NULL;
02655 q = rpmteTSI(q)->tsi_chain)
02656 {
02657 if (rpmteTSI(q)->tsi_queued)
02658 break;
02659 rpmteTSI(q)->tsi_queued = 1;
02660 }
02661
02662
02663 while ((p = q) != NULL && (q = rpmteTSI(p)->tsi_chain) != NULL) {
02664 #if 0
02665 const char * nevra;
02666 #endif
02667 const char * dp;
02668 rpmlogLvl msglvl = (anaconda || (rpmtsDFlags(ts) & RPMDEPS_FLAG_DEPLOOPS))
02669 ? RPMLOG_WARNING : RPMLOG_ERR;
02670 #if defined(RPM_VENDOR_MANDRIVA)
02671
02672 msglvl = rpmExpandNumeric("%{?_loop_detection_loglevel}%{?!_loop_detection_loglevel:7}");
02673 #endif
02674
02675
02676 rpmteTSI(p)->tsi_chain = NULL;
02677
02678 if (!printed) {
02679 rpmlog(msglvl, _("LOOP:\n"));
02680 printed = 1;
02681 }
02682
02683
02684 dp = zapRelation(q, p, 1, &nzaps, msglvl);
02685
02686 #if 0
02687
02688 nevra = rpmteNEVRA(p);
02689 rpmlog(msglvl, " %-40s %s\n", (nevra ? nevra : "???"),
02690 (dp ? dp : "not found!?!"));
02691 #endif
02692
02693 dp = _free(dp);
02694 }
02695
02696
02697 for (p = r, q = rpmteTSI(r)->tsi_chain; q != NULL;
02698 p = q, q = rpmteTSI(q)->tsi_chain)
02699 {
02700
02701 rpmteTSI(p)->tsi_chain = NULL;
02702 rpmteTSI(p)->tsi_queued = 0;
02703 }
02704 }
02705 ri = rpmtsiFree(ri);
02706
02707
02708
02709 if (nzaps && nrescans-- > 0) {
02710 rpmlog(RPMLOG_DEBUG, D_("========== continuing tsort ...\n"));
02711 goto rescan;
02712 }
02713
02714
02715 rpmlog(RPMLOG_ERR, _("rpmtsOrder failed, %d elements remain\n"),
02716 loopcheck);
02717
02718 #ifdef NOTYET
02719
02720 (void) rpmtsRollback(ts, RPMPROB_FILTER_NONE, 0, NULL);
02721 #endif
02722
02723 return loopcheck;
02724 }
02725
02726
02727 pi = rpmtsiInit(ts);
02728 while ((p = rpmtsiNext(pi, 0)) != NULL)
02729 rpmteFreeTSI(p);
02730 pi = rpmtsiFree(pi);
02731
02732
02733
02734
02735 orderList = xcalloc(numOrderList, sizeof(*orderList));
02736 j = 0;
02737 pi = rpmtsiInit(ts);
02738 while ((p = rpmtsiNext(pi, oType)) != NULL) {
02739
02740 orderList[j].pkgKey = rpmteAddedKey(p);
02741 orderList[j].orIndex = rpmtsiOc(pi);
02742 j++;
02743 }
02744 pi = rpmtsiFree(pi);
02745
02746 qsort(orderList, numOrderList, sizeof(*orderList), orderListIndexCmp);
02747
02748
02749 newOrder = xcalloc(ts->orderCount, sizeof(*newOrder));
02750
02751 for (i = 0, newOrderCount = 0; i < orderingCount; i++)
02752 {
02753 struct orderListIndex_s key;
02754 orderListIndex needle;
02755
02756 key.pkgKey = ordering[i];
02757 needle = bsearch(&key, orderList, numOrderList,
02758 sizeof(key), orderListIndexCmp);
02759 if (needle == NULL)
02760 continue;
02761
02762 j = needle->orIndex;
02763 if ((q = ts->order[j]) == NULL || needle->pkgKey == RPMAL_NOMATCH)
02764 continue;
02765
02766 newOrder[newOrderCount++] = q;
02767 ts->order[j] = NULL;
02768 }
02769
02770 assert(newOrderCount == ts->orderCount);
02771
02772
02773 ts->order = _free(ts->order);
02774
02775 ts->order = newOrder;
02776 ts->orderAlloced = ts->orderCount;
02777 orderList = _free(orderList);
02778
02779 #ifdef DYING
02780 rpmtsClean(ts);
02781 #endif
02782 freeBadDeps();
02783
02784 (void) rpmswExit(rpmtsOp(ts, RPMTS_OP_ORDER), 0);
02785
02786 return 0;
02787 }
02788
02789 int rpmtsCheck(rpmts ts)
02790 {
02791 const char * depName = NULL;
02792 rpmdepFlags depFlags = rpmtsDFlags(ts);
02793 rpmuint32_t tscolor = rpmtsColor(ts);
02794 rpmmi mi = NULL;
02795 rpmtsi pi = NULL; rpmte p;
02796 int closeatexit = 0;
02797 int xx;
02798 int terminate = 2;
02799 int rc = 0;
02800 int ourrc = 0;
02801
02802 (void) rpmswEnter(rpmtsOp(ts, RPMTS_OP_CHECK), 0);
02803
02804
02805 if (rpmtsGetRdb(ts) == NULL && rpmtsDBMode(ts) != -1) {
02806 rc = (rpmtsOpenDB(ts, rpmtsDBMode(ts)) ? 2 : 0);
02807 closeatexit = (rc == 0);
02808 }
02809 if (rc && (ourrc = rc) >= terminate)
02810 goto exit;
02811
02812 ts->probs = rpmpsFree(ts->probs);
02813
02814 rpmalMakeIndex(ts->addedPackages);
02815
02816
02817
02818
02819
02820 pi = rpmtsiInit(ts);
02821 while (ourrc < terminate && (p = rpmtsiNext(pi, TR_ADDED)) != NULL) {
02822 rpmds provides, requires, conflicts, dirnames, linktos;
02823 rpmfi fi;
02824
02825
02826 rpmlog(RPMLOG_DEBUG, "========== +++ %s %s/%s 0x%x\n",
02827 rpmteNEVR(p), rpmteA(p), rpmteO(p), rpmteColor(p));
02828
02829 requires = (!(depFlags & RPMDEPS_FLAG_NOREQUIRES)
02830 ? rpmteDS(p, RPMTAG_REQUIRENAME) : NULL);
02831 conflicts = (!(depFlags & RPMDEPS_FLAG_NOCONFLICTS)
02832 ? rpmteDS(p, RPMTAG_CONFLICTNAME) : NULL);
02833
02834 if (p->isSource) {
02835 dirnames = NULL;
02836 linktos = NULL;
02837 } else {
02838 dirnames = (!(depFlags & RPMDEPS_FLAG_NOPARENTDIRS)
02839 ? rpmteDS(p, RPMTAG_DIRNAMES) : NULL);
02840 linktos = (!(depFlags & RPMDEPS_FLAG_NOLINKTOS)
02841 ? rpmteDS(p, RPMTAG_FILELINKTOS) : NULL);
02842 }
02843
02844 rc = checkPackageDeps(ts, rpmteNEVRA(p),
02845 requires, conflicts, dirnames, linktos,
02846 NULL, tscolor, 1);
02847 if (rc && (ourrc = rc) >= terminate)
02848 break;
02849
02850 provides = rpmteDS(p, RPMTAG_PROVIDENAME);
02851 provides = rpmdsInit(provides);
02852 if (provides != NULL)
02853 while (ourrc < terminate && rpmdsNext(provides) >= 0) {
02854 depName = _free(depName);
02855 depName = xstrdup(rpmdsN(provides));
02856
02857 #ifdef NOTYET
02858 if (rpmdsNSType(provides) == RPMNS_TYPE_ENVVAR) {
02859 const char * EVR = rpmdsEVR(provides);
02860 if (rpmdsNegateRC(provides, 0))
02861 EVR = NULL;
02862 if (envPut(depName, EVR));
02863 rc = 2;
02864 } else
02865 #endif
02866
02867
02868 if (checkDependentConflicts(ts, depName))
02869 rc = 1;
02870 }
02871 if (rc && (ourrc = rc) >= terminate)
02872 break;
02873
02874 fi = rpmteFI(p, RPMTAG_BASENAMES);
02875 fi = rpmfiInit(fi, 0);
02876 while (ourrc < terminate && rpmfiNext(fi) >= 0) {
02877 depName = _free(depName);
02878 depName = xstrdup(rpmfiFN(fi));
02879
02880 if (checkDependentConflicts(ts, depName))
02881 rc = 1;
02882 }
02883 if (rc && (ourrc = rc) >= terminate)
02884 break;
02885 }
02886 pi = rpmtsiFree(pi);
02887 if (rc && (ourrc = rc) >= terminate)
02888 goto exit;
02889
02890
02891
02892
02893 pi = rpmtsiInit(ts);
02894 while (ourrc < terminate && (p = rpmtsiNext(pi, TR_REMOVED)) != NULL) {
02895 rpmds provides;
02896 rpmfi fi;
02897
02898
02899 rpmlog(RPMLOG_DEBUG, "========== --- %s %s/%s 0x%x\n",
02900 rpmteNEVR(p), rpmteA(p), rpmteO(p), rpmteColor(p));
02901
02902
02903 provides = rpmteDS(p, RPMTAG_PROVIDENAME);
02904 provides = rpmdsInit(provides);
02905 if (provides != NULL)
02906 while (ourrc < terminate && rpmdsNext(provides) >= 0) {
02907 depName = _free(depName);
02908 depName = xstrdup(rpmdsN(provides));
02909
02910
02911 if (checkDependentPackages(ts, depName))
02912 rc = 1;
02913 }
02914 if (rc && (ourrc = rc) >= terminate)
02915 break;
02916
02917 fi = rpmteFI(p, RPMTAG_BASENAMES);
02918 fi = rpmfiInit(fi, 0);
02919 while (ourrc < terminate && rpmfiNext(fi) >= 0) {
02920 depName = _free(depName);
02921 depName = xstrdup(rpmfiFN(fi));
02922
02923 if (checkDependentPackages(ts, depName))
02924 rc = 1;
02925 }
02926 if (rc && (ourrc = rc) >= terminate)
02927 break;
02928 }
02929 pi = rpmtsiFree(pi);
02930 if (rc && (ourrc = rc) >= terminate)
02931 goto exit;
02932
02933
02934
02935
02936 { const char * tsNEVRA = "transaction dependencies";
02937 rpmds R = rpmdsFromPRCO(rpmtsPRCO(ts), RPMTAG_REQUIRENAME);
02938 rpmds C = rpmdsFromPRCO(rpmtsPRCO(ts), RPMTAG_CONFLICTNAME);
02939 rpmds D = NULL;
02940 rpmds L = NULL;
02941 const char * dep = NULL;
02942 int adding = 2;
02943 tscolor = 0;
02944 rc = checkPackageDeps(ts, tsNEVRA, R, C, D, L, dep, tscolor, adding);
02945 }
02946 if (rc && (ourrc = rc) >= terminate)
02947 goto exit;
02948
02949 exit:
02950 mi = rpmmiFree(mi);
02951 pi = rpmtsiFree(pi);
02952 depName = _free(depName);
02953
02954 (void) rpmswExit(rpmtsOp(ts, RPMTS_OP_CHECK), 0);
02955
02956 if (closeatexit)
02957 xx = rpmtsCloseDB(ts);
02958 #if defined(CACHE_DEPENDENCY_RESULT)
02959 else if (_cacheDependsRC)
02960 xx = rpmdbCloseDBI(rpmtsGetRdb(ts), RPMDBI_DEPENDS);
02961 #endif
02962
02963 #ifdef NOTYET
02964
02965 { rpmps ps = rpmtsProblems(ts);
02966 if (rc || rpmpsNumProblems(ps) > 0)
02967 (void) rpmtsRollback(ts, RPMPROB_FILTER_NONE, 0, NULL);
02968 ps = rpmpsFree(ps);
02969 }
02970 #endif
02971
02972 return ourrc;
02973 }