2 * Copyright (c) 2005 Michael Bushkov <bushman@rsu.ru>
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
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
26 * $FreeBSD: src/usr.sbin/nscd/config.c,v 1.3 2008/10/12 00:44:27 delphij Exp $
39 * Default entries, which always exist in the configuration
41 const char *c_default_entries
[6] = {
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 *);
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
70 configuration_entry_cmp(const void *e1
, const void *e2
)
72 return (strcmp((const char *)e1
,
73 (*((struct configuration_entry
**)e2
))->name
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
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
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
)
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
;
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
);
127 LOG_ERR_2("create_configuration_entry",
128 "can't create positive cache lock");
129 TRACE_OUT(create_configuration_entry
);
133 res
= pthread_mutex_init(&retval
->negative_cache_lock
, NULL
);
135 pthread_mutex_destroy(&retval
->positive_cache_lock
);
137 LOG_ERR_2("create_configuration_entry",
138 "can't create negative cache lock");
139 TRACE_OUT(create_configuration_entry
);
143 res
= pthread_mutex_init(&retval
->mp_cache_lock
, NULL
);
145 pthread_mutex_destroy(&retval
->positive_cache_lock
);
146 pthread_mutex_destroy(&retval
->negative_cache_lock
);
148 LOG_ERR_2("create_configuration_entry",
149 "can't create negative cache lock");
150 TRACE_OUT(create_configuration_entry
);
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
));
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
);
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
,
230 TRACE_OUT(create_def_configuration_entry
);
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
);
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
);
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
);
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
);
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
,
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
,
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
,
354 configuration_entry_cache_mp_sort_cmp
);
356 TRACE_OUT(configuration_entry_add_mp_cache_entry
);
361 configuration_entry_find_mp_cache_entry(
362 struct configuration_entry
*config_entry
, const char *mp_name
)
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
);
375 TRACE_OUT(configuration_entry_find_mp_cache_entry
);
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
)
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
);
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)
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;
421 TRACE_OUT(configuration_entry_find_mp_cache_entries
);
426 * Configuration entry uses rwlock to handle access to its fields.
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
);
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
);
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
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
);
466 pthread_mutex_lock(&entry
->positive_cache_lock
);
469 pthread_mutex_lock(&entry
->negative_cache_lock
);
472 pthread_mutex_lock(&entry
->mp_cache_lock
);
475 /* should be unreachable */
478 TRACE_OUT(configuration_lock_entry
);
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
);
490 pthread_mutex_unlock(&entry
->positive_cache_lock
);
493 pthread_mutex_unlock(&entry
->negative_cache_lock
);
496 pthread_mutex_unlock(&entry
->mp_cache_lock
);
499 /* should be unreachable */
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
);
527 fill_configuration_defaults(struct configuration
*config
)
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
);
562 destroy_configuration(struct configuration
*config
)
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
);
576 TRACE_OUT(destroy_configuration
);