Sophie

Sophie

distrib > Mandriva > 2009.0 > i586 > by-pkgid > 7ce23f99807f9a2f70929a432f12f6ae > files > 4

sysklogd-1.4.2-8mdv2009.0.src.rpm

--- sysklogd-1.4.2rh/sysklogd.8.dispatcher	2007-06-07 10:40:15.000000000 +0200
+++ sysklogd-1.4.2rh/sysklogd.8	2007-06-07 10:40:15.000000000 +0200
@@ -30,6 +30,9 @@
 .RB [ " \-s "
 .I domainlist
 ]
+.RB [ " \-D "
+.I dispatcher
+]
 .RB [ " \-v " ]
 .RB [ " \-x " ]
 .LP
@@ -178,6 +181,14 @@
 once, the names of the facility and priority are logged with each
 locally-written message.
 .TP
+.BI "\-D " "dispatcher"
+The syslogd daemon will start up a dispatcher program and open
+standard input to the socketpair used to pass events. So, the 
+dispatcher only needs to read stdin. Because IPC communication 
+buffers have a limited size, it must read the events as fast 
+as possible. The syslogd send SIGTERM to indicate that the 
+dispatcher should exit.
+.TP
 .B "\-v"
 Print version and exit.
 .TP
@@ -444,6 +455,19 @@
 	kern.=debug			|/usr/adm/debug
 .fi
 .LP
+.SH OUTPUT TO DISPATCHER
+If you run syslogd with the
+.B \-D 
+option, you can route your messages 
+to dispatcher process. To specify messages, which go to dispatcher, 
+you use "!dispatcher" directive. 
+.IP
+Following configuration routes info messages to a dispatcher process:
+.IP
+.nf
+	*.info				!dispatcher
+.fi
+.LP
 .SH INSTALLATION CONCERNS
 There is probably one important consideration when installing this
 version of syslogd.  This version of syslogd is dependent on proper
--- /dev/null	2007-06-04 11:07:53.480224378 +0200
+++ sysklogd-1.4.2rh/sysklogd-dispatch.h	2007-06-07 10:40:15.000000000 +0200
@@ -0,0 +1,64 @@
+/* sysklogd-dispatch.h -- 
+ * Copyright 2007 Red Hat Inc., Durham, North Carolina.
+ * All Rights Reserved.
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * Authors:
+ *   Steve Grubb <sgrubb@redhat.com>
+ *   Peter Vrabec <pvrabec@redhat.com>
+ * 
+ */
+
+#ifndef SYSKLOGD_DISPATCH_H
+#define SYSKLOGD_DISPATCH_H
+
+
+typedef enum { QOS_NON_BLOCKING, QOS_BLOCKING } qos_t;
+
+struct daemon_conf
+{
+        char * dispatcher;
+        qos_t qos;              /* use blocking/non-blocking sockets */
+};
+
+/* Sysklogd protocol #1 contains only one type of reply message
+   and that is standart message. */
+#define SYSKLOGD_PROTOCOL_VER	1
+#define MAXLINE			1024 /* Should be same MAXLINE as in syslogd.c */
+typedef enum { STD_MESS } mess_t;   
+
+struct sysklogd_reply {
+        mess_t			type;
+        int			len;
+	union {
+	       	const char		*message;
+	};
+};
+
+struct sysklogd_dispatcher_header {
+        int        ver;    /* The version of this protocol */
+        int        hlen;   /* Header length */
+        mess_t     type;   /* Message type */
+        int        size;   /* Size of data following the header */
+};
+
+
+int init_dispatcher(const struct daemon_conf *config);
+void shutdown_dispatcher(void);
+void reconfigure_dispatcher(void);
+void dispatch_event(const struct sysklogd_reply *rep);
+
+#endif
--- sysklogd-1.4.2rh/Makefile.dispatcher	2007-02-26 10:46:08.000000000 +0100
+++ sysklogd-1.4.2rh/Makefile	2007-06-07 10:40:15.000000000 +0200
@@ -10,6 +10,7 @@
 INSTALL = /usr/bin/install
 BINDIR = $(TOPDIR)/sbin
 MANDIR = $(TOPDIR)/usr/man
+INCLUDEDIR = $(TOPDIR)/usr/include
 
 # There is one report that under an all ELF system there may be a need to
 # explicilty link with libresolv.a.  If linking syslogd fails you may wish
@@ -57,10 +58,10 @@
 
 test: syslog_tst ksym oops_test tsyslogd
 
-install: install_man install_exec
+install: install_man install_exec install_include
 
