¿Cómo agregar un mensaje que se leerá con dmesg?

44

Estoy tratando de escribir algunos mensajes personalizados en mi salida dmesg. Lo intenté:

logger "Hello"

Pero esto no funciona. Sale sin error, pero no aparece "Hola" en la salida de:

dmesg

Estoy usando un Fedora 9, y parece que no hay ningún demonio syslogd / klogd ejecutándose. Sin embargo, todos los mensajes de mi núcleo se escriben correctamente en el búfer dmesg.

¿Alguna idea?

calandoa
fuente

Respuestas:

37

dmesgmuestra lo que está en el búfer del núcleo, mientras que loggeres para syslogd. Creo que si desea imprimir cosas en el búfer del núcleo, deberá crear un controlador que utilice la printk()función del núcleo. Si solo lo quieres /var/log/messages, entonces con una configuración "normal" creo que lo que has hecho loggerya está bien.

El ejemplo más básico de un controlador con printk()sería:

Hola 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

Entonces:

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

http://tldp.org/LDP/lkmpg/2.6/html/lkmpg.html#AEN121 para más ...

Kyle Brandt
fuente
Recibí un error, ya que has puesto espacios antes del make -C ...archivo Makefile en lugar de una pestaña, por lo que copiar el contenido anterior del archivo Makefile no funciona, más aquí . Parece que no puedo agregar esto en una edición ... Gracias por cierto, gran respuesta.
Wilf
107

Puede, como root, escribir /dev/kmsgpara imprimir en el búfer de mensajes del núcleo:

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

He probado esto en mi servidor y en un dispositivo Linux incorporado, y funciona en ambos, así que voy a suponer que funciona prácticamente en todas partes.

wvdschel
fuente
1
Es interesante que en Ubuntu, esto funcione como root pero no con sudo. Uno realmente necesita convertirse en root.
dotancohen
15
En realidad, eso se debe a que la redirección de entrada es manejada por su shell, que no se ejecuta con derechos elevados. Intenta ejecutar echo Some message | sudo tee /dev/kmesgcomo no root.
wvdschel
3
Eso funciona. Gracias interesante. Por cierto, kmsgno es kmesgpero también me confundo con el dmesgque tiene el e!
dotancohen
44
Mucho más fácil que compilar el módulo del núcleo
e271p314
13

Basado en el módulo de Kyle anterior:


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

Para hacer un printk desde el espacio del usuario:

echo "Hello" > /proc/printk
calandoa
fuente
1
Esto funciona solo para el kernel de Linux <3.10. Vea mi respuesta para una alternativa más nueva.
kevinf
5

La respuesta de @ Calandoa ya no funciona para Kernel +3.10. Combinó su código y el código de ejemplo que encontré aquí . Luego mejoró la calidad del código ...

Código guardado en 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);

Hacer usando este 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
fuente
3

Basado en la respuesta de Kyle, aquí hay un tutorial rápido que muestra cómo hacerlo.

TCampbell
fuente
2

Pensé que seguiría adelante e incluiría un ejemplo completo de algo que la gente puede compilar y ejecutar para aquellos que no son tan hábiles con C basándose en la respuesta 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);
};

Para ejecutar, guarde lo anterior como kmsg.c y gcc kmsg.c -o kmsg; sudo ./kmsg "cadena que desea agregar a / dev / kmsg"

linuxgeek
fuente
0

Solo quería algunos mensajes de depuración rápida en un demonio escrito por otra persona en un núcleo con cumplimiento cruzado. Me encontré con un error de compilación al intentar usarlo printk, ya <linux/module.h>que no podía ser incluido. En lugar de luchar con eso en exceso (para hacer esto de la manera correcta) hice trampa y usé la siguiente solución perezosa pero funcional de 5 minutos:

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
fuente