106a99fe3SHajimu UMEMOTO /*- 206a99fe3SHajimu UMEMOTO * Copyright (c) 2005 Michael Bushkov <bushman@rsu.ru> 306a99fe3SHajimu UMEMOTO * All rights reserved. 406a99fe3SHajimu UMEMOTO * 506a99fe3SHajimu UMEMOTO * Redistribution and use in source and binary forms, with or without 606a99fe3SHajimu UMEMOTO * modification, are permitted provided that the following conditions 706a99fe3SHajimu UMEMOTO * are met: 806a99fe3SHajimu UMEMOTO * 1. Redistributions of source code must retain the above copyright 906a99fe3SHajimu UMEMOTO * notice, this list of conditions and the following disclaimer. 1006a99fe3SHajimu UMEMOTO * 2. Redistributions in binary form must reproduce the above copyright 1106a99fe3SHajimu UMEMOTO * notice, this list of conditions and the following disclaimer in thereg 1206a99fe3SHajimu UMEMOTO * documentation and/or other materials provided with the distribution. 1306a99fe3SHajimu UMEMOTO * 1406a99fe3SHajimu UMEMOTO * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1506a99fe3SHajimu UMEMOTO * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1606a99fe3SHajimu UMEMOTO * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1706a99fe3SHajimu UMEMOTO * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 1806a99fe3SHajimu UMEMOTO * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 1906a99fe3SHajimu UMEMOTO * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2006a99fe3SHajimu UMEMOTO * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2106a99fe3SHajimu UMEMOTO * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2206a99fe3SHajimu UMEMOTO * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2306a99fe3SHajimu UMEMOTO * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2406a99fe3SHajimu UMEMOTO * SUCH DAMAGE. 2506a99fe3SHajimu UMEMOTO * 2606a99fe3SHajimu UMEMOTO */ 2706a99fe3SHajimu UMEMOTO 2806a99fe3SHajimu UMEMOTO #include <sys/cdefs.h> 2906a99fe3SHajimu UMEMOTO __FBSDID("$FreeBSD$"); 3006a99fe3SHajimu UMEMOTO 3106a99fe3SHajimu UMEMOTO #include <sys/types.h> 3206a99fe3SHajimu UMEMOTO #include <sys/event.h> 3306a99fe3SHajimu UMEMOTO #include <sys/socket.h> 3406a99fe3SHajimu UMEMOTO #include <sys/time.h> 3506a99fe3SHajimu UMEMOTO #include <sys/param.h> 3606a99fe3SHajimu UMEMOTO #include <sys/un.h> 3706a99fe3SHajimu UMEMOTO #include <assert.h> 3806a99fe3SHajimu UMEMOTO #include <err.h> 3906a99fe3SHajimu UMEMOTO #include <errno.h> 4006a99fe3SHajimu UMEMOTO #include <fcntl.h> 4106a99fe3SHajimu UMEMOTO #include <libutil.h> 4206a99fe3SHajimu UMEMOTO #include <pthread.h> 4306a99fe3SHajimu UMEMOTO #include <signal.h> 4406a99fe3SHajimu UMEMOTO #include <stdio.h> 4506a99fe3SHajimu UMEMOTO #include <stdlib.h> 4606a99fe3SHajimu UMEMOTO #include <string.h> 4706a99fe3SHajimu UMEMOTO #include <unistd.h> 4806a99fe3SHajimu UMEMOTO 4906a99fe3SHajimu UMEMOTO #include "agents/passwd.h" 5006a99fe3SHajimu UMEMOTO #include "agents/group.h" 5106a99fe3SHajimu UMEMOTO #include "agents/services.h" 5206a99fe3SHajimu UMEMOTO #include "cachelib.h" 5306a99fe3SHajimu UMEMOTO #include "config.h" 5406a99fe3SHajimu UMEMOTO #include "debug.h" 5506a99fe3SHajimu UMEMOTO #include "log.h" 56db1bdf2bSMichael Bushkov #include "nscdcli.h" 5706a99fe3SHajimu UMEMOTO #include "parser.h" 5806a99fe3SHajimu UMEMOTO #include "query.h" 5906a99fe3SHajimu UMEMOTO #include "singletons.h" 6006a99fe3SHajimu UMEMOTO 6106a99fe3SHajimu UMEMOTO #ifndef CONFIG_PATH 62db1bdf2bSMichael Bushkov #define CONFIG_PATH "/etc/nscd.conf" 6306a99fe3SHajimu UMEMOTO #endif 64db1bdf2bSMichael Bushkov #define DEFAULT_CONFIG_PATH "nscd.conf" 6506a99fe3SHajimu UMEMOTO 6606a99fe3SHajimu UMEMOTO #define MAX_SOCKET_IO_SIZE 4096 6706a99fe3SHajimu UMEMOTO 6806a99fe3SHajimu UMEMOTO struct processing_thread_args { 6906a99fe3SHajimu UMEMOTO cache the_cache; 7006a99fe3SHajimu UMEMOTO struct configuration *the_configuration; 7106a99fe3SHajimu UMEMOTO struct runtime_env *the_runtime_env; 7206a99fe3SHajimu UMEMOTO }; 7306a99fe3SHajimu UMEMOTO 7406a99fe3SHajimu UMEMOTO static void accept_connection(struct kevent *, struct runtime_env *, 7506a99fe3SHajimu UMEMOTO struct configuration *); 7606a99fe3SHajimu UMEMOTO static void destroy_cache_(cache); 7706a99fe3SHajimu UMEMOTO static void destroy_runtime_env(struct runtime_env *); 7806a99fe3SHajimu UMEMOTO static cache init_cache_(struct configuration *); 7906a99fe3SHajimu UMEMOTO static struct runtime_env *init_runtime_env(struct configuration *); 8006a99fe3SHajimu UMEMOTO static void processing_loop(cache, struct runtime_env *, 8106a99fe3SHajimu UMEMOTO struct configuration *); 8206a99fe3SHajimu UMEMOTO static void process_socket_event(struct kevent *, struct runtime_env *, 8306a99fe3SHajimu UMEMOTO struct configuration *); 8406a99fe3SHajimu UMEMOTO static void process_timer_event(struct kevent *, struct runtime_env *, 8506a99fe3SHajimu UMEMOTO struct configuration *); 8606a99fe3SHajimu UMEMOTO static void *processing_thread(void *); 8706a99fe3SHajimu UMEMOTO static void usage(void); 8806a99fe3SHajimu UMEMOTO 8906a99fe3SHajimu UMEMOTO void get_time_func(struct timeval *); 9006a99fe3SHajimu UMEMOTO 9106a99fe3SHajimu UMEMOTO static void 9206a99fe3SHajimu UMEMOTO usage(void) 9306a99fe3SHajimu UMEMOTO { 940708945aSRuslan Ermilov fprintf(stderr, 95db1bdf2bSMichael Bushkov "usage: nscd [-dnst] [-i cachename] [-I cachename]\n"); 9606a99fe3SHajimu UMEMOTO exit(1); 9706a99fe3SHajimu UMEMOTO } 9806a99fe3SHajimu UMEMOTO 9906a99fe3SHajimu UMEMOTO static cache 10006a99fe3SHajimu UMEMOTO init_cache_(struct configuration *config) 10106a99fe3SHajimu UMEMOTO { 10206a99fe3SHajimu UMEMOTO struct cache_params params; 10306a99fe3SHajimu UMEMOTO cache retval; 10406a99fe3SHajimu UMEMOTO 10506a99fe3SHajimu UMEMOTO struct configuration_entry *config_entry; 10606a99fe3SHajimu UMEMOTO size_t size, i; 10706a99fe3SHajimu UMEMOTO int res; 10806a99fe3SHajimu UMEMOTO 10906a99fe3SHajimu UMEMOTO TRACE_IN(init_cache_); 11006a99fe3SHajimu UMEMOTO 11106a99fe3SHajimu UMEMOTO memset(¶ms, 0, sizeof(struct cache_params)); 11206a99fe3SHajimu UMEMOTO params.get_time_func = get_time_func; 11306a99fe3SHajimu UMEMOTO retval = init_cache(¶ms); 11406a99fe3SHajimu UMEMOTO 11506a99fe3SHajimu UMEMOTO size = configuration_get_entries_size(config); 11606a99fe3SHajimu UMEMOTO for (i = 0; i < size; ++i) { 11706a99fe3SHajimu UMEMOTO config_entry = configuration_get_entry(config, i); 11806a99fe3SHajimu UMEMOTO /* 11906a99fe3SHajimu UMEMOTO * We should register common entries now - multipart entries 12006a99fe3SHajimu UMEMOTO * would be registered automatically during the queries. 12106a99fe3SHajimu UMEMOTO */ 12206a99fe3SHajimu UMEMOTO res = register_cache_entry(retval, (struct cache_entry_params *) 12306a99fe3SHajimu UMEMOTO &config_entry->positive_cache_params); 12406a99fe3SHajimu UMEMOTO config_entry->positive_cache_entry = find_cache_entry(retval, 12506a99fe3SHajimu UMEMOTO config_entry->positive_cache_params.entry_name); 12606a99fe3SHajimu UMEMOTO assert(config_entry->positive_cache_entry != 12706a99fe3SHajimu UMEMOTO INVALID_CACHE_ENTRY); 12806a99fe3SHajimu UMEMOTO 12906a99fe3SHajimu UMEMOTO res = register_cache_entry(retval, (struct cache_entry_params *) 13006a99fe3SHajimu UMEMOTO &config_entry->negative_cache_params); 13106a99fe3SHajimu UMEMOTO config_entry->negative_cache_entry = find_cache_entry(retval, 13206a99fe3SHajimu UMEMOTO config_entry->negative_cache_params.entry_name); 13306a99fe3SHajimu UMEMOTO assert(config_entry->negative_cache_entry != 13406a99fe3SHajimu UMEMOTO INVALID_CACHE_ENTRY); 13506a99fe3SHajimu UMEMOTO } 13606a99fe3SHajimu UMEMOTO 13706a99fe3SHajimu UMEMOTO LOG_MSG_2("cache", "cache was successfully initialized"); 13806a99fe3SHajimu UMEMOTO TRACE_OUT(init_cache_); 13906a99fe3SHajimu UMEMOTO return (retval); 14006a99fe3SHajimu UMEMOTO } 14106a99fe3SHajimu UMEMOTO 14206a99fe3SHajimu UMEMOTO static void 14306a99fe3SHajimu UMEMOTO destroy_cache_(cache the_cache) 14406a99fe3SHajimu UMEMOTO { 14506a99fe3SHajimu UMEMOTO TRACE_IN(destroy_cache_); 14606a99fe3SHajimu UMEMOTO destroy_cache(the_cache); 14706a99fe3SHajimu UMEMOTO TRACE_OUT(destroy_cache_); 14806a99fe3SHajimu UMEMOTO } 14906a99fe3SHajimu UMEMOTO 15006a99fe3SHajimu UMEMOTO /* 15106a99fe3SHajimu UMEMOTO * Socket and kqueues are prepared here. We have one global queue for both 15206a99fe3SHajimu UMEMOTO * socket and timers events. 15306a99fe3SHajimu UMEMOTO */ 15406a99fe3SHajimu UMEMOTO static struct runtime_env * 15506a99fe3SHajimu UMEMOTO init_runtime_env(struct configuration *config) 15606a99fe3SHajimu UMEMOTO { 15706a99fe3SHajimu UMEMOTO int serv_addr_len; 15806a99fe3SHajimu UMEMOTO struct sockaddr_un serv_addr; 15906a99fe3SHajimu UMEMOTO 16006a99fe3SHajimu UMEMOTO struct kevent eventlist; 16106a99fe3SHajimu UMEMOTO struct timespec timeout; 16206a99fe3SHajimu UMEMOTO 16306a99fe3SHajimu UMEMOTO struct runtime_env *retval; 16406a99fe3SHajimu UMEMOTO 16506a99fe3SHajimu UMEMOTO TRACE_IN(init_runtime_env); 1664f7df5c2SXin LI retval = (struct runtime_env *)calloc(1, sizeof(struct runtime_env)); 16706a99fe3SHajimu UMEMOTO assert(retval != NULL); 16806a99fe3SHajimu UMEMOTO 16906a99fe3SHajimu UMEMOTO retval->sockfd = socket(PF_LOCAL, SOCK_STREAM, 0); 17006a99fe3SHajimu UMEMOTO 17106a99fe3SHajimu UMEMOTO if (config->force_unlink == 1) 17206a99fe3SHajimu UMEMOTO unlink(config->socket_path); 17306a99fe3SHajimu UMEMOTO 17406a99fe3SHajimu UMEMOTO memset(&serv_addr, 0, sizeof(struct sockaddr_un)); 17506a99fe3SHajimu UMEMOTO serv_addr.sun_family = PF_LOCAL; 176ecce338eSXin LI strlcpy(serv_addr.sun_path, config->socket_path, 17706a99fe3SHajimu UMEMOTO sizeof(serv_addr.sun_path)); 17806a99fe3SHajimu UMEMOTO serv_addr_len = sizeof(serv_addr.sun_family) + 17906a99fe3SHajimu UMEMOTO strlen(serv_addr.sun_path) + 1; 18006a99fe3SHajimu UMEMOTO 18106a99fe3SHajimu UMEMOTO if (bind(retval->sockfd, (struct sockaddr *)&serv_addr, 18206a99fe3SHajimu UMEMOTO serv_addr_len) == -1) { 18306a99fe3SHajimu UMEMOTO close(retval->sockfd); 18406a99fe3SHajimu UMEMOTO free(retval); 18506a99fe3SHajimu UMEMOTO 18606a99fe3SHajimu UMEMOTO LOG_ERR_2("runtime environment", "can't bind socket to path: " 18706a99fe3SHajimu UMEMOTO "%s", config->socket_path); 18806a99fe3SHajimu UMEMOTO TRACE_OUT(init_runtime_env); 18906a99fe3SHajimu UMEMOTO return (NULL); 19006a99fe3SHajimu UMEMOTO } 19106a99fe3SHajimu UMEMOTO LOG_MSG_2("runtime environment", "using socket %s", 19206a99fe3SHajimu UMEMOTO config->socket_path); 19306a99fe3SHajimu UMEMOTO 19406a99fe3SHajimu UMEMOTO /* 19506a99fe3SHajimu UMEMOTO * Here we're marking socket as non-blocking and setting its backlog 19606a99fe3SHajimu UMEMOTO * to the maximum value 19706a99fe3SHajimu UMEMOTO */ 19806a99fe3SHajimu UMEMOTO chmod(config->socket_path, config->socket_mode); 19906a99fe3SHajimu UMEMOTO listen(retval->sockfd, -1); 20006a99fe3SHajimu UMEMOTO fcntl(retval->sockfd, F_SETFL, O_NONBLOCK); 20106a99fe3SHajimu UMEMOTO 20206a99fe3SHajimu UMEMOTO retval->queue = kqueue(); 20306a99fe3SHajimu UMEMOTO assert(retval->queue != -1); 20406a99fe3SHajimu UMEMOTO 20506a99fe3SHajimu UMEMOTO EV_SET(&eventlist, retval->sockfd, EVFILT_READ, EV_ADD | EV_ONESHOT, 20606a99fe3SHajimu UMEMOTO 0, 0, 0); 20706a99fe3SHajimu UMEMOTO memset(&timeout, 0, sizeof(struct timespec)); 20806a99fe3SHajimu UMEMOTO kevent(retval->queue, &eventlist, 1, NULL, 0, &timeout); 20906a99fe3SHajimu UMEMOTO 21006a99fe3SHajimu UMEMOTO LOG_MSG_2("runtime environment", "successfully initialized"); 21106a99fe3SHajimu UMEMOTO TRACE_OUT(init_runtime_env); 21206a99fe3SHajimu UMEMOTO return (retval); 21306a99fe3SHajimu UMEMOTO } 21406a99fe3SHajimu UMEMOTO 21506a99fe3SHajimu UMEMOTO static void 21606a99fe3SHajimu UMEMOTO destroy_runtime_env(struct runtime_env *env) 21706a99fe3SHajimu UMEMOTO { 21806a99fe3SHajimu UMEMOTO TRACE_IN(destroy_runtime_env); 21906a99fe3SHajimu UMEMOTO close(env->queue); 22006a99fe3SHajimu UMEMOTO close(env->sockfd); 22106a99fe3SHajimu UMEMOTO free(env); 22206a99fe3SHajimu UMEMOTO TRACE_OUT(destroy_runtime_env); 22306a99fe3SHajimu UMEMOTO } 22406a99fe3SHajimu UMEMOTO 22506a99fe3SHajimu UMEMOTO static void 22606a99fe3SHajimu UMEMOTO accept_connection(struct kevent *event_data, struct runtime_env *env, 22706a99fe3SHajimu UMEMOTO struct configuration *config) 22806a99fe3SHajimu UMEMOTO { 22906a99fe3SHajimu UMEMOTO struct kevent eventlist[2]; 23006a99fe3SHajimu UMEMOTO struct timespec timeout; 23106a99fe3SHajimu UMEMOTO struct query_state *qstate; 23206a99fe3SHajimu UMEMOTO 23306a99fe3SHajimu UMEMOTO int fd; 23406a99fe3SHajimu UMEMOTO int res; 23506a99fe3SHajimu UMEMOTO 23606a99fe3SHajimu UMEMOTO uid_t euid; 23706a99fe3SHajimu UMEMOTO gid_t egid; 23806a99fe3SHajimu UMEMOTO 23906a99fe3SHajimu UMEMOTO TRACE_IN(accept_connection); 24006a99fe3SHajimu UMEMOTO fd = accept(event_data->ident, NULL, NULL); 24106a99fe3SHajimu UMEMOTO if (fd == -1) { 24206a99fe3SHajimu UMEMOTO LOG_ERR_2("accept_connection", "error %d during accept()", 24306a99fe3SHajimu UMEMOTO errno); 24406a99fe3SHajimu UMEMOTO TRACE_OUT(accept_connection); 24506a99fe3SHajimu UMEMOTO return; 24606a99fe3SHajimu UMEMOTO } 24706a99fe3SHajimu UMEMOTO 24806a99fe3SHajimu UMEMOTO if (getpeereid(fd, &euid, &egid) != 0) { 24906a99fe3SHajimu UMEMOTO LOG_ERR_2("accept_connection", "error %d during getpeereid()", 25006a99fe3SHajimu UMEMOTO errno); 25106a99fe3SHajimu UMEMOTO TRACE_OUT(accept_connection); 25206a99fe3SHajimu UMEMOTO return; 25306a99fe3SHajimu UMEMOTO } 25406a99fe3SHajimu UMEMOTO 25506a99fe3SHajimu UMEMOTO qstate = init_query_state(fd, sizeof(int), euid, egid); 25606a99fe3SHajimu UMEMOTO if (qstate == NULL) { 25706a99fe3SHajimu UMEMOTO LOG_ERR_2("accept_connection", "can't init query_state"); 25806a99fe3SHajimu UMEMOTO TRACE_OUT(accept_connection); 25906a99fe3SHajimu UMEMOTO return; 26006a99fe3SHajimu UMEMOTO } 26106a99fe3SHajimu UMEMOTO 26206a99fe3SHajimu UMEMOTO memset(&timeout, 0, sizeof(struct timespec)); 26306a99fe3SHajimu UMEMOTO EV_SET(&eventlist[0], fd, EVFILT_TIMER, EV_ADD | EV_ONESHOT, 26406a99fe3SHajimu UMEMOTO 0, qstate->timeout.tv_sec * 1000, qstate); 26506a99fe3SHajimu UMEMOTO EV_SET(&eventlist[1], fd, EVFILT_READ, EV_ADD | EV_ONESHOT, 26606a99fe3SHajimu UMEMOTO NOTE_LOWAT, qstate->kevent_watermark, qstate); 26706a99fe3SHajimu UMEMOTO res = kevent(env->queue, eventlist, 2, NULL, 0, &timeout); 26806a99fe3SHajimu UMEMOTO if (res < 0) 26906a99fe3SHajimu UMEMOTO LOG_ERR_2("accept_connection", "kevent error"); 27006a99fe3SHajimu UMEMOTO 27106a99fe3SHajimu UMEMOTO TRACE_OUT(accept_connection); 27206a99fe3SHajimu UMEMOTO } 27306a99fe3SHajimu UMEMOTO 27406a99fe3SHajimu UMEMOTO static void 27506a99fe3SHajimu UMEMOTO process_socket_event(struct kevent *event_data, struct runtime_env *env, 27606a99fe3SHajimu UMEMOTO struct configuration *config) 27706a99fe3SHajimu UMEMOTO { 27806a99fe3SHajimu UMEMOTO struct kevent eventlist[2]; 27906a99fe3SHajimu UMEMOTO struct timeval query_timeout; 28006a99fe3SHajimu UMEMOTO struct timespec kevent_timeout; 28106a99fe3SHajimu UMEMOTO int nevents; 28206a99fe3SHajimu UMEMOTO int eof_res, res; 28306a99fe3SHajimu UMEMOTO ssize_t io_res; 28406a99fe3SHajimu UMEMOTO struct query_state *qstate; 28506a99fe3SHajimu UMEMOTO 28606a99fe3SHajimu UMEMOTO TRACE_IN(process_socket_event); 28706a99fe3SHajimu UMEMOTO eof_res = event_data->flags & EV_EOF ? 1 : 0; 28806a99fe3SHajimu UMEMOTO res = 0; 28906a99fe3SHajimu UMEMOTO 29006a99fe3SHajimu UMEMOTO memset(&kevent_timeout, 0, sizeof(struct timespec)); 29106a99fe3SHajimu UMEMOTO EV_SET(&eventlist[0], event_data->ident, EVFILT_TIMER, EV_DELETE, 29206a99fe3SHajimu UMEMOTO 0, 0, NULL); 29306a99fe3SHajimu UMEMOTO nevents = kevent(env->queue, eventlist, 1, NULL, 0, &kevent_timeout); 29406a99fe3SHajimu UMEMOTO if (nevents == -1) { 29506a99fe3SHajimu UMEMOTO if (errno == ENOENT) { 29606a99fe3SHajimu UMEMOTO /* the timer is already handling this event */ 29706a99fe3SHajimu UMEMOTO TRACE_OUT(process_socket_event); 29806a99fe3SHajimu UMEMOTO return; 29906a99fe3SHajimu UMEMOTO } else { 30006a99fe3SHajimu UMEMOTO /* some other error happened */ 30106a99fe3SHajimu UMEMOTO LOG_ERR_2("process_socket_event", "kevent error, errno" 30206a99fe3SHajimu UMEMOTO " is %d", errno); 30306a99fe3SHajimu UMEMOTO TRACE_OUT(process_socket_event); 30406a99fe3SHajimu UMEMOTO return; 30506a99fe3SHajimu UMEMOTO } 30606a99fe3SHajimu UMEMOTO } 30706a99fe3SHajimu UMEMOTO qstate = (struct query_state *)event_data->udata; 30806a99fe3SHajimu UMEMOTO 30906a99fe3SHajimu UMEMOTO /* 31006a99fe3SHajimu UMEMOTO * If the buffer that is to be send/received is too large, 31106a99fe3SHajimu UMEMOTO * we send it implicitly, by using query_io_buffer_read and 31206a99fe3SHajimu UMEMOTO * query_io_buffer_write functions in the query_state. These functions 31306a99fe3SHajimu UMEMOTO * use the temporary buffer, which is later send/received in parts. 31406a99fe3SHajimu UMEMOTO * The code below implements buffer splitting/mergind for send/receive 31506a99fe3SHajimu UMEMOTO * operations. It also does the actual socket IO operations. 31606a99fe3SHajimu UMEMOTO */ 31706a99fe3SHajimu UMEMOTO if (((qstate->use_alternate_io == 0) && 31806a99fe3SHajimu UMEMOTO (qstate->kevent_watermark <= event_data->data)) || 31906a99fe3SHajimu UMEMOTO ((qstate->use_alternate_io != 0) && 32006a99fe3SHajimu UMEMOTO (qstate->io_buffer_watermark <= event_data->data))) { 32106a99fe3SHajimu UMEMOTO if (qstate->use_alternate_io != 0) { 32206a99fe3SHajimu UMEMOTO switch (qstate->io_buffer_filter) { 32306a99fe3SHajimu UMEMOTO case EVFILT_READ: 32406a99fe3SHajimu UMEMOTO io_res = query_socket_read(qstate, 32506a99fe3SHajimu UMEMOTO qstate->io_buffer_p, 32606a99fe3SHajimu UMEMOTO qstate->io_buffer_watermark); 32706a99fe3SHajimu UMEMOTO if (io_res < 0) { 32806a99fe3SHajimu UMEMOTO qstate->use_alternate_io = 0; 32906a99fe3SHajimu UMEMOTO qstate->process_func = NULL; 33006a99fe3SHajimu UMEMOTO } else { 33106a99fe3SHajimu UMEMOTO qstate->io_buffer_p += io_res; 33206a99fe3SHajimu UMEMOTO if (qstate->io_buffer_p == 33306a99fe3SHajimu UMEMOTO qstate->io_buffer + 33406a99fe3SHajimu UMEMOTO qstate->io_buffer_size) { 33506a99fe3SHajimu UMEMOTO qstate->io_buffer_p = 33606a99fe3SHajimu UMEMOTO qstate->io_buffer; 33706a99fe3SHajimu UMEMOTO qstate->use_alternate_io = 0; 33806a99fe3SHajimu UMEMOTO } 33906a99fe3SHajimu UMEMOTO } 34006a99fe3SHajimu UMEMOTO break; 34106a99fe3SHajimu UMEMOTO default: 34206a99fe3SHajimu UMEMOTO break; 34306a99fe3SHajimu UMEMOTO } 34406a99fe3SHajimu UMEMOTO } 34506a99fe3SHajimu UMEMOTO 34606a99fe3SHajimu UMEMOTO if (qstate->use_alternate_io == 0) { 34706a99fe3SHajimu UMEMOTO do { 34806a99fe3SHajimu UMEMOTO res = qstate->process_func(qstate); 34906a99fe3SHajimu UMEMOTO } while ((qstate->kevent_watermark == 0) && 35006a99fe3SHajimu UMEMOTO (qstate->process_func != NULL) && 35106a99fe3SHajimu UMEMOTO (res == 0)); 35206a99fe3SHajimu UMEMOTO 35306a99fe3SHajimu UMEMOTO if (res != 0) 35406a99fe3SHajimu UMEMOTO qstate->process_func = NULL; 35506a99fe3SHajimu UMEMOTO } 35606a99fe3SHajimu UMEMOTO 35706a99fe3SHajimu UMEMOTO if ((qstate->use_alternate_io != 0) && 35806a99fe3SHajimu UMEMOTO (qstate->io_buffer_filter == EVFILT_WRITE)) { 35906a99fe3SHajimu UMEMOTO io_res = query_socket_write(qstate, qstate->io_buffer_p, 36006a99fe3SHajimu UMEMOTO qstate->io_buffer_watermark); 36106a99fe3SHajimu UMEMOTO if (io_res < 0) { 36206a99fe3SHajimu UMEMOTO qstate->use_alternate_io = 0; 36306a99fe3SHajimu UMEMOTO qstate->process_func = NULL; 36406a99fe3SHajimu UMEMOTO } else 36506a99fe3SHajimu UMEMOTO qstate->io_buffer_p += io_res; 36606a99fe3SHajimu UMEMOTO } 36706a99fe3SHajimu UMEMOTO } else { 36806a99fe3SHajimu UMEMOTO /* assuming that socket was closed */ 36906a99fe3SHajimu UMEMOTO qstate->process_func = NULL; 37006a99fe3SHajimu UMEMOTO qstate->use_alternate_io = 0; 37106a99fe3SHajimu UMEMOTO } 37206a99fe3SHajimu UMEMOTO 37306a99fe3SHajimu UMEMOTO if (((qstate->process_func == NULL) && 37406a99fe3SHajimu UMEMOTO (qstate->use_alternate_io == 0)) || 37506a99fe3SHajimu UMEMOTO (eof_res != 0) || (res != 0)) { 37606a99fe3SHajimu UMEMOTO destroy_query_state(qstate); 37706a99fe3SHajimu UMEMOTO close(event_data->ident); 37806a99fe3SHajimu UMEMOTO TRACE_OUT(process_socket_event); 37906a99fe3SHajimu UMEMOTO return; 38006a99fe3SHajimu UMEMOTO } 38106a99fe3SHajimu UMEMOTO 38206a99fe3SHajimu UMEMOTO /* updating the query_state lifetime variable */ 38306a99fe3SHajimu UMEMOTO get_time_func(&query_timeout); 38406a99fe3SHajimu UMEMOTO query_timeout.tv_usec = 0; 38506a99fe3SHajimu UMEMOTO query_timeout.tv_sec -= qstate->creation_time.tv_sec; 38606a99fe3SHajimu UMEMOTO if (query_timeout.tv_sec > qstate->timeout.tv_sec) 38706a99fe3SHajimu UMEMOTO query_timeout.tv_sec = 0; 38806a99fe3SHajimu UMEMOTO else 38906a99fe3SHajimu UMEMOTO query_timeout.tv_sec = qstate->timeout.tv_sec - 39006a99fe3SHajimu UMEMOTO query_timeout.tv_sec; 39106a99fe3SHajimu UMEMOTO 39206a99fe3SHajimu UMEMOTO if ((qstate->use_alternate_io != 0) && (qstate->io_buffer_p == 39306a99fe3SHajimu UMEMOTO qstate->io_buffer + qstate->io_buffer_size)) 39406a99fe3SHajimu UMEMOTO qstate->use_alternate_io = 0; 39506a99fe3SHajimu UMEMOTO 39606a99fe3SHajimu UMEMOTO if (qstate->use_alternate_io == 0) { 39706a99fe3SHajimu UMEMOTO /* 39806a99fe3SHajimu UMEMOTO * If we must send/receive the large block of data, 39906a99fe3SHajimu UMEMOTO * we should prepare the query_state's io_XXX fields. 40006a99fe3SHajimu UMEMOTO * We should also substitute its write_func and read_func 40106a99fe3SHajimu UMEMOTO * with the query_io_buffer_write and query_io_buffer_read, 40206a99fe3SHajimu UMEMOTO * which will allow us to implicitly send/receive this large 40306a99fe3SHajimu UMEMOTO * buffer later (in the subsequent calls to the 40406a99fe3SHajimu UMEMOTO * process_socket_event). 40506a99fe3SHajimu UMEMOTO */ 40606a99fe3SHajimu UMEMOTO if (qstate->kevent_watermark > MAX_SOCKET_IO_SIZE) { 40706a99fe3SHajimu UMEMOTO if (qstate->io_buffer != NULL) 40806a99fe3SHajimu UMEMOTO free(qstate->io_buffer); 40906a99fe3SHajimu UMEMOTO 4104f7df5c2SXin LI qstate->io_buffer = (char *)calloc(1, 41106a99fe3SHajimu UMEMOTO qstate->kevent_watermark); 41206a99fe3SHajimu UMEMOTO assert(qstate->io_buffer != NULL); 41306a99fe3SHajimu UMEMOTO 41406a99fe3SHajimu UMEMOTO qstate->io_buffer_p = qstate->io_buffer; 41506a99fe3SHajimu UMEMOTO qstate->io_buffer_size = qstate->kevent_watermark; 41606a99fe3SHajimu UMEMOTO qstate->io_buffer_filter = qstate->kevent_filter; 41706a99fe3SHajimu UMEMOTO 41806a99fe3SHajimu UMEMOTO qstate->write_func = query_io_buffer_write; 41906a99fe3SHajimu UMEMOTO qstate->read_func = query_io_buffer_read; 42006a99fe3SHajimu UMEMOTO 42106a99fe3SHajimu UMEMOTO if (qstate->kevent_filter == EVFILT_READ) 42206a99fe3SHajimu UMEMOTO qstate->use_alternate_io = 1; 42306a99fe3SHajimu UMEMOTO 42406a99fe3SHajimu UMEMOTO qstate->io_buffer_watermark = MAX_SOCKET_IO_SIZE; 42506a99fe3SHajimu UMEMOTO EV_SET(&eventlist[1], event_data->ident, 42606a99fe3SHajimu UMEMOTO qstate->kevent_filter, EV_ADD | EV_ONESHOT, 42706a99fe3SHajimu UMEMOTO NOTE_LOWAT, MAX_SOCKET_IO_SIZE, qstate); 42806a99fe3SHajimu UMEMOTO } else { 42906a99fe3SHajimu UMEMOTO EV_SET(&eventlist[1], event_data->ident, 43006a99fe3SHajimu UMEMOTO qstate->kevent_filter, EV_ADD | EV_ONESHOT, 43106a99fe3SHajimu UMEMOTO NOTE_LOWAT, qstate->kevent_watermark, qstate); 43206a99fe3SHajimu UMEMOTO } 43306a99fe3SHajimu UMEMOTO } else { 43406a99fe3SHajimu UMEMOTO if (qstate->io_buffer + qstate->io_buffer_size - 43506a99fe3SHajimu UMEMOTO qstate->io_buffer_p < 43606a99fe3SHajimu UMEMOTO MAX_SOCKET_IO_SIZE) { 43706a99fe3SHajimu UMEMOTO qstate->io_buffer_watermark = qstate->io_buffer + 43806a99fe3SHajimu UMEMOTO qstate->io_buffer_size - qstate->io_buffer_p; 43906a99fe3SHajimu UMEMOTO EV_SET(&eventlist[1], event_data->ident, 44006a99fe3SHajimu UMEMOTO qstate->io_buffer_filter, 44106a99fe3SHajimu UMEMOTO EV_ADD | EV_ONESHOT, NOTE_LOWAT, 44206a99fe3SHajimu UMEMOTO qstate->io_buffer_watermark, 44306a99fe3SHajimu UMEMOTO qstate); 44406a99fe3SHajimu UMEMOTO } else { 44506a99fe3SHajimu UMEMOTO qstate->io_buffer_watermark = MAX_SOCKET_IO_SIZE; 44606a99fe3SHajimu UMEMOTO EV_SET(&eventlist[1], event_data->ident, 44706a99fe3SHajimu UMEMOTO qstate->io_buffer_filter, EV_ADD | EV_ONESHOT, 44806a99fe3SHajimu UMEMOTO NOTE_LOWAT, MAX_SOCKET_IO_SIZE, qstate); 44906a99fe3SHajimu UMEMOTO } 45006a99fe3SHajimu UMEMOTO } 45106a99fe3SHajimu UMEMOTO EV_SET(&eventlist[0], event_data->ident, EVFILT_TIMER, 45206a99fe3SHajimu UMEMOTO EV_ADD | EV_ONESHOT, 0, query_timeout.tv_sec * 1000, qstate); 45306a99fe3SHajimu UMEMOTO kevent(env->queue, eventlist, 2, NULL, 0, &kevent_timeout); 45406a99fe3SHajimu UMEMOTO 45506a99fe3SHajimu UMEMOTO TRACE_OUT(process_socket_event); 45606a99fe3SHajimu UMEMOTO } 45706a99fe3SHajimu UMEMOTO 45806a99fe3SHajimu UMEMOTO /* 45906a99fe3SHajimu UMEMOTO * This routine is called if timer event has been signaled in the kqueue. It 46006a99fe3SHajimu UMEMOTO * just closes the socket and destroys the query_state. 46106a99fe3SHajimu UMEMOTO */ 46206a99fe3SHajimu UMEMOTO static void 46306a99fe3SHajimu UMEMOTO process_timer_event(struct kevent *event_data, struct runtime_env *env, 46406a99fe3SHajimu UMEMOTO struct configuration *config) 46506a99fe3SHajimu UMEMOTO { 46606a99fe3SHajimu UMEMOTO struct query_state *qstate; 46706a99fe3SHajimu UMEMOTO 46806a99fe3SHajimu UMEMOTO TRACE_IN(process_timer_event); 46906a99fe3SHajimu UMEMOTO qstate = (struct query_state *)event_data->udata; 47006a99fe3SHajimu UMEMOTO destroy_query_state(qstate); 47106a99fe3SHajimu UMEMOTO close(event_data->ident); 47206a99fe3SHajimu UMEMOTO TRACE_OUT(process_timer_event); 47306a99fe3SHajimu UMEMOTO } 47406a99fe3SHajimu UMEMOTO 47506a99fe3SHajimu UMEMOTO /* 47606a99fe3SHajimu UMEMOTO * Processing loop is the basic processing routine, that forms a body of each 47706a99fe3SHajimu UMEMOTO * procssing thread 47806a99fe3SHajimu UMEMOTO */ 47906a99fe3SHajimu UMEMOTO static void 48006a99fe3SHajimu UMEMOTO processing_loop(cache the_cache, struct runtime_env *env, 48106a99fe3SHajimu UMEMOTO struct configuration *config) 48206a99fe3SHajimu UMEMOTO { 48306a99fe3SHajimu UMEMOTO struct timespec timeout; 48406a99fe3SHajimu UMEMOTO const int eventlist_size = 1; 48506a99fe3SHajimu UMEMOTO struct kevent eventlist[eventlist_size]; 48606a99fe3SHajimu UMEMOTO int nevents, i; 48706a99fe3SHajimu UMEMOTO 48806a99fe3SHajimu UMEMOTO TRACE_MSG("=> processing_loop"); 48906a99fe3SHajimu UMEMOTO memset(&timeout, 0, sizeof(struct timespec)); 49006a99fe3SHajimu UMEMOTO memset(&eventlist, 0, sizeof(struct kevent) * eventlist_size); 49106a99fe3SHajimu UMEMOTO 49206a99fe3SHajimu UMEMOTO for (;;) { 49306a99fe3SHajimu UMEMOTO nevents = kevent(env->queue, NULL, 0, eventlist, 49406a99fe3SHajimu UMEMOTO eventlist_size, NULL); 49506a99fe3SHajimu UMEMOTO /* 49606a99fe3SHajimu UMEMOTO * we can only receive 1 event on success 49706a99fe3SHajimu UMEMOTO */ 49806a99fe3SHajimu UMEMOTO if (nevents == 1) { 49906a99fe3SHajimu UMEMOTO struct kevent *event_data; 50006a99fe3SHajimu UMEMOTO event_data = &eventlist[0]; 50106a99fe3SHajimu UMEMOTO 50206a99fe3SHajimu UMEMOTO if (event_data->ident == env->sockfd) { 50306a99fe3SHajimu UMEMOTO for (i = 0; i < event_data->data; ++i) 50406a99fe3SHajimu UMEMOTO accept_connection(event_data, env, config); 50506a99fe3SHajimu UMEMOTO 50606a99fe3SHajimu UMEMOTO EV_SET(eventlist, s_runtime_env->sockfd, 50706a99fe3SHajimu UMEMOTO EVFILT_READ, EV_ADD | EV_ONESHOT, 50806a99fe3SHajimu UMEMOTO 0, 0, 0); 50906a99fe3SHajimu UMEMOTO memset(&timeout, 0, 51006a99fe3SHajimu UMEMOTO sizeof(struct timespec)); 51106a99fe3SHajimu UMEMOTO kevent(s_runtime_env->queue, eventlist, 51206a99fe3SHajimu UMEMOTO 1, NULL, 0, &timeout); 51306a99fe3SHajimu UMEMOTO 51406a99fe3SHajimu UMEMOTO } else { 51506a99fe3SHajimu UMEMOTO switch (event_data->filter) { 51606a99fe3SHajimu UMEMOTO case EVFILT_READ: 51706a99fe3SHajimu UMEMOTO case EVFILT_WRITE: 51806a99fe3SHajimu UMEMOTO process_socket_event(event_data, 51906a99fe3SHajimu UMEMOTO env, config); 52006a99fe3SHajimu UMEMOTO break; 52106a99fe3SHajimu UMEMOTO case EVFILT_TIMER: 52206a99fe3SHajimu UMEMOTO process_timer_event(event_data, 52306a99fe3SHajimu UMEMOTO env, config); 52406a99fe3SHajimu UMEMOTO break; 52506a99fe3SHajimu UMEMOTO default: 52606a99fe3SHajimu UMEMOTO break; 52706a99fe3SHajimu UMEMOTO } 52806a99fe3SHajimu UMEMOTO } 52906a99fe3SHajimu UMEMOTO } else { 53006a99fe3SHajimu UMEMOTO /* this branch shouldn't be currently executed */ 53106a99fe3SHajimu UMEMOTO } 53206a99fe3SHajimu UMEMOTO } 53306a99fe3SHajimu UMEMOTO 53406a99fe3SHajimu UMEMOTO TRACE_MSG("<= processing_loop"); 53506a99fe3SHajimu UMEMOTO } 53606a99fe3SHajimu UMEMOTO 53706a99fe3SHajimu UMEMOTO /* 53806a99fe3SHajimu UMEMOTO * Wrapper above the processing loop function. It sets the thread signal mask 53906a99fe3SHajimu UMEMOTO * to avoid SIGPIPE signals (which can happen if the client works incorrectly). 54006a99fe3SHajimu UMEMOTO */ 54106a99fe3SHajimu UMEMOTO static void * 54206a99fe3SHajimu UMEMOTO processing_thread(void *data) 54306a99fe3SHajimu UMEMOTO { 54406a99fe3SHajimu UMEMOTO struct processing_thread_args *args; 54506a99fe3SHajimu UMEMOTO sigset_t new; 54606a99fe3SHajimu UMEMOTO 54706a99fe3SHajimu UMEMOTO TRACE_MSG("=> processing_thread"); 54806a99fe3SHajimu UMEMOTO args = (struct processing_thread_args *)data; 54906a99fe3SHajimu UMEMOTO 55006a99fe3SHajimu UMEMOTO sigemptyset(&new); 55106a99fe3SHajimu UMEMOTO sigaddset(&new, SIGPIPE); 55206a99fe3SHajimu UMEMOTO if (pthread_sigmask(SIG_BLOCK, &new, NULL) != 0) 55306a99fe3SHajimu UMEMOTO LOG_ERR_1("processing thread", 55406a99fe3SHajimu UMEMOTO "thread can't block the SIGPIPE signal"); 55506a99fe3SHajimu UMEMOTO 55606a99fe3SHajimu UMEMOTO processing_loop(args->the_cache, args->the_runtime_env, 55706a99fe3SHajimu UMEMOTO args->the_configuration); 55806a99fe3SHajimu UMEMOTO free(args); 55906a99fe3SHajimu UMEMOTO TRACE_MSG("<= processing_thread"); 56006a99fe3SHajimu UMEMOTO 56106a99fe3SHajimu UMEMOTO return (NULL); 56206a99fe3SHajimu UMEMOTO } 56306a99fe3SHajimu UMEMOTO 56406a99fe3SHajimu UMEMOTO void 56506a99fe3SHajimu UMEMOTO get_time_func(struct timeval *time) 56606a99fe3SHajimu UMEMOTO { 56706a99fe3SHajimu UMEMOTO struct timespec res; 56806a99fe3SHajimu UMEMOTO memset(&res, 0, sizeof(struct timespec)); 56906a99fe3SHajimu UMEMOTO clock_gettime(CLOCK_MONOTONIC, &res); 57006a99fe3SHajimu UMEMOTO 57106a99fe3SHajimu UMEMOTO time->tv_sec = res.tv_sec; 57206a99fe3SHajimu UMEMOTO time->tv_usec = 0; 57306a99fe3SHajimu UMEMOTO } 57406a99fe3SHajimu UMEMOTO 57506a99fe3SHajimu UMEMOTO /* 5760309c35eSDag-Erling Smørgrav * The idea of _nss_cache_cycle_prevention_function is that nsdispatch 5770309c35eSDag-Erling Smørgrav * will search for this symbol in the executable. This symbol is the 5780309c35eSDag-Erling Smørgrav * attribute of the caching daemon. So, if it exists, nsdispatch won't try 5790309c35eSDag-Erling Smørgrav * to connect to the caching daemon and will just ignore the 'cache' 5800309c35eSDag-Erling Smørgrav * source in the nsswitch.conf. This method helps to avoid cycles and 5810309c35eSDag-Erling Smørgrav * organize self-performing requests. 5820309c35eSDag-Erling Smørgrav * 5830309c35eSDag-Erling Smørgrav * (not actually a function; it used to be, but it doesn't make any 5840309c35eSDag-Erling Smørgrav * difference, as long as it has external linkage) 58506a99fe3SHajimu UMEMOTO */ 5860309c35eSDag-Erling Smørgrav void *_nss_cache_cycle_prevention_function; 58706a99fe3SHajimu UMEMOTO 58806a99fe3SHajimu UMEMOTO int 58906a99fe3SHajimu UMEMOTO main(int argc, char *argv[]) 59006a99fe3SHajimu UMEMOTO { 59106a99fe3SHajimu UMEMOTO struct processing_thread_args *thread_args; 59206a99fe3SHajimu UMEMOTO pthread_t *threads; 59306a99fe3SHajimu UMEMOTO 59406a99fe3SHajimu UMEMOTO struct pidfh *pidfile; 59506a99fe3SHajimu UMEMOTO pid_t pid; 59606a99fe3SHajimu UMEMOTO 59706a99fe3SHajimu UMEMOTO char const *config_file; 59806a99fe3SHajimu UMEMOTO char const *error_str; 59906a99fe3SHajimu UMEMOTO int error_line; 60006a99fe3SHajimu UMEMOTO int i, res; 60106a99fe3SHajimu UMEMOTO 60206a99fe3SHajimu UMEMOTO int trace_mode_enabled; 60306a99fe3SHajimu UMEMOTO int force_single_threaded; 60406a99fe3SHajimu UMEMOTO int do_not_daemonize; 60506a99fe3SHajimu UMEMOTO int clear_user_cache_entries, clear_all_cache_entries; 60606a99fe3SHajimu UMEMOTO char *user_config_entry_name, *global_config_entry_name; 60706a99fe3SHajimu UMEMOTO int show_statistics; 60806a99fe3SHajimu UMEMOTO int daemon_mode, interactive_mode; 60906a99fe3SHajimu UMEMOTO 61006a99fe3SHajimu UMEMOTO 61106a99fe3SHajimu UMEMOTO /* by default all debug messages are omitted */ 61206a99fe3SHajimu UMEMOTO TRACE_OFF(); 61306a99fe3SHajimu UMEMOTO 61406a99fe3SHajimu UMEMOTO /* parsing command line arguments */ 61506a99fe3SHajimu UMEMOTO trace_mode_enabled = 0; 61606a99fe3SHajimu UMEMOTO force_single_threaded = 0; 61706a99fe3SHajimu UMEMOTO do_not_daemonize = 0; 61806a99fe3SHajimu UMEMOTO clear_user_cache_entries = 0; 61906a99fe3SHajimu UMEMOTO clear_all_cache_entries = 0; 62006a99fe3SHajimu UMEMOTO show_statistics = 0; 62106a99fe3SHajimu UMEMOTO user_config_entry_name = NULL; 62206a99fe3SHajimu UMEMOTO global_config_entry_name = NULL; 62306a99fe3SHajimu UMEMOTO while ((res = getopt(argc, argv, "nstdi:I:")) != -1) { 62406a99fe3SHajimu UMEMOTO switch (res) { 62506a99fe3SHajimu UMEMOTO case 'n': 62606a99fe3SHajimu UMEMOTO do_not_daemonize = 1; 62706a99fe3SHajimu UMEMOTO break; 62806a99fe3SHajimu UMEMOTO case 's': 62906a99fe3SHajimu UMEMOTO force_single_threaded = 1; 63006a99fe3SHajimu UMEMOTO break; 63106a99fe3SHajimu UMEMOTO case 't': 63206a99fe3SHajimu UMEMOTO trace_mode_enabled = 1; 63306a99fe3SHajimu UMEMOTO break; 63406a99fe3SHajimu UMEMOTO case 'i': 63506a99fe3SHajimu UMEMOTO clear_user_cache_entries = 1; 63606a99fe3SHajimu UMEMOTO if (optarg != NULL) 63706a99fe3SHajimu UMEMOTO if (strcmp(optarg, "all") != 0) 63806a99fe3SHajimu UMEMOTO user_config_entry_name = strdup(optarg); 63906a99fe3SHajimu UMEMOTO break; 64006a99fe3SHajimu UMEMOTO case 'I': 64106a99fe3SHajimu UMEMOTO clear_all_cache_entries = 1; 64206a99fe3SHajimu UMEMOTO if (optarg != NULL) 64306a99fe3SHajimu UMEMOTO if (strcmp(optarg, "all") != 0) 64406a99fe3SHajimu UMEMOTO global_config_entry_name = 64506a99fe3SHajimu UMEMOTO strdup(optarg); 64606a99fe3SHajimu UMEMOTO break; 64706a99fe3SHajimu UMEMOTO case 'd': 64806a99fe3SHajimu UMEMOTO show_statistics = 1; 64906a99fe3SHajimu UMEMOTO break; 65006a99fe3SHajimu UMEMOTO case '?': 65106a99fe3SHajimu UMEMOTO default: 65206a99fe3SHajimu UMEMOTO usage(); 65306a99fe3SHajimu UMEMOTO /* NOT REACHED */ 65406a99fe3SHajimu UMEMOTO } 65506a99fe3SHajimu UMEMOTO } 65606a99fe3SHajimu UMEMOTO 65706a99fe3SHajimu UMEMOTO daemon_mode = do_not_daemonize | force_single_threaded | 65806a99fe3SHajimu UMEMOTO trace_mode_enabled; 65906a99fe3SHajimu UMEMOTO interactive_mode = clear_user_cache_entries | clear_all_cache_entries | 66006a99fe3SHajimu UMEMOTO show_statistics; 66106a99fe3SHajimu UMEMOTO 66206a99fe3SHajimu UMEMOTO if ((daemon_mode != 0) && (interactive_mode != 0)) { 66306a99fe3SHajimu UMEMOTO LOG_ERR_1("main", "daemon mode and interactive_mode arguments " 66406a99fe3SHajimu UMEMOTO "can't be used together"); 66506a99fe3SHajimu UMEMOTO usage(); 66606a99fe3SHajimu UMEMOTO } 66706a99fe3SHajimu UMEMOTO 66806a99fe3SHajimu UMEMOTO if (interactive_mode != 0) { 66906a99fe3SHajimu UMEMOTO FILE *pidfin = fopen(DEFAULT_PIDFILE_PATH, "r"); 67006a99fe3SHajimu UMEMOTO char pidbuf[256]; 67106a99fe3SHajimu UMEMOTO 672db1bdf2bSMichael Bushkov struct nscd_connection_params connection_params; 673db1bdf2bSMichael Bushkov nscd_connection connection; 67406a99fe3SHajimu UMEMOTO 67506a99fe3SHajimu UMEMOTO int result; 67606a99fe3SHajimu UMEMOTO 67706a99fe3SHajimu UMEMOTO if (pidfin == NULL) 67806a99fe3SHajimu UMEMOTO errx(EXIT_FAILURE, "There is no daemon running."); 67906a99fe3SHajimu UMEMOTO 68006a99fe3SHajimu UMEMOTO memset(pidbuf, 0, sizeof(pidbuf)); 68106a99fe3SHajimu UMEMOTO fread(pidbuf, sizeof(pidbuf) - 1, 1, pidfin); 68206a99fe3SHajimu UMEMOTO fclose(pidfin); 68306a99fe3SHajimu UMEMOTO 68406a99fe3SHajimu UMEMOTO if (ferror(pidfin) != 0) 68506a99fe3SHajimu UMEMOTO errx(EXIT_FAILURE, "Can't read from pidfile."); 68606a99fe3SHajimu UMEMOTO 68706a99fe3SHajimu UMEMOTO if (sscanf(pidbuf, "%d", &pid) != 1) 68806a99fe3SHajimu UMEMOTO errx(EXIT_FAILURE, "Invalid pidfile."); 68906a99fe3SHajimu UMEMOTO LOG_MSG_1("main", "daemon PID is %d", pid); 69006a99fe3SHajimu UMEMOTO 69106a99fe3SHajimu UMEMOTO 69206a99fe3SHajimu UMEMOTO memset(&connection_params, 0, 693db1bdf2bSMichael Bushkov sizeof(struct nscd_connection_params)); 69406a99fe3SHajimu UMEMOTO connection_params.socket_path = DEFAULT_SOCKET_PATH; 695db1bdf2bSMichael Bushkov connection = open_nscd_connection__(&connection_params); 696db1bdf2bSMichael Bushkov if (connection == INVALID_NSCD_CONNECTION) 69706a99fe3SHajimu UMEMOTO errx(EXIT_FAILURE, "Can't connect to the daemon."); 69806a99fe3SHajimu UMEMOTO 69906a99fe3SHajimu UMEMOTO if (clear_user_cache_entries != 0) { 700db1bdf2bSMichael Bushkov result = nscd_transform__(connection, 70106a99fe3SHajimu UMEMOTO user_config_entry_name, TT_USER); 70206a99fe3SHajimu UMEMOTO if (result != 0) 70306a99fe3SHajimu UMEMOTO LOG_MSG_1("main", 70406a99fe3SHajimu UMEMOTO "user cache transformation failed"); 70506a99fe3SHajimu UMEMOTO else 70606a99fe3SHajimu UMEMOTO LOG_MSG_1("main", 70706a99fe3SHajimu UMEMOTO "user cache_transformation " 70806a99fe3SHajimu UMEMOTO "succeeded"); 70906a99fe3SHajimu UMEMOTO } 71006a99fe3SHajimu UMEMOTO 71106a99fe3SHajimu UMEMOTO if (clear_all_cache_entries != 0) { 71206a99fe3SHajimu UMEMOTO if (geteuid() != 0) 71306a99fe3SHajimu UMEMOTO errx(EXIT_FAILURE, "Only root can initiate " 71406a99fe3SHajimu UMEMOTO "global cache transformation."); 71506a99fe3SHajimu UMEMOTO 716db1bdf2bSMichael Bushkov result = nscd_transform__(connection, 71706a99fe3SHajimu UMEMOTO global_config_entry_name, TT_ALL); 71806a99fe3SHajimu UMEMOTO if (result != 0) 71906a99fe3SHajimu UMEMOTO LOG_MSG_1("main", 72006a99fe3SHajimu UMEMOTO "global cache transformation " 72106a99fe3SHajimu UMEMOTO "failed"); 72206a99fe3SHajimu UMEMOTO else 72306a99fe3SHajimu UMEMOTO LOG_MSG_1("main", 72406a99fe3SHajimu UMEMOTO "global cache transformation " 72506a99fe3SHajimu UMEMOTO "succeeded"); 72606a99fe3SHajimu UMEMOTO } 72706a99fe3SHajimu UMEMOTO 728db1bdf2bSMichael Bushkov close_nscd_connection__(connection); 72906a99fe3SHajimu UMEMOTO 73006a99fe3SHajimu UMEMOTO free(user_config_entry_name); 73106a99fe3SHajimu UMEMOTO free(global_config_entry_name); 73206a99fe3SHajimu UMEMOTO return (EXIT_SUCCESS); 73306a99fe3SHajimu UMEMOTO } 73406a99fe3SHajimu UMEMOTO 73506a99fe3SHajimu UMEMOTO pidfile = pidfile_open(DEFAULT_PIDFILE_PATH, 0644, &pid); 73606a99fe3SHajimu UMEMOTO if (pidfile == NULL) { 73706a99fe3SHajimu UMEMOTO if (errno == EEXIST) 73806a99fe3SHajimu UMEMOTO errx(EXIT_FAILURE, "Daemon already running, pid: %d.", 73906a99fe3SHajimu UMEMOTO pid); 74006a99fe3SHajimu UMEMOTO warn("Cannot open or create pidfile"); 74106a99fe3SHajimu UMEMOTO } 74206a99fe3SHajimu UMEMOTO 74306a99fe3SHajimu UMEMOTO if (trace_mode_enabled == 1) 74406a99fe3SHajimu UMEMOTO TRACE_ON(); 74506a99fe3SHajimu UMEMOTO 74606a99fe3SHajimu UMEMOTO /* blocking the main thread from receiving SIGPIPE signal */ 74706a99fe3SHajimu UMEMOTO sigblock(sigmask(SIGPIPE)); 74806a99fe3SHajimu UMEMOTO 74906a99fe3SHajimu UMEMOTO /* daemonization */ 75006a99fe3SHajimu UMEMOTO if (do_not_daemonize == 0) { 75106a99fe3SHajimu UMEMOTO res = daemon(0, trace_mode_enabled == 0 ? 0 : 1); 75206a99fe3SHajimu UMEMOTO if (res != 0) { 75306a99fe3SHajimu UMEMOTO LOG_ERR_1("main", "can't daemonize myself: %s", 75406a99fe3SHajimu UMEMOTO strerror(errno)); 75506a99fe3SHajimu UMEMOTO pidfile_remove(pidfile); 75606a99fe3SHajimu UMEMOTO goto fin; 75706a99fe3SHajimu UMEMOTO } else 75806a99fe3SHajimu UMEMOTO LOG_MSG_1("main", "successfully daemonized"); 75906a99fe3SHajimu UMEMOTO } 76006a99fe3SHajimu UMEMOTO 76106a99fe3SHajimu UMEMOTO pidfile_write(pidfile); 76206a99fe3SHajimu UMEMOTO 76306a99fe3SHajimu UMEMOTO s_agent_table = init_agent_table(); 76406a99fe3SHajimu UMEMOTO register_agent(s_agent_table, init_passwd_agent()); 76506a99fe3SHajimu UMEMOTO register_agent(s_agent_table, init_passwd_mp_agent()); 76606a99fe3SHajimu UMEMOTO register_agent(s_agent_table, init_group_agent()); 76706a99fe3SHajimu UMEMOTO register_agent(s_agent_table, init_group_mp_agent()); 76806a99fe3SHajimu UMEMOTO register_agent(s_agent_table, init_services_agent()); 76906a99fe3SHajimu UMEMOTO register_agent(s_agent_table, init_services_mp_agent()); 77006a99fe3SHajimu UMEMOTO LOG_MSG_1("main", "request agents registered successfully"); 77106a99fe3SHajimu UMEMOTO 77206a99fe3SHajimu UMEMOTO /* 77306a99fe3SHajimu UMEMOTO * Hosts agent can't work properly until we have access to the 77406a99fe3SHajimu UMEMOTO * appropriate dtab structures, which are used in nsdispatch 77506a99fe3SHajimu UMEMOTO * calls 77606a99fe3SHajimu UMEMOTO * 77706a99fe3SHajimu UMEMOTO register_agent(s_agent_table, init_hosts_agent()); 77806a99fe3SHajimu UMEMOTO */ 77906a99fe3SHajimu UMEMOTO 78006a99fe3SHajimu UMEMOTO /* configuration initialization */ 78106a99fe3SHajimu UMEMOTO s_configuration = init_configuration(); 78206a99fe3SHajimu UMEMOTO fill_configuration_defaults(s_configuration); 78306a99fe3SHajimu UMEMOTO 78406a99fe3SHajimu UMEMOTO error_str = NULL; 78506a99fe3SHajimu UMEMOTO error_line = 0; 78606a99fe3SHajimu UMEMOTO config_file = CONFIG_PATH; 78706a99fe3SHajimu UMEMOTO 78806a99fe3SHajimu UMEMOTO res = parse_config_file(s_configuration, config_file, &error_str, 78906a99fe3SHajimu UMEMOTO &error_line); 79006a99fe3SHajimu UMEMOTO if ((res != 0) && (error_str == NULL)) { 79106a99fe3SHajimu UMEMOTO config_file = DEFAULT_CONFIG_PATH; 79206a99fe3SHajimu UMEMOTO res = parse_config_file(s_configuration, config_file, 79306a99fe3SHajimu UMEMOTO &error_str, &error_line); 79406a99fe3SHajimu UMEMOTO } 79506a99fe3SHajimu UMEMOTO 79606a99fe3SHajimu UMEMOTO if (res != 0) { 79706a99fe3SHajimu UMEMOTO if (error_str != NULL) { 79806a99fe3SHajimu UMEMOTO LOG_ERR_1("main", "error in configuration file(%s, %d): %s\n", 79906a99fe3SHajimu UMEMOTO config_file, error_line, error_str); 80006a99fe3SHajimu UMEMOTO } else { 80106a99fe3SHajimu UMEMOTO LOG_ERR_1("main", "no configuration file found " 80206a99fe3SHajimu UMEMOTO "- was looking for %s and %s", 80306a99fe3SHajimu UMEMOTO CONFIG_PATH, DEFAULT_CONFIG_PATH); 80406a99fe3SHajimu UMEMOTO } 80506a99fe3SHajimu UMEMOTO destroy_configuration(s_configuration); 80606a99fe3SHajimu UMEMOTO return (-1); 80706a99fe3SHajimu UMEMOTO } 80806a99fe3SHajimu UMEMOTO 80906a99fe3SHajimu UMEMOTO if (force_single_threaded == 1) 81006a99fe3SHajimu UMEMOTO s_configuration->threads_num = 1; 81106a99fe3SHajimu UMEMOTO 81206a99fe3SHajimu UMEMOTO /* cache initialization */ 81306a99fe3SHajimu UMEMOTO s_cache = init_cache_(s_configuration); 81406a99fe3SHajimu UMEMOTO if (s_cache == NULL) { 81506a99fe3SHajimu UMEMOTO LOG_ERR_1("main", "can't initialize the cache"); 81606a99fe3SHajimu UMEMOTO destroy_configuration(s_configuration); 81706a99fe3SHajimu UMEMOTO return (-1); 81806a99fe3SHajimu UMEMOTO } 81906a99fe3SHajimu UMEMOTO 82006a99fe3SHajimu UMEMOTO /* runtime environment initialization */ 82106a99fe3SHajimu UMEMOTO s_runtime_env = init_runtime_env(s_configuration); 82206a99fe3SHajimu UMEMOTO if (s_runtime_env == NULL) { 82306a99fe3SHajimu UMEMOTO LOG_ERR_1("main", "can't initialize the runtime environment"); 82406a99fe3SHajimu UMEMOTO destroy_configuration(s_configuration); 82506a99fe3SHajimu UMEMOTO destroy_cache_(s_cache); 82606a99fe3SHajimu UMEMOTO return (-1); 82706a99fe3SHajimu UMEMOTO } 82806a99fe3SHajimu UMEMOTO 82906a99fe3SHajimu UMEMOTO if (s_configuration->threads_num > 1) { 8304f7df5c2SXin LI threads = (pthread_t *)calloc(1, sizeof(pthread_t) * 83106a99fe3SHajimu UMEMOTO s_configuration->threads_num); 83206a99fe3SHajimu UMEMOTO for (i = 0; i < s_configuration->threads_num; ++i) { 83306a99fe3SHajimu UMEMOTO thread_args = (struct processing_thread_args *)malloc( 83406a99fe3SHajimu UMEMOTO sizeof(struct processing_thread_args)); 83506a99fe3SHajimu UMEMOTO thread_args->the_cache = s_cache; 83606a99fe3SHajimu UMEMOTO thread_args->the_runtime_env = s_runtime_env; 83706a99fe3SHajimu UMEMOTO thread_args->the_configuration = s_configuration; 83806a99fe3SHajimu UMEMOTO 83906a99fe3SHajimu UMEMOTO LOG_MSG_1("main", "thread #%d was successfully created", 84006a99fe3SHajimu UMEMOTO i); 84106a99fe3SHajimu UMEMOTO pthread_create(&threads[i], NULL, processing_thread, 84206a99fe3SHajimu UMEMOTO thread_args); 84306a99fe3SHajimu UMEMOTO 84406a99fe3SHajimu UMEMOTO thread_args = NULL; 84506a99fe3SHajimu UMEMOTO } 84606a99fe3SHajimu UMEMOTO 84706a99fe3SHajimu UMEMOTO for (i = 0; i < s_configuration->threads_num; ++i) 84806a99fe3SHajimu UMEMOTO pthread_join(threads[i], NULL); 84906a99fe3SHajimu UMEMOTO } else { 85006a99fe3SHajimu UMEMOTO LOG_MSG_1("main", "working in single-threaded mode"); 85106a99fe3SHajimu UMEMOTO processing_loop(s_cache, s_runtime_env, s_configuration); 85206a99fe3SHajimu UMEMOTO } 85306a99fe3SHajimu UMEMOTO 85406a99fe3SHajimu UMEMOTO fin: 85506a99fe3SHajimu UMEMOTO /* runtime environment destruction */ 85606a99fe3SHajimu UMEMOTO destroy_runtime_env(s_runtime_env); 85706a99fe3SHajimu UMEMOTO 85806a99fe3SHajimu UMEMOTO /* cache destruction */ 85906a99fe3SHajimu UMEMOTO destroy_cache_(s_cache); 86006a99fe3SHajimu UMEMOTO 86106a99fe3SHajimu UMEMOTO /* configuration destruction */ 86206a99fe3SHajimu UMEMOTO destroy_configuration(s_configuration); 86306a99fe3SHajimu UMEMOTO 86406a99fe3SHajimu UMEMOTO /* agents table destruction */ 86506a99fe3SHajimu UMEMOTO destroy_agent_table(s_agent_table); 86606a99fe3SHajimu UMEMOTO 86706a99fe3SHajimu UMEMOTO pidfile_remove(pidfile); 86806a99fe3SHajimu UMEMOTO return (EXIT_SUCCESS); 86906a99fe3SHajimu UMEMOTO } 870