JiamiJiemi

字符設備驅動

任務

  編寫利用字符設備實現對字符串加密解密的程序。
  加密:將大小寫字母循環加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;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章