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

# rpmdb/legacy.c

Go to the documentation of this file.

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