วิธีเพิ่มข้อความที่จะอ่านด้วย dmesg?


44

ฉันพยายามเขียนข้อความที่กำหนดเองในเอาต์พุต dmesg ของฉัน ฉันเหนื่อย:

logger "Hello"

แต่มันไม่ได้ผล มันออกโดยไม่มีข้อผิดพลาด แต่ไม่มี "Hello" ปรากฏขึ้นภายในผลลัพธ์ของ:

dmesg

ฉันใช้งาน Fedora 9 และดูเหมือนว่าไม่มี syslogd / klogd daemon ทำงานอยู่ อย่างไรก็ตามข้อความเคอร์เนลทั้งหมดของฉันเขียนสำเร็จในบัฟเฟอร์ dmesg

ความคิดใด ๆ

คำตอบ:


37

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#AEN121สำหรับข้อมูลเพิ่มเติม ...


ผมได้รับข้อผิดพลาดเนื่องจากคุณได้ใส่ช่องว่างก่อนmake -C ...ใน Makefile แทนของแท็บเพื่อคัดลอกเนื้อหาข้างต้นของ Makefile ไม่ทำงาน - อื่น ๆ อีกมากมายที่นี่ ฉันดูเหมือนจะไม่สามารถเพิ่มสิ่งนี้ในการแก้ไข ... ขอบคุณโดยคำตอบที่ดี
Wilf

107

คุณสามารถเขียนไป/dev/kmsgที่บัฟเฟอร์ข้อความเคอร์เนลในฐานะรูทได้

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

ฉันได้ทดสอบสิ่งนี้บนเซิร์ฟเวอร์ของฉันและอุปกรณ์ Linux ที่ฝังอยู่และมันทำงานได้ทั้งสองอย่างดังนั้นฉันแค่คิดว่ามันใช้ได้ทุกที่


1
ที่น่าสนใจในอูบุนตูนี่ใช้งานได้ดี แต่ไม่ได้ใช้กับ sudo อันที่จริงต้องกลายเป็นรูต
dotancohen

15
ที่จริงแล้วนั่นเป็นเพราะการเปลี่ยนเส้นทางอินพุตนั้นถูกจัดการโดยเชลล์ของคุณซึ่งไม่ได้ทำงานด้วยสิทธิ์ยกระดับ ลองใช้งานecho Some message | sudo tee /dev/kmesgโดยไม่ใช้รูท
wvdschel

3
ที่ได้ผล ขอบคุณที่น่าสนใจ โดยวิธีการมันkmsgไม่ได้kmesgแต่ฉันยังสับสนกับdmesgที่มี e!
dotancohen

4
ง่ายกว่าการคอมไพล์โมดูลเคอร์เนล
e271p314

13

ขึ้นอยู่กับโมดูลของไคล์ด้านบน:


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

ในการพิมพ์จากพื้นที่ผู้ใช้:

echo "Hello" > /proc/printk

1
สิ่งนี้ใช้ได้กับเคอร์เนล Linux <3.10 เท่านั้น ดูคำตอบของฉันสำหรับทางเลือกที่ใหม่กว่า
kevinf

5

@ คำตอบของ Calandoa ไม่ทำงานสำหรับ Kernel +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


2

คิดว่าฉันจะดำเนินการต่อไปและรวมถึงตัวอย่างที่สมบูรณ์ของสิ่งที่ผู้คนสามารถรวบรวมและเรียกใช้สำหรับผู้ที่ไม่มีทักษะด้วย 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"


0

ฉันแค่ต้องการข้อความดีบั๊กอย่างรวดเร็วใน daemon ที่เขียนโดยคนอื่นในเคอร์เนลที่เข้ากันได้ ฉันพบข้อผิดพลาดในการรวบรวมพยายามที่จะใช้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.