Как добавить сообщение, которое будет прочитано с помощью dmesg?
Я пытаюсь написать несколько пользовательских сообщений в выводе dmesg. Я старался:
logger "Hello"
но это не работает. Он завершается без ошибок, но "Hello" не появляется в выходных данных:
dmesg
Я использую Fedora 9, и похоже, что демон syslogd/klogd не запущен. Тем не менее, все мои сообщения ядра успешно записаны в буфере dmesg.
Любая идея?
7 ответов
dmesg
отображает то, что находится в буфере ядра, тогда как logger
для syslogd
, Я думаю, что если вы хотите распечатать вещи в буфер ядра, вам нужно будет создать драйвер, который использует printk()
функция ядра. Если вы просто хотите это в /var/log/messages
то с "нормальной" настройкой думаю что вы сделали с logger
уже хорошо.
Самый простой пример с водителем printk()
было бы:
Привет:
#include <linux/module.h>
#include <linux/kernel.h>
int init_module(void)
{
printk(KERN_INFO "Hello world\n");
return 0;
}
void cleanup_module(void)
{
printk(KERN_INFO "Goodbye world\n");
}
Makefile:
obj-m += hello.o
all:
make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules
Затем:
$ make
$ sudo insmod hello.ko
$ dmesg | tail -n1
[7089996.746366] Hello world
http://tldp.org/LDP/lkmpg/2.6/html/lkmpg.html для получения дополнительной информации...
Вы можете от имени root написать /dev/kmsg
для печати в буфер сообщений ядра:
fixnum:~# echo Some message > /dev/kmsg
fixnum:~# dmesg | tail -n1
[28078118.692242] Some message
Я проверил это на своем сервере и на встроенном устройстве Linux, и оно работает на обоих, поэтому я просто собираюсь предположить, что оно работает практически везде.
Основываясь на модуле Кайла выше:
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/proc_fs.h>
#include <asm/uaccess.h>
static int pk_write(struct file *file, const char *buffer, unsigned long count, void *data)
{
char string[256];
count = count < 255 ? count : 255;
if(copy_from_user(string, buffer, count))
return -EFAULT;
string[count] = '\0';
printk(string);
return count;
}
static int __init printk_init(void)
{
struct proc_dir_entry *pk_file;
pk_file = create_proc_entry("printk", 0222, NULL);
if(pk_file == NULL)
return -ENOMEM;
pk_file->write_proc = pk_write;
pk_file->owner = THIS_MODULE;
return 0;
}
static void __exit printk_cleanup(void)
{
remove_proc_entry("printk", NULL);
}
module_init(printk_init);
module_exit(printk_cleanup);
MODULE_LICENSE("GPL");
Чтобы сделать printk из пространства пользователя:
echo "Hello" > /proc/printk
Ответ @Calandoa больше не работает для Ядра +3.10. Сочетал его код и пример кода, который я нашел здесь. Затем улучшилось качество кода...
Код сохранен в printk_user.c
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/proc_fs.h>
#include <asm/uaccess.h>
static ssize_t write_proc(struct file *filep, const char *buffer, size_t count, loff_t *offsetp)
{
char string[256];
count = count < 255 ? count : 255;
if(copy_from_user(string, buffer, count) != 0) {
return -EFAULT;
}
string[count] = '\0';
printk(string);
return count;
}
static const struct file_operations proc_fops = {
.owner = THIS_MODULE,
.write = write_proc,
};
static int proc_init(void) {
struct proc_dir_entry *proc_file;
proc_file = proc_create("printk_user", 0, NULL, &proc_fops);
if(proc_file == NULL) {
return -ENOMEM;
}
return 0;
}
static void proc_cleanup(void) {
remove_proc_entry("printk_user", NULL);
}
MODULE_LICENSE("GPL");
module_init(proc_init);
module_exit(proc_cleanup);
Сделать с помощью этого Makefile
TARGET = printk_user
obj-m := $(TARGET).o
KERNEL_VERSION=$(shell uname -r)
KDIR = /lib/modules/$(KERNEL_VERSION)/build
PWD = $(shell pwd)
printk:
$(MAKE) -C $(KDIR) M=$(PWD) modules
clean:
$(MAKE) -C $(KDIR) M=$(PWD) clean
Думаю, я бы пошел вперед и включил полный пример того, что люди могут просто скомпилировать и запустить для тех, кто не настолько квалифицирован с C, основываясь на ответе @BuvinJ
#include <stdio.h>
#include <string.h>
#include <fcntl.h> // open function
#include <unistd.h> // close function
#include "sys/syscall.h"
int main(); // Let's not worry about this for now
void dmesg( const char *tag, const char *msg, const int len )
{
const int TAG_LEN=3;
char buffer[128]={0};
memcpy( &buffer[0], tag, TAG_LEN );
memcpy( &buffer[TAG_LEN], msg, len );
int fd_kmsg = open( "/dev/kmsg", O_WRONLY );
write( fd_kmsg, &buffer, TAG_LEN+len );
close( fd_kmsg );
}
void dmesgWarn( const char *msg, const int len ){ dmesg( "<4>", msg, len ); }
void dmesgInfo( const char *msg, const int len ){ dmesg( "<6>", msg, len ); }
void dmesgDebug( const char *msg, const int len ){ dmesg( "<7>", msg, len ); }
int main(int argc, char **argv)
{
int getmysize = strlen(argv[1]);
printf("%d\n", getmysize);
printf("To be written: %s\nSize of argument: %d\n", argv[1], getmysize);
// dmesgWarn dmesgInfo or dmesgDebug
dmesgDebug(argv[1], getmysize);
};
Для запуска сохраните вышеприведенное как kmsg.c и gcc kmsg.c -o kmsg;sudo ./kmsg "строка, которую вы хотите добавить в /dev/kmsg"
Основываясь на ответе Кайла, вот краткое руководство, показывающее, как это сделать.
Я просто хотел, чтобы в демоне, написанном кем-то другим в кросс-совместимом ядре, было несколько быстрых сообщений отладки. Я столкнулся с ошибкой компиляции, пытаясь использовать printk
, как <linux/module.h>
не может быть включен. Вместо того, чтобы бороться с этим чрезмерно (чтобы сделать это правильно), я обманул и использовал следующий ленивый, но функциональный 5-минутный обходной путь:
void dmesg( const char *tag, const char *msg, const int len )
{
const int TAG_LEN=3;
char buffer[128]={0};
memcpy( &buffer[0], tag, TAG_LEN );
memcpy( &buffer[TAG_LEN], msg, len );
int fd_kmsg = open( "/dev/kmsg", O_WRONLY );
write( fd_kmsg, &buffer, TAG_LEN+len );
close( fd_kmsg );
}
void dmesgWarn( const char *msg, const int len ){ dmesg( "<4>", msg, len ); }
void dmesgInfo( const char *msg, const int len ){ dmesg( "<6>", msg, len ); }
void dmesgDebug( const char *msg, const int len ){ dmesg( "<7>", msg, len ); }