-syslogd: syslogd.o pidfile.o
-	${CC} ${LDFLAGS} -o syslogd syslogd.o pidfile.o ${LIBS}
+syslogd: syslogd.o pidfile.o sysklogd-dispatch.o
+	${CC} ${LDFLAGS} -o syslogd syslogd.o pidfile.o sysklogd-dispatch.o ${LIBS}
 
 klogd:	klogd.o syslog.o pidfile.o ksym.o ksym_mod.o
 	${CC} ${LDFLAGS} -o klogd klogd.o syslog.o pidfile.o ksym.o \
@@ -121,6 +122,9 @@
 	${INSTALL} -m 644 syslog.conf.5 ${MANDIR}/man5/syslog.conf.5
 	${INSTALL} -m 644 klogd.8 ${MANDIR}/man8/klogd.8
 
+install_include:
+	${INSTALL} -m 644 sysklogd-dispatch.h ${INCLUDEDIR}/sysklogd/sysklogd-dispatch.h
+
 
 ## Red Hat specific additions
 
--- /dev/null	2007-06-04 11:07:53.480224378 +0200
+++ sysklogd-1.4.2rh/dispatcher_example.c	2007-06-07 10:38:28.000000000 +0200
@@ -0,0 +1,205 @@
+/* dispatcher.c --
+ * 
+ * This is a sample program that you can customize to create your own syslog
+ * event handler. It will be started by syslog via the dispatcher option on
+ * command line. This program can be built as follows:
+ *
+ * gcc dispatcher_example.c -o dispatcher
+ */
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/uio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <signal.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <string.h>
+#include <locale.h>
+#include <sys/socket.h>
+#include <arpa/inet.h>
+#include <sys/select.h>
+#include <sys/un.h>
+
+#include "sysklogd/sysklogd-dispatch.h"
+
+
+/* Local data */
+static volatile int signaled = 0;
+static int pipe_fd;
+static struct sockaddr_un my_addr;
+static int fd;
+
+/* Local functions */
+static int event_loop(void);
+
+/* SIGTERM handler */
+static void term_handler( int sig )
+{
+	signaled = 1;
+}
+
+
+/*
+ * main is started by sysklogd. See dispatcher in man sysklogd.
+ */
+int main(int argc, char *argv[])
+{
+	struct sigaction sa;
+	struct stat stat_buf;
+
+	setlocale (LC_ALL, "");
+	fprintf(stderr, "starting dispatcher...\n");
+
+#ifndef DEBUG
+	/* Make sure we are root */
+	if (getuid() != 0) {
+		fprintf(stderr, "You must be root to run this program.");
+		exit(1);
+	}
+#endif
+
+	/* register sighandlers */
+	sa.sa_flags = 0 ;
+	sa.sa_handler = term_handler;
+	sigemptyset( &sa.sa_mask ) ;
+	sigaction( SIGTERM, &sa, NULL );
+     /*	sa.sa_handler = term_handler;
+	sigemptyset( &sa.sa_mask ) ;
+	sigaction( SIGCHLD, &sa, NULL ); */
+	sa.sa_handler = SIG_IGN;
+	sigaction( SIGHUP, &sa, NULL );
+	sigaction( SIGPIPE, &sa, NULL );
+	(void)chdir("/");
+
+	/* change over to pipe_fd */
+	pipe_fd = dup(0);
+	close(0);
+	fcntl(pipe_fd, F_SETFD, FD_CLOEXEC);
+
+	/* Setup server */
+	if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) {
+		perror("socket()");
+		exit(1);
+	}
+	fcntl(fd, F_SETFD, O_NONBLOCK);
+	my_addr.sun_family=AF_UNIX;  
+  	strncpy(my_addr.sun_path, "/tmp/dispatcher.sock", sizeof(my_addr.sun_path));
+	unlink(my_addr.sun_path); /* not necessary */
+	if (bind(fd, (struct sockaddr *) &my_addr, sizeof(my_addr)) == -1) {
+		perror("bind()");
+		exit(1);
+	}
+	stat(my_addr.sun_path, &stat_buf);
+	chmod(my_addr.sun_path, stat_buf.st_mode | S_IWOTH);
+	if (listen(fd, 1) == -1) {
+		perror("listen()");
+		exit(1);
+	}
+
+	/* Start the program */
+	return event_loop();
+}
+
+static int event_loop(void)
+{
+	void* data;
+	struct iovec vec[2];
+	struct sysklogd_dispatcher_header hdr;
+	pid_t pid;
+	static socklen_t addrlen;
+	int new_fd = -1;
+
+
+	/* Allocate data structures */
+	data = malloc(MAXLINE);
+	if (data == NULL) {
+		fprintf(stderr, "Cannot allocate buffer\n");
+		return 1;
+	}
+
+	do {
+		int rc;
+		struct timeval tv;
+		fd_set fdset;
+
+
+		/* if there isn't anybody connected to server, try accept */
+		if (new_fd == -1 ) {
+			addrlen = sizeof(my_addr);
+			if ((new_fd = accept( fd, (struct sockaddr *) &my_addr, &addrlen))==-1) {
+				perror("accept()");
+				exit(1);
+			}
+		}
+
+		memset(data, 0, MAXLINE);
+		memset(&hdr, 0, sizeof(hdr));
+
+		tv.tv_sec = 1;
+		tv.tv_usec = 0;
+		FD_ZERO(&fdset);
+		FD_SET(pipe_fd, &fdset);
+		rc = select(pipe_fd+1, &fdset, NULL, NULL, &tv);
+		if (rc == 0) 
+			continue;
+		 else if (rc == -1)
+			break;
+
+		/* Get header first. it is fixed size */
+		vec[0].iov_base = (void*)&hdr;
+		vec[0].iov_len = sizeof(hdr);
+		rc = readv(pipe_fd, vec, 1);
+		if (rc == 0 || rc == -1) {
+			fprintf(stderr, "rc == %d(%s)\n", rc, strerror(errno));
+			break;
+		}
+
+		/* Analyze header */
+			/*nothing to do at the momemnt */
+
+        	/* Next payload */
+		vec[1].iov_base = data;
+		vec[1].iov_len = MAXLINE; 
+		rc = readv(pipe_fd, &vec[1], 1);
+		if (rc == 0 || rc == -1) {
+			fprintf(stderr, "rc == %d(%s)\n", rc, strerror(errno));
+			break;
+		}
+
+		/* handle some events here. */
+		if (new_fd != -1) {
+			rc = write(new_fd, (char *)data, strlen(data));
+			if (rc <= 0) {
+				if (errno == EPIPE) {
+					close(new_fd);
+					new_fd=-1;
+				} else {	
+					perror("writev()");
+					new_fd=-1;
+				}
+			}
+		}		
+/*
+		if( strstr((char *)data, "oops") ) {
+			pid = fork();
+			if( !pid ) {
+				execl("/usr/bin/zenity","/usr/bin/zenity","--warning",
+				      "--text", (char *)data, NULL);
+				fprintf(stderr, "exec() failed\n");
+		        }
+		}
+*/
+/*
+		 fprintf(stderr,"type=%d, payload size=%d\n", 
+			hdr.type, hdr.size);
+		   fprintf(stderr,"data=\"%.*s\"\n", hdr.size,
+			(char *)data); 
+*/
+	} while(!signaled);
+
+	return 0;
+}
+
--- /dev/null	2007-06-04 11:07:53.480224378 +0200
+++ sysklogd-1.4.2rh/sysklogd-dispatch.c	2007-06-07 10:40:15.000000000 +0200
@@ -0,0 +1,190 @@
+/* sysklogd-dispatch.c -- 
+ * Copyright 2007 Red Hat Inc., Durham, North Carolina.
+ * All Rights Reserved.
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * Authors:
+ *   Steve Grubb <sgrubb@redhat.com>
+ *   Junji Kanemaru <junji.kanemaru@linuon.com>
+ *   Peter Vrabec <pvrabec@redhat.com>
+ */
+
+#include <unistd.h>
+#include <sys/uio.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <errno.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+
+#include "sysklogd-dispatch.h"
+
+/* This is the communications channel between sysklogd & the dispatcher */
+static int disp_pipe[2] = {-1, -1};
+static pid_t pid = 0;
+static int n_errs = 0;
+#define REPORT_LIMIT 10
+
+/* set_flags: to set flags to file desc */
+static int set_flags(int fn, int flags)
+{
+	int fl;
+
+	if ((fl = fcntl(fn, F_GETFL, 0)) < 0) {
+		fprintf(stderr, "fcntl failed. Cannot get flags (%s)\n", 
+			strerror(errno));
+		return fl;
+	}
+
+	fl |= flags;
+
+	return fcntl(fn, F_SETFL, fl);
+}
+
+/* This function returns 1 on error & 0 on success */
+int init_dispatcher(const struct daemon_conf *config)
+{
+	if (config->dispatcher == NULL) 
+		return 0;
+
+	if (socketpair(AF_UNIX, SOCK_STREAM, 0, disp_pipe)) {
+		fprintf(stderr, "Failed creating disp_pipe\n");
+		return 1;
+	}
+
+	/* Make both disp_pipe non-blocking */
+	if (config->qos == QOS_NON_BLOCKING) {
+		if (set_flags(disp_pipe[0], O_NONBLOCK) < 0 ||
+			set_flags(disp_pipe[1], O_NONBLOCK) < 0) {
+			fprintf(stderr, "Failed to set O_NONBLOCK flag\n");
+			return 1;
+		}
+	}
+
+	// do the fork
+	pid = fork();
+	switch(pid) {
+		case 0:	// child
+			/* in case stdin was closed before sockerpair(),
+			   disp_pipe[0] --eq 0. It's usual because syslogd 
+			   run as daemon. */
+			if( disp_pipe[0] != 0 ) {
+				dup2(disp_pipe[0], 0);
+				close(disp_pipe[0]);
+			}
+			close(disp_pipe[1]);
+			setsid();
+			execl(config->dispatcher, config->dispatcher, NULL);
+			fprintf(stderr, "exec() failed\n");
+			exit(1);
+			break;
+		case -1:	// error
+			return 1;
+			break;
+		default:	// parent
+			close(disp_pipe[0]);
+			disp_pipe[0] = -1;
+			/* Avoid leaking this */
+			if (fcntl(disp_pipe[1], F_SETFD, FD_CLOEXEC) < 0) {
+				fprintf(stderr,
+					"Failed to set FD_CLOEXEC flag\n");
+				return 1;
+			}
+			fprintf(stderr, "Started dispatcher: %s pid: %u\n",
+					config->dispatcher, pid);
+			break;
+	}
+
+	return 0;
+}
+
+void shutdown_dispatcher(void)
+{
+	// kill child
+	if (pid)
+		kill(pid, SIGTERM);
+	// wait for term
+	// if not in time, send sigkill
+	pid = 0;
+
+	// cleanup comm pipe
+	if (disp_pipe[0] >= 0) {
+		close(disp_pipe[0]);
+		disp_pipe[0] = -1;
+	}
+	if (disp_pipe[1] >= 0) {
+		close(disp_pipe[1]);
+		disp_pipe[1] = -1;
+	}
+}
+
+void reconfigure_dispatcher(void)
+{
+	// signal child
+	if (pid)
+		kill(pid, SIGHUP);
+}
+
+void dispatch_event(const struct sysklogd_reply *rep)
+{
+	int rc, count = 0;
+	struct iovec vec[2];
+	struct sysklogd_dispatcher_header hdr;
+
+	if (disp_pipe[1] == -1)
+		return;
+
+	hdr.ver = SYSKLOGD_PROTOCOL_VER; /* Hard-coded to current protocol */
+	hdr.hlen = sizeof(struct sysklogd_dispatcher_header);
+	hdr.type = rep->type;
+	hdr.size = rep->len;
+
+	vec[0].iov_base = (void*)&hdr;
+	vec[0].iov_len = sizeof(hdr);
+	vec[1].iov_base = (void*)rep->message;
+	vec[1].iov_len = rep->len;
+
+	do {
+		rc = writev(disp_pipe[1], vec, 2);
+	} while (rc < 0 && errno == EAGAIN && count++ < 10);
+
+	// close pipe if no child or peer has been lost
+	if (rc <= 0) {
+		if (errno == EPIPE) {
+			shutdown_dispatcher();
+			n_errs = 0;
+		} else {
+			if (n_errs <= REPORT_LIMIT) {
+				fprintf(stderr, 
+					"dispatch err (%s) event lost\n",
+					errno == EAGAIN ? "pipe full" :
+					strerror(errno));
+				n_errs++;
+			}
+			if (n_errs == REPORT_LIMIT) {
+				fprintf(stderr, 
+					"dispatch error reporting limit\n"
+					" reached - ending report"
+					" notification.");
+				n_errs++;
+			}
+		}
+	} else
+		n_errs = 0;
+}
--- sysklogd-1.4.2rh/syslogd.c.dispatcher	2007-06-07 10:40:15.000000000 +0200
+++ sysklogd-1.4.2rh/syslogd.c	2007-06-07 10:40:15.000000000 +0200
@@ -507,6 +507,8 @@
 #endif
 #include "version.h"
 
