ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/ermyth/src/main.C
Revision: 1.10
Committed: Sat Sep 22 14:27:30 2007 UTC (16 years, 7 months ago) by pippijn
Content type: text/plain
Branch: MAIN
CVS Tags: HEAD
Changes since 1.9: +36 -22 lines
Log Message:
split up ermyth into ermyth-modules, libermyth (currently just ermyth-util) and ermyth-core

File Contents

# Content
1 /*
2 * main.C: Initialisation routine.
3 *
4 * Copyright © 2007 Pippijn van Steenhoven / The Ermyth Team
5 * Rights to this code are as documented in COPYING.
6 *
7 *
8 * Portions of this file were derived from sources bearing the following license:
9 * Rights to this code are documented in doc/pod/license.pod.
10 * Copyright © 2005-2007 Atheme Project (http://www.atheme.org)
11 */
12
13 static char const rcsid[] = "$Id: main.C,v 1.9 2007-09-16 18:54:45 pippijn Exp $";
14
15 #include "atheme.h"
16 #include <libermyth.h>
17 #include <util/time.h>
18 #include "servers.h"
19 #include <ermyth/database.h>
20 #include <ermyth/module.h>
21 #include <account/kline.h>
22 #include <account/myuser.h>
23 #include <account/mynick.h>
24 #include <account/mychan.h>
25 #include "account.h" // XXX: expire_check
26 #include "uplink.h"
27 #include "internal.h"
28 #include "datastream.h"
29 #include "authcookie.h"
30 #include "connection.h"
31 #include "confparse.h"
32 #include <util/random.h>
33
34 /* *INDENT-OFF* */
35 static void
36 print_help (void)
37 {
38 printf ("usage: %s [-dhnv] [-c conf] [-l logfile] [-p pidfile]\n\n"
39 "-c <file> Specify the config file\n"
40 "-d Start in debugging mode\n"
41 "-h Print this message and exit\n"
42 "-l <file> Specify the log file\n"
43 "-n Don't fork into the background (log screen + log file)\n"
44 "-p <file> Specify the pid file (will be overwritten)\n"
45 "-v Print version information and exit\n", me.execname);
46 }
47
48 static void
49 print_version (void)
50 {
51 printf ("Ermyth IRC Services (" PACKAGE_NAME "-%s)\n"
52 "Compiled %s, build %s\n\n"
53 "Copyright © 2007 Pippijn van Steenhoven / The Ermyth Team\n"
54 "Copyright © 2005-2007 Atheme Development Group\n"
55 "Rights to this code are documented in doc/pod/license.pod.\n",
56 version, creation, generation);
57 }
58 /* *INDENT-ON* */
59
60 static void
61 db_save (void *)
62 {
63 backend->save ();
64 }
65
66 int
67 main (int argc, char *argv[], char *envp[])
68 {
69 bool have_conf = false;
70 bool have_log = false;
71 char buf[32];
72 int i, pid, r;
73 FILE *pid_file;
74 char const *pidfilename = RUNDIR "/" PACKAGE_NAME ".pid";
75 #ifdef HAVE_GETRLIMIT
76 struct rlimit rlim;
77 #endif
78 curr_uplink = NULL;
79 me.argc = argc;
80 me.argv = argv;
81 me.execname = argv[0];
82
83 /* Prepare gettext */
84 #ifdef ENABLE_NLS
85 setlocale (LC_ALL, "");
86 bindtextdomain (PACKAGE_NAME, LOCALEDIR);
87 textdomain (PACKAGE_NAME);
88 #endif
89
90 /* change to our local directory */
91 if (chdir (PREFIX) < 0)
92 {
93 perror (PREFIX);
94 return 20;
95 }
96
97 #ifdef HAVE_GETRLIMIT
98 /* it appears certian systems *ahem*linux*ahem*
99 * don't dump cores by default, so we do this here.
100 */
101 if (!getrlimit (RLIMIT_CORE, &rlim))
102 {
103 rlim.rlim_cur = rlim.rlim_max;
104 setrlimit (RLIMIT_CORE, &rlim);
105 }
106 #endif
107
108 /* do command-line options */
109 while ((r = getopt (argc, argv, "c:dhl:np:v")) != -1)
110 {
111 switch (r)
112 {
113 case 'c':
114 config_file = sstrdup (optarg);
115 have_conf = true;
116 break;
117 case 'd':
118 log_force = true;
119 break;
120 case 'h':
121 print_help ();
122 exit (EXIT_SUCCESS);
123 break;
124 case 'l':
125 log_path = sstrdup (optarg);
126 have_log = true;
127 break;
128 case 'n':
129 runflags |= RF_LIVE;
130 break;
131 case 'p':
132 pidfilename = optarg;
133 break;
134 case 'v':
135 print_version ();
136 exit (EXIT_SUCCESS);
137 break;
138 default:
139 printf ("usage: %s [-dhnv] [-c conf] [-l logfile] [-p pidfile]\n", me.execname);
140 exit (EXIT_SUCCESS);
141 break;
142 }
143 }
144
145 if (have_conf == false)
146 config_file = sstrdup (SYSCONFDIR "/" PACKAGE_NAME ".conf");
147
148 if (have_log == false)
149 log_path = sstrdup (LOGDIR "/" PACKAGE_NAME ".log");
150
151 cold_start = true;
152
153 runflags |= RF_STARTING;
154
155 me.start = time_t (now ());
156 NOW = me.start;
157 init_gen_rand (NOW);
158 srand (gen_rand32 ());
159 me.execname = argv[0];
160
161 /* set signal handlers */
162 init_signal_handlers ();
163
164 /* open log */
165 log_open ();
166
167 printf ("%s: version " PACKAGE_NAME "-%s\n", me.execname, version);
168
169 /* check for pid file */
170 if ((pid_file = fopen (pidfilename, "r")))
171 {
172 if (fgets (buf, 32, pid_file))
173 {
174 pid = atoi (buf);
175
176 if (!kill (pid, 0))
177 {
178 fprintf (stderr, "%s: daemon is already running\n", me.execname);
179 exit (EXIT_FAILURE);
180 }
181 }
182
183 fclose (pid_file);
184 }
185
186 #if HAVE_UMASK
187 /* file creation mask */
188 umask (077);
189 #endif
190
191 event_init ();
192 init_dlink_nodes ();
193 init_netio ();
194 init_socket_queues ();
195
196 init_nodes ();
197 init_newconf ();
198 servtree_init ();
199 init_ircpacket ();
200
201 conf_init ();
202 if (!conf_parse (config_file))
203 {
204 slog (LG_ERROR, "Error loading config file %s, aborting", config_file);
205 exit (EXIT_FAILURE);
206 }
207
208 authcookie_init ();
209 common_ctcp_init ();
210 update_chanacs_flags ();
211
212 if (!database::handler::loaded)
213 {
214 fprintf (stderr, "%s: no backend loaded, see your configuration file.\n", me.execname);
215 exit (EXIT_FAILURE);
216 }
217
218 /* check our config file */
219 if (!conf_check ())
220 exit (EXIT_FAILURE);
221
222 /* we've done the critical startup steps now */
223 cold_start = false;
224
225 /* load our db */
226 if (database::handler::loaded)
227 backend->load ();
228 else
229 {
230 /* XXX: We should have bailed by now! --nenolod */
231 fprintf (stderr, "%s: no backend loaded, see your configuration file.\n", me.execname);
232 exit (EXIT_FAILURE);
233 }
234 db_check ();
235
236 #ifdef HAVE_FORK
237 /* fork into the background */
238 if (!(runflags & RF_LIVE))
239 {
240 close (0);
241 if (open ("/dev/null", O_RDWR) != 0)
242 {
243 fprintf (stderr, "%s: unable to open /dev/null??\n", me.execname);
244 exit (EXIT_FAILURE);
245 }
246 if ((i = fork ()) < 0)
247 {
248 fprintf (stderr, "%s: can't fork into the background\n", me.execname);
249 exit (EXIT_FAILURE);
250 }
251
252 /* parent */
253 else if (i != 0)
254 {
255 printf ("%s: pid %d\n", me.execname, i);
256 printf ("%s: running in background mode from " PREFIX "\n", me.execname);
257 exit (EXIT_SUCCESS);
258 }
259
260 /* parent is gone, just us now */
261 if (setsid () < 0)
262 {
263 fprintf (stderr, "%s: unable to create new session\n", me.execname);
264 exit (EXIT_FAILURE);
265 }
266 dup2 (0, 1);
267 dup2 (0, 2);
268 }
269 else
270 {
271 printf ("%s: pid %d\n", me.execname, getpid ());
272 printf ("%s: running in foreground mode from %s\n", me.execname, PREFIX);
273 }
274 #else
275 printf ("%s: running in foreground mode from %s\n", me.execname, PREFIX);
276 #endif
277
278 #ifdef HAVE_GETPID
279 /* write pid */
280 if ((pid_file = fopen (pidfilename, "w")))
281 {
282 fprintf (pid_file, "%d\n", getpid ());
283 fclose (pid_file);
284 }
285 else
286 {
287 fprintf (stderr, "%s: unable to write pid file\n", me.execname);
288 exit (EXIT_FAILURE);
289 }
290 #endif
291 /* no longer starting */
292 runflags &= ~RF_STARTING;
293
294 /* we probably have a few open already... */
295 me.maxfd = 3;
296
297 /* DB commit interval is configurable */
298 event_add ("db_save", db_save, NULL, config_options.commit_interval);
299
300 /* check expires every hour */
301 event_add ("expire_check", expire_check, NULL, 3600);
302
303 /* check kline expires every minute */
304 event_add ("kline_t::expire", kline_t::expire, NULL, 60);
305
306 /* check authcookie expires every ten minutes */
307 event_add ("authcookie_expire", authcookie_expire, NULL, 600);
308
309 me.connected = false;
310 uplink_connect ();
311
312 /* main loop */
313 io_loop ();
314
315 /* we're shutting down */
316 backend->save ();
317 if (chansvs.me != NULL && chansvs.me->me != NULL)
318 phandler->quit_sts (chansvs.me->me, "shutting down");
319
320 /* free used memory */
321 modules::cleanup ();
322 operclass_cleanup ();
323 soper_cleanup ();
324
325 remove (pidfilename);
326 errno = 0;
327 if (curr_uplink != NULL && curr_uplink->conn != NULL)
328 sendq_flush (curr_uplink->conn);
329 connection_t::close_all ();
330
331 me.connected = false;
332
333 mynick_t::cleanup ();
334 myuser_t::cleanup (); // XXX: this currently breaks and I don't know why
335 mychan_t::cleanup ();
336
337 chansvs.cleanup ();
338 globsvs.cleanup ();
339 opersvs.cleanup ();
340 memosvs.cleanup ();
341 gamesvs.cleanup ();
342 nicksvs.cleanup ();
343 saslsvs.cleanup ();
344
345 delete phandler;
346 delete backend;
347 uplink_cleanup ();
348 server_delete (me.me, true);
349 tld_cleanup ();
350
351 conf_cleanup ();
352 sfree (config_file);
353 sfree (log_path);
354
355 #ifdef HAVE_EXECVE
356 /* should we restart? */
357 if (runflags & RF_RESTART)
358 {
359 slog (LG_INFO, "main(): restarting");
360 log_shutdown ();
361
362 execve (me.execname, argv, envp);
363 }
364 #endif
365
366 slog (LG_INFO, "main(): shutting down");
367 log_shutdown ();
368
369 return 0;
370 }