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