54

I am trying to write some custom messages in my dmesg output. I tried:

logger "Hello"

but this does not work. It exits without error, but no "Hello" appears int the output of:

dmesg

I am using a Fedora 9, and it seems that there is no syslogd/klogd daemon running. However, all my kernel messages are succesfully written in the dmesg buffer.

Any idea?

calandoa
  • 1,345
  • 2
  • 12
  • 14

8 Answers8

138

You can, as root, write to /dev/kmsg to print to the kernel message buffer:

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

I've tested this on my server and an embedded Linux device, and it works on both, so I'm just going to assume it works pretty much everywhere.

wvdschel
  • 1,481
46

dmesg displays what is in the kernel buffer, whereas logger is for syslogd. I think if you want to print things into the kernel buffer you will need to create a driver that uses the printk() kernel function. If you just want it in /var/log/messages, then with a "normal" setup I think what you have done with logger is already fine.

The most basic example of a driver with printk() would be:

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

Then:

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

http://tldp.org/LDP/lkmpg/2.6/html/lkmpg.html#AEN121 for more...

kasperd
  • 31,086
Kyle Brandt
  • 85,693
14

Based on Kyle's module above:


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

To do a printk from user space:

echo "Hello" > /proc/printk
calandoa
  • 1,345
  • 2
  • 12
  • 14
6

@Calandoa's answer no longer works for Kernel +3.10. Combined his code, and the example code I found here. Then improved on the code quality...

Code saved to 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);

Make using this 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

You'll need your current running kernel source code installed in order to make this. After you run make you will need to sudo insmod printk_user.ko to load the kernel module. The module creates /proc/printk_user, by default with permissions 444. If you need all users to access, modify with sudo chmod 666 /proc/printk_user

To do a printk from user space:

echo "Hello" > /proc/printk_user

Sample output:

$ dmesg | tail
[13291030.939275] printk_user: loading out-of-tree module taints kernel.
[13291030.939862] printk_user: module verification failed: signature and/or required key missing - tainting kernel
[13291103.728306] Hello

edit: /proc/printk used to be for Kernel 3/4, but it appears the latest kernel has support for /proc/printk_user

Kevin
  • 217
  • 2
  • 9
3

Based off of Kyle's answer, here is a quick tutorial showing how to do just that.

TCampbell
  • 2,054
3

Figured I'd go ahead and include a full blown example of something that people can just compile and run for those that aren't as skilled with C based off of @BuvinJ 's answer

#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(&quot;To be written: %s\nSize of argument: %d\n&quot;, argv[1], getmysize);
// dmesgWarn dmesgInfo or dmesgDebug
dmesgDebug(argv[1], getmysize);

};

To run save the above as kmsg.c then execute gcc kmsg.c -o kmsg and run as sudo ./kmsg "string you want to add to /dev/kmsg"

linuxgeek
  • 130
2

I just wanted some quick debugging messages in a daemon written by someone else in a cross complied kernel. I ran into a compile error trying to use printk, as <linux/module.h> could not be included. Rather then battle with that excessively (to do this the right way) I cheated and used the following lazy, but functional 5 minute workaround:

void dmesg( const char *tag, const char *msg, const int len )
{
    size_t taglen = strlen(tag);
    char buffer[taglen + len];
    memcpy(&buffer[0], tag, taglen);
    memcpy(&buffer[taglen], 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); }

UPDATE (Thanks @glglgl!)

A much simpler version could be like this:

void dmesg( const unsigned int tag, const char *msg)
{
    size_t msglen = sprintf(NULL, "<%u>%s", tag, msg);
    char buffer[msglen + 1];
    sprintf(buffer, "<%u>%s", tag, msg);
    // snprintf(buffer, sizeof(buffer), "<%u>%s", tag, msg);
    // would be safer, but here we make sure that everything works as it should.
    int fd_kmsg = open("/dev/kmsg", O_WRONLY);
    write(fd_kmsg, &buffer, msglen);
    close(fd_kmsg);
}
void dmesgWarn(const char *msg) { dmesg(4, msg); }
void dmesgInfo(const char *msg) { dmesg(6, msg); }
void dmesgDebug(const char *msg) { dmesg(7, msg); }

It now just takes strings, integrates them in a message to be written to that file and writes it.

Now that we talk about it, it can be even much easier:

void dmesg( const unsigned int tag, const char *msg)
{
    int fd_kmsg = open("/dev/kmsg", O_WRONLY);
    FILE * f_kmsg = fdopen(fd_kmsg, "w");
    fprintf(f_kmsg, "<%u>%s", tag, msg);
    fclose(f_kmsg); // closes the underlying fd_kmsg as well
}
void dmesgWarn(const char *msg) { dmesg(4, msg); }
void dmesgInfo(const char *msg) { dmesg(6, msg); }
void dmesgDebug(const char *msg) { dmesg(7, msg); }
BuvinJ
  • 419
0

In case it can help someone dealing with this dmesg / kernel logs from userspace topic, but with interaction with upper level tools like journald/journalctl and loki/promtail.

As an addition to previous comment How to add message that will be read with dmesg?,

I'd recommend to use this form:

echo "<2>kernel: EXT4-fs (sda2): I/O error while writing superblock" > /dev/kmsg

With <i> being severity level and kernel: specific tag, before any kernel "subsystem" additional tag.

Using kernel tag, journalctl won't report the log as issued by service "unknown". And in some cases it can also help to get your log properly ingested by tools like Loki/Promtail.

Rip
  • 1