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 psm, 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 @*/
    00811         /*@modifies psm, psmtbl, fileSystem @*/
    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 @*/
    00857         /*@modifies psmtbl, fileSystem @*/
    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 {
    00902     sigset_t newMask, oldMask;
    00903     pid_t reaped;
    00904
    00905     (void) sigfillset(&newMask);                /* block all signals */
    00906     (void) sigprocmask(SIG_BLOCK, &newMask, &oldMask);
    00907     reaped = psm->reaped;
    00908     (void) sigprocmask(SIG_SETMASK, &oldMask, NULL);
    00909     return reaped;
    00910 }
    00911
    00917 static pid_t psmWait(rpmpsm psm)
    00918         /*@globals fileSystem, internalState @*/
    00919         /*@modifies psm, fileSystem, internalState @*/
    00920 {
    00921     if (psm->reaper) {
    00922         /*@-infloops@*/
    00923         while (psmGetReaped(psm) == 0)
    00924             (void) pause();
    00925         /*@=infloops@*/
    00926 /*@-modfilesys@*/
    00927 if (_psm_debug)
    00928 fprintf(stderr, "      Wait: %p[%d:%d:%d] = %p child %d\n", psmtbl.psms, 0, psmtbl.npsms, psmtbl.nalloced, psm, psm->child);
    00929 /*@=modfilesys@*/
    00930         (void) psmUnregister(psm, psm->child);
    00931     } else {
    00932         do {
    00933             psm->reaped = waitpid(psm->child, &psm->status, 0);
    00934         } while (psm->reaped >= 0 && psm->reaped != psm->child);
    00935     }
    00936
    00937     rpmMessage(RPMMESS_DEBUG, _("%s: waitpid(%d) rc %d status %x\n"),
    00938         psm->stepName, (unsigned)psm->child,
    00939         (unsigned)psm->reaped, psm->status);
    00940
    00941     return psm->reaped;
    00942 }
    00943
    00946 /*@unchecked@*/
    00947 static int ldconfig_done = 0;
    00948
    00949 /*@unchecked@*/ /*@observer@*/ /*@null@*/
    00950 static const char * ldconfig_path = "/sbin/ldconfig";
    00951
    00970 static rpmRC runScript(rpmpsm psm, Header h, const char * sln,
    00971                 int progArgc, const char ** progArgv,
    00972                 const char * script, int arg1, int arg2)
    00973         /*@globals ldconfig_done, rpmGlobalMacroContext,
    00974                 fileSystem, internalState@*/
    00975         /*@modifies psm, ldconfig_done, rpmGlobalMacroContext,
    00976                 fileSystem, internalState @*/
    00977 {
    00978     const rpmts ts = psm->ts;
    00979     rpmfi fi = psm->fi;
    00980     HGE_t hge = fi->hge;
    00981     HFD_t hfd = (fi->hfd ? fi->hfd : headerFreeData);
    00982     const char ** argv = NULL;
    00983     int argc = 0;
    00984     const char ** prefixes = NULL;
    00985     int numPrefixes;
    00986     rpmTagType ipt;
    00987     const char * oldPrefix;
    00988     int maxPrefixLength;
    00989     int len;
    00990     char * prefixBuf = NULL;
    00991     const char * fn = NULL;
    00992     int i, xx;
    00993     int freePrefixes = 0;
    00994     FD_t scriptFd;
    00995     FD_t out;
    00996     rpmRC rc = RPMRC_OK;
    00997     const char *n, *v, *r;
    00998
    00999     if (progArgv == NULL && script == NULL)
    01000         return rc;
    01001
    01002     psm->child = 0;
    01003     psm->reaped = 0;
    01004     psm->status = 0;
    01005     psm->reaper = 1;
    01006
    01007     /* XXX FIXME: except for %verifyscript, rpmteNEVR can be used. */
    01008     xx = headerNVR(h, &n, &v, &r);
    01009     /*
    01010      * If a successor node, and ldconfig was just run, don't bother.
    01011      */
    01012     if (ldconfig_path && progArgv && psm->unorderedSuccessor) {
    01013         if (ldconfig_done && !strcmp(progArgv[0], ldconfig_path)) {
    01014             rpmMessage(RPMMESS_DEBUG,
    01015                 _("%s: %s(%s-%s-%s) skipping redundant \"%s\".\n"),
    01016                 psm->stepName, tag2sln(psm->scriptTag), n, v, r,
    01017                 progArgv[0]);
    01018             return rc;
    01019         }
    01020     }
    01021
    01022     rpmMessage(RPMMESS_DEBUG,
    01023                 _("%s: %s(%s-%s-%s) %ssynchronous scriptlet start\n"),
    01024                 psm->stepName, tag2sln(psm->scriptTag), n, v, r,
    01025                 (psm->unorderedSuccessor ? "a" : ""));
    01026
    01027     if (!progArgv) {
    01028         argv = alloca(5 * sizeof(*argv));
    01029         argv[0] = "/bin/sh";
    01030         argc = 1;
    01031         ldconfig_done = 0;
    01032     } else {
    01033         argv = alloca((progArgc + 4) * sizeof(*argv));
    01034         memcpy(argv, progArgv, progArgc * sizeof(*argv));
    01035         argc = progArgc;
    01036         ldconfig_done = (ldconfig_path && !strcmp(argv[0], ldconfig_path)
    01037                 ? 1 : 0);
    01038     }
    01039
    01040     if (hge(h, RPMTAG_INSTPREFIXES, &ipt, (void **) &prefixes, &numPrefixes)) {
    01041         freePrefixes = 1;
    01042     } else if (hge(h, RPMTAG_INSTALLPREFIX, NULL, (void **) &oldPrefix, NULL)) {
    01043         prefixes = &oldPrefix;
    01044         numPrefixes = 1;
    01045     } else {
    01046         numPrefixes = 0;
    01047     }
    01048
    01049     maxPrefixLength = 0;
    01050     for (i = 0; i < numPrefixes; i++) {
    01051         len = strlen(prefixes[i]);
    01052         if (len > maxPrefixLength) maxPrefixLength = len;
    01053     }
    01054     prefixBuf = alloca(maxPrefixLength + 50);
    01055
    01056     if (script) {
    01057         const char * rootDir = rpmtsRootDir(ts);
    01058         FD_t fd;
    01059
    01060         /*@-branchstate@*/
    01061         if (makeTempFile((!rpmtsChrootDone(ts) ? rootDir : "/"), &fn, &fd)) {
    01062             if (freePrefixes) free(prefixes);
    01063             return RPMRC_FAIL;
    01064         }
    01065         /*@=branchstate@*/
    01066
    01067         if (rpmIsDebug() &&
    01068             (!strcmp(argv[0], "/bin/sh") || !strcmp(argv[0], "/bin/bash")))
    01069         {
    01070             static const char set_x[] = "set -x\n";
    01071             xx = Fwrite(set_x, sizeof(set_x[0]), sizeof(set_x)-1, fd);
    01072         }
    01073
    01074         if (ldconfig_path && strstr(script, ldconfig_path) != NULL)
    01075             ldconfig_done = 1;
    01076
    01077         xx = Fwrite(script, sizeof(script[0]), strlen(script), fd);
    01078         xx = Fclose(fd);
    01079
    01080         {   const char * sn = fn;
    01081             if (!rpmtsChrootDone(ts) && rootDir != NULL &&
    01082                 !(rootDir[0] == '/' && rootDir[1] == '\0'))
    01083             {
    01084                 sn += strlen(rootDir)-1;
    01085             }
    01086             argv[argc++] = sn;
    01087         }
    01088
    01089         if (arg1 >= 0) {
    01090             char *av = alloca(20);
    01091             sprintf(av, "%d", arg1);
    01092             argv[argc++] = av;
    01093         }
    01094         if (arg2 >= 0) {
    01095             char *av = alloca(20);
    01096             sprintf(av, "%d", arg2);
    01097             argv[argc++] = av;
    01098         }
    01099     }
    01100
    01101     argv[argc] = NULL;
    01102
    01103     scriptFd = rpmtsScriptFd(ts);
    01104     if (scriptFd != NULL) {
    01105         if (rpmIsVerbose()) {
    01106             out = fdDup(Fileno(scriptFd));
    01107         } else {
    01108             out = Fopen("/dev/null", "w.fdio");
    01109             if (Ferror(out)) {
    01110                 out = fdDup(Fileno(scriptFd));
    01111             }
    01112         }
    01113     } else {
    01114         out = fdDup(STDOUT_FILENO);
    01115     }
    01116     if (out == NULL) return RPMRC_FAIL; /* XXX can't happen */
    01117
    01118     /*@-branchstate@*/
    01119     if ((psm->child = psmRegisterFork(psm)) == 0) {
    01120         const char * rootDir;
    01121         int pipes[2];
    01122
    01123         pipes[0] = pipes[1] = 0;
    01124         /* make stdin inaccessible */
    01125         xx = pipe(pipes);
    01126         xx = close(pipes[1]);
    01127         xx = dup2(pipes[0], STDIN_FILENO);
    01128         xx = close(pipes[0]);
    01129
    01130         if (scriptFd != NULL) {
    01131             int sfdno = Fileno(scriptFd);
    01132             int ofdno = Fileno(out);
    01133             if (sfdno != STDERR_FILENO)
    01134                 xx = dup2(sfdno, STDERR_FILENO);
    01135             if (ofdno != STDOUT_FILENO)
    01136                 xx = dup2(ofdno, STDOUT_FILENO);
    01137             /* make sure we don't close stdin/stderr/stdout by mistake! */
    01138             if (ofdno > STDERR_FILENO && ofdno != sfdno) {
    01139                 xx = Fclose (out);
    01140             }
    01141             if (sfdno > STDERR_FILENO) {
    01142                 xx = Fclose (scriptFd);
    01143             }
    01144         }
    01145
    01146         {   const char *ipath = rpmExpand("PATH=%{_install_script_path}", NULL);
    01147             const char *path = SCRIPT_PATH;
    01148
    01149             if (ipath && ipath[5] != '%')
    01150                 path = ipath;
    01151
    01152             xx = doputenv(path);
    01153             /*@-modobserver@*/
    01154             ipath = _free(ipath);
    01155             /*@=modobserver@*/
    01156         }
    01157
    01158         for (i = 0; i < numPrefixes; i++) {
    01159             sprintf(prefixBuf, "RPM_INSTALL_PREFIX%d=%s", i, prefixes[i]);
    01160             xx = doputenv(prefixBuf);
    01161
    01162             /* backwards compatibility */
    01163             if (i == 0) {
    01164                 sprintf(prefixBuf, "RPM_INSTALL_PREFIX=%s", prefixes[i]);
    01165                 xx = doputenv(prefixBuf);
    01166             }
    01167         }
    01168
    01169         rootDir = rpmtsRootDir(ts);
    01170         if (rootDir  != NULL)   /* XXX can't happen */
    01171         switch(urlIsURL(rootDir)) {
    01172         case URL_IS_PATH:
    01173             rootDir += sizeof("file://") - 1;
    01174             rootDir = strchr(rootDir, '/');
    01175             /*@fallthrough@*/
    01176         case URL_IS_UNKNOWN:
    01177             if (!rpmtsChrootDone(ts) &&
    01178                 !(rootDir[0] == '/' && rootDir[1] == '\0'))
    01179             {
    01180                 /*@-superuser -noeffect @*/
    01181                 xx = chroot(rootDir);
    01182                 /*@=superuser =noeffect @*/
    01183             }
    01184             xx = chdir("/");
    01185             rpmMessage(RPMMESS_DEBUG, _("%s: %s(%s-%s-%s)\texecv(%s) pid %d\n"),
    01186                         psm->stepName, sln, n, v, r,
    01187                         argv[0], (unsigned)getpid());
    01188 /*@-modfilesys@*/
    01189 if (_psm_debug)
    01190 fprintf(stderr, "      Exec: %s \"%s\"\n", sln, argv[0]);
    01191 /*@=modfilesys@*/
    01192             unsetenv("MALLOC_CHECK_");
    01193             xx = execv(argv[0], (char *const *)argv);
    01194             break;
    01195         default:
    01196             break;
    01197         }
    01198
    01199         _exit(-1);
    01200         /*@notreached@*/
    01201     }
    01202     /*@=branchstate@*/
    01203
    01204     (void) psmWait(psm);
    01205
    01206     if (psm->reaped < 0) {
    01207         rpmError(RPMERR_SCRIPT,
    01208                 _("%s(%s-%s-%s) scriptlet failed, waitpid(%d) rc %d: %s\n"),
    01209                  sln, n, v, r, psm->child, psm->reaped, strerror(errno));
    01210         rc = RPMRC_FAIL;
    01211     } else
    01212     if (!WIFEXITED(psm->status) || WEXITSTATUS(psm->status)) {
    01213         rpmError(RPMERR_SCRIPT,
    01214                 _("%s(%s-%s-%s) scriptlet failed, exit status %d\n"),
    01215                 sln, n, v, r, WEXITSTATUS(psm->status));
    01216         rc = RPMRC_FAIL;
    01217     }
    01218
    01219     if (freePrefixes) prefixes = hfd(prefixes, ipt);
    01220
    01221     xx = Fclose(out);   /* XXX dup'd STDOUT_FILENO */
    01222
    01223     /*@-branchstate@*/
    01224     if (script) {
    01225         if (!rpmIsDebug())
    01226             xx = unlink(fn);
    01227         fn = _free(fn);
    01228     }
    01229     /*@=branchstate@*/
    01230
    01231     return rc;
    01232 }
    01233
    01239 static rpmRC runInstScript(rpmpsm psm)
    01240         /*@globals rpmGlobalMacroContext, fileSystem, internalState @*/
    01241         /*@modifies psm, rpmGlobalMacroContext, fileSystem, internalState @*/
    01242 {
    01243     rpmfi fi = psm->fi;
    01244     HGE_t hge = fi->hge;
    01245     HFD_t hfd = (fi->hfd ? fi->hfd : headerFreeData);
    01246     void ** progArgv;
    01247     int progArgc;
    01248     const char ** argv;
    01249     rpmTagType ptt, stt;
    01250     const char * script;
    01251     rpmRC rc = RPMRC_OK;
    01252     int xx;
    01253
    01254     /*
    01255      * headerGetEntry() sets the data pointer to NULL if the entry does
    01256      * not exist.
    01257      */
    01258     xx = hge(fi->h, psm->scriptTag, &stt, (void **) &script, NULL);
    01259     xx = hge(fi->h, psm->progTag, &ptt, (void **) &progArgv, &progArgc);
    01260     if (progArgv == NULL && script == NULL)
    01261         goto exit;
    01262
    01263     /*@-branchstate@*/
    01264     if (progArgv && ptt == RPM_STRING_TYPE) {
    01265         argv = alloca(sizeof(*argv));
    01266         *argv = (const char *) progArgv;
    01267     } else {
    01268         argv = (const char **) progArgv;
    01269     }
    01270     /*@=branchstate@*/
    01271
    01272     if (fi->h != NULL)  /* XXX can't happen */
    01273     rc = runScript(psm, fi->h, tag2sln(psm->scriptTag), progArgc, argv,
    01274                 script, psm->scriptArg, -1);
    01275
    01276 exit:
    01277     progArgv = hfd(progArgv, ptt);
    01278     script = hfd(script, stt);
    01279     return rc;
    01280 }
    01281
    01292 static rpmRC handleOneTrigger(const rpmpsm psm,
    01293                         Header sourceH, Header triggeredH,
    01294                         int arg2, unsigned char * triggersAlreadyRun)
    01295         /*@globals rpmGlobalMacroContext, fileSystem, internalState@*/
    01296         /*@modifies psm, sourceH, triggeredH, *triggersAlreadyRun,
    01297                 rpmGlobalMacroContext, fileSystem, internalState @*/
    01298 {
    01299     int scareMem = 1;
    01300     const rpmts ts = psm->ts;
    01301     rpmfi fi = psm->fi;
    01302     HGE_t hge = fi->hge;
    01303     HFD_t hfd = (fi->hfd ? fi->hfd : headerFreeData);
    01304     rpmds trigger = NULL;
    01305     const char ** triggerScripts;
    01306     const char ** triggerProgs;
    01307     int_32 * triggerIndices;
    01308     const char * sourceName;
    01309     rpmRC rc = RPMRC_OK;
    01310     int xx;
    01311     int i;
    01312
    01313     xx = headerNVR(sourceH, &sourceName, NULL, NULL);
    01314
    01315     trigger = rpmdsInit(rpmdsNew(triggeredH, RPMTAG_TRIGGERNAME, scareMem));
    01316     if (trigger == NULL)
    01317         return rc;
    01318
    01319     (void) rpmdsSetNoPromote(trigger, 1);
    01320
    01321     while ((i = rpmdsNext(trigger)) >= 0) {
    01322         rpmTagType tit, tst, tpt;
    01323         const char * Name;
    01324         int_32 Flags = rpmdsFlags(trigger);
    01325
    01326         if ((Name = rpmdsN(trigger)) == NULL)
    01327             continue;   /* XXX can't happen */
    01328
    01329         if (strcmp(Name, sourceName))
    01330             continue;
    01331         if (!(Flags & psm->sense))
    01332             continue;
    01333
    01334         /*
    01335          * XXX Trigger on any provided dependency, not just the package NEVR.
    01336          */
    01337         if (!rpmdsAnyMatchesDep(sourceH, trigger, 1))
    01338             continue;
    01339
    01340         if (!(  hge(triggeredH, RPMTAG_TRIGGERINDEX, &tit,
    01341                        (void **) &triggerIndices, NULL) &&
    01342                 hge(triggeredH, RPMTAG_TRIGGERSCRIPTS, &tst,
    01343                        (void **) &triggerScripts, NULL) &&
    01344                 hge(triggeredH, RPMTAG_TRIGGERSCRIPTPROG, &tpt,
    01345                        (void **) &triggerProgs, NULL))
    01346             )
    01347             continue;
    01348
    01349         {   int arg1;
    01350             int index;
    01351
    01352             arg1 = rpmdbCountPackages(rpmtsGetRdb(ts), Name);
    01353             if (arg1 < 0) {
    01354                 /* XXX W2DO? fails as "execution of script failed" */
    01355                 rc = RPMRC_FAIL;
    01356             } else {
    01357                 arg1 += psm->countCorrection;
    01358                 index = triggerIndices[i];
    01359                 if (triggersAlreadyRun == NULL ||
    01360                     triggersAlreadyRun[index] == 0)
    01361                 {
    01362                     rc = runScript(psm, triggeredH, "%trigger", 1,
    01363                             triggerProgs + index, triggerScripts[index],
    01364                             arg1, arg2);
    01365                     if (triggersAlreadyRun != NULL)
    01366                         triggersAlreadyRun[index] = 1;
    01367                 }
    01368             }
    01369         }
    01370
    01371         triggerIndices = hfd(triggerIndices, tit);
    01372         triggerScripts = hfd(triggerScripts, tst);
    01373         triggerProgs = hfd(triggerProgs, tpt);
    01374
    01375         /*
    01376          * Each target/source header pair can only result in a single
    01377          * script being run.
    01378          */
    01379         break;
    01380     }
    01381
    01382     trigger = rpmdsFree(trigger);
    01383
    01384     return rc;
    01385 }
    01386
    01392 static rpmRC runTriggers(rpmpsm psm)
    01393         /*@globals rpmGlobalMacroContext,
    01394                 fileSystem, internalState @*/
    01395         /*@modifies psm, rpmGlobalMacroContext,
    01396                 fileSystem, internalState @*/
    01397 {
    01398     const rpmts ts = psm->ts;
    01399     rpmfi fi = psm->fi;
    01400     int numPackage = -1;
    01401     rpmRC rc = RPMRC_OK;
    01402     const char * N = NULL;
    01403
    01404     if (psm->te)        /* XXX can't happen */
    01405         N = rpmteN(psm->te);
    01406     if (N)              /* XXX can't happen */
    01407         numPackage = rpmdbCountPackages(rpmtsGetRdb(ts), N)
    01408                                 + psm->countCorrection;
    01409     if (numPackage < 0)
    01410         return RPMRC_NOTFOUND;
    01411
    01412     if (fi->h != NULL)  /* XXX can't happen */
    01413     {   Header triggeredH;
    01414         rpmdbMatchIterator mi;
    01415         int countCorrection = psm->countCorrection;
    01416
    01417         psm->countCorrection = 0;
    01418         mi = rpmtsInitIterator(ts, RPMTAG_TRIGGERNAME, N, 0);
    01419         while((triggeredH = rpmdbNextIterator(mi)) != NULL)
    01420             rc |= handleOneTrigger(psm, fi->h, triggeredH, numPackage, NULL);
    01421         mi = rpmdbFreeIterator(mi);
    01422         psm->countCorrection = countCorrection;
    01423     }
    01424
    01425     return rc;
    01426 }
    01427
    01433 static rpmRC runImmedTriggers(rpmpsm psm)
    01434         /*@globals rpmGlobalMacroContext,
    01435                 fileSystem, internalState @*/
    01436         /*@modifies psm, rpmGlobalMacroContext,
    01437                 fileSystem, internalState @*/
    01438 {
    01439     const rpmts ts = psm->ts;
    01440     rpmfi fi = psm->fi;
    01441     HGE_t hge = fi->hge;
    01442     HFD_t hfd = (fi->hfd ? fi->hfd : headerFreeData);
    01443     const char ** triggerNames;
    01444     int numTriggers;
    01445     int_32 * triggerIndices;
    01446     rpmTagType tnt, tit;
    01447     int numTriggerIndices;
    01448     unsigned char * triggersRun;
    01449     rpmRC rc = RPMRC_OK;
    01450
    01451     if (fi->h == NULL)  return rc;      /* XXX can't happen */
    01452
    01453     if (!(      hge(fi->h, RPMTAG_TRIGGERNAME, &tnt,
    01454                         (void **) &triggerNames, &numTriggers) &&
    01455                 hge(fi->h, RPMTAG_TRIGGERINDEX, &tit,
    01456                         (void **) &triggerIndices, &numTriggerIndices))
    01457         )
    01458         return rc;
    01459
    01460     triggersRun = alloca(sizeof(*triggersRun) * numTriggerIndices);
    01461     memset(triggersRun, 0, sizeof(*triggersRun) * numTriggerIndices);
    01462
    01463     {   Header sourceH = NULL;
    01464         int i;
    01465
    01466         for (i = 0; i < numTriggers; i++) {
    01467             rpmdbMatchIterator mi;
    01468
    01469             if (triggersRun[triggerIndices[i]] != 0) continue;
    01470
    01471             mi = rpmtsInitIterator(ts, RPMTAG_NAME, triggerNames[i], 0);
    01472
    01473             while((sourceH = rpmdbNextIterator(mi)) != NULL) {
    01474                 rc |= handleOneTrigger(psm, sourceH, fi->h,
    01475                                 rpmdbGetIteratorCount(mi),
    01476                                 triggersRun);
    01477             }
    01478
    01479             mi = rpmdbFreeIterator(mi);
    01480         }
    01481     }
    01482     triggerIndices = hfd(triggerIndices, tit);
    01483     triggerNames = hfd(triggerNames, tnt);
    01484     return rc;
    01485 }
    01486
    01487 /*@observer@*/ static const char *const pkgStageString(pkgStage a)
    01488         /*@*/
    01489 {
    01490     switch(a) {
    01491     case PSM_UNKNOWN:           return "unknown";
    01492
    01493     case PSM_PKGINSTALL:        return "  install";
    01494     case PSM_PKGERASE:          return "    erase";
    01495     case PSM_PKGCOMMIT:         return "   commit";
    01496     case PSM_PKGSAVE:           return "repackage";
    01497
    01498     case PSM_INIT:              return "init";
    01499     case PSM_PRE:               return "pre";
    01500     case PSM_PROCESS:           return "process";
    01501     case PSM_POST:              return "post";
    01502     case PSM_UNDO:              return "undo";
    01503     case PSM_FINI:              return "fini";
    01504
    01505     case PSM_CREATE:            return "create";
    01506     case PSM_NOTIFY:            return "notify";
    01507     case PSM_DESTROY:           return "destroy";
    01508     case PSM_COMMIT:            return "commit";
    01509
    01510     case PSM_CHROOT_IN:         return "chrootin";
    01511     case PSM_CHROOT_OUT:        return "chrootout";
    01512     case PSM_SCRIPT:            return "script";
    01513     case PSM_TRIGGERS:          return "triggers";
    01514     case PSM_IMMED_TRIGGERS:    return "immedtriggers";
    01515
    01516     case PSM_RPMIO_FLAGS:       return "rpmioflags";
    01517
    01518     case PSM_RPMDB_LOAD:        return "rpmdbload";
    01519     case PSM_RPMDB_ADD:         return "rpmdbadd";
    01520     case PSM_RPMDB_REMOVE:      return "rpmdbremove";
    01521
    01522     default:                    return "???";
    01523     }
    01524     /*@noteached@*/
    01525 }
    01526
    01527 rpmpsm XrpmpsmUnlink(rpmpsm psm, const char * msg, const char * fn, unsigned ln)
    01528 {
    01529     if (psm == NULL) return NULL;
    01530 /*@-modfilesys@*/
    01531 if (_psm_debug && msg != NULL)
    01532 fprintf(stderr, "--> psm %p -- %d %s at %s:%u\n", psm, psm->nrefs, msg, fn, ln);
    01533 /*@=modfilesys@*/
    01534     psm->nrefs--;
    01535     return NULL;
    01536 }
    01537
    01538 rpmpsm XrpmpsmLink(rpmpsm psm, const char * msg, const char * fn, unsigned ln)
    01539 {
    01540     if (psm == NULL) return NULL;
    01541     psm->nrefs++;
    01542
    01543 /*@-modfilesys@*/
    01544 if (_psm_debug && msg != NULL)
    01545 fprintf(stderr, "--> psm %p ++ %d %s at %s:%u\n", psm, psm->nrefs, msg, fn, ln);
    01546 /*@=modfilesys@*/
    01547
    01548     /*@-refcounttrans@*/ return psm; /*@=refcounttrans@*/
    01549 }
    01550
    01551 rpmpsm rpmpsmFree(rpmpsm psm)
    01552 {
    01553     const char * msg = "rpmpsmFree";
    01554     if (psm == NULL)
    01555         return NULL;
    01556
    01557     if (psm->nrefs > 1)
    01558         return rpmpsmUnlink(psm, msg);
    01559
    01560 /*@-nullstate@*/
    01561     psm->fi = rpmfiFree(psm->fi);
    01562 #ifdef  NOTYET
    01563     psm->te = rpmteFree(psm->te);
    01564 #else
    01565     psm->te = NULL;
    01566 #endif
    01567     psm->ts = rpmtsFree(psm->ts);
    01568
    01569     (void) rpmpsmUnlink(psm, msg);
    01570
    01571     /*@-refcounttrans -usereleased@*/
    01572 /*@-boundswrite@*/
    01573     memset(psm, 0, sizeof(*psm));               /* XXX trash and burn */
    01574 /*@=boundswrite@*/
    01575     psm = _free(psm);
    01576     /*@=refcounttrans =usereleased@*/
    01577
    01578     return NULL;
    01579 /*@=nullstate@*/
    01580 }
    01581
    01582 rpmpsm rpmpsmNew(rpmts ts, rpmte te, rpmfi fi)
    01583 {
    01584     const char * msg = "rpmpsmNew";
    01585     rpmpsm psm = xcalloc(1, sizeof(*psm));
    01586
    01587     if (ts)     psm->ts = rpmtsLink(ts, msg);
    01588 #ifdef  NOTYET
    01589     if (te)     psm->te = rpmteLink(te, msg);
    01590 #else
    01591 /*@-assignexpose -temptrans @*/
    01592     if (te)     psm->te = te;
    01593 /*@=assignexpose =temptrans @*/
    01594 #endif
    01595     if (fi)     psm->fi = rpmfiLink(fi, msg);
    01596
    01597     return rpmpsmLink(psm, msg);
    01598 }
    01599
    01604 /*@-bounds -nullpass@*/ /* FIX: testing null annotation for fi->h */
    01605 rpmRC rpmpsmStage(rpmpsm psm, pkgStage stage)
    01606 {
    01607     const rpmts ts = psm->ts;
    01608     rpmfi fi = psm->fi;
    01609     HGE_t hge = fi->hge;
    01610     HME_t hme = fi->hme;
    01611     HFD_t hfd = (fi->hfd ? fi->hfd : headerFreeData);
    01612     rpmRC rc = psm->rc;
    01613     int saveerrno;
    01614     int xx;
    01615
    01616     /*@-branchstate@*/
    01617     switch (stage) {
    01618     case PSM_UNKNOWN:
    01619         break;
    01620     case PSM_INIT:
    01621         rpmMessage(RPMMESS_DEBUG, _("%s: %s has %d files, test = %d\n"),
    01622                 psm->stepName, rpmteNEVR(psm->te),
    01623                 rpmfiFC(fi), (rpmtsFlags(ts) & RPMTRANS_FLAG_TEST));
    01624
    01625         /*
    01626          * When we run scripts, we pass an argument which is the number of
    01627          * versions of this package that will be installed when we are
    01628          * finished.
    01629          */
    01630         psm->npkgs_installed = rpmdbCountPackages(rpmtsGetRdb(ts), rpmteN(psm->te));
    01631         if (psm->npkgs_installed < 0) {
    01632             rc = RPMRC_FAIL;
    01633             break;
    01634         }
    01635
    01636         if (psm->goal == PSM_PKGINSTALL) {
    01637             int fc = rpmfiFC(fi);
    01638
    01639             psm->scriptArg = psm->npkgs_installed + 1;
    01640
    01641 assert(psm->mi == NULL);
    01642             psm->mi = rpmtsInitIterator(ts, RPMTAG_NAME, rpmteN(psm->te), 0);
    01643             xx = rpmdbSetIteratorRE(psm->mi, RPMTAG_EPOCH, RPMMIRE_DEFAULT,
    01644                         rpmteE(psm->te));
    01645             xx = rpmdbSetIteratorRE(psm->mi, RPMTAG_VERSION, RPMMIRE_DEFAULT,
    01646                         rpmteV(psm->te));
    01647             xx = rpmdbSetIteratorRE(psm->mi, RPMTAG_RELEASE, RPMMIRE_DEFAULT,
    01648                         rpmteR(psm->te));
    01649
    01650             while ((psm->oh = rpmdbNextIterator(psm->mi))) {
    01651                 fi->record = rpmdbGetIteratorOffset(psm->mi);
    01652                 if (rpmtsFlags(ts) & RPMTRANS_FLAG_MULTILIB)
    01653                     psm->oh = headerCopy(psm->oh);
    01654                 else
    01655                     psm->oh = NULL;
    01656                 /*@loopbreak@*/ break;
    01657             }
    01658             psm->mi = rpmdbFreeIterator(psm->mi);
    01659             rc = RPMRC_OK;
    01660
    01661             /* XXX lazy alloc here may need to be done elsewhere. */
    01662             if (fi->fstates == NULL && fc > 0) {
    01663                 fi->fstates = xmalloc(sizeof(*fi->fstates) * fc);
    01664                 memset(fi->fstates, RPMFILE_STATE_NORMAL, fc);
    01665             }
    01666
    01667             if (rpmtsFlags(ts) & RPMTRANS_FLAG_JUSTDB)  break;
    01668             if (fc <= 0)                                break;
    01669
    01670             /*
    01671              * Old format relocateable packages need the entire default
    01672              * prefix stripped to form the cpio list, while all other packages
    01673              * need the leading / stripped.
    01674              */
    01675             {   const char * p;
    01676                 xx = hge(fi->h, RPMTAG_DEFAULTPREFIX, NULL, (void **) &p, NULL);
    01677                 fi->striplen = (xx ? strlen(p) + 1 : 1);
    01678             }
    01679             fi->mapflags =
    01680                 CPIO_MAP_PATH | CPIO_MAP_MODE | CPIO_MAP_UID | CPIO_MAP_GID;
    01681
    01682             if (headerIsEntry(fi->h, RPMTAG_ORIGBASENAMES))
    01683                 buildOrigFileList(fi->h, &fi->apath, NULL);
    01684             else
    01685                 rpmBuildFileList(fi->h, &fi->apath, NULL);
    01686
    01687             if (fi->fuser == NULL)
    01688                 xx = hge(fi->h, RPMTAG_FILEUSERNAME, NULL,
    01689                                 (void **) &fi->fuser, NULL);
    01690             if (fi->fgroup == NULL)
    01691                 xx = hge(fi->h, RPMTAG_FILEGROUPNAME, NULL,
    01692                                 (void **) &fi->fgroup, NULL);
    01693             if (fi->fuids == NULL)
    01694                 fi->fuids = xcalloc(sizeof(*fi->fuids), fc);
    01695             if (fi->fgids == NULL)
    01696                 fi->fgids = xcalloc(sizeof(*fi->fgids), fc);
    01697             rc = RPMRC_OK;
    01698         }
    01699         if (psm->goal == PSM_PKGERASE || psm->goal == PSM_PKGSAVE) {
    01700             psm->scriptArg = psm->npkgs_installed - 1;
    01701
    01702             /* Retrieve installed header. */
    01703             rc = rpmpsmStage(psm, PSM_RPMDB_LOAD);
    01704 if (rc == RPMRC_OK)
    01705 if (psm->te)
    01706 psm->te->h = headerLink(fi->h);
    01707         }
    01708         if (psm->goal == PSM_PKGSAVE) {
    01709             /* Open output package for writing. */
    01710             {   const char * bfmt = rpmGetPath("%{_repackage_name_fmt}", NULL);
    01711                 const char * pkgbn =
    01712                         headerSprintf(fi->h, bfmt, rpmTagTable, rpmHeaderFormats, NULL);
    01713
    01714                 bfmt = _free(bfmt);
    01715                 psm->pkgURL = rpmGenPath("%{?_repackage_root}",
    01716                                          "%{?_repackage_dir}",
    01717                                         pkgbn);
    01718                 pkgbn = _free(pkgbn);
    01719                 (void) urlPath(psm->pkgURL, &psm->pkgfn);
    01720                 psm->fd = Fopen(psm->pkgfn, "w.ufdio");
    01721                 if (psm->fd == NULL || Ferror(psm->fd)) {
    01722                     rc = RPMRC_FAIL;
    01723                     break;
    01724                 }
    01725             }
    01726         }
    01727         break;
    01728     case PSM_PRE:
    01729         if (rpmtsFlags(ts) & RPMTRANS_FLAG_TEST)        break;
    01730
    01731         /* Change root directory if requested and not already done. */
    01732         rc = rpmpsmStage(psm, PSM_CHROOT_IN);
    01733
    01734         if (psm->goal == PSM_PKGINSTALL) {
    01735             psm->scriptTag = RPMTAG_PREIN;
    01736             psm->progTag = RPMTAG_PREINPROG;
    01737
    01738             if (!(rpmtsFlags(ts) & RPMTRANS_FLAG_NOTRIGGERPREIN)) {
    01739                 /* XXX FIXME: implement %triggerprein. */
    01740             }
    01741
    01742             if (!(rpmtsFlags(ts) & RPMTRANS_FLAG_NOPRE)) {
    01743                 rc = rpmpsmStage(psm, PSM_SCRIPT);
    01744                 if (rc != RPMRC_OK) {
    01745                     rpmError(RPMERR_SCRIPT,
    01746                         _("%s: %s scriptlet failed (%d), skipping %s\n"),
    01747                         psm->stepName, tag2sln(psm->scriptTag), rc,
    01748                         rpmteNEVR(psm->te));
    01749                     break;
    01750                 }
    01751             }
    01752         }
    01753
    01754         if (psm->goal == PSM_PKGERASE) {
    01755             psm->scriptTag = RPMTAG_PREUN;
    01756             psm->progTag = RPMTAG_PREUNPROG;
    01757             psm->sense = RPMSENSE_TRIGGERUN;
    01758             psm->countCorrection = -1;
    01759
    01760             if (!(rpmtsFlags(ts) & RPMTRANS_FLAG_NOTRIGGERUN)) {
    01761                 /* Run triggers in other package(s) this package sets off. */
    01762                 rc = rpmpsmStage(psm, PSM_TRIGGERS);
    01763                 if (rc) break;
    01764
    01765                 /* Run triggers in this package other package(s) set off. */
    01766                 rc = rpmpsmStage(psm, PSM_IMMED_TRIGGERS);
    01767                 if (rc) break;
    01768             }
    01769
    01770             if (!(rpmtsFlags(ts) & RPMTRANS_FLAG_NOPREUN))
    01771                 rc = rpmpsmStage(psm, PSM_SCRIPT);
    01772         }
    01773         if (psm->goal == PSM_PKGSAVE) {
    01774             int noArchiveSize = 0;
    01775
    01776             /* Regenerate original header. */
    01777             {   void * uh = NULL;
    01778                 int_32 uht, uhc;
    01779
    01780                 if (headerGetEntry(fi->h, RPMTAG_HEADERIMMUTABLE, &uht, &uh, &uhc)) {
    01781                     psm->oh = headerCopyLoad(uh);
    01782                     uh = hfd(uh, uht);
    01783                 } else
    01784                 if (headerGetEntry(fi->h, RPMTAG_HEADERIMAGE, &uht, &uh, &uhc))
    01785                 {
    01786                     HeaderIterator hi;
    01787                     int_32 tag, type, count;
    01788                     hPTR_t ptr;
    01789                     Header oh;
    01790
    01791                     /* Load the original header from the blob. */
    01792                     oh = headerCopyLoad(uh);
    01793
    01794                     /* XXX this is headerCopy w/o headerReload() */
    01795                     psm->oh = headerNew();
    01796
    01797                     /*@-branchstate@*/
    01798                     for (hi = headerInitIterator(oh);
    01799                         headerNextIterator(hi, &tag, &type, &ptr, &count);
    01800                         ptr = headerFreeData((void *)ptr, type))
    01801                     {
    01802                         if (tag == RPMTAG_ARCHIVESIZE)
    01803                             noArchiveSize = 1;
    01804                         if (ptr) (void) headerAddEntry(psm->oh, tag, type, ptr, count);
    01805                     }
    01806                     hi = headerFreeIterator(hi);
    01807                     /*@=branchstate@*/
    01808
    01809                     oh = headerFree(oh);
    01810                     uh = hfd(uh, uht);
    01811                 } else
    01812                     break;      /* XXX shouldn't ever happen */
    01813             }
    01814
    01815             /* Retrieve type of payload compression. */
    01816             /*@-nullstate@*/    /* FIX: psm->oh may be NULL */
    01817             rc = rpmpsmStage(psm, PSM_RPMIO_FLAGS);
    01818             /*@=nullstate@*/
    01819
    01820             /* Write the lead section into the package. */
    01821             {   int archnum = -1;
    01822                 int osnum = -1;
    01823                 struct rpmlead lead;
    01824
    01825 #ifndef DYING
    01826                 rpmGetArchInfo(NULL, &archnum);
    01827                 rpmGetOsInfo(NULL, &osnum);
    01828 #endif
    01829
    01830                 memset(&lead, 0, sizeof(lead));
    01831                 /* XXX Set package version conditioned on noDirTokens. */
    01832                 lead.major = 3;
    01833                 lead.minor = 0;
    01834                 lead.type = RPMLEAD_BINARY;
    01835                 lead.archnum = archnum;
    01836                 lead.osnum = osnum;
    01837                 lead.signature_type = RPMSIGTYPE_HEADERSIG;
    01838
    01839                 strncpy(lead.name, rpmteNEVR(psm->te), sizeof(lead.name));
    01840
    01841                 rc = writeLead(psm->fd, &lead);
    01842                 if (rc != RPMRC_OK) {
    01843                     rpmError(RPMERR_NOSPACE, _("Unable to write package: %s\n"),
    01844                          Fstrerror(psm->fd));
    01845                     break;
    01846                 }
    01847             }
    01848
    01849             /* Write the signature section into the package. */
    01850             /* XXX rpm-4.1 and later has archive size in signature header. */
    01851             {   Header sigh = headerRegenSigHeader(fi->h, noArchiveSize);
    01852                 /* Reallocate the signature into one contiguous region. */
    01853                 sigh = headerReload(sigh, RPMTAG_HEADERSIGNATURES);
    01854                 if (sigh == NULL) {
    01855                     rpmError(RPMERR_NOSPACE, _("Unable to reload signature header\n"));
    01856                     rc = RPMRC_FAIL;
    01857                     break;
    01858                 }
    01859                 rc = rpmWriteSignature(psm->fd, sigh);
    01860                 sigh = rpmFreeSignature(sigh);
    01861                 if (rc) break;
    01862             }
    01863
    01864             /* Add remove transaction id to header. */
    01865             if (psm->oh)
    01866             {   int_32 tid = rpmtsGetTid(ts);
    01867                 xx = headerAddEntry(psm->oh, RPMTAG_REMOVETID,
    01868                         RPM_INT32_TYPE, &tid, 1);
    01869             }
    01870
    01871             /* Write the metadata section into the package. */
    01872             rc = headerWrite(psm->fd, psm->oh, HEADER_MAGIC_YES);
    01873             if (rc) break;
    01874         }
    01875         break;
    01876     case PSM_PROCESS:
    01877         if (rpmtsFlags(ts) & RPMTRANS_FLAG_TEST)        break;
    01878
    01879         if (psm->goal == PSM_PKGINSTALL) {
    01880             int i;
    01881
    01882             if (rpmtsFlags(ts) & RPMTRANS_FLAG_JUSTDB)  break;
    01883
    01884             /* XXX Synthesize callbacks for packages with no files. */
    01885             if (rpmfiFC(fi) <= 0) {
    01886                 void * ptr;
    01887                 ptr = rpmtsNotify(ts, fi->te, RPMCALLBACK_INST_START, 0, 100);
    01888                 ptr = rpmtsNotify(ts, fi->te, RPMCALLBACK_INST_PROGRESS, 100, 100);
    01889                 break;
    01890             }
    01891
    01892             (void) rpmfiInit(fi, 0);
    01893             while ((i = rpmfiNext(fi)) >= 0) {
    01894                 uid_t uid;
    01895                 gid_t gid;
    01896
    01897                 uid = fi->uid;
    01898                 gid = fi->gid;
    01899                 if (fi->fuser && unameToUid(fi->fuser[i], &uid)) {
    01900                     rpmMessage(RPMMESS_WARNING,
    01901                         _("user %s does not exist - using root\n"),
    01902                         fi->fuser[i]);
    01903                     uid = 0;
    01904                     /* XXX this diddles header memory. */
    01905                     fi->fmodes[i] &= ~S_ISUID;  /* turn off the suid bit */
    01906                 }
    01907
    01908                 if (fi->fgroup && gnameToGid(fi->fgroup[i], &gid)) {
    01909                     rpmMessage(RPMMESS_WARNING,
    01910                         _("group %s does not exist - using root\n"),
    01911                         fi->fgroup[i]);
    01912                     gid = 0;
    01913                     /* XXX this diddles header memory. */
    01914                     fi->fmodes[i] &= ~S_ISGID;  /* turn off the sgid bit */
    01915                 }
    01916                 if (fi->fuids) fi->fuids[i] = uid;
    01917                 if (fi->fgids) fi->fgids[i] = gid;
    01918             }
    01919
    01920             /* Retrieve type of payload compression. */
    01921             rc = rpmpsmStage(psm, PSM_RPMIO_FLAGS);
    01922
    01923             if (rpmteFd(fi->te) == NULL) {      /* XXX can't happen */
    01924                 rc = RPMRC_FAIL;
    01925                 break;
    01926             }
    01927
    01928             /*@-nullpass@*/     /* LCL: fi->fd != NULL here. */
    01929             psm->cfd = Fdopen(fdDup(Fileno(rpmteFd(fi->te))), psm->rpmio_flags);
    01930             /*@=nullpass@*/
    01931             if (psm->cfd == NULL) {     /* XXX can't happen */
    01932                 rc = RPMRC_FAIL;
    01933                 break;
    01934             }
    01935
    01936             rc = fsmSetup(fi->fsm, FSM_PKGINSTALL, ts, fi,
    01937                         psm->cfd, NULL, &psm->failedFile);
    01938             xx = fsmTeardown(fi->fsm);
    01939
    01940             saveerrno = errno; /* XXX FIXME: Fclose with libio destroys errno */
    01941             xx = Fclose(psm->cfd);
    01942             psm->cfd = NULL;
    01943             /*@-mods@*/
    01944             errno = saveerrno; /* XXX FIXME: Fclose with libio destroys errno */
    01945             /*@=mods@*/
    01946
    01947             if (!rc)
    01948                 rc = rpmpsmStage(psm, PSM_COMMIT);
    01949
    01950             /* XXX make sure progress is closed out */
    01951             psm->what = RPMCALLBACK_INST_PROGRESS;
    01952             psm->amount = (fi->archiveSize ? fi->archiveSize : 100);
    01953             psm->total = psm->amount;
    01954             xx = rpmpsmStage(psm, PSM_NOTIFY);
    01955
    01956             if (rc) {
    01957                 rpmError(RPMERR_CPIO,
    01958                         _("unpacking of archive failed%s%s: %s\n"),
    01959                         (psm->failedFile != NULL ? _(" on file ") : ""),
    01960                         (psm->failedFile != NULL ? psm->failedFile : ""),
    01961                         cpioStrerror(rc));
    01962                 rc = RPMRC_FAIL;
    01963
    01964                 /* XXX notify callback on error. */
    01965                 psm->what = RPMCALLBACK_UNPACK_ERROR;
    01966                 psm->amount = 0;
    01967                 psm->total = 0;
    01968                 xx = rpmpsmStage(psm, PSM_NOTIFY);
    01969
    01970                 break;
    01971             }
    01972         }
    01973         if (psm->goal == PSM_PKGERASE) {
    01974             int fc = rpmfiFC(fi);
    01975
    01976             if (rpmtsFlags(ts) & RPMTRANS_FLAG_JUSTDB)  break;
    01977             if (rpmtsFlags(ts) & RPMTRANS_FLAG_APPLYONLY)       break;
    01978             if (fc <= 0)                                break;
    01979
    01980             psm->what = RPMCALLBACK_UNINST_START;
    01981             psm->amount = fc;           /* XXX W2DO? looks wrong. */
    01982             psm->total = fc;
    01983             xx = rpmpsmStage(psm, PSM_NOTIFY);
    01984
    01985             rc = fsmSetup(fi->fsm, FSM_PKGERASE, ts, fi,
    01986                         NULL, NULL, &psm->failedFile);
    01987             xx = fsmTeardown(fi->fsm);
    01988
    01989             psm->what = RPMCALLBACK_UNINST_STOP;
    01990             psm->amount = 0;            /* XXX W2DO? looks wrong. */
    01991             psm->total = fc;
    01992             xx = rpmpsmStage(psm, PSM_NOTIFY);
    01993
    01994         }
    01995         if (psm->goal == PSM_PKGSAVE) {
    01996             fileAction * actions = fi->actions;
    01997             fileAction action = fi->action;
    01998
    01999             fi->action = FA_COPYOUT;
    02000             fi->actions = NULL;
    02001
    02002             if (psm->fd == NULL) {      /* XXX can't happen */
    02003                 rc = RPMRC_FAIL;
    02004                 break;
    02005             }
    02006             /*@-nullpass@*/     /* FIX: fdDup mey return NULL. */
    02007             xx = Fflush(psm->fd);
    02008             psm->cfd = Fdopen(fdDup(Fileno(psm->fd)), psm->rpmio_flags);
    02009             /*@=nullpass@*/
    02010             if (psm->cfd == NULL) {     /* XXX can't happen */
    02011                 rc = RPMRC_FAIL;
    02012                 break;
    02013             }
    02014
    02015             rc = fsmSetup(fi->fsm, FSM_PKGBUILD, ts, fi, psm->cfd,
    02016                         NULL, &psm->failedFile);
    02017             xx = fsmTeardown(fi->fsm);
    02018
    02019             saveerrno = errno; /* XXX FIXME: Fclose with libio destroys errno */
    02020             xx = Fclose(psm->cfd);
    02021             psm->cfd = NULL;
    02022             /*@-mods@*/
    02023             errno = saveerrno;
    02024             /*@=mods@*/
    02025
    02026             /* XXX make sure progress is closed out */
    02027             psm->what = RPMCALLBACK_INST_PROGRESS;
    02028             psm->amount = (fi->archiveSize ? fi->archiveSize : 100);
    02029             psm->total = psm->amount;
    02030             xx = rpmpsmStage(psm, PSM_NOTIFY);
    02031
    02032             fi->action = action;
    02033             fi->actions = actions;
    02034         }
    02035         break;
    02036     case PSM_POST:
    02037         if (rpmtsFlags(ts) & RPMTRANS_FLAG_TEST)        break;
    02038
    02039         if (psm->goal == PSM_PKGINSTALL) {
    02040             int_32 installTime = (int_32) time(NULL);
    02041             int fc = rpmfiFC(fi);
    02042
    02043             if (fi->h == NULL) break;   /* XXX can't happen */
    02044             if (fi->fstates != NULL && fc > 0)
    02045                 xx = headerAddEntry(fi->h, RPMTAG_FILESTATES, RPM_CHAR_TYPE,
    02046                                 fi->fstates, fc);
    02047
    02048             xx = headerAddEntry(fi->h, RPMTAG_INSTALLTIME, RPM_INT32_TYPE,
    02049                                 &installTime, 1);
    02050
    02051             if (rpmtsFlags(ts) & RPMTRANS_FLAG_MULTILIB) {
    02052                 uint_32 multiLib, * newMultiLib, * p;
    02053
    02054                 if (hge(fi->h, RPMTAG_MULTILIBS, NULL,
    02055                                 (void **) &newMultiLib, NULL) &&
    02056                     hge(psm->oh, RPMTAG_MULTILIBS, NULL,
    02057                                 (void **) &p, NULL))
    02058                 {
    02059                     multiLib = *p;
    02060                     multiLib |= *newMultiLib;
    02061                     xx = hme(psm->oh, RPMTAG_MULTILIBS, RPM_INT32_TYPE,
    02062                                       &multiLib, 1);
    02063                 }
    02064                 rc = mergeFiles(fi, psm->oh, fi->h);
    02065                 if (rc) break;
    02066             }
    02067
    02068
    02069             /*
    02070              * If this package has already been installed, remove it from
    02071              * the database before adding the new one.
    02072              */
    02073             if (fi->record && !(rpmtsFlags(ts) & RPMTRANS_FLAG_APPLYONLY)) {
    02074                 rc = rpmpsmStage(psm, PSM_RPMDB_REMOVE);
    02075                 if (rc) break;
    02076             }
    02077
    02078             rc = rpmpsmStage(psm, PSM_RPMDB_ADD);
    02079             if (rc) break;
    02080
    02081             psm->scriptTag = RPMTAG_POSTIN;
    02082             psm->progTag = RPMTAG_POSTINPROG;
    02083             psm->sense = RPMSENSE_TRIGGERIN;
    02084             psm->countCorrection = 0;
    02085
    02086             if (!(rpmtsFlags(ts) & RPMTRANS_FLAG_NOPOST)) {
    02087                 rc = rpmpsmStage(psm, PSM_SCRIPT);
    02088                 if (rc) break;
    02089             }
    02090             if (!(rpmtsFlags(ts) & RPMTRANS_FLAG_NOTRIGGERIN)) {
    02091                 /* Run triggers in other package(s) this package sets off. */
    02092                 rc = rpmpsmStage(psm, PSM_TRIGGERS);
    02093                 if (rc) break;
    02094
    02095                 /* Run triggers in this package other package(s) set off. */
    02096                 rc = rpmpsmStage(psm, PSM_IMMED_TRIGGERS);
    02097                 if (rc) break;
    02098             }
    02099
    02100             if (!(rpmtsFlags(ts) & RPMTRANS_FLAG_APPLYONLY))
    02101                 rc = markReplacedFiles(psm);
    02102
    02103         }
    02104         if (psm->goal == PSM_PKGERASE) {
    02105
    02106             psm->scriptTag = RPMTAG_POSTUN;
    02107             psm->progTag = RPMTAG_POSTUNPROG;
    02108             psm->sense = RPMSENSE_TRIGGERPOSTUN;
    02109             psm->countCorrection = -1;
    02110
    02111             if (!(rpmtsFlags(ts) & RPMTRANS_FLAG_NOPOSTUN)) {
    02112                 rc = rpmpsmStage(psm, PSM_SCRIPT);
    02113                 /* XXX WTFO? postun failures don't cause erasure failure. */
    02114             }
    02115
    02116             if (!(rpmtsFlags(ts) & RPMTRANS_FLAG_NOTRIGGERPOSTUN)) {
    02117                 /* Run triggers in other package(s) this package sets off. */
    02118                 rc = rpmpsmStage(psm, PSM_TRIGGERS);
    02119                 if (rc) break;
    02120             }
    02121
    02122             if (!(rpmtsFlags(ts) & RPMTRANS_FLAG_APPLYONLY))
    02123                 rc = rpmpsmStage(psm, PSM_RPMDB_REMOVE);
    02124         }
    02125         if (psm->goal == PSM_PKGSAVE) {
    02126         }
    02127
    02128         /* Restore root directory if changed. */
    02129         xx = rpmpsmStage(psm, PSM_CHROOT_OUT);
    02130         break;
    02131     case PSM_UNDO:
    02132         break;
    02133     case PSM_FINI:
    02134         /* Restore root directory if changed. */
    02135         xx = rpmpsmStage(psm, PSM_CHROOT_OUT);
    02136
    02137         if (psm->fd) {
    02138             saveerrno = errno; /* XXX FIXME: Fclose with libio destroys errno */
    02139             xx = Fclose(psm->fd);
    02140             psm->fd = NULL;
    02141             /*@-mods@*/
    02142             errno = saveerrno;
    02143             /*@=mods@*/
    02144         }
    02145
    02146         if (psm->goal == PSM_PKGSAVE) {
    02147             if (!rc && ts && ts->notify == NULL) {
    02148                 rpmMessage(RPMMESS_VERBOSE, _("Wrote: %s\n"),
    02149                         (psm->pkgURL ? psm->pkgURL : "???"));
    02150             }
    02151         }
    02152
    02153         if (rc) {
    02154             if (psm->failedFile)
    02155                 rpmError(RPMERR_CPIO,
    02156                         _("%s failed on file %s: %s\n"),
    02157                         psm->stepName, psm->failedFile, cpioStrerror(rc));
    02158             else
    02159                 rpmError(RPMERR_CPIO, _("%s failed: %s\n"),
    02160                         psm->stepName, cpioStrerror(rc));
    02161
    02162             /* XXX notify callback on error. */
    02163             psm->what = RPMCALLBACK_CPIO_ERROR;
    02164             psm->amount = 0;
    02165             psm->total = 0;
    02166             /*@-nullstate@*/ /* FIX: psm->fd may be NULL. */
    02167             xx = rpmpsmStage(psm, PSM_NOTIFY);
    02168             /*@=nullstate@*/
    02169         }
    02170
    02171         if (psm->goal == PSM_PKGERASE || psm->goal == PSM_PKGSAVE) {
    02172 if (psm->te)
    02173 if (psm->te->h)
    02174 psm->te->h = headerFree(psm->te->h);
    02175             if (fi->h)
    02176                 fi->h = headerFree(fi->h);
    02177         }
    02178         psm->oh = headerFree(psm->oh);
    02179         psm->pkgURL = _free(psm->pkgURL);
    02180         psm->rpmio_flags = _free(psm->rpmio_flags);
    02181         psm->failedFile = _free(psm->failedFile);
    02182
    02183         fi->fgids = _free(fi->fgids);
    02184         fi->fuids = _free(fi->fuids);
    02185         fi->fgroup = hfd(fi->fgroup, -1);
    02186         fi->fuser = hfd(fi->fuser, -1);
    02187         fi->apath = _free(fi->apath);
    02188         fi->fstates = _free(fi->fstates);
    02189         break;
    02190
    02191     case PSM_PKGINSTALL:
    02192     case PSM_PKGERASE:
    02193     case PSM_PKGSAVE:
    02194         psm->goal = stage;
    02195         psm->rc = RPMRC_OK;
    02196         psm->stepName = pkgStageString(stage);
    02197
    02198         rc = rpmpsmStage(psm, PSM_INIT);
    02199         if (!rc) rc = rpmpsmStage(psm, PSM_PRE);
    02200         if (!rc) rc = rpmpsmStage(psm, PSM_PROCESS);
    02201         if (!rc) rc = rpmpsmStage(psm, PSM_POST);
    02202         xx = rpmpsmStage(psm, PSM_FINI);
    02203         break;
    02204     case PSM_PKGCOMMIT:
    02205         break;
    02206
    02207     case PSM_CREATE:
    02208         break;
    02209     case PSM_NOTIFY:
    02210     {   void * ptr;
    02211 /*@-nullpass@*/ /* FIX: psm->te may be NULL */
    02212         ptr = rpmtsNotify(ts, psm->te, psm->what, psm->amount, psm->total);
    02213 /*@-nullpass@*/
    02214     }   break;
    02215     case PSM_DESTROY:
    02216         break;
    02217     case PSM_COMMIT:
    02218         if (!(rpmtsFlags(ts) & RPMTRANS_FLAG_PKGCOMMIT)) break;
    02219         if (rpmtsFlags(ts) & RPMTRANS_FLAG_APPLYONLY) break;
    02220
    02221         rc = fsmSetup(fi->fsm, FSM_PKGCOMMIT, ts, fi,
    02222                         NULL, NULL, &psm->failedFile);
    02223         xx = fsmTeardown(fi->fsm);
    02224         break;
    02225
    02226     case PSM_CHROOT_IN:
    02227     {   const char * rootDir = rpmtsRootDir(ts);
    02228         /* Change root directory if requested and not already done. */
    02229         if (rootDir != NULL && !rpmtsChrootDone(ts) && !psm->chrootDone) {
    02230             static int _loaded = 0;
    02231
    02232             /*
    02233              * This loads all of the name services libraries, in case we
    02234              * don't have access to them in the chroot().
    02235              */
    02236             if (!_loaded) {
    02237                 (void)getpwnam("root");
    02238                 endpwent();
    02239                 _loaded++;
    02240             }
    02241
    02242             xx = chdir("/");
    02243             /*@-superuser@*/
    02244             rc = chroot(rootDir);
    02245             /*@=superuser@*/
    02246             psm->chrootDone = 1;
    02247             (void) rpmtsSetChrootDone(ts, 1);
    02248         }
    02249     }   break;
    02250     case PSM_CHROOT_OUT:
    02251         /* Restore root directory if changed. */
    02252         if (psm->chrootDone) {
    02253             const char * currDir = rpmtsCurrDir(ts);
    02254             /*@-superuser@*/
    02255             rc = chroot(".");
    02256             /*@=superuser@*/
    02257             psm->chrootDone = 0;
    02258             (void) rpmtsSetChrootDone(ts, 0);
    02259             if (currDir != NULL)        /* XXX can't happen */
    02260                 xx = chdir(currDir);
    02261         }
    02262         break;
    02263     case PSM_SCRIPT:    /* Run current package scriptlets. */
    02264         rc = runInstScript(psm);
    02265         break;
    02266     case PSM_TRIGGERS:
    02267         /* Run triggers in other package(s) this package sets off. */
    02268         rc = runTriggers(psm);
    02269         break;
    02270     case PSM_IMMED_TRIGGERS:
    02271         /* Run triggers in this package other package(s) set off. */
    02272         rc = runImmedTriggers(psm);
    02273         break;
    02274
    02275     case PSM_RPMIO_FLAGS:
    02276     {   const char * payload_compressor = NULL;
    02277         char * t;
    02278
    02279         /*@-branchstate@*/
    02280         if (!hge(fi->h, RPMTAG_PAYLOADCOMPRESSOR, NULL,
    02281                             (void **) &payload_compressor, NULL))
    02282             payload_compressor = "gzip";
    02283         /*@=branchstate@*/
    02284         psm->rpmio_flags = t = xmalloc(sizeof("w9.gzdio"));
    02285         *t = '\0';
    02286         t = stpcpy(t, ((psm->goal == PSM_PKGSAVE) ? "w9" : "r"));
    02287         if (!strcmp(payload_compressor, "gzip"))
    02288             t = stpcpy(t, ".gzdio");
    02289         if (!strcmp(payload_compressor, "bzip2"))
    02290             t = stpcpy(t, ".bzdio");
    02291         rc = RPMRC_OK;
    02292     }   break;
    02293
    02294     case PSM_RPMDB_LOAD:
    02295 assert(psm->mi == NULL);
    02296         psm->mi = rpmtsInitIterator(ts, RPMDBI_PACKAGES,
    02297                                 &fi->record, sizeof(fi->record));
    02298
    02299         fi->h = rpmdbNextIterator(psm->mi);
    02300         if (fi->h)
    02301             fi->h = headerLink(fi->h);
    02302
    02303         psm->mi = rpmdbFreeIterator(psm->mi);
    02304         rc = (fi->h ? RPMRC_OK : RPMRC_FAIL);
    02305         break;
    02306     case PSM_RPMDB_ADD:
    02307         if (rpmtsFlags(ts) & RPMTRANS_FLAG_TEST)        break;
    02308         if (fi->h == NULL)      break;  /* XXX can't happen */
    02309         if (!(rpmtsVSFlags(ts) & RPMVSF_NOHDRCHK))
    02310             rc = rpmdbAdd(rpmtsGetRdb(ts), rpmtsGetTid(ts), fi->h,
    02311                                 ts, headerCheck);
    02312         else
    02313             rc = rpmdbAdd(rpmtsGetRdb(ts), rpmtsGetTid(ts), fi->h,
    02314                                 NULL, NULL);
    02315         break;
    02316     case PSM_RPMDB_REMOVE:
    02317         if (rpmtsFlags(ts) & RPMTRANS_FLAG_TEST)        break;
    02318         rc = rpmdbRemove(rpmtsGetRdb(ts), rpmtsGetTid(ts), fi->record,
    02319                                 NULL, NULL);
    02320         break;
    02321
    02322     default:
    02323         break;
    02324 /*@i@*/    }
    02325     /*@=branchstate@*/
    02326
    02327     /*@-nullstate@*/    /* FIX: psm->oh and psm->fi->h may be NULL. */
    02328     return rc;
    02329     /*@=nullstate@*/
    02330 }
    02331 /*@=bounds =nullpass@*/