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