~ubuntu-branches/ubuntu/trusty/util-linux/trusty-proposed

« back to all changes in this revision

Viewing changes to sys-utils/dmesg.c

  • Committer: Package Import Robot
  • Author(s): LaMont Jones
  • Date: 2011-11-03 15:38:23 UTC
  • mto: (4.5.5 sid) (1.6.4)
  • mto: This revision was merged to the branch mainline in revision 85.
  • Revision ID: package-import@ubuntu.com-20111103153823-10sx16jprzxlhkqf
ImportĀ upstreamĀ versionĀ 2.20.1

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/* dmesg.c -- Print out the contents of the kernel ring buffer
2
 
 * Created: Sat Oct  9 16:19:47 1993
3
 
 * Revised: Thu Oct 28 21:52:17 1993 by faith@cs.unc.edu
4
 
 * Copyright 1993 Theodore Ts'o (tytso@athena.mit.edu)
 
1
/*
 
2
 * dmesg.c -- Print out the contents of the kernel ring buffer
 
3
 *
 
4
 * Copyright (C) 1993 Theodore Ts'o <tytso@athena.mit.edu>
 
5
 * Copyright (C) 2011 Karel Zak <kzak@redhat.com>
 
6
 *
5
7
 * This program comes with ABSOLUTELY NO WARRANTY.
6
 
 * Modifications by Rick Sladkey (jrs@world.std.com)
7
 
 * Larger buffersize 3 June 1998 by Nicolai Langfeldt, based on a patch
8
 
 * by Peeter Joot.  This was also suggested by John Hudson.
9
 
 * 1999-02-22 Arkadiusz Miļæ½kiewicz <misiek@pld.ORG.PL>
10
 
 * - added Native Language Support
11
 
 *
12
 
 */
13
 
 
14
 
/*
15
 
 * Commands to sys_syslog:
16
 
 *
17
 
 *      0 -- Close the log.  Currently a NOP.
18
 
 *      1 -- Open the log. Currently a NOP.
19
 
 *      2 -- Read from the log.
20
 
 *      3 -- Read all messages remaining in the ring buffer.
21
 
 *      4 -- Read and clear all messages remaining in the ring buffer
22
 
 *      5 -- Clear ring buffer.
23
 
 *      6 -- Disable printk's to console
24
 
 *      7 -- Enable printk's to console
25
 
 *      8 -- Set level of messages printed to console
26
 
 *      9 -- Return number of unread characters in the log buffer
27
 
 *           [supported since 2.4.10]
28
 
 *
29
 
 * Only function 3 is allowed to non-root processes.
30
 
 */
31
 
 
 
8
 */
32
9
#include <linux/unistd.h>
33
10
#include <stdio.h>
34
11
#include <getopt.h>
35
12
#include <stdlib.h>
36
13
#include <sys/klog.h>
 
14
#include <sys/syslog.h>
 
15
#include <sys/time.h>
 
16
#include <sys/sysinfo.h>
 
17
#include <ctype.h>
 
18
#include <time.h>
37
19
 
 
20
#include "c.h"
38
21
#include "nls.h"
39
22
#include "strutils.h"
40
 
 
41
 
static char *progname;
42
 
 
43
 
static void
44
 
usage(void) {
45
 
        fprintf(stderr,
46
 
                _("Usage: %s [-c] [-n level] [-r] [-s bufsize]\n"), progname);
47
 
}
48
 
 
49
 
int
50
 
