rpm 5.3.12
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 #if defined(RPM_VENDOR_MANDRIVA)
01629                 continue;
01630 #else
01631             tagno = (N[strlen(N)-1] == '/')
01632                         ? RPMTAG_DIRNAMES : RPMTAG_FILEPATHS;
01633 #endif
01634         }
01635         /* XXX For now, permit globs only in unversioned triggers. */
01636         if ((EVR == NULL || *EVR == '\0') && Glob_pattern_p(N, 0))
01637             xx = rpmdbMireApply(rpmtsGetRdb(ts), tagno, RPMMIRE_GLOB, N, &keys);
01638         else
01639             xx = argvAdd(&keys, N);
01640     }
01641     (void)rpmdsFree(triggers);
01642     triggers = NULL;
01643 
01644     /* For all primary keys, retrieve headers and fire triggers. */
01645     if (keys != NULL)
01646     for (i = 0; (Name = keys[i]) != NULL; i++) {
01647         unsigned prev, instance;
01648         unsigned nvals;
01649         ARGint_t vals;
01650 
01651         /* If not limited to NEVRA triggers, use file/dir index. */
01652         if (tagno != RPMTAG_NAME) {
01653             /* XXX if trigger name ends with '/', use dirnames instead. */
01654             if (Name[0] == '/') 
01655                 tagno = (Name[strlen(Name)-1] == '/')
01656                         ? RPMTAG_DIRNAMES : RPMTAG_FILEPATHS;
01657         }
01658 
01659         mi = rpmtsInitIterator(ts, tagno, Name, 0);
01660 
01661         /* Don't retrieve headers that have already been processed. */
01662         nvals = argiCount(instances);
01663         vals = argiData(instances);
01664         if (nvals > 0)
01665             xx = rpmmiPrune(mi, (uint32_t *)vals, nvals, 1);
01666 
01667         prev = 0;
01668         while((sourceH = rpmmiNext(mi)) != NULL) {
01669 
01670             /* Skip headers that have already been processed. */
01671             instance = rpmmiInstance(mi);
01672             if (prev == instance)
01673                 /*@innercontinue@*/ continue;
01674 
01675             rc |= handleOneTrigger(psm, sourceH, fi->h, rpmmiCount(mi));
01676 
01677             /* Mark header instance as processed. */
01678             prev = instance;
01679             xx = argiAdd(&instances, -1, instance);
01680             xx = argiSort(instances, NULL);
01681         }
01682 
01683         mi = rpmmiFree(mi);
01684     }
01685 
01686 exit:
01687     instances = argiFree(instances);
01688     keys = argvFree(keys);
01689     Ihe->p.ptr = _free(Ihe->p.ptr);
01690     return rc;
01691 }
01692 
01693 /*@observer@*/
01694 static const char * pkgStageString(pkgStage a)
01695         /*@*/
01696 {
01697     switch(a) {
01698     case PSM_UNKNOWN:           return "unknown";
01699 
01700     case PSM_PKGINSTALL:        return "  install";
01701     case PSM_PKGERASE:          return "    erase";
01702     case PSM_PKGCOMMIT:         return "   commit";
01703     case PSM_PKGSAVE:           return "repackage";
01704 
01705     case PSM_INIT:              return "init";
01706     case PSM_PRE:               return "pre";
01707     case PSM_PROCESS:           return "process";
01708     case PSM_POST:              return "post";
01709     case PSM_UNDO:              return "undo";
01710     case PSM_FINI:              return "fini";
01711 
01712     case PSM_CREATE:            return "create";
01713     case PSM_NOTIFY:            return "notify";
01714     case PSM_DESTROY:           return "destroy";
01715     case PSM_COMMIT:            return "commit";
01716 
01717     case PSM_CHROOT_IN:         return "chrootin";
01718     case PSM_CHROOT_OUT:        return "chrootout";
01719     case PSM_SCRIPT:            return "script";
01720     case PSM_TRIGGERS:          return "triggers";
01721     case PSM_IMMED_TRIGGERS:    return "immedtriggers";
01722 
01723     case PSM_RPMIO_FLAGS:       return "rpmioflags";
01724 
01725     case PSM_RPMDB_LOAD:        return "rpmdbload";
01726     case PSM_RPMDB_ADD:         return "rpmdbadd";
01727     case PSM_RPMDB_REMOVE:      return "rpmdbremove";
01728 
01729     default:                    return "???";
01730     }
01731     /*@noteached@*/
01732 }
01733 
01734 void rpmpsmSetAsync(rpmpsm psm, int async)
01735 {
01736     assert(psm != NULL);
01737 #ifdef  REFERENCE
01738     psm->unorderedSuccessor = async;
01739 #else
01740     if (async)
01741         psm->flags |= RPMPSM_FLAGS_UNORDERED;
01742     else
01743         psm->flags &= ~RPMPSM_FLAGS_UNORDERED;
01744 #endif
01745 }
01746 
01747 rpmRC rpmpsmScriptStage(rpmpsm psm, rpmTag scriptTag, rpmTag progTag)
01748 {
01749 assert(psm != NULL);
01750     psm->scriptTag = scriptTag;
01751     psm->progTag = progTag;
01752     /* XXX other tags needed? */
01753     switch (scriptTag) {
01754     default:    break;
01755     case RPMTAG_SANITYCHECK:    psm->stepName = "sanitycheck";  break;
01756     case RPMTAG_VERIFYSCRIPT:   psm->stepName = "verify";       break;
01757     case RPMTAG_PRETRANS:       psm->stepName = "pretrans";     break;
01758     case RPMTAG_POSTTRANS:      psm->stepName = "posttrans";    break;
01759     }
01760     return rpmpsmStage(psm, PSM_SCRIPT);
01761 }
01762 
01763 /*@-mustmod@*/
01764 static void rpmpsmFini(void * _psm)
01765         /*@modifies _psm @*/
01766 {
01767     rpmpsm psm = _psm;
01768 
01769 /*@-nullstate@*/
01770     psm->fi = rpmfiFree(psm->fi);
01771 #ifdef  NOTYET
01772     psm->te = rpmteFree(psm->te);
01773 #else
01774     psm->te = NULL;
01775 #endif
01776 /*@-internalglobs@*/
01777     (void)rpmtsFree(psm->ts); 
01778     psm->ts = NULL;
01779 /*@=internalglobs@*/
01780 
01781     psm->IPhe->p.ptr = _free(psm->IPhe->p.ptr);
01782     psm->IPhe = _free(psm->IPhe);
01783     psm->NVRA = _free(psm->NVRA);
01784     (void)rpmdsFree(psm->triggers);
01785     psm->triggers = NULL;
01786 /*@=nullstate@*/
01787 }
01788 /*@=mustmod@*/
01789 
01790 /*@unchecked@*/ /*@only@*/ /*@null@*/
01791 rpmioPool _psmPool;
01792 
01793 static rpmpsm rpmpsmGetPool(/*@null@*/ rpmioPool pool)
01794         /*@globals _psmPool, fileSystem, internalState @*/
01795         /*@modifies pool, _psmPool, fileSystem, internalState @*/
01796 {
01797     rpmpsm psm;
01798 
01799     if (_psmPool == NULL) {
01800         _psmPool = rpmioNewPool("psm", sizeof(*psm), -1, _psm_debug,
01801                         NULL, NULL, rpmpsmFini);
01802         pool = _psmPool;
01803     }
01804     psm = (rpmpsm) rpmioGetPool(pool, sizeof(*psm));
01805     memset(((char *)psm)+sizeof(psm->_item), 0, sizeof(*psm)-sizeof(psm->_item));
01806     return psm;
01807 }
01808 
01809 rpmpsm rpmpsmNew(rpmts ts, rpmte te, rpmfi fi)
01810 {
01811     static const char msg[] = "rpmpsmNew";
01812     rpmpsm psm = rpmpsmGetPool(_psmPool);
01813 
01814 /*@-assignexpose -castexpose @*/
01815     if (ts)     psm->ts = rpmtsLink(ts, msg);
01816 #ifdef  NOTYET
01817     if (te)     psm->te = rpmteLink(te, msg);
01818 #else
01819 /*@-temptrans @*/
01820     if (te)     psm->te = te;
01821 /*@=temptrans @*/
01822 #endif
01823     if (fi)     psm->fi = rpmfiLink(fi, msg);
01824 /*@=assignexpose =castexpose @*/
01825 
01826     psm->triggers = NULL;
01827     psm->NVRA = NULL;
01828     psm->IPhe = xcalloc(1, sizeof(*psm->IPhe));
01829     memset(psm->sstates, 0, sizeof(psm->sstates));
01830     memset(psm->smetrics, 0, sizeof(psm->smetrics));
01831 
01832     return rpmpsmLink(psm, msg);
01833 }
01834 
01841 static rpmuint32_t hLoadTID(Header h, rpmTag tag)
01842         /*@globals internalState @*/
01843         /*@modifies internalState @*/
01844 {
01845     HE_t he = memset(alloca(sizeof(*he)), 0, sizeof(*he));
01846     rpmuint32_t val;
01847     int xx;
01848 
01849     he->tag = tag;
01850     xx = headerGet(h, he, 0);
01851     val = (xx && he->p.ui32p ? he->p.ui32p[0] : 0);
01852     he->p.ptr = _free(he->p.ptr);
01853     return val;
01854 }
01855 
01863 static int hCopyTag(Header sh, Header th, rpmTag tag)
01864         /*@globals internalState @*/
01865         /*@modifies th, internalState @*/
01866 {
01867     HE_t he = memset(alloca(sizeof(*he)), 0, sizeof(*he));
01868     int xx = 1;
01869 
01870     he->tag = tag;
01871     if (headerGet(sh, he, 0) && he->c > 0)
01872         xx = headerPut(th, he, 0);
01873     he->p.ptr = _free(he->p.ptr);
01874     return 0;
01875 }
01876 
01883 static int hSaveBlinks(Header h, const struct rpmChainLink_s * blink)
01884         /*@modifies h @*/
01885 {
01886     HE_t he = memset(alloca(sizeof(*he)), 0, sizeof(*he));
01887 /*@observer@*/
01888     static const char * chain_end = RPMTE_CHAIN_END;
01889     int ac;
01890     int xx = 1;
01891 
01892     /* Save forward links into header upgrade chain. */
01893     he->tag = RPMTAG_BLINKNEVRA;
01894     he->t = RPM_STRING_ARRAY_TYPE;
01895     ac = argvCount(blink->NEVRA);
01896     if (ac > 0) {
01897         he->p.argv = argvData(blink->NEVRA);
01898         he->c = ac;
01899     } else {    /* XXX Add an explicit chain terminator on 1st install. */
01900         he->p.argv = &chain_end;
01901         he->c = 1;
01902     }
01903     xx = headerPut(h, he, 0);
01904     
01905     he->tag = RPMTAG_BLINKPKGID;
01906     he->t = RPM_STRING_ARRAY_TYPE;
01907     ac = argvCount(blink->Pkgid);
01908     if (ac > 0) {
01909         he->p.argv = argvData(blink->Pkgid);
01910         he->c = ac;
01911     } else {    /* XXX Add an explicit chain terminator on 1st install. */
01912         he->p.argv = &chain_end;
01913         he->c = 1;
01914     }
01915     xx = headerPut(h, he, 0);
01916 
01917     he->tag = RPMTAG_BLINKHDRID;
01918     he->t = RPM_STRING_ARRAY_TYPE;
01919     ac = argvCount(blink->Hdrid);
01920     if (ac > 0) {
01921         he->p.argv = argvData(blink->Hdrid);
01922         he->c = ac;
01923     } else {    /* XXX Add an explicit chain terminator on 1st install. */
01924         he->p.argv = &chain_end;
01925         he->c = 1;
01926     }
01927     xx = headerPut(h, he, 0);
01928 
01929     return 0;
01930 }
01931 
01938 static int hSaveFlinks(Header h, const struct rpmChainLink_s * flink)
01939         /*@modifies h @*/
01940 {
01941     HE_t he = memset(alloca(sizeof(*he)), 0, sizeof(*he));
01942 #ifdef  NOTYET
01943     /*@observer@*/
01944     static const char * chain_end = RPMTE_CHAIN_END;
01945 #endif
01946     int ac;
01947     int xx = 1;
01948 
01949     /* Save forward links into header upgrade chain. */
01950     he->tag = RPMTAG_FLINKNEVRA;
01951     he->t = RPM_STRING_ARRAY_TYPE;
01952     ac = argvCount(flink->NEVRA);
01953     if (ac > 0) {
01954         he->p.argv = argvData(flink->NEVRA);
01955         he->c = ac;
01956     }
01957 #ifdef  NOTYET  /* XXX is an explicit flink terminator needed? */
01958     else {      /* XXX Add an explicit chain terminator on 1st install. */
01959         he->p.argv = &chain_end;
01960         he->c = 1;
01961     }
01962 #endif
01963     xx = headerPut(h, he, 0);
01964 
01965     he->tag = RPMTAG_FLINKPKGID;
01966     he->t = RPM_STRING_ARRAY_TYPE;
01967     ac = argvCount(flink->Pkgid);
01968     if (ac > 0) {
01969         he->p.argv = argvData(flink->Pkgid);
01970         he->c = ac;
01971     }
01972 #ifdef  NOTYET  /* XXX is an explicit flink terminator needed? */
01973     else {      /* XXX Add an explicit chain terminator on 1st install. */
01974         he->p.argv = &chain_end;
01975         he->c = 1;
01976     }
01977 #endif
01978     xx = headerPut(h, he, 0);
01979 
01980     he->tag = RPMTAG_FLINKHDRID;
01981     he->t = RPM_STRING_ARRAY_TYPE;
01982     ac = argvCount(flink->Hdrid);
01983     if (ac > 0) {
01984         he->p.argv = argvData(flink->Hdrid);
01985         he->c = ac;
01986     }
01987 #ifdef  NOTYET  /* XXX is an explicit flink terminator needed? */
01988     else {      /* XXX Add an explicit chain terminator on 1st install. */
01989         he->p.argv = &chain_end;
01990         he->c = 1;
01991     }
01992 #endif
01993     xx = headerPut(h, he, 0);
01994 
01995     return 0;
01996 }
01997 
02005 static int populateInstallHeader(const rpmts ts, const rpmte te, rpmfi fi)
02006         /*@globals h_errno, fileSystem, internalState @*/
02007         /*@modifies fi, fileSystem, internalState @*/
02008 {
02009     HE_t he = memset(alloca(sizeof(*he)), 0, sizeof(*he));
02010     rpmuint32_t tscolor = rpmtsColor(ts);
02011     rpmuint32_t tecolor = rpmteColor(te);
02012     rpmuint32_t * uip;
02013     rpmuint32_t installTime[2];
02014     rpmuint32_t originTime[2];
02015     rpmuint32_t originTid[2];
02016     int xx = 1;
02017 
02018 assert(fi->h != NULL);
02019 
02020     {   struct timeval tv;
02021         xx = gettimeofday(&tv, NULL);
02022         installTime[0] = (rpmuint32_t) tv.tv_sec;
02023         installTime[1] = (rpmuint32_t) tv.tv_usec;
02024     }
02025     he->tag = RPMTAG_INSTALLTIME;
02026     he->t = RPM_UINT32_TYPE;
02027     he->p.ui32p = &installTime[0];
02028     he->c = 2;
02029     xx = headerPut(fi->h, he, 0);
02030 
02031     /* Propagate the tid & time that the package was first installed. */
02032     if ((uip = rpmteOriginTime(te)) != NULL)
02033         memcpy(originTime, uip, sizeof(originTime));
02034     if (originTime[0] == 0)
02035         memcpy(originTime, installTime, sizeof(originTime));
02036     he->tag = RPMTAG_ORIGINTIME;
02037     he->t = RPM_UINT32_TYPE;
02038     he->p.ui32p = originTime;
02039     he->c = 2;
02040     xx = headerPut(fi->h, he, 0);
02041 
02042     if ((uip = rpmteOriginTid(te)) != NULL)
02043         memcpy(originTid, uip, sizeof(originTid));
02044     if (originTid[0] == 0)
02045         memcpy(originTid, ts->tid, sizeof(originTid));
02046     he->tag = RPMTAG_ORIGINTID;
02047     he->t = RPM_UINT32_TYPE;
02048     he->p.ui32p = originTid;
02049     he->c = 2;
02050     xx = headerPut(fi->h, he, 0);
02051 
02052     he->tag = RPMTAG_INSTALLCOLOR;
02053     he->t = RPM_UINT32_TYPE;
02054     he->p.ui32p = &tscolor;
02055     he->c = 1;
02056     xx = headerPut(fi->h, he, 0);
02057 
02058     /* XXX FIXME: add preferred color at install. */
02059 
02060     he->tag = RPMTAG_PACKAGECOLOR;
02061     he->t = RPM_UINT32_TYPE;
02062     he->p.ui32p = &tecolor;
02063     he->c = 1;
02064     xx = headerPut(fi->h, he, 0);
02065 
02066     /* Add the header's origin/digest/stat (i.e. URL) */
02067     {   const char * fn = headerGetOrigin(fi->h);
02068         const char * digest = headerGetDigest(fi->h);
02069         struct stat * st = headerGetStatbuf(fi->h);
02070 
02071         if (fn != NULL) {
02072             he->tag = RPMTAG_PACKAGEORIGIN;
02073             he->t = RPM_STRING_TYPE;
02074             he->p.str = xstrdup(fn);
02075             he->c = 1;
02076             xx = headerPut(fi->h, he, 0);
02077             he->p.ptr = _free(he->p.ptr);
02078 
02079             if (digest != NULL) {
02080                 he->tag = RPMTAG_PACKAGEDIGEST;
02081                 he->t = RPM_STRING_TYPE;
02082                 he->p.str = headerGetDigest(fi->h);
02083                 he->c = 1;
02084                 xx = headerPut(fi->h, he, 0);
02085             }
02086             if (st != NULL) {
02087 /* XXX Fstat(2) in pkgio.c should set *st. Verify st->st_mode w assert(3). */
02088 #ifndef DYING
02089                 int ut = urlPath(fn, NULL);
02090                 /* XXX URI is active, so avoid the lazy Stat(2) for now. */
02091                 if (!(ut == URL_IS_HTTP || ut == URL_IS_HTTPS))
02092                 if (st->st_mode == 0 && st->st_mtime == 0 && st->st_size == 0)
02093                     xx = Stat(fn, st);
02094 #endif
02095                 if (st->st_mode != 0) {
02096                     he->tag = RPMTAG_PACKAGESTAT;
02097                     he->t = RPM_BIN_TYPE;
02098                     he->p.ptr = (void *)st;
02099                     he->c = (rpmTagCount) sizeof(*st);
02100                     xx = headerPut(fi->h, he, 0);
02101                 }
02102             }
02103         }
02104     }
02105 
02106     /* XXX Don't clobber forward/backward upgrade chain on rollbacks */
02107     if (rpmtsType(ts) != RPMTRANS_TYPE_ROLLBACK)
02108         xx = hSaveBlinks(fi->h, &te->blink);
02109 
02110     return 0;
02111 }
02112 
02120 static int postPopulateInstallHeader(/*@unused@*/ const rpmts ts,
02121                 const rpmpsm psm, rpmfi fi)
02122         /*@modifies psm, fi @*/
02123 {
02124     HE_t he = memset(alloca(sizeof(*he)), 0, sizeof(*he));
02125     int fc = rpmfiFC(fi);
02126     int xx = 1;
02127 
02128     /* Add the (install) scriptlet status/metrics. */
02129     he->tag = RPMTAG_SCRIPTSTATES;
02130     he->t = RPM_UINT32_TYPE;
02131     he->p.ui32p = psm->sstates;
02132     he->c = RPMSCRIPT_MAX;
02133     xx = headerPut(fi->h, he, 0);
02134     he->tag = RPMTAG_SCRIPTMETRICS;
02135     he->t = RPM_UINT32_TYPE;
02136     he->p.ui32p = psm->smetrics;
02137     he->c = RPMSCRIPT_MAX;
02138     xx = headerPut(fi->h, he, 0);
02139 
02140     /* Add file states to install header. */
02141     if (fi->fstates != NULL && fc > 0) {
02142         he->tag = RPMTAG_FILESTATES;
02143         he->t = RPM_UINT8_TYPE;
02144         he->p.ui8p = fi->fstates;
02145         he->c = fc;
02146         xx = headerPut(fi->h, he, 0);
02147     }
02148 
02149     return 0;
02150 }
02151 
02152 #if defined(WITH_PTHREADS)
02153 static void * rpmpsmThread(void * arg)
02154         /*@globals rpmGlobalMacroContext, h_errno, fileSystem, internalState @*/
02155         /*@modifies arg, rpmGlobalMacroContext, fileSystem, internalState @*/
02156 {
02157     rpmpsm psm = arg;
02158 /*@-unqualifiedtrans@*/
02159     return ((void *) rpmpsmStage(psm, psm->nstage));
02160 /*@=unqualifiedtrans@*/
02161 }
02162 #endif
02163 
02164 static int rpmpsmNext(rpmpsm psm, pkgStage nstage)
02165         /*@globals rpmGlobalMacroContext, h_errno, fileSystem, internalState @*/
02166         /*@modifies psm, rpmGlobalMacroContext, fileSystem, internalState @*/
02167 {
02168     psm->nstage = nstage;
02169 #if defined(WITH_PTHREADS)
02170     if (_psm_threads)
02171         return rpmsqJoin( rpmsqThread(rpmpsmThread, psm) );
02172 #endif
02173     return rpmpsmStage(psm, psm->nstage);
02174 }
02175 
02180 /*@-nullpass@*/ /* FIX: testing null annotation for fi->h */
02181 rpmRC rpmpsmStage(rpmpsm psm, pkgStage stage)
02182 {
02183     HE_t he = memset(alloca(sizeof(*he)), 0, sizeof(*he));
02184     const rpmts ts = psm->ts;
02185     rpmuint32_t tscolor = rpmtsColor(ts);
02186     rpmfi fi = psm->fi;
02187     rpmRC rc = psm->rc;
02188     int saveerrno;
02189     int xx;
02190     int non_pre_scripts_dont_fail = 0;
02191 #if defined(RPM_VENDOR_MANDRIVA)
02192     non_pre_scripts_dont_fail = rpmExpandNumeric("%{?_legacy_compat_non_pre_scripts_dont_fail}");
02193 #endif
02194 
02195 /* XXX hackery to assert(!scareMem) in rpmfiNew. */
02196 /*@-castexpose@*/
02197 if (fi->h == NULL && fi->te && ((rpmte)fi->te)->h != NULL) fi->h = headerLink(((rpmte)fi->te)->h);
02198 /*@=castexpose@*/
02199 
02200     switch (stage) {
02201     case PSM_UNKNOWN:
02202         break;
02203     case PSM_INIT:
02204         rpmlog(RPMLOG_DEBUG, D_("%s: %s has %d files, test = %d\n"),
02205                 psm->stepName, rpmteNEVR(psm->te),
02206                 rpmfiFC(fi), (rpmtsFlags(ts) & RPMTRANS_FLAG_TEST));
02207 
02208         /*
02209          * When we run scripts, we pass an argument which is the number of
02210          * versions of this package that will be installed when we are
02211          * finished.
02212          */
02213         psm->npkgs_installed = rpmdbCountPackages(rpmtsGetRdb(ts), rpmteN(psm->te));
02214         if (psm->npkgs_installed < 0) {
02215             rc = RPMRC_FAIL;
02216             break;
02217         }
02218 
02219         /* Adjust package count on rollback downgrade. */
02220 assert(psm->te != NULL);
02221         if (rpmtsType(ts) == RPMTRANS_TYPE_AUTOROLLBACK &&
02222             (psm->goal & ~(PSM_PKGSAVE|PSM_PKGERASE)))
02223         {
02224             if (psm->te->downgrade)
02225                 psm->npkgs_installed--;
02226         }
02227 
02228         if (psm->goal == PSM_PKGINSTALL) {
02229             int fc = rpmfiFC(fi);
02230             const char * hdrid;
02231 
02232             /* Add per-transaction data to install header. */
02233             xx = populateInstallHeader(ts, psm->te, fi);
02234 
02235             psm->scriptArg = psm->npkgs_installed + 1;
02236 
02237 assert(psm->mi == NULL);
02238             hdrid = rpmteHdrid(psm->te);
02239             if (hdrid != NULL) {
02240                 /* XXX should use RPMTAG_HDRID not RPMTAG_SHA1HEADER */
02241                 psm->mi = rpmtsInitIterator(ts, RPMTAG_SHA1HEADER, hdrid, 0);
02242             } else {
02243                 psm->mi = rpmtsInitIterator(ts, RPMTAG_NAME, rpmteN(psm->te),0);
02244                 xx = rpmmiAddPattern(psm->mi, RPMTAG_EPOCH, RPMMIRE_STRCMP,
02245                         rpmteE(psm->te));
02246                 xx = rpmmiAddPattern(psm->mi, RPMTAG_VERSION, RPMMIRE_STRCMP,
02247                         rpmteV(psm->te));
02248                 xx = rpmmiAddPattern(psm->mi, RPMTAG_RELEASE, RPMMIRE_STRCMP,
02249                         rpmteR(psm->te));
02250 #ifdef  RPM_VENDOR_MANDRIVA
02251                 xx = rpmmiAddPattern(psm->mi, RPMTAG_DISTEPOCH, RPMMIRE_STRCMP,
02252                         rpmteD(psm->te));
02253 #endif
02254                 if (tscolor) {
02255                     xx = rpmmiAddPattern(psm->mi,RPMTAG_ARCH, RPMMIRE_STRCMP,
02256                         rpmteA(psm->te));
02257                     xx = rpmmiAddPattern(psm->mi, RPMTAG_OS, RPMMIRE_STRCMP,
02258                         rpmteO(psm->te));
02259                 }
02260             }
02261 
02262             while ((psm->oh = rpmmiNext(psm->mi)) != NULL) {
02263                 fi->record = rpmmiInstance(psm->mi);
02264                 psm->oh = NULL;
02265                 /*@loopbreak@*/ break;
02266             }
02267             psm->mi = rpmmiFree(psm->mi);
02268 
02269             rc = RPMRC_OK;
02270 
02271             /* XXX lazy alloc here may need to be done elsewhere. */
02272             if (fi->fstates == NULL && fc > 0) {
02273                 fi->fstates = xmalloc(sizeof(*fi->fstates) * fc);
02274                 memset(fi->fstates, RPMFILE_STATE_NORMAL, fc);
02275             }
02276 
02277             xx = rpmtxnBegin(rpmtsGetRdb(ts), ts->txn, &psm->te->txn);
02278 
02279             if (rpmtsFlags(ts) & RPMTRANS_FLAG_JUSTDB)  break;
02280             if (fc <= 0)                                break;
02281         
02282             /*
02283              * Old format relocatable packages need the entire default
02284              * prefix stripped to form the cpio list, while all other packages
02285              * need the leading / stripped.
02286              */
02287             he->tag = RPMTAG_DEFAULTPREFIX;
02288             xx = headerGet(fi->h, he, 0);
02289             fi->striplen = (xx && he->p.str ? strlen(he->p.str) + 1 : 1);
02290             he->p.ptr = _free(he->p.ptr);
02291             fi->mapflags =
02292                 IOSM_MAP_PATH | IOSM_MAP_MODE | IOSM_MAP_UID | IOSM_MAP_GID | (fi->mapflags & IOSM_SBIT_CHECK);
02293         
02294             if (headerIsEntry(fi->h, RPMTAG_ORIGBASENAMES))
02295                 he->tag = RPMTAG_ORIGPATHS;
02296             else
02297                 he->tag = RPMTAG_FILEPATHS;
02298             xx = headerGet(fi->h, he, 0);
02299 assert(he->p.argv != NULL);
02300             fi->apath = he->p.argv;
02301         
02302             if (fi->fuser == NULL) {
02303                 he->tag = RPMTAG_FILEUSERNAME;
02304                 xx = headerGet(fi->h, he, 0);
02305                 fi->fuser = he->p.argv;
02306             }
02307             if (fi->fgroup == NULL) {
02308                 he->tag = RPMTAG_FILEGROUPNAME;
02309                 xx = headerGet(fi->h, he, 0);
02310                 fi->fgroup = he->p.argv;
02311             }
02312             rc = RPMRC_OK;
02313         }
02314         if (psm->goal == PSM_PKGERASE || psm->goal == PSM_PKGSAVE) {
02315             psm->scriptArg = psm->npkgs_installed - 1;
02316         
02317             /* XXX FIXME: PSM_PKGSAVE needs to be transactionally protected. */
02318             if (psm->goal == PSM_PKGERASE)
02319                 xx = rpmtxnBegin(rpmtsGetRdb(ts), ts->txn, &psm->te->txn);
02320 
02321             /* Retrieve installed header. */
02322             rc = rpmpsmNext(psm, PSM_RPMDB_LOAD);
02323             if (rc == RPMRC_OK && psm->te)
02324                 (void) rpmteSetHeader(psm->te, fi->h);
02325         }
02326         if (psm->goal == PSM_PKGSAVE) {
02327             /* Open output package for writing. */
02328             {   char tiddn[32];
02329                 const char * bfmt;
02330                 const char * pkgdn;
02331                 const char * pkgbn;
02332                 char * pkgdn_buf;
02333 
02334                 xx = snprintf(tiddn, sizeof(tiddn), "%d", rpmtsGetTid(ts));
02335                 bfmt = rpmGetPath(tiddn, "/", "%{_repackage_name_fmt}", NULL);
02336                 pkgbn = headerSprintf(fi->h, bfmt,
02337                                         NULL, rpmHeaderFormats, NULL);
02338                 bfmt = _free(bfmt);
02339                 psm->pkgURL = rpmGenPath("%{?_repackage_root}",
02340                                          "%{?_repackage_dir}",
02341                                         pkgbn);
02342                 pkgbn = _free(pkgbn);
02343                 (void) urlPath(psm->pkgURL, &psm->pkgfn);
02344                 pkgdn_buf = xstrdup(psm->pkgfn);
02345 /*@-moduncon@*/
02346                 pkgdn = dirname(pkgdn_buf);
02347 /*@=moduncon@*/
02348                 rc = rpmMkdirPath(pkgdn, "_repackage_dir");
02349                 pkgdn_buf = _free(pkgdn_buf);
02350                 if (rc == RPMRC_FAIL)
02351                     break;
02352                 psm->fd = Fopen(psm->pkgfn, "w.fdio");
02353                 if (psm->fd == NULL || Ferror(psm->fd)) {
02354                     rc = RPMRC_FAIL;
02355                     break;
02356                 }
02357             }
02358         }
02359         break;
02360     case PSM_PRE:
02361         if (rpmtsFlags(ts) & RPMTRANS_FLAG_TEST)        break;
02362 
02363 /* XXX insure that trigger index is opened before entering chroot. */
02364 #ifdef  NOTYET
02365  { static int oneshot = 0;
02366    dbiIndex dbi;
02367    if (!oneshot) {
02368      dbi = dbiOpen(rpmtsGetRdb(ts), RPMTAG_TRIGGERNAME, 0);
02369      oneshot++;
02370    }
02371  }
02372 #endif
02373 
02374         /* Change root directory if requested and not already done. */
02375         rc = rpmpsmNext(psm, PSM_CHROOT_IN);
02376 
02377         if (psm->goal == PSM_PKGINSTALL) {
02378             psm->scriptTag = RPMTAG_PREIN;
02379             psm->progTag = RPMTAG_PREINPROG;
02380             psm->sense = RPMSENSE_TRIGGERPREIN;
02381             psm->countCorrection = 0;   /* XXX is this correct?!? */
02382 
02383             if (!(rpmtsFlags(ts) & RPMTRANS_FLAG_NOTRIGGERPREIN)) {
02384 
02385                 /* Run triggers in other package(s) this package sets off. */
02386                 rc = rpmpsmNext(psm, PSM_TRIGGERS);
02387                 if (rc) break;
02388 
02389                 /* Run triggers in this package other package(s) set off. */
02390                 rc = rpmpsmNext(psm, PSM_IMMED_TRIGGERS);
02391                 if (rc) break;
02392             }
02393 
02394             if (!(rpmtsFlags(ts) & RPMTRANS_FLAG_NOPRE)) {
02395                 rc = rpmpsmNext(psm, PSM_SCRIPT);
02396                 if (rc != RPMRC_OK) {
02397                     rpmlog(RPMLOG_ERR,
02398                         _("%s: %s scriptlet failed (%d), skipping %s\n"),
02399                         psm->stepName, tag2sln(psm->scriptTag), rc,
02400                         rpmteNEVR(psm->te));
02401                     break;
02402                 }
02403             }
02404         }
02405 
02406         if (psm->goal == PSM_PKGERASE) {
02407             psm->scriptTag = RPMTAG_PREUN;
02408             psm->progTag = RPMTAG_PREUNPROG;
02409             psm->sense = RPMSENSE_TRIGGERUN;
02410             psm->countCorrection = -1;
02411 
02412             if (!(rpmtsFlags(ts) & RPMTRANS_FLAG_NOTRIGGERUN)) {
02413                 /* Run triggers in this package other package(s) set off. */
02414                 rc = rpmpsmNext(psm, PSM_IMMED_TRIGGERS);
02415                 if(rc && !non_pre_scripts_dont_fail) break;
02416 
02417                 /* Run triggers in other package(s) this package sets off. */
02418                 rc = rpmpsmNext(psm, PSM_TRIGGERS);
02419                 if(rc && !non_pre_scripts_dont_fail) break;
02420             }
02421 
02422             if (!(rpmtsFlags(ts) & RPMTRANS_FLAG_NOPREUN))
02423                 rc = rpmpsmNext(psm, PSM_SCRIPT);
02424         }
02425         if (psm->goal == PSM_PKGSAVE) {
02426             int noArchiveSize = 0;
02427             const char * origin = NULL;
02428             const char * digest = NULL;
02429             const struct stat * st = NULL;
02430             size_t nstbytes = 0;
02431 
02432             /* Regenerate original header. */
02433             {   void * uh = NULL;
02434 
02435                 /* Save original header's origin/digest/stat (i.e. URL) */
02436                 he->tag = RPMTAG_PACKAGEORIGIN;
02437                 xx = headerGet(fi->h, he, 0);
02438                 origin = he->p.str;
02439                 he->tag = RPMTAG_PACKAGEDIGEST;
02440                 xx = headerGet(fi->h, he, 0);
02441                 if (xx && he->p.str != NULL)
02442                     digest = he->p.str;
02443                 he->tag = RPMTAG_PACKAGESTAT;
02444                 xx = headerGet(fi->h, he, 0);
02445                 if (xx && he->p.ptr != NULL && (size_t)he->c == sizeof(*st)) {
02446                     st = he->p.ptr;
02447                     nstbytes = he->c;
02448                 }
02449 
02450                 /* Retrieve original header blob. */
02451                 he->tag = RPMTAG_HEADERIMMUTABLE;
02452                 xx = headerGet(fi->h, he, 0);
02453                 uh = he->p.ptr;
02454                 if (xx && uh != NULL) {
02455                     psm->oh = headerCopyLoad(uh);
02456                     uh = _free(uh);
02457                 } else {
02458                     he->tag = RPMTAG_HEADERIMAGE;
02459                     xx = headerGet(fi->h, he, 0);
02460                     uh = he->p.ptr;
02461                     if (xx && uh != NULL) {
02462                         HeaderIterator hi;
02463                         Header oh;
02464 
02465                         /* Load the original header from the blob. */
02466                         oh = headerCopyLoad(uh);
02467 
02468                         /* XXX this is headerCopy w/o headerReload() */
02469                         psm->oh = headerNew();
02470 
02471                         for (hi = headerInit(oh);
02472                              headerNext(hi, he, 0);
02473                              he->p.ptr = _free(he->p.ptr))
02474                         {
02475                             if (he->tag == RPMTAG_ARCHIVESIZE)
02476                                 noArchiveSize = 1;
02477                             xx = headerPut(psm->oh, he, 0);
02478                         }
02479                         hi = headerFini(hi);
02480 
02481                         (void)headerFree(oh);
02482                         oh = NULL;
02483                         uh = _free(uh);
02484                     } else
02485                         break;  /* XXX shouldn't ever happen */
02486                 }
02487             }
02488 
02489             /* Retrieve type of payload compression. */
02490             /*@-nullstate@*/    /* FIX: psm->oh may be NULL */
02491             rc = rpmpsmNext(psm, PSM_RPMIO_FLAGS);
02492             /*@=nullstate@*/
02493 
02494             /* Write the lead section into the package. */
02495             {   static const char item[] = "Lead";
02496                 const char * NEVR = rpmteNEVR(psm->te);
02497                 size_t nb = rpmpkgSizeof(item, NULL);
02498         
02499                 if (nb == 0)
02500                     rc = RPMRC_FAIL;
02501                 else {
02502                     void * l = alloca(nb);
02503                     memset(l, 0, nb);
02504                     rc = rpmpkgWrite(item, psm->fd, l, &NEVR);
02505                 }
02506                 if (rc != RPMRC_OK) {
02507                     rpmlog(RPMLOG_ERR, _("Unable to write package: %s\n"),
02508                                 Fstrerror(psm->fd));
02509                     break;
02510                 }
02511             }
02512 
02513             /* Write the signature section into the package. */
02514             /* XXX rpm-4.1 and later has archive size in signature header. */
02515             {   static const char item[] = "Signature";
02516                 Header sigh = headerRegenSigHeader(fi->h, noArchiveSize);
02517                 /* Reallocate the signature into one contiguous region. */
02518                 sigh = headerReload(sigh, RPMTAG_HEADERSIGNATURES);
02519                 if (sigh == NULL) {
02520                     rpmlog(RPMLOG_ERR, _("Unable to reload signature header\n"));
02521                     rc = RPMRC_FAIL;
02522                     break;
02523                 }
02524                 rc = rpmpkgWrite(item, psm->fd, sigh, NULL);
02525                 (void)headerFree(sigh);
02526                 sigh = NULL;
02527                 if (rc != RPMRC_OK) {
02528                     break;
02529                 }
02530             }
02531 
02532             /* Add remove transaction id to header. */
02533             if (psm->oh != NULL)
02534             {   rpmuint32_t tid = rpmtsGetTid(ts);
02535 
02536                 he->tag = RPMTAG_REMOVETID;
02537                 he->t = RPM_UINT32_TYPE;
02538                 he->p.ui32p = &tid;
02539                 he->c = 1;
02540                 xx = headerPut(psm->oh, he, 0);
02541 
02542                 /* Add original header's origin/digest/stat (i.e. URL) */
02543                 if (origin != NULL) {
02544                     he->tag = RPMTAG_PACKAGEORIGIN;
02545                     he->t = RPM_STRING_TYPE;
02546                     he->p.str = origin;
02547                     he->c = 1;
02548                     xx = headerPut(psm->oh, he, 0);
02549                     origin = _free(origin);
02550                 }
02551                 if (digest != NULL) {
02552                     he->tag = RPMTAG_PACKAGEDIGEST;
02553                     he->t = RPM_STRING_TYPE;
02554                     he->p.str = digest;
02555                     he->c = 1;
02556                     xx = headerPut(psm->oh, he, 0);
02557                     digest = _free(digest);
02558                 }
02559                 if (st != NULL) {
02560                     he->tag = RPMTAG_PACKAGESTAT;
02561                     he->t = RPM_BIN_TYPE;
02562                     he->p.ptr = (void *)st;
02563                     he->c = (rpmTagCount)nstbytes;
02564                     xx = headerPut(psm->oh, he, 0);
02565                     st = _free(st);
02566                 }
02567 
02568                 /* Copy upgrade chain link tags. */
02569                 xx = hCopyTag(fi->h, psm->oh, RPMTAG_INSTALLTID);
02570                 xx = hCopyTag(fi->h, psm->oh, RPMTAG_BLINKPKGID);
02571                 xx = hCopyTag(fi->h, psm->oh, RPMTAG_BLINKHDRID);
02572                 xx = hCopyTag(fi->h, psm->oh, RPMTAG_BLINKNEVRA);
02573 
02574 assert(psm->te != NULL);
02575                 xx = hSaveFlinks(psm->oh, &psm->te->flink);
02576             }
02577 
02578             /* Write the metadata section into the package. */
02579             {   const char item[] = "Header";
02580                 const char * msg = NULL;
02581                 rc = rpmpkgWrite(item, psm->fd, psm->oh, &msg);
02582                 if (rc != RPMRC_OK) {
02583                     rpmlog(RPMLOG_ERR, "%s: %s: %s", psm->pkgfn, item,
02584                         (msg && *msg ? msg : "write failed\n"));
02585                     msg = _free(msg);
02586                 }
02587             }
02588         }
02589         break;
02590     case PSM_PROCESS:
02591         if (rpmtsFlags(ts) & RPMTRANS_FLAG_TEST)        break;
02592 
02593         if (psm->goal == PSM_PKGINSTALL) {
02594 
02595             if (rpmtsFlags(ts) & RPMTRANS_FLAG_JUSTDB)  break;
02596 
02597             /* XXX Synthesize callbacks for packages with no files. */
02598             if (rpmfiFC(fi) <= 0) {
02599                 void * ptr;
02600                 ptr = rpmtsNotify(ts, fi->te, RPMCALLBACK_INST_START, 0, 100);
02601                 ptr = rpmtsNotify(ts, fi->te, RPMCALLBACK_INST_PROGRESS, 100, 100);
02602                 break;
02603             }
02604 
02605             /* Retrieve type of payload compression. */
02606             rc = rpmpsmNext(psm, PSM_RPMIO_FLAGS);
02607 
02608             if (rpmteFd(fi->te) == NULL) {      /* XXX can't happen */
02609                 rc = RPMRC_FAIL;
02610                 break;
02611             }
02612 
02613             /*@-nullpass@*/     /* LCL: fi->fd != NULL here. */
02614             psm->cfd = Fdopen(fdDup(Fileno(rpmteFd(fi->te))), psm->rpmio_flags);
02615             /*@=nullpass@*/
02616             if (psm->cfd == NULL) {     /* XXX can't happen */
02617                 rc = RPMRC_FAIL;
02618                 break;
02619             }
02620 
02621             xx = rpmtxnBegin(rpmtsGetRdb(ts), psm->te->txn, NULL);
02622 
02623             rc = fsmSetup(fi->fsm, IOSM_PKGINSTALL, psm->payload_format, ts, fi,
02624                         psm->cfd, NULL, &psm->failedFile);
02625             (void) rpmswAdd(rpmtsOp(ts, RPMTS_OP_UNCOMPRESS),
02626                         fdstat_op(psm->cfd, FDSTAT_READ));
02627             (void) rpmswAdd(rpmtsOp(ts, RPMTS_OP_DIGEST),
02628                         fdstat_op(psm->cfd, FDSTAT_DIGEST));
02629             xx = fsmTeardown(fi->fsm);
02630 
02631             saveerrno = errno; /* XXX FIXME: Fclose with libio destroys errno */
02632             xx = Fclose(psm->cfd);
02633             psm->cfd = NULL;
02634             /*@-mods@*/
02635             errno = saveerrno; /* XXX FIXME: Fclose with libio destroys errno */
02636             /*@=mods@*/
02637 
02638             if (!rc)
02639                 rc = rpmpsmNext(psm, PSM_COMMIT);
02640 
02641             /* Commit/abort the SRPM install transaction. */
02642             /* XXX move into the PSM package state machine w PSM_COMMIT */
02643         {   rpmdb db = rpmtsGetRdb(ts);
02644             rpmtxn _txn = (db ? db->db_txn : NULL);
02645             if (_txn != NULL) {
02646                 if (rc)
02647                     xx = rpmtxnAbort(_txn);
02648                 else
02649                     xx = rpmtxnCommit(_txn);
02650                 db->db_txn = NULL;
02651             }
02652         }
02653 
02654             /* XXX make sure progress is closed out */
02655             psm->what = RPMCALLBACK_INST_PROGRESS;
02656             psm->amount = (fi->archiveSize ? fi->archiveSize : 100);
02657             psm->total = psm->amount;
02658             xx = rpmpsmNext(psm, PSM_NOTIFY);
02659 
02660             if (rc) {
02661                 const char * msg = iosmStrerror(rc);
02662                 rpmlog(RPMLOG_ERR,
02663                         _("unpacking of archive failed%s%s: %s\n"),
02664                         (psm->failedFile != NULL ? _(" on file ") : ""),
02665                         (psm->failedFile != NULL ? psm->failedFile : ""),
02666                         msg);
02667                 msg = _free(msg);
02668                 rc = RPMRC_FAIL;
02669 
02670                 /* XXX notify callback on error. */
02671                 psm->what = RPMCALLBACK_UNPACK_ERROR;
02672                 psm->amount = 0;
02673                 psm->total = 0;
02674                 xx = rpmpsmNext(psm, PSM_NOTIFY);
02675 
02676                 break;
02677             }
02678         }
02679         if (psm->goal == PSM_PKGERASE) {
02680             int fc = rpmfiFC(fi);
02681 
02682             if (rpmtsFlags(ts) & RPMTRANS_FLAG_JUSTDB)  break;
02683             if (rpmtsFlags(ts) & RPMTRANS_FLAG_APPLYONLY)       break;
02684 
02685             psm->what = RPMCALLBACK_UNINST_START;
02686             psm->amount = fc;
02687             psm->total = (fc ? fc : 100);
02688             xx = rpmpsmNext(psm, PSM_NOTIFY);
02689 
02690             if (fc > 0) {
02691                 rc = fsmSetup(fi->fsm, IOSM_PKGERASE, psm->payload_format, ts, fi,
02692                         NULL, NULL, &psm->failedFile);
02693                 xx = fsmTeardown(fi->fsm);
02694             }
02695 
02696             psm->what = RPMCALLBACK_UNINST_STOP;
02697             psm->amount = (fc ? fc : 100);
02698             psm->total = (fc ? fc : 100);
02699             xx = rpmpsmNext(psm, PSM_NOTIFY);
02700 
02701         }
02702         if (psm->goal == PSM_PKGSAVE) {
02703             iosmFileAction * actions = (iosmFileAction *) fi->actions;
02704             iosmFileAction action = (iosmFileAction) fi->action;
02705 
02706             fi->action = FA_COPYOUT;
02707             fi->actions = NULL;
02708 
02709             if (psm->fd == NULL) {      /* XXX can't happen */
02710                 rc = RPMRC_FAIL;
02711                 break;
02712             }
02713             /*@-nullpass@*/     /* FIX: fdDup mey return NULL. */
02714             xx = Fflush(psm->fd);
02715             psm->cfd = Fdopen(fdDup(Fileno(psm->fd)), psm->rpmio_flags);
02716             /*@=nullpass@*/
02717             if (psm->cfd == NULL) {     /* XXX can't happen */
02718                 rc = RPMRC_FAIL;
02719                 break;
02720             }
02721 
02722             rc = fsmSetup(fi->fsm, IOSM_PKGBUILD, psm->payload_format, ts, fi,
02723                         psm->cfd, NULL, &psm->failedFile);
02724             (void) rpmswAdd(rpmtsOp(ts, RPMTS_OP_COMPRESS),
02725                         fdstat_op(psm->cfd, FDSTAT_WRITE));
02726             (void) rpmswAdd(rpmtsOp(ts, RPMTS_OP_DIGEST),
02727                         fdstat_op(psm->cfd, FDSTAT_DIGEST));
02728             xx = fsmTeardown(fi->fsm);
02729 
02730             saveerrno = errno; /* XXX FIXME: Fclose with libio destroys errno */
02731             xx = Fclose(psm->cfd);
02732             psm->cfd = NULL;
02733             /*@-mods@*/
02734             errno = saveerrno;
02735             /*@=mods@*/
02736 
02737             /* XXX make sure progress is closed out */
02738             psm->what = RPMCALLBACK_INST_PROGRESS;
02739             psm->amount = (fi->archiveSize ? fi->archiveSize : 100);
02740             psm->total = psm->amount;
02741             xx = rpmpsmNext(psm, PSM_NOTIFY);
02742 
02743             fi->action = (int) action;
02744             fi->actions = (int *) actions;
02745         }
02746         break;
02747     case PSM_POST:
02748         if (rpmtsFlags(ts) & RPMTRANS_FLAG_TEST)        break;
02749 
02750         if (psm->goal == PSM_PKGINSTALL) {
02751 
02752             psm->scriptTag = RPMTAG_POSTIN;
02753             psm->progTag = RPMTAG_POSTINPROG;
02754             psm->sense = RPMSENSE_TRIGGERIN;
02755             psm->countCorrection = 0;
02756 
02757             if (!(rpmtsFlags(ts) & RPMTRANS_FLAG_NOPOST)) {
02758                 rc = rpmpsmNext(psm, PSM_SCRIPT);
02759                 if(rc && !non_pre_scripts_dont_fail) break;
02760             }
02761             if (!(rpmtsFlags(ts) & RPMTRANS_FLAG_NOTRIGGERIN)) {
02762                 /* Run triggers in other package(s) this package sets off. */
02763                 rc = rpmpsmNext(psm, PSM_TRIGGERS);
02764                 if(rc && !non_pre_scripts_dont_fail) break;
02765 
02766                 /* Run triggers in this package other package(s) set off. */
02767                 rc = rpmpsmNext(psm, PSM_IMMED_TRIGGERS);
02768                 if(rc && !non_pre_scripts_dont_fail) break;
02769             }
02770 
02771             /*
02772              * If this header has already been installed, remove it from
02773              * the database before adding the new header.
02774              */
02775             if (fi->record && !(rpmtsFlags(ts) & RPMTRANS_FLAG_APPLYONLY)) {
02776                 rc = rpmpsmNext(psm, PSM_RPMDB_REMOVE);
02777                 if (rc) break;
02778             }
02779 
02780             /* Add scriptlet/file states to install header. */
02781             xx = postPopulateInstallHeader(ts, psm, fi);
02782 
02783             rc = rpmpsmNext(psm, PSM_RPMDB_ADD);
02784             if (rc) break;
02785 
02786 #ifdef  DYING
02787             if (!(rpmtsFlags(ts) & RPMTRANS_FLAG_APPLYONLY))
02788                 rc = markReplacedFiles(psm);
02789 #endif
02790 
02791         }
02792         if (psm->goal == PSM_PKGERASE) {
02793 
02794             psm->scriptTag = RPMTAG_POSTUN;
02795             psm->progTag = RPMTAG_POSTUNPROG;
02796             psm->sense = RPMSENSE_TRIGGERPOSTUN;
02797             psm->countCorrection = -1;
02798 
02799             if (!(rpmtsFlags(ts) & RPMTRANS_FLAG_NOPOSTUN)) {
02800                 rc = rpmpsmNext(psm, PSM_SCRIPT);
02801                 if(rc && !non_pre_scripts_dont_fail) break;
02802             }
02803 
02804             if (!(rpmtsFlags(ts) & RPMTRANS_FLAG_NOTRIGGERPOSTUN)) {
02805                 /* Run triggers in other package(s) this package sets off. */
02806                 rc = rpmpsmNext(psm, PSM_TRIGGERS);
02807                 if(rc && !non_pre_scripts_dont_fail) break;
02808 
02809                 /* Run triggers in this package other package(s) set off. */
02810                 rc = rpmpsmNext(psm, PSM_IMMED_TRIGGERS);
02811                 if(rc && !non_pre_scripts_dont_fail) break;
02812             }
02813 
02814             if (!(rpmtsFlags(ts) & RPMTRANS_FLAG_APPLYONLY))
02815                 rc = rpmpsmNext(psm, PSM_RPMDB_REMOVE);
02816         }
02817         if (psm->goal == PSM_PKGSAVE) {
02818         }
02819 
02820         /* Restore root directory if changed. */
02821         xx = rpmpsmNext(psm, PSM_CHROOT_OUT);
02822         break;
02823     case PSM_UNDO:
02824         break;
02825     case PSM_FINI:
02826         /* Restore root directory if changed. */
02827         xx = rpmpsmNext(psm, PSM_CHROOT_OUT);
02828 
02829         if (psm->fd != NULL) {
02830             saveerrno = errno; /* XXX FIXME: Fclose with libio destroys errno */
02831             xx = Fclose(psm->fd);
02832             psm->fd = NULL;
02833             /*@-mods@*/
02834             errno = saveerrno;
02835             /*@=mods@*/
02836         }
02837 
02838         if (psm->goal == PSM_PKGSAVE) {
02839             if (!rc && ts && ts->notify == NULL) {
02840                 rpmlog(RPMLOG_INFO, _("Wrote: %s\n"),
02841                         (psm->pkgURL ? psm->pkgURL : "???"));
02842             }
02843         }
02844 
02845         if (rc) {
02846             const char * msg = iosmStrerror(rc);
02847             if (psm->failedFile)
02848                 rpmlog(RPMLOG_ERR,
02849                         _("%s failed on file %s: %s\n"),
02850                         psm->stepName, psm->failedFile, msg);
02851             else
02852                 rpmlog(RPMLOG_ERR, _("%s failed: %s\n"),
02853                         psm->stepName, msg);
02854             msg = _free(msg);
02855 
02856             /* XXX notify callback on error. */
02857             psm->what = RPMCALLBACK_CPIO_ERROR;
02858             psm->amount = 0;
02859             psm->total = 0;
02860             /*@-nullstate@*/ /* FIX: psm->fd may be NULL. */
02861             xx = rpmpsmNext(psm, PSM_NOTIFY);
02862             /*@=nullstate@*/
02863             if (psm->te->txn != NULL) {
02864                 xx = rpmtxnAbort(psm->te->txn);
02865                 psm->te->txn = NULL;
02866             }
02867         } else {
02868             if (psm->te->txn != NULL) {
02869                 xx = rpmtxnCommit(psm->te->txn);
02870                 psm->te->txn = NULL;
02871             }
02872         }
02873 
02874         if (psm->goal == PSM_PKGERASE || psm->goal == PSM_PKGSAVE) {
02875             if (psm->te != NULL)
02876                 (void) rpmteSetHeader(psm->te, NULL);
02877             if (fi->h != NULL) {
02878                 (void)headerFree(fi->h);
02879                 fi->h = NULL;
02880             }
02881         }
02882         (void)headerFree(psm->oh);
02883         psm->oh = NULL;
02884         psm->pkgURL = _free(psm->pkgURL);
02885         psm->rpmio_flags = _free(psm->rpmio_flags);
02886         psm->payload_format = _free(psm->payload_format);
02887         psm->failedFile = _free(psm->failedFile);
02888 
02889         fi->fgroup = _free(fi->fgroup);
02890         fi->fuser = _free(fi->fuser);
02891         fi->apath = _free(fi->apath);
02892         fi->fstates = _free(fi->fstates);
02893         break;
02894 
02895     case PSM_PKGINSTALL:
02896     case PSM_PKGERASE:
02897     case PSM_PKGSAVE:
02898         psm->goal = stage;
02899         psm->rc = RPMRC_OK;
02900         psm->stepName = pkgStageString(stage);
02901 
02902         rc = rpmpsmNext(psm, PSM_INIT);
02903         if (!rc) rc = rpmpsmNext(psm, PSM_PRE);
02904         if (!rc) rc = rpmpsmNext(psm, PSM_PROCESS);
02905         if (!rc) rc = rpmpsmNext(psm, PSM_POST);
02906         xx = rpmpsmNext(psm, PSM_FINI);
02907         break;
02908     case PSM_PKGCOMMIT:
02909         break;
02910 
02911     case PSM_CREATE:
02912         break;
02913     case PSM_NOTIFY:
02914     {   void * ptr;
02915 /*@-nullpass@*/ /* FIX: psm->te may be NULL */
02916         ptr = rpmtsNotify(ts, psm->te, psm->what, psm->amount, psm->total);
02917 /*@-nullpass@*/
02918     }   break;
02919     case PSM_DESTROY:
02920         break;
02921     case PSM_COMMIT:
02922         if (!(rpmtsFlags(ts) & RPMTRANS_FLAG_PKGCOMMIT)) break;
02923         if (rpmtsFlags(ts) & RPMTRANS_FLAG_APPLYONLY) break;
02924 
02925         rc = fsmSetup(fi->fsm, IOSM_PKGCOMMIT, psm->payload_format, ts, fi,
02926                         NULL, NULL, &psm->failedFile);
02927         xx = fsmTeardown(fi->fsm);
02928         break;
02929 
02930     case PSM_CHROOT_IN:
02931     {   const char * rootDir = rpmtsRootDir(ts);
02932         /* Change root directory if requested and not already done. */
02933         if (rootDir != NULL && !(rootDir[0] == '/' && rootDir[1] == '\0')
02934          && !rpmtsChrootDone(ts) && !F_ISSET(psm, CHROOTDONE))
02935         {
02936             static int _pw_loaded = 0;
02937             static int _gr_loaded = 0;
02938 
02939             if (!_pw_loaded) {
02940                 (void)getpwnam("root");
02941                 endpwent();
02942                 _pw_loaded++;
02943             }
02944             if (!_gr_loaded) {
02945                 (void)getgrnam("root");
02946                 endgrent();
02947                 _gr_loaded++;
02948             }
02949 
02950             xx = Chdir("/");
02951             /*@-modobserver@*/
02952             if (rootDir != NULL && strcmp(rootDir, "/") && *rootDir == '/')
02953                 rc = Chroot(rootDir);
02954             /*@=modobserver@*/
02955             F_SET(psm, CHROOTDONE);
02956             (void) rpmtsSetChrootDone(ts, 1);
02957         }
02958     }   break;
02959     case PSM_CHROOT_OUT:
02960         /* Restore root directory if changed. */
02961         if (F_ISSET(psm, CHROOTDONE)) {
02962             const char * rootDir = rpmtsRootDir(ts);
02963             const char * currDir = rpmtsCurrDir(ts);
02964             /*@-modobserver@*/
02965             if (rootDir != NULL && strcmp(rootDir, "/") && *rootDir == '/')
02966                 rc = Chroot(".");
02967             /*@=modobserver@*/
02968             F_CLR(psm, CHROOTDONE);
02969             (void) rpmtsSetChrootDone(ts, 0);
02970             if (currDir != NULL)        /* XXX can't happen */
02971                 xx = Chdir(currDir);
02972         }
02973         break;
02974     case PSM_SCRIPT:    /* Run current package scriptlets. */
02975         /* XXX running %verifyscript/%sanitycheck doesn't have psm->te */
02976     {   rpmtxn _parent = (psm && psm->te ? psm->te->txn : NULL);
02977         xx = rpmtxnBegin(rpmtsGetRdb(ts), _parent, NULL);
02978         rc = runInstScript(psm);
02979         if (rc)
02980              xx = rpmtxnAbort(rpmtsGetRdb(ts)->db_txn);
02981         else
02982              xx = rpmtxnCommit(rpmtsGetRdb(ts)->db_txn);
02983         rpmtsGetRdb(ts)->db_txn = NULL;
02984     }   break;
02985     case PSM_TRIGGERS:
02986         /* Run triggers in other package(s) this package sets off. */
02987         if (rpmtsFlags(ts) & RPMTRANS_FLAG_TEST)        break;
02988         rc = runTriggers(psm);
02989         break;
02990     case PSM_IMMED_TRIGGERS:
02991         /* Run triggers in this package other package(s) set off. */
02992         if (rpmtsFlags(ts) & RPMTRANS_FLAG_TEST)        break;
02993         if (!F_ISSET(psm, GOTTRIGGERS)) {
02994             psm->triggers = rpmdsNew(fi->h, RPMTAG_TRIGGERNAME, 0);
02995             F_SET(psm, GOTTRIGGERS);
02996         }
02997         if (psm->triggers != NULL)
02998             rc = runImmedTriggers(psm);
02999         break;
03000 
03001     case PSM_RPMIO_FLAGS:
03002     {   const char * payload_compressor = NULL;
03003         const char * payload_format = NULL;
03004         char * t;
03005 
03006         he->tag = RPMTAG_PAYLOADCOMPRESSOR;
03007         xx = headerGet(fi->h, he, 0);
03008         payload_compressor = he->p.str;
03009         if (payload_compressor == NULL)
03010             payload_compressor = xstrdup("gzip");
03011 
03012         psm->rpmio_flags = t = xmalloc(sizeof("w9.gzdio"));
03013         *t = '\0';
03014         t = stpcpy(t, ((psm->goal == PSM_PKGSAVE) ? "w9" : "r"));
03015         if (!strcmp(payload_compressor, "gzip"))
03016             t = stpcpy(t, ".gzdio");
03017         if (!strcmp(payload_compressor, "bzip2"))
03018             t = stpcpy(t, ".bzdio");
03019         if (!strcmp(payload_compressor, "lzma"))
03020             t = stpcpy(t, ".lzdio");
03021         if (!strcmp(payload_compressor, "xz"))
03022             t = stpcpy(t, ".xzdio");
03023         payload_compressor = _free(payload_compressor);
03024 
03025         he->tag = RPMTAG_PAYLOADFORMAT;
03026         xx = headerGet(fi->h, he, 0);
03027         payload_format = he->p.str;
03028         if (!xx || payload_format == NULL || !(
03029           !strcmp(payload_format, "tar") || !strcmp(payload_format, "ustar")
03030 #if defined(SUPPORT_AR_PAYLOADS)
03031          || !strcmp(payload_format, "ar")
03032 #endif
03033            ))
03034         {
03035             payload_format = _free(payload_format);
03036             payload_format = xstrdup("cpio");
03037         }
03038         psm->payload_format = _free(psm->payload_format);
03039         psm->payload_format = payload_format;
03040         rc = RPMRC_OK;
03041     }   break;
03042 
03043     case PSM_RPMDB_LOAD:
03044 assert(psm->mi == NULL);
03045         psm->mi = rpmtsInitIterator(ts, RPMDBI_PACKAGES,
03046                                 &fi->record, sizeof(fi->record));
03047         fi->h = rpmmiNext(psm->mi);
03048 /*@-castexpose@*/
03049         if (fi->h != NULL)
03050             fi->h = headerLink(fi->h);
03051 /*@=castexpose@*/
03052         psm->mi = rpmmiFree(psm->mi);
03053 
03054         if (fi->h != NULL) {
03055             (void) headerSetInstance(fi->h, fi->record);
03056             rc = RPMRC_OK;
03057         } else
03058             rc = RPMRC_FAIL;
03059         break;
03060     case PSM_RPMDB_ADD:
03061         if (rpmtsFlags(ts) & RPMTRANS_FLAG_TEST)        break;
03062         if (rpmtsFlags(ts) & RPMTRANS_FLAG_NORPMDB)     break;
03063         if (fi->isSource)       break;  /* XXX never add SRPM's */
03064         if (fi->h == NULL)      break;  /* XXX can't happen */
03065 
03066         xx = rpmtxnBegin(rpmtsGetRdb(ts), psm->te->txn, NULL);
03067 
03068         /* Add header to db, doing header check if requested */
03069         /* XXX rollback headers propagate the previous transaction id. */
03070         {   rpmuint32_t tid = ((rpmtsType(ts) == RPMTRANS_TYPE_ROLLBACK)
03071                 ? hLoadTID(fi->h, RPMTAG_INSTALLTID) : rpmtsGetTid(ts));
03072             (void) rpmswEnter(rpmtsOp(ts, RPMTS_OP_DBADD), 0);
03073             if (!(rpmtsVSFlags(ts) & RPMVSF_NOHDRCHK))
03074                 rc = rpmdbAdd(rpmtsGetRdb(ts), tid, fi->h, ts);
03075             else
03076                 rc = rpmdbAdd(rpmtsGetRdb(ts), tid, fi->h, NULL);
03077             (void) rpmswExit(rpmtsOp(ts, RPMTS_OP_DBADD), 0);
03078 #if defined(HAVE_SYSLOG) && defined(RPM_VENDOR_MANDRIVA) /* log-install-remove-to-syslog */
03079             {
03080                 char *s, *fmt;
03081                 fmt = rpmExpand("%{___NVRA}", NULL);
03082                 s = headerSprintf(fi->h, fmt,
03083                         rpmTagTable, rpmHeaderFormats, NULL);
03084                 syslog(LOG_NOTICE, "[RPM] %s installed\n", s);
03085                 fmt = _free(fmt);
03086                 s = _free(s);
03087             }
03088 #endif
03089         }
03090 
03091         if (rc != RPMRC_OK) {
03092             xx = rpmtxnAbort(rpmtsGetRdb(ts)->db_txn);
03093             rpmtsGetRdb(ts)->db_txn = NULL;
03094             break;
03095         } else
03096             xx = rpmtxnCommit(rpmtsGetRdb(ts)->db_txn);
03097         rpmtsGetRdb(ts)->db_txn = NULL;
03098 
03099 assert(psm->te != NULL);
03100         /* Mark non-rollback elements as installed. */
03101         if (rpmtsType(ts) != RPMTRANS_TYPE_ROLLBACK)
03102             psm->te->installed = 1;
03103 
03104         /* Set the database instance for (possible) rollbacks. */
03105         rpmteSetDBInstance(psm->te, headerGetInstance(fi->h));
03106 
03107         break;
03108     case PSM_RPMDB_REMOVE:
03109     {   
03110         if (rpmtsFlags(ts) & RPMTRANS_FLAG_TEST)        break;
03111         if (rpmtsFlags(ts) & RPMTRANS_FLAG_NORPMDB)     break;
03112 
03113         xx = rpmtxnBegin(rpmtsGetRdb(ts), psm->te->txn, NULL);
03114 
03115         (void) rpmswEnter(rpmtsOp(ts, RPMTS_OP_DBREMOVE), 0);
03116         rc = rpmdbRemove(rpmtsGetRdb(ts), rpmtsGetTid(ts), fi->record, NULL);
03117         (void) rpmswExit(rpmtsOp(ts, RPMTS_OP_DBREMOVE), 0);
03118 #if defined(HAVE_SYSLOG) && defined(RPM_VENDOR_MANDRIVA) /* log-install-remove-to-syslog */
03119         {
03120             char *s, *fmt;
03121             fmt = rpmExpand("%{___NVRA}", NULL);
03122             s = headerSprintf(fi->h, fmt,
03123                     rpmTagTable, rpmHeaderFormats, NULL);
03124             syslog(LOG_NOTICE, "[RPM] %s removed\n", s);
03125             fmt = _free(fmt);
03126             s = _free(s);
03127         }
03128 #endif
03129 
03130         if (rc != RPMRC_OK) {
03131             xx = rpmtxnAbort(rpmtsGetRdb(ts)->db_txn);
03132             rpmtsGetRdb(ts)->db_txn = NULL;
03133             break;
03134         } else
03135             xx = rpmtxnCommit(rpmtsGetRdb(ts)->db_txn);
03136         rpmtsGetRdb(ts)->db_txn = NULL;
03137 
03138         /* Forget the offset of a successfully removed header. */
03139         if (psm->te != NULL)    /* XXX can't happen */
03140             psm->te->u.removed.dboffset = 0;
03141 
03142     }   break;
03143 
03144     default:
03145         break;
03146 /*@i@*/    }
03147 
03148 /*@-nullstate@*/        /* FIX: psm->oh and psm->fi->h may be NULL. */
03149     return rc;
03150 /*@=nullstate@*/
03151 }
03152 /*@=nullpass@*/