LKM入出力用LKM
LKMからのファイル出力での多少は使えるかな(?)ってレベルの、端末を通してLKMで入出力するLKMを作ってみました。関数名はtty_writek/tty_readkです。printkのかわりにtty_writekといった具合です。端末はカレントプロセスとなります。通常カレントプロセスは、insmodした端末となります。入出力は標準入出力で行っています。従って、入力でのプロンプトは表示されませんが、LKMからの出力はリダイレクトして、ファイルに落とし込むことが可能です。
LKM入出力用LKM
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/fs.h>
#include <linux/file.h>
#include <linux/mm.h>
#include <linux/err.h>
#include <asm-generic/mman-common.h>
#include <linux/stat.h>
MODULE_DESCRIPTION("ttyk");
MODULE_AUTHOR("y.kitamura");
MODULE_LICENSE("GPL");
struct lkm_prn_buff {
char prompt[64];
char msg[];
};
int tty_writek(char const * buff);
int tty_readk(char *buf);
static int is_ireg(struct inode *inode);
static long my_mmap(void *addr, size_t length, int prot, int flags);
static long my_munmap(void *addr, size_t length);
static int ttyk_init(void) { return 0; }
static void ttyk_exit(void) {}
int tty_readk(char *buff)
{
struct file *file0, *file1;
int ret = 0;
struct lkm_prn_buff *addr;
file0 = fget(0);
file1 = fget(1);
addr = (struct lkm_prn_buff *)my_mmap(
NULL, PAGE_SIZE, PROT_READ|PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS);
if (!is_ireg(file1->f_dentry->d_inode)) {
strcpy(addr->prompt, "[lkm]< ");
ret = file1->f_op->write(file1, addr->prompt, strlen(addr->prompt), &file1->f_pos);
}
ret = file0->f_op->read(file0, addr->msg, PAGE_SIZE - sizeof(addr->prompt), &file0->f_pos);
if (ret > 0) {
strcpy(buff, addr->msg);
if (buff[ret - 1] == 0x0a) {
buff[ret - 1] = 0x00;
ret--;
}
}
fput(file0);
fput(file1);
if (my_munmap(addr, PAGE_SIZE)) {
ret = -1;
printk("munmap err\n");
}
return ret;
}
EXPORT_SYMBOL_GPL(tty_readk);
int tty_writek(char const * buff)
{
struct file *file;
int ret = 0;
struct lkm_prn_buff *addr;
file = fget(1);
addr = (struct lkm_prn_buff *)my_mmap(
NULL, PAGE_SIZE, PROT_READ|PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS);
if (!is_ireg(file->f_dentry->d_inode)) {
strcpy(addr->prompt, "[lkm]> ");
ret = file->f_op->write(file, addr->prompt, strlen(addr->prompt), &file->f_pos);
if (ret != strlen(addr->prompt)) {
ret = -1;
printk("err\n");
}
}
strcpy(addr->msg, buff);
ret = file->f_op->write(file, addr->msg, strlen(addr->msg), &file->f_pos);
fput(file);
if (ret != strlen(addr->msg)) {
ret = -1;
printk("err\n");
}
ret = my_munmap(addr, PAGE_SIZE);
if (ret) {
printk("%d\n", ret);
}
return ret;
}
EXPORT_SYMBOL_GPL(tty_writek);
static long my_mmap(void *addr, size_t length, int prot, int flags)
{
long mmap;
int dymmy = 0;
__asm__ volatile ("push %%ebp;movl %%edi,%%ebp;int $0x80;pop %%ebp"
: "=a"(mmap)
: "a"(__NR_mmap2), "b"(addr), "c"(length), "d"(prot),"S"(flags), "D"(dymmy));
if (IS_ERR((const void *)mmap))
return PTR_ERR((const void *)mmap);
return mmap;
}
static long my_munmap(void *addr, size_t length)
{
long err;
__asm__ volatile ("int $0x80"
: "=a"(err)
: "a"(__NR_munmap), "b"(addr), "c"(length));
return err;
}
static int is_ireg(struct inode *inode)
{
return (S_ISREG(inode->i_mode))? 1: 0;
}
module_init(ttyk_init);
module_exit(ttyk_exit);
使用サンプル
#include <linux/module.h>
MODULE_DESCRIPTION("ttyk test");
MODULE_AUTHOR("y.kitamura");
MODULE_LICENSE("GPL");
long tty_writek(const char* a);
long tty_readk(char* a);
static int test_init(void)
{
long ret;
char buff1[64], buff2[64];
ret = tty_readk(buff1);
sprintf(buff2, "%s is from tty\n", buff1);
ret = tty_writek(buff2);
return 0;
}
static void test_exit()
{
}
module_init(test_init);
module_exit(test_exit);
使用方法
端末 [root@localhost kitamura]# insmod ttyk.ko [root@localhost kitamura]# insmod test.ko [lkm]< abcdefg [lkm]> abcdefg is from tty [root@localhost kitamura]# rmmod test.ko リダイレクト [root@localhost kitamura]# insmod test.ko > log abcdefg [root@localhost kitamura]# cat log abcdefg is from tty





