[PATCH 1/1] dmesg: adds the ability to "follow" the klog ring buffer

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



adds the "-f" option to dmesg, which allows an underpriviledged
user to "follow" the kernel ring buffer, outputting new messages as they
appear.  this is done non-destructively so that the current buffer remains
after execution.

this also changes the log output to be by-line instead of by-character,
and saves the last line printed on each read of the buffer.  if looping,
it will then read the buffer again, but not output until it finds the last
line that it printed.
---
 sys-utils/dmesg.1 |    4 ++
 sys-utils/dmesg.c |  147 ++++++++++++++++++++++++++++++++++++++++------------
 2 files changed, 117 insertions(+), 34 deletions(-)

diff --git a/sys-utils/dmesg.1 b/sys-utils/dmesg.1
index d7af1da..bbdd462 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,9 @@ 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.
+.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..3342b80 100644
--- a/sys-utils/dmesg.c
+++ b/sys-utils/dmesg.c
@@ -35,6 +35,8 @@
 #include <stdlib.h>
 #include <sys/klog.h>
 #include <ctype.h>
+#include <signal.h>
+#include <unistd.h>

 #include "c.h"
 #include "nls.h"
@@ -44,34 +46,55 @@
 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);

 }

+typedef void (*sighandler_t)(int);
+static int follow_loop = 0;
+static void follow_sighandler(int signum) {
+	switch (signum) {
+	case SIGINT:
+		if(follow_loop) {
+			printf("\n");
+			follow_loop = 0;
+		}
+		break;
+	default:
+		break;
+	}
+}
+
 int main(int argc, char *argv[])
 {
 	char *buf = NULL;
 	int  sz;
 	int  bufsize = 0;
-	int  i;
+	int  i, j;
 	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;
+	char* last_line = NULL;
+	char* this_line = NULL;
+	sighandler_t prev_sighandler;

 	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':
+			follow = 1;
+			break;
 		case 'n':
 			cmd = 8;	/* Set level of messages */
 			level = strtol_or_err(optarg, _("failed to parse level"));
@@ -103,49 +126,105 @@ int main(int argc, char *argv[])
 		return EXIT_SUCCESS;
 	}

+	if (follow) {
+		cmd = 3; // override command to just print the buffer
+		follow_loop = 1;
+		prev_sighandler = signal(SIGINT, follow_sighandler);
+	}
+
 	if (!bufsize) {
 		n = klogctl(10, NULL, 0);	/* read ringbuffer size */
 		if (n > 0)
 			bufsize = n;
 	}

-	if (bufsize) {
-		sz = bufsize + 8;
-		buf = xmalloc(sz * sizeof(char));
-		n = klogctl(cmd, buf, sz);
-	} else {
-		sz = 16392;
-		while (1) {
+	do {
+		if (bufsize) {
+			sz = bufsize + 8;
 			buf = xmalloc(sz * sizeof(char));
-			n = klogctl(3, buf, sz);	/* read only */
-			if (n != sz || sz > (1 << 28))
-				break;
-			free(buf);
-			sz *= 4;
+			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;
+				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"));
+		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] == '>')
+		this_line = xmalloc(n * sizeof(char));
+		for (i = 0, j = 0; i < n; i++) {
+			if (!raw && (i == 0 || buf[i - 1] == '\n') && buf[i] == '<') {
 				i++;
+				while (isdigit(buf[i]))
+					i++;
+				if (buf[i] == '>')
+					i++;
+			}
+			this_line[j] = buf[i];
+
+			if (this_line[j] == '\n') {
+				this_line[j] = '\0';
+				if (last_line) {
+					if (!strcmp(last_line, this_line)) {
+						free(last_line);
+						last_line = NULL;
+					}
+				} else
+					printf("%s\n", this_line);
+
+				j = 0;
+			} else
+				j++;
+		}
+
+		// if we have stale data to print, then print it!
+		if (j && !last_line) {
+			this_line[j] = '\0';
+			printf("%s\n", this_line);
+		}
+
+		free(buf);
+
+		if (last_line) {
+			/* we traversed the whole log and never found
+			 * the last line, so we didn't output anything.
+			 * we clear last_line now so that next time we
+			 * print the whole log */
+			free(last_line);
+			last_line = NULL;
+
+			/* free this_line as well */
+			free(this_line);
+			this_line = NULL;
+		} else {
+			last_line = this_line;
+			this_line = NULL;
 		}
-		lastc = buf[i];
-		putchar(lastc);
+		usleep(200);
+
+	} while (follow_loop);
+
+	if (follow) {
+		if (last_line) {
+			free(last_line);
+			last_line = NULL;
+		}
+
+		if (prev_sighandler)
+			signal(SIGINT, prev_sighandler);
+		else
+			signal(SIGINT, SIG_DFL);
 	}
-	if (lastc != '\n')
-		putchar('\n');
-	free(buf);

 	return EXIT_SUCCESS;
 }
--
To unsubscribe from this list: send the line "unsubscribe util-linux" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[Index of Archives]     [Netdev]     [Ethernet Bridging]     [Linux Wireless]     [Kernel Newbies]     [Security]     [Linux for Hams]     [Netfilter]     [Bugtraq]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux RAID]     [Linux Admin]     [Samba]

  Powered by Linux