<commit_before>/* Copyright (c) 2002-2008 Dovecot authors, see the included COPYING file */

#include "lib.h"
#include "ioloop.h"
#include "str.h"
#include "backtrace-string.h"
#include "printf-format-fix.h"
#include "write-full.h"
#include "fd-close-on-exec.h"

#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <syslog.h>
#include <time.h>

const char *failure_log_type_prefixes[] = {
	"Info: ",
	"Warning: ",
	"Error: ",
	"Fatal: ",
	"Panic: "
};
static char log_type_internal_chars[] = {
	'I', 'W', 'E', 'F', 'P'
};

/* Initialize working defaults */
static fatal_failure_callback_t *fatal_handler ATTR_NORETURN =
	default_fatal_handler;
static failure_callback_t *error_handler = default_error_handler;
static failure_callback_t *info_handler = default_error_handler;
static void (*failure_exit_callback)(int *) = NULL;

static int log_fd = STDERR_FILENO, log_info_fd = STDERR_FILENO;
static char *log_prefix = NULL, *log_stamp_format = NULL;

/* kludgy .. we want to trust log_stamp_format with -Wformat-nonliteral */
static const char *get_log_stamp_format(const char *unused)
	ATTR_FORMAT_ARG(1);

static const char *get_log_stamp_format(const char *unused ATTR_UNUSED)
{
	return log_stamp_format;
}

void failure_exit(int status)
{
	if (failure_exit_callback != NULL)
		failure_exit_callback(&status);
	exit(status);
}

static void log_prefix_add(string_t *str)
{
	struct tm *tm;
	char buf[256];
	time_t now;

	if (log_prefix != NULL)
		str_append(str, log_prefix);

	if (log_stamp_format != NULL) {
		now = time(NULL);
		tm = localtime(&now);

		if (strftime(buf, sizeof(buf),
			     get_log_stamp_format("unused"), tm) > 0)
			str_append(str, buf);
	}
}

static void log_fd_flush_stop(struct ioloop *ioloop)
{
	io_loop_stop(ioloop);
}

static int log_fd_write(int fd, const unsigned char *data, unsigned int len)
{
	struct ioloop *ioloop;
	struct io *io;
	ssize_t ret;

	while ((ret = write(fd, data, len)) != (ssize_t)len) {
		if (ret > 0) {
			/* some was written, continue.. */
			data += ret;
			len -= ret;
			continue;
		}
		if (ret == 0) {
			/* out of disk space? */
			return -1;
		}
		if (errno != EAGAIN)
			return -1;

		/* wait until we can write more. this can happen at least
		   when writing to terminal, even if fd is blocking. */
		ioloop = io_loop_create();
		io = io_add(IO_WRITE, fd, log_fd_flush_stop, ioloop);
		io_loop_run(ioloop);
		io_remove(&io);
		io_loop_destroy(&ioloop);
	}
	return 0;
}

static int ATTR_FORMAT(3, 0)
default_handler(const char *prefix, int fd, const char *format, va_list args)
{
	static int recursed = 0;
	int ret, old_errno = errno;

	if (recursed >= 2) {
		/* we're being called from some signal handler or we ran
		   out of memory */
		return 0;
	}

	recursed++;

	T_BEGIN {
		string_t *str = t_str_new(256);
		log_prefix_add(str);
		str_append(str, prefix);

		/* make sure there's no %n in there and fix %m */<commit_msg>If writing to log failed with EAGAIN (shouldn't normally happen), waiting for the log fd to be writable again was buggy.<commit_after>/* Copyright (c) 2002-2008 Dovecot authors, see the included COPYING file */

#include "lib.h"
#include "ioloop.h"
#include "str.h"
#include "backtrace-string.h"
#include "printf-format-fix.h"
#include "write-full.h"
#include "fd-close-on-exec.h"

#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <syslog.h>
#include <time.h>

const char *failure_log_type_prefixes[] = {
	"Info: ",
	"Warning: ",
	"Error: ",
	"Fatal: ",
	"Panic: "
};
static char log_type_internal_chars[] = {
	'I', 'W', 'E', 'F', 'P'
};

/* Initialize working defaults */
static fatal_failure_callback_t *fatal_handler ATTR_NORETURN =
	default_fatal_handler;
static failure_callback_t *error_handler = default_error_handler;
static failure_callback_t *info_handler = default_error_handler;
static void (*failure_exit_callback)(int *) = NULL;

static int log_fd = STDERR_FILENO, log_info_fd = STDERR_FILENO;
static char *log_prefix = NULL, *log_stamp_format = NULL;

/* kludgy .. we want to trust log_stamp_format with -Wformat-nonliteral */
static const char *get_log_stamp_format(const char *unused)
	ATTR_FORMAT_ARG(1);

static const char *get_log_stamp_format(const char *unused ATTR_UNUSED)
{
	return log_stamp_format;
}

void failure_exit(int status)
{
	if (failure_exit_callback != NULL)
		failure_exit_callback(&status);
	exit(status);
}

static void log_prefix_add(string_t *str)
{
	struct tm *tm;
	char buf[256];
	time_t now;

	if (log_prefix != NULL)
		str_append(str, log_prefix);

	if (log_stamp_format != NULL) {
		now = time(NULL);
		tm = localtime(&now);

		if (strftime(buf, sizeof(buf),
			     get_log_stamp_format("unused"), tm) > 0)
			str_append(str, buf);
	}
}

static void log_fd_flush_stop(struct ioloop *ioloop)
{
	io_loop_stop(ioloop);
}

static int log_fd_write(int fd, const unsigned char *data, unsigned int len)
{
	struct ioloop *ioloop;
	struct io *io;
	ssize_t ret;

	while ((ret = write(fd, data, len)) != (ssize_t)len) {
		if (ret > 0) {
			/* some was written, continue.. */
			data += ret;
			len -= ret;
			continue;
		}
		if (ret == 0) {
			/* out of disk space? */
			return -1;
		}
		if (errno != EAGAIN)
			return -1;

		/* wait until we can write more. this can happen at least
		   when writing to terminal, even if fd is blocking. */
		ioloop = io_loop_create();
		io = io_add(fd, IO_WRITE, log_fd_flush_stop, ioloop);
		io_loop_run(ioloop);
		io_remove(&io);
		io_loop_destroy(&ioloop);
	}
	return 0;
}

static int ATTR_FORMAT(3, 0)
default_handler(const char *prefix, int fd, const char *format, va_list args)
{
	static int recursed = 0;
	int ret, old_errno = errno;

	if (recursed >= 2) {
		/* we're being called from some signal handler or we ran
		   out of memory */
		return 0;
	}

	recursed++;

	T_BEGIN {
		string_t *str = t_str_new(256);
		log_prefix_add(str);
		str_append(str, prefix);

		/* make sure there's no %n in there and fix %m */
{'fraction_non_alphanumeric': 0.13122783313629455, 'fraction_numerical': 0.008782300287113663, 'mean_word_length': 4.25, 'pattern_counts': {'":': 0, '<': 13, '<?xml version=': 0, '>': 19, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1503566', 'n_tokens_mistral': 2392, 'n_tokens_neox': 2224, 'n_words': 606}