]> jfr.im git - irc/evilnet/x3.git/blob - src/main.c
Fix for "whats the color" 8ball question formats
[irc/evilnet/x3.git] / src / main.c
1 /* main.c - X3
2 * Copyright 2000-2006 srvx Development Team
3 *
4 * This file is part of X3.
5 *
6 * srvx is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 3 of the License, or
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
21 #define PID_FILE "x3.pid"
22
23 #include "conf.h"
24 #include "gline.h"
25 #include "ioset.h"
26 #include "modcmd.h"
27 #include "saxdb.h"
28 #include "mail.h"
29 #include "timeq.h"
30 #include "sar.h"
31 #include "shun.h"
32
33 #include "chanserv.h"
34 #include "global.h"
35 #include "modules.h"
36 #include "opserv.h"
37 #include "spamserv.h"
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
57 #include "main-common.c"
58
59 void 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
69 void 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
80 void sigaction_wait(UNUSED_ARG(int x))
81 {
82 int code;
83 wait4(-1, &code, WNOHANG, NULL);
84 }
85
86 void 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
96 #if WITH_MALLOC_BOEHM_GC
97 void
98 gc_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
104 int main(int argc, char *argv[])
105 {
106 int run_as_daemon;
107 int debug;
108 pid_t pid = 0;
109 FILE *file_out;
110 struct sigaction sv;
111
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
118 if (!chdir(PREFIX))
119 log_module(MAIN_LOG, LOG_INFO, "changed to %s\n", PREFIX);
120 else
121 log_module(MAIN_LOG, LOG_WARNING, "unable to change directory to %s, using current directory instead\n", PREFIX);
122 run_as_daemon = 1;
123 debug = 0;
124 tools_init();
125
126 /* set up some signal handlers */
127 memset(&sv, 0, sizeof(sv));
128 sigemptyset(&sv.sa_mask);
129 sv.sa_handler = SIG_IGN;
130 sigaction(SIGPIPE, &sv, NULL);
131 sv.sa_handler = sigaction_rehash;
132 sigaction(SIGHUP, &sv, NULL);
133 sv.sa_handler = sigaction_writedb;
134 sigaction(SIGINT, &sv, NULL);
135 sv.sa_handler = sigaction_exit;
136 sigaction(SIGQUIT, &sv, NULL);
137 sv.sa_handler = sigaction_wait;
138 sigaction(SIGCHLD, &sv, NULL);
139
140 if (argc > 1) { /* parse command line, if any */
141 int c;
142 struct option options[] =
143 {
144 {"config", 1, 0, 'c'},
145 {"debug", 0, 0, 'd'},
146 {"foreground", 0, 0, 'f'},
147 {"help", 0, 0, 'h'},
148 {"check", 0, 0, 'k'},
149 {"replay", 1, 0, 'r'},
150 {"version", 0, 0, 'v'},
151 {0, 0, 0, 0}
152 };
153
154 while ((c = getopt_long(argc, argv, "c:dfhkr:v", options, NULL)) != -1) {
155 switch (c) {
156 case 'c':
157 services_config = optarg;
158 break;
159 case 'k':
160 if (conf_read(services_config)) {
161 printf("%s appears to be a valid configuration file.\n", services_config);
162 } else {
163 printf("%s is an invalid configuration file.\n", services_config);
164 }
165 exit(0);
166 case 'r':
167 replay_file = fopen(optarg, "r");
168 if (!replay_file) {
169 fprintf(stderr, "Could not open %s for reading: %s (%d)\n",
170 optarg, strerror(errno), errno);
171 exit(0);
172 }
173 break;
174 case 'd':
175 debug = 1;
176 break;
177 case 'f':
178 run_as_daemon = 0;
179 break;
180 case 'v':
181 version();
182 license();
183 exit(0);
184 case 'h':
185 default:
186 usage(argv[0]);
187 exit(0);
188 }
189 }
190 }
191
192 version();
193
194 if (replay_file) {
195 /* We read a line here to "prime" the replay file parser, but
196 * mostly to get the right value of "now" for when we do the
197 * irc_introduce. */
198 replay_read_line();
199 } else {
200 now = time(NULL);
201 }
202 boot_time = now;
203
204 fprintf(stdout, "Initializing daemon...\n");
205 if (!conf_read(services_config)) {
206 fprintf(stderr, "Unable to read %s.\n", services_config);
207 exit(1);
208 }
209
210 conf_register_reload(uplink_compile);
211
212 if (run_as_daemon) {
213 /* Attempt to fork into the background if daemon mode is on. */
214 pid = fork();
215 if (pid < 0) {
216 fprintf(stderr, "Unable to fork: %s\n", strerror(errno));
217 } else if (pid > 0) {
218 fprintf(stdout, "Forking into the background (pid: %d)...\n", pid);
219 exit(0);
220 }
221 setsid();
222 }
223
224 file_out = fopen(PID_FILE, "w");
225 if (file_out == NULL) {
226 /* Create the main process' pid file */
227 fprintf(stderr, "Unable to create PID file: %s", strerror(errno));
228 } else {
229 fprintf(file_out, "%i\n", (int)getpid());
230 fclose(file_out);
231 }
232
233 if (run_as_daemon) {
234 /* Close these since we should not use them from now on. */
235 fclose(stdin);
236 fclose(stdout);
237 fclose(stderr);
238 }
239
240 services_argc = argc;
241 services_argv = argv;
242
243 atexit(call_exit_funcs);
244 reg_exit_func(main_shutdown, NULL);
245
246 log_init();
247 MAIN_LOG = log_register_type("x3", "file:main.log");
248 if (debug)
249 log_debug();
250 ioset_init();
251 init_structs();
252 init_parse();
253 modcmd_init();
254 saxdb_init();
255 sar_init();
256 gline_init();
257 shun_init();
258 mail_init();
259 helpfile_init();
260 conf_globals(); /* initializes the core services */
261 conf_rlimits();
262 modules_init();
263 message_register_table(msgtab);
264 modcmd_finalize();
265 saxdb_finalize();
266 helpfile_finalize();
267 modules_finalize();
268
269 /* The first exit func to be called *should* be saxdb_write_all(). */
270 reg_exit_func(saxdb_write_all, NULL);
271 if (replay_file) {
272 char *msg;
273 log_module(MAIN_LOG, LOG_INFO, "Beginning replay...");
274 srand(now);
275 replay_event_loop();
276 if ((msg = dict_sanity_check(clients))) {
277 log_module(MAIN_LOG, LOG_ERROR, "Clients insanity: %s", msg);
278 free(msg);
279 }
280 if ((msg = dict_sanity_check(channels))) {
281 log_module(MAIN_LOG, LOG_ERROR, "Channels insanity: %s", msg);
282 free(msg);
283 }
284 if ((msg = dict_sanity_check(servers))) {
285 log_module(MAIN_LOG, LOG_ERROR, "Servers insanity: %s", msg);
286 free(msg);
287 }
288 } else {
289 now = time(NULL);
290 srand(now);
291 ioset_run();
292 }
293 return 0;
294 }