main(int argc, char *argv[]) {
51
 
        char *buf;
52
 
        int  sz;
 
23
#include "xalloc.h"
 
24
#include "widechar.h"
 
25
#include "writeall.h"
 
26
#include "bitops.h"
 
27
 
 
28
/* Close the log.  Currently a NOP. */
 
29
#define SYSLOG_ACTION_CLOSE          0
 
30
/* Open the log. Currently a NOP. */
 
31
#define SYSLOG_ACTION_OPEN           1
 
32
/* Read from the log. */
 
33
#define SYSLOG_ACTION_READ           2
 
34
/* Read all messages remaining in the ring buffer. (allowed for non-root) */
 
35
#define SYSLOG_ACTION_READ_ALL       3
 
36
/* Read and clear all messages remaining in the ring buffer */
 
37
#define SYSLOG_ACTION_READ_CLEAR     4
 
38
/* Clear ring buffer. */
 
39
#define SYSLOG_ACTION_CLEAR          5
 
40
/* Disable printk's to console */
 
41
#define SYSLOG_ACTION_CONSOLE_OFF    6
 
42
/* Enable printk's to console */
 
43
#define SYSLOG_ACTION_CONSOLE_ON     7
 
44
/* Set level of messages printed to console */
 
45
#define SYSLOG_ACTION_CONSOLE_LEVEL  8
 
46
/* Return number of unread characters in the log buffer */
 
47
#define SYSLOG_ACTION_SIZE_UNREAD    9
 
48
/* Return size of the log buffer */
 
49
#define SYSLOG_ACTION_SIZE_BUFFER   10
 
50
 
 
51
/*
 
52
 * Priority and facility names
 
53
 */
 
54
struct dmesg_name {
 
55
        const char *name;
 
56
        const char *help;
 
57
};
 
58
 
 
59
/*
 
60
 * Priority names -- based on sys/syslog.h
 
61
 */
 
62
static const struct dmesg_name level_names[] =
 
63
{
 
64
        [LOG_EMERG]   = { "emerg", N_("system is unusable") },
 
65
        [LOG_ALERT]   = { "alert", N_("action must be taken immediately") },
 
66
        [LOG_CRIT]    = { "crit",  N_("critical conditions") },
 
67
        [LOG_ERR]     = { "err",   N_("error conditions") },
 
68
        [LOG_WARNING] = { "warn",  N_("warning conditions") },
 
69
        [LOG_NOTICE]  = { "notice",N_("normal but significant condition") },
 
70
        [LOG_INFO]    = { "info",  N_("informational") },
 
71
        [LOG_DEBUG]   = { "debug", N_("debug-level messages") }
 
72
};
 
73
 
 
74
/*
 
75
 * sys/syslog.h uses (f << 3) for all facility codes.
 
76
 * We want to use the codes as array idexes, so shift back...
 
77
 *
 
78
 * Note that libc LOG_FAC() macro returns the base codes, not the
 
79
 * shifted code :-)
 
80
 */
 
81
#define FAC_BASE(f)     ((f) >> 3)
 
82
 
 
83
static const struct dmesg_name facility_names[] =
 
84
{
 
85
        [FAC_BASE(LOG_KERN)]     = { "kern",     N_("kernel messages") },
 
86
        [FAC_BASE(LOG_USER)]     = { "user",     N_("random user-level messages") },
 
87
        [FAC_BASE(LOG_MAIL)]     = { "mail",     N_("mail system") },
 
88
        [FAC_BASE(LOG_DAEMON)]   = { "daemon",   N_("system daemons") },
 
89
        [FAC_BASE(LOG_AUTH)]     = { "auth",     N_("security/authorization messages") },
 
90
        [FAC_BASE(LOG_SYSLOG)]   = { "syslog",   N_("messages generated internally by syslogd") },
 
91
        [FAC_BASE(LOG_LPR)]      = { "lpr",      N_("line printer subsystem") },
 
92
        [FAC_BASE(LOG_NEWS)]     = { "news",     N_("network news subsystem") },
 
93
        [FAC_BASE(LOG_UUCP)]     = { "uucp",     N_("UUCP subsystem") },
 
94
        [FAC_BASE(LOG_CRON)]     = { "cron",     N_("clock daemon") },
 
95
        [FAC_BASE(LOG_AUTHPRIV)] = { "authpriv", N_("security/authorization messages (private)") },
 
96
        [FAC_BASE(LOG_FTP)]      = { "ftp",      N_("ftp daemon") },
 
97
};
 
98
 
 
99
struct dmesg_control {
 
100
        /* bit arrays -- see include/bitops.h */
 
101
        char levels[ARRAY_SIZE(level_names) / NBBY + 1];
 
102
        char facilities[ARRAY_SIZE(facility_names) / NBBY + 1];
 
103
 
 
104
        struct timeval  lasttime;       /* last printed timestamp */
 
105
        time_t          boot_time;      /* system boot time */
 
106
 
 
107
        unsigned int    raw:1,          /* raw mode */
 
108
                        fltr_lev:1,     /* filter out by levels[] */
 
109
                        fltr_fac:1,     /* filter out by facilities[] */
 
110
                        decode:1,       /* use "facility: level: " prefix */
 
111
                        notime:1,       /* don't print timestamp */
 
112
                        delta:1,        /* show time deltas */
 
113
                        ctime:1;        /* show human readable time */
 
114
};
 
115
 
 
116
struct dmesg_record {
 
117
        const char      *mesg;
 
118
        size_t          mesg_size;
 
119
 
 
120
        int             level;
 
121
        int             facility;
 
122
        struct timeval  tv;
 
123
 
 
124
        const char      *next;          /* buffer with next unparsed record */
 
125
        size_t          next_size;      /* size of the next buffer */
 
126
};
 
127
 
 
128
static void __attribute__((__noreturn__)) usage(FILE *out)
 
129
{
 
130
        size_t i;
 
131
 
 
132
        fputs(_("\nUsage:\n"), out);
 
133
        fprintf(out,
 
134
              _(" %s [options]\n"), program_invocation_short_name);
 
135
 
 
136
        fputs(_("\nOptions:\n"), out);
 
137
        fputs(_(" -C, --clear                 clear the kernel ring buffer\n"
 
138
                " -c, --read-clear            read and clear all messages\n"
 
139
                " -D, --console-off           disable printing messages to console\n"
 
140
                " -d, --show-delta            show time delta between printed messages\n"
 
141
                " -E, --console-on            enable printing messages to console\n"
 
142
                " -f, --facility <list>       restrict output to defined facilities\n"
 
143
                " -h, --help                  display this help and exit\n"
 
144
                " -k, --kernel                display kernel messages\n"
 
145
                " -l, --level <list>          restrict output to defined levels\n"
 
146
                " -n, --console-level <level> set level of messages printed to console\n"
 
147
                " -r, --raw                   print the raw message buffer\n"
 
148
                " -s, --buffer-size <size>    buffer size to query the kernel ring buffer\n"
 
149
                " -T, --ctime                 show human readable timestamp (could be \n"
 
150
                "                             inaccurate if you have used SUSPEND/RESUME)\n"
 
151
                " -t, --notime                don't print messages timestamp\n"
 
152
                " -u, --userspace             display userspace messages\n"
 
153
                " -V, --version               output version information and exit\n"
 
154
                " -x, --decode                decode facility and level to readable string\n"), out);
 
155
 
 
156
        fputs(_("\nSupported log facilities:\n"), out);
 
157
        for (i = 0; i < ARRAY_SIZE(level_names); i++) {
 
158
                fprintf(stderr, " %7s - %s\n",
 
159
                                facility_names[i].name,
 
160
                                _(facility_names[i].help));
 
161
        }
 
162
 
 
163
        fputs(_("\nSupported log levels (priorities):\n"), out);
 
164
        for (i = 0; i < ARRAY_SIZE(level_names); i++) {
 
165
                fprintf(stderr, " %7s - %s\n",
 
166
                                level_names[i].name,
 
167
                                _(level_names[i].help));
 
168
        }
 
169
 
 
170
        fputc('\n', out);
 
171
 
 
172
        exit(out == stderr ? EXIT_FAILURE : EXIT_SUCCESS);
 
173
}
 
174
 
 
175
/*
 
176
 * LEVEL     ::= <number> | <name>
 
177
 *  <number> ::= number in range <0..N>, where N < ARRAY_SIZE(level_names)
 
178
 *  <name>   ::= case-insensitive text
 
179
 */
 
180
static int parse_level(const char *str, size_t len)
 
181
{
 
182
        if (!str)
 
183
                return -1;
 
184
        if (!len)
 
185
                len = strlen(str);
 
186
        errno = 0;
 
187
 
 
188
        if (isdigit(*str)) {
 
189
                char *end = NULL;
 
190
                long x = strtol(str, &end, 10);
 
191
 
 
192
                if (!errno && end && end > str && (size_t) (end - str) == len &&
 
193
                    x >= 0 && (size_t) x < ARRAY_SIZE(level_names))
 
194
                        return x;
 
195
        } else {
 
196
                size_t i;
 
197
 
 
198
                for (i = 0; i < ARRAY_SIZE(level_names); i++) {
 
199
                        const char *n = level_names[i].name;
 
200
 
 
201
                        if (strncasecmp(str, n, len) == 0 && *(n + len) == '\0')
 
202
                                return i;
 
203
                }
 
204
        }
 
205
 
 
206
        if (errno)
 
207
                err(EXIT_FAILURE, _("failed to parse level '%s'"), str);
 
208
 
 
209
        errx(EXIT_FAILURE, _("unknown level '%s'"), str);
 
210
        return -1;
 
211
}
 
212
 
 
213
/*
 
214
 * FACILITY  ::= <number> | <name>
 
215
 *  <number> ::= number in range <0..N>, where N < ARRAY_SIZE(facility_names)
 
216
 *  <name>   ::= case-insensitive text
 
217
 */
 
218
static int parse_facility(const char *str, size_t len)
 
219
{
 
220
        if (!str)
 
221
                return -1;
 
222
        if (!len)
 
223
                len = strlen(str);
 
224
        errno = 0;
 
225
 
 
226
        if (isdigit(*str)) {
 
227
                char *end = NULL;
 
228
                long x = strtol(str, &end, 10);
 
229
 
 
230
                if (!errno && end && end > str && (size_t) (end - str) == len &&
 
231
                    x >= 0 && (size_t) x < ARRAY_SIZE(facility_names))
 
232
                        return x;
 
233
        } else {
 
234
                size_t i;
 
235
 
 
236
                for (i = 0; i < ARRAY_SIZE(facility_names); i++) {
 
237
                        const char *n = facility_names[i].name;
 
238
 
 
239
                        if (strncasecmp(str, n, len) == 0 && *(n + len) == '\0')
 
240
                                return i;
 
241
                }
 
242
        }
 
243
 
 
244
        if (errno)
 
245
                err(EXIT_FAILURE, _("failed to parse facility '%s'"), str);
 
246
 
 
247
        errx(EXIT_FAILURE, _("unknown facility '%s'"), str);
 
248
        return -1;
 
249
}
 
250
 
 
251
/*
 
252
 * Parses numerical prefix used for all messages in kernel ring buffer.
 
253
 *
 
254
 * Priorities/facilities are encoded into a single 32-bit quantity, where the
 
255
 * bottom 3 bits are the priority (0-7) and the top 28 bits are the facility
 
256
 * (0-big number).
 
257
 *
 
258
 * Note that the number has to end with '>' char.
 
259
 */
 
260
static const char *parse_faclev(const char *str, int *fac, int *lev)
 
261
{
 
262
        long num;
 
263
        char *end = NULL;
 
264
 
 
265
        if (!str)
 
266
                return str;
 
267
 
 
268
        errno = 0;
 
269
        num = strtol(str, &end, 10);
 
270
 
 
271
        if (!errno && end && end > str) {
 
272
                *fac = LOG_FAC(num);
 
273
                *lev = LOG_PRI(num);
 
274
 
 
275
                if (*lev < 0 || (size_t) *lev > ARRAY_SIZE(level_names))
 
276
                        *lev = -1;
 
277
                if (*fac < 0 || (size_t) *fac > ARRAY_SIZE(facility_names))
 
278
                        *fac = -1;
 
279
                return end + 1;         /* skip '<' */
 
280
        }
 
281
 
 
282
        return str;
 
283
}
 
284
 
 
285
static const char *parse_timestamp(const char *str0, struct timeval *tv)
 
286
{
 
287
        const char *str = str0;
 
288
        char *end = NULL;
 
289
 
 
290
        if (!str0)
 
291
                return str0;
 
292
 
 
293
        errno = 0;
 
294
        tv->tv_sec = strtol(str, &end, 10);
 
295
 
 
296
        if (!errno && end && *end == '.' && *(end + 1)) {
 
297
                str = end + 1;
 
298
                end = NULL;
 
299
                tv->tv_usec = strtol(str, &end, 10);
 
300
        }
 
301
        if (errno || !end || end == str || *end != ']')
 
302
                return str0;
 
303
 
 
304
        return end + 1; /* skip ']' */
 
305
}
 
306
 
 
307
 
 
308
static double time_diff(struct timeval *a, struct timeval *b)
 
309
{
 
310
        return (a->tv_sec - b->tv_sec) + (a->tv_usec - b->tv_usec) / 1E6;
 
311
}
 
312
 
 
313
static int get_buffer_size()
 
314
{
 
315
        int n = klogctl(SYSLOG_ACTION_SIZE_BUFFER, NULL, 0);
 
316
 
 
317
        return n > 0 ? n : 0;
 
318
}
 
319
 
 
320
static time_t get_boot_time(void)
 
321
{
 
322
        struct sysinfo info;
 
323
        struct timeval tv;
 
324
 
 
325
        if (sysinfo(&info) != 0)
 
326
                warn(_("sysinfo failed"));
 
327
        else if (gettimeofday(&tv, NULL) != 0)
 
328
                warn(_("gettimeofday failed"));
 
329
        else
 
330
                return tv.tv_sec -= info.uptime;
 
331
        return 0;
 
332
}
 
333
 
 
334
/*
 
335
 * Reads messages from kernel ring buffer
 
336
 */
 
337
static int read_buffer(char **buf, size_t bufsize, int clear)
 
338
{
 
339
        size_t sz;
 
340
        int rc = -1;
 
341
        int cmd = clear ? SYSLOG_ACTION_READ_CLEAR :
 
342
                          SYSLOG_ACTION_READ_ALL;
 
343
 
 
344
        if (bufsize) {
 
345
                sz = bufsize + 8;
 
346
                *buf = xmalloc(sz * sizeof(char));
 
347
                rc = klogctl(cmd, *buf, sz);
 
348
        } else {
 
349
                sz = 16392;
 
350
                while (1) {
 
351
                        *buf = xmalloc(sz * sizeof(char));
 
352
                        rc = klogctl(SYSLOG_ACTION_READ_ALL, *buf, sz);
 
353
                        if (rc < 0)
 
354
                                break;
 
355
                        if ((size_t) rc != sz || sz > (1 << 28))
 
356
                                break;
 
357
                        free(*buf);
 
358
                        *buf = NULL;
 
359
                        sz *= 4;
 
360
                }
 
361
 
 
362
                if (rc > 0 && clear)
 
363
                        rc = klogctl(SYSLOG_ACTION_READ_CLEAR, *buf, sz);
 
364
        }
 
365
 
 
366
        return rc;
 
367
}
 
368
 
 
369
static int fwrite_hex(const char *buf, size_t size, FILE *out)
 
370
{
 
371
        size_t i;
 
372
 
 
373
        for (i = 0; i < size; i++) {
 
374
                int rc = fprintf(out, "\\x%02x", buf[i]);
 
375
                if (rc < 0)
 
376
                        return rc;
 
377
        }
 
378
        return 0;
 
379
}
 
380
 
 
381
/*
 
382
 * Prints to 'out' and non-printable chars are replaced with \x<hex> sequences.
 
383
 */
 
384
static void safe_fwrite(const char *buf, size_t size, FILE *out)
 
385
{
 
386
        size_t i;
 
387
#ifdef HAVE_WIDECHAR
 
388
        mbstate_t s;
 
389
        memset(&s, 0, sizeof (s));
 
390
#endif
 
391
        for (i = 0; i < size; i++) {
 
392
                const char *p = buf + i;
 
393
                int rc, hex = 0;
 
394
 
 
395
#ifdef HAVE_WIDECHAR
 
396
                wchar_t wc;
 
397
                size_t len = mbrtowc(&wc, p, size - i, &s);
 
398
 
 
399
                if (len == 0)                           /* L'\0' */
 
400
                        return;
 
401
 
 
402
                if (len == (size_t)-1 || len == (size_t)-2) {           /* invalid sequence */
 
403
                        memset(&s, 0, sizeof (s));
 
404
                        len = hex = 1;
 
405
 
 
406
                } else if (len > 1 && !iswprint(wc)) {  /* non-printable multibyte */
 
407
                        hex = 1;
 
408
                } else
 
409
#endif
 
410
                {
 
411
                        if (!isprint((unsigned int) *p) &&
 
412
                            !isspace((unsigned int) *p))                /* non-printable */
 
413
                                hex = 1;
 
414
                }
 
415
                if (hex)
 
416
                        rc = fwrite_hex(p, len, out);
 
417
                else
 
418
                        rc = fwrite(p, 1, len, out) != len;
 
419
                if (rc != 0)
 
420
                        err(EXIT_FAILURE, _("write failed"));
 
421
        }
 
422
}
 
423
 
 
424
static int get_next_record(struct dmesg_control *ctl, struct dmesg_record *rec)
 
425
{
 
426
        size_t i;
 
427
        const char *begin = NULL;
 
428
 
 
429
        if (!rec->next || !rec->next_size)
 
430
                return 1;
 
431
 
 
432
        rec->mesg = NULL;
 
433
        rec->mesg_size = 0;
 
434
        rec->facility = -1;
 
435
        rec->level = -1;
 
436
        rec->tv.tv_sec = 0;
 
437
        rec->tv.tv_usec = 0;
 
438
 
 
439
        for (i = 0; i < rec->next_size; i++) {
 
440
                const char *p = rec->next + i;
 
441
                const char *end = NULL;
 
442
 
 
443
                if (!begin)
 
444
                        begin = p;
 
445
                if (i + 1 == rec->next_size) {
 
446
                        end = p + 1;
 
447
                        i++;
 
448
                } else if (*p == '\n' && *(p + 1) == '<')
 
449
                        end = p;
 
450
 
 
451
                if (begin && !*begin)
 
452
                        begin = NULL;   /* zero(s) at the end of the buffer? */
 
453
                if (!begin || !end)
 
454
                        continue;
 
455
                if (end <= begin)
 
456
                        continue;       /* error or empty line? */
 
457
 
 
458
                if (*begin == '<') {
 
459
                        if (ctl->fltr_lev || ctl->fltr_fac || ctl->decode) {
 
460
                                begin = parse_faclev(begin + 1, &rec->facility,
 
461
                                                     &rec->level);
 
462
                        } else {
 
463
                                /* ignore facility and level */
 
464
                                while (begin < end) {
 
465
                                        begin++;
 
466
                                        if (*(begin - 1) == '>')
 
467
                                                break;
 
468
                                }
 
469
                        }
 
470
                }
 
471
 
 
472
                if (*begin == '[' && (*(begin + 1) == ' ' ||
 
473
                                      isdigit(*(begin + 1)))) {
 
474
                        if (ctl->delta || ctl->ctime) {
 
475
                                begin = parse_timestamp(begin + 1, &rec->tv);
 
476
                        } else if (ctl->notime) {
 
477
                                while (begin < end) {
 
478
                                        begin++;
 
479
                                        if (*(begin - 1) == ']')
 
480
                                                break;
 
481
                                }
 
482
                        }
 
483
                        if (begin < end && *begin == ' ')
 
484
                                begin++;
 
485
                }
 
486
 
 
487
                rec->mesg = begin;
 
488
                rec->mesg_size = end - begin;
 
489
 
 
490
                rec->next_size -= end - rec->next;
 
491
                rec->next = rec->next_size > 0 ? end + 1 : NULL;
 
492
                if (rec->next_size > 0)
 
493
                        rec->next_size--;
 
494
 
 
495
                return 0;
 
496
        }
 
497
 
 
498
        return 1;
 
499
}
 
500
 
 
501
static int accept_record(struct dmesg_control *ctl, struct dmesg_record *rec)
 
502
{
 
503
        if (ctl->fltr_lev && (rec->facility < 0 ||
 
504
                              !isset(ctl->levels, rec->level)))
 
505
                return 0;
 
506
 
 
507
        if (ctl->fltr_fac && (rec->facility < 0 ||
 
508
                              !isset(ctl->facilities, rec->facility)))
 
509
                return 0;
 
510
 
 
511
        return 1;
 
512
}
 
513
 
 
514
/*
 
515
 * Prints the 'buf' kernel ring buffer; the messages are filtered out according
 
516
 * to 'levels' and 'facilities' bitarrays.
 
517
 */
 
518
static void print_buffer(const char *buf, size_t size,
 
519
                         struct dmesg_control *ctl)
 
520
{
 
521
        struct dmesg_record rec = { .next = buf, .next_size = size };
 
522
        char tbuf[256];
 
523
 
 
524
        if (ctl->raw) {
 
525
                /* print whole buffer */
 
526
                safe_fwrite(buf, size, stdout);
 
527
                if (buf[size - 1] != '\n')
 
528
                        putchar('\n');
 
529
                return;
 
530
        }
 
531
 
 
532
        while (get_next_record(ctl, &rec) == 0) {
 
533
 
 
534
                if (!accept_record(ctl, &rec))
 
535
                        continue;
 
536
 
 
537
                if (!rec.mesg_size) {
 
538
                        putchar('\n');
 
539
                        continue;
 
540
                }
 
541
 
 
542
                if (ctl->decode && rec.level >= 0 && rec.facility >= 0)
 
543
                        printf("%-6s:%-6s: ", facility_names[rec.facility].name,
 
544
                                              level_names[rec.level].name);
 
545
 
 
546
                *tbuf = '\0';
 
547
                if (ctl->ctime) {
 
548
                        time_t t = ctl->boot_time + rec.tv.tv_sec;
 
549
                        if (strftime(tbuf, sizeof(tbuf), "%a %b %e %H:%M:%S %Y",
 
550
                                     localtime(&t)) == 0)
 
551
                                *tbuf = '\0';
 
552
                }
 
553
                if (ctl->delta) {
 
554
                        double delta = 0;
 
555
 
 
556
                        if (timerisset(&ctl->lasttime))
 
557
                                delta = time_diff(&rec.tv, &ctl->lasttime);
 
558
                        ctl->lasttime = rec.tv;
 
559
 
 
560
                        if (ctl->ctime && *tbuf)
 
561
                                printf("[%s ", tbuf);
 
562
                        else if (ctl->notime)
 
563
                                putchar('[');
 
564
                        else
 
565
                                printf("[%5d.%06d ", (int) rec.tv.tv_sec,
 
566
                                                     (int) rec.tv.tv_usec);
 
567
                        printf("<%12.06f>] ", delta);
 
568
                } else if (ctl->ctime && *tbuf) {
 
569
                        printf("[%s] ", tbuf);
 
570
                }
 
571
 
 
572
                safe_fwrite(rec.mesg, rec.mesg_size, stdout);
 
573
 
 
574
                if (*(rec.mesg + rec.mesg_size - 1) != '\n')
 
575
                        putchar('\n');
 
576
        }
 
577
}
 
578
 
 
579
int main(int argc, char *argv[])
 
580
{
 
581
        char *buf = NULL;
53
582
        int  bufsize = 0;
54
 
        int  i;
55
583
        int  n;
56
584
        int  c;
57
 
        int  level = 0;
58
 
        int  lastc;
59
 
        int  cmd = 3;           /* Read all messages in the ring buffer */
60
 
        int  raw = 0;
 
585
        int  console_level = 0;
 
586
        int  cmd = -1;
 
587
        static struct dmesg_control ctl;
 
588
 
 
589
        static const struct option longopts[] = {
 
590
                { "buffer-size",   required_argument, NULL, 's' },
 
591
                { "clear",         no_argument,       NULL, 'C' },
 
592
                { "console-level", required_argument, NULL, 'n' },
 
593
                { "console-off",   no_argument,       NULL, 'D' },
 
594
                { "console-on",    no_argument,       NULL, 'E' },
 
595
                { "decode",        no_argument,       NULL, 'x' },
 
596
                { "facility",      required_argument, NULL, 'f' },
 
597
                { "help",          no_argument,       NULL, 'h' },
 
598
                { "kernel",        no_argument,       NULL, 'k' },
 
599
                { "level",         required_argument, NULL, 'l' },
 
600
                { "raw",           no_argument,       NULL, 'r' },
 
601
                { "read-clear",    no_argument,       NULL, 'c' },
 
602
                { "show-delta",    no_argument,       NULL, 'd' },
 
603
                { "ctime",         no_argument,       NULL, 'T' },
 
604
                { "notime",        no_argument,       NULL, 't' },
 
605
                { "userspace",     no_argument,       NULL, 'u' },
 
606
                { "version",       no_argument,       NULL, 'V' },
 
607
                { NULL,            0, NULL, 0 }
 
608
        };
61
609
 
62
610
        setlocale(LC_ALL, "");
63
611
        bindtextdomain(PACKAGE, LOCALEDIR);
64
612
        textdomain(PACKAGE);
65
613
 
66
 
        progname = argv[0];
67
 
        while ((c = getopt(argc, argv, "crn:s:")) != -1) {
 
614
        while ((c = getopt_long(argc, argv, "CcDdEf:hkl:n:rs:TtuVx",
 
615
                                longopts, NULL)) != -1) {
 
616
 
 
617
                if (cmd != -1 && strchr("CcnDE", c))
 
618
                        errx(EXIT_FAILURE, _("clear, read-clear, console-level, "
 
619
                             "console-on, and console-off options are mutually "
 
620
                             "exclusive"));
 
621
 
68
622
                switch (c) {
 
623
                case 'C':
 
624
                        cmd = SYSLOG_ACTION_CLEAR;
 
625
                        break;
69
626
                case 'c':
70
 
                        cmd = 4;        /* Read and clear all messages */
 
627
                        cmd = SYSLOG_ACTION_READ_CLEAR;
 
628
                        break;
 
629
                case 'D':
 
630
                        cmd = SYSLOG_ACTION_CONSOLE_OFF;
 
631
                        break;
 
632
                case 'd':
 
633
                        ctl.delta = 1;
 
634
                        break;
 
635
                case 'E':
 
636
                        cmd = SYSLOG_ACTION_CONSOLE_ON;
 
637
                        break;
 
638
                case 'f':
 
639
                        ctl.fltr_fac = 1;
 
640
                        if (string_to_bitarray(optarg,
 
641
                                             ctl.facilities, parse_facility) < 0)
 
642
                                return EXIT_FAILURE;
 
643
                        break;
 
644
                case 'h':
 
645
                        usage(stdout);
 
646
                        break;
 
647
                case 'k':
 
648
                        ctl.fltr_fac = 1;
 
649
                        setbit(ctl.facilities, FAC_BASE(LOG_KERN));
 
650
                        break;
 
651
                case 'l':
 
652
                        ctl.fltr_lev= 1;
 
653
                        if (string_to_bitarray(optarg,
 
654
                                             ctl.levels, parse_level) < 0)
 
655
                                return EXIT_FAILURE;
71
656
                        break;
72
657
                case 'n':
73
 
                        cmd = 8;        /* Set level of messages */
74
 
                        level = strtol_or_err(optarg, _("failed to parse level"));
 
658
                        cmd = SYSLOG_ACTION_CONSOLE_LEVEL;
 
659
                        console_level = parse_level(optarg, 0);
75
660
                        break;
76
661
                case 'r':
77
 
                        raw = 1;
 
662
                        ctl.raw = 1;
78
663
                        break;
79
664
                case 's':
80
 
                        bufsize = strtol_or_err(optarg, _("failed to parse buffer size"));
 
665
                        bufsize = strtol_or_err(optarg,
 
666
                                        _("failed to parse buffer size"));
81
667
                        if (bufsize < 4096)
82
668
                                bufsize = 4096;
83
669
                        break;
 
670
                case 'T':
 
671
                        ctl.boot_time = get_boot_time();
 
672
                        if (ctl.boot_time)
 
673
                                ctl.ctime = 1;
 
674
                        break;
 
675
                case 't':
 
676
                        ctl.notime = 1;
 
677
                        break;
 
678
                case 'u':
 
679
                        ctl.fltr_fac = 1;
 
680
                        for (n = 1; (size_t) n < ARRAY_SIZE(facility_names); n++)
 
681
                                setbit(ctl.facilities, n);
 
682
                        break;
 
683
                case 'V':
 
684
                        printf(_("%s from %s\n"), program_invocation_short_name,
 
685
                                                  PACKAGE_STRING);
 
686
                        return EXIT_SUCCESS;
 
687
                case 'x':
 
688
                        ctl.decode = 1;
 
689
                        break;
84
690
                case '?':
85
691
                default:
86
 
                        usage();
87
 
                        exit(EXIT_FAILURE);
 
692
                        usage(stderr);
88
693
                }
89
694
        }
90
695
        argc -= optind;
91
696
        argv += optind;
92
 
 
93
 
        if (argc > 1) {
94
 
                usage();
95
 
                exit(EXIT_FAILURE);
96
 
        }
97
 
 
98
 
        if (cmd == 8) {
99
 
                n = klogctl(cmd, NULL, level);
100
 
                if (n < 0) {
101
 
                        perror("klogctl");
102
 
                        exit(EXIT_FAILURE);
103
 
                }
104
 
                exit(EXIT_SUCCESS);
105
 
        }
106
 
 
107
 
        if (!bufsize) {
108
 
                n = klogctl(10, NULL, 0);       /* read ringbuffer size */
 
697
        n = 0;
 
698
 
 
699
        if (argc > 1)
 
700
                usage(stderr);
 
701
 
 
702
        if (cmd == -1)
 
703
                cmd = SYSLOG_ACTION_READ_ALL;   /* default */
 
704
 
 
705
        if (ctl.raw && (ctl.fltr_lev || ctl.fltr_fac || ctl.delta ||
 
706
                        ctl.notime || ctl.ctime || ctl.decode))
 
707
                errx(EXIT_FAILURE, _("--raw can't be used together with level, "
 
708
                     "facility, decode, delta, ctime or notime options"));
 
709
 
 
710
        if (ctl.notime && ctl.ctime)
 
711
                errx(EXIT_FAILURE, _("--notime can't be used together with ctime "));
 
712
 
 
713
        switch (cmd) {
 
714
        case SYSLOG_ACTION_READ_ALL:
 
715
        case SYSLOG_ACTION_READ_CLEAR:
 
716
                if (!bufsize)
 
717
                        bufsize = get_buffer_size();
 
718
                n = read_buffer(&buf, bufsize, cmd == SYSLOG_ACTION_READ_CLEAR);
109
719
                if (n > 0)
110
 
                        bufsize = n;
111
 
        }
112
 
 
113
 
        if (bufsize) {
114
 
                sz = bufsize + 8;
115
 
                buf = (char *) malloc(sz * sizeof(char));
116
 
                n = klogctl(cmd, buf, sz);
117
 
        } else {
118
 
                sz = 16392;
119
 
                while (1) {
120
 
                        buf = (char *) malloc(sz * sizeof(char));
121
 
                        n = klogctl(3, buf, sz);        /* read only */
122
 
                        if (n != sz || sz > (1<<28))
123
 
                                break;
124
 
                        free(buf);
125
 
                        sz *= 4;
126
 
                }
127
 
 
128
 
                if (n > 0 && cmd == 4)
129
 
                        n = klogctl(cmd, buf, sz);      /* read and clear */
130
 
        }
131
 
 
132
 
        if (n < 0) {
133
 
                perror("klogctl");
134
 
                exit(EXIT_FAILURE);
135
 
        }
136
 
 
137
 
        lastc = '\n';
138
 
        for (i = 0; i < n; i++) {
139
 
                if (!raw && (i == 0 || buf[i - 1] == '\n') && buf[i] == '<') {
140
 
                        i++;
141
 
                        while (buf[i] >= '0' && buf[i] <= '9')
142
 
                                i++;
143
 
                        if (buf[i] == '>')
144
 
                                i++;
145
 
                }
146
 
                lastc = buf[i];
147
 
                putchar(lastc);
148
 
        }
149
 
        if (lastc != '\n')
150
 
                putchar('\n');
151
 
        free(buf);
152
 
        return 0;
 
720
                        print_buffer(buf, n, &ctl);
 
721
                free(buf);
 
722
                break;
 
723
        case SYSLOG_ACTION_CLEAR:
 
724
        case SYSLOG_ACTION_CONSOLE_OFF:
 
725
        case SYSLOG_ACTION_CONSOLE_ON:
 
726
                n = klogctl(cmd, NULL, 0);
 
727
                break;
 
728
        case SYSLOG_ACTION_CONSOLE_LEVEL:
 
729
                n = klogctl(cmd, NULL, console_level);
 
730
                break;
 
731
        default:
 
732
                errx(EXIT_FAILURE, _("unsupported command"));
 
733
                break;
 
734
        }
 
735
 
 
736
        if (n < 0)
 
737
                err(EXIT_FAILURE, _("klogctl failed"));
 
738
 
 
739
        return EXIT_SUCCESS;
153
740
}