klibc-utils: add dmesg

read and/or clear kernel message ring buffer

Signed-off-by: Kyle McMartin <kyle@parisc-linux.org>
Signed-off-by: maximilian attems <max@stro.at>
diff --git a/usr/utils/Kbuild b/usr/utils/Kbuild
index 4ce17be..09157a8 100644
--- a/usr/utils/Kbuild
+++ b/usr/utils/Kbuild
@@ -4,7 +4,7 @@
 
 progs := chroot dd mkdir mkfifo mknod mount pivot_root umount
 progs += true false sleep ln nuke minips cat
-progs += insmod uname halt kill readlink cpio sync
+progs += insmod uname halt kill readlink cpio sync dmesg
 
 static-y := $(addprefix static/, $(progs))
 shared-y := $(addprefix shared/, $(progs))
@@ -14,6 +14,8 @@
 shared/chroot-y     := chroot.o
 static/dd-y         := dd.o
 shared/dd-y         := dd.o
+static/dmesg-y      := dmesg.o
+shared/dmesg-y      := dmesg.o
 static/mkdir-y      := mkdir.o file_mode.o
 shared/mkdir-y      := mkdir.o file_mode.o
 static/mkfifo-y     := mkfifo.o file_mode.o
diff --git a/usr/utils/dmesg.c b/usr/utils/dmesg.c
new file mode 100644
index 0000000..5369c03
--- /dev/null
+++ b/usr/utils/dmesg.c
@@ -0,0 +1,71 @@
+#include <unistd.h>
+#include <errno.h>
+#include <stdio.h>
+#include <ctype.h>
+#include <stdlib.h>
+
+static void usage(char *name)
+{
+	fprintf(stderr, "usage: %s [-c]\n", name);
+}
+
+int main(int argc, char *argv[])
+{
+	char *buf = NULL;
+	int bufsz = 0;
+	int cmd = 3;	/* Read all messages remaining in the ring buffer */
+	int len = 0;
+	int opt;
+	int i = 0;
+
+	while ((opt = getopt(argc, argv, "c")) != -1) {
+		switch(opt) {
+		/* Read and clear all messages remaining in the ring buffer */
+		case 'c':
+			cmd = 4;
+			break;
+		case '?':
+		default:
+			usage(argv[0]);
+			exit(1);
+		}
+	}
+
+	if (!bufsz) {
+		len = klogctl(10, NULL, 0);	/* Return size of the log buffer */
+		if (len > 0)
+			bufsz = len;
+	}
+
+	if (bufsz) {
+		int sz = bufsz + 8;
+
+		buf = (char *)malloc(sz);
+		len = klogctl(cmd, buf, sz);
+	}
+
+	if (len < 0) {
+		perror("klogctl");
+		exit(1);
+	}
+
+	while (buf[i] && i < len)
+		switch (buf[i]) {
+		case '<':
+			if (i == 0 || buf[i-1] == '\n')	
+				i++;
+		case '0' ... '9':
+			if (i > 0 && buf[i-1] == '<')	
+				i++;
+		case '>':
+			if (i > 0 && isdigit(buf[i-1]))
+				i++;
+		default:
+			putchar(buf[i++]);
+		}
+
+	if (buf[i-1] != '\n')
+		putchar('\n');
+
+	return 0;
+}