字符設備驅動
任務
編寫利用字符設備實現對字符串加密解密的程序。
加密:將大小寫字母循環加4
解密:將大小寫字母循環減4
例如:"China!“加密成"Glmre!”
驅動代碼
//這是驅動代碼,實現一個主設備號,兩個次設備。一個次設備號加密,一個次設備號解密。
//相應的測試程序是 test1.c
#include<linux/module.h>
#include<linux/types.h>
#include<linux/kdev_t.h>
#include<linux/fs.h>
#include<linux/cdev.h>
#include<asm/uaccess.h>
#define OFFSET 4
#define Major 200
#define SIZE 256
MODULE_LICENSE("GPL");
dev_t mydev;//存放申請的主次設備號
struct cdev mycdev[2]; //用於描述設備信息的結構體
char str[SIZE]={0}; //用於存放從用戶態傳送到內存態的數據
ssize_t my_write1(struct file* pfile,const char __user * buff, size_t num, loff_t *f_p)
{
int n=0;
printk(KERN_INFO"Write1 now\n");
if(num>SIZE) //若是num大小超出存儲的數組大小
return -ENOMEM;
if(copy_from_user(str,buff,num)) //若是還有從用戶態未讀完的數據
return -EFAULT;
// copy_from_user(str,buff,num);
#if 1
while(str[n] != 0) //字符加密,即字母往後循環移動 OFFSET 位數
{
if( ('a'<=str[n]&&str[n]<='z') || ('A'<=str[n]&&str[n]<='Z') )
{
if( ('a'<=str[n]&&str[n]<=('z'-OFFSET)) || ('A'<=str[n]&&str[n]<=('Z'-OFFSET)) )
str[n] += OFFSET;
else
{
str[n] += OFFSET - 26;
}
n++;
}
}
#endif
printk(KERN_INFO"Write1 Succeed\n");
return 0;
}
ssize_t my_write2(struct file* pfile,const char __user * buff, size_t num, loff_t *f_p)
{
printk(KERN_INFO"Write2 Now\n");
if(num>SIZE) //若是num大小超出存儲的數組大小
return -ENOMEM;
if(copy_from_user(str,buff,num)) //若是還有從用戶態未讀完的數據
return -EFAULT;
printk(KERN_INFO"Write2 Succeed\n");
return 0;
}
ssize_t my_read1(struct file* pfile,char __user* buff, size_t num, loff_t *f_p)
{
printk(KERN_INFO"Read1 now\n");
if(num>SIZE) //若所讀大小超出內核態儲存的大小
num=SIZE;
if(copy_to_user(buff,str,num)) //若是還有從內核態未讀完的數據
return -EFAULT;
printk(KERN_INFO"Read1 Succeed\n");
return 0;
}
ssize_t my_read2(struct file* pfile,char __user* buff, size_t num, loff_t *f_p)
{
int n=0;
printk(KERN_INFO"Read2 now\n");
while(str[n] != 0) //字符解密,即字母循環向前移動 OFFSET 位數
{
if( ('a'<=str[n]&&str[n]<='z') || ('A'<=str[n]&&str[n]<='Z') )
{
if( (('a'+OFFSET)<=str[n]&&str[n]<='z') || (('A'+OFFSET)<=str[n]&&str[n]<='Z') )
str[n] -= OFFSET;
else
{
str[n] += 26 - OFFSET;
}
}
n++;
}
#endif
if(num>SIZE) //若所讀大小超出內核態儲存的大小
num=SIZE;
if(copy_to_user(buff,str,num)) //若是還有從內核態未讀完的數據
return -EFAULT;
printk(KERN_INFO"Read2 Succeed\n");
return 0;
}
int my_open(struct inode * id,struct file* pfile)
{
printk(KERN_INFO"Open file\n");
printk(KERN_INFO"Open Succeed\n");
return 0;
}
int my_release(struct inode * id,struct file* pfile)
{
printk(KERN_INFO"Release file\n");
printk(KERN_INFO"Release Succeed\n");
return 0;
}
struct file_operations ops1={ //第一個次設備號用於加密
.owner = THIS_MODULE,
.open = my_open,
.release = my_release,
.read = my_read1,
.write = my_write1 //對於設備特性的描述
};
struct file_operations ops2={ //第二個次設備號用於解密
.owner = THIS_MODULE,
.open = my_open,
.release = my_release,
.read = my_read2,
.write = my_write2 //對於設備特性的描述
};
int __init init_module(void)
{
int ret = 1;
printk(KERN_INFO"Init cdev now\n");
mydev = MKDEV(Major,0); //創建設備號
ret = register_chrdev_region(mydev,2,"cdevTest"); //申請兩個設備號 即次設備號是0,1
if(ret != 0 )
{
printk(KERN_INFO"Error dev number\n"); //設備號申請失敗
return 0;
}
cdev_init(&mycdev[0],&ops1);
ret = cdev_add(&mycdev[0],mydev,1);
if(ret != 0 )
{
printk(KERN_INFO"Error cdev1\n"); //設備特性添加失敗
return 0;
}
cdev_init(&mycdev[1],&ops2);
ret = cdev_add(&mycdev[1],mydev+1,1);
if(ret != 0 )
{
printk(KERN_INFO"Error cdev2\n"); //設備特性添加失敗
return 0;
}
printk(KERN_INFO" Succeed\n");
return 0;
}
void __exit cleanup_module (void)
{
printk(KERN_INFO"Exit cdev now\n");
unregister_chrdev_region(mydev,2);//註銷設備號
cdev_del(&mycdev[0]); //註銷設備
cdev_del(&mycdev[1]); //註銷設備
}
測試代碼
測試前,需要現在Linux 的 /dev 下創建相應的驅動文件。
mknod /dev/code_cdev1 c 200 0
mknod /dev/code_cdev2 c 200 0
由於實驗中涉及對驅動文件的讀寫操作,所以需要更改對文件的權限。
sudo chmod 777 /dev/code_cdev1
sudo chmod 777 /dev/code_cdev2
#include<stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include<unistd.h>
#include<string.h>
int main()
{
int fd_1 =-1;
int fd_2 =-1;
char str[256] = {0};
fd_1 = open("/dev/code_cdev1",O_RDWR); //打開相應的驅動文件,此文件需要自己手動提前創建
if(fd_1<0)
{
printf("fd_1 error\n");
return 0;
}
fd_2 = open("/dev/code_cdev2",O_RDWR);
if(fd_2<0)
{
printf("fd_2 error\n");
return 0;
}
printf("Please Enter:");
gets(str);
printf("You Enter:%s\n",str);
write(fd_1,str,strlen(str));
read(fd_1,str,strlen(str));
printf("Encode Print:%s\n",str);
write(fd_2,str,strlen(str));
read(fd_2,str,strlen(str));
printf("Uncode Print:%s\n",str);
close(fd_1);
close(fd_2);
return 0;
}