Comment ajouter un message qui sera lu avec dmesg?

44

J'essaie d'écrire des messages personnalisés dans ma sortie dmesg. J'ai essayé:

logger "Hello"

mais ça ne marche pas. Il se ferme sans erreur, mais aucun "Bonjour" n'apparaît dans la sortie de:

dmesg

J'utilise une Fedora 9 et il semble qu'aucun démon syslogd / klogd ne soit en cours d'exécution. Cependant, tous les messages de mon noyau sont écrits avec succès dans le tampon dmesg.

Une idée?

calandoa
la source

Réponses:

37

dmesgaffiche ce qui est dans le tampon du noyau, alors que loggerc'est pour syslogd. Je pense que si vous souhaitez imprimer des éléments dans la mémoire tampon du noyau, vous devez créer un pilote qui utilise la printk()fonction du noyau. Si vous le voulez /var/log/messages, alors avec une configuration "normale", je pense que ce que vous avez fait avec loggerest déjà bien.

L'exemple le plus fondamental d'un pilote avec printk()serait:

Bonjour 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

Ensuite:

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

http://tldp.org/LDP/lkmpg/2.6/html/lkmpg.html#AEN121 pour plus ...

Kyle Brandt
la source
J'ai une erreur, car vous avez mis des espaces avant make -C ...dans le Makefile au lieu d'un onglet, donc copier le contenu ci-dessus du Makefile ne fonctionne pas - plus ici . Il semble que je ne puisse pas ajouter ceci dans une édition ... Merci au fait, bonne réponse.
Wilf
108

Vous pouvez, en tant que root, écrire sur /dev/kmsgpour imprimer dans le tampon de messages du noyau:

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

J'ai testé cela sur mon serveur et un périphérique Linux intégré, et cela fonctionne sur les deux, donc je vais simplement supposer que cela fonctionne un peu partout.

Wvdschel
la source
1
Ce qui est intéressant dans Ubuntu, cela fonctionne en tant que root mais pas avec sudo. Il faut en fait devenir root.
dotancohen
15
En réalité, c'est parce que la redirection des entrées est gérée par votre shell, qui ne s'exécute pas avec des droits élevés. Essayez d’exécuter en echo Some message | sudo tee /dev/kmesgtant que non-root.
wvdschel
3
Ça marche. Merci, intéressant. Par ailleurs, ce kmsgn'est pas kmesgmais je confonds aussi avec dmesgqui a le e!
dotancohen
4
Beaucoup plus facile que la compilation du module de noyau
e271p314
13

Basé sur le module de Kyle ci-dessus:


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

Pour faire un printk à partir de l'espace utilisateur:

echo "Hello" > /proc/printk
calandoa
la source
1
Cela fonctionne pour le noyau Linux <3.10 seulement. Voir ma réponse pour une alternative plus récente.
kevinf
5

La réponse de @ Calandoa ne fonctionne plus pour le noyau +3.10. Combiné son code, et l'exemple de code que j'ai trouvé ici . Puis amélioration de la qualité du code ...

Code enregistré dans 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);

Faire en utilisant ce 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
la source
3

Sur la base de la réponse de Kyle, voici un tutoriel rapide montrant comment faire exactement cela.

TCampbell
la source
2

Je pensais pouvoir inclure un exemple complet de quelque chose que les gens peuvent simplement compiler et lancer pour ceux qui ne sont pas aussi doués avec C que la réponse de @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);
};

Pour exécuter, sauvegardez ce qui précède sous les noms kmsg.c et gcc kmsg.c -o kmsg; sudo ./kmsg "chaîne à ajouter à / dev / kmsg"

linuxgeek
la source
0

Je voulais juste quelques messages de débogage rapides dans un démon écrit par quelqu'un d'autre dans un noyau compatible. Je suis tombé sur une erreur de compilation en essayant d'utiliser printk, car <linux/module.h>il ne pouvait pas être inclus. Plutôt que de me battre avec cela de façon excessive (pour faire ceci correctement), j'ai triché et utilisé la solution de contournement paresseuse, mais fonctionnelle, de 5 minutes suivante:

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
la source