lib/psm.c

Go to the documentation of this file.
00001 
00006 #include "system.h"
00007 
00008 #include <rpmio_internal.h>
00009 #include <rpmlib.h>
00010 #include <rpmmacro.h>
00011 #include <rpmurl.h>
00012 #include <rpmlua.h>
00013 
00014 #include "cpio.h"
00015 #include "fsm.h"                /* XXX CPIO_FOO/FSM_FOO constants */
00016 #include "psm.h"
00017 
00018 #define _RPMEVR_INTERNAL
00019 #include "rpmds.h"
00020 
00021 #define _RPMFI_INTERNAL
00022 #include "rpmfi.h"
00023 
00024 #define _RPMTE_INTERNAL
00025 #include "rpmte.h"
00026 
00027 #define _RPMTS_INTERNAL         /* XXX ts->notify */
00028 #include "rpmts.h"
00029 
00030 #include "rpmlead.h"            /* writeLead proto */
00031 #include "signature.h"          /* signature constants */
00032 #include "legacy.h"             /* XXX rpmfiBuildFNames() */
00033 #include "misc.h"               /* XXX stripTrailingChar() */
00034 #include "rpmdb.h"              /* XXX for db_chrootDone */
00035 #include "debug.h"
00036 
00037 #define _PSM_DEBUG      0
00038 /*@unchecked@*/
00039 int _psm_debug = _PSM_DEBUG;
00040 /*@unchecked@*/
00041 int _psm_threads = 0;
00042 
00043 /*@access FD_t @*/              /* XXX void ptr args */
00044 /*@access rpmpsm @*/
00045 
00046 /*@access rpmfi @*/
00047 /*@access rpmte @*/     /* XXX rpmInstallSourcePackage */
00048 /*@access rpmts @*/     /* XXX ts->notify */
00049 
00050 /*@access rpmluav @*/
00051 
00052 int rpmVersionCompare(Header first, Header second)
00053 {
00054     const char * one, * two;
00055     int_32 * epochOne, * epochTwo;
00056     static int_32 zero = 0;
00057     int rc;
00058 
00059     if (!headerGetEntry(first, RPMTAG_EPOCH, NULL, &epochOne, NULL))
00060         epochOne = &zero;
00061     if (!headerGetEntry(second, RPMTAG_EPOCH, NULL, &epochTwo, NULL))
00062         epochTwo = &zero;
00063 
00064 /*@-boundsread@*/
00065     if (*epochOne < *epochTwo)
00066         return -1;
00067     else if (*epochOne > *epochTwo)
00068         return 1;
00069 /*@=boundsread@*/
00070 
00071     rc = headerGetEntry(first, RPMTAG_VERSION, NULL, &one, NULL);
00072     rc = headerGetEntry(second, RPMTAG_VERSION, NULL, &two, NULL);
00073 
00074     rc = rpmvercmp(one, two);
00075     if (rc)
00076         return rc;
00077 
00078     rc = headerGetEntry(first, RPMTAG_RELEASE, NULL, &one, NULL);
00079     rc = headerGetEntry(second, RPMTAG_RELEASE, NULL, &two, NULL);
00080 
00081     return rpmvercmp(one, two);
00082 }
00083 
00089 /*@-bounds@*/
00090 static rpmRC markReplacedFiles(const rpmpsm psm)
00091         /*@globals rpmGlobalMacroContext, h_errno, fileSystem, internalState @*/
00092         /*@modifies psm, rpmGlobalMacroContext, fileSystem, internalState @*/
00093 {
00094     const rpmts ts = psm->ts;
00095     rpmfi fi = psm->fi;
00096     HGE_t hge = (HGE_t)fi->hge;
00097     sharedFileInfo replaced = fi->replaced;
00098     sharedFileInfo sfi;
00099     rpmdbMatchIterator mi;
00100     Header h;
00101     unsigned int * offsets;
00102     unsigned int prev;
00103     int num, xx;
00104 
00105     if (!(rpmfiFC(fi) > 0 && fi->replaced))
00106         return RPMRC_OK;
00107 
00108     num = prev = 0;
00109     for (sfi = replaced; sfi->otherPkg; sfi++) {
00110         if (prev && prev == sfi->otherPkg)
00111             continue;
00112         prev = sfi->otherPkg;
00113         num++;
00114     }
00115     if (num == 0)
00116         return RPMRC_OK;
00117 
00118     offsets = alloca(num * sizeof(*offsets));
00119     offsets[0] = 0;
00120     num = prev = 0;
00121     for (sfi = replaced; sfi->otherPkg; sfi++) {
00122         if (prev && prev == sfi->otherPkg)
00123             continue;
00124         prev = sfi->otherPkg;
00125         offsets[num++] = sfi->otherPkg;
00126     }
00127 
00128     mi = rpmtsInitIterator(ts, RPMDBI_PACKAGES, NULL, 0);
00129     xx = rpmdbAppendIterator(mi, offsets, num);
00130     xx = rpmdbSetIteratorRewrite(mi, 1);
00131 
00132     sfi = replaced;
00133     while ((h = rpmdbNextIterator(mi)) != NULL) {
00134         char * secStates;
00135         int modified;
00136         int count;
00137 
00138         modified = 0;
00139 
00140         if (!hge(h, RPMTAG_FILESTATES, NULL, &secStates, &count))
00141             continue;
00142         
00143         prev = rpmdbGetIteratorOffset(mi);
00144         num = 0;
00145         while (sfi->otherPkg && sfi->otherPkg == prev) {
00146             assert(sfi->otherFileNum < count);
00147             if (secStates[sfi->otherFileNum] != RPMFILE_STATE_REPLACED) {
00148                 secStates[sfi->otherFileNum] = RPMFILE_STATE_REPLACED;
00149                 if (modified == 0) {
00150                     /* Modified header will be rewritten. */
00151                     modified = 1;
00152                     xx = rpmdbSetIteratorModified(mi, modified);
00153                 }
00154                 num++;
00155             }
00156             sfi++;
00157         }
00158     }
00159     mi = rpmdbFreeIterator(mi);
00160 
00161     return RPMRC_OK;
00162 }
00163 /*@=bounds@*/
00164 
00165 rpmRC rpmInstallSourcePackage(rpmts ts, FD_t fd,
00166                 const char ** specFilePtr, const char ** cookie)
00167 {
00168     int scareMem = 1;   /* XXX fi->h is needed */
00169     rpmfi fi = NULL;
00170     const char * _sourcedir = NULL;
00171     const char * _specdir = NULL;
00172     const char * specFile = NULL;
00173     HGE_t hge;
00174     HFD_t hfd;
00175     Header h = NULL;
00176     struct rpmpsm_s psmbuf;
00177     rpmpsm psm = &psmbuf;
00178     int isSource;
00179     rpmRC rpmrc;
00180     int i;
00181 
00182     memset(psm, 0, sizeof(*psm));
00183     psm->ts = rpmtsLink(ts, "InstallSourcePackage");
00184 
00185     rpmrc = rpmReadPackageFile(ts, fd, "InstallSourcePackage", &h);
00186     switch (rpmrc) {
00187     case RPMRC_NOTTRUSTED:
00188     case RPMRC_NOKEY:
00189     case RPMRC_OK:
00190         break;
00191     default:
00192         goto exit;
00193         /*@notreached@*/ break;
00194     }
00195     if (h == NULL)
00196         goto exit;
00197 
00198     rpmrc = RPMRC_OK;
00199 
00200     isSource = (headerIsEntry(h, RPMTAG_SOURCERPM) == 0);
00201 
00202     if (!isSource) {
00203         rpmError(RPMERR_NOTSRPM, _("source package expected, binary found\n"));
00204         rpmrc = RPMRC_FAIL;
00205         goto exit;
00206     }
00207 
00208     (void) rpmtsAddInstallElement(ts, h, NULL, 0, NULL);
00209 
00210     fi = rpmfiNew(ts, h, RPMTAG_BASENAMES, scareMem);
00211     h = headerFree(h);
00212 
00213     if (fi == NULL) {   /* XXX can't happen */
00214         rpmrc = RPMRC_FAIL;
00215         goto exit;
00216     }
00217 
00218 /*@-onlytrans@*/        /* FIX: te reference */
00219     fi->te = rpmtsElement(ts, 0);
00220 /*@=onlytrans@*/
00221     if (fi->te == NULL) {       /* XXX can't happen */
00222         rpmrc = RPMRC_FAIL;
00223         goto exit;
00224     }
00225 
00226 assert(fi->h != NULL);
00227     fi->te->h = headerLink(fi->h);
00228     fi->te->fd = fdLink(fd, "installSourcePackage");
00229     hge = fi->hge;
00230     hfd = fi->hfd;
00231 
00232 /*@i@*/ (void) headerMacrosLoad(fi->h);
00233 
00234     psm->fi = rpmfiLink(fi, NULL);
00235     /*@-assignexpose -usereleased @*/
00236     psm->te = fi->te;
00237     /*@=assignexpose =usereleased @*/
00238 
00239     if (cookie) {
00240         *cookie = NULL;
00241         if (hge(fi->h, RPMTAG_COOKIE, NULL, (void **) cookie, NULL))
00242             *cookie = xstrdup(*cookie);
00243     }
00244 
00245     /* XXX FIXME: don't do per-file mapping, force global flags. */
00246     fi->fmapflags = _free(fi->fmapflags);
00247     fi->mapflags = CPIO_MAP_PATH | CPIO_MAP_MODE | CPIO_MAP_UID | CPIO_MAP_GID;
00248 
00249     fi->uid = getuid();
00250     fi->gid = getgid();
00251     fi->astriplen = 0;
00252     fi->striplen = 0;
00253 
00254     for (i = 0; i < fi->fc; i++)
00255         fi->actions[i] = FA_CREATE;
00256 
00257     i = fi->fc;
00258 
00259     if (fi->h != NULL) {        /* XXX can't happen */
00260         rpmfiBuildFNames(fi->h, RPMTAG_BASENAMES, &fi->apath, NULL);
00261 
00262         if (headerIsEntry(fi->h, RPMTAG_COOKIE))
00263             for (i = 0; i < fi->fc; i++)
00264                 if (fi->fflags[i] & RPMFILE_SPECFILE) break;
00265     }
00266 
00267     if (i == fi->fc) {
00268         /* Find the spec file by name. */
00269         for (i = 0; i < fi->fc; i++) {
00270             const char * t = fi->apath[i];
00271             t += strlen(fi->apath[i]) - 5;
00272             if (!strcmp(t, ".spec")) break;
00273         }
00274     }
00275 
00276     _sourcedir = rpmGenPath(rpmtsRootDir(ts), "%{_sourcedir}", "");
00277     rpmrc = rpmMkdirPath(_sourcedir, "sourcedir");
00278     if (rpmrc) {
00279         rpmrc = RPMRC_FAIL;
00280         goto exit;
00281     }
00282     if (Access(_sourcedir, W_OK)) {
00283         rpmError(RPMERR_CREATE, _("cannot write to %%%s %s\n"),
00284                 "_sourcedir", _sourcedir);
00285         rpmrc = RPMRC_FAIL;
00286         goto exit;
00287     }
00288 
00289     _specdir = rpmGenPath(rpmtsRootDir(ts), "%{_specdir}", "");
00290     rpmrc = rpmMkdirPath(_specdir, "specdir");
00291     if (rpmrc) {
00292         rpmrc = RPMRC_FAIL;
00293         goto exit;
00294     }
00295     if (Access(_specdir, W_OK)) {
00296         rpmError(RPMERR_CREATE, _("cannot write to %%%s %s\n"),
00297                 "_specdir", _specdir);
00298         rpmrc = RPMRC_FAIL;
00299         goto exit;
00300     }
00301 
00302     /* Build dnl/dil with {_sourcedir, _specdir} as values. */
00303     if (i < fi->fc) {
00304         int speclen = strlen(_specdir) + 2;
00305         int sourcelen = strlen(_sourcedir) + 2;
00306         char * t;
00307 
00308 /*@i@*/ fi->dnl = hfd(fi->dnl, -1);
00309 
00310         fi->dc = 2;
00311         fi->dnl = xmalloc(fi->dc * sizeof(*fi->dnl)
00312                         + fi->fc * sizeof(*fi->dil)
00313                         + speclen + sourcelen);
00314         /*@-dependenttrans@*/
00315         fi->dil = (int *)(fi->dnl + fi->dc);
00316         /*@=dependenttrans@*/
00317         memset(fi->dil, 0, fi->fc * sizeof(*fi->dil));
00318         fi->dil[i] = 1;
00319         /*@-dependenttrans@*/
00320         fi->dnl[0] = t = (char *)(fi->dil + fi->fc);
00321         fi->dnl[1] = t = stpcpy( stpcpy(t, _sourcedir), "/") + 1;
00322         /*@=dependenttrans@*/
00323         (void) stpcpy( stpcpy(t, _specdir), "/");
00324 
00325         t = xmalloc(speclen + strlen(fi->bnl[i]) + 1);
00326         (void) stpcpy( stpcpy( stpcpy(t, _specdir), "/"), fi->bnl[i]);
00327         specFile = t;
00328     } else {
00329         rpmError(RPMERR_NOSPEC, _("source package contains no .spec file\n"));
00330         rpmrc = RPMRC_FAIL;
00331         goto exit;
00332     }
00333 
00334     psm->goal = PSM_PKGINSTALL;
00335 
00336     /*@-compmempass@*/  /* FIX: psm->fi->dnl should be owned. */
00337     rpmrc = rpmpsmStage(psm, PSM_PROCESS);
00338 
00339     (void) rpmpsmStage(psm, PSM_FINI);
00340     /*@=compmempass@*/
00341 
00342     if (rpmrc) rpmrc = RPMRC_FAIL;
00343 
00344 exit:
00345     if (specFilePtr && specFile && rpmrc == RPMRC_OK)
00346         *specFilePtr = specFile;
00347     else
00348         specFile = _free(specFile);
00349 
00350     _specdir = _free(_specdir);
00351     _sourcedir = _free(_sourcedir);
00352 
00353     psm->fi = rpmfiFree(psm->fi);
00354     psm->te = NULL;
00355 
00356     if (h != NULL) h = headerFree(h);
00357 
00358     /*@-branchstate@*/
00359     if (fi != NULL) {
00360         fi->te->h = headerFree(fi->te->h);
00361         if (fi->te->fd != NULL)
00362             (void) Fclose(fi->te->fd);
00363         fi->te->fd = NULL;
00364         fi->te = NULL;
00365         fi = rpmfiFree(fi);
00366     }
00367     /*@=branchstate@*/
00368 
00369     /* XXX nuke the added package(s). */
00370     rpmtsClean(ts);
00371 
00372     psm->ts = rpmtsFree(psm->ts);
00373 
00374     return rpmrc;
00375 }
00376 
00377 /*@observer@*/ /*@unchecked@*/
00378 static char * SCRIPT_PATH = "PATH=/sbin:/bin:/usr/sbin:/usr/bin:/usr/X11R6/bin";
00379 
00385 static /*@observer@*/ const char * tag2sln(int tag)
00386         /*@*/
00387 {
00388     switch (tag) {
00389     case RPMTAG_PRETRANS:       return "%pretrans";
00390     case RPMTAG_TRIGGERPREIN:   return "%triggerprein";
00391     case RPMTAG_PREIN:          return "%pre";
00392     case RPMTAG_POSTIN:         return "%post";
00393     case RPMTAG_TRIGGERIN:      return "%triggerin";
00394     case RPMTAG_TRIGGERUN:      return "%triggerun";
00395     case RPMTAG_PREUN:          return "%preun";
00396     case RPMTAG_POSTUN:         return "%postun";
00397     case RPMTAG_POSTTRANS:      return "%posttrans";
00398     case RPMTAG_TRIGGERPOSTUN:  return "%triggerpostun";
00399     case RPMTAG_VERIFYSCRIPT:   return "%verify";
00400     }
00401     return "%unknownscript";
00402 }
00403 
00409 static rpmScriptID tag2slx(int tag)
00410         /*@*/
00411 {
00412     switch (tag) {
00413     case RPMTAG_PRETRANS:       return RPMSCRIPT_PRETRANS;
00414     case RPMTAG_TRIGGERPREIN:   return RPMSCRIPT_TRIGGERPREIN;
00415     case RPMTAG_PREIN:          return RPMSCRIPT_PREIN;
00416     case RPMTAG_POSTIN:         return RPMSCRIPT_POSTIN;
00417     case RPMTAG_TRIGGERIN:      return RPMSCRIPT_TRIGGERIN;
00418     case RPMTAG_TRIGGERUN:      return RPMSCRIPT_TRIGGERUN;
00419     case RPMTAG_PREUN:          return RPMSCRIPT_PREUN;
00420     case RPMTAG_POSTUN:         return RPMSCRIPT_POSTUN;
00421     case RPMTAG_POSTTRANS:      return RPMSCRIPT_POSTTRANS;
00422     case RPMTAG_TRIGGERPOSTUN:  return RPMSCRIPT_TRIGGERPOSTUN;
00423     case RPMTAG_VERIFYSCRIPT:   return RPMSCRIPT_VERIFY;
00424     }
00425     return RPMSCRIPT_UNKNOWN;
00426 }
00427 
00433 static pid_t psmWait(rpmpsm psm)
00434         /*@globals fileSystem, internalState @*/
00435         /*@modifies psm, fileSystem, internalState @*/
00436 {
00437     const rpmts ts = psm->ts;
00438     rpmtime_t msecs;
00439 
00440     (void) rpmsqWait(&psm->sq);
00441     msecs = psm->sq.op.usecs/1000;
00442     (void) rpmswAdd(rpmtsOp(ts, RPMTS_OP_SCRIPTLETS), &psm->sq.op);
00443 
00444     rpmMessage(RPMMESS_DEBUG,
00445         _("%s: waitpid(%d) rc %d status %x secs %u.%03u\n"),
00446         psm->stepName, (unsigned)psm->sq.child,
00447         (unsigned)psm->sq.reaped, psm->sq.status,
00448         (unsigned)msecs/1000, (unsigned)msecs%1000);
00449 
00450     if (psm->sstates != NULL)
00451     {   int * ssp = psm->sstates + tag2slx(psm->scriptTag);
00452         *ssp &= ~0xffff;
00453         *ssp |= (psm->sq.status & 0xffff);
00454         *ssp |= RPMSCRIPT_STATE_REAPED;
00455     }
00456 
00457     return psm->sq.reaped;
00458 }
00459 
00460 #ifdef WITH_LUA
00461 
00464 static rpmRC runLuaScript(rpmpsm psm, Header h, const char *sln,
00465                    int progArgc, const char **progArgv,
00466                    const char *script, int arg1, int arg2)
00467         /*@globals h_errno, fileSystem, internalState @*/
00468         /*@modifies psm, fileSystem, internalState @*/
00469 {
00470     const rpmts ts = psm->ts;
00471     int rootFdno = -1;
00472     const char *n, *v, *r;
00473     rpmRC rc = RPMRC_OK;
00474     int i;
00475     int xx;
00476     rpmlua lua = NULL; /* Global state. */
00477     rpmluav var;
00478     int * ssp = NULL;
00479 
00480     if (psm->sstates != NULL)
00481         ssp = psm->sstates + tag2slx(psm->scriptTag);
00482     if (ssp != NULL)
00483         *ssp |= (RPMSCRIPT_STATE_LUA|RPMSCRIPT_STATE_EXEC);
00484 
00485     xx = headerNVR(h, &n, &v, &r);
00486 
00487     /* Save the current working directory. */
00488 /*@-nullpass@*/
00489     rootFdno = open(".", O_RDONLY, 0);
00490 /*@=nullpass@*/
00491 
00492     /* Get into the chroot. */
00493     if (!rpmtsChrootDone(ts)) {
00494         const char *rootDir = rpmtsRootDir(ts);
00495         /*@-superuser -noeffect @*/
00496         if (rootDir != NULL && strcmp(rootDir, "/") && *rootDir == '/') {
00497             xx = Chroot(rootDir);
00498         /*@=superuser =noeffect @*/
00499             xx = rpmtsSetChrootDone(ts, 1);
00500         }
00501     }
00502 
00503     /* All lua scripts run with CWD == "/". */
00504     xx = Chdir("/");
00505 
00506     /* Create arg variable */
00507     rpmluaPushTable(lua, "arg");
00508     var = rpmluavNew();
00509     rpmluavSetListMode(var, 1);
00510 /*@+relaxtypes@*/
00511     if (progArgv) {
00512         for (i = 0; i < progArgc && progArgv[i]; i++) {
00513             rpmluavSetValue(var, RPMLUAV_STRING, progArgv[i]);
00514             rpmluaSetVar(lua, var);
00515         }
00516     }
00517     if (arg1 >= 0) {
00518         rpmluavSetValueNum(var, arg1);
00519         rpmluaSetVar(lua, var);
00520     }
00521     if (arg2 >= 0) {
00522         rpmluavSetValueNum(var, arg2);
00523         rpmluaSetVar(lua, var);
00524     }
00525 /*@=relaxtypes@*/
00526 /*@-moduncon@*/
00527     var = rpmluavFree(var);
00528 /*@=moduncon@*/
00529     rpmluaPop(lua);
00530 
00531     {
00532         char buf[BUFSIZ];
00533         xx = snprintf(buf, BUFSIZ, "%s(%s-%s-%s)", sln, n, v, r);
00534         xx = rpmluaRunScript(lua, script, buf);
00535         if (xx == -1)
00536             rc = RPMRC_FAIL;
00537         if (ssp != NULL) {
00538             *ssp &= ~0xffff;
00539             *ssp |= (xx & 0xffff);
00540             *ssp |= RPMSCRIPT_STATE_REAPED;
00541         }
00542     }
00543 
00544     rpmluaDelVar(lua, "arg");
00545 
00546     /* Get out of chroot. */
00547     if (rpmtsChrootDone(ts)) {
00548         const char *rootDir = rpmtsRootDir(ts);
00549         xx = fchdir(rootFdno);
00550         /*@-superuser -noeffect @*/
00551         if (rootDir != NULL && strcmp(rootDir, "/") && *rootDir == '/') {
00552             xx = Chroot(".");
00553         /*@=superuser =noeffect @*/
00554             xx = rpmtsSetChrootDone(ts, 0);
00555         }
00556     } else
00557         xx = fchdir(rootFdno);
00558 
00559     xx = close(rootFdno);
00560 
00561     return rc;
00562 }
00563 #endif
00564 
00567 /*@unchecked@*/
00568 static int ldconfig_done = 0;
00569 
00570 /*@unchecked@*/ /*@observer@*/ /*@null@*/
00571 static const char * ldconfig_path = "/sbin/ldconfig";
00572 
00591 static rpmRC runScript(rpmpsm psm, Header h, const char * sln,
00592                 int progArgc, const char ** progArgv,
00593                 const char * script, int arg1, int arg2)
00594         /*@globals ldconfig_done, rpmGlobalMacroContext, h_errno,
00595                 fileSystem, internalState@*/
00596         /*@modifies psm, ldconfig_done, rpmGlobalMacroContext,
00597                 fileSystem, internalState @*/
00598 {
00599     const rpmts ts = psm->ts;
00600     rpmfi fi = psm->fi;
00601     HGE_t hge = fi->hge;
00602     HFD_t hfd = (fi->hfd ? fi->hfd : headerFreeData);
00603     const char ** argv = NULL;
00604     int argc = 0;
00605     const char ** prefixes = NULL;
00606     int numPrefixes;
00607     rpmTagType ipt;
00608     const char * oldPrefix;
00609     int maxPrefixLength;
00610     int len;
00611     char * prefixBuf = NULL;
00612     const char * fn = NULL;
00613     int xx;
00614     int i;
00615     int freePrefixes = 0;
00616     FD_t scriptFd;
00617     FD_t out;
00618     rpmRC rc = RPMRC_OK;
00619     const char *n, *v, *r, *a;
00620     int * ssp = NULL;
00621 
00622     if (psm->sstates != NULL)
00623         ssp = psm->sstates + tag2slx(psm->scriptTag);
00624     if (ssp != NULL)
00625         *ssp = RPMSCRIPT_STATE_UNKNOWN;
00626 
00627     if (progArgv == NULL && script == NULL)
00628         return rc;
00629 
00630     /* XXX FIXME: except for %verifyscript, rpmteNEVR can be used. */
00631     xx = headerNVR(h, &n, &v, &r);
00632     xx = hge(h, RPMTAG_ARCH, NULL, &a, NULL);
00633 
00634     if (progArgv && strcmp(progArgv[0], "<lua>") == 0) {
00635 #ifdef WITH_LUA
00636         rpmMessage(RPMMESS_DEBUG,
00637                 _("%s: %s(%s-%s-%s.%s) running <lua> scriptlet.\n"),
00638                 psm->stepName, tag2sln(psm->scriptTag), n, v, r, a);
00639         return runLuaScript(psm, h, sln, progArgc, progArgv,
00640                             script, arg1, arg2);
00641 #else
00642         return RPMRC_FAIL;
00643 #endif
00644     }
00645 
00646     psm->sq.reaper = 1;
00647 
00648     /* XXX bash must have functional libtermcap.so.2 */
00649     if (!strcmp(n, "libtermcap"))
00650         ldconfig_done = 0;
00651 
00652     /*
00653      * If a successor node, and ldconfig was just run, don't bother.
00654      */
00655     if (ldconfig_path && progArgv != NULL && psm->unorderedSuccessor) {
00656         if (ldconfig_done && !strcmp(progArgv[0], ldconfig_path)) {
00657             rpmMessage(RPMMESS_DEBUG,
00658                 _("%s: %s(%s-%s-%s.%s) skipping redundant \"%s\".\n"),
00659                 psm->stepName, tag2sln(psm->scriptTag), n, v, r, a,
00660                 progArgv[0]);
00661             return rc;
00662         }
00663     }
00664 
00665     rpmMessage(RPMMESS_DEBUG,
00666                 _("%s: %s(%s-%s-%s.%s) %ssynchronous scriptlet start\n"),
00667                 psm->stepName, tag2sln(psm->scriptTag), n, v, r, a,
00668                 (psm->unorderedSuccessor ? "a" : ""));
00669 
00670     if (!progArgv) {
00671         argv = alloca(5 * sizeof(*argv));
00672         argv[0] = "/bin/sh";
00673         argc = 1;
00674         ldconfig_done = 0;
00675     } else {
00676         argv = alloca((progArgc + 4) * sizeof(*argv));
00677         memcpy(argv, progArgv, progArgc * sizeof(*argv));
00678         argc = progArgc;
00679         ldconfig_done = (ldconfig_path && !strcmp(argv[0], ldconfig_path)
00680                 ? 1 : 0);
00681     }
00682 
00683 #if __ia64__
00684     /* XXX This assumes that all interpreters are elf executables. */
00685     if ((a != NULL && a[0] == 'i' && a[1] != '\0' && a[2] == '8' && a[3] == '6')
00686      && strcmp(argv[0], "/sbin/ldconfig"))
00687     {
00688         const char * fmt = rpmGetPath("%{?_autorelocate_path}", NULL);
00689         const char * errstr;
00690         char * newPath;
00691         char * t;
00692 
00693         newPath = headerSprintf(h, fmt, rpmTagTable, rpmHeaderFormats, &errstr);
00694         fmt = _free(fmt);
00695 
00696         /* XXX On ia64, change leading /emul/ix86 -> /emul/ia32, ick. */
00697         if (newPath != NULL && *newPath != '\0'
00698          && strlen(newPath) >= (sizeof("/emul/i386")-1)
00699          && newPath[0] == '/' && newPath[1] == 'e' && newPath[2] == 'm'
00700          && newPath[3] == 'u' && newPath[4] == 'l' && newPath[5] == '/'
00701          && newPath[6] == 'i' && newPath[8] == '8' && newPath[9] == '6')
00702         {
00703             newPath[7] = 'a';
00704             newPath[8] = '3';
00705             newPath[9] = '2';
00706         }
00707 
00708         t = alloca(strlen(newPath) + strlen(argv[0]) + 1);
00709         *t = '\0';
00710         (void) stpcpy( stpcpy(t, newPath), argv[0]);
00711         newPath = _free(newPath);
00712         argv[0] = t;
00713     }
00714 #endif
00715 
00716     if (hge(h, RPMTAG_INSTPREFIXES, &ipt, &prefixes, &numPrefixes)) {
00717         freePrefixes = 1;
00718     } else if (hge(h, RPMTAG_INSTALLPREFIX, NULL, &oldPrefix, NULL)) {
00719         prefixes = &oldPrefix;
00720         numPrefixes = 1;
00721     } else {
00722         numPrefixes = 0;
00723     }
00724 
00725     maxPrefixLength = 0;
00726     if (prefixes != NULL)
00727     for (i = 0; i < numPrefixes; i++) {
00728         len = strlen(prefixes[i]);
00729         if (len > maxPrefixLength) maxPrefixLength = len;
00730     }
00731     prefixBuf = alloca(maxPrefixLength + 50);
00732 
00733     if (script) {
00734         const char * rootDir = rpmtsRootDir(ts);
00735         FD_t fd;
00736 
00737         /*@-branchstate@*/
00738         if (makeTempFile((!rpmtsChrootDone(ts) ? rootDir : "/"), &fn, &fd)) {
00739             if (prefixes != NULL && freePrefixes) free(prefixes);
00740             return RPMRC_FAIL;
00741         }
00742         /*@=branchstate@*/
00743 
00744         if (rpmIsDebug() &&
00745             (!strcmp(argv[0], "/bin/sh") || !strcmp(argv[0], "/bin/bash")))
00746         {
00747             static const char set_x[] = "set -x\n";
00748             xx = Fwrite(set_x, sizeof(set_x[0]), sizeof(set_x)-1, fd);
00749         }
00750 
00751         if (ldconfig_path && strstr(script, ldconfig_path) != NULL)
00752             ldconfig_done = 1;
00753 
00754         xx = Fwrite(script, sizeof(script[0]), strlen(script), fd);
00755         xx = Fclose(fd);
00756 
00757         {   const char * sn = fn;
00758             if (!rpmtsChrootDone(ts) && rootDir != NULL &&
00759                 !(rootDir[0] == '/' && rootDir[1] == '\0'))
00760             {
00761                 sn += strlen(rootDir)-1;
00762             }
00763             argv[argc++] = sn;
00764         }
00765 
00766         if (arg1 >= 0) {
00767             char *av = alloca(20);
00768             sprintf(av, "%d", arg1);
00769             argv[argc++] = av;
00770         }
00771         if (arg2 >= 0) {
00772             char *av = alloca(20);
00773             sprintf(av, "%d", arg2);
00774             argv[argc++] = av;
00775         }
00776     }
00777 
00778     argv[argc] = NULL;
00779 
00780     scriptFd = rpmtsScriptFd(ts);
00781     if (scriptFd != NULL) {
00782         if (rpmIsVerbose()) {
00783             out = fdDup(Fileno(scriptFd));
00784         } else {
00785             out = Fopen("/dev/null", "w.fdio");
00786             if (Ferror(out)) {
00787                 out = fdDup(Fileno(scriptFd));
00788             }
00789         }
00790     } else {
00791         out = fdDup(STDOUT_FILENO);
00792     }
00793     if (out == NULL) return RPMRC_FAIL; /* XXX can't happen */
00794 
00795     /*@-branchstate@*/
00796     xx = rpmsqFork(&psm->sq);
00797     if (psm->sq.child == 0) {
00798         const char * rootDir;
00799         int pipes[2];
00800         int flag;
00801         int fdno;
00802 
00803         pipes[0] = pipes[1] = 0;
00804         /* make stdin inaccessible */
00805         xx = pipe(pipes);
00806         xx = close(pipes[1]);
00807         xx = dup2(pipes[0], STDIN_FILENO);
00808         xx = close(pipes[0]);
00809 
00810         /* XXX Force FD_CLOEXEC on 1st 100 inherited fdno's. */
00811         for (fdno = 3; fdno < 100; fdno++) {
00812             flag = fcntl(fdno, F_GETFD);
00813             if (flag == -1 || (flag & FD_CLOEXEC))
00814                 continue;
00815             xx = fcntl(fdno, F_SETFD, FD_CLOEXEC);
00816             /* XXX W2DO? debug msg for inheirited fdno w/o FD_CLOEXEC */
00817         }
00818 
00819         if (scriptFd != NULL) {
00820             int sfdno = Fileno(scriptFd);
00821             int ofdno = Fileno(out);
00822             if (sfdno != STDERR_FILENO)
00823                 xx = dup2(sfdno, STDERR_FILENO);
00824             if (ofdno != STDOUT_FILENO)
00825                 xx = dup2(ofdno, STDOUT_FILENO);
00826             /* make sure we don't close stdin/stderr/stdout by mistake! */
00827             if (ofdno > STDERR_FILENO && ofdno != sfdno)
00828                 xx = Fclose (out);
00829             if (sfdno > STDERR_FILENO)
00830                 xx = Fclose (scriptFd);
00831             else {
00832 /*@-usereleased@*/
00833                 xx = Fclose(out);
00834 /*@=usereleased@*/
00835             }
00836         }
00837 
00838         {   const char *ipath = rpmExpand("PATH=%{_install_script_path}", NULL);
00839             const char *path = SCRIPT_PATH;
00840 
00841             if (ipath && ipath[5] != '%')
00842                 path = ipath;
00843 
00844             xx = doputenv(path);
00845             /*@-modobserver@*/
00846             ipath = _free(ipath);
00847             /*@=modobserver@*/
00848         }
00849 
00850         if (prefixes != NULL)
00851         for (i = 0; i < numPrefixes; i++) {
00852             sprintf(prefixBuf, "RPM_INSTALL_PREFIX%d=%s", i, prefixes[i]);
00853             xx = doputenv(prefixBuf);
00854 
00855             /* backwards compatibility */
00856             if (i == 0) {
00857                 sprintf(prefixBuf, "RPM_INSTALL_PREFIX=%s", prefixes[i]);
00858                 xx = doputenv(prefixBuf);
00859             }
00860         }
00861 
00862         rootDir = ts->rootDir;  /* HACK: rootDir = rpmtsRootDir(ts); instead */
00863         if (rootDir  != NULL)   /* XXX can't happen */
00864         switch(urlIsURL(rootDir)) {
00865         case URL_IS_PATH:
00866             rootDir += sizeof("file://") - 1;
00867             rootDir = strchr(rootDir, '/');
00868             /*@fallthrough@*/
00869         case URL_IS_UNKNOWN:
00870             if (!rpmtsChrootDone(ts) &&
00871                 !(rootDir[0] == '/' && rootDir[1] == '\0'))
00872             {
00873                 /*@-superuser -noeffect @*/
00874                 xx = Chroot(rootDir);
00875                 /*@=superuser =noeffect @*/
00876             }
00877             xx = Chdir("/");
00878             rpmMessage(RPMMESS_DEBUG, _("%s: %s(%s-%s-%s.%s)\texecv(%s) pid %d\n"),
00879                         psm->stepName, sln, n, v, r, a,
00880                         argv[0], (unsigned)getpid());
00881 
00882             /* XXX Don't mtrace into children. */
00883             unsetenv("MALLOC_CHECK_");
00884 
00885             if (ssp != NULL)
00886                 *ssp |= RPMSCRIPT_STATE_EXEC;
00887 
00888             /* Permit libselinux to do the scriptlet exec. */
00889             if (rpmtsSELinuxEnabled(ts) == 1) { 
00890                 if (ssp != NULL)
00891                     *ssp |= RPMSCRIPT_STATE_SELINUX;
00892 /*@-moduncon@*/
00893                 xx = rpm_execcon(0, argv[0], argv, environ);
00894 /*@=moduncon@*/
00895                 if (xx != 0)
00896                     break;
00897             }
00898 
00899 /*@-nullstate@*/
00900             xx = execv(argv[0], (char *const *)argv);
00901 /*@=nullstate@*/
00902             break;
00903         case URL_IS_HTTPS:
00904         case URL_IS_HTTP:
00905         case URL_IS_FTP:
00906         case URL_IS_DASH:
00907         case URL_IS_HKP:
00908         default:
00909             break;
00910         }
00911 
00912         if (ssp != NULL)
00913             *ssp &= ~RPMSCRIPT_STATE_EXEC;
00914 
00915         _exit(-1);
00916         /*@notreached@*/
00917     }
00918     /*@=branchstate@*/
00919 
00920     (void) psmWait(psm);
00921 
00922   /* XXX filter order dependent multilib "other" arch helper error. */
00923   if (!(psm->sq.reaped >= 0 && !strcmp(argv[0], "/usr/sbin/glibc_post_upgrade") && WEXITSTATUS(psm->sq.status) == 110)) {
00924     if (psm->sq.reaped < 0) {
00925         rpmError(RPMERR_SCRIPT,
00926                 _("%s(%s-%s-%s.%s) scriptlet failed, waitpid(%d) rc %d: %s\n"),
00927                  sln, n, v, r, a, psm->sq.child, psm->sq.reaped, strerror(errno));
00928         rc = RPMRC_FAIL;
00929     } else
00930     if (!WIFEXITED(psm->sq.status) || WEXITSTATUS(psm->sq.status)) {
00931       if (WIFSIGNALED(psm->sq.status)) {
00932         rpmError(RPMERR_SCRIPT,
00933                  _("%s(%s-%s-%s.%s) scriptlet failed, signal %d\n"),
00934                  sln, n, v, r, a, WTERMSIG(psm->sq.status));
00935       } else {
00936         rpmError(RPMERR_SCRIPT,
00937                 _("%s(%s-%s-%s.%s) scriptlet failed, exit status %d\n"),
00938                 sln, n, v, r, a, WEXITSTATUS(psm->sq.status));
00939       }
00940         rc = RPMRC_FAIL;
00941     }
00942   }
00943 
00944     if (freePrefixes) prefixes = hfd(prefixes, ipt);
00945 
00946     xx = Fclose(out);   /* XXX dup'd STDOUT_FILENO */
00947 
00948     /*@-branchstate@*/
00949     if (script) {
00950         if (!rpmIsDebug())
00951             xx = unlink(fn);
00952         fn = _free(fn);
00953     }
00954     /*@=branchstate@*/
00955 
00956     return rc;
00957 }
00958 
00964 static rpmRC runInstScript(rpmpsm psm)
00965         /*@globals rpmGlobalMacroContext, h_errno, fileSystem, internalState @*/
00966         /*@modifies psm, rpmGlobalMacroContext, fileSystem, internalState @*/
00967 {
00968     rpmfi fi = psm->fi;
00969     HGE_t hge = fi->hge;
00970     HFD_t hfd = (fi->hfd ? fi->hfd : headerFreeData);
00971     void ** progArgv = NULL;
00972     int progArgc;
00973     const char * argv0 = NULL;
00974     const char ** argv;
00975     rpmTagType ptt, stt;
00976     const char * script;
00977     rpmRC rc = RPMRC_OK;
00978     int xx;
00979 
00980 assert(fi->h != NULL);
00981     xx = hge(fi->h, psm->scriptTag, &stt, &script, NULL);
00982     xx = hge(fi->h, psm->progTag, &ptt, &progArgv, &progArgc);
00983     if (progArgv == NULL && script == NULL)
00984         goto exit;
00985 
00986     /*@-branchstate@*/
00987     if (progArgv && ptt == RPM_STRING_TYPE) {
00988         argv = alloca(sizeof(*argv));
00989         *argv = (const char *) progArgv;
00990     } else {
00991         argv = (const char **) progArgv;
00992     }
00993     /*@=branchstate@*/
00994 
00995     if (argv[0][0] == '%')
00996         argv[0] = argv0 = rpmExpand(argv[0], NULL);
00997 
00998     if (fi->h != NULL)  /* XXX can't happen */
00999     rc = runScript(psm, fi->h, tag2sln(psm->scriptTag), progArgc, argv,
01000                 script, psm->scriptArg, -1);
01001 
01002 exit:
01003     argv0 = _free(argv0);
01004     progArgv = hfd(progArgv, ptt);
01005     script = hfd(script, stt);
01006     return rc;
01007 }
01008 
01019 static rpmRC handleOneTrigger(const rpmpsm psm,
01020                         Header sourceH, Header triggeredH,
01021                         int arg2, unsigned char * triggersAlreadyRun)
01022         /*@globals rpmGlobalMacroContext, h_errno, fileSystem, internalState@*/
01023         /*@modifies psm, sourceH, triggeredH, *triggersAlreadyRun,
01024                 rpmGlobalMacroContext, fileSystem, internalState @*/
01025 {
01026     int scareMem = 0;
01027     const rpmts ts = psm->ts;
01028     rpmfi fi = psm->fi;
01029     HGE_t hge = fi->hge;
01030     HFD_t hfd = (fi->hfd ? fi->hfd : headerFreeData);
01031     rpmds trigger = NULL;
01032     const char ** triggerScripts;
01033     const char ** triggerProgs;
01034     int_32 * triggerIndices;
01035     const char * sourceName;
01036     const char * triggerName;
01037     rpmRC rc = RPMRC_OK;
01038     int xx;
01039     int i;
01040 
01041     xx = headerNVR(sourceH, &sourceName, NULL, NULL);
01042     xx = headerNVR(triggeredH, &triggerName, NULL, NULL);
01043 
01044     trigger = rpmdsInit(rpmdsNew(triggeredH, RPMTAG_TRIGGERNAME, scareMem));
01045     if (trigger == NULL)
01046         return rc;
01047 
01048     (void) rpmdsSetNoPromote(trigger, 1);
01049 
01050     while ((i = rpmdsNext(trigger)) >= 0) {
01051         rpmTagType tit, tst, tpt;
01052         const char * Name;
01053         int_32 Flags = rpmdsFlags(trigger);
01054 
01055         if ((Name = rpmdsN(trigger)) == NULL)
01056             continue;   /* XXX can't happen */
01057 
01058         if (strcmp(Name, sourceName))
01059             continue;
01060         if (!(Flags & psm->sense))
01061             continue;
01062 
01063         /*
01064          * XXX Trigger on any provided dependency, not just the package NEVR.
01065          */
01066         if (!rpmdsAnyMatchesDep(sourceH, trigger, 1))
01067             continue;
01068 
01069         if (!(  hge(triggeredH, RPMTAG_TRIGGERINDEX, &tit,
01070                        &triggerIndices, NULL) &&
01071                 hge(triggeredH, RPMTAG_TRIGGERSCRIPTS, &tst,
01072                        &triggerScripts, NULL) &&
01073                 hge(triggeredH, RPMTAG_TRIGGERSCRIPTPROG, &tpt,
01074                        &triggerProgs, NULL))
01075             )
01076             continue;
01077 
01078         {   int arg1;
01079             int index;
01080 
01081             arg1 = rpmdbCountPackages(rpmtsGetRdb(ts), triggerName);
01082             if (arg1 < 0) {
01083                 /* XXX W2DO? fails as "execution of script failed" */
01084                 rc = RPMRC_FAIL;
01085             } else {
01086                 arg1 += psm->countCorrection;
01087                 index = triggerIndices[i];
01088                 if (triggersAlreadyRun == NULL ||
01089                     triggersAlreadyRun[index] == 0)
01090                 {
01091                     rc = runScript(psm, triggeredH, "%trigger", 1,
01092                             triggerProgs + index, triggerScripts[index],
01093                             arg1, arg2);
01094                     if (triggersAlreadyRun != NULL)
01095                         triggersAlreadyRun[index] = 1;
01096                 }
01097             }
01098         }
01099 
01100         triggerIndices = hfd(triggerIndices, tit);
01101         triggerScripts = hfd(triggerScripts, tst);
01102         triggerProgs = hfd(triggerProgs, tpt);
01103 
01104         /*
01105          * Each target/source header pair can only result in a single
01106          * script being run.
01107          */
01108         break;
01109     }
01110 
01111     trigger = rpmdsFree(trigger);
01112 
01113     return rc;
01114 }
01115 
01121 static rpmRC runTriggers(rpmpsm psm)
01122         /*@globals rpmGlobalMacroContext, h_errno,
01123                 fileSystem, internalState @*/
01124         /*@modifies psm, rpmGlobalMacroContext,
01125                 fileSystem, internalState @*/
01126 {
01127     const rpmts ts = psm->ts;
01128     rpmfi fi = psm->fi;
01129     int numPackage = -1;
01130     rpmRC rc = RPMRC_OK;
01131     const char * N = NULL;
01132 
01133     if (psm->te)        /* XXX can't happen */
01134         N = rpmteN(psm->te);
01135 /* XXX: Might need to adjust instance counts for autorollback. */
01136     if (N)              /* XXX can't happen */
01137         numPackage = rpmdbCountPackages(rpmtsGetRdb(ts), N)
01138                                 + psm->countCorrection;
01139     if (numPackage < 0)
01140         return RPMRC_NOTFOUND;
01141 
01142     if (fi != NULL && fi->h != NULL)    /* XXX can't happen */
01143     {   Header triggeredH;
01144         rpmdbMatchIterator mi;
01145         int countCorrection = psm->countCorrection;
01146 
01147         psm->countCorrection = 0;
01148         mi = rpmtsInitIterator(ts, RPMTAG_TRIGGERNAME, N, 0);
01149         while((triggeredH = rpmdbNextIterator(mi)) != NULL)
01150             rc |= handleOneTrigger(psm, fi->h, triggeredH, numPackage, NULL);
01151         mi = rpmdbFreeIterator(mi);
01152         psm->countCorrection = countCorrection;
01153     }
01154 
01155     return rc;
01156 }
01157 
01163 static rpmRC runImmedTriggers(rpmpsm psm)
01164         /*@globals rpmGlobalMacroContext, h_errno,
01165                 fileSystem, internalState @*/
01166         /*@modifies psm, rpmGlobalMacroContext,
01167                 fileSystem, internalState @*/
01168 {
01169     const rpmts ts = psm->ts;
01170     rpmfi fi = psm->fi;
01171     HGE_t hge = fi->hge;
01172     HFD_t hfd = (fi->hfd ? fi->hfd : headerFreeData);
01173     const char ** triggerNames;
01174     int numTriggers;
01175     int_32 * triggerIndices;
01176     rpmTagType tnt, tit;
01177     int numTriggerIndices;
01178     unsigned char * triggersRun;
01179     rpmRC rc = RPMRC_OK;
01180     size_t nb;
01181 
01182     if (fi->h == NULL)  return rc;      /* XXX can't happen */
01183 
01184     if (!(      hge(fi->h, RPMTAG_TRIGGERNAME, &tnt,
01185                         &triggerNames, &numTriggers) &&
01186                 hge(fi->h, RPMTAG_TRIGGERINDEX, &tit,
01187                         &triggerIndices, &numTriggerIndices))
01188         )
01189         return rc;
01190 
01191     nb = sizeof(*triggersRun) * numTriggerIndices;
01192     triggersRun = memset(alloca(nb), 0, nb);
01193 
01194     {   Header sourceH = NULL;
01195         int i;
01196 
01197         for (i = 0; i < numTriggers; i++) {
01198             rpmdbMatchIterator mi;
01199 
01200             if (triggersRun[triggerIndices[i]] != 0) continue;
01201         
01202             mi = rpmtsInitIterator(ts, RPMTAG_NAME, triggerNames[i], 0);
01203 
01204             while((sourceH = rpmdbNextIterator(mi)) != NULL) {
01205                 rc |= handleOneTrigger(psm, sourceH, fi->h,
01206                                 rpmdbGetIteratorCount(mi),
01207                                 triggersRun);
01208             }
01209 
01210             mi = rpmdbFreeIterator(mi);
01211         }
01212     }
01213     triggerIndices = hfd(triggerIndices, tit);
01214     triggerNames = hfd(triggerNames, tnt);
01215     return rc;
01216 }
01217 
01218 /*@observer@*/
01219 static const char * pkgStageString(pkgStage a)
01220         /*@*/
01221 {
01222     switch(a) {
01223     case PSM_UNKNOWN:           return "unknown";
01224 
01225     case PSM_PKGINSTALL:        return "  install";
01226     case PSM_PKGERASE:          return "    erase";
01227     case PSM_PKGCOMMIT:         return "   commit";
01228     case PSM_PKGSAVE:           return "repackage";
01229 
01230     case PSM_INIT:              return "init";
01231     case PSM_PRE:               return "pre";
01232     case PSM_PROCESS:           return "process";
01233     case PSM_POST:              return "post";
01234     case PSM_UNDO:              return "undo";
01235     case PSM_FINI:              return "fini";
01236 
01237     case PSM_CREATE:            return "create";
01238     case PSM_NOTIFY:            return "notify";
01239     case PSM_DESTROY:           return "destroy";
01240     case PSM_COMMIT:            return "commit";
01241 
01242     case PSM_CHROOT_IN:         return "chrootin";
01243     case PSM_CHROOT_OUT:        return "chrootout";
01244     case PSM_SCRIPT:            return "script";
01245     case PSM_TRIGGERS:          return "triggers";
01246     case PSM_IMMED_TRIGGERS:    return "immedtriggers";
01247 
01248     case PSM_RPMIO_FLAGS:       return "rpmioflags";
01249 
01250     case PSM_RPMDB_LOAD:        return "rpmdbload";
01251     case PSM_RPMDB_ADD:         return "rpmdbadd";
01252     case PSM_RPMDB_REMOVE:      return "rpmdbremove";
01253 
01254     default:                    return "???";
01255     }
01256     /*@noteached@*/
01257 }
01258 
01259 rpmpsm XrpmpsmUnlink(rpmpsm psm, const char * msg, const char * fn, unsigned ln)
01260 {
01261     if (psm == NULL) return NULL;
01262 /*@-modfilesys@*/
01263 if (_psm_debug && msg != NULL)
01264 fprintf(stderr, "--> psm %p -- %d %s at %s:%u\n", psm, psm->nrefs, msg, fn, ln);
01265 /*@=modfilesys@*/
01266     psm->nrefs--;
01267     return NULL;
01268 }
01269 
01270 rpmpsm XrpmpsmLink(rpmpsm psm, const char * msg, const char * fn, unsigned ln)
01271 {
01272     if (psm == NULL) return NULL;
01273     psm->nrefs++;
01274 
01275 /*@-modfilesys@*/
01276 if (_psm_debug && msg != NULL)
01277 fprintf(stderr, "--> psm %p ++ %d %s at %s:%u\n", psm, psm->nrefs, msg, fn, ln);
01278 /*@=modfilesys@*/
01279 
01280     /*@-refcounttrans@*/ return psm; /*@=refcounttrans@*/
01281 }
01282 
01283 rpmpsm rpmpsmFree(rpmpsm psm)
01284 {
01285     const char * msg = "rpmpsmFree";
01286     if (psm == NULL)
01287         return NULL;
01288 
01289     if (psm->nrefs > 1)
01290         return rpmpsmUnlink(psm, msg);
01291 
01292 /*@-nullstate@*/
01293     psm->fi = rpmfiFree(psm->fi);
01294 #ifdef  NOTYET
01295     psm->te = rpmteFree(psm->te);
01296 #else
01297     psm->te = NULL;
01298 #endif
01299 /*@-internalglobs@*/
01300     psm->ts = rpmtsFree(psm->ts);
01301 /*@=internalglobs@*/
01302 
01303     psm->sstates = _free(psm->sstates);
01304 
01305     (void) rpmpsmUnlink(psm, msg);
01306 
01307     /*@-refcounttrans -usereleased@*/
01308 /*@-boundswrite@*/
01309     memset(psm, 0, sizeof(*psm));               /* XXX trash and burn */
01310 /*@=boundswrite@*/
01311     psm = _free(psm);
01312     /*@=refcounttrans =usereleased@*/
01313 
01314     return NULL;
01315 /*@=nullstate@*/
01316 }
01317 
01318 rpmpsm rpmpsmNew(rpmts ts, rpmte te, rpmfi fi)
01319 {
01320     const char * msg = "rpmpsmNew";
01321     rpmpsm psm = xcalloc(1, sizeof(*psm));
01322 
01323     if (ts)     psm->ts = rpmtsLink(ts, msg);
01324 #ifdef  NOTYET
01325     if (te)     psm->te = rpmteLink(te, msg);
01326 #else
01327 /*@-assignexpose -temptrans @*/
01328     if (te)     psm->te = te;
01329 /*@=assignexpose =temptrans @*/
01330 #endif
01331     if (fi)     psm->fi = rpmfiLink(fi, msg);
01332 
01333     psm->sstates = xcalloc(RPMSCRIPT_MAX, sizeof(*psm->sstates));
01334 
01335     return rpmpsmLink(psm, msg);
01336 }
01337 
01344 static uint_32 hLoadTID(Header h, int_32 tag)
01345         /*@*/
01346 {
01347     uint_32 val = 0;
01348     int_32 typ = 0;
01349     void * ptr = NULL;
01350     int_32 cnt = 0;
01351 
01352     if (headerGetEntry(h, tag, &typ, &ptr, &cnt)
01353      && typ == RPM_INT32_TYPE && ptr != NULL && cnt == 1)
01354         val = *(uint_32 *)ptr;
01355     ptr = headerFreeData(ptr, typ);
01356     return val;
01357 }
01358 
01366 static int hCopyTag(Header sh, Header th, int_32 tag)
01367         /*@modifies th @*/
01368 {
01369     int_32 typ = 0;
01370     void * ptr = NULL;
01371     int_32 cnt = 0;
01372     int xx = 1;
01373 
01374     if (headerGetEntry(sh, tag, &typ, &ptr, &cnt) && cnt > 0)
01375         xx = headerAddEntry(th, tag, typ, ptr, cnt);
01376 assert(xx);
01377     ptr = headerFreeData(ptr, typ);
01378     return 0;
01379 }
01380 
01387 static int hSaveBlinks(Header h, const struct rpmChainLink_s * blink)
01388         /*@modifies h @*/
01389 {
01390     /*@observer@*/
01391     static const char * chain_end = RPMTE_CHAIN_END;
01392     int ac;
01393     int xx = 1;
01394 
01395     ac = argvCount(blink->NEVRA);
01396     if (ac > 0)
01397         xx = headerAddEntry(h, RPMTAG_BLINKNEVRA, RPM_STRING_ARRAY_TYPE,
01398                         argvData(blink->NEVRA), ac);
01399     else     /* XXX Add an explicit chain terminator on 1st install. */
01400         xx = headerAddEntry(h, RPMTAG_BLINKNEVRA, RPM_STRING_ARRAY_TYPE,
01401                         &chain_end, 1);
01402 assert(xx);
01403     
01404     ac = argvCount(blink->Pkgid);
01405     if (ac > 0) 
01406         xx = headerAddEntry(h, RPMTAG_BLINKPKGID, RPM_STRING_ARRAY_TYPE,
01407                         argvData(blink->Pkgid), ac);
01408     else     /* XXX Add an explicit chain terminator on 1st install. */
01409         xx = headerAddEntry(h, RPMTAG_BLINKPKGID, RPM_STRING_ARRAY_TYPE,
01410                         &chain_end, 1);
01411 assert(xx);
01412 
01413     ac = argvCount(blink->Hdrid);
01414     if (ac > 0)
01415         xx = headerAddEntry(h, RPMTAG_BLINKHDRID, RPM_STRING_ARRAY_TYPE,
01416                         argvData(blink->Hdrid), ac);
01417     else     /* XXX Add an explicit chain terminator on 1st install. */
01418         xx = headerAddEntry(h, RPMTAG_BLINKNEVRA, RPM_STRING_ARRAY_TYPE,
01419                         &chain_end, 1);
01420 assert(xx);
01421 
01422     return 0;
01423 }
01424 
01431 static int hSaveFlinks(Header h, const struct rpmChainLink_s * flink)
01432         /*@modifies h @*/
01433 {
01434 #ifdef  NOTYET
01435     /*@observer@*/
01436     static const char * chain_end = RPMTE_CHAIN_END;
01437 #endif
01438     int ac;
01439     int xx = 1;
01440 
01441     /* Save backward links into header upgrade chain. */
01442     ac = argvCount(flink->NEVRA);
01443     if (ac > 0)
01444         xx = headerAddEntry(h, RPMTAG_FLINKNEVRA, RPM_STRING_ARRAY_TYPE,
01445                         argvData(flink->NEVRA), ac);
01446 #ifdef  NOTYET  /* XXX is an explicit flink terminator needed? */
01447     else     /* XXX Add an explicit chain terminator on 1st install. */
01448         xx = headerAddEntry(h, RPMTAG_FLINKNEVRA, RPM_STRING_ARRAY_TYPE,
01449                         &chain_end, 1);
01450 #endif
01451 assert(xx);
01452 
01453     ac = argvCount(flink->Pkgid);
01454     if (ac > 0) 
01455         xx = headerAddEntry(h, RPMTAG_FLINKPKGID, RPM_STRING_ARRAY_TYPE,
01456                         argvData(flink->Pkgid), ac);
01457 #ifdef  NOTYET  /* XXX is an explicit flink terminator needed? */
01458     else     /* XXX Add an explicit chain terminator on 1st install. */
01459         xx = headerAddEntry(h, RPMTAG_FLINKPKGID, RPM_STRING_ARRAY_TYPE,
01460                         &chain_end, 1);
01461 #endif
01462 assert(xx);
01463 
01464     ac = argvCount(flink->Hdrid);
01465     if (ac > 0)
01466         xx = headerAddEntry(h, RPMTAG_FLINKHDRID, RPM_STRING_ARRAY_TYPE,
01467                         argvData(flink->Hdrid), ac);
01468 #ifdef  NOTYET  /* XXX is an explicit flink terminator needed? */
01469     else     /* XXX Add an explicit chain terminator on 1st install. */
01470         xx = headerAddEntry(h, RPMTAG_FLINKNEVRA, RPM_STRING_ARRAY_TYPE,
01471                         &chain_end, 1);
01472 #endif
01473 assert(xx);
01474 
01475     return 0;
01476 }
01477 
01485 static int populateInstallHeader(const rpmts ts, const rpmte te, rpmfi fi)
01486         /*@modifies fi @*/
01487 {
01488     uint_32 tscolor = rpmtsColor(ts);
01489     uint_32 tecolor = rpmteColor(te);
01490     int_32 installTime = (int_32) time(NULL);
01491     int fc = rpmfiFC(fi);
01492     const char * origin;
01493     int xx = 1;
01494 
01495 assert(fi->h != NULL);
01496     if (fi->fstates != NULL && fc > 0)
01497         xx = headerAddEntry(fi->h, RPMTAG_FILESTATES, RPM_CHAR_TYPE,
01498                                 fi->fstates, fc);
01499 assert(xx);
01500 
01501     xx = headerAddEntry(fi->h, RPMTAG_INSTALLTIME, RPM_INT32_TYPE,
01502                         &installTime, 1);
01503 assert(xx);
01504 
01505     xx = headerAddEntry(fi->h, RPMTAG_INSTALLCOLOR, RPM_INT32_TYPE,
01506                         &tscolor, 1);
01507 assert(xx);
01508 
01509     /* XXX FIXME: add preferred color at install. */
01510 
01511     xx = headerAddEntry(fi->h, RPMTAG_PACKAGECOLOR, RPM_INT32_TYPE,
01512                                 &tecolor, 1);
01513 assert(xx);
01514 
01515     /* Add the header's origin (i.e. URL) */
01516     origin = headerGetOrigin(fi->h);
01517     if (origin != NULL)
01518         xx = headerAddEntry(fi->h, RPMTAG_PACKAGEORIGIN, RPM_STRING_TYPE,
01519                                 origin, 1);
01520 assert(xx);
01521 
01522     /* XXX Don't clobber forward/backward upgrade chain on rollbacks */
01523     if (rpmtsType(ts) != RPMTRANS_TYPE_ROLLBACK)
01524         xx = hSaveBlinks(fi->h, &te->blink);
01525 
01526     return 0;
01527 }
01528 
01529 static void * rpmpsmThread(void * arg)
01530         /*@globals rpmGlobalMacroContext, h_errno, fileSystem, internalState @*/
01531         /*@modifies arg, rpmGlobalMacroContext, fileSystem, internalState @*/
01532 {
01533     rpmpsm psm = arg;
01534 /*@-unqualifiedtrans@*/
01535     return ((void *) rpmpsmStage(psm, psm->nstage));
01536 /*@=unqualifiedtrans@*/
01537 }
01538 
01539 static int rpmpsmNext(rpmpsm psm, pkgStage nstage)
01540         /*@globals rpmGlobalMacroContext, h_errno, fileSystem, internalState @*/
01541         /*@modifies psm, rpmGlobalMacroContext, fileSystem, internalState @*/
01542 {
01543     psm->nstage = nstage;
01544     if (_psm_threads)
01545         return rpmsqJoin( rpmsqThread(rpmpsmThread, psm) );
01546     return rpmpsmStage(psm, psm->nstage);
01547 }
01548 
01553 /*@-bounds -nullpass@*/ /* FIX: testing null annotation for fi->h */
01554 rpmRC rpmpsmStage(rpmpsm psm, pkgStage stage)
01555 {
01556     const rpmts ts = psm->ts;
01557     uint_32 tscolor = rpmtsColor(ts);
01558     rpmfi fi = psm->fi;
01559     HGE_t hge = fi->hge;
01560     HAE_t hae = fi->hae;
01561     HFD_t hfd = (fi->hfd ? fi->hfd : headerFreeData);
01562     rpmRC rc = psm->rc;
01563     int saveerrno;
01564     int xx;
01565 
01566 /*@-branchstate@*/
01567     switch (stage) {
01568     case PSM_UNKNOWN:
01569         break;
01570     case PSM_INIT:
01571         rpmMessage(RPMMESS_DEBUG, _("%s: %s has %d files, test = %d\n"),
01572                 psm->stepName, rpmteNEVR(psm->te),
01573                 rpmfiFC(fi), (rpmtsFlags(ts) & RPMTRANS_FLAG_TEST));
01574 
01575         /*
01576          * When we run scripts, we pass an argument which is the number of
01577          * versions of this package that will be installed when we are
01578          * finished.
01579          */
01580         psm->npkgs_installed = rpmdbCountPackages(rpmtsGetRdb(ts), rpmteN(psm->te));
01581         if (psm->npkgs_installed < 0) {
01582             rc = RPMRC_FAIL;
01583             break;
01584         }
01585 
01586         /* Adjust package count on rollback downgrade. */
01587 assert(psm->te != NULL);
01588         if (rpmtsType(ts) == RPMTRANS_TYPE_AUTOROLLBACK &&
01589             (psm->goal & ~(PSM_PKGSAVE|PSM_PKGERASE)))
01590         {
01591             if (psm->te->downgrade)
01592                 psm->npkgs_installed--;
01593         }
01594 
01595         if (psm->goal == PSM_PKGINSTALL) {
01596             int fc = rpmfiFC(fi);
01597             const char * hdrid;
01598 
01599             /* Add per-transaction data to install header. */
01600             xx = populateInstallHeader(ts, psm->te, fi);
01601 
01602             psm->scriptArg = psm->npkgs_installed + 1;
01603 
01604 assert(psm->mi == NULL);
01605             hdrid = rpmteHdrid(psm->te);
01606             if (hdrid != NULL) {
01607                 /* XXX should use RPMTAG_HDRID not RPMTAG_SHA1HEADER */
01608                 psm->mi = rpmtsInitIterator(ts, RPMTAG_SHA1HEADER, hdrid, 0);
01609             } else {
01610                 psm->mi = rpmtsInitIterator(ts, RPMTAG_NAME, rpmteN(psm->te),0);
01611                 xx = rpmdbSetIteratorRE(psm->mi, RPMTAG_EPOCH, RPMMIRE_STRCMP,
01612                         rpmteE(psm->te));
01613                 xx = rpmdbSetIteratorRE(psm->mi, RPMTAG_VERSION, RPMMIRE_STRCMP,
01614                         rpmteV(psm->te));
01615                 xx = rpmdbSetIteratorRE(psm->mi, RPMTAG_RELEASE, RPMMIRE_STRCMP,
01616                         rpmteR(psm->te));
01617                 if (tscolor) {
01618                     xx = rpmdbSetIteratorRE(psm->mi,RPMTAG_ARCH, RPMMIRE_STRCMP,
01619                         rpmteA(psm->te));
01620                     xx = rpmdbSetIteratorRE(psm->mi, RPMTAG_OS, RPMMIRE_STRCMP,
01621                         rpmteO(psm->te));
01622                 }
01623             }
01624 
01625             while ((psm->oh = rpmdbNextIterator(psm->mi)) != NULL) {
01626                 fi->record = rpmdbGetIteratorOffset(psm->mi);
01627                 psm->oh = NULL;
01628                 /*@loopbreak@*/ break;
01629             }
01630             psm->mi = rpmdbFreeIterator(psm->mi);
01631 
01632             rc = RPMRC_OK;
01633 
01634             /* XXX lazy alloc here may need to be done elsewhere. */
01635             if (fi->fstates == NULL && fc > 0) {
01636                 fi->fstates = xmalloc(sizeof(*fi->fstates) * fc);
01637                 memset(fi->fstates, RPMFILE_STATE_NORMAL, fc);
01638             }
01639 
01640             if (rpmtsFlags(ts) & RPMTRANS_FLAG_JUSTDB)  break;
01641             if (fc <= 0)                                break;
01642         
01643             /*
01644              * Old format relocatable packages need the entire default
01645              * prefix stripped to form the cpio list, while all other packages
01646              * need the leading / stripped.
01647              */
01648             {   const char * p;
01649                 xx = hge(fi->h, RPMTAG_DEFAULTPREFIX, NULL, &p, NULL);
01650                 fi->striplen = (xx ? strlen(p) + 1 : 1);
01651             }
01652             fi->mapflags =
01653                 CPIO_MAP_PATH | CPIO_MAP_MODE | CPIO_MAP_UID | CPIO_MAP_GID | (fi->mapflags & CPIO_SBIT_CHECK);
01654         
01655             if (headerIsEntry(fi->h, RPMTAG_ORIGBASENAMES))
01656                 rpmfiBuildFNames(fi->h, RPMTAG_ORIGBASENAMES, &fi->apath, NULL);
01657             else
01658                 rpmfiBuildFNames(fi->h, RPMTAG_BASENAMES, &fi->apath, NULL);
01659         
01660             if (fi->fuser == NULL)
01661                 xx = hge(fi->h, RPMTAG_FILEUSERNAME, NULL,
01662                                 &fi->fuser, NULL);
01663             if (fi->fgroup == NULL)
01664                 xx = hge(fi->h, RPMTAG_FILEGROUPNAME, NULL,
01665                                 &fi->fgroup, NULL);
01666             rc = RPMRC_OK;
01667         }
01668         if (psm->goal == PSM_PKGERASE || psm->goal == PSM_PKGSAVE) {
01669             psm->scriptArg = psm->npkgs_installed - 1;
01670         
01671             /* Retrieve installed header. */
01672             rc = rpmpsmNext(psm, PSM_RPMDB_LOAD);
01673 if (rc == RPMRC_OK)
01674 if (psm->te)
01675 psm->te->h = headerLink(fi->h);
01676         }
01677         if (psm->goal == PSM_PKGSAVE) {
01678             /* Open output package for writing. */
01679             {   char tiddn[32];
01680                 const char * bfmt;
01681                 const char * pkgdn;
01682                 const char * pkgbn;
01683 
01684                 xx = snprintf(tiddn, sizeof(tiddn), "%d", rpmtsGetTid(ts));
01685                 bfmt = rpmGetPath(tiddn, "/", "%{_repackage_name_fmt}", NULL);
01686                 pkgbn = headerSprintf(fi->h, bfmt,
01687                                         rpmTagTable, rpmHeaderFormats, NULL);
01688                 bfmt = _free(bfmt);
01689                 psm->pkgURL = rpmGenPath("%{?_repackage_root}",
01690                                          "%{?_repackage_dir}",
01691                                         pkgbn);
01692                 pkgbn = _free(pkgbn);
01693                 (void) urlPath(psm->pkgURL, &psm->pkgfn);
01694                 pkgdn = dirname(xstrdup(psm->pkgfn));
01695                 rc = rpmMkdirPath(pkgdn, "_repackage_dir");
01696                 pkgdn = _free(pkgdn);
01697                 if (rc == RPMRC_FAIL)
01698                     break;
01699                 psm->fd = Fopen(psm->pkgfn, "w");
01700                 if (psm->fd == NULL || Ferror(psm->fd)) {
01701                     rc = RPMRC_FAIL;
01702                     break;
01703                 }
01704             }
01705         }
01706         break;
01707     case PSM_PRE:
01708         if (rpmtsFlags(ts) & RPMTRANS_FLAG_TEST)        break;
01709 
01710 /* XXX insure that trigger index is opened before entering chroot. */
01711 #ifdef  NOTYET
01712  { static int oneshot = 0;
01713    dbiIndex dbi;
01714    if (!oneshot) {
01715      dbi = dbiOpen(rpmtsGetRdb(ts), RPMTAG_TRIGGERNAME, 0);
01716      oneshot++;
01717    }
01718  }
01719 #endif
01720 
01721         /* Change root directory if requested and not already done. */
01722         rc = rpmpsmNext(psm, PSM_CHROOT_IN);
01723 
01724         if (psm->goal == PSM_PKGINSTALL) {
01725             psm->scriptTag = RPMTAG_PREIN;
01726             psm->progTag = RPMTAG_PREINPROG;
01727             psm->sense = RPMSENSE_TRIGGERPREIN;
01728             psm->countCorrection = 0;   /* XXX is this correct?!? */
01729 
01730             if (!(rpmtsFlags(ts) & RPMTRANS_FLAG_NOTRIGGERPREIN)) {
01731 
01732                 /* Run triggers in other package(s) this package sets off. */
01733                 rc = rpmpsmNext(psm, PSM_TRIGGERS);
01734                 if (rc) break;
01735 
01736                 /* Run triggers in this package other package(s) set off. */
01737                 rc = rpmpsmNext(psm, PSM_IMMED_TRIGGERS);
01738                 if (rc) break;
01739             }
01740 
01741             if (!(rpmtsFlags(ts) & RPMTRANS_FLAG_NOPRE)) {
01742                 rc = rpmpsmNext(psm, PSM_SCRIPT);
01743                 if (rc != RPMRC_OK) {
01744                     rpmError(RPMERR_SCRIPT,
01745                         _("%s: %s scriptlet failed (%d), skipping %s\n"),
01746                         psm->stepName, tag2sln(psm->scriptTag), rc,
01747                         rpmteNEVR(psm->te));
01748                     break;
01749                 }
01750             }
01751         }
01752 
01753         if (psm->goal == PSM_PKGERASE) {
01754             psm->scriptTag = RPMTAG_PREUN;
01755             psm->progTag = RPMTAG_PREUNPROG;
01756             psm->sense = RPMSENSE_TRIGGERUN;
01757             psm->countCorrection = -1;
01758 
01759             if (!(rpmtsFlags(ts) & RPMTRANS_FLAG_NOTRIGGERUN)) {
01760                 /* Run triggers in this package other package(s) set off. */
01761                 rc = rpmpsmNext(psm, PSM_IMMED_TRIGGERS);
01762                 if (rc) break;
01763 
01764                 /* Run triggers in other package(s) this package sets off. */
01765                 rc = rpmpsmNext(psm, PSM_TRIGGERS);
01766                 if (rc) break;
01767             }
01768 
01769             if (!(rpmtsFlags(ts) & RPMTRANS_FLAG_NOPREUN))
01770                 rc = rpmpsmNext(psm, PSM_SCRIPT);
01771         }
01772         if (psm->goal == PSM_PKGSAVE) {
01773             int noArchiveSize = 0;
01774             const char * origin;
01775 
01776             /* Regenerate original header. */
01777             {   void * uh = NULL;
01778                 int_32 uht, uhc;
01779 
01780                 /* Save originnal header's origin (i.e. URL) */
01781                 origin = NULL;
01782                 xx = headerGetEntry(fi->h, RPMTAG_PACKAGEORIGIN, NULL,
01783                         &origin, NULL);
01784 
01785                 /* Retrieve original header blob. */
01786                 if (headerGetEntry(fi->h, RPMTAG_HEADERIMMUTABLE, &uht, &uh, &uhc)) {
01787                     psm->oh = headerCopyLoad(uh);
01788                     uh = hfd(uh, uht);
01789                 } else
01790                 if (headerGetEntry(fi->h, RPMTAG_HEADERIMAGE, &uht, &uh, &uhc))
01791                 {
01792                     HeaderIterator hi;
01793                     int_32 tag, type, count;
01794                     hPTR_t ptr;
01795                     Header oh;
01796 
01797                     /* Load the original header from the blob. */
01798                     oh = headerCopyLoad(uh);
01799 
01800                     /* XXX this is headerCopy w/o headerReload() */
01801                     psm->oh = headerNew();
01802 
01803                     /*@-branchstate@*/
01804                     for (hi = headerInitIterator(oh);
01805                         headerNextIterator(hi, &tag, &type, &ptr, &count);
01806                         ptr = headerFreeData((void *)ptr, type))
01807                     {
01808                         if (tag == RPMTAG_ARCHIVESIZE)
01809                             noArchiveSize = 1;
01810                         if (ptr) xx = hae(psm->oh, tag, type, ptr, count);
01811                     }
01812                     hi = headerFreeIterator(hi);
01813                     /*@=branchstate@*/
01814 
01815                     oh = headerFree(oh);
01816                     uh = hfd(uh, uht);
01817                 } else
01818                     break;      /* XXX shouldn't ever happen */
01819             }
01820 
01821             /* Retrieve type of payload compression. */
01822             /*@-nullstate@*/    /* FIX: psm->oh may be NULL */
01823             rc = rpmpsmNext(psm, PSM_RPMIO_FLAGS);
01824             /*@=nullstate@*/
01825 
01826             /* Write the lead section into the package. */
01827             {   struct rpmlead lead;
01828 
01829                 memset(&lead, 0, sizeof(lead));
01830                 /* XXX Set package version conditioned on noDirTokens. */
01831                 lead.major = 3;
01832                 lead.minor = 0;
01833                 lead.type = RPMLEAD_BINARY;
01834 
01835                 /* XXX DIEDIEDIE: legacy values were not 0. */
01836                 lead.archnum = 0;
01837                 lead.osnum = 0;
01838                 lead.signature_type = RPMSIGTYPE_HEADERSIG;
01839 
01840                 strncpy(lead.name, rpmteNEVR(psm->te), sizeof(lead.name));
01841 
01842                 rc = writeLead(psm->fd, &lead);
01843                 if (rc != RPMRC_OK) {
01844                     rpmError(RPMERR_NOSPACE, _("Unable to write package: %s\n"),
01845                          Fstrerror(psm->fd));
01846                     break;
01847                 }
01848             }
01849 
01850             /* Write the signature section into the package. */
01851             /* XXX rpm-4.1 and later has archive size in signature header. */
01852             {   Header sigh = headerRegenSigHeader(fi->h, noArchiveSize);
01853                 /* Reallocate the signature into one contiguous region. */
01854                 sigh = headerReload(sigh, RPMTAG_HEADERSIGNATURES);
01855                 if (sigh == NULL) {
01856                     rpmError(RPMERR_NOSPACE, _("Unable to reload signature header\n"));
01857                     rc = RPMRC_FAIL;
01858                     break;
01859                 }
01860                 rc = rpmWriteSignature(psm->fd, sigh);
01861                 sigh = rpmFreeSignature(sigh);
01862                 if (rc) break;
01863             }
01864 
01865             /* Add remove transaction id to header. */
01866             if (psm->oh != NULL)
01867             {   int_32 tid = rpmtsGetTid(ts);
01868 
01869                 xx = hae(psm->oh, RPMTAG_REMOVETID, RPM_INT32_TYPE,
01870                                 &tid, 1);
01871 
01872                 /* Add original header's origin (i.e. URL) */
01873                 if (origin != NULL)
01874                     xx = hae(psm->oh, RPMTAG_PACKAGEORIGIN, RPM_STRING_TYPE,
01875                                 origin, 1);
01876 
01877                 /* Copy upgrade chain link tags. */
01878                 xx = hCopyTag(fi->h, psm->oh, RPMTAG_INSTALLTID);
01879                 xx = hCopyTag(fi->h, psm->oh, RPMTAG_BLINKPKGID);
01880                 xx = hCopyTag(fi->h, psm->oh, RPMTAG_BLINKHDRID);
01881                 xx = hCopyTag(fi->h, psm->oh, RPMTAG_BLINKNEVRA);
01882 
01883 assert(psm->te != NULL);
01884                 xx = hSaveFlinks(psm->oh, &psm->te->flink);
01885             }
01886 
01887             /* Write the metadata section into the package. */
01888             rc = headerWrite(psm->fd, psm->oh, HEADER_MAGIC_YES);
01889             if (rc) break;
01890         }
01891         break;
01892     case PSM_PROCESS:
01893         if (rpmtsFlags(ts) & RPMTRANS_FLAG_TEST)        break;
01894 
01895         if (psm->goal == PSM_PKGINSTALL) {
01896 
01897             if (rpmtsFlags(ts) & RPMTRANS_FLAG_JUSTDB)  break;
01898 
01899             /* XXX Synthesize callbacks for packages with no files. */
01900             if (rpmfiFC(fi) <= 0) {
01901                 void * ptr;
01902                 ptr = rpmtsNotify(ts, fi->te, RPMCALLBACK_INST_START, 0, 100);
01903                 ptr = rpmtsNotify(ts, fi->te, RPMCALLBACK_INST_PROGRESS, 100, 100);
01904                 break;
01905             }
01906 
01907             /* Retrieve type of payload compression. */
01908             rc = rpmpsmNext(psm, PSM_RPMIO_FLAGS);
01909 
01910             if (rpmteFd(fi->te) == NULL) {      /* XXX can't happen */
01911                 rc = RPMRC_FAIL;
01912                 break;
01913             }
01914 
01915             /*@-nullpass@*/     /* LCL: fi->fd != NULL here. */
01916             psm->cfd = Fdopen(fdDup(Fileno(rpmteFd(fi->te))), psm->rpmio_flags);
01917             /*@=nullpass@*/
01918             if (psm->cfd == NULL) {     /* XXX can't happen */
01919                 rc = RPMRC_FAIL;
01920                 break;
01921             }
01922 
01923             rc = fsmSetup(fi->fsm, FSM_PKGINSTALL, psm->payload_format, ts, fi,
01924                         psm->cfd, NULL, &psm->failedFile);
01925             (void) rpmswAdd(rpmtsOp(ts, RPMTS_OP_UNCOMPRESS),
01926                         fdstat_op(psm->cfd, FDSTAT_READ));
01927             (void) rpmswAdd(rpmtsOp(ts, RPMTS_OP_DIGEST),
01928                         fdstat_op(psm->cfd, FDSTAT_DIGEST));
01929             xx = fsmTeardown(fi->fsm);
01930 
01931             saveerrno = errno; /* XXX FIXME: Fclose with libio destroys errno */
01932             xx = Fclose(psm->cfd);
01933             psm->cfd = NULL;
01934             /*@-mods@*/
01935             errno = saveerrno; /* XXX FIXME: Fclose with libio destroys errno */
01936             /*@=mods@*/
01937 
01938             if (!rc)
01939                 rc = rpmpsmNext(psm, PSM_COMMIT);
01940 
01941             /* XXX make sure progress is closed out */
01942             psm->what = RPMCALLBACK_INST_PROGRESS;
01943             psm->amount = (fi->archiveSize ? fi->archiveSize : 100);
01944             psm->total = psm->amount;
01945             xx = rpmpsmNext(psm, PSM_NOTIFY);
01946 
01947             if (rc) {
01948                 rpmError(RPMERR_CPIO,
01949                         _("unpacking of archive failed%s%s: %s\n"),
01950                         (psm->failedFile != NULL ? _(" on file ") : ""),
01951                         (psm->failedFile != NULL ? psm->failedFile : ""),
01952                         cpioStrerror(rc));
01953                 rc = RPMRC_FAIL;
01954 
01955                 /* XXX notify callback on error. */
01956                 psm->what = RPMCALLBACK_UNPACK_ERROR;
01957                 psm->amount = 0;
01958                 psm->total = 0;
01959                 xx = rpmpsmNext(psm, PSM_NOTIFY);
01960 
01961                 break;
01962             }
01963         }
01964         if (psm->goal == PSM_PKGERASE) {
01965             int fc = rpmfiFC(fi);
01966 
01967             if (rpmtsFlags(ts) & RPMTRANS_FLAG_JUSTDB)  break;
01968             if (rpmtsFlags(ts) & RPMTRANS_FLAG_APPLYONLY)       break;
01969             if (fc <= 0)                                break;
01970 
01971             psm->what = RPMCALLBACK_UNINST_START;
01972             psm->amount = fc;           /* XXX W2DO? looks wrong. */
01973             psm->total = fc;
01974             xx = rpmpsmNext(psm, PSM_NOTIFY);
01975 
01976             rc = fsmSetup(fi->fsm, FSM_PKGERASE, psm->payload_format, ts, fi,
01977                         NULL, NULL, &psm->failedFile);
01978             xx = fsmTeardown(fi->fsm);
01979 
01980             psm->what = RPMCALLBACK_UNINST_STOP;
01981             psm->amount = 0;            /* XXX W2DO? looks wrong. */
01982             psm->total = fc;
01983             xx = rpmpsmNext(psm, PSM_NOTIFY);
01984 
01985         }
01986         if (psm->goal == PSM_PKGSAVE) {
01987             fileAction * actions = fi->actions;
01988             fileAction action = fi->action;
01989 
01990             fi->action = FA_COPYOUT;
01991             fi->actions = NULL;
01992 
01993             if (psm->fd == NULL) {      /* XXX can't happen */
01994                 rc = RPMRC_FAIL;
01995                 break;
01996             }
01997             /*@-nullpass@*/     /* FIX: fdDup mey return NULL. */
01998             xx = Fflush(psm->fd);
01999             psm->cfd = Fdopen(fdDup(Fileno(psm->fd)), psm->rpmio_flags);
02000             /*@=nullpass@*/
02001             if (psm->cfd == NULL) {     /* XXX can't happen */
02002                 rc = RPMRC_FAIL;
02003                 break;
02004             }
02005 
02006             rc = fsmSetup(fi->fsm, FSM_PKGBUILD, psm->payload_format, ts, fi,
02007                         psm->cfd, NULL, &psm->failedFile);
02008             (void) rpmswAdd(rpmtsOp(ts, RPMTS_OP_COMPRESS),
02009                         fdstat_op(psm->cfd, FDSTAT_WRITE));
02010             (void) rpmswAdd(rpmtsOp(ts, RPMTS_OP_DIGEST),
02011                         fdstat_op(psm->cfd, FDSTAT_DIGEST));
02012             xx = fsmTeardown(fi->fsm);
02013 
02014             saveerrno = errno; /* XXX FIXME: Fclose with libio destroys errno */
02015             xx = Fclose(psm->cfd);
02016             psm->cfd = NULL;
02017             /*@-mods@*/
02018             errno = saveerrno;
02019             /*@=mods@*/
02020 
02021             /* XXX make sure progress is closed out */
02022             psm->what = RPMCALLBACK_INST_PROGRESS;
02023             psm->amount = (fi->archiveSize ? fi->archiveSize : 100);
02024             psm->total = psm->amount;
02025             xx = rpmpsmNext(psm, PSM_NOTIFY);
02026 
02027             fi->action = action;
02028             fi->actions = actions;
02029         }
02030         break;
02031     case PSM_POST:
02032         if (rpmtsFlags(ts) & RPMTRANS_FLAG_TEST)        break;
02033 
02034         if (psm->goal == PSM_PKGINSTALL) {
02035 
02036             /*
02037              * If this header has already been installed, remove it from
02038              * the database before adding the new header.
02039              */
02040             if (fi->record && !(rpmtsFlags(ts) & RPMTRANS_FLAG_APPLYONLY)) {
02041                 rc = rpmpsmNext(psm, PSM_RPMDB_REMOVE);
02042                 if (rc) break;
02043             }
02044 
02045             rc = rpmpsmNext(psm, PSM_RPMDB_ADD);
02046             if (rc) break;
02047 
02048             psm->scriptTag = RPMTAG_POSTIN;
02049             psm->progTag = RPMTAG_POSTINPROG;
02050             psm->sense = RPMSENSE_TRIGGERIN;
02051             psm->countCorrection = 0;
02052 
02053             if (!(rpmtsFlags(ts) & RPMTRANS_FLAG_NOPOST)) {
02054                 rc = rpmpsmNext(psm, PSM_SCRIPT);
02055                 if (rc) break;
02056             }
02057             if (!(rpmtsFlags(ts) & RPMTRANS_FLAG_NOTRIGGERIN)) {
02058                 /* Run triggers in other package(s) this package sets off. */
02059                 rc = rpmpsmNext(psm, PSM_TRIGGERS);
02060                 if (rc) break;
02061 
02062                 /* Run triggers in this package other package(s) set off. */
02063                 rc = rpmpsmNext(psm, PSM_IMMED_TRIGGERS);
02064                 if (rc) break;
02065             }
02066 
02067             if (!(rpmtsFlags(ts) & RPMTRANS_FLAG_APPLYONLY))
02068                 rc = markReplacedFiles(psm);
02069 
02070         }
02071         if (psm->goal == PSM_PKGERASE) {
02072 
02073             psm->scriptTag = RPMTAG_POSTUN;
02074             psm->progTag = RPMTAG_POSTUNPROG;
02075             psm->sense = RPMSENSE_TRIGGERPOSTUN;
02076             psm->countCorrection = -1;
02077 
02078             if (!(rpmtsFlags(ts) & RPMTRANS_FLAG_NOPOSTUN)) {
02079                 rc = rpmpsmNext(psm, PSM_SCRIPT);
02080                 if (rc) break;
02081             }
02082 
02083             if (!(rpmtsFlags(ts) & RPMTRANS_FLAG_NOTRIGGERPOSTUN)) {
02084                 /* Run triggers in other package(s) this package sets off. */
02085                 rc = rpmpsmNext(psm, PSM_TRIGGERS);
02086                 if (rc) break;
02087 
02088                 /* Run triggers in this package other package(s) set off. */
02089                 rc = rpmpsmNext(psm, PSM_IMMED_TRIGGERS);
02090                 if (rc) break;
02091             }
02092 
02093             if (!(rpmtsFlags(ts) & RPMTRANS_FLAG_APPLYONLY))
02094                 rc = rpmpsmNext(psm, PSM_RPMDB_REMOVE);
02095         }
02096         if (psm->goal == PSM_PKGSAVE) {
02097         }
02098 
02099         /* Restore root directory if changed. */
02100         xx = rpmpsmNext(psm, PSM_CHROOT_OUT);
02101         break;
02102     case PSM_UNDO:
02103         break;
02104     case PSM_FINI:
02105         /* Restore root directory if changed. */
02106         xx = rpmpsmNext(psm, PSM_CHROOT_OUT);
02107 
02108         if (psm->fd != NULL) {
02109             saveerrno = errno; /* XXX FIXME: Fclose with libio destroys errno */
02110             xx = Fclose(psm->fd);
02111             psm->fd = NULL;
02112             /*@-mods@*/
02113             errno = saveerrno;
02114             /*@=mods@*/
02115         }
02116 
02117         if (psm->goal == PSM_PKGSAVE) {
02118             if (!rc && ts && ts->notify == NULL) {
02119                 rpmMessage(RPMMESS_VERBOSE, _("Wrote: %s\n"),
02120                         (psm->pkgURL ? psm->pkgURL : "???"));
02121             }
02122         }
02123 
02124         if (rc) {
02125             if (psm->failedFile)
02126                 rpmError(RPMERR_CPIO,
02127                         _("%s failed on file %s: %s\n"),
02128                         psm->stepName, psm->failedFile, cpioStrerror(rc));
02129             else
02130                 rpmError(RPMERR_CPIO, _("%s failed: %s\n"),
02131                         psm->stepName, cpioStrerror(rc));
02132 
02133             /* XXX notify callback on error. */
02134             psm->what = RPMCALLBACK_CPIO_ERROR;
02135             psm->amount = 0;
02136             psm->total = 0;
02137             /*@-nullstate@*/ /* FIX: psm->fd may be NULL. */
02138             xx = rpmpsmNext(psm, PSM_NOTIFY);
02139             /*@=nullstate@*/
02140         }
02141 
02142 /*@-branchstate@*/
02143         if (psm->goal == PSM_PKGERASE || psm->goal == PSM_PKGSAVE) {
02144 if (psm->te != NULL)
02145 if (psm->te->h != NULL)
02146 psm->te->h = headerFree(psm->te->h);
02147             if (fi->h != NULL)
02148                 fi->h = headerFree(fi->h);
02149         }
02150 /*@=branchstate@*/
02151         psm->oh = headerFree(psm->oh);
02152         psm->pkgURL = _free(psm->pkgURL);
02153         psm->rpmio_flags = _free(psm->rpmio_flags);
02154         psm->payload_format = _free(psm->payload_format);
02155         psm->failedFile = _free(psm->failedFile);
02156 
02157         fi->fgroup = hfd(fi->fgroup, -1);
02158         fi->fuser = hfd(fi->fuser, -1);
02159         fi->apath = _free(fi->apath);
02160         fi->fstates = _free(fi->fstates);
02161         break;
02162 
02163     case PSM_PKGINSTALL:
02164     case PSM_PKGERASE:
02165     case PSM_PKGSAVE:
02166         psm->goal = stage;
02167         psm->rc = RPMRC_OK;
02168         psm->stepName = pkgStageString(stage);
02169 
02170         rc = rpmpsmNext(psm, PSM_INIT);
02171         if (!rc) rc = rpmpsmNext(psm, PSM_PRE);
02172         if (!rc) rc = rpmpsmNext(psm, PSM_PROCESS);
02173         if (!rc) rc = rpmpsmNext(psm, PSM_POST);
02174         xx = rpmpsmNext(psm, PSM_FINI);
02175         break;
02176     case PSM_PKGCOMMIT:
02177         break;
02178 
02179     case PSM_CREATE:
02180         break;
02181     case PSM_NOTIFY:
02182     {   void * ptr;
02183 /*@-nullpass@*/ /* FIX: psm->te may be NULL */
02184         ptr = rpmtsNotify(ts, psm->te, psm->what, psm->amount, psm->total);
02185 /*@-nullpass@*/
02186     }   break;
02187     case PSM_DESTROY:
02188         break;
02189     case PSM_COMMIT:
02190         if (!(rpmtsFlags(ts) & RPMTRANS_FLAG_PKGCOMMIT)) break;
02191         if (rpmtsFlags(ts) & RPMTRANS_FLAG_APPLYONLY) break;
02192 
02193         rc = fsmSetup(fi->fsm, FSM_PKGCOMMIT, psm->payload_format, ts, fi,
02194                         NULL, NULL, &psm->failedFile);
02195         xx = fsmTeardown(fi->fsm);
02196         break;
02197 
02198     case PSM_CHROOT_IN:
02199     {   const char * rootDir = rpmtsRootDir(ts);
02200         /* Change root directory if requested and not already done. */
02201         if (rootDir != NULL && !(rootDir[0] == '/' && rootDir[1] == '\0')
02202          && !rpmtsChrootDone(ts) && !psm->chrootDone)
02203         {
02204             static int _pw_loaded = 0;
02205             static int _gr_loaded = 0;
02206 
02207             if (!_pw_loaded) {
02208                 (void)getpwnam("root");
02209                 endpwent();
02210                 _pw_loaded++;
02211             }
02212             if (!_gr_loaded) {
02213                 (void)getgrnam("root");
02214                 endgrent();
02215                 _gr_loaded++;
02216             }
02217 
02218             xx = Chdir("/");
02219             /*@-superuser@*/
02220             if (rootDir != NULL && strcmp(rootDir, "/") && *rootDir == '/')
02221                 rc = Chroot(rootDir);
02222             /*@=superuser@*/
02223             psm->chrootDone = 1;
02224             (void) rpmtsSetChrootDone(ts, 1);
02225         }
02226     }   break;
02227     case PSM_CHROOT_OUT:
02228         /* Restore root directory if changed. */
02229         if (psm->chrootDone) {
02230             const char * rootDir = rpmtsRootDir(ts);
02231             const char * currDir = rpmtsCurrDir(ts);
02232             /*@-superuser@*/
02233             if (rootDir != NULL && strcmp(rootDir, "/") && *rootDir == '/')
02234                 rc = Chroot(".");
02235             /*@=superuser@*/
02236             psm->chrootDone = 0;
02237             (void) rpmtsSetChrootDone(ts, 0);
02238             if (currDir != NULL)        /* XXX can't happen */
02239                 xx = Chdir(currDir);
02240         }
02241         break;
02242     case PSM_SCRIPT:    /* Run current package scriptlets. */
02243         rc = runInstScript(psm);
02244         break;
02245     case PSM_TRIGGERS:
02246         /* Run triggers in other package(s) this package sets off. */
02247         if (rpmtsFlags(ts) & RPMTRANS_FLAG_TEST)        break;
02248         rc = runTriggers(psm);
02249         break;
02250     case PSM_IMMED_TRIGGERS:
02251         /* Run triggers in this package other package(s) set off. */
02252         if (rpmtsFlags(ts) & RPMTRANS_FLAG_TEST)        break;
02253         rc = runImmedTriggers(psm);
02254         break;
02255 
02256     case PSM_RPMIO_FLAGS:
02257     {   const char * payload_compressor = NULL;
02258         const char * payload_format = NULL;
02259         char * t;
02260 
02261         /*@-branchstate@*/
02262         if (!hge(fi->h, RPMTAG_PAYLOADCOMPRESSOR, NULL,
02263                             &payload_compressor, NULL))
02264             payload_compressor = "gzip";
02265         /*@=branchstate@*/
02266         psm->rpmio_flags = t = xmalloc(sizeof("w9.gzdio"));
02267         *t = '\0';
02268         t = stpcpy(t, ((psm->goal == PSM_PKGSAVE) ? "w9" : "r"));
02269         if (!strcmp(payload_compressor, "gzip"))
02270             t = stpcpy(t, ".gzdio");
02271         if (!strcmp(payload_compressor, "bzip2"))
02272             t = stpcpy(t, ".bzdio");
02273         if (!strcmp(payload_compressor, "lzma"))
02274             t = stpcpy(t, ".lzdio");
02275 
02276         /*@-branchstate@*/
02277         if (!hge(fi->h, RPMTAG_PAYLOADFORMAT, NULL,
02278                             &payload_format, NULL)
02279          || !(!strcmp(payload_format, "tar") || !strcmp(payload_format, "ustar")))
02280             payload_format = "cpio";
02281         /*@=branchstate@*/
02282         psm->payload_format = xstrdup(payload_format);
02283         rc = RPMRC_OK;
02284     }   break;
02285 
02286     case PSM_RPMDB_LOAD:
02287 assert(psm->mi == NULL);
02288         psm->mi = rpmtsInitIterator(ts, RPMDBI_PACKAGES,
02289                                 &fi->record, sizeof(fi->record));
02290         fi->h = rpmdbNextIterator(psm->mi);
02291         if (fi->h != NULL)
02292             fi->h = headerLink(fi->h);
02293         psm->mi = rpmdbFreeIterator(psm->mi);
02294 
02295         if (fi->h != NULL) {
02296             (void) headerSetInstance(fi->h, fi->record);
02297             rc = RPMRC_OK;
02298         } else
02299             rc = RPMRC_FAIL;
02300         break;
02301     case PSM_RPMDB_ADD:
02302         if (rpmtsFlags(ts) & RPMTRANS_FLAG_TEST)        break;
02303         if (fi->h == NULL)      break;  /* XXX can't happen */
02304 
02305         /* Add header to db, doing header check if requested */
02306         /* XXX rollback headers propagate the previous transaction id. */
02307         {   uint_32 tid = ((rpmtsType(ts) == RPMTRANS_TYPE_ROLLBACK)
02308                 ? hLoadTID(fi->h, RPMTAG_INSTALLTID) : rpmtsGetTid(ts));
02309             (void) rpmswEnter(rpmtsOp(ts, RPMTS_OP_DBADD), 0);
02310             if (!(rpmtsVSFlags(ts) & RPMVSF_NOHDRCHK))
02311                 rc = rpmdbAdd(rpmtsGetRdb(ts), tid, fi->h, ts, headerCheck);
02312             else
02313                 rc = rpmdbAdd(rpmtsGetRdb(ts), tid, fi->h, NULL, NULL);
02314             (void) rpmswExit(rpmtsOp(ts, RPMTS_OP_DBADD), 0);
02315         }
02316 
02317         if (rc != RPMRC_OK) break;
02318 
02319 assert(psm->te != NULL);
02320         /* Mark non-rollback elements as installed. */
02321         if (rpmtsType(ts) != RPMTRANS_TYPE_ROLLBACK)
02322             psm->te->installed = 1;
02323 
02324         /* Set the database instance for (possible) rollbacks. */
02325         rpmteSetDBInstance(psm->te, headerGetInstance(fi->h));
02326 
02327         break;
02328     case PSM_RPMDB_REMOVE:
02329     {   
02330         if (rpmtsFlags(ts) & RPMTRANS_FLAG_TEST)        break;
02331 
02332         (void) rpmswEnter(rpmtsOp(ts, RPMTS_OP_DBREMOVE), 0);
02333         rc = rpmdbRemove(rpmtsGetRdb(ts), rpmtsGetTid(ts), fi->record,
02334                                 NULL, NULL);
02335         (void) rpmswExit(rpmtsOp(ts, RPMTS_OP_DBREMOVE), 0);
02336 
02337         if (rc != RPMRC_OK) break;
02338 
02339         /* Forget the offset of a successfully removed header. */
02340         psm->te->u.removed.dboffset = 0;
02341 
02342     }   break;
02343 
02344     default:
02345         break;
02346 /*@i@*/    }
02347 /*@=branchstate@*/
02348 
02349 /*@-nullstate@*/        /* FIX: psm->oh and psm->fi->h may be NULL. */
02350     return rc;
02351 /*@=nullstate@*/
02352 }
02353 /*@=bounds =nullpass@*/

Generated on Fri Aug 31 11:16:07 2007 for rpm by  doxygen 1.4.6