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 <math.h> 33 #include <stdio.h> 34 #include <stdlib.h> 35 #include <string.h> 36 #include "config.h" 37 #include "debug.h" 38 #include "log.h" 39 40 /* 41 * Default entries, which always exist in the configuration 42 */ 43 const char *c_default_entries[6] = { 44 NSDB_PASSWD, 45 NSDB_GROUP, 46 NSDB_HOSTS, 47 NSDB_SERVICES, 48 NSDB_PROTOCOLS, 49 NSDB_RPC 50 }; 51 52 static int configuration_entry_cmp(const void *, const void *); 53 static int configuration_entry_sort_cmp(const void *, const void *); 54 static int configuration_entry_cache_mp_sort_cmp(const void *, const void *); 55 static int configuration_entry_cache_mp_cmp(const void *, const void *); 56 static int configuration_entry_cache_mp_part_cmp(const void *, const void *); 57 static struct configuration_entry *create_configuration_entry(const char *, 58 struct timeval const *, struct timeval const *, 59 struct common_cache_entry_params const *, 60 struct common_cache_entry_params const *, 61 struct mp_cache_entry_params const *); 62 63 static int 64 configuration_entry_sort_cmp(const void *e1, const void *e2) 65 { 66 return (strcmp((*((struct configuration_entry **)e1))->name, 67 (*((struct configuration_entry **)e2))->name 68 )); 69 } 70 71 static int 72 configuration_entry_cmp(const void *e1, const void *e2) 73 { 74 return (strcmp((const char *)e1, 75 (*((struct configuration_entry **)e2))->name 76 )); 77 } 78 79 static int 80 configuration_entry_cache_mp_sort_cmp(const void *e1, const void *e2) 81 { 82 return (strcmp((*((cache_entry *)e1))->params->entry_name, 83 (*((cache_entry *)e2))->params->entry_name 84 )); 85 } 86 87 static int 88 configuration_entry_cache_mp_cmp(const void *e1, const void *e2) 89 { 90 return (strcmp((const char *)e1, 91 (*((cache_entry *)e2))->params->entry_name 92 )); 93 } 94 95 static int 96 configuration_entry_cache_mp_part_cmp(const void *e1, const void *e2) 97 { 98 return (strncmp((const char *)e1, 99 (*((cache_entry *)e2))->params->entry_name, 100 strlen((const char *)e1) 101 )); 102 } 103 104 static struct configuration_entry * 105 create_configuration_entry(const char *name, 106 struct timeval const *common_timeout, 107 struct timeval const *mp_timeout, 108 struct common_cache_entry_params const *positive_params, 109 struct common_cache_entry_params const *negative_params, 110 struct mp_cache_entry_params const *mp_params) 111 { 112 struct configuration_entry *retval; 113 size_t size; 114 int res; 115 116 TRACE_IN(create_configuration_entry); 117 assert(name != NULL); 118 assert(positive_params != NULL); 119 assert(negative_params != NULL); 120 assert(mp_params != NULL); 121 122 retval = (struct configuration_entry *)malloc( 123 sizeof(struct configuration_entry)); 124 assert(retval != NULL); 125 memset(retval, 0, sizeof(struct configuration_entry)); 126 127 res = pthread_mutex_init(&retval->positive_cache_lock, NULL); 128 if (res != 0) { 129 free(retval); 130 LOG_ERR_2("create_configuration_entry", 131 "can't create positive cache lock"); 132 TRACE_OUT(create_configuration_entry); 133 return (NULL); 134 } 135 136 res = pthread_mutex_init(&retval->negative_cache_lock, NULL); 137 if (res != 0) { 138 pthread_mutex_destroy(&retval->positive_cache_lock); 139 free(retval); 140 LOG_ERR_2("create_configuration_entry", 141 "can't create negative cache lock"); 142 TRACE_OUT(create_configuration_entry); 143 return (NULL); 144 } 145 146 res = pthread_mutex_init(&retval->mp_cache_lock, NULL); 147 if (res != 0) { 148 pthread_mutex_destroy(&retval->positive_cache_lock); 149 pthread_mutex_destroy(&retval->negative_cache_lock); 150 free(retval); 151 LOG_ERR_2("create_configuration_entry", 152 "can't create negative cache lock"); 153 TRACE_OUT(create_configuration_entry); 154 return (NULL); 155 } 156 157 memcpy(&retval->positive_cache_params, positive_params, 158 sizeof(struct common_cache_entry_params)); 159 memcpy(&retval->negative_cache_params, negative_params, 160 sizeof(struct common_cache_entry_params)); 161 memcpy(&retval->mp_cache_params, mp_params, 162 sizeof(struct mp_cache_entry_params)); 163 164 size = strlen(name); 165 retval->name = (char *)malloc(size + 1); 166 assert(retval->name != NULL); 167 memset(retval->name, 0, size + 1); 168 memcpy(retval->name, name, size); 169 170 memcpy(&retval->common_query_timeout, common_timeout, 171 sizeof(struct timeval)); 172 memcpy(&retval->mp_query_timeout, mp_timeout, 173 sizeof(struct timeval)); 174 175 asprintf(&retval->positive_cache_params.entry_name, "%s+", name); 176 assert(retval->positive_cache_params.entry_name != NULL); 177 178 asprintf(&retval->negative_cache_params.entry_name, "%s-", name); 179 assert(retval->negative_cache_params.entry_name != NULL); 180 181 asprintf(&retval->mp_cache_params.entry_name, "%s*", name); 182 assert(retval->mp_cache_params.entry_name != NULL); 183 184 TRACE_OUT(create_configuration_entry); 185 return (retval); 186 } 187 188 /* 189 * Creates configuration entry and fills it with default values 190 */ 191 struct configuration_entry * 192 create_def_configuration_entry(const char *name) 193 { 194 struct common_cache_entry_params positive_params, negative_params; 195 struct mp_cache_entry_params mp_params; 196 struct timeval default_common_timeout, default_mp_timeout; 197 198 struct configuration_entry *res = NULL; 199 200 TRACE_IN(create_def_configuration_entry); 201 memset(&positive_params, 0, 202 sizeof(struct common_cache_entry_params)); 203 positive_params.entry_type = CET_COMMON; 204 positive_params.cache_entries_size = DEFAULT_CACHE_HT_SIZE; 205 positive_params.max_elemsize = DEFAULT_POSITIVE_ELEMENTS_SIZE; 206 positive_params.satisf_elemsize = DEFAULT_POSITIVE_ELEMENTS_SIZE / 2; 207 positive_params.max_lifetime.tv_sec = DEFAULT_POSITIVE_LIFETIME; 208 positive_params.policy = CPT_LRU; 209 210 memcpy(&negative_params, &positive_params, 211 sizeof(struct common_cache_entry_params)); 212 negative_params.max_elemsize = DEFAULT_NEGATIVE_ELEMENTS_SIZE; 213 negative_params.satisf_elemsize = DEFAULT_NEGATIVE_ELEMENTS_SIZE / 2; 214 negative_params.max_lifetime.tv_sec = DEFAULT_NEGATIVE_LIFETIME; 215 negative_params.policy = CPT_FIFO; 216 217 memset(&default_common_timeout, 0, sizeof(struct timeval)); 218 default_common_timeout.tv_sec = DEFAULT_COMMON_ENTRY_TIMEOUT; 219 220 memset(&default_mp_timeout, 0, sizeof(struct timeval)); 221 default_mp_timeout.tv_sec = DEFAULT_MP_ENTRY_TIMEOUT; 222 223 memset(&mp_params, 0, 224 sizeof(struct mp_cache_entry_params)); 225 mp_params.entry_type = CET_MULTIPART; 226 mp_params.max_elemsize = DEFAULT_MULTIPART_ELEMENTS_SIZE; 227 mp_params.max_sessions = DEFAULT_MULITPART_SESSIONS_SIZE; 228 mp_params.max_lifetime.tv_sec = DEFAULT_MULITPART_LIFETIME; 229 230 res = create_configuration_entry(name, &default_common_timeout, 231 &default_mp_timeout, &positive_params, &negative_params, 232 &mp_params); 233 234 TRACE_OUT(create_def_configuration_entry); 235 return (res); 236 } 237 238 void 239 destroy_configuration_entry(struct configuration_entry *entry) 240 { 241 TRACE_IN(destroy_configuration_entry); 242 assert(entry != NULL); 243 pthread_mutex_destroy(&entry->positive_cache_lock); 244 pthread_mutex_destroy(&entry->negative_cache_lock); 245 pthread_mutex_destroy(&entry->mp_cache_lock); 246 free(entry->name); 247 free(entry->positive_cache_params.entry_name); 248 free(entry->negative_cache_params.entry_name); 249 free(entry->mp_cache_params.entry_name); 250 free(entry->mp_cache_entries); 251 free(entry); 252 TRACE_OUT(destroy_configuration_entry); 253 } 254 255 int 256 add_configuration_entry(struct configuration *config, 257 struct configuration_entry *entry) 258 { 259 TRACE_IN(add_configuration_entry); 260 assert(entry != NULL); 261 assert(entry->name != NULL); 262 if (configuration_find_entry(config, entry->name) != NULL) { 263 TRACE_OUT(add_configuration_entry); 264 return (-1); 265 } 266 267 if (config->entries_size == config->entries_capacity) { 268 struct configuration_entry **new_entries; 269 270 config->entries_capacity *= 2; 271 new_entries = (struct configuration_entry **)malloc( 272 sizeof(struct configuration_entry *) * 273 config->entries_capacity); 274 assert(new_entries != NULL); 275 memset(new_entries, 0, sizeof(struct configuration_entry *) * 276 config->entries_capacity); 277 memcpy(new_entries, config->entries, 278 sizeof(struct configuration_entry *) * 279 config->entries_size); 280 281 free(config->entries); 282 config->entries = new_entries; 283 } 284 285 config->entries[config->entries_size++] = entry; 286 qsort(config->entries, config->entries_size, 287 sizeof(struct configuration_entry *), 288 configuration_entry_sort_cmp); 289 290 TRACE_OUT(add_configuration_entry); 291 return (0); 292 } 293 294 size_t 295 configuration_get_entries_size(struct configuration *config) 296 { 297 TRACE_IN(configuration_get_entries_size); 298 assert(config != NULL); 299 TRACE_OUT(configuration_get_entries_size); 300 return (config->entries_size); 301 } 302 303 struct configuration_entry * 304 configuration_get_entry(struct configuration *config, size_t index) 305 { 306 TRACE_IN(configuration_get_entry); 307 assert(config != NULL); 308 assert(index < config->entries_size); 309 TRACE_OUT(configuration_get_entry); 310 return (config->entries[index]); 311 } 312 313 struct configuration_entry * 314 configuration_find_entry(struct configuration *config, 315 const char *name) 316 { 317 struct configuration_entry **retval; 318 319 TRACE_IN(configuration_find_entry); 320 321 retval = bsearch(name, config->entries, config->entries_size, 322 sizeof(struct configuration_entry *), configuration_entry_cmp); 323 TRACE_OUT(configuration_find_entry); 324 325 return ((retval != NULL) ? *retval : NULL); 326 } 327 328 /* 329 * All multipart cache entries are stored in the configuration_entry in the 330 * sorted array (sorted by names). The 3 functions below manage this array. 331 */ 332 333 int 334 configuration_entry_add_mp_cache_entry(struct configuration_entry *config_entry, 335 cache_entry c_entry) 336 { 337 cache_entry *new_mp_entries, *old_mp_entries; 338 339 TRACE_IN(configuration_entry_add_mp_cache_entry); 340 ++config_entry->mp_cache_entries_size; 341 new_mp_entries = (cache_entry *)malloc(sizeof(cache_entry) * 342 config_entry->mp_cache_entries_size); 343 assert(new_mp_entries != NULL); 344 new_mp_entries[0] = c_entry; 345 346 if (config_entry->mp_cache_entries_size - 1 > 0) { 347 memcpy(new_mp_entries + 1, 348 config_entry->mp_cache_entries, 349 (config_entry->mp_cache_entries_size - 1) * 350 sizeof(cache_entry)); 351 } 352 353 old_mp_entries = config_entry->mp_cache_entries; 354 config_entry->mp_cache_entries = new_mp_entries; 355 free(old_mp_entries); 356 357 qsort(config_entry->mp_cache_entries, 358 config_entry->mp_cache_entries_size, 359 sizeof(cache_entry), 360 configuration_entry_cache_mp_sort_cmp); 361 362 TRACE_OUT(configuration_entry_add_mp_cache_entry); 363 return (0); 364 } 365 366 cache_entry 367 configuration_entry_find_mp_cache_entry( 368 struct configuration_entry *config_entry, const char *mp_name) 369 { 370 cache_entry *result; 371 372 TRACE_IN(configuration_entry_find_mp_cache_entry); 373 result = bsearch(mp_name, config_entry->mp_cache_entries, 374 config_entry->mp_cache_entries_size, 375 sizeof(cache_entry), configuration_entry_cache_mp_cmp); 376 377 if (result == NULL) { 378 TRACE_OUT(configuration_entry_find_mp_cache_entry); 379 return (NULL); 380 } else { 381 TRACE_OUT(configuration_entry_find_mp_cache_entry); 382 return (*result); 383 } 384 } 385 386 /* 387 * Searches for all multipart entries with names starting with mp_name. 388 * Needed for cache flushing. 389 */ 390 int 391 configuration_entry_find_mp_cache_entries( 392 struct configuration_entry *config_entry, const char *mp_name, 393 cache_entry **start, cache_entry **finish) 394 { 395 cache_entry *result; 396 397 TRACE_IN(configuration_entry_find_mp_cache_entries); 398 result = bsearch(mp_name, config_entry->mp_cache_entries, 399 config_entry->mp_cache_entries_size, 400 sizeof(cache_entry), configuration_entry_cache_mp_part_cmp); 401 402 if (result == NULL) { 403 TRACE_OUT(configuration_entry_find_mp_cache_entries); 404 return (-1); 405 } 406 407 *start = result; 408 *finish = result + 1; 409 410 while (*start != config_entry->mp_cache_entries) { 411 if (configuration_entry_cache_mp_part_cmp(mp_name, *start - 1) == 0) 412 *start = *start - 1; 413 else 414 break; 415 } 416 417 while (*finish != config_entry->mp_cache_entries + 418 config_entry->mp_cache_entries_size) { 419 420 if (configuration_entry_cache_mp_part_cmp( 421 mp_name, *finish) == 0) 422 *finish = *finish + 1; 423 else 424 break; 425 } 426 427 TRACE_OUT(configuration_entry_find_mp_cache_entries); 428 return (0); 429 } 430 431 /* 432 * Configuration entry uses rwlock to handle access to its fields. 433 */ 434 void 435 configuration_lock_rdlock(struct configuration *config) 436 { 437 TRACE_IN(configuration_lock_rdlock); 438 pthread_rwlock_rdlock(&config->rwlock); 439 TRACE_OUT(configuration_lock_rdlock); 440 } 441 442 void 443 configuration_lock_wrlock(struct configuration *config) 444 { 445 TRACE_IN(configuration_lock_wrlock); 446 pthread_rwlock_wrlock(&config->rwlock); 447 TRACE_OUT(configuration_lock_wrlock); 448 } 449 450 void 451 configuration_unlock(struct configuration *config) 452 { 453 TRACE_IN(configuration_unlock); 454 pthread_rwlock_unlock(&config->rwlock); 455 TRACE_OUT(configuration_unlock); 456 } 457 458 /* 459 * Configuration entry uses 3 mutexes to handle cache operations. They are 460 * acquired by configuration_lock_entry and configuration_unlock_entry 461 * functions. 462 */ 463 void 464 configuration_lock_entry(struct configuration_entry *entry, 465 enum config_entry_lock_type lock_type) 466 { 467 TRACE_IN(configuration_lock_entry); 468 assert(entry != NULL); 469 470 switch (lock_type) { 471 case CELT_POSITIVE: 472 pthread_mutex_lock(&entry->positive_cache_lock); 473 break; 474 case CELT_NEGATIVE: 475 pthread_mutex_lock(&entry->negative_cache_lock); 476 break; 477 case CELT_MULTIPART: 478 pthread_mutex_lock(&entry->mp_cache_lock); 479 break; 480 default: 481 /* should be unreachable */ 482 break; 483 } 484 TRACE_OUT(configuration_lock_entry); 485 } 486 487 void 488 configuration_unlock_entry(struct configuration_entry *entry, 489 enum config_entry_lock_type lock_type) 490 { 491 TRACE_IN(configuration_unlock_entry); 492 assert(entry != NULL); 493 494 switch (lock_type) { 495 case CELT_POSITIVE: 496 pthread_mutex_unlock(&entry->positive_cache_lock); 497 break; 498 case CELT_NEGATIVE: 499 pthread_mutex_unlock(&entry->negative_cache_lock); 500 break; 501 case CELT_MULTIPART: 502 pthread_mutex_unlock(&entry->mp_cache_lock); 503 break; 504 default: 505 /* should be unreachable */ 506 break; 507 } 508 TRACE_OUT(configuration_unlock_entry); 509 } 510 511 struct configuration * 512 init_configuration(void) 513 { 514 struct configuration *retval; 515 516 TRACE_IN(init_configuration); 517 retval = (struct configuration *)malloc(sizeof(struct configuration)); 518 assert(retval != NULL); 519 memset(retval, 0, sizeof(struct configuration)); 520 521 retval->entries_capacity = INITIAL_ENTRIES_CAPACITY; 522 retval->entries = (struct configuration_entry **)malloc( 523 sizeof(struct configuration_entry *) * 524 retval->entries_capacity); 525 assert(retval->entries != NULL); 526 memset(retval->entries, 0, sizeof(struct configuration_entry *) * 527 retval->entries_capacity); 528 529 pthread_rwlock_init(&retval->rwlock, NULL); 530 531 TRACE_OUT(init_configuration); 532 return (retval); 533 } 534 535 void 536 fill_configuration_defaults(struct configuration *config) 537 { 538 size_t len, i; 539 540 TRACE_IN(fill_configuration_defaults); 541 assert(config != NULL); 542 543 if (config->socket_path != NULL) 544 free(config->socket_path); 545 546 len = strlen(DEFAULT_SOCKET_PATH); 547 config->socket_path = (char *)malloc(len + 1); 548 assert(config->socket_path != NULL); 549 memset(config->socket_path, 0, len + 1); 550 memcpy(config->socket_path, DEFAULT_SOCKET_PATH, len); 551 552 len = strlen(DEFAULT_PIDFILE_PATH); 553 config->pidfile_path = (char *)malloc(len + 1); 554 assert(config->pidfile_path != NULL); 555 memset(config->pidfile_path, 0, len + 1); 556 memcpy(config->pidfile_path, DEFAULT_PIDFILE_PATH, len); 557 558 config->socket_mode = S_IFSOCK | S_IRUSR | S_IWUSR | 559 S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH; 560 config->force_unlink = 1; 561 562 config->query_timeout = DEFAULT_QUERY_TIMEOUT; 563 config->threads_num = DEFAULT_THREADS_NUM; 564 565 for (i = 0; i < config->entries_size; ++i) 566 destroy_configuration_entry(config->entries[i]); 567 config->entries_size = 0; 568 569 TRACE_OUT(fill_configuration_defaults); 570 } 571 572 void 573 destroy_configuration(struct configuration *config) 574 { 575 int i; 576 TRACE_IN(destroy_configuration); 577 assert(config != NULL); 578 free(config->pidfile_path); 579 free(config->socket_path); 580 581 for (i = 0; i < config->entries_size; ++i) 582 destroy_configuration_entry(config->entries[i]); 583 free(config->entries); 584 585 pthread_rwlock_destroy(&config->rwlock); 586 free(config); 587 TRACE_OUT(destroy_configuration); 588 } 589