cpdup - Fix NULL pointer indirection on lost socket
[dragonfly.git] / usr.sbin / nscd / parser.c
blob2134303cf4d9175714891510d6a37f6c7a61ace7
1 /*-
2 * Copyright (c) 2005 Michael Bushkov <bushman@rsu.ru>
3 * All rights reserved.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24 * SUCH DAMAGE.
26 * $FreeBSD: src/usr.sbin/nscd/parser.c,v 1.2 2007/09/27 12:30:11 bushman Exp $
29 #include <assert.h>
30 #include <stdio.h>
31 #include <string.h>
32 #include "config.h"
33 #include "debug.h"
34 #include "log.h"
35 #include "parser.h"
37 static void enable_cache(struct configuration *,const char *, int);
38 static struct configuration_entry *find_create_entry(struct configuration *,
39 const char *);
40 static int get_number(const char *, int, int);
41 static enum cache_policy_t get_policy(const char *);
42 static int get_yesno(const char *);
43 static int check_cachename(const char *);
44 static void check_files(struct configuration *, const char *, int);
45 static void set_keep_hot_count(struct configuration *, const char *, int);
46 static void set_negative_policy(struct configuration *, const char *,
47 enum cache_policy_t);
48 static void set_negative_time_to_live(struct configuration *,
49 const char *, int);
50 static void set_positive_policy(struct configuration *, const char *,
51 enum cache_policy_t);
52 static void set_perform_actual_lookups(struct configuration *, const char *,
53 int);
54 static void set_positive_time_to_live(struct configuration *,
55 const char *, int);
56 static void set_suggested_size(struct configuration *, const char *,
57 int size);
58 static void set_threads_num(struct configuration *, int);
59 static int strbreak(char *, char **, int);
61 static int
62 strbreak(char *str, char **fields, int fields_size)
64 char *c = str;
65 int i, num;
67 TRACE_IN(strbreak);
68 num = 0;
69 for (i = 0;
70 ((*fields =
71 strsep(i < fields_size ? &c : NULL, "\n\t ")) != NULL);
72 ++i)
73 if ((*(*fields)) != '\0') {
74 ++fields;
75 ++num;
78 TRACE_OUT(strbreak);
79 return (num);
83 * Tries to find the configuration entry with the specified name. If search
84 * fails, the new entry with the default parameters will be created.
86 static struct configuration_entry *
87 find_create_entry(struct configuration *config,
88 const char *entry_name)
90 struct configuration_entry *entry = NULL;
91 int res;
93 TRACE_IN(find_create_entry);
94 entry = configuration_find_entry(config, entry_name);
95 if (entry == NULL) {
96 entry = create_def_configuration_entry(entry_name);
97 assert( entry != NULL);
98 res = add_configuration_entry(config, entry);
99 assert(res == 0);
102 TRACE_OUT(find_create_entry);
103 return (entry);
107 * The vast majority of the functions below corresponds to the particular
108 * keywords in the configuration file.
110 static void
111 enable_cache(struct configuration *config, const char *entry_name, int flag)
113 struct configuration_entry *entry;
115 TRACE_IN(enable_cache);
116 entry = find_create_entry(config, entry_name);
117 entry->enabled = flag;
118 TRACE_OUT(enable_cache);
121 static void
122 set_positive_time_to_live(struct configuration *config,
123 const char *entry_name, int ttl)
125 struct configuration_entry *entry;
126 struct timeval lifetime;
128 TRACE_IN(set_positive_time_to_live);
129 assert(ttl >= 0);
130 assert(entry_name != NULL);
131 memset(&lifetime, 0, sizeof(struct timeval));
132 lifetime.tv_sec = ttl;
134 entry = find_create_entry(config, entry_name);
135 memcpy(&entry->positive_cache_params.max_lifetime,
136 &lifetime, sizeof(struct timeval));
137 memcpy(&entry->mp_cache_params.max_lifetime,
138 &lifetime, sizeof(struct timeval));
140 TRACE_OUT(set_positive_time_to_live);
143 static void
144 set_negative_time_to_live(struct configuration *config,
145 const char *entry_name, int nttl)
147 struct configuration_entry *entry;
148 struct timeval lifetime;
150 TRACE_IN(set_negative_time_to_live);
151 assert(nttl > 0);
152 assert(entry_name != NULL);
153 memset(&lifetime, 0, sizeof(struct timeval));
154 lifetime.tv_sec = nttl;
156 entry = find_create_entry(config, entry_name);
157 assert(entry != NULL);
158 memcpy(&entry->negative_cache_params.max_lifetime,
159 &lifetime, sizeof(struct timeval));
161 TRACE_OUT(set_negative_time_to_live);
165 * Hot count is actually the elements size limit.
167 static void
168 set_keep_hot_count(struct configuration *config,
169 const char *entry_name, int count)
171 struct configuration_entry *entry;
173 TRACE_IN(set_keep_hot_count);
174 assert(count >= 0);
175 assert(entry_name != NULL);
177 entry = find_create_entry(config, entry_name);
178 assert(entry != NULL);
179 entry->positive_cache_params.max_elemsize = count;
181 entry = find_create_entry(config, entry_name);
182 assert(entry != NULL);
183 entry->negative_cache_params.max_elemsize = count;
185 TRACE_OUT(set_keep_hot_count);
188 static void
189 set_positive_policy(struct configuration *config,
190 const char *entry_name, enum cache_policy_t policy)
192 struct configuration_entry *entry;
194 TRACE_IN(set_positive_policy);
195 assert(entry_name != NULL);
197 entry = find_create_entry(config, entry_name);
198 assert(entry != NULL);
199 entry->positive_cache_params.policy = policy;
201 TRACE_OUT(set_positive_policy);
204 static void
205 set_negative_policy(struct configuration *config,
206 const char *entry_name, enum cache_policy_t policy)
208 struct configuration_entry *entry;
210 TRACE_IN(set_negative_policy);
211 assert(entry_name != NULL);
213 entry = find_create_entry(config, entry_name);
214 assert(entry != NULL);
215 entry->negative_cache_params.policy = policy;
217 TRACE_OUT(set_negative_policy);
220 static void
221 set_perform_actual_lookups(struct configuration *config,
222 const char *entry_name, int flag)
224 struct configuration_entry *entry;
226 TRACE_IN(set_perform_actual_lookups);
227 assert(entry_name != NULL);
229 entry = find_create_entry(config, entry_name);
230 assert(entry != NULL);
231 entry->perform_actual_lookups = flag;
233 TRACE_OUT(set_perform_actual_lookups);
236 static void
237 set_suggested_size(struct configuration *config,
238 const char *entry_name, int size)
240 struct configuration_entry *entry;
242 TRACE_IN(set_suggested_size);
243 assert(config != NULL);
244 assert(entry_name != NULL);
245 assert(size > 0);
247 entry = find_create_entry(config, entry_name);
248 assert(entry != NULL);
249 entry->positive_cache_params.cache_entries_size = size;
250 entry->negative_cache_params.cache_entries_size = size;
252 TRACE_OUT(set_suggested_size);
255 static void
256 check_files(struct configuration *config, const char *entry_name, int flag)
259 TRACE_IN(check_files);
260 assert(entry_name != NULL);
261 TRACE_OUT(check_files);
264 static int
265 get_yesno(const char *str)
268 if (strcmp(str, "yes") == 0)
269 return (1);
270 else if (strcmp(str, "no") == 0)
271 return (0);
272 else
273 return (-1);
276 static int
277 get_number(const char *str, int low, int max)
280 char *end = NULL;
281 int res = 0;
283 if (str[0] == '\0')
284 return (-1);
286 res = strtol(str, &end, 10);
287 if (*end != '\0')
288 return (-1);
289 else
290 if (((res >= low) || (low == -1)) &&
291 ((res <= max) || (max == -1)))
292 return (res);
293 else
294 return (-2);
297 static enum cache_policy_t
298 get_policy(const char *str)
301 if (strcmp(str, "fifo") == 0)
302 return (CPT_FIFO);
303 else if (strcmp(str, "lru") == 0)
304 return (CPT_LRU);
305 else if (strcmp(str, "lfu") == 0)
306 return (CPT_LFU);
308 return (-1);
311 static int
312 check_cachename(const char *str)
315 assert(str != NULL);
316 return ((strlen(str) > 0) ? 0 : -1);
319 static void
320 set_threads_num(struct configuration *config, int value)
323 assert(config != NULL);
324 config->threads_num = value;
328 * The main configuration routine. Its implementation is hugely inspired by the
329 * the same routine implementation in Solaris NSCD.
332 parse_config_file(struct configuration *config,
333 const char *fname, char const **error_str, int *error_line)
335 FILE *fin;
336 char buffer[255];
337 char *fields[128];
338 int field_count, line_num, value;
339 int res;
341 TRACE_IN(parse_config_file);
342 assert(config != NULL);
343 assert(fname != NULL);
345 fin = fopen(fname, "r");
346 if (fin == NULL) {
347 TRACE_OUT(parse_config_file);
348 return (-1);
351 res = 0;
352 line_num = 0;
353 memset(buffer, 0, sizeof(buffer));
354 while ((res == 0) && (fgets(buffer, sizeof(buffer) - 1, fin) != NULL)) {
355 field_count = strbreak(buffer, fields, sizeof(fields));
356 ++line_num;
358 if (field_count == 0)
359 continue;
361 switch (fields[0][0]) {
362 case '#':
363 case '\0':
364 continue;
365 case 'e':
366 if ((field_count == 3) &&
367 (strcmp(fields[0], "enable-cache") == 0) &&
368 (check_cachename(fields[1]) == 0) &&
369 ((value = get_yesno(fields[2])) != -1)) {
370 enable_cache(config, fields[1], value);
371 continue;
373 break;
374 case 'd':
375 if ((field_count == 2) &&
376 (strcmp(fields[0], "debug-level") == 0) &&
377 ((value = get_number(fields[1], 0, 10)) != -1)) {
378 continue;
380 break;
381 case 'p':
382 if ((field_count == 3) &&
383 (strcmp(fields[0], "positive-time-to-live") == 0) &&
384 (check_cachename(fields[1]) == 0) &&
385 ((value = get_number(fields[2], 0, -1)) != -1)) {
386 set_positive_time_to_live(config,
387 fields[1], value);
388 continue;
389 } else if ((field_count == 3) &&
390 (strcmp(fields[0], "positive-policy") == 0) &&
391 (check_cachename(fields[1]) == 0) &&
392 ((value = get_policy(fields[2])) != -1)) {
393 set_positive_policy(config, fields[1], value);
394 continue;
395 } else if ((field_count == 3) &&
396 (strcmp(fields[0], "perform-actual-lookups") == 0) &&
397 (check_cachename(fields[1]) == 0) &&
398 ((value = get_yesno(fields[2])) != -1)) {
399 set_perform_actual_lookups(config, fields[1],
400 value);
401 continue;
403 break;
404 case 'n':
405 if ((field_count == 3) &&
406 (strcmp(fields[0], "negative-time-to-live") == 0) &&
407 (check_cachename(fields[1]) == 0) &&
408 ((value = get_number(fields[2], 0, -1)) != -1)) {
409 set_negative_time_to_live(config,
410 fields[1], value);
411 continue;
412 } else if ((field_count == 3) &&
413 (strcmp(fields[0], "negative-policy") == 0) &&
414 (check_cachename(fields[1]) == 0) &&
415 ((value = get_policy(fields[2])) != -1)) {
416 set_negative_policy(config,
417 fields[1], value);
418 continue;
420 break;
421 case 's':
422 if ((field_count == 3) &&
423 (strcmp(fields[0], "suggested-size") == 0) &&
424 (check_cachename(fields[1]) == 0) &&
425 ((value = get_number(fields[2], 1, -1)) != -1)) {
426 set_suggested_size(config, fields[1], value);
427 continue;
429 break;
430 case 't':
431 if ((field_count == 2) &&
432 (strcmp(fields[0], "threads") == 0) &&
433 ((value = get_number(fields[1], 1, -1)) != -1)) {
434 set_threads_num(config, value);
435 continue;
437 break;
438 case 'k':
439 if ((field_count == 3) &&
440 (strcmp(fields[0], "keep-hot-count") == 0) &&
441 (check_cachename(fields[1]) == 0) &&
442 ((value = get_number(fields[2], 0, -1)) != -1)) {
443 set_keep_hot_count(config,
444 fields[1], value);
445 continue;
447 break;
448 case 'c':
449 if ((field_count == 3) &&
450 (strcmp(fields[0], "check-files") == 0) &&
451 (check_cachename(fields[1]) == 0) &&
452 ((value = get_yesno(fields[2])) != -1)) {
453 check_files(config,
454 fields[1], value);
455 continue;
457 break;
458 default:
459 break;
462 LOG_ERR_2("config file parser", "error in file "
463 "%s on line %d", fname, line_num);
464 *error_str = "syntax error";
465 *error_line = line_num;
466 res = -1;
468 fclose(fin);
470 TRACE_OUT(parse_config_file);
471 return (res);