--- rpm-5.4.5/lib/rpmds.c.16004~ 2012-02-24 14:13:37.649093023 +0100 +++ rpm-5.4.5/lib/rpmds.c 2012-02-24 14:13:40.677094532 +0100 @@ -2901,7 +2901,234 @@ rpmds rpmdsFromPRCO(rpmPRCO PRCO, rpmTag * @param isElf64 is this an ELF64 symbol? */ #if defined(HAVE_GELF_H) && defined(HAVE_LIBELF) && !defined(__FreeBSD__) -static char * sonameDep(/*@returned@*/ char * t, const char * s, int isElf64) +#if defined(RPM_VENDOR_MANDRIVA) +static char * sonameDep(/*@returned@*/ char * t, const char * s, int isElf64, int devel, int uClibc) + /*@modifies t @*/ +{ + char *tmp = t; + *t = '\0'; + if (uClibc) + tmp = stpcpy(tmp, "uClibc("); + if (devel) { + tmp = stpcpy(tmp, "devel("); + } +#if !defined(__alpha__) && !defined(__sun) + if (!isElf64) { + /* XXX: eehhk, would've been nice with consistency, mandriva legacy... :| */ + if (!devel && s[strlen(s)-1] != ')') + (void) stpcpy( stpcpy(tmp, s), "()(64bit)"); + else { + tmp = stpcpy(tmp, s); + if (devel) + tmp = strstr(t, ".so"); + tmp = stpcpy(tmp, "(64bit)"); + } + }else +#endif + tmp = stpcpy(tmp, s); + if (devel) { + char *suffix = strstr(t, ".so"); + if (suffix) + tmp = suffix; + tmp = stpcpy(tmp, ")"); + } + if (uClibc) + tmp = stpcpy(tmp, ")"); + + return t; +} + +static char *find_elf_interpreter(GElf_Ehdr *ehdr, Elf *elf, char *filename) +{ + FILE *fp = NULL; + struct stat statbuf; + GElf_Ehdr ehdr_mem; + GElf_Shdr shdr_mem, *shdr; + GElf_Phdr phdr_mem, *phdr; + GElf_Dyn dyn_mem, *dyn; + Elf_Data * data; + Elf_Scn *scn = NULL; + int fdno; + char *interp_name = NULL; + char *libpath = NULL; + int cnt; + int class; + size_t shstrndx; + + if (filename) { + if (!(fp = fopen(filename, "r"))) { + perror(filename); + return NULL; + } + if (fstat((fdno = fileno(fp)), &statbuf) < 0) { + perror(filename); + goto end; + } + if ((size_t) statbuf.st_size < sizeof(Elf64_Ehdr) || !S_ISREG(statbuf.st_mode)) + goto foo; + + (void) elf_version(EV_CURRENT); + elf = NULL; + if ((elf = elf_begin (fdno, ELF_C_READ, NULL)) == NULL + || elf_kind(elf) != ELF_K_ELF + || (ehdr = gelf_getehdr(elf, &ehdr_mem)) == NULL + || !(ehdr->e_type == ET_DYN || ehdr->e_type == ET_EXEC)) + goto end; + } +foo: + + if (ehdr->e_type != ET_EXEC && ehdr->e_type != ET_DYN) { + fprintf(stderr, "%s: not a dynamic executable\n", filename); + goto end; + } + class = gelf_getclass(elf); + + for (cnt = 0; cnt < ehdr->e_phnum; cnt++) { + phdr = gelf_getphdr (elf, cnt, &phdr_mem); + if (phdr->p_type == PT_INTERP) + break; + phdr = NULL; + } + if (phdr) { + Elf_Data *data = NULL; + + scn = gelf_offscn (elf, phdr->p_offset); + shdr = gelf_getshdr(scn, &shdr_mem); + data = elf_getdata (scn, data); + interp_name = strdup(data->d_buf); + goto end; + } + + if (elf_getshdrstrndx (elf, &shstrndx) >= 0) + while ((scn = elf_nextscn(elf, scn)) != NULL) { + shdr = gelf_getshdr(scn, &shdr_mem); + if (shdr->sh_type == SHT_DYNAMIC) { + char *rpath = NULL; + for (cnt = 0; cnt < ehdr->e_phnum; cnt++) { + phdr = gelf_getphdr (elf, cnt, &phdr_mem); + if (phdr->p_type == PT_LOAD) + break; + } + + data = NULL; + while ((data = elf_getdata (scn, data)) != NULL) { + int dynsize = (int)(shdr->sh_size / shdr->sh_entsize)-1; + for (cnt = 0; cnt <= dynsize; ++cnt) { + dyn = gelf_getdyn (data, cnt, &dyn_mem); + + if (rpath == NULL) { + if (dyn->d_tag == DT_RPATH) + rpath = elf_strptr (elf, shdr->sh_link, dyn->d_un.d_val); + else if (cnt == dynsize) + rpath = ""; + if (rpath != NULL) + cnt = -1; + continue; + } + else if (rpath && DT_NEEDED == dyn->d_tag) { + char *tmp, *tmp2; + char buf[1024]; + char path[1024] = ""; + + libpath = elf_strptr (elf, shdr->sh_link, dyn->d_un.d_val); + + if (!libpath || !strlen(libpath)) + continue; + + tmp = libpath; + while (*tmp) { + if (*tmp == '/') + libpath = tmp + 1; + tmp++; + } + + /* If this is a fully resolved name, we don't need to modify the path */ + if (stat(libpath, &statbuf) == 0) + continue; + + tmp2 = path; + if (rpath && *rpath) { + tmp2 = stpcpy(tmp2, rpath); + tmp2 = stpcpy(tmp2, ":"); + } + tmp = getenv("LD_LIBRARY_PATH"); + if (tmp) + tmp2 = stpcpy(tmp2, tmp); + if ((rpath && *rpath) || tmp) + tmp2 = stpcpy(tmp2, ":"); + /* XXX: do better check to ensure libraries are all of the same class */ + tmp2 = stpcpy(tmp2, (class == ELFCLASS64) ? "/lib64" : "/lib"); + tmp = buf; + { + int i, count = 1; + char *path_n; + + /* Eliminate all double //s */ + path_n = path; + while ((path_n = strstr(path_n, "//"))) { + i = strlen(path_n); + memmove(path_n, path_n + 1, i - 1); + *(path_n + i - 1) = '\0'; + } + + /* Replace colons with zeros in path_list and count them */ + for (i = strlen(path); i > 0; i--) { + if (path[i] == ':') { + path[i] = 0; + count++; + } + } + path_n = path; + for (i = 0; i < count; i++) { + strcpy(tmp, path_n); + strcat(tmp, "/"); + strcat(tmp, libpath); + if (stat(tmp, &statbuf) == 0 && statbuf.st_mode & S_IRUSR) { + path[0] = '\0'; + break; + } + path_n += (strlen(path_n) + 1); + } + if(path[0]) + *tmp = '\0'; + } + libpath = buf; + } + } + } + break; + } + } + +end: + if (fp) { + if (elf) (void) elf_end(elf); + fclose(fp); + } + if (!interp_name && libpath) + return find_elf_interpreter(NULL, NULL, libpath); + return interp_name; +} + +static int checkuClibc(GElf_Ehdr *ehdr, Elf *elf) { + int ret = 0; + char *interp = find_elf_interpreter(ehdr, elf, NULL); + + if (interp) { + char *tmp = basename(interp); + if (tmp[0] == 'l' && tmp[1] == 'd') { + tmp += ((tmp[2] == '3' && tmp[3] == '2') || + (tmp[2] == '6' && tmp[3] == '4')) ? + 5 : 7; + if (!strncasecmp(tmp, "uClibc.so", sizeof("uClibc.so")-1)) + ret = 1; + } + free(interp); + } + return ret; +} +#else +static char * sonameDep(/*@returned@*/ char * t, const char * s, int isElf64, int devel, int uClibc) /*@modifies t @*/ { *t = '\0'; @@ -2917,6 +3144,7 @@ static char * sonameDep(/*@returned@*/ c return t; } #endif +#endif /*@-moduncon -noeffectuncon @*/ int rpmdsELF(const char * fn, int flags, @@ -2945,6 +3173,7 @@ int rpmdsELF(const char * fn, int flags, int xx; int isElf64; int isDSO; + int isuClibc; int gotSONAME = 0; int gotDEBUG = 0; int gotHASH = 0; @@ -2987,6 +3216,11 @@ fprintf(stderr, "*** rpmdsELF(%s, %d, %p isElf64 = ehdr->e_ident[EI_CLASS] == ELFCLASS64; isDSO = ehdr->e_type == ET_DYN; +#if defined(RPM_VENDOR_MANDRIVA) + isuClibc = checkuClibc(ehdr, elf); +#else + isuClibc = 0; +#endif /*@-uniondef @*/ scn = NULL; @@ -3085,7 +3319,7 @@ fprintf(stderr, "*** rpmdsELF(%s, %d, %p /* Add next provide dependency. */ ds = rpmdsSingle(RPMTAG_PROVIDES, - sonameDep(t, buf, isElf64), + sonameDep(t, buf, isElf64, 0, isuClibc), "", RPMSENSE_FIND_PROVIDES); xx = add(context, ds); (void)rpmdsFree(ds); @@ -3138,7 +3372,7 @@ fprintf(stderr, "*** rpmdsELF(%s, %d, %p /* Add next require dependency. */ ds = rpmdsSingle(RPMTAG_REQUIRENAME, - sonameDep(t, buf, isElf64), + sonameDep(t, buf, isElf64, 0, isuClibc), "", RPMSENSE_FIND_REQUIRES); xx = add(context, ds); (void)rpmdsFree(ds); @@ -3180,7 +3414,7 @@ fprintf(stderr, "*** rpmdsELF(%s, %d, %p assert(s != NULL); buf[0] = '\0'; ds = rpmdsSingle(RPMTAG_REQUIRENAME, - sonameDep(buf, s, isElf64), + sonameDep(buf, s, isElf64, 0, isuClibc), "", RPMSENSE_FIND_REQUIRES); xx = add(context, ds); (void)rpmdsFree(ds); @@ -3195,7 +3429,7 @@ assert(s != NULL); /* Add next provide dependency. */ buf[0] = '\0'; ds = rpmdsSingle(RPMTAG_PROVIDENAME, - sonameDep(buf, s, isElf64), + sonameDep(buf, s, isElf64, 0, isuClibc), "", RPMSENSE_FIND_PROVIDES); xx = add(context, ds); (void)rpmdsFree(ds); @@ -3231,7 +3465,7 @@ assert(s != NULL); /* Add next provide dependency. */ buf[0] = '\0'; ds = rpmdsSingle(RPMTAG_PROVIDENAME, - sonameDep(buf, s, isElf64), "", RPMSENSE_FIND_PROVIDES); + sonameDep(buf, s, isElf64, 0, isuClibc), "", RPMSENSE_FIND_PROVIDES); xx = add(context, ds); (void)rpmdsFree(ds); ds = NULL; @@ -3251,46 +3485,6 @@ exit: #if defined(RPM_VENDOR_MANDRIVA) -/** - * Return a soname dependency constructed from an elf string, Mandriva-style. - * @retval t soname dependency - * @param s elf string (NULL uses "") - * @param isElf64 is this an ELF64 symbol? - */ -#if defined(HAVE_GELF_H) && defined(HAVE_LIBELF) && !defined(__FreeBSD__) -static char * mdvSonameDep(/*@returned@*/ char * t, const char * s, int isElf64, int devel) - /*@modifies t @*/ -{ - char *tmp = t; - *t = '\0'; - if (devel) { - tmp = stpcpy(t, "devel("); - } -#if !defined(__alpha__) && !defined(__sun) - if (!isElf64) { - /* XXX: eehhk, would've been nice with consistency, mandriva legacy... :| */ - if (!devel && s[strlen(s)-1] != ')') - (void) stpcpy( stpcpy(tmp, s), "()(64bit)"); - else { - tmp = stpcpy(tmp, s); - if (devel) - tmp = strstr(t, ".so"); - tmp = stpcpy(tmp, "(64bit)"); - } - }else -#endif - tmp = stpcpy(tmp, s); - if (devel) { - char *suffix = strstr(t, ".so"); - if (suffix) - tmp = suffix; - tmp = stpcpy(tmp, ")"); - } - - return t; -} -#endif - /** \ingroup rpmds * Extract dependencies from a symlink. * XXX Prototype added to keep GCC quiet and avoid adding a symbol. @@ -3324,6 +3518,7 @@ int rpmdsSymlink(const char * fn, int fl rpmds ds; int xx; int isElf64; + int isuClibc; int gotSONAME = 0; int skipP = (flags & RPMELF_FLAG_SKIPPROVIDES); int skipR = (flags & RPMELF_FLAG_SKIPREQUIRES); @@ -3378,6 +3573,11 @@ fprintf(stderr, "*** rpmdsELF(%s, %d, %p /*@=evalorder@*/ isElf64 = ehdr->e_ident[EI_CLASS] == ELFCLASS64; +#if defined(RPM_VENDOR_MANDRIVA) + isuClibc = checkuClibc(ehdr, elf); +#else + isuClibc = 0; +#endif /*@-uniondef @*/ scn = NULL; @@ -3413,7 +3613,7 @@ assert(s != NULL); buf[0] = '\0'; for (i = 0; i < (int)(sizeof(filterRequires)/sizeof(filterRequires[0])); i++) - if (!strncmp(s, filterRequires[i], strlen(filterRequires[i]))) + if (!strncmp(s, filterRequires[i], strlen(filterRequires[i])) && !isuClibc) break; if (sizeof(filterRequires)/sizeof(filterRequires[0]) == i) @@ -3428,7 +3628,7 @@ assert(s != NULL); if (!skipP) { ds = rpmdsSingle(RPMTAG_PROVIDENAME, - mdvSonameDep(buf, s, isElf64, 1), + sonameDep(buf, s, isElf64, 1, isuClibc), "", RPMSENSE_FIND_PROVIDES); xx = add(context, ds); (void)rpmdsFree(ds); @@ -3447,7 +3647,7 @@ exit: if (gotSONAME && !skipR) for (i = 0, cnt = argvCount(deps); i < cnt; i++) { ds = rpmdsSingle(RPMTAG_REQUIRENAME, - mdvSonameDep(buf, deps[i], isElf64, 1), + sonameDep(buf, deps[i], isElf64, 1, isuClibc), "", RPMSENSE_FIND_REQUIRES); xx = add(context, ds); (void)rpmdsFree(ds);