Imported Upstream version 0.6.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 #include "config.h"
11
12 char *checker_state_names[] = {
13       "wild",
14       "unchecked",
15       "down",
16       "up",
17       "shaky",
18       "ghost",
19       "pending",
20       "timeout",
21       "removed",
22       "delayed",
23 };
24
25 static LIST_HEAD(checkers);
26
27 char * checker_state_name (int i)
28 {
29         return checker_state_names[i];
30 }
31
32 int init_checkers (void)
33 {
34         if (!add_checker(DEFAULT_CHECKER))
35                 return 1;
36         return 0;
37 }
38
39 struct checker * alloc_checker (void)
40 {
41         struct checker *c;
42
43         c = MALLOC(sizeof(struct checker));
44         if (c) {
45                 INIT_LIST_HEAD(&c->node);
46                 c->refcount = 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 add_checker(name);
93 }
94
95 struct checker * add_checker (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         snprintf(libname, LIB_CHECKER_NAMELEN, "%s/libcheck%s.so",
107                  conf->multipath_dir, name);
108         if (stat(libname,&stbuf) < 0) {
109                 condlog(0,"Checker '%s' not found in %s",
110                         name, conf->multipath_dir);
111                 goto out;
112         }
113         condlog(3, "loading %s checker", libname);
114         c->handle = dlopen(libname, RTLD_NOW);
115         if (!c->handle) {
116                 if ((errstr = dlerror()) != NULL)
117                         condlog(0, "A dynamic linking error occurred: (%s)",
118                                 errstr);
119                 goto out;
120         }
121         c->check = (int (*)(struct checker *)) dlsym(c->handle, "libcheck_check");
122         errstr = dlerror();
123         if (errstr != NULL)
124                 condlog(0, "A dynamic linking error occurred: (%s)", errstr);
125         if (!c->check)
126                 goto out;
127
128         c->init = (int (*)(struct checker *)) dlsym(c->handle, "libcheck_init");
129         errstr = dlerror();
130         if (errstr != NULL)
131                 condlog(0, "A dynamic linking error occurred: (%s)", errstr);
132         if (!c->init)
133                 goto out;
134
135         c->free = (void (*)(struct checker *)) dlsym(c->handle, "libcheck_free");
136         errstr = dlerror();
137         if (errstr != NULL)
138                 condlog(0, "A dynamic linking error occurred: (%s)", errstr);
139         if (!c->free)
140                 goto out;
141
142         c->fd = 0;
143         c->sync = 1;
144         list_add(&c->node, &checkers);
145         return c;
146 out:
147         free_checker(c);
148         return NULL;
149 }
150
151 void checker_set_fd (struct checker * c, int fd)
152 {
153         if (!c)
154                 return;
155         c->fd = fd;
156 }
157
158 void checker_set_sync (struct checker * c)
159 {
160         if (!c)
161                 return;
162         c->sync = 1;
163 }
164
165 void checker_set_async (struct checker * c)
166 {
167         if (!c)
168                 return;
169         c->sync = 0;
170 }
171
172 void checker_enable (struct checker * c)
173 {
174         if (!c)
175                 return;
176         c->disable = 0;
177 }
178
179 void checker_disable (struct checker * c)
180 {
181         if (!c)
182                 return;
183         c->disable = 1;
184 }
185
186 int checker_init (struct checker * c, void ** mpctxt_addr)
187 {
188         if (!c)
189                 return 1;
190         c->mpcontext = mpctxt_addr;
191         return c->init(c);
192 }
193
194 void checker_put (struct checker * dst)
195 {
196         struct checker * src;
197
198         if (!dst || !dst->check)
199                 return;
200         src = checker_lookup(dst->name);
201         if (dst->free)
202                 dst->free(dst);
203         memset(dst, 0x0, sizeof(struct checker));
204         free_checker(src);
205 }
206
207 int checker_check (struct checker * c)
208 {
209         int r;
210
211         if (!c)
212                 return PATH_WILD;
213
214         c->message[0] = '\0';
215         if (c->disable) {
216                 MSG(c, "checker disabled");
217                 return PATH_UNCHECKED;
218         }
219         if (c->fd <= 0) {
220                 MSG(c, "no usable fd");
221                 return PATH_WILD;
222         }
223         r = c->check(c);
224
225         return r;
226 }
227
228 int checker_selected (struct checker * c)
229 {
230         if (!c)
231                 return 0;
232         return (c->check) ? 1 : 0;
233 }
234
235 char * checker_name (struct checker * c)
236 {
237         if (!c)
238                 return NULL;
239         return c->name;
240 }
241
242 char * checker_message (struct checker * c)
243 {
244         if (!c)
245                 return NULL;
246         return c->message;
247 }
248
249 void checker_clear_message (struct checker *c)
250 {
251         if (!c)
252                 return;
253         c->message[0] = '\0';
254 }
255
256 void checker_get (struct checker * dst, char * name)
257 {
258         struct checker * src = checker_lookup(name);
259
260         if (!dst)
261                 return;
262
263         if (!src) {
264                 dst->check = NULL;
265                 return;
266         }
267         dst->fd = src->fd;
268         dst->sync = src->sync;
269         strncpy(dst->name, src->name, CHECKER_NAME_LEN);
270         strncpy(dst->message, src->message, CHECKER_MSG_LEN);
271         dst->check = src->check;
272         dst->init = src->init;
273         dst->free = src->free;
274         dst->handle = NULL;
275         src->refcount++;
276 }