ad7d96cbe094e749a7568bbbbc271a48b6eba3ff
[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         }
47         return c;
48 }
49
50 void free_checker (struct checker * c)
51 {
52         if (!c)
53                 return;
54         c->refcount--;
55         if (c->refcount) {
56                 condlog(3, "%s checker refcount %d",
57                         c->name, c->refcount);
58                 return;
59         }
60         condlog(3, "unloading %s checker", c->name);
61         list_del(&c->node);
62         if (c->handle) {
63                 if (dlclose(c->handle) != 0) {
64                         condlog(0, "Cannot unload checker %s: %s",
65                                 c->name, dlerror());
66                 }
67         }
68         FREE(c);
69 }
70
71 void cleanup_checkers (void)
72 {
73         struct checker * checker_loop;
74         struct checker * checker_temp;
75
76         list_for_each_entry_safe(checker_loop, checker_temp, &checkers, node) {
77                 free_checker(checker_loop);
78         }
79 }
80
81 struct checker * checker_lookup (char * name)
82 {
83         struct checker * c;
84
85         if (!name || !strlen(name))
86                 return NULL;
87         list_for_each_entry(c, &checkers, node) {
88                 if (!strncmp(name, c->name, CHECKER_NAME_LEN))
89                         return c;
90         }
91         return NULL;
92 }
93
94 struct checker * add_checker (char *multipath_dir, char * name)
95 {
96         char libname[LIB_CHECKER_NAMELEN];
97         struct stat stbuf;
98         struct checker * c;
99         char *errstr;
100
101         c = alloc_checker();
102         if (!c)
103                 return NULL;
104         snprintf(c->name, CHECKER_NAME_LEN, "%s", name);
105         snprintf(libname, LIB_CHECKER_NAMELEN, "%s/libcheck%s.so",
106                  multipath_dir, name);
107         if (stat(libname,&stbuf) < 0) {
108                 condlog(0,"Checker '%s' not found in %s",
109                         name, multipath_dir);
110                 goto out;
111         }
112         condlog(3, "loading %s checker", libname);
113         c->handle = dlopen(libname, RTLD_NOW);
114         if (!c->handle) {
115                 if ((errstr = dlerror()) != NULL)
116                         condlog(0, "A dynamic linking error occurred: (%s)",
117                                 errstr);
118                 goto out;
119         }
120         c->check = (int (*)(struct checker *)) dlsym(c->handle, "libcheck_check");
121         errstr = dlerror();
122         if (errstr != NULL)
123                 condlog(0, "A dynamic linking error occurred: (%s)", errstr);
124         if (!c->check)
125                 goto out;
126
127         c->init = (int (*)(struct checker *)) dlsym(c->handle, "libcheck_init");
128         errstr = dlerror();
129         if (errstr != NULL)
130                 condlog(0, "A dynamic linking error occurred: (%s)", errstr);
131         if (!c->init)
132                 goto out;
133
134         c->free = (void (*)(struct checker *)) dlsym(c->handle, "libcheck_free");
135         errstr = dlerror();
136         if (errstr != NULL)
137                 condlog(0, "A dynamic linking error occurred: (%s)", errstr);
138         if (!c->free)
139                 goto out;
140
141         c->fd = 0;
142         c->sync = 1;
143         list_add(&c->node, &checkers);
144         return c;
145 out:
146         free_checker(c);
147         return NULL;
148 }
149
150 void checker_set_fd (struct checker * c, int fd)
151 {
152         if (!c)
153                 return;
154         c->fd = fd;
155 }
156
157 void checker_set_sync (struct checker * c)
158 {
159         if (!c)
160                 return;
161         c->sync = 1;
162 }
163
164 void checker_set_async (struct checker * c)
165 {
166         if (!c)
167                 return;
168         c->sync = 0;
169 }
170
171 void checker_enable (struct checker * c)
172 {
173         if (!c)
174                 return;
175         c->disable = 0;
176 }
177
178 void checker_disable (struct checker * c)
179 {
180         if (!c)
181                 return;
182         c->disable = 1;
183 }
184
185 int checker_init (struct checker * c, void ** mpctxt_addr)
186 {
187         if (!c)
188                 return 1;
189         c->mpcontext = mpctxt_addr;
190         return c->init(c);
191 }
192
193 void checker_put (struct checker * dst)
194 {
195         struct checker * src;
196
197         if (!dst || !dst->check)
198                 return;
199         src = checker_lookup(dst->name);
200         if (dst->free)
201                 dst->free(dst);
202         memset(dst, 0x0, sizeof(struct checker));
203         free_checker(src);
204 }
205
206 int checker_check (struct checker * c)
207 {
208         int r;
209
210         if (!c)
211                 return PATH_WILD;
212
213         c->message[0] = '\0';
214         if (c->disable) {
215                 MSG(c, "checker disabled");
216                 return PATH_UNCHECKED;
217         }
218         if (c->fd <= 0) {
219                 MSG(c, "no usable fd");
220                 return PATH_WILD;
221         }
222         r = c->check(c);
223
224         return r;
225 }
226
227 int checker_selected (struct checker * c)
228 {
229         if (!c)
230                 return 0;
231         return (c->check) ? 1 : 0;
232 }
233
234 char * checker_name (struct checker * c)
235 {
236         if (!c)
237                 return NULL;
238         return c->name;
239 }
240
241 char * checker_message (struct checker * c)
242 {
243         if (!c)
244                 return NULL;
245         return c->message;
246 }
247
248 void checker_clear_message (struct checker *c)
249 {
250         if (!c)
251                 return;
252         c->message[0] = '\0';
253 }
254
255 void checker_get (char *multipath_dir, struct checker * dst, char * name)
256 {
257         struct checker * src = NULL;
258
259         if (!dst)
260                 return;
261
262         if (name && strlen(name)) {
263                 src = checker_lookup(name);
264                 if (!src)
265                         src = add_checker(multipath_dir, name);
266         }
267         if (!src) {
268                 dst->check = NULL;
269                 return;
270         }
271         dst->fd = src->fd;
272         dst->sync = src->sync;
273         strncpy(dst->name, src->name, CHECKER_NAME_LEN);
274         strncpy(dst->message, src->message, CHECKER_MSG_LEN);
275         dst->check = src->check;
276         dst->init = src->init;
277         dst->free = src->free;
278         dst->handle = NULL;
279         src->refcount++;
280 }