multipathd: fix reservation_key check
[multipath-tools/.git] / libmultipath / checkers.c
1 #include <stdio.h>
2 #include <string.h>
3 #include <stddef.h>
4 #include <dlfcn.h>
5 #include <sys/stat.h>
6
7 #include "debug.h"
8 #include "checkers.h"
9 #include "vector.h"
10
11 char *checker_state_names[] = {
12         "wild",
13         "unchecked",
14         "down",
15         "up",
16         "shaky",
17         "ghost",
18         "pending",
19         "timeout",
20         "removed",
21         "delayed",
22 };
23
24 static LIST_HEAD(checkers);
25
26 char * checker_state_name (int i)
27 {
28         return checker_state_names[i];
29 }
30
31 int init_checkers (char *multipath_dir)
32 {
33         if (!add_checker(multipath_dir, DEFAULT_CHECKER))
34                 return 1;
35         return 0;
36 }
37
38 struct checker * alloc_checker (void)
39 {
40         struct checker *c;
41
42         c = MALLOC(sizeof(struct checker));
43         if (c) {
44                 INIT_LIST_HEAD(&c->node);
45                 c->refcount = 1;
46                 c->fd = -1;
47         }
48         return c;
49 }
50
51 void free_checker (struct checker * c)
52 {
53         if (!c)
54                 return;
55         c->refcount--;
56         if (c->refcount) {
57                 condlog(3, "%s checker refcount %d",
58                         c->name, c->refcount);
59                 return;
60         }
61         condlog(3, "unloading %s checker", c->name);
62         list_del(&c->node);
63         if (c->handle) {
64                 if (dlclose(c->handle) != 0) {
65                         condlog(0, "Cannot unload checker %s: %s",
66                                 c->name, dlerror());
67                 }
68         }
69         FREE(c);
70 }
71
72 void cleanup_checkers (void)
73 {
74         struct checker * checker_loop;
75         struct checker * checker_temp;
76
77         list_for_each_entry_safe(checker_loop, checker_temp, &checkers, node) {
78                 free_checker(checker_loop);
79         }
80 }
81
82 struct checker * checker_lookup (char * name)
83 {
84         struct checker * c;
85
86         if (!name || !strlen(name))
87                 return NULL;
88         list_for_each_entry(c, &checkers, node) {
89                 if (!strncmp(name, c->name, CHECKER_NAME_LEN))
90                         return c;
91         }
92         return NULL;
93 }
94
95 struct checker * add_checker (char *multipath_dir, char * name)
96 {
97         char libname[LIB_CHECKER_NAMELEN];
98         struct stat stbuf;
99         struct checker * c;
100         char *errstr;
101
102         c = alloc_checker();
103         if (!c)
104                 return NULL;
105         snprintf(c->name, CHECKER_NAME_LEN, "%s", name);
106         if (!strncmp(c->name, NONE, 4))
107                 goto done;
108         snprintf(libname, LIB_CHECKER_NAMELEN, "%s/libcheck%s.so",
109                  multipath_dir, name);
110         if (stat(libname,&stbuf) < 0) {
111                 condlog(0,"Checker '%s' not found in %s",
112                         name, multipath_dir);
113                 goto out;
114         }
115         condlog(3, "loading %s checker", libname);
116         c->handle = dlopen(libname, RTLD_NOW);
117         if (!c->handle) {
118                 if ((errstr = dlerror()) != NULL)
119                         condlog(0, "A dynamic linking error occurred: (%s)",
120                                 errstr);
121                 goto out;
122         }
123         c->check = (int (*)(struct checker *)) dlsym(c->handle, "libcheck_check");
124         errstr = dlerror();
125         if (errstr != NULL)
126                 condlog(0, "A dynamic linking error occurred: (%s)", errstr);
127         if (!c->check)
128                 goto out;
129
130         c->init = (int (*)(struct checker *)) dlsym(c->handle, "libcheck_init");
131         errstr = dlerror();
132         if (errstr != NULL)
133                 condlog(0, "A dynamic linking error occurred: (%s)", errstr);
134         if (!c->init)
135                 goto out;
136
137         c->free = (void (*)(struct checker *)) dlsym(c->handle, "libcheck_free");
138         errstr = dlerror();
139         if (errstr != NULL)
140                 condlog(0, "A dynamic linking error occurred: (%s)", errstr);
141         if (!c->free)
142                 goto out;
143
144         c->repair = (void (*)(struct checker *)) dlsym(c->handle,
145                                                        "libcheck_repair");
146         errstr = dlerror();
147         if (errstr != NULL)
148                 condlog(0, "A dynamic linking error occurred: (%s)", errstr);
149         if (!c->repair)
150                 goto out;
151 done:
152         c->fd = -1;
153         c->sync = 1;
154         list_add(&c->node, &checkers);
155         return c;
156 out:
157         free_checker(c);
158         return NULL;
159 }
160
161 void checker_set_fd (struct checker * c, int fd)
162 {
163         if (!c)
164                 return;
165         c->fd = fd;
166 }
167
168 void checker_set_sync (struct checker * c)
169 {
170         if (!c)
171                 return;
172         c->sync = 1;
173 }
174
175 void checker_set_async (struct checker * c)
176 {
177         if (!c)
178                 return;
179         c->sync = 0;
180 }
181
182 void checker_enable (struct checker * c)
183 {
184         if (!c)
185                 return;
186         c->disable = 0;
187 }
188
189 void checker_disable (struct checker * c)
190 {
191         if (!c)
192                 return;
193         c->disable = 1;
194 }
195
196 int checker_init (struct checker * c, void ** mpctxt_addr)
197 {
198         if (!c)
199                 return 1;
200         c->mpcontext = mpctxt_addr;
201         if (c->init)
202                 return c->init(c);
203         return 0;
204 }
205
206 void checker_clear (struct checker *c)
207 {
208         memset(c, 0x0, sizeof(struct checker));
209         c->fd = -1;
210 }
211
212 void checker_put (struct checker * dst)
213 {
214         struct checker * src;
215
216         if (!dst || !strlen(dst->name))
217                 return;
218         src = checker_lookup(dst->name);
219         if (dst->free)
220                 dst->free(dst);
221         checker_clear(dst);
222         free_checker(src);
223 }
224
225 void checker_repair (struct checker * c)
226 {
227         if (!checker_selected(c))
228                 return;
229
230         c->message[0] = '\0';
231         if (c->disable) {
232                 MSG(c, "checker disabled");
233                 return;
234         }
235         if (c->repair)
236                 c->repair(c);
237 }
238
239 int checker_check (struct checker * c, int path_state)
240 {
241         int r;
242
243         if (!c)
244                 return PATH_WILD;
245
246         c->message[0] = '\0';
247         if (c->disable) {
248                 MSG(c, "checker disabled");
249                 return PATH_UNCHECKED;
250         }
251         if (!strncmp(c->name, NONE, 4))
252                 return path_state;
253
254         if (c->fd < 0) {
255                 MSG(c, "no usable fd");
256                 return PATH_WILD;
257         }
258         r = c->check(c);
259
260         return r;
261 }
262
263 int checker_selected (struct checker * c)
264 {
265         if (!c)
266                 return 0;
267         if (!strncmp(c->name, NONE, 4))
268                 return 1;
269         return (c->check) ? 1 : 0;
270 }
271
272 char * checker_name (struct checker * c)
273 {
274         if (!c)
275                 return NULL;
276         return c->name;
277 }
278
279 char * checker_message (struct checker * c)
280 {
281         if (!c)
282                 return NULL;
283         return c->message;
284 }
285
286 void checker_clear_message (struct checker *c)
287 {
288         if (!c)
289                 return;
290         c->message[0] = '\0';
291 }
292
293 void checker_get (char *multipath_dir, struct checker * dst, char * name)
294 {
295         struct checker * src = NULL;
296
297         if (!dst)
298                 return;
299
300         if (name && strlen(name)) {
301                 src = checker_lookup(name);
302                 if (!src)
303                         src = add_checker(multipath_dir, name);
304         }
305         if (!src) {
306                 dst->check = NULL;
307                 return;
308         }
309         dst->fd = src->fd;
310         dst->sync = src->sync;
311         strncpy(dst->name, src->name, CHECKER_NAME_LEN);
312         strncpy(dst->message, src->message, CHECKER_MSG_LEN);
313         dst->repair = src->repair;
314         dst->check = src->check;
315         dst->init = src->init;
316         dst->free = src->free;
317         dst->handle = NULL;
318         src->refcount++;
319 }