* Exim - an Internet mail transport agent *
*************************************************/
-/* Copyright (c) University of Cambridge 1995 - 2009 */
+/* Copyright (c) University of Cambridge 1995 - 2012 */
/* See the file NOTICE for conditions of use and distribution. */
/* Functions for writing log files. The code for maintaining datestamped
Returns: a file descriptor, or < 0 on failure (errno set)
*/
-static int
+int
log_create(uschar *name)
{
int fd = Uopen(name, O_CREAT|O_APPEND|O_WRONLY, LOG_MODE);
We try to save the relevant message in the panic_save buffer before crashing
out.
+The potential invoker should probably not call us for EINTR -1 writes. But
+otherwise, short writes are bad as we don't do non-blocking writes to fds
+subject to flow control. (If we do, that's new and the logic of this should
+be reconsidered).
+
Arguments:
name the name of the log being written
length the string length being written
+/*************************************************
+* Write to an fd, retrying after signals *
+*************************************************/
+
+/* Basic write to fd for logs, handling EINTR.
+
+Arguments:
+ fd the fd to write to
+ buf the string to write
+ length the string length being written
+
+Returns:
+ length actually written, persisting an errno from write()
+*/
+ssize_t
+write_to_fd_buf(int fd, const uschar *buf, size_t length)
+{
+ssize_t wrote;
+size_t total_written = 0;
+const uschar *p = buf;
+size_t left = length;
+
+while (1)
+ {
+ wrote = write(fd, p, left);
+ if (wrote == (ssize_t)-1)
+ {
+ if (errno == EINTR) continue;
+ return wrote;
+ }
+ total_written += wrote;
+ if (wrote == left)
+ break;
+ else
+ {
+ p += wrote;
+ left -= wrote;
+ }
+ }
+return total_written;
+}
+
+
/*************************************************
* Write message to log file *
*************************************************/
log_write(unsigned int selector, int flags, const char *format, ...)
{
uschar *ptr;
-int length, rc;
+int length;
int paniclogfd;
+ssize_t written_len;
va_list ap;
/* If panic_recurseflag is set, we have failed to open the panic log. This is
}
}
- sprintf(CS ptr, "%s%s%s%s%s\n ",
+ sprintf(CS ptr, "%s%s%s%s\n ",
((flags & LOG_MAIN) != 0)? " MAIN" : "",
((flags & LOG_PANIC) != 0)? " PANIC" : "",
((flags & LOG_PANIC_DIE) == LOG_PANIC_DIE)? " DIE" : "",
/* Failing to write to the log is disastrous */
- if ((rc = write(mainlogfd, log_buffer, length)) != length)
+ written_len = write_to_fd_buf(mainlogfd, log_buffer, length);
+ if (written_len != length)
{
- log_write_failed(US"main log", length, rc);
+ log_write_failed(US"main log", length, written_len);
/* That function does not return */
}
}
if (fstat(rejectlogfd, &statbuf) >= 0) rejectlog_inode = statbuf.st_ino;
}
- if ((rc = write(rejectlogfd, log_buffer, length)) != length)
+ written_len = write_to_fd_buf(rejectlogfd, log_buffer, length);
+ if (written_len != length)
{
- log_write_failed(US"reject log", length, rc);
+ log_write_failed(US"reject log", length, written_len);
/* That function does not return */
}
}
panic_recurseflag = FALSE;
if (panic_save_buffer != NULL)
- (void) write(paniclogfd, panic_save_buffer, Ustrlen(panic_save_buffer));
+ {
+ int i = write(paniclogfd, panic_save_buffer, Ustrlen(panic_save_buffer));
+ i = i; /* compiler quietening */
+ }
- if ((rc = write(paniclogfd, log_buffer, length)) != length)
+ written_len = write_to_fd_buf(paniclogfd, log_buffer, length);
+ if (written_len != length)
{
int save_errno = errno;
write_syslog(LOG_CRIT, log_buffer);
sprintf(CS log_buffer, "write failed on panic log: length=%d result=%d "
- "errno=%d (%s)", length, rc, save_errno, strerror(save_errno));
+ "errno=%d (%s)", length, (int)written_len, save_errno, strerror(save_errno));
write_syslog(LOG_CRIT, log_buffer);
flags |= LOG_PANIC_DIE;
}
The first use of this is in ACL logic, "control = debug/tag=foo/opts=+expand"
which can be combined with conditions, etc, to activate extra logging only
-for certain sources. */
+for certain sources. The second use is inetd wait mode debug preservation. */
void
debug_logging_activate(uschar *tag_name, uschar *opts)
if (debug_file)
{
debug_printf("DEBUGGING ACTIVATED FROM WITHIN CONFIG.\n"
- "DEBUG: Tag=\"%s\" Opts=\"%s\"\n", tag_name, opts);
+ "DEBUG: Tag=\"%s\" Opts=\"%s\"\n", tag_name, opts ? opts : US"");
return;
}