diff options
Diffstat (limited to 'plugins/imklog/solaris_cddl.c')
-rw-r--r-- | plugins/imklog/solaris_cddl.c | 293 |
1 files changed, 293 insertions, 0 deletions
diff --git a/plugins/imklog/solaris_cddl.c b/plugins/imklog/solaris_cddl.c new file mode 100644 index 00000000..7e86c68c --- /dev/null +++ b/plugins/imklog/solaris_cddl.c @@ -0,0 +1,293 @@ +/* + * 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); +} |