ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/ermyth/src/main.C
Revision: 1.5
Committed: Tue Aug 28 17:08:12 2007 UTC (16 years, 9 months ago) by pippijn
Content type: text/plain
Branch: MAIN
Changes since 1.4: +88 -87 lines
Log Message:
- changed name
- updated the example config to the new system
- added more documentation
- enhanced documentation generators
- added a link to the pdf to the website
- added an RSS feed generator
- transitioned hooks to c++ callbacks
- did various merges with upstream along the way
- added const where appropriate
- removed the old block allocator
- fixed most memory leaks
- transitioned some dictionaries to std::map
- transitioned some lists to std::vector
- made some free functions members where appropriate
- renamed string to dynstr and added a static string ststr
- use NOW instead of time (NULL) if possible
- completely reworked database backends, crypto handlers and protocol handlers
  to use an object factory
- removed the old module system. ermyth does not do any dynamic loading anymore
- fixed most of the build system
- reworked how protocol commands work

File Contents

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