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