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, pid_t * pidp, size_t *fsizep)
00040
00041
00042 {
00043
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
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
00063
00064 fdno = open(path, O_RDONLY);
00065 if (fdno < 0)
00066 return fdno;
00067
00068
00069 if (!(cmd && *cmd))
00070 return fdno;
00071
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
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 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 }
00196 #endif
00197 case URL_IS_FTP:
00198 case URL_IS_HTTP:
00199 case URL_IS_DASH:
00200 default:
00201
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
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
00233 if (fsizep)
00234 *fsizep = fsize;
00235 if (!rc)
00236 memcpy(digest, md5sum, md5len);
00237
00238 md5sum = _free(md5sum);
00239
00240 return rc;
00241 }
00242
00243
00244
00245 int _noDirTokens = 0;
00246
00247
00248
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
00257
00258
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
00276
00277
00278
00279
00280 if (headerIsEntry(h, RPMTAG_DIRNAMES)) {
00281 xx = hre(h, RPMTAG_OLDFILENAMES);
00282 return;
00283 }
00284
00285 if (!hge(h, RPMTAG_OLDFILENAMES, &fnt, (void **) &fileNames, &count))
00286 return;
00287 if (fileNames == NULL || count <= 0)
00288 return;
00289
00290 dirNames = alloca(sizeof(*dirNames) * count);
00291 baseNames = alloca(sizeof(*dirNames) * count);
00292 dirIndexes = alloca(sizeof(*dirIndexes) * count);
00293
00294 if (fileNames[0][0] != '/') {
00295
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
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)
00313 continue;
00314 baseName = strrchr(fileNames[i], '/') + 1;
00315 len = baseName - fileNames[i];
00316 needle = dirNames;
00317 savechar = *baseName;
00318 *baseName = '\0';
00319
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
00330
00331 *baseName = savechar;
00332 baseNames[i] = baseName;
00333 }
00334
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
00350
00351
00352
00353
00354
00355 static void doBuildFileList(Header h, const char *** fileListPtr,
00356 int * fileCountPtr, rpmTag baseNameTag,
00357 rpmTag dirNameTag, rpmTag dirIndexesTag)
00358
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;
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
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
00394 baseNames = hfd(baseNames, bnt);
00395 dirNames = hfd(dirNames, dnt);
00396
00397
00398 if (fileListPtr)
00399 *fileListPtr = fileNames;
00400 else
00401 fileNames = _free(fileNames);
00402
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
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
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
00446
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
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
00480
00481
00482 if (!hge(h, RPMTAG_PROVIDENAME, &pnt, (void **) &provides, &providesCount))
00483 goto exit;
00484
00485
00486
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
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
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
00535
00536
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
00545
00546
00547
00548
00549
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
00557
00558
00559
00560
00561
00562
00563
00564 if (lead->major < 4)
00565 compressFilelist(h);
00566
00567
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
00575 providePackageNVR(h);
00576 }
00577 }