/*
 * Copyright 2001, 2002, 2003, 2013 Adam Sampson <ats@offog.org>
 *
 * 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 appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */

#include <unistd.h>
#include <signal.h>
#include <time.h>
#include <string.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include "iolib.h"
#include "freedt.h"
#include "config.h"
const char *progname = "dumblog";
const char *proghelp =
	"Usage: dumblog [OPTIONS] logfile\n"
	"Log standard input to a file.\n\n"
	"-c        Prepend a timestamp to each line\n";

int stamp_ctime = 0;
char *logfile_name;
int logfile;
int return_code = 0;
buffer line = BUFFER;
buffer overflow = BUFFER;

void flush_line() {
	if (blength(&line) > 0) {
		buffer out = BUFFER;

		if (stamp_ctime) {
			time_t t = time(NULL);
			const char *s = ctime(&t);
			bappendm(&out, s, strlen(s) - 1);
			bappendc(&out, ' ');
		}
		bappend(&out, &line);
		bappendc(&out, '\n');

		while (1) {
			if (writeba(logfile, &out) >= 0)
				break;

			warn2(logfile_name, "unable to write to logfile");
			reliable_sleep(5);
		}

		bfree(&out);
	}
	bfree(&line);
}

void open_logfile() {
	logfile = open(logfile_name, O_WRONLY | O_APPEND | O_CREAT | O_SYNC,
		0644);
	if (logfile < 0)
		die2(logfile_name, "unable to open logfile");
}

void close_logfile() {
	flush_line();

	while (1) {
		if (close(logfile) >= 0)
			break;

		warn2(logfile_name, "unable to close logfile");
		reliable_sleep(5);
	}
}

void roll_handler(int dummy) {
	close_logfile();
	open_logfile();
}

void quit_handler(int dummy) {
	flush_line();
	bappend(&line, &overflow);
	close_logfile();
	exit(return_code);
}

int main(int argc, char **argv) {
	struct sigaction sa;

	while (1) {
		int c = getopt(argc, argv, "V?c");
		if (c == -1)
			break;
		switch (c) {
		case 'c':
			stamp_ctime = 1;
			break;
		case 'V':
			version();
		default:
			help();
		}
	}

	if ((argc - optind) != 1)
		help();
	logfile_name = argv[optind];

	sigemptyset(&sa.sa_mask);
	sa.sa_flags = 0;

	sa.sa_handler = roll_handler;
	if (sigaction(SIGHUP, &sa, NULL) < 0)
		die("unable to install sighup handler");
	sa.sa_handler = quit_handler;
	if (sigaction(SIGTERM, &sa, NULL) < 0)
		die("unable to install sigterm handler");

	open_logfile();

	while (1) {
		int rc = readlineb(fd_in, &line, 0, &overflow);
		if (rc < 0) {
			warn("unable to read from stdin");
			return_code = 1;
			quit_handler(0);
		}
		if (rc == 0)
			break;

		flush_line();
	}

	quit_handler(0);
	return 0; /* NOTREACHED */
}

