dmesg.c 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181
  1. /* dmesg.c - display/control kernel ring buffer.
  2. *
  3. * Copyright 2006, 2007 Rob Landley <rob@landley.net>
  4. *
  5. * See http://refspecs.linuxfoundation.org/LSB_4.1.0/LSB-Core-generic/LSB-Core-generic/dmesg.html
  6. *
  7. * Don't ask me why the horrible new dmesg API is still in "testing":
  8. * http://kernel.org/doc/Documentation/ABI/testing/dev-kmsg
  9. // We care that FLAG_c is 1, so keep c at the end.
  10. USE_DMESG(NEWTOY(dmesg, "w(follow)CSTtrs#<1n#c[!Ttr][!Cc][!Sw]", TOYFLAG_BIN))
  11. config DMESG
  12. bool "dmesg"
  13. default y
  14. help
  15. usage: dmesg [-Cc] [-r|-t|-T] [-n LEVEL] [-s SIZE] [-w]
  16. Print or control the kernel ring buffer.
  17. -C Clear ring buffer without printing
  18. -c Clear ring buffer after printing
  19. -n Set kernel logging LEVEL (1-9)
  20. -r Raw output (with <level markers>)
  21. -S Use syslog(2) rather than /dev/kmsg
  22. -s Show the last SIZE many bytes
  23. -T Human readable timestamps
  24. -t Don't print timestamps
  25. -w Keep waiting for more output (aka --follow)
  26. */
  27. #define FOR_dmesg
  28. #include "toys.h"
  29. #include <sys/klog.h>
  30. GLOBALS(
  31. long n, s;
  32. int use_color;
  33. time_t tea;
  34. )
  35. static void color(int c)
  36. {
  37. if (TT.use_color) printf("\e[%dm", c);
  38. }
  39. static void format_message(char *msg, int new)
  40. {
  41. unsigned long long time_s, time_us;
  42. int facpri, subsystem, pos;
  43. char *p, *text;
  44. // The new /dev/kmsg and the old syslog(2) formats differ slightly.
  45. if (new) {
  46. if (sscanf(msg, "%u,%*u,%llu,%*[^;]; %n", &facpri, &time_us, &pos) != 2)
  47. return;
  48. time_s = time_us/1000000;
  49. time_us %= 1000000;
  50. } else if (sscanf(msg, "<%u>[%llu.%llu] %n",
  51. &facpri, &time_s, &time_us, &pos) != 3) return;
  52. // Drop extras after end of message text.
  53. if ((p = strchr(text = msg+pos, '\n'))) *p = 0;
  54. // Is there a subsystem? (The ": " is just a convention.)
  55. p = strstr(text, ": ");
  56. subsystem = p ? (p-text) : 0;
  57. // To get "raw" output for /dev/kmsg we need to add priority to each line
  58. if (FLAG(r)) {
  59. color(0);
  60. printf("<%d>", facpri);
  61. }
  62. // Format the time.
  63. if (!FLAG(t)) {
  64. color(32);
  65. if (FLAG(T)) {
  66. time_t t = TT.tea+time_s;
  67. char *ts = ctime(&t);
  68. printf("[%.*s] ", (int)(strlen(ts)-1), ts);
  69. } else printf("[%5lld.%06lld] ", time_s, time_us);
  70. }
  71. // Errors (or worse) are shown in red, subsystems are shown in yellow.
  72. if (subsystem) {
  73. color(33);
  74. printf("%.*s", subsystem, text);
  75. text += subsystem;
  76. }
  77. color(31*((facpri&7)<=3));
  78. xputs(text);
  79. }
  80. static int xklogctl(int type, char *buf, int len)
  81. {
  82. int rc = klogctl(type, buf, len);
  83. if (rc<0) perror_exit("klogctl");
  84. return rc;
  85. }
  86. static void dmesg_cleanup(void)
  87. {
  88. color(0);
  89. }
  90. void dmesg_main(void)
  91. {
  92. TT.use_color = isatty(1);
  93. if (TT.use_color) sigatexit(dmesg_cleanup);
  94. // If we're displaying output, is it klogctl or /dev/kmsg?
  95. if (FLAG(C)||FLAG(n)) goto no_output;
  96. if (FLAG(T)) {
  97. struct sysinfo info;
  98. sysinfo(&info);
  99. TT.tea = time(0)-info.uptime;
  100. }
  101. if (!FLAG(S)) {
  102. char msg[8193]; // CONSOLE_EXT_LOG_MAX+1
  103. ssize_t len;
  104. int fd;
  105. // Each read returns one message. By default, we block when there are no
  106. // more messages (--follow); O_NONBLOCK is needed for for usual behavior.
  107. fd = open("/dev/kmsg", O_RDONLY|(O_NONBLOCK*!FLAG(w)));
  108. if (fd == -1) goto klogctl_mode;
  109. // SYSLOG_ACTION_CLEAR(5) doesn't actually remove anything from /dev/kmsg,
  110. // you need to seek to the last clear point.
  111. lseek(fd, 0, SEEK_DATA);
  112. for (;;) {
  113. // why does /dev/kmesg return EPIPE instead of EAGAIN if oldest message
  114. // expires as we read it?
  115. if (-1==(len = read(fd, msg, sizeof(msg)-1)) && errno==EPIPE) continue;
  116. // read() from kmsg always fails on a pre-3.5 kernel.
  117. if (len==-1 && errno==EINVAL) goto klogctl_mode;
  118. if (len<1) break;
  119. msg[len] = 0;
  120. format_message(msg, 1);
  121. }
  122. close(fd);
  123. } else {
  124. char *data, *to, *from, *end;
  125. int size;
  126. klogctl_mode:
  127. // Figure out how much data we need, and fetch it.
  128. if (!(size = TT.s)) size = xklogctl(10, 0, 0);
  129. data = from = xmalloc(size+1);
  130. data[size = xklogctl(3+FLAG(c), data, size)] = 0;
  131. // Send each line to format_message.
  132. to = data + size;
  133. while (from < to) {
  134. if (!(end = memchr(from, '\n', to-from))) break;
  135. *end = 0;
  136. format_message(from, 0);
  137. from = end + 1;
  138. }
  139. if (CFG_TOYBOX_FREE) free(data);
  140. }
  141. no_output:
  142. // Set the log level?
  143. if (FLAG(n)) xklogctl(8, 0, TT.n);
  144. // Clear the buffer?
  145. if (FLAG(C)||FLAG(c)) xklogctl(5, 0, 0);
  146. }