]> jfr.im git - irc/evilnet/x3.git/blame - src/main.c
Improve the hidden/undocumented 'modes' trace criteria, and document it'
[irc/evilnet/x3.git] / src / main.c
CommitLineData
7637f48f 1/* main.c - X3
1136f709 2 * Copyright 2000-2006 srvx Development Team
d76ed9a9 3 *
1136f709 4 * This file is part of X3.
d76ed9a9 5 *
1136f709 6 * srvx is free software; you can redistribute it and/or modify
d76ed9a9 7 * it under the terms of the GNU General Public License as published by
be2c97a5 8 * the Free Software Foundation; either version 3 of the License, or
d76ed9a9 9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with srvx; if not, write to the Free Software Foundation,
18 * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
19 */
20
ceafd592 21#define PID_FILE "x3.pid"
d76ed9a9 22
23#include "conf.h"
24#include "gline.h"
25#include "ioset.h"
26#include "modcmd.h"
27#include "saxdb.h"
1136f709 28#include "mail.h"
d76ed9a9 29#include "timeq.h"
1136f709 30#include "sar.h"
31#include "shun.h"
d76ed9a9 32
33#include "chanserv.h"
34#include "global.h"
35#include "modules.h"
36#include "opserv.h"
37c8e812 37#include "spamserv.h"
d76ed9a9 38
39#ifdef HAVE_GETOPT_H
40#include <getopt.h>
41#else
42#include "getopt.h"
43#endif
44#ifdef HAVE_SYS_RESOURCE_H
45#include <sys/resource.h>
46#endif
47#ifdef HAVE_NETINET_IN_H
48#include <netinet/in.h>
49#endif
50#ifdef HAVE_SYS_SOCKET_H
51#include <sys/socket.h>
52#endif
53#ifdef HAVE_SYS_WAIT_H
54#include <sys/wait.h>
55#endif
56
1136f709 57#include "main-common.c"
d76ed9a9 58
59void sigaction_writedb(int x)
60{
61#ifndef HAVE_STRSIGNAL
62 log_module(MAIN_LOG, LOG_INFO, "Signal %d -- writing databases.", x);
63#else
64 log_module(MAIN_LOG, LOG_INFO, "%s -- writing databases.", strsignal(x));
65#endif
66 do_write_dbs = 1;
67}
68
69void sigaction_exit(int x)
70{
71#ifndef HAVE_STRSIGNAL
72 log_module(MAIN_LOG, LOG_INFO, "Signal %d -- exiting.", x);
73#else
74 log_module(MAIN_LOG, LOG_INFO, "%s -- exiting.", strsignal(x));
75#endif
76 irc_squit(self, "Exiting on signal from console.", NULL);
77 quit_services = 1;
78}
79
80void sigaction_wait(UNUSED_ARG(int x))
81{
82 int code;
83 wait4(-1, &code, WNOHANG, NULL);
84}
85
86void sigaction_rehash(int x)
87{
88#ifndef HAVE_STRSIGNAL
89 log_module(MAIN_LOG, LOG_INFO, "Signal %d -- rehashing.", x);
90#else
91 log_module(MAIN_LOG, LOG_INFO, "%s -- rehashing.", strsignal(x));
92#endif
93 do_reopen = 1;
94}
95
d76ed9a9 96#if WITH_MALLOC_BOEHM_GC
97void
98gc_warn_proc(char *msg, GC_word arg)
99{
100 log_module(MAIN_LOG, LOG_ERROR, "GC(%p): %s", (void*)arg, msg);
101}
102#endif
103
104int main(int argc, char *argv[])
105{
1136f709 106 int run_as_daemon;
107 int debug;
d76ed9a9 108 pid_t pid = 0;
109 FILE *file_out;
110 struct sigaction sv;
111
0d16e639 112#if WITH_MALLOC_BOEHM_GC
113 GC_find_leak = 1;
114 GC_set_warn_proc(gc_warn_proc);
115 GC_enable_incremental();
116#endif
117
c3211b62
AS
118 chdir(PREFIX);
119 log_module(MAIN_LOG, LOG_INFO, "changed to %s\n", PREFIX);
1136f709 120 run_as_daemon = 1;
d76ed9a9 121 debug = 0;
122 tools_init();
123
124 /* set up some signal handlers */
125 memset(&sv, 0, sizeof(sv));
126 sigemptyset(&sv.sa_mask);
127 sv.sa_handler = SIG_IGN;
128 sigaction(SIGPIPE, &sv, NULL);
129 sv.sa_handler = sigaction_rehash;
130 sigaction(SIGHUP, &sv, NULL);
131 sv.sa_handler = sigaction_writedb;
132 sigaction(SIGINT, &sv, NULL);
133 sv.sa_handler = sigaction_exit;
134 sigaction(SIGQUIT, &sv, NULL);
135 sv.sa_handler = sigaction_wait;
136 sigaction(SIGCHLD, &sv, NULL);
137
138 if (argc > 1) { /* parse command line, if any */
1136f709 139 int c;
140 struct option options[] =
141 {
142 {"config", 1, 0, 'c'},
d76ed9a9 143 {"debug", 0, 0, 'd'},
1136f709 144 {"foreground", 0, 0, 'f'},
145 {"help", 0, 0, 'h'},
146 {"check", 0, 0, 'k'},
d76ed9a9 147 {"replay", 1, 0, 'r'},
1136f709 148 {"version", 0, 0, 'v'},
149 {0, 0, 0, 0}
150 };
151
152 while ((c = getopt_long(argc, argv, "c:dfhkr:v", options, NULL)) != -1) {
153 switch (c) {
154 case 'c':
155 services_config = optarg;
156 break;
157 case 'k':
158 if (conf_read(services_config)) {
159 printf("%s appears to be a valid configuration file.\n", services_config);
160 } else {
161 printf("%s is an invalid configuration file.\n", services_config);
162 }
163 exit(0);
d76ed9a9 164 case 'r':
165 replay_file = fopen(optarg, "r");
166 if (!replay_file) {
167 fprintf(stderr, "Could not open %s for reading: %s (%d)\n",
168 optarg, strerror(errno), errno);
169 exit(0);
170 }
171 break;
172 case 'd':
173 debug = 1;
174 break;
1136f709 175 case 'f':
176 run_as_daemon = 0;
177 break;
178 case 'v':
179 version();
180 license();
181 exit(0);
182 case 'h':
183 default:
184 usage(argv[0]);
185 exit(0);
186 }
187 }
d76ed9a9 188 }
189
190 version();
191
192 if (replay_file) {
193 /* We read a line here to "prime" the replay file parser, but
194 * mostly to get the right value of "now" for when we do the
195 * irc_introduce. */
196 replay_read_line();
d76ed9a9 197 } else {
1136f709 198 now = time(NULL);
d76ed9a9 199 }
1136f709 200 boot_time = now;
d76ed9a9 201
1136f709 202 fprintf(stdout, "Initializing daemon...\n");
d76ed9a9 203 if (!conf_read(services_config)) {
1136f709 204 fprintf(stderr, "Unable to read %s.\n", services_config);
205 exit(1);
d76ed9a9 206 }
207
208 conf_register_reload(uplink_compile);
209
1136f709 210 if (run_as_daemon) {
211 /* Attempt to fork into the background if daemon mode is on. */
212 pid = fork();
213 if (pid < 0) {
214 fprintf(stderr, "Unable to fork: %s\n", strerror(errno));
d76ed9a9 215 } else if (pid > 0) {
1136f709 216 fprintf(stdout, "Forking into the background (pid: %d)...\n", pid);
217 exit(0);
218 }
219 setsid();
220 }
221
222 file_out = fopen(PID_FILE, "w");
223 if (file_out == NULL) {
224 /* Create the main process' pid file */
225 fprintf(stderr, "Unable to create PID file: %s", strerror(errno));
226 } else {
227 fprintf(file_out, "%i\n", (int)getpid());
228 fclose(file_out);
229 }
230
231 if (run_as_daemon) {
0f6fe38c 232 /* Close these since we should not use them from now on. */
233 fclose(stdin);
234 fclose(stdout);
235 fclose(stderr);
d76ed9a9 236 }
237
d76ed9a9 238 services_argc = argc;
239 services_argv = argv;
240
241 atexit(call_exit_funcs);
30874d66 242 reg_exit_func(main_shutdown, NULL);
d76ed9a9 243
244 log_init();
ceafd592 245 MAIN_LOG = log_register_type("x3", "file:main.log");
d76ed9a9 246 if (debug)
247 log_debug();
1136f709 248 ioset_init();
d76ed9a9 249 init_structs();
250 init_parse();
251 modcmd_init();
252 saxdb_init();
1136f709 253 sar_init();
d76ed9a9 254 gline_init();
d914d1cb 255 shun_init();
1136f709 256 mail_init();
d76ed9a9 257 helpfile_init();
258 conf_globals(); /* initializes the core services */
259 conf_rlimits();
260 modules_init();
261 message_register_table(msgtab);
262 modcmd_finalize();
263 saxdb_finalize();
264 helpfile_finalize();
265 modules_finalize();
266
267 /* The first exit func to be called *should* be saxdb_write_all(). */
30874d66 268 reg_exit_func(saxdb_write_all, NULL);
d76ed9a9 269 if (replay_file) {
270 char *msg;
271 log_module(MAIN_LOG, LOG_INFO, "Beginning replay...");
272 srand(now);
273 replay_event_loop();
274 if ((msg = dict_sanity_check(clients))) {
275 log_module(MAIN_LOG, LOG_ERROR, "Clients insanity: %s", msg);
276 free(msg);
277 }
278 if ((msg = dict_sanity_check(channels))) {
279 log_module(MAIN_LOG, LOG_ERROR, "Channels insanity: %s", msg);
280 free(msg);
281 }
282 if ((msg = dict_sanity_check(servers))) {
283 log_module(MAIN_LOG, LOG_ERROR, "Servers insanity: %s", msg);
284 free(msg);
285 }
286 } else {
1136f709 287 now = time(NULL);
288 srand(now);
d76ed9a9 289 ioset_run();
290 }
291 return 0;
292}