Klogd&&Syslogd
1> 所有系统信息是输出到ring buffer中去的.dmesg所显示的内容也是从ring buffer中读取的.
2> LINUX系统中/etc/init.d/sysklogd会启动2个守护进程:Klogd&&Syslogd
3> klogd是负责读取内核信息的,有2种方式:
syslog()系统调用
直接的对/proc/kmsg进行读取(再这提一下,/proc/kmsg是专门输出内核信息的地方)
4> Klogd的输出结果会传送给syslogd进行处理,syslogd会根据/etc/syslog.conf的配置把log 信息输出到/var/log/下的不同文件中.
printk
日志级别字符串:KERN_EMERG, KERN_ALERT, KERN_CRIT, KERN_ERR, KERN_WARNING, KERN_NOTICE, KERN_INFO, KERN_DEBUG. printk默认级别是DEFAULT_MESSAGE_LOGLEVEL(在kernel/printk.c中定义)。当优先级小于console_loglevel消息才会显示出来。
宏定义中##和#的作用
##是一个连接符号,用于把参数连在一起,例如:
> #define FOO(arg) my##arg
> FOO(abc) 相当于 myabc
#是“字符串化”的意思。出现在宏定义中的#是把跟在后面的参数转换成一个字符串,例如:
> #define STRCPY(dst, src) strcpy(dst, #src) 则
> STRCPY(buff, abc) 相当于 strcpy(buff, "abc")
#undef PDEBUG /* undef it, just in case */
#ifdef SCULLC_DEBUG
# ifdef __KERNEL__
/* This one if debugging is on, and kernel space */
# define PDEBUG(fmt, args...) printk( KERN_DEBUG "scullc: " fmt, ## args)
# else
/* This one for user space */
# define PDEBUG(fmt, args...) fprintf(stderr, fmt, ## args)
# endif
#else
# define PDEBUG(fmt, args...) /* not debugging: nothing */
#endif
Makefie
ifeq ($(DEBUG),y)
DEBFLAGS = -O -g -DSCULLC_DEBUG # "-O" is needed to expand inlines, -D can remove space
else
DEBFLAGS = -O2
endif
CFLAGS += $(DEBFLAGS) -I$(LDDINC)
有些进程在遇到失败后会不停的重试,这样会造成巨量输出,并可能在控制台设备较慢时独占CPU。printk_ratelimit可以控制一定间隔打印。
if(printk_ratelimit())
printk(KERN_NOTICE "The printer is still on fire\n");
//打印设备编号,下面两个函数都可以
int print_dev_t(char *buffer, dev_t dev);
char *format_dev_t(char *buffer, dev_t dev);
使用/proc文件系统
/proc是由软件创建的文件系统,/proc下面每个文件都绑定一个内核函数,用户读取其中文件时,该函数动态的生成文件的内容。创建一个只读文件时,驱动程序需要实现一个函数,用于读取文件时生成数据。当进程读取 这个文件时,读取请求会通过函数发送到驱动程序模块。当进程读取/proc文件时,内核会分配一个内存页,驱动程序可以通过其将数据返回给用空间。写好read_proc函数就要把它和/proc入口连接起来,通过create_proc_read_entry实现。卸载模块通过remove_proc_entry实现。
注意:删除调用可能在文件正在使用时发生,因为/proc入口项不存在关联的使用者,因此对这些文件的使用不会作用到模块的引用计数上。
int (*read_proc)(char *page, char **start, off_t offset, int count, int *eof, void *data);
//在scull中就是scullc_read_procmem, start返回实际数据写到内存页哪个位置。
//第一个参数是创建的文件名称,第三个是该文件所在目录,NULL表示在/proc根目录下
//第5个参数为void *data 是传给第四个参数执行的函数
create_proc_read_entry("scullcmem", 0 /*mode, 0表示系统默认权限*/, NULL, scullc_read_procmem, NULL);
remove_proc_entry("scullmen", NULL /*parent dir*/);
int scullc_read_procmem(char *buf, char **start, off_t offset,
int count, int *eof, void *data)
{
int i, j, quantum, qset, len = 0;
int limit = count - 80; /* Don't print more than this */
struct scullc_dev *d;
*start = buf;
for(i = 0; i < scullc_devs; i++) {
d = &scullc_devices[i];
if (down_interruptible (&d->sem))
return -ERESTARTSYS;
qset = d->qset; /* retrieve the features of each device */
quantum=d->quantum;
len += sprintf(buf+len,"\nDevice %i: qset %i, quantum %i, sz %li\n",
i, qset, quantum, (long)(d->size));
for (; d; d = d->next) { /* scan the list */
len += sprintf(buf+len," item at %p, qset at %p\n",d,d->data);
scullc_proc_offset (buf, start, &offset, &len);
if (len > limit)
goto out;
if (d->data && !d->next) /* dump only the last item - save space */
for (j = 0; j < qset; j++) {
if (d->data[j])
len += sprintf(buf+len," % 4i:%8p\n",j,d->data[j]);
scullc_proc_offset (buf, start, &offset, &len);
if (len > limit)
goto out;
}
}
out:
up (&scullc_devices[i].sem);
if (len > limit)
break;
}
*eof = 1;
return len;
}