Merge branch '4.next'
[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 {
30f962e0 164# ifdef SYSLOG_LOG_PID
059ec3d9 165 openlog(CS syslog_processname, LOG_PID|LOG_CONS, syslog_facility);
30f962e0 166# else
059ec3d9 167 openlog(CS syslog_processname, LOG_CONS, syslog_facility);
30f962e0 168# endif
059ec3d9
PH
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;
30f962e0 186#ifndef SYSLOG_LONG_LINES
059ec3d9 187 if (plen > MAX_SYSLOG_LEN) plen = MAX_SYSLOG_LEN;
30f962e0 188#endif
059ec3d9
PH
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,
30f962e0 198 ss[plen] == '\n' && tlen != 0 ? '\\' : '/',
059ec3d9
PH
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);
30f962e0 235 if (log_stderr && log_stderr != debug_file)
059ec3d9
PH
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 {
30f962e0
JH
435 uschar * from = buffer + string_datestamp_offset;
436 uschar * to = from + string_datestamp_length;
437
921b12ca 438 if (from == buffer || from[-1] == '/')
ed7f7860 439 {
921b12ca 440 if (!isalnum(*to)) to++;
ed7f7860 441 }
921b12ca 442 else
921b12ca 443 if (!isalnum(from[-1])) from--;
059ec3d9 444
30f962e0
JH
445 /* This copy is ok, because we know that to is a substring of from. But
446 due to overlap we must use memmove() not Ustrcpy(). */
447 memmove(from, to, Ustrlen(to)+1);
059ec3d9
PH
448 }
449
450/* If the file name is too long, it is an unrecoverable disaster */
451
452if (!ok)
059ec3d9
PH
453 die(US"exim: log file path too long: aborting",
454 US"Logging failure; please try later");
059ec3d9
PH
455
456/* We now have the file name. Try to open an existing file. After a successful
457open, arrange for automatic closure on exec(), and then return. */
458
92b0827a
JH
459*fd = Uopen(buffer,
460#ifdef O_CLOEXEC
461 O_CLOEXEC |
462#endif
463 O_APPEND|O_WRONLY, LOG_MODE);
059ec3d9
PH
464
465if (*fd >= 0)
466 {
92b0827a 467#ifndef O_CLOEXEC
ff790e47 468 (void)fcntl(*fd, F_SETFD, fcntl(*fd, F_GETFD) | FD_CLOEXEC);
92b0827a 469#endif
059ec3d9
PH
470 return;
471 }
472
473/* Open was not successful: try creating the file. If this is a root process,
474we must do the creating in a subprocess set to exim:exim in order to ensure
475that the file is created with the right ownership. Otherwise, there can be a
901f42cb
PH
476race if another Exim process is trying to write to the log at the same time.
477The use of SIGUSR1 by the exiwhat utility can provoke a lot of simultaneous
478writing. */
059ec3d9
PH
479
480euid = geteuid();
481
482/* If we are already running as the Exim user (even if that user is root),
483we can go ahead and create in the current process. */
484
921b12ca 485if (euid == exim_uid) *fd = log_create(buffer);
059ec3d9
PH
486
487/* Otherwise, if we are root, do the creation in an exim:exim subprocess. If we
488are neither exim nor root, creation is not attempted. */
489
921b12ca 490else if (euid == root_uid) *fd = log_create_as_exim(buffer);
059ec3d9
PH
491
492/* If we now have an open file, set the close-on-exec flag and return. */
493
494if (*fd >= 0)
495 {
92b0827a 496#ifndef O_CLOEXEC
ff790e47 497 (void)fcntl(*fd, F_SETFD, fcntl(*fd, F_GETFD) | FD_CLOEXEC);
92b0827a 498#endif
059ec3d9
PH
499 return;
500 }
501
502/* Creation failed. There are some circumstances in which we get here when
503the effective uid is not root or exim, which is the problem. (For example, a
504non-setuid binary with log_arguments set, called in certain ways.) Rather than
505just bombing out, force the log to stderr and carry on if stderr is available.
506*/
507
508if (euid != root_uid && euid != exim_uid && log_stderr != NULL)
509 {
510 *fd = fileno(log_stderr);
511 return;
512 }
513
514/* Otherwise this is a disaster. This call is deliberately ONLY to the panic
515log. If possible, save a copy of the original line that was being logged. If we
516are recursing (can't open the panic log either), the pointer will already be
517set. */
518
40c90bca
JH
519if (!panic_save_buffer)
520 if ((panic_save_buffer = US malloc(LOG_BUFFER_SIZE)))
059ec3d9 521 memcpy(panic_save_buffer, log_buffer, LOG_BUFFER_SIZE);
059ec3d9
PH
522
523log_write(0, LOG_PANIC_DIE, "Cannot open %s log file \"%s\": %s: "
524 "euid=%d egid=%d", log_names[type], buffer, strerror(errno), euid, getegid());
525/* Never returns */
526}
527
528
b0d68adc
JH
529static void
530unlink_log(int type)
531{
532if (type == lt_debug) unlink(CS debuglog_name);
533}
534
535
059ec3d9
PH
536
537/*************************************************
538* Add configuration file info to log line *
539*************************************************/
540
541/* This is put in a function because it's needed twice (once for debugging,
542once for real).
543
544Arguments:
545 ptr pointer to the end of the line we are building
546 flags log flags
547
548Returns: updated pointer
549*/
550
551static uschar *
552log_config_info(uschar *ptr, int flags)
553{
554Ustrcpy(ptr, "Exim configuration error");
555ptr += 24;
556
557if ((flags & (LOG_CONFIG_FOR & ~LOG_CONFIG)) != 0)
558 {
559 Ustrcpy(ptr, " for ");
560 return ptr + 5;
561 }
562
563if ((flags & (LOG_CONFIG_IN & ~LOG_CONFIG)) != 0)
571b2715 564 ptr += sprintf(CS ptr, " in line %d of %s", config_lineno, config_filename);
059ec3d9
PH
565
566Ustrcpy(ptr, ":\n ");
567return ptr + 4;
568}
569
570
571/*************************************************
572* A write() operation failed *
573*************************************************/
574
575/* This function is called when write() fails on anything other than the panic
576log, which can happen if a disk gets full or a file gets too large or whatever.
577We try to save the relevant message in the panic_save buffer before crashing
578out.
579
23ecb73d
PP
580The potential invoker should probably not call us for EINTR -1 writes. But
581otherwise, short writes are bad as we don't do non-blocking writes to fds
582subject to flow control. (If we do, that's new and the logic of this should
583be reconsidered).
584
059ec3d9
PH
585Arguments:
586 name the name of the log being written
587 length the string length being written
588 rc the return value from write()
589
590Returns: does not return
591*/
592
593static void
594log_write_failed(uschar *name, int length, int rc)
595{
596int save_errno = errno;
597
40c90bca
JH
598if (!panic_save_buffer)
599 if ((panic_save_buffer = US malloc(LOG_BUFFER_SIZE)))
059ec3d9 600 memcpy(panic_save_buffer, log_buffer, LOG_BUFFER_SIZE);
059ec3d9
PH
601
602log_write(0, LOG_PANIC_DIE, "failed to write to %s: length=%d result=%d "
603 "errno=%d (%s)", name, length, rc, save_errno,
604 (save_errno == 0)? "write incomplete" : strerror(save_errno));
605/* Never returns */
606}
607
608
609
0599f9cf
PP
610/*************************************************
611* Write to an fd, retrying after signals *
612*************************************************/
613
614/* Basic write to fd for logs, handling EINTR.
615
616Arguments:
617 fd the fd to write to
618 buf the string to write
619 length the string length being written
620
621Returns:
622 length actually written, persisting an errno from write()
623*/
624ssize_t
17c76198 625write_to_fd_buf(int fd, const uschar *buf, size_t length)
0599f9cf
PP
626{
627ssize_t wrote;
628size_t total_written = 0;
17c76198 629const uschar *p = buf;
0599f9cf
PP
630size_t left = length;
631
632while (1)
633 {
634 wrote = write(fd, p, left);
635 if (wrote == (ssize_t)-1)
636 {
637 if (errno == EINTR) continue;
638 return wrote;
639 }
640 total_written += wrote;
641 if (wrote == left)
642 break;
643 else
644 {
645 p += wrote;
646 left -= wrote;
647 }
648 }
649return total_written;
650}
651
652
e4a6fb35
JH
653
654static void
655set_file_path(void)
656{
657int sep = ':'; /* Fixed separator - outside use */
658uschar *t;
659const uschar *tt = US LOG_FILE_PATH;
660while ((t = string_nextinlist(&tt, &sep, log_buffer, LOG_BUFFER_SIZE)))
661 {
662 if (Ustrcmp(t, "syslog") == 0 || t[0] == 0) continue;
663 file_path = string_copy(t);
664 break;
665 }
666}
667
668
9cd319d9
JH
669void
670mainlog_close(void)
671{
672if (mainlogfd < 0) return;
673(void)close(mainlogfd);
674mainlogfd = -1;
675mainlog_inode = 0;
676}
e4a6fb35 677
059ec3d9
PH
678/*************************************************
679* Write message to log file *
680*************************************************/
681
682/* Exim can be configured to log to local files, or use syslog, or both. This
683is controlled by the setting of log_file_path. The following cases are
684recognized:
685
686 log_file_path = "" write files in the spool/log directory
687 log_file_path = "xxx" write files in the xxx directory
688 log_file_path = "syslog" write to syslog
689 log_file_path = "syslog : xxx" write to syslog and to files (any order)
690
059ec3d9
PH
691The message always gets '\n' added on the end of it, since more than one
692process may be writing to the log at once and we don't want intermingling to
693happen in the middle of lines. To be absolutely sure of this we write the data
694into a private buffer and then put it out in a single write() call.
695
696The flags determine which log(s) the message is written to, or for syslogging,
697which priority to use, and in the case of the panic log, whether the process
698should die afterwards.
699
700The variable really_exim is TRUE only when exim is running in privileged state
701(i.e. not with a changed configuration or with testing options such as -brw).
702If it is not, don't try to write to the log because permission will probably be
703denied.
704
705Avoid actually writing to the logs when exim is called with -bv or -bt to
4c04137d 706test an address, but take other actions, such as panicking.
059ec3d9
PH
707
708In Exim proper, the buffer for building the message is got at start-up, so that
709nothing gets done if it can't be got. However, some functions that are also
710used in utilities occasionally obey log_write calls in error situations, and it
711is simplest to put a single malloc() here rather than put one in each utility.
712Malloc is used directly because the store functions may call log_write().
713
714If a message_id exists, we include it after the timestamp.
715
716Arguments:
717 selector write to main log or LOG_INFO only if this value is zero, or if
6c6d6e48 718 its bit is set in log_selector[0]
059ec3d9
PH
719 flags each bit indicates some independent action:
720 LOG_SENDER add raw sender to the message
721 LOG_RECIPIENTS add raw recipients list to message
722 LOG_CONFIG add "Exim configuration error"
723 LOG_CONFIG_FOR add " for " instead of ":\n "
724 LOG_CONFIG_IN add " in line x[ of file y]"
725 LOG_MAIN write to main log or syslog LOG_INFO
726 LOG_REJECT write to reject log or syslog LOG_NOTICE
727 LOG_PANIC write to panic log or syslog LOG_ALERT
728 LOG_PANIC_DIE write to panic log or LOG_ALERT and then crash
059ec3d9
PH
729 format a printf() format
730 ... arguments for format
731
732Returns: nothing
733*/
734
735void
1ba28e2b 736log_write(unsigned int selector, int flags, const char *format, ...)
059ec3d9 737{
571b2715 738uschar * ptr;
0599f9cf 739int length;
059ec3d9 740int paniclogfd;
23ecb73d 741ssize_t written_len;
059ec3d9
PH
742va_list ap;
743
744/* If panic_recurseflag is set, we have failed to open the panic log. This is
745the ultimate disaster. First try to write the message to a debug file and/or
746stderr and also to syslog. If panic_save_buffer is not NULL, it contains the
747original log line that caused the problem. Afterwards, expire. */
748
749if (panic_recurseflag)
750 {
30f962e0
JH
751 uschar *extra = panic_save_buffer ? panic_save_buffer : US"";
752 if (debug_file) debug_printf("%s%s", extra, log_buffer);
753 if (log_stderr && log_stderr != debug_file)
059ec3d9 754 fprintf(log_stderr, "%s%s", extra, log_buffer);
30f962e0 755 if (*extra) write_syslog(LOG_CRIT, extra);
059ec3d9
PH
756 write_syslog(LOG_CRIT, log_buffer);
757 die(US"exim: could not open panic log - aborting: see message(s) above",
758 US"Unexpected log failure, please try later");
759 }
760
761/* Ensure we have a buffer (see comment above); this should never be obeyed
762when running Exim proper, only when running utilities. */
763
40c90bca
JH
764if (!log_buffer)
765 if (!(log_buffer = US malloc(LOG_BUFFER_SIZE)))
059ec3d9
PH
766 {
767 fprintf(stderr, "exim: failed to get store for log buffer\n");
9bfb7e1b 768 exim_exit(EXIT_FAILURE, NULL);
059ec3d9 769 }
059ec3d9
PH
770
771/* If we haven't already done so, inspect the setting of log_file_path to
772determine whether to log to files and/or to syslog. Bits in logging_mode
773control this, and for file logging, the path must end up in file_path. This
774variable must be in permanent store because it may be required again later in
775the process. */
776
777if (!path_inspected)
778 {
779 BOOL multiple = FALSE;
780 int old_pool = store_pool;
781
782 store_pool = POOL_PERM;
783
784 /* If nothing has been set, don't waste effort... the default values for the
785 statics are file_path="" and logging_mode = LOG_MODE_FILE. */
786
e4a6fb35 787 if (*log_file_path)
059ec3d9
PH
788 {
789 int sep = ':'; /* Fixed separator - outside use */
790 uschar *s;
55414b25 791 const uschar *ss = log_file_path;
30f962e0 792
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;
30f962e0
JH
798 else if (logging_mode & LOG_MODE_FILE)
799 multiple = TRUE;
059ec3d9
PH
800 else
801 {
802 logging_mode |= LOG_MODE_FILE;
803
804 /* If a non-empty path is given, use it */
805
e4a6fb35 806 if (*s)
059ec3d9 807 file_path = string_copy(s);
059ec3d9
PH
808
809 /* If the path is empty, we want to use the first non-empty, non-
810 syslog item in LOG_FILE_PATH, if there is one, since the value of
811 log_file_path may have been set at runtime. If there is no such item,
812 use the ultimate default in the spool directory. */
813
814 else
e4a6fb35 815 set_file_path(); /* Empty item in log_file_path */
059ec3d9
PH
816 } /* First non-syslog item in log_file_path */
817 } /* Scan of log_file_path */
818 }
819
820 /* If no modes have been selected, it is a major disaster */
821
822 if (logging_mode == 0)
823 die(US"Neither syslog nor file logging set in log_file_path",
824 US"Unexpected logging failure");
825
826 /* Set up the ultimate default if necessary. Then revert to the old store
827 pool, and record that we've sorted out the path. */
828
30f962e0 829 if (logging_mode & LOG_MODE_FILE && !file_path[0])
059ec3d9
PH
830 file_path = string_sprintf("%s/log/%%slog", spool_directory);
831 store_pool = old_pool;
832 path_inspected = TRUE;
833
834 /* If more than one file path was given, log a complaint. This recursive call
835 should work since we have now set up the routing. */
836
837 if (multiple)
059ec3d9
PH
838 log_write(0, LOG_MAIN|LOG_PANIC,
839 "More than one path given in log_file_path: using %s", file_path);
059ec3d9
PH
840 }
841
842/* If debugging, show all log entries, but don't show headers. Do it all
843in one go so that it doesn't get split when multi-processing. */
844
845DEBUG(D_any|D_v)
846 {
847 int i;
848 ptr = log_buffer;
849
850 Ustrcpy(ptr, "LOG:");
851 ptr += 4;
852
6c6d6e48 853 /* Show the selector that was passed into the call. */
059ec3d9
PH
854
855 for (i = 0; i < log_options_count; i++)
856 {
ac881e27
TF
857 unsigned int bitnum = log_options[i].bit;
858 if (bitnum < BITWORDSIZE && selector == BIT(bitnum))
059ec3d9
PH
859 {
860 *ptr++ = ' ';
861 Ustrcpy(ptr, log_options[i].name);
862 while (*ptr) ptr++;
863 }
864 }
865
5976eb99 866 ptr += sprintf(CS ptr, "%s%s%s%s\n ",
30f962e0
JH
867 flags & LOG_MAIN ? " MAIN" : "",
868 flags & LOG_PANIC ? " PANIC" : "",
869 (flags & LOG_PANIC_DIE) == LOG_PANIC_DIE ? " DIE" : "",
870 flags & LOG_REJECT ? " REJECT" : "");
059ec3d9 871
30f962e0 872 if (flags & LOG_CONFIG) ptr = log_config_info(ptr, flags);
059ec3d9
PH
873
874 va_start(ap, format);
875 if (!string_vformat(ptr, LOG_BUFFER_SIZE - (ptr-log_buffer)-1, format, ap))
876 Ustrcpy(ptr, "**** log string overflowed log buffer ****");
877 va_end(ap);
878
879 while(*ptr) ptr++;
880 Ustrcat(ptr, "\n");
881 debug_printf("%s", log_buffer);
882 }
883
884/* If no log file is specified, we are in a mess. */
885
30f962e0 886if (!(flags & (LOG_MAIN|LOG_PANIC|LOG_REJECT)))
059ec3d9
PH
887 log_write(0, LOG_MAIN|LOG_PANIC_DIE, "log_write called with no log "
888 "flags set");
889
890/* There are some weird circumstances in which logging is disabled. */
891
892if (disable_logging)
893 {
894 DEBUG(D_any) debug_printf("log writing disabled\n");
895 return;
896 }
897
a7d7aa58
PH
898/* Handle disabled reject log */
899
900if (!write_rejectlog) flags &= ~LOG_REJECT;
901
921b12ca
TF
902/* Create the main message in the log buffer. Do not include the message id
903when called by a utility. */
059ec3d9
PH
904
905ptr = log_buffer;
571b2715 906ptr += sprintf(CS ptr, "%s ", tod_stamp(tod_log));
f3f065bb 907
6c6d6e48 908if (LOGGING(pid))
f3f065bb 909 {
dd7b74e9 910 if (!syslog_pid) pid_position[0] = ptr - log_buffer; /* remember begin … */
571b2715 911 ptr += sprintf(CS ptr, "[%d] ", (int)getpid());
dd7b74e9 912 if (!syslog_pid) pid_position[1] = ptr - log_buffer; /* … and end+1 of the PID */
f3f065bb
PH
913 }
914
921b12ca 915if (really_exim && message_id[0] != 0)
571b2715 916 ptr += sprintf(CS ptr, "%s ", message_id);
059ec3d9 917
30f962e0 918if (flags & LOG_CONFIG) ptr = log_config_info(ptr, flags);
059ec3d9
PH
919
920va_start(ap, format);
921if (!string_vformat(ptr, LOG_BUFFER_SIZE - (ptr-log_buffer)-1, format, ap))
922 Ustrcpy(ptr, "**** log string overflowed log buffer ****\n");
923while(*ptr) ptr++;
924va_end(ap);
925
926/* Add the raw, unrewritten, sender to the message if required. This is done
927this way because it kind of fits with LOG_RECIPIENTS. */
928
30f962e0
JH
929if ( flags & LOG_SENDER
930 && ptr < log_buffer + LOG_BUFFER_SIZE - 10 - Ustrlen(raw_sender))
571b2715 931 ptr += sprintf(CS ptr, " from <%s>", raw_sender);
059ec3d9
PH
932
933/* Add list of recipients to the message if required; the raw list,
934before rewriting, was saved in raw_recipients. There may be none, if an ACL
935discarded them all. */
936
30f962e0
JH
937if ( flags & LOG_RECIPIENTS
938 && ptr < log_buffer + LOG_BUFFER_SIZE - 6
939 && raw_recipients_count > 0)
059ec3d9
PH
940 {
941 int i;
571b2715 942 ptr += sprintf(CS ptr, " for");
059ec3d9
PH
943 for (i = 0; i < raw_recipients_count; i++)
944 {
571b2715 945 uschar * s = raw_recipients[i];
059ec3d9 946 if (log_buffer + LOG_BUFFER_SIZE - ptr < Ustrlen(s) + 3) break;
571b2715 947 ptr += sprintf(CS ptr, " %s", s);
059ec3d9
PH
948 }
949 }
950
571b2715 951ptr += sprintf(CS ptr, "\n");
059ec3d9
PH
952length = ptr - log_buffer;
953
954/* Handle loggable errors when running a utility, or when address testing.
955Write to log_stderr unless debugging (when it will already have been written),
956or unless there is no log_stderr (expn called from daemon, for example). */
957
958if (!really_exim || log_testing_mode)
959 {
30f962e0
JH
960 if ( !debug_selector
961 && log_stderr
962 && (selector == 0 || (selector & log_selector[0]) != 0)
963 )
059ec3d9
PH
964 if (host_checking)
965 fprintf(log_stderr, "LOG: %s", CS(log_buffer + 20)); /* no timestamp */
966 else
967 fprintf(log_stderr, "%s", CS log_buffer);
30f962e0 968
9bfb7e1b 969 if ((flags & LOG_PANIC_DIE) == LOG_PANIC_DIE) exim_exit(EXIT_FAILURE, US"");
059ec3d9
PH
970 return;
971 }
972
973/* Handle the main log. We know that either syslog or file logging (or both) is
974set up. A real file gets left open during reception or delivery once it has
975been opened, but we don't want to keep on writing to it for too long after it
976has been renamed. Therefore, do a stat() and see if the inode has changed, and
977if so, re-open. */
978
3cc3f762
JH
979if ( flags & LOG_MAIN
980 && (!selector || selector & log_selector[0]))
059ec3d9 981 {
3cc3f762
JH
982 if ( logging_mode & LOG_MODE_SYSLOG
983 && (syslog_duplication || !(flags & (LOG_REJECT|LOG_PANIC))))
059ec3d9
PH
984 write_syslog(LOG_INFO, log_buffer);
985
3cc3f762 986 if (logging_mode & LOG_MODE_FILE)
059ec3d9
PH
987 {
988 struct stat statbuf;
989
990 /* Check for a change to the mainlog file name when datestamping is in
991 operation. This happens at midnight, at which point we want to roll over
992 the file. Closing it has the desired effect. */
993
cd2e3fd0 994 if (mainlog_datestamp)
059ec3d9 995 {
f1e5fef5 996 uschar *nowstamp = tod_stamp(string_datestamp_type);
059ec3d9
PH
997 if (Ustrncmp (mainlog_datestamp, nowstamp, Ustrlen(nowstamp)) != 0)
998 {
f1e894f3 999 (void)close(mainlogfd); /* Close the file */
059ec3d9
PH
1000 mainlogfd = -1; /* Clear the file descriptor */
1001 mainlog_inode = 0; /* Unset the inode */
1002 mainlog_datestamp = NULL; /* Clear the datestamp */
1003 }
1004 }
1005
1006 /* Otherwise, we want to check whether the file has been renamed by a
1007 cycling script. This could be "if else", but for safety's sake, leave it as
1008 "if" so that renaming the log starts a new file even when datestamping is
1009 happening. */
1010
1011 if (mainlogfd >= 0)
059ec3d9 1012 if (Ustat(mainlog_name, &statbuf) < 0 || statbuf.st_ino != mainlog_inode)
9cd319d9 1013 mainlog_close();
059ec3d9
PH
1014
1015 /* If the log is closed, open it. Then write the line. */
1016
1017 if (mainlogfd < 0)
1018 {
ed7f7860 1019 open_log(&mainlogfd, lt_main, NULL); /* No return on error */
059ec3d9
PH
1020 if (fstat(mainlogfd, &statbuf) >= 0) mainlog_inode = statbuf.st_ino;
1021 }
1022
1023 /* Failing to write to the log is disastrous */
1024
0599f9cf 1025 written_len = write_to_fd_buf(mainlogfd, log_buffer, length);
23ecb73d 1026 if (written_len != length)
059ec3d9 1027 {
23ecb73d 1028 log_write_failed(US"main log", length, written_len);
059ec3d9
PH
1029 /* That function does not return */
1030 }
1031 }
1032 }
1033
a7d7aa58
PH
1034/* Handle the log for rejected messages. This can be globally disabled, in
1035which case the flags are altered above. If there are any header lines (i.e. if
1036the rejection is happening after the DATA phase), log the recipients and the
1037headers. */
059ec3d9 1038
30f962e0 1039if (flags & LOG_REJECT)
059ec3d9
PH
1040 {
1041 header_line *h;
1042
30f962e0 1043 if (header_list && LOGGING(rejected_header))
059ec3d9
PH
1044 {
1045 if (recipients_count > 0)
1046 {
1047 int i;
1048
1049 /* List the sender */
1050
1051 string_format(ptr, LOG_BUFFER_SIZE - (ptr-log_buffer),
1052 "Envelope-from: <%s>\n", sender_address);
1053 while (*ptr) ptr++;
1054
1055 /* List up to 5 recipients */
1056
1057 string_format(ptr, LOG_BUFFER_SIZE - (ptr-log_buffer),
1058 "Envelope-to: <%s>\n", recipients_list[0].address);
1059 while (*ptr) ptr++;
1060
1061 for (i = 1; i < recipients_count && i < 5; i++)
1062 {
1063 string_format(ptr, LOG_BUFFER_SIZE - (ptr-log_buffer), " <%s>\n",
1064 recipients_list[i].address);
1065 while (*ptr) ptr++;
1066 }
1067
1068 if (i < recipients_count)
1069 {
1070 (void)string_format(ptr, LOG_BUFFER_SIZE - (ptr-log_buffer),
1071 " ...\n");
1072 while (*ptr) ptr++;
1073 }
1074 }
1075
1076 /* A header with a NULL text is an unfilled in Received: header */
1077
571b2715 1078 for (h = header_list; h; h = h->next) if (h->text)
059ec3d9 1079 {
571b2715 1080 BOOL fitted = string_format(ptr, LOG_BUFFER_SIZE - (ptr-log_buffer),
059ec3d9
PH
1081 "%c %s", h->type, h->text);
1082 while(*ptr) ptr++;
1083 if (!fitted) /* Buffer is full; truncate */
1084 {
1085 ptr -= 100; /* For message and separator */
1086 if (ptr[-1] == '\n') ptr--;
1087 Ustrcpy(ptr, "\n*** truncated ***\n");
1088 while (*ptr) ptr++;
1089 break;
1090 }
1091 }
1092
1093 length = ptr - log_buffer;
1094 }
1095
1096 /* Write to syslog or to a log file */
1097
30f962e0
JH
1098 if ( logging_mode & LOG_MODE_SYSLOG
1099 && (syslog_duplication || !(flags & LOG_PANIC)))
059ec3d9
PH
1100 write_syslog(LOG_NOTICE, log_buffer);
1101
1102 /* Check for a change to the rejectlog file name when datestamping is in
1103 operation. This happens at midnight, at which point we want to roll over
1104 the file. Closing it has the desired effect. */
1105
30f962e0 1106 if (logging_mode & LOG_MODE_FILE)
059ec3d9
PH
1107 {
1108 struct stat statbuf;
1109
571b2715 1110 if (rejectlog_datestamp)
059ec3d9 1111 {
f1e5fef5 1112 uschar *nowstamp = tod_stamp(string_datestamp_type);
059ec3d9
PH
1113 if (Ustrncmp (rejectlog_datestamp, nowstamp, Ustrlen(nowstamp)) != 0)
1114 {
f1e894f3 1115 (void)close(rejectlogfd); /* Close the file */
059ec3d9
PH
1116 rejectlogfd = -1; /* Clear the file descriptor */
1117 rejectlog_inode = 0; /* Unset the inode */
1118 rejectlog_datestamp = NULL; /* Clear the datestamp */
1119 }
1120 }
1121
1122 /* Otherwise, we want to check whether the file has been renamed by a
1123 cycling script. This could be "if else", but for safety's sake, leave it as
1124 "if" so that renaming the log starts a new file even when datestamping is
1125 happening. */
1126
1127 if (rejectlogfd >= 0)
059ec3d9
PH
1128 if (Ustat(rejectlog_name, &statbuf) < 0 ||
1129 statbuf.st_ino != rejectlog_inode)
1130 {
f1e894f3 1131 (void)close(rejectlogfd);
059ec3d9
PH
1132 rejectlogfd = -1;
1133 rejectlog_inode = 0;
1134 }
059ec3d9
PH
1135
1136 /* Open the file if necessary, and write the data */
1137
1138 if (rejectlogfd < 0)
1139 {
ed7f7860 1140 open_log(&rejectlogfd, lt_reject, NULL); /* No return on error */
059ec3d9
PH
1141 if (fstat(rejectlogfd, &statbuf) >= 0) rejectlog_inode = statbuf.st_ino;
1142 }
1143
0599f9cf
PP
1144 written_len = write_to_fd_buf(rejectlogfd, log_buffer, length);
1145 if (written_len != length)
059ec3d9 1146 {
0599f9cf 1147 log_write_failed(US"reject log", length, written_len);
059ec3d9
PH
1148 /* That function does not return */
1149 }
1150 }
1151 }
1152
1153
059ec3d9
PH
1154/* Handle the panic log, which is not kept open like the others. If it fails to
1155open, there will be a recursive call to log_write(). We detect this above and
1156attempt to write to the system log as a last-ditch try at telling somebody. In
47c7a64a 1157all cases except mua_wrapper, try to write to log_stderr. */
059ec3d9 1158
30f962e0 1159if (flags & LOG_PANIC)
059ec3d9 1160 {
30f962e0 1161 if (log_stderr && log_stderr != debug_file && !mua_wrapper)
059ec3d9
PH
1162 fprintf(log_stderr, "%s", CS log_buffer);
1163
30f962e0 1164 if (logging_mode & LOG_MODE_SYSLOG)
059ec3d9 1165 write_syslog(LOG_ALERT, log_buffer);
059ec3d9
PH
1166
1167 /* If this panic logging was caused by a failure to open the main log,
1168 the original log line is in panic_save_buffer. Make an attempt to write it. */
1169
30f962e0 1170 if (logging_mode & LOG_MODE_FILE)
059ec3d9
PH
1171 {
1172 panic_recurseflag = TRUE;
ed7f7860 1173 open_log(&paniclogfd, lt_panic, NULL); /* Won't return on failure */
059ec3d9
PH
1174 panic_recurseflag = FALSE;
1175
30f962e0 1176 if (panic_save_buffer)
1ac6b2e7
JH
1177 {
1178 int i = write(paniclogfd, panic_save_buffer, Ustrlen(panic_save_buffer));
1179 i = i; /* compiler quietening */
1180 }
059ec3d9 1181
0599f9cf
PP
1182 written_len = write_to_fd_buf(paniclogfd, log_buffer, length);
1183 if (written_len != length)
059ec3d9
PH
1184 {
1185 int save_errno = errno;
1186 write_syslog(LOG_CRIT, log_buffer);
1187 sprintf(CS log_buffer, "write failed on panic log: length=%d result=%d "
0599f9cf 1188 "errno=%d (%s)", length, (int)written_len, save_errno, strerror(save_errno));
059ec3d9
PH
1189 write_syslog(LOG_CRIT, log_buffer);
1190 flags |= LOG_PANIC_DIE;
1191 }
1192
f1e894f3 1193 (void)close(paniclogfd);
059ec3d9
PH
1194 }
1195
1196 /* Give up if the DIE flag is set */
1197
1198 if ((flags & LOG_PANIC_DIE) != LOG_PANIC)
1199 die(NULL, US"Unexpected failure, please try later");
1200 }
1201}
1202
1203
1204
1205/*************************************************
1206* Close any open log files *
1207*************************************************/
1208
1209void
1210log_close_all(void)
1211{
1212if (mainlogfd >= 0)
f1e894f3 1213 { (void)close(mainlogfd); mainlogfd = -1; }
059ec3d9 1214if (rejectlogfd >= 0)
f1e894f3 1215 { (void)close(rejectlogfd); rejectlogfd = -1; }
059ec3d9
PH
1216closelog();
1217syslog_open = FALSE;
1218}
1219
ed7f7860
PP
1220
1221
6c6d6e48
TF
1222/*************************************************
1223* Multi-bit set or clear *
1224*************************************************/
1225
1226/* These functions take a list of bit indexes (terminated by -1) and
1227clear or set the corresponding bits in the selector.
1228
1229Arguments:
1230 selector address of the bit string
1231 selsize number of words in the bit string
1232 bits list of bits to set
1233*/
1234
1235void
1236bits_clear(unsigned int *selector, size_t selsize, int *bits)
1237{
1238for(; *bits != -1; ++bits)
1239 BIT_CLEAR(selector, selsize, *bits);
1240}
1241
1242void
1243bits_set(unsigned int *selector, size_t selsize, int *bits)
1244{
1245for(; *bits != -1; ++bits)
1246 BIT_SET(selector, selsize, *bits);
1247}
1248
1249
1250
ed7f7860
PP
1251/*************************************************
1252* Decode bit settings for log/debug *
1253*************************************************/
1254
1255/* This function decodes a string containing bit settings in the form of +name
1256and/or -name sequences, and sets/unsets bits in a bit string accordingly. It
1257also recognizes a numeric setting of the form =<number>, but this is not
1258intended for user use. It's an easy way for Exim to pass the debug settings
1259when it is re-exec'ed.
1260
6c6d6e48
TF
1261The option table is a list of names and bit indexes. The index -1
1262means "set all bits, except for those listed in notall". The notall
1263list is terminated by -1.
ed7f7860
PP
1264
1265The action taken for bad values varies depending upon why we're here.
1266For log messages, or if the debugging is triggered from config, then we write
1267to the log on the way out. For debug setting triggered from the command-line,
1268we treat it as an unknown option: error message to stderr and die.
1269
1270Arguments:
6c6d6e48
TF
1271 selector address of the bit string
1272 selsize number of words in the bit string
1273 notall list of bits to exclude from "all"
ed7f7860
PP
1274 string the configured string
1275 options the table of option names
1276 count size of table
1277 which "log" or "debug"
1278 flags DEBUG_FROM_CONFIG
1279
1280Returns: nothing on success - bomb out on failure
1281*/
1282
1283void
6c6d6e48
TF
1284decode_bits(unsigned int *selector, size_t selsize, int *notall,
1285 uschar *string, bit_table *options, int count, uschar *which, int flags)
ed7f7860
PP
1286{
1287uschar *errmsg;
1288if (string == NULL) return;
1289
1290if (*string == '=')
1291 {
1292 char *end; /* Not uschar */
6c6d6e48
TF
1293 memset(selector, 0, sizeof(*selector)*selsize);
1294 *selector = strtoul(CS string+1, &end, 0);
ed7f7860
PP
1295 if (*end == 0) return;
1296 errmsg = string_sprintf("malformed numeric %s_selector setting: %s", which,
1297 string);
1298 goto ERROR_RETURN;
1299 }
1300
1301/* Handle symbolic setting */
1302
1303else for(;;)
1304 {
1305 BOOL adding;
1306 uschar *s;
1307 int len;
1308 bit_table *start, *end;
1309
1310 while (isspace(*string)) string++;
1311 if (*string == 0) return;
1312
1313 if (*string != '+' && *string != '-')
1314 {
1315 errmsg = string_sprintf("malformed %s_selector setting: "
1316 "+ or - expected but found \"%s\"", which, string);
1317 goto ERROR_RETURN;
1318 }
1319
1320 adding = *string++ == '+';
1321 s = string;
1322 while (isalnum(*string) || *string == '_') string++;
1323 len = string - s;
1324
1325 start = options;
1326 end = options + count;
1327
1328 while (start < end)
1329 {
1330 bit_table *middle = start + (end - start)/2;
1331 int c = Ustrncmp(s, middle->name, len);
1332 if (c == 0)
1333 {
1334 if (middle->name[len] != 0) c = -1; else
1335 {
1336 unsigned int bit = middle->bit;
ed7f7860 1337
6c6d6e48
TF
1338 if (bit == -1)
1339 {
1340 if (adding)
1341 {
1342 memset(selector, -1, sizeof(*selector)*selsize);
1343 bits_clear(selector, selsize, notall);
1344 }
1345 else
1346 memset(selector, 0, sizeof(*selector)*selsize);
1347 }
1348 else if (adding)
1349 BIT_SET(selector, selsize, bit);
1350 else
1351 BIT_CLEAR(selector, selsize, bit);
1352
ed7f7860
PP
1353 break; /* Out of loop to match selector name */
1354 }
1355 }
1356 if (c < 0) end = middle; else start = middle + 1;
1357 } /* Loop to match selector name */
1358
1359 if (start >= end)
1360 {
1361 errmsg = string_sprintf("unknown %s_selector setting: %c%.*s", which,
1362 adding? '+' : '-', len, s);
1363 goto ERROR_RETURN;
1364 }
1365 } /* Loop for selector names */
1366
1367/* Handle disasters */
1368
1369ERROR_RETURN:
1370if (Ustrcmp(which, "debug") == 0)
1371 {
1372 if (flags & DEBUG_FROM_CONFIG)
1373 {
1374 log_write(0, LOG_CONFIG|LOG_PANIC, "%s", errmsg);
1375 return;
1376 }
1377 fprintf(stderr, "exim: %s\n", errmsg);
1378 exit(EXIT_FAILURE);
1379 }
1380else log_write(0, LOG_CONFIG|LOG_PANIC_DIE, "%s", errmsg);
1381}
1382
1383
1384
1385/*************************************************
1386* Activate a debug logfile (late) *
1387*************************************************/
1388
1389/* Normally, debugging is activated from the command-line; it may be useful
1390within the configuration to activate debugging later, based on certain
1391conditions. If debugging is already in progress, we return early, no action
1392taken (besides debug-logging that we wanted debug-logging).
1393
1394Failures in options are not fatal but will result in paniclog entries for the
1395misconfiguration.
1396
1397The first use of this is in ACL logic, "control = debug/tag=foo/opts=+expand"
1398which can be combined with conditions, etc, to activate extra logging only
9ee44efb 1399for certain sources. The second use is inetd wait mode debug preservation. */
ed7f7860
PP
1400
1401void
1402debug_logging_activate(uschar *tag_name, uschar *opts)
1403{
1404int fd = -1;
1405
1406if (debug_file)
1407 {
1408 debug_printf("DEBUGGING ACTIVATED FROM WITHIN CONFIG.\n"
b0d68adc 1409 "DEBUG: Tag=\"%s\" opts=\"%s\"\n", tag_name, opts ? opts : US"");
ed7f7860
PP
1410 return;
1411 }
1412
1413if (tag_name != NULL && (Ustrchr(tag_name, '/') != NULL))
1414 {
1415 log_write(0, LOG_MAIN|LOG_PANIC, "debug tag may not contain a '/' in: %s",
1416 tag_name);
1417 return;
1418 }
1419
1420debug_selector = D_default;
1421if (opts)
6c6d6e48 1422 decode_bits(&debug_selector, 1, debug_notall, opts,
ed7f7860 1423 debug_options, debug_options_count, US"debug", DEBUG_FROM_CONFIG);
ed7f7860 1424
e4a6fb35
JH
1425/* When activating from a transport process we may never have logged at all
1426resulting in certain setup not having been done. Hack this for now so we
1427do not segfault; note that nondefault log locations will not work */
1428
1429if (!*file_path) set_file_path();
1430
ed7f7860
PP
1431open_log(&fd, lt_debug, tag_name);
1432
1433if (fd != -1)
1434 debug_file = fdopen(fd, "w");
1435else
1436 log_write(0, LOG_MAIN|LOG_PANIC, "unable to open debug log");
1437}
1438
1439
b0d68adc
JH
1440void
1441debug_logging_stop(void)
1442{
1443if (!debug_file || !debuglog_name[0]) return;
1444
1445debug_selector = 0;
1446fclose(debug_file);
1447debug_file = NULL;
1448unlink_log(lt_debug);
1449}
1450
1451
059ec3d9 1452/* End of log.c */