This introduces constructor and destructor for struct elf_file,
following the grab/release naming pattern used elsewhere. Care is
taken to ensure the constructor returns a valid errno on failure.

The first user is grab_module() in depmod.c

Signed-off-by: Andreas Robinson <[email protected]>
---
 depmod.c |   42 +++++------------------------
 depmod.h |    2 +-
 elfops.c |   87 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 elfops.h |    6 ++++
 tables.c |   19 ++++++-------
 5 files changed, 111 insertions(+), 45 deletions(-)

diff --git a/depmod.c b/depmod.c
index a7bd948..e636659 100644
--- a/depmod.c
+++ b/depmod.c
@@ -264,7 +264,6 @@ static int ends_in(const char *name, const char *ext)
 static struct module *grab_module(const char *dirname, const char *filename)
 {
        struct module *new;
-       struct elf_file *file;
 
        new = NOFAIL(malloc(sizeof(*new)
                            + strlen(dirname?:"") + 1 + strlen(filename) + 1));
@@ -277,39 +276,14 @@ static struct module *grab_module(const char *dirname, 
const char *filename)
        INIT_LIST_HEAD(&new->dep_list);
        new->order = INDEX_PRIORITY_MIN;
 
-       file = &new->file;
-
-       file->data = grab_file(new->pathname, &file->len);
-       if (!file->data) {
+       new->file = grab_elf_file(new->pathname);
+       if (!new->file) {
                warn("Can't read module %s: %s\n",
                     new->pathname, strerror(errno));
-               goto fail_data;
+               free(new);
+               return NULL;
        }
-
-       switch (elf_ident(file->data, file->len, &file->conv)) {
-       case ELFCLASS32:
-               file->ops = &mod_ops32;
-               break;
-       case ELFCLASS64:
-               file->ops = &mod_ops64;
-               break;
-       case -ENOEXEC:
-               warn("Module %s is not an elf object\n", new->pathname);
-               goto fail;
-       case -EINVAL:
-               warn("Module %s has unknown endianness\n", new->pathname);
-               goto fail;
-       default:
-               warn("Module %s has unknown word size\n", new->pathname);
-               goto fail;
-       }
        return new;
-
-fail:
-       release_file(file->data, new->file.len);
-fail_data:
-       free(new);
-       return NULL;
 }
 
 struct module_traverse
@@ -680,7 +654,7 @@ static void calculate_deps(struct module *module)
 
        module->num_deps = 0;
        module->deps = NULL;
-       file = &module->file;
+       file = module->file;
 
        symnames = file->ops->load_dep_syms(module->pathname, file, &symtypes);
        if (!symnames || !symtypes)
@@ -714,7 +688,7 @@ static struct module *parse_modules(struct module *list)
        int j;
 
        for (i = list; i; i = i->next) {
-               file = &i->file;
+               file = i->file;
                syms = file->ops->load_symbols(file);
                if (syms) {
                        for (j = 0; j < syms->cnt; j++)
@@ -803,7 +777,7 @@ static void output_aliases(struct module *modules, FILE 
*out, char *dirname)
        for (i = modules; i; i = i->next) {
                char modname[strlen(i->pathname)+1];
 
-               file = &i->file;
+               file = i->file;
                filename2modname(modname, i->pathname);
 
                /* Grab from old-style .modalias section. */
@@ -838,7 +812,7 @@ static void output_aliases_bin(struct module *modules, FILE 
*out, char *dirname)
        for (i = modules; i; i = i->next) {
                char modname[strlen(i->pathname)+1];
 
-               file = &i->file;
+               file = i->file;
                filename2modname(modname, i->pathname);
 
                /* Grab from old-style .modalias section. */
diff --git a/depmod.h b/depmod.h
index be06b7c..d6d61f6 100644
--- a/depmod.h
+++ b/depmod.h
@@ -23,7 +23,7 @@ struct module
        /* Tables extracted from module by ops->fetch_tables(). */
        struct module_tables tables;
 
-       struct elf_file file;
+       struct elf_file *file;
 
        char *basename; /* points into pathname */
        char pathname[0];
diff --git a/elfops.c b/elfops.c
index 9ae77ef..ac33c96 100644
--- a/elfops.c
+++ b/elfops.c
@@ -5,11 +5,15 @@
 #include <stdlib.h>
 #include <string.h>
 #include <errno.h>
+#include <fcntl.h>
 #include "depmod.h"
 #include "util.h"
 #include "logging.h"
 #include "elfops.h"
 #include "tables.h"
+#include "zlibsupport.h"
+
+#include "testing.h"
 
 /* Symbol types, returned by load_dep_syms */
 static const char *weak_sym = "W";
@@ -55,3 +59,86 @@ void *get_section(void *file, unsigned long filesize,
                return NULL;
        }
 }
+
+/*
+ * grab_elf_file - read ELF file into memory
+ * @pathame: file to load
+ *
+ * Returns NULL, and errno set on error.
+ */
+struct elf_file *grab_elf_file(const char *pathname)
+{
+       int fd;
+       int err;
+       struct elf_file *file;
+
+       fd = open(pathname, O_RDONLY, 0);
+       if (fd < 0)
+               return NULL;
+       file = grab_elf_file_fd(pathname, fd);
+
+       err = errno;
+       close(fd);
+       errno = err;
+       return file;
+}
+
+/*
+ * grab_elf_file_fd - read ELF file from file descriptor into memory
+ * @pathame: name of file to load
+ * @fd: file descriptor of file to load
+ *
+ * Returns NULL, and errno set on error.
+ */
+struct elf_file *grab_elf_file_fd(const char *pathname, int fd)
+{
+       struct elf_file *file;
+
+       file = malloc(sizeof(*file));
+       if (!file) {
+               errno = ENOMEM;
+               return NULL;
+       }
+       file->pathname = strdup(pathname);
+       if (!file->pathname) {
+               free(file);
+               errno = ENOMEM;
+               return NULL;
+       }
+       file->data = grab_fd(fd, &file->len);
+       if (!file->data)
+               goto fail;
+
+       switch (elf_ident(file->data, file->len, &file->conv)) {
+       case ELFCLASS32:
+               file->ops = &mod_ops32;
+               break;
+       case ELFCLASS64:
+               file->ops = &mod_ops64;
+               break;
+       case -ENOEXEC: /* Not an ELF object */
+       case -EINVAL: /* Unknown endianness */
+       default: /* Unknown word size */
+               errno = ENOEXEC;
+               goto fail;
+       }
+       return file;
+fail:
+       release_elf_file(file);
+       return NULL;
+}
+
+void release_elf_file(struct elf_file *file)
+{
+       int err = errno;
+
+       if (!file)
+               return;
+
+       release_file(file->data, file->len);
+       free(file->pathname);
+       free(file);
+
+       errno = err;
+}
+
diff --git a/elfops.h b/elfops.h
index 24ebc07..dffd9f5 100644
--- a/elfops.h
+++ b/elfops.h
@@ -16,6 +16,8 @@ struct kernel_symbol64 {
 
 struct elf_file
 {
+       char *pathname;
+
        /* File operations */
        struct module_ops *ops;
 
@@ -75,4 +77,8 @@ void *get_section32(void *file, unsigned long filesize,
 void *get_section64(void *file, unsigned long filesize,
        const char *secname, unsigned long *secsize, int conv);
 
+struct elf_file *grab_elf_file(const char *pathname);
+struct elf_file *grab_elf_file_fd(const char *pathname, int fd);
+void release_elf_file(struct elf_file *file);
+
 #endif /* MODINITTOOLS_MODULEOPS_H */
diff --git a/tables.c b/tables.c
index ecbf030..2f44450 100644
--- a/tables.c
+++ b/tables.c
@@ -51,7 +51,7 @@ void output_pci_table(struct module *modules, FILE *out, char 
*dirname)
 
                make_shortname(shortname, i->pathname);
                for (e = t->pci_table; e->vendor; e = (void *)e + t->pci_size)
-                       output_pci_entry(e, shortname, out, i->file.conv);
+                       output_pci_entry(e, shortname, out, i->file->conv);
        }
 }
 
@@ -102,7 +102,7 @@ void output_usb_table(struct module *modules, FILE *out, 
char *dirname)
                for (e = t->usb_table;
                     e->idVendor || e->bDeviceClass || e->bInterfaceClass;
                     e = (void *)e + t->usb_size)
-                       output_usb_entry(e, shortname, out, i->file.conv);
+                       output_usb_entry(e, shortname, out, i->file->conv);
        }
 }
 
@@ -136,7 +136,7 @@ void output_ieee1394_table(struct module *modules, FILE 
*out, char *dirname)
                make_shortname(shortname, i->pathname);
                for (fw = t->ieee1394_table; fw->match_flags;
                     fw = (void *) fw + t->ieee1394_size)
-                       output_ieee1394_entry(fw, shortname, out, i->file.conv);
+                       output_ieee1394_entry(fw, shortname, out, 
i->file->conv);
        }
 }
 
@@ -170,7 +170,7 @@ void output_ccw_table(struct module *modules, FILE *out, 
char *dirname)
                for (e = t->ccw_table;
                     e->cu_type || e->cu_model || e->dev_type || e->dev_model;
                     e = (void *) e + t->ccw_size)
-                       output_ccw_entry(e, shortname, out, i->file.conv);
+                       output_ccw_entry(e, shortname, out, i->file->conv);
        }
 }
 
