The modified patch looks good to me. I'm not sure how to get around the whole klogctl(2, ) incomplete output issue. I'm not too familiar with the overhead question about klogctl vs open(/proc/klog) + read(). Are you referring to that open() causes the kernel to call klogctl instead of having to route the syscall thorugh glibc? I know that they both are logically equivalent, so I guess I'll leave that call up to you since you seem to be more knowledgeable about it. ~Austen On Wed, May 4, 2011 at 07:43, Karel Zak <kzak@xxxxxxxxxx> wrote: > On Tue, May 03, 2011 at 09:14:41AM -0500, Austen Dicken wrote: >> > Then you can use klogctl(2, ...). It waits until the kernel log buffer >> > is non-empty, so the last_line and usleep() will be unnecessary, and >> > the implementation will be pretty simple. >> >> Agreed. ÂI have decided to change the patch to function this way, >> which simplifies things >> immensely. > > Unfortunately, it seems that SYSLOG_ACTION_READ (aka klogctl(2, ...)) > is not ideal solution too. Sorry. > > The output is incomplete if another process(e.g. syslog daemon) is > reading the buffer. The buffer (and index into the buffer) is shared > for all processes, so it's possible to read the information only once. > For more details see kernel/printk.c (log_start index) in kernel > sources. > > Anyway for debugging or on some non-standard boxes the '-f' option > could be still usable. I'd like to add --level= and --facility= > options, so dmesg(1) should be definitely better than the "cat > /proc/kmsg" command. > > I did some changes to the patch to minimize overhead, see below. Maybe > it would be better to use open(/proc/kmsg) + read() instead of > klogctl(2, ...) for the -f option to minimize overhead in glibc. > > Comments? > >  ÂKarel > > > From 8e2ae5130c8f03e8ab6e28f194e409f8c322daf8 Mon Sep 17 00:00:00 2001 > From: Austen Dicken <cvpcsm@xxxxxxxxx> > Date: Tue, 3 May 2011 09:14:41 -0500 > Subject: [PATCH] dmesg: adds the ability to "follow" (-f) the klog ring buffer > > Co-Author: Karel Zak <kzak@xxxxxxxxxx> > Signed-off-by: Austen Dicken <cvpcsm@xxxxxxxxx> > Signed-off-by: Karel Zak <kzak@xxxxxxxxxx> > --- > Âsys-utils/dmesg.1 |  Â5 +++ > Âsys-utils/dmesg.c |  88 ++++++++++++++++++++++++++++++----------------------- > Â2 files changed, 55 insertions(+), 38 deletions(-) > > diff --git a/sys-utils/dmesg.1 b/sys-utils/dmesg.1 > index d7af1da..9b4471d 100644 > --- a/sys-utils/dmesg.1 > +++ b/sys-utils/dmesg.1 > @@ -6,6 +6,7 @@ dmesg \- print or control the kernel ring buffer > Â.SH SYNOPSIS > Â.B dmesg > Â.RB [ \-c ] > +.RB [ \-f ] > Â.RB [ \-r ] > Â.RB [ \-n > Â.IR level ] > @@ -28,6 +29,10 @@ file to whoever can debug their problem. > Â.B \-c > ÂClear the ring buffer contents after printing. > Â.TP > +.B \-f > +Output ring buffer contents as they are added. The output could be incomplete > +if another process (e.g. syslog daemon) is reading the kernel log buffer. > +.TP > Â.B \-r > ÂPrint the raw message buffer, i.e., don't strip the log level prefixes. > Â.TP > diff --git a/sys-utils/dmesg.c b/sys-utils/dmesg.c > index c3e5659..2f6b30e 100644 > --- a/sys-utils/dmesg.c > +++ b/sys-utils/dmesg.c > @@ -40,38 +40,41 @@ > Â#include "nls.h" > Â#include "strutils.h" > Â#include "xalloc.h" > +#include "writeall.h" > > Âstatic void __attribute__ ((noreturn)) usage(void) > Â{ >    Âfprintf(stderr, > -        _("Usage: %s [-c] [-n level] [-r] [-s bufsize]\n"), > +        _("Usage: %s [-c] [-f] [-n level] [-r] [-s bufsize]\n"), >        Âprogram_invocation_short_name); >    Âexit(EXIT_FAILURE); > - > Â} > > Âint main(int argc, char *argv[]) > Â{ >    Âchar *buf = NULL; > -    int Âsz; > +    int Âsz = 0; >    Âint Âbufsize = 0; > -    int Âi; >    Âint Ân; >    Âint Âc; >    Âint Âlevel = 0; > -    int Âlastc; >    Âint Âcmd = 3;      /* Read all messages in the ring buffer */ >    Âint Âraw = 0; > +    int Âfollow = 0; > >    Âsetlocale(LC_ALL, ""); >    Âbindtextdomain(PACKAGE, LOCALEDIR); >    Âtextdomain(PACKAGE); > > -    while ((c = getopt(argc, argv, "crn:s:")) != -1) { > +    while ((c = getopt(argc, argv, "cfrn:s:")) != -1) { >        Âswitch (c) { >        Âcase 'c': >            Âcmd = 4;    Â/* Read and clear all messages */ >            Âbreak; > +        case 'f': > +            cmd = 2; > +            follow = 1; > +            break; >        Âcase 'n': >            Âcmd = 8;    Â/* Set level of messages */ >            Âlevel = strtol_or_err(optarg, _("failed to parse level")); > @@ -105,46 +108,55 @@ int main(int argc, char *argv[]) > >    Âif (!bufsize) { >        Ân = klogctl(10, NULL, 0);    /* read ringbuffer size */ > -        if (n > 0) > +        if (n > 0) { >            Âbufsize = n; > +            sz = bufsize + 8; > +            buf = xmalloc(sz * sizeof(char)); > +        } >    Â} > > -    if (bufsize) { > -        sz = bufsize + 8; > -        buf = xmalloc(sz * sizeof(char)); > -        n = klogctl(cmd, buf, sz); > -    } else { > -        sz = 16392; > -        while (1) { > -            buf = xmalloc(sz * sizeof(char)); > -            n = klogctl(3, buf, sz);    Â/* read only */ > -            if (n != sz || sz > (1 << 28)) > -                break; > +    do { > +        if (bufsize && sz) > +            n = klogctl(cmd, buf, sz); > +        else { >            Âfree(buf); > -            sz *= 4; > +            sz = 16392; > +            while (1) { > +                buf = xmalloc(sz * sizeof(char)); > +                n = klogctl(3, buf, sz);    Â/* read only */ > +                if (n != sz || sz > (1 << 28)) > +                    break; > +                free(buf); > +                sz *= 4; > +            } > +            if (n > 0 && cmd == 4) > +                n = klogctl(cmd, buf, sz);   Â/* read and clear */ >        Â} > > -        if (n > 0 && cmd == 4) > -            n = klogctl(cmd, buf, sz);   Â/* read and clear */ > -    } > - > -    if (n < 0) > -        err(EXIT_FAILURE, _("klogctl failed")); > - > -    lastc = '\n'; > -    for (i = 0; i < n; i++) { > -        if (!raw && (i == 0 || buf[i - 1] == '\n') && buf[i] == '<') { > -            i++; > -            while (isdigit(buf[i])) > -                i++; > -            if (buf[i] == '>') > -                i++; > +        if (n < 0) > +            err(EXIT_FAILURE, _("klogctl failed")); > +        if (raw) > +            write_all(STDIN_FILENO, buf, n); > +        else { > +            int i; > + > +            for (i = 0; i < n; i++) { > +                if ((i == 0 || buf[i - 1] == '\n') && > +                  buf[i] == '<') { > +                    i++; > +                    while (isdigit(buf[i])) > +                        i++; > +                    if (buf[i] == '>') > +                        i++; > +                } > +                putchar(buf[i]); > +            } >        Â} > -        lastc = buf[i]; > -        putchar(lastc); > -    } > -    if (lastc != '\n') > +    } while (follow); > + > +    if (sz && n > 0 && buf && buf[n - 1] != '\n') >        Âputchar('\n'); > + >    Âfree(buf); > >    Âreturn EXIT_SUCCESS; > -- > 1.7.3.4 > > ÿô.nÇ·®+%˱é¥wÿº{.nÇ·®¶)ÿ)¡Ü}©²ÆzÚj:+v¨þø®w¥þàÞ¨è&¢)ß«a¶Úÿûz¹ÞúÝjÿwèf