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