Bagaimana cara menambahkan pesan yang akan dibaca dengan dmesg?

44

Saya mencoba menulis beberapa pesan khusus di output dmesg saya. Saya mencoba:

logger "Hello"

tetapi ini tidak berhasil. Keluar tanpa kesalahan, tetapi tidak ada "Hello" muncul di output dari:

dmesg

Saya menggunakan Fedora 9, dan sepertinya tidak ada daemon syslogd / klogd yang berjalan. Namun, semua pesan kernel saya berhasil ditulis dalam buffer dmesg.

Ada ide?

calandoa
sumber

Jawaban:

37

dmesgmenampilkan apa yang ada di buffer kernel, sedangkan loggeruntuk syslogd. Saya pikir jika Anda ingin mencetak hal-hal ke dalam buffer kernel Anda perlu membuat driver yang menggunakan printk()fungsi kernel. Jika Anda hanya menginginkannya /var/log/messages, maka dengan pengaturan "normal" saya pikir apa yang telah Anda lakukan loggersudah baik-baik saja.

Contoh paling mendasar dari seorang pengemudi printk()adalah:

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

}

Makefile:

obj-m += hello.o

all:
    make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules

Kemudian:

$ make
$ sudo insmod hello.ko
$ dmesg | tail -n1
 [7089996.746366] Hello world

http://tldp.org/LDP/lkmpg/2.6/html/lkmpg.html#AEN121 untuk informasi lebih lanjut ...

Kyle Brandt
sumber
Saya mendapat kesalahan, karena Anda telah menempatkan spasi sebelum make -C ...di Makefile daripada Tab, jadi menyalin konten Makefile di atas tidak berfungsi - lebih lanjut di sini . Tampaknya saya tidak dapat menambahkan ini dalam edit ... Terima kasih, jawaban yang bagus.
Wilf
107

Anda dapat, sebagai root, menulis /dev/kmsguntuk mencetak ke buffer pesan kernel:

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

Saya sudah menguji ini di server saya dan perangkat Linux yang disematkan, dan itu berfungsi pada keduanya, jadi saya hanya akan menganggap itu bekerja cukup banyak di mana-mana.

wvdschel
sumber
1
Menarik bahwa di Ubuntu, ini berfungsi sebagai root tetapi tidak dengan sudo. Seseorang sebenarnya perlu menjadi root.
dotancohen
15
Sebenarnya, itu karena pengalihan input ditangani oleh shell Anda, yang tidak berjalan dengan hak tinggi. Coba jalankan echo Some message | sudo tee /dev/kmesgsebagai non-root.
wvdschel
3
Itu bekerja. Terima kasih, menarik. By the way, itu kmsgtidak kmesgtetapi saya juga bingung dengan dmesgyang memiliki e!
dotancohen
4
Jauh lebih mudah daripada mengkompilasi modul kernel
e271p314
13

Berdasarkan modul Kyle di atas:


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

Untuk melakukan printk dari ruang pengguna:

echo "Hello" > /proc/printk
calandoa
sumber
1
Ini bekerja untuk kernel Linux <3,10 saja. Lihat jawaban saya untuk alternatif yang lebih baru.
kevinf
5

@ Jawaban Calandoa tidak lagi berfungsi untuk Kernel +3.10. Gabungan kodenya, dan contoh kode yang saya temukan di sini . Kemudian ditingkatkan pada kualitas kode ...

Kode disimpan ke 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);

Buat menggunakan Makefile ini

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
kevinf
sumber
3

Berdasarkan jawaban Kyle, berikut ini adalah tutorial singkat yang menunjukkan bagaimana melakukan hal itu.

TCampbell
sumber
2

Kupikir aku akan pergi ke depan dan memasukkan contoh lengkap dari sesuatu yang bisa dikompilasi dan dijalankan oleh orang-orang yang tidak begitu mahir dengan C berdasarkan dari jawaban @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);
};

Untuk menjalankan simpan di atas sebagai kmsg.c dan gcc kmsg.c -o kmsg; sudo ./kmsg "string yang ingin Anda tambahkan ke / dev / kmsg"

linuxgeek
sumber
0

Saya hanya ingin beberapa pesan debug cepat dalam daemon yang ditulis oleh orang lain di kernel yang dipenuhi lintas. Saya mengalami kesalahan kompilasi yang mencoba digunakan printk, karena <linux/module.h>tidak dapat dimasukkan. Alih-alih bertarung dengan hal itu secara berlebihan (untuk melakukan ini dengan cara yang benar), saya curang dan menggunakan solusi 5 menit yang malas, tetapi fungsional:

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 ); }
Terima kasih
sumber