diff options
author | Marco Pfatschbacher <mpf@cvs.openbsd.org> | 2007-01-03 13:25:22 +0000 |
---|---|---|
committer | Marco Pfatschbacher <mpf@cvs.openbsd.org> | 2007-01-03 13:25:22 +0000 |
commit | f0348aacfc51f98bd7766c43f4a9cbc01b71748f (patch) | |
tree | bbaf5948947bdc8dcbd97ce9d59c61a24feccf14 | |
parent | 9b5b5d7554523aab6e544310b7270eceac53e1f3 (diff) |
Support for continuous reading of syslog memory buffers.
Works like ``tail -f'' on a log file.
OK markus@, djm@
-rw-r--r-- | usr.sbin/syslogc/syslogc.8 | 14 | ||||
-rw-r--r-- | usr.sbin/syslogc/syslogc.c | 21 | ||||
-rw-r--r-- | usr.sbin/syslogd/syslogd.c | 125 |
3 files changed, 134 insertions, 26 deletions
diff --git a/usr.sbin/syslogc/syslogc.8 b/usr.sbin/syslogc/syslogc.8 index 730bb0242fd..a1769c48b70 100644 --- a/usr.sbin/syslogc/syslogc.8 +++ b/usr.sbin/syslogc/syslogc.8 @@ -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 , diff --git a/usr.sbin/syslogc/syslogc.c b/usr.sbin/syslogc/syslogc.c index 7cf6d8c115c..42f54e0b3b3 100644 --- a/usr.sbin/syslogc/syslogc.c +++ b/usr.sbin/syslogc/syslogc.c @@ -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); diff --git a/usr.sbin/syslogd/syslogd.c b/usr.sbin/syslogd/syslogd.c index b8ae34eee7b..5ccd8c68c75 100644 --- a/usr.sbin/syslogd/syslogd.c +++ b/usr.sbin/syslogd/syslogd.c @@ -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; + + /* 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'; + } +} - if (ctl_reply_offset >= ctl_reply_size) - ctlconn_cleanup(); +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; } |