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, 8 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

# User Rev Content
1 pippijn 1.1 /*
2     * main.C: Initialisation routine.
3 pippijn 1.9 *
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 pippijn 1.2 * Rights to this code are documented in doc/pod/license.pod.
10 pippijn 1.9 * Copyright © 2005-2007 Atheme Project (http://www.atheme.org)
11 pippijn 1.1 */
12    
13 pippijn 1.10 static char const rcsid[] = "$Id: main.C,v 1.9 2007-09-16 18:54:45 pippijn Exp $";
14 pippijn 1.1
15     #include "atheme.h"
16 pippijn 1.10 #include <libermyth.h>
17     #include <util/time.h>
18 pippijn 1.8 #include "servers.h"
19 pippijn 1.5 #include <ermyth/database.h>
20     #include <ermyth/module.h>
21 pippijn 1.1 #include <account/kline.h>
22 pippijn 1.5 #include <account/myuser.h>
23     #include <account/mynick.h>
24     #include <account/mychan.h>
25     #include "account.h" // XXX: expire_check
26 pippijn 1.1 #include "uplink.h"
27     #include "internal.h"
28     #include "datastream.h"
29     #include "authcookie.h"
30     #include "connection.h"
31     #include "confparse.h"
32 pippijn 1.10 #include <util/random.h>
33 pippijn 1.5
34 pippijn 1.1 /* *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 pippijn 1.2 "Rights to this code are documented in doc/pod/license.pod.\n",
56 pippijn 1.1 version, creation, generation);
57     }
58     /* *INDENT-ON* */
59    
60     static void
61 pippijn 1.5 db_save (void *)
62 pippijn 1.1 {
63 pippijn 1.5 backend->save ();
64 pippijn 1.1 }
65    
66     int
67 pippijn 1.4 main (int argc, char *argv[], char *envp[])
68 pippijn 1.1 {
69     bool have_conf = false;
70     bool have_log = false;
71     char buf[32];
72     int i, pid, r;
73     FILE *pid_file;
74 pippijn 1.5 char const *pidfilename = RUNDIR "/" PACKAGE_NAME ".pid";
75 pippijn 1.1 #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 pippijn 1.5 me.start = time_t (now ());
156 pippijn 1.1 NOW = me.start;
157 pippijn 1.5 init_gen_rand (NOW);
158     srand (gen_rand32 ());
159 pippijn 1.1 me.execname = argv[0];
160    
161     /* set signal handlers */
162     init_signal_handlers ();
163    
164     /* open log */
165     log_open ();
166 pippijn 1.5
167 pippijn 1.1 printf ("%s: version " PACKAGE_NAME "-%s\n", me.execname, version);
168 pippijn 1.5
169 pippijn 1.1 /* check for pid file */
170     if ((pid_file = fopen (pidfilename, "r")))
171     {
172     if (fgets (buf, 32, pid_file))
173 pippijn 1.5 {
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 pippijn 1.1 fclose (pid_file);
184     }
185 pippijn 1.5
186 pippijn 1.1 #if HAVE_UMASK
187     /* file creation mask */
188     umask (077);
189     #endif
190 pippijn 1.5
191 pippijn 1.1 event_init ();
192     init_dlink_nodes ();
193     init_netio ();
194     init_socket_queues ();
195 pippijn 1.5
196 pippijn 1.1 init_nodes ();
197     init_newconf ();
198     servtree_init ();
199     init_ircpacket ();
200 pippijn 1.5
201 pippijn 1.1 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 pippijn 1.5
208 pippijn 1.1 authcookie_init ();
209     common_ctcp_init ();
210     update_chanacs_flags ();
211 pippijn 1.5
212     if (!database::handler::loaded)
213 pippijn 1.1 {
214 pippijn 1.5 fprintf (stderr, "%s: no backend loaded, see your configuration file.\n", me.execname);
215 pippijn 1.1 exit (EXIT_FAILURE);
216     }
217 pippijn 1.5
218 pippijn 1.1 /* check our config file */
219     if (!conf_check ())
220     exit (EXIT_FAILURE);
221 pippijn 1.5
222 pippijn 1.1 /* we've done the critical startup steps now */
223     cold_start = false;
224 pippijn 1.5
225 pippijn 1.1 /* load our db */
226 pippijn 1.5 if (database::handler::loaded)
227     backend->load ();
228 pippijn 1.1 else
229     {
230     /* XXX: We should have bailed by now! --nenolod */
231 pippijn 1.5 fprintf (stderr, "%s: no backend loaded, see your configuration file.\n", me.execname);
232 pippijn 1.1 exit (EXIT_FAILURE);
233     }
234     db_check ();
235 pippijn 1.5
236 pippijn 1.1 #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 pippijn 1.5 {
243     fprintf (stderr, "%s: unable to open /dev/null??\n", me.execname);
244     exit (EXIT_FAILURE);
245     }
246 pippijn 1.1 if ((i = fork ()) < 0)
247 pippijn 1.5 {
248     fprintf (stderr, "%s: can't fork into the background\n", me.execname);
249     exit (EXIT_FAILURE);
250     }
251    
252 pippijn 1.1 /* parent */
253     else if (i != 0)
254 pippijn 1.5 {
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 pippijn 1.1 /* parent is gone, just us now */
261     if (setsid () < 0)
262 pippijn 1.5 {
263     fprintf (stderr, "%s: unable to create new session\n", me.execname);
264     exit (EXIT_FAILURE);
265     }
266 pippijn 1.1 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 pippijn 1.5
278 pippijn 1.1 #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 pippijn 1.5
294 pippijn 1.1 /* we probably have a few open already... */
295     me.maxfd = 3;
296 pippijn 1.5
297 pippijn 1.1 /* DB commit interval is configurable */
298     event_add ("db_save", db_save, NULL, config_options.commit_interval);
299 pippijn 1.5
300 pippijn 1.1 /* check expires every hour */
301     event_add ("expire_check", expire_check, NULL, 3600);
302 pippijn 1.5
303 pippijn 1.1 /* check kline expires every minute */
304 pippijn 1.8 event_add ("kline_t::expire", kline_t::expire, NULL, 60);
305 pippijn 1.5
306 pippijn 1.1 /* check authcookie expires every ten minutes */
307     event_add ("authcookie_expire", authcookie_expire, NULL, 600);
308 pippijn 1.5
309 pippijn 1.1 me.connected = false;
310     uplink_connect ();
311    
312     /* main loop */
313     io_loop ();
314 pippijn 1.5
315 pippijn 1.1 /* we're shutting down */
316 pippijn 1.5 backend->save ();
317 pippijn 1.1 if (chansvs.me != NULL && chansvs.me->me != NULL)
318 pippijn 1.5 phandler->quit_sts (chansvs.me->me, "shutting down");
319    
320 pippijn 1.10 /* free used memory */
321     modules::cleanup ();
322     operclass_cleanup ();
323     soper_cleanup ();
324    
325 pippijn 1.1 remove (pidfilename);
326     errno = 0;
327     if (curr_uplink != NULL && curr_uplink->conn != NULL)
328     sendq_flush (curr_uplink->conn);
329 pippijn 1.7 connection_t::close_all ();
330 pippijn 1.1
331     me.connected = false;
332 pippijn 1.10
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 pippijn 1.5
351 pippijn 1.10 conf_cleanup ();
352     sfree (config_file);
353     sfree (log_path);
354    
355     #ifdef HAVE_EXECVE
356 pippijn 1.1 /* should we restart? */
357     if (runflags & RF_RESTART)
358     {
359     slog (LG_INFO, "main(): restarting");
360 pippijn 1.10 log_shutdown ();
361 pippijn 1.1
362 pippijn 1.4 execve (me.execname, argv, envp);
363 pippijn 1.10 }
364 pippijn 1.1 #endif
365 pippijn 1.10
366 pippijn 1.1 slog (LG_INFO, "main(): shutting down");
367 pippijn 1.10 log_shutdown ();
368 pippijn 1.5
369 pippijn 1.1 return 0;
370     }