summaryrefslogtreecommitdiff
path: root/src/init.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/init.cpp')
-rw-r--r--src/init.cpp472
1 files changed, 472 insertions, 0 deletions
diff --git a/src/init.cpp b/src/init.cpp
new file mode 100644
index 000000000..2c2a64ed4
--- /dev/null
+++ b/src/init.cpp
@@ -0,0 +1,472 @@
+/* Initalization and related routines.
+ *
+ * (C) 2003-2010 Anope Team
+ * Contact us at team@anope.org
+ *
+ * Please read COPYING and README for further details.
+ *
+ * Based on the original code of Epona by Lara.
+ * Based on the original code of Services by Andy Church.
+ *
+ *
+ */
+
+#include "services.h"
+#include "modules.h"
+
+Uplink *uplink_server;
+
+extern void moduleAddMsgs();
+extern void moduleAddIRCDMsgs();
+
+/*************************************************************************/
+
+void introduce_user(const std::string &user)
+{
+
+ /* Watch out for infinite loops... */
+#define LTSIZE 20
+ static int lasttimes[LTSIZE];
+ if (lasttimes[0] >= time(NULL) - 3)
+ fatal("introduce_user() loop detected");
+ memmove(lasttimes, lasttimes + 1, sizeof(lasttimes) - sizeof(int));
+ lasttimes[LTSIZE - 1] = time(NULL);
+#undef LTSIZE
+ /* We make the bots go online */
+
+ /* XXX: it might be nice to have this inside BotInfo's constructor, or something? */
+ for (botinfo_map::const_iterator it = BotList.begin(); it != BotList.end(); ++it)
+ {
+ BotInfo *bi = it->second;
+
+ ci::string ci_bi_nick(bi->nick.c_str());
+ if (user.empty() || ci_bi_nick == user)
+ {
+ ircdproto->SendClientIntroduction(bi->nick, bi->user, bi->host, bi->real, ircd->pseudoclient_mode, bi->uid);
+ XLine x(bi->nick.c_str(), "Reserved for services");
+ ircdproto->SendSQLine(&x);
+ }
+ }
+}
+
+/*************************************************************************/
+
+/* Set GID if necessary. Return 0 if successful (or if RUNGROUP not
+ * defined), else print an error message to logfile and return -1.
+ */
+
+static int set_group()
+{
+#if defined(RUNGROUP) && defined(HAVE_SETGRENT)
+ struct group *gr;
+
+ setgrent();
+ while ((gr = getgrent()) != NULL) {
+ if (strcmp(gr->gr_name, RUNGROUP) == 0)
+ break;
+ }
+ endgrent();
+ if (gr) {
+ setgid(gr->gr_gid);
+ return 0;
+ } else {
+ Alog() << "Unknown group `" << RUNGROUP << "'";
+ return -1;
+ }
+#else
+ return 0;
+#endif
+}
+
+/*************************************************************************/
+
+/* Vector of pairs of command line arguments and their params */
+static std::vector<std::pair<std::string, std::string> > CommandLineArguments;
+
+/** Called on startup to organize our starting arguments in a better way
+ * and check for errors
+ * @param ac number of args
+ * @param av args
+ */
+static void ParseCommandLineArguments(int ac, char **av)
+{
+ for (int i = 1; i < ac; ++i)
+ {
+ std::string option = av[i];
+ std::string param = "";
+ while (!option.empty() && option[0] == '-')
+ option.erase(option.begin());
+ size_t t = option.find('=');
+ if (t != std::string::npos)
+ {
+ param = option.substr(t + 1);
+ option.erase(t);
+ }
+
+ if (option.empty())
+ continue;
+
+ CommandLineArguments.push_back(std::make_pair(option, param));
+ }
+}
+
+/** Check if an argument was given on startup
+ * @param name The argument name
+ * @param shortname A shorter name, eg --debug and -d
+ * @return true if name/shortname was found, false if not
+ */
+bool GetCommandLineArgument(const std::string &name, char shortname)
+{
+ std::string Unused;
+ return GetCommandLineArgument(name, shortname, Unused);
+}
+
+/** Check if an argument was given on startup and its parameter
+ * @param name The argument name
+ * @param shortname A shorter name, eg --debug and -d
+ * @param param A string to put the param, if any, of the argument
+ * @return true if name/shortname was found, false if not
+ */
+bool GetCommandLineArgument(const std::string &name, char shortname, std::string &param)
+{
+ param.clear();
+
+ for (std::vector<std::pair<std::string, std::string> >::iterator it = CommandLineArguments.begin(); it != CommandLineArguments.end(); ++it)
+ {
+ if (it->first == name || it->first[0] == shortname)
+ {
+ param = it->second;
+ return true;
+ }
+ }
+
+ return false;
+}
+
+/*************************************************************************/
+
+/* Remove our PID file. Done at exit. */
+
+static void remove_pidfile()
+{
+ remove(Config.PIDFilename);
+}
+
+/*************************************************************************/
+
+/* Create our PID file and write the PID to it. */
+
+static void write_pidfile()
+{
+ FILE *pidfile;
+
+ pidfile = fopen(Config.PIDFilename, "w");
+ if (pidfile) {
+#ifdef _WIN32
+ fprintf(pidfile, "%d\n", static_cast<int>(GetCurrentProcessId()));
+#else
+ fprintf(pidfile, "%d\n", static_cast<int>(getpid()));
+#endif
+ fclose(pidfile);
+ atexit(remove_pidfile);
+ } else {
+ log_perror("Warning: cannot write to PID file %s", Config.PIDFilename);
+ }
+}
+
+/*************************************************************************/
+
+/* Overall initialization routines. Return 0 on success, -1 on failure. */
+
+int openlog_failed = 0, openlog_errno = 0;
+
+int init_primary(int ac, char **av)
+{
+ int started_from_term = isatty(0) && isatty(1) && isatty(2);
+
+ /* Set file creation mask and group ID. */
+#if defined(DEFUMASK) && HAVE_UMASK
+ umask(DEFUMASK);
+#endif
+ if (set_group() < 0)
+ return -1;
+
+ /* Parse command line arguments */
+ ParseCommandLineArguments(ac, av);
+
+ if (GetCommandLineArgument("version", 'v'))
+ {
+ Alog(LOG_TERMINAL) << "Anope-" << version_number << " -- " << version_build;
+ return -1;
+ }
+
+ if (GetCommandLineArgument("help", 'h'))
+ {
+ Alog(LOG_TERMINAL) << "Anope-" << version_number << " -- " << version_build;
+ Alog(LOG_TERMINAL) << "Anope IRC Services (http://www.anope.org)";
+ Alog(LOG_TERMINAL) << "Usage ./" << SERVICES_BIN << " [options] ...";
+ Alog(LOG_TERMINAL) << "-c, --config=filename.conf";
+ Alog(LOG_TERMINAL) << "-d, --debug[=level]";
+ Alog(LOG_TERMINAL) << " --dir=services_directory";
+ Alog(LOG_TERMINAL) << "-h, --help";
+ Alog(LOG_TERMINAL) << " --log=log_filename";
+ Alog(LOG_TERMINAL) << "-e, --noexpire";
+ Alog(LOG_TERMINAL) << "-n, --nofork";
+ Alog(LOG_TERMINAL) << " --nothird";
+ Alog(LOG_TERMINAL) << " --protocoldebug";
+ Alog(LOG_TERMINAL) << "-r, --readonly";
+ Alog(LOG_TERMINAL) << "-s, --support";
+ Alog(LOG_TERMINAL) << "-v, --version";
+ Alog(LOG_TERMINAL) << "";
+ Alog(LOG_TERMINAL) << "Further support is available from http://www.anope.org";
+ Alog(LOG_TERMINAL) << "Or visit us on IRC at irc.anope.org #anope";
+ return -1;
+ }
+
+ if (GetCommandLineArgument("nofork", 'n'))
+ {
+ nofork = 1;
+ }
+
+ if (GetCommandLineArgument("support", 's'))
+ {
+ nofork = nothird = 1;
+ ++debug;
+ }
+
+ if (GetCommandLineArgument("readonly", 'r'))
+ {
+ readonly = 1;
+ }
+
+ if (GetCommandLineArgument("nothird"))
+ {
+ nothird = 1;
+ }
+
+ if (GetCommandLineArgument("noexpire", 'e'))
+ {
+ noexpire = 1;
+ }
+
+ if (GetCommandLineArgument("protocoldebug"))
+ {
+ protocoldebug = 1;
+ }
+
+ std::string Arg;
+ if (GetCommandLineArgument("debug", 'd', Arg))
+ {
+ if (!Arg.empty())
+ {
+ int level = atoi(Arg.c_str());
+ if (level > 0)
+ debug = level;
+ else
+ {
+ Alog(LOG_TERMINAL) << "Invalid option given to --debug";
+ return -1;
+ }
+ }
+ else
+ ++debug;
+ }
+
+ if (GetCommandLineArgument("config", 'c', Arg))
+ {
+ if (Arg.empty())
+ {
+ Alog(LOG_TERMINAL) << "The --config option requires a file name";
+ return -1;
+ }
+ services_conf = Arg;
+ }
+
+ if (GetCommandLineArgument("dir", 0, Arg))
+ {
+ if (Arg.empty())
+ {
+ Alog(LOG_TERMINAL) << "The --dir option requires a directory name";
+ return -1;
+ }
+ services_dir = Arg;
+ }
+
+ if (GetCommandLineArgument("log", 0, Arg))
+ {
+ if (Arg.empty())
+ {
+ Alog(LOG_TERMINAL) << "The --log option requires a file name";
+ return -1;
+ }
+ log_filename = Arg;
+ }
+
+ /* Chdir to Services data directory. */
+ if (chdir(services_dir.c_str()) < 0) {
+ fprintf(stderr, "chdir(%s): %s\n", services_dir.c_str(), strerror(errno));
+ return -1;
+ }
+
+ /* Open logfile, and complain if we didn't. */
+ if (open_log() < 0) {
+ openlog_errno = errno;
+ if (started_from_term) {
+ fprintf(stderr, "Warning: unable to open log file %s: %s\n",
+ log_filename.c_str(), strerror(errno));
+ } else {
+ openlog_failed = 1;
+ }
+ }
+
+ /* Read configuration file; exit if there are problems. */
+ if (!read_config(0)) {
+ return -1;
+ }
+
+ /* Add IRCD Protocol Module; exit if there are errors */
+ if (protocol_module_init())
+ return -1;
+
+ /* First thing, add our core bots internally. Before modules are loaded and before the database is read
+ * This is used for modules adding commands and for the BotInfo* poiners in the command classes.
+ * When these bots are loaded from the databases the proper user/host/rname are added.
+ *
+ * If a user renames a bot in the configuration file, the new bot gets created here, and the old bot
+ * that is in the database gets created aswell, on its old nick. The old nick remains in all the channels
+ * etc and the new bot becomes the new client to accept commands. The user can use /bs bot del later
+ * if they want the old bot deleted.
+ *
+ * Note that it is important this is after loading the protocol module. The ircd struct must exist for
+ * the ts6_ functions
+ */
+ if (Config.s_OperServ)
+ new BotInfo(Config.s_OperServ, Config.ServiceUser, Config.ServiceHost, Config.desc_OperServ);
+ if (Config.s_NickServ)
+ new BotInfo(Config.s_NickServ, Config.ServiceUser, Config.ServiceHost, Config.desc_NickServ);
+ if (Config.s_ChanServ)
+ new BotInfo(Config.s_ChanServ, Config.ServiceUser, Config.ServiceHost, Config.desc_ChanServ);
+ if (Config.s_HostServ)
+ new BotInfo(Config.s_HostServ, Config.ServiceUser, Config.ServiceHost, Config.desc_HostServ);
+ if (Config.s_MemoServ)
+ new BotInfo(Config.s_MemoServ, Config.ServiceUser, Config.ServiceHost, Config.desc_MemoServ);
+ if (Config.s_BotServ)
+ new BotInfo(Config.s_BotServ, Config.ServiceUser, Config.ServiceHost, Config.desc_BotServ);
+ if (Config.s_GlobalNoticer)
+ new BotInfo(Config.s_GlobalNoticer, Config.ServiceUser, Config.ServiceHost, Config.desc_GlobalNoticer);
+
+ /* Add Encryption Modules */
+ ModuleManager::LoadModuleList(Config.EncModuleList);
+
+ /* Add Database Modules */
+ ModuleManager::LoadModuleList(Config.DBModuleList);
+
+ return 0;
+}
+
+int init_secondary(int ac, char **av)
+{
+#ifndef _WIN32
+ int started_from_term = isatty(0) && isatty(1) && isatty(2);
+#endif
+
+ /* Add Core MSG handles */
+ moduleAddMsgs();
+
+#ifndef _WIN32
+ if (!nofork)
+ {
+ int i;
+ if ((i = fork()) < 0) {
+ perror("fork()");
+ return -1;
+ } else if (i != 0) {
+ Alog(LOG_TERMINAL) << "PID " << i;
+ exit(0);
+ }
+ if (started_from_term) {
+ close(0);
+ close(1);
+ close(2);
+ }
+ if (setpgid(0, 0) < 0) {
+ perror("setpgid()");
+ return -1;
+ }
+ }
+#else
+ if (!SupportedWindowsVersion()) {
+
+ char *winver = GetWindowsVersion();
+
+ Alog() << winver << " is not a supported version of Windows";
+
+ delete [] winver;
+
+ return -1;
+
+ }
+ if (!nofork) {
+ Alog(LOG_TERMINAL) << "PID " << GetCurrentProcessId();
+ Alog() << "Launching Anope into the background";
+ FreeConsole();
+ }
+#endif
+
+ /* Write our PID to the PID file. */
+ write_pidfile();
+
+ /* Announce ourselves to the logfile. */
+ Alog() << "Anope " << version_number << " (ircd protocol: " << version_protocol << ") starting up"
+ << (debug || readonly ? " (options:" : "") << (debug ? " debug" : "")
+ << (readonly ? " readonly" : "") << (debug || readonly ? ")" : "");
+ start_time = time(NULL);
+
+
+
+ /* If in read-only mode, close the logfile again. */
+ if (readonly)
+ close_log();
+
+ /* Set signal handlers. Catch certain signals to let us do things or
+ * panic as necessary, and ignore all others.
+ */
+#ifndef _WIN32
+ signal(SIGHUP, sighandler);
+#endif
+ signal(SIGTERM, sighandler);
+ signal(SIGINT, sighandler);
+
+ /* Initialize multi-language support */
+ lang_init();
+ Alog(LOG_DEBUG) << "Loaded languages";
+
+
+ /* Initialize subservices */
+ ns_init();
+ cs_init();
+ ms_init();
+ bs_init();
+ os_init();
+ hostserv_init();
+
+ /* load any custom modules */
+ if (!nothird)
+ ModuleManager::LoadModuleList(Config.ModulesAutoLoad);
+
+ /* Initialize random number generator */
+ rand_init();
+ add_entropy_userkeys();
+
+ /* Load up databases */
+ Alog() << "Loading databases...";
+ EventReturn MOD_RESULT;
+ FOREACH_RESULT(I_OnLoadDatabase, OnLoadDatabase());
+ Alog() << "Databases loaded";
+
+ FOREACH_MOD(I_OnPostLoadDatabases, OnPostLoadDatabases());
+
+ return 0;
+}
+
+/*************************************************************************/