Remove dead code.
[platform/upstream/rpm.git] / lib / transaction.c
1 /** \ingroup rpmtrans
2  * \file lib/transaction.c
3  */
4
5 #include "system.h"
6
7 #define _NEED_TEITERATOR        1
8 #include "psm.h"
9
10 #include "rpmal.h"
11 #include <rpmmacro.h>   /* XXX for rpmExpand */
12
13 #include "fprint.h"
14 #include "legacy.h"     /* XXX mdfile */
15 #include "misc.h" /* XXX stripTrailingChar, splitString, currentDirectory */
16 #include "rpmdb.h"
17
18 /*@-redecl -exportheadervar@*/
19 /*@unchecked@*/
20 extern const char * chroot_prefix;
21 /*@=redecl =exportheadervar@*/
22
23 /* XXX FIXME: merge with existing (broken?) tests in system.h */
24 /* portability fiddles */
25 #if STATFS_IN_SYS_STATVFS
26 /*@-incondefs@*/
27 # include <sys/statvfs.h>
28 #if defined(__LCLINT__)
29 /*@-declundef -exportheader -protoparammatch @*/ /* LCL: missing annotation */
30 extern int statvfs (const char * file, /*@out@*/ struct statvfs * buf)
31         /*@globals fileSystem @*/
32         /*@modifies *buf, fileSystem @*/;
33 /*@=declundef =exportheader =protoparammatch @*/
34 /*@=incondefs@*/
35 #endif
36 #else
37 # if STATFS_IN_SYS_VFS
38 #  include <sys/vfs.h>
39 # else
40 #  if STATFS_IN_SYS_MOUNT
41 #   include <sys/mount.h>
42 #  else
43 #   if STATFS_IN_SYS_STATFS
44 #    include <sys/statfs.h>
45 #   endif
46 #  endif
47 # endif
48 #endif
49
50 #include "debug.h"
51
52 /*@access FD_t@*/               /* XXX compared with NULL */
53 /*@access Header@*/             /* XXX compared with NULL */
54 /*@access rpmProblemSet@*/      /* XXX need rpmProblemSetOK() */
55 /*@access dbiIndexSet@*/
56 /*@access rpmdb@*/
57
58 /*@access PSM_t@*/
59
60 /*@access alKey@*/
61 /*@access fnpyKey@*/
62
63 /*@access TFI_t@*/
64 /*@access teIterator@*/
65 /*@access transactionElement@*/
66 /*@access rpmTransactionSet@*/
67
68 /**
69  */
70 struct diskspaceInfo {
71     dev_t dev;                  /*!< file system device number. */
72     signed long bneeded;        /*!< no. of blocks needed. */
73     signed long ineeded;        /*!< no. of inodes needed. */
74     int bsize;                  /*!< file system block size. */
75     signed long bavail;         /*!< no. of blocks available. */
76     signed long iavail;         /*!< no. of inodes available. */
77 };
78
79 /**
80  * Adjust for root only reserved space. On linux e2fs, this is 5%.
81  */
82 #define adj_fs_blocks(_nb)      (((_nb) * 21) / 20)
83
84 /* argon thought a shift optimization here was a waste of time...  he's
85    probably right :-( */
86 #define BLOCK_ROUND(size, block) (((size) + (block) - 1) / (block))
87
88 /**
89  */
90 static /*@null@*/ void * freeFl(rpmTransactionSet ts,
91                 /*@only@*/ /*@null@*/ TFI_t flList)
92         /*@*/
93 {
94     if (flList) {
95         TFI_t fi;
96         int oc;
97
98         /*@-usereleased -onlytrans @*/ /* FIX: fi needs to be only */
99         for (oc = 0, fi = flList; oc < ts->orderCount; oc++, fi++)
100             freeFi(fi);
101         flList = _free(flList);
102         /*@=usereleased =onlytrans @*/
103     }
104     return NULL;
105 }
106
107 void rpmtransSetScriptFd(rpmTransactionSet ts, FD_t fd)
108 {
109     /*@-type@*/ /* FIX: cast? */
110     ts->scriptFd = (fd ? fdLink(fd, "rpmtransSetScriptFd") : NULL);
111     /*@=type@*/
112 }
113
114 int rpmtransGetKeys(const rpmTransactionSet ts, fnpyKey ** ep, int * nep)
115 {
116     int rc = 0;
117
118     if (nep) *nep = ts->orderCount;
119     if (ep) {
120         fnpyKey * e;
121         int oc;
122
123         *ep = e = xmalloc(ts->orderCount * sizeof(*e));
124         for (oc = 0; oc < ts->orderCount; oc++, e++) {
125             switch (ts->order[oc].type) {
126             case TR_ADDED:
127                 *e = ts->order[oc].key;
128                 /*@switchbreak@*/ break;
129             default:
130             case TR_REMOVED:
131                 /*@-mods@*/     /* FIX: double indirection. */
132                 *e = NULL;
133                 /*@=mods@*/
134                 /*@switchbreak@*/ break;
135             }
136         }
137     }
138     return rc;
139 }
140
141 /**
142  */
143 static int archOkay(Header h)
144         /*@*/
145 {
146     void * pkgArch;
147     int type, count;
148
149     /* make sure we're trying to install this on the proper architecture */
150     (void) headerGetEntry(h, RPMTAG_ARCH, &type, (void **) &pkgArch, &count);
151 #ifndef DYING
152     if (type == RPM_INT8_TYPE) {
153         int_8 * pkgArchNum;
154         int archNum;
155
156         /* old arch handling */
157         rpmGetArchInfo(NULL, &archNum);
158         pkgArchNum = pkgArch;
159         if (archNum != *pkgArchNum) {
160             return 0;
161         }
162     } else
163 #endif
164     {
165         /* new arch handling */
166         if (!rpmMachineScore(RPM_MACHTABLE_INSTARCH, pkgArch)) {
167             return 0;
168         }
169     }
170
171     return 1;
172 }
173
174 /**
175  */
176 static int osOkay(Header h)
177         /*@*/
178 {
179     void * pkgOs;
180     int type, count;
181
182     /* make sure we're trying to install this on the proper os */
183     (void) headerGetEntry(h, RPMTAG_OS, &type, (void **) &pkgOs, &count);
184 #ifndef DYING
185     if (type == RPM_INT8_TYPE) {
186         /* v1 packages and v2 packages both used improper OS numbers, so just
187            deal with it hope things work */
188         return 1;
189     } else
190 #endif
191     {
192         /* new os handling */
193         if (!rpmMachineScore(RPM_MACHTABLE_INSTOS, pkgOs)) {
194             return 0;
195         }
196     }
197
198     return 1;
199 }
200
201 /**
202  */
203 static int sharedCmp(const void * one, const void * two)
204         /*@*/
205 {
206     const struct sharedFileInfo * a = one;
207     const struct sharedFileInfo * b = two;
208
209     if (a->otherPkg < b->otherPkg)
210         return -1;
211     else if (a->otherPkg > b->otherPkg)
212         return 1;
213
214     return 0;
215 }
216
217 /**
218  */
219 static fileAction decideFileFate(const char * dirName,
220                         const char * baseName, short dbMode,
221                         const char * dbMd5, const char * dbLink, short newMode,
222                         const char * newMd5, const char * newLink, int newFlags,
223                         rpmtransFlags transFlags)
224         /*@globals fileSystem @*/
225         /*@modifies fileSystem @*/
226 {
227     char buffer[1024];
228     const char * dbAttr, * newAttr;
229     fileTypes dbWhat, newWhat, diskWhat;
230     struct stat sb;
231     int i, rc;
232     int save = (newFlags & RPMFILE_NOREPLACE) ? FA_ALTNAME : FA_SAVE;
233     char * filespec = alloca(strlen(dirName) + strlen(baseName) + 1);
234
235     (void) stpcpy( stpcpy(filespec, dirName), baseName);
236
237     if (lstat(filespec, &sb)) {
238         /*
239          * The file doesn't exist on the disk. Create it unless the new
240          * package has marked it as missingok, or allfiles is requested.
241          */
242         if (!(transFlags & RPMTRANS_FLAG_ALLFILES) &&
243            (newFlags & RPMFILE_MISSINGOK)) {
244             rpmMessage(RPMMESS_DEBUG, _("%s skipped due to missingok flag\n"),
245                         filespec);
246             return FA_SKIP;
247         } else {
248             return FA_CREATE;
249         }
250     }
251
252     diskWhat = whatis(sb.st_mode);
253     dbWhat = whatis(dbMode);
254     newWhat = whatis(newMode);
255
256     /* RPM >= 2.3.10 shouldn't create config directories -- we'll ignore
257        them in older packages as well */
258     if (newWhat == XDIR) {
259         return FA_CREATE;
260     }
261
262     if (diskWhat != newWhat) {
263         return save;
264     } else if (newWhat != dbWhat && diskWhat != dbWhat) {
265         return save;
266     } else if (dbWhat != newWhat) {
267         return FA_CREATE;
268     } else if (dbWhat != LINK && dbWhat != REG) {
269         return FA_CREATE;
270     }
271
272     if (dbWhat == REG) {
273         rc = mdfile(filespec, buffer);
274
275         if (rc) {
276             /* assume the file has been removed, don't freak */
277             return FA_CREATE;
278         }
279         dbAttr = dbMd5;
280         newAttr = newMd5;
281     } else /* dbWhat == LINK */ {
282         memset(buffer, 0, sizeof(buffer));
283         i = readlink(filespec, buffer, sizeof(buffer) - 1);
284         if (i == -1) {
285             /* assume the file has been removed, don't freak */
286             return FA_CREATE;
287         }
288         dbAttr = dbLink;
289         newAttr = newLink;
290      }
291
292     /* this order matters - we'd prefer to CREATE the file if at all
293        possible in case something else (like the timestamp) has changed */
294
295     if (!strcmp(dbAttr, buffer)) {
296         /* this config file has never been modified, so just replace it */
297         return FA_CREATE;
298     }
299
300     if (!strcmp(dbAttr, newAttr)) {
301         /* this file is the same in all versions of this package */
302         return FA_SKIP;
303     }
304
305     /*
306      * The config file on the disk has been modified, but
307      * the ones in the two packages are different. It would
308      * be nice if RPM was smart enough to at least try and
309      * merge the difference ala CVS, but...
310      */
311     return save;
312 }
313
314 /**
315  */
316 static int filecmp(short mode1, const char * md51, const char * link1,
317                    short mode2, const char * md52, const char * link2)
318         /*@*/
319 {
320     fileTypes what1 = whatis(mode1);
321     fileTypes what2 = whatis(mode2);
322
323     if (what1 != what2) return 1;
324
325     if (what1 == LINK)
326         return strcmp(link1, link2);
327     else if (what1 == REG)
328         return strcmp(md51, md52);
329
330     return 0;
331 }
332
333 /**
334  */
335 /* XXX only ts->{probs,rpmdb} modified */
336 static int handleInstInstalledFiles(const rpmTransactionSet ts, TFI_t fi,
337                 struct sharedFileInfo * shared,
338                 int sharedCount, int reportConflicts)
339         /*@globals fileSystem @*/
340         /*@modifies ts, fi, fileSystem @*/
341 {
342     HGE_t hge = fi->hge;
343     HFD_t hfd = (fi->hfd ? fi->hfd : headerFreeData);
344     rpmtransFlags transFlags = ts->transFlags;
345     rpmTagType oltype, omtype;
346     Header h;
347     int i;
348     const char ** otherMd5s;
349     const char ** otherLinks;
350     const char * otherStates;
351     uint_32 * otherFlags;
352     uint_32 * otherSizes;
353     uint_16 * otherModes;
354     int numReplaced = 0;
355     int xx;
356
357     rpmdbMatchIterator mi;
358
359     mi = rpmtsInitIterator(ts, RPMDBI_PACKAGES, &shared->otherPkg, sizeof(shared->otherPkg));
360     h = rpmdbNextIterator(mi);
361     if (h == NULL) {
362         mi = rpmdbFreeIterator(mi);
363         return 1;
364     }
365
366     xx = hge(h, RPMTAG_FILEMD5S, &omtype, (void **) &otherMd5s, NULL);
367     xx = hge(h, RPMTAG_FILELINKTOS, &oltype, (void **) &otherLinks, NULL);
368     xx = hge(h, RPMTAG_FILESTATES, NULL, (void **) &otherStates, NULL);
369     xx = hge(h, RPMTAG_FILEMODES, NULL, (void **) &otherModes, NULL);
370     xx = hge(h, RPMTAG_FILEFLAGS, NULL, (void **) &otherFlags, NULL);
371     xx = hge(h, RPMTAG_FILESIZES, NULL, (void **) &otherSizes, NULL);
372
373     fi->replaced = xmalloc(sharedCount * sizeof(*fi->replaced));
374
375     for (i = 0; i < sharedCount; i++, shared++) {
376         int otherFileNum, fileNum;
377         otherFileNum = shared->otherFileNum;
378         fileNum = shared->pkgFileNum;
379
380         /* XXX another tedious segfault, assume file state normal. */
381         if (otherStates && otherStates[otherFileNum] != RPMFILE_STATE_NORMAL)
382             continue;
383
384         if (XFA_SKIPPING(fi->actions[fileNum]))
385             continue;
386
387         if (filecmp(otherModes[otherFileNum],
388                         otherMd5s[otherFileNum],
389                         otherLinks[otherFileNum],
390                         fi->fmodes[fileNum],
391                         fi->fmd5s[fileNum],
392                         fi->flinks[fileNum])) {
393             /*@-compdef@*/ /* FIX: *fi->replaced undefined */
394             if (reportConflicts)
395                 rpmProblemSetAppend(ts->probs, RPMPROB_FILE_CONFLICT,
396                         fiGetNVR(fi), fi->key,
397                         fi->dnl[fi->dil[fileNum]], fi->bnl[fileNum],
398                         hGetNVR(h, NULL),
399                         0);
400             /*@=compdef@*/
401             if (!(otherFlags[otherFileNum] | fi->fflags[fileNum])
402                         & RPMFILE_CONFIG) {
403                 /*@-assignexpose@*/
404                 if (!shared->isRemoved)
405                     fi->replaced[numReplaced++] = *shared;
406                 /*@=assignexpose@*/
407             }
408         }
409
410         if ((otherFlags[otherFileNum] | fi->fflags[fileNum]) & RPMFILE_CONFIG) {
411             fi->actions[fileNum] = decideFileFate(
412                         fi->dnl[fi->dil[fileNum]],
413                         fi->bnl[fileNum],
414                         otherModes[otherFileNum],
415                         otherMd5s[otherFileNum],
416                         otherLinks[otherFileNum],
417                         fi->fmodes[fileNum],
418                         fi->fmd5s[fileNum],
419                         fi->flinks[fileNum],
420                         fi->fflags[fileNum],
421                         transFlags);
422         }
423
424         fi->replacedSizes[fileNum] = otherSizes[otherFileNum];
425     }
426
427     otherMd5s = hfd(otherMd5s, omtype);
428     otherLinks = hfd(otherLinks, oltype);
429     mi = rpmdbFreeIterator(mi);
430
431     fi->replaced = xrealloc(fi->replaced,       /* XXX memory leak */
432                            sizeof(*fi->replaced) * (numReplaced + 1));
433     fi->replaced[numReplaced].otherPkg = 0;
434
435     return 0;
436 }
437
438 /**
439  */
440 /* XXX only ts->rpmdb modified */
441 static int handleRmvdInstalledFiles(const rpmTransactionSet ts, TFI_t fi,
442                 struct sharedFileInfo * shared, int sharedCount)
443         /*@globals fileSystem @*/
444         /*@modifies fi, fileSystem @*/
445 {
446     HGE_t hge = fi->hge;
447     Header h;
448     const char * otherStates;
449     int i, xx;
450    
451     rpmdbMatchIterator mi;
452
453     mi = rpmtsInitIterator(ts, RPMDBI_PACKAGES,
454                         &shared->otherPkg, sizeof(shared->otherPkg));
455     h = rpmdbNextIterator(mi);
456     if (h == NULL) {
457         mi = rpmdbFreeIterator(mi);
458         return 1;
459     }
460
461     xx = hge(h, RPMTAG_FILESTATES, NULL, (void **) &otherStates, NULL);
462
463     for (i = 0; i < sharedCount; i++, shared++) {
464         int otherFileNum, fileNum;
465         otherFileNum = shared->otherFileNum;
466         fileNum = shared->pkgFileNum;
467
468         if (otherStates[otherFileNum] != RPMFILE_STATE_NORMAL)
469             continue;
470
471         fi->actions[fileNum] = FA_SKIP;
472     }
473
474     mi = rpmdbFreeIterator(mi);
475
476     return 0;
477 }
478
479 /**
480  * Update disk space needs on each partition for this package.
481  */
482 /* XXX only ts->{probs,di} modified */
483 static void handleOverlappedFiles(const rpmTransactionSet ts, TFI_t fi)
484         /*@globals fileSystem @*/
485         /*@modifies ts, fi, fileSystem @*/
486 {
487     struct diskspaceInfo * ds = NULL;
488     uint_32 fixupSize = 0;
489     char * filespec = NULL;
490     int fileSpecAlloced = 0;
491     int i, j;
492   
493     for (i = 0; i < fi->fc; i++) {
494         int otherPkgNum, otherFileNum;
495         const TFI_t * recs;
496         int numRecs;
497
498         if (XFA_SKIPPING(fi->actions[i]))
499             continue;
500
501         j = strlen(fi->dnl[fi->dil[i]]) + strlen(fi->bnl[i]) + 1;
502         /*@-branchstate@*/
503         if (j > fileSpecAlloced) {
504             fileSpecAlloced = j * 2;
505             filespec = xrealloc(filespec, fileSpecAlloced);
506         }
507         /*@=branchstate@*/
508
509         (void) stpcpy( stpcpy( filespec, fi->dnl[fi->dil[i]]), fi->bnl[i]);
510
511         if (ts->di) {
512             ds = ts->di;
513             while (ds->bsize && ds->dev != fi->fps[i].entry->dev) ds++;
514             if (!ds->bsize) ds = NULL;
515             fixupSize = 0;
516         }
517
518         /*
519          * Retrieve all records that apply to this file. Note that the
520          * file info records were built in the same order as the packages
521          * will be installed and removed so the records for an overlapped
522          * files will be sorted in exactly the same order.
523          */
524         (void) htGetEntry(ts->ht, &fi->fps[i],
525                         (const void ***) &recs, &numRecs, NULL);
526
527         /*
528          * If this package is being added, look only at other packages
529          * being added -- removed packages dance to a different tune.
530          * If both this and the other package are being added, overlapped
531          * files must be identical (or marked as a conflict). The
532          * disposition of already installed config files leads to
533          * a small amount of extra complexity.
534          *
535          * If this package is being removed, then there are two cases that
536          * need to be worried about:
537          * If the other package is being added, then skip any overlapped files
538          * so that this package removal doesn't nuke the overlapped files
539          * that were just installed.
540          * If both this and the other package are being removed, then each
541          * file removal from preceding packages needs to be skipped so that
542          * the file removal occurs only on the last occurence of an overlapped
543          * file in the transaction set.
544          *
545          */
546
547         /* Locate this overlapped file in the set of added/removed packages. */
548         for (j = 0; j < numRecs && recs[j] != fi; j++)
549             {};
550
551         /* Find what the previous disposition of this file was. */
552         otherFileNum = -1;                      /* keep gcc quiet */
553         for (otherPkgNum = j - 1; otherPkgNum >= 0; otherPkgNum--) {
554             /* Added packages need only look at other added packages. */
555             if (fi->type == TR_ADDED && recs[otherPkgNum]->type != TR_ADDED)
556                 /*@innercontinue@*/ continue;
557
558             /* TESTME: there are more efficient searches in the world... */
559             for (otherFileNum = 0; otherFileNum < recs[otherPkgNum]->fc;
560                  otherFileNum++) {
561
562                 /* If the addresses are the same, so are the values. */
563                 if ((fi->fps + i) == (recs[otherPkgNum]->fps + otherFileNum))
564                     /*@innerbreak@*/ break;
565
566                 /* Otherwise, compare fingerprints by value. */
567                 /*@-nullpass@*/ /* LCL: looks good to me */
568                 if (FP_EQUAL(fi->fps[i], recs[otherPkgNum]->fps[otherFileNum]))
569                     /*@innerbreak@*/ break;
570                 /*@=nullpass@*/
571
572             }
573             /* XXX is this test still necessary? */
574             if (recs[otherPkgNum]->actions[otherFileNum] != FA_UNKNOWN)
575                 /*@innerbreak@*/ break;
576         }
577
578         switch (fi->type) {
579         case TR_ADDED:
580           { struct stat sb;
581             if (otherPkgNum < 0) {
582                 /* XXX is this test still necessary? */
583                 if (fi->actions[i] != FA_UNKNOWN)
584                     /*@switchbreak@*/ break;
585                 if ((fi->fflags[i] & RPMFILE_CONFIG) && 
586                         !lstat(filespec, &sb)) {
587                     /* Here is a non-overlapped pre-existing config file. */
588                     fi->actions[i] = (fi->fflags[i] & RPMFILE_NOREPLACE)
589                         ? FA_ALTNAME : FA_BACKUP;
590                 } else {
591                     fi->actions[i] = FA_CREATE;
592                 }
593                 /*@switchbreak@*/ break;
594             }
595
596             /* Mark added overlapped non-identical files as a conflict. */
597             if ((ts->ignoreSet & RPMPROB_FILTER_REPLACENEWFILES)
598              && filecmp(recs[otherPkgNum]->fmodes[otherFileNum],
599                         recs[otherPkgNum]->fmd5s[otherFileNum],
600                         recs[otherPkgNum]->flinks[otherFileNum],
601                         fi->fmodes[i],
602                         fi->fmd5s[i],
603                         fi->flinks[i]))
604             {
605                 rpmProblemSetAppend(ts->probs, RPMPROB_NEW_FILE_CONFLICT,
606                         fiGetNVR(fi), fi->key,
607                         filespec, NULL,
608                         fiGetNVR(recs[otherPkgNum]),
609                         0);
610             }
611
612             /* Try to get the disk accounting correct even if a conflict. */
613             fixupSize = recs[otherPkgNum]->fsizes[otherFileNum];
614
615             if ((fi->fflags[i] & RPMFILE_CONFIG) && !lstat(filespec, &sb)) {
616                 /* Here is an overlapped  pre-existing config file. */
617                 fi->actions[i] = (fi->fflags[i] & RPMFILE_NOREPLACE)
618                         ? FA_ALTNAME : FA_SKIP;
619             } else {
620                 fi->actions[i] = FA_CREATE;
621             }
622           } /*@switchbreak@*/ break;
623         case TR_REMOVED:
624             if (otherPkgNum >= 0) {
625                 /* Here is an overlapped added file we don't want to nuke. */
626                 if (recs[otherPkgNum]->actions[otherFileNum] != FA_ERASE) {
627                     /* On updates, don't remove files. */
628                     fi->actions[i] = FA_SKIP;
629                     /*@switchbreak@*/ break;
630                 }
631                 /* Here is an overlapped removed file: skip in previous. */
632                 recs[otherPkgNum]->actions[otherFileNum] = FA_SKIP;
633             }
634             if (XFA_SKIPPING(fi->actions[i]))
635                 /*@switchbreak@*/ break;
636             if (fi->fstates && fi->fstates[i] != RPMFILE_STATE_NORMAL)
637                 /*@switchbreak@*/ break;
638             if (!(S_ISREG(fi->fmodes[i]) && (fi->fflags[i] & RPMFILE_CONFIG))) {
639                 fi->actions[i] = FA_ERASE;
640                 /*@switchbreak@*/ break;
641             }
642                 
643             /* Here is a pre-existing modified config file that needs saving. */
644             {   char mdsum[50];
645                 if (!mdfile(filespec, mdsum) && strcmp(fi->fmd5s[i], mdsum)) {
646                     fi->actions[i] = FA_BACKUP;
647                     /*@switchbreak@*/ break;
648                 }
649             }
650             fi->actions[i] = FA_ERASE;
651             /*@switchbreak@*/ break;
652         }
653
654         if (ds) {
655             uint_32 s = BLOCK_ROUND(fi->fsizes[i], ds->bsize);
656
657             switch (fi->actions[i]) {
658               case FA_BACKUP:
659               case FA_SAVE:
660               case FA_ALTNAME:
661                 ds->ineeded++;
662                 ds->bneeded += s;
663                 /*@switchbreak@*/ break;
664
665             /*
666              * FIXME: If two packages share a file (same md5sum), and
667              * that file is being replaced on disk, will ds->bneeded get
668              * decremented twice? Quite probably!
669              */
670               case FA_CREATE:
671                 ds->bneeded += s;
672                 ds->bneeded -= BLOCK_ROUND(fi->replacedSizes[i], ds->bsize);
673                 /*@switchbreak@*/ break;
674
675               case FA_ERASE:
676                 ds->ineeded--;
677                 ds->bneeded -= s;
678                 /*@switchbreak@*/ break;
679
680               default:
681                 /*@switchbreak@*/ break;
682             }
683
684             ds->bneeded -= BLOCK_ROUND(fixupSize, ds->bsize);
685         }
686     }
687     filespec = _free(filespec);
688 }
689
690 /**
691  */
692 static int ensureOlder(rpmTransactionSet ts,
693                 const Header h, /*@null@*/ const Header old,
694                 /*@dependent@*/ /*@null@*/ const void * key)
695         /*@modifies ts @*/
696 {
697     int result, rc = 0;
698
699     if (old == NULL) return 1;
700
701     result = rpmVersionCompare(old, h);
702     if (result <= 0)
703         rc = 0;
704     else if (result > 0) {
705         rc = 1;
706         /*@-evalorder@*/ /* LCL: is confused */
707         rpmProblemSetAppend(ts->probs, RPMPROB_OLDPACKAGE,
708                 hGetNVR(h, NULL), key,
709                 NULL, NULL,
710                 hGetNVR(old, NULL),
711                 0);
712         /*@=evalorder@*/
713     }
714
715     return rc;
716 }
717
718 /**
719  */
720 static void skipFiles(const rpmTransactionSet ts, TFI_t fi)
721         /*@globals rpmGlobalMacroContext @*/
722         /*@modifies fi, rpmGlobalMacroContext @*/
723 {
724     int noDocs = (ts->transFlags & RPMTRANS_FLAG_NODOCS);
725     char ** netsharedPaths = NULL;
726     const char ** languages;
727     const char * dn, * bn;
728     int dnlen, bnlen, ix;
729     const char * s;
730     int * drc;
731     char * dff;
732     int i, j;
733
734     if (!noDocs)
735         noDocs = rpmExpandNumeric("%{_excludedocs}");
736
737     {   const char *tmpPath = rpmExpand("%{_netsharedpath}", NULL);
738         /*@-branchstate@*/
739         if (tmpPath && *tmpPath != '%')
740             netsharedPaths = splitString(tmpPath, strlen(tmpPath), ':');
741         /*@=branchstate@*/
742         tmpPath = _free(tmpPath);
743     }
744
745     s = rpmExpand("%{_install_langs}", NULL);
746     /*@-branchstate@*/
747     if (!(s && *s != '%'))
748         s = _free(s);
749     if (s) {
750         languages = (const char **) splitString(s, strlen(s), ':');
751         s = _free(s);
752     } else
753         languages = NULL;
754     /*@=branchstate@*/
755
756     /* Compute directory refcount, skip directory if now empty. */
757     drc = alloca(fi->dc * sizeof(*drc));
758     memset(drc, 0, fi->dc * sizeof(*drc));
759     dff = alloca(fi->dc * sizeof(*dff));
760     memset(dff, 0, fi->dc * sizeof(*dff));
761
762     for (i = 0; i < fi->fc; i++) {
763         char **nsp;
764
765         bn = fi->bnl[i];
766         bnlen = strlen(bn);
767         ix = fi->dil[i];
768         dn = fi->dnl[ix];
769         dnlen = strlen(dn);
770
771         drc[ix]++;
772
773         /* Don't bother with skipped files */
774         if (XFA_SKIPPING(fi->actions[i])) {
775             drc[ix]--;
776             continue;
777         }
778
779         /*
780          * Skip net shared paths.
781          * Net shared paths are not relative to the current root (though
782          * they do need to take package relocations into account).
783          */
784         for (nsp = netsharedPaths; nsp && *nsp; nsp++) {
785             int len;
786
787             len = strlen(*nsp);
788             if (dnlen >= len) {
789                 if (strncmp(dn, *nsp, len))
790                     /*@innercontinue@*/ continue;
791                 /* Only directories or complete file paths can be net shared */
792                 if (!(dn[len] == '/' || dn[len] == '\0'))
793                     /*@innercontinue@*/ continue;
794             } else {
795                 if (len < (dnlen + bnlen))
796                     /*@innercontinue@*/ continue;
797                 if (strncmp(dn, *nsp, dnlen))
798                     /*@innercontinue@*/ continue;
799                 if (strncmp(bn, (*nsp) + dnlen, bnlen))
800                     /*@innercontinue@*/ continue;
801                 len = dnlen + bnlen;
802                 /* Only directories or complete file paths can be net shared */
803                 if (!((*nsp)[len] == '/' || (*nsp)[len] == '\0'))
804                     /*@innercontinue@*/ continue;
805             }
806
807             /*@innerbreak@*/ break;
808         }
809
810         if (nsp && *nsp) {
811             drc[ix]--;  dff[ix] = 1;
812             fi->actions[i] = FA_SKIPNETSHARED;
813             continue;
814         }
815
816         /*
817          * Skip i18n language specific files.
818          */
819         if (fi->flangs && languages && *fi->flangs[i]) {
820             const char **lang, *l, *le;
821             for (lang = languages; *lang != NULL; lang++) {
822                 if (!strcmp(*lang, "all"))
823                     /*@innerbreak@*/ break;
824                 for (l = fi->flangs[i]; *l != '\0'; l = le) {
825                     for (le = l; *le != '\0' && *le != '|'; le++)
826                         {};
827                     if ((le-l) > 0 && !strncmp(*lang, l, (le-l)))
828                         /*@innerbreak@*/ break;
829                     if (*le == '|') le++;       /* skip over | */
830                 }
831                 if (*l != '\0')
832                     /*@innerbreak@*/ break;
833             }
834             if (*lang == NULL) {
835                 drc[ix]--;      dff[ix] = 1;
836                 fi->actions[i] = FA_SKIPNSTATE;
837                 continue;
838             }
839         }
840
841         /*
842          * Skip documentation if requested.
843          */
844         if (noDocs && (fi->fflags[i] & RPMFILE_DOC)) {
845             drc[ix]--;  dff[ix] = 1;
846             fi->actions[i] = FA_SKIPNSTATE;
847             continue;
848         }
849     }
850
851     /* Skip (now empty) directories that had skipped files. */
852     for (j = 0; j < fi->dc; j++) {
853
854         if (drc[j]) continue;   /* dir still has files. */
855         if (!dff[j]) continue;  /* dir was not emptied here. */
856         
857         /* Find parent directory and basename. */
858         dn = fi->dnl[j];        dnlen = strlen(dn) - 1;
859         bn = dn + dnlen;        bnlen = 0;
860         while (bn > dn && bn[-1] != '/') {
861                 bnlen++;
862                 dnlen--;
863                 bn--;
864         }
865
866         /* If explicitly included in the package, skip the directory. */
867         for (i = 0; i < fi->fc; i++) {
868             const char * dir;
869
870             if (XFA_SKIPPING(fi->actions[i]))
871                 /*@innercontinue@*/ continue;
872             if (whatis(fi->fmodes[i]) != XDIR)
873                 /*@innercontinue@*/ continue;
874             dir = fi->dnl[fi->dil[i]];
875             if (strlen(dir) != dnlen)
876                 /*@innercontinue@*/ continue;
877             if (strncmp(dir, dn, dnlen))
878                 /*@innercontinue@*/ continue;
879             if (strlen(fi->bnl[i]) != bnlen)
880                 /*@innercontinue@*/ continue;
881             if (strncmp(fi->bnl[i], bn, bnlen))
882                 /*@innercontinue@*/ continue;
883             rpmMessage(RPMMESS_DEBUG, _("excluding directory %s\n"), dn);
884             fi->actions[i] = FA_SKIPNSTATE;
885             /*@innerbreak@*/ break;
886         }
887     }
888
889     if (netsharedPaths) freeSplitString(netsharedPaths);
890 #ifdef  DYING   /* XXX freeFi will deal with this later. */
891     fi->flangs = _free(fi->flangs);
892 #endif
893     if (languages) freeSplitString((char **)languages);
894 }
895
896 /**
897  * Return next transaction element's file info.
898  * @param tei           transaction element iterator
899  * @return              nest transaction element file info, NULL on termination
900  */
901 /*@unused@*/ static inline
902 TFI_t teNextFi(teIterator tei)
903         /*@modifies tei @*/
904 {
905     TFI_t fi = NULL;
906
907     if (teNextIterator(tei) != NULL && tei->ocsave != -1)
908         fi = tei->ts->flList + tei->ocsave;
909     /*@-compdef -onlytrans -usereleased@*/ /* FIX: ts->flList may be released */
910     return fi;
911     /*@=compdef =onlytrans =usereleased@*/
912 }
913
914 #define NOTIFY(_ts, _al)        if ((_ts)->notify) (void) (_ts)->notify _al
915
916 int rpmRunTransactions( rpmTransactionSet ts,
917                         rpmCallbackFunction notify, rpmCallbackData notifyData,
918                         rpmProblemSet okProbs, rpmProblemSet * newProbs,
919                         rpmtransFlags transFlags, rpmprobFilterFlags ignoreSet)
920 {
921     int i, j;
922     int ourrc = 0;
923     int totalFileCount = 0;
924     TFI_t fi;
925     struct diskspaceInfo * dip;
926     struct sharedFileInfo * shared, * sharedList;
927     int numShared;
928     int nexti;
929     alKey pkgKey, lastKey;
930     int oc;
931     transactionElement p;
932     fingerPrintCache fpc;
933     struct psm_s psmbuf;
934     PSM_t psm = &psmbuf;
935     teIterator tei;
936     int xx;
937
938 int keep_header = 1;    /* XXX rpmProblemSetAppend prevents dumping headers. */
939
940     /* FIXME: what if the same package is included in ts twice? */
941
942     ts->transFlags = transFlags;
943     if (ts->transFlags & RPMTRANS_FLAG_NOSCRIPTS)
944         ts->transFlags |= (_noTransScripts | _noTransTriggers);
945     if (ts->transFlags & RPMTRANS_FLAG_NOTRIGGERS)
946         ts->transFlags |= _noTransTriggers;
947
948     /* XXX MULTILIB is broken, as packages can and do execute /sbin/ldconfig. */
949     if (ts->transFlags & (RPMTRANS_FLAG_JUSTDB | RPMTRANS_FLAG_MULTILIB))
950         ts->transFlags |= (_noTransScripts | _noTransTriggers);
951
952     ts->notify = notify;
953     ts->notifyData = notifyData;
954     /*@-assignexpose@*/
955     ts->probs = *newProbs = rpmProblemSetCreate();
956     /*@=assignexpose@*/
957     ts->ignoreSet = ignoreSet;
958     ts->currDir = _free(ts->currDir);
959     ts->currDir = currentDirectory();
960     ts->chrootDone = 0;
961     if (ts->rpmdb) ts->rpmdb->db_chrootDone = 0;
962     ts->id = (int_32) time(NULL);
963
964     memset(psm, 0, sizeof(*psm));
965     /*@-assignexpose@*/
966     psm->ts = rpmtsLink(ts, "tsRun");
967     /*@=assignexpose@*/
968
969     /* Get available space on mounted file systems. */
970     if (!(ts->ignoreSet & RPMPROB_FILTER_DISKSPACE) &&
971                 !rpmGetFilesystemList(&ts->filesystems, &ts->filesystemCount)) {
972         struct stat sb;
973
974         ts->di = _free(ts->di);
975         dip = ts->di = xcalloc((ts->filesystemCount + 1), sizeof(*ts->di));
976
977         for (i = 0; (i < ts->filesystemCount) && dip; i++) {
978 #if STATFS_IN_SYS_STATVFS
979             struct statvfs sfb;
980             memset(&sfb, 0, sizeof(sfb));
981             if (statvfs(ts->filesystems[i], &sfb))
982 #else
983             struct statfs sfb;
984 #  if STAT_STATFS4
985 /* This platform has the 4-argument version of the statfs call.  The last two
986  * should be the size of struct statfs and 0, respectively.  The 0 is the
987  * filesystem type, and is always 0 when statfs is called on a mounted
988  * filesystem, as we're doing.
989  */
990             memset(&sfb, 0, sizeof(sfb));
991             if (statfs(ts->filesystems[i], &sfb, sizeof(sfb), 0))
992 #  else
993             memset(&sfb, 0, sizeof(sfb));
994             if (statfs(ts->filesystems[i], &sfb))
995 #  endif
996 #endif
997             {
998                 dip = NULL;
999             } else {
1000                 ts->di[i].bsize = sfb.f_bsize;
1001                 ts->di[i].bneeded = 0;
1002                 ts->di[i].ineeded = 0;
1003 #ifdef STATFS_HAS_F_BAVAIL
1004                 ts->di[i].bavail = sfb.f_bavail;
1005 #else
1006 /* FIXME: the statfs struct doesn't have a member to tell how many blocks are
1007  * available for non-superusers.  f_blocks - f_bfree is probably too big, but
1008  * it's about all we can do.
1009  */
1010                 ts->di[i].bavail = sfb.f_blocks - sfb.f_bfree;
1011 #endif
1012                 /* XXX Avoid FAT and other file systems that have not inodes. */
1013                 ts->di[i].iavail = !(sfb.f_ffree == 0 && sfb.f_files == 0)
1014                                 ? sfb.f_ffree : -1;
1015
1016                 xx = stat(ts->filesystems[i], &sb);
1017                 ts->di[i].dev = sb.st_dev;
1018             }
1019         }
1020
1021         if (dip) ts->di[i].bsize = 0;
1022     }
1023
1024     /* ===============================================
1025      * For packages being installed:
1026      * - verify package arch/os.
1027      * - verify package epoch:version-release is newer.
1028      * - count files.
1029      * For packages being removed:
1030      * - count files.
1031      */
1032     /* The ordering doesn't matter here */
1033     tei = teInitIterator(ts);
1034     while ((p = teNext(tei, TR_ADDED)) != NULL) {
1035         const char * n, * v, * r;
1036         fnpyKey key;
1037         rpmdbMatchIterator mi;
1038         Header h;
1039
1040         pkgKey = p->u.addedKey;
1041
1042         h = alGetHeader(ts->addedPackages, pkgKey, 0);
1043         if (h == NULL)  /* XXX can't happen */
1044             continue;
1045
1046         (void) headerNVR(h, &n, &v, &r);
1047         key = p->key;
1048
1049         if (!archOkay(h) && !(ts->ignoreSet & RPMPROB_FILTER_IGNOREARCH))
1050             rpmProblemSetAppend(ts->probs, RPMPROB_BADARCH,
1051                         hGetNVR(h, NULL), key,
1052                         NULL, NULL, NULL, 0);
1053
1054         if (!osOkay(h) && !(ts->ignoreSet & RPMPROB_FILTER_IGNOREOS))
1055             rpmProblemSetAppend(ts->probs, RPMPROB_BADOS,
1056                         hGetNVR(h, NULL), key,
1057                         NULL, NULL, NULL, 0);
1058
1059         if (!(ts->ignoreSet & RPMPROB_FILTER_OLDPACKAGE)) {
1060             Header oldH;
1061             mi = rpmtsInitIterator(ts, RPMTAG_NAME, n, 0);
1062             while ((oldH = rpmdbNextIterator(mi)) != NULL)
1063                 xx = ensureOlder(ts, h, oldH, key);
1064             mi = rpmdbFreeIterator(mi);
1065         }
1066
1067         /* XXX multilib should not display "already installed" problems */
1068         if (!(ts->ignoreSet & RPMPROB_FILTER_REPLACEPKG)
1069 #ifdef DYING    /* XXX MULTILIB multiLib from transactionElement */
1070          && !alGetMultiLib(ts->addedPackages, i)
1071 #endif
1072         ) {
1073             mi = rpmtsInitIterator(ts, RPMTAG_NAME, n, 0);
1074             xx = rpmdbSetIteratorRE(mi, RPMTAG_VERSION, RPMMIRE_DEFAULT, v);
1075             xx = rpmdbSetIteratorRE(mi, RPMTAG_RELEASE, RPMMIRE_DEFAULT, r);
1076
1077             while (rpmdbNextIterator(mi) != NULL) {
1078                 rpmProblemSetAppend(ts->probs, RPMPROB_PKG_INSTALLED,
1079                         hGetNVR(h, NULL), key,
1080                         NULL, NULL, NULL, 0);
1081                 /*@innerbreak@*/ break;
1082             }
1083             mi = rpmdbFreeIterator(mi);
1084         }
1085
1086         totalFileCount += alGetFilesCount(ts->addedPackages, pkgKey);
1087
1088         h = headerFree(h, "alGetHeader (rpmtsRun sanity)");
1089
1090     }
1091     tei = teFreeIterator(tei);
1092
1093     /* FIXME: it seems a bit silly to read in all of these headers twice */
1094     /* The ordering doesn't matter here */
1095     if (ts->numRemovedPackages > 0) {
1096         rpmdbMatchIterator mi;
1097         Header h;
1098         int fileCount;
1099
1100         mi = rpmtsInitIterator(ts, RPMDBI_PACKAGES, NULL, 0);
1101         xx = rpmdbAppendIterator(mi, ts->removedPackages, ts->numRemovedPackages);
1102         while ((h = rpmdbNextIterator(mi)) != NULL) {
1103             if (headerGetEntry(h, RPMTAG_BASENAMES, NULL, NULL, &fileCount))
1104                 totalFileCount += fileCount;
1105         }
1106         mi = rpmdbFreeIterator(mi);
1107     }
1108
1109     /* ===============================================
1110      * Initialize transaction element file info for package:
1111      */
1112     ts->flEntries = alGetSize(ts->addedPackages) + ts->numRemovedPackages;
1113     ts->flList = xcalloc(ts->flEntries, sizeof(*ts->flList));
1114
1115     /*
1116      * FIXME?: we'd be better off assembling one very large file list and
1117      * calling fpLookupList only once. I'm not sure that the speedup is
1118      * worth the trouble though.
1119      */
1120     tei = teInitIterator(ts);
1121     while ((fi = teNextFi(tei)) != NULL) {
1122
1123         oc = teGetOc(tei);
1124         fi->magic = TFIMAGIC;
1125
1126         fi->type = ts->order[oc].type;
1127
1128         /*@-branchstate@*/
1129         switch (fi->type) {
1130         case TR_ADDED:
1131             fi->record = 0;
1132
1133             pkgKey = ts->order[oc].u.addedKey;
1134
1135             fi->h = alGetHeader(ts->addedPackages, pkgKey, 1);
1136 #ifdef DYING    /* XXX MULTILIB multiLib from transactionElement */
1137             fi->multiLib = alGetMultiLib(ts->addedPackages, i);
1138 #else
1139             fi->multiLib = ts->order[oc].multiLib;
1140 #endif
1141
1142 /*@i@*/     fi->key = ts->order[oc].key;
1143             fi->relocs = ts->order[oc].relocs;
1144 /*@i@*/     fi->fd = ts->order[oc].fd;
1145
1146             /* XXX availablePackage can be dumped here XXX */
1147
1148             /* XXX header arg unused. */
1149             loadFi(ts, fi, fi->h, keep_header);
1150
1151             if (fi->fc == 0)
1152                 continue;
1153
1154             /* Skip netshared paths, not our i18n files, and excluded docs */
1155             skipFiles(ts, fi);
1156             /*@switchbreak@*/ break;
1157         case TR_REMOVED:
1158             fi->record = ts->order[oc].u.removed.dboffset;
1159             /* Retrieve erased package header from the database. */
1160             {   rpmdbMatchIterator mi;
1161
1162                 mi = rpmtsInitIterator(ts, RPMDBI_PACKAGES,
1163                                 &fi->record, sizeof(fi->record));
1164                 if ((fi->h = rpmdbNextIterator(mi)) != NULL)
1165                     fi->h = headerLink(fi->h,  "TR_REMOVED loadFi");
1166                 mi = rpmdbFreeIterator(mi);
1167             }
1168             if (fi->h == NULL) {
1169                 /* ACK! */
1170                 continue;
1171             }
1172             /* XXX header arg unused. */
1173             loadFi(ts, fi, fi->h, 0);
1174             /*@switchbreak@*/ break;
1175         }
1176         /*@=branchstate@*/
1177
1178         if (fi->fc)
1179             fi->fps = xmalloc(fi->fc * sizeof(*fi->fps));
1180     }
1181     tei = teFreeIterator(tei);
1182
1183     if (!ts->chrootDone) {
1184         xx = chdir("/");
1185         /*@-superuser -noeffect @*/
1186         xx = chroot(ts->rootDir);
1187         /*@=superuser =noeffect @*/
1188         ts->chrootDone = 1;
1189         if (ts->rpmdb) ts->rpmdb->db_chrootDone = 1;
1190         /*@-onlytrans@*/
1191         /*@-mods@*/
1192         chroot_prefix = ts->rootDir;
1193         /*@=mods@*/
1194         /*@=onlytrans@*/
1195     }
1196
1197     ts->ht = htCreate(totalFileCount * 2, 0, 0, fpHashFunction, fpEqual);
1198     fpc = fpCacheCreate(totalFileCount);
1199
1200     /* ===============================================
1201      * Add fingerprint for each file not skipped.
1202      */
1203     tei = teInitIterator(ts);
1204     while ((fi = teNextFi(tei)) != NULL) {
1205         fpLookupList(fpc, fi->dnl, fi->bnl, fi->dil, fi->fc, fi->fps);
1206         for (i = 0; i < fi->fc; i++) {
1207             if (XFA_SKIPPING(fi->actions[i]))
1208                 /*@innercontinue@*/ continue;
1209             /*@-dependenttrans@*/
1210             htAddEntry(ts->ht, fi->fps + i, fi);
1211             /*@=dependenttrans@*/
1212         }
1213     }
1214     tei = teFreeIterator(tei);
1215
1216     /*@-noeffectuncon @*/ /* FIX: check rc */
1217     NOTIFY(ts, (NULL, RPMCALLBACK_TRANS_START, 6, ts->flEntries,
1218         NULL, ts->notifyData));
1219     /*@=noeffectuncon@*/
1220
1221     /* ===============================================
1222      * Compute file disposition for each package in transaction set.
1223      */
1224     tei = teInitIterator(ts);
1225     while ((fi = teNextFi(tei)) != NULL) {
1226         dbiIndexSet * matches;
1227         int knownBad;
1228
1229         /*@-noeffectuncon @*/ /* FIX: check rc */
1230         NOTIFY(ts, (NULL, RPMCALLBACK_TRANS_PROGRESS, (fi - ts->flList),
1231                         ts->flEntries, NULL, ts->notifyData));
1232         /*@=noeffectuncon@*/
1233
1234         if (fi->fc == 0) continue;
1235
1236         /* Extract file info for all files in this package from the database. */
1237         matches = xcalloc(fi->fc, sizeof(*matches));
1238         if (rpmdbFindFpList(ts->rpmdb, fi->fps, matches, fi->fc)) {
1239             psm->ts = rpmtsUnlink(ts, "tsRun (rpmFindFpList fail)");
1240             return 1;   /* XXX WTFO? */
1241         }
1242
1243         numShared = 0;
1244         for (i = 0; i < fi->fc; i++)
1245             numShared += dbiIndexSetCount(matches[i]);
1246
1247         /* Build sorted file info list for this package. */
1248         shared = sharedList = xcalloc((numShared + 1), sizeof(*sharedList));
1249         for (i = 0; i < fi->fc; i++) {
1250             /*
1251              * Take care not to mark files as replaced in packages that will
1252              * have been removed before we will get here.
1253              */
1254             for (j = 0; j < dbiIndexSetCount(matches[i]); j++) {
1255                 int k, ro;
1256                 ro = dbiIndexRecordOffset(matches[i], j);
1257                 knownBad = 0;
1258                 for (k = 0; ro != knownBad && k < ts->orderCount; k++) {
1259                     switch (ts->order[k].type) {
1260                     case TR_REMOVED:
1261                         if (ts->order[k].u.removed.dboffset == ro)
1262                             knownBad = ro;
1263                         /*@switchbreak@*/ break;
1264                     case TR_ADDED:
1265                         /*@switchbreak@*/ break;
1266                     }
1267                 }
1268
1269                 shared->pkgFileNum = i;
1270                 shared->otherPkg = dbiIndexRecordOffset(matches[i], j);
1271                 shared->otherFileNum = dbiIndexRecordFileNumber(matches[i], j);
1272                 shared->isRemoved = (knownBad == ro);
1273                 shared++;
1274             }
1275             matches[i] = dbiFreeIndexSet(matches[i]);
1276         }
1277         numShared = shared - sharedList;
1278         shared->otherPkg = -1;
1279         matches = _free(matches);
1280
1281         /* Sort file info by other package index (otherPkg) */
1282         qsort(sharedList, numShared, sizeof(*shared), sharedCmp);
1283
1284         /* For all files from this package that are in the database ... */
1285         for (i = 0; i < numShared; i = nexti) {
1286             int beingRemoved;
1287
1288             shared = sharedList + i;
1289
1290             /* Find the end of the files in the other package. */
1291             for (nexti = i + 1; nexti < numShared; nexti++) {
1292                 if (sharedList[nexti].otherPkg != shared->otherPkg)
1293                     /*@innerbreak@*/ break;
1294             }
1295
1296             /* Is this file from a package being removed? */
1297             beingRemoved = 0;
1298             for (j = 0; j < ts->numRemovedPackages; j++) {
1299                 if (ts->removedPackages[j] != shared->otherPkg)
1300                     /*@innercontinue@*/ continue;
1301                 beingRemoved = 1;
1302                 /*@innerbreak@*/ break;
1303             }
1304
1305             /* Determine the fate of each file. */
1306             switch (fi->type) {
1307             case TR_ADDED:
1308                 xx = handleInstInstalledFiles(ts, fi, shared, nexti - i,
1309         !(beingRemoved || (ts->ignoreSet & RPMPROB_FILTER_REPLACEOLDFILES)));
1310                 /*@switchbreak@*/ break;
1311             case TR_REMOVED:
1312                 if (!beingRemoved)
1313                     xx = handleRmvdInstalledFiles(ts, fi, shared, nexti - i);
1314                 /*@switchbreak@*/ break;
1315             }
1316         }
1317
1318         free(sharedList);
1319
1320         /* Update disk space needs on each partition for this package. */
1321         handleOverlappedFiles(ts, fi);
1322
1323         /* Check added package has sufficient space on each partition used. */
1324         switch (fi->type) {
1325         case TR_ADDED:
1326             if (!(ts->di && fi->fc))
1327                 /*@switchbreak@*/ break;
1328             for (i = 0; i < ts->filesystemCount; i++) {
1329
1330                 dip = ts->di + i;
1331
1332                 /* XXX Avoid FAT and other file systems that have not inodes. */
1333                 if (dip->iavail <= 0)
1334                     /*@innercontinue@*/ continue;
1335
1336                 if (adj_fs_blocks(dip->bneeded) > dip->bavail)
1337                     rpmProblemSetAppend(ts->probs, RPMPROB_DISKSPACE,
1338                                 fiGetNVR(fi), fi->key,
1339                                 ts->filesystems[i], NULL, NULL,
1340                    (adj_fs_blocks(dip->bneeded) - dip->bavail) * dip->bsize);
1341
1342                 if (adj_fs_blocks(dip->ineeded) > dip->iavail)
1343                     rpmProblemSetAppend(ts->probs, RPMPROB_DISKNODES,
1344                                 fiGetNVR(fi), fi->key,
1345                                 ts->filesystems[i], NULL, NULL,
1346                     (adj_fs_blocks(dip->ineeded) - dip->iavail));
1347             }
1348             /*@switchbreak@*/ break;
1349         case TR_REMOVED:
1350             /*@switchbreak@*/ break;
1351         }
1352     }
1353     tei = teFreeIterator(tei);
1354
1355     if (ts->chrootDone) {
1356         /*@-superuser -noeffect @*/
1357         xx = chroot(".");
1358         /*@=superuser =noeffect @*/
1359         ts->chrootDone = 0;
1360         if (ts->rpmdb) ts->rpmdb->db_chrootDone = 0;
1361         /*@-mods@*/
1362         chroot_prefix = NULL;
1363         /*@=mods@*/
1364         xx = chdir(ts->currDir);
1365     }
1366
1367     /*@-noeffectuncon @*/ /* FIX: check rc */
1368     NOTIFY(ts, (NULL, RPMCALLBACK_TRANS_STOP, 6, ts->flEntries,
1369         NULL, ts->notifyData));
1370     /*@=noeffectuncon @*/
1371
1372     /* ===============================================
1373      * Free unused memory as soon as possible.
1374      */
1375
1376     tei = teInitIterator(ts);
1377     while ((fi = teNextFi(tei)) != NULL) {
1378         if (fi->fc == 0)
1379             continue;
1380         fi->fps = _free(fi->fps);
1381     }
1382     tei = teFreeIterator(tei);
1383
1384     fpCacheFree(fpc);
1385     htFree(ts->ht);
1386     ts->ht = NULL;
1387
1388     /* ===============================================
1389      * If unfiltered problems exist, free memory and return.
1390      */
1391     if ((ts->transFlags & RPMTRANS_FLAG_BUILD_PROBS)
1392      || (ts->probs->numProblems &&
1393                 (okProbs != NULL || rpmProblemSetTrim(ts->probs, okProbs)))
1394        )
1395     {
1396         *newProbs = ts->probs;
1397
1398         ts->flList = freeFl(ts, ts->flList);
1399         ts->flEntries = 0;
1400         if (psm->ts != NULL)
1401             psm->ts = rpmtsUnlink(psm->ts, "tsRun (problems)");
1402         /*@-nullstate@*/ /* FIX: ts->flList may be NULL */
1403         return ts->orderCount;
1404         /*@=nullstate@*/
1405     }
1406
1407     /* ===============================================
1408      * Save removed files before erasing.
1409      */
1410     if (ts->transFlags & (RPMTRANS_FLAG_DIRSTASH | RPMTRANS_FLAG_REPACKAGE)) {
1411         tei = teInitIterator(ts);
1412         while ((fi = teNextFi(tei)) != NULL) {
1413             switch (fi->type) {
1414             case TR_ADDED:
1415                 /*@switchbreak@*/ break;
1416             case TR_REMOVED:
1417                 if (ts->transFlags & RPMTRANS_FLAG_REPACKAGE) {
1418                     psm->fi = rpmfiLink(fi, "tsRepackage");
1419                     xx = psmStage(psm, PSM_PKGSAVE);
1420                     (void) rpmfiUnlink(fi, "tsRepackage");
1421                     psm->fi = NULL;
1422                 }
1423                 /*@switchbreak@*/ break;
1424             }
1425         }
1426         tei = teFreeIterator(tei);
1427     }
1428
1429     /* ===============================================
1430      * Install and remove packages.
1431      */
1432
1433     lastKey = (alKey)-2;        /* erased packages have -1 */
1434     tei = teInitIterator(ts);
1435     /*@-branchstate@*/ /* FIX: fi reload needs work */
1436     while ((fi = teNextFi(tei)) != NULL) {
1437         Header h;
1438         int gotfd;
1439
1440         oc = teGetOc(tei);
1441         gotfd = 0;
1442         psm->fi = rpmfiLink(fi, "tsInstall");
1443         switch (fi->type) {
1444         case TR_ADDED:
1445
1446             pkgKey = ts->order[oc].u.addedKey;
1447
1448             rpmMessage(RPMMESS_DEBUG, "========== +++ %s-%s-%s\n",
1449                         fi->name, fi->version, fi->release);
1450             h = (fi->h ? headerLink(fi->h, "TR_ADDED install") : NULL);
1451             /*@-branchstate@*/
1452             if (fi->fd == NULL) {
1453                 /*@-noeffectuncon @*/ /* FIX: ??? */
1454                 fi->fd = ts->notify(fi->h, RPMCALLBACK_INST_OPEN_FILE, 0, 0,
1455                                 fi->key, ts->notifyData);
1456                 /*@=noeffectuncon @*/
1457                 if (fi->fd != NULL) {
1458                     rpmRC rpmrc;
1459
1460                     h = headerFree(h, "TR_ADDED install");
1461
1462                     /*@-mustmod@*/      /* LCL: segfault */
1463                     rpmrc = rpmReadPackageFile(ts, fi->fd,
1464                                 "rpmRunTransactions", &h);
1465                     /*@=mustmod@*/
1466
1467                     if (!(rpmrc == RPMRC_OK || rpmrc == RPMRC_BADSIZE)) {
1468                         /*@-noeffectuncon @*/ /* FIX: check rc */
1469                         (void) ts->notify(fi->h, RPMCALLBACK_INST_CLOSE_FILE,
1470                                         0, 0,
1471                                         fi->key, ts->notifyData);
1472                         /*@=noeffectuncon @*/
1473                         fi->fd = NULL;
1474                         ourrc++;
1475                     } else if (fi->h != NULL) {
1476                         Header foo = relocateFileList(ts, fi, h, NULL);
1477                         h = headerFree(h, "TR_ADDED read free");
1478                         h = headerLink(foo, "TR_ADDED relocate xfer");
1479                         foo = headerFree(foo, "TR_ADDED relocate");
1480                     }
1481                     if (fi->fd != NULL) gotfd = 1;
1482                 }
1483             }
1484             /*@=branchstate@*/
1485
1486             if (fi->fd != NULL) {
1487                 Header hsave = NULL;
1488
1489                 if (fi->h) {
1490                     hsave = headerLink(fi->h, "TR_ADDED fi->h hsave");
1491                     fi->h = headerFree(fi->h, "TR_ADDED fi->h free");
1492                     fi->h = headerLink(h, "TR_ADDED fi->h link");
1493                 } else {
1494 char * fstates = fi->fstates;
1495 fileAction * actions = fi->actions;
1496 uint_32 multiLib = fi->multiLib;
1497 const void * key = fi->key;
1498 rpmRelocation * relocs = fi->relocs;
1499 FD_t fd = fi->fd;
1500
1501 fi->fstates = NULL;
1502 fi->actions = NULL;
1503 fi->key = NULL;
1504 fi->relocs = NULL;
1505 fi->fd = NULL;
1506                     freeFi(fi);
1507 oc = teGetOc(tei);
1508 fi->magic = TFIMAGIC;
1509 fi->type = ts->order[oc].type;
1510 fi->record = 0;
1511                     loadFi(ts, fi, h, 1);
1512 fi->fstates = _free(fi->fstates);
1513 fi->fstates = fstates;
1514 fi->actions = _free(fi->actions);
1515 fi->actions = actions;
1516 fi->multiLib = multiLib;
1517 fi->key = key;
1518 fi->relocs = relocs;
1519 /*@-newreftrans@*/
1520 /*@i@*/ fi->fd = fd;
1521 /*@=newreftrans@*/
1522
1523                 }
1524                 if (fi->multiLib)
1525                     ts->transFlags |= RPMTRANS_FLAG_MULTILIB;
1526
1527                 if (psmStage(psm, PSM_PKGINSTALL)) {
1528                     ourrc++;
1529                     lastKey = pkgKey;
1530                 }
1531                 fi->h = headerFree(fi->h, "TR_ADDED fi->h free");
1532                 if (hsave) {
1533                     fi->h = headerLink(hsave, "TR_ADDED fi->h restore");
1534                     hsave = headerFree(hsave, "TR_ADDED hsave free");
1535                 }
1536             } else {
1537                 ourrc++;
1538                 lastKey = pkgKey;
1539             }
1540
1541             h = headerFree(h, "TR_ADDED h free");
1542
1543             if (gotfd) {
1544                 /*@-noeffectuncon @*/ /* FIX: check rc */
1545                 (void)ts->notify(fi->h, RPMCALLBACK_INST_CLOSE_FILE, 0, 0,
1546                         fi->key, ts->notifyData);
1547                 /*@=noeffectuncon @*/
1548                 fi->fd = NULL;
1549             }
1550             freeFi(fi);
1551             /*@switchbreak@*/ break;
1552         case TR_REMOVED:
1553             rpmMessage(RPMMESS_DEBUG, "========== --- %s-%s-%s\n",
1554                         fi->name, fi->version, fi->release);
1555             oc = teGetOc(tei);
1556             /* If install failed, then we shouldn't erase. */
1557             if (ts->order[oc].u.removed.dependsOnKey != lastKey) {
1558                 if (psmStage(psm, PSM_PKGERASE))
1559                     ourrc++;
1560             }
1561             freeFi(fi);
1562             /*@switchbreak@*/ break;
1563         }
1564         xx = rpmdbSync(ts->rpmdb);
1565         (void) rpmfiUnlink(fi, "tsInstall");
1566         psm->fi = NULL;
1567     }
1568     /*@=branchstate@*/
1569     tei = teFreeIterator(tei);
1570
1571     ts->flList = freeFl(ts, ts->flList);
1572     ts->flEntries = 0;
1573
1574     psm->ts = rpmtsUnlink(psm->ts, "tsRun");
1575
1576     /*@-nullstate@*/ /* FIX: ts->flList may be NULL */
1577     if (ourrc)
1578         return -1;
1579     else
1580         return 0;
1581     /*@=nullstate@*/
1582 }