mirror of
https://github.com/rsyslog/rsyslog.git
synced 2025-12-21 21:50:42 +01:00
294 lines
6.7 KiB
C
294 lines
6.7 KiB
C
/*
|
|
* CDDL HEADER START
|
|
*
|
|
* The contents of this file are subject to the terms of the
|
|
* Common Development and Distribution License (the "License").
|
|
* You may not use this file except in compliance with the License.
|
|
*
|
|
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
|
|
* or http://www.opensolaris.org/os/licensing.
|
|
* See the License for the specific language governing permissions
|
|
* and limitations under the License.
|
|
*
|
|
* When distributing Covered Code, include this CDDL HEADER in each
|
|
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
|
|
* If applicable, add the following below this CDDL HEADER, with the
|
|
* fields enclosed by brackets "[]" replaced with your own identifying
|
|
* information: Portions Copyright [yyyy] [name of copyright owner]
|
|
*
|
|
* CDDL HEADER END
|
|
*/
|
|
/* Portions Copyright 2010 by Rainer Gerhards and Adiscon
|
|
*/
|
|
/*
|
|
* Copyright 2008 Sun Microsystems, Inc. All rights reserved.
|
|
* Use is subject to license terms.
|
|
*/
|
|
|
|
/*
|
|
* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T
|
|
* All Rights Reserved
|
|
*/
|
|
|
|
/*
|
|
* University Copyright- Copyright (c) 1982, 1986, 1988
|
|
* The Regents of the University of California
|
|
* All Rights Reserved
|
|
*
|
|
* University Acknowledgment- Portions of this document are derived from
|
|
* software developed by the University of California, Berkeley, and its
|
|
* contributors.
|
|
*/
|
|
#include "config.h"
|
|
#include <stdlib.h>
|
|
#include <unistd.h>
|
|
#include <errno.h>
|
|
#include <pthread.h>
|
|
#include <sys/poll.h>
|
|
#include <pthread.h>
|
|
#include <fcntl.h>
|
|
#include <stropts.h>
|
|
#include <assert.h>
|
|
#include <sys/strlog.h>
|
|
|
|
#include "rsyslog.h"
|
|
#include "imklog.h"
|
|
|
|
/* TODO: this define should be changed over time to the more generic
|
|
* system-provided (configurable) upper limit. However, it is quite
|
|
* unexpected that Solaris-emitted messages are so long, so it seems
|
|
* acceptable to set a fixed (relatively high) limit for the time
|
|
* being -- and gain some experience with it. -- rgerhars, 2010-04-12
|
|
*/
|
|
#define MAXLINE 4096
|
|
|
|
static struct pollfd Pfd; /* Pollfd for local the log device */
|
|
|
|
|
|
/* findnl_bkwd:
|
|
* Scans each character in buf until it finds the last newline in buf,
|
|
* or the scanned character becomes the last COMPLETE character in buf.
|
|
* Returns the number of scanned bytes.
|
|
*
|
|
* buf - pointer to a buffer containing the message string
|
|
* len - the length of the buffer
|
|
*/
|
|
size_t
|
|
findnl_bkwd(const char *buf, const size_t len)
|
|
{
|
|
const char *p;
|
|
size_t mb_cur_max;
|
|
|
|
if (len == 0) {
|
|
return (0);
|
|
}
|
|
|
|
mb_cur_max = MB_CUR_MAX;
|
|
|
|
if (mb_cur_max == 1) {
|
|
/* single-byte locale */
|
|
for (p = buf + len - 1; p != buf; p--) {
|
|
if (*p == '\n') {
|
|
return ((size_t)(p - buf));
|
|
}
|
|
}
|
|
return ((size_t)len);
|
|
} else {
|
|
/* multi-byte locale */
|
|
int mlen;
|
|
const char *nl;
|
|
size_t rem;
|
|
|
|
p = buf;
|
|
nl = NULL;
|
|
for (rem = len; rem >= mb_cur_max; ) {
|
|
mlen = mblen(p, mb_cur_max);
|
|
if (mlen == -1) {
|
|
/*
|
|
* Invalid character found.
|
|
*/
|
|
dbgprintf("klog:findnl_bkwd: Invalid MB sequence\n");
|
|
/*
|
|
* handle as a single byte character.
|
|
*/
|
|
p++;
|
|
rem--;
|
|
} else {
|
|
/*
|
|
* It's guaranteed that *p points to
|
|
* the 1st byte of a multibyte character.
|
|
*/
|
|
if (*p == '\n') {
|
|
nl = p;
|
|
}
|
|
p += mlen;
|
|
rem -= mlen;
|
|
}
|
|
}
|
|
if (nl) {
|
|
return ((size_t)(nl - buf));
|
|
}
|
|
/*
|
|
* no newline nor null byte found.
|
|
* Also it's guaranteed that *p points to
|
|
* the 1st byte of a (multibyte) character
|
|
* at this point.
|
|
*/
|
|
return (len - rem);
|
|
}
|
|
}
|
|
//___ end
|
|
|
|
|
|
/* Attempts to open the local log device
|
|
* and return a file descriptor.
|
|
*/
|
|
int
|
|
sun_openklog(char *name, int mode)
|
|
{
|
|
int fd;
|
|
struct strioctl str;
|
|
|
|
if ((fd = open(name, mode)) < 0) {
|
|
dbgprintf("klog:openklog: cannot open %s (%d)\n",
|
|
name, errno);
|
|
return (-1);
|
|
}
|
|
str.ic_cmd = I_CONSLOG;
|
|
str.ic_timout = 0;
|
|
str.ic_len = 0;
|
|
str.ic_dp = NULL;
|
|
if (ioctl(fd, I_STR, &str) < 0) {
|
|
dbgprintf("klog:openklog: cannot register to log "
|
|
"console messages (%d)\n", errno);
|
|
return (-1);
|
|
}
|
|
Pfd.fd = fd;
|
|
Pfd.events = POLLIN;
|
|
return (fd);
|
|
}
|
|
|
|
|
|
/*
|
|
* Pull up one message from log driver.
|
|
*/
|
|
void
|
|
sun_getkmsg()
|
|
{
|
|
int flags = 0, i;
|
|
char *lastline;
|
|
struct strbuf ctl, dat;
|
|
struct log_ctl hdr;
|
|
char buf[MAXLINE+1];
|
|
size_t buflen;
|
|
size_t len;
|
|
char tmpbuf[MAXLINE+1];
|
|
|
|
dat.maxlen = MAXLINE;
|
|
dat.buf = buf;
|
|
ctl.maxlen = sizeof (struct log_ctl);
|
|
ctl.buf = (caddr_t)&hdr;
|
|
|
|
while ((i = getmsg(Pfd.fd, &ctl, &dat, &flags)) == MOREDATA) {
|
|
lastline = &dat.buf[dat.len];
|
|
*lastline = '\0';
|
|
|
|
dbgprintf("klog:sys_poll: getmsg: dat.len = %d\n", dat.len);
|
|
buflen = strlen(buf);
|
|
len = findnl_bkwd(buf, buflen);
|
|
|
|
(void) memcpy(tmpbuf, buf, len);
|
|
tmpbuf[len] = '\0';
|
|
|
|
Syslog(LOG_INFO, (uchar*) buf);
|
|
|
|
if (len != buflen) {
|
|
/* If anything remains in buf */
|
|
size_t remlen;
|
|
|
|
if (buf[len] == '\n') {
|
|
/* skip newline */
|
|
len++;
|
|
}
|
|
|
|
/* Move the remaining bytes to
|
|
* the beginnning of buf.
|
|
*/
|
|
|
|
remlen = buflen - len;
|
|
(void) memcpy(buf, &buf[len], remlen);
|
|
dat.maxlen = MAXLINE - remlen;
|
|
dat.buf = &buf[remlen];
|
|
} else {
|
|
dat.maxlen = MAXLINE;
|
|
dat.buf = buf;
|
|
}
|
|
}
|
|
|
|
if (i == 0 && dat.len > 0) {
|
|
dat.buf[dat.len] = '\0';
|
|
/* Format sys will enqueue the log message.
|
|
* Set the sync flag if timeout != 0, which
|
|
* means that we're done handling all the
|
|
* initial messages ready during startup.
|
|
*/
|
|
dbgprintf("klog:getkmsg: getmsg: dat.maxlen = %d\n", dat.maxlen);
|
|
dbgprintf("klog:getkmsg: getmsg: dat.len = %d\n", dat.len);
|
|
dbgprintf("klog:getkmsg: getmsg: strlen(dat.buf) = %d\n", strlen(dat.buf));
|
|
dbgprintf("klog:getkmsg: getmsg: dat.buf = \"%s\"\n", dat.buf);
|
|
dbgprintf("klog:getkmsg: buf len = %d\n", strlen(buf));
|
|
Syslog(LOG_INFO, (uchar*) buf);
|
|
} else if (i < 0 && errno != EINTR) {
|
|
if(1){ /* V5-TODO: rsyslog-like termination! (!shutting_down) { */
|
|
dbgprintf("klog:kernel log driver read error");
|
|
}
|
|
// TODO trigger retry logic
|
|
//(void) close(Pfd.fd);
|
|
//Pfd.fd = -1;
|
|
}
|
|
}
|
|
|
|
|
|
/* this thread listens to the local stream log driver for log messages
|
|
* generated by this host, formats them, and queues them to the logger
|
|
* thread.
|
|
*/
|
|
/*ARGSUSED*/
|
|
void *
|
|
sun_sys_poll()
|
|
{
|
|
int nfds;
|
|
|
|
dbgprintf("klog:sys_poll: sys_thread started\n");
|
|
|
|
for (;;) {
|
|
errno = 0;
|
|
|
|
nfds = poll(&Pfd, 1, INFTIM);
|
|
|
|
if (nfds == 0)
|
|
continue;
|
|
|
|
if (nfds < 0) {
|
|
if (errno != EINTR)
|
|
dbgprintf("klog:poll error");
|
|
continue;
|
|
}
|
|
if (Pfd.revents & POLLIN) {
|
|
sun_getkmsg();
|
|
} else {
|
|
/* TODO: shutdown, the rsyslog way (in v5!) -- check shutdown flag */
|
|
if (Pfd.revents & (POLLNVAL|POLLHUP|POLLERR)) {
|
|
// TODO: trigger retry logic
|
|
/* logerror("kernel log driver poll error");
|
|
(void) close(Pfd.fd);
|
|
Pfd.fd = -1;
|
|
*/
|
|
}
|
|
}
|
|
|
|
}
|
|
/*NOTREACHED*/
|
|
return (NULL);
|
|
}
|