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:
parent
9c2bdec2cf
commit
c5dd883e85
@ -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 ,
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user