fizzbuzz systemcall in FreeBSD
Linuxは知らないですが、FreeBSDはわりと簡単システムコールが
追加できるので、紹介します。
コード
#include <sys/param.h> #include <sys/proc.h> #include <sys/module.h> #include <sys/sysproto.h> #include <sys/sysent.h> #include <sys/kernel.h> #include <sys/systm.h> struct fizzbuzz_args { int a_number; char *a_buf; }; static int fizzbuzz(struct thread *td, struct fizzbuzz_args *uap) { int num = uap->a_number, len; char buf[32] = {0}, *p; if (num % 5 == 0 && num % 3 == 0) { p = "fizzbuzz"; len = sizeof("fizzbuzz"); } else if (num % 5 == 0) { p = "buzz"; len = sizeof("buzz"); } else if (num % 3 == 0) { p = "fuzz"; len = sizeof("fizz"); } else { len = sprintf(buf, "%d", num); len +=1; p = buf; } return copyout(p, uap->a_buf, len); } static struct sysent fizzbuzz_sysent = { .sy_narg = 2, .sy_call = (sy_call_t*)fizzbuzz }; static int fizzbuzz_offset = NO_SYSCALL; static int fizzbuzz_load(struct module *module, int cmd, void *arg) { int error = 0; switch (cmd) { case MOD_LOAD : printf("load fizzbuzz syscall\n"); break; case MOD_UNLOAD : printf("unload fizzbuzz syscall\n"); break; default : error = EOPNOTSUPP; break; } return (error); } SYSCALL_MODULE(fizzbuzz, &fizzbuzz_offset, &fizzbuzz_sysent, fizzbuzz_load, NULL);
ローダブルモジュールのロード
まず Makefileを書きます。
KMOD= fizzbuzz SRCS= fizzbuzz.c .include <bsd.kmod.mk>
そしてビルドします。
% make
ビルドに成功すると fizzbuzz.koができるので
それをローダブルモジュールとしてロードします。
% sudo kldload ./fizzbuzz.ko
カーネル内の print文は dmesgに出力されるので確認します。
% dmesg ... load fizzbuzz syscall
テストプログラム
システムコールの実行には間接的にシステムコールを呼び出す、
syscallシステムコールを使います。
#include <sys/types.h> #include <sys/module.h> #include <sys/syscall.h> #include <stdio.h> #include <stdlib.h> #include <unistd.h> int main(void) { struct module_stat stat; int syscall_number, i, error; char buf[32]; stat.version = sizeof(stat); modstat(modfind("sys/fizzbuzz"), &stat); syscall_number = stat.data.intval; for (i = 1; i <= 15; i++) { error = syscall(syscall_number, i, buf); if (error) { fprintf(stderr, "Error %d\n", error); return -1; } printf("%2d = %s\n", i, buf); } return 0; }
実行, 確認
あとは普通にコンパイルして実行するだけです。
% gcc test.c %./a.out 1 = 1 2 = 2 3 = fuzz 4 = 4 5 = buzz 6 = fuzz 7 = 7 8 = 8 9 = fuzz 10 = buzz 11 = 11 12 = fuzz 13 = 13 14 = 14 15 = fizzbuzz
アンロード
最後に unloadしておきます。
% sudo kldunload fizzbuzz.ko
おわりに
カーネル内で誤ったメモリ操作を行うと panicするので
若干の注意が必要です。まあ今時普通に OS使ってて panic
することなんて皆無なので一度ぐらい経験しておくと良い
かもしれません。