/*
 * dsyslog - a dumb syslog (e.g. syslog for people who have a clue)
 * Copyright (c) 2008 William Pitcock <nenolod@sacredspiral.co.uk>
 *
 * Permission to use, copy, modify, and/or distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice is present in all copies.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include <glib.h>
#include <sys/stat.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <sys/poll.h>
#include <sys/stat.h>

#include "dsyslog.h"

static void
klogfile_parse_inbound_line(gchar *line)
{
	int logcode;
	gchar *message;
	time_t now;
	static char datebuf[400];
	struct tm *tm;

	_ENTER;

	if (*line != '<') {
		_LEAVE;
	}

	if ((logcode = atoi(++line)) <= 0) {
		_LEAVE;
	}

	while (*line != '>') {
		if (*line == '\0') {
			_LEAVE;
		}

		line++;
	}
	message = ++line;

	now = time(NULL);
	tm = localtime(&now);
	strftime(datebuf, sizeof datebuf, "%b %e %T", tm);

	dsyslog_event_dispatch(logcode, datebuf, NULL, "kernel", 0, message);

	_LEAVE;
}

static gboolean
klogfile_ioevent_cb(GIOChannel *source, GIOCondition cond, gpointer unused)
{
	gchar *line;
	GError *error = NULL;
	gsize termpos = 0;

	_ENTER;

	g_io_channel_read_line(source, &line, NULL, &termpos, &error);
	line[termpos] = '\0';
	klogfile_parse_inbound_line(line);
	g_free(line);

	_LEAVE TRUE;
}

struct dsyslog_source_klogfile {
	GIOChannel *logchan;
	gint tag;
};

static void
dsyslog_source_klogfile_delete(dsyslog_source_t *src)
{
	struct dsyslog_source_klogfile *klogfile;

	_ENTER;

	klogfile = src->opaque;
	g_source_remove(klogfile->tag);
	g_io_channel_unref(klogfile->logchan);
	g_slice_free(struct dsyslog_source_klogfile, klogfile);

	_LEAVE;
}

static void
dsyslog_source_klogfile_new(dsyslog_source_t *src)
{
	struct dsyslog_source_klogfile *klogfile;
	GError *error = NULL;

	_ENTER;

	if (!src->path) {
		_LEAVE;
	}

	klogfile = g_slice_new0(struct dsyslog_source_klogfile);
	klogfile->logchan = g_io_channel_new_file(src->path, "r", &error);

	if (error) {
		_ERROR("while opening %s: %s", src->path, error->message);
		g_clear_error(&error);
		_LEAVE;
	}

	klogfile->tag = g_io_add_watch(klogfile->logchan, G_IO_IN, klogfile_ioevent_cb, NULL);
	src->opaque = klogfile;
	src->destructor = dsyslog_source_klogfile_delete;

	_LEAVE;
}

void
_modinit(void)
{
	_ENTER;

	dsyslog_source_register("klogfile", dsyslog_source_klogfile_new);

	_LEAVE;
}

void
_modfini(void)
{
	_ENTER;

	dsyslog_source_unregister("klogfile");

	_LEAVE;
}
