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