/*
 * This file is part of the UCB release of Plan 9. It is subject to the license
 * terms in the LICENSE file found in the top-level directory of this
 * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
 * part of the UCB release of Plan 9, including this file, may be copied,
 * modified, propagated, or distributed except according to the terms contained
 * in the LICENSE file.
 */

#include <u.h>
#include <libc.h>

static struct
{
	int	fd;
	int	consfd;
	char	*name;
	Dir	*d;
	Dir	*consd;
	Lock;
} sl =
{
	-1, -1,
};

static void
_syslogopen(void)
{
	char buf[1024];

	if(sl.fd >= 0)
		close(sl.fd);
	jehanne_snprint(buf, sizeof(buf), "/sys/log/%s", sl.name);
	sl.fd = open(buf, OWRITE|OCEXEC);
}

static int
eqdirdev(Dir *a, Dir *b)
{
	return a != nil && b != nil &&
		a->dev == b->dev && a->type == b->type &&
		a->qid.path == b->qid.path;
}

/*
 * Print
 *  sysname: time: mesg
 * on /sys/log/logname.
 * If cons or log file can't be opened, print on the system console, too.
 */
void
jehanne_syslog(int cons, const char *logname, const char *fmt, ...)
{
	char buf[1024];
	char *ctim, *p;
	va_list arg;
	int n;
	Dir *d;
	char err[ERRMAX];

	err[0] = '\0';
	errstr(err, sizeof err);
	jehanne_lock(&sl);

	/*
	 *  paranoia makes us stat to make sure a fork+close
	 *  hasn't broken our fd's
	 */
	d = jehanne_dirfstat(sl.fd);
	if(sl.fd < 0 || sl.name == nil || jehanne_strcmp(sl.name, logname) != 0 ||
	   !eqdirdev(d, sl.d)){
		jehanne_free(sl.name);
		sl.name = jehanne_strdup(logname);
		if(sl.name == nil)
			cons = 1;
		else{
			jehanne_free(sl.d);
			sl.d = nil;
			_syslogopen();
			if(sl.fd < 0)
				cons = 1;
			else
				sl.d = jehanne_dirfstat(sl.fd);
		}
	}
	jehanne_free(d);
	if(cons){
		d = jehanne_dirfstat(sl.consfd);
		if(sl.consfd < 0 || !eqdirdev(d, sl.consd)){
			jehanne_free(sl.consd);
			sl.consd = nil;
			sl.consfd = open("#c/cons", OWRITE|OCEXEC);
			if(sl.consfd >= 0)
				sl.consd = jehanne_dirfstat(sl.consfd);
		}
		jehanne_free(d);
	}

	if(fmt == nil){
		jehanne_unlock(&sl);
		return;
	}

	ctim = jehanne_ctime(jehanne_time(0));
	p = buf + jehanne_snprint(buf, sizeof(buf)-1, "%s ", jehanne_sysname());
	jehanne_strncpy(p, ctim+4, 15);
	p += 15;
	*p++ = ' ';
	errstr(err, sizeof err);
	va_start(arg, fmt);
	p = jehanne_vseprint(p, buf+sizeof(buf)-1, fmt, arg);
	va_end(arg);
	*p++ = '\n';
	n = p - buf;

	if(sl.fd >= 0){
		seek(sl.fd, 0, 2);
		write(sl.fd, buf, n);
	}

	if(cons && sl.consfd >=0)
		write(sl.consfd, buf, n);

	jehanne_unlock(&sl);
}
