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