3caa19ee606e991e37c0945fef80c2954f455dc8
[platform/upstream/rpm.git] / lib / psm.c
1 /** \ingroup rpmtrans payload
2  * \file lib/psm.c
3  * Package state machine to handle a package from a transaction set.
4  */
5
6 #include "system.h"
7
8 #include "psm.h"
9 #include <rpmmacro.h>
10 #include <rpmurl.h>
11
12 #include "rpmlead.h"            /* writeLead proto */
13 #include "signature.h"          /* signature constants */
14 #include "misc.h"
15 #include "rpmdb.h"              /* XXX for db_chrootDone */
16 #include "debug.h"
17
18 /*@access Header @*/            /* compared with NULL */
19 /*@access rpmTransactionSet @*/ /* compared with NULL */
20 /*@access rpmdbMatchIterator @*/ /* compared with NULL */
21 /*@access TFI_t @*/             /* compared with NULL */
22 /*@access FSM_t @*/             /* compared with NULL */
23 /*@access PSM_t @*/             /* compared with NULL */
24 /*@access FD_t @*/              /* compared with NULL */
25 /*@access rpmdb @*/             /* compared with NULL */
26
27 /*@-redecl -declundef -exportheadervar@*/
28 /*@unchecked@*/
29 extern const char * chroot_prefix;
30 /*@=redecl =declundef =exportheadervar@*/
31
32 int rpmVersionCompare(Header first, Header second)
33 {
34     const char * one, * two;
35     int_32 * epochOne, * epochTwo;
36     int rc;
37
38     if (!headerGetEntry(first, RPMTAG_EPOCH, NULL, (void **) &epochOne, NULL))
39         epochOne = NULL;
40     if (!headerGetEntry(second, RPMTAG_EPOCH, NULL, (void **) &epochTwo,
41                         NULL))
42         epochTwo = NULL;
43
44     if (epochOne && !epochTwo)
45         return 1;
46     else if (!epochOne && epochTwo)
47         return -1;
48     else if (epochOne && epochTwo) {
49         if (*epochOne < *epochTwo)
50             return -1;
51         else if (*epochOne > *epochTwo)
52             return 1;
53     }
54
55     rc = headerGetEntry(first, RPMTAG_VERSION, NULL, (void **) &one, NULL);
56     rc = headerGetEntry(second, RPMTAG_VERSION, NULL, (void **) &two, NULL);
57
58     rc = rpmvercmp(one, two);
59     if (rc)
60         return rc;
61
62     rc = headerGetEntry(first, RPMTAG_RELEASE, NULL, (void **) &one, NULL);
63     rc = headerGetEntry(second, RPMTAG_RELEASE, NULL, (void **) &two, NULL);
64
65     return rpmvercmp(one, two);
66 }
67
68 void loadFi(Header h, TFI_t fi)
69 {
70     HGE_t hge;
71     HFD_t hfd;
72     uint_32 * uip;
73     int len;
74     int rc;
75     int i;
76     
77     if (fi->fsm == NULL)
78         fi->fsm = newFSM();
79
80     /* XXX avoid gcc noise on pointer (4th arg) cast(s) */
81     hge = (fi->type == TR_ADDED)
82         ? (HGE_t) headerGetEntryMinMemory : (HGE_t) headerGetEntry;
83     fi->hge = hge;
84     fi->hae = (HAE_t) headerAddEntry;
85     fi->hme = (HME_t) headerModifyEntry;
86     fi->hre = (HRE_t) headerRemoveEntry;
87     fi->hfd = hfd = headerFreeData;
88
89     /*@-branchstate@*/
90     if (h && fi->h == NULL)     fi->h = headerLink(h);
91     /*@=branchstate@*/
92
93     /* Duplicate name-version-release so that headers can be free'd. */
94     rc = hge(fi->h, RPMTAG_NAME, NULL, (void **) &fi->name, NULL);
95     fi->name = xstrdup(fi->name);
96     rc = hge(fi->h, RPMTAG_VERSION, NULL, (void **) &fi->version, NULL);
97     fi->version = xstrdup(fi->version);
98     rc = hge(fi->h, RPMTAG_RELEASE, NULL, (void **) &fi->release, NULL);
99     fi->release = xstrdup(fi->release);
100
101     /* -1 means not found */
102     rc = hge(fi->h, RPMTAG_EPOCH, NULL, (void **) &uip, NULL);
103     fi->epoch = (rc ? *uip : -1);
104     /* 0 means unknown */
105     rc = hge(fi->h, RPMTAG_ARCHIVESIZE, NULL, (void **) &uip, NULL);
106     fi->archiveSize = (rc ? *uip : 0);
107
108     if (!hge(fi->h, RPMTAG_BASENAMES, NULL, (void **) &fi->bnl, &fi->fc)) {
109         fi->dc = 0;
110         fi->fc = 0;
111         return;
112     }
113
114     rc = hge(fi->h, RPMTAG_DIRINDEXES, NULL, (void **) &fi->dil, NULL);
115     rc = hge(fi->h, RPMTAG_DIRNAMES, NULL, (void **) &fi->dnl, &fi->dc);
116     rc = hge(fi->h, RPMTAG_FILEMODES, NULL, (void **) &fi->fmodes, NULL);
117     rc = hge(fi->h, RPMTAG_FILEFLAGS, NULL, (void **) &fi->fflags, NULL);
118     rc = hge(fi->h, RPMTAG_FILESIZES, NULL, (void **) &fi->fsizes, NULL);
119     rc = hge(fi->h, RPMTAG_FILESTATES, NULL, (void **) &fi->fstates, NULL);
120
121     fi->action = FA_UNKNOWN;
122     fi->flags = 0;
123
124     /* actions is initialized earlier for added packages */
125     if (fi->actions == NULL)
126         fi->actions = xcalloc(fi->fc, sizeof(*fi->actions));
127
128     switch (fi->type) {
129     case TR_ADDED:
130         fi->mapflags =
131                 CPIO_MAP_PATH | CPIO_MAP_MODE | CPIO_MAP_UID | CPIO_MAP_GID;
132         rc = hge(fi->h, RPMTAG_FILEMD5S, NULL, (void **) &fi->fmd5s, NULL);
133         rc = hge(fi->h, RPMTAG_FILELINKTOS, NULL, (void **) &fi->flinks, NULL);
134         rc = hge(fi->h, RPMTAG_FILELANGS, NULL, (void **) &fi->flangs, NULL);
135         rc = hge(fi->h, RPMTAG_FILEMTIMES, NULL, (void **) &fi->fmtimes, NULL);
136         rc = hge(fi->h, RPMTAG_FILERDEVS, NULL, (void **) &fi->frdevs, NULL);
137
138         /* 0 makes for noops */
139         fi->replacedSizes = xcalloc(fi->fc, sizeof(*fi->replacedSizes));
140
141         break;
142     case TR_REMOVED:
143         fi->mapflags = 
144                 CPIO_MAP_ABSOLUTE | CPIO_MAP_ADDDOT | CPIO_ALL_HARDLINKS |
145                 CPIO_MAP_PATH | CPIO_MAP_MODE | CPIO_MAP_UID | CPIO_MAP_GID;
146         rc = hge(fi->h, RPMTAG_FILEMD5S, NULL, (void **) &fi->fmd5s, NULL);
147         rc = hge(fi->h, RPMTAG_FILELINKTOS, NULL, (void **) &fi->flinks, NULL);
148         fi->fsizes = memcpy(xmalloc(fi->fc * sizeof(*fi->fsizes)),
149                                 fi->fsizes, fi->fc * sizeof(*fi->fsizes));
150         fi->fflags = memcpy(xmalloc(fi->fc * sizeof(*fi->fflags)),
151                                 fi->fflags, fi->fc * sizeof(*fi->fflags));
152         fi->fmodes = memcpy(xmalloc(fi->fc * sizeof(*fi->fmodes)),
153                                 fi->fmodes, fi->fc * sizeof(*fi->fmodes));
154         /* XXX there's a tedious segfault here for some version(s) of rpm */
155         if (fi->fstates)
156             fi->fstates = memcpy(xmalloc(fi->fc * sizeof(*fi->fstates)),
157                                 fi->fstates, fi->fc * sizeof(*fi->fstates));
158         else
159             fi->fstates = xcalloc(1, fi->fc * sizeof(*fi->fstates));
160         fi->dil = memcpy(xmalloc(fi->fc * sizeof(*fi->dil)),
161                                 fi->dil, fi->fc * sizeof(*fi->dil));
162         fi->h = headerFree(fi->h);
163         break;
164     }
165
166     fi->dnlmax = -1;
167     for (i = 0; i < fi->dc; i++) {
168         if ((len = strlen(fi->dnl[i])) > fi->dnlmax)
169             fi->dnlmax = len;
170     }
171
172     fi->bnlmax = -1;
173     for (i = 0; i < fi->fc; i++) {
174         if ((len = strlen(fi->bnl[i])) > fi->bnlmax)
175             fi->bnlmax = len;
176     }
177
178     fi->dperms = 0755;
179     fi->fperms = 0644;
180
181     /*@-nullstate@*/    /* FIX: fi->h is NULL for TR_REMOVED */
182     return;
183     /*@=nullstate@*/
184 }
185
186 void freeFi(TFI_t fi)
187 {
188     HFD_t hfd = (fi->hfd ? fi->hfd : headerFreeData);
189
190     fi->name = _free(fi->name);
191     fi->version = _free(fi->version);
192     fi->release = _free(fi->release);
193     fi->actions = _free(fi->actions);
194     fi->replacedSizes = _free(fi->replacedSizes);
195     fi->replaced = _free(fi->replaced);
196
197     fi->bnl = hfd(fi->bnl, -1);
198     fi->dnl = hfd(fi->dnl, -1);
199     fi->obnl = hfd(fi->obnl, -1);
200     fi->odnl = hfd(fi->odnl, -1);
201     fi->flinks = hfd(fi->flinks, -1);
202     fi->fmd5s = hfd(fi->fmd5s, -1);
203     fi->fuser = hfd(fi->fuser, -1);
204     fi->fgroup = hfd(fi->fgroup, -1);
205     fi->flangs = hfd(fi->flangs, -1);
206
207     fi->apath = _free(fi->apath);
208     fi->fuids = _free(fi->fuids);
209     fi->fgids = _free(fi->fgids);
210     fi->fmapflags = _free(fi->fmapflags);
211
212     fi->fsm = freeFSM(fi->fsm);
213
214     switch (fi->type) {
215     case TR_ADDED:
216             break;
217     case TR_REMOVED:
218         fi->fsizes = hfd(fi->fsizes, -1);
219         fi->fflags = hfd(fi->fflags, -1);
220         fi->fmodes = hfd(fi->fmodes, -1);
221         fi->fstates = hfd(fi->fstates, -1);
222         fi->dil = hfd(fi->dil, -1);
223         break;
224     }
225
226     fi->h = headerFree(fi->h);
227
228     /*@-nullstate@*/ /* FIX: fi->{name,version,release,actions,...,h} NULL */
229     return;
230     /*@=nullstate@*/
231 }
232
233 /*@observer@*/ const char *const fiTypeString(TFI_t fi)
234 {
235     switch(fi->type) {
236     case TR_ADDED:      return " install";
237     case TR_REMOVED:    return "   erase";
238     default:            return "???";
239     }
240     /*@noteached@*/
241 }
242
243 /**
244  * Macros to be defined from per-header tag values.
245  * @todo Should other macros be added from header when installing a package?
246  */
247 /*@observer@*/ /*@unchecked@*/
248 static struct tagMacro {
249 /*@observer@*/ /*@null@*/ const char *  macroname; /*!< Macro name to define. */
250     rpmTag      tag;            /*!< Header tag to use for value. */
251 } tagMacros[] = {
252     { "name",           RPMTAG_NAME },
253     { "version",        RPMTAG_VERSION },
254     { "release",        RPMTAG_RELEASE },
255     { "epoch",          RPMTAG_EPOCH },
256     { NULL, 0 }
257 };
258
259 /**
260  * Define per-header macros.
261  * @param fi            transaction element file info
262  * @param h             header
263  * @return              0 always
264  */
265 static int rpmInstallLoadMacros(TFI_t fi, Header h)
266         /*@globals rpmGlobalMacroContext, internalState @*/
267         /*@modifies rpmGlobalMacroContext, internalState @*/
268 {
269     HGE_t hge = (HGE_t) fi->hge;
270     struct tagMacro * tagm;
271     union {
272 /*@unused@*/ void * ptr;
273 /*@unused@*/ const char ** argv;
274         const char * str;
275         int_32 * i32p;
276     } body;
277     char numbuf[32];
278     rpmTagType type;
279
280     for (tagm = tagMacros; tagm->macroname != NULL; tagm++) {
281         if (!hge(h, tagm->tag, &type, (void **) &body, NULL))
282             continue;
283         switch (type) {
284         case RPM_INT32_TYPE:
285             sprintf(numbuf, "%d", *body.i32p);
286             addMacro(NULL, tagm->macroname, NULL, numbuf, -1);
287             /*@switchbreak@*/ break;
288         case RPM_STRING_TYPE:
289             addMacro(NULL, tagm->macroname, NULL, body.str, -1);
290             /*@switchbreak@*/ break;
291         case RPM_NULL_TYPE:
292         case RPM_CHAR_TYPE:
293         case RPM_INT8_TYPE:
294         case RPM_INT16_TYPE:
295         case RPM_BIN_TYPE:
296         case RPM_STRING_ARRAY_TYPE:
297         case RPM_I18NSTRING_TYPE:
298         default:
299             /*@switchbreak@*/ break;
300         }
301     }
302     return 0;
303 }
304
305 /**
306  * Copy file data from h to newH.
307  * @param h             header from
308  * @param newH          header to
309  * @param actions       array of file dispositions
310  * @return              0 on success, 1 on failure
311  */
312 static int mergeFiles(TFI_t fi, Header h, Header newH)
313         /*@modifies h @*/
314 {
315     HGE_t hge = (HGE_t)fi->hge;
316     HME_t hme = (HME_t)fi->hme;
317     HFD_t hfd = (fi->hfd ? fi->hfd : headerFreeData);
318     fileAction * actions = fi->actions;
319     int i, j, k, fc, xx;
320     rpmTagType type = 0;
321     int_32 count = 0;
322     int_32 dirNamesCount, dirCount;
323     void * data, * newdata;
324     int_32 * dirIndexes, * newDirIndexes;
325     uint_32 * fileSizes, fileSize;
326     const char ** dirNames;
327     const char ** newDirNames;
328     static rpmTag mergeTags[] = {
329         RPMTAG_FILESIZES,
330         RPMTAG_FILESTATES,
331         RPMTAG_FILEMODES,
332         RPMTAG_FILERDEVS,
333         RPMTAG_FILEMTIMES,
334         RPMTAG_FILEMD5S,
335         RPMTAG_FILELINKTOS,
336         RPMTAG_FILEFLAGS,
337         RPMTAG_FILEUSERNAME,
338         RPMTAG_FILEGROUPNAME,
339         RPMTAG_FILEVERIFYFLAGS,
340         RPMTAG_FILEDEVICES,
341         RPMTAG_FILEINODES,
342         RPMTAG_FILELANGS,
343         RPMTAG_BASENAMES,
344         0,
345     };
346     static rpmTag requireTags[] = {
347         RPMTAG_REQUIRENAME, RPMTAG_REQUIREVERSION, RPMTAG_REQUIREFLAGS,
348         RPMTAG_PROVIDENAME, RPMTAG_PROVIDEVERSION, RPMTAG_PROVIDEFLAGS,
349         RPMTAG_CONFLICTNAME, RPMTAG_CONFLICTVERSION, RPMTAG_CONFLICTFLAGS
350     };
351
352     xx = hge(h, RPMTAG_SIZE, NULL, (void **) &fileSizes, NULL);
353     fileSize = *fileSizes;
354     xx = hge(newH, RPMTAG_FILESIZES, NULL, (void **) &fileSizes, &count);
355     for (i = 0, fc = 0; i < count; i++)
356         if (actions[i] != FA_SKIPMULTILIB) {
357             fc++;
358             fileSize += fileSizes[i];
359         }
360     xx = hme(h, RPMTAG_SIZE, RPM_INT32_TYPE, &fileSize, 1);
361
362     /*@-sizeoftype@*/
363     for (i = 0; mergeTags[i]; i++) {
364         if (!hge(newH, mergeTags[i], &type, (void **) &data, &count))
365             continue;
366         switch (type) {
367         case RPM_CHAR_TYPE:
368         case RPM_INT8_TYPE:
369             newdata = xcalloc(fc, sizeof(int_8));
370             for (j = 0, k = 0; j < count; j++)
371                 if (actions[j] != FA_SKIPMULTILIB)
372                         ((int_8 *) newdata)[k++] = ((int_8 *) data)[j];
373             xx = headerAddOrAppendEntry(h, mergeTags[i], type, newdata, fc);
374             free (newdata);
375             /*@switchbreak@*/ break;
376         case RPM_INT16_TYPE:
377             newdata = xcalloc(fc, sizeof(int_16));
378             for (j = 0, k = 0; j < count; j++)
379                 if (actions[j] != FA_SKIPMULTILIB)
380                     ((int_16 *) newdata)[k++] = ((int_16 *) data)[j];
381             xx = headerAddOrAppendEntry(h, mergeTags[i], type, newdata, fc);
382             free (newdata);
383             /*@switchbreak@*/ break;
384         case RPM_INT32_TYPE:
385             newdata = xcalloc(fc, sizeof(int_32));
386             for (j = 0, k = 0; j < count; j++)
387                 if (actions[j] != FA_SKIPMULTILIB)
388                     ((int_32 *) newdata)[k++] = ((int_32 *) data)[j];
389             xx = headerAddOrAppendEntry(h, mergeTags[i], type, newdata, fc);
390             free (newdata);
391             /*@switchbreak@*/ break;
392         case RPM_STRING_ARRAY_TYPE:
393             newdata = xcalloc(fc, sizeof(char *));
394             for (j = 0, k = 0; j < count; j++)
395                 if (actions[j] != FA_SKIPMULTILIB)
396                     ((char **) newdata)[k++] = ((char **) data)[j];
397             xx = headerAddOrAppendEntry(h, mergeTags[i], type, newdata, fc);
398             free (newdata);
399             /*@switchbreak@*/ break;
400         default:
401             rpmError(RPMERR_DATATYPE, _("Data type %d not supported\n"),
402                         (int) type);
403             return 1;
404             /*@notreached@*/ /*@switchbreak@*/ break;
405         }
406         data = hfd(data, type);
407     }
408     /*@=sizeoftype@*/
409     xx = hge(newH, RPMTAG_DIRINDEXES, NULL, (void **) &newDirIndexes, &count);
410     xx = hge(newH, RPMTAG_DIRNAMES, NULL, (void **) &newDirNames, NULL);
411     xx = hge(h, RPMTAG_DIRINDEXES, NULL, (void **) &dirIndexes, NULL);
412     xx = hge(h, RPMTAG_DIRNAMES, NULL, (void **) &data, &dirNamesCount);
413
414     dirNames = xcalloc(dirNamesCount + fc, sizeof(*dirNames));
415     for (i = 0; i < dirNamesCount; i++)
416         dirNames[i] = ((char **) data)[i];
417     dirCount = dirNamesCount;
418     newdata = xcalloc(fc, sizeof(*newDirIndexes));
419     for (i = 0, k = 0; i < count; i++) {
420         if (actions[i] == FA_SKIPMULTILIB)
421             continue;
422         for (j = 0; j < dirCount; j++)
423             if (!strcmp(dirNames[j], newDirNames[newDirIndexes[i]]))
424                 /*@innerbreak@*/ break;
425         if (j == dirCount)
426             dirNames[dirCount++] = newDirNames[newDirIndexes[i]];
427         ((int_32 *) newdata)[k++] = j;
428     }
429     xx = headerAddOrAppendEntry(h, RPMTAG_DIRINDEXES, RPM_INT32_TYPE, newdata, fc);
430     if (dirCount > dirNamesCount)
431         xx = headerAddOrAppendEntry(h, RPMTAG_DIRNAMES, RPM_STRING_ARRAY_TYPE,
432                                dirNames + dirNamesCount,
433                                dirCount - dirNamesCount);
434     data = hfd(data, -1);
435     newDirNames = hfd(newDirNames, -1);
436     free (newdata);
437     free (dirNames);
438
439     for (i = 0; i < 9; i += 3) {
440         const char **Names, **EVR, **newNames, **newEVR;
441         rpmTagType nnt, nvt, rnt;
442         uint_32 *Flags, *newFlags;
443         int Count = 0, newCount = 0;
444
445         if (!hge(newH, requireTags[i], &nnt, (void **) &newNames, &newCount))
446             continue;
447
448         xx = hge(newH, requireTags[i+1], &nvt, (void **) &newEVR, NULL);
449         xx = hge(newH, requireTags[i+2], NULL, (void **) &newFlags, NULL);
450         if (hge(h, requireTags[i], &rnt, (void **) &Names, &Count))
451         {
452             xx = hge(h, requireTags[i+1], NULL, (void **) &EVR, NULL);
453             xx = hge(h, requireTags[i+2], NULL, (void **) &Flags, NULL);
454             for (j = 0; j < newCount; j++)
455                 for (k = 0; k < Count; k++)
456                     if (!strcmp (newNames[j], Names[k])
457                         && !strcmp (newEVR[j], EVR[k])
458                         && (newFlags[j] & RPMSENSE_SENSEMASK) ==
459                            (Flags[k] & RPMSENSE_SENSEMASK))
460                     {
461                         newNames[j] = NULL;
462                         /*@innerbreak@*/ break;
463                     }
464         }
465         for (j = 0, k = 0; j < newCount; j++) {
466             if (!newNames[j] || !isDependsMULTILIB(newFlags[j]))
467                 /*@innercontinue@*/ continue;
468             if (j != k) {
469                 newNames[k] = newNames[j];
470                 newEVR[k] = newEVR[j];
471                 newFlags[k] = newFlags[j];
472             }
473             k++;
474         }
475         if (k) {
476             xx = headerAddOrAppendEntry(h, requireTags[i],
477                                        RPM_STRING_ARRAY_TYPE, newNames, k);
478             xx = headerAddOrAppendEntry(h, requireTags[i+1],
479                                        RPM_STRING_ARRAY_TYPE, newEVR, k);
480             xx = headerAddOrAppendEntry(h, requireTags[i+2], RPM_INT32_TYPE,
481                                        newFlags, k);
482         }
483         newNames = hfd(newNames, nnt);
484         newEVR = hfd(newEVR, nvt);
485         Names = hfd(Names, rnt);
486     }
487     return 0;
488 }
489
490 /**
491  * Mark files in database shared with this package as "replaced".
492  * @param psm           package state machine data
493  * @return              0 always
494  */
495 static int markReplacedFiles(PSM_t psm)
496         /*@globals fileSystem@*/
497         /*@modifies psm, fileSystem @*/
498 {
499     const rpmTransactionSet ts = psm->ts;
500     TFI_t fi = psm->fi;
501     HGE_t hge = (HGE_t)fi->hge;
502     const struct sharedFileInfo * replaced = fi->replaced;
503     const struct sharedFileInfo * sfi;
504     rpmdbMatchIterator mi;
505     Header h;
506     unsigned int * offsets;
507     unsigned int prev;
508     int num, xx;
509
510     if (!(fi->fc > 0 && fi->replaced))
511         return 0;
512
513     num = prev = 0;
514     for (sfi = replaced; sfi->otherPkg; sfi++) {
515         if (prev && prev == sfi->otherPkg)
516             continue;
517         prev = sfi->otherPkg;
518         num++;
519     }
520     if (num == 0)
521         return 0;
522
523     offsets = alloca(num * sizeof(*offsets));
524     num = prev = 0;
525     for (sfi = replaced; sfi->otherPkg; sfi++) {
526         if (prev && prev == sfi->otherPkg)
527             continue;
528         prev = sfi->otherPkg;
529         offsets[num++] = sfi->otherPkg;
530     }
531
532     mi = rpmdbInitIterator(ts->rpmdb, RPMDBI_PACKAGES, NULL, 0);
533     xx = rpmdbAppendIterator(mi, offsets, num);
534     xx = rpmdbSetIteratorRewrite(mi, 1);
535
536     sfi = replaced;
537     while ((h = rpmdbNextIterator(mi)) != NULL) {
538         char * secStates;
539         int modified;
540         int count;
541
542         modified = 0;
543
544         if (!hge(h, RPMTAG_FILESTATES, NULL, (void **)&secStates, &count))
545             continue;
546         
547         prev = rpmdbGetIteratorOffset(mi);
548         num = 0;
549         while (sfi->otherPkg && sfi->otherPkg == prev) {
550             assert(sfi->otherFileNum < count);
551             if (secStates[sfi->otherFileNum] != RPMFILE_STATE_REPLACED) {
552                 secStates[sfi->otherFileNum] = RPMFILE_STATE_REPLACED;
553                 if (modified == 0) {
554                     /* Modified header will be rewritten. */
555                     modified = 1;
556                     xx = rpmdbSetIteratorModified(mi, modified);
557                 }
558                 num++;
559             }
560             sfi++;
561         }
562     }
563     mi = rpmdbFreeIterator(mi);
564
565     return 0;
566 }
567
568 /**
569  * Create directory if it does not exist, make sure path is writable.
570  * @note This will only create last component of directory path.
571  * @param dpath         directory path
572  * @param dname         directory use
573  * @return              rpmRC return code
574  */
575 static rpmRC chkdir (const char * dpath, const char * dname)
576         /*@globals fileSystem@*/
577         /*@modifies fileSystem @*/
578 {
579     struct stat st;
580     int rc;
581
582     if ((rc = Stat(dpath, &st)) < 0) {
583         int ut = urlPath(dpath, NULL);
584         switch (ut) {
585         case URL_IS_PATH:
586         case URL_IS_UNKNOWN:
587             if (errno != ENOENT)
588                 break;
589             /*@fallthrough@*/
590         case URL_IS_FTP:
591         case URL_IS_HTTP:
592             rc = Mkdir(dpath, 0755);
593             break;
594         case URL_IS_DASH:
595             break;
596         }
597         if (rc < 0) {
598             rpmError(RPMERR_CREATE, _("cannot create %%%s %s\n"),
599                         dname, dpath);
600             return RPMRC_FAIL;
601         }
602     }
603     if ((rc = Access(dpath, W_OK))) {
604         rpmError(RPMERR_CREATE, _("cannot write to %%%s %s\n"), dname, dpath);
605         return RPMRC_FAIL;
606     }
607     return RPMRC_OK;
608 }
609
610 rpmRC rpmInstallSourcePackage(const char * rootDir, FD_t fd,
611                         const char ** specFilePtr,
612                         rpmCallbackFunction notify, rpmCallbackData notifyData,
613                         char ** cookie)
614 {
615     rpmdb rpmdb = NULL;
616     rpmTransactionSet ts = rpmtransCreateSet(rpmdb, rootDir);
617     TFI_t fi = xcalloc(sizeof(*fi), 1);
618     const char * _sourcedir = NULL;
619     const char * _specdir = NULL;
620     const char * specFile = NULL;
621     HGE_t hge;
622     HFD_t hfd;
623     Header h = NULL;
624     struct psm_s psmbuf;
625     PSM_t psm = &psmbuf;
626     int isSource;
627     rpmRC rc;
628     int i;
629
630     ts->notify = notify;
631     /*@-temptrans -assignexpose@*/
632     ts->notifyData = notifyData;
633     /*@=temptrans =assignexpose@*/
634
635     /*@-mustmod@*/      /* LCL: segfault */
636     rc = rpmReadPackageHeader(fd, &h, &isSource, NULL, NULL);
637     /*@=mustmod@*/
638     if (rc)
639         goto exit;
640
641     if (!isSource) {
642         rpmError(RPMERR_NOTSRPM, _("source package expected, binary found\n"));
643         rc = RPMRC_FAIL;
644         goto exit;
645     }
646
647     (void) rpmtransAddPackage(ts, h, fd, NULL, 0, NULL);
648     if (ts->addedPackages.list == NULL) {       /* XXX can't happen */
649         rc = RPMRC_FAIL;
650         goto exit;
651     }
652
653     fi->type = TR_ADDED;
654     fi->ap = ts->addedPackages.list;
655     loadFi(h, fi);
656     hge = fi->hge;
657     hfd = (fi->hfd ? fi->hfd : headerFreeData);
658     h = headerFree(h);  /* XXX reference held by transaction set */
659
660     (void) rpmInstallLoadMacros(fi, fi->h);
661
662     memset(psm, 0, sizeof(*psm));
663     psm->ts = ts;
664     psm->fi = fi;
665
666     if (cookie) {
667         *cookie = NULL;
668         if (hge(fi->h, RPMTAG_COOKIE, NULL, (void **) cookie, NULL))
669             *cookie = xstrdup(*cookie);
670     }
671
672     /* XXX FIXME: can't do endian neutral MD5 verification yet. */
673     fi->fmd5s = hfd(fi->fmd5s, -1);
674
675     /* XXX FIXME: don't do per-file mapping, force global flags. */
676     fi->fmapflags = _free(fi->fmapflags);
677     fi->mapflags = CPIO_MAP_PATH | CPIO_MAP_MODE | CPIO_MAP_UID | CPIO_MAP_GID;
678
679     fi->uid = getuid();
680     fi->gid = getgid();
681     fi->astriplen = 0;
682     fi->striplen = 0;
683
684     fi->fuids = xcalloc(sizeof(*fi->fuids), fi->fc);
685     fi->fgids = xcalloc(sizeof(*fi->fgids), fi->fc);
686     for (i = 0; i < fi->fc; i++) {
687         fi->fuids[i] = fi->uid;
688         fi->fgids[i] = fi->gid;
689     }
690
691     for (i = 0; i < fi->fc; i++) {
692         fi->actions[i] = FA_CREATE;
693     }
694
695     rpmBuildFileList(fi->h, &fi->apath, NULL);
696
697     i = fi->fc;
698     if (headerIsEntry(fi->h, RPMTAG_COOKIE))
699         for (i = 0; i < fi->fc; i++)
700                 if (fi->fflags[i] & RPMFILE_SPECFILE) break;
701
702     if (i == fi->fc) {
703         /* Find the spec file by name. */
704         for (i = 0; i < fi->fc; i++) {
705             const char * t = fi->apath[i];
706             t += strlen(fi->apath[i]) - 5;
707             if (!strcmp(t, ".spec")) break;
708         }
709     }
710
711     _sourcedir = rpmGenPath(ts->rootDir, "%{_sourcedir}", "");
712     rc = chkdir(_sourcedir, "sourcedir");
713     if (rc) {
714         rc = RPMRC_FAIL;
715         goto exit;
716     }
717
718     _specdir = rpmGenPath(ts->rootDir, "%{_specdir}", "");
719     rc = chkdir(_specdir, "specdir");
720     if (rc) {
721         rc = RPMRC_FAIL;
722         goto exit;
723     }
724
725     /* Build dnl/dil with {_sourcedir, _specdir} as values. */
726     if (i < fi->fc) {
727         int speclen = strlen(_specdir) + 2;
728         int sourcelen = strlen(_sourcedir) + 2;
729         char * t;
730
731         fi->dnl = hfd(fi->dnl, -1);
732
733         fi->dc = 2;
734         fi->dnl = xmalloc(fi->dc * sizeof(*fi->dnl) + fi->fc * sizeof(*fi->dil) +
735                         speclen + sourcelen);
736         fi->dil = (int *)(fi->dnl + fi->dc);
737         memset(fi->dil, 0, fi->fc * sizeof(*fi->dil));
738         fi->dil[i] = 1;
739         /*@-dependenttrans@*/
740         fi->dnl[0] = t = (char *)(fi->dil + fi->fc);
741         fi->dnl[1] = t = stpcpy( stpcpy(t, _sourcedir), "/") + 1;
742         /*@=dependenttrans@*/
743         (void) stpcpy( stpcpy(t, _specdir), "/");
744
745         t = xmalloc(speclen + strlen(fi->bnl[i]) + 1);
746         (void) stpcpy( stpcpy( stpcpy(t, _specdir), "/"), fi->bnl[i]);
747         specFile = t;
748     } else {
749         rpmError(RPMERR_NOSPEC, _("source package contains no .spec file\n"));
750         rc = RPMRC_FAIL;
751         goto exit;
752     }
753
754     psm->goal = PSM_PKGINSTALL;
755
756     /*@-compmempass@*/  /* FIX: psm->fi->dnl should be owned. */
757     rc = psmStage(psm, PSM_PROCESS);
758
759     (void) psmStage(psm, PSM_FINI);
760     /*@=compmempass@*/
761
762     if (rc) rc = RPMRC_FAIL;
763
764 exit:
765     if (specFilePtr && specFile && rc == RPMRC_OK)
766         *specFilePtr = specFile;
767     else
768         specFile = _free(specFile);
769
770     _specdir = _free(_specdir);
771     _sourcedir = _free(_sourcedir);
772
773     if (h) h = headerFree(h);
774
775     if (fi) {
776         freeFi(fi);
777         fi = _free(fi);
778     }
779     ts = rpmtransFree(ts);
780
781     return rc;
782 }
783
784 /*@observer@*/ /*@unchecked@*/
785 static char * SCRIPT_PATH = "PATH=/sbin:/bin:/usr/sbin:/usr/bin:/usr/X11R6/bin";
786
787 /**
788  * Return scriptlet name from tag.
789  * @param tag           scriptlet tag
790  * @return              name of scriptlet
791  */
792 static /*@observer@*/ const char * const tag2sln(int tag)
793         /*@*/
794 {
795     switch (tag) {
796     case RPMTAG_PREIN:          return "%pre";
797     case RPMTAG_POSTIN:         return "%post";
798     case RPMTAG_PREUN:          return "%preun";
799     case RPMTAG_POSTUN:         return "%postun";
800     case RPMTAG_VERIFYSCRIPT:   return "%verify";
801     }
802     return "%unknownscript";
803 }
804
805 /**
806  * Run scriptlet with args.
807  *
808  * Run a script with an interpreter. If the interpreter is not specified,
809  * /bin/sh will be used. If the interpreter is /bin/sh, then the args from
810  * the header will be ignored, passing instead arg1 and arg2.
811  * 
812  * @param psm           package state machine data
813  * @param h             header
814  * @param sln           name of scriptlet section
815  * @param progArgc      no. of args from header
816  * @param progArgv      args from header, progArgv[0] is the interpreter to use
817  * @param script        scriptlet from header
818  * @param arg1          no. instances of package installed after scriptlet exec
819  *                      (-1 is no arg)
820  * @param arg2          ditto, but for the target package
821  * @return              0 on success, 1 on error
822  */
823 static int runScript(PSM_t psm, Header h,
824                 const char * sln,
825                 int progArgc, const char ** progArgv, 
826                 const char * script, int arg1, int arg2)
827         /*@globals rpmGlobalMacroContext,
828                 fileSystem, internalState@*/
829         /*@modifies psm, rpmGlobalMacroContext, fileSystem, internalState @*/
830 {
831     const rpmTransactionSet ts = psm->ts;
832     TFI_t fi = psm->fi;
833     HGE_t hge = fi->hge;
834     HFD_t hfd = (fi->hfd ? fi->hfd : headerFreeData);
835     const char ** argv = NULL;
836     int argc = 0;
837     const char ** prefixes = NULL;
838     int numPrefixes;
839     rpmTagType ipt;
840     const char * oldPrefix;
841     int maxPrefixLength;
842     int len;
843     char * prefixBuf = NULL;
844     pid_t child;
845     int status = 0;
846     const char * fn = NULL;
847     int i, xx;
848     int freePrefixes = 0;
849     FD_t out;
850     rpmRC rc = RPMRC_OK;
851     const char *n, *v, *r;
852
853     if (!progArgv && !script)
854         return 0;
855
856     if (!progArgv) {
857         argv = alloca(5 * sizeof(*argv));
858         argv[0] = "/bin/sh";
859         argc = 1;
860     } else {
861         argv = alloca((progArgc + 4) * sizeof(*argv));
862         memcpy(argv, progArgv, progArgc * sizeof(*argv));
863         argc = progArgc;
864     }
865
866     xx = headerNVR(h, &n, &v, &r);
867     if (hge(h, RPMTAG_INSTPREFIXES, &ipt, (void **) &prefixes, &numPrefixes)) {
868         freePrefixes = 1;
869     } else if (hge(h, RPMTAG_INSTALLPREFIX, NULL, (void **) &oldPrefix, NULL)) {
870         prefixes = &oldPrefix;
871         numPrefixes = 1;
872     } else {
873         numPrefixes = 0;
874     }
875
876     maxPrefixLength = 0;
877     for (i = 0; i < numPrefixes; i++) {
878         len = strlen(prefixes[i]);
879         if (len > maxPrefixLength) maxPrefixLength = len;
880     }
881     prefixBuf = alloca(maxPrefixLength + 50);
882
883     if (script) {
884         FD_t fd;
885         /*@-branchstate@*/
886         if (makeTempFile((!ts->chrootDone ? ts->rootDir : "/"), &fn, &fd)) {
887             if (freePrefixes) free(prefixes);
888             return 1;
889         }
890         /*@=branchstate@*/
891
892         if (rpmIsDebug() &&
893             (!strcmp(argv[0], "/bin/sh") || !strcmp(argv[0], "/bin/bash")))
894         {
895             static const char set_x[] = "set -x\n";
896             xx = Fwrite(set_x, sizeof(set_x[0]), sizeof(set_x)-1, fd);
897         }
898
899         xx = Fwrite(script, sizeof(script[0]), strlen(script), fd);
900         xx = Fclose(fd);
901
902         {   const char * sn = fn;
903             if (!ts->chrootDone &&
904                 !(ts->rootDir[0] == '/' && ts->rootDir[1] == '\0'))
905             {
906                 sn += strlen(ts->rootDir)-1;
907             }
908             argv[argc++] = sn;
909         }
910
911         if (arg1 >= 0) {
912             char *av = alloca(20);
913             sprintf(av, "%d", arg1);
914             argv[argc++] = av;
915         }
916         if (arg2 >= 0) {
917             char *av = alloca(20);
918             sprintf(av, "%d", arg2);
919             argv[argc++] = av;
920         }
921     }
922
923     argv[argc] = NULL;
924
925     if (ts->scriptFd != NULL) {
926         if (rpmIsVerbose()) {
927             out = fdDup(Fileno(ts->scriptFd));
928         } else {
929             out = Fopen("/dev/null", "w.fdio");
930             if (Ferror(out)) {
931                 out = fdDup(Fileno(ts->scriptFd));
932             }
933         }
934     } else {
935         out = fdDup(STDOUT_FILENO);
936 #ifdef  DYING
937         out = fdLink(out, "runScript persist");
938 #endif
939     }
940     if (out == NULL) return 1;  /* XXX can't happen */
941     
942     if (!(child = fork())) {
943         const char * rootDir;
944         int pipes[2];
945
946         pipes[0] = pipes[1] = 0;
947         /* make stdin inaccessible */
948         xx = pipe(pipes);
949         xx = close(pipes[1]);
950         xx = dup2(pipes[0], STDIN_FILENO);
951         xx = close(pipes[0]);
952
953         /*@-branchstate@*/
954         if (ts->scriptFd != NULL) {
955             int sfdno = Fileno(ts->scriptFd);
956             int ofdno = Fileno(out);
957             if (sfdno != STDERR_FILENO)
958                 xx = dup2(sfdno, STDERR_FILENO);
959             if (ofdno != STDOUT_FILENO)
960                 xx = dup2(ofdno, STDOUT_FILENO);
961             /* make sure we don't close stdin/stderr/stdout by mistake! */
962             if (ofdno > STDERR_FILENO && ofdno != sfdno) {
963                 xx = Fclose (out);
964             }
965             if (sfdno > STDERR_FILENO) {
966                 xx = Fclose (ts->scriptFd);
967             }
968         }
969         /*@=branchstate@*/
970
971         /*@-branchstate@*/
972         {   const char *ipath = rpmExpand("PATH=%{_install_script_path}", NULL);
973             const char *path = SCRIPT_PATH;
974
975             if (ipath && ipath[5] != '%')
976                 path = ipath;
977
978             xx = doputenv(path);
979             /*@-modobserver@*/
980             ipath = _free(ipath);
981             /*@=modobserver@*/
982         }
983         /*@=branchstate@*/
984
985         for (i = 0; i < numPrefixes; i++) {
986             sprintf(prefixBuf, "RPM_INSTALL_PREFIX%d=%s", i, prefixes[i]);
987             xx = doputenv(prefixBuf);
988
989             /* backwards compatibility */
990             if (i == 0) {
991                 sprintf(prefixBuf, "RPM_INSTALL_PREFIX=%s", prefixes[i]);
992                 xx = doputenv(prefixBuf);
993             }
994         }
995
996         if ((rootDir = ts->rootDir) != NULL)    /* XXX can't happen */
997         switch(urlIsURL(rootDir)) {
998         case URL_IS_PATH:
999             rootDir += sizeof("file://") - 1;
1000             rootDir = strchr(rootDir, '/');
1001             /*@fallthrough@*/
1002         case URL_IS_UNKNOWN:
1003             if (!ts->chrootDone && !(rootDir[0] == '/' && rootDir[1] == '\0')) {
1004                 /*@-superuser -noeffect @*/
1005                 xx = chroot(rootDir);
1006                 /*@=superuser =noeffect @*/
1007             }
1008             xx = chdir("/");
1009             xx = execv(argv[0], (char *const *)argv);
1010             break;
1011         default:
1012             break;
1013         }
1014
1015         _exit(-1);
1016         /*@notreached@*/
1017     }
1018
1019     if (waitpid(child, &status, 0) < 0) {
1020         rpmError(RPMERR_SCRIPT,
1021      _("execution of %s scriptlet from %s-%s-%s failed, waitpid returned %s\n"),
1022                  sln, n, v, r, strerror (errno));
1023         /* XXX what to do here? */
1024         rc = RPMRC_OK;
1025     } else {
1026         if (!WIFEXITED(status) || WEXITSTATUS(status)) {
1027             rpmError(RPMERR_SCRIPT,
1028      _("execution of %s scriptlet from %s-%s-%s failed, exit status %d\n"),
1029                      sln, n, v, r, WEXITSTATUS(status));
1030             rc = RPMRC_FAIL;
1031         }
1032     }
1033
1034     if (freePrefixes) prefixes = hfd(prefixes, ipt);
1035
1036     xx = Fclose(out);   /* XXX dup'd STDOUT_FILENO */
1037     
1038     /*@-branchstate@*/
1039     if (script) {
1040         if (!rpmIsDebug())
1041             xx = unlink(fn);
1042         fn = _free(fn);
1043     }
1044     /*@=branchstate@*/
1045
1046     return rc;
1047 }
1048
1049 /**
1050  * Retrieve and run scriptlet from header.
1051  * @param psm           package state machine data
1052  * @return              rpmRC return code
1053  */
1054 static rpmRC runInstScript(PSM_t psm)
1055         /*@globals rpmGlobalMacroContext,
1056                 fileSystem, internalState @*/
1057         /*@modifies psm, rpmGlobalMacroContext,
1058                 fileSystem, internalState @*/
1059 {
1060     TFI_t fi = psm->fi;
1061     HGE_t hge = fi->hge;
1062     HFD_t hfd = (fi->hfd ? fi->hfd : headerFreeData);
1063     void ** programArgv;
1064     int programArgc;
1065     const char ** argv;
1066     rpmTagType ptt, stt;
1067     const char * script;
1068     rpmRC rc = RPMRC_OK;
1069     int xx;
1070
1071     /*
1072      * headerGetEntry() sets the data pointer to NULL if the entry does
1073      * not exist.
1074      */
1075     xx = hge(fi->h, psm->progTag, &ptt, (void **) &programArgv, &programArgc);
1076     xx = hge(fi->h, psm->scriptTag, &stt, (void **) &script, NULL);
1077
1078     /*@-branchstate@*/
1079     if (programArgv && ptt == RPM_STRING_TYPE) {
1080         argv = alloca(sizeof(*argv));
1081         *argv = (const char *) programArgv;
1082     } else {
1083         argv = (const char **) programArgv;
1084     }
1085     /*@=branchstate@*/
1086
1087     rc = runScript(psm, fi->h, tag2sln(psm->scriptTag), programArgc, argv,
1088                 script, psm->scriptArg, -1);
1089
1090     programArgv = hfd(programArgv, ptt);
1091     script = hfd(script, stt);
1092     return rc;
1093 }
1094
1095 /**
1096  * @param psm           package state machine data
1097  * @param sourceH
1098  * @param triggeredH
1099  * @param arg2
1100  * @param triggersAlreadyRun
1101  * @return
1102  */
1103 static int handleOneTrigger(PSM_t psm, Header sourceH, Header triggeredH,
1104                         int arg2, unsigned char * triggersAlreadyRun)
1105         /*@globals rpmGlobalMacroContext,
1106                 fileSystem, internalState@*/
1107         /*@modifies psm, *triggersAlreadyRun, rpmGlobalMacroContext,
1108                 fileSystem, internalState @*/
1109 {
1110     const rpmTransactionSet ts = psm->ts;
1111     TFI_t fi = psm->fi;
1112     HGE_t hge = fi->hge;
1113     HFD_t hfd = (fi->hfd ? fi->hfd : headerFreeData);
1114     const char ** triggerNames;
1115     const char ** triggerEVR;
1116     const char ** triggerScripts;
1117     const char ** triggerProgs;
1118     int_32 * triggerFlags;
1119     int_32 * triggerIndices;
1120     rpmTagType tnt, tvt, tft;
1121     const char * triggerPackageName;
1122     const char * sourceName;
1123     int numTriggers;
1124     rpmRC rc = RPMRC_OK;
1125     int i, xx;
1126     int skip;
1127
1128     if (!(      hge(triggeredH, RPMTAG_TRIGGERNAME, &tnt, 
1129                         (void **) &triggerNames, &numTriggers) &&
1130                 hge(triggeredH, RPMTAG_TRIGGERFLAGS, &tft,
1131                         (void **) &triggerFlags, NULL) &&
1132                 hge(triggeredH, RPMTAG_TRIGGERVERSION, &tvt,
1133                         (void **) &triggerEVR, NULL))
1134         )
1135         return 0;
1136
1137     xx = headerNVR(sourceH, &sourceName, NULL, NULL);
1138
1139     for (i = 0; i < numTriggers; i++) {
1140         rpmTagType tit, tst, tpt;
1141
1142         if (!(triggerFlags[i] & psm->sense)) continue;
1143         if (strcmp(triggerNames[i], sourceName)) continue;
1144
1145         /*
1146          * For some reason, the TRIGGERVERSION stuff includes the name of
1147          * the package which the trigger is based on. We need to skip
1148          * over that here. I suspect that we'll change our minds on this
1149          * and remove that, so I'm going to just 'do the right thing'.
1150          */
1151         skip = strlen(triggerNames[i]);
1152         if (!strncmp(triggerEVR[i], triggerNames[i], skip) &&
1153             (triggerEVR[i][skip] == '-'))
1154             skip++;
1155         else
1156             skip = 0;
1157
1158         if (!headerMatchesDepFlags(sourceH, triggerNames[i],
1159                 triggerEVR[i] + skip, triggerFlags[i]))
1160             continue;
1161
1162         if (!(  hge(triggeredH, RPMTAG_TRIGGERINDEX, &tit,
1163                        (void **) &triggerIndices, NULL) &&
1164                 hge(triggeredH, RPMTAG_TRIGGERSCRIPTS, &tst,
1165                        (void **) &triggerScripts, NULL) &&
1166                 hge(triggeredH, RPMTAG_TRIGGERSCRIPTPROG, &tpt,
1167                        (void **) &triggerProgs, NULL))
1168             )
1169             continue;
1170
1171         xx = headerNVR(triggeredH, &triggerPackageName, NULL, NULL);
1172
1173         {   int arg1;
1174             int index;
1175
1176             arg1 = rpmdbCountPackages(ts->rpmdb, triggerPackageName);
1177             if (arg1 < 0) {
1178                 /* XXX W2DO? same as "execution of script failed" */
1179                 rc = RPMRC_FAIL;
1180             } else {
1181                 arg1 += psm->countCorrection;
1182                 index = triggerIndices[i];
1183                 if (triggersAlreadyRun == NULL ||
1184                     triggersAlreadyRun[index] == 0)
1185                 {
1186                     rc = runScript(psm, triggeredH, "%trigger", 1,
1187                             triggerProgs + index, triggerScripts[index], 
1188                             arg1, arg2);
1189                     if (triggersAlreadyRun != NULL)
1190                         triggersAlreadyRun[index] = 1;
1191                 }
1192             }
1193         }
1194
1195         triggerIndices = hfd(triggerIndices, tit);
1196         triggerScripts = hfd(triggerScripts, tst);
1197         triggerProgs = hfd(triggerProgs, tpt);
1198
1199         /*
1200          * Each target/source header pair can only result in a single
1201          * script being run.
1202          */
1203         break;
1204     }
1205
1206     triggerNames = hfd(triggerNames, tnt);
1207     triggerFlags = hfd(triggerFlags, tft);
1208     triggerEVR = hfd(triggerEVR, tvt);
1209
1210     return rc;
1211 }
1212
1213 /**
1214  * Run trigger scripts in the database that are fired by this header.
1215  * @param psm           package state machine data
1216  * @return              0 on success, 1 on error
1217  */
1218 static int runTriggers(PSM_t psm)
1219         /*@globals rpmGlobalMacroContext,
1220                 fileSystem, internalState @*/
1221         /*@modifies psm, rpmGlobalMacroContext,
1222                 fileSystem, internalState @*/
1223 {
1224     const rpmTransactionSet ts = psm->ts;
1225     TFI_t fi = psm->fi;
1226     int numPackage;
1227     rpmRC rc = RPMRC_OK;
1228
1229     numPackage = rpmdbCountPackages(ts->rpmdb, fi->name) + psm->countCorrection;
1230     if (numPackage < 0)
1231         return 1;
1232
1233     {   Header triggeredH;
1234         rpmdbMatchIterator mi;
1235         int countCorrection = psm->countCorrection;
1236
1237         psm->countCorrection = 0;
1238         mi = rpmdbInitIterator(ts->rpmdb, RPMTAG_TRIGGERNAME, fi->name, 0);
1239         while((triggeredH = rpmdbNextIterator(mi)) != NULL) {
1240             rc |= handleOneTrigger(psm, fi->h, triggeredH, numPackage, NULL);
1241         }
1242
1243         mi = rpmdbFreeIterator(mi);
1244         psm->countCorrection = countCorrection;
1245     }
1246
1247     return rc;
1248 }
1249
1250 /**
1251  * Run triggers from this header that are fired by headers in the database.
1252  * @param psm           package state machine data
1253  * @return              0 on success, 1 on error
1254  */
1255 static int runImmedTriggers(PSM_t psm)
1256         /*@globals rpmGlobalMacroContext,
1257                 fileSystem, internalState @*/
1258         /*@modifies psm, rpmGlobalMacroContext,
1259                 fileSystem, internalState @*/
1260 {
1261     const rpmTransactionSet ts = psm->ts;
1262     TFI_t fi = psm->fi;
1263     HGE_t hge = fi->hge;
1264     HFD_t hfd = (fi->hfd ? fi->hfd : headerFreeData);
1265     const char ** triggerNames;
1266     int numTriggers;
1267     int_32 * triggerIndices;
1268     rpmTagType tnt, tit;
1269     int numTriggerIndices;
1270     unsigned char * triggersRun;
1271     rpmRC rc = RPMRC_OK;
1272
1273     if (!(      hge(fi->h, RPMTAG_TRIGGERNAME, &tnt,
1274                         (void **) &triggerNames, &numTriggers) &&
1275                 hge(fi->h, RPMTAG_TRIGGERINDEX, &tit,
1276                         (void **) &triggerIndices, &numTriggerIndices))
1277         )
1278         return 0;
1279
1280     triggersRun = alloca(sizeof(*triggersRun) * numTriggerIndices);
1281     memset(triggersRun, 0, sizeof(*triggersRun) * numTriggerIndices);
1282
1283     {   Header sourceH = NULL;
1284         int i;
1285
1286         for (i = 0; i < numTriggers; i++) {
1287             rpmdbMatchIterator mi;
1288
1289             if (triggersRun[triggerIndices[i]] != 0) continue;
1290         
1291             mi = rpmdbInitIterator(ts->rpmdb, RPMTAG_NAME, triggerNames[i], 0);
1292
1293             while((sourceH = rpmdbNextIterator(mi)) != NULL) {
1294                 rc |= handleOneTrigger(psm, sourceH, fi->h, 
1295                                 rpmdbGetIteratorCount(mi),
1296                                 triggersRun);
1297             }
1298
1299             mi = rpmdbFreeIterator(mi);
1300         }
1301     }
1302     triggerIndices = hfd(triggerIndices, tit);
1303     triggerNames = hfd(triggerNames, tnt);
1304     return rc;
1305 }
1306
1307 /*@observer@*/ static const char *const pkgStageString(pkgStage a)
1308         /*@*/
1309 {
1310     switch(a) {
1311     case PSM_UNKNOWN:           return "unknown";
1312
1313     case PSM_PKGINSTALL:        return "  install";
1314     case PSM_PKGERASE:          return "    erase";
1315     case PSM_PKGCOMMIT:         return "   commit";
1316     case PSM_PKGSAVE:           return "repackage";
1317
1318     case PSM_INIT:              return "init";
1319     case PSM_PRE:               return "pre";
1320     case PSM_PROCESS:           return "process";
1321     case PSM_POST:              return "post";
1322     case PSM_UNDO:              return "undo";
1323     case PSM_FINI:              return "fini";
1324
1325     case PSM_CREATE:            return "create";
1326     case PSM_NOTIFY:            return "notify";
1327     case PSM_DESTROY:           return "destroy";
1328     case PSM_COMMIT:            return "commit";
1329
1330     case PSM_CHROOT_IN:         return "chrootin";
1331     case PSM_CHROOT_OUT:        return "chrootout";
1332     case PSM_SCRIPT:            return "script";
1333     case PSM_TRIGGERS:          return "triggers";
1334     case PSM_IMMED_TRIGGERS:    return "immedtriggers";
1335
1336     case PSM_RPMIO_FLAGS:       return "rpmioflags";
1337
1338     case PSM_RPMDB_LOAD:        return "rpmdbload";
1339     case PSM_RPMDB_ADD:         return "rpmdbadd";
1340     case PSM_RPMDB_REMOVE:      return "rpmdbremove";
1341
1342     default:                    return "???";
1343     }
1344     /*@noteached@*/
1345 }
1346
1347 /**
1348  * @todo Packages w/o files never get a callback, hence don't get displayed
1349  * on install with -v.
1350  */
1351 int psmStage(PSM_t psm, pkgStage stage)
1352 {
1353     const rpmTransactionSet ts = psm->ts;
1354     TFI_t fi = psm->fi;
1355     HGE_t hge = fi->hge;
1356     HME_t hme = fi->hme;
1357     HFD_t hfd = (fi->hfd ? fi->hfd : headerFreeData);
1358     rpmRC rc = psm->rc;
1359     int saveerrno;
1360     int xx;
1361
1362     /*@-branchstate@*/
1363     switch (stage) {
1364     case PSM_UNKNOWN:
1365         break;
1366     case PSM_INIT:
1367         rpmMessage(RPMMESS_DEBUG, _("%s: %s-%s-%s has %d files, test = %d\n"),
1368                 psm->stepName, fi->name, fi->version, fi->release,
1369                 fi->fc, (ts->transFlags & RPMTRANS_FLAG_TEST));
1370
1371         /*
1372          * When we run scripts, we pass an argument which is the number of 
1373          * versions of this package that will be installed when we are
1374          * finished.
1375          */
1376         psm->npkgs_installed = rpmdbCountPackages(ts->rpmdb, fi->name);
1377         if (psm->npkgs_installed < 0) {
1378             rc = RPMRC_FAIL;
1379             break;
1380         }
1381
1382         if (psm->goal == PSM_PKGINSTALL) {
1383             psm->scriptArg = psm->npkgs_installed + 1;
1384
1385 assert(psm->mi == NULL);
1386             psm->mi = rpmdbInitIterator(ts->rpmdb, RPMTAG_NAME, fi->name, 0);
1387             xx = rpmdbSetIteratorRE(psm->mi, RPMTAG_VERSION,
1388                         RPMMIRE_DEFAULT, fi->version);
1389             xx = rpmdbSetIteratorRE(psm->mi, RPMTAG_RELEASE,
1390                         RPMMIRE_DEFAULT, fi->release);
1391
1392             while ((psm->oh = rpmdbNextIterator(psm->mi))) {
1393                 fi->record = rpmdbGetIteratorOffset(psm->mi);
1394                 if (ts->transFlags & RPMTRANS_FLAG_MULTILIB)
1395                     psm->oh = headerCopy(psm->oh);
1396                 else
1397                     psm->oh = NULL;
1398                 /*@loopbreak@*/ break;
1399             }
1400             psm->mi = rpmdbFreeIterator(psm->mi);
1401             rc = RPMRC_OK;
1402
1403             if (fi->fc > 0 && fi->fstates == NULL) {
1404                 fi->fstates = xmalloc(sizeof(*fi->fstates) * fi->fc);
1405                 memset(fi->fstates, RPMFILE_STATE_NORMAL, fi->fc);
1406             }
1407
1408             if (fi->fc <= 0)                            break;
1409             if (ts->transFlags & RPMTRANS_FLAG_JUSTDB)  break;
1410         
1411             /*
1412              * Old format relocateable packages need the entire default
1413              * prefix stripped to form the cpio list, while all other packages
1414              * need the leading / stripped.
1415              */
1416             {   const char * p;
1417                 rc = hge(fi->h, RPMTAG_DEFAULTPREFIX, NULL, (void **) &p, NULL);
1418                 fi->striplen = (rc ? strlen(p) + 1 : 1); 
1419             }
1420             fi->mapflags =
1421                 CPIO_MAP_PATH | CPIO_MAP_MODE | CPIO_MAP_UID | CPIO_MAP_GID;
1422         
1423             if (headerIsEntry(fi->h, RPMTAG_ORIGBASENAMES))
1424                 buildOrigFileList(fi->h, &fi->apath, NULL);
1425             else
1426                 rpmBuildFileList(fi->h, &fi->apath, NULL);
1427         
1428             if (fi->fuser == NULL)
1429                 xx = hge(fi->h, RPMTAG_FILEUSERNAME, NULL,
1430                                 (void **) &fi->fuser, NULL);
1431             if (fi->fgroup == NULL)
1432                 xx = hge(fi->h, RPMTAG_FILEGROUPNAME, NULL,
1433                                 (void **) &fi->fgroup, NULL);
1434             if (fi->fuids == NULL)
1435                 fi->fuids = xcalloc(sizeof(*fi->fuids), fi->fc);
1436             if (fi->fgids == NULL)
1437                 fi->fgids = xcalloc(sizeof(*fi->fgids), fi->fc);
1438             rc = RPMRC_OK;
1439         }
1440         if (psm->goal == PSM_PKGERASE || psm->goal == PSM_PKGSAVE) {
1441             psm->scriptArg = psm->npkgs_installed - 1;
1442         
1443             /* Retrieve installed header. */
1444             rc = psmStage(psm, PSM_RPMDB_LOAD);
1445         }
1446         if (psm->goal == PSM_PKGSAVE) {
1447             /* Open output package for writing. */
1448             {   const char * bfmt = rpmGetPath("%{_repackage_name_fmt}", NULL);
1449                 const char * pkgbn =
1450                         headerSprintf(fi->h, bfmt, rpmTagTable, rpmHeaderFormats, NULL);
1451
1452                 bfmt = _free(bfmt);
1453                 psm->pkgURL = rpmGenPath("%{?_repackage_root:%{_repackage_root}}",
1454                                          "%{?_repackage_dir:%{_repackage_dir}}",
1455                                         pkgbn);
1456                 pkgbn = _free(pkgbn);
1457                 (void) urlPath(psm->pkgURL, &psm->pkgfn);
1458                 psm->fd = Fopen(psm->pkgfn, "w.ufdio");
1459                 if (psm->fd == NULL || Ferror(psm->fd)) {
1460                     rc = RPMRC_FAIL;
1461                     break;
1462                 }
1463             }
1464         }
1465         break;
1466     case PSM_PRE:
1467         if (ts->transFlags & RPMTRANS_FLAG_TEST)        break;
1468
1469         /* Change root directory if requested and not already done. */
1470         rc = psmStage(psm, PSM_CHROOT_IN);
1471
1472         if (psm->goal == PSM_PKGINSTALL) {
1473             psm->scriptTag = RPMTAG_PREIN;
1474             psm->progTag = RPMTAG_PREINPROG;
1475
1476             if (!(ts->transFlags & RPMTRANS_FLAG_NOTRIGGERPREIN)) {
1477                 /* XXX FIXME: implement %triggerprein. */
1478             }
1479
1480             if (!(ts->transFlags & RPMTRANS_FLAG_NOPRE)) {
1481                 rc = psmStage(psm, PSM_SCRIPT);
1482                 if (rc) {
1483                     rpmError(RPMERR_SCRIPT,
1484                         _("%s: %s scriptlet failed (%d), skipping %s-%s-%s\n"),
1485                         psm->stepName, tag2sln(psm->scriptTag), rc,
1486                         fi->name, fi->version, fi->release);
1487                     break;
1488                 }
1489             }
1490         }
1491
1492         if (psm->goal == PSM_PKGERASE) {
1493             psm->scriptTag = RPMTAG_PREUN;
1494             psm->progTag = RPMTAG_PREUNPROG;
1495             psm->sense = RPMSENSE_TRIGGERUN;
1496             psm->countCorrection = -1;
1497
1498             if (!(ts->transFlags & RPMTRANS_FLAG_NOTRIGGERUN)) {
1499                 /* Run triggers in other package(s) this package sets off. */
1500                 rc = psmStage(psm, PSM_TRIGGERS);
1501                 if (rc) break;
1502
1503                 /* Run triggers in this package other package(s) set off. */
1504                 rc = psmStage(psm, PSM_IMMED_TRIGGERS);
1505                 if (rc) break;
1506             }
1507
1508             if (!(ts->transFlags & RPMTRANS_FLAG_NOPREUN))
1509                 rc = psmStage(psm, PSM_SCRIPT);
1510         }
1511         if (psm->goal == PSM_PKGSAVE) {
1512             /* Regenerate original header. */
1513             {   void * uh = NULL;
1514                 int_32 uht, uhc;
1515
1516                 if (headerGetEntry(fi->h, RPMTAG_HEADERIMMUTABLE, &uht, &uh, &uhc)) {
1517                     psm->oh = headerCopyLoad(uh);
1518                     uh = hfd(uh, uht);
1519                 } else {
1520                     psm->oh = headerLink(fi->h);
1521                 }
1522             }
1523
1524             /* Add remove transaction id to header. */
1525             if (psm->oh)
1526             {   int_32 tid = ts->id;
1527                 xx = headerAddEntry(psm->oh, RPMTAG_REMOVETID,
1528                         RPM_INT32_TYPE, &tid, 1);
1529             }
1530
1531             /* Retrieve type of payload compression. */
1532             /*@-nullstate@*/    /* FIX: psm->oh may be NULL */
1533             rc = psmStage(psm, PSM_RPMIO_FLAGS);
1534             /*@=nullstate@*/
1535
1536             /* Write the lead section into the package. */
1537             {   int archnum = -1;
1538                 int osnum = -1;
1539                 struct rpmlead lead;
1540
1541 #ifndef DYING
1542                 rpmGetArchInfo(NULL, &archnum);
1543                 rpmGetOsInfo(NULL, &osnum);
1544 #endif
1545
1546                 memset(&lead, 0, sizeof(lead));
1547                 /* XXX Set package version conditioned on noDirTokens. */
1548                 lead.major = 4;
1549                 lead.minor = 0;
1550                 lead.type = RPMLEAD_BINARY;
1551                 lead.archnum = archnum;
1552                 lead.osnum = osnum;
1553                 lead.signature_type = RPMSIGTYPE_HEADERSIG;
1554
1555                 {   char buf[256];
1556                     sprintf(buf, "%s-%s-%s", fi->name, fi->version, fi->release);
1557                     strncpy(lead.name, buf, sizeof(lead.name));
1558                 }
1559
1560                 rc = writeLead(psm->fd, &lead);
1561                 if (rc) {
1562                     rpmError(RPMERR_NOSPACE, _("Unable to write package: %s\n"),
1563                          Fstrerror(psm->fd));
1564                     rc = RPMRC_FAIL;
1565                     break;
1566                 }
1567             }
1568
1569             /* Write the signature section into the package. */
1570             {   Header sig = headerRegenSigHeader(fi->h);
1571                 rc = rpmWriteSignature(psm->fd, sig);
1572                 sig = rpmFreeSignature(sig);
1573                 if (rc) break;
1574             }
1575
1576             /* Write the metadata section into the package. */
1577             rc = headerWrite(psm->fd, psm->oh, HEADER_MAGIC_YES);
1578             if (rc) break;
1579         }
1580         break;
1581     case PSM_PROCESS:
1582         if (ts->transFlags & RPMTRANS_FLAG_TEST)        break;
1583
1584         if (psm->goal == PSM_PKGINSTALL) {
1585             struct availablePackage * alp = fi->ap;
1586             int i;
1587
1588             if (fi->fc <= 0)                            break;
1589             if (ts->transFlags & RPMTRANS_FLAG_JUSTDB)  break;
1590
1591             for (i = 0; i < fi->fc; i++) {
1592                 uid_t uid;
1593                 gid_t gid;
1594
1595                 uid = fi->uid;
1596                 gid = fi->gid;
1597                 if (fi->fuser && unameToUid(fi->fuser[i], &uid)) {
1598                     rpmMessage(RPMMESS_WARNING,
1599                         _("user %s does not exist - using root\n"),
1600                         fi->fuser[i]);
1601                     uid = 0;
1602                     /* XXX this diddles header memory. */
1603                     fi->fmodes[i] &= ~S_ISUID;  /* turn off the suid bit */
1604                 }
1605
1606                 if (fi->fgroup && gnameToGid(fi->fgroup[i], &gid)) {
1607                     rpmMessage(RPMMESS_WARNING,
1608                         _("group %s does not exist - using root\n"),
1609                         fi->fgroup[i]);
1610                     gid = 0;
1611                     /* XXX this diddles header memory. */
1612                     fi->fmodes[i] &= ~S_ISGID;  /* turn off the sgid bit */
1613                 }
1614                 if (fi->fuids) fi->fuids[i] = uid;
1615                 if (fi->fgids) fi->fgids[i] = gid;
1616             }
1617
1618             /* Retrieve type of payload compression. */
1619             rc = psmStage(psm, PSM_RPMIO_FLAGS);
1620
1621             if (alp->fd == NULL) {      /* XXX can't happen */
1622                 rc = RPMRC_FAIL;
1623                 break;
1624             }
1625             /*@-nullpass@*/     /* LCL: alp->fd != NULL here. */
1626             psm->cfd = Fdopen(fdDup(Fileno(alp->fd)), psm->rpmio_flags);
1627             /*@=nullpass@*/
1628             if (psm->cfd == NULL) {     /* XXX can't happen */
1629                 rc = RPMRC_FAIL;
1630                 break;
1631             }
1632
1633             rc = fsmSetup(fi->fsm, FSM_PKGINSTALL, ts, fi,
1634                         psm->cfd, NULL, &psm->failedFile);
1635             xx = fsmTeardown(fi->fsm);
1636
1637             saveerrno = errno; /* XXX FIXME: Fclose with libio destroys errno */
1638             xx = Fclose(psm->cfd);
1639             psm->cfd = NULL;
1640             /*@-mods@*/
1641             errno = saveerrno; /* XXX FIXME: Fclose with libio destroys errno */
1642             /*@=mods@*/
1643
1644             if (!rc)
1645                 rc = psmStage(psm, PSM_COMMIT);
1646
1647             if (rc) {
1648                 rpmError(RPMERR_CPIO,
1649                         _("unpacking of archive failed%s%s: %s\n"),
1650                         (psm->failedFile != NULL ? _(" on file ") : ""),
1651                         (psm->failedFile != NULL ? psm->failedFile : ""),
1652                         cpioStrerror(rc));
1653                 rc = RPMRC_FAIL;
1654                 break;
1655             }
1656             psm->what = RPMCALLBACK_INST_PROGRESS;
1657             psm->amount = (fi->archiveSize ? fi->archiveSize : 100);
1658             psm->total = psm->amount;
1659             xx = psmStage(psm, PSM_NOTIFY);
1660         }
1661         if (psm->goal == PSM_PKGERASE) {
1662
1663             if (fi->fc <= 0)                            break;
1664             if (ts->transFlags & RPMTRANS_FLAG_JUSTDB)  break;
1665             if (ts->transFlags & RPMTRANS_FLAG_APPLYONLY)       break;
1666
1667             psm->what = RPMCALLBACK_UNINST_START;
1668             psm->amount = fi->fc;       /* XXX W2DO? looks wrong. */
1669             psm->total = fi->fc;
1670             xx = psmStage(psm, PSM_NOTIFY);
1671
1672             rc = fsmSetup(fi->fsm, FSM_PKGERASE, ts, fi,
1673                         NULL, NULL, &psm->failedFile);
1674             xx = fsmTeardown(fi->fsm);
1675
1676             psm->what = RPMCALLBACK_UNINST_STOP;
1677             psm->amount = 0;            /* XXX W2DO? looks wrong. */
1678             psm->total = fi->fc;
1679             xx = psmStage(psm, PSM_NOTIFY);
1680
1681         }
1682         if (psm->goal == PSM_PKGSAVE) {
1683             fileAction * actions = fi->actions;
1684             fileAction action = fi->action;
1685
1686             fi->action = FA_COPYOUT;
1687             fi->actions = NULL;
1688
1689             if (psm->fd == NULL) {      /* XXX can't happen */
1690                 rc = RPMRC_FAIL;
1691                 break;
1692             }
1693             /*@-nullpass@*/     /* LCL: psm->fd != NULL here. */
1694             xx = Fflush(psm->fd);
1695             psm->cfd = Fdopen(fdDup(Fileno(psm->fd)), psm->rpmio_flags);
1696             /*@=nullpass@*/
1697             if (psm->cfd == NULL) {     /* XXX can't happen */
1698                 rc = RPMRC_FAIL;
1699                 break;
1700             }
1701
1702             rc = fsmSetup(fi->fsm, FSM_PKGBUILD, ts, fi, psm->cfd,
1703                         NULL, &psm->failedFile);
1704             xx = fsmTeardown(fi->fsm);
1705
1706             saveerrno = errno; /* XXX FIXME: Fclose with libio destroys errno */
1707             xx = Fclose(psm->cfd);
1708             psm->cfd = NULL;
1709             /*@-mods@*/
1710             errno = saveerrno;
1711             /*@=mods@*/
1712
1713             fi->action = action;
1714             fi->actions = actions;
1715         }
1716         break;
1717     case PSM_POST:
1718         if (ts->transFlags & RPMTRANS_FLAG_TEST)        break;
1719
1720         if (psm->goal == PSM_PKGINSTALL) {
1721             int_32 installTime = (int_32) time(NULL);
1722
1723             if (fi->fstates != NULL && fi->fc > 0)
1724                 xx = headerAddEntry(fi->h, RPMTAG_FILESTATES, RPM_CHAR_TYPE,
1725                                 fi->fstates, fi->fc);
1726
1727             xx = headerAddEntry(fi->h, RPMTAG_INSTALLTIME, RPM_INT32_TYPE,
1728                                 &installTime, 1);
1729
1730             if (ts->transFlags & RPMTRANS_FLAG_MULTILIB) {
1731                 uint_32 multiLib, * newMultiLib, * p;
1732
1733                 if (hge(fi->h, RPMTAG_MULTILIBS, NULL,
1734                                 (void **) &newMultiLib, NULL) &&
1735                     hge(psm->oh, RPMTAG_MULTILIBS, NULL,
1736                                 (void **) &p, NULL))
1737                 {
1738                     multiLib = *p;
1739                     multiLib |= *newMultiLib;
1740                     xx = hme(psm->oh, RPMTAG_MULTILIBS, RPM_INT32_TYPE,
1741                                       &multiLib, 1);
1742                 }
1743                 rc = mergeFiles(fi, psm->oh, fi->h);
1744                 if (rc) break;
1745             }
1746
1747
1748             /*
1749              * If this package has already been installed, remove it from
1750              * the database before adding the new one.
1751              */
1752             if (fi->record && !(ts->transFlags & RPMTRANS_FLAG_APPLYONLY)) {
1753                 rc = psmStage(psm, PSM_RPMDB_REMOVE);
1754                 if (rc) break;
1755             }
1756
1757             rc = psmStage(psm, PSM_RPMDB_ADD);
1758             if (rc) break;
1759
1760             psm->scriptTag = RPMTAG_POSTIN;
1761             psm->progTag = RPMTAG_POSTINPROG;
1762             psm->sense = RPMSENSE_TRIGGERIN;
1763             psm->countCorrection = 0;
1764
1765             if (!(ts->transFlags & RPMTRANS_FLAG_NOPOST)) {
1766                 rc = psmStage(psm, PSM_SCRIPT);
1767                 if (rc) break;
1768             }
1769             if (!(ts->transFlags & RPMTRANS_FLAG_NOTRIGGERIN)) {
1770                 /* Run triggers in other package(s) this package sets off. */
1771                 rc = psmStage(psm, PSM_TRIGGERS);
1772                 if (rc) break;
1773
1774                 /* Run triggers in this package other package(s) set off. */
1775                 rc = psmStage(psm, PSM_IMMED_TRIGGERS);
1776                 if (rc) break;
1777             }
1778
1779             if (!(ts->transFlags & RPMTRANS_FLAG_APPLYONLY))
1780                 rc = markReplacedFiles(psm);
1781
1782         }
1783         if (psm->goal == PSM_PKGERASE) {
1784
1785             psm->scriptTag = RPMTAG_POSTUN;
1786             psm->progTag = RPMTAG_POSTUNPROG;
1787             psm->sense = RPMSENSE_TRIGGERPOSTUN;
1788             psm->countCorrection = -1;
1789
1790             if (!(ts->transFlags & RPMTRANS_FLAG_NOPOSTUN)) {
1791                 rc = psmStage(psm, PSM_SCRIPT);
1792                 /* XXX WTFO? postun failures don't cause erasure failure. */
1793             }
1794
1795             if (!(ts->transFlags & RPMTRANS_FLAG_NOTRIGGERPOSTUN)) {
1796                 /* Run triggers in other package(s) this package sets off. */
1797                 rc = psmStage(psm, PSM_TRIGGERS);
1798                 if (rc) break;
1799             }
1800
1801             if (!(ts->transFlags & RPMTRANS_FLAG_APPLYONLY))
1802                 rc = psmStage(psm, PSM_RPMDB_REMOVE);
1803         }
1804         if (psm->goal == PSM_PKGSAVE) {
1805         }
1806
1807         /* Restore root directory if changed. */
1808         xx = psmStage(psm, PSM_CHROOT_OUT);
1809         break;
1810     case PSM_UNDO:
1811         break;
1812     case PSM_FINI:
1813         /* Restore root directory if changed. */
1814         xx = psmStage(psm, PSM_CHROOT_OUT);
1815
1816         if (psm->fd) {
1817             saveerrno = errno; /* XXX FIXME: Fclose with libio destroys errno */
1818             xx = Fclose(psm->fd);
1819             psm->fd = NULL;
1820             /*@-mods@*/
1821             errno = saveerrno;
1822             /*@=mods@*/
1823         }
1824
1825         if (psm->goal == PSM_PKGSAVE) {
1826             if (!rc) {
1827                 rpmMessage(RPMMESS_VERBOSE, _("Wrote: %s\n"),
1828                         (psm->pkgURL ? psm->pkgURL : "???"));
1829             }
1830         }
1831
1832         if (rc) {
1833             if (psm->failedFile)
1834                 rpmError(RPMERR_CPIO,
1835                         _("%s failed on file %s: %s\n"),
1836                         psm->stepName, psm->failedFile, cpioStrerror(rc));
1837             else
1838                 rpmError(RPMERR_CPIO, _("%s failed: %s\n"),
1839                         psm->stepName, cpioStrerror(rc));
1840         }
1841
1842         if (fi->h && (psm->goal == PSM_PKGERASE || psm->goal == PSM_PKGSAVE))
1843             fi->h = headerFree(fi->h);
1844         psm->oh = headerFree(psm->oh);
1845         psm->pkgURL = _free(psm->pkgURL);
1846         psm->rpmio_flags = _free(psm->rpmio_flags);
1847         psm->failedFile = _free(psm->failedFile);
1848
1849         fi->fgids = _free(fi->fgids);
1850         fi->fuids = _free(fi->fuids);
1851         fi->fgroup = hfd(fi->fgroup, -1);
1852         fi->fuser = hfd(fi->fuser, -1);
1853         fi->apath = _free(fi->apath);
1854         fi->fstates = _free(fi->fstates);
1855         break;
1856
1857     case PSM_PKGINSTALL:
1858     case PSM_PKGERASE:
1859     case PSM_PKGSAVE:
1860         psm->goal = stage;
1861         psm->rc = RPMRC_OK;
1862         psm->stepName = pkgStageString(stage);
1863
1864         rc = psmStage(psm, PSM_INIT);
1865         if (!rc) rc = psmStage(psm, PSM_PRE);
1866         if (!rc) rc = psmStage(psm, PSM_PROCESS);
1867         if (!rc) rc = psmStage(psm, PSM_POST);
1868         xx = psmStage(psm, PSM_FINI);
1869         break;
1870     case PSM_PKGCOMMIT:
1871         break;
1872
1873     case PSM_CREATE:
1874         break;
1875     case PSM_NOTIFY:
1876         if (ts && ts->notify) {
1877             /*@-noeffectuncon @*/ /* FIX: check rc */
1878             (void) ts->notify(fi->h, psm->what, psm->amount, psm->total,
1879                 (fi->ap ? fi->ap->key : NULL), ts->notifyData);
1880             /*@=noeffectuncon @*/
1881         }
1882         break;
1883     case PSM_DESTROY:
1884         break;
1885     case PSM_COMMIT:
1886         if (!(ts->transFlags & RPMTRANS_FLAG_PKGCOMMIT)) break;
1887         if (ts->transFlags & RPMTRANS_FLAG_APPLYONLY) break;
1888
1889         rc = fsmSetup(fi->fsm, FSM_PKGCOMMIT, ts, fi,
1890                         NULL, NULL, &psm->failedFile);
1891         xx = fsmTeardown(fi->fsm);
1892         break;
1893
1894     case PSM_CHROOT_IN:
1895         /* Change root directory if requested and not already done. */
1896         if (ts->rootDir && !ts->chrootDone && !psm->chrootDone) {
1897             static int _loaded = 0;
1898
1899             /*
1900              * This loads all of the name services libraries, in case we
1901              * don't have access to them in the chroot().
1902              */
1903             if (!_loaded) {
1904                 (void)getpwnam("root");
1905                 endpwent();
1906                 _loaded++;
1907             }
1908
1909             xx = chdir("/");
1910             /*@-superuser@*/
1911             rc = chroot(ts->rootDir);
1912             /*@=superuser@*/
1913             psm->chrootDone = ts->chrootDone = 1;
1914             if (ts->rpmdb != NULL) ts->rpmdb->db_chrootDone = 1;
1915             /*@-onlytrans@*/
1916             /*@-mods@*/
1917             chroot_prefix = ts->rootDir;
1918             /*@=mods@*/
1919             /*@=onlytrans@*/
1920         }
1921         break;
1922     case PSM_CHROOT_OUT:
1923         /* Restore root directory if changed. */
1924         if (psm->chrootDone) {
1925             /*@-superuser@*/
1926             rc = chroot(".");
1927             /*@=superuser@*/
1928             psm->chrootDone = ts->chrootDone = 0;
1929             if (ts->rpmdb != NULL) ts->rpmdb->db_chrootDone = 0;
1930             /*@-mods@*/
1931             chroot_prefix = NULL;
1932             /*@=mods@*/
1933             xx = chdir(ts->currDir);
1934         }
1935         break;
1936     case PSM_SCRIPT:
1937         rpmMessage(RPMMESS_DEBUG, _("%s: running %s script(s) (if any)\n"),
1938                 psm->stepName, tag2sln(psm->scriptTag));
1939         rc = runInstScript(psm);
1940         break;
1941     case PSM_TRIGGERS:
1942         /* Run triggers in other package(s) this package sets off. */
1943         rc = runTriggers(psm);
1944         break;
1945     case PSM_IMMED_TRIGGERS:
1946         /* Run triggers in this package other package(s) set off. */
1947         rc = runImmedTriggers(psm);
1948         break;
1949
1950     case PSM_RPMIO_FLAGS:
1951     {   const char * payload_compressor = NULL;
1952         char * t;
1953
1954         if (!hge(fi->h, RPMTAG_PAYLOADCOMPRESSOR, NULL,
1955                             (void **) &payload_compressor, NULL))
1956             payload_compressor = "gzip";
1957         psm->rpmio_flags = t = xmalloc(sizeof("w9.gzdio"));
1958         *t = '\0';
1959         t = stpcpy(t, ((psm->goal == PSM_PKGSAVE) ? "w9" : "r"));
1960         if (!strcmp(payload_compressor, "gzip"))
1961             t = stpcpy(t, ".gzdio");
1962         if (!strcmp(payload_compressor, "bzip2"))
1963             t = stpcpy(t, ".bzdio");
1964         rc = RPMRC_OK;
1965     }   break;
1966
1967     case PSM_RPMDB_LOAD:
1968 assert(psm->mi == NULL);
1969         psm->mi = rpmdbInitIterator(ts->rpmdb, RPMDBI_PACKAGES,
1970                                 &fi->record, sizeof(fi->record));
1971
1972         fi->h = rpmdbNextIterator(psm->mi);
1973         if (fi->h)
1974             fi->h = headerLink(fi->h);
1975 else {
1976 fprintf(stderr, "*** PSM_RDB_LOAD: header #%u not found\n", fi->record);
1977 }
1978         psm->mi = rpmdbFreeIterator(psm->mi);
1979         rc = (fi->h ? RPMRC_OK : RPMRC_FAIL);
1980         break;
1981     case PSM_RPMDB_ADD:
1982         if (ts->transFlags & RPMTRANS_FLAG_TEST)        break;
1983         rc = rpmdbAdd(ts->rpmdb, ts->id, fi->h);
1984         break;
1985     case PSM_RPMDB_REMOVE:
1986         if (ts->transFlags & RPMTRANS_FLAG_TEST)        break;
1987         rc = rpmdbRemove(ts->rpmdb, ts->id, fi->record);
1988         break;
1989
1990     default:
1991         break;
1992     }
1993     /*@=branchstate@*/
1994
1995     /*@-nullstate@*/    /* FIX: psm->oh and psm->fi->h may be NULL. */
1996     return rc;
1997     /*@=nullstate@*/
1998 }