/*
 * Copyright (c) 1983 Regents of the University of California.
 * All rights reserved.  The Berkeley software License Agreement
 * specifies the terms and conditions for redistribution.
 */

#if defined(LIBC_SCCS) && !defined(lint)
static char sccsid[] = "@(#)syslog.c	5.9 (Berkeley) 5/7/86";
#endif /* LIBC_SCCS and not lint */

/*
 * SYSLOG -- print message on log file
 *
 * This routine looks a lot like printf, except that it
 * outputs to the log file instead of the standard output.
 * Also:
 *	adds a timestamp,
 *	prints the module name in front of the message,
 *	has some other formatting types (or will sometime),
 *	adds a newline on the end of the message.
 *
 * The output of this routine is intended to be read by /etc/syslogd.
 *
 * Author: Eric Allman
 * Modified to use UNIX domain IPC by Ralph Campbell
 * Modified to write directly to a file for use on SYSV
 */

#include"structs.h"

#define	MAXLINE	1024			/* max message size */
#ifndef NULL
#define NULL	0			/* manifest */
#endif
#define PRIMASK(p)	(1 << ((p) & LOG_PRIMASK))
#define PRIFAC(p)	(((p) & LOG_FACMASK) >> 3)
#define IMPORTANT 	LOG_ERR

#ifndef SYSLOG
static char     local_log[] = LOGFILE;
static int	LogFile = -1;		/* fd for log */
#endif /* SYSLOG */
static int	LogStat	= 0;		/* status bits, set by openlog() */
static char	*LogTag = "syslog";	/* string to tag the entry with */
static int	LogMask = 0xff;		/* mask of priorities to be logged */
static int	LogFacility = LOG_USER;	/* default facility code */

/*VARARGS2*/
intsyslog(pri, fmt, p0, p1, p2, p3, p4)
	int pri;
	char *fmt;
{
	char buf[MAXLINE + 1], outline[MAXLINE + 1];
	register char *b, *f, *o;
	register int c;
	long now;
	int olderrno = errno;

#ifdef SYSLOG
	syslog(pri, fmt, p0, p1, p2, p3, p4);
	if (!DEBUG) return;
#endif /* SYSLOG */

	/* see if we should just throw out this message */
	if (pri <= 0 || PRIFAC(pri) >= LOG_NFACILITIES || (PRIMASK(pri) & LogMask) == 0)
		return;
#ifndef SYSLOG
	if (LogFile < 0)
		intopenlog(LogTag, LogStat | LOG_NDELAY, 0);
#endif /* SYSLOG */
	/* set default facility if none specified */
	if ((pri & LOG_FACMASK) == 0)
		pri |= LogFacility;

	/* build the message */
	o = outline;
	sprintf(o, "<%d>", pri);
	o += strlen(o);
	time(&now);
	sprintf(o, "%.15s ", ctime(&now) + 4);
	o += strlen(o);
	if (LogTag) {
		strcpy(o, LogTag);
		o += strlen(o);
	}
	if (LogStat & LOG_PID) {
		sprintf(o, "[%d]", getpid());
		o += strlen(o);
	}
	if (LogTag) {
		strcpy(o, ": ");
		o += 2;
	}

	b = buf;
	f = fmt;
	while ((c = *f++) != '\0' && c != '\n' && b < &buf[MAXLINE]) {
		if (c != '%') {
			*b++ = c;
			continue;
		}
		if ((c = *f++) != 'm') {
			*b++ = '%';
			*b++ = c;
			continue;
		}
		if ((unsigned)olderrno > sys_nerr)
			sprintf(b, "error %d", olderrno);
		else
			strcpy(b, sys_errlist[olderrno]);
		b += strlen(b);
	}
	*b++ = '\n';
	*b = '\0';
	sprintf(o, buf, p0, p1, p2, p3, p4);
	c = strlen(outline);
	if (c > MAXLINE)
		c = MAXLINE;
	strcat(o, "\r");
	o = strchr(outline, '>') + 1;
#ifndef SYSLOG
	/* output the message to the local file */
	write(LogFile, o, c + 1 - (o - outline));
#ifndef SYSV
	fsync(LogFile);
#endif /* SYSV */
#endif /* SYSLOG */
	if (DEBUG)
	  write(1, o, c + 1 - (o - outline));
}

/*
 * OPENLOG -- open system log
 */

intopenlog(ident, logstat, logfac)
	char *ident;
	int logstat, logfac;
{
#ifdef SYSLOG
openlog(ident, logstat, logfac);
#endif /* SYSLOG */
  if (ident != NULL)
    LogTag = ident;
  LogStat = logstat;
  if (logfac != 0)
    LogFacility = logfac & LOG_FACMASK;
#ifndef SYSLOG
  if (LogFile >= 0)
    return;
  if (LogStat & LOG_NDELAY)
    LogFile = open(local_log, O_CREAT | O_WRONLY | O_APPEND, 0777);
#endif /* SYSLOG */
}

/*
 * CLOSELOG -- close the system log
 */

intcloselog()
{
#ifdef SYSLOG
  closelog();
#else
  (void) close(LogFile);
  LogFile = -1;
#endif /* SYSLOG */
}

/*
 * SETLOGMASK -- set the log mask level
 */
intsetlogmask(pmask)
	int pmask;
{
#ifdef SYSLOG
  setlogmask(pmask);
#else
  int omask;
  omask = LogMask;
  if (pmask != 0)
    LogMask = pmask;
  return (omask);
#endif /* SYSLOG */
}

microsleep(useconds)
     unsigned useconds;
{
  struct timeval waiter;
  int cc;
  waiter.tv_sec = useconds/1000000;
  waiter.tv_usec = (long)useconds%1000000;
  do {
    cc = select(0, 0, 0, 0, &waiter);
  } while (cc == -1 && errno == EINTR);
}
