chiark / gitweb /
use libinn logging where applicable - compiles
[inn-innduct.git] / innd / innd.c
1 /*  $Id: innd.c 7858 2008-06-05 18:51:20Z iulius $
2 **
3 **  Variable definitions, miscellany, and main().
4 */
5
6 #include "config.h"
7 #include "clibrary.h"
8
9 #include "inn/innconf.h"
10 #include "inn/messages.h"
11 #include "innperl.h"
12
13 #define DEFINE_DATA
14 #include "innd.h"
15 #include "ov.h"
16
17
18 bool            Debug = false;
19 bool            NNRPTracing = false;
20 bool            StreamingOff = false ; /* default is we can stream */
21 bool            Tracing = false;
22 bool            DoCancels = true;
23 char            LogName[] = "SERVER";
24 int             ErrorCount = IO_ERROR_COUNT;
25 OPERATINGMODE   Mode = OMrunning;
26 int             RemoteLimit = REMOTELIMIT;
27 time_t          RemoteTimer = REMOTETIMER;
28 int             RemoteTotal = REMOTETOTAL;
29 bool            ThrottledbyIOError = false;
30
31 static char     *PID = NULL;
32
33 /* Signal handling.  If we receive a signal that should kill the server,
34    killer_signal is set to the signal number that we received.  This isn't
35    what indicates that we should terminate; that's the separate global
36    variable GotTerminate, used in CHANreadloop. */
37 static volatile sig_atomic_t killer_signal = 0;
38
39 /* Whether our self-maintained logs (stdout and stderr) are buffered, used
40    to determine whether fflush is needed.  Should be static. */
41 bool BufferedLogs = true;
42
43 /* FILEs for logs and error logs.  Everything should just use stdout and
44    stderr. */
45 FILE *Log = NULL;
46 FILE *Errlog = NULL;
47
48 /* Some very old systems have a completely inadequate BUFSIZ buffer size, at
49    least for our logging purposes. */
50 #if BUFSIZ < 4096
51 # define LOG_BUFSIZ 4096
52 #else
53 # define LOG_BUFSIZ BUFSIZ
54 #endif
55
56 /* Internal prototypes. */
57 static RETSIGTYPE       catch_terminate(int sig);
58 static void             xmalloc_abort(const char *what, size_t size,
59                                       const char *file, int line);
60
61 /* header table initialization */
62 #define ARTHEADERINIT(name, type) {name, type, sizeof(name) - 1}
63 const ARTHEADER ARTheaders[] = {
64   /*             Name                   Type */
65   ARTHEADERINIT("Approved",             HTstd),
66 /* #define HDR__APPROVED                        0 */
67   ARTHEADERINIT("Control",              HTstd),
68 /* #define HDR__CONTROL                         1 */
69   ARTHEADERINIT("Date",                 HTreq),
70 /* #define HDR__DATE                            2 */
71   ARTHEADERINIT("Distribution",         HTstd),
72 /* #define HDR__DISTRIBUTION                    3 */
73   ARTHEADERINIT("Expires",              HTstd),
74 /* #define HDR__EXPIRES                         4 */
75   ARTHEADERINIT("From",                 HTreq),
76 /* #define HDR__FROM                            5 */
77   ARTHEADERINIT("Lines",                HTstd),
78 /* #define HDR__LINES                           6 */
79   ARTHEADERINIT("Message-ID",           HTreq),
80 /* #define HDR__MESSAGE_ID                      7 */
81   ARTHEADERINIT("Newsgroups",           HTreq),
82 /* #define HDR__NEWSGROUPS                      8 */
83   ARTHEADERINIT("Path",                 HTreq),
84 /* #define HDR__PATH                            9 */
85   ARTHEADERINIT("Reply-To",             HTstd),
86 /* #define HDR__REPLY_TO                        10 */
87   ARTHEADERINIT("Sender",               HTstd),
88 /* #define HDR__SENDER                          11 */
89   ARTHEADERINIT("Subject",              HTreq),
90 /* #define HDR__SUBJECT                         12 */
91   ARTHEADERINIT("Supersedes",           HTstd),
92 /* #define HDR__SUPERSEDES                      13 */
93   ARTHEADERINIT("Bytes",                HTstd),
94 /* #define HDR__BYTES                           14 */
95   ARTHEADERINIT("Also-Control",         HTobs),
96 /* #define HDR__ALSOCONTROL                     15 */
97   ARTHEADERINIT("References",           HTstd),
98 /* #define HDR__REFERENCES                      16 */
99   ARTHEADERINIT("Xref",                 HTsav),
100 /* #define HDR__XREF                            17 */
101   ARTHEADERINIT("Keywords",             HTstd),
102 /* #define HDR__KEYWORDS                        18 */
103   ARTHEADERINIT("X-Trace",              HTstd),
104 /* #define HDR__XTRACE                          19 */
105   ARTHEADERINIT("Date-Received",        HTobs),
106 /* #define HDR__DATERECEIVED                    20 */
107   ARTHEADERINIT("Posted",               HTobs),
108 /* #define HDR__POSTED                          21 */
109   ARTHEADERINIT("Posting-Version",      HTobs),
110 /* #define HDR__POSTINGVERSION                  22 */
111   ARTHEADERINIT("Received",             HTobs),
112 /* #define HDR__RECEIVED                        23 */
113   ARTHEADERINIT("Relay-Version",        HTobs),
114 /* #define HDR__RELAYVERSION                    24 */
115   ARTHEADERINIT("NNTP-Posting-Host",    HTstd),
116 /* #define HDR__NNTPPOSTINGHOST                 25 */
117   ARTHEADERINIT("Followup-To",          HTstd),
118 /* #define HDR__FOLLOWUPTO                      26 */
119   ARTHEADERINIT("Organization",         HTstd),
120 /* #define HDR__ORGANIZATION                    27 */
121   ARTHEADERINIT("Content-Type",         HTstd),
122 /* #define HDR__CONTENTTYPE                     28 */
123   ARTHEADERINIT("Content-Base",         HTstd),
124 /* #define HDR__CONTENTBASE                     29 */
125   ARTHEADERINIT("Content-Disposition",  HTstd),
126 /* #define HDR__CONTENTDISPOSITION              30 */
127   ARTHEADERINIT("X-Newsreader",         HTstd),
128 /* #define HDR__XNEWSREADER                     31 */
129   ARTHEADERINIT("X-Mailer",             HTstd),
130 /* #define HDR__XMAILER                         32 */
131   ARTHEADERINIT("X-Newsposter",         HTstd),
132 /* #define HDR__XNEWSPOSTER                     33 */
133   ARTHEADERINIT("X-Cancelled-By",       HTstd),
134 /* #define HDR__XCANCELLEDBY                    34 */
135   ARTHEADERINIT("X-Canceled-By",        HTstd),
136 /* #define HDR__XCANCELEDBY                     35 */
137   ARTHEADERINIT("Cancel-Key",           HTstd),
138 /* #define HDR__CANCELKEY                       36 */
139   ARTHEADERINIT("User-Agent",           HTstd),
140 /* #define HDR__USER_AGENT                      37 */
141   ARTHEADERINIT("X-Original-Message-ID",        HTstd),
142 /* #define HDR__X_ORIGINAL_MESSAGE_ID           38 */
143   ARTHEADERINIT("Cancel-Lock",          HTstd),
144 /* #define HDR__CANCEL_LOCK                     39 */
145   ARTHEADERINIT("Content-Transfer-Encoding",    HTstd),
146 /* #define HDR__CONTENT_TRANSFER_ENCODING       40 */
147   ARTHEADERINIT("Face",                 HTstd),
148 /* #define HDR__FACE                            41 */
149   ARTHEADERINIT("Injection-Info",       HTstd),
150 /* #define HDR__INJECTION_INFO                  42 */
151   ARTHEADERINIT("List-ID",              HTstd),
152 /* #define HDR__LIST_ID                         43 */
153   ARTHEADERINIT("MIME-Version",         HTstd),
154 /* #define HDR__MIME_VERSION                    44 */
155   ARTHEADERINIT("Originator",           HTstd),
156 /* #define HDR__ORIGINATOR                      45 */
157   ARTHEADERINIT("X-Auth",               HTstd),
158 /* #define HDR__X_AUTH                          46 */
159   ARTHEADERINIT("X-Complaints-To",      HTstd),
160 /* #define HDR__X_COMPLAINTS_TO                 47 */
161   ARTHEADERINIT("X-Face",               HTstd),
162 /* #define HDR__X_FACE                          48 */
163   ARTHEADERINIT("X-HTTP-UserAgent",     HTstd),
164 /* #define HDR__X_HTTP_USERAGENT                49 */
165   ARTHEADERINIT("X-HTTP-Via",           HTstd),
166 /* #define HDR__X_HTTP_VIA                      50 */
167   ARTHEADERINIT("X-Modbot",             HTstd),
168 /* #define HDR__X_MODBOT                        51 */
169   ARTHEADERINIT("X-Modtrace",           HTstd),
170 /* #define HDR__X_MODTRACE                      52 */
171   ARTHEADERINIT("X-No-Archive",         HTstd),
172 /* #define HDR__X_NO_ARCHIVE                    53 */
173   ARTHEADERINIT("X-Original-Trace",     HTstd),
174 /* #define HDR__X_ORIGINAL_TRACE                54 */
175   ARTHEADERINIT("X-Originating-IP",     HTstd),
176 /* #define HDR__X_ORIGINATING_IP                55 */
177   ARTHEADERINIT("X-PGP-Key",            HTstd),
178 /* #define HDR__X_PGP_KEY                       56 */
179   ARTHEADERINIT("X-PGP-Sig",            HTstd),
180 /* #define HDR__X_PGP_SIG                       57 */
181   ARTHEADERINIT("X-Poster-Trace",       HTstd),
182 /* #define HDR__X_POSTER_TRACE                  58 */
183   ARTHEADERINIT("X-Postfilter",         HTstd),
184 /* #define HDR__X_POSTFILTER                    59 */
185   ARTHEADERINIT("X-Proxy-User",         HTstd),
186 /* #define HDR__X_PROXY_USER                    60 */
187   ARTHEADERINIT("X-Submissions-To",     HTstd),
188 /* #define HDR__X_SUBMISSIONS_TO                61 */
189   ARTHEADERINIT("X-Usenet-Provider",    HTstd),
190 /* #define HDR__X_USENET_PROVIDER               62 */
191   ARTHEADERINIT("In-Reply-To",          HTstd),
192 /* #define HDR__IN_REPLY_TO                     63 */
193   ARTHEADERINIT("Injection-Date",       HTstd),
194 /* #define HDR__INJECTION_DATE                  64 */
195   ARTHEADERINIT("NNTP-Posting-Date",    HTstd)
196 /* #define HDR__NNTP_POSTING_DATE               65 */
197 };
198 /* #define MAX_ARTHEADER                        66 */
199 \f
200
201 /*
202 **  Signal handler to catch SIGTERM and similar signals and queue a clean
203 **  shutdown.
204 */
205 static RETSIGTYPE
206 catch_terminate(int sig)
207 {
208     GotTerminate = true;
209     killer_signal = sig;
210
211 #ifndef HAVE_SIGACTION
212     xsignal(sig, catch_terminate);
213 #endif
214 }
215
216
217 /*
218 **  Memory allocation failure handler.  Instead of the default behavior of
219 **  just exiting, call abort to generate a core dump.
220 */
221 static void
222 xmalloc_abort(const char *what, size_t size, const char *file, int line)
223 {
224     fprintf(stderr, "SERVER cant %s %lu bytes at %s line %d: %s", what,
225             (unsigned long) size, file, line, strerror(errno));
226     syslog(LOG_CRIT, "SERVER cant %s %lu bytes at %s line %d: %m", what,
227            (unsigned long) size, file, line);
228     abort();
229 }
230
231
232 /*
233 **  The name is self-explanatory.
234 */
235 void
236 CleanupAndExit(int status, const char *why)
237 {
238     JustCleanup();
239     if (why)
240         syslog(LOG_WARNING, "SERVER shutdown %s", why);
241     else
242         syslog(LOG_WARNING, "SERVER shutdown received signal %d",
243                killer_signal);
244     exit(status);
245 }
246
247
248 /*
249 **  Close down all parts of the system (e.g., before calling exit or exec).
250 */
251 void
252 JustCleanup(void)
253 {
254     SITEflushall(false);
255     CCclose();
256     LCclose();
257     NCclose();
258     RCclose();
259     ICDclose();
260     InndHisClose();
261     ARTclose();
262     if (innconf->enableoverview) 
263         OVclose();
264     NGclose();
265     SMshutdown();
266
267 #if DO_TCL
268     TCLclose();
269 #endif
270
271 #if DO_PERL
272     PerlFilter(false);
273     PerlClose();
274 #endif
275
276 #if DO_PYTHON
277     PYclose();
278 #endif
279
280     CHANshutdown();
281     innconf_free(innconf);
282     innconf = NULL;
283
284     sleep(1);
285
286     if (unlink(PID) < 0 && errno != ENOENT)
287         syslog(LOG_ERR, "SERVER cant unlink %s: %m", PID);
288 }
289
290
291 /*
292 **  Flush one log file, re-establishing buffering if necessary.  stdout is
293 **  block-buffered, stderr is line-buffered.
294 */
295 void
296 ReopenLog(FILE *F)
297 {
298     char *path, *oldpath;
299     int mask;
300
301     if (Debug)
302         return;
303
304     path = concatpath(innconf->pathlog,
305                       (F == stdout) ? _PATH_LOGFILE : _PATH_ERRLOG);
306     oldpath = concat(path, ".old", (char *) 0);
307     if (rename(path, oldpath) < 0)
308         syswarn("SERVER cant rename %s to %s", path, oldpath);
309     free(oldpath);
310     mask = umask(033);
311     if (freopen(path, "a", F) != F)
312         sysdie("SERVER cant freopen %s", path);
313     free(path);
314     umask(mask);
315     if (BufferedLogs)
316         setvbuf(F, NULL, (F == stdout) ? _IOFBF : _IOLBF, LOG_BUFSIZ);
317 }
318
319
320 /*
321 **  Print a usage message and exit.
322 */
323 static void
324 Usage(void)
325 {
326     fprintf(stderr, "Usage error.\n");
327     exit(1);
328 }
329
330
331 int
332 main(int ac, char *av[])
333 {
334     const char *name, *p;
335     char *path;
336     char *t;
337     bool flag;
338     static char         WHEN[] = "PID file";
339     int                 i, j, fd[MAX_SOCKETS + 1];
340     char                buff[SMBUF], *path1, *path2;
341     FILE                *F;
342     bool                ShouldFork;
343     bool                ShouldRenumber;
344     bool                ShouldSyntaxCheck;
345     bool                filter = true;
346     pid_t               pid;
347 #if     defined(_DEBUG_MALLOC_INC)
348     union malloptarg    m;
349 #endif  /* defined(_DEBUG_MALLOC_INC) */
350
351     /* Set up the pathname, first thing, and teach our error handlers about
352        the name of the program. */
353     name = av[0];
354     if (name == NULL || *name == '\0')
355         name = "innd";
356     else {
357         p = strrchr(name, '/');
358         if (p != NULL)
359             name = p + 1;
360     }
361     message_program_name = name;
362     openlog(name, LOG_CONS | LOG_NDELAY, LOG_INN_SERVER);
363     message_handlers_die(2, message_log_stderr, message_log_syslog_crit);
364     message_handlers_warn(2, message_log_stderr, message_log_syslog_err);
365     message_handlers_notice(1, message_log_syslog_notice);
366
367     /* Make sure innd is not running as root.  innd must be either started
368        via inndstart or use a non-privileged port. */
369     if (getuid() == 0 || geteuid() == 0)
370         die("SERVER must be run as user news, not root (use inndstart)");
371
372     /* Handle malloc debugging. */
373 #if     defined(_DEBUG_MALLOC_INC)
374     m.i = M_HANDLE_ABORT;
375     dbmallopt(MALLOC_WARN, &m);
376     dbmallopt(MALLOC_FATAL, &m);
377     m.i = 3;
378     dbmallopt(MALLOC_FILLAREA, &m);
379     m.i = 0;
380     dbmallopt(MALLOC_CKCHAIN, &m);
381     dbmallopt(MALLOC_CKDATA, &m);
382 #endif  /* defined(_DEBUG_MALLOC_INC) */
383
384     /* Set defaults. */
385     TimeOut.tv_sec = DEFAULT_TIMEOUT;
386     TimeOut.tv_usec = 0;
387     ShouldFork = true;
388     ShouldRenumber = false;
389     ShouldSyntaxCheck = false;
390     fd[0] = fd[1] = -1;
391
392     /* Set some options from inn.conf that can be overridden with
393        command-line options if they exist, so read inn.conf first. */
394     if (!innconf_read(NULL))
395         exit(1);
396
397     /* Parse JCL. */
398     CCcopyargv(av);
399     while ((i = getopt(ac, av, "ac:Cdfi:l:m:o:Nn:p:P:rst:uH:T:X:")) != EOF)
400         switch (i) {
401         default:
402             Usage();
403             /* NOTREACHED */
404         case 'a':
405             AnyIncoming = true;
406             break;
407         case 'c':
408             innconf->artcutoff = atoi(optarg);
409             break;
410         case 'C':
411             DoCancels = false;
412             break;
413         case 'd':
414             Debug = true;
415             break;
416         case 'f':
417             ShouldFork = false;
418             break;
419         case 'H':
420             RemoteLimit = atoi(optarg);
421             break;
422         case 'i':
423             innconf->maxconnections = atoi(optarg);
424             break;
425         case 'I':
426             if (innconf->bindaddress) free(innconf->bindaddress);
427             innconf->bindaddress = xstrdup(optarg);
428             break;
429         case 'l':
430             innconf->maxartsize = atol(optarg);
431             break;
432         case 'm':
433             if (ModeReason)
434                 free(ModeReason);
435             switch (*optarg) {
436             default:
437                 Usage();
438                 /* NOTREACHED */
439             case 'g':   Mode = OMrunning;       break;
440             case 'p':   Mode = OMpaused;        break;
441             case 't':   Mode = OMthrottled;     break;
442             }
443             if (Mode != OMrunning)
444                 ModeReason = concat(OMpaused ? "Paus" : "Throttl",
445                                     "ed from the command line", (char *) 0);
446             break;
447         case 'N':
448             filter = false;
449             break;
450         case 'n':
451             switch (*optarg) {
452             default:
453                 Usage();
454                 /* NOTREACHED */
455             case 'n':   innconf->readerswhenstopped = false;    break;
456             case 'y':   innconf->readerswhenstopped = true;     break;
457             }
458             break;
459         case 'o':
460             MaxOutgoing = atoi(optarg);
461             break;
462         case 'p':
463             /* Silently ignore multiple -p flags, in case ctlinnd xexec
464                called inndstart. */
465             if (fd[0] != -1)
466                 break;
467             t = xstrdup(optarg);
468             p = strtok(t, ",");
469             j = 0;
470             do {
471                 fd[j++] = atoi(p);
472                 if (j == MAX_SOCKETS)
473                     break;
474             } while ((p = strtok(NULL, ",")) != NULL);
475             fd[j] = -1;
476             free(t);
477             break;
478         case 'P':
479             innconf->port = atoi(optarg);
480             break;
481         case 'r':
482             ShouldRenumber = true;
483             break;
484         case 's':
485             ShouldSyntaxCheck = true;
486             break;
487         case 't':
488             TimeOut.tv_sec = atol(optarg);
489             break;
490         case 'T':
491             RemoteTotal = atoi(optarg);
492             break;
493         case 'u':
494             BufferedLogs = false;
495             break;
496         case 'X':
497             RemoteTimer = atoi(optarg);
498             break;
499         case 'Z':
500             StreamingOff = true;
501             break;
502         }
503     ac -= optind;
504     if (ac != 0)
505         Usage();
506     if (ModeReason && !innconf->readerswhenstopped)
507         NNRPReason = xstrdup(ModeReason);
508
509     if (ShouldSyntaxCheck) {
510         if ((p = CCcheckfile((char **)NULL)) == NULL)
511             exit(0);
512         fprintf(stderr, "%s\n", p + 2);
513         exit(1);
514     }
515
516     /* Get the Path entry. */
517     if (innconf->pathhost == NULL) {
518         syslog(L_FATAL, "%s No pathhost set", LogName);
519         exit(1);
520     }
521     Path.used = strlen(innconf->pathhost) + 1;
522     Path.size = Path.used + 1;
523     Path.data = xmalloc(Path.size);
524     snprintf(Path.data, Path.size, "%s!", innconf->pathhost);
525     if (innconf->pathalias == NULL) {
526         Pathalias.used = 0;
527         Pathalias.data = NULL;
528     } else {
529         Pathalias.used = strlen(innconf->pathalias) + 1;
530         Pathalias.size = Pathalias.used + 1;
531         Pathalias.data = xmalloc(Pathalias.size);
532         snprintf(Pathalias.data, Pathalias.size, "%s!", innconf->pathalias);
533     }
534     if (innconf->pathcluster == NULL) {
535         Pathcluster.used = 0;
536         Pathcluster.data = NULL;
537     } else {
538         Pathcluster.used = strlen(innconf->pathcluster) + 1;
539         Pathcluster.size = Pathcluster.used + 1;
540         Pathcluster.data = xmalloc(Pathcluster.size);
541         snprintf(Pathcluster.data, Pathcluster.size, "%s!", innconf->pathcluster);
542     }
543     /* Trace history ? */
544     if (innconf->stathist != NULL) {
545         syslog(L_NOTICE, "logging hist stats to %s", innconf->stathist);
546         HISlogto(innconf->stathist);
547     }
548
549     i = dbzneedfilecount();
550     if (!fdreserve(3 + i)) { /* TEMPORARYOPEN, history stats, INND_HISTORY and i */
551         syslog(L_FATAL, "%s cant reserve file descriptors %m", LogName);
552         exit(1);
553     }
554
555     /* Set up our permissions. */
556     umask(NEWSUMASK);
557
558     /* Become a daemon and initialize our log files. */
559     if (Debug) {
560         xsignal(SIGINT, catch_terminate);
561         if (chdir(innconf->patharticles) < 0)
562             sysdie("SERVER cant chdir to %s", innconf->patharticles);
563     } else {
564         if (ShouldFork)
565             daemonize(innconf->patharticles);
566
567         /* Open the logs.  stdout is used to log information about incoming
568            articles and stderr is used to log serious error conditions (as
569            well as to capture stderr from embedded filters).  Both are
570            normally fully buffered. */
571         path = concatpath(innconf->pathlog, _PATH_LOGFILE);
572         if (freopen(path, "a", stdout) == NULL)
573             sysdie("SERVER cant freopen stdout to %s", path);
574         setvbuf(stdout, NULL, _IOFBF, LOG_BUFSIZ);
575         free(path);
576         path = concatpath(innconf->pathlog, _PATH_ERRLOG);
577         if (freopen(path, "a", stderr) == NULL)
578             sysdie("SERVER cant freopen stderr to %s", path);
579         setvbuf(stderr, NULL, _IOLBF, BUFSIZ);
580         free(path);
581     }
582     Log = stdout;
583     Errlog = stderr;
584
585     /* Initialize overview if necessary. */
586     if (innconf->enableoverview && !OVopen(OV_WRITE))
587         die("SERVER cant open overview method");
588
589     /* Always attempt to increase the number of open file descriptors.  If
590        we're not root, this may just fail quietly. */
591     if (innconf->rlimitnofile > 0)
592         setfdlimit(innconf->rlimitnofile);
593
594     /* Get number of open channels. */
595     i = getfdlimit();
596     if (i < 0) {
597         syslog(L_FATAL, "%s cant get file descriptor limit: %m", LogName);
598         exit(1);
599     }
600
601     /* There is no file descriptor limit on some hosts; for those, cap at
602        MaxOutgoing plus maxconnections plus 20, or 5000, whichever is larger. 
603        Otherwise, we use insane amounts of memory for the channel table.
604        FIXME: Get rid of this hard-coded constant. */
605     if (i > 5000) {
606         int max;
607
608         max = innconf->maxconnections + MaxOutgoing + 20;
609         if (max < 5000)
610             max = 5000;
611         i = max;
612     }
613     syslog(L_NOTICE, "%s descriptors %d", LogName, i);
614     if (MaxOutgoing == 0) {
615         /* getfdlimit() - (stdio + dbz + cc + lc + rc + art + fudge) */
616         MaxOutgoing = i - (  3   +  3  +  2 +  1 +  1 +  1  +  2  );
617         syslog(L_NOTICE, "%s outgoing %d", LogName, MaxOutgoing);
618     }
619
620     /* See if another instance is alive. */
621     if (PID == NULL)
622         PID = concatpath(innconf->pathrun, _PATH_SERVERPID);
623     if ((F = fopen(PID, "r")) != NULL) {
624         if (fgets(buff, sizeof buff, F) != NULL
625          && ((pid = (pid_t) atol(buff)) > 0)
626          && (kill(pid, 0) > 0 || errno != ESRCH)) {
627             syslog(L_FATAL, "%s already_running pid %ld", LogName,
628             (long) pid);
629             exit(1);
630         }
631         fclose(F);
632     }
633
634     if (GetTimeInfo(&Now) < 0)
635         syslog(L_ERROR, "%s cant gettimeinfo %m", LogName);
636
637     /* Set up signal and error handlers. */
638     xmalloc_error_handler = xmalloc_abort;
639     xsignal(SIGHUP, catch_terminate);
640     xsignal(SIGTERM, catch_terminate);
641
642     /* Set up the various parts of the system.  Channel feeds start
643        processes so call PROCsetup before ICDsetup.  NNTP needs to know if
644        it's a slave, so call RCsetup before NCsetup. */
645     CHANsetup(i);
646     PROCsetup(10);
647     if (Mode == OMrunning)
648         InndHisOpen();
649     CCsetup();
650     LCsetup();
651     RCsetup(fd[0]);
652     for (i = 1; fd[i] != -1; i++)
653         RCsetup(fd[i]);
654     WIPsetup();
655     NCsetup();
656     ARTsetup();
657     ICDsetup(true);
658     if (innconf->timer)
659         TMRinit(TMR_MAX);
660
661     /* Initialize the storage subsystem. */
662     flag = true;
663     if (!SMsetup(SM_RDWR, &flag) || !SMsetup(SM_PREOPEN, &flag))
664         die("SERVER cant set up storage manager");
665     if (!SMinit())
666         die("SERVER cant initalize storage manager: %s", SMerrorstr);
667
668 #if     defined(_DEBUG_MALLOC_INC)
669     m.i = 1;
670     dbmallopt(MALLOC_CKCHAIN, &m);
671     dbmallopt(MALLOC_CKDATA, &m);
672 #endif  /* defined(_DEBUG_MALLOC_INC) */
673
674     /* Record our PID. */
675     pid = getpid();
676     if ((F = fopen(PID, "w")) == NULL) {
677         i = errno;
678         syslog(L_ERROR, "%s cant fopen %s %m", LogName, PID);
679         IOError(WHEN, i);
680     }
681     else {
682         if (fprintf(F, "%ld\n", (long)pid) == EOF || ferror(F)) {
683             i = errno;
684             syslog(L_ERROR, "%s cant fprintf %s %m", LogName, PID);
685             IOError(WHEN, i);
686         }
687         if (fclose(F) == EOF) {
688             i = errno;
689             syslog(L_ERROR, "%s cant fclose %s %m", LogName, PID);
690             IOError(WHEN, i);
691         }
692         if (chmod(PID, 0664) < 0) {
693             i = errno;
694             syslog(L_ERROR, "%s cant chmod %s %m", LogName, PID);
695             IOError(WHEN, i);
696         }
697     }
698
699 #if DO_TCL
700     TCLsetup();
701     if (!filter)
702         TCLfilter(false);
703 #endif /* DO_TCL */
704
705 #if DO_PERL
706     /* Load the Perl code */
707     path1 = concatpath(innconf->pathfilter, _PATH_PERL_STARTUP_INND);
708     path2 = concatpath(innconf->pathfilter, _PATH_PERL_FILTER_INND);
709     PERLsetup(path1, path2, "filter_art");
710     free(path1);
711     free(path2);
712     PLxsinit();
713     if (filter)
714         PerlFilter(true);
715 #endif /* DO_PERL */
716
717 #if DO_PYTHON
718     PYsetup();
719     if (!filter)
720         PYfilter(false);
721 #endif /* DO_PYTHON */
722  
723     /* And away we go... */
724     if (ShouldRenumber) {
725         syslog(LOG_NOTICE, "SERVER renumbering");
726         if (!ICDrenumberactive())
727             die("SERVER cant renumber");
728     }
729     syslog(LOG_NOTICE, "SERVER starting");
730     CHANreadloop();
731
732     /* CHANreadloop should never return. */
733     CleanupAndExit(1, "CHANreadloop returned");
734     return 1;
735 }