1 #include "../declarations.h"
2 #include "../conf_str.h"
3 #include "remotetool_conf.h"
4 
5 
6 
conf_read(void)7 int conf_read(void) {
8 	unsigned int i;
9 
10 	char *p;
11 
12 	size_t t;
13 
14 	t = CONFIG_PATH_LENGTH;
15 
16 	if((p = malloc(t + sizeof(char))) == NULL) {
17 		(void) fprintf(
18 			stderr,
19 			SUBSYSTEM "Failed to allocate %lu bytes of memory: %s.%c",
20 			(unsigned long) (t + sizeof(char)), strerror(errno), CONFIG_LINE_FEED
21 		);
22 
23 		return(-1);
24 	}
25 
26 	for(i = 0; ; i++) {
27 		if(c_d_t[i] == NULL) break;
28 
29 		if(conf_read_try(c_d_t[i], CONFIG_FILE, p, t) != 0) continue;
30 		if(conf_read_real(p) == 0) {
31 			(void) free(p);
32 
33 			return(0);
34 		}
35 	}
36 
37 	(void) fprintf(
38 		stderr,
39 		SUBSYSTEM "Failed to read configuration file '%s' from any of these directories:%c%c",
40 		CONFIG_FILE, CONFIG_LINE_FEED, CONFIG_LINE_FEED
41 	);
42 
43 	for(i = 0; ; i++) {
44 		if(c_d_t[i] == NULL) break;
45 
46 		(void) fprintf(
47 			stderr,
48 			"  %u. %s%c%c",
49 			(i + 1), c_d_t[i], CONFIG_PATH_DELIM, CONFIG_LINE_FEED
50 		);
51 	}
52 
53 	(void) fprintf(stderr, "%c", CONFIG_LINE_FEED);
54 
55 	(void) free(p);
56 
57 	return(-1);
58 }
59 
conf_read_try(const char * c,char * d,char * p,size_t t)60 int conf_read_try(const char *c, char *d, char *p, size_t t) {
61 	unsigned int i;
62 
63 	char *s, *v;
64 
65 	if(strncmp((const char *) c, "@", sizeof(char)) == 0) {
66 		(void) snprintf(p, t, "%s%s%c%s", DIR_PLACE_PRE, c + sizeof(char), CONFIG_PATH_DELIM, d);
67 	}
68 	else if(strncmp((const char *) c, "~", sizeof(char)) == 0) {
69 		if((s = node_get_homedir()) == NULL) return(-1);
70 
71 		(void) snprintf(p, t, "%s%s%c%s", s, c + sizeof(char), CONFIG_PATH_DELIM, d);
72 	}
73 	else if(strncmp((const char *) c, "$", sizeof(char)) == 0) {
74 		if((v = malloc(t + sizeof(char))) == NULL) {
75 			(void) fprintf(
76 				stderr,
77 				SUBSYSTEM "Failed to allocate %lu bytes of memory: %s.%c",
78 				(unsigned long) (t + sizeof(char)), strerror(errno), CONFIG_LINE_FEED
79 			);
80 
81 			return(-1);
82 		}
83 
84 		for(i = 0; ; i++) {
85 			if((size_t) i >= t || c[i + sizeof(char)] == 0 || c[i + sizeof(char)] == CONFIG_PATH_DELIM) break;
86 
87 			v[i] = c[i + sizeof(char)];
88 		}
89 
90 		v[i] = 0;
91 
92 		if((s = env_get(v)) == NULL) {
93 			(void) free(v);
94 
95 			return(-1);
96 		}
97 
98 		(void) free(v);
99 
100 		(void) snprintf(p, t, "%s%c%s", s, CONFIG_PATH_DELIM, d);
101 
102 		(void) env_free(s);
103 	}
104 	else (void) snprintf(p, t, "%s%c%s", c, CONFIG_PATH_DELIM, d);
105 
106 	return(0);
107 }
108 
conf_read_def(void)109 char *conf_read_def(void) {
110 	unsigned int i;
111 
112 	char *p;
113 
114 	size_t t;
115 
116 	FILE *f;
117 
118 	t = CONFIG_PATH_LENGTH;
119 
120 	if((p = malloc(t + sizeof(char))) == NULL) {
121 		(void) fprintf(
122 			stderr,
123 			SUBSYSTEM "Failed to allocate %lu bytes of memory: %s.%c",
124 			(unsigned long) (t + sizeof(char)), strerror(errno), CONFIG_LINE_FEED
125 		);
126 
127 		return(NULL);
128 	}
129 
130 	for(i = 0; ; i++) {
131 		if(c_d_t[i] == NULL) break;
132 
133 		if(conf_read_try(c_d_t[i], CONFIG_FILE, p, t) != 0) continue;
134 
135 		if((f = fopen((const char *) p, FILE_MODE_READ)) != NULL) {
136 			(void) fclose(f);
137 
138 			return(p);
139 		}
140 	}
141 
142 	(void) free(p);
143 
144 	return(NULL);
145 }
146 
conf_read_def_free(char * s)147 void conf_read_def_free(char *s) {
148 	if(s != NULL) (void) free(s);
149 }
150 
conf_read_real(char * s)151 static int conf_read_real(char *s) {
152 	unsigned int k;
153 
154 	char *p;
155 
156 	size_t t;
157 
158 	FILE *f;
159 
160 	if(s == NULL) return(-1);
161 
162 	t = CONFIG_LINE_LENGTH;
163 
164 	if((p = malloc(t + sizeof(char))) == NULL) {
165 		(void) fprintf(
166 			stderr,
167 			SUBSYSTEM "Failed to allocate %lu bytes of memory: %s.%c",
168 			(unsigned long) (t + sizeof(char)), strerror(errno), CONFIG_LINE_FEED
169 		);
170 
171 		return(-1);
172 	}
173 
174 	if((f = fopen((const char *) s, FILE_MODE_READ)) != NULL) {
175 		k = 1;
176 
177 		while(fgets(p, (int) t, f) != NULL) {
178 			if(p[0] == '\r' || p[0] == '\n' || p[0] == '#' || p[0] == '%' || p[0] == ';' || p[0] == '!') {
179 				++k;
180 
181 				continue;
182 			}
183 
184 			(void) conf_read_op(c_f_t, p, k);
185 
186 			++k;
187 		}
188 
189 		if(fclose(f) != 0) {
190 			(void) fprintf(
191 				stderr,
192 				SUBSYSTEM "Failed to close configuration '%s': %s.%c",
193 				s, strerror(errno), CONFIG_LINE_FEED
194 			);
195 		}
196 
197 		(void) free(p);
198 
199 		return(0);
200 	}
201 
202 	(void) free(p);
203 
204 	return(-1);
205 }
206 
conf_read_op(struct c_f * c,char * p,unsigned int k)207 static int conf_read_op(struct c_f *c, char *p, unsigned int k) {
208 	unsigned int i;
209 
210 	char *a;
211 
212 	for(i = 0; ; i++) {
213 		if(c[i].ck == NULL) break;
214 		if(strncasecmp((const char *) c[i].ck, (const char *) p, str_len(c[i].ck, STRING_ASCII)) == 0) {
215 			if((a = conf_read_it(p)) == NULL) break;
216 
217 			if(a == (char *) -1) {
218 				switch(c[i].c_t) {
219 					case CONFIG_TYPE_BOOLEAN:
220 						(void) fprintf(
221 							stderr,
222 							"Keyword %s at line %u requires a boolean (yes/no/1/0) value, going with builtin default.%c",
223 							c[i].ck, k, CONFIG_LINE_FEED
224 						);
225 
226 						break;
227 					case CONFIG_TYPE_INTEGER:
228 						(void) fprintf(
229 							stderr,
230 							"Keyword %s at line %u requires a numeral (<-0->) value, going with builtin default.%c",
231 							c[i].ck, k, CONFIG_LINE_FEED
232 						);
233 
234 						break;
235 					case CONFIG_TYPE_FLOAT:
236 						(void) fprintf(
237 							stderr,
238 							"Keyword %s at line %u requires a numeral (<-0.0->) value, going with builtin default.%c",
239 							c[i].ck, k, CONFIG_LINE_FEED
240 						);
241 
242 						break;
243 					case CONFIG_TYPE_STRING:
244 						(void) fprintf(
245 							stderr,
246 							"Keyword %s at line %u requires a string value, going with builtin default.%c",
247 							c[i].ck, k, CONFIG_LINE_FEED
248 						);
249 
250 						break;
251 					default:
252 						(void) fprintf(
253 							stderr,
254 							"Keyword %s at line %u requires a value of type %d.%c",
255 							c[i].ck, k, c[i].c_t, CONFIG_LINE_FEED
256 						);
257 
258 						break;
259 				}
260 
261 				break;
262 			}
263 
264 			switch(c[i].c_t) {
265 				case CONFIG_TYPE_BOOLEAN:
266 					if((conf_boolean(a, &c[i].c_i)) != 0) {
267 						(void) fprintf(
268 							stderr,
269 							"Keyword %s at line %u requires a boolean (yes/no/1/0) value.%c",
270 							c[i].ck, k, CONFIG_LINE_FEED
271 						);
272 
273 						break;
274 					}
275 
276 					break;
277 				case CONFIG_TYPE_INTEGER:
278 					if((conf_integer(a, &c[i].c_i)) != 0) {
279 						(void) fprintf(
280 							stderr,
281 							"Keyword %s at line %u requires a numeral (<-0->) value.%c",
282 							c[i].ck, k, CONFIG_LINE_FEED
283 						);
284 
285 						break;
286 					}
287 
288 					break;
289 				case CONFIG_TYPE_FLOAT:
290 					if((conf_float(a, &c[i].c_d)) != 0) {
291 						(void) fprintf(
292 							stderr,
293 							"Keyword %s at line %u requires a numeral (<-0.0->) value.%c",
294 							c[i].ck, k, CONFIG_LINE_FEED
295 						);
296 
297 						break;
298 					}
299 
300 					break;
301 				case CONFIG_TYPE_STRING:
302 					if(c[i].c_s == NULL) {
303 						if((c[i].c_s = malloc((size_t) CONFIG_LINE_LENGTH)) == NULL) {
304 							(void) fprintf(
305 								stderr,
306 								SUBSYSTEM "Failed to allocate %lu bytes of memory: %s.%c",
307 								(unsigned long) CONFIG_LINE_LENGTH, strerror(errno), CONFIG_LINE_FEED
308 							);
309 
310 							break;
311 						}
312 
313 						(void) memset((void *) c[i].c_s, 0, CONFIG_LINE_LENGTH);
314 					}
315 
316 					(void) conf_string(a, c[i].c_s);
317 
318 					break;
319 				default:
320 					(void) fprintf(
321 						stderr,
322 						"Unknown value type %d for keyword %s at line %u.%c",
323 						c[i].c_t, c[i].ck, k, CONFIG_LINE_FEED
324 					);
325 
326 					break;
327 			}
328 
329 			c[i].c_q = 2;
330 
331 			return(0);
332 		}
333 	}
334 
335 	return(-1);
336 }
337 
conf_read_it(char * s)338 static char *conf_read_it(char *s) {
339 	char *e;
340 
341 	size_t t;
342 
343 	if((e = str_chr((const char *) s, '=')) == NULL) {
344 		if((e = str_chr((const char *) s, ':')) == NULL) {
345 			return(NULL);
346 		}
347 	}
348 
349 	if((t = str_len(++e, STRING_ASCII)) < 2) {
350 		return(NULL);
351 	}
352 
353 	if(e[t - 2] == '\r') {
354 		e[t - 2] = 0;
355 	}
356 	else e[t - 1] = 0;
357 
358 	while(*e == ' ' || *e == '\t') e++;
359 
360 	if(*e == '\r' || *e == '\n' || *e == 0) return((char *) -1);
361 
362 	return(e);
363 }
364 
conf_boolean(char * a,int * o)365 static int conf_boolean(char *a, int *o) {
366 	if((strncasecmp((const char *) a, "yes", 3)) == 0) {
367 		*o = CONFIG_TYPE_BOOLEAN_YES;
368 
369 		return(0);
370 	}
371 	else if((strncasecmp((const char *) a, "no", 2)) == 0) {
372 		*o = CONFIG_TYPE_BOOLEAN_NO;
373 
374 		return(0);
375 	}
376 	else if((strncasecmp((const char *) a, "y", 1)) == 0) {
377 		*o = CONFIG_TYPE_BOOLEAN_YES;
378 
379 		return(0);
380 	}
381 	else if((strncasecmp((const char *) a, "n", 1)) == 0) {
382 		*o = CONFIG_TYPE_BOOLEAN_NO;
383 
384 		return(0);
385 	}
386 	else if((strncasecmp((const char *) a, "1", 1)) == 0) {
387 		*o = CONFIG_TYPE_BOOLEAN_YES;
388 
389 		return(0);
390 	}
391 	else if((strncasecmp((const char *) a, "0", 1)) == 0) {
392 		*o = CONFIG_TYPE_BOOLEAN_NO;
393 
394 		return(0);
395 	}
396 
397 	return(-1);
398 }
399 
conf_integer(char * a,int * o)400 static int conf_integer(char *a, int *o) {
401 	char *e, *f;
402 
403 	(void) flush_error();
404 
405 	e = a;
406 
407 	*o = (int) strtol((const char *) e, &f, 0);
408 
409 	if(errno == ERANGE || (errno != 0 && *o == 0) || e == f) return(-1);
410 
411 	return(0);
412 }
413 
conf_float(char * a,double * o)414 static int conf_float(char *a, double *o) {
415 	char *e, *f;
416 
417 	(void) flush_error();
418 
419 	e = a;
420 
421 	*o = strtod((const char *) e, &f);
422 
423 	if(errno == ERANGE || e == f) return(-1);
424 
425 	return(0);
426 }
427 
conf_string(char * a,char * o)428 static int conf_string(char *a, char *o) {
429 	size_t t;
430 
431 	t = str_len(a, STRING_ASCII);
432 
433 	if(t > CONFIG_LINE_LENGTH - 1) t = CONFIG_LINE_LENGTH - 1;
434 
435 	(void) memcpy((void *) o, (const void *) a, t);
436 
437 	o[t] = 0;
438 
439 	return(0);
440 }
441 
conf_free(void)442 void conf_free(void) {
443 	(void) conf_free_op(c_f_t);
444 }
445 
conf_free_op(void * v)446 void conf_free_op(void *v) {
447 	unsigned int i;
448 
449 	struct c_f *c;
450 
451 	c = (struct c_f *) v;
452 
453 	for(i = 0; ; i++) {
454 		if(c[i].ck == NULL) break;
455 		if(c[i].c_t == CONFIG_TYPE_STRING && c[i].c_s != NULL) {
456 			(void) free(c[i].c_s);
457 
458 			c[i].c_s = NULL;
459 		}
460 	}
461 }
462 
conf_fetch(char * s)463 void *conf_fetch(char *s) {
464 	void *r;
465 
466 	if((r = conf_fetch_op(c_f_t, s)) == (void *) -1) {
467 		(void) flush_error();
468 
469 		(void) fprintf(
470 			stderr,
471 			"Configuration parameter '%s' does not exist, please check configuration definitions.%c",
472 			s, CONFIG_LINE_FEED
473 		);
474 
475 		return(NULL);
476 	}
477 
478 	return(r);
479 }
480 
conf_fetch_op(void * v,char * s)481 void *conf_fetch_op(void *v, char *s) {
482 	unsigned int i;
483 
484 	size_t t;
485 
486 	struct c_f *c;
487 
488 	if(s == NULL) return(NULL);
489 
490 	t = str_len(s, STRING_ASCII);
491 
492 	c = (struct c_f *) v;
493 
494 	for(i = 0; ; i++) {
495 		if(c[i].ck == NULL) break;
496 		if(str_len(c[i].ck, STRING_ASCII) != t) continue;
497 		if(strncasecmp((const char *) c[i].ck, (const char *) s, t) == 0) {
498 			/* Leave if non-boolean parameter is not supplied by user */
499 			if(c[i].c_t != CONFIG_TYPE_BOOLEAN && c[i].c_q == 0) return(NULL);
500 
501 			switch(c[i].c_t) {
502 				case CONFIG_TYPE_BOOLEAN:
503 					return(&c[i].c_i);
504 				case CONFIG_TYPE_INTEGER:
505 					return(&c[i].c_i);
506 				case CONFIG_TYPE_FLOAT:
507 					return(&c[i].c_d);
508 				case CONFIG_TYPE_STRING:
509 					if(c[i].c_s == NULL || c[i].c_s[0] == 0) return(NULL);
510 
511 					return(c[i].c_s);
512 				default:
513 					(void) flush_error();
514 
515 					(void) fprintf(
516 						stderr,
517 						"Configuration parameter '%s' has unknown type, please check configuration definitions.%c",
518 						s, CONFIG_LINE_FEED
519 					);
520 
521 					return(NULL);
522 			}
523 		}
524 	}
525 
526 	return((void *) -1);
527 }
528 
conf_update_boolean(char * s,char * o)529 void conf_update_boolean(char *s, char *o) {
530 	(void) conf_update_boolean_op(c_f_t, s, o);
531 }
532 
conf_update_boolean_op(struct c_f * c,char * s,__UNUSED__ char * o)533 static void conf_update_boolean_op(struct c_f *c, char *s, __UNUSED__ char *o) {
534 	unsigned int i;
535 
536 	for(i = 0; ; i++) {
537 		if(c[i].ck == NULL) return;
538 		if(strncasecmp((const char *) c[i].ck, (const char *) s, str_len(c[i].ck, STRING_ASCII)) == 0) {
539 			c[i].c_i = CONFIG_TYPE_BOOLEAN_YES;
540 			c[i].c_q = 1;
541 
542 			return;
543 		}
544 	}
545 }
546 
conf_update_integer(char * s,char * o)547 void conf_update_integer(char *s, char *o) {
548 	(void) conf_update_integer_op(c_f_t, s, o);
549 }
550 
conf_update_integer_op(struct c_f * c,char * s,char * o)551 static void conf_update_integer_op(struct c_f *c, char *s, char *o) {
552 	unsigned int i;
553 
554 	char *e, *f;
555 
556 	for(i = 0; ; i++) {
557 		if(c[i].ck == NULL) return;
558 		if(strncasecmp((const char *) c[i].ck, (const char *) s, str_len(c[i].ck, STRING_ASCII)) == 0) {
559 			(void) flush_error();
560 
561 			e = o;
562 
563 			c[i].c_i = (int) strtol((const char *) e, &f, 0);
564 
565 			if(errno == ERANGE || (errno != 0 && c[i].c_i == 0) || e == f) {
566 				if(e == f) (void) set_error(EINVAL);
567 
568 				(void) fprintf(
569 					stderr,
570 					"Parameter '%s' requires numeral (<-0->) value.%c",
571 					s, CONFIG_LINE_FEED
572 				);
573 
574 				(void) conf_free();
575 				(void) exit(1);
576 			}
577 
578 			c[i].c_q = 1;
579 
580 			return;
581 		}
582 	}
583 }
584 
conf_update_float(char * s,char * o)585 void conf_update_float(char *s, char *o) {
586 	(void) conf_update_float_op(c_f_t, s, o);
587 }
588 
conf_update_float_op(struct c_f * c,char * s,char * o)589 static void conf_update_float_op(struct c_f *c, char *s, char *o) {
590 	unsigned int i;
591 
592 	char *e, *f;
593 
594 	for(i = 0; ; i++) {
595 		if(c[i].ck == NULL) return;
596 		if(strncasecmp((const char *) c[i].ck, (const char *) s, str_len(c[i].ck, STRING_ASCII)) == 0) {
597 			(void) flush_error();
598 
599 			e = o;
600 
601 			c[i].c_d = strtod((const char *) e, &f);
602 
603 			if(errno == ERANGE || e == f) {
604 				if(e == f) (void) set_error(EINVAL);
605 
606 				(void) fprintf(
607 					stderr,
608 					"Parameter '%s' requires numeral floating point (<-0.0->) value.%c",
609 					s, CONFIG_LINE_FEED
610 				);
611 
612 				(void) conf_free();
613 				(void) exit(1);
614 			}
615 
616 			c[i].c_q = 1;
617 
618 			return;
619 		}
620 	}
621 }
622 
conf_update_string(char * s,char * o)623 void conf_update_string(char *s, char *o) {
624 	(void) conf_update_string_op(c_f_t, s, o);
625 }
626 
conf_update_string_op(struct c_f * c,char * s,char * o)627 static void conf_update_string_op(struct c_f *c, char *s, char *o) {
628 	unsigned int i;
629 
630 	size_t t;
631 
632 	for(i = 0; ; i++) {
633 		if(c[i].ck == NULL) return;
634 		if(strncasecmp((const char *) c[i].ck, (const char *) s, str_len(c[i].ck, STRING_ASCII)) == 0) {
635 			t = str_len(o, STRING_ASCII);
636 
637 			if(t > CONFIG_LINE_LENGTH - 1) {
638 				(void) fprintf(
639 					stderr,
640 					"Parameter for '%s' is too long, it will be chopped.%c",
641 					s, CONFIG_LINE_FEED
642 				);
643 
644 				t = CONFIG_LINE_LENGTH - 1;
645 			}
646 
647 			if(c[i].c_s == NULL) {
648 				if((c[i].c_s = malloc((size_t) CONFIG_LINE_LENGTH)) == NULL) {
649 					(void) fprintf(
650 						stderr,
651 						SUBSYSTEM "Failed to allocate %lu bytes of memory: %s.%c",
652 						(unsigned long) CONFIG_LINE_LENGTH, strerror(errno), CONFIG_LINE_FEED
653 					);
654 
655 					return;
656 				}
657 
658 				(void) memset((void *) c[i].c_s, 0, CONFIG_LINE_LENGTH);
659 			}
660 
661 			(void) snprintf(c[i].c_s, t + sizeof(char), "%s", o);
662 
663 			c[i].c_q = 1;
664 
665 			return;
666 		}
667 	}
668 }
669 
conf_get_default_conf_path(unsigned int i)670 char *conf_get_default_conf_path(unsigned int i) {
671 	return(c_d_t[i]);
672 }
673