Imported Upstream version 0.7.0
[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
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->repair = (void (*)(struct checker *)) dlsym(c->handle,
142                                                        "libcheck_repair");
143         errstr = dlerror();
144         if (errstr != NULL)
145                 condlog(0, "A dynamic linking error occurred: (%s)", errstr);
146         if (!c->repair)
147                 goto out;
148
149         c->fd = 0;
150         c->sync = 1;
151         list_add(&c->node, &checkers);
152         return c;
153 out:
154         free_checker(c);
155         return NULL;
156 }
157
158 void checker_set_fd (struct checker * c, int fd)
159 {
160         if (!c)
161                 return;
162         c->fd = fd;
163 }
164
165 void checker_set_sync (struct checker * c)
166 {
167         if (!c)
168                 return;
169         c->sync = 1;
170 }
171
172 void checker_set_async (struct checker * c)
173 {
174         if (!c)
175                 return;
176         c->sync = 0;
177 }
178
179 void checker_enable (struct checker * c)
180 {
181         if (!c)
182                 return;
183         c->disable = 0;
184 }
185
186 void checker_disable (struct checker * c)
187 {
188         if (!c)
189                 return;
190         c->disable = 1;
191 }
192
193 int checker_init (struct checker * c, void ** mpctxt_addr)
194 {
195         if (!c)
196                 return 1;
197         c->mpcontext = mpctxt_addr;
198         return c->init(c);
199 }
200
201 void checker_put (struct checker * dst)
202 {
203         struct checker * src;
204
205         if (!dst || !dst->check)
206                 return;
207         src = checker_lookup(dst->name);
208         if (dst->free)
209                 dst->free(dst);
210         memset(dst, 0x0, sizeof(struct checker));
211         free_checker(src);
212 }
213
214 void checker_repair (struct checker * c)
215 {
216         if (!checker_selected(c))
217                 return;
218
219         c->message[0] = '\0';
220         if (c->disable) {
221                 MSG(c, "checker disabled");
222                 return;
223         }
224
225         c->repair(c);
226 }
227
228 int checker_check (struct checker * c)
229 {
230         int r;
231
232         if (!c)
233                 return PATH_WILD;
234
235         c->message[0] = '\0';
236         if (c->disable) {
237                 MSG(c, "checker disabled");
238                 return PATH_UNCHECKED;
239         }
240         if (c->fd <= 0) {
241                 MSG(c, "no usable fd");
242                 return PATH_WILD;
243         }
244         r = c->check(c);
245
246         return r;
247 }
248
249 int checker_selected (struct checker * c)
250 {
251         if (!c)
252                 return 0;
253         return (c->check) ? 1 : 0;
254 }
255
256 char * checker_name (struct checker * c)
257 {
258         if (!c)
259                 return NULL;
260         return c->name;
261 }
262
263 char * checker_message (struct checker * c)
264 {
265         if (!c)
266                 return NULL;
267         return c->message;
268 }
269
270 void checker_clear_message (struct checker *c)
271 {
272         if (!c)
273                 return;
274         c->message[0] = '\0';
275 }
276
277 void checker_get (char *multipath_dir, struct checker * dst, char * name)
278 {
279         struct checker * src = NULL;
280
281         if (!dst)
282                 return;
283
284         if (name && strlen(name)) {
285                 src = checker_lookup(name);
286                 if (!src)
287                         src = add_checker(multipath_dir, name);
288         }
289         if (!src) {
290                 dst->check = NULL;
291                 return;
292         }
293         dst->fd = src->fd;
294         dst->sync = src->sync;
295         strncpy(dst->name, src->name, CHECKER_NAME_LEN);
296         strncpy(dst->message, src->message, CHECKER_MSG_LEN);
297         dst->repair = src->repair;
298         dst->check = src->check;
299         dst->init = src->init;
300         dst->free = src->free;
301         dst->handle = NULL;
302         src->refcount++;
303 }