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, pid_t * pidp, size_t *fsizep)
00037
00038
00039
00040 {
00041
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
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
00061
00062 fdno = open(path, O_RDONLY);
00063 if (fdno < 0)
00064 return fdno;
00065
00066
00067 if (!(cmd && *cmd))
00068 return fdno;
00069
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
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
00089
00090 bingo = 0;
00091
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 continue;
00104 bingo = 1;
00105 break;
00106 }
00107 }
00108 }
00109
00110
00111
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
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
00195 fdno = open_dso(path, &pid, &fsize);
00196
00197 if (fdno < 0) {
00198 rc = 1;
00199 goto exit;
00200 }
00201
00202
00203 if (fsize > (size_t) 32*1024*1024)
00204 if (ut == URL_IS_PATH || ut == URL_IS_UNKNOWN)
00205 ut = URL_IS_DASH;
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 }
00237 #endif
00238 case URL_IS_FTP:
00239 case URL_IS_HTTP:
00240 case URL_IS_DASH:
00241 default:
00242
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
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
00274 if (fsizep)
00275 *fsizep = fsize;
00276 if (!rc)
00277 memcpy(digest, md5sum, md5len);
00278
00279 md5sum = _free(md5sum);
00280
00281 return rc;
00282 }
00283
00284
00285
00286 int _noDirTokens = 0;
00287
00288
00289
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
00298
00299
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
00317
00318
00319
00320
00321 if (headerIsEntry(h, RPMTAG_DIRNAMES)) {
00322 xx = hre(h, RPMTAG_OLDFILENAMES);
00323 return;
00324 }
00325
00326 if (!hge(h, RPMTAG_OLDFILENAMES, &fnt, (void **) &fileNames, &count))
00327 return;
00328 if (fileNames == NULL || count <= 0)
00329 return;
00330
00331 dirNames = xmalloc(sizeof(*dirNames) * count);
00332 baseNames = xmalloc(sizeof(*dirNames) * count);
00333 dirIndexes = xmalloc(sizeof(*dirIndexes) * count);
00334
00335 if (fileNames[0][0] != '/') {
00336
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
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)
00354 continue;
00355 baseName = strrchr(fileNames[i], '/') + 1;
00356 len = baseName - fileNames[i];
00357 needle = dirNames;
00358 savechar = *baseName;
00359 *baseName = '\0';
00360
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
00371
00372 *baseName = savechar;
00373 baseNames[i] = baseName;
00374 }
00375
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
00394
00395 void rpmfiBuildFNames(Header h, rpmTag tagN,
00396 const char *** fnp, 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;
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
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
00442 baseNames = hfd(baseNames, bnt);
00443 dirNames = hfd(dirNames, dnt);
00444
00445
00446 if (fnp)
00447 *fnp = fileNames;
00448 else
00449 fileNames = _free(fileNames);
00450
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
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
00472
00473 xx = hre(h, RPMTAG_DIRNAMES);
00474 xx = hre(h, RPMTAG_BASENAMES);
00475 xx = hre(h, RPMTAG_DIRINDEXES);
00476 }
00477
00478
00479
00480
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
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
00514
00515
00516 if (!hge(h, RPMTAG_PROVIDENAME, &pnt, (void **) &provides, &providesCount))
00517 goto exit;
00518
00519
00520
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
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
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
00569
00570
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
00579
00580
00581
00582
00583
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
00591
00592
00593
00594
00595
00596
00597
00598 if (lead->major < 4)
00599 compressFilelist(h);
00600
00601
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
00609 providePackageNVR(h);
00610 }
00611 }