]> git.ipfire.org Git - people/ric9/pakfire.git/commitdiff
ELF: Fetch provided dependencies
authorMichael Tremer <michael.tremer@ipfire.org>
Fri, 3 Jan 2025 17:27:05 +0000 (17:27 +0000)
committerMichael Tremer <michael.tremer@ipfire.org>
Fri, 3 Jan 2025 17:27:05 +0000 (17:27 +0000)
Signed-off-by: Michael Tremer <michael.tremer@ipfire.org>
src/pakfire/build.c
src/pakfire/elf.c
src/pakfire/elf.h

index d07c5e9dfc2c6d9cc6591b00ad2d4bae39dee221..c7bfa22ef4c3d28ee9bcb8f2311bf0a58ba43b10 100644 (file)
@@ -584,6 +584,57 @@ ERROR:
        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;
@@ -682,7 +733,6 @@ static int pakfire_build_find_provides(
        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
@@ -693,7 +743,6 @@ static int pakfire_build_find_provides(
                                return r;
                        break;
        }
-#endif
 
        return 0;
 }
index 8f4670815ddb2b3bc3d9f1fec799aec117697f1e..101b1e3f06f693372a875e4a78cc4c9eb075ffe8 100644 (file)
@@ -945,10 +945,83 @@ int pakfire_elf_is_stripped(struct pakfire_elf* self) {
        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;
index d6f3ef99e83c558ff224f808f8cf97601738fd36..170698f59a78579e60be7570ab70fe4b570e02a4 100644 (file)
@@ -65,6 +65,7 @@ enum {
 };
 
 // Dependencies
+int pakfire_elf_provides(struct pakfire_elf* self, char*** provides);
 int pakfire_elf_requires(struct pakfire_elf* self, char*** requires);
 
 // Source Files