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