1 /*
2 * SysDB - src/tools/sysdbd/main.c
3 * Copyright (C) 2012 Sebastian 'tokkee' Harl <sh@tokkee.org>
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
16 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
17 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
18 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR
19 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
20 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
22 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
23 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
24 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
25 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
28 #if HAVE_CONFIG_H
29 # include "config.h"
30 #endif /* HAVE_CONFIG_H */
32 #include "sysdb.h"
33 #include "core/plugin.h"
34 #include "core/store.h"
35 #include "utils/error.h"
37 #include "frontend/connection.h"
38 #include "frontend/sock.h"
40 #include "tools/sysdbd/configfile.h"
42 #if HAVE_LIBGEN_H
43 # include <libgen.h>
44 #else /* HAVE_LIBGEN_H */
45 # define basename(path) (path)
46 #endif /* ! HAVE_LIBGEN_H */
48 #include <errno.h>
50 #include <sys/stat.h>
51 #include <fcntl.h>
53 #include <signal.h>
55 #include <stdio.h>
56 #include <stdlib.h>
57 #include <string.h>
59 #include <unistd.h>
61 #include <pthread.h>
63 #ifndef CONFIGFILE
64 # define CONFIGFILE SYSCONFDIR"/sysdb/sysdbd.conf"
65 #endif
67 #ifndef DEFAULT_SOCKET
68 # define DEFAULT_SOCKET "unix:"LOCALSTATEDIR"/run/sysdbd.sock"
69 #endif
71 static sdb_plugin_loop_t plugin_main_loop = SDB_PLUGIN_LOOP_INIT;
72 static sdb_fe_loop_t frontend_main_loop = SDB_FE_LOOP_INIT;
74 static char *default_listen_addresses[] = {
75 DEFAULT_SOCKET,
76 };
78 static void
79 sigintterm_handler(int __attribute__((unused)) signo)
80 {
81 frontend_main_loop.do_loop = 0;
82 } /* sigintterm_handler */
84 static void
85 exit_usage(char *name, int status)
86 {
87 printf(
88 "Usage: %s <options>\n"
90 "\nOptions:\n"
91 " -C FILE the main configuration file\n"
92 " default: "CONFIGFILE"\n"
93 " -D do not run in background (daemonize)\n"
94 "\n"
95 " -h display this help and exit\n"
96 " -V display the version number and copyright\n"
98 "\nSysDB daemon "SDB_VERSION_STRING SDB_VERSION_EXTRA", "PACKAGE_URL"\n",
99 basename(name));
100 exit(status);
101 } /* exit_usage */
103 static void
104 exit_version(void)
105 {
106 printf("SysDBd version "SDB_VERSION_STRING SDB_VERSION_EXTRA", "
107 "built "BUILD_DATE"\n"
108 "using libsysdb version %s%s\n"
109 "Copyright (C) 2012-2014 "PACKAGE_MAINTAINER"\n"
111 "\nThis is free software under the terms of the BSD license, see "
112 "the source for\ncopying conditions. There is NO WARRANTY; not "
113 "even for MERCHANTABILITY or\nFITNESS FOR A PARTICULAR "
114 "PURPOSE.\n", sdb_version_string(), sdb_version_extra());
115 exit(0);
116 } /* exit_version */
118 static int
119 daemonize(void)
120 {
121 pid_t pid;
123 if ((pid = fork()) < 0) {
124 char errbuf[1024];
125 sdb_log(SDB_LOG_ERR, "Failed to fork to background: %s",
126 sdb_strerror(errno, errbuf, sizeof(errbuf)));
127 return errno;
128 }
129 else if (pid != 0) {
130 /* parent */
131 exit(0);
132 }
134 if (chdir("/")) {
135 char errbuf[1024];
136 sdb_log(SDB_LOG_ERR, "Failed to change working directory to "
137 "the root directory: %s",
138 sdb_strerror(errno, errbuf, sizeof(errbuf)));
139 return errno;
140 }
142 /* detach from session */
143 setsid();
145 close(0);
146 if (open("/dev/null", O_RDWR)) {
147 char errbuf[1024];
148 sdb_log(SDB_LOG_ERR, "Failed to connect stdin to '/dev/null': %s",
149 sdb_strerror(errno, errbuf, sizeof(errbuf)));
150 return errno;
151 }
153 close(1);
154 if (dup(0) != 1) {
155 char errbuf[1024];
156 sdb_log(SDB_LOG_ERR, "Could not connect stdout to '/dev/null': %s",
157 sdb_strerror(errno, errbuf, sizeof(errbuf)));
158 return errno;
159 }
161 close(2);
162 if (dup(0) != 2) {
163 char errbuf[1024];
164 sdb_log(SDB_LOG_ERR, "Could not connect stderr to '/dev/null': %s",
165 sdb_strerror(errno, errbuf, sizeof(errbuf)));
166 return errno;
167 }
168 return 0;
169 } /* daemonize */
171 static void *
172 backend_handler(void __attribute__((unused)) *data)
173 {
174 sdb_plugin_collector_loop(&plugin_main_loop);
175 sdb_log(SDB_LOG_INFO, "Shutting down backend thread");
176 return NULL;
177 } /* backend_handler */
179 int
180 main(int argc, char **argv)
181 {
182 char *config_filename = NULL;
183 _Bool do_daemonize = 1;
185 pthread_t backend_thread;
187 struct sigaction sa_intterm;
188 int status;
190 sdb_error_set_logger(sdb_plugin_log);
192 while (42) {
193 int opt = getopt(argc, argv, "C:DhV");
195 if (-1 == opt)
196 break;
198 switch (opt) {
199 case 'C':
200 config_filename = optarg;
201 break;
202 case 'D':
203 do_daemonize = 0;
204 break;
206 case 'h':
207 exit_usage(argv[0], 0);
208 break;
209 case 'V':
210 exit_version();
211 break;
212 default:
213 exit_usage(argv[0], 1);
214 }
215 }
217 if (optind < argc)
218 exit_usage(argv[0], 1);
220 if (! config_filename)
221 config_filename = CONFIGFILE;
223 if ((status = daemon_parse_config(config_filename))) {
224 if (status > 0)
225 sdb_log(SDB_LOG_ERR, "Failed to parse configuration file.");
226 else
227 sdb_log(SDB_LOG_ERR, "Failed to load configuration file.\n"
228 "\tCheck other error messages for details.");
229 exit(1);
230 }
232 if (! listen_addresses) {
233 listen_addresses = default_listen_addresses;
234 listen_addresses_num = SDB_STATIC_ARRAY_LEN(default_listen_addresses);
235 }
237 memset(&sa_intterm, 0, sizeof(sa_intterm));
238 sa_intterm.sa_handler = sigintterm_handler;
239 sa_intterm.sa_flags = 0;
241 if (sigaction(SIGINT, &sa_intterm, /* old action */ NULL)) {
242 char errbuf[1024];
243 sdb_log(SDB_LOG_ERR, "Failed to install signal handler for "
244 "SIGINT: %s", sdb_strerror(errno, errbuf, sizeof(errbuf)));
245 exit(1);
246 }
247 if (sigaction(SIGTERM, &sa_intterm, /* old action */ NULL)) {
248 char errbuf[1024];
249 sdb_log(SDB_LOG_ERR, "Failed to install signal handler for "
250 "SIGTERM: %s", sdb_strerror(errno, errbuf, sizeof(errbuf)));
251 exit(1);
252 }
254 if (do_daemonize)
255 if (daemonize())
256 exit(1);
258 sdb_log(SDB_LOG_INFO, "SysDB daemon "SDB_VERSION_STRING
259 SDB_VERSION_EXTRA " (pid %i) initialized successfully",
260 (int)getpid());
262 sdb_plugin_init_all();
263 plugin_main_loop.default_interval = SECS_TO_SDB_TIME(60);
265 /* ignore, we see this, for example, if a client disconnects without
266 * closing the connection cleanly */
267 signal(SIGPIPE, SIG_IGN);
269 memset(&backend_thread, 0, sizeof(backend_thread));
270 if (pthread_create(&backend_thread, /* attr = */ NULL,
271 backend_handler, /* arg = */ NULL)) {
272 char buf[1024];
273 sdb_log(SDB_LOG_ERR, "Failed to create backend handler thread: %s",
274 sdb_strerror(errno, buf, sizeof(buf)));
276 plugin_main_loop.do_loop = 0;
277 }
278 else {
279 size_t i;
281 sdb_fe_socket_t *sock = sdb_fe_sock_create();
282 for (i = 0; i < listen_addresses_num; ++i)
283 if (sdb_fe_sock_add_listener(sock, listen_addresses[i]))
284 break;
286 sdb_connection_enable_logging();
288 /* break on error */
289 if (i >= listen_addresses_num)
290 sdb_fe_sock_listen_and_serve(sock, &frontend_main_loop);
292 sdb_log(SDB_LOG_INFO, "Waiting for backend thread to terminate");
293 plugin_main_loop.do_loop = 0;
294 pthread_kill(backend_thread, SIGINT);
295 pthread_join(backend_thread, NULL);
296 sdb_fe_sock_destroy(sock);
297 }
299 sdb_log(SDB_LOG_INFO, "Shutting down SysDB daemon "SDB_VERSION_STRING
300 SDB_VERSION_EXTRA" (pid %i)", (int)getpid());
301 return 0;
302 } /* main */
304 /* vim: set tw=78 sw=4 ts=4 noexpandtab : */