+#include "sysklogd-dispatch.h"
+
 #if defined(__linux__)
 #include <paths.h>
 #endif
@@ -572,6 +574,8 @@
 static int alarm_signal = 0;
 static int exit_on_signal = 0;
 
+struct daemon_conf disp =  { NULL, QOS_NON_BLOCKING };
+
 #define MAXFUNIX	20
 
 int nfunix = 1;
@@ -674,10 +678,11 @@
 #define F_FORW_SUSP	7		/* suspended host forwarding */
 #define F_FORW_UNKN	8		/* unknown host forwarding */
 #define F_PIPE		9		/* named pipe */
+#define F_DISP		10		/* named pipe */
 char	*TypeNames[] = {
 	"UNUSED",	"FILE",		"TTY",		"CONSOLE",
 	"FORW",		"USERS",	"WALL",		"FORW(SUSPENDED)",
-	"FORW(UNKNOWN)", "PIPE"
+	"FORW(UNKNOWN)", "PIPE",	"DISP"
 };
 
 struct	filed *Files = (struct filed *) 0;
@@ -859,7 +864,7 @@
 		funix[i]  = -1;
 	}
 
-	while ((ch = getopt(argc, argv, "46Aa:dhf:l:m:np:rSs:vx")) != EOF)
+	while ((ch = getopt(argc, argv, "46Aa:dhf:D:l:m:np:rSs:vx")) != EOF)
 		switch((char)ch) {
                 case '4':
                               family = PF_INET;
@@ -881,6 +886,9 @@
 		case 'd':		/* debug */
 			Debug = 1;
 			break;
+		case 'D':		/* dispatcher */
+			disp.dispatcher = optarg;
+			break;
 		case 'f':		/* configuration file */
 			ConfFile = optarg;
 			break;
@@ -1067,6 +1075,15 @@
 	    parts[i] = (char *) 0;
 
 	dprintf("Starting.\n");
+
+	if( disp.dispatcher != NULL ) {
+		dprintf("Dispatcher initialisation.\n");
+	        if( init_dispatcher(&disp) == 1) {
+			dprintf("Dispatcher initialisation FAIL.\n");
+			die(0);
+		}
+        }
+
 	init();
 #ifndef TESTING
 	if ( Debug )
@@ -1249,7 +1266,7 @@
 int usage()
 {
 	fprintf(stderr, "usage: syslogd [-46AdiIrvxh] [-l hostlist] [-m markinterval] [-n] [-p path]\n" \
-		" [-s domainlist] [-f conffile]\n");
+		" [-s domainlist] [-D dispatcher] [-f conffile]\n");
 	exit(1);
 }
 
