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, (void **) &epochOne, NULL))
00060         epochOne = &zero;
00061     if (!headerGetEntry(second, RPMTAG_EPOCH, NULL, (void **) &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, (void **) &one, NULL);
00072     rc = headerGetEntry(second, RPMTAG_VERSION, NULL, (void **) &two, NULL);
00073 
00074     rc = rpmvercmp(one, two);
00075     if (rc)
00076         return rc;
00077 
00078     rc = headerGetEntry(first, RPMTAG_RELEASE, NULL, (void **) &one, NULL);
00079     rc = headerGetEntry(second, RPMTAG_RELEASE, NULL, (void **) &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, (void **)&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, (void **) &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, (void **) &prefixes, &numPrefixes)) {
00717         freePrefixes = 1;
00718     } else if (hge(h, RPMTAG_INSTALLPREFIX, NULL, (void **) &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, (void **) &script, NULL);
00982     xx = hge(fi->h, psm->progTag, &ptt, (void **) &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