1 |
|
/* Dynamic loading of store class modules |
2 |
|
Copyright (C) 2002 Free Software Foundation, Inc. |
3 |
|
|
4 |
|
This file is part of the GNU Hurd. |
5 |
|
|
6 |
|
The GNU Hurd is free software; you can redistribute it and/or |
7 |
|
modify it under the terms of the GNU General Public License as |
8 |
|
published by the Free Software Foundation; either version 2, or (at |
9 |
|
your option) any later version. |
10 |
|
|
11 |
|
The GNU Hurd is distributed in the hope that it will be useful, but |
12 |
|
WITHOUT ANY WARRANTY; without even the implied warranty of |
13 |
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
14 |
|
General Public License for more details. |
15 |
|
|
16 |
|
You should have received a copy of the GNU General Public License |
17 |
|
along with this program; if not, write to the Free Software |
18 |
|
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. */ |
19 |
|
|
20 |
|
#include "store.h" |
21 |
|
#include <dlfcn.h> |
22 |
|
#include <stdio.h> |
23 |
|
#include <stdlib.h> |
24 |
|
#include <string.h> |
25 |
|
#include <error.h> /* XXX */ |
26 |
|
|
27 |
|
static error_t |
28 |
|
open_class (int need_open, |
29 |
|
const char *name, const char *clname_end, |
30 |
|
const struct store_class **classp) |
31 |
|
{ |
32 |
|
char *modname, *clsym; |
33 |
|
void *mod; |
34 |
|
|
35 |
|
/* Construct the name of the shared object for this module. */ |
36 |
|
if (asprintf (&modname, |
37 |
|
"libstore_%.*s%s", clname_end - name, name, |
38 |
|
STORE_SONAME_SUFFIX) < 0) |
39 |
|
return ENOMEM; |
40 |
|
|
41 |
|
/* Now try to load the module. |
42 |
|
|
43 |
|
Note we never dlclose the module, and add a ref every time we open it |
44 |
|
anew. We can't dlclose it until no stores of this class exist, so |
45 |
|
we'd need a creation/deletion hook for that. */ |
46 |
|
|
47 |
|
errno = 0; |
48 |
|
mod = dlopen (modname, RTLD_LAZY); |
49 |
|
if (mod == NULL) |
50 |
|
{ |
51 |
|
const char *errstring = dlerror (); /* Must always call or it leaks! */ |
52 |
|
if (errno != ENOENT) |
53 |
|
/* XXX not good, but how else to report the error? */ |
54 |
|
error (0, 0, "cannot load %s: %s", modname, errstring); |
55 |
|
} |
56 |
|
free (modname); |
57 |
|
if (mod == NULL) |
58 |
|
return errno ?: ENOENT; |
59 |
|
|
60 |
|
if (asprintf (&clsym, "store_%.*s_class", clname_end - name, name) < 0) |
61 |
|
{ |
62 |
|
dlclose (mod); |
63 |
|
return ENOMEM; |
64 |
|
} |
65 |
|
|
66 |
|
*classp = dlsym (mod, clsym); |
67 |
|
free (clsym); |
68 |
|
if (*classp == NULL) |
69 |
|
{ |
70 |
|
error (0, 0, "invalid store module %.*s: %s", |
71 |
|
clname_end - name, name, dlerror ()); |
72 |
|
dlclose (mod); |
73 |
|
return EGRATUITOUS; |
74 |
|
} |
75 |
|
|
76 |
|
if (need_open && ! (*classp)->open) |
77 |
|
{ |
78 |
|
/* This class cannot be opened as needed. */ |
79 |
|
dlclose (mod); |
80 |
|
return EOPNOTSUPP; |
81 |
|
} |
82 |
|
|
83 |
|
return 0; |
84 |
|
} |
85 |
|
|
86 |
|
error_t |
87 |
|
store_module_find_class (const char *name, const char *clname_end, |
88 |
|
const struct store_class **classp) |
89 |
|
{ |
90 |
|
return open_class (0, name, clname_end, classp); |
91 |
|
} |
92 |
|
|
93 |
|
error_t |
94 |
|
store_module_open (const char *name, int flags, |
95 |
|
const struct store_class *const *classes, |
96 |
|
struct store **store) |
97 |
|
{ |
98 |
|
const struct store_class *cl; |
99 |
|
const char *clname_end = strchr (name, ':'); |
100 |
|
error_t err; |
101 |
|
|
102 |
|
if (! clname_end) |
103 |
|
return EINVAL; |
104 |
|
|
105 |
|
err = open_class (1, name, clname_end, &cl); |
106 |
|
if (err) |
107 |
|
return err; |
108 |
|
|
109 |
|
if (*clname_end) |
110 |
|
/* Skip the ':' separating the class-name from the device name. */ |
111 |
|
clname_end++; |
112 |
|
|
113 |
|
if (! *clname_end) |
114 |
|
/* The class-specific portion of the name is empty, so make it *really* |
115 |
|
empty. */ |
116 |
|
clname_end = 0; |
117 |
|
|
118 |
|
return (*cl->open) (clname_end, flags, classes, store); |
119 |
|
} |
120 |
|
|
121 |
|
const struct store_class store_module_open_class = |
122 |
|
{ -1, "module", open: store_module_open }; |
123 |
|
STORE_STD_CLASS (module_open); |
124 |
|
|
125 |
|
error_t |
126 |
|
store_module_decode (struct store_enc *enc, |
127 |
|
const struct store_class *const *classes, |
128 |
|
struct store **store) |
129 |
|
{ |
130 |
|
char *modname; |
131 |
|
void *mod; |
132 |
|
const struct store_class *const *cl, *const *clend; |
133 |
|
enum file_storage_class id; |
134 |
|
|
135 |
|
if (enc->cur_int >= enc->num_ints) |
136 |
|
/* The first int should always be the type. */ |
137 |
|
return EINVAL; |
138 |
|
|
139 |
|
id = enc->ints[enc->cur_int]; |
140 |
|
|
141 |
|
/* Construct the name of the shared object for this module. */ |
142 |
|
if (asprintf (&modname, "libstore_type-%d%s", id, STORE_SONAME_SUFFIX) < 0) |
143 |
|
return ENOMEM; |
144 |
|
|
145 |
|
/* Try to open the module. */ |
146 |
|
mod = dlopen (modname, RTLD_LAZY); |
147 |
|
free (modname); |
148 |
|
if (mod == NULL) |
149 |
|
{ |
150 |
|
(void) dlerror (); /* otherwise it leaks */ |
151 |
|
return ENOENT; |
152 |
|
} |
153 |
|
|
154 |
|
/* Now find its "store_std_classes" section, which points to each |
155 |
|
`struct store_class' defined in this module. */ |
156 |
|
cl = dlsym (mod, "__start_store_std_classes"); |
157 |
|
if (cl == NULL) |
158 |
|
{ |
159 |
|
error (0, 0, "invalid store module type-%d: %s", id, dlerror ()); |
160 |
|
dlclose (mod); |
161 |
|
return EGRATUITOUS; |
162 |
|
} |
163 |
|
clend = dlsym (mod, "__stop_store_std_classes"); |
164 |
|
if (clend == NULL) |
165 |
|
{ |
166 |
|
error (0, 0, "invalid store module type-%d: %s", id, dlerror ()); |
167 |
|
dlclose (mod); |
168 |
|
return EGRATUITOUS; |
169 |
|
} |
170 |
|
|
171 |
|
while (cl < clend) |
172 |
|
if ((*cl)->decode && (*cl)->id == id) |
173 |
|
return (*(*cl)->decode) (enc, classes, store); |
174 |
|
else |
175 |
|
++cl; |
176 |
|
|
177 |
|
/* This class cannot be opened via store_decode. */ |
178 |
|
dlclose (mod); |
179 |
|
return EOPNOTSUPP; |
180 |
|
} |