dmesg로 읽을 메시지를 추가하는 방법은 무엇입니까?


44

내 dmesg 출력에 사용자 정의 메시지를 작성하려고합니다. 나는 시도했다 :

logger "Hello"

그러나 이것은 작동하지 않습니다. 오류없이 종료되지만 다음과 같은 출력에 "Hello"가 나타나지 않습니다.

dmesg

Fedora 9를 사용하고 있는데 syslogd / klogd 데몬이 실행되지 않는 것 같습니다. 그러나 모든 커널 메시지가 dmesg 버퍼에 성공적으로 작성되었습니다.

어떤 생각?

답변:


37

dmesg커널 버퍼에있는 것을 표시하는 반면 logger에는입니다 syslogd. 커널 버퍼에 내용을 인쇄하려면 printk()커널 기능 을 사용하는 드라이버를 만들어야한다고 생각합니다 . 당신이 그것을 원한다면 /var/log/messages"정상"설정으로 당신이 한 일 logger이 이미 훌륭 하다고 생각 합니다.

드라이버의 가장 기본적인 예는 다음과 printk()같습니다.

hello.c :

#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");

}

메이크 파일 :

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#AEN121 ...


당신이 전에 공백을 넣어 가지고 있기 때문에 나는 오류를 가지고 make -C ...더 - 대신 탭의 메이크 너무 작업 메이크의 위의 내용을하지 않는 복사, 여기 . 편집에 이것을 추가 할 수없는 것 같습니다 ... 그건 그렇고, 훌륭한 답변입니다.
Wilf

107

루트로서 /dev/kmsg커널 메시지 버퍼에 인쇄하기 위해 쓸 수 있습니다 .

 fixnum:~# echo Some message > /dev/kmsg
 fixnum:~# dmesg | tail -n1
 [28078118.692242] Some message

나는 이것을 서버와 임베디드 리눅스 장치에서 테스트했으며 두 가지 모두에서 작동하므로 거의 모든 곳에서 작동한다고 가정합니다.


1
우분투에서 이것은 루트로 작동하지만 sudo에서는 작동하지 않습니다. 실제로 루트가되어야합니다.
dotancohen

15
실제로는 입력 리디렉션이 높은 권한으로 실행되지 않는 셸에서 처리되기 때문입니다. echo Some message | sudo tee /dev/kmesg비 루트로 실행 해보십시오 .
wvdschel

3
작동합니다. 고마워요 그건 그렇고, 그 kmsg뿐만 kmesg아니라 dmesg전자가있는 것과 혼동 합니다!
dotancohen

4
커널 모듈을 컴파일하는 것보다 훨씬 쉽습니다.
e271p314 9

13

위의 Kyle 모듈을 기반으로 :


#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

1
이것은 Linux 커널 <3.10에서만 작동합니다. 새로운 대안에 대한 내 대답을 참조하십시오.
kevinf

5

@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

3

카일의 대답의 기반으로, 여기 다만 그것을하는 방법을 보여주는 간단한 튜토리얼입니다.


2

@BuvinJ의 답변을 기반으로 C에 익숙하지 않은 사람들을 위해 사람들이 컴파일하고 실행할 수있는 전체 예제를 포함 시켰습니다.

#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에 추가 할 문자열"로 저장하십시오.


0

교차 호환 커널의 다른 사람이 작성한 데몬의 빠른 디버깅 메시지를 원했습니다. 내가 사용하려고 컴파일 오류에 달렸다 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 ); }
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.