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 
8 USE_KLOGD(NEWTOY(klogd, "c#<1>8n", TOYFLAG_SBIN))
9 
10 config 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 
19 config 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>
GLOBALS(long level;int fd;)29 GLOBALS(
30   long level;
31 
32   int fd;
33 )
34 
35 static 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 
handle_signal(int sig)47 static 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  */
klogd_main(void)64 void 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