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