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

Generated on Tue Sep 17 15:56:44 2002 for rpm by doxygen1.2.14 written by Dimitri van Heesch, © 1997-2002