diff options
author | Roland McGrath <roland@gnu.org> | 2002-03-14 21:09:49 +0000 |
---|---|---|
committer | Roland McGrath <roland@gnu.org> | 2002-03-14 21:09:49 +0000 |
commit | 00079039055aa37c6e372a76e2872aaeca12adfc (patch) | |
tree | 20100a73e02ad9389186d913c28620eda174bd85 /libstore | |
parent | 0976f65ddb35075a7fb824413506675da1cd2070 (diff) |
2002-03-11 Roland McGrath <roland@frob.com>
* Makefile (module-CPPFLAGS): New variable.
* module.c (STORE_SONAME_SUFFIX): Macro removed.
2002-02-08 Roland McGrath <roland@frob.com>
* Makefile (store-types): New variable.
(all): Depend on $(store-types:%=libstore_%.a).
(libstore_%.so.$(hurd-version)): New pattern rule.
($(store-types:%=libstore_%.a): libstore_%.a): New static pattern rule
to create `-lstore_TYPE' pseudo-objects (linker scripts) for each type.
(libstore.so-LDLIBS): New variable, adds -ldl.
(GUNZIP_OBJS, BUNZIP2_OBJS): New variables.
(UNZIP_OBJS): Variable removed, replaced by those two.
(OBJS): Update use.
(libstore_gunzip.so.$(hurd-version)): Depend on PIC $(GUNZIP_OBJS).
(libstore_bunzip2.so.$(hurd-version)): Depend on PIC $(BUNZIP2_OBJS).
* unknown.c: Add STORE_STD_CLASS decl.
* bunzip2.c: Likewise.
* copy.c: Likewise.
* device.c: Likewise.
* file.c: Likewise.
* gunzip.c: Likewise.
* memobj.c: Likewise.
* module.c: Likewise.
* mvol.c: Likewise.
* nbd.c: Likewise.
* open.c: Likewise.
* part.c: Likewise.
* remap.c: Likewise.
* stripe.c: Likewise.
* stripe.c: Likewise.
* task.c: Likewise.
* typed.c: Likewise.
* typed.c: Likewise.
* unknown.c: Likewise.
* url.c: Likewise.
* zero.c: Likewise.
2001-12-28 Roland McGrath <roland@frob.com>
* module.c: New file.
* store.h (store_module_open, store_module_find_class,
store_module_decode): Declare them.
* argp.c (parse_opt): Leave PARSED->classes null here instead
of defaulting to store_std_classes.
(find_class): Default null class-list parameter to store_std_classes
here instead. If no matches when defaulted, try calling
store_module_open_class too.
* typed.c (store_typed_open): If no match when search list is
store_std_classes, try calling store_module_open_class too.
* url.c (find_url_class): Likewise.
* decode.c (store_decode): If no match when search list is
store_std_classes, try calling store_module_decode too.
Diffstat (limited to 'libstore')
-rw-r--r-- | libstore/module.c | 180 |
1 files changed, 180 insertions, 0 deletions
diff --git a/libstore/module.c b/libstore/module.c new file mode 100644 index 00000000..c127e6cb --- /dev/null +++ b/libstore/module.c @@ -0,0 +1,180 @@ +/* Dynamic loading of store class modules + Copyright (C) 2002 Free Software Foundation, Inc. + + This file is part of the GNU Hurd. + + The GNU Hurd is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2, or (at + your option) any later version. + + The GNU Hurd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. */ + +#include "store.h" +#include <dlfcn.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <error.h> /* XXX */ + +static error_t +open_class (int need_open, + const char *name, const char *clname_end, + const struct store_class **classp) +{ + char *modname, *clsym; + void *mod; + + /* Construct the name of the shared object for this module. */ + if (asprintf (&modname, + "libstore_%.*s%s", clname_end - name, name, + STORE_SONAME_SUFFIX) < 0) + return ENOMEM; + + /* Now try to load the module. + + Note we never dlclose the module, and add a ref every time we open it + anew. We can't dlclose it until no stores of this class exist, so + we'd need a creation/deletion hook for that. */ + + errno = 0; + mod = dlopen (modname, RTLD_LAZY); + if (mod == NULL) + { + const char *errstring = dlerror (); /* Must always call or it leaks! */ + if (errno != ENOENT) + /* XXX not good, but how else to report the error? */ + error (0, 0, "cannot load %s: %s", modname, errstring); + } + free (modname); + if (mod == NULL) + return errno ?: ENOENT; + + if (asprintf (&clsym, "store_%.*s_class", clname_end - name, name) < 0) + { + dlclose (mod); + return ENOMEM; + } + + *classp = dlsym (mod, clsym); + free (clsym); + if (*classp == NULL) + { + error (0, 0, "invalid store module %.*s: %s", + clname_end - name, name, dlerror ()); + dlclose (mod); + return EGRATUITOUS; + } + + if (need_open && ! (*classp)->open) + { + /* This class cannot be opened as needed. */ + dlclose (mod); + return EOPNOTSUPP; + } + + return 0; +} + +error_t +store_module_find_class (const char *name, const char *clname_end, + const struct store_class **classp) +{ + return open_class (0, name, clname_end, classp); +} + +error_t +store_module_open (const char *name, int flags, + const struct store_class *const *classes, + struct store **store) +{ + const struct store_class *cl; + const char *clname_end = strchr (name, ':'); + error_t err; + + if (! clname_end) + return EINVAL; + + err = open_class (1, name, clname_end, &cl); + if (err) + return err; + + if (*clname_end) + /* Skip the ':' separating the class-name from the device name. */ + clname_end++; + + if (! *clname_end) + /* The class-specific portion of the name is empty, so make it *really* + empty. */ + clname_end = 0; + + return (*cl->open) (clname_end, flags, classes, store); +} + +const struct store_class store_module_open_class = +{ -1, "module", open: store_module_open }; +STORE_STD_CLASS (module_open); + +error_t +store_module_decode (struct store_enc *enc, + const struct store_class *const *classes, + struct store **store) +{ + char *modname; + void *mod; + const struct store_class *const *cl, *const *clend; + enum file_storage_class id; + + if (enc->cur_int >= enc->num_ints) + /* The first int should always be the type. */ + return EINVAL; + + id = enc->ints[enc->cur_int]; + + /* Construct the name of the shared object for this module. */ + if (asprintf (&modname, "libstore_type-%d%s", id, STORE_SONAME_SUFFIX) < 0) + return ENOMEM; + + /* Try to open the module. */ + mod = dlopen (modname, RTLD_LAZY); + free (modname); + if (mod == NULL) + { + (void) dlerror (); /* otherwise it leaks */ + return ENOENT; + } + + /* Now find its "store_std_classes" section, which points to each + `struct store_class' defined in this module. */ + cl = dlsym (mod, "__start_store_std_classes"); + if (cl == NULL) + { + error (0, 0, "invalid store module type-%d: %s", id, dlerror ()); + dlclose (mod); + return EGRATUITOUS; + } + clend = dlsym (mod, "__stop_store_std_classes"); + if (clend == NULL) + { + error (0, 0, "invalid store module type-%d: %s", id, dlerror ()); + dlclose (mod); + return EGRATUITOUS; + } + + while (cl < clend) + if ((*cl)->decode && (*cl)->id == id) + return (*(*cl)->decode) (enc, classes, store); + else + ++cl; + + /* This class cannot be opened via store_decode. */ + dlclose (mod); + return EOPNOTSUPP; +} |