1/* klogd.c - Klogd, The kernel log Dameon.
2 *
3 * Copyright 2013 Sandeep Sharma <sandeep.jack2756@gmail.com>
4 * Copyright 2013 Kyungwan Han <asura321@gmail.com>
5 *
6 * No standard
7
8USE_KLOGD(NEWTOY(klogd, "c#<1>8n", TOYFLAG_SBIN))
9
10config KLOGD
11    bool "klogd"
12    default n
13    help
14    usage: klogd [-n] [-c N]
15
16    -c  N   Print to console messages more urgent than prio N (1-8)"
17    -n    Run in foreground
18
19config KLOGD_SOURCE_RING_BUFFER
20    bool "enable kernel ring buffer as log source."
21    default n
22    depends on KLOGD
23*/
24
25#define FOR_klogd
26#include "toys.h"
27#include <signal.h>
28#include <sys/klog.h>
29GLOBALS(
30  long level;
31
32  int fd;
33)
34
35static void set_log_level(int level)
36{
37  if (CFG_KLOGD_SOURCE_RING_BUFFER)
38    klogctl(8, NULL, level);
39  else {
40    FILE *fptr = xfopen("/proc/sys/kernel/printk", "w");
41    fprintf(fptr, "%u\n", level);
42    fclose(fptr);
43    fptr = NULL;
44  }
45}
46
47static void handle_signal(int sig)
48{
49  if (CFG_KLOGD_SOURCE_RING_BUFFER) {
50    klogctl(7, NULL, 0);
51    klogctl(0, NULL, 0);
52  } else {
53    set_log_level(7);
54    xclose(TT.fd);
55  }
56  syslog(LOG_NOTICE,"KLOGD: Daemon exiting......");
57  exit(1);
58}
59
60/*
61 * Read kernel ring buffer in local buff and keep track of
62 * "used" amount to track next read to start.
63 */
64void klogd_main(void)
65{
66  int prio, size, used = 0;
67  char *start, *line_start, msg_buffer[16348]; //LOG_LINE_LENGTH - Ring buffer size
68
69  sigatexit(handle_signal);
70  if (toys.optflags & FLAG_c) set_log_level(TT.level);    //set log level
71  if (!(toys.optflags & FLAG_n)) daemon(0, 0);            //Make it daemon
72
73  if (CFG_KLOGD_SOURCE_RING_BUFFER) {
74    syslog(LOG_NOTICE, "KLOGD: started with Kernel ring buffer as log source\n");
75    klogctl(1, NULL, 0);
76  } else {
77    TT.fd = xopenro("/proc/kmsg"); //_PATH_KLOG in paths.h
78    syslog(LOG_NOTICE, "KLOGD: started with /proc/kmsg as log source\n");
79  }
80  openlog("Kernel", 0, LOG_KERN);    //open connection to system logger..
81
82  while(1) {
83    start = msg_buffer + used; //start updated for re-read.
84    if (CFG_KLOGD_SOURCE_RING_BUFFER) {
85      size = klogctl(2, start, sizeof(msg_buffer) - used - 1);
86    } else {
87      size = xread(TT.fd, start, sizeof(msg_buffer) - used - 1);
88    }
89    if (size < 0) perror_exit("error reading file:");
90    start[size] = '\0';  //Ensure last line to be NUL terminated.
91    if (used) start = msg_buffer;
92    while(start) {
93      if ((line_start = strsep(&start, "\n")) != NULL && start != NULL) used = 0;
94      else {                            //Incomplete line, copy it to start of buff.
95        used = strlen(line_start);
96        strcpy(msg_buffer, line_start);
97        if (used < (sizeof(msg_buffer) - 1)) break;
98        used = 0; //we have buffer full, log it as it is.
99      }
100      prio = LOG_INFO;  //we dont know priority, mark it INFO
101      if (*line_start == '<') {  //we have new line to syslog
102        line_start++;
103        if (line_start) prio = (int)strtoul(line_start, &line_start, 10);
104        if (*line_start == '>') line_start++;
105      }
106      if (*line_start) syslog(prio, "%s", line_start);
107    }
108  }
109}
110