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 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
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
00163 fdno = open_dso(path, &pid, &fsize);
00164
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 if (fsize) {
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
00191 ctx = rpmDigestInit(PGPHASHALGO_MD5, RPMDIGEST_NONE);
00192 if (fsize)
00193 xx = rpmDigestUpdate(ctx, mapped, fsize);
00194 xx = rpmDigestFinal(ctx, (void **)&md5sum, &md5len, asAscii);
00195 if (fsize)
00196 xx = munmap(mapped, fsize);
00197 xx = close(fdno);
00198 break;
00199 }
00200 #endif
00201 case URL_IS_HTTPS:
00202 case URL_IS_HTTP:
00203 case URL_IS_FTP:
00204 case URL_IS_HKP:
00205 case URL_IS_DASH:
00206 default:
00207
00208 fd = (pid != 0) ? fdDup(fdno) : Fopen(fn, "r.ufdio");
00209 (void) close(fdno);
00210 if (fd == NULL || Ferror(fd)) {
00211 rc = 1;
00212 if (fd != NULL)
00213 (void) Fclose(fd);
00214 break;
00215 }
00216
00217 fdInitDigest(fd, PGPHASHALGO_MD5, 0);
00218 fsize = 0;
00219 while ((rc = Fread(buf, sizeof(buf[0]), sizeof(buf), fd)) > 0)
00220 fsize += rc;
00221 fdFiniDigest(fd, PGPHASHALGO_MD5, (void **)&md5sum, &md5len, asAscii);
00222 if (Ferror(fd))
00223 rc = 1;
00224
00225 (void) Fclose(fd);
00226 break;
00227 }
00228
00229
00230 if (pid) {
00231 int status;
00232 (void) waitpid(pid, &status, 0);
00233 if (!WIFEXITED(status) || WEXITSTATUS(status))
00234 rc = 1;
00235 }
00236
00237 exit:
00238
00239 if (fsizep)
00240 *fsizep = fsize;
00241 if (!rc)
00242 memcpy(digest, md5sum, md5len);
00243
00244 md5sum = _free(md5sum);
00245
00246 return rc;
00247 }
00248
00249
00250
00251 int _noDirTokens = 0;
00252
00253
00254
00255 static int dncmp(const void * a, const void * b)
00256
00257 {
00258 const char *const * first = a;
00259 const char *const * second = b;
00260 return strcmp(*first, *second);
00261 }
00262
00263
00264
00265 void compressFilelist(Header h)
00266 {
00267 HGE_t hge = (HGE_t)headerGetEntryMinMemory;
00268 HAE_t hae = (HAE_t)headerAddEntry;
00269 HRE_t hre = (HRE_t)headerRemoveEntry;
00270 HFD_t hfd = headerFreeData;
00271 char ** fileNames;
00272 const char ** dirNames;
00273 const char ** baseNames;
00274 int_32 * dirIndexes;
00275 rpmTagType fnt;
00276 int count;
00277 int i, xx;
00278 int dirIndex = -1;
00279
00280
00281
00282
00283
00284
00285
00286 if (headerIsEntry(h, RPMTAG_DIRNAMES)) {
00287 xx = hre(h, RPMTAG_OLDFILENAMES);
00288 return;
00289 }
00290
00291 if (!hge(h, RPMTAG_OLDFILENAMES, &fnt, (void **) &fileNames, &count))
00292 return;
00293 if (fileNames == NULL || count <= 0)
00294 return;
00295
00296 dirNames = alloca(sizeof(*dirNames) * count);
00297 baseNames = alloca(sizeof(*dirNames) * count);
00298 dirIndexes = alloca(sizeof(*dirIndexes) * count);
00299
00300 if (fileNames[0][0] != '/') {
00301
00302 dirIndex = 0;
00303 dirNames[dirIndex] = "";
00304 for (i = 0; i < count; i++) {
00305 dirIndexes[i] = dirIndex;
00306 baseNames[i] = fileNames[i];
00307 }
00308 goto exit;
00309 }
00310
00311
00312 for (i = 0; i < count; i++) {
00313 const char ** needle;
00314 char savechar;
00315 char * baseName;
00316 int len;
00317
00318 if (fileNames[i] == NULL)
00319 continue;
00320 baseName = strrchr(fileNames[i], '/') + 1;
00321 len = baseName - fileNames[i];
00322 needle = dirNames;
00323 savechar = *baseName;
00324 *baseName = '\0';
00325
00326 if (dirIndex < 0 ||
00327 (needle = bsearch(&fileNames[i], dirNames, dirIndex + 1, sizeof(dirNames[0]), dncmp)) == NULL) {
00328 char *s = alloca(len + 1);
00329 memcpy(s, fileNames[i], len + 1);
00330 s[len] = '\0';
00331 dirIndexes[i] = ++dirIndex;
00332 dirNames[dirIndex] = s;
00333 } else
00334 dirIndexes[i] = needle - dirNames;
00335
00336
00337 *baseName = savechar;
00338 baseNames[i] = baseName;
00339 }
00340
00341
00342 exit:
00343 if (count > 0) {
00344 xx = hae(h, RPMTAG_DIRINDEXES, RPM_INT32_TYPE, dirIndexes, count);
00345 xx = hae(h, RPMTAG_BASENAMES, RPM_STRING_ARRAY_TYPE,
00346 baseNames, count);
00347 xx = hae(h, RPMTAG_DIRNAMES, RPM_STRING_ARRAY_TYPE,
00348 dirNames, dirIndex + 1);
00349 }
00350
00351 fileNames = hfd(fileNames, fnt);
00352
00353 xx = hre(h, RPMTAG_OLDFILENAMES);
00354 }
00355
00356
00357 void rpmfiBuildFNames(Header h, rpmTag tagN,
00358 const char *** fnp, int * fcp)
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 rpmTag dirNameTag = 0;
00369 rpmTag dirIndexesTag = 0;
00370 rpmTagType bnt, dnt;
00371 char * t;
00372 int i, xx;
00373
00374 if (tagN == RPMTAG_BASENAMES) {
00375 dirNameTag = RPMTAG_DIRNAMES;
00376 dirIndexesTag = RPMTAG_DIRINDEXES;
00377 } else if (tagN == RPMTAG_ORIGBASENAMES) {
00378 dirNameTag = RPMTAG_ORIGDIRNAMES;
00379 dirIndexesTag = RPMTAG_ORIGDIRINDEXES;
00380 }
00381
00382 if (!hge(h, tagN, &bnt, (void **) &baseNames, &count)) {
00383 if (fnp) *fnp = NULL;
00384 if (fcp) *fcp = 0;
00385 return;
00386 }
00387
00388 xx = hge(h, dirNameTag, &dnt, (void **) &dirNames, NULL);
00389 xx = hge(h, dirIndexesTag, NULL, (void **) &dirIndexes, &count);
00390
00391 size = sizeof(*fileNames) * count;
00392 for (i = 0; i < count; i++)
00393 size += strlen(baseNames[i]) + strlen(dirNames[dirIndexes[i]]) + 1;
00394
00395 fileNames = xmalloc(size);
00396 t = ((char *) fileNames) + (sizeof(*fileNames) * count);
00397
00398 for (i = 0; i < count; i++) {
00399 fileNames[i] = t;
00400 t = stpcpy( stpcpy(t, dirNames[dirIndexes[i]]), baseNames[i]);
00401 *t++ = '\0';
00402 }
00403
00404 baseNames = hfd(baseNames, bnt);
00405 dirNames = hfd(dirNames, dnt);
00406
00407
00408 if (fnp)
00409 *fnp = fileNames;
00410 else
00411 fileNames = _free(fileNames);
00412
00413 if (fcp) *fcp = count;
00414 }
00415
00416 void expandFilelist(Header h)
00417 {
00418 HAE_t hae = (HAE_t)headerAddEntry;
00419 HRE_t hre = (HRE_t)headerRemoveEntry;
00420 const char ** fileNames = NULL;
00421 int count = 0;
00422 int xx;
00423
00424
00425 if (!headerIsEntry(h, RPMTAG_OLDFILENAMES)) {
00426 rpmfiBuildFNames(h, RPMTAG_BASENAMES, &fileNames, &count);
00427 if (fileNames == NULL || count <= 0)
00428 return;
00429 xx = hae(h, RPMTAG_OLDFILENAMES, RPM_STRING_ARRAY_TYPE,
00430 fileNames, count);
00431 fileNames = _free(fileNames);
00432 }
00433
00434
00435 xx = hre(h, RPMTAG_DIRNAMES);
00436 xx = hre(h, RPMTAG_BASENAMES);
00437 xx = hre(h, RPMTAG_DIRINDEXES);
00438 }
00439
00440
00441
00442
00443
00444 void providePackageNVR(Header h)
00445 {
00446 HGE_t hge = (HGE_t)headerGetEntryMinMemory;
00447 HFD_t hfd = headerFreeData;
00448 const char *name, *version, *release;
00449 int_32 * epoch;
00450 const char *pEVR;
00451 char *p;
00452 int_32 pFlags = RPMSENSE_EQUAL;
00453 const char ** provides = NULL;
00454 const char ** providesEVR = NULL;
00455 rpmTagType pnt, pvt;
00456 int_32 * provideFlags = NULL;
00457 int providesCount;
00458 int i, xx;
00459 int bingo = 1;
00460
00461
00462 xx = headerNVR(h, &name, &version, &release);
00463 if (!(name && version && release))
00464 return;
00465 pEVR = p = alloca(21 + strlen(version) + 1 + strlen(release) + 1);
00466 *p = '\0';
00467 if (hge(h, RPMTAG_EPOCH, NULL, (void **) &epoch, NULL)) {
00468 sprintf(p, "%d:", *epoch);
00469 while (*p != '\0')
00470 p++;
00471 }
00472 (void) stpcpy( stpcpy( stpcpy(p, version) , "-") , release);
00473
00474
00475
00476
00477
00478 if (!hge(h, RPMTAG_PROVIDENAME, &pnt, (void **) &provides, &providesCount))
00479 goto exit;
00480
00481
00482
00483
00484 if (!hge(h, RPMTAG_PROVIDEVERSION, &pvt, (void **) &providesEVR, NULL)) {
00485 for (i = 0; i < providesCount; i++) {
00486 char * vdummy = "";
00487 int_32 fdummy = RPMSENSE_ANY;
00488 xx = headerAddOrAppendEntry(h, RPMTAG_PROVIDEVERSION, RPM_STRING_ARRAY_TYPE,
00489 &vdummy, 1);
00490 xx = headerAddOrAppendEntry(h, RPMTAG_PROVIDEFLAGS, RPM_INT32_TYPE,
00491 &fdummy, 1);
00492 }
00493 goto exit;
00494 }
00495
00496 xx = hge(h, RPMTAG_PROVIDEFLAGS, NULL, (void **) &provideFlags, NULL);
00497
00498
00499 if (provides && providesEVR && provideFlags)
00500 for (i = 0; i < providesCount; i++) {
00501 if (!(provides[i] && providesEVR[i]))
00502 continue;
00503 if (!(provideFlags[i] == RPMSENSE_EQUAL &&
00504 !strcmp(name, provides[i]) && !strcmp(pEVR, providesEVR[i])))
00505 continue;
00506 bingo = 0;
00507 break;
00508 }
00509
00510
00511 exit:
00512 provides = hfd(provides, pnt);
00513 providesEVR = hfd(providesEVR, pvt);
00514
00515 if (bingo) {
00516 xx = headerAddOrAppendEntry(h, RPMTAG_PROVIDENAME, RPM_STRING_ARRAY_TYPE,
00517 &name, 1);
00518 xx = headerAddOrAppendEntry(h, RPMTAG_PROVIDEFLAGS, RPM_INT32_TYPE,
00519 &pFlags, 1);
00520 xx = headerAddOrAppendEntry(h, RPMTAG_PROVIDEVERSION, RPM_STRING_ARRAY_TYPE,
00521 &pEVR, 1);
00522 }
00523 }
00524
00525 void legacyRetrofit(Header h, const struct rpmlead * lead)
00526 {
00527 const char * prefix;
00528
00529
00530
00531
00532
00533
00534 if (headerIsEntry(h, RPMTAG_FILEUSERNAME))
00535 (void) headerRemoveEntry(h, RPMTAG_FILEUIDS);
00536 if (headerIsEntry(h, RPMTAG_FILEGROUPNAME))
00537 (void) headerRemoveEntry(h, RPMTAG_FILEGIDS);
00538
00539
00540
00541
00542
00543
00544
00545
00546 if (headerGetEntry(h, RPMTAG_DEFAULTPREFIX, NULL, (void **) &prefix, NULL))
00547 {
00548 const char * nprefix = stripTrailingChar(alloca_strdup(prefix), '/');
00549 (void) headerAddEntry(h, RPMTAG_PREFIXES, RPM_STRING_ARRAY_TYPE,
00550 &nprefix, 1);
00551 }
00552
00553
00554
00555
00556
00557
00558
00559
00560 if (lead->major < 4)
00561 compressFilelist(h);
00562
00563
00564 if (lead->type == RPMLEAD_SOURCE) {
00565 int_32 one = 1;
00566 if (!headerIsEntry(h, RPMTAG_SOURCEPACKAGE))
00567 (void) headerAddEntry(h, RPMTAG_SOURCEPACKAGE, RPM_INT32_TYPE,
00568 &one, 1);
00569 } else if (lead->major < 4) {
00570
00571 providePackageNVR(h);
00572 }
00573 }