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