/*
 * syslog.c
 *
 * Issue syslog messages via the kernel printk queue.
 */

#include <stdio.h>
#include <string.h>
#include <stdarg.h>
#include <syslog.h>
#include <unistd.h>
#include <fcntl.h>

/* Maximum size for a kernel message */
#define BUFLEN 1024

/* Logging node */
#define LOGDEV "/dev/kmsg"

/* Max length of ID string */
#define MAXID 31		/* MAXID+5 must be < BUFLEN */

int __syslog_fd = -1;
static char id[MAXID + 1];
static int syslog_flags = 0;

void openlog(const char *ident, int option, int facility)
{
	int fd;

	(void)option;
	(void)facility;		/* Unused */

	if (__syslog_fd == -1) {
		__syslog_fd = fd = open(LOGDEV, O_WRONLY);
		if (fd == -1)
			return;
		fcntl(fd, F_SETFD, (long)FD_CLOEXEC);
	}

	syslog_flags = option;

	strncpy(id, ident ? ident : "", MAXID);
}

void vsyslog(int prio, const char *format, va_list ap)
{
	char buf[BUFLEN];
	int len;
	int fd;

	if (__syslog_fd == -1)
		openlog(NULL, 0, 0);

	buf[0] = '<';
	buf[1] = LOG_PRI(prio) + '0';
	buf[2] = '>';
	len = 3;

	if (syslog_flags & LOG_PID)
		len += sprintf(buf + 3, "%s[%u]: ", id, getpid());
	else if (*id)
		len += sprintf(buf + 3, "%s: ", id);

	len += vsnprintf(buf + len, BUFLEN - len, format, ap);

	if (len > BUFLEN - 1)
		len = BUFLEN - 1;
	if (buf[len - 1] != '\n')
		buf[len++] = '\n';

	fd = __syslog_fd;
	if (fd == -1)
		fd = 2;		/* Failed to open log, write to stderr */

	write(fd, buf, len);

	if (syslog_flags & LOG_PERROR)
		_fwrite(buf + 3, len - 3, stderr);
}

void syslog(int prio, const char *format, ...)
{
	va_list ap;

	va_start(ap, format);
	vsyslog(prio, format, ap);
	va_end(ap);
}
