]> jfr.im git - irc.git/blame - software/ircd/www.irc.org/ftp/irc/org/irc2.11.2p3/ircd/ircd.c
init
[irc.git] / software / ircd / www.irc.org / ftp / irc / org / irc2.11.2p3 / ircd / ircd.c
CommitLineData
3bd189cb
JR
1/************************************************************************
2 * IRC - Internet Relay Chat, ircd/ircd.c
3 * Copyright (C) 1990 Jarkko Oikarinen and
4 * University of Oulu, Computing Center
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 1, or (at your option)
9 * any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19 */
20
21#ifndef lint
22static const volatile char rcsid[] = "@(#)$Id: ircd.c,v 1.165 2010/08/11 17:39:00 bif Exp $";
23#endif
24
25#include "os.h"
26#include "s_defines.h"
27#define IRCD_C
28#include "s_externs.h"
29#undef IRCD_C
30
31aClient me; /* That's me */
32aClient *client = &me; /* Pointer to beginning of Client list */
33
34static void open_debugfile(void), setup_signals(void), io_loop(void);
35
36#if defined(USE_IAUTH)
37static RETSIGTYPE s_slave(int s);
38#endif
39
40istat_t istat;
41iconf_t iconf;
42char **myargv;
43int rehashed = 0;
44int portnum = -1; /* Server port number, listening this */
45char *configfile = IRCDCONF_PATH; /* Server configuration file */
46int debuglevel = -1; /* Server debug level */
47int bootopt = BOOT_PROT|BOOT_STRICTPROT; /* Server boot option flags */
48int serverbooting = 1;
49int firstrejoindone = 0; /* Server rejoined the network after
50 start */
51char *debugmode = ""; /* -"- -"- -"- -"- */
52char *sbrk0; /* initial sbrk(0) */
53char *tunefile = IRCDTUNE_PATH;
54volatile static int dorehash = 0,
55 dorestart = 0,
56 restart_iauth = 0;
57
58#ifdef DELAY_CLOSE
59time_t nextdelayclose = 0; /* time for next delayed close */
60#endif
61time_t nextconnect = 1; /* time for next try_connections call */
62time_t nextgarbage = 1; /* time for next collect_channel_garbage call*/
63time_t nextping = 1; /* same as above for check_pings() */
64time_t nextdnscheck = 0; /* next time to poll dns to force timeouts */
65time_t nextexpire = 1; /* next expire run on the dns cache */
66time_t nextiarestart = 1; /* next time to check if iauth is alive */
67time_t nextpreference = 1; /* time for next calculate_preference call */
68#ifdef TKLINE
69time_t nexttkexpire = 0; /* time for next tkline_expire call */
70#endif
71
72aClient *ListenerLL = NULL; /* Listeners linked list */
73
74RETSIGTYPE s_die(int s)
75{
76 sendto_serv_v(NULL, SV_UID, ":%s SDIE", me.serv->sid);
77#ifdef USE_SYSLOG
78 (void)syslog(LOG_CRIT, "Server Killed By SIGTERM");
79 (void)closelog();
80#endif
81 logfiles_close();
82 ircd_writetune(tunefile);
83 flush_connections(me.fd);
84#ifdef UNIXPORT
85 {
86 aClient *acptr;
87 char unixpath[256];
88 for (acptr = ListenerLL; acptr; acptr = acptr->next)
89 {
90 if (IsUnixSocket(acptr))
91 {
92 sprintf(unixpath, "%s/%d",
93 acptr->confs->value.aconf->host,
94 acptr->confs->value.aconf->port);
95 (void)unlink(unixpath);
96 }
97 }
98 }
99#endif
100 exit(-1);
101}
102
103#if defined(USE_IAUTH)
104static RETSIGTYPE s_slave(int s)
105{
106# if POSIX_SIGNALS
107 struct sigaction act;
108
109 act.sa_handler = s_slave;
110 act.sa_flags = 0;
111 (void)sigemptyset(&act.sa_mask);
112 (void)sigaddset(&act.sa_mask, SIGUSR1);
113 (void)sigaction(SIGUSR1, &act, NULL);
114# else
115 (void)signal(SIGUSR1, s_slave);
116# endif
117 restart_iauth = 1;
118}
119#endif
120
121static RETSIGTYPE s_rehash(int s)
122{
123#if POSIX_SIGNALS
124 struct sigaction act;
125
126 act.sa_handler = s_rehash;
127 act.sa_flags = 0;
128 (void)sigemptyset(&act.sa_mask);
129 (void)sigaddset(&act.sa_mask, SIGHUP);
130 (void)sigaction(SIGHUP, &act, NULL);
131#else
132 (void)signal(SIGHUP, s_rehash); /* sysV -argv */
133#endif
134 if (dorehash >= 1)
135 dorehash = 2;
136 else
137 dorehash = 1;
138}
139
140void restart(char *mesg)
141{
142#ifdef USE_SYSLOG
143 (void)syslog(LOG_WARNING, "Restarting Server because: %s (%u)", mesg,
144 (u_int)((char *)sbrk((size_t)0)-sbrk0));
145#endif
146 sendto_flag(SCH_NOTICE, "Restarting server because: %s (%u)", mesg,
147 (u_int)((char *)sbrk((size_t)0)-sbrk0));
148 server_reboot();
149}
150
151RETSIGTYPE s_restart(int s)
152{
153#if POSIX_SIGNALS
154 struct sigaction act;
155
156 act.sa_handler = s_restart;
157 act.sa_flags = 0;
158 (void)sigemptyset(&act.sa_mask);
159 (void)sigaddset(&act.sa_mask, SIGINT);
160 (void)sigaction(SIGINT, &act, NULL);
161#else
162
163 (void)signal(SIGHUP, SIG_DFL); /* sysV -argv */
164#endif
165 if (bootopt & BOOT_TTY)
166 {
167 fprintf(stderr, "Caught SIGINT, terminating...\n");
168 exit(-1);
169 }
170
171 dorestart = 1;
172}
173
174void server_reboot(void)
175{
176 Reg int i;
177
178 sendto_flag(SCH_NOTICE, "Aieeeee!!! Restarting server... (%u)",
179 (u_int)((char *)sbrk((size_t)0)-sbrk0));
180
181 Debug((DEBUG_NOTICE,"Restarting server..."));
182 flush_connections(me.fd);
183 /*
184 ** fd 0 must be 'preserved' if either the -d or -i options have
185 ** been passed to us before restarting.
186 */
187#ifdef USE_SYSLOG
188 (void)closelog();
189#endif
190 logfiles_close();
191 for (i = 3; i < MAXCONNECTIONS; i++)
192 (void)close(i);
193 if (!(bootopt & (BOOT_TTY|BOOT_DEBUG)))
194 {
195 (void)close(2);
196 (void)close(1);
197 }
198 if ((bootopt & BOOT_CONSOLE) || isatty(0))
199 (void)close(0);
200 ircd_writetune(tunefile);
201 if (!(bootopt & BOOT_INETD))
202 {
203 (void)execv(IRCD_PATH, myargv);
204#ifdef USE_SYSLOG
205 /* Have to reopen since it has been closed above */
206
207 openlog(mybasename(myargv[0]), LOG_PID|LOG_NDELAY, LOG_FACILITY);
208 syslog(LOG_CRIT, "execv(%s,%s) failed: %m\n", IRCD_PATH,
209 myargv[0]);
210 closelog();
211#endif
212 Debug((DEBUG_FATAL,"Couldn't restart server: %s",
213 strerror(errno)));
214 }
215 exit(-1);
216}
217
218
219/*
220** try_connections
221**
222** Scan through configuration and try new connections.
223** Returns the calendar time when the next call to this
224** function should be made latest. (No harm done if this
225** is called earlier or later...)
226*/
227static time_t try_connections(time_t currenttime)
228{
229 Reg aConfItem *aconf;
230 Reg aClient *cptr;
231 aConfItem **pconf;
232 int confrq;
233 time_t next = 0;
234 aClass *cltmp;
235 aConfItem *con_conf = NULL;
236 int allheld = 1;
237#ifdef DISABLE_DOUBLE_CONNECTS
238 int i;
239#endif
240
241 if ((bootopt & BOOT_STANDALONE))
242 return 0;
243
244 Debug((DEBUG_NOTICE,"Connection check at : %s",
245 myctime(currenttime)));
246 for (aconf = conf; aconf; aconf = aconf->next )
247 {
248 /* not a C-line */
249 if (!(aconf->status & (CONF_CONNECT_SERVER|CONF_ZCONNECT_SERVER)))
250 continue;
251
252 /* not a candidate for AC */
253 if (aconf->port <= 0)
254 continue;
255
256 cltmp = Class(aconf);
257 /* not a candidate for AC */
258 if (MaxLinks(cltmp) == 0)
259 continue;
260
261 /* minimize next to lowest hold time of all AC-able C-lines */
262 if (next > aconf->hold || next == 0)
263 next = aconf->hold;
264
265 /* skip conf if the use of it is on hold until future. */
266 if (aconf->hold > currenttime)
267 continue;
268
269 /* at least one candidate not held for future, good */
270 allheld = 0;
271
272 /* see if another link in this conf is allowed */
273 if (Links(cltmp) >= MaxLinks(cltmp))
274 continue;
275
276 /* next possible check after connfreq secs for this C-line */
277 confrq = get_con_freq(cltmp);
278 aconf->hold = currenttime + confrq;
279
280 /* is this server already connected? */
281 cptr = find_name(aconf->name, (aClient *)NULL);
282 if (!cptr)
283 cptr = find_mask(aconf->name, (aClient *)NULL);
284
285 /* matching client already exists, no AC to it */
286 if (cptr)
287 continue;
288
289 /* no such server, check D-lines */
290 if (find_denied(aconf->name, Class(cltmp)))
291 continue;
292
293#ifdef DISABLE_DOUBLE_CONNECTS
294 /* Much better would be traversing only unknown
295 ** connections, but this requires another global
296 ** variable, adding and removing from there in
297 ** proper places etc. Some day. --B. */
298 for (i = highest_fd; i >= 0; i--)
299 {
300 if (!(cptr = local[i]) ||
301 cptr->status > STAT_UNKNOWN)
302 {
303 continue;
304 }
305 /* an unknown traveller we have */
306 if (
307#ifndef INET6
308 cptr->ip.s_addr == aconf->ipnum.s_addr
309#else
310 !memcmp(cptr->ip.s6_addr,
311 aconf->ipnum.s6_addr, 16)
312#endif
313 )
314 {
315 /* IP the same. Coincidence? Maybe.
316 ** Do not cause havoc with double connect. */
317 break;
318 }
319 cptr = NULL;
320 }
321 if (cptr)
322 {
323 sendto_flag(SCH_SERVER, "AC to %s postponed", aconf->name);
324 continue;
325 }
326#endif
327 /* we have a candidate! */
328
329 /* choose the best. */
330 if (!con_conf ||
331 (con_conf->pref > aconf->pref && aconf->pref >= 0) ||
332 (con_conf->pref == -1 &&
333 Class(cltmp) > ConfClass(con_conf)))
334 {
335 con_conf = aconf;
336 }
337 /* above is my doubt: if we always choose best connection
338 ** and it always fails connecting, we may never try another,
339 ** even "worse"; what shall we do? --Beeth */
340 }
341 if (con_conf)
342 {
343 if (con_conf->next) /* are we already last? */
344 {
345 for (pconf = &conf; (aconf = *pconf);
346 pconf = &(aconf->next))
347 /* put the current one at the end and
348 * make sure we try all connections
349 */
350 if (aconf == con_conf)
351 *pconf = aconf->next;
352 (*pconf = con_conf)->next = 0;
353 }
354
355 /* "Penalty" for being the best, so in next call of
356 * try_connections() other servers have chance. --B. */
357 con_conf->hold += get_con_freq(Class(con_conf));
358
359 if (iconf.aconnect == 0 || iconf.aconnect == 2 &&
360 timeofday - iconf.split > DELAYCHASETIMELIMIT)
361 {
362 sendto_flag(SCH_NOTICE,
363 "Connection to %s deferred. Autoconnect "
364 "administratively disabled", con_conf->name);
365 }
366 else if (connect_server(con_conf, (aClient *)NULL,
367 (struct hostent *)NULL) == 0)
368 {
369 sendto_flag(SCH_NOTICE,
370 "Connection to %s[%s] activated.",
371 con_conf->name, con_conf->host);
372 }
373 }
374 else
375 if (allheld == 0) /* disable AC only when some C: got checked */
376 {
377 /* No suitable conf for AC was found, so why bother checking
378 ** again? If some server quits, it'd get reenabled --B. */
379 next = 0;
380 }
381 Debug((DEBUG_NOTICE,"Next connection check : %s", myctime(next)));
382 return (next);
383}
384
385/*
386 * calculate preference value based on accumulated stats.
387 */
388time_t calculate_preference(time_t currenttime)
389{
390 aConfItem *aconf;
391 aCPing *cp;
392 double f, f2;
393
394 for (aconf = conf; aconf; aconf = aconf->next)
395 {
396 /* not a C-line */
397 if (!(aconf->status & (CONF_CONNECT_SERVER|CONF_ZCONNECT_SERVER)))
398 continue;
399
400 /* not a candidate for AC */
401 if (aconf->port <= 0)
402 continue;
403
404 /* send (udp) pings for all AC-able C-lines, we'll use it to
405 ** calculate preferences */
406 send_ping(aconf);
407
408 if (!(cp = aconf->ping) || !cp->seq || !cp->recvd)
409 {
410 aconf->pref = -1;
411 }
412 else
413 {
414 f = (double)cp->recvd / (double)cp->seq;
415 f2 = pow(f, (double)20.0);
416 if (f2 < (double)0.001)
417 f = (double)0.001;
418 else
419 f = f2;
420 f2 = (double)cp->ping / (double)cp->recvd;
421 f = f2 / f;
422 if (f > 100000.0)
423 f = 100000.0;
424 aconf->pref = (u_int) (f * (double)100.0);
425 }
426 }
427 return currenttime + 60;
428}
429
430/* Checks all clients against KILL lines. (And remove them, if found.)
431** Only MAXDELAYEDKILLS at a time or all, if not defined.
432** Returns 1, if still work to do, 0 if finished.
433*/
434static int delayed_kills(time_t currenttime)
435{
436 static time_t dk_rehashed = 0; /* time of last rehash we're processing */
437 static int dk_lastfd; /* fd we last checked */
438 static int dk_checked; /* # clients we checked */
439 static int dk_killed; /* # clients we killed */
440 Reg aClient *cptr;
441 Reg int i, j;
442
443 if (dk_rehashed == 0)
444 {
445 dk_rehashed = currenttime;
446 dk_checked = 0;
447 dk_killed = 0;
448 dk_lastfd = highest_fd;
449 }
450#ifdef MAXDELAYEDKILLS
451 /* checking only this many clients each time */
452 j = dk_lastfd - MAXDELAYEDKILLS + 1;
453 if (j < 0)
454#endif
455 j = 0;
456
457 for (i = dk_lastfd; i >= j; i--)
458 {
459 int kflag = 0;
460 char *reason = NULL;
461
462 if (!(cptr = local[i]) || !IsPerson(cptr))
463 {
464 /* for K:lines we're interested only in local,
465 ** fully registered clients */
466 if (j > 0)
467 j--;
468 continue;
469 }
470
471 dk_checked++;
472 kflag = find_kill(cptr, 0, &reason);
473
474 /* If the client is a user and a KILL line was found
475 ** to be active, close this connection. */
476 if (kflag == -1)
477 {
478 char buf[100];
479
480 dk_killed++;
481 sendto_flag(SCH_NOTICE,
482 "Kill line active for %s",
483 get_client_name(cptr, FALSE));
484 cptr->exitc = EXITC_KLINE;
485 if (!BadPtr(reason))
486 sprintf(buf, "Kill line active: %.80s",
487 reason);
488 (void)exit_client(cptr, cptr, &me, (reason) ?
489 buf : "Kill line active");
490 }
491 }
492 dk_lastfd = i; /* from which fd to start next time */
493 Debug((DEBUG_DEBUG, "DelayedKills killed %d and counting...",
494 dk_killed));
495
496 if (dk_lastfd < 0)
497 {
498 sendto_flag(SCH_NOTICE, "DelayedKills checked %d killed %d "
499 "in %d sec", dk_checked, dk_killed,
500 currenttime - dk_rehashed);
501 dk_rehashed = 0;
502 if (rehashed == 2)
503 {
504 /* there was rehash queued, start again */
505 return 1;
506 }
507 return 0;
508 }
509 return rehashed;
510}
511
512static time_t check_pings(time_t currenttime)
513{
514#ifdef TIMEDKLINES
515 static time_t lkill = 0;
516#endif
517 Reg aClient *cptr;
518 Reg int kflag = 0;
519 aClient *bysptr = NULL;
520 int ping = 0, i;
521 time_t oldest = 0, timeout;
522 char *reason = NULL;
523
524 for (i = highest_fd; i >= 0; i--)
525 {
526 if (!(cptr = local[i]) || IsListener(cptr))
527 continue;
528
529#ifdef TIMEDKLINES
530 kflag = 0;
531 reason = NULL;
532 /*
533 ** Once per TIMEDKLINES seconds.
534 ** (1 minute is minimum resolution in K-line field)
535 */
536 if ((currenttime - lkill > TIMEDKLINES)
537 && IsPerson(cptr) && !IsKlineExempt(cptr))
538 {
539 kflag = find_kill(cptr, 1, &reason);
540 }
541#endif
542 ping = IsRegistered(cptr) ? cptr->ping : ACCEPTTIMEOUT;
543 Debug((DEBUG_DEBUG, "c(%s) %d p %d k %d a %d",
544 cptr->name, cptr->status, ping, kflag,
545 currenttime - cptr->lasttime));
546 /*
547 * Ok, so goto's are ugly and can be avoided here but this code
548 * is already indented enough so I think its justified. -avalon
549 */
550 if (!kflag && IsRegistered(cptr) &&
551 (ping >= currenttime - cptr->lasttime))
552 goto ping_timeout;
553 /*
554 * If the server hasnt talked to us in 2*ping seconds
555 * and it has a ping time, then close its connection.
556 * If the client is a user and a KILL line was found
557 * to be active, close this connection too.
558 */
559 if (kflag ||
560 ((currenttime - cptr->lasttime) >= (2 * ping) &&
561 (cptr->flags & FLAGS_PINGSENT)) ||
562 (!IsRegistered(cptr) &&
563 (currenttime - cptr->firsttime) >= ping))
564 {
565 if (!IsRegistered(cptr) &&
566 (DoingDNS(cptr) || DoingAuth(cptr) ||
567 DoingXAuth(cptr)))
568 {
569 if (cptr->authfd >= 0)
570 {
571 (void)close(cptr->authfd);
572 cptr->authfd = -1;
573 cptr->count = 0;
574 *cptr->buffer = '\0';
575 }
576 Debug((DEBUG_NOTICE, "%s/%c%s timeout %s",
577 (DoingDNS(cptr)) ? "DNS" : "dns",
578 (DoingXAuth(cptr)) ? "X" : "x",
579 (DoingAuth(cptr)) ? "AUTH" : "auth",
580 get_client_name(cptr,TRUE)));
581 del_queries((char *)cptr);
582 ClearAuth(cptr);
583#if defined(USE_IAUTH)
584 if (DoingDNS(cptr) || DoingXAuth(cptr))
585 {
586 if (DoingDNS(cptr) &&
587 (iauth_options & XOPT_EXTWAIT))
588 {
589 /* iauth wants more time */
590 sendto_iauth("%d d", cptr->fd);
591 ClearDNS(cptr);
592 cptr->lasttime = currenttime;
593 continue;
594 }
595 if (DoingXAuth(cptr) &&
596 (iauth_options & XOPT_NOTIMEOUT))
597 {
598 cptr->exitc = EXITC_AUTHTOUT;
599 sendto_iauth("%d T", cptr->fd);
600 exit_client(cptr, cptr, &me,
601 "Authentication Timeout");
602 continue;
603 }
604 sendto_iauth("%d T", cptr->fd);
605 SetDoneXAuth(cptr);
606 }
607#endif
608 ClearDNS(cptr);
609 ClearXAuth(cptr);
610 ClearWXAuth(cptr);
611 cptr->firsttime = currenttime;
612 cptr->lasttime = currenttime;
613 continue;
614 }
615 if (IsServer(cptr) || IsConnecting(cptr) ||
616 IsHandshake(cptr))
617 {
618 if (cptr->serv && cptr->serv->byuid[0])
619 {
620 bysptr = find_uid(cptr->serv->byuid,
621 NULL);
622 }
623 /* we are interested only in *remote* opers */
624 if (bysptr && !MyConnect(bysptr))
625 {
626 sendto_one(bysptr, ":%s NOTICE %s :"
627 "No response from %s, closing"
628 " link", ME, bysptr->name,
629 get_client_name(cptr, FALSE));
630 }
631 sendto_flag(SCH_NOTICE,
632 "No response from %s closing link",
633 get_client_name(cptr, FALSE));
634 }
635 /*
636 * this is used for KILL lines with time restrictions
637 * on them - send a message to the user being killed
638 * first.
639 */
640 if (kflag && IsPerson(cptr))
641 {
642 char buf[100];
643
644 sendto_flag(SCH_NOTICE,
645 "Kill line active for %s",
646 get_client_name(cptr, FALSE));
647 cptr->exitc = EXITC_KLINE;
648 if (!BadPtr(reason))
649 sprintf(buf, "Kill line active: %.80s",
650 reason);
651 (void)exit_client(cptr, cptr, &me, (reason) ?
652 buf : "Kill line active");
653 }
654 else
655 {
656 cptr->exitc = EXITC_PING;
657 (void)exit_client(cptr, cptr, &me,
658 "Ping timeout");
659 }
660 continue;
661 }
662 else if (IsRegistered(cptr) &&
663 (cptr->flags & FLAGS_PINGSENT) == 0)
664 {
665 /*
666 * if we havent PINGed the connection and we havent
667 * heard from it in a while, PING it to make sure
668 * it is still alive.
669 */
670 cptr->flags |= FLAGS_PINGSENT;
671 /* not nice but does the job */
672 cptr->lasttime = currenttime - ping;
673 sendto_one(cptr, "PING :%s", me.name);
674 }
675ping_timeout:
676 timeout = cptr->lasttime + ping;
677 while (timeout <= currenttime)
678 timeout += ping;
679 if (timeout < oldest || !oldest)
680 oldest = timeout;
681 }
682#ifdef TIMEDKLINES
683 if (currenttime - lkill > 60)
684 lkill = currenttime;
685#endif
686 if (!oldest || oldest < currenttime)
687 oldest = currenttime + PINGFREQUENCY;
688 if (oldest < currenttime + 30)
689 oldest += 30;
690 Debug((DEBUG_NOTICE,"Next check_ping() call at: %s, %d %d %d",
691 myctime(oldest), ping, oldest, currenttime));
692 return (oldest);
693}
694
695
696static void setup_me(aClient *mp)
697{
698 struct passwd *p;
699
700 p = getpwuid(getuid());
701 strncpyzt(mp->username, (p) ? p->pw_name : "unknown",
702 sizeof(mp->username));
703 (void)get_my_name(mp, mp->sockhost, sizeof(mp->sockhost)-1);
704 /* I think we need no hostp, especially fake one --B. */
705 mp->hostp = NULL;
706 if (mp->serv->namebuf[0] == '\0')
707 strncpyzt(mp->serv->namebuf, mp->sockhost, sizeof(mp->serv->namebuf));
708 if (me.info == DefInfo)
709 me.info = mystrdup("IRCers United");
710 mp->lasttime = mp->since = mp->firsttime = time(NULL);
711 mp->hopcount = 0;
712 mp->authfd = -1;
713 mp->auth = mp->username;
714 mp->confs = NULL;
715 mp->flags = 0;
716 mp->acpt = mp->from = mp;
717 mp->next = NULL;
718 mp->user = NULL;
719 mp->fd = -1;
720 SetMe(mp);
721 mp->serv->snum = find_server_num (ME);
722 /* we don't fill our own IP -> 0 as ip lenght */
723 (void) make_user(mp,0);
724 istat.is_users++; /* here, cptr->next is NULL, see make_user() */
725 mp->user->flags |= FLAGS_OPER;
726 mp->serv->up = mp;
727 mp->serv->maskedby = mp;
728 mp->serv->version |= SV_UID;
729 mp->user->server = find_server_string(mp->serv->snum);
730 strncpyzt(mp->user->username, (p) ? p->pw_name : "unknown",
731 sizeof(mp->user->username));
732 (void) strcpy(mp->user->host, mp->name);
733 SetEOB(mp);
734 istat.is_eobservers = 1;
735
736 (void)add_to_client_hash_table(mp->name, mp);
737 (void)add_to_sid_hash_table(mp->serv->sid, mp);
738 strncpyzt(mp->serv->verstr, PATCHLEVEL, sizeof(mp->serv->verstr));
739 setup_server_channels(mp);
740}
741
742/*
743** bad_command
744** This is called when the commandline is not acceptable.
745** Give error message and exit without starting anything.
746*/
747static void bad_command(void)
748{
749 (void)printf(
750 "Usage: ircd [-a] [-b] [-c]%s [-h servername] [-q] [-i]"
751 "[-T [tunefile]] [-p (strict|on|off)] [-s] [-v] [-t] %s\n",
752#ifdef CMDLINE_CONFIG
753 " [-f config]",
754#else
755 "",
756#endif
757#ifdef DEBUGMODE
758 " [-x loglevel]"
759#else
760 ""
761#endif
762 );
763 (void)printf("Server not started\n\n");
764 exit(-1);
765}
766
767int main(int argc, char *argv[])
768{
769 uid_t uid, euid;
770
771 sbrk0 = (char *)sbrk((size_t)0);
772 uid = getuid();
773 euid = geteuid();
774
775#ifdef CHROOTDIR
776 ircd_res_init();
777 if (chdir(ROOT_PATH)!=0)
778 {
779 perror("chdir");
780 (void)fprintf(stderr,"%s: Cannot chdir: %s.\n", IRCD_PATH,
781 ROOT_PATH);
782 exit(5);
783 }
784 if (chroot(ROOT_PATH)!=0)
785 {
786 perror("chroot");
787 (void)fprintf(stderr,"%s: Cannot chroot: %s.\n", IRCD_PATH,
788 ROOT_PATH);
789 exit(5);
790 }
791#endif /*CHROOTDIR*/
792
793#ifdef ZIP_LINKS
794 if (zlib_version[0] == '0')
795 {
796 fprintf(stderr, "zlib version 1.0 or higher required\n");
797 exit(1);
798 }
799 if (zlib_version[0] != ZLIB_VERSION[0])
800 {
801 fprintf(stderr, "incompatible zlib version\n");
802 exit(1);
803 }
804 if (strcmp(zlib_version, ZLIB_VERSION) != 0)
805 {
806 fprintf(stderr, "warning: different zlib version\n");
807 }
808#endif
809
810 myargv = argv;
811 (void)umask(077); /* better safe than sorry --SRB */
812 bzero((char *)&me, sizeof(me));
813
814 make_server(&me);
815 register_server(&me);
816
817 version = make_version(); /* Generate readable version string */
818
819 /*
820 ** All command line parameters have the syntax "-fstring"
821 ** or "-f string" (e.g. the space is optional). String may
822 ** be empty. Flag characters cannot be concatenated (like
823 ** "-fxyz"), it would conflict with the form "-fstring".
824 */
825 while (--argc > 0 && (*++argv)[0] == '-')
826 {
827 char *p = argv[0]+1;
828 int flag = *p++;
829
830 if (flag == '\0' || *p == '\0')
831 {
832 if (argc > 1 && argv[1][0] != '-')
833 {
834 p = *++argv;
835 argc -= 1;
836 }
837 else
838 {
839 p = "";
840 }
841 }
842
843 switch (flag)
844 {
845 case 'a':
846 bootopt |= BOOT_AUTODIE;
847 break;
848 case 'b':
849 bootopt |= BOOT_BADTUNE;
850 break;
851 case 'c':
852 bootopt |= BOOT_CONSOLE;
853 break;
854 case 'q':
855 bootopt |= BOOT_QUICK;
856 break;
857#ifdef CMDLINE_CONFIG
858 case 'f':
859 (void)setuid((uid_t)uid);
860 configfile = p;
861 break;
862#endif
863 case 'h':
864 if (*p == '\0')
865 bad_command();
866 strncpyzt(me.serv->namebuf, p, sizeof(me.serv->namebuf));
867 break;
868 case 'i':
869 bootopt |= BOOT_INETD|BOOT_AUTODIE;
870 break;
871 case 'p':
872 if (!strcmp(p, "strict"))
873 bootopt |= BOOT_PROT|BOOT_STRICTPROT;
874 else if (!strcmp(p, "on"))
875 bootopt |= BOOT_PROT;
876 else if (!strcmp(p, "off"))
877 bootopt &= ~(BOOT_PROT|BOOT_STRICTPROT);
878 else if (!strcmp(p, "standalone"))
879 bootopt |= BOOT_STANDALONE;
880 else
881 bad_command();
882 break;
883 case 's':
884 bootopt |= BOOT_NOIAUTH;
885 break;
886 case 't':
887#ifdef DEBUGMODE
888 (void)setuid((uid_t)uid);
889#endif
890 bootopt |= BOOT_TTY;
891 break;
892 case 'T':
893 tunefile = p;
894 break;
895 case 'v':
896 (void)printf("ircd %s %s\n\tzlib %s\n\tircd.conf delimiter %c\n\t%s #%s\n",
897 version, serveropts,
898#ifndef ZIP_LINKS
899 "not used",
900#else
901 zlib_version,
902#endif
903 IRCDCONF_DELIMITER,
904 creation, generation);
905 exit(0);
906 case 'x':
907#ifdef DEBUGMODE
908 (void)setuid((uid_t)uid);
909 debuglevel = atoi(p);
910 debugmode = *p ? p : "0";
911 bootopt |= BOOT_DEBUG;
912 break;
913#else
914 (void)fprintf(stderr,
915 "%s: DEBUGMODE must be defined for -x y\n",
916 myargv[0]);
917 exit(0);
918#endif
919 default:
920 bad_command();
921 }
922 }
923
924 if (strlen(tunefile) > 1023 || strlen(mybasename(tunefile)) > 42)
925 {
926 fprintf(stderr, "Too long tune filename\n");
927 exit(-1);
928 }
929 if (argc > 0)
930 bad_command(); /* This exits out */
931
932#ifndef IRC_UID
933 if ((uid != euid) && !euid)
934 {
935 (void)fprintf(stderr,
936 "ERROR: do not run ircd setuid root. Make it setuid a\
937 normal user.\n");
938 exit(-1);
939 }
940#endif
941
942#if !defined(CHROOTDIR)
943 (void)setuid((uid_t)euid);
944# if defined(IRC_UID) && defined(IRC_GID)
945 if ((int)getuid() == 0)
946 {
947 /* run as a specified user */
948 (void)fprintf(stderr,"WARNING: running ircd with uid = %d\n",
949 IRC_UID);
950 (void)fprintf(stderr," changing to gid %d.\n",IRC_GID);
951 (void)setgid(IRC_GID);
952 (void)setuid(IRC_UID);
953 }
954# endif
955#endif /*CHROOTDIR/UID/GID*/
956
957#if defined(USE_IAUTH)
958 /* At this point, we just check whether iauth is there. Real start
959 * is done in init_sys(). */
960 if ((bootopt & BOOT_NOIAUTH) == 0)
961 switch (vfork())
962 {
963 case -1:
964 fprintf(stderr, "%s: Unable to fork!", myargv[0]);
965 exit(-1);
966 case 0:
967 close(0); close(1); close(3);
968 if (execl(IAUTH_PATH, IAUTH, "-X", NULL) < 0)
969 _exit(-1);
970 default:
971 {
972 int rc;
973
974 (void)wait(&rc);
975 if (rc != 0)
976 {
977 fprintf(stderr,
978 "%s: error: unable to find \"%s\".\n",
979 myargv[0], IAUTH_PATH);
980 exit(-1);
981 }
982 }
983 }
984#endif
985
986 setup_signals();
987
988 /* didn't set debuglevel */
989 /* but asked for debugging output to tty */
990#ifdef DEBUGMODE
991
992 if ((debuglevel < 0) && (bootopt & BOOT_TTY))
993 {
994 (void)fprintf(stderr,
995 "you specified -t without -x. use -x <n>\n");
996 exit(-1);
997 }
998
999#endif
1000 timeofday = time(NULL);
1001 initanonymous();
1002 initstats();
1003 initruntimeconf();
1004 ircd_readtune(tunefile);
1005 motd = NULL;
1006 read_motd(IRCDMOTD_PATH);
1007 inithashtables();
1008 initlists();
1009 initclass();
1010 initwhowas();
1011 timeofday = time(NULL);
1012 open_debugfile();
1013 timeofday = time(NULL);
1014 (void)init_sys();
1015
1016#ifdef USE_SYSLOG
1017 openlog(mybasename(myargv[0]), LOG_PID|LOG_NDELAY, LOG_FACILITY);
1018#endif
1019 timeofday = time(NULL);
1020 if (initconf(bootopt) == -1)
1021 {
1022 Debug((DEBUG_FATAL, "Couldn't open configuration file %s",
1023 configfile));
1024 (void)fprintf(stderr,
1025 "Couldn't open configuration file %s (%s)\n",
1026 configfile,strerror(errno));
1027
1028 exit(-1);
1029 }
1030 else
1031 {
1032 aClient *acptr = NULL;
1033 int i;
1034
1035 for (i = 0; i <= highest_fd; i++)
1036 {
1037 if (!(acptr = local[i]))
1038 continue;
1039 if (IsListener(acptr))
1040 break;
1041 acptr = NULL;
1042 }
1043 /* exit if there is nothing to listen to */
1044 if (acptr == NULL && !(bootopt & BOOT_INETD))
1045 {
1046 fprintf(stderr,
1047 "Fatal Error: No working P-line in ircd.conf\n");
1048 exit(-1);
1049 }
1050 /* Is there an M-line? */
1051 if (!find_me())
1052 {
1053 fprintf(stderr,
1054 "Fatal Error: No M-line in ircd.conf.\n");
1055 exit(-1);
1056 }
1057 if ((i=check_servername(ME)))
1058 {
1059 fprintf(stderr,
1060 "Fatal Error: %s.\n", check_servername_errors[i-1][1]);
1061 exit(-1);
1062 }
1063 if (!me.serv->sid)
1064 {
1065 fprintf(stderr,
1066 "Fatal Error: No SID specified in ircd.conf\n");
1067 exit(-1);
1068 }
1069 if (!sid_valid(me.serv->sid))
1070 {
1071 fprintf(stderr,
1072 "Fatal Error: Invalid sid %s specified in ircd.conf\n",
1073 me.serv->sid);
1074 exit(-1);
1075 }
1076 if (!networkname)
1077 {
1078 fprintf(stderr,
1079 "Warning: Network name is not set in ircd.conf\n");
1080 }
1081 isupport = make_isupport(); /* Generate RPL_ISUPPORT (005) numerics */
1082 }
1083
1084 setup_me(&me);
1085 check_class();
1086 ircd_writetune(tunefile);
1087 if (bootopt & BOOT_INETD)
1088 {
1089 aClient *tmp;
1090 aConfItem *aconf;
1091
1092 tmp = make_client(NULL);
1093 make_server(tmp);
1094 register_server(tmp);
1095
1096 tmp->fd = 0;
1097 tmp->flags = FLAGS_LISTEN;
1098 tmp->acpt = tmp;
1099 tmp->from = tmp;
1100 tmp->firsttime = time(NULL);
1101
1102 SetMe(tmp);
1103
1104 (void)strcpy(tmp->serv->namebuf, "*");
1105
1106 if (inetport(tmp, 0, "0.0.0.0", 0, 1))
1107 tmp->fd = -1;
1108 if (tmp->fd == 0)
1109 {
1110 aconf = make_conf();
1111 aconf->status = CONF_LISTEN_PORT;
1112 aconf->clients++;
1113 aconf->next = conf;
1114 conf = aconf;
1115
1116 tmp->confs = make_link();
1117 tmp->confs->next = NULL;
1118 tmp->confs->value.aconf = aconf;
1119 add_fd(tmp->fd, &fdas);
1120 add_fd(tmp->fd, &fdall);
1121 set_non_blocking(tmp->fd, tmp);
1122 }
1123 else
1124 exit(5);
1125 }
1126
1127 Debug((DEBUG_NOTICE,"Server ready..."));
1128#ifdef USE_SYSLOG
1129 syslog(LOG_NOTICE, "Server Ready: v%s (%s #%s)", version, creation,
1130 generation);
1131#endif
1132 printf("Server %s (%s) version %s starting%s%s", ME, me.serv->sid,
1133 version, (bootopt & BOOT_TTY) ? " in foreground mode." : ".",
1134#ifdef DEBUGMODE
1135 "(DEBUGMODE)\n"
1136#else
1137 "\n"
1138#endif
1139 );
1140
1141 timeofday = time(NULL);
1142 mysrand(timeofday);
1143
1144 /* daemonize() closes 0,1,2 -- make sure you don't have any fd open */
1145 daemonize();
1146 logfiles_open();
1147 write_pidfile();
1148 dbuf_init();
1149
1150 serverbooting = 0;
1151
1152 while (1)
1153 io_loop();
1154}
1155
1156
1157static void io_loop(void)
1158{
1159 static time_t delay = 0;
1160 int maxs = 4;
1161
1162 if (timeofday >= nextpreference)
1163 nextpreference = calculate_preference(timeofday);
1164 /*
1165 ** We only want to connect if a connection is due,
1166 ** not every time through. Note, if there are no
1167 ** active C lines, this call to Tryconnections is
1168 ** made once only; it will return 0. - avalon
1169 */
1170 if (nextconnect && timeofday >= nextconnect)
1171 nextconnect = try_connections(timeofday);
1172#ifdef DELAY_CLOSE
1173 /* close all overdue delayed fds */
1174 if (nextdelayclose && timeofday >= nextdelayclose)
1175 nextdelayclose = delay_close(-1);
1176#endif
1177#ifdef TKLINE
1178 /* expire tklines */
1179 if (nexttkexpire && timeofday >= nexttkexpire)
1180 nexttkexpire = tkline_expire(0);
1181#endif
1182 /*
1183 ** Every once in a while, hunt channel structures that
1184 ** can be freed. Reop channels while at it, too.
1185 */
1186 if (timeofday >= nextgarbage)
1187 nextgarbage = collect_channel_garbage(timeofday);
1188 /*
1189 ** DNS checks. One to timeout queries, one for cache expiries.
1190 */
1191 if (timeofday >= nextdnscheck)
1192 nextdnscheck = timeout_query_list(timeofday);
1193 if (timeofday >= nextexpire)
1194 nextexpire = expire_cache(timeofday);
1195 /*
1196 ** take the smaller of the two 'timed' event times as
1197 ** the time of next event (stops us being late :) - avalon
1198 ** WARNING - nextconnect can return 0!
1199 */
1200 if (nextconnect)
1201 delay = MIN(nextping, nextconnect);
1202 else
1203 delay = nextping;
1204#ifdef DELAY_CLOSE
1205 if (nextdelayclose)
1206 delay = MIN(nextdelayclose, delay);
1207#endif
1208 delay = MIN(nextdnscheck, delay);
1209 delay = MIN(nextexpire, delay);
1210 delay = MIN(nextpreference, delay);
1211 delay -= timeofday;
1212 /*
1213 ** Adjust delay to something reasonable [ad hoc values]
1214 ** (one might think something more clever here... --msa)
1215 ** We don't really need to check that often and as long
1216 ** as we don't delay too long, everything should be ok.
1217 ** waiting too long can cause things to timeout...
1218 ** i.e. PINGS -> a disconnection :(
1219 ** - avalon
1220 */
1221 if (delay < 1)
1222 delay = 1;
1223 else
1224 delay = MIN(delay, TIMESEC);
1225
1226 /*
1227 ** First, try to drain traffic from servers and listening sockets.
1228 ** Give up either if there's no traffic or too many iterations.
1229 */
1230 while (maxs--)
1231 if (read_message(0, &fdas, 0))
1232 flush_fdary(&fdas);
1233 else
1234 break;
1235
1236 Debug((DEBUG_DEBUG, "delay for %d", delay));
1237 /*
1238 ** Second, deal with _all_ clients but only try to empty sendQ's for
1239 ** servers. Other clients are dealt with below..
1240 */
1241 if (read_message(1, &fdall, 1) == 0 && delay > 1)
1242 {
1243 /*
1244 ** Timed out (e.g. *NO* traffic at all).
1245 ** Try again but also check to empty sendQ's for all clients.
1246 */
1247 (void)read_message(delay - 1, &fdall, 0);
1248 }
1249 timeofday = time(NULL);
1250
1251 Debug((DEBUG_DEBUG ,"Got message(s)"));
1252 /*
1253 ** ...perhaps should not do these loops every time,
1254 ** but only if there is some chance of something
1255 ** happening (but, note that conf->hold times may
1256 ** be changed elsewhere--so precomputed next event
1257 ** time might be too far away... (similarly with
1258 ** ping times) --msa
1259 */
1260 if (timeofday >= nextping)
1261 {
1262 nextping = check_pings(timeofday);
1263 if (rehashed > 0)
1264 {
1265 rehashed = delayed_kills(timeofday);
1266 }
1267 }
1268
1269 if (dorestart)
1270 restart("Caught SIGINT");
1271 if (dorehash > 0)
1272 { /* Only on signal, not on oper /rehash */
1273 ircd_writetune(tunefile);
1274 (void)rehash(&me, &me, 1);
1275 dorehash--;
1276 }
1277 if (restart_iauth || timeofday >= nextiarestart)
1278 {
1279 start_iauth(restart_iauth);
1280 restart_iauth = 0;
1281 nextiarestart = timeofday + 15;
1282 }
1283 /*
1284 ** Flush output buffers on all connections now if they
1285 ** have data in them (or at least try to flush)
1286 ** -avalon
1287 */
1288 flush_connections(me.fd);
1289
1290#ifdef DEBUGMODE
1291 checklists();
1292#endif
1293
1294}
1295
1296/*
1297 * open_debugfile
1298 *
1299 * If the -t option is not given on the command line when the server is
1300 * started, all debugging output is sent to the file set by IRCDDBG_PATH.
1301 * Here we just open that file and make sure it is opened to fd 2 so that
1302 * any fprintf's to stderr also goto the logfile. If the debuglevel is not
1303 * set from the command line by -x, use /dev/null as the dummy logfile as long
1304 * as DEBUGMODE has been defined, else don't waste the fd.
1305 */
1306static void open_debugfile(void)
1307{
1308#ifdef DEBUGMODE
1309 int fd;
1310
1311 if (debuglevel >= 0)
1312 {
1313 (void)printf("isatty = %d ttyname = %#x\n",
1314 isatty(2), (u_int)ttyname(2));
1315 if (!(bootopt & BOOT_TTY)) /* leave debugging output on fd 2 */
1316 {
1317 (void)truncate(IRCDDBG_PATH, 0);
1318 if ((fd = open(IRCDDBG_PATH,O_WRONLY|O_CREAT,0600))<0)
1319 if ((fd = open("/dev/null", O_WRONLY)) < 0)
1320 exit(-1);
1321 if (fd != 2)
1322 {
1323 (void)dup2(fd, 2);
1324 (void)close(fd);
1325 }
1326 }
1327 Debug((DEBUG_FATAL, "Debug: File <%s> Level: %d at %s",
1328 ( (!(bootopt & BOOT_TTY)) ? IRCDDBG_PATH :
1329 (isatty(2) && ttyname(2)) ? ttyname(2) : "FD2-Pipe"),
1330 debuglevel, myctime(time(NULL))));
1331 }
1332#endif
1333 return;
1334}
1335
1336static void setup_signals(void)
1337{
1338#if POSIX_SIGNALS
1339 struct sigaction act;
1340
1341 act.sa_handler = SIG_IGN;
1342 act.sa_flags = 0;
1343 (void)sigemptyset(&act.sa_mask);
1344 (void)sigaddset(&act.sa_mask, SIGPIPE);
1345 (void)sigaddset(&act.sa_mask, SIGALRM);
1346# ifdef SIGWINCH
1347 (void)sigaddset(&act.sa_mask, SIGWINCH);
1348 (void)sigaction(SIGWINCH, &act, NULL);
1349# endif
1350 (void)sigaction(SIGPIPE, &act, NULL);
1351 act.sa_handler = dummy;
1352 (void)sigaction(SIGALRM, &act, NULL);
1353 act.sa_handler = s_rehash;
1354 (void)sigemptyset(&act.sa_mask);
1355 (void)sigaddset(&act.sa_mask, SIGHUP);
1356 (void)sigaction(SIGHUP, &act, NULL);
1357 act.sa_handler = s_restart;
1358 (void)sigaddset(&act.sa_mask, SIGINT);
1359 (void)sigaction(SIGINT, &act, NULL);
1360 act.sa_handler = s_die;
1361 (void)sigaddset(&act.sa_mask, SIGTERM);
1362 (void)sigaction(SIGTERM, &act, NULL);
1363# if defined(USE_IAUTH)
1364 act.sa_handler = s_slave;
1365# else
1366 act.sa_handler = SIG_IGN;
1367# endif
1368 (void)sigaddset(&act.sa_mask, SIGUSR1);
1369 (void)sigaction(SIGUSR1, &act, NULL);
1370# if defined(USE_IAUTH)
1371 act.sa_handler = SIG_IGN;
1372# ifdef SA_NOCLDWAIT
1373 act.sa_flags = SA_NOCLDWAIT;
1374# else
1375 act.sa_flags = 0;
1376# endif
1377 (void)sigaddset(&act.sa_mask, SIGCHLD);
1378 (void)sigaction(SIGCHLD, &act, NULL);
1379# endif
1380
1381# if defined(__FreeBSD__)
1382 /* Don't core after detaching from gdb on fbsd */
1383
1384 act.sa_handler = SIG_IGN;
1385 act.sa_flags = 0;
1386 (void)sigaddset(&act.sa_mask, SIGTRAP);
1387 (void)sigaction(SIGTRAP,&act,NULL);
1388# endif /* __FreeBSD__ */
1389
1390#else /* POSIX_SIGNALS */
1391
1392# ifndef HAVE_RELIABLE_SIGNALS
1393 (void)signal(SIGPIPE, dummy);
1394# ifdef SIGWINCH
1395 (void)signal(SIGWINCH, dummy);
1396# endif
1397# else /* HAVE_RELIABLE_SIGNALS */
1398# ifdef SIGWINCH
1399 (void)signal(SIGWINCH, SIG_IGN);
1400# endif
1401 (void)signal(SIGPIPE, SIG_IGN);
1402
1403# endif /* HAVE_RELIABLE_SIGNALS */
1404 (void)signal(SIGALRM, dummy);
1405 (void)signal(SIGHUP, s_rehash);
1406 (void)signal(SIGTERM, s_die);
1407 (void)signal(SIGINT, s_restart);
1408# if defined(USE_IAUTH)
1409 (void)signal(SIGUSR1, s_slave);
1410 (void)signal(SIGCHLD, SIG_IGN);
1411# else
1412 (void)signal(SIGUSR1, SIG_IGN);
1413# endif
1414
1415# if defined(__FreeBSD__)
1416 /* don't core after detaching from gdb on fbsd */
1417 (void)signal(SIGTRAP, SIG_IGN);
1418# endif /* __FreeBSD__ */
1419
1420#endif /* POSIX_SIGNAL */
1421
1422#ifdef RESTARTING_SYSTEMCALLS
1423 /*
1424 ** At least on Apollo sr10.1 it seems continuing system calls
1425 ** after signal is the default. The following 'siginterrupt'
1426 ** should change that default to interrupting calls.
1427 */
1428 (void)siginterrupt(SIGALRM, 1);
1429#endif
1430}
1431
1432/*
1433 * Called from bigger_hash_table(), s_die(), server_reboot(),
1434 * main(after initializations), grow_history(), rehash(io_loop) signal.
1435 */
1436void ircd_writetune(char *filename)
1437{
1438 int fd;
1439 char buf[100];
1440
1441 if (!filename || !*filename)
1442 return;
1443
1444 (void)truncate(filename, 0);
1445 if ((fd = open(filename, O_CREAT|O_WRONLY, 0600)) >= 0)
1446 {
1447 (void)sprintf(buf, "%d\n%d\n%d\n%d\n%d\n%d\n%d\n", ww_size,
1448 lk_size, _HASHSIZE, _CHANNELHASHSIZE,
1449 _SIDSIZE, poolsize, _UIDSIZE);
1450 if (write(fd, buf, strlen(buf)) == -1)
1451 sendto_flag(SCH_ERROR,
1452 "Failed (%d) to write tune file: %s.",
1453 errno, mybasename(filename));
1454 else
1455 sendto_flag(SCH_NOTICE, "Updated %s.",
1456 mybasename(filename));
1457 close(fd);
1458 }
1459 else
1460 sendto_flag(SCH_ERROR, "Failed (%d) to open tune file: %s.",
1461 errno, mybasename(filename));
1462}
1463
1464/*
1465 * Called only from main() at startup.
1466 */
1467void ircd_readtune(char *filename)
1468{
1469 int fd, t_data[7];
1470 char buf[100];
1471
1472 memset(buf, 0, sizeof(buf));
1473 if ((fd = open(filename, O_RDONLY)) != -1)
1474 {
1475 read(fd, buf, 100); /* no panic if this fails.. */
1476 if (sscanf(buf, "%d\n%d\n%d\n%d\n%d\n%d\n%d\n", &t_data[0],
1477 &t_data[1], &t_data[2], &t_data[3],
1478 &t_data[4], &t_data[5], &t_data[6]) != 7)
1479 {
1480 close(fd);
1481 if (bootopt & BOOT_BADTUNE)
1482 return;
1483 else
1484 {
1485 fprintf(stderr,
1486 "ircd tune file %s: bad format\n",
1487 filename);
1488 exit(1);
1489 }
1490 }
1491
1492 /*
1493 ** Initiate the tune-values after successfully
1494 ** reading the tune-file.
1495 */
1496 ww_size = t_data[0];
1497 lk_size = t_data[1];
1498 _HASHSIZE = t_data[2];
1499#ifdef USE_HOSTHASH
1500 _HOSTNAMEHASHSIZE = t_data[2]; /* hostname has always same size
1501 as the client hash */
1502#endif
1503#ifdef USE_IPHASH
1504 _IPHASHSIZE = t_data[2];
1505#endif
1506 _CHANNELHASHSIZE = t_data[3];
1507 _SIDSIZE = t_data[4];
1508 poolsize = t_data[5];
1509 _UIDSIZE = t_data[6];
1510
1511 /*
1512 ** the lock array only grows if the whowas array grows,
1513 ** I don't think it should be initialized with a lower
1514 ** size since it will never adjust unless whowas array does.
1515 */
1516 if (lk_size < ww_size)
1517 lk_size = ww_size;
1518 close(fd);
1519 }
1520}
1521