rpm  5.4.4
lib/psm.c
Go to the documentation of this file.
00001 
00006 #include "system.h"
00007 
00008 #define _MIRE_INTERNAL  /* XXX mireApply doesn't tell which pattern matched. */
00009 
00010 #include <rpmio_internal.h>     /* XXX FDSTAT_READ */
00011 #include <rpmcb.h>              /* XXX fnpyKey */
00012 #include <rpmsx.h>
00013 #include <rpmmacro.h>
00014 #include <rpmurl.h>
00015 
00016 #include <rpmaug.h>
00017 #include <rpmficl.h>
00018 #include <rpmjs.h>
00019 #include <rpmlua.h>
00020 #include <rpmperl.h>
00021 #include <rpmpython.h>
00022 #include <rpmruby.h>
00023 #include <rpmsm.h>
00024 #include <rpmsql.h>
00025 #include <rpmsquirrel.h>
00026 #include <rpmtcl.h>
00027 
00028 #if defined(WITH_LUA) || defined(WITH_AUGEAS) || defined(WITH_FICL) || defined(WITH_GPSEE) || defined(WITH_PERLEMBED) || defined(WITH_PYTHONEMBED) || defined(WITH_RUBYEMBED) || defined(WITH_SEMANAGE) || defined(WITH_SQLITE) || defined(WITH_SQUIRREL) || defined(WITH_TCL)
00029 #define _WITH_EMBEDDED
00030 #else
00031 #undef _WITH_ENBEDDED
00032 #endif
00033 
00034 #include <rpmtag.h>
00035 #include <rpmtypes.h>
00036 #include <pkgio.h>
00037 #define _RPMDB_INTERNAL
00038 #include <rpmdb.h>              /* XXX for db_chrootDone */
00039 #include <rpmtxn.h>
00040 #include "signature.h"          /* signature constants */
00041 #include <rpmlib.h>
00042 
00043 #define _RPMFI_INTERNAL
00044 #include "rpmfi.h"
00045 #include "fsm.h"                /* XXX CPIO_FOO/IOSM_FOO constants */
00046 #define _RPMSQ_INTERNAL
00047 #define _RPMPSM_INTERNAL
00048 #include "psm.h"
00049 #define F_ISSET(_psm, _FLAG)    ((_psm)->flags & (RPMPSM_FLAGS_##_FLAG))
00050 #define F_SET(_psm, _FLAG)      ((_psm)->flags |=  (RPMPSM_FLAGS_##_FLAG))
00051 #define F_CLR(_psm, _FLAG)      ((_psm)->flags &= ~(RPMPSM_FLAGS_##_FLAG))
00052 
00053 #define _RPMEVR_INTERNAL
00054 #include "rpmds.h"
00055 
00056 #define _RPMTE_INTERNAL
00057 #include "rpmte.h"
00058 
00059 #define _RPMTS_INTERNAL         /* XXX ts->notify */
00060 #include "rpmts.h"
00061 
00062 #include "misc.h"               /* XXX rpmMkdirPath, makeTempFile, doputenv */
00063 
00064 #include <rpmcli.h>
00065 
00066 #include "debug.h"
00067 
00068 #if HAVE_SYSLOG
00069 #include <syslog.h>
00070 #include <rpmlog.h>
00071 #endif
00072 
00073 #define _PSM_DEBUG      0
00074 /*@unchecked@*/
00075 int _psm_debug = _PSM_DEBUG;
00076 /*@unchecked@*/
00077 int _psm_threads = 0;
00078 
00079 /*@access FD_t @*/              /* XXX void * arg */
00080 /*@access Header @*/            /* XXX void * arg */
00081 /*@access miRE @*/
00082 
00083 /*@access rpmpsm @*/
00084 
00085 /*@access rpmfi @*/
00086 /*@access rpmte @*/     /* XXX rpmInstallSourcePackage */
00087 /*@access rpmts @*/     /* XXX ts->notify */
00088 
00089 /*@access rpmluav @*/
00090 
00091 #ifdef  DYING
00092 
00097 static rpmRC markReplacedFiles(const rpmpsm psm)
00098         /*@globals rpmGlobalMacroContext, h_errno, fileSystem, internalState @*/
00099         /*@modifies psm, rpmGlobalMacroContext, fileSystem, internalState @*/
00100 {
00101     HE_t he = memset(alloca(sizeof(*he)), 0, sizeof(*he));
00102     const rpmts ts = psm->ts;
00103     rpmte te = psm->te;
00104     rpmfi fi = psm->fi;
00105     sharedFileInfo replaced = (te ? te->replaced : NULL);
00106     sharedFileInfo sfi;
00107     rpmmi mi;
00108     Header h;
00109     uint32_t * offsets;
00110     rpmuint32_t prev;
00111     int num;
00112     int xx;
00113 
00114     if (!(rpmfiFC(fi) > 0 && replaced != NULL))
00115         return RPMRC_OK;
00116 
00117     num = prev = 0;
00118     for (sfi = replaced; sfi->otherPkg; sfi++) {
00119         if (prev && prev == sfi->otherPkg)
00120             continue;
00121         prev = sfi->otherPkg;
00122         num++;
00123     }
00124     if (num == 0)
00125         return RPMRC_OK;
00126 
00127     offsets = alloca(num * sizeof(*offsets));
00128     offsets[0] = 0;
00129     num = prev = 0;
00130     for (sfi = replaced; sfi->otherPkg; sfi++) {
00131         if (prev && prev == sfi->otherPkg)
00132             continue;
00133         prev = sfi->otherPkg;
00134         offsets[num++] = sfi->otherPkg;
00135     }
00136 
00137     mi = rpmtsInitIterator(ts, RPMDBI_PACKAGES, NULL, 0);
00138     xx = rpmmiGrow(mi, offsets, num);
00139     xx = rpmmiSetRewrite(mi, 1);
00140 
00141     sfi = replaced;
00142     while ((h = rpmmiNext(mi)) != NULL) {
00143         int modified;
00144 
00145         modified = 0;
00146 
00147         /* XXX FIXME: not correct yet, but headerGetEntry needs to die now! */
00148         he->tag = RPMTAG_FILESTATES;
00149         xx = headerGet(h, he, 0);
00150         if (!xx)
00151             continue;
00152         
00153         prev = rpmmiInstance(mi);
00154         num = 0;
00155         while (sfi->otherPkg && sfi->otherPkg == prev) {
00156 assert(sfi->otherFileNum < he->c);
00157             if (he->p.ui8p[sfi->otherFileNum] != RPMFILE_STATE_REPLACED) {
00158                 he->p.ui8p[sfi->otherFileNum] = RPMFILE_STATE_REPLACED;
00159                 if (modified == 0) {
00160                     /* Modified header will be rewritten. */
00161                     modified = 1;
00162                     xx = rpmmiSetModified(mi, modified);
00163                 }
00164                 num++;
00165             }
00166             sfi++;
00167         }
00168         he->p.ptr = _free(he->p.ptr);
00169     }
00170     mi = rpmmiFree(mi);
00171 
00172     return RPMRC_OK;
00173 }
00174 #endif
00175 
00176 static rpmRC createDir(rpmts ts, rpmfi fi, const char ** fn, const char * name)
00177         /*@globals rpmGlobalMacroContext @*/
00178         /*@modifies *fn, rpmGlobalMacroContext @*/
00179 {
00180     const char * N = rpmGenPath(rpmtsRootDir(ts), name, "");
00181     char * t = xstrdup(name+2);
00182     rpmRC rc;
00183 
00184     t[strlen(t)-1] = '\0';
00185 
00186     rc = rpmMkdirPath(N, t+1);
00187     if (rc != RPMRC_OK) {
00188         if (Access(N, W_OK))
00189             rpmlog(RPMLOG_ERR, _("cannot write to %%%s %s\n"), t, N);
00190         else if (fi)
00191             Chown(N, fi->uid, fi->gid);
00192     }
00193 
00194     if (fn)
00195         *fn = N;
00196     else
00197         N = _free(N);
00198     t = _free(t);
00199 
00200     return rc;
00201 }
00202 
00203 rpmRC rpmInstallSourcePackage(rpmts ts, void * _fd,
00204                 const char ** specFilePtr, const char ** cookie)
00205 {
00206     HE_t he = memset(alloca(sizeof(*he)), 0, sizeof(*he));
00207     FD_t fd = _fd;
00208     rpmfi fi = NULL;
00209     rpmte p = NULL;
00210     rpmpsm psm = NULL;
00211     Header h = NULL;
00212     int isSource;
00213     rpmRC rc;
00214     int i;
00215 
00216 /*@-mods@*/     /* Avoid void * _fd annotations for now. */
00217     rc = rpmReadPackageFile(ts, fd, __FUNCTION__, &h);
00218 /*@=mods@*/
00219     switch (rc) {
00220     case RPMRC_NOTTRUSTED:
00221     case RPMRC_NOKEY:
00222     case RPMRC_OK:
00223         break;
00224     default:
00225         goto exit;
00226         /*@notreached@*/ break;
00227     }
00228     if (h == NULL)
00229         goto exit;
00230 
00231     rc = RPMRC_FAIL;            /* assume failure */
00232 
00233     isSource =
00234         (headerIsEntry(h, RPMTAG_SOURCERPM) == 0 &&
00235          headerIsEntry(h, RPMTAG_ARCH) != 0);
00236 
00237     if (!isSource) {
00238         rpmlog(RPMLOG_ERR, _("source package expected, binary found\n"));
00239         goto exit;
00240     }
00241 
00242     (void) rpmtsAddInstallElement(ts, h, NULL, 0, NULL);
00243 
00244     p = rpmtsElement(ts, 0);
00245 assert(p->h == NULL);
00246     (void) rpmteSetHeader(p, h);
00247 /*@-mods@*/     /* LCL: avoid void * _fd annotation for now. */
00248 /*@-assignexpose -castexpose -temptrans @*/
00249     p->fd = fdLink(fd, __FUNCTION__);
00250 /*@=assignexpose =castexpose =temptrans @*/
00251 /*@=mods@*/
00252 
00253     fi = rpmteFI(p, RPMTAG_BASENAMES);
00254     fi->h = headerLink(h);
00255 /*@-onlytrans@*/        /* FIX: te reference */
00256     fi->te = p;
00257 /*@=onlytrans@*/
00258 
00259     /* XXX FIXME: don't do per-file mapping, force global flags. */
00260     fi->fmapflags = _free(fi->fmapflags);
00261     fi->mapflags = IOSM_MAP_PATH | IOSM_MAP_MODE | IOSM_MAP_UID | IOSM_MAP_GID;
00262 
00263     fi->uid = getuid();
00264     fi->gid = getgid();
00265 #if defined(RPM_VENDOR_OPENPKG) /* switch-from-susr-to-musr-on-srpm-install */
00266     /* If running as the OpenPKG "susr", do not unpack source RPM
00267        packages with "susr" file ownerships as the OpenPKG Set-UID
00268        wrapper switches from "musr" to "susr" on "openpkg rpm -Uvh
00269        *.src.rpm". As a result the installed files could be never
00270        removed again by "musr". It is more consistent to always unpack
00271        as "musr" if possible. */
00272     if (fi->uid == 0) {
00273         char *muid_str;
00274         char *mgid_str;
00275         uid_t muid;
00276         gid_t mgid;
00277         if ((muid_str = rpmExpand("%{l_muid}", NULL)) != NULL)
00278             if ((muid = (uid_t)strtol(muid_str, (char **)NULL, 10)) > 0)
00279                 fi->uid = muid;
00280         if ((mgid_str = rpmExpand("%{l_mgid}", NULL)) != NULL)
00281             if ((mgid = (gid_t)strtol(mgid_str, (char **)NULL, 10)) > 0)
00282                 fi->gid = mgid;
00283     }
00284 #endif
00285     for (i = 0; i < (int)fi->fc; i++)
00286         fi->actions[i] = FA_CREATE;
00287 
00288     /* Load relative (in a *.src.rpm) file paths as an argv array. */
00289     fi->astriplen = 0;
00290     fi->striplen = 0;
00291     he->tag = RPMTAG_FILEPATHS;
00292     if (!headerGet(h, he, 0) || he->p.argv == NULL || he->p.argv[0] == NULL)
00293         goto exit;
00294     fi->apath = he->p.argv;
00295 
00296     (void) headerMacrosLoad(h);
00297 
00298 #if defined(RPM_VENDOR_OPENPKG) /* switch-from-susr-to-musr-on-srpm-install */
00299     if (createDir(ts, fi, NULL, "%{_topdir}")
00300      || createDir(ts, fi, NULL, "%{_builddir}")
00301      || createDir(ts, fi, NULL, "%{_rpmdir}")
00302      || createDir(ts, fi, NULL, "%{_srcrpmdir}")
00303      || createDir(ts, fi, NULL, "%{_sourcedir}")
00304      || createDir(ts, fi, NULL, "%{_specdir}"))
00305 #else
00306     if (createDir(ts, NULL, NULL, "%{_topdir}")
00307      || createDir(ts, NULL, NULL, "%{_builddir}")
00308      || createDir(ts, NULL, NULL, "%{_rpmdir}")
00309      || createDir(ts, NULL, NULL, "%{_srcrpmdir}")
00310      || createDir(ts, NULL, NULL, "%{_sourcedir}")
00311      || createDir(ts, NULL, NULL, "%{_specdir}"))
00312 #endif
00313         goto exit;
00314 
00315     /* Retrieve build cookie. */
00316     if (cookie) {
00317         *cookie = NULL;
00318         he->tag = RPMTAG_COOKIE;
00319         if (headerGet(h, he, 0)) *cookie = he->p.str;
00320     }
00321 
00322     /* Find spec file path. */
00323     if (specFilePtr) {
00324         *specFilePtr = NULL;
00325         fi = rpmfiInit(fi, 0);
00326         while ((i = rpmfiNext(fi)) >= 0) {
00327             if (!(rpmfiFFlags(fi) & RPMFILE_SPECFILE))
00328                 continue;
00329             *specFilePtr = xstrdup(rpmfiFN(fi));
00330             break;
00331         }
00332         if (*specFilePtr == NULL) {
00333             rpmlog(RPMLOG_ERR, _("source package contains no .spec file\n"));
00334             goto exit;
00335         }
00336     }
00337 
00338     /* Unpack the SRPM contents. */
00339     psm = rpmpsmNew(ts, p, fi);
00340     psm->goal = PSM_PKGINSTALL;
00341     rc = rpmpsmStage(psm, PSM_PROCESS);
00342     (void) rpmpsmStage(psm, PSM_FINI);
00343     psm = rpmpsmFree(psm, __FUNCTION__);
00344 
00345 exit:
00346     if (rc != RPMRC_OK) {
00347         if (specFilePtr) *specFilePtr = _free(*specFilePtr);
00348         if (cookie) *cookie = _free(*cookie);
00349     }
00350 
00351     if (fi)
00352         fi->te = NULL;
00353 
00354     if (p) {
00355         (void) rpmteSetHeader(p, NULL);
00356 /*@-mods@*/     /* Avoid void * _fd annotations for now. */
00357         if (p->fd != NULL)
00358             (void) Fclose(p->fd);
00359 /*@=mods@*/
00360         p->fd = NULL;
00361     }
00362 
00363     /* XXX nuke the added package(s). */
00364     rpmtsClean(ts);
00365 
00366     (void) headerFree(h);
00367     h = NULL;
00368 
00369     return rc;
00370 }
00371 
00372 /*@observer@*/ /*@unchecked@*/
00373 static char * SCRIPT_PATH = "PATH=/sbin:/bin:/usr/sbin:/usr/bin:/usr/X11R6/bin";
00374 
00380 static /*@observer@*/ const char * tag2sln(rpmTag tag)
00381         /*@*/
00382 {
00383     switch (tag) {
00384     case RPMTAG_PRETRANS:       return "%pretrans";
00385     case RPMTAG_TRIGGERPREIN:   return "%triggerprein";
00386     case RPMTAG_PREIN:          return "%pre";
00387     case RPMTAG_POSTIN:         return "%post";
00388     case RPMTAG_TRIGGERIN:      return "%triggerin";
00389     case RPMTAG_TRIGGERUN:      return "%triggerun";
00390     case RPMTAG_PREUN:          return "%preun";
00391     case RPMTAG_POSTUN:         return "%postun";
00392     case RPMTAG_POSTTRANS:      return "%posttrans";
00393     case RPMTAG_TRIGGERPOSTUN:  return "%triggerpostun";
00394     case RPMTAG_VERIFYSCRIPT:   return "%verify";
00395     case RPMTAG_SANITYCHECK:    return "%sanitycheck";
00396     case RPMTAG_BUILDPREP:      return "%prep";
00397     case RPMTAG_BUILDBUILD:     return "%build";
00398     case RPMTAG_BUILDINSTALL:   return "%install";
00399     case RPMTAG_BUILDCHECK:     return "%check";
00400     default:    break;
00401     }
00402     return "%unknownscript";
00403 }
00404 
00410 static rpmScriptID tag2slx(rpmTag tag)
00411         /*@*/
00412 {
00413     switch (tag) {
00414     case RPMTAG_PRETRANS:       return RPMSCRIPT_PRETRANS;
00415     case RPMTAG_TRIGGERPREIN:   return RPMSCRIPT_TRIGGERPREIN;
00416     case RPMTAG_PREIN:          return RPMSCRIPT_PREIN;
00417     case RPMTAG_POSTIN:         return RPMSCRIPT_POSTIN;
00418     case RPMTAG_TRIGGERIN:      return RPMSCRIPT_TRIGGERIN;
00419     case RPMTAG_TRIGGERUN:      return RPMSCRIPT_TRIGGERUN;
00420     case RPMTAG_PREUN:          return RPMSCRIPT_PREUN;
00421     case RPMTAG_POSTUN:         return RPMSCRIPT_POSTUN;
00422     case RPMTAG_POSTTRANS:      return RPMSCRIPT_POSTTRANS;
00423     case RPMTAG_TRIGGERPOSTUN:  return RPMSCRIPT_TRIGGERPOSTUN;
00424     case RPMTAG_VERIFYSCRIPT:   return RPMSCRIPT_VERIFY;
00425     case RPMTAG_SANITYCHECK:    return RPMSCRIPT_SANITYCHECK;
00426     case RPMTAG_BUILDPREP:      return RPMSCRIPT_PREP;
00427     case RPMTAG_BUILDBUILD:     return RPMSCRIPT_BUILD;
00428     case RPMTAG_BUILDINSTALL:   return RPMSCRIPT_INSTALL;
00429     case RPMTAG_BUILDCHECK:     return RPMSCRIPT_CHECK;
00430     default:    break;
00431     }
00432     return RPMSCRIPT_MAX;
00433 }
00434 
00440 static pid_t psmWait(rpmpsm psm)
00441         /*@globals fileSystem, internalState @*/
00442         /*@modifies psm, fileSystem, internalState @*/
00443 {
00444     const rpmts ts = psm->ts;
00445     rpmtime_t msecs;
00446 
00447     (void) rpmsqWait(&psm->sq);
00448     msecs = psm->sq.op.usecs/1000;
00449     (void) rpmswAdd(rpmtsOp(ts, RPMTS_OP_SCRIPTLETS), &psm->sq.op);
00450 
00451     rpmlog(RPMLOG_DEBUG,
00452         D_("%s: waitpid(%d) rc %d status %x secs %u.%03u\n"),
00453         psm->stepName, (unsigned)psm->sq.child,
00454         (unsigned)psm->sq.reaped, psm->sq.status,
00455         (unsigned)msecs/1000, (unsigned)msecs%1000);
00456 
00457     if (psm->sstates != NULL)
00458     {   rpmuint32_t * ssp = psm->sstates + tag2slx(psm->scriptTag);
00459         *ssp &= ~0xffff;
00460         *ssp |= (psm->sq.status & 0xffff);
00461         *ssp |= RPMSCRIPT_STATE_REAPED;
00462     }
00463 
00464     return psm->sq.reaped;
00465 }
00466 
00467 #ifdef WITH_LUA
00468 
00479 static rpmRC runLuaScript(rpmpsm psm, const char * sln, HE_t Phe,
00480                    const char *script, int arg1, int arg2)
00481         /*@globals fileSystem, internalState @*/
00482         /*@modifies psm, fileSystem, internalState @*/
00483 {
00484     rpmRC rc = RPMRC_OK;
00485     int xx;
00486     rpmlua lua = NULL;  /* Global state. */
00487     rpmluav var;
00488 
00489     /* Create arg variable */
00490     rpmluaPushTable(lua, "arg");
00491     var = rpmluavNew();
00492     rpmluavSetListMode(var, 1);
00493 /*@+relaxtypes@*/
00494     if (Phe->p.argv) {
00495         int i;
00496         for (i = 0; i < (int)Phe->c && Phe->p.argv[i]; i++) {
00497             rpmluavSetValue(var, RPMLUAV_STRING, Phe->p.argv[i]);
00498             rpmluaSetVar(lua, var);
00499         }
00500     }
00501     if (arg1 >= 0) {
00502         rpmluavSetValueNum(var, arg1);
00503         rpmluaSetVar(lua, var);
00504     }
00505     if (arg2 >= 0) {
00506         rpmluavSetValueNum(var, arg2);
00507         rpmluaSetVar(lua, var);
00508     }
00509 /*@=relaxtypes@*/
00510 /*@-moduncon@*/
00511     var = rpmluavFree(var);
00512 /*@=moduncon@*/
00513     rpmluaPop(lua);
00514 
00515     {   char buf[BUFSIZ];
00516         xx = snprintf(buf, BUFSIZ, "%s(%s)", sln, psm->NVRA);
00517         xx = rpmluaRunScript(lua, script, buf);
00518         if (xx == -1) {
00519             void * ptr = rpmtsNotify(psm->ts, psm->te, RPMCALLBACK_SCRIPT_ERROR,
00520                                  psm->scriptTag, 1);
00521             ptr = ptr;  /* XXX keep gcc happy. */
00522             rc = RPMRC_FAIL;
00523         } else
00524             rc = RPMRC_OK;
00525     }
00526     rpmluaDelVar(lua, "arg");
00527 
00528     return rc;
00529 }
00530 #endif  /* WITH_LUA */
00531 
00532 #if defined(_WITH_EMBEDDED)
00533 static int enterChroot(rpmpsm psm, int * pwdFdnop, int * rootFdnop)
00534         /*@globals fileSystem, internalState @*/
00535         /*@modifies *pwdFdnop, *rootFdnop, fileSystem, internalState @*/
00536 {
00537     const rpmts ts = psm->ts;
00538     int inChroot;
00539     int xx;
00540 
00541     /* Save the current working directory. */
00542     if (pwdFdnop)
00543         (*pwdFdnop) = open(".", O_RDONLY, 0);
00544 
00545     /* Save the current root directory. */
00546     if (rootFdnop)
00547         (*rootFdnop) = open("/", O_RDONLY, 0);
00548 
00549     /* Get into the chroot. */
00550     if (!rpmtsChrootDone(ts)) {
00551         const char *rootDir = rpmtsRootDir(ts);
00552         inChroot = 0;
00553         /*@-modobserver @*/
00554         if (rootDir != NULL && strcmp(rootDir, "/") && *rootDir == '/') {
00555             xx = Chroot(rootDir);
00556         /*@=modobserver @*/
00557             xx = rpmtsSetChrootDone(ts, 1);
00558         }
00559     } else
00560        inChroot = 1;
00561 
00562     /* All embedded scriptlets run with CWD == "/". */
00563     xx = Chdir("/");
00564 
00565     return inChroot;
00566 }
00567 
00568 static int exitChroot(rpmpsm psm, int inChroot, int pwdFdno, int rootFdno)
00569         /*@globals fileSystem, internalState @*/
00570         /*@modifies psm, fileSystem, internalState @*/
00571 {
00572     const rpmts ts = psm->ts;
00573     const char *rootDir = rpmtsRootDir(ts);
00574     int xx;
00575 
00576     if (rpmtsChrootDone(ts) && !inChroot) {
00577         xx = fchdir(rootFdno);
00578 /*@-modobserver@*/
00579         if (rootDir != NULL && strcmp(rootDir, "/") && *rootDir == '/') {
00580             xx = Chroot(".");
00581 /*@=modobserver@*/
00582             xx = rpmtsSetChrootDone(ts, 0);
00583         }
00584         xx = fchdir(pwdFdno);
00585     } else
00586         xx = fchdir(pwdFdno);
00587 
00588     xx = close(rootFdno);
00589     xx = close(pwdFdno);
00590 
00591     return 0;
00592 }
00593 
00605 static rpmRC runEmbeddedScript(rpmpsm psm, const char * sln, HE_t Phe,
00606                    const char *script, int arg1, int arg2)
00607         /*@globals fileSystem, internalState @*/
00608         /*@modifies psm, fileSystem, internalState @*/
00609 {
00610     char * av[] = { NULL, NULL, NULL, NULL };
00611     int pwdFdno = -1;
00612     int rootFdno = -1;
00613     rpmRC rc = RPMRC_OK;
00614     int xx = 0;
00615     rpmuint32_t * ssp = NULL;
00616     int inChroot = enterChroot(psm, &pwdFdno, &rootFdno);
00617 
00618     if (psm->sstates != NULL)
00619         ssp = psm->sstates + tag2slx(psm->scriptTag);
00620     if (ssp != NULL)
00621         *ssp |= (RPMSCRIPT_STATE_EMBEDDED|RPMSCRIPT_STATE_EXEC);
00622 
00623     av[0] = (char *) Phe->p.argv[0];
00624     if (arg1 >= 0)
00625         (void) sprintf((av[1] = alloca(32)), "%d", arg1);
00626     if (arg2 >= 0)
00627         (void) sprintf((av[2] = alloca(32)), "%d", arg2);
00628 
00629 #if defined(WITH_LUA)
00630     if (!strcmp(Phe->p.argv[0], "<lua>")) {
00631         rc = runLuaScript(psm, sln, Phe, script, arg1, arg2);
00632     } else
00633 #endif
00634 #if defined(WITH_AUGEAS)
00635     if (!strcmp(Phe->p.argv[0], "<augeas>")) {
00636         /* XXX change rpmaugNew() to common embedded interpreter API */
00637         rpmaug aug = NULL;
00638         rc = rpmaugRun(aug, script, NULL) == RPMRC_OK
00639             ? RPMRC_OK : RPMRC_FAIL;
00640         aug = rpmaugFree(aug);
00641     } else
00642 #endif
00643 #if defined(WITH_FICL)
00644     if (!strcmp(Phe->p.argv[0], "<ficl>")) {
00645         rpmficl ficl = rpmficlNew((char **)av, 0);
00646         rc = rpmficlRun(ficl, script, NULL) == RPMRC_OK
00647             ? RPMRC_OK : RPMRC_FAIL;
00648         ficl = rpmficlFree(ficl);
00649     } else
00650 #endif
00651 #if defined(WITH_GPSEE)
00652     if (!strcmp(Phe->p.argv[0], "<js>")) {
00653         rpmjs js = rpmjsNew((char **)av, 0);
00654         rc = rpmjsRun(js, script, NULL) == RPMRC_OK
00655             ? RPMRC_OK : RPMRC_FAIL;
00656         js = rpmjsFree(js);
00657     } else
00658 #endif
00659 #if defined(WITH_PERLEMBED)
00660     if (!strcmp(Phe->p.argv[0], "<perl>")) {
00661         rpmperl perl = rpmperlNew((char **)av, 0);
00662         rc = rpmperlRun(perl, script, NULL) == RPMRC_OK
00663             ? RPMRC_OK : RPMRC_FAIL;
00664         perl = rpmperlFree(perl);
00665     } else
00666 #endif
00667 #if defined(WITH_PYTHONEMBED)
00668     if (!strcmp(Phe->p.argv[0], "<python>")) {
00669         rpmpython python = rpmpythonNew((char **)av, 0);
00670         rc = rpmpythonRun(python, script, NULL) == RPMRC_OK
00671             ? RPMRC_OK : RPMRC_FAIL;
00672         python = rpmpythonFree(python);
00673     } else
00674 #endif
00675 #if defined(WITH_RUBY)
00676     if (!strcmp(Phe->p.argv[0], "<ruby>")) {
00677         rpmruby ruby = rpmrubyNew((char **)av, 0);
00678         rc = rpmrubyRun(ruby, script, NULL) == RPMRC_OK
00679             ? RPMRC_OK : RPMRC_FAIL;
00680         ruby = rpmrubyFree(ruby);
00681     } else
00682 #endif
00683 #if defined(WITH_SEMANAGE)
00684     if (!strcmp(Phe->p.argv[0], "<spook>")) {
00685         /* XXX change rpmsmNew() to common embedded interpreter API */
00686         rpmsm sm = NULL;
00687         /* XXX HACK: use an argv for now. */
00688         const char * av[2];
00689         av[0] = script;
00690         av[1] = NULL;
00691         rc = rpmsmRun(sm, (char **)av, NULL) == RPMRC_OK
00692             ? RPMRC_OK : RPMRC_FAIL;
00693         sm = rpmsmFree(sm);
00694     } else
00695 #endif
00696 #if defined(WITH_SQLITE)
00697     if (!strcmp(Phe->p.argv[0], "<sql>")) {
00698         int Pac = Phe->c;
00699         const char ** Pav = xmalloc((Pac + 1) * sizeof(*Pav));
00700         const char * result = NULL;
00701         rpmsql sql;
00702         int i;
00703 
00704         /* XXX ignore $1/$2, copy the tag array instead. */
00705         /* XXX no NULL sentinel in tag arrays. */
00706         for (i = 0; i < Pac; i++)
00707             Pav[i] = rpmExpand(Phe->p.argv[i], NULL);
00708         Pav[Pac] = NULL;
00709 
00710         sql = rpmsqlNew((char **)Pav, 0);
00711         rc = rpmsqlRun(sql, script, &result) == RPMRC_OK
00712             ? RPMRC_OK : RPMRC_FAIL;
00713         sql = rpmsqlFree(sql);
00714         Pav = argvFree(Pav);
00715     } else
00716 #endif
00717 #if defined(WITH_SQUIRREL)
00718     if (!strcmp(Phe->p.argv[0], "<squirrel>")) {
00719         rpmsquirrel squirrel = rpmsquirrelNew((char **)av, 0);
00720         rc = rpmsquirrelRun(squirrel, script, NULL) == RPMRC_OK
00721             ? RPMRC_OK : RPMRC_FAIL;
00722         squirrel = rpmsquirrelFree(squirrel);
00723     } else
00724 #endif
00725 #if defined(WITH_TCL)
00726     if (!strcmp(Phe->p.argv[0], "<tcl>")) {
00727         rpmtcl tcl = rpmtclNew((char **)av, 0);
00728         rc = rpmtclRun(tcl, script, NULL) == RPMRC_OK
00729             ? RPMRC_OK : RPMRC_FAIL;
00730         tcl = rpmtclFree(tcl);
00731     } else
00732 #endif
00733         rc = RPMRC_NOTFOUND;
00734 
00735     if (ssp != NULL) {
00736         *ssp &= ~0xffff;
00737         *ssp |= (xx & 0xffff);
00738         *ssp |= RPMSCRIPT_STATE_REAPED;
00739     }
00740 
00741     xx = exitChroot(psm, inChroot, pwdFdno, rootFdno);
00742 
00743     return rc;
00744 }
00745 #endif
00746 
00749 /*@unchecked@*/
00750 static int ldconfig_done = 0;
00751 
00752 /*@unchecked@*/ /*@observer@*/ /*@null@*/
00753 static const char * ldconfig_path = "/sbin/ldconfig";
00754 
00771 static rpmRC runScript(rpmpsm psm, Header h, const char * sln, HE_t Phe,
00772                 const char * script, int arg1, int arg2)
00773         /*@globals ldconfig_done, rpmGlobalMacroContext, h_errno,
00774                 fileSystem, internalState@*/
00775         /*@modifies psm, ldconfig_done, rpmGlobalMacroContext,
00776                 fileSystem, internalState @*/
00777 {
00778     const rpmts ts = psm->ts;
00779     const char * NVRA = psm->NVRA;
00780     HE_t IPhe = psm->IPhe;
00781     const char ** argv = NULL;
00782     int argc = 0;
00783     const char ** IP = NULL;
00784     int nIP;
00785     size_t maxPrefixLength;
00786     size_t len;
00787     char * prefixBuf = NULL;
00788     const char * fn = NULL;
00789     FD_t scriptFd = NULL;
00790     FD_t out = NULL;            /* exit: expects this to be initialized. */
00791     rpmRC rc = RPMRC_FAIL;      /* assume failure */
00792     const char * body = NULL;
00793     rpmop op = memset(alloca(sizeof(*op)), 0, sizeof(*op));
00794     int ix = tag2slx(psm->scriptTag);
00795     rpmuint32_t * ssp = NULL;
00796     pid_t pid;
00797     int xx;
00798     int i;
00799 
00800     if (psm->sstates != NULL && ix >= 0 && ix < RPMSCRIPT_MAX)
00801         ssp = psm->sstates + ix;
00802     if (ssp != NULL)
00803         *ssp = RPMSCRIPT_STATE_UNKNOWN;
00804 
00805     if (Phe->p.argv == NULL && script == NULL)
00806         return RPMRC_OK;
00807 
00808     /* Macro expand all scriptlets. */
00809     body = rpmExpand(script, NULL);
00810 
00811     /* XXX Load NVRA lazily. This should be done elsewhere ... */
00812     if (NVRA == NULL) {
00813         HE_t he = memset(alloca(sizeof(*he)), 0, sizeof(*he));
00814         he->tag = RPMTAG_NVRA;
00815         xx = headerGet(h, he, 0);
00816 assert(he->p.str != NULL);
00817         psm->NVRA = NVRA = he->p.str;
00818     }
00819 
00820     if (op != NULL)
00821         (void) rpmswEnter(op, 0);
00822     
00823     if (Phe->p.argv && Phe->p.argv[0])
00824     if (!strcmp(Phe->p.argv[0], "<lua>")
00825      || !strcmp(Phe->p.argv[0], "<augeas>")
00826      || !strcmp(Phe->p.argv[0], "<ficl>")
00827      || !strcmp(Phe->p.argv[0], "<js>")
00828      || !strcmp(Phe->p.argv[0], "<perl>")
00829      || !strcmp(Phe->p.argv[0], "<python>")
00830      || !strcmp(Phe->p.argv[0], "<ruby>")
00831      || !strcmp(Phe->p.argv[0], "<sql>")
00832      || !strcmp(Phe->p.argv[0], "<squirrel>")
00833      || !strcmp(Phe->p.argv[0], "<tcl>"))
00834     {
00835 #if defined(_WITH_EMBEDDED)
00836         rpmlog(RPMLOG_DEBUG,
00837                 D_("%s: %s(%s) running %s scriptlet.\n"),
00838                 psm->stepName, tag2sln(psm->scriptTag), NVRA, Phe->p.argv[0]);
00839         rc = runEmbeddedScript(psm, sln, Phe, body, arg1, arg2);
00840 #endif
00841         goto exit;
00842     }
00843 
00844     psm->sq.reaper = 1;
00845 
00846     /*
00847      * If a successor node, and ldconfig was just run, don't bother.
00848      */
00849     if (ldconfig_path && Phe->p.argv != NULL && F_ISSET(psm, UNORDERED)) {
00850         if (ldconfig_done && !strcmp(Phe->p.argv[0], ldconfig_path)) {
00851             rpmlog(RPMLOG_DEBUG,
00852                 D_("%s: %s(%s) skipping redundant \"%s\".\n"),
00853                 psm->stepName, tag2sln(psm->scriptTag), NVRA,
00854                 Phe->p.argv[0]);
00855             rc = RPMRC_OK;
00856             goto exit;
00857         }
00858     }
00859 
00860     rpmlog(RPMLOG_DEBUG,
00861                 D_("%s: %s(%s) %ssynchronous scriptlet start\n"),
00862                 psm->stepName, tag2sln(psm->scriptTag), NVRA,
00863                 (F_ISSET(psm, UNORDERED) ? "a" : ""));
00864 
00865     if (Phe->p.argv == NULL) {
00866         argv = alloca(5 * sizeof(*argv));
00867         argv[0] = "/bin/sh";
00868         argc = 1;
00869         ldconfig_done = 0;
00870     } else {
00871         argv = alloca((Phe->c + 4) * sizeof(*argv));
00872         memcpy(argv, Phe->p.argv, Phe->c * sizeof(*argv));
00873         argc = Phe->c;
00874         ldconfig_done = (ldconfig_path && !strcmp(argv[0], ldconfig_path)
00875                 ? 1 : 0);
00876     }
00877 
00878     /* XXX Load INSTPREFIXES lazily. This should be done elsewhere ... */
00879     if (IPhe->tag == 0) {
00880         IPhe->tag = RPMTAG_INSTPREFIXES;
00881         xx = headerGet(h, IPhe, 0);
00882         if (!xx) {
00883             IPhe->p.ptr = _free(IPhe->p.ptr);
00884             IPhe->tag = RPMTAG_INSTALLPREFIX;
00885             xx = headerGet(h, IPhe, 0);
00886             if (xx) {
00887                 const char ** av =
00888                         xmalloc(sizeof(*av) + strlen(IPhe->p.argv[0]) + 1);
00889                 char * t = (char *) &av[1];
00890 
00891                 av[0] = t;
00892                 t = stpcpy(t, IPhe->p.argv[0]);
00893                 *t = '\0';
00894                 IPhe->p.ptr = _free(IPhe->p.ptr);
00895                 IPhe->t = RPM_STRING_ARRAY_TYPE;
00896                 IPhe->p.argv = av;
00897                 IPhe->c = 1;
00898             } else {
00899                 IPhe->p.argv = NULL;
00900                 IPhe->c = 0;
00901             }
00902         }
00903     }
00904     IP = IPhe->p.argv;
00905     nIP = IPhe->c;
00906 
00907     maxPrefixLength = 0;
00908     if (IP != NULL)
00909     for (i = 0; i < nIP; i++) {
00910         len = strlen(IP[i]);
00911         if (len > maxPrefixLength) maxPrefixLength = len;
00912     }
00913     prefixBuf = alloca(maxPrefixLength + 50);
00914 
00915     if (script) {
00916         const char * rootDir = rpmtsRootDir(ts);
00917         FD_t fd;
00918         size_t nw;
00919 
00920         if (rpmTempFile((!rpmtsChrootDone(ts) ? rootDir : "/"), &fn, &fd))
00921             goto exit;
00922 
00923         if (rpmIsDebug() &&
00924             (!strcmp(argv[0], "/bin/sh") || !strcmp(argv[0], "/bin/bash")))
00925         {
00926             static const char set_x[] = "set -x\n";
00927             nw = Fwrite(set_x, sizeof(set_x[0]), sizeof(set_x)-1, fd);
00928         }
00929 
00930         if (ldconfig_path && strstr(body, ldconfig_path) != NULL)
00931             ldconfig_done = 1;
00932 
00933         nw = Fwrite(body, sizeof(body[0]), strlen(body), fd);
00934         xx = Fclose(fd);
00935 
00936         {   const char * sn = fn;
00937             if (!rpmtsChrootDone(ts) && rootDir != NULL &&
00938                 !(rootDir[0] == '/' && rootDir[1] == '\0'))
00939             {
00940                 sn += strlen(rootDir)-1;
00941             }
00942             argv[argc++] = sn;
00943         }
00944 
00945         if (arg1 >= 0) {
00946             char *av = alloca(20);
00947             sprintf(av, "%d", arg1);
00948             argv[argc++] = av;
00949         }
00950         if (arg2 >= 0) {
00951             char *av = alloca(20);
00952             sprintf(av, "%d", arg2);
00953             argv[argc++] = av;
00954         }
00955     }
00956 
00957     argv[argc] = NULL;
00958 
00959     /* Log the scriptlet to be exec'd. */
00960     switch (psm->scriptTag) {
00961     default:
00962         break;
00963     case RPMTAG_PREIN:
00964         (void) rpmlioPrein(rpmtsGetRdb(ts), argv, body);
00965         break;
00966     case RPMTAG_POSTIN:
00967         (void) rpmlioPostin(rpmtsGetRdb(ts), argv, body);
00968         break;
00969     case RPMTAG_PREUN:
00970         (void) rpmlioPreun(rpmtsGetRdb(ts), argv, body);
00971         break;
00972     case RPMTAG_POSTUN:
00973         (void) rpmlioPostun(rpmtsGetRdb(ts), argv, body);
00974         break;
00975     }
00976 
00977     scriptFd = rpmtsScriptFd(ts);
00978     if (scriptFd != NULL) {
00979         if (rpmIsVerbose()) {
00980             out = fdDup(Fileno(scriptFd));
00981         } else {
00982             out = Fopen("/dev/null", "w.fdio");
00983             if (Ferror(out)) {
00984                 out = fdDup(Fileno(scriptFd));
00985             }
00986         }
00987     } else {
00988         out = fdDup(STDOUT_FILENO);
00989     }
00990     if (out == NULL)    /* XXX can't happen */
00991         goto exit;
00992 
00993     pid = rpmsqFork(&psm->sq);
00994     if (psm->sq.child == 0) {
00995         int pipes[2];
00996         int flag;
00997         int fdno;
00998 
00999         pipes[0] = pipes[1] = 0;
01000         /* Make stdin inaccessible */
01001         xx = pipe(pipes);
01002         xx = close(pipes[1]);
01003         xx = dup2(pipes[0], STDIN_FILENO);
01004         xx = close(pipes[0]);
01005 
01006         /* XXX Force FD_CLOEXEC on 1st 100 inherited fdno's. */
01007         for (fdno = 3; fdno < 100; fdno++) {
01008             flag = fcntl(fdno, F_GETFD);
01009             if (flag == -1 || (flag & FD_CLOEXEC))
01010                 continue;
01011             rpmlog(RPMLOG_DEBUG,
01012                         D_("%s: %s(%s)\tfdno(%d) missing FD_CLOEXEC\n"),
01013                         psm->stepName, sln, NVRA,
01014                         fdno);
01015             xx = fcntl(fdno, F_SETFD, FD_CLOEXEC);
01016             /* XXX W2DO? debug msg for inheirited fdno w/o FD_CLOEXEC */
01017         }
01018 
01019         if (scriptFd != NULL) {
01020             int sfdno = Fileno(scriptFd);
01021             int ofdno = Fileno(out);
01022             if (sfdno != STDERR_FILENO)
01023                 xx = dup2(sfdno, STDERR_FILENO);
01024             if (ofdno != STDOUT_FILENO)
01025                 xx = dup2(ofdno, STDOUT_FILENO);
01026             /* make sure we don't close stdin/stderr/stdout by mistake! */
01027             if (ofdno > STDERR_FILENO && ofdno != sfdno)
01028                 xx = Fclose (out);
01029             if (sfdno > STDERR_FILENO && ofdno != sfdno)
01030                 xx = Fclose (scriptFd);
01031         }
01032 
01033         {   const char *ipath = rpmExpand("PATH=%{_install_script_path}", NULL);
01034             const char *path = SCRIPT_PATH;
01035 
01036             if (ipath && ipath[5] != '%')
01037                 path = ipath;
01038 
01039             xx = doputenv(path);
01040             /*@-modobserver@*/
01041             ipath = _free(ipath);
01042             /*@=modobserver@*/
01043         }
01044 
01045         if (IP != NULL)
01046         for (i = 0; i < nIP; i++) {
01047             sprintf(prefixBuf, "RPM_INSTALL_PREFIX%d=%s", i, IP[i]);
01048             xx = doputenv(prefixBuf);
01049 
01050             /* backwards compatibility */
01051             if (i == 0) {
01052                 sprintf(prefixBuf, "RPM_INSTALL_PREFIX=%s", IP[i]);
01053                 xx = doputenv(prefixBuf);
01054             }
01055         }
01056 
01057         {   const char * rootDir = rpmtsRootDir(ts);
01058             if (!rpmtsChrootDone(ts) && rootDir != NULL &&
01059                 !(rootDir[0] == '/' && rootDir[1] == '\0'))
01060             {
01061                 /*@-modobserver@*/
01062                 xx = Chroot(rootDir);
01063                 /*@=modobserver@*/
01064             }
01065             xx = Chdir("/");
01066             rpmlog(RPMLOG_DEBUG, D_("%s: %s(%s)\texecv(%s) pid %d\n"),
01067                         psm->stepName, sln, NVRA,
01068                         argv[0], (unsigned)getpid());
01069 
01070             /* XXX Don't mtrace into children. */
01071             unsetenv("MALLOC_CHECK_");
01072 
01073             if (ssp != NULL)
01074                 *ssp |= RPMSCRIPT_STATE_EXEC;
01075 
01076             /* Permit libselinux to do the scriptlet exec. */
01077             if (rpmtsSELinuxEnabled(ts) == 1) { 
01078                 if (ssp != NULL)
01079                     *ssp |= RPMSCRIPT_STATE_SELINUX;
01080                 xx = rpmsxExec(NULL, 0, argv);
01081             } else {
01082 /*@-nullstate@*/
01083                 xx = execv(argv[0], (char *const *)argv);
01084 /*@=nullstate@*/
01085             }
01086         }
01087 
01088         if (ssp != NULL)
01089             *ssp &= ~RPMSCRIPT_STATE_EXEC;
01090 
01091         _exit(-1);
01092         /*@notreached@*/
01093     }
01094 
01095     if (psm->sq.child == (pid_t)-1) {
01096         rpmlog(RPMLOG_ERR, _("Couldn't fork %s: %s\n"), sln, strerror(errno));
01097         goto exit;
01098     }
01099 
01100     (void) psmWait(psm);
01101 
01102   /* XXX filter order dependent multilib "other" arch helper error. */
01103   if (!(psm->sq.reaped >= 0 && !strcmp(argv[0], "/usr/sbin/glibc_post_upgrade") && WEXITSTATUS(psm->sq.status) == 110)) {
01104     void *ptr = NULL;
01105     if (psm->sq.reaped < 0) {
01106         rpmlog(RPMLOG_ERR,
01107                 _("%s(%s) scriptlet failed, waitpid(%d) rc %d: %s\n"),
01108                  sln, NVRA, (int)psm->sq.child, (int)psm->sq.reaped,
01109                 strerror(errno));
01110         goto exit;
01111     } else
01112     if (!WIFEXITED(psm->sq.status) || WEXITSTATUS(psm->sq.status)) {
01113         if (WIFSIGNALED(psm->sq.status)) {
01114             ptr = rpmtsNotify(ts, psm->te, RPMCALLBACK_SCRIPT_ERROR,
01115                                  psm->scriptTag, WTERMSIG(psm->sq.status));
01116             rpmlog(RPMLOG_ERR,
01117                  _("%s(%s) scriptlet failed, signal %d\n"),
01118                  sln, NVRA, WTERMSIG(psm->sq.status));
01119         } else {
01120             ptr = rpmtsNotify(ts, psm->te, RPMCALLBACK_SCRIPT_ERROR,
01121                                  psm->scriptTag, WEXITSTATUS(psm->sq.status));
01122             rpmlog(RPMLOG_ERR,
01123                 _("%s(%s) scriptlet failed, exit status %d\n"),
01124                 sln, NVRA, WEXITSTATUS(psm->sq.status));
01125         }
01126         goto exit;
01127     }
01128   }
01129 
01130     rc = RPMRC_OK;
01131 
01132 exit:
01133     if (op != NULL) {
01134         static unsigned int scale = 1000;
01135         (void) rpmswExit(op, 0);
01136         if (ix >= 0 && ix < RPMSCRIPT_MAX)
01137             psm->smetrics[ix] += op->usecs / scale;
01138     }
01139 
01140     if (out)
01141         xx = Fclose(out);       /* XXX dup'd STDOUT_FILENO */
01142 
01143     if (script) {
01144         if (!rpmIsDebug() && fn != NULL)
01145             xx = Unlink(fn);
01146         fn = _free(fn);
01147     }
01148 
01149     body = _free(body);
01150 
01151     return rc;
01152 }
01153 
01159 static rpmRC runInstScript(rpmpsm psm)
01160         /*@globals rpmGlobalMacroContext, h_errno, fileSystem, internalState @*/
01161         /*@modifies psm, rpmGlobalMacroContext, fileSystem, internalState @*/
01162 {
01163     HE_t Phe = memset(alloca(sizeof(*Phe)), 0, sizeof(*Phe));
01164     HE_t She = memset(alloca(sizeof(*She)), 0, sizeof(*She));
01165     rpmfi fi = psm->fi;
01166     const char * argv0 = NULL;
01167     rpmRC rc = RPMRC_OK;
01168 
01169 assert(fi->h != NULL);
01170     She->tag = psm->scriptTag;
01171     if (!headerGet(fi->h, She, 0))
01172         goto exit;
01173 
01174     Phe->tag = psm->progTag;
01175     if (!headerGet(fi->h, Phe, 0))
01176         goto exit;
01177 
01178     /* Coerce strings into header argv return. */
01179     if (Phe->t == RPM_STRING_TYPE) {
01180         const char * s = Phe->p.str;
01181         char * t;
01182         Phe->p.argv = xmalloc(sizeof(Phe->p.argv[0]) + strlen(s) + 1);
01183         Phe->p.argv[0] = t = (char *) &Phe->p.argv[1];
01184         t = stpcpy(t, s);
01185         *t = '\0';
01186         s = _free(s);
01187     }
01188 
01189     /* Expand "%script -p %%{interpreter}" macros. */
01190     if (Phe->p.argv[0][0] == '%')
01191         Phe->p.argv[0] = argv0 = rpmExpand(Phe->p.argv[0], NULL);
01192 
01193     rc = runScript(psm, fi->h, tag2sln(psm->scriptTag), Phe,
01194                 She->p.str, psm->scriptArg, -1);
01195 
01196 exit:
01197     argv0 = _free(argv0);
01198     Phe->p.ptr = _free(Phe->p.ptr);
01199     She->p.ptr = _free(She->p.ptr);
01200     return rc;
01201 }
01202 
01203 /*@unchecked@*/
01204 static rpmTag _trigger_tag;
01205 
01214 static rpmRC handleOneTrigger(const rpmpsm psm,
01215                         Header sourceH, Header triggeredH, int arg2)
01216         /*@globals rpmGlobalMacroContext, h_errno, fileSystem, internalState@*/
01217         /*@modifies psm, sourceH, triggeredH,
01218                 rpmGlobalMacroContext, fileSystem, internalState @*/
01219 {
01220     static int scareMem = 0;
01221     HE_t he = memset(alloca(sizeof(*he)), 0, sizeof(*he));
01222     HE_t Ihe = memset(alloca(sizeof(*Ihe)), 0, sizeof(*Ihe));
01223     HE_t She = memset(alloca(sizeof(*She)), 0, sizeof(*She));
01224     HE_t Phe = memset(alloca(sizeof(*Phe)), 0, sizeof(*Phe));
01225     miRE mire = NULL;
01226     const rpmts ts = psm->ts;
01227     rpmds Tds = NULL;
01228     rpmds Fds = NULL;
01229     rpmds Dds = NULL;
01230     rpmds Pds = NULL;
01231     const char * sourceName;
01232     const char * triggerName;
01233     rpmRC rc = RPMRC_OK;
01234     int arg1;
01235     int xx;
01236     int i;
01237 
01238     he->tag = RPMTAG_NAME;
01239     xx = headerGet(sourceH, he, 0);
01240     sourceName = he->p.str;
01241 
01242     he->tag = RPMTAG_NAME;
01243     xx = headerGet(triggeredH, he, 0);
01244     triggerName = he->p.str;
01245 
01246     arg1 = rpmdbCountPackages(rpmtsGetRdb(ts), triggerName);
01247     if (arg1 < 0) {
01248         /* XXX W2DO? fails as "execution of script failed" */
01249         rc = RPMRC_FAIL;
01250         goto exit;
01251     }
01252     arg1 += psm->countCorrection;
01253 
01254     Tds = rpmdsNew(triggeredH, RPMTAG_TRIGGERNAME, scareMem);
01255     if (Tds == NULL)
01256         goto exit;
01257     xx = rpmdsSetNoPromote(Tds, 1);
01258 
01259     Ihe->tag = RPMTAG_TRIGGERINDEX;
01260     if (!headerGet(triggeredH, Ihe, 0))
01261         goto exit;
01262 
01263     She->tag = RPMTAG_TRIGGERSCRIPTS;
01264     if (!headerGet(triggeredH, She, 0))
01265         goto exit;
01266 
01267     Phe->tag = RPMTAG_TRIGGERSCRIPTPROG;
01268     if (!headerGet(triggeredH, Phe, 0))
01269         goto exit;
01270 
01271     if ((Tds = rpmdsInit(Tds)) != NULL)
01272     while ((i = rpmdsNext(Tds)) >= 0) {
01273         rpmuint32_t Flags = rpmdsFlags(Tds);
01274         char * depName;
01275         int bingo;
01276 
01277         /* Skip triggers that are not in this context. */
01278         if (!(Flags & psm->sense))
01279             continue;
01280 
01281         bingo = 0;              /* no trigger to fire. */
01282         depName = (char *) rpmdsN(Tds);
01283         if (depName[0] == '/') {
01284             size_t nb = strlen(depName);
01285             if (Glob_pattern_p(depName, 0)) {
01286                 rpmds ds = NULL;
01287                 if (depName[nb-1] == '/') {
01288                     /* XXX Dirnames w trailing "/" needed. */
01289                     if (Dds == NULL)
01290                         Dds = rpmdsNew(sourceH, RPMTAG_DIRNAMES, 0x2);
01291                     ds = rpmdsLink(Dds, "Triggers");
01292                 } else {
01293                     if (Fds == NULL)
01294                         Fds = rpmdsNew(sourceH, RPMTAG_BASENAMES, 0);
01295                     ds = rpmdsLink(Fds, "Triggers");
01296                 }
01297                 if (mire == NULL)
01298                     mire = mireNew(RPMMIRE_GLOB, 0);
01299 
01300                 xx = mireRegcomp(mire, depName);
01301                 if ((ds = rpmdsInit(ds)) != NULL)
01302                 while (rpmdsNext(ds) >= 0) {
01303                     const char * N = rpmdsN(ds);
01304                     xx = mireRegexec(mire, N, 0);
01305                     if (xx < 0)
01306                         /*@innercontinue@*/ continue;
01307                     bingo = 1;
01308                     /*@innerbreak@*/ break;
01309                 }
01310                 (void)rpmdsFree(ds);
01311                 ds = NULL;
01312                 xx = mireClean(mire);
01313             }
01314 
01315             /* If not matched, and directory trigger, try dir names. */
01316             if (!bingo && depName[nb-1] == '/') {
01317                 /* XXX Dirnames w trailing "/" needed. */
01318                 if (Dds == NULL)
01319                     Dds = rpmdsNew(sourceH, RPMTAG_DIRNAMES, 0x2);
01320                 bingo = rpmdsMatch(Tds, Dds);
01321             }
01322 
01323             /* If not matched, try file paths. */
01324             if (!bingo) {
01325                 if (Fds == NULL)
01326                     Fds = rpmdsNew(sourceH, RPMTAG_BASENAMES, 0);
01327                 bingo = rpmdsMatch(Tds, Fds);
01328             }
01329         }
01330 
01331         /* If trigger not fired yet, try provided dependency match. */
01332         if (!bingo) {
01333             if (Pds == NULL)
01334                 Pds = rpmdsNew(sourceH, RPMTAG_PROVIDENAME, 0);
01335             bingo = rpmdsMatch(Tds, Pds);
01336             bingo = rpmdsNegateRC(Tds, bingo);
01337         }
01338         if (!bingo)
01339             continue;
01340 
01341         /* Coerce strings into header argv return. */
01342         /* XXX FIXME: permit trigger scripts with arguments. */
01343         {   int index = Ihe->p.ui32p[i];
01344             const char * s = Phe->p.argv[index];
01345             char * t;
01346             
01347             he->tag = Phe->tag;
01348             he->t = RPM_STRING_ARRAY_TYPE;
01349             he->c = 1;
01350             he->p.argv = xmalloc(sizeof(Phe->p.argv[0]) + strlen(s) + 1);
01351             he->p.argv[0] = t = (char *) &he->p.argv[1];
01352             t = stpcpy(t, s);
01353             *t = '\0';
01354 
01355             rc |= runScript(psm, triggeredH, "%trigger", he,
01356                         She->p.argv[index], arg1, arg2);
01357 
01358             he->p.ptr = _free(he->p.ptr);
01359         }
01360     }
01361 
01362     mire = mireFree(mire);
01363     (void)rpmdsFree(Pds);
01364     Pds = NULL;
01365     (void)rpmdsFree(Dds);
01366     Dds = NULL;
01367     (void)rpmdsFree(Fds);
01368     Fds = NULL;
01369     (void)rpmdsFree(Tds);
01370     Tds = NULL;
01371 
01372 exit:
01373     Ihe->p.ptr = _free(Ihe->p.ptr);
01374     She->p.ptr = _free(She->p.ptr);
01375     Phe->p.ptr = _free(Phe->p.ptr);
01376     triggerName = _free(triggerName);
01377     sourceName = _free(sourceName);
01378 
01379     return rc;
01380 }
01381 
01382 /* Retrieve trigger patterns from rpmdb. */
01383 static int rpmdbTriggerGlobs(rpmpsm psm)
01384         /*@globals rpmGlobalMacroContext @*/
01385         /*@modifies psm, rpmGlobalMacroContext @*/
01386 {
01387     const rpmts ts = psm->ts;
01388     ARGV_t keys = NULL;
01389     int xx = rpmdbMireApply(rpmtsGetRdb(ts), RPMTAG_TRIGGERNAME,
01390                 RPMMIRE_STRCMP, NULL, &keys);
01391     int nkeys = argvCount(keys);
01392     int i;
01393     
01394     if (keys)
01395     for (i = 0; i < nkeys; i++) {
01396         char * t = (char *) keys[i];
01397         if (!Glob_pattern_p(t, 0))
01398             continue;
01399         xx = mireAppend(RPMMIRE_GLOB, 0, t, NULL,
01400                 (void *)&psm->Tmires, &psm->nTmires);
01401         xx = argvAdd(&psm->Tpats, t);
01402     }
01403     keys = argvFree(keys);
01404     return 0;
01405 }
01406 
01414 static rpmRC runTriggersLoop(rpmpsm psm, rpmTag tagno, int arg2)
01415         /*@globals rpmGlobalMacroContext, h_errno,
01416                 fileSystem, internalState @*/
01417         /*@modifies psm, rpmGlobalMacroContext,
01418                 fileSystem, internalState @*/
01419 {
01420     static int scareMem = 0;
01421     const rpmts ts = psm->ts;
01422     rpmfi fi = psm->fi;
01423     rpmds ds = rpmdsNew(fi->h, tagno, scareMem);
01424     char * depName = NULL;
01425     ARGI_t instances = NULL;
01426     rpmmi mi;
01427     Header triggeredH;
01428     rpmRC rc = RPMRC_OK;
01429     int i;
01430     int xx;
01431 
01432     /* Fire elements against rpmdb trigger strings. */
01433     if ((ds = rpmdsInit(ds)) != NULL)
01434     while ((i = rpmdsNext(ds)) >= 0) {
01435         const char * Name = rpmdsN(ds);
01436         size_t nName = strlen(Name);
01437         unsigned prev, instance;
01438         unsigned nvals;
01439         ARGint_t vals;
01440 
01441         depName = _free(depName);
01442         depName = xmalloc(nName + 1 + 1);
01443         (void) stpcpy(depName, Name);
01444         /* XXX re-add the pesky trailing '/' to dirnames. */
01445         depName[nName] = (tagno == RPMTAG_DIRNAMES ? '/' : '\0');
01446         depName[nName+1] = '\0';
01447 
01448         if (depName[0] == '/' && psm->Tmires != NULL) {
01449             miRE mire;
01450             int j;
01451 
01452             /* XXX mireApply doesn't tell which pattern matched. */
01453             for (j = 0, mire = psm->Tmires; j < psm->nTmires; j++, mire++) {
01454                 const char * pattern = psm->Tpats[j];
01455                 if (depName[nName-1] != '/') {
01456                     size_t npattern = strlen(pattern);
01457                     depName[nName] = (pattern[npattern-1] == '/') ? '/' : '\0';
01458                 }
01459                 if (mireRegexec(mire, depName, 0) < 0)
01460                     /*@innercontinue@*/ continue;
01461 
01462                 /* Reset the primary retrieval key to the pattern. */
01463                 depName = _free(depName);
01464                 depName = xstrdup(pattern);
01465                 /*@innerbreak@*/ break;
01466             }
01467         }
01468 
01469         /* Retrieve triggered header(s) by key. */
01470         mi = rpmtsInitIterator(ts, RPMTAG_TRIGGERNAME, depName, 0);
01471 
01472         nvals = argiCount(instances);
01473         vals = argiData(instances);
01474         if (nvals > 0)
01475             xx = rpmmiPrune(mi, (uint32_t *)vals, nvals, 1);
01476 
01477         prev = 0;
01478         while((triggeredH = rpmmiNext(mi)) != NULL) {
01479             instance = rpmmiInstance(mi);
01480             if (prev == instance)
01481                 /*@innercontinue@*/ continue;
01482             rc |= handleOneTrigger(psm, fi->h, triggeredH, arg2);
01483             prev = instance;
01484             xx = argiAdd(&instances, -1, instance);
01485             xx = argiSort(instances, NULL);
01486         }
01487 
01488         mi = rpmmiFree(mi);
01489     }
01490 
01491     instances = argiFree(instances);
01492     depName = _free(depName);
01493     (void)rpmdsFree(ds);
01494     ds = NULL;
01495 
01496     return rc;
01497 }
01498 
01504 static rpmRC runTriggers(rpmpsm psm)
01505         /*@globals rpmGlobalMacroContext, h_errno,
01506                 fileSystem, internalState @*/
01507         /*@modifies psm, rpmGlobalMacroContext,
01508                 fileSystem, internalState @*/
01509 {
01510     const rpmts ts = psm->ts;
01511     rpmfi fi = psm->fi;
01512     int numPackage;
01513     rpmTag tagno;
01514     rpmRC rc = RPMRC_OK;
01515 
01516     /* Select RPMTAG_NAME or RPMTAG_PROVIDENAME index for triggering. */
01517     if (_trigger_tag == 0) {
01518         const char * t = rpmExpand("%{?_trigger_tag}", NULL);
01519 /*@-mods@*/
01520         _trigger_tag = (!strcmp(t, "name") ? RPMTAG_NAME : RPMTAG_PROVIDENAME);
01521 /*@=mods@*/
01522         t = _free(t);
01523     }
01524     tagno = _trigger_tag;
01525 
01526 assert(psm->te != NULL);
01527     {   const char * N = rpmteN(psm->te);
01528 assert(N != NULL);
01529         numPackage = rpmdbCountPackages(rpmtsGetRdb(ts), N);
01530         numPackage += psm->countCorrection;
01531         if (numPackage < 0)
01532             return RPMRC_NOTFOUND;
01533     }
01534 assert(fi != NULL);
01535 assert(fi->h != NULL);
01536 
01537     /* XXX Save/restore count correction. */
01538     {   int countCorrection = psm->countCorrection;
01539 
01540         psm->countCorrection = 0;
01541 
01542         /* Try name/providename triggers first. */
01543         rc |= runTriggersLoop(psm, tagno, numPackage);
01544 
01545         /* If not limited to NEVRA triggers, also try file/dir path triggers. */
01546         if (tagno != RPMTAG_NAME) {
01547             int xx;
01548             /* Retrieve trigger patterns from rpmdb. */
01549             xx = rpmdbTriggerGlobs(psm);
01550 
01551             rc |= runTriggersLoop(psm, RPMTAG_BASENAMES, numPackage);
01552             rc |= runTriggersLoop(psm, RPMTAG_DIRNAMES, numPackage);
01553 
01554             psm->Tpats = argvFree(psm->Tpats);
01555             psm->Tmires = mireFreeAll(psm->Tmires, psm->nTmires);
01556             psm->nTmires = 0;
01557         }
01558 
01559         psm->countCorrection = countCorrection;
01560     }
01561 
01562     return rc;
01563 }
01564 
01570 static rpmRC runImmedTriggers(rpmpsm psm)
01571         /*@globals rpmGlobalMacroContext, h_errno,
01572                 fileSystem, internalState @*/
01573         /*@modifies psm, rpmGlobalMacroContext,
01574                 fileSystem, internalState @*/
01575 {
01576     HE_t Ihe = memset(alloca(sizeof(*Ihe)), 0, sizeof(*Ihe));
01577     const rpmts ts = psm->ts;
01578     rpmfi fi = psm->fi;
01579     rpmds triggers = NULL;
01580     rpmmi mi;
01581     ARGV_t keys = NULL;
01582     ARGI_t instances = NULL;
01583     Header sourceH = NULL;
01584     const char * Name;
01585     rpmTag tagno;
01586     rpmRC rc = RPMRC_OK;
01587     int i;
01588     int xx;
01589 
01590 assert(fi->h != NULL);
01591 
01592     /* Select RPMTAG_NAME or RPMTAG_PROVIDENAME index for triggering. */
01593     if (_trigger_tag == 0) {
01594         const char * t = rpmExpand("%{?_trigger_tag}", NULL);
01595 /*@-mods@*/
01596         _trigger_tag = (!strcmp(t, "name") ? RPMTAG_NAME : RPMTAG_PROVIDENAME);
01597 /*@=mods@*/
01598         t = _free(t);
01599     }
01600     tagno = _trigger_tag;
01601 
01602 /*@-castexpose@*/
01603     triggers = rpmdsLink(psm->triggers, "ImmedTriggers");
01604 /*@=castexpose@*/
01605     if (triggers == NULL)
01606         goto exit;
01607 
01608     Ihe->tag = RPMTAG_TRIGGERINDEX;
01609     xx = headerGet(fi->h, Ihe, 0);
01610     if (!(xx && Ihe->p.ui32p && Ihe->c)) goto exit;
01611 
01612     /* Collect primary trigger keys, expanding globs as needed. */
01613     triggers = rpmdsInit(triggers);
01614     if (triggers != NULL)
01615     while ((i = rpmdsNext(triggers)) >= 0) {
01616         evrFlags Flags = rpmdsFlags(triggers);
01617         const char * N = rpmdsN(triggers);
01618         const char * EVR = rpmdsEVR(triggers);
01619 
01620         /* Skip triggers that are not in this context. */
01621         if (!(Flags & psm->sense))
01622             continue;
01623 
01624         /* If not limited to NEVRA triggers, use file/dir index. */
01625         if (tagno != RPMTAG_NAME) {
01626             /* XXX if trigger name ends with '/', use dirnames instead. */
01627             if (N[0] == '/') 
01628                 tagno = (N[strlen(N)-1] == '/')
01629                         ? RPMTAG_DIRNAMES : RPMTAG_FILEPATHS;
01630         }
01631         /* XXX For now, permit globs only in unversioned triggers. */
01632         if ((EVR == NULL || *EVR == '\0') && Glob_pattern_p(N, 0))
01633             xx = rpmdbMireApply(rpmtsGetRdb(ts), tagno, RPMMIRE_GLOB, N, &keys);
01634         else
01635             xx = argvAdd(&keys, N);
01636     }
01637     (void)rpmdsFree(triggers);
01638     triggers = NULL;
01639 
01640     /* For all primary keys, retrieve headers and fire triggers. */
01641     if (keys != NULL)
01642     for (i = 0; (Name = keys[i]) != NULL; i++) {
01643         unsigned prev, instance;
01644         unsigned nvals;
01645         ARGint_t vals;
01646 
01647         /* If not limited to NEVRA triggers, use file/dir index. */
01648         if (tagno != RPMTAG_NAME) {
01649             /* XXX if trigger name ends with '/', use dirnames instead. */
01650             if (Name[0] == '/') 
01651                 tagno = (Name[strlen(Name)-1] == '/')
01652                         ? RPMTAG_DIRNAMES : RPMTAG_FILEPATHS;
01653         }
01654 
01655         mi = rpmtsInitIterator(ts, tagno, Name, 0);
01656 
01657         /* Don't retrieve headers that have already been processed. */
01658         nvals = argiCount(instances);
01659         vals = argiData(instances);
01660         if (nvals > 0)
01661             xx = rpmmiPrune(mi, (uint32_t *)vals, nvals, 1);
01662 
01663         prev = 0;
01664         while((sourceH = rpmmiNext(mi)) != NULL) {
01665 
01666             /* Skip headers that have already been processed. */
01667             instance = rpmmiInstance(mi);
01668             if (prev == instance)
01669                 /*@innercontinue@*/ continue;
01670 
01671             rc |= handleOneTrigger(psm, sourceH, fi->h, rpmmiCount(mi));
01672 
01673             /* Mark header instance as processed. */
01674             prev = instance;
01675             xx = argiAdd(&instances, -1, instance);
01676             xx = argiSort(instances, NULL);
01677         }
01678 
01679         mi = rpmmiFree(mi);
01680     }
01681 
01682 exit:
01683     instances = argiFree(instances);
01684     keys = argvFree(keys);
01685     Ihe->p.ptr = _free(Ihe->p.ptr);
01686     return rc;
01687 }
01688 
01689 /*@observer@*/
01690 static const char * pkgStageString(pkgStage a)
01691         /*@*/
01692 {
01693     switch(a) {
01694     case PSM_UNKNOWN:           return "unknown";
01695 
01696     case PSM_PKGINSTALL:        return "  install";
01697     case PSM_PKGERASE:          return "    erase";
01698     case PSM_PKGCOMMIT:         return "   commit";
01699     case PSM_PKGSAVE:           return "repackage";
01700 
01701     case PSM_INIT:              return "init";
01702     case PSM_PRE:               return "pre";
01703     case PSM_PROCESS:           return "process";
01704     case PSM_POST:              return "post";
01705     case PSM_UNDO:              return "undo";
01706     case PSM_FINI:              return "fini";
01707 
01708     case PSM_CREATE:            return "create";
01709     case PSM_NOTIFY:            return "notify";
01710     case PSM_DESTROY:           return "destroy";
01711     case PSM_COMMIT:            return "commit";
01712 
01713     case PSM_CHROOT_IN:         return "chrootin";
01714     case PSM_CHROOT_OUT:        return "chrootout";
01715     case PSM_SCRIPT:            return "script";
01716     case PSM_TRIGGERS:          return "triggers";
01717     case PSM_IMMED_TRIGGERS:    return "immedtriggers";
01718 
01719     case PSM_RPMIO_FLAGS:       return "rpmioflags";
01720 
01721     case PSM_RPMDB_LOAD:        return "rpmdbload";
01722     case PSM_RPMDB_ADD:         return "rpmdbadd";
01723     case PSM_RPMDB_REMOVE:      return "rpmdbremove";
01724 
01725     default:                    return "???";
01726     }
01727     /*@noteached@*/
01728 }
01729 
01730 void rpmpsmSetAsync(rpmpsm psm, int async)
01731 {
01732     assert(psm != NULL);
01733 #ifdef  REFERENCE
01734     psm->unorderedSuccessor = async;
01735 #else
01736     if (async)
01737         psm->flags |= RPMPSM_FLAGS_UNORDERED;
01738     else
01739         psm->flags &= ~RPMPSM_FLAGS_UNORDERED;
01740 #endif
01741 }
01742 
01743 rpmRC rpmpsmScriptStage(rpmpsm psm, rpmTag scriptTag, rpmTag progTag)
01744 {
01745 assert(psm != NULL);
01746     psm->scriptTag = scriptTag;
01747     psm->progTag = progTag;
01748     /* XXX other tags needed? */
01749     switch (scriptTag) {
01750     default:    break;
01751     case RPMTAG_SANITYCHECK:    psm->stepName = "sanitycheck";  break;
01752     case RPMTAG_VERIFYSCRIPT:   psm->stepName = "verify";       break;
01753     case RPMTAG_PRETRANS:       psm->stepName = "pretrans";     break;
01754     case RPMTAG_POSTTRANS:      psm->stepName = "posttrans";    break;
01755     }
01756     return rpmpsmStage(psm, PSM_SCRIPT);
01757 }
01758 
01759 /*@-mustmod@*/
01760 static void rpmpsmFini(void * _psm)
01761         /*@modifies _psm @*/
01762 {
01763     rpmpsm psm = _psm;
01764 
01765 /*@-nullstate@*/
01766     psm->fi = rpmfiFree(psm->fi);
01767 #ifdef  NOTYET
01768     psm->te = rpmteFree(psm->te);
01769 #else
01770     psm->te = NULL;
01771 #endif
01772 /*@-internalglobs@*/
01773     (void)rpmtsFree(psm->ts); 
01774     psm->ts = NULL;
01775 /*@=internalglobs@*/
01776 
01777     psm->IPhe->p.ptr = _free(psm->IPhe->p.ptr);
01778     psm->IPhe = _free(psm->IPhe);
01779     psm->NVRA = _free(psm->NVRA);
01780     (void)rpmdsFree(psm->triggers);
01781     psm->triggers = NULL;
01782 /*@=nullstate@*/
01783 }
01784 /*@=mustmod@*/
01785 
01786 /*@unchecked@*/ /*@only@*/ /*@null@*/
01787 rpmioPool _psmPool;
01788 
01789 static rpmpsm rpmpsmGetPool(/*@null@*/ rpmioPool pool)
01790         /*@globals _psmPool, fileSystem, internalState @*/
01791         /*@modifies pool, _psmPool, fileSystem, internalState @*/
01792 {
01793     rpmpsm psm;
01794 
01795     if (_psmPool == NULL) {
01796         _psmPool = rpmioNewPool("psm", sizeof(*psm), -1, _psm_debug,
01797                         NULL, NULL, rpmpsmFini);
01798         pool = _psmPool;
01799     }
01800     psm = (rpmpsm) rpmioGetPool(pool, sizeof(*psm));
01801     memset(((char *)psm)+sizeof(psm->_item), 0, sizeof(*psm)-sizeof(psm->_item));
01802     return psm;
01803 }
01804 
01805 rpmpsm rpmpsmNew(rpmts ts, rpmte te, rpmfi fi)
01806 {
01807     static const char msg[] = "rpmpsmNew";
01808     rpmpsm psm = rpmpsmGetPool(_psmPool);
01809 
01810 /*@-assignexpose -castexpose @*/
01811     if (ts)     psm->ts = rpmtsLink(ts, msg);
01812 #ifdef  NOTYET
01813     if (te)     psm->te = rpmteLink(te, msg);
01814 #else
01815 /*@-temptrans @*/
01816     if (te)     psm->te = te;
01817 /*@=temptrans @*/
01818 #endif
01819     if (fi)     psm->fi = rpmfiLink(fi, msg);
01820 /*@=assignexpose =castexpose @*/
01821 
01822     psm->triggers = NULL;
01823     psm->NVRA = NULL;
01824     psm->IPhe = xcalloc(1, sizeof(*psm->IPhe));
01825     memset(psm->sstates, 0, sizeof(psm->sstates));
01826     memset(psm->smetrics, 0, sizeof(psm->smetrics));
01827 
01828     return rpmpsmLink(psm, msg);
01829 }
01830 
01837 static rpmuint32_t hLoadTID(Header h, rpmTag tag)
01838         /*@globals internalState @*/
01839         /*@modifies internalState @*/
01840 {
01841     HE_t he = memset(alloca(sizeof(*he)), 0, sizeof(*he));
01842     rpmuint32_t val;
01843     int xx;
01844 
01845     he->tag = tag;
01846     xx = headerGet(h, he, 0);
01847     val = (xx && he->p.ui32p ? he->p.ui32p[0] : 0);
01848     he->p.ptr = _free(he->p.ptr);
01849     return val;
01850 }
01851 
01859 static int hCopyTag(Header sh, Header th, rpmTag tag)
01860         /*@globals internalState @*/
01861         /*@modifies th, internalState @*/
01862 {
01863     HE_t he = memset(alloca(sizeof(*he)), 0, sizeof(*he));
01864     int xx = 1;
01865 
01866     he->tag = tag;
01867     if (headerGet(sh, he, 0) && he->c > 0)
01868         xx = headerPut(th, he, 0);
01869     he->p.ptr = _free(he->p.ptr);
01870     return 0;
01871 }
01872 
01879 static int hSaveBlinks(Header h, const struct rpmChainLink_s * blink)
01880         /*@modifies h @*/
01881 {
01882     HE_t he = memset(alloca(sizeof(*he)), 0, sizeof(*he));
01883 /*@observer@*/
01884     static const char * chain_end = RPMTE_CHAIN_END;
01885     int ac;
01886     int xx = 1;
01887 
01888     /* Save forward links into header upgrade chain. */
01889     he->tag = RPMTAG_BLINKNEVRA;
01890     he->t = RPM_STRING_ARRAY_TYPE;
01891     ac = argvCount(blink->NEVRA);
01892     if (ac > 0) {
01893         he->p.argv = argvData(blink->NEVRA);
01894         he->c = ac;
01895     } else {    /* XXX Add an explicit chain terminator on 1st install. */
01896         he->p.argv = &chain_end;
01897         he->c = 1;
01898     }
01899     xx = headerPut(h, he, 0);
01900     
01901     he->tag = RPMTAG_BLINKPKGID;
01902     he->t = RPM_STRING_ARRAY_TYPE;
01903     ac = argvCount(blink->Pkgid);
01904     if (ac > 0) {
01905         he->p.argv = argvData(blink->Pkgid);
01906         he->c = ac;
01907     } else {    /* XXX Add an explicit chain terminator on 1st install. */
01908         he->p.argv = &chain_end;
01909         he->c = 1;
01910     }
01911     xx = headerPut(h, he, 0);
01912 
01913     he->tag = RPMTAG_BLINKHDRID;
01914     he->t = RPM_STRING_ARRAY_TYPE;
01915     ac = argvCount(blink->Hdrid);
01916     if (ac > 0) {
01917         he->p.argv = argvData(blink->Hdrid);
01918         he->c = ac;
01919     } else {    /* XXX Add an explicit chain terminator on 1st install. */
01920         he->p.argv = &chain_end;
01921         he->c = 1;
01922     }
01923     xx = headerPut(h, he, 0);
01924 
01925     return 0;
01926 }
01927 
01934 static int hSaveFlinks(Header h, const struct rpmChainLink_s * flink)
01935         /*@modifies h @*/
01936 {
01937     HE_t he = memset(alloca(sizeof(*he)), 0, sizeof(*he));
01938 #ifdef  NOTYET
01939     /*@observer@*/
01940     static const char * chain_end = RPMTE_CHAIN_END;
01941 #endif
01942     int ac;
01943     int xx = 1;
01944 
01945     /* Save forward links into header upgrade chain. */
01946     he->tag = RPMTAG_FLINKNEVRA;
01947     he->t = RPM_STRING_ARRAY_TYPE;
01948     ac = argvCount(flink->NEVRA);
01949     if (ac > 0) {
01950         he->p.argv = argvData(flink->NEVRA);
01951         he->c = ac;
01952     }
01953 #ifdef  NOTYET  /* XXX is an explicit flink terminator needed? */
01954     else {      /* XXX Add an explicit chain terminator on 1st install. */
01955         he->p.argv = &chain_end;
01956         he->c = 1;
01957     }
01958 #endif
01959     xx = headerPut(h, he, 0);
01960 
01961     he->tag = RPMTAG_FLINKPKGID;
01962     he->t = RPM_STRING_ARRAY_TYPE;
01963     ac = argvCount(flink->Pkgid);
01964     if (ac > 0) {
01965         he->p.argv = argvData(flink->Pkgid);
01966         he->c = ac;
01967     }
01968 #ifdef  NOTYET  /* XXX is an explicit flink terminator needed? */
01969     else {      /* XXX Add an explicit chain terminator on 1st install. */
01970         he->p.argv = &chain_end;
01971         he->c = 1;
01972     }
01973 #endif
01974     xx = headerPut(h, he, 0);
01975 
01976     he->tag = RPMTAG_FLINKHDRID;
01977     he->t = RPM_STRING_ARRAY_TYPE;
01978     ac = argvCount(flink->Hdrid);
01979     if (ac > 0) {
01980         he->p.argv = argvData(flink->Hdrid);
01981         he->c = ac;
01982     }
01983 #ifdef  NOTYET  /* XXX is an explicit flink terminator needed? */
01984     else {      /* XXX Add an explicit chain terminator on 1st install. */
01985         he->p.argv = &chain_end;
01986         he->c = 1;
01987     }
01988 #endif
01989     xx = headerPut(h, he, 0);
01990 
01991     return 0;
01992 }
01993 
02001 static int populateInstallHeader(const rpmts ts, const rpmte te, rpmfi fi)
02002         /*@globals h_errno, fileSystem, internalState @*/
02003         /*@modifies fi, fileSystem, internalState @*/
02004 {
02005     HE_t he = memset(alloca(sizeof(*he)), 0, sizeof(*he));
02006     rpmuint32_t tscolor = rpmtsColor(ts);
02007     rpmuint32_t tecolor = rpmteColor(te);
02008     rpmuint32_t * uip;
02009     rpmuint32_t installTime[2];
02010     rpmuint32_t originTime[2];
02011     rpmuint32_t originTid[2];
02012     int xx = 1;
02013 
02014 assert(fi->h != NULL);
02015 
02016     {   struct timeval tv;
02017         xx = gettimeofday(&tv, NULL);
02018         installTime[0] = (rpmuint32_t) tv.tv_sec;
02019         installTime[1] = (rpmuint32_t) tv.tv_usec;
02020     }
02021     he->tag = RPMTAG_INSTALLTIME;
02022     he->t = RPM_UINT32_TYPE;
02023     he->p.ui32p = &installTime[0];
02024     he->c = 2;
02025     xx = headerPut(fi->h, he, 0);
02026 
02027     /* Propagate the tid & time that the package was first installed. */
02028     if ((uip = rpmteOriginTime(te)) != NULL)
02029         memcpy(originTime, uip, sizeof(originTime));
02030     if (originTime[0] == 0)
02031         memcpy(originTime, installTime, sizeof(originTime));
02032     he->tag = RPMTAG_ORIGINTIME;
02033     he->t = RPM_UINT32_TYPE;
02034     he->p.ui32p = originTime;
02035     he->c = 2;
02036     xx = headerPut(fi->h, he, 0);
02037 
02038     if ((uip = rpmteOriginTid(te)) != NULL)
02039         memcpy(originTid, uip, sizeof(originTid));
02040     if (originTid[0] == 0)
02041         memcpy(originTid, ts->tid, sizeof(originTid));
02042     he->tag = RPMTAG_ORIGINTID;
02043     he->t = RPM_UINT32_TYPE;
02044     he->p.ui32p = originTid;
02045     he->c = 2;
02046     xx = headerPut(fi->h, he, 0);
02047 
02048     he->tag = RPMTAG_INSTALLCOLOR;
02049     he->t = RPM_UINT32_TYPE;
02050     he->p.ui32p = &tscolor;
02051     he->c = 1;
02052     xx = headerPut(fi->h, he, 0);
02053 
02054     /* XXX FIXME: add preferred color at install. */
02055 
02056     he->tag = RPMTAG_PACKAGECOLOR;
02057     he->t = RPM_UINT32_TYPE;
02058     he->p.ui32p = &tecolor;
02059     he->c = 1;
02060     xx = headerPut(fi->h, he, 0);
02061 
02062     /* Add the header's origin/digest/stat (i.e. URL) */
02063     {   const char * fn = headerGetOrigin(fi->h);
02064         const char * digest = headerGetDigest(fi->h);
02065         struct stat * st = headerGetStatbuf(fi->h);
02066 
02067         if (fn != NULL) {
02068             he->tag = RPMTAG_PACKAGEORIGIN;
02069             he->t = RPM_STRING_TYPE;
02070             he->p.str = xstrdup(fn);
02071             he->c = 1;
02072             xx = headerPut(fi->h, he, 0);
02073             he->p.ptr = _free(he->p.ptr);
02074 
02075             if (digest != NULL) {
02076                 he->tag = RPMTAG_PACKAGEDIGEST;
02077                 he->t = RPM_STRING_TYPE;
02078                 he->p.str = headerGetDigest(fi->h);
02079                 he->c = 1;
02080                 xx = headerPut(fi->h, he, 0);
02081             }
02082             if (st != NULL) {
02083 /* XXX Fstat(2) in pkgio.c should set *st. Verify st->st_mode w assert(3). */
02084 #ifndef DYING
02085                 int ut = urlPath(fn, NULL);
02086                 /* XXX URI is active, so avoid the lazy Stat(2) for now. */
02087                 if (!(ut == URL_IS_HTTP || ut == URL_IS_HTTPS))
02088                 if (st->st_mode == 0 && st->st_mtime == 0 && st->st_size == 0)
02089                     xx = Stat(fn, st);
02090 #endif
02091                 if (st->st_mode != 0) {
02092                     he->tag = RPMTAG_PACKAGESTAT;
02093                     he->t = RPM_BIN_TYPE;
02094                     he->p.ptr = (void *)st;
02095                     he->c = (rpmTagCount) sizeof(*st);
02096                     xx = headerPut(fi->h, he, 0);
02097                 }
02098             }
02099         }
02100     }
02101 
02102     /* XXX Don't clobber forward/backward upgrade chain on rollbacks */
02103     if (rpmtsType(ts) != RPMTRANS_TYPE_ROLLBACK)
02104         xx = hSaveBlinks(fi->h, &te->blink);
02105 
02106     return 0;
02107 }
02108 
02116 static int postPopulateInstallHeader(/*@unused@*/ const rpmts ts,
02117                 const rpmpsm psm, rpmfi fi)
02118         /*@modifies psm, fi @*/
02119 {
02120     HE_t he = memset(alloca(sizeof(*he)), 0, sizeof(*he));
02121     int fc = rpmfiFC(fi);
02122     int xx = 1;
02123 
02124     /* Add the (install) scriptlet status/metrics. */
02125     he->tag = RPMTAG_SCRIPTSTATES;
02126     he->t = RPM_UINT32_TYPE;
02127     he->p.ui32p = psm->sstates;
02128     he->c = RPMSCRIPT_MAX;
02129     xx = headerPut(fi->h, he, 0);
02130     he->tag = RPMTAG_SCRIPTMETRICS;
02131     he->t = RPM_UINT32_TYPE;
02132     he->p.ui32p = psm->smetrics;
02133     he->c = RPMSCRIPT_MAX;
02134     xx = headerPut(fi->h, he, 0);
02135 
02136     /* Add file states to install header. */
02137     if (fi->fstates != NULL && fc > 0) {
02138         he->tag = RPMTAG_FILESTATES;
02139         he->t = RPM_UINT8_TYPE;
02140         he->p.ui8p = fi->fstates;
02141         he->c = fc;
02142         xx = headerPut(fi->h, he, 0);
02143     }
02144 
02145     return 0;
02146 }
02147 
02148 #if defined(WITH_PTHREADS)
02149 static void * rpmpsmThread(void * arg)
02150         /*@globals rpmGlobalMacroContext, h_errno, fileSystem, internalState @*/
02151         /*@modifies arg, rpmGlobalMacroContext, fileSystem, internalState @*/
02152 {
02153     rpmpsm psm = arg;
02154 /*@-unqualifiedtrans@*/
02155     return ((void *) rpmpsmStage(psm, psm->nstage));
02156 /*@=unqualifiedtrans@*/
02157 }
02158 #endif
02159 
02160 static int rpmpsmNext(rpmpsm psm, pkgStage nstage)
02161         /*@globals rpmGlobalMacroContext, h_errno, fileSystem, internalState @*/
02162         /*@modifies psm, rpmGlobalMacroContext, fileSystem, internalState @*/
02163 {
02164     psm->nstage = nstage;
02165 #if defined(WITH_PTHREADS)
02166     if (_psm_threads)
02167         return rpmsqJoin( rpmsqThread(rpmpsmThread, psm) );
02168 #endif
02169     return rpmpsmStage(psm, psm->nstage);
02170 }
02171 
02176 /*@-nullpass@*/ /* FIX: testing null annotation for fi->h */
02177 rpmRC rpmpsmStage(rpmpsm psm, pkgStage stage)
02178 {
02179     HE_t he = memset(alloca(sizeof(*he)), 0, sizeof(*he));
02180     const rpmts ts = psm->ts;
02181     rpmuint32_t tscolor = rpmtsColor(ts);
02182     rpmfi fi = psm->fi;
02183     rpmRC rc = psm->rc;
02184     int saveerrno;
02185     int xx;
02186     int non_pre_scripts_dont_fail = 0;
02187 #if defined(RPM_VENDOR_MANDRIVA)
02188     non_pre_scripts_dont_fail = rpmExpandNumeric("%{?_legacy_compat_non_pre_scripts_dont_fail}");
02189 #endif
02190 
02191 /* XXX hackery to assert(!scareMem) in rpmfiNew. */
02192 /*@-castexpose@*/
02193 if (fi->h == NULL && fi->te && ((rpmte)fi->te)->h != NULL) fi->h = headerLink(((rpmte)fi->te)->h);
02194 /*@=castexpose@*/
02195 
02196     switch (stage) {
02197     case PSM_UNKNOWN:
02198         break;
02199     case PSM_INIT:
02200         rpmlog(RPMLOG_DEBUG, D_("%s: %s has %d files, test = %d\n"),
02201                 psm->stepName, rpmteNEVR(psm->te),
02202                 rpmfiFC(fi), (rpmtsFlags(ts) & RPMTRANS_FLAG_TEST));
02203 
02204         /*
02205          * When we run scripts, we pass an argument which is the number of
02206          * versions of this package that will be installed when we are
02207          * finished.
02208          */
02209         psm->npkgs_installed = rpmdbCountPackages(rpmtsGetRdb(ts), rpmteN(psm->te));
02210         if (psm->npkgs_installed < 0) {
02211             rc = RPMRC_FAIL;
02212             break;
02213         }
02214 
02215         /* Adjust package count on rollback downgrade. */
02216 assert(psm->te != NULL);
02217         if (rpmtsType(ts) == RPMTRANS_TYPE_AUTOROLLBACK &&
02218             (psm->goal & ~(PSM_PKGSAVE|PSM_PKGERASE)))
02219         {
02220             if (psm->te->downgrade)
02221                 psm->npkgs_installed--;
02222         }
02223 
02224         if (psm->goal == PSM_PKGINSTALL) {
02225             int fc = rpmfiFC(fi);
02226             const char * hdrid;
02227 
02228             /* Add per-transaction data to install header. */
02229             xx = populateInstallHeader(ts, psm->te, fi);
02230 
02231             psm->scriptArg = psm->npkgs_installed + 1;
02232 
02233 assert(psm->mi == NULL);
02234             hdrid = rpmteHdrid(psm->te);
02235             if (hdrid != NULL) {
02236                 /* XXX should use RPMTAG_HDRID not RPMTAG_SHA1HEADER */
02237                 psm->mi = rpmtsInitIterator(ts, RPMTAG_SHA1HEADER, hdrid, 0);
02238             } else {
02239                 psm->mi = rpmtsInitIterator(ts, RPMTAG_NAME, rpmteN(psm->te),0);
02240                 xx = rpmmiAddPattern(psm->mi, RPMTAG_EPOCH, RPMMIRE_STRCMP,
02241                         rpmteE(psm->te));
02242                 xx = rpmmiAddPattern(psm->mi, RPMTAG_VERSION, RPMMIRE_STRCMP,
02243                         rpmteV(psm->te));
02244                 xx = rpmmiAddPattern(psm->mi, RPMTAG_RELEASE, RPMMIRE_STRCMP,
02245                         rpmteR(psm->te));
02246 #ifdef  RPM_VENDOR_MANDRIVA
02247                 xx = rpmmiAddPattern(psm->mi, RPMTAG_DISTEPOCH, RPMMIRE_STRCMP,
02248                         rpmteD(psm->te));
02249 #endif
02250                 if (tscolor) {
02251                     xx = rpmmiAddPattern(psm->mi,RPMTAG_ARCH, RPMMIRE_STRCMP,
02252                         rpmteA(psm->te));
02253                     xx = rpmmiAddPattern(psm->mi, RPMTAG_OS, RPMMIRE_STRCMP,
02254                         rpmteO(psm->te));
02255                 }
02256             }
02257 
02258             while ((psm->oh = rpmmiNext(psm->mi)) != NULL) {
02259                 fi->record = rpmmiInstance(psm->mi);
02260                 psm->oh = NULL;
02261                 /*@loopbreak@*/ break;
02262             }
02263             psm->mi = rpmmiFree(psm->mi);
02264 
02265             rc = RPMRC_OK;
02266 
02267             /* XXX lazy alloc here may need to be done elsewhere. */
02268             if (fi->fstates == NULL && fc > 0) {
02269                 fi->fstates = xmalloc(sizeof(*fi->fstates) * fc);
02270                 memset(fi->fstates, RPMFILE_STATE_NORMAL, fc);
02271             }
02272 
02273             xx = rpmtxnBegin(rpmtsGetRdb(ts), ts->txn, &psm->te->txn);
02274 
02275             if (rpmtsFlags(ts) & RPMTRANS_FLAG_JUSTDB)  break;
02276             if (fc <= 0)                                break;
02277         
02278             /*
02279              * Old format relocatable packages need the entire default
02280              * prefix stripped to form the cpio list, while all other packages
02281              * need the leading / stripped.
02282              */
02283             he->tag = RPMTAG_DEFAULTPREFIX;
02284             xx = headerGet(fi->h, he, 0);
02285             fi->striplen = (xx && he->p.str ? strlen(he->p.str) + 1 : 1);
02286             he->p.ptr = _free(he->p.ptr);
02287             fi->mapflags =
02288                 IOSM_MAP_PATH | IOSM_MAP_MODE | IOSM_MAP_UID | IOSM_MAP_GID | (fi->mapflags & IOSM_SBIT_CHECK);
02289         
02290             if (headerIsEntry(fi->h, RPMTAG_ORIGBASENAMES))
02291                 he->tag = RPMTAG_ORIGPATHS;
02292             else
02293                 he->tag = RPMTAG_FILEPATHS;
02294             xx = headerGet(fi->h, he, 0);
02295 assert(he->p.argv != NULL);
02296             fi->apath = he->p.argv;
02297         
02298             if (fi->fuser == NULL) {
02299                 he->tag = RPMTAG_FILEUSERNAME;
02300                 xx = headerGet(fi->h, he, 0);
02301                 fi->fuser = he->p.argv;
02302             }
02303             if (fi->fgroup == NULL) {
02304                 he->tag = RPMTAG_FILEGROUPNAME;
02305                 xx = headerGet(fi->h, he, 0);
02306                 fi->fgroup = he->p.argv;
02307             }
02308             rc = RPMRC_OK;
02309         }
02310         if (psm->goal == PSM_PKGERASE || psm->goal == PSM_PKGSAVE) {
02311             psm->scriptArg = psm->npkgs_installed - 1;
02312         
02313             /* XXX FIXME: PSM_PKGSAVE needs to be transactionally protected. */
02314             if (psm->goal == PSM_PKGERASE)
02315                 xx = rpmtxnBegin(rpmtsGetRdb(ts), ts->txn, &psm->te->txn);
02316 
02317             /* Retrieve installed header. */
02318             rc = rpmpsmNext(psm, PSM_RPMDB_LOAD);
02319             if (rc == RPMRC_OK && psm->te)
02320                 (void) rpmteSetHeader(psm->te, fi->h);
02321         }
02322         if (psm->goal == PSM_PKGSAVE) {
02323             /* Open output package for writing. */
02324             {   char tiddn[32];
02325                 const char * bfmt;
02326                 const char * pkgdn;
02327                 const char * pkgbn;
02328                 char * pkgdn_buf;
02329 
02330                 xx = snprintf(tiddn, sizeof(tiddn), "%d", rpmtsGetTid(ts));
02331                 bfmt = rpmGetPath(tiddn, "/", "%{_repackage_name_fmt}", NULL);
02332                 pkgbn = headerSprintf(fi->h, bfmt,
02333                                         NULL, rpmHeaderFormats, NULL);
02334                 bfmt = _free(bfmt);
02335                 psm->pkgURL = rpmGenPath("%{?_repackage_root}",
02336                                          "%{?_repackage_dir}",
02337                                         pkgbn);
02338                 pkgbn = _free(pkgbn);
02339                 (void) urlPath(psm->pkgURL, &psm->pkgfn);
02340                 pkgdn_buf = xstrdup(psm->pkgfn);
02341 /*@-moduncon@*/
02342                 pkgdn = dirname(pkgdn_buf);
02343 /*@=moduncon@*/
02344                 rc = rpmMkdirPath(pkgdn, "_repackage_dir");
02345                 pkgdn_buf = _free(pkgdn_buf);
02346                 if (rc == RPMRC_FAIL)
02347                     break;
02348                 psm->fd = Fopen(psm->pkgfn, "w.fdio");
02349                 if (psm->fd == NULL || Ferror(psm->fd)) {
02350                     rc = RPMRC_FAIL;
02351                     break;
02352                 }
02353             }
02354         }
02355         break;
02356     case PSM_PRE:
02357         if (rpmtsFlags(ts) & RPMTRANS_FLAG_TEST)        break;
02358 
02359 /* XXX insure that trigger index is opened before entering chroot. */
02360 #ifdef  NOTYET
02361  { static int oneshot = 0;
02362    dbiIndex dbi;
02363    if (!oneshot) {
02364      dbi = dbiOpen(rpmtsGetRdb(ts), RPMTAG_TRIGGERNAME, 0);
02365      oneshot++;
02366    }
02367  }
02368 #endif
02369 
02370         /* Change root directory if requested and not already done. */
02371         rc = rpmpsmNext(psm, PSM_CHROOT_IN);
02372 
02373         if (psm->goal == PSM_PKGINSTALL) {
02374             psm->scriptTag = RPMTAG_PREIN;
02375             psm->progTag = RPMTAG_PREINPROG;
02376             psm->sense = RPMSENSE_TRIGGERPREIN;
02377             psm->countCorrection = 0;   /* XXX is this correct?!? */
02378 
02379             if (!(rpmtsFlags(ts) & RPMTRANS_FLAG_NOTRIGGERPREIN)) {
02380 
02381                 /* Run triggers in other package(s) this package sets off. */
02382                 rc = rpmpsmNext(psm, PSM_TRIGGERS);
02383                 if (rc) break;
02384 
02385                 /* Run triggers in this package other package(s) set off. */
02386                 rc = rpmpsmNext(psm, PSM_IMMED_TRIGGERS);
02387                 if (rc) break;
02388             }
02389 
02390             if (!(rpmtsFlags(ts) & RPMTRANS_FLAG_NOPRE)) {
02391                 rc = rpmpsmNext(psm, PSM_SCRIPT);
02392                 if (rc != RPMRC_OK) {
02393                     rpmlog(RPMLOG_ERR,
02394                         _("%s: %s scriptlet failed (%d), skipping %s\n"),
02395                         psm->stepName, tag2sln(psm->scriptTag), rc,
02396                         rpmteNEVR(psm->te));
02397                     break;
02398                 }
02399             }
02400         }
02401 
02402         if (psm->goal == PSM_PKGERASE) {
02403             psm->scriptTag = RPMTAG_PREUN;
02404             psm->progTag = RPMTAG_PREUNPROG;
02405             psm->sense = RPMSENSE_TRIGGERUN;
02406             psm->countCorrection = -1;
02407 
02408             if (!(rpmtsFlags(ts) & RPMTRANS_FLAG_NOTRIGGERUN)) {
02409                 /* Run triggers in this package other package(s) set off. */
02410                 rc = rpmpsmNext(psm, PSM_IMMED_TRIGGERS);
02411                 if(rc && !non_pre_scripts_dont_fail) break;
02412 
02413                 /* Run triggers in other package(s) this package sets off. */
02414                 rc = rpmpsmNext(psm, PSM_TRIGGERS);
02415                 if(rc && !non_pre_scripts_dont_fail) break;
02416             }
02417 
02418             if (!(rpmtsFlags(ts) & RPMTRANS_FLAG_NOPREUN))
02419                 rc = rpmpsmNext(psm, PSM_SCRIPT);
02420         }
02421         if (psm->goal == PSM_PKGSAVE) {
02422             int noArchiveSize = 0;
02423             const char * origin = NULL;
02424             const char * digest = NULL;
02425             const struct stat * st = NULL;
02426             size_t nstbytes = 0;
02427 
02428             /* Regenerate original header. */
02429             {   void * uh = NULL;
02430 
02431                 /* Save original header's origin/digest/stat (i.e. URL) */
02432                 he->tag = RPMTAG_PACKAGEORIGIN;
02433                 xx = headerGet(fi->h, he, 0);
02434                 origin = he->p.str;
02435                 he->tag = RPMTAG_PACKAGEDIGEST;
02436                 xx = headerGet(fi->h, he, 0);
02437                 if (xx && he->p.str != NULL)
02438                     digest = he->p.str;
02439                 he->tag = RPMTAG_PACKAGESTAT;
02440                 xx = headerGet(fi->h, he, 0);
02441                 if (xx && he->p.ptr != NULL && (size_t)he->c == sizeof(*st)) {
02442                     st = he->p.ptr;
02443                     nstbytes = he->c;
02444                 }
02445 
02446                 /* Retrieve original header blob. */
02447                 he->tag = RPMTAG_HEADERIMMUTABLE;
02448                 xx = headerGet(fi->h, he, 0);
02449                 uh = he->p.ptr;
02450                 if (xx && uh != NULL) {
02451                     psm->oh = headerCopyLoad(uh);
02452                     uh = _free(uh);
02453                 } else {
02454                     he->tag = RPMTAG_HEADERIMAGE;
02455                     xx = headerGet(fi->h, he, 0);
02456                     uh = he->p.ptr;
02457                     if (xx && uh != NULL) {
02458                         HeaderIterator hi;
02459                         Header oh;
02460 
02461                         /* Load the original header from the blob. */
02462                         oh = headerCopyLoad(uh);
02463 
02464                         /* XXX this is headerCopy w/o headerReload() */
02465                         psm->oh = headerNew();
02466 
02467                         for (hi = headerInit(oh);
02468                              headerNext(hi, he, 0);
02469                              he->p.ptr = _free(he->p.ptr))
02470                         {
02471                             if (he->tag == RPMTAG_ARCHIVESIZE)
02472                                 noArchiveSize = 1;
02473                             xx = headerPut(psm->oh, he, 0);
02474                         }
02475                         hi = headerFini(hi);
02476 
02477                         (void)headerFree(oh);
02478                         oh = NULL;
02479                         uh = _free(uh);
02480                     } else
02481                         break;  /* XXX shouldn't ever happen */
02482                 }
02483             }
02484 
02485             /* Retrieve type of payload compression. */
02486             /*@-nullstate@*/    /* FIX: psm->oh may be NULL */
02487             rc = rpmpsmNext(psm, PSM_RPMIO_FLAGS);
02488             /*@=nullstate@*/
02489 
02490             /* Write the lead section into the package. */
02491             {   static const char item[] = "Lead";
02492                 const char * NEVR = rpmteNEVR(psm->te);
02493                 size_t nb = rpmpkgSizeof(item, NULL);
02494         
02495                 if (nb == 0)
02496                     rc = RPMRC_FAIL;
02497                 else {
02498                     void * l = alloca(nb);
02499                     memset(l, 0, nb);
02500                     rc = rpmpkgWrite(item, psm->fd, l, &NEVR);
02501                 }
02502                 if (rc != RPMRC_OK) {
02503                     rpmlog(RPMLOG_ERR, _("Unable to write package: %s\n"),
02504                                 Fstrerror(psm->fd));
02505                     break;
02506                 }
02507             }
02508 
02509             /* Write the signature section into the package. */
02510             /* XXX rpm-4.1 and later has archive size in signature header. */
02511             {   static const char item[] = "Signature";
02512                 Header sigh = headerRegenSigHeader(fi->h, noArchiveSize);
02513                 /* Reallocate the signature into one contiguous region. */
02514                 sigh = headerReload(sigh, RPMTAG_HEADERSIGNATURES);
02515                 if (sigh == NULL) {
02516                     rpmlog(RPMLOG_ERR, _("Unable to reload signature header\n"));
02517                     rc = RPMRC_FAIL;
02518                     break;
02519                 }
02520                 rc = rpmpkgWrite(item, psm->fd, sigh, NULL);
02521                 (void)headerFree(sigh);
02522                 sigh = NULL;
02523                 if (rc != RPMRC_OK) {
02524                     break;
02525                 }
02526             }
02527 
02528             /* Add remove transaction id to header. */
02529             if (psm->oh != NULL)
02530             {   rpmuint32_t tid = rpmtsGetTid(ts);
02531 
02532                 he->tag = RPMTAG_REMOVETID;
02533                 he->t = RPM_UINT32_TYPE;
02534                 he->p.ui32p = &tid;
02535                 he->c = 1;
02536                 xx = headerPut(psm->oh, he, 0);
02537 
02538                 /* Add original header's origin/digest/stat (i.e. URL) */
02539                 if (origin != NULL) {
02540                     he->tag = RPMTAG_PACKAGEORIGIN;
02541                     he->t = RPM_STRING_TYPE;
02542                     he->p.str = origin;
02543                     he->c = 1;
02544                     xx = headerPut(psm->oh, he, 0);
02545                     origin = _free(origin);
02546                 }
02547                 if (digest != NULL) {
02548                     he->tag = RPMTAG_PACKAGEDIGEST;
02549                     he->t = RPM_STRING_TYPE;
02550                     he->p.str = digest;
02551                     he->c = 1;
02552                     xx = headerPut(psm->oh, he, 0);
02553                     digest = _free(digest);
02554                 }
02555                 if (st != NULL) {
02556                     he->tag = RPMTAG_PACKAGESTAT;
02557                     he->t = RPM_BIN_TYPE;
02558                     he->p.ptr = (void *)st;
02559                     he->c = (rpmTagCount)nstbytes;
02560                     xx = headerPut(psm->oh, he, 0);
02561                     st = _free(st);
02562                 }
02563 
02564                 /* Copy upgrade chain link tags. */
02565                 xx = hCopyTag(fi->h, psm->oh, RPMTAG_INSTALLTID);
02566                 xx = hCopyTag(fi->h, psm->oh, RPMTAG_BLINKPKGID);
02567                 xx = hCopyTag(fi->h, psm->oh, RPMTAG_BLINKHDRID);
02568                 xx = hCopyTag(fi->h, psm->oh, RPMTAG_BLINKNEVRA);
02569 
02570 assert(psm->te != NULL);
02571                 xx = hSaveFlinks(psm->oh, &psm->te->flink);
02572             }
02573 
02574             /* Write the metadata section into the package. */
02575             {   const char item[] = "Header";
02576                 const char * msg = NULL;
02577                 rc = rpmpkgWrite(item, psm->fd, psm->oh, &msg);
02578                 if (rc != RPMRC_OK) {
02579                     rpmlog(RPMLOG_ERR, "%s: %s: %s", psm->pkgfn, item,
02580                         (msg && *msg ? msg : "write failed\n"));
02581                     msg = _free(msg);
02582                 }
02583             }
02584         }
02585         break;
02586     case PSM_PROCESS:
02587         if (rpmtsFlags(ts) & RPMTRANS_FLAG_TEST)        break;
02588 
02589         if (psm->goal == PSM_PKGINSTALL) {
02590 
02591             if (rpmtsFlags(ts) & RPMTRANS_FLAG_JUSTDB)  break;
02592 
02593             /* XXX Synthesize callbacks for packages with no files. */
02594             if (rpmfiFC(fi) <= 0) {
02595                 void * ptr;
02596                 ptr = rpmtsNotify(ts, fi->te, RPMCALLBACK_INST_START, 0, 100);
02597                 ptr = rpmtsNotify(ts, fi->te, RPMCALLBACK_INST_PROGRESS, 100, 100);
02598                 break;
02599             }
02600 
02601             /* Retrieve type of payload compression. */
02602             rc = rpmpsmNext(psm, PSM_RPMIO_FLAGS);
02603 
02604             if (rpmteFd(fi->te) == NULL) {      /* XXX can't happen */
02605                 rc = RPMRC_FAIL;
02606                 break;
02607             }
02608 
02609             /*@-nullpass@*/     /* LCL: fi->fd != NULL here. */
02610             psm->cfd = Fdopen(fdDup(Fileno(rpmteFd(fi->te))), psm->rpmio_flags);
02611             /*@=nullpass@*/
02612             if (psm->cfd == NULL) {     /* XXX can't happen */
02613                 rc = RPMRC_FAIL;
02614                 break;
02615             }
02616 
02617             xx = rpmtxnBegin(rpmtsGetRdb(ts), psm->te->txn, NULL);
02618 
02619             rc = fsmSetup(fi->fsm, IOSM_PKGINSTALL, psm->payload_format, ts, fi,
02620                         psm->cfd, NULL, &psm->failedFile);
02621             (void) rpmswAdd(rpmtsOp(ts, RPMTS_OP_UNCOMPRESS),
02622                         fdstat_op(psm->cfd, FDSTAT_READ));
02623             (void) rpmswAdd(rpmtsOp(ts, RPMTS_OP_DIGEST),
02624                         fdstat_op(psm->cfd, FDSTAT_DIGEST));
02625             xx = fsmTeardown(fi->fsm);
02626 
02627             saveerrno = errno; /* XXX FIXME: Fclose with libio destroys errno */
02628             xx = Fclose(psm->cfd);
02629             psm->cfd = NULL;
02630             /*@-mods@*/
02631             errno = saveerrno; /* XXX FIXME: Fclose with libio destroys errno */
02632             /*@=mods@*/
02633 
02634             if (!rc)
02635                 rc = rpmpsmNext(psm, PSM_COMMIT);
02636 
02637             /* Commit/abort the SRPM install transaction. */
02638             /* XXX move into the PSM package state machine w PSM_COMMIT */
02639         {   rpmdb db = rpmtsGetRdb(ts);
02640             rpmtxn _txn = (db ? db->db_txn : NULL);
02641             if (_txn != NULL) {
02642                 if (rc)
02643                     xx = rpmtxnAbort(_txn);
02644                 else
02645                     xx = rpmtxnCommit(_txn);
02646                 db->db_txn = NULL;
02647             }
02648         }
02649 
02650             /* XXX make sure progress is closed out */
02651             psm->what = RPMCALLBACK_INST_PROGRESS;
02652             psm->amount = (fi->archiveSize ? fi->archiveSize : 100);
02653             psm->total = psm->amount;
02654             xx = rpmpsmNext(psm, PSM_NOTIFY);
02655 
02656             if (rc) {
02657                 const char * msg = iosmStrerror(rc);
02658                 rpmlog(RPMLOG_ERR,
02659                         _("unpacking of archive failed%s%s: %s\n"),
02660                         (psm->failedFile != NULL ? _(" on file ") : ""),
02661                         (psm->failedFile != NULL ? psm->failedFile : ""),
02662                         msg);
02663                 msg = _free(msg);
02664                 rc = RPMRC_FAIL;
02665 
02666                 /* XXX notify callback on error. */
02667                 psm->what = RPMCALLBACK_UNPACK_ERROR;
02668                 psm->amount = 0;
02669                 psm->total = 0;
02670                 xx = rpmpsmNext(psm, PSM_NOTIFY);
02671 
02672                 break;
02673             }
02674         }
02675         if (psm->goal == PSM_PKGERASE) {
02676             int fc = rpmfiFC(fi);
02677 
02678             if (rpmtsFlags(ts) & RPMTRANS_FLAG_JUSTDB)  break;
02679             if (rpmtsFlags(ts) & RPMTRANS_FLAG_APPLYONLY)       break;
02680 
02681             psm->what = RPMCALLBACK_UNINST_START;
02682             psm->amount = fc;
02683             psm->total = (fc ? fc : 100);
02684             xx = rpmpsmNext(psm, PSM_NOTIFY);
02685 
02686             if (fc > 0) {
02687                 rc = fsmSetup(fi->fsm, IOSM_PKGERASE, psm->payload_format, ts, fi,
02688                         NULL, NULL, &psm->failedFile);
02689                 xx = fsmTeardown(fi->fsm);
02690             }
02691 
02692             psm->what = RPMCALLBACK_UNINST_STOP;
02693             psm->amount = (fc ? fc : 100);
02694             psm->total = (fc ? fc : 100);
02695             xx = rpmpsmNext(psm, PSM_NOTIFY);
02696 
02697         }
02698         if (psm->goal == PSM_PKGSAVE) {
02699             iosmFileAction * actions = (iosmFileAction *) fi->actions;
02700             iosmFileAction action = (iosmFileAction) fi->action;
02701 
02702             fi->action = FA_COPYOUT;
02703             fi->actions = NULL;
02704 
02705             if (psm->fd == NULL) {      /* XXX can't happen */
02706                 rc = RPMRC_FAIL;
02707                 break;
02708             }
02709             /*@-nullpass@*/     /* FIX: fdDup mey return NULL. */
02710             xx = Fflush(psm->fd);
02711             psm->cfd = Fdopen(fdDup(Fileno(psm->fd)), psm->rpmio_flags);
02712             /*@=nullpass@*/
02713             if (psm->cfd == NULL) {     /* XXX can't happen */
02714                 rc = RPMRC_FAIL;
02715                 break;
02716             }
02717 
02718             rc = fsmSetup(fi->fsm, IOSM_PKGBUILD, psm->payload_format, ts, fi,
02719                         psm->cfd, NULL, &psm->failedFile);
02720             (void) rpmswAdd(rpmtsOp(ts, RPMTS_OP_COMPRESS),
02721                         fdstat_op(psm->cfd, FDSTAT_WRITE));
02722             (void) rpmswAdd(rpmtsOp(ts, RPMTS_OP_DIGEST),
02723                         fdstat_op(psm->cfd, FDSTAT_DIGEST));
02724             xx = fsmTeardown(fi->fsm);
02725 
02726             saveerrno = errno; /* XXX FIXME: Fclose with libio destroys errno */
02727             xx = Fclose(psm->cfd);
02728             psm->cfd = NULL;
02729             /*@-mods@*/
02730             errno = saveerrno;
02731             /*@=mods@*/
02732 
02733             /* XXX make sure progress is closed out */
02734             psm->what = RPMCALLBACK_INST_PROGRESS;
02735             psm->amount = (fi->archiveSize ? fi->archiveSize : 100);
02736             psm->total = psm->amount;
02737             xx = rpmpsmNext(psm, PSM_NOTIFY);
02738 
02739             fi->action = (int) action;
02740             fi->actions = (int *) actions;
02741         }
02742         break;
02743     case PSM_POST:
02744         if (rpmtsFlags(ts) & RPMTRANS_FLAG_TEST)        break;
02745 
02746         if (psm->goal == PSM_PKGINSTALL) {
02747 
02748             psm->scriptTag = RPMTAG_POSTIN;
02749             psm->progTag = RPMTAG_POSTINPROG;
02750             psm->sense = RPMSENSE_TRIGGERIN;
02751             psm->countCorrection = 0;
02752 
02753             if (!(rpmtsFlags(ts) & RPMTRANS_FLAG_NOPOST)) {
02754                 rc = rpmpsmNext(psm, PSM_SCRIPT);
02755                 if(rc && !non_pre_scripts_dont_fail) break;
02756             }
02757             if (!(rpmtsFlags(ts) & RPMTRANS_FLAG_NOTRIGGERIN)) {
02758                 /* Run triggers in other package(s) this package sets off. */
02759                 rc = rpmpsmNext(psm, PSM_TRIGGERS);
02760                 if(rc && !non_pre_scripts_dont_fail) break;
02761 
02762                 /* Run triggers in this package other package(s) set off. */
02763                 rc = rpmpsmNext(psm, PSM_IMMED_TRIGGERS);
02764                 if(rc && !non_pre_scripts_dont_fail) break;
02765             }
02766 
02767             /*
02768              * If this header has already been installed, remove it from
02769              * the database before adding the new header.
02770              */
02771             if (fi->record && !(rpmtsFlags(ts) & RPMTRANS_FLAG_APPLYONLY)) {
02772                 rc = rpmpsmNext(psm, PSM_RPMDB_REMOVE);
02773                 if (rc) break;
02774             }
02775 
02776             /* Add scriptlet/file states to install header. */
02777             xx = postPopulateInstallHeader(ts, psm, fi);
02778 
02779             rc = rpmpsmNext(psm, PSM_RPMDB_ADD);
02780             if (rc) break;
02781 
02782 #ifdef  DYING
02783             if (!(rpmtsFlags(ts) & RPMTRANS_FLAG_APPLYONLY))
02784                 rc = markReplacedFiles(psm);
02785 #endif
02786 
02787         }
02788         if (psm->goal == PSM_PKGERASE) {
02789 
02790             psm->scriptTag = RPMTAG_POSTUN;
02791             psm->progTag = RPMTAG_POSTUNPROG;
02792             psm->sense = RPMSENSE_TRIGGERPOSTUN;
02793             psm->countCorrection = -1;
02794 
02795             if (!(rpmtsFlags(ts) & RPMTRANS_FLAG_NOPOSTUN)) {
02796                 rc = rpmpsmNext(psm, PSM_SCRIPT);
02797                 if(rc && !non_pre_scripts_dont_fail) break;
02798             }
02799 
02800             if (!(rpmtsFlags(ts) & RPMTRANS_FLAG_NOTRIGGERPOSTUN)) {
02801                 /* Run triggers in other package(s) this package sets off. */
02802                 rc = rpmpsmNext(psm, PSM_TRIGGERS);
02803                 if(rc && !non_pre_scripts_dont_fail) break;
02804 
02805                 /* Run triggers in this package other package(s) set off. */
02806                 rc = rpmpsmNext(psm, PSM_IMMED_TRIGGERS);
02807                 if(rc && !non_pre_scripts_dont_fail) break;
02808             }
02809 
02810             if (!(rpmtsFlags(ts) & RPMTRANS_FLAG_APPLYONLY))
02811                 rc = rpmpsmNext(psm, PSM_RPMDB_REMOVE);
02812         }
02813         if (psm->goal == PSM_PKGSAVE) {
02814         }
02815 
02816         /* Restore root directory if changed. */
02817         xx = rpmpsmNext(psm, PSM_CHROOT_OUT);
02818         break;
02819     case PSM_UNDO:
02820         break;
02821     case PSM_FINI:
02822         /* Restore root directory if changed. */
02823         xx = rpmpsmNext(psm, PSM_CHROOT_OUT);
02824 
02825         if (psm->fd != NULL) {
02826             saveerrno = errno; /* XXX FIXME: Fclose with libio destroys errno */
02827             xx = Fclose(psm->fd);
02828             psm->fd = NULL;
02829             /*@-mods@*/
02830             errno = saveerrno;
02831             /*@=mods@*/
02832         }
02833 
02834         if (psm->goal == PSM_PKGSAVE) {
02835             if (!rc && ts && ts->notify == NULL) {
02836                 rpmlog(RPMLOG_INFO, _("Wrote: %s\n"),
02837                         (psm->pkgURL ? psm->pkgURL : "???"));
02838             }
02839         }
02840 
02841         if (rc) {
02842             const char * msg = iosmStrerror(rc);
02843             if (psm->failedFile)
02844                 rpmlog(RPMLOG_ERR,
02845                         _("%s failed on file %s: %s\n"),
02846                         psm->stepName, psm->failedFile, msg);
02847             else
02848                 rpmlog(RPMLOG_ERR, _("%s failed: %s\n"),
02849                         psm->stepName, msg);
02850             msg = _free(msg);
02851 
02852             /* XXX notify callback on error. */
02853             psm->what = RPMCALLBACK_CPIO_ERROR;
02854             psm->amount = 0;
02855             psm->total = 0;
02856             /*@-nullstate@*/ /* FIX: psm->fd may be NULL. */
02857             xx = rpmpsmNext(psm, PSM_NOTIFY);
02858             /*@=nullstate@*/
02859             if (psm->te->txn != NULL) {
02860                 xx = rpmtxnAbort(psm->te->txn);
02861                 psm->te->txn = NULL;
02862             }
02863         } else {
02864             if (psm->te->txn != NULL) {
02865                 xx = rpmtxnCommit(psm->te->txn);
02866                 psm->te->txn = NULL;
02867             }
02868         }
02869 
02870         if (psm->goal == PSM_PKGERASE || psm->goal == PSM_PKGSAVE) {
02871             if (psm->te != NULL)
02872                 (void) rpmteSetHeader(psm->te, NULL);
02873             if (fi->h != NULL) {
02874                 (void)headerFree(fi->h);
02875                 fi->h = NULL;
02876             }
02877         }
02878         (void)headerFree(psm->oh);
02879         psm->oh = NULL;
02880         psm->pkgURL = _free(psm->pkgURL);
02881         psm->rpmio_flags = _free(psm->rpmio_flags);
02882         psm->payload_format = _free(psm->payload_format);
02883         psm->failedFile = _free(psm->failedFile);
02884 
02885         fi->fgroup = _free(fi->fgroup);
02886         fi->fuser = _free(fi->fuser);
02887         fi->apath = _free(fi->apath);
02888         fi->fstates = _free(fi->fstates);
02889         break;
02890 
02891     case PSM_PKGINSTALL:
02892     case PSM_PKGERASE:
02893     case PSM_PKGSAVE:
02894         psm->goal = stage;
02895         psm->rc = RPMRC_OK;
02896         psm->stepName = pkgStageString(stage);
02897 
02898         rc = rpmpsmNext(psm, PSM_INIT);
02899         if (!rc) rc = rpmpsmNext(psm, PSM_PRE);
02900         if (!rc) rc = rpmpsmNext(psm, PSM_PROCESS);
02901         if (!rc) rc = rpmpsmNext(psm, PSM_POST);
02902         xx = rpmpsmNext(psm, PSM_FINI);
02903         break;
02904     case PSM_PKGCOMMIT:
02905         break;
02906 
02907     case PSM_CREATE:
02908         break;
02909     case PSM_NOTIFY:
02910     {   void * ptr;
02911 /*@-nullpass@*/ /* FIX: psm->te may be NULL */
02912         ptr = rpmtsNotify(ts, psm->te, psm->what, psm->amount, psm->total);
02913 /*@-nullpass@*/
02914     }   break;
02915     case PSM_DESTROY:
02916         break;
02917     case PSM_COMMIT:
02918         if (!(rpmtsFlags(ts) & RPMTRANS_FLAG_PKGCOMMIT)) break;
02919         if (rpmtsFlags(ts) & RPMTRANS_FLAG_APPLYONLY) break;
02920 
02921         rc = fsmSetup(fi->fsm, IOSM_PKGCOMMIT, psm->payload_format, ts, fi,
02922                         NULL, NULL, &psm->failedFile);
02923         xx = fsmTeardown(fi->fsm);
02924         break;
02925 
02926     case PSM_CHROOT_IN:
02927     {   const char * rootDir = rpmtsRootDir(ts);
02928         /* Change root directory if requested and not already done. */
02929         if (rootDir != NULL && !(rootDir[0] == '/' && rootDir[1] == '\0')
02930          && !rpmtsChrootDone(ts) && !F_ISSET(psm, CHROOTDONE))
02931         {
02932             static int _pw_loaded = 0;
02933             static int _gr_loaded = 0;
02934 
02935             if (!_pw_loaded) {
02936                 (void)getpwnam("root");
02937                 endpwent();
02938                 _pw_loaded++;
02939             }
02940             if (!_gr_loaded) {
02941                 (void)getgrnam("root");
02942                 endgrent();
02943                 _gr_loaded++;
02944             }
02945 
02946             xx = Chdir("/");
02947             /*@-modobserver@*/
02948             if (rootDir != NULL && strcmp(rootDir, "/") && *rootDir == '/')
02949                 rc = Chroot(rootDir);
02950             /*@=modobserver@*/
02951             F_SET(psm, CHROOTDONE);
02952             (void) rpmtsSetChrootDone(ts, 1);
02953         }
02954     }   break;
02955     case PSM_CHROOT_OUT:
02956         /* Restore root directory if changed. */
02957         if (F_ISSET(psm, CHROOTDONE)) {
02958             const char * rootDir = rpmtsRootDir(ts);
02959             const char * currDir = rpmtsCurrDir(ts);
02960             /*@-modobserver@*/
02961             if (rootDir != NULL && strcmp(rootDir, "/") && *rootDir == '/')
02962                 rc = Chroot(".");
02963             /*@=modobserver@*/
02964             F_CLR(psm, CHROOTDONE);
02965             (void) rpmtsSetChrootDone(ts, 0);
02966             if (currDir != NULL)        /* XXX can't happen */
02967                 xx = Chdir(currDir);
02968         }
02969         break;
02970     case PSM_SCRIPT:    /* Run current package scriptlets. */
02971         /* XXX running %verifyscript/%sanitycheck doesn't have psm->te */
02972     {   rpmtxn _parent = (psm && psm->te ? psm->te->txn : NULL);
02973         xx = rpmtxnBegin(rpmtsGetRdb(ts), _parent, NULL);
02974         rc = runInstScript(psm);
02975         if (rc)
02976              xx = rpmtxnAbort(rpmtsGetRdb(ts)->db_txn);
02977         else
02978              xx = rpmtxnCommit(rpmtsGetRdb(ts)->db_txn);
02979         rpmtsGetRdb(ts)->db_txn = NULL;
02980     }   break;
02981     case PSM_TRIGGERS:
02982         /* Run triggers in other package(s) this package sets off. */
02983         if (rpmtsFlags(ts) & RPMTRANS_FLAG_TEST)        break;
02984         rc = runTriggers(psm);
02985         break;
02986     case PSM_IMMED_TRIGGERS:
02987         /* Run triggers in this package other package(s) set off. */
02988         if (rpmtsFlags(ts) & RPMTRANS_FLAG_TEST)        break;
02989         if (!F_ISSET(psm, GOTTRIGGERS)) {
02990             psm->triggers = rpmdsNew(fi->h, RPMTAG_TRIGGERNAME, 0);
02991             F_SET(psm, GOTTRIGGERS);
02992         }
02993         if (psm->triggers != NULL)
02994             rc = runImmedTriggers(psm);
02995         break;
02996 
02997     case PSM_RPMIO_FLAGS:
02998     {   const char * payload_compressor = NULL;
02999         const char * payload_format = NULL;
03000         char * t;
03001 
03002         he->tag = RPMTAG_PAYLOADCOMPRESSOR;
03003         xx = headerGet(fi->h, he, 0);
03004         payload_compressor = he->p.str;
03005         if (payload_compressor == NULL)
03006             payload_compressor = xstrdup("gzip");
03007 
03008         psm->rpmio_flags = t = xmalloc(sizeof("w9.gzdio"));
03009         *t = '\0';
03010         t = stpcpy(t, ((psm->goal == PSM_PKGSAVE) ? "w9" : "r"));
03011         if (!strcmp(payload_compressor, "gzip"))
03012             t = stpcpy(t, ".gzdio");
03013         if (!strcmp(payload_compressor, "bzip2"))
03014             t = stpcpy(t, ".bzdio");
03015         if (!strcmp(payload_compressor, "lzma"))
03016             t = stpcpy(t, ".lzdio");
03017         if (!strcmp(payload_compressor, "xz"))
03018             t = stpcpy(t, ".xzdio");
03019         payload_compressor = _free(payload_compressor);
03020 
03021         he->tag = RPMTAG_PAYLOADFORMAT;
03022         xx = headerGet(fi->h, he, 0);
03023         payload_format = he->p.str;
03024         if (!xx || payload_format == NULL || !(
03025           !strcmp(payload_format, "tar") || !strcmp(payload_format, "ustar")
03026 #if defined(SUPPORT_AR_PAYLOADS)
03027          || !strcmp(payload_format, "ar")
03028 #endif
03029            ))
03030         {
03031             payload_format = _free(payload_format);
03032             payload_format = xstrdup("cpio");
03033         }
03034         psm->payload_format = _free(psm->payload_format);
03035         psm->payload_format = payload_format;
03036         rc = RPMRC_OK;
03037     }   break;
03038 
03039     case PSM_RPMDB_LOAD:
03040 assert(psm->mi == NULL);
03041         psm->mi = rpmtsInitIterator(ts, RPMDBI_PACKAGES,
03042                                 &fi->record, sizeof(fi->record));
03043         fi->h = rpmmiNext(psm->mi);
03044 /*@-castexpose@*/
03045         if (fi->h != NULL)
03046             fi->h = headerLink(fi->h);
03047 /*@=castexpose@*/
03048         psm->mi = rpmmiFree(psm->mi);
03049 
03050         if (fi->h != NULL) {
03051             (void) headerSetInstance(fi->h, fi->record);
03052             rc = RPMRC_OK;
03053         } else
03054             rc = RPMRC_FAIL;
03055         break;
03056     case PSM_RPMDB_ADD:
03057         if (rpmtsFlags(ts) & RPMTRANS_FLAG_TEST)        break;
03058         if (rpmtsFlags(ts) & RPMTRANS_FLAG_NORPMDB)     break;
03059         if (fi->isSource)       break;  /* XXX never add SRPM's */
03060         if (fi->h == NULL)      break;  /* XXX can't happen */
03061 
03062         xx = rpmtxnBegin(rpmtsGetRdb(ts), psm->te->txn, NULL);
03063 
03064         /* Add header to db, doing header check if requested */
03065         /* XXX rollback headers propagate the previous transaction id. */
03066         {   rpmuint32_t tid = ((rpmtsType(ts) == RPMTRANS_TYPE_ROLLBACK)
03067                 ? hLoadTID(fi->h, RPMTAG_INSTALLTID) : rpmtsGetTid(ts));
03068             (void) rpmswEnter(rpmtsOp(ts, RPMTS_OP_DBADD), 0);
03069             if (!(rpmtsVSFlags(ts) & RPMVSF_NOHDRCHK))
03070                 rc = rpmdbAdd(rpmtsGetRdb(ts), tid, fi->h, ts);
03071             else
03072                 rc = rpmdbAdd(rpmtsGetRdb(ts), tid, fi->h, NULL);
03073             (void) rpmswExit(rpmtsOp(ts, RPMTS_OP_DBADD), 0);
03074 #if defined(HAVE_SYSLOG) && defined(RPM_VENDOR_MANDRIVA) /* log-install-remove-to-syslog */
03075             {
03076                 char *s, *fmt;
03077                 fmt = rpmExpand("%{___NVRA}", NULL);
03078                 s = headerSprintf(fi->h, fmt,
03079                         rpmTagTable, rpmHeaderFormats, NULL);
03080                 syslog(LOG_NOTICE, "[RPM] %s installed\n", s);
03081                 fmt = _free(fmt);
03082                 s = _free(s);
03083             }
03084 #endif
03085         }
03086 
03087         if (rc != RPMRC_OK) {
03088             xx = rpmtxnAbort(rpmtsGetRdb(ts)->db_txn);
03089             rpmtsGetRdb(ts)->db_txn = NULL;
03090             break;
03091         } else
03092             xx = rpmtxnCommit(rpmtsGetRdb(ts)->db_txn);
03093         rpmtsGetRdb(ts)->db_txn = NULL;
03094 
03095 assert(psm->te != NULL);
03096         /* Mark non-rollback elements as installed. */
03097         if (rpmtsType(ts) != RPMTRANS_TYPE_ROLLBACK)
03098             psm->te->installed = 1;
03099 
03100         /* Set the database instance for (possible) rollbacks. */
03101         rpmteSetDBInstance(psm->te, headerGetInstance(fi->h));
03102 
03103         break;
03104     case PSM_RPMDB_REMOVE:
03105     {   
03106         if (rpmtsFlags(ts) & RPMTRANS_FLAG_TEST)        break;
03107         if (rpmtsFlags(ts) & RPMTRANS_FLAG_NORPMDB)     break;
03108 
03109         xx = rpmtxnBegin(rpmtsGetRdb(ts), psm->te->txn, NULL);
03110 
03111         (void) rpmswEnter(rpmtsOp(ts, RPMTS_OP_DBREMOVE), 0);
03112         rc = rpmdbRemove(rpmtsGetRdb(ts), rpmtsGetTid(ts), fi->record, NULL);
03113         (void) rpmswExit(rpmtsOp(ts, RPMTS_OP_DBREMOVE), 0);
03114 #if defined(HAVE_SYSLOG) && defined(RPM_VENDOR_MANDRIVA) /* log-install-remove-to-syslog */
03115         {
03116             char *s, *fmt;
03117             fmt = rpmExpand("%{___NVRA}", NULL);
03118             s = headerSprintf(fi->h, fmt,
03119                     rpmTagTable, rpmHeaderFormats, NULL);
03120             syslog(LOG_NOTICE, "[RPM] %s removed\n", s);
03121             fmt = _free(fmt);
03122             s = _free(s);
03123         }
03124 #endif
03125 
03126         if (rc != RPMRC_OK) {
03127             xx = rpmtxnAbort(rpmtsGetRdb(ts)->db_txn);
03128             rpmtsGetRdb(ts)->db_txn = NULL;
03129             break;
03130         } else
03131             xx = rpmtxnCommit(rpmtsGetRdb(ts)->db_txn);
03132         rpmtsGetRdb(ts)->db_txn = NULL;
03133 
03134         /* Forget the offset of a successfully removed header. */
03135         if (psm->te != NULL)    /* XXX can't happen */
03136             psm->te->u.removed.dboffset = 0;
03137 
03138     }   break;
03139 
03140     default:
03141         break;
03142 /*@i@*/    }
03143 
03144 /*@-nullstate@*/        /* FIX: psm->oh and psm->fi->h may be NULL. */
03145     return rc;
03146 /*@=nullstate@*/
03147 }
03148 /*@=nullpass@*/