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

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 
00131 #if defined(__GLIBC__)
00132 
00136                 {
00137                    char* bypassVar = (char*) malloc(1024*sizeof(char));
00138                    if (bypassVar != NULL)
00139                    {
00140                       snprintf(bypassVar,1024*sizeof(char), "__PASSTHROUGH_LD_ASSUME_KERNEL_%d", getppid());
00141                       bypassVar[1023] = '\0';
00142                       if (getenv(bypassVar) != NULL)
00143                       {
00144                          char* bypassVal = (char*) malloc(1024*sizeof(char));
00145                          if (bypassVal != NULL)
00146                          {
00147                             snprintf(bypassVal, 1024*sizeof(char), "%s", getenv(bypassVar));
00148                             unsetenv(bypassVar);
00149                             snprintf(bypassVar, 1024*sizeof(char), "LD_ASSUME_KERNEL=%s", bypassVal);
00150                             bypassVar[1023] = '\0';
00151                             putenv(bypassVar);
00152                             free(bypassVal);
00153                          }
00154                          else
00155                          {
00156                             free(bypassVar);
00157                          }
00158                       }
00159                    }
00160                 }
00161 #endif
00162                 xx = execve(av[0], (char *const *)av+1, environ);
00163             }
00164             _exit(127);
00165         }
00166         *pidp = pid;
00167         fdno = pipes[0];
00168         xx = close(pipes[1]);
00169     }
00170 /*@=boundswrite@*/
00171 
00172 exit:
00173     if (elf) (void) elf_end(elf);
00174  }
00175 #endif
00176 
00177     return fdno;
00178 }
00179 
00180 int domd5(const char * fn, unsigned char * digest, int asAscii, size_t *fsizep)
00181 {
00182     const char * path;
00183     urltype ut = urlPath(fn, &path);
00184     unsigned char * md5sum = NULL;
00185     size_t md5len;
00186     unsigned char buf[32*BUFSIZ];
00187     FD_t fd;
00188     size_t fsize = 0;
00189     pid_t pid = 0;
00190     int rc = 0;
00191     int fdno;
00192     int xx;
00193 
00194 /*@-globs -internalglobs -mods @*/
00195     fdno = open_dso(path, &pid, &fsize);
00196 /*@=globs =internalglobs =mods @*/
00197     if (fdno < 0) {
00198         rc = 1;
00199         goto exit;
00200     }
00201 
00202     /* file to large (32 MB), do not mmap file */
00203     if (fsize > (size_t) 32*1024*1024)
00204       if (ut == URL_IS_PATH || ut == URL_IS_UNKNOWN)
00205         ut = URL_IS_DASH; /* force fd io */
00206 
00207     switch(ut) {
00208     case URL_IS_PATH:
00209     case URL_IS_UNKNOWN:
00210 #if HAVE_MMAP
00211       if (pid == 0) {
00212         DIGEST_CTX ctx;
00213         void * mapped;
00214 
00215         if (fsize) {
00216             mapped = mmap(NULL, fsize, PROT_READ, MAP_SHARED, fdno, 0);
00217             if (mapped == (void *)-1) {
00218                 xx = close(fdno);
00219                 rc = 1;
00220                 break;
00221             }
00222 
00223 #ifdef  MADV_SEQUENTIAL
00224             xx = madvise(mapped, fsize, MADV_SEQUENTIAL);
00225 #endif
00226         }
00227 
00228         ctx = rpmDigestInit(PGPHASHALGO_MD5, RPMDIGEST_NONE);
00229         if (fsize)
00230             xx = rpmDigestUpdate(ctx, mapped, fsize);
00231         xx = rpmDigestFinal(ctx, (void **)&md5sum, &md5len, asAscii);
00232         if (fsize)
00233             xx = munmap(mapped, fsize);
00234         xx = close(fdno);
00235         break;
00236       } /*@fallthrough@*/
00237 #endif
00238     case URL_IS_FTP:
00239     case URL_IS_HTTP:
00240     case URL_IS_DASH:
00241     default:
00242         /* Either use the pipe to prelink -y or open the URL. */
00243         fd = (pid != 0) ? fdDup(fdno) : Fopen(fn, "r.ufdio");
00244         (void) close(fdno);
00245         if (fd == NULL || Ferror(fd)) {
00246             rc = 1;
00247             if (fd != NULL)
00248                 (void) Fclose(fd);
00249             break;
00250         }
00251         
00252         fdInitDigest(fd, PGPHASHALGO_MD5, 0);
00253         fsize = 0;
00254         while ((rc = Fread(buf, sizeof(buf[0]), sizeof(buf), fd)) > 0)
00255             fsize += rc;
00256         fdFiniDigest(fd, PGPHASHALGO_MD5, (void **)&md5sum, &md5len, asAscii);
00257         if (Ferror(fd))
00258             rc = 1;
00259 
00260         (void) Fclose(fd);
00261         break;
00262     }
00263 
00264     /* Reap the prelink -y helper. */
00265     if (pid) {
00266         int status;
00267         (void) waitpid(pid, &status, 0);
00268         if (!WIFEXITED(status) || WEXITSTATUS(status))
00269             rc = 1;
00270     }
00271 
00272 exit:
00273 /*@-boundswrite@*/
00274     if (fsizep)
00275         *fsizep = fsize;
00276     if (!rc)
00277         memcpy(digest, md5sum, md5len);
00278 /*@=boundswrite@*/
00279     md5sum = _free(md5sum);
00280 
00281     return rc;
00282 }
00283 
00284 /*@-exportheadervar@*/
00285 /*@unchecked@*/
00286 int _noDirTokens = 0;
00287 /*@=exportheadervar@*/
00288 
00289 /*@-boundsread@*/
00290 static int dncmp(const void * a, const void * b)
00291         /*@*/
00292 {
00293     const char *const * first = a;
00294     const char *const * second = b;
00295     return strcmp(*first, *second);
00296 }
00297 /*@=boundsread@*/
00298 
00299 /*@-bounds@*/
00300 void compressFilelist(Header h)
00301 {
00302     HGE_t hge = (HGE_t)headerGetEntryMinMemory;
00303     HAE_t hae = (HAE_t)headerAddEntry;
00304     HRE_t hre = (HRE_t)headerRemoveEntry;
00305     HFD_t hfd = headerFreeData;
00306     char ** fileNames;
00307     const char ** dirNames;
00308     const char ** baseNames;
00309     int_32 * dirIndexes;
00310     rpmTagType fnt;
00311     int count;
00312     int i, xx;
00313     int dirIndex = -1;
00314 
00315     /*
00316      * This assumes the file list is already sorted, and begins with a
00317      * single '/'. That assumption isn't critical, but it makes things go
00318      * a bit faster.
00319      */
00320 
00321     if (headerIsEntry(h, RPMTAG_DIRNAMES)) {
00322         xx = hre(h, RPMTAG_OLDFILENAMES);
00323         return;         /* Already converted. */
00324     }
00325 
00326     if (!hge(h, RPMTAG_OLDFILENAMES, &fnt, (void **) &fileNames, &count))
00327         return;         /* no file list */
00328     if (fileNames == NULL || count <= 0)
00329         return;
00330 
00331     dirNames = xmalloc(sizeof(*dirNames) * count);      /* worst case */
00332     baseNames = xmalloc(sizeof(*dirNames) * count);
00333     dirIndexes = xmalloc(sizeof(*dirIndexes) * count);
00334 
00335     if (fileNames[0][0] != '/') {
00336         /* HACK. Source RPM, so just do things differently */
00337         dirIndex = 0;
00338         dirNames[dirIndex] = "";
00339         for (i = 0; i < count; i++) {
00340             dirIndexes[i] = dirIndex;
00341             baseNames[i] = fileNames[i];
00342         }
00343         goto exit;
00344     }
00345 
00346     /*@-branchstate@*/
00347     for (i = 0; i < count; i++) {
00348         const char ** needle;
00349         char savechar;
00350         char * baseName;
00351         int len;
00352 
00353         if (fileNames[i] == NULL)       /* XXX can't happen */
00354             continue;
00355         baseName = strrchr(fileNames[i], '/') + 1;
00356         len = baseName - fileNames[i];
00357         needle = dirNames;
00358         savechar = *baseName;
00359         *baseName = '\0';
00360 /*@-compdef@*/
00361         if (dirIndex < 0 ||
00362             (needle = bsearch(&fileNames[i], dirNames, dirIndex + 1, sizeof(dirNames[0]), dncmp)) == NULL) {
00363             char *s = alloca(len + 1);
00364             memcpy(s, fileNames[i], len + 1);
00365             s[len] = '\0';
00366             dirIndexes[i] = ++dirIndex;
00367             dirNames[dirIndex] = s;
00368         } else
00369             dirIndexes[i] = needle - dirNames;
00370 /*@=compdef@*/
00371 
00372         *baseName = savechar;
00373         baseNames[i] = baseName;
00374     }
00375     /*@=branchstate@*/
00376 
00377 exit:
00378     if (count > 0) {
00379         xx = hae(h, RPMTAG_DIRINDEXES, RPM_INT32_TYPE, dirIndexes, count);
00380         xx = hae(h, RPMTAG_BASENAMES, RPM_STRING_ARRAY_TYPE,
00381                         baseNames, count);
00382         xx = hae(h, RPMTAG_DIRNAMES, RPM_STRING_ARRAY_TYPE,
00383                         dirNames, dirIndex + 1);
00384     }
00385 
00386     fileNames = hfd(fileNames, fnt);
00387 
00388     free(dirNames);
00389     free(baseNames);
00390     free(dirIndexes);
00391     xx = hre(h, RPMTAG_OLDFILENAMES);
00392 }
00393 /*@=bounds@*/
00394 
00395 void rpmfiBuildFNames(Header h, rpmTag tagN,
00396         /*@out@*/ const char *** fnp, /*@out@*/ int * fcp)
00397 {
00398     HGE_t hge = (HGE_t)headerGetEntryMinMemory;
00399     HFD_t hfd = headerFreeData;
00400     const char ** baseNames;
00401     const char ** dirNames;
00402     int * dirIndexes;
00403     int count;
00404     const char ** fileNames;
00405     int size;
00406     rpmTag dirNameTag = 0;
00407     rpmTag dirIndexesTag = 0;
00408     rpmTagType bnt, dnt;
00409     char * t;
00410     int i, xx;
00411 
00412     if (tagN == RPMTAG_BASENAMES) {
00413         dirNameTag = RPMTAG_DIRNAMES;
00414         dirIndexesTag = RPMTAG_DIRINDEXES;
00415     } else if (tagN == RPMTAG_ORIGBASENAMES) {
00416         dirNameTag = RPMTAG_ORIGDIRNAMES;
00417         dirIndexesTag = RPMTAG_ORIGDIRINDEXES;
00418     }
00419 
00420     if (!hge(h, tagN, &bnt, (void **) &baseNames, &count)) {
00421         if (fnp) *fnp = NULL;
00422         if (fcp) *fcp = 0;
00423         return;         /* no file list */
00424     }
00425 
00426     xx = hge(h, dirNameTag, &dnt, (void **) &dirNames, NULL);
00427     xx = hge(h, dirIndexesTag, NULL, (void **) &dirIndexes, &count);
00428 
00429     size = sizeof(*fileNames) * count;
00430     for (i = 0; i < count; i++)
00431         size += strlen(baseNames[i]) + strlen(dirNames[dirIndexes[i]]) + 1;
00432 
00433     fileNames = xmalloc(size);
00434     t = ((char *) fileNames) + (sizeof(*fileNames) * count);
00435     /*@-branchstate@*/
00436     for (i = 0; i < count; i++) {
00437         fileNames[i] = t;
00438         t = stpcpy( stpcpy(t, dirNames[dirIndexes[i]]), baseNames[i]);
00439         *t++ = '\0';
00440     }
00441     /*@=branchstate@*/
00442     baseNames = hfd(baseNames, bnt);
00443     dirNames = hfd(dirNames, dnt);
00444 
00445     /*@-branchstate@*/
00446     if (fnp)
00447         *fnp = fileNames;
00448     else
00449         fileNames = _free(fileNames);
00450     /*@=branchstate@*/
00451     if (fcp) *fcp = count;
00452 }
00453 
00454 void expandFilelist(Header h)
00455 {
00456     HAE_t hae = (HAE_t)headerAddEntry;
00457     HRE_t hre = (HRE_t)headerRemoveEntry;
00458     const char ** fileNames = NULL;
00459     int count = 0;
00460     int xx;
00461 
00462     /*@-branchstate@*/
00463     if (!headerIsEntry(h, RPMTAG_OLDFILENAMES)) {
00464         rpmfiBuildFNames(h, RPMTAG_BASENAMES, &fileNames, &count);
00465         if (fileNames == NULL || count <= 0)
00466             return;
00467         xx = hae(h, RPMTAG_OLDFILENAMES, RPM_STRING_ARRAY_TYPE,
00468                         fileNames, count);
00469         fileNames = _free(fileNames);
00470     }
00471     /*@=branchstate@*/
00472 
00473     xx = hre(h, RPMTAG_DIRNAMES);
00474     xx = hre(h, RPMTAG_BASENAMES);
00475     xx = hre(h, RPMTAG_DIRINDEXES);
00476 }
00477 
00478 /*
00479  * Up to rpm 3.0.4, packages implicitly provided their own name-version-release.
00480  * Retrofit an explicit "Provides: name = epoch:version-release.
00481  */
00482 void providePackageNVR(Header h)
00483 {
00484     HGE_t hge = (HGE_t)headerGetEntryMinMemory;
00485     HFD_t hfd = headerFreeData;
00486     const char *name, *version, *release;
00487     int_32 * epoch;
00488     const char *pEVR;
00489     char *p;
00490     int_32 pFlags = RPMSENSE_EQUAL;
00491     const char ** provides = NULL;
00492     const char ** providesEVR = NULL;
00493     rpmTagType pnt, pvt;
00494     int_32 * provideFlags = NULL;
00495     int providesCount;
00496     int i, xx;
00497     int bingo = 1;
00498 
00499     /* Generate provides for this package name-version-release. */
00500     xx = headerNVR(h, &name, &version, &release);
00501     if (!(name && version && release))
00502         return;
00503     pEVR = p = alloca(21 + strlen(version) + 1 + strlen(release) + 1);
00504     *p = '\0';
00505     if (hge(h, RPMTAG_EPOCH, NULL, (void **) &epoch, NULL)) {
00506         sprintf(p, "%d:", *epoch);
00507         while (*p != '\0')
00508             p++;
00509     }
00510     (void) stpcpy( stpcpy( stpcpy(p, version) , "-") , release);
00511 
00512     /*
00513      * Rpm prior to 3.0.3 does not have versioned provides.
00514      * If no provides at all are available, we can just add.
00515      */
00516     if (!hge(h, RPMTAG_PROVIDENAME, &pnt, (void **) &provides, &providesCount))
00517         goto exit;
00518 
00519     /*
00520      * Otherwise, fill in entries on legacy packages.
00521      */
00522     if (!hge(h, RPMTAG_PROVIDEVERSION, &pvt, (void **) &providesEVR, NULL)) {
00523         for (i = 0; i < providesCount; i++) {
00524             char * vdummy = "";
00525             int_32 fdummy = RPMSENSE_ANY;
00526             xx = headerAddOrAppendEntry(h, RPMTAG_PROVIDEVERSION, RPM_STRING_ARRAY_TYPE,
00527                         &vdummy, 1);
00528             xx = headerAddOrAppendEntry(h, RPMTAG_PROVIDEFLAGS, RPM_INT32_TYPE,
00529                         &fdummy, 1);
00530         }
00531         goto exit;
00532     }
00533 
00534     xx = hge(h, RPMTAG_PROVIDEFLAGS, NULL, (void **) &provideFlags, NULL);
00535 
00536     /*@-nullderef@*/    /* LCL: providesEVR is not NULL */
00537     if (provides && providesEVR && provideFlags)
00538     for (i = 0; i < providesCount; i++) {
00539         if (!(provides[i] && providesEVR[i]))
00540             continue;
00541         if (!(provideFlags[i] == RPMSENSE_EQUAL &&
00542             !strcmp(name, provides[i]) && !strcmp(pEVR, providesEVR[i])))
00543             continue;
00544         bingo = 0;
00545         break;
00546     }
00547     /*@=nullderef@*/
00548 
00549 exit:
00550     provides = hfd(provides, pnt);
00551     providesEVR = hfd(providesEVR, pvt);
00552 
00553     if (bingo) {
00554         xx = headerAddOrAppendEntry(h, RPMTAG_PROVIDENAME, RPM_STRING_ARRAY_TYPE,
00555                 &name, 1);
00556         xx = headerAddOrAppendEntry(h, RPMTAG_PROVIDEFLAGS, RPM_INT32_TYPE,
00557                 &pFlags, 1);
00558         xx = headerAddOrAppendEntry(h, RPMTAG_PROVIDEVERSION, RPM_STRING_ARRAY_TYPE,
00559                 &pEVR, 1);
00560     }
00561 }
00562 
00563 void legacyRetrofit(Header h, const struct rpmlead * lead)
00564 {
00565     const char * prefix;
00566 
00567     /*
00568      * We don't use these entries (and rpm >= 2 never has) and they are
00569      * pretty misleading. Let's just get rid of them so they don't confuse
00570      * anyone.
00571      */
00572     if (headerIsEntry(h, RPMTAG_FILEUSERNAME))
00573         (void) headerRemoveEntry(h, RPMTAG_FILEUIDS);
00574     if (headerIsEntry(h, RPMTAG_FILEGROUPNAME))
00575         (void) headerRemoveEntry(h, RPMTAG_FILEGIDS);
00576 
00577     /*
00578      * We switched the way we do relocatable packages. We fix some of
00579      * it up here, though the install code still has to be a bit 
00580      * careful. This fixup makes queries give the new values though,
00581      * which is quite handy.
00582      */
00583     /*@=branchstate@*/
00584     if (headerGetEntry(h, RPMTAG_DEFAULTPREFIX, NULL, (void **) &prefix, NULL))
00585     {
00586         const char * nprefix = stripTrailingChar(alloca_strdup(prefix), '/');
00587         (void) headerAddEntry(h, RPMTAG_PREFIXES, RPM_STRING_ARRAY_TYPE,
00588                 &nprefix, 1); 
00589     }
00590     /*@=branchstate@*/
00591 
00592     /*
00593      * The file list was moved to a more compressed format which not
00594      * only saves memory (nice), but gives fingerprinting a nice, fat
00595      * speed boost (very nice). Go ahead and convert old headers to
00596      * the new style (this is a noop for new headers).
00597      */
00598     if (lead->major < 4)
00599         compressFilelist(h);
00600 
00601     /* XXX binary rpms always have RPMTAG_SOURCERPM, source rpms do not */
00602     if (lead->type == RPMLEAD_SOURCE) {
00603         int_32 one = 1;
00604         if (!headerIsEntry(h, RPMTAG_SOURCEPACKAGE))
00605             (void) headerAddEntry(h, RPMTAG_SOURCEPACKAGE, RPM_INT32_TYPE,
00606                                 &one, 1);
00607     } else if (lead->major < 4) {
00608         /* Retrofit "Provide: name = EVR" for binary packages. */
00609         providePackageNVR(h);
00610     }
00611 }

Generated on Sat May 23 04:08:18 2009 for rpm by  doxygen 1.3.9.1