extern void init_counters(void);
+enum {
+ BOOT_DEBUG = 1,
+ BOOT_TTY = 2
+};
+
struct Client me; /* That's me */
struct Client* GlobalClientList = &me; /* Pointer to beginning of Client list */
time_t TSoffset = 0; /* Offset of timestamps to system clock */
int GlobalRestartFlag = 0; /* do a restart if set */
time_t CurrentTime; /* Updated every time we leave select() */
-char **myargv;
+static struct Daemon thisServer = { 0 }; /* server process info */
+
char *configfile = CPATH; /* Server configuration file */
int debuglevel = -1; /* Server debug level */
-unsigned int bootopt = 0; /* Server boot option flags */
char *debugmode = ""; /* -"- -"- -"- */
static char *dpath = DPATH;
static void server_reboot(const char* message)
{
- int i;
-
sendto_ops("Restarting server: %s", message);
Debug((DEBUG_NOTICE, "Restarting server..."));
flush_connections(0);
- /*
- * fd 0 must be 'preserved' if either the -d or -i options have
- * been passed to us before restarting.
- */
- close_log();
- for (i = 3; i < MAXCONNECTIONS; i++)
- close(i);
- if (!(bootopt & (BOOT_TTY | BOOT_DEBUG)))
- close(2);
- close(1);
- close(0);
+ close_log();
+ close_connections(!(thisServer.bootopt & (BOOT_TTY | BOOT_DEBUG)));
- execv(SPATH, myargv);
+ execv(SPATH, thisServer.argv);
- /* Have to reopen since it has been closed above */
- open_log(myargv[0]);
- ircd_log(L_CRIT, "execv(%s,%s) failed: %m\n", SPATH, myargv[0]);
+ /*
+ * Have to reopen since it has been closed above
+ */
+ open_log(*thisServer.argv);
+ ircd_log(L_CRIT, "execv(%s,%s) failed: %m\n", SPATH, *thisServer.argv);
Debug((DEBUG_FATAL, "Couldn't restart server \"%s\": %s",
SPATH, (strerror(errno)) ? strerror(errno) : ""));
ircd_log(L_CRIT, "Server terminating: %s", message);
sendto_ops("Server terminating: %s", message);
flush_connections(0);
- exit(2);
+ close_connections(1);
+ thisServer.running = 0;
}
void server_restart(const char* message)
* This is called when the commandline is not acceptable.
* Give error message and exit without starting anything.
*/
-static int bad_command(void)
+static void print_usage(void)
{
- printf("Usage: ircd %s[-h servername] [-x loglevel] [-t]\n",
-#ifdef CMDLINE_CONFIG
- "[-f config] "
-#else
- ""
+ printf("Usage: ircd [-f config] [-h servername] [-x loglevel] [-ntv]\n");
+ printf("Server not started\n");
+}
+
+
+/*
+ * for getopt
+ * ZZZ this is going to need confirmation on other OS's
+ *
+ * #include <getopt.h>
+ * Solaris has getopt.h, you should too... hopefully
+ * BSD declares them in stdlib.h
+ * extern char *optarg;
+ *
+ * for FreeBSD the following are defined:
+ *
+ * extern char *optarg;
+ * extern int optind;
+ * extern in optopt;
+ * extern int opterr;
+ * extern in optreset;
+ *
+ *
+ * All command line parameters have the syntax "-f string" or "-fstring"
+ * OPTIONS:
+ * -d filename - specify d:line file
+ * -f filename - specify config file
+ * -h hostname - specify server name
+ * -k filename - specify k:line file (hybrid)
+ * -l filename - specify log file
+ * -n - do not fork, run in foreground
+ * -t - do not fork send debugging info to tty
+ * -v - print version and exit
+ * -x - set debug level, if compiled for debug logging
+ */
+static void parse_command_line(int argc, char** argv)
+{
+ const char* options = "d:f:h:ntvx:";
+ int opt;
+
+ if (thisServer.euid != thisServer.uid)
+ setuid(thisServer.uid);
+
+ while ((opt = getopt(argc, argv, options)) != EOF) {
+ switch (opt) {
+ case 'd':
+ if (optarg)
+ dpath = optarg;
+ break;
+ case 'f':
+ if (optarg)
+ configfile = optarg;
+ break;
+ case 'h':
+ if (optarg)
+ ircd_strncpy(me.name, optarg, HOSTLEN);
+ break;
+ case 'n':
+ case 't':
+ thisServer.bootopt |= BOOT_TTY;
+ break;
+ case 'v':
+ printf("ircd %s\n", version);
+ exit(0);
+ case 'x':
+ if (optarg) {
+ debuglevel = atoi(optarg);
+ if (debuglevel < 0)
+ debuglevel = 0;
+ debugmode = optarg;
+ thisServer.bootopt |= BOOT_DEBUG;
+ }
+ break;
+ default:
+ print_usage();
+ exit(1);
+ }
+ }
+}
+
+/*
+ * daemon_init
+ */
+static void daemon_init(int no_fork)
+{
+ if (!init_connection_limits())
+ exit(2);
+
+ close_connections(!(thisServer.bootopt & (BOOT_DEBUG | BOOT_TTY)));
+ if (no_fork)
+ return;
+
+ if (fork())
+ exit(0);
+#ifdef TIOCNOTTY
+ {
+ int fd;
+ if ((fd = open("/dev/tty", O_RDWR)) > -1) {
+ ioctl(fd, TIOCNOTTY, 0);
+ close(fd);
+ }
+ }
#endif
- );
- printf("Server not started\n\n");
- return (-1);
+ setsid();
}
-int main(int argc, char *argv[])
+
+static void event_loop(void)
{
- uid_t uid;
- uid_t euid;
time_t delay = 0;
+
+ while (thisServer.running) {
+ /*
+ * We only want to connect if a connection is due,
+ * not every time through. Note, if there are no
+ * active C lines, this call to Tryconnections is
+ * made once only; it will return 0. - avalon
+ */
+ if (nextconnect && CurrentTime >= nextconnect)
+ nextconnect = try_connections();
+ /*
+ * DNS checks. One to timeout queries, one for cache expiries.
+ */
+ nextdnscheck = timeout_resolver(CurrentTime);
+ /*
+ * Take the smaller of the two 'timed' event times as
+ * the time of next event (stops us being late :) - avalon
+ * WARNING - nextconnect can return 0!
+ */
+ if (nextconnect)
+ delay = IRCD_MIN(nextping, nextconnect);
+ else
+ delay = nextping;
+ delay = IRCD_MIN(nextdnscheck, delay);
+ delay -= CurrentTime;
+ /*
+ * Adjust delay to something reasonable [ad hoc values]
+ * (one might think something more clever here... --msa)
+ * We don't really need to check that often and as long
+ * as we don't delay too long, everything should be ok.
+ * waiting too long can cause things to timeout...
+ * i.e. PINGS -> a disconnection :(
+ * - avalon
+ */
+ if (delay < 1)
+ delay = 1;
+ else
+ delay = IRCD_MIN(delay, TIMESEC);
+ read_message(delay);
+
+ Debug((DEBUG_DEBUG, "Got message(s)"));
+
+ /*
+ * ...perhaps should not do these loops every time,
+ * but only if there is some chance of something
+ * happening (but, note that conf->hold times may
+ * be changed elsewhere--so precomputed next event
+ * time might be too far away... (similarly with
+ * ping times) --msa
+ */
+ if (CurrentTime >= nextping)
+ nextping = check_pings();
+
+ /*
+ * timeout pending queries that haven't been responded to
+ */
+ timeout_auth_queries(CurrentTime);
+
+ if (GlobalRehashFlag) {
+ rehash(&me, 1);
+ GlobalRehashFlag = 0;
+ }
+ if (GlobalRestartFlag)
+ server_restart("caught signal: SIGINT");
+ }
+}
+
+int main(int argc, char *argv[])
+{
#if defined(HAVE_SETRLIMIT) && defined(RLIMIT_CORE)
struct rlimit corelim;
#endif
CurrentTime = time(NULL);
-
/*
* sanity check
*/
fprintf(stderr, "%s: MAXCONNECTIONS insane: %d\n", *argv, MAXCONNECTIONS);
return 2;
}
-
- uid = getuid();
- euid = geteuid();
+ thisServer.argc = argc;
+ thisServer.argv = argv;
+ thisServer.uid = getuid();
+ thisServer.euid = geteuid();
#ifdef PROFIL
monstartup(0, etext);
moncontrol(1);
#endif
#ifdef CHROOTDIR
- if (chdir(DPATH))
- {
- fprintf(stderr, "Fail: Cannot chdir(%s): %s\n", DPATH, (strerror(errno)) ? strerror(errno) : "");
+ if (chdir(DPATH)) {
+ fprintf(stderr, "Fail: Cannot chdir(%s): %s\n", DPATH, strerror(errno));
exit(2);
}
- if (chroot(DPATH))
- {
- fprintf(stderr, "Fail: Cannot chroot(%s): %s\n", DPATH, (strerror(errno)) ? strerror(errno) : "");
+ if (chroot(DPATH)) {
+ fprintf(stderr, "Fail: Cannot chroot(%s): %s\n", DPATH, strerror(errno));
exit(5);
}
dpath = "/";
#endif /*CHROOTDIR */
- myargv = argv;
umask(077); /* better safe than sorry --SRB */
memset(&me, 0, sizeof(me));
me.fd = -1;
-#if 0
-#ifdef VIRTUAL_HOST
- memset(&vserv, 0, sizeof(vserv));
-#endif
-#endif
-
setup_signals();
initload();
#if defined(HAVE_SETRLIMIT) && defined(RLIMIT_CORE)
if (getrlimit(RLIMIT_CORE, &corelim))
{
- fprintf(stderr, "Read of rlimit core size failed: %s\n", (strerror(errno) ? strerror(errno) : "");
+ fprintf(stderr, "Read of rlimit core size failed: %s\n", strerror(errno));
corelim.rlim_max = RLIM_INFINITY; /* Try to recover */
}
corelim.rlim_cur = corelim.rlim_max;
if (setrlimit(RLIMIT_CORE, &corelim))
- fprintf(stderr, "Setting rlimit core size failed: %s\n", (strerror(errno) ? strerror(errno) : "");
-#endif
-
- /*
- * All command line parameters have the syntax "-fstring"
- * or "-f string" (e.g. the space is optional). String may
- * be empty. Flag characters cannot be concatenated (like
- * "-fxyz"), it would conflict with the form "-fstring".
- */
- while (--argc > 0 && (*++argv)[0] == '-')
- {
- char *p = argv[0] + 1;
- int flag = *p++;
-
- if (flag == '\0' || *p == '\0')
- {
- if (argc > 1 && argv[1][0] != '-')
- {
- p = *++argv;
- argc -= 1;
- }
- else
- p = "";
- }
-
- switch (flag)
- {
- case 'q':
- bootopt |= BOOT_QUICK;
- break;
- case 'd':
- if (euid != uid)
- setuid((uid_t) uid);
- dpath = p;
- break;
-#ifdef CMDLINE_CONFIG
- case 'f':
- if (euid != uid)
- setuid((uid_t) uid);
- configfile = p;
- break;
-#endif
- case 'h':
- ircd_strncpy(me.name, p, HOSTLEN);
- break;
- case 't':
- if (euid != uid)
- setuid((uid_t) uid);
- bootopt |= BOOT_TTY;
- break;
- case 'v':
- printf("ircd %s\n", version);
- exit(0);
-#if 0
-#ifdef VIRTUAL_HOST
- case 'w':
- {
- struct hostent *hep;
- if (!(hep = gethostbyname(p)))
- {
- fprintf(stderr, "%s: Error creating virtual host \"%s\": %d",
- argv[0], p, h_errno);
- return 2;
- }
- if (hep->h_addrtype == AF_INET && hep->h_addr_list[0] &&
- !hep->h_addr_list[1])
- {
- memcpy(&vserv.sin_addr, hep->h_addr_list[0], sizeof(struct in_addr));
- vserv.sin_family = AF_INET;
- }
- else
- {
- fprintf(stderr, "%s: Error creating virtual host \"%s\": "
- "Use -w <IP-number of interface>\n", argv[0], p);
- return 2;
- }
- break;
- }
+ fprintf(stderr, "Setting rlimit core size failed: %s\n", strerror(errno));
#endif
-#endif
- case 'x':
-#ifdef DEBUGMODE
- if (euid != uid)
- setuid((uid_t) uid);
- debuglevel = atoi(p);
- debugmode = *p ? p : "0";
- bootopt |= BOOT_DEBUG;
- break;
-#else
- fprintf(stderr, "%s: DEBUGMODE must be defined for -x y\n", myargv[0]);
- exit(0);
-#endif
- default:
- bad_command();
- break;
- }
- }
+ parse_command_line(argc, argv);
- if (chdir(dpath))
- {
- fprintf(stderr, "Fail: Cannot chdir(%s): %s\n", dpath, (strerror(errno)) ? strerror(errno) : "");
+ if (chdir(dpath)) {
+ fprintf(stderr, "Fail: Cannot chdir(%s): %s\n", dpath, strerror(errno));
exit(2);
}
#ifndef IRC_UID
- if ((uid != euid) && !euid)
- {
+ if ((thisServer.uid != thisServer.euid) && !thisServer.euid) {
fprintf(stderr,
"ERROR: do not run ircd setuid root. Make it setuid a normal user.\n");
exit(2);
#endif
#if !defined(CHROOTDIR) || (defined(IRC_UID) && defined(IRC_GID))
- if (euid != uid)
- {
- setuid(uid);
- setuid(euid);
+ if (thisServer.euid != thisServer.uid) {
+ setuid(thisServer.uid);
+ setuid(thisServer.euid);
}
- if (0 == getuid())
- {
+ if (0 == getuid()) {
#if defined(IRC_UID) && defined(IRC_GID)
/* run as a specified user */
}
#endif /*CHROOTDIR/UID/GID */
- if (argc > 0)
- return bad_command(); /* This should exit out */
-
/* Sanity checks */
{
char c;
}
}
}
- if (c)
- {
- fprintf(stderr, "Check on %cPATH (%s) failed: %s\n",
- c, path, (strerror(errno)) ? strerror(errno) : "");
+ if (c) {
+ fprintf(stderr, "Check on %cPATH (%s) failed: %s\n", c, path, strerror(errno));
fprintf(stderr,
"Please create file and/or rerun `make config' and recompile to correct this.\n");
#ifdef CHROOTDIR
- fprintf(stderr,
- "Keep in mind that all paths are relative to CHROOTDIR.\n");
+ fprintf(stderr, "Keep in mind that all paths are relative to CHROOTDIR.\n");
#endif
exit(2);
}
initwhowas();
initmsgtree();
initstats();
- open_debugfile();
- init_sys();
- set_nomem_handler(outofmemory);
- me.fd = -1;
+ debug_init(thisServer.bootopt & BOOT_TTY);
+ daemon_init(thisServer.bootopt & BOOT_TTY);
- open_log(myargv[0]);
+ set_nomem_handler(outofmemory);
+ init_resolver();
+
+ open_log(*argv);
- if (initconf(bootopt) == -1) {
+ if (!conf_init()) {
Debug((DEBUG_FATAL, "Failed in reading configuration file %s", configfile));
printf("Couldn't open configuration file %s\n", configfile);
exit(2);
Debug((DEBUG_NOTICE, "Server ready..."));
ircd_log(L_NOTICE, "Server Ready");
+ thisServer.running = 1;
- for (;;)
- {
- /*
- * We only want to connect if a connection is due,
- * not every time through. Note, if there are no
- * active C lines, this call to Tryconnections is
- * made once only; it will return 0. - avalon
- */
- if (nextconnect && CurrentTime >= nextconnect)
- nextconnect = try_connections();
- /*
- * DNS checks. One to timeout queries, one for cache expiries.
- */
- nextdnscheck = timeout_resolver(CurrentTime);
- /*
- * Take the smaller of the two 'timed' event times as
- * the time of next event (stops us being late :) - avalon
- * WARNING - nextconnect can return 0!
- */
- if (nextconnect)
- delay = IRCD_MIN(nextping, nextconnect);
- else
- delay = nextping;
- delay = IRCD_MIN(nextdnscheck, delay);
- delay -= CurrentTime;
- /*
- * Adjust delay to something reasonable [ad hoc values]
- * (one might think something more clever here... --msa)
- * We don't really need to check that often and as long
- * as we don't delay too long, everything should be ok.
- * waiting too long can cause things to timeout...
- * i.e. PINGS -> a disconnection :(
- * - avalon
- */
- if (delay < 1)
- delay = 1;
- else
- delay = IRCD_MIN(delay, TIMESEC);
- read_message(delay);
-
- Debug((DEBUG_DEBUG, "Got message(s)"));
+ event_loop();
+ return 0;
+}
- /*
- * ...perhaps should not do these loops every time,
- * but only if there is some chance of something
- * happening (but, note that conf->hold times may
- * be changed elsewhere--so precomputed next event
- * time might be too far away... (similarly with
- * ping times) --msa
- */
- if (CurrentTime >= nextping)
- nextping = check_pings();
-
- /*
- * timeout pending queries that haven't been responded to
- */
- timeout_auth_queries(CurrentTime);
- if (GlobalRehashFlag) {
- rehash(&me, 1);
- GlobalRehashFlag = 0;
- }
- if (GlobalRestartFlag)
- server_restart("caught signal: SIGINT");
- }
-}