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 <rpmlib.h>
00009 #include <rpmmacro.h>
00010 #include <rpmurl.h>
00011 
00012 #include "psm.h"
00013 #include "rpmlead.h"            /* writeLead proto */
00014 #include "signature.h"          /* signature constants */
00015 #include "misc.h"
00016 #include "debug.h"
00017 
00018 /*@access Header @*/            /* compared with NULL */
00019 /*@access rpmTransactionSet @*/ /* compared with NULL */
00020 /*@access rpmdbMatchIterator @*/ /* compared with NULL */
00021 /*@access TFI_t @*/             /* compared with NULL */
00022 /*@access FSM_t @*/             /* compared with NULL */
00023 /*@access PSM_t @*/             /* compared with NULL */
00024 /*@access FD_t @*/              /* compared with NULL */
00025 
00026 extern int _fsm_debug;
00027 
00033 static /*@null@*/ void * _free(/*@only@*/ /*@null@*/ const void * this) {
00034     if (this)   free((void *)this);
00035     return NULL;
00036 }
00037 
00038 int rpmVersionCompare(Header first, Header second)
00039 {
00040     const char * one, * two;
00041     int_32 * epochOne, * epochTwo;
00042     int rc;
00043 
00044     if (!headerGetEntry(first, RPMTAG_EPOCH, NULL, (void **) &epochOne, NULL))
00045         epochOne = NULL;
00046     if (!headerGetEntry(second, RPMTAG_EPOCH, NULL, (void **) &epochTwo,
00047                         NULL))
00048         epochTwo = NULL;
00049 
00050     if (epochOne && !epochTwo)
00051         return 1;
00052     else if (!epochOne && epochTwo)
00053         return -1;
00054     else if (epochOne && epochTwo) {
00055         if (*epochOne < *epochTwo)
00056             return -1;
00057         else if (*epochOne > *epochTwo)
00058             return 1;
00059     }
00060 
00061     headerGetEntry(first, RPMTAG_VERSION, NULL, (void **) &one, NULL);
00062     headerGetEntry(second, RPMTAG_VERSION, NULL, (void **) &two, NULL);
00063 
00064     rc = rpmvercmp(one, two);
00065     if (rc)
00066         return rc;
00067 
00068     headerGetEntry(first, RPMTAG_RELEASE, NULL, (void **) &one, NULL);
00069     headerGetEntry(second, RPMTAG_RELEASE, NULL, (void **) &two, NULL);
00070 
00071     return rpmvercmp(one, two);
00072 }
00073 
00074 void loadFi(Header h, TFI_t fi)
00075 {
00076     HGE_t hge;
00077     HFD_t hfd;
00078     uint_32 * uip;
00079     int len;
00080     int rc;
00081     int i;
00082     
00083     if (fi->fsm == NULL)
00084         fi->fsm = newFSM();
00085 
00086     /* XXX avoid gcc noise on pointer (4th arg) cast(s) */
00087     hge = (fi->type == TR_ADDED)
00088         ? (HGE_t) headerGetEntryMinMemory : (HGE_t) headerGetEntry;
00089     fi->hge = hge;
00090 
00091     fi->hfd = hfd = headerFreeData;
00092 
00093     if (h && fi->h == NULL)     fi->h = headerLink(h);
00094 
00095     /* Duplicate name-version-release so that headers can be free'd. */
00096     hge(fi->h, RPMTAG_NAME, NULL, (void **) &fi->name, NULL);
00097     fi->name = xstrdup(fi->name);
00098     hge(fi->h, RPMTAG_VERSION, NULL, (void **) &fi->version, NULL);
00099     fi->version = xstrdup(fi->version);
00100     hge(fi->h, RPMTAG_RELEASE, NULL, (void **) &fi->release, NULL);
00101     fi->release = xstrdup(fi->release);
00102 
00103     /* -1 means not found */
00104     rc = hge(fi->h, RPMTAG_EPOCH, NULL, (void **) &uip, NULL);
00105     fi->epoch = (rc ? *uip : -1);
00106     /* 0 means unknown */
00107     rc = hge(fi->h, RPMTAG_ARCHIVESIZE, NULL, (void **) &uip, NULL);
00108     fi->archiveSize = (rc ? *uip : 0);
00109 
00110     if (!hge(fi->h, RPMTAG_BASENAMES, NULL, (void **) &fi->bnl, &fi->fc)) {
00111         fi->dc = 0;
00112         fi->fc = 0;
00113         return;
00114     }
00115 
00116     hge(fi->h, RPMTAG_DIRINDEXES, NULL, (void **) &fi->dil, NULL);
00117     hge(fi->h, RPMTAG_DIRNAMES, NULL, (void **) &fi->dnl, &fi->dc);
00118     hge(fi->h, RPMTAG_FILEMODES, NULL, (void **) &fi->fmodes, NULL);
00119     hge(fi->h, RPMTAG_FILEFLAGS, NULL, (void **) &fi->fflags, NULL);
00120     hge(fi->h, RPMTAG_FILESIZES, NULL, (void **) &fi->fsizes, NULL);
00121     hge(fi->h, RPMTAG_FILESTATES, NULL, (void **) &fi->fstates, NULL);
00122 
00123     fi->action = FA_UNKNOWN;
00124     fi->flags = 0;
00125 
00126     /* actions is initialized earlier for added packages */
00127     if (fi->actions == NULL)
00128         fi->actions = xcalloc(fi->fc, sizeof(*fi->actions));
00129 
00130     switch (fi->type) {
00131     case TR_ADDED:
00132         fi->mapflags = CPIO_MAP_PATH | CPIO_MAP_MODE | CPIO_MAP_UID | CPIO_MAP_GID;
00133         hge(fi->h, RPMTAG_FILEMD5S, NULL, (void **) &fi->fmd5s, NULL);
00134         hge(fi->h, RPMTAG_FILELINKTOS, NULL, (void **) &fi->flinks, NULL);
00135         hge(fi->h, RPMTAG_FILELANGS, NULL, (void **) &fi->flangs, NULL);
00136         hge(fi->h, RPMTAG_FILEMTIMES, NULL, (void **) &fi->fmtimes, NULL);
00137 
00138         /* 0 makes for noops */
00139         fi->replacedSizes = xcalloc(fi->fc, sizeof(*fi->replacedSizes));
00140 
00141         break;
00142     case TR_REMOVED:
00143         fi->mapflags = CPIO_MAP_ABSOLUTE | CPIO_MAP_ADDDOT | CPIO_MAP_PATH | CPIO_MAP_MODE;
00144         hge(fi->h, RPMTAG_FILEMD5S, NULL, (void **) &fi->fmd5s, NULL);
00145         hge(fi->h, RPMTAG_FILELINKTOS, NULL, (void **) &fi->flinks, NULL);
00146         fi->fsizes = memcpy(xmalloc(fi->fc * sizeof(*fi->fsizes)),
00147                                 fi->fsizes, fi->fc * sizeof(*fi->fsizes));
00148         fi->fflags = memcpy(xmalloc(fi->fc * sizeof(*fi->fflags)),
00149                                 fi->fflags, fi->fc * sizeof(*fi->fflags));
00150         fi->fmodes = memcpy(xmalloc(fi->fc * sizeof(*fi->fmodes)),
00151                                 fi->fmodes, fi->fc * sizeof(*fi->fmodes));
00152         /* XXX there's a tedious segfault here for some version(s) of rpm */
00153         if (fi->fstates)
00154             fi->fstates = memcpy(xmalloc(fi->fc * sizeof(*fi->fstates)),
00155                                 fi->fstates, fi->fc * sizeof(*fi->fstates));
00156         else
00157             fi->fstates = xcalloc(1, fi->fc * sizeof(*fi->fstates));
00158         fi->dil = memcpy(xmalloc(fi->fc * sizeof(*fi->dil)),
00159                                 fi->dil, fi->fc * sizeof(*fi->dil));
00160         headerFree(fi->h);
00161         fi->h = NULL;
00162         break;
00163     }
00164 
00165     fi->dnlmax = -1;
00166     for (i = 0; i < fi->dc; i++) {
00167         if ((len = strlen(fi->dnl[i])) > fi->dnlmax)
00168             fi->dnlmax = len;
00169     }
00170 
00171     fi->bnlmax = -1;
00172     for (i = 0; i < fi->fc; i++) {
00173         if ((len = strlen(fi->bnl[i])) > fi->bnlmax)
00174             fi->bnlmax = len;
00175     }
00176 
00177     fi->dperms = 0755;
00178     fi->fperms = 0644;
00179 
00180     return;
00181 }
00182 
00183 void freeFi(TFI_t fi)
00184 {
00185     HFD_t hfd = (fi->hfd ? fi->hfd : headerFreeData);
00186 
00187     fi->name = _free(fi->name);
00188     fi->version = _free(fi->version);
00189     fi->release = _free(fi->release);
00190     fi->actions = _free(fi->actions);
00191     fi->replacedSizes = _free(fi->replacedSizes);
00192     fi->replaced = _free(fi->replaced);
00193 
00194     fi->bnl = hfd(fi->bnl, -1);
00195     fi->dnl = hfd(fi->dnl, -1);
00196     fi->obnl = hfd(fi->obnl, -1);
00197     fi->odnl = hfd(fi->odnl, -1);
00198     fi->flinks = hfd(fi->flinks, -1);
00199     fi->fmd5s = hfd(fi->fmd5s, -1);
00200     fi->fuser = hfd(fi->fuser, -1);
00201     fi->fgroup = hfd(fi->fgroup, -1);
00202     fi->flangs = hfd(fi->flangs, -1);
00203 
00204     fi->apath = _free(fi->apath);
00205     fi->fuids = _free(fi->fuids);
00206     fi->fgids = _free(fi->fgids);
00207     fi->fmapflags = _free(fi->fmapflags);
00208 
00209     fi->fsm = freeFSM(fi->fsm);
00210 
00211     switch (fi->type) {
00212     case TR_ADDED:
00213             break;
00214     case TR_REMOVED:
00215         fi->fsizes = hfd(fi->fsizes, -1);
00216         fi->fflags = hfd(fi->fflags, -1);
00217         fi->fmodes = hfd(fi->fmodes, -1);
00218         fi->fstates = hfd(fi->fstates, -1);
00219         fi->dil = hfd(fi->dil, -1);
00220         break;
00221     }
00222     if (fi->h) {
00223         headerFree(fi->h); fi->h = NULL;
00224     }
00225 }
00226 
00227 /*@observer@*/ const char *const fiTypeString(TFI_t fi) {
00228     switch(fi->type) {
00229     case TR_ADDED:      return " install";
00230     case TR_REMOVED:    return "   erase";
00231     default:            return "???";
00232     }
00233     /*@noteached@*/
00234 }
00235 
00240 static struct tagMacro {
00241         const char *    macroname;      
00242         int             tag;            
00243 } tagMacros[] = {
00244         { "name",       RPMTAG_NAME },
00245         { "version",    RPMTAG_VERSION },
00246         { "release",    RPMTAG_RELEASE },
00247 #if 0
00248         { "epoch",      RPMTAG_EPOCH },
00249 #endif
00250         { NULL, 0 }
00251 };
00252 
00258 static int rpmInstallLoadMacros(TFI_t fi, Header h)
00259 {
00260     HGE_t hge = (HGE_t)fi->hge;
00261     struct tagMacro *tagm;
00262     union {
00263         const char * ptr;
00264         int_32 * i32p;
00265     } body;
00266     char numbuf[32];
00267     int_32 type;
00268 
00269     for (tagm = tagMacros; tagm->macroname != NULL; tagm++) {
00270         if (!hge(h, tagm->tag, &type, (void **) &body, NULL))
00271             continue;
00272         switch (type) {
00273         case RPM_INT32_TYPE:
00274             sprintf(numbuf, "%d", *body.i32p);
00275             addMacro(NULL, tagm->macroname, NULL, numbuf, -1);
00276             break;
00277         case RPM_STRING_TYPE:
00278             addMacro(NULL, tagm->macroname, NULL, body.ptr, -1);
00279             break;
00280         }
00281     }
00282     return 0;
00283 }
00284 
00292 static int mergeFiles(TFI_t fi, Header h, Header newH)
00293 {
00294     HGE_t hge = (HGE_t)fi->hge;
00295     HFD_t hfd = fi->hfd;
00296     fileAction * actions = fi->actions;
00297     int i, j, k, fc;
00298     int_32 type = 0;
00299     int_32 count = 0;
00300     int_32 dirNamesCount, dirCount;
00301     void * data, * newdata;
00302     int_32 * dirIndexes, * newDirIndexes;
00303     uint_32 * fileSizes, fileSize;
00304     const char ** dirNames;
00305     const char ** newDirNames;
00306     static int_32 mergeTags[] = {
00307         RPMTAG_FILESIZES,
00308         RPMTAG_FILESTATES,
00309         RPMTAG_FILEMODES,
00310         RPMTAG_FILERDEVS,
00311         RPMTAG_FILEMTIMES,
00312         RPMTAG_FILEMD5S,
00313         RPMTAG_FILELINKTOS,
00314         RPMTAG_FILEFLAGS,
00315         RPMTAG_FILEUSERNAME,
00316         RPMTAG_FILEGROUPNAME,
00317         RPMTAG_FILEVERIFYFLAGS,
00318         RPMTAG_FILEDEVICES,
00319         RPMTAG_FILEINODES,
00320         RPMTAG_FILELANGS,
00321         RPMTAG_BASENAMES,
00322         0,
00323     };
00324     static int_32 requireTags[] = {
00325         RPMTAG_REQUIRENAME, RPMTAG_REQUIREVERSION, RPMTAG_REQUIREFLAGS,
00326         RPMTAG_PROVIDENAME, RPMTAG_PROVIDEVERSION, RPMTAG_PROVIDEFLAGS,
00327         RPMTAG_CONFLICTNAME, RPMTAG_CONFLICTVERSION, RPMTAG_CONFLICTFLAGS
00328     };
00329 
00330     hge(h, RPMTAG_SIZE, NULL, (void **) &fileSizes, NULL);
00331     fileSize = *fileSizes;
00332     hge(newH, RPMTAG_FILESIZES, NULL, (void **) &fileSizes, &count);
00333     for (i = 0, fc = 0; i < count; i++)
00334         if (actions[i] != FA_SKIPMULTILIB) {
00335             fc++;
00336             fileSize += fileSizes[i];
00337         }
00338     headerModifyEntry(h, RPMTAG_SIZE, RPM_INT32_TYPE, &fileSize, 1);
00339 
00340     for (i = 0; mergeTags[i]; i++) {
00341         if (!hge(newH, mergeTags[i], &type, (void **) &data, &count))
00342             continue;
00343         switch (type) {
00344         case RPM_CHAR_TYPE:
00345         case RPM_INT8_TYPE:
00346             newdata = xmalloc(fc * sizeof(int_8));
00347             for (j = 0, k = 0; j < count; j++)
00348                 if (actions[j] != FA_SKIPMULTILIB)
00349                         ((int_8 *) newdata)[k++] = ((int_8 *) data)[j];
00350             headerAddOrAppendEntry(h, mergeTags[i], type, newdata, fc);
00351             free (newdata);
00352             break;
00353         case RPM_INT16_TYPE:
00354             newdata = xmalloc(fc * sizeof(int_16));
00355             for (j = 0, k = 0; j < count; j++)
00356                 if (actions[j] != FA_SKIPMULTILIB)
00357                     ((int_16 *) newdata)[k++] = ((int_16 *) data)[j];
00358             headerAddOrAppendEntry(h, mergeTags[i], type, newdata, fc);
00359             free (newdata);
00360             break;
00361         case RPM_INT32_TYPE:
00362             newdata = xmalloc(fc * sizeof(int_32));
00363             for (j = 0, k = 0; j < count; j++)
00364                 if (actions[j] != FA_SKIPMULTILIB)
00365                     ((int_32 *) newdata)[k++] = ((int_32 *) data)[j];
00366             headerAddOrAppendEntry(h, mergeTags[i], type, newdata, fc);
00367             free (newdata);
00368             break;
00369         case RPM_STRING_ARRAY_TYPE:
00370             newdata = xmalloc(fc * sizeof(char *));
00371             for (j = 0, k = 0; j < count; j++)
00372                 if (actions[j] != FA_SKIPMULTILIB)
00373                     ((char **) newdata)[k++] = ((char **) data)[j];
00374             headerAddOrAppendEntry(h, mergeTags[i], type, newdata, fc);
00375             free (newdata);
00376             break;
00377         default:
00378             rpmError(RPMERR_DATATYPE, _("Data type %d not supported\n"),
00379                         (int) type);
00380             return 1;
00381             /*@notreached@*/ break;
00382         }
00383         data = hfd(data, type);
00384     }
00385     hge(newH, RPMTAG_DIRINDEXES, NULL, (void **) &newDirIndexes, &count);
00386     hge(newH, RPMTAG_DIRNAMES, NULL, (void **) &newDirNames, NULL);
00387     hge(h, RPMTAG_DIRINDEXES, NULL, (void **) &dirIndexes, NULL);
00388     hge(h, RPMTAG_DIRNAMES, NULL, (void **) &data, &dirNamesCount);
00389 
00390     dirNames = xcalloc(dirNamesCount + fc, sizeof(char *));
00391     for (i = 0; i < dirNamesCount; i++)
00392         dirNames[i] = ((char **) data)[i];
00393     dirCount = dirNamesCount;
00394     newdata = xmalloc(fc * sizeof(int_32));
00395     for (i = 0, k = 0; i < count; i++) {
00396         if (actions[i] == FA_SKIPMULTILIB)
00397             continue;
00398         for (j = 0; j < dirCount; j++)
00399             if (!strcmp(dirNames[j], newDirNames[newDirIndexes[i]]))
00400                 break;
00401         if (j == dirCount)
00402             dirNames[dirCount++] = newDirNames[newDirIndexes[i]];
00403         ((int_32 *) newdata)[k++] = j;
00404     }
00405     headerAddOrAppendEntry(h, RPMTAG_DIRINDEXES, RPM_INT32_TYPE, newdata, fc);
00406     if (dirCount > dirNamesCount)
00407         headerAddOrAppendEntry(h, RPMTAG_DIRNAMES, RPM_STRING_ARRAY_TYPE,
00408                                dirNames + dirNamesCount,
00409                                dirCount - dirNamesCount);
00410     data = hfd(data, -1);
00411     newDirNames = hfd(newDirNames, -1);
00412     free (newdata);
00413     free (dirNames);
00414 
00415     for (i = 0; i < 9; i += 3) {
00416         const char **Names, **EVR, **newNames, **newEVR;
00417         int nnt, nvt, rnt;
00418         uint_32 *Flags, *newFlags;
00419         int Count = 0, newCount = 0;
00420 
00421         if (!hge(newH, requireTags[i], &nnt, (void **) &newNames, &newCount))
00422             continue;
00423 
00424         hge(newH, requireTags[i+1], &nvt, (void **) &newEVR, NULL);
00425         hge(newH, requireTags[i+2], NULL, (void **) &newFlags, NULL);
00426         if (hge(h, requireTags[i], &rnt, (void **) &Names, &Count))
00427         {
00428             hge(h, requireTags[i+1], NULL, (void **) &EVR, NULL);
00429             hge(h, requireTags[i+2], NULL, (void **) &Flags, NULL);
00430             for (j = 0; j < newCount; j++)
00431                 for (k = 0; k < Count; k++)
00432                     if (!strcmp (newNames[j], Names[k])
00433                         && !strcmp (newEVR[j], EVR[k])
00434                         && (newFlags[j] & RPMSENSE_SENSEMASK) ==
00435                            (Flags[k] & RPMSENSE_SENSEMASK))
00436                     {
00437                         newNames[j] = NULL;
00438                         break;
00439                     }
00440         }
00441         for (j = 0, k = 0; j < newCount; j++) {
00442             if (!newNames[j] || !isDependsMULTILIB(newFlags[j]))
00443                 continue;
00444             if (j != k) {
00445                 newNames[k] = newNames[j];
00446                 newEVR[k] = newEVR[j];
00447                 newFlags[k] = newFlags[j];
00448             }
00449             k++;
00450         }
00451         if (k) {
00452             headerAddOrAppendEntry(h, requireTags[i],
00453                                        RPM_STRING_ARRAY_TYPE, newNames, k);
00454             headerAddOrAppendEntry(h, requireTags[i+1],
00455                                        RPM_STRING_ARRAY_TYPE, newEVR, k);
00456             headerAddOrAppendEntry(h, requireTags[i+2], RPM_INT32_TYPE,
00457                                        newFlags, k);
00458         }
00459         newNames = hfd(newNames, nnt);
00460         newEVR = hfd(newEVR, nvt);
00461         Names = hfd(Names, rnt);
00462     }
00463     return 0;
00464 }
00465 
00471 static int markReplacedFiles(PSM_t psm)
00472 {
00473     const rpmTransactionSet ts = psm->ts;
00474     TFI_t fi = psm->fi;
00475     HGE_t hge = (HGE_t)fi->hge;
00476     const struct sharedFileInfo * replaced = fi->replaced;
00477     const struct sharedFileInfo * sfi;
00478     rpmdbMatchIterator mi;
00479     Header h;
00480     unsigned int * offsets;
00481     unsigned int prev;
00482     int num;
00483 
00484     if (!(fi->fc > 0 && fi->replaced))
00485         return 0;
00486 
00487     num = prev = 0;
00488     for (sfi = replaced; sfi->otherPkg; sfi++) {
00489         if (prev && prev == sfi->otherPkg)
00490             continue;
00491         prev = sfi->otherPkg;
00492         num++;
00493     }
00494     if (num == 0)
00495         return 0;
00496 
00497     offsets = alloca(num * sizeof(*offsets));
00498     num = prev = 0;
00499     for (sfi = replaced; sfi->otherPkg; sfi++) {
00500         if (prev && prev == sfi->otherPkg)
00501             continue;
00502         prev = sfi->otherPkg;
00503         offsets[num++] = sfi->otherPkg;
00504     }
00505 
00506     mi = rpmdbInitIterator(ts->rpmdb, RPMDBI_PACKAGES, NULL, 0);
00507     rpmdbAppendIterator(mi, offsets, num);
00508 
00509     sfi = replaced;
00510     while ((h = rpmdbNextIterator(mi)) != NULL) {
00511         char * secStates;
00512         int modified;
00513         int count;
00514 
00515         modified = 0;
00516 
00517         if (!hge(h, RPMTAG_FILESTATES, NULL, (void **)&secStates, &count))
00518             continue;
00519         
00520         prev = rpmdbGetIteratorOffset(mi);
00521         num = 0;
00522         while (sfi->otherPkg && sfi->otherPkg == prev) {
00523             assert(sfi->otherFileNum < count);
00524             if (secStates[sfi->otherFileNum] != RPMFILE_STATE_REPLACED) {
00525                 secStates[sfi->otherFileNum] = RPMFILE_STATE_REPLACED;
00526                 if (modified == 0) {
00527                     /* Modified header will be rewritten. */
00528                     modified = 1;
00529                     rpmdbSetIteratorModified(mi, modified);
00530                 }
00531                 num++;
00532             }
00533             sfi++;
00534         }
00535     }
00536     rpmdbFreeIterator(mi);
00537 
00538     return 0;
00539 }
00540 
00543 static rpmRC chkdir (const char * dpath, const char * dname)
00544 {
00545     struct stat st;
00546     int rc;
00547 
00548     if ((rc = Stat(dpath, &st)) < 0) {
00549         int ut = urlPath(dpath, NULL);
00550         switch (ut) {
00551         case URL_IS_PATH:
00552         case URL_IS_UNKNOWN:
00553             if (errno != ENOENT)
00554                 break;
00555             /*@fallthrough@*/
00556         case URL_IS_FTP:
00557         case URL_IS_HTTP:
00558             /* XXX this will only create last component of directory path */
00559             rc = Mkdir(dpath, 0755);
00560             break;
00561         case URL_IS_DASH:
00562             break;
00563         }
00564         if (rc < 0) {
00565             rpmError(RPMERR_CREATE, _("cannot create %s %s\n"),
00566                         dname, dpath);
00567             return RPMRC_FAIL;
00568         }
00569     }
00570     if ((rc = Access(dpath, W_OK))) {
00571         rpmError(RPMERR_CREATE, _("cannot write to %s\n"), dpath);
00572         return RPMRC_FAIL;
00573     }
00574     return RPMRC_OK;
00575 }
00576 
00577 rpmRC rpmInstallSourcePackage(const char * rootDir, FD_t fd,
00578                         const char ** specFilePtr,
00579                         rpmCallbackFunction notify, rpmCallbackData notifyData,
00580                         char ** cookie)
00581 {
00582     rpmdb rpmdb = NULL;
00583     rpmTransactionSet ts = rpmtransCreateSet(rpmdb, rootDir);
00584     TFI_t fi = xcalloc(sizeof(*fi), 1);
00585     const char * _sourcedir = NULL;
00586     const char * _specdir = NULL;
00587     const char * specFile = NULL;
00588     HGE_t hge;
00589     HFD_t hfd;
00590     Header h;
00591     struct psm_s psmbuf;
00592     PSM_t psm = &psmbuf;
00593     int isSource;
00594     rpmRC rc;
00595     int i;
00596 
00597     ts->notify = notify;
00598     ts->notifyData = notifyData;
00599 
00600     rc = rpmReadPackageHeader(fd, &h, &isSource, NULL, NULL);
00601     if (rc)
00602         goto exit;
00603 
00604     if (!isSource) {
00605         rpmError(RPMERR_NOTSRPM, _("source package expected, binary found\n"));
00606         rc = RPMRC_FAIL;
00607         goto exit;
00608     }
00609 
00610     (void) rpmtransAddPackage(ts, h, fd, NULL, 0, NULL);
00611 
00612     fi->type = TR_ADDED;
00613     fi->ap = ts->addedPackages.list;
00614     loadFi(h, fi);
00615     hge = fi->hge;
00616     hfd = fi->hfd;
00617     headerFree(h);      /* XXX reference held by transaction set */
00618     h = NULL;
00619 
00620     rpmInstallLoadMacros(fi, fi->h);
00621 
00622     memset(psm, 0, sizeof(*psm));
00623     psm->ts = ts;
00624     psm->fi = fi;
00625 
00626     if (cookie) {
00627         *cookie = NULL;
00628         if (hge(h, RPMTAG_COOKIE, NULL, (void **) cookie, NULL))
00629             *cookie = xstrdup(*cookie);
00630     }
00631 
00632     /* XXX FIXME: can't do endian neutral MD5 verification yet. */
00633     fi->fmd5s = hfd(fi->fmd5s, -1);
00634 
00635     /* XXX FIXME: don't do per-file mapping, force global flags. */
00636     fi->fmapflags = hfd(fi->fmapflags, -1);
00637     fi->mapflags = CPIO_MAP_PATH | CPIO_MAP_MODE | CPIO_MAP_UID | CPIO_MAP_GID;
00638 
00639     fi->uid = getuid();
00640     fi->gid = getgid();
00641     fi->astriplen = 0;
00642     fi->striplen = 0;
00643 
00644     fi->fuids = xcalloc(sizeof(*fi->fuids), fi->fc);
00645     fi->fgids = xcalloc(sizeof(*fi->fgids), fi->fc);
00646     for (i = 0; i < fi->fc; i++) {
00647         fi->fuids[i] = fi->uid;
00648         fi->fgids[i] = fi->gid;
00649     }
00650 
00651     for (i = 0; i < fi->fc; i++) {
00652         fi->actions[i] = FA_CREATE;
00653     }
00654 
00655     rpmBuildFileList(fi->h, &fi->apath, NULL);
00656 
00657     i = fi->fc;
00658     if (headerIsEntry(fi->h, RPMTAG_COOKIE))
00659         for (i = 0; i < fi->fc; i++)
00660                 if (fi->fflags[i] & RPMFILE_SPECFILE) break;
00661 
00662     if (i == fi->fc) {
00663         /* Find the spec file by name. */
00664         for (i = 0; i < fi->fc; i++) {
00665             const char * t = fi->apath[i];
00666             t += strlen(fi->apath[i]) - 5;
00667             if (!strcmp(t, ".spec")) break;
00668         }
00669     }
00670 
00671     _sourcedir = rpmGenPath(ts->rootDir, "%{_sourcedir}", "");
00672     rc = chkdir(_sourcedir, "sourcedir");
00673     if (rc) {
00674         rc = RPMRC_FAIL;
00675         goto exit;
00676     }
00677 
00678     _specdir = rpmGenPath(ts->rootDir, "%{_specdir}", "");
00679     rc = chkdir(_specdir, "specdir");
00680     if (rc) {
00681         rc = RPMRC_FAIL;
00682         goto exit;
00683     }
00684 
00685     /* Build dnl/dil with {_sourcedir, _specdir} as values. */
00686     if (i < fi->fc) {
00687         int speclen = strlen(_specdir) + 2;
00688         int sourcelen = strlen(_sourcedir) + 2;
00689         char * t;
00690 
00691         fi->dnl = hfd(fi->dnl, -1);
00692 
00693         fi->dc = 2;
00694         fi->dnl = xmalloc(fi->dc * sizeof(*fi->dnl) + fi->fc * sizeof(*fi->dil) +
00695                         speclen + sourcelen);
00696         fi->dil = (int *)(fi->dnl + fi->dc);
00697         memset(fi->dil, 0, fi->fc * sizeof(*fi->dil));
00698         fi->dil[i] = 1;
00699         fi->dnl[0] = t = (char *)(fi->dil + fi->fc);
00700         fi->dnl[1] = t = stpcpy( stpcpy(t, _sourcedir), "/") + 1;
00701         (void) stpcpy( stpcpy(t, _specdir), "/");
00702 
00703         t = xmalloc(speclen + strlen(fi->bnl[i]) + 1);
00704         (void) stpcpy( stpcpy( stpcpy(t, _specdir), "/"), fi->bnl[i]);
00705         specFile = t;
00706     } else {
00707         rpmError(RPMERR_NOSPEC, _("source package contains no .spec file\n"));
00708         rc = RPMRC_FAIL;
00709         goto exit;
00710     }
00711 
00712     psm->goal = PSM_PKGINSTALL;
00713 
00714     rc = psmStage(psm, PSM_PROCESS);
00715 
00716     (void) psmStage(psm, PSM_FINI);
00717 
00718     if (rc) rc = RPMRC_FAIL;
00719 
00720 exit:
00721     if (rc == RPMRC_OK && specFile && specFilePtr)
00722         *specFilePtr = specFile;
00723     else
00724         specFile = _free(specFile);
00725 
00726     _specdir = _free(_specdir);
00727     _sourcedir = _free(_sourcedir);
00728 
00729     if (h)
00730         headerFree(h);
00731 
00732     if (fi) {
00733         freeFi(fi);
00734         free(fi);
00735     }
00736     if (ts)
00737         rpmtransFree(ts);
00738 
00739     return rc;
00740 }
00741 
00742 static char * SCRIPT_PATH = "PATH=/sbin:/bin:/usr/sbin:/usr/bin:/usr/X11R6/bin";
00743 
00749 static /*@observer@*/ const char * const tag2sln(int tag)
00750 {
00751     switch (tag) {
00752     case RPMTAG_PREIN:          return "%pre";
00753     case RPMTAG_POSTIN:         return "%post";
00754     case RPMTAG_PREUN:          return "%preun";
00755     case RPMTAG_POSTUN:         return "%postun";
00756     case RPMTAG_VERIFYSCRIPT:   return "%verify";
00757     }
00758     return "%unknownscript";
00759 }
00760 
00779 static int runScript(PSM_t psm, Header h,
00780                 const char * sln,
00781                 int progArgc, const char ** progArgv, 
00782                 const char * script, int arg1, int arg2)
00783 {
00784     const rpmTransactionSet ts = psm->ts;
00785     TFI_t fi = psm->fi;
00786     HGE_t hge = fi->hge;
00787     HFD_t hfd = fi->hfd;
00788     const char ** argv = NULL;
00789     int argc = 0;
00790     const char ** prefixes = NULL;
00791     int numPrefixes;
00792     int_32 ipt;
00793     const char * oldPrefix;
00794     int maxPrefixLength;
00795     int len;
00796     char * prefixBuf = NULL;
00797     pid_t child;
00798     int status = 0;
00799     const char * fn = NULL;
00800     int i;
00801     int freePrefixes = 0;
00802     FD_t out;
00803     rpmRC rc = RPMRC_OK;
00804     const char *n, *v, *r;
00805 
00806     if (!progArgv && !script)
00807         return 0;
00808 
00809     if (!progArgv) {
00810         argv = alloca(5 * sizeof(char *));
00811         argv[0] = "/bin/sh";
00812         argc = 1;
00813     } else {
00814         argv = alloca((progArgc + 4) * sizeof(char *));
00815         memcpy(argv, progArgv, progArgc * sizeof(char *));
00816         argc = progArgc;
00817     }
00818 
00819     headerNVR(h, &n, &v, &r);
00820     if (hge(h, RPMTAG_INSTPREFIXES, &ipt, (void **) &prefixes, &numPrefixes)) {
00821         freePrefixes = 1;
00822     } else if (hge(h, RPMTAG_INSTALLPREFIX, NULL, (void **) &oldPrefix, NULL)) {
00823         prefixes = &oldPrefix;
00824         numPrefixes = 1;
00825     } else {
00826         numPrefixes = 0;
00827     }
00828 
00829     maxPrefixLength = 0;
00830     for (i = 0; i < numPrefixes; i++) {
00831         len = strlen(prefixes[i]);
00832         if (len > maxPrefixLength) maxPrefixLength = len;
00833     }
00834     prefixBuf = alloca(maxPrefixLength + 50);
00835 
00836     if (script) {
00837         FD_t fd;
00838         if (makeTempFile((!ts->chrootDone ? ts->rootDir : "/"), &fn, &fd)) {
00839             if (freePrefixes) free(prefixes);
00840             return 1;
00841         }
00842 
00843         if (rpmIsDebug() &&
00844             (!strcmp(argv[0], "/bin/sh") || !strcmp(argv[0], "/bin/bash")))
00845             (void)Fwrite("set -x\n", sizeof(char), 7, fd);
00846 
00847         (void)Fwrite(script, sizeof(script[0]), strlen(script), fd);
00848         Fclose(fd);
00849 
00850         {   const char * sn = fn;
00851             if (!ts->chrootDone &&
00852                 !(ts->rootDir[0] == '/' && ts->rootDir[1] == '\0'))
00853             {
00854                 sn += strlen(ts->rootDir)-1;
00855             }
00856             argv[argc++] = sn;
00857         }
00858 
00859         if (arg1 >= 0) {
00860             char *av = alloca(20);
00861             sprintf(av, "%d", arg1);
00862             argv[argc++] = av;
00863         }
00864         if (arg2 >= 0) {
00865             char *av = alloca(20);
00866             sprintf(av, "%d", arg2);
00867             argv[argc++] = av;
00868         }
00869     }
00870 
00871     argv[argc] = NULL;
00872 
00873     if (ts->scriptFd != NULL) {
00874         if (rpmIsVerbose()) {
00875             out = fdDup(Fileno(ts->scriptFd));
00876         } else {
00877             out = Fopen("/dev/null", "w.fdio");
00878             if (Ferror(out)) {
00879                 out = fdDup(Fileno(ts->scriptFd));
00880             }
00881         }
00882     } else {
00883         out = fdDup(STDOUT_FILENO);
00884         out = fdLink(out, "runScript persist");
00885     }
00886     
00887     if (!(child = fork())) {
00888         const char * rootDir;
00889         int pipes[2];
00890 
00891         pipes[0] = pipes[1] = 0;
00892         /* make stdin inaccessible */
00893         pipe(pipes);
00894         close(pipes[1]);
00895         dup2(pipes[0], STDIN_FILENO);
00896         close(pipes[0]);
00897 
00898         if (ts->scriptFd != NULL) {
00899             if (Fileno(ts->scriptFd) != STDERR_FILENO)
00900                 dup2(Fileno(ts->scriptFd), STDERR_FILENO);
00901             if (Fileno(out) != STDOUT_FILENO)
00902                 dup2(Fileno(out), STDOUT_FILENO);
00903             /* make sure we don't close stdin/stderr/stdout by mistake! */
00904             if (Fileno(out) > STDERR_FILENO && Fileno(out) != Fileno(ts->scriptFd)) {
00905                 Fclose (out);
00906             }
00907             if (Fileno(ts->scriptFd) > STDERR_FILENO) {
00908                 Fclose (ts->scriptFd);
00909             }
00910         }
00911 
00912         {   const char *ipath = rpmExpand("PATH=%{_install_script_path}", NULL);
00913             const char *path = SCRIPT_PATH;
00914 
00915             if (ipath && ipath[5] != '%')
00916                 path = ipath;
00917             doputenv(path);
00918             if (ipath)  free((void *)ipath);
00919         }
00920 
00921         for (i = 0; i < numPrefixes; i++) {
00922             sprintf(prefixBuf, "RPM_INSTALL_PREFIX%d=%s", i, prefixes[i]);
00923             doputenv(prefixBuf);
00924 
00925             /* backwards compatibility */
00926             if (i == 0) {
00927                 sprintf(prefixBuf, "RPM_INSTALL_PREFIX=%s", prefixes[i]);
00928                 doputenv(prefixBuf);
00929             }
00930         }
00931 
00932         rootDir = ts->rootDir;
00933         switch(urlIsURL(rootDir)) {
00934         case URL_IS_PATH:
00935             rootDir += sizeof("file://") - 1;
00936             rootDir = strchr(rootDir, '/');
00937             /*@fallthrough@*/
00938         case URL_IS_UNKNOWN:
00939             if (!ts->chrootDone && !(rootDir[0] == '/' && rootDir[1] == '\0')) {
00940                 /*@-unrecog@*/ chroot(rootDir); /*@=unrecog@*/
00941             }
00942             chdir("/");
00943             execv(argv[0], (char *const *)argv);
00944             break;
00945         default:
00946             break;
00947         }
00948 
00949         _exit(-1);
00950         /*@notreached@*/
00951     }
00952 
00953     if (waitpid(child, &status, 0) < 0) {
00954         rpmError(RPMERR_SCRIPT,
00955      _("execution of %s scriptlet from %s-%s-%s failed, waitpid returned %s\n"),
00956                  sln, n, v, r, strerror (errno));
00957         /* XXX what to do here? */
00958         rc = RPMRC_OK;
00959     } else {
00960         if (!WIFEXITED(status) || WEXITSTATUS(status)) {
00961             rpmError(RPMERR_SCRIPT,
00962      _("execution of %s scriptlet from %s-%s-%s failed, exit status %d\n"),
00963                      sln, n, v, r, WEXITSTATUS(status));
00964             rc = RPMRC_FAIL;
00965         }
00966     }
00967 
00968     if (freePrefixes) prefixes = hfd(prefixes, ipt);
00969 
00970     Fclose(out);        /* XXX dup'd STDOUT_FILENO */
00971     
00972     if (script) {
00973         if (!rpmIsDebug()) unlink(fn);
00974         free((void *)fn);
00975     }
00976 
00977     return rc;
00978 }
00979 
00985 static rpmRC runInstScript(PSM_t psm)
00986 {
00987     TFI_t fi = psm->fi;
00988     HGE_t hge = fi->hge;
00989     HFD_t hfd = fi->hfd;
00990     void ** programArgv;
00991     int programArgc;
00992     const char ** argv;
00993     int_32 ptt, stt;
00994     const char * script;
00995     rpmRC rc = RPMRC_OK;
00996 
00997     /*
00998      * headerGetEntry() sets the data pointer to NULL if the entry does
00999      * not exist.
01000      */
01001     hge(fi->h, psm->progTag, &ptt, (void **) &programArgv, &programArgc);
01002     hge(fi->h, psm->scriptTag, &stt, (void **) &script, NULL);
01003 
01004     if (programArgv && ptt == RPM_STRING_TYPE) {
01005         argv = alloca(sizeof(char *));
01006         *argv = (const char *) programArgv;
01007     } else {
01008         argv = (const char **) programArgv;
01009     }
01010 
01011     rc = runScript(psm, fi->h, tag2sln(psm->scriptTag), programArgc, argv,
01012                 script, psm->scriptArg, -1);
01013 
01014     programArgv = hfd(programArgv, ptt);
01015     script = hfd(script, stt);
01016     return rc;
01017 }
01018 
01027 static int handleOneTrigger(PSM_t psm, Header sourceH, Header triggeredH,
01028                         int arg2, char * triggersAlreadyRun)
01029 {
01030     const rpmTransactionSet ts = psm->ts;
01031     TFI_t fi = psm->fi;
01032     HGE_t hge = fi->hge;
01033     HFD_t hfd = fi->hfd;
01034     const char ** triggerNames;
01035     const char ** triggerEVR;
01036     const char ** triggerScripts;
01037     const char ** triggerProgs;
01038     int_32 * triggerFlags;
01039     int_32 * triggerIndices;
01040     int_32 tnt, tvt, tft;
01041     const char * triggerPackageName;
01042     const char * sourceName;
01043     int numTriggers;
01044     rpmRC rc = RPMRC_OK;
01045     int i;
01046     int skip;
01047 
01048     if (!hge(triggeredH, RPMTAG_TRIGGERNAME, &tnt, 
01049                         (void **) &triggerNames, &numTriggers))
01050         return 0;
01051 
01052     headerNVR(sourceH, &sourceName, NULL, NULL);
01053 
01054     hge(triggeredH, RPMTAG_TRIGGERFLAGS, &tft, (void **) &triggerFlags, NULL);
01055     hge(triggeredH, RPMTAG_TRIGGERVERSION, &tvt, (void **) &triggerEVR, NULL);
01056 
01057     for (i = 0; i < numTriggers; i++) {
01058         int_32 tit, tst, tpt;
01059 
01060         if (!(triggerFlags[i] & psm->sense)) continue;
01061         if (strcmp(triggerNames[i], sourceName)) continue;
01062 
01063         /*
01064          * For some reason, the TRIGGERVERSION stuff includes the name of
01065          * the package which the trigger is based on. We need to skip
01066          * over that here. I suspect that we'll change our minds on this
01067          * and remove that, so I'm going to just 'do the right thing'.
01068          */
01069         skip = strlen(triggerNames[i]);
01070         if (!strncmp(triggerEVR[i], triggerNames[i], skip) &&
01071             (triggerEVR[i][skip] == '-'))
01072             skip++;
01073         else
01074             skip = 0;
01075 
01076         if (!headerMatchesDepFlags(sourceH, triggerNames[i],
01077                 triggerEVR[i] + skip, triggerFlags[i]))
01078             continue;
01079 
01080         hge(triggeredH, RPMTAG_TRIGGERINDEX, &tit,
01081                        (void **) &triggerIndices, NULL);
01082         hge(triggeredH, RPMTAG_TRIGGERSCRIPTS, &tst,
01083                        (void **) &triggerScripts, NULL);
01084         hge(triggeredH, RPMTAG_TRIGGERSCRIPTPROG, &tpt,
01085                        (void **) &triggerProgs, NULL);
01086 
01087         headerNVR(triggeredH, &triggerPackageName, NULL, NULL);
01088 
01089         {   int arg1;
01090             int index;
01091 
01092             arg1 = rpmdbCountPackages(ts->rpmdb, triggerPackageName);
01093             if (arg1 < 0) {
01094                 /* XXX W2DO? same as "execution of script failed" */
01095                 rc = RPMRC_FAIL;
01096             } else {
01097                 arg1 += psm->countCorrection;
01098                 index = triggerIndices[i];
01099                 if (!triggersAlreadyRun || !triggersAlreadyRun[index]) {
01100                     rc = runScript(psm, triggeredH, "%trigger", 1,
01101                             triggerProgs + index, triggerScripts[index], 
01102                             arg1, arg2);
01103                     if (triggersAlreadyRun) triggersAlreadyRun[index] = 1;
01104                 }
01105             }
01106         }
01107 
01108         triggerIndices = hfd(triggerIndices, tit);
01109         triggerScripts = hfd(triggerScripts, tst);
01110         triggerProgs = hfd(triggerProgs, tpt);
01111 
01112         /*
01113          * Each target/source header pair can only result in a single
01114          * script being run.
01115          */
01116         break;
01117     }
01118 
01119     triggerNames = hfd(triggerNames, tnt);
01120     triggerFlags = hfd(triggerFlags, tft);
01121     triggerEVR = hfd(triggerEVR, tvt);
01122 
01123     return rc;
01124 }
01125 
01131 static int runTriggers(PSM_t psm)
01132 {
01133     const rpmTransactionSet ts = psm->ts;
01134     TFI_t fi = psm->fi;
01135     int numPackage;
01136     rpmRC rc = RPMRC_OK;
01137 
01138     numPackage = rpmdbCountPackages(ts->rpmdb, fi->name) + psm->countCorrection;
01139     if (numPackage < 0)
01140         return 1;
01141 
01142     {   Header triggeredH;
01143         rpmdbMatchIterator mi;
01144         int countCorrection = psm->countCorrection;
01145 
01146         psm->countCorrection = 0;
01147         mi = rpmdbInitIterator(ts->rpmdb, RPMTAG_TRIGGERNAME, fi->name, 0);
01148         while((triggeredH = rpmdbNextIterator(mi)) != NULL) {
01149             rc |= handleOneTrigger(psm, fi->h, triggeredH, numPackage, NULL);
01150         }
01151 
01152         rpmdbFreeIterator(mi);
01153         psm->countCorrection = countCorrection;
01154     }
01155 
01156     return rc;
01157 }
01158 
01164 static int runImmedTriggers(PSM_t psm)
01165 {
01166     const rpmTransactionSet ts = psm->ts;
01167     TFI_t fi = psm->fi;
01168     HGE_t hge = fi->hge;
01169     HFD_t hfd = fi->hfd;
01170     const char ** triggerNames;
01171     int numTriggers;
01172     int_32 * triggerIndices;
01173     int_32 tnt, tit;
01174     int numTriggerIndices;
01175     char * triggersRun;
01176     rpmRC rc = RPMRC_OK;
01177 
01178     if (!hge(fi->h, RPMTAG_TRIGGERNAME, &tnt,
01179                         (void **) &triggerNames, &numTriggers))
01180         return 0;
01181 
01182     hge(fi->h, RPMTAG_TRIGGERINDEX, &tit, (void **) &triggerIndices, 
01183                    &numTriggerIndices);
01184     triggersRun = alloca(sizeof(*triggersRun) * numTriggerIndices);
01185     memset(triggersRun, 0, sizeof(*triggersRun) * numTriggerIndices);
01186 
01187     {   Header sourceH = NULL;
01188         int i;
01189 
01190         for (i = 0; i < numTriggers; i++) {
01191             rpmdbMatchIterator mi;
01192 
01193             if (triggersRun[triggerIndices[i]]) continue;
01194         
01195             mi = rpmdbInitIterator(ts->rpmdb, RPMTAG_NAME, triggerNames[i], 0);
01196 
01197             while((sourceH = rpmdbNextIterator(mi)) != NULL) {
01198                 rc |= handleOneTrigger(psm, sourceH, fi->h, 
01199                                 rpmdbGetIteratorCount(mi),
01200                                 triggersRun);
01201             }
01202 
01203             rpmdbFreeIterator(mi);
01204         }
01205     }
01206     triggerIndices = hfd(triggerIndices, tit);
01207     triggerNames = hfd(triggerNames, tnt);
01208     return rc;
01209 }
01210 
01211 /*@observer@*/ static const char *const pkgStageString(pkgStage a) {
01212     switch(a) {
01213     case PSM_UNKNOWN:           return "unknown";
01214 
01215     case PSM_PKGINSTALL:        return "  install";
01216     case PSM_PKGERASE:          return "    erase";
01217     case PSM_PKGCOMMIT:         return "   commit";
01218     case PSM_PKGSAVE:           return "repackage";
01219 
01220     case PSM_INIT:              return "init";
01221     case PSM_PRE:               return "pre";
01222     case PSM_PROCESS:           return "process";
01223     case PSM_POST:              return "post";
01224     case PSM_UNDO:              return "undo";
01225     case PSM_FINI:              return "fini";
01226 
01227     case PSM_CREATE:            return "create";
01228     case PSM_NOTIFY:            return "notify";
01229     case PSM_DESTROY:           return "destroy";
01230     case PSM_COMMIT:            return "commit";
01231 
01232     case PSM_CHROOT_IN:         return "chrootin";
01233     case PSM_CHROOT_OUT:        return "chrootout";
01234     case PSM_SCRIPT:            return "script";
01235     case PSM_TRIGGERS:          return "triggers";
01236     case PSM_IMMED_TRIGGERS:    return "immedtriggers";
01237 
01238     case PSM_RPMIO_FLAGS:       return "rpmioflags";
01239 
01240     case PSM_RPMDB_LOAD:        return "rpmdbload";
01241     case PSM_RPMDB_ADD:         return "rpmdbadd";
01242     case PSM_RPMDB_REMOVE:      return "rpmdbremove";
01243 
01244     default:                    return "???";
01245     }
01246     /*@noteached@*/
01247 }
01248 
01253 int psmStage(PSM_t psm, pkgStage stage)
01254 {
01255     const rpmTransactionSet ts = psm->ts;
01256     TFI_t fi = psm->fi;
01257     HGE_t hge = fi->hge;
01258     HFD_t hfd = fi->hfd;
01259     rpmRC rc = psm->rc;
01260     int saveerrno;
01261 
01262     switch (stage) {
01263     case PSM_UNKNOWN:
01264         break;
01265     case PSM_INIT:
01266         rpmMessage(RPMMESS_DEBUG, _("%s: %s-%s-%s has %d files, test = %d\n"),
01267                 psm->stepName, fi->name, fi->version, fi->release,
01268                 fi->fc, (ts->transFlags & RPMTRANS_FLAG_TEST));
01269 
01270         /*
01271          * When we run scripts, we pass an argument which is the number of 
01272          * versions of this package that will be installed when we are
01273          * finished.
01274          */
01275         psm->npkgs_installed = rpmdbCountPackages(ts->rpmdb, fi->name);
01276         if (psm->npkgs_installed < 0) {
01277             rc = RPMRC_FAIL;
01278             break;
01279         }
01280 
01281         if (psm->goal == PSM_PKGINSTALL) {
01282             psm->scriptArg = psm->npkgs_installed + 1;
01283 
01284 assert(psm->mi == NULL);
01285             psm->mi = rpmdbInitIterator(ts->rpmdb, RPMTAG_NAME, fi->name, 0);
01286             rpmdbSetIteratorVersion(psm->mi, fi->version);
01287             rpmdbSetIteratorRelease(psm->mi, fi->release);
01288             while ((psm->oh = rpmdbNextIterator(psm->mi))) {
01289                 fi->record = rpmdbGetIteratorOffset(psm->mi);
01290                 psm->oh = (ts->transFlags & RPMTRANS_FLAG_MULTILIB)
01291                         ? headerCopy(psm->oh) : NULL;
01292                 break;
01293             }
01294             rpmdbFreeIterator(psm->mi);
01295             psm->mi = NULL;
01296             rc = RPMRC_OK;
01297 
01298             if (fi->fc > 0 && fi->fstates == NULL) {
01299                 fi->fstates = xmalloc(sizeof(*fi->fstates) * fi->fc);
01300                 memset(fi->fstates, RPMFILE_STATE_NORMAL, fi->fc);
01301             }
01302 
01303             if (fi->fc <= 0)                            break;
01304             if (ts->transFlags & RPMTRANS_FLAG_JUSTDB)  break;
01305         
01306             /*
01307              * Old format relocateable packages need the entire default
01308              * prefix stripped to form the cpio list, while all other packages
01309              * need the leading / stripped.
01310              */
01311             {   const char * p;
01312                 rc = hge(fi->h, RPMTAG_DEFAULTPREFIX, NULL, (void **) &p, NULL);
01313                 fi->striplen = (rc ? strlen(p) + 1 : 1); 
01314             }
01315             fi->mapflags =
01316                 CPIO_MAP_PATH | CPIO_MAP_MODE | CPIO_MAP_UID | CPIO_MAP_GID;
01317         
01318             if (headerIsEntry(fi->h, RPMTAG_ORIGBASENAMES))
01319                 buildOrigFileList(fi->h, &fi->apath, NULL);
01320             else
01321                 rpmBuildFileList(fi->h, &fi->apath, NULL);
01322         
01323             if (fi->fuser == NULL)
01324                 hge(fi->h, RPMTAG_FILEUSERNAME, NULL,
01325                                 (void **) &fi->fuser, NULL);
01326             if (fi->fgroup == NULL)
01327                 hge(fi->h, RPMTAG_FILEGROUPNAME, NULL,
01328                                 (void **) &fi->fgroup, NULL);
01329             if (fi->fuids == NULL)
01330                 fi->fuids = xcalloc(sizeof(*fi->fuids), fi->fc);
01331             if (fi->fgids == NULL)
01332                 fi->fgids = xcalloc(sizeof(*fi->fgids), fi->fc);
01333             rc = RPMRC_OK;
01334         }
01335         if (psm->goal == PSM_PKGERASE || psm->goal == PSM_PKGSAVE) {
01336             psm->scriptArg = psm->npkgs_installed - 1;
01337         
01338             /* Retrieve installed header. */
01339             rc = psmStage(psm, PSM_RPMDB_LOAD);
01340         }
01341         if (psm->goal == PSM_PKGSAVE) {
01342             /* Open output package for writing. */
01343             {   const char * bfmt = rpmGetPath("%{_repackage_name_fmt}", NULL);
01344                 const char * pkgbn =
01345                         headerSprintf(fi->h, bfmt, rpmTagTable, rpmHeaderFormats, NULL);
01346 
01347                 bfmt = _free(bfmt);
01348                 psm->pkgURL = rpmGenPath("%{?_repackage_root:%{_repackage_root}}",
01349                                          "%{?_repackage_dir:%{_repackage_dir}}",
01350                                         pkgbn);
01351                 pkgbn = _free(pkgbn);
01352                 (void) urlPath(psm->pkgURL, &psm->pkgfn);
01353                 psm->fd = Fopen(psm->pkgfn, "w.ufdio");
01354                 if (psm->fd == NULL || Ferror(psm->fd)) {
01355                     rc = RPMRC_FAIL;
01356                     break;
01357                 }
01358             }
01359         }
01360         break;
01361     case PSM_PRE:
01362         if (ts->transFlags & RPMTRANS_FLAG_TEST)        break;
01363 
01364         /* Change root directory if requested and not already done. */
01365         rc = psmStage(psm, PSM_CHROOT_IN);
01366 
01367         if (psm->goal == PSM_PKGINSTALL) {
01368             psm->scriptTag = RPMTAG_PREIN;
01369             psm->progTag = RPMTAG_PREINPROG;
01370 
01371             if (!(ts->transFlags & RPMTRANS_FLAG_NOTRIGGERPREIN)) {
01372                 /* XXX FIXME: implement %triggerprein. */
01373             }
01374 
01375             if (!(ts->transFlags & RPMTRANS_FLAG_NOPRE)) {
01376                 rc = psmStage(psm, PSM_SCRIPT);
01377                 if (rc) {
01378                     rpmError(RPMERR_SCRIPT,
01379                         _("%s: %s scriptlet failed (%d), skipping %s-%s-%s\n"),
01380                         psm->stepName, tag2sln(psm->scriptTag), rc,
01381                         fi->name, fi->version, fi->release);
01382                     break;
01383                 }
01384             }
01385         }
01386 
01387         if (psm->goal == PSM_PKGERASE) {
01388             psm->scriptTag = RPMTAG_PREUN;
01389             psm->progTag = RPMTAG_PREUNPROG;
01390             psm->sense = RPMSENSE_TRIGGERUN;
01391             psm->countCorrection = -1;
01392 
01393             if (!(ts->transFlags & RPMTRANS_FLAG_NOTRIGGERUN)) {
01394                 /* Run triggers in other package(s) this package sets off. */
01395                 rc = psmStage(psm, PSM_TRIGGERS);
01396                 if (rc) break;
01397 
01398                 /* Run triggers in this package other package(s) set off. */
01399                 rc = psmStage(psm, PSM_IMMED_TRIGGERS);
01400                 if (rc) break;
01401             }
01402 
01403             if (!(ts->transFlags & RPMTRANS_FLAG_NOPREUN))
01404                 rc = psmStage(psm, PSM_SCRIPT);
01405         }
01406         if (psm->goal == PSM_PKGSAVE) {
01407             /* Regenerate original header. */
01408             {   void * uh = NULL;
01409                 int_32 uht, uhc;
01410 
01411                 if (headerGetEntry(fi->h, RPMTAG_HEADERIMMUTABLE, &uht, &uh, &uhc)) {
01412                     psm->oh = headerCopyLoad(uh);
01413                     uh = hfd(uh, uht);
01414                 } else {
01415                     psm->oh = headerLink(fi->h);
01416                 }
01417             }
01418 
01419             /* Retrieve type of payload compression. */
01420             rc = psmStage(psm, PSM_RPMIO_FLAGS);
01421 
01422             /* Write the lead section into the package. */
01423             {   int archnum = -1;
01424                 int osnum = -1;
01425                 struct rpmlead lead;
01426 
01427 #ifndef DYING
01428                 rpmGetArchInfo(NULL, &archnum);
01429                 rpmGetOsInfo(NULL, &osnum);
01430 #endif
01431 
01432                 memset(&lead, 0, sizeof(lead));
01433                 /* XXX Set package version conditioned on noDirTokens. */
01434                 lead.major = 4;
01435                 lead.minor = 0;
01436                 lead.type = RPMLEAD_BINARY;
01437                 lead.archnum = archnum;
01438                 lead.osnum = osnum;
01439                 lead.signature_type = RPMSIGTYPE_HEADERSIG;
01440 
01441                 {   char buf[256];
01442                     sprintf(buf, "%s-%s-%s", fi->name, fi->version, fi->release);
01443                     strncpy(lead.name, buf, sizeof(lead.name));
01444                 }
01445 
01446                 rc = writeLead(psm->fd, &lead);
01447                 if (rc) {
01448                     rpmError(RPMERR_NOSPACE, _("Unable to write package: %s\n"),
01449                          Fstrerror(psm->fd));
01450                     rc = RPMRC_FAIL;
01451                     break;
01452                 }
01453             }
01454 
01455             /* Write the signature section into the package. */
01456             {   Header sig = headerRegenSigHeader(fi->h);
01457                 rc = rpmWriteSignature(psm->fd, sig);
01458                 headerFree(sig);
01459                 if (rc) break;
01460             }
01461 
01462             /* Write the metadata section into the package. */
01463             rc = headerWrite(psm->fd, psm->oh, HEADER_MAGIC_YES);
01464             if (rc) break;
01465         }
01466         break;
01467     case PSM_PROCESS:
01468         if (ts->transFlags & RPMTRANS_FLAG_TEST)        break;
01469 
01470         if (psm->goal == PSM_PKGINSTALL) {
01471             struct availablePackage * alp = fi->ap;
01472             int i;
01473 
01474             if (fi->fc <= 0)                            break;
01475             if (ts->transFlags & RPMTRANS_FLAG_JUSTDB)  break;
01476 
01477             for (i = 0; i < fi->fc; i++) {
01478                 uid_t uid;
01479                 gid_t gid;
01480 
01481                 uid = fi->uid;
01482                 gid = fi->gid;
01483                 if (fi->fuser && unameToUid(fi->fuser[i], &uid)) {
01484                     rpmMessage(RPMMESS_WARNING,
01485                         _("user %s does not exist - using root\n"),
01486                         fi->fuser[i]);
01487                     uid = 0;
01488                     /* XXX this diddles header memory. */
01489                     fi->fmodes[i] &= ~S_ISUID;  /* turn off the suid bit */
01490                 }
01491 
01492                 if (fi->fgroup && gnameToGid(fi->fgroup[i], &gid)) {
01493                     rpmMessage(RPMMESS_WARNING,
01494                         _("group %s does not exist - using root\n"),
01495                         fi->fgroup[i]);
01496                     gid = 0;
01497                     /* XXX this diddles header memory. */
01498                     fi->fmodes[i] &= ~S_ISGID;  /* turn off the sgid bit */
01499                 }
01500                 if (fi->fuids) fi->fuids[i] = uid;
01501                 if (fi->fgids) fi->fgids[i] = gid;
01502             }
01503 
01504             /* Retrieve type of payload compression. */
01505             rc = psmStage(psm, PSM_RPMIO_FLAGS);
01506 
01507             psm->cfd = Fdopen(fdDup(Fileno(alp->fd)), psm->rpmio_flags);
01508 
01509             rc = fsmSetup(fi->fsm, FSM_PKGINSTALL, ts, fi,
01510                         psm->cfd, NULL, &psm->failedFile);
01511             (void) fsmTeardown(fi->fsm);
01512 
01513             saveerrno = errno; /* XXX FIXME: Fclose with libio destroys errno */
01514             Fclose(psm->cfd);
01515             psm->cfd = NULL;
01516             errno = saveerrno; /* XXX FIXME: Fclose with libio destroys errno */
01517 
01518             if (!rc)
01519                 rc = psmStage(psm, PSM_COMMIT);
01520 
01521             if (rc) {
01522                 rpmError(RPMERR_CPIO,
01523                         _("unpacking of archive failed%s%s: %s\n"),
01524                         (psm->failedFile != NULL ? _(" on file ") : ""),
01525                         (psm->failedFile != NULL ? psm->failedFile : ""),
01526                         cpioStrerror(rc));
01527                 rc = RPMRC_FAIL;
01528                 break;
01529             }
01530             psm->what = RPMCALLBACK_INST_PROGRESS;
01531             psm->amount = (fi->archiveSize ? fi->archiveSize : 100);
01532             psm->total = psm->amount;
01533             (void) psmStage(psm, PSM_NOTIFY);
01534         }
01535         if (psm->goal == PSM_PKGERASE) {
01536 
01537             if (fi->fc <= 0)                            break;
01538             if (ts->transFlags & RPMTRANS_FLAG_JUSTDB)  break;
01539             if (ts->transFlags & RPMTRANS_FLAG_APPLYONLY)       break;
01540 
01541             psm->what = RPMCALLBACK_UNINST_START;
01542             psm->amount = fi->fc;       /* XXX W2DO? looks wrong. */
01543             psm->total = fi->fc;
01544             (void) psmStage(psm, PSM_NOTIFY);
01545 
01546             rc = fsmSetup(fi->fsm, FSM_PKGERASE, ts, fi,
01547                         NULL, NULL, &psm->failedFile);
01548             (void) fsmTeardown(fi->fsm);
01549 
01550             psm->what = RPMCALLBACK_UNINST_STOP;
01551             psm->amount = 0;            /* XXX W2DO? looks wrong. */
01552             psm->total = fi->fc;
01553             (void) psmStage(psm, PSM_NOTIFY);
01554 
01555         }
01556         if (psm->goal == PSM_PKGSAVE) {
01557             fileAction * actions = fi->actions;
01558             fileAction action = fi->action;
01559 
01560             fi->action = FA_COPYOUT;
01561             fi->actions = NULL;
01562 
01563             Fflush(psm->fd);
01564             psm->cfd = Fdopen(fdDup(Fileno(psm->fd)), psm->rpmio_flags);
01565 
01566             /* XXX failedFile? */
01567             rc = fsmSetup(fi->fsm, FSM_PKGBUILD, ts, fi, psm->cfd, NULL, NULL);
01568             (void) fsmTeardown(fi->fsm);
01569 
01570             saveerrno = errno; /* XXX FIXME: Fclose with libio destroys errno */
01571             Fclose(psm->cfd);
01572             psm->cfd = NULL;
01573             errno = saveerrno;
01574 
01575             fi->action = action;
01576             fi->actions = actions;
01577         }
01578         break;
01579     case PSM_POST:
01580         if (ts->transFlags & RPMTRANS_FLAG_TEST)        break;
01581 
01582         if (psm->goal == PSM_PKGINSTALL) {
01583             int_32 installTime = time(NULL);
01584 
01585             if (fi->fc > 0 && fi->fstates)
01586                 headerAddEntry(fi->h, RPMTAG_FILESTATES, RPM_CHAR_TYPE,
01587                                 fi->fstates, fi->fc);
01588 
01589             headerAddEntry(fi->h, RPMTAG_INSTALLTIME, RPM_INT32_TYPE,
01590                                 &installTime, 1);
01591 
01592             if (ts->transFlags & RPMTRANS_FLAG_MULTILIB) {
01593                 uint_32 multiLib, * newMultiLib, * p;
01594 
01595                 if (hge(fi->h, RPMTAG_MULTILIBS, NULL, (void **) &newMultiLib, NULL) &&
01596                     hge(psm->oh, RPMTAG_MULTILIBS, NULL, (void **) &p, NULL)) {
01597                     multiLib = *p;
01598                     multiLib |= *newMultiLib;
01599                     headerModifyEntry(psm->oh, RPMTAG_MULTILIBS, RPM_INT32_TYPE,
01600                                       &multiLib, 1);
01601                 }
01602                 rc = mergeFiles(fi, psm->oh, fi->h);
01603                 if (rc) break;
01604             }
01605 
01606 
01607             /*
01608              * If this package has already been installed, remove it from
01609              * the database before adding the new one.
01610              */
01611             if (fi->record && !(ts->transFlags & RPMTRANS_FLAG_APPLYONLY)) {
01612                 rc = psmStage(psm, PSM_RPMDB_REMOVE);
01613                 if (rc) break;
01614             }
01615 
01616             rc = psmStage(psm, PSM_RPMDB_ADD);
01617             if (rc) break;
01618 
01619             psm->scriptTag = RPMTAG_POSTIN;
01620             psm->progTag = RPMTAG_POSTINPROG;
01621             psm->sense = RPMSENSE_TRIGGERIN;
01622             psm->countCorrection = 0;
01623 
01624             if (!(ts->transFlags & RPMTRANS_FLAG_NOPOST)) {
01625                 rc = psmStage(psm, PSM_SCRIPT);
01626                 if (rc) break;
01627             }
01628             if (!(ts->transFlags & RPMTRANS_FLAG_NOTRIGGERIN)) {
01629                 /* Run triggers in other package(s) this package sets off. */
01630                 rc = psmStage(psm, PSM_TRIGGERS);
01631                 if (rc) break;
01632 
01633                 /* Run triggers in this package other package(s) set off. */
01634                 rc = psmStage(psm, PSM_IMMED_TRIGGERS);
01635                 if (rc) break;
01636             }
01637 
01638             if (!(ts->transFlags & RPMTRANS_FLAG_APPLYONLY))
01639                 rc = markReplacedFiles(psm);
01640 
01641         }
01642         if (psm->goal == PSM_PKGERASE) {
01643 
01644             psm->scriptTag = RPMTAG_POSTUN;
01645             psm->progTag = RPMTAG_POSTUNPROG;
01646             psm->sense = RPMSENSE_TRIGGERPOSTUN;
01647             psm->countCorrection = -1;
01648 
01649             if (!(ts->transFlags & RPMTRANS_FLAG_NOPOSTUN)) {
01650                 rc = psmStage(psm, PSM_SCRIPT);
01651                 /* XXX WTFO? postun failures don't cause erasure failure. */
01652             }
01653 
01654             if (!(ts->transFlags & RPMTRANS_FLAG_NOTRIGGERPOSTUN)) {
01655                 /* Run triggers in other package(s) this package sets off. */
01656                 rc = psmStage(psm, PSM_TRIGGERS);
01657                 if (rc) break;
01658             }
01659 
01660             if (!(ts->transFlags & RPMTRANS_FLAG_APPLYONLY))
01661                 rc = psmStage(psm, PSM_RPMDB_REMOVE);
01662         }
01663         if (psm->goal == PSM_PKGSAVE) {
01664         }
01665 
01666         /* Restore root directory if changed. */
01667         (void) psmStage(psm, PSM_CHROOT_OUT);
01668         break;
01669     case PSM_UNDO:
01670         break;
01671     case PSM_FINI:
01672         /* Restore root directory if changed. */
01673         (void) psmStage(psm, PSM_CHROOT_OUT);
01674 
01675         if (psm->fd) {
01676             saveerrno = errno; /* XXX FIXME: Fclose with libio destroys errno */
01677             Fclose(psm->fd);
01678             psm->fd = NULL;
01679             errno = saveerrno;
01680         }
01681 
01682         if (psm->goal == PSM_PKGSAVE) {
01683             if (!rc)
01684                 rpmMessage(RPMMESS_VERBOSE, _("Wrote: %s\n"), psm->pkgURL);
01685         }
01686 
01687         if (fi->h && (psm->goal == PSM_PKGERASE || psm->goal == PSM_PKGSAVE)) {
01688             headerFree(fi->h);
01689             fi->h = NULL;
01690         }
01691         if (psm->oh) {
01692             headerFree(psm->oh);
01693             psm->oh = NULL;
01694         }
01695         psm->pkgURL = _free(psm->pkgURL);
01696         psm->rpmio_flags = _free(psm->rpmio_flags);
01697         psm->failedFile = _free(psm->failedFile);
01698 
01699         fi->fgids = _free(fi->fgids);
01700         fi->fuids = _free(fi->fuids);
01701         fi->fgroup = hfd(fi->fgroup, -1);
01702         fi->fuser = hfd(fi->fuser, -1);
01703         fi->apath = _free(fi->apath);
01704         fi->fstates = _free(fi->fstates);
01705 
01706         break;
01707 
01708     case PSM_PKGINSTALL:
01709     case PSM_PKGERASE:
01710     case PSM_PKGSAVE:
01711         psm->goal = stage;
01712         psm->rc = RPMRC_OK;
01713         psm->stepName = pkgStageString(stage);
01714 
01715         rc = psmStage(psm, PSM_INIT);
01716         if (!rc) rc = psmStage(psm, PSM_PRE);
01717         if (!rc) rc = psmStage(psm, PSM_PROCESS);
01718         if (!rc) rc = psmStage(psm, PSM_POST);
01719         (void) psmStage(psm, PSM_FINI);
01720         break;
01721     case PSM_PKGCOMMIT:
01722         break;
01723 
01724     case PSM_CREATE:
01725         break;
01726     case PSM_NOTIFY:
01727         if (ts && ts->notify)
01728             (void) ts->notify(fi->h, psm->what, psm->amount, psm->total,
01729                 (fi->ap ? fi->ap->key : NULL), ts->notifyData);
01730         break;
01731     case PSM_DESTROY:
01732         break;
01733     case PSM_COMMIT:
01734         if (!(ts->transFlags & RPMTRANS_FLAG_PKGCOMMIT)) break;
01735         if (ts->transFlags & RPMTRANS_FLAG_APPLYONLY) break;
01736 
01737         rc = fsmSetup(fi->fsm, FSM_PKGCOMMIT, ts, fi,
01738                         NULL, NULL, &psm->failedFile);
01739         (void) fsmTeardown(fi->fsm);
01740         break;
01741 
01742     case PSM_CHROOT_IN:
01743         /* Change root directory if requested and not already done. */
01744         if (ts->rootDir && !ts->chrootDone && !psm->chrootDone) {
01745             static int _loaded = 0;
01746 
01747             /*
01748              * This loads all of the name services libraries, in case we
01749              * don't have access to them in the chroot().
01750              */
01751             if (!_loaded) {
01752                 (void)getpwnam("root");
01753                 endpwent();
01754                 _loaded++;
01755             }
01756 
01757             chdir("/");
01758             /*@-unrecog@*/
01759             rc = chroot(ts->rootDir);
01760             /*@=unrecog@*/
01761             psm->chrootDone = ts->chrootDone = 1;
01762         }
01763         break;
01764     case PSM_CHROOT_OUT:
01765         /* Restore root directory if changed. */
01766         if (psm->chrootDone) {
01767             /*@-unrecog@*/
01768             rc = chroot(".");
01769             /*@=unrecog@*/
01770             psm->chrootDone = ts->chrootDone = 0;
01771             chdir(ts->currDir);
01772         }
01773         break;
01774     case PSM_SCRIPT:
01775         rpmMessage(RPMMESS_DEBUG, _("%s: running %s script(s) (if any)\n"),
01776                 psm->stepName, tag2sln(psm->scriptTag));
01777         rc = runInstScript(psm);
01778         break;
01779     case PSM_TRIGGERS:
01780         /* Run triggers in other package(s) this package sets off. */
01781         rc = runTriggers(psm);
01782         break;
01783     case PSM_IMMED_TRIGGERS:
01784         /* Run triggers in this package other package(s) set off. */
01785         rc = runImmedTriggers(psm);
01786         break;
01787 
01788     case PSM_RPMIO_FLAGS:
01789     {   const char * payload_compressor = NULL;
01790         char * t;
01791 
01792         if (!hge(fi->h, RPMTAG_PAYLOADCOMPRESSOR, NULL,
01793                             (void **) &payload_compressor, NULL))
01794             payload_compressor = "gzip";
01795         psm->rpmio_flags = t = xmalloc(sizeof("w9.gzdio"));
01796         *t = '\0';
01797         t = stpcpy(t, ((psm->goal == PSM_PKGSAVE) ? "w9" : "r"));
01798         if (!strcmp(payload_compressor, "gzip"))
01799             t = stpcpy(t, ".gzdio");
01800         if (!strcmp(payload_compressor, "bzip2"))
01801             t = stpcpy(t, ".bzdio");
01802         rc = RPMRC_OK;
01803     }   break;
01804 
01805     case PSM_RPMDB_LOAD:
01806 assert(psm->mi == NULL);
01807         psm->mi = rpmdbInitIterator(ts->rpmdb, RPMDBI_PACKAGES,
01808                                 &fi->record, sizeof(fi->record));
01809 
01810         fi->h = rpmdbNextIterator(psm->mi);
01811         if (fi->h)
01812             fi->h = headerLink(fi->h);
01813         rpmdbFreeIterator(psm->mi);
01814         psm->mi = NULL;
01815         rc = (fi->h ? RPMRC_OK : RPMRC_FAIL);
01816         break;
01817     case PSM_RPMDB_ADD:
01818         if (ts->transFlags & RPMTRANS_FLAG_TEST)        break;
01819         rc = rpmdbAdd(ts->rpmdb, ts->id, fi->h);
01820         break;
01821     case PSM_RPMDB_REMOVE:
01822         if (ts->transFlags & RPMTRANS_FLAG_TEST)        break;
01823         rc = rpmdbRemove(ts->rpmdb, ts->id, fi->record);
01824         break;
01825 
01826     default:
01827         break;
01828     }
01829 
01830     return rc;
01831 }

Generated at Thu Apr 19 15:29:43 2001 for rpm by doxygen1.2.6-20010408 written by Dimitri van Heesch, © 1997-2001