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
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
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
00064
00065 fdno = open(path, O_RDONLY);
00066 if (fdno < 0)
00067 return fdno;
00068
00069
00070 if (!(cmd && *cmd))
00071 return fdno;
00072
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
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 continue;
00105 bingo = 1;
00106 break;
00107 }
00108 }
00109 }
00110
00111
00112
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
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
00164 fdno = open_dso(path, &pid, &fsize);
00165
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 }
00197 #endif
00198 case URL_IS_FTP:
00199 case URL_IS_HTTP:
00200 case URL_IS_DASH:
00201 default:
00202
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
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
00234 if (fsizep)
00235 *fsizep = fsize;
00236 if (!rc)
00237 memcpy(digest, md5sum, md5len);
00238
00239 md5sum = _free(md5sum);
00240
00241 return rc;
00242 }
00243
00244
00245
00246 int _noDirTokens = 0;
00247
00248
00249
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
00258
00259
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
00277
00278
00279
00280
00281 if (headerIsEntry(h, RPMTAG_DIRNAMES)) {
00282 xx = hre(h, RPMTAG_OLDFILENAMES);
00283 return;
00284 }
00285
00286 if (!hge(h, RPMTAG_OLDFILENAMES, &fnt, (void **) &fileNames, &count))
00287 return;
00288 if (fileNames == NULL || count <= 0)
00289 return;
00290
00291 dirNames = alloca(sizeof(*dirNames) * count);
00292 baseNames = alloca(sizeof(*dirNames) * count);
00293 dirIndexes = alloca(sizeof(*dirIndexes) * count);
00294
00295 if (fileNames[0][0] != '/') {
00296
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
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)
00314 continue;
00315 baseName = strrchr(fileNames[i], '/') + 1;
00316 len = baseName - fileNames[i];
00317 needle = dirNames;
00318 savechar = *baseName;
00319 *baseName = '\0';
00320
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
00331
00332 *baseName = savechar;
00333 baseNames[i] = baseName;
00334 }
00335
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
00351
00352
00353
00354
00355
00356 static void doBuildFileList(Header h, const char *** fileListPtr,
00357 int * fileCountPtr, rpmTag baseNameTag,
00358 rpmTag dirNameTag, rpmTag dirIndexesTag)
00359
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;
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
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
00395 baseNames = hfd(baseNames, bnt);
00396 dirNames = hfd(dirNames, dnt);
00397
00398
00399 if (fileListPtr)
00400 *fileListPtr = fileNames;
00401 else
00402 fileNames = _free(fileNames);
00403
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
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
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
00447
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
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
00481
00482
00483 if (!hge(h, RPMTAG_PROVIDENAME, &pnt, (void **) &provides, &providesCount))
00484 goto exit;
00485
00486
00487
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
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
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
00536
00537
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
00546
00547
00548
00549
00550
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
00558
00559
00560
00561
00562
00563
00564
00565 if (lead->major < 4)
00566 compressFilelist(h);
00567
00568
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
00576 providePackageNVR(h);
00577 }
00578 }