1 /*
2 * Copyright 2012 Red Hat, Inc.
3 *
4 * This copyrighted material is made available to anyone wishing to use,
5 * modify, copy, or redistribute it subject to the terms and conditions
6 * of the GNU General Public License v2 or (at your option) any later version.
7 */
8
9
10 #include <stdio.h>
11 #include <stdlib.h>
12 #include <unistd.h>
13 #include <string.h>
14 #include <errno.h>
15
16 #include "fence_config.h"
17
18 #if 0
19
20 Empty new line separates the config for each fence device.
21
22 -
23
24 fence_all fence_foo key=val ...
25
26 Special fence config format that applies to all nodes and allows
27 no per node config parameters. Multiple fence devices (parallel
28 or priority) cannot be used with fence_all.
29
30 fence_all fence_foo ...
31 unfence_all
32
33 Apply unfencing to all nodes.
34
35 -
36
37 device <dev_name> <agent> <dev_args>
38 connect <dev_name> node=<nodeid> <con_args>
39
40 General fence config format, allowing per node config
41 parameters.
42
43 device <dev_name> <agent> <dev_args>
44 connect <dev_name> node=<nodeid> <con_args>
45 unfence <dev_name>
46
47 Apply unfencing to all nodes connected to this device.
48
49 -
50
51 device foo fence_foo ipaddr=1.1.1.1 login=x password=y
52 connect foo node=1 port=1
53 connect foo node=2 port=2
54 connect foo node=3 port=3
55
56 Simple example of nodes connected to switch ports.
57 If fencing with the device fails, the next device
58 listed for the node, if any, will be tried.
59
60 -
61
62 device foo:1 fence_foo ipaddr=1.1.1.1 login=x password=y
63 connect foo:1 node=1 port=1
64 connect foo:1 node=2 port=2
65 connect foo:1 node=3 port=3
66
67 device foo:2 fence_foo ipaddr=2.2.2.2 login=x password=y
68 connect foo:2 node=1 port=1
69 connect foo:2 node=2 port=2
70 connect foo:2 node=3 port=3
71
72 Associate two parallel path/power devices that must both
73 succeed for fencing to succeed. Devices have same base
74 name with :1 :2 suffix.
75
76 -
77
78 device foo fence_foo ipaddr=1.1.1.1 login=x password=y
79 connect foo node=1 port=1
80 connect foo node=2 port=2
81 connect foo node=3 port=3
82 unfence foo
83
84 Add unfence line to indicate nodes connected to the device
85 should be unfenced.
86
87 #endif
88
89 #define MAX_LINE (FENCE_CONFIG_ARGS_MAX + (3 * FENCE_CONFIG_NAME_MAX))
90
91 static unsigned int con_args_nodeid(char *args)
92 {
93 char *k;
94 unsigned int v;
95 int rv;
96
97 k = strstr(args, "node=");
98
99 rv = sscanf(k, "node=%u", &v);
100 if (rv != 1)
101 return 0;
102 return v;
103 }
104
105 static int read_config_section(unsigned int nodeid, FILE *file, char *dev_line,
106 struct fence_device **dev_out,
107 struct fence_connect **con_out)
108 {
109 struct fence_device *dev = NULL;
110 struct fence_connect *con;
111 char line[MAX_LINE];
112 char unused[FENCE_CONFIG_NAME_MAX];
113 char agent[FENCE_CONFIG_NAME_MAX];
114 char dev_name[FENCE_CONFIG_NAME_MAX];
115 char con_name[FENCE_CONFIG_NAME_MAX];
116 char dev_args[FENCE_CONFIG_ARGS_MAX];
117 char con_args[FENCE_CONFIG_ARGS_MAX];
118 int rv, unfence = 0;
119
120 if (strlen(dev_line) > MAX_LINE)
121 return -1;
122
123 memset(dev_name, 0, sizeof(dev_name));
124 memset(agent, 0, sizeof(agent));
125 memset(dev_args, 0, sizeof(dev_args));
126
127 rv = sscanf(dev_line, "%s %s %s %[^\n]s\n", unused, dev_name, agent, dev_args);
128 if (rv < 3)
129 return -1;
130
131 while (fgets(line, MAX_LINE, file)) {
132 if (line[0] == '\n')
133 break;
134 if (line[0] == ' ')
135 break;
136 if (line[0] == '#')
137 continue;
138
139 if (!strncmp(line, "unfence", strlen("unfence"))) {
140 if (!strstr(line, dev_name))
141 return -EINVAL;
142 unfence = 1;
143 continue;
144 }
145
146 /* invalid config */
147 if (strncmp(line, "connect", strlen("connect")))
148 return -EINVAL;
149
150 /* once we've found the connect line we want, continue
151 scanning lines until end of section so we pick up an
152 unfence line at the end */
153
154 if (dev)
155 continue;
156
157 memset(con_name, 0, sizeof(con_name));
158 memset(con_args, 0, sizeof(con_args));
159
160 sscanf(line, "%s %s %[^\n]s", unused, con_name, con_args);
161
162 /* invalid config */
163 if (strncmp(dev_name, con_name, FENCE_CONFIG_NAME_MAX))
164 return -EINVAL;
165
166 /* skip connection for another node */
167 if (con_args_nodeid(con_args) != nodeid)
168 continue;
169
170 dev = malloc(sizeof(struct fence_device));
171 if (!dev)
172 return -ENOMEM;
173
174 con = malloc(sizeof(struct fence_connect));
175 if (!con) {
176 free(dev);
177 return -ENOMEM;
178 }
179
180 memset(dev, 0, sizeof(struct fence_device));
181 memset(con, 0, sizeof(struct fence_connect));
182
183 strncpy(dev->name, dev_name, FENCE_CONFIG_NAME_MAX);
184 dev->name[FENCE_CONFIG_NAME_MAX - 1] = '\0';
185
186 strncpy(dev->agent, agent, FENCE_CONFIG_NAME_MAX);
187 dev->agent[FENCE_CONFIG_NAME_MAX - 1] = '\0';
188
189 strncpy(dev->args, dev_args, FENCE_CONFIG_ARGS_MAX);
190 dev->args[FENCE_CONFIG_ARGS_MAX - 1] = '\0';
191
192 strncpy(con->name, con_name, FENCE_CONFIG_NAME_MAX);
193 con->name[FENCE_CONFIG_NAME_MAX - 1] = '\0';
194
195 strncpy(con->args, con_args, FENCE_CONFIG_ARGS_MAX);
196 con->args[FENCE_CONFIG_ARGS_MAX - 1] = '\0';
197
198 dev->unfence = unfence;
199
200 *dev_out = dev;
201 *con_out = con;
202 }
203
204 if (dev && unfence)
205 dev->unfence = 1;
206
207 if (dev)
208 return 0;
209 else
210 return -ENOENT;
211 }
212
213 void fence_config_free(struct fence_config *fc)
214 {
215 struct fence_device *dev;
216 struct fence_connect *con;
217 int i;
218
219 for (i = 0; i < FENCE_CONFIG_DEVS_MAX; i++) {
220 dev = fc->dev[i];
221 con = fc->con[i];
222 if (dev)
223 free(dev);
224 if (con)
225 free(con);
226 }
227
228 memset(fc, 0, sizeof(struct fence_config));
229 }
230
231 int fence_config_init(struct fence_config *fc, unsigned int nodeid, char *path)
232 {
233 char line[MAX_LINE];
234 struct fence_device *dev;
235 struct fence_connect *con;
236 FILE *file;
237 int pos = 0;
238 int rv;
239
240 fc->nodeid = nodeid;
241
242 file = fopen(path, "r");
243 if (!file)
244 return -ENOENT;
245
246 while (fgets(line, MAX_LINE, file)) {
247 if (line[0] == '#')
248 continue;
249 if (line[0] == '\n')
250 continue;
251
252 if (!strncmp(line, "fence_all", strlen("fence_all"))) {
253 /* fence_all cannot be used with other fence devices */
254 if (pos) {
255 rv = -EINVAL;
256 goto out;
257 }
258
259 dev = malloc(sizeof(struct fence_device));
260 if (!dev) {
261 rv = -ENOMEM;
262 goto out;
263 }
264 memset(dev, 0, sizeof(struct fence_device));
265
266 rv = sscanf(line, "%s %s %[^\n]s\n", dev->name, dev->agent, dev->args);
267 if (rv < 2) {
268 rv = -EINVAL;
269 goto out;
270 }
271
272 if (fgets(line, MAX_LINE, file) &&
273 !strncmp(line, "unfence_all", strlen("unfence_all")))
274 dev->unfence = 1;
275
276 fc->dev[0] = dev;
277 fc->pos = 0;
278 rv = 0;
279 goto out;
280 }
281
282 if (strncmp(line, "device", strlen("device")))
283 continue;
284
285 dev = NULL;
286 con = NULL;
287
288 /* read connect and unfence lines following a device line */
289 rv = read_config_section(nodeid, file, line, &dev, &con);
290
291 /* nodeid not listed in this section */
292 if (rv == -ENOENT)
293 continue;
294
295 /* an error parsing the section, may be config to free */
296 if (rv < 0) {
297 if (dev)
298 free(dev);
299 if (con)
300 free(con);
301 goto out;
302 }
303
304 fc->dev[pos] = dev;
305 fc->con[pos] = con;
306 pos++;
307 }
308
309 if (!pos)
310 rv = -ENOENT;
311 else
312 rv = 0;
313 out:
314 fclose(file);
315 return rv;
316 }
317
318 static int same_base_name(struct fence_device *a,
319 struct fence_device *b)
320 {
321 int len, i;
322
323 len = strlen(a->name);
324 if (len > strlen(b->name))
325 len = strlen(b->name);
326
327 for (i = 0; i < len; i++) {
328 if (a->name[i] == ':' && b->name[i] == ':')
329 return 1;
330 if (a->name[i] == b->name[i])
331 continue;
332 return 0;
333 }
334 return 0;
335 }
336
337 /*
338 * if next dev is in parallel with last one,
339 * set d,c return 0, else -1
340 *
341 * two consecutive devs with same basename are parallel
342 */
343
344 int fence_config_next_parallel(struct fence_config *fc)
345 {
346 struct fence_device *prev, *next;
347 int d = fc->pos;
348
|
(2) Event cond_false: |
Condition "d >= 4", taking false branch. |
|
(4) Event cond_at_most: |
Checking "d >= 4" implies that "d" and "fc->pos" may be up to 3 on the false branch. |
| Also see events: |
[assignment][overrun-local] |
349 if (d >= FENCE_CONFIG_DEVS_MAX)
|
(3) Event if_end: |
End of if statement. |
350 return -1;
351
352 prev = fc->dev[d];
|
(5) Event overrun-local: |
Overrunning array "fc->dev" of 4 8-byte elements at element index 4 (byte offset 39) using index "d + 1" (which evaluates to 4). |
| Also see events: |
[assignment][cond_at_most] |
353 next = fc->dev[d+1];
354
355 if (!next)
356 return -1;
357
358 if (same_base_name(prev, next)) {
359 fc->pos = d+1;
360 return 0;
361 }
362 return -1;
363 }
364
365 /*
366 * if there's a dev with the next priority,
367 * set d,c return 0, else -1
368 *
369 * look for another dev with a non-matching basename
370 */
371
372 int fence_config_next_priority(struct fence_config *fc)
373 {
374 struct fence_device *prev, *next;
375 int d = fc->pos;
376 int i;
377
378 if (d >= FENCE_CONFIG_DEVS_MAX)
379 return -1;
380
381 prev = fc->dev[d];
382
383 for (i = d+1; i < FENCE_CONFIG_DEVS_MAX; i++) {
384 next = fc->dev[i];
385
386 if (!next)
387 return -1;
388
389 if (same_base_name(prev, next))
390 continue;
391
392 fc->pos = d+1;
393 return 0;
394 }
395 return -1;
396 }
397
398 int fence_config_agent_args(struct fence_config *fc, char *extra, char *args)
399 {
400 struct fence_device *dev;
401 struct fence_connect *con;
402 char node[FENCE_CONFIG_NAME_MAX];
403 char *p;
404 int n = 0;
405 int i, len;
406
407 dev = fc->dev[fc->pos];
408 con = fc->con[fc->pos];
409
410 memset(node, 0, sizeof(node));
411 snprintf(node, FENCE_CONFIG_NAME_MAX-1, "node=%u\n", fc->nodeid);
412 len = strlen(node);
413
414 if (dev)
415 len += strlen(dev->args) + 1; /* +1 for \n */
416 if (con)
417 len += strlen(con->args) + 1;
418 if (extra)
419 len += strlen(extra) + 1;
420
421 if (len > FENCE_CONFIG_ARGS_MAX - 1)
422 return -1;
423
424 if (dev && dev->args[0]) {
425 p = dev->args;
426
427 for (i = 0; i < strlen(dev->args); i++) {
428 if (*p == ' ')
429 args[n++] = '\n';
430 else
431 args[n++] = *p;
432 p++;
433 }
434 args[n++] = '\n';
435 }
436
437 if (con && con->args[0]) {
438 p = con->args;
439
440 for (i = 0; i < strlen(con->args); i++) {
441 if (*p == ' ')
442 args[n++] = '\n';
443 else
444 args[n++] = *p;
445 p++;
446 }
447 args[n++] = '\n';
448 }
449
450 if (!strstr(args, "node="))
451 strcat(args, node);
452 if (extra)
453 strcat(args, extra);
454
455 return 0;
456 }
457
458