标签:kernel chapter8.5 log 0.000000 int 入门篇 tm buffer Linux
奔跑吧Linux内核入门篇 第8章 进程管理 8.5.3 实验3: 后台守护进程
文章目录
实验详述
-
实验目的
通过本实验了解和熟悉Linux是如何创建和使用后台守护进程的. -
实验步骤
(1) 写一个用户程序, 创建一个守护进程.
(2) 该守护进程每隔5秒去查看当前内核的日志中是否有Oops错误.
实验解析
本实验完全是个用户态的程序, 需要知道
- 如何创建一个守护进程? (跑在后台, 无控制终端, 无法对前台输出信息)
- 如何去读内核的日志?
问题1可以用glibc提供的daemon()函数
man 3 daemon
NAME
daemon - run in the background
SYNOPSIS
#include <unistd.h>
int daemon(int nochdir, int noclose);
Feature Test Macro Requirements for glibc (see feature_test_macros(7)):
daemon():
Since glibc 2.21:
_DEFAULT_SOURCE
In glibc 2.19 and 2.20:
_DEFAULT_SOURCE || (_XOPEN_SOURCE && _XOPEN_SOURCE < 500)
Up to and including glibc 2.19:
_BSD_SOURCE || (_XOPEN_SOURCE && _XOPEN_SOURCE < 500)
问题2 可以用glibc提供的klogctl()函数
man 3 klogctl
NAME
syslog, klogctl - read and/or clear kernel message ring buffer; set console_loglevel
SYNOPSIS
int syslog(int type, char *bufp, int len);
/* No wrapper provided in glibc */
/* The glibc interface */
#include <sys/klog.h>
int klogctl(int type, char *bufp, int len);
本实验相对简单,直接看代码.
程序源码
文件名: my_daemon.c
这个直接参考了笨叔的答案
(runninglinuxkernel_4.0/rlk_lab/rlk_basic/chapter_8/lab3_daemon/daemon_test1.c)
/* create a daemon which checks if there are opps errors in the kernel log
* every 5 second
*/
#include <stdio.h>
#include <unistd.h>
#include <errno.h>
#include <stdlib.h>
#include <time.h>
#include <fcntl.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/klog.h>
#define FALLBACK_KLOG_BUF_SHIFT 17 /* CONFIG_LOG_BUF_SHIFT in kernel */
#define FALLBACK_KLOG_BUF_LEN (1 << FALLBACK_KLOG_BUF_SHIFT)
#define KLOG_CLOSE 0
#define KLOG_OPEN 1
#define KLOG_READ 2
#define KLOG_READ_ALL 3
#define KLOG_READ_CLEAR 4
#define KLOG_CLEAR 5
#define KLOG_CONSOLE_OFF 6
#define KLOG_CONSOLE_ON 7
#define KLOG_CONSOLE_LEVEL 8
#define KLOG_SIZE_UNREAD 9
#define KLOG_SIZE_BUFFER 10
/* we use 'Linux version' string instead of Oops in this lab */
//#define OOPS_LOG "Oops"
#define OOPS_LOG "Linux version"
int save_kernel_log(char *buffer)
{
char path[128];
time_t t;
struct tm *tm;
int fd;
/* time(2): returns the time as the number of seconds
* since the Epoch, 1970-01-01 00:00:00 +0000 (UTC). */
t = time(0);
/* transform date and time to broken-down time or ASCII */
tm = localtime(&t);
/* the structure tm, which is defined in <time.h> as follows:
* struct tm {
* int tm_sec; // Seconds (0-60)
* int tm_min; // Minutes (0-59)
* int tm_hour; // Hours (0-23)
* int tm_mday; // Day of the month (1-31)
* int tm_mon; // Month (0-11)
* int tm_year; // Year - 1900
* int tm_wday; // Day of the week (0-6, Sunday = 0)
* int tm_yday; // Day in the year (0-365, 1 Jan = 0)
* int tm_isdst; // Daylight saving time
* };
*/
snprintf(path, 128, "/mnt/%d.%d.%d.%d.%d.%d.log", tm->tm_year+1900,
tm->tm_mon+1, tm->tm_mday, tm->tm_hour,
tm->tm_min, tm->tm_sec);
printf("%s\n", path);
fd = open(path, O_WRONLY|O_CREAT, 0644);
if(fd == -1) {
printf("open error\n");
return -1;
}
write(fd, buffer, strlen(buffer));
close(fd);
return 0;
}
int check_kernel_log()
{
char *buffer;
char *p;
ssize_t klog_size;
int ret = -1;
int size;
printf("start kernel log\n");
/* klogctl(3): read and/or clear kernel message
* ring buffer; set console_loglevel.
* Here returns the total size of the kernel log buffer.
* */
klog_size = klogctl(KLOG_SIZE_BUFFER, 0, 0);
if (klog_size <= 0) {
klog_size = FALLBACK_KLOG_BUF_LEN;
}
printf("kernel log size: %d\n", klog_size);
buffer = malloc(klog_size + 1);
if (!buffer)
return -1;
/* Read all messages remaining in the ring buffer,
* placing them in the buffer pointed to by buffer.
* The call reads the last klog_size bytes from
* the log buffer (nondestructively) */
size = klogctl(KLOG_READ_ALL, buffer, klog_size);
if (size < 0) {
printf("klogctl read error\n");
goto done;
}
buffer[size] = '\0';
/* strstr(3), finds the first occurrence of the substring */
/* check if oops in klog */
p = strstr(buffer,OOPS_LOG);
if (p) {
printf("we found '%s' on kernel log\n", OOPS_LOG);
save_kernel_log(buffer);
ret = 0;
}
done:
free(buffer);
return ret;
}
int main(void)
{
/* The daemon(3) function is for programs wishing to
* detach themselves from the controlling terminal
* and run in the background as system daemons. */
if (daemon(0, 0) == -1) {
printf("failed to daemon(): %s(%d)\n", strerror(errno), errno);
return -1;
}
while (1) {
check_kernel_log();
sleep(5);
}
return 0;
}
编译
这里直接编译就行
arm-linux-gnueabi-gcc my_daemon.c -o my_daemon.exe --static
验证执行
/mnt #
/mnt # pwd
/mnt
/mnt # find . -name "*.log"
/mnt # ./my_daemon.exe
/mnt #
/mnt # find . -name "*.log"
./2021.1.24.1.45.50.log
./2021.1.24.1.45.55.log
./2021.1.24.1.46.0.log
/mnt #
/mnt # pgrep my_daemon
792
/mnt # kill -9 792
/mnt #
/mnt #
/mnt # head 2021.1.24.1.45.50.log
<6>[ 0.000000] Booting Linux on physical CPU 0x0
<6>[ 0.000000] Initializing cgroup subsys cpuset
<5>[ 0.000000] Linux version 4.0.0+ (gewkiff@ukylin) (gcc version 5.5.0 20171010 (Ubuntu/Linaro 5.5.0-12ubuntu1) ) #2 SMP Sun Sep 20 06:37:58 CST 2020
<6>[ 0.000000] CPU: ARMv7 Processor [410fc090] revision 0 (ARMv7), cr=10c5387d
<6>[ 0.000000] CPU: PIPT / VIPT nonaliasing data cache, VIPT nonaliasing instruction cache
<6>[ 0.000000] Machine model: V2P-CA9
<6>[ 0.000000] Memory policy: Data cache writealloc
<7>[ 0.000000] On node 0 totalpages: 25600
<7>[ 0.000000] free_area_init_node: node 0, pgdat c10e9e40, node_mem_map c6332000
<7>[ 0.000000] Normal zone: 200 pages used for memmap
/mnt #
/mnt #
/mnt # head 2021.1.24.1.45.55.log
<6>[ 0.000000] Booting Linux on physical CPU 0x0
<6>[ 0.000000] Initializing cgroup subsys cpuset
<5>[ 0.000000] Linux version 4.0.0+ (gewkiff@ukylin) (gcc version 5.5.0 20171010 (Ubuntu/Linaro 5.5.0-12ubuntu1) ) #2 SMP Sun Sep 20 06:37:58 CST 2020
<6>[ 0.000000] CPU: ARMv7 Processor [410fc090] revision 0 (ARMv7), cr=10c5387d
<6>[ 0.000000] CPU: PIPT / VIPT nonaliasing data cache, VIPT nonaliasing instruction cache
<6>[ 0.000000] Machine model: V2P-CA9
<6>[ 0.000000] Memory policy: Data cache writealloc
<7>[ 0.000000] On node 0 totalpages: 25600
<7>[ 0.000000] free_area_init_node: node 0, pgdat c10e9e40, node_mem_map c6332000
<7>[ 0.000000] Normal zone: 200 pages used for memmap
/mnt #
kernel log buffer
这是在man 3 klogctl 中看到的关于kernel log buffer的简短介绍
The kernel log buffer
The kernel has a cyclic buffer of length LOG_BUF_LEN in which
messages given as arguments to the kernel function printk()
are stored (regardless of their log level).
In early kernels, LOG_BUF_LEN had the value 4096;
from kernel 1.3.54, it was 8192; from kernel 2.1.113, it was 16384;
since kernel 2.4.23/2.6, the value is a kernel configuration option
(CONFIG_LOG_BUF_SHIFT, default value dependent on the architecture).
Since Linux 2.6.6, the size can be queried with command type 10 (see below).
标签:kernel,chapter8.5,log,0.000000,int,入门篇,tm,buffer,Linux 来源: https://blog.csdn.net/weixin_42992444/article/details/113068927
本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享; 2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关; 3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关; 4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除; 5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。