]> CyberLeo.Net >> Repos - FreeBSD/releng/7.2.git/blob - usr.sbin/nscd/parser.c
Create releng/7.2 from stable/7 in preparation for 7.2-RELEASE.
[FreeBSD/releng/7.2.git] / usr.sbin / nscd / parser.c
1 /*-
2  * Copyright (c) 2005 Michael Bushkov <bushman@rsu.ru>
3  * All rights reserved.
4  *
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.
13  *
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.
25  *
26  */
27
28 #include <sys/cdefs.h>
29 __FBSDID("$FreeBSD$");
30
31 #include <assert.h>
32 #include <stdio.h>
33 #include <string.h>
34 #include "config.h"
35 #include "debug.h"
36 #include "log.h"
37 #include "parser.h"
38
39 static void enable_cache(struct configuration *,const char *, int);
40 static struct configuration_entry *find_create_entry(struct configuration *,
41         const char *);
42 static int get_number(const char *, int, int);
43 static enum cache_policy_t get_policy(const char *);
44 static int get_yesno(const char *);
45 static int check_cachename(const char *);
46 static void check_files(struct configuration *, const char *, int);
47 static void set_keep_hot_count(struct configuration *, const char *, int);
48 static void set_negative_policy(struct configuration *, const char *,
49         enum cache_policy_t);
50 static void set_negative_time_to_live(struct configuration *,
51         const char *, int);
52 static void set_positive_policy(struct configuration *, const char *,
53         enum cache_policy_t);
54 static void set_perform_actual_lookups(struct configuration *, const char *,
55         int);
56 static void set_positive_time_to_live(struct configuration *,
57         const char *, int);
58 static void set_suggested_size(struct configuration *, const char *,
59         int size);
60 static void set_threads_num(struct configuration *, int);
61 static int strbreak(char *, char **, int);
62
63 static int
64 strbreak(char *str, char **fields, int fields_size)
65 {
66         char    *c = str;
67         int     i, num;
68
69         TRACE_IN(strbreak);
70         num = 0;
71         for (i = 0;
72              ((*fields =
73                 strsep(i < fields_size ? &c : NULL, "\n\t ")) != NULL);
74              ++i)
75                 if ((*(*fields)) != '\0') {
76                         ++fields;
77                         ++num;
78                 }
79
80         TRACE_OUT(strbreak);
81         return (num);
82 }
83
84 /*
85  * Tries to find the configuration entry with the specified name. If search
86  * fails, the new entry with the default parameters will be created.
87  */
88 static struct configuration_entry *
89 find_create_entry(struct configuration *config,
90         const char *entry_name)
91 {
92         struct configuration_entry *entry = NULL;
93         int res;
94
95         TRACE_IN(find_create_entry);
96         entry = configuration_find_entry(config, entry_name);
97         if (entry == NULL) {
98                 entry = create_def_configuration_entry(entry_name);
99                 assert( entry != NULL);
100                 res = add_configuration_entry(config, entry);
101                 assert(res == 0);
102         }
103
104         TRACE_OUT(find_create_entry);
105         return (entry);
106 }
107
108 /*
109  * The vast majority of the functions below corresponds to the particular
110  * keywords in the configuration file.
111  */
112 static void
113 enable_cache(struct configuration *config, const char *entry_name, int flag)
114 {
115         struct configuration_entry      *entry;
116
117         TRACE_IN(enable_cache);
118         entry = find_create_entry(config, entry_name);
119         entry->enabled = flag;
120         TRACE_OUT(enable_cache);
121 }
122
123 static void
124 set_positive_time_to_live(struct configuration *config,
125         const char *entry_name, int ttl)
126 {
127         struct configuration_entry *entry;
128         struct timeval lifetime;
129
130         TRACE_IN(set_positive_time_to_live);
131         assert(ttl >= 0);
132         assert(entry_name != NULL);
133         memset(&lifetime, 0, sizeof(struct timeval));
134         lifetime.tv_sec = ttl;
135
136         entry = find_create_entry(config, entry_name);
137         memcpy(&entry->positive_cache_params.max_lifetime,
138                 &lifetime, sizeof(struct timeval));
139         memcpy(&entry->mp_cache_params.max_lifetime,
140                 &lifetime, sizeof(struct timeval));
141
142         TRACE_OUT(set_positive_time_to_live);
143 }
144
145 static void
146 set_negative_time_to_live(struct configuration *config,
147         const char *entry_name, int nttl)
148 {
149         struct configuration_entry *entry;
150         struct timeval lifetime;
151
152         TRACE_IN(set_negative_time_to_live);
153         assert(nttl > 0);
154         assert(entry_name != NULL);
155         memset(&lifetime, 0, sizeof(struct timeval));
156         lifetime.tv_sec = nttl;
157
158         entry = find_create_entry(config, entry_name);
159         assert(entry != NULL);
160         memcpy(&entry->negative_cache_params.max_lifetime,
161                 &lifetime, sizeof(struct timeval));
162
163         TRACE_OUT(set_negative_time_to_live);
164 }
165
166 /*
167  * Hot count is actually the elements size limit.
168  */
169 static void
170 set_keep_hot_count(struct configuration *config,
171         const char *entry_name, int count)
172 {
173         struct configuration_entry *entry;
174
175         TRACE_IN(set_keep_hot_count);
176         assert(count >= 0);
177         assert(entry_name != NULL);
178
179         entry = find_create_entry(config, entry_name);
180         assert(entry != NULL);
181         entry->positive_cache_params.max_elemsize = count;
182
183         entry = find_create_entry(config, entry_name);
184         assert(entry != NULL);
185         entry->negative_cache_params.max_elemsize = count;
186
187         TRACE_OUT(set_keep_hot_count);
188 }
189
190 static void
191 set_positive_policy(struct configuration *config,
192         const char *entry_name, enum cache_policy_t policy)
193 {
194         struct configuration_entry *entry;
195
196         TRACE_IN(set_positive_policy);
197         assert(entry_name != NULL);
198
199         entry = find_create_entry(config, entry_name);
200         assert(entry != NULL);
201         entry->positive_cache_params.policy = policy;
202
203         TRACE_OUT(set_positive_policy);
204 }
205
206 static void
207 set_negative_policy(struct configuration *config,
208         const char *entry_name, enum cache_policy_t policy)
209 {
210         struct configuration_entry *entry;
211
212         TRACE_IN(set_negative_policy);
213         assert(entry_name != NULL);
214
215         entry = find_create_entry(config, entry_name);
216         assert(entry != NULL);
217         entry->negative_cache_params.policy = policy;
218
219         TRACE_OUT(set_negative_policy);
220 }
221
222 static void
223 set_perform_actual_lookups(struct configuration *config,
224         const char *entry_name, int flag)
225 {
226         struct configuration_entry *entry;
227
228         TRACE_IN(set_perform_actual_lookups);
229         assert(entry_name != NULL);
230
231         entry = find_create_entry(config, entry_name);
232         assert(entry != NULL);
233         entry->perform_actual_lookups = flag;
234
235         TRACE_OUT(set_perform_actual_lookups);
236 }
237
238 static void
239 set_suggested_size(struct configuration *config,
240         const char *entry_name, int size)
241 {
242         struct configuration_entry      *entry;
243
244         TRACE_IN(set_suggested_size);
245         assert(config != NULL);
246         assert(entry_name != NULL);
247         assert(size > 0);
248
249         entry = find_create_entry(config, entry_name);
250         assert(entry != NULL);
251         entry->positive_cache_params.cache_entries_size = size;
252         entry->negative_cache_params.cache_entries_size = size;
253
254         TRACE_OUT(set_suggested_size);
255 }
256
257 static void
258 check_files(struct configuration *config, const char *entry_name, int flag)
259 {
260
261         TRACE_IN(check_files);
262         assert(entry_name != NULL);
263         TRACE_OUT(check_files);
264 }
265
266 static int
267 get_yesno(const char *str)
268 {
269
270         if (strcmp(str, "yes") == 0)
271                 return (1);
272         else if (strcmp(str, "no") == 0)
273                 return (0);
274         else
275                 return (-1);
276 }
277
278 static int
279 get_number(const char *str, int low, int max)
280 {
281
282         char *end = NULL;
283         int res = 0;
284
285         if (str[0] == '\0')
286                 return (-1);
287
288         res = strtol(str, &end, 10);
289         if (*end != '\0')
290                 return (-1);
291         else
292                 if (((res >= low) || (low == -1)) &&
293                         ((res <= max) || (max == -1)))
294                         return (res);
295                 else
296                         return (-2);
297 }
298
299 static enum cache_policy_t
300 get_policy(const char *str)
301 {
302
303         if (strcmp(str, "fifo") == 0)
304                 return (CPT_FIFO);
305         else if (strcmp(str, "lru") == 0)
306                 return (CPT_LRU);
307         else if (strcmp(str, "lfu") == 0)
308                 return (CPT_LFU);
309
310         return (-1);
311 }
312
313 static int
314 check_cachename(const char *str)
315 {
316
317         assert(str != NULL);
318         return ((strlen(str) > 0) ? 0 : -1);
319 }
320
321 static void
322 set_threads_num(struct configuration *config, int value)
323 {
324
325         assert(config != NULL);
326         config->threads_num = value;
327 }
328
329 /*
330  * The main configuration routine. Its implementation is hugely inspired by the
331  * the same routine implementation in Solaris NSCD.
332  */
333 int
334 parse_config_file(struct configuration *config,
335         const char *fname, char const **error_str, int *error_line)
336 {
337         FILE    *fin;
338         char    buffer[255];
339         char    *fields[128];
340         int     field_count, line_num, value;
341         int     res;
342
343         TRACE_IN(parse_config_file);
344         assert(config != NULL);
345         assert(fname != NULL);
346
347         fin = fopen(fname, "r");
348         if (fin == NULL) {
349                 TRACE_OUT(parse_config_file);
350                 return (-1);
351         }
352
353         res = 0;
354         line_num = 0;
355         memset(buffer, 0, sizeof(buffer));
356         while ((res == 0) && (fgets(buffer, sizeof(buffer) - 1, fin) != NULL)) {
357                 field_count = strbreak(buffer, fields, sizeof(fields));
358                 ++line_num;
359
360                 if (field_count == 0)
361                         continue;
362
363                 switch (fields[0][0]) {
364                 case '#':
365                 case '\0':
366                         continue;
367                 case 'e':
368                         if ((field_count == 3) &&
369                         (strcmp(fields[0], "enable-cache") == 0) &&
370                         (check_cachename(fields[1]) == 0) &&
371                         ((value = get_yesno(fields[2])) != -1)) {
372                                 enable_cache(config, fields[1], value);
373                                 continue;
374                         }
375                         break;
376                 case 'd':
377                         if ((field_count == 2) &&
378                         (strcmp(fields[0], "debug-level") == 0) &&
379                         ((value = get_number(fields[1], 0, 10)) != -1)) {
380                                 continue;
381                         }
382                         break;
383                 case 'p':
384                         if ((field_count == 3) &&
385                         (strcmp(fields[0], "positive-time-to-live") == 0) &&
386                         (check_cachename(fields[1]) == 0) &&
387                         ((value = get_number(fields[2], 0, -1)) != -1)) {
388                                 set_positive_time_to_live(config,
389                                         fields[1], value);
390                                 continue;
391                         } else if ((field_count == 3) &&
392                         (strcmp(fields[0], "positive-policy") == 0) &&
393                         (check_cachename(fields[1]) == 0) &&
394                         ((value = get_policy(fields[2])) != -1)) {
395                                 set_positive_policy(config, fields[1], value);
396                                 continue;
397                         } else if ((field_count == 3) &&
398                         (strcmp(fields[0], "perform-actual-lookups") == 0) &&
399                         (check_cachename(fields[1]) == 0) &&
400                         ((value = get_yesno(fields[2])) != -1)) {
401                                 set_perform_actual_lookups(config, fields[1],
402                                         value);
403                                 continue;
404                         }
405                         break;
406                 case 'n':
407                         if ((field_count == 3) &&
408                         (strcmp(fields[0], "negative-time-to-live") == 0) &&
409                         (check_cachename(fields[1]) == 0) &&
410                         ((value = get_number(fields[2], 0, -1)) != -1)) {
411                                 set_negative_time_to_live(config,
412                                         fields[1], value);
413                                 continue;
414                         } else if ((field_count == 3) &&
415                         (strcmp(fields[0], "negative-policy") == 0) &&
416                         (check_cachename(fields[1]) == 0) &&
417                         ((value = get_policy(fields[2])) != -1)) {
418                                 set_negative_policy(config,
419                                         fields[1], value);
420                                 continue;
421                         }
422                         break;
423                 case 's':
424                         if ((field_count == 3) &&
425                         (strcmp(fields[0], "suggested-size") == 0) &&
426                         (check_cachename(fields[1]) == 0) &&
427                         ((value = get_number(fields[2], 1, -1)) != -1)) {
428                                 set_suggested_size(config, fields[1], value);
429                                 continue;
430                         }
431                         break;
432                 case 't':
433                         if ((field_count == 2) &&
434                         (strcmp(fields[0], "threads") == 0) &&
435                         ((value = get_number(fields[1], 1, -1)) != -1)) {
436                                 set_threads_num(config, value);
437                                 continue;
438                         }
439                         break;
440                 case 'k':
441                         if ((field_count == 3) &&
442                         (strcmp(fields[0], "keep-hot-count") == 0) &&
443                         (check_cachename(fields[1]) == 0) &&
444                         ((value = get_number(fields[2], 0, -1)) != -1)) {
445                                 set_keep_hot_count(config,
446                                         fields[1], value);
447                                 continue;
448                         }
449                         break;
450                 case 'c':
451                         if ((field_count == 3) &&
452                         (strcmp(fields[0], "check-files") == 0) &&
453                         (check_cachename(fields[1]) == 0) &&
454                         ((value = get_yesno(fields[2])) != -1)) {
455                                 check_files(config,
456                                         fields[1], value);
457                                 continue;
458                         }
459                         break;
460                 default:
461                         break;
462                 }
463
464                 LOG_ERR_2("config file parser", "error in file "
465                         "%s on line %d", fname, line_num);
466                 *error_str = "syntax error";
467                 *error_line = line_num;
468                 res = -1;
469         }
470         fclose(fin);
471
472         TRACE_OUT(parse_config_file);
473         return (res);
474 }