1
0
mirror of https://github.com/openbsd/src.git synced 2025-01-03 06:45:37 -08:00

Support for continuous reading of syslog memory buffers.

Works like ``tail -f'' on a log file.
OK markus@, djm@
This commit is contained in:
mpf 2007-01-03 13:25:20 +00:00
parent 9c2bdec2cf
commit c5dd883e85
3 changed files with 134 additions and 26 deletions

View File

@ -1,4 +1,4 @@
.\" $OpenBSD: syslogc.8,v 1.4 2005/09/24 02:09:54 djm Exp $
.\" $OpenBSD: syslogc.8,v 1.5 2007/01/03 13:25:21 mpf Exp $
.\"
.\" Copyright (c) 2004 Damien Miller
.\"
@ -21,7 +21,7 @@
.Nd collect messages from syslog memory buffer
.Sh SYNOPSIS
.Nm syslogc
.Op Fl Ccoq
.Op Fl Ccfoq
.Op Fl s Ar reporting_socket
.Ar logname
.Nm syslogc
@ -59,6 +59,12 @@ The options are as follows:
Request that the log buffer be cleared without reading it.
.It Fl c
Request that the log buffer be cleared once it has been read.
.It Fl f
Print out the last 10 lines and read from the buffer continuously.
Like
.Ar -f
in
.Xr tail 1
.It Fl o
Check whether the specified log has overflowed.
If the log has overflowed, then a message will be printed to
@ -73,6 +79,10 @@ will be appended to its name.
Specify alternate reporting socket location (the default is
.Pa /var/run/syslogd.sock ) .
.El
.Sh CAVEATS
The buffer space used for writing logs through the socket is limited.
Thus it is possible to lose logs when running in continuous mode.
Losses are reported on standard error.
.Sh SEE ALSO
.Xr syslog 3 ,
.Xr syslog.conf 5 ,

View File

