Merge branch 'master' of git://git.kernel.org/pub/scm/linux/storage/multipath-tools/
[multipath-tools/.git] / libmultipath / checkers.c
1 #include <stdio.h>
2 #include <string.h>
3 #include <stddef.h>
4 #include <dlfcn.h>
5
6 #include "debug.h"
7 #include "checkers.h"
8 #include "vector.h"
9 #include "config.h"
10
11 char *checker_state_names[] = {
12       "wild",
13       "unchecked",
14       "down",
15       "up",
16       "shaky",
17       "ghost",
18       "pending"
19 };
20
21 static LIST_HEAD(checkers);
22
23 char * checker_state_name (int i)
24 {
25         return checker_state_names[i];
26 }
27
28 int init_checkers (void)
29 {
30         if (!add_checker(DEFAULT_CHECKER))
31                 return 1;
32         return 0;
33 }
34
35 struct checker * alloc_checker (void)
36 {
37         return MALLOC(sizeof(struct checker));
38 }
39
40 void free_checker (struct checker * c)
41 {
42         FREE(c);
43 }
44
45 void cleanup_checkers (void)
46 {
47         struct checker * checker_loop;
48         struct checker * checker_temp;
49
50         list_for_each_entry_safe(checker_loop, checker_temp, &checkers, node) {
51                 list_del(&checker_loop->node);
52                 free_checker(checker_loop);
53         }
54 }
55
56 struct checker * checker_lookup (char * name)
57 {
58         struct checker * c;
59
60         list_for_each_entry(c, &checkers, node) {
61                 if (!strncmp(name, c->name, CHECKER_NAME_LEN))
62                         return c;
63         }
64         return add_checker(name);
65 }
66
67 struct checker * add_checker (char * name)
68 {
69         char libname[LIB_CHECKER_NAMELEN];
70         void * handle;
71         struct checker * c;
72         char *errstr;
73
74         c = alloc_checker();
75         if (!c)
76                 return NULL;
77         snprintf(libname, LIB_CHECKER_NAMELEN, "%s/libcheck%s.so",
78                  conf->multipath_dir, name);
79         condlog(3, "loading %s checker", libname);
80         handle = dlopen(libname, RTLD_NOW);
81         errstr = dlerror();
82         if (errstr != NULL)
83         condlog(0, "A dynamic linking error occurred: (%s)", errstr);
84         if (!handle)
85                 goto out;
86
87         c->check = (int (*)(struct checker *)) dlsym(handle, "libcheck_check");
88         errstr = dlerror();
89         if (errstr != NULL)
90         condlog(0, "A dynamic linking error occurred: (%s)", errstr);
91         if (!c->check)
92                 goto out;
93
94         c->init = (int (*)(struct checker *)) dlsym(handle, "libcheck_init");
95         errstr = dlerror();
96         if (errstr != NULL)
97         condlog(0, "A dynamic linking error occurred: (%s)", errstr);
98         if (!c->init)
99                 goto out;
100
101         c->free = (void (*)(struct checker *)) dlsym(handle, "libcheck_free");
102         errstr = dlerror();
103         if (errstr != NULL)
104         condlog(0, "A dynamic linking error occurred: (%s)", errstr);
105         if (!c->free)
106                 goto out;
107
108         snprintf(c->name, CHECKER_NAME_LEN, "%s", name);
109         c->fd = 0;
110         c->sync = 1;
111         list_add(&c->node, &checkers);
112         return c;
113 out:
114         free_checker(c);
115         return NULL;
116 }
117
118 void checker_set_fd (struct checker * c, int fd)
119 {
120         c->fd = fd;
121 }
122
123 void checker_set_sync (struct checker * c)
124 {
125         c->sync = 1;
126 }
127
128 void checker_set_async (struct checker * c)
129 {
130         c->sync = 0;
131 }
132
133 void checker_enable (struct checker * c)
134 {
135         c->disable = 0;
136 }
137
138 void checker_disable (struct checker * c)
139 {
140         c->disable = 1;
141 }
142
143 int checker_init (struct checker * c, void ** mpctxt_addr)
144 {
145         c->mpcontext = mpctxt_addr;
146         return c->init(c);
147 }
148
149 void checker_put (struct checker * c)
150 {
151         if (c->free)
152                 c->free(c);
153         memset(c, 0x0, sizeof(struct checker));
154 }
155
156 int checker_check (struct checker * c)
157 {
158         int r;
159
160         if (c->disable)
161                 return PATH_UNCHECKED;
162         if (c->fd <= 0) {
163                 MSG(c, "no usable fd");
164                 return PATH_WILD;
165         }
166         r = c->check(c);
167
168         return r;
169 }
170
171 int checker_selected (struct checker * c)
172 {
173         return (c->check) ? 1 : 0;
174 }
175
176 char * checker_name (struct checker * c)
177 {
178         return c->name;
179 }
180
181 char * checker_message (struct checker * c)
182 {
183         return c->message;
184 }
185
186 void checker_get (struct checker * dst, char * name)
187 {
188         struct checker * src = checker_lookup(name);
189
190         if (!src) {
191                 dst->check = NULL;
192                 return;
193         }
194         dst->fd = src->fd;
195         dst->sync = src->sync;
196         strncpy(dst->name, src->name, CHECKER_NAME_LEN);
197         strncpy(dst->message, src->message, CHECKER_MSG_LEN);
198         dst->check = src->check;
199         dst->init = src->init;
200         dst->free = src->free;
201 }