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   	
(2) Event example_assign: Example 1: Assigning: "k" = return value from "strstr(args, "node=")".
Also see events: [returned_null][example_checked][example_assign][example_checked][example_checked][example_assign][example_checked][example_checked][var_assigned][dereference]
76   			k = strstr(args, "node=");
(3) Event example_checked: Example 1 (cont.): "k" has its value checked in "k".
Also see events: [returned_null][example_assign][example_assign][example_checked][example_checked][example_assign][example_checked][example_checked][var_assigned][dereference]
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  	
(4) Event example_assign: Example 2: Assigning: "k" = return value from "strstr(args, "nodir=")".
Also see events: [returned_null][example_assign][example_checked][example_checked][example_checked][example_assign][example_checked][example_checked][var_assigned][dereference]
134  			k = strstr(args, "nodir=");
(5) Event example_checked: Example 2 (cont.): "k" has its value checked in "k".
Also see events: [returned_null][example_assign][example_checked][example_assign][example_checked][example_assign][example_checked][example_checked][var_assigned][dereference]
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