Goto sanos source index
//
// syslog.c
//
// System error logging
//
// Copyright (C) 2002 Michael Ringgaard. All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
//
// 1. Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
// 3. Neither the name of the project nor the names of its contributors
// may be used to endorse or promote products derived from this software
// without specific prior written permission.
//
// 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 <os.h>
#include <syslog.h>
#include <stdarg.h>
#include <string.h>
#include <inifile.h>
#include <time.h>
extern const char *_months_abbrev[]; // in time.c
int vsprintf(char *buf, const char *fmt, va_list args);
int sprintf(char *buf, const char *fmt, ...);
unsigned long logmask = LOG_UPTO(LOG_DEBUG);
static handle_t syslogfd = -1;
static int syslogsock = -1;
static int syslogcons = 1;
void openlog(char *ident, int option, int facility) {
struct process *proc = gettib()->proc;
if (ident && strlen(ident) < 64) {
if (proc->ident) {
char *oldident = proc->ident;
proc->ident = strdup(ident);
free(oldident);
} else {
proc->ident = strdup(ident);
}
}
proc->facility = facility;
}
void closelog() {
}
int setlogmask(int mask) {
int oldmask = logmask;
if (mask != 0) logmask = mask;
return oldmask;
}
static void add_to_syslog(int pri, char *msg, int msglen, char *ident, int id, int display) {
struct peb *peb = getpeb();
char buffer[1024];
char pribuf[32];
char *bufend;
char *hostname;
time_t now;
struct tm tm;
struct iovec iov[4];
if ((logmask & LOG_MASK(LOG_PRI(pri))) == 0) return;
if (*peb->hostname) {
hostname = peb->hostname;
} else {
hostname = get_property(osconfig(), "os", "hostname", NULL);
if (!hostname && peb->ipaddr.s_addr != INADDR_ANY) hostname = inet_ntoa(peb->ipaddr);
if (!hostname) hostname = "localhost";
}
now = time(NULL);
localtime_r(&now, &tm);
sprintf(pribuf, "<%d>", pri);
sprintf(buffer, "%s %2d %02d:%02d:%02d %s ", _months_abbrev[tm.tm_mon], tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec, hostname);
bufend = buffer + strlen(buffer);
if (ident) {
if (id != -1) {
sprintf(bufend, "%s[%d]: ", ident, id);
} else {
sprintf(bufend, "%s: ", ident);
}
bufend += strlen(bufend);
}
iov[0].iov_base = pribuf;
iov[0].iov_len = strlen(pribuf);
iov[1].iov_base = buffer;
iov[1].iov_len = bufend - buffer;
iov[2].iov_base = msg;
iov[2].iov_len = msglen;
iov[3].iov_base = "\n";
iov[3].iov_len = 1;
if (display) writev(syslogcons, iov + 1, 3);
if (syslogfd >= 0) writev(syslogfd, iov, 4);
if (syslogsock >= 0) writev(syslogsock, iov, 3);
}
void vsyslog(int pri, const char *fmt, va_list args) {
char buffer[1024];
char *ident;
int priority;
int facility;
struct tib *tib;
priority = LOG_PRI(pri);
facility = LOG_FAC(pri);
if ((logmask & LOG_MASK(priority)) == 0) return;
tib = gettib();
if (facility == 0) {
if (tib->proc) {
facility = tib->proc->facility;
} else {
facility = LOG_USER;
}
}
if (tib->proc && tib->proc->ident) {
ident = tib->proc->ident;
} else {
ident = "thread";
}
vsprintf(buffer, fmt, args);
add_to_syslog(LOG_MAKEPRI(facility, priority), buffer, strlen(buffer), ident, tib->tid, 1);
}
void syslog(int pri, const char *fmt, ...) {
va_list args;
va_start(args, fmt);
vsyslog(pri, fmt, args);
}
void add_to_klog(char *msg, int msglen) {
int pri = LOG_DEBUG;
if (msglen >= 3 && msg[0] == '<' && msg[1] >= '0' && msg[1] <= '7' && msg[2] == '>') {
pri = msg[1] - '0';
msg += 3;
msglen -= 3;
}
add_to_syslog(LOG_MAKEPRI(LOG_KERN, pri), msg, msglen, NULL, -1, 0);
}
void __stdcall klogd(void *arg) {
int klog;
char buffer[512];
char line[512];
int size;
int linelen;
klog = open("/dev/klog", O_BINARY);
if (klog < 0) return;
linelen = 0;
while (1) {
size = read(klog, buffer, sizeof buffer);
if (size < 0) {
break;
} else if (size > 0) {
int i;
for (i = 0; i < size; i++) {
if (linelen == sizeof(line)) {
add_to_klog(line, linelen);
linelen = 0;
}
if (buffer[i] == '\n') {
if (linelen > 0) add_to_klog(line, linelen);
linelen = 0;
} else {
line[linelen++] = buffer[i];
}
}
} else {
if (ioctl(klog, IOCTL_KLOG_WAIT, NULL, 0) < 0) break;
}
}
close(klog);
}
void start_syslog() {
char *logfn;
char *loghost;
logmask = LOG_UPTO(get_numeric_property(osconfig(), "os", "loglevel", LOG_DEBUG));
syslogcons = fderr;
logfn = get_property(osconfig(), "os", "logfile", NULL);
if (logfn != NULL) {
syslogfd = open(logfn, O_CREAT, S_IREAD | S_IWRITE);
if (syslogfd >= 0) lseek(syslogfd, 0, SEEK_END);
}
loghost = get_property(osconfig(), "os", "loghost", NULL);
if (loghost != NULL) {
struct hostent *hp;
hp = gethostbyname(loghost);
if (hp) {
struct sockaddr_in sin;
memset(&sin, 0, sizeof(sin));
sin.sin_family = AF_INET;
memcpy(&sin.sin_addr, hp->h_addr_list[0], hp->h_length);
sin.sin_port = htons(514);
syslogsock = socket(AF_INET, SOCK_DGRAM, 0);
connect(syslogsock, (struct sockaddr *) &sin, sizeof(sin));
} else {
syslog(LOG_ERR | LOG_SYSLOG, "unknown syslog server %s", loghost);
}
}
close(beginthread(klogd, 0, NULL, 0, "syslogd", NULL));
}
void stop_syslog() {
if (syslogfd >= 0) {
close(syslogfd);
syslogfd = -1;
}
if (syslogsock > 0) {
close(syslogsock);
syslogsock = -1;
}
}