fix: prevent segfault if malicious server sends 1 GB of data through ftpNLST.
[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(rpmtsOp(ts, RPMTS_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 /*@-internalglobs@*/
1116     psm->ts = rpmtsFree(psm->ts);
1117 /*@=internalglobs@*/
1118
1119     (void) rpmpsmUnlink(psm, msg);
1120
1121     /*@-refcounttrans -usereleased@*/
1122 /*@-boundswrite@*/
1123     memset(psm, 0, sizeof(*psm));               /* XXX trash and burn */
1124 /*@=boundswrite@*/
1125     psm = _free(psm);
1126     /*@=refcounttrans =usereleased@*/
1127
1128     return NULL;
1129 /*@=nullstate@*/
1130 }
1131
1132 rpmpsm rpmpsmNew(rpmts ts, rpmte te, rpmfi fi)
1133 {
1134     const char * msg = "rpmpsmNew";
1135     rpmpsm psm = xcalloc(1, sizeof(*psm));
1136
1137     if (ts)     psm->ts = rpmtsLink(ts, msg);
1138 #ifdef  NOTYET
1139     if (te)     psm->te = rpmteLink(te, msg);
1140 #else
1141 /*@-assignexpose -temptrans @*/
1142     if (te)     psm->te = te;
1143 /*@=assignexpose =temptrans @*/
1144 #endif
1145     if (fi)     psm->fi = rpmfiLink(fi, msg);
1146
1147     return rpmpsmLink(psm, msg);
1148 }
1149
1150 static void * rpmpsmThread(void * arg)
1151         /*@globals rpmGlobalMacroContext, fileSystem, internalState @*/
1152         /*@modifies arg, rpmGlobalMacroContext, fileSystem, internalState @*/
1153 {
1154     rpmpsm psm = arg;
1155 /*@-unqualifiedtrans@*/
1156     return ((void *) rpmpsmStage(psm, psm->nstage));
1157 /*@=unqualifiedtrans@*/
1158 }
1159
1160 static int rpmpsmNext(rpmpsm psm, pkgStage nstage)
1161         /*@globals rpmGlobalMacroContext, fileSystem, internalState @*/
1162         /*@modifies psm, rpmGlobalMacroContext, fileSystem, internalState @*/
1163 {
1164     psm->nstage = nstage;
1165     if (_psm_threads)
1166         return rpmsqJoin( rpmsqThread(rpmpsmThread, psm) );
1167     return rpmpsmStage(psm, psm->nstage);
1168 }
1169
1170 /**
1171  * @todo Packages w/o files never get a callback, hence don't get displayed
1172  * on install with -v.
1173  */
1174 /*@-bounds -nullpass@*/ /* FIX: testing null annotation for fi->h */
1175 rpmRC rpmpsmStage(rpmpsm psm, pkgStage stage)
1176 {
1177     const rpmts ts = psm->ts;
1178     uint_32 tscolor = rpmtsColor(ts);
1179     rpmfi fi = psm->fi;
1180     HGE_t hge = fi->hge;
1181     HFD_t hfd = (fi->hfd ? fi->hfd : headerFreeData);
1182     rpmRC rc = psm->rc;
1183     int saveerrno;
1184     int xx;
1185
1186     /*@-branchstate@*/
1187     switch (stage) {
1188     case PSM_UNKNOWN:
1189         break;
1190     case PSM_INIT:
1191         rpmMessage(RPMMESS_DEBUG, _("%s: %s has %d files, test = %d\n"),
1192                 psm->stepName, rpmteNEVR(psm->te),
1193                 rpmfiFC(fi), (rpmtsFlags(ts) & RPMTRANS_FLAG_TEST));
1194
1195         /*
1196          * When we run scripts, we pass an argument which is the number of 
1197          * versions of this package that will be installed when we are
1198          * finished.
1199          */
1200         psm->npkgs_installed = rpmdbCountPackages(rpmtsGetRdb(ts), rpmteN(psm->te));
1201         if (psm->npkgs_installed < 0) {
1202             rc = RPMRC_FAIL;
1203             break;
1204         }
1205
1206         if (psm->goal == PSM_PKGINSTALL) {
1207             int fc = rpmfiFC(fi);
1208
1209             psm->scriptArg = psm->npkgs_installed + 1;
1210
1211 assert(psm->mi == NULL);
1212             psm->mi = rpmtsInitIterator(ts, RPMTAG_NAME, rpmteN(psm->te), 0);
1213             xx = rpmdbSetIteratorRE(psm->mi, RPMTAG_EPOCH, RPMMIRE_DEFAULT,
1214                         rpmteE(psm->te));
1215             xx = rpmdbSetIteratorRE(psm->mi, RPMTAG_VERSION, RPMMIRE_DEFAULT,
1216                         rpmteV(psm->te));
1217             xx = rpmdbSetIteratorRE(psm->mi, RPMTAG_RELEASE, RPMMIRE_DEFAULT,
1218                         rpmteR(psm->te));
1219             if (tscolor) {
1220                 xx = rpmdbSetIteratorRE(psm->mi, RPMTAG_ARCH, RPMMIRE_DEFAULT,
1221                         rpmteA(psm->te));
1222                 xx = rpmdbSetIteratorRE(psm->mi, RPMTAG_OS, RPMMIRE_DEFAULT,
1223                         rpmteO(psm->te));
1224             }
1225
1226             while ((psm->oh = rpmdbNextIterator(psm->mi)) != NULL) {
1227                 fi->record = rpmdbGetIteratorOffset(psm->mi);
1228                 psm->oh = NULL;
1229                 /*@loopbreak@*/ break;
1230             }
1231             psm->mi = rpmdbFreeIterator(psm->mi);
1232             rc = RPMRC_OK;
1233
1234             /* XXX lazy alloc here may need to be done elsewhere. */
1235             if (fi->fstates == NULL && fc > 0) {
1236                 fi->fstates = xmalloc(sizeof(*fi->fstates) * fc);
1237                 memset(fi->fstates, RPMFILE_STATE_NORMAL, fc);
1238             }
1239
1240             if (rpmtsFlags(ts) & RPMTRANS_FLAG_JUSTDB)  break;
1241             if (fc <= 0)                                break;
1242         
1243             /*
1244              * Old format relocateable packages need the entire default
1245              * prefix stripped to form the cpio list, while all other packages
1246              * need the leading / stripped.
1247              */
1248             {   const char * p;
1249                 xx = hge(fi->h, RPMTAG_DEFAULTPREFIX, NULL, (void **) &p, NULL);
1250                 fi->striplen = (xx ? strlen(p) + 1 : 1); 
1251             }
1252             fi->mapflags =
1253                 CPIO_MAP_PATH | CPIO_MAP_MODE | CPIO_MAP_UID | CPIO_MAP_GID;
1254         
1255             if (headerIsEntry(fi->h, RPMTAG_ORIGBASENAMES))
1256                 rpmfiBuildFNames(fi->h, RPMTAG_ORIGBASENAMES, &fi->apath, NULL);
1257             else
1258                 rpmfiBuildFNames(fi->h, RPMTAG_BASENAMES, &fi->apath, NULL);
1259         
1260             if (fi->fuser == NULL)
1261                 xx = hge(fi->h, RPMTAG_FILEUSERNAME, NULL,
1262                                 (void **) &fi->fuser, NULL);
1263             if (fi->fgroup == NULL)
1264                 xx = hge(fi->h, RPMTAG_FILEGROUPNAME, NULL,
1265                                 (void **) &fi->fgroup, NULL);
1266             if (fi->fuids == NULL)
1267                 fi->fuids = xcalloc(sizeof(*fi->fuids), fc);
1268             if (fi->fgids == NULL)
1269                 fi->fgids = xcalloc(sizeof(*fi->fgids), fc);
1270             rc = RPMRC_OK;
1271         }
1272         if (psm->goal == PSM_PKGERASE || psm->goal == PSM_PKGSAVE) {
1273             psm->scriptArg = psm->npkgs_installed - 1;
1274         
1275             /* Retrieve installed header. */
1276             rc = rpmpsmNext(psm, PSM_RPMDB_LOAD);
1277 if (rc == RPMRC_OK)
1278 if (psm->te)
1279 psm->te->h = headerLink(fi->h);
1280         }
1281         if (psm->goal == PSM_PKGSAVE) {
1282             /* Open output package for writing. */
1283             {   const char * bfmt = rpmGetPath("%{_repackage_name_fmt}", NULL);
1284                 const char * pkgbn =
1285                         headerSprintf(fi->h, bfmt, rpmTagTable, rpmHeaderFormats, NULL);
1286
1287                 bfmt = _free(bfmt);
1288                 psm->pkgURL = rpmGenPath("%{?_repackage_root}",
1289                                          "%{?_repackage_dir}",
1290                                         pkgbn);
1291                 pkgbn = _free(pkgbn);
1292                 (void) urlPath(psm->pkgURL, &psm->pkgfn);
1293                 psm->fd = Fopen(psm->pkgfn, "w.ufdio");
1294                 if (psm->fd == NULL || Ferror(psm->fd)) {
1295                     rc = RPMRC_FAIL;
1296                     break;
1297                 }
1298             }
1299         }
1300         break;
1301     case PSM_PRE:
1302         if (rpmtsFlags(ts) & RPMTRANS_FLAG_TEST)        break;
1303
1304 /* XXX insure that trigger index is opened before entering chroot. */
1305 #ifdef  NOTYET
1306  { static int oneshot = 0;
1307    dbiIndex dbi;
1308    if (!oneshot) {
1309      dbi = dbiOpen(rpmtsGetRdb(ts), RPMTAG_TRIGGERNAME, 0);
1310      oneshot++;
1311    }
1312  }
1313 #endif
1314
1315         /* Change root directory if requested and not already done. */
1316         rc = rpmpsmNext(psm, PSM_CHROOT_IN);
1317
1318         if (psm->goal == PSM_PKGINSTALL) {
1319             psm->scriptTag = RPMTAG_PREIN;
1320             psm->progTag = RPMTAG_PREINPROG;
1321
1322             if (!(rpmtsFlags(ts) & RPMTRANS_FLAG_NOTRIGGERPREIN)) {
1323                 /* XXX FIXME: implement %triggerprein. */
1324             }
1325
1326             if (!(rpmtsFlags(ts) & RPMTRANS_FLAG_NOPRE)) {
1327                 rc = rpmpsmNext(psm, PSM_SCRIPT);
1328                 if (rc != RPMRC_OK) {
1329                     rpmError(RPMERR_SCRIPT,
1330                         _("%s: %s scriptlet failed (%d), skipping %s\n"),
1331                         psm->stepName, tag2sln(psm->scriptTag), rc,
1332                         rpmteNEVR(psm->te));
1333                     break;
1334                 }
1335             }
1336         }
1337
1338         if (psm->goal == PSM_PKGERASE) {
1339             psm->scriptTag = RPMTAG_PREUN;
1340             psm->progTag = RPMTAG_PREUNPROG;
1341             psm->sense = RPMSENSE_TRIGGERUN;
1342             psm->countCorrection = -1;
1343
1344             if (!(rpmtsFlags(ts) & RPMTRANS_FLAG_NOTRIGGERUN)) {
1345                 /* Run triggers in this package other package(s) set off. */
1346                 rc = rpmpsmNext(psm, PSM_IMMED_TRIGGERS);
1347                 if (rc) break;
1348
1349                 /* Run triggers in other package(s) this package sets off. */
1350                 rc = rpmpsmNext(psm, PSM_TRIGGERS);
1351                 if (rc) break;
1352             }
1353
1354             if (!(rpmtsFlags(ts) & RPMTRANS_FLAG_NOPREUN))
1355                 rc = rpmpsmNext(psm, PSM_SCRIPT);
1356         }
1357         if (psm->goal == PSM_PKGSAVE) {
1358             int noArchiveSize = 0;
1359
1360             /* Regenerate original header. */
1361             {   void * uh = NULL;
1362                 int_32 uht, uhc;
1363
1364                 if (headerGetEntry(fi->h, RPMTAG_HEADERIMMUTABLE, &uht, &uh, &uhc)) {
1365                     psm->oh = headerCopyLoad(uh);
1366                     uh = hfd(uh, uht);
1367                 } else
1368                 if (headerGetEntry(fi->h, RPMTAG_HEADERIMAGE, &uht, &uh, &uhc))
1369                 {
1370                     HeaderIterator hi;
1371                     int_32 tag, type, count;
1372                     hPTR_t ptr;
1373                     Header oh;
1374
1375                     /* Load the original header from the blob. */
1376                     oh = headerCopyLoad(uh);
1377
1378                     /* XXX this is headerCopy w/o headerReload() */
1379                     psm->oh = headerNew();
1380
1381                     /*@-branchstate@*/
1382                     for (hi = headerInitIterator(oh);
1383                         headerNextIterator(hi, &tag, &type, &ptr, &count);
1384                         ptr = headerFreeData((void *)ptr, type))
1385                     {
1386                         if (tag == RPMTAG_ARCHIVESIZE)
1387                             noArchiveSize = 1;
1388                         if (ptr) (void) headerAddEntry(psm->oh, tag, type, ptr, count);
1389                     }
1390                     hi = headerFreeIterator(hi);
1391                     /*@=branchstate@*/
1392
1393                     oh = headerFree(oh);
1394                     uh = hfd(uh, uht);
1395                 } else
1396                     break;      /* XXX shouldn't ever happen */
1397             }
1398
1399             /* Retrieve type of payload compression. */
1400             /*@-nullstate@*/    /* FIX: psm->oh may be NULL */
1401             rc = rpmpsmNext(psm, PSM_RPMIO_FLAGS);
1402             /*@=nullstate@*/
1403
1404             /* Write the lead section into the package. */
1405             {   int archnum = -1;
1406                 int osnum = -1;
1407                 struct rpmlead lead;
1408
1409 #ifndef DYING
1410                 rpmGetArchInfo(NULL, &archnum);
1411                 rpmGetOsInfo(NULL, &osnum);
1412 #endif
1413
1414                 memset(&lead, 0, sizeof(lead));
1415                 /* XXX Set package version conditioned on noDirTokens. */
1416                 lead.major = 3;
1417                 lead.minor = 0;
1418                 lead.type = RPMLEAD_BINARY;
1419                 lead.archnum = archnum;
1420                 lead.osnum = osnum;
1421                 lead.signature_type = RPMSIGTYPE_HEADERSIG;
1422
1423                 strncpy(lead.name, rpmteNEVR(psm->te), sizeof(lead.name));
1424
1425                 rc = writeLead(psm->fd, &lead);
1426                 if (rc != RPMRC_OK) {
1427                     rpmError(RPMERR_NOSPACE, _("Unable to write package: %s\n"),
1428                          Fstrerror(psm->fd));
1429                     break;
1430                 }
1431             }
1432
1433             /* Write the signature section into the package. */
1434             /* XXX rpm-4.1 and later has archive size in signature header. */
1435             {   Header sigh = headerRegenSigHeader(fi->h, noArchiveSize);
1436                 /* Reallocate the signature into one contiguous region. */
1437                 sigh = headerReload(sigh, RPMTAG_HEADERSIGNATURES);
1438                 if (sigh == NULL) {
1439                     rpmError(RPMERR_NOSPACE, _("Unable to reload signature header\n"));
1440                     rc = RPMRC_FAIL;
1441                     break;
1442                 }
1443                 rc = rpmWriteSignature(psm->fd, sigh);
1444                 sigh = rpmFreeSignature(sigh);
1445                 if (rc) break;
1446             }
1447
1448             /* Add remove transaction id to header. */
1449             if (psm->oh != NULL)
1450             {   int_32 tid = rpmtsGetTid(ts);
1451                 xx = headerAddEntry(psm->oh, RPMTAG_REMOVETID,
1452                         RPM_INT32_TYPE, &tid, 1);
1453             }
1454
1455             /* Write the metadata section into the package. */
1456             rc = headerWrite(psm->fd, psm->oh, HEADER_MAGIC_YES);
1457             if (rc) break;
1458         }
1459         break;
1460     case PSM_PROCESS:
1461         if (rpmtsFlags(ts) & RPMTRANS_FLAG_TEST)        break;
1462
1463         if (psm->goal == PSM_PKGINSTALL) {
1464             int i;
1465
1466             if (rpmtsFlags(ts) & RPMTRANS_FLAG_JUSTDB)  break;
1467
1468             /* XXX Synthesize callbacks for packages with no files. */
1469             if (rpmfiFC(fi) <= 0) {
1470                 void * ptr;
1471                 ptr = rpmtsNotify(ts, fi->te, RPMCALLBACK_INST_START, 0, 100);
1472                 ptr = rpmtsNotify(ts, fi->te, RPMCALLBACK_INST_PROGRESS, 100, 100);
1473                 break;
1474             }
1475
1476             (void) rpmfiInit(fi, 0);
1477             while ((i = rpmfiNext(fi)) >= 0) {
1478                 uid_t uid;
1479                 gid_t gid;
1480
1481                 uid = fi->uid;
1482                 gid = fi->gid;
1483                 if (fi->fuser && unameToUid(fi->fuser[i], &uid)) {
1484                     rpmMessage(RPMMESS_WARNING,
1485                         _("user %s does not exist - using root\n"),
1486                         fi->fuser[i]);
1487                     uid = 0;
1488                     /* XXX this diddles header memory. */
1489                     fi->fmodes[i] &= ~S_ISUID;  /* turn off the suid bit */
1490                 }
1491
1492                 if (fi->fgroup && gnameToGid(fi->fgroup[i], &gid)) {
1493                     rpmMessage(RPMMESS_WARNING,
1494                         _("group %s does not exist - using root\n"),
1495                         fi->fgroup[i]);
1496                     gid = 0;
1497                     /* XXX this diddles header memory. */
1498                     fi->fmodes[i] &= ~S_ISGID;  /* turn off the sgid bit */
1499                 }
1500                 if (fi->fuids) fi->fuids[i] = uid;
1501                 if (fi->fgids) fi->fgids[i] = gid;
1502             }
1503
1504             /* Retrieve type of payload compression. */
1505             rc = rpmpsmNext(psm, PSM_RPMIO_FLAGS);
1506
1507             if (rpmteFd(fi->te) == NULL) {      /* XXX can't happen */
1508                 rc = RPMRC_FAIL;
1509                 break;
1510             }
1511
1512             /*@-nullpass@*/     /* LCL: fi->fd != NULL here. */
1513             psm->cfd = Fdopen(fdDup(Fileno(rpmteFd(fi->te))), psm->rpmio_flags);
1514             /*@=nullpass@*/
1515             if (psm->cfd == NULL) {     /* XXX can't happen */
1516                 rc = RPMRC_FAIL;
1517                 break;
1518             }
1519
1520             rc = fsmSetup(fi->fsm, FSM_PKGINSTALL, ts, fi,
1521                         psm->cfd, NULL, &psm->failedFile);
1522             (void) rpmswAdd(rpmtsOp(ts, RPMTS_OP_UNCOMPRESS),
1523                         fdstat_op(psm->cfd, FDSTAT_READ));
1524             (void) rpmswAdd(rpmtsOp(ts, RPMTS_OP_DIGEST),
1525                         fdstat_op(psm->cfd, FDSTAT_DIGEST));
1526             xx = fsmTeardown(fi->fsm);
1527
1528             saveerrno = errno; /* XXX FIXME: Fclose with libio destroys errno */
1529             xx = Fclose(psm->cfd);
1530             psm->cfd = NULL;
1531             /*@-mods@*/
1532             errno = saveerrno; /* XXX FIXME: Fclose with libio destroys errno */
1533             /*@=mods@*/
1534
1535             if (!rc)
1536                 rc = rpmpsmNext(psm, PSM_COMMIT);
1537
1538             /* XXX make sure progress is closed out */
1539             psm->what = RPMCALLBACK_INST_PROGRESS;
1540             psm->amount = (fi->archiveSize ? fi->archiveSize : 100);
1541             psm->total = psm->amount;
1542             xx = rpmpsmNext(psm, PSM_NOTIFY);
1543
1544             if (rc) {
1545                 rpmError(RPMERR_CPIO,
1546                         _("unpacking of archive failed%s%s: %s\n"),
1547                         (psm->failedFile != NULL ? _(" on file ") : ""),
1548                         (psm->failedFile != NULL ? psm->failedFile : ""),
1549                         cpioStrerror(rc));
1550                 rc = RPMRC_FAIL;
1551
1552                 /* XXX notify callback on error. */
1553                 psm->what = RPMCALLBACK_UNPACK_ERROR;
1554                 psm->amount = 0;
1555                 psm->total = 0;
1556                 xx = rpmpsmNext(psm, PSM_NOTIFY);
1557
1558                 break;
1559             }
1560         }
1561         if (psm->goal == PSM_PKGERASE) {
1562             int fc = rpmfiFC(fi);
1563
1564             if (rpmtsFlags(ts) & RPMTRANS_FLAG_JUSTDB)  break;
1565             if (rpmtsFlags(ts) & RPMTRANS_FLAG_APPLYONLY)       break;
1566             if (fc <= 0)                                break;
1567
1568             psm->what = RPMCALLBACK_UNINST_START;
1569             psm->amount = fc;           /* XXX W2DO? looks wrong. */
1570             psm->total = fc;
1571             xx = rpmpsmNext(psm, PSM_NOTIFY);
1572
1573             rc = fsmSetup(fi->fsm, FSM_PKGERASE, ts, fi,
1574                         NULL, NULL, &psm->failedFile);
1575             xx = fsmTeardown(fi->fsm);
1576
1577             psm->what = RPMCALLBACK_UNINST_STOP;
1578             psm->amount = 0;            /* XXX W2DO? looks wrong. */
1579             psm->total = fc;
1580             xx = rpmpsmNext(psm, PSM_NOTIFY);
1581
1582         }
1583         if (psm->goal == PSM_PKGSAVE) {
1584             fileAction * actions = fi->actions;
1585             fileAction action = fi->action;
1586
1587             fi->action = FA_COPYOUT;
1588             fi->actions = NULL;
1589
1590             if (psm->fd == NULL) {      /* XXX can't happen */
1591                 rc = RPMRC_FAIL;
1592                 break;
1593             }
1594             /*@-nullpass@*/     /* FIX: fdDup mey return NULL. */
1595             xx = Fflush(psm->fd);
1596             psm->cfd = Fdopen(fdDup(Fileno(psm->fd)), psm->rpmio_flags);
1597             /*@=nullpass@*/
1598             if (psm->cfd == NULL) {     /* XXX can't happen */
1599                 rc = RPMRC_FAIL;
1600                 break;
1601             }
1602
1603             rc = fsmSetup(fi->fsm, FSM_PKGBUILD, ts, fi, psm->cfd,
1604                         NULL, &psm->failedFile);
1605             (void) rpmswAdd(rpmtsOp(ts, RPMTS_OP_COMPRESS),
1606                         fdstat_op(psm->cfd, FDSTAT_WRITE));
1607             (void) rpmswAdd(rpmtsOp(ts, RPMTS_OP_DIGEST),
1608                         fdstat_op(psm->cfd, FDSTAT_DIGEST));
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(rpmtsOp(ts, RPMTS_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(rpmtsOp(ts, RPMTS_OP_DBADD), 0);
1896         break;
1897     case PSM_RPMDB_REMOVE:
1898         if (rpmtsFlags(ts) & RPMTRANS_FLAG_TEST)        break;
1899         (void) rpmswEnter(rpmtsOp(ts, RPMTS_OP_DBREMOVE), 0);
1900         rc = rpmdbRemove(rpmtsGetRdb(ts), rpmtsGetTid(ts), fi->record,
1901                                 NULL, NULL);
1902         (void) rpmswExit(rpmtsOp(ts, RPMTS_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@*/