Main Page   Modules   Data Structures   File List   Data Fields   Globals   Related Pages  

lib/transaction.c

Go to the documentation of this file.
00001 
00005 #include "system.h"
00006 
00007 #include "rpmmacro.h"   /* XXX for rpmExpand */
00008 
00009 #include "psm.h"
00010 
00011 #include "rpmdb.h"
00012 #include "fprint.h"
00013 #include "rpmhash.h"
00014 #include "misc.h" /* XXX stripTrailingChar, splitString, currentDirectory */
00015 
00016 #ifdef  DYING
00017 /*@-redecl -exportheadervar@*/
00018 extern const char * chroot_prefix;
00019 /*@=redecl =exportheadervar@*/
00020 #endif
00021 
00022 /* XXX FIXME: merge with existing (broken?) tests in system.h */
00023 /* portability fiddles */
00024 #if STATFS_IN_SYS_STATVFS
00025 # include <sys/statvfs.h>
00026 #else
00027 # if STATFS_IN_SYS_VFS
00028 #  include <sys/vfs.h>
00029 # else
00030 #  if STATFS_IN_SYS_MOUNT
00031 #   include <sys/mount.h>
00032 #  else
00033 #   if STATFS_IN_SYS_STATFS
00034 #    include <sys/statfs.h>
00035 #   endif
00036 #  endif
00037 # endif
00038 #endif
00039 
00040 #include "debug.h"
00041 
00042 #define MNT_DEV_PREFIX  "/mnt/"
00043 #define MNT_DEV_PREFIX_LENGTH   (sizeof(MNT_DEV_PREFIX)-1)
00044 
00045 /*@access FD_t@*/               /* XXX compared with NULL */
00046 /*@access Header@*/             /* XXX compared with NULL */
00047 /*@access dbiIndexSet@*/
00048 /*@access rpmdb@*/
00049 /*@access rpmTransactionSet@*/
00050 /*@access TFI_t@*/
00051 /*@access PSM_t@*/
00052 /*@access rpmProblemSet@*/
00053 /*@access rpmProblem@*/
00054 
00055 struct diskspaceInfo {
00056     dev_t dev;                  
00057     signed long bneeded;        
00058     signed long ineeded;        
00059     int bsize;                  
00060     signed long bavail;         
00061     signed long iavail;         
00062 };
00063 
00064 /* Adjust for root only reserved space. On linux e2fs, this is 5%. */
00065 #define adj_fs_blocks(_nb)      (((_nb) * 21) / 20)
00066 
00067 /* argon thought a shift optimization here was a waste of time...  he's
00068    probably right :-( */
00069 #define BLOCK_ROUND(size, block) (((size) + (block) - 1) / (block))
00070 
00071 #define XSTRCMP(a, b) ((!(a) && !(b)) || ((a) && (b) && !strcmp((a), (b))))
00072 
00073 static /*@null@*/ void * freeFl(rpmTransactionSet ts,
00074                 /*@only@*/ /*@null@*/ TFI_t flList)
00075         /*@*/
00076 {
00077     if (flList) {
00078         TFI_t fi;
00079         int oc;
00080 
00081         /*@-usereleased@*/
00082         for (oc = 0, fi = flList; oc < ts->orderCount; oc++, fi++)
00083             freeFi(fi);
00084         flList = _free(flList);
00085         /*@=usereleased@*/
00086     }
00087     return NULL;
00088 }
00089 
00090 void rpmtransSetScriptFd(rpmTransactionSet ts, FD_t fd)
00091 {
00092     ts->scriptFd = (fd ? fdLink(fd, "rpmtransSetScriptFd") : NULL);
00093 }
00094 
00095 int rpmtransGetKeys(const rpmTransactionSet ts, const void *** ep, int * nep)
00096 {
00097     int rc = 0;
00098 
00099     if (nep) *nep = ts->orderCount;
00100     if (ep) {
00101         const void ** e;
00102         int oc;
00103 
00104         *ep = e = xmalloc(ts->orderCount * sizeof(*e));
00105         for (oc = 0; oc < ts->orderCount; oc++, e++) {
00106             switch (ts->order[oc].type) {
00107             case TR_ADDED:
00108                 if (ts->addedPackages.list) {
00109                     struct availablePackage * alp;
00110                     alp = ts->addedPackages.list + ts->order[oc].u.addedIndex;
00111                     *e = alp->key;
00112                     break;
00113                 }
00114                 /*@fallthrough@*/
00115             default:
00116             case TR_REMOVED:
00117                 /*@-mods@*/     /* FIX: double indirection. */
00118                 *e = NULL;
00119                 /*@=mods@*/
00120                 break;
00121             }
00122         }
00123     }
00124     return rc;
00125 }
00126 
00127 static rpmProblemSet psCreate(void)
00128         /*@*/
00129 {
00130     rpmProblemSet probs;
00131 
00132     probs = xmalloc(sizeof(*probs));    /* XXX memory leak */
00133     probs->numProblems = probs->numProblemsAlloced = 0;
00134     probs->probs = NULL;
00135 
00136     return probs;
00137 }
00138 
00139 static void psAppend(rpmProblemSet probs, rpmProblemType type,
00140                 const struct availablePackage * alp,
00141                 const char * dn, const char *bn,
00142                 Header altH, unsigned long ulong1)
00143         /*@modifies probs, alp @*/
00144 {
00145     rpmProblem p;
00146     char *t;
00147 
00148     if (probs->numProblems == probs->numProblemsAlloced) {
00149         if (probs->numProblemsAlloced)
00150             probs->numProblemsAlloced *= 2;
00151         else
00152             probs->numProblemsAlloced = 2;
00153         probs->probs = xrealloc(probs->probs,
00154                         probs->numProblemsAlloced * sizeof(*probs->probs));
00155     }
00156 
00157     p = probs->probs + probs->numProblems++;
00158     p->type = type;
00159     /*@-assignexpose@*/
00160     p->key = alp->key;
00161     /*@=assignexpose@*/
00162     p->ulong1 = ulong1;
00163     p->ignoreProblem = 0;
00164 
00165     if (dn || bn) {
00166         p->str1 =
00167             t = xmalloc((dn ? strlen(dn) : 0) + (bn ? strlen(bn) : 0) + 1);
00168         if (dn) t = stpcpy(t, dn);
00169         if (bn) t = stpcpy(t, bn);
00170     } else
00171         p->str1 = NULL;
00172 
00173     if (alp) {
00174         p->h = headerLink(alp->h);
00175         p->pkgNEVR =
00176             t = xmalloc(strlen(alp->name) +
00177                         strlen(alp->version) +
00178                         strlen(alp->release) + sizeof("--"));
00179         t = stpcpy(t, alp->name);
00180         t = stpcpy(t, "-");
00181         t = stpcpy(t, alp->version);
00182         t = stpcpy(t, "-");
00183         t = stpcpy(t, alp->release);
00184     } else {
00185         p->h = NULL;
00186         p->pkgNEVR = NULL;
00187     }
00188 
00189     if (altH) {
00190         const char * n, * v, * r;
00191         (void) headerNVR(altH, &n, &v, &r);
00192         p->altNEVR =
00193             t = xmalloc(strlen(n) + strlen(v) + strlen(r) + sizeof("--"));
00194         t = stpcpy(t, n);
00195         t = stpcpy(t, "-");
00196         t = stpcpy(t, v);
00197         t = stpcpy(t, "-");
00198         t = stpcpy(t, r);
00199     } else
00200         p->altNEVR = NULL;
00201 }
00202 
00203 static int archOkay(Header h)
00204         /*@*/
00205 {
00206     void * pkgArch;
00207     int type, count;
00208 
00209     /* make sure we're trying to install this on the proper architecture */
00210     (void) headerGetEntry(h, RPMTAG_ARCH, &type, (void **) &pkgArch, &count);
00211 #ifndef DYING
00212     if (type == RPM_INT8_TYPE) {
00213         int_8 * pkgArchNum;
00214         int archNum;
00215 
00216         /* old arch handling */
00217         rpmGetArchInfo(NULL, &archNum);
00218         pkgArchNum = pkgArch;
00219         if (archNum != *pkgArchNum) {
00220             return 0;
00221         }
00222     } else
00223 #endif
00224     {
00225         /* new arch handling */
00226         if (!rpmMachineScore(RPM_MACHTABLE_INSTARCH, pkgArch)) {
00227             return 0;
00228         }
00229     }
00230 
00231     return 1;
00232 }
00233 
00234 static int osOkay(Header h)
00235         /*@*/
00236 {
00237     void * pkgOs;
00238     int type, count;
00239 
00240     /* make sure we're trying to install this on the proper os */
00241     (void) headerGetEntry(h, RPMTAG_OS, &type, (void **) &pkgOs, &count);
00242 #ifndef DYING
00243     if (type == RPM_INT8_TYPE) {
00244         /* v1 packages and v2 packages both used improper OS numbers, so just
00245            deal with it hope things work */
00246         return 1;
00247     } else
00248 #endif
00249     {
00250         /* new os handling */
00251         if (!rpmMachineScore(RPM_MACHTABLE_INSTOS, pkgOs)) {
00252             return 0;
00253         }
00254     }
00255 
00256     return 1;
00257 }
00258 
00259 void rpmProblemSetFree(rpmProblemSet probs)
00260 {
00261     int i;
00262 
00263     for (i = 0; i < probs->numProblems; i++) {
00264         rpmProblem p = probs->probs + i;
00265         p->h = headerFree(p->h);
00266         p->pkgNEVR = _free(p->pkgNEVR);
00267         p->altNEVR = _free(p->altNEVR);
00268         p->str1 = _free(p->str1);
00269     }
00270     free(probs);
00271 }
00272 
00273 static /*@observer@*/ const char *const ftstring (fileTypes ft)
00274         /*@*/
00275 {
00276     switch (ft) {
00277     case XDIR:  return "directory";
00278     case CDEV:  return "char dev";
00279     case BDEV:  return "block dev";
00280     case LINK:  return "link";
00281     case SOCK:  return "sock";
00282     case PIPE:  return "fifo/pipe";
00283     case REG:   return "file";
00284     default:    return "unknown file type";
00285     }
00286     /*@notreached@*/
00287 }
00288 
00289 static fileTypes whatis(uint_16 mode)
00290         /*@*/
00291 {
00292     if (S_ISDIR(mode))  return XDIR;
00293     if (S_ISCHR(mode))  return CDEV;
00294     if (S_ISBLK(mode))  return BDEV;
00295     if (S_ISLNK(mode))  return LINK;
00296     if (S_ISSOCK(mode)) return SOCK;
00297     if (S_ISFIFO(mode)) return PIPE;
00298     return REG;
00299 }
00300 
00301 #define alloca_strdup(_s)       strcpy(alloca(strlen(_s)+1), (_s))
00302 
00313 static Header relocateFileList(const rpmTransactionSet ts, TFI_t fi,
00314                 struct availablePackage * alp,
00315                 Header origH, fileAction * actions)
00316         /*@modifies ts, fi, alp, origH, actions @*/
00317 {
00318     HGE_t hge = fi->hge;
00319     HAE_t hae = fi->hae;
00320     HME_t hme = fi->hme;
00321     HFD_t hfd = (fi->hfd ? fi->hfd : headerFreeData);
00322     static int _printed = 0;
00323     rpmProblemSet probs = ts->probs;
00324     int allowBadRelocate = (ts->ignoreSet & RPMPROB_FILTER_FORCERELOCATE);
00325     rpmRelocation * rawRelocations = alp->relocs;
00326     rpmRelocation * relocations = NULL;
00327     int numRelocations;
00328     const char ** validRelocations;
00329     rpmTagType validType;
00330     int numValid;
00331     const char ** baseNames;
00332     const char ** dirNames;
00333     int_32 * dirIndexes;
00334     int_32 * newDirIndexes;
00335     int_32 fileCount;
00336     int_32 dirCount;
00337     uint_32 * fFlags = NULL;
00338     uint_16 * fModes = NULL;
00339     char * skipDirList;
00340     Header h;
00341     int nrelocated = 0;
00342     int fileAlloced = 0;
00343     char * fn = NULL;
00344     int haveRelocatedFile = 0;
00345     int reldel = 0;
00346     int len;
00347     int i, j;
00348 
00349     if (!hge(origH, RPMTAG_PREFIXES, &validType,
00350                         (void **) &validRelocations, &numValid))
00351         numValid = 0;
00352 
00353     numRelocations = 0;
00354     if (rawRelocations)
00355         while (rawRelocations[numRelocations].newPath ||
00356                rawRelocations[numRelocations].oldPath)
00357             numRelocations++;
00358 
00359     /*
00360      * If no relocations are specified (usually the case), then return the
00361      * original header. If there are prefixes, however, then INSTPREFIXES
00362      * should be added, but, since relocateFileList() can be called more
00363      * than once for the same header, don't bother if already present.
00364      */
00365     if (rawRelocations == NULL || numRelocations == 0) {
00366         if (numValid) {
00367             if (!headerIsEntry(origH, RPMTAG_INSTPREFIXES))
00368                 (void) hae(origH, RPMTAG_INSTPREFIXES,
00369                         validType, validRelocations, numValid);
00370             validRelocations = hfd(validRelocations, validType);
00371         }
00372         /* XXX FIXME multilib file actions need to be checked. */
00373         return headerLink(origH);
00374     }
00375 
00376 #ifdef DYING
00377     h = headerCopy(origH);
00378 #else
00379     h = headerLink(origH);
00380 #endif
00381 
00382     relocations = alloca(sizeof(*relocations) * numRelocations);
00383 
00384     /* Build sorted relocation list from raw relocations. */
00385     for (i = 0; i < numRelocations; i++) {
00386         char * t;
00387 
00388         /*
00389          * Default relocations (oldPath == NULL) are handled in the UI,
00390          * not rpmlib.
00391          */
00392         if (rawRelocations[i].oldPath == NULL) continue; /* XXX can't happen */
00393 
00394         /* FIXME: Trailing /'s will confuse us greatly. Internal ones will 
00395            too, but those are more trouble to fix up. :-( */
00396         t = alloca_strdup(rawRelocations[i].oldPath);
00397         relocations[i].oldPath = (t[0] == '/' && t[1] == '\0')
00398             ? t
00399             : stripTrailingChar(t, '/');
00400 
00401         /* An old path w/o a new path is valid, and indicates exclusion */
00402         if (rawRelocations[i].newPath) {
00403             int del;
00404 
00405             t = alloca_strdup(rawRelocations[i].newPath);
00406             relocations[i].newPath = (t[0] == '/' && t[1] == '\0')
00407                 ? t
00408                 : stripTrailingChar(t, '/');
00409 
00410             /*@-nullpass@*/     /* FIX:  relocations[i].oldPath == NULL */
00411             /* Verify that the relocation's old path is in the header. */
00412             for (j = 0; j < numValid; j++)
00413                 if (!strcmp(validRelocations[j], relocations[i].oldPath))
00414                     /*@innerbreak@*/ break;
00415             /* XXX actions check prevents problem from being appended twice. */
00416             if (j == numValid && !allowBadRelocate && actions)
00417                 psAppend(probs, RPMPROB_BADRELOCATE, alp,
00418                          relocations[i].oldPath, NULL, NULL, 0);
00419             del =
00420                 strlen(relocations[i].newPath) - strlen(relocations[i].oldPath);
00421             /*@=nullpass@*/
00422 
00423             if (del > reldel)
00424                 reldel = del;
00425         } else {
00426             relocations[i].newPath = NULL;
00427         }
00428     }
00429 
00430     /* stupid bubble sort, but it's probably faster here */
00431     for (i = 0; i < numRelocations; i++) {
00432         int madeSwap;
00433         madeSwap = 0;
00434         for (j = 1; j < numRelocations; j++) {
00435             rpmRelocation tmpReloc;
00436             if (relocations[j - 1].oldPath == NULL || /* XXX can't happen */
00437                 relocations[j    ].oldPath == NULL || /* XXX can't happen */
00438         strcmp(relocations[j - 1].oldPath, relocations[j].oldPath) <= 0)
00439                 continue;
00440             tmpReloc = relocations[j - 1];
00441             relocations[j - 1] = relocations[j];
00442             relocations[j] = tmpReloc;
00443             madeSwap = 1;
00444         }
00445         if (!madeSwap) break;
00446     }
00447 
00448     if (!_printed) {
00449         _printed = 1;
00450         rpmMessage(RPMMESS_DEBUG, _("========== relocations\n"));
00451         for (i = 0; i < numRelocations; i++) {
00452             if (relocations[i].oldPath == NULL) continue; /* XXX can't happen */
00453             if (relocations[i].newPath == NULL)
00454                 rpmMessage(RPMMESS_DEBUG, _("%5d exclude  %s\n"),
00455                         i, relocations[i].oldPath);
00456             else
00457                 rpmMessage(RPMMESS_DEBUG, _("%5d relocate %s -> %s\n"),
00458                         i, relocations[i].oldPath, relocations[i].newPath);
00459         }
00460     }
00461 
00462     /* Add relocation values to the header */
00463     if (numValid) {
00464         const char ** actualRelocations;
00465         int numActual;
00466 
00467         actualRelocations = xmalloc(numValid * sizeof(*actualRelocations));
00468         numActual = 0;
00469         for (i = 0; i < numValid; i++) {
00470             for (j = 0; j < numRelocations; j++) {
00471                 if (relocations[j].oldPath == NULL || /* XXX can't happen */
00472                     strcmp(validRelocations[i], relocations[j].oldPath))
00473                     continue;
00474                 /* On install, a relocate to NULL means skip the path. */
00475                 if (relocations[j].newPath) {
00476                     actualRelocations[numActual] = relocations[j].newPath;
00477                     numActual++;
00478                 }
00479                 /*@innerbreak@*/ break;
00480             }
00481             if (j == numRelocations) {
00482                 actualRelocations[numActual] = validRelocations[i];
00483                 numActual++;
00484             }
00485         }
00486 
00487         if (numActual)
00488             (void) hae(h, RPMTAG_INSTPREFIXES, RPM_STRING_ARRAY_TYPE,
00489                        (void **) actualRelocations, numActual);
00490 
00491         actualRelocations = _free(actualRelocations);
00492         validRelocations = hfd(validRelocations, validType);
00493     }
00494 
00495     (void) hge(h, RPMTAG_BASENAMES, NULL, (void **) &baseNames, &fileCount);
00496     (void) hge(h, RPMTAG_DIRINDEXES, NULL, (void **) &dirIndexes, NULL);
00497     (void) hge(h, RPMTAG_DIRNAMES, NULL, (void **) &dirNames, &dirCount);
00498     (void) hge(h, RPMTAG_FILEFLAGS, NULL, (void **) &fFlags, NULL);
00499     (void) hge(h, RPMTAG_FILEMODES, NULL, (void **) &fModes, NULL);
00500 
00501     skipDirList = alloca(dirCount * sizeof(*skipDirList));
00502     memset(skipDirList, 0, dirCount * sizeof(*skipDirList));
00503 
00504     newDirIndexes = alloca(sizeof(*newDirIndexes) * fileCount);
00505     memcpy(newDirIndexes, dirIndexes, sizeof(*newDirIndexes) * fileCount);
00506     dirIndexes = newDirIndexes;
00507 
00508     /*
00509      * For all relocations, we go through sorted file/relocation lists 
00510      * backwards so that /usr/local relocations take precedence over /usr 
00511      * ones.
00512      */
00513 
00514     /* Relocate individual paths. */
00515 
00516     for (i = fileCount - 1; i >= 0; i--) {
00517         fileTypes ft;
00518         int fnlen;
00519 
00520         /*
00521          * If only adding libraries of different arch into an already
00522          * installed package, skip all other files.
00523          */
00524         if (alp->multiLib && !isFileMULTILIB((fFlags[i]))) {
00525             if (actions) {
00526                 actions[i] = FA_SKIPMULTILIB;
00527                 rpmMessage(RPMMESS_DEBUG, _("excluding multilib path %s%s\n"), 
00528                         dirNames[dirIndexes[i]], baseNames[i]);
00529             }
00530             continue;
00531         }
00532 
00533         len = reldel +
00534                 strlen(dirNames[dirIndexes[i]]) + strlen(baseNames[i]) + 1;
00535         if (len >= fileAlloced) {
00536             fileAlloced = len * 2;
00537             fn = xrealloc(fn, fileAlloced);
00538         }
00539         *fn = '\0';
00540         fnlen = stpcpy( stpcpy(fn, dirNames[dirIndexes[i]]), baseNames[i]) - fn;
00541 
00542         /*
00543          * See if this file path needs relocating.
00544          */
00545         /*
00546          * XXX FIXME: Would a bsearch of the (already sorted) 
00547          * relocation list be a good idea?
00548          */
00549         for (j = numRelocations - 1; j >= 0; j--) {
00550             if (relocations[j].oldPath == NULL) continue; /* XXX can't happen */
00551             len = strcmp(relocations[j].oldPath, "/")
00552                 ? strlen(relocations[j].oldPath)
00553                 : 0;
00554 
00555             if (fnlen < len)
00556                 continue;
00557             /*
00558              * Only subdirectories or complete file paths may be relocated. We
00559              * don't check for '\0' as our directory names all end in '/'.
00560              */
00561             if (!(fn[len] == '/' || fnlen == len))
00562                 continue;
00563 
00564             if (strncmp(relocations[j].oldPath, fn, len))
00565                 continue;
00566             /*@innerbreak@*/ break;
00567         }
00568         if (j < 0) continue;
00569 
00570         ft = whatis(fModes[i]);
00571 
00572         /* On install, a relocate to NULL means skip the path. */
00573         if (relocations[j].newPath == NULL) {
00574             if (ft == XDIR) {
00575                 /* Start with the parent, looking for directory to exclude. */
00576                 for (j = dirIndexes[i]; j < dirCount; j++) {
00577                     len = strlen(dirNames[j]) - 1;
00578                     while (len > 0 && dirNames[j][len-1] == '/') len--;
00579                     if (fnlen != len)
00580                         continue;
00581                     if (strncmp(fn, dirNames[j], fnlen))
00582                         continue;
00583                     /*@innerbreak@*/ break;
00584                 }
00585                 if (j < dirCount)
00586                     skipDirList[j] = 1;
00587             }
00588             if (actions) {
00589                 actions[i] = FA_SKIPNSTATE;
00590                 rpmMessage(RPMMESS_DEBUG, _("excluding %s %s\n"),
00591                         ftstring(ft), fn);
00592             }
00593             continue;
00594         }
00595 
00596         /* Relocation on full paths only, please. */
00597         if (fnlen != len) continue;
00598 
00599         if (actions)
00600             rpmMessage(RPMMESS_DEBUG, _("relocating %s to %s\n"),
00601                     fn, relocations[j].newPath);
00602         nrelocated++;
00603 
00604         strcpy(fn, relocations[j].newPath);
00605         {   char * te = strrchr(fn, '/');
00606             if (te) {
00607                 if (te > fn) te++;      /* root is special */
00608                 fnlen = te - fn;
00609             } else
00610                 te = fn + strlen(fn);
00611             /*@-nullpass -nullderef@*/  /* LCL: te != NULL here. */
00612             if (strcmp(baseNames[i], te)) /* basename changed too? */
00613                 baseNames[i] = alloca_strdup(te);
00614             *te = '\0';                 /* terminate new directory name */
00615             /*@=nullpass =nullderef@*/
00616         }
00617 
00618         /* Does this directory already exist in the directory list? */
00619         for (j = 0; j < dirCount; j++) {
00620             if (fnlen != strlen(dirNames[j]))
00621                 continue;
00622             if (strncmp(fn, dirNames[j], fnlen))
00623                 continue;
00624             /*@innerbreak@*/ break;
00625         }
00626         
00627         if (j < dirCount) {
00628             dirIndexes[i] = j;
00629             continue;
00630         }
00631 
00632         /* Creating new paths is a pita */
00633         if (!haveRelocatedFile) {
00634             const char ** newDirList;
00635 
00636             haveRelocatedFile = 1;
00637             newDirList = xmalloc((dirCount + 1) * sizeof(*newDirList));
00638             for (j = 0; j < dirCount; j++)
00639                 newDirList[j] = alloca_strdup(dirNames[j]);
00640             dirNames = hfd(dirNames, RPM_STRING_ARRAY_TYPE);
00641             dirNames = newDirList;
00642         } else {
00643             dirNames = xrealloc(dirNames, 
00644                                sizeof(*dirNames) * (dirCount + 1));
00645         }
00646 
00647         dirNames[dirCount] = alloca_strdup(fn);
00648         dirIndexes[i] = dirCount;
00649         dirCount++;
00650     }
00651 
00652     /* Finish off by relocating directories. */
00653     for (i = dirCount - 1; i >= 0; i--) {
00654         for (j = numRelocations - 1; j >= 0; j--) {
00655 
00656             if (relocations[j].oldPath == NULL) continue; /* XXX can't happen */
00657             len = strcmp(relocations[j].oldPath, "/")
00658                 ? strlen(relocations[j].oldPath)
00659                 : 0;
00660 
00661             if (len && strncmp(relocations[j].oldPath, dirNames[i], len))
00662                 continue;
00663 
00664             /*
00665              * Only subdirectories or complete file paths may be relocated. We
00666              * don't check for '\0' as our directory names all end in '/'.
00667              */
00668             if (dirNames[i][len] != '/')
00669                 continue;
00670 
00671             if (relocations[j].newPath) { /* Relocate the path */
00672                 const char * s = relocations[j].newPath;
00673                 char * t = alloca(strlen(s) + strlen(dirNames[i]) - len + 1);
00674 
00675                 (void) stpcpy( stpcpy(t, s) , dirNames[i] + len);
00676                 if (actions)
00677                     rpmMessage(RPMMESS_DEBUG,
00678                         _("relocating directory %s to %s\n"), dirNames[i], t);
00679                 dirNames[i] = t;
00680                 nrelocated++;
00681             }
00682         }
00683     }
00684 
00685     /* Save original filenames in header and replace (relocated) filenames. */
00686     if (nrelocated) {
00687         int c;
00688         void * p;
00689         rpmTagType t;
00690 
00691         p = NULL;
00692         (void) hge(h, RPMTAG_BASENAMES, &t, &p, &c);
00693         (void) hae(h, RPMTAG_ORIGBASENAMES, t, p, c);
00694         p = hfd(p, t);
00695 
00696         p = NULL;
00697         (void) hge(h, RPMTAG_DIRNAMES, &t, &p, &c);
00698         (void) hae(h, RPMTAG_ORIGDIRNAMES, t, p, c);
00699         p = hfd(p, t);
00700 
00701         p = NULL;
00702         (void) hge(h, RPMTAG_DIRINDEXES, &t, &p, &c);
00703         (void) hae(h, RPMTAG_ORIGDIRINDEXES, t, p, c);
00704         p = hfd(p, t);
00705 
00706         (void) hme(h, RPMTAG_BASENAMES, RPM_STRING_ARRAY_TYPE,
00707                           baseNames, fileCount);
00708         fi->bnl = hfd(fi->bnl, RPM_STRING_ARRAY_TYPE);
00709         (void) hge(h, RPMTAG_BASENAMES, NULL, (void **) &fi->bnl, &fi->fc);
00710 
00711         (void) hme(h, RPMTAG_DIRNAMES, RPM_STRING_ARRAY_TYPE,
00712                           dirNames, dirCount);
00713         fi->dnl = hfd(fi->dnl, RPM_STRING_ARRAY_TYPE);
00714         (void) hge(h, RPMTAG_DIRNAMES, NULL, (void **) &fi->dnl, &fi->dc);
00715 
00716         (void) hme(h, RPMTAG_DIRINDEXES, RPM_INT32_TYPE,
00717                           dirIndexes, fileCount);
00718         (void) hge(h, RPMTAG_DIRINDEXES, NULL, (void **) &fi->dil, NULL);
00719     }
00720 
00721     baseNames = hfd(baseNames, RPM_STRING_ARRAY_TYPE);
00722     dirNames = hfd(dirNames, RPM_STRING_ARRAY_TYPE);
00723     fn = _free(fn);
00724 
00725     return h;
00726 }
00727 
00728 /*
00729  * As the problem sets are generated in an order solely dependent
00730  * on the ordering of the packages in the transaction, and that
00731  * ordering can't be changed, the problem sets must be parallel to
00732  * one another. Additionally, the filter set must be a subset of the
00733  * target set, given the operations available on transaction set.
00734  * This is good, as it lets us perform this trim in linear time, rather
00735  * then logarithmic or quadratic.
00736  */
00737 static int psTrim(rpmProblemSet filter, rpmProblemSet target)
00738         /*@modifies target @*/
00739 {
00740     rpmProblem f = filter->probs;
00741     rpmProblem t = target->probs;
00742     int gotProblems = 0;
00743 
00744     while ((f - filter->probs) < filter->numProblems) {
00745         if (!f->ignoreProblem) {
00746             f++;
00747             continue;
00748         }
00749         while ((t - target->probs) < target->numProblems) {
00750             /*@-nullpass@*/     /* LCL: looks good to me */
00751             if (f->h == t->h && f->type == t->type && t->key == f->key &&
00752                      XSTRCMP(f->str1, t->str1))
00753                 /*@innerbreak@*/ break;
00754             /*@=nullpass@*/
00755             t++;
00756             gotProblems = 1;
00757         }
00758 
00759         if ((t - target->probs) == target->numProblems) {
00760             /* this can't happen ;-) lets be sane if it doesn though */
00761             break;
00762         }
00763 
00764         t->ignoreProblem = f->ignoreProblem;
00765         t++, f++;
00766     }
00767 
00768     if ((t - target->probs) < target->numProblems)
00769         gotProblems = 1;
00770 
00771     return gotProblems;
00772 }
00773 
00774 static int sharedCmp(const void * one, const void * two)
00775         /*@*/
00776 {
00777     const struct sharedFileInfo * a = one;
00778     const struct sharedFileInfo * b = two;
00779 
00780     if (a->otherPkg < b->otherPkg)
00781         return -1;
00782     else if (a->otherPkg > b->otherPkg)
00783         return 1;
00784 
00785     return 0;
00786 }
00787 
00788 static fileAction decideFileFate(const char * dirName,
00789                         const char * baseName, short dbMode,
00790                         const char * dbMd5, const char * dbLink, short newMode,
00791                         const char * newMd5, const char * newLink, int newFlags,
00792                         rpmtransFlags transFlags)
00793         /*@*/
00794 {
00795     char buffer[1024];
00796     const char * dbAttr, * newAttr;
00797     fileTypes dbWhat, newWhat, diskWhat;
00798     struct stat sb;
00799     int i, rc;
00800     int save = (newFlags & RPMFILE_NOREPLACE) ? FA_ALTNAME : FA_SAVE;
00801     char * filespec = alloca(strlen(dirName) + strlen(baseName) + 1);
00802 
00803     (void) stpcpy( stpcpy(filespec, dirName), baseName);
00804 
00805     if (lstat(filespec, &sb)) {
00806         /*
00807          * The file doesn't exist on the disk. Create it unless the new
00808          * package has marked it as missingok, or allfiles is requested.
00809          */
00810         if (!(transFlags & RPMTRANS_FLAG_ALLFILES) &&
00811            (newFlags & RPMFILE_MISSINGOK)) {
00812             rpmMessage(RPMMESS_DEBUG, _("%s skipped due to missingok flag\n"),
00813                         filespec);
00814             return FA_SKIP;
00815         } else {
00816             return FA_CREATE;
00817         }
00818     }
00819 
00820     diskWhat = whatis(sb.st_mode);
00821     dbWhat = whatis(dbMode);
00822     newWhat = whatis(newMode);
00823 
00824     /* RPM >= 2.3.10 shouldn't create config directories -- we'll ignore
00825        them in older packages as well */
00826     if (newWhat == XDIR) {
00827         return FA_CREATE;
00828     }
00829 
00830     if (diskWhat != newWhat) {
00831         return save;
00832     } else if (newWhat != dbWhat && diskWhat != dbWhat) {
00833         return save;
00834     } else if (dbWhat != newWhat) {
00835         return FA_CREATE;
00836     } else if (dbWhat != LINK && dbWhat != REG) {
00837         return FA_CREATE;
00838     }
00839 
00840     if (dbWhat == REG) {
00841         rc = domd5(filespec, buffer, 1);
00842         if (rc) {
00843             /* assume the file has been removed, don't freak */
00844             return FA_CREATE;
00845         }
00846         dbAttr = dbMd5;
00847         newAttr = newMd5;
00848     } else /* dbWhat == LINK */ {
00849         memset(buffer, 0, sizeof(buffer));
00850         i = readlink(filespec, buffer, sizeof(buffer) - 1);
00851         if (i == -1) {
00852             /* assume the file has been removed, don't freak */
00853             return FA_CREATE;
00854         }
00855         dbAttr = dbLink;
00856         newAttr = newLink;
00857      }
00858 
00859     /* this order matters - we'd prefer to CREATE the file if at all
00860        possible in case something else (like the timestamp) has changed */
00861 
00862     if (!strcmp(dbAttr, buffer)) {
00863         /* this config file has never been modified, so just replace it */
00864         return FA_CREATE;
00865     }
00866 
00867     if (!strcmp(dbAttr, newAttr)) {
00868         /* this file is the same in all versions of this package */
00869         return FA_SKIP;
00870     }
00871 
00872     /*
00873      * The config file on the disk has been modified, but
00874      * the ones in the two packages are different. It would
00875      * be nice if RPM was smart enough to at least try and
00876      * merge the difference ala CVS, but...
00877      */
00878     return save;
00879 }
00880 
00881 static int filecmp(short mode1, const char * md51, const char * link1,
00882                    short mode2, const char * md52, const char * link2)
00883         /*@*/
00884 {
00885     fileTypes what1 = whatis(mode1);
00886     fileTypes what2 = whatis(mode2);
00887 
00888     if (what1 != what2) return 1;
00889 
00890     if (what1 == LINK)
00891         return strcmp(link1, link2);
00892     else if (what1 == REG)
00893         return strcmp(md51, md52);
00894 
00895     return 0;
00896 }
00897 
00898 static int handleInstInstalledFiles(TFI_t fi, /*@null@*/ rpmdb db,
00899                                     struct sharedFileInfo * shared,
00900                                     int sharedCount, int reportConflicts,
00901                                     rpmProblemSet probs,
00902                                     rpmtransFlags transFlags)
00903         /*@modifies fi, db, probs @*/
00904 {
00905     HGE_t hge = fi->hge;
00906     HFD_t hfd = (fi->hfd ? fi->hfd : headerFreeData);
00907     rpmTagType oltype, omtype;
00908     Header h;
00909     int i;
00910     const char ** otherMd5s;
00911     const char ** otherLinks;
00912     const char * otherStates;
00913     uint_32 * otherFlags;
00914     uint_32 * otherSizes;
00915     uint_16 * otherModes;
00916     int numReplaced = 0;
00917 
00918     rpmdbMatchIterator mi;
00919 
00920     mi = rpmdbInitIterator(db, RPMDBI_PACKAGES, &shared->otherPkg, sizeof(shared->otherPkg));
00921     h = rpmdbNextIterator(mi);
00922     if (h == NULL) {
00923         mi = rpmdbFreeIterator(mi);
00924         return 1;
00925     }
00926 
00927     (void) hge(h, RPMTAG_FILEMD5S, &omtype, (void **) &otherMd5s, NULL);
00928     (void) hge(h, RPMTAG_FILELINKTOS, &oltype, (void **) &otherLinks, NULL);
00929     (void) hge(h, RPMTAG_FILESTATES, NULL, (void **) &otherStates, NULL);
00930     (void) hge(h, RPMTAG_FILEMODES, NULL, (void **) &otherModes, NULL);
00931     (void) hge(h, RPMTAG_FILEFLAGS, NULL, (void **) &otherFlags, NULL);
00932     (void) hge(h, RPMTAG_FILESIZES, NULL, (void **) &otherSizes, NULL);
00933 
00934     fi->replaced = xmalloc(sharedCount * sizeof(*fi->replaced));
00935 
00936     for (i = 0; i < sharedCount; i++, shared++) {
00937         int otherFileNum, fileNum;
00938         otherFileNum = shared->otherFileNum;
00939         fileNum = shared->pkgFileNum;
00940 
00941         /* XXX another tedious segfault, assume file state normal. */
00942         if (otherStates && otherStates[otherFileNum] != RPMFILE_STATE_NORMAL)
00943             continue;
00944 
00945         if (XFA_SKIPPING(fi->actions[fileNum]))
00946             continue;
00947 
00948         if (filecmp(otherModes[otherFileNum],
00949                         otherMd5s[otherFileNum],
00950                         otherLinks[otherFileNum],
00951                         fi->fmodes[fileNum],
00952                         fi->fmd5s[fileNum],
00953                         fi->flinks[fileNum])) {
00954             if (reportConflicts)
00955                 psAppend(probs, RPMPROB_FILE_CONFLICT, fi->ap,
00956                         fi->dnl[fi->dil[fileNum]], fi->bnl[fileNum], h, 0);
00957             if (!(otherFlags[otherFileNum] | fi->fflags[fileNum])
00958                         & RPMFILE_CONFIG) {
00959                 /*@-assignexpose@*/
00960                 if (!shared->isRemoved)
00961                     fi->replaced[numReplaced++] = *shared;
00962                 /*@=assignexpose@*/
00963             }
00964         }
00965 
00966         if ((otherFlags[otherFileNum] | fi->fflags[fileNum]) & RPMFILE_CONFIG) {
00967             fi->actions[fileNum] = decideFileFate(
00968                         fi->dnl[fi->dil[fileNum]],
00969                         fi->bnl[fileNum],
00970                         otherModes[otherFileNum],
00971                         otherMd5s[otherFileNum],
00972                         otherLinks[otherFileNum],
00973                         fi->fmodes[fileNum],
00974                         fi->fmd5s[fileNum],
00975                         fi->flinks[fileNum],
00976                         fi->fflags[fileNum],
00977                         transFlags);
00978         }
00979 
00980         fi->replacedSizes[fileNum] = otherSizes[otherFileNum];
00981     }
00982 
00983     otherMd5s = hfd(otherMd5s, omtype);
00984     otherLinks = hfd(otherLinks, oltype);
00985     mi = rpmdbFreeIterator(mi);
00986 
00987     fi->replaced = xrealloc(fi->replaced,
00988                            sizeof(*fi->replaced) * (numReplaced + 1));
00989     fi->replaced[numReplaced].otherPkg = 0;
00990 
00991     return 0;
00992 }
00993 
00994 static int handleRmvdInstalledFiles(TFI_t fi, /*@null@*/ rpmdb db,
00995                                     struct sharedFileInfo * shared,
00996                                     int sharedCount)
00997         /*@modifies fi, db @*/
00998 {
00999     HGE_t hge = fi->hge;
01000     Header h;
01001     const char * otherStates;
01002     int i;
01003    
01004     rpmdbMatchIterator mi;
01005 
01006     mi = rpmdbInitIterator(db, RPMDBI_PACKAGES,
01007                         &shared->otherPkg, sizeof(shared->otherPkg));
01008     h = rpmdbNextIterator(mi);
01009     if (h == NULL) {
01010         mi = rpmdbFreeIterator(mi);
01011         return 1;
01012     }
01013 
01014     (void) hge(h, RPMTAG_FILESTATES, NULL, (void **) &otherStates, NULL);
01015 
01016     for (i = 0; i < sharedCount; i++, shared++) {
01017         int otherFileNum, fileNum;
01018         otherFileNum = shared->otherFileNum;
01019         fileNum = shared->pkgFileNum;
01020 
01021         if (otherStates[otherFileNum] != RPMFILE_STATE_NORMAL)
01022             continue;
01023 
01024         fi->actions[fileNum] = FA_SKIP;
01025     }
01026 
01027     mi = rpmdbFreeIterator(mi);
01028 
01029     return 0;
01030 }
01031 
01035 static void handleOverlappedFiles(TFI_t fi, hashTable ht,
01036                            rpmProblemSet probs, struct diskspaceInfo * dsl)
01037         /*@modifies fi, probs, dsl @*/
01038 {
01039     int i, j;
01040     struct diskspaceInfo * ds = NULL;
01041     uint_32 fixupSize = 0;
01042     char * filespec = NULL;
01043     int fileSpecAlloced = 0;
01044   
01045     for (i = 0; i < fi->fc; i++) {
01046         int otherPkgNum, otherFileNum;
01047         const TFI_t * recs;
01048         int numRecs;
01049 
01050         if (XFA_SKIPPING(fi->actions[i]))
01051             continue;
01052 
01053         j = strlen(fi->dnl[fi->dil[i]]) + strlen(fi->bnl[i]) + 1;
01054         if (j > fileSpecAlloced) {
01055             fileSpecAlloced = j * 2;
01056             filespec = xrealloc(filespec, fileSpecAlloced);
01057         }
01058 
01059         (void) stpcpy( stpcpy( filespec, fi->dnl[fi->dil[i]]), fi->bnl[i]);
01060 
01061         if (dsl) {
01062             ds = dsl;
01063             while (ds->bsize && ds->dev != fi->fps[i].entry->dev) ds++;
01064             if (!ds->bsize) ds = NULL;
01065             fixupSize = 0;
01066         }
01067 
01068         /*
01069          * Retrieve all records that apply to this file. Note that the
01070          * file info records were built in the same order as the packages
01071          * will be installed and removed so the records for an overlapped
01072          * files will be sorted in exactly the same order.
01073          */
01074         (void) htGetEntry(ht, &fi->fps[i], (const void ***) &recs, &numRecs, NULL);
01075 
01076         /*
01077          * If this package is being added, look only at other packages
01078          * being added -- removed packages dance to a different tune.
01079          * If both this and the other package are being added, overlapped
01080          * files must be identical (or marked as a conflict). The
01081          * disposition of already installed config files leads to
01082          * a small amount of extra complexity.
01083          *
01084          * If this package is being removed, then there are two cases that
01085          * need to be worried about:
01086          * If the other package is being added, then skip any overlapped files
01087          * so that this package removal doesn't nuke the overlapped files
01088          * that were just installed.
01089          * If both this and the other package are being removed, then each
01090          * file removal from preceding packages needs to be skipped so that
01091          * the file removal occurs only on the last occurence of an overlapped
01092          * file in the transaction set.
01093          *
01094          */
01095 
01096         /* Locate this overlapped file in the set of added/removed packages. */
01097         for (j = 0; j < numRecs && recs[j] != fi; j++)
01098             {};
01099 
01100         /* Find what the previous disposition of this file was. */
01101         otherFileNum = -1;                      /* keep gcc quiet */
01102         for (otherPkgNum = j - 1; otherPkgNum >= 0; otherPkgNum--) {
01103             /* Added packages need only look at other added packages. */
01104             if (fi->type == TR_ADDED && recs[otherPkgNum]->type != TR_ADDED)
01105                 continue;
01106 
01107             /* TESTME: there are more efficient searches in the world... */
01108             for (otherFileNum = 0; otherFileNum < recs[otherPkgNum]->fc;
01109                  otherFileNum++) {
01110 
01111                 /* If the addresses are the same, so are the values. */
01112                 if ((fi->fps + i) == (recs[otherPkgNum]->fps + otherFileNum))
01113                     /*@innerbreak@*/ break;
01114 
01115                 /* Otherwise, compare fingerprints by value. */
01116                 /*@-nullpass@*/ /* LCL: looks good to me */
01117                 if (FP_EQUAL(fi->fps[i], recs[otherPkgNum]->fps[otherFileNum]))
01118                     /*@innerbreak@*/ break;
01119                 /*@=nullpass@*/
01120 
01121             }
01122             /* XXX is this test still necessary? */
01123             if (recs[otherPkgNum]->actions[otherFileNum] != FA_UNKNOWN)
01124                 /*@innerbreak@*/ break;
01125         }
01126 
01127         switch (fi->type) {
01128         case TR_ADDED:
01129           { struct stat sb;
01130             if (otherPkgNum < 0) {
01131                 /* XXX is this test still necessary? */
01132                 if (fi->actions[i] != FA_UNKNOWN)
01133                     break;
01134                 if ((fi->fflags[i] & RPMFILE_CONFIG) && 
01135                         !lstat(filespec, &sb)) {
01136                     /* Here is a non-overlapped pre-existing config file. */
01137                     fi->actions[i] = (fi->fflags[i] & RPMFILE_NOREPLACE)
01138                         ? FA_ALTNAME : FA_BACKUP;
01139                 } else {
01140                     fi->actions[i] = FA_CREATE;
01141                 }
01142                 break;
01143             }
01144 
01145             /* Mark added overlapped non-identical files as a conflict. */
01146             if (probs && filecmp(recs[otherPkgNum]->fmodes[otherFileNum],
01147                         recs[otherPkgNum]->fmd5s[otherFileNum],
01148                         recs[otherPkgNum]->flinks[otherFileNum],
01149                         fi->fmodes[i],
01150                         fi->fmd5s[i],
01151                         fi->flinks[i])) {
01152                 psAppend(probs, RPMPROB_NEW_FILE_CONFLICT, fi->ap,
01153                                 filespec, NULL, recs[otherPkgNum]->ap->h, 0);
01154             }
01155 
01156             /* Try to get the disk accounting correct even if a conflict. */
01157             fixupSize = recs[otherPkgNum]->fsizes[otherFileNum];
01158 
01159             if ((fi->fflags[i] & RPMFILE_CONFIG) && !lstat(filespec, &sb)) {
01160                 /* Here is an overlapped  pre-existing config file. */
01161                 fi->actions[i] = (fi->fflags[i] & RPMFILE_NOREPLACE)
01162                         ? FA_ALTNAME : FA_SKIP;
01163             } else {
01164                 fi->actions[i] = FA_CREATE;
01165             }
01166           } break;
01167         case TR_REMOVED:
01168             if (otherPkgNum >= 0) {
01169                 /* Here is an overlapped added file we don't want to nuke. */
01170                 if (recs[otherPkgNum]->actions[otherFileNum] != FA_ERASE) {
01171                     /* On updates, don't remove files. */
01172                     fi->actions[i] = FA_SKIP;
01173                     break;
01174                 }
01175                 /* Here is an overlapped removed file: skip in previous. */
01176                 recs[otherPkgNum]->actions[otherFileNum] = FA_SKIP;
01177             }
01178             if (XFA_SKIPPING(fi->actions[i]))
01179                 break;
01180             if (fi->fstates && fi->fstates[i] != RPMFILE_STATE_NORMAL)
01181                 break;
01182             if (!(S_ISREG(fi->fmodes[i]) && (fi->fflags[i] & RPMFILE_CONFIG))) {
01183                 fi->actions[i] = FA_ERASE;
01184                 break;
01185             }
01186                 
01187             /* Here is a pre-existing modified config file that needs saving. */
01188             {   char mdsum[50];
01189                 if (!mdfile(filespec, mdsum) && strcmp(fi->fmd5s[i], mdsum)) {
01190                     fi->actions[i] = FA_BACKUP;
01191                     break;
01192                 }
01193             }
01194             fi->actions[i] = FA_ERASE;
01195             break;
01196         }
01197 
01198         if (ds) {
01199             uint_32 s = BLOCK_ROUND(fi->fsizes[i], ds->bsize);
01200 
01201             switch (fi->actions[i]) {
01202               case FA_BACKUP:
01203               case FA_SAVE:
01204               case FA_ALTNAME:
01205                 ds->ineeded++;
01206                 ds->bneeded += s;
01207                 break;
01208 
01209             /*
01210              * FIXME: If two packages share a file (same md5sum), and
01211              * that file is being replaced on disk, will ds->bneeded get
01212              * decremented twice? Quite probably!
01213              */
01214               case FA_CREATE:
01215                 ds->bneeded += s;
01216                 ds->bneeded -= BLOCK_ROUND(fi->replacedSizes[i], ds->bsize);
01217                 break;
01218 
01219               case FA_ERASE:
01220                 ds->ineeded--;
01221                 ds->bneeded -= s;
01222                 break;
01223 
01224               default:
01225                 break;
01226             }
01227 
01228             ds->bneeded -= BLOCK_ROUND(fixupSize, ds->bsize);
01229         }
01230     }
01231     if (filespec) free(filespec);
01232 }
01233 
01234 static int ensureOlder(struct availablePackage * alp, Header old,
01235                 rpmProblemSet probs)
01236         /*@modifies alp, probs @*/
01237 {
01238     int result, rc = 0;
01239 
01240     if (old == NULL) return 1;
01241 
01242     result = rpmVersionCompare(old, alp->h);
01243     if (result <= 0)
01244         rc = 0;
01245     else if (result > 0) {
01246         rc = 1;
01247         psAppend(probs, RPMPROB_OLDPACKAGE, alp, NULL, NULL, old, 0);
01248     }
01249 
01250     return rc;
01251 }
01252 
01253 static void skipFiles(const rpmTransactionSet ts, TFI_t fi)
01254         /*@globals rpmGlobalMacroContext @*/
01255         /*@modifies fi, rpmGlobalMacroContext @*/
01256 {
01257     int noDocs = (ts->transFlags & RPMTRANS_FLAG_NODOCS);
01258     char ** netsharedPaths = NULL;
01259     const char ** languages;
01260     const char * dn, * bn;
01261     int dnlen, bnlen, ix;
01262     const char * s;
01263     int * drc;
01264     char * dff;
01265     int i, j;
01266 
01267     if (!noDocs)
01268         noDocs = rpmExpandNumeric("%{_excludedocs}");
01269 
01270     {   const char *tmpPath = rpmExpand("%{_netsharedpath}", NULL);
01271         if (tmpPath && *tmpPath != '%')
01272             netsharedPaths = splitString(tmpPath, strlen(tmpPath), ':');
01273         tmpPath = _free(tmpPath);
01274     }
01275 
01276     s = rpmExpand("%{_install_langs}", NULL);
01277     if (!(s && *s != '%'))
01278         s = _free(s);
01279     if (s) {
01280         languages = (const char **) splitString(s, strlen(s), ':');
01281         s = _free(s);
01282     } else
01283         languages = NULL;
01284 
01285     /* Compute directory refcount, skip directory if now empty. */
01286     drc = alloca(fi->dc * sizeof(*drc));
01287     memset(drc, 0, fi->dc * sizeof(*drc));
01288     dff = alloca(fi->dc * sizeof(*dff));
01289     memset(dff, 0, fi->dc * sizeof(*dff));
01290 
01291     for (i = 0; i < fi->fc; i++) {
01292         char **nsp;
01293 
01294         bn = fi->bnl[i];
01295         bnlen = strlen(bn);
01296         ix = fi->dil[i];
01297         dn = fi->dnl[ix];
01298         dnlen = strlen(dn);
01299 
01300         drc[ix]++;
01301 
01302         /* Don't bother with skipped files */
01303         if (XFA_SKIPPING(fi->actions[i])) {
01304             drc[ix]--;
01305             continue;
01306         }
01307 
01308         /*
01309          * Skip net shared paths.
01310          * Net shared paths are not relative to the current root (though
01311          * they do need to take package relocations into account).
01312          */
01313         for (nsp = netsharedPaths; nsp && *nsp; nsp++) {
01314             int len;
01315 
01316             len = strlen(*nsp);
01317             if (dnlen >= len) {
01318                 if (strncmp(dn, *nsp, len)) continue;
01319                 /* Only directories or complete file paths can be net shared */
01320                 if (!(dn[len] == '/' || dn[len] == '\0')) continue;
01321             } else {
01322                 if (len < (dnlen + bnlen)) continue;
01323                 if (strncmp(dn, *nsp, dnlen)) continue;
01324                 if (strncmp(bn, (*nsp) + dnlen, bnlen)) continue;
01325                 len = dnlen + bnlen;
01326                 /* Only directories or complete file paths can be net shared */
01327                 if (!((*nsp)[len] == '/' || (*nsp)[len] == '\0')) continue;
01328             }
01329 
01330             /*@innerbreak@*/ break;
01331         }
01332 
01333         if (nsp && *nsp) {
01334             drc[ix]--;  dff[ix] = 1;
01335             fi->actions[i] = FA_SKIPNETSHARED;
01336             continue;
01337         }
01338 
01339         /*
01340          * Skip i18n language specific files.
01341          */
01342         if (fi->flangs && languages && *fi->flangs[i]) {
01343             const char **lang, *l, *le;
01344             for (lang = languages; *lang != '\0'; lang++) {
01345                 if (!strcmp(*lang, "all"))
01346                     /*@innerbreak@*/ break;
01347                 for (l = fi->flangs[i]; *l != '\0'; l = le) {
01348                     for (le = l; *le != '\0' && *le != '|'; le++)
01349                         {};
01350                     if ((le-l) > 0 && !strncmp(*lang, l, (le-l)))
01351                         /*@innerbreak@*/ break;
01352                     if (*le == '|') le++;       /* skip over | */
01353                 }
01354                 if (*l != '\0')
01355                     /*@innerbreak@*/ break;
01356             }
01357             if (*lang == NULL) {
01358                 drc[ix]--;      dff[ix] = 1;
01359                 fi->actions[i] = FA_SKIPNSTATE;
01360                 continue;
01361             }
01362         }
01363 
01364         /*
01365          * Skip documentation if requested.
01366          */
01367         if (noDocs && (fi->fflags[i] & RPMFILE_DOC)) {
01368             drc[ix]--;  dff[ix] = 1;
01369             fi->actions[i] = FA_SKIPNSTATE;
01370             continue;
01371         }
01372     }
01373 
01374     /* Skip (now empty) directories that had skipped files. */
01375     for (j = 0; j < fi->dc; j++) {
01376 
01377         if (drc[j]) continue;   /* dir still has files. */
01378         if (!dff[j]) continue;  /* dir was not emptied here. */
01379         
01380         /* Find parent directory and basename. */
01381         dn = fi->dnl[j];        dnlen = strlen(dn) - 1;
01382         bn = dn + dnlen;        bnlen = 0;
01383         while (bn > dn && bn[-1] != '/') {
01384                 bnlen++;
01385                 dnlen--;
01386                 bn--;
01387         }
01388 
01389         /* If explicitly included in the package, skip the directory. */
01390         for (i = 0; i < fi->fc; i++) {
01391             const char * dir;
01392 
01393             if (XFA_SKIPPING(fi->actions[i]))
01394                 continue;
01395             if (whatis(fi->fmodes[i]) != XDIR)
01396                 continue;
01397             dir = fi->dnl[fi->dil[i]];
01398             if (strlen(dir) != dnlen)
01399                 continue;
01400             if (strncmp(dir, dn, dnlen))
01401                 continue;
01402             if (strlen(fi->bnl[i]) != bnlen)
01403                 continue;
01404             if (strncmp(fi->bnl[i], bn, bnlen))
01405                 continue;
01406             rpmMessage(RPMMESS_DEBUG, _("excluding directory %s\n"), dn);
01407             fi->actions[i] = FA_SKIPNSTATE;
01408             /*@innerbreak@*/ break;
01409         }
01410     }
01411 
01412     if (netsharedPaths) freeSplitString(netsharedPaths);
01413 #ifdef  DYING   /* XXX freeFi will deal with this later. */
01414     fi->flangs = _free(fi->flangs);
01415 #endif
01416     if (languages) freeSplitString((char **)languages);
01417 }
01418 
01422 struct tsIterator_s {
01423 /*@kept@*/ rpmTransactionSet ts;        
01424     int reverse;                        
01425     int ocsave;                         
01426     int oc;                             
01427 };
01428 
01434 static int tsGetOc(void * a)
01435         /*@*/
01436 {
01437     struct tsIterator_s * iter = a;
01438     int oc = iter->ocsave;
01439     return oc;
01440 }
01441 
01447 static /*@dependent@*/ struct availablePackage * tsGetAlp(void * a)
01448         /*@*/
01449 {
01450     struct tsIterator_s * iter = a;
01451     struct availablePackage * alp = NULL;
01452     int oc = iter->ocsave;
01453 
01454     if (oc != -1) {
01455         rpmTransactionSet ts = iter->ts;
01456         TFI_t fi = ts->flList + oc;
01457         if (ts->addedPackages.list && fi->type == TR_ADDED)
01458             alp = ts->addedPackages.list + ts->order[oc].u.addedIndex;
01459     }
01460     return alp;
01461 }
01462 
01468 static /*@null@*/ void * tsFreeIterator(/*@only@*//*@null@*/ const void * a)
01469         /*@modifies a @*/
01470 {
01471     return _free(a);
01472 }
01473 
01479 static void * tsInitIterator(/*@kept@*/ const void * a)
01480         /*@*/
01481 {
01482     rpmTransactionSet ts = (void *)a;
01483     struct tsIterator_s * iter = NULL;
01484 
01485     iter = xcalloc(1, sizeof(*iter));
01486     iter->ts = ts;
01487     iter->reverse = ((ts->transFlags & RPMTRANS_FLAG_REVERSE) ? 1 : 0);
01488     iter->oc = (iter->reverse ? (ts->orderCount - 1) : 0);
01489     iter->ocsave = iter->oc;
01490     return iter;
01491 }
01492 
01498 static /*@dependent@*/ TFI_t tsNextIterator(void * a)
01499         /*@*/
01500 {
01501     struct tsIterator_s * iter = a;
01502     rpmTransactionSet ts = iter->ts;
01503     TFI_t fi = NULL;
01504     int oc = -1;
01505 
01506     if (iter->reverse) {
01507         if (iter->oc >= 0)              oc = iter->oc--;
01508     } else {
01509         if (iter->oc < ts->orderCount)  oc = iter->oc++;
01510     }
01511     iter->ocsave = oc;
01512     if (oc != -1)
01513         fi = ts->flList + oc;
01514     return fi;
01515 }
01516 
01517 #define NOTIFY(_ts, _al)        if ((_ts)->notify) (void) (_ts)->notify _al
01518 
01519 int rpmRunTransactions( rpmTransactionSet ts,
01520                         rpmCallbackFunction notify, rpmCallbackData notifyData,
01521                         rpmProblemSet okProbs, rpmProblemSet * newProbs,
01522                         rpmtransFlags transFlags, rpmprobFilterFlags ignoreSet)
01523 {
01524     int i, j;
01525     int ourrc = 0;
01526     struct availablePackage * alp;
01527     int totalFileCount = 0;
01528     hashTable ht;
01529     TFI_t fi;
01530     struct diskspaceInfo * dip;
01531     struct sharedFileInfo * shared, * sharedList;
01532     int numShared;
01533     int nexti;
01534     int lastFailed;
01535     int oc;
01536     fingerPrintCache fpc;
01537     struct psm_s psmbuf;
01538     PSM_t psm = &psmbuf;
01539     void * tsi;
01540 
01541     /* FIXME: what if the same package is included in ts twice? */
01542 
01543     ts->transFlags = transFlags;
01544     if (ts->transFlags & RPMTRANS_FLAG_NOSCRIPTS)
01545         ts->transFlags |= (_noTransScripts | _noTransTriggers);
01546     if (ts->transFlags & RPMTRANS_FLAG_NOTRIGGERS)
01547         ts->transFlags |= _noTransTriggers;
01548 
01549     /* XXX MULTILIB is broken, as packages can and do execute /sbin/ldconfig. */
01550     if (ts->transFlags & (RPMTRANS_FLAG_JUSTDB | RPMTRANS_FLAG_MULTILIB))
01551         ts->transFlags |= (_noTransScripts | _noTransTriggers);
01552 
01553     ts->notify = notify;
01554     ts->notifyData = notifyData;
01555     /*@-assignexpose@*/
01556     ts->probs = *newProbs = psCreate();
01557     /*@=assignexpose@*/
01558     ts->ignoreSet = ignoreSet;
01559     ts->currDir = _free(ts->currDir);
01560     ts->currDir = currentDirectory();
01561     ts->chrootDone = 0;
01562     if (ts->rpmdb) ts->rpmdb->db_chrootDone = 0;
01563     ts->id = (int_32) time(NULL);
01564 
01565     memset(psm, 0, sizeof(*psm));
01566     /*@-assignexpose@*/
01567     psm->ts = ts;
01568     /*@=assignexpose@*/
01569 
01570     /* Get available space on mounted file systems. */
01571     if (!(ts->ignoreSet & RPMPROB_FILTER_DISKSPACE) &&
01572                 !rpmGetFilesystemList(&ts->filesystems, &ts->filesystemCount)) {
01573         struct stat sb;
01574 
01575         ts->di = _free(ts->di);
01576         dip = ts->di = xcalloc(sizeof(*ts->di), ts->filesystemCount + 1);
01577 
01578         for (i = 0; (i < ts->filesystemCount) && dip; i++)
01579         if (strncmp(ts->filesystems[i], MNT_DEV_PREFIX, MNT_DEV_PREFIX_LENGTH)) {
01580 #if STATFS_IN_SYS_STATVFS
01581             struct statvfs sfb;
01582             memset(&sfb, 0, sizeof(sfb));
01583             if (statvfs(ts->filesystems[i], &sfb))
01584 #else
01585             struct statfs sfb;
01586 #  if STAT_STATFS4
01587 /* This platform has the 4-argument version of the statfs call.  The last two
01588  * should be the size of struct statfs and 0, respectively.  The 0 is the
01589  * filesystem type, and is always 0 when statfs is called on a mounted
01590  * filesystem, as we're doing.
01591  */
01592             memset(&sfb, 0, sizeof(sfb));
01593             if (statfs(ts->filesystems[i], &sfb, sizeof(sfb), 0))
01594 #  else
01595             memset(&sfb, 0, sizeof(sfb));
01596             if (statfs(ts->filesystems[i], &sfb))
01597 #  endif
01598 #endif
01599             {
01600                 dip = NULL;
01601             } else {
01602                 ts->di[i].bsize = sfb.f_bsize;
01603                 ts->di[i].bneeded = 0;
01604                 ts->di[i].ineeded = 0;
01605 #ifdef STATFS_HAS_F_BAVAIL
01606                 ts->di[i].bavail = sfb.f_bavail;
01607 #else
01608 /* FIXME: the statfs struct doesn't have a member to tell how many blocks are
01609  * available for non-superusers.  f_blocks - f_bfree is probably too big, but
01610  * it's about all we can do.
01611  */
01612                 ts->di[i].bavail = sfb.f_blocks - sfb.f_bfree;
01613 #endif
01614                 /* XXX Avoid FAT and other file systems that have not inodes. */
01615                 ts->di[i].iavail = !(sfb.f_ffree == 0 && sfb.f_files == 0)
01616                                 ? sfb.f_ffree : -1;
01617 
01618                 (void) stat(ts->filesystems[i], &sb);
01619                 ts->di[i].dev = sb.st_dev;
01620             }
01621         }
01622 
01623         if (dip) ts->di[i].bsize = 0;
01624     }
01625 
01626     /* ===============================================
01627      * For packages being installed:
01628      * - verify package arch/os.
01629      * - verify package epoch:version-release is newer.
01630      * - count files.
01631      * For packages being removed:
01632      * - count files.
01633      */
01634     /* The ordering doesn't matter here */
01635     if (ts->addedPackages.list != NULL)
01636     for (alp = ts->addedPackages.list;
01637         (alp - ts->addedPackages.list) < ts->addedPackages.size;
01638         alp++)
01639     {
01640         if (!archOkay(alp->h) && !(ts->ignoreSet & RPMPROB_FILTER_IGNOREARCH))
01641             psAppend(ts->probs, RPMPROB_BADARCH, alp, NULL, NULL, NULL, 0);
01642 
01643         if (!osOkay(alp->h) && !(ts->ignoreSet & RPMPROB_FILTER_IGNOREOS))
01644             psAppend(ts->probs, RPMPROB_BADOS, alp, NULL, NULL, NULL, 0);
01645 
01646         if (!(ts->ignoreSet & RPMPROB_FILTER_OLDPACKAGE)) {
01647             rpmdbMatchIterator mi;
01648             Header oldH;
01649             mi = rpmdbInitIterator(ts->rpmdb, RPMTAG_NAME, alp->name, 0);
01650             while ((oldH = rpmdbNextIterator(mi)) != NULL)
01651                 (void) ensureOlder(alp, oldH, ts->probs);
01652             mi = rpmdbFreeIterator(mi);
01653         }
01654 
01655         /* XXX multilib should not display "already installed" problems */
01656         if (!(ts->ignoreSet & RPMPROB_FILTER_REPLACEPKG) && !alp->multiLib) {
01657             rpmdbMatchIterator mi;
01658             mi = rpmdbInitIterator(ts->rpmdb, RPMTAG_NAME, alp->name, 0);
01659             (void) rpmdbSetIteratorRE(mi, RPMTAG_VERSION,
01660                         RPMMIRE_DEFAULT, alp->version);
01661             (void) rpmdbSetIteratorRE(mi, RPMTAG_RELEASE,
01662                         RPMMIRE_DEFAULT, alp->release);
01663 
01664             while (rpmdbNextIterator(mi) != NULL) {
01665                 psAppend(ts->probs, RPMPROB_PKG_INSTALLED, alp,
01666                         NULL, NULL, NULL, 0);
01667                 /*@innerbreak@*/ break;
01668             }
01669             mi = rpmdbFreeIterator(mi);
01670         }
01671 
01672         totalFileCount += alp->filesCount;
01673 
01674     }
01675 
01676     /* FIXME: it seems a bit silly to read in all of these headers twice */
01677     /* The ordering doesn't matter here */
01678     if (ts->numRemovedPackages > 0) {
01679         rpmdbMatchIterator mi;
01680         Header h;
01681         int fileCount;
01682 
01683         mi = rpmdbInitIterator(ts->rpmdb, RPMDBI_PACKAGES, NULL, 0);
01684         (void) rpmdbAppendIterator(mi, ts->removedPackages, ts->numRemovedPackages);
01685         while ((h = rpmdbNextIterator(mi)) != NULL) {
01686             if (headerGetEntry(h, RPMTAG_BASENAMES, NULL, NULL, &fileCount))
01687                 totalFileCount += fileCount;
01688         }
01689         mi = rpmdbFreeIterator(mi);
01690     }
01691 
01692     /* ===============================================
01693      * Initialize file list:
01694      */
01695     ts->flEntries = ts->addedPackages.size + ts->numRemovedPackages;
01696     ts->flList = xcalloc(ts->flEntries, sizeof(*ts->flList));
01697 
01698     /*
01699      * FIXME?: we'd be better off assembling one very large file list and
01700      * calling fpLookupList only once. I'm not sure that the speedup is
01701      * worth the trouble though.
01702      */
01703     tsi = tsInitIterator(ts);
01704     while ((fi = tsNextIterator(tsi)) != NULL) {
01705         oc = tsGetOc(tsi);
01706         fi->magic = TFIMAGIC;
01707 
01708         /* XXX watchout: fi->type must be set for tsGetAlp() to "work" */
01709         fi->type = ts->order[oc].type;
01710         switch (fi->type) {
01711         case TR_ADDED:
01712             i = ts->order[oc].u.addedIndex;
01713             /* XXX watchout: fi->type must be set for tsGetAlp() to "work" */
01714             fi->ap = tsGetAlp(tsi);
01715             fi->record = 0;
01716             loadFi(fi->ap->h, fi);
01717             if (fi->fc == 0)
01718                 continue;
01719 
01720             {   Header foo = relocateFileList(ts, fi, fi->ap, fi->h, fi->actions);
01721                 foo = headerFree(foo);
01722             }
01723 
01724             /* Skip netshared paths, not our i18n files, and excluded docs */
01725             skipFiles(ts, fi);
01726             break;
01727         case TR_REMOVED:
01728             fi->ap = NULL;
01729             fi->record = ts->order[oc].u.removed.dboffset;
01730             {   rpmdbMatchIterator mi;
01731 
01732                 mi = rpmdbInitIterator(ts->rpmdb, RPMDBI_PACKAGES,
01733                                 &fi->record, sizeof(fi->record));
01734                 if ((fi->h = rpmdbNextIterator(mi)) != NULL)
01735                     fi->h = headerLink(fi->h);
01736                 mi = rpmdbFreeIterator(mi);
01737             }
01738             if (fi->h == NULL) {
01739                 /* ACK! */
01740                 continue;
01741             }
01742             /* XXX header arg unused. */
01743             loadFi(fi->h, fi);
01744             break;
01745         }
01746 
01747         if (fi->fc)
01748             fi->fps = xmalloc(fi->fc * sizeof(*fi->fps));
01749     }
01750     tsi = tsFreeIterator(tsi);
01751 
01752     if (!ts->chrootDone) {
01753         (void) chdir("/");
01754         /*@-unrecog -superuser @*/
01755         (void) chroot(ts->rootDir);
01756         /*@=unrecog =superuser @*/
01757         ts->chrootDone = 1;
01758         if (ts->rpmdb) ts->rpmdb->db_chrootDone = 1;
01759 #ifdef  DYING
01760         /*@-onlytrans@*/
01761         chroot_prefix = ts->rootDir;
01762         /*@=onlytrans@*/
01763 #endif
01764     }
01765 
01766     ht = htCreate(totalFileCount * 2, 0, 0, fpHashFunction, fpEqual);
01767     fpc = fpCacheCreate(totalFileCount);
01768 
01769     /* ===============================================
01770      * Add fingerprint for each file not skipped.
01771      */
01772     tsi = tsInitIterator(ts);
01773     while ((fi = tsNextIterator(tsi)) != NULL) {
01774         fpLookupList(fpc, fi->dnl, fi->bnl, fi->dil, fi->fc, fi->fps);
01775         for (i = 0; i < fi->fc; i++) {
01776             if (XFA_SKIPPING(fi->actions[i]))
01777                 continue;
01778             /*@-dependenttrans@*/
01779             htAddEntry(ht, fi->fps + i, fi);
01780             /*@=dependenttrans@*/
01781         }
01782     }
01783     tsi = tsFreeIterator(tsi);
01784 
01785     /*@-moduncon@*/
01786     NOTIFY(ts, (NULL, RPMCALLBACK_TRANS_START, 6, ts->flEntries,
01787         NULL, ts->notifyData));
01788     /*@=moduncon@*/
01789 
01790     /* ===============================================
01791      * Compute file disposition for each package in transaction set.
01792      */
01793     tsi = tsInitIterator(ts);
01794     while ((fi = tsNextIterator(tsi)) != NULL) {
01795         dbiIndexSet * matches;
01796         int knownBad;
01797 
01798         /*@-moduncon@*/
01799         NOTIFY(ts, (NULL, RPMCALLBACK_TRANS_PROGRESS, (fi - ts->flList),
01800                         ts->flEntries, NULL, ts->notifyData));
01801         /*@=moduncon@*/
01802 
01803         if (fi->fc == 0) continue;
01804 
01805         /* Extract file info for all files in this package from the database. */
01806         matches = xcalloc(sizeof(*matches), fi->fc);
01807         if (rpmdbFindFpList(ts->rpmdb, fi->fps, matches, fi->fc))
01808             return 1;   /* XXX WTFO? */
01809 
01810         numShared = 0;
01811         for (i = 0; i < fi->fc; i++)
01812             numShared += dbiIndexSetCount(matches[i]);
01813 
01814         /* Build sorted file info list for this package. */
01815         shared = sharedList = xmalloc((numShared + 1) * sizeof(*sharedList));
01816         for (i = 0; i < fi->fc; i++) {
01817             /*
01818              * Take care not to mark files as replaced in packages that will
01819              * have been removed before we will get here.
01820              */
01821             for (j = 0; j < dbiIndexSetCount(matches[i]); j++) {
01822                 int k, ro;
01823                 ro = dbiIndexRecordOffset(matches[i], j);
01824                 knownBad = 0;
01825                 for (k = 0; ro != knownBad && k < ts->orderCount; k++) {
01826                     switch (ts->order[k].type) {
01827                     case TR_REMOVED:
01828                         if (ts->order[k].u.removed.dboffset == ro)
01829                             knownBad = ro;
01830                         break;
01831                     case TR_ADDED:
01832                         break;
01833                     }
01834                 }
01835 
01836                 shared->pkgFileNum = i;
01837                 shared->otherPkg = dbiIndexRecordOffset(matches[i], j);
01838                 shared->otherFileNum = dbiIndexRecordFileNumber(matches[i], j);
01839                 shared->isRemoved = (knownBad == ro);
01840                 shared++;
01841             }
01842             matches[i] = dbiFreeIndexSet(matches[i]);
01843         }
01844         numShared = shared - sharedList;
01845         shared->otherPkg = -1;
01846         matches = _free(matches);
01847 
01848         /* Sort file info by other package index (otherPkg) */
01849         qsort(sharedList, numShared, sizeof(*shared), sharedCmp);
01850 
01851         /* For all files from this package that are in the database ... */
01852         for (i = 0; i < numShared; i = nexti) {
01853             int beingRemoved;
01854 
01855             shared = sharedList + i;
01856 
01857             /* Find the end of the files in the other package. */
01858             for (nexti = i + 1; nexti < numShared; nexti++) {
01859                 if (sharedList[nexti].otherPkg != shared->otherPkg)
01860                     /*@innerbreak@*/ break;
01861             }
01862 
01863             /* Is this file from a package being removed? */
01864             beingRemoved = 0;
01865             for (j = 0; j < ts->numRemovedPackages; j++) {
01866                 if (ts->removedPackages[j] != shared->otherPkg)
01867                     continue;
01868                 beingRemoved = 1;
01869                 /*@innerbreak@*/ break;
01870             }
01871 
01872             /* Determine the fate of each file. */
01873             switch (fi->type) {
01874             case TR_ADDED:
01875                 (void) handleInstInstalledFiles(fi, ts->rpmdb, shared, nexti - i,
01876                 !(beingRemoved || (ts->ignoreSet & RPMPROB_FILTER_REPLACEOLDFILES)),
01877                          ts->probs, ts->transFlags);
01878                 break;
01879             case TR_REMOVED:
01880                 if (!beingRemoved)
01881                     (void) handleRmvdInstalledFiles(fi, ts->rpmdb, shared, nexti - i);
01882                 break;
01883             }
01884         }
01885 
01886         free(sharedList);
01887 
01888         /* Update disk space needs on each partition for this package. */
01889         handleOverlappedFiles(fi, ht,
01890                ((ts->ignoreSet & RPMPROB_FILTER_REPLACENEWFILES)
01891                     ? NULL : ts->probs), ts->di);
01892 
01893         /* Check added package has sufficient space on each partition used. */
01894         switch (fi->type) {
01895         case TR_ADDED:
01896             if (!(ts->di && fi->fc))
01897                 break;
01898             for (i = 0; i < ts->filesystemCount; i++) {
01899 
01900                 dip = ts->di + i;
01901 
01902                 /* XXX Avoid FAT and other file systems that have not inodes. */
01903                 if (dip->iavail <= 0)
01904                     continue;
01905 
01906                 if (adj_fs_blocks(dip->bneeded) > dip->bavail)
01907                     psAppend(ts->probs, RPMPROB_DISKSPACE, fi->ap,
01908                                 ts->filesystems[i], NULL, NULL,
01909                    (adj_fs_blocks(dip->bneeded) - dip->bavail) * dip->bsize);
01910 
01911                 if (adj_fs_blocks(dip->ineeded) > dip->iavail)
01912                     psAppend(ts->probs, RPMPROB_DISKNODES, fi->ap,
01913                                 ts->filesystems[i], NULL, NULL,
01914                     (adj_fs_blocks(dip->ineeded) - dip->iavail));
01915             }
01916             break;
01917         case TR_REMOVED:
01918             break;
01919         }
01920     }
01921     tsi = tsFreeIterator(tsi);
01922 
01923     if (ts->chrootDone) {
01924         /*@-unrecog -superuser @*/
01925         (void) chroot(".");
01926         /*@=unrecog =superuser @*/
01927         ts->chrootDone = 0;
01928         if (ts->rpmdb) ts->rpmdb->db_chrootDone = 0;
01929 #ifdef  DYING
01930         chroot_prefix = NULL;
01931 #endif
01932         (void) chdir(ts->currDir);
01933     }
01934 
01935     /*@-moduncon@*/
01936     NOTIFY(ts, (NULL, RPMCALLBACK_TRANS_STOP, 6, ts->flEntries,
01937         NULL, ts->notifyData));
01938     /*@=moduncon@*/
01939 
01940     /* ===============================================
01941      * Free unused memory as soon as possible.
01942      */
01943 
01944     tsi = tsInitIterator(ts);
01945     while ((fi = tsNextIterator(tsi)) != NULL) {
01946         psm->fi = fi;
01947         if (fi->fc == 0)
01948             continue;
01949         fi->fps = _free(fi->fps);
01950     }
01951     tsi = tsFreeIterator(tsi);
01952 
01953     fpCacheFree(fpc);
01954     htFree(ht);
01955 
01956     /* ===============================================
01957      * If unfiltered problems exist, free memory and return.
01958      */
01959     if ((ts->transFlags & RPMTRANS_FLAG_BUILD_PROBS) ||
01960            (ts->probs->numProblems && (!okProbs || psTrim(okProbs, ts->probs))))
01961     {
01962         *newProbs = ts->probs;
01963 
01964         ts->flList = freeFl(ts, ts->flList);
01965         ts->flEntries = 0;
01966         /*@-nullstate@*/
01967         return ts->orderCount;
01968         /*@=nullstate@*/
01969     }
01970 
01971     /* ===============================================
01972      * Save removed files before erasing.
01973      */
01974     if (ts->transFlags & (RPMTRANS_FLAG_DIRSTASH | RPMTRANS_FLAG_REPACKAGE)) {
01975         tsi = tsInitIterator(ts);
01976         while ((fi = tsNextIterator(tsi)) != NULL) {
01977             psm->fi = fi;
01978             switch (fi->type) {
01979             case TR_ADDED:
01980                 break;
01981             case TR_REMOVED:
01982                 if (ts->transFlags & RPMTRANS_FLAG_REPACKAGE)
01983                     (void) psmStage(psm, PSM_PKGSAVE);
01984                 break;
01985             }
01986         }
01987         tsi = tsFreeIterator(tsi);
01988     }
01989 
01990     /* ===============================================
01991      * Install and remove packages.
01992      */
01993 
01994     lastFailed = -2;    /* erased packages have -1 */
01995     tsi = tsInitIterator(ts);
01996     while ((fi = tsNextIterator(tsi)) != NULL) {
01997         Header h;
01998         int gotfd;
01999 
02000         gotfd = 0;
02001         psm->fi = fi;
02002         switch (fi->type)
02003         {
02004         case TR_ADDED:
02005             alp = tsGetAlp(tsi);
02006 assert(alp == fi->ap);
02007             i = alp - ts->addedPackages.list;
02008 
02009             h = headerLink(fi->h);
02010             if (alp->fd == NULL) {
02011                 alp->fd = ts->notify(fi->h, RPMCALLBACK_INST_OPEN_FILE, 0, 0,
02012                             alp->key, ts->notifyData);
02013                 if (alp->fd) {
02014                     rpmRC rpmrc;
02015 
02016                     h = headerFree(h);
02017 
02018                     /*@-mustmod@*/      /* LCL: segfault */
02019                     rpmrc = rpmReadPackageHeader(alp->fd, &h, NULL, NULL, NULL);
02020                     /*@=mustmod@*/
02021                     if (!(rpmrc == RPMRC_OK || rpmrc == RPMRC_BADSIZE)) {
02022                         (void)ts->notify(fi->h, RPMCALLBACK_INST_CLOSE_FILE,
02023                                         0, 0, alp->key, ts->notifyData);
02024                         alp->fd = NULL;
02025                         ourrc++;
02026                     } else {
02027                         Header foo = relocateFileList(ts, fi, alp, h, NULL);
02028                         h = headerFree(h);
02029                         h = headerLink(foo);
02030                         foo = headerFree(foo);
02031                     }
02032                     if (alp->fd) gotfd = 1;
02033                 }
02034             }
02035 
02036             if (alp->fd) {
02037                 Header hsave = NULL;
02038 
02039                 if (fi->h) {
02040                     hsave = headerLink(fi->h);
02041                     fi->h = headerFree(fi->h);
02042                 }
02043                 fi->h = headerLink(h);
02044                 if (alp->multiLib)
02045                     ts->transFlags |= RPMTRANS_FLAG_MULTILIB;
02046 
02047 assert(alp == fi->ap);
02048                 if (psmStage(psm, PSM_PKGINSTALL)) {
02049                     ourrc++;
02050                     lastFailed = i;
02051                 }
02052                 fi->h = headerFree(fi->h);
02053                 if (hsave) {
02054                     fi->h = headerLink(hsave);
02055                     hsave = headerFree(hsave);
02056                 }
02057             } else {
02058                 ourrc++;
02059                 lastFailed = i;
02060             }
02061 
02062             h = headerFree(h);
02063 
02064             if (gotfd) {
02065                 (void)ts->notify(fi->h, RPMCALLBACK_INST_CLOSE_FILE, 0, 0,
02066                         alp->key, ts->notifyData);
02067                 alp->fd = NULL;
02068             }
02069             break;
02070         case TR_REMOVED:
02071             oc = tsGetOc(tsi);
02072             /* If install failed, then we shouldn't erase. */
02073             if (ts->order[oc].u.removed.dependsOnIndex == lastFailed)
02074                 break;
02075 
02076             if (psmStage(psm, PSM_PKGERASE))
02077                 ourrc++;
02078 
02079             break;
02080         }
02081         (void) rpmdbSync(ts->rpmdb);
02082     }
02083     tsi = tsFreeIterator(tsi);
02084 
02085     ts->flList = freeFl(ts, ts->flList);
02086     ts->flEntries = 0;
02087 
02088     /*@-nullstate@*/
02089     if (ourrc)
02090         return -1;
02091     else
02092         return 0;
02093     /*@=nullstate@*/
02094 }

Generated on Sun Feb 2 23:32:03 2003 for rpm by doxygen1.2.18