使用fopen開啟檔案時
有時會發生無法開啟的錯誤
此時可以在程式碼中加入
extern int errno;
取得開檔之錯誤代碼
之後可用strerror()取得錯誤代碼之錯誤訊息
char *err_str = strerror(errno);
印出錯誤訊息就可以知道問題在哪
使用fopen開啟檔案時
有時會發生無法開啟的錯誤
此時可以在程式碼中加入
extern int errno;
取得開檔之錯誤代碼
之後可用strerror()取得錯誤代碼之錯誤訊息
char *err_str = strerror(errno);
印出錯誤訊息就可以知道問題在哪
1.
引用標頭檔 linux/ioctl.h
#include <linux/ioctl.h>
若 kernel 內有定義 CONFIG_COMPAT 這 defined constant
表示 ioctl 在 相容模式 (compatibility mode)
要多引用 linux/compat.h
#include <linux/compat.h>
2.
建立 defined constants
2.1.
建立等會建立 ioctl command 要用的 type,類似 prefix
#define TYPE 's'
#define TYPE '<char>'
<char>: 任何字元用以當 command 的 type
2.2.
建立 ioctl command
例:
#define SM_GET _IOR(TYPE, 1, int)
#define SM_SET _IOW(TYPE, 2, int)
定義 command 可用的 macro
_IO(<cmd type>, <number>);
_IOR(<cmd type>, <number>, <arg type>);
_IOW(<cmd type>, <number>, <arg type>);
_IOWR(<cmd type>, <number>, <arg type>);
_IO 讀寫:寫到 proc 用 arg,回傳值是要讀取的資料
_IOR 讀:把 arg 當指標從 kernel 取得資料,配合 copy_to_user() 和 put_user()
_IOW 寫:把 arg 當指標傳資料至 kernel,配合 copy_from_user() 和 get_user()
_IOWR 讀寫:把arg 當指標進行讀取與寫入,copy_from_user() 和 get_user()
copy_to_user() 和 put_user()
<cmd type>: 被 shift 至 <number> 前端,類似 prefix
<number>: 第幾個 command
<arg type>: 參數的型態,像是 int, long,...
2.3.
撰寫 ioctl
例:
int smalldd_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
{
int ret = 0;
int value = 1;
struct data data;
switch(cmd)
{
case SM_GET:
put_user(value, arg);
OR
copy_to_user((void *)arg, &data, sizeof(struct data));
break;
case SM_SET:
get_user(value, arg);
OR
copy_from_user((void *)arg, &data, sizeof(struct data));
break;
default:
break;
}
return ret;
}
若有定義 CONFIG_COMPAT 這 defined constant
要多撰寫相容模式的 compat_ioctl
例:
#ifdef CONFIG_COMPAT
long smalldd_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
return smalldd_ioctl(NULL, file, cmd, arg);
}
#endif
2.4.
建立 file_operations
順道加入 compat_ioctl
例:
struct file_operations smalldd_fops
{
.owner = THIS_MODULE,
.ioctl = smalldd_ioctl,
#ifdef CONFIT_COMPAT
.compat_ioctl = smalldd_compat_ioctl,
#endif
}
3.
user space 的程式透過 ioctl 與 kernel space 交換資料
例:
int fd = 0;
int ret = 0;
int data = 0; // 參數
fd = open(<file>, O_RDWR);
if(fd >= 0)
{
ret = ioctl(fd, SM_SET, &data); // 傳資料到 kernel space
ret = ioctl(fd, SM_GET, &data); // 從 kernel 取得資料
}
假設寫了一支 smalldd 的程式是一支以網路核心功能開發的程式
1.
把 smalldd.h 檔放到 include/net/ 下
2.
把 smalldd.c 檔放到 net/core/ 下
smalldd.c 檔內引用 smalldd.h 的寫法 #include <net/smalldd.h>
3.
編輯 net/Kconfig
>vim net/Kconfig
在 endif # if NET 前加入
config SMALLDD
bool "smalldd network function"
default y
help
If you say Y, smallddd can help you.
說明
config <tag>
bool "<title>"
default <default>
help
<description>
<tag>: 一個專用的標籤,在 gcc 編譯時就會有一個定義 CONFIG_<tag>
<title>: 程式的標題
<default>: 預設設定要不要一起編譯
<description>: 程式的說明
4.
編輯 Makefile
>vim net/core/Makefile
加入
obj-$(CONFIG_SMALLDD) += smalldd.o
5.
設定 kernel 編譯設定檔
>make menuconfig
因為預設是要加入編譯
所以進入直接存檔就好
6.
編譯 kernel 吧!!!!
這是從 Joey 的 Who call me – kernel版 看來的
在 Linux kernel 中可以使用 sprint_symbol() 來查看函式指標指到的函式名稱和 stack 位址
用法相當簡單
假設有個加法函式
int add(int augend, int addend);
和函式指標
int (*func)(int, int);
且這函式指標指向加法函式
func = add;
接著以 sprint_symbol() 取得 func 指向的函式名稱和 stack 位址
char fname[KSYM_SYMBOL_LEN];
sprint_symbol(fname, func);
利用 printk() 就可以印出 函式名稱和 stack 位址
printk(KERN_INFO "%s\n", fname);
藉由這函式就可以很方便追蹤 kernel 的 函式呼叫流程