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

Generated on Wed Mar 13 15:34:49 2002 for rpm by doxygen1.2.14 written by Dimitri van Heesch, © 1997-2002