LTO: Prevent -flto being used in main system libraries.
[dragonfly.git] / usr.sbin / nscd / config.c
blob2ee648aeb702ace2e4e02de9d305165b0473dedb
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/config.c,v 1.3 2008/10/12 00:44:27 delphij Exp $
29 #include <assert.h>
30 #include <math.h>
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <string.h>
34 #include "config.h"
35 #include "debug.h"
36 #include "log.h"
39 * Default entries, which always exist in the configuration
41 const char *c_default_entries[6] = {
42 NSDB_PASSWD,
43 NSDB_GROUP,
44 NSDB_HOSTS,
45 NSDB_SERVICES,
46 NSDB_PROTOCOLS,
47 NSDB_RPC
50 static int configuration_entry_cmp(const void *, const void *);
51 static int configuration_entry_sort_cmp(const void *, const void *);
52 static int configuration_entry_cache_mp_sort_cmp(const void *, const void *);
53 static int configuration_entry_cache_mp_cmp(const void *, const void *);
54 static int configuration_entry_cache_mp_part_cmp(const void *, const void *);
55 static struct configuration_entry *create_configuration_entry(const char *,
56 struct timeval const *, struct timeval const *,
57 struct common_cache_entry_params const *,
58 struct common_cache_entry_params const *,
59 struct mp_cache_entry_params const *);
61 static int
62 configuration_entry_sort_cmp(const void *e1, const void *e2)
64 return (strcmp((*((struct configuration_entry **)e1))->name,
65 (*((struct configuration_entry **)e2))->name
66 ));
69 static int
70 configuration_entry_cmp(const void *e1, const void *e2)
72 return (strcmp((const char *)e1,
73 (*((struct configuration_entry **)e2))->name
74 ));
77 static int
78 configuration_entry_cache_mp_sort_cmp(const void *e1, const void *e2)
80 return (strcmp((*((cache_entry *)e1))->params->entry_name,
81 (*((cache_entry *)e2))->params->entry_name
82 ));
85 static int
86 configuration_entry_cache_mp_cmp(const void *e1, const void *e2)
88 return (strcmp((const char *)e1,
89 (*((cache_entry *)e2))->params->entry_name
90 ));
93 static int
94 configuration_entry_cache_mp_part_cmp(const void *e1, const void *e2)
96 return (strncmp((const char *)e1,
97 (*((cache_entry *)e2))->params->entry_name,
98 strlen((const char *)e1)
99 ));
102 static struct configuration_entry *
103 create_configuration_entry(const char *name,
104 struct timeval const *common_timeout,
105 struct timeval const *mp_timeout,
106 struct common_cache_entry_params const *positive_params,
107 struct common_cache_entry_params const *negative_params,
108 struct mp_cache_entry_params const *mp_params)
110 struct configuration_entry *retval;
111 size_t size;
112 int res;
114 TRACE_IN(create_configuration_entry);
115 assert(name != NULL);
116 assert(positive_params != NULL);
117 assert(negative_params != NULL);
118 assert(mp_params != NULL);
120 retval = (struct configuration_entry *)calloc(1,
121 sizeof(struct configuration_entry));
122 assert(retval != NULL);
124 res = pthread_mutex_init(&retval->positive_cache_lock, NULL);
125 if (res != 0) {
126 free(retval);
127 LOG_ERR_2("create_configuration_entry",
128 "can't create positive cache lock");
129 TRACE_OUT(create_configuration_entry);
130 return (NULL);
133 res = pthread_mutex_init(&retval->negative_cache_lock, NULL);
134 if (res != 0) {
135 pthread_mutex_destroy(&retval->positive_cache_lock);
136 free(retval);
137 LOG_ERR_2("create_configuration_entry",
138 "can't create negative cache lock");
139 TRACE_OUT(create_configuration_entry);
140 return (NULL);
143 res = pthread_mutex_init(&retval->mp_cache_lock, NULL);
144 if (res != 0) {
145 pthread_mutex_destroy(&retval->positive_cache_lock);
146 pthread_mutex_destroy(&retval->negative_cache_lock);
147 free(retval);
148 LOG_ERR_2("create_configuration_entry",
149 "can't create negative cache lock");
150 TRACE_OUT(create_configuration_entry);
151 return (NULL);
154 memcpy(&retval->positive_cache_params, positive_params,
155 sizeof(struct common_cache_entry_params));
156 memcpy(&retval->negative_cache_params, negative_params,
157 sizeof(struct common_cache_entry_params));
158 memcpy(&retval->mp_cache_params, mp_params,
159 sizeof(struct mp_cache_entry_params));
161 size = strlen(name);
162 retval->name = (char *)calloc(1, size + 1);
163 assert(retval->name != NULL);
164 memcpy(retval->name, name, size);
166 memcpy(&retval->common_query_timeout, common_timeout,
167 sizeof(struct timeval));
168 memcpy(&retval->mp_query_timeout, mp_timeout,
169 sizeof(struct timeval));
171 asprintf(&retval->positive_cache_params.entry_name, "%s+", name);
172 assert(retval->positive_cache_params.entry_name != NULL);
174 asprintf(&retval->negative_cache_params.entry_name, "%s-", name);
175 assert(retval->negative_cache_params.entry_name != NULL);
177 asprintf(&retval->mp_cache_params.entry_name, "%s*", name);
178 assert(retval->mp_cache_params.entry_name != NULL);
180 TRACE_OUT(create_configuration_entry);
181 return (retval);
185 * Creates configuration entry and fills it with default values
187 struct configuration_entry *
188 create_def_configuration_entry(const char *name)
190 struct common_cache_entry_params positive_params, negative_params;
191 struct mp_cache_entry_params mp_params;
192 struct timeval default_common_timeout, default_mp_timeout;
194 struct configuration_entry *res = NULL;
196 TRACE_IN(create_def_configuration_entry);
197 memset(&positive_params, 0,
198 sizeof(struct common_cache_entry_params));
199 positive_params.entry_type = CET_COMMON;
200 positive_params.cache_entries_size = DEFAULT_CACHE_HT_SIZE;
201 positive_params.max_elemsize = DEFAULT_POSITIVE_ELEMENTS_SIZE;
202 positive_params.satisf_elemsize = DEFAULT_POSITIVE_ELEMENTS_SIZE / 2;
203 positive_params.max_lifetime.tv_sec = DEFAULT_POSITIVE_LIFETIME;
204 positive_params.policy = CPT_LRU;
206 memcpy(&negative_params, &positive_params,
207 sizeof(struct common_cache_entry_params));
208 negative_params.max_elemsize = DEFAULT_NEGATIVE_ELEMENTS_SIZE;
209 negative_params.satisf_elemsize = DEFAULT_NEGATIVE_ELEMENTS_SIZE / 2;
210 negative_params.max_lifetime.tv_sec = DEFAULT_NEGATIVE_LIFETIME;
211 negative_params.policy = CPT_FIFO;
213 memset(&default_common_timeout, 0, sizeof(struct timeval));
214 default_common_timeout.tv_sec = DEFAULT_COMMON_ENTRY_TIMEOUT;
216 memset(&default_mp_timeout, 0, sizeof(struct timeval));
217 default_mp_timeout.tv_sec = DEFAULT_MP_ENTRY_TIMEOUT;
219 memset(&mp_params, 0,
220 sizeof(struct mp_cache_entry_params));
221 mp_params.entry_type = CET_MULTIPART;
222 mp_params.max_elemsize = DEFAULT_MULTIPART_ELEMENTS_SIZE;
223 mp_params.max_sessions = DEFAULT_MULITPART_SESSIONS_SIZE;
224 mp_params.max_lifetime.tv_sec = DEFAULT_MULITPART_LIFETIME;
226 res = create_configuration_entry(name, &default_common_timeout,
227 &default_mp_timeout, &positive_params, &negative_params,
228 &mp_params);
230 TRACE_OUT(create_def_configuration_entry);
231 return (res);
234 void
235 destroy_configuration_entry(struct configuration_entry *entry)
237 TRACE_IN(destroy_configuration_entry);
238 assert(entry != NULL);
239 pthread_mutex_destroy(&entry->positive_cache_lock);
240 pthread_mutex_destroy(&entry->negative_cache_lock);
241 pthread_mutex_destroy(&entry->mp_cache_lock);
242 free(entry->name);
243 free(entry->positive_cache_params.entry_name);
244 free(entry->negative_cache_params.entry_name);
245 free(entry->mp_cache_params.entry_name);
246 free(entry->mp_cache_entries);
247 free(entry);
248 TRACE_OUT(destroy_configuration_entry);
252 add_configuration_entry(struct configuration *config,
253 struct configuration_entry *entry)
255 TRACE_IN(add_configuration_entry);
256 assert(entry != NULL);
257 assert(entry->name != NULL);
258 if (configuration_find_entry(config, entry->name) != NULL) {
259 TRACE_OUT(add_configuration_entry);
260 return (-1);
263 if (config->entries_size == config->entries_capacity) {
264 struct configuration_entry **new_entries;
266 config->entries_capacity *= 2;
267 new_entries = (struct configuration_entry **)calloc(1,
268 sizeof(struct configuration_entry *) *
269 config->entries_capacity);
270 assert(new_entries != NULL);
271 memcpy(new_entries, config->entries,
272 sizeof(struct configuration_entry *) *
273 config->entries_size);
275 free(config->entries);
276 config->entries = new_entries;
279 config->entries[config->entries_size++] = entry;
280 qsort(config->entries, config->entries_size,
281 sizeof(struct configuration_entry *),
282 configuration_entry_sort_cmp);
284 TRACE_OUT(add_configuration_entry);
285 return (0);
288 size_t
289 configuration_get_entries_size(struct configuration *config)
291 TRACE_IN(configuration_get_entries_size);
292 assert(config != NULL);
293 TRACE_OUT(configuration_get_entries_size);
294 return (config->entries_size);
297 struct configuration_entry *
298 configuration_get_entry(struct configuration *config, size_t index)
300 TRACE_IN(configuration_get_entry);
301 assert(config != NULL);
302 assert(index < config->entries_size);
303 TRACE_OUT(configuration_get_entry);
304 return (config->entries[index]);
307 struct configuration_entry *
308 configuration_find_entry(struct configuration *config,
309 const char *name)
311 struct configuration_entry **retval;
313 TRACE_IN(configuration_find_entry);
315 retval = bsearch(name, config->entries, config->entries_size,
316 sizeof(struct configuration_entry *), configuration_entry_cmp);
317 TRACE_OUT(configuration_find_entry);
319 return ((retval != NULL) ? *retval : NULL);
323 * All multipart cache entries are stored in the configuration_entry in the
324 * sorted array (sorted by names). The 3 functions below manage this array.
328 configuration_entry_add_mp_cache_entry(struct configuration_entry *config_entry,
329 cache_entry c_entry)
331 cache_entry *new_mp_entries, *old_mp_entries;
333 TRACE_IN(configuration_entry_add_mp_cache_entry);
334 ++config_entry->mp_cache_entries_size;
335 new_mp_entries = (cache_entry *)malloc(sizeof(cache_entry) *
336 config_entry->mp_cache_entries_size);
337 assert(new_mp_entries != NULL);
338 new_mp_entries[0] = c_entry;
340 if (config_entry->mp_cache_entries_size - 1 > 0) {
341 memcpy(new_mp_entries + 1,
342 config_entry->mp_cache_entries,
343 (config_entry->mp_cache_entries_size - 1) *
344 sizeof(cache_entry));
347 old_mp_entries = config_entry->mp_cache_entries;
348 config_entry->mp_cache_entries = new_mp_entries;
349 free(old_mp_entries);
351 qsort(config_entry->mp_cache_entries,
352 config_entry->mp_cache_entries_size,
353 sizeof(cache_entry),
354 configuration_entry_cache_mp_sort_cmp);
356 TRACE_OUT(configuration_entry_add_mp_cache_entry);
357 return (0);
360 cache_entry
361 configuration_entry_find_mp_cache_entry(
362 struct configuration_entry *config_entry, const char *mp_name)
364 cache_entry *result;
366 TRACE_IN(configuration_entry_find_mp_cache_entry);
367 result = bsearch(mp_name, config_entry->mp_cache_entries,
368 config_entry->mp_cache_entries_size,
369 sizeof(cache_entry), configuration_entry_cache_mp_cmp);
371 if (result == NULL) {
372 TRACE_OUT(configuration_entry_find_mp_cache_entry);
373 return (NULL);
374 } else {
375 TRACE_OUT(configuration_entry_find_mp_cache_entry);
376 return (*result);
381 * Searches for all multipart entries with names starting with mp_name.
382 * Needed for cache flushing.
385 configuration_entry_find_mp_cache_entries(
386 struct configuration_entry *config_entry, const char *mp_name,
387 cache_entry **start, cache_entry **finish)
389 cache_entry *result;
391 TRACE_IN(configuration_entry_find_mp_cache_entries);
392 result = bsearch(mp_name, config_entry->mp_cache_entries,
393 config_entry->mp_cache_entries_size,
394 sizeof(cache_entry), configuration_entry_cache_mp_part_cmp);
396 if (result == NULL) {
397 TRACE_OUT(configuration_entry_find_mp_cache_entries);
398 return (-1);
401 *start = result;
402 *finish = result + 1;
404 while (*start != config_entry->mp_cache_entries) {
405 if (configuration_entry_cache_mp_part_cmp(mp_name, *start - 1) == 0)
406 *start = *start - 1;
407 else
408 break;
411 while (*finish != config_entry->mp_cache_entries +
412 config_entry->mp_cache_entries_size) {
414 if (configuration_entry_cache_mp_part_cmp(
415 mp_name, *finish) == 0)
416 *finish = *finish + 1;
417 else
418 break;
421 TRACE_OUT(configuration_entry_find_mp_cache_entries);
422 return (0);
426 * Configuration entry uses rwlock to handle access to its fields.
428 void
429 configuration_lock_rdlock(struct configuration *config)
431 TRACE_IN(configuration_lock_rdlock);
432 pthread_rwlock_rdlock(&config->rwlock);
433 TRACE_OUT(configuration_lock_rdlock);
436 void
437 configuration_lock_wrlock(struct configuration *config)
439 TRACE_IN(configuration_lock_wrlock);
440 pthread_rwlock_wrlock(&config->rwlock);
441 TRACE_OUT(configuration_lock_wrlock);
444 void
445 configuration_unlock(struct configuration *config)
447 TRACE_IN(configuration_unlock);
448 pthread_rwlock_unlock(&config->rwlock);
449 TRACE_OUT(configuration_unlock);
453 * Configuration entry uses 3 mutexes to handle cache operations. They are
454 * acquired by configuration_lock_entry and configuration_unlock_entry
455 * functions.
457 void
458 configuration_lock_entry(struct configuration_entry *entry,
459 enum config_entry_lock_type lock_type)
461 TRACE_IN(configuration_lock_entry);
462 assert(entry != NULL);
464 switch (lock_type) {
465 case CELT_POSITIVE:
466 pthread_mutex_lock(&entry->positive_cache_lock);
467 break;
468 case CELT_NEGATIVE:
469 pthread_mutex_lock(&entry->negative_cache_lock);
470 break;
471 case CELT_MULTIPART:
472 pthread_mutex_lock(&entry->mp_cache_lock);
473 break;
474 default:
475 /* should be unreachable */
476 break;
478 TRACE_OUT(configuration_lock_entry);
481 void
482 configuration_unlock_entry(struct configuration_entry *entry,
483 enum config_entry_lock_type lock_type)
485 TRACE_IN(configuration_unlock_entry);
486 assert(entry != NULL);
488 switch (lock_type) {
489 case CELT_POSITIVE:
490 pthread_mutex_unlock(&entry->positive_cache_lock);
491 break;
492 case CELT_NEGATIVE:
493 pthread_mutex_unlock(&entry->negative_cache_lock);
494 break;
495 case CELT_MULTIPART:
496 pthread_mutex_unlock(&entry->mp_cache_lock);
497 break;
498 default:
499 /* should be unreachable */
500 break;
502 TRACE_OUT(configuration_unlock_entry);
505 struct configuration *
506 init_configuration(void)
508 struct configuration *retval;
510 TRACE_IN(init_configuration);
511 retval = (struct configuration *)calloc(1, sizeof(struct configuration));
512 assert(retval != NULL);
514 retval->entries_capacity = INITIAL_ENTRIES_CAPACITY;
515 retval->entries = (struct configuration_entry **)calloc(1,
516 sizeof(struct configuration_entry *) *
517 retval->entries_capacity);
518 assert(retval->entries != NULL);
520 pthread_rwlock_init(&retval->rwlock, NULL);
522 TRACE_OUT(init_configuration);
523 return (retval);
526 void
527 fill_configuration_defaults(struct configuration *config)
529 size_t len, i;
531 TRACE_IN(fill_configuration_defaults);
532 assert(config != NULL);
534 if (config->socket_path != NULL)
535 free(config->socket_path);
537 len = strlen(DEFAULT_SOCKET_PATH);
538 config->socket_path = (char *)calloc(1, len + 1);
539 assert(config->socket_path != NULL);
540 memcpy(config->socket_path, DEFAULT_SOCKET_PATH, len);
542 len = strlen(DEFAULT_PIDFILE_PATH);
543 config->pidfile_path = (char *)calloc(1, len + 1);
544 assert(config->pidfile_path != NULL);
545 memcpy(config->pidfile_path, DEFAULT_PIDFILE_PATH, len);
547 config->socket_mode = S_IFSOCK | S_IRUSR | S_IWUSR |
548 S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH;
549 config->force_unlink = 1;
551 config->query_timeout = DEFAULT_QUERY_TIMEOUT;
552 config->threads_num = DEFAULT_THREADS_NUM;
554 for (i = 0; i < config->entries_size; ++i)
555 destroy_configuration_entry(config->entries[i]);
556 config->entries_size = 0;
558 TRACE_OUT(fill_configuration_defaults);
561 void
562 destroy_configuration(struct configuration *config)
564 int i;
565 TRACE_IN(destroy_configuration);
566 assert(config != NULL);
567 free(config->pidfile_path);
568 free(config->socket_path);
570 for (i = 0; i < config->entries_size; ++i)
571 destroy_configuration_entry(config->entries[i]);
572 free(config->entries);
574 pthread_rwlock_destroy(&config->rwlock);
575 free(config);
576 TRACE_OUT(destroy_configuration);