Main Page   Modules   Data Structures   File List   Data Fields   Globals   Related Pages  

lib/psm.c

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

Generated on Tue Sep 17 15:56:40 2002 for rpm by doxygen1.2.14 written by Dimitri van Heesch, © 1997-2002