Wie füge ich eine Nachricht hinzu, die mit dmesg gelesen wird?

44

Ich versuche, einige benutzerdefinierte Nachrichten in meine dmesg-Ausgabe zu schreiben. Ich habe es versucht:

logger "Hello"

aber das geht nicht. Es wird ohne Fehler beendet, aber in der Ausgabe von wird kein "Hallo" angezeigt:

dmesg

Ich verwende Fedora 9 und es scheint, dass kein syslogd / klogd-Daemon läuft. Alle meine Kernel-Nachrichten werden jedoch erfolgreich in den Dmesg-Puffer geschrieben.

Irgendeine Idee?

calandoa
quelle

Antworten:

37

dmesgzeigt an, was sich im Kernelpuffer befindet, wohingegen loggerfür syslogd. Ich denke, wenn Sie Dinge in den Kernel-Puffer drucken möchten, müssen Sie einen Treiber erstellen, der die printk()Kernel-Funktion verwendet. Wenn Sie es nur wollen /var/log/messages, dann mit einem "normalen" Setup denke ich, was Sie getan haben, loggerist bereits in Ordnung.

Das grundlegendste Beispiel für einen Fahrer mit printk()wäre:

Hallo 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

Dann:

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

http://tldp.org/LDP/lkmpg/2.6/html/lkmpg.html#AEN121 für mehr ...

Kyle Brandt
quelle
Ich habe eine Fehlermeldung erhalten, da Sie make -C ...im Makefile anstelle eines Tabulators Leerzeichen vor dem eingefügt haben . Daher funktioniert das Kopieren der obigen Inhalte des Makefiles nicht - mehr hier . Ich scheine nicht in der Lage zu sein, dies in einer Bearbeitung hinzuzufügen ... Danke übrigens, tolle Antwort.
Wilf
107

Sie können als Root schreiben /dev/kmsg, um in den Kernel-Nachrichtenpuffer zu drucken:

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

Ich habe dies auf meinem Server und einem eingebetteten Linux-Gerät getestet und es funktioniert auf beiden, also gehe ich davon aus, dass es so ziemlich überall funktioniert.

wvdschel
quelle
1
Interessanterweise funktioniert dies in Ubuntu als root, aber nicht mit sudo. Man muss eigentlich Wurzel werden.
Dotancohen
15
Tatsächlich liegt das daran, dass die Eingabeumleitung von Ihrer Shell übernommen wird, die nicht mit erhöhten Rechten ausgeführt wird. Versuchen Sie, echo Some message | sudo tee /dev/kmesgals Nicht-Root-Benutzer zu arbeiten.
Wvdschel
3
Das funktioniert. Danke, interessant. Übrigens ist es kmsgnicht, kmesgaber ich verwechsle auch mit dem, dmesgwas das e hat!
Dotancohen
4
Viel einfacher als das Kompilieren des Kernelmoduls
e271p314
13

Basierend auf Kyles Modul oben:


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

So drucken Sie aus dem Benutzerbereich:

echo "Hello" > /proc/printk
calandoa
quelle
1
Dies funktioniert nur für Linux-Kernel <3.10. Siehe meine Antwort für eine neuere Alternative.
Kevin vom
5

@ Calandoas Antwort funktioniert nicht mehr für Kernel +3.10. Kombiniert seinen Code und den Beispielcode, den ich hier gefunden habe . Dann verbesserte sich die Codequalität ...

In printk_user.c gespeicherter Code

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

Machen Sie mit diesem 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
kevinf
quelle
3

Basierend auf Kyles Antwort finden Sie hier ein kurzes Tutorial, das zeigt, wie Sie genau das tun können.

TCampbell
quelle
2

Ich habe mir vorgenommen, ein vollständiges Beispiel für etwas beizufügen, das die Leute nur für diejenigen kompilieren und ausführen können, die auf der Grundlage von @BuvinJs Antwort nicht so gut mit C umgehen können

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

Um es auszuführen, speichere es als kmsg.c und gcc kmsg.c -o kmsg; sudo ./kmsg "String, den du zu / dev / kmsg hinzufügen willst"

linuxgeek
quelle
0

Ich wollte nur ein paar schnelle Debugging-Meldungen in einem Daemon, der von jemand anderem in einem cross-konformen Kernel geschrieben wurde. Ich bin auf einen Kompilierungsfehler gestoßen, der versucht zu verwenden printk, da dieser <linux/module.h>nicht enthalten sein konnte. Statt übermäßig damit umzugehen (um das richtig zu machen), habe ich betrogen und die folgende faule, aber funktionierende 5-minütige Problemumgehung verwendet:

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 ); }
BuvinJ
quelle