@@ -425,6 +425,7 @@ void output_input_table(struct module *modules, FILE *out, 
char *dirname)
                char shortname[strlen(i->pathname) + 1];
                int done = 0;
                struct module_tables *t = &i->tables;
+               int conv = i->file->conv;
 
                if (!t->input_table)
                        continue;
@@ -449,22 +450,20 @@ void output_input_table(struct module *modules, FILE 
*out, char *dirname)
                        case sizeof(struct input_device_id_old_64):
                                done = output_input_entry_64_old(p,
                                                                 shortname,
-                                                                out,
-                                                                i->file.conv);
+                                                                out, conv);
                                break;
                        case sizeof(struct input_device_id_64):
                                done = output_input_entry_64(p, shortname,
-                                                            out, i->file.conv);
+                                                            out, conv);
                                break;
                        case sizeof(struct input_device_id_old_32):
                                done = output_input_entry_32_old(p,
                                                                 shortname,
-                                                                out,
-                                                                i->file.conv);
+                                                                out, conv);
                                break;
                        case sizeof(struct input_device_id_32):
                                done = output_input_entry_32(p, shortname,
-                                                            out, i->file.conv);
+                                                            out, conv);
                                break;
                        }
                }                               
-- 
1.6.0.4

--
To unsubscribe from this list: send the line "unsubscribe linux-modules" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to