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