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