]>
Commit | Line | Data |
---|---|---|
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 | } |