/* * main.C: Initialisation routine. * * Copyright © 2007 Pippijn van Steenhoven / The Ermyth Team * Rights to this code are as documented in COPYING. * * * Portions of this file were derived from sources bearing the following license: * Rights to this code are documented in doc/pod/license.pod. * Copyright © 2005-2007 Atheme Project (http://www.atheme.org) */ static char const rcsid[] = "$Id: main.C,v 1.10 2007/09/22 14:27:30 pippijn Exp $"; #include "atheme.h" #include #include #include "servers.h" #include #include #include #include #include #include #include "account.h" // XXX: expire_check #include "uplink.h" #include "internal.h" #include "datastream.h" #include "authcookie.h" #include "connection.h" #include "confparse.h" #include /* *INDENT-OFF* */ static void print_help (void) { printf ("usage: %s [-dhnv] [-c conf] [-l logfile] [-p pidfile]\n\n" "-c Specify the config file\n" "-d Start in debugging mode\n" "-h Print this message and exit\n" "-l Specify the log file\n" "-n Don't fork into the background (log screen + log file)\n" "-p Specify the pid file (will be overwritten)\n" "-v Print version information and exit\n", me.execname); } static void print_version (void) { printf ("Ermyth IRC Services (" PACKAGE_NAME "-%s)\n" "Compiled %s, build %s\n\n" "Copyright © 2007 Pippijn van Steenhoven / The Ermyth Team\n" "Copyright © 2005-2007 Atheme Development Group\n" "Rights to this code are documented in doc/pod/license.pod.\n", version, creation, generation); } /* *INDENT-ON* */ static void db_save (void *) { backend->save (); } int main (int argc, char *argv[], char *envp[]) { bool have_conf = false; bool have_log = false; char buf[32]; int i, pid, r; FILE *pid_file; char const *pidfilename = RUNDIR "/" PACKAGE_NAME ".pid"; #ifdef HAVE_GETRLIMIT struct rlimit rlim; #endif curr_uplink = NULL; me.argc = argc; me.argv = argv; me.execname = argv[0]; /* Prepare gettext */ #ifdef ENABLE_NLS setlocale (LC_ALL, ""); bindtextdomain (PACKAGE_NAME, LOCALEDIR); textdomain (PACKAGE_NAME); #endif /* change to our local directory */ if (chdir (PREFIX) < 0) { perror (PREFIX); return 20; } #ifdef HAVE_GETRLIMIT /* it appears certian systems *ahem*linux*ahem* * don't dump cores by default, so we do this here. */ if (!getrlimit (RLIMIT_CORE, &rlim)) { rlim.rlim_cur = rlim.rlim_max; setrlimit (RLIMIT_CORE, &rlim); } #endif /* do command-line options */ while ((r = getopt (argc, argv, "c:dhl:np:v")) != -1) { switch (r) { case 'c': config_file = sstrdup (optarg); have_conf = true; break; case 'd': log_force = true; break; case 'h': print_help (); exit (EXIT_SUCCESS); break; case 'l': log_path = sstrdup (optarg); have_log = true; break; case 'n': runflags |= RF_LIVE; break; case 'p': pidfilename = optarg; break; case 'v': print_version (); exit (EXIT_SUCCESS); break; default: printf ("usage: %s [-dhnv] [-c conf] [-l logfile] [-p pidfile]\n", me.execname); exit (EXIT_SUCCESS); break; } } if (have_conf == false) config_file = sstrdup (SYSCONFDIR "/" PACKAGE_NAME ".conf"); if (have_log == false) log_path = sstrdup (LOGDIR "/" PACKAGE_NAME ".log"); cold_start = true; runflags |= RF_STARTING; me.start = time_t (now ()); NOW = me.start; init_gen_rand (NOW); srand (gen_rand32 ()); me.execname = argv[0]; /* set signal handlers */ init_signal_handlers (); /* open log */ log_open (); printf ("%s: version " PACKAGE_NAME "-%s\n", me.execname, version); /* check for pid file */ if ((pid_file = fopen (pidfilename, "r"))) { if (fgets (buf, 32, pid_file)) { pid = atoi (buf); if (!kill (pid, 0)) { fprintf (stderr, "%s: daemon is already running\n", me.execname); exit (EXIT_FAILURE); } } fclose (pid_file); } #if HAVE_UMASK /* file creation mask */ umask (077); #endif event_init (); init_dlink_nodes (); init_netio (); init_socket_queues (); init_nodes (); init_newconf (); servtree_init (); init_ircpacket (); conf_init (); if (!conf_parse (config_file)) { slog (LG_ERROR, "Error loading config file %s, aborting", config_file); exit (EXIT_FAILURE); } authcookie_init (); common_ctcp_init (); update_chanacs_flags (); if (!database::handler::loaded) { fprintf (stderr, "%s: no backend loaded, see your configuration file.\n", me.execname); exit (EXIT_FAILURE); } /* check our config file */ if (!conf_check ()) exit (EXIT_FAILURE); /* we've done the critical startup steps now */ cold_start = false; /* load our db */ if (database::handler::loaded) backend->load (); else { /* XXX: We should have bailed by now! --nenolod */ fprintf (stderr, "%s: no backend loaded, see your configuration file.\n", me.execname); exit (EXIT_FAILURE); } db_check (); #ifdef HAVE_FORK /* fork into the background */ if (!(runflags & RF_LIVE)) { close (0); if (open ("/dev/null", O_RDWR) != 0) { fprintf (stderr, "%s: unable to open /dev/null??\n", me.execname); exit (EXIT_FAILURE); } if ((i = fork ()) < 0) { fprintf (stderr, "%s: can't fork into the background\n", me.execname); exit (EXIT_FAILURE); } /* parent */ else if (i != 0) { printf ("%s: pid %d\n", me.execname, i); printf ("%s: running in background mode from " PREFIX "\n", me.execname); exit (EXIT_SUCCESS); } /* parent is gone, just us now */ if (setsid () < 0) { fprintf (stderr, "%s: unable to create new session\n", me.execname); exit (EXIT_FAILURE); } dup2 (0, 1); dup2 (0, 2); } else { printf ("%s: pid %d\n", me.execname, getpid ()); printf ("%s: running in foreground mode from %s\n", me.execname, PREFIX); } #else printf ("%s: running in foreground mode from %s\n", me.execname, PREFIX); #endif #ifdef HAVE_GETPID /* write pid */ if ((pid_file = fopen (pidfilename, "w"))) { fprintf (pid_file, "%d\n", getpid ()); fclose (pid_file); } else { fprintf (stderr, "%s: unable to write pid file\n", me.execname); exit (EXIT_FAILURE); } #endif /* no longer starting */ runflags &= ~RF_STARTING; /* we probably have a few open already... */ me.maxfd = 3; /* DB commit interval is configurable */ event_add ("db_save", db_save, NULL, config_options.commit_interval); /* check expires every hour */ event_add ("expire_check", expire_check, NULL, 3600); /* check kline expires every minute */ event_add ("kline_t::expire", kline_t::expire, NULL, 60); /* check authcookie expires every ten minutes */ event_add ("authcookie_expire", authcookie_expire, NULL, 600); me.connected = false; uplink_connect (); /* main loop */ io_loop (); /* we're shutting down */ backend->save (); if (chansvs.me != NULL && chansvs.me->me != NULL) phandler->quit_sts (chansvs.me->me, "shutting down"); /* free used memory */ modules::cleanup (); operclass_cleanup (); soper_cleanup (); remove (pidfilename); errno = 0; if (curr_uplink != NULL && curr_uplink->conn != NULL) sendq_flush (curr_uplink->conn); connection_t::close_all (); me.connected = false; mynick_t::cleanup (); myuser_t::cleanup (); // XXX: this currently breaks and I don't know why mychan_t::cleanup (); chansvs.cleanup (); globsvs.cleanup (); opersvs.cleanup (); memosvs.cleanup (); gamesvs.cleanup (); nicksvs.cleanup (); saslsvs.cleanup (); delete phandler; delete backend; uplink_cleanup (); server_delete (me.me, true); tld_cleanup (); conf_cleanup (); sfree (config_file); sfree (log_path); #ifdef HAVE_EXECVE /* should we restart? */ if (runflags & RF_RESTART) { slog (LG_INFO, "main(): restarting"); log_shutdown (); execve (me.execname, argv, envp); } #endif slog (LG_INFO, "main(): shutting down"); log_shutdown (); return 0; }