字符设备驱动
任务
编写利用字符设备实现对字符串加密解密的程序。
加密:将大小写字母循环加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;
}