summaryrefslogtreecommitdiffstats
path: root/sys-utils/dmesg.c
blob: 49fd707abf8f10f2c0a781ecf4b31bca8fcbfc59 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
/* dmesg.c -- Print out the contents of the kernel ring buffer
 * Created: Sat Oct  9 16:19:47 1993
 * Revised: Thu Oct 28 21:52:17 1993 by faith@cs.unc.edu
 * Copyright 1993 Theodore Ts'o (tytso@athena.mit.edu)
 * This program comes with ABSOLUTELY NO WARRANTY.
 * Modifications by Rick Sladkey (jrs@world.std.com)
 * Larger buffersize 3 June 1998 by Nicolai Langfeldt, based on a patch
 * by Peeter Joot.  This was also suggested by John Hudson.
 * 1999-02-22 Arkadiusz Mi¶kiewicz <misiek@pld.ORG.PL>
 * - added Native Language Support
 *
 */

/*
 * Commands to sys_syslog:
 *
 *      0 -- Close the log.  Currently a NOP.
 *      1 -- Open the log. Currently a NOP.
 *      2 -- Read from the log.
 *      3 -- Read all messages remaining in the ring buffer.
 *      4 -- Read and clear all messages remaining in the ring buffer
 *      5 -- Clear ring buffer.
 *      6 -- Disable printk's to console
 *      7 -- Enable printk's to console
 *      8 -- Set level of messages printed to console
 *      9 -- Return number of unread characters in the log buffer
 *           [supported since 2.4.10]
 *
 * Only function 3 is allowed to non-root processes.
 */

#include <linux/unistd.h>
#include <stdio.h>
#include <getopt.h>
#include <stdlib.h>
#include <sys/klog.h>

#include "nls.h"
#include "strutils.h"

static char *progname;

static void
usage(void) {
	fprintf(stderr,
		_("Usage: %s [-c] [-n level] [-r] [-s bufsize]\n"), progname);
}

int
main(int argc, char *argv[]) {
	char *buf;
	int  sz;
	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;

	setlocale(LC_ALL, "");
	bindtextdomain(PACKAGE, LOCALEDIR);
	textdomain(PACKAGE);

	progname = argv[0];
	while ((c = getopt(argc, argv, "crn:s:")) != -1) {
		switch (c) {
		case 'c':
			cmd = 4;	/* Read and clear all messages */
			break;
		case 'n':
			cmd = 8;	/* Set level of messages */
			level = strtol_or_err(optarg, _("failed to parse level"));
			break;
		case 'r':
			raw = 1;
			break;
		case 's':
			bufsize = strtol_or_err(optarg, _("failed to parse buffer size"));
			if (bufsize < 4096)
				bufsize = 4096;
			break;
		case '?':
		default:
			usage();
			exit(EXIT_FAILURE);
		}
	}
	argc -= optind;
	argv += optind;

	if (argc > 1) {
		usage();
		exit(EXIT_FAILURE);
	}

	if (cmd == 8) {
		n = klogctl(cmd, NULL, level);
		if (n < 0) {
			perror("klogctl");
			exit(EXIT_FAILURE);
		}
		exit(EXIT_SUCCESS);
	}

	if (!bufsize) {
		n = klogctl(10, NULL, 0);	/* read ringbuffer size */
		if (n > 0)
			bufsize = n;
	}

	if (bufsize) {
		sz = bufsize + 8;
		buf = (char *) malloc(sz * sizeof(char));
		n = klogctl(cmd, buf, sz);
	} else {
		sz = 16392;
		while (1) {
			buf = (char *) malloc(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) {
		perror("klogctl");
		exit(EXIT_FAILURE);
	}

	lastc = '\n';
	for (i = 0; i < n; i++) {
		if (!raw && (i == 0 || buf[i - 1] == '\n') && buf[i] == '<') {
			i++;
			while (buf[i] >= '0' && buf[i] <= '9')
				i++;
			if (buf[i] == '>')
				i++;
		}
		lastc = buf[i];
		putchar(lastc);
	}
	if (lastc != '\n')
		putchar('\n');
	free(buf);
	return 0;
}