Clear more globals between messages
[exim.git] / src / src / log.c
CommitLineData
059ec3d9
PH
1/*************************************************
2* Exim - an Internet mail transport agent *
3*************************************************/
4
f9ba5e22 5/* Copyright (c) University of Cambridge 1995 - 2018 */
059ec3d9
PH
6/* See the file NOTICE for conditions of use and distribution. */
7
8/* Functions for writing log files. The code for maintaining datestamped
9log files was originally contributed by Tony Sheen. */
10
11
12#include "exim.h"
13
14#define LOG_NAME_SIZE 256
15#define MAX_SYSLOG_LEN 870
16
17#define LOG_MODE_FILE 1
18#define LOG_MODE_SYSLOG 2
19
921b12ca 20enum { lt_main, lt_reject, lt_panic, lt_debug };
059ec3d9 21
921b12ca 22static uschar *log_names[] = { US"main", US"reject", US"panic", US"debug" };
059ec3d9
PH
23
24
25
26/*************************************************
27* Local static variables *
28*************************************************/
29
30static uschar mainlog_name[LOG_NAME_SIZE];
31static uschar rejectlog_name[LOG_NAME_SIZE];
ed7f7860 32static uschar debuglog_name[LOG_NAME_SIZE];
059ec3d9
PH
33
34static uschar *mainlog_datestamp = NULL;
35static uschar *rejectlog_datestamp = NULL;
36
37static int mainlogfd = -1;
38static int rejectlogfd = -1;
39static ino_t mainlog_inode = 0;
40static ino_t rejectlog_inode = 0;
41
42static uschar *panic_save_buffer = NULL;
43static BOOL panic_recurseflag = FALSE;
44
45static BOOL syslog_open = FALSE;
46static BOOL path_inspected = FALSE;
47static int logging_mode = LOG_MODE_FILE;
48static uschar *file_path = US"";
49
2333e06f
HSHR
50static size_t pid_position[2];
51
059ec3d9 52
37f3dc43
JH
53/* These should be kept in-step with the private delivery error
54number definitions in macros.h */
55
56static const uschar * exim_errstrings[] = {
57 US"",
58 US"unknown error",
59 US"user slash",
60 US"exist race",
61 US"not regular",
62 US"not directory",
63 US"bad ugid",
64 US"bad mode",
65 US"inode changed",
66 US"lock failed",
67 US"bad address2",
68 US"forbid pipe",
69 US"forbid file",
70 US"forbid reply",
71 US"missing pipe",
72 US"missing file",
73 US"missing reply",
74 US"bad redirect",
75 US"smtp closed",
76 US"smtp format",
77 US"spool format",
78 US"not absolute",
79 US"Exim-imposed quota",
80 US"held",
81 US"Delivery filter process failure",
82 US"Delivery add/remove header failure",
83 US"Delivery write incomplete error",
84 US"Some expansion failed",
85 US"Failed to get gid",
86 US"Failed to get uid",
87 US"Unset or non-existent transport",
88 US"MBX length mismatch",
89 US"Lookup failed routing or in smtp tpt",
90 US"Can't match format in appendfile",
91 US"Creation outside home in appendfile",
92 US"Can't check a list; lookup defer",
93 US"DNS lookup defer",
94 US"Failed to start TLS session",
95 US"Mandatory TLS session not started",
96 US"Failed to chown a file",
97 US"Failed to create a pipe",
98 US"When verifying",
99 US"When required by client",
100 US"Used internally in smtp transport",
101 US"RCPT gave 4xx error",
102 US"MAIL gave 4xx error",
103 US"DATA gave 4xx error",
104 US"Negotiation failed for proxy configured host",
105 US"Authenticator 'other' failure",
106 US"target not supporting SMTPUTF8",
107 US"",
108
109 US"Not time for routing",
110 US"Not time for local delivery",
111 US"Not time for any remote host",
112 US"Local-only delivery",
113 US"Domain in queue_domains",
114 US"Transport concurrency limit",
115};
116
117
118/************************************************/
119const uschar *
120exim_errstr(int err)
121{
584ddd64 122return err < 0 ? exim_errstrings[-err] : CUS strerror(err);
37f3dc43 123}
059ec3d9
PH
124
125/*************************************************
126* Write to syslog *
127*************************************************/
128
129/* The given string is split into sections according to length, or at embedded
130newlines, and syslogged as a numbered sequence if it is overlong or if there is
9675b384
PH
131more than one line. However, if we are running in the test harness, do not do
132anything. (The test harness doesn't use syslog - for obvious reasons - but we
133can get here if there is a failure to open the panic log.)
059ec3d9
PH
134
135Arguments:
136 priority syslog priority
3203e7ba 137 s the string to be written
059ec3d9
PH
138
139Returns: nothing
140*/
141
142static void
3203e7ba 143write_syslog(int priority, const uschar *s)
059ec3d9
PH
144{
145int len, pass;
146int linecount = 0;
147
9675b384
PH
148if (running_in_test_harness) return;
149
2333e06f 150if (!syslog_pid && LOGGING(pid))
3203e7ba
JH
151 s = string_sprintf("%.*s%s", (int)pid_position[0], s, s + pid_position[1]);
152if (!syslog_timestamp)
153 {
154 len = log_timezone ? 26 : 20;
155 if (LOGGING(millisec)) len += 4;
156 s += len;
157 }
059ec3d9
PH
158
159len = Ustrlen(s);
160
161#ifndef NO_OPENLOG
162if (!syslog_open)
163 {
164 #ifdef SYSLOG_LOG_PID
165 openlog(CS syslog_processname, LOG_PID|LOG_CONS, syslog_facility);
166 #else
167 openlog(CS syslog_processname, LOG_CONS, syslog_facility);
168 #endif
169 syslog_open = TRUE;
170 }
171#endif
172
173/* First do a scan through the message in order to determine how many lines
174it is going to end up as. Then rescan to output it. */
175
176for (pass = 0; pass < 2; pass++)
177 {
178 int i;
179 int tlen;
3203e7ba 180 const uschar * ss = s;
059ec3d9
PH
181 for (i = 1, tlen = len; tlen > 0; i++)
182 {
183 int plen = tlen;
184 uschar *nlptr = Ustrchr(ss, '\n');
185 if (nlptr != NULL) plen = nlptr - ss;
186 #ifndef SYSLOG_LONG_LINES
187 if (plen > MAX_SYSLOG_LEN) plen = MAX_SYSLOG_LEN;
188 #endif
189 tlen -= plen;
190 if (ss[plen] == '\n') tlen--; /* chars left */
191
192 if (pass == 0) linecount++; else
193 {
194 if (linecount == 1)
195 syslog(priority, "%.*s", plen, ss);
196 else
197 syslog(priority, "[%d%c%d] %.*s", i,
198 (ss[plen] == '\n' && tlen != 0)? '\\' : '/',
199 linecount, plen, ss);
200 }
201 ss += plen;
202 if (*ss == '\n') ss++;
203 }
204 }
205}
206
207
208
209/*************************************************
210* Die tidily *
211*************************************************/
212
213/* This is called when Exim is dying as a result of something going wrong in
214the logging, or after a log call with LOG_PANIC_DIE set. Optionally write a
215message to debug_file or a stderr file, if they exist. Then, if in the middle
8f128379
PH
216of accepting a message, throw it away tidily by calling receive_bomb_out();
217this will attempt to send an SMTP response if appropriate. Passing NULL as the
218first argument stops it trying to run the NOTQUIT ACL (which might try further
219logging and thus cause problems). Otherwise, try to close down an outstanding
220SMTP call tidily.
059ec3d9
PH
221
222Arguments:
223 s1 Error message to write to debug_file and/or stderr and syslog
224 s2 Error message for any SMTP call that is in progress
225Returns: The function does not return
226*/
227
228static void
229die(uschar *s1, uschar *s2)
230{
571b2715 231if (s1)
059ec3d9
PH
232 {
233 write_syslog(LOG_CRIT, s1);
571b2715 234 if (debug_file) debug_printf("%s\n", s1);
059ec3d9
PH
235 if (log_stderr != NULL && log_stderr != debug_file)
236 fprintf(log_stderr, "%s\n", s1);
237 }
8f128379 238if (receive_call_bombout) receive_bomb_out(NULL, s2); /* does not return */
059ec3d9 239if (smtp_input) smtp_closedown(s2);
9bfb7e1b 240exim_exit(EXIT_FAILURE, NULL);
059ec3d9
PH
241}
242
243
244
245/*************************************************
246* Create a log file *
247*************************************************/
248
249/* This function is called to create and open a log file. It may be called in a
250subprocess when the original process is root.
251
252Arguments:
253 name the file name
254
255The file name has been build in a working buffer, so it is permissible to
256overwrite it temporarily if it is necessary to create the directory.
257
258Returns: a file descriptor, or < 0 on failure (errno set)
259*/
260
4840604e 261int
921b12ca 262log_create(uschar *name)
059ec3d9 263{
92b0827a
JH
264int fd = Uopen(name,
265#ifdef O_CLOEXEC
266 O_CLOEXEC |
267#endif
268 O_CREAT|O_APPEND|O_WRONLY, LOG_MODE);
059ec3d9
PH
269
270/* If creation failed, attempt to build a log directory in case that is the
271problem. */
272
273if (fd < 0 && errno == ENOENT)
274 {
275 BOOL created;
276 uschar *lastslash = Ustrrchr(name, '/');
277 *lastslash = 0;
278 created = directory_make(NULL, name, LOG_DIRECTORY_MODE, FALSE);
279 DEBUG(D_any) debug_printf("%s log directory %s\n",
571b2715 280 created ? "created" : "failed to create", name);
059ec3d9 281 *lastslash = '/';
92b0827a
JH
282 if (created) fd = Uopen(name,
283#ifdef O_CLOEXEC
284 O_CLOEXEC |
285#endif
286 O_CREAT|O_APPEND|O_WRONLY, LOG_MODE);
059ec3d9
PH
287 }
288
289return fd;
290}
291
292
293
921b12ca
TF
294/*************************************************
295* Create a log file as the exim user *
296*************************************************/
297
298/* This function is called when we are root to spawn an exim:exim subprocess
299in which we can create a log file. It must be signal-safe since it is called
300by the usr1_handler().
301
302Arguments:
303 name the file name
304
305Returns: a file descriptor, or < 0 on failure (errno set)
306*/
307
308int
309log_create_as_exim(uschar *name)
310{
311pid_t pid = fork();
312int status = 1;
313int fd = -1;
314
315/* In the subprocess, change uid/gid and do the creation. Return 0 from the
316subprocess on success. If we don't check for setuid failures, then the file
317can be created as root, so vulnerabilities which cause setuid to fail mean
318that the Exim user can use symlinks to cause a file to be opened/created as
319root. We always open for append, so can't nuke existing content but it would
320still be Rather Bad. */
321
322if (pid == 0)
323 {
324 if (setgid(exim_gid) < 0)
325 die(US"exim: setgid for log-file creation failed, aborting",
326 US"Unexpected log failure, please try later");
327 if (setuid(exim_uid) < 0)
328 die(US"exim: setuid for log-file creation failed, aborting",
329 US"Unexpected log failure, please try later");
330 _exit((log_create(name) < 0)? 1 : 0);
331 }
332
333/* If we created a subprocess, wait for it. If it succeeded, try the open. */
334
335while (pid > 0 && waitpid(pid, &status, 0) != pid);
92b0827a
JH
336if (status == 0) fd = Uopen(name,
337#ifdef O_CLOEXEC
338 O_CLOEXEC |
339#endif
340 O_APPEND|O_WRONLY, LOG_MODE);
921b12ca
TF
341
342/* If we failed to create a subprocess, we are in a bad way. We return
343with fd still < 0, and errno set, letting the caller handle the error. */
344
345return fd;
346}
347
348
349
059ec3d9
PH
350
351/*************************************************
352* Open a log file *
353*************************************************/
354
921b12ca
TF
355/* This function opens one of a number of logs, creating the log directory if
356it does not exist. This may be called recursively on failure, in order to open
357the panic log.
059ec3d9
PH
358
359The directory is in the static variable file_path. This is static so that it
360the work of sorting out the path is done just once per Exim process.
361
362Exim is normally configured to avoid running as root wherever possible, the log
363files must be owned by the non-privileged exim user. To ensure this, first try
364an open without O_CREAT - most of the time this will succeed. If it fails, try
365to create the file; if running as root, this must be done in a subprocess to
366avoid races.
367
368Arguments:
369 fd where to return the resulting file descriptor
921b12ca 370 type lt_main, lt_reject, lt_panic, or lt_debug
ed7f7860 371 tag optional tag to include in the name (only hooked up for debug)
059ec3d9
PH
372
373Returns: nothing
374*/
375
376static void
ed7f7860 377open_log(int *fd, int type, uschar *tag)
059ec3d9
PH
378{
379uid_t euid;
ed7f7860 380BOOL ok, ok2;
059ec3d9
PH
381uschar buffer[LOG_NAME_SIZE];
382
921b12ca
TF
383/* The names of the log files are controlled by file_path. The panic log is
384written to the same directory as the main and reject logs, but its name does
f1e5fef5
PP
385not have a datestamp. The use of datestamps is indicated by %D/%M in file_path.
386When opening the panic log, if %D or %M is present, we remove the datestamp
387from the generated name; if it is at the start, remove a following
388non-alphanumeric character as well; otherwise, remove a preceding
389non-alphanumeric character. This is definitely kludgy, but it sort of does what
390people want, I hope. */
059ec3d9 391
921b12ca
TF
392ok = string_format(buffer, sizeof(buffer), CS file_path, log_names[type]);
393
394/* Save the name of the mainlog for rollover processing. Without a datestamp,
395it gets statted to see if it has been cycled. With a datestamp, the datestamp
396will be compared. The static slot for saving it is the same size as buffer,
397and the text has been checked above to fit, so this use of strcpy() is OK. */
398
cd2e3fd0 399if (type == lt_main && string_datestamp_offset >= 0)
059ec3d9 400 {
921b12ca
TF
401 Ustrcpy(mainlog_name, buffer);
402 mainlog_datestamp = mainlog_name + string_datestamp_offset;
403 }
059ec3d9 404
921b12ca 405/* Ditto for the reject log */
059ec3d9 406
cd2e3fd0 407else if (type == lt_reject && string_datestamp_offset >= 0)
921b12ca
TF
408 {
409 Ustrcpy(rejectlog_name, buffer);
410 rejectlog_datestamp = rejectlog_name + string_datestamp_offset;
411 }
059ec3d9 412
921b12ca
TF
413/* and deal with the debug log (which keeps the datestamp, but does not
414update it) */
059ec3d9 415
921b12ca
TF
416else if (type == lt_debug)
417 {
418 Ustrcpy(debuglog_name, buffer);
419 if (tag)
059ec3d9 420 {
921b12ca
TF
421 /* this won't change the offset of the datestamp */
422 ok2 = string_format(buffer, sizeof(buffer), "%s%s",
423 debuglog_name, tag);
424 if (ok2)
425 Ustrcpy(debuglog_name, buffer);
059ec3d9 426 }
921b12ca 427 }
059ec3d9 428
921b12ca
TF
429/* Remove any datestamp if this is the panic log. This is rare, so there's no
430need to optimize getting the datestamp length. We remove one non-alphanumeric
431char afterwards if at the start, otherwise one before. */
ed7f7860 432
921b12ca
TF
433else if (string_datestamp_offset >= 0)
434 {
435 uschar *from = buffer + string_datestamp_offset;
436 uschar *to = from + string_datestamp_length;
437 if (from == buffer || from[-1] == '/')
ed7f7860 438 {
921b12ca 439 if (!isalnum(*to)) to++;
ed7f7860 440 }
921b12ca 441 else
059ec3d9 442 {
921b12ca
TF
443 if (!isalnum(from[-1])) from--;
444 }
059ec3d9 445
921b12ca 446 /* This strcpy is ok, because we know that to is a substring of from. */
059ec3d9 447
921b12ca 448 Ustrcpy(from, to);
059ec3d9
PH
449 }
450
451/* If the file name is too long, it is an unrecoverable disaster */
452
453if (!ok)
059ec3d9
PH
454 die(US"exim: log file path too long: aborting",
455 US"Logging failure; please try later");
059ec3d9
PH
456
457/* We now have the file name. Try to open an existing file. After a successful
458open, arrange for automatic closure on exec(), and then return. */
459
92b0827a
JH
460*fd = Uopen(buffer,
461#ifdef O_CLOEXEC
462 O_CLOEXEC |
463#endif
464 O_APPEND|O_WRONLY, LOG_MODE);
059ec3d9
PH
465
466if (*fd >= 0)
467 {
92b0827a 468#ifndef O_CLOEXEC
ff790e47 469 (void)fcntl(*fd, F_SETFD, fcntl(*fd, F_GETFD) | FD_CLOEXEC);
92b0827a 470#endif
059ec3d9
PH
471 return;
472 }
473
474/* Open was not successful: try creating the file. If this is a root process,
475we must do the creating in a subprocess set to exim:exim in order to ensure
476that the file is created with the right ownership. Otherwise, there can be a
901f42cb
PH
477race if another Exim process is trying to write to the log at the same time.
478The use of SIGUSR1 by the exiwhat utility can provoke a lot of simultaneous
479writing. */
059ec3d9
PH
480
481euid = geteuid();
482
483/* If we are already running as the Exim user (even if that user is root),
484we can go ahead and create in the current process. */
485
921b12ca 486if (euid == exim_uid) *fd = log_create(buffer);
059ec3d9
PH
487
488/* Otherwise, if we are root, do the creation in an exim:exim subprocess. If we
489are neither exim nor root, creation is not attempted. */
490
921b12ca 491else if (euid == root_uid) *fd = log_create_as_exim(buffer);
059ec3d9
PH
492
493/* If we now have an open file, set the close-on-exec flag and return. */
494
495if (*fd >= 0)
496 {
92b0827a 497#ifndef O_CLOEXEC
ff790e47 498 (void)fcntl(*fd, F_SETFD, fcntl(*fd, F_GETFD) | FD_CLOEXEC);
92b0827a 499#endif
059ec3d9
PH
500 return;
501 }
502
503/* Creation failed. There are some circumstances in which we get here when
504the effective uid is not root or exim, which is the problem. (For example, a
505non-setuid binary with log_arguments set, called in certain ways.) Rather than
506just bombing out, force the log to stderr and carry on if stderr is available.
507*/
508
509if (euid != root_uid && euid != exim_uid && log_stderr != NULL)
510 {
511 *fd = fileno(log_stderr);
512 return;
513 }
514
515/* Otherwise this is a disaster. This call is deliberately ONLY to the panic
516log. If possible, save a copy of the original line that was being logged. If we
517are recursing (can't open the panic log either), the pointer will already be
518set. */
519
40c90bca
JH
520if (!panic_save_buffer)
521 if ((panic_save_buffer = US malloc(LOG_BUFFER_SIZE)))
059ec3d9 522 memcpy(panic_save_buffer, log_buffer, LOG_BUFFER_SIZE);
059ec3d9
PH
523
524log_write(0, LOG_PANIC_DIE, "Cannot open %s log file \"%s\": %s: "
525 "euid=%d egid=%d", log_names[type], buffer, strerror(errno), euid, getegid());
526/* Never returns */
527}
528
529
b0d68adc
JH
530static void
531unlink_log(int type)
532{
533if (type == lt_debug) unlink(CS debuglog_name);
534}
535
536
059ec3d9
PH
537
538/*************************************************
539* Add configuration file info to log line *
540*************************************************/
541
542/* This is put in a function because it's needed twice (once for debugging,
543once for real).
544
545Arguments:
546 ptr pointer to the end of the line we are building
547 flags log flags
548
549Returns: updated pointer
550*/
551
552static uschar *
553log_config_info(uschar *ptr, int flags)
554{
555Ustrcpy(ptr, "Exim configuration error");
556ptr += 24;
557
558if ((flags & (LOG_CONFIG_FOR & ~LOG_CONFIG)) != 0)
559 {
560 Ustrcpy(ptr, " for ");
561 return ptr + 5;
562 }
563
564if ((flags & (LOG_CONFIG_IN & ~LOG_CONFIG)) != 0)
571b2715 565 ptr += sprintf(CS ptr, " in line %d of %s", config_lineno, config_filename);
059ec3d9
PH
566
567Ustrcpy(ptr, ":\n ");
568return ptr + 4;
569}
570
571
572/*************************************************
573* A write() operation failed *
574*************************************************/
575
576/* This function is called when write() fails on anything other than the panic
577log, which can happen if a disk gets full or a file gets too large or whatever.
578We try to save the relevant message in the panic_save buffer before crashing
579out.
580
23ecb73d
PP
581The potential invoker should probably not call us for EINTR -1 writes. But
582otherwise, short writes are bad as we don't do non-blocking writes to fds
583subject to flow control. (If we do, that's new and the logic of this should
584be reconsidered).
585
059ec3d9
PH
586Arguments:
587 name the name of the log being written
588 length the string length being written
589 rc the return value from write()
590
591Returns: does not return
592*/
593
594static void
595log_write_failed(uschar *name, int length, int rc)
596{
597int save_errno = errno;
598
40c90bca
JH
599if (!panic_save_buffer)
600 if ((panic_save_buffer = US malloc(LOG_BUFFER_SIZE)))
059ec3d9 601 memcpy(panic_save_buffer, log_buffer, LOG_BUFFER_SIZE);
059ec3d9
PH
602
603log_write(0, LOG_PANIC_DIE, "failed to write to %s: length=%d result=%d "
604 "errno=%d (%s)", name, length, rc, save_errno,
605 (save_errno == 0)? "write incomplete" : strerror(save_errno));
606/* Never returns */
607}
608
609
610
611/*************************************************
0599f9cf
PP
612* Write to an fd, retrying after signals *
613*************************************************/
614
615/* Basic write to fd for logs, handling EINTR.
616
617Arguments:
618 fd the fd to write to
619 buf the string to write
620 length the string length being written
621
622Returns:
623 length actually written, persisting an errno from write()
624*/
625ssize_t
17c76198 626write_to_fd_buf(int fd, const uschar *buf, size_t length)
0599f9cf
PP
627{
628ssize_t wrote;
629size_t total_written = 0;
17c76198 630const uschar *p = buf;
0599f9cf
PP
631size_t left = length;
632
633while (1)
634 {
635 wrote = write(fd, p, left);
636 if (wrote == (ssize_t)-1)
637 {
638 if (errno == EINTR) continue;
639 return wrote;
640 }
641 total_written += wrote;
642 if (wrote == left)
643 break;
644 else
645 {
646 p += wrote;
647 left -= wrote;
648 }
649 }
650return total_written;
651}
652
653
e4a6fb35
JH
654
655static void
656set_file_path(void)
657{
658int sep = ':'; /* Fixed separator - outside use */
659uschar *t;
660const uschar *tt = US LOG_FILE_PATH;
661while ((t = string_nextinlist(&tt, &sep, log_buffer, LOG_BUFFER_SIZE)))
662 {
663 if (Ustrcmp(t, "syslog") == 0 || t[0] == 0) continue;
664 file_path = string_copy(t);
665 break;
666 }
667}
668
669
9cd319d9
JH
670void
671mainlog_close(void)
672{
673if (mainlogfd < 0) return;
674(void)close(mainlogfd);
675mainlogfd = -1;
676mainlog_inode = 0;
677}
e4a6fb35 678
0599f9cf 679/*************************************************
059ec3d9
PH
680* Write message to log file *
681*************************************************/
682
683/* Exim can be configured to log to local files, or use syslog, or both. This
684is controlled by the setting of log_file_path. The following cases are
685recognized:
686
687 log_file_path = "" write files in the spool/log directory
688 log_file_path = "xxx" write files in the xxx directory
689 log_file_path = "syslog" write to syslog
690 log_file_path = "syslog : xxx" write to syslog and to files (any order)
691
059ec3d9
PH
692The message always gets '\n' added on the end of it, since more than one
693process may be writing to the log at once and we don't want intermingling to
694happen in the middle of lines. To be absolutely sure of this we write the data
695into a private buffer and then put it out in a single write() call.
696
697The flags determine which log(s) the message is written to, or for syslogging,
698which priority to use, and in the case of the panic log, whether the process
699should die afterwards.
700
701The variable really_exim is TRUE only when exim is running in privileged state
702(i.e. not with a changed configuration or with testing options such as -brw).
703If it is not, don't try to write to the log because permission will probably be
704denied.
705
706Avoid actually writing to the logs when exim is called with -bv or -bt to
4c04137d 707test an address, but take other actions, such as panicking.
059ec3d9
PH
708
709In Exim proper, the buffer for building the message is got at start-up, so that
710nothing gets done if it can't be got. However, some functions that are also
711used in utilities occasionally obey log_write calls in error situations, and it
712is simplest to put a single malloc() here rather than put one in each utility.
713Malloc is used directly because the store functions may call log_write().
714
715If a message_id exists, we include it after the timestamp.
716
717Arguments:
718 selector write to main log or LOG_INFO only if this value is zero, or if
6c6d6e48 719 its bit is set in log_selector[0]
059ec3d9
PH
720 flags each bit indicates some independent action:
721 LOG_SENDER add raw sender to the message
722 LOG_RECIPIENTS add raw recipients list to message
723 LOG_CONFIG add "Exim configuration error"
724 LOG_CONFIG_FOR add " for " instead of ":\n "
725 LOG_CONFIG_IN add " in line x[ of file y]"
726 LOG_MAIN write to main log or syslog LOG_INFO
727 LOG_REJECT write to reject log or syslog LOG_NOTICE
728 LOG_PANIC write to panic log or syslog LOG_ALERT
729 LOG_PANIC_DIE write to panic log or LOG_ALERT and then crash
059ec3d9
PH
730 format a printf() format
731 ... arguments for format
732
733Returns: nothing
734*/
735
736void
1ba28e2b 737log_write(unsigned int selector, int flags, const char *format, ...)
059ec3d9 738{
571b2715 739uschar * ptr;
0599f9cf 740int length;
059ec3d9 741int paniclogfd;
23ecb73d 742ssize_t written_len;
059ec3d9
PH
743va_list ap;
744
745/* If panic_recurseflag is set, we have failed to open the panic log. This is
746the ultimate disaster. First try to write the message to a debug file and/or
747stderr and also to syslog. If panic_save_buffer is not NULL, it contains the
748original log line that caused the problem. Afterwards, expire. */
749
750if (panic_recurseflag)
751 {
752 uschar *extra = (panic_save_buffer == NULL)? US"" : panic_save_buffer;
753 if (debug_file != NULL) debug_printf("%s%s", extra, log_buffer);
754 if (log_stderr != NULL && log_stderr != debug_file)
755 fprintf(log_stderr, "%s%s", extra, log_buffer);
756 if (*extra != 0) write_syslog(LOG_CRIT, extra);
757 write_syslog(LOG_CRIT, log_buffer);
758 die(US"exim: could not open panic log - aborting: see message(s) above",
759 US"Unexpected log failure, please try later");
760 }
761
762/* Ensure we have a buffer (see comment above); this should never be obeyed
763when running Exim proper, only when running utilities. */
764
40c90bca
JH
765if (!log_buffer)
766 if (!(log_buffer = US malloc(LOG_BUFFER_SIZE)))
059ec3d9
PH
767 {
768 fprintf(stderr, "exim: failed to get store for log buffer\n");
9bfb7e1b 769 exim_exit(EXIT_FAILURE, NULL);
059ec3d9 770 }
059ec3d9
PH
771
772/* If we haven't already done so, inspect the setting of log_file_path to
773determine whether to log to files and/or to syslog. Bits in logging_mode
774control this, and for file logging, the path must end up in file_path. This
775variable must be in permanent store because it may be required again later in
776the process. */
777
778if (!path_inspected)
779 {
780 BOOL multiple = FALSE;
781 int old_pool = store_pool;
782
783 store_pool = POOL_PERM;
784
785 /* If nothing has been set, don't waste effort... the default values for the
786 statics are file_path="" and logging_mode = LOG_MODE_FILE. */
787
e4a6fb35 788 if (*log_file_path)
059ec3d9
PH
789 {
790 int sep = ':'; /* Fixed separator - outside use */
791 uschar *s;
55414b25 792 const uschar *ss = log_file_path;
059ec3d9 793 logging_mode = 0;
55414b25 794 while ((s = string_nextinlist(&ss, &sep, log_buffer, LOG_BUFFER_SIZE)))
059ec3d9
PH
795 {
796 if (Ustrcmp(s, "syslog") == 0)
797 logging_mode |= LOG_MODE_SYSLOG;
798 else if ((logging_mode & LOG_MODE_FILE) != 0) multiple = TRUE;
799 else
800 {
801 logging_mode |= LOG_MODE_FILE;
802
803 /* If a non-empty path is given, use it */
804
e4a6fb35 805 if (*s)
059ec3d9 806 file_path = string_copy(s);
059ec3d9
PH
807
808 /* If the path is empty, we want to use the first non-empty, non-
809 syslog item in LOG_FILE_PATH, if there is one, since the value of
810 log_file_path may have been set at runtime. If there is no such item,
811 use the ultimate default in the spool directory. */
812
813 else
e4a6fb35 814 set_file_path(); /* Empty item in log_file_path */
059ec3d9
PH
815 } /* First non-syslog item in log_file_path */
816 } /* Scan of log_file_path */
817 }
818
819 /* If no modes have been selected, it is a major disaster */
820
821 if (logging_mode == 0)
822 die(US"Neither syslog nor file logging set in log_file_path",
823 US"Unexpected logging failure");
824
825 /* Set up the ultimate default if necessary. Then revert to the old store
826 pool, and record that we've sorted out the path. */
827
828 if ((logging_mode & LOG_MODE_FILE) != 0 && file_path[0] == 0)
829 file_path = string_sprintf("%s/log/%%slog", spool_directory);
830 store_pool = old_pool;
831 path_inspected = TRUE;
832
833 /* If more than one file path was given, log a complaint. This recursive call
834 should work since we have now set up the routing. */
835
836 if (multiple)
059ec3d9
PH
837 log_write(0, LOG_MAIN|LOG_PANIC,
838 "More than one path given in log_file_path: using %s", file_path);
059ec3d9
PH
839 }
840
841/* If debugging, show all log entries, but don't show headers. Do it all
842in one go so that it doesn't get split when multi-processing. */
843
844DEBUG(D_any|D_v)
845 {
846 int i;
847 ptr = log_buffer;
848
849 Ustrcpy(ptr, "LOG:");
850 ptr += 4;
851
6c6d6e48 852 /* Show the selector that was passed into the call. */
059ec3d9
PH
853
854 for (i = 0; i < log_options_count; i++)
855 {
ac881e27
TF
856 unsigned int bitnum = log_options[i].bit;
857 if (bitnum < BITWORDSIZE && selector == BIT(bitnum))
059ec3d9
PH
858 {
859 *ptr++ = ' ';
860 Ustrcpy(ptr, log_options[i].name);
861 while (*ptr) ptr++;
862 }
863 }
864
5976eb99 865 ptr += sprintf(CS ptr, "%s%s%s%s\n ",
059ec3d9
PH
866 ((flags & LOG_MAIN) != 0)? " MAIN" : "",
867 ((flags & LOG_PANIC) != 0)? " PANIC" : "",
868 ((flags & LOG_PANIC_DIE) == LOG_PANIC_DIE)? " DIE" : "",
059ec3d9
PH
869 ((flags & LOG_REJECT) != 0)? " REJECT" : "");
870
059ec3d9
PH
871 if ((flags & LOG_CONFIG) != 0) ptr = log_config_info(ptr, flags);
872
873 va_start(ap, format);
874 if (!string_vformat(ptr, LOG_BUFFER_SIZE - (ptr-log_buffer)-1, format, ap))
875 Ustrcpy(ptr, "**** log string overflowed log buffer ****");
876 va_end(ap);
877
878 while(*ptr) ptr++;
879 Ustrcat(ptr, "\n");
880 debug_printf("%s", log_buffer);
881 }
882
883/* If no log file is specified, we are in a mess. */
884
921b12ca 885if ((flags & (LOG_MAIN|LOG_PANIC|LOG_REJECT)) == 0)
059ec3d9
PH
886 log_write(0, LOG_MAIN|LOG_PANIC_DIE, "log_write called with no log "
887 "flags set");
888
889/* There are some weird circumstances in which logging is disabled. */
890
891if (disable_logging)
892 {
893 DEBUG(D_any) debug_printf("log writing disabled\n");
894 return;
895 }
896
a7d7aa58
PH
897/* Handle disabled reject log */
898
899if (!write_rejectlog) flags &= ~LOG_REJECT;
900
921b12ca
TF
901/* Create the main message in the log buffer. Do not include the message id
902when called by a utility. */
059ec3d9
PH
903
904ptr = log_buffer;
571b2715 905ptr += sprintf(CS ptr, "%s ", tod_stamp(tod_log));
f3f065bb 906
6c6d6e48 907if (LOGGING(pid))
f3f065bb 908 {
dd7b74e9 909 if (!syslog_pid) pid_position[0] = ptr - log_buffer; /* remember begin … */
571b2715 910 ptr += sprintf(CS ptr, "[%d] ", (int)getpid());
dd7b74e9 911 if (!syslog_pid) pid_position[1] = ptr - log_buffer; /* … and end+1 of the PID */
f3f065bb
PH
912 }
913
921b12ca 914if (really_exim && message_id[0] != 0)
571b2715 915 ptr += sprintf(CS ptr, "%s ", message_id);
059ec3d9 916
059ec3d9
PH
917if ((flags & LOG_CONFIG) != 0) ptr = log_config_info(ptr, flags);
918
919va_start(ap, format);
920if (!string_vformat(ptr, LOG_BUFFER_SIZE - (ptr-log_buffer)-1, format, ap))
921 Ustrcpy(ptr, "**** log string overflowed log buffer ****\n");
922while(*ptr) ptr++;
923va_end(ap);
924
925/* Add the raw, unrewritten, sender to the message if required. This is done
926this way because it kind of fits with LOG_RECIPIENTS. */
927
928if ((flags & LOG_SENDER) != 0 &&
ccfdb010 929 ptr < log_buffer + LOG_BUFFER_SIZE - 10 - Ustrlen(raw_sender))
571b2715 930 ptr += sprintf(CS ptr, " from <%s>", raw_sender);
059ec3d9
PH
931
932/* Add list of recipients to the message if required; the raw list,
933before rewriting, was saved in raw_recipients. There may be none, if an ACL
934discarded them all. */
935
936if ((flags & LOG_RECIPIENTS) != 0 && ptr < log_buffer + LOG_BUFFER_SIZE - 6 &&
937 raw_recipients_count > 0)
938 {
939 int i;
571b2715 940 ptr += sprintf(CS ptr, " for");
059ec3d9
PH
941 for (i = 0; i < raw_recipients_count; i++)
942 {
571b2715 943 uschar * s = raw_recipients[i];
059ec3d9 944 if (log_buffer + LOG_BUFFER_SIZE - ptr < Ustrlen(s) + 3) break;
571b2715 945 ptr += sprintf(CS ptr, " %s", s);
059ec3d9
PH
946 }
947 }
948
571b2715 949ptr += sprintf(CS ptr, "\n");
059ec3d9
PH
950length = ptr - log_buffer;
951
952/* Handle loggable errors when running a utility, or when address testing.
953Write to log_stderr unless debugging (when it will already have been written),
954or unless there is no log_stderr (expn called from daemon, for example). */
955
956if (!really_exim || log_testing_mode)
957 {
958 if (debug_selector == 0 && log_stderr != NULL &&
6c6d6e48 959 (selector == 0 || (selector & log_selector[0]) != 0))
059ec3d9
PH
960 {
961 if (host_checking)
962 fprintf(log_stderr, "LOG: %s", CS(log_buffer + 20)); /* no timestamp */
963 else
964 fprintf(log_stderr, "%s", CS log_buffer);
965 }
9bfb7e1b 966 if ((flags & LOG_PANIC_DIE) == LOG_PANIC_DIE) exim_exit(EXIT_FAILURE, US"");
059ec3d9
PH
967 return;
968 }
969
970/* Handle the main log. We know that either syslog or file logging (or both) is
971set up. A real file gets left open during reception or delivery once it has
972been opened, but we don't want to keep on writing to it for too long after it
973has been renamed. Therefore, do a stat() and see if the inode has changed, and
974if so, re-open. */
975
3cc3f762
JH
976if ( flags & LOG_MAIN
977 && (!selector || selector & log_selector[0]))
059ec3d9 978 {
3cc3f762
JH
979 if ( logging_mode & LOG_MODE_SYSLOG
980 && (syslog_duplication || !(flags & (LOG_REJECT|LOG_PANIC))))
059ec3d9
PH
981 write_syslog(LOG_INFO, log_buffer);
982
3cc3f762 983 if (logging_mode & LOG_MODE_FILE)
059ec3d9
PH
984 {
985 struct stat statbuf;
986
987 /* Check for a change to the mainlog file name when datestamping is in
988 operation. This happens at midnight, at which point we want to roll over
989 the file. Closing it has the desired effect. */
990
cd2e3fd0 991 if (mainlog_datestamp)
059ec3d9 992 {
f1e5fef5 993 uschar *nowstamp = tod_stamp(string_datestamp_type);
059ec3d9
PH
994 if (Ustrncmp (mainlog_datestamp, nowstamp, Ustrlen(nowstamp)) != 0)
995 {
f1e894f3 996 (void)close(mainlogfd); /* Close the file */
059ec3d9
PH
997 mainlogfd = -1; /* Clear the file descriptor */
998 mainlog_inode = 0; /* Unset the inode */
999 mainlog_datestamp = NULL; /* Clear the datestamp */
1000 }
1001 }
1002
1003 /* Otherwise, we want to check whether the file has been renamed by a
1004 cycling script. This could be "if else", but for safety's sake, leave it as
1005 "if" so that renaming the log starts a new file even when datestamping is
1006 happening. */
1007
1008 if (mainlogfd >= 0)
059ec3d9 1009 if (Ustat(mainlog_name, &statbuf) < 0 || statbuf.st_ino != mainlog_inode)
9cd319d9 1010 mainlog_close();
059ec3d9
PH
1011
1012 /* If the log is closed, open it. Then write the line. */
1013
1014 if (mainlogfd < 0)
1015 {
ed7f7860 1016 open_log(&mainlogfd, lt_main, NULL); /* No return on error */
059ec3d9
PH
1017 if (fstat(mainlogfd, &statbuf) >= 0) mainlog_inode = statbuf.st_ino;
1018 }
1019
1020 /* Failing to write to the log is disastrous */
1021
0599f9cf 1022 written_len = write_to_fd_buf(mainlogfd, log_buffer, length);
23ecb73d 1023 if (written_len != length)
059ec3d9 1024 {
23ecb73d 1025 log_write_failed(US"main log", length, written_len);
059ec3d9
PH
1026 /* That function does not return */
1027 }
1028 }
1029 }
1030
a7d7aa58
PH
1031/* Handle the log for rejected messages. This can be globally disabled, in
1032which case the flags are altered above. If there are any header lines (i.e. if
1033the rejection is happening after the DATA phase), log the recipients and the
1034headers. */
059ec3d9 1035
a7d7aa58 1036if ((flags & LOG_REJECT) != 0)
059ec3d9
PH
1037 {
1038 header_line *h;
1039
6c6d6e48 1040 if (header_list != NULL && LOGGING(rejected_header))
059ec3d9
PH
1041 {
1042 if (recipients_count > 0)
1043 {
1044 int i;
1045
1046 /* List the sender */
1047
1048 string_format(ptr, LOG_BUFFER_SIZE - (ptr-log_buffer),
1049 "Envelope-from: <%s>\n", sender_address);
1050 while (*ptr) ptr++;
1051
1052 /* List up to 5 recipients */
1053
1054 string_format(ptr, LOG_BUFFER_SIZE - (ptr-log_buffer),
1055 "Envelope-to: <%s>\n", recipients_list[0].address);
1056 while (*ptr) ptr++;
1057
1058 for (i = 1; i < recipients_count && i < 5; i++)
1059 {
1060 string_format(ptr, LOG_BUFFER_SIZE - (ptr-log_buffer), " <%s>\n",
1061 recipients_list[i].address);
1062 while (*ptr) ptr++;
1063 }
1064
1065 if (i < recipients_count)
1066 {
1067 (void)string_format(ptr, LOG_BUFFER_SIZE - (ptr-log_buffer),
1068 " ...\n");
1069 while (*ptr) ptr++;
1070 }
1071 }
1072
1073 /* A header with a NULL text is an unfilled in Received: header */
1074
571b2715 1075 for (h = header_list; h; h = h->next) if (h->text)
059ec3d9 1076 {
571b2715 1077 BOOL fitted = string_format(ptr, LOG_BUFFER_SIZE - (ptr-log_buffer),
059ec3d9
PH
1078 "%c %s", h->type, h->text);
1079 while(*ptr) ptr++;
1080 if (!fitted) /* Buffer is full; truncate */
1081 {
1082 ptr -= 100; /* For message and separator */
1083 if (ptr[-1] == '\n') ptr--;
1084 Ustrcpy(ptr, "\n*** truncated ***\n");
1085 while (*ptr) ptr++;
1086 break;
1087 }
1088 }
1089
1090 length = ptr - log_buffer;
1091 }
1092
1093 /* Write to syslog or to a log file */
1094
1095 if ((logging_mode & LOG_MODE_SYSLOG) != 0 &&
1096 (syslog_duplication || (flags & LOG_PANIC) == 0))
1097 write_syslog(LOG_NOTICE, log_buffer);
1098
1099 /* Check for a change to the rejectlog file name when datestamping is in
1100 operation. This happens at midnight, at which point we want to roll over
1101 the file. Closing it has the desired effect. */
1102
1103 if ((logging_mode & LOG_MODE_FILE) != 0)
1104 {
1105 struct stat statbuf;
1106
571b2715 1107 if (rejectlog_datestamp)
059ec3d9 1108 {
f1e5fef5 1109 uschar *nowstamp = tod_stamp(string_datestamp_type);
059ec3d9
PH
1110 if (Ustrncmp (rejectlog_datestamp, nowstamp, Ustrlen(nowstamp)) != 0)
1111 {
f1e894f3 1112 (void)close(rejectlogfd); /* Close the file */
059ec3d9
PH
1113 rejectlogfd = -1; /* Clear the file descriptor */
1114 rejectlog_inode = 0; /* Unset the inode */
1115 rejectlog_datestamp = NULL; /* Clear the datestamp */
1116 }
1117 }
1118
1119 /* Otherwise, we want to check whether the file has been renamed by a
1120 cycling script. This could be "if else", but for safety's sake, leave it as
1121 "if" so that renaming the log starts a new file even when datestamping is
1122 happening. */
1123
1124 if (rejectlogfd >= 0)
1125 {
1126 if (Ustat(rejectlog_name, &statbuf) < 0 ||
1127 statbuf.st_ino != rejectlog_inode)
1128 {
f1e894f3 1129 (void)close(rejectlogfd);
059ec3d9
PH
1130 rejectlogfd = -1;
1131 rejectlog_inode = 0;
1132 }
1133 }
1134
1135 /* Open the file if necessary, and write the data */
1136
1137 if (rejectlogfd < 0)
1138 {
ed7f7860 1139 open_log(&rejectlogfd, lt_reject, NULL); /* No return on error */
059ec3d9
PH
1140 if (fstat(rejectlogfd, &statbuf) >= 0) rejectlog_inode = statbuf.st_ino;
1141 }
1142
0599f9cf
PP
1143 written_len = write_to_fd_buf(rejectlogfd, log_buffer, length);
1144 if (written_len != length)
059ec3d9 1145 {
0599f9cf 1146 log_write_failed(US"reject log", length, written_len);
059ec3d9
PH
1147 /* That function does not return */
1148 }
1149 }
1150 }
1151
1152
059ec3d9
PH
1153/* Handle the panic log, which is not kept open like the others. If it fails to
1154open, there will be a recursive call to log_write(). We detect this above and
1155attempt to write to the system log as a last-ditch try at telling somebody. In
47c7a64a 1156all cases except mua_wrapper, try to write to log_stderr. */
059ec3d9
PH
1157
1158if ((flags & LOG_PANIC) != 0)
1159 {
47c7a64a 1160 if (log_stderr != NULL && log_stderr != debug_file && !mua_wrapper)
059ec3d9
PH
1161 fprintf(log_stderr, "%s", CS log_buffer);
1162
1163 if ((logging_mode & LOG_MODE_SYSLOG) != 0)
059ec3d9 1164 write_syslog(LOG_ALERT, log_buffer);
059ec3d9
PH
1165
1166 /* If this panic logging was caused by a failure to open the main log,
1167 the original log line is in panic_save_buffer. Make an attempt to write it. */
1168
1169 if ((logging_mode & LOG_MODE_FILE) != 0)
1170 {
1171 panic_recurseflag = TRUE;
ed7f7860 1172 open_log(&paniclogfd, lt_panic, NULL); /* Won't return on failure */
059ec3d9
PH
1173 panic_recurseflag = FALSE;
1174
1175 if (panic_save_buffer != NULL)
1ac6b2e7
JH
1176 {
1177 int i = write(paniclogfd, panic_save_buffer, Ustrlen(panic_save_buffer));
1178 i = i; /* compiler quietening */
1179 }
059ec3d9 1180
0599f9cf
PP
1181 written_len = write_to_fd_buf(paniclogfd, log_buffer, length);
1182 if (written_len != length)
059ec3d9
PH
1183 {
1184 int save_errno = errno;
1185 write_syslog(LOG_CRIT, log_buffer);
1186 sprintf(CS log_buffer, "write failed on panic log: length=%d result=%d "
0599f9cf 1187 "errno=%d (%s)", length, (int)written_len, save_errno, strerror(save_errno));
059ec3d9
PH
1188 write_syslog(LOG_CRIT, log_buffer);
1189 flags |= LOG_PANIC_DIE;
1190 }
1191
f1e894f3 1192 (void)close(paniclogfd);
059ec3d9
PH
1193 }
1194
1195 /* Give up if the DIE flag is set */
1196
1197 if ((flags & LOG_PANIC_DIE) != LOG_PANIC)
1198 die(NULL, US"Unexpected failure, please try later");
1199 }
1200}
1201
1202
1203
1204/*************************************************
1205* Close any open log files *
1206*************************************************/
1207
1208void
1209log_close_all(void)
1210{
1211if (mainlogfd >= 0)
f1e894f3 1212 { (void)close(mainlogfd); mainlogfd = -1; }
059ec3d9 1213if (rejectlogfd >= 0)
f1e894f3 1214 { (void)close(rejectlogfd); rejectlogfd = -1; }
059ec3d9
PH
1215closelog();
1216syslog_open = FALSE;
1217}
1218
ed7f7860
PP
1219
1220
1221/*************************************************
6c6d6e48
TF
1222* Multi-bit set or clear *
1223*************************************************/
1224
1225/* These functions take a list of bit indexes (terminated by -1) and
1226clear or set the corresponding bits in the selector.
1227
1228Arguments:
1229 selector address of the bit string
1230 selsize number of words in the bit string
1231 bits list of bits to set
1232*/
1233
1234void
1235bits_clear(unsigned int *selector, size_t selsize, int *bits)
1236{
1237for(; *bits != -1; ++bits)
1238 BIT_CLEAR(selector, selsize, *bits);
1239}
1240
1241void
1242bits_set(unsigned int *selector, size_t selsize, int *bits)
1243{
1244for(; *bits != -1; ++bits)
1245 BIT_SET(selector, selsize, *bits);
1246}
1247
1248
1249
1250/*************************************************
ed7f7860
PP
1251* Decode bit settings for log/debug *
1252*************************************************/
1253
1254/* This function decodes a string containing bit settings in the form of +name
1255and/or -name sequences, and sets/unsets bits in a bit string accordingly. It
1256also recognizes a numeric setting of the form =<number>, but this is not
1257intended for user use. It's an easy way for Exim to pass the debug settings
1258when it is re-exec'ed.
1259
6c6d6e48
TF
1260The option table is a list of names and bit indexes. The index -1
1261means "set all bits, except for those listed in notall". The notall
1262list is terminated by -1.
ed7f7860
PP
1263
1264The action taken for bad values varies depending upon why we're here.
1265For log messages, or if the debugging is triggered from config, then we write
1266to the log on the way out. For debug setting triggered from the command-line,
1267we treat it as an unknown option: error message to stderr and die.
1268
1269Arguments:
6c6d6e48
TF
1270 selector address of the bit string
1271 selsize number of words in the bit string
1272 notall list of bits to exclude from "all"
ed7f7860
PP
1273 string the configured string
1274 options the table of option names
1275 count size of table
1276 which "log" or "debug"
1277 flags DEBUG_FROM_CONFIG
1278
1279Returns: nothing on success - bomb out on failure
1280*/
1281
1282void
6c6d6e48
TF
1283decode_bits(unsigned int *selector, size_t selsize, int *notall,
1284 uschar *string, bit_table *options, int count, uschar *which, int flags)
ed7f7860
PP
1285{
1286uschar *errmsg;
1287if (string == NULL) return;
1288
1289if (*string == '=')
1290 {
1291 char *end; /* Not uschar */
6c6d6e48
TF
1292 memset(selector, 0, sizeof(*selector)*selsize);
1293 *selector = strtoul(CS string+1, &end, 0);
ed7f7860
PP
1294 if (*end == 0) return;
1295 errmsg = string_sprintf("malformed numeric %s_selector setting: %s", which,
1296 string);
1297 goto ERROR_RETURN;
1298 }
1299
1300/* Handle symbolic setting */
1301
1302else for(;;)
1303 {
1304 BOOL adding;
1305 uschar *s;
1306 int len;
1307 bit_table *start, *end;
1308
1309 while (isspace(*string)) string++;
1310 if (*string == 0) return;
1311
1312 if (*string != '+' && *string != '-')
1313 {
1314 errmsg = string_sprintf("malformed %s_selector setting: "
1315 "+ or - expected but found \"%s\"", which, string);
1316 goto ERROR_RETURN;
1317 }
1318
1319 adding = *string++ == '+';
1320 s = string;
1321 while (isalnum(*string) || *string == '_') string++;
1322 len = string - s;
1323
1324 start = options;
1325 end = options + count;
1326
1327 while (start < end)
1328 {
1329 bit_table *middle = start + (end - start)/2;
1330 int c = Ustrncmp(s, middle->name, len);
1331 if (c == 0)
1332 {
1333 if (middle->name[len] != 0) c = -1; else
1334 {
1335 unsigned int bit = middle->bit;
ed7f7860 1336
6c6d6e48
TF
1337 if (bit == -1)
1338 {
1339 if (adding)
1340 {
1341 memset(selector, -1, sizeof(*selector)*selsize);
1342 bits_clear(selector, selsize, notall);
1343 }
1344 else
1345 memset(selector, 0, sizeof(*selector)*selsize);
1346 }
1347 else if (adding)
1348 BIT_SET(selector, selsize, bit);
1349 else
1350 BIT_CLEAR(selector, selsize, bit);
1351
ed7f7860
PP
1352 break; /* Out of loop to match selector name */
1353 }
1354 }
1355 if (c < 0) end = middle; else start = middle + 1;
1356 } /* Loop to match selector name */
1357
1358 if (start >= end)
1359 {
1360 errmsg = string_sprintf("unknown %s_selector setting: %c%.*s", which,
1361 adding? '+' : '-', len, s);
1362 goto ERROR_RETURN;
1363 }
1364 } /* Loop for selector names */
1365
1366/* Handle disasters */
1367
1368ERROR_RETURN:
1369if (Ustrcmp(which, "debug") == 0)
1370 {
1371 if (flags & DEBUG_FROM_CONFIG)
1372 {
1373 log_write(0, LOG_CONFIG|LOG_PANIC, "%s", errmsg);
1374 return;
1375 }
1376 fprintf(stderr, "exim: %s\n", errmsg);
1377 exit(EXIT_FAILURE);
1378 }
1379else log_write(0, LOG_CONFIG|LOG_PANIC_DIE, "%s", errmsg);
1380}
1381
1382
1383
1384/*************************************************
1385* Activate a debug logfile (late) *
1386*************************************************/
1387
1388/* Normally, debugging is activated from the command-line; it may be useful
1389within the configuration to activate debugging later, based on certain
1390conditions. If debugging is already in progress, we return early, no action
1391taken (besides debug-logging that we wanted debug-logging).
1392
1393Failures in options are not fatal but will result in paniclog entries for the
1394misconfiguration.
1395
1396The first use of this is in ACL logic, "control = debug/tag=foo/opts=+expand"
1397which can be combined with conditions, etc, to activate extra logging only
9ee44efb 1398for certain sources. The second use is inetd wait mode debug preservation. */
ed7f7860
PP
1399
1400void
1401debug_logging_activate(uschar *tag_name, uschar *opts)
1402{
1403int fd = -1;
1404
1405if (debug_file)
1406 {
1407 debug_printf("DEBUGGING ACTIVATED FROM WITHIN CONFIG.\n"
b0d68adc 1408 "DEBUG: Tag=\"%s\" opts=\"%s\"\n", tag_name, opts ? opts : US"");
ed7f7860
PP
1409 return;
1410 }
1411
1412if (tag_name != NULL && (Ustrchr(tag_name, '/') != NULL))
1413 {
1414 log_write(0, LOG_MAIN|LOG_PANIC, "debug tag may not contain a '/' in: %s",
1415 tag_name);
1416 return;
1417 }
1418
1419debug_selector = D_default;
1420if (opts)
6c6d6e48 1421 decode_bits(&debug_selector, 1, debug_notall, opts,
ed7f7860 1422 debug_options, debug_options_count, US"debug", DEBUG_FROM_CONFIG);
ed7f7860 1423
e4a6fb35
JH
1424/* When activating from a transport process we may never have logged at all
1425resulting in certain setup not having been done. Hack this for now so we
1426do not segfault; note that nondefault log locations will not work */
1427
1428if (!*file_path) set_file_path();
1429
ed7f7860
PP
1430open_log(&fd, lt_debug, tag_name);
1431
1432if (fd != -1)
1433 debug_file = fdopen(fd, "w");
1434else
1435 log_write(0, LOG_MAIN|LOG_PANIC, "unable to open debug log");
1436}
1437
1438
b0d68adc
JH
1439void
1440debug_logging_stop(void)
1441{
1442if (!debug_file || !debuglog_name[0]) return;
1443
1444debug_selector = 0;
1445fclose(debug_file);
1446debug_file = NULL;
1447unlink_log(lt_debug);
1448}
1449
1450
059ec3d9 1451/* End of log.c */