return r;
}
+static int pakfire_build_find_elf_provides(
+ struct pakfire_ctx* ctx, struct pakfire_file* file, struct pakfire_find_deps_ctx* deps) {
+ struct pakfire_elf* elf = NULL;
+ char** provides = NULL;
+ int r;
+
+ // Skip files that are not executable
+ if (!pakfire_file_is_executable(file))
+ return 0;
+
+ // Only handle .so files
+ if (!pakfire_file_matches(file, "**.so") && !pakfire_file_matches(file, "**.so.*"))
+ return 0;
+
+ // Try to open the ELF file
+ r = pakfire_elf_open_file(&elf, ctx, file);
+ if (r < 0) {
+ switch (-r) {
+ // This does not seem to be an ELF file
+ case ENOTSUP:
+ return 0;
+
+ // Raise any other errors
+ default:
+ goto ERROR;
+ }
+ }
+
+ // Fetch all provides
+ r = pakfire_elf_provides(elf, &provides);
+ if (r < 0)
+ goto ERROR;
+
+ // Add them all to the package
+ if (provides) {
+ for (char** p = provides; *p; p++) {
+ r = pakfire_package_add_dep(deps->pkg, PAKFIRE_PKG_PROVIDES, "%s", *p);
+ if (r < 0)
+ goto ERROR;
+ }
+ }
+
+ERROR:
+ if (provides)
+ pakfire_strings_free(provides);
+ if (elf)
+ pakfire_elf_unref(elf);
+
+ return r;
+}
+
static int pakfire_build_find_elf_requires(
struct pakfire_ctx* ctx, struct pakfire_file* file, struct pakfire_find_deps_ctx* deps) {
struct pakfire_elf* elf = NULL;
else if (pakfire_path_match("**.pc", path))
return pakfire_build_find_pkgconfig_provides(ctx, file, deps);
-#if 0
// Split certain file types differently
switch (pakfire_file_get_type(file)) {
// Regular files
return r;
break;
}
-#endif
return 0;
}
return 1;
}
+static int pakfire_elf_find_provides(struct pakfire_elf* self,
+ Elf_Scn* section, const GElf_Shdr* shdr, void* data) {
+ GElf_Verdaux verdaux = {};
+ GElf_Verdef verdef = {};
+ const char* version = NULL;
+ const char* base = NULL;
+ char*** provides = data;
+ int r;
+
+ // Fetch the section data
+ Elf_Data* d = elf_getdata(section, NULL);
+
+ size_t offset = 0;
+
+ while (offset < shdr->sh_size) {
+ if (!gelf_getverdef(d, offset, &verdef))
+ break;
+
+ size_t aux_offset = offset + verdef.vd_aux;
+
+ for (int i = 0; i < verdef.vd_cnt; i++) {
+ if (!gelf_getverdaux(d, aux_offset, &verdaux))
+ break;
+
+ // Fetch the version string
+ version = elf_strptr(self->elf, shdr->sh_link, verdaux.vda_name);
+
+ // Skip empty versions
+ if (!version || !*version)
+ continue;
+
+ // Is this the base?
+ if (verdef.vd_flags & VER_FLG_BASE) {
+ base = version;
+ break;
+ }
+
+ // Add it to the list
+ r = pakfire_strings_appendf(provides, "%s(%s)%s",
+ base, version, pakfire_elf_is_elf64(self) ? "(64bit)" : "");
+ if (r < 0)
+ return r;
+
+ if (!verdaux.vda_next)
+ break;
+
+ aux_offset += verdaux.vda_next;
+ }
+
+ if (!verdef.vd_next)
+ break;
+
+ offset += verdef.vd_next;
+ }
+
+ return 0;
+}
+
+int pakfire_elf_provides(struct pakfire_elf* self, char*** provides) {
+ int r;
+
+ // Fetch the soname
+ const char* soname = pakfire_elf_soname(self);
+ if (soname) {
+ r = pakfire_strings_appendf(provides,
+ "%s()%s", soname, pakfire_elf_is_elf64(self) ? "(64bit)" : "");
+ if (r < 0)
+ return r;
+ }
+
+ return pakfire_elf_foreach_section(self, SHT_GNU_verdef, pakfire_elf_find_provides, provides);
+}
+
static int pakfire_elf_find_requires(struct pakfire_elf* self,
Elf_Scn* section, const GElf_Shdr* shdr, void* data) {
- GElf_Verneed verneed = {};
GElf_Vernaux vernaux = {};
+ GElf_Verneed verneed = {};
const char* version = NULL;
const char* name = NULL;
char*** requires = data;