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