/***************************************************************************
*
* Copyright (c) 1999 Balázs Scheidler
* Copyright (c) 1999-2001 BalaBit IT Ltd.
*
* This program 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 2 of the License, or
* (at your option) any later version.
*
* This program 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 this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* Inspired by nsyslog, originally written by Darren Reed.
*
* $Id: afstreams.c,v 1.16.4.2 2004/05/13 11:33:36 bazsi Exp $
*
***************************************************************************/
#include "afstreams.h"
#include "sources.h"
#include "format.h"
#include "cfgfile.h"
#include "afstreams.c.x"
#if HAVE_SUN_STREAMS
#include <sys/types.h>
#include <sys/stat.h>
#include <stropts.h>
#include <sys/strlog.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <alloca.h>
#if HAVE_SUN_DOOR && HAVE_DOOR_H
#include <door.h>
#endif
/* CLASS:
(class
(name door_fd)
(super resource)
(vars
(fd simple int)))
*/
#if HAVE_SUN_DOOR
static void do_kill_door(struct resource *r)
{
CAST(door_fd, self, r);
door_revoke(self->fd);
close(self->fd);
}
static struct door_fd *make_door_fd(int fd)
{
NEW(door_fd, f);
f->super.kill = do_kill_door;
f->fd = fd;
return f;
}
#endif
/* CLASS:
(class
(name stream_fd)
(super nonblocking_fd)
(vars
(bad_hostname special-struct regex_t #f regfree)
(max_log_line . UINT32)
(pipe object log_handler)))
*/
static void prepare_stream_fd(struct nonblocking_fd *fd)
{
if (fd->to_be_closed)
kill_fd(fd);
}
static int do_stream_read(int fd, UINT32 *pri, UINT32 length, UINT8 *buf)
{
struct strbuf ctl, data;
struct log_ctl lc;
int flags;
int res;
ctl.maxlen = ctl.len = sizeof(lc);
ctl.buf = (char *) &lc;
data.maxlen = length;
data.len = 0;
data.buf = buf;
flags = 0;
res = getmsg(fd, &ctl, &data, &flags);
if ((res & MORECTL) == 0) {
if (res & MOREDATA) {
werror("do_stream_read: STREAMS device gave too long line\n");
}
*pri = lc.pri;
}
else {
werror("do_stream_read: getmsg() trying to return too much ctl data, res=%i %z\n", res, strerror(errno));
return A_FAIL;
}
return data.len;
}
static void stream_read_callback(struct nonblocking_fd *fd)
{
CAST(stream_fd, self, fd);
char *line = alloca(self->max_log_line + 1);
UINT32 pri;
int n;
n = do_stream_read(self->super.fd, &pri, self->max_log_line, line);
if (n < 0) {
close_fd(fd, CLOSE_EOF);
return;
}
{
UINT8 *eol, *bol;
UINT32 length;
struct log_info *li;
bol = line;
eol = memchr(bol, '\n', n);
if (!eol) eol = memchr(bol, '\0', n);
if (!eol) {
/* FIXME: there must be space for this '\0' as we
* specified sizeof(buf) - 1 when reading the message
*/
eol = &line[n];
line[n] = '\0';
n++;
}
while (eol) {
if (*bol == '\r') {
bol++;
n--;
}
length = eol - bol;
if (length) {
li = make_log_info(length, bol, NULL, 0, &self->bad_hostname);
li->pri = pri;
HANDLE_LOG(self->pipe, li);
}
n -= length + 1;
bol = eol + 1;
eol = memchr(bol, '\n', n);
if (!eol) eol = memchr(bol, '\0', n);
}
}
}
struct nonblocking_fd *io_stream_get(struct io_backend *backend,
int fd,
UINT8 *hostname_re,
UINT32 max_log_line,
struct log_handler *pipe)
{
NEW(stream_fd, f);
init_file(backend, &f->super, fd, NULL);
f->super.prepare = prepare_stream_fd;
f->super.read = stream_read_callback;
f->super.want_read = 1;
f->pipe = pipe;
f->max_log_line = max_log_line;
if (hostname_re == NULL)
regcomp(&f->bad_hostname, "^$", REG_NOSUB | REG_EXTENDED);
else
regcomp(&f->bad_hostname, hostname_re, REG_NOSUB | REG_EXTENDED);
return &f->super;
}
/* CLASS:
(class
(name afstreams_source)
(super log_source_driver)
(vars
(name string)
(door_name string)
(stream_fd object nonblocking_fd)
(door object door_fd)))
*/
#if HAVE_SUN_DOOR
void afstreams_door_server_proc(void *cookie, char *argp, size_t arg_size, door_desc_t *dp, size_t n_desc)
{
door_return(NULL, 0, NULL, 0);
return;
}
#endif
void afstreams_set_sundoor(struct log_source_driver *c, const char *door)
{
CAST(afstreams_source, self, c);
self->door_name = c_format_cstring("%z", door);
}
static int
do_init_afstreams_source(struct log_handler *c,
struct syslog_config *cfg,
struct persistent_config *persistent)
{
CAST(afstreams_source, self, c);
int fd;
fd = open(self->name->data, O_RDONLY | O_NOCTTY | O_NONBLOCK);
if (fd != -1) {
struct strioctl ioc;
#if HAVE_SUN_DOOR
struct stat st;
#endif
memset(&ioc, 0, sizeof(ioc));
ioc.ic_cmd = I_CONSLOG;
if (ioctl(fd, I_STR, &ioc) < 0) {
werror("do_init_afstreams_source: Cannot enable console logging on sun-stream %S (%z)\n", self->name, strerror(errno));
close(fd);
return ST_FAIL | ST_QUIT;
}
self->stream_fd = io_stream_get(cfg->backend, fd, cfg->bad_hostname, cfg->log_msg_size, c);
REMEMBER_RESOURCE(cfg->resources, &self->stream_fd->super);
#if HAVE_SUN_DOOR
if (self->door_name) {
if (stat(self->door_name->data, &st) == -1) {
fd = creat(self->door_name->data, 0666);
if (fd == -1) {
werror("do_init_afstreams_source: cannot create door file %S (%z)\n", self->door_name, strerror(errno));
return ST_FAIL | ST_QUIT;
}
close(fd);
}
fdetach(self->door_name->data);
fd = door_create(afstreams_door_server_proc, NULL, 0);
if (fd == -1) {
werror("do_init_afstreams_source: Cannot initialize door server %S (%z)\n", self->name, strerror(errno));
return ST_FAIL | ST_QUIT;
}
if (fattach(fd, self->door_name->data) == -1) {
werror("do_init_afstreams_source: Cannot attach door to %S (%z)\n", self->name, strerror(errno));
close(fd);
return ST_FAIL | ST_QUIT;
}
self->door = make_door_fd(fd);
REMEMBER_RESOURCE(cfg->resources, &self->door->super);
}
#else
if (self->door_name) {
close_fd(self->stream_fd, 0);
werror("sun-door support is not compiled in, door=%S\n", self->door_name);
return ST_FAIL | ST_QUIT;
}
#endif
}
else {
werror("do_init_afstreams_source: Cannot open sun-stream %S (%z)\n", self->name, strerror(errno));
return ST_FAIL | ST_QUIT;
}
return ST_OK | ST_GOON;
}
static void do_handle_afstreams_source(struct log_handler *c, struct log_info *log)
{
CAST(afstreams_source, self, c);
log->flags |= LF_LOCAL;
HANDLE_LOG(self->super.super.next, log);
}
struct log_source_driver *make_afstreams_source(const char *name)
{
NEW(afstreams_source, self);
self->super.super.super.init = do_init_afstreams_source;
self->super.super.super.handler = do_handle_afstreams_source;
self->name = c_format_cstring("%z", name);
return &self->super;
}
#else
void afstreams_set_sundoor(struct log_source_driver *c, const char *door_name)
{
}
static int
do_init_afstreams_source(struct log_handler *c,
struct syslog_config *cfg,
struct persistent_config *persistent)
{
CAST(afstreams_source, self, c);
werror("sun-streams support not compiled in (STREAM=%S)\n", self->name);
return ST_FAIL | ST_QUIT;
}
struct log_source_driver *make_afstreams_source(const char *name)
{
NEW(afstreams_source, self);
self->super.super.super.init = do_init_afstreams_source;
self->name = c_format_cstring("%z", name);
return &self->super;
}
#endif
syntax highlighted by Code2HTML, v. 0.9.1