rpm 5.3.7

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