@ -1,4 +1,4 @@
/* $OpenBSD: syslogc.c,v 1.11 2005/09/28 08:49:28 stevesk Exp $ */
/* $OpenBSD: syslogc.c,v 1.12 2007/01/03 13:25:21 mpf Exp $ */
/*
* Copyright (c) 2004 Damien Miller
@ -33,7 +33,7 @@
/*
* Client protocol NB. all numeric fields in network byte order
*/
#define CTL_VERSION 0
#define CTL_VERSION 1
/* Request */
struct ctl_cmd {
@ -43,6 +43,7 @@ struct ctl_cmd {
#define CMD_CLEAR 3 /* Clear log */
#define CMD_LIST 4 /* List available logs */
#define CMD_FLAGS 5 /* Query flags only */
#define CMD_READ_CONT 6 /* Read out log continuously */
u_int32_t cmd;
char logname[MAX_MEMBUF_NAME];
};
@ -60,7 +61,7 @@ usage(void)
{
extern char *__progname;
fprintf(stderr, "Usage: %s [-Ccoq] [-s ctlsock] logname\n", __progname);
fprintf(stderr, "Usage: %s [-Ccfhoq] [-s ctlsock] logname\n", __progname);
exit(1);
}
@ -81,7 +82,7 @@ main(int argc, char **argv)
ctlsock_path = DEFAULT_CTLSOCK;
rval = oflag = 0;
while ((ch = getopt(argc, argv, "Cchoqs:")) != -1) {
while ((ch = getopt(argc, argv, "Ccfhoqs:")) != -1) {
switch (ch) {
case 'C':
cc.cmd = CMD_CLEAR;
@ -92,6 +93,9 @@ main(int argc, char **argv)
case 'h':
usage();
break;
case 'f':
cc.cmd = CMD_READ_CONT;
break;
case 'o':
cc.cmd = CMD_FLAGS;
oflag = 1;
@ -149,8 +153,13 @@ main(int argc, char **argv)
errx(1, "unsupported syslogd version");
/* Write out reply */
while ((fgets(buf, sizeof(buf), ctlf)) != NULL)
fputs(buf, stdout);
while ((fgets(buf, sizeof(buf), ctlf)) != NULL) {
if (!strcmp(buf, "<ENOBUFS>\n"))
fprintf(stderr, "syslogc [%s]: Lines were dropped!\n",
cc.logname);
else
fputs(buf, stdout);
}
if (oflag && (ntohl(rr.flags) & CTL_HDR_FLAG_OVERFLOW)) {
printf("%s has overflowed\n", cc.logname);

View File

@ -1,4 +1,4 @@
/* $OpenBSD: syslogd.c,v 1.93 2006/09/17 18:28:34 djm Exp $ */
/* $OpenBSD: syslogd.c,v 1.94 2007/01/03 13:25:20 mpf Exp $ */
/*
* Copyright (c) 1983, 1988, 1993, 1994
@ -39,7 +39,7 @@ static const char copyright[] =
#if 0
static const char sccsid[] = "@(#)syslogd.c 8.3 (Berkeley) 4/4/94";
#else
static const char rcsid[] = "$OpenBSD: syslogd.c,v 1.93 2006/09/17 18:28:34 djm Exp $";
static const char rcsid[] = "$OpenBSD: syslogd.c,v 1.94 2007/01/03 13:25:20 mpf Exp $";
#endif
#endif /* not lint */
@ -149,6 +149,7 @@ struct filed {
char f_mname[MAX_MEMBUF_NAME];
struct ringbuf *f_rb;
int f_overflow;
int f_attached;
} f_mb; /* Memory buffer */
} f_un;
char f_prevline[MAXSVLINE]; /* last message logged */
@ -210,12 +211,14 @@ char *ctlsock_path = NULL; /* Path to control socket */
#define CTL_READING_CMD 1
#define CTL_WRITING_REPLY 2
#define CTL_WRITING_CONT_REPLY 3
int ctl_state = 0; /* What the control socket is up to */
int membuf_drop = 0; /* logs were dropped in continuous membuf read */
/*
* Client protocol NB. all numeric fields in network byte order
*/
#define CTL_VERSION 0
#define CTL_VERSION 1
/* Request */
struct {
@ -225,6 +228,7 @@ struct {
#define CMD_CLEAR 3 /* Clear log */
#define CMD_LIST 4 /* List available logs */
#define CMD_FLAGS 5 /* Query flags only */
#define CMD_READ_CONT 6 /* Read out log continuously */
u_int32_t cmd;
char logname[MAX_MEMBUF_NAME];
} ctl_cmd;
@ -241,8 +245,10 @@ struct ctl_reply_hdr {
#define CTL_HDR_LEN (sizeof(struct ctl_reply_hdr))
#define CTL_REPLY_MAXSIZE (CTL_HDR_LEN + MAX_MEMBUF)
#define CTL_REPLY_SIZE (strlen(reply_text) + CTL_HDR_LEN)
char *ctl_reply = NULL; /* Buffer for control connection reply */
char *reply_text; /* Start of reply text in buffer */
size_t ctl_reply_size = 0; /* Number of bytes used in reply */
size_t ctl_reply_offset = 0; /* Number of bytes of reply written so far */
@ -277,6 +283,8 @@ void double_rbuf(int);
void ctlsock_accept_handler(void);
void ctlconn_read_handler(void);
void ctlconn_write_handler(void);
void tailify_replytext(char *, int);
void logto_ctlconn(char *);
int
main(int argc, char *argv[])
@ -478,6 +486,7 @@ main(int argc, char *argv[])
logerror("Couldn't allocate ctlsock reply buffer");
die(0);
}
reply_text = ctl_reply + CTL_HDR_LEN;
if (!Debug) {
dup2(nullfd, STDIN_FILENO);
@ -944,6 +953,8 @@ fprintlog(struct filed *f, int flags, char *msg)
(char *)iov[4].iov_base);
if (ringbuf_append_line(f->f_un.f_mb.f_rb, line) == 1)
f->f_un.f_mb.f_overflow = 1;
if (f->f_un.f_mb.f_attached)
logto_ctlconn(line);
break;
}
f->f_prevcount = 0;
@ -1507,6 +1518,7 @@ cfline(char *line, char *prog)
break;
}
f->f_un.f_mb.f_overflow = 0;
f->f_un.f_mb.f_attached = 0;
break;
default:
@ -1671,6 +1683,8 @@ double_rbuf(int fd)
static void
ctlconn_cleanup(void)
{
struct filed *f;
if (pfd[PFD_CTLCONN].fd != -1)
close(pfd[PFD_CTLCONN].fd);
@ -1679,6 +1693,11 @@ ctlconn_cleanup(void)
pfd[PFD_CTLSOCK].events = POLLIN;
if (ctl_state == CTL_WRITING_CONT_REPLY)
for (f = Files; f != NULL; f = f->f_next)
if (f->f_type == F_MEMBUF)
f->f_un.f_mb.f_attached = 0;
ctl_state = ctl_cmd_bytes = ctl_reply_offset = ctl_reply_size = 0;
}
@ -1732,13 +1751,11 @@ ctlconn_read_handler(void)
ssize_t n;
struct filed *f;
u_int32_t flags = 0;
size_t reply_text_size;
struct ctl_reply_hdr *reply_hdr = (struct ctl_reply_hdr *)ctl_reply;
char *reply_text = ctl_reply + CTL_HDR_LEN;
if (ctl_state != CTL_READING_CMD) {
/* Shouldn't be here! */
logerror("ctlconn_read with bad ctl_state");
if (ctl_state == CTL_WRITING_REPLY ||
ctl_state == CTL_WRITING_CONT_REPLY) {
/* client has closed the connection */
ctlconn_cleanup();
return;
}
@ -1777,7 +1794,7 @@ ctlconn_read_handler(void)
*reply_text = '\0';
ctl_reply_size = reply_text_size = ctl_reply_offset = 0;
ctl_reply_size = ctl_reply_offset = 0;
memset(reply_hdr, '\0', sizeof(*reply_hdr));
ctl_cmd.cmd = ntohl(ctl_cmd.cmd);
@ -1786,6 +1803,7 @@ ctlconn_read_handler(void)
switch (ctl_cmd.cmd) {
case CMD_READ:
case CMD_READ_CLEAR:
case CMD_READ_CONT:
case CMD_FLAGS:
f = find_membuf_log(ctl_cmd.logname);
if (f == NULL) {
@ -1801,8 +1819,11 @@ ctlconn_read_handler(void)
ringbuf_clear(f->f_un.f_mb.f_rb);
f->f_un.f_mb.f_overflow = 0;
}
if (ctl_cmd.cmd == CMD_READ_CONT) {
f->f_un.f_mb.f_attached = 1;
tailify_replytext(reply_text, 10);
}
}
reply_text_size = strlen(reply_text);
break;
case CMD_CLEAR:
f = find_membuf_log(ctl_cmd.logname);
@ -1815,7 +1836,6 @@ ctlconn_read_handler(void)
f->f_un.f_mb.f_overflow = 0;
strlcpy(reply_text, "Log cleared\n", MAX_MEMBUF);
}
reply_text_size = strlen(reply_text);
break;
case CMD_LIST:
for (f = Files; f != NULL; f = f->f_next) {
@ -1830,7 +1850,6 @@ ctlconn_read_handler(void)
}
}
strlcat(reply_text, "\n", MAX_MEMBUF);
reply_text_size = strlen(reply_text);
break;
default:
logerror("Unsupported ctlsock command");
@ -1840,13 +1859,22 @@ ctlconn_read_handler(void)
reply_hdr->version = htonl(CTL_VERSION);
reply_hdr->flags = htonl(flags);
ctl_reply_size = reply_text_size + CTL_HDR_LEN;
ctl_reply_size = CTL_REPLY_SIZE;
dprintf("ctlcmd reply length %lu\n", (u_long)ctl_reply_size);
/* Otherwise, set up to write out reply */
ctl_state = CTL_WRITING_REPLY;
ctl_state = (ctl_cmd.cmd == CMD_READ_CONT) ?
CTL_WRITING_CONT_REPLY : CTL_WRITING_REPLY;
pfd[PFD_CTLCONN].events = POLLOUT;
pfd[PFD_CTLCONN].revents = 0;
/* monitor terminating syslogc */
pfd[PFD_CTLCONN].events |= POLLIN;
/* another syslogc can kick us out */
if (ctl_state == CTL_WRITING_CONT_REPLY)
pfd[PFD_CTLSOCK].events = POLLIN;
}
void
@ -1854,7 +1882,8 @@ ctlconn_write_handler(void)
{
ssize_t n;
if (ctl_state != CTL_WRITING_REPLY) {
if (!(ctl_state == CTL_WRITING_REPLY ||
ctl_state == CTL_WRITING_CONT_REPLY)) {
/* Shouldn't be here! */
logerror("ctlconn_write with bad ctl_state");
ctlconn_cleanup();
@ -1876,7 +1905,67 @@ ctlconn_write_handler(void)
default:
ctl_reply_offset += n;
}
if (ctl_reply_offset >= ctl_reply_size) {
/*
* Make space in the buffer for continous writes.
* Set offset behind reply header to skip it
*/
if (ctl_state == CTL_WRITING_CONT_REPLY) {
*reply_text = '\0';
ctl_reply_offset = ctl_reply_size = CTL_REPLY_SIZE;
if (ctl_reply_offset >= ctl_reply_size)
ctlconn_cleanup();
/* Now is a good time to report dropped lines */
if (membuf_drop) {
strlcat(reply_text, "<ENOBUFS>\n", MAX_MEMBUF);
ctl_reply_size = CTL_REPLY_SIZE;
membuf_drop = 0;
} else {
/* Nothing left to write */
pfd[PFD_CTLCONN].events = POLLIN;
}
} else
ctlconn_cleanup();
}
}
/* Shorten replytext to number of lines */
void
tailify_replytext(char *replytext, int lines)
{
char *start, *nl;
int count = 0;
start = nl = replytext;
while ((nl = strchr(nl, '\n')) != NULL) {
nl++;
if (++count > lines) {
start = strchr(start, '\n');
start++;
}
}
if (start != replytext) {
int len = strlen(start);
memmove(replytext, start, len);
*(replytext + len) = '\0';
}
}
void
logto_ctlconn(char *line)
{
size_t l;
if (membuf_drop)
return;
l = strlen(line);
if (l + 2 > (CTL_REPLY_MAXSIZE - ctl_reply_size)) {
/* remember line drops for later report */
membuf_drop = 1;
return;
}
memcpy(ctl_reply + ctl_reply_size, line, l);
memcpy(ctl_reply + ctl_reply_size + l, "\n", 2);
ctl_reply_size += l + 1;
pfd[PFD_CTLCONN].events |= POLLOUT;
}