Skip to content

Instantly share code, notes, and snippets.

@mu-mu-mu
Forked from furandon-pig/krpn.c
Created July 18, 2023 18:35
Show Gist options
  • Save mu-mu-mu/4ef9ef103fc30a59980e324612accb82 to your computer and use it in GitHub Desktop.
Save mu-mu-mu/4ef9ef103fc30a59980e324612accb82 to your computer and use it in GitHub Desktop.
逆ポーランド計算機カーネルモジュール(仮)のサンプルコードです。
/*
* krpn.c - 逆ポーランド計算機カーネルモジュール(仮)
*
* ビルド方法:
* * /usr/src/samples/krpn にソースコードを置いてください。
* * 同じディレクトリにKbuildファイルを作成し、以下を記載します。
*
* obj-m := krpn.o
*
* * 以下の手順でビルドします。
*
* make -C /usr/src M=$PWD
*
* * ビルドしたカーネルモジュールをinsmodします。
*
* # insmod ./krpn.ko
*
* * echo,catコマンドで数字と演算子を/proc/krpnに渡して演算を実行します。
*
* # echo 3 > /proc/krpn
* # echo 4 > /proc/krpn
* # echo '+' > /proc/krpn
* # cat /proc/krpn # => 7
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/seq_file.h>
#include <linux/string.h>
#include <linux/fs.h>
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
#define SEQ_FILE_KRPN_BUFSIZ 1
#define PROC_KRPN_NAME "krpn"
struct seq_file_krpn_data {
char s[32];
};
static struct seq_file_krpn_data krpn_data[16];
#define KRPN_STACK_SIZE 128
static int krpn_stack[KRPN_STACK_SIZE];
static int krpn_index = 0;
static void *seq_file_krpn_get_next_pos(loff_t *pos)
{
if (*pos > SEQ_FILE_KRPN_BUFSIZ - 1) {
return NULL;
}
return krpn_data + *pos;
}
static void *seq_file_krpn_start(struct seq_file *m, loff_t *pos)
{
return seq_file_krpn_get_next_pos(pos);
}
static void seq_file_krpn_stop(struct seq_file *m, void *v)
{
}
static void *seq_file_krpn_next(struct seq_file *m, void *v, loff_t *pos)
{
(*pos)++;
return seq_file_krpn_get_next_pos(pos);
}
static int seq_file_krpn_show(struct seq_file *m, void *v)
{
int i;
char stack_state_str[128];
char *s = stack_state_str;
*s = '\0';
for (i = 0; i < krpn_index; i++) {
printk("%d ", krpn_stack[i]);
s += sprintf(s, "%d ", krpn_stack[i]);
}
printk("krpn stack: %s\n", stack_state_str);
seq_printf(m, "%s\n", stack_state_str);
return 0;
}
static struct seq_operations seq_file_krpn_seq_ops = {
.start = seq_file_krpn_start,
.stop = seq_file_krpn_stop,
.next = seq_file_krpn_next,
.show = seq_file_krpn_show,
};
static int seq_file_krpn_open(struct inode *inode, struct file *file)
{
return seq_open(file, &seq_file_krpn_seq_ops);
}
// echo 1 > /proc/krpn が実行されるとこの関数が呼ばれる。
static ssize_t proc_krpn_write(struct file *filp, const char __user *buf, size_t count, loff_t *f_pos)
{
int is_number = 1;
int i;
char str[32];
char *c;
char stack_state_str[128];
char *s = stack_state_str;
if (count > sizeof(str)) {
count = sizeof(str) - 1;
}
if (copy_from_user(str, buf, count)) {
return -EFAULT;
}
str[count] = '\0';
// 改行文字があった場合は除去しておく。
for (c = str; *c; c++) {
if (*c == '\n') { *c = '\0'; }
}
// 数字のみで構成される文字列かどうかチェックする。
// (isdigit()相当の挙動を想定)
for (c = str; *c; c++) {
if (*c != '0'
&& *c != '1'
&& *c != '2'
&& *c != '3'
&& *c != '4'
&& *c != '5'
&& *c != '6'
&& *c != '7'
&& *c != '8'
&& *c != '9'
) {
is_number = 0;
}
}
// 四則演算子・数字のそれぞれに応じて処理を分ける。
c = str;
if(*c == '+' || *c == '-' || *c == '*' || *c == '/') {
// 四則演算子だった場合は、各演算子に沿った演算を実行して結果をスタックに戻す。
int x, y;
y = krpn_stack[--krpn_index];
x = krpn_stack[--krpn_index];
switch (*c) {
case '+': krpn_stack[krpn_index++] = x + y; break;
case '-': krpn_stack[krpn_index++] = x - y; break;
case '*': krpn_stack[krpn_index++] = x * y; break;
case '/': krpn_stack[krpn_index++] = x / y; break;
}
} else if (is_number == 1 && *c != '\0') {
// 数字だった場合は単にスタックに値を積む。
krpn_stack[krpn_index++] = (int)simple_strtol(str, NULL, 10);
}
// デバッグ用にカーネルメッセージでスタックの内容を表示させる。
s = stack_state_str;
*s = '\0';
for (i = 0; i < krpn_index; i++) {
s += sprintf(s, "%d ", krpn_stack[i]);
}
printk("krpn stack: %s\n", stack_state_str);
return count;
}
static struct proc_ops seq_file_krpn_fops = {
.proc_open = seq_file_krpn_open,
.proc_read = seq_read,
.proc_write = proc_krpn_write,
.proc_release = seq_release,
};
static int krpn_init(void)
{
struct proc_dir_entry *entry = NULL;
printk("-=> krpn_init()\n");
entry = proc_create(PROC_KRPN_NAME, S_IRUGO | S_IWUGO, NULL, &seq_file_krpn_fops);
return 0;
}
static void krpn_exit(void)
{
printk("-=> krpn_exit()\n");
remove_proc_entry(PROC_KRPN_NAME, NULL);
}
module_init(krpn_init);
module_exit(krpn_exit);
MODULE_LICENSE("GPL");
MODULE_INFO(krpn, "Y");
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment