secgateway/Product/modules/proc_api/proc_api.c

503 lines
13 KiB
C
Raw Normal View History

#ifdef __KERNEL__
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/string.h>
#include <linux/slab.h>
#include <linux/errno.h>
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
#include <linux/uaccess.h>
#include <asm/bitops.h>
#include <linux/mutex.h>
#include "proc_api.h"
#include "../../common/uthash.h"
#include "../../common/common.h"
#define MAX_COMMAND_LEN (256)
#define MAX_CMD_LEN (32)
#define MAX_PARAMS_LEN (128)
#define TOLOWER(x) ((x) | 0x20)
#ifndef MAX
#define MAX(a, b) (((a) > (b)) ? (a) : (b))
#endif
#define HELP_BITS (31)
#define IOCTL_BITS (30)
#define PROC_API_DBG_DIR ("api")
typedef struct {
char key[MAX_PATH]; ///< <20>ڵ<EFBFBD><DAB5><EFBFBD><EFBFBD><EFBFBD>
char dir_name[MAX_NAME_LEN]; ///< Ŀ¼<C4BF><C2BC><EFBFBD><EFBFBD>
PDBGFS_PRIV data; ///< <20>ڵ<EFBFBD><DAB5><EFBFBD><EFBFBD><EFBFBD>
struct proc_dir_entry* entry; ///< proc Ŀ¼<C4BF><C2BC><EFBFBD>ݽṹ
UT_hash_handle hh; ///< Hash<73><68><EFBFBD><EFBFBD><EFBFBD>ڵ<EFBFBD>
} PROC_INFO, *PPROC_INFO;
static const struct file_operations g_DbgSeq_fops;
static struct proc_dir_entry* g_DebugProcFS;
static DEFINE_RWLOCK(g_proc_lock);
static PPROC_INFO g_proc_items = NULL;
static int proc_api_show(struct seq_file* seq, void* token)
{
PPROC_INFO pInfo = NULL, tmp = NULL;
int i = 0;
seq_printf(seq, "Total API items: %u\n", HASH_COUNT(g_proc_items));
seq_printf(seq, "API root direcotry: /proc/%s/\n", PROC_API_DIR_NAME);
seq_puts(seq, "-------------------------------------"
"-------------------------------------\n");
seq_puts(seq, "| ID | Direcotry | Name | Show | IOCtrl | Help |\n");
seq_puts(seq, "|------------------------------------"
"------------------------------------|\n");
read_lock(&g_proc_lock);
HASH_ITER(hh, g_proc_items, pInfo, tmp) {
seq_printf(seq, "| %03d | %14s | %14s | %1s | %1s | %1s |\n",
i++,
pInfo->dir_name ? pInfo->dir_name : "",
pInfo->data->name,
pInfo->data->show ? "*" : "-",
pInfo->data->ioctl ? "*" : "-",
pInfo->data->help ? "*" : "-");
}
read_unlock(&g_proc_lock);
seq_puts(seq, "-------------------------------------"
"-------------------------------------\n");
return 0;
}
static int proc_api_ioctl(struct seq_file* seq, void* token)
{
PDBGFS_PRIV priv = (PDBGFS_PRIV)(seq->private);
seq_printf(seq, "Run Command [%s] with (%s)\n", priv->cmd, priv->cmd_data);
return 0;
}
static int proc_api_help(struct seq_file* seq, void* token)
{
PDBGFS_PRIV priv = (PDBGFS_PRIV)(seq->private);
seq_puts(seq, "==============Options Helps=============\n");
seq_printf(seq, "usage: echo \"<params>\" > /proc/%s/%s/%s\n",
PROC_API_DIR_NAME, PROC_API_DBG_DIR, priv->name);
return 0;
}
static DBGFS_PRIV g_DbgConfig[] = {
{
"info", 0, 0L, NULL, NULL,
proc_api_show, proc_api_ioctl, proc_api_help
},
};
static PROC_API g_ProcApi = {
PROC_API_DBG_DIR, g_DbgConfig, sizeof(g_DbgConfig) / sizeof(g_DbgConfig[0]),
};
static int proc_api_init(const char* proc_dir_name)
{
if(proc_dir_name) {
g_DebugProcFS = proc_mkdir(proc_dir_name, NULL);
if(g_DebugProcFS != NULL) {
return ERR_DBGFS_NO_ERROR;
}
}
return ERR_DBGFS_INIT;
}
static void proc_api_uninit(const char* proc_dir_name)
{
remove_proc_entry(proc_dir_name, NULL);
}
/**
* @brief ע<EFBFBD><EFBFBD>procģ<EFBFBD><EFBFBD>
*
* @param pv: ģ<EFBFBD><EFBFBD>proc<EFBFBD><EFBFBD>Ϣ
* @return int: 0 <EFBFBD>ɹ<EFBFBD><EFBFBD><EFBFBD> -EINVAL <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
*/
int proc_api_register(PPROC_API pv)
{
struct proc_dir_entry* pdir;
int i = 0;
if(pv == NULL || pv->data == NULL || pv->num_data <= 0) {
return -EINVAL;
}
if(pv->dir_name && strlen(pv->dir_name) > 0) {
pdir = proc_mkdir(pv->dir_name, g_DebugProcFS);
} else {
pdir = g_DebugProcFS;
}
// printk(KERN_ERR "Register: %s number %d of %s\n", pv->dir_name, pv->num_data, pv->data->name);
for(i = 0; i < pv->num_data; i++) {
PPROC_INFO pInfo = (PPROC_INFO)kmalloc(sizeof(PROC_INFO), GFP_KERNEL);
if(pInfo == NULL) {
printk(KERN_ERR "Malloc Error\n");
return ERR_MALLOC_MEMORY;
}
memset(pInfo, 0, sizeof(PROC_INFO));
if(!proc_create_data(pv->data[i].name, 0x644, pdir, &g_DbgSeq_fops, &pv->data[i])) {
printk(KERN_ERR "proc_create_data Error\n");
continue;
}
if(pv->dir_name && strlen(pv->dir_name) > 0) {
strcpy(pInfo->dir_name, pv->dir_name);
sprintf(pInfo->key, "%s%s", pv->dir_name, pv->data[i].name);
} else {
sprintf(pInfo->key, "%s", pv->data[i].name);
}
pInfo->entry = pdir;
pInfo->data = &pv->data[i];
write_lock(&g_proc_lock);
HASH_ADD_STR(g_proc_items, key, pInfo);
write_unlock(&g_proc_lock);
}
return 0;
}
/**
* @brief <EFBFBD><EFBFBD><EFBFBD><EFBFBD>procģ<EFBFBD><EFBFBD>ע<EFBFBD><EFBFBD>
*
* @param pv: ģ<EFBFBD><EFBFBD>proc<EFBFBD><EFBFBD>Ϣ
* @return int: 0 <EFBFBD>ɹ<EFBFBD><EFBFBD><EFBFBD> -EINVAL <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
*/
int proc_api_unregister(PPROC_API pv)
{
PPROC_INFO pInfo = NULL;
char key[MAX_PATH];
int i;
if(pv == NULL || pv->data == NULL || pv->num_data <= 0) {
return -EINVAL;
}
for(i = 0; i < pv->num_data; i++) {
memset(key, 0, MAX_PATH);
if(pv->dir_name && strlen(pv->dir_name) > 0) {
sprintf(key, "%s%s", pv->dir_name, pv->data[i].name);
} else {
sprintf(key, "%s", pv->data[i].name);
}
HASH_FIND_STR(g_proc_items, key, pInfo);
if(pInfo) {
write_lock(&g_proc_lock);
HASH_DEL(g_proc_items, pInfo);
write_unlock(&g_proc_lock);
remove_proc_entry(pv->data[i].name, pInfo->entry);
kfree(pInfo);
}
}
if(pv->dir_name && strlen(pv->dir_name) > 0) {
remove_proc_subtree(pv->dir_name, g_DebugProcFS);
}
return 0;
}
static int proc_seq_open(struct inode* inode, struct file* file)
{
PDBGFS_PRIV priv = (PDBGFS_PRIV)(PDE_DATA(inode));
if(test_bit(HELP_BITS, &priv->mask) && priv->help) {
clear_bit(HELP_BITS, &priv->mask);
return single_open(file, priv->help, priv);
} else if(test_bit(IOCTL_BITS, &priv->mask) && priv->ioctl) {
clear_bit(IOCTL_BITS, &priv->mask);
return single_open(file, priv->ioctl, priv);
} else {
return single_open(file, priv->show, priv);
}
}
static int proc_seq_release(struct inode* inode, struct file* file)
{
return single_release(inode, file);
}
static int get_value_base(unsigned char* pBuf)
{
int strLen = pBuf ? strlen(pBuf) : -1;
if(pBuf) {
int i = 0;
if(pBuf[0] == '0' && pBuf[1] == 'x') {
return 16;
}
for(i = 0; i < strLen; i++) {
if(TOLOWER(pBuf[i]) >= 'a' && TOLOWER(pBuf[i]) <= 'f') {
return 16;
}
}
}
return 10;
}
/**
* @brief <EFBFBD><EFBFBD>ȡ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>е<EFBFBD><EFBFBD>ַ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ֵ
*
* @param pBuf: <EFBFBD>ַ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
* @param index: ָ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>λ<EFBFBD><EFBFBD>
* @param pValue: <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ȡ<EFBFBD><EFBFBD><EFBFBD>ַ<EFBFBD><EFBFBD><EFBFBD>ֵ
* @param maxBytes: <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
* @return int: 0 <EFBFBD>ɹ<EFBFBD><EFBFBD><EFBFBD> -EINVAL <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>-ENOENT û<EFBFBD>ж<EFBFBD>Ӧ<EFBFBD><EFBFBD>ֵ
*/
int get_string_value(unsigned char* pBuf, int index, unsigned char* pValue, unsigned int maxBytes)
{
char tmpBuf[128];
char* token;
char* s = tmpBuf;
int paramIndex = 0;
if(pBuf == NULL || index < 0 || pValue == NULL) {
return -EINVAL;
}
memset(pValue, 0, maxBytes);
strcpy(tmpBuf, pBuf);
for(token = strsep(&s, " ");
token != NULL;
token = strsep(&s, " ")) {
if(token != NULL) {
if(index != paramIndex) {
paramIndex += 1;
continue;
}
strcpy(pValue, token);
return 0;
}
}
return -ENOENT;
}
/**
* @brief <EFBFBD>Ӳ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ָ<EFBFBD><EFBFBD>λ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ȡ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ֵ
*
* @param pBuf: <EFBFBD>ַ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
* @param index: ָ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>λ<EFBFBD><EFBFBD>
* @param pValue: <EFBFBD><EFBFBD><EFBFBD>ػ<EFBFBD>ȡ<EFBFBD><EFBFBD>ֵ
* @return int: 0 <EFBFBD>ɹ<EFBFBD><EFBFBD><EFBFBD> -EINVAL <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>-ENOENT û<EFBFBD>ж<EFBFBD>Ӧ<EFBFBD><EFBFBD>ֵ<EFBFBD><EFBFBD>-EFAULT <EFBFBD>ַ<EFBFBD><EFBFBD><EFBFBD>ת<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
*/
int get_int_value(unsigned char* pBuf, int index, int* pValue)
{
char tmpBuf[128];
char* token;
char* s = tmpBuf;
int paramIndex = 0;
int paramValue = -1;
if(pBuf == NULL || index < 0 || pValue == NULL) {
return -EINVAL;
}
strcpy(tmpBuf, pBuf);
for(token = strsep(&s, " ");
token != NULL;
token = strsep(&s, " ")) {
if(token != NULL) {
if(index != paramIndex) {
paramIndex += 1;
continue;
}
if(kstrtol(token, get_value_base(token), (long*)&paramValue) != 0) {
printk(KERN_ERR "strict_strtol [%s] Error\n", token);
return -EFAULT;
} else {
*pValue = paramValue;
return 0;
}
}
}
return -ENOENT;
}
static int process_input_content(struct seq_file* seq, unsigned char* pBuf, PDBGFS_PRIV pv)
{
int strLen = pBuf ? strlen(pBuf) - 1 : -1;
char tmpBuf[MAX_COMMAND_LEN], cmdBuf[MAX_CMD_LEN], paramBuf[MAX_PARAMS_LEN];
int i = 0;
int bIsCmd = 0;
if(strlen <= 0){
return -ERR_PARA_OUTOFRANGE;
}
memset(tmpBuf, 0, MAX_COMMAND_LEN);
memset(cmdBuf, 0, MAX_CMD_LEN);
memset(paramBuf, 0, MAX_PARAMS_LEN);
if(pBuf == NULL && pv == NULL) {
return -ERR_PARA_OUTOFRANGE;
}
strcpy(tmpBuf, pBuf);
for(i = 0; i < strLen; i++) {
if(tmpBuf[i] == ' ') {
strncpy(cmdBuf, tmpBuf, i);
strncpy(paramBuf, &tmpBuf[i + 1], MAX(strLen - i - 1, 0));
bIsCmd = 1;
break;
}
}
if(!bIsCmd) {
if(kstrtoul(pBuf, get_value_base(pBuf), (long unsigned int*)&pv->params)) {
printk(KERN_ERR "strict_strtoul [%s] base %d Error\n", pBuf, get_value_base(pBuf));
return -ERR_DBGFS_WRITEOPTS;
}
} else {
if(pv->ioctl != NULL) {
if(pv->cmd != NULL) {
kfree(pv->cmd);
}
if(pv->cmd_data) {
kfree(pv->cmd_data);
}
if(strlen(cmdBuf) > 0) {
pv->cmd = kmalloc(strlen(cmdBuf) + 1, GFP_KERNEL);
if(pv->cmd == NULL) {
printk(KERN_ERR "Malloc %lu Error\n", strlen(cmdBuf) + 1);
return -ERR_MALLOC_MEMORY;
}
strcpy(pv->cmd, cmdBuf);
}
if(strlen(paramBuf) > 0) {
pv->cmd_data = kmalloc(strlen(paramBuf) + 1, GFP_KERNEL);
if(pv->cmd_data == NULL) {
printk(KERN_ERR "Malloc %ld Error\n", strlen(paramBuf) + 1);
return -ERR_MALLOC_MEMORY;
}
strcpy(pv->cmd_data, paramBuf);
}
set_bit(IOCTL_BITS, &pv->mask);
printk(KERN_INFO "%s do %s command with %s\n", pv->name, pv->cmd, pv->cmd_data);
}
return ERR_DBGFS_NO_ERROR;
}
return ERR_PARA_OUTOFRANGE;
}
static ssize_t proc_seq_option_write(struct file* file, const char __user* userbuf,
size_t count, loff_t* data)
{
char buf[64];
struct seq_file* seq = (struct seq_file*)file->private_data;
PDBGFS_PRIV pv = (PDBGFS_PRIV)seq->private;
if(count >= sizeof(buf)) {
printk(KERN_ERR "Input Params Error:count = %ld, max size = %ld\n", count,
sizeof(buf));
return -ERR_PARA_OUTOFRANGE;
}
if(copy_from_user(buf, userbuf, count)) {
printk(KERN_ERR "Copy Data To Kernel Error\n");
return -ERR_DBGFS_WRITEOPTS;
}
if(buf[0] == 'h' &&
buf[1] == 'e' &&
buf[2] == 'l' &&
buf[3] == 'p') {
if(pv->help != NULL) {
set_bit(HELP_BITS, &pv->mask);
//pv->help((struct seq_file*)file->private_data, pv);
}
return count;
}
buf[count] = 0x00;
if(!process_input_content(seq, buf, pv) == ERR_DBGFS_NO_ERROR) {
printk(KERN_ERR "Input [%s] Process Error\n", buf);
}
return count;
}
static const struct file_operations g_DbgSeq_fops = {
.owner = THIS_MODULE,
.open = proc_seq_open,
.read = seq_read,
.write = proc_seq_option_write,
.llseek = seq_lseek,
.release = proc_seq_release,
};
#define VERSION ("v0.0.0.2")
static int __init api_module_init(void)
{
printk(KERN_INFO "Hello ISG PROC API version: %s\n", VERSION);
proc_api_init(PROC_API_DIR_NAME);
if(proc_api_register(&g_ProcApi) != ERR_DBGFS_NO_ERROR) {
printk(KERN_ERR "Regisetr %s Error\n", g_ProcApi.dir_name);
}
return 0;
}
module_init(api_module_init);
static void __exit api_module_exit(void)
{
printk(KERN_INFO "Bye ISG PROC API version: %s\n", VERSION);
proc_api_unregister(&g_ProcApi);
proc_api_uninit(PROC_API_DIR_NAME);
}
module_exit(api_module_exit);
EXPORT_SYMBOL(proc_api_register);
EXPORT_SYMBOL(proc_api_unregister);
EXPORT_SYMBOL(get_int_value);
EXPORT_SYMBOL(get_string_value);
MODULE_LICENSE("Dual BSD/GPL");
MODULE_VERSION("0.1");
#endif