@@ -1767,6 +1784,7 @@
 	time_t fwd_suspend;
 	struct addrinfo *saddr;
 #endif
+	struct sysklogd_reply reply;
 
 	dprintf("Called fprintlog, ");
 
@@ -2012,7 +2030,19 @@
 		} else if (f->f_flags & SYNC_FILE)
 			(void) fsync(f->f_file);
 		break;
-
+	case F_DISP:
+		f->f_time = now;
+		dprintf("\n");
+                v->iov_base = "";
+                v->iov_len = 0;
+		(void) snprintf(line, sizeof(line), "%s%s%s%s%s%s%s\n", (char *) iov[0].iov_base, 
+				(char *) iov[1].iov_base, (char *) iov[2].iov_base, (char *) iov[3].iov_base,
+         			(char *) iov[4].iov_base, (char *) iov[5].iov_base, (char *) iov[6].iov_base);
+                reply.type = STD_MESS;
+		reply.message = line;
+	        reply.len = strlen(reply.message);
+	        dispatch_event(&reply);
+		break;
 	case F_USERS:
 	case F_WALL:
 		f->f_time = now;
@@ -2338,6 +2368,12 @@
 		logmsg(LOG_SYSLOG|LOG_INFO, buf, LocalHostName, ADDDATE);
 	}
 
+	/* Terminate dispatcher */
+	if (disp.dispatcher != NULL) {
+		shutdown_dispatcher();
+		disp.dispatcher = NULL;
+	}
+
 	/* Close the UNIX sockets. */
         for (i = 0; i < nfunix; i++)
 		if (funix[i] != -1)
@@ -2868,7 +2904,15 @@
 		if (strcmp(p, ctty) == 0)
 			f->f_type = F_CONSOLE;
 		break;
-
+	case '!':
+		if( !strncmp(++p, "dispatcher", 10) ) {
+			dprintf ("sending to: %s\n", disp.dispatcher);
+			f->f_type = F_DISP;
+		}
+		else {
+			dprintf ("\"!\" is not followed by \"dispatcher\"\n");
+		}
+		break;
 	case '*':
 		dprintf ("write-all\n");
 		f->f_type = F_WALL;