1 /*
2 * Copyright 2004-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 #include "dlm_daemon.h"
10
11 #if 0
12
13 lockspace ls_name [ls_args]
14 master ls_name node=nodeid [node_args]
15 master ls_name node=nodeid [node_args]
16 master ls_name node=nodeid [node_args]
17
18 lockspace foo nodir=1
19 master node=1 weight=2
20 master node=2 weight=1
21
22 #endif
23
24 /* The max line length in dlm.conf */
25
26 #define MAX_LINE 256
27
28 int get_weight(struct lockspace *ls, int nodeid)
29 {
30 int i;
31
32 /* if no masters are defined, everyone defaults to weight 1 */
33
34 if (!ls->master_count)
35 return 1;
36
37 for (i = 0; i < ls->master_count; i++) {
38 if (ls->master_nodeid[i] == nodeid)
39 return ls->master_weight[i];
40 }
41
42 /* if masters are defined, non-masters default to weight 0 */
43
44 return 0;
45 }
46
47 static void read_master_config(struct lockspace *ls, FILE *file)
48 {
49 char line[MAX_LINE];
50 char name[MAX_LINE];
51 char args[MAX_LINE];
52 char *k;
53 int nodeid, weight, i;
54
55 while (fgets(line, MAX_LINE, file)) {
56 if (line[0] == '\n')
57 break;
58 if (line[0] == ' ')
59 break;
60 if (line[0] == '#')
61 continue;
62
63 if (strncmp(line, "master", strlen("master")))
64 break;
65
66 memset(name, 0, sizeof(name));
67 memset(args, 0, sizeof(args));
68 nodeid = 0;
69 weight = 1;
70
71 sscanf(line, "master %s %[^\n]s", name, args);
72
73 if (strcmp(name, ls->name))
74 break;
75
76 k = strstr(args, "node=");
77 if (!k)
78 break;
79
80 sscanf(k, "node=%d", &nodeid);
81 if (!nodeid)
82 break;
83
84 k = strstr(args, "weight=");
85 if (k)
86 sscanf(k, "weight=%d", &weight);
87
88 log_debug("config lockspace %s nodeid %d weight %d",
89 ls->name, nodeid, weight);
90
91 i = ls->master_count++;
92 ls->master_nodeid[i] = nodeid;
93 ls->master_weight[i] = weight;
94
95 if (ls->master_count >= MAX_NODES)
96 break;
97 }
98 }
99
100 void setup_lockspace_config(struct lockspace *ls)
101 {
102 FILE *file;
103 char line[MAX_LINE];
104 char name[MAX_LINE];
105 char args[MAX_LINE];
106 char *k;
107 int val;
108
109 if (!path_exists(CONF_FILE_PATH))
110 return;
111
112 file = fopen(CONF_FILE_PATH, "r");
113 if (!file)
114 return;
115
116 while (fgets(line, MAX_LINE, file)) {
117 if (line[0] == '#')
118 continue;
119 if (line[0] == '\n')
120 continue;
121
122 if (strncmp(line, "lockspace", strlen("lockspace")))
123 continue;
124
125 memset(name, 0, sizeof(name));
126 memset(args, 0, sizeof(args));
127 val = 0;
128
129 sscanf(line, "lockspace %s %[^\n]s", name, args);
130
131 if (strcmp(name, ls->name))
132 continue;
133
134 k = strstr(args, "nodir=");
135 if (k) {
136 sscanf(k, "nodir=%d", &val);
137 ls->nodir = val;
138 }
139
140 read_master_config(ls, file);
141 }
142
143 fclose(file);
144 }
145
146 static void get_val_int(char *line, int *val_out)
147 {
148 char key[MAX_LINE];
149 char val[MAX_LINE];
150 int rv;
151
152 rv = sscanf(line, "%[^=]=%s", key, val);
153 if (rv != 2) {
154 log_error("Failed to parse config line %s", line);
155 return;
156 }
157
158 *val_out = atoi(val);
159 }
160
161 static void get_val_uint(char *line, unsigned int *val_out)
162 {
163 char key[MAX_LINE];
164 char val[MAX_LINE];
165 int rv;
166
167 rv = sscanf(line, "%[^=]=%s", key, val);
168 if (rv != 2) {
169 log_error("Failed to parse config line %s", line);
170 return;
171 }
172
173 *val_out = strtoul(val, NULL, 0);
174 }
175
176 static void get_val_str(char *line, char *val_out)
177 {
178 char key[MAX_LINE];
179 char val[MAX_LINE];
180 int rv;
181
182 rv = sscanf(line, "%[^=]=%s", key, val);
183 if (rv != 2) {
184 log_error("Failed to parse config line %s", line);
185 return;
186 }
187
188 strcpy(val_out, val);
189 }
190
191 inline static void reload_setting(int index)
192 {
193 switch(index) {
194 case log_debug_ind:
195 set_configfs_opt("log_debug", NULL, opt(log_debug_ind));
196 break;
197 case debug_logfile_ind:
198 set_logfile_priority();
199 break;
200 default:
201 break;
202 }
203 }
204
205 static void reset_opt_value(int index)
206 {
207 struct dlm_option *o = &dlm_options[index];
208
209 /* config priority: cli, config file, default */
210
211 if (o->cli_set) {
212 o->use_int = o->cli_int;
213 o->use_uint = o->cli_uint;
214 o->use_str = o->cli_str;
215
216 } else if (o->file_set) {
217 o->use_int = o->file_int;
218 o->use_uint = o->file_uint;
219 o->use_str = o->file_str;
220
221 } else {
222 o->use_int = o->default_int;
223 o->use_uint = o->default_uint;
224 o->use_str = (char *)o->default_str;
225 }
226
227 /*
228 * We don't handle reset value same as legacy value.
229 *
230 * i.e.
231 * 1. option abc default value is 0, while in dlm.conf abc=0.
232 * 2. Then remove abc from dlm.conf.
233 * 3. This function still call reload_setting(), and won't bypass this
234 * calling for no change.
235 */
236 reload_setting(index);
237 return;
238 }
239
240 void set_opt_file(int update)
241 {
242 unsigned int uval = 0;
243 struct dlm_option *o;
244 FILE *file;
245 char line[MAX_LINE];
246 char str[MAX_LINE];
247 int i, val = 0, ind;
248 char scanned_dlm_opt[dlm_options_max];
249
250 if (!path_exists(CONF_FILE_PATH))
251 return;
252
253 file = fopen(CONF_FILE_PATH, "r");
254 if (!file)
255 return;
256
257 /* In update mode, there is a little bit bother if one option ever set
258 * but later be removed or commented out */
259 memset(scanned_dlm_opt, 0, sizeof(scanned_dlm_opt));
260 scanned_dlm_opt[help_ind] = 1;
261 scanned_dlm_opt[version_ind] = 1;
262
263 while (fgets(line, MAX_LINE, file)) {
264 if (line[0] == '#')
265 continue;
266 if (line[0] == '\n')
267 continue;
268
269 memset(str, 0, sizeof(str));
270
271 for (i = 0; i < MAX_LINE; i++) {
272 if (line[i] == ' ')
273 break;
274 if (line[i] == '=')
275 break;
276 if (line[i] == '\0')
277 break;
278 if (line[i] == '\n')
279 break;
280 if (line[i] == '\t')
281 break;
282 str[i] = line[i];
283 }
284
285 ind = get_ind_name(str);
286 if (ind < 0)
287 continue;
288 o = &dlm_options[ind];
289 if (!o->name)
290 continue;
291
292 scanned_dlm_opt[ind] = 1;
293
294 /* In update flow, bypass the item which doesn't support reload. */
295 if (update && !o->reload)
296 continue;
297
298 o->file_set++;
299
300 if (!o->req_arg) {
301 /* current only "help" & "version" are no_arg type, ignore them */
302 continue;
303
304 } else if (o->req_arg == req_arg_int) {
305 get_val_int(line, &val);
306
307 if (update && (o->file_int == val))
308 continue;
309
310 o->file_int = val;
311
312 if (!o->cli_set)
313 o->use_int = o->file_int;
314
315 log_debug("config file %s = %d cli_set %d use %d",
316 o->name, o->file_int, o->cli_set, o->use_int);
317
318 } else if (o->req_arg == req_arg_uint) {
319 get_val_uint(line, &uval);
320
321 if (update && (o->file_uint == uval))
322 continue;
323
324 o->file_uint = uval;
325
326 if (!o->cli_set)
327 o->use_uint = o->file_uint;
328
329 log_debug("config file %s = %u cli_set %d use %u",
330 o->name, o->file_uint, o->cli_set, o->use_uint);
331
332 } else if (o->req_arg == req_arg_bool) {
333 get_val_int(line, &val);
334 val = val ? 1 : 0;
335
336 if (update && (o->file_int == val))
337 continue;
338
339 o->file_int = val;
340
341 if (!o->cli_set)
342 o->use_int = o->file_int;
343
344 log_debug("config file %s = %d cli_set %d use %d",
345 o->name, o->file_int, o->cli_set, o->use_int);
346 } else if (o->req_arg == req_arg_str) {
347 memset(str, 0, sizeof(str));
348 get_val_str(line, str);
349
350 if (update && !strcmp(o->file_str, str))
351 continue;
352
353 if (o->file_str)
354 free(o->file_str);
355 o->file_str = strdup(str);
356
357 if (!o->cli_set)
358 o->use_str = o->file_str;
359
360 log_debug("config file %s = %s cli_set %d use %s",
361 o->name, o->file_str, o->cli_set, o->use_str);
362 }
363
364 if (update)
365 reload_setting(ind);
366 }
367
368 if (update) {
369 /* handle commented out options */
370 for (i=0; i<dlm_options_max; i++) {
371 if (scanned_dlm_opt[i])
372 continue;
373 if (!dlm_options[i].reload || !dlm_options[i].file_set)
374 continue;
375
376 dlm_options[i].file_set = 0;
377 dlm_options[i].file_int = 0;
378 dlm_options[i].file_uint = 0;
379 if(dlm_options[i].file_str) {
380 free(dlm_options[i].file_str);
381 dlm_options[i].file_str = NULL;
382 }
383 reset_opt_value(i);
384 }
385 }
386
387 fclose(file);
388 }
389
390 /*
391 * do the clean/restore job:
392 * - clean up dlm_options[].dynamic_xx
393 * - using top priority item to set use option
394 */
395 static void reset_dynamic(int index)
396 {
397 struct dlm_option *o = &dlm_options[index];
398
399 if (!o->reload)
400 return;
401
402 o->dynamic_set = 0;
403 o->dynamic_int = 0;
404 if (o->dynamic_str){
405 free(o->dynamic_str);
406 o->dynamic_str = NULL;
407 }
408 o->dynamic_uint = 0;
409 reset_opt_value(index);
410
411 return;
412 }
413
414 /* copy code from exec_command() */
415 void set_opt_online(char *cmd_str, int cmd_len)
416 {
417 int i, ind, val = 0;
418 int av_count = 0;
419 int arg_len;
420 unsigned int uval = 0;
421 struct dlm_option *o;
422 char str[MAX_LINE];
423 char arg[ONE_ARG_LEN];
424 char *av[MAX_AV_COUNT + 1]; /* +1 for NULL */
425
426 if (cmd_len > RUN_COMMAND_LEN)
427 return;
428
429 for (i = 0; i < MAX_AV_COUNT + 1; i++)
430 av[i] = NULL;
431
432 if (!cmd_str[0])
433 return;
434
435 /* this should already be done, but make sure */
436 cmd_str[cmd_len - 1] = '\0';
437
438 memset(&arg, 0, sizeof(arg));
439 arg_len = 0;
440 cmd_len = strlen(cmd_str);
441
442 for (i = 0; i < cmd_len; i++) {
443 if (!cmd_str[i])
444 break;
445
446 if (av_count == MAX_AV_COUNT)
447 break;
448
449 if (cmd_str[i] == '\\') {
450 if (i == (cmd_len - 1))
451 break;
452 i++;
453
454 if (cmd_str[i] == '\\') {
455 arg[arg_len++] = cmd_str[i];
456 continue;
457 }
458 if (isspace(cmd_str[i])) {
459 arg[arg_len++] = cmd_str[i];
460 continue;
461 } else {
462 break;
463 }
464 }
465
466 if (isalnum(cmd_str[i]) || ispunct(cmd_str[i])) {
467 arg[arg_len++] = cmd_str[i];
468 } else if (isspace(cmd_str[i])) {
469 if (arg_len)
470 av[av_count++] = strdup(arg);
471
472 memset(arg, 0, sizeof(arg));
473 arg_len = 0;
474 } else {
475 break;
476 }
477 }
478
479 if ((av_count < MAX_AV_COUNT) && arg_len) {
480 av[av_count++] = strdup(arg);
481 }
482
483 /*
484 for (i = 0; i < MAX_AV_COUNT + 1; i++) {
485 if (!av[i])
486 break;
487
488 syslog(LOG_ERR, "command av[%d] \"%s\"", i, av[i]);
489 }
490 */
491
492 if (!strcmp(av[0], "restore_all")) {
493 for (i = 0; i < dlm_options_max; i++)
494 reset_dynamic(i);
495 return;
496 }
497
498 for (i = 0; i < av_count; i++) {
499 ind = get_ind_name(av[i]);
500 if (ind < 0)
501 continue;
502 o = &dlm_options[ind];
503 if (!o || !o->reload)
504 continue;
505
506 get_val_str(av[i], str);
507 if (!strcmp(str, "restore")) {
508 reset_dynamic(ind);
509 continue;
510 }
511
512 o->dynamic_set++;
513
514 if (!o->req_arg || o->req_arg == req_arg_int) {
515 get_val_int(av[i], &val);
516 if (!o->req_arg)
517 val = val ? 1 : 0;
518
519 o->dynamic_int = val;
520
521 log_debug("config dynamic %s = %d previous use %d",
522 o->name, o->dynamic_int, o->use_int);
523 o->use_int = o->dynamic_int;
524
525 } else if (o->req_arg == req_arg_uint) {
526 get_val_uint(av[i], &uval);
527 o->dynamic_uint = uval;
528
529 log_debug("config dynamic %s = %u previous use %u",
530 o->name, o->dynamic_uint, o->use_uint);
531 o->use_uint = o->dynamic_uint;
532
533 } else if (o->req_arg == req_arg_bool) {
534 get_val_int(av[i], &val);
535 o->dynamic_int = val ? 1 : 0;
536
537 log_debug("config dynamic %s = %d previous use %d",
538 o->name, o->dynamic_int, o->use_int);
539 o->use_int = o->dynamic_int;
540
541 } else if (o->req_arg == req_arg_str) {
542 memset(str, 0, sizeof(str));
543 get_val_str(av[i], str);
544
545 o->dynamic_str = strdup(str);
546
547 log_debug("config dynamic %s = %s previous use %s",
548 o->name, o->dynamic_str, o->use_str);
549 o->use_str = o->dynamic_str;
550 }
551
552 reload_setting(ind);
553 }
554
555 return;
556 }
557