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 }

Generated on Wed Sep 4 12:49:55 2002 for rpm by doxygen1.2.14 written by Dimitri van Heesch, © 1997-2002