rpmdb/legacy.c

Go to the documentation of this file.
00001 
00005 #include "system.h"
00006 
00007 #if HAVE_GELF_H
00008 
00009 #include <gelf.h>
00010 
00011 #if !defined(DT_GNU_PRELINKED)
00012 #define DT_GNU_PRELINKED        0x6ffffdf5
00013 #endif
00014 #if !defined(DT_GNU_LIBLIST)
00015 #define DT_GNU_LIBLIST          0x6ffffef9
00016 #endif
00017 
00018 #endif
00019 
00020 #include "rpmio_internal.h"
00021 #include <rpmlib.h>
00022 #include <rpmmacro.h>
00023 #include "misc.h"
00024 #include "legacy.h"
00025 #include "debug.h"
00026 
00027 #define alloca_strdup(_s)       strcpy(alloca(strlen(_s)+1), (_s))
00028 
00036 static int open_dso(const char * path, /*@null@*/ pid_t * pidp, /*@null@*/ size_t *fsizep)
00037         /*@globals rpmGlobalMacroContext, h_errno, fileSystem, internalState @*/
00038         /*@modifies *pidp, *fsizep, rpmGlobalMacroContext,
00039                 fileSystem, internalState @*/
00040 {
00041 /*@only@*/
00042     static const char * cmd = NULL;
00043     static int initted = 0;
00044     int fdno;
00045 
00046     if (!initted) {
00047         cmd = rpmExpand("%{?__prelink_undo_cmd}", NULL);
00048         initted++;
00049     }
00050 
00051 /*@-boundswrite@*/
00052     if (pidp) *pidp = 0;
00053 
00054     if (fsizep) {
00055         struct stat sb, * st = &sb;
00056         if (stat(path, st) < 0)
00057             return -1;
00058         *fsizep = st->st_size;
00059     }
00060 /*@=boundswrite@*/
00061 
00062     fdno = open(path, O_RDONLY);
00063     if (fdno < 0)
00064         return fdno;
00065 
00066 /*@-boundsread@*/
00067     if (!(cmd && *cmd))
00068         return fdno;
00069 /*@=boundsread@*/
00070 
00071 #if HAVE_GELF_H && HAVE_LIBELF
00072  {  Elf *elf = NULL;
00073     Elf_Scn *scn = NULL;
00074     Elf_Data *data = NULL;
00075     GElf_Ehdr ehdr;
00076     GElf_Shdr shdr;
00077     GElf_Dyn dyn;
00078     int bingo;
00079 
00080     (void) elf_version(EV_CURRENT);
00081 
00082 /*@-evalorder@*/
00083     if ((elf = elf_begin (fdno, ELF_C_READ, NULL)) == NULL
00084      || elf_kind(elf) != ELF_K_ELF
00085      || gelf_getehdr(elf, &ehdr) == NULL
00086      || !(ehdr.e_type == ET_DYN || ehdr.e_type == ET_EXEC))
00087         goto exit;
00088 /*@=evalorder@*/
00089 
00090     bingo = 0;
00091     /*@-branchstate -uniondef @*/
00092     while (!bingo && (scn = elf_nextscn(elf, scn)) != NULL) {
00093         (void) gelf_getshdr(scn, &shdr);
00094         if (shdr.sh_type != SHT_DYNAMIC)
00095             continue;
00096         while (!bingo && (data = elf_getdata (scn, data)) != NULL) {
00097             int maxndx = data->d_size / shdr.sh_entsize;
00098             int ndx;
00099 
00100             for (ndx = 0; ndx < maxndx; ++ndx) {
00101                 (void) gelf_getdyn (data, ndx, &dyn);
00102                 if (!(dyn.d_tag == DT_GNU_PRELINKED || dyn.d_tag == DT_GNU_LIBLIST))
00103                     /*@innercontinue@*/ continue;
00104                 bingo = 1;
00105                 /*@innerbreak@*/ break;
00106             }
00107         }
00108     }
00109     /*@=branchstate =uniondef @*/
00110 
00111 /*@-boundswrite@*/
00112     if (pidp != NULL && bingo) {
00113         int pipes[2];
00114         pid_t pid;
00115         int xx;
00116 
00117         xx = close(fdno);
00118         pipes[0] = pipes[1] = -1;
00119         xx = pipe(pipes);
00120         if (!(pid = fork())) {
00121             const char ** av;
00122             int ac;
00123             xx = close(pipes[0]);
00124             xx = dup2(pipes[1], STDOUT_FILENO);
00125             xx = close(pipes[1]);
00126             if (!poptParseArgvString(cmd, &ac, &av)) {
00127                 av[ac-1] = path;
00128                 av[ac] = NULL;
00129                 unsetenv("MALLOC_CHECK_");
00130                 xx = execve(av[0], (char *const *)av+1, environ);
00131             }
00132             _exit(127);
00133         }
00134         *pidp = pid;
00135         fdno = pipes[0];
00136         xx = close(pipes[1]);
00137     }
00138 /*@=boundswrite@*/
00139 
00140 exit:
00141     if (elf) (void) elf_end(elf);
00142  }
00143 #endif
00144 
00145     return fdno;
00146 }
00147 
00148 int domd5(const char * fn, unsigned char * digest, int asAscii, size_t *fsizep)
00149 {
00150     const char * path;
00151     urltype ut = urlPath(fn, &path);
00152     unsigned char * md5sum = NULL;
00153     size_t md5len;
00154     unsigned char buf[32*BUFSIZ];
00155     FD_t fd;
00156     size_t fsize = 0;
00157     pid_t pid = 0;
00158     int rc = 0;
00159     int fdno;
00160     int xx;
00161 
00162 /*@-globs -internalglobs -mods @*/
00163     fdno = open_dso(path, &pid, &fsize);
00164 /*@=globs =internalglobs =mods @*/
00165     if (fdno < 0) {
00166         rc = 1;
00167         goto exit;
00168     }
00169 
00170     switch(ut) {
00171     case URL_IS_PATH:
00172     case URL_IS_UNKNOWN:
00173 #if HAVE_MMAP
00174       if (pid == 0) {
00175         DIGEST_CTX ctx;
00176         void * mapped;
00177 
00178         if (fsize) {
00179             mapped = mmap(NULL, fsize, PROT_READ, MAP_SHARED, fdno, 0);
00180             if (mapped == (void *)-1) {
00181                 xx = close(fdno);
00182                 rc = 1;
00183                 break;
00184             }
00185 
00186 #ifdef  MADV_SEQUENTIAL
00187             xx = madvise(mapped, fsize, MADV_SEQUENTIAL);
00188 #endif
00189         }
00190 
00191         ctx = rpmDigestInit(PGPHASHALGO_MD5, RPMDIGEST_NONE);
00192         if (fsize)
00193             xx = rpmDigestUpdate(ctx, mapped, fsize);
00194         xx = rpmDigestFinal(ctx, (void **)&md5sum, &md5len, asAscii);
00195         if (fsize)
00196             xx = munmap(mapped, fsize);
00197         xx = close(fdno);
00198         break;
00199       } /*@fallthrough@*/
00200 #endif
00201     case URL_IS_HTTPS:
00202     case URL_IS_HTTP:
00203     case URL_IS_FTP:
00204     case URL_IS_HKP:
00205     case URL_IS_DASH:
00206     default:
00207         /* Either use the pipe to prelink -y or open the URL. */
00208         fd = (pid != 0) ? fdDup(fdno) : Fopen(fn, "r.ufdio");
00209         (void) close(fdno);
00210         if (fd == NULL || Ferror(fd)) {
00211             rc = 1;
00212             if (fd != NULL)
00213                 (void) Fclose(fd);
00214             break;
00215         }
00216         
00217         fdInitDigest(fd, PGPHASHALGO_MD5, 0);
00218         fsize = 0;
00219         while ((rc = Fread(buf, sizeof(buf[0]), sizeof(buf), fd)) > 0)
00220             fsize += rc;
00221         fdFiniDigest(fd, PGPHASHALGO_MD5, (void **)&md5sum, &md5len, asAscii);
00222         if (Ferror(fd))
00223             rc = 1;
00224 
00225         (void) Fclose(fd);
00226         break;
00227     }
00228 
00229     /* Reap the prelink -y helper. */
00230     if (pid) {
00231         int status;
00232         (void) waitpid(pid, &status, 0);
00233         if (!WIFEXITED(status) || WEXITSTATUS(status))
00234             rc = 1;
00235     }
00236 
00237 exit:
00238 /*@-boundswrite@*/
00239     if (fsizep)
00240         *fsizep = fsize;
00241     if (!rc)
00242         memcpy(digest, md5sum, md5len);
00243 /*@=boundswrite@*/
00244     md5sum = _free(md5sum);
00245 
00246     return rc;
00247 }
00248 
00249 /*@-exportheadervar@*/
00250 /*@unchecked@*/
00251 int _noDirTokens = 0;
00252 /*@=exportheadervar@*/
00253 
00254 /*@-boundsread@*/
00255 static int dncmp(const void * a, const void * b)
00256         /*@*/
00257 {
00258     const char *const * first = a;
00259     const char *const * second = b;
00260     return strcmp(*first, *second);
00261 }
00262 /*@=boundsread@*/
00263 
00264 /*@-bounds@*/
00265 void compressFilelist(Header h)
00266 {
00267     HGE_t hge = (HGE_t)headerGetEntryMinMemory;
00268     HAE_t hae = (HAE_t)headerAddEntry;
00269     HRE_t hre = (HRE_t)headerRemoveEntry;
00270     HFD_t hfd = headerFreeData;
00271     char ** fileNames;
00272     const char ** dirNames;
00273     const char ** baseNames;
00274     int_32 * dirIndexes;
00275     rpmTagType fnt;
00276     int count;
00277     int i, xx;
00278     int dirIndex = -1;
00279 
00280     /*
00281      * This assumes the file list is already sorted, and begins with a
00282      * single '/'. That assumption isn't critical, but it makes things go
00283      * a bit faster.
00284      */
00285 
00286     if (headerIsEntry(h, RPMTAG_DIRNAMES)) {
00287         xx = hre(h, RPMTAG_OLDFILENAMES);
00288         return;         /* Already converted. */
00289     }
00290 
00291     if (!hge(h, RPMTAG_OLDFILENAMES, &fnt, (void **) &fileNames, &count))
00292         return;         /* no file list */
00293     if (fileNames == NULL || count <= 0)
00294         return;
00295 
00296     dirNames = alloca(sizeof(*dirNames) * count);       /* worst case */
00297     baseNames = alloca(sizeof(*dirNames) * count);
00298     dirIndexes = alloca(sizeof(*dirIndexes) * count);
00299 
00300     if (fileNames[0][0] != '/') {
00301         /* HACK. Source RPM, so just do things differently */
00302         dirIndex = 0;
00303         dirNames[dirIndex] = "";
00304         for (i = 0; i < count; i++) {
00305             dirIndexes[i] = dirIndex;
00306             baseNames[i] = fileNames[i];
00307         }
00308         goto exit;
00309     }
00310 
00311     /*@-branchstate@*/
00312     for (i = 0; i < count; i++) {
00313         const char ** needle;
00314         char savechar;
00315         char * baseName;
00316         int len;
00317 
00318         if (fileNames[i] == NULL)       /* XXX can't happen */
00319             continue;
00320         baseName = strrchr(fileNames[i], '/') + 1;
00321         len = baseName - fileNames[i];
00322         needle = dirNames;
00323         savechar = *baseName;
00324         *baseName = '\0';
00325 /*@-compdef@*/
00326         if (dirIndex < 0 ||
00327             (needle = bsearch(&fileNames[i], dirNames, dirIndex + 1, sizeof(dirNames[0]), dncmp)) == NULL) {
00328             char *s = alloca(len + 1);
00329             memcpy(s, fileNames[i], len + 1);
00330             s[len] = '\0';
00331             dirIndexes[i] = ++dirIndex;
00332             dirNames[dirIndex] = s;
00333         } else
00334             dirIndexes[i] = needle - dirNames;
00335 /*@=compdef@*/
00336 
00337         *baseName = savechar;
00338         baseNames[i] = baseName;
00339     }
00340     /*@=branchstate@*/
00341 
00342 exit:
00343     if (count > 0) {
00344         xx = hae(h, RPMTAG_DIRINDEXES, RPM_INT32_TYPE, dirIndexes, count);
00345         xx = hae(h, RPMTAG_BASENAMES, RPM_STRING_ARRAY_TYPE,
00346                         baseNames, count);
00347         xx = hae(h, RPMTAG_DIRNAMES, RPM_STRING_ARRAY_TYPE,
00348                         dirNames, dirIndex + 1);
00349     }
00350 
00351     fileNames = hfd(fileNames, fnt);
00352 
00353     xx = hre(h, RPMTAG_OLDFILENAMES);
00354 }
00355 /*@=bounds@*/
00356 
00357 void rpmfiBuildFNames(Header h, rpmTag tagN,
00358         /*@out@*/ const char *** fnp, /*@out@*/ int * fcp)
00359 {
00360     HGE_t hge = (HGE_t)headerGetEntryMinMemory;
00361     HFD_t hfd = headerFreeData;
00362     const char ** baseNames;
00363     const char ** dirNames;
00364     int * dirIndexes;
00365     int count;
00366     const char ** fileNames;
00367     int size;
00368     rpmTag dirNameTag = 0;
00369     rpmTag dirIndexesTag = 0;
00370     rpmTagType bnt, dnt;
00371     char * t;
00372     int i, xx;
00373 
00374     if (tagN == RPMTAG_BASENAMES) {
00375         dirNameTag = RPMTAG_DIRNAMES;
00376         dirIndexesTag = RPMTAG_DIRINDEXES;
00377     } else if (tagN == RPMTAG_ORIGBASENAMES) {
00378         dirNameTag = RPMTAG_ORIGDIRNAMES;
00379         dirIndexesTag = RPMTAG_ORIGDIRINDEXES;
00380     }
00381 
00382     if (!hge(h, tagN, &bnt, (void **) &baseNames, &count)) {
00383         if (fnp) *fnp = NULL;
00384         if (fcp) *fcp = 0;
00385         return;         /* no file list */
00386     }
00387 
00388     xx = hge(h, dirNameTag, &dnt, (void **) &dirNames, NULL);
00389     xx = hge(h, dirIndexesTag, NULL, (void **) &dirIndexes, &count);
00390 
00391     size = sizeof(*fileNames) * count;
00392     for (i = 0; i < count; i++)
00393         size += strlen(baseNames[i]) + strlen(dirNames[dirIndexes[i]]) + 1;
00394 
00395     fileNames = xmalloc(size);
00396     t = ((char *) fileNames) + (sizeof(*fileNames) * count);
00397     /*@-branchstate@*/
00398     for (i = 0; i < count; i++) {
00399         fileNames[i] = t;
00400         t = stpcpy( stpcpy(t, dirNames[dirIndexes[i]]), baseNames[i]);
00401         *t++ = '\0';
00402     }
00403     /*@=branchstate@*/
00404     baseNames = hfd(baseNames, bnt);
00405     dirNames = hfd(dirNames, dnt);
00406 
00407     /*@-branchstate@*/
00408     if (fnp)
00409         *fnp = fileNames;
00410     else
00411         fileNames = _free(fileNames);
00412     /*@=branchstate@*/
00413     if (fcp) *fcp = count;
00414 }
00415 
00416 void expandFilelist(Header h)
00417 {
00418     HAE_t hae = (HAE_t)headerAddEntry;
00419     HRE_t hre = (HRE_t)headerRemoveEntry;
00420     const char ** fileNames = NULL;
00421     int count = 0;
00422     int xx;
00423 
00424     /*@-branchstate@*/
00425     if (!headerIsEntry(h, RPMTAG_OLDFILENAMES)) {
00426         rpmfiBuildFNames(h, RPMTAG_BASENAMES, &fileNames, &count);
00427         if (fileNames == NULL || count <= 0)
00428             return;
00429         xx = hae(h, RPMTAG_OLDFILENAMES, RPM_STRING_ARRAY_TYPE,
00430                         fileNames, count);
00431         fileNames = _free(fileNames);
00432     }
00433     /*@=branchstate@*/
00434 
00435     xx = hre(h, RPMTAG_DIRNAMES);
00436     xx = hre(h, RPMTAG_BASENAMES);
00437     xx = hre(h, RPMTAG_DIRINDEXES);
00438 }
00439 
00440 /*
00441  * Up to rpm 3.0.4, packages implicitly provided their own name-version-release.
00442  * Retrofit an explicit "Provides: name = epoch:version-release.
00443  */
00444 void providePackageNVR(Header h)
00445 {
00446     HGE_t hge = (HGE_t)headerGetEntryMinMemory;
00447     HFD_t hfd = headerFreeData;
00448     const char *name, *version, *release;
00449     int_32 * epoch;
00450     const char *pEVR;
00451     char *p;
00452     int_32 pFlags = RPMSENSE_EQUAL;
00453     const char ** provides = NULL;
00454     const char ** providesEVR = NULL;
00455     rpmTagType pnt, pvt;
00456     int_32 * provideFlags = NULL;
00457     int providesCount;
00458     int i, xx;
00459     int bingo = 1;
00460 
00461     /* Generate provides for this package name-version-release. */
00462     xx = headerNVR(h, &name, &version, &release);
00463     if (!(name && version && release))
00464         return;
00465     pEVR = p = alloca(21 + strlen(version) + 1 + strlen(release) + 1);
00466     *p = '\0';
00467     if (hge(h, RPMTAG_EPOCH, NULL, (void **) &epoch, NULL)) {
00468         sprintf(p, "%d:", *epoch);
00469         while (*p != '\0')
00470             p++;
00471     }
00472     (void) stpcpy( stpcpy( stpcpy(p, version) , "-") , release);
00473 
00474     /*
00475      * Rpm prior to 3.0.3 does not have versioned provides.
00476      * If no provides at all are available, we can just add.
00477      */
00478     if (!hge(h, RPMTAG_PROVIDENAME, &pnt, (void **) &provides, &providesCount))
00479         goto exit;
00480 
00481     /*
00482      * Otherwise, fill in entries on legacy packages.
00483      */
00484     if (!hge(h, RPMTAG_PROVIDEVERSION, &pvt, (void **) &providesEVR, NULL)) {
00485         for (i = 0; i < providesCount; i++) {
00486             char * vdummy = "";
00487             int_32 fdummy = RPMSENSE_ANY;
00488             xx = headerAddOrAppendEntry(h, RPMTAG_PROVIDEVERSION, RPM_STRING_ARRAY_TYPE,
00489                         &vdummy, 1);
00490             xx = headerAddOrAppendEntry(h, RPMTAG_PROVIDEFLAGS, RPM_INT32_TYPE,
00491                         &fdummy, 1);
00492         }
00493         goto exit;
00494     }
00495 
00496     xx = hge(h, RPMTAG_PROVIDEFLAGS, NULL, (void **) &provideFlags, NULL);
00497 
00498     /*@-nullderef@*/    /* LCL: providesEVR is not NULL */
00499     if (provides && providesEVR && provideFlags)
00500     for (i = 0; i < providesCount; i++) {
00501         if (!(provides[i] && providesEVR[i]))
00502             continue;
00503         if (!(provideFlags[i] == RPMSENSE_EQUAL &&
00504             !strcmp(name, provides[i]) && !strcmp(pEVR, providesEVR[i])))
00505             continue;
00506         bingo = 0;
00507         break;
00508     }
00509     /*@=nullderef@*/
00510 
00511 exit:
00512     provides = hfd(provides, pnt);
00513     providesEVR = hfd(providesEVR, pvt);
00514 
00515     if (bingo) {
00516         xx = headerAddOrAppendEntry(h, RPMTAG_PROVIDENAME, RPM_STRING_ARRAY_TYPE,
00517                 &name, 1);
00518         xx = headerAddOrAppendEntry(h, RPMTAG_PROVIDEFLAGS, RPM_INT32_TYPE,
00519                 &pFlags, 1);
00520         xx = headerAddOrAppendEntry(h, RPMTAG_PROVIDEVERSION, RPM_STRING_ARRAY_TYPE,
00521                 &pEVR, 1);
00522     }
00523 }
00524 
00525 void legacyRetrofit(Header h, const struct rpmlead * lead)
00526 {
00527     const char * prefix;
00528 
00529     /*
00530      * We don't use these entries (and rpm >= 2 never has) and they are
00531      * pretty misleading. Let's just get rid of them so they don't confuse
00532      * anyone.
00533      */
00534     if (headerIsEntry(h, RPMTAG_FILEUSERNAME))
00535         (void) headerRemoveEntry(h, RPMTAG_FILEUIDS);
00536     if (headerIsEntry(h, RPMTAG_FILEGROUPNAME))
00537         (void) headerRemoveEntry(h, RPMTAG_FILEGIDS);
00538 
00539     /*
00540      * We switched the way we do relocatable packages. We fix some of
00541      * it up here, though the install code still has to be a bit 
00542      * careful. This fixup makes queries give the new values though,
00543      * which is quite handy.
00544      */
00545     /*@=branchstate@*/
00546     if (headerGetEntry(h, RPMTAG_DEFAULTPREFIX, NULL, (void **) &prefix, NULL))
00547     {
00548         const char * nprefix = stripTrailingChar(alloca_strdup(prefix), '/');
00549         (void) headerAddEntry(h, RPMTAG_PREFIXES, RPM_STRING_ARRAY_TYPE,
00550                 &nprefix, 1); 
00551     }
00552     /*@=branchstate@*/
00553 
00554     /*
00555      * The file list was moved to a more compressed format which not
00556      * only saves memory (nice), but gives fingerprinting a nice, fat
00557      * speed boost (very nice). Go ahead and convert old headers to
00558      * the new style (this is a noop for new headers).
00559      */
00560     if (lead->major < 4)
00561         compressFilelist(h);
00562 
00563     /* XXX binary rpms always have RPMTAG_SOURCERPM, source rpms do not */
00564     if (lead->type == RPMLEAD_SOURCE) {
00565         int_32 one = 1;
00566         if (!headerIsEntry(h, RPMTAG_SOURCEPACKAGE))
00567             (void) headerAddEntry(h, RPMTAG_SOURCEPACKAGE, RPM_INT32_TYPE,
00568                                 &one, 1);
00569     } else if (lead->major < 4) {
00570         /* Retrofit "Provide: name = EVR" for binary packages. */
00571         providePackageNVR(h);
00572     }
00573 }

Generated on Mon Mar 5 13:30:28 2007 for rpm by  doxygen 1.5.1