10f66f451Sopenharmony_ci/* klogd.c - Klogd, The kernel log Dameon.
20f66f451Sopenharmony_ci *
30f66f451Sopenharmony_ci * Copyright 2013 Sandeep Sharma <sandeep.jack2756@gmail.com>
40f66f451Sopenharmony_ci * Copyright 2013 Kyungwan Han <asura321@gmail.com>
50f66f451Sopenharmony_ci *
60f66f451Sopenharmony_ci * No standard
70f66f451Sopenharmony_ci
80f66f451Sopenharmony_ciUSE_KLOGD(NEWTOY(klogd, "c#<1>8n", TOYFLAG_SBIN))
90f66f451Sopenharmony_ci
100f66f451Sopenharmony_ciconfig KLOGD
110f66f451Sopenharmony_ci    bool "klogd"
120f66f451Sopenharmony_ci    default n
130f66f451Sopenharmony_ci    help
140f66f451Sopenharmony_ci    usage: klogd [-n] [-c N]
150f66f451Sopenharmony_ci
160f66f451Sopenharmony_ci    -c  N   Print to console messages more urgent than prio N (1-8)"
170f66f451Sopenharmony_ci    -n    Run in foreground
180f66f451Sopenharmony_ci
190f66f451Sopenharmony_ciconfig KLOGD_SOURCE_RING_BUFFER
200f66f451Sopenharmony_ci    bool "enable kernel ring buffer as log source."
210f66f451Sopenharmony_ci    default n
220f66f451Sopenharmony_ci    depends on KLOGD
230f66f451Sopenharmony_ci*/
240f66f451Sopenharmony_ci
250f66f451Sopenharmony_ci#define FOR_klogd
260f66f451Sopenharmony_ci#include "toys.h"
270f66f451Sopenharmony_ci#include <signal.h>
280f66f451Sopenharmony_ci#include <sys/klog.h>
290f66f451Sopenharmony_ciGLOBALS(
300f66f451Sopenharmony_ci  long level;
310f66f451Sopenharmony_ci
320f66f451Sopenharmony_ci  int fd;
330f66f451Sopenharmony_ci)
340f66f451Sopenharmony_ci
350f66f451Sopenharmony_cistatic void set_log_level(int level)
360f66f451Sopenharmony_ci{
370f66f451Sopenharmony_ci  if (CFG_KLOGD_SOURCE_RING_BUFFER)
380f66f451Sopenharmony_ci    klogctl(8, NULL, level);
390f66f451Sopenharmony_ci  else {
400f66f451Sopenharmony_ci    FILE *fptr = xfopen("/proc/sys/kernel/printk", "w");
410f66f451Sopenharmony_ci    fprintf(fptr, "%u\n", level);
420f66f451Sopenharmony_ci    fclose(fptr);
430f66f451Sopenharmony_ci    fptr = NULL;
440f66f451Sopenharmony_ci  }
450f66f451Sopenharmony_ci}
460f66f451Sopenharmony_ci
470f66f451Sopenharmony_cistatic void handle_signal(int sig)
480f66f451Sopenharmony_ci{
490f66f451Sopenharmony_ci  if (CFG_KLOGD_SOURCE_RING_BUFFER) {
500f66f451Sopenharmony_ci    klogctl(7, NULL, 0);
510f66f451Sopenharmony_ci    klogctl(0, NULL, 0);
520f66f451Sopenharmony_ci  } else {
530f66f451Sopenharmony_ci    set_log_level(7);
540f66f451Sopenharmony_ci    xclose(TT.fd);
550f66f451Sopenharmony_ci  }
560f66f451Sopenharmony_ci  syslog(LOG_NOTICE,"KLOGD: Daemon exiting......");
570f66f451Sopenharmony_ci  exit(1);
580f66f451Sopenharmony_ci}
590f66f451Sopenharmony_ci
600f66f451Sopenharmony_ci/*
610f66f451Sopenharmony_ci * Read kernel ring buffer in local buff and keep track of
620f66f451Sopenharmony_ci * "used" amount to track next read to start.
630f66f451Sopenharmony_ci */
640f66f451Sopenharmony_civoid klogd_main(void)
650f66f451Sopenharmony_ci{
660f66f451Sopenharmony_ci  int prio, size, used = 0;
670f66f451Sopenharmony_ci  char *start, *line_start, msg_buffer[16348]; //LOG_LINE_LENGTH - Ring buffer size
680f66f451Sopenharmony_ci
690f66f451Sopenharmony_ci  sigatexit(handle_signal);
700f66f451Sopenharmony_ci  if (toys.optflags & FLAG_c) set_log_level(TT.level);    //set log level
710f66f451Sopenharmony_ci  if (!(toys.optflags & FLAG_n)) daemon(0, 0);            //Make it daemon
720f66f451Sopenharmony_ci
730f66f451Sopenharmony_ci  if (CFG_KLOGD_SOURCE_RING_BUFFER) {
740f66f451Sopenharmony_ci    syslog(LOG_NOTICE, "KLOGD: started with Kernel ring buffer as log source\n");
750f66f451Sopenharmony_ci    klogctl(1, NULL, 0);
760f66f451Sopenharmony_ci  } else {
770f66f451Sopenharmony_ci    TT.fd = xopenro("/proc/kmsg"); //_PATH_KLOG in paths.h
780f66f451Sopenharmony_ci    syslog(LOG_NOTICE, "KLOGD: started with /proc/kmsg as log source\n");
790f66f451Sopenharmony_ci  }
800f66f451Sopenharmony_ci  openlog("Kernel", 0, LOG_KERN);    //open connection to system logger..
810f66f451Sopenharmony_ci
820f66f451Sopenharmony_ci  while(1) {
830f66f451Sopenharmony_ci    start = msg_buffer + used; //start updated for re-read.
840f66f451Sopenharmony_ci    if (CFG_KLOGD_SOURCE_RING_BUFFER) {
850f66f451Sopenharmony_ci      size = klogctl(2, start, sizeof(msg_buffer) - used - 1);
860f66f451Sopenharmony_ci    } else {
870f66f451Sopenharmony_ci      size = xread(TT.fd, start, sizeof(msg_buffer) - used - 1);
880f66f451Sopenharmony_ci    }
890f66f451Sopenharmony_ci    if (size < 0) perror_exit("error reading file:");
900f66f451Sopenharmony_ci    start[size] = '\0';  //Ensure last line to be NUL terminated.
910f66f451Sopenharmony_ci    if (used) start = msg_buffer;
920f66f451Sopenharmony_ci    while(start) {
930f66f451Sopenharmony_ci      if ((line_start = strsep(&start, "\n")) != NULL && start != NULL) used = 0;
940f66f451Sopenharmony_ci      else {                            //Incomplete line, copy it to start of buff.
950f66f451Sopenharmony_ci        used = strlen(line_start);
960f66f451Sopenharmony_ci        strcpy(msg_buffer, line_start);
970f66f451Sopenharmony_ci        if (used < (sizeof(msg_buffer) - 1)) break;
980f66f451Sopenharmony_ci        used = 0; //we have buffer full, log it as it is.
990f66f451Sopenharmony_ci      }
1000f66f451Sopenharmony_ci      prio = LOG_INFO;  //we dont know priority, mark it INFO
1010f66f451Sopenharmony_ci      if (*line_start == '<') {  //we have new line to syslog
1020f66f451Sopenharmony_ci        line_start++;
1030f66f451Sopenharmony_ci        if (line_start) prio = (int)strtoul(line_start, &line_start, 10);
1040f66f451Sopenharmony_ci        if (*line_start == '>') line_start++;
1050f66f451Sopenharmony_ci      }
1060f66f451Sopenharmony_ci      if (*line_start) syslog(prio, "%s", line_start);
1070f66f451Sopenharmony_ci    }
1080f66f451Sopenharmony_ci  }
1090f66f451Sopenharmony_ci}
110