From 92369b253c302c7be30156b69b62f5ad90369cf0 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Thu, 25 Mar 2010 18:22:14 +0100 Subject: added some starting point for a solaris imklog driver ... far from being functional at this time! --- plugins/imklog/Makefile.am | 4 + plugins/imklog/solaris_cddl.c | 292 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 296 insertions(+) create mode 100644 plugins/imklog/solaris_cddl.c (limited to 'plugins/imklog') diff --git a/plugins/imklog/Makefile.am b/plugins/imklog/Makefile.am index 5d4d0465..85305ce3 100644 --- a/plugins/imklog/Makefile.am +++ b/plugins/imklog/Makefile.am @@ -11,6 +11,10 @@ if ENABLE_IMKLOG_LINUX imklog_la_SOURCES += linux.c module.h ksym.c ksyms.h ksym_mod.c endif +if ENABLE_IMKLOG_SOLARIS +imklog_la_SOURCES += solaris_cddl.c +endif + imklog_la_CPPFLAGS = -I$(top_srcdir) $(PTHREADS_CFLAGS) $(RSRT_CFLAGS) imklog_la_LDFLAGS = -module -avoid-version imklog_la_LIBADD = diff --git a/plugins/imklog/solaris_cddl.c b/plugins/imklog/solaris_cddl.c new file mode 100644 index 00000000..df783c46 --- /dev/null +++ b/plugins/imklog/solaris_cddl.c @@ -0,0 +1,292 @@ +/* + * 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" + + + +/* + * Attempts to open the local log device + * and return a file descriptor. + */ +int +sun_oopenklog(char *name, int mode) +{ + int fd; + struct strioctl str; + pthread_t mythreadno; + + if (Debug) { + mythreadno = pthread_self(); + } + + if ((fd = open(name, mode)) < 0) { + logerror("cannot open %s", name); + DPRINT3(1, "openklog(%u): cannot create %s (%d)\n", + mythreadno, 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) { + logerror("cannot register to log console messages"); + DPRINT2(1, "openklog(%u): cannot register to log " + "console messages (%d)\n", mythreadno, errno); + return (-1); + } + return (fd); +} + + +/* + * Open the log device, and pull up all pending messages. + */ +void +sun_prepare_sys_poll() +{ + int nfds, funix; + + if ((funix = openklog(LogName, O_RDONLY)) < 0) { + logerror("can't open kernel log device - fatal"); + exit(1); + } + + Pfd.fd = funix; + Pfd.events = POLLIN; + + for (;;) { + nfds = poll(&Pfd, 1, 0); + if (nfds <= 0) { + if (sys_init_msg_count > 0) + flushmsg(SYNC_FILE); + break; + } + + if (Pfd.revents & POLLIN) { + getkmsg(0); + } else if (Pfd.revents & (POLLNVAL|POLLHUP|POLLERR)) { + logerror("kernel log driver poll error"); + break; + } + } + +} + +/* + * 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(void *ap) +{ + int nfds; + static int klogerrs = 0; + pthread_t mythreadno; + + if (Debug) { + mythreadno = pthread_self(); + } + + DPRINT1(1, "sys_poll(%u): sys_thread started\n", mythreadno); + + /* + * Try to process as many messages as we can without blocking on poll. + * We count such "initial" messages with sys_init_msg_count and + * enqueue them without the SYNC_FILE flag. When no more data is + * waiting on the local log device, we set timeout to INFTIM, + * clear sys_init_msg_count, and generate a flush message to sync + * the previously counted initial messages out to disk. + */ + + sys_init_msg_count = 0; + + for (;;) { + errno = 0; + t_errno = 0; + + nfds = poll(&Pfd, 1, INFTIM); + + if (nfds == 0) + continue; + + if (nfds < 0) { + if (errno != EINTR) + logerror("poll"); + continue; + } + if (Pfd.revents & POLLIN) { + getkmsg(INFTIM); + } else { + if (shutting_down) { + pthread_exit(0); + } + if (Pfd.revents & (POLLNVAL|POLLHUP|POLLERR)) { + logerror("kernel log driver poll error"); + (void) close(Pfd.fd); + Pfd.fd = -1; + } + } + + while (Pfd.fd == -1 && klogerrs++ < 10) { + Pfd.fd = openklog(LogName, O_RDONLY); + } + if (klogerrs >= 10) { + logerror("can't reopen kernel log device - fatal"); + exit(1); + } + } + /*NOTREACHED*/ + return (NULL); +} + +/* + * Pull up one message from log driver. + */ +void +sun_getkmsg(int timeout) +{ + 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]; + pthread_t mythreadno; + + if (Debug) { + mythreadno = pthread_self(); + } + + 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'; + + DPRINT2(5, "sys_poll:(%u): getmsg: dat.len = %d\n", + mythreadno, dat.len); + buflen = strlen(buf); + len = findnl_bkwd(buf, buflen); + + (void) memcpy(tmpbuf, buf, len); + tmpbuf[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. + */ + if (timeout == 0) { + formatsys(&hdr, tmpbuf, 0); + sys_init_msg_count++; + } else { + formatsys(&hdr, tmpbuf, 1); + } + sys_msg_count++; + + 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. + */ + DPRINT2(5, "getkmsg(%u): getmsg: dat.maxlen = %d\n", + mythreadno, dat.maxlen); + DPRINT2(5, "getkmsg(%u): getmsg: dat.len = %d\n", + mythreadno, dat.len); + DPRINT2(5, "getkmsg(%u): getmsg: strlen(dat.buf) = %d\n", + mythreadno, strlen(dat.buf)); + DPRINT2(5, "getkmsg(%u): getmsg: dat.buf = \"%s\"\n", + mythreadno, dat.buf); + DPRINT2(5, "getkmsg(%u): buf len = %d\n", + mythreadno, strlen(buf)); + if (timeout == 0) { + formatsys(&hdr, buf, 0); + sys_init_msg_count++; + } else { + formatsys(&hdr, buf, 1); + } + sys_msg_count++; + } else if (i < 0 && errno != EINTR) { + if (!shutting_down) { + logerror("kernel log driver read error"); + } + (void) close(Pfd.fd); + Pfd.fd = -1; + } +} -- cgit From da65d88017e1824fe60574fef1ef83f1932ab0a6 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Thu, 25 Mar 2010 18:36:27 +0100 Subject: added forgotten file --- plugins/imklog/solaris.c | 545 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 545 insertions(+) create mode 100644 plugins/imklog/solaris.c (limited to 'plugins/imklog') diff --git a/plugins/imklog/solaris.c b/plugins/imklog/solaris.c new file mode 100644 index 00000000..97aead22 --- /dev/null +++ b/plugins/imklog/solaris.c @@ -0,0 +1,545 @@ +/* klog driver for solaris + * + * This contains OS-specific functionality to read the + * kernel log. For a general overview, see head comment in + * imklog.c. + * + * This file relies on Sun code in solaris_cddl.c. We have split + * it from Sun's code to keep the copyright issue as simple as possible. + * + * This file is part of rsyslog. + * + * Rsyslog is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * If that may be required, an exception is granted to permit linking + * this code to the code in solaris_cddl.c that is under the cddl license. + * + * Rsyslog is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Rsyslog. If not, see . + * + * A copy of the GPL can be found in the file "COPYING" in this distribution. + */ +#include "config.h" +#include "rsyslog.h" +#include +#include +#include +#include +#include +#include +#include "cfsysline.h" +#include "template.h" +#include "msg.h" +#include "module-template.h" +#include "imklog.h" +#include "unicode-helper.h" + + +/* Includes. */ +#include +#include +#include +#include + +#if HAVE_TIME_H +# include +#endif + +#include +#include +#include "ksyms.h" + +#define __LIBRARY__ +#include + + +#if !defined(__GLIBC__) +# define __NR_ksyslog __NR_syslog +_syscall3(int,ksyslog,int, type, char *, buf, int, len); +#else +#include +#define ksyslog klogctl +#endif + + + +#ifndef _PATH_KLOG +#define _PATH_KLOG "/proc/kmsg" +#endif + +#define LOG_BUFFER_SIZE 4096 +#define LOG_LINE_LENGTH 1000 + +static int kmsg; +static char log_buffer[LOG_BUFFER_SIZE]; + +static enum LOGSRC {none, proc, kernel} logsrc; + + +/* Function prototypes. */ +extern int ksyslog(int type, char *buf, int len); + + +static uchar *GetPath(void) +{ + return pszPath ? pszPath : UCHAR_CONSTANT(_PATH_KLOG); +} + +static void CloseLogSrc(void) +{ + /* Turn on logging of messages to console, but only if a log level was speficied */ + if(console_log_level != -1) + ksyslog(7, NULL, 0); + + /* Shutdown the log sources. */ + switch(logsrc) { + case kernel: + ksyslog(0, NULL, 0); + imklogLogIntMsg(LOG_INFO, "Kernel logging (ksyslog) stopped."); + break; + case proc: + close(kmsg); + imklogLogIntMsg(LOG_INFO, "Kernel logging (proc) stopped."); + break; + case none: + break; + } + + return; +} + + +static enum LOGSRC GetKernelLogSrc(void) +{ + auto struct stat sb; + + /* Set level of kernel console messaging.. */ + if ( (console_log_level != -1) && + (ksyslog(8, NULL, console_log_level) < 0) && + (errno == EINVAL) ) + { + /* + * An invalid arguement error probably indicates that + * a pre-0.14 kernel is being run. At this point we + * issue an error message and simply shut-off console + * logging completely. + */ + imklogLogIntMsg(LOG_WARNING, "Cannot set console log level - disabling " + "console output."); + } + + /* + * First do a stat to determine whether or not the proc based + * file system is available to get kernel messages from. + */ + if ( use_syscall || + ((stat((char*)GetPath(), &sb) < 0) && (errno == ENOENT)) ) + { + /* Initialize kernel logging. */ + ksyslog(1, NULL, 0); + imklogLogIntMsg(LOG_INFO, "imklog %s, log source = ksyslog " + "started.", VERSION); + return(kernel); + } + + if ( (kmsg = open((char*)GetPath(), O_RDONLY|O_CLOEXEC)) < 0 ) + { + imklogLogIntMsg(LOG_ERR, "imklog: Cannot open proc file system, %d.\n", errno); + ksyslog(7, NULL, 0); + return(none); + } + + imklogLogIntMsg(LOG_INFO, "imklog %s, log source = %s started.", VERSION, GetPath()); + return(proc); +} + + +/* Copy characters from ptr to line until a char in the delim + * string is encountered or until min( space, len ) chars have + * been copied. + * + * Returns the actual number of chars copied. + */ +static int copyin( uchar *line, int space, + const char *ptr, int len, + const char *delim ) +{ + auto int i; + auto int count; + + count = len < space ? len : space; + + for(i=0; i]", + * where "aaaaaa" is the address. These are replaced with + * "[symbolname+offset/size]" in the output line - symbolname, + * offset, and size come from the kernel symbol table. + * + * If a kernel symbol happens to fall at the end of a message close + * in length to LOG_LINE_LENGTH, the symbol will not be expanded. + * (This should never happen, since the kernel should never generate + * messages that long. + * + * To preserve the original addresses, lines containing kernel symbols + * are output twice. Once with the symbols converted and again with the + * original text. Just in case somebody wants to run their own Oops + * analysis on the syslog, e.g. ksymoops. + */ +static void LogLine(char *ptr, int len) +{ + enum parse_state_enum { + PARSING_TEXT, + PARSING_SYMSTART, /* at < */ + PARSING_SYMBOL, + PARSING_SYMEND /* at ] */ + }; + + static uchar line_buff[LOG_LINE_LENGTH]; + + static uchar *line =line_buff; + static enum parse_state_enum parse_state = PARSING_TEXT; + static int space = sizeof(line_buff)-1; + + static uchar *sym_start; /* points at the '<' of a symbol */ + + auto int delta = 0; /* number of chars copied */ + auto int symbols_expanded = 0; /* 1 if symbols were expanded */ + auto int skip_symbol_lookup = 0; /* skip symbol lookup on this pass */ + auto char *save_ptr = ptr; /* save start of input line */ + auto int save_len = len; /* save length at start of input line */ + + while( len > 0 ) + { + if( space == 0 ) /* line buffer is full */ + { + /* + ** Line too long. Start a new line. + */ + *line = 0; /* force null terminator */ + + //dbgprintf("Line buffer full:\n"); + //dbgprintf("\tLine: %s\n", line); + + Syslog(LOG_INFO, line_buff); + line = line_buff; + space = sizeof(line_buff)-1; + parse_state = PARSING_TEXT; + symbols_expanded = 0; + skip_symbol_lookup = 0; + save_ptr = ptr; + save_len = len; + } + + switch( parse_state ) + { + case PARSING_TEXT: + delta = copyin(line, space, ptr, len, "\n[" ); + line += delta; + ptr += delta; + space -= delta; + len -= delta; + + if( space == 0 || len == 0 ) + { + break; /* full line_buff or end of input buffer */ + } + + if( *ptr == '\0' ) /* zero byte */ + { + ptr++; /* skip zero byte */ + space -= 1; + len -= 1; + + break; + } + + if( *ptr == '\n' ) /* newline */ + { + ptr++; /* skip newline */ + space -= 1; + len -= 1; + + *line = 0; /* force null terminator */ + Syslog(LOG_INFO, line_buff); + line = line_buff; + space = sizeof(line_buff)-1; + if (symbols_twice) { + if (symbols_expanded) { + /* reprint this line without symbol lookup */ + symbols_expanded = 0; + skip_symbol_lookup = 1; + ptr = save_ptr; + len = save_len; + } + else + { + skip_symbol_lookup = 0; + save_ptr = ptr; + save_len = len; + } + } + break; + } + if( *ptr == '[' ) /* possible kernel symbol */ + { + *line++ = *ptr++; + space -= 1; + len -= 1; + if (!skip_symbol_lookup) + parse_state = PARSING_SYMSTART; /* at < */ + break; + } + /* Now that line_buff is no longer fed to *printf as format + * string, '%'s are no longer "dangerous". + */ + break; + + case PARSING_SYMSTART: + if( *ptr != '<' ) + { + parse_state = PARSING_TEXT; /* not a symbol */ + break; + } + + /* + ** Save this character for now. If this turns out to + ** be a valid symbol, this char will be replaced later. + ** If not, we'll just leave it there. + */ + + sym_start = line; /* this will point at the '<' */ + + *line++ = *ptr++; + space -= 1; + len -= 1; + parse_state = PARSING_SYMBOL; /* symbol... */ + break; + + case PARSING_SYMBOL: + delta = copyin( line, space, ptr, len, ">\n[" ); + line += delta; + ptr += delta; + space -= delta; + len -= delta; + if( space == 0 || len == 0 ) + { + break; /* full line_buff or end of input buffer */ + } + if( *ptr != '>' ) + { + parse_state = PARSING_TEXT; + break; + } + + *line++ = *ptr++; /* copy the '>' */ + space -= 1; + len -= 1; + + parse_state = PARSING_SYMEND; + + break; + + case PARSING_SYMEND: + if( *ptr != ']' ) + { + parse_state = PARSING_TEXT; /* not a symbol */ + break; + } + + /* + ** It's really a symbol! Replace address with the + ** symbol text. + */ + { + auto int sym_space; + + unsigned long value; + auto struct symbol sym; + auto char *symbol; + + *(line-1) = 0; /* null terminate the address string */ + value = strtoul((char*)(sym_start+1), (char **) 0, 16); + *(line-1) = '>'; /* put back delim */ + + if ( !symbol_lookup || (symbol = LookupSymbol(value, &sym)) == (char *)0 ) + { + parse_state = PARSING_TEXT; + break; + } + + /* + ** verify there is room in the line buffer + */ + sym_space = space + ( line - sym_start ); + if( (unsigned) sym_space < strlen(symbol) + 30 ) /*(30 should be overkill)*/ + { + parse_state = PARSING_TEXT; /* not enough space */ + break; + } + + // TODO: sprintf!!!! + delta = sprintf( (char*) sym_start, "%s+%d/%d]", + symbol, sym.offset, sym.size ); + + space = sym_space + delta; + line = sym_start + delta; + symbols_expanded = 1; + } + ptr++; + len--; + parse_state = PARSING_TEXT; + break; + + default: /* Can't get here! */ + parse_state = PARSING_TEXT; + + } + } + + return; +} + + +static void LogKernelLine(void) +{ + auto int rdcnt; + + /* + * Zero-fill the log buffer. This should cure a multitude of + * problems with klogd logging the tail end of the message buffer + * which will contain old messages. Then read the kernel log + * messages into this fresh buffer. + */ + memset(log_buffer, '\0', sizeof(log_buffer)); + if ( (rdcnt = ksyslog(2, log_buffer, sizeof(log_buffer)-1)) < 0 ) + { + if(errno == EINTR) + return; + imklogLogIntMsg(LOG_ERR, "imklog Error return from sys_sycall: %d\n", errno); + } + else + LogLine(log_buffer, rdcnt); + return; +} + + +static void LogProcLine(void) +{ + auto int rdcnt; + + /* + * Zero-fill the log buffer. This should cure a multitude of + * problems with klogd logging the tail end of the message buffer + * which will contain old messages. Then read the kernel messages + * from the message pseudo-file into this fresh buffer. + */ + memset(log_buffer, '\0', sizeof(log_buffer)); + if ( (rdcnt = read(kmsg, log_buffer, sizeof(log_buffer)-1)) < 0 ) { + if ( errno == EINTR ) + return; + imklogLogIntMsg(LOG_ERR, "Cannot read proc file system: %d - %s.", errno, strerror(errno)); + } else { + LogLine(log_buffer, rdcnt); + } + + return; +} + + +/* to be called in the module's WillRun entry point + * rgerhards, 2008-04-09 + */ +rsRetVal klogLogKMsg(void) +{ + DEFiRet; + switch(logsrc) { + case kernel: + LogKernelLine(); + break; + case proc: + LogProcLine(); + break; + case none: + /* TODO: We need to handle this case here somewhat more intelligent + * This is now at least partly done - code should never reach this point + * as willRun() already checked for the "none" status -- rgerhards, 2007-12-17 + */ + pause(); + break; + } + RETiRet; +} + + +/* to be called in the module's WillRun entry point + * rgerhards, 2008-04-09 + */ +rsRetVal klogWillRun(void) +{ + DEFiRet; + /* Initialize this module. If that fails, we tell the engine we don't like to run */ + /* Determine where kernel logging information is to come from. */ + logsrc = GetKernelLogSrc(); + if(logsrc == none) { + iRet = RS_RET_NO_KERNEL_LOGSRC; + } else { + if (symbol_lookup) { + symbol_lookup = (InitKsyms(symfile) == 1); + symbol_lookup |= InitMsyms(); + if (symbol_lookup == 0) { + imklogLogIntMsg(LOG_WARNING, "cannot find any symbols, turning off symbol lookups"); + } + } + } + + RETiRet; +} + + +/* to be called in the module's AfterRun entry point + * rgerhards, 2008-04-09 + */ +rsRetVal klogAfterRun(void) +{ + DEFiRet; + /* cleanup here */ + if(logsrc != none) + CloseLogSrc(); + + DeinitKsyms(); + DeinitMsyms(); + + RETiRet; +} + + +/* provide the (system-specific) default facility for internal messages + * rgerhards, 2008-04-14 + */ +int +klogFacilIntMsg(void) +{ + return LOG_KERN; +} + + +/* vi:set ai: + */ -- cgit From ee6ce30b474c033c71f5f5e9edf7941e29ea30b6 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Fri, 26 Mar 2010 09:14:31 +0100 Subject: interim commit: imklog/solaris compiles, but does not work saving this area of work, because some further clarification is needed. Do not try to run the current imklog, it will fail. --- plugins/imklog/Makefile.am | 2 +- plugins/imklog/solaris.c | 589 ++++++++++-------------------------------- plugins/imklog/solaris_cddl.c | 402 +++++++++++++++++----------- 3 files changed, 389 insertions(+), 604 deletions(-) (limited to 'plugins/imklog') diff --git a/plugins/imklog/Makefile.am b/plugins/imklog/Makefile.am index 85305ce3..06d4013c 100644 --- a/plugins/imklog/Makefile.am +++ b/plugins/imklog/Makefile.am @@ -12,7 +12,7 @@ imklog_la_SOURCES += linux.c module.h ksym.c ksyms.h ksym_mod.c endif if ENABLE_IMKLOG_SOLARIS -imklog_la_SOURCES += solaris_cddl.c +imklog_la_SOURCES += solaris.c solaris_cddl.c endif imklog_la_CPPFLAGS = -I$(top_srcdir) $(PTHREADS_CFLAGS) $(RSRT_CFLAGS) diff --git a/plugins/imklog/solaris.c b/plugins/imklog/solaris.c index 97aead22..294efa7c 100644 --- a/plugins/imklog/solaris.c +++ b/plugins/imklog/solaris.c @@ -27,507 +27,181 @@ * * A copy of the GPL can be found in the file "COPYING" in this distribution. */ -#include "config.h" -#include "rsyslog.h" -#include -#include -#include -#include -#include -#include -#include "cfsysline.h" -#include "template.h" -#include "msg.h" -#include "module-template.h" -#include "imklog.h" -#include "unicode-helper.h" - - -/* Includes. */ -#include -#include -#include -#include -#if HAVE_TIME_H -# include +#ifdef HAVE_CONFIG_H +# include "config.h" #endif - -#include -#include -#include "ksyms.h" - -#define __LIBRARY__ +#include #include +#include +#include +#include +#include -#if !defined(__GLIBC__) -# define __NR_ksyslog __NR_syslog -_syscall3(int,ksyslog,int, type, char *, buf, int, len); -#else -#include -#define ksyslog klogctl -#endif - +#include "rsyslog.h" +#include "imklog.h" +#include "unicode-helper.h" +#include "solaris_cddl.h" +/* globals */ +static int fklog; // TODO: remove #ifndef _PATH_KLOG -#define _PATH_KLOG "/proc/kmsg" +# define _PATH_KLOG "/dev/log" #endif -#define LOG_BUFFER_SIZE 4096 -#define LOG_LINE_LENGTH 1000 - -static int kmsg; -static char log_buffer[LOG_BUFFER_SIZE]; - -static enum LOGSRC {none, proc, kernel} logsrc; - - -/* Function prototypes. */ -extern int ksyslog(int type, char *buf, int len); - - -static uchar *GetPath(void) -{ - return pszPath ? pszPath : UCHAR_CONSTANT(_PATH_KLOG); -} - -static void CloseLogSrc(void) -{ - /* Turn on logging of messages to console, but only if a log level was speficied */ - if(console_log_level != -1) - ksyslog(7, NULL, 0); - - /* Shutdown the log sources. */ - switch(logsrc) { - case kernel: - ksyslog(0, NULL, 0); - imklogLogIntMsg(LOG_INFO, "Kernel logging (ksyslog) stopped."); - break; - case proc: - close(kmsg); - imklogLogIntMsg(LOG_INFO, "Kernel logging (proc) stopped."); - break; - case none: - break; - } - - return; -} - +// HELPER +/* handle some defines missing on more than one platform */ +#ifndef SUN_LEN +#define SUN_LEN(su) \ + (sizeof(*(su)) - sizeof((su)->sun_path) + strlen((su)->sun_path)) +#endif -static enum LOGSRC GetKernelLogSrc(void) +int solaris_create_unix_socket(const char *path) { - auto struct stat sb; - - /* Set level of kernel console messaging.. */ - if ( (console_log_level != -1) && - (ksyslog(8, NULL, console_log_level) < 0) && - (errno == EINVAL) ) - { - /* - * An invalid arguement error probably indicates that - * a pre-0.14 kernel is being run. At this point we - * issue an error message and simply shut-off console - * logging completely. - */ - imklogLogIntMsg(LOG_WARNING, "Cannot set console log level - disabling " - "console output."); - } - - /* - * First do a stat to determine whether or not the proc based - * file system is available to get kernel messages from. - */ - if ( use_syscall || - ((stat((char*)GetPath(), &sb) < 0) && (errno == ENOENT)) ) - { - /* Initialize kernel logging. */ - ksyslog(1, NULL, 0); - imklogLogIntMsg(LOG_INFO, "imklog %s, log source = ksyslog " - "started.", VERSION); - return(kernel); - } - - if ( (kmsg = open((char*)GetPath(), O_RDONLY|O_CLOEXEC)) < 0 ) - { - imklogLogIntMsg(LOG_ERR, "imklog: Cannot open proc file system, %d.\n", errno); - ksyslog(7, NULL, 0); - return(none); + struct sockaddr_un sunx; + int fd; + +return; + if (path[0] == '\0') + return -1; + + unlink(path); + + memset(&sunx, 0, sizeof(sunx)); + sunx.sun_family = AF_UNIX; + (void) strncpy(sunx.sun_path, path, sizeof(sunx.sun_path)); + fd = socket(AF_UNIX, SOCK_DGRAM, 0); + if (fd < 0 || bind(fd, (struct sockaddr *) &sunx, SUN_LEN(&sunx)) < 0 || + chmod(path, 0666) < 0) { + //errmsg.LogError(errno, NO_ERRCODE, "connot create '%s'", path); + dbgprintf("cannot create %s (%d).\n", path, errno); + close(fd); + return -1; } - - imklogLogIntMsg(LOG_INFO, "imklog %s, log source = %s started.", VERSION, GetPath()); - return(proc); + return fd; } +// END HELPER -/* Copy characters from ptr to line until a char in the delim - * string is encountered or until min( space, len ) chars have - * been copied. - * - * Returns the actual number of chars copied. - */ -static int copyin( uchar *line, int space, - const char *ptr, int len, - const char *delim ) +static uchar *GetPath(void) { - auto int i; - auto int count; - - count = len < space ? len : space; - - for(i=0; i]", - * where "aaaaaa" is the address. These are replaced with - * "[symbolname+offset/size]" in the output line - symbolname, - * offset, and size come from the kernel symbol table. - * - * If a kernel symbol happens to fall at the end of a message close - * in length to LOG_LINE_LENGTH, the symbol will not be expanded. - * (This should never happen, since the kernel should never generate - * messages that long. - * - * To preserve the original addresses, lines containing kernel symbols - * are output twice. Once with the symbols converted and again with the - * original text. Just in case somebody wants to run their own Oops - * analysis on the syslog, e.g. ksymoops. +/* open the kernel log - will be called inside the willRun() imklog + * entry point. -- rgerhards, 2008-04-09 */ -static void LogLine(char *ptr, int len) -{ - enum parse_state_enum { - PARSING_TEXT, - PARSING_SYMSTART, /* at < */ - PARSING_SYMBOL, - PARSING_SYMEND /* at ] */ - }; - - static uchar line_buff[LOG_LINE_LENGTH]; - - static uchar *line =line_buff; - static enum parse_state_enum parse_state = PARSING_TEXT; - static int space = sizeof(line_buff)-1; - - static uchar *sym_start; /* points at the '<' of a symbol */ - - auto int delta = 0; /* number of chars copied */ - auto int symbols_expanded = 0; /* 1 if symbols were expanded */ - auto int skip_symbol_lookup = 0; /* skip symbol lookup on this pass */ - auto char *save_ptr = ptr; /* save start of input line */ - auto int save_len = len; /* save length at start of input line */ - - while( len > 0 ) - { - if( space == 0 ) /* line buffer is full */ - { - /* - ** Line too long. Start a new line. - */ - *line = 0; /* force null terminator */ - - //dbgprintf("Line buffer full:\n"); - //dbgprintf("\tLine: %s\n", line); - - Syslog(LOG_INFO, line_buff); - line = line_buff; - space = sizeof(line_buff)-1; - parse_state = PARSING_TEXT; - symbols_expanded = 0; - skip_symbol_lookup = 0; - save_ptr = ptr; - save_len = len; - } - - switch( parse_state ) - { - case PARSING_TEXT: - delta = copyin(line, space, ptr, len, "\n[" ); - line += delta; - ptr += delta; - space -= delta; - len -= delta; - - if( space == 0 || len == 0 ) - { - break; /* full line_buff or end of input buffer */ - } - - if( *ptr == '\0' ) /* zero byte */ - { - ptr++; /* skip zero byte */ - space -= 1; - len -= 1; - - break; - } - - if( *ptr == '\n' ) /* newline */ - { - ptr++; /* skip newline */ - space -= 1; - len -= 1; - - *line = 0; /* force null terminator */ - Syslog(LOG_INFO, line_buff); - line = line_buff; - space = sizeof(line_buff)-1; - if (symbols_twice) { - if (symbols_expanded) { - /* reprint this line without symbol lookup */ - symbols_expanded = 0; - skip_symbol_lookup = 1; - ptr = save_ptr; - len = save_len; - } - else - { - skip_symbol_lookup = 0; - save_ptr = ptr; - save_len = len; - } - } - break; - } - if( *ptr == '[' ) /* possible kernel symbol */ - { - *line++ = *ptr++; - space -= 1; - len -= 1; - if (!skip_symbol_lookup) - parse_state = PARSING_SYMSTART; /* at < */ - break; - } - /* Now that line_buff is no longer fed to *printf as format - * string, '%'s are no longer "dangerous". - */ - break; - - case PARSING_SYMSTART: - if( *ptr != '<' ) - { - parse_state = PARSING_TEXT; /* not a symbol */ - break; - } - - /* - ** Save this character for now. If this turns out to - ** be a valid symbol, this char will be replaced later. - ** If not, we'll just leave it there. - */ - - sym_start = line; /* this will point at the '<' */ - - *line++ = *ptr++; - space -= 1; - len -= 1; - parse_state = PARSING_SYMBOL; /* symbol... */ - break; - - case PARSING_SYMBOL: - delta = copyin( line, space, ptr, len, ">\n[" ); - line += delta; - ptr += delta; - space -= delta; - len -= delta; - if( space == 0 || len == 0 ) - { - break; /* full line_buff or end of input buffer */ - } - if( *ptr != '>' ) - { - parse_state = PARSING_TEXT; - break; - } - - *line++ = *ptr++; /* copy the '>' */ - space -= 1; - len -= 1; - - parse_state = PARSING_SYMEND; - - break; - - case PARSING_SYMEND: - if( *ptr != ']' ) - { - parse_state = PARSING_TEXT; /* not a symbol */ - break; - } - - /* - ** It's really a symbol! Replace address with the - ** symbol text. - */ - { - auto int sym_space; - - unsigned long value; - auto struct symbol sym; - auto char *symbol; - - *(line-1) = 0; /* null terminate the address string */ - value = strtoul((char*)(sym_start+1), (char **) 0, 16); - *(line-1) = '>'; /* put back delim */ - - if ( !symbol_lookup || (symbol = LookupSymbol(value, &sym)) == (char *)0 ) - { - parse_state = PARSING_TEXT; - break; - } - - /* - ** verify there is room in the line buffer - */ - sym_space = space + ( line - sym_start ); - if( (unsigned) sym_space < strlen(symbol) + 30 ) /*(30 should be overkill)*/ - { - parse_state = PARSING_TEXT; /* not enough space */ - break; - } - - // TODO: sprintf!!!! - delta = sprintf( (char*) sym_start, "%s+%d/%d]", - symbol, sym.offset, sym.size ); - - space = sym_space + delta; - line = sym_start + delta; - symbols_expanded = 1; - } - ptr++; - len--; - parse_state = PARSING_TEXT; - break; - - default: /* Can't get here! */ - parse_state = PARSING_TEXT; - - } - } - - return; -} - - -static void LogKernelLine(void) +rsRetVal +klogWillRun(void) { - auto int rdcnt; - - /* - * Zero-fill the log buffer. This should cure a multitude of - * problems with klogd logging the tail end of the message buffer - * which will contain old messages. Then read the kernel log - * messages into this fresh buffer. - */ - memset(log_buffer, '\0', sizeof(log_buffer)); - if ( (rdcnt = ksyslog(2, log_buffer, sizeof(log_buffer)-1)) < 0 ) - { - if(errno == EINTR) - return; - imklogLogIntMsg(LOG_ERR, "imklog Error return from sys_sycall: %d\n", errno); + DEFiRet; + + fklog = sun_openklog((char*) GetPath(), O_RDONLY); + if (fklog < 0) { + char errStr[1024]; + int err = errno; +perror("XXX"); + rs_strerror_r(err, errStr, sizeof(errStr)); + DBGPRINTF("error %d opening log socket %s: %s\n", + GetPath(), errStr); + iRet = RS_RET_ERR; // TODO: better error code } - else - LogLine(log_buffer, rdcnt); - return; + + RETiRet; } -static void LogProcLine(void) +/* Read /dev/klog while data are available, split into lines. + * Contrary to standard BSD syslogd, we do a blocking read. We can + * afford this as imklog is running on its own threads. So if we have + * a single file, it really doesn't matter if we wait inside a 1-file + * select or the read() directly. + */ +static void +readklog(void) { - auto int rdcnt; - - /* - * Zero-fill the log buffer. This should cure a multitude of - * problems with klogd logging the tail end of the message buffer - * which will contain old messages. Then read the kernel messages - * from the message pseudo-file into this fresh buffer. + char *p, *q; + int len, i; + int iMaxLine; + uchar bufRcv[4096+1]; + uchar *pRcv = NULL; /* receive buffer */ + + iMaxLine = klog_getMaxLine(); + + /* we optimize performance: if iMaxLine is below 4K (which it is in almost all + * cases, we use a fixed buffer on the stack. Only if it is higher, heap memory + * is used. We could use alloca() to achive a similar aspect, but there are so + * many issues with alloca() that I do not want to take that route. + * rgerhards, 2008-09-02 */ - memset(log_buffer, '\0', sizeof(log_buffer)); - if ( (rdcnt = read(kmsg, log_buffer, sizeof(log_buffer)-1)) < 0 ) { - if ( errno == EINTR ) - return; - imklogLogIntMsg(LOG_ERR, "Cannot read proc file system: %d - %s.", errno, strerror(errno)); + if((size_t) iMaxLine < sizeof(bufRcv) - 1) { + pRcv = bufRcv; } else { - LogLine(log_buffer, rdcnt); - } + if((pRcv = (uchar*) malloc(sizeof(uchar) * (iMaxLine + 1))) == NULL) + iMaxLine = sizeof(bufRcv) - 1; /* better this than noting */ + } - return; -} + len = 0; + for (;;) { + dbgprintf("----------imklog(BSD) waiting for kernel log line\n"); + i = read(fklog, pRcv + len, iMaxLine - len); + if (i > 0) { + pRcv[i + len] = '\0'; + } else { + if (i < 0 && errno != EINTR && errno != EAGAIN) { + imklogLogIntMsg(LOG_ERR, + "imklog error %d reading kernel log - shutting down imklog", + errno); + fklog = -1; + } + break; + } + for (p = pRcv; (q = strchr(p, '\n')) != NULL; p = q + 1) { + *q = '\0'; + Syslog(LOG_INFO, (uchar*) p); + } + len = strlen(p); + if (len >= iMaxLine - 1) { + Syslog(LOG_INFO, (uchar*)p); + len = 0; + } + if (len > 0) + memmove(pRcv, p, len + 1); + } + if (len > 0) + Syslog(LOG_INFO, pRcv); -/* to be called in the module's WillRun entry point - * rgerhards, 2008-04-09 - */ -rsRetVal klogLogKMsg(void) -{ - DEFiRet; - switch(logsrc) { - case kernel: - LogKernelLine(); - break; - case proc: - LogProcLine(); - break; - case none: - /* TODO: We need to handle this case here somewhat more intelligent - * This is now at least partly done - code should never reach this point - * as willRun() already checked for the "none" status -- rgerhards, 2007-12-17 - */ - pause(); - break; - } - RETiRet; + if(pRcv != NULL && (size_t) iMaxLine >= sizeof(bufRcv) - 1) + free(pRcv); } -/* to be called in the module's WillRun entry point +/* to be called in the module's AfterRun entry point * rgerhards, 2008-04-09 */ -rsRetVal klogWillRun(void) +rsRetVal klogAfterRun(void) { DEFiRet; - /* Initialize this module. If that fails, we tell the engine we don't like to run */ - /* Determine where kernel logging information is to come from. */ - logsrc = GetKernelLogSrc(); - if(logsrc == none) { - iRet = RS_RET_NO_KERNEL_LOGSRC; - } else { - if (symbol_lookup) { - symbol_lookup = (InitKsyms(symfile) == 1); - symbol_lookup |= InitMsyms(); - if (symbol_lookup == 0) { - imklogLogIntMsg(LOG_WARNING, "cannot find any symbols, turning off symbol lookups"); - } - } - } - + if(fklog != -1) + close(fklog); RETiRet; } -/* to be called in the module's AfterRun entry point + +/* to be called in the module's WillRun entry point, this is the main + * "message pull" mechanism. * rgerhards, 2008-04-09 */ -rsRetVal klogAfterRun(void) +rsRetVal klogLogKMsg(void) { DEFiRet; - /* cleanup here */ - if(logsrc != none) - CloseLogSrc(); - - DeinitKsyms(); - DeinitMsyms(); - - RETiRet; + sun_sys_poll(); + //readklog(); + RETiRet; } @@ -537,9 +211,6 @@ rsRetVal klogAfterRun(void) int klogFacilIntMsg(void) { - return LOG_KERN; + return LOG_SYSLOG; } - -/* vi:set ai: - */ diff --git a/plugins/imklog/solaris_cddl.c b/plugins/imklog/solaris_cddl.c index df783c46..f45c5e62 100644 --- a/plugins/imklog/solaris_cddl.c +++ b/plugins/imklog/solaris_cddl.c @@ -1,3 +1,4 @@ +#define MAXLINE 4096 /* * CDDL HEADER START * @@ -41,28 +42,153 @@ */ #include "config.h" +#include +#include +#include +#include +#include + +//--------- +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +//-------- + + +#include "rsyslog.h" + +static struct pollfd Pfd; /* Pollfd for local the log device */ + /* - * Attempts to open the local log device - * and return a file descriptor. + * 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 */ -int -sun_oopenklog(char *name, int mode) +size_t +findnl_bkwd(const char *buf, const size_t len) { - int fd; - struct strioctl str; + const char *p; + size_t mb_cur_max; pthread_t mythreadno; if (Debug) { mythreadno = pthread_self(); } + 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("findnl_bkwd(%u): Invalid MB " + "sequence\n", mythreadno); + /* + * 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; + + solaris_create_unix_socket(name); if ((fd = open(name, mode)) < 0) { - logerror("cannot open %s", name); - DPRINT3(1, "openklog(%u): cannot create %s (%d)\n", - mythreadno, name, errno); + //logerror("cannot open %s", name); + dbgprintf("openklog: cannot open %s (%d)\n", + name, errno); return (-1); } str.ic_cmd = I_CONSLOG; @@ -70,15 +196,114 @@ sun_oopenklog(char *name, int mode) str.ic_len = 0; str.ic_dp = NULL; if (ioctl(fd, I_STR, &str) < 0) { - logerror("cannot register to log console messages"); - DPRINT2(1, "openklog(%u): cannot register to log " - "console messages (%d)\n", mythreadno, errno); + //logerror("cannot register to log console messages"); + dbgprintf("openklog: cannot register to log " + "console messages (%d)\n", errno); return (-1); } + Pfd.fd = fd; return (fd); } +/* + * Pull up one message from log driver. + */ +void +sun_getkmsg(int timeout) +{ + 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("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'; + + /* 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. + */ + Syslog(LOG_INFO, buf); + /*if (timeout == 0) { + formatsys(&hdr, tmpbuf, 0); + //sys_init_msg_count++; + } else { + formatsys(&hdr, tmpbuf, 1); + }*/ + + 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("getkmsg: getmsg: dat.maxlen = %d\n", dat.maxlen); + dbgprintf("getkmsg: getmsg: dat.len = %d\n", dat.len); + dbgprintf("getkmsg: getmsg: strlen(dat.buf) = %d\n", strlen(dat.buf)); + dbgprintf("getkmsg: getmsg: dat.buf = \"%s\"\n", dat.buf); + dbgprintf("getkmsg: buf len = %d\n", strlen(buf)); + //if (timeout == 0) { + //formatsys(&hdr, buf, 0); + //--sys_init_msg_count++; + //} else { + //formatsys(&hdr, buf, 1); + //} + Syslog(LOG_INFO, buf); + } else if (i < 0 && errno != EINTR) { + if(1){ // (!shutting_down) { + dbgprintf("kernel log driver read error"); + } + // TODO trigger retry logic + //(void) close(Pfd.fd); + //Pfd.fd = -1; + } +} + + /* * Open the log device, and pull up all pending messages. */ @@ -87,26 +312,30 @@ sun_prepare_sys_poll() { int nfds, funix; - if ((funix = openklog(LogName, O_RDONLY)) < 0) { +/* + if ((funix = sun_openklog(LogName, O_RDONLY)) < 0) { logerror("can't open kernel log device - fatal"); exit(1); } +*/ Pfd.fd = funix; Pfd.events = POLLIN; for (;;) { nfds = poll(&Pfd, 1, 0); + /* if (nfds <= 0) { if (sys_init_msg_count > 0) flushmsg(SYNC_FILE); break; - } + }*/ if (Pfd.revents & POLLIN) { - getkmsg(0); + sun_getkmsg(0); } else if (Pfd.revents & (POLLNVAL|POLLHUP|POLLERR)) { - logerror("kernel log driver poll error"); + //logerror("kernel log driver poll error"); + dbgprintf("kernel log driver poll error"); break; } } @@ -123,14 +352,8 @@ void * sun_sys_poll(void *ap) { int nfds; - static int klogerrs = 0; - pthread_t mythreadno; - - if (Debug) { - mythreadno = pthread_self(); - } - DPRINT1(1, "sys_poll(%u): sys_thread started\n", mythreadno); + dbgprintf("sys_poll: sys_thread started\n"); /* * Try to process as many messages as we can without blocking on poll. @@ -141,11 +364,8 @@ sun_sys_poll(void *ap) * the previously counted initial messages out to disk. */ - sys_init_msg_count = 0; - for (;;) { errno = 0; - t_errno = 0; nfds = poll(&Pfd, 1, INFTIM); @@ -154,139 +374,33 @@ sun_sys_poll(void *ap) if (nfds < 0) { if (errno != EINTR) - logerror("poll"); + dbgprintf("poll error");// logerror("poll"); continue; } if (Pfd.revents & POLLIN) { - getkmsg(INFTIM); + sun_getkmsg(INFTIM); } else { - if (shutting_down) { - pthread_exit(0); - } + // TODO: shutdown, the rsyslog way + //if (shutting_down) { + //pthread_exit(0); + //} if (Pfd.revents & (POLLNVAL|POLLHUP|POLLERR)) { - logerror("kernel log driver poll error"); + // TODO: trigger retry logic +/* logerror("kernel log driver poll error"); (void) close(Pfd.fd); Pfd.fd = -1; + */ } } - while (Pfd.fd == -1 && klogerrs++ < 10) { - Pfd.fd = openklog(LogName, O_RDONLY); +/* while (Pfd.fd == -1 && klogerrs++ < 10) { + Pfd.fd = sun_openklog(LogName, O_RDONLY); } if (klogerrs >= 10) { logerror("can't reopen kernel log device - fatal"); exit(1); - } + }*/ } /*NOTREACHED*/ return (NULL); } - -/* - * Pull up one message from log driver. - */ -void -sun_getkmsg(int timeout) -{ - 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]; - pthread_t mythreadno; - - if (Debug) { - mythreadno = pthread_self(); - } - - 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'; - - DPRINT2(5, "sys_poll:(%u): getmsg: dat.len = %d\n", - mythreadno, dat.len); - buflen = strlen(buf); - len = findnl_bkwd(buf, buflen); - - (void) memcpy(tmpbuf, buf, len); - tmpbuf[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. - */ - if (timeout == 0) { - formatsys(&hdr, tmpbuf, 0); - sys_init_msg_count++; - } else { - formatsys(&hdr, tmpbuf, 1); - } - sys_msg_count++; - - 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. - */ - DPRINT2(5, "getkmsg(%u): getmsg: dat.maxlen = %d\n", - mythreadno, dat.maxlen); - DPRINT2(5, "getkmsg(%u): getmsg: dat.len = %d\n", - mythreadno, dat.len); - DPRINT2(5, "getkmsg(%u): getmsg: strlen(dat.buf) = %d\n", - mythreadno, strlen(dat.buf)); - DPRINT2(5, "getkmsg(%u): getmsg: dat.buf = \"%s\"\n", - mythreadno, dat.buf); - DPRINT2(5, "getkmsg(%u): buf len = %d\n", - mythreadno, strlen(buf)); - if (timeout == 0) { - formatsys(&hdr, buf, 0); - sys_init_msg_count++; - } else { - formatsys(&hdr, buf, 1); - } - sys_msg_count++; - } else if (i < 0 && errno != EINTR) { - if (!shutting_down) { - logerror("kernel log driver read error"); - } - (void) close(Pfd.fd); - Pfd.fd = -1; - } -} -- cgit From 91a5e176d609d77d4451d7d7b1bf00dfdac5fe50 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Fri, 26 Mar 2010 15:49:39 +0100 Subject: added initial files for door support & fixed imklog imklog now basically works, but needs quite some more work to do --- plugins/imklog/solaris.c | 35 +---------------------------------- plugins/imklog/solaris_cddl.c | 33 +++++++++++++++++++-------------- 2 files changed, 20 insertions(+), 48 deletions(-) (limited to 'plugins/imklog') diff --git a/plugins/imklog/solaris.c b/plugins/imklog/solaris.c index 294efa7c..a0e85dc7 100644 --- a/plugins/imklog/solaris.c +++ b/plugins/imklog/solaris.c @@ -51,39 +51,6 @@ static int fklog; // TODO: remove # define _PATH_KLOG "/dev/log" #endif -// HELPER -/* handle some defines missing on more than one platform */ -#ifndef SUN_LEN -#define SUN_LEN(su) \ - (sizeof(*(su)) - sizeof((su)->sun_path) + strlen((su)->sun_path)) -#endif - -int solaris_create_unix_socket(const char *path) -{ - struct sockaddr_un sunx; - int fd; - -return; - if (path[0] == '\0') - return -1; - - unlink(path); - - memset(&sunx, 0, sizeof(sunx)); - sunx.sun_family = AF_UNIX; - (void) strncpy(sunx.sun_path, path, sizeof(sunx.sun_path)); - fd = socket(AF_UNIX, SOCK_DGRAM, 0); - if (fd < 0 || bind(fd, (struct sockaddr *) &sunx, SUN_LEN(&sunx)) < 0 || - chmod(path, 0666) < 0) { - //errmsg.LogError(errno, NO_ERRCODE, "connot create '%s'", path); - dbgprintf("cannot create %s (%d).\n", path, errno); - close(fd); - return -1; - } - return fd; -} -// END HELPER - static uchar *GetPath(void) { @@ -104,7 +71,7 @@ klogWillRun(void) int err = errno; perror("XXX"); rs_strerror_r(err, errStr, sizeof(errStr)); - DBGPRINTF("error %d opening log socket %s: %s\n", + DBGPRINTF("error %d opening log socket: %s\n", GetPath(), errStr); iRet = RS_RET_ERR; // TODO: better error code } diff --git a/plugins/imklog/solaris_cddl.c b/plugins/imklog/solaris_cddl.c index f45c5e62..700e0ab3 100644 --- a/plugins/imklog/solaris_cddl.c +++ b/plugins/imklog/solaris_cddl.c @@ -141,7 +141,7 @@ findnl_bkwd(const char *buf, const size_t len) /* * Invalid character found. */ - dbgprintf("findnl_bkwd(%u): Invalid MB " + dbgprintf("klog:findnl_bkwd(%u): Invalid MB " "sequence\n", mythreadno); /* * handle as a single byte character. @@ -184,10 +184,9 @@ sun_openklog(char *name, int mode) int fd; struct strioctl str; - solaris_create_unix_socket(name); if ((fd = open(name, mode)) < 0) { //logerror("cannot open %s", name); - dbgprintf("openklog: cannot open %s (%d)\n", + dbgprintf("klog:openklog: cannot open %s (%d)\n", name, errno); return (-1); } @@ -197,11 +196,12 @@ sun_openklog(char *name, int mode) str.ic_dp = NULL; if (ioctl(fd, I_STR, &str) < 0) { //logerror("cannot register to log console messages"); - dbgprintf("openklog: cannot register to log " + dbgprintf("klog:openklog: cannot register to log " "console messages (%d)\n", errno); return (-1); } Pfd.fd = fd; + Pfd.events = POLLIN; return (fd); } @@ -230,7 +230,7 @@ sun_getkmsg(int timeout) lastline = &dat.buf[dat.len]; *lastline = '\0'; - dbgprintf("sys_poll: getmsg: dat.len = %d\n", dat.len); + dbgprintf("klog:sys_poll: getmsg: dat.len = %d\n", dat.len); buflen = strlen(buf); len = findnl_bkwd(buf, buflen); @@ -281,11 +281,11 @@ sun_getkmsg(int timeout) * means that we're done handling all the * initial messages ready during startup. */ - dbgprintf("getkmsg: getmsg: dat.maxlen = %d\n", dat.maxlen); - dbgprintf("getkmsg: getmsg: dat.len = %d\n", dat.len); - dbgprintf("getkmsg: getmsg: strlen(dat.buf) = %d\n", strlen(dat.buf)); - dbgprintf("getkmsg: getmsg: dat.buf = \"%s\"\n", dat.buf); - dbgprintf("getkmsg: buf len = %d\n", strlen(buf)); + 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)); //if (timeout == 0) { //formatsys(&hdr, buf, 0); //--sys_init_msg_count++; @@ -295,7 +295,7 @@ sun_getkmsg(int timeout) Syslog(LOG_INFO, buf); } else if (i < 0 && errno != EINTR) { if(1){ // (!shutting_down) { - dbgprintf("kernel log driver read error"); + dbgprintf("klog:kernel log driver read error"); } // TODO trigger retry logic //(void) close(Pfd.fd); @@ -304,6 +304,7 @@ sun_getkmsg(int timeout) } +#if 0 /* * Open the log device, and pull up all pending messages. */ @@ -335,12 +336,14 @@ sun_prepare_sys_poll() sun_getkmsg(0); } else if (Pfd.revents & (POLLNVAL|POLLHUP|POLLERR)) { //logerror("kernel log driver poll error"); - dbgprintf("kernel log driver poll error"); + dbgprintf("klog:kernel log driver poll error"); break; } } } +#endif + /* * this thread listens to the local stream log driver for log messages @@ -353,7 +356,7 @@ sun_sys_poll(void *ap) { int nfds; - dbgprintf("sys_poll: sys_thread started\n"); + dbgprintf("klog:sys_poll: sys_thread started\n"); /* * Try to process as many messages as we can without blocking on poll. @@ -366,15 +369,17 @@ sun_sys_poll(void *ap) for (;;) { errno = 0; +dbgprintf("XXX: before poll\n"); nfds = poll(&Pfd, 1, INFTIM); +dbgprintf("XXX: after poll, nfds %d\n", nfds); if (nfds == 0) continue; if (nfds < 0) { if (errno != EINTR) - dbgprintf("poll error");// logerror("poll"); + dbgprintf("klog:poll error");// logerror("poll"); continue; } if (Pfd.revents & POLLIN) { -- cgit From 3ab759c40d34f518744efa9b266640784fc3655f Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Fri, 26 Mar 2010 16:59:00 +0100 Subject: cleanup in solaris components for imklog --- plugins/imklog/solaris.c | 2 - plugins/imklog/solaris_cddl.c | 104 ++++-------------------------------------- 2 files changed, 8 insertions(+), 98 deletions(-) (limited to 'plugins/imklog') diff --git a/plugins/imklog/solaris.c b/plugins/imklog/solaris.c index a0e85dc7..c2aec30a 100644 --- a/plugins/imklog/solaris.c +++ b/plugins/imklog/solaris.c @@ -69,7 +69,6 @@ klogWillRun(void) if (fklog < 0) { char errStr[1024]; int err = errno; -perror("XXX"); rs_strerror_r(err, errStr, sizeof(errStr)); DBGPRINTF("error %d opening log socket: %s\n", GetPath(), errStr); @@ -167,7 +166,6 @@ rsRetVal klogLogKMsg(void) { DEFiRet; sun_sys_poll(); - //readklog(); RETiRet; } diff --git a/plugins/imklog/solaris_cddl.c b/plugins/imklog/solaris_cddl.c index 700e0ab3..1053de66 100644 --- a/plugins/imklog/solaris_cddl.c +++ b/plugins/imklog/solaris_cddl.c @@ -40,61 +40,24 @@ * software developed by the University of California, Berkeley, and its * contributors. */ - #include "config.h" #include #include #include #include #include - -//--------- -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include #include #include #include #include -#include - -#include -#include -#include #include -#include -#include -#include -#include -#include -#include -#include -#include -#include -//-------- - #include "rsyslog.h" static struct pollfd Pfd; /* Pollfd for local the log device */ - - -/* - * findnl_bkwd: +/* 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. @@ -174,8 +137,8 @@ findnl_bkwd(const char *buf, const size_t len) } //___ end -/* - * Attempts to open the local log device + +/* Attempts to open the local log device * and return a file descriptor. */ int @@ -210,7 +173,7 @@ sun_openklog(char *name, int mode) * Pull up one message from log driver. */ void -sun_getkmsg(int timeout) +sun_getkmsg() { int flags = 0, i; char *lastline; @@ -304,55 +267,13 @@ sun_getkmsg(int timeout) } -#if 0 -/* - * Open the log device, and pull up all pending messages. - */ -void -sun_prepare_sys_poll() -{ - int nfds, funix; - -/* - if ((funix = sun_openklog(LogName, O_RDONLY)) < 0) { - logerror("can't open kernel log device - fatal"); - exit(1); - } -*/ - - Pfd.fd = funix; - Pfd.events = POLLIN; - - for (;;) { - nfds = poll(&Pfd, 1, 0); - /* - if (nfds <= 0) { - if (sys_init_msg_count > 0) - flushmsg(SYNC_FILE); - break; - }*/ - - if (Pfd.revents & POLLIN) { - sun_getkmsg(0); - } else if (Pfd.revents & (POLLNVAL|POLLHUP|POLLERR)) { - //logerror("kernel log driver poll error"); - dbgprintf("klog:kernel log driver poll error"); - break; - } - } - -} -#endif - - -/* - * this thread listens to the local stream log driver for log messages +/* 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(void *ap) +sun_sys_poll() { int nfds; @@ -369,10 +290,8 @@ sun_sys_poll(void *ap) for (;;) { errno = 0; -dbgprintf("XXX: before poll\n"); nfds = poll(&Pfd, 1, INFTIM); -dbgprintf("XXX: after poll, nfds %d\n", nfds); if (nfds == 0) continue; @@ -383,9 +302,9 @@ dbgprintf("XXX: after poll, nfds %d\n", nfds); continue; } if (Pfd.revents & POLLIN) { - sun_getkmsg(INFTIM); + sun_getkmsg(); } else { - // TODO: shutdown, the rsyslog way + // TODO: shutdown, the rsyslog way (in v5!) //if (shutting_down) { //pthread_exit(0); //} @@ -398,13 +317,6 @@ dbgprintf("XXX: after poll, nfds %d\n", nfds); } } -/* while (Pfd.fd == -1 && klogerrs++ < 10) { - Pfd.fd = sun_openklog(LogName, O_RDONLY); - } - if (klogerrs >= 10) { - logerror("can't reopen kernel log device - fatal"); - exit(1); - }*/ } /*NOTREACHED*/ return (NULL); -- cgit From 23a3fdb094cd992b2081db014d583b975c03ca57 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Thu, 1 Apr 2010 15:16:05 +0200 Subject: git "bugfix": added file previously forgotten --- plugins/imklog/solaris_cddl.h | 1 + 1 file changed, 1 insertion(+) create mode 100644 plugins/imklog/solaris_cddl.h (limited to 'plugins/imklog') diff --git a/plugins/imklog/solaris_cddl.h b/plugins/imklog/solaris_cddl.h new file mode 100644 index 00000000..22295658 --- /dev/null +++ b/plugins/imklog/solaris_cddl.h @@ -0,0 +1 @@ +int sun_openklog(char *name, int mode); -- cgit From 2a8d484a73654c26e427a11fb10162a41a7be79d Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Mon, 12 Apr 2010 17:09:50 +0200 Subject: some cleanup of solaris imklog --- plugins/imklog/solaris.c | 9 ++++--- plugins/imklog/solaris_cddl.c | 62 +++++++++++-------------------------------- plugins/imklog/solaris_cddl.h | 1 + 3 files changed, 23 insertions(+), 49 deletions(-) (limited to 'plugins/imklog') diff --git a/plugins/imklog/solaris.c b/plugins/imklog/solaris.c index c2aec30a..8a6d5af1 100644 --- a/plugins/imklog/solaris.c +++ b/plugins/imklog/solaris.c @@ -42,6 +42,7 @@ #include "rsyslog.h" #include "imklog.h" +#include "srUtils.h" #include "unicode-helper.h" #include "solaris_cddl.h" @@ -70,8 +71,8 @@ klogWillRun(void) char errStr[1024]; int err = errno; rs_strerror_r(err, errStr, sizeof(errStr)); - DBGPRINTF("error %d opening log socket: %s\n", - GetPath(), errStr); + DBGPRINTF("error %s opening log socket: %s\n", + errStr, GetPath()); iRet = RS_RET_ERR; // TODO: better error code } @@ -79,6 +80,7 @@ klogWillRun(void) } +#if 0 /* Read /dev/klog while data are available, split into lines. * Contrary to standard BSD syslogd, we do a blocking read. We can * afford this as imklog is running on its own threads. So if we have @@ -125,7 +127,7 @@ readklog(void) break; } - for (p = pRcv; (q = strchr(p, '\n')) != NULL; p = q + 1) { + for(p = pRcv; (q = strchr(p, '\n')) != NULL; p = q + 1) { *q = '\0'; Syslog(LOG_INFO, (uchar*) p); } @@ -143,6 +145,7 @@ readklog(void) if(pRcv != NULL && (size_t) iMaxLine >= sizeof(bufRcv) - 1) free(pRcv); } +#endif /* to be called in the module's AfterRun entry point diff --git a/plugins/imklog/solaris_cddl.c b/plugins/imklog/solaris_cddl.c index 1053de66..7e86c68c 100644 --- a/plugins/imklog/solaris_cddl.c +++ b/plugins/imklog/solaris_cddl.c @@ -1,4 +1,3 @@ -#define MAXLINE 4096 /* * CDDL HEADER START * @@ -53,6 +52,15 @@ #include #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 */ @@ -70,11 +78,6 @@ findnl_bkwd(const char *buf, const size_t len) { const char *p; size_t mb_cur_max; - pthread_t mythreadno; - - if (Debug) { - mythreadno = pthread_self(); - } if (len == 0) { return (0); @@ -104,8 +107,7 @@ findnl_bkwd(const char *buf, const size_t len) /* * Invalid character found. */ - dbgprintf("klog:findnl_bkwd(%u): Invalid MB " - "sequence\n", mythreadno); + dbgprintf("klog:findnl_bkwd: Invalid MB sequence\n"); /* * handle as a single byte character. */ @@ -148,7 +150,6 @@ sun_openklog(char *name, int mode) struct strioctl str; if ((fd = open(name, mode)) < 0) { - //logerror("cannot open %s", name); dbgprintf("klog:openklog: cannot open %s (%d)\n", name, errno); return (-1); @@ -158,7 +159,6 @@ sun_openklog(char *name, int mode) str.ic_len = 0; str.ic_dp = NULL; if (ioctl(fd, I_STR, &str) < 0) { - //logerror("cannot register to log console messages"); dbgprintf("klog:openklog: cannot register to log " "console messages (%d)\n", errno); return (-1); @@ -200,18 +200,7 @@ sun_getkmsg() (void) memcpy(tmpbuf, buf, len); tmpbuf[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. - */ - Syslog(LOG_INFO, buf); - /*if (timeout == 0) { - formatsys(&hdr, tmpbuf, 0); - //sys_init_msg_count++; - } else { - formatsys(&hdr, tmpbuf, 1); - }*/ + Syslog(LOG_INFO, (uchar*) buf); if (len != buflen) { /* If anything remains in buf */ @@ -238,8 +227,7 @@ sun_getkmsg() if (i == 0 && dat.len > 0) { dat.buf[dat.len] = '\0'; - /* - * Format sys will enqueue the log message. + /* 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. @@ -249,15 +237,9 @@ sun_getkmsg() 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)); - //if (timeout == 0) { - //formatsys(&hdr, buf, 0); - //--sys_init_msg_count++; - //} else { - //formatsys(&hdr, buf, 1); - //} - Syslog(LOG_INFO, buf); + Syslog(LOG_INFO, (uchar*) buf); } else if (i < 0 && errno != EINTR) { - if(1){ // (!shutting_down) { + if(1){ /* V5-TODO: rsyslog-like termination! (!shutting_down) { */ dbgprintf("klog:kernel log driver read error"); } // TODO trigger retry logic @@ -279,15 +261,6 @@ sun_sys_poll() dbgprintf("klog:sys_poll: sys_thread started\n"); - /* - * Try to process as many messages as we can without blocking on poll. - * We count such "initial" messages with sys_init_msg_count and - * enqueue them without the SYNC_FILE flag. When no more data is - * waiting on the local log device, we set timeout to INFTIM, - * clear sys_init_msg_count, and generate a flush message to sync - * the previously counted initial messages out to disk. - */ - for (;;) { errno = 0; @@ -298,16 +271,13 @@ sun_sys_poll() if (nfds < 0) { if (errno != EINTR) - dbgprintf("klog:poll error");// logerror("poll"); + dbgprintf("klog:poll error"); continue; } if (Pfd.revents & POLLIN) { sun_getkmsg(); } else { - // TODO: shutdown, the rsyslog way (in v5!) - //if (shutting_down) { - //pthread_exit(0); - //} + /* 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"); diff --git a/plugins/imklog/solaris_cddl.h b/plugins/imklog/solaris_cddl.h index 22295658..d48ef628 100644 --- a/plugins/imklog/solaris_cddl.h +++ b/plugins/imklog/solaris_cddl.h @@ -1 +1,2 @@ +void *sun_sys_poll(); int sun_openklog(char *name, int mode); -- cgit From b00e7946e8dec90270f35c1060ac6d0abfe9df3e Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Thu, 15 Apr 2010 17:59:38 +0200 Subject: first version of imsolaris created, cleanup for solaris done more cleanup required, but things now basically work --- plugins/imklog/Makefile.am | 4 ---- 1 file changed, 4 deletions(-) (limited to 'plugins/imklog') diff --git a/plugins/imklog/Makefile.am b/plugins/imklog/Makefile.am index 06d4013c..5d4d0465 100644 --- a/plugins/imklog/Makefile.am +++ b/plugins/imklog/Makefile.am @@ -11,10 +11,6 @@ if ENABLE_IMKLOG_LINUX imklog_la_SOURCES += linux.c module.h ksym.c ksyms.h ksym_mod.c endif -if ENABLE_IMKLOG_SOLARIS -imklog_la_SOURCES += solaris.c solaris_cddl.c -endif - imklog_la_CPPFLAGS = -I$(top_srcdir) $(PTHREADS_CFLAGS) $(RSRT_CFLAGS) imklog_la_LDFLAGS = -module -avoid-version imklog_la_LIBADD